syscall_emul.hh revision 2462
12810SN/A/*
210764Sandreas.hansson@arm.com * Copyright (c) 2003-2005 The Regents of The University of Michigan
39663Suri.wiener@arm.com * All rights reserved.
49663Suri.wiener@arm.com *
59663Suri.wiener@arm.com * Redistribution and use in source and binary forms, with or without
69663Suri.wiener@arm.com * modification, are permitted provided that the following conditions are
79663Suri.wiener@arm.com * met: redistributions of source code must retain the above copyright
89663Suri.wiener@arm.com * notice, this list of conditions and the following disclaimer;
99663Suri.wiener@arm.com * redistributions in binary form must reproduce the above copyright
109663Suri.wiener@arm.com * notice, this list of conditions and the following disclaimer in the
119663Suri.wiener@arm.com * documentation and/or other materials provided with the distribution;
129663Suri.wiener@arm.com * neither the name of the copyright holders nor the names of its
139663Suri.wiener@arm.com * contributors may be used to endorse or promote products derived from
142810SN/A * this software without specific prior written permission.
157636Ssteve.reinhardt@amd.com *
162810SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172810SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182810SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192810SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202810SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212810SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222810SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232810SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242810SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252810SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262810SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272810SN/A */
282810SN/A
292810SN/A#ifndef __SIM_SYSCALL_EMUL_HH__
302810SN/A#define __SIM_SYSCALL_EMUL_HH__
312810SN/A
322810SN/A#define BSD_HOST (defined(__APPLE__) || defined(__OpenBSD__) || \
332810SN/A                  defined(__FreeBSD__))
342810SN/A
352810SN/A///
362810SN/A/// @file syscall_emul.hh
372810SN/A///
382810SN/A/// This file defines objects used to emulate syscalls from the target
392810SN/A/// application on the host machine.
402810SN/A
412810SN/A#include <errno.h>
422810SN/A#include <string>
432810SN/A#ifdef __CYGWIN32__
442810SN/A#include <sys/fcntl.h>	// for O_BINARY
452810SN/A#endif
462810SN/A#include <sys/uio.h>
472810SN/A
482810SN/A#include "base/intmath.hh"	// for RoundUp
492810SN/A#include "mem/translating_port.hh"
506216Snate@binkert.org#include "arch/isa_traits.hh"	// for Addr
516216Snate@binkert.org#include "base/misc.hh"
522810SN/A#include "base/trace.hh"
532810SN/A#include "cpu/exec_context.hh"
542810SN/A#include "cpu/base.hh"
556216Snate@binkert.org#include "sim/process.hh"
566216Snate@binkert.org
578232Snate@binkert.org///
586216Snate@binkert.org/// System call descriptor.
595338Sstever@gmail.com///
606216Snate@binkert.orgclass SyscallDesc {
612810SN/A
622810SN/A  public:
632810SN/A
649725Sandreas.hansson@arm.com    /// Typedef for target syscall handler functions.
6510582SCurtis.Dunham@arm.com    typedef SyscallReturn (*FuncPtr)(SyscallDesc *, int num,
6610503SCurtis.Dunham@arm.com                           Process *, ExecContext *);
6710764Sandreas.hansson@arm.com
6810764Sandreas.hansson@arm.com    const char *name;	//!< Syscall name (e.g., "open").
6911197Sandreas.hansson@arm.com    FuncPtr funcPtr;	//!< Pointer to emulation function.
7011278Sandreas.hansson@arm.com    int flags;		//!< Flags (see Flags enum).
712810SN/A
722810SN/A    /// Flag values for controlling syscall behavior.
732810SN/A    enum Flags {
744903SN/A        /// Don't set return regs according to funcPtr return value.
754903SN/A        /// Used for syscalls with non-standard return conventions
764903SN/A        /// that explicitly set the ExecContext regs (e.g.,
774903SN/A        /// sigreturn).
784903SN/A        SuppressReturnValue = 1
794903SN/A    };
804903SN/A
814908SN/A    /// Constructor.
825875Ssteve.reinhardt@amd.com    SyscallDesc(const char *_name, FuncPtr _funcPtr, int _flags = 0)
834903SN/A        : name(_name), funcPtr(_funcPtr), flags(_flags)
845875Ssteve.reinhardt@amd.com    {
854903SN/A    }
864903SN/A
874903SN/A    /// Emulate the syscall.  Public interface for calling through funcPtr.
884903SN/A    void doSyscall(int callnum, Process *proc, ExecContext *xc);
897669Ssteve.reinhardt@amd.com};
907669Ssteve.reinhardt@amd.com
917669Ssteve.reinhardt@amd.com
927669Ssteve.reinhardt@amd.comclass BaseBufferArg {
934903SN/A
944903SN/A  public:
955318SN/A
964908SN/A    BaseBufferArg(Addr _addr, int _size) : addr(_addr), size(_size)
975318SN/A    {
989543Ssascha.bischoff@arm.com        bufPtr = new uint8_t[size];
999543Ssascha.bischoff@arm.com        // clear out buffer: in case we only partially populate this,
1009543Ssascha.bischoff@arm.com        // and then do a copyOut(), we want to make sure we don't
1019543Ssascha.bischoff@arm.com        // introduce any random junk into the simulated address space
1024908SN/A        memset(bufPtr, 0, size);
1034908SN/A    }
1044908SN/A
10511083Sandreas.hansson@arm.com    virtual ~BaseBufferArg() { delete [] bufPtr; }
10611083Sandreas.hansson@arm.com
10711083Sandreas.hansson@arm.com    //
1084908SN/A    // copy data into simulator space (read from target memory)
1094903SN/A    //
1104903SN/A    virtual bool copyIn(TranslatingPort *memport)
11110922Sandreas.hansson@arm.com    {
1124903SN/A        memport->readBlob(addr, bufPtr, size);
1134903SN/A        return true;	// no EFAULT detection for now
1144903SN/A    }
1157667Ssteve.reinhardt@amd.com
1167667Ssteve.reinhardt@amd.com    //
1177667Ssteve.reinhardt@amd.com    // copy data out of simulator space (write to target memory)
1187667Ssteve.reinhardt@amd.com    //
1197667Ssteve.reinhardt@amd.com    virtual bool copyOut(TranslatingPort *memport)
1207667Ssteve.reinhardt@amd.com    {
1217667Ssteve.reinhardt@amd.com        memport->writeBlob(addr, bufPtr, size);
1227667Ssteve.reinhardt@amd.com        return true;	// no EFAULT detection for now
1237667Ssteve.reinhardt@amd.com    }
1247669Ssteve.reinhardt@amd.com
1257669Ssteve.reinhardt@amd.com  protected:
1267669Ssteve.reinhardt@amd.com    Addr addr;
1277667Ssteve.reinhardt@amd.com    int size;
1287667Ssteve.reinhardt@amd.com    uint8_t *bufPtr;
1297667Ssteve.reinhardt@amd.com};
1307667Ssteve.reinhardt@amd.com
1314903SN/A
1324903SN/Aclass BufferArg : public BaseBufferArg
1334903SN/A{
1344903SN/A  public:
1354903SN/A    BufferArg(Addr _addr, int _size) : BaseBufferArg(_addr, _size) { }
1364903SN/A    void *bufferPtr()	{ return bufPtr; }
13710766Sandreas.hansson@arm.com};
13810766Sandreas.hansson@arm.com
1394903SN/Atemplate <class T>
1404903SN/Aclass TypedBufferArg : public BaseBufferArg
1414903SN/A{
1424903SN/A  public:
1434903SN/A    // user can optionally specify a specific number of bytes to
1444903SN/A    // allocate to deal with those structs that have variable-size
1452810SN/A    // arrays at the end
1464908SN/A    TypedBufferArg(Addr _addr, int _size = sizeof(T))
1474908SN/A        : BaseBufferArg(_addr, _size)
14810766Sandreas.hansson@arm.com    { }
14910766Sandreas.hansson@arm.com
1509543Ssascha.bischoff@arm.com    // type case
1519543Ssascha.bischoff@arm.com    operator T*() { return (T *)bufPtr; }
1529543Ssascha.bischoff@arm.com
1539543Ssascha.bischoff@arm.com    // dereference operators
1549543Ssascha.bischoff@arm.com    T &operator*()	 { return *((T *)bufPtr); }
1559543Ssascha.bischoff@arm.com    T* operator->()	 { return (T *)bufPtr; }
15610766Sandreas.hansson@arm.com    T &operator[](int i) { return ((T *)bufPtr)[i]; }
1575318SN/A};
1585318SN/A
1595318SN/A//////////////////////////////////////////////////////////////////////
1604908SN/A//
1614908SN/A// The following emulation functions are generic enough that they
1624908SN/A// don't need to be recompiled for different emulated OS's.  They are
1634908SN/A// defined in sim/syscall_emul.cc.
1644908SN/A//
1654920SN/A//////////////////////////////////////////////////////////////////////
1664920SN/A
1674920SN/A
16810766Sandreas.hansson@arm.com/// Handler for unimplemented syscalls that we haven't thought about.
16910766Sandreas.hansson@arm.comSyscallReturn unimplementedFunc(SyscallDesc *desc, int num,
1704920SN/A                                Process *p, ExecContext *xc);
1714920SN/A
1724920SN/A/// Handler for unimplemented syscalls that we never intend to
1734920SN/A/// implement (signal handling, etc.) and should not affect the correct
1744920SN/A/// behavior of the program.  Print a warning only if the appropriate
1754920SN/A/// trace flag is enabled.  Return success to the target program.
1764920SN/ASyscallReturn ignoreFunc(SyscallDesc *desc, int num,
1774920SN/A                         Process *p, ExecContext *xc);
1784908SN/A
17910766Sandreas.hansson@arm.com/// Target exit() handler: terminate simulation.
18010766Sandreas.hansson@arm.comSyscallReturn exitFunc(SyscallDesc *desc, int num,
1815314SN/A                       Process *p, ExecContext *xc);
18210766Sandreas.hansson@arm.com
1835875Ssteve.reinhardt@amd.com/// Target getpagesize() handler.
18410766Sandreas.hansson@arm.comSyscallReturn getpagesizeFunc(SyscallDesc *desc, int num,
1858988SAli.Saidi@ARM.com                              Process *p, ExecContext *xc);
1868988SAli.Saidi@ARM.com
1878988SAli.Saidi@ARM.com/// Target obreak() handler: set brk address.
1888988SAli.Saidi@ARM.comSyscallReturn obreakFunc(SyscallDesc *desc, int num,
1898988SAli.Saidi@ARM.com                         Process *p, ExecContext *xc);
1908988SAli.Saidi@ARM.com
1918988SAli.Saidi@ARM.com/// Target close() handler.
1928988SAli.Saidi@ARM.comSyscallReturn closeFunc(SyscallDesc *desc, int num,
1938988SAli.Saidi@ARM.com                        Process *p, ExecContext *xc);
1948988SAli.Saidi@ARM.com
1958988SAli.Saidi@ARM.com/// Target read() handler.
1968988SAli.Saidi@ARM.comSyscallReturn readFunc(SyscallDesc *desc, int num,
1975875Ssteve.reinhardt@amd.com                       Process *p, ExecContext *xc);
1985875Ssteve.reinhardt@amd.com
19910766Sandreas.hansson@arm.com/// Target write() handler.
2005314SN/ASyscallReturn writeFunc(SyscallDesc *desc, int num,
2015314SN/A                        Process *p, ExecContext *xc);
2025314SN/A
2035314SN/A/// Target lseek() handler.
2045314SN/ASyscallReturn lseekFunc(SyscallDesc *desc, int num,
20510764Sandreas.hansson@arm.com                        Process *p, ExecContext *xc);
20611197Sandreas.hansson@arm.com
2072810SN/A/// Target munmap() handler.
20810764Sandreas.hansson@arm.comSyscallReturn munmapFunc(SyscallDesc *desc, int num,
20910764Sandreas.hansson@arm.com                         Process *p, ExecContext *xc);
21010028SGiacomo.Gabrielli@arm.com
21110764Sandreas.hansson@arm.com/// Target gethostname() handler.
2124666SN/ASyscallReturn gethostnameFunc(SyscallDesc *desc, int num,
2134626SN/A                              Process *p, ExecContext *xc);
2145730SSteve.Reinhardt@amd.com
21511197Sandreas.hansson@arm.com/// Target unlink() handler.
2164626SN/ASyscallReturn unlinkFunc(SyscallDesc *desc, int num,
2174626SN/A                         Process *p, ExecContext *xc);
2184908SN/A
2199725Sandreas.hansson@arm.com/// Target rename() handler.
2204626SN/ASyscallReturn renameFunc(SyscallDesc *desc, int num,
2215875Ssteve.reinhardt@amd.com                         Process *p, ExecContext *xc);
2225875Ssteve.reinhardt@amd.com
2235875Ssteve.reinhardt@amd.com
22410764Sandreas.hansson@arm.com/// Target truncate() handler.
2259725Sandreas.hansson@arm.comSyscallReturn truncateFunc(SyscallDesc *desc, int num,
2264668SN/A                           Process *p, ExecContext *xc);
2272810SN/A
2282810SN/A
2294908SN/A/// Target ftruncate() handler.
2305318SN/ASyscallReturn ftruncateFunc(SyscallDesc *desc, int num,
2315318SN/A                            Process *p, ExecContext *xc);
2325318SN/A
2335318SN/A
2345318SN/A/// Target chown() handler.
2355318SN/ASyscallReturn chownFunc(SyscallDesc *desc, int num,
2365318SN/A                        Process *p, ExecContext *xc);
2379725Sandreas.hansson@arm.com
2385318SN/A
2395318SN/A/// Target fchown() handler.
2404908SN/ASyscallReturn fchownFunc(SyscallDesc *desc, int num,
24110679Sandreas.hansson@arm.com                         Process *p, ExecContext *xc);
2424908SN/A
2434908SN/A/// Target fnctl() handler.
2445730SSteve.Reinhardt@amd.comSyscallReturn fcntlFunc(SyscallDesc *desc, int num,
2454908SN/A                        Process *process, ExecContext *xc);
2464908SN/A
2474908SN/A/// Target setuid() handler.
2484908SN/ASyscallReturn setuidFunc(SyscallDesc *desc, int num,
2494908SN/A                               Process *p, ExecContext *xc);
2504908SN/A
25110424Sandreas.hansson@arm.com/// Target getpid() handler.
2524908SN/ASyscallReturn getpidFunc(SyscallDesc *desc, int num,
25310679Sandreas.hansson@arm.com                               Process *p, ExecContext *xc);
2547667Ssteve.reinhardt@amd.com
2557667Ssteve.reinhardt@amd.com/// Target getuid() handler.
2564908SN/ASyscallReturn getuidFunc(SyscallDesc *desc, int num,
2574908SN/A                               Process *p, ExecContext *xc);
2584908SN/A
2599725Sandreas.hansson@arm.com/// Target getgid() handler.
2604908SN/ASyscallReturn getgidFunc(SyscallDesc *desc, int num,
2614908SN/A                               Process *p, ExecContext *xc);
2624908SN/A
2634908SN/A/// Target getppid() handler.
2644908SN/ASyscallReturn getppidFunc(SyscallDesc *desc, int num,
2652810SN/A                               Process *p, ExecContext *xc);
2662810SN/A
2672810SN/A/// Target geteuid() handler.
2689725Sandreas.hansson@arm.comSyscallReturn geteuidFunc(SyscallDesc *desc, int num,
2699725Sandreas.hansson@arm.com                               Process *p, ExecContext *xc);
2709725Sandreas.hansson@arm.com
2712810SN/A/// Target getegid() handler.
2722810SN/ASyscallReturn getegidFunc(SyscallDesc *desc, int num,
2732810SN/A                               Process *p, ExecContext *xc);
2742810SN/A
2752810SN/A
2762810SN/A
2772810SN/A/// Pseudo Funcs  - These functions use a different return convension,
27811197Sandreas.hansson@arm.com/// returning a second value in a register other than the normal return register
27911197Sandreas.hansson@arm.comSyscallReturn pipePseudoFunc(SyscallDesc *desc, int num,
2802810SN/A                             Process *process, ExecContext *xc);
28110768Sandreas.hansson@arm.com
28210768Sandreas.hansson@arm.com/// Target getpidPseudo() handler.
28310768Sandreas.hansson@arm.comSyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num,
28410768Sandreas.hansson@arm.com                               Process *p, ExecContext *xc);
28510768Sandreas.hansson@arm.com
28610768Sandreas.hansson@arm.com/// Target getuidPseudo() handler.
28710768Sandreas.hansson@arm.comSyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num,
28810768Sandreas.hansson@arm.com                               Process *p, ExecContext *xc);
28910768Sandreas.hansson@arm.com
29011197Sandreas.hansson@arm.com/// Target getgidPseudo() handler.
29111197Sandreas.hansson@arm.comSyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num,
29211197Sandreas.hansson@arm.com                               Process *p, ExecContext *xc);
29311197Sandreas.hansson@arm.com
2944903SN/A
2954903SN/A/// This struct is used to build an target-OS-dependent table that
2964903SN/A/// maps the target's open() flags to the host open() flags.
2974903SN/Astruct OpenFlagTransTable {
2984903SN/A    int tgtFlag;	//!< Target system flag value.
2994903SN/A    int hostFlag;	//!< Corresponding host system flag value.
3007667Ssteve.reinhardt@amd.com};
3017667Ssteve.reinhardt@amd.com
3027667Ssteve.reinhardt@amd.com
3037667Ssteve.reinhardt@amd.com
3044903SN/A/// A readable name for 1,000,000, for converting microseconds to seconds.
3059725Sandreas.hansson@arm.comconst int one_million = 1000000;
3067667Ssteve.reinhardt@amd.com
3077667Ssteve.reinhardt@amd.com/// Approximate seconds since the epoch (1/1/1970).  About a billion,
3084903SN/A/// by my reckoning.  We want to keep this a constant (not use the
3097667Ssteve.reinhardt@amd.com/// real-world time) to keep simulations repeatable.
3107667Ssteve.reinhardt@amd.comconst unsigned seconds_since_epoch = 1000000000;
3119725Sandreas.hansson@arm.com
3124665SN/A/// Helper function to convert current elapsed time to seconds and
3135318SN/A/// microseconds.
3145318SN/Atemplate <class T1, class T2>
3155318SN/Avoid
3165318SN/AgetElapsedTime(T1 &sec, T2 &usec)
3179725Sandreas.hansson@arm.com{
3182810SN/A    int elapsed_usecs = curTick / Clock::Int::us;
3194665SN/A    sec = elapsed_usecs / one_million;
3204665SN/A    usec = elapsed_usecs % one_million;
3214902SN/A}
3224902SN/A
3234665SN/A//////////////////////////////////////////////////////////////////////
32410725Sandreas.hansson@arm.com//
3259663Suri.wiener@arm.com// The following emulation functions are generic, but need to be
3264910SN/A// templated to account for differences in types, constants, etc.
3274903SN/A//
3284903SN/A//////////////////////////////////////////////////////////////////////
3294903SN/A
3304903SN/A/// Target ioctl() handler.  For the most part, programs call ioctl()
3314903SN/A/// only to find out if their stdout is a tty, to determine whether to
3324903SN/A/// do line or block buffering.
3334903SN/Atemplate <class OS>
3344903SN/ASyscallReturn
3354903SN/AioctlFunc(SyscallDesc *desc, int callnum, Process *process,
3364903SN/A          ExecContext *xc)
3374903SN/A{
3384903SN/A    int fd = xc->getSyscallArg(0);
3394903SN/A    unsigned req = xc->getSyscallArg(1);
3404903SN/A
3419725Sandreas.hansson@arm.com    DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", fd, req);
3429725Sandreas.hansson@arm.com
3434903SN/A    if (fd < 0 || process->sim_fd(fd) < 0) {
3444903SN/A        // doesn't map to any simulator fd: not a valid target fd
3454902SN/A        return -EBADF;
3464902SN/A    }
3474665SN/A
3484903SN/A    switch (req) {
3494903SN/A      case OS::TIOCISATTY:
3504903SN/A      case OS::TIOCGETP:
3514903SN/A      case OS::TIOCSETP:
3524903SN/A      case OS::TIOCSETN:
3539725Sandreas.hansson@arm.com      case OS::TIOCSETC:
3544903SN/A      case OS::TIOCGETC:
3554903SN/A      case OS::TIOCGETS:
3567667Ssteve.reinhardt@amd.com      case OS::TIOCGETA:
3574665SN/A        return -ENOTTY;
3584903SN/A
3594903SN/A      default:
3604902SN/A        fatal("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ 0x%llx\n",
3614665SN/A              fd, req, xc->readPC());
3624665SN/A    }
3637667Ssteve.reinhardt@amd.com}
3647667Ssteve.reinhardt@amd.com
3657667Ssteve.reinhardt@amd.com/// Target open() handler.
36611271Sandreas.hansson@arm.comtemplate <class OS>
3677667Ssteve.reinhardt@amd.comSyscallReturn
3687667Ssteve.reinhardt@amd.comopenFunc(SyscallDesc *desc, int callnum, Process *process,
3697667Ssteve.reinhardt@amd.com         ExecContext *xc)
37010571Sandreas.hansson@arm.com{
37111271Sandreas.hansson@arm.com    std::string path;
37211271Sandreas.hansson@arm.com
37311271Sandreas.hansson@arm.com    if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
37411271Sandreas.hansson@arm.com        return -EFAULT;
37511271Sandreas.hansson@arm.com
37611271Sandreas.hansson@arm.com    if (path == "/dev/sysdev0") {
37711271Sandreas.hansson@arm.com        // This is a memory-mapped high-resolution timer device on Alpha.
37811271Sandreas.hansson@arm.com        // We don't support it, so just punt.
37911271Sandreas.hansson@arm.com        warn("Ignoring open(%s, ...)\n", path);
38011271Sandreas.hansson@arm.com        return -ENOENT;
38111271Sandreas.hansson@arm.com    }
38211271Sandreas.hansson@arm.com
38311271Sandreas.hansson@arm.com    int tgtFlags = xc->getSyscallArg(1);
38411271Sandreas.hansson@arm.com    int mode = xc->getSyscallArg(2);
38511271Sandreas.hansson@arm.com    int hostFlags = 0;
38611271Sandreas.hansson@arm.com
38711271Sandreas.hansson@arm.com    // translate open flags
3884670SN/A    for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) {
38910582SCurtis.Dunham@arm.com        if (tgtFlags & OS::openFlagTable[i].tgtFlag) {
39011271Sandreas.hansson@arm.com            tgtFlags &= ~OS::openFlagTable[i].tgtFlag;
39110826Sstephan.diestelhorst@ARM.com            hostFlags |= OS::openFlagTable[i].hostFlag;
3924670SN/A        }
39310821Sandreas.hansson@arm.com    }
39410821Sandreas.hansson@arm.com
39510821Sandreas.hansson@arm.com    // any target flags left?
3964916SN/A    if (tgtFlags != 0)
3974670SN/A        warn("Syscall: open: cannot decode flags 0x%x", tgtFlags);
39810826Sstephan.diestelhorst@ARM.com
39910826Sstephan.diestelhorst@ARM.com#ifdef __CYGWIN32__
4004670SN/A    hostFlags |= O_BINARY;
4014670SN/A#endif
4024670SN/A
4037667Ssteve.reinhardt@amd.com    DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str());
4044670SN/A
4057667Ssteve.reinhardt@amd.com    // open the file
4067667Ssteve.reinhardt@amd.com    int fd = open(path.c_str(), hostFlags, mode);
40710821Sandreas.hansson@arm.com
4087667Ssteve.reinhardt@amd.com    return (fd == -1) ? -errno : process->alloc_fd(fd);
4097667Ssteve.reinhardt@amd.com}
4107667Ssteve.reinhardt@amd.com
4114670SN/A
4124667SN/A/// Target chmod() handler.
4134902SN/Atemplate <class OS>
4144902SN/ASyscallReturn
4154665SN/AchmodFunc(SyscallDesc *desc, int callnum, Process *process,
4164665SN/A          ExecContext *xc)
4174665SN/A{
4184665SN/A    std::string path;
4194665SN/A
4204665SN/A    if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
4219725Sandreas.hansson@arm.com        return -EFAULT;
4229725Sandreas.hansson@arm.com
4234665SN/A    uint32_t mode = xc->getSyscallArg(1);
4244665SN/A    mode_t hostMode = 0;
4254665SN/A
4264903SN/A    // XXX translate mode flags via OS::something???
4279725Sandreas.hansson@arm.com    hostMode = mode;
4284903SN/A
4294903SN/A    // do the chmod
4309725Sandreas.hansson@arm.com    int result = chmod(path.c_str(), hostMode);
4314903SN/A    if (result < 0)
4329725Sandreas.hansson@arm.com        return -errno;
4339725Sandreas.hansson@arm.com
4344665SN/A    return 0;
4354665SN/A}
4362810SN/A
4372810SN/A
4382810SN/A/// Target fchmod() handler.
4392810SN/Atemplate <class OS>
44011177Sandreas.hansson@arm.comSyscallReturn
4414668SN/AfchmodFunc(SyscallDesc *desc, int callnum, Process *process,
44211177Sandreas.hansson@arm.com           ExecContext *xc)
44311177Sandreas.hansson@arm.com{
4445270SN/A    int fd = xc->getSyscallArg(0);
4455270SN/A    if (fd < 0 || process->sim_fd(fd) < 0) {
4465270SN/A        // doesn't map to any simulator fd: not a valid target fd
4475270SN/A        return -EBADF;
4485270SN/A    }
4495270SN/A
4505270SN/A    uint32_t mode = xc->getSyscallArg(1);
4515270SN/A    mode_t hostMode = 0;
4529725Sandreas.hansson@arm.com
4539725Sandreas.hansson@arm.com    // XXX translate mode flags via OS::someting???
4545318SN/A    hostMode = mode;
4555318SN/A
4565318SN/A    // do the fchmod
4579725Sandreas.hansson@arm.com    int result = fchmod(process->sim_fd(fd), hostMode);
4585270SN/A    if (result < 0)
4599725Sandreas.hansson@arm.com        return -errno;
4609725Sandreas.hansson@arm.com
4615270SN/A    return 0;
4624668SN/A}
4634668SN/A
4644668SN/A
4655314SN/A/// Target stat() handler.
4665314SN/Atemplate <class OS>
4675314SN/ASyscallReturn
4685314SN/AstatFunc(SyscallDesc *desc, int callnum, Process *process,
4695314SN/A         ExecContext *xc)
4705314SN/A{
4715314SN/A    std::string path;
47210764Sandreas.hansson@arm.com
4735314SN/A    if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
4745314SN/A    return -EFAULT;
4759725Sandreas.hansson@arm.com
4769725Sandreas.hansson@arm.com    struct stat hostBuf;
4775314SN/A    int result = stat(path.c_str(), &hostBuf);
4785314SN/A
4795314SN/A    if (result < 0)
4805314SN/A        return -errno;
4814668SN/A
4825314SN/A    OS::copyOutStatBuf(xc->getMemPort(), xc->getSyscallArg(1), &hostBuf);
4832810SN/A
48410725Sandreas.hansson@arm.com    return 0;
48510764Sandreas.hansson@arm.com}
48610028SGiacomo.Gabrielli@arm.com
4875730SSteve.Reinhardt@amd.com
48811197Sandreas.hansson@arm.com/// Target fstat64() handler.
4895730SSteve.Reinhardt@amd.comtemplate <class OS>
4905314SN/ASyscallReturn
4915314SN/Afstat64Func(SyscallDesc *desc, int callnum, Process *process,
4925314SN/A            ExecContext *xc)
4935314SN/A{
4947667Ssteve.reinhardt@amd.com    int fd = xc->getSyscallArg(0);
4957667Ssteve.reinhardt@amd.com    if (fd < 0 || process->sim_fd(fd) < 0) {
4962810SN/A        // doesn't map to any simulator fd: not a valid target fd
4975314SN/A        return -EBADF;
4989725Sandreas.hansson@arm.com    }
4999725Sandreas.hansson@arm.com
5005314SN/A#if BSD_HOST
5019725Sandreas.hansson@arm.com    struct stat  hostBuf;
5022810SN/A    int result = fstat(process->sim_fd(fd), &hostBuf);
5032810SN/A#else
5042810SN/A    struct stat64  hostBuf;
5059663Suri.wiener@arm.com    int result = fstat64(process->sim_fd(fd), &hostBuf);
5069663Suri.wiener@arm.com#endif
5079663Suri.wiener@arm.com
5089663Suri.wiener@arm.com    if (result < 0)
5099663Suri.wiener@arm.com        return -errno;
5109663Suri.wiener@arm.com
5119663Suri.wiener@arm.com    OS::copyOutStat64Buf(xc->getMemPort(), fd, xc->getSyscallArg(1), &hostBuf);
512
513    return 0;
514}
515
516
517/// Target lstat() handler.
518template <class OS>
519SyscallReturn
520lstatFunc(SyscallDesc *desc, int callnum, Process *process,
521          ExecContext *xc)
522{
523    std::string path;
524
525    if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
526      return -EFAULT;
527
528    struct stat hostBuf;
529    int result = lstat(path.c_str(), &hostBuf);
530
531    if (result < 0)
532        return -errno;
533
534    OS::copyOutStatBuf(xc->getMemPort(), xc->getSyscallArg(1), &hostBuf);
535
536    return 0;
537}
538
539/// Target lstat64() handler.
540template <class OS>
541SyscallReturn
542lstat64Func(SyscallDesc *desc, int callnum, Process *process,
543            ExecContext *xc)
544{
545    std::string path;
546
547    if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
548      return -EFAULT;
549
550#if BSD_HOST
551    struct stat hostBuf;
552    int result = lstat(path.c_str(), &hostBuf);
553#else
554    struct stat64 hostBuf;
555    int result = lstat64(path.c_str(), &hostBuf);
556#endif
557
558    if (result < 0)
559        return -errno;
560
561    OS::copyOutStat64Buf(xc->getMemPort(), -1, xc->getSyscallArg(1), &hostBuf);
562
563    return 0;
564}
565
566/// Target fstat() handler.
567template <class OS>
568SyscallReturn
569fstatFunc(SyscallDesc *desc, int callnum, Process *process,
570          ExecContext *xc)
571{
572    int fd = process->sim_fd(xc->getSyscallArg(0));
573
574    DPRINTF(SyscallVerbose, "fstat(%d, ...)\n", fd);
575
576    if (fd < 0)
577        return -EBADF;
578
579    struct stat hostBuf;
580    int result = fstat(fd, &hostBuf);
581
582    if (result < 0)
583        return -errno;
584
585    OS::copyOutStatBuf(xc->getMemPort(), xc->getSyscallArg(1), &hostBuf);
586
587    return 0;
588}
589
590
591/// Target statfs() handler.
592template <class OS>
593SyscallReturn
594statfsFunc(SyscallDesc *desc, int callnum, Process *process,
595           ExecContext *xc)
596{
597    std::string path;
598
599    if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
600      return -EFAULT;
601
602    struct statfs hostBuf;
603    int result = statfs(path.c_str(), &hostBuf);
604
605    if (result < 0)
606        return -errno;
607
608    OS::copyOutStatfsBuf(xc->getMemPort(), xc->getSyscallArg(1), &hostBuf);
609
610    return 0;
611}
612
613
614/// Target fstatfs() handler.
615template <class OS>
616SyscallReturn
617fstatfsFunc(SyscallDesc *desc, int callnum, Process *process,
618            ExecContext *xc)
619{
620    int fd = process->sim_fd(xc->getSyscallArg(0));
621
622    if (fd < 0)
623        return -EBADF;
624
625    struct statfs hostBuf;
626    int result = fstatfs(fd, &hostBuf);
627
628    if (result < 0)
629        return -errno;
630
631    OS::copyOutStatfsBuf(xc->getMemPort(), xc->getSyscallArg(1), &hostBuf);
632
633    return 0;
634}
635
636
637/// Target writev() handler.
638template <class OS>
639SyscallReturn
640writevFunc(SyscallDesc *desc, int callnum, Process *process,
641           ExecContext *xc)
642{
643    int fd = xc->getSyscallArg(0);
644    if (fd < 0 || process->sim_fd(fd) < 0) {
645        // doesn't map to any simulator fd: not a valid target fd
646        return -EBADF;
647    }
648
649    TranslatingPort *p = xc->getMemPort();
650    uint64_t tiov_base = xc->getSyscallArg(1);
651    size_t count = xc->getSyscallArg(2);
652    struct iovec hiov[count];
653    for (int i = 0; i < count; ++i)
654    {
655        typename OS::tgt_iovec tiov;
656
657        p->readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec),
658                    (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec));
659        hiov[i].iov_len = gtoh(tiov.iov_len);
660        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