syscall_emul.hh revision 11367:f85d49a098a7
12689Sktlim@umich.edu/* 210282Sdam.sunwoo@arm.com * Copyright (c) 2012-2013, 2015 ARM Limited 38666SPrakash.Ramrakhyani@arm.com * Copyright (c) 2015 Advanced Micro Devices, Inc. 48666SPrakash.Ramrakhyani@arm.com * All rights reserved 58666SPrakash.Ramrakhyani@arm.com * 68666SPrakash.Ramrakhyani@arm.com * The license below extends only to copyright in the software and shall 78666SPrakash.Ramrakhyani@arm.com * not be construed as granting a license to any other intellectual 88666SPrakash.Ramrakhyani@arm.com * property including but not limited to intellectual property relating 98666SPrakash.Ramrakhyani@arm.com * to a hardware implementation of the functionality of the software 108666SPrakash.Ramrakhyani@arm.com * licensed hereunder. You may use the software subject to the license 118666SPrakash.Ramrakhyani@arm.com * terms below provided that you ensure that this notice is replicated 128666SPrakash.Ramrakhyani@arm.com * unmodified and in its entirety in all distributions of the software, 138666SPrakash.Ramrakhyani@arm.com * modified or unmodified, in source code or in binary form. 142689Sktlim@umich.edu * 157897Shestness@cs.utexas.edu * Copyright (c) 2003-2005 The Regents of The University of Michigan 162689Sktlim@umich.edu * All rights reserved. 172689Sktlim@umich.edu * 182689Sktlim@umich.edu * Redistribution and use in source and binary forms, with or without 192689Sktlim@umich.edu * modification, are permitted provided that the following conditions are 202689Sktlim@umich.edu * met: redistributions of source code must retain the above copyright 212689Sktlim@umich.edu * notice, this list of conditions and the following disclaimer; 222689Sktlim@umich.edu * redistributions in binary form must reproduce the above copyright 232689Sktlim@umich.edu * notice, this list of conditions and the following disclaimer in the 242689Sktlim@umich.edu * documentation and/or other materials provided with the distribution; 252689Sktlim@umich.edu * neither the name of the copyright holders nor the names of its 262689Sktlim@umich.edu * contributors may be used to endorse or promote products derived from 272689Sktlim@umich.edu * this software without specific prior written permission. 282689Sktlim@umich.edu * 292689Sktlim@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 302689Sktlim@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 312689Sktlim@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 322689Sktlim@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 332689Sktlim@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 342689Sktlim@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 352689Sktlim@umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 362689Sktlim@umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 372689Sktlim@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 382689Sktlim@umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 392689Sktlim@umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 402689Sktlim@umich.edu * 412689Sktlim@umich.edu * Authors: Steve Reinhardt 422689Sktlim@umich.edu * Kevin Lim 432689Sktlim@umich.edu */ 442689Sktlim@umich.edu 457897Shestness@cs.utexas.edu#ifndef __SIM_SYSCALL_EMUL_HH__ 462689Sktlim@umich.edu#define __SIM_SYSCALL_EMUL_HH__ 472689Sktlim@umich.edu 483960Sgblack@eecs.umich.edu#define NO_STAT64 (defined(__APPLE__) || defined(__OpenBSD__) || \ 494194Ssaidi@eecs.umich.edu defined(__FreeBSD__) || defined(__CYGWIN__) || \ 501070SN/A defined(__NetBSD__)) 511070SN/A 529142Ssteve.reinhardt@amd.com/// 532521SN/A/// @file syscall_emul.hh 548229Snate@binkert.org/// 558232Snate@binkert.org/// This file defines objects used to emulate syscalls from the target 568666SPrakash.Ramrakhyani@arm.com/// application on the host machine. 579293Sandreas.hansson@arm.com 582522SN/A#ifdef __CYGWIN32__ 598769Sgblack@eecs.umich.edu#include <sys/fcntl.h> // for O_BINARY 602037SN/A#endif 618229Snate@binkert.org#include <sys/stat.h> 628769Sgblack@eecs.umich.edu#include <sys/time.h> 6356SN/A#include <sys/uio.h> 646658Snate@binkert.org#include <fcntl.h> 6510494Sandreas.hansson@arm.com 6610494Sandreas.hansson@arm.com#include <cerrno> 6710494Sandreas.hansson@arm.com#include <string> 6810494Sandreas.hansson@arm.com 6910494Sandreas.hansson@arm.com#include "base/chunk_generator.hh" 7010494Sandreas.hansson@arm.com#include "base/intmath.hh" // for RoundUp 7110494Sandreas.hansson@arm.com#include "base/misc.hh" 7210494Sandreas.hansson@arm.com#include "base/trace.hh" 732SN/A#include "base/types.hh" 742107SN/A#include "config/the_isa.hh" 752SN/A#include "cpu/base.hh" 762SN/A#include "cpu/thread_context.hh" 772SN/A#include "debug/SyscallVerbose.hh" 782SN/A#include "mem/page_table.hh" 792SN/A#include "sim/byteswap.hh" 801070SN/A#include "sim/emul_driver.hh" 818703Sandreas.hansson@arm.com#include "sim/process.hh" 828703Sandreas.hansson@arm.com#include "sim/syscall_emul_buf.hh" 838826Snilay@cs.wisc.edu#include "sim/syscallreturn.hh" 842521SN/A#include "sim/system.hh" 859814Sandreas.hansson@arm.com 8610360Sandreas.hansson@arm.com/// 8710360Sandreas.hansson@arm.com/// System call descriptor. 887580SAli.Saidi@arm.com/// 8910037SARM gem5 Developersclass SyscallDesc { 907770SAli.Saidi@ARM.com 9110700Sandreas.hansson@arm.com public: 927914SBrad.Beckmann@amd.com 939814Sandreas.hansson@arm.com /// Typedef for target syscall handler functions. 947914SBrad.Beckmann@amd.com typedef SyscallReturn (*FuncPtr)(SyscallDesc *, int num, 957914SBrad.Beckmann@amd.com LiveProcess *, ThreadContext *); 968666SPrakash.Ramrakhyani@arm.com 977914SBrad.Beckmann@amd.com const char *name; //!< Syscall name (e.g., "open"). 988666SPrakash.Ramrakhyani@arm.com FuncPtr funcPtr; //!< Pointer to emulation function. 997897Shestness@cs.utexas.edu int flags; //!< Flags (see Flags enum). 1002SN/A bool warned; //!< Have we warned about unimplemented syscall? 1011070SN/A 1021070SN/A /// Flag values for controlling syscall behavior. 1031070SN/A enum Flags { 1048769Sgblack@eecs.umich.edu /// Don't set return regs according to funcPtr return value. 1058769Sgblack@eecs.umich.edu /// Used for syscalls with non-standard return conventions 1068769Sgblack@eecs.umich.edu /// that explicitly set the ThreadContext regs (e.g., 1078769Sgblack@eecs.umich.edu /// sigreturn). 1088666SPrakash.Ramrakhyani@arm.com SuppressReturnValue = 1, 1098832SAli.Saidi@ARM.com WarnOnce = 2 1109814Sandreas.hansson@arm.com }; 1119814Sandreas.hansson@arm.com 1129814Sandreas.hansson@arm.com /// Constructor. 1139814Sandreas.hansson@arm.com SyscallDesc(const char *_name, FuncPtr _funcPtr, int _flags = 0) 1149814Sandreas.hansson@arm.com : name(_name), funcPtr(_funcPtr), flags(_flags), warned(false) 1158832SAli.Saidi@ARM.com { 1168832SAli.Saidi@ARM.com } 1178832SAli.Saidi@ARM.com 1188832SAli.Saidi@ARM.com /// Emulate the syscall. Public interface for calling through funcPtr. 1198832SAli.Saidi@ARM.com void doSyscall(int callnum, LiveProcess *proc, ThreadContext *tc); 1208832SAli.Saidi@ARM.com 1218832SAli.Saidi@ARM.com /// Is the WarnOnce flag set? 1228832SAli.Saidi@ARM.com bool warnOnce() const { return (flags & WarnOnce); } 1238832SAli.Saidi@ARM.com}; 1248885SAli.Saidi@ARM.com 1258885SAli.Saidi@ARM.com 1268885SAli.Saidi@ARM.com////////////////////////////////////////////////////////////////////// 1279147Snilay@cs.wisc.edu// 1288885SAli.Saidi@ARM.com// The following emulation functions are generic enough that they 1298885SAli.Saidi@ARM.com// don't need to be recompiled for different emulated OS's. They are 1308885SAli.Saidi@ARM.com// defined in sim/syscall_emul.cc. 1318885SAli.Saidi@ARM.com// 1328885SAli.Saidi@ARM.com////////////////////////////////////////////////////////////////////// 1338885SAli.Saidi@ARM.com 1348885SAli.Saidi@ARM.com 1358885SAli.Saidi@ARM.com/// Handler for unimplemented syscalls that we haven't thought about. 1368885SAli.Saidi@ARM.comSyscallReturn unimplementedFunc(SyscallDesc *desc, int num, 1378885SAli.Saidi@ARM.com LiveProcess *p, ThreadContext *tc); 1388885SAli.Saidi@ARM.com 1398885SAli.Saidi@ARM.com/// Handler for unimplemented syscalls that we never intend to 1408885SAli.Saidi@ARM.com/// implement (signal handling, etc.) and should not affect the correct 1418885SAli.Saidi@ARM.com/// behavior of the program. Print a warning only if the appropriate 1428885SAli.Saidi@ARM.com/// trace flag is enabled. Return success to the target program. 1438885SAli.Saidi@ARM.comSyscallReturn ignoreFunc(SyscallDesc *desc, int num, 1448885SAli.Saidi@ARM.com LiveProcess *p, ThreadContext *tc); 1458885SAli.Saidi@ARM.com 1468885SAli.Saidi@ARM.com/// Target exit() handler: terminate current context. 1478885SAli.Saidi@ARM.comSyscallReturn exitFunc(SyscallDesc *desc, int num, 1488885SAli.Saidi@ARM.com LiveProcess *p, ThreadContext *tc); 1498885SAli.Saidi@ARM.com 1508885SAli.Saidi@ARM.com/// Target exit_group() handler: terminate simulation. (exit all threads) 1518885SAli.Saidi@ARM.comSyscallReturn exitGroupFunc(SyscallDesc *desc, int num, 1528885SAli.Saidi@ARM.com LiveProcess *p, ThreadContext *tc); 1538885SAli.Saidi@ARM.com 1548885SAli.Saidi@ARM.com/// Target getpagesize() handler. 1558885SAli.Saidi@ARM.comSyscallReturn getpagesizeFunc(SyscallDesc *desc, int num, 1568885SAli.Saidi@ARM.com LiveProcess *p, ThreadContext *tc); 1578885SAli.Saidi@ARM.com 1588885SAli.Saidi@ARM.com/// Target brk() handler: set brk address. 1598885SAli.Saidi@ARM.comSyscallReturn brkFunc(SyscallDesc *desc, int num, 1608885SAli.Saidi@ARM.com LiveProcess *p, ThreadContext *tc); 1618885SAli.Saidi@ARM.com 1629053Sdam.sunwoo@arm.com/// Target close() handler. 1639053Sdam.sunwoo@arm.comSyscallReturn closeFunc(SyscallDesc *desc, int num, 1649053Sdam.sunwoo@arm.com LiveProcess *p, ThreadContext *tc); 1652SN/A 1662SN/A/// Target read() handler. 1672SN/ASyscallReturn readFunc(SyscallDesc *desc, int num, 1682SN/A LiveProcess *p, ThreadContext *tc); 1691070SN/A 1701070SN/A/// Target write() handler. 1718666SPrakash.Ramrakhyani@arm.comSyscallReturn writeFunc(SyscallDesc *desc, int num, 1728666SPrakash.Ramrakhyani@arm.com LiveProcess *p, ThreadContext *tc); 1738666SPrakash.Ramrakhyani@arm.com 1742SN/A/// Target lseek() handler. 1752SN/ASyscallReturn lseekFunc(SyscallDesc *desc, int num, 1768706Sandreas.hansson@arm.com LiveProcess *p, ThreadContext *tc); 1778706Sandreas.hansson@arm.com 1788706Sandreas.hansson@arm.com/// Target _llseek() handler. 1798706Sandreas.hansson@arm.comSyscallReturn _llseekFunc(SyscallDesc *desc, int num, 1808706Sandreas.hansson@arm.com LiveProcess *p, ThreadContext *tc); 1818706Sandreas.hansson@arm.com 1828706Sandreas.hansson@arm.com/// Target munmap() handler. 1838706Sandreas.hansson@arm.comSyscallReturn munmapFunc(SyscallDesc *desc, int num, 1849294Sandreas.hansson@arm.com LiveProcess *p, ThreadContext *tc); 1859294Sandreas.hansson@arm.com 1868703Sandreas.hansson@arm.com/// Target gethostname() handler. 1878703Sandreas.hansson@arm.comSyscallReturn gethostnameFunc(SyscallDesc *desc, int num, 1888922Swilliam.wang@arm.com LiveProcess *p, ThreadContext *tc); 1898703Sandreas.hansson@arm.com 1908703Sandreas.hansson@arm.com/// Target getcwd() handler. 1912901Ssaidi@eecs.umich.eduSyscallReturn getcwdFunc(SyscallDesc *desc, int num, 1924762Snate@binkert.org LiveProcess *p, ThreadContext *tc); 1932901Ssaidi@eecs.umich.edu 1949342SAndreas.Sandberg@arm.com/// Target readlink() handler. 1952901Ssaidi@eecs.umich.eduSyscallReturn readlinkFunc(SyscallDesc *desc, int num, 1962901Ssaidi@eecs.umich.edu LiveProcess *p, ThreadContext *tc, 1972901Ssaidi@eecs.umich.edu int index = 0); 1983960Sgblack@eecs.umich.eduSyscallReturn readlinkFunc(SyscallDesc *desc, int num, 1993960Sgblack@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 2004095Sbinkertn@umich.edu 2014095Sbinkertn@umich.edu/// Target unlink() handler. 2024095Sbinkertn@umich.eduSyscallReturn unlinkHelper(SyscallDesc *desc, int num, 2033960Sgblack@eecs.umich.edu LiveProcess *p, ThreadContext *tc, 2043960Sgblack@eecs.umich.edu int index); 2057445Ssteve.reinhardt@amd.comSyscallReturn unlinkFunc(SyscallDesc *desc, int num, 2067445Ssteve.reinhardt@amd.com LiveProcess *p, ThreadContext *tc); 2077445Ssteve.reinhardt@amd.com 2087445Ssteve.reinhardt@amd.com/// Target mkdir() handler. 2097445Ssteve.reinhardt@amd.comSyscallReturn mkdirFunc(SyscallDesc *desc, int num, 2107445Ssteve.reinhardt@amd.com LiveProcess *p, ThreadContext *tc); 2117445Ssteve.reinhardt@amd.com 212180SN/A/// Target rename() handler. 2135718Shsul@eecs.umich.eduSyscallReturn renameFunc(SyscallDesc *desc, int num, 2142SN/A LiveProcess *p, ThreadContext *tc); 2155712Shsul@eecs.umich.edu 2165718Shsul@eecs.umich.edu 2175718Shsul@eecs.umich.edu/// Target truncate() handler. 2185718Shsul@eecs.umich.eduSyscallReturn truncateFunc(SyscallDesc *desc, int num, 2195718Shsul@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 2205718Shsul@eecs.umich.edu 2215718Shsul@eecs.umich.edu 2225718Shsul@eecs.umich.edu/// Target ftruncate() handler. 2235718Shsul@eecs.umich.eduSyscallReturn ftruncateFunc(SyscallDesc *desc, int num, 2245718Shsul@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 2255718Shsul@eecs.umich.edu 2265718Shsul@eecs.umich.edu 2275718Shsul@eecs.umich.edu/// Target truncate64() handler. 2281806SN/ASyscallReturn truncate64Func(SyscallDesc *desc, int num, 2291806SN/A LiveProcess *p, ThreadContext *tc); 2302680Sktlim@umich.edu 2315823Ssaidi@eecs.umich.edu/// Target ftruncate64() handler. 2321806SN/ASyscallReturn ftruncate64Func(SyscallDesc *desc, int num, 2332680Sktlim@umich.edu LiveProcess *p, ThreadContext *tc); 2345714Shsul@eecs.umich.edu 2351070SN/A 2369850Sandreas.hansson@arm.com/// Target umask() handler. 2375512SMichael.Adler@intel.comSyscallReturn umaskFunc(SyscallDesc *desc, int num, 2387445Ssteve.reinhardt@amd.com LiveProcess *p, ThreadContext *tc); 2394095Sbinkertn@umich.edu 2405512SMichael.Adler@intel.com 2414095Sbinkertn@umich.edu/// Target chown() handler. 2427445Ssteve.reinhardt@amd.comSyscallReturn chownFunc(SyscallDesc *desc, int num, 2434095Sbinkertn@umich.edu LiveProcess *p, ThreadContext *tc); 2444095Sbinkertn@umich.edu 2451070SN/A 2464095Sbinkertn@umich.edu/// Target fchown() handler. 2474095Sbinkertn@umich.eduSyscallReturn fchownFunc(SyscallDesc *desc, int num, 2484095Sbinkertn@umich.edu LiveProcess *p, ThreadContext *tc); 2494095Sbinkertn@umich.edu 2504095Sbinkertn@umich.edu/// Target dup() handler. 2511070SN/ASyscallReturn dupFunc(SyscallDesc *desc, int num, 2529850Sandreas.hansson@arm.com LiveProcess *process, ThreadContext *tc); 2531070SN/A 2547914SBrad.Beckmann@amd.com/// Target fnctl() handler. 2557914SBrad.Beckmann@amd.comSyscallReturn fcntlFunc(SyscallDesc *desc, int num, 2561806SN/A LiveProcess *process, ThreadContext *tc); 257180SN/A 25875SN/A/// Target fcntl64() handler. 2596029Ssteve.reinhardt@amd.comSyscallReturn fcntl64Func(SyscallDesc *desc, int num, 2606029Ssteve.reinhardt@amd.com LiveProcess *process, ThreadContext *tc); 2616029Ssteve.reinhardt@amd.com 2626029Ssteve.reinhardt@amd.com/// Target setuid() handler. 2636029Ssteve.reinhardt@amd.comSyscallReturn setuidFunc(SyscallDesc *desc, int num, 2646029Ssteve.reinhardt@amd.com LiveProcess *p, ThreadContext *tc); 2656029Ssteve.reinhardt@amd.com 2666029Ssteve.reinhardt@amd.com/// Target getpid() handler. 2676029Ssteve.reinhardt@amd.comSyscallReturn getpidFunc(SyscallDesc *desc, int num, 2686029Ssteve.reinhardt@amd.com LiveProcess *p, ThreadContext *tc); 2696029Ssteve.reinhardt@amd.com 270180SN/A/// Target getuid() handler. 2717733SAli.Saidi@ARM.comSyscallReturn getuidFunc(SyscallDesc *desc, int num, 2721129SN/A LiveProcess *p, ThreadContext *tc); 2738769Sgblack@eecs.umich.edu 2749172Snilay@cs.wisc.edu/// Target getgid() handler. 2758769Sgblack@eecs.umich.eduSyscallReturn getgidFunc(SyscallDesc *desc, int num, 2768799Sgblack@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 2778799Sgblack@eecs.umich.edu 2788799Sgblack@eecs.umich.edu/// Target getppid() handler. 2798799Sgblack@eecs.umich.eduSyscallReturn getppidFunc(SyscallDesc *desc, int num, 2808799Sgblack@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 2818885SAli.Saidi@ARM.com 28210282Sdam.sunwoo@arm.com/// Target geteuid() handler. 28310282Sdam.sunwoo@arm.comSyscallReturn geteuidFunc(SyscallDesc *desc, int num, 28410282Sdam.sunwoo@arm.com LiveProcess *p, ThreadContext *tc); 28510282Sdam.sunwoo@arm.com 28610282Sdam.sunwoo@arm.com/// Target getegid() handler. 28710282Sdam.sunwoo@arm.comSyscallReturn getegidFunc(SyscallDesc *desc, int num, 28810282Sdam.sunwoo@arm.com LiveProcess *p, ThreadContext *tc); 28910282Sdam.sunwoo@arm.com 29010282Sdam.sunwoo@arm.com/// Target clone() handler. 29110282Sdam.sunwoo@arm.comSyscallReturn cloneFunc(SyscallDesc *desc, int num, 29210282Sdam.sunwoo@arm.com LiveProcess *p, ThreadContext *tc); 29310282Sdam.sunwoo@arm.com 29410282Sdam.sunwoo@arm.com/// Target access() handler 2959187SKrishnendra.Nathella@arm.comSyscallReturn accessFunc(SyscallDesc *desc, int num, 2968799Sgblack@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 29710037SARM gem5 DevelopersSyscallReturn accessFunc(SyscallDesc *desc, int num, 2988706Sandreas.hansson@arm.com LiveProcess *p, ThreadContext *tc, 2998799Sgblack@eecs.umich.edu int index); 3008799Sgblack@eecs.umich.edu 3018799Sgblack@eecs.umich.edu/// Futex system call 3028799Sgblack@eecs.umich.edu/// Implemented by Daniel Sanchez 3038799Sgblack@eecs.umich.edu/// Used by printf's in multi-threaded apps 3048706Sandreas.hansson@arm.comtemplate <class OS> 3058706Sandreas.hansson@arm.comSyscallReturn 3068706Sandreas.hansson@arm.comfutexFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 3071129SN/A ThreadContext *tc) 3081129SN/A{ 3091129SN/A int index_uaddr = 0; 3105713Shsul@eecs.umich.edu int index_op = 1; 311180SN/A int index_val = 2; 3125713Shsul@eecs.umich.edu int index_timeout = 3; 3132680Sktlim@umich.edu 3145713Shsul@eecs.umich.edu uint64_t uaddr = process->getSyscallArg(tc, index_uaddr); 315180SN/A int op = process->getSyscallArg(tc, index_op); 316180SN/A int val = process->getSyscallArg(tc, index_val); 3175713Shsul@eecs.umich.edu uint64_t timeout = process->getSyscallArg(tc, index_timeout); 3185713Shsul@eecs.umich.edu 3195713Shsul@eecs.umich.edu std::map<uint64_t, std::list<ThreadContext *> * > 3202SN/A &futex_map = tc->getSystemPtr()->futexMap; 3212SN/A 3222378SN/A DPRINTF(SyscallVerbose, "In sys_futex: Address=%llx, op=%d, val=%d\n", 3238601Ssteve.reinhardt@amd.com uaddr, op, val); 3242378SN/A 32510318Sandreas.hansson@arm.com op &= ~OS::TGT_FUTEX_PRIVATE_FLAG; 3268601Ssteve.reinhardt@amd.com 32710553Salexandru.dutu@amd.com if (op == OS::TGT_FUTEX_WAIT) { 32810553Salexandru.dutu@amd.com if (timeout != 0) { 32910553Salexandru.dutu@amd.com warn("sys_futex: FUTEX_WAIT with non-null timeout unimplemented;" 33010553Salexandru.dutu@amd.com "we'll wait indefinitely"); 33110553Salexandru.dutu@amd.com } 33210553Salexandru.dutu@amd.com 33310553Salexandru.dutu@amd.com uint8_t *buf = new uint8_t[sizeof(int)]; 33410553Salexandru.dutu@amd.com tc->getMemProxy().readBlob((Addr)uaddr, buf, (int)sizeof(int)); 33510553Salexandru.dutu@amd.com int mem_val = *((int *)buf); 33610553Salexandru.dutu@amd.com delete[] buf; 33710318Sandreas.hansson@arm.com 3383162Ssaidi@eecs.umich.edu if (val != mem_val) { 3392378SN/A DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAKE, read: %d, " 3402378SN/A "expected: %d\n", mem_val, val); 3415795Ssaidi@eecs.umich.edu return -OS::TGT_EWOULDBLOCK; 3425795Ssaidi@eecs.umich.edu } 3438931Sandreas.hansson@arm.com 3445795Ssaidi@eecs.umich.edu // Queue the thread context 3458931Sandreas.hansson@arm.com std::list<ThreadContext *> * tcWaitList; 3465795Ssaidi@eecs.umich.edu if (futex_map.count(uaddr)) { 3475795Ssaidi@eecs.umich.edu tcWaitList = futex_map.find(uaddr)->second; 3485795Ssaidi@eecs.umich.edu } else { 3498931Sandreas.hansson@arm.com tcWaitList = new std::list<ThreadContext *>(); 3505795Ssaidi@eecs.umich.edu futex_map.insert(std::pair< uint64_t, 35110318Sandreas.hansson@arm.com std::list<ThreadContext *> * >(uaddr, tcWaitList)); 3525795Ssaidi@eecs.umich.edu } 3535795Ssaidi@eecs.umich.edu tcWaitList->push_back(tc); 3548460SAli.Saidi@ARM.com DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAIT, suspending calling " 3558931Sandreas.hansson@arm.com "thread context\n"); 3568460SAli.Saidi@ARM.com tc->suspend(); 3578931Sandreas.hansson@arm.com return 0; 3588460SAli.Saidi@ARM.com } else if (op == OS::TGT_FUTEX_WAKE){ 3598460SAli.Saidi@ARM.com int wokenUp = 0; 3609342SAndreas.Sandberg@arm.com std::list<ThreadContext *> * tcWaitList; 3619342SAndreas.Sandberg@arm.com if (futex_map.count(uaddr)) { 3629342SAndreas.Sandberg@arm.com tcWaitList = futex_map.find(uaddr)->second; 3639342SAndreas.Sandberg@arm.com while (tcWaitList->size() > 0 && wokenUp < val) { 3649342SAndreas.Sandberg@arm.com tcWaitList->front()->activate(); 3659342SAndreas.Sandberg@arm.com tcWaitList->pop_front(); 3669342SAndreas.Sandberg@arm.com wokenUp++; 3671070SN/A } 3689342SAndreas.Sandberg@arm.com if (tcWaitList->empty()) { 3697897Shestness@cs.utexas.edu futex_map.erase(uaddr); 3709342SAndreas.Sandberg@arm.com delete tcWaitList; 3717897Shestness@cs.utexas.edu } 3727897Shestness@cs.utexas.edu } 3737897Shestness@cs.utexas.edu DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAKE, activated %d waiting " 3747897Shestness@cs.utexas.edu "thread contexts\n", wokenUp); 3751070SN/A return wokenUp; 3761070SN/A } else { 3778769Sgblack@eecs.umich.edu warn("sys_futex: op %d is not implemented, just returning...", op); 3788769Sgblack@eecs.umich.edu return 0; 3797770SAli.Saidi@ARM.com } 3807770SAli.Saidi@ARM.com 3819292Sandreas.hansson@arm.com} 3829293Sandreas.hansson@arm.com 3839293Sandreas.hansson@arm.com 3849293Sandreas.hansson@arm.com/// Pseudo Funcs - These functions use a different return convension, 3859293Sandreas.hansson@arm.com/// returning a second value in a register other than the normal return register 3861070SN/ASyscallReturn pipePseudoFunc(SyscallDesc *desc, int num, 3871070SN/A LiveProcess *process, ThreadContext *tc); 3881070SN/A 3891070SN/A/// Target getpidPseudo() handler. 3901070SN/ASyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num, 3911070SN/A LiveProcess *p, ThreadContext *tc); 3928769Sgblack@eecs.umich.edu 3938769Sgblack@eecs.umich.edu/// Target getuidPseudo() handler. 3947770SAli.Saidi@ARM.comSyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num, 3957770SAli.Saidi@ARM.com LiveProcess *p, ThreadContext *tc); 3969292Sandreas.hansson@arm.com 3979293Sandreas.hansson@arm.com/// Target getgidPseudo() handler. 3989293Sandreas.hansson@arm.comSyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num, 3999293Sandreas.hansson@arm.com LiveProcess *p, ThreadContext *tc); 4001070SN/A 4012SN/A 4022SN/A/// A readable name for 1,000,000, for converting microseconds to seconds. 4038666SPrakash.Ramrakhyani@arm.comconst int one_million = 1000000; 4048666SPrakash.Ramrakhyani@arm.com/// A readable name for 1,000,000,000, for converting nanoseconds to seconds. 4058666SPrakash.Ramrakhyani@arm.comconst int one_billion = 1000000000; 4068666SPrakash.Ramrakhyani@arm.com 4078666SPrakash.Ramrakhyani@arm.com/// Approximate seconds since the epoch (1/1/1970). About a billion, 4088666SPrakash.Ramrakhyani@arm.com/// by my reckoning. We want to keep this a constant (not use the 4098666SPrakash.Ramrakhyani@arm.com/// real-world time) to keep simulations repeatable. 4108666SPrakash.Ramrakhyani@arm.comconst unsigned seconds_since_epoch = 1000000000; 4118666SPrakash.Ramrakhyani@arm.com 4128666SPrakash.Ramrakhyani@arm.com/// Helper function to convert current elapsed time to seconds and 4138666SPrakash.Ramrakhyani@arm.com/// microseconds. 4148666SPrakash.Ramrakhyani@arm.comtemplate <class T1, class T2> 4158666SPrakash.Ramrakhyani@arm.comvoid 4168666SPrakash.Ramrakhyani@arm.comgetElapsedTimeMicro(T1 &sec, T2 &usec) 4178666SPrakash.Ramrakhyani@arm.com{ 4188666SPrakash.Ramrakhyani@arm.com uint64_t elapsed_usecs = curTick() / SimClock::Int::us; 4198666SPrakash.Ramrakhyani@arm.com sec = elapsed_usecs / one_million; 4208666SPrakash.Ramrakhyani@arm.com usec = elapsed_usecs % one_million; 4218666SPrakash.Ramrakhyani@arm.com} 4228666SPrakash.Ramrakhyani@arm.com 4238666SPrakash.Ramrakhyani@arm.com/// Helper function to convert current elapsed time to seconds and 4248666SPrakash.Ramrakhyani@arm.com/// nanoseconds. 4258666SPrakash.Ramrakhyani@arm.comtemplate <class T1, class T2> 4268666SPrakash.Ramrakhyani@arm.comvoid 4278666SPrakash.Ramrakhyani@arm.comgetElapsedTimeNano(T1 &sec, T2 &nsec) 4288666SPrakash.Ramrakhyani@arm.com{ 4298666SPrakash.Ramrakhyani@arm.com uint64_t elapsed_nsecs = curTick() / SimClock::Int::ns; 4308666SPrakash.Ramrakhyani@arm.com sec = elapsed_nsecs / one_billion; 4318666SPrakash.Ramrakhyani@arm.com nsec = elapsed_nsecs % one_billion; 4328666SPrakash.Ramrakhyani@arm.com} 4338666SPrakash.Ramrakhyani@arm.com 4342SN/A////////////////////////////////////////////////////////////////////// 4352SN/A// 43610375Sandreas.hansson@arm.com// The following emulation functions are generic, but need to be 43710375Sandreas.hansson@arm.com// templated to account for differences in types, constants, etc. 4382SN/A// 4392SN/A////////////////////////////////////////////////////////////////////// 4402SN/A 4412SN/A#if NO_STAT64 4422SN/A typedef struct stat hst_stat; 4432SN/A typedef struct stat hst_stat64; 44410375Sandreas.hansson@arm.com#else 44510375Sandreas.hansson@arm.com typedef struct stat hst_stat; 4462SN/A typedef struct stat64 hst_stat64; 4472SN/A#endif 4482SN/A 4492SN/A//// Helper function to convert a host stat buffer to a target stat 4502SN/A//// buffer. Also copies the target buffer out to the simulated 4512SN/A//// memory space. Used by stat(), fstat(), and lstat(). 4522SN/A 4532SN/Atemplate <typename target_stat, typename host_stat> 4548832SAli.Saidi@ARM.comstatic void 4558832SAli.Saidi@ARM.comconvertStatBuf(target_stat &tgt, host_stat *host, bool fakeTTY = false) 4568832SAli.Saidi@ARM.com{ 4578832SAli.Saidi@ARM.com using namespace TheISA; 4589142Ssteve.reinhardt@amd.com 4598832SAli.Saidi@ARM.com if (fakeTTY) 4608832SAli.Saidi@ARM.com tgt->st_dev = 0xA; 4618832SAli.Saidi@ARM.com else 4628832SAli.Saidi@ARM.com tgt->st_dev = host->st_dev; 4638832SAli.Saidi@ARM.com tgt->st_dev = TheISA::htog(tgt->st_dev); 4648832SAli.Saidi@ARM.com tgt->st_ino = host->st_ino; 4658832SAli.Saidi@ARM.com tgt->st_ino = TheISA::htog(tgt->st_ino); 4668832SAli.Saidi@ARM.com tgt->st_mode = host->st_mode; 4678832SAli.Saidi@ARM.com if (fakeTTY) { 4688986SAli.Saidi@ARM.com // Claim to be a character device 4698986SAli.Saidi@ARM.com tgt->st_mode &= ~S_IFMT; // Clear S_IFMT 4708986SAli.Saidi@ARM.com tgt->st_mode |= S_IFCHR; // Set S_IFCHR 4718832SAli.Saidi@ARM.com } 47210367SAndrew.Bardsley@arm.com tgt->st_mode = TheISA::htog(tgt->st_mode); 47310367SAndrew.Bardsley@arm.com tgt->st_nlink = host->st_nlink; 47410367SAndrew.Bardsley@arm.com tgt->st_nlink = TheISA::htog(tgt->st_nlink); 47510367SAndrew.Bardsley@arm.com tgt->st_uid = host->st_uid; 4768832SAli.Saidi@ARM.com tgt->st_uid = TheISA::htog(tgt->st_uid); 4778832SAli.Saidi@ARM.com tgt->st_gid = host->st_gid; 4788832SAli.Saidi@ARM.com tgt->st_gid = TheISA::htog(tgt->st_gid); 4798832SAli.Saidi@ARM.com if (fakeTTY) 4808832SAli.Saidi@ARM.com tgt->st_rdev = 0x880d; 4818832SAli.Saidi@ARM.com else 4828832SAli.Saidi@ARM.com tgt->st_rdev = host->st_rdev; 4838832SAli.Saidi@ARM.com tgt->st_rdev = TheISA::htog(tgt->st_rdev); 4848832SAli.Saidi@ARM.com tgt->st_size = host->st_size; 4858832SAli.Saidi@ARM.com tgt->st_size = TheISA::htog(tgt->st_size); 4868832SAli.Saidi@ARM.com tgt->st_atimeX = host->st_atime; 4878832SAli.Saidi@ARM.com tgt->st_atimeX = TheISA::htog(tgt->st_atimeX); 4888832SAli.Saidi@ARM.com tgt->st_mtimeX = host->st_mtime; 4898832SAli.Saidi@ARM.com tgt->st_mtimeX = TheISA::htog(tgt->st_mtimeX); 4908832SAli.Saidi@ARM.com tgt->st_ctimeX = host->st_ctime; 4914762Snate@binkert.org tgt->st_ctimeX = TheISA::htog(tgt->st_ctimeX); 4924762Snate@binkert.org // Force the block size to be 8k. This helps to ensure buffered io works 4932424SN/A // consistently across different hosts. 4945530Snate@binkert.org tgt->st_blksize = 0x2000; 4952424SN/A tgt->st_blksize = TheISA::htog(tgt->st_blksize); 496 tgt->st_blocks = host->st_blocks; 497 tgt->st_blocks = TheISA::htog(tgt->st_blocks); 498} 499 500// Same for stat64 501 502template <typename target_stat, typename host_stat64> 503static void 504convertStat64Buf(target_stat &tgt, host_stat64 *host, bool fakeTTY = false) 505{ 506 using namespace TheISA; 507 508 convertStatBuf<target_stat, host_stat64>(tgt, host, fakeTTY); 509#if defined(STAT_HAVE_NSEC) 510 tgt->st_atime_nsec = host->st_atime_nsec; 511 tgt->st_atime_nsec = TheISA::htog(tgt->st_atime_nsec); 512 tgt->st_mtime_nsec = host->st_mtime_nsec; 513 tgt->st_mtime_nsec = TheISA::htog(tgt->st_mtime_nsec); 514 tgt->st_ctime_nsec = host->st_ctime_nsec; 515 tgt->st_ctime_nsec = TheISA::htog(tgt->st_ctime_nsec); 516#else 517 tgt->st_atime_nsec = 0; 518 tgt->st_mtime_nsec = 0; 519 tgt->st_ctime_nsec = 0; 520#endif 521} 522 523//Here are a couple convenience functions 524template<class OS> 525static void 526copyOutStatBuf(SETranslatingPortProxy &mem, Addr addr, 527 hst_stat *host, bool fakeTTY = false) 528{ 529 typedef TypedBufferArg<typename OS::tgt_stat> tgt_stat_buf; 530 tgt_stat_buf tgt(addr); 531 convertStatBuf<tgt_stat_buf, hst_stat>(tgt, host, fakeTTY); 532 tgt.copyOut(mem); 533} 534 535template<class OS> 536static void 537copyOutStat64Buf(SETranslatingPortProxy &mem, Addr addr, 538 hst_stat64 *host, bool fakeTTY = false) 539{ 540 typedef TypedBufferArg<typename OS::tgt_stat64> tgt_stat_buf; 541 tgt_stat_buf tgt(addr); 542 convertStat64Buf<tgt_stat_buf, hst_stat64>(tgt, host, fakeTTY); 543 tgt.copyOut(mem); 544} 545 546/// Target ioctl() handler. For the most part, programs call ioctl() 547/// only to find out if their stdout is a tty, to determine whether to 548/// do line or block buffering. We always claim that output fds are 549/// not TTYs to provide repeatable results. 550template <class OS> 551SyscallReturn 552ioctlFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 553 ThreadContext *tc) 554{ 555 int index = 0; 556 int tgt_fd = process->getSyscallArg(tc, index); 557 unsigned req = process->getSyscallArg(tc, index); 558 559 DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", tgt_fd, req); 560 561 FDEntry *fde = process->getFDEntry(tgt_fd); 562 563 if (fde == NULL) { 564 // doesn't map to any simulator fd: not a valid target fd 565 return -EBADF; 566 } 567 568 if (fde->driver != NULL) { 569 return fde->driver->ioctl(process, tc, req); 570 } 571 572 if (OS::isTtyReq(req)) { 573 return -ENOTTY; 574 } 575 576 warn("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ \n", 577 tgt_fd, req, tc->pcState()); 578 return -ENOTTY; 579} 580 581template <class OS> 582static SyscallReturn 583openFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 584 ThreadContext *tc, int index) 585{ 586 std::string path; 587 588 if (!tc->getMemProxy().tryReadString(path, 589 process->getSyscallArg(tc, index))) 590 return -EFAULT; 591 592 int tgtFlags = process->getSyscallArg(tc, index); 593 int mode = process->getSyscallArg(tc, index); 594 int hostFlags = 0; 595 596 // translate open flags 597 for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) { 598 if (tgtFlags & OS::openFlagTable[i].tgtFlag) { 599 tgtFlags &= ~OS::openFlagTable[i].tgtFlag; 600 hostFlags |= OS::openFlagTable[i].hostFlag; 601 } 602 } 603 604 // any target flags left? 605 if (tgtFlags != 0) 606 warn("Syscall: open: cannot decode flags 0x%x", tgtFlags); 607 608#ifdef __CYGWIN32__ 609 hostFlags |= O_BINARY; 610#endif 611 612 // Adjust path for current working directory 613 path = process->fullPath(path); 614 615 DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str()); 616 617 if (startswith(path, "/dev/")) { 618 std::string filename = path.substr(strlen("/dev/")); 619 if (filename == "sysdev0") { 620 // This is a memory-mapped high-resolution timer device on Alpha. 621 // We don't support it, so just punt. 622 warn("Ignoring open(%s, ...)\n", path); 623 return -ENOENT; 624 } 625 626 EmulatedDriver *drv = process->findDriver(filename); 627 if (drv != NULL) { 628 // the driver's open method will allocate a fd from the 629 // process if necessary. 630 return drv->open(process, tc, mode, hostFlags); 631 } 632 633 // fall through here for pass through to host devices, such as 634 // /dev/zero 635 } 636 637 int fd; 638 int local_errno; 639 if (startswith(path, "/proc/") || startswith(path, "/system/") || 640 startswith(path, "/platform/") || startswith(path, "/sys/")) { 641 // It's a proc/sys entry and requires special handling 642 fd = OS::openSpecialFile(path, process, tc); 643 local_errno = ENOENT; 644 } else { 645 // open the file 646 fd = open(path.c_str(), hostFlags, mode); 647 local_errno = errno; 648 } 649 650 if (fd == -1) 651 return -local_errno; 652 653 return process->allocFD(fd, path.c_str(), hostFlags, mode, false); 654} 655 656/// Target open() handler. 657template <class OS> 658SyscallReturn 659openFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 660 ThreadContext *tc) 661{ 662 return openFunc<OS>(desc, callnum, process, tc, 0); 663} 664 665/// Target openat() handler. 666template <class OS> 667SyscallReturn 668openatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 669 ThreadContext *tc) 670{ 671 int index = 0; 672 int dirfd = process->getSyscallArg(tc, index); 673 if (dirfd != OS::TGT_AT_FDCWD) 674 warn("openat: first argument not AT_FDCWD; unlikely to work"); 675 return openFunc<OS>(desc, callnum, process, tc, 1); 676} 677 678/// Target unlinkat() handler. 679template <class OS> 680SyscallReturn 681unlinkatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 682 ThreadContext *tc) 683{ 684 int index = 0; 685 int dirfd = process->getSyscallArg(tc, index); 686 if (dirfd != OS::TGT_AT_FDCWD) 687 warn("unlinkat: first argument not AT_FDCWD; unlikely to work"); 688 689 return unlinkHelper(desc, callnum, process, tc, 1); 690} 691 692/// Target facessat() handler 693template <class OS> 694SyscallReturn 695faccessatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 696 ThreadContext *tc) 697{ 698 int index = 0; 699 int dirfd = process->getSyscallArg(tc, index); 700 if (dirfd != OS::TGT_AT_FDCWD) 701 warn("faccessat: first argument not AT_FDCWD; unlikely to work"); 702 return accessFunc(desc, callnum, process, tc, 1); 703} 704 705/// Target readlinkat() handler 706template <class OS> 707SyscallReturn 708readlinkatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 709 ThreadContext *tc) 710{ 711 int index = 0; 712 int dirfd = process->getSyscallArg(tc, index); 713 if (dirfd != OS::TGT_AT_FDCWD) 714 warn("openat: first argument not AT_FDCWD; unlikely to work"); 715 return readlinkFunc(desc, callnum, process, tc, 1); 716} 717 718/// Target renameat() handler. 719template <class OS> 720SyscallReturn 721renameatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 722 ThreadContext *tc) 723{ 724 int index = 0; 725 726 int olddirfd = process->getSyscallArg(tc, index); 727 if (olddirfd != OS::TGT_AT_FDCWD) 728 warn("renameat: first argument not AT_FDCWD; unlikely to work"); 729 730 std::string old_name; 731 732 if (!tc->getMemProxy().tryReadString(old_name, 733 process->getSyscallArg(tc, index))) 734 return -EFAULT; 735 736 int newdirfd = process->getSyscallArg(tc, index); 737 if (newdirfd != OS::TGT_AT_FDCWD) 738 warn("renameat: third argument not AT_FDCWD; unlikely to work"); 739 740 std::string new_name; 741 742 if (!tc->getMemProxy().tryReadString(new_name, 743 process->getSyscallArg(tc, index))) 744 return -EFAULT; 745 746 // Adjust path for current working directory 747 old_name = process->fullPath(old_name); 748 new_name = process->fullPath(new_name); 749 750 int result = rename(old_name.c_str(), new_name.c_str()); 751 return (result == -1) ? -errno : result; 752} 753 754/// Target sysinfo() handler. 755template <class OS> 756SyscallReturn 757sysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 758 ThreadContext *tc) 759{ 760 761 int index = 0; 762 TypedBufferArg<typename OS::tgt_sysinfo> 763 sysinfo(process->getSyscallArg(tc, index)); 764 765 sysinfo->uptime=seconds_since_epoch; 766 sysinfo->totalram=process->system->memSize(); 767 768 sysinfo.copyOut(tc->getMemProxy()); 769 770 return 0; 771} 772 773/// Target chmod() handler. 774template <class OS> 775SyscallReturn 776chmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 777 ThreadContext *tc) 778{ 779 std::string path; 780 781 int index = 0; 782 if (!tc->getMemProxy().tryReadString(path, 783 process->getSyscallArg(tc, index))) { 784 return -EFAULT; 785 } 786 787 uint32_t mode = process->getSyscallArg(tc, index); 788 mode_t hostMode = 0; 789 790 // XXX translate mode flags via OS::something??? 791 hostMode = mode; 792 793 // Adjust path for current working directory 794 path = process->fullPath(path); 795 796 // do the chmod 797 int result = chmod(path.c_str(), hostMode); 798 if (result < 0) 799 return -errno; 800 801 return 0; 802} 803 804 805/// Target fchmod() handler. 806template <class OS> 807SyscallReturn 808fchmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 809 ThreadContext *tc) 810{ 811 int index = 0; 812 int tgt_fd = process->getSyscallArg(tc, index); 813 uint32_t mode = process->getSyscallArg(tc, index); 814 815 int sim_fd = process->getSimFD(tgt_fd); 816 if (sim_fd < 0) 817 return -EBADF; 818 819 mode_t hostMode = 0; 820 821 // XXX translate mode flags via OS::someting??? 822 hostMode = mode; 823 824 // do the fchmod 825 int result = fchmod(sim_fd, hostMode); 826 if (result < 0) 827 return -errno; 828 829 return 0; 830} 831 832/// Target mremap() handler. 833template <class OS> 834SyscallReturn 835mremapFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) 836{ 837 int index = 0; 838 Addr start = process->getSyscallArg(tc, index); 839 uint64_t old_length = process->getSyscallArg(tc, index); 840 uint64_t new_length = process->getSyscallArg(tc, index); 841 uint64_t flags = process->getSyscallArg(tc, index); 842 uint64_t provided_address = 0; 843 bool use_provided_address = flags & OS::TGT_MREMAP_FIXED; 844 845 if (use_provided_address) 846 provided_address = process->getSyscallArg(tc, index); 847 848 if ((start % TheISA::PageBytes != 0) || 849 (provided_address % TheISA::PageBytes != 0)) { 850 warn("mremap failing: arguments not page aligned"); 851 return -EINVAL; 852 } 853 854 new_length = roundUp(new_length, TheISA::PageBytes); 855 856 if (new_length > old_length) { 857 if ((start + old_length) == process->mmap_end && 858 (!use_provided_address || provided_address == start)) { 859 uint64_t diff = new_length - old_length; 860 process->allocateMem(process->mmap_end, diff); 861 process->mmap_end += diff; 862 return start; 863 } else { 864 if (!use_provided_address && !(flags & OS::TGT_MREMAP_MAYMOVE)) { 865 warn("can't remap here and MREMAP_MAYMOVE flag not set\n"); 866 return -ENOMEM; 867 } else { 868 uint64_t new_start = use_provided_address ? 869 provided_address : process->mmap_end; 870 process->pTable->remap(start, old_length, new_start); 871 warn("mremapping to new vaddr %08p-%08p, adding %d\n", 872 new_start, new_start + new_length, 873 new_length - old_length); 874 // add on the remaining unallocated pages 875 process->allocateMem(new_start + old_length, 876 new_length - old_length, 877 use_provided_address /* clobber */); 878 if (!use_provided_address) 879 process->mmap_end += new_length; 880 if (use_provided_address && 881 new_start + new_length > process->mmap_end) { 882 // something fishy going on here, at least notify the user 883 // @todo: increase mmap_end? 884 warn("mmap region limit exceeded with MREMAP_FIXED\n"); 885 } 886 warn("returning %08p as start\n", new_start); 887 return new_start; 888 } 889 } 890 } else { 891 if (use_provided_address && provided_address != start) 892 process->pTable->remap(start, new_length, provided_address); 893 process->pTable->unmap(start + new_length, old_length - new_length); 894 return use_provided_address ? provided_address : start; 895 } 896} 897 898/// Target stat() handler. 899template <class OS> 900SyscallReturn 901statFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 902 ThreadContext *tc) 903{ 904 std::string path; 905 906 int index = 0; 907 if (!tc->getMemProxy().tryReadString(path, 908 process->getSyscallArg(tc, index))) { 909 return -EFAULT; 910 } 911 Addr bufPtr = process->getSyscallArg(tc, index); 912 913 // Adjust path for current working directory 914 path = process->fullPath(path); 915 916 struct stat hostBuf; 917 int result = stat(path.c_str(), &hostBuf); 918 919 if (result < 0) 920 return -errno; 921 922 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 923 924 return 0; 925} 926 927 928/// Target stat64() handler. 929template <class OS> 930SyscallReturn 931stat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 932 ThreadContext *tc) 933{ 934 std::string path; 935 936 int index = 0; 937 if (!tc->getMemProxy().tryReadString(path, 938 process->getSyscallArg(tc, index))) 939 return -EFAULT; 940 Addr bufPtr = process->getSyscallArg(tc, index); 941 942 // Adjust path for current working directory 943 path = process->fullPath(path); 944 945#if NO_STAT64 946 struct stat hostBuf; 947 int result = stat(path.c_str(), &hostBuf); 948#else 949 struct stat64 hostBuf; 950 int result = stat64(path.c_str(), &hostBuf); 951#endif 952 953 if (result < 0) 954 return -errno; 955 956 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 957 958 return 0; 959} 960 961 962/// Target fstatat64() handler. 963template <class OS> 964SyscallReturn 965fstatat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 966 ThreadContext *tc) 967{ 968 int index = 0; 969 int dirfd = process->getSyscallArg(tc, index); 970 if (dirfd != OS::TGT_AT_FDCWD) 971 warn("fstatat64: first argument not AT_FDCWD; unlikely to work"); 972 973 std::string path; 974 if (!tc->getMemProxy().tryReadString(path, 975 process->getSyscallArg(tc, index))) 976 return -EFAULT; 977 Addr bufPtr = process->getSyscallArg(tc, index); 978 979 // Adjust path for current working directory 980 path = process->fullPath(path); 981 982#if NO_STAT64 983 struct stat hostBuf; 984 int result = stat(path.c_str(), &hostBuf); 985#else 986 struct stat64 hostBuf; 987 int result = stat64(path.c_str(), &hostBuf); 988#endif 989 990 if (result < 0) 991 return -errno; 992 993 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 994 995 return 0; 996} 997 998 999/// Target fstat64() handler. 1000template <class OS> 1001SyscallReturn 1002fstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 1003 ThreadContext *tc) 1004{ 1005 int index = 0; 1006 int tgt_fd = process->getSyscallArg(tc, index); 1007 Addr bufPtr = process->getSyscallArg(tc, index); 1008 1009 int sim_fd = process->getSimFD(tgt_fd); 1010 if (sim_fd < 0) 1011 return -EBADF; 1012 1013#if NO_STAT64 1014 struct stat hostBuf; 1015 int result = fstat(sim_fd, &hostBuf); 1016#else 1017 struct stat64 hostBuf; 1018 int result = fstat64(sim_fd, &hostBuf); 1019#endif 1020 1021 if (result < 0) 1022 return -errno; 1023 1024 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (sim_fd == 1)); 1025 1026 return 0; 1027} 1028 1029 1030/// Target lstat() handler. 1031template <class OS> 1032SyscallReturn 1033lstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1034 ThreadContext *tc) 1035{ 1036 std::string path; 1037 1038 int index = 0; 1039 if (!tc->getMemProxy().tryReadString(path, 1040 process->getSyscallArg(tc, index))) { 1041 return -EFAULT; 1042 } 1043 Addr bufPtr = process->getSyscallArg(tc, index); 1044 1045 // Adjust path for current working directory 1046 path = process->fullPath(path); 1047 1048 struct stat hostBuf; 1049 int result = lstat(path.c_str(), &hostBuf); 1050 1051 if (result < 0) 1052 return -errno; 1053 1054 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1055 1056 return 0; 1057} 1058 1059/// Target lstat64() handler. 1060template <class OS> 1061SyscallReturn 1062lstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 1063 ThreadContext *tc) 1064{ 1065 std::string path; 1066 1067 int index = 0; 1068 if (!tc->getMemProxy().tryReadString(path, 1069 process->getSyscallArg(tc, index))) { 1070 return -EFAULT; 1071 } 1072 Addr bufPtr = process->getSyscallArg(tc, index); 1073 1074 // Adjust path for current working directory 1075 path = process->fullPath(path); 1076 1077#if NO_STAT64 1078 struct stat hostBuf; 1079 int result = lstat(path.c_str(), &hostBuf); 1080#else 1081 struct stat64 hostBuf; 1082 int result = lstat64(path.c_str(), &hostBuf); 1083#endif 1084 1085 if (result < 0) 1086 return -errno; 1087 1088 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1089 1090 return 0; 1091} 1092 1093/// Target fstat() handler. 1094template <class OS> 1095SyscallReturn 1096fstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1097 ThreadContext *tc) 1098{ 1099 int index = 0; 1100 int tgt_fd = process->getSyscallArg(tc, index); 1101 Addr bufPtr = process->getSyscallArg(tc, index); 1102 1103 DPRINTF(SyscallVerbose, "fstat(%d, ...)\n", tgt_fd); 1104 1105 int sim_fd = process->getSimFD(tgt_fd); 1106 if (sim_fd < 0) 1107 return -EBADF; 1108 1109 struct stat hostBuf; 1110 int result = fstat(sim_fd, &hostBuf); 1111 1112 if (result < 0) 1113 return -errno; 1114 1115 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (sim_fd == 1)); 1116 1117 return 0; 1118} 1119 1120 1121/// Target statfs() handler. 1122template <class OS> 1123SyscallReturn 1124statfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1125 ThreadContext *tc) 1126{ 1127 std::string path; 1128 1129 int index = 0; 1130 if (!tc->getMemProxy().tryReadString(path, 1131 process->getSyscallArg(tc, index))) { 1132 return -EFAULT; 1133 } 1134 Addr bufPtr = process->getSyscallArg(tc, index); 1135 1136 // Adjust path for current working directory 1137 path = process->fullPath(path); 1138 1139 struct statfs hostBuf; 1140 int result = statfs(path.c_str(), &hostBuf); 1141 1142 if (result < 0) 1143 return -errno; 1144 1145 OS::copyOutStatfsBuf(tc->getMemProxy(), bufPtr, &hostBuf); 1146 1147 return 0; 1148} 1149 1150 1151/// Target fstatfs() handler. 1152template <class OS> 1153SyscallReturn 1154fstatfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1155 ThreadContext *tc) 1156{ 1157 int index = 0; 1158 int tgt_fd = process->getSyscallArg(tc, index); 1159 Addr bufPtr = process->getSyscallArg(tc, index); 1160 1161 int sim_fd = process->getSimFD(tgt_fd); 1162 if (sim_fd < 0) 1163 return -EBADF; 1164 1165 struct statfs hostBuf; 1166 int result = fstatfs(sim_fd, &hostBuf); 1167 1168 if (result < 0) 1169 return -errno; 1170 1171 OS::copyOutStatfsBuf(tc->getMemProxy(), bufPtr, &hostBuf); 1172 1173 return 0; 1174} 1175 1176 1177/// Target writev() handler. 1178template <class OS> 1179SyscallReturn 1180writevFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1181 ThreadContext *tc) 1182{ 1183 int index = 0; 1184 int tgt_fd = process->getSyscallArg(tc, index); 1185 1186 int sim_fd = process->getSimFD(tgt_fd); 1187 if (sim_fd < 0) 1188 return -EBADF; 1189 1190 SETranslatingPortProxy &p = tc->getMemProxy(); 1191 uint64_t tiov_base = process->getSyscallArg(tc, index); 1192 size_t count = process->getSyscallArg(tc, index); 1193 struct iovec hiov[count]; 1194 for (size_t i = 0; i < count; ++i) { 1195 typename OS::tgt_iovec tiov; 1196 1197 p.readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec), 1198 (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec)); 1199 hiov[i].iov_len = TheISA::gtoh(tiov.iov_len); 1200 hiov[i].iov_base = new char [hiov[i].iov_len]; 1201 p.readBlob(TheISA::gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base, 1202 hiov[i].iov_len); 1203 } 1204 1205 int result = writev(sim_fd, hiov, count); 1206 1207 for (size_t i = 0; i < count; ++i) 1208 delete [] (char *)hiov[i].iov_base; 1209 1210 if (result < 0) 1211 return -errno; 1212 1213 return result; 1214} 1215 1216 1217/// Target mmap() handler. 1218/// 1219/// We don't really handle mmap(). If the target is mmaping an 1220/// anonymous region or /dev/zero, we can get away with doing basically 1221/// nothing (since memory is initialized to zero and the simulator 1222/// doesn't really check addresses anyway). 1223/// 1224template <class OS> 1225SyscallReturn 1226mmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 1227{ 1228 int index = 0; 1229 Addr start = p->getSyscallArg(tc, index); 1230 uint64_t length = p->getSyscallArg(tc, index); 1231 index++; // int prot = p->getSyscallArg(tc, index); 1232 int flags = p->getSyscallArg(tc, index); 1233 int tgt_fd = p->getSyscallArg(tc, index); 1234 int offset = p->getSyscallArg(tc, index); 1235 1236 if (length > 0x100000000ULL) 1237 warn("mmap length argument %#x is unreasonably large.\n", length); 1238 1239 if (!(flags & OS::TGT_MAP_ANONYMOUS)) { 1240 FDEntry *fde = p->getFDEntry(tgt_fd); 1241 if (!fde || fde->fd < 0) { 1242 warn("mmap failing: target fd %d is not valid\n", tgt_fd); 1243 return -EBADF; 1244 } 1245 1246 if (fde->filename != "/dev/zero") { 1247 // This is very likely broken, but leave a warning here 1248 // (rather than panic) in case /dev/zero is known by 1249 // another name on some platform 1250 warn("allowing mmap of file %s; mmap not supported on files" 1251 " other than /dev/zero\n", fde->filename); 1252 } 1253 } 1254 1255 length = roundUp(length, TheISA::PageBytes); 1256 1257 if ((start % TheISA::PageBytes) != 0 || 1258 (offset % TheISA::PageBytes) != 0) { 1259 warn("mmap failing: arguments not page-aligned: " 1260 "start 0x%x offset 0x%x", 1261 start, offset); 1262 return -EINVAL; 1263 } 1264 1265 // are we ok with clobbering existing mappings? only set this to 1266 // true if the user has been warned. 1267 bool clobber = false; 1268 1269 // try to use the caller-provided address if there is one 1270 bool use_provided_address = (start != 0); 1271 1272 if (use_provided_address) { 1273 // check to see if the desired address is already in use 1274 if (!p->pTable->isUnmapped(start, length)) { 1275 // there are existing mappings in the desired range 1276 // whether we clobber them or not depends on whether the caller 1277 // specified MAP_FIXED 1278 if (flags & OS::TGT_MAP_FIXED) { 1279 // MAP_FIXED specified: map attempt fails 1280 return -EINVAL; 1281 } else { 1282 // MAP_FIXED not specified: ignore suggested start address 1283 warn("mmap: ignoring suggested map address 0x%x\n", start); 1284 use_provided_address = false; 1285 } 1286 } 1287 } 1288 1289 if (!use_provided_address) { 1290 // no address provided, or provided address unusable: 1291 // pick next address from our "mmap region" 1292 if (OS::mmapGrowsDown()) { 1293 start = p->mmap_end - length; 1294 p->mmap_end = start; 1295 } else { 1296 start = p->mmap_end; 1297 p->mmap_end += length; 1298 } 1299 } 1300 1301 p->allocateMem(start, length, clobber); 1302 1303 return start; 1304} 1305 1306/// Target getrlimit() handler. 1307template <class OS> 1308SyscallReturn 1309getrlimitFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1310 ThreadContext *tc) 1311{ 1312 int index = 0; 1313 unsigned resource = process->getSyscallArg(tc, index); 1314 TypedBufferArg<typename OS::rlimit> rlp(process->getSyscallArg(tc, index)); 1315 1316 switch (resource) { 1317 case OS::TGT_RLIMIT_STACK: 1318 // max stack size in bytes: make up a number (8MB for now) 1319 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; 1320 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1321 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1322 break; 1323 1324 case OS::TGT_RLIMIT_DATA: 1325 // max data segment size in bytes: make up a number 1326 rlp->rlim_cur = rlp->rlim_max = 256 * 1024 * 1024; 1327 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1328 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1329 break; 1330 1331 default: 1332 warn("getrlimit: unimplemented resource %d", resource); 1333 return -EINVAL; 1334 break; 1335 } 1336 1337 rlp.copyOut(tc->getMemProxy()); 1338 return 0; 1339} 1340 1341/// Target clock_gettime() function. 1342template <class OS> 1343SyscallReturn 1344clock_gettimeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 1345{ 1346 int index = 1; 1347 //int clk_id = p->getSyscallArg(tc, index); 1348 TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index)); 1349 1350 getElapsedTimeNano(tp->tv_sec, tp->tv_nsec); 1351 tp->tv_sec += seconds_since_epoch; 1352 tp->tv_sec = TheISA::htog(tp->tv_sec); 1353 tp->tv_nsec = TheISA::htog(tp->tv_nsec); 1354 1355 tp.copyOut(tc->getMemProxy()); 1356 1357 return 0; 1358} 1359 1360/// Target clock_getres() function. 1361template <class OS> 1362SyscallReturn 1363clock_getresFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 1364{ 1365 int index = 1; 1366 TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index)); 1367 1368 // Set resolution at ns, which is what clock_gettime() returns 1369 tp->tv_sec = 0; 1370 tp->tv_nsec = 1; 1371 1372 tp.copyOut(tc->getMemProxy()); 1373 1374 return 0; 1375} 1376 1377/// Target gettimeofday() handler. 1378template <class OS> 1379SyscallReturn 1380gettimeofdayFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1381 ThreadContext *tc) 1382{ 1383 int index = 0; 1384 TypedBufferArg<typename OS::timeval> tp(process->getSyscallArg(tc, index)); 1385 1386 getElapsedTimeMicro(tp->tv_sec, tp->tv_usec); 1387 tp->tv_sec += seconds_since_epoch; 1388 tp->tv_sec = TheISA::htog(tp->tv_sec); 1389 tp->tv_usec = TheISA::htog(tp->tv_usec); 1390 1391 tp.copyOut(tc->getMemProxy()); 1392 1393 return 0; 1394} 1395 1396 1397/// Target utimes() handler. 1398template <class OS> 1399SyscallReturn 1400utimesFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1401 ThreadContext *tc) 1402{ 1403 std::string path; 1404 1405 int index = 0; 1406 if (!tc->getMemProxy().tryReadString(path, 1407 process->getSyscallArg(tc, index))) { 1408 return -EFAULT; 1409 } 1410 1411 TypedBufferArg<typename OS::timeval [2]> 1412 tp(process->getSyscallArg(tc, index)); 1413 tp.copyIn(tc->getMemProxy()); 1414 1415 struct timeval hostTimeval[2]; 1416 for (int i = 0; i < 2; ++i) 1417 { 1418 hostTimeval[i].tv_sec = TheISA::gtoh((*tp)[i].tv_sec); 1419 hostTimeval[i].tv_usec = TheISA::gtoh((*tp)[i].tv_usec); 1420 } 1421 1422 // Adjust path for current working directory 1423 path = process->fullPath(path); 1424 1425 int result = utimes(path.c_str(), hostTimeval); 1426 1427 if (result < 0) 1428 return -errno; 1429 1430 return 0; 1431} 1432/// Target getrusage() function. 1433template <class OS> 1434SyscallReturn 1435getrusageFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1436 ThreadContext *tc) 1437{ 1438 int index = 0; 1439 int who = process->getSyscallArg(tc, index); // THREAD, SELF, or CHILDREN 1440 TypedBufferArg<typename OS::rusage> rup(process->getSyscallArg(tc, index)); 1441 1442 rup->ru_utime.tv_sec = 0; 1443 rup->ru_utime.tv_usec = 0; 1444 rup->ru_stime.tv_sec = 0; 1445 rup->ru_stime.tv_usec = 0; 1446 rup->ru_maxrss = 0; 1447 rup->ru_ixrss = 0; 1448 rup->ru_idrss = 0; 1449 rup->ru_isrss = 0; 1450 rup->ru_minflt = 0; 1451 rup->ru_majflt = 0; 1452 rup->ru_nswap = 0; 1453 rup->ru_inblock = 0; 1454 rup->ru_oublock = 0; 1455 rup->ru_msgsnd = 0; 1456 rup->ru_msgrcv = 0; 1457 rup->ru_nsignals = 0; 1458 rup->ru_nvcsw = 0; 1459 rup->ru_nivcsw = 0; 1460 1461 switch (who) { 1462 case OS::TGT_RUSAGE_SELF: 1463 getElapsedTimeMicro(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec); 1464 rup->ru_utime.tv_sec = TheISA::htog(rup->ru_utime.tv_sec); 1465 rup->ru_utime.tv_usec = TheISA::htog(rup->ru_utime.tv_usec); 1466 break; 1467 1468 case OS::TGT_RUSAGE_CHILDREN: 1469 // do nothing. We have no child processes, so they take no time. 1470 break; 1471 1472 default: 1473 // don't really handle THREAD or CHILDREN, but just warn and 1474 // plow ahead 1475 warn("getrusage() only supports RUSAGE_SELF. Parameter %d ignored.", 1476 who); 1477 } 1478 1479 rup.copyOut(tc->getMemProxy()); 1480 1481 return 0; 1482} 1483 1484/// Target times() function. 1485template <class OS> 1486SyscallReturn 1487timesFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1488 ThreadContext *tc) 1489{ 1490 int index = 0; 1491 TypedBufferArg<typename OS::tms> bufp(process->getSyscallArg(tc, index)); 1492 1493 // Fill in the time structure (in clocks) 1494 int64_t clocks = curTick() * OS::M5_SC_CLK_TCK / SimClock::Int::s; 1495 bufp->tms_utime = clocks; 1496 bufp->tms_stime = 0; 1497 bufp->tms_cutime = 0; 1498 bufp->tms_cstime = 0; 1499 1500 // Convert to host endianness 1501 bufp->tms_utime = TheISA::htog(bufp->tms_utime); 1502 1503 // Write back 1504 bufp.copyOut(tc->getMemProxy()); 1505 1506 // Return clock ticks since system boot 1507 return clocks; 1508} 1509 1510/// Target time() function. 1511template <class OS> 1512SyscallReturn 1513timeFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1514 ThreadContext *tc) 1515{ 1516 typename OS::time_t sec, usec; 1517 getElapsedTimeMicro(sec, usec); 1518 sec += seconds_since_epoch; 1519 1520 int index = 0; 1521 Addr taddr = (Addr)process->getSyscallArg(tc, index); 1522 if (taddr != 0) { 1523 typename OS::time_t t = sec; 1524 t = TheISA::htog(t); 1525 SETranslatingPortProxy &p = tc->getMemProxy(); 1526 p.writeBlob(taddr, (uint8_t*)&t, (int)sizeof(typename OS::time_t)); 1527 } 1528 return sec; 1529} 1530 1531 1532#endif // __SIM_SYSCALL_EMUL_HH__ 1533