syscall_emul.hh revision 11380
12623SN/A/*
22623SN/A * Copyright (c) 2012-2013, 2015 ARM Limited
32623SN/A * Copyright (c) 2015 Advanced Micro Devices, Inc.
42623SN/A * All rights reserved
52623SN/A *
62623SN/A * The license below extends only to copyright in the software and shall
72623SN/A * not be construed as granting a license to any other intellectual
82623SN/A * property including but not limited to intellectual property relating
92623SN/A * to a hardware implementation of the functionality of the software
102623SN/A * licensed hereunder.  You may use the software subject to the license
112623SN/A * terms below provided that you ensure that this notice is replicated
122623SN/A * unmodified and in its entirety in all distributions of the software,
132623SN/A * modified or unmodified, in source code or in binary form.
142623SN/A *
152623SN/A * Copyright (c) 2003-2005 The Regents of The University of Michigan
162623SN/A * All rights reserved.
172623SN/A *
182623SN/A * Redistribution and use in source and binary forms, with or without
192623SN/A * modification, are permitted provided that the following conditions are
202623SN/A * met: redistributions of source code must retain the above copyright
212623SN/A * notice, this list of conditions and the following disclaimer;
222623SN/A * redistributions in binary form must reproduce the above copyright
232623SN/A * notice, this list of conditions and the following disclaimer in the
242623SN/A * documentation and/or other materials provided with the distribution;
252623SN/A * neither the name of the copyright holders nor the names of its
262623SN/A * contributors may be used to endorse or promote products derived from
272665Ssaidi@eecs.umich.edu * this software without specific prior written permission.
282665Ssaidi@eecs.umich.edu *
292623SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
302623SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
313170Sstever@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
325103Ssaidi@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
332623SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
344040Ssaidi@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
352623SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
362623SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
373348Sbinkertn@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
383348Sbinkertn@umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
394762Snate@binkert.org * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
402901Ssaidi@eecs.umich.edu *
412623SN/A * Authors: Steve Reinhardt
422623SN/A *          Kevin Lim
432623SN/A */
442623SN/A
452856Srdreslin@umich.edu#ifndef __SIM_SYSCALL_EMUL_HH__
462856Srdreslin@umich.edu#define __SIM_SYSCALL_EMUL_HH__
472856Srdreslin@umich.edu
482856Srdreslin@umich.edu#define NO_STAT64 (defined(__APPLE__) || defined(__OpenBSD__) || \
492856Srdreslin@umich.edu  defined(__FreeBSD__) || defined(__CYGWIN__) || \
502856Srdreslin@umich.edu  defined(__NetBSD__))
512856Srdreslin@umich.edu
522856Srdreslin@umich.edu///
532856Srdreslin@umich.edu/// @file syscall_emul.hh
542856Srdreslin@umich.edu///
552623SN/A/// This file defines objects used to emulate syscalls from the target
562623SN/A/// application on the host machine.
572623SN/A
582623SN/A#ifdef __CYGWIN32__
592623SN/A#include <sys/fcntl.h>  // for O_BINARY
602623SN/A#endif
612680Sktlim@umich.edu#include <sys/stat.h>
622680Sktlim@umich.edu#include <sys/time.h>
632623SN/A#include <sys/uio.h>
642623SN/A#include <fcntl.h>
652680Sktlim@umich.edu
662623SN/A#include <cerrno>
672623SN/A#include <string>
682623SN/A
692623SN/A#include "base/chunk_generator.hh"
702623SN/A#include "base/intmath.hh"      // for RoundUp
713349Sbinkertn@umich.edu#include "base/misc.hh"
722623SN/A#include "base/trace.hh"
732623SN/A#include "base/types.hh"
742623SN/A#include "config/the_isa.hh"
752623SN/A#include "cpu/base.hh"
762623SN/A#include "cpu/thread_context.hh"
772623SN/A#include "debug/SyscallBase.hh"
783349Sbinkertn@umich.edu#include "debug/SyscallVerbose.hh"
792623SN/A#include "mem/page_table.hh"
803184Srdreslin@umich.edu#include "sim/byteswap.hh"
813184Srdreslin@umich.edu#include "sim/emul_driver.hh"
822623SN/A#include "sim/process.hh"
832623SN/A#include "sim/syscall_emul_buf.hh"
842623SN/A#include "sim/syscallreturn.hh"
852623SN/A#include "sim/system.hh"
862623SN/A
873647Srdreslin@umich.edu// This wrapper macro helps out with readability a bit. FLAGEXT specifies
883647Srdreslin@umich.edu// the verbosity and FMT is the message to be appended to the syscall
893647Srdreslin@umich.edu// header information. The syscall header information contains the cpuid
903647Srdreslin@umich.edu// and thread id.
913647Srdreslin@umich.edu#define DPRINTF_SYSCALL(FLAGEXT, FMT, ...)                                  \
922631SN/A    DPRINTFS(Syscall##FLAGEXT, tc->getCpuPtr(), "T%d : syscall " FMT,       \
933647Srdreslin@umich.edu             tc->threadId(), __VA_ARGS__)
942631SN/A
952623SN/A///
962623SN/A/// System call descriptor.
972623SN/A///
982948Ssaidi@eecs.umich.educlass SyscallDesc {
992948Ssaidi@eecs.umich.edu
1003349Sbinkertn@umich.edu  public:
1012948Ssaidi@eecs.umich.edu
1022948Ssaidi@eecs.umich.edu    /// Typedef for target syscall handler functions.
1032948Ssaidi@eecs.umich.edu    typedef SyscallReturn (*FuncPtr)(SyscallDesc *, int num,
1042948Ssaidi@eecs.umich.edu                           LiveProcess *, ThreadContext *);
1052948Ssaidi@eecs.umich.edu
1062623SN/A    const char *name;   //!< Syscall name (e.g., "open").
1075169Ssaidi@eecs.umich.edu    FuncPtr funcPtr;    //!< Pointer to emulation function.
1082623SN/A    int flags;          //!< Flags (see Flags enum).
1092623SN/A    bool warned;        //!< Have we warned about unimplemented syscall?
1103647Srdreslin@umich.edu
1113647Srdreslin@umich.edu    /// Flag values for controlling syscall behavior.
1123647Srdreslin@umich.edu    enum Flags {
1133647Srdreslin@umich.edu        /// Don't set return regs according to funcPtr return value.
1142623SN/A        /// Used for syscalls with non-standard return conventions
1152839Sktlim@umich.edu        /// that explicitly set the ThreadContext regs (e.g.,
1162867Sktlim@umich.edu        /// sigreturn).
1173222Sktlim@umich.edu        SuppressReturnValue = 1,
1182901Ssaidi@eecs.umich.edu        WarnOnce = 2
1192623SN/A    };
1202623SN/A
1212623SN/A    /// Constructor.
1222623SN/A    SyscallDesc(const char *_name, FuncPtr _funcPtr, int _flags = 0)
1232623SN/A        : name(_name), funcPtr(_funcPtr), flags(_flags), warned(false)
1242623SN/A    {
1252623SN/A    }
1262623SN/A
1272623SN/A    /// Emulate the syscall.  Public interface for calling through funcPtr.
1282623SN/A    void doSyscall(int callnum, LiveProcess *proc, ThreadContext *tc);
1292915Sktlim@umich.edu
1302915Sktlim@umich.edu    /// Is the WarnOnce flag set?
1312623SN/A    bool warnOnce() const {  return (flags & WarnOnce); }
1322623SN/A};
1332623SN/A
1342623SN/A
1352623SN/A//////////////////////////////////////////////////////////////////////
1362623SN/A//
1372915Sktlim@umich.edu// The following emulation functions are generic enough that they
1382915Sktlim@umich.edu// don't need to be recompiled for different emulated OS's.  They are
1392623SN/A// defined in sim/syscall_emul.cc.
1402798Sktlim@umich.edu//
1412798Sktlim@umich.edu//////////////////////////////////////////////////////////////////////
1422901Ssaidi@eecs.umich.edu
1432839Sktlim@umich.edu
1442798Sktlim@umich.edu/// Handler for unimplemented syscalls that we haven't thought about.
1452839Sktlim@umich.eduSyscallReturn unimplementedFunc(SyscallDesc *desc, int num,
1462798Sktlim@umich.edu                                LiveProcess *p, ThreadContext *tc);
1472798Sktlim@umich.edu
1482901Ssaidi@eecs.umich.edu/// Handler for unimplemented syscalls that we never intend to
1492901Ssaidi@eecs.umich.edu/// implement (signal handling, etc.) and should not affect the correct
1502798Sktlim@umich.edu/// behavior of the program.  Print a warning only if the appropriate
1512839Sktlim@umich.edu/// trace flag is enabled.  Return success to the target program.
1522839Sktlim@umich.eduSyscallReturn ignoreFunc(SyscallDesc *desc, int num,
1532901Ssaidi@eecs.umich.edu                         LiveProcess *p, ThreadContext *tc);
1542798Sktlim@umich.edu
1552623SN/A/// Target exit() handler: terminate current context.
1562623SN/ASyscallReturn exitFunc(SyscallDesc *desc, int num,
1572623SN/A                       LiveProcess *p, ThreadContext *tc);
1582798Sktlim@umich.edu
1592623SN/A/// Target exit_group() handler: terminate simulation. (exit all threads)
1605221Ssaidi@eecs.umich.eduSyscallReturn exitGroupFunc(SyscallDesc *desc, int num,
1612798Sktlim@umich.edu                       LiveProcess *p, ThreadContext *tc);
1624762Snate@binkert.org
1633201Shsul@eecs.umich.edu/// Target getpagesize() handler.
1642867Sktlim@umich.eduSyscallReturn getpagesizeFunc(SyscallDesc *desc, int num,
1652867Sktlim@umich.edu                              LiveProcess *p, ThreadContext *tc);
1662915Sktlim@umich.edu
1672915Sktlim@umich.edu/// Target brk() handler: set brk address.
1682915Sktlim@umich.eduSyscallReturn brkFunc(SyscallDesc *desc, int num,
1692867Sktlim@umich.edu                      LiveProcess *p, ThreadContext *tc);
1702867Sktlim@umich.edu
1712867Sktlim@umich.edu/// Target close() handler.
1724471Sstever@eecs.umich.eduSyscallReturn closeFunc(SyscallDesc *desc, int num,
1732623SN/A                        LiveProcess *p, ThreadContext *tc);
1742798Sktlim@umich.edu
1752901Ssaidi@eecs.umich.edu/// Target read() handler.
1762798Sktlim@umich.eduSyscallReturn readFunc(SyscallDesc *desc, int num,
1772798Sktlim@umich.edu                       LiveProcess *p, ThreadContext *tc);
1782798Sktlim@umich.edu
1792798Sktlim@umich.edu/// Target write() handler.
1802798Sktlim@umich.eduSyscallReturn writeFunc(SyscallDesc *desc, int num,
1812798Sktlim@umich.edu                        LiveProcess *p, ThreadContext *tc);
1822798Sktlim@umich.edu
1835099Ssaidi@eecs.umich.edu/// Target lseek() handler.
1842867Sktlim@umich.eduSyscallReturn lseekFunc(SyscallDesc *desc, int num,
1852867Sktlim@umich.edu                        LiveProcess *p, ThreadContext *tc);
1862867Sktlim@umich.edu
1872867Sktlim@umich.edu/// Target _llseek() handler.
1882867Sktlim@umich.eduSyscallReturn _llseekFunc(SyscallDesc *desc, int num,
1892623SN/A                        LiveProcess *p, ThreadContext *tc);
1902623SN/A
1912623SN/A/// Target munmap() handler.
1922623SN/ASyscallReturn munmapFunc(SyscallDesc *desc, int num,
1932623SN/A                         LiveProcess *p, ThreadContext *tc);
1942623SN/A
1954192Sktlim@umich.edu/// Target gethostname() handler.
1962623SN/ASyscallReturn gethostnameFunc(SyscallDesc *desc, int num,
1972680Sktlim@umich.edu                              LiveProcess *p, ThreadContext *tc);
1982623SN/A
1992680Sktlim@umich.edu/// Target getcwd() handler.
2002680Sktlim@umich.eduSyscallReturn getcwdFunc(SyscallDesc *desc, int num,
2012680Sktlim@umich.edu                         LiveProcess *p, ThreadContext *tc);
2022623SN/A
2032623SN/A/// Target readlink() handler.
2042623SN/ASyscallReturn readlinkFunc(SyscallDesc *desc, int num,
2052623SN/A                           LiveProcess *p, ThreadContext *tc,
2063201Shsul@eecs.umich.edu                           int index = 0);
2073201Shsul@eecs.umich.eduSyscallReturn readlinkFunc(SyscallDesc *desc, int num,
2083201Shsul@eecs.umich.edu                           LiveProcess *p, ThreadContext *tc);
2093201Shsul@eecs.umich.edu
2105169Ssaidi@eecs.umich.edu/// Target unlink() handler.
2115169Ssaidi@eecs.umich.eduSyscallReturn unlinkHelper(SyscallDesc *desc, int num,
2125101Ssaidi@eecs.umich.edu                           LiveProcess *p, ThreadContext *tc,
2132623SN/A                           int index);
2142623SN/ASyscallReturn unlinkFunc(SyscallDesc *desc, int num,
2152623SN/A                         LiveProcess *p, ThreadContext *tc);
2162623SN/A
2172623SN/A/// Target mkdir() handler.
2182623SN/ASyscallReturn mkdirFunc(SyscallDesc *desc, int num,
2195221Ssaidi@eecs.umich.edu                        LiveProcess *p, ThreadContext *tc);
2205221Ssaidi@eecs.umich.edu
2212623SN/A/// Target rename() handler.
2222683Sktlim@umich.eduSyscallReturn renameFunc(SyscallDesc *desc, int num,
2232623SN/A                         LiveProcess *p, ThreadContext *tc);
2242623SN/A
2252623SN/A
2262623SN/A/// Target truncate() handler.
2272623SN/ASyscallReturn truncateFunc(SyscallDesc *desc, int num,
2283686Sktlim@umich.edu                           LiveProcess *p, ThreadContext *tc);
2292623SN/A
2305100Ssaidi@eecs.umich.edu
2312623SN/A/// Target ftruncate() handler.
2322623SN/ASyscallReturn ftruncateFunc(SyscallDesc *desc, int num,
2332623SN/A                            LiveProcess *p, ThreadContext *tc);
2342623SN/A
2352623SN/A
2362623SN/A/// Target truncate64() handler.
2375221Ssaidi@eecs.umich.eduSyscallReturn truncate64Func(SyscallDesc *desc, int num,
2385221Ssaidi@eecs.umich.edu                             LiveProcess *p, ThreadContext *tc);
2392623SN/A
2402683Sktlim@umich.edu/// Target ftruncate64() handler.
2412623SN/ASyscallReturn ftruncate64Func(SyscallDesc *desc, int num,
2422644Sstever@eecs.umich.edu                              LiveProcess *p, ThreadContext *tc);
2432623SN/A
2442644Sstever@eecs.umich.edu
2452644Sstever@eecs.umich.edu/// Target umask() handler.
2462623SN/ASyscallReturn umaskFunc(SyscallDesc *desc, int num,
2472623SN/A                        LiveProcess *p, ThreadContext *tc);
2482623SN/A
2492623SN/A
2502623SN/A/// Target chown() handler.
2512623SN/ASyscallReturn chownFunc(SyscallDesc *desc, int num,
2522623SN/A                        LiveProcess *p, ThreadContext *tc);
2532623SN/A
2542623SN/A
2552623SN/A/// Target fchown() handler.
2563169Sstever@eecs.umich.eduSyscallReturn fchownFunc(SyscallDesc *desc, int num,
2573169Sstever@eecs.umich.edu                         LiveProcess *p, ThreadContext *tc);
2585169Ssaidi@eecs.umich.edu
2592623SN/A/// Target dup() handler.
2602623SN/ASyscallReturn dupFunc(SyscallDesc *desc, int num,
2613169Sstever@eecs.umich.edu                      LiveProcess *process, ThreadContext *tc);
2622623SN/A
2632623SN/A/// Target fnctl() handler.
2642623SN/ASyscallReturn fcntlFunc(SyscallDesc *desc, int num,
2653169Sstever@eecs.umich.edu                        LiveProcess *process, ThreadContext *tc);
2662623SN/A
2672623SN/A/// Target fcntl64() handler.
2682623SN/ASyscallReturn fcntl64Func(SyscallDesc *desc, int num,
2693349Sbinkertn@umich.edu                        LiveProcess *process, ThreadContext *tc);
2704878Sstever@eecs.umich.edu
2714878Sstever@eecs.umich.edu/// Target setuid() handler.
2724878Sstever@eecs.umich.eduSyscallReturn setuidFunc(SyscallDesc *desc, int num,
2734878Sstever@eecs.umich.edu                               LiveProcess *p, ThreadContext *tc);
2743169Sstever@eecs.umich.edu
2752623SN/A/// Target getpid() handler.
2765103Ssaidi@eecs.umich.eduSyscallReturn getpidFunc(SyscallDesc *desc, int num,
2775103Ssaidi@eecs.umich.edu                               LiveProcess *p, ThreadContext *tc);
2785103Ssaidi@eecs.umich.edu
2795103Ssaidi@eecs.umich.edu/// Target getuid() handler.
2805103Ssaidi@eecs.umich.eduSyscallReturn getuidFunc(SyscallDesc *desc, int num,
2815103Ssaidi@eecs.umich.edu                               LiveProcess *p, ThreadContext *tc);
2825103Ssaidi@eecs.umich.edu
2832623SN/A/// Target getgid() handler.
2843169Sstever@eecs.umich.eduSyscallReturn getgidFunc(SyscallDesc *desc, int num,
2852623SN/A                               LiveProcess *p, ThreadContext *tc);
2862623SN/A
2873169Sstever@eecs.umich.edu/// Target getppid() handler.
2882623SN/ASyscallReturn getppidFunc(SyscallDesc *desc, int num,
2892623SN/A                               LiveProcess *p, ThreadContext *tc);
2904200Ssaidi@eecs.umich.edu
2914200Ssaidi@eecs.umich.edu/// Target geteuid() handler.
2924200Ssaidi@eecs.umich.eduSyscallReturn geteuidFunc(SyscallDesc *desc, int num,
2934200Ssaidi@eecs.umich.edu                               LiveProcess *p, ThreadContext *tc);
2943658Sktlim@umich.edu
2953658Sktlim@umich.edu/// Target getegid() handler.
2962623SN/ASyscallReturn getegidFunc(SyscallDesc *desc, int num,
2972623SN/A                               LiveProcess *p, ThreadContext *tc);
2982623SN/A
2992623SN/A/// Target clone() handler.
3002623SN/ASyscallReturn cloneFunc(SyscallDesc *desc, int num,
3015177Sgblack@eecs.umich.edu                               LiveProcess *p, ThreadContext *tc);
3025177Sgblack@eecs.umich.edu
3035177Sgblack@eecs.umich.edu/// Target access() handler
3045177Sgblack@eecs.umich.eduSyscallReturn accessFunc(SyscallDesc *desc, int num,
3055177Sgblack@eecs.umich.edu                               LiveProcess *p, ThreadContext *tc);
3065177Sgblack@eecs.umich.eduSyscallReturn accessFunc(SyscallDesc *desc, int num,
3075177Sgblack@eecs.umich.edu                               LiveProcess *p, ThreadContext *tc,
3085177Sgblack@eecs.umich.edu                               int index);
3095177Sgblack@eecs.umich.edu
3105177Sgblack@eecs.umich.edu/// Futex system call
3115177Sgblack@eecs.umich.edu///  Implemented by Daniel Sanchez
3125177Sgblack@eecs.umich.edu///  Used by printf's in multi-threaded apps
3135177Sgblack@eecs.umich.edutemplate <class OS>
3145177Sgblack@eecs.umich.eduSyscallReturn
3155177Sgblack@eecs.umich.edufutexFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
3165177Sgblack@eecs.umich.edu          ThreadContext *tc)
3175177Sgblack@eecs.umich.edu{
3185177Sgblack@eecs.umich.edu    int index_uaddr = 0;
3195177Sgblack@eecs.umich.edu    int index_op = 1;
3205177Sgblack@eecs.umich.edu    int index_val = 2;
3212623SN/A    int index_timeout = 3;
3222623SN/A
3232623SN/A    uint64_t uaddr = process->getSyscallArg(tc, index_uaddr);
3242623SN/A    int op = process->getSyscallArg(tc, index_op);
3254040Ssaidi@eecs.umich.edu    int val = process->getSyscallArg(tc, index_val);
3264040Ssaidi@eecs.umich.edu    uint64_t timeout = process->getSyscallArg(tc, index_timeout);
3274040Ssaidi@eecs.umich.edu
3284040Ssaidi@eecs.umich.edu    std::map<uint64_t, std::list<ThreadContext *> * >
3294115Ssaidi@eecs.umich.edu        &futex_map = tc->getSystemPtr()->futexMap;
3304115Ssaidi@eecs.umich.edu
3314115Ssaidi@eecs.umich.edu    DPRINTF(SyscallVerbose, "In sys_futex: Address=%llx, op=%d, val=%d\n",
3324115Ssaidi@eecs.umich.edu            uaddr, op, val);
3332623SN/A
3342623SN/A    op &= ~OS::TGT_FUTEX_PRIVATE_FLAG;
3352623SN/A
3362623SN/A    if (op == OS::TGT_FUTEX_WAIT) {
3372623SN/A        if (timeout != 0) {
3382623SN/A            warn("sys_futex: FUTEX_WAIT with non-null timeout unimplemented;"
3392623SN/A                 "we'll wait indefinitely");
3402623SN/A        }
3412623SN/A
3422623SN/A        uint8_t *buf = new uint8_t[sizeof(int)];
3432623SN/A        tc->getMemProxy().readBlob((Addr)uaddr, buf, (int)sizeof(int));
3442623SN/A        int mem_val = *((int *)buf);
3452623SN/A        delete[] buf;
3462623SN/A
3472623SN/A        if (val != mem_val) {
3482623SN/A            DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAKE, read: %d, "
3492623SN/A                                    "expected: %d\n", mem_val, val);
3502623SN/A            return -OS::TGT_EWOULDBLOCK;
3512623SN/A        }
3522623SN/A
3532623SN/A        // Queue the thread context
3542623SN/A        std::list<ThreadContext *> * tcWaitList;
3552623SN/A        if (futex_map.count(uaddr)) {
3562623SN/A            tcWaitList = futex_map.find(uaddr)->second;
3572623SN/A        } else {
3582623SN/A            tcWaitList = new std::list<ThreadContext *>();
3592623SN/A            futex_map.insert(std::pair< uint64_t,
3602623SN/A                            std::list<ThreadContext *> * >(uaddr, tcWaitList));
3612623SN/A        }
3622623SN/A        tcWaitList->push_back(tc);
3632623SN/A        DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAIT, suspending calling "
3642623SN/A                                "thread context\n");
3652623SN/A        tc->suspend();
3662623SN/A        return 0;
3672623SN/A    } else if (op == OS::TGT_FUTEX_WAKE){
3682623SN/A        int wokenUp = 0;
3692623SN/A        std::list<ThreadContext *> * tcWaitList;
3702623SN/A        if (futex_map.count(uaddr)) {
3712623SN/A            tcWaitList = futex_map.find(uaddr)->second;
3722623SN/A            while (tcWaitList->size() > 0 && wokenUp < val) {
3732623SN/A                tcWaitList->front()->activate();
3742623SN/A                tcWaitList->pop_front();
3752623SN/A                wokenUp++;
3763169Sstever@eecs.umich.edu            }
3773169Sstever@eecs.umich.edu            if (tcWaitList->empty()) {
3785169Ssaidi@eecs.umich.edu                futex_map.erase(uaddr);
3792623SN/A                delete tcWaitList;
3804040Ssaidi@eecs.umich.edu            }
3814040Ssaidi@eecs.umich.edu        }
3824040Ssaidi@eecs.umich.edu        DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAKE, activated %d waiting "
3834040Ssaidi@eecs.umich.edu                                "thread contexts\n", wokenUp);
3842623SN/A        return wokenUp;
3853169Sstever@eecs.umich.edu    } else {
3863169Sstever@eecs.umich.edu        warn("sys_futex: op %d is not implemented, just returning...", op);
3872623SN/A        return 0;
3882623SN/A    }
3894878Sstever@eecs.umich.edu
3903170Sstever@eecs.umich.edu}
3913170Sstever@eecs.umich.edu
3923170Sstever@eecs.umich.edu
3934878Sstever@eecs.umich.edu/// Pseudo Funcs  - These functions use a different return convension,
3943170Sstever@eecs.umich.edu/// returning a second value in a register other than the normal return register
3954878Sstever@eecs.umich.eduSyscallReturn pipePseudoFunc(SyscallDesc *desc, int num,
3964878Sstever@eecs.umich.edu                             LiveProcess *process, ThreadContext *tc);
3974878Sstever@eecs.umich.edu
3984878Sstever@eecs.umich.edu/// Target getpidPseudo() handler.
3994878Sstever@eecs.umich.eduSyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num,
4004878Sstever@eecs.umich.edu                               LiveProcess *p, ThreadContext *tc);
4013170Sstever@eecs.umich.edu
4024584Ssaidi@eecs.umich.edu/// Target getuidPseudo() handler.
4034881Sstever@eecs.umich.eduSyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num,
4044881Sstever@eecs.umich.edu                               LiveProcess *p, ThreadContext *tc);
4054881Sstever@eecs.umich.edu
4064881Sstever@eecs.umich.edu/// Target getgidPseudo() handler.
4074881Sstever@eecs.umich.eduSyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num,
4084881Sstever@eecs.umich.edu                               LiveProcess *p, ThreadContext *tc);
4093170Sstever@eecs.umich.edu
4103170Sstever@eecs.umich.edu
4115103Ssaidi@eecs.umich.edu/// A readable name for 1,000,000, for converting microseconds to seconds.
4125103Ssaidi@eecs.umich.educonst int one_million = 1000000;
4135103Ssaidi@eecs.umich.edu/// A readable name for 1,000,000,000, for converting nanoseconds to seconds.
4145103Ssaidi@eecs.umich.educonst int one_billion = 1000000000;
4155103Ssaidi@eecs.umich.edu
4165103Ssaidi@eecs.umich.edu/// Approximate seconds since the epoch (1/1/1970).  About a billion,
4175103Ssaidi@eecs.umich.edu/// by my reckoning.  We want to keep this a constant (not use the
4185103Ssaidi@eecs.umich.edu/// real-world time) to keep simulations repeatable.
4193170Sstever@eecs.umich.educonst unsigned seconds_since_epoch = 1000000000;
4203170Sstever@eecs.umich.edu
4213170Sstever@eecs.umich.edu/// Helper function to convert current elapsed time to seconds and
4223170Sstever@eecs.umich.edu/// microseconds.
4233170Sstever@eecs.umich.edutemplate <class T1, class T2>
4243170Sstever@eecs.umich.eduvoid
4252623SN/AgetElapsedTimeMicro(T1 &sec, T2 &usec)
4264200Ssaidi@eecs.umich.edu{
4274200Ssaidi@eecs.umich.edu    uint64_t elapsed_usecs = curTick() / SimClock::Int::us;
4284200Ssaidi@eecs.umich.edu    sec = elapsed_usecs / one_million;
4293658Sktlim@umich.edu    usec = elapsed_usecs % one_million;
4303658Sktlim@umich.edu}
4312623SN/A
4322623SN/A/// Helper function to convert current elapsed time to seconds and
4332623SN/A/// nanoseconds.
4342623SN/Atemplate <class T1, class T2>
4352623SN/Avoid
4362623SN/AgetElapsedTimeNano(T1 &sec, T2 &nsec)
4372623SN/A{
4382623SN/A    uint64_t elapsed_nsecs = curTick() / SimClock::Int::ns;
4395177Sgblack@eecs.umich.edu    sec = elapsed_nsecs / one_billion;
4405177Sgblack@eecs.umich.edu    nsec = elapsed_nsecs % one_billion;
4415177Sgblack@eecs.umich.edu}
4425177Sgblack@eecs.umich.edu
4435177Sgblack@eecs.umich.edu//////////////////////////////////////////////////////////////////////
4445177Sgblack@eecs.umich.edu//
4455177Sgblack@eecs.umich.edu// The following emulation functions are generic, but need to be
4465177Sgblack@eecs.umich.edu// templated to account for differences in types, constants, etc.
4475177Sgblack@eecs.umich.edu//
4485177Sgblack@eecs.umich.edu//////////////////////////////////////////////////////////////////////
4495177Sgblack@eecs.umich.edu
4505177Sgblack@eecs.umich.edu#if NO_STAT64
4515177Sgblack@eecs.umich.edu    typedef struct stat hst_stat;
4525177Sgblack@eecs.umich.edu    typedef struct stat hst_stat64;
4535177Sgblack@eecs.umich.edu#else
4545177Sgblack@eecs.umich.edu    typedef struct stat hst_stat;
4555177Sgblack@eecs.umich.edu    typedef struct stat64 hst_stat64;
4565177Sgblack@eecs.umich.edu#endif
4575177Sgblack@eecs.umich.edu
4585177Sgblack@eecs.umich.edu//// Helper function to convert a host stat buffer to a target stat
4592623SN/A//// buffer.  Also copies the target buffer out to the simulated
4602623SN/A//// memory space.  Used by stat(), fstat(), and lstat().
4612623SN/A
4622623SN/Atemplate <typename target_stat, typename host_stat>
4634224Sgblack@eecs.umich.edustatic void
4644224Sgblack@eecs.umich.educonvertStatBuf(target_stat &tgt, host_stat *host, bool fakeTTY = false)
4654224Sgblack@eecs.umich.edu{
4664224Sgblack@eecs.umich.edu    using namespace TheISA;
4674224Sgblack@eecs.umich.edu
4684224Sgblack@eecs.umich.edu    if (fakeTTY)
4694224Sgblack@eecs.umich.edu        tgt->st_dev = 0xA;
4704224Sgblack@eecs.umich.edu    else
4714224Sgblack@eecs.umich.edu        tgt->st_dev = host->st_dev;
4724224Sgblack@eecs.umich.edu    tgt->st_dev = TheISA::htog(tgt->st_dev);
4732623SN/A    tgt->st_ino = host->st_ino;
4742623SN/A    tgt->st_ino = TheISA::htog(tgt->st_ino);
4752623SN/A    tgt->st_mode = host->st_mode;
4762623SN/A    if (fakeTTY) {
4772623SN/A        // Claim to be a character device
4782623SN/A        tgt->st_mode &= ~S_IFMT;    // Clear S_IFMT
4792623SN/A        tgt->st_mode |= S_IFCHR;    // Set S_IFCHR
4802623SN/A    }
4812623SN/A    tgt->st_mode = TheISA::htog(tgt->st_mode);
4822623SN/A    tgt->st_nlink = host->st_nlink;
4832623SN/A    tgt->st_nlink = TheISA::htog(tgt->st_nlink);
4842623SN/A    tgt->st_uid = host->st_uid;
4852623SN/A    tgt->st_uid = TheISA::htog(tgt->st_uid);
4862623SN/A    tgt->st_gid = host->st_gid;
4872623SN/A    tgt->st_gid = TheISA::htog(tgt->st_gid);
4882623SN/A    if (fakeTTY)
4892623SN/A        tgt->st_rdev = 0x880d;
4902623SN/A    else
4912623SN/A        tgt->st_rdev = host->st_rdev;
4922623SN/A    tgt->st_rdev = TheISA::htog(tgt->st_rdev);
4932623SN/A    tgt->st_size = host->st_size;
4942623SN/A    tgt->st_size = TheISA::htog(tgt->st_size);
4952623SN/A    tgt->st_atimeX = host->st_atime;
4962623SN/A    tgt->st_atimeX = TheISA::htog(tgt->st_atimeX);
4972623SN/A    tgt->st_mtimeX = host->st_mtime;
4982623SN/A    tgt->st_mtimeX = TheISA::htog(tgt->st_mtimeX);
4992623SN/A    tgt->st_ctimeX = host->st_ctime;
5002623SN/A    tgt->st_ctimeX = TheISA::htog(tgt->st_ctimeX);
5012623SN/A    // Force the block size to be 8k. This helps to ensure buffered io works
5022623SN/A    // consistently across different hosts.
5032623SN/A    tgt->st_blksize = 0x2000;
5042623SN/A    tgt->st_blksize = TheISA::htog(tgt->st_blksize);
5052623SN/A    tgt->st_blocks = host->st_blocks;
5062623SN/A    tgt->st_blocks = TheISA::htog(tgt->st_blocks);
5072623SN/A}
5082623SN/A
5092623SN/A// Same for stat64
5102623SN/A
5112623SN/Atemplate <typename target_stat, typename host_stat64>
5122623SN/Astatic void
5132623SN/AconvertStat64Buf(target_stat &tgt, host_stat64 *host, bool fakeTTY = false)
5142623SN/A{
5152623SN/A    using namespace TheISA;
5162623SN/A
5172623SN/A    convertStatBuf<target_stat, host_stat64>(tgt, host, fakeTTY);
5182623SN/A#if defined(STAT_HAVE_NSEC)
5195221Ssaidi@eecs.umich.edu    tgt->st_atime_nsec = host->st_atime_nsec;
5205221Ssaidi@eecs.umich.edu    tgt->st_atime_nsec = TheISA::htog(tgt->st_atime_nsec);
5213387Sgblack@eecs.umich.edu    tgt->st_mtime_nsec = host->st_mtime_nsec;
5223387Sgblack@eecs.umich.edu    tgt->st_mtime_nsec = TheISA::htog(tgt->st_mtime_nsec);
5232631SN/A    tgt->st_ctime_nsec = host->st_ctime_nsec;
5242663Sstever@eecs.umich.edu    tgt->st_ctime_nsec = TheISA::htog(tgt->st_ctime_nsec);
5255169Ssaidi@eecs.umich.edu#else
5262662Sstever@eecs.umich.edu    tgt->st_atime_nsec = 0;
5272623SN/A    tgt->st_mtime_nsec = 0;
5284022Sstever@eecs.umich.edu    tgt->st_ctime_nsec = 0;
5292623SN/A#endif
5302623SN/A}
5312623SN/A
5322630SN/A//Here are a couple convenience functions
5332623SN/Atemplate<class OS>
5342623SN/Astatic void
5352623SN/AcopyOutStatBuf(SETranslatingPortProxy &mem, Addr addr,
5362623SN/A        hst_stat *host, bool fakeTTY = false)
5372623SN/A{
5382623SN/A    typedef TypedBufferArg<typename OS::tgt_stat> tgt_stat_buf;
5392623SN/A    tgt_stat_buf tgt(addr);
5402623SN/A    convertStatBuf<tgt_stat_buf, hst_stat>(tgt, host, fakeTTY);
5412623SN/A    tgt.copyOut(mem);
5423658Sktlim@umich.edu}
5433658Sktlim@umich.edu
5442644Sstever@eecs.umich.edutemplate<class OS>
5452644Sstever@eecs.umich.edustatic void
5462623SN/AcopyOutStat64Buf(SETranslatingPortProxy &mem, Addr addr,
5473222Sktlim@umich.edu        hst_stat64 *host, bool fakeTTY = false)
5485099Ssaidi@eecs.umich.edu{
5493222Sktlim@umich.edu    typedef TypedBufferArg<typename OS::tgt_stat64> tgt_stat_buf;
5502623SN/A    tgt_stat_buf tgt(addr);
5512623SN/A    convertStat64Buf<tgt_stat_buf, hst_stat64>(tgt, host, fakeTTY);
5522623SN/A    tgt.copyOut(mem);
5532623SN/A}
5542644Sstever@eecs.umich.edu
5552623SN/A/// Target ioctl() handler.  For the most part, programs call ioctl()
5562623SN/A/// only to find out if their stdout is a tty, to determine whether to
5572623SN/A/// do line or block buffering.  We always claim that output fds are
5582631SN/A/// not TTYs to provide repeatable results.
5592631SN/Atemplate <class OS>
5602631SN/ASyscallReturn
5612631SN/AioctlFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
5622631SN/A          ThreadContext *tc)
5632631SN/A{
5642623SN/A    int index = 0;
5652623SN/A    int tgt_fd = process->getSyscallArg(tc, index);
5662623SN/A    unsigned req = process->getSyscallArg(tc, index);
5672623SN/A
5683349Sbinkertn@umich.edu    DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", tgt_fd, req);
5692623SN/A
5705221Ssaidi@eecs.umich.edu    FDEntry *fde = process->getFDEntry(tgt_fd);
5715221Ssaidi@eecs.umich.edu
5722623SN/A    if (fde == NULL) {
5732623SN/A        // doesn't map to any simulator fd: not a valid target fd
5744870Sstever@eecs.umich.edu        return -EBADF;
5752623SN/A    }
5762798Sktlim@umich.edu
5772623SN/A    if (fde->driver != NULL) {
5782644Sstever@eecs.umich.edu        return fde->driver->ioctl(process, tc, req);
5795099Ssaidi@eecs.umich.edu    }
5803222Sktlim@umich.edu
5813222Sktlim@umich.edu    if (OS::isTtyReq(req)) {
5822839Sktlim@umich.edu        return -ENOTTY;
5833658Sktlim@umich.edu    }
5843658Sktlim@umich.edu
5853658Sktlim@umich.edu    warn("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ \n",
5862839Sktlim@umich.edu         tgt_fd, req, tc->pcState());
5872798Sktlim@umich.edu    return -ENOTTY;
5882798Sktlim@umich.edu}
5892798Sktlim@umich.edu
5902623SN/Atemplate <class OS>
5912644Sstever@eecs.umich.edustatic SyscallReturn
5922623SN/AopenFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
5932623SN/A         ThreadContext *tc, int index)
5943170Sstever@eecs.umich.edu{
5953170Sstever@eecs.umich.edu    std::string path;
5963170Sstever@eecs.umich.edu
5973170Sstever@eecs.umich.edu    if (!tc->getMemProxy().tryReadString(path,
5982644Sstever@eecs.umich.edu                process->getSyscallArg(tc, index)))
5993170Sstever@eecs.umich.edu        return -EFAULT;
6003170Sstever@eecs.umich.edu
6013170Sstever@eecs.umich.edu    int tgtFlags = process->getSyscallArg(tc, index);
6023170Sstever@eecs.umich.edu    int mode = process->getSyscallArg(tc, index);
6033170Sstever@eecs.umich.edu    int hostFlags = 0;
6043170Sstever@eecs.umich.edu
6053170Sstever@eecs.umich.edu    // translate open flags
6063170Sstever@eecs.umich.edu    for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) {
6074998Sgblack@eecs.umich.edu        if (tgtFlags & OS::openFlagTable[i].tgtFlag) {
6084998Sgblack@eecs.umich.edu            tgtFlags &= ~OS::openFlagTable[i].tgtFlag;
6094998Sgblack@eecs.umich.edu            hostFlags |= OS::openFlagTable[i].hostFlag;
6104998Sgblack@eecs.umich.edu        }
6115001Sgblack@eecs.umich.edu    }
6125001Sgblack@eecs.umich.edu
6135001Sgblack@eecs.umich.edu    // any target flags left?
6145001Sgblack@eecs.umich.edu    if (tgtFlags != 0)
6153170Sstever@eecs.umich.edu        warn("Syscall: open: cannot decode flags 0x%x", tgtFlags);
6164998Sgblack@eecs.umich.edu
6172644Sstever@eecs.umich.edu#ifdef __CYGWIN32__
6185103Ssaidi@eecs.umich.edu    hostFlags |= O_BINARY;
6195103Ssaidi@eecs.umich.edu#endif
6205103Ssaidi@eecs.umich.edu
6215103Ssaidi@eecs.umich.edu    // Adjust path for current working directory
6222644Sstever@eecs.umich.edu    path = process->fullPath(path);
6232644Sstever@eecs.umich.edu
6242623SN/A    DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str());
6252623SN/A
6262623SN/A    if (startswith(path, "/dev/")) {
6274998Sgblack@eecs.umich.edu        std::string filename = path.substr(strlen("/dev/"));
6284998Sgblack@eecs.umich.edu        if (filename == "sysdev0") {
6294998Sgblack@eecs.umich.edu            // This is a memory-mapped high-resolution timer device on Alpha.
6304998Sgblack@eecs.umich.edu            // We don't support it, so just punt.
6315001Sgblack@eecs.umich.edu            warn("Ignoring open(%s, ...)\n", path);
6325001Sgblack@eecs.umich.edu            return -ENOENT;
6335001Sgblack@eecs.umich.edu        }
6345001Sgblack@eecs.umich.edu
6355001Sgblack@eecs.umich.edu        EmulatedDriver *drv = process->findDriver(filename);
6364998Sgblack@eecs.umich.edu        if (drv != NULL) {
6372644Sstever@eecs.umich.edu            // the driver's open method will allocate a fd from the
6385103Ssaidi@eecs.umich.edu            // process if necessary.
6395103Ssaidi@eecs.umich.edu            return drv->open(process, tc, mode, hostFlags);
6405103Ssaidi@eecs.umich.edu        }
6415103Ssaidi@eecs.umich.edu
6422644Sstever@eecs.umich.edu        // fall through here for pass through to host devices, such as
6432623SN/A        // /dev/zero
6443658Sktlim@umich.edu    }
6453658Sktlim@umich.edu
6463658Sktlim@umich.edu    int fd;
6472623SN/A    int local_errno;
6482623SN/A    if (startswith(path, "/proc/") || startswith(path, "/system/") ||
6492948Ssaidi@eecs.umich.edu        startswith(path, "/platform/") || startswith(path, "/sys/")) {
6502948Ssaidi@eecs.umich.edu        // It's a proc/sys entry and requires special handling
6512948Ssaidi@eecs.umich.edu        fd = OS::openSpecialFile(path, process, tc);
6522948Ssaidi@eecs.umich.edu        local_errno = ENOENT;
6532948Ssaidi@eecs.umich.edu     } else {
6542623SN/A        // open the file
6552623SN/A        fd = open(path.c_str(), hostFlags, mode);
6563349Sbinkertn@umich.edu        local_errno = errno;
6572623SN/A     }
6584986Ssaidi@eecs.umich.edu
6593310Srdreslin@umich.edu    if (fd == -1)
6604584Ssaidi@eecs.umich.edu        return -local_errno;
6612948Ssaidi@eecs.umich.edu
6623495Sktlim@umich.edu    return process->allocFD(fd, path.c_str(), hostFlags, mode, false);
6633310Srdreslin@umich.edu}
6643310Srdreslin@umich.edu
6653495Sktlim@umich.edu/// Target open() handler.
6662948Ssaidi@eecs.umich.edutemplate <class OS>
6673310Srdreslin@umich.eduSyscallReturn
6683310Srdreslin@umich.eduopenFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
6694870Sstever@eecs.umich.edu         ThreadContext *tc)
6704433Ssaidi@eecs.umich.edu{
6714433Ssaidi@eecs.umich.edu    return openFunc<OS>(desc, callnum, process, tc, 0);
6724433Ssaidi@eecs.umich.edu}
6734433Ssaidi@eecs.umich.edu
6744433Ssaidi@eecs.umich.edu/// Target openat() handler.
6754433Ssaidi@eecs.umich.edutemplate <class OS>
6763310Srdreslin@umich.eduSyscallReturn
6774433Ssaidi@eecs.umich.eduopenatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
6784433Ssaidi@eecs.umich.edu         ThreadContext *tc)
6792623SN/A{
6802623SN/A    int index = 0;
6812657Ssaidi@eecs.umich.edu    int dirfd = process->getSyscallArg(tc, index);
6822623SN/A    if (dirfd != OS::TGT_AT_FDCWD)
6832623SN/A        warn("openat: first argument not AT_FDCWD; unlikely to work");
6842623SN/A    return openFunc<OS>(desc, callnum, process, tc, 1);
6852623SN/A}
6862623SN/A
6872623SN/A/// Target unlinkat() handler.
6883349Sbinkertn@umich.edutemplate <class OS>
6892657Ssaidi@eecs.umich.eduSyscallReturn
6902657Ssaidi@eecs.umich.eduunlinkatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
6912657Ssaidi@eecs.umich.edu             ThreadContext *tc)
6922657Ssaidi@eecs.umich.edu{
6932623SN/A    int index = 0;
6942623SN/A    int dirfd = process->getSyscallArg(tc, index);
6952623SN/A    if (dirfd != OS::TGT_AT_FDCWD)
6963349Sbinkertn@umich.edu        warn("unlinkat: first argument not AT_FDCWD; unlikely to work");
6972623SN/A
6982623SN/A    return unlinkHelper(desc, callnum, process, tc, 1);
6992623SN/A}
7004870Sstever@eecs.umich.edu
7012623SN/A/// Target facessat() handler
7022623SN/Atemplate <class OS>
7032623SN/ASyscallReturn
7045099Ssaidi@eecs.umich.edufaccessatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
7053222Sktlim@umich.edu        ThreadContext *tc)
7063184Srdreslin@umich.edu{
7072623SN/A    int index = 0;
7082623SN/A    int dirfd = process->getSyscallArg(tc, index);
7094998Sgblack@eecs.umich.edu    if (dirfd != OS::TGT_AT_FDCWD)
7104998Sgblack@eecs.umich.edu        warn("faccessat: first argument not AT_FDCWD; unlikely to work");
7114998Sgblack@eecs.umich.edu    return accessFunc(desc, callnum, process, tc, 1);
7125001Sgblack@eecs.umich.edu}
7135001Sgblack@eecs.umich.edu
7145001Sgblack@eecs.umich.edu/// Target readlinkat() handler
7155001Sgblack@eecs.umich.edutemplate <class OS>
7165001Sgblack@eecs.umich.eduSyscallReturn
7174998Sgblack@eecs.umich.edureadlinkatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
7184878Sstever@eecs.umich.edu        ThreadContext *tc)
7193170Sstever@eecs.umich.edu{
7203170Sstever@eecs.umich.edu    int index = 0;
7213170Sstever@eecs.umich.edu    int dirfd = process->getSyscallArg(tc, index);
7222644Sstever@eecs.umich.edu    if (dirfd != OS::TGT_AT_FDCWD)
7232644Sstever@eecs.umich.edu        warn("openat: first argument not AT_FDCWD; unlikely to work");
7242644Sstever@eecs.umich.edu    return readlinkFunc(desc, callnum, process, tc, 1);
7253184Srdreslin@umich.edu}
7263227Sktlim@umich.edu
7273201Shsul@eecs.umich.edu/// Target renameat() handler.
7283201Shsul@eecs.umich.edutemplate <class OS>
7293201Shsul@eecs.umich.eduSyscallReturn
7303201Shsul@eecs.umich.edurenameatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
7313201Shsul@eecs.umich.edu             ThreadContext *tc)
7323201Shsul@eecs.umich.edu{
7333201Shsul@eecs.umich.edu    int index = 0;
7342644Sstever@eecs.umich.edu
7352623SN/A    int olddirfd = process->getSyscallArg(tc, index);
7362623SN/A    if (olddirfd != OS::TGT_AT_FDCWD)
7372623SN/A        warn("renameat: first argument not AT_FDCWD; unlikely to work");
7382798Sktlim@umich.edu
7392839Sktlim@umich.edu    std::string old_name;
7402798Sktlim@umich.edu
7412839Sktlim@umich.edu    if (!tc->getMemProxy().tryReadString(old_name,
7422901Ssaidi@eecs.umich.edu                                         process->getSyscallArg(tc, index)))
7432839Sktlim@umich.edu        return -EFAULT;
7442798Sktlim@umich.edu
7452623SN/A    int newdirfd = process->getSyscallArg(tc, index);
7464192Sktlim@umich.edu    if (newdirfd != OS::TGT_AT_FDCWD)
7474192Sktlim@umich.edu        warn("renameat: third argument not AT_FDCWD; unlikely to work");
7484192Sktlim@umich.edu
7494192Sktlim@umich.edu    std::string new_name;
7504192Sktlim@umich.edu
7514192Sktlim@umich.edu    if (!tc->getMemProxy().tryReadString(new_name,
7524192Sktlim@umich.edu                                         process->getSyscallArg(tc, index)))
7534192Sktlim@umich.edu        return -EFAULT;
7544192Sktlim@umich.edu
7554192Sktlim@umich.edu    // Adjust path for current working directory
7564192Sktlim@umich.edu    old_name = process->fullPath(old_name);
7574192Sktlim@umich.edu    new_name = process->fullPath(new_name);
7582623SN/A
7593349Sbinkertn@umich.edu    int result = rename(old_name.c_str(), new_name.c_str());
7602623SN/A    return (result == -1) ? -errno : result;
7614986Ssaidi@eecs.umich.edu}
7623310Srdreslin@umich.edu
7634584Ssaidi@eecs.umich.edu/// Target sysinfo() handler.
7642948Ssaidi@eecs.umich.edutemplate <class OS>
7653495Sktlim@umich.eduSyscallReturn
7663310Srdreslin@umich.edusysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
7673310Srdreslin@umich.edu         ThreadContext *tc)
7683495Sktlim@umich.edu{
7692948Ssaidi@eecs.umich.edu
7703310Srdreslin@umich.edu    int index = 0;
7713310Srdreslin@umich.edu    TypedBufferArg<typename OS::tgt_sysinfo>
7724870Sstever@eecs.umich.edu        sysinfo(process->getSyscallArg(tc, index));
7734433Ssaidi@eecs.umich.edu
7744433Ssaidi@eecs.umich.edu    sysinfo->uptime=seconds_since_epoch;
7754433Ssaidi@eecs.umich.edu    sysinfo->totalram=process->system->memSize();
7764433Ssaidi@eecs.umich.edu
7774433Ssaidi@eecs.umich.edu    sysinfo.copyOut(tc->getMemProxy());
7784433Ssaidi@eecs.umich.edu
7793310Srdreslin@umich.edu    return 0;
7804433Ssaidi@eecs.umich.edu}
7814433Ssaidi@eecs.umich.edu
7822948Ssaidi@eecs.umich.edu/// Target chmod() handler.
7832948Ssaidi@eecs.umich.edutemplate <class OS>
7842948Ssaidi@eecs.umich.eduSyscallReturn
7852948Ssaidi@eecs.umich.educhmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
7862948Ssaidi@eecs.umich.edu          ThreadContext *tc)
7872630SN/A{
7882623SN/A    std::string path;
7892623SN/A
7902657Ssaidi@eecs.umich.edu    int index = 0;
7912623SN/A    if (!tc->getMemProxy().tryReadString(path,
7922623SN/A                process->getSyscallArg(tc, index))) {
7932623SN/A        return -EFAULT;
7942623SN/A    }
7952623SN/A
7962623SN/A    uint32_t mode = process->getSyscallArg(tc, index);
7973349Sbinkertn@umich.edu    mode_t hostMode = 0;
7982657Ssaidi@eecs.umich.edu
7992657Ssaidi@eecs.umich.edu    // XXX translate mode flags via OS::something???
8003170Sstever@eecs.umich.edu    hostMode = mode;
8012657Ssaidi@eecs.umich.edu
8022657Ssaidi@eecs.umich.edu    // Adjust path for current working directory
8032623SN/A    path = process->fullPath(path);
8042623SN/A
8055103Ssaidi@eecs.umich.edu    // do the chmod
8065103Ssaidi@eecs.umich.edu    int result = chmod(path.c_str(), hostMode);
8075103Ssaidi@eecs.umich.edu    if (result < 0)
8085103Ssaidi@eecs.umich.edu        return -errno;
8095103Ssaidi@eecs.umich.edu
8105103Ssaidi@eecs.umich.edu    return 0;
8115103Ssaidi@eecs.umich.edu}
8125103Ssaidi@eecs.umich.edu
8135103Ssaidi@eecs.umich.edu
8145103Ssaidi@eecs.umich.edu/// Target fchmod() handler.
8155103Ssaidi@eecs.umich.edutemplate <class OS>
8165103Ssaidi@eecs.umich.eduSyscallReturn
8175103Ssaidi@eecs.umich.edufchmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
8185103Ssaidi@eecs.umich.edu           ThreadContext *tc)
8195103Ssaidi@eecs.umich.edu{
8205103Ssaidi@eecs.umich.edu    int index = 0;
8215103Ssaidi@eecs.umich.edu    int tgt_fd = process->getSyscallArg(tc, index);
8225103Ssaidi@eecs.umich.edu    uint32_t mode = process->getSyscallArg(tc, index);
8232623SN/A
8242623SN/A    int sim_fd = process->getSimFD(tgt_fd);
8252623SN/A    if (sim_fd < 0)
8262623SN/A        return -EBADF;
8272623SN/A
8284762Snate@binkert.org    mode_t hostMode = 0;
8294762Snate@binkert.org
8302623SN/A    // XXX translate mode flags via OS::someting???
8312623SN/A    hostMode = mode;
8324762Snate@binkert.org
8332623SN/A    // do the fchmod
8342623SN/A    int result = fchmod(sim_fd, hostMode);
8352623SN/A    if (result < 0)
8362623SN/A        return -errno;
8372623SN/A
8383119Sktlim@umich.edu    return 0;
8392623SN/A}
8402623SN/A
8413661Srdreslin@umich.edu/// Target mremap() handler.
8422623SN/Atemplate <class OS>
8432623SN/ASyscallReturn
8442901Ssaidi@eecs.umich.edumremapFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc)
8453170Sstever@eecs.umich.edu{
8464776Sgblack@eecs.umich.edu    int index = 0;
8472623SN/A    Addr start = process->getSyscallArg(tc, index);
8482623SN/A    uint64_t old_length = process->getSyscallArg(tc, index);
8492623SN/A    uint64_t new_length = process->getSyscallArg(tc, index);
8504997Sgblack@eecs.umich.edu    uint64_t flags = process->getSyscallArg(tc, index);
8512623SN/A    uint64_t provided_address = 0;
8523617Sbinkertn@umich.edu    bool use_provided_address = flags & OS::TGT_MREMAP_FIXED;
8533617Sbinkertn@umich.edu
8543617Sbinkertn@umich.edu    if (use_provided_address)
8552623SN/A        provided_address = process->getSyscallArg(tc, index);
8564762Snate@binkert.org
8574762Snate@binkert.org    if ((start % TheISA::PageBytes != 0) ||
8584762Snate@binkert.org        (provided_address % TheISA::PageBytes != 0)) {
8592623SN/A        warn("mremap failing: arguments not page aligned");
8602623SN/A        return -EINVAL;
8612623SN/A    }
8622623SN/A
8632623SN/A    new_length = roundUp(new_length, TheISA::PageBytes);
864
865    if (new_length > old_length) {
866        if ((start + old_length) == process->mmap_end &&
867            (!use_provided_address || provided_address == start)) {
868            uint64_t diff = new_length - old_length;
869            process->allocateMem(process->mmap_end, diff);
870            process->mmap_end += diff;
871            return start;
872        } else {
873            if (!use_provided_address && !(flags & OS::TGT_MREMAP_MAYMOVE)) {
874                warn("can't remap here and MREMAP_MAYMOVE flag not set\n");
875                return -ENOMEM;
876            } else {
877                uint64_t new_start = use_provided_address ?
878                    provided_address : process->mmap_end;
879                process->pTable->remap(start, old_length, new_start);
880                warn("mremapping to new vaddr %08p-%08p, adding %d\n",
881                     new_start, new_start + new_length,
882                     new_length - old_length);
883                // add on the remaining unallocated pages
884                process->allocateMem(new_start + old_length,
885                                     new_length - old_length,
886                                     use_provided_address /* clobber */);
887                if (!use_provided_address)
888                    process->mmap_end += new_length;
889                if (use_provided_address &&
890                    new_start + new_length > process->mmap_end) {
891                    // something fishy going on here, at least notify the user
892                    // @todo: increase mmap_end?
893                    warn("mmap region limit exceeded with MREMAP_FIXED\n");
894                }
895                warn("returning %08p as start\n", new_start);
896                return new_start;
897            }
898        }
899    } else {
900        if (use_provided_address && provided_address != start)
901            process->pTable->remap(start, new_length, provided_address);
902        process->pTable->unmap(start + new_length, old_length - new_length);
903        return use_provided_address ? provided_address : start;
904    }
905}
906
907/// Target stat() handler.
908template <class OS>
909SyscallReturn
910statFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
911         ThreadContext *tc)
912{
913    std::string path;
914
915    int index = 0;
916    if (!tc->getMemProxy().tryReadString(path,
917                process->getSyscallArg(tc, index))) {
918        return -EFAULT;
919    }
920    Addr bufPtr = process->getSyscallArg(tc, index);
921
922    // Adjust path for current working directory
923    path = process->fullPath(path);
924
925    struct stat hostBuf;
926    int result = stat(path.c_str(), &hostBuf);
927
928    if (result < 0)
929        return -errno;
930
931    copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
932
933    return 0;
934}
935
936
937/// Target stat64() handler.
938template <class OS>
939SyscallReturn
940stat64Func(SyscallDesc *desc, int callnum, LiveProcess *process,
941           ThreadContext *tc)
942{
943    std::string path;
944
945    int index = 0;
946    if (!tc->getMemProxy().tryReadString(path,
947                process->getSyscallArg(tc, index)))
948        return -EFAULT;
949    Addr bufPtr = process->getSyscallArg(tc, index);
950
951    // Adjust path for current working directory
952    path = process->fullPath(path);
953
954#if NO_STAT64
955    struct stat  hostBuf;
956    int result = stat(path.c_str(), &hostBuf);
957#else
958    struct stat64 hostBuf;
959    int result = stat64(path.c_str(), &hostBuf);
960#endif
961
962    if (result < 0)
963        return -errno;
964
965    copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
966
967    return 0;
968}
969
970
971/// Target fstatat64() handler.
972template <class OS>
973SyscallReturn
974fstatat64Func(SyscallDesc *desc, int callnum, LiveProcess *process,
975              ThreadContext *tc)
976{
977    int index = 0;
978    int dirfd = process->getSyscallArg(tc, index);
979    if (dirfd != OS::TGT_AT_FDCWD)
980        warn("fstatat64: first argument not AT_FDCWD; unlikely to work");
981
982    std::string path;
983    if (!tc->getMemProxy().tryReadString(path,
984                process->getSyscallArg(tc, index)))
985        return -EFAULT;
986    Addr bufPtr = process->getSyscallArg(tc, index);
987
988    // Adjust path for current working directory
989    path = process->fullPath(path);
990
991#if NO_STAT64
992    struct stat  hostBuf;
993    int result = stat(path.c_str(), &hostBuf);
994#else
995    struct stat64 hostBuf;
996    int result = stat64(path.c_str(), &hostBuf);
997#endif
998
999    if (result < 0)
1000        return -errno;
1001
1002    copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
1003
1004    return 0;
1005}
1006
1007
1008/// Target fstat64() handler.
1009template <class OS>
1010SyscallReturn
1011fstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process,
1012            ThreadContext *tc)
1013{
1014    int index = 0;
1015    int tgt_fd = process->getSyscallArg(tc, index);
1016    Addr bufPtr = process->getSyscallArg(tc, index);
1017
1018    int sim_fd = process->getSimFD(tgt_fd);
1019    if (sim_fd < 0)
1020        return -EBADF;
1021
1022#if NO_STAT64
1023    struct stat  hostBuf;
1024    int result = fstat(sim_fd, &hostBuf);
1025#else
1026    struct stat64  hostBuf;
1027    int result = fstat64(sim_fd, &hostBuf);
1028#endif
1029
1030    if (result < 0)
1031        return -errno;
1032
1033    copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (sim_fd == 1));
1034
1035    return 0;
1036}
1037
1038
1039/// Target lstat() handler.
1040template <class OS>
1041SyscallReturn
1042lstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1043          ThreadContext *tc)
1044{
1045    std::string path;
1046
1047    int index = 0;
1048    if (!tc->getMemProxy().tryReadString(path,
1049                process->getSyscallArg(tc, index))) {
1050        return -EFAULT;
1051    }
1052    Addr bufPtr = process->getSyscallArg(tc, index);
1053
1054    // Adjust path for current working directory
1055    path = process->fullPath(path);
1056
1057    struct stat hostBuf;
1058    int result = lstat(path.c_str(), &hostBuf);
1059
1060    if (result < 0)
1061        return -errno;
1062
1063    copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
1064
1065    return 0;
1066}
1067
1068/// Target lstat64() handler.
1069template <class OS>
1070SyscallReturn
1071lstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process,
1072            ThreadContext *tc)
1073{
1074    std::string path;
1075
1076    int index = 0;
1077    if (!tc->getMemProxy().tryReadString(path,
1078                process->getSyscallArg(tc, index))) {
1079        return -EFAULT;
1080    }
1081    Addr bufPtr = process->getSyscallArg(tc, index);
1082
1083    // Adjust path for current working directory
1084    path = process->fullPath(path);
1085
1086#if NO_STAT64
1087    struct stat hostBuf;
1088    int result = lstat(path.c_str(), &hostBuf);
1089#else
1090    struct stat64 hostBuf;
1091    int result = lstat64(path.c_str(), &hostBuf);
1092#endif
1093
1094    if (result < 0)
1095        return -errno;
1096
1097    copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
1098
1099    return 0;
1100}
1101
1102/// Target fstat() handler.
1103template <class OS>
1104SyscallReturn
1105fstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1106          ThreadContext *tc)
1107{
1108    int index = 0;
1109    int tgt_fd = process->getSyscallArg(tc, index);
1110    Addr bufPtr = process->getSyscallArg(tc, index);
1111
1112    DPRINTF_SYSCALL(Verbose, "fstat(%d, ...)\n", tgt_fd);
1113
1114    int sim_fd = process->getSimFD(tgt_fd);
1115    if (sim_fd < 0)
1116        return -EBADF;
1117
1118    struct stat hostBuf;
1119    int result = fstat(sim_fd, &hostBuf);
1120
1121    if (result < 0)
1122        return -errno;
1123
1124    copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (sim_fd == 1));
1125
1126    return 0;
1127}
1128
1129
1130/// Target statfs() handler.
1131template <class OS>
1132SyscallReturn
1133statfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1134           ThreadContext *tc)
1135{
1136    std::string path;
1137
1138    int index = 0;
1139    if (!tc->getMemProxy().tryReadString(path,
1140                process->getSyscallArg(tc, index))) {
1141        return -EFAULT;
1142    }
1143    Addr bufPtr = process->getSyscallArg(tc, index);
1144
1145    // Adjust path for current working directory
1146    path = process->fullPath(path);
1147
1148    struct statfs hostBuf;
1149    int result = statfs(path.c_str(), &hostBuf);
1150
1151    if (result < 0)
1152        return -errno;
1153
1154    OS::copyOutStatfsBuf(tc->getMemProxy(), bufPtr, &hostBuf);
1155
1156    return 0;
1157}
1158
1159
1160/// Target fstatfs() handler.
1161template <class OS>
1162SyscallReturn
1163fstatfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1164            ThreadContext *tc)
1165{
1166    int index = 0;
1167    int tgt_fd = process->getSyscallArg(tc, index);
1168    Addr bufPtr = process->getSyscallArg(tc, index);
1169
1170    int sim_fd = process->getSimFD(tgt_fd);
1171    if (sim_fd < 0)
1172        return -EBADF;
1173
1174    struct statfs hostBuf;
1175    int result = fstatfs(sim_fd, &hostBuf);
1176
1177    if (result < 0)
1178        return -errno;
1179
1180    OS::copyOutStatfsBuf(tc->getMemProxy(), bufPtr, &hostBuf);
1181
1182    return 0;
1183}
1184
1185
1186/// Target writev() handler.
1187template <class OS>
1188SyscallReturn
1189writevFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1190           ThreadContext *tc)
1191{
1192    int index = 0;
1193    int tgt_fd = process->getSyscallArg(tc, index);
1194
1195    int sim_fd = process->getSimFD(tgt_fd);
1196    if (sim_fd < 0)
1197        return -EBADF;
1198
1199    SETranslatingPortProxy &p = tc->getMemProxy();
1200    uint64_t tiov_base = process->getSyscallArg(tc, index);
1201    size_t count = process->getSyscallArg(tc, index);
1202    struct iovec hiov[count];
1203    for (size_t i = 0; i < count; ++i) {
1204        typename OS::tgt_iovec tiov;
1205
1206        p.readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec),
1207                   (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec));
1208        hiov[i].iov_len = TheISA::gtoh(tiov.iov_len);
1209        hiov[i].iov_base = new char [hiov[i].iov_len];
1210        p.readBlob(TheISA::gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base,
1211                   hiov[i].iov_len);
1212    }
1213
1214    int result = writev(sim_fd, hiov, count);
1215
1216    for (size_t i = 0; i < count; ++i)
1217        delete [] (char *)hiov[i].iov_base;
1218
1219    if (result < 0)
1220        return -errno;
1221
1222    return result;
1223}
1224
1225
1226/// Target mmap() handler.
1227///
1228/// We don't really handle mmap().  If the target is mmaping an
1229/// anonymous region or /dev/zero, we can get away with doing basically
1230/// nothing (since memory is initialized to zero and the simulator
1231/// doesn't really check addresses anyway).
1232///
1233template <class OS>
1234SyscallReturn
1235mmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
1236{
1237    int index = 0;
1238    Addr start = p->getSyscallArg(tc, index);
1239    uint64_t length = p->getSyscallArg(tc, index);
1240    index++; // int prot = p->getSyscallArg(tc, index);
1241    int flags = p->getSyscallArg(tc, index);
1242    int tgt_fd = p->getSyscallArg(tc, index);
1243    int offset = p->getSyscallArg(tc, index);
1244
1245    if (length > 0x100000000ULL)
1246        warn("mmap length argument %#x is unreasonably large.\n", length);
1247
1248    if (!(flags & OS::TGT_MAP_ANONYMOUS)) {
1249        FDEntry *fde = p->getFDEntry(tgt_fd);
1250        if (!fde || fde->fd < 0) {
1251            warn("mmap failing: target fd %d is not valid\n", tgt_fd);
1252            return -EBADF;
1253        }
1254
1255        if (fde->filename != "/dev/zero") {
1256            // This is very likely broken, but leave a warning here
1257            // (rather than panic) in case /dev/zero is known by
1258            // another name on some platform
1259            warn("allowing mmap of file %s; mmap not supported on files"
1260                 " other than /dev/zero\n", fde->filename);
1261        }
1262    }
1263
1264    length = roundUp(length, TheISA::PageBytes);
1265
1266    if ((start  % TheISA::PageBytes) != 0 ||
1267        (offset % TheISA::PageBytes) != 0) {
1268        warn("mmap failing: arguments not page-aligned: "
1269             "start 0x%x offset 0x%x",
1270             start, offset);
1271        return -EINVAL;
1272    }
1273
1274    // are we ok with clobbering existing mappings?  only set this to
1275    // true if the user has been warned.
1276    bool clobber = false;
1277
1278    // try to use the caller-provided address if there is one
1279    bool use_provided_address = (start != 0);
1280
1281    if (use_provided_address) {
1282        // check to see if the desired address is already in use
1283        if (!p->pTable->isUnmapped(start, length)) {
1284            // there are existing mappings in the desired range
1285            // whether we clobber them or not depends on whether the caller
1286            // specified MAP_FIXED
1287            if (flags & OS::TGT_MAP_FIXED) {
1288                // MAP_FIXED specified: map attempt fails
1289                return -EINVAL;
1290            } else {
1291                // MAP_FIXED not specified: ignore suggested start address
1292                warn("mmap: ignoring suggested map address 0x%x\n", start);
1293                use_provided_address = false;
1294            }
1295        }
1296    }
1297
1298    if (!use_provided_address) {
1299        // no address provided, or provided address unusable:
1300        // pick next address from our "mmap region"
1301        if (OS::mmapGrowsDown()) {
1302            start = p->mmap_end - length;
1303            p->mmap_end = start;
1304        } else {
1305            start = p->mmap_end;
1306            p->mmap_end += length;
1307        }
1308    }
1309
1310    p->allocateMem(start, length, clobber);
1311
1312    return start;
1313}
1314
1315/// Target getrlimit() handler.
1316template <class OS>
1317SyscallReturn
1318getrlimitFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1319        ThreadContext *tc)
1320{
1321    int index = 0;
1322    unsigned resource = process->getSyscallArg(tc, index);
1323    TypedBufferArg<typename OS::rlimit> rlp(process->getSyscallArg(tc, index));
1324
1325    switch (resource) {
1326        case OS::TGT_RLIMIT_STACK:
1327            // max stack size in bytes: make up a number (8MB for now)
1328            rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024;
1329            rlp->rlim_cur = TheISA::htog(rlp->rlim_cur);
1330            rlp->rlim_max = TheISA::htog(rlp->rlim_max);
1331            break;
1332
1333        case OS::TGT_RLIMIT_DATA:
1334            // max data segment size in bytes: make up a number
1335            rlp->rlim_cur = rlp->rlim_max = 256 * 1024 * 1024;
1336            rlp->rlim_cur = TheISA::htog(rlp->rlim_cur);
1337            rlp->rlim_max = TheISA::htog(rlp->rlim_max);
1338            break;
1339
1340        default:
1341            warn("getrlimit: unimplemented resource %d", resource);
1342            return -EINVAL;
1343            break;
1344    }
1345
1346    rlp.copyOut(tc->getMemProxy());
1347    return 0;
1348}
1349
1350/// Target clock_gettime() function.
1351template <class OS>
1352SyscallReturn
1353clock_gettimeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
1354{
1355    int index = 1;
1356    //int clk_id = p->getSyscallArg(tc, index);
1357    TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index));
1358
1359    getElapsedTimeNano(tp->tv_sec, tp->tv_nsec);
1360    tp->tv_sec += seconds_since_epoch;
1361    tp->tv_sec = TheISA::htog(tp->tv_sec);
1362    tp->tv_nsec = TheISA::htog(tp->tv_nsec);
1363
1364    tp.copyOut(tc->getMemProxy());
1365
1366    return 0;
1367}
1368
1369/// Target clock_getres() function.
1370template <class OS>
1371SyscallReturn
1372clock_getresFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
1373{
1374    int index = 1;
1375    TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index));
1376
1377    // Set resolution at ns, which is what clock_gettime() returns
1378    tp->tv_sec = 0;
1379    tp->tv_nsec = 1;
1380
1381    tp.copyOut(tc->getMemProxy());
1382
1383    return 0;
1384}
1385
1386/// Target gettimeofday() handler.
1387template <class OS>
1388SyscallReturn
1389gettimeofdayFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1390        ThreadContext *tc)
1391{
1392    int index = 0;
1393    TypedBufferArg<typename OS::timeval> tp(process->getSyscallArg(tc, index));
1394
1395    getElapsedTimeMicro(tp->tv_sec, tp->tv_usec);
1396    tp->tv_sec += seconds_since_epoch;
1397    tp->tv_sec = TheISA::htog(tp->tv_sec);
1398    tp->tv_usec = TheISA::htog(tp->tv_usec);
1399
1400    tp.copyOut(tc->getMemProxy());
1401
1402    return 0;
1403}
1404
1405
1406/// Target utimes() handler.
1407template <class OS>
1408SyscallReturn
1409utimesFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1410           ThreadContext *tc)
1411{
1412    std::string path;
1413
1414    int index = 0;
1415    if (!tc->getMemProxy().tryReadString(path,
1416                process->getSyscallArg(tc, index))) {
1417        return -EFAULT;
1418    }
1419
1420    TypedBufferArg<typename OS::timeval [2]>
1421        tp(process->getSyscallArg(tc, index));
1422    tp.copyIn(tc->getMemProxy());
1423
1424    struct timeval hostTimeval[2];
1425    for (int i = 0; i < 2; ++i)
1426    {
1427        hostTimeval[i].tv_sec = TheISA::gtoh((*tp)[i].tv_sec);
1428        hostTimeval[i].tv_usec = TheISA::gtoh((*tp)[i].tv_usec);
1429    }
1430
1431    // Adjust path for current working directory
1432    path = process->fullPath(path);
1433
1434    int result = utimes(path.c_str(), hostTimeval);
1435
1436    if (result < 0)
1437        return -errno;
1438
1439    return 0;
1440}
1441/// Target getrusage() function.
1442template <class OS>
1443SyscallReturn
1444getrusageFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1445              ThreadContext *tc)
1446{
1447    int index = 0;
1448    int who = process->getSyscallArg(tc, index); // THREAD, SELF, or CHILDREN
1449    TypedBufferArg<typename OS::rusage> rup(process->getSyscallArg(tc, index));
1450
1451    rup->ru_utime.tv_sec = 0;
1452    rup->ru_utime.tv_usec = 0;
1453    rup->ru_stime.tv_sec = 0;
1454    rup->ru_stime.tv_usec = 0;
1455    rup->ru_maxrss = 0;
1456    rup->ru_ixrss = 0;
1457    rup->ru_idrss = 0;
1458    rup->ru_isrss = 0;
1459    rup->ru_minflt = 0;
1460    rup->ru_majflt = 0;
1461    rup->ru_nswap = 0;
1462    rup->ru_inblock = 0;
1463    rup->ru_oublock = 0;
1464    rup->ru_msgsnd = 0;
1465    rup->ru_msgrcv = 0;
1466    rup->ru_nsignals = 0;
1467    rup->ru_nvcsw = 0;
1468    rup->ru_nivcsw = 0;
1469
1470    switch (who) {
1471      case OS::TGT_RUSAGE_SELF:
1472        getElapsedTimeMicro(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec);
1473        rup->ru_utime.tv_sec = TheISA::htog(rup->ru_utime.tv_sec);
1474        rup->ru_utime.tv_usec = TheISA::htog(rup->ru_utime.tv_usec);
1475        break;
1476
1477      case OS::TGT_RUSAGE_CHILDREN:
1478        // do nothing.  We have no child processes, so they take no time.
1479        break;
1480
1481      default:
1482        // don't really handle THREAD or CHILDREN, but just warn and
1483        // plow ahead
1484        warn("getrusage() only supports RUSAGE_SELF.  Parameter %d ignored.",
1485             who);
1486    }
1487
1488    rup.copyOut(tc->getMemProxy());
1489
1490    return 0;
1491}
1492
1493/// Target times() function.
1494template <class OS>
1495SyscallReturn
1496timesFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1497           ThreadContext *tc)
1498{
1499    int index = 0;
1500    TypedBufferArg<typename OS::tms> bufp(process->getSyscallArg(tc, index));
1501
1502    // Fill in the time structure (in clocks)
1503    int64_t clocks = curTick() * OS::M5_SC_CLK_TCK / SimClock::Int::s;
1504    bufp->tms_utime = clocks;
1505    bufp->tms_stime = 0;
1506    bufp->tms_cutime = 0;
1507    bufp->tms_cstime = 0;
1508
1509    // Convert to host endianness
1510    bufp->tms_utime = TheISA::htog(bufp->tms_utime);
1511
1512    // Write back
1513    bufp.copyOut(tc->getMemProxy());
1514
1515    // Return clock ticks since system boot
1516    return clocks;
1517}
1518
1519/// Target time() function.
1520template <class OS>
1521SyscallReturn
1522timeFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1523           ThreadContext *tc)
1524{
1525    typename OS::time_t sec, usec;
1526    getElapsedTimeMicro(sec, usec);
1527    sec += seconds_since_epoch;
1528
1529    int index = 0;
1530    Addr taddr = (Addr)process->getSyscallArg(tc, index);
1531    if (taddr != 0) {
1532        typename OS::time_t t = sec;
1533        t = TheISA::htog(t);
1534        SETranslatingPortProxy &p = tc->getMemProxy();
1535        p.writeBlob(taddr, (uint8_t*)&t, (int)sizeof(typename OS::time_t));
1536    }
1537    return sec;
1538}
1539
1540
1541#endif // __SIM_SYSCALL_EMUL_HH__
1542