syscall_emul.hh revision 2238
1360SN/A/* 21458SN/A * Copyright (c) 2003-2005 The Regents of The University of Michigan 3360SN/A * All rights reserved. 4360SN/A * 5360SN/A * Redistribution and use in source and binary forms, with or without 6360SN/A * modification, are permitted provided that the following conditions are 7360SN/A * met: redistributions of source code must retain the above copyright 8360SN/A * notice, this list of conditions and the following disclaimer; 9360SN/A * redistributions in binary form must reproduce the above copyright 10360SN/A * notice, this list of conditions and the following disclaimer in the 11360SN/A * documentation and/or other materials provided with the distribution; 12360SN/A * neither the name of the copyright holders nor the names of its 13360SN/A * contributors may be used to endorse or promote products derived from 14360SN/A * this software without specific prior written permission. 15360SN/A * 16360SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17360SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18360SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19360SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20360SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21360SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22360SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23360SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24360SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25360SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26360SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272665Ssaidi@eecs.umich.edu */ 282665Ssaidi@eecs.umich.edu 292665Ssaidi@eecs.umich.edu#ifndef __SIM_SYSCALL_EMUL_HH__ 30360SN/A#define __SIM_SYSCALL_EMUL_HH__ 31360SN/A 321354SN/A#define BSD_HOST (defined(__APPLE__) || defined(__OpenBSD__) || \ 331354SN/A defined(__FreeBSD__)) 34360SN/A 352764Sstever@eecs.umich.edu/// 362764Sstever@eecs.umich.edu/// @file syscall_emul.hh 372064SN/A/// 38360SN/A/// This file defines objects used to emulate syscalls from the target 39360SN/A/// application on the host machine. 40360SN/A 41360SN/A#include <errno.h> 42360SN/A#include <string> 43360SN/A#ifdef __CYGWIN32__ 441354SN/A#include <sys/fcntl.h> // for O_BINARY 45360SN/A#endif 461809SN/A#include <sys/uio.h> 475543Ssaidi@eecs.umich.edu 481809SN/A#include "base/intmath.hh" // for RoundUp 493113Sgblack@eecs.umich.edu#include "mem/functional/functional.hh" 503113Sgblack@eecs.umich.edu#include "arch/isa_traits.hh" // for Addr 511999SN/A 52360SN/A#include "base/trace.hh" 532474SN/A#include "cpu/exec_context.hh" 545543Ssaidi@eecs.umich.edu#include "sim/process.hh" 552462SN/A 561354SN/A/// 576216Snate@binkert.org/// System call descriptor. 582474SN/A/// 592680Sktlim@umich.educlass SyscallDesc { 602474SN/A 612474SN/A public: 621354SN/A 63360SN/A /// Typedef for target syscall handler functions. 64360SN/A typedef SyscallReturn (*FuncPtr)(SyscallDesc *, int num, 65360SN/A Process *, ExecContext *); 66360SN/A 67360SN/A const char *name; //!< Syscall name (e.g., "open"). 68360SN/A FuncPtr funcPtr; //!< Pointer to emulation function. 69360SN/A int flags; //!< Flags (see Flags enum). 70360SN/A 71378SN/A /// Flag values for controlling syscall behavior. 721450SN/A enum Flags { 733114Sgblack@eecs.umich.edu /// Don't set return regs according to funcPtr return value. 74360SN/A /// Used for syscalls with non-standard return conventions 755543Ssaidi@eecs.umich.edu /// that explicitly set the ExecContext regs (e.g., 765543Ssaidi@eecs.umich.edu /// sigreturn). 775543Ssaidi@eecs.umich.edu SuppressReturnValue = 1 78360SN/A }; 79360SN/A 80360SN/A /// Constructor. 81360SN/A SyscallDesc(const char *_name, FuncPtr _funcPtr, int _flags = 0) 82360SN/A : name(_name), funcPtr(_funcPtr), flags(_flags) 832680Sktlim@umich.edu { 84360SN/A } 85360SN/A 86360SN/A /// Emulate the syscall. Public interface for calling through funcPtr. 87360SN/A void doSyscall(int callnum, Process *proc, ExecContext *xc); 88360SN/A}; 89360SN/A 90360SN/A 91360SN/Aclass BaseBufferArg { 92360SN/A 93360SN/A public: 94360SN/A 953114Sgblack@eecs.umich.edu BaseBufferArg(Addr _addr, int _size) : addr(_addr), size(_size) 96360SN/A { 97360SN/A bufPtr = new uint8_t[size]; 98360SN/A // clear out buffer: in case we only partially populate this, 99360SN/A // and then do a copyOut(), we want to make sure we don't 100360SN/A // introduce any random junk into the simulated address space 101360SN/A memset(bufPtr, 0, size); 102360SN/A } 103360SN/A 104360SN/A virtual ~BaseBufferArg() { delete [] bufPtr; } 105360SN/A 106360SN/A // 107360SN/A // copy data into simulator space (read from target memory) 108360SN/A // 109360SN/A virtual bool copyIn(FunctionalMemory *mem) 110360SN/A { 111360SN/A mem->access(Read, addr, bufPtr, size); 112360SN/A return true; // no EFAULT detection for now 113360SN/A } 114360SN/A 115360SN/A // 116360SN/A // copy data out of simulator space (write to target memory) 1172400SN/A // 118360SN/A virtual bool copyOut(FunctionalMemory *mem) 1192461SN/A { 1205543Ssaidi@eecs.umich.edu mem->access(Write, addr, bufPtr, size); 121360SN/A return true; // no EFAULT detection for now 122360SN/A } 123360SN/A 124360SN/A protected: 125360SN/A Addr addr; 1262400SN/A int size; 127360SN/A uint8_t *bufPtr; 1282461SN/A}; 1295543Ssaidi@eecs.umich.edu 130360SN/A 131360SN/Aclass BufferArg : public BaseBufferArg 132360SN/A{ 133360SN/A public: 134360SN/A BufferArg(Addr _addr, int _size) : BaseBufferArg(_addr, _size) { } 135360SN/A void *bufferPtr() { return bufPtr; } 136360SN/A}; 137360SN/A 138360SN/Atemplate <class T> 139360SN/Aclass TypedBufferArg : public BaseBufferArg 140360SN/A{ 141360SN/A public: 142360SN/A // user can optionally specify a specific number of bytes to 1435543Ssaidi@eecs.umich.edu // allocate to deal with those structs that have variable-size 144360SN/A // arrays at the end 145360SN/A TypedBufferArg(Addr _addr, int _size = sizeof(T)) 146360SN/A : BaseBufferArg(_addr, _size) 147360SN/A { } 148360SN/A 149360SN/A // type case 150360SN/A operator T*() { return (T *)bufPtr; } 151360SN/A 152360SN/A // dereference operators 153360SN/A T &operator*() { return *((T *)bufPtr); } 154360SN/A T* operator->() { return (T *)bufPtr; } 155360SN/A T &operator[](int i) { return ((T *)bufPtr)[i]; } 156360SN/A}; 157360SN/A 158360SN/A////////////////////////////////////////////////////////////////////// 159360SN/A// 160360SN/A// The following emulation functions are generic enough that they 1615543Ssaidi@eecs.umich.edu// don't need to be recompiled for different emulated OS's. They are 1625543Ssaidi@eecs.umich.edu// defined in sim/syscall_emul.cc. 163502SN/A// 164360SN/A////////////////////////////////////////////////////////////////////// 165360SN/A 166360SN/A 167360SN/A/// Handler for unimplemented syscalls that we haven't thought about. 168360SN/ASyscallReturn unimplementedFunc(SyscallDesc *desc, int num, 169360SN/A Process *p, ExecContext *xc); 170360SN/A 171360SN/A/// Handler for unimplemented syscalls that we never intend to 172360SN/A/// implement (signal handling, etc.) and should not affect the correct 173360SN/A/// behavior of the program. Print a warning only if the appropriate 174360SN/A/// trace flag is enabled. Return success to the target program. 175378SN/ASyscallReturn ignoreFunc(SyscallDesc *desc, int num, 1761706SN/A Process *p, ExecContext *xc); 1773114Sgblack@eecs.umich.edu 178378SN/A/// Target exit() handler: terminate simulation. 179378SN/ASyscallReturn exitFunc(SyscallDesc *desc, int num, 180378SN/A Process *p, ExecContext *xc); 181378SN/A 182378SN/A/// Target getpagesize() handler. 1831706SN/ASyscallReturn getpagesizeFunc(SyscallDesc *desc, int num, 1843114Sgblack@eecs.umich.edu Process *p, ExecContext *xc); 185360SN/A 1866109Ssanchezd@stanford.edu/// Target obreak() handler: set brk address. 1871706SN/ASyscallReturn obreakFunc(SyscallDesc *desc, int num, 1883114Sgblack@eecs.umich.edu Process *p, ExecContext *xc); 189378SN/A 1906109Ssanchezd@stanford.edu/// Target close() handler. 1916109Ssanchezd@stanford.eduSyscallReturn closeFunc(SyscallDesc *desc, int num, 1926109Ssanchezd@stanford.edu Process *p, ExecContext *xc); 1936109Ssanchezd@stanford.edu 194378SN/A/// Target read() handler. 1951706SN/ASyscallReturn readFunc(SyscallDesc *desc, int num, 1963114Sgblack@eecs.umich.edu Process *p, ExecContext *xc); 197378SN/A 1985748SSteve.Reinhardt@amd.com/// Target write() handler. 1995748SSteve.Reinhardt@amd.comSyscallReturn writeFunc(SyscallDesc *desc, int num, 2005748SSteve.Reinhardt@amd.com Process *p, ExecContext *xc); 201378SN/A 202378SN/A/// Target lseek() handler. 2031706SN/ASyscallReturn lseekFunc(SyscallDesc *desc, int num, 2043114Sgblack@eecs.umich.edu Process *p, ExecContext *xc); 205378SN/A 206378SN/A/// Target munmap() handler. 2071706SN/ASyscallReturn munmapFunc(SyscallDesc *desc, int num, 2083114Sgblack@eecs.umich.edu Process *p, ExecContext *xc); 209378SN/A 210378SN/A/// Target gethostname() handler. 2111706SN/ASyscallReturn gethostnameFunc(SyscallDesc *desc, int num, 2123114Sgblack@eecs.umich.edu Process *p, ExecContext *xc); 213378SN/A 214378SN/A/// Target unlink() handler. 2151706SN/ASyscallReturn unlinkFunc(SyscallDesc *desc, int num, 2163114Sgblack@eecs.umich.edu Process *p, ExecContext *xc); 217378SN/A 2184118Sgblack@eecs.umich.edu/// Target rename() handler. 2194118Sgblack@eecs.umich.eduSyscallReturn renameFunc(SyscallDesc *desc, int num, 2204118Sgblack@eecs.umich.edu Process *p, ExecContext *xc); 2214118Sgblack@eecs.umich.edu 222378SN/A 2231706SN/A/// Target truncate() handler. 2243114Sgblack@eecs.umich.eduSyscallReturn truncateFunc(SyscallDesc *desc, int num, 225378SN/A Process *p, ExecContext *xc); 226378SN/A 2271706SN/A 2283114Sgblack@eecs.umich.edu/// Target ftruncate() handler. 229360SN/ASyscallReturn ftruncateFunc(SyscallDesc *desc, int num, 2305513SMichael.Adler@intel.com Process *p, ExecContext *xc); 2315513SMichael.Adler@intel.com 2325513SMichael.Adler@intel.com 2335513SMichael.Adler@intel.com/// Target chown() handler. 2345513SMichael.Adler@intel.comSyscallReturn chownFunc(SyscallDesc *desc, int num, 2355513SMichael.Adler@intel.com Process *p, ExecContext *xc); 2365513SMichael.Adler@intel.com 2375513SMichael.Adler@intel.com 238511SN/A/// Target fchown() handler. 2391706SN/ASyscallReturn fchownFunc(SyscallDesc *desc, int num, 2403114Sgblack@eecs.umich.edu Process *p, ExecContext *xc); 241511SN/A 2425513SMichael.Adler@intel.com/// Target fnctl() handler. 2435513SMichael.Adler@intel.comSyscallReturn fcntlFunc(SyscallDesc *desc, int num, 2445513SMichael.Adler@intel.com Process *process, ExecContext *xc); 2455513SMichael.Adler@intel.com 246511SN/A/// Target setuid() handler. 2471706SN/ASyscallReturn setuidFunc(SyscallDesc *desc, int num, 2483114Sgblack@eecs.umich.edu Process *p, ExecContext *xc); 2491706SN/A 2501706SN/A/// Target getpid() handler. 2511706SN/ASyscallReturn getpidFunc(SyscallDesc *desc, int num, 2521706SN/A Process *p, ExecContext *xc); 2533114Sgblack@eecs.umich.edu 2541706SN/A/// Target getuid() handler. 2551706SN/ASyscallReturn getuidFunc(SyscallDesc *desc, int num, 2561706SN/A Process *p, ExecContext *xc); 2571706SN/A 2583114Sgblack@eecs.umich.edu/// Target getgid() handler. 2591706SN/ASyscallReturn getgidFunc(SyscallDesc *desc, int num, 260511SN/A Process *p, ExecContext *xc); 2615513SMichael.Adler@intel.com 2625513SMichael.Adler@intel.com/// Target getppid() handler. 2635513SMichael.Adler@intel.comSyscallReturn getppidFunc(SyscallDesc *desc, int num, 2645513SMichael.Adler@intel.com Process *p, ExecContext *xc); 2655513SMichael.Adler@intel.com 2661999SN/A/// Target geteuid() handler. 2671999SN/ASyscallReturn geteuidFunc(SyscallDesc *desc, int num, 2683114Sgblack@eecs.umich.edu Process *p, ExecContext *xc); 2691999SN/A 2701999SN/A/// Target getegid() handler. 2711999SN/ASyscallReturn getegidFunc(SyscallDesc *desc, int num, 2721999SN/A Process *p, ExecContext *xc); 2733114Sgblack@eecs.umich.edu 2741999SN/A 2753079Sstever@eecs.umich.edu 2763079Sstever@eecs.umich.edu/// Pseudo Funcs - These functions use a different return convension, 2773114Sgblack@eecs.umich.edu/// returning a second value in a register other than the normal return register 2783079Sstever@eecs.umich.eduSyscallReturn pipePseudoFunc(SyscallDesc *desc, int num, 2792093SN/A Process *process, ExecContext *xc); 2802093SN/A 2813114Sgblack@eecs.umich.edu/// Target getpidPseudo() handler. 2822093SN/ASyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num, 2832687Sksewell@umich.edu Process *p, ExecContext *xc); 2842687Sksewell@umich.edu 2853114Sgblack@eecs.umich.edu/// Target getuidPseudo() handler. 2862687Sksewell@umich.eduSyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num, 2872238SN/A Process *p, ExecContext *xc); 2882238SN/A 2893114Sgblack@eecs.umich.edu/// Target getgidPseudo() handler. 2902238SN/ASyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num, 2912238SN/A Process *p, ExecContext *xc); 2922238SN/A 2933114Sgblack@eecs.umich.edu 2942238SN/A/// This struct is used to build an target-OS-dependent table that 2952238SN/A/// maps the target's open() flags to the host open() flags. 2962238SN/Astruct OpenFlagTransTable { 2973114Sgblack@eecs.umich.edu int tgtFlag; //!< Target system flag value. 2982238SN/A int hostFlag; //!< Corresponding host system flag value. 2992238SN/A}; 3002238SN/A 3013114Sgblack@eecs.umich.edu 3022238SN/A 3032238SN/A/// A readable name for 1,000,000, for converting microseconds to seconds. 3042238SN/Aconst int one_million = 1000000; 3053114Sgblack@eecs.umich.edu 3062238SN/A/// Approximate seconds since the epoch (1/1/1970). About a billion, 3072238SN/A/// by my reckoning. We want to keep this a constant (not use the 3082238SN/A/// real-world time) to keep simulations repeatable. 3093114Sgblack@eecs.umich.educonst unsigned seconds_since_epoch = 1000000000; 3102238SN/A 3112238SN/A/// Helper function to convert current elapsed time to seconds and 3122238SN/A/// microseconds. 3133114Sgblack@eecs.umich.edutemplate <class T1, class T2> 3142238SN/Avoid 3156109Ssanchezd@stanford.edugetElapsedTime(T1 &sec, T2 &usec) 3166109Ssanchezd@stanford.edu{ 3176109Ssanchezd@stanford.edu int elapsed_usecs = curTick / Clock::Int::us; 3182238SN/A sec = elapsed_usecs / one_million; 3192238SN/A usec = elapsed_usecs % one_million; 3202238SN/A} 3212238SN/A 3222238SN/A////////////////////////////////////////////////////////////////////// 3233114Sgblack@eecs.umich.edu// 3242238SN/A// The following emulation functions are generic, but need to be 3252238SN/A// templated to account for differences in types, constants, etc. 3262238SN/A// 3273114Sgblack@eecs.umich.edu////////////////////////////////////////////////////////////////////// 3282238SN/A 3292238SN/A/// Target ioctl() handler. For the most part, programs call ioctl() 3302238SN/A/// only to find out if their stdout is a tty, to determine whether to 3313114Sgblack@eecs.umich.edu/// do line or block buffering. 3322238SN/Atemplate <class OS> 3332238SN/ASyscallReturn 3342238SN/AioctlFunc(SyscallDesc *desc, int callnum, Process *process, 3353114Sgblack@eecs.umich.edu ExecContext *xc) 3362238SN/A{ 3372238SN/A int fd = xc->getSyscallArg(0); 3381354SN/A unsigned req = xc->getSyscallArg(1); 3391354SN/A 3401354SN/A DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", fd, req); 3411354SN/A 3421354SN/A if (fd < 0 || process->sim_fd(fd) < 0) { 3431354SN/A // doesn't map to any simulator fd: not a valid target fd 3441354SN/A return -EBADF; 3451354SN/A } 3461354SN/A 3471354SN/A switch (req) { 3481354SN/A case OS::TIOCISATTY: 3491354SN/A case OS::TIOCGETP: 3501354SN/A case OS::TIOCSETP: 3511354SN/A case OS::TIOCSETN: 3521609SN/A case OS::TIOCSETC: 3531354SN/A case OS::TIOCGETC: 3541354SN/A case OS::TIOCGETS: 3551354SN/A case OS::TIOCGETA: 3561354SN/A return -ENOTTY; 357360SN/A 358360SN/A default: 359360SN/A fatal("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ 0x%llx\n", 360360SN/A fd, req, xc->readPC()); 361360SN/A } 362360SN/A} 363360SN/A 3643113Sgblack@eecs.umich.edu/// Target open() handler. 3653113Sgblack@eecs.umich.edutemplate <class OS> 3663113Sgblack@eecs.umich.eduSyscallReturn 3673113Sgblack@eecs.umich.eduopenFunc(SyscallDesc *desc, int callnum, Process *process, 3683113Sgblack@eecs.umich.edu ExecContext *xc) 3693113Sgblack@eecs.umich.edu{ 3703113Sgblack@eecs.umich.edu std::string path; 3713113Sgblack@eecs.umich.edu 3723113Sgblack@eecs.umich.edu if (xc->mem->readString(path, xc->getSyscallArg(0)) != NoFault) 3733113Sgblack@eecs.umich.edu return -EFAULT; 3743113Sgblack@eecs.umich.edu 3753113Sgblack@eecs.umich.edu if (path == "/dev/sysdev0") { 3763113Sgblack@eecs.umich.edu // This is a memory-mapped high-resolution timer device on Alpha. 3773113Sgblack@eecs.umich.edu // We don't support it, so just punt. 3783113Sgblack@eecs.umich.edu warn("Ignoring open(%s, ...)\n", path); 3793113Sgblack@eecs.umich.edu return -ENOENT; 3804189Sgblack@eecs.umich.edu } 3814189Sgblack@eecs.umich.edu 3823113Sgblack@eecs.umich.edu int tgtFlags = xc->getSyscallArg(1); 3833113Sgblack@eecs.umich.edu int mode = xc->getSyscallArg(2); 3843113Sgblack@eecs.umich.edu int hostFlags = 0; 3853113Sgblack@eecs.umich.edu 3863113Sgblack@eecs.umich.edu // translate open flags 3873113Sgblack@eecs.umich.edu for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) { 3883113Sgblack@eecs.umich.edu if (tgtFlags & OS::openFlagTable[i].tgtFlag) { 3893277Sgblack@eecs.umich.edu tgtFlags &= ~OS::openFlagTable[i].tgtFlag; 3905515SMichael.Adler@intel.com hostFlags |= OS::openFlagTable[i].hostFlag; 3915515SMichael.Adler@intel.com } 3925515SMichael.Adler@intel.com } 3935515SMichael.Adler@intel.com 3945515SMichael.Adler@intel.com // any target flags left? 3953277Sgblack@eecs.umich.edu if (tgtFlags != 0) 3963277Sgblack@eecs.umich.edu warn("Syscall: open: cannot decode flags 0x%x", tgtFlags); 3973277Sgblack@eecs.umich.edu 3983277Sgblack@eecs.umich.edu#ifdef __CYGWIN32__ 3993277Sgblack@eecs.umich.edu hostFlags |= O_BINARY; 4003277Sgblack@eecs.umich.edu#endif 4013277Sgblack@eecs.umich.edu 4023113Sgblack@eecs.umich.edu DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str()); 4033113Sgblack@eecs.umich.edu 4043113Sgblack@eecs.umich.edu // open the file 4053113Sgblack@eecs.umich.edu int fd = open(path.c_str(), hostFlags, mode); 4063113Sgblack@eecs.umich.edu 4073113Sgblack@eecs.umich.edu return (fd == -1) ? -errno : process->alloc_fd(fd); 4083113Sgblack@eecs.umich.edu} 4093114Sgblack@eecs.umich.edu 4103113Sgblack@eecs.umich.edu 4113114Sgblack@eecs.umich.edu/// Target chmod() handler. 4123113Sgblack@eecs.umich.edutemplate <class OS> 4133114Sgblack@eecs.umich.eduSyscallReturn 4143113Sgblack@eecs.umich.educhmodFunc(SyscallDesc *desc, int callnum, Process *process, 4154061Sgblack@eecs.umich.edu ExecContext *xc) 4164061Sgblack@eecs.umich.edu{ 4174061Sgblack@eecs.umich.edu std::string path; 4183113Sgblack@eecs.umich.edu 4193113Sgblack@eecs.umich.edu if (xc->mem->readString(path, xc->getSyscallArg(0)) != NoFault) 4203113Sgblack@eecs.umich.edu return -EFAULT; 4213113Sgblack@eecs.umich.edu 4223113Sgblack@eecs.umich.edu uint32_t mode = xc->getSyscallArg(1); 4233113Sgblack@eecs.umich.edu mode_t hostMode = 0; 4243113Sgblack@eecs.umich.edu 4253113Sgblack@eecs.umich.edu // XXX translate mode flags via OS::something??? 4263113Sgblack@eecs.umich.edu hostMode = mode; 4273113Sgblack@eecs.umich.edu 4283113Sgblack@eecs.umich.edu // do the chmod 4294189Sgblack@eecs.umich.edu int result = chmod(path.c_str(), hostMode); 4304189Sgblack@eecs.umich.edu if (result < 0) 4313113Sgblack@eecs.umich.edu return -errno; 4323113Sgblack@eecs.umich.edu 4333113Sgblack@eecs.umich.edu return 0; 4343113Sgblack@eecs.umich.edu} 4353113Sgblack@eecs.umich.edu 4363113Sgblack@eecs.umich.edu 4373113Sgblack@eecs.umich.edu/// Target fchmod() handler. 4383113Sgblack@eecs.umich.edutemplate <class OS> 4393113Sgblack@eecs.umich.eduSyscallReturn 4403113Sgblack@eecs.umich.edufchmodFunc(SyscallDesc *desc, int callnum, Process *process, 4413113Sgblack@eecs.umich.edu ExecContext *xc) 4423113Sgblack@eecs.umich.edu{ 4433113Sgblack@eecs.umich.edu int fd = xc->getSyscallArg(0); 4443113Sgblack@eecs.umich.edu if (fd < 0 || process->sim_fd(fd) < 0) { 4453113Sgblack@eecs.umich.edu // doesn't map to any simulator fd: not a valid target fd 4463113Sgblack@eecs.umich.edu return -EBADF; 4473113Sgblack@eecs.umich.edu } 4483113Sgblack@eecs.umich.edu 4493113Sgblack@eecs.umich.edu uint32_t mode = xc->getSyscallArg(1); 4503113Sgblack@eecs.umich.edu mode_t hostMode = 0; 4513113Sgblack@eecs.umich.edu 4523113Sgblack@eecs.umich.edu // XXX translate mode flags via OS::someting??? 4533113Sgblack@eecs.umich.edu hostMode = mode; 4543113Sgblack@eecs.umich.edu 4553113Sgblack@eecs.umich.edu // do the fchmod 4563113Sgblack@eecs.umich.edu int result = fchmod(process->sim_fd(fd), hostMode); 4573113Sgblack@eecs.umich.edu if (result < 0) 4583113Sgblack@eecs.umich.edu return -errno; 4593113Sgblack@eecs.umich.edu 4603113Sgblack@eecs.umich.edu return 0; 4613113Sgblack@eecs.umich.edu} 4623113Sgblack@eecs.umich.edu 4633113Sgblack@eecs.umich.edu 4643113Sgblack@eecs.umich.edu/// Target stat() handler. 4653113Sgblack@eecs.umich.edutemplate <class OS> 4663113Sgblack@eecs.umich.eduSyscallReturn 4673113Sgblack@eecs.umich.edustatFunc(SyscallDesc *desc, int callnum, Process *process, 4683113Sgblack@eecs.umich.edu ExecContext *xc) 469378SN/A{ 470378SN/A std::string path; 471378SN/A 472360SN/A if (xc->mem->readString(path, xc->getSyscallArg(0)) != NoFault) 4731450SN/A return -EFAULT; 4743114Sgblack@eecs.umich.edu 4752680Sktlim@umich.edu struct stat hostBuf; 476360SN/A int result = stat(path.c_str(), &hostBuf); 4775958Sgblack@eecs.umich.edu 4785958Sgblack@eecs.umich.edu if (result < 0) 479360SN/A return -errno; 4801969SN/A 481360SN/A OS::copyOutStatBuf(xc->mem, xc->getSyscallArg(1), &hostBuf); 482360SN/A 483360SN/A return 0; 4841458SN/A} 485360SN/A 486360SN/A 487360SN/A/// Target fstat64() handler. 4884131Sbinkertn@umich.edutemplate <class OS> 4894131Sbinkertn@umich.eduSyscallReturn 4904131Sbinkertn@umich.edufstat64Func(SyscallDesc *desc, int callnum, Process *process, 4914131Sbinkertn@umich.edu ExecContext *xc) 4924131Sbinkertn@umich.edu{ 4934131Sbinkertn@umich.edu int fd = xc->getSyscallArg(0); 4944131Sbinkertn@umich.edu if (fd < 0 || process->sim_fd(fd) < 0) { 4954131Sbinkertn@umich.edu // doesn't map to any simulator fd: not a valid target fd 4961458SN/A return -EBADF; 497360SN/A } 498360SN/A 4991706SN/A#if BSD_HOST 5002680Sktlim@umich.edu struct stat hostBuf; 501360SN/A int result = fstat(process->sim_fd(fd), &hostBuf); 502360SN/A#else 503360SN/A struct stat64 hostBuf; 504378SN/A int result = fstat64(process->sim_fd(fd), &hostBuf); 505360SN/A#endif 5061450SN/A 5073114Sgblack@eecs.umich.edu if (result < 0) 5082680Sktlim@umich.edu return -errno; 509360SN/A 510360SN/A OS::copyOutStat64Buf(xc->mem, fd, xc->getSyscallArg(1), &hostBuf); 511360SN/A 5125958Sgblack@eecs.umich.edu return 0; 5131458SN/A} 514360SN/A 515360SN/A 516360SN/A/// Target lstat() handler. 517360SN/Atemplate <class OS> 5181706SN/ASyscallReturn 5191458SN/AlstatFunc(SyscallDesc *desc, int callnum, Process *process, 520360SN/A ExecContext *xc) 521360SN/A{ 5225958Sgblack@eecs.umich.edu std::string path; 5235958Sgblack@eecs.umich.edu 524360SN/A if (xc->mem->readString(path, xc->getSyscallArg(0)) != NoFault) 525360SN/A return -EFAULT; 526360SN/A 527360SN/A struct stat hostBuf; 528360SN/A int result = lstat(path.c_str(), &hostBuf); 529360SN/A 530360SN/A if (result < 0) 531360SN/A return -errno; 532360SN/A 533360SN/A OS::copyOutStatBuf(xc->mem, xc->getSyscallArg(1), &hostBuf); 534360SN/A 535360SN/A return 0; 5361706SN/A} 537360SN/A 538360SN/A/// Target lstat64() handler. 539360SN/Atemplate <class OS> 540360SN/ASyscallReturn 541360SN/Alstat64Func(SyscallDesc *desc, int callnum, Process *process, 5423669Sbinkertn@umich.edu ExecContext *xc) 5433669Sbinkertn@umich.edu{ 5443669Sbinkertn@umich.edu std::string path; 5451706SN/A 5461706SN/A if (xc->mem->readString(path, xc->getSyscallArg(0)) != NoFault) 5475795Ssaidi@eecs.umich.edu return -EFAULT; 5485795Ssaidi@eecs.umich.edu 5495795Ssaidi@eecs.umich.edu#if BSD_HOST 5505795Ssaidi@eecs.umich.edu struct stat hostBuf; 5515795Ssaidi@eecs.umich.edu int result = lstat(path.c_str(), &hostBuf); 5525795Ssaidi@eecs.umich.edu#else 5535795Ssaidi@eecs.umich.edu struct stat64 hostBuf; 5545795Ssaidi@eecs.umich.edu int result = lstat64(path.c_str(), &hostBuf); 5555795Ssaidi@eecs.umich.edu#endif 5565795Ssaidi@eecs.umich.edu 5575795Ssaidi@eecs.umich.edu if (result < 0) 558360SN/A return -errno; 559360SN/A 560360SN/A OS::copyOutStat64Buf(xc->mem, -1, xc->getSyscallArg(1), &hostBuf); 561360SN/A 5621999SN/A return 0; 5631999SN/A} 5641999SN/A 5653114Sgblack@eecs.umich.edu/// Target fstat() handler. 5662680Sktlim@umich.edutemplate <class OS> 5671999SN/ASyscallReturn 5681999SN/AfstatFunc(SyscallDesc *desc, int callnum, Process *process, 5691999SN/A ExecContext *xc) 5705958Sgblack@eecs.umich.edu{ 5711999SN/A int fd = process->sim_fd(xc->getSyscallArg(0)); 5721999SN/A 5735958Sgblack@eecs.umich.edu DPRINTF(SyscallVerbose, "fstat(%d, ...)\n", fd); 5741999SN/A 5751999SN/A if (fd < 0) 5761999SN/A return -EBADF; 5771999SN/A 5781999SN/A struct stat hostBuf; 5793669Sbinkertn@umich.edu int result = fstat(fd, &hostBuf); 5803669Sbinkertn@umich.edu 5813669Sbinkertn@umich.edu if (result < 0) 5821999SN/A return -errno; 5831999SN/A 5841999SN/A OS::copyOutStatBuf(xc->mem, xc->getSyscallArg(1), &hostBuf); 5852218SN/A return 0; 5861999SN/A} 5871999SN/A 5881999SN/A 5891999SN/A/// Target statfs() handler. 5901999SN/Atemplate <class OS> 5911999SN/ASyscallReturn 5921999SN/AstatfsFunc(SyscallDesc *desc, int callnum, Process *process, 5931999SN/A ExecContext *xc) 5943114Sgblack@eecs.umich.edu{ 5952680Sktlim@umich.edu std::string path; 5961999SN/A 5975958Sgblack@eecs.umich.edu if (xc->mem->readString(path, xc->getSyscallArg(0)) != NoFault) 5981999SN/A return -EFAULT; 5991999SN/A 6001999SN/A struct statfs hostBuf; 6011999SN/A int result = statfs(path.c_str(), &hostBuf); 6021999SN/A 6035958Sgblack@eecs.umich.edu if (result < 0) 6041999SN/A return -errno; 6051999SN/A 6061999SN/A OS::copyOutStatfsBuf(xc->mem, xc->getSyscallArg(1), &hostBuf); 6071999SN/A 6081999SN/A return 0; 6091999SN/A} 6101999SN/A 6111999SN/A 6122218SN/A/// Target fstatfs() handler. 6131999SN/Atemplate <class OS> 6141999SN/ASyscallReturn 6151999SN/AfstatfsFunc(SyscallDesc *desc, int callnum, Process *process, 6161999SN/A ExecContext *xc) 6175877Shsul@eecs.umich.edu{ 6185877Shsul@eecs.umich.edu int fd = process->sim_fd(xc->getSyscallArg(0)); 6195877Shsul@eecs.umich.edu 6205877Shsul@eecs.umich.edu if (fd < 0) 6215877Shsul@eecs.umich.edu return -EBADF; 6225958Sgblack@eecs.umich.edu 6235958Sgblack@eecs.umich.edu struct statfs hostBuf; 6245958Sgblack@eecs.umich.edu int result = fstatfs(fd, &hostBuf); 6255958Sgblack@eecs.umich.edu 6265877Shsul@eecs.umich.edu if (result < 0) 6275877Shsul@eecs.umich.edu return -errno; 6285877Shsul@eecs.umich.edu 6295877Shsul@eecs.umich.edu OS::copyOutStatfsBuf(xc->mem, xc->getSyscallArg(1), &hostBuf); 6305877Shsul@eecs.umich.edu 6315877Shsul@eecs.umich.edu return 0; 6325877Shsul@eecs.umich.edu} 6335877Shsul@eecs.umich.edu 6345877Shsul@eecs.umich.edu 6355877Shsul@eecs.umich.edu/// Target writev() handler. 6365877Shsul@eecs.umich.edutemplate <class OS> 6375877Shsul@eecs.umich.eduSyscallReturn 6385877Shsul@eecs.umich.eduwritevFunc(SyscallDesc *desc, int callnum, Process *process, 6395877Shsul@eecs.umich.edu ExecContext *xc) 6405877Shsul@eecs.umich.edu{ 6415877Shsul@eecs.umich.edu int fd = xc->getSyscallArg(0); 6425877Shsul@eecs.umich.edu if (fd < 0 || process->sim_fd(fd) < 0) { 6435877Shsul@eecs.umich.edu // doesn't map to any simulator fd: not a valid target fd 6445877Shsul@eecs.umich.edu return -EBADF; 6455877Shsul@eecs.umich.edu } 6465877Shsul@eecs.umich.edu 6475877Shsul@eecs.umich.edu uint64_t tiov_base = xc->getSyscallArg(1); 6485877Shsul@eecs.umich.edu size_t count = xc->getSyscallArg(2); 6495877Shsul@eecs.umich.edu struct iovec hiov[count]; 6505877Shsul@eecs.umich.edu for (int i = 0; i < count; ++i) 6515877Shsul@eecs.umich.edu { 6525877Shsul@eecs.umich.edu typename OS::tgt_iovec tiov; 6535877Shsul@eecs.umich.edu xc->mem->access(Read, tiov_base + i*sizeof(typename OS::tgt_iovec), 6545877Shsul@eecs.umich.edu &tiov, sizeof(typename OS::tgt_iovec)); 6555877Shsul@eecs.umich.edu hiov[i].iov_len = gtoh(tiov.iov_len); 6565877Shsul@eecs.umich.edu hiov[i].iov_base = new char [hiov[i].iov_len]; 6575877Shsul@eecs.umich.edu xc->mem->access(Read, gtoh(tiov.iov_base), 6585877Shsul@eecs.umich.edu hiov[i].iov_base, hiov[i].iov_len); 6595877Shsul@eecs.umich.edu } 6605877Shsul@eecs.umich.edu 6615877Shsul@eecs.umich.edu int result = writev(process->sim_fd(fd), hiov, count); 6621999SN/A 663378SN/A for (int i = 0; i < count; ++i) 664360SN/A { 6651450SN/A delete [] (char *)hiov[i].iov_base; 6663114Sgblack@eecs.umich.edu } 6672680Sktlim@umich.edu 668360SN/A if (result < 0) 669360SN/A return -errno; 670360SN/A 6715958Sgblack@eecs.umich.edu return 0; 6722400SN/A} 673360SN/A 6743669Sbinkertn@umich.edu 6753669Sbinkertn@umich.edu/// Target mmap() handler. 6763669Sbinkertn@umich.edu/// 677360SN/A/// We don't really handle mmap(). If the target is mmaping an 678360SN/A/// anonymous region or /dev/zero, we can get away with doing basically 679360SN/A/// nothing (since memory is initialized to zero and the simulator 680360SN/A/// doesn't really check addresses anyway). Always print a warning, 6812218SN/A/// since this could be seriously broken if we're not mapping 682360SN/A/// /dev/zero. 6835958Sgblack@eecs.umich.edu// 6845958Sgblack@eecs.umich.edu/// Someday we should explicitly check for /dev/zero in open, flag the 685360SN/A/// file descriptor, and fail (or implement!) a non-anonymous mmap to 6861458SN/A/// anything else. 687360SN/Atemplate <class OS> 688360SN/ASyscallReturn 689360SN/AmmapFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) 6905074Ssaidi@eecs.umich.edu{ 6915074Ssaidi@eecs.umich.edu Addr start = xc->getSyscallArg(0); 6925074Ssaidi@eecs.umich.edu uint64_t length = xc->getSyscallArg(1); 6935074Ssaidi@eecs.umich.edu // int prot = xc->getSyscallArg(2); 6945074Ssaidi@eecs.umich.edu int flags = xc->getSyscallArg(3); 6955074Ssaidi@eecs.umich.edu // int fd = p->sim_fd(xc->getSyscallArg(4)); 6965074Ssaidi@eecs.umich.edu // int offset = xc->getSyscallArg(5); 6975074Ssaidi@eecs.umich.edu 6985958Sgblack@eecs.umich.edu if (start == 0) { 6995074Ssaidi@eecs.umich.edu // user didn't give an address... pick one from our "mmap region" 7005074Ssaidi@eecs.umich.edu start = p->mmap_end; 7015074Ssaidi@eecs.umich.edu p->mmap_end += roundUp(length, TheISA::VMPageSize); 7025074Ssaidi@eecs.umich.edu if (p->nxm_start != 0) { 7035074Ssaidi@eecs.umich.edu //If we have an nxm space, make sure we haven't colided 7045208Ssaidi@eecs.umich.edu assert(p->mmap_end < p->nxm_start); 7055208Ssaidi@eecs.umich.edu } 7065208Ssaidi@eecs.umich.edu } 7075208Ssaidi@eecs.umich.edu 7085074Ssaidi@eecs.umich.edu if (!(flags & OS::TGT_MAP_ANONYMOUS)) { 7095074Ssaidi@eecs.umich.edu warn("allowing mmap of file @ fd %d. " 7105208Ssaidi@eecs.umich.edu "This will break if not /dev/zero.", xc->getSyscallArg(4)); 7115074Ssaidi@eecs.umich.edu } 7125074Ssaidi@eecs.umich.edu 7135074Ssaidi@eecs.umich.edu return start; 7145074Ssaidi@eecs.umich.edu} 7155958Sgblack@eecs.umich.edu 7165958Sgblack@eecs.umich.edu/// Target getrlimit() handler. 7175074Ssaidi@eecs.umich.edutemplate <class OS> 7185074Ssaidi@eecs.umich.eduSyscallReturn 7195074Ssaidi@eecs.umich.edugetrlimitFunc(SyscallDesc *desc, int callnum, Process *process, 7205074Ssaidi@eecs.umich.edu ExecContext *xc) 7215074Ssaidi@eecs.umich.edu{ 7221999SN/A unsigned resource = xc->getSyscallArg(0); 7231999SN/A TypedBufferArg<typename OS::rlimit> rlp(xc->getSyscallArg(1)); 7241999SN/A 7253114Sgblack@eecs.umich.edu switch (resource) { 7262680Sktlim@umich.edu case OS::TGT_RLIMIT_STACK: 7271999SN/A // max stack size in bytes: make up a number (2MB for now) 7285958Sgblack@eecs.umich.edu rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; 7291999SN/A rlp->rlim_cur = htog(rlp->rlim_cur); 7301999SN/A rlp->rlim_max = htog(rlp->rlim_max); 7311999SN/A break; 7321999SN/A 7331999SN/A default: 7342764Sstever@eecs.umich.edu std::cerr << "getrlimitFunc: unimplemented resource " << resource 7352064SN/A << std::endl; 7362064SN/A abort(); 7372064SN/A break; 7382064SN/A } 7391999SN/A 7402064SN/A rlp.copyOut(xc->mem); 7411999SN/A return 0; 7421999SN/A} 7432218SN/A 7441999SN/A/// Target gettimeofday() handler. 7455958Sgblack@eecs.umich.edutemplate <class OS> 7463114Sgblack@eecs.umich.eduSyscallReturn 7471999SN/AgettimeofdayFunc(SyscallDesc *desc, int callnum, Process *process, 7481999SN/A ExecContext *xc) 7491999SN/A{ 7501999SN/A TypedBufferArg<typename OS::timeval> tp(xc->getSyscallArg(0)); 7511999SN/A 752378SN/A getElapsedTime(tp->tv_sec, tp->tv_usec); 753360SN/A tp->tv_sec += seconds_since_epoch; 7541450SN/A tp->tv_sec = htog(tp->tv_sec); 7553114Sgblack@eecs.umich.edu tp->tv_usec = htog(tp->tv_usec); 7562680Sktlim@umich.edu 757360SN/A tp.copyOut(xc->mem); 758360SN/A 759360SN/A return 0; 7605958Sgblack@eecs.umich.edu} 7612400SN/A 762360SN/A 7633669Sbinkertn@umich.edu/// Target utimes() handler. 7643669Sbinkertn@umich.edutemplate <class OS> 7653669Sbinkertn@umich.eduSyscallReturn 766360SN/AutimesFunc(SyscallDesc *desc, int callnum, Process *process, 767360SN/A ExecContext *xc) 768360SN/A{ 769360SN/A std::string path; 7701458SN/A 771360SN/A if (xc->mem->readString(path, xc->getSyscallArg(0)) != NoFault) 7725958Sgblack@eecs.umich.edu return -EFAULT; 7735958Sgblack@eecs.umich.edu 774360SN/A TypedBufferArg<typename OS::timeval [2]> tp(xc->getSyscallArg(1)); 7751458SN/A tp.copyIn(xc->mem); 776360SN/A 777360SN/A struct timeval hostTimeval[2]; 7781999SN/A for (int i = 0; i < 2; ++i) 7791999SN/A { 7801999SN/A hostTimeval[i].tv_sec = gtoh((*tp)[i].tv_sec); 7813114Sgblack@eecs.umich.edu hostTimeval[i].tv_usec = gtoh((*tp)[i].tv_usec); 7822680Sktlim@umich.edu } 7831999SN/A int result = utimes(path.c_str(), hostTimeval); 7841999SN/A 7851999SN/A if (result < 0) 7865958Sgblack@eecs.umich.edu return -errno; 7872400SN/A 7881999SN/A return 0; 7893669Sbinkertn@umich.edu} 7903669Sbinkertn@umich.edu/// Target getrusage() function. 7913669Sbinkertn@umich.edutemplate <class OS> 7922764Sstever@eecs.umich.eduSyscallReturn 7932064SN/AgetrusageFunc(SyscallDesc *desc, int callnum, Process *process, 7942064SN/A ExecContext *xc) 7952064SN/A{ 7961999SN/A int who = xc->getSyscallArg(0); // THREAD, SELF, or CHILDREN 7971999SN/A TypedBufferArg<typename OS::rusage> rup(xc->getSyscallArg(1)); 7982064SN/A 7991999SN/A if (who != OS::TGT_RUSAGE_SELF) { 8001999SN/A // don't really handle THREAD or CHILDREN, but just warn and 8011999SN/A // plow ahead 8021999SN/A warn("getrusage() only supports RUSAGE_SELF. Parameter %d ignored.", 8035958Sgblack@eecs.umich.edu who); 8045958Sgblack@eecs.umich.edu } 8051999SN/A 8061999SN/A getElapsedTime(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec); 8071999SN/A rup->ru_utime.tv_sec = htog(rup->ru_utime.tv_sec); 8081999SN/A rup->ru_utime.tv_usec = htog(rup->ru_utime.tv_usec); 809378SN/A 810360SN/A rup->ru_stime.tv_sec = 0; 8111450SN/A rup->ru_stime.tv_usec = 0; 8123114Sgblack@eecs.umich.edu rup->ru_maxrss = 0; 8132680Sktlim@umich.edu rup->ru_ixrss = 0; 814360SN/A rup->ru_idrss = 0; 8155958Sgblack@eecs.umich.edu rup->ru_isrss = 0; 816360SN/A rup->ru_minflt = 0; 8171969SN/A rup->ru_majflt = 0; 818360SN/A rup->ru_nswap = 0; 819360SN/A rup->ru_inblock = 0; 8201458SN/A rup->ru_oublock = 0; 821360SN/A rup->ru_msgsnd = 0; 822360SN/A rup->ru_msgrcv = 0; 823360SN/A rup->ru_nsignals = 0; 824360SN/A rup->ru_nvcsw = 0; 825360SN/A rup->ru_nivcsw = 0; 8261458SN/A 827360SN/A rup.copyOut(xc->mem); 8285958Sgblack@eecs.umich.edu 8293114Sgblack@eecs.umich.edu return 0; 8302021SN/A} 8311458SN/A 832360SN/A#endif // __SIM_SYSCALL_EMUL_HH__ 833360SN/A