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