syscall_emul.hh revision 2462
12292SN/A/*
28948Sandreas.hansson@arm.com * Copyright (c) 2003-2005 The Regents of The University of Michigan
38707Sandreas.hansson@arm.com * All rights reserved.
48707Sandreas.hansson@arm.com *
58707Sandreas.hansson@arm.com * Redistribution and use in source and binary forms, with or without
68707Sandreas.hansson@arm.com * modification, are permitted provided that the following conditions are
78707Sandreas.hansson@arm.com * met: redistributions of source code must retain the above copyright
88707Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer;
98707Sandreas.hansson@arm.com * redistributions in binary form must reproduce the above copyright
108707Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer in the
118707Sandreas.hansson@arm.com * documentation and/or other materials provided with the distribution;
128707Sandreas.hansson@arm.com * neither the name of the copyright holders nor the names of its
138707Sandreas.hansson@arm.com * contributors may be used to endorse or promote products derived from
142727Sktlim@umich.edu * this software without specific prior written permission.
152292SN/A *
162292SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172292SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182292SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192292SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202292SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212292SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222292SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232292SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242292SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252292SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262292SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272292SN/A */
282292SN/A
292292SN/A#ifndef __SIM_SYSCALL_EMUL_HH__
302292SN/A#define __SIM_SYSCALL_EMUL_HH__
312292SN/A
322292SN/A#define BSD_HOST (defined(__APPLE__) || defined(__OpenBSD__) || \
332292SN/A                  defined(__FreeBSD__))
342292SN/A
352292SN/A///
362292SN/A/// @file syscall_emul.hh
372292SN/A///
382292SN/A/// This file defines objects used to emulate syscalls from the target
392689Sktlim@umich.edu/// application on the host machine.
402689Sktlim@umich.edu
412292SN/A#include <errno.h>
422292SN/A#include <string>
432329SN/A#ifdef __CYGWIN32__
442980Sgblack@eecs.umich.edu#include <sys/fcntl.h>	// for O_BINARY
452329SN/A#endif
462329SN/A#include <sys/uio.h>
472292SN/A
489444SAndreas.Sandberg@ARM.com#include "base/intmath.hh"	// for RoundUp
498232Snate@binkert.org#include "mem/translating_port.hh"
508232Snate@binkert.org#include "arch/isa_traits.hh"	// for Addr
518232Snate@binkert.org#include "base/misc.hh"
526221Snate@binkert.org#include "base/trace.hh"
532292SN/A#include "cpu/exec_context.hh"
546221Snate@binkert.org#include "cpu/base.hh"
555529Snate@binkert.org#include "sim/process.hh"
562292SN/A
575529Snate@binkert.org///
588707Sandreas.hansson@arm.com/// System call descriptor.
594329Sktlim@umich.edu///
604329Sktlim@umich.educlass SyscallDesc {
615529Snate@binkert.org
622907Sktlim@umich.edu  public:
632292SN/A
649868Sjthestness@gmail.com    /// Typedef for target syscall handler functions.
659868Sjthestness@gmail.com    typedef SyscallReturn (*FuncPtr)(SyscallDesc *, int num,
662292SN/A                           Process *, ExecContext *);
672292SN/A
682292SN/A    const char *name;	//!< Syscall name (e.g., "open").
692980Sgblack@eecs.umich.edu    FuncPtr funcPtr;	//!< Pointer to emulation function.
702292SN/A    int flags;		//!< Flags (see Flags enum).
712292SN/A
722292SN/A    /// Flag values for controlling syscall behavior.
732292SN/A    enum Flags {
742292SN/A        /// Don't set return regs according to funcPtr return value.
752292SN/A        /// Used for syscalls with non-standard return conventions
762292SN/A        /// that explicitly set the ExecContext regs (e.g.,
772292SN/A        /// sigreturn).
782292SN/A        SuppressReturnValue = 1
792292SN/A    };
802292SN/A
814329Sktlim@umich.edu    /// Constructor.
822292SN/A    SyscallDesc(const char *_name, FuncPtr _funcPtr, int _flags = 0)
832292SN/A        : name(_name), funcPtr(_funcPtr), flags(_flags)
842292SN/A    {
852292SN/A    }
862292SN/A
872292SN/A    /// Emulate the syscall.  Public interface for calling through funcPtr.
882292SN/A    void doSyscall(int callnum, Process *proc, ExecContext *xc);
894329Sktlim@umich.edu};
902292SN/A
918346Sksewell@umich.edu
922292SN/Aclass BaseBufferArg {
932292SN/A
942292SN/A  public:
952292SN/A
962292SN/A    BaseBufferArg(Addr _addr, int _size) : addr(_addr), size(_size)
972292SN/A    {
982292SN/A        bufPtr = new uint8_t[size];
992292SN/A        // clear out buffer: in case we only partially populate this,
1002292SN/A        // and then do a copyOut(), we want to make sure we don't
1012292SN/A        // introduce any random junk into the simulated address space
1022292SN/A        memset(bufPtr, 0, size);
1032292SN/A    }
1044329Sktlim@umich.edu
1052292SN/A    virtual ~BaseBufferArg() { delete [] bufPtr; }
1068346Sksewell@umich.edu
1072292SN/A    //
1082292SN/A    // copy data into simulator space (read from target memory)
1092292SN/A    //
1102292SN/A    virtual bool copyIn(TranslatingPort *memport)
1112292SN/A    {
1122292SN/A        memport->readBlob(addr, bufPtr, size);
1132292SN/A        return true;	// no EFAULT detection for now
1149868Sjthestness@gmail.com    }
1156221Snate@binkert.org
1164329Sktlim@umich.edu    //
1174329Sktlim@umich.edu    // copy data out of simulator space (write to target memory)
1188850Sandreas.hansson@arm.com    //
1192292SN/A    virtual bool copyOut(TranslatingPort *memport)
1202292SN/A    {
1212292SN/A        memport->writeBlob(addr, bufPtr, size);
1222292SN/A        return true;	// no EFAULT detection for now
1232292SN/A    }
1242292SN/A
1252292SN/A  protected:
1262292SN/A    Addr addr;
1272292SN/A    int size;
1282292SN/A    uint8_t *bufPtr;
1292292SN/A};
1302292SN/A
1312292SN/A
1322727Sktlim@umich.educlass BufferArg : public BaseBufferArg
1332727Sktlim@umich.edu{
1342727Sktlim@umich.edu  public:
1356221Snate@binkert.org    BufferArg(Addr _addr, int _size) : BaseBufferArg(_addr, _size) { }
1362727Sktlim@umich.edu    void *bufferPtr()	{ return bufPtr; }
1372727Sktlim@umich.edu};
1382727Sktlim@umich.edu
1392727Sktlim@umich.edutemplate <class T>
1402727Sktlim@umich.educlass TypedBufferArg : public BaseBufferArg
1412727Sktlim@umich.edu{
1426221Snate@binkert.org  public:
1432292SN/A    // user can optionally specify a specific number of bytes to
1442292SN/A    // allocate to deal with those structs that have variable-size
1452292SN/A    // arrays at the end
1462292SN/A    TypedBufferArg(Addr _addr, int _size = sizeof(T))
1472292SN/A        : BaseBufferArg(_addr, _size)
1482292SN/A    { }
1492307SN/A
1509444SAndreas.Sandberg@ARM.com    // type case
1512307SN/A    operator T*() { return (T *)bufPtr; }
1529444SAndreas.Sandberg@ARM.com
1539444SAndreas.Sandberg@ARM.com    // dereference operators
1549444SAndreas.Sandberg@ARM.com    T &operator*()	 { return *((T *)bufPtr); }
1559444SAndreas.Sandberg@ARM.com    T* operator->()	 { return (T *)bufPtr; }
1569444SAndreas.Sandberg@ARM.com    T &operator[](int i) { return ((T *)bufPtr)[i]; }
1579444SAndreas.Sandberg@ARM.com};
1589444SAndreas.Sandberg@ARM.com
1599444SAndreas.Sandberg@ARM.com//////////////////////////////////////////////////////////////////////
1609444SAndreas.Sandberg@ARM.com//
1619444SAndreas.Sandberg@ARM.com// The following emulation functions are generic enough that they
1629444SAndreas.Sandberg@ARM.com// don't need to be recompiled for different emulated OS's.  They are
1639444SAndreas.Sandberg@ARM.com// defined in sim/syscall_emul.cc.
1649444SAndreas.Sandberg@ARM.com//
1659444SAndreas.Sandberg@ARM.com//////////////////////////////////////////////////////////////////////
1669444SAndreas.Sandberg@ARM.com
1672307SN/A
1689444SAndreas.Sandberg@ARM.com/// Handler for unimplemented syscalls that we haven't thought about.
1699444SAndreas.Sandberg@ARM.comSyscallReturn unimplementedFunc(SyscallDesc *desc, int num,
1709444SAndreas.Sandberg@ARM.com                                Process *p, ExecContext *xc);
1719444SAndreas.Sandberg@ARM.com
1729444SAndreas.Sandberg@ARM.com/// Handler for unimplemented syscalls that we never intend to
1739444SAndreas.Sandberg@ARM.com/// implement (signal handling, etc.) and should not affect the correct
1749444SAndreas.Sandberg@ARM.com/// behavior of the program.  Print a warning only if the appropriate
1759444SAndreas.Sandberg@ARM.com/// trace flag is enabled.  Return success to the target program.
1769444SAndreas.Sandberg@ARM.comSyscallReturn ignoreFunc(SyscallDesc *desc, int num,
1779444SAndreas.Sandberg@ARM.com                         Process *p, ExecContext *xc);
1789444SAndreas.Sandberg@ARM.com
1799444SAndreas.Sandberg@ARM.com/// Target exit() handler: terminate simulation.
1802307SN/ASyscallReturn exitFunc(SyscallDesc *desc, int num,
1812307SN/A                       Process *p, ExecContext *xc);
1822307SN/A
1832307SN/A/// Target getpagesize() handler.
1842307SN/ASyscallReturn getpagesizeFunc(SyscallDesc *desc, int num,
1852307SN/A                              Process *p, ExecContext *xc);
1866221Snate@binkert.org
1872307SN/A/// Target obreak() handler: set brk address.
1882307SN/ASyscallReturn obreakFunc(SyscallDesc *desc, int num,
1892307SN/A                         Process *p, ExecContext *xc);
1902307SN/A
1912307SN/A/// Target close() handler.
1922292SN/ASyscallReturn closeFunc(SyscallDesc *desc, int num,
1936221Snate@binkert.org                        Process *p, ExecContext *xc);
1942292SN/A
1952292SN/A/// Target read() handler.
1962292SN/ASyscallReturn readFunc(SyscallDesc *desc, int num,
1972292SN/A                       Process *p, ExecContext *xc);
1982292SN/A
1992292SN/A/// Target write() handler.
2002292SN/ASyscallReturn writeFunc(SyscallDesc *desc, int num,
2012292SN/A                        Process *p, ExecContext *xc);
2022292SN/A
2032292SN/A/// Target lseek() handler.
2042292SN/ASyscallReturn lseekFunc(SyscallDesc *desc, int num,
2052292SN/A                        Process *p, ExecContext *xc);
2062292SN/A
2073867Sbinkertn@umich.edu/// Target munmap() handler.
2082292SN/ASyscallReturn munmapFunc(SyscallDesc *desc, int num,
2092292SN/A                         Process *p, ExecContext *xc);
2102292SN/A
2112292SN/A/// Target gethostname() handler.
2122292SN/ASyscallReturn gethostnameFunc(SyscallDesc *desc, int num,
2132292SN/A                              Process *p, ExecContext *xc);
2142292SN/A
2152292SN/A/// Target unlink() handler.
2162292SN/ASyscallReturn unlinkFunc(SyscallDesc *desc, int num,
2172292SN/A                         Process *p, ExecContext *xc);
2182292SN/A
2196221Snate@binkert.org/// Target rename() handler.
2206221Snate@binkert.orgSyscallReturn renameFunc(SyscallDesc *desc, int num,
2213867Sbinkertn@umich.edu                         Process *p, ExecContext *xc);
2223867Sbinkertn@umich.edu
2236221Snate@binkert.org
2243867Sbinkertn@umich.edu/// Target truncate() handler.
2253867Sbinkertn@umich.eduSyscallReturn truncateFunc(SyscallDesc *desc, int num,
2262292SN/A                           Process *p, ExecContext *xc);
2272292SN/A
2282292SN/A
2292292SN/A/// Target ftruncate() handler.
2302292SN/ASyscallReturn ftruncateFunc(SyscallDesc *desc, int num,
2312292SN/A                            Process *p, ExecContext *xc);
2326221Snate@binkert.org
2332292SN/A
2342292SN/A/// Target chown() handler.
2352292SN/ASyscallReturn chownFunc(SyscallDesc *desc, int num,
2362292SN/A                        Process *p, ExecContext *xc);
2372292SN/A
2382292SN/A
2392292SN/A/// Target fchown() handler.
2406221Snate@binkert.orgSyscallReturn fchownFunc(SyscallDesc *desc, int num,
2412292SN/A                         Process *p, ExecContext *xc);
2422292SN/A
2432292SN/A/// Target fnctl() handler.
2442292SN/ASyscallReturn fcntlFunc(SyscallDesc *desc, int num,
2452292SN/A                        Process *process, ExecContext *xc);
2462292SN/A
2472292SN/A/// Target setuid() handler.
2482292SN/ASyscallReturn setuidFunc(SyscallDesc *desc, int num,
2492292SN/A                               Process *p, ExecContext *xc);
2506221Snate@binkert.org
2516221Snate@binkert.org/// Target getpid() handler.
2522292SN/ASyscallReturn getpidFunc(SyscallDesc *desc, int num,
2533867Sbinkertn@umich.edu                               Process *p, ExecContext *xc);
2546221Snate@binkert.org
2552292SN/A/// Target getuid() handler.
2562292SN/ASyscallReturn getuidFunc(SyscallDesc *desc, int num,
2572292SN/A                               Process *p, ExecContext *xc);
2582292SN/A
2592292SN/A/// Target getgid() handler.
2602292SN/ASyscallReturn getgidFunc(SyscallDesc *desc, int num,
2612292SN/A                               Process *p, ExecContext *xc);
2622292SN/A
2632292SN/A/// Target getppid() handler.
2646221Snate@binkert.orgSyscallReturn getppidFunc(SyscallDesc *desc, int num,
2652292SN/A                               Process *p, ExecContext *xc);
2662292SN/A
2672292SN/A/// Target geteuid() handler.
2682292SN/ASyscallReturn geteuidFunc(SyscallDesc *desc, int num,
2692292SN/A                               Process *p, ExecContext *xc);
2702292SN/A
2712292SN/A/// Target getegid() handler.
2722292SN/ASyscallReturn getegidFunc(SyscallDesc *desc, int num,
2736221Snate@binkert.org                               Process *p, ExecContext *xc);
2742292SN/A
2752292SN/A
2762292SN/A
2772292SN/A/// Pseudo Funcs  - These functions use a different return convension,
2782292SN/A/// returning a second value in a register other than the normal return register
2792292SN/ASyscallReturn pipePseudoFunc(SyscallDesc *desc, int num,
2802292SN/A                             Process *process, ExecContext *xc);
2812292SN/A
2826221Snate@binkert.org/// Target getpidPseudo() handler.
2832292SN/ASyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num,
2842292SN/A                               Process *p, ExecContext *xc);
2852292SN/A
2862292SN/A/// Target getuidPseudo() handler.
2872292SN/ASyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num,
2882292SN/A                               Process *p, ExecContext *xc);
2892292SN/A
2902292SN/A/// Target getgidPseudo() handler.
2916221Snate@binkert.orgSyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num,
2922292SN/A                               Process *p, ExecContext *xc);
2932292SN/A
2942292SN/A
2952292SN/A/// This struct is used to build an target-OS-dependent table that
2962292SN/A/// maps the target's open() flags to the host open() flags.
2972292SN/Astruct OpenFlagTransTable {
2982292SN/A    int tgtFlag;	//!< Target system flag value.
2992292SN/A    int hostFlag;	//!< Corresponding host system flag value.
3006221Snate@binkert.org};
3016221Snate@binkert.org
3022292SN/A
3033867Sbinkertn@umich.edu
3046221Snate@binkert.org/// A readable name for 1,000,000, for converting microseconds to seconds.
3052292SN/Aconst int one_million = 1000000;
3062292SN/A
3072329SN/A/// Approximate seconds since the epoch (1/1/1970).  About a billion,
3082329SN/A/// by my reckoning.  We want to keep this a constant (not use the
3092292SN/A/// real-world time) to keep simulations repeatable.
3102292SN/Aconst unsigned seconds_since_epoch = 1000000000;
3112292SN/A
3122292SN/A/// Helper function to convert current elapsed time to seconds and
3132292SN/A/// microseconds.
3142292SN/Atemplate <class T1, class T2>
3152292SN/Avoid
3162292SN/AgetElapsedTime(T1 &sec, T2 &usec)
3172292SN/A{
3182292SN/A    int elapsed_usecs = curTick / Clock::Int::us;
3192292SN/A    sec = elapsed_usecs / one_million;
3206221Snate@binkert.org    usec = elapsed_usecs % one_million;
3216221Snate@binkert.org}
3222292SN/A
3233867Sbinkertn@umich.edu//////////////////////////////////////////////////////////////////////
3246221Snate@binkert.org//
3253867Sbinkertn@umich.edu// The following emulation functions are generic, but need to be
3262292SN/A// templated to account for differences in types, constants, etc.
3272292SN/A//
3282292SN/A//////////////////////////////////////////////////////////////////////
3292292SN/A
3302292SN/A/// Target ioctl() handler.  For the most part, programs call ioctl()
3312292SN/A/// only to find out if their stdout is a tty, to determine whether to
3322292SN/A/// do line or block buffering.
3338707Sandreas.hansson@arm.comtemplate <class OS>
3348707Sandreas.hansson@arm.comSyscallReturn
3358707Sandreas.hansson@arm.comioctlFunc(SyscallDesc *desc, int callnum, Process *process,
3368707Sandreas.hansson@arm.com          ExecContext *xc)
3378707Sandreas.hansson@arm.com{
3388707Sandreas.hansson@arm.com    int fd = xc->getSyscallArg(0);
3398707Sandreas.hansson@arm.com    unsigned req = xc->getSyscallArg(1);
3408707Sandreas.hansson@arm.com
3418707Sandreas.hansson@arm.com    DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", fd, req);
3428707Sandreas.hansson@arm.com
3438707Sandreas.hansson@arm.com    if (fd < 0 || process->sim_fd(fd) < 0) {
3448707Sandreas.hansson@arm.com        // doesn't map to any simulator fd: not a valid target fd
3458707Sandreas.hansson@arm.com        return -EBADF;
3468707Sandreas.hansson@arm.com    }
3478707Sandreas.hansson@arm.com
3488707Sandreas.hansson@arm.com    switch (req) {
3498707Sandreas.hansson@arm.com      case OS::TIOCISATTY:
3508707Sandreas.hansson@arm.com      case OS::TIOCGETP:
3518975Sandreas.hansson@arm.com      case OS::TIOCSETP:
3528707Sandreas.hansson@arm.com      case OS::TIOCSETN:
3538707Sandreas.hansson@arm.com      case OS::TIOCSETC:
3548707Sandreas.hansson@arm.com      case OS::TIOCGETC:
3558707Sandreas.hansson@arm.com      case OS::TIOCGETS:
3568948Sandreas.hansson@arm.com      case OS::TIOCGETA:
3578948Sandreas.hansson@arm.com        return -ENOTTY;
3588948Sandreas.hansson@arm.com
3598707Sandreas.hansson@arm.com      default:
3608948Sandreas.hansson@arm.com        fatal("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ 0x%llx\n",
3618975Sandreas.hansson@arm.com              fd, req, xc->readPC());
3628975Sandreas.hansson@arm.com    }
3638948Sandreas.hansson@arm.com}
3648948Sandreas.hansson@arm.com
3658948Sandreas.hansson@arm.com/// Target open() handler.
3668948Sandreas.hansson@arm.comtemplate <class OS>
3678948Sandreas.hansson@arm.comSyscallReturn
3688948Sandreas.hansson@arm.comopenFunc(SyscallDesc *desc, int callnum, Process *process,
3698948Sandreas.hansson@arm.com         ExecContext *xc)
3708948Sandreas.hansson@arm.com{
3718948Sandreas.hansson@arm.com    std::string path;
3728948Sandreas.hansson@arm.com
3738707Sandreas.hansson@arm.com    if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
3748707Sandreas.hansson@arm.com        return -EFAULT;
3758707Sandreas.hansson@arm.com
3768707Sandreas.hansson@arm.com    if (path == "/dev/sysdev0") {
3772292SN/A        // This is a memory-mapped high-resolution timer device on Alpha.
3782292SN/A        // We don't support it, so just punt.
3792292SN/A        warn("Ignoring open(%s, ...)\n", path);
3802292SN/A        return -ENOENT;
3812292SN/A    }
3822292SN/A
3836221Snate@binkert.org    int tgtFlags = xc->getSyscallArg(1);
3846221Snate@binkert.org    int mode = xc->getSyscallArg(2);
3852292SN/A    int hostFlags = 0;
3863867Sbinkertn@umich.edu
3876221Snate@binkert.org    // translate open flags
3883867Sbinkertn@umich.edu    for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) {
3892292SN/A        if (tgtFlags & OS::openFlagTable[i].tgtFlag) {
3902292SN/A            tgtFlags &= ~OS::openFlagTable[i].tgtFlag;
3912292SN/A            hostFlags |= OS::openFlagTable[i].hostFlag;
3922292SN/A        }
3932292SN/A    }
3942292SN/A
3952292SN/A    // any target flags left?
3962292SN/A    if (tgtFlags != 0)
3972292SN/A        warn("Syscall: open: cannot decode flags 0x%x", tgtFlags);
3982292SN/A
3992292SN/A#ifdef __CYGWIN32__
4002292SN/A    hostFlags |= O_BINARY;
4016221Snate@binkert.org#endif
4026221Snate@binkert.org
4032292SN/A    DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str());
4043867Sbinkertn@umich.edu
4056221Snate@binkert.org    // open the file
4063867Sbinkertn@umich.edu    int fd = open(path.c_str(), hostFlags, mode);
4072292SN/A
4082292SN/A    return (fd == -1) ? -errno : process->alloc_fd(fd);
4092292SN/A}
4102292SN/A
4112292SN/A
4122292SN/A/// Target chmod() handler.
4132292SN/Atemplate <class OS>
4142292SN/ASyscallReturn
4152292SN/AchmodFunc(SyscallDesc *desc, int callnum, Process *process,
4162292SN/A          ExecContext *xc)
4172292SN/A{
4182292SN/A    std::string path;
4196221Snate@binkert.org
4206221Snate@binkert.org    if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
4212292SN/A        return -EFAULT;
4223867Sbinkertn@umich.edu
4236221Snate@binkert.org    uint32_t mode = xc->getSyscallArg(1);
4243867Sbinkertn@umich.edu    mode_t hostMode = 0;
4252292SN/A
4262292SN/A    // XXX translate mode flags via OS::something???
4272292SN/A    hostMode = mode;
4282292SN/A
4292292SN/A    // do the chmod
4302292SN/A    int result = chmod(path.c_str(), hostMode);
4312292SN/A    if (result < 0)
4322292SN/A        return -errno;
4332292SN/A
4342292SN/A    return 0;
4352292SN/A}
4362292SN/A
4376221Snate@binkert.org
4386221Snate@binkert.org/// Target fchmod() handler.
4392292SN/Atemplate <class OS>
4403867Sbinkertn@umich.eduSyscallReturn
4416221Snate@binkert.orgfchmodFunc(SyscallDesc *desc, int callnum, Process *process,
4423867Sbinkertn@umich.edu           ExecContext *xc)
4432292SN/A{
4442292SN/A    int fd = xc->getSyscallArg(0);
4452292SN/A    if (fd < 0 || process->sim_fd(fd) < 0) {
4462292SN/A        // doesn't map to any simulator fd: not a valid target fd
4472292SN/A        return -EBADF;
4482292SN/A    }
4492292SN/A
4502292SN/A    uint32_t mode = xc->getSyscallArg(1);
4516221Snate@binkert.org    mode_t hostMode = 0;
4522292SN/A
4533870Sbinkertn@umich.edu    // XXX translate mode flags via OS::someting???
4542292SN/A    hostMode = mode;
4552292SN/A
4562292SN/A    // do the fchmod
4572292SN/A    int result = fchmod(process->sim_fd(fd), hostMode);
4582292SN/A    if (result < 0)
4592292SN/A        return -errno;
4602292SN/A
4612292SN/A    return 0;
4622292SN/A}
4636221Snate@binkert.org
4646221Snate@binkert.org
4652292SN/A/// Target stat() handler.
4663867Sbinkertn@umich.edutemplate <class OS>
4676221Snate@binkert.orgSyscallReturn
4683867Sbinkertn@umich.edustatFunc(SyscallDesc *desc, int callnum, Process *process,
4693867Sbinkertn@umich.edu         ExecContext *xc)
4702292SN/A{
4712292SN/A    std::string path;
4722292SN/A
4732292SN/A    if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
4742292SN/A    return -EFAULT;
4752292SN/A
4762292SN/A    struct stat hostBuf;
4772292SN/A    int result = stat(path.c_str(), &hostBuf);
4786221Snate@binkert.org
4792292SN/A    if (result < 0)
4802292SN/A        return -errno;
4812292SN/A
4823867Sbinkertn@umich.edu    OS::copyOutStatBuf(xc->getMemPort(), xc->getSyscallArg(1), &hostBuf);
4832292SN/A
4842292SN/A    return 0;
4852292SN/A}
4862292SN/A
4872292SN/A
4882292SN/A/// Target fstat64() handler.
4892292SN/Atemplate <class OS>
4909444SAndreas.Sandberg@ARM.comSyscallReturn
4919444SAndreas.Sandberg@ARM.comfstat64Func(SyscallDesc *desc, int callnum, Process *process,
4929444SAndreas.Sandberg@ARM.com            ExecContext *xc)
4939444SAndreas.Sandberg@ARM.com{
4949444SAndreas.Sandberg@ARM.com    int fd = xc->getSyscallArg(0);
4959444SAndreas.Sandberg@ARM.com    if (fd < 0 || process->sim_fd(fd) < 0) {
4969444SAndreas.Sandberg@ARM.com        // doesn't map to any simulator fd: not a valid target fd
4979444SAndreas.Sandberg@ARM.com        return -EBADF;
4989444SAndreas.Sandberg@ARM.com    }
4999444SAndreas.Sandberg@ARM.com
5009444SAndreas.Sandberg@ARM.com#if BSD_HOST
5019444SAndreas.Sandberg@ARM.com    struct stat  hostBuf;
5029444SAndreas.Sandberg@ARM.com    int result = fstat(process->sim_fd(fd), &hostBuf);
5039444SAndreas.Sandberg@ARM.com#else
5049444SAndreas.Sandberg@ARM.com    struct stat64  hostBuf;
5059444SAndreas.Sandberg@ARM.com    int result = fstat64(process->sim_fd(fd), &hostBuf);
5069444SAndreas.Sandberg@ARM.com#endif
5079444SAndreas.Sandberg@ARM.com
5089444SAndreas.Sandberg@ARM.com    if (result < 0)
5099444SAndreas.Sandberg@ARM.com        return -errno;
5109444SAndreas.Sandberg@ARM.com
5119444SAndreas.Sandberg@ARM.com    OS::copyOutStat64Buf(xc->getMemPort(), fd, xc->getSyscallArg(1), &hostBuf);
5129444SAndreas.Sandberg@ARM.com
5139444SAndreas.Sandberg@ARM.com    return 0;
5149444SAndreas.Sandberg@ARM.com}
5159444SAndreas.Sandberg@ARM.com
5169444SAndreas.Sandberg@ARM.com
5179444SAndreas.Sandberg@ARM.com/// Target lstat() handler.
5189444SAndreas.Sandberg@ARM.comtemplate <class OS>
5199444SAndreas.Sandberg@ARM.comSyscallReturn
5209444SAndreas.Sandberg@ARM.comlstatFunc(SyscallDesc *desc, int callnum, Process *process,
5219444SAndreas.Sandberg@ARM.com          ExecContext *xc)
5229444SAndreas.Sandberg@ARM.com{
5239444SAndreas.Sandberg@ARM.com    std::string path;
5249444SAndreas.Sandberg@ARM.com
5259444SAndreas.Sandberg@ARM.com    if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
5269444SAndreas.Sandberg@ARM.com      return -EFAULT;
5279444SAndreas.Sandberg@ARM.com
5289444SAndreas.Sandberg@ARM.com    struct stat hostBuf;
5299444SAndreas.Sandberg@ARM.com    int result = lstat(path.c_str(), &hostBuf);
5309444SAndreas.Sandberg@ARM.com
5312292SN/A    if (result < 0)
5322292SN/A        return -errno;
5336221Snate@binkert.org
5346221Snate@binkert.org    OS::copyOutStatBuf(xc->getMemPort(), xc->getSyscallArg(1), &hostBuf);
5352292SN/A
5363867Sbinkertn@umich.edu    return 0;
5376221Snate@binkert.org}
5383867Sbinkertn@umich.edu
5392292SN/A/// Target lstat64() handler.
5402292SN/Atemplate <class OS>
5412292SN/ASyscallReturn
5422292SN/Alstat64Func(SyscallDesc *desc, int callnum, Process *process,
5432292SN/A            ExecContext *xc)
5442292SN/A{
5452292SN/A    std::string path;
5462292SN/A
5472292SN/A    if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
5486221Snate@binkert.org      return -EFAULT;
5492292SN/A
5502292SN/A#if BSD_HOST
5512292SN/A    struct stat hostBuf;
5523870Sbinkertn@umich.edu    int result = lstat(path.c_str(), &hostBuf);
5532292SN/A#else
5542292SN/A    struct stat64 hostBuf;
5552292SN/A    int result = lstat64(path.c_str(), &hostBuf);
5562292SN/A#endif
5572292SN/A
5582292SN/A    if (result < 0)
5592292SN/A        return -errno;
5602292SN/A
5612292SN/A    OS::copyOutStat64Buf(xc->getMemPort(), -1, xc->getSyscallArg(1), &hostBuf);
5626221Snate@binkert.org
5636221Snate@binkert.org    return 0;
5642292SN/A}
5653867Sbinkertn@umich.edu
5666221Snate@binkert.org/// Target fstat() handler.
5673867Sbinkertn@umich.edutemplate <class OS>
5682292SN/ASyscallReturn
5692292SN/AfstatFunc(SyscallDesc *desc, int callnum, Process *process,
5702292SN/A          ExecContext *xc)
5712292SN/A{
5722292SN/A    int fd = process->sim_fd(xc->getSyscallArg(0));
5732292SN/A
5742292SN/A    DPRINTF(SyscallVerbose, "fstat(%d, ...)\n", fd);
5752292SN/A
5762292SN/A    if (fd < 0)
5776221Snate@binkert.org        return -EBADF;
5782292SN/A
5792292SN/A    struct stat hostBuf;
5802292SN/A    int result = fstat(fd, &hostBuf);
5813870Sbinkertn@umich.edu
5822292SN/A    if (result < 0)
5832292SN/A        return -errno;
5842292SN/A
5852292SN/A    OS::copyOutStatBuf(xc->getMemPort(), xc->getSyscallArg(1), &hostBuf);
5862292SN/A
5872292SN/A    return 0;
5882292SN/A}
5892292SN/A
5902292SN/A
5916221Snate@binkert.org/// Target statfs() handler.
5926221Snate@binkert.orgtemplate <class OS>
5932292SN/ASyscallReturn
5943867Sbinkertn@umich.edustatfsFunc(SyscallDesc *desc, int callnum, Process *process,
5956221Snate@binkert.org           ExecContext *xc)
5963867Sbinkertn@umich.edu{
5972292SN/A    std::string path;
5982292SN/A
5992292SN/A    if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
6002292SN/A      return -EFAULT;
6012292SN/A
6022292SN/A    struct statfs hostBuf;
6032292SN/A    int result = statfs(path.c_str(), &hostBuf);
6042292SN/A
6052292SN/A    if (result < 0)
6066221Snate@binkert.org        return -errno;
6072292SN/A
6083870Sbinkertn@umich.edu    OS::copyOutStatfsBuf(xc->getMemPort(), xc->getSyscallArg(1), &hostBuf);
6092292SN/A
6102292SN/A    return 0;
6112292SN/A}
6122292SN/A
6132292SN/A
6142292SN/A/// Target fstatfs() handler.
6152292SN/Atemplate <class OS>
6162292SN/ASyscallReturn
6172292SN/AfstatfsFunc(SyscallDesc *desc, int callnum, Process *process,
6186221Snate@binkert.org            ExecContext *xc)
6196221Snate@binkert.org{
6202292SN/A    int fd = process->sim_fd(xc->getSyscallArg(0));
6213867Sbinkertn@umich.edu
6226221Snate@binkert.org    if (fd < 0)
6233867Sbinkertn@umich.edu        return -EBADF;
6245557Sktlim@umich.edu
6255557Sktlim@umich.edu    struct statfs hostBuf;
6262292SN/A    int result = fstatfs(fd, &hostBuf);
6272292SN/A
6285557Sktlim@umich.edu    if (result < 0)
6292292SN/A        return -errno;
6302292SN/A
6312292SN/A    OS::copyOutStatfsBuf(xc->getMemPort(), xc->getSyscallArg(1), &hostBuf);
6322292SN/A
6332292SN/A    return 0;
6342292SN/A}
6356221Snate@binkert.org
6366221Snate@binkert.org
6372292SN/A/// Target writev() handler.
6383867Sbinkertn@umich.edutemplate <class OS>
6396221Snate@binkert.orgSyscallReturn
6403867Sbinkertn@umich.eduwritevFunc(SyscallDesc *desc, int callnum, Process *process,
6415557Sktlim@umich.edu           ExecContext *xc)
6425557Sktlim@umich.edu{
6432292SN/A    int fd = xc->getSyscallArg(0);
6442292SN/A    if (fd < 0 || process->sim_fd(fd) < 0) {
6455557Sktlim@umich.edu        // doesn't map to any simulator fd: not a valid target fd
6462292SN/A        return -EBADF;
6472292SN/A    }
6482292SN/A
6492292SN/A    TranslatingPort *p = xc->getMemPort();
6509440SAndreas.Sandberg@ARM.com    uint64_t tiov_base = xc->getSyscallArg(1);
6512292SN/A    size_t count = xc->getSyscallArg(2);
6529440SAndreas.Sandberg@ARM.com    struct iovec hiov[count];
6539440SAndreas.Sandberg@ARM.com    for (int i = 0; i < count; ++i)
6542292SN/A    {
6553867Sbinkertn@umich.edu        typename OS::tgt_iovec tiov;
6566221Snate@binkert.org
6573867Sbinkertn@umich.edu        p->readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec),
6582292SN/A                    (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec));
6592292SN/A        hiov[i].iov_len = gtoh(tiov.iov_len);
6602292SN/A        hiov[i].iov_base = new char [hiov[i].iov_len];
661        p->readBlob(gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base,
662                    hiov[i].iov_len);
663    }
664
665    int result = writev(process->sim_fd(fd), hiov, count);
666
667    for (int i = 0; i < count; ++i)
668    {
669        delete [] (char *)hiov[i].iov_base;
670    }
671
672    if (result < 0)
673        return -errno;
674
675    return 0;
676}
677
678
679/// Target mmap() handler.
680///
681/// We don't really handle mmap().  If the target is mmaping an
682/// anonymous region or /dev/zero, we can get away with doing basically
683/// nothing (since memory is initialized to zero and the simulator
684/// doesn't really check addresses anyway).  Always print a warning,
685/// since this could be seriously broken if we're not mapping
686/// /dev/zero.
687//
688/// Someday we should explicitly check for /dev/zero in open, flag the
689/// file descriptor, and fail (or implement!) a non-anonymous mmap to
690/// anything else.
691template <class OS>
692SyscallReturn
693mmapFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
694{
695    Addr start = xc->getSyscallArg(0);
696    uint64_t length = xc->getSyscallArg(1);
697    // int prot = xc->getSyscallArg(2);
698    int flags = xc->getSyscallArg(3);
699    // int fd = p->sim_fd(xc->getSyscallArg(4));
700    // int offset = xc->getSyscallArg(5);
701
702    if (start == 0) {
703        // user didn't give an address... pick one from our "mmap region"
704        start = p->mmap_end;
705        p->mmap_end += roundUp(length, TheISA::VMPageSize);
706        if (p->nxm_start != 0) {
707            //If we have an nxm space, make sure we haven't colided
708            assert(p->mmap_end < p->nxm_start);
709        }
710    }
711
712    if (!(flags & OS::TGT_MAP_ANONYMOUS)) {
713        warn("allowing mmap of file @ fd %d. "
714             "This will break if not /dev/zero.", xc->getSyscallArg(4));
715    }
716
717    return start;
718}
719
720/// Target getrlimit() handler.
721template <class OS>
722SyscallReturn
723getrlimitFunc(SyscallDesc *desc, int callnum, Process *process,
724        ExecContext *xc)
725{
726    unsigned resource = xc->getSyscallArg(0);
727    TypedBufferArg<typename OS::rlimit> rlp(xc->getSyscallArg(1));
728
729    switch (resource) {
730        case OS::TGT_RLIMIT_STACK:
731            // max stack size in bytes: make up a number (2MB for now)
732            rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024;
733            rlp->rlim_cur = htog(rlp->rlim_cur);
734            rlp->rlim_max = htog(rlp->rlim_max);
735            break;
736
737        default:
738            std::cerr << "getrlimitFunc: unimplemented resource " << resource
739                << std::endl;
740            abort();
741            break;
742    }
743
744    rlp.copyOut(xc->getMemPort());
745    return 0;
746}
747
748/// Target gettimeofday() handler.
749template <class OS>
750SyscallReturn
751gettimeofdayFunc(SyscallDesc *desc, int callnum, Process *process,
752        ExecContext *xc)
753{
754    TypedBufferArg<typename OS::timeval> tp(xc->getSyscallArg(0));
755
756    getElapsedTime(tp->tv_sec, tp->tv_usec);
757    tp->tv_sec += seconds_since_epoch;
758    tp->tv_sec = htog(tp->tv_sec);
759    tp->tv_usec = htog(tp->tv_usec);
760
761    tp.copyOut(xc->getMemPort());
762
763    return 0;
764}
765
766
767/// Target utimes() handler.
768template <class OS>
769SyscallReturn
770utimesFunc(SyscallDesc *desc, int callnum, Process *process,
771           ExecContext *xc)
772{
773    std::string path;
774
775    if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
776      return -EFAULT;
777
778    TypedBufferArg<typename OS::timeval [2]> tp(xc->getSyscallArg(1));
779    tp.copyIn(xc->getMemPort());
780
781    struct timeval hostTimeval[2];
782    for (int i = 0; i < 2; ++i)
783    {
784        hostTimeval[i].tv_sec = gtoh((*tp)[i].tv_sec);
785        hostTimeval[i].tv_usec = gtoh((*tp)[i].tv_usec);
786    }
787    int result = utimes(path.c_str(), hostTimeval);
788
789    if (result < 0)
790        return -errno;
791
792    return 0;
793}
794/// Target getrusage() function.
795template <class OS>
796SyscallReturn
797getrusageFunc(SyscallDesc *desc, int callnum, Process *process,
798              ExecContext *xc)
799{
800    int who = xc->getSyscallArg(0);	// THREAD, SELF, or CHILDREN
801    TypedBufferArg<typename OS::rusage> rup(xc->getSyscallArg(1));
802
803    if (who != OS::TGT_RUSAGE_SELF) {
804        // don't really handle THREAD or CHILDREN, but just warn and
805        // plow ahead
806        warn("getrusage() only supports RUSAGE_SELF.  Parameter %d ignored.",
807             who);
808    }
809
810    getElapsedTime(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec);
811    rup->ru_utime.tv_sec = htog(rup->ru_utime.tv_sec);
812    rup->ru_utime.tv_usec = htog(rup->ru_utime.tv_usec);
813
814    rup->ru_stime.tv_sec = 0;
815    rup->ru_stime.tv_usec = 0;
816    rup->ru_maxrss = 0;
817    rup->ru_ixrss = 0;
818    rup->ru_idrss = 0;
819    rup->ru_isrss = 0;
820    rup->ru_minflt = 0;
821    rup->ru_majflt = 0;
822    rup->ru_nswap = 0;
823    rup->ru_inblock = 0;
824    rup->ru_oublock = 0;
825    rup->ru_msgsnd = 0;
826    rup->ru_msgrcv = 0;
827    rup->ru_nsignals = 0;
828    rup->ru_nvcsw = 0;
829    rup->ru_nivcsw = 0;
830
831    rup.copyOut(xc->getMemPort());
832
833    return 0;
834}
835
836#endif // __SIM_SYSCALL_EMUL_HH__
837