syscall_emul.hh revision 8852
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 * Authors: Steve Reinhardt 292665Ssaidi@eecs.umich.edu * Kevin Lim 30360SN/A */ 31360SN/A 321354SN/A#ifndef __SIM_SYSCALL_EMUL_HH__ 331354SN/A#define __SIM_SYSCALL_EMUL_HH__ 34360SN/A 352764Sstever@eecs.umich.edu#define NO_STAT64 (defined(__APPLE__) || defined(__OpenBSD__) || \ 362764Sstever@eecs.umich.edu defined(__FreeBSD__) || defined(__CYGWIN__)) 372064SN/A 38360SN/A/// 39360SN/A/// @file syscall_emul.hh 40360SN/A/// 41360SN/A/// This file defines objects used to emulate syscalls from the target 42360SN/A/// application on the host machine. 43360SN/A 441354SN/A#ifdef __CYGWIN32__ 45360SN/A#include <sys/fcntl.h> // for O_BINARY 461809SN/A#endif 471809SN/A#include <sys/stat.h> 481809SN/A#include <sys/time.h> 493113Sgblack@eecs.umich.edu#include <sys/uio.h> 503113Sgblack@eecs.umich.edu#include <fcntl.h> 511999SN/A 52360SN/A#include <cerrno> 533113Sgblack@eecs.umich.edu#include <string> 542474SN/A 55360SN/A#include "base/chunk_generator.hh" 562462SN/A#include "base/intmath.hh" // for RoundUp 571354SN/A#include "base/misc.hh" 582474SN/A#include "base/trace.hh" 592680Sktlim@umich.edu#include "base/types.hh" 602474SN/A#include "config/the_isa.hh" 612474SN/A#include "cpu/base.hh" 621354SN/A#include "cpu/thread_context.hh" 63360SN/A#include "debug/SyscallVerbose.hh" 64360SN/A#include "mem/page_table.hh" 65360SN/A#include "mem/se_translating_port_proxy.hh" 66360SN/A#include "sim/byteswap.hh" 67360SN/A#include "sim/process.hh" 68360SN/A#include "sim/syscallreturn.hh" 69360SN/A#include "sim/system.hh" 70360SN/A 71378SN/A/// 721450SN/A/// System call descriptor. 733114Sgblack@eecs.umich.edu/// 74360SN/Aclass SyscallDesc { 75360SN/A 76360SN/A public: 77360SN/A 78360SN/A /// Typedef for target syscall handler functions. 79360SN/A typedef SyscallReturn (*FuncPtr)(SyscallDesc *, int num, 80360SN/A LiveProcess *, ThreadContext *); 81360SN/A 82360SN/A const char *name; //!< Syscall name (e.g., "open"). 832680Sktlim@umich.edu FuncPtr funcPtr; //!< Pointer to emulation function. 84360SN/A int flags; //!< Flags (see Flags enum). 85360SN/A 86360SN/A /// Flag values for controlling syscall behavior. 87360SN/A enum Flags { 88360SN/A /// Don't set return regs according to funcPtr return value. 89360SN/A /// Used for syscalls with non-standard return conventions 90360SN/A /// that explicitly set the ThreadContext regs (e.g., 91360SN/A /// sigreturn). 92360SN/A SuppressReturnValue = 1 93360SN/A }; 94360SN/A 953114Sgblack@eecs.umich.edu /// Constructor. 96360SN/A SyscallDesc(const char *_name, FuncPtr _funcPtr, int _flags = 0) 97360SN/A : name(_name), funcPtr(_funcPtr), flags(_flags) 98360SN/A { 99360SN/A } 100360SN/A 101360SN/A /// Emulate the syscall. Public interface for calling through funcPtr. 102360SN/A void doSyscall(int callnum, LiveProcess *proc, ThreadContext *tc); 103360SN/A}; 104360SN/A 105360SN/A 106360SN/Aclass BaseBufferArg { 107360SN/A 108360SN/A public: 109360SN/A 110360SN/A BaseBufferArg(Addr _addr, int _size) : addr(_addr), size(_size) 111360SN/A { 112360SN/A bufPtr = new uint8_t[size]; 113360SN/A // clear out buffer: in case we only partially populate this, 114360SN/A // and then do a copyOut(), we want to make sure we don't 115360SN/A // introduce any random junk into the simulated address space 116360SN/A memset(bufPtr, 0, size); 1172400SN/A } 118360SN/A 1192461SN/A virtual ~BaseBufferArg() { delete [] bufPtr; } 120360SN/A 121360SN/A // 122360SN/A // copy data into simulator space (read from target memory) 123360SN/A // 124360SN/A virtual bool copyIn(SETranslatingPortProxy &memproxy) 125360SN/A { 1262400SN/A memproxy.readBlob(addr, bufPtr, size); 127360SN/A return true; // no EFAULT detection for now 1282461SN/A } 129360SN/A 130360SN/A // 131360SN/A // copy data out of simulator space (write to target memory) 132360SN/A // 133360SN/A virtual bool copyOut(SETranslatingPortProxy &memproxy) 134360SN/A { 135360SN/A memproxy.writeBlob(addr, bufPtr, size); 136360SN/A return true; // no EFAULT detection for now 137360SN/A } 138360SN/A 139360SN/A protected: 140360SN/A Addr addr; 141360SN/A int size; 142360SN/A uint8_t *bufPtr; 143360SN/A}; 144360SN/A 145360SN/A 146360SN/Aclass BufferArg : public BaseBufferArg 147360SN/A{ 148360SN/A public: 149360SN/A BufferArg(Addr _addr, int _size) : BaseBufferArg(_addr, _size) { } 150360SN/A void *bufferPtr() { return bufPtr; } 151360SN/A}; 152360SN/A 153360SN/Atemplate <class T> 154360SN/Aclass TypedBufferArg : public BaseBufferArg 155360SN/A{ 156360SN/A public: 157360SN/A // user can optionally specify a specific number of bytes to 158360SN/A // allocate to deal with those structs that have variable-size 159360SN/A // arrays at the end 160360SN/A TypedBufferArg(Addr _addr, int _size = sizeof(T)) 161502SN/A : BaseBufferArg(_addr, _size) 162360SN/A { } 163502SN/A 164360SN/A // type case 165360SN/A operator T*() { return (T *)bufPtr; } 166360SN/A 167360SN/A // dereference operators 168360SN/A T &operator*() { return *((T *)bufPtr); } 169360SN/A T* operator->() { return (T *)bufPtr; } 170360SN/A T &operator[](int i) { return ((T *)bufPtr)[i]; } 171360SN/A}; 172360SN/A 173360SN/A////////////////////////////////////////////////////////////////////// 174360SN/A// 175378SN/A// The following emulation functions are generic enough that they 1761706SN/A// don't need to be recompiled for different emulated OS's. They are 1773114Sgblack@eecs.umich.edu// defined in sim/syscall_emul.cc. 178378SN/A// 179378SN/A////////////////////////////////////////////////////////////////////// 180378SN/A 181378SN/A 182378SN/A/// Handler for unimplemented syscalls that we haven't thought about. 1831706SN/ASyscallReturn unimplementedFunc(SyscallDesc *desc, int num, 1843114Sgblack@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 185360SN/A 186378SN/A/// Handler for unimplemented syscalls that we never intend to 1871706SN/A/// implement (signal handling, etc.) and should not affect the correct 1883114Sgblack@eecs.umich.edu/// behavior of the program. Print a warning only if the appropriate 189378SN/A/// trace flag is enabled. Return success to the target program. 190378SN/ASyscallReturn ignoreFunc(SyscallDesc *desc, int num, 1911706SN/A LiveProcess *p, ThreadContext *tc); 1923114Sgblack@eecs.umich.eduSyscallReturn ignoreWarnOnceFunc(SyscallDesc *desc, int num, 193378SN/A LiveProcess *p, ThreadContext *tc); 194378SN/A 1951706SN/A/// Target exit() handler: terminate current context. 1963114Sgblack@eecs.umich.eduSyscallReturn exitFunc(SyscallDesc *desc, int num, 197378SN/A LiveProcess *p, ThreadContext *tc); 198378SN/A 1991706SN/A/// Target exit_group() handler: terminate simulation. (exit all threads) 2003114Sgblack@eecs.umich.eduSyscallReturn exitGroupFunc(SyscallDesc *desc, int num, 201378SN/A LiveProcess *p, ThreadContext *tc); 202378SN/A 2031706SN/A/// Target getpagesize() handler. 2043114Sgblack@eecs.umich.eduSyscallReturn getpagesizeFunc(SyscallDesc *desc, int num, 205378SN/A LiveProcess *p, ThreadContext *tc); 206378SN/A 2071706SN/A/// Target brk() handler: set brk address. 2083114Sgblack@eecs.umich.eduSyscallReturn brkFunc(SyscallDesc *desc, int num, 209378SN/A LiveProcess *p, ThreadContext *tc); 210378SN/A 2111706SN/A/// Target close() handler. 2123114Sgblack@eecs.umich.eduSyscallReturn closeFunc(SyscallDesc *desc, int num, 213378SN/A LiveProcess *p, ThreadContext *tc); 2144118Sgblack@eecs.umich.edu 2154118Sgblack@eecs.umich.edu/// Target read() handler. 2164118Sgblack@eecs.umich.eduSyscallReturn readFunc(SyscallDesc *desc, int num, 2174118Sgblack@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 218378SN/A 2191706SN/A/// Target write() handler. 2203114Sgblack@eecs.umich.eduSyscallReturn writeFunc(SyscallDesc *desc, int num, 221378SN/A LiveProcess *p, ThreadContext *tc); 222378SN/A 2231706SN/A/// Target lseek() handler. 2243114Sgblack@eecs.umich.eduSyscallReturn lseekFunc(SyscallDesc *desc, int num, 225360SN/A LiveProcess *p, ThreadContext *tc); 226511SN/A 2271706SN/A/// Target _llseek() handler. 2283114Sgblack@eecs.umich.eduSyscallReturn _llseekFunc(SyscallDesc *desc, int num, 229511SN/A LiveProcess *p, ThreadContext *tc); 230511SN/A 2311706SN/A/// Target munmap() handler. 2323114Sgblack@eecs.umich.eduSyscallReturn munmapFunc(SyscallDesc *desc, int num, 2331706SN/A LiveProcess *p, ThreadContext *tc); 2341706SN/A 2351706SN/A/// Target gethostname() handler. 2361706SN/ASyscallReturn gethostnameFunc(SyscallDesc *desc, int num, 2373114Sgblack@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 2381706SN/A 2391706SN/A/// Target getcwd() handler. 2401706SN/ASyscallReturn getcwdFunc(SyscallDesc *desc, int num, 2411706SN/A LiveProcess *p, ThreadContext *tc); 2423114Sgblack@eecs.umich.edu 2431706SN/A/// Target unlink() handler. 244511SN/ASyscallReturn readlinkFunc(SyscallDesc *desc, int num, 2451999SN/A LiveProcess *p, ThreadContext *tc); 2461999SN/A 2473114Sgblack@eecs.umich.edu/// Target unlink() handler. 2481999SN/ASyscallReturn unlinkFunc(SyscallDesc *desc, int num, 2491999SN/A LiveProcess *p, ThreadContext *tc); 2501999SN/A 2511999SN/A/// Target mkdir() handler. 2523114Sgblack@eecs.umich.eduSyscallReturn mkdirFunc(SyscallDesc *desc, int num, 2531999SN/A LiveProcess *p, ThreadContext *tc); 2543079Sstever@eecs.umich.edu 2553079Sstever@eecs.umich.edu/// Target rename() handler. 2563114Sgblack@eecs.umich.eduSyscallReturn renameFunc(SyscallDesc *desc, int num, 2573079Sstever@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 2582093SN/A 2592093SN/A 2603114Sgblack@eecs.umich.edu/// Target truncate() handler. 2612093SN/ASyscallReturn truncateFunc(SyscallDesc *desc, int num, 2622687Sksewell@umich.edu LiveProcess *p, ThreadContext *tc); 2632687Sksewell@umich.edu 2643114Sgblack@eecs.umich.edu 2652687Sksewell@umich.edu/// Target ftruncate() handler. 2662238SN/ASyscallReturn ftruncateFunc(SyscallDesc *desc, int num, 2672238SN/A LiveProcess *p, ThreadContext *tc); 2683114Sgblack@eecs.umich.edu 2692238SN/A 2702238SN/A/// Target truncate64() handler. 2712238SN/ASyscallReturn truncate64Func(SyscallDesc *desc, int num, 2723114Sgblack@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 2732238SN/A 2742238SN/A/// Target ftruncate64() handler. 2752238SN/ASyscallReturn ftruncate64Func(SyscallDesc *desc, int num, 2763114Sgblack@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 2772238SN/A 2782238SN/A 2792238SN/A/// Target umask() handler. 2803114Sgblack@eecs.umich.eduSyscallReturn umaskFunc(SyscallDesc *desc, int num, 2812238SN/A LiveProcess *p, ThreadContext *tc); 2822238SN/A 2832238SN/A 2843114Sgblack@eecs.umich.edu/// Target chown() handler. 2852238SN/ASyscallReturn chownFunc(SyscallDesc *desc, int num, 2862238SN/A LiveProcess *p, ThreadContext *tc); 2872238SN/A 2883114Sgblack@eecs.umich.edu 2892238SN/A/// Target fchown() handler. 2902238SN/ASyscallReturn fchownFunc(SyscallDesc *desc, int num, 2912238SN/A LiveProcess *p, ThreadContext *tc); 2923114Sgblack@eecs.umich.edu 2932238SN/A/// Target dup() handler. 2942238SN/ASyscallReturn dupFunc(SyscallDesc *desc, int num, 2952238SN/A LiveProcess *process, ThreadContext *tc); 2962238SN/A 2972238SN/A/// Target fnctl() handler. 2982238SN/ASyscallReturn fcntlFunc(SyscallDesc *desc, int num, 2993114Sgblack@eecs.umich.edu LiveProcess *process, ThreadContext *tc); 3002238SN/A 3012238SN/A/// Target fcntl64() handler. 3022238SN/ASyscallReturn fcntl64Func(SyscallDesc *desc, int num, 3033114Sgblack@eecs.umich.edu LiveProcess *process, ThreadContext *tc); 3042238SN/A 3052238SN/A/// Target setuid() handler. 3062238SN/ASyscallReturn setuidFunc(SyscallDesc *desc, int num, 3073114Sgblack@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 3082238SN/A 3092238SN/A/// Target getpid() handler. 3102238SN/ASyscallReturn getpidFunc(SyscallDesc *desc, int num, 3113114Sgblack@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 3122238SN/A 3132238SN/A/// Target getuid() handler. 3141354SN/ASyscallReturn getuidFunc(SyscallDesc *desc, int num, 3151354SN/A LiveProcess *p, ThreadContext *tc); 3161354SN/A 3171354SN/A/// Target getgid() handler. 3181354SN/ASyscallReturn getgidFunc(SyscallDesc *desc, int num, 3191354SN/A LiveProcess *p, ThreadContext *tc); 3201354SN/A 3211354SN/A/// Target getppid() handler. 3221354SN/ASyscallReturn getppidFunc(SyscallDesc *desc, int num, 3231354SN/A LiveProcess *p, ThreadContext *tc); 3241354SN/A 3251354SN/A/// Target geteuid() handler. 3261354SN/ASyscallReturn geteuidFunc(SyscallDesc *desc, int num, 3271354SN/A LiveProcess *p, ThreadContext *tc); 3281609SN/A 3291354SN/A/// Target getegid() handler. 3301354SN/ASyscallReturn getegidFunc(SyscallDesc *desc, int num, 3311354SN/A LiveProcess *p, ThreadContext *tc); 3321354SN/A 333360SN/A/// Target clone() handler. 334360SN/ASyscallReturn cloneFunc(SyscallDesc *desc, int num, 335360SN/A LiveProcess *p, ThreadContext *tc); 336360SN/A 337360SN/A 338360SN/A/// Pseudo Funcs - These functions use a different return convension, 339360SN/A/// returning a second value in a register other than the normal return register 3403113Sgblack@eecs.umich.eduSyscallReturn pipePseudoFunc(SyscallDesc *desc, int num, 3413113Sgblack@eecs.umich.edu LiveProcess *process, ThreadContext *tc); 3423113Sgblack@eecs.umich.edu 3433113Sgblack@eecs.umich.edu/// Target getpidPseudo() handler. 3443113Sgblack@eecs.umich.eduSyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num, 3453113Sgblack@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 3463113Sgblack@eecs.umich.edu 3473113Sgblack@eecs.umich.edu/// Target getuidPseudo() handler. 3483113Sgblack@eecs.umich.eduSyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num, 3493113Sgblack@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 3503113Sgblack@eecs.umich.edu 3513113Sgblack@eecs.umich.edu/// Target getgidPseudo() handler. 3523113Sgblack@eecs.umich.eduSyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num, 3533113Sgblack@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 3543113Sgblack@eecs.umich.edu 3553113Sgblack@eecs.umich.edu 3564189Sgblack@eecs.umich.edu/// A readable name for 1,000,000, for converting microseconds to seconds. 3574189Sgblack@eecs.umich.educonst int one_million = 1000000; 3583113Sgblack@eecs.umich.edu 3593113Sgblack@eecs.umich.edu/// Approximate seconds since the epoch (1/1/1970). About a billion, 3603113Sgblack@eecs.umich.edu/// by my reckoning. We want to keep this a constant (not use the 3613113Sgblack@eecs.umich.edu/// real-world time) to keep simulations repeatable. 3623113Sgblack@eecs.umich.educonst unsigned seconds_since_epoch = 1000000000; 3633113Sgblack@eecs.umich.edu 3643113Sgblack@eecs.umich.edu/// Helper function to convert current elapsed time to seconds and 3653277Sgblack@eecs.umich.edu/// microseconds. 3663277Sgblack@eecs.umich.edutemplate <class T1, class T2> 3673277Sgblack@eecs.umich.eduvoid 3683277Sgblack@eecs.umich.edugetElapsedTime(T1 &sec, T2 &usec) 3693277Sgblack@eecs.umich.edu{ 3703277Sgblack@eecs.umich.edu int elapsed_usecs = curTick() / SimClock::Int::us; 3713277Sgblack@eecs.umich.edu sec = elapsed_usecs / one_million; 3723277Sgblack@eecs.umich.edu usec = elapsed_usecs % one_million; 3733113Sgblack@eecs.umich.edu} 3743113Sgblack@eecs.umich.edu 3753113Sgblack@eecs.umich.edu////////////////////////////////////////////////////////////////////// 3763113Sgblack@eecs.umich.edu// 3773113Sgblack@eecs.umich.edu// The following emulation functions are generic, but need to be 3783113Sgblack@eecs.umich.edu// templated to account for differences in types, constants, etc. 3793113Sgblack@eecs.umich.edu// 3803114Sgblack@eecs.umich.edu////////////////////////////////////////////////////////////////////// 3813113Sgblack@eecs.umich.edu 3823114Sgblack@eecs.umich.edu#if NO_STAT64 3833113Sgblack@eecs.umich.edu typedef struct stat hst_stat; 3843114Sgblack@eecs.umich.edu typedef struct stat hst_stat64; 3853113Sgblack@eecs.umich.edu#else 3864061Sgblack@eecs.umich.edu typedef struct stat hst_stat; 3874061Sgblack@eecs.umich.edu typedef struct stat64 hst_stat64; 3884061Sgblack@eecs.umich.edu#endif 3893113Sgblack@eecs.umich.edu 3903113Sgblack@eecs.umich.edu//// Helper function to convert a host stat buffer to a target stat 3913113Sgblack@eecs.umich.edu//// buffer. Also copies the target buffer out to the simulated 3923113Sgblack@eecs.umich.edu//// memory space. Used by stat(), fstat(), and lstat(). 3933113Sgblack@eecs.umich.edu 3943113Sgblack@eecs.umich.edutemplate <typename target_stat, typename host_stat> 3953113Sgblack@eecs.umich.edustatic void 3963113Sgblack@eecs.umich.educonvertStatBuf(target_stat &tgt, host_stat *host, bool fakeTTY = false) 3973113Sgblack@eecs.umich.edu{ 3983113Sgblack@eecs.umich.edu using namespace TheISA; 3993113Sgblack@eecs.umich.edu 4004189Sgblack@eecs.umich.edu if (fakeTTY) 4014189Sgblack@eecs.umich.edu tgt->st_dev = 0xA; 4023113Sgblack@eecs.umich.edu else 4033113Sgblack@eecs.umich.edu tgt->st_dev = host->st_dev; 4043113Sgblack@eecs.umich.edu tgt->st_dev = TheISA::htog(tgt->st_dev); 4053113Sgblack@eecs.umich.edu tgt->st_ino = host->st_ino; 4063113Sgblack@eecs.umich.edu tgt->st_ino = TheISA::htog(tgt->st_ino); 4073113Sgblack@eecs.umich.edu tgt->st_mode = host->st_mode; 4083113Sgblack@eecs.umich.edu if (fakeTTY) { 4093113Sgblack@eecs.umich.edu // Claim to be a character device 4103113Sgblack@eecs.umich.edu tgt->st_mode &= ~S_IFMT; // Clear S_IFMT 4113113Sgblack@eecs.umich.edu tgt->st_mode |= S_IFCHR; // Set S_IFCHR 4123113Sgblack@eecs.umich.edu } 4133113Sgblack@eecs.umich.edu tgt->st_mode = TheISA::htog(tgt->st_mode); 4143113Sgblack@eecs.umich.edu tgt->st_nlink = host->st_nlink; 4153113Sgblack@eecs.umich.edu tgt->st_nlink = TheISA::htog(tgt->st_nlink); 4163113Sgblack@eecs.umich.edu tgt->st_uid = host->st_uid; 4173113Sgblack@eecs.umich.edu tgt->st_uid = TheISA::htog(tgt->st_uid); 4183113Sgblack@eecs.umich.edu tgt->st_gid = host->st_gid; 4193113Sgblack@eecs.umich.edu tgt->st_gid = TheISA::htog(tgt->st_gid); 4203113Sgblack@eecs.umich.edu if (fakeTTY) 4213113Sgblack@eecs.umich.edu tgt->st_rdev = 0x880d; 4223113Sgblack@eecs.umich.edu else 4233113Sgblack@eecs.umich.edu tgt->st_rdev = host->st_rdev; 4243113Sgblack@eecs.umich.edu tgt->st_rdev = TheISA::htog(tgt->st_rdev); 4253113Sgblack@eecs.umich.edu tgt->st_size = host->st_size; 4263113Sgblack@eecs.umich.edu tgt->st_size = TheISA::htog(tgt->st_size); 4273113Sgblack@eecs.umich.edu tgt->st_atimeX = host->st_atime; 4283113Sgblack@eecs.umich.edu tgt->st_atimeX = TheISA::htog(tgt->st_atimeX); 4293113Sgblack@eecs.umich.edu tgt->st_mtimeX = host->st_mtime; 4303113Sgblack@eecs.umich.edu tgt->st_mtimeX = TheISA::htog(tgt->st_mtimeX); 4313113Sgblack@eecs.umich.edu tgt->st_ctimeX = host->st_ctime; 4323113Sgblack@eecs.umich.edu tgt->st_ctimeX = TheISA::htog(tgt->st_ctimeX); 4333113Sgblack@eecs.umich.edu // Force the block size to be 8k. This helps to ensure buffered io works 4343113Sgblack@eecs.umich.edu // consistently across different hosts. 4353113Sgblack@eecs.umich.edu tgt->st_blksize = 0x2000; 4363113Sgblack@eecs.umich.edu tgt->st_blksize = TheISA::htog(tgt->st_blksize); 4373113Sgblack@eecs.umich.edu tgt->st_blocks = host->st_blocks; 4383113Sgblack@eecs.umich.edu tgt->st_blocks = TheISA::htog(tgt->st_blocks); 4393113Sgblack@eecs.umich.edu} 440378SN/A 441378SN/A// Same for stat64 442378SN/A 443360SN/Atemplate <typename target_stat, typename host_stat64> 4441450SN/Astatic void 4453114Sgblack@eecs.umich.educonvertStat64Buf(target_stat &tgt, host_stat64 *host, bool fakeTTY = false) 4462680Sktlim@umich.edu{ 447360SN/A using namespace TheISA; 4482680Sktlim@umich.edu 4492680Sktlim@umich.edu convertStatBuf<target_stat, host_stat64>(tgt, host, fakeTTY); 450360SN/A#if defined(STAT_HAVE_NSEC) 4511969SN/A tgt->st_atime_nsec = host->st_atime_nsec; 452360SN/A tgt->st_atime_nsec = TheISA::htog(tgt->st_atime_nsec); 453360SN/A tgt->st_mtime_nsec = host->st_mtime_nsec; 454360SN/A tgt->st_mtime_nsec = TheISA::htog(tgt->st_mtime_nsec); 4551458SN/A tgt->st_ctime_nsec = host->st_ctime_nsec; 456360SN/A tgt->st_ctime_nsec = TheISA::htog(tgt->st_ctime_nsec); 457360SN/A#else 458360SN/A tgt->st_atime_nsec = 0; 4594131Sbinkertn@umich.edu tgt->st_mtime_nsec = 0; 4604131Sbinkertn@umich.edu tgt->st_ctime_nsec = 0; 4614131Sbinkertn@umich.edu#endif 4624131Sbinkertn@umich.edu} 4634131Sbinkertn@umich.edu 4644131Sbinkertn@umich.edu//Here are a couple convenience functions 4654131Sbinkertn@umich.edutemplate<class OS> 4664131Sbinkertn@umich.edustatic void 4671458SN/AcopyOutStatBuf(SETranslatingPortProxy &mem, Addr addr, 468360SN/A hst_stat *host, bool fakeTTY = false) 469360SN/A{ 4701706SN/A typedef TypedBufferArg<typename OS::tgt_stat> tgt_stat_buf; 4712680Sktlim@umich.edu tgt_stat_buf tgt(addr); 472360SN/A convertStatBuf<tgt_stat_buf, hst_stat>(tgt, host, fakeTTY); 473360SN/A tgt.copyOut(mem); 474360SN/A} 475378SN/A 476360SN/Atemplate<class OS> 4771450SN/Astatic void 4783114Sgblack@eecs.umich.educopyOutStat64Buf(SETranslatingPortProxy &mem, Addr addr, 4792680Sktlim@umich.edu hst_stat64 *host, bool fakeTTY = false) 480360SN/A{ 481360SN/A typedef TypedBufferArg<typename OS::tgt_stat64> tgt_stat_buf; 482360SN/A tgt_stat_buf tgt(addr); 4832680Sktlim@umich.edu convertStat64Buf<tgt_stat_buf, hst_stat64>(tgt, host, fakeTTY); 4841458SN/A tgt.copyOut(mem); 485360SN/A} 486360SN/A 487360SN/A/// Target ioctl() handler. For the most part, programs call ioctl() 488360SN/A/// only to find out if their stdout is a tty, to determine whether to 4891706SN/A/// do line or block buffering. 4901458SN/Atemplate <class OS> 491360SN/ASyscallReturn 492360SN/AioctlFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 4932680Sktlim@umich.edu ThreadContext *tc) 4942680Sktlim@umich.edu{ 495360SN/A int index = 0; 496360SN/A int fd = process->getSyscallArg(tc, index); 497360SN/A unsigned req = process->getSyscallArg(tc, index); 498360SN/A 499360SN/A DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", fd, req); 500360SN/A 501360SN/A if (fd < 0 || process->sim_fd(fd) < 0) { 502360SN/A // doesn't map to any simulator fd: not a valid target fd 503360SN/A return -EBADF; 504360SN/A } 505360SN/A 506360SN/A switch (req) { 5071706SN/A case OS::TIOCISATTY_: 508360SN/A case OS::TIOCGETP_: 509360SN/A case OS::TIOCSETP_: 510360SN/A case OS::TIOCSETN_: 511360SN/A case OS::TIOCSETC_: 512360SN/A case OS::TIOCGETC_: 5133669Sbinkertn@umich.edu case OS::TIOCGETS_: 5143669Sbinkertn@umich.edu case OS::TIOCGETA_: 5153669Sbinkertn@umich.edu case OS::TCSETAW_: 5161706SN/A return -ENOTTY; 5171706SN/A 518360SN/A default: 519360SN/A fatal("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ \n", 520360SN/A fd, req, tc->pcState()); 5215282Srstrong@cs.ucsd.edu } 522360SN/A} 523360SN/A 524360SN/A/// Target open() handler. 5251999SN/Atemplate <class OS> 5261999SN/ASyscallReturn 5271999SN/AopenFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 5283114Sgblack@eecs.umich.edu ThreadContext *tc) 5292680Sktlim@umich.edu{ 5301999SN/A std::string path; 5311999SN/A 5321999SN/A int index = 0; 5332680Sktlim@umich.edu if (!tc->getMemProxy().tryReadString(path, 5341999SN/A process->getSyscallArg(tc, index))) 5351999SN/A return -EFAULT; 5362680Sktlim@umich.edu 5371999SN/A if (path == "/dev/sysdev0") { 5381999SN/A // This is a memory-mapped high-resolution timer device on Alpha. 5391999SN/A // We don't support it, so just punt. 5401999SN/A warn("Ignoring open(%s, ...)\n", path); 5411999SN/A return -ENOENT; 5423669Sbinkertn@umich.edu } 5433669Sbinkertn@umich.edu 5443669Sbinkertn@umich.edu int tgtFlags = process->getSyscallArg(tc, index); 5451999SN/A int mode = process->getSyscallArg(tc, index); 5461999SN/A int hostFlags = 0; 5471999SN/A 5482218SN/A // translate open flags 5491999SN/A for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) { 5501999SN/A if (tgtFlags & OS::openFlagTable[i].tgtFlag) { 5511999SN/A tgtFlags &= ~OS::openFlagTable[i].tgtFlag; 5521999SN/A hostFlags |= OS::openFlagTable[i].hostFlag; 5531999SN/A } 5541999SN/A } 5551999SN/A 5561999SN/A // any target flags left? 5573114Sgblack@eecs.umich.edu if (tgtFlags != 0) 5582680Sktlim@umich.edu warn("Syscall: open: cannot decode flags 0x%x", tgtFlags); 5591999SN/A 5602680Sktlim@umich.edu#ifdef __CYGWIN32__ 5611999SN/A hostFlags |= O_BINARY; 5621999SN/A#endif 5631999SN/A 5641999SN/A // Adjust path for current working directory 5651999SN/A path = process->fullPath(path); 5662680Sktlim@umich.edu 5671999SN/A DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str()); 5681999SN/A 5691999SN/A int fd; 5701999SN/A if (!path.compare(0, 6, "/proc/") || !path.compare(0, 8, "/system/") || 5711999SN/A !path.compare(0, 10, "/platform/") || !path.compare(0, 5, "/sys/")) { 5721999SN/A // It's a proc/sys entery and requires special handling 5731999SN/A fd = OS::openSpecialFile(path, process, tc); 5741999SN/A return (fd == -1) ? -1 : process->alloc_fd(fd,path.c_str(),hostFlags,mode, false); 5752218SN/A } else { 5761999SN/A // open the file 5771999SN/A fd = open(path.c_str(), hostFlags, mode); 5781999SN/A return (fd == -1) ? -errno : process->alloc_fd(fd,path.c_str(),hostFlags,mode, false); 5791999SN/A } 5801999SN/A 581378SN/A} 582360SN/A 5831450SN/A/// Target sysinfo() handler. 5843114Sgblack@eecs.umich.edutemplate <class OS> 5852680Sktlim@umich.eduSyscallReturn 586360SN/AsysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 587360SN/A ThreadContext *tc) 588360SN/A{ 5892680Sktlim@umich.edu 5902400SN/A int index = 0; 591360SN/A TypedBufferArg<typename OS::tgt_sysinfo> 5923669Sbinkertn@umich.edu sysinfo(process->getSyscallArg(tc, index)); 5933669Sbinkertn@umich.edu 5943669Sbinkertn@umich.edu sysinfo->uptime=seconds_since_epoch; 595360SN/A sysinfo->totalram=process->system->memSize(); 596360SN/A 597360SN/A sysinfo.copyOut(tc->getMemProxy()); 598360SN/A 5992218SN/A return 0; 600360SN/A} 6013113Sgblack@eecs.umich.edu 602360SN/A/// Target chmod() handler. 6031458SN/Atemplate <class OS> 604360SN/ASyscallReturn 605360SN/AchmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 606360SN/A ThreadContext *tc) 6075074Ssaidi@eecs.umich.edu{ 6085074Ssaidi@eecs.umich.edu std::string path; 6095074Ssaidi@eecs.umich.edu 6105074Ssaidi@eecs.umich.edu int index = 0; 6115074Ssaidi@eecs.umich.edu if (!tc->getMemProxy().tryReadString(path, 6125074Ssaidi@eecs.umich.edu process->getSyscallArg(tc, index))) { 6135074Ssaidi@eecs.umich.edu return -EFAULT; 6145074Ssaidi@eecs.umich.edu } 6155074Ssaidi@eecs.umich.edu 6165074Ssaidi@eecs.umich.edu uint32_t mode = process->getSyscallArg(tc, index); 6175074Ssaidi@eecs.umich.edu mode_t hostMode = 0; 6185074Ssaidi@eecs.umich.edu 6195074Ssaidi@eecs.umich.edu // XXX translate mode flags via OS::something??? 6205074Ssaidi@eecs.umich.edu hostMode = mode; 6215208Ssaidi@eecs.umich.edu 6225208Ssaidi@eecs.umich.edu // Adjust path for current working directory 6235208Ssaidi@eecs.umich.edu path = process->fullPath(path); 6245208Ssaidi@eecs.umich.edu 6255074Ssaidi@eecs.umich.edu // do the chmod 6265074Ssaidi@eecs.umich.edu int result = chmod(path.c_str(), hostMode); 6275208Ssaidi@eecs.umich.edu if (result < 0) 6285074Ssaidi@eecs.umich.edu return -errno; 6295074Ssaidi@eecs.umich.edu 6305074Ssaidi@eecs.umich.edu return 0; 6315074Ssaidi@eecs.umich.edu} 6325074Ssaidi@eecs.umich.edu 6335074Ssaidi@eecs.umich.edu 6345074Ssaidi@eecs.umich.edu/// Target fchmod() handler. 6355074Ssaidi@eecs.umich.edutemplate <class OS> 6365074Ssaidi@eecs.umich.eduSyscallReturn 6375074Ssaidi@eecs.umich.edufchmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 6381999SN/A ThreadContext *tc) 6391999SN/A{ 6401999SN/A int index = 0; 6413114Sgblack@eecs.umich.edu int fd = process->getSyscallArg(tc, index); 6422680Sktlim@umich.edu if (fd < 0 || process->sim_fd(fd) < 0) { 6431999SN/A // doesn't map to any simulator fd: not a valid target fd 6442680Sktlim@umich.edu return -EBADF; 6451999SN/A } 6461999SN/A 6471999SN/A uint32_t mode = process->getSyscallArg(tc, index); 6481999SN/A mode_t hostMode = 0; 6491999SN/A 6502764Sstever@eecs.umich.edu // XXX translate mode flags via OS::someting??? 6512064SN/A hostMode = mode; 6522064SN/A 6532064SN/A // do the fchmod 6542064SN/A int result = fchmod(process->sim_fd(fd), hostMode); 6551999SN/A if (result < 0) 6562064SN/A return -errno; 6571999SN/A 6581999SN/A return 0; 6592218SN/A} 6601999SN/A 6613114Sgblack@eecs.umich.edu/// Target mremap() handler. 6623114Sgblack@eecs.umich.edutemplate <class OS> 6631999SN/ASyscallReturn 6641999SN/AmremapFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) 6651999SN/A{ 6661999SN/A int index = 0; 6671999SN/A Addr start = process->getSyscallArg(tc, index); 668378SN/A uint64_t old_length = process->getSyscallArg(tc, index); 669360SN/A uint64_t new_length = process->getSyscallArg(tc, index); 6701450SN/A uint64_t flags = process->getSyscallArg(tc, index); 6713114Sgblack@eecs.umich.edu 6722680Sktlim@umich.edu if ((start % TheISA::VMPageSize != 0) || 673360SN/A (new_length % TheISA::VMPageSize != 0)) { 674360SN/A warn("mremap failing: arguments not page aligned"); 675360SN/A return -EINVAL; 6762680Sktlim@umich.edu } 6772400SN/A 678360SN/A if (new_length > old_length) { 6793669Sbinkertn@umich.edu if ((start + old_length) == process->mmap_end) { 6803669Sbinkertn@umich.edu uint64_t diff = new_length - old_length; 6813669Sbinkertn@umich.edu process->allocateMem(process->mmap_end, diff); 682360SN/A process->mmap_end += diff; 683360SN/A return start; 684360SN/A } else { 685360SN/A // sys/mman.h defined MREMAP_MAYMOVE 6861458SN/A if (!(flags & 1)) { 687360SN/A warn("can't remap here and MREMAP_MAYMOVE flag not set\n"); 6883113Sgblack@eecs.umich.edu return -ENOMEM; 689360SN/A } else { 6901458SN/A process->pTable->remap(start, old_length, process->mmap_end); 691360SN/A warn("mremapping to totally new vaddr %08p-%08p, adding %d\n", 692360SN/A process->mmap_end, process->mmap_end + new_length, new_length); 6931999SN/A start = process->mmap_end; 6941999SN/A // add on the remaining unallocated pages 6951999SN/A process->allocateMem(start + old_length, 6963114Sgblack@eecs.umich.edu new_length - old_length); 6972680Sktlim@umich.edu process->mmap_end += new_length; 6981999SN/A warn("returning %08p as start\n", start); 6991999SN/A return start; 7001999SN/A } 7012680Sktlim@umich.edu } 7022400SN/A } else { 7031999SN/A process->pTable->unmap(start + new_length, old_length - new_length); 7043669Sbinkertn@umich.edu return start; 7053669Sbinkertn@umich.edu } 7063669Sbinkertn@umich.edu} 7072764Sstever@eecs.umich.edu 7082064SN/A/// Target stat() handler. 7092064SN/Atemplate <class OS> 7102064SN/ASyscallReturn 7111999SN/AstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 7121999SN/A ThreadContext *tc) 7132064SN/A{ 7141999SN/A std::string path; 7151999SN/A 7161999SN/A int index = 0; 7171999SN/A if (!tc->getMemProxy().tryReadString(path, 7183114Sgblack@eecs.umich.edu process->getSyscallArg(tc, index))) { 7191999SN/A return -EFAULT; 7201999SN/A } 7211999SN/A Addr bufPtr = process->getSyscallArg(tc, index); 7221999SN/A 723378SN/A // Adjust path for current working directory 724360SN/A path = process->fullPath(path); 7251450SN/A 7263114Sgblack@eecs.umich.edu struct stat hostBuf; 7272680Sktlim@umich.edu int result = stat(path.c_str(), &hostBuf); 728360SN/A 7292680Sktlim@umich.edu if (result < 0) 730360SN/A return -errno; 7311969SN/A 732360SN/A copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 733360SN/A 7341458SN/A return 0; 735360SN/A} 736360SN/A 737360SN/A 738360SN/A/// Target stat64() handler. 739360SN/Atemplate <class OS> 7401458SN/ASyscallReturn 741360SN/Astat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 7423114Sgblack@eecs.umich.edu ThreadContext *tc) 7433114Sgblack@eecs.umich.edu{ 7442021SN/A std::string path; 7451458SN/A 746360SN/A int index = 0; 747360SN/A if (!tc->getMemProxy().tryReadString(path, 748360SN/A process->getSyscallArg(tc, index))) 7491706SN/A return -EFAULT; 7501706SN/A Addr bufPtr = process->getSyscallArg(tc, index); 7511706SN/A 7523114Sgblack@eecs.umich.edu // Adjust path for current working directory 7532680Sktlim@umich.edu path = process->fullPath(path); 7541706SN/A 7551706SN/A#if NO_STAT64 7561706SN/A struct stat hostBuf; 7572680Sktlim@umich.edu int result = stat(path.c_str(), &hostBuf); 7582400SN/A#else 7591706SN/A struct stat64 hostBuf; 7603669Sbinkertn@umich.edu int result = stat64(path.c_str(), &hostBuf); 7613669Sbinkertn@umich.edu#endif 7623669Sbinkertn@umich.edu 7631706SN/A if (result < 0) 7641706SN/A return -errno; 7651706SN/A 7661706SN/A copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 7672218SN/A 7681706SN/A return 0; 7693114Sgblack@eecs.umich.edu} 7703114Sgblack@eecs.umich.edu 7711706SN/A 7721706SN/A/// Target fstat64() handler. 7731706SN/Atemplate <class OS> 7741706SN/ASyscallReturn 7751706SN/Afstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 7761706SN/A ThreadContext *tc) 7771706SN/A{ 7781706SN/A int index = 0; 7793114Sgblack@eecs.umich.edu int fd = process->getSyscallArg(tc, index); 7802680Sktlim@umich.edu Addr bufPtr = process->getSyscallArg(tc, index); 7811706SN/A if (fd < 0 || process->sim_fd(fd) < 0) { 7822680Sktlim@umich.edu // doesn't map to any simulator fd: not a valid target fd 7831706SN/A return -EBADF; 7841706SN/A } 7851706SN/A 7861706SN/A#if NO_STAT64 7871706SN/A struct stat hostBuf; 7881706SN/A int result = fstat(process->sim_fd(fd), &hostBuf); 7891706SN/A#else 7901706SN/A struct stat64 hostBuf; 7912218SN/A int result = fstat64(process->sim_fd(fd), &hostBuf); 7921706SN/A#endif 7933114Sgblack@eecs.umich.edu 7943114Sgblack@eecs.umich.edu if (result < 0) 7951706SN/A return -errno; 7961706SN/A 7971706SN/A copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (fd == 1)); 7981706SN/A 7991706SN/A return 0; 8001999SN/A} 8011999SN/A 8021999SN/A 8033114Sgblack@eecs.umich.edu/// Target lstat() handler. 8042680Sktlim@umich.edutemplate <class OS> 8051999SN/ASyscallReturn 8062680Sktlim@umich.edulstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 8071999SN/A ThreadContext *tc) 8081999SN/A{ 8091999SN/A std::string path; 8101999SN/A 8111999SN/A int index = 0; 8122680Sktlim@umich.edu if (!tc->getMemProxy().tryReadString(path, 8132680Sktlim@umich.edu process->getSyscallArg(tc, index))) { 8142680Sktlim@umich.edu return -EFAULT; 8151999SN/A } 8161999SN/A Addr bufPtr = process->getSyscallArg(tc, index); 8171999SN/A 8181999SN/A // Adjust path for current working directory 8192461SN/A path = process->fullPath(path); 8202461SN/A 8212461SN/A struct stat hostBuf; 8222091SN/A int result = lstat(path.c_str(), &hostBuf); 8231999SN/A 8242461SN/A if (result < 0) 8252461SN/A return -errno; 8261999SN/A 8271999SN/A copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 8281999SN/A 8291999SN/A return 0; 8301999SN/A} 8311999SN/A 8321999SN/A/// Target lstat64() handler. 8331999SN/Atemplate <class OS> 8341999SN/ASyscallReturn 8351999SN/Alstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 8362218SN/A ThreadContext *tc) 8371999SN/A{ 8381999SN/A std::string path; 8391999SN/A 8401999SN/A int index = 0; 8411999SN/A if (!tc->getMemProxy().tryReadString(path, 842378SN/A process->getSyscallArg(tc, index))) { 843378SN/A return -EFAULT; 844378SN/A } 845378SN/A Addr bufPtr = process->getSyscallArg(tc, index); 846378SN/A 847378SN/A // Adjust path for current working directory 848378SN/A path = process->fullPath(path); 849378SN/A 850360SN/A#if NO_STAT64 851378SN/A struct stat hostBuf; 852378SN/A int result = lstat(path.c_str(), &hostBuf); 853378SN/A#else 854360SN/A struct stat64 hostBuf; 8551450SN/A int result = lstat64(path.c_str(), &hostBuf); 8563114Sgblack@eecs.umich.edu#endif 857360SN/A 8582680Sktlim@umich.edu if (result < 0) 8592680Sktlim@umich.edu return -errno; 8602680Sktlim@umich.edu 8612680Sktlim@umich.edu copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 8622680Sktlim@umich.edu 8632680Sktlim@umich.edu return 0; 864360SN/A} 8652544SN/A 8662544SN/A/// Target fstat() handler. 8672544SN/Atemplate <class OS> 8682544SN/ASyscallReturn 8692544SN/AfstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 8702544SN/A ThreadContext *tc) 871360SN/A{ 872360SN/A int index = 0; 8732544SN/A int fd = process->sim_fd(process->getSyscallArg(tc, index)); 8742544SN/A Addr bufPtr = process->getSyscallArg(tc, index); 8752544SN/A 8762544SN/A DPRINTF(SyscallVerbose, "fstat(%d, ...)\n", fd); 8772544SN/A 8782544SN/A if (fd < 0) 8792544SN/A return -EBADF; 8802544SN/A 8812544SN/A struct stat hostBuf; 8822544SN/A int result = fstat(fd, &hostBuf); 8832553SN/A 8841969SN/A if (result < 0) 8852680Sktlim@umich.edu return -errno; 886360SN/A 887360SN/A copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (fd == 1)); 8881458SN/A 889360SN/A return 0; 890360SN/A} 891378SN/A 892360SN/A 8931450SN/A/// Target statfs() handler. 8943114Sgblack@eecs.umich.edutemplate <class OS> 8952680Sktlim@umich.eduSyscallReturn 896360SN/AstatfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 8972680Sktlim@umich.edu ThreadContext *tc) 8982680Sktlim@umich.edu{ 899360SN/A std::string path; 900360SN/A 9012064SN/A int index = 0; 9022064SN/A if (!tc->getMemProxy().tryReadString(path, 9032064SN/A process->getSyscallArg(tc, index))) { 9042091SN/A return -EFAULT; 9052091SN/A } 9062064SN/A Addr bufPtr = process->getSyscallArg(tc, index); 907360SN/A 9082064SN/A // Adjust path for current working directory 9092064SN/A path = process->fullPath(path); 9102064SN/A 9112064SN/A struct statfs hostBuf; 9122064SN/A int result = statfs(path.c_str(), &hostBuf); 913360SN/A 914360SN/A if (result < 0) 9152680Sktlim@umich.edu return -errno; 9161458SN/A 917360SN/A OS::copyOutStatfsBuf(tc->getMemProxy(), bufPtr, &hostBuf); 918360SN/A 919378SN/A return 0; 920360SN/A} 9211450SN/A 9223114Sgblack@eecs.umich.edu 9232680Sktlim@umich.edu/// Target fstatfs() handler. 924360SN/Atemplate <class OS> 9252680Sktlim@umich.eduSyscallReturn 926360SN/AfstatfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 927360SN/A ThreadContext *tc) 928360SN/A{ 9292091SN/A int index = 0; 9302091SN/A int fd = process->sim_fd(process->getSyscallArg(tc, index)); 931360SN/A Addr bufPtr = process->getSyscallArg(tc, index); 9322680Sktlim@umich.edu 933360SN/A if (fd < 0) 9341458SN/A return -EBADF; 935360SN/A 936360SN/A struct statfs hostBuf; 937360SN/A int result = fstatfs(fd, &hostBuf); 9381999SN/A 9391999SN/A if (result < 0) 9401999SN/A return -errno; 9413114Sgblack@eecs.umich.edu 9422680Sktlim@umich.edu OS::copyOutStatfsBuf(tc->getMemProxy(), bufPtr, &hostBuf); 9431999SN/A 9441999SN/A return 0; 9451999SN/A} 9462680Sktlim@umich.edu 9472400SN/A 9481999SN/A/// Target writev() handler. 9492680Sktlim@umich.edutemplate <class OS> 9502680Sktlim@umich.eduSyscallReturn 9511999SN/AwritevFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 9521999SN/A ThreadContext *tc) 9531999SN/A{ 9541999SN/A int index = 0; 9552091SN/A int fd = process->getSyscallArg(tc, index); 9562091SN/A if (fd < 0 || process->sim_fd(fd) < 0) { 9571999SN/A // doesn't map to any simulator fd: not a valid target fd 9583669Sbinkertn@umich.edu return -EBADF; 9593669Sbinkertn@umich.edu } 9603669Sbinkertn@umich.edu 9613669Sbinkertn@umich.edu SETranslatingPortProxy &p = tc->getMemProxy(); 9621999SN/A uint64_t tiov_base = process->getSyscallArg(tc, index); 9631999SN/A size_t count = process->getSyscallArg(tc, index); 9641999SN/A struct iovec hiov[count]; 9651999SN/A for (size_t i = 0; i < count; ++i) { 9661999SN/A typename OS::tgt_iovec tiov; 9671999SN/A 9681999SN/A p.readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec), 969378SN/A (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec)); 970360SN/A hiov[i].iov_len = TheISA::gtoh(tiov.iov_len); 9711450SN/A hiov[i].iov_base = new char [hiov[i].iov_len]; 9723114Sgblack@eecs.umich.edu p.readBlob(TheISA::gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base, 9732680Sktlim@umich.edu hiov[i].iov_len); 974360SN/A } 9752680Sktlim@umich.edu 9762680Sktlim@umich.edu int result = writev(process->sim_fd(fd), hiov, count); 977360SN/A 9783670Sbinkertn@umich.edu for (size_t i = 0; i < count; ++i) 9793670Sbinkertn@umich.edu delete [] (char *)hiov[i].iov_base; 980360SN/A 981360SN/A if (result < 0) 982360SN/A return -errno; 983360SN/A 984360SN/A return 0; 985360SN/A} 986360SN/A 987360SN/A 988360SN/A/// Target mmap() handler. 989360SN/A/// 990360SN/A/// We don't really handle mmap(). If the target is mmaping an 991360SN/A/// anonymous region or /dev/zero, we can get away with doing basically 992360SN/A/// nothing (since memory is initialized to zero and the simulator 993360SN/A/// doesn't really check addresses anyway). 994360SN/A/// 995360SN/Atemplate <class OS> 996360SN/ASyscallReturn 9973670Sbinkertn@umich.edummapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 9983670Sbinkertn@umich.edu{ 9993670Sbinkertn@umich.edu int index = 0; 10003670Sbinkertn@umich.edu Addr start = p->getSyscallArg(tc, index); 10013670Sbinkertn@umich.edu uint64_t length = p->getSyscallArg(tc, index); 10023670Sbinkertn@umich.edu index++; // int prot = p->getSyscallArg(tc, index); 10033670Sbinkertn@umich.edu int flags = p->getSyscallArg(tc, index); 10043670Sbinkertn@umich.edu int tgt_fd = p->getSyscallArg(tc, index); 10053670Sbinkertn@umich.edu // int offset = p->getSyscallArg(tc, index); 10063670Sbinkertn@umich.edu 10073670Sbinkertn@umich.edu if (!(flags & OS::TGT_MAP_ANONYMOUS)) { 10083670Sbinkertn@umich.edu Process::FdMap *fd_map = p->sim_fd_obj(tgt_fd); 10093670Sbinkertn@umich.edu if (!fd_map || fd_map->fd < 0) { 10103670Sbinkertn@umich.edu warn("mmap failing: target fd %d is not valid\n", tgt_fd); 10113670Sbinkertn@umich.edu return -EBADF; 10123670Sbinkertn@umich.edu } 10133670Sbinkertn@umich.edu 10143670Sbinkertn@umich.edu if (fd_map->filename != "/dev/zero") { 10152680Sktlim@umich.edu // This is very likely broken, but leave a warning here 1016360SN/A // (rather than panic) in case /dev/zero is known by 10171458SN/A // another name on some platform 1018360SN/A warn("allowing mmap of file %s; mmap not supported on files" 1019360SN/A " other than /dev/zero\n", fd_map->filename); 10202553SN/A } 10212553SN/A } 10222553SN/A 10231354SN/A if ((start % TheISA::VMPageSize) != 0 || 1024 (length % TheISA::VMPageSize) != 0) { 1025 warn("mmap failing: arguments not page-aligned: " 1026 "start 0x%x length 0x%x", 1027 start, length); 1028 return -EINVAL; 1029 } 1030 1031 // are we ok with clobbering existing mappings? only set this to 1032 // true if the user has been warned. 1033 bool clobber = false; 1034 1035 // try to use the caller-provided address if there is one 1036 bool use_provided_address = (start != 0); 1037 1038 if (use_provided_address) { 1039 // check to see if the desired address is already in use 1040 if (!p->pTable->isUnmapped(start, length)) { 1041 // there are existing mappings in the desired range 1042 // whether we clobber them or not depends on whether the caller 1043 // specified MAP_FIXED 1044 if (flags & OS::TGT_MAP_FIXED) { 1045 // MAP_FIXED specified: clobber existing mappings 1046 warn("mmap: MAP_FIXED at 0x%x overwrites existing mappings\n", 1047 start); 1048 clobber = true; 1049 } else { 1050 // MAP_FIXED not specified: ignore suggested start address 1051 warn("mmap: ignoring suggested map address 0x%x\n", start); 1052 use_provided_address = false; 1053 } 1054 } 1055 } 1056 1057 if (!use_provided_address) { 1058 // no address provided, or provided address unusable: 1059 // pick next address from our "mmap region" 1060 if (OS::mmapGrowsDown()) { 1061 start = p->mmap_end - length; 1062 p->mmap_end = start; 1063 } else { 1064 start = p->mmap_end; 1065 p->mmap_end += length; 1066 } 1067 } 1068 1069 p->allocateMem(start, length, clobber); 1070 1071 return start; 1072} 1073 1074/// Target getrlimit() handler. 1075template <class OS> 1076SyscallReturn 1077getrlimitFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1078 ThreadContext *tc) 1079{ 1080 int index = 0; 1081 unsigned resource = process->getSyscallArg(tc, index); 1082 TypedBufferArg<typename OS::rlimit> rlp(process->getSyscallArg(tc, index)); 1083 1084 switch (resource) { 1085 case OS::TGT_RLIMIT_STACK: 1086 // max stack size in bytes: make up a number (8MB for now) 1087 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; 1088 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1089 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1090 break; 1091 1092 case OS::TGT_RLIMIT_DATA: 1093 // max data segment size in bytes: make up a number 1094 rlp->rlim_cur = rlp->rlim_max = 256 * 1024 * 1024; 1095 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1096 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1097 break; 1098 1099 default: 1100 std::cerr << "getrlimitFunc: unimplemented resource " << resource 1101 << std::endl; 1102 abort(); 1103 break; 1104 } 1105 1106 rlp.copyOut(tc->getMemProxy()); 1107 return 0; 1108} 1109 1110/// Target gettimeofday() handler. 1111template <class OS> 1112SyscallReturn 1113gettimeofdayFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1114 ThreadContext *tc) 1115{ 1116 int index = 0; 1117 TypedBufferArg<typename OS::timeval> tp(process->getSyscallArg(tc, index)); 1118 1119 getElapsedTime(tp->tv_sec, tp->tv_usec); 1120 tp->tv_sec += seconds_since_epoch; 1121 tp->tv_sec = TheISA::htog(tp->tv_sec); 1122 tp->tv_usec = TheISA::htog(tp->tv_usec); 1123 1124 tp.copyOut(tc->getMemProxy()); 1125 1126 return 0; 1127} 1128 1129 1130/// Target utimes() handler. 1131template <class OS> 1132SyscallReturn 1133utimesFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1134 ThreadContext *tc) 1135{ 1136 std::string path; 1137 1138 int index = 0; 1139 if (!tc->getMemProxy().tryReadString(path, 1140 process->getSyscallArg(tc, index))) { 1141 return -EFAULT; 1142 } 1143 1144 TypedBufferArg<typename OS::timeval [2]> 1145 tp(process->getSyscallArg(tc, index)); 1146 tp.copyIn(tc->getMemProxy()); 1147 1148 struct timeval hostTimeval[2]; 1149 for (int i = 0; i < 2; ++i) 1150 { 1151 hostTimeval[i].tv_sec = TheISA::gtoh((*tp)[i].tv_sec); 1152 hostTimeval[i].tv_usec = TheISA::gtoh((*tp)[i].tv_usec); 1153 } 1154 1155 // Adjust path for current working directory 1156 path = process->fullPath(path); 1157 1158 int result = utimes(path.c_str(), hostTimeval); 1159 1160 if (result < 0) 1161 return -errno; 1162 1163 return 0; 1164} 1165/// Target getrusage() function. 1166template <class OS> 1167SyscallReturn 1168getrusageFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1169 ThreadContext *tc) 1170{ 1171 int index = 0; 1172 int who = process->getSyscallArg(tc, index); // THREAD, SELF, or CHILDREN 1173 TypedBufferArg<typename OS::rusage> rup(process->getSyscallArg(tc, index)); 1174 1175 rup->ru_utime.tv_sec = 0; 1176 rup->ru_utime.tv_usec = 0; 1177 rup->ru_stime.tv_sec = 0; 1178 rup->ru_stime.tv_usec = 0; 1179 rup->ru_maxrss = 0; 1180 rup->ru_ixrss = 0; 1181 rup->ru_idrss = 0; 1182 rup->ru_isrss = 0; 1183 rup->ru_minflt = 0; 1184 rup->ru_majflt = 0; 1185 rup->ru_nswap = 0; 1186 rup->ru_inblock = 0; 1187 rup->ru_oublock = 0; 1188 rup->ru_msgsnd = 0; 1189 rup->ru_msgrcv = 0; 1190 rup->ru_nsignals = 0; 1191 rup->ru_nvcsw = 0; 1192 rup->ru_nivcsw = 0; 1193 1194 switch (who) { 1195 case OS::TGT_RUSAGE_SELF: 1196 getElapsedTime(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec); 1197 rup->ru_utime.tv_sec = TheISA::htog(rup->ru_utime.tv_sec); 1198 rup->ru_utime.tv_usec = TheISA::htog(rup->ru_utime.tv_usec); 1199 break; 1200 1201 case OS::TGT_RUSAGE_CHILDREN: 1202 // do nothing. We have no child processes, so they take no time. 1203 break; 1204 1205 default: 1206 // don't really handle THREAD or CHILDREN, but just warn and 1207 // plow ahead 1208 warn("getrusage() only supports RUSAGE_SELF. Parameter %d ignored.", 1209 who); 1210 } 1211 1212 rup.copyOut(tc->getMemProxy()); 1213 1214 return 0; 1215} 1216 1217/// Target times() function. 1218template <class OS> 1219SyscallReturn 1220timesFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1221 ThreadContext *tc) 1222{ 1223 int index = 0; 1224 TypedBufferArg<typename OS::tms> bufp(process->getSyscallArg(tc, index)); 1225 1226 // Fill in the time structure (in clocks) 1227 int64_t clocks = curTick() * OS::M5_SC_CLK_TCK / SimClock::Int::s; 1228 bufp->tms_utime = clocks; 1229 bufp->tms_stime = 0; 1230 bufp->tms_cutime = 0; 1231 bufp->tms_cstime = 0; 1232 1233 // Convert to host endianness 1234 bufp->tms_utime = TheISA::htog(bufp->tms_utime); 1235 1236 // Write back 1237 bufp.copyOut(tc->getMemProxy()); 1238 1239 // Return clock ticks since system boot 1240 return clocks; 1241} 1242 1243/// Target time() function. 1244template <class OS> 1245SyscallReturn 1246timeFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1247 ThreadContext *tc) 1248{ 1249 typename OS::time_t sec, usec; 1250 getElapsedTime(sec, usec); 1251 sec += seconds_since_epoch; 1252 1253 int index = 0; 1254 Addr taddr = (Addr)process->getSyscallArg(tc, index); 1255 if(taddr != 0) { 1256 typename OS::time_t t = sec; 1257 t = TheISA::htog(t); 1258 SETranslatingPortProxy &p = tc->getMemProxy(); 1259 p.writeBlob(taddr, (uint8_t*)&t, (int)sizeof(typename OS::time_t)); 1260 } 1261 return sec; 1262} 1263 1264 1265#endif // __SIM_SYSCALL_EMUL_HH__ 1266