syscall_emul.hh revision 11392
1360SN/A/* 21458SN/A * Copyright (c) 2012-2013, 2015 ARM Limited 3360SN/A * Copyright (c) 2015 Advanced Micro Devices, Inc. 4360SN/A * All rights reserved 5360SN/A * 6360SN/A * The license below extends only to copyright in the software and shall 7360SN/A * not be construed as granting a license to any other intellectual 8360SN/A * property including but not limited to intellectual property relating 9360SN/A * to a hardware implementation of the functionality of the software 10360SN/A * licensed hereunder. You may use the software subject to the license 11360SN/A * terms below provided that you ensure that this notice is replicated 12360SN/A * unmodified and in its entirety in all distributions of the software, 13360SN/A * modified or unmodified, in source code or in binary form. 14360SN/A * 15360SN/A * Copyright (c) 2003-2005 The Regents of The University of Michigan 16360SN/A * All rights reserved. 17360SN/A * 18360SN/A * Redistribution and use in source and binary forms, with or without 19360SN/A * modification, are permitted provided that the following conditions are 20360SN/A * met: redistributions of source code must retain the above copyright 21360SN/A * notice, this list of conditions and the following disclaimer; 22360SN/A * redistributions in binary form must reproduce the above copyright 23360SN/A * notice, this list of conditions and the following disclaimer in the 24360SN/A * documentation and/or other materials provided with the distribution; 25360SN/A * neither the name of the copyright holders nor the names of its 26360SN/A * contributors may be used to endorse or promote products derived from 272665Ssaidi@eecs.umich.edu * this software without specific prior written permission. 282665Ssaidi@eecs.umich.edu * 292665Ssaidi@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 30360SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 31360SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 321354SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 331354SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 34360SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 352764Sstever@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 362764Sstever@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 372064SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 38360SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 39360SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 40360SN/A * 41360SN/A * Authors: Steve Reinhardt 42360SN/A * Kevin Lim 43360SN/A */ 441809SN/A 455543Ssaidi@eecs.umich.edu#ifndef __SIM_SYSCALL_EMUL_HH__ 461809SN/A#define __SIM_SYSCALL_EMUL_HH__ 473113Sgblack@eecs.umich.edu 488229Snate@binkert.org#define NO_STAT64 (defined(__APPLE__) || defined(__OpenBSD__) || \ 498229Snate@binkert.org defined(__FreeBSD__) || defined(__CYGWIN__) || \ 503113Sgblack@eecs.umich.edu defined(__NetBSD__)) 517075Snate@binkert.org 528229Snate@binkert.org/// 537075Snate@binkert.org/// @file syscall_emul.hh 54360SN/A/// 552474SN/A/// This file defines objects used to emulate syscalls from the target 565543Ssaidi@eecs.umich.edu/// application on the host machine. 572462SN/A 581354SN/A#ifdef __CYGWIN32__ 596216Snate@binkert.org#include <sys/fcntl.h> // for O_BINARY 606658Snate@binkert.org 612474SN/A#endif 622680Sktlim@umich.edu#include <fcntl.h> 638232Snate@binkert.org#include <sys/mman.h> 648229Snate@binkert.org#include <sys/stat.h> 658706Sandreas.hansson@arm.com#include <sys/time.h> 667678Sgblack@eecs.umich.edu#include <sys/uio.h> 678229Snate@binkert.org 688766Sgblack@eecs.umich.edu#include <cerrno> 696640Svince@csl.cornell.edu#include <string> 70360SN/A 71360SN/A#include "base/chunk_generator.hh" 72360SN/A#include "base/intmath.hh" // for RoundUp 73360SN/A#include "base/loader/object_file.hh" 74360SN/A#include "base/misc.hh" 75360SN/A#include "base/trace.hh" 76360SN/A#include "base/types.hh" 77360SN/A#include "config/the_isa.hh" 78378SN/A#include "cpu/base.hh" 791450SN/A#include "cpu/thread_context.hh" 803114Sgblack@eecs.umich.edu#include "debug/SyscallBase.hh" 81360SN/A#include "debug/SyscallVerbose.hh" 825543Ssaidi@eecs.umich.edu#include "mem/page_table.hh" 835543Ssaidi@eecs.umich.edu#include "sim/byteswap.hh" 845543Ssaidi@eecs.umich.edu#include "sim/emul_driver.hh" 85360SN/A#include "sim/process.hh" 86360SN/A#include "sim/syscall_emul_buf.hh" 87360SN/A#include "sim/syscallreturn.hh" 88360SN/A#include "sim/system.hh" 89360SN/A 902680Sktlim@umich.edu// This wrapper macro helps out with readability a bit. FLAGEXT specifies 91360SN/A// the verbosity and FMT is the message to be appended to the syscall 92360SN/A// header information. The syscall header information contains the cpuid 93360SN/A// and thread id. 94360SN/A#define DPRINTF_SYSCALL(FLAGEXT, FMT, ...) \ 95360SN/A DPRINTFS(Syscall##FLAGEXT, tc->getCpuPtr(), "T%d : syscall " FMT, \ 96360SN/A tc->threadId(), __VA_ARGS__) 97360SN/A 98360SN/A/// 99360SN/A/// System call descriptor. 100360SN/A/// 101360SN/Aclass SyscallDesc { 1023114Sgblack@eecs.umich.edu 103360SN/A public: 104360SN/A 105360SN/A /// Typedef for target syscall handler functions. 106360SN/A typedef SyscallReturn (*FuncPtr)(SyscallDesc *, int num, 107360SN/A LiveProcess *, ThreadContext *); 108360SN/A 109360SN/A const char *name; //!< Syscall name (e.g., "open"). 110360SN/A FuncPtr funcPtr; //!< Pointer to emulation function. 111360SN/A int flags; //!< Flags (see Flags enum). 112360SN/A bool warned; //!< Have we warned about unimplemented syscall? 113360SN/A 114360SN/A /// Flag values for controlling syscall behavior. 115360SN/A enum Flags { 116360SN/A /// Don't set return regs according to funcPtr return value. 117360SN/A /// Used for syscalls with non-standard return conventions 118360SN/A /// that explicitly set the ThreadContext regs (e.g., 119360SN/A /// sigreturn). 120360SN/A SuppressReturnValue = 1, 121360SN/A WarnOnce = 2 122360SN/A }; 123360SN/A 1248852Sandreas.hansson@arm.com /// Constructor. 125360SN/A SyscallDesc(const char *_name, FuncPtr _funcPtr, int _flags = 0) 1268852Sandreas.hansson@arm.com : name(_name), funcPtr(_funcPtr), flags(_flags), warned(false) 1275543Ssaidi@eecs.umich.edu { 128360SN/A } 129360SN/A 130360SN/A /// Emulate the syscall. Public interface for calling through funcPtr. 131360SN/A void doSyscall(int callnum, LiveProcess *proc, ThreadContext *tc); 132360SN/A 1338852Sandreas.hansson@arm.com /// Is the WarnOnce flag set? 134360SN/A bool warnOnce() const { return (flags & WarnOnce); } 1358852Sandreas.hansson@arm.com}; 1365543Ssaidi@eecs.umich.edu 137360SN/A 138360SN/A////////////////////////////////////////////////////////////////////// 139360SN/A// 140360SN/A// The following emulation functions are generic enough that they 141360SN/A// don't need to be recompiled for different emulated OS's. They are 142360SN/A// defined in sim/syscall_emul.cc. 143360SN/A// 144360SN/A////////////////////////////////////////////////////////////////////// 145360SN/A 146360SN/A 147360SN/A/// Handler for unimplemented syscalls that we haven't thought about. 148360SN/ASyscallReturn unimplementedFunc(SyscallDesc *desc, int num, 149360SN/A LiveProcess *p, ThreadContext *tc); 1505543Ssaidi@eecs.umich.edu 151360SN/A/// Handler for unimplemented syscalls that we never intend to 152360SN/A/// implement (signal handling, etc.) and should not affect the correct 153360SN/A/// behavior of the program. Print a warning only if the appropriate 154360SN/A/// trace flag is enabled. Return success to the target program. 155360SN/ASyscallReturn ignoreFunc(SyscallDesc *desc, int num, 156360SN/A LiveProcess *p, ThreadContext *tc); 157360SN/A 158360SN/A/// Target exit() handler: terminate current context. 159360SN/ASyscallReturn exitFunc(SyscallDesc *desc, int num, 160360SN/A LiveProcess *p, ThreadContext *tc); 161360SN/A 162360SN/A/// Target exit_group() handler: terminate simulation. (exit all threads) 163360SN/ASyscallReturn exitGroupFunc(SyscallDesc *desc, int num, 164360SN/A LiveProcess *p, ThreadContext *tc); 165360SN/A 166360SN/A/// Target getpagesize() handler. 167360SN/ASyscallReturn getpagesizeFunc(SyscallDesc *desc, int num, 1685543Ssaidi@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 1695543Ssaidi@eecs.umich.edu 170502SN/A/// Target brk() handler: set brk address. 171360SN/ASyscallReturn brkFunc(SyscallDesc *desc, int num, 172360SN/A LiveProcess *p, ThreadContext *tc); 173360SN/A 174360SN/A/// Target close() handler. 175360SN/ASyscallReturn closeFunc(SyscallDesc *desc, int num, 176360SN/A LiveProcess *p, ThreadContext *tc); 177360SN/A 178360SN/A/// Target read() handler. 179360SN/ASyscallReturn readFunc(SyscallDesc *desc, int num, 180360SN/A LiveProcess *p, ThreadContext *tc); 181360SN/A 182378SN/A/// Target write() handler. 1831706SN/ASyscallReturn writeFunc(SyscallDesc *desc, int num, 1843114Sgblack@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 185378SN/A 186378SN/A/// Target lseek() handler. 187378SN/ASyscallReturn lseekFunc(SyscallDesc *desc, int num, 188378SN/A LiveProcess *p, ThreadContext *tc); 189378SN/A 1901706SN/A/// Target _llseek() handler. 1913114Sgblack@eecs.umich.eduSyscallReturn _llseekFunc(SyscallDesc *desc, int num, 1928149SChris.Emmons@ARM.com LiveProcess *p, ThreadContext *tc); 1938149SChris.Emmons@ARM.com 194360SN/A/// Target munmap() handler. 1956109Ssanchezd@stanford.eduSyscallReturn munmapFunc(SyscallDesc *desc, int num, 1961706SN/A LiveProcess *p, ThreadContext *tc); 1973114Sgblack@eecs.umich.edu 198378SN/A/// Target gethostname() handler. 1996109Ssanchezd@stanford.eduSyscallReturn gethostnameFunc(SyscallDesc *desc, int num, 2006109Ssanchezd@stanford.edu LiveProcess *p, ThreadContext *tc); 2016109Ssanchezd@stanford.edu 2026109Ssanchezd@stanford.edu/// Target getcwd() handler. 203378SN/ASyscallReturn getcwdFunc(SyscallDesc *desc, int num, 2041706SN/A LiveProcess *p, ThreadContext *tc); 2053114Sgblack@eecs.umich.edu 206378SN/A/// Target readlink() handler. 2075748SSteve.Reinhardt@amd.comSyscallReturn readlinkFunc(SyscallDesc *desc, int num, 2085748SSteve.Reinhardt@amd.com LiveProcess *p, ThreadContext *tc, 2095748SSteve.Reinhardt@amd.com int index = 0); 210378SN/ASyscallReturn readlinkFunc(SyscallDesc *desc, int num, 211378SN/A LiveProcess *p, ThreadContext *tc); 2121706SN/A 2133114Sgblack@eecs.umich.edu/// Target unlink() handler. 214378SN/ASyscallReturn unlinkHelper(SyscallDesc *desc, int num, 215378SN/A LiveProcess *p, ThreadContext *tc, 2161706SN/A int index); 2173114Sgblack@eecs.umich.eduSyscallReturn unlinkFunc(SyscallDesc *desc, int num, 218378SN/A LiveProcess *p, ThreadContext *tc); 219378SN/A 2201706SN/A/// Target mkdir() handler. 2213114Sgblack@eecs.umich.eduSyscallReturn mkdirFunc(SyscallDesc *desc, int num, 222378SN/A LiveProcess *p, ThreadContext *tc); 223378SN/A 2241706SN/A/// Target rename() handler. 2253114Sgblack@eecs.umich.eduSyscallReturn renameFunc(SyscallDesc *desc, int num, 226378SN/A LiveProcess *p, ThreadContext *tc); 2274118Sgblack@eecs.umich.edu 2284118Sgblack@eecs.umich.edu 2294118Sgblack@eecs.umich.edu/// Target truncate() handler. 2304118Sgblack@eecs.umich.eduSyscallReturn truncateFunc(SyscallDesc *desc, int num, 231378SN/A LiveProcess *p, ThreadContext *tc); 2321706SN/A 2333114Sgblack@eecs.umich.edu 234378SN/A/// Target ftruncate() handler. 235378SN/ASyscallReturn ftruncateFunc(SyscallDesc *desc, int num, 2361706SN/A LiveProcess *p, ThreadContext *tc); 2373114Sgblack@eecs.umich.edu 238360SN/A 2395513SMichael.Adler@intel.com/// Target truncate64() handler. 2405513SMichael.Adler@intel.comSyscallReturn truncate64Func(SyscallDesc *desc, int num, 2415513SMichael.Adler@intel.com LiveProcess *p, ThreadContext *tc); 2425513SMichael.Adler@intel.com 2435513SMichael.Adler@intel.com/// Target ftruncate64() handler. 2445513SMichael.Adler@intel.comSyscallReturn ftruncate64Func(SyscallDesc *desc, int num, 2455513SMichael.Adler@intel.com LiveProcess *p, ThreadContext *tc); 2465513SMichael.Adler@intel.com 247511SN/A 2481706SN/A/// Target umask() handler. 2493114Sgblack@eecs.umich.eduSyscallReturn umaskFunc(SyscallDesc *desc, int num, 250511SN/A LiveProcess *p, ThreadContext *tc); 2515513SMichael.Adler@intel.com 2525513SMichael.Adler@intel.com 2535513SMichael.Adler@intel.com/// Target chown() handler. 2545513SMichael.Adler@intel.comSyscallReturn chownFunc(SyscallDesc *desc, int num, 255511SN/A LiveProcess *p, ThreadContext *tc); 2561706SN/A 2573114Sgblack@eecs.umich.edu 2581706SN/A/// Target fchown() handler. 2591706SN/ASyscallReturn fchownFunc(SyscallDesc *desc, int num, 2601706SN/A LiveProcess *p, ThreadContext *tc); 2611706SN/A 2623114Sgblack@eecs.umich.edu/// Target dup() handler. 2631706SN/ASyscallReturn dupFunc(SyscallDesc *desc, int num, 2641706SN/A LiveProcess *process, ThreadContext *tc); 2651706SN/A 2661706SN/A/// Target fnctl() handler. 2673114Sgblack@eecs.umich.eduSyscallReturn fcntlFunc(SyscallDesc *desc, int num, 2681706SN/A LiveProcess *process, ThreadContext *tc); 269511SN/A 2706703Svince@csl.cornell.edu/// Target fcntl64() handler. 2716703Svince@csl.cornell.eduSyscallReturn fcntl64Func(SyscallDesc *desc, int num, 2726703Svince@csl.cornell.edu LiveProcess *process, ThreadContext *tc); 2736703Svince@csl.cornell.edu 2746685Stjones1@inf.ed.ac.uk/// Target setuid() handler. 2756685Stjones1@inf.ed.ac.ukSyscallReturn setuidFunc(SyscallDesc *desc, int num, 2766685Stjones1@inf.ed.ac.uk LiveProcess *p, ThreadContext *tc); 2776685Stjones1@inf.ed.ac.uk 2786685Stjones1@inf.ed.ac.uk/// Target getpid() handler. 2795513SMichael.Adler@intel.comSyscallReturn getpidFunc(SyscallDesc *desc, int num, 2805513SMichael.Adler@intel.com LiveProcess *p, ThreadContext *tc); 2815513SMichael.Adler@intel.com 2825513SMichael.Adler@intel.com/// Target getuid() handler. 2835513SMichael.Adler@intel.comSyscallReturn getuidFunc(SyscallDesc *desc, int num, 2841999SN/A LiveProcess *p, ThreadContext *tc); 2851999SN/A 2863114Sgblack@eecs.umich.edu/// Target getgid() handler. 2871999SN/ASyscallReturn getgidFunc(SyscallDesc *desc, int num, 2881999SN/A LiveProcess *p, ThreadContext *tc); 2891999SN/A 2901999SN/A/// Target getppid() handler. 2913114Sgblack@eecs.umich.eduSyscallReturn getppidFunc(SyscallDesc *desc, int num, 2921999SN/A LiveProcess *p, ThreadContext *tc); 2933079Sstever@eecs.umich.edu 2943079Sstever@eecs.umich.edu/// Target geteuid() handler. 2953114Sgblack@eecs.umich.eduSyscallReturn geteuidFunc(SyscallDesc *desc, int num, 2963079Sstever@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 2972093SN/A 2982093SN/A/// Target getegid() handler. 2993114Sgblack@eecs.umich.eduSyscallReturn getegidFunc(SyscallDesc *desc, int num, 3002093SN/A LiveProcess *p, ThreadContext *tc); 3012687Sksewell@umich.edu 3022687Sksewell@umich.edu/// Target clone() handler. 3033114Sgblack@eecs.umich.eduSyscallReturn cloneFunc(SyscallDesc *desc, int num, 3042687Sksewell@umich.edu LiveProcess *p, ThreadContext *tc); 3052238SN/A 3062238SN/A/// Target access() handler 3073114Sgblack@eecs.umich.eduSyscallReturn accessFunc(SyscallDesc *desc, int num, 3082238SN/A LiveProcess *p, ThreadContext *tc); 3092238SN/ASyscallReturn accessFunc(SyscallDesc *desc, int num, 3102238SN/A LiveProcess *p, ThreadContext *tc, 3113114Sgblack@eecs.umich.edu int index); 3122238SN/A 3132238SN/A/// Futex system call 3142238SN/A/// Implemented by Daniel Sanchez 3153114Sgblack@eecs.umich.edu/// Used by printf's in multi-threaded apps 3162238SN/Atemplate <class OS> 3172238SN/ASyscallReturn 3182238SN/AfutexFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 3193114Sgblack@eecs.umich.edu ThreadContext *tc) 3202238SN/A{ 3212238SN/A int index_uaddr = 0; 3222238SN/A int index_op = 1; 3233114Sgblack@eecs.umich.edu int index_val = 2; 3242238SN/A int index_timeout = 3; 3252238SN/A 3262238SN/A uint64_t uaddr = process->getSyscallArg(tc, index_uaddr); 3273114Sgblack@eecs.umich.edu int op = process->getSyscallArg(tc, index_op); 3282238SN/A int val = process->getSyscallArg(tc, index_val); 3292238SN/A uint64_t timeout = process->getSyscallArg(tc, index_timeout); 3302238SN/A 3313114Sgblack@eecs.umich.edu std::map<uint64_t, std::list<ThreadContext *> * > 3322238SN/A &futex_map = tc->getSystemPtr()->futexMap; 3336109Ssanchezd@stanford.edu 3346109Ssanchezd@stanford.edu DPRINTF(SyscallVerbose, "In sys_futex: Address=%llx, op=%d, val=%d\n", 3356109Ssanchezd@stanford.edu uaddr, op, val); 3362238SN/A 3379112Smarc.orr@gmail.com op &= ~OS::TGT_FUTEX_PRIVATE_FLAG; 3389112Smarc.orr@gmail.com 3399112Smarc.orr@gmail.com if (op == OS::TGT_FUTEX_WAIT) { 3409112Smarc.orr@gmail.com if (timeout != 0) { 3419112Smarc.orr@gmail.com warn("sys_futex: FUTEX_WAIT with non-null timeout unimplemented;" 3429112Smarc.orr@gmail.com "we'll wait indefinitely"); 3439112Smarc.orr@gmail.com } 3449112Smarc.orr@gmail.com 3459112Smarc.orr@gmail.com uint8_t *buf = new uint8_t[sizeof(int)]; 3469112Smarc.orr@gmail.com tc->getMemProxy().readBlob((Addr)uaddr, buf, (int)sizeof(int)); 3479112Smarc.orr@gmail.com int mem_val = *((int *)buf); 3489112Smarc.orr@gmail.com delete[] buf; 3499112Smarc.orr@gmail.com 3509112Smarc.orr@gmail.com if (val != mem_val) { 3519112Smarc.orr@gmail.com DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAKE, read: %d, " 3529112Smarc.orr@gmail.com "expected: %d\n", mem_val, val); 3539112Smarc.orr@gmail.com return -OS::TGT_EWOULDBLOCK; 3549112Smarc.orr@gmail.com } 3559112Smarc.orr@gmail.com 3569112Smarc.orr@gmail.com // Queue the thread context 3579112Smarc.orr@gmail.com std::list<ThreadContext *> * tcWaitList; 3589112Smarc.orr@gmail.com if (futex_map.count(uaddr)) { 3599112Smarc.orr@gmail.com tcWaitList = futex_map.find(uaddr)->second; 3609112Smarc.orr@gmail.com } else { 3619112Smarc.orr@gmail.com tcWaitList = new std::list<ThreadContext *>(); 3629112Smarc.orr@gmail.com futex_map.insert(std::pair< uint64_t, 3639112Smarc.orr@gmail.com std::list<ThreadContext *> * >(uaddr, tcWaitList)); 3649112Smarc.orr@gmail.com } 3659112Smarc.orr@gmail.com tcWaitList->push_back(tc); 3669112Smarc.orr@gmail.com DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAIT, suspending calling " 3679112Smarc.orr@gmail.com "thread context\n"); 3689112Smarc.orr@gmail.com tc->suspend(); 3699112Smarc.orr@gmail.com return 0; 3709112Smarc.orr@gmail.com } else if (op == OS::TGT_FUTEX_WAKE){ 3719112Smarc.orr@gmail.com int wokenUp = 0; 3729112Smarc.orr@gmail.com std::list<ThreadContext *> * tcWaitList; 3739112Smarc.orr@gmail.com if (futex_map.count(uaddr)) { 3749112Smarc.orr@gmail.com tcWaitList = futex_map.find(uaddr)->second; 3759112Smarc.orr@gmail.com while (tcWaitList->size() > 0 && wokenUp < val) { 3769112Smarc.orr@gmail.com tcWaitList->front()->activate(); 3779112Smarc.orr@gmail.com tcWaitList->pop_front(); 3789112Smarc.orr@gmail.com wokenUp++; 3799112Smarc.orr@gmail.com } 3809112Smarc.orr@gmail.com if (tcWaitList->empty()) { 3819112Smarc.orr@gmail.com futex_map.erase(uaddr); 3829112Smarc.orr@gmail.com delete tcWaitList; 3839112Smarc.orr@gmail.com } 3849112Smarc.orr@gmail.com } 3859112Smarc.orr@gmail.com DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAKE, activated %d waiting " 3869112Smarc.orr@gmail.com "thread contexts\n", wokenUp); 3879112Smarc.orr@gmail.com return wokenUp; 3889112Smarc.orr@gmail.com } else { 3899112Smarc.orr@gmail.com warn("sys_futex: op %d is not implemented, just returning...", op); 3909112Smarc.orr@gmail.com return 0; 3919112Smarc.orr@gmail.com } 3929112Smarc.orr@gmail.com 3939112Smarc.orr@gmail.com} 3949112Smarc.orr@gmail.com 3959112Smarc.orr@gmail.com 3969112Smarc.orr@gmail.com/// Pseudo Funcs - These functions use a different return convension, 3979112Smarc.orr@gmail.com/// returning a second value in a register other than the normal return register 3989112Smarc.orr@gmail.comSyscallReturn pipePseudoFunc(SyscallDesc *desc, int num, 3999112Smarc.orr@gmail.com LiveProcess *process, ThreadContext *tc); 4009112Smarc.orr@gmail.com 4019112Smarc.orr@gmail.com/// Target getpidPseudo() handler. 4029112Smarc.orr@gmail.comSyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num, 4039112Smarc.orr@gmail.com LiveProcess *p, ThreadContext *tc); 4049112Smarc.orr@gmail.com 4059112Smarc.orr@gmail.com/// Target getuidPseudo() handler. 4069112Smarc.orr@gmail.comSyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num, 4079112Smarc.orr@gmail.com LiveProcess *p, ThreadContext *tc); 4089112Smarc.orr@gmail.com 4099112Smarc.orr@gmail.com/// Target getgidPseudo() handler. 4109112Smarc.orr@gmail.comSyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num, 4119112Smarc.orr@gmail.com LiveProcess *p, ThreadContext *tc); 4129112Smarc.orr@gmail.com 4139112Smarc.orr@gmail.com 4149112Smarc.orr@gmail.com/// A readable name for 1,000,000, for converting microseconds to seconds. 4159112Smarc.orr@gmail.comconst int one_million = 1000000; 4169112Smarc.orr@gmail.com/// A readable name for 1,000,000,000, for converting nanoseconds to seconds. 4179112Smarc.orr@gmail.comconst int one_billion = 1000000000; 4182238SN/A 4192238SN/A/// Approximate seconds since the epoch (1/1/1970). About a billion, 4202238SN/A/// by my reckoning. We want to keep this a constant (not use the 4212238SN/A/// real-world time) to keep simulations repeatable. 4223114Sgblack@eecs.umich.educonst unsigned seconds_since_epoch = 1000000000; 4232238SN/A 4242238SN/A/// Helper function to convert current elapsed time to seconds and 4252238SN/A/// microseconds. 4263114Sgblack@eecs.umich.edutemplate <class T1, class T2> 4272238SN/Avoid 4282238SN/AgetElapsedTimeMicro(T1 &sec, T2 &usec) 4292238SN/A{ 4303114Sgblack@eecs.umich.edu uint64_t elapsed_usecs = curTick() / SimClock::Int::us; 4312238SN/A sec = elapsed_usecs / one_million; 4322238SN/A usec = elapsed_usecs % one_million; 4332238SN/A} 4343114Sgblack@eecs.umich.edu 4352238SN/A/// Helper function to convert current elapsed time to seconds and 4362238SN/A/// nanoseconds. 4371354SN/Atemplate <class T1, class T2> 4381354SN/Avoid 4391354SN/AgetElapsedTimeNano(T1 &sec, T2 &nsec) 4401354SN/A{ 4411354SN/A uint64_t elapsed_nsecs = curTick() / SimClock::Int::ns; 4421354SN/A sec = elapsed_nsecs / one_billion; 4431354SN/A nsec = elapsed_nsecs % one_billion; 4441354SN/A} 4451354SN/A 4461354SN/A////////////////////////////////////////////////////////////////////// 4471354SN/A// 4481354SN/A// The following emulation functions are generic, but need to be 4491354SN/A// templated to account for differences in types, constants, etc. 4501354SN/A// 4517823Ssteve.reinhardt@amd.com////////////////////////////////////////////////////////////////////// 4521354SN/A 4531354SN/A#if NO_STAT64 4541354SN/A typedef struct stat hst_stat; 4551354SN/A typedef struct stat hst_stat64; 456360SN/A#else 457360SN/A typedef struct stat hst_stat; 458360SN/A typedef struct stat64 hst_stat64; 459360SN/A#endif 460360SN/A 461360SN/A//// Helper function to convert a host stat buffer to a target stat 462360SN/A//// buffer. Also copies the target buffer out to the simulated 4633113Sgblack@eecs.umich.edu//// memory space. Used by stat(), fstat(), and lstat(). 4643113Sgblack@eecs.umich.edu 4653113Sgblack@eecs.umich.edutemplate <typename target_stat, typename host_stat> 4663113Sgblack@eecs.umich.edustatic void 4673113Sgblack@eecs.umich.educonvertStatBuf(target_stat &tgt, host_stat *host, bool fakeTTY = false) 4683113Sgblack@eecs.umich.edu{ 4693113Sgblack@eecs.umich.edu using namespace TheISA; 4703113Sgblack@eecs.umich.edu 4713113Sgblack@eecs.umich.edu if (fakeTTY) 4723113Sgblack@eecs.umich.edu tgt->st_dev = 0xA; 4733113Sgblack@eecs.umich.edu else 4743113Sgblack@eecs.umich.edu tgt->st_dev = host->st_dev; 4753113Sgblack@eecs.umich.edu tgt->st_dev = TheISA::htog(tgt->st_dev); 4763113Sgblack@eecs.umich.edu tgt->st_ino = host->st_ino; 4773113Sgblack@eecs.umich.edu tgt->st_ino = TheISA::htog(tgt->st_ino); 4783113Sgblack@eecs.umich.edu tgt->st_mode = host->st_mode; 4794189Sgblack@eecs.umich.edu if (fakeTTY) { 4804189Sgblack@eecs.umich.edu // Claim to be a character device 4813113Sgblack@eecs.umich.edu tgt->st_mode &= ~S_IFMT; // Clear S_IFMT 4823113Sgblack@eecs.umich.edu tgt->st_mode |= S_IFCHR; // Set S_IFCHR 4833113Sgblack@eecs.umich.edu } 4843113Sgblack@eecs.umich.edu tgt->st_mode = TheISA::htog(tgt->st_mode); 4858737Skoansin.tan@gmail.com tgt->st_nlink = host->st_nlink; 4863113Sgblack@eecs.umich.edu tgt->st_nlink = TheISA::htog(tgt->st_nlink); 4878737Skoansin.tan@gmail.com tgt->st_uid = host->st_uid; 4883277Sgblack@eecs.umich.edu tgt->st_uid = TheISA::htog(tgt->st_uid); 4895515SMichael.Adler@intel.com tgt->st_gid = host->st_gid; 4905515SMichael.Adler@intel.com tgt->st_gid = TheISA::htog(tgt->st_gid); 4915515SMichael.Adler@intel.com if (fakeTTY) 4925515SMichael.Adler@intel.com tgt->st_rdev = 0x880d; 4935515SMichael.Adler@intel.com else 4948737Skoansin.tan@gmail.com tgt->st_rdev = host->st_rdev; 4953277Sgblack@eecs.umich.edu tgt->st_rdev = TheISA::htog(tgt->st_rdev); 4968737Skoansin.tan@gmail.com tgt->st_size = host->st_size; 4973277Sgblack@eecs.umich.edu tgt->st_size = TheISA::htog(tgt->st_size); 4988737Skoansin.tan@gmail.com tgt->st_atimeX = host->st_atime; 4993277Sgblack@eecs.umich.edu tgt->st_atimeX = TheISA::htog(tgt->st_atimeX); 5008737Skoansin.tan@gmail.com tgt->st_mtimeX = host->st_mtime; 5013113Sgblack@eecs.umich.edu tgt->st_mtimeX = TheISA::htog(tgt->st_mtimeX); 5023113Sgblack@eecs.umich.edu tgt->st_ctimeX = host->st_ctime; 5033113Sgblack@eecs.umich.edu tgt->st_ctimeX = TheISA::htog(tgt->st_ctimeX); 5043113Sgblack@eecs.umich.edu // Force the block size to be 8k. This helps to ensure buffered io works 5058737Skoansin.tan@gmail.com // consistently across different hosts. 5063113Sgblack@eecs.umich.edu tgt->st_blksize = 0x2000; 5078737Skoansin.tan@gmail.com tgt->st_blksize = TheISA::htog(tgt->st_blksize); 5083114Sgblack@eecs.umich.edu tgt->st_blocks = host->st_blocks; 5098737Skoansin.tan@gmail.com tgt->st_blocks = TheISA::htog(tgt->st_blocks); 5103114Sgblack@eecs.umich.edu} 5118737Skoansin.tan@gmail.com 5123114Sgblack@eecs.umich.edu// Same for stat64 5138737Skoansin.tan@gmail.com 5144061Sgblack@eecs.umich.edutemplate <typename target_stat, typename host_stat64> 5154061Sgblack@eecs.umich.edustatic void 5164061Sgblack@eecs.umich.educonvertStat64Buf(target_stat &tgt, host_stat64 *host, bool fakeTTY = false) 5178737Skoansin.tan@gmail.com{ 5183113Sgblack@eecs.umich.edu using namespace TheISA; 5198737Skoansin.tan@gmail.com 5203113Sgblack@eecs.umich.edu convertStatBuf<target_stat, host_stat64>(tgt, host, fakeTTY); 5213113Sgblack@eecs.umich.edu#if defined(STAT_HAVE_NSEC) 5223113Sgblack@eecs.umich.edu tgt->st_atime_nsec = host->st_atime_nsec; 5233113Sgblack@eecs.umich.edu tgt->st_atime_nsec = TheISA::htog(tgt->st_atime_nsec); 5243113Sgblack@eecs.umich.edu tgt->st_mtime_nsec = host->st_mtime_nsec; 5253113Sgblack@eecs.umich.edu tgt->st_mtime_nsec = TheISA::htog(tgt->st_mtime_nsec); 5263113Sgblack@eecs.umich.edu tgt->st_ctime_nsec = host->st_ctime_nsec; 5273113Sgblack@eecs.umich.edu tgt->st_ctime_nsec = TheISA::htog(tgt->st_ctime_nsec); 5284189Sgblack@eecs.umich.edu#else 5294189Sgblack@eecs.umich.edu tgt->st_atime_nsec = 0; 5303113Sgblack@eecs.umich.edu tgt->st_mtime_nsec = 0; 5313113Sgblack@eecs.umich.edu tgt->st_ctime_nsec = 0; 5323113Sgblack@eecs.umich.edu#endif 5338737Skoansin.tan@gmail.com} 5343113Sgblack@eecs.umich.edu 5358737Skoansin.tan@gmail.com//Here are a couple convenience functions 5363113Sgblack@eecs.umich.edutemplate<class OS> 5378737Skoansin.tan@gmail.comstatic void 5383113Sgblack@eecs.umich.educopyOutStatBuf(SETranslatingPortProxy &mem, Addr addr, 5393113Sgblack@eecs.umich.edu hst_stat *host, bool fakeTTY = false) 5403113Sgblack@eecs.umich.edu{ 5413113Sgblack@eecs.umich.edu typedef TypedBufferArg<typename OS::tgt_stat> tgt_stat_buf; 5423113Sgblack@eecs.umich.edu tgt_stat_buf tgt(addr); 5433113Sgblack@eecs.umich.edu convertStatBuf<tgt_stat_buf, hst_stat>(tgt, host, fakeTTY); 5443113Sgblack@eecs.umich.edu tgt.copyOut(mem); 5453113Sgblack@eecs.umich.edu} 5463113Sgblack@eecs.umich.edu 5473113Sgblack@eecs.umich.edutemplate<class OS> 5488852Sandreas.hansson@arm.comstatic void 5493113Sgblack@eecs.umich.educopyOutStat64Buf(SETranslatingPortProxy &mem, Addr addr, 5503113Sgblack@eecs.umich.edu hst_stat64 *host, bool fakeTTY = false) 5513113Sgblack@eecs.umich.edu{ 5523113Sgblack@eecs.umich.edu typedef TypedBufferArg<typename OS::tgt_stat64> tgt_stat_buf; 5533113Sgblack@eecs.umich.edu tgt_stat_buf tgt(addr); 5543113Sgblack@eecs.umich.edu convertStat64Buf<tgt_stat_buf, hst_stat64>(tgt, host, fakeTTY); 5553113Sgblack@eecs.umich.edu tgt.copyOut(mem); 5563113Sgblack@eecs.umich.edu} 5573113Sgblack@eecs.umich.edu 5583113Sgblack@eecs.umich.edu/// Target ioctl() handler. For the most part, programs call ioctl() 5598852Sandreas.hansson@arm.com/// only to find out if their stdout is a tty, to determine whether to 5603113Sgblack@eecs.umich.edu/// do line or block buffering. We always claim that output fds are 5613113Sgblack@eecs.umich.edu/// not TTYs to provide repeatable results. 5623113Sgblack@eecs.umich.edutemplate <class OS> 5633113Sgblack@eecs.umich.eduSyscallReturn 5646686Stjones1@inf.ed.ac.ukioctlFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 5653113Sgblack@eecs.umich.edu ThreadContext *tc) 5663113Sgblack@eecs.umich.edu{ 5673113Sgblack@eecs.umich.edu int index = 0; 568378SN/A int tgt_fd = process->getSyscallArg(tc, index); 569378SN/A unsigned req = process->getSyscallArg(tc, index); 5709141Smarc.orr@gmail.com 5719141Smarc.orr@gmail.com DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", tgt_fd, req); 572360SN/A 5731450SN/A FDEntry *fde = process->getFDEntry(tgt_fd); 5743114Sgblack@eecs.umich.edu 5752680Sktlim@umich.edu if (fde == NULL) { 576360SN/A // doesn't map to any simulator fd: not a valid target fd 5776701Sgblack@eecs.umich.edu return -EBADF; 5786701Sgblack@eecs.umich.edu } 5796701Sgblack@eecs.umich.edu 580360SN/A if (fde->driver != NULL) { 5811969SN/A return fde->driver->ioctl(process, tc, req); 582360SN/A } 583360SN/A 584360SN/A if (OS::isTtyReq(req)) { 5851458SN/A return -ENOTTY; 586360SN/A } 587360SN/A 5889141Smarc.orr@gmail.com warn("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ \n", 5891458SN/A tgt_fd, req, tc->pcState()); 5909141Smarc.orr@gmail.com return -ENOTTY; 591360SN/A} 5929141Smarc.orr@gmail.com 5939141Smarc.orr@gmail.comtemplate <class OS> 5949141Smarc.orr@gmail.comstatic SyscallReturn 595360SN/AopenFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 596360SN/A ThreadContext *tc, int index) 597378SN/A{ 598360SN/A std::string path; 5991450SN/A 6003114Sgblack@eecs.umich.edu if (!tc->getMemProxy().tryReadString(path, 6012680Sktlim@umich.edu process->getSyscallArg(tc, index))) 602360SN/A return -EFAULT; 603360SN/A 604360SN/A int tgtFlags = process->getSyscallArg(tc, index); 6056701Sgblack@eecs.umich.edu int mode = process->getSyscallArg(tc, index); 6068852Sandreas.hansson@arm.com int hostFlags = 0; 6076701Sgblack@eecs.umich.edu 6081458SN/A // translate open flags 609360SN/A for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) { 610360SN/A if (tgtFlags & OS::openFlagTable[i].tgtFlag) { 611360SN/A tgtFlags &= ~OS::openFlagTable[i].tgtFlag; 612360SN/A hostFlags |= OS::openFlagTable[i].hostFlag; 6131706SN/A } 6141458SN/A } 615360SN/A 616360SN/A // any target flags left? 6176701Sgblack@eecs.umich.edu if (tgtFlags != 0) 6186701Sgblack@eecs.umich.edu warn("Syscall: open: cannot decode flags 0x%x", tgtFlags); 619360SN/A 620360SN/A#ifdef __CYGWIN32__ 621360SN/A hostFlags |= O_BINARY; 622360SN/A#endif 623360SN/A 624360SN/A // Adjust path for current working directory 625360SN/A path = process->fullPath(path); 626360SN/A 627360SN/A DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str()); 628360SN/A 629360SN/A if (startswith(path, "/dev/")) { 630360SN/A std::string filename = path.substr(strlen("/dev/")); 6311706SN/A if (filename == "sysdev0") { 632360SN/A // This is a memory-mapped high-resolution timer device on Alpha. 633360SN/A // We don't support it, so just punt. 634360SN/A warn("Ignoring open(%s, ...)\n", path); 635360SN/A return -ENOENT; 636360SN/A } 6373669Sbinkertn@umich.edu 6383669Sbinkertn@umich.edu EmulatedDriver *drv = process->findDriver(filename); 6393669Sbinkertn@umich.edu if (drv != NULL) { 6401706SN/A // the driver's open method will allocate a fd from the 6411706SN/A // process if necessary. 6425795Ssaidi@eecs.umich.edu return drv->open(process, tc, mode, hostFlags); 6435795Ssaidi@eecs.umich.edu } 6445795Ssaidi@eecs.umich.edu 6455795Ssaidi@eecs.umich.edu // fall through here for pass through to host devices, such as 6465795Ssaidi@eecs.umich.edu // /dev/zero 6475795Ssaidi@eecs.umich.edu } 6485795Ssaidi@eecs.umich.edu 6495795Ssaidi@eecs.umich.edu int fd; 6505795Ssaidi@eecs.umich.edu int local_errno; 6515795Ssaidi@eecs.umich.edu if (startswith(path, "/proc/") || startswith(path, "/system/") || 6525795Ssaidi@eecs.umich.edu startswith(path, "/platform/") || startswith(path, "/sys/")) { 653360SN/A // It's a proc/sys entry and requires special handling 654360SN/A fd = OS::openSpecialFile(path, process, tc); 655360SN/A local_errno = ENOENT; 6566640Svince@csl.cornell.edu } else { 6576640Svince@csl.cornell.edu // open the file 6586640Svince@csl.cornell.edu fd = open(path.c_str(), hostFlags, mode); 6596640Svince@csl.cornell.edu local_errno = errno; 6606640Svince@csl.cornell.edu } 6616640Svince@csl.cornell.edu 6626640Svince@csl.cornell.edu if (fd == -1) 6636701Sgblack@eecs.umich.edu return -local_errno; 6646701Sgblack@eecs.umich.edu 6656701Sgblack@eecs.umich.edu return process->allocFD(fd, path.c_str(), hostFlags, mode, false); 6666640Svince@csl.cornell.edu} 6676701Sgblack@eecs.umich.edu 6686701Sgblack@eecs.umich.edu/// Target open() handler. 6696640Svince@csl.cornell.edutemplate <class OS> 6708706Sandreas.hansson@arm.comSyscallReturn 6716640Svince@csl.cornell.eduopenFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 6726701Sgblack@eecs.umich.edu ThreadContext *tc) 6736640Svince@csl.cornell.edu{ 674360SN/A return openFunc<OS>(desc, callnum, process, tc, 0); 6751999SN/A} 6761999SN/A 6771999SN/A/// Target openat() handler. 6783114Sgblack@eecs.umich.edutemplate <class OS> 6792680Sktlim@umich.eduSyscallReturn 6801999SN/AopenatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 6811999SN/A ThreadContext *tc) 6821999SN/A{ 6836701Sgblack@eecs.umich.edu int index = 0; 6848852Sandreas.hansson@arm.com int dirfd = process->getSyscallArg(tc, index); 6856701Sgblack@eecs.umich.edu if (dirfd != OS::TGT_AT_FDCWD) 6861999SN/A warn("openat: first argument not AT_FDCWD; unlikely to work"); 6876701Sgblack@eecs.umich.edu return openFunc<OS>(desc, callnum, process, tc, 1); 6881999SN/A} 6896701Sgblack@eecs.umich.edu 6901999SN/A/// Target unlinkat() handler. 6911999SN/Atemplate <class OS> 6921999SN/ASyscallReturn 6931999SN/AunlinkatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 6941999SN/A ThreadContext *tc) 6953669Sbinkertn@umich.edu{ 6963669Sbinkertn@umich.edu int index = 0; 6973669Sbinkertn@umich.edu int dirfd = process->getSyscallArg(tc, index); 6981999SN/A if (dirfd != OS::TGT_AT_FDCWD) 6991999SN/A warn("unlinkat: first argument not AT_FDCWD; unlikely to work"); 7001999SN/A 7012218SN/A return unlinkHelper(desc, callnum, process, tc, 1); 7021999SN/A} 7031999SN/A 7041999SN/A/// Target facessat() handler 7051999SN/Atemplate <class OS> 7061999SN/ASyscallReturn 7071999SN/AfaccessatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 7081999SN/A ThreadContext *tc) 7091999SN/A{ 7103114Sgblack@eecs.umich.edu int index = 0; 7112680Sktlim@umich.edu int dirfd = process->getSyscallArg(tc, index); 7121999SN/A if (dirfd != OS::TGT_AT_FDCWD) 7136701Sgblack@eecs.umich.edu warn("faccessat: first argument not AT_FDCWD; unlikely to work"); 7146701Sgblack@eecs.umich.edu return accessFunc(desc, callnum, process, tc, 1); 7151999SN/A} 7161999SN/A 7171999SN/A/// Target readlinkat() handler 7181999SN/Atemplate <class OS> 7191999SN/ASyscallReturn 7206701Sgblack@eecs.umich.edureadlinkatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 7211999SN/A ThreadContext *tc) 7221999SN/A{ 7231999SN/A int index = 0; 7241999SN/A int dirfd = process->getSyscallArg(tc, index); 7251999SN/A if (dirfd != OS::TGT_AT_FDCWD) 7261999SN/A warn("openat: first argument not AT_FDCWD; unlikely to work"); 7271999SN/A return readlinkFunc(desc, callnum, process, tc, 1); 7281999SN/A} 7292218SN/A 7301999SN/A/// Target renameat() handler. 7311999SN/Atemplate <class OS> 7321999SN/ASyscallReturn 7331999SN/ArenameatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 7345877Shsul@eecs.umich.edu ThreadContext *tc) 7355877Shsul@eecs.umich.edu{ 7365877Shsul@eecs.umich.edu int index = 0; 7375877Shsul@eecs.umich.edu 7385877Shsul@eecs.umich.edu int olddirfd = process->getSyscallArg(tc, index); 7396701Sgblack@eecs.umich.edu if (olddirfd != OS::TGT_AT_FDCWD) 7406701Sgblack@eecs.umich.edu warn("renameat: first argument not AT_FDCWD; unlikely to work"); 7416701Sgblack@eecs.umich.edu 7426701Sgblack@eecs.umich.edu std::string old_name; 7436701Sgblack@eecs.umich.edu 7445877Shsul@eecs.umich.edu if (!tc->getMemProxy().tryReadString(old_name, 7455877Shsul@eecs.umich.edu process->getSyscallArg(tc, index))) 7465877Shsul@eecs.umich.edu return -EFAULT; 7475877Shsul@eecs.umich.edu 7485877Shsul@eecs.umich.edu int newdirfd = process->getSyscallArg(tc, index); 7495877Shsul@eecs.umich.edu if (newdirfd != OS::TGT_AT_FDCWD) 7505877Shsul@eecs.umich.edu warn("renameat: third argument not AT_FDCWD; unlikely to work"); 7515877Shsul@eecs.umich.edu 7525877Shsul@eecs.umich.edu std::string new_name; 7535877Shsul@eecs.umich.edu 7548601Ssteve.reinhardt@amd.com if (!tc->getMemProxy().tryReadString(new_name, 7555877Shsul@eecs.umich.edu process->getSyscallArg(tc, index))) 7565877Shsul@eecs.umich.edu return -EFAULT; 7575877Shsul@eecs.umich.edu 7585877Shsul@eecs.umich.edu // Adjust path for current working directory 7595877Shsul@eecs.umich.edu old_name = process->fullPath(old_name); 7605877Shsul@eecs.umich.edu new_name = process->fullPath(new_name); 7615877Shsul@eecs.umich.edu 7625877Shsul@eecs.umich.edu int result = rename(old_name.c_str(), new_name.c_str()); 7635877Shsul@eecs.umich.edu return (result == -1) ? -errno : result; 7645877Shsul@eecs.umich.edu} 7655877Shsul@eecs.umich.edu 7665877Shsul@eecs.umich.edu/// Target sysinfo() handler. 7675877Shsul@eecs.umich.edutemplate <class OS> 7688601Ssteve.reinhardt@amd.comSyscallReturn 7698601Ssteve.reinhardt@amd.comsysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 7705877Shsul@eecs.umich.edu ThreadContext *tc) 7715877Shsul@eecs.umich.edu{ 7725877Shsul@eecs.umich.edu 7735877Shsul@eecs.umich.edu int index = 0; 7745877Shsul@eecs.umich.edu TypedBufferArg<typename OS::tgt_sysinfo> 7755877Shsul@eecs.umich.edu sysinfo(process->getSyscallArg(tc, index)); 7768601Ssteve.reinhardt@amd.com 7775877Shsul@eecs.umich.edu sysinfo->uptime=seconds_since_epoch; 7785877Shsul@eecs.umich.edu sysinfo->totalram=process->system->memSize(); 7795877Shsul@eecs.umich.edu 7801999SN/A sysinfo.copyOut(tc->getMemProxy()); 781378SN/A 782360SN/A return 0; 7831450SN/A} 7843114Sgblack@eecs.umich.edu 7852680Sktlim@umich.edu/// Target chmod() handler. 786360SN/Atemplate <class OS> 787360SN/ASyscallReturn 788360SN/AchmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 7896701Sgblack@eecs.umich.edu ThreadContext *tc) 7908852Sandreas.hansson@arm.com{ 7916701Sgblack@eecs.umich.edu std::string path; 7926701Sgblack@eecs.umich.edu 7936701Sgblack@eecs.umich.edu int index = 0; 7946701Sgblack@eecs.umich.edu if (!tc->getMemProxy().tryReadString(path, 795360SN/A process->getSyscallArg(tc, index))) { 7963669Sbinkertn@umich.edu return -EFAULT; 7973669Sbinkertn@umich.edu } 7983669Sbinkertn@umich.edu 799360SN/A uint32_t mode = process->getSyscallArg(tc, index); 800360SN/A mode_t hostMode = 0; 801360SN/A 802360SN/A // XXX translate mode flags via OS::something??? 8032218SN/A hostMode = mode; 804360SN/A 8058706Sandreas.hansson@arm.com // Adjust path for current working directory 806360SN/A path = process->fullPath(path); 8071458SN/A 808360SN/A // do the chmod 809360SN/A int result = chmod(path.c_str(), hostMode); 810360SN/A if (result < 0) 8115074Ssaidi@eecs.umich.edu return -errno; 8125074Ssaidi@eecs.umich.edu 8135074Ssaidi@eecs.umich.edu return 0; 8145074Ssaidi@eecs.umich.edu} 8155074Ssaidi@eecs.umich.edu 8165074Ssaidi@eecs.umich.edu 8175074Ssaidi@eecs.umich.edu/// Target fchmod() handler. 8185074Ssaidi@eecs.umich.edutemplate <class OS> 8196701Sgblack@eecs.umich.eduSyscallReturn 8208852Sandreas.hansson@arm.comfchmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 8216701Sgblack@eecs.umich.edu ThreadContext *tc) 8225074Ssaidi@eecs.umich.edu{ 8236701Sgblack@eecs.umich.edu int index = 0; 8245074Ssaidi@eecs.umich.edu int tgt_fd = process->getSyscallArg(tc, index); 8255074Ssaidi@eecs.umich.edu uint32_t mode = process->getSyscallArg(tc, index); 8265074Ssaidi@eecs.umich.edu 8275074Ssaidi@eecs.umich.edu int sim_fd = process->getSimFD(tgt_fd); 8285208Ssaidi@eecs.umich.edu if (sim_fd < 0) 8295208Ssaidi@eecs.umich.edu return -EBADF; 8305208Ssaidi@eecs.umich.edu 8315208Ssaidi@eecs.umich.edu mode_t hostMode = 0; 8325074Ssaidi@eecs.umich.edu 8335074Ssaidi@eecs.umich.edu // XXX translate mode flags via OS::someting??? 8345208Ssaidi@eecs.umich.edu hostMode = mode; 8355074Ssaidi@eecs.umich.edu 8365074Ssaidi@eecs.umich.edu // do the fchmod 8375074Ssaidi@eecs.umich.edu int result = fchmod(sim_fd, hostMode); 8385074Ssaidi@eecs.umich.edu if (result < 0) 8398706Sandreas.hansson@arm.com return -errno; 8405074Ssaidi@eecs.umich.edu 8415074Ssaidi@eecs.umich.edu return 0; 8425074Ssaidi@eecs.umich.edu} 8435074Ssaidi@eecs.umich.edu 8445074Ssaidi@eecs.umich.edu/// Target mremap() handler. 8451999SN/Atemplate <class OS> 8461999SN/ASyscallReturn 8471999SN/AmremapFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) 8483114Sgblack@eecs.umich.edu{ 8492680Sktlim@umich.edu int index = 0; 8501999SN/A Addr start = process->getSyscallArg(tc, index); 8516701Sgblack@eecs.umich.edu uint64_t old_length = process->getSyscallArg(tc, index); 8526701Sgblack@eecs.umich.edu uint64_t new_length = process->getSyscallArg(tc, index); 8536701Sgblack@eecs.umich.edu uint64_t flags = process->getSyscallArg(tc, index); 8541999SN/A uint64_t provided_address = 0; 8551999SN/A bool use_provided_address = flags & OS::TGT_MREMAP_FIXED; 8561999SN/A 8571999SN/A if (use_provided_address) 8581999SN/A provided_address = process->getSyscallArg(tc, index); 8592764Sstever@eecs.umich.edu 8602064SN/A if ((start % TheISA::PageBytes != 0) || 8612064SN/A (provided_address % TheISA::PageBytes != 0)) { 8622064SN/A warn("mremap failing: arguments not page aligned"); 8632064SN/A return -EINVAL; 8641999SN/A } 8652064SN/A 8661999SN/A new_length = roundUp(new_length, TheISA::PageBytes); 8671999SN/A 8682218SN/A if (new_length > old_length) { 8691999SN/A if ((start + old_length) == process->mmap_end && 8708706Sandreas.hansson@arm.com (!use_provided_address || provided_address == start)) { 8711999SN/A uint64_t diff = new_length - old_length; 8721999SN/A process->allocateMem(process->mmap_end, diff); 8731999SN/A process->mmap_end += diff; 8741999SN/A return start; 8751999SN/A } else { 876378SN/A if (!use_provided_address && !(flags & OS::TGT_MREMAP_MAYMOVE)) { 877360SN/A warn("can't remap here and MREMAP_MAYMOVE flag not set\n"); 8781450SN/A return -ENOMEM; 8793114Sgblack@eecs.umich.edu } else { 8802680Sktlim@umich.edu uint64_t new_start = use_provided_address ? 881360SN/A provided_address : process->mmap_end; 882360SN/A process->pTable->remap(start, old_length, new_start); 883360SN/A warn("mremapping to new vaddr %08p-%08p, adding %d\n", 8846701Sgblack@eecs.umich.edu new_start, new_start + new_length, 8858852Sandreas.hansson@arm.com new_length - old_length); 8866701Sgblack@eecs.umich.edu // add on the remaining unallocated pages 8876701Sgblack@eecs.umich.edu process->allocateMem(new_start + old_length, 8886701Sgblack@eecs.umich.edu new_length - old_length, 8896701Sgblack@eecs.umich.edu use_provided_address /* clobber */); 890360SN/A if (!use_provided_address) 8913669Sbinkertn@umich.edu process->mmap_end += new_length; 8923669Sbinkertn@umich.edu if (use_provided_address && 8933669Sbinkertn@umich.edu new_start + new_length > process->mmap_end) { 894360SN/A // something fishy going on here, at least notify the user 895360SN/A // @todo: increase mmap_end? 896360SN/A warn("mmap region limit exceeded with MREMAP_FIXED\n"); 897360SN/A } 8981458SN/A warn("returning %08p as start\n", new_start); 899360SN/A return new_start; 9008706Sandreas.hansson@arm.com } 901360SN/A } 9021458SN/A } else { 903360SN/A if (use_provided_address && provided_address != start) 904360SN/A process->pTable->remap(start, new_length, provided_address); 9051999SN/A process->pTable->unmap(start + new_length, old_length - new_length); 9061999SN/A return use_provided_address ? provided_address : start; 9071999SN/A } 9083114Sgblack@eecs.umich.edu} 9092680Sktlim@umich.edu 9101999SN/A/// Target stat() handler. 9111999SN/Atemplate <class OS> 9121999SN/ASyscallReturn 9136701Sgblack@eecs.umich.edustatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 9148852Sandreas.hansson@arm.com ThreadContext *tc) 9156701Sgblack@eecs.umich.edu{ 9166701Sgblack@eecs.umich.edu std::string path; 9176701Sgblack@eecs.umich.edu 9186701Sgblack@eecs.umich.edu int index = 0; 9191999SN/A if (!tc->getMemProxy().tryReadString(path, 9203669Sbinkertn@umich.edu process->getSyscallArg(tc, index))) { 9213669Sbinkertn@umich.edu return -EFAULT; 9223669Sbinkertn@umich.edu } 9232764Sstever@eecs.umich.edu Addr bufPtr = process->getSyscallArg(tc, index); 9242064SN/A 9252064SN/A // Adjust path for current working directory 9262064SN/A path = process->fullPath(path); 9271999SN/A 9281999SN/A struct stat hostBuf; 9292064SN/A int result = stat(path.c_str(), &hostBuf); 9301999SN/A 9311999SN/A if (result < 0) 9321999SN/A return -errno; 9331999SN/A 9348706Sandreas.hansson@arm.com copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 9351999SN/A 9361999SN/A return 0; 9371999SN/A} 9381999SN/A 939378SN/A 940360SN/A/// Target stat64() handler. 9411450SN/Atemplate <class OS> 9423114Sgblack@eecs.umich.eduSyscallReturn 9432680Sktlim@umich.edustat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 944360SN/A ThreadContext *tc) 9456701Sgblack@eecs.umich.edu{ 9466701Sgblack@eecs.umich.edu std::string path; 9476701Sgblack@eecs.umich.edu 948360SN/A int index = 0; 9491969SN/A if (!tc->getMemProxy().tryReadString(path, 950360SN/A process->getSyscallArg(tc, index))) 951360SN/A return -EFAULT; 9521458SN/A Addr bufPtr = process->getSyscallArg(tc, index); 953360SN/A 954360SN/A // Adjust path for current working directory 955360SN/A path = process->fullPath(path); 956360SN/A 957360SN/A#if NO_STAT64 9581458SN/A struct stat hostBuf; 959360SN/A int result = stat(path.c_str(), &hostBuf); 9608706Sandreas.hansson@arm.com#else 9612021SN/A struct stat64 hostBuf; 9621458SN/A int result = stat64(path.c_str(), &hostBuf); 963360SN/A#endif 964360SN/A 965360SN/A if (result < 0) 9661706SN/A return -errno; 9671706SN/A 9681706SN/A copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 9693114Sgblack@eecs.umich.edu 9702680Sktlim@umich.edu return 0; 9711706SN/A} 9721706SN/A 9731706SN/A 9746701Sgblack@eecs.umich.edu/// Target fstatat64() handler. 9758852Sandreas.hansson@arm.comtemplate <class OS> 9766701Sgblack@eecs.umich.eduSyscallReturn 9776701Sgblack@eecs.umich.edufstatat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 9786701Sgblack@eecs.umich.edu ThreadContext *tc) 9796701Sgblack@eecs.umich.edu{ 9801706SN/A int index = 0; 9813669Sbinkertn@umich.edu int dirfd = process->getSyscallArg(tc, index); 9823669Sbinkertn@umich.edu if (dirfd != OS::TGT_AT_FDCWD) 9833669Sbinkertn@umich.edu warn("fstatat64: first argument not AT_FDCWD; unlikely to work"); 9841706SN/A 9851706SN/A std::string path; 9861706SN/A if (!tc->getMemProxy().tryReadString(path, 9871706SN/A process->getSyscallArg(tc, index))) 9882218SN/A return -EFAULT; 9891706SN/A Addr bufPtr = process->getSyscallArg(tc, index); 9908706Sandreas.hansson@arm.com 9911706SN/A // Adjust path for current working directory 9921706SN/A path = process->fullPath(path); 9931706SN/A 9941706SN/A#if NO_STAT64 9951706SN/A struct stat hostBuf; 9961706SN/A int result = stat(path.c_str(), &hostBuf); 9971706SN/A#else 9981706SN/A struct stat64 hostBuf; 9993114Sgblack@eecs.umich.edu int result = stat64(path.c_str(), &hostBuf); 10002680Sktlim@umich.edu#endif 10011706SN/A 10026701Sgblack@eecs.umich.edu if (result < 0) 10036701Sgblack@eecs.umich.edu return -errno; 10046701Sgblack@eecs.umich.edu 10051706SN/A copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 10061706SN/A 10071706SN/A return 0; 10081706SN/A} 10091706SN/A 10101706SN/A 10111706SN/A/// Target fstat64() handler. 10121706SN/Atemplate <class OS> 10132218SN/ASyscallReturn 10141706SN/Afstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 10158706Sandreas.hansson@arm.com ThreadContext *tc) 10161706SN/A{ 10171706SN/A int index = 0; 10181706SN/A int tgt_fd = process->getSyscallArg(tc, index); 10191706SN/A Addr bufPtr = process->getSyscallArg(tc, index); 10201706SN/A 10211999SN/A int sim_fd = process->getSimFD(tgt_fd); 10221999SN/A if (sim_fd < 0) 10231999SN/A return -EBADF; 10243114Sgblack@eecs.umich.edu 10252680Sktlim@umich.edu#if NO_STAT64 10261999SN/A struct stat hostBuf; 10276701Sgblack@eecs.umich.edu int result = fstat(sim_fd, &hostBuf); 10286701Sgblack@eecs.umich.edu#else 10291999SN/A struct stat64 hostBuf; 10301999SN/A int result = fstat64(sim_fd, &hostBuf); 10311999SN/A#endif 10321999SN/A 10331999SN/A if (result < 0) 10348852Sandreas.hansson@arm.com return -errno; 10356701Sgblack@eecs.umich.edu 10366701Sgblack@eecs.umich.edu copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (sim_fd == 1)); 10371999SN/A 10386227Snate@binkert.org return 0; 10391999SN/A} 10402461SN/A 10418852Sandreas.hansson@arm.com 10428852Sandreas.hansson@arm.com/// Target lstat() handler. 10438737Skoansin.tan@gmail.comtemplate <class OS> 10441999SN/ASyscallReturn 10458852Sandreas.hansson@arm.comlstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 10468852Sandreas.hansson@arm.com ThreadContext *tc) 10471999SN/A{ 10481999SN/A std::string path; 10491999SN/A 10501999SN/A int index = 0; 10516227Snate@binkert.org if (!tc->getMemProxy().tryReadString(path, 10521999SN/A process->getSyscallArg(tc, index))) { 10531999SN/A return -EFAULT; 10541999SN/A } 10552218SN/A Addr bufPtr = process->getSyscallArg(tc, index); 10561999SN/A 10571999SN/A // Adjust path for current working directory 10581999SN/A path = process->fullPath(path); 10591999SN/A 10601999SN/A struct stat hostBuf; 1061378SN/A int result = lstat(path.c_str(), &hostBuf); 1062378SN/A 1063378SN/A if (result < 0) 1064378SN/A return -errno; 1065378SN/A 10668324Ssteve.reinhardt@amd.com copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 10678324Ssteve.reinhardt@amd.com 1068360SN/A return 0; 10691450SN/A} 10703114Sgblack@eecs.umich.edu 1071360SN/A/// Target lstat64() handler. 10726701Sgblack@eecs.umich.edutemplate <class OS> 10736701Sgblack@eecs.umich.eduSyscallReturn 10746701Sgblack@eecs.umich.edulstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 10756701Sgblack@eecs.umich.edu ThreadContext *tc) 10766701Sgblack@eecs.umich.edu{ 10778324Ssteve.reinhardt@amd.com std::string path; 10786701Sgblack@eecs.umich.edu 1079360SN/A int index = 0; 10809008Sgblack@eecs.umich.edu if (!tc->getMemProxy().tryReadString(path, 10819008Sgblack@eecs.umich.edu process->getSyscallArg(tc, index))) { 10829008Sgblack@eecs.umich.edu return -EFAULT; 10838324Ssteve.reinhardt@amd.com } 10848324Ssteve.reinhardt@amd.com Addr bufPtr = process->getSyscallArg(tc, index); 10858324Ssteve.reinhardt@amd.com 10868324Ssteve.reinhardt@amd.com // Adjust path for current working directory 10878324Ssteve.reinhardt@amd.com path = process->fullPath(path); 10888324Ssteve.reinhardt@amd.com 10898324Ssteve.reinhardt@amd.com#if NO_STAT64 10908324Ssteve.reinhardt@amd.com struct stat hostBuf; 10918324Ssteve.reinhardt@amd.com int result = lstat(path.c_str(), &hostBuf); 10928324Ssteve.reinhardt@amd.com#else 10938324Ssteve.reinhardt@amd.com struct stat64 hostBuf; 10948324Ssteve.reinhardt@amd.com int result = lstat64(path.c_str(), &hostBuf); 10958324Ssteve.reinhardt@amd.com#endif 10968324Ssteve.reinhardt@amd.com 10978324Ssteve.reinhardt@amd.com if (result < 0) 10985877Shsul@eecs.umich.edu return -errno; 10992544SN/A 11002544SN/A copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 11012544SN/A 11022544SN/A return 0; 11032544SN/A} 11042544SN/A 1105360SN/A/// Target fstat() handler. 1106360SN/Atemplate <class OS> 11078600Ssteve.reinhardt@amd.comSyscallReturn 11088600Ssteve.reinhardt@amd.comfstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 11098600Ssteve.reinhardt@amd.com ThreadContext *tc) 11108600Ssteve.reinhardt@amd.com{ 11118600Ssteve.reinhardt@amd.com int index = 0; 11128600Ssteve.reinhardt@amd.com int tgt_fd = process->getSyscallArg(tc, index); 11138600Ssteve.reinhardt@amd.com Addr bufPtr = process->getSyscallArg(tc, index); 11148600Ssteve.reinhardt@amd.com 11158600Ssteve.reinhardt@amd.com DPRINTF_SYSCALL(Verbose, "fstat(%d, ...)\n", tgt_fd); 11168600Ssteve.reinhardt@amd.com 11178600Ssteve.reinhardt@amd.com int sim_fd = process->getSimFD(tgt_fd); 11188600Ssteve.reinhardt@amd.com if (sim_fd < 0) 11198600Ssteve.reinhardt@amd.com return -EBADF; 11208600Ssteve.reinhardt@amd.com 11218600Ssteve.reinhardt@amd.com struct stat hostBuf; 11228600Ssteve.reinhardt@amd.com int result = fstat(sim_fd, &hostBuf); 11238600Ssteve.reinhardt@amd.com 11248600Ssteve.reinhardt@amd.com if (result < 0) 11258600Ssteve.reinhardt@amd.com return -errno; 11268600Ssteve.reinhardt@amd.com 11278600Ssteve.reinhardt@amd.com copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (sim_fd == 1)); 11288600Ssteve.reinhardt@amd.com 11298600Ssteve.reinhardt@amd.com return 0; 11308600Ssteve.reinhardt@amd.com} 11312544SN/A 11322544SN/A 11338600Ssteve.reinhardt@amd.com/// Target statfs() handler. 11348600Ssteve.reinhardt@amd.comtemplate <class OS> 11358600Ssteve.reinhardt@amd.comSyscallReturn 11368600Ssteve.reinhardt@amd.comstatfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 11378600Ssteve.reinhardt@amd.com ThreadContext *tc) 11388600Ssteve.reinhardt@amd.com{ 11398600Ssteve.reinhardt@amd.com std::string path; 11408600Ssteve.reinhardt@amd.com 11418600Ssteve.reinhardt@amd.com int index = 0; 11428600Ssteve.reinhardt@amd.com if (!tc->getMemProxy().tryReadString(path, 11436672Sgblack@eecs.umich.edu process->getSyscallArg(tc, index))) { 11448600Ssteve.reinhardt@amd.com return -EFAULT; 11458601Ssteve.reinhardt@amd.com } 11462544SN/A Addr bufPtr = process->getSyscallArg(tc, index); 11471458SN/A 1148360SN/A // Adjust path for current working directory 1149360SN/A path = process->fullPath(path); 1150378SN/A 1151360SN/A struct statfs hostBuf; 11521450SN/A int result = statfs(path.c_str(), &hostBuf); 11533114Sgblack@eecs.umich.edu 11542680Sktlim@umich.edu if (result < 0) 1155360SN/A return -errno; 11566701Sgblack@eecs.umich.edu 11576701Sgblack@eecs.umich.edu OS::copyOutStatfsBuf(tc->getMemProxy(), bufPtr, &hostBuf); 11586701Sgblack@eecs.umich.edu 1159360SN/A return 0; 1160360SN/A} 11612064SN/A 11625877Shsul@eecs.umich.edu 11632064SN/A/// Target fstatfs() handler. 11648737Skoansin.tan@gmail.comtemplate <class OS> 11658737Skoansin.tan@gmail.comSyscallReturn 11662064SN/AfstatfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1167360SN/A ThreadContext *tc) 11685877Shsul@eecs.umich.edu{ 11695877Shsul@eecs.umich.edu int index = 0; 11705877Shsul@eecs.umich.edu int tgt_fd = process->getSyscallArg(tc, index); 11718737Skoansin.tan@gmail.com Addr bufPtr = process->getSyscallArg(tc, index); 11728737Skoansin.tan@gmail.com 11735877Shsul@eecs.umich.edu int sim_fd = process->getSimFD(tgt_fd); 11745877Shsul@eecs.umich.edu if (sim_fd < 0) 11752064SN/A return -EBADF; 11762064SN/A 11772064SN/A struct statfs hostBuf; 11782064SN/A int result = fstatfs(sim_fd, &hostBuf); 11792064SN/A 1180360SN/A if (result < 0) 1181360SN/A return -errno; 11828706Sandreas.hansson@arm.com 11831458SN/A OS::copyOutStatfsBuf(tc->getMemProxy(), bufPtr, &hostBuf); 1184360SN/A 1185360SN/A return 0; 1186378SN/A} 1187360SN/A 11881450SN/A 11893114Sgblack@eecs.umich.edu/// Target writev() handler. 11902680Sktlim@umich.edutemplate <class OS> 1191360SN/ASyscallReturn 11926701Sgblack@eecs.umich.eduwritevFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 11936701Sgblack@eecs.umich.edu ThreadContext *tc) 1194360SN/A{ 1195360SN/A int index = 0; 1196360SN/A int tgt_fd = process->getSyscallArg(tc, index); 11976109Ssanchezd@stanford.edu 11986109Ssanchezd@stanford.edu int sim_fd = process->getSimFD(tgt_fd); 1199360SN/A if (sim_fd < 0) 12008706Sandreas.hansson@arm.com return -EBADF; 1201360SN/A 12021458SN/A SETranslatingPortProxy &p = tc->getMemProxy(); 1203360SN/A uint64_t tiov_base = process->getSyscallArg(tc, index); 1204360SN/A size_t count = process->getSyscallArg(tc, index); 1205360SN/A struct iovec hiov[count]; 12061999SN/A for (size_t i = 0; i < count; ++i) { 12071999SN/A typename OS::tgt_iovec tiov; 12081999SN/A 12093114Sgblack@eecs.umich.edu p.readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec), 12102680Sktlim@umich.edu (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec)); 12111999SN/A hiov[i].iov_len = TheISA::gtoh(tiov.iov_len); 12121999SN/A hiov[i].iov_base = new char [hiov[i].iov_len]; 12131999SN/A p.readBlob(TheISA::gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base, 12146701Sgblack@eecs.umich.edu hiov[i].iov_len); 12158852Sandreas.hansson@arm.com } 12166701Sgblack@eecs.umich.edu 12176701Sgblack@eecs.umich.edu int result = writev(sim_fd, hiov, count); 12186701Sgblack@eecs.umich.edu 12191999SN/A for (size_t i = 0; i < count; ++i) 12206701Sgblack@eecs.umich.edu delete [] (char *)hiov[i].iov_base; 12216701Sgblack@eecs.umich.edu 12228706Sandreas.hansson@arm.com if (result < 0) 12231999SN/A return -errno; 12241999SN/A 12251999SN/A return result; 12261999SN/A} 12278737Skoansin.tan@gmail.com 12288737Skoansin.tan@gmail.com/// Real mmap handler. 12291999SN/Atemplate <class OS> 12303669Sbinkertn@umich.eduSyscallReturn 12313669Sbinkertn@umich.edummapImpl(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc, 12323669Sbinkertn@umich.edu bool is_mmap2) 12333669Sbinkertn@umich.edu{ 12341999SN/A int index = 0; 12351999SN/A Addr start = p->getSyscallArg(tc, index); 12361999SN/A uint64_t length = p->getSyscallArg(tc, index); 12371999SN/A int prot = p->getSyscallArg(tc, index); 12381999SN/A int tgt_flags = p->getSyscallArg(tc, index); 12391999SN/A int tgt_fd = p->getSyscallArg(tc, index); 12401999SN/A int offset = p->getSyscallArg(tc, index); 1241378SN/A 1242360SN/A if (is_mmap2) 12431450SN/A offset *= TheISA::PageBytes; 12443114Sgblack@eecs.umich.edu 12452680Sktlim@umich.edu if (start & (TheISA::PageBytes - 1) || 1246360SN/A offset & (TheISA::PageBytes - 1) || 12476701Sgblack@eecs.umich.edu (tgt_flags & OS::TGT_MAP_PRIVATE && 12486701Sgblack@eecs.umich.edu tgt_flags & OS::TGT_MAP_SHARED) || 12496701Sgblack@eecs.umich.edu (!(tgt_flags & OS::TGT_MAP_PRIVATE) && 1250360SN/A !(tgt_flags & OS::TGT_MAP_SHARED)) || 12513670Sbinkertn@umich.edu !length) { 12523670Sbinkertn@umich.edu return -EINVAL; 1253360SN/A } 1254360SN/A 1255360SN/A if ((prot & PROT_WRITE) && (tgt_flags & OS::TGT_MAP_SHARED)) { 1256360SN/A // With shared mmaps, there are two cases to consider: 1257360SN/A // 1) anonymous: writes should modify the mapping and this should be 1258360SN/A // visible to observers who share the mapping. Currently, it's 1259360SN/A // difficult to update the shared mapping because there's no 1260360SN/A // structure which maintains information about the which virtual 1261360SN/A // memory areas are shared. If that structure existed, it would be 1262360SN/A // possible to make the translations point to the same frames. 1263360SN/A // 2) file-backed: writes should modify the mapping and the file 1264360SN/A // which is backed by the mapping. The shared mapping problem is the 1265360SN/A // same as what was mentioned about the anonymous mappings. For 1266360SN/A // file-backed mappings, the writes to the file are difficult 1267360SN/A // because it requires syncing what the mapping holds with the file 1268360SN/A // that resides on the host system. So, any write on a real system 1269360SN/A // would cause the change to be propagated to the file mapping at 12703670Sbinkertn@umich.edu // some point in the future (the inode is tracked along with the 12713670Sbinkertn@umich.edu // mapping). This isn't guaranteed to always happen, but it usually 12723670Sbinkertn@umich.edu // works well enough. The guarantee is provided by the msync system 12738737Skoansin.tan@gmail.com // call. We could force the change through with shared mappings with 12748737Skoansin.tan@gmail.com // a call to msync, but that again would require more information 12753670Sbinkertn@umich.edu // than we currently maintain. 12763670Sbinkertn@umich.edu warn("mmap: writing to shared mmap region is currently " 12773670Sbinkertn@umich.edu "unsupported. The write succeeds on the target, but it " 12783670Sbinkertn@umich.edu "will not be propagated to the host or shared mappings"); 12793670Sbinkertn@umich.edu } 12803670Sbinkertn@umich.edu 12813670Sbinkertn@umich.edu length = roundUp(length, TheISA::PageBytes); 12823670Sbinkertn@umich.edu 12833670Sbinkertn@umich.edu int sim_fd = -1; 12843670Sbinkertn@umich.edu uint8_t *pmap = nullptr; 12853670Sbinkertn@umich.edu if (!(tgt_flags & OS::TGT_MAP_ANONYMOUS)) { 12863670Sbinkertn@umich.edu sim_fd = p->getSimFD(tgt_fd); 12873670Sbinkertn@umich.edu if (sim_fd < 0) 12888706Sandreas.hansson@arm.com return -EBADF; 1289360SN/A 12901458SN/A pmap = (decltype(pmap))mmap(NULL, length, PROT_READ, MAP_PRIVATE, 1291360SN/A sim_fd, offset); 1292360SN/A 12936683Stjones1@inf.ed.ac.uk if (pmap == (decltype(pmap))-1) { 12946683Stjones1@inf.ed.ac.uk warn("mmap: failed to map file into host address space"); 12956683Stjones1@inf.ed.ac.uk return -errno; 12966683Stjones1@inf.ed.ac.uk } 12976683Stjones1@inf.ed.ac.uk } 12986683Stjones1@inf.ed.ac.uk 12996701Sgblack@eecs.umich.edu // Extend global mmap region if necessary. Note that we ignore the 13006701Sgblack@eecs.umich.edu // start address unless MAP_FIXED is specified. 13016683Stjones1@inf.ed.ac.uk if (!(tgt_flags & OS::TGT_MAP_FIXED)) { 13026683Stjones1@inf.ed.ac.uk start = p->mmapGrowsDown() ? p->mmap_end - length : p->mmap_end; 13037823Ssteve.reinhardt@amd.com p->mmap_end = p->mmapGrowsDown() ? start : p->mmap_end + length; 13046683Stjones1@inf.ed.ac.uk } 13056683Stjones1@inf.ed.ac.uk 13066683Stjones1@inf.ed.ac.uk DPRINTF_SYSCALL(Verbose, " mmap range is 0x%x - 0x%x\n", 13076683Stjones1@inf.ed.ac.uk start, start + length - 1); 13086683Stjones1@inf.ed.ac.uk 13096683Stjones1@inf.ed.ac.uk // We only allow mappings to overwrite existing mappings if 13108737Skoansin.tan@gmail.com // TGT_MAP_FIXED is set. Otherwise it shouldn't be a problem 13116683Stjones1@inf.ed.ac.uk // because we ignore the start hint if TGT_MAP_FIXED is not set. 13126683Stjones1@inf.ed.ac.uk int clobber = tgt_flags & OS::TGT_MAP_FIXED; 13138706Sandreas.hansson@arm.com if (clobber) { 13146683Stjones1@inf.ed.ac.uk for (auto tc : p->system->threadContexts) { 13156683Stjones1@inf.ed.ac.uk // If we might be overwriting old mappings, we need to 13166683Stjones1@inf.ed.ac.uk // invalidate potentially stale mappings out of the TLBs. 13176683Stjones1@inf.ed.ac.uk tc->getDTBPtr()->flushAll(); 13182553SN/A tc->getITBPtr()->flushAll(); 13196684Stjones1@inf.ed.ac.uk } 13206684Stjones1@inf.ed.ac.uk } 13216684Stjones1@inf.ed.ac.uk 13226684Stjones1@inf.ed.ac.uk // Allocate physical memory and map it in. If the page table is already 13236684Stjones1@inf.ed.ac.uk // mapped and clobber is not set, the simulator will issue throw a 13246684Stjones1@inf.ed.ac.uk // fatal and bail out of the simulation. 13256684Stjones1@inf.ed.ac.uk p->allocateMem(start, length, clobber); 13266684Stjones1@inf.ed.ac.uk 13276684Stjones1@inf.ed.ac.uk // Transfer content into target address space. 13286684Stjones1@inf.ed.ac.uk SETranslatingPortProxy &tp = tc->getMemProxy(); 13296701Sgblack@eecs.umich.edu if (tgt_flags & OS::TGT_MAP_ANONYMOUS) { 13306701Sgblack@eecs.umich.edu // In general, we should zero the mapped area for anonymous mappings, 13316684Stjones1@inf.ed.ac.uk // with something like: 13326684Stjones1@inf.ed.ac.uk // tp.memsetBlob(start, 0, length); 13338737Skoansin.tan@gmail.com // However, given that we don't support sparse mappings, and 13348852Sandreas.hansson@arm.com // some applications can map a couple of gigabytes of space 13358852Sandreas.hansson@arm.com // (intending sparse usage), that can get painfully expensive. 13366684Stjones1@inf.ed.ac.uk // Fortunately, since we don't properly implement munmap either, 13376684Stjones1@inf.ed.ac.uk // there's no danger of remapping used memory, so for now all 13386684Stjones1@inf.ed.ac.uk // newly mapped memory should already be zeroed so we can skip it. 13392553SN/A } else { 13402553SN/A // It is possible to mmap an area larger than a file, however 13411354SN/A // accessing unmapped portions the system triggers a "Bus error" 1342 // on the host. We must know when to stop copying the file from 1343 // the host into the target address space. 1344 struct stat file_stat; 1345 if (fstat(sim_fd, &file_stat) > 0) 1346 fatal("mmap: cannot stat file"); 1347 1348 // Copy the portion of the file that is resident. This requires 1349 // checking both the mmap size and the filesize that we are 1350 // trying to mmap into this space; the mmap size also depends 1351 // on the specified offset into the file. 1352 uint64_t size = std::min((uint64_t)file_stat.st_size - offset, 1353 length); 1354 tp.writeBlob(start, pmap, size); 1355 1356 // Cleanup the mmap region before exiting this function. 1357 munmap(pmap, length); 1358 1359 // Maintain the symbol table for dynamic executables. 1360 // The loader will call mmap to map the images into its address 1361 // space and we intercept that here. We can verify that we are 1362 // executing inside the loader by checking the program counter value. 1363 // XXX: with multiprogrammed workloads or multi-node configurations, 1364 // this will not work since there is a single global symbol table. 1365 ObjectFile *interpreter = p->getInterpreter(); 1366 if (interpreter) { 1367 Addr text_start = interpreter->textBase(); 1368 Addr text_end = text_start + interpreter->textSize(); 1369 1370 Addr pc = tc->pcState().pc(); 1371 1372 if (pc >= text_start && pc < text_end) { 1373 FDEntry *fde = p->getFDEntry(tgt_fd); 1374 1375 ObjectFile *lib = createObjectFile(fde->filename); 1376 1377 if (lib) { 1378 lib->loadAllSymbols(debugSymbolTable, 1379 lib->textBase(), start); 1380 } 1381 } 1382 } 1383 1384 // Note that we do not zero out the remainder of the mapping. This 1385 // is done by a real system, but it probably will not affect 1386 // execution (hopefully). 1387 } 1388 1389 return start; 1390} 1391 1392/// Target mmap() handler. 1393template <class OS> 1394SyscallReturn 1395mmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 1396{ 1397 return mmapImpl<OS>(desc, num, p, tc, false); 1398} 1399 1400/// Target mmap2() handler. 1401template <class OS> 1402SyscallReturn 1403mmap2Func(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 1404{ 1405 return mmapImpl<OS>(desc, num, p, tc, true); 1406} 1407 1408/// Target getrlimit() handler. 1409template <class OS> 1410SyscallReturn 1411getrlimitFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1412 ThreadContext *tc) 1413{ 1414 int index = 0; 1415 unsigned resource = process->getSyscallArg(tc, index); 1416 TypedBufferArg<typename OS::rlimit> rlp(process->getSyscallArg(tc, index)); 1417 1418 switch (resource) { 1419 case OS::TGT_RLIMIT_STACK: 1420 // max stack size in bytes: make up a number (8MB for now) 1421 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; 1422 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1423 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1424 break; 1425 1426 case OS::TGT_RLIMIT_DATA: 1427 // max data segment size in bytes: make up a number 1428 rlp->rlim_cur = rlp->rlim_max = 256 * 1024 * 1024; 1429 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1430 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1431 break; 1432 1433 default: 1434 warn("getrlimit: unimplemented resource %d", resource); 1435 return -EINVAL; 1436 break; 1437 } 1438 1439 rlp.copyOut(tc->getMemProxy()); 1440 return 0; 1441} 1442 1443/// Target clock_gettime() function. 1444template <class OS> 1445SyscallReturn 1446clock_gettimeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 1447{ 1448 int index = 1; 1449 //int clk_id = p->getSyscallArg(tc, index); 1450 TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index)); 1451 1452 getElapsedTimeNano(tp->tv_sec, tp->tv_nsec); 1453 tp->tv_sec += seconds_since_epoch; 1454 tp->tv_sec = TheISA::htog(tp->tv_sec); 1455 tp->tv_nsec = TheISA::htog(tp->tv_nsec); 1456 1457 tp.copyOut(tc->getMemProxy()); 1458 1459 return 0; 1460} 1461 1462/// Target clock_getres() function. 1463template <class OS> 1464SyscallReturn 1465clock_getresFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 1466{ 1467 int index = 1; 1468 TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index)); 1469 1470 // Set resolution at ns, which is what clock_gettime() returns 1471 tp->tv_sec = 0; 1472 tp->tv_nsec = 1; 1473 1474 tp.copyOut(tc->getMemProxy()); 1475 1476 return 0; 1477} 1478 1479/// Target gettimeofday() handler. 1480template <class OS> 1481SyscallReturn 1482gettimeofdayFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1483 ThreadContext *tc) 1484{ 1485 int index = 0; 1486 TypedBufferArg<typename OS::timeval> tp(process->getSyscallArg(tc, index)); 1487 1488 getElapsedTimeMicro(tp->tv_sec, tp->tv_usec); 1489 tp->tv_sec += seconds_since_epoch; 1490 tp->tv_sec = TheISA::htog(tp->tv_sec); 1491 tp->tv_usec = TheISA::htog(tp->tv_usec); 1492 1493 tp.copyOut(tc->getMemProxy()); 1494 1495 return 0; 1496} 1497 1498 1499/// Target utimes() handler. 1500template <class OS> 1501SyscallReturn 1502utimesFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1503 ThreadContext *tc) 1504{ 1505 std::string path; 1506 1507 int index = 0; 1508 if (!tc->getMemProxy().tryReadString(path, 1509 process->getSyscallArg(tc, index))) { 1510 return -EFAULT; 1511 } 1512 1513 TypedBufferArg<typename OS::timeval [2]> 1514 tp(process->getSyscallArg(tc, index)); 1515 tp.copyIn(tc->getMemProxy()); 1516 1517 struct timeval hostTimeval[2]; 1518 for (int i = 0; i < 2; ++i) 1519 { 1520 hostTimeval[i].tv_sec = TheISA::gtoh((*tp)[i].tv_sec); 1521 hostTimeval[i].tv_usec = TheISA::gtoh((*tp)[i].tv_usec); 1522 } 1523 1524 // Adjust path for current working directory 1525 path = process->fullPath(path); 1526 1527 int result = utimes(path.c_str(), hostTimeval); 1528 1529 if (result < 0) 1530 return -errno; 1531 1532 return 0; 1533} 1534/// Target getrusage() function. 1535template <class OS> 1536SyscallReturn 1537getrusageFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1538 ThreadContext *tc) 1539{ 1540 int index = 0; 1541 int who = process->getSyscallArg(tc, index); // THREAD, SELF, or CHILDREN 1542 TypedBufferArg<typename OS::rusage> rup(process->getSyscallArg(tc, index)); 1543 1544 rup->ru_utime.tv_sec = 0; 1545 rup->ru_utime.tv_usec = 0; 1546 rup->ru_stime.tv_sec = 0; 1547 rup->ru_stime.tv_usec = 0; 1548 rup->ru_maxrss = 0; 1549 rup->ru_ixrss = 0; 1550 rup->ru_idrss = 0; 1551 rup->ru_isrss = 0; 1552 rup->ru_minflt = 0; 1553 rup->ru_majflt = 0; 1554 rup->ru_nswap = 0; 1555 rup->ru_inblock = 0; 1556 rup->ru_oublock = 0; 1557 rup->ru_msgsnd = 0; 1558 rup->ru_msgrcv = 0; 1559 rup->ru_nsignals = 0; 1560 rup->ru_nvcsw = 0; 1561 rup->ru_nivcsw = 0; 1562 1563 switch (who) { 1564 case OS::TGT_RUSAGE_SELF: 1565 getElapsedTimeMicro(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec); 1566 rup->ru_utime.tv_sec = TheISA::htog(rup->ru_utime.tv_sec); 1567 rup->ru_utime.tv_usec = TheISA::htog(rup->ru_utime.tv_usec); 1568 break; 1569 1570 case OS::TGT_RUSAGE_CHILDREN: 1571 // do nothing. We have no child processes, so they take no time. 1572 break; 1573 1574 default: 1575 // don't really handle THREAD or CHILDREN, but just warn and 1576 // plow ahead 1577 warn("getrusage() only supports RUSAGE_SELF. Parameter %d ignored.", 1578 who); 1579 } 1580 1581 rup.copyOut(tc->getMemProxy()); 1582 1583 return 0; 1584} 1585 1586/// Target times() function. 1587template <class OS> 1588SyscallReturn 1589timesFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1590 ThreadContext *tc) 1591{ 1592 int index = 0; 1593 TypedBufferArg<typename OS::tms> bufp(process->getSyscallArg(tc, index)); 1594 1595 // Fill in the time structure (in clocks) 1596 int64_t clocks = curTick() * OS::M5_SC_CLK_TCK / SimClock::Int::s; 1597 bufp->tms_utime = clocks; 1598 bufp->tms_stime = 0; 1599 bufp->tms_cutime = 0; 1600 bufp->tms_cstime = 0; 1601 1602 // Convert to host endianness 1603 bufp->tms_utime = TheISA::htog(bufp->tms_utime); 1604 1605 // Write back 1606 bufp.copyOut(tc->getMemProxy()); 1607 1608 // Return clock ticks since system boot 1609 return clocks; 1610} 1611 1612/// Target time() function. 1613template <class OS> 1614SyscallReturn 1615timeFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1616 ThreadContext *tc) 1617{ 1618 typename OS::time_t sec, usec; 1619 getElapsedTimeMicro(sec, usec); 1620 sec += seconds_since_epoch; 1621 1622 int index = 0; 1623 Addr taddr = (Addr)process->getSyscallArg(tc, index); 1624 if (taddr != 0) { 1625 typename OS::time_t t = sec; 1626 t = TheISA::htog(t); 1627 SETranslatingPortProxy &p = tc->getMemProxy(); 1628 p.writeBlob(taddr, (uint8_t*)&t, (int)sizeof(typename OS::time_t)); 1629 } 1630 return sec; 1631} 1632 1633 1634#endif // __SIM_SYSCALL_EMUL_HH__ 1635