syscall_emul.hh revision 2474
12381SN/A/* 28853Sandreas.hansson@arm.com * Copyright (c) 2003-2005 The Regents of The University of Michigan 38711Sandreas.hansson@arm.com * All rights reserved. 48711Sandreas.hansson@arm.com * 58711Sandreas.hansson@arm.com * Redistribution and use in source and binary forms, with or without 68711Sandreas.hansson@arm.com * modification, are permitted provided that the following conditions are 78711Sandreas.hansson@arm.com * met: redistributions of source code must retain the above copyright 88711Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer; 98711Sandreas.hansson@arm.com * redistributions in binary form must reproduce the above copyright 108711Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer in the 118711Sandreas.hansson@arm.com * documentation and/or other materials provided with the distribution; 128711Sandreas.hansson@arm.com * neither the name of the copyright holders nor the names of its 138711Sandreas.hansson@arm.com * contributors may be used to endorse or promote products derived from 142381SN/A * this software without specific prior written permission. 152381SN/A * 162381SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172381SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182381SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192381SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202381SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212381SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222381SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232381SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242381SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252381SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262381SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272381SN/A */ 282381SN/A 292381SN/A#ifndef __SIM_SYSCALL_EMUL_HH__ 302381SN/A#define __SIM_SYSCALL_EMUL_HH__ 312381SN/A 322381SN/A#define BSD_HOST (defined(__APPLE__) || defined(__OpenBSD__) || \ 332381SN/A defined(__FreeBSD__)) 342381SN/A 352381SN/A/// 362381SN/A/// @file syscall_emul.hh 372381SN/A/// 382381SN/A/// This file defines objects used to emulate syscalls from the target 392665Ssaidi@eecs.umich.edu/// application on the host machine. 402665Ssaidi@eecs.umich.edu 418853Sandreas.hansson@arm.com#include <errno.h> 428922Swilliam.wang@arm.com#include <string> 432381SN/A#ifdef __CYGWIN32__ 442381SN/A#include <sys/fcntl.h> // for O_BINARY 452381SN/A#endif 462381SN/A#include <sys/uio.h> 478922Swilliam.wang@arm.com 482381SN/A#include "arch/isa_traits.hh" // for Addr 492381SN/A#include "base/chunk_generator.hh" 502381SN/A#include "base/intmath.hh" // for RoundUp 512381SN/A#include "base/misc.hh" 522381SN/A#include "base/trace.hh" 532381SN/A#include "cpu/base.hh" 542381SN/A#include "cpu/exec_context.hh" 552381SN/A#include "mem/translating_port.hh" 562381SN/A#include "mem/page_table.hh" 572381SN/A#include "sim/process.hh" 588922Swilliam.wang@arm.com 598922Swilliam.wang@arm.com/// 602407SN/A/// System call descriptor. 612407SN/A/// 622407SN/Aclass SyscallDesc { 632407SN/A 642407SN/A public: 652407SN/A 662521SN/A /// Typedef for target syscall handler functions. 679090Sandreas.hansson@arm.com typedef SyscallReturn (*FuncPtr)(SyscallDesc *, int num, 682407SN/A Process *, ExecContext *); 693401Sktlim@umich.edu 703401Sktlim@umich.edu const char *name; //!< Syscall name (e.g., "open"). 712381SN/A FuncPtr funcPtr; //!< Pointer to emulation function. 728922Swilliam.wang@arm.com int flags; //!< Flags (see Flags enum). 738922Swilliam.wang@arm.com 749087Sandreas.hansson@arm.com /// Flag values for controlling syscall behavior. 752381SN/A enum Flags { 768708Sandreas.hansson@arm.com /// Don't set return regs according to funcPtr return value. 772381SN/A /// Used for syscalls with non-standard return conventions 788922Swilliam.wang@arm.com /// that explicitly set the ExecContext regs (e.g., 798922Swilliam.wang@arm.com /// sigreturn). 808922Swilliam.wang@arm.com SuppressReturnValue = 1 818922Swilliam.wang@arm.com }; 828922Swilliam.wang@arm.com 838922Swilliam.wang@arm.com /// Constructor. 845476Snate@binkert.org SyscallDesc(const char *_name, FuncPtr _funcPtr, int _flags = 0) 852640Sstever@eecs.umich.edu : name(_name), funcPtr(_funcPtr), flags(_flags) 868965Sandreas.hansson@arm.com { 878965Sandreas.hansson@arm.com } 889031Sandreas.hansson@arm.com 898965Sandreas.hansson@arm.com /// Emulate the syscall. Public interface for calling through funcPtr. 909031Sandreas.hansson@arm.com void doSyscall(int callnum, Process *proc, ExecContext *xc); 918965Sandreas.hansson@arm.com}; 928922Swilliam.wang@arm.com 938922Swilliam.wang@arm.com 948922Swilliam.wang@arm.comclass BaseBufferArg { 958922Swilliam.wang@arm.com 968922Swilliam.wang@arm.com public: 978922Swilliam.wang@arm.com 988922Swilliam.wang@arm.com BaseBufferArg(Addr _addr, int _size) : addr(_addr), size(_size) 998922Swilliam.wang@arm.com { 1008965Sandreas.hansson@arm.com bufPtr = new uint8_t[size]; 1018922Swilliam.wang@arm.com // clear out buffer: in case we only partially populate this, 1029031Sandreas.hansson@arm.com // and then do a copyOut(), we want to make sure we don't 1038922Swilliam.wang@arm.com // introduce any random junk into the simulated address space 1048922Swilliam.wang@arm.com memset(bufPtr, 0, size); 1058922Swilliam.wang@arm.com } 1068922Swilliam.wang@arm.com 1078922Swilliam.wang@arm.com virtual ~BaseBufferArg() { delete [] bufPtr; } 1083401Sktlim@umich.edu 1092381SN/A // 1102640Sstever@eecs.umich.edu // copy data into simulator space (read from target memory) 1112640Sstever@eecs.umich.edu // 1128922Swilliam.wang@arm.com virtual bool copyIn(TranslatingPort *memport) 1134190Ssaidi@eecs.umich.edu { 1148965Sandreas.hansson@arm.com memport->readBlob(addr, bufPtr, size); 1159031Sandreas.hansson@arm.com return true; // no EFAULT detection for now 1168965Sandreas.hansson@arm.com } 1178922Swilliam.wang@arm.com 1188922Swilliam.wang@arm.com // 1198922Swilliam.wang@arm.com // copy data out of simulator space (write to target memory) 1208922Swilliam.wang@arm.com // 1218922Swilliam.wang@arm.com virtual bool copyOut(TranslatingPort *memport) 1228922Swilliam.wang@arm.com { 1238922Swilliam.wang@arm.com memport->writeBlob(addr, bufPtr, size); 1248922Swilliam.wang@arm.com return true; // no EFAULT detection for now 1258922Swilliam.wang@arm.com } 1268922Swilliam.wang@arm.com 1278922Swilliam.wang@arm.com protected: 1288922Swilliam.wang@arm.com Addr addr; 1298922Swilliam.wang@arm.com int size; 1308922Swilliam.wang@arm.com uint8_t *bufPtr; 1318975Sandreas.hansson@arm.com}; 1328975Sandreas.hansson@arm.com 1338922Swilliam.wang@arm.com 1348922Swilliam.wang@arm.comclass BufferArg : public BaseBufferArg 1358922Swilliam.wang@arm.com{ 1368922Swilliam.wang@arm.com public: 1378922Swilliam.wang@arm.com BufferArg(Addr _addr, int _size) : BaseBufferArg(_addr, _size) { } 1388922Swilliam.wang@arm.com void *bufferPtr() { return bufPtr; } 1398965Sandreas.hansson@arm.com}; 1409031Sandreas.hansson@arm.com 1418922Swilliam.wang@arm.comtemplate <class T> 1428922Swilliam.wang@arm.comclass TypedBufferArg : public BaseBufferArg 1438922Swilliam.wang@arm.com{ 1448922Swilliam.wang@arm.com public: 1458922Swilliam.wang@arm.com // user can optionally specify a specific number of bytes to 1468922Swilliam.wang@arm.com // allocate to deal with those structs that have variable-size 1478922Swilliam.wang@arm.com // arrays at the end 1488948Sandreas.hansson@arm.com TypedBufferArg(Addr _addr, int _size = sizeof(T)) 1498948Sandreas.hansson@arm.com : BaseBufferArg(_addr, _size) 1508948Sandreas.hansson@arm.com { } 1518948Sandreas.hansson@arm.com 1528948Sandreas.hansson@arm.com // type case 1538948Sandreas.hansson@arm.com operator T*() { return (T *)bufPtr; } 1548948Sandreas.hansson@arm.com 1558948Sandreas.hansson@arm.com // dereference operators 1568948Sandreas.hansson@arm.com T &operator*() { return *((T *)bufPtr); } 1578948Sandreas.hansson@arm.com T* operator->() { return (T *)bufPtr; } 1588948Sandreas.hansson@arm.com T &operator[](int i) { return ((T *)bufPtr)[i]; } 1598948Sandreas.hansson@arm.com}; 1608948Sandreas.hansson@arm.com 1618948Sandreas.hansson@arm.com////////////////////////////////////////////////////////////////////// 1628948Sandreas.hansson@arm.com// 1638948Sandreas.hansson@arm.com// The following emulation functions are generic enough that they 1648948Sandreas.hansson@arm.com// don't need to be recompiled for different emulated OS's. They are 1658948Sandreas.hansson@arm.com// defined in sim/syscall_emul.cc. 1668948Sandreas.hansson@arm.com// 1678948Sandreas.hansson@arm.com////////////////////////////////////////////////////////////////////// 1688975Sandreas.hansson@arm.com 1698975Sandreas.hansson@arm.com 1708975Sandreas.hansson@arm.com/// Handler for unimplemented syscalls that we haven't thought about. 1718975Sandreas.hansson@arm.comSyscallReturn unimplementedFunc(SyscallDesc *desc, int num, 1728975Sandreas.hansson@arm.com Process *p, ExecContext *xc); 1738975Sandreas.hansson@arm.com 1748975Sandreas.hansson@arm.com/// Handler for unimplemented syscalls that we never intend to 1758975Sandreas.hansson@arm.com/// implement (signal handling, etc.) and should not affect the correct 1768975Sandreas.hansson@arm.com/// behavior of the program. Print a warning only if the appropriate 1778975Sandreas.hansson@arm.com/// trace flag is enabled. Return success to the target program. 1788975Sandreas.hansson@arm.comSyscallReturn ignoreFunc(SyscallDesc *desc, int num, 1798948Sandreas.hansson@arm.com Process *p, ExecContext *xc); 1808948Sandreas.hansson@arm.com 1818975Sandreas.hansson@arm.com/// Target exit() handler: terminate simulation. 1828975Sandreas.hansson@arm.comSyscallReturn exitFunc(SyscallDesc *desc, int num, 1838975Sandreas.hansson@arm.com Process *p, ExecContext *xc); 1848975Sandreas.hansson@arm.com 1858975Sandreas.hansson@arm.com/// Target getpagesize() handler. 1868975Sandreas.hansson@arm.comSyscallReturn getpagesizeFunc(SyscallDesc *desc, int num, 1878975Sandreas.hansson@arm.com Process *p, ExecContext *xc); 1888948Sandreas.hansson@arm.com 1898975Sandreas.hansson@arm.com/// Target obreak() handler: set brk address. 1908922Swilliam.wang@arm.comSyscallReturn obreakFunc(SyscallDesc *desc, int num, 1918922Swilliam.wang@arm.com Process *p, ExecContext *xc); 1929087Sandreas.hansson@arm.com 1939087Sandreas.hansson@arm.com/// Target close() handler. 1949087Sandreas.hansson@arm.comSyscallReturn closeFunc(SyscallDesc *desc, int num, 1959087Sandreas.hansson@arm.com Process *p, ExecContext *xc); 1969087Sandreas.hansson@arm.com 1979087Sandreas.hansson@arm.com/// Target read() handler. 1988922Swilliam.wang@arm.comSyscallReturn readFunc(SyscallDesc *desc, int num, 1998711Sandreas.hansson@arm.com Process *p, ExecContext *xc); 2008922Swilliam.wang@arm.com 2018922Swilliam.wang@arm.com/// Target write() handler. 2028922Swilliam.wang@arm.comSyscallReturn writeFunc(SyscallDesc *desc, int num, 2038711Sandreas.hansson@arm.com Process *p, ExecContext *xc); 2048711Sandreas.hansson@arm.com 2058711Sandreas.hansson@arm.com/// Target lseek() handler. 2068922Swilliam.wang@arm.comSyscallReturn lseekFunc(SyscallDesc *desc, int num, 2072381SN/A Process *p, ExecContext *xc); 2088711Sandreas.hansson@arm.com 2098922Swilliam.wang@arm.com/// Target munmap() handler. 2108922Swilliam.wang@arm.comSyscallReturn munmapFunc(SyscallDesc *desc, int num, 2118711Sandreas.hansson@arm.com Process *p, ExecContext *xc); 2128922Swilliam.wang@arm.com 2132381SN/A/// Target gethostname() handler. 2142381SN/ASyscallReturn gethostnameFunc(SyscallDesc *desc, int num, 2152381SN/A Process *p, ExecContext *xc); 2162381SN/A 2178922Swilliam.wang@arm.com/// Target unlink() handler. 2182381SN/ASyscallReturn unlinkFunc(SyscallDesc *desc, int num, 2199089Sandreas.hansson@arm.com Process *p, ExecContext *xc); 2209089Sandreas.hansson@arm.com 2219089Sandreas.hansson@arm.com/// Target rename() handler. 2229089Sandreas.hansson@arm.comSyscallReturn renameFunc(SyscallDesc *desc, int num, 2239089Sandreas.hansson@arm.com Process *p, ExecContext *xc); 2245314Sstever@gmail.com 2255314Sstever@gmail.com 2265314Sstever@gmail.com/// Target truncate() handler. 2275314Sstever@gmail.comSyscallReturn truncateFunc(SyscallDesc *desc, int num, 2288975Sandreas.hansson@arm.com Process *p, ExecContext *xc); 2298975Sandreas.hansson@arm.com 2308975Sandreas.hansson@arm.com 2318975Sandreas.hansson@arm.com/// Target ftruncate() handler. 2328975Sandreas.hansson@arm.comSyscallReturn ftruncateFunc(SyscallDesc *desc, int num, 2338975Sandreas.hansson@arm.com Process *p, ExecContext *xc); 2348975Sandreas.hansson@arm.com 2358975Sandreas.hansson@arm.com 2368975Sandreas.hansson@arm.com/// Target chown() handler. 2378975Sandreas.hansson@arm.comSyscallReturn chownFunc(SyscallDesc *desc, int num, 2388975Sandreas.hansson@arm.com Process *p, ExecContext *xc); 2398975Sandreas.hansson@arm.com 2408975Sandreas.hansson@arm.com 2418975Sandreas.hansson@arm.com/// Target fchown() handler. 2428975Sandreas.hansson@arm.comSyscallReturn fchownFunc(SyscallDesc *desc, int num, 2438975Sandreas.hansson@arm.com Process *p, ExecContext *xc); 2448975Sandreas.hansson@arm.com 2458975Sandreas.hansson@arm.com/// Target fnctl() handler. 2468975Sandreas.hansson@arm.comSyscallReturn fcntlFunc(SyscallDesc *desc, int num, 2478975Sandreas.hansson@arm.com Process *process, ExecContext *xc); 2488975Sandreas.hansson@arm.com 2498975Sandreas.hansson@arm.com/// Target setuid() handler. 2508975Sandreas.hansson@arm.comSyscallReturn setuidFunc(SyscallDesc *desc, int num, 2518975Sandreas.hansson@arm.com Process *p, ExecContext *xc); 2528975Sandreas.hansson@arm.com 2538975Sandreas.hansson@arm.com/// Target getpid() handler. 2548975Sandreas.hansson@arm.comSyscallReturn getpidFunc(SyscallDesc *desc, int num, 2558975Sandreas.hansson@arm.com Process *p, ExecContext *xc); 2568975Sandreas.hansson@arm.com 2578975Sandreas.hansson@arm.com/// Target getuid() handler. 2588975Sandreas.hansson@arm.comSyscallReturn getuidFunc(SyscallDesc *desc, int num, 2598975Sandreas.hansson@arm.com Process *p, ExecContext *xc); 2608975Sandreas.hansson@arm.com 2618975Sandreas.hansson@arm.com/// Target getgid() handler. 2629087Sandreas.hansson@arm.comSyscallReturn getgidFunc(SyscallDesc *desc, int num, 2639087Sandreas.hansson@arm.com Process *p, ExecContext *xc); 2649087Sandreas.hansson@arm.com 2659087Sandreas.hansson@arm.com/// Target getppid() handler. 2669087Sandreas.hansson@arm.comSyscallReturn getppidFunc(SyscallDesc *desc, int num, 2679087Sandreas.hansson@arm.com Process *p, ExecContext *xc); 2689087Sandreas.hansson@arm.com 2699087Sandreas.hansson@arm.com/// Target geteuid() handler. 2708975Sandreas.hansson@arm.comSyscallReturn geteuidFunc(SyscallDesc *desc, int num, 2718975Sandreas.hansson@arm.com Process *p, ExecContext *xc); 2728975Sandreas.hansson@arm.com 2738975Sandreas.hansson@arm.com/// Target getegid() handler. 2748975Sandreas.hansson@arm.comSyscallReturn getegidFunc(SyscallDesc *desc, int num, 2758975Sandreas.hansson@arm.com Process *p, ExecContext *xc); 2768975Sandreas.hansson@arm.com 2772381SN/A 2782381SN/A 2798922Swilliam.wang@arm.com/// Pseudo Funcs - These functions use a different return convension, 2808922Swilliam.wang@arm.com/// returning a second value in a register other than the normal return register 2818922Swilliam.wang@arm.comSyscallReturn pipePseudoFunc(SyscallDesc *desc, int num, 2828922Swilliam.wang@arm.com Process *process, ExecContext *xc); 2838922Swilliam.wang@arm.com 2848922Swilliam.wang@arm.com/// Target getpidPseudo() handler. 2858922Swilliam.wang@arm.comSyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num, 2868922Swilliam.wang@arm.com Process *p, ExecContext *xc); 2878922Swilliam.wang@arm.com 2888975Sandreas.hansson@arm.com/// Target getuidPseudo() handler. 2898975Sandreas.hansson@arm.comSyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num, 2908922Swilliam.wang@arm.com Process *p, ExecContext *xc); 2918922Swilliam.wang@arm.com 2928922Swilliam.wang@arm.com/// Target getgidPseudo() handler. 2938922Swilliam.wang@arm.comSyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num, 2948922Swilliam.wang@arm.com Process *p, ExecContext *xc); 2958922Swilliam.wang@arm.com 2968965Sandreas.hansson@arm.com 2979031Sandreas.hansson@arm.com/// This struct is used to build an target-OS-dependent table that 2988922Swilliam.wang@arm.com/// maps the target's open() flags to the host open() flags. 2998922Swilliam.wang@arm.comstruct OpenFlagTransTable { 3008922Swilliam.wang@arm.com int tgtFlag; //!< Target system flag value. 3018922Swilliam.wang@arm.com int hostFlag; //!< Corresponding host system flag value. 3028922Swilliam.wang@arm.com}; 3038922Swilliam.wang@arm.com 3048922Swilliam.wang@arm.com 3058948Sandreas.hansson@arm.com 3068948Sandreas.hansson@arm.com/// A readable name for 1,000,000, for converting microseconds to seconds. 3078948Sandreas.hansson@arm.comconst int one_million = 1000000; 3088948Sandreas.hansson@arm.com 3098948Sandreas.hansson@arm.com/// Approximate seconds since the epoch (1/1/1970). About a billion, 3108948Sandreas.hansson@arm.com/// by my reckoning. We want to keep this a constant (not use the 3118948Sandreas.hansson@arm.com/// real-world time) to keep simulations repeatable. 3128948Sandreas.hansson@arm.comconst unsigned seconds_since_epoch = 1000000000; 3138948Sandreas.hansson@arm.com 3148948Sandreas.hansson@arm.com/// Helper function to convert current elapsed time to seconds and 3158948Sandreas.hansson@arm.com/// microseconds. 3168948Sandreas.hansson@arm.comtemplate <class T1, class T2> 3178948Sandreas.hansson@arm.comvoid 3188948Sandreas.hansson@arm.comgetElapsedTime(T1 &sec, T2 &usec) 3198948Sandreas.hansson@arm.com{ 3208948Sandreas.hansson@arm.com int elapsed_usecs = curTick / Clock::Int::us; 3218948Sandreas.hansson@arm.com sec = elapsed_usecs / one_million; 3228948Sandreas.hansson@arm.com usec = elapsed_usecs % one_million; 3238948Sandreas.hansson@arm.com} 3248948Sandreas.hansson@arm.com 3258975Sandreas.hansson@arm.com////////////////////////////////////////////////////////////////////// 3268975Sandreas.hansson@arm.com// 3278975Sandreas.hansson@arm.com// The following emulation functions are generic, but need to be 3288975Sandreas.hansson@arm.com// templated to account for differences in types, constants, etc. 3298975Sandreas.hansson@arm.com// 3308975Sandreas.hansson@arm.com////////////////////////////////////////////////////////////////////// 3318975Sandreas.hansson@arm.com 3328975Sandreas.hansson@arm.com/// Target ioctl() handler. For the most part, programs call ioctl() 3338975Sandreas.hansson@arm.com/// only to find out if their stdout is a tty, to determine whether to 3348975Sandreas.hansson@arm.com/// do line or block buffering. 3358975Sandreas.hansson@arm.comtemplate <class OS> 3368948Sandreas.hansson@arm.comSyscallReturn 3378948Sandreas.hansson@arm.comioctlFunc(SyscallDesc *desc, int callnum, Process *process, 3388975Sandreas.hansson@arm.com ExecContext *xc) 3398975Sandreas.hansson@arm.com{ 3408975Sandreas.hansson@arm.com int fd = xc->getSyscallArg(0); 3418975Sandreas.hansson@arm.com unsigned req = xc->getSyscallArg(1); 3428975Sandreas.hansson@arm.com 3438948Sandreas.hansson@arm.com DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", fd, req); 3448975Sandreas.hansson@arm.com 3458948Sandreas.hansson@arm.com if (fd < 0 || process->sim_fd(fd) < 0) { 3468948Sandreas.hansson@arm.com // doesn't map to any simulator fd: not a valid target fd 3479087Sandreas.hansson@arm.com return -EBADF; 3489087Sandreas.hansson@arm.com } 3499087Sandreas.hansson@arm.com 3509087Sandreas.hansson@arm.com switch (req) { 3519087Sandreas.hansson@arm.com case OS::TIOCISATTY: 3529087Sandreas.hansson@arm.com case OS::TIOCGETP: 3539087Sandreas.hansson@arm.com case OS::TIOCSETP: 3548922Swilliam.wang@arm.com case OS::TIOCSETN: 3558922Swilliam.wang@arm.com case OS::TIOCSETC: 3568922Swilliam.wang@arm.com case OS::TIOCGETC: 3578922Swilliam.wang@arm.com case OS::TIOCGETS: 3588922Swilliam.wang@arm.com case OS::TIOCGETA: 3598922Swilliam.wang@arm.com return -ENOTTY; 3608922Swilliam.wang@arm.com 3618922Swilliam.wang@arm.com default: 3628922Swilliam.wang@arm.com fatal("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ 0x%llx\n", 3638922Swilliam.wang@arm.com fd, req, xc->readPC()); 3648922Swilliam.wang@arm.com } 3659088Sandreas.hansson@arm.com} 3669088Sandreas.hansson@arm.com 3679088Sandreas.hansson@arm.com/// Target open() handler. 3689088Sandreas.hansson@arm.comtemplate <class OS> 3699088Sandreas.hansson@arm.comSyscallReturn 3709088Sandreas.hansson@arm.comopenFunc(SyscallDesc *desc, int callnum, Process *process, 3719088Sandreas.hansson@arm.com ExecContext *xc) 3728922Swilliam.wang@arm.com{ 3738922Swilliam.wang@arm.com std::string path; 3748922Swilliam.wang@arm.com 3758922Swilliam.wang@arm.com if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0))) 3768922Swilliam.wang@arm.com return -EFAULT; 3778922Swilliam.wang@arm.com 3788922Swilliam.wang@arm.com if (path == "/dev/sysdev0") { 3798922Swilliam.wang@arm.com // This is a memory-mapped high-resolution timer device on Alpha. 3808922Swilliam.wang@arm.com // We don't support it, so just punt. 3818922Swilliam.wang@arm.com warn("Ignoring open(%s, ...)\n", path); 3828922Swilliam.wang@arm.com return -ENOENT; 3839090Sandreas.hansson@arm.com } 3848975Sandreas.hansson@arm.com 3858975Sandreas.hansson@arm.com int tgtFlags = xc->getSyscallArg(1); 3868975Sandreas.hansson@arm.com int mode = xc->getSyscallArg(2); 3878975Sandreas.hansson@arm.com int hostFlags = 0; 3888975Sandreas.hansson@arm.com 3898975Sandreas.hansson@arm.com // translate open flags 3908975Sandreas.hansson@arm.com for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) { 3918975Sandreas.hansson@arm.com if (tgtFlags & OS::openFlagTable[i].tgtFlag) { 3928975Sandreas.hansson@arm.com tgtFlags &= ~OS::openFlagTable[i].tgtFlag; 3938975Sandreas.hansson@arm.com hostFlags |= OS::openFlagTable[i].hostFlag; 3948975Sandreas.hansson@arm.com } 3958975Sandreas.hansson@arm.com } 3968975Sandreas.hansson@arm.com 3978975Sandreas.hansson@arm.com // any target flags left? 3988975Sandreas.hansson@arm.com if (tgtFlags != 0) 3998975Sandreas.hansson@arm.com warn("Syscall: open: cannot decode flags 0x%x", tgtFlags); 4008975Sandreas.hansson@arm.com 4018975Sandreas.hansson@arm.com#ifdef __CYGWIN32__ 4028975Sandreas.hansson@arm.com hostFlags |= O_BINARY; 4038975Sandreas.hansson@arm.com#endif 4048975Sandreas.hansson@arm.com 4058975Sandreas.hansson@arm.com DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str()); 4068975Sandreas.hansson@arm.com 4078975Sandreas.hansson@arm.com // open the file 4088975Sandreas.hansson@arm.com int fd = open(path.c_str(), hostFlags, mode); 4098975Sandreas.hansson@arm.com 4109087Sandreas.hansson@arm.com return (fd == -1) ? -errno : process->alloc_fd(fd); 4119087Sandreas.hansson@arm.com} 4129087Sandreas.hansson@arm.com 4139087Sandreas.hansson@arm.com 4149087Sandreas.hansson@arm.com/// Target chmod() handler. 4159087Sandreas.hansson@arm.comtemplate <class OS> 4169087Sandreas.hansson@arm.comSyscallReturn 4178922Swilliam.wang@arm.comchmodFunc(SyscallDesc *desc, int callnum, Process *process, 4188922Swilliam.wang@arm.com ExecContext *xc) 4192381SN/A{ 420 std::string path; 421 422 if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0))) 423 return -EFAULT; 424 425 uint32_t mode = xc->getSyscallArg(1); 426 mode_t hostMode = 0; 427 428 // XXX translate mode flags via OS::something??? 429 hostMode = mode; 430 431 // do the chmod 432 int result = chmod(path.c_str(), hostMode); 433 if (result < 0) 434 return -errno; 435 436 return 0; 437} 438 439 440/// Target fchmod() handler. 441template <class OS> 442SyscallReturn 443fchmodFunc(SyscallDesc *desc, int callnum, Process *process, 444 ExecContext *xc) 445{ 446 int fd = xc->getSyscallArg(0); 447 if (fd < 0 || process->sim_fd(fd) < 0) { 448 // doesn't map to any simulator fd: not a valid target fd 449 return -EBADF; 450 } 451 452 uint32_t mode = xc->getSyscallArg(1); 453 mode_t hostMode = 0; 454 455 // XXX translate mode flags via OS::someting??? 456 hostMode = mode; 457 458 // do the fchmod 459 int result = fchmod(process->sim_fd(fd), hostMode); 460 if (result < 0) 461 return -errno; 462 463 return 0; 464} 465 466 467/// Target stat() handler. 468template <class OS> 469SyscallReturn 470statFunc(SyscallDesc *desc, int callnum, Process *process, 471 ExecContext *xc) 472{ 473 std::string path; 474 475 if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0))) 476 return -EFAULT; 477 478 struct stat hostBuf; 479 int result = stat(path.c_str(), &hostBuf); 480 481 if (result < 0) 482 return -errno; 483 484 OS::copyOutStatBuf(xc->getMemPort(), xc->getSyscallArg(1), &hostBuf); 485 486 return 0; 487} 488 489 490/// Target fstat64() handler. 491template <class OS> 492SyscallReturn 493fstat64Func(SyscallDesc *desc, int callnum, Process *process, 494 ExecContext *xc) 495{ 496 int fd = xc->getSyscallArg(0); 497 if (fd < 0 || process->sim_fd(fd) < 0) { 498 // doesn't map to any simulator fd: not a valid target fd 499 return -EBADF; 500 } 501 502#if BSD_HOST 503 struct stat hostBuf; 504 int result = fstat(process->sim_fd(fd), &hostBuf); 505#else 506 struct stat64 hostBuf; 507 int result = fstat64(process->sim_fd(fd), &hostBuf); 508#endif 509 510 if (result < 0) 511 return -errno; 512 513 OS::copyOutStat64Buf(xc->getMemPort(), fd, xc->getSyscallArg(1), &hostBuf); 514 515 return 0; 516} 517 518 519/// Target lstat() handler. 520template <class OS> 521SyscallReturn 522lstatFunc(SyscallDesc *desc, int callnum, Process *process, 523 ExecContext *xc) 524{ 525 std::string path; 526 527 if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0))) 528 return -EFAULT; 529 530 struct stat hostBuf; 531 int result = lstat(path.c_str(), &hostBuf); 532 533 if (result < 0) 534 return -errno; 535 536 OS::copyOutStatBuf(xc->getMemPort(), xc->getSyscallArg(1), &hostBuf); 537 538 return 0; 539} 540 541/// Target lstat64() handler. 542template <class OS> 543SyscallReturn 544lstat64Func(SyscallDesc *desc, int callnum, Process *process, 545 ExecContext *xc) 546{ 547 std::string path; 548 549 if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0))) 550 return -EFAULT; 551 552#if BSD_HOST 553 struct stat hostBuf; 554 int result = lstat(path.c_str(), &hostBuf); 555#else 556 struct stat64 hostBuf; 557 int result = lstat64(path.c_str(), &hostBuf); 558#endif 559 560 if (result < 0) 561 return -errno; 562 563 OS::copyOutStat64Buf(xc->getMemPort(), -1, xc->getSyscallArg(1), &hostBuf); 564 565 return 0; 566} 567 568/// Target fstat() handler. 569template <class OS> 570SyscallReturn 571fstatFunc(SyscallDesc *desc, int callnum, Process *process, 572 ExecContext *xc) 573{ 574 int fd = process->sim_fd(xc->getSyscallArg(0)); 575 576 DPRINTF(SyscallVerbose, "fstat(%d, ...)\n", fd); 577 578 if (fd < 0) 579 return -EBADF; 580 581 struct stat hostBuf; 582 int result = fstat(fd, &hostBuf); 583 584 if (result < 0) 585 return -errno; 586 587 OS::copyOutStatBuf(xc->getMemPort(), xc->getSyscallArg(1), &hostBuf); 588 589 return 0; 590} 591 592 593/// Target statfs() handler. 594template <class OS> 595SyscallReturn 596statfsFunc(SyscallDesc *desc, int callnum, Process *process, 597 ExecContext *xc) 598{ 599 std::string path; 600 601 if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0))) 602 return -EFAULT; 603 604 struct statfs hostBuf; 605 int result = statfs(path.c_str(), &hostBuf); 606 607 if (result < 0) 608 return -errno; 609 610 OS::copyOutStatfsBuf(xc->getMemPort(), xc->getSyscallArg(1), &hostBuf); 611 612 return 0; 613} 614 615 616/// Target fstatfs() handler. 617template <class OS> 618SyscallReturn 619fstatfsFunc(SyscallDesc *desc, int callnum, Process *process, 620 ExecContext *xc) 621{ 622 int fd = process->sim_fd(xc->getSyscallArg(0)); 623 624 if (fd < 0) 625 return -EBADF; 626 627 struct statfs hostBuf; 628 int result = fstatfs(fd, &hostBuf); 629 630 if (result < 0) 631 return -errno; 632 633 OS::copyOutStatfsBuf(xc->getMemPort(), xc->getSyscallArg(1), &hostBuf); 634 635 return 0; 636} 637 638 639/// Target writev() handler. 640template <class OS> 641SyscallReturn 642writevFunc(SyscallDesc *desc, int callnum, Process *process, 643 ExecContext *xc) 644{ 645 int fd = xc->getSyscallArg(0); 646 if (fd < 0 || process->sim_fd(fd) < 0) { 647 // doesn't map to any simulator fd: not a valid target fd 648 return -EBADF; 649 } 650 651 TranslatingPort *p = xc->getMemPort(); 652 uint64_t tiov_base = xc->getSyscallArg(1); 653 size_t count = xc->getSyscallArg(2); 654 struct iovec hiov[count]; 655 for (int i = 0; i < count; ++i) 656 { 657 typename OS::tgt_iovec tiov; 658 659 p->readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec), 660 (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec)); 661 hiov[i].iov_len = gtoh(tiov.iov_len); 662 hiov[i].iov_base = new char [hiov[i].iov_len]; 663 p->readBlob(gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base, 664 hiov[i].iov_len); 665 } 666 667 int result = writev(process->sim_fd(fd), hiov, count); 668 669 for (int i = 0; i < count; ++i) 670 { 671 delete [] (char *)hiov[i].iov_base; 672 } 673 674 if (result < 0) 675 return -errno; 676 677 return 0; 678} 679 680 681/// Target mmap() handler. 682/// 683/// We don't really handle mmap(). If the target is mmaping an 684/// anonymous region or /dev/zero, we can get away with doing basically 685/// nothing (since memory is initialized to zero and the simulator 686/// doesn't really check addresses anyway). Always print a warning, 687/// since this could be seriously broken if we're not mapping 688/// /dev/zero. 689// 690/// Someday we should explicitly check for /dev/zero in open, flag the 691/// file descriptor, and fail (or implement!) a non-anonymous mmap to 692/// anything else. 693template <class OS> 694SyscallReturn 695mmapFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) 696{ 697 Addr start = xc->getSyscallArg(0); 698 uint64_t length = xc->getSyscallArg(1); 699 // int prot = xc->getSyscallArg(2); 700 int flags = xc->getSyscallArg(3); 701 // int fd = p->sim_fd(xc->getSyscallArg(4)); 702 // int offset = xc->getSyscallArg(5); 703 Addr junk; 704 705 if (start == 0) { 706 // user didn't give an address... pick one from our "mmap region" 707 start = p->mmap_end; 708 for (ChunkGenerator gen(start, roundUp(length, TheISA::VMPageSize), TheISA::VMPageSize); !gen.done(); gen.next()) { 709 if (!p->pTable->translate(gen.addr(), junk)) 710 p->pTable->allocate(roundDown(gen.addr(), TheISA::VMPageSize), TheISA::VMPageSize); 711 } 712 p->mmap_end += roundUp(length, TheISA::VMPageSize); 713 if (p->nxm_start != 0) { 714 //If we have an nxm space, make sure we haven't colided 715 assert(p->mmap_end < p->nxm_start); 716 } 717 } 718 719 if (!(flags & OS::TGT_MAP_ANONYMOUS)) { 720 warn("allowing mmap of file @ fd %d. " 721 "This will break if not /dev/zero.", xc->getSyscallArg(4)); 722 } 723 724 return start; 725} 726 727/// Target getrlimit() handler. 728template <class OS> 729SyscallReturn 730getrlimitFunc(SyscallDesc *desc, int callnum, Process *process, 731 ExecContext *xc) 732{ 733 unsigned resource = xc->getSyscallArg(0); 734 TypedBufferArg<typename OS::rlimit> rlp(xc->getSyscallArg(1)); 735 736 switch (resource) { 737 case OS::TGT_RLIMIT_STACK: 738 // max stack size in bytes: make up a number (2MB for now) 739 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; 740 rlp->rlim_cur = htog(rlp->rlim_cur); 741 rlp->rlim_max = htog(rlp->rlim_max); 742 break; 743 744 default: 745 std::cerr << "getrlimitFunc: unimplemented resource " << resource 746 << std::endl; 747 abort(); 748 break; 749 } 750 751 rlp.copyOut(xc->getMemPort()); 752 return 0; 753} 754 755/// Target gettimeofday() handler. 756template <class OS> 757SyscallReturn 758gettimeofdayFunc(SyscallDesc *desc, int callnum, Process *process, 759 ExecContext *xc) 760{ 761 TypedBufferArg<typename OS::timeval> tp(xc->getSyscallArg(0)); 762 763 getElapsedTime(tp->tv_sec, tp->tv_usec); 764 tp->tv_sec += seconds_since_epoch; 765 tp->tv_sec = htog(tp->tv_sec); 766 tp->tv_usec = htog(tp->tv_usec); 767 768 tp.copyOut(xc->getMemPort()); 769 770 return 0; 771} 772 773 774/// Target utimes() handler. 775template <class OS> 776SyscallReturn 777utimesFunc(SyscallDesc *desc, int callnum, Process *process, 778 ExecContext *xc) 779{ 780 std::string path; 781 782 if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0))) 783 return -EFAULT; 784 785 TypedBufferArg<typename OS::timeval [2]> tp(xc->getSyscallArg(1)); 786 tp.copyIn(xc->getMemPort()); 787 788 struct timeval hostTimeval[2]; 789 for (int i = 0; i < 2; ++i) 790 { 791 hostTimeval[i].tv_sec = gtoh((*tp)[i].tv_sec); 792 hostTimeval[i].tv_usec = gtoh((*tp)[i].tv_usec); 793 } 794 int result = utimes(path.c_str(), hostTimeval); 795 796 if (result < 0) 797 return -errno; 798 799 return 0; 800} 801/// Target getrusage() function. 802template <class OS> 803SyscallReturn 804getrusageFunc(SyscallDesc *desc, int callnum, Process *process, 805 ExecContext *xc) 806{ 807 int who = xc->getSyscallArg(0); // THREAD, SELF, or CHILDREN 808 TypedBufferArg<typename OS::rusage> rup(xc->getSyscallArg(1)); 809 810 if (who != OS::TGT_RUSAGE_SELF) { 811 // don't really handle THREAD or CHILDREN, but just warn and 812 // plow ahead 813 warn("getrusage() only supports RUSAGE_SELF. Parameter %d ignored.", 814 who); 815 } 816 817 getElapsedTime(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec); 818 rup->ru_utime.tv_sec = htog(rup->ru_utime.tv_sec); 819 rup->ru_utime.tv_usec = htog(rup->ru_utime.tv_usec); 820 821 rup->ru_stime.tv_sec = 0; 822 rup->ru_stime.tv_usec = 0; 823 rup->ru_maxrss = 0; 824 rup->ru_ixrss = 0; 825 rup->ru_idrss = 0; 826 rup->ru_isrss = 0; 827 rup->ru_minflt = 0; 828 rup->ru_majflt = 0; 829 rup->ru_nswap = 0; 830 rup->ru_inblock = 0; 831 rup->ru_oublock = 0; 832 rup->ru_msgsnd = 0; 833 rup->ru_msgrcv = 0; 834 rup->ru_nsignals = 0; 835 rup->ru_nvcsw = 0; 836 rup->ru_nivcsw = 0; 837 838 rup.copyOut(xc->getMemPort()); 839 840 return 0; 841} 842 843#endif // __SIM_SYSCALL_EMUL_HH__ 844