syscall_emul.hh revision 13902
1360SN/A/* 21458SN/A * Copyright (c) 2012-2013, 2015 ARM Limited 3360SN/A * Copyright (c) 2015 Advanced Micro Devices, Inc. 4360SN/A * All rights reserved 5360SN/A * 6360SN/A * The license below extends only to copyright in the software and shall 7360SN/A * not be construed as granting a license to any other intellectual 8360SN/A * property including but not limited to intellectual property relating 9360SN/A * to a hardware implementation of the functionality of the software 10360SN/A * licensed hereunder. You may use the software subject to the license 11360SN/A * terms below provided that you ensure that this notice is replicated 12360SN/A * unmodified and in its entirety in all distributions of the software, 13360SN/A * modified or unmodified, in source code or in binary form. 14360SN/A * 15360SN/A * Copyright (c) 2003-2005 The Regents of The University of Michigan 16360SN/A * All rights reserved. 17360SN/A * 18360SN/A * Redistribution and use in source and binary forms, with or without 19360SN/A * modification, are permitted provided that the following conditions are 20360SN/A * met: redistributions of source code must retain the above copyright 21360SN/A * notice, this list of conditions and the following disclaimer; 22360SN/A * redistributions in binary form must reproduce the above copyright 23360SN/A * notice, this list of conditions and the following disclaimer in the 24360SN/A * documentation and/or other materials provided with the distribution; 25360SN/A * neither the name of the copyright holders nor the names of its 26360SN/A * contributors may be used to endorse or promote products derived from 272665Ssaidi@eecs.umich.edu * this software without specific prior written permission. 282665Ssaidi@eecs.umich.edu * 292665Ssaidi@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 30360SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 31360SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 321354SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 331354SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 34360SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 352764Sstever@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 369202Spalle@lyckegaard.dk * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 379202Spalle@lyckegaard.dk * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 382064SN/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 */ 44360SN/A 451809SN/A#ifndef __SIM_SYSCALL_EMUL_HH__ 465543Ssaidi@eecs.umich.edu#define __SIM_SYSCALL_EMUL_HH__ 471809SN/A 483113Sgblack@eecs.umich.edu#if (defined(__APPLE__) || defined(__OpenBSD__) || \ 498229Snate@binkert.org defined(__FreeBSD__) || defined(__CYGWIN__) || \ 508229Snate@binkert.org defined(__NetBSD__)) 513113Sgblack@eecs.umich.edu#define NO_STAT64 1 527075Snate@binkert.org#else 538229Snate@binkert.org#define NO_STAT64 0 547075Snate@binkert.org#endif 55360SN/A 562474SN/A#if (defined(__APPLE__) || defined(__OpenBSD__) || \ 575543Ssaidi@eecs.umich.edu defined(__FreeBSD__) || defined(__NetBSD__)) 582462SN/A#define NO_STATFS 1 591354SN/A#else 606216Snate@binkert.org#define NO_STATFS 0 616658Snate@binkert.org#endif 622474SN/A 632680Sktlim@umich.edu#if (defined(__APPLE__) || defined(__OpenBSD__) || \ 648232Snate@binkert.org defined(__FreeBSD__) || defined(__NetBSD__)) 658229Snate@binkert.org#define NO_FALLOCATE 1 668706Sandreas.hansson@arm.com#else 677678Sgblack@eecs.umich.edu#define NO_FALLOCATE 0 688229Snate@binkert.org#endif 698766Sgblack@eecs.umich.edu 706640Svince@csl.cornell.edu/// 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 79378SN/A#endif 801450SN/A#include <fcntl.h> 813114Sgblack@eecs.umich.edu#include <net/if.h> 82360SN/A#include <poll.h> 835543Ssaidi@eecs.umich.edu#include <sys/ioctl.h> 845543Ssaidi@eecs.umich.edu#include <sys/mman.h> 855543Ssaidi@eecs.umich.edu#include <sys/socket.h> 86360SN/A#include <sys/stat.h> 87360SN/A 88360SN/A#if (NO_STATFS == 0) 89360SN/A#include <sys/statfs.h> 90360SN/A 912680Sktlim@umich.edu#else 92360SN/A#include <sys/mount.h> 93360SN/A 94360SN/A#endif 95360SN/A#include <sys/time.h> 96360SN/A#include <sys/types.h> 97360SN/A#include <sys/uio.h> 98360SN/A#include <unistd.h> 99360SN/A 100360SN/A#include <cerrno> 101360SN/A#include <memory> 102360SN/A#include <string> 1033114Sgblack@eecs.umich.edu 104360SN/A#include "arch/generic/tlb.hh" 105360SN/A#include "arch/utility.hh" 106360SN/A#include "base/intmath.hh" 107360SN/A#include "base/loader/object_file.hh" 108360SN/A#include "base/logging.hh" 109360SN/A#include "base/trace.hh" 110360SN/A#include "base/types.hh" 111360SN/A#include "config/the_isa.hh" 112360SN/A#include "cpu/base.hh" 113360SN/A#include "cpu/thread_context.hh" 114360SN/A#include "mem/page_table.hh" 115360SN/A#include "params/Process.hh" 116360SN/A#include "sim/emul_driver.hh" 117360SN/A#include "sim/futex_map.hh" 118360SN/A#include "sim/process.hh" 119360SN/A#include "sim/syscall_debug_macros.hh" 120360SN/A#include "sim/syscall_desc.hh" 121360SN/A#include "sim/syscall_emul_buf.hh" 122360SN/A#include "sim/syscall_return.hh" 123360SN/A 124360SN/A#if defined(__APPLE__) && defined(__MACH__) && !defined(CMSG_ALIGN) 1258852Sandreas.hansson@arm.com#define CMSG_ALIGN(len) (((len) + sizeof(size_t) - 1) & ~(sizeof(size_t) - 1)) 126360SN/A#endif 1278852Sandreas.hansson@arm.com 1285543Ssaidi@eecs.umich.edu////////////////////////////////////////////////////////////////////// 129360SN/A// 130360SN/A// The following emulation functions are generic enough that they 131360SN/A// don't need to be recompiled for different emulated OS's. They are 132360SN/A// defined in sim/syscall_emul.cc. 133360SN/A// 1348852Sandreas.hansson@arm.com////////////////////////////////////////////////////////////////////// 135360SN/A 1368852Sandreas.hansson@arm.com 1375543Ssaidi@eecs.umich.edu/// Handler for unimplemented syscalls that we haven't thought about. 138360SN/ASyscallReturn unimplementedFunc(SyscallDesc *desc, int num, 139360SN/A Process *p, ThreadContext *tc); 140360SN/A 141360SN/A/// Handler for unimplemented syscalls that we never intend to 142360SN/A/// implement (signal handling, etc.) and should not affect the correct 143360SN/A/// behavior of the program. Print a warning only if the appropriate 144360SN/A/// trace flag is enabled. Return success to the target program. 145360SN/ASyscallReturn ignoreFunc(SyscallDesc *desc, int num, 146360SN/A Process *p, ThreadContext *tc); 147360SN/A 148360SN/A// Target fallocateFunc() handler. 149360SN/ASyscallReturn fallocateFunc(SyscallDesc *desc, int num, 150360SN/A Process *p, ThreadContext *tc); 1515543Ssaidi@eecs.umich.edu 152360SN/A/// Target exit() handler: terminate current context. 153360SN/ASyscallReturn exitFunc(SyscallDesc *desc, int num, 154360SN/A Process *p, ThreadContext *tc); 155360SN/A 156360SN/A/// Target exit_group() handler: terminate simulation. (exit all threads) 157360SN/ASyscallReturn exitGroupFunc(SyscallDesc *desc, int num, 158360SN/A Process *p, ThreadContext *tc); 159360SN/A 160360SN/A/// Target set_tid_address() handler. 161360SN/ASyscallReturn setTidAddressFunc(SyscallDesc *desc, int num, 162360SN/A Process *p, ThreadContext *tc); 163360SN/A 164360SN/A/// Target getpagesize() handler. 165360SN/ASyscallReturn getpagesizeFunc(SyscallDesc *desc, int num, 166360SN/A Process *p, ThreadContext *tc); 167360SN/A 168360SN/A/// Target brk() handler: set brk address. 1695543Ssaidi@eecs.umich.eduSyscallReturn brkFunc(SyscallDesc *desc, int num, 1705543Ssaidi@eecs.umich.edu Process *p, ThreadContext *tc); 171502SN/A 172360SN/A/// Target close() handler. 173360SN/ASyscallReturn closeFunc(SyscallDesc *desc, int num, 174360SN/A Process *p, ThreadContext *tc); 175360SN/A 176360SN/A/// Target lseek() handler. 177360SN/ASyscallReturn lseekFunc(SyscallDesc *desc, int num, 178360SN/A Process *p, ThreadContext *tc); 179360SN/A 180360SN/A/// Target _llseek() handler. 181360SN/ASyscallReturn _llseekFunc(SyscallDesc *desc, int num, 182360SN/A Process *p, ThreadContext *tc); 183378SN/A 1841706SN/A/// Target munmap() handler. 1853114Sgblack@eecs.umich.eduSyscallReturn munmapFunc(SyscallDesc *desc, int num, 186378SN/A Process *p, ThreadContext *tc); 187378SN/A 188378SN/A/// Target shutdown() handler. 189378SN/ASyscallReturn shutdownFunc(SyscallDesc *desc, int num, 190378SN/A Process *p, ThreadContext *tc); 1911706SN/A 1923114Sgblack@eecs.umich.edu/// Target gethostname() handler. 1938149SChris.Emmons@ARM.comSyscallReturn gethostnameFunc(SyscallDesc *desc, int num, 1948149SChris.Emmons@ARM.com Process *p, ThreadContext *tc); 195360SN/A 1966109Ssanchezd@stanford.edu/// Target getcwd() handler. 1971706SN/ASyscallReturn getcwdFunc(SyscallDesc *desc, int num, 1983114Sgblack@eecs.umich.edu Process *p, ThreadContext *tc); 199378SN/A 2006109Ssanchezd@stanford.edu/// Target readlink() handler. 2016109Ssanchezd@stanford.eduSyscallReturn readlinkFunc(SyscallDesc *desc, int num, 2026109Ssanchezd@stanford.edu Process *p, ThreadContext *tc, 2036109Ssanchezd@stanford.edu int index = 0); 204378SN/ASyscallReturn readlinkFunc(SyscallDesc *desc, int num, 2051706SN/A Process *p, ThreadContext *tc); 2063114Sgblack@eecs.umich.edu 207378SN/A/// Target unlink() handler. 2085748SSteve.Reinhardt@amd.comSyscallReturn unlinkHelper(SyscallDesc *desc, int num, 2095748SSteve.Reinhardt@amd.com Process *p, ThreadContext *tc, 2105748SSteve.Reinhardt@amd.com int index); 211378SN/ASyscallReturn unlinkFunc(SyscallDesc *desc, int num, 212378SN/A Process *p, ThreadContext *tc); 2131706SN/A 2143114Sgblack@eecs.umich.edu/// Target link() handler 215378SN/ASyscallReturn linkFunc(SyscallDesc *desc, int num, Process *p, 216378SN/A ThreadContext *tc); 2171706SN/A 2183114Sgblack@eecs.umich.edu/// Target symlink() handler. 219378SN/ASyscallReturn symlinkFunc(SyscallDesc *desc, int num, Process *p, 220378SN/A ThreadContext *tc); 2211706SN/A 2223114Sgblack@eecs.umich.edu/// Target mkdir() handler. 223378SN/ASyscallReturn mkdirFunc(SyscallDesc *desc, int num, 224378SN/A Process *p, ThreadContext *tc); 2251706SN/A 2263114Sgblack@eecs.umich.edu/// Target mknod() handler. 227378SN/ASyscallReturn mknodFunc(SyscallDesc *desc, int num, 2284118Sgblack@eecs.umich.edu Process *p, ThreadContext *tc); 2294118Sgblack@eecs.umich.edu 2304118Sgblack@eecs.umich.edu/// Target chdir() handler. 2314118Sgblack@eecs.umich.eduSyscallReturn chdirFunc(SyscallDesc *desc, int num, 232378SN/A Process *p, ThreadContext *tc); 2331706SN/A 2343114Sgblack@eecs.umich.edu// Target rmdir() handler. 235378SN/ASyscallReturn rmdirFunc(SyscallDesc *desc, int num, 236378SN/A Process *p, ThreadContext *tc); 2371706SN/A 2383114Sgblack@eecs.umich.edu/// Target rename() handler. 239360SN/ASyscallReturn renameFunc(SyscallDesc *desc, int num, 2405513SMichael.Adler@intel.com Process *p, ThreadContext *tc); 2415513SMichael.Adler@intel.com 2425513SMichael.Adler@intel.com 2435513SMichael.Adler@intel.com/// Target truncate() handler. 2445513SMichael.Adler@intel.comSyscallReturn truncateFunc(SyscallDesc *desc, int num, 2455513SMichael.Adler@intel.com Process *p, ThreadContext *tc); 2465513SMichael.Adler@intel.com 2475513SMichael.Adler@intel.com 248511SN/A/// Target ftruncate() handler. 2491706SN/ASyscallReturn ftruncateFunc(SyscallDesc *desc, int num, 2503114Sgblack@eecs.umich.edu Process *p, ThreadContext *tc); 251511SN/A 2525513SMichael.Adler@intel.com 2535513SMichael.Adler@intel.com/// Target truncate64() handler. 2545513SMichael.Adler@intel.comSyscallReturn truncate64Func(SyscallDesc *desc, int num, 2555513SMichael.Adler@intel.com Process *p, ThreadContext *tc); 256511SN/A 2571706SN/A/// Target ftruncate64() handler. 2583114Sgblack@eecs.umich.eduSyscallReturn ftruncate64Func(SyscallDesc *desc, int num, 2591706SN/A Process *p, ThreadContext *tc); 2601706SN/A 2611706SN/A 2621706SN/A/// Target umask() handler. 2633114Sgblack@eecs.umich.eduSyscallReturn umaskFunc(SyscallDesc *desc, int num, 2641706SN/A Process *p, ThreadContext *tc); 2651706SN/A 2661706SN/A/// Target gettid() handler. 2671706SN/ASyscallReturn gettidFunc(SyscallDesc *desc, int num, 2683114Sgblack@eecs.umich.edu Process *p, ThreadContext *tc); 2691706SN/A 270511SN/A/// Target chown() handler. 2716703Svince@csl.cornell.eduSyscallReturn chownFunc(SyscallDesc *desc, int num, 2726703Svince@csl.cornell.edu Process *p, ThreadContext *tc); 2736703Svince@csl.cornell.edu 2746703Svince@csl.cornell.edu/// Target setpgid() handler. 2756685Stjones1@inf.ed.ac.ukSyscallReturn setpgidFunc(SyscallDesc *desc, int num, 2766685Stjones1@inf.ed.ac.uk Process *p, ThreadContext *tc); 2776685Stjones1@inf.ed.ac.uk 2786685Stjones1@inf.ed.ac.uk/// Target fchown() handler. 2796685Stjones1@inf.ed.ac.ukSyscallReturn fchownFunc(SyscallDesc *desc, int num, 2805513SMichael.Adler@intel.com Process *p, ThreadContext *tc); 2815513SMichael.Adler@intel.com 2825513SMichael.Adler@intel.com/// Target dup() handler. 2835513SMichael.Adler@intel.comSyscallReturn dupFunc(SyscallDesc *desc, int num, 2845513SMichael.Adler@intel.com Process *process, ThreadContext *tc); 2851999SN/A 2861999SN/A/// Target dup2() handler. 2873114Sgblack@eecs.umich.eduSyscallReturn dup2Func(SyscallDesc *desc, int num, 2881999SN/A Process *process, ThreadContext *tc); 2891999SN/A 2901999SN/A/// Target fcntl() handler. 2911999SN/ASyscallReturn fcntlFunc(SyscallDesc *desc, int num, 2923114Sgblack@eecs.umich.edu Process *process, ThreadContext *tc); 2931999SN/A 2943079Sstever@eecs.umich.edu/// Target fcntl64() handler. 2953079Sstever@eecs.umich.eduSyscallReturn fcntl64Func(SyscallDesc *desc, int num, 2963114Sgblack@eecs.umich.edu Process *process, ThreadContext *tc); 2973079Sstever@eecs.umich.edu 2982093SN/A/// Target setuid() handler. 2992093SN/ASyscallReturn setuidFunc(SyscallDesc *desc, int num, 3003114Sgblack@eecs.umich.edu Process *p, ThreadContext *tc); 3012093SN/A 3022687Sksewell@umich.edu/// Target pipe() handler. 3032687Sksewell@umich.eduSyscallReturn pipeFunc(SyscallDesc *desc, int num, 3043114Sgblack@eecs.umich.edu Process *p, ThreadContext *tc); 3052687Sksewell@umich.edu 3062238SN/A/// Internal pipe() handler. 3072238SN/ASyscallReturn pipeImpl(SyscallDesc *desc, int num, Process *p, 3083114Sgblack@eecs.umich.edu ThreadContext *tc, bool pseudoPipe); 3092238SN/A 3102238SN/A/// Target getpid() handler. 3112238SN/ASyscallReturn getpidFunc(SyscallDesc *desc, int num, 3123114Sgblack@eecs.umich.edu Process *p, ThreadContext *tc); 3132238SN/A 3142238SN/A// Target getpeername() handler. 3152238SN/ASyscallReturn getpeernameFunc(SyscallDesc *desc, int num, 3163114Sgblack@eecs.umich.edu Process *p, ThreadContext *tc); 3172238SN/A 3182238SN/A// Target bind() handler. 3192238SN/ASyscallReturn bindFunc(SyscallDesc *desc, int num, 3203114Sgblack@eecs.umich.edu Process *p, ThreadContext *tc); 3212238SN/A 3222238SN/A// Target listen() handler. 3232238SN/ASyscallReturn listenFunc(SyscallDesc *desc, int num, 3243114Sgblack@eecs.umich.edu Process *p, ThreadContext *tc); 3252238SN/A 3262238SN/A// Target connect() handler. 3272238SN/ASyscallReturn connectFunc(SyscallDesc *desc, int num, 3283114Sgblack@eecs.umich.edu Process *p, ThreadContext *tc); 3292238SN/A 3302238SN/A#if defined(SYS_getdents) 3312238SN/A// Target getdents() handler. 3323114Sgblack@eecs.umich.eduSyscallReturn getdentsFunc(SyscallDesc *desc, int num, 3332238SN/A Process *p, ThreadContext *tc); 3346109Ssanchezd@stanford.edu#endif 3356109Ssanchezd@stanford.edu 3366109Ssanchezd@stanford.edu#if defined(SYS_getdents64) 3372238SN/A// Target getdents() handler. 3389112Smarc.orr@gmail.comSyscallReturn getdents64Func(SyscallDesc *desc, int num, 3399112Smarc.orr@gmail.com Process *p, ThreadContext *tc); 3409112Smarc.orr@gmail.com#endif 3419112Smarc.orr@gmail.com 3429112Smarc.orr@gmail.com// Target sendto() handler. 3439112Smarc.orr@gmail.comSyscallReturn sendtoFunc(SyscallDesc *desc, int num, 3449112Smarc.orr@gmail.com Process *p, ThreadContext *tc); 3459112Smarc.orr@gmail.com 3469112Smarc.orr@gmail.com// Target recvfrom() handler. 3479112Smarc.orr@gmail.comSyscallReturn recvfromFunc(SyscallDesc *desc, int num, 3489112Smarc.orr@gmail.com Process *p, ThreadContext *tc); 3499112Smarc.orr@gmail.com 3509112Smarc.orr@gmail.com// Target recvmsg() handler. 3519112Smarc.orr@gmail.comSyscallReturn recvmsgFunc(SyscallDesc *desc, int num, 3529112Smarc.orr@gmail.com Process *p, ThreadContext *tc); 3539112Smarc.orr@gmail.com 3549112Smarc.orr@gmail.com// Target sendmsg() handler. 3559112Smarc.orr@gmail.comSyscallReturn sendmsgFunc(SyscallDesc *desc, int num, 3569112Smarc.orr@gmail.com Process *p, ThreadContext *tc); 3579112Smarc.orr@gmail.com 3589112Smarc.orr@gmail.com// Target getuid() handler. 3599112Smarc.orr@gmail.comSyscallReturn getuidFunc(SyscallDesc *desc, int num, 3609112Smarc.orr@gmail.com Process *p, ThreadContext *tc); 3619112Smarc.orr@gmail.com 3629112Smarc.orr@gmail.com/// Target getgid() handler. 3639112Smarc.orr@gmail.comSyscallReturn getgidFunc(SyscallDesc *desc, int num, 3649112Smarc.orr@gmail.com Process *p, ThreadContext *tc); 3659112Smarc.orr@gmail.com 3669112Smarc.orr@gmail.com/// Target getppid() handler. 3679112Smarc.orr@gmail.comSyscallReturn getppidFunc(SyscallDesc *desc, int num, 3689112Smarc.orr@gmail.com Process *p, ThreadContext *tc); 3699112Smarc.orr@gmail.com 3709112Smarc.orr@gmail.com/// Target geteuid() handler. 3719112Smarc.orr@gmail.comSyscallReturn geteuidFunc(SyscallDesc *desc, int num, 3729112Smarc.orr@gmail.com Process *p, ThreadContext *tc); 3739112Smarc.orr@gmail.com 3749112Smarc.orr@gmail.com/// Target getegid() handler. 3759112Smarc.orr@gmail.comSyscallReturn getegidFunc(SyscallDesc *desc, int num, 3769112Smarc.orr@gmail.com Process *p, ThreadContext *tc); 3779112Smarc.orr@gmail.com 3789112Smarc.orr@gmail.com/// Target access() handler 3799112Smarc.orr@gmail.comSyscallReturn accessFunc(SyscallDesc *desc, int num, 3809112Smarc.orr@gmail.com Process *p, ThreadContext *tc); 3819112Smarc.orr@gmail.comSyscallReturn accessFunc(SyscallDesc *desc, int num, 3829112Smarc.orr@gmail.com Process *p, ThreadContext *tc, 3839112Smarc.orr@gmail.com int index); 3849112Smarc.orr@gmail.com 3859112Smarc.orr@gmail.com// Target getsockopt() handler. 3869112Smarc.orr@gmail.comSyscallReturn getsockoptFunc(SyscallDesc *desc, int num, 3879112Smarc.orr@gmail.com Process *p, ThreadContext *tc); 3889112Smarc.orr@gmail.com 3899112Smarc.orr@gmail.com// Target setsockopt() handler. 3909112Smarc.orr@gmail.comSyscallReturn setsockoptFunc(SyscallDesc *desc, int num, 3919112Smarc.orr@gmail.com Process *p, ThreadContext *tc); 3929112Smarc.orr@gmail.com 3939112Smarc.orr@gmail.com// Target getsockname() handler. 3949112Smarc.orr@gmail.comSyscallReturn getsocknameFunc(SyscallDesc *desc, int num, 3959112Smarc.orr@gmail.com Process *p, ThreadContext *tc); 3969112Smarc.orr@gmail.com 3979112Smarc.orr@gmail.com/// Futex system call 3989112Smarc.orr@gmail.com/// Implemented by Daniel Sanchez 3999112Smarc.orr@gmail.com/// Used by printf's in multi-threaded apps 4009112Smarc.orr@gmail.comtemplate <class OS> 4019112Smarc.orr@gmail.comSyscallReturn 4029112Smarc.orr@gmail.comfutexFunc(SyscallDesc *desc, int callnum, Process *process, 4039112Smarc.orr@gmail.com ThreadContext *tc) 4049112Smarc.orr@gmail.com{ 4059112Smarc.orr@gmail.com using namespace std; 4069112Smarc.orr@gmail.com 4079112Smarc.orr@gmail.com int index = 0; 4089112Smarc.orr@gmail.com Addr uaddr = process->getSyscallArg(tc, index); 4099112Smarc.orr@gmail.com int op = process->getSyscallArg(tc, index); 4109112Smarc.orr@gmail.com int val = process->getSyscallArg(tc, index); 4119112Smarc.orr@gmail.com int timeout M5_VAR_USED = process->getSyscallArg(tc, index); 4129112Smarc.orr@gmail.com Addr uaddr2 M5_VAR_USED = process->getSyscallArg(tc, index); 4139112Smarc.orr@gmail.com int val3 = process->getSyscallArg(tc, index); 4149112Smarc.orr@gmail.com 4159112Smarc.orr@gmail.com /* 4169112Smarc.orr@gmail.com * Unsupported option that does not affect the correctness of the 4179112Smarc.orr@gmail.com * application. This is a performance optimization utilized by Linux. 4189112Smarc.orr@gmail.com */ 4192238SN/A op &= ~OS::TGT_FUTEX_PRIVATE_FLAG; 4202238SN/A op &= ~OS::TGT_FUTEX_CLOCK_REALTIME_FLAG; 4212238SN/A 4222238SN/A FutexMap &futex_map = tc->getSystemPtr()->futexMap; 4233114Sgblack@eecs.umich.edu 4242238SN/A if (OS::TGT_FUTEX_WAIT == op || OS::TGT_FUTEX_WAIT_BITSET == op) { 4252238SN/A // Ensure futex system call accessed atomically. 4262238SN/A BufferArg buf(uaddr, sizeof(int)); 4273114Sgblack@eecs.umich.edu buf.copyIn(tc->getMemProxy()); 4282238SN/A int mem_val = *(int*)buf.bufferPtr(); 4292238SN/A 4302238SN/A /* 4313114Sgblack@eecs.umich.edu * The value in memory at uaddr is not equal with the expected val 4322238SN/A * (a different thread must have changed it before the system call was 4332238SN/A * invoked). In this case, we need to throw an error. 4342238SN/A */ 4353114Sgblack@eecs.umich.edu if (val != mem_val) 4362238SN/A return -OS::TGT_EWOULDBLOCK; 4372238SN/A 4381354SN/A if (OS::TGT_FUTEX_WAIT) { 4391354SN/A futex_map.suspend(uaddr, process->tgid(), tc); 4401354SN/A } else { 4411354SN/A futex_map.suspend_bitset(uaddr, process->tgid(), tc, val3); 4421354SN/A } 4431354SN/A 4441354SN/A return 0; 4451354SN/A } else if (OS::TGT_FUTEX_WAKE == op) { 4461354SN/A return futex_map.wakeup(uaddr, process->tgid(), val); 4471354SN/A } else if (OS::TGT_FUTEX_WAKE_BITSET == op) { 4481354SN/A return futex_map.wakeup_bitset(uaddr, process->tgid(), val3); 4491354SN/A } else if (OS::TGT_FUTEX_REQUEUE == op || 4501354SN/A OS::TGT_FUTEX_CMP_REQUEUE == op) { 4511354SN/A 4527823Ssteve.reinhardt@amd.com // Ensure futex system call accessed atomically. 4531354SN/A BufferArg buf(uaddr, sizeof(int)); 4541354SN/A buf.copyIn(tc->getMemProxy()); 4551354SN/A int mem_val = *(int*)buf.bufferPtr(); 4561354SN/A /* 457360SN/A * For CMP_REQUEUE, the whole operation is only started only if 458360SN/A * val3 is still the value of the futex pointed to by uaddr. 459360SN/A */ 460360SN/A if (OS::TGT_FUTEX_CMP_REQUEUE && val3 != mem_val) 461360SN/A return -OS::TGT_EWOULDBLOCK; 462360SN/A return futex_map.requeue(uaddr, process->tgid(), val, timeout, uaddr2); 463360SN/A } else if (OS::TGT_FUTEX_WAKE_OP == op) { 4643113Sgblack@eecs.umich.edu /* 4653113Sgblack@eecs.umich.edu * The FUTEX_WAKE_OP operation is equivalent to executing the 4663113Sgblack@eecs.umich.edu * following code atomically and totally ordered with respect to 4673113Sgblack@eecs.umich.edu * other futex operations on any of the two supplied futex words: 4683113Sgblack@eecs.umich.edu * 4693113Sgblack@eecs.umich.edu * int oldval = *(int *) addr2; 4703113Sgblack@eecs.umich.edu * *(int *) addr2 = oldval op oparg; 4713113Sgblack@eecs.umich.edu * futex(addr1, FUTEX_WAKE, val, 0, 0, 0); 4723113Sgblack@eecs.umich.edu * if (oldval cmp cmparg) 4733113Sgblack@eecs.umich.edu * futex(addr2, FUTEX_WAKE, val2, 0, 0, 0); 4743113Sgblack@eecs.umich.edu * 4753113Sgblack@eecs.umich.edu * (op, oparg, cmp, cmparg are encoded in val3) 4763113Sgblack@eecs.umich.edu * 4773113Sgblack@eecs.umich.edu * +---+---+-----------+-----------+ 4783113Sgblack@eecs.umich.edu * |op |cmp| oparg | cmparg | 4793113Sgblack@eecs.umich.edu * +---+---+-----------+-----------+ 4804189Sgblack@eecs.umich.edu * 4 4 12 12 <== # of bits 4814189Sgblack@eecs.umich.edu * 4823113Sgblack@eecs.umich.edu * reference: http://man7.org/linux/man-pages/man2/futex.2.html 4833113Sgblack@eecs.umich.edu * 4843113Sgblack@eecs.umich.edu */ 4853113Sgblack@eecs.umich.edu // get value from simulated-space 4868737Skoansin.tan@gmail.com BufferArg buf(uaddr2, sizeof(int)); 4873113Sgblack@eecs.umich.edu buf.copyIn(tc->getMemProxy()); 4888737Skoansin.tan@gmail.com int oldval = *(int*)buf.bufferPtr(); 4893277Sgblack@eecs.umich.edu int newval = oldval; 4905515SMichael.Adler@intel.com // extract op, oparg, cmp, cmparg from val3 4915515SMichael.Adler@intel.com int wake_cmparg = val3 & 0xfff; 4925515SMichael.Adler@intel.com int wake_oparg = (val3 & 0xfff000) >> 12; 4935515SMichael.Adler@intel.com int wake_cmp = (val3 & 0xf000000) >> 24; 4945515SMichael.Adler@intel.com int wake_op = (val3 & 0xf0000000) >> 28; 4958737Skoansin.tan@gmail.com if ((wake_op & OS::TGT_FUTEX_OP_ARG_SHIFT) >> 3 == 1) 4963277Sgblack@eecs.umich.edu wake_oparg = (1 << wake_oparg); 4978737Skoansin.tan@gmail.com wake_op &= ~OS::TGT_FUTEX_OP_ARG_SHIFT; 4983277Sgblack@eecs.umich.edu // perform operation on the value of the second futex 4998737Skoansin.tan@gmail.com if (wake_op == OS::TGT_FUTEX_OP_SET) 5003277Sgblack@eecs.umich.edu newval = wake_oparg; 5018737Skoansin.tan@gmail.com else if (wake_op == OS::TGT_FUTEX_OP_ADD) 5023113Sgblack@eecs.umich.edu newval += wake_oparg; 5033113Sgblack@eecs.umich.edu else if (wake_op == OS::TGT_FUTEX_OP_OR) 5043113Sgblack@eecs.umich.edu newval |= wake_oparg; 5053113Sgblack@eecs.umich.edu else if (wake_op == OS::TGT_FUTEX_OP_ANDN) 5068737Skoansin.tan@gmail.com newval &= ~wake_oparg; 5073113Sgblack@eecs.umich.edu else if (wake_op == OS::TGT_FUTEX_OP_XOR) 5088737Skoansin.tan@gmail.com newval ^= wake_oparg; 5093114Sgblack@eecs.umich.edu // copy updated value back to simulated-space 5108737Skoansin.tan@gmail.com *(int*)buf.bufferPtr() = newval; 5113114Sgblack@eecs.umich.edu buf.copyOut(tc->getMemProxy()); 5128737Skoansin.tan@gmail.com // perform the first wake-up 5133114Sgblack@eecs.umich.edu int woken1 = futex_map.wakeup(uaddr, process->tgid(), val); 5148737Skoansin.tan@gmail.com int woken2 = 0; 5154061Sgblack@eecs.umich.edu // calculate the condition of the second wake-up 5164061Sgblack@eecs.umich.edu bool is_wake2 = false; 5174061Sgblack@eecs.umich.edu if (wake_cmp == OS::TGT_FUTEX_OP_CMP_EQ) 5188737Skoansin.tan@gmail.com is_wake2 = oldval == wake_cmparg; 5193113Sgblack@eecs.umich.edu else if (wake_cmp == OS::TGT_FUTEX_OP_CMP_NE) 5208737Skoansin.tan@gmail.com is_wake2 = oldval != wake_cmparg; 5213113Sgblack@eecs.umich.edu else if (wake_cmp == OS::TGT_FUTEX_OP_CMP_LT) 5223113Sgblack@eecs.umich.edu is_wake2 = oldval < wake_cmparg; 5233113Sgblack@eecs.umich.edu else if (wake_cmp == OS::TGT_FUTEX_OP_CMP_LE) 5243113Sgblack@eecs.umich.edu is_wake2 = oldval <= wake_cmparg; 5253113Sgblack@eecs.umich.edu else if (wake_cmp == OS::TGT_FUTEX_OP_CMP_GT) 5263113Sgblack@eecs.umich.edu is_wake2 = oldval > wake_cmparg; 5273113Sgblack@eecs.umich.edu else if (wake_cmp == OS::TGT_FUTEX_OP_CMP_GE) 5283113Sgblack@eecs.umich.edu is_wake2 = oldval >= wake_cmparg; 5294189Sgblack@eecs.umich.edu // perform the second wake-up 5304189Sgblack@eecs.umich.edu if (is_wake2) 5313113Sgblack@eecs.umich.edu woken2 = futex_map.wakeup(uaddr2, process->tgid(), timeout); 5323113Sgblack@eecs.umich.edu 5333113Sgblack@eecs.umich.edu return woken1 + woken2; 5348737Skoansin.tan@gmail.com } 5353113Sgblack@eecs.umich.edu warn("futex: op %d not implemented; ignoring.", op); 5368737Skoansin.tan@gmail.com return -ENOSYS; 5373113Sgblack@eecs.umich.edu} 5388737Skoansin.tan@gmail.com 5393113Sgblack@eecs.umich.edu 5403113Sgblack@eecs.umich.edu/// Pseudo Funcs - These functions use a different return convension, 5413113Sgblack@eecs.umich.edu/// returning a second value in a register other than the normal return register 5423113Sgblack@eecs.umich.eduSyscallReturn pipePseudoFunc(SyscallDesc *desc, int num, 5433113Sgblack@eecs.umich.edu Process *process, ThreadContext *tc); 5443113Sgblack@eecs.umich.edu 5453113Sgblack@eecs.umich.edu/// Target getpidPseudo() handler. 5463113Sgblack@eecs.umich.eduSyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num, 5473113Sgblack@eecs.umich.edu Process *p, ThreadContext *tc); 5483113Sgblack@eecs.umich.edu 5498852Sandreas.hansson@arm.com/// Target getuidPseudo() handler. 5503113Sgblack@eecs.umich.eduSyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num, 5513113Sgblack@eecs.umich.edu Process *p, ThreadContext *tc); 5523113Sgblack@eecs.umich.edu 5533113Sgblack@eecs.umich.edu/// Target getgidPseudo() handler. 5543113Sgblack@eecs.umich.eduSyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num, 5553113Sgblack@eecs.umich.edu Process *p, ThreadContext *tc); 5563113Sgblack@eecs.umich.edu 5573113Sgblack@eecs.umich.edu 5583113Sgblack@eecs.umich.edu/// A readable name for 1,000,000, for converting microseconds to seconds. 5593113Sgblack@eecs.umich.educonst int one_million = 1000000; 5608852Sandreas.hansson@arm.com/// A readable name for 1,000,000,000, for converting nanoseconds to seconds. 5613113Sgblack@eecs.umich.educonst int one_billion = 1000000000; 5623113Sgblack@eecs.umich.edu 5633113Sgblack@eecs.umich.edu/// Approximate seconds since the epoch (1/1/1970). About a billion, 5643113Sgblack@eecs.umich.edu/// by my reckoning. We want to keep this a constant (not use the 5656686Stjones1@inf.ed.ac.uk/// real-world time) to keep simulations repeatable. 5663113Sgblack@eecs.umich.educonst unsigned seconds_since_epoch = 1000000000; 5673113Sgblack@eecs.umich.edu 5683113Sgblack@eecs.umich.edu/// Helper function to convert current elapsed time to seconds and 569378SN/A/// microseconds. 570378SN/Atemplate <class T1, class T2> 5719141Smarc.orr@gmail.comvoid 5729141Smarc.orr@gmail.comgetElapsedTimeMicro(T1 &sec, T2 &usec) 573360SN/A{ 5741450SN/A uint64_t elapsed_usecs = curTick() / SimClock::Int::us; 5753114Sgblack@eecs.umich.edu sec = elapsed_usecs / one_million; 5762680Sktlim@umich.edu usec = elapsed_usecs % one_million; 577360SN/A} 5786701Sgblack@eecs.umich.edu 5796701Sgblack@eecs.umich.edu/// Helper function to convert current elapsed time to seconds and 5806701Sgblack@eecs.umich.edu/// nanoseconds. 581360SN/Atemplate <class T1, class T2> 5821969SN/Avoid 583360SN/AgetElapsedTimeNano(T1 &sec, T2 &nsec) 584360SN/A{ 585360SN/A uint64_t elapsed_nsecs = curTick() / SimClock::Int::ns; 5861458SN/A sec = elapsed_nsecs / one_billion; 587360SN/A nsec = elapsed_nsecs % one_billion; 588360SN/A} 5899141Smarc.orr@gmail.com 5901458SN/A////////////////////////////////////////////////////////////////////// 5919141Smarc.orr@gmail.com// 592360SN/A// The following emulation functions are generic, but need to be 5939141Smarc.orr@gmail.com// templated to account for differences in types, constants, etc. 5949141Smarc.orr@gmail.com// 5959141Smarc.orr@gmail.com////////////////////////////////////////////////////////////////////// 596360SN/A 597360SN/A typedef struct statfs hst_statfs; 598378SN/A#if NO_STAT64 599360SN/A typedef struct stat hst_stat; 6001450SN/A typedef struct stat hst_stat64; 6013114Sgblack@eecs.umich.edu#else 6022680Sktlim@umich.edu typedef struct stat hst_stat; 603360SN/A typedef struct stat64 hst_stat64; 604360SN/A#endif 605360SN/A 6066701Sgblack@eecs.umich.edu//// Helper function to convert a host stat buffer to a target stat 6078852Sandreas.hansson@arm.com//// buffer. Also copies the target buffer out to the simulated 6086701Sgblack@eecs.umich.edu//// memory space. Used by stat(), fstat(), and lstat(). 6091458SN/A 610360SN/Atemplate <typename target_stat, typename host_stat> 611360SN/Avoid 612360SN/AconvertStatBuf(target_stat &tgt, host_stat *host, bool fakeTTY = false) 613360SN/A{ 6141706SN/A using namespace TheISA; 6151458SN/A 616360SN/A if (fakeTTY) 617360SN/A tgt->st_dev = 0xA; 6186701Sgblack@eecs.umich.edu else 6196701Sgblack@eecs.umich.edu tgt->st_dev = host->st_dev; 620360SN/A tgt->st_dev = TheISA::htog(tgt->st_dev); 621360SN/A tgt->st_ino = host->st_ino; 622360SN/A tgt->st_ino = TheISA::htog(tgt->st_ino); 623360SN/A tgt->st_mode = host->st_mode; 624360SN/A if (fakeTTY) { 625360SN/A // Claim to be a character device 626360SN/A tgt->st_mode &= ~S_IFMT; // Clear S_IFMT 627360SN/A tgt->st_mode |= S_IFCHR; // Set S_IFCHR 628360SN/A } 629360SN/A tgt->st_mode = TheISA::htog(tgt->st_mode); 630360SN/A tgt->st_nlink = host->st_nlink; 631360SN/A tgt->st_nlink = TheISA::htog(tgt->st_nlink); 6321706SN/A tgt->st_uid = host->st_uid; 633360SN/A tgt->st_uid = TheISA::htog(tgt->st_uid); 634360SN/A tgt->st_gid = host->st_gid; 635360SN/A tgt->st_gid = TheISA::htog(tgt->st_gid); 636360SN/A if (fakeTTY) 637360SN/A tgt->st_rdev = 0x880d; 6383669Sbinkertn@umich.edu else 6393669Sbinkertn@umich.edu tgt->st_rdev = host->st_rdev; 6403669Sbinkertn@umich.edu tgt->st_rdev = TheISA::htog(tgt->st_rdev); 6411706SN/A tgt->st_size = host->st_size; 6421706SN/A tgt->st_size = TheISA::htog(tgt->st_size); 6435795Ssaidi@eecs.umich.edu tgt->st_atimeX = host->st_atime; 6449143Ssteve.reinhardt@amd.com tgt->st_atimeX = TheISA::htog(tgt->st_atimeX); 6459142Ssteve.reinhardt@amd.com tgt->st_mtimeX = host->st_mtime; 6469142Ssteve.reinhardt@amd.com tgt->st_mtimeX = TheISA::htog(tgt->st_mtimeX); 6479143Ssteve.reinhardt@amd.com tgt->st_ctimeX = host->st_ctime; 6485795Ssaidi@eecs.umich.edu tgt->st_ctimeX = TheISA::htog(tgt->st_ctimeX); 6499143Ssteve.reinhardt@amd.com // Force the block size to be 8KB. This helps to ensure buffered io works 6505795Ssaidi@eecs.umich.edu // consistently across different hosts. 6515795Ssaidi@eecs.umich.edu tgt->st_blksize = 0x2000; 6525795Ssaidi@eecs.umich.edu tgt->st_blksize = TheISA::htog(tgt->st_blksize); 6539143Ssteve.reinhardt@amd.com tgt->st_blocks = host->st_blocks; 6545795Ssaidi@eecs.umich.edu tgt->st_blocks = TheISA::htog(tgt->st_blocks); 655360SN/A} 6569143Ssteve.reinhardt@amd.com 6579143Ssteve.reinhardt@amd.com// Same for stat64 6589143Ssteve.reinhardt@amd.com 6599143Ssteve.reinhardt@amd.comtemplate <typename target_stat, typename host_stat64> 660360SN/Avoid 661360SN/AconvertStat64Buf(target_stat &tgt, host_stat64 *host, bool fakeTTY = false) 6626640Svince@csl.cornell.edu{ 6636640Svince@csl.cornell.edu using namespace TheISA; 6646640Svince@csl.cornell.edu 6656640Svince@csl.cornell.edu convertStatBuf<target_stat, host_stat64>(tgt, host, fakeTTY); 6666640Svince@csl.cornell.edu#if defined(STAT_HAVE_NSEC) 6676640Svince@csl.cornell.edu tgt->st_atime_nsec = host->st_atime_nsec; 6686640Svince@csl.cornell.edu tgt->st_atime_nsec = TheISA::htog(tgt->st_atime_nsec); 6696701Sgblack@eecs.umich.edu tgt->st_mtime_nsec = host->st_mtime_nsec; 6706701Sgblack@eecs.umich.edu tgt->st_mtime_nsec = TheISA::htog(tgt->st_mtime_nsec); 6716701Sgblack@eecs.umich.edu tgt->st_ctime_nsec = host->st_ctime_nsec; 6726640Svince@csl.cornell.edu tgt->st_ctime_nsec = TheISA::htog(tgt->st_ctime_nsec); 6736701Sgblack@eecs.umich.edu#else 6746701Sgblack@eecs.umich.edu tgt->st_atime_nsec = 0; 6756640Svince@csl.cornell.edu tgt->st_mtime_nsec = 0; 6768706Sandreas.hansson@arm.com tgt->st_ctime_nsec = 0; 6776640Svince@csl.cornell.edu#endif 6786701Sgblack@eecs.umich.edu} 6796640Svince@csl.cornell.edu 680360SN/A// Here are a couple of convenience functions 6811999SN/Atemplate<class OS> 6821999SN/Avoid 6831999SN/AcopyOutStatBuf(SETranslatingPortProxy &mem, Addr addr, 6843114Sgblack@eecs.umich.edu hst_stat *host, bool fakeTTY = false) 6852680Sktlim@umich.edu{ 6861999SN/A typedef TypedBufferArg<typename OS::tgt_stat> tgt_stat_buf; 6871999SN/A tgt_stat_buf tgt(addr); 6881999SN/A convertStatBuf<tgt_stat_buf, hst_stat>(tgt, host, fakeTTY); 6896701Sgblack@eecs.umich.edu tgt.copyOut(mem); 6908852Sandreas.hansson@arm.com} 6916701Sgblack@eecs.umich.edu 6921999SN/Atemplate<class OS> 6936701Sgblack@eecs.umich.eduvoid 6941999SN/AcopyOutStat64Buf(SETranslatingPortProxy &mem, Addr addr, 6956701Sgblack@eecs.umich.edu hst_stat64 *host, bool fakeTTY = false) 6961999SN/A{ 6971999SN/A typedef TypedBufferArg<typename OS::tgt_stat64> tgt_stat_buf; 6981999SN/A tgt_stat_buf tgt(addr); 6991999SN/A convertStat64Buf<tgt_stat_buf, hst_stat64>(tgt, host, fakeTTY); 7001999SN/A tgt.copyOut(mem); 7013669Sbinkertn@umich.edu} 7023669Sbinkertn@umich.edu 7033669Sbinkertn@umich.edutemplate <class OS> 7041999SN/Avoid 7051999SN/AcopyOutStatfsBuf(SETranslatingPortProxy &mem, Addr addr, 7061999SN/A hst_statfs *host) 7072218SN/A{ 7081999SN/A TypedBufferArg<typename OS::tgt_statfs> tgt(addr); 7091999SN/A 7101999SN/A tgt->f_type = TheISA::htog(host->f_type); 7111999SN/A#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) 7121999SN/A tgt->f_bsize = TheISA::htog(host->f_iosize); 7131999SN/A#else 7141999SN/A tgt->f_bsize = TheISA::htog(host->f_bsize); 7151999SN/A#endif 7163114Sgblack@eecs.umich.edu tgt->f_blocks = TheISA::htog(host->f_blocks); 7172680Sktlim@umich.edu tgt->f_bfree = TheISA::htog(host->f_bfree); 7181999SN/A tgt->f_bavail = TheISA::htog(host->f_bavail); 7196701Sgblack@eecs.umich.edu tgt->f_files = TheISA::htog(host->f_files); 7206701Sgblack@eecs.umich.edu tgt->f_ffree = TheISA::htog(host->f_ffree); 7211999SN/A memcpy(&tgt->f_fsid, &host->f_fsid, sizeof(host->f_fsid)); 7221999SN/A#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) 7231999SN/A tgt->f_namelen = TheISA::htog(host->f_namemax); 7241999SN/A tgt->f_frsize = TheISA::htog(host->f_bsize); 7251999SN/A#elif defined(__APPLE__) 7266701Sgblack@eecs.umich.edu tgt->f_namelen = 0; 7271999SN/A tgt->f_frsize = 0; 7281999SN/A#else 7291999SN/A tgt->f_namelen = TheISA::htog(host->f_namelen); 7301999SN/A tgt->f_frsize = TheISA::htog(host->f_frsize); 7311999SN/A#endif 7321999SN/A#if defined(__linux__) 7331999SN/A memcpy(&tgt->f_spare, &host->f_spare, sizeof(host->f_spare)); 7341999SN/A#else 7352218SN/A /* 7361999SN/A * The fields are different sizes per OS. Don't bother with 7371999SN/A * f_spare or f_reserved on non-Linux for now. 7381999SN/A */ 7391999SN/A memset(&tgt->f_spare, 0, sizeof(tgt->f_spare)); 7405877Shsul@eecs.umich.edu#endif 7415877Shsul@eecs.umich.edu 7425877Shsul@eecs.umich.edu tgt.copyOut(mem); 7435877Shsul@eecs.umich.edu} 7445877Shsul@eecs.umich.edu 7456701Sgblack@eecs.umich.edu/// Target ioctl() handler. For the most part, programs call ioctl() 7466701Sgblack@eecs.umich.edu/// only to find out if their stdout is a tty, to determine whether to 7476701Sgblack@eecs.umich.edu/// do line or block buffering. We always claim that output fds are 7486701Sgblack@eecs.umich.edu/// not TTYs to provide repeatable results. 7496701Sgblack@eecs.umich.edutemplate <class OS> 7505877Shsul@eecs.umich.eduSyscallReturn 7515877Shsul@eecs.umich.eduioctlFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 7525877Shsul@eecs.umich.edu{ 7535877Shsul@eecs.umich.edu int index = 0; 7545877Shsul@eecs.umich.edu int tgt_fd = p->getSyscallArg(tc, index); 7555877Shsul@eecs.umich.edu unsigned req = p->getSyscallArg(tc, index); 7565877Shsul@eecs.umich.edu 7575877Shsul@eecs.umich.edu DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", tgt_fd, req); 7585877Shsul@eecs.umich.edu 7595877Shsul@eecs.umich.edu if (OS::isTtyReq(req)) 7608601Ssteve.reinhardt@amd.com return -ENOTTY; 7615877Shsul@eecs.umich.edu 7625877Shsul@eecs.umich.edu auto dfdp = std::dynamic_pointer_cast<DeviceFDEntry>((*p->fds)[tgt_fd]); 7635877Shsul@eecs.umich.edu if (dfdp) { 7645877Shsul@eecs.umich.edu EmulatedDriver *emul_driver = dfdp->getDriver(); 7655877Shsul@eecs.umich.edu if (emul_driver) 7665877Shsul@eecs.umich.edu return emul_driver->ioctl(p, tc, req); 7675877Shsul@eecs.umich.edu } 7685877Shsul@eecs.umich.edu 7695877Shsul@eecs.umich.edu auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 7705877Shsul@eecs.umich.edu if (sfdp) { 7715877Shsul@eecs.umich.edu int status; 7725877Shsul@eecs.umich.edu 7735877Shsul@eecs.umich.edu switch (req) { 7748601Ssteve.reinhardt@amd.com case SIOCGIFCONF: { 7758601Ssteve.reinhardt@amd.com Addr conf_addr = p->getSyscallArg(tc, index); 7765877Shsul@eecs.umich.edu BufferArg conf_arg(conf_addr, sizeof(ifconf)); 7775877Shsul@eecs.umich.edu conf_arg.copyIn(tc->getMemProxy()); 7785877Shsul@eecs.umich.edu 7795877Shsul@eecs.umich.edu ifconf *conf = (ifconf*)conf_arg.bufferPtr(); 7805877Shsul@eecs.umich.edu Addr ifc_buf_addr = (Addr)conf->ifc_buf; 7815877Shsul@eecs.umich.edu BufferArg ifc_buf_arg(ifc_buf_addr, conf->ifc_len); 7828601Ssteve.reinhardt@amd.com ifc_buf_arg.copyIn(tc->getMemProxy()); 7835877Shsul@eecs.umich.edu 7845877Shsul@eecs.umich.edu conf->ifc_buf = (char*)ifc_buf_arg.bufferPtr(); 7855877Shsul@eecs.umich.edu 7861999SN/A status = ioctl(sfdp->getSimFD(), req, conf_arg.bufferPtr()); 787378SN/A if (status != -1) { 788360SN/A conf->ifc_buf = (char*)ifc_buf_addr; 7891450SN/A ifc_buf_arg.copyOut(tc->getMemProxy()); 7903114Sgblack@eecs.umich.edu conf_arg.copyOut(tc->getMemProxy()); 7912680Sktlim@umich.edu } 792360SN/A 793360SN/A return status; 794360SN/A } 7956701Sgblack@eecs.umich.edu case SIOCGIFFLAGS: 7968852Sandreas.hansson@arm.com#ifdef __linux__ 7976701Sgblack@eecs.umich.edu case SIOCGIFINDEX: 7986701Sgblack@eecs.umich.edu#endif 7996701Sgblack@eecs.umich.edu case SIOCGIFNETMASK: 8006701Sgblack@eecs.umich.edu case SIOCGIFADDR: 801360SN/A#ifdef __linux__ 8023669Sbinkertn@umich.edu case SIOCGIFHWADDR: 8033669Sbinkertn@umich.edu#endif 8043669Sbinkertn@umich.edu case SIOCGIFMTU: { 805360SN/A Addr req_addr = p->getSyscallArg(tc, index); 806360SN/A BufferArg req_arg(req_addr, sizeof(ifreq)); 807360SN/A req_arg.copyIn(tc->getMemProxy()); 808360SN/A 8092218SN/A status = ioctl(sfdp->getSimFD(), req, req_arg.bufferPtr()); 810360SN/A if (status != -1) 8118706Sandreas.hansson@arm.com req_arg.copyOut(tc->getMemProxy()); 812360SN/A return status; 8131458SN/A } 814360SN/A } 815360SN/A } 816360SN/A 8175074Ssaidi@eecs.umich.edu /** 8185074Ssaidi@eecs.umich.edu * For lack of a better return code, return ENOTTY. Ideally, we should 8195074Ssaidi@eecs.umich.edu * return something better here, but at least we issue the warning. 8205074Ssaidi@eecs.umich.edu */ 8215074Ssaidi@eecs.umich.edu warn("Unsupported ioctl call (return ENOTTY): ioctl(%d, 0x%x, ...) @ \n", 8225074Ssaidi@eecs.umich.edu tgt_fd, req, tc->pcState()); 8235074Ssaidi@eecs.umich.edu return -ENOTTY; 8245074Ssaidi@eecs.umich.edu} 8256701Sgblack@eecs.umich.edu 8268852Sandreas.hansson@arm.comtemplate <class OS> 8276701Sgblack@eecs.umich.eduSyscallReturn 8285074Ssaidi@eecs.umich.eduopenImpl(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc, 8296701Sgblack@eecs.umich.edu bool isopenat) 8305074Ssaidi@eecs.umich.edu{ 8315074Ssaidi@eecs.umich.edu int index = 0; 8325074Ssaidi@eecs.umich.edu int tgt_dirfd = -1; 8335074Ssaidi@eecs.umich.edu 8345208Ssaidi@eecs.umich.edu /** 8355208Ssaidi@eecs.umich.edu * If using the openat variant, read in the target directory file 8365208Ssaidi@eecs.umich.edu * descriptor from the simulated process. 8375208Ssaidi@eecs.umich.edu */ 8385074Ssaidi@eecs.umich.edu if (isopenat) 8395074Ssaidi@eecs.umich.edu tgt_dirfd = p->getSyscallArg(tc, index); 8405208Ssaidi@eecs.umich.edu 8415074Ssaidi@eecs.umich.edu /** 8425074Ssaidi@eecs.umich.edu * Retrieve the simulated process' memory proxy and then read in the path 8435074Ssaidi@eecs.umich.edu * string from that memory space into the host's working memory space. 8445074Ssaidi@eecs.umich.edu */ 8458706Sandreas.hansson@arm.com std::string path; 8465074Ssaidi@eecs.umich.edu if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 8475074Ssaidi@eecs.umich.edu return -EFAULT; 8485074Ssaidi@eecs.umich.edu 8495074Ssaidi@eecs.umich.edu#ifdef __CYGWIN32__ 8505074Ssaidi@eecs.umich.edu int host_flags = O_BINARY; 8511999SN/A#else 8521999SN/A int host_flags = 0; 8531999SN/A#endif 8543114Sgblack@eecs.umich.edu /** 8552680Sktlim@umich.edu * Translate target flags into host flags. Flags exist which are not 8561999SN/A * ported between architectures which can cause check failures. 8576701Sgblack@eecs.umich.edu */ 8586701Sgblack@eecs.umich.edu int tgt_flags = p->getSyscallArg(tc, index); 8596701Sgblack@eecs.umich.edu for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) { 8601999SN/A if (tgt_flags & OS::openFlagTable[i].tgtFlag) { 8611999SN/A tgt_flags &= ~OS::openFlagTable[i].tgtFlag; 8621999SN/A host_flags |= OS::openFlagTable[i].hostFlag; 8631999SN/A } 8641999SN/A } 8652764Sstever@eecs.umich.edu if (tgt_flags) { 8662064SN/A warn("open%s: cannot decode flags 0x%x", 8672064SN/A isopenat ? "at" : "", tgt_flags); 8682064SN/A } 8692064SN/A#ifdef __CYGWIN32__ 8701999SN/A host_flags |= O_BINARY; 8712064SN/A#endif 8721999SN/A 8731999SN/A int mode = p->getSyscallArg(tc, index); 8742218SN/A 8751999SN/A /** 8768706Sandreas.hansson@arm.com * If the simulated process called open or openat with AT_FDCWD specified, 8771999SN/A * take the current working directory value which was passed into the 8781999SN/A * process class as a Python parameter and append the current path to 8791999SN/A * create a full path. 8801999SN/A * Otherwise, openat with a valid target directory file descriptor has 8811999SN/A * been called. If the path option, which was passed in as a parameter, 882378SN/A * is not absolute, retrieve the directory file descriptor's path and 883360SN/A * prepend it to the path passed in as a parameter. 8841450SN/A * In every case, we should have a full path (which is relevant to the 8853114Sgblack@eecs.umich.edu * host) to work with after this block has been passed. 8862680Sktlim@umich.edu */ 887360SN/A std::string redir_path = path; 888360SN/A std::string abs_path = path; 889360SN/A if (!isopenat || tgt_dirfd == OS::TGT_AT_FDCWD) { 8906701Sgblack@eecs.umich.edu abs_path = p->absolutePath(path, true); 8918852Sandreas.hansson@arm.com redir_path = p->checkPathRedirect(path); 8926701Sgblack@eecs.umich.edu } else if (!startswith(path, "/")) { 8936701Sgblack@eecs.umich.edu std::shared_ptr<FDEntry> fdep = ((*p->fds)[tgt_dirfd]); 8946701Sgblack@eecs.umich.edu auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep); 8956701Sgblack@eecs.umich.edu if (!ffdp) 896360SN/A return -EBADF; 8973669Sbinkertn@umich.edu abs_path = ffdp->getFileName() + path; 8983669Sbinkertn@umich.edu redir_path = p->checkPathRedirect(abs_path); 8993669Sbinkertn@umich.edu } 900360SN/A 901360SN/A /** 902360SN/A * Since this is an emulated environment, we create pseudo file 903360SN/A * descriptors for device requests that have been registered with 9041458SN/A * the process class through Python; this allows us to create a file 905360SN/A * descriptor for subsequent ioctl or mmap calls. 9068706Sandreas.hansson@arm.com */ 907360SN/A if (startswith(abs_path, "/dev/")) { 9081458SN/A std::string filename = abs_path.substr(strlen("/dev/")); 909360SN/A EmulatedDriver *drv = p->findDriver(filename); 910360SN/A if (drv) { 9111999SN/A DPRINTF_SYSCALL(Verbose, "open%s: passing call to " 9121999SN/A "driver open with path[%s]\n", 9131999SN/A isopenat ? "at" : "", abs_path.c_str()); 9143114Sgblack@eecs.umich.edu return drv->open(p, tc, mode, host_flags); 9152680Sktlim@umich.edu } 9161999SN/A /** 9171999SN/A * Fall through here for pass through to host devices, such 9181999SN/A * as /dev/zero 9196701Sgblack@eecs.umich.edu */ 9208852Sandreas.hansson@arm.com } 9216701Sgblack@eecs.umich.edu 9226701Sgblack@eecs.umich.edu /** 9236701Sgblack@eecs.umich.edu * We make several attempts resolve a call to open. 9246701Sgblack@eecs.umich.edu * 9251999SN/A * 1) Resolve any path redirection before hand. This will set the path 9263669Sbinkertn@umich.edu * up with variable 'redir_path' which may contain a modified path or 9273669Sbinkertn@umich.edu * the original path value. This should already be done in prior code. 9283669Sbinkertn@umich.edu * 2) Try to handle the access using 'special_paths'. Some special_paths 9292764Sstever@eecs.umich.edu * and files cannot be called on the host and need to be handled as 9302064SN/A * special cases inside the simulator. These special_paths are handled by 9312064SN/A * C++ routines to provide output back to userspace. 9322064SN/A * 3) If the full path that was created above does not match any of the 9331999SN/A * special cases, pass it through to the open call on the __HOST__ to let 9341999SN/A * the host open the file on our behalf. Again, the openImpl tries to 9352064SN/A * USE_THE_HOST_FILESYSTEM_OPEN (with a possible redirection to the 9361999SN/A * faux-filesystem files). The faux-filesystem is dynamically created 9371999SN/A * during simulator configuration using Python functions. 9381999SN/A * 4) If the host cannot open the file, the open attempt failed in "3)". 9391999SN/A * Return the host's error code back through the system call to the 9408706Sandreas.hansson@arm.com * simulated process. If running a debug trace, also notify the user that 9411999SN/A * the open call failed. 9421999SN/A * 9431999SN/A * Any success will set sim_fd to something other than -1 and skip the 9441999SN/A * next conditions effectively bypassing them. 945378SN/A */ 946360SN/A int sim_fd = -1; 9471450SN/A std::string used_path; 9483114Sgblack@eecs.umich.edu std::vector<std::string> special_paths = 9492680Sktlim@umich.edu { "/proc/meminfo/", "/system/", "/sys/", "/platform/", 950360SN/A "/etc/passwd" }; 9516701Sgblack@eecs.umich.edu for (auto entry : special_paths) { 9526701Sgblack@eecs.umich.edu if (startswith(path, entry)) { 9536701Sgblack@eecs.umich.edu sim_fd = OS::openSpecialFile(abs_path, p, tc); 954360SN/A used_path = abs_path; 9551969SN/A } 956360SN/A } 957360SN/A if (sim_fd == -1) { 9581458SN/A sim_fd = open(redir_path.c_str(), host_flags, mode); 959360SN/A used_path = redir_path; 960360SN/A } 961360SN/A if (sim_fd == -1) { 962360SN/A int local = -errno; 963360SN/A DPRINTF_SYSCALL(Verbose, "open%s: failed -> path:%s " 9641458SN/A "(inferred from:%s)\n", isopenat ? "at" : "", 965360SN/A used_path.c_str(), path.c_str()); 9668706Sandreas.hansson@arm.com return local; 9672021SN/A } 9681458SN/A 969360SN/A /** 970360SN/A * The file was opened successfully and needs to be recorded in the 971360SN/A * process' file descriptor array so that it can be retrieved later. 9721706SN/A * The target file descriptor that is chosen will be the lowest unused 9731706SN/A * file descriptor. 9741706SN/A * Return the indirect target file descriptor back to the simulated 9753114Sgblack@eecs.umich.edu * process to act as a handle for the opened file. 9762680Sktlim@umich.edu */ 9771706SN/A auto ffdp = std::make_shared<FileFDEntry>(sim_fd, host_flags, path, 0); 9781706SN/A int tgt_fd = p->fds->allocFD(ffdp); 9791706SN/A DPRINTF_SYSCALL(Verbose, "open%s: sim_fd[%d], target_fd[%d] -> path:%s\n" 9806701Sgblack@eecs.umich.edu "(inferred from:%s)\n", isopenat ? "at" : "", 9818852Sandreas.hansson@arm.com sim_fd, tgt_fd, used_path.c_str(), path.c_str()); 9826701Sgblack@eecs.umich.edu return tgt_fd; 9836701Sgblack@eecs.umich.edu} 9846701Sgblack@eecs.umich.edu 9856701Sgblack@eecs.umich.edu/// Target open() handler. 9861706SN/Atemplate <class OS> 9873669Sbinkertn@umich.eduSyscallReturn 9883669Sbinkertn@umich.eduopenFunc(SyscallDesc *desc, int callnum, Process *process, 9893669Sbinkertn@umich.edu ThreadContext *tc) 9901706SN/A{ 9911706SN/A return openImpl<OS>(desc, callnum, process, tc, false); 9921706SN/A} 9931706SN/A 9942218SN/A/// Target openat() handler. 9951706SN/Atemplate <class OS> 9968706Sandreas.hansson@arm.comSyscallReturn 9971706SN/AopenatFunc(SyscallDesc *desc, int callnum, Process *process, 9981706SN/A ThreadContext *tc) 9991706SN/A{ 10001706SN/A return openImpl<OS>(desc, callnum, process, tc, true); 10011706SN/A} 10021706SN/A 10031706SN/A/// Target unlinkat() handler. 10041706SN/Atemplate <class OS> 10053114Sgblack@eecs.umich.eduSyscallReturn 10062680Sktlim@umich.eduunlinkatFunc(SyscallDesc *desc, int callnum, Process *process, 10071706SN/A ThreadContext *tc) 10086701Sgblack@eecs.umich.edu{ 10096701Sgblack@eecs.umich.edu int index = 0; 10106701Sgblack@eecs.umich.edu int dirfd = process->getSyscallArg(tc, index); 10111706SN/A if (dirfd != OS::TGT_AT_FDCWD) 10121706SN/A warn("unlinkat: first argument not AT_FDCWD; unlikely to work"); 10131706SN/A 10141706SN/A return unlinkHelper(desc, callnum, process, tc, 1); 10151706SN/A} 10161706SN/A 10171706SN/A/// Target facessat() handler 10181706SN/Atemplate <class OS> 10192218SN/ASyscallReturn 10201706SN/AfaccessatFunc(SyscallDesc *desc, int callnum, Process *process, 10218706Sandreas.hansson@arm.com ThreadContext *tc) 10221706SN/A{ 10231706SN/A int index = 0; 10241706SN/A int dirfd = process->getSyscallArg(tc, index); 10251706SN/A if (dirfd != OS::TGT_AT_FDCWD) 10261706SN/A warn("faccessat: first argument not AT_FDCWD; unlikely to work"); 10271999SN/A return accessFunc(desc, callnum, process, tc, 1); 10281999SN/A} 10291999SN/A 10303114Sgblack@eecs.umich.edu/// Target readlinkat() handler 10312680Sktlim@umich.edutemplate <class OS> 10321999SN/ASyscallReturn 10336701Sgblack@eecs.umich.edureadlinkatFunc(SyscallDesc *desc, int callnum, Process *process, 10346701Sgblack@eecs.umich.edu ThreadContext *tc) 10351999SN/A{ 10361999SN/A int index = 0; 10371999SN/A int dirfd = process->getSyscallArg(tc, index); 10381999SN/A if (dirfd != OS::TGT_AT_FDCWD) 10391999SN/A warn("openat: first argument not AT_FDCWD; unlikely to work"); 10408852Sandreas.hansson@arm.com return readlinkFunc(desc, callnum, process, tc, 1); 10416701Sgblack@eecs.umich.edu} 10426701Sgblack@eecs.umich.edu 10431999SN/A/// Target renameat() handler. 10446227Snate@binkert.orgtemplate <class OS> 10451999SN/ASyscallReturn 10462461SN/ArenameatFunc(SyscallDesc *desc, int callnum, Process *process, 10478852Sandreas.hansson@arm.com ThreadContext *tc) 10488852Sandreas.hansson@arm.com{ 10498737Skoansin.tan@gmail.com int index = 0; 10501999SN/A 10518852Sandreas.hansson@arm.com int olddirfd = process->getSyscallArg(tc, index); 10528852Sandreas.hansson@arm.com if (olddirfd != OS::TGT_AT_FDCWD) 10531999SN/A warn("renameat: first argument not AT_FDCWD; unlikely to work"); 10541999SN/A 10551999SN/A std::string old_name; 10561999SN/A 10576227Snate@binkert.org if (!tc->getMemProxy().tryReadString(old_name, 10581999SN/A process->getSyscallArg(tc, index))) 10591999SN/A return -EFAULT; 10601999SN/A 10612218SN/A int newdirfd = process->getSyscallArg(tc, index); 10621999SN/A if (newdirfd != OS::TGT_AT_FDCWD) 10631999SN/A warn("renameat: third argument not AT_FDCWD; unlikely to work"); 10641999SN/A 10651999SN/A std::string new_name; 10661999SN/A 1067378SN/A if (!tc->getMemProxy().tryReadString(new_name, 1068378SN/A process->getSyscallArg(tc, index))) 1069378SN/A return -EFAULT; 1070378SN/A 1071378SN/A // Adjust path for cwd and redirection 10728324Ssteve.reinhardt@amd.com old_name = process->checkPathRedirect(old_name); 10738324Ssteve.reinhardt@amd.com new_name = process->checkPathRedirect(new_name); 1074360SN/A 10751450SN/A int result = rename(old_name.c_str(), new_name.c_str()); 10763114Sgblack@eecs.umich.edu return (result == -1) ? -errno : result; 1077360SN/A} 10786701Sgblack@eecs.umich.edu 10796701Sgblack@eecs.umich.edu/// Target sysinfo() handler. 10806701Sgblack@eecs.umich.edutemplate <class OS> 10816701Sgblack@eecs.umich.eduSyscallReturn 10826701Sgblack@eecs.umich.edusysinfoFunc(SyscallDesc *desc, int callnum, Process *process, 10838324Ssteve.reinhardt@amd.com ThreadContext *tc) 10846701Sgblack@eecs.umich.edu{ 1085360SN/A 10869008Sgblack@eecs.umich.edu int index = 0; 10879008Sgblack@eecs.umich.edu TypedBufferArg<typename OS::tgt_sysinfo> 10889008Sgblack@eecs.umich.edu sysinfo(process->getSyscallArg(tc, index)); 10898324Ssteve.reinhardt@amd.com 10908324Ssteve.reinhardt@amd.com sysinfo->uptime = seconds_since_epoch; 10918324Ssteve.reinhardt@amd.com sysinfo->totalram = process->system->memSize(); 10928324Ssteve.reinhardt@amd.com sysinfo->mem_unit = 1; 10938324Ssteve.reinhardt@amd.com 10948324Ssteve.reinhardt@amd.com sysinfo.copyOut(tc->getMemProxy()); 10958324Ssteve.reinhardt@amd.com 10968324Ssteve.reinhardt@amd.com return 0; 10978324Ssteve.reinhardt@amd.com} 10988324Ssteve.reinhardt@amd.com 10998324Ssteve.reinhardt@amd.com/// Target chmod() handler. 11008324Ssteve.reinhardt@amd.comtemplate <class OS> 11018324Ssteve.reinhardt@amd.comSyscallReturn 11028324Ssteve.reinhardt@amd.comchmodFunc(SyscallDesc *desc, int callnum, Process *process, 11038324Ssteve.reinhardt@amd.com ThreadContext *tc) 11045877Shsul@eecs.umich.edu{ 11052544SN/A std::string path; 11062544SN/A 11072544SN/A int index = 0; 11082544SN/A if (!tc->getMemProxy().tryReadString(path, 11092544SN/A process->getSyscallArg(tc, index))) { 11102544SN/A return -EFAULT; 1111360SN/A } 1112360SN/A 11138600Ssteve.reinhardt@amd.com uint32_t mode = process->getSyscallArg(tc, index); 11148600Ssteve.reinhardt@amd.com mode_t hostMode = 0; 11158600Ssteve.reinhardt@amd.com 11168600Ssteve.reinhardt@amd.com // XXX translate mode flags via OS::something??? 11178600Ssteve.reinhardt@amd.com hostMode = mode; 11188600Ssteve.reinhardt@amd.com 11198600Ssteve.reinhardt@amd.com // Adjust path for cwd and redirection 11208600Ssteve.reinhardt@amd.com path = process->checkPathRedirect(path); 11218600Ssteve.reinhardt@amd.com 11228600Ssteve.reinhardt@amd.com // do the chmod 11238600Ssteve.reinhardt@amd.com int result = chmod(path.c_str(), hostMode); 11248600Ssteve.reinhardt@amd.com if (result < 0) 11258600Ssteve.reinhardt@amd.com return -errno; 11268600Ssteve.reinhardt@amd.com 11278600Ssteve.reinhardt@amd.com return 0; 11288600Ssteve.reinhardt@amd.com} 11298600Ssteve.reinhardt@amd.com 11308600Ssteve.reinhardt@amd.comtemplate <class OS> 11318600Ssteve.reinhardt@amd.comSyscallReturn 11328600Ssteve.reinhardt@amd.compollFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 11338600Ssteve.reinhardt@amd.com{ 11348600Ssteve.reinhardt@amd.com int index = 0; 11358600Ssteve.reinhardt@amd.com Addr fdsPtr = p->getSyscallArg(tc, index); 11368600Ssteve.reinhardt@amd.com int nfds = p->getSyscallArg(tc, index); 11372544SN/A int tmout = p->getSyscallArg(tc, index); 11382544SN/A 11398600Ssteve.reinhardt@amd.com BufferArg fdsBuf(fdsPtr, sizeof(struct pollfd) * nfds); 11408600Ssteve.reinhardt@amd.com fdsBuf.copyIn(tc->getMemProxy()); 11418600Ssteve.reinhardt@amd.com 11428600Ssteve.reinhardt@amd.com /** 11438600Ssteve.reinhardt@amd.com * Record the target file descriptors in a local variable. We need to 11448600Ssteve.reinhardt@amd.com * replace them with host file descriptors but we need a temporary copy 11458600Ssteve.reinhardt@amd.com * for later. Afterwards, replace each target file descriptor in the 11468600Ssteve.reinhardt@amd.com * poll_fd array with its host_fd. 11478600Ssteve.reinhardt@amd.com */ 11488600Ssteve.reinhardt@amd.com int temp_tgt_fds[nfds]; 11496672Sgblack@eecs.umich.edu for (index = 0; index < nfds; index++) { 11508600Ssteve.reinhardt@amd.com temp_tgt_fds[index] = ((struct pollfd *)fdsBuf.bufferPtr())[index].fd; 11518601Ssteve.reinhardt@amd.com auto tgt_fd = temp_tgt_fds[index]; 11522544SN/A auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 11531458SN/A if (!hbfdp) 1154360SN/A return -EBADF; 1155360SN/A auto host_fd = hbfdp->getSimFD(); 1156378SN/A ((struct pollfd *)fdsBuf.bufferPtr())[index].fd = host_fd; 1157360SN/A } 11581450SN/A 11593114Sgblack@eecs.umich.edu /** 11602680Sktlim@umich.edu * We cannot allow an infinite poll to occur or it will inevitably cause 1161360SN/A * a deadlock in the gem5 simulator with clone. We must pass in tmout with 11626701Sgblack@eecs.umich.edu * a non-negative value, however it also makes no sense to poll on the 11636701Sgblack@eecs.umich.edu * underlying host for any other time than tmout a zero timeout. 11646701Sgblack@eecs.umich.edu */ 1165360SN/A int status; 1166360SN/A if (tmout < 0) { 11672064SN/A status = poll((struct pollfd *)fdsBuf.bufferPtr(), nfds, 0); 11685877Shsul@eecs.umich.edu if (status == 0) { 11692064SN/A /** 11708737Skoansin.tan@gmail.com * If blocking indefinitely, check the signal list to see if a 11718737Skoansin.tan@gmail.com * signal would break the poll out of the retry cycle and try 11722064SN/A * to return the signal interrupt instead. 1173360SN/A */ 11745877Shsul@eecs.umich.edu System *sysh = tc->getSystemPtr(); 11755877Shsul@eecs.umich.edu std::list<BasicSignal>::iterator it; 11765877Shsul@eecs.umich.edu for (it=sysh->signalList.begin(); it!=sysh->signalList.end(); it++) 11778737Skoansin.tan@gmail.com if (it->receiver == p) 11788737Skoansin.tan@gmail.com return -EINTR; 11795877Shsul@eecs.umich.edu return SyscallReturn::retry(); 11805877Shsul@eecs.umich.edu } 11812064SN/A } else 11822064SN/A status = poll((struct pollfd *)fdsBuf.bufferPtr(), nfds, 0); 11832064SN/A 11842064SN/A if (status == -1) 11852064SN/A return -errno; 1186360SN/A 1187360SN/A /** 11888706Sandreas.hansson@arm.com * Replace each host_fd in the returned poll_fd array with its original 11891458SN/A * target file descriptor. 1190360SN/A */ 1191360SN/A for (index = 0; index < nfds; index++) { 1192378SN/A auto tgt_fd = temp_tgt_fds[index]; 1193360SN/A ((struct pollfd *)fdsBuf.bufferPtr())[index].fd = tgt_fd; 11941450SN/A } 11953114Sgblack@eecs.umich.edu 11962680Sktlim@umich.edu /** 1197360SN/A * Copy out the pollfd struct because the host may have updated fields 11986701Sgblack@eecs.umich.edu * in the structure. 11996701Sgblack@eecs.umich.edu */ 1200360SN/A fdsBuf.copyOut(tc->getMemProxy()); 1201360SN/A 1202360SN/A return status; 12036109Ssanchezd@stanford.edu} 12046109Ssanchezd@stanford.edu 1205360SN/A/// Target fchmod() handler. 12068706Sandreas.hansson@arm.comtemplate <class OS> 1207360SN/ASyscallReturn 12081458SN/AfchmodFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1209360SN/A{ 1210360SN/A int index = 0; 1211360SN/A int tgt_fd = p->getSyscallArg(tc, index); 12121999SN/A uint32_t mode = p->getSyscallArg(tc, index); 12131999SN/A 12141999SN/A auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 12153114Sgblack@eecs.umich.edu if (!ffdp) 12162680Sktlim@umich.edu return -EBADF; 12171999SN/A int sim_fd = ffdp->getSimFD(); 12181999SN/A 12191999SN/A mode_t hostMode = mode; 12206701Sgblack@eecs.umich.edu 12218852Sandreas.hansson@arm.com int result = fchmod(sim_fd, hostMode); 12226701Sgblack@eecs.umich.edu 12236701Sgblack@eecs.umich.edu return (result < 0) ? -errno : 0; 12246701Sgblack@eecs.umich.edu} 12251999SN/A 12266701Sgblack@eecs.umich.edu/// Target mremap() handler. 12276701Sgblack@eecs.umich.edutemplate <class OS> 12288706Sandreas.hansson@arm.comSyscallReturn 12291999SN/AmremapFunc(SyscallDesc *desc, int callnum, Process *process, ThreadContext *tc) 12301999SN/A{ 12311999SN/A int index = 0; 12321999SN/A Addr start = process->getSyscallArg(tc, index); 12338737Skoansin.tan@gmail.com uint64_t old_length = process->getSyscallArg(tc, index); 12348737Skoansin.tan@gmail.com uint64_t new_length = process->getSyscallArg(tc, index); 12351999SN/A uint64_t flags = process->getSyscallArg(tc, index); 12363669Sbinkertn@umich.edu uint64_t provided_address = 0; 12373669Sbinkertn@umich.edu bool use_provided_address = flags & OS::TGT_MREMAP_FIXED; 12383669Sbinkertn@umich.edu 12393669Sbinkertn@umich.edu if (use_provided_address) 12401999SN/A provided_address = process->getSyscallArg(tc, index); 12411999SN/A 12421999SN/A if ((start % TheISA::PageBytes != 0) || 12431999SN/A (provided_address % TheISA::PageBytes != 0)) { 12441999SN/A warn("mremap failing: arguments not page aligned"); 12451999SN/A return -EINVAL; 12461999SN/A } 1247378SN/A 1248360SN/A new_length = roundUp(new_length, TheISA::PageBytes); 12491450SN/A 12503114Sgblack@eecs.umich.edu if (new_length > old_length) { 12512680Sktlim@umich.edu std::shared_ptr<MemState> mem_state = process->memState; 1252360SN/A Addr mmap_end = mem_state->getMmapEnd(); 12536701Sgblack@eecs.umich.edu 12546701Sgblack@eecs.umich.edu if ((start + old_length) == mmap_end && 12556701Sgblack@eecs.umich.edu (!use_provided_address || provided_address == start)) { 1256360SN/A // This case cannot occur when growing downward, as 12573670Sbinkertn@umich.edu // start is greater than or equal to mmap_end. 12583670Sbinkertn@umich.edu uint64_t diff = new_length - old_length; 1259360SN/A process->allocateMem(mmap_end, diff); 1260360SN/A mem_state->setMmapEnd(mmap_end + diff); 1261360SN/A return start; 1262360SN/A } else { 1263360SN/A if (!use_provided_address && !(flags & OS::TGT_MREMAP_MAYMOVE)) { 1264360SN/A warn("can't remap here and MREMAP_MAYMOVE flag not set\n"); 1265360SN/A return -ENOMEM; 1266360SN/A } else { 1267360SN/A uint64_t new_start = provided_address; 1268360SN/A if (!use_provided_address) { 1269360SN/A new_start = process->mmapGrowsDown() ? 1270360SN/A mmap_end - new_length : mmap_end; 1271360SN/A mmap_end = process->mmapGrowsDown() ? 1272360SN/A new_start : mmap_end + new_length; 1273360SN/A mem_state->setMmapEnd(mmap_end); 1274360SN/A } 1275360SN/A 12763670Sbinkertn@umich.edu process->pTable->remap(start, old_length, new_start); 12773670Sbinkertn@umich.edu warn("mremapping to new vaddr %08p-%08p, adding %d\n", 12783670Sbinkertn@umich.edu new_start, new_start + new_length, 12798737Skoansin.tan@gmail.com new_length - old_length); 12808737Skoansin.tan@gmail.com // add on the remaining unallocated pages 12813670Sbinkertn@umich.edu process->allocateMem(new_start + old_length, 12823670Sbinkertn@umich.edu new_length - old_length, 12833670Sbinkertn@umich.edu use_provided_address /* clobber */); 12843670Sbinkertn@umich.edu if (use_provided_address && 12853670Sbinkertn@umich.edu ((new_start + new_length > mem_state->getMmapEnd() && 12863670Sbinkertn@umich.edu !process->mmapGrowsDown()) || 12873670Sbinkertn@umich.edu (new_start < mem_state->getMmapEnd() && 12883670Sbinkertn@umich.edu process->mmapGrowsDown()))) { 12893670Sbinkertn@umich.edu // something fishy going on here, at least notify the user 12903670Sbinkertn@umich.edu // @todo: increase mmap_end? 12913670Sbinkertn@umich.edu warn("mmap region limit exceeded with MREMAP_FIXED\n"); 12923670Sbinkertn@umich.edu } 12933670Sbinkertn@umich.edu warn("returning %08p as start\n", new_start); 12948706Sandreas.hansson@arm.com return new_start; 1295360SN/A } 12961458SN/A } 1297360SN/A } else { 1298360SN/A if (use_provided_address && provided_address != start) 12996683Stjones1@inf.ed.ac.uk process->pTable->remap(start, new_length, provided_address); 13006683Stjones1@inf.ed.ac.uk process->pTable->unmap(start + new_length, old_length - new_length); 13016683Stjones1@inf.ed.ac.uk return use_provided_address ? provided_address : start; 13026683Stjones1@inf.ed.ac.uk } 13036683Stjones1@inf.ed.ac.uk} 13046683Stjones1@inf.ed.ac.uk 13056701Sgblack@eecs.umich.edu/// Target stat() handler. 13066701Sgblack@eecs.umich.edutemplate <class OS> 13076683Stjones1@inf.ed.ac.ukSyscallReturn 13086683Stjones1@inf.ed.ac.ukstatFunc(SyscallDesc *desc, int callnum, Process *process, 13097823Ssteve.reinhardt@amd.com ThreadContext *tc) 13106683Stjones1@inf.ed.ac.uk{ 13116683Stjones1@inf.ed.ac.uk std::string path; 13126683Stjones1@inf.ed.ac.uk 13136683Stjones1@inf.ed.ac.uk int index = 0; 13146683Stjones1@inf.ed.ac.uk if (!tc->getMemProxy().tryReadString(path, 13156683Stjones1@inf.ed.ac.uk process->getSyscallArg(tc, index))) { 13168737Skoansin.tan@gmail.com return -EFAULT; 13176683Stjones1@inf.ed.ac.uk } 13186683Stjones1@inf.ed.ac.uk Addr bufPtr = process->getSyscallArg(tc, index); 13198706Sandreas.hansson@arm.com 13206683Stjones1@inf.ed.ac.uk // Adjust path for cwd and redirection 13216683Stjones1@inf.ed.ac.uk path = process->checkPathRedirect(path); 13226683Stjones1@inf.ed.ac.uk 13236683Stjones1@inf.ed.ac.uk struct stat hostBuf; 13242553SN/A int result = stat(path.c_str(), &hostBuf); 13256684Stjones1@inf.ed.ac.uk 13266684Stjones1@inf.ed.ac.uk if (result < 0) 13276684Stjones1@inf.ed.ac.uk return -errno; 13286684Stjones1@inf.ed.ac.uk 13296684Stjones1@inf.ed.ac.uk copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 13306684Stjones1@inf.ed.ac.uk 13316684Stjones1@inf.ed.ac.uk return 0; 13326684Stjones1@inf.ed.ac.uk} 13336684Stjones1@inf.ed.ac.uk 13346684Stjones1@inf.ed.ac.uk 13356701Sgblack@eecs.umich.edu/// Target stat64() handler. 13366701Sgblack@eecs.umich.edutemplate <class OS> 13376684Stjones1@inf.ed.ac.ukSyscallReturn 13386684Stjones1@inf.ed.ac.ukstat64Func(SyscallDesc *desc, int callnum, Process *process, 13398737Skoansin.tan@gmail.com ThreadContext *tc) 13408852Sandreas.hansson@arm.com{ 13418852Sandreas.hansson@arm.com std::string path; 13426684Stjones1@inf.ed.ac.uk 13436684Stjones1@inf.ed.ac.uk int index = 0; 13446684Stjones1@inf.ed.ac.uk if (!tc->getMemProxy().tryReadString(path, 13452553SN/A process->getSyscallArg(tc, index))) 13462553SN/A return -EFAULT; 13471354SN/A Addr bufPtr = process->getSyscallArg(tc, index); 1348 1349 // Adjust path for cwd and redirection 1350 path = process->checkPathRedirect(path); 1351 1352#if NO_STAT64 1353 struct stat hostBuf; 1354 int result = stat(path.c_str(), &hostBuf); 1355#else 1356 struct stat64 hostBuf; 1357 int result = stat64(path.c_str(), &hostBuf); 1358#endif 1359 1360 if (result < 0) 1361 return -errno; 1362 1363 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1364 1365 return 0; 1366} 1367 1368 1369/// Target fstatat64() handler. 1370template <class OS> 1371SyscallReturn 1372fstatat64Func(SyscallDesc *desc, int callnum, Process *process, 1373 ThreadContext *tc) 1374{ 1375 int index = 0; 1376 int dirfd = process->getSyscallArg(tc, index); 1377 if (dirfd != OS::TGT_AT_FDCWD) 1378 warn("fstatat64: first argument not AT_FDCWD; unlikely to work"); 1379 1380 std::string path; 1381 if (!tc->getMemProxy().tryReadString(path, 1382 process->getSyscallArg(tc, index))) 1383 return -EFAULT; 1384 Addr bufPtr = process->getSyscallArg(tc, index); 1385 1386 // Adjust path for cwd and redirection 1387 path = process->checkPathRedirect(path); 1388 1389#if NO_STAT64 1390 struct stat hostBuf; 1391 int result = stat(path.c_str(), &hostBuf); 1392#else 1393 struct stat64 hostBuf; 1394 int result = stat64(path.c_str(), &hostBuf); 1395#endif 1396 1397 if (result < 0) 1398 return -errno; 1399 1400 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1401 1402 return 0; 1403} 1404 1405 1406/// Target fstat64() handler. 1407template <class OS> 1408SyscallReturn 1409fstat64Func(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1410{ 1411 int index = 0; 1412 int tgt_fd = p->getSyscallArg(tc, index); 1413 Addr bufPtr = p->getSyscallArg(tc, index); 1414 1415 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 1416 if (!ffdp) 1417 return -EBADF; 1418 int sim_fd = ffdp->getSimFD(); 1419 1420#if NO_STAT64 1421 struct stat hostBuf; 1422 int result = fstat(sim_fd, &hostBuf); 1423#else 1424 struct stat64 hostBuf; 1425 int result = fstat64(sim_fd, &hostBuf); 1426#endif 1427 1428 if (result < 0) 1429 return -errno; 1430 1431 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (sim_fd == 1)); 1432 1433 return 0; 1434} 1435 1436 1437/// Target lstat() handler. 1438template <class OS> 1439SyscallReturn 1440lstatFunc(SyscallDesc *desc, int callnum, Process *process, 1441 ThreadContext *tc) 1442{ 1443 std::string path; 1444 1445 int index = 0; 1446 if (!tc->getMemProxy().tryReadString(path, 1447 process->getSyscallArg(tc, index))) { 1448 return -EFAULT; 1449 } 1450 Addr bufPtr = process->getSyscallArg(tc, index); 1451 1452 // Adjust path for cwd and redirection 1453 path = process->checkPathRedirect(path); 1454 1455 struct stat hostBuf; 1456 int result = lstat(path.c_str(), &hostBuf); 1457 1458 if (result < 0) 1459 return -errno; 1460 1461 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1462 1463 return 0; 1464} 1465 1466/// Target lstat64() handler. 1467template <class OS> 1468SyscallReturn 1469lstat64Func(SyscallDesc *desc, int callnum, Process *process, 1470 ThreadContext *tc) 1471{ 1472 std::string path; 1473 1474 int index = 0; 1475 if (!tc->getMemProxy().tryReadString(path, 1476 process->getSyscallArg(tc, index))) { 1477 return -EFAULT; 1478 } 1479 Addr bufPtr = process->getSyscallArg(tc, index); 1480 1481 // Adjust path for cwd and redirection 1482 path = process->checkPathRedirect(path); 1483 1484#if NO_STAT64 1485 struct stat hostBuf; 1486 int result = lstat(path.c_str(), &hostBuf); 1487#else 1488 struct stat64 hostBuf; 1489 int result = lstat64(path.c_str(), &hostBuf); 1490#endif 1491 1492 if (result < 0) 1493 return -errno; 1494 1495 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1496 1497 return 0; 1498} 1499 1500/// Target fstat() handler. 1501template <class OS> 1502SyscallReturn 1503fstatFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1504{ 1505 int index = 0; 1506 int tgt_fd = p->getSyscallArg(tc, index); 1507 Addr bufPtr = p->getSyscallArg(tc, index); 1508 1509 DPRINTF_SYSCALL(Verbose, "fstat(%d, ...)\n", tgt_fd); 1510 1511 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 1512 if (!ffdp) 1513 return -EBADF; 1514 int sim_fd = ffdp->getSimFD(); 1515 1516 struct stat hostBuf; 1517 int result = fstat(sim_fd, &hostBuf); 1518 1519 if (result < 0) 1520 return -errno; 1521 1522 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (sim_fd == 1)); 1523 1524 return 0; 1525} 1526 1527/// Target statfs() handler. 1528template <class OS> 1529SyscallReturn 1530statfsFunc(SyscallDesc *desc, int callnum, Process *process, 1531 ThreadContext *tc) 1532{ 1533#if NO_STATFS 1534 warn("Host OS cannot support calls to statfs. Ignoring syscall"); 1535#else 1536 std::string path; 1537 1538 int index = 0; 1539 if (!tc->getMemProxy().tryReadString(path, 1540 process->getSyscallArg(tc, index))) { 1541 return -EFAULT; 1542 } 1543 Addr bufPtr = process->getSyscallArg(tc, index); 1544 1545 // Adjust path for cwd and redirection 1546 path = process->checkPathRedirect(path); 1547 1548 struct statfs hostBuf; 1549 int result = statfs(path.c_str(), &hostBuf); 1550 1551 if (result < 0) 1552 return -errno; 1553 1554 copyOutStatfsBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1555#endif 1556 return 0; 1557} 1558 1559template <class OS> 1560SyscallReturn 1561cloneFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1562{ 1563 int index = 0; 1564 1565 RegVal flags = p->getSyscallArg(tc, index); 1566 RegVal newStack = p->getSyscallArg(tc, index); 1567 Addr ptidPtr = p->getSyscallArg(tc, index); 1568 1569#if THE_ISA == RISCV_ISA or THE_ISA == ARM_ISA 1570 /** 1571 * Linux sets CLONE_BACKWARDS flag for RISC-V and Arm. 1572 * The flag defines the list of clone() arguments in the following 1573 * order: flags -> newStack -> ptidPtr -> tlsPtr -> ctidPtr 1574 */ 1575 Addr tlsPtr = p->getSyscallArg(tc, index); 1576 Addr ctidPtr = p->getSyscallArg(tc, index); 1577#else 1578 Addr ctidPtr = p->getSyscallArg(tc, index); 1579 Addr tlsPtr = p->getSyscallArg(tc, index); 1580#endif 1581 1582 if (((flags & OS::TGT_CLONE_SIGHAND)&& !(flags & OS::TGT_CLONE_VM)) || 1583 ((flags & OS::TGT_CLONE_THREAD) && !(flags & OS::TGT_CLONE_SIGHAND)) || 1584 ((flags & OS::TGT_CLONE_FS) && (flags & OS::TGT_CLONE_NEWNS)) || 1585 ((flags & OS::TGT_CLONE_NEWIPC) && (flags & OS::TGT_CLONE_SYSVSEM)) || 1586 ((flags & OS::TGT_CLONE_NEWPID) && (flags & OS::TGT_CLONE_THREAD)) || 1587 ((flags & OS::TGT_CLONE_VM) && !(newStack))) 1588 return -EINVAL; 1589 1590 ThreadContext *ctc; 1591 if (!(ctc = p->findFreeContext())) { 1592 DPRINTF_SYSCALL(Verbose, "clone: no spare thread context in system" 1593 "[cpu %d, thread %d]", tc->cpuId(), tc->threadId()); 1594 return -EAGAIN; 1595 } 1596 1597 /** 1598 * Note that ProcessParams is generated by swig and there are no other 1599 * examples of how to create anything but this default constructor. The 1600 * fields are manually initialized instead of passing parameters to the 1601 * constructor. 1602 */ 1603 ProcessParams *pp = new ProcessParams(); 1604 pp->executable.assign(*(new std::string(p->progName()))); 1605 pp->cmd.push_back(*(new std::string(p->progName()))); 1606 pp->system = p->system; 1607 pp->cwd.assign(p->tgtCwd); 1608 pp->input.assign("stdin"); 1609 pp->output.assign("stdout"); 1610 pp->errout.assign("stderr"); 1611 pp->uid = p->uid(); 1612 pp->euid = p->euid(); 1613 pp->gid = p->gid(); 1614 pp->egid = p->egid(); 1615 1616 /* Find the first free PID that's less than the maximum */ 1617 std::set<int> const& pids = p->system->PIDs; 1618 int temp_pid = *pids.begin(); 1619 do { 1620 temp_pid++; 1621 } while (pids.find(temp_pid) != pids.end()); 1622 if (temp_pid >= System::maxPID) 1623 fatal("temp_pid is too large: %d", temp_pid); 1624 1625 pp->pid = temp_pid; 1626 pp->ppid = (flags & OS::TGT_CLONE_THREAD) ? p->ppid() : p->pid(); 1627 pp->useArchPT = p->useArchPT; 1628 pp->kvmInSE = p->kvmInSE; 1629 Process *cp = pp->create(); 1630 delete pp; 1631 1632 Process *owner = ctc->getProcessPtr(); 1633 ctc->setProcessPtr(cp); 1634 cp->assignThreadContext(ctc->contextId()); 1635 owner->revokeThreadContext(ctc->contextId()); 1636 1637 if (flags & OS::TGT_CLONE_PARENT_SETTID) { 1638 BufferArg ptidBuf(ptidPtr, sizeof(long)); 1639 long *ptid = (long *)ptidBuf.bufferPtr(); 1640 *ptid = cp->pid(); 1641 ptidBuf.copyOut(tc->getMemProxy()); 1642 } 1643 1644 if (flags & OS::TGT_CLONE_THREAD) { 1645 cp->pTable->shared = true; 1646 cp->useForClone = true; 1647 } 1648 cp->initState(); 1649 p->clone(tc, ctc, cp, flags); 1650 1651 if (flags & OS::TGT_CLONE_THREAD) { 1652 delete cp->sigchld; 1653 cp->sigchld = p->sigchld; 1654 } else if (flags & OS::TGT_SIGCHLD) { 1655 *cp->sigchld = true; 1656 } 1657 1658 if (flags & OS::TGT_CLONE_CHILD_SETTID) { 1659 BufferArg ctidBuf(ctidPtr, sizeof(long)); 1660 long *ctid = (long *)ctidBuf.bufferPtr(); 1661 *ctid = cp->pid(); 1662 ctidBuf.copyOut(ctc->getMemProxy()); 1663 } 1664 1665 if (flags & OS::TGT_CLONE_CHILD_CLEARTID) 1666 cp->childClearTID = (uint64_t)ctidPtr; 1667 1668 ctc->clearArchRegs(); 1669 1670 OS::archClone(flags, p, cp, tc, ctc, newStack, tlsPtr); 1671 1672 cp->setSyscallReturn(ctc, 0); 1673 1674#if THE_ISA == ALPHA_ISA 1675 ctc->setIntReg(TheISA::SyscallSuccessReg, 0); 1676#elif THE_ISA == SPARC_ISA 1677 tc->setIntReg(TheISA::SyscallPseudoReturnReg, 0); 1678 ctc->setIntReg(TheISA::SyscallPseudoReturnReg, 1); 1679#endif 1680 1681 if (p->kvmInSE) { 1682#if THE_ISA == X86_ISA 1683 ctc->pcState(tc->readIntReg(TheISA::INTREG_RCX)); 1684#else 1685 panic("KVM CPU model is not supported for this ISA"); 1686#endif 1687 } else { 1688 TheISA::PCState cpc = tc->pcState(); 1689 cpc.advance(); 1690 ctc->pcState(cpc); 1691 } 1692 ctc->activate(); 1693 1694 return cp->pid(); 1695} 1696 1697/// Target fstatfs() handler. 1698template <class OS> 1699SyscallReturn 1700fstatfsFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1701{ 1702 int index = 0; 1703 int tgt_fd = p->getSyscallArg(tc, index); 1704 Addr bufPtr = p->getSyscallArg(tc, index); 1705 1706 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 1707 if (!ffdp) 1708 return -EBADF; 1709 int sim_fd = ffdp->getSimFD(); 1710 1711 struct statfs hostBuf; 1712 int result = fstatfs(sim_fd, &hostBuf); 1713 1714 if (result < 0) 1715 return -errno; 1716 1717 copyOutStatfsBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1718 1719 return 0; 1720} 1721 1722/// Target readv() handler. 1723template <class OS> 1724SyscallReturn 1725readvFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1726{ 1727 int index = 0; 1728 int tgt_fd = p->getSyscallArg(tc, index); 1729 1730 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 1731 if (!ffdp) 1732 return -EBADF; 1733 int sim_fd = ffdp->getSimFD(); 1734 1735 SETranslatingPortProxy &prox = tc->getMemProxy(); 1736 uint64_t tiov_base = p->getSyscallArg(tc, index); 1737 size_t count = p->getSyscallArg(tc, index); 1738 typename OS::tgt_iovec tiov[count]; 1739 struct iovec hiov[count]; 1740 for (size_t i = 0; i < count; ++i) { 1741 prox.readBlob(tiov_base + (i * sizeof(typename OS::tgt_iovec)), 1742 (uint8_t*)&tiov[i], sizeof(typename OS::tgt_iovec)); 1743 hiov[i].iov_len = TheISA::gtoh(tiov[i].iov_len); 1744 hiov[i].iov_base = new char [hiov[i].iov_len]; 1745 } 1746 1747 int result = readv(sim_fd, hiov, count); 1748 int local_errno = errno; 1749 1750 for (size_t i = 0; i < count; ++i) { 1751 if (result != -1) { 1752 prox.writeBlob(TheISA::htog(tiov[i].iov_base), 1753 (uint8_t*)hiov[i].iov_base, hiov[i].iov_len); 1754 } 1755 delete [] (char *)hiov[i].iov_base; 1756 } 1757 1758 return (result == -1) ? -local_errno : result; 1759} 1760 1761/// Target writev() handler. 1762template <class OS> 1763SyscallReturn 1764writevFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1765{ 1766 int index = 0; 1767 int tgt_fd = p->getSyscallArg(tc, index); 1768 1769 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 1770 if (!hbfdp) 1771 return -EBADF; 1772 int sim_fd = hbfdp->getSimFD(); 1773 1774 SETranslatingPortProxy &prox = tc->getMemProxy(); 1775 uint64_t tiov_base = p->getSyscallArg(tc, index); 1776 size_t count = p->getSyscallArg(tc, index); 1777 struct iovec hiov[count]; 1778 for (size_t i = 0; i < count; ++i) { 1779 typename OS::tgt_iovec tiov; 1780 1781 prox.readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec), 1782 (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec)); 1783 hiov[i].iov_len = TheISA::gtoh(tiov.iov_len); 1784 hiov[i].iov_base = new char [hiov[i].iov_len]; 1785 prox.readBlob(TheISA::gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base, 1786 hiov[i].iov_len); 1787 } 1788 1789 int result = writev(sim_fd, hiov, count); 1790 1791 for (size_t i = 0; i < count; ++i) 1792 delete [] (char *)hiov[i].iov_base; 1793 1794 return (result == -1) ? -errno : result; 1795} 1796 1797/// Real mmap handler. 1798template <class OS> 1799SyscallReturn 1800mmapImpl(SyscallDesc *desc, int num, Process *p, ThreadContext *tc, 1801 bool is_mmap2) 1802{ 1803 int index = 0; 1804 Addr start = p->getSyscallArg(tc, index); 1805 uint64_t length = p->getSyscallArg(tc, index); 1806 int prot = p->getSyscallArg(tc, index); 1807 int tgt_flags = p->getSyscallArg(tc, index); 1808 int tgt_fd = p->getSyscallArg(tc, index); 1809 int offset = p->getSyscallArg(tc, index); 1810 1811 if (is_mmap2) 1812 offset *= TheISA::PageBytes; 1813 1814 if (start & (TheISA::PageBytes - 1) || 1815 offset & (TheISA::PageBytes - 1) || 1816 (tgt_flags & OS::TGT_MAP_PRIVATE && 1817 tgt_flags & OS::TGT_MAP_SHARED) || 1818 (!(tgt_flags & OS::TGT_MAP_PRIVATE) && 1819 !(tgt_flags & OS::TGT_MAP_SHARED)) || 1820 !length) { 1821 return -EINVAL; 1822 } 1823 1824 if ((prot & PROT_WRITE) && (tgt_flags & OS::TGT_MAP_SHARED)) { 1825 // With shared mmaps, there are two cases to consider: 1826 // 1) anonymous: writes should modify the mapping and this should be 1827 // visible to observers who share the mapping. Currently, it's 1828 // difficult to update the shared mapping because there's no 1829 // structure which maintains information about the which virtual 1830 // memory areas are shared. If that structure existed, it would be 1831 // possible to make the translations point to the same frames. 1832 // 2) file-backed: writes should modify the mapping and the file 1833 // which is backed by the mapping. The shared mapping problem is the 1834 // same as what was mentioned about the anonymous mappings. For 1835 // file-backed mappings, the writes to the file are difficult 1836 // because it requires syncing what the mapping holds with the file 1837 // that resides on the host system. So, any write on a real system 1838 // would cause the change to be propagated to the file mapping at 1839 // some point in the future (the inode is tracked along with the 1840 // mapping). This isn't guaranteed to always happen, but it usually 1841 // works well enough. The guarantee is provided by the msync system 1842 // call. We could force the change through with shared mappings with 1843 // a call to msync, but that again would require more information 1844 // than we currently maintain. 1845 warn("mmap: writing to shared mmap region is currently " 1846 "unsupported. The write succeeds on the target, but it " 1847 "will not be propagated to the host or shared mappings"); 1848 } 1849 1850 length = roundUp(length, TheISA::PageBytes); 1851 1852 int sim_fd = -1; 1853 uint8_t *pmap = nullptr; 1854 if (!(tgt_flags & OS::TGT_MAP_ANONYMOUS)) { 1855 std::shared_ptr<FDEntry> fdep = (*p->fds)[tgt_fd]; 1856 1857 auto dfdp = std::dynamic_pointer_cast<DeviceFDEntry>(fdep); 1858 if (dfdp) { 1859 EmulatedDriver *emul_driver = dfdp->getDriver(); 1860 return emul_driver->mmap(p, tc, start, length, prot, 1861 tgt_flags, tgt_fd, offset); 1862 } 1863 1864 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep); 1865 if (!ffdp) 1866 return -EBADF; 1867 sim_fd = ffdp->getSimFD(); 1868 1869 pmap = (decltype(pmap))mmap(nullptr, length, PROT_READ, MAP_PRIVATE, 1870 sim_fd, offset); 1871 1872 if (pmap == (decltype(pmap))-1) { 1873 warn("mmap: failed to map file into host address space"); 1874 return -errno; 1875 } 1876 } 1877 1878 // Extend global mmap region if necessary. Note that we ignore the 1879 // start address unless MAP_FIXED is specified. 1880 if (!(tgt_flags & OS::TGT_MAP_FIXED)) { 1881 std::shared_ptr<MemState> mem_state = p->memState; 1882 Addr mmap_end = mem_state->getMmapEnd(); 1883 1884 start = p->mmapGrowsDown() ? mmap_end - length : mmap_end; 1885 mmap_end = p->mmapGrowsDown() ? start : mmap_end + length; 1886 1887 mem_state->setMmapEnd(mmap_end); 1888 } 1889 1890 DPRINTF_SYSCALL(Verbose, " mmap range is 0x%x - 0x%x\n", 1891 start, start + length - 1); 1892 1893 // We only allow mappings to overwrite existing mappings if 1894 // TGT_MAP_FIXED is set. Otherwise it shouldn't be a problem 1895 // because we ignore the start hint if TGT_MAP_FIXED is not set. 1896 int clobber = tgt_flags & OS::TGT_MAP_FIXED; 1897 if (clobber) { 1898 for (auto tc : p->system->threadContexts) { 1899 // If we might be overwriting old mappings, we need to 1900 // invalidate potentially stale mappings out of the TLBs. 1901 tc->getDTBPtr()->flushAll(); 1902 tc->getITBPtr()->flushAll(); 1903 } 1904 } 1905 1906 // Allocate physical memory and map it in. If the page table is already 1907 // mapped and clobber is not set, the simulator will issue throw a 1908 // fatal and bail out of the simulation. 1909 p->allocateMem(start, length, clobber); 1910 1911 // Transfer content into target address space. 1912 SETranslatingPortProxy &tp = tc->getMemProxy(); 1913 if (tgt_flags & OS::TGT_MAP_ANONYMOUS) { 1914 // In general, we should zero the mapped area for anonymous mappings, 1915 // with something like: 1916 // tp.memsetBlob(start, 0, length); 1917 // However, given that we don't support sparse mappings, and 1918 // some applications can map a couple of gigabytes of space 1919 // (intending sparse usage), that can get painfully expensive. 1920 // Fortunately, since we don't properly implement munmap either, 1921 // there's no danger of remapping used memory, so for now all 1922 // newly mapped memory should already be zeroed so we can skip it. 1923 } else { 1924 // It is possible to mmap an area larger than a file, however 1925 // accessing unmapped portions the system triggers a "Bus error" 1926 // on the host. We must know when to stop copying the file from 1927 // the host into the target address space. 1928 struct stat file_stat; 1929 if (fstat(sim_fd, &file_stat) > 0) 1930 fatal("mmap: cannot stat file"); 1931 1932 // Copy the portion of the file that is resident. This requires 1933 // checking both the mmap size and the filesize that we are 1934 // trying to mmap into this space; the mmap size also depends 1935 // on the specified offset into the file. 1936 uint64_t size = std::min((uint64_t)file_stat.st_size - offset, 1937 length); 1938 tp.writeBlob(start, pmap, size); 1939 1940 // Cleanup the mmap region before exiting this function. 1941 munmap(pmap, length); 1942 1943 // Maintain the symbol table for dynamic executables. 1944 // The loader will call mmap to map the images into its address 1945 // space and we intercept that here. We can verify that we are 1946 // executing inside the loader by checking the program counter value. 1947 // XXX: with multiprogrammed workloads or multi-node configurations, 1948 // this will not work since there is a single global symbol table. 1949 ObjectFile *interpreter = p->getInterpreter(); 1950 if (interpreter) { 1951 Addr text_start = interpreter->textBase(); 1952 Addr text_end = text_start + interpreter->textSize(); 1953 1954 Addr pc = tc->pcState().pc(); 1955 1956 if (pc >= text_start && pc < text_end) { 1957 std::shared_ptr<FDEntry> fdep = (*p->fds)[tgt_fd]; 1958 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep); 1959 ObjectFile *lib = createObjectFile(ffdp->getFileName()); 1960 1961 if (lib) { 1962 lib->loadAllSymbols(debugSymbolTable, 1963 lib->textBase(), start); 1964 } 1965 } 1966 } 1967 1968 // Note that we do not zero out the remainder of the mapping. This 1969 // is done by a real system, but it probably will not affect 1970 // execution (hopefully). 1971 } 1972 1973 return start; 1974} 1975 1976template <class OS> 1977SyscallReturn 1978pwrite64Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1979{ 1980 int index = 0; 1981 int tgt_fd = p->getSyscallArg(tc, index); 1982 Addr bufPtr = p->getSyscallArg(tc, index); 1983 int nbytes = p->getSyscallArg(tc, index); 1984 int offset = p->getSyscallArg(tc, index); 1985 1986 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 1987 if (!ffdp) 1988 return -EBADF; 1989 int sim_fd = ffdp->getSimFD(); 1990 1991 BufferArg bufArg(bufPtr, nbytes); 1992 bufArg.copyIn(tc->getMemProxy()); 1993 1994 int bytes_written = pwrite(sim_fd, bufArg.bufferPtr(), nbytes, offset); 1995 1996 return (bytes_written == -1) ? -errno : bytes_written; 1997} 1998 1999/// Target mmap() handler. 2000template <class OS> 2001SyscallReturn 2002mmapFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 2003{ 2004 return mmapImpl<OS>(desc, num, p, tc, false); 2005} 2006 2007/// Target mmap2() handler. 2008template <class OS> 2009SyscallReturn 2010mmap2Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 2011{ 2012 return mmapImpl<OS>(desc, num, p, tc, true); 2013} 2014 2015/// Target getrlimit() handler. 2016template <class OS> 2017SyscallReturn 2018getrlimitFunc(SyscallDesc *desc, int callnum, Process *process, 2019 ThreadContext *tc) 2020{ 2021 int index = 0; 2022 unsigned resource = process->getSyscallArg(tc, index); 2023 TypedBufferArg<typename OS::rlimit> rlp(process->getSyscallArg(tc, index)); 2024 2025 switch (resource) { 2026 case OS::TGT_RLIMIT_STACK: 2027 // max stack size in bytes: make up a number (8MB for now) 2028 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; 2029 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 2030 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 2031 break; 2032 2033 case OS::TGT_RLIMIT_DATA: 2034 // max data segment size in bytes: make up a number 2035 rlp->rlim_cur = rlp->rlim_max = 256 * 1024 * 1024; 2036 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 2037 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 2038 break; 2039 2040 default: 2041 warn("getrlimit: unimplemented resource %d", resource); 2042 return -EINVAL; 2043 break; 2044 } 2045 2046 rlp.copyOut(tc->getMemProxy()); 2047 return 0; 2048} 2049 2050template <class OS> 2051SyscallReturn 2052prlimitFunc(SyscallDesc *desc, int callnum, Process *process, 2053 ThreadContext *tc) 2054{ 2055 int index = 0; 2056 if (process->getSyscallArg(tc, index) != 0) 2057 { 2058 warn("prlimit: ignoring rlimits for nonzero pid"); 2059 return -EPERM; 2060 } 2061 int resource = process->getSyscallArg(tc, index); 2062 Addr n = process->getSyscallArg(tc, index); 2063 if (n != 0) 2064 warn("prlimit: ignoring new rlimit"); 2065 Addr o = process->getSyscallArg(tc, index); 2066 if (o != 0) 2067 { 2068 TypedBufferArg<typename OS::rlimit> rlp(o); 2069 switch (resource) { 2070 case OS::TGT_RLIMIT_STACK: 2071 // max stack size in bytes: make up a number (8MB for now) 2072 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; 2073 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 2074 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 2075 break; 2076 case OS::TGT_RLIMIT_DATA: 2077 // max data segment size in bytes: make up a number 2078 rlp->rlim_cur = rlp->rlim_max = 256*1024*1024; 2079 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 2080 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 2081 break; 2082 default: 2083 warn("prlimit: unimplemented resource %d", resource); 2084 return -EINVAL; 2085 break; 2086 } 2087 rlp.copyOut(tc->getMemProxy()); 2088 } 2089 return 0; 2090} 2091 2092/// Target clock_gettime() function. 2093template <class OS> 2094SyscallReturn 2095clock_gettimeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 2096{ 2097 int index = 1; 2098 //int clk_id = p->getSyscallArg(tc, index); 2099 TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index)); 2100 2101 getElapsedTimeNano(tp->tv_sec, tp->tv_nsec); 2102 tp->tv_sec += seconds_since_epoch; 2103 tp->tv_sec = TheISA::htog(tp->tv_sec); 2104 tp->tv_nsec = TheISA::htog(tp->tv_nsec); 2105 2106 tp.copyOut(tc->getMemProxy()); 2107 2108 return 0; 2109} 2110 2111/// Target clock_getres() function. 2112template <class OS> 2113SyscallReturn 2114clock_getresFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 2115{ 2116 int index = 1; 2117 TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index)); 2118 2119 // Set resolution at ns, which is what clock_gettime() returns 2120 tp->tv_sec = 0; 2121 tp->tv_nsec = 1; 2122 2123 tp.copyOut(tc->getMemProxy()); 2124 2125 return 0; 2126} 2127 2128/// Target gettimeofday() handler. 2129template <class OS> 2130SyscallReturn 2131gettimeofdayFunc(SyscallDesc *desc, int callnum, Process *process, 2132 ThreadContext *tc) 2133{ 2134 int index = 0; 2135 TypedBufferArg<typename OS::timeval> tp(process->getSyscallArg(tc, index)); 2136 2137 getElapsedTimeMicro(tp->tv_sec, tp->tv_usec); 2138 tp->tv_sec += seconds_since_epoch; 2139 tp->tv_sec = TheISA::htog(tp->tv_sec); 2140 tp->tv_usec = TheISA::htog(tp->tv_usec); 2141 2142 tp.copyOut(tc->getMemProxy()); 2143 2144 return 0; 2145} 2146 2147 2148/// Target utimes() handler. 2149template <class OS> 2150SyscallReturn 2151utimesFunc(SyscallDesc *desc, int callnum, Process *process, 2152 ThreadContext *tc) 2153{ 2154 std::string path; 2155 2156 int index = 0; 2157 if (!tc->getMemProxy().tryReadString(path, 2158 process->getSyscallArg(tc, index))) { 2159 return -EFAULT; 2160 } 2161 2162 TypedBufferArg<typename OS::timeval [2]> 2163 tp(process->getSyscallArg(tc, index)); 2164 tp.copyIn(tc->getMemProxy()); 2165 2166 struct timeval hostTimeval[2]; 2167 for (int i = 0; i < 2; ++i) { 2168 hostTimeval[i].tv_sec = TheISA::gtoh((*tp)[i].tv_sec); 2169 hostTimeval[i].tv_usec = TheISA::gtoh((*tp)[i].tv_usec); 2170 } 2171 2172 // Adjust path for cwd and redirection 2173 path = process->checkPathRedirect(path); 2174 2175 int result = utimes(path.c_str(), hostTimeval); 2176 2177 if (result < 0) 2178 return -errno; 2179 2180 return 0; 2181} 2182 2183template <class OS> 2184SyscallReturn 2185execveFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 2186{ 2187 desc->setFlags(0); 2188 2189 int index = 0; 2190 std::string path; 2191 SETranslatingPortProxy & mem_proxy = tc->getMemProxy(); 2192 if (!mem_proxy.tryReadString(path, p->getSyscallArg(tc, index))) 2193 return -EFAULT; 2194 2195 if (access(path.c_str(), F_OK) == -1) 2196 return -EACCES; 2197 2198 auto read_in = [](std::vector<std::string> & vect, 2199 SETranslatingPortProxy & mem_proxy, 2200 Addr mem_loc) 2201 { 2202 for (int inc = 0; ; inc++) { 2203 BufferArg b((mem_loc + sizeof(Addr) * inc), sizeof(Addr)); 2204 b.copyIn(mem_proxy); 2205 2206 if (!*(Addr*)b.bufferPtr()) 2207 break; 2208 2209 vect.push_back(std::string()); 2210 mem_proxy.tryReadString(vect[inc], *(Addr*)b.bufferPtr()); 2211 } 2212 }; 2213 2214 /** 2215 * Note that ProcessParams is generated by swig and there are no other 2216 * examples of how to create anything but this default constructor. The 2217 * fields are manually initialized instead of passing parameters to the 2218 * constructor. 2219 */ 2220 ProcessParams *pp = new ProcessParams(); 2221 pp->executable = path; 2222 Addr argv_mem_loc = p->getSyscallArg(tc, index); 2223 read_in(pp->cmd, mem_proxy, argv_mem_loc); 2224 Addr envp_mem_loc = p->getSyscallArg(tc, index); 2225 read_in(pp->env, mem_proxy, envp_mem_loc); 2226 pp->uid = p->uid(); 2227 pp->egid = p->egid(); 2228 pp->euid = p->euid(); 2229 pp->gid = p->gid(); 2230 pp->ppid = p->ppid(); 2231 pp->pid = p->pid(); 2232 pp->input.assign("cin"); 2233 pp->output.assign("cout"); 2234 pp->errout.assign("cerr"); 2235 pp->cwd.assign(p->tgtCwd); 2236 pp->system = p->system; 2237 /** 2238 * Prevent process object creation with identical PIDs (which will trip 2239 * a fatal check in Process constructor). The execve call is supposed to 2240 * take over the currently executing process' identity but replace 2241 * whatever it is doing with a new process image. Instead of hijacking 2242 * the process object in the simulator, we create a new process object 2243 * and bind to the previous process' thread below (hijacking the thread). 2244 */ 2245 p->system->PIDs.erase(p->pid()); 2246 Process *new_p = pp->create(); 2247 delete pp; 2248 2249 /** 2250 * Work through the file descriptor array and close any files marked 2251 * close-on-exec. 2252 */ 2253 new_p->fds = p->fds; 2254 for (int i = 0; i < new_p->fds->getSize(); i++) { 2255 std::shared_ptr<FDEntry> fdep = (*new_p->fds)[i]; 2256 if (fdep && fdep->getCOE()) 2257 new_p->fds->closeFDEntry(i); 2258 } 2259 2260 *new_p->sigchld = true; 2261 2262 delete p; 2263 tc->clearArchRegs(); 2264 tc->setProcessPtr(new_p); 2265 new_p->assignThreadContext(tc->contextId()); 2266 new_p->initState(); 2267 tc->activate(); 2268 TheISA::PCState pcState = tc->pcState(); 2269 tc->setNPC(pcState.instAddr()); 2270 2271 desc->setFlags(SyscallDesc::SuppressReturnValue); 2272 return 0; 2273} 2274 2275/// Target getrusage() function. 2276template <class OS> 2277SyscallReturn 2278getrusageFunc(SyscallDesc *desc, int callnum, Process *process, 2279 ThreadContext *tc) 2280{ 2281 int index = 0; 2282 int who = process->getSyscallArg(tc, index); // THREAD, SELF, or CHILDREN 2283 TypedBufferArg<typename OS::rusage> rup(process->getSyscallArg(tc, index)); 2284 2285 rup->ru_utime.tv_sec = 0; 2286 rup->ru_utime.tv_usec = 0; 2287 rup->ru_stime.tv_sec = 0; 2288 rup->ru_stime.tv_usec = 0; 2289 rup->ru_maxrss = 0; 2290 rup->ru_ixrss = 0; 2291 rup->ru_idrss = 0; 2292 rup->ru_isrss = 0; 2293 rup->ru_minflt = 0; 2294 rup->ru_majflt = 0; 2295 rup->ru_nswap = 0; 2296 rup->ru_inblock = 0; 2297 rup->ru_oublock = 0; 2298 rup->ru_msgsnd = 0; 2299 rup->ru_msgrcv = 0; 2300 rup->ru_nsignals = 0; 2301 rup->ru_nvcsw = 0; 2302 rup->ru_nivcsw = 0; 2303 2304 switch (who) { 2305 case OS::TGT_RUSAGE_SELF: 2306 getElapsedTimeMicro(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec); 2307 rup->ru_utime.tv_sec = TheISA::htog(rup->ru_utime.tv_sec); 2308 rup->ru_utime.tv_usec = TheISA::htog(rup->ru_utime.tv_usec); 2309 break; 2310 2311 case OS::TGT_RUSAGE_CHILDREN: 2312 // do nothing. We have no child processes, so they take no time. 2313 break; 2314 2315 default: 2316 // don't really handle THREAD or CHILDREN, but just warn and 2317 // plow ahead 2318 warn("getrusage() only supports RUSAGE_SELF. Parameter %d ignored.", 2319 who); 2320 } 2321 2322 rup.copyOut(tc->getMemProxy()); 2323 2324 return 0; 2325} 2326 2327/// Target times() function. 2328template <class OS> 2329SyscallReturn 2330timesFunc(SyscallDesc *desc, int callnum, Process *process, 2331 ThreadContext *tc) 2332{ 2333 int index = 0; 2334 TypedBufferArg<typename OS::tms> bufp(process->getSyscallArg(tc, index)); 2335 2336 // Fill in the time structure (in clocks) 2337 int64_t clocks = curTick() * OS::M5_SC_CLK_TCK / SimClock::Int::s; 2338 bufp->tms_utime = clocks; 2339 bufp->tms_stime = 0; 2340 bufp->tms_cutime = 0; 2341 bufp->tms_cstime = 0; 2342 2343 // Convert to host endianness 2344 bufp->tms_utime = TheISA::htog(bufp->tms_utime); 2345 2346 // Write back 2347 bufp.copyOut(tc->getMemProxy()); 2348 2349 // Return clock ticks since system boot 2350 return clocks; 2351} 2352 2353/// Target time() function. 2354template <class OS> 2355SyscallReturn 2356timeFunc(SyscallDesc *desc, int callnum, Process *process, ThreadContext *tc) 2357{ 2358 typename OS::time_t sec, usec; 2359 getElapsedTimeMicro(sec, usec); 2360 sec += seconds_since_epoch; 2361 2362 int index = 0; 2363 Addr taddr = (Addr)process->getSyscallArg(tc, index); 2364 if (taddr != 0) { 2365 typename OS::time_t t = sec; 2366 t = TheISA::htog(t); 2367 SETranslatingPortProxy &p = tc->getMemProxy(); 2368 p.writeBlob(taddr, (uint8_t*)&t, (int)sizeof(typename OS::time_t)); 2369 } 2370 return sec; 2371} 2372 2373template <class OS> 2374SyscallReturn 2375tgkillFunc(SyscallDesc *desc, int num, Process *process, ThreadContext *tc) 2376{ 2377 int index = 0; 2378 int tgid = process->getSyscallArg(tc, index); 2379 int tid = process->getSyscallArg(tc, index); 2380 int sig = process->getSyscallArg(tc, index); 2381 2382 /** 2383 * This system call is intended to allow killing a specific thread 2384 * within an arbitrary thread group if sanctioned with permission checks. 2385 * It's usually true that threads share the termination signal as pointed 2386 * out by the pthread_kill man page and this seems to be the intended 2387 * usage. Due to this being an emulated environment, assume the following: 2388 * Threads are allowed to call tgkill because the EUID for all threads 2389 * should be the same. There is no signal handling mechanism for kernel 2390 * registration of signal handlers since signals are poorly supported in 2391 * emulation mode. Since signal handlers cannot be registered, all 2392 * threads within in a thread group must share the termination signal. 2393 * We never exhaust PIDs so there's no chance of finding the wrong one 2394 * due to PID rollover. 2395 */ 2396 2397 System *sys = tc->getSystemPtr(); 2398 Process *tgt_proc = nullptr; 2399 for (int i = 0; i < sys->numContexts(); i++) { 2400 Process *temp = sys->threadContexts[i]->getProcessPtr(); 2401 if (temp->pid() == tid) { 2402 tgt_proc = temp; 2403 break; 2404 } 2405 } 2406 2407 if (sig != 0 || sig != OS::TGT_SIGABRT) 2408 return -EINVAL; 2409 2410 if (tgt_proc == nullptr) 2411 return -ESRCH; 2412 2413 if (tgid != -1 && tgt_proc->tgid() != tgid) 2414 return -ESRCH; 2415 2416 if (sig == OS::TGT_SIGABRT) 2417 exitGroupFunc(desc, 252, process, tc); 2418 2419 return 0; 2420} 2421 2422template <class OS> 2423SyscallReturn 2424socketFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 2425{ 2426 int index = 0; 2427 int domain = p->getSyscallArg(tc, index); 2428 int type = p->getSyscallArg(tc, index); 2429 int prot = p->getSyscallArg(tc, index); 2430 2431 int sim_fd = socket(domain, type, prot); 2432 if (sim_fd == -1) 2433 return -errno; 2434 2435 auto sfdp = std::make_shared<SocketFDEntry>(sim_fd, domain, type, prot); 2436 int tgt_fd = p->fds->allocFD(sfdp); 2437 2438 return tgt_fd; 2439} 2440 2441template <class OS> 2442SyscallReturn 2443socketpairFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 2444{ 2445 int index = 0; 2446 int domain = p->getSyscallArg(tc, index); 2447 int type = p->getSyscallArg(tc, index); 2448 int prot = p->getSyscallArg(tc, index); 2449 Addr svPtr = p->getSyscallArg(tc, index); 2450 2451 BufferArg svBuf((Addr)svPtr, 2 * sizeof(int)); 2452 int status = socketpair(domain, type, prot, (int *)svBuf.bufferPtr()); 2453 if (status == -1) 2454 return -errno; 2455 2456 int *fds = (int *)svBuf.bufferPtr(); 2457 2458 auto sfdp1 = std::make_shared<SocketFDEntry>(fds[0], domain, type, prot); 2459 fds[0] = p->fds->allocFD(sfdp1); 2460 auto sfdp2 = std::make_shared<SocketFDEntry>(fds[1], domain, type, prot); 2461 fds[1] = p->fds->allocFD(sfdp2); 2462 svBuf.copyOut(tc->getMemProxy()); 2463 2464 return status; 2465} 2466 2467template <class OS> 2468SyscallReturn 2469selectFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 2470{ 2471 int retval; 2472 2473 int index = 0; 2474 int nfds_t = p->getSyscallArg(tc, index); 2475 Addr fds_read_ptr = p->getSyscallArg(tc, index); 2476 Addr fds_writ_ptr = p->getSyscallArg(tc, index); 2477 Addr fds_excp_ptr = p->getSyscallArg(tc, index); 2478 Addr time_val_ptr = p->getSyscallArg(tc, index); 2479 2480 TypedBufferArg<typename OS::fd_set> rd_t(fds_read_ptr); 2481 TypedBufferArg<typename OS::fd_set> wr_t(fds_writ_ptr); 2482 TypedBufferArg<typename OS::fd_set> ex_t(fds_excp_ptr); 2483 TypedBufferArg<typename OS::timeval> tp(time_val_ptr); 2484 2485 /** 2486 * Host fields. Notice that these use the definitions from the system 2487 * headers instead of the gem5 headers and libraries. If the host and 2488 * target have different header file definitions, this will not work. 2489 */ 2490 fd_set rd_h; 2491 FD_ZERO(&rd_h); 2492 fd_set wr_h; 2493 FD_ZERO(&wr_h); 2494 fd_set ex_h; 2495 FD_ZERO(&ex_h); 2496 2497 /** 2498 * Copy in the fd_set from the target. 2499 */ 2500 if (fds_read_ptr) 2501 rd_t.copyIn(tc->getMemProxy()); 2502 if (fds_writ_ptr) 2503 wr_t.copyIn(tc->getMemProxy()); 2504 if (fds_excp_ptr) 2505 ex_t.copyIn(tc->getMemProxy()); 2506 2507 /** 2508 * We need to translate the target file descriptor set into a host file 2509 * descriptor set. This involves both our internal process fd array 2510 * and the fd_set defined in Linux header files. The nfds field also 2511 * needs to be updated as it will be only target specific after 2512 * retrieving it from the target; the nfds value is expected to be the 2513 * highest file descriptor that needs to be checked, so we need to extend 2514 * it out for nfds_h when we do the update. 2515 */ 2516 int nfds_h = 0; 2517 std::map<int, int> trans_map; 2518 auto try_add_host_set = [&](fd_set *tgt_set_entry, 2519 fd_set *hst_set_entry, 2520 int iter) -> bool 2521 { 2522 /** 2523 * By this point, we know that we are looking at a valid file 2524 * descriptor set on the target. We need to check if the target file 2525 * descriptor value passed in as iter is part of the set. 2526 */ 2527 if (FD_ISSET(iter, tgt_set_entry)) { 2528 /** 2529 * We know that the target file descriptor belongs to the set, 2530 * but we do not yet know if the file descriptor is valid or 2531 * that we have a host mapping. Check that now. 2532 */ 2533 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[iter]); 2534 if (!hbfdp) 2535 return true; 2536 auto sim_fd = hbfdp->getSimFD(); 2537 2538 /** 2539 * Add the sim_fd to tgt_fd translation into trans_map for use 2540 * later when we need to zero the target fd_set structures and 2541 * then update them with hits returned from the host select call. 2542 */ 2543 trans_map[sim_fd] = iter; 2544 2545 /** 2546 * We know that the host file descriptor exists so now we check 2547 * if we need to update the max count for nfds_h before passing 2548 * the duplicated structure into the host. 2549 */ 2550 nfds_h = std::max(nfds_h - 1, sim_fd + 1); 2551 2552 /** 2553 * Add the host file descriptor to the set that we are going to 2554 * pass into the host. 2555 */ 2556 FD_SET(sim_fd, hst_set_entry); 2557 } 2558 return false; 2559 }; 2560 2561 for (int i = 0; i < nfds_t; i++) { 2562 if (fds_read_ptr) { 2563 bool ebadf = try_add_host_set((fd_set*)&*rd_t, &rd_h, i); 2564 if (ebadf) return -EBADF; 2565 } 2566 if (fds_writ_ptr) { 2567 bool ebadf = try_add_host_set((fd_set*)&*wr_t, &wr_h, i); 2568 if (ebadf) return -EBADF; 2569 } 2570 if (fds_excp_ptr) { 2571 bool ebadf = try_add_host_set((fd_set*)&*ex_t, &ex_h, i); 2572 if (ebadf) return -EBADF; 2573 } 2574 } 2575 2576 if (time_val_ptr) { 2577 /** 2578 * It might be possible to decrement the timeval based on some 2579 * derivation of wall clock determined from elapsed simulator ticks 2580 * but that seems like overkill. Rather, we just set the timeval with 2581 * zero timeout. (There is no reason to block during the simulation 2582 * as it only decreases simulator performance.) 2583 */ 2584 tp->tv_sec = 0; 2585 tp->tv_usec = 0; 2586 2587 retval = select(nfds_h, 2588 fds_read_ptr ? &rd_h : nullptr, 2589 fds_writ_ptr ? &wr_h : nullptr, 2590 fds_excp_ptr ? &ex_h : nullptr, 2591 (timeval*)&*tp); 2592 } else { 2593 /** 2594 * If the timeval pointer is null, setup a new timeval structure to 2595 * pass into the host select call. Unfortunately, we will need to 2596 * manually check the return value and throw a retry fault if the 2597 * return value is zero. Allowing the system call to block will 2598 * likely deadlock the event queue. 2599 */ 2600 struct timeval tv = { 0, 0 }; 2601 2602 retval = select(nfds_h, 2603 fds_read_ptr ? &rd_h : nullptr, 2604 fds_writ_ptr ? &wr_h : nullptr, 2605 fds_excp_ptr ? &ex_h : nullptr, 2606 &tv); 2607 2608 if (retval == 0) { 2609 /** 2610 * If blocking indefinitely, check the signal list to see if a 2611 * signal would break the poll out of the retry cycle and try to 2612 * return the signal interrupt instead. 2613 */ 2614 for (auto sig : tc->getSystemPtr()->signalList) 2615 if (sig.receiver == p) 2616 return -EINTR; 2617 return SyscallReturn::retry(); 2618 } 2619 } 2620 2621 if (retval == -1) 2622 return -errno; 2623 2624 FD_ZERO((fd_set*)&*rd_t); 2625 FD_ZERO((fd_set*)&*wr_t); 2626 FD_ZERO((fd_set*)&*ex_t); 2627 2628 /** 2629 * We need to translate the host file descriptor set into a target file 2630 * descriptor set. This involves both our internal process fd array 2631 * and the fd_set defined in header files. 2632 */ 2633 for (int i = 0; i < nfds_h; i++) { 2634 if (fds_read_ptr) { 2635 if (FD_ISSET(i, &rd_h)) 2636 FD_SET(trans_map[i], (fd_set*)&*rd_t); 2637 } 2638 2639 if (fds_writ_ptr) { 2640 if (FD_ISSET(i, &wr_h)) 2641 FD_SET(trans_map[i], (fd_set*)&*wr_t); 2642 } 2643 2644 if (fds_excp_ptr) { 2645 if (FD_ISSET(i, &ex_h)) 2646 FD_SET(trans_map[i], (fd_set*)&*ex_t); 2647 } 2648 } 2649 2650 if (fds_read_ptr) 2651 rd_t.copyOut(tc->getMemProxy()); 2652 if (fds_writ_ptr) 2653 wr_t.copyOut(tc->getMemProxy()); 2654 if (fds_excp_ptr) 2655 ex_t.copyOut(tc->getMemProxy()); 2656 if (time_val_ptr) 2657 tp.copyOut(tc->getMemProxy()); 2658 2659 return retval; 2660} 2661 2662template <class OS> 2663SyscallReturn 2664readFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 2665{ 2666 int index = 0; 2667 int tgt_fd = p->getSyscallArg(tc, index); 2668 Addr buf_ptr = p->getSyscallArg(tc, index); 2669 int nbytes = p->getSyscallArg(tc, index); 2670 2671 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 2672 if (!hbfdp) 2673 return -EBADF; 2674 int sim_fd = hbfdp->getSimFD(); 2675 2676 struct pollfd pfd; 2677 pfd.fd = sim_fd; 2678 pfd.events = POLLIN | POLLPRI; 2679 if ((poll(&pfd, 1, 0) == 0) 2680 && !(hbfdp->getFlags() & OS::TGT_O_NONBLOCK)) 2681 return SyscallReturn::retry(); 2682 2683 BufferArg buf_arg(buf_ptr, nbytes); 2684 int bytes_read = read(sim_fd, buf_arg.bufferPtr(), nbytes); 2685 2686 if (bytes_read > 0) 2687 buf_arg.copyOut(tc->getMemProxy()); 2688 2689 return (bytes_read == -1) ? -errno : bytes_read; 2690} 2691 2692template <class OS> 2693SyscallReturn 2694writeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 2695{ 2696 int index = 0; 2697 int tgt_fd = p->getSyscallArg(tc, index); 2698 Addr buf_ptr = p->getSyscallArg(tc, index); 2699 int nbytes = p->getSyscallArg(tc, index); 2700 2701 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 2702 if (!hbfdp) 2703 return -EBADF; 2704 int sim_fd = hbfdp->getSimFD(); 2705 2706 BufferArg buf_arg(buf_ptr, nbytes); 2707 buf_arg.copyIn(tc->getMemProxy()); 2708 2709 struct pollfd pfd; 2710 pfd.fd = sim_fd; 2711 pfd.events = POLLOUT; 2712 2713 /** 2714 * We don't want to poll on /dev/random. The kernel will not enable the 2715 * file descriptor for writing unless the entropy in the system falls 2716 * below write_wakeup_threshold. This is not guaranteed to happen 2717 * depending on host settings. 2718 */ 2719 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(hbfdp); 2720 if (ffdp && (ffdp->getFileName() != "/dev/random")) { 2721 if (!poll(&pfd, 1, 0) && !(ffdp->getFlags() & OS::TGT_O_NONBLOCK)) 2722 return SyscallReturn::retry(); 2723 } 2724 2725 int bytes_written = write(sim_fd, buf_arg.bufferPtr(), nbytes); 2726 2727 if (bytes_written != -1) 2728 fsync(sim_fd); 2729 2730 return (bytes_written == -1) ? -errno : bytes_written; 2731} 2732 2733template <class OS> 2734SyscallReturn 2735wait4Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 2736{ 2737 int index = 0; 2738 pid_t pid = p->getSyscallArg(tc, index); 2739 Addr statPtr = p->getSyscallArg(tc, index); 2740 int options = p->getSyscallArg(tc, index); 2741 Addr rusagePtr = p->getSyscallArg(tc, index); 2742 2743 if (rusagePtr) 2744 DPRINTFR(SyscallVerbose, 2745 "%d: %s: syscall wait4: rusage pointer provided however " 2746 "functionality not supported. Ignoring rusage pointer.\n", 2747 curTick(), tc->getCpuPtr()->name()); 2748 2749 /** 2750 * Currently, wait4 is only implemented so that it will wait for children 2751 * exit conditions which are denoted by a SIGCHLD signals posted into the 2752 * system signal list. We return no additional information via any of the 2753 * parameters supplied to wait4. If nothing is found in the system signal 2754 * list, we will wait indefinitely for SIGCHLD to post by retrying the 2755 * call. 2756 */ 2757 System *sysh = tc->getSystemPtr(); 2758 std::list<BasicSignal>::iterator iter; 2759 for (iter=sysh->signalList.begin(); iter!=sysh->signalList.end(); iter++) { 2760 if (iter->receiver == p) { 2761 if (pid < -1) { 2762 if ((iter->sender->pgid() == -pid) 2763 && (iter->signalValue == OS::TGT_SIGCHLD)) 2764 goto success; 2765 } else if (pid == -1) { 2766 if (iter->signalValue == OS::TGT_SIGCHLD) 2767 goto success; 2768 } else if (pid == 0) { 2769 if ((iter->sender->pgid() == p->pgid()) 2770 && (iter->signalValue == OS::TGT_SIGCHLD)) 2771 goto success; 2772 } else { 2773 if ((iter->sender->pid() == pid) 2774 && (iter->signalValue == OS::TGT_SIGCHLD)) 2775 goto success; 2776 } 2777 } 2778 } 2779 2780 return (options & OS::TGT_WNOHANG) ? 0 : SyscallReturn::retry(); 2781 2782success: 2783 // Set status to EXITED for WIFEXITED evaluations. 2784 const int EXITED = 0; 2785 BufferArg statusBuf(statPtr, sizeof(int)); 2786 *(int *)statusBuf.bufferPtr() = EXITED; 2787 statusBuf.copyOut(tc->getMemProxy()); 2788 2789 // Return the child PID. 2790 pid_t retval = iter->sender->pid(); 2791 sysh->signalList.erase(iter); 2792 return retval; 2793} 2794 2795template <class OS> 2796SyscallReturn 2797acceptFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 2798{ 2799 struct sockaddr sa; 2800 socklen_t addrLen; 2801 int host_fd; 2802 int index = 0; 2803 int tgt_fd = p->getSyscallArg(tc, index); 2804 Addr addrPtr = p->getSyscallArg(tc, index); 2805 Addr lenPtr = p->getSyscallArg(tc, index); 2806 2807 BufferArg *lenBufPtr = nullptr; 2808 BufferArg *addrBufPtr = nullptr; 2809 2810 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 2811 if (!sfdp) 2812 return -EBADF; 2813 int sim_fd = sfdp->getSimFD(); 2814 2815 /** 2816 * We poll the socket file descriptor first to guarantee that we do not 2817 * block on our accept call. The socket can be opened without the 2818 * non-blocking flag (it blocks). This will cause deadlocks between 2819 * communicating processes. 2820 */ 2821 struct pollfd pfd; 2822 pfd.fd = sim_fd; 2823 pfd.events = POLLIN | POLLPRI; 2824 if ((poll(&pfd, 1, 0) == 0) 2825 && !(sfdp->getFlags() & OS::TGT_O_NONBLOCK)) 2826 return SyscallReturn::retry(); 2827 2828 if (lenPtr) { 2829 lenBufPtr = new BufferArg(lenPtr, sizeof(socklen_t)); 2830 lenBufPtr->copyIn(tc->getMemProxy()); 2831 memcpy(&addrLen, (socklen_t *)lenBufPtr->bufferPtr(), 2832 sizeof(socklen_t)); 2833 } 2834 2835 if (addrPtr) { 2836 addrBufPtr = new BufferArg(addrPtr, sizeof(struct sockaddr)); 2837 addrBufPtr->copyIn(tc->getMemProxy()); 2838 memcpy(&sa, (struct sockaddr *)addrBufPtr->bufferPtr(), 2839 sizeof(struct sockaddr)); 2840 } 2841 2842 host_fd = accept(sim_fd, &sa, &addrLen); 2843 2844 if (host_fd == -1) 2845 return -errno; 2846 2847 if (addrPtr) { 2848 memcpy(addrBufPtr->bufferPtr(), &sa, sizeof(sa)); 2849 addrBufPtr->copyOut(tc->getMemProxy()); 2850 delete(addrBufPtr); 2851 } 2852 2853 if (lenPtr) { 2854 *(socklen_t *)lenBufPtr->bufferPtr() = addrLen; 2855 lenBufPtr->copyOut(tc->getMemProxy()); 2856 delete(lenBufPtr); 2857 } 2858 2859 auto afdp = std::make_shared<SocketFDEntry>(host_fd, sfdp->_domain, 2860 sfdp->_type, sfdp->_protocol); 2861 return p->fds->allocFD(afdp); 2862} 2863 2864#endif // __SIM_SYSCALL_EMUL_HH__ 2865