syscall_emul.hh revision 9008
12221SN/A/* 22221SN/A * Copyright (c) 2003-2005 The Regents of The University of Michigan 32221SN/A * All rights reserved. 42221SN/A * 52221SN/A * Redistribution and use in source and binary forms, with or without 62221SN/A * modification, are permitted provided that the following conditions are 72221SN/A * met: redistributions of source code must retain the above copyright 82221SN/A * notice, this list of conditions and the following disclaimer; 92221SN/A * redistributions in binary form must reproduce the above copyright 102221SN/A * notice, this list of conditions and the following disclaimer in the 112221SN/A * documentation and/or other materials provided with the distribution; 122221SN/A * neither the name of the copyright holders nor the names of its 132221SN/A * contributors may be used to endorse or promote products derived from 142221SN/A * this software without specific prior written permission. 152221SN/A * 162221SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172221SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182221SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192221SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202221SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212221SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222221SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232221SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242221SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252221SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262221SN/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 302221SN/A */ 312221SN/A 323415Sgblack@eecs.umich.edu#ifndef __SIM_SYSCALL_EMUL_HH__ 333415Sgblack@eecs.umich.edu#define __SIM_SYSCALL_EMUL_HH__ 342223SN/A 353415Sgblack@eecs.umich.edu#define NO_STAT64 (defined(__APPLE__) || defined(__OpenBSD__) || \ 363578Sgblack@eecs.umich.edu defined(__FreeBSD__) || defined(__CYGWIN__)) 373415Sgblack@eecs.umich.edu 383415Sgblack@eecs.umich.edu/// 393523Sgblack@eecs.umich.edu/// @file syscall_emul.hh 403415Sgblack@eecs.umich.edu/// 412680Sktlim@umich.edu/// This file defines objects used to emulate syscalls from the target 422800Ssaidi@eecs.umich.edu/// application on the host machine. 433523Sgblack@eecs.umich.edu 443415Sgblack@eecs.umich.edu#ifdef __CYGWIN32__ 452800Ssaidi@eecs.umich.edu#include <sys/fcntl.h> // for O_BINARY 462800Ssaidi@eecs.umich.edu#endif 472221SN/A#include <sys/stat.h> 483415Sgblack@eecs.umich.edu#include <sys/time.h> 493415Sgblack@eecs.umich.edu#include <sys/uio.h> 502223SN/A#include <fcntl.h> 512221SN/A 522221SN/A#include <cerrno> 533573Sgblack@eecs.umich.edu#include <string> 543576Sgblack@eecs.umich.edu 553576Sgblack@eecs.umich.edu#include "base/chunk_generator.hh" 562221SN/A#include "base/intmath.hh" // for RoundUp 573573Sgblack@eecs.umich.edu#include "base/misc.hh" 583576Sgblack@eecs.umich.edu#include "base/trace.hh" 593576Sgblack@eecs.umich.edu#include "base/types.hh" 602221SN/A#include "config/the_isa.hh" 613573Sgblack@eecs.umich.edu#include "cpu/base.hh" 623576Sgblack@eecs.umich.edu#include "cpu/thread_context.hh" 633576Sgblack@eecs.umich.edu#include "debug/SyscallVerbose.hh" 642221SN/A#include "mem/page_table.hh" 653573Sgblack@eecs.umich.edu#include "mem/se_translating_port_proxy.hh" 663576Sgblack@eecs.umich.edu#include "sim/byteswap.hh" 673576Sgblack@eecs.umich.edu#include "sim/process.hh" 682221SN/A#include "sim/syscallreturn.hh" 693573Sgblack@eecs.umich.edu#include "sim/system.hh" 703576Sgblack@eecs.umich.edu 713576Sgblack@eecs.umich.edu/// 722221SN/A/// System call descriptor. 733573Sgblack@eecs.umich.edu/// 743576Sgblack@eecs.umich.educlass SyscallDesc { 753576Sgblack@eecs.umich.edu 762221SN/A public: 773573Sgblack@eecs.umich.edu 783576Sgblack@eecs.umich.edu /// Typedef for target syscall handler functions. 793576Sgblack@eecs.umich.edu typedef SyscallReturn (*FuncPtr)(SyscallDesc *, int num, 803576Sgblack@eecs.umich.edu LiveProcess *, ThreadContext *); 813576Sgblack@eecs.umich.edu 823576Sgblack@eecs.umich.edu const char *name; //!< Syscall name (e.g., "open"). 833576Sgblack@eecs.umich.edu FuncPtr funcPtr; //!< Pointer to emulation function. 843576Sgblack@eecs.umich.edu int flags; //!< Flags (see Flags enum). 852221SN/A 863573Sgblack@eecs.umich.edu /// Flag values for controlling syscall behavior. 873576Sgblack@eecs.umich.edu enum Flags { 883576Sgblack@eecs.umich.edu /// Don't set return regs according to funcPtr return value. 892221SN/A /// Used for syscalls with non-standard return conventions 903573Sgblack@eecs.umich.edu /// that explicitly set the ThreadContext regs (e.g., 913576Sgblack@eecs.umich.edu /// sigreturn). 923576Sgblack@eecs.umich.edu SuppressReturnValue = 1 932221SN/A }; 943573Sgblack@eecs.umich.edu 953576Sgblack@eecs.umich.edu /// Constructor. 963576Sgblack@eecs.umich.edu SyscallDesc(const char *_name, FuncPtr _funcPtr, int _flags = 0) 973576Sgblack@eecs.umich.edu : name(_name), funcPtr(_funcPtr), flags(_flags) 983576Sgblack@eecs.umich.edu { 993576Sgblack@eecs.umich.edu } 1003576Sgblack@eecs.umich.edu 1013576Sgblack@eecs.umich.edu /// Emulate the syscall. Public interface for calling through funcPtr. 1023576Sgblack@eecs.umich.edu void doSyscall(int callnum, LiveProcess *proc, ThreadContext *tc); 1033576Sgblack@eecs.umich.edu}; 1043576Sgblack@eecs.umich.edu 1053576Sgblack@eecs.umich.edu 1063576Sgblack@eecs.umich.educlass BaseBufferArg { 1072221SN/A 1083573Sgblack@eecs.umich.edu public: 1093576Sgblack@eecs.umich.edu 1103576Sgblack@eecs.umich.edu BaseBufferArg(Addr _addr, int _size) : addr(_addr), size(_size) 1112221SN/A { 1123573Sgblack@eecs.umich.edu bufPtr = new uint8_t[size]; 1133576Sgblack@eecs.umich.edu // clear out buffer: in case we only partially populate this, 1143576Sgblack@eecs.umich.edu // and then do a copyOut(), we want to make sure we don't 1152221SN/A // introduce any random junk into the simulated address space 1163573Sgblack@eecs.umich.edu memset(bufPtr, 0, size); 1173576Sgblack@eecs.umich.edu } 1183576Sgblack@eecs.umich.edu 1192221SN/A virtual ~BaseBufferArg() { delete [] bufPtr; } 1203573Sgblack@eecs.umich.edu 1213576Sgblack@eecs.umich.edu // 1223576Sgblack@eecs.umich.edu // copy data into simulator space (read from target memory) 1232221SN/A // 1243573Sgblack@eecs.umich.edu virtual bool copyIn(SETranslatingPortProxy &memproxy) 1253576Sgblack@eecs.umich.edu { 1263576Sgblack@eecs.umich.edu memproxy.readBlob(addr, bufPtr, size); 1272221SN/A return true; // no EFAULT detection for now 1283573Sgblack@eecs.umich.edu } 1293576Sgblack@eecs.umich.edu 1303576Sgblack@eecs.umich.edu // 1312223SN/A // copy data out of simulator space (write to target memory) 1323573Sgblack@eecs.umich.edu // 1333576Sgblack@eecs.umich.edu virtual bool copyOut(SETranslatingPortProxy &memproxy) 1343576Sgblack@eecs.umich.edu { 1352223SN/A memproxy.writeBlob(addr, bufPtr, size); 1363573Sgblack@eecs.umich.edu return true; // no EFAULT detection for now 1373576Sgblack@eecs.umich.edu } 1383576Sgblack@eecs.umich.edu 1392223SN/A protected: 1403573Sgblack@eecs.umich.edu Addr addr; 1413576Sgblack@eecs.umich.edu int size; 1423576Sgblack@eecs.umich.edu uint8_t *bufPtr; 1432223SN/A}; 1443573Sgblack@eecs.umich.edu 1453576Sgblack@eecs.umich.edu 1463576Sgblack@eecs.umich.educlass BufferArg : public BaseBufferArg 1473576Sgblack@eecs.umich.edu{ 1483576Sgblack@eecs.umich.edu public: 1493576Sgblack@eecs.umich.edu BufferArg(Addr _addr, int _size) : BaseBufferArg(_addr, _size) { } 1503576Sgblack@eecs.umich.edu void *bufferPtr() { return bufPtr; } 1513576Sgblack@eecs.umich.edu}; 1522223SN/A 1533573Sgblack@eecs.umich.edutemplate <class T> 1543576Sgblack@eecs.umich.educlass TypedBufferArg : public BaseBufferArg 1553576Sgblack@eecs.umich.edu{ 1562223SN/A public: 1573573Sgblack@eecs.umich.edu // user can optionally specify a specific number of bytes to 1583576Sgblack@eecs.umich.edu // allocate to deal with those structs that have variable-size 1593576Sgblack@eecs.umich.edu // arrays at the end 1602223SN/A TypedBufferArg(Addr _addr, int _size = sizeof(T)) 1613573Sgblack@eecs.umich.edu : BaseBufferArg(_addr, _size) 1623576Sgblack@eecs.umich.edu { } 1633576Sgblack@eecs.umich.edu 1642223SN/A // type case 1653573Sgblack@eecs.umich.edu operator T*() { return (T *)bufPtr; } 1663576Sgblack@eecs.umich.edu 1673576Sgblack@eecs.umich.edu // dereference operators 1682223SN/A T &operator*() { return *((T *)bufPtr); } 1693573Sgblack@eecs.umich.edu T* operator->() { return (T *)bufPtr; } 1703576Sgblack@eecs.umich.edu T &operator[](int i) { return ((T *)bufPtr)[i]; } 1713576Sgblack@eecs.umich.edu}; 1722223SN/A 1733573Sgblack@eecs.umich.edu////////////////////////////////////////////////////////////////////// 1743576Sgblack@eecs.umich.edu// 1753576Sgblack@eecs.umich.edu// The following emulation functions are generic enough that they 1762223SN/A// don't need to be recompiled for different emulated OS's. They are 1773573Sgblack@eecs.umich.edu// defined in sim/syscall_emul.cc. 1783576Sgblack@eecs.umich.edu// 1793576Sgblack@eecs.umich.edu////////////////////////////////////////////////////////////////////// 1802223SN/A 1813573Sgblack@eecs.umich.edu 1823576Sgblack@eecs.umich.edu/// Handler for unimplemented syscalls that we haven't thought about. 1833576Sgblack@eecs.umich.eduSyscallReturn unimplementedFunc(SyscallDesc *desc, int num, 1842223SN/A LiveProcess *p, ThreadContext *tc); 1853573Sgblack@eecs.umich.edu 1863576Sgblack@eecs.umich.edu/// Handler for unimplemented syscalls that we never intend to 1873576Sgblack@eecs.umich.edu/// implement (signal handling, etc.) and should not affect the correct 1882223SN/A/// behavior of the program. Print a warning only if the appropriate 1893573Sgblack@eecs.umich.edu/// trace flag is enabled. Return success to the target program. 1903576Sgblack@eecs.umich.eduSyscallReturn ignoreFunc(SyscallDesc *desc, int num, 1913576Sgblack@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 1922223SN/ASyscallReturn ignoreWarnOnceFunc(SyscallDesc *desc, int num, 1933576Sgblack@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 1943576Sgblack@eecs.umich.edu 1953576Sgblack@eecs.umich.edu/// Target exit() handler: terminate current context. 1963576Sgblack@eecs.umich.eduSyscallReturn exitFunc(SyscallDesc *desc, int num, 1972527SN/A LiveProcess *p, ThreadContext *tc); 1983573Sgblack@eecs.umich.edu 1993576Sgblack@eecs.umich.edu/// Target exit_group() handler: terminate simulation. (exit all threads) 2003890Ssaidi@eecs.umich.eduSyscallReturn exitGroupFunc(SyscallDesc *desc, int num, 2012223SN/A LiveProcess *p, ThreadContext *tc); 2023573Sgblack@eecs.umich.edu 2033576Sgblack@eecs.umich.edu/// Target getpagesize() handler. 2043576Sgblack@eecs.umich.eduSyscallReturn getpagesizeFunc(SyscallDesc *desc, int num, 2052223SN/A LiveProcess *p, ThreadContext *tc); 2063573Sgblack@eecs.umich.edu 2073576Sgblack@eecs.umich.edu/// Target brk() handler: set brk address. 2083576Sgblack@eecs.umich.eduSyscallReturn brkFunc(SyscallDesc *desc, int num, 2092223SN/A LiveProcess *p, ThreadContext *tc); 2103573Sgblack@eecs.umich.edu 2114103Ssaidi@eecs.umich.edu/// Target close() handler. 2124103Ssaidi@eecs.umich.eduSyscallReturn closeFunc(SyscallDesc *desc, int num, 2134103Ssaidi@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 2144103Ssaidi@eecs.umich.edu 2153576Sgblack@eecs.umich.edu/// Target read() handler. 2163576Sgblack@eecs.umich.eduSyscallReturn readFunc(SyscallDesc *desc, int num, 2172223SN/A LiveProcess *p, ThreadContext *tc); 2183573Sgblack@eecs.umich.edu 2193576Sgblack@eecs.umich.edu/// Target write() handler. 2203576Sgblack@eecs.umich.eduSyscallReturn writeFunc(SyscallDesc *desc, int num, 2212223SN/A LiveProcess *p, ThreadContext *tc); 2223573Sgblack@eecs.umich.edu 2233576Sgblack@eecs.umich.edu/// Target lseek() handler. 2243576Sgblack@eecs.umich.eduSyscallReturn lseekFunc(SyscallDesc *desc, int num, 2253576Sgblack@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 2263576Sgblack@eecs.umich.edu 2273576Sgblack@eecs.umich.edu/// Target _llseek() handler. 2283576Sgblack@eecs.umich.eduSyscallReturn _llseekFunc(SyscallDesc *desc, int num, 2293576Sgblack@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 2303576Sgblack@eecs.umich.edu 2313576Sgblack@eecs.umich.edu/// Target munmap() handler. 2323576Sgblack@eecs.umich.eduSyscallReturn munmapFunc(SyscallDesc *desc, int num, 2333576Sgblack@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 2343576Sgblack@eecs.umich.edu 2353576Sgblack@eecs.umich.edu/// Target gethostname() handler. 2363576Sgblack@eecs.umich.eduSyscallReturn gethostnameFunc(SyscallDesc *desc, int num, 2373576Sgblack@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 2383576Sgblack@eecs.umich.edu 2393576Sgblack@eecs.umich.edu/// Target getcwd() handler. 2403576Sgblack@eecs.umich.eduSyscallReturn getcwdFunc(SyscallDesc *desc, int num, 2413576Sgblack@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 2423576Sgblack@eecs.umich.edu 2433576Sgblack@eecs.umich.edu/// Target unlink() handler. 2443576Sgblack@eecs.umich.eduSyscallReturn readlinkFunc(SyscallDesc *desc, int num, 2453576Sgblack@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 2463576Sgblack@eecs.umich.edu 2473893Shsul@eecs.umich.edu/// Target unlink() handler. 2483576Sgblack@eecs.umich.eduSyscallReturn unlinkFunc(SyscallDesc *desc, int num, 2493576Sgblack@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 2503576Sgblack@eecs.umich.edu 2513576Sgblack@eecs.umich.edu/// Target mkdir() handler. 2523576Sgblack@eecs.umich.eduSyscallReturn mkdirFunc(SyscallDesc *desc, int num, 2533576Sgblack@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 2543576Sgblack@eecs.umich.edu 2553576Sgblack@eecs.umich.edu/// Target rename() handler. 2563576Sgblack@eecs.umich.eduSyscallReturn renameFunc(SyscallDesc *desc, int num, 2573576Sgblack@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 2583576Sgblack@eecs.umich.edu 2593576Sgblack@eecs.umich.edu 2603576Sgblack@eecs.umich.edu/// Target truncate() handler. 2613576Sgblack@eecs.umich.eduSyscallReturn truncateFunc(SyscallDesc *desc, int num, 2623576Sgblack@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 2633576Sgblack@eecs.umich.edu 2643576Sgblack@eecs.umich.edu 2653576Sgblack@eecs.umich.edu/// Target ftruncate() handler. 2663576Sgblack@eecs.umich.eduSyscallReturn ftruncateFunc(SyscallDesc *desc, int num, 2673576Sgblack@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 2683576Sgblack@eecs.umich.edu 2692223SN/A 2702800Ssaidi@eecs.umich.edu/// Target truncate64() handler. 2713573Sgblack@eecs.umich.eduSyscallReturn truncate64Func(SyscallDesc *desc, int num, 2723576Sgblack@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 2733576Sgblack@eecs.umich.edu 2742800Ssaidi@eecs.umich.edu/// Target ftruncate64() handler. 2752800Ssaidi@eecs.umich.eduSyscallReturn ftruncate64Func(SyscallDesc *desc, int num, 2763415Sgblack@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 2773578Sgblack@eecs.umich.edu 2783578Sgblack@eecs.umich.edu 2793415Sgblack@eecs.umich.edu/// Target umask() handler. 2803415Sgblack@eecs.umich.eduSyscallReturn umaskFunc(SyscallDesc *desc, int num, 2813578Sgblack@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 2823415Sgblack@eecs.umich.edu 2833578Sgblack@eecs.umich.edu 2843578Sgblack@eecs.umich.edu/// Target chown() handler. 2853578Sgblack@eecs.umich.eduSyscallReturn chownFunc(SyscallDesc *desc, int num, 2863578Sgblack@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 2873578Sgblack@eecs.umich.edu 2883578Sgblack@eecs.umich.edu 2893578Sgblack@eecs.umich.edu/// Target fchown() handler. 2903595Sgblack@eecs.umich.eduSyscallReturn fchownFunc(SyscallDesc *desc, int num, 2913746Sgblack@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 2923746Sgblack@eecs.umich.edu 2933746Sgblack@eecs.umich.edu/// Target dup() handler. 2943746Sgblack@eecs.umich.eduSyscallReturn dupFunc(SyscallDesc *desc, int num, 2953746Sgblack@eecs.umich.edu LiveProcess *process, ThreadContext *tc); 2963578Sgblack@eecs.umich.edu 2973578Sgblack@eecs.umich.edu/// Target fnctl() handler. 2983578Sgblack@eecs.umich.eduSyscallReturn fcntlFunc(SyscallDesc *desc, int num, 2993578Sgblack@eecs.umich.edu LiveProcess *process, ThreadContext *tc); 3003578Sgblack@eecs.umich.edu 3013578Sgblack@eecs.umich.edu/// Target fcntl64() handler. 3023578Sgblack@eecs.umich.eduSyscallReturn fcntl64Func(SyscallDesc *desc, int num, 3033578Sgblack@eecs.umich.edu LiveProcess *process, ThreadContext *tc); 3043578Sgblack@eecs.umich.edu 3053578Sgblack@eecs.umich.edu/// Target setuid() handler. 3063578Sgblack@eecs.umich.eduSyscallReturn setuidFunc(SyscallDesc *desc, int num, 3073578Sgblack@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 3083578Sgblack@eecs.umich.edu 3093761Sgblack@eecs.umich.edu/// Target getpid() handler. 3103761Sgblack@eecs.umich.eduSyscallReturn getpidFunc(SyscallDesc *desc, int num, 3113578Sgblack@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 3123578Sgblack@eecs.umich.edu 3133761Sgblack@eecs.umich.edu/// Target getuid() handler. 3143761Sgblack@eecs.umich.eduSyscallReturn getuidFunc(SyscallDesc *desc, int num, 3153578Sgblack@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 3163578Sgblack@eecs.umich.edu 3173578Sgblack@eecs.umich.edu/// Target getgid() handler. 3183578Sgblack@eecs.umich.eduSyscallReturn getgidFunc(SyscallDesc *desc, int num, 3193578Sgblack@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 3203578Sgblack@eecs.umich.edu 3213928Ssaidi@eecs.umich.edu/// Target getppid() handler. 3223928Ssaidi@eecs.umich.eduSyscallReturn getppidFunc(SyscallDesc *desc, int num, 3233928Ssaidi@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 3243928Ssaidi@eecs.umich.edu 3253928Ssaidi@eecs.umich.edu/// Target geteuid() handler. 3263578Sgblack@eecs.umich.eduSyscallReturn geteuidFunc(SyscallDesc *desc, int num, 3273578Sgblack@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 3283578Sgblack@eecs.umich.edu 3293578Sgblack@eecs.umich.edu/// Target getegid() handler. 3303578Sgblack@eecs.umich.eduSyscallReturn getegidFunc(SyscallDesc *desc, int num, 3313578Sgblack@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 3323578Sgblack@eecs.umich.edu 3333578Sgblack@eecs.umich.edu/// Target clone() handler. 3343578Sgblack@eecs.umich.eduSyscallReturn cloneFunc(SyscallDesc *desc, int num, 3353578Sgblack@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 3363578Sgblack@eecs.umich.edu 3373578Sgblack@eecs.umich.edu 3383578Sgblack@eecs.umich.edu/// Pseudo Funcs - These functions use a different return convension, 3393578Sgblack@eecs.umich.edu/// returning a second value in a register other than the normal return register 3403578Sgblack@eecs.umich.eduSyscallReturn pipePseudoFunc(SyscallDesc *desc, int num, 3413578Sgblack@eecs.umich.edu LiveProcess *process, ThreadContext *tc); 3423578Sgblack@eecs.umich.edu 3433578Sgblack@eecs.umich.edu/// Target getpidPseudo() handler. 3443578Sgblack@eecs.umich.eduSyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num, 3453578Sgblack@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 3463578Sgblack@eecs.umich.edu 3473578Sgblack@eecs.umich.edu/// Target getuidPseudo() handler. 3483578Sgblack@eecs.umich.eduSyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num, 3493578Sgblack@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 3503578Sgblack@eecs.umich.edu 3513578Sgblack@eecs.umich.edu/// Target getgidPseudo() handler. 3523578Sgblack@eecs.umich.eduSyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num, 3533578Sgblack@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 3543926Ssaidi@eecs.umich.edu 3553926Ssaidi@eecs.umich.edu 3563578Sgblack@eecs.umich.edu/// A readable name for 1,000,000, for converting microseconds to seconds. 3573578Sgblack@eecs.umich.educonst int one_million = 1000000; 3583578Sgblack@eecs.umich.edu 3593578Sgblack@eecs.umich.edu/// Approximate seconds since the epoch (1/1/1970). About a billion, 3603578Sgblack@eecs.umich.edu/// by my reckoning. We want to keep this a constant (not use the 3613578Sgblack@eecs.umich.edu/// real-world time) to keep simulations repeatable. 3623578Sgblack@eecs.umich.educonst unsigned seconds_since_epoch = 1000000000; 3633578Sgblack@eecs.umich.edu 3643578Sgblack@eecs.umich.edu/// Helper function to convert current elapsed time to seconds and 3653578Sgblack@eecs.umich.edu/// microseconds. 3663578Sgblack@eecs.umich.edutemplate <class T1, class T2> 3673578Sgblack@eecs.umich.eduvoid 3683578Sgblack@eecs.umich.edugetElapsedTime(T1 &sec, T2 &usec) 3693578Sgblack@eecs.umich.edu{ 3703578Sgblack@eecs.umich.edu int elapsed_usecs = curTick() / SimClock::Int::us; 3713578Sgblack@eecs.umich.edu sec = elapsed_usecs / one_million; 3723578Sgblack@eecs.umich.edu usec = elapsed_usecs % one_million; 3733578Sgblack@eecs.umich.edu} 3743578Sgblack@eecs.umich.edu 3753578Sgblack@eecs.umich.edu////////////////////////////////////////////////////////////////////// 3763578Sgblack@eecs.umich.edu// 3773578Sgblack@eecs.umich.edu// The following emulation functions are generic, but need to be 3783578Sgblack@eecs.umich.edu// templated to account for differences in types, constants, etc. 3793578Sgblack@eecs.umich.edu// 3803578Sgblack@eecs.umich.edu////////////////////////////////////////////////////////////////////// 3813578Sgblack@eecs.umich.edu 3823578Sgblack@eecs.umich.edu#if NO_STAT64 3833578Sgblack@eecs.umich.edu typedef struct stat hst_stat; 3843578Sgblack@eecs.umich.edu typedef struct stat hst_stat64; 3853578Sgblack@eecs.umich.edu#else 3863578Sgblack@eecs.umich.edu typedef struct stat hst_stat; 3873578Sgblack@eecs.umich.edu typedef struct stat64 hst_stat64; 3883578Sgblack@eecs.umich.edu#endif 3893578Sgblack@eecs.umich.edu 3903578Sgblack@eecs.umich.edu//// Helper function to convert a host stat buffer to a target stat 3913578Sgblack@eecs.umich.edu//// buffer. Also copies the target buffer out to the simulated 3923578Sgblack@eecs.umich.edu//// memory space. Used by stat(), fstat(), and lstat(). 3933578Sgblack@eecs.umich.edu 3943578Sgblack@eecs.umich.edutemplate <typename target_stat, typename host_stat> 3953578Sgblack@eecs.umich.edustatic void 3963761Sgblack@eecs.umich.educonvertStatBuf(target_stat &tgt, host_stat *host, bool fakeTTY = false) 3973761Sgblack@eecs.umich.edu{ 3983578Sgblack@eecs.umich.edu using namespace TheISA; 3993578Sgblack@eecs.umich.edu 4003761Sgblack@eecs.umich.edu if (fakeTTY) 4013761Sgblack@eecs.umich.edu tgt->st_dev = 0xA; 4023578Sgblack@eecs.umich.edu else 4033578Sgblack@eecs.umich.edu tgt->st_dev = host->st_dev; 4043578Sgblack@eecs.umich.edu tgt->st_dev = TheISA::htog(tgt->st_dev); 4053415Sgblack@eecs.umich.edu tgt->st_ino = host->st_ino; 4063928Ssaidi@eecs.umich.edu tgt->st_ino = TheISA::htog(tgt->st_ino); 4073928Ssaidi@eecs.umich.edu tgt->st_mode = host->st_mode; 4083928Ssaidi@eecs.umich.edu if (fakeTTY) { 4093928Ssaidi@eecs.umich.edu // Claim to be a character device 4103928Ssaidi@eecs.umich.edu tgt->st_mode &= ~S_IFMT; // Clear S_IFMT 4113415Sgblack@eecs.umich.edu tgt->st_mode |= S_IFCHR; // Set S_IFCHR 4123415Sgblack@eecs.umich.edu } 4133415Sgblack@eecs.umich.edu tgt->st_mode = TheISA::htog(tgt->st_mode); 4143415Sgblack@eecs.umich.edu tgt->st_nlink = host->st_nlink; 4153415Sgblack@eecs.umich.edu tgt->st_nlink = TheISA::htog(tgt->st_nlink); 4163415Sgblack@eecs.umich.edu tgt->st_uid = host->st_uid; 4173415Sgblack@eecs.umich.edu tgt->st_uid = TheISA::htog(tgt->st_uid); 4183415Sgblack@eecs.umich.edu tgt->st_gid = host->st_gid; 4193415Sgblack@eecs.umich.edu tgt->st_gid = TheISA::htog(tgt->st_gid); 4203415Sgblack@eecs.umich.edu if (fakeTTY) 4213415Sgblack@eecs.umich.edu tgt->st_rdev = 0x880d; 4223415Sgblack@eecs.umich.edu else 4233415Sgblack@eecs.umich.edu tgt->st_rdev = host->st_rdev; 4243415Sgblack@eecs.umich.edu tgt->st_rdev = TheISA::htog(tgt->st_rdev); 4253415Sgblack@eecs.umich.edu tgt->st_size = host->st_size; 4263415Sgblack@eecs.umich.edu tgt->st_size = TheISA::htog(tgt->st_size); 4273415Sgblack@eecs.umich.edu tgt->st_atimeX = host->st_atime; 4283415Sgblack@eecs.umich.edu tgt->st_atimeX = TheISA::htog(tgt->st_atimeX); 4293415Sgblack@eecs.umich.edu tgt->st_mtimeX = host->st_mtime; 4303415Sgblack@eecs.umich.edu tgt->st_mtimeX = TheISA::htog(tgt->st_mtimeX); 4313415Sgblack@eecs.umich.edu tgt->st_ctimeX = host->st_ctime; 4323415Sgblack@eecs.umich.edu tgt->st_ctimeX = TheISA::htog(tgt->st_ctimeX); 4333415Sgblack@eecs.umich.edu // Force the block size to be 8k. This helps to ensure buffered io works 4343415Sgblack@eecs.umich.edu // consistently across different hosts. 4353415Sgblack@eecs.umich.edu tgt->st_blksize = 0x2000; 4363415Sgblack@eecs.umich.edu tgt->st_blksize = TheISA::htog(tgt->st_blksize); 4373415Sgblack@eecs.umich.edu tgt->st_blocks = host->st_blocks; 4383415Sgblack@eecs.umich.edu tgt->st_blocks = TheISA::htog(tgt->st_blocks); 4393415Sgblack@eecs.umich.edu} 4403415Sgblack@eecs.umich.edu 4413415Sgblack@eecs.umich.edu// Same for stat64 4423415Sgblack@eecs.umich.edu 4433893Shsul@eecs.umich.edutemplate <typename target_stat, typename host_stat64> 4443578Sgblack@eecs.umich.edustatic void 4453415Sgblack@eecs.umich.educonvertStat64Buf(target_stat &tgt, host_stat64 *host, bool fakeTTY = false) 4463578Sgblack@eecs.umich.edu{ 4473415Sgblack@eecs.umich.edu using namespace TheISA; 4483415Sgblack@eecs.umich.edu 4493926Ssaidi@eecs.umich.edu convertStatBuf<target_stat, host_stat64>(tgt, host, fakeTTY); 4503926Ssaidi@eecs.umich.edu#if defined(STAT_HAVE_NSEC) 4513926Ssaidi@eecs.umich.edu tgt->st_atime_nsec = host->st_atime_nsec; 4523415Sgblack@eecs.umich.edu tgt->st_atime_nsec = TheISA::htog(tgt->st_atime_nsec); 4533415Sgblack@eecs.umich.edu tgt->st_mtime_nsec = host->st_mtime_nsec; 4543415Sgblack@eecs.umich.edu tgt->st_mtime_nsec = TheISA::htog(tgt->st_mtime_nsec); 4553893Shsul@eecs.umich.edu tgt->st_ctime_nsec = host->st_ctime_nsec; 4563415Sgblack@eecs.umich.edu tgt->st_ctime_nsec = TheISA::htog(tgt->st_ctime_nsec); 4573926Ssaidi@eecs.umich.edu#else 4583926Ssaidi@eecs.umich.edu tgt->st_atime_nsec = 0; 4593926Ssaidi@eecs.umich.edu tgt->st_mtime_nsec = 0; 4603926Ssaidi@eecs.umich.edu tgt->st_ctime_nsec = 0; 4613926Ssaidi@eecs.umich.edu#endif 4623415Sgblack@eecs.umich.edu} 4633415Sgblack@eecs.umich.edu 4643926Ssaidi@eecs.umich.edu//Here are a couple convenience functions 4653926Ssaidi@eecs.umich.edutemplate<class OS> 4663926Ssaidi@eecs.umich.edustatic void 4673415Sgblack@eecs.umich.educopyOutStatBuf(SETranslatingPortProxy &mem, Addr addr, 4683926Ssaidi@eecs.umich.edu hst_stat *host, bool fakeTTY = false) 4693926Ssaidi@eecs.umich.edu{ 4703415Sgblack@eecs.umich.edu typedef TypedBufferArg<typename OS::tgt_stat> tgt_stat_buf; 4713415Sgblack@eecs.umich.edu tgt_stat_buf tgt(addr); 4723893Shsul@eecs.umich.edu convertStatBuf<tgt_stat_buf, hst_stat>(tgt, host, fakeTTY); 4733415Sgblack@eecs.umich.edu tgt.copyOut(mem); 4743893Shsul@eecs.umich.edu} 4753415Sgblack@eecs.umich.edu 4763893Shsul@eecs.umich.edutemplate<class OS> 4773415Sgblack@eecs.umich.edustatic void 4783415Sgblack@eecs.umich.educopyOutStat64Buf(SETranslatingPortProxy &mem, Addr addr, 4793415Sgblack@eecs.umich.edu hst_stat64 *host, bool fakeTTY = false) 4803420Sgblack@eecs.umich.edu{ 4813893Shsul@eecs.umich.edu typedef TypedBufferArg<typename OS::tgt_stat64> tgt_stat_buf; 4823415Sgblack@eecs.umich.edu tgt_stat_buf tgt(addr); 4833415Sgblack@eecs.umich.edu convertStat64Buf<tgt_stat_buf, hst_stat64>(tgt, host, fakeTTY); 4843415Sgblack@eecs.umich.edu tgt.copyOut(mem); 4853415Sgblack@eecs.umich.edu} 4863415Sgblack@eecs.umich.edu 4873415Sgblack@eecs.umich.edu/// Target ioctl() handler. For the most part, programs call ioctl() 4883595Sgblack@eecs.umich.edu/// only to find out if their stdout is a tty, to determine whether to 4893578Sgblack@eecs.umich.edu/// do line or block buffering. 4903585Sgblack@eecs.umich.edutemplate <class OS> 4913603Ssaidi@eecs.umich.eduSyscallReturn 4923595Sgblack@eecs.umich.eduioctlFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 4933578Sgblack@eecs.umich.edu ThreadContext *tc) 4943578Sgblack@eecs.umich.edu{ 4953578Sgblack@eecs.umich.edu int index = 0; 4963585Sgblack@eecs.umich.edu int fd = process->getSyscallArg(tc, index); 4973578Sgblack@eecs.umich.edu unsigned req = process->getSyscallArg(tc, index); 4983585Sgblack@eecs.umich.edu 4993578Sgblack@eecs.umich.edu DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", fd, req); 5003578Sgblack@eecs.umich.edu 5013578Sgblack@eecs.umich.edu if (fd < 0 || process->sim_fd(fd) < 0) { 5023578Sgblack@eecs.umich.edu // doesn't map to any simulator fd: not a valid target fd 5033585Sgblack@eecs.umich.edu return -EBADF; 5043578Sgblack@eecs.umich.edu } 5053585Sgblack@eecs.umich.edu 5063578Sgblack@eecs.umich.edu switch (req) { 5073578Sgblack@eecs.umich.edu case OS::TIOCISATTY_: 5083578Sgblack@eecs.umich.edu case OS::TIOCGETP_: 5093578Sgblack@eecs.umich.edu case OS::TIOCSETP_: 5103578Sgblack@eecs.umich.edu case OS::TIOCSETN_: 5113578Sgblack@eecs.umich.edu case OS::TIOCSETC_: 5122221SN/A case OS::TIOCGETC_: 5132221SN/A case OS::TIOCGETS_: 5143573Sgblack@eecs.umich.edu case OS::TIOCGETA_: 5152221SN/A case OS::TCSETAW_: 5163825Ssaidi@eecs.umich.edu return -ENOTTY; 5172680Sktlim@umich.edu 5182223SN/A default: 5192221SN/A fatal("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ \n", 5203578Sgblack@eecs.umich.edu fd, req, tc->pcState()); 5213578Sgblack@eecs.umich.edu } 5223893Shsul@eecs.umich.edu} 5233893Shsul@eecs.umich.edu 5243893Shsul@eecs.umich.edu/// Target open() handler. 5253893Shsul@eecs.umich.edutemplate <class OS> 5263578Sgblack@eecs.umich.eduSyscallReturn 5273578Sgblack@eecs.umich.eduopenFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 5283578Sgblack@eecs.umich.edu ThreadContext *tc) 5293578Sgblack@eecs.umich.edu{ 5303893Shsul@eecs.umich.edu std::string path; 5313746Sgblack@eecs.umich.edu 5323893Shsul@eecs.umich.edu int index = 0; 5333578Sgblack@eecs.umich.edu if (!tc->getMemProxy().tryReadString(path, 5343578Sgblack@eecs.umich.edu process->getSyscallArg(tc, index))) 5353746Sgblack@eecs.umich.edu return -EFAULT; 5363578Sgblack@eecs.umich.edu 5373578Sgblack@eecs.umich.edu if (path == "/dev/sysdev0") { 5383578Sgblack@eecs.umich.edu // This is a memory-mapped high-resolution timer device on Alpha. 5393893Shsul@eecs.umich.edu // We don't support it, so just punt. 5403595Sgblack@eecs.umich.edu warn("Ignoring open(%s, ...)\n", path); 5413893Shsul@eecs.umich.edu return -ENOENT; 5423746Sgblack@eecs.umich.edu } 5433746Sgblack@eecs.umich.edu 5443578Sgblack@eecs.umich.edu int tgtFlags = process->getSyscallArg(tc, index); 5453893Shsul@eecs.umich.edu int mode = process->getSyscallArg(tc, index); 5463825Ssaidi@eecs.umich.edu int hostFlags = 0; 5473578Sgblack@eecs.umich.edu 5483578Sgblack@eecs.umich.edu // translate open flags 5493578Sgblack@eecs.umich.edu for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) { 5503893Shsul@eecs.umich.edu if (tgtFlags & OS::openFlagTable[i].tgtFlag) { 5513578Sgblack@eecs.umich.edu tgtFlags &= ~OS::openFlagTable[i].tgtFlag; 5523578Sgblack@eecs.umich.edu hostFlags |= OS::openFlagTable[i].hostFlag; 5533585Sgblack@eecs.umich.edu } 5543893Shsul@eecs.umich.edu } 5553826Ssaidi@eecs.umich.edu 5563578Sgblack@eecs.umich.edu // any target flags left? 5573585Sgblack@eecs.umich.edu if (tgtFlags != 0) 5583826Ssaidi@eecs.umich.edu warn("Syscall: open: cannot decode flags 0x%x", tgtFlags); 5593578Sgblack@eecs.umich.edu 5603893Shsul@eecs.umich.edu#ifdef __CYGWIN32__ 5613578Sgblack@eecs.umich.edu hostFlags |= O_BINARY; 5623578Sgblack@eecs.umich.edu#endif 5633578Sgblack@eecs.umich.edu 5643578Sgblack@eecs.umich.edu // Adjust path for current working directory 5653578Sgblack@eecs.umich.edu path = process->fullPath(path); 5663420Sgblack@eecs.umich.edu 5672221SN/A DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str()); 5683523Sgblack@eecs.umich.edu 5693523Sgblack@eecs.umich.edu int fd; 5703523Sgblack@eecs.umich.edu if (!path.compare(0, 6, "/proc/") || !path.compare(0, 8, "/system/") || 5713523Sgblack@eecs.umich.edu !path.compare(0, 10, "/platform/") || !path.compare(0, 5, "/sys/")) { 5723523Sgblack@eecs.umich.edu // It's a proc/sys entery and requires special handling 5733595Sgblack@eecs.umich.edu fd = OS::openSpecialFile(path, process, tc); 5743595Sgblack@eecs.umich.edu return (fd == -1) ? -1 : process->alloc_fd(fd,path.c_str(),hostFlags,mode, false); 5753595Sgblack@eecs.umich.edu } else { 5763595Sgblack@eecs.umich.edu // open the file 5773595Sgblack@eecs.umich.edu fd = open(path.c_str(), hostFlags, mode); 5783746Sgblack@eecs.umich.edu return (fd == -1) ? -errno : process->alloc_fd(fd,path.c_str(),hostFlags,mode, false); 5793746Sgblack@eecs.umich.edu } 5803595Sgblack@eecs.umich.edu 5813595Sgblack@eecs.umich.edu} 5823628Sgblack@eecs.umich.edu 5833628Sgblack@eecs.umich.edu/// Target sysinfo() handler. 5843628Sgblack@eecs.umich.edutemplate <class OS> 5853628Sgblack@eecs.umich.eduSyscallReturn 5863628Sgblack@eecs.umich.edusysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 5873628Sgblack@eecs.umich.edu ThreadContext *tc) 5883628Sgblack@eecs.umich.edu{ 5893628Sgblack@eecs.umich.edu 5903628Sgblack@eecs.umich.edu int index = 0; 5913628Sgblack@eecs.umich.edu TypedBufferArg<typename OS::tgt_sysinfo> 5923595Sgblack@eecs.umich.edu sysinfo(process->getSyscallArg(tc, index)); 5933595Sgblack@eecs.umich.edu 5943595Sgblack@eecs.umich.edu sysinfo->uptime=seconds_since_epoch; 5953595Sgblack@eecs.umich.edu sysinfo->totalram=process->system->memSize(); 5963746Sgblack@eecs.umich.edu 5973746Sgblack@eecs.umich.edu sysinfo.copyOut(tc->getMemProxy()); 5983746Sgblack@eecs.umich.edu 5993746Sgblack@eecs.umich.edu return 0; 6003595Sgblack@eecs.umich.edu} 6013595Sgblack@eecs.umich.edu 6023595Sgblack@eecs.umich.edu/// Target chmod() handler. 6033595Sgblack@eecs.umich.edutemplate <class OS> 6043595Sgblack@eecs.umich.eduSyscallReturn 6053595Sgblack@eecs.umich.educhmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 6063595Sgblack@eecs.umich.edu ThreadContext *tc) 6073595Sgblack@eecs.umich.edu{ 6083523Sgblack@eecs.umich.edu std::string path; 6093595Sgblack@eecs.umich.edu 6103595Sgblack@eecs.umich.edu int index = 0; 6113595Sgblack@eecs.umich.edu if (!tc->getMemProxy().tryReadString(path, 6123595Sgblack@eecs.umich.edu process->getSyscallArg(tc, index))) { 6133595Sgblack@eecs.umich.edu return -EFAULT; 6143523Sgblack@eecs.umich.edu } 6153523Sgblack@eecs.umich.edu 6163523Sgblack@eecs.umich.edu uint32_t mode = process->getSyscallArg(tc, index); 6173523Sgblack@eecs.umich.edu mode_t hostMode = 0; 6183523Sgblack@eecs.umich.edu 6193523Sgblack@eecs.umich.edu // XXX translate mode flags via OS::something??? 6203523Sgblack@eecs.umich.edu hostMode = mode; 6213523Sgblack@eecs.umich.edu 6223523Sgblack@eecs.umich.edu // Adjust path for current working directory 6233523Sgblack@eecs.umich.edu path = process->fullPath(path); 6243523Sgblack@eecs.umich.edu 6252221SN/A // do the chmod 6262221SN/A int result = chmod(path.c_str(), hostMode); 6273578Sgblack@eecs.umich.edu if (result < 0) 6282612SN/A return -errno; 6293415Sgblack@eecs.umich.edu 6303415Sgblack@eecs.umich.edu return 0; 6313578Sgblack@eecs.umich.edu} 6323415Sgblack@eecs.umich.edu 6333415Sgblack@eecs.umich.edu 6343415Sgblack@eecs.umich.edu/// Target fchmod() handler. 6353578Sgblack@eecs.umich.edutemplate <class OS> 6363415Sgblack@eecs.umich.eduSyscallReturn 6373415Sgblack@eecs.umich.edufchmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 6383415Sgblack@eecs.umich.edu ThreadContext *tc) 6393415Sgblack@eecs.umich.edu{ 6403415Sgblack@eecs.umich.edu int index = 0; 6413415Sgblack@eecs.umich.edu int fd = process->getSyscallArg(tc, index); 6423415Sgblack@eecs.umich.edu if (fd < 0 || process->sim_fd(fd) < 0) { 6433415Sgblack@eecs.umich.edu // doesn't map to any simulator fd: not a valid target fd 6443415Sgblack@eecs.umich.edu return -EBADF; 6453415Sgblack@eecs.umich.edu } 6463415Sgblack@eecs.umich.edu 6473415Sgblack@eecs.umich.edu uint32_t mode = process->getSyscallArg(tc, index); 6483578Sgblack@eecs.umich.edu mode_t hostMode = 0; 6493415Sgblack@eecs.umich.edu 6503415Sgblack@eecs.umich.edu // XXX translate mode flags via OS::someting??? 6513415Sgblack@eecs.umich.edu hostMode = mode; 6523578Sgblack@eecs.umich.edu 6533415Sgblack@eecs.umich.edu // do the fchmod 6543415Sgblack@eecs.umich.edu int result = fchmod(process->sim_fd(fd), hostMode); 6553415Sgblack@eecs.umich.edu if (result < 0) 6563578Sgblack@eecs.umich.edu return -errno; 6573415Sgblack@eecs.umich.edu 6583415Sgblack@eecs.umich.edu return 0; 6593415Sgblack@eecs.umich.edu} 6603415Sgblack@eecs.umich.edu 6613415Sgblack@eecs.umich.edu/// Target mremap() handler. 6623415Sgblack@eecs.umich.edutemplate <class OS> 6632800Ssaidi@eecs.umich.eduSyscallReturn 6642800Ssaidi@eecs.umich.edumremapFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) 6652800Ssaidi@eecs.umich.edu{ 6662800Ssaidi@eecs.umich.edu int index = 0; 6673786Sgblack@eecs.umich.edu Addr start = process->getSyscallArg(tc, index); 6683786Sgblack@eecs.umich.edu uint64_t old_length = process->getSyscallArg(tc, index); 6693786Sgblack@eecs.umich.edu uint64_t new_length = process->getSyscallArg(tc, index); 6703786Sgblack@eecs.umich.edu uint64_t flags = process->getSyscallArg(tc, index); 6712800Ssaidi@eecs.umich.edu 6723786Sgblack@eecs.umich.edu if ((start % TheISA::VMPageSize != 0) || 6732800Ssaidi@eecs.umich.edu (new_length % TheISA::VMPageSize != 0)) { 6742800Ssaidi@eecs.umich.edu warn("mremap failing: arguments not page aligned"); 6752800Ssaidi@eecs.umich.edu return -EINVAL; 6763786Sgblack@eecs.umich.edu } 6773786Sgblack@eecs.umich.edu 6783786Sgblack@eecs.umich.edu if (new_length > old_length) { 6793786Sgblack@eecs.umich.edu if ((start + old_length) == process->mmap_end) { 6803786Sgblack@eecs.umich.edu uint64_t diff = new_length - old_length; 6813786Sgblack@eecs.umich.edu process->allocateMem(process->mmap_end, diff); 6822800Ssaidi@eecs.umich.edu process->mmap_end += diff; 6832800Ssaidi@eecs.umich.edu return start; 6843415Sgblack@eecs.umich.edu } else { 6852221SN/A // sys/mman.h defined MREMAP_MAYMOVE 6862221SN/A if (!(flags & 1)) { 6872223SN/A warn("can't remap here and MREMAP_MAYMOVE flag not set\n"); 6882221SN/A 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 (length > 0x100000000ULL) 1008 warn("mmap length argument %#x is unreasonably large.\n", length); 1009 1010 if (!(flags & OS::TGT_MAP_ANONYMOUS)) { 1011 Process::FdMap *fd_map = p->sim_fd_obj(tgt_fd); 1012 if (!fd_map || fd_map->fd < 0) { 1013 warn("mmap failing: target fd %d is not valid\n", tgt_fd); 1014 return -EBADF; 1015 } 1016 1017 if (fd_map->filename != "/dev/zero") { 1018 // This is very likely broken, but leave a warning here 1019 // (rather than panic) in case /dev/zero is known by 1020 // another name on some platform 1021 warn("allowing mmap of file %s; mmap not supported on files" 1022 " other than /dev/zero\n", fd_map->filename); 1023 } 1024 } 1025 1026 if ((start % TheISA::VMPageSize) != 0 || 1027 (length % TheISA::VMPageSize) != 0) { 1028 warn("mmap failing: arguments not page-aligned: " 1029 "start 0x%x length 0x%x", 1030 start, length); 1031 return -EINVAL; 1032 } 1033 1034 // are we ok with clobbering existing mappings? only set this to 1035 // true if the user has been warned. 1036 bool clobber = false; 1037 1038 // try to use the caller-provided address if there is one 1039 bool use_provided_address = (start != 0); 1040 1041 if (use_provided_address) { 1042 // check to see if the desired address is already in use 1043 if (!p->pTable->isUnmapped(start, length)) { 1044 // there are existing mappings in the desired range 1045 // whether we clobber them or not depends on whether the caller 1046 // specified MAP_FIXED 1047 if (flags & OS::TGT_MAP_FIXED) { 1048 // MAP_FIXED specified: clobber existing mappings 1049 warn("mmap: MAP_FIXED at 0x%x overwrites existing mappings\n", 1050 start); 1051 clobber = true; 1052 } else { 1053 // MAP_FIXED not specified: ignore suggested start address 1054 warn("mmap: ignoring suggested map address 0x%x\n", start); 1055 use_provided_address = false; 1056 } 1057 } 1058 } 1059 1060 if (!use_provided_address) { 1061 // no address provided, or provided address unusable: 1062 // pick next address from our "mmap region" 1063 if (OS::mmapGrowsDown()) { 1064 start = p->mmap_end - length; 1065 p->mmap_end = start; 1066 } else { 1067 start = p->mmap_end; 1068 p->mmap_end += length; 1069 } 1070 } 1071 1072 p->allocateMem(start, length, clobber); 1073 1074 return start; 1075} 1076 1077/// Target getrlimit() handler. 1078template <class OS> 1079SyscallReturn 1080getrlimitFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1081 ThreadContext *tc) 1082{ 1083 int index = 0; 1084 unsigned resource = process->getSyscallArg(tc, index); 1085 TypedBufferArg<typename OS::rlimit> rlp(process->getSyscallArg(tc, index)); 1086 1087 switch (resource) { 1088 case OS::TGT_RLIMIT_STACK: 1089 // max stack size in bytes: make up a number (8MB for now) 1090 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; 1091 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1092 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1093 break; 1094 1095 case OS::TGT_RLIMIT_DATA: 1096 // max data segment size in bytes: make up a number 1097 rlp->rlim_cur = rlp->rlim_max = 256 * 1024 * 1024; 1098 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1099 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1100 break; 1101 1102 default: 1103 std::cerr << "getrlimitFunc: unimplemented resource " << resource 1104 << std::endl; 1105 abort(); 1106 break; 1107 } 1108 1109 rlp.copyOut(tc->getMemProxy()); 1110 return 0; 1111} 1112 1113/// Target gettimeofday() handler. 1114template <class OS> 1115SyscallReturn 1116gettimeofdayFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1117 ThreadContext *tc) 1118{ 1119 int index = 0; 1120 TypedBufferArg<typename OS::timeval> tp(process->getSyscallArg(tc, index)); 1121 1122 getElapsedTime(tp->tv_sec, tp->tv_usec); 1123 tp->tv_sec += seconds_since_epoch; 1124 tp->tv_sec = TheISA::htog(tp->tv_sec); 1125 tp->tv_usec = TheISA::htog(tp->tv_usec); 1126 1127 tp.copyOut(tc->getMemProxy()); 1128 1129 return 0; 1130} 1131 1132 1133/// Target utimes() handler. 1134template <class OS> 1135SyscallReturn 1136utimesFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1137 ThreadContext *tc) 1138{ 1139 std::string path; 1140 1141 int index = 0; 1142 if (!tc->getMemProxy().tryReadString(path, 1143 process->getSyscallArg(tc, index))) { 1144 return -EFAULT; 1145 } 1146 1147 TypedBufferArg<typename OS::timeval [2]> 1148 tp(process->getSyscallArg(tc, index)); 1149 tp.copyIn(tc->getMemProxy()); 1150 1151 struct timeval hostTimeval[2]; 1152 for (int i = 0; i < 2; ++i) 1153 { 1154 hostTimeval[i].tv_sec = TheISA::gtoh((*tp)[i].tv_sec); 1155 hostTimeval[i].tv_usec = TheISA::gtoh((*tp)[i].tv_usec); 1156 } 1157 1158 // Adjust path for current working directory 1159 path = process->fullPath(path); 1160 1161 int result = utimes(path.c_str(), hostTimeval); 1162 1163 if (result < 0) 1164 return -errno; 1165 1166 return 0; 1167} 1168/// Target getrusage() function. 1169template <class OS> 1170SyscallReturn 1171getrusageFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1172 ThreadContext *tc) 1173{ 1174 int index = 0; 1175 int who = process->getSyscallArg(tc, index); // THREAD, SELF, or CHILDREN 1176 TypedBufferArg<typename OS::rusage> rup(process->getSyscallArg(tc, index)); 1177 1178 rup->ru_utime.tv_sec = 0; 1179 rup->ru_utime.tv_usec = 0; 1180 rup->ru_stime.tv_sec = 0; 1181 rup->ru_stime.tv_usec = 0; 1182 rup->ru_maxrss = 0; 1183 rup->ru_ixrss = 0; 1184 rup->ru_idrss = 0; 1185 rup->ru_isrss = 0; 1186 rup->ru_minflt = 0; 1187 rup->ru_majflt = 0; 1188 rup->ru_nswap = 0; 1189 rup->ru_inblock = 0; 1190 rup->ru_oublock = 0; 1191 rup->ru_msgsnd = 0; 1192 rup->ru_msgrcv = 0; 1193 rup->ru_nsignals = 0; 1194 rup->ru_nvcsw = 0; 1195 rup->ru_nivcsw = 0; 1196 1197 switch (who) { 1198 case OS::TGT_RUSAGE_SELF: 1199 getElapsedTime(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec); 1200 rup->ru_utime.tv_sec = TheISA::htog(rup->ru_utime.tv_sec); 1201 rup->ru_utime.tv_usec = TheISA::htog(rup->ru_utime.tv_usec); 1202 break; 1203 1204 case OS::TGT_RUSAGE_CHILDREN: 1205 // do nothing. We have no child processes, so they take no time. 1206 break; 1207 1208 default: 1209 // don't really handle THREAD or CHILDREN, but just warn and 1210 // plow ahead 1211 warn("getrusage() only supports RUSAGE_SELF. Parameter %d ignored.", 1212 who); 1213 } 1214 1215 rup.copyOut(tc->getMemProxy()); 1216 1217 return 0; 1218} 1219 1220/// Target times() function. 1221template <class OS> 1222SyscallReturn 1223timesFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1224 ThreadContext *tc) 1225{ 1226 int index = 0; 1227 TypedBufferArg<typename OS::tms> bufp(process->getSyscallArg(tc, index)); 1228 1229 // Fill in the time structure (in clocks) 1230 int64_t clocks = curTick() * OS::M5_SC_CLK_TCK / SimClock::Int::s; 1231 bufp->tms_utime = clocks; 1232 bufp->tms_stime = 0; 1233 bufp->tms_cutime = 0; 1234 bufp->tms_cstime = 0; 1235 1236 // Convert to host endianness 1237 bufp->tms_utime = TheISA::htog(bufp->tms_utime); 1238 1239 // Write back 1240 bufp.copyOut(tc->getMemProxy()); 1241 1242 // Return clock ticks since system boot 1243 return clocks; 1244} 1245 1246/// Target time() function. 1247template <class OS> 1248SyscallReturn 1249timeFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1250 ThreadContext *tc) 1251{ 1252 typename OS::time_t sec, usec; 1253 getElapsedTime(sec, usec); 1254 sec += seconds_since_epoch; 1255 1256 int index = 0; 1257 Addr taddr = (Addr)process->getSyscallArg(tc, index); 1258 if(taddr != 0) { 1259 typename OS::time_t t = sec; 1260 t = TheISA::htog(t); 1261 SETranslatingPortProxy &p = tc->getMemProxy(); 1262 p.writeBlob(taddr, (uint8_t*)&t, (int)sizeof(typename OS::time_t)); 1263 } 1264 return sec; 1265} 1266 1267 1268#endif // __SIM_SYSCALL_EMUL_HH__ 1269