syscall_emul.hh revision 8852
1955SN/A/* 2955SN/A * Copyright (c) 2003-2005 The Regents of The University of Michigan 31762SN/A * All rights reserved. 4955SN/A * 5955SN/A * Redistribution and use in source and binary forms, with or without 6955SN/A * modification, are permitted provided that the following conditions are 7955SN/A * met: redistributions of source code must retain the above copyright 8955SN/A * notice, this list of conditions and the following disclaimer; 9955SN/A * redistributions in binary form must reproduce the above copyright 10955SN/A * notice, this list of conditions and the following disclaimer in the 11955SN/A * documentation and/or other materials provided with the distribution; 12955SN/A * neither the name of the copyright holders nor the names of its 13955SN/A * contributors may be used to endorse or promote products derived from 14955SN/A * this software without specific prior written permission. 15955SN/A * 16955SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17955SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18955SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19955SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20955SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21955SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22955SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23955SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24955SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25955SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26955SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27955SN/A * 282665Ssaidi@eecs.umich.edu * Authors: Steve Reinhardt 292665Ssaidi@eecs.umich.edu * Kevin Lim 30955SN/A */ 31955SN/A 32955SN/A#ifndef __SIM_SYSCALL_EMUL_HH__ 33955SN/A#define __SIM_SYSCALL_EMUL_HH__ 34955SN/A 352632Sstever@eecs.umich.edu#define NO_STAT64 (defined(__APPLE__) || defined(__OpenBSD__) || \ 362632Sstever@eecs.umich.edu defined(__FreeBSD__) || defined(__CYGWIN__)) 372632Sstever@eecs.umich.edu 382632Sstever@eecs.umich.edu/// 39955SN/A/// @file syscall_emul.hh 402632Sstever@eecs.umich.edu/// 412632Sstever@eecs.umich.edu/// This file defines objects used to emulate syscalls from the target 422632Sstever@eecs.umich.edu/// application on the host machine. 432632Sstever@eecs.umich.edu 442632Sstever@eecs.umich.edu#ifdef __CYGWIN32__ 452632Sstever@eecs.umich.edu#include <sys/fcntl.h> // for O_BINARY 462632Sstever@eecs.umich.edu#endif 472632Sstever@eecs.umich.edu#include <sys/stat.h> 482632Sstever@eecs.umich.edu#include <sys/time.h> 492632Sstever@eecs.umich.edu#include <sys/uio.h> 502632Sstever@eecs.umich.edu#include <fcntl.h> 512632Sstever@eecs.umich.edu 522632Sstever@eecs.umich.edu#include <cerrno> 532632Sstever@eecs.umich.edu#include <string> 542632Sstever@eecs.umich.edu 552632Sstever@eecs.umich.edu#include "base/chunk_generator.hh" 562632Sstever@eecs.umich.edu#include "base/intmath.hh" // for RoundUp 572632Sstever@eecs.umich.edu#include "base/misc.hh" 582632Sstever@eecs.umich.edu#include "base/trace.hh" 592632Sstever@eecs.umich.edu#include "base/types.hh" 60955SN/A#include "config/the_isa.hh" 61955SN/A#include "cpu/base.hh" 62955SN/A#include "cpu/thread_context.hh" 63955SN/A#include "debug/SyscallVerbose.hh" 64955SN/A#include "mem/page_table.hh" 65955SN/A#include "mem/se_translating_port_proxy.hh" 66955SN/A#include "sim/byteswap.hh" 672656Sstever@eecs.umich.edu#include "sim/process.hh" 682656Sstever@eecs.umich.edu#include "sim/syscallreturn.hh" 692656Sstever@eecs.umich.edu#include "sim/system.hh" 702656Sstever@eecs.umich.edu 712656Sstever@eecs.umich.edu/// 722656Sstever@eecs.umich.edu/// System call descriptor. 732656Sstever@eecs.umich.edu/// 742653Sstever@eecs.umich.educlass SyscallDesc { 752653Sstever@eecs.umich.edu 762653Sstever@eecs.umich.edu public: 772653Sstever@eecs.umich.edu 782653Sstever@eecs.umich.edu /// Typedef for target syscall handler functions. 792653Sstever@eecs.umich.edu typedef SyscallReturn (*FuncPtr)(SyscallDesc *, int num, 802653Sstever@eecs.umich.edu LiveProcess *, ThreadContext *); 812653Sstever@eecs.umich.edu 822653Sstever@eecs.umich.edu const char *name; //!< Syscall name (e.g., "open"). 832653Sstever@eecs.umich.edu FuncPtr funcPtr; //!< Pointer to emulation function. 842653Sstever@eecs.umich.edu int flags; //!< Flags (see Flags enum). 851852SN/A 86955SN/A /// Flag values for controlling syscall behavior. 87955SN/A enum Flags { 88955SN/A /// Don't set return regs according to funcPtr return value. 892632Sstever@eecs.umich.edu /// Used for syscalls with non-standard return conventions 902632Sstever@eecs.umich.edu /// that explicitly set the ThreadContext regs (e.g., 91955SN/A /// sigreturn). 921533SN/A SuppressReturnValue = 1 932632Sstever@eecs.umich.edu }; 941533SN/A 95955SN/A /// Constructor. 96955SN/A SyscallDesc(const char *_name, FuncPtr _funcPtr, int _flags = 0) 972632Sstever@eecs.umich.edu : name(_name), funcPtr(_funcPtr), flags(_flags) 982632Sstever@eecs.umich.edu { 99955SN/A } 100955SN/A 101955SN/A /// Emulate the syscall. Public interface for calling through funcPtr. 102955SN/A void doSyscall(int callnum, LiveProcess *proc, ThreadContext *tc); 1032632Sstever@eecs.umich.edu}; 104955SN/A 1052632Sstever@eecs.umich.edu 106955SN/Aclass BaseBufferArg { 107955SN/A 1082632Sstever@eecs.umich.edu public: 1092632Sstever@eecs.umich.edu 1102632Sstever@eecs.umich.edu BaseBufferArg(Addr _addr, int _size) : addr(_addr), size(_size) 1112632Sstever@eecs.umich.edu { 1122632Sstever@eecs.umich.edu bufPtr = new uint8_t[size]; 1132632Sstever@eecs.umich.edu // clear out buffer: in case we only partially populate this, 1142632Sstever@eecs.umich.edu // and then do a copyOut(), we want to make sure we don't 1152632Sstever@eecs.umich.edu // introduce any random junk into the simulated address space 1162632Sstever@eecs.umich.edu memset(bufPtr, 0, size); 1172632Sstever@eecs.umich.edu } 1182632Sstever@eecs.umich.edu 1192632Sstever@eecs.umich.edu virtual ~BaseBufferArg() { delete [] bufPtr; } 1202632Sstever@eecs.umich.edu 1212632Sstever@eecs.umich.edu // 1222632Sstever@eecs.umich.edu // copy data into simulator space (read from target memory) 1232632Sstever@eecs.umich.edu // 1242632Sstever@eecs.umich.edu virtual bool copyIn(SETranslatingPortProxy &memproxy) 1252634Sstever@eecs.umich.edu { 1262634Sstever@eecs.umich.edu memproxy.readBlob(addr, bufPtr, size); 1272632Sstever@eecs.umich.edu return true; // no EFAULT detection for now 1282638Sstever@eecs.umich.edu } 1292632Sstever@eecs.umich.edu 1302632Sstever@eecs.umich.edu // 1312632Sstever@eecs.umich.edu // copy data out of simulator space (write to target memory) 1322632Sstever@eecs.umich.edu // 1332632Sstever@eecs.umich.edu virtual bool copyOut(SETranslatingPortProxy &memproxy) 1342632Sstever@eecs.umich.edu { 1351858SN/A memproxy.writeBlob(addr, bufPtr, size); 1362638Sstever@eecs.umich.edu return true; // no EFAULT detection for now 1372638Sstever@eecs.umich.edu } 1382638Sstever@eecs.umich.edu 1392638Sstever@eecs.umich.edu protected: 1402638Sstever@eecs.umich.edu Addr addr; 1412638Sstever@eecs.umich.edu int size; 1422638Sstever@eecs.umich.edu uint8_t *bufPtr; 1432638Sstever@eecs.umich.edu}; 1442634Sstever@eecs.umich.edu 1452634Sstever@eecs.umich.edu 1462634Sstever@eecs.umich.educlass BufferArg : public BaseBufferArg 147955SN/A{ 148955SN/A public: 149955SN/A BufferArg(Addr _addr, int _size) : BaseBufferArg(_addr, _size) { } 150955SN/A void *bufferPtr() { return bufPtr; } 151955SN/A}; 152955SN/A 153955SN/Atemplate <class T> 154955SN/Aclass TypedBufferArg : public BaseBufferArg 1551858SN/A{ 1561858SN/A public: 1572632Sstever@eecs.umich.edu // user can optionally specify a specific number of bytes to 158955SN/A // allocate to deal with those structs that have variable-size 1591858SN/A // arrays at the end 1601105SN/A TypedBufferArg(Addr _addr, int _size = sizeof(T)) 1611869SN/A : BaseBufferArg(_addr, _size) 1621869SN/A { } 1631869SN/A 1641869SN/A // type case 1651869SN/A operator T*() { return (T *)bufPtr; } 1661065SN/A 1672632Sstever@eecs.umich.edu // dereference operators 1682632Sstever@eecs.umich.edu T &operator*() { return *((T *)bufPtr); } 169955SN/A T* operator->() { return (T *)bufPtr; } 1701858SN/A T &operator[](int i) { return ((T *)bufPtr)[i]; } 1711858SN/A}; 1721858SN/A 1731858SN/A////////////////////////////////////////////////////////////////////// 1741851SN/A// 1751851SN/A// The following emulation functions are generic enough that they 1761858SN/A// don't need to be recompiled for different emulated OS's. They are 1772632Sstever@eecs.umich.edu// defined in sim/syscall_emul.cc. 178955SN/A// 1792656Sstever@eecs.umich.edu////////////////////////////////////////////////////////////////////// 1802656Sstever@eecs.umich.edu 1812656Sstever@eecs.umich.edu 1822656Sstever@eecs.umich.edu/// Handler for unimplemented syscalls that we haven't thought about. 1832656Sstever@eecs.umich.eduSyscallReturn unimplementedFunc(SyscallDesc *desc, int num, 1842656Sstever@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 1852656Sstever@eecs.umich.edu 1862656Sstever@eecs.umich.edu/// Handler for unimplemented syscalls that we never intend to 1872656Sstever@eecs.umich.edu/// implement (signal handling, etc.) and should not affect the correct 1882656Sstever@eecs.umich.edu/// behavior of the program. Print a warning only if the appropriate 1892656Sstever@eecs.umich.edu/// trace flag is enabled. Return success to the target program. 1902656Sstever@eecs.umich.eduSyscallReturn ignoreFunc(SyscallDesc *desc, int num, 1912656Sstever@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 1922656Sstever@eecs.umich.eduSyscallReturn ignoreWarnOnceFunc(SyscallDesc *desc, int num, 1932656Sstever@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 1942656Sstever@eecs.umich.edu 1952655Sstever@eecs.umich.edu/// Target exit() handler: terminate current context. 1962655Sstever@eecs.umich.eduSyscallReturn exitFunc(SyscallDesc *desc, int num, 1971858SN/A LiveProcess *p, ThreadContext *tc); 1981858SN/A 1992638Sstever@eecs.umich.edu/// Target exit_group() handler: terminate simulation. (exit all threads) 2002638Sstever@eecs.umich.eduSyscallReturn exitGroupFunc(SyscallDesc *desc, int num, 2012638Sstever@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 2022638Sstever@eecs.umich.edu 2032638Sstever@eecs.umich.edu/// Target getpagesize() handler. 2041858SN/ASyscallReturn getpagesizeFunc(SyscallDesc *desc, int num, 2051858SN/A LiveProcess *p, ThreadContext *tc); 2061858SN/A 2071858SN/A/// Target brk() handler: set brk address. 2081858SN/ASyscallReturn brkFunc(SyscallDesc *desc, int num, 2091858SN/A LiveProcess *p, ThreadContext *tc); 2101858SN/A 2111859SN/A/// Target close() handler. 2121858SN/ASyscallReturn closeFunc(SyscallDesc *desc, int num, 2131858SN/A LiveProcess *p, ThreadContext *tc); 2141858SN/A 2151859SN/A/// Target read() handler. 2161859SN/ASyscallReturn readFunc(SyscallDesc *desc, int num, 2171862SN/A LiveProcess *p, ThreadContext *tc); 2181862SN/A 2191862SN/A/// Target write() handler. 2201862SN/ASyscallReturn writeFunc(SyscallDesc *desc, int num, 2211859SN/A LiveProcess *p, ThreadContext *tc); 2221859SN/A 2231963SN/A/// Target lseek() handler. 2241963SN/ASyscallReturn lseekFunc(SyscallDesc *desc, int num, 2251859SN/A LiveProcess *p, ThreadContext *tc); 2261859SN/A 2271859SN/A/// Target _llseek() handler. 2281859SN/ASyscallReturn _llseekFunc(SyscallDesc *desc, int num, 2291859SN/A LiveProcess *p, ThreadContext *tc); 2301859SN/A 2311859SN/A/// Target munmap() handler. 2321859SN/ASyscallReturn munmapFunc(SyscallDesc *desc, int num, 2331862SN/A LiveProcess *p, ThreadContext *tc); 2341859SN/A 2351859SN/A/// Target gethostname() handler. 2361859SN/ASyscallReturn gethostnameFunc(SyscallDesc *desc, int num, 2371858SN/A LiveProcess *p, ThreadContext *tc); 2381858SN/A 2392139SN/A/// Target getcwd() handler. 2402139SN/ASyscallReturn getcwdFunc(SyscallDesc *desc, int num, 2412139SN/A LiveProcess *p, ThreadContext *tc); 2422155SN/A 2432623SN/A/// Target unlink() handler. 2442637Sstever@eecs.umich.eduSyscallReturn readlinkFunc(SyscallDesc *desc, int num, 2452155SN/A LiveProcess *p, ThreadContext *tc); 2461869SN/A 2471869SN/A/// Target unlink() handler. 2481869SN/ASyscallReturn unlinkFunc(SyscallDesc *desc, int num, 2491869SN/A LiveProcess *p, ThreadContext *tc); 2501869SN/A 2512139SN/A/// Target mkdir() handler. 2521869SN/ASyscallReturn mkdirFunc(SyscallDesc *desc, int num, 2532508SN/A LiveProcess *p, ThreadContext *tc); 2542508SN/A 2552508SN/A/// Target rename() handler. 2562508SN/ASyscallReturn renameFunc(SyscallDesc *desc, int num, 2572635Sstever@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 2582635Sstever@eecs.umich.edu 2591869SN/A 2601869SN/A/// Target truncate() handler. 2611869SN/ASyscallReturn truncateFunc(SyscallDesc *desc, int num, 2621869SN/A LiveProcess *p, ThreadContext *tc); 2631869SN/A 2641869SN/A 2651869SN/A/// Target ftruncate() handler. 2661869SN/ASyscallReturn ftruncateFunc(SyscallDesc *desc, int num, 2671965SN/A LiveProcess *p, ThreadContext *tc); 2681965SN/A 2691965SN/A 2701869SN/A/// Target truncate64() handler. 2711869SN/ASyscallReturn truncate64Func(SyscallDesc *desc, int num, 2721869SN/A LiveProcess *p, ThreadContext *tc); 2731869SN/A 2741884SN/A/// Target ftruncate64() handler. 2751884SN/ASyscallReturn ftruncate64Func(SyscallDesc *desc, int num, 2761884SN/A LiveProcess *p, ThreadContext *tc); 2771869SN/A 2781858SN/A 2791869SN/A/// Target umask() handler. 2801869SN/ASyscallReturn umaskFunc(SyscallDesc *desc, int num, 2811869SN/A LiveProcess *p, ThreadContext *tc); 2821869SN/A 2831869SN/A 2841858SN/A/// Target chown() handler. 2851869SN/ASyscallReturn chownFunc(SyscallDesc *desc, int num, 2861869SN/A LiveProcess *p, ThreadContext *tc); 2871869SN/A 2881869SN/A 2891869SN/A/// Target fchown() handler. 2901869SN/ASyscallReturn fchownFunc(SyscallDesc *desc, int num, 2911869SN/A LiveProcess *p, ThreadContext *tc); 2921869SN/A 2931869SN/A/// Target dup() handler. 2941869SN/ASyscallReturn dupFunc(SyscallDesc *desc, int num, 2951858SN/A LiveProcess *process, ThreadContext *tc); 296955SN/A 297955SN/A/// Target fnctl() handler. 2981869SN/ASyscallReturn fcntlFunc(SyscallDesc *desc, int num, 2991869SN/A LiveProcess *process, ThreadContext *tc); 3001869SN/A 3011869SN/A/// Target fcntl64() handler. 3021869SN/ASyscallReturn fcntl64Func(SyscallDesc *desc, int num, 3031869SN/A LiveProcess *process, ThreadContext *tc); 3041869SN/A 3051869SN/A/// Target setuid() handler. 3061869SN/ASyscallReturn setuidFunc(SyscallDesc *desc, int num, 3071869SN/A LiveProcess *p, ThreadContext *tc); 3081869SN/A 3091869SN/A/// Target getpid() handler. 3101869SN/ASyscallReturn getpidFunc(SyscallDesc *desc, int num, 3111869SN/A LiveProcess *p, ThreadContext *tc); 3121869SN/A 3131869SN/A/// Target getuid() handler. 3141869SN/ASyscallReturn getuidFunc(SyscallDesc *desc, int num, 3151869SN/A LiveProcess *p, ThreadContext *tc); 3161869SN/A 3171869SN/A/// Target getgid() handler. 3181869SN/ASyscallReturn getgidFunc(SyscallDesc *desc, int num, 3191869SN/A LiveProcess *p, ThreadContext *tc); 3201869SN/A 3211869SN/A/// Target getppid() handler. 3221869SN/ASyscallReturn getppidFunc(SyscallDesc *desc, int num, 3231869SN/A LiveProcess *p, ThreadContext *tc); 3241869SN/A 3251869SN/A/// Target geteuid() handler. 3261869SN/ASyscallReturn geteuidFunc(SyscallDesc *desc, int num, 3271869SN/A LiveProcess *p, ThreadContext *tc); 3281869SN/A 3291869SN/A/// Target getegid() handler. 3301869SN/ASyscallReturn getegidFunc(SyscallDesc *desc, int num, 3311869SN/A LiveProcess *p, ThreadContext *tc); 3321869SN/A 3331869SN/A/// Target clone() handler. 3341869SN/ASyscallReturn cloneFunc(SyscallDesc *desc, int num, 3351869SN/A LiveProcess *p, ThreadContext *tc); 3361869SN/A 3372655Sstever@eecs.umich.edu 3382655Sstever@eecs.umich.edu/// Pseudo Funcs - These functions use a different return convension, 3392655Sstever@eecs.umich.edu/// returning a second value in a register other than the normal return register 3402655Sstever@eecs.umich.eduSyscallReturn pipePseudoFunc(SyscallDesc *desc, int num, 3412655Sstever@eecs.umich.edu LiveProcess *process, ThreadContext *tc); 3422655Sstever@eecs.umich.edu 3432655Sstever@eecs.umich.edu/// Target getpidPseudo() handler. 3442655Sstever@eecs.umich.eduSyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num, 3452655Sstever@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 3462655Sstever@eecs.umich.edu 3472655Sstever@eecs.umich.edu/// Target getuidPseudo() handler. 3482655Sstever@eecs.umich.eduSyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num, 3492655Sstever@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 3502655Sstever@eecs.umich.edu 3512655Sstever@eecs.umich.edu/// Target getgidPseudo() handler. 3522655Sstever@eecs.umich.eduSyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num, 3532655Sstever@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 3542655Sstever@eecs.umich.edu 3552655Sstever@eecs.umich.edu 3562655Sstever@eecs.umich.edu/// A readable name for 1,000,000, for converting microseconds to seconds. 3572655Sstever@eecs.umich.educonst int one_million = 1000000; 3582655Sstever@eecs.umich.edu 3592655Sstever@eecs.umich.edu/// Approximate seconds since the epoch (1/1/1970). About a billion, 3602655Sstever@eecs.umich.edu/// by my reckoning. We want to keep this a constant (not use the 3612655Sstever@eecs.umich.edu/// real-world time) to keep simulations repeatable. 3622655Sstever@eecs.umich.educonst unsigned seconds_since_epoch = 1000000000; 3632634Sstever@eecs.umich.edu 3642634Sstever@eecs.umich.edu/// Helper function to convert current elapsed time to seconds and 3652634Sstever@eecs.umich.edu/// microseconds. 3662634Sstever@eecs.umich.edutemplate <class T1, class T2> 3672634Sstever@eecs.umich.eduvoid 3682634Sstever@eecs.umich.edugetElapsedTime(T1 &sec, T2 &usec) 3692638Sstever@eecs.umich.edu{ 3702638Sstever@eecs.umich.edu int elapsed_usecs = curTick() / SimClock::Int::us; 3712638Sstever@eecs.umich.edu sec = elapsed_usecs / one_million; 3722638Sstever@eecs.umich.edu usec = elapsed_usecs % one_million; 3732638Sstever@eecs.umich.edu} 3741869SN/A 3751869SN/A////////////////////////////////////////////////////////////////////// 376955SN/A// 377955SN/A// The following emulation functions are generic, but need to be 378955SN/A// templated to account for differences in types, constants, etc. 379955SN/A// 3801858SN/A////////////////////////////////////////////////////////////////////// 3811858SN/A 3821858SN/A#if NO_STAT64 3832632Sstever@eecs.umich.edu typedef struct stat hst_stat; 3842632Sstever@eecs.umich.edu typedef struct stat hst_stat64; 3852632Sstever@eecs.umich.edu#else 3862632Sstever@eecs.umich.edu typedef struct stat hst_stat; 3872632Sstever@eecs.umich.edu typedef struct stat64 hst_stat64; 3882634Sstever@eecs.umich.edu#endif 3892638Sstever@eecs.umich.edu 3902023SN/A//// Helper function to convert a host stat buffer to a target stat 3912632Sstever@eecs.umich.edu//// buffer. Also copies the target buffer out to the simulated 3922632Sstever@eecs.umich.edu//// memory space. Used by stat(), fstat(), and lstat(). 3932632Sstever@eecs.umich.edu 3942632Sstever@eecs.umich.edutemplate <typename target_stat, typename host_stat> 3952632Sstever@eecs.umich.edustatic void 3962632Sstever@eecs.umich.educonvertStatBuf(target_stat &tgt, host_stat *host, bool fakeTTY = false) 3972632Sstever@eecs.umich.edu{ 3982632Sstever@eecs.umich.edu using namespace TheISA; 3992632Sstever@eecs.umich.edu 4002632Sstever@eecs.umich.edu if (fakeTTY) 4012632Sstever@eecs.umich.edu tgt->st_dev = 0xA; 4022023SN/A else 4032632Sstever@eecs.umich.edu tgt->st_dev = host->st_dev; 4042632Sstever@eecs.umich.edu tgt->st_dev = TheISA::htog(tgt->st_dev); 4051889SN/A tgt->st_ino = host->st_ino; 4061889SN/A tgt->st_ino = TheISA::htog(tgt->st_ino); 4072632Sstever@eecs.umich.edu tgt->st_mode = host->st_mode; 4082632Sstever@eecs.umich.edu if (fakeTTY) { 4092632Sstever@eecs.umich.edu // Claim to be a character device 4102632Sstever@eecs.umich.edu tgt->st_mode &= ~S_IFMT; // Clear S_IFMT 4112632Sstever@eecs.umich.edu tgt->st_mode |= S_IFCHR; // Set S_IFCHR 4122632Sstever@eecs.umich.edu } 4132632Sstever@eecs.umich.edu tgt->st_mode = TheISA::htog(tgt->st_mode); 4142632Sstever@eecs.umich.edu tgt->st_nlink = host->st_nlink; 4152632Sstever@eecs.umich.edu tgt->st_nlink = TheISA::htog(tgt->st_nlink); 4162632Sstever@eecs.umich.edu tgt->st_uid = host->st_uid; 4172632Sstever@eecs.umich.edu tgt->st_uid = TheISA::htog(tgt->st_uid); 4182632Sstever@eecs.umich.edu tgt->st_gid = host->st_gid; 4192632Sstever@eecs.umich.edu tgt->st_gid = TheISA::htog(tgt->st_gid); 4202632Sstever@eecs.umich.edu if (fakeTTY) 4211888SN/A tgt->st_rdev = 0x880d; 4221888SN/A else 4231869SN/A tgt->st_rdev = host->st_rdev; 4241869SN/A tgt->st_rdev = TheISA::htog(tgt->st_rdev); 4251858SN/A tgt->st_size = host->st_size; 4262598SN/A tgt->st_size = TheISA::htog(tgt->st_size); 4272598SN/A tgt->st_atimeX = host->st_atime; 4282598SN/A tgt->st_atimeX = TheISA::htog(tgt->st_atimeX); 4292598SN/A tgt->st_mtimeX = host->st_mtime; 4302598SN/A tgt->st_mtimeX = TheISA::htog(tgt->st_mtimeX); 4311858SN/A tgt->st_ctimeX = host->st_ctime; 4321858SN/A tgt->st_ctimeX = TheISA::htog(tgt->st_ctimeX); 4331858SN/A // Force the block size to be 8k. This helps to ensure buffered io works 4341858SN/A // consistently across different hosts. 4351858SN/A tgt->st_blksize = 0x2000; 4361858SN/A tgt->st_blksize = TheISA::htog(tgt->st_blksize); 4371858SN/A tgt->st_blocks = host->st_blocks; 4381858SN/A tgt->st_blocks = TheISA::htog(tgt->st_blocks); 4391858SN/A} 4401871SN/A 4411858SN/A// Same for stat64 4421858SN/A 4431858SN/Atemplate <typename target_stat, typename host_stat64> 4441858SN/Astatic void 4451858SN/AconvertStat64Buf(target_stat &tgt, host_stat64 *host, bool fakeTTY = false) 4461858SN/A{ 4471858SN/A using namespace TheISA; 4481858SN/A 4491858SN/A convertStatBuf<target_stat, host_stat64>(tgt, host, fakeTTY); 4501858SN/A#if defined(STAT_HAVE_NSEC) 4511858SN/A tgt->st_atime_nsec = host->st_atime_nsec; 4521859SN/A tgt->st_atime_nsec = TheISA::htog(tgt->st_atime_nsec); 4531859SN/A tgt->st_mtime_nsec = host->st_mtime_nsec; 4541869SN/A tgt->st_mtime_nsec = TheISA::htog(tgt->st_mtime_nsec); 4551888SN/A tgt->st_ctime_nsec = host->st_ctime_nsec; 4562632Sstever@eecs.umich.edu tgt->st_ctime_nsec = TheISA::htog(tgt->st_ctime_nsec); 4571869SN/A#else 4581884SN/A tgt->st_atime_nsec = 0; 4591884SN/A tgt->st_mtime_nsec = 0; 4601884SN/A tgt->st_ctime_nsec = 0; 4611884SN/A#endif 4621884SN/A} 4631884SN/A 4641965SN/A//Here are a couple convenience functions 4651965SN/Atemplate<class OS> 4661965SN/Astatic void 467955SN/AcopyOutStatBuf(SETranslatingPortProxy &mem, Addr addr, 4681869SN/A hst_stat *host, bool fakeTTY = false) 4691869SN/A{ 4702632Sstever@eecs.umich.edu typedef TypedBufferArg<typename OS::tgt_stat> tgt_stat_buf; 4711869SN/A tgt_stat_buf tgt(addr); 4721869SN/A convertStatBuf<tgt_stat_buf, hst_stat>(tgt, host, fakeTTY); 4731869SN/A tgt.copyOut(mem); 4742632Sstever@eecs.umich.edu} 4752632Sstever@eecs.umich.edu 4762632Sstever@eecs.umich.edutemplate<class OS> 4772632Sstever@eecs.umich.edustatic void 478955SN/AcopyOutStat64Buf(SETranslatingPortProxy &mem, Addr addr, 4792598SN/A hst_stat64 *host, bool fakeTTY = false) 4802598SN/A{ 481955SN/A typedef TypedBufferArg<typename OS::tgt_stat64> tgt_stat_buf; 482955SN/A tgt_stat_buf tgt(addr); 483955SN/A convertStat64Buf<tgt_stat_buf, hst_stat64>(tgt, host, fakeTTY); 4841530SN/A tgt.copyOut(mem); 485955SN/A} 486955SN/A 487955SN/A/// Target ioctl() handler. For the most part, programs call ioctl() 488/// only to find out if their stdout is a tty, to determine whether to 489/// do line or block buffering. 490template <class OS> 491SyscallReturn 492ioctlFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 493 ThreadContext *tc) 494{ 495 int index = 0; 496 int fd = process->getSyscallArg(tc, index); 497 unsigned req = process->getSyscallArg(tc, index); 498 499 DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", fd, req); 500 501 if (fd < 0 || process->sim_fd(fd) < 0) { 502 // doesn't map to any simulator fd: not a valid target fd 503 return -EBADF; 504 } 505 506 switch (req) { 507 case OS::TIOCISATTY_: 508 case OS::TIOCGETP_: 509 case OS::TIOCSETP_: 510 case OS::TIOCSETN_: 511 case OS::TIOCSETC_: 512 case OS::TIOCGETC_: 513 case OS::TIOCGETS_: 514 case OS::TIOCGETA_: 515 case OS::TCSETAW_: 516 return -ENOTTY; 517 518 default: 519 fatal("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ \n", 520 fd, req, tc->pcState()); 521 } 522} 523 524/// Target open() handler. 525template <class OS> 526SyscallReturn 527openFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 528 ThreadContext *tc) 529{ 530 std::string path; 531 532 int index = 0; 533 if (!tc->getMemProxy().tryReadString(path, 534 process->getSyscallArg(tc, index))) 535 return -EFAULT; 536 537 if (path == "/dev/sysdev0") { 538 // This is a memory-mapped high-resolution timer device on Alpha. 539 // We don't support it, so just punt. 540 warn("Ignoring open(%s, ...)\n", path); 541 return -ENOENT; 542 } 543 544 int tgtFlags = process->getSyscallArg(tc, index); 545 int mode = process->getSyscallArg(tc, index); 546 int hostFlags = 0; 547 548 // translate open flags 549 for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) { 550 if (tgtFlags & OS::openFlagTable[i].tgtFlag) { 551 tgtFlags &= ~OS::openFlagTable[i].tgtFlag; 552 hostFlags |= OS::openFlagTable[i].hostFlag; 553 } 554 } 555 556 // any target flags left? 557 if (tgtFlags != 0) 558 warn("Syscall: open: cannot decode flags 0x%x", tgtFlags); 559 560#ifdef __CYGWIN32__ 561 hostFlags |= O_BINARY; 562#endif 563 564 // Adjust path for current working directory 565 path = process->fullPath(path); 566 567 DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str()); 568 569 int fd; 570 if (!path.compare(0, 6, "/proc/") || !path.compare(0, 8, "/system/") || 571 !path.compare(0, 10, "/platform/") || !path.compare(0, 5, "/sys/")) { 572 // It's a proc/sys entery and requires special handling 573 fd = OS::openSpecialFile(path, process, tc); 574 return (fd == -1) ? -1 : process->alloc_fd(fd,path.c_str(),hostFlags,mode, false); 575 } else { 576 // open the file 577 fd = open(path.c_str(), hostFlags, mode); 578 return (fd == -1) ? -errno : process->alloc_fd(fd,path.c_str(),hostFlags,mode, false); 579 } 580 581} 582 583/// Target sysinfo() handler. 584template <class OS> 585SyscallReturn 586sysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 587 ThreadContext *tc) 588{ 589 590 int index = 0; 591 TypedBufferArg<typename OS::tgt_sysinfo> 592 sysinfo(process->getSyscallArg(tc, index)); 593 594 sysinfo->uptime=seconds_since_epoch; 595 sysinfo->totalram=process->system->memSize(); 596 597 sysinfo.copyOut(tc->getMemProxy()); 598 599 return 0; 600} 601 602/// Target chmod() handler. 603template <class OS> 604SyscallReturn 605chmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 606 ThreadContext *tc) 607{ 608 std::string path; 609 610 int index = 0; 611 if (!tc->getMemProxy().tryReadString(path, 612 process->getSyscallArg(tc, index))) { 613 return -EFAULT; 614 } 615 616 uint32_t mode = process->getSyscallArg(tc, index); 617 mode_t hostMode = 0; 618 619 // XXX translate mode flags via OS::something??? 620 hostMode = mode; 621 622 // Adjust path for current working directory 623 path = process->fullPath(path); 624 625 // do the chmod 626 int result = chmod(path.c_str(), hostMode); 627 if (result < 0) 628 return -errno; 629 630 return 0; 631} 632 633 634/// Target fchmod() handler. 635template <class OS> 636SyscallReturn 637fchmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 638 ThreadContext *tc) 639{ 640 int index = 0; 641 int fd = process->getSyscallArg(tc, index); 642 if (fd < 0 || process->sim_fd(fd) < 0) { 643 // doesn't map to any simulator fd: not a valid target fd 644 return -EBADF; 645 } 646 647 uint32_t mode = process->getSyscallArg(tc, index); 648 mode_t hostMode = 0; 649 650 // XXX translate mode flags via OS::someting??? 651 hostMode = mode; 652 653 // do the fchmod 654 int result = fchmod(process->sim_fd(fd), hostMode); 655 if (result < 0) 656 return -errno; 657 658 return 0; 659} 660 661/// Target mremap() handler. 662template <class OS> 663SyscallReturn 664mremapFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) 665{ 666 int index = 0; 667 Addr start = process->getSyscallArg(tc, index); 668 uint64_t old_length = process->getSyscallArg(tc, index); 669 uint64_t new_length = process->getSyscallArg(tc, index); 670 uint64_t flags = process->getSyscallArg(tc, index); 671 672 if ((start % TheISA::VMPageSize != 0) || 673 (new_length % TheISA::VMPageSize != 0)) { 674 warn("mremap failing: arguments not page aligned"); 675 return -EINVAL; 676 } 677 678 if (new_length > old_length) { 679 if ((start + old_length) == process->mmap_end) { 680 uint64_t diff = new_length - old_length; 681 process->allocateMem(process->mmap_end, diff); 682 process->mmap_end += diff; 683 return start; 684 } else { 685 // sys/mman.h defined MREMAP_MAYMOVE 686 if (!(flags & 1)) { 687 warn("can't remap here and MREMAP_MAYMOVE flag not set\n"); 688 return -ENOMEM; 689 } else { 690 process->pTable->remap(start, old_length, process->mmap_end); 691 warn("mremapping to totally new vaddr %08p-%08p, adding %d\n", 692 process->mmap_end, process->mmap_end + new_length, new_length); 693 start = process->mmap_end; 694 // add on the remaining unallocated pages 695 process->allocateMem(start + old_length, 696 new_length - old_length); 697 process->mmap_end += new_length; 698 warn("returning %08p as start\n", start); 699 return start; 700 } 701 } 702 } else { 703 process->pTable->unmap(start + new_length, old_length - new_length); 704 return start; 705 } 706} 707 708/// Target stat() handler. 709template <class OS> 710SyscallReturn 711statFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 712 ThreadContext *tc) 713{ 714 std::string path; 715 716 int index = 0; 717 if (!tc->getMemProxy().tryReadString(path, 718 process->getSyscallArg(tc, index))) { 719 return -EFAULT; 720 } 721 Addr bufPtr = process->getSyscallArg(tc, index); 722 723 // Adjust path for current working directory 724 path = process->fullPath(path); 725 726 struct stat hostBuf; 727 int result = stat(path.c_str(), &hostBuf); 728 729 if (result < 0) 730 return -errno; 731 732 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 733 734 return 0; 735} 736 737 738/// Target stat64() handler. 739template <class OS> 740SyscallReturn 741stat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 742 ThreadContext *tc) 743{ 744 std::string path; 745 746 int index = 0; 747 if (!tc->getMemProxy().tryReadString(path, 748 process->getSyscallArg(tc, index))) 749 return -EFAULT; 750 Addr bufPtr = process->getSyscallArg(tc, index); 751 752 // Adjust path for current working directory 753 path = process->fullPath(path); 754 755#if NO_STAT64 756 struct stat hostBuf; 757 int result = stat(path.c_str(), &hostBuf); 758#else 759 struct stat64 hostBuf; 760 int result = stat64(path.c_str(), &hostBuf); 761#endif 762 763 if (result < 0) 764 return -errno; 765 766 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 767 768 return 0; 769} 770 771 772/// Target fstat64() handler. 773template <class OS> 774SyscallReturn 775fstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 776 ThreadContext *tc) 777{ 778 int index = 0; 779 int fd = process->getSyscallArg(tc, index); 780 Addr bufPtr = process->getSyscallArg(tc, index); 781 if (fd < 0 || process->sim_fd(fd) < 0) { 782 // doesn't map to any simulator fd: not a valid target fd 783 return -EBADF; 784 } 785 786#if NO_STAT64 787 struct stat hostBuf; 788 int result = fstat(process->sim_fd(fd), &hostBuf); 789#else 790 struct stat64 hostBuf; 791 int result = fstat64(process->sim_fd(fd), &hostBuf); 792#endif 793 794 if (result < 0) 795 return -errno; 796 797 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (fd == 1)); 798 799 return 0; 800} 801 802 803/// Target lstat() handler. 804template <class OS> 805SyscallReturn 806lstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 807 ThreadContext *tc) 808{ 809 std::string path; 810 811 int index = 0; 812 if (!tc->getMemProxy().tryReadString(path, 813 process->getSyscallArg(tc, index))) { 814 return -EFAULT; 815 } 816 Addr bufPtr = process->getSyscallArg(tc, index); 817 818 // Adjust path for current working directory 819 path = process->fullPath(path); 820 821 struct stat hostBuf; 822 int result = lstat(path.c_str(), &hostBuf); 823 824 if (result < 0) 825 return -errno; 826 827 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 828 829 return 0; 830} 831 832/// Target lstat64() handler. 833template <class OS> 834SyscallReturn 835lstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 836 ThreadContext *tc) 837{ 838 std::string path; 839 840 int index = 0; 841 if (!tc->getMemProxy().tryReadString(path, 842 process->getSyscallArg(tc, index))) { 843 return -EFAULT; 844 } 845 Addr bufPtr = process->getSyscallArg(tc, index); 846 847 // Adjust path for current working directory 848 path = process->fullPath(path); 849 850#if NO_STAT64 851 struct stat hostBuf; 852 int result = lstat(path.c_str(), &hostBuf); 853#else 854 struct stat64 hostBuf; 855 int result = lstat64(path.c_str(), &hostBuf); 856#endif 857 858 if (result < 0) 859 return -errno; 860 861 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 862 863 return 0; 864} 865 866/// Target fstat() handler. 867template <class OS> 868SyscallReturn 869fstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 870 ThreadContext *tc) 871{ 872 int index = 0; 873 int fd = process->sim_fd(process->getSyscallArg(tc, index)); 874 Addr bufPtr = process->getSyscallArg(tc, index); 875 876 DPRINTF(SyscallVerbose, "fstat(%d, ...)\n", fd); 877 878 if (fd < 0) 879 return -EBADF; 880 881 struct stat hostBuf; 882 int result = fstat(fd, &hostBuf); 883 884 if (result < 0) 885 return -errno; 886 887 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (fd == 1)); 888 889 return 0; 890} 891 892 893/// Target statfs() handler. 894template <class OS> 895SyscallReturn 896statfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 897 ThreadContext *tc) 898{ 899 std::string path; 900 901 int index = 0; 902 if (!tc->getMemProxy().tryReadString(path, 903 process->getSyscallArg(tc, index))) { 904 return -EFAULT; 905 } 906 Addr bufPtr = process->getSyscallArg(tc, index); 907 908 // Adjust path for current working directory 909 path = process->fullPath(path); 910 911 struct statfs hostBuf; 912 int result = statfs(path.c_str(), &hostBuf); 913 914 if (result < 0) 915 return -errno; 916 917 OS::copyOutStatfsBuf(tc->getMemProxy(), bufPtr, &hostBuf); 918 919 return 0; 920} 921 922 923/// Target fstatfs() handler. 924template <class OS> 925SyscallReturn 926fstatfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 927 ThreadContext *tc) 928{ 929 int index = 0; 930 int fd = process->sim_fd(process->getSyscallArg(tc, index)); 931 Addr bufPtr = process->getSyscallArg(tc, index); 932 933 if (fd < 0) 934 return -EBADF; 935 936 struct statfs hostBuf; 937 int result = fstatfs(fd, &hostBuf); 938 939 if (result < 0) 940 return -errno; 941 942 OS::copyOutStatfsBuf(tc->getMemProxy(), bufPtr, &hostBuf); 943 944 return 0; 945} 946 947 948/// Target writev() handler. 949template <class OS> 950SyscallReturn 951writevFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 952 ThreadContext *tc) 953{ 954 int index = 0; 955 int fd = process->getSyscallArg(tc, index); 956 if (fd < 0 || process->sim_fd(fd) < 0) { 957 // doesn't map to any simulator fd: not a valid target fd 958 return -EBADF; 959 } 960 961 SETranslatingPortProxy &p = tc->getMemProxy(); 962 uint64_t tiov_base = process->getSyscallArg(tc, index); 963 size_t count = process->getSyscallArg(tc, index); 964 struct iovec hiov[count]; 965 for (size_t i = 0; i < count; ++i) { 966 typename OS::tgt_iovec tiov; 967 968 p.readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec), 969 (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec)); 970 hiov[i].iov_len = TheISA::gtoh(tiov.iov_len); 971 hiov[i].iov_base = new char [hiov[i].iov_len]; 972 p.readBlob(TheISA::gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base, 973 hiov[i].iov_len); 974 } 975 976 int result = writev(process->sim_fd(fd), hiov, count); 977 978 for (size_t i = 0; i < count; ++i) 979 delete [] (char *)hiov[i].iov_base; 980 981 if (result < 0) 982 return -errno; 983 984 return 0; 985} 986 987 988/// Target mmap() handler. 989/// 990/// We don't really handle mmap(). If the target is mmaping an 991/// anonymous region or /dev/zero, we can get away with doing basically 992/// nothing (since memory is initialized to zero and the simulator 993/// doesn't really check addresses anyway). 994/// 995template <class OS> 996SyscallReturn 997mmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 998{ 999 int index = 0; 1000 Addr start = p->getSyscallArg(tc, index); 1001 uint64_t length = p->getSyscallArg(tc, index); 1002 index++; // int prot = p->getSyscallArg(tc, index); 1003 int flags = p->getSyscallArg(tc, index); 1004 int tgt_fd = p->getSyscallArg(tc, index); 1005 // int offset = p->getSyscallArg(tc, index); 1006 1007 if (!(flags & OS::TGT_MAP_ANONYMOUS)) { 1008 Process::FdMap *fd_map = p->sim_fd_obj(tgt_fd); 1009 if (!fd_map || fd_map->fd < 0) { 1010 warn("mmap failing: target fd %d is not valid\n", tgt_fd); 1011 return -EBADF; 1012 } 1013 1014 if (fd_map->filename != "/dev/zero") { 1015 // This is very likely broken, but leave a warning here 1016 // (rather than panic) in case /dev/zero is known by 1017 // another name on some platform 1018 warn("allowing mmap of file %s; mmap not supported on files" 1019 " other than /dev/zero\n", fd_map->filename); 1020 } 1021 } 1022 1023 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