syscall_emul.hh revision 13883
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 352064SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 362064SN/A * 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 */ 441354SN/A 45360SN/A#ifndef __SIM_SYSCALL_EMUL_HH__ 461809SN/A#define __SIM_SYSCALL_EMUL_HH__ 471809SN/A 481809SN/A#if (defined(__APPLE__) || defined(__OpenBSD__) || \ 491999SN/A defined(__FreeBSD__) || defined(__CYGWIN__) || \ 50360SN/A defined(__NetBSD__)) 512474SN/A#define NO_STAT64 1 522474SN/A#else 53360SN/A#define NO_STAT64 0 542462SN/A#endif 551354SN/A 562474SN/A#if (defined(__APPLE__) || defined(__OpenBSD__) || \ 571354SN/A defined(__FreeBSD__) || defined(__NetBSD__)) 582474SN/A#define NO_STATFS 1 592474SN/A#else 601354SN/A#define NO_STATFS 0 61360SN/A#endif 62360SN/A 63360SN/A#if (defined(__APPLE__) || defined(__OpenBSD__) || \ 64360SN/A defined(__FreeBSD__) || defined(__NetBSD__)) 65360SN/A#define NO_FALLOCATE 1 66360SN/A#else 67360SN/A#define NO_FALLOCATE 0 68360SN/A#endif 69378SN/A 701450SN/A/// 71360SN/A/// @file syscall_emul.hh 72360SN/A/// 73360SN/A/// This file defines objects used to emulate syscalls from the target 74360SN/A/// application on the host machine. 75360SN/A 76360SN/A#ifdef __CYGWIN32__ 77360SN/A#include <sys/fcntl.h> 78360SN/A 79360SN/A#endif 80360SN/A#include <fcntl.h> 81360SN/A#include <poll.h> 82360SN/A#include <sys/mman.h> 83360SN/A#include <sys/socket.h> 84360SN/A#include <sys/stat.h> 85360SN/A#if (NO_STATFS == 0) 86360SN/A#include <sys/statfs.h> 87360SN/A#else 88360SN/A#include <sys/mount.h> 89360SN/A#endif 90360SN/A#include <sys/time.h> 91360SN/A#include <sys/types.h> 92360SN/A#include <sys/uio.h> 93360SN/A#include <unistd.h> 94360SN/A 95360SN/A#include <cerrno> 96360SN/A#include <memory> 97360SN/A#include <string> 98360SN/A 99360SN/A#include "arch/generic/tlb.hh" 100360SN/A#include "arch/utility.hh" 101360SN/A#include "base/intmath.hh" 102360SN/A#include "base/loader/object_file.hh" 103360SN/A#include "base/logging.hh" 104360SN/A#include "base/trace.hh" 105360SN/A#include "base/types.hh" 106360SN/A#include "config/the_isa.hh" 107360SN/A#include "cpu/base.hh" 108360SN/A#include "cpu/thread_context.hh" 109360SN/A#include "mem/page_table.hh" 110360SN/A#include "params/Process.hh" 111360SN/A#include "sim/emul_driver.hh" 112360SN/A#include "sim/futex_map.hh" 113360SN/A#include "sim/process.hh" 114360SN/A#include "sim/syscall_debug_macros.hh" 1152400SN/A#include "sim/syscall_desc.hh" 116360SN/A#include "sim/syscall_emul_buf.hh" 1172461SN/A#include "sim/syscall_return.hh" 118360SN/A 119360SN/A#if defined(__APPLE__) && defined(__MACH__) && !defined(CMSG_ALIGN) 120360SN/A#define CMSG_ALIGN(len) (((len) + sizeof(size_t) - 1) & ~(sizeof(size_t) - 1)) 121360SN/A#endif 122360SN/A 123360SN/A////////////////////////////////////////////////////////////////////// 1242400SN/A// 125360SN/A// The following emulation functions are generic enough that they 1262461SN/A// don't need to be recompiled for different emulated OS's. They are 127360SN/A// defined in sim/syscall_emul.cc. 128360SN/A// 129360SN/A////////////////////////////////////////////////////////////////////// 130360SN/A 131360SN/A 132360SN/A/// Handler for unimplemented syscalls that we haven't thought about. 133360SN/ASyscallReturn unimplementedFunc(SyscallDesc *desc, int num, 134360SN/A Process *p, ThreadContext *tc); 135360SN/A 136360SN/A/// Handler for unimplemented syscalls that we never intend to 137360SN/A/// implement (signal handling, etc.) and should not affect the correct 138360SN/A/// behavior of the program. Print a warning only if the appropriate 139360SN/A/// trace flag is enabled. Return success to the target program. 140360SN/ASyscallReturn ignoreFunc(SyscallDesc *desc, int num, 141360SN/A Process *p, ThreadContext *tc); 142360SN/A 143360SN/A// Target fallocateFunc() handler. 144360SN/ASyscallReturn fallocateFunc(SyscallDesc *desc, int num, 145360SN/A Process *p, ThreadContext *tc); 146360SN/A 147360SN/A/// Target exit() handler: terminate current context. 148360SN/ASyscallReturn exitFunc(SyscallDesc *desc, int num, 149360SN/A Process *p, ThreadContext *tc); 150360SN/A 151360SN/A/// Target exit_group() handler: terminate simulation. (exit all threads) 152360SN/ASyscallReturn exitGroupFunc(SyscallDesc *desc, int num, 153360SN/A Process *p, ThreadContext *tc); 154360SN/A 155360SN/A/// Target set_tid_address() handler. 156360SN/ASyscallReturn setTidAddressFunc(SyscallDesc *desc, int num, 157360SN/A Process *p, ThreadContext *tc); 158360SN/A 159502SN/A/// Target getpagesize() handler. 160360SN/ASyscallReturn getpagesizeFunc(SyscallDesc *desc, int num, 161502SN/A Process *p, ThreadContext *tc); 162360SN/A 163360SN/A/// Target brk() handler: set brk address. 164360SN/ASyscallReturn brkFunc(SyscallDesc *desc, int num, 165360SN/A Process *p, ThreadContext *tc); 166360SN/A 167360SN/A/// Target close() handler. 168360SN/ASyscallReturn closeFunc(SyscallDesc *desc, int num, 169360SN/A Process *p, ThreadContext *tc); 170360SN/A 171360SN/A/// Target lseek() handler. 172360SN/ASyscallReturn lseekFunc(SyscallDesc *desc, int num, 173378SN/A Process *p, ThreadContext *tc); 1741706SN/A 1751706SN/A/// Target _llseek() handler. 176378SN/ASyscallReturn _llseekFunc(SyscallDesc *desc, int num, 177378SN/A Process *p, ThreadContext *tc); 178378SN/A 179378SN/A/// Target munmap() handler. 180378SN/ASyscallReturn munmapFunc(SyscallDesc *desc, int num, 1811706SN/A Process *p, ThreadContext *tc); 1821706SN/A 183360SN/A/// Target shutdown() handler. 184378SN/ASyscallReturn shutdownFunc(SyscallDesc *desc, int num, 1851706SN/A Process *p, ThreadContext *tc); 1861706SN/A 187378SN/A/// Target gethostname() handler. 188378SN/ASyscallReturn gethostnameFunc(SyscallDesc *desc, int num, 1891706SN/A Process *p, ThreadContext *tc); 1901706SN/A 191378SN/A/// Target getcwd() handler. 192378SN/ASyscallReturn getcwdFunc(SyscallDesc *desc, int num, 1931706SN/A Process *p, ThreadContext *tc); 1941706SN/A 195378SN/A/// Target readlink() handler. 196378SN/ASyscallReturn readlinkFunc(SyscallDesc *desc, int num, 1971706SN/A Process *p, ThreadContext *tc, 1981706SN/A int index = 0); 199378SN/ASyscallReturn readlinkFunc(SyscallDesc *desc, int num, 200378SN/A Process *p, ThreadContext *tc); 2011706SN/A 2021706SN/A/// Target unlink() handler. 203378SN/ASyscallReturn unlinkHelper(SyscallDesc *desc, int num, 204378SN/A Process *p, ThreadContext *tc, 2051706SN/A int index); 2061706SN/ASyscallReturn unlinkFunc(SyscallDesc *desc, int num, 207378SN/A Process *p, ThreadContext *tc); 208378SN/A 2091706SN/A/// Target link() handler 2101706SN/ASyscallReturn linkFunc(SyscallDesc *desc, int num, Process *p, 211378SN/A ThreadContext *tc); 212378SN/A 2131706SN/A/// Target symlink() handler. 2141706SN/ASyscallReturn symlinkFunc(SyscallDesc *desc, int num, Process *p, 215378SN/A ThreadContext *tc); 216378SN/A 2171706SN/A/// Target mkdir() handler. 2181706SN/ASyscallReturn mkdirFunc(SyscallDesc *desc, int num, 219360SN/A Process *p, ThreadContext *tc); 220511SN/A 2211706SN/A/// Target mknod() handler. 2221706SN/ASyscallReturn mknodFunc(SyscallDesc *desc, int num, 223511SN/A Process *p, ThreadContext *tc); 224511SN/A 2251706SN/A/// Target chdir() handler. 2261706SN/ASyscallReturn chdirFunc(SyscallDesc *desc, int num, 2271706SN/A Process *p, ThreadContext *tc); 2281706SN/A 2291706SN/A// Target rmdir() handler. 2301706SN/ASyscallReturn rmdirFunc(SyscallDesc *desc, int num, 2311706SN/A Process *p, ThreadContext *tc); 2321706SN/A 2331706SN/A/// Target rename() handler. 2341706SN/ASyscallReturn renameFunc(SyscallDesc *desc, int num, 2351706SN/A Process *p, ThreadContext *tc); 2361706SN/A 2371706SN/A 238511SN/A/// Target truncate() handler. 2391999SN/ASyscallReturn truncateFunc(SyscallDesc *desc, int num, 2401999SN/A Process *p, ThreadContext *tc); 2411999SN/A 2421999SN/A 2431999SN/A/// Target ftruncate() handler. 2441999SN/ASyscallReturn ftruncateFunc(SyscallDesc *desc, int num, 2451999SN/A Process *p, ThreadContext *tc); 2461999SN/A 2471999SN/A 2482093SN/A/// Target truncate64() handler. 2492093SN/ASyscallReturn truncate64Func(SyscallDesc *desc, int num, 2502093SN/A Process *p, ThreadContext *tc); 2512093SN/A 2522238SN/A/// Target ftruncate64() handler. 2532238SN/ASyscallReturn ftruncate64Func(SyscallDesc *desc, int num, 2542238SN/A Process *p, ThreadContext *tc); 2552238SN/A 2562238SN/A 2572238SN/A/// Target umask() handler. 2582238SN/ASyscallReturn umaskFunc(SyscallDesc *desc, int num, 2592238SN/A Process *p, ThreadContext *tc); 2602238SN/A 2612238SN/A/// Target gettid() handler. 2622238SN/ASyscallReturn gettidFunc(SyscallDesc *desc, int num, 2632238SN/A Process *p, ThreadContext *tc); 2642238SN/A 2652238SN/A/// Target chown() handler. 2662238SN/ASyscallReturn chownFunc(SyscallDesc *desc, int num, 2672238SN/A Process *p, ThreadContext *tc); 2682238SN/A 2692238SN/A/// Target setpgid() handler. 2702238SN/ASyscallReturn setpgidFunc(SyscallDesc *desc, int num, 2712238SN/A Process *p, ThreadContext *tc); 2722238SN/A 2732238SN/A/// Target fchown() handler. 2742238SN/ASyscallReturn fchownFunc(SyscallDesc *desc, int num, 2752238SN/A Process *p, ThreadContext *tc); 2762238SN/A 2772238SN/A/// Target dup() handler. 2782238SN/ASyscallReturn dupFunc(SyscallDesc *desc, int num, 2792238SN/A Process *process, ThreadContext *tc); 2802238SN/A 2812238SN/A/// Target dup2() handler. 2822238SN/ASyscallReturn dup2Func(SyscallDesc *desc, int num, 2832238SN/A Process *process, ThreadContext *tc); 2842238SN/A 2852238SN/A/// Target fcntl() handler. 2862238SN/ASyscallReturn fcntlFunc(SyscallDesc *desc, int num, 2872238SN/A Process *process, ThreadContext *tc); 2882238SN/A 2892238SN/A/// Target fcntl64() handler. 2902238SN/ASyscallReturn fcntl64Func(SyscallDesc *desc, int num, 2912238SN/A Process *process, ThreadContext *tc); 2922238SN/A 2932238SN/A/// Target setuid() handler. 2942238SN/ASyscallReturn setuidFunc(SyscallDesc *desc, int num, 2952238SN/A Process *p, ThreadContext *tc); 2962238SN/A 2972238SN/A/// Target pipe() handler. 2982238SN/ASyscallReturn pipeFunc(SyscallDesc *desc, int num, 2992238SN/A Process *p, ThreadContext *tc); 3001354SN/A 3011354SN/A/// Internal pipe() handler. 3021354SN/ASyscallReturn pipeImpl(SyscallDesc *desc, int num, Process *p, 3031354SN/A ThreadContext *tc, bool pseudoPipe); 3041354SN/A 3051354SN/A/// Target getpid() handler. 3061354SN/ASyscallReturn getpidFunc(SyscallDesc *desc, int num, 3071354SN/A Process *p, ThreadContext *tc); 3081354SN/A 3091354SN/A// Target getpeername() handler. 3101354SN/ASyscallReturn getpeernameFunc(SyscallDesc *desc, int num, 3111354SN/A Process *p, ThreadContext *tc); 3121354SN/A 3131354SN/A// Target bind() handler. 3141354SN/ASyscallReturn bindFunc(SyscallDesc *desc, int num, 3151354SN/A Process *p, ThreadContext *tc); 3161354SN/A 3171354SN/A// Target listen() handler. 3181354SN/ASyscallReturn listenFunc(SyscallDesc *desc, int num, 3191354SN/A Process *p, ThreadContext *tc); 3201354SN/A 3211354SN/A// Target connect() handler. 3221354SN/ASyscallReturn connectFunc(SyscallDesc *desc, int num, 3231609SN/A Process *p, ThreadContext *tc); 3241354SN/A 3251354SN/A#if defined(SYS_getdents) 3261354SN/A// Target getdents() handler. 3271354SN/ASyscallReturn getdentsFunc(SyscallDesc *desc, int num, 328360SN/A Process *p, ThreadContext *tc); 329360SN/A#endif 330360SN/A 331360SN/A#if defined(SYS_getdents64) 332360SN/A// Target getdents() handler. 333360SN/ASyscallReturn getdents64Func(SyscallDesc *desc, int num, 334360SN/A Process *p, ThreadContext *tc); 335378SN/A#endif 336378SN/A 337378SN/A// Target sendto() handler. 338360SN/ASyscallReturn sendtoFunc(SyscallDesc *desc, int num, 3391450SN/A Process *p, ThreadContext *tc); 340360SN/A 341360SN/A// Target recvfrom() handler. 342360SN/ASyscallReturn recvfromFunc(SyscallDesc *desc, int num, 343360SN/A Process *p, ThreadContext *tc); 344360SN/A 345360SN/A// Target recvmsg() handler. 3461969SN/ASyscallReturn recvmsgFunc(SyscallDesc *desc, int num, 347360SN/A Process *p, ThreadContext *tc); 348360SN/A 349360SN/A// Target sendmsg() handler. 3501458SN/ASyscallReturn sendmsgFunc(SyscallDesc *desc, int num, 351360SN/A Process *p, ThreadContext *tc); 352360SN/A 353360SN/A// Target getuid() handler. 3542553SN/ASyscallReturn getuidFunc(SyscallDesc *desc, int num, 3552553SN/A Process *p, ThreadContext *tc); 3562553SN/A 3572553SN/A/// Target getgid() handler. 3582553SN/ASyscallReturn getgidFunc(SyscallDesc *desc, int num, 3592553SN/A Process *p, ThreadContext *tc); 3602553SN/A 3612553SN/A/// Target getppid() handler. 3621458SN/ASyscallReturn getppidFunc(SyscallDesc *desc, int num, 363360SN/A Process *p, ThreadContext *tc); 364360SN/A 3651706SN/A/// Target geteuid() handler. 3661706SN/ASyscallReturn geteuidFunc(SyscallDesc *desc, int num, 367360SN/A Process *p, ThreadContext *tc); 368360SN/A 369360SN/A/// Target getegid() handler. 370378SN/ASyscallReturn getegidFunc(SyscallDesc *desc, int num, 371360SN/A Process *p, ThreadContext *tc); 3721450SN/A 373360SN/A/// Target access() handler 374360SN/ASyscallReturn accessFunc(SyscallDesc *desc, int num, 375360SN/A Process *p, ThreadContext *tc); 376360SN/ASyscallReturn accessFunc(SyscallDesc *desc, int num, 377360SN/A Process *p, ThreadContext *tc, 3782461SN/A int index); 3791458SN/A 380360SN/A// Target getsockopt() handler. 381360SN/ASyscallReturn getsockoptFunc(SyscallDesc *desc, int num, 382360SN/A Process *p, ThreadContext *tc); 383360SN/A 3841706SN/A// Target setsockopt() handler. 3851458SN/ASyscallReturn setsockoptFunc(SyscallDesc *desc, int num, 386360SN/A Process *p, ThreadContext *tc); 387360SN/A 388360SN/A// Target getsockname() handler. 389360SN/ASyscallReturn getsocknameFunc(SyscallDesc *desc, int num, 390360SN/A Process *p, ThreadContext *tc); 391360SN/A 392360SN/A/// Futex system call 393360SN/A/// Implemented by Daniel Sanchez 394360SN/A/// Used by printf's in multi-threaded apps 395360SN/Atemplate <class OS> 396360SN/ASyscallReturn 397360SN/AfutexFunc(SyscallDesc *desc, int callnum, Process *process, 398360SN/A ThreadContext *tc) 399360SN/A{ 400360SN/A using namespace std; 401360SN/A 4021706SN/A int index = 0; 403360SN/A Addr uaddr = process->getSyscallArg(tc, index); 404360SN/A int op = process->getSyscallArg(tc, index); 405360SN/A int val = process->getSyscallArg(tc, index); 406360SN/A int timeout M5_VAR_USED = process->getSyscallArg(tc, index); 407360SN/A Addr uaddr2 M5_VAR_USED = process->getSyscallArg(tc, index); 4081706SN/A int val3 = process->getSyscallArg(tc, index); 4091706SN/A 410360SN/A /* 411360SN/A * Unsupported option that does not affect the correctness of the 412360SN/A * application. This is a performance optimization utilized by Linux. 4131970SN/A */ 414360SN/A op &= ~OS::TGT_FUTEX_PRIVATE_FLAG; 415360SN/A op &= ~OS::TGT_FUTEX_CLOCK_REALTIME_FLAG; 416360SN/A 4171999SN/A FutexMap &futex_map = tc->getSystemPtr()->futexMap; 4181999SN/A 4191999SN/A if (OS::TGT_FUTEX_WAIT == op || OS::TGT_FUTEX_WAIT_BITSET == op) { 4201999SN/A // Ensure futex system call accessed atomically. 4211999SN/A BufferArg buf(uaddr, sizeof(int)); 4221999SN/A buf.copyIn(tc->getMemProxy()); 4231999SN/A int mem_val = *(int*)buf.bufferPtr(); 4241999SN/A 4252461SN/A /* 4261999SN/A * The value in memory at uaddr is not equal with the expected val 4271999SN/A * (a different thread must have changed it before the system call was 4281999SN/A * invoked). In this case, we need to throw an error. 4291999SN/A */ 4301999SN/A if (val != mem_val) 4311999SN/A return -OS::TGT_EWOULDBLOCK; 4321999SN/A 4331999SN/A if (OS::TGT_FUTEX_WAIT) { 4341999SN/A futex_map.suspend(uaddr, process->tgid(), tc); 4351999SN/A } else { 4361999SN/A futex_map.suspend_bitset(uaddr, process->tgid(), tc, val3); 4372218SN/A } 4381999SN/A 4391999SN/A return 0; 4401999SN/A } else if (OS::TGT_FUTEX_WAKE == op) { 4411999SN/A return futex_map.wakeup(uaddr, process->tgid(), val); 4421999SN/A } else if (OS::TGT_FUTEX_WAKE_BITSET == op) { 4431999SN/A return futex_map.wakeup_bitset(uaddr, process->tgid(), val3); 4441999SN/A } else if (OS::TGT_FUTEX_REQUEUE == op || 4451999SN/A OS::TGT_FUTEX_CMP_REQUEUE == op) { 4461999SN/A 4471999SN/A // Ensure futex system call accessed atomically. 4481999SN/A BufferArg buf(uaddr, sizeof(int)); 4491999SN/A buf.copyIn(tc->getMemProxy()); 4501999SN/A int mem_val = *(int*)buf.bufferPtr(); 4511999SN/A /* 4521999SN/A * For CMP_REQUEUE, the whole operation is only started only if 4531999SN/A * val3 is still the value of the futex pointed to by uaddr. 4541999SN/A */ 4551999SN/A if (OS::TGT_FUTEX_CMP_REQUEUE && val3 != mem_val) 4561999SN/A return -OS::TGT_EWOULDBLOCK; 4571999SN/A return futex_map.requeue(uaddr, process->tgid(), val, timeout, uaddr2); 4581999SN/A } else if (OS::TGT_FUTEX_WAKE_OP == op) { 4591999SN/A /* 4601999SN/A * The FUTEX_WAKE_OP operation is equivalent to executing the 4611999SN/A * following code atomically and totally ordered with respect to 4621999SN/A * other futex operations on any of the two supplied futex words: 4631999SN/A * 4642218SN/A * int oldval = *(int *) addr2; 4651999SN/A * *(int *) addr2 = oldval op oparg; 4661999SN/A * futex(addr1, FUTEX_WAKE, val, 0, 0, 0); 4671999SN/A * if (oldval cmp cmparg) 4681999SN/A * futex(addr2, FUTEX_WAKE, val2, 0, 0, 0); 4691999SN/A * 470378SN/A * (op, oparg, cmp, cmparg are encoded in val3) 471360SN/A * 4721450SN/A * +---+---+-----------+-----------+ 473360SN/A * |op |cmp| oparg | cmparg | 474360SN/A * +---+---+-----------+-----------+ 475360SN/A * 4 4 12 12 <== # of bits 476360SN/A * 477360SN/A * reference: http://man7.org/linux/man-pages/man2/futex.2.html 4782461SN/A * 4792400SN/A */ 480360SN/A // get value from simulated-space 481360SN/A BufferArg buf(uaddr2, sizeof(int)); 482360SN/A buf.copyIn(tc->getMemProxy()); 483360SN/A int oldval = *(int*)buf.bufferPtr(); 484360SN/A int newval = oldval; 4852218SN/A // extract op, oparg, cmp, cmparg from val3 486360SN/A int wake_cmparg = val3 & 0xfff; 4872426SN/A int wake_oparg = (val3 & 0xfff000) >> 12; 488360SN/A int wake_cmp = (val3 & 0xf000000) >> 24; 4891458SN/A int wake_op = (val3 & 0xf0000000) >> 28; 490360SN/A if ((wake_op & OS::TGT_FUTEX_OP_ARG_SHIFT) >> 3 == 1) 491360SN/A wake_oparg = (1 << wake_oparg); 492360SN/A wake_op &= ~OS::TGT_FUTEX_OP_ARG_SHIFT; 4931999SN/A // perform operation on the value of the second futex 4941999SN/A if (wake_op == OS::TGT_FUTEX_OP_SET) 4951999SN/A newval = wake_oparg; 4961999SN/A else if (wake_op == OS::TGT_FUTEX_OP_ADD) 4971999SN/A newval += wake_oparg; 4981999SN/A else if (wake_op == OS::TGT_FUTEX_OP_OR) 4991999SN/A newval |= wake_oparg; 5001999SN/A else if (wake_op == OS::TGT_FUTEX_OP_ANDN) 5011999SN/A newval &= ~wake_oparg; 5021999SN/A else if (wake_op == OS::TGT_FUTEX_OP_XOR) 5031999SN/A newval ^= wake_oparg; 5041999SN/A // copy updated value back to simulated-space 5052067SN/A *(int*)buf.bufferPtr() = newval; 5062064SN/A buf.copyOut(tc->getMemProxy()); 5072064SN/A // perform the first wake-up 5082064SN/A int woken1 = futex_map.wakeup(uaddr, process->tgid(), val); 5092064SN/A int woken2 = 0; 5101999SN/A // calculate the condition of the second wake-up 5112064SN/A bool is_wake2 = false; 5121999SN/A if (wake_cmp == OS::TGT_FUTEX_OP_CMP_EQ) 5131999SN/A is_wake2 = oldval == wake_cmparg; 5142218SN/A else if (wake_cmp == OS::TGT_FUTEX_OP_CMP_NE) 5151999SN/A is_wake2 = oldval != wake_cmparg; 5162426SN/A else if (wake_cmp == OS::TGT_FUTEX_OP_CMP_LT) 5171999SN/A is_wake2 = oldval < wake_cmparg; 5181999SN/A else if (wake_cmp == OS::TGT_FUTEX_OP_CMP_LE) 5191999SN/A is_wake2 = oldval <= wake_cmparg; 5201999SN/A else if (wake_cmp == OS::TGT_FUTEX_OP_CMP_GT) 5211999SN/A is_wake2 = oldval > wake_cmparg; 522378SN/A else if (wake_cmp == OS::TGT_FUTEX_OP_CMP_GE) 523360SN/A is_wake2 = oldval >= wake_cmparg; 5241450SN/A // perform the second wake-up 525360SN/A if (is_wake2) 526360SN/A woken2 = futex_map.wakeup(uaddr2, process->tgid(), timeout); 527360SN/A 528360SN/A return woken1 + woken2; 529360SN/A } 5302461SN/A warn("futex: op %d not implemented; ignoring.", op); 5312400SN/A return -ENOSYS; 532360SN/A} 533360SN/A 534360SN/A 535360SN/A/// Pseudo Funcs - These functions use a different return convension, 536360SN/A/// returning a second value in a register other than the normal return register 5371458SN/ASyscallReturn pipePseudoFunc(SyscallDesc *desc, int num, 538360SN/A Process *process, ThreadContext *tc); 5392426SN/A 540360SN/A/// Target getpidPseudo() handler. 5411458SN/ASyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num, 542360SN/A Process *p, ThreadContext *tc); 543360SN/A 5441999SN/A/// Target getuidPseudo() handler. 5451999SN/ASyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num, 5461999SN/A Process *p, ThreadContext *tc); 5471999SN/A 5481999SN/A/// Target getgidPseudo() handler. 5491999SN/ASyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num, 5501999SN/A Process *p, ThreadContext *tc); 5511999SN/A 5522461SN/A 5532400SN/A/// A readable name for 1,000,000, for converting microseconds to seconds. 5541999SN/Aconst int one_million = 1000000; 5552067SN/A/// A readable name for 1,000,000,000, for converting nanoseconds to seconds. 5562064SN/Aconst int one_billion = 1000000000; 5572064SN/A 5582064SN/A/// Approximate seconds since the epoch (1/1/1970). About a billion, 5591999SN/A/// by my reckoning. We want to keep this a constant (not use the 5601999SN/A/// real-world time) to keep simulations repeatable. 5612064SN/Aconst unsigned seconds_since_epoch = 1000000000; 5621999SN/A 5631999SN/A/// Helper function to convert current elapsed time to seconds and 5641999SN/A/// microseconds. 5651999SN/Atemplate <class T1, class T2> 5662426SN/Avoid 5671999SN/AgetElapsedTimeMicro(T1 &sec, T2 &usec) 5681999SN/A{ 5691999SN/A uint64_t elapsed_usecs = curTick() / SimClock::Int::us; 5701999SN/A sec = elapsed_usecs / one_million; 571378SN/A usec = elapsed_usecs % one_million; 572360SN/A} 5731450SN/A 574360SN/A/// Helper function to convert current elapsed time to seconds and 575360SN/A/// nanoseconds. 576360SN/Atemplate <class T1, class T2> 577360SN/Avoid 578360SN/AgetElapsedTimeNano(T1 &sec, T2 &nsec) 5791969SN/A{ 580360SN/A uint64_t elapsed_nsecs = curTick() / SimClock::Int::ns; 581360SN/A sec = elapsed_nsecs / one_billion; 5821458SN/A nsec = elapsed_nsecs % one_billion; 583360SN/A} 584360SN/A 585360SN/A////////////////////////////////////////////////////////////////////// 586360SN/A// 587360SN/A// The following emulation functions are generic, but need to be 5881458SN/A// templated to account for differences in types, constants, etc. 589360SN/A// 5902426SN/A////////////////////////////////////////////////////////////////////// 5912021SN/A 5921458SN/A typedef struct statfs hst_statfs; 593360SN/A#if NO_STAT64 594360SN/A typedef struct stat hst_stat; 595360SN/A typedef struct stat hst_stat64; 5961706SN/A#else 5971706SN/A typedef struct stat hst_stat; 5981706SN/A typedef struct stat64 hst_stat64; 5991706SN/A#endif 6001706SN/A 6011706SN/A//// Helper function to convert a host stat buffer to a target stat 6021706SN/A//// buffer. Also copies the target buffer out to the simulated 6031706SN/A//// memory space. Used by stat(), fstat(), and lstat(). 6042461SN/A 6052400SN/Atemplate <typename target_stat, typename host_stat> 6061706SN/Avoid 6071706SN/AconvertStatBuf(target_stat &tgt, host_stat *host, bool fakeTTY = false) 6081706SN/A{ 6091706SN/A using namespace TheISA; 6101706SN/A 6112218SN/A if (fakeTTY) 6121706SN/A tgt->st_dev = 0xA; 6132426SN/A else 6141706SN/A tgt->st_dev = host->st_dev; 6151706SN/A tgt->st_dev = TheISA::htog(tgt->st_dev); 6161706SN/A tgt->st_ino = host->st_ino; 6171706SN/A tgt->st_ino = TheISA::htog(tgt->st_ino); 6181706SN/A tgt->st_mode = host->st_mode; 6191706SN/A if (fakeTTY) { 6201706SN/A // Claim to be a character device 6211706SN/A tgt->st_mode &= ~S_IFMT; // Clear S_IFMT 6221706SN/A tgt->st_mode |= S_IFCHR; // Set S_IFCHR 6231706SN/A } 6241706SN/A tgt->st_mode = TheISA::htog(tgt->st_mode); 6251706SN/A tgt->st_nlink = host->st_nlink; 6261706SN/A tgt->st_nlink = TheISA::htog(tgt->st_nlink); 6271706SN/A tgt->st_uid = host->st_uid; 6281706SN/A tgt->st_uid = TheISA::htog(tgt->st_uid); 6291706SN/A tgt->st_gid = host->st_gid; 6301706SN/A tgt->st_gid = TheISA::htog(tgt->st_gid); 6311706SN/A if (fakeTTY) 6321706SN/A tgt->st_rdev = 0x880d; 6331706SN/A else 6342218SN/A tgt->st_rdev = host->st_rdev; 6351706SN/A tgt->st_rdev = TheISA::htog(tgt->st_rdev); 6362426SN/A tgt->st_size = host->st_size; 6371706SN/A tgt->st_size = TheISA::htog(tgt->st_size); 6381706SN/A tgt->st_atimeX = host->st_atime; 6391706SN/A tgt->st_atimeX = TheISA::htog(tgt->st_atimeX); 6401706SN/A tgt->st_mtimeX = host->st_mtime; 6411706SN/A tgt->st_mtimeX = TheISA::htog(tgt->st_mtimeX); 6421999SN/A tgt->st_ctimeX = host->st_ctime; 6431999SN/A tgt->st_ctimeX = TheISA::htog(tgt->st_ctimeX); 6441999SN/A // Force the block size to be 8KB. This helps to ensure buffered io works 6451999SN/A // consistently across different hosts. 6461999SN/A tgt->st_blksize = 0x2000; 6471999SN/A tgt->st_blksize = TheISA::htog(tgt->st_blksize); 6481999SN/A tgt->st_blocks = host->st_blocks; 6491999SN/A tgt->st_blocks = TheISA::htog(tgt->st_blocks); 6501999SN/A} 6511999SN/A 6521999SN/A// Same for stat64 6531999SN/A 6542461SN/Atemplate <typename target_stat, typename host_stat64> 6551999SN/Avoid 6561999SN/AconvertStat64Buf(target_stat &tgt, host_stat64 *host, bool fakeTTY = false) 6571999SN/A{ 6581999SN/A using namespace TheISA; 6591999SN/A 6601999SN/A convertStatBuf<target_stat, host_stat64>(tgt, host, fakeTTY); 6612461SN/A#if defined(STAT_HAVE_NSEC) 6622461SN/A tgt->st_atime_nsec = host->st_atime_nsec; 6632461SN/A tgt->st_atime_nsec = TheISA::htog(tgt->st_atime_nsec); 6642091SN/A tgt->st_mtime_nsec = host->st_mtime_nsec; 6651999SN/A tgt->st_mtime_nsec = TheISA::htog(tgt->st_mtime_nsec); 6662461SN/A tgt->st_ctime_nsec = host->st_ctime_nsec; 6672461SN/A tgt->st_ctime_nsec = TheISA::htog(tgt->st_ctime_nsec); 6681999SN/A#else 6691999SN/A tgt->st_atime_nsec = 0; 6701999SN/A tgt->st_mtime_nsec = 0; 6711999SN/A tgt->st_ctime_nsec = 0; 6721999SN/A#endif 6731999SN/A} 6741999SN/A 6751999SN/A// Here are a couple of convenience functions 6761999SN/Atemplate<class OS> 6771999SN/Avoid 6782218SN/AcopyOutStatBuf(SETranslatingPortProxy &mem, Addr addr, 6791999SN/A hst_stat *host, bool fakeTTY = false) 6801999SN/A{ 6811999SN/A typedef TypedBufferArg<typename OS::tgt_stat> tgt_stat_buf; 6821999SN/A tgt_stat_buf tgt(addr); 6831999SN/A convertStatBuf<tgt_stat_buf, hst_stat>(tgt, host, fakeTTY); 684378SN/A tgt.copyOut(mem); 685378SN/A} 686378SN/A 687378SN/Atemplate<class OS> 688378SN/Avoid 689378SN/AcopyOutStat64Buf(SETranslatingPortProxy &mem, Addr addr, 690378SN/A hst_stat64 *host, bool fakeTTY = false) 691378SN/A{ 692360SN/A typedef TypedBufferArg<typename OS::tgt_stat64> tgt_stat_buf; 693378SN/A tgt_stat_buf tgt(addr); 694378SN/A convertStat64Buf<tgt_stat_buf, hst_stat64>(tgt, host, fakeTTY); 695378SN/A tgt.copyOut(mem); 696360SN/A} 6971450SN/A 698360SN/Atemplate <class OS> 699360SN/Avoid 7002130SN/AcopyOutStatfsBuf(SETranslatingPortProxy &mem, Addr addr, 701360SN/A hst_statfs *host) 702360SN/A{ 703360SN/A TypedBufferArg<typename OS::tgt_statfs> tgt(addr); 704378SN/A 705360SN/A tgt->f_type = TheISA::htog(host->f_type); 706360SN/A#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) 7072544SN/A tgt->f_bsize = TheISA::htog(host->f_iosize); 7082544SN/A#else 7092544SN/A tgt->f_bsize = TheISA::htog(host->f_bsize); 7102544SN/A#endif 7112544SN/A tgt->f_blocks = TheISA::htog(host->f_blocks); 7122544SN/A tgt->f_bfree = TheISA::htog(host->f_bfree); 713360SN/A tgt->f_bavail = TheISA::htog(host->f_bavail); 714360SN/A tgt->f_files = TheISA::htog(host->f_files); 7152544SN/A tgt->f_ffree = TheISA::htog(host->f_ffree); 7162544SN/A memcpy(&tgt->f_fsid, &host->f_fsid, sizeof(host->f_fsid)); 7172544SN/A#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) 7182544SN/A tgt->f_namelen = TheISA::htog(host->f_namemax); 7192544SN/A tgt->f_frsize = TheISA::htog(host->f_bsize); 7202544SN/A#elif defined(__APPLE__) 7212544SN/A tgt->f_namelen = 0; 7222544SN/A tgt->f_frsize = 0; 7232544SN/A#else 7242544SN/A tgt->f_namelen = TheISA::htog(host->f_namelen); 7252553SN/A tgt->f_frsize = TheISA::htog(host->f_frsize); 7261969SN/A#endif 7271969SN/A#if defined(__linux__) 728360SN/A memcpy(&tgt->f_spare, &host->f_spare, sizeof(host->f_spare)); 729360SN/A#else 7301458SN/A /* 731360SN/A * The fields are different sizes per OS. Don't bother with 732360SN/A * f_spare or f_reserved on non-Linux for now. 733378SN/A */ 734360SN/A memset(&tgt->f_spare, 0, sizeof(tgt->f_spare)); 7351450SN/A#endif 736360SN/A 7372064SN/A tgt.copyOut(mem); 738360SN/A} 739360SN/A 740360SN/A/// Target ioctl() handler. For the most part, programs call ioctl() 741360SN/A/// only to find out if their stdout is a tty, to determine whether to 742360SN/A/// do line or block buffering. We always claim that output fds are 7432064SN/A/// not TTYs to provide repeatable results. 7442064SN/Atemplate <class OS> 7452064SN/ASyscallReturn 7462091SN/AioctlFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 7472091SN/A{ 7482064SN/A int index = 0; 749360SN/A int tgt_fd = p->getSyscallArg(tc, index); 7502064SN/A unsigned req = p->getSyscallArg(tc, index); 7512064SN/A 7522064SN/A DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", tgt_fd, req); 7532064SN/A 7542064SN/A if (OS::isTtyReq(req)) 755360SN/A return -ENOTTY; 756360SN/A 7572426SN/A auto dfdp = std::dynamic_pointer_cast<DeviceFDEntry>((*p->fds)[tgt_fd]); 7581458SN/A if (!dfdp) 759360SN/A return -EBADF; 760360SN/A 761378SN/A /** 762360SN/A * If the driver is valid, issue the ioctl through it. Otherwise, 7631450SN/A * there's an implicit assumption that the device is a TTY type and we 764360SN/A * return that we do not have a valid TTY. 7652064SN/A */ 766360SN/A EmulatedDriver *emul_driver = dfdp->getDriver(); 767360SN/A if (emul_driver) 768360SN/A return emul_driver->ioctl(p, tc, req); 769360SN/A 770360SN/A /** 7712091SN/A * For lack of a better return code, return ENOTTY. Ideally, we should 7722091SN/A * return something better here, but at least we issue the warning. 773360SN/A */ 7742426SN/A warn("Unsupported ioctl call (return ENOTTY): ioctl(%d, 0x%x, ...) @ \n", 775360SN/A tgt_fd, req, tc->pcState()); 7761458SN/A return -ENOTTY; 777360SN/A} 778360SN/A 779360SN/Atemplate <class OS> 7801999SN/ASyscallReturn 7811999SN/AopenImpl(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc, 7821999SN/A bool isopenat) 7831999SN/A{ 7841999SN/A int index = 0; 7851999SN/A int tgt_dirfd = -1; 7861999SN/A 7871999SN/A /** 7882461SN/A * If using the openat variant, read in the target directory file 7892400SN/A * descriptor from the simulated process. 7901999SN/A */ 7911999SN/A if (isopenat) 7922426SN/A tgt_dirfd = p->getSyscallArg(tc, index); 7931999SN/A 7941999SN/A /** 7951999SN/A * Retrieve the simulated process' memory proxy and then read in the path 7961999SN/A * string from that memory space into the host's working memory space. 7972091SN/A */ 7982091SN/A std::string path; 7991999SN/A if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 8001999SN/A return -EFAULT; 8011999SN/A 8021999SN/A#ifdef __CYGWIN32__ 8031999SN/A int host_flags = O_BINARY; 8041999SN/A#else 8051999SN/A int host_flags = 0; 8061999SN/A#endif 807378SN/A /** 808360SN/A * Translate target flags into host flags. Flags exist which are not 8091450SN/A * ported between architectures which can cause check failures. 810360SN/A */ 811360SN/A int tgt_flags = p->getSyscallArg(tc, index); 812360SN/A for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) { 813360SN/A if (tgt_flags & OS::openFlagTable[i].tgtFlag) { 814360SN/A tgt_flags &= ~OS::openFlagTable[i].tgtFlag; 815360SN/A host_flags |= OS::openFlagTable[i].hostFlag; 8162553SN/A } 817360SN/A } 818360SN/A if (tgt_flags) { 8191969SN/A warn("open%s: cannot decode flags 0x%x", 8201969SN/A isopenat ? "at" : "", tgt_flags); 821360SN/A } 822360SN/A#ifdef __CYGWIN32__ 823360SN/A host_flags |= O_BINARY; 8242091SN/A#endif 8252091SN/A 8262091SN/A int mode = p->getSyscallArg(tc, index); 827360SN/A 828360SN/A /** 829360SN/A * If the simulated process called open or openat with AT_FDCWD specified, 830360SN/A * take the current working directory value which was passed into the 831360SN/A * process class as a Python parameter and append the current path to 832360SN/A * create a full path. 833360SN/A * Otherwise, openat with a valid target directory file descriptor has 834360SN/A * been called. If the path option, which was passed in as a parameter, 835360SN/A * is not absolute, retrieve the directory file descriptor's path and 836360SN/A * prepend it to the path passed in as a parameter. 837360SN/A * In every case, we should have a full path (which is relevant to the 838360SN/A * host) to work with after this block has been passed. 839360SN/A */ 840360SN/A std::string redir_path = path; 841360SN/A std::string abs_path = path; 842360SN/A if (!isopenat || tgt_dirfd == OS::TGT_AT_FDCWD) { 843360SN/A abs_path = p->absolutePath(path, true); 8442426SN/A redir_path = p->checkPathRedirect(path); 845360SN/A } else if (!startswith(path, "/")) { 8461458SN/A std::shared_ptr<FDEntry> fdep = ((*p->fds)[tgt_dirfd]); 847360SN/A auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep); 848360SN/A if (!ffdp) 8492553SN/A return -EBADF; 8502553SN/A abs_path = ffdp->getFileName() + path; 8512553SN/A redir_path = p->checkPathRedirect(abs_path); 8521354SN/A } 853 854 /** 855 * Since this is an emulated environment, we create pseudo file 856 * descriptors for device requests that have been registered with 857 * the process class through Python; this allows us to create a file 858 * descriptor for subsequent ioctl or mmap calls. 859 */ 860 if (startswith(abs_path, "/dev/")) { 861 std::string filename = abs_path.substr(strlen("/dev/")); 862 EmulatedDriver *drv = p->findDriver(filename); 863 if (drv) { 864 DPRINTF_SYSCALL(Verbose, "open%s: passing call to " 865 "driver open with path[%s]\n", 866 isopenat ? "at" : "", abs_path.c_str()); 867 return drv->open(p, tc, mode, host_flags); 868 } 869 /** 870 * Fall through here for pass through to host devices, such 871 * as /dev/zero 872 */ 873 } 874 875 /** 876 * We make several attempts resolve a call to open. 877 * 878 * 1) Resolve any path redirection before hand. This will set the path 879 * up with variable 'redir_path' which may contain a modified path or 880 * the original path value. This should already be done in prior code. 881 * 2) Try to handle the access using 'special_paths'. Some special_paths 882 * and files cannot be called on the host and need to be handled as 883 * special cases inside the simulator. These special_paths are handled by 884 * C++ routines to provide output back to userspace. 885 * 3) If the full path that was created above does not match any of the 886 * special cases, pass it through to the open call on the __HOST__ to let 887 * the host open the file on our behalf. Again, the openImpl tries to 888 * USE_THE_HOST_FILESYSTEM_OPEN (with a possible redirection to the 889 * faux-filesystem files). The faux-filesystem is dynamically created 890 * during simulator configuration using Python functions. 891 * 4) If the host cannot open the file, the open attempt failed in "3)". 892 * Return the host's error code back through the system call to the 893 * simulated process. If running a debug trace, also notify the user that 894 * the open call failed. 895 * 896 * Any success will set sim_fd to something other than -1 and skip the 897 * next conditions effectively bypassing them. 898 */ 899 int sim_fd = -1; 900 std::string used_path; 901 std::vector<std::string> special_paths = 902 { "/proc/meminfo/", "/system/", "/sys/", "/platform/", 903 "/etc/passwd" }; 904 for (auto entry : special_paths) { 905 if (startswith(path, entry)) { 906 sim_fd = OS::openSpecialFile(abs_path, p, tc); 907 used_path = abs_path; 908 } 909 } 910 if (sim_fd == -1) { 911 sim_fd = open(redir_path.c_str(), host_flags, mode); 912 used_path = redir_path; 913 } 914 if (sim_fd == -1) { 915 int local = -errno; 916 DPRINTF_SYSCALL(Verbose, "open%s: failed -> path:%s " 917 "(inferred from:%s)\n", isopenat ? "at" : "", 918 used_path.c_str(), path.c_str()); 919 return local; 920 } 921 922 /** 923 * The file was opened successfully and needs to be recorded in the 924 * process' file descriptor array so that it can be retrieved later. 925 * The target file descriptor that is chosen will be the lowest unused 926 * file descriptor. 927 * Return the indirect target file descriptor back to the simulated 928 * process to act as a handle for the opened file. 929 */ 930 auto ffdp = std::make_shared<FileFDEntry>(sim_fd, host_flags, path, 0); 931 int tgt_fd = p->fds->allocFD(ffdp); 932 DPRINTF_SYSCALL(Verbose, "open%s: sim_fd[%d], target_fd[%d] -> path:%s\n" 933 "(inferred from:%s)\n", isopenat ? "at" : "", 934 sim_fd, tgt_fd, used_path.c_str(), path.c_str()); 935 return tgt_fd; 936} 937 938/// Target open() handler. 939template <class OS> 940SyscallReturn 941openFunc(SyscallDesc *desc, int callnum, Process *process, 942 ThreadContext *tc) 943{ 944 return openImpl<OS>(desc, callnum, process, tc, false); 945} 946 947/// Target openat() handler. 948template <class OS> 949SyscallReturn 950openatFunc(SyscallDesc *desc, int callnum, Process *process, 951 ThreadContext *tc) 952{ 953 return openImpl<OS>(desc, callnum, process, tc, true); 954} 955 956/// Target unlinkat() handler. 957template <class OS> 958SyscallReturn 959unlinkatFunc(SyscallDesc *desc, int callnum, Process *process, 960 ThreadContext *tc) 961{ 962 int index = 0; 963 int dirfd = process->getSyscallArg(tc, index); 964 if (dirfd != OS::TGT_AT_FDCWD) 965 warn("unlinkat: first argument not AT_FDCWD; unlikely to work"); 966 967 return unlinkHelper(desc, callnum, process, tc, 1); 968} 969 970/// Target facessat() handler 971template <class OS> 972SyscallReturn 973faccessatFunc(SyscallDesc *desc, int callnum, Process *process, 974 ThreadContext *tc) 975{ 976 int index = 0; 977 int dirfd = process->getSyscallArg(tc, index); 978 if (dirfd != OS::TGT_AT_FDCWD) 979 warn("faccessat: first argument not AT_FDCWD; unlikely to work"); 980 return accessFunc(desc, callnum, process, tc, 1); 981} 982 983/// Target readlinkat() handler 984template <class OS> 985SyscallReturn 986readlinkatFunc(SyscallDesc *desc, int callnum, Process *process, 987 ThreadContext *tc) 988{ 989 int index = 0; 990 int dirfd = process->getSyscallArg(tc, index); 991 if (dirfd != OS::TGT_AT_FDCWD) 992 warn("openat: first argument not AT_FDCWD; unlikely to work"); 993 return readlinkFunc(desc, callnum, process, tc, 1); 994} 995 996/// Target renameat() handler. 997template <class OS> 998SyscallReturn 999renameatFunc(SyscallDesc *desc, int callnum, Process *process, 1000 ThreadContext *tc) 1001{ 1002 int index = 0; 1003 1004 int olddirfd = process->getSyscallArg(tc, index); 1005 if (olddirfd != OS::TGT_AT_FDCWD) 1006 warn("renameat: first argument not AT_FDCWD; unlikely to work"); 1007 1008 std::string old_name; 1009 1010 if (!tc->getMemProxy().tryReadString(old_name, 1011 process->getSyscallArg(tc, index))) 1012 return -EFAULT; 1013 1014 int newdirfd = process->getSyscallArg(tc, index); 1015 if (newdirfd != OS::TGT_AT_FDCWD) 1016 warn("renameat: third argument not AT_FDCWD; unlikely to work"); 1017 1018 std::string new_name; 1019 1020 if (!tc->getMemProxy().tryReadString(new_name, 1021 process->getSyscallArg(tc, index))) 1022 return -EFAULT; 1023 1024 // Adjust path for cwd and redirection 1025 old_name = process->checkPathRedirect(old_name); 1026 new_name = process->checkPathRedirect(new_name); 1027 1028 int result = rename(old_name.c_str(), new_name.c_str()); 1029 return (result == -1) ? -errno : result; 1030} 1031 1032/// Target sysinfo() handler. 1033template <class OS> 1034SyscallReturn 1035sysinfoFunc(SyscallDesc *desc, int callnum, Process *process, 1036 ThreadContext *tc) 1037{ 1038 1039 int index = 0; 1040 TypedBufferArg<typename OS::tgt_sysinfo> 1041 sysinfo(process->getSyscallArg(tc, index)); 1042 1043 sysinfo->uptime = seconds_since_epoch; 1044 sysinfo->totalram = process->system->memSize(); 1045 sysinfo->mem_unit = 1; 1046 1047 sysinfo.copyOut(tc->getMemProxy()); 1048 1049 return 0; 1050} 1051 1052/// Target chmod() handler. 1053template <class OS> 1054SyscallReturn 1055chmodFunc(SyscallDesc *desc, int callnum, Process *process, 1056 ThreadContext *tc) 1057{ 1058 std::string path; 1059 1060 int index = 0; 1061 if (!tc->getMemProxy().tryReadString(path, 1062 process->getSyscallArg(tc, index))) { 1063 return -EFAULT; 1064 } 1065 1066 uint32_t mode = process->getSyscallArg(tc, index); 1067 mode_t hostMode = 0; 1068 1069 // XXX translate mode flags via OS::something??? 1070 hostMode = mode; 1071 1072 // Adjust path for cwd and redirection 1073 path = process->checkPathRedirect(path); 1074 1075 // do the chmod 1076 int result = chmod(path.c_str(), hostMode); 1077 if (result < 0) 1078 return -errno; 1079 1080 return 0; 1081} 1082 1083template <class OS> 1084SyscallReturn 1085pollFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1086{ 1087 int index = 0; 1088 Addr fdsPtr = p->getSyscallArg(tc, index); 1089 int nfds = p->getSyscallArg(tc, index); 1090 int tmout = p->getSyscallArg(tc, index); 1091 1092 BufferArg fdsBuf(fdsPtr, sizeof(struct pollfd) * nfds); 1093 fdsBuf.copyIn(tc->getMemProxy()); 1094 1095 /** 1096 * Record the target file descriptors in a local variable. We need to 1097 * replace them with host file descriptors but we need a temporary copy 1098 * for later. Afterwards, replace each target file descriptor in the 1099 * poll_fd array with its host_fd. 1100 */ 1101 int temp_tgt_fds[nfds]; 1102 for (index = 0; index < nfds; index++) { 1103 temp_tgt_fds[index] = ((struct pollfd *)fdsBuf.bufferPtr())[index].fd; 1104 auto tgt_fd = temp_tgt_fds[index]; 1105 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 1106 if (!hbfdp) 1107 return -EBADF; 1108 auto host_fd = hbfdp->getSimFD(); 1109 ((struct pollfd *)fdsBuf.bufferPtr())[index].fd = host_fd; 1110 } 1111 1112 /** 1113 * We cannot allow an infinite poll to occur or it will inevitably cause 1114 * a deadlock in the gem5 simulator with clone. We must pass in tmout with 1115 * a non-negative value, however it also makes no sense to poll on the 1116 * underlying host for any other time than tmout a zero timeout. 1117 */ 1118 int status; 1119 if (tmout < 0) { 1120 status = poll((struct pollfd *)fdsBuf.bufferPtr(), nfds, 0); 1121 if (status == 0) { 1122 /** 1123 * If blocking indefinitely, check the signal list to see if a 1124 * signal would break the poll out of the retry cycle and try 1125 * to return the signal interrupt instead. 1126 */ 1127 System *sysh = tc->getSystemPtr(); 1128 std::list<BasicSignal>::iterator it; 1129 for (it=sysh->signalList.begin(); it!=sysh->signalList.end(); it++) 1130 if (it->receiver == p) 1131 return -EINTR; 1132 return SyscallReturn::retry(); 1133 } 1134 } else 1135 status = poll((struct pollfd *)fdsBuf.bufferPtr(), nfds, 0); 1136 1137 if (status == -1) 1138 return -errno; 1139 1140 /** 1141 * Replace each host_fd in the returned poll_fd array with its original 1142 * target file descriptor. 1143 */ 1144 for (index = 0; index < nfds; index++) { 1145 auto tgt_fd = temp_tgt_fds[index]; 1146 ((struct pollfd *)fdsBuf.bufferPtr())[index].fd = tgt_fd; 1147 } 1148 1149 /** 1150 * Copy out the pollfd struct because the host may have updated fields 1151 * in the structure. 1152 */ 1153 fdsBuf.copyOut(tc->getMemProxy()); 1154 1155 return status; 1156} 1157 1158/// Target fchmod() handler. 1159template <class OS> 1160SyscallReturn 1161fchmodFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1162{ 1163 int index = 0; 1164 int tgt_fd = p->getSyscallArg(tc, index); 1165 uint32_t mode = p->getSyscallArg(tc, index); 1166 1167 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 1168 if (!ffdp) 1169 return -EBADF; 1170 int sim_fd = ffdp->getSimFD(); 1171 1172 mode_t hostMode = mode; 1173 1174 int result = fchmod(sim_fd, hostMode); 1175 1176 return (result < 0) ? -errno : 0; 1177} 1178 1179/// Target mremap() handler. 1180template <class OS> 1181SyscallReturn 1182mremapFunc(SyscallDesc *desc, int callnum, Process *process, ThreadContext *tc) 1183{ 1184 int index = 0; 1185 Addr start = process->getSyscallArg(tc, index); 1186 uint64_t old_length = process->getSyscallArg(tc, index); 1187 uint64_t new_length = process->getSyscallArg(tc, index); 1188 uint64_t flags = process->getSyscallArg(tc, index); 1189 uint64_t provided_address = 0; 1190 bool use_provided_address = flags & OS::TGT_MREMAP_FIXED; 1191 1192 if (use_provided_address) 1193 provided_address = process->getSyscallArg(tc, index); 1194 1195 if ((start % TheISA::PageBytes != 0) || 1196 (provided_address % TheISA::PageBytes != 0)) { 1197 warn("mremap failing: arguments not page aligned"); 1198 return -EINVAL; 1199 } 1200 1201 new_length = roundUp(new_length, TheISA::PageBytes); 1202 1203 if (new_length > old_length) { 1204 std::shared_ptr<MemState> mem_state = process->memState; 1205 Addr mmap_end = mem_state->getMmapEnd(); 1206 1207 if ((start + old_length) == mmap_end && 1208 (!use_provided_address || provided_address == start)) { 1209 // This case cannot occur when growing downward, as 1210 // start is greater than or equal to mmap_end. 1211 uint64_t diff = new_length - old_length; 1212 process->allocateMem(mmap_end, diff); 1213 mem_state->setMmapEnd(mmap_end + diff); 1214 return start; 1215 } else { 1216 if (!use_provided_address && !(flags & OS::TGT_MREMAP_MAYMOVE)) { 1217 warn("can't remap here and MREMAP_MAYMOVE flag not set\n"); 1218 return -ENOMEM; 1219 } else { 1220 uint64_t new_start = provided_address; 1221 if (!use_provided_address) { 1222 new_start = process->mmapGrowsDown() ? 1223 mmap_end - new_length : mmap_end; 1224 mmap_end = process->mmapGrowsDown() ? 1225 new_start : mmap_end + new_length; 1226 mem_state->setMmapEnd(mmap_end); 1227 } 1228 1229 process->pTable->remap(start, old_length, new_start); 1230 warn("mremapping to new vaddr %08p-%08p, adding %d\n", 1231 new_start, new_start + new_length, 1232 new_length - old_length); 1233 // add on the remaining unallocated pages 1234 process->allocateMem(new_start + old_length, 1235 new_length - old_length, 1236 use_provided_address /* clobber */); 1237 if (use_provided_address && 1238 ((new_start + new_length > mem_state->getMmapEnd() && 1239 !process->mmapGrowsDown()) || 1240 (new_start < mem_state->getMmapEnd() && 1241 process->mmapGrowsDown()))) { 1242 // something fishy going on here, at least notify the user 1243 // @todo: increase mmap_end? 1244 warn("mmap region limit exceeded with MREMAP_FIXED\n"); 1245 } 1246 warn("returning %08p as start\n", new_start); 1247 return new_start; 1248 } 1249 } 1250 } else { 1251 if (use_provided_address && provided_address != start) 1252 process->pTable->remap(start, new_length, provided_address); 1253 process->pTable->unmap(start + new_length, old_length - new_length); 1254 return use_provided_address ? provided_address : start; 1255 } 1256} 1257 1258/// Target stat() handler. 1259template <class OS> 1260SyscallReturn 1261statFunc(SyscallDesc *desc, int callnum, Process *process, 1262 ThreadContext *tc) 1263{ 1264 std::string path; 1265 1266 int index = 0; 1267 if (!tc->getMemProxy().tryReadString(path, 1268 process->getSyscallArg(tc, index))) { 1269 return -EFAULT; 1270 } 1271 Addr bufPtr = process->getSyscallArg(tc, index); 1272 1273 // Adjust path for cwd and redirection 1274 path = process->checkPathRedirect(path); 1275 1276 struct stat hostBuf; 1277 int result = stat(path.c_str(), &hostBuf); 1278 1279 if (result < 0) 1280 return -errno; 1281 1282 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1283 1284 return 0; 1285} 1286 1287 1288/// Target stat64() handler. 1289template <class OS> 1290SyscallReturn 1291stat64Func(SyscallDesc *desc, int callnum, Process *process, 1292 ThreadContext *tc) 1293{ 1294 std::string path; 1295 1296 int index = 0; 1297 if (!tc->getMemProxy().tryReadString(path, 1298 process->getSyscallArg(tc, index))) 1299 return -EFAULT; 1300 Addr bufPtr = process->getSyscallArg(tc, index); 1301 1302 // Adjust path for cwd and redirection 1303 path = process->checkPathRedirect(path); 1304 1305#if NO_STAT64 1306 struct stat hostBuf; 1307 int result = stat(path.c_str(), &hostBuf); 1308#else 1309 struct stat64 hostBuf; 1310 int result = stat64(path.c_str(), &hostBuf); 1311#endif 1312 1313 if (result < 0) 1314 return -errno; 1315 1316 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1317 1318 return 0; 1319} 1320 1321 1322/// Target fstatat64() handler. 1323template <class OS> 1324SyscallReturn 1325fstatat64Func(SyscallDesc *desc, int callnum, Process *process, 1326 ThreadContext *tc) 1327{ 1328 int index = 0; 1329 int dirfd = process->getSyscallArg(tc, index); 1330 if (dirfd != OS::TGT_AT_FDCWD) 1331 warn("fstatat64: first argument not AT_FDCWD; unlikely to work"); 1332 1333 std::string path; 1334 if (!tc->getMemProxy().tryReadString(path, 1335 process->getSyscallArg(tc, index))) 1336 return -EFAULT; 1337 Addr bufPtr = process->getSyscallArg(tc, index); 1338 1339 // Adjust path for cwd and redirection 1340 path = process->checkPathRedirect(path); 1341 1342#if NO_STAT64 1343 struct stat hostBuf; 1344 int result = stat(path.c_str(), &hostBuf); 1345#else 1346 struct stat64 hostBuf; 1347 int result = stat64(path.c_str(), &hostBuf); 1348#endif 1349 1350 if (result < 0) 1351 return -errno; 1352 1353 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1354 1355 return 0; 1356} 1357 1358 1359/// Target fstat64() handler. 1360template <class OS> 1361SyscallReturn 1362fstat64Func(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1363{ 1364 int index = 0; 1365 int tgt_fd = p->getSyscallArg(tc, index); 1366 Addr bufPtr = p->getSyscallArg(tc, index); 1367 1368 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 1369 if (!ffdp) 1370 return -EBADF; 1371 int sim_fd = ffdp->getSimFD(); 1372 1373#if NO_STAT64 1374 struct stat hostBuf; 1375 int result = fstat(sim_fd, &hostBuf); 1376#else 1377 struct stat64 hostBuf; 1378 int result = fstat64(sim_fd, &hostBuf); 1379#endif 1380 1381 if (result < 0) 1382 return -errno; 1383 1384 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (sim_fd == 1)); 1385 1386 return 0; 1387} 1388 1389 1390/// Target lstat() handler. 1391template <class OS> 1392SyscallReturn 1393lstatFunc(SyscallDesc *desc, int callnum, Process *process, 1394 ThreadContext *tc) 1395{ 1396 std::string path; 1397 1398 int index = 0; 1399 if (!tc->getMemProxy().tryReadString(path, 1400 process->getSyscallArg(tc, index))) { 1401 return -EFAULT; 1402 } 1403 Addr bufPtr = process->getSyscallArg(tc, index); 1404 1405 // Adjust path for cwd and redirection 1406 path = process->checkPathRedirect(path); 1407 1408 struct stat hostBuf; 1409 int result = lstat(path.c_str(), &hostBuf); 1410 1411 if (result < 0) 1412 return -errno; 1413 1414 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1415 1416 return 0; 1417} 1418 1419/// Target lstat64() handler. 1420template <class OS> 1421SyscallReturn 1422lstat64Func(SyscallDesc *desc, int callnum, Process *process, 1423 ThreadContext *tc) 1424{ 1425 std::string path; 1426 1427 int index = 0; 1428 if (!tc->getMemProxy().tryReadString(path, 1429 process->getSyscallArg(tc, index))) { 1430 return -EFAULT; 1431 } 1432 Addr bufPtr = process->getSyscallArg(tc, index); 1433 1434 // Adjust path for cwd and redirection 1435 path = process->checkPathRedirect(path); 1436 1437#if NO_STAT64 1438 struct stat hostBuf; 1439 int result = lstat(path.c_str(), &hostBuf); 1440#else 1441 struct stat64 hostBuf; 1442 int result = lstat64(path.c_str(), &hostBuf); 1443#endif 1444 1445 if (result < 0) 1446 return -errno; 1447 1448 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1449 1450 return 0; 1451} 1452 1453/// Target fstat() handler. 1454template <class OS> 1455SyscallReturn 1456fstatFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1457{ 1458 int index = 0; 1459 int tgt_fd = p->getSyscallArg(tc, index); 1460 Addr bufPtr = p->getSyscallArg(tc, index); 1461 1462 DPRINTF_SYSCALL(Verbose, "fstat(%d, ...)\n", tgt_fd); 1463 1464 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 1465 if (!ffdp) 1466 return -EBADF; 1467 int sim_fd = ffdp->getSimFD(); 1468 1469 struct stat hostBuf; 1470 int result = fstat(sim_fd, &hostBuf); 1471 1472 if (result < 0) 1473 return -errno; 1474 1475 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (sim_fd == 1)); 1476 1477 return 0; 1478} 1479 1480/// Target statfs() handler. 1481template <class OS> 1482SyscallReturn 1483statfsFunc(SyscallDesc *desc, int callnum, Process *process, 1484 ThreadContext *tc) 1485{ 1486#if NO_STATFS 1487 warn("Host OS cannot support calls to statfs. Ignoring syscall"); 1488#else 1489 std::string path; 1490 1491 int index = 0; 1492 if (!tc->getMemProxy().tryReadString(path, 1493 process->getSyscallArg(tc, index))) { 1494 return -EFAULT; 1495 } 1496 Addr bufPtr = process->getSyscallArg(tc, index); 1497 1498 // Adjust path for cwd and redirection 1499 path = process->checkPathRedirect(path); 1500 1501 struct statfs hostBuf; 1502 int result = statfs(path.c_str(), &hostBuf); 1503 1504 if (result < 0) 1505 return -errno; 1506 1507 copyOutStatfsBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1508#endif 1509 return 0; 1510} 1511 1512template <class OS> 1513SyscallReturn 1514cloneFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1515{ 1516 int index = 0; 1517 1518 RegVal flags = p->getSyscallArg(tc, index); 1519 RegVal newStack = p->getSyscallArg(tc, index); 1520 Addr ptidPtr = p->getSyscallArg(tc, index); 1521 1522#if THE_ISA == RISCV_ISA or THE_ISA == ARM_ISA 1523 /** 1524 * Linux sets CLONE_BACKWARDS flag for RISC-V and Arm. 1525 * The flag defines the list of clone() arguments in the following 1526 * order: flags -> newStack -> ptidPtr -> tlsPtr -> ctidPtr 1527 */ 1528 Addr tlsPtr = p->getSyscallArg(tc, index); 1529 Addr ctidPtr = p->getSyscallArg(tc, index); 1530#else 1531 Addr ctidPtr = p->getSyscallArg(tc, index); 1532 Addr tlsPtr = p->getSyscallArg(tc, index); 1533#endif 1534 1535 if (((flags & OS::TGT_CLONE_SIGHAND)&& !(flags & OS::TGT_CLONE_VM)) || 1536 ((flags & OS::TGT_CLONE_THREAD) && !(flags & OS::TGT_CLONE_SIGHAND)) || 1537 ((flags & OS::TGT_CLONE_FS) && (flags & OS::TGT_CLONE_NEWNS)) || 1538 ((flags & OS::TGT_CLONE_NEWIPC) && (flags & OS::TGT_CLONE_SYSVSEM)) || 1539 ((flags & OS::TGT_CLONE_NEWPID) && (flags & OS::TGT_CLONE_THREAD)) || 1540 ((flags & OS::TGT_CLONE_VM) && !(newStack))) 1541 return -EINVAL; 1542 1543 ThreadContext *ctc; 1544 if (!(ctc = p->findFreeContext())) { 1545 DPRINTF_SYSCALL(Verbose, "clone: no spare thread context in system" 1546 "[cpu %d, thread %d]", tc->cpuId(), tc->threadId()); 1547 return -EAGAIN; 1548 } 1549 1550 /** 1551 * Note that ProcessParams is generated by swig and there are no other 1552 * examples of how to create anything but this default constructor. The 1553 * fields are manually initialized instead of passing parameters to the 1554 * constructor. 1555 */ 1556 ProcessParams *pp = new ProcessParams(); 1557 pp->executable.assign(*(new std::string(p->progName()))); 1558 pp->cmd.push_back(*(new std::string(p->progName()))); 1559 pp->system = p->system; 1560 pp->cwd.assign(p->tgtCwd); 1561 pp->input.assign("stdin"); 1562 pp->output.assign("stdout"); 1563 pp->errout.assign("stderr"); 1564 pp->uid = p->uid(); 1565 pp->euid = p->euid(); 1566 pp->gid = p->gid(); 1567 pp->egid = p->egid(); 1568 1569 /* Find the first free PID that's less than the maximum */ 1570 std::set<int> const& pids = p->system->PIDs; 1571 int temp_pid = *pids.begin(); 1572 do { 1573 temp_pid++; 1574 } while (pids.find(temp_pid) != pids.end()); 1575 if (temp_pid >= System::maxPID) 1576 fatal("temp_pid is too large: %d", temp_pid); 1577 1578 pp->pid = temp_pid; 1579 pp->ppid = (flags & OS::TGT_CLONE_THREAD) ? p->ppid() : p->pid(); 1580 pp->useArchPT = p->useArchPT; 1581 pp->kvmInSE = p->kvmInSE; 1582 Process *cp = pp->create(); 1583 delete pp; 1584 1585 Process *owner = ctc->getProcessPtr(); 1586 ctc->setProcessPtr(cp); 1587 cp->assignThreadContext(ctc->contextId()); 1588 owner->revokeThreadContext(ctc->contextId()); 1589 1590 if (flags & OS::TGT_CLONE_PARENT_SETTID) { 1591 BufferArg ptidBuf(ptidPtr, sizeof(long)); 1592 long *ptid = (long *)ptidBuf.bufferPtr(); 1593 *ptid = cp->pid(); 1594 ptidBuf.copyOut(tc->getMemProxy()); 1595 } 1596 1597 if (flags & OS::TGT_CLONE_THREAD) { 1598 cp->pTable->shared = true; 1599 cp->useForClone = true; 1600 } 1601 cp->initState(); 1602 p->clone(tc, ctc, cp, flags); 1603 1604 if (flags & OS::TGT_CLONE_THREAD) { 1605 delete cp->sigchld; 1606 cp->sigchld = p->sigchld; 1607 } else if (flags & OS::TGT_SIGCHLD) { 1608 *cp->sigchld = true; 1609 } 1610 1611 if (flags & OS::TGT_CLONE_CHILD_SETTID) { 1612 BufferArg ctidBuf(ctidPtr, sizeof(long)); 1613 long *ctid = (long *)ctidBuf.bufferPtr(); 1614 *ctid = cp->pid(); 1615 ctidBuf.copyOut(ctc->getMemProxy()); 1616 } 1617 1618 if (flags & OS::TGT_CLONE_CHILD_CLEARTID) 1619 cp->childClearTID = (uint64_t)ctidPtr; 1620 1621 ctc->clearArchRegs(); 1622 1623 OS::archClone(flags, p, cp, tc, ctc, newStack, tlsPtr); 1624 1625 cp->setSyscallReturn(ctc, 0); 1626 1627#if THE_ISA == ALPHA_ISA 1628 ctc->setIntReg(TheISA::SyscallSuccessReg, 0); 1629#elif THE_ISA == SPARC_ISA 1630 tc->setIntReg(TheISA::SyscallPseudoReturnReg, 0); 1631 ctc->setIntReg(TheISA::SyscallPseudoReturnReg, 1); 1632#endif 1633 1634 if (p->kvmInSE) { 1635#if THE_ISA == X86_ISA 1636 ctc->pcState(tc->readIntReg(TheISA::INTREG_RCX)); 1637#else 1638 panic("KVM CPU model is not supported for this ISA"); 1639#endif 1640 } else { 1641 TheISA::PCState cpc = tc->pcState(); 1642 cpc.advance(); 1643 ctc->pcState(cpc); 1644 } 1645 ctc->activate(); 1646 1647 return cp->pid(); 1648} 1649 1650/// Target fstatfs() handler. 1651template <class OS> 1652SyscallReturn 1653fstatfsFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1654{ 1655 int index = 0; 1656 int tgt_fd = p->getSyscallArg(tc, index); 1657 Addr bufPtr = p->getSyscallArg(tc, index); 1658 1659 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 1660 if (!ffdp) 1661 return -EBADF; 1662 int sim_fd = ffdp->getSimFD(); 1663 1664 struct statfs hostBuf; 1665 int result = fstatfs(sim_fd, &hostBuf); 1666 1667 if (result < 0) 1668 return -errno; 1669 1670 copyOutStatfsBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1671 1672 return 0; 1673} 1674 1675/// Target readv() handler. 1676template <class OS> 1677SyscallReturn 1678readvFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1679{ 1680 int index = 0; 1681 int tgt_fd = p->getSyscallArg(tc, index); 1682 1683 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 1684 if (!ffdp) 1685 return -EBADF; 1686 int sim_fd = ffdp->getSimFD(); 1687 1688 SETranslatingPortProxy &prox = tc->getMemProxy(); 1689 uint64_t tiov_base = p->getSyscallArg(tc, index); 1690 size_t count = p->getSyscallArg(tc, index); 1691 typename OS::tgt_iovec tiov[count]; 1692 struct iovec hiov[count]; 1693 for (size_t i = 0; i < count; ++i) { 1694 prox.readBlob(tiov_base + (i * sizeof(typename OS::tgt_iovec)), 1695 (uint8_t*)&tiov[i], sizeof(typename OS::tgt_iovec)); 1696 hiov[i].iov_len = TheISA::gtoh(tiov[i].iov_len); 1697 hiov[i].iov_base = new char [hiov[i].iov_len]; 1698 } 1699 1700 int result = readv(sim_fd, hiov, count); 1701 int local_errno = errno; 1702 1703 for (size_t i = 0; i < count; ++i) { 1704 if (result != -1) { 1705 prox.writeBlob(TheISA::htog(tiov[i].iov_base), 1706 (uint8_t*)hiov[i].iov_base, hiov[i].iov_len); 1707 } 1708 delete [] (char *)hiov[i].iov_base; 1709 } 1710 1711 return (result == -1) ? -local_errno : result; 1712} 1713 1714/// Target writev() handler. 1715template <class OS> 1716SyscallReturn 1717writevFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1718{ 1719 int index = 0; 1720 int tgt_fd = p->getSyscallArg(tc, index); 1721 1722 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 1723 if (!hbfdp) 1724 return -EBADF; 1725 int sim_fd = hbfdp->getSimFD(); 1726 1727 SETranslatingPortProxy &prox = tc->getMemProxy(); 1728 uint64_t tiov_base = p->getSyscallArg(tc, index); 1729 size_t count = p->getSyscallArg(tc, index); 1730 struct iovec hiov[count]; 1731 for (size_t i = 0; i < count; ++i) { 1732 typename OS::tgt_iovec tiov; 1733 1734 prox.readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec), 1735 (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec)); 1736 hiov[i].iov_len = TheISA::gtoh(tiov.iov_len); 1737 hiov[i].iov_base = new char [hiov[i].iov_len]; 1738 prox.readBlob(TheISA::gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base, 1739 hiov[i].iov_len); 1740 } 1741 1742 int result = writev(sim_fd, hiov, count); 1743 1744 for (size_t i = 0; i < count; ++i) 1745 delete [] (char *)hiov[i].iov_base; 1746 1747 return (result == -1) ? -errno : result; 1748} 1749 1750/// Real mmap handler. 1751template <class OS> 1752SyscallReturn 1753mmapImpl(SyscallDesc *desc, int num, Process *p, ThreadContext *tc, 1754 bool is_mmap2) 1755{ 1756 int index = 0; 1757 Addr start = p->getSyscallArg(tc, index); 1758 uint64_t length = p->getSyscallArg(tc, index); 1759 int prot = p->getSyscallArg(tc, index); 1760 int tgt_flags = p->getSyscallArg(tc, index); 1761 int tgt_fd = p->getSyscallArg(tc, index); 1762 int offset = p->getSyscallArg(tc, index); 1763 1764 if (is_mmap2) 1765 offset *= TheISA::PageBytes; 1766 1767 if (start & (TheISA::PageBytes - 1) || 1768 offset & (TheISA::PageBytes - 1) || 1769 (tgt_flags & OS::TGT_MAP_PRIVATE && 1770 tgt_flags & OS::TGT_MAP_SHARED) || 1771 (!(tgt_flags & OS::TGT_MAP_PRIVATE) && 1772 !(tgt_flags & OS::TGT_MAP_SHARED)) || 1773 !length) { 1774 return -EINVAL; 1775 } 1776 1777 if ((prot & PROT_WRITE) && (tgt_flags & OS::TGT_MAP_SHARED)) { 1778 // With shared mmaps, there are two cases to consider: 1779 // 1) anonymous: writes should modify the mapping and this should be 1780 // visible to observers who share the mapping. Currently, it's 1781 // difficult to update the shared mapping because there's no 1782 // structure which maintains information about the which virtual 1783 // memory areas are shared. If that structure existed, it would be 1784 // possible to make the translations point to the same frames. 1785 // 2) file-backed: writes should modify the mapping and the file 1786 // which is backed by the mapping. The shared mapping problem is the 1787 // same as what was mentioned about the anonymous mappings. For 1788 // file-backed mappings, the writes to the file are difficult 1789 // because it requires syncing what the mapping holds with the file 1790 // that resides on the host system. So, any write on a real system 1791 // would cause the change to be propagated to the file mapping at 1792 // some point in the future (the inode is tracked along with the 1793 // mapping). This isn't guaranteed to always happen, but it usually 1794 // works well enough. The guarantee is provided by the msync system 1795 // call. We could force the change through with shared mappings with 1796 // a call to msync, but that again would require more information 1797 // than we currently maintain. 1798 warn("mmap: writing to shared mmap region is currently " 1799 "unsupported. The write succeeds on the target, but it " 1800 "will not be propagated to the host or shared mappings"); 1801 } 1802 1803 length = roundUp(length, TheISA::PageBytes); 1804 1805 int sim_fd = -1; 1806 uint8_t *pmap = nullptr; 1807 if (!(tgt_flags & OS::TGT_MAP_ANONYMOUS)) { 1808 std::shared_ptr<FDEntry> fdep = (*p->fds)[tgt_fd]; 1809 1810 auto dfdp = std::dynamic_pointer_cast<DeviceFDEntry>(fdep); 1811 if (dfdp) { 1812 EmulatedDriver *emul_driver = dfdp->getDriver(); 1813 return emul_driver->mmap(p, tc, start, length, prot, 1814 tgt_flags, tgt_fd, offset); 1815 } 1816 1817 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep); 1818 if (!ffdp) 1819 return -EBADF; 1820 sim_fd = ffdp->getSimFD(); 1821 1822 pmap = (decltype(pmap))mmap(nullptr, length, PROT_READ, MAP_PRIVATE, 1823 sim_fd, offset); 1824 1825 if (pmap == (decltype(pmap))-1) { 1826 warn("mmap: failed to map file into host address space"); 1827 return -errno; 1828 } 1829 } 1830 1831 // Extend global mmap region if necessary. Note that we ignore the 1832 // start address unless MAP_FIXED is specified. 1833 if (!(tgt_flags & OS::TGT_MAP_FIXED)) { 1834 std::shared_ptr<MemState> mem_state = p->memState; 1835 Addr mmap_end = mem_state->getMmapEnd(); 1836 1837 start = p->mmapGrowsDown() ? mmap_end - length : mmap_end; 1838 mmap_end = p->mmapGrowsDown() ? start : mmap_end + length; 1839 1840 mem_state->setMmapEnd(mmap_end); 1841 } 1842 1843 DPRINTF_SYSCALL(Verbose, " mmap range is 0x%x - 0x%x\n", 1844 start, start + length - 1); 1845 1846 // We only allow mappings to overwrite existing mappings if 1847 // TGT_MAP_FIXED is set. Otherwise it shouldn't be a problem 1848 // because we ignore the start hint if TGT_MAP_FIXED is not set. 1849 int clobber = tgt_flags & OS::TGT_MAP_FIXED; 1850 if (clobber) { 1851 for (auto tc : p->system->threadContexts) { 1852 // If we might be overwriting old mappings, we need to 1853 // invalidate potentially stale mappings out of the TLBs. 1854 tc->getDTBPtr()->flushAll(); 1855 tc->getITBPtr()->flushAll(); 1856 } 1857 } 1858 1859 // Allocate physical memory and map it in. If the page table is already 1860 // mapped and clobber is not set, the simulator will issue throw a 1861 // fatal and bail out of the simulation. 1862 p->allocateMem(start, length, clobber); 1863 1864 // Transfer content into target address space. 1865 SETranslatingPortProxy &tp = tc->getMemProxy(); 1866 if (tgt_flags & OS::TGT_MAP_ANONYMOUS) { 1867 // In general, we should zero the mapped area for anonymous mappings, 1868 // with something like: 1869 // tp.memsetBlob(start, 0, length); 1870 // However, given that we don't support sparse mappings, and 1871 // some applications can map a couple of gigabytes of space 1872 // (intending sparse usage), that can get painfully expensive. 1873 // Fortunately, since we don't properly implement munmap either, 1874 // there's no danger of remapping used memory, so for now all 1875 // newly mapped memory should already be zeroed so we can skip it. 1876 } else { 1877 // It is possible to mmap an area larger than a file, however 1878 // accessing unmapped portions the system triggers a "Bus error" 1879 // on the host. We must know when to stop copying the file from 1880 // the host into the target address space. 1881 struct stat file_stat; 1882 if (fstat(sim_fd, &file_stat) > 0) 1883 fatal("mmap: cannot stat file"); 1884 1885 // Copy the portion of the file that is resident. This requires 1886 // checking both the mmap size and the filesize that we are 1887 // trying to mmap into this space; the mmap size also depends 1888 // on the specified offset into the file. 1889 uint64_t size = std::min((uint64_t)file_stat.st_size - offset, 1890 length); 1891 tp.writeBlob(start, pmap, size); 1892 1893 // Cleanup the mmap region before exiting this function. 1894 munmap(pmap, length); 1895 1896 // Maintain the symbol table for dynamic executables. 1897 // The loader will call mmap to map the images into its address 1898 // space and we intercept that here. We can verify that we are 1899 // executing inside the loader by checking the program counter value. 1900 // XXX: with multiprogrammed workloads or multi-node configurations, 1901 // this will not work since there is a single global symbol table. 1902 ObjectFile *interpreter = p->getInterpreter(); 1903 if (interpreter) { 1904 Addr text_start = interpreter->textBase(); 1905 Addr text_end = text_start + interpreter->textSize(); 1906 1907 Addr pc = tc->pcState().pc(); 1908 1909 if (pc >= text_start && pc < text_end) { 1910 std::shared_ptr<FDEntry> fdep = (*p->fds)[tgt_fd]; 1911 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep); 1912 ObjectFile *lib = createObjectFile(ffdp->getFileName()); 1913 1914 if (lib) { 1915 lib->loadAllSymbols(debugSymbolTable, 1916 lib->textBase(), start); 1917 } 1918 } 1919 } 1920 1921 // Note that we do not zero out the remainder of the mapping. This 1922 // is done by a real system, but it probably will not affect 1923 // execution (hopefully). 1924 } 1925 1926 return start; 1927} 1928 1929template <class OS> 1930SyscallReturn 1931pwrite64Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1932{ 1933 int index = 0; 1934 int tgt_fd = p->getSyscallArg(tc, index); 1935 Addr bufPtr = p->getSyscallArg(tc, index); 1936 int nbytes = p->getSyscallArg(tc, index); 1937 int offset = p->getSyscallArg(tc, index); 1938 1939 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 1940 if (!ffdp) 1941 return -EBADF; 1942 int sim_fd = ffdp->getSimFD(); 1943 1944 BufferArg bufArg(bufPtr, nbytes); 1945 bufArg.copyIn(tc->getMemProxy()); 1946 1947 int bytes_written = pwrite(sim_fd, bufArg.bufferPtr(), nbytes, offset); 1948 1949 return (bytes_written == -1) ? -errno : bytes_written; 1950} 1951 1952/// Target mmap() handler. 1953template <class OS> 1954SyscallReturn 1955mmapFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1956{ 1957 return mmapImpl<OS>(desc, num, p, tc, false); 1958} 1959 1960/// Target mmap2() handler. 1961template <class OS> 1962SyscallReturn 1963mmap2Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1964{ 1965 return mmapImpl<OS>(desc, num, p, tc, true); 1966} 1967 1968/// Target getrlimit() handler. 1969template <class OS> 1970SyscallReturn 1971getrlimitFunc(SyscallDesc *desc, int callnum, Process *process, 1972 ThreadContext *tc) 1973{ 1974 int index = 0; 1975 unsigned resource = process->getSyscallArg(tc, index); 1976 TypedBufferArg<typename OS::rlimit> rlp(process->getSyscallArg(tc, index)); 1977 1978 switch (resource) { 1979 case OS::TGT_RLIMIT_STACK: 1980 // max stack size in bytes: make up a number (8MB for now) 1981 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; 1982 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1983 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1984 break; 1985 1986 case OS::TGT_RLIMIT_DATA: 1987 // max data segment size in bytes: make up a number 1988 rlp->rlim_cur = rlp->rlim_max = 256 * 1024 * 1024; 1989 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1990 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1991 break; 1992 1993 default: 1994 warn("getrlimit: unimplemented resource %d", resource); 1995 return -EINVAL; 1996 break; 1997 } 1998 1999 rlp.copyOut(tc->getMemProxy()); 2000 return 0; 2001} 2002 2003template <class OS> 2004SyscallReturn 2005prlimitFunc(SyscallDesc *desc, int callnum, Process *process, 2006 ThreadContext *tc) 2007{ 2008 int index = 0; 2009 if (process->getSyscallArg(tc, index) != 0) 2010 { 2011 warn("prlimit: ignoring rlimits for nonzero pid"); 2012 return -EPERM; 2013 } 2014 int resource = process->getSyscallArg(tc, index); 2015 Addr n = process->getSyscallArg(tc, index); 2016 if (n != 0) 2017 warn("prlimit: ignoring new rlimit"); 2018 Addr o = process->getSyscallArg(tc, index); 2019 if (o != 0) 2020 { 2021 TypedBufferArg<typename OS::rlimit> rlp(o); 2022 switch (resource) { 2023 case OS::TGT_RLIMIT_STACK: 2024 // max stack size in bytes: make up a number (8MB for now) 2025 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; 2026 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 2027 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 2028 break; 2029 case OS::TGT_RLIMIT_DATA: 2030 // max data segment size in bytes: make up a number 2031 rlp->rlim_cur = rlp->rlim_max = 256*1024*1024; 2032 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 2033 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 2034 break; 2035 default: 2036 warn("prlimit: unimplemented resource %d", resource); 2037 return -EINVAL; 2038 break; 2039 } 2040 rlp.copyOut(tc->getMemProxy()); 2041 } 2042 return 0; 2043} 2044 2045/// Target clock_gettime() function. 2046template <class OS> 2047SyscallReturn 2048clock_gettimeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 2049{ 2050 int index = 1; 2051 //int clk_id = p->getSyscallArg(tc, index); 2052 TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index)); 2053 2054 getElapsedTimeNano(tp->tv_sec, tp->tv_nsec); 2055 tp->tv_sec += seconds_since_epoch; 2056 tp->tv_sec = TheISA::htog(tp->tv_sec); 2057 tp->tv_nsec = TheISA::htog(tp->tv_nsec); 2058 2059 tp.copyOut(tc->getMemProxy()); 2060 2061 return 0; 2062} 2063 2064/// Target clock_getres() function. 2065template <class OS> 2066SyscallReturn 2067clock_getresFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 2068{ 2069 int index = 1; 2070 TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index)); 2071 2072 // Set resolution at ns, which is what clock_gettime() returns 2073 tp->tv_sec = 0; 2074 tp->tv_nsec = 1; 2075 2076 tp.copyOut(tc->getMemProxy()); 2077 2078 return 0; 2079} 2080 2081/// Target gettimeofday() handler. 2082template <class OS> 2083SyscallReturn 2084gettimeofdayFunc(SyscallDesc *desc, int callnum, Process *process, 2085 ThreadContext *tc) 2086{ 2087 int index = 0; 2088 TypedBufferArg<typename OS::timeval> tp(process->getSyscallArg(tc, index)); 2089 2090 getElapsedTimeMicro(tp->tv_sec, tp->tv_usec); 2091 tp->tv_sec += seconds_since_epoch; 2092 tp->tv_sec = TheISA::htog(tp->tv_sec); 2093 tp->tv_usec = TheISA::htog(tp->tv_usec); 2094 2095 tp.copyOut(tc->getMemProxy()); 2096 2097 return 0; 2098} 2099 2100 2101/// Target utimes() handler. 2102template <class OS> 2103SyscallReturn 2104utimesFunc(SyscallDesc *desc, int callnum, Process *process, 2105 ThreadContext *tc) 2106{ 2107 std::string path; 2108 2109 int index = 0; 2110 if (!tc->getMemProxy().tryReadString(path, 2111 process->getSyscallArg(tc, index))) { 2112 return -EFAULT; 2113 } 2114 2115 TypedBufferArg<typename OS::timeval [2]> 2116 tp(process->getSyscallArg(tc, index)); 2117 tp.copyIn(tc->getMemProxy()); 2118 2119 struct timeval hostTimeval[2]; 2120 for (int i = 0; i < 2; ++i) { 2121 hostTimeval[i].tv_sec = TheISA::gtoh((*tp)[i].tv_sec); 2122 hostTimeval[i].tv_usec = TheISA::gtoh((*tp)[i].tv_usec); 2123 } 2124 2125 // Adjust path for cwd and redirection 2126 path = process->checkPathRedirect(path); 2127 2128 int result = utimes(path.c_str(), hostTimeval); 2129 2130 if (result < 0) 2131 return -errno; 2132 2133 return 0; 2134} 2135 2136template <class OS> 2137SyscallReturn 2138execveFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 2139{ 2140 desc->setFlags(0); 2141 2142 int index = 0; 2143 std::string path; 2144 SETranslatingPortProxy & mem_proxy = tc->getMemProxy(); 2145 if (!mem_proxy.tryReadString(path, p->getSyscallArg(tc, index))) 2146 return -EFAULT; 2147 2148 if (access(path.c_str(), F_OK) == -1) 2149 return -EACCES; 2150 2151 auto read_in = [](std::vector<std::string> & vect, 2152 SETranslatingPortProxy & mem_proxy, 2153 Addr mem_loc) 2154 { 2155 for (int inc = 0; ; inc++) { 2156 BufferArg b((mem_loc + sizeof(Addr) * inc), sizeof(Addr)); 2157 b.copyIn(mem_proxy); 2158 2159 if (!*(Addr*)b.bufferPtr()) 2160 break; 2161 2162 vect.push_back(std::string()); 2163 mem_proxy.tryReadString(vect[inc], *(Addr*)b.bufferPtr()); 2164 } 2165 }; 2166 2167 /** 2168 * Note that ProcessParams is generated by swig and there are no other 2169 * examples of how to create anything but this default constructor. The 2170 * fields are manually initialized instead of passing parameters to the 2171 * constructor. 2172 */ 2173 ProcessParams *pp = new ProcessParams(); 2174 pp->executable = path; 2175 Addr argv_mem_loc = p->getSyscallArg(tc, index); 2176 read_in(pp->cmd, mem_proxy, argv_mem_loc); 2177 Addr envp_mem_loc = p->getSyscallArg(tc, index); 2178 read_in(pp->env, mem_proxy, envp_mem_loc); 2179 pp->uid = p->uid(); 2180 pp->egid = p->egid(); 2181 pp->euid = p->euid(); 2182 pp->gid = p->gid(); 2183 pp->ppid = p->ppid(); 2184 pp->pid = p->pid(); 2185 pp->input.assign("cin"); 2186 pp->output.assign("cout"); 2187 pp->errout.assign("cerr"); 2188 pp->cwd.assign(p->tgtCwd); 2189 pp->system = p->system; 2190 /** 2191 * Prevent process object creation with identical PIDs (which will trip 2192 * a fatal check in Process constructor). The execve call is supposed to 2193 * take over the currently executing process' identity but replace 2194 * whatever it is doing with a new process image. Instead of hijacking 2195 * the process object in the simulator, we create a new process object 2196 * and bind to the previous process' thread below (hijacking the thread). 2197 */ 2198 p->system->PIDs.erase(p->pid()); 2199 Process *new_p = pp->create(); 2200 delete pp; 2201 2202 /** 2203 * Work through the file descriptor array and close any files marked 2204 * close-on-exec. 2205 */ 2206 new_p->fds = p->fds; 2207 for (int i = 0; i < new_p->fds->getSize(); i++) { 2208 std::shared_ptr<FDEntry> fdep = (*new_p->fds)[i]; 2209 if (fdep && fdep->getCOE()) 2210 new_p->fds->closeFDEntry(i); 2211 } 2212 2213 *new_p->sigchld = true; 2214 2215 delete p; 2216 tc->clearArchRegs(); 2217 tc->setProcessPtr(new_p); 2218 new_p->assignThreadContext(tc->contextId()); 2219 new_p->initState(); 2220 tc->activate(); 2221 TheISA::PCState pcState = tc->pcState(); 2222 tc->setNPC(pcState.instAddr()); 2223 2224 desc->setFlags(SyscallDesc::SuppressReturnValue); 2225 return 0; 2226} 2227 2228/// Target getrusage() function. 2229template <class OS> 2230SyscallReturn 2231getrusageFunc(SyscallDesc *desc, int callnum, Process *process, 2232 ThreadContext *tc) 2233{ 2234 int index = 0; 2235 int who = process->getSyscallArg(tc, index); // THREAD, SELF, or CHILDREN 2236 TypedBufferArg<typename OS::rusage> rup(process->getSyscallArg(tc, index)); 2237 2238 rup->ru_utime.tv_sec = 0; 2239 rup->ru_utime.tv_usec = 0; 2240 rup->ru_stime.tv_sec = 0; 2241 rup->ru_stime.tv_usec = 0; 2242 rup->ru_maxrss = 0; 2243 rup->ru_ixrss = 0; 2244 rup->ru_idrss = 0; 2245 rup->ru_isrss = 0; 2246 rup->ru_minflt = 0; 2247 rup->ru_majflt = 0; 2248 rup->ru_nswap = 0; 2249 rup->ru_inblock = 0; 2250 rup->ru_oublock = 0; 2251 rup->ru_msgsnd = 0; 2252 rup->ru_msgrcv = 0; 2253 rup->ru_nsignals = 0; 2254 rup->ru_nvcsw = 0; 2255 rup->ru_nivcsw = 0; 2256 2257 switch (who) { 2258 case OS::TGT_RUSAGE_SELF: 2259 getElapsedTimeMicro(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec); 2260 rup->ru_utime.tv_sec = TheISA::htog(rup->ru_utime.tv_sec); 2261 rup->ru_utime.tv_usec = TheISA::htog(rup->ru_utime.tv_usec); 2262 break; 2263 2264 case OS::TGT_RUSAGE_CHILDREN: 2265 // do nothing. We have no child processes, so they take no time. 2266 break; 2267 2268 default: 2269 // don't really handle THREAD or CHILDREN, but just warn and 2270 // plow ahead 2271 warn("getrusage() only supports RUSAGE_SELF. Parameter %d ignored.", 2272 who); 2273 } 2274 2275 rup.copyOut(tc->getMemProxy()); 2276 2277 return 0; 2278} 2279 2280/// Target times() function. 2281template <class OS> 2282SyscallReturn 2283timesFunc(SyscallDesc *desc, int callnum, Process *process, 2284 ThreadContext *tc) 2285{ 2286 int index = 0; 2287 TypedBufferArg<typename OS::tms> bufp(process->getSyscallArg(tc, index)); 2288 2289 // Fill in the time structure (in clocks) 2290 int64_t clocks = curTick() * OS::M5_SC_CLK_TCK / SimClock::Int::s; 2291 bufp->tms_utime = clocks; 2292 bufp->tms_stime = 0; 2293 bufp->tms_cutime = 0; 2294 bufp->tms_cstime = 0; 2295 2296 // Convert to host endianness 2297 bufp->tms_utime = TheISA::htog(bufp->tms_utime); 2298 2299 // Write back 2300 bufp.copyOut(tc->getMemProxy()); 2301 2302 // Return clock ticks since system boot 2303 return clocks; 2304} 2305 2306/// Target time() function. 2307template <class OS> 2308SyscallReturn 2309timeFunc(SyscallDesc *desc, int callnum, Process *process, ThreadContext *tc) 2310{ 2311 typename OS::time_t sec, usec; 2312 getElapsedTimeMicro(sec, usec); 2313 sec += seconds_since_epoch; 2314 2315 int index = 0; 2316 Addr taddr = (Addr)process->getSyscallArg(tc, index); 2317 if (taddr != 0) { 2318 typename OS::time_t t = sec; 2319 t = TheISA::htog(t); 2320 SETranslatingPortProxy &p = tc->getMemProxy(); 2321 p.writeBlob(taddr, (uint8_t*)&t, (int)sizeof(typename OS::time_t)); 2322 } 2323 return sec; 2324} 2325 2326template <class OS> 2327SyscallReturn 2328tgkillFunc(SyscallDesc *desc, int num, Process *process, ThreadContext *tc) 2329{ 2330 int index = 0; 2331 int tgid = process->getSyscallArg(tc, index); 2332 int tid = process->getSyscallArg(tc, index); 2333 int sig = process->getSyscallArg(tc, index); 2334 2335 /** 2336 * This system call is intended to allow killing a specific thread 2337 * within an arbitrary thread group if sanctioned with permission checks. 2338 * It's usually true that threads share the termination signal as pointed 2339 * out by the pthread_kill man page and this seems to be the intended 2340 * usage. Due to this being an emulated environment, assume the following: 2341 * Threads are allowed to call tgkill because the EUID for all threads 2342 * should be the same. There is no signal handling mechanism for kernel 2343 * registration of signal handlers since signals are poorly supported in 2344 * emulation mode. Since signal handlers cannot be registered, all 2345 * threads within in a thread group must share the termination signal. 2346 * We never exhaust PIDs so there's no chance of finding the wrong one 2347 * due to PID rollover. 2348 */ 2349 2350 System *sys = tc->getSystemPtr(); 2351 Process *tgt_proc = nullptr; 2352 for (int i = 0; i < sys->numContexts(); i++) { 2353 Process *temp = sys->threadContexts[i]->getProcessPtr(); 2354 if (temp->pid() == tid) { 2355 tgt_proc = temp; 2356 break; 2357 } 2358 } 2359 2360 if (sig != 0 || sig != OS::TGT_SIGABRT) 2361 return -EINVAL; 2362 2363 if (tgt_proc == nullptr) 2364 return -ESRCH; 2365 2366 if (tgid != -1 && tgt_proc->tgid() != tgid) 2367 return -ESRCH; 2368 2369 if (sig == OS::TGT_SIGABRT) 2370 exitGroupFunc(desc, 252, process, tc); 2371 2372 return 0; 2373} 2374 2375template <class OS> 2376SyscallReturn 2377socketFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 2378{ 2379 int index = 0; 2380 int domain = p->getSyscallArg(tc, index); 2381 int type = p->getSyscallArg(tc, index); 2382 int prot = p->getSyscallArg(tc, index); 2383 2384 int sim_fd = socket(domain, type, prot); 2385 if (sim_fd == -1) 2386 return -errno; 2387 2388 auto sfdp = std::make_shared<SocketFDEntry>(sim_fd, domain, type, prot); 2389 int tgt_fd = p->fds->allocFD(sfdp); 2390 2391 return tgt_fd; 2392} 2393 2394template <class OS> 2395SyscallReturn 2396socketpairFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 2397{ 2398 int index = 0; 2399 int domain = p->getSyscallArg(tc, index); 2400 int type = p->getSyscallArg(tc, index); 2401 int prot = p->getSyscallArg(tc, index); 2402 Addr svPtr = p->getSyscallArg(tc, index); 2403 2404 BufferArg svBuf((Addr)svPtr, 2 * sizeof(int)); 2405 int status = socketpair(domain, type, prot, (int *)svBuf.bufferPtr()); 2406 if (status == -1) 2407 return -errno; 2408 2409 int *fds = (int *)svBuf.bufferPtr(); 2410 2411 auto sfdp1 = std::make_shared<SocketFDEntry>(fds[0], domain, type, prot); 2412 fds[0] = p->fds->allocFD(sfdp1); 2413 auto sfdp2 = std::make_shared<SocketFDEntry>(fds[1], domain, type, prot); 2414 fds[1] = p->fds->allocFD(sfdp2); 2415 svBuf.copyOut(tc->getMemProxy()); 2416 2417 return status; 2418} 2419 2420template <class OS> 2421SyscallReturn 2422selectFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 2423{ 2424 int retval; 2425 2426 int index = 0; 2427 int nfds_t = p->getSyscallArg(tc, index); 2428 Addr fds_read_ptr = p->getSyscallArg(tc, index); 2429 Addr fds_writ_ptr = p->getSyscallArg(tc, index); 2430 Addr fds_excp_ptr = p->getSyscallArg(tc, index); 2431 Addr time_val_ptr = p->getSyscallArg(tc, index); 2432 2433 TypedBufferArg<typename OS::fd_set> rd_t(fds_read_ptr); 2434 TypedBufferArg<typename OS::fd_set> wr_t(fds_writ_ptr); 2435 TypedBufferArg<typename OS::fd_set> ex_t(fds_excp_ptr); 2436 TypedBufferArg<typename OS::timeval> tp(time_val_ptr); 2437 2438 /** 2439 * Host fields. Notice that these use the definitions from the system 2440 * headers instead of the gem5 headers and libraries. If the host and 2441 * target have different header file definitions, this will not work. 2442 */ 2443 fd_set rd_h; 2444 FD_ZERO(&rd_h); 2445 fd_set wr_h; 2446 FD_ZERO(&wr_h); 2447 fd_set ex_h; 2448 FD_ZERO(&ex_h); 2449 2450 /** 2451 * Copy in the fd_set from the target. 2452 */ 2453 if (fds_read_ptr) 2454 rd_t.copyIn(tc->getMemProxy()); 2455 if (fds_writ_ptr) 2456 wr_t.copyIn(tc->getMemProxy()); 2457 if (fds_excp_ptr) 2458 ex_t.copyIn(tc->getMemProxy()); 2459 2460 /** 2461 * We need to translate the target file descriptor set into a host file 2462 * descriptor set. This involves both our internal process fd array 2463 * and the fd_set defined in Linux header files. The nfds field also 2464 * needs to be updated as it will be only target specific after 2465 * retrieving it from the target; the nfds value is expected to be the 2466 * highest file descriptor that needs to be checked, so we need to extend 2467 * it out for nfds_h when we do the update. 2468 */ 2469 int nfds_h = 0; 2470 std::map<int, int> trans_map; 2471 auto try_add_host_set = [&](fd_set *tgt_set_entry, 2472 fd_set *hst_set_entry, 2473 int iter) -> bool 2474 { 2475 /** 2476 * By this point, we know that we are looking at a valid file 2477 * descriptor set on the target. We need to check if the target file 2478 * descriptor value passed in as iter is part of the set. 2479 */ 2480 if (FD_ISSET(iter, tgt_set_entry)) { 2481 /** 2482 * We know that the target file descriptor belongs to the set, 2483 * but we do not yet know if the file descriptor is valid or 2484 * that we have a host mapping. Check that now. 2485 */ 2486 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[iter]); 2487 if (!hbfdp) 2488 return true; 2489 auto sim_fd = hbfdp->getSimFD(); 2490 2491 /** 2492 * Add the sim_fd to tgt_fd translation into trans_map for use 2493 * later when we need to zero the target fd_set structures and 2494 * then update them with hits returned from the host select call. 2495 */ 2496 trans_map[sim_fd] = iter; 2497 2498 /** 2499 * We know that the host file descriptor exists so now we check 2500 * if we need to update the max count for nfds_h before passing 2501 * the duplicated structure into the host. 2502 */ 2503 nfds_h = std::max(nfds_h - 1, sim_fd + 1); 2504 2505 /** 2506 * Add the host file descriptor to the set that we are going to 2507 * pass into the host. 2508 */ 2509 FD_SET(sim_fd, hst_set_entry); 2510 } 2511 return false; 2512 }; 2513 2514 for (int i = 0; i < nfds_t; i++) { 2515 if (fds_read_ptr) { 2516 bool ebadf = try_add_host_set((fd_set*)&*rd_t, &rd_h, i); 2517 if (ebadf) return -EBADF; 2518 } 2519 if (fds_writ_ptr) { 2520 bool ebadf = try_add_host_set((fd_set*)&*wr_t, &wr_h, i); 2521 if (ebadf) return -EBADF; 2522 } 2523 if (fds_excp_ptr) { 2524 bool ebadf = try_add_host_set((fd_set*)&*ex_t, &ex_h, i); 2525 if (ebadf) return -EBADF; 2526 } 2527 } 2528 2529 if (time_val_ptr) { 2530 /** 2531 * It might be possible to decrement the timeval based on some 2532 * derivation of wall clock determined from elapsed simulator ticks 2533 * but that seems like overkill. Rather, we just set the timeval with 2534 * zero timeout. (There is no reason to block during the simulation 2535 * as it only decreases simulator performance.) 2536 */ 2537 tp->tv_sec = 0; 2538 tp->tv_usec = 0; 2539 2540 retval = select(nfds_h, 2541 fds_read_ptr ? &rd_h : nullptr, 2542 fds_writ_ptr ? &wr_h : nullptr, 2543 fds_excp_ptr ? &ex_h : nullptr, 2544 (timeval*)&*tp); 2545 } else { 2546 /** 2547 * If the timeval pointer is null, setup a new timeval structure to 2548 * pass into the host select call. Unfortunately, we will need to 2549 * manually check the return value and throw a retry fault if the 2550 * return value is zero. Allowing the system call to block will 2551 * likely deadlock the event queue. 2552 */ 2553 struct timeval tv = { 0, 0 }; 2554 2555 retval = select(nfds_h, 2556 fds_read_ptr ? &rd_h : nullptr, 2557 fds_writ_ptr ? &wr_h : nullptr, 2558 fds_excp_ptr ? &ex_h : nullptr, 2559 &tv); 2560 2561 if (retval == 0) { 2562 /** 2563 * If blocking indefinitely, check the signal list to see if a 2564 * signal would break the poll out of the retry cycle and try to 2565 * return the signal interrupt instead. 2566 */ 2567 for (auto sig : tc->getSystemPtr()->signalList) 2568 if (sig.receiver == p) 2569 return -EINTR; 2570 return SyscallReturn::retry(); 2571 } 2572 } 2573 2574 if (retval == -1) 2575 return -errno; 2576 2577 FD_ZERO((fd_set*)&*rd_t); 2578 FD_ZERO((fd_set*)&*wr_t); 2579 FD_ZERO((fd_set*)&*ex_t); 2580 2581 /** 2582 * We need to translate the host file descriptor set into a target file 2583 * descriptor set. This involves both our internal process fd array 2584 * and the fd_set defined in header files. 2585 */ 2586 for (int i = 0; i < nfds_h; i++) { 2587 if (fds_read_ptr) { 2588 if (FD_ISSET(i, &rd_h)) 2589 FD_SET(trans_map[i], (fd_set*)&*rd_t); 2590 } 2591 2592 if (fds_writ_ptr) { 2593 if (FD_ISSET(i, &wr_h)) 2594 FD_SET(trans_map[i], (fd_set*)&*wr_t); 2595 } 2596 2597 if (fds_excp_ptr) { 2598 if (FD_ISSET(i, &ex_h)) 2599 FD_SET(trans_map[i], (fd_set*)&*ex_t); 2600 } 2601 } 2602 2603 if (fds_read_ptr) 2604 rd_t.copyOut(tc->getMemProxy()); 2605 if (fds_writ_ptr) 2606 wr_t.copyOut(tc->getMemProxy()); 2607 if (fds_excp_ptr) 2608 ex_t.copyOut(tc->getMemProxy()); 2609 if (time_val_ptr) 2610 tp.copyOut(tc->getMemProxy()); 2611 2612 return retval; 2613} 2614 2615template <class OS> 2616SyscallReturn 2617readFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 2618{ 2619 int index = 0; 2620 int tgt_fd = p->getSyscallArg(tc, index); 2621 Addr buf_ptr = p->getSyscallArg(tc, index); 2622 int nbytes = p->getSyscallArg(tc, index); 2623 2624 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 2625 if (!hbfdp) 2626 return -EBADF; 2627 int sim_fd = hbfdp->getSimFD(); 2628 2629 struct pollfd pfd; 2630 pfd.fd = sim_fd; 2631 pfd.events = POLLIN | POLLPRI; 2632 if ((poll(&pfd, 1, 0) == 0) 2633 && !(hbfdp->getFlags() & OS::TGT_O_NONBLOCK)) 2634 return SyscallReturn::retry(); 2635 2636 BufferArg buf_arg(buf_ptr, nbytes); 2637 int bytes_read = read(sim_fd, buf_arg.bufferPtr(), nbytes); 2638 2639 if (bytes_read > 0) 2640 buf_arg.copyOut(tc->getMemProxy()); 2641 2642 return (bytes_read == -1) ? -errno : bytes_read; 2643} 2644 2645template <class OS> 2646SyscallReturn 2647writeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 2648{ 2649 int index = 0; 2650 int tgt_fd = p->getSyscallArg(tc, index); 2651 Addr buf_ptr = p->getSyscallArg(tc, index); 2652 int nbytes = p->getSyscallArg(tc, index); 2653 2654 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 2655 if (!hbfdp) 2656 return -EBADF; 2657 int sim_fd = hbfdp->getSimFD(); 2658 2659 BufferArg buf_arg(buf_ptr, nbytes); 2660 buf_arg.copyIn(tc->getMemProxy()); 2661 2662 struct pollfd pfd; 2663 pfd.fd = sim_fd; 2664 pfd.events = POLLOUT; 2665 2666 /** 2667 * We don't want to poll on /dev/random. The kernel will not enable the 2668 * file descriptor for writing unless the entropy in the system falls 2669 * below write_wakeup_threshold. This is not guaranteed to happen 2670 * depending on host settings. 2671 */ 2672 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(hbfdp); 2673 if (ffdp && (ffdp->getFileName() != "/dev/random")) { 2674 if (!poll(&pfd, 1, 0) && !(ffdp->getFlags() & OS::TGT_O_NONBLOCK)) 2675 return SyscallReturn::retry(); 2676 } 2677 2678 int bytes_written = write(sim_fd, buf_arg.bufferPtr(), nbytes); 2679 2680 if (bytes_written != -1) 2681 fsync(sim_fd); 2682 2683 return (bytes_written == -1) ? -errno : bytes_written; 2684} 2685 2686template <class OS> 2687SyscallReturn 2688wait4Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 2689{ 2690 int index = 0; 2691 pid_t pid = p->getSyscallArg(tc, index); 2692 Addr statPtr = p->getSyscallArg(tc, index); 2693 int options = p->getSyscallArg(tc, index); 2694 Addr rusagePtr = p->getSyscallArg(tc, index); 2695 2696 if (rusagePtr) 2697 DPRINTFR(SyscallVerbose, 2698 "%d: %s: syscall wait4: rusage pointer provided however " 2699 "functionality not supported. Ignoring rusage pointer.\n", 2700 curTick(), tc->getCpuPtr()->name()); 2701 2702 /** 2703 * Currently, wait4 is only implemented so that it will wait for children 2704 * exit conditions which are denoted by a SIGCHLD signals posted into the 2705 * system signal list. We return no additional information via any of the 2706 * parameters supplied to wait4. If nothing is found in the system signal 2707 * list, we will wait indefinitely for SIGCHLD to post by retrying the 2708 * call. 2709 */ 2710 System *sysh = tc->getSystemPtr(); 2711 std::list<BasicSignal>::iterator iter; 2712 for (iter=sysh->signalList.begin(); iter!=sysh->signalList.end(); iter++) { 2713 if (iter->receiver == p) { 2714 if (pid < -1) { 2715 if ((iter->sender->pgid() == -pid) 2716 && (iter->signalValue == OS::TGT_SIGCHLD)) 2717 goto success; 2718 } else if (pid == -1) { 2719 if (iter->signalValue == OS::TGT_SIGCHLD) 2720 goto success; 2721 } else if (pid == 0) { 2722 if ((iter->sender->pgid() == p->pgid()) 2723 && (iter->signalValue == OS::TGT_SIGCHLD)) 2724 goto success; 2725 } else { 2726 if ((iter->sender->pid() == pid) 2727 && (iter->signalValue == OS::TGT_SIGCHLD)) 2728 goto success; 2729 } 2730 } 2731 } 2732 2733 return (options & OS::TGT_WNOHANG) ? 0 : SyscallReturn::retry(); 2734 2735success: 2736 // Set status to EXITED for WIFEXITED evaluations. 2737 const int EXITED = 0; 2738 BufferArg statusBuf(statPtr, sizeof(int)); 2739 *(int *)statusBuf.bufferPtr() = EXITED; 2740 statusBuf.copyOut(tc->getMemProxy()); 2741 2742 // Return the child PID. 2743 pid_t retval = iter->sender->pid(); 2744 sysh->signalList.erase(iter); 2745 return retval; 2746} 2747 2748template <class OS> 2749SyscallReturn 2750acceptFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 2751{ 2752 struct sockaddr sa; 2753 socklen_t addrLen; 2754 int host_fd; 2755 int index = 0; 2756 int tgt_fd = p->getSyscallArg(tc, index); 2757 Addr addrPtr = p->getSyscallArg(tc, index); 2758 Addr lenPtr = p->getSyscallArg(tc, index); 2759 2760 BufferArg *lenBufPtr = nullptr; 2761 BufferArg *addrBufPtr = nullptr; 2762 2763 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 2764 if (!sfdp) 2765 return -EBADF; 2766 int sim_fd = sfdp->getSimFD(); 2767 2768 /** 2769 * We poll the socket file descriptor first to guarantee that we do not 2770 * block on our accept call. The socket can be opened without the 2771 * non-blocking flag (it blocks). This will cause deadlocks between 2772 * communicating processes. 2773 */ 2774 struct pollfd pfd; 2775 pfd.fd = sim_fd; 2776 pfd.events = POLLIN | POLLPRI; 2777 if ((poll(&pfd, 1, 0) == 0) 2778 && !(sfdp->getFlags() & OS::TGT_O_NONBLOCK)) 2779 return SyscallReturn::retry(); 2780 2781 if (lenPtr) { 2782 lenBufPtr = new BufferArg(lenPtr, sizeof(socklen_t)); 2783 lenBufPtr->copyIn(tc->getMemProxy()); 2784 memcpy(&addrLen, (socklen_t *)lenBufPtr->bufferPtr(), 2785 sizeof(socklen_t)); 2786 } 2787 2788 if (addrPtr) { 2789 addrBufPtr = new BufferArg(addrPtr, sizeof(struct sockaddr)); 2790 addrBufPtr->copyIn(tc->getMemProxy()); 2791 memcpy(&sa, (struct sockaddr *)addrBufPtr->bufferPtr(), 2792 sizeof(struct sockaddr)); 2793 } 2794 2795 host_fd = accept(sim_fd, &sa, &addrLen); 2796 2797 if (host_fd == -1) 2798 return -errno; 2799 2800 if (addrPtr) { 2801 memcpy(addrBufPtr->bufferPtr(), &sa, sizeof(sa)); 2802 addrBufPtr->copyOut(tc->getMemProxy()); 2803 delete(addrBufPtr); 2804 } 2805 2806 if (lenPtr) { 2807 *(socklen_t *)lenBufPtr->bufferPtr() = addrLen; 2808 lenBufPtr->copyOut(tc->getMemProxy()); 2809 delete(lenBufPtr); 2810 } 2811 2812 auto afdp = std::make_shared<SocketFDEntry>(host_fd, sfdp->_domain, 2813 sfdp->_type, sfdp->_protocol); 2814 return p->fds->allocFD(afdp); 2815} 2816 2817#endif // __SIM_SYSCALL_EMUL_HH__ 2818