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