syscall_emul.hh revision 14010
16167SN/A/* 26167SN/A * Copyright (c) 2012-2013, 2015 ARM Limited 36167SN/A * Copyright (c) 2015 Advanced Micro Devices, Inc. 410036SAli.Saidi@ARM.com * All rights reserved 58835SAli.Saidi@ARM.com * 610036SAli.Saidi@ARM.com * The license below extends only to copyright in the software and shall 77935SN/A * not be construed as granting a license to any other intellectual 87935SN/A * property including but not limited to intellectual property relating 97935SN/A * to a hardware implementation of the functionality of the software 106167SN/A * licensed hereunder. You may use the software subject to the license 116167SN/A * terms below provided that you ensure that this notice is replicated 126167SN/A * unmodified and in its entirety in all distributions of the software, 1310526Snilay@cs.wisc.edu * modified or unmodified, in source code or in binary form. 148835SAli.Saidi@ARM.com * 159864Snilay@cs.wisc.edu * Copyright (c) 2003-2005 The Regents of The University of Michigan 169864Snilay@cs.wisc.edu * All rights reserved. 1710036SAli.Saidi@ARM.com * 188835SAli.Saidi@ARM.com * Redistribution and use in source and binary forms, with or without 198835SAli.Saidi@ARM.com * modification, are permitted provided that the following conditions are 2010315Snilay@cs.wisc.edu * met: redistributions of source code must retain the above copyright 218835SAli.Saidi@ARM.com * notice, this list of conditions and the following disclaimer; 2210093Snilay@cs.wisc.edu * redistributions in binary form must reproduce the above copyright 237935SN/A * notice, this list of conditions and the following disclaimer in the 249864Snilay@cs.wisc.edu * documentation and/or other materials provided with the distribution; 2510526Snilay@cs.wisc.edu * neither the name of the copyright holders nor the names of its 2610736Snilay@cs.wisc.edu * contributors may be used to endorse or promote products derived from 278721SN/A * this software without specific prior written permission. 288835SAli.Saidi@ARM.com * 298835SAli.Saidi@ARM.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 307935SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 317935SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 327935SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 337935SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 347935SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 357935SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 367935SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 378983Snate@binkert.org * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 386167SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 399864Snilay@cs.wisc.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 409864Snilay@cs.wisc.edu * 419864Snilay@cs.wisc.edu * Authors: Steve Reinhardt 4210315Snilay@cs.wisc.edu * Kevin Lim 4310036SAli.Saidi@ARM.com */ 4410315Snilay@cs.wisc.edu 459864Snilay@cs.wisc.edu#ifndef __SIM_SYSCALL_EMUL_HH__ 469864Snilay@cs.wisc.edu#define __SIM_SYSCALL_EMUL_HH__ 476167SN/A 486167SN/A#if (defined(__APPLE__) || defined(__OpenBSD__) || \ 499864Snilay@cs.wisc.edu defined(__FreeBSD__) || defined(__CYGWIN__) || \ 5010093Snilay@cs.wisc.edu defined(__NetBSD__)) 516167SN/A#define NO_STAT64 1 529864Snilay@cs.wisc.edu#else 536167SN/A#define NO_STAT64 0 546167SN/A#endif 558835SAli.Saidi@ARM.com 566167SN/A/// 576167SN/A/// @file syscall_emul.hh 5810036SAli.Saidi@ARM.com/// 596167SN/A/// This file defines objects used to emulate syscalls from the target 606167SN/A/// application on the host machine. 618835SAli.Saidi@ARM.com 629469Snilay@cs.wisc.edu#if defined(__linux__) 636167SN/A#include <sys/eventfd.h> 646167SN/A#include <sys/statfs.h> 656167SN/A 666167SN/A#else 676167SN/A#include <sys/mount.h> 686167SN/A 698835SAli.Saidi@ARM.com#endif 706167SN/A 719864Snilay@cs.wisc.edu#ifdef __CYGWIN32__ 7210229Snilay@cs.wisc.edu#include <sys/fcntl.h> 739469Snilay@cs.wisc.edu 746167SN/A#endif 756167SN/A#include <fcntl.h> 766167SN/A#include <net/if.h> 779469Snilay@cs.wisc.edu#include <poll.h> 789469Snilay@cs.wisc.edu#include <sys/ioctl.h> 796167SN/A#include <sys/mman.h> 809864Snilay@cs.wisc.edu#include <sys/socket.h> 819864Snilay@cs.wisc.edu#include <sys/stat.h> 829864Snilay@cs.wisc.edu#include <sys/time.h> 8310315Snilay@cs.wisc.edu#include <sys/types.h> 8410036SAli.Saidi@ARM.com#include <sys/uio.h> 8510315Snilay@cs.wisc.edu#include <unistd.h> 869864Snilay@cs.wisc.edu 879864Snilay@cs.wisc.edu#include <cerrno> 886167SN/A#include <memory> 896167SN/A#include <string> 9010036SAli.Saidi@ARM.com 916167SN/A#include "arch/generic/tlb.hh" 926167SN/A#include "arch/utility.hh" 938835SAli.Saidi@ARM.com#include "base/intmath.hh" 948835SAli.Saidi@ARM.com#include "base/loader/object_file.hh" 9510036SAli.Saidi@ARM.com#include "base/logging.hh" 968835SAli.Saidi@ARM.com#include "base/trace.hh" 979469Snilay@cs.wisc.edu#include "base/types.hh" 989469Snilay@cs.wisc.edu#include "config/the_isa.hh" 9910036SAli.Saidi@ARM.com#include "cpu/base.hh" 1009469Snilay@cs.wisc.edu#include "cpu/thread_context.hh" 1019469Snilay@cs.wisc.edu#include "mem/page_table.hh" 10210036SAli.Saidi@ARM.com#include "params/Process.hh" 1039469Snilay@cs.wisc.edu#include "sim/emul_driver.hh" 1046167SN/A#include "sim/futex_map.hh" 1056167SN/A#include "sim/process.hh" 10610036SAli.Saidi@ARM.com#include "sim/syscall_debug_macros.hh" 1076167SN/A#include "sim/syscall_desc.hh" 1086167SN/A#include "sim/syscall_emul_buf.hh" 1096167SN/A#include "sim/syscall_return.hh" 1106167SN/A 11110036SAli.Saidi@ARM.com#if defined(__APPLE__) && defined(__MACH__) && !defined(CMSG_ALIGN) 1126167SN/A#define CMSG_ALIGN(len) (((len) + sizeof(size_t) - 1) & ~(sizeof(size_t) - 1)) 1136167SN/A#endif 1146167SN/A 1156167SN/A////////////////////////////////////////////////////////////////////// 1166167SN/A// 11710736Snilay@cs.wisc.edu// The following emulation functions are generic enough that they 1186167SN/A// don't need to be recompiled for different emulated OS's. They are 1196167SN/A// defined in sim/syscall_emul.cc. 1206167SN/A// 1216167SN/A////////////////////////////////////////////////////////////////////// 12210036SAli.Saidi@ARM.com 12311023Sjthestness@gmail.comvoid warnUnsupportedOS(std::string syscall_name); 1246167SN/A 1256167SN/A/// Handler for unimplemented syscalls that we haven't thought about. 12610736Snilay@cs.wisc.eduSyscallReturn unimplementedFunc(SyscallDesc *desc, int num, ThreadContext *tc); 1276167SN/A 1286167SN/A/// Handler for unimplemented syscalls that we never intend to 1296167SN/A/// implement (signal handling, etc.) and should not affect the correct 1306167SN/A/// behavior of the program. Print a warning only if the appropriate 1316167SN/A/// trace flag is enabled. Return success to the target program. 1326167SN/ASyscallReturn ignoreFunc(SyscallDesc *desc, int num, ThreadContext *tc); 1336167SN/A 13410451Snilay@cs.wisc.edu// Target fallocateFunc() handler. 1356167SN/ASyscallReturn fallocateFunc(SyscallDesc *desc, int num, ThreadContext *tc); 13610315Snilay@cs.wisc.edu 13710315Snilay@cs.wisc.edu/// Target exit() handler: terminate current context. 13810315Snilay@cs.wisc.eduSyscallReturn exitFunc(SyscallDesc *desc, int num, ThreadContext *tc); 13910315Snilay@cs.wisc.edu 14010315Snilay@cs.wisc.edu/// Target exit_group() handler: terminate simulation. (exit all threads) 14110315Snilay@cs.wisc.eduSyscallReturn exitGroupFunc(SyscallDesc *desc, int num, ThreadContext *tc); 14210315Snilay@cs.wisc.edu 14310315Snilay@cs.wisc.edu/// Target set_tid_address() handler. 14410526Snilay@cs.wisc.eduSyscallReturn setTidAddressFunc(SyscallDesc *desc, int num, ThreadContext *tc); 14510526Snilay@cs.wisc.edu 14610526Snilay@cs.wisc.edu/// Target getpagesize() handler. 14710526Snilay@cs.wisc.eduSyscallReturn getpagesizeFunc(SyscallDesc *desc, int num, ThreadContext *tc); 14810526Snilay@cs.wisc.edu 14910526Snilay@cs.wisc.edu/// Target brk() handler: set brk address. 15010526Snilay@cs.wisc.eduSyscallReturn brkFunc(SyscallDesc *desc, int num, ThreadContext *tc); 15110526Snilay@cs.wisc.edu 15210526Snilay@cs.wisc.edu/// Target close() handler. 15310526Snilay@cs.wisc.eduSyscallReturn closeFunc(SyscallDesc *desc, int num, ThreadContext *tc); 15410526Snilay@cs.wisc.edu 15510526Snilay@cs.wisc.edu/// Target lseek() handler. 15610526Snilay@cs.wisc.eduSyscallReturn lseekFunc(SyscallDesc *desc, int num, ThreadContext *tc); 15710526Snilay@cs.wisc.edu 15810526Snilay@cs.wisc.edu/// Target _llseek() handler. 15910526Snilay@cs.wisc.eduSyscallReturn _llseekFunc(SyscallDesc *desc, int num, ThreadContext *tc); 16010526Snilay@cs.wisc.edu 16110526Snilay@cs.wisc.edu/// Target munmap() handler. 16210526Snilay@cs.wisc.eduSyscallReturn munmapFunc(SyscallDesc *desc, int num, ThreadContext *tc); 16310526Snilay@cs.wisc.edu 16410526Snilay@cs.wisc.edu/// Target shutdown() handler. 16510526Snilay@cs.wisc.eduSyscallReturn shutdownFunc(SyscallDesc *desc, int num, ThreadContext *tc); 16610526Snilay@cs.wisc.edu 16710526Snilay@cs.wisc.edu/// Target gethostname() handler. 16810526Snilay@cs.wisc.eduSyscallReturn gethostnameFunc(SyscallDesc *desc, int num, ThreadContext *tc); 16910526Snilay@cs.wisc.edu 17010526Snilay@cs.wisc.edu/// Target getcwd() handler. 17110736Snilay@cs.wisc.eduSyscallReturn getcwdFunc(SyscallDesc *desc, int num, ThreadContext *tc); 17210526Snilay@cs.wisc.edu 17310526Snilay@cs.wisc.edu/// Target readlink() handler. 17410526Snilay@cs.wisc.eduSyscallReturn readlinkFunc(SyscallDesc *desc, int num, ThreadContext *tc, 17510526Snilay@cs.wisc.edu int index = 0); 1769864Snilay@cs.wisc.eduSyscallReturn readlinkFunc(SyscallDesc *desc, int num, ThreadContext *tc); 1779864Snilay@cs.wisc.edu 17810526Snilay@cs.wisc.edu/// Target unlink() handler. 17910526Snilay@cs.wisc.eduSyscallReturn unlinkHelper(SyscallDesc *desc, int num, ThreadContext *tc, 18010526Snilay@cs.wisc.edu int index); 18110526Snilay@cs.wisc.eduSyscallReturn unlinkFunc(SyscallDesc *desc, int num, ThreadContext *tc); 18210526Snilay@cs.wisc.edu 18310036SAli.Saidi@ARM.com/// Target link() handler 1849469Snilay@cs.wisc.eduSyscallReturn linkFunc(SyscallDesc *desc, int num, ThreadContext *tc); 18510526Snilay@cs.wisc.edu 18610526Snilay@cs.wisc.edu/// Target symlink() handler. 18710526Snilay@cs.wisc.eduSyscallReturn symlinkFunc(SyscallDesc *desc, int num, ThreadContext *tc); 18810526Snilay@cs.wisc.edu 18910526Snilay@cs.wisc.edu/// Target mkdir() handler. 19010526Snilay@cs.wisc.eduSyscallReturn mkdirFunc(SyscallDesc *desc, int num, ThreadContext *tc); 19110526Snilay@cs.wisc.edu 19210526Snilay@cs.wisc.edu/// Target mknod() handler. 19310526Snilay@cs.wisc.eduSyscallReturn mknodFunc(SyscallDesc *desc, int num, ThreadContext *tc); 19410526Snilay@cs.wisc.edu 19510526Snilay@cs.wisc.edu/// Target chdir() handler. 19610526Snilay@cs.wisc.eduSyscallReturn chdirFunc(SyscallDesc *desc, int num, ThreadContext *tc); 19710526Snilay@cs.wisc.edu 19810526Snilay@cs.wisc.edu// Target rmdir() handler. 19910526Snilay@cs.wisc.eduSyscallReturn rmdirFunc(SyscallDesc *desc, int num, ThreadContext *tc); 20010526Snilay@cs.wisc.edu 20110526Snilay@cs.wisc.edu/// Target rename() handler. 20210526Snilay@cs.wisc.eduSyscallReturn renameFunc(SyscallDesc *desc, int num, ThreadContext *tc); 20310526Snilay@cs.wisc.edu 20410526Snilay@cs.wisc.edu 20510526Snilay@cs.wisc.edu/// Target truncate() handler. 20610526Snilay@cs.wisc.eduSyscallReturn truncateFunc(SyscallDesc *desc, int num, ThreadContext *tc); 20710526Snilay@cs.wisc.edu 20810526Snilay@cs.wisc.edu 20910526Snilay@cs.wisc.edu/// Target ftruncate() handler. 21010526Snilay@cs.wisc.eduSyscallReturn ftruncateFunc(SyscallDesc *desc, int num, ThreadContext *tc); 21110526Snilay@cs.wisc.edu 21210526Snilay@cs.wisc.edu 21310526Snilay@cs.wisc.edu/// Target truncate64() handler. 21410526Snilay@cs.wisc.eduSyscallReturn truncate64Func(SyscallDesc *desc, int num, ThreadContext *tc); 21510526Snilay@cs.wisc.edu 21610526Snilay@cs.wisc.edu/// Target ftruncate64() handler. 21710526Snilay@cs.wisc.eduSyscallReturn ftruncate64Func(SyscallDesc *desc, int num, ThreadContext *tc); 21810526Snilay@cs.wisc.edu 21910526Snilay@cs.wisc.edu 2209469Snilay@cs.wisc.edu/// Target umask() handler. 2219469Snilay@cs.wisc.eduSyscallReturn umaskFunc(SyscallDesc *desc, int num, ThreadContext *tc); 2229469Snilay@cs.wisc.edu 22310036SAli.Saidi@ARM.com/// Target gettid() handler. 22410736Snilay@cs.wisc.eduSyscallReturn gettidFunc(SyscallDesc *desc, int num, ThreadContext *tc); 22510036SAli.Saidi@ARM.com 2269469Snilay@cs.wisc.edu/// Target chown() handler. 2279864Snilay@cs.wisc.eduSyscallReturn chownFunc(SyscallDesc *desc, int num, ThreadContext *tc); 22810036SAli.Saidi@ARM.com 22910036SAli.Saidi@ARM.com/// Target setpgid() handler. 23010526Snilay@cs.wisc.eduSyscallReturn setpgidFunc(SyscallDesc *desc, int num, ThreadContext *tc); 23110036SAli.Saidi@ARM.com 23210526Snilay@cs.wisc.edu/// Target fchown() handler. 2339469Snilay@cs.wisc.eduSyscallReturn fchownFunc(SyscallDesc *desc, int num, ThreadContext *tc); 2349469Snilay@cs.wisc.edu 2359469Snilay@cs.wisc.edu/// Target dup() handler. 2369864Snilay@cs.wisc.eduSyscallReturn dupFunc(SyscallDesc *desc, int num, ThreadContext *tc); 2379864Snilay@cs.wisc.edu 2389864Snilay@cs.wisc.edu/// Target dup2() handler. 23910315Snilay@cs.wisc.eduSyscallReturn dup2Func(SyscallDesc *desc, int num, ThreadContext *tc); 24010036SAli.Saidi@ARM.com 24110315Snilay@cs.wisc.edu/// Target fcntl() handler. 2429864Snilay@cs.wisc.eduSyscallReturn fcntlFunc(SyscallDesc *desc, int num, ThreadContext *tc); 2439864Snilay@cs.wisc.edu 2449469Snilay@cs.wisc.edu/// Target fcntl64() handler. 2456928SN/ASyscallReturn fcntl64Func(SyscallDesc *desc, int num, ThreadContext *tc); 24611023Sjthestness@gmail.com 2476928SN/A/// Target setuid() handler. 2489864Snilay@cs.wisc.eduSyscallReturn setuidFunc(SyscallDesc *desc, int num, ThreadContext *tc); 24910036SAli.Saidi@ARM.com 2509469Snilay@cs.wisc.edu/// Target pipe() handler. 2516928SN/ASyscallReturn pipeFunc(SyscallDesc *desc, int num, ThreadContext *tc); 25211023Sjthestness@gmail.com 25311023Sjthestness@gmail.com/// Internal pipe() handler. 25410036SAli.Saidi@ARM.comSyscallReturn pipeImpl(SyscallDesc *desc, int num, ThreadContext *tc, 25511023Sjthestness@gmail.com bool pseudoPipe); 2566928SN/A 2576928SN/A/// Target getpid() handler. 25811023Sjthestness@gmail.comSyscallReturn getpidFunc(SyscallDesc *desc, int num, ThreadContext *tc); 25911023Sjthestness@gmail.com 26011023Sjthestness@gmail.com// Target getpeername() handler. 2618540SN/ASyscallReturn getpeernameFunc(SyscallDesc *desc, int num, ThreadContext *tc); 26210526Snilay@cs.wisc.edu 26310526Snilay@cs.wisc.edu// Target bind() handler. 2649864Snilay@cs.wisc.eduSyscallReturn bindFunc(SyscallDesc *desc, int num, ThreadContext *tc); 2656928SN/A 26610526Snilay@cs.wisc.edu// Target listen() handler. 2676928SN/ASyscallReturn listenFunc(SyscallDesc *desc, int num, ThreadContext *tc); 2689469Snilay@cs.wisc.edu 2696928SN/A// Target connect() handler. 27010036SAli.Saidi@ARM.comSyscallReturn connectFunc(SyscallDesc *desc, int num, ThreadContext *tc); 2719469Snilay@cs.wisc.edu 2729864Snilay@cs.wisc.edu#if defined(SYS_getdents) 2736928SN/A// Target getdents() handler. 2746928SN/ASyscallReturn getdentsFunc(SyscallDesc *desc, int num, ThreadContext *tc); 27511023Sjthestness@gmail.com#endif 27611023Sjthestness@gmail.com 27711023Sjthestness@gmail.com#if defined(SYS_getdents64) 27811023Sjthestness@gmail.com// Target getdents() handler. 27911023Sjthestness@gmail.comSyscallReturn getdents64Func(SyscallDesc *desc, int num, ThreadContext *tc); 28011023Sjthestness@gmail.com#endif 28111023Sjthestness@gmail.com 28211023Sjthestness@gmail.com// Target sendto() handler. 28311023Sjthestness@gmail.comSyscallReturn sendtoFunc(SyscallDesc *desc, int num, ThreadContext *tc); 28411023Sjthestness@gmail.com 28511023Sjthestness@gmail.com// Target recvfrom() handler. 28611023Sjthestness@gmail.comSyscallReturn recvfromFunc(SyscallDesc *desc, int num, ThreadContext *tc); 28711023Sjthestness@gmail.com 28811023Sjthestness@gmail.com// Target recvmsg() handler. 28911023Sjthestness@gmail.comSyscallReturn recvmsgFunc(SyscallDesc *desc, int num, ThreadContext *tc); 29011023Sjthestness@gmail.com 29111023Sjthestness@gmail.com// Target sendmsg() handler. 29211023Sjthestness@gmail.comSyscallReturn sendmsgFunc(SyscallDesc *desc, int num, ThreadContext *tc); 29311023Sjthestness@gmail.com 29411023Sjthestness@gmail.com// Target getuid() handler. 29511023Sjthestness@gmail.comSyscallReturn getuidFunc(SyscallDesc *desc, int num, ThreadContext *tc); 29611023Sjthestness@gmail.com 29711023Sjthestness@gmail.com/// Target getgid() handler. 29811023Sjthestness@gmail.comSyscallReturn getgidFunc(SyscallDesc *desc, int num, ThreadContext *tc); 29911023Sjthestness@gmail.com 30011023Sjthestness@gmail.com/// Target getppid() handler. 30111023Sjthestness@gmail.comSyscallReturn getppidFunc(SyscallDesc *desc, int num, ThreadContext *tc); 30211023Sjthestness@gmail.com 30311023Sjthestness@gmail.com/// Target geteuid() handler. 30411023Sjthestness@gmail.comSyscallReturn geteuidFunc(SyscallDesc *desc, int num, ThreadContext *tc); 30511023Sjthestness@gmail.com 30611023Sjthestness@gmail.com/// Target getegid() handler. 30711023Sjthestness@gmail.comSyscallReturn getegidFunc(SyscallDesc *desc, int num, ThreadContext *tc); 30811023Sjthestness@gmail.com 30911023Sjthestness@gmail.com/// Target access() handler 31011023Sjthestness@gmail.comSyscallReturn accessFunc(SyscallDesc *desc, int num, ThreadContext *tc); 31111023Sjthestness@gmail.comSyscallReturn accessFunc(SyscallDesc *desc, int num, ThreadContext *tc, 31211023Sjthestness@gmail.com int index); 31311023Sjthestness@gmail.com 31411023Sjthestness@gmail.com// Target getsockopt() handler. 31511023Sjthestness@gmail.comSyscallReturn getsockoptFunc(SyscallDesc *desc, int num, ThreadContext *tc); 31611023Sjthestness@gmail.com 31711023Sjthestness@gmail.com// Target setsockopt() handler. 31811023Sjthestness@gmail.comSyscallReturn setsockoptFunc(SyscallDesc *desc, int num, ThreadContext *tc); 31911023Sjthestness@gmail.com 32011023Sjthestness@gmail.com// Target getsockname() handler. 32111023Sjthestness@gmail.comSyscallReturn getsocknameFunc(SyscallDesc *desc, int num, ThreadContext *tc); 32211023Sjthestness@gmail.com 32311023Sjthestness@gmail.com/// Futex system call 32411023Sjthestness@gmail.com/// Implemented by Daniel Sanchez 32511023Sjthestness@gmail.com/// Used by printf's in multi-threaded apps 32611023Sjthestness@gmail.comtemplate <class OS> 32711023Sjthestness@gmail.comSyscallReturn 3289469Snilay@cs.wisc.edufutexFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 3297935SN/A{ 33011023Sjthestness@gmail.com using namespace std; 3317935SN/A 3329469Snilay@cs.wisc.edu int index = 0; 3337935SN/A auto process = tc->getProcessPtr(); 33410315Snilay@cs.wisc.edu 33510036SAli.Saidi@ARM.com Addr uaddr = process->getSyscallArg(tc, index); 33610036SAli.Saidi@ARM.com int op = process->getSyscallArg(tc, index); 33711023Sjthestness@gmail.com int val = process->getSyscallArg(tc, index); 3387935SN/A int timeout M5_VAR_USED = process->getSyscallArg(tc, index); 33911023Sjthestness@gmail.com Addr uaddr2 M5_VAR_USED = process->getSyscallArg(tc, index); 3407935SN/A int val3 = process->getSyscallArg(tc, index); 3417935SN/A 34211023Sjthestness@gmail.com /* 34311023Sjthestness@gmail.com * Unsupported option that does not affect the correctness of the 34411023Sjthestness@gmail.com * application. This is a performance optimization utilized by Linux. 3458540SN/A */ 3468835SAli.Saidi@ARM.com op &= ~OS::TGT_FUTEX_PRIVATE_FLAG; 3479469Snilay@cs.wisc.edu op &= ~OS::TGT_FUTEX_CLOCK_REALTIME_FLAG; 34810526Snilay@cs.wisc.edu 3499864Snilay@cs.wisc.edu FutexMap &futex_map = tc->getSystemPtr()->futexMap; 3507935SN/A 3517935SN/A if (OS::TGT_FUTEX_WAIT == op || OS::TGT_FUTEX_WAIT_BITSET == op) { 3529469Snilay@cs.wisc.edu // Ensure futex system call accessed atomically. 3538540SN/A BufferArg buf(uaddr, sizeof(int)); 35411023Sjthestness@gmail.com buf.copyIn(tc->getMemProxy()); 3558540SN/A int mem_val = *(int*)buf.bufferPtr(); 3569113SBrad.Beckmann@amd.com 3579113SBrad.Beckmann@amd.com /* 35810036SAli.Saidi@ARM.com * The value in memory at uaddr is not equal with the expected val 3598721SN/A * (a different thread must have changed it before the system call was 36011023Sjthestness@gmail.com * invoked). In this case, we need to throw an error. 3619113SBrad.Beckmann@amd.com */ 36211023Sjthestness@gmail.com if (val != mem_val) 3638540SN/A return -OS::TGT_EWOULDBLOCK; 3648540SN/A 3659113SBrad.Beckmann@amd.com if (OS::TGT_FUTEX_WAIT) { 3669113SBrad.Beckmann@amd.com futex_map.suspend(uaddr, process->tgid(), tc); 3678540SN/A } else { 36811023Sjthestness@gmail.com futex_map.suspend_bitset(uaddr, process->tgid(), tc, val3); 36911023Sjthestness@gmail.com } 37011023Sjthestness@gmail.com 37111023Sjthestness@gmail.com return 0; 37211023Sjthestness@gmail.com } else if (OS::TGT_FUTEX_WAKE == op) { 37311023Sjthestness@gmail.com return futex_map.wakeup(uaddr, process->tgid(), val); 37411023Sjthestness@gmail.com } else if (OS::TGT_FUTEX_WAKE_BITSET == op) { 37511023Sjthestness@gmail.com return futex_map.wakeup_bitset(uaddr, process->tgid(), val3); 37611023Sjthestness@gmail.com } else if (OS::TGT_FUTEX_REQUEUE == op || 37711023Sjthestness@gmail.com OS::TGT_FUTEX_CMP_REQUEUE == op) { 37811023Sjthestness@gmail.com 37911023Sjthestness@gmail.com // Ensure futex system call accessed atomically. 38011023Sjthestness@gmail.com BufferArg buf(uaddr, sizeof(int)); 38111023Sjthestness@gmail.com buf.copyIn(tc->getMemProxy()); 38211023Sjthestness@gmail.com int mem_val = *(int*)buf.bufferPtr(); 38311023Sjthestness@gmail.com /* 38411023Sjthestness@gmail.com * For CMP_REQUEUE, the whole operation is only started only if 38511023Sjthestness@gmail.com * val3 is still the value of the futex pointed to by uaddr. 38611023Sjthestness@gmail.com */ 38711023Sjthestness@gmail.com if (OS::TGT_FUTEX_CMP_REQUEUE && val3 != mem_val) 38811023Sjthestness@gmail.com return -OS::TGT_EWOULDBLOCK; 38911023Sjthestness@gmail.com return futex_map.requeue(uaddr, process->tgid(), val, timeout, uaddr2); 39011023Sjthestness@gmail.com } else if (OS::TGT_FUTEX_WAKE_OP == op) { 39111023Sjthestness@gmail.com /* 39211023Sjthestness@gmail.com * The FUTEX_WAKE_OP operation is equivalent to executing the 39311023Sjthestness@gmail.com * following code atomically and totally ordered with respect to 39411023Sjthestness@gmail.com * other futex operations on any of the two supplied futex words: 39511023Sjthestness@gmail.com * 39611023Sjthestness@gmail.com * int oldval = *(int *) addr2; 39711023Sjthestness@gmail.com * *(int *) addr2 = oldval op oparg; 39811023Sjthestness@gmail.com * futex(addr1, FUTEX_WAKE, val, 0, 0, 0); 39911023Sjthestness@gmail.com * if (oldval cmp cmparg) 40011023Sjthestness@gmail.com * futex(addr2, FUTEX_WAKE, val2, 0, 0, 0); 40111023Sjthestness@gmail.com * 40211023Sjthestness@gmail.com * (op, oparg, cmp, cmparg are encoded in val3) 40311023Sjthestness@gmail.com * 40411023Sjthestness@gmail.com * +---+---+-----------+-----------+ 40511023Sjthestness@gmail.com * |op |cmp| oparg | cmparg | 40611023Sjthestness@gmail.com * +---+---+-----------+-----------+ 40711023Sjthestness@gmail.com * 4 4 12 12 <== # of bits 40811023Sjthestness@gmail.com * 40911023Sjthestness@gmail.com * reference: http://man7.org/linux/man-pages/man2/futex.2.html 41011023Sjthestness@gmail.com * 41111023Sjthestness@gmail.com */ 41211023Sjthestness@gmail.com // get value from simulated-space 41311023Sjthestness@gmail.com BufferArg buf(uaddr2, sizeof(int)); 41411023Sjthestness@gmail.com buf.copyIn(tc->getMemProxy()); 41511023Sjthestness@gmail.com int oldval = *(int*)buf.bufferPtr(); 41611023Sjthestness@gmail.com int newval = oldval; 41711023Sjthestness@gmail.com // extract op, oparg, cmp, cmparg from val3 41811023Sjthestness@gmail.com int wake_cmparg = val3 & 0xfff; 4199469Snilay@cs.wisc.edu int wake_oparg = (val3 & 0xfff000) >> 12; 4208540SN/A int wake_cmp = (val3 & 0xf000000) >> 24; 42110315Snilay@cs.wisc.edu int wake_op = (val3 & 0xf0000000) >> 28; 4229469Snilay@cs.wisc.edu if ((wake_op & OS::TGT_FUTEX_OP_ARG_SHIFT) >> 3 == 1) 42311023Sjthestness@gmail.com wake_oparg = (1 << wake_oparg); 4248540SN/A wake_op &= ~OS::TGT_FUTEX_OP_ARG_SHIFT; 42510036SAli.Saidi@ARM.com // perform operation on the value of the second futex 4269469Snilay@cs.wisc.edu if (wake_op == OS::TGT_FUTEX_OP_SET) 42711023Sjthestness@gmail.com newval = wake_oparg; 4288540SN/A else if (wake_op == OS::TGT_FUTEX_OP_ADD) 4298540SN/A newval += wake_oparg; 4308983Snate@binkert.org else if (wake_op == OS::TGT_FUTEX_OP_OR) 4318983Snate@binkert.org newval |= wake_oparg; 4328983Snate@binkert.org else if (wake_op == OS::TGT_FUTEX_OP_ANDN) 4338540SN/A newval &= ~wake_oparg; 4348540SN/A else if (wake_op == OS::TGT_FUTEX_OP_XOR) 4358540SN/A newval ^= wake_oparg; 4368983Snate@binkert.org // copy updated value back to simulated-space 4378540SN/A *(int*)buf.bufferPtr() = newval; 4389864Snilay@cs.wisc.edu buf.copyOut(tc->getMemProxy()); 4399864Snilay@cs.wisc.edu // perform the first wake-up 4409864Snilay@cs.wisc.edu int woken1 = futex_map.wakeup(uaddr, process->tgid(), val); 4419864Snilay@cs.wisc.edu int woken2 = 0; 44210036SAli.Saidi@ARM.com // calculate the condition of the second wake-up 4439864Snilay@cs.wisc.edu bool is_wake2 = false; 4447935SN/A if (wake_cmp == OS::TGT_FUTEX_OP_CMP_EQ) 4457935SN/A is_wake2 = oldval == wake_cmparg; 44611023Sjthestness@gmail.com else if (wake_cmp == OS::TGT_FUTEX_OP_CMP_NE) 4477935SN/A is_wake2 = oldval != wake_cmparg; 4487935SN/A else if (wake_cmp == OS::TGT_FUTEX_OP_CMP_LT) 4499864Snilay@cs.wisc.edu is_wake2 = oldval < wake_cmparg; 4507935SN/A else if (wake_cmp == OS::TGT_FUTEX_OP_CMP_LE) 4518540SN/A is_wake2 = oldval <= wake_cmparg; 45210036SAli.Saidi@ARM.com else if (wake_cmp == OS::TGT_FUTEX_OP_CMP_GT) 4539605Snilay@cs.wisc.edu is_wake2 = oldval > wake_cmparg; 45411023Sjthestness@gmail.com else if (wake_cmp == OS::TGT_FUTEX_OP_CMP_GE) 4559605Snilay@cs.wisc.edu is_wake2 = oldval >= wake_cmparg; 45610229Snilay@cs.wisc.edu // perform the second wake-up 4577935SN/A if (is_wake2) 45811023Sjthestness@gmail.com woken2 = futex_map.wakeup(uaddr2, process->tgid(), timeout); 4599864Snilay@cs.wisc.edu 4608540SN/A return woken1 + woken2; 4619605Snilay@cs.wisc.edu } 46211023Sjthestness@gmail.com warn("futex: op %d not implemented; ignoring.", op); 46311023Sjthestness@gmail.com return -ENOSYS; 4647935SN/A} 4659605Snilay@cs.wisc.edu 4668540SN/A 4678540SN/A/// Pseudo Funcs - These functions use a different return convension, 46810036SAli.Saidi@ARM.com/// returning a second value in a register other than the normal return register 4699469Snilay@cs.wisc.eduSyscallReturn pipePseudoFunc(SyscallDesc *desc, int num, ThreadContext *tc); 4709864Snilay@cs.wisc.edu 4717935SN/A/// Target getpidPseudo() handler. 4728540SN/ASyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num, ThreadContext *tc); 4737935SN/A 4747935SN/A/// Target getuidPseudo() handler. 4759605Snilay@cs.wisc.eduSyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num, ThreadContext *tc); 4768540SN/A 4778540SN/A/// Target getgidPseudo() handler. 47810036SAli.Saidi@ARM.comSyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num, ThreadContext *tc); 4799469Snilay@cs.wisc.edu 4809864Snilay@cs.wisc.edu 4817935SN/A/// A readable name for 1,000,000, for converting microseconds to seconds. 4828540SN/Aconst int one_million = 1000000; 4837935SN/A/// A readable name for 1,000,000,000, for converting nanoseconds to seconds. 4847935SN/Aconst int one_billion = 1000000000; 48511023Sjthestness@gmail.com 48611023Sjthestness@gmail.com/// Approximate seconds since the epoch (1/1/1970). About a billion, 48711023Sjthestness@gmail.com/// by my reckoning. We want to keep this a constant (not use the 48811023Sjthestness@gmail.com/// real-world time) to keep simulations repeatable. 48911023Sjthestness@gmail.comconst unsigned seconds_since_epoch = 1000000000; 49011023Sjthestness@gmail.com 49111023Sjthestness@gmail.com/// Helper function to convert current elapsed time to seconds and 49211023Sjthestness@gmail.com/// microseconds. 49311023Sjthestness@gmail.comtemplate <class T1, class T2> 49411023Sjthestness@gmail.comvoid 49511023Sjthestness@gmail.comgetElapsedTimeMicro(T1 &sec, T2 &usec) 49611023Sjthestness@gmail.com{ 49711023Sjthestness@gmail.com uint64_t elapsed_usecs = curTick() / SimClock::Int::us; 49811023Sjthestness@gmail.com sec = elapsed_usecs / one_million; 49911023Sjthestness@gmail.com usec = elapsed_usecs % one_million; 50011023Sjthestness@gmail.com} 50111023Sjthestness@gmail.com 50211023Sjthestness@gmail.com/// Helper function to convert current elapsed time to seconds and 50311023Sjthestness@gmail.com/// nanoseconds. 50411023Sjthestness@gmail.comtemplate <class T1, class T2> 50511023Sjthestness@gmail.comvoid 50611023Sjthestness@gmail.comgetElapsedTimeNano(T1 &sec, T2 &nsec) 50711023Sjthestness@gmail.com{ 50811023Sjthestness@gmail.com uint64_t elapsed_nsecs = curTick() / SimClock::Int::ns; 50911023Sjthestness@gmail.com sec = elapsed_nsecs / one_billion; 51011023Sjthestness@gmail.com nsec = elapsed_nsecs % one_billion; 51111023Sjthestness@gmail.com} 51211023Sjthestness@gmail.com 51311023Sjthestness@gmail.com////////////////////////////////////////////////////////////////////// 51411023Sjthestness@gmail.com// 51511023Sjthestness@gmail.com// The following emulation functions are generic, but need to be 51611023Sjthestness@gmail.com// templated to account for differences in types, constants, etc. 51711023Sjthestness@gmail.com// 51811023Sjthestness@gmail.com////////////////////////////////////////////////////////////////////// 51911023Sjthestness@gmail.com 52011023Sjthestness@gmail.com typedef struct statfs hst_statfs; 52111023Sjthestness@gmail.com#if NO_STAT64 52211023Sjthestness@gmail.com typedef struct stat hst_stat; 52311023Sjthestness@gmail.com typedef struct stat hst_stat64; 52411023Sjthestness@gmail.com#else 52511023Sjthestness@gmail.com typedef struct stat hst_stat; 52611023Sjthestness@gmail.com typedef struct stat64 hst_stat64; 52711023Sjthestness@gmail.com#endif 52811023Sjthestness@gmail.com 52911023Sjthestness@gmail.com//// Helper function to convert a host stat buffer to a target stat 53011023Sjthestness@gmail.com//// buffer. Also copies the target buffer out to the simulated 53111023Sjthestness@gmail.com//// memory space. Used by stat(), fstat(), and lstat(). 53211023Sjthestness@gmail.com 53311023Sjthestness@gmail.comtemplate <typename target_stat, typename host_stat> 53411023Sjthestness@gmail.comvoid 53511023Sjthestness@gmail.comconvertStatBuf(target_stat &tgt, host_stat *host, bool fakeTTY = false) 53611023Sjthestness@gmail.com{ 53711023Sjthestness@gmail.com using namespace TheISA; 53811023Sjthestness@gmail.com 53911023Sjthestness@gmail.com if (fakeTTY) 54011023Sjthestness@gmail.com tgt->st_dev = 0xA; 54111023Sjthestness@gmail.com else 54211023Sjthestness@gmail.com tgt->st_dev = host->st_dev; 54311023Sjthestness@gmail.com tgt->st_dev = TheISA::htog(tgt->st_dev); 54411023Sjthestness@gmail.com tgt->st_ino = host->st_ino; 54511023Sjthestness@gmail.com tgt->st_ino = TheISA::htog(tgt->st_ino); 54611023Sjthestness@gmail.com tgt->st_mode = host->st_mode; 54711023Sjthestness@gmail.com if (fakeTTY) { 54811023Sjthestness@gmail.com // Claim to be a character device 54911023Sjthestness@gmail.com tgt->st_mode &= ~S_IFMT; // Clear S_IFMT 55011023Sjthestness@gmail.com tgt->st_mode |= S_IFCHR; // Set S_IFCHR 55111023Sjthestness@gmail.com } 55211023Sjthestness@gmail.com tgt->st_mode = TheISA::htog(tgt->st_mode); 55311023Sjthestness@gmail.com tgt->st_nlink = host->st_nlink; 55411023Sjthestness@gmail.com tgt->st_nlink = TheISA::htog(tgt->st_nlink); 55511023Sjthestness@gmail.com tgt->st_uid = host->st_uid; 55611023Sjthestness@gmail.com tgt->st_uid = TheISA::htog(tgt->st_uid); 55711023Sjthestness@gmail.com tgt->st_gid = host->st_gid; 55811023Sjthestness@gmail.com tgt->st_gid = TheISA::htog(tgt->st_gid); 55911023Sjthestness@gmail.com if (fakeTTY) 56011023Sjthestness@gmail.com tgt->st_rdev = 0x880d; 56111023Sjthestness@gmail.com else 56211023Sjthestness@gmail.com tgt->st_rdev = host->st_rdev; 56311023Sjthestness@gmail.com tgt->st_rdev = TheISA::htog(tgt->st_rdev); 56411023Sjthestness@gmail.com tgt->st_size = host->st_size; 56511023Sjthestness@gmail.com tgt->st_size = TheISA::htog(tgt->st_size); 56611023Sjthestness@gmail.com tgt->st_atimeX = host->st_atime; 56711023Sjthestness@gmail.com tgt->st_atimeX = TheISA::htog(tgt->st_atimeX); 56811023Sjthestness@gmail.com tgt->st_mtimeX = host->st_mtime; 56911023Sjthestness@gmail.com tgt->st_mtimeX = TheISA::htog(tgt->st_mtimeX); 57011023Sjthestness@gmail.com tgt->st_ctimeX = host->st_ctime; 57111023Sjthestness@gmail.com tgt->st_ctimeX = TheISA::htog(tgt->st_ctimeX); 57211023Sjthestness@gmail.com // Force the block size to be 8KB. This helps to ensure buffered io works 57311023Sjthestness@gmail.com // consistently across different hosts. 57411023Sjthestness@gmail.com tgt->st_blksize = 0x2000; 57511023Sjthestness@gmail.com tgt->st_blksize = TheISA::htog(tgt->st_blksize); 57611023Sjthestness@gmail.com tgt->st_blocks = host->st_blocks; 57711023Sjthestness@gmail.com tgt->st_blocks = TheISA::htog(tgt->st_blocks); 57811023Sjthestness@gmail.com} 57911023Sjthestness@gmail.com 58011023Sjthestness@gmail.com// Same for stat64 58111023Sjthestness@gmail.com 58211023Sjthestness@gmail.comtemplate <typename target_stat, typename host_stat64> 58311023Sjthestness@gmail.comvoid 58411023Sjthestness@gmail.comconvertStat64Buf(target_stat &tgt, host_stat64 *host, bool fakeTTY = false) 58511023Sjthestness@gmail.com{ 58611023Sjthestness@gmail.com using namespace TheISA; 58711023Sjthestness@gmail.com 58811023Sjthestness@gmail.com convertStatBuf<target_stat, host_stat64>(tgt, host, fakeTTY); 58911023Sjthestness@gmail.com#if defined(STAT_HAVE_NSEC) 59011023Sjthestness@gmail.com tgt->st_atime_nsec = host->st_atime_nsec; 59111023Sjthestness@gmail.com tgt->st_atime_nsec = TheISA::htog(tgt->st_atime_nsec); 59211023Sjthestness@gmail.com tgt->st_mtime_nsec = host->st_mtime_nsec; 59311023Sjthestness@gmail.com tgt->st_mtime_nsec = TheISA::htog(tgt->st_mtime_nsec); 59411023Sjthestness@gmail.com tgt->st_ctime_nsec = host->st_ctime_nsec; 59511023Sjthestness@gmail.com tgt->st_ctime_nsec = TheISA::htog(tgt->st_ctime_nsec); 59611023Sjthestness@gmail.com#else 59711023Sjthestness@gmail.com tgt->st_atime_nsec = 0; 59811023Sjthestness@gmail.com tgt->st_mtime_nsec = 0; 59911023Sjthestness@gmail.com tgt->st_ctime_nsec = 0; 60011023Sjthestness@gmail.com#endif 60111023Sjthestness@gmail.com} 60211023Sjthestness@gmail.com 60311023Sjthestness@gmail.com// Here are a couple of convenience functions 60411023Sjthestness@gmail.comtemplate<class OS> 60511023Sjthestness@gmail.comvoid 60611023Sjthestness@gmail.comcopyOutStatBuf(SETranslatingPortProxy &mem, Addr addr, 60711023Sjthestness@gmail.com hst_stat *host, bool fakeTTY = false) 60811023Sjthestness@gmail.com{ 60911023Sjthestness@gmail.com typedef TypedBufferArg<typename OS::tgt_stat> tgt_stat_buf; 61011023Sjthestness@gmail.com tgt_stat_buf tgt(addr); 61111023Sjthestness@gmail.com convertStatBuf<tgt_stat_buf, hst_stat>(tgt, host, fakeTTY); 61211023Sjthestness@gmail.com tgt.copyOut(mem); 61311023Sjthestness@gmail.com} 61411023Sjthestness@gmail.com 61511023Sjthestness@gmail.comtemplate<class OS> 61611023Sjthestness@gmail.comvoid 61711023Sjthestness@gmail.comcopyOutStat64Buf(SETranslatingPortProxy &mem, Addr addr, 61811023Sjthestness@gmail.com hst_stat64 *host, bool fakeTTY = false) 61911023Sjthestness@gmail.com{ 62011023Sjthestness@gmail.com typedef TypedBufferArg<typename OS::tgt_stat64> tgt_stat_buf; 62111023Sjthestness@gmail.com tgt_stat_buf tgt(addr); 62211023Sjthestness@gmail.com convertStat64Buf<tgt_stat_buf, hst_stat64>(tgt, host, fakeTTY); 62311023Sjthestness@gmail.com tgt.copyOut(mem); 62411023Sjthestness@gmail.com} 62511023Sjthestness@gmail.com 62611023Sjthestness@gmail.comtemplate <class OS> 62711023Sjthestness@gmail.comvoid 62811023Sjthestness@gmail.comcopyOutStatfsBuf(SETranslatingPortProxy &mem, Addr addr, 62911023Sjthestness@gmail.com hst_statfs *host) 63011023Sjthestness@gmail.com{ 63111023Sjthestness@gmail.com TypedBufferArg<typename OS::tgt_statfs> tgt(addr); 63211023Sjthestness@gmail.com 63311023Sjthestness@gmail.com tgt->f_type = TheISA::htog(host->f_type); 63411023Sjthestness@gmail.com#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) 63511023Sjthestness@gmail.com tgt->f_bsize = TheISA::htog(host->f_iosize); 63611023Sjthestness@gmail.com#else 63711023Sjthestness@gmail.com tgt->f_bsize = TheISA::htog(host->f_bsize); 63811023Sjthestness@gmail.com#endif 63911023Sjthestness@gmail.com tgt->f_blocks = TheISA::htog(host->f_blocks); 64011023Sjthestness@gmail.com tgt->f_bfree = TheISA::htog(host->f_bfree); 64111023Sjthestness@gmail.com tgt->f_bavail = TheISA::htog(host->f_bavail); 64211023Sjthestness@gmail.com tgt->f_files = TheISA::htog(host->f_files); 64311023Sjthestness@gmail.com tgt->f_ffree = TheISA::htog(host->f_ffree); 64411023Sjthestness@gmail.com memcpy(&tgt->f_fsid, &host->f_fsid, sizeof(host->f_fsid)); 64511023Sjthestness@gmail.com#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) 64611023Sjthestness@gmail.com tgt->f_namelen = TheISA::htog(host->f_namemax); 64711023Sjthestness@gmail.com tgt->f_frsize = TheISA::htog(host->f_bsize); 64811023Sjthestness@gmail.com#elif defined(__APPLE__) 64911023Sjthestness@gmail.com tgt->f_namelen = 0; 65011023Sjthestness@gmail.com tgt->f_frsize = 0; 65111023Sjthestness@gmail.com#else 65211023Sjthestness@gmail.com tgt->f_namelen = TheISA::htog(host->f_namelen); 65311023Sjthestness@gmail.com tgt->f_frsize = TheISA::htog(host->f_frsize); 65411023Sjthestness@gmail.com#endif 65511023Sjthestness@gmail.com#if defined(__linux__) 65611023Sjthestness@gmail.com memcpy(&tgt->f_spare, &host->f_spare, sizeof(host->f_spare)); 65711023Sjthestness@gmail.com#else 65811023Sjthestness@gmail.com /* 65911023Sjthestness@gmail.com * The fields are different sizes per OS. Don't bother with 66011023Sjthestness@gmail.com * f_spare or f_reserved on non-Linux for now. 66111023Sjthestness@gmail.com */ 66211023Sjthestness@gmail.com memset(&tgt->f_spare, 0, sizeof(tgt->f_spare)); 66311023Sjthestness@gmail.com#endif 66411023Sjthestness@gmail.com 66511023Sjthestness@gmail.com tgt.copyOut(mem); 66611023Sjthestness@gmail.com} 66711023Sjthestness@gmail.com 66811023Sjthestness@gmail.com/// Target ioctl() handler. For the most part, programs call ioctl() 66911023Sjthestness@gmail.com/// only to find out if their stdout is a tty, to determine whether to 67011023Sjthestness@gmail.com/// do line or block buffering. We always claim that output fds are 67111023Sjthestness@gmail.com/// not TTYs to provide repeatable results. 67211023Sjthestness@gmail.comtemplate <class OS> 67311023Sjthestness@gmail.comSyscallReturn 67411023Sjthestness@gmail.comioctlFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 67511023Sjthestness@gmail.com{ 67611023Sjthestness@gmail.com int index = 0; 67711023Sjthestness@gmail.com auto p = tc->getProcessPtr(); 67811023Sjthestness@gmail.com 67911023Sjthestness@gmail.com int tgt_fd = p->getSyscallArg(tc, index); 68011023Sjthestness@gmail.com unsigned req = p->getSyscallArg(tc, index); 68111023Sjthestness@gmail.com 68211023Sjthestness@gmail.com DPRINTF_SYSCALL(Verbose, "ioctl(%d, 0x%x, ...)\n", tgt_fd, req); 68311023Sjthestness@gmail.com 68411023Sjthestness@gmail.com if (OS::isTtyReq(req)) 68511023Sjthestness@gmail.com return -ENOTTY; 68611023Sjthestness@gmail.com 68711023Sjthestness@gmail.com auto dfdp = std::dynamic_pointer_cast<DeviceFDEntry>((*p->fds)[tgt_fd]); 68811023Sjthestness@gmail.com if (dfdp) { 68911023Sjthestness@gmail.com EmulatedDriver *emul_driver = dfdp->getDriver(); 69011023Sjthestness@gmail.com if (emul_driver) 69111023Sjthestness@gmail.com return emul_driver->ioctl(tc, req); 69211023Sjthestness@gmail.com } 69311023Sjthestness@gmail.com 69411023Sjthestness@gmail.com auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 69511023Sjthestness@gmail.com if (sfdp) { 69611023Sjthestness@gmail.com int status; 69711023Sjthestness@gmail.com 69811023Sjthestness@gmail.com switch (req) { 69911023Sjthestness@gmail.com case SIOCGIFCONF: { 70011023Sjthestness@gmail.com Addr conf_addr = p->getSyscallArg(tc, index); 70111023Sjthestness@gmail.com BufferArg conf_arg(conf_addr, sizeof(ifconf)); 70211023Sjthestness@gmail.com conf_arg.copyIn(tc->getMemProxy()); 70311023Sjthestness@gmail.com 70411023Sjthestness@gmail.com ifconf *conf = (ifconf*)conf_arg.bufferPtr(); 70511023Sjthestness@gmail.com Addr ifc_buf_addr = (Addr)conf->ifc_buf; 70611023Sjthestness@gmail.com BufferArg ifc_buf_arg(ifc_buf_addr, conf->ifc_len); 70711023Sjthestness@gmail.com ifc_buf_arg.copyIn(tc->getMemProxy()); 70811023Sjthestness@gmail.com 70911023Sjthestness@gmail.com conf->ifc_buf = (char*)ifc_buf_arg.bufferPtr(); 71011023Sjthestness@gmail.com 71111023Sjthestness@gmail.com status = ioctl(sfdp->getSimFD(), req, conf_arg.bufferPtr()); 71211023Sjthestness@gmail.com if (status != -1) { 71311023Sjthestness@gmail.com conf->ifc_buf = (char*)ifc_buf_addr; 71411023Sjthestness@gmail.com ifc_buf_arg.copyOut(tc->getMemProxy()); 71511023Sjthestness@gmail.com conf_arg.copyOut(tc->getMemProxy()); 71611023Sjthestness@gmail.com } 71711023Sjthestness@gmail.com 71811023Sjthestness@gmail.com return status; 71911023Sjthestness@gmail.com } 72011023Sjthestness@gmail.com case SIOCGIFFLAGS: 72111023Sjthestness@gmail.com#if defined(__linux__) 72211023Sjthestness@gmail.com case SIOCGIFINDEX: 72311023Sjthestness@gmail.com#endif 72411023Sjthestness@gmail.com case SIOCGIFNETMASK: 72511023Sjthestness@gmail.com case SIOCGIFADDR: 72611023Sjthestness@gmail.com#if defined(__linux__) 72711023Sjthestness@gmail.com case SIOCGIFHWADDR: 72811023Sjthestness@gmail.com#endif 72911023Sjthestness@gmail.com case SIOCGIFMTU: { 73011023Sjthestness@gmail.com Addr req_addr = p->getSyscallArg(tc, index); 73111023Sjthestness@gmail.com BufferArg req_arg(req_addr, sizeof(ifreq)); 73211023Sjthestness@gmail.com req_arg.copyIn(tc->getMemProxy()); 73311023Sjthestness@gmail.com 73411023Sjthestness@gmail.com status = ioctl(sfdp->getSimFD(), req, req_arg.bufferPtr()); 73511023Sjthestness@gmail.com if (status != -1) 73611023Sjthestness@gmail.com req_arg.copyOut(tc->getMemProxy()); 73711023Sjthestness@gmail.com return status; 73811023Sjthestness@gmail.com } 73911023Sjthestness@gmail.com } 74011023Sjthestness@gmail.com } 74111023Sjthestness@gmail.com 74211023Sjthestness@gmail.com /** 74311023Sjthestness@gmail.com * For lack of a better return code, return ENOTTY. Ideally, we should 74411023Sjthestness@gmail.com * return something better here, but at least we issue the warning. 74511023Sjthestness@gmail.com */ 74611023Sjthestness@gmail.com warn("Unsupported ioctl call (return ENOTTY): ioctl(%d, 0x%x, ...) @ \n", 74711023Sjthestness@gmail.com tgt_fd, req, tc->pcState()); 74811023Sjthestness@gmail.com return -ENOTTY; 74911023Sjthestness@gmail.com} 75011023Sjthestness@gmail.com 75111023Sjthestness@gmail.comtemplate <class OS> 75211023Sjthestness@gmail.comSyscallReturn 75311023Sjthestness@gmail.comopenImpl(SyscallDesc *desc, int callnum, ThreadContext *tc, bool isopenat) 75411023Sjthestness@gmail.com{ 75511023Sjthestness@gmail.com int index = 0; 75611023Sjthestness@gmail.com auto p = tc->getProcessPtr(); 75711023Sjthestness@gmail.com int tgt_dirfd = -1; 75811023Sjthestness@gmail.com 75911023Sjthestness@gmail.com /** 76011023Sjthestness@gmail.com * If using the openat variant, read in the target directory file 76111023Sjthestness@gmail.com * descriptor from the simulated process. 76211023Sjthestness@gmail.com */ 76311023Sjthestness@gmail.com if (isopenat) 76411023Sjthestness@gmail.com tgt_dirfd = p->getSyscallArg(tc, index); 76511023Sjthestness@gmail.com 76611023Sjthestness@gmail.com /** 76711023Sjthestness@gmail.com * Retrieve the simulated process' memory proxy and then read in the path 76811023Sjthestness@gmail.com * string from that memory space into the host's working memory space. 76911023Sjthestness@gmail.com */ 77011023Sjthestness@gmail.com std::string path; 77111023Sjthestness@gmail.com if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 77211023Sjthestness@gmail.com return -EFAULT; 77311023Sjthestness@gmail.com 77411023Sjthestness@gmail.com#ifdef __CYGWIN32__ 77511023Sjthestness@gmail.com int host_flags = O_BINARY; 77611023Sjthestness@gmail.com#else 77711023Sjthestness@gmail.com int host_flags = 0; 77811023Sjthestness@gmail.com#endif 77911023Sjthestness@gmail.com /** 78011023Sjthestness@gmail.com * Translate target flags into host flags. Flags exist which are not 78111023Sjthestness@gmail.com * ported between architectures which can cause check failures. 78211023Sjthestness@gmail.com */ 78311023Sjthestness@gmail.com int tgt_flags = p->getSyscallArg(tc, index); 78411023Sjthestness@gmail.com for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) { 78511023Sjthestness@gmail.com if (tgt_flags & OS::openFlagTable[i].tgtFlag) { 78611023Sjthestness@gmail.com tgt_flags &= ~OS::openFlagTable[i].tgtFlag; 78711023Sjthestness@gmail.com host_flags |= OS::openFlagTable[i].hostFlag; 78811023Sjthestness@gmail.com } 78911023Sjthestness@gmail.com } 79011023Sjthestness@gmail.com if (tgt_flags) { 79111023Sjthestness@gmail.com warn("open%s: cannot decode flags 0x%x", 79211023Sjthestness@gmail.com isopenat ? "at" : "", tgt_flags); 79311023Sjthestness@gmail.com } 79411023Sjthestness@gmail.com#ifdef __CYGWIN32__ 79511023Sjthestness@gmail.com host_flags |= O_BINARY; 79611023Sjthestness@gmail.com#endif 79711023Sjthestness@gmail.com 79811023Sjthestness@gmail.com int mode = p->getSyscallArg(tc, index); 79911023Sjthestness@gmail.com 80011023Sjthestness@gmail.com /** 80111023Sjthestness@gmail.com * If the simulated process called open or openat with AT_FDCWD specified, 80211023Sjthestness@gmail.com * take the current working directory value which was passed into the 80311023Sjthestness@gmail.com * process class as a Python parameter and append the current path to 80411023Sjthestness@gmail.com * create a full path. 8059605Snilay@cs.wisc.edu * Otherwise, openat with a valid target directory file descriptor has 8068540SN/A * been called. If the path option, which was passed in as a parameter, 8078540SN/A * is not absolute, retrieve the directory file descriptor's path and 80810036SAli.Saidi@ARM.com * prepend it to the path passed in as a parameter. 8096928SN/A * In every case, we should have a full path (which is relevant to the 8108540SN/A * host) to work with after this block has been passed. 8119864Snilay@cs.wisc.edu */ 8129864Snilay@cs.wisc.edu std::string redir_path = path; 8136928SN/A std::string abs_path = path; 8146928SN/A if (!isopenat || tgt_dirfd == OS::TGT_AT_FDCWD) { 8159605Snilay@cs.wisc.edu abs_path = p->absolutePath(path, true); 8168540SN/A redir_path = p->checkPathRedirect(path); 8178540SN/A } else if (!startswith(path, "/")) { 81810036SAli.Saidi@ARM.com std::shared_ptr<FDEntry> fdep = ((*p->fds)[tgt_dirfd]); 8196928SN/A auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep); 8208540SN/A if (!ffdp) 8219864Snilay@cs.wisc.edu return -EBADF; 8229864Snilay@cs.wisc.edu abs_path = ffdp->getFileName() + path; 8236928SN/A redir_path = p->checkPathRedirect(abs_path); 8246928SN/A } 8259864Snilay@cs.wisc.edu 8269864Snilay@cs.wisc.edu /** 82711023Sjthestness@gmail.com * Since this is an emulated environment, we create pseudo file 8289864Snilay@cs.wisc.edu * descriptors for device requests that have been registered with 82910036SAli.Saidi@ARM.com * the process class through Python; this allows us to create a file 83011023Sjthestness@gmail.com * descriptor for subsequent ioctl or mmap calls. 83111023Sjthestness@gmail.com */ 8329864Snilay@cs.wisc.edu if (startswith(abs_path, "/dev/")) { 8339864Snilay@cs.wisc.edu std::string filename = abs_path.substr(strlen("/dev/")); 8349864Snilay@cs.wisc.edu EmulatedDriver *drv = p->findDriver(filename); 83511023Sjthestness@gmail.com if (drv) { 83611023Sjthestness@gmail.com DPRINTF_SYSCALL(Verbose, "open%s: passing call to " 83711023Sjthestness@gmail.com "driver open with path[%s]\n", 83811023Sjthestness@gmail.com isopenat ? "at" : "", abs_path.c_str()); 83911023Sjthestness@gmail.com return drv->open(tc, mode, host_flags); 84011023Sjthestness@gmail.com } 84111023Sjthestness@gmail.com /** 84211023Sjthestness@gmail.com * Fall through here for pass through to host devices, such 84311023Sjthestness@gmail.com * as /dev/zero 84411023Sjthestness@gmail.com */ 84511023Sjthestness@gmail.com } 84611023Sjthestness@gmail.com 84711023Sjthestness@gmail.com /** 84811023Sjthestness@gmail.com * We make several attempts resolve a call to open. 84911023Sjthestness@gmail.com * 85011023Sjthestness@gmail.com * 1) Resolve any path redirection before hand. This will set the path 85111023Sjthestness@gmail.com * up with variable 'redir_path' which may contain a modified path or 85211023Sjthestness@gmail.com * the original path value. This should already be done in prior code. 85311023Sjthestness@gmail.com * 2) Try to handle the access using 'special_paths'. Some special_paths 85411023Sjthestness@gmail.com * and files cannot be called on the host and need to be handled as 85511023Sjthestness@gmail.com * special cases inside the simulator. These special_paths are handled by 85611023Sjthestness@gmail.com * C++ routines to provide output back to userspace. 85711023Sjthestness@gmail.com * 3) If the full path that was created above does not match any of the 85811023Sjthestness@gmail.com * special cases, pass it through to the open call on the __HOST__ to let 85911023Sjthestness@gmail.com * the host open the file on our behalf. Again, the openImpl tries to 86011023Sjthestness@gmail.com * USE_THE_HOST_FILESYSTEM_OPEN (with a possible redirection to the 86111023Sjthestness@gmail.com * faux-filesystem files). The faux-filesystem is dynamically created 86211023Sjthestness@gmail.com * during simulator configuration using Python functions. 86311023Sjthestness@gmail.com * 4) If the host cannot open the file, the open attempt failed in "3)". 86411023Sjthestness@gmail.com * Return the host's error code back through the system call to the 86511023Sjthestness@gmail.com * simulated process. If running a debug trace, also notify the user that 86611023Sjthestness@gmail.com * the open call failed. 86711023Sjthestness@gmail.com * 86811023Sjthestness@gmail.com * Any success will set sim_fd to something other than -1 and skip the 86911023Sjthestness@gmail.com * next conditions effectively bypassing them. 87011023Sjthestness@gmail.com */ 87111023Sjthestness@gmail.com int sim_fd = -1; 87211023Sjthestness@gmail.com std::string used_path; 87311023Sjthestness@gmail.com std::vector<std::string> special_paths = 87411023Sjthestness@gmail.com { "/proc/meminfo/", "/system/", "/platform/", "/etc/passwd" }; 87511023Sjthestness@gmail.com for (auto entry : special_paths) { 87611023Sjthestness@gmail.com if (startswith(path, entry)) { 87711023Sjthestness@gmail.com sim_fd = OS::openSpecialFile(abs_path, p, tc); 87811023Sjthestness@gmail.com used_path = abs_path; 87911023Sjthestness@gmail.com } 88011023Sjthestness@gmail.com } 88111023Sjthestness@gmail.com if (sim_fd == -1) { 88211023Sjthestness@gmail.com sim_fd = open(redir_path.c_str(), host_flags, mode); 88311023Sjthestness@gmail.com used_path = redir_path; 88411023Sjthestness@gmail.com } 88511023Sjthestness@gmail.com if (sim_fd == -1) { 88611023Sjthestness@gmail.com int local = -errno; 88711023Sjthestness@gmail.com DPRINTF_SYSCALL(Verbose, "open%s: failed -> path:%s " 88811023Sjthestness@gmail.com "(inferred from:%s)\n", isopenat ? "at" : "", 88911023Sjthestness@gmail.com used_path.c_str(), path.c_str()); 89011023Sjthestness@gmail.com return local; 89111023Sjthestness@gmail.com } 89211023Sjthestness@gmail.com 89311023Sjthestness@gmail.com /** 89411023Sjthestness@gmail.com * The file was opened successfully and needs to be recorded in the 89511023Sjthestness@gmail.com * process' file descriptor array so that it can be retrieved later. 89611023Sjthestness@gmail.com * The target file descriptor that is chosen will be the lowest unused 89711023Sjthestness@gmail.com * file descriptor. 89811023Sjthestness@gmail.com * Return the indirect target file descriptor back to the simulated 89911023Sjthestness@gmail.com * process to act as a handle for the opened file. 90011023Sjthestness@gmail.com */ 90111023Sjthestness@gmail.com auto ffdp = std::make_shared<FileFDEntry>(sim_fd, host_flags, path, 0); 90211023Sjthestness@gmail.com int tgt_fd = p->fds->allocFD(ffdp); 90311023Sjthestness@gmail.com DPRINTF_SYSCALL(Verbose, "open%s: sim_fd[%d], target_fd[%d] -> path:%s\n" 90411023Sjthestness@gmail.com "(inferred from:%s)\n", isopenat ? "at" : "", 90511023Sjthestness@gmail.com sim_fd, tgt_fd, used_path.c_str(), path.c_str()); 90611023Sjthestness@gmail.com return tgt_fd; 90711023Sjthestness@gmail.com} 90811023Sjthestness@gmail.com 90911023Sjthestness@gmail.com/// Target open() handler. 91011023Sjthestness@gmail.comtemplate <class OS> 91111023Sjthestness@gmail.comSyscallReturn 91211023Sjthestness@gmail.comopenFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 91311023Sjthestness@gmail.com{ 91411023Sjthestness@gmail.com return openImpl<OS>(desc, callnum, tc, false); 91511023Sjthestness@gmail.com} 91611023Sjthestness@gmail.com 91711023Sjthestness@gmail.com/// Target openat() handler. 91811023Sjthestness@gmail.comtemplate <class OS> 91911023Sjthestness@gmail.comSyscallReturn 92011023Sjthestness@gmail.comopenatFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 92111023Sjthestness@gmail.com{ 92211023Sjthestness@gmail.com return openImpl<OS>(desc, callnum, tc, true); 92311023Sjthestness@gmail.com} 92411023Sjthestness@gmail.com 92511023Sjthestness@gmail.com/// Target unlinkat() handler. 92611023Sjthestness@gmail.comtemplate <class OS> 92711023Sjthestness@gmail.comSyscallReturn 92811023Sjthestness@gmail.comunlinkatFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 92911023Sjthestness@gmail.com{ 93011023Sjthestness@gmail.com int index = 0; 93111023Sjthestness@gmail.com auto process = tc->getProcessPtr(); 93211023Sjthestness@gmail.com int dirfd = process->getSyscallArg(tc, index); 93311023Sjthestness@gmail.com if (dirfd != OS::TGT_AT_FDCWD) 93411023Sjthestness@gmail.com warn("unlinkat: first argument not AT_FDCWD; unlikely to work"); 93511023Sjthestness@gmail.com 93611023Sjthestness@gmail.com return unlinkHelper(desc, callnum, tc, 1); 93711023Sjthestness@gmail.com} 93811023Sjthestness@gmail.com 93911023Sjthestness@gmail.com/// Target facessat() handler 94011023Sjthestness@gmail.comtemplate <class OS> 94111023Sjthestness@gmail.comSyscallReturn 94211023Sjthestness@gmail.comfaccessatFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 94311023Sjthestness@gmail.com{ 94411023Sjthestness@gmail.com int index = 0; 94511023Sjthestness@gmail.com auto process = tc->getProcessPtr(); 94611023Sjthestness@gmail.com int dirfd = process->getSyscallArg(tc, index); 94711023Sjthestness@gmail.com if (dirfd != OS::TGT_AT_FDCWD) 94811023Sjthestness@gmail.com warn("faccessat: first argument not AT_FDCWD; unlikely to work"); 94911023Sjthestness@gmail.com return accessFunc(desc, callnum, tc, 1); 95011023Sjthestness@gmail.com} 95111023Sjthestness@gmail.com 95211023Sjthestness@gmail.com/// Target readlinkat() handler 95311023Sjthestness@gmail.comtemplate <class OS> 95411023Sjthestness@gmail.comSyscallReturn 95511023Sjthestness@gmail.comreadlinkatFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 95611023Sjthestness@gmail.com{ 95711023Sjthestness@gmail.com int index = 0; 95811023Sjthestness@gmail.com auto process = tc->getProcessPtr(); 95911023Sjthestness@gmail.com int dirfd = process->getSyscallArg(tc, index); 96011023Sjthestness@gmail.com if (dirfd != OS::TGT_AT_FDCWD) 96111023Sjthestness@gmail.com warn("openat: first argument not AT_FDCWD; unlikely to work"); 96211023Sjthestness@gmail.com return readlinkFunc(desc, callnum, tc, 1); 96311023Sjthestness@gmail.com} 96411023Sjthestness@gmail.com 96511023Sjthestness@gmail.com/// Target renameat() handler. 96611023Sjthestness@gmail.comtemplate <class OS> 96711023Sjthestness@gmail.comSyscallReturn 96811023Sjthestness@gmail.comrenameatFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 96911023Sjthestness@gmail.com{ 97011023Sjthestness@gmail.com int index = 0; 97111023Sjthestness@gmail.com auto process = tc->getProcessPtr(); 97211023Sjthestness@gmail.com 97311023Sjthestness@gmail.com int olddirfd = process->getSyscallArg(tc, index); 97411023Sjthestness@gmail.com if (olddirfd != OS::TGT_AT_FDCWD) 97511023Sjthestness@gmail.com warn("renameat: first argument not AT_FDCWD; unlikely to work"); 97611023Sjthestness@gmail.com 97711023Sjthestness@gmail.com std::string old_name; 97811023Sjthestness@gmail.com 97911023Sjthestness@gmail.com if (!tc->getMemProxy().tryReadString(old_name, 98011023Sjthestness@gmail.com process->getSyscallArg(tc, index))) 98111023Sjthestness@gmail.com return -EFAULT; 98211023Sjthestness@gmail.com 98311023Sjthestness@gmail.com int newdirfd = process->getSyscallArg(tc, index); 98411023Sjthestness@gmail.com if (newdirfd != OS::TGT_AT_FDCWD) 98511023Sjthestness@gmail.com warn("renameat: third argument not AT_FDCWD; unlikely to work"); 98611023Sjthestness@gmail.com 98711023Sjthestness@gmail.com std::string new_name; 98811023Sjthestness@gmail.com 98911023Sjthestness@gmail.com if (!tc->getMemProxy().tryReadString(new_name, 99011023Sjthestness@gmail.com process->getSyscallArg(tc, index))) 99111023Sjthestness@gmail.com return -EFAULT; 99211023Sjthestness@gmail.com 99311023Sjthestness@gmail.com // Adjust path for cwd and redirection 99411023Sjthestness@gmail.com old_name = process->checkPathRedirect(old_name); 99511023Sjthestness@gmail.com new_name = process->checkPathRedirect(new_name); 99611023Sjthestness@gmail.com 99711023Sjthestness@gmail.com int result = rename(old_name.c_str(), new_name.c_str()); 99811023Sjthestness@gmail.com return (result == -1) ? -errno : result; 99911023Sjthestness@gmail.com} 100011023Sjthestness@gmail.com 100111023Sjthestness@gmail.com/// Target sysinfo() handler. 100211023Sjthestness@gmail.comtemplate <class OS> 100311023Sjthestness@gmail.comSyscallReturn 100411023Sjthestness@gmail.comsysinfoFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 100511023Sjthestness@gmail.com{ 100611023Sjthestness@gmail.com int index = 0; 100711023Sjthestness@gmail.com auto process = tc->getProcessPtr(); 100811023Sjthestness@gmail.com 100911023Sjthestness@gmail.com TypedBufferArg<typename OS::tgt_sysinfo> 101011023Sjthestness@gmail.com sysinfo(process->getSyscallArg(tc, index)); 101111023Sjthestness@gmail.com 101211023Sjthestness@gmail.com sysinfo->uptime = seconds_since_epoch; 101311023Sjthestness@gmail.com sysinfo->totalram = process->system->memSize(); 101411023Sjthestness@gmail.com sysinfo->mem_unit = 1; 101511023Sjthestness@gmail.com 101611023Sjthestness@gmail.com sysinfo.copyOut(tc->getMemProxy()); 101711023Sjthestness@gmail.com 101811023Sjthestness@gmail.com return 0; 101911023Sjthestness@gmail.com} 102011023Sjthestness@gmail.com 102111023Sjthestness@gmail.com/// Target chmod() handler. 102211023Sjthestness@gmail.comtemplate <class OS> 102311023Sjthestness@gmail.comSyscallReturn 102411023Sjthestness@gmail.comchmodFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 102511023Sjthestness@gmail.com{ 102611023Sjthestness@gmail.com std::string path; 102711023Sjthestness@gmail.com auto process = tc->getProcessPtr(); 102811023Sjthestness@gmail.com 102911023Sjthestness@gmail.com int index = 0; 103011023Sjthestness@gmail.com if (!tc->getMemProxy().tryReadString(path, 103111023Sjthestness@gmail.com process->getSyscallArg(tc, index))) { 103211023Sjthestness@gmail.com return -EFAULT; 103311023Sjthestness@gmail.com } 103411023Sjthestness@gmail.com 103511023Sjthestness@gmail.com uint32_t mode = process->getSyscallArg(tc, index); 103611023Sjthestness@gmail.com mode_t hostMode = 0; 103711023Sjthestness@gmail.com 103811023Sjthestness@gmail.com // XXX translate mode flags via OS::something??? 103911023Sjthestness@gmail.com hostMode = mode; 104011023Sjthestness@gmail.com 104111023Sjthestness@gmail.com // Adjust path for cwd and redirection 104211023Sjthestness@gmail.com path = process->checkPathRedirect(path); 104311023Sjthestness@gmail.com 104411023Sjthestness@gmail.com // do the chmod 104511023Sjthestness@gmail.com int result = chmod(path.c_str(), hostMode); 104611023Sjthestness@gmail.com if (result < 0) 104711023Sjthestness@gmail.com return -errno; 104811023Sjthestness@gmail.com 104911023Sjthestness@gmail.com return 0; 105011023Sjthestness@gmail.com} 105111023Sjthestness@gmail.com 105211023Sjthestness@gmail.comtemplate <class OS> 105311023Sjthestness@gmail.comSyscallReturn 105411023Sjthestness@gmail.compollFunc(SyscallDesc *desc, int num, ThreadContext *tc) 105511023Sjthestness@gmail.com{ 105611023Sjthestness@gmail.com int index = 0; 105711023Sjthestness@gmail.com auto p = tc->getProcessPtr(); 105811023Sjthestness@gmail.com Addr fdsPtr = p->getSyscallArg(tc, index); 105911023Sjthestness@gmail.com int nfds = p->getSyscallArg(tc, index); 106011023Sjthestness@gmail.com int tmout = p->getSyscallArg(tc, index); 106111023Sjthestness@gmail.com 106211023Sjthestness@gmail.com BufferArg fdsBuf(fdsPtr, sizeof(struct pollfd) * nfds); 106311023Sjthestness@gmail.com fdsBuf.copyIn(tc->getMemProxy()); 106411023Sjthestness@gmail.com 106511023Sjthestness@gmail.com /** 106611023Sjthestness@gmail.com * Record the target file descriptors in a local variable. We need to 106711023Sjthestness@gmail.com * replace them with host file descriptors but we need a temporary copy 106811023Sjthestness@gmail.com * for later. Afterwards, replace each target file descriptor in the 106911023Sjthestness@gmail.com * poll_fd array with its host_fd. 107011023Sjthestness@gmail.com */ 107111023Sjthestness@gmail.com int temp_tgt_fds[nfds]; 107211023Sjthestness@gmail.com for (index = 0; index < nfds; index++) { 107311023Sjthestness@gmail.com temp_tgt_fds[index] = ((struct pollfd *)fdsBuf.bufferPtr())[index].fd; 107411023Sjthestness@gmail.com auto tgt_fd = temp_tgt_fds[index]; 10759864Snilay@cs.wisc.edu auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 10769864Snilay@cs.wisc.edu if (!hbfdp) 107711023Sjthestness@gmail.com return -EBADF; 10789864Snilay@cs.wisc.edu auto host_fd = hbfdp->getSimFD(); 107910036SAli.Saidi@ARM.com ((struct pollfd *)fdsBuf.bufferPtr())[index].fd = host_fd; 108011023Sjthestness@gmail.com } 108111023Sjthestness@gmail.com 10829864Snilay@cs.wisc.edu /** 10839864Snilay@cs.wisc.edu * We cannot allow an infinite poll to occur or it will inevitably cause 10849864Snilay@cs.wisc.edu * a deadlock in the gem5 simulator with clone. We must pass in tmout with 108511023Sjthestness@gmail.com * a non-negative value, however it also makes no sense to poll on the 108611023Sjthestness@gmail.com * underlying host for any other time than tmout a zero timeout. 108711023Sjthestness@gmail.com */ 108811023Sjthestness@gmail.com int status; 108911023Sjthestness@gmail.com if (tmout < 0) { 109011023Sjthestness@gmail.com status = poll((struct pollfd *)fdsBuf.bufferPtr(), nfds, 0); 109111023Sjthestness@gmail.com if (status == 0) { 109211023Sjthestness@gmail.com /** 109311023Sjthestness@gmail.com * If blocking indefinitely, check the signal list to see if a 109411023Sjthestness@gmail.com * signal would break the poll out of the retry cycle and try 109511023Sjthestness@gmail.com * to return the signal interrupt instead. 109611023Sjthestness@gmail.com */ 109711023Sjthestness@gmail.com System *sysh = tc->getSystemPtr(); 109811023Sjthestness@gmail.com std::list<BasicSignal>::iterator it; 109911023Sjthestness@gmail.com for (it=sysh->signalList.begin(); it!=sysh->signalList.end(); it++) 110011023Sjthestness@gmail.com if (it->receiver == p) 110111023Sjthestness@gmail.com return -EINTR; 110211023Sjthestness@gmail.com return SyscallReturn::retry(); 110311023Sjthestness@gmail.com } 110411023Sjthestness@gmail.com } else 110511023Sjthestness@gmail.com status = poll((struct pollfd *)fdsBuf.bufferPtr(), nfds, 0); 110611023Sjthestness@gmail.com 110711023Sjthestness@gmail.com if (status == -1) 110811023Sjthestness@gmail.com return -errno; 110911023Sjthestness@gmail.com 111011023Sjthestness@gmail.com /** 111111023Sjthestness@gmail.com * Replace each host_fd in the returned poll_fd array with its original 111211023Sjthestness@gmail.com * target file descriptor. 111311023Sjthestness@gmail.com */ 111411023Sjthestness@gmail.com for (index = 0; index < nfds; index++) { 111511023Sjthestness@gmail.com auto tgt_fd = temp_tgt_fds[index]; 111611023Sjthestness@gmail.com ((struct pollfd *)fdsBuf.bufferPtr())[index].fd = tgt_fd; 111711023Sjthestness@gmail.com } 111811023Sjthestness@gmail.com 111911023Sjthestness@gmail.com /** 112011023Sjthestness@gmail.com * Copy out the pollfd struct because the host may have updated fields 112111023Sjthestness@gmail.com * in the structure. 112211023Sjthestness@gmail.com */ 112311023Sjthestness@gmail.com fdsBuf.copyOut(tc->getMemProxy()); 112411023Sjthestness@gmail.com 112511023Sjthestness@gmail.com return status; 112611023Sjthestness@gmail.com} 112711023Sjthestness@gmail.com 112811023Sjthestness@gmail.com/// Target fchmod() handler. 112911023Sjthestness@gmail.comtemplate <class OS> 113011023Sjthestness@gmail.comSyscallReturn 113111023Sjthestness@gmail.comfchmodFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 113211023Sjthestness@gmail.com{ 113311023Sjthestness@gmail.com int index = 0; 113411023Sjthestness@gmail.com auto p = tc->getProcessPtr(); 113511023Sjthestness@gmail.com int tgt_fd = p->getSyscallArg(tc, index); 113611023Sjthestness@gmail.com uint32_t mode = p->getSyscallArg(tc, index); 113711023Sjthestness@gmail.com 113811023Sjthestness@gmail.com auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 113911023Sjthestness@gmail.com if (!ffdp) 114011023Sjthestness@gmail.com return -EBADF; 114111023Sjthestness@gmail.com int sim_fd = ffdp->getSimFD(); 114211023Sjthestness@gmail.com 114311023Sjthestness@gmail.com mode_t hostMode = mode; 114411023Sjthestness@gmail.com 114511023Sjthestness@gmail.com int result = fchmod(sim_fd, hostMode); 114611023Sjthestness@gmail.com 114711023Sjthestness@gmail.com return (result < 0) ? -errno : 0; 114811023Sjthestness@gmail.com} 114911023Sjthestness@gmail.com 115011023Sjthestness@gmail.com/// Target mremap() handler. 115111023Sjthestness@gmail.comtemplate <class OS> 115211023Sjthestness@gmail.comSyscallReturn 115311023Sjthestness@gmail.commremapFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 115411023Sjthestness@gmail.com{ 115511023Sjthestness@gmail.com int index = 0; 115611023Sjthestness@gmail.com auto process = tc->getProcessPtr(); 115711023Sjthestness@gmail.com Addr start = process->getSyscallArg(tc, index); 115811023Sjthestness@gmail.com uint64_t old_length = process->getSyscallArg(tc, index); 115911023Sjthestness@gmail.com uint64_t new_length = process->getSyscallArg(tc, index); 116011023Sjthestness@gmail.com uint64_t flags = process->getSyscallArg(tc, index); 116111023Sjthestness@gmail.com uint64_t provided_address = 0; 116211023Sjthestness@gmail.com bool use_provided_address = flags & OS::TGT_MREMAP_FIXED; 116311023Sjthestness@gmail.com 116411023Sjthestness@gmail.com if (use_provided_address) 116511023Sjthestness@gmail.com provided_address = process->getSyscallArg(tc, index); 116611023Sjthestness@gmail.com 116711023Sjthestness@gmail.com if ((start % TheISA::PageBytes != 0) || 116811023Sjthestness@gmail.com (provided_address % TheISA::PageBytes != 0)) { 116911023Sjthestness@gmail.com warn("mremap failing: arguments not page aligned"); 117011023Sjthestness@gmail.com return -EINVAL; 117111023Sjthestness@gmail.com } 117211023Sjthestness@gmail.com 117311023Sjthestness@gmail.com new_length = roundUp(new_length, TheISA::PageBytes); 117411023Sjthestness@gmail.com 117511023Sjthestness@gmail.com if (new_length > old_length) { 117611023Sjthestness@gmail.com std::shared_ptr<MemState> mem_state = process->memState; 117711023Sjthestness@gmail.com Addr mmap_end = mem_state->getMmapEnd(); 117811023Sjthestness@gmail.com 117911023Sjthestness@gmail.com if ((start + old_length) == mmap_end && 118011023Sjthestness@gmail.com (!use_provided_address || provided_address == start)) { 118111023Sjthestness@gmail.com // This case cannot occur when growing downward, as 118211023Sjthestness@gmail.com // start is greater than or equal to mmap_end. 118311023Sjthestness@gmail.com uint64_t diff = new_length - old_length; 118411023Sjthestness@gmail.com process->allocateMem(mmap_end, diff); 118511023Sjthestness@gmail.com mem_state->setMmapEnd(mmap_end + diff); 118611023Sjthestness@gmail.com return start; 118711023Sjthestness@gmail.com } else { 118811023Sjthestness@gmail.com if (!use_provided_address && !(flags & OS::TGT_MREMAP_MAYMOVE)) { 118911023Sjthestness@gmail.com warn("can't remap here and MREMAP_MAYMOVE flag not set\n"); 119011023Sjthestness@gmail.com return -ENOMEM; 119111023Sjthestness@gmail.com } else { 119211023Sjthestness@gmail.com uint64_t new_start = provided_address; 119311023Sjthestness@gmail.com if (!use_provided_address) { 119411023Sjthestness@gmail.com new_start = process->mmapGrowsDown() ? 119511023Sjthestness@gmail.com mmap_end - new_length : mmap_end; 119611023Sjthestness@gmail.com mmap_end = process->mmapGrowsDown() ? 119711023Sjthestness@gmail.com new_start : mmap_end + new_length; 119811023Sjthestness@gmail.com mem_state->setMmapEnd(mmap_end); 119911023Sjthestness@gmail.com } 120011023Sjthestness@gmail.com 120111023Sjthestness@gmail.com process->pTable->remap(start, old_length, new_start); 120211023Sjthestness@gmail.com warn("mremapping to new vaddr %08p-%08p, adding %d\n", 120311023Sjthestness@gmail.com new_start, new_start + new_length, 120411023Sjthestness@gmail.com new_length - old_length); 120511023Sjthestness@gmail.com // add on the remaining unallocated pages 120611023Sjthestness@gmail.com process->allocateMem(new_start + old_length, 120711023Sjthestness@gmail.com new_length - old_length, 120811023Sjthestness@gmail.com use_provided_address /* clobber */); 120911023Sjthestness@gmail.com if (use_provided_address && 121011023Sjthestness@gmail.com ((new_start + new_length > mem_state->getMmapEnd() && 121111023Sjthestness@gmail.com !process->mmapGrowsDown()) || 121211023Sjthestness@gmail.com (new_start < mem_state->getMmapEnd() && 121311023Sjthestness@gmail.com process->mmapGrowsDown()))) { 121411023Sjthestness@gmail.com // something fishy going on here, at least notify the user 121511023Sjthestness@gmail.com // @todo: increase mmap_end? 121611023Sjthestness@gmail.com warn("mmap region limit exceeded with MREMAP_FIXED\n"); 121711023Sjthestness@gmail.com } 121811023Sjthestness@gmail.com warn("returning %08p as start\n", new_start); 121911023Sjthestness@gmail.com return new_start; 122011023Sjthestness@gmail.com } 122111023Sjthestness@gmail.com } 122211023Sjthestness@gmail.com } else { 122311023Sjthestness@gmail.com if (use_provided_address && provided_address != start) 122411023Sjthestness@gmail.com process->pTable->remap(start, new_length, provided_address); 122511023Sjthestness@gmail.com process->pTable->unmap(start + new_length, old_length - new_length); 122611023Sjthestness@gmail.com return use_provided_address ? provided_address : start; 122711023Sjthestness@gmail.com } 122811023Sjthestness@gmail.com} 122911023Sjthestness@gmail.com 123011023Sjthestness@gmail.com/// Target stat() handler. 123111023Sjthestness@gmail.comtemplate <class OS> 123211023Sjthestness@gmail.comSyscallReturn 123311023Sjthestness@gmail.comstatFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 123411023Sjthestness@gmail.com{ 123511023Sjthestness@gmail.com std::string path; 123611023Sjthestness@gmail.com auto process = tc->getProcessPtr(); 123711023Sjthestness@gmail.com 123811023Sjthestness@gmail.com int index = 0; 123911023Sjthestness@gmail.com if (!tc->getMemProxy().tryReadString(path, 124011023Sjthestness@gmail.com process->getSyscallArg(tc, index))) { 124111023Sjthestness@gmail.com return -EFAULT; 124211023Sjthestness@gmail.com } 124311023Sjthestness@gmail.com Addr bufPtr = process->getSyscallArg(tc, index); 124411023Sjthestness@gmail.com 124511023Sjthestness@gmail.com // Adjust path for cwd and redirection 124611023Sjthestness@gmail.com path = process->checkPathRedirect(path); 124711023Sjthestness@gmail.com 124811023Sjthestness@gmail.com struct stat hostBuf; 124911023Sjthestness@gmail.com int result = stat(path.c_str(), &hostBuf); 125011023Sjthestness@gmail.com 125111023Sjthestness@gmail.com if (result < 0) 125211023Sjthestness@gmail.com return -errno; 125311023Sjthestness@gmail.com 125411023Sjthestness@gmail.com copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 125511023Sjthestness@gmail.com 125611023Sjthestness@gmail.com return 0; 125711023Sjthestness@gmail.com} 125811023Sjthestness@gmail.com 125911023Sjthestness@gmail.com 126011023Sjthestness@gmail.com/// Target stat64() handler. 126111023Sjthestness@gmail.comtemplate <class OS> 126211023Sjthestness@gmail.comSyscallReturn 126311023Sjthestness@gmail.comstat64Func(SyscallDesc *desc, int callnum, ThreadContext *tc) 126411023Sjthestness@gmail.com{ 126511023Sjthestness@gmail.com std::string path; 126611023Sjthestness@gmail.com auto process = tc->getProcessPtr(); 126711023Sjthestness@gmail.com 126811023Sjthestness@gmail.com int index = 0; 126911023Sjthestness@gmail.com if (!tc->getMemProxy().tryReadString(path, 127011023Sjthestness@gmail.com process->getSyscallArg(tc, index))) 127111023Sjthestness@gmail.com return -EFAULT; 127211023Sjthestness@gmail.com Addr bufPtr = process->getSyscallArg(tc, index); 127311023Sjthestness@gmail.com 127411023Sjthestness@gmail.com // Adjust path for cwd and redirection 127511023Sjthestness@gmail.com path = process->checkPathRedirect(path); 127611023Sjthestness@gmail.com 127711023Sjthestness@gmail.com#if NO_STAT64 127811023Sjthestness@gmail.com struct stat hostBuf; 127911023Sjthestness@gmail.com int result = stat(path.c_str(), &hostBuf); 128011023Sjthestness@gmail.com#else 128111023Sjthestness@gmail.com struct stat64 hostBuf; 128211023Sjthestness@gmail.com int result = stat64(path.c_str(), &hostBuf); 128311023Sjthestness@gmail.com#endif 128411023Sjthestness@gmail.com 128511023Sjthestness@gmail.com if (result < 0) 128611023Sjthestness@gmail.com return -errno; 128711023Sjthestness@gmail.com 128811023Sjthestness@gmail.com copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 128911023Sjthestness@gmail.com 129011023Sjthestness@gmail.com return 0; 129111023Sjthestness@gmail.com} 129211023Sjthestness@gmail.com 129311023Sjthestness@gmail.com 129411023Sjthestness@gmail.com/// Target fstatat64() handler. 129511023Sjthestness@gmail.comtemplate <class OS> 129611023Sjthestness@gmail.comSyscallReturn 129711023Sjthestness@gmail.comfstatat64Func(SyscallDesc *desc, int callnum, ThreadContext *tc) 129811023Sjthestness@gmail.com{ 129911023Sjthestness@gmail.com int index = 0; 130011023Sjthestness@gmail.com auto process = tc->getProcessPtr(); 130111023Sjthestness@gmail.com int dirfd = process->getSyscallArg(tc, index); 130211023Sjthestness@gmail.com if (dirfd != OS::TGT_AT_FDCWD) 130311023Sjthestness@gmail.com warn("fstatat64: first argument not AT_FDCWD; unlikely to work"); 130411023Sjthestness@gmail.com 130511023Sjthestness@gmail.com std::string path; 130611023Sjthestness@gmail.com if (!tc->getMemProxy().tryReadString(path, 130711023Sjthestness@gmail.com process->getSyscallArg(tc, index))) 130811023Sjthestness@gmail.com return -EFAULT; 130911023Sjthestness@gmail.com Addr bufPtr = process->getSyscallArg(tc, index); 131011023Sjthestness@gmail.com 131111023Sjthestness@gmail.com // Adjust path for cwd and redirection 131211023Sjthestness@gmail.com path = process->checkPathRedirect(path); 131311023Sjthestness@gmail.com 131411023Sjthestness@gmail.com#if NO_STAT64 131511023Sjthestness@gmail.com struct stat hostBuf; 131611023Sjthestness@gmail.com int result = stat(path.c_str(), &hostBuf); 131711023Sjthestness@gmail.com#else 131811023Sjthestness@gmail.com struct stat64 hostBuf; 131911023Sjthestness@gmail.com int result = stat64(path.c_str(), &hostBuf); 132011023Sjthestness@gmail.com#endif 132111023Sjthestness@gmail.com 132211023Sjthestness@gmail.com if (result < 0) 132311023Sjthestness@gmail.com return -errno; 132411023Sjthestness@gmail.com 13259864Snilay@cs.wisc.edu copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 13269864Snilay@cs.wisc.edu 132711023Sjthestness@gmail.com return 0; 13289864Snilay@cs.wisc.edu} 132910036SAli.Saidi@ARM.com 133011023Sjthestness@gmail.com 133111023Sjthestness@gmail.com/// Target fstat64() handler. 13329864Snilay@cs.wisc.edutemplate <class OS> 13339864Snilay@cs.wisc.eduSyscallReturn 13349864Snilay@cs.wisc.edufstat64Func(SyscallDesc *desc, int callnum, ThreadContext *tc) 133511023Sjthestness@gmail.com{ 133611023Sjthestness@gmail.com int index = 0; 133711023Sjthestness@gmail.com auto p = tc->getProcessPtr(); 133811023Sjthestness@gmail.com int tgt_fd = p->getSyscallArg(tc, index); 133911023Sjthestness@gmail.com Addr bufPtr = p->getSyscallArg(tc, index); 134011023Sjthestness@gmail.com 134111023Sjthestness@gmail.com auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 134211023Sjthestness@gmail.com if (!ffdp) 134311023Sjthestness@gmail.com return -EBADF; 134411023Sjthestness@gmail.com int sim_fd = ffdp->getSimFD(); 134511023Sjthestness@gmail.com 134611023Sjthestness@gmail.com#if NO_STAT64 134711023Sjthestness@gmail.com struct stat hostBuf; 134811023Sjthestness@gmail.com int result = fstat(sim_fd, &hostBuf); 134911023Sjthestness@gmail.com#else 135011023Sjthestness@gmail.com struct stat64 hostBuf; 135111023Sjthestness@gmail.com int result = fstat64(sim_fd, &hostBuf); 135211023Sjthestness@gmail.com#endif 135311023Sjthestness@gmail.com 135411023Sjthestness@gmail.com if (result < 0) 135511023Sjthestness@gmail.com return -errno; 135611023Sjthestness@gmail.com 135711023Sjthestness@gmail.com copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (sim_fd == 1)); 135811023Sjthestness@gmail.com 135911023Sjthestness@gmail.com return 0; 136011023Sjthestness@gmail.com} 136111023Sjthestness@gmail.com 136211023Sjthestness@gmail.com 136311023Sjthestness@gmail.com/// Target lstat() handler. 136411023Sjthestness@gmail.comtemplate <class OS> 136511023Sjthestness@gmail.comSyscallReturn 136611023Sjthestness@gmail.comlstatFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 136711023Sjthestness@gmail.com{ 136811023Sjthestness@gmail.com std::string path; 136911023Sjthestness@gmail.com auto process = tc->getProcessPtr(); 137011023Sjthestness@gmail.com 137111023Sjthestness@gmail.com int index = 0; 137211023Sjthestness@gmail.com if (!tc->getMemProxy().tryReadString(path, 137311023Sjthestness@gmail.com process->getSyscallArg(tc, index))) { 137411023Sjthestness@gmail.com return -EFAULT; 137511023Sjthestness@gmail.com } 137611023Sjthestness@gmail.com Addr bufPtr = process->getSyscallArg(tc, index); 137711023Sjthestness@gmail.com 137811023Sjthestness@gmail.com // Adjust path for cwd and redirection 137911023Sjthestness@gmail.com path = process->checkPathRedirect(path); 138011023Sjthestness@gmail.com 138111023Sjthestness@gmail.com struct stat hostBuf; 138211023Sjthestness@gmail.com int result = lstat(path.c_str(), &hostBuf); 138311023Sjthestness@gmail.com 138411023Sjthestness@gmail.com if (result < 0) 138511023Sjthestness@gmail.com return -errno; 138611023Sjthestness@gmail.com 138711023Sjthestness@gmail.com copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 138811023Sjthestness@gmail.com 138911023Sjthestness@gmail.com return 0; 139011023Sjthestness@gmail.com} 139111023Sjthestness@gmail.com 139211023Sjthestness@gmail.com/// Target lstat64() handler. 139311023Sjthestness@gmail.comtemplate <class OS> 139411023Sjthestness@gmail.comSyscallReturn 139511023Sjthestness@gmail.comlstat64Func(SyscallDesc *desc, int callnum, ThreadContext *tc) 139611023Sjthestness@gmail.com{ 139711023Sjthestness@gmail.com std::string path; 139811023Sjthestness@gmail.com auto process = tc->getProcessPtr(); 139911023Sjthestness@gmail.com 140011023Sjthestness@gmail.com int index = 0; 140111023Sjthestness@gmail.com if (!tc->getMemProxy().tryReadString(path, 140211023Sjthestness@gmail.com process->getSyscallArg(tc, index))) { 140311023Sjthestness@gmail.com return -EFAULT; 140411023Sjthestness@gmail.com } 140511023Sjthestness@gmail.com Addr bufPtr = process->getSyscallArg(tc, index); 140611023Sjthestness@gmail.com 140711023Sjthestness@gmail.com // Adjust path for cwd and redirection 140811023Sjthestness@gmail.com path = process->checkPathRedirect(path); 140911023Sjthestness@gmail.com 141011023Sjthestness@gmail.com#if NO_STAT64 141111023Sjthestness@gmail.com struct stat hostBuf; 141211023Sjthestness@gmail.com int result = lstat(path.c_str(), &hostBuf); 141311023Sjthestness@gmail.com#else 141411023Sjthestness@gmail.com struct stat64 hostBuf; 141511023Sjthestness@gmail.com int result = lstat64(path.c_str(), &hostBuf); 141611023Sjthestness@gmail.com#endif 141711023Sjthestness@gmail.com 141811023Sjthestness@gmail.com if (result < 0) 141911023Sjthestness@gmail.com return -errno; 142011023Sjthestness@gmail.com 142111023Sjthestness@gmail.com copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 142211023Sjthestness@gmail.com 142311023Sjthestness@gmail.com return 0; 142411023Sjthestness@gmail.com} 142511023Sjthestness@gmail.com 142611023Sjthestness@gmail.com/// Target fstat() handler. 142711023Sjthestness@gmail.comtemplate <class OS> 142811023Sjthestness@gmail.comSyscallReturn 142911023Sjthestness@gmail.comfstatFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 143011023Sjthestness@gmail.com{ 143111023Sjthestness@gmail.com int index = 0; 143211023Sjthestness@gmail.com auto p = tc->getProcessPtr(); 143311023Sjthestness@gmail.com int tgt_fd = p->getSyscallArg(tc, index); 143411023Sjthestness@gmail.com Addr bufPtr = p->getSyscallArg(tc, index); 143511023Sjthestness@gmail.com 143611023Sjthestness@gmail.com DPRINTF_SYSCALL(Verbose, "fstat(%d, ...)\n", tgt_fd); 143711023Sjthestness@gmail.com 143811023Sjthestness@gmail.com auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 143911023Sjthestness@gmail.com if (!ffdp) 144011023Sjthestness@gmail.com return -EBADF; 144111023Sjthestness@gmail.com int sim_fd = ffdp->getSimFD(); 144211023Sjthestness@gmail.com 144311023Sjthestness@gmail.com struct stat hostBuf; 144411023Sjthestness@gmail.com int result = fstat(sim_fd, &hostBuf); 144511023Sjthestness@gmail.com 144611023Sjthestness@gmail.com if (result < 0) 144711023Sjthestness@gmail.com return -errno; 144811023Sjthestness@gmail.com 144911023Sjthestness@gmail.com copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (sim_fd == 1)); 145011023Sjthestness@gmail.com 145111023Sjthestness@gmail.com return 0; 145211023Sjthestness@gmail.com} 145311023Sjthestness@gmail.com 145411023Sjthestness@gmail.com/// Target statfs() handler. 145511023Sjthestness@gmail.comtemplate <class OS> 145611023Sjthestness@gmail.comSyscallReturn 145711023Sjthestness@gmail.comstatfsFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 145811023Sjthestness@gmail.com{ 145911023Sjthestness@gmail.com#if defined(__linux__) 146011023Sjthestness@gmail.com std::string path; 146111023Sjthestness@gmail.com auto process = tc->getProcessPtr(); 146211023Sjthestness@gmail.com 146311023Sjthestness@gmail.com int index = 0; 146411023Sjthestness@gmail.com if (!tc->getMemProxy().tryReadString(path, 146511023Sjthestness@gmail.com process->getSyscallArg(tc, index))) { 146611023Sjthestness@gmail.com return -EFAULT; 146711023Sjthestness@gmail.com } 146811023Sjthestness@gmail.com Addr bufPtr = process->getSyscallArg(tc, index); 146911023Sjthestness@gmail.com 147011023Sjthestness@gmail.com // Adjust path for cwd and redirection 147111023Sjthestness@gmail.com path = process->checkPathRedirect(path); 147211023Sjthestness@gmail.com 147311023Sjthestness@gmail.com struct statfs hostBuf; 147411023Sjthestness@gmail.com int result = statfs(path.c_str(), &hostBuf); 147511023Sjthestness@gmail.com 147611023Sjthestness@gmail.com if (result < 0) 147711023Sjthestness@gmail.com return -errno; 147811023Sjthestness@gmail.com 147911023Sjthestness@gmail.com copyOutStatfsBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 148011023Sjthestness@gmail.com return 0; 148111023Sjthestness@gmail.com#else 148211023Sjthestness@gmail.com warnUnsupportedOS("statfs"); 148311023Sjthestness@gmail.com return -1; 148411023Sjthestness@gmail.com#endif 148511023Sjthestness@gmail.com} 148611023Sjthestness@gmail.com 148711023Sjthestness@gmail.comtemplate <class OS> 148811023Sjthestness@gmail.comSyscallReturn 148911023Sjthestness@gmail.comcloneFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 149011023Sjthestness@gmail.com{ 149111023Sjthestness@gmail.com int index = 0; 149211023Sjthestness@gmail.com 149311023Sjthestness@gmail.com auto p = tc->getProcessPtr(); 149411023Sjthestness@gmail.com RegVal flags = p->getSyscallArg(tc, index); 149511023Sjthestness@gmail.com RegVal newStack = p->getSyscallArg(tc, index); 149611023Sjthestness@gmail.com Addr ptidPtr = p->getSyscallArg(tc, index); 149711023Sjthestness@gmail.com 149811023Sjthestness@gmail.com#if THE_ISA == RISCV_ISA or THE_ISA == ARM_ISA 149911023Sjthestness@gmail.com /** 150011023Sjthestness@gmail.com * Linux sets CLONE_BACKWARDS flag for RISC-V and Arm. 150111023Sjthestness@gmail.com * The flag defines the list of clone() arguments in the following 150211023Sjthestness@gmail.com * order: flags -> newStack -> ptidPtr -> tlsPtr -> ctidPtr 150311023Sjthestness@gmail.com */ 150411023Sjthestness@gmail.com Addr tlsPtr = p->getSyscallArg(tc, index); 150511023Sjthestness@gmail.com Addr ctidPtr = p->getSyscallArg(tc, index); 150611023Sjthestness@gmail.com#else 150711023Sjthestness@gmail.com Addr ctidPtr = p->getSyscallArg(tc, index); 150811023Sjthestness@gmail.com Addr tlsPtr = p->getSyscallArg(tc, index); 150911023Sjthestness@gmail.com#endif 151011023Sjthestness@gmail.com 151111023Sjthestness@gmail.com if (((flags & OS::TGT_CLONE_SIGHAND)&& !(flags & OS::TGT_CLONE_VM)) || 151211023Sjthestness@gmail.com ((flags & OS::TGT_CLONE_THREAD) && !(flags & OS::TGT_CLONE_SIGHAND)) || 151311023Sjthestness@gmail.com ((flags & OS::TGT_CLONE_FS) && (flags & OS::TGT_CLONE_NEWNS)) || 151411023Sjthestness@gmail.com ((flags & OS::TGT_CLONE_NEWIPC) && (flags & OS::TGT_CLONE_SYSVSEM)) || 151511023Sjthestness@gmail.com ((flags & OS::TGT_CLONE_NEWPID) && (flags & OS::TGT_CLONE_THREAD)) || 151611023Sjthestness@gmail.com ((flags & OS::TGT_CLONE_VM) && !(newStack))) 151711023Sjthestness@gmail.com return -EINVAL; 151811023Sjthestness@gmail.com 151911023Sjthestness@gmail.com ThreadContext *ctc; 152011023Sjthestness@gmail.com if (!(ctc = p->findFreeContext())) { 152111023Sjthestness@gmail.com DPRINTF_SYSCALL(Verbose, "clone: no spare thread context in system" 152211023Sjthestness@gmail.com "[cpu %d, thread %d]", tc->cpuId(), tc->threadId()); 152311023Sjthestness@gmail.com return -EAGAIN; 152411023Sjthestness@gmail.com } 152511023Sjthestness@gmail.com 152611023Sjthestness@gmail.com /** 152711023Sjthestness@gmail.com * Note that ProcessParams is generated by swig and there are no other 152811023Sjthestness@gmail.com * examples of how to create anything but this default constructor. The 152911023Sjthestness@gmail.com * fields are manually initialized instead of passing parameters to the 153011023Sjthestness@gmail.com * constructor. 153111023Sjthestness@gmail.com */ 153211023Sjthestness@gmail.com ProcessParams *pp = new ProcessParams(); 153311023Sjthestness@gmail.com pp->executable.assign(*(new std::string(p->progName()))); 153411023Sjthestness@gmail.com pp->cmd.push_back(*(new std::string(p->progName()))); 153511023Sjthestness@gmail.com pp->system = p->system; 153611023Sjthestness@gmail.com pp->cwd.assign(p->tgtCwd); 153711023Sjthestness@gmail.com pp->input.assign("stdin"); 153811023Sjthestness@gmail.com pp->output.assign("stdout"); 153911023Sjthestness@gmail.com pp->errout.assign("stderr"); 154011023Sjthestness@gmail.com pp->uid = p->uid(); 154111023Sjthestness@gmail.com pp->euid = p->euid(); 154211023Sjthestness@gmail.com pp->gid = p->gid(); 154311023Sjthestness@gmail.com pp->egid = p->egid(); 154411023Sjthestness@gmail.com 154511023Sjthestness@gmail.com /* Find the first free PID that's less than the maximum */ 154611023Sjthestness@gmail.com std::set<int> const& pids = p->system->PIDs; 154711023Sjthestness@gmail.com int temp_pid = *pids.begin(); 154811023Sjthestness@gmail.com do { 154911023Sjthestness@gmail.com temp_pid++; 155011023Sjthestness@gmail.com } while (pids.find(temp_pid) != pids.end()); 155111023Sjthestness@gmail.com if (temp_pid >= System::maxPID) 155211023Sjthestness@gmail.com fatal("temp_pid is too large: %d", temp_pid); 155311023Sjthestness@gmail.com 155411023Sjthestness@gmail.com pp->pid = temp_pid; 155511023Sjthestness@gmail.com pp->ppid = (flags & OS::TGT_CLONE_THREAD) ? p->ppid() : p->pid(); 155611023Sjthestness@gmail.com pp->useArchPT = p->useArchPT; 155711023Sjthestness@gmail.com pp->kvmInSE = p->kvmInSE; 155811023Sjthestness@gmail.com Process *cp = pp->create(); 155911023Sjthestness@gmail.com delete pp; 156011023Sjthestness@gmail.com 156111023Sjthestness@gmail.com Process *owner = ctc->getProcessPtr(); 156211023Sjthestness@gmail.com ctc->setProcessPtr(cp); 156311023Sjthestness@gmail.com cp->assignThreadContext(ctc->contextId()); 156411023Sjthestness@gmail.com owner->revokeThreadContext(ctc->contextId()); 156511023Sjthestness@gmail.com 156611023Sjthestness@gmail.com if (flags & OS::TGT_CLONE_PARENT_SETTID) { 156711023Sjthestness@gmail.com BufferArg ptidBuf(ptidPtr, sizeof(long)); 156811023Sjthestness@gmail.com long *ptid = (long *)ptidBuf.bufferPtr(); 156911023Sjthestness@gmail.com *ptid = cp->pid(); 157011023Sjthestness@gmail.com ptidBuf.copyOut(tc->getMemProxy()); 157111023Sjthestness@gmail.com } 157211023Sjthestness@gmail.com 157311023Sjthestness@gmail.com if (flags & OS::TGT_CLONE_THREAD) { 157411023Sjthestness@gmail.com cp->pTable->shared = true; 157511023Sjthestness@gmail.com cp->useForClone = true; 157611023Sjthestness@gmail.com } 157711023Sjthestness@gmail.com cp->initState(); 157811023Sjthestness@gmail.com p->clone(tc, ctc, cp, flags); 157911023Sjthestness@gmail.com 158011023Sjthestness@gmail.com if (flags & OS::TGT_CLONE_THREAD) { 158111023Sjthestness@gmail.com delete cp->sigchld; 158211023Sjthestness@gmail.com cp->sigchld = p->sigchld; 158311023Sjthestness@gmail.com } else if (flags & OS::TGT_SIGCHLD) { 158411023Sjthestness@gmail.com *cp->sigchld = true; 158511023Sjthestness@gmail.com } 158611023Sjthestness@gmail.com 158711023Sjthestness@gmail.com if (flags & OS::TGT_CLONE_CHILD_SETTID) { 158811023Sjthestness@gmail.com BufferArg ctidBuf(ctidPtr, sizeof(long)); 158911023Sjthestness@gmail.com long *ctid = (long *)ctidBuf.bufferPtr(); 159011023Sjthestness@gmail.com *ctid = cp->pid(); 159111023Sjthestness@gmail.com ctidBuf.copyOut(ctc->getMemProxy()); 159211023Sjthestness@gmail.com } 159311023Sjthestness@gmail.com 159411023Sjthestness@gmail.com if (flags & OS::TGT_CLONE_CHILD_CLEARTID) 159511023Sjthestness@gmail.com cp->childClearTID = (uint64_t)ctidPtr; 159611023Sjthestness@gmail.com 159711023Sjthestness@gmail.com ctc->clearArchRegs(); 159811023Sjthestness@gmail.com 159911023Sjthestness@gmail.com OS::archClone(flags, p, cp, tc, ctc, newStack, tlsPtr); 160011023Sjthestness@gmail.com 160111023Sjthestness@gmail.com cp->setSyscallReturn(ctc, 0); 160211023Sjthestness@gmail.com 160311023Sjthestness@gmail.com#if THE_ISA == ALPHA_ISA 160411023Sjthestness@gmail.com ctc->setIntReg(TheISA::SyscallSuccessReg, 0); 160511023Sjthestness@gmail.com#elif THE_ISA == SPARC_ISA 160611023Sjthestness@gmail.com tc->setIntReg(TheISA::SyscallPseudoReturnReg, 0); 160711023Sjthestness@gmail.com ctc->setIntReg(TheISA::SyscallPseudoReturnReg, 1); 160811023Sjthestness@gmail.com#endif 160911023Sjthestness@gmail.com 161011023Sjthestness@gmail.com if (p->kvmInSE) { 161111023Sjthestness@gmail.com#if THE_ISA == X86_ISA 161211023Sjthestness@gmail.com ctc->pcState(tc->readIntReg(TheISA::INTREG_RCX)); 161311023Sjthestness@gmail.com#else 161411023Sjthestness@gmail.com panic("KVM CPU model is not supported for this ISA"); 161511023Sjthestness@gmail.com#endif 161611023Sjthestness@gmail.com } else { 161711023Sjthestness@gmail.com TheISA::PCState cpc = tc->pcState(); 161811023Sjthestness@gmail.com cpc.advance(); 161911023Sjthestness@gmail.com ctc->pcState(cpc); 162011023Sjthestness@gmail.com } 162111023Sjthestness@gmail.com ctc->activate(); 162211023Sjthestness@gmail.com 162311023Sjthestness@gmail.com return cp->pid(); 162411023Sjthestness@gmail.com} 162511023Sjthestness@gmail.com 162611023Sjthestness@gmail.com/// Target fstatfs() handler. 162711023Sjthestness@gmail.comtemplate <class OS> 162811023Sjthestness@gmail.comSyscallReturn 162911023Sjthestness@gmail.comfstatfsFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 163011023Sjthestness@gmail.com{ 163111023Sjthestness@gmail.com int index = 0; 163211023Sjthestness@gmail.com auto p = tc->getProcessPtr(); 163311023Sjthestness@gmail.com int tgt_fd = p->getSyscallArg(tc, index); 163411023Sjthestness@gmail.com Addr bufPtr = p->getSyscallArg(tc, index); 163511023Sjthestness@gmail.com 163611023Sjthestness@gmail.com auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 163711023Sjthestness@gmail.com if (!ffdp) 163811023Sjthestness@gmail.com return -EBADF; 163911023Sjthestness@gmail.com int sim_fd = ffdp->getSimFD(); 164011023Sjthestness@gmail.com 164111023Sjthestness@gmail.com struct statfs hostBuf; 164211023Sjthestness@gmail.com int result = fstatfs(sim_fd, &hostBuf); 164311023Sjthestness@gmail.com 164411023Sjthestness@gmail.com if (result < 0) 164511023Sjthestness@gmail.com return -errno; 164611023Sjthestness@gmail.com 164711023Sjthestness@gmail.com copyOutStatfsBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 164811023Sjthestness@gmail.com 164911023Sjthestness@gmail.com return 0; 165011023Sjthestness@gmail.com} 165111023Sjthestness@gmail.com 165211023Sjthestness@gmail.com/// Target readv() handler. 165311023Sjthestness@gmail.comtemplate <class OS> 165411023Sjthestness@gmail.comSyscallReturn 16558721SN/AreadvFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 16568721SN/A{ 16579864Snilay@cs.wisc.edu int index = 0; 165810036SAli.Saidi@ARM.com auto p = tc->getProcessPtr(); 16598540SN/A int tgt_fd = p->getSyscallArg(tc, index); 16608983Snate@binkert.org 16618983Snate@binkert.org auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 16628983Snate@binkert.org if (!ffdp) 16638721SN/A return -EBADF; 16648721SN/A int sim_fd = ffdp->getSimFD(); 16658983Snate@binkert.org 16666928SN/A SETranslatingPortProxy &prox = tc->getMemProxy(); 16679864Snilay@cs.wisc.edu uint64_t tiov_base = p->getSyscallArg(tc, index); 16689864Snilay@cs.wisc.edu size_t count = p->getSyscallArg(tc, index); 166910036SAli.Saidi@ARM.com typename OS::tgt_iovec tiov[count]; 16709864Snilay@cs.wisc.edu struct iovec hiov[count]; 16719864Snilay@cs.wisc.edu for (size_t i = 0; i < count; ++i) { 1672 prox.readBlob(tiov_base + (i * sizeof(typename OS::tgt_iovec)), 1673 &tiov[i], sizeof(typename OS::tgt_iovec)); 1674 hiov[i].iov_len = TheISA::gtoh(tiov[i].iov_len); 1675 hiov[i].iov_base = new char [hiov[i].iov_len]; 1676 } 1677 1678 int result = readv(sim_fd, hiov, count); 1679 int local_errno = errno; 1680 1681 for (size_t i = 0; i < count; ++i) { 1682 if (result != -1) { 1683 prox.writeBlob(TheISA::htog(tiov[i].iov_base), 1684 hiov[i].iov_base, hiov[i].iov_len); 1685 } 1686 delete [] (char *)hiov[i].iov_base; 1687 } 1688 1689 return (result == -1) ? -local_errno : result; 1690} 1691 1692/// Target writev() handler. 1693template <class OS> 1694SyscallReturn 1695writevFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 1696{ 1697 int index = 0; 1698 auto p = tc->getProcessPtr(); 1699 int tgt_fd = p->getSyscallArg(tc, index); 1700 1701 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 1702 if (!hbfdp) 1703 return -EBADF; 1704 int sim_fd = hbfdp->getSimFD(); 1705 1706 SETranslatingPortProxy &prox = tc->getMemProxy(); 1707 uint64_t tiov_base = p->getSyscallArg(tc, index); 1708 size_t count = p->getSyscallArg(tc, index); 1709 struct iovec hiov[count]; 1710 for (size_t i = 0; i < count; ++i) { 1711 typename OS::tgt_iovec tiov; 1712 1713 prox.readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec), 1714 &tiov, sizeof(typename OS::tgt_iovec)); 1715 hiov[i].iov_len = TheISA::gtoh(tiov.iov_len); 1716 hiov[i].iov_base = new char [hiov[i].iov_len]; 1717 prox.readBlob(TheISA::gtoh(tiov.iov_base), hiov[i].iov_base, 1718 hiov[i].iov_len); 1719 } 1720 1721 int result = writev(sim_fd, hiov, count); 1722 1723 for (size_t i = 0; i < count; ++i) 1724 delete [] (char *)hiov[i].iov_base; 1725 1726 return (result == -1) ? -errno : result; 1727} 1728 1729/// Real mmap handler. 1730template <class OS> 1731SyscallReturn 1732mmapImpl(SyscallDesc *desc, int num, ThreadContext *tc, bool is_mmap2) 1733{ 1734 int index = 0; 1735 auto p = tc->getProcessPtr(); 1736 Addr start = p->getSyscallArg(tc, index); 1737 uint64_t length = p->getSyscallArg(tc, index); 1738 int prot = p->getSyscallArg(tc, index); 1739 int tgt_flags = p->getSyscallArg(tc, index); 1740 int tgt_fd = p->getSyscallArg(tc, index); 1741 int offset = p->getSyscallArg(tc, index); 1742 1743 if (is_mmap2) 1744 offset *= TheISA::PageBytes; 1745 1746 if (start & (TheISA::PageBytes - 1) || 1747 offset & (TheISA::PageBytes - 1) || 1748 (tgt_flags & OS::TGT_MAP_PRIVATE && 1749 tgt_flags & OS::TGT_MAP_SHARED) || 1750 (!(tgt_flags & OS::TGT_MAP_PRIVATE) && 1751 !(tgt_flags & OS::TGT_MAP_SHARED)) || 1752 !length) { 1753 return -EINVAL; 1754 } 1755 1756 if ((prot & PROT_WRITE) && (tgt_flags & OS::TGT_MAP_SHARED)) { 1757 // With shared mmaps, there are two cases to consider: 1758 // 1) anonymous: writes should modify the mapping and this should be 1759 // visible to observers who share the mapping. Currently, it's 1760 // difficult to update the shared mapping because there's no 1761 // structure which maintains information about the which virtual 1762 // memory areas are shared. If that structure existed, it would be 1763 // possible to make the translations point to the same frames. 1764 // 2) file-backed: writes should modify the mapping and the file 1765 // which is backed by the mapping. The shared mapping problem is the 1766 // same as what was mentioned about the anonymous mappings. For 1767 // file-backed mappings, the writes to the file are difficult 1768 // because it requires syncing what the mapping holds with the file 1769 // that resides on the host system. So, any write on a real system 1770 // would cause the change to be propagated to the file mapping at 1771 // some point in the future (the inode is tracked along with the 1772 // mapping). This isn't guaranteed to always happen, but it usually 1773 // works well enough. The guarantee is provided by the msync system 1774 // call. We could force the change through with shared mappings with 1775 // a call to msync, but that again would require more information 1776 // than we currently maintain. 1777 warn("mmap: writing to shared mmap region is currently " 1778 "unsupported. The write succeeds on the target, but it " 1779 "will not be propagated to the host or shared mappings"); 1780 } 1781 1782 length = roundUp(length, TheISA::PageBytes); 1783 1784 int sim_fd = -1; 1785 uint8_t *pmap = nullptr; 1786 if (!(tgt_flags & OS::TGT_MAP_ANONYMOUS)) { 1787 std::shared_ptr<FDEntry> fdep = (*p->fds)[tgt_fd]; 1788 1789 auto dfdp = std::dynamic_pointer_cast<DeviceFDEntry>(fdep); 1790 if (dfdp) { 1791 EmulatedDriver *emul_driver = dfdp->getDriver(); 1792 return emul_driver->mmap(tc, start, length, prot, tgt_flags, 1793 tgt_fd, offset); 1794 } 1795 1796 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep); 1797 if (!ffdp) 1798 return -EBADF; 1799 sim_fd = ffdp->getSimFD(); 1800 1801 pmap = (decltype(pmap))mmap(nullptr, length, PROT_READ, MAP_PRIVATE, 1802 sim_fd, offset); 1803 1804 if (pmap == (decltype(pmap))-1) { 1805 warn("mmap: failed to map file into host address space"); 1806 return -errno; 1807 } 1808 } 1809 1810 // Extend global mmap region if necessary. Note that we ignore the 1811 // start address unless MAP_FIXED is specified. 1812 if (!(tgt_flags & OS::TGT_MAP_FIXED)) { 1813 std::shared_ptr<MemState> mem_state = p->memState; 1814 Addr mmap_end = mem_state->getMmapEnd(); 1815 1816 start = p->mmapGrowsDown() ? mmap_end - length : mmap_end; 1817 mmap_end = p->mmapGrowsDown() ? start : mmap_end + length; 1818 1819 mem_state->setMmapEnd(mmap_end); 1820 } 1821 1822 DPRINTF_SYSCALL(Verbose, " mmap range is 0x%x - 0x%x\n", 1823 start, start + length - 1); 1824 1825 // We only allow mappings to overwrite existing mappings if 1826 // TGT_MAP_FIXED is set. Otherwise it shouldn't be a problem 1827 // because we ignore the start hint if TGT_MAP_FIXED is not set. 1828 int clobber = tgt_flags & OS::TGT_MAP_FIXED; 1829 if (clobber) { 1830 for (auto tc : p->system->threadContexts) { 1831 // If we might be overwriting old mappings, we need to 1832 // invalidate potentially stale mappings out of the TLBs. 1833 tc->getDTBPtr()->flushAll(); 1834 tc->getITBPtr()->flushAll(); 1835 } 1836 } 1837 1838 // Allocate physical memory and map it in. If the page table is already 1839 // mapped and clobber is not set, the simulator will issue throw a 1840 // fatal and bail out of the simulation. 1841 p->allocateMem(start, length, clobber); 1842 1843 // Transfer content into target address space. 1844 SETranslatingPortProxy &tp = tc->getMemProxy(); 1845 if (tgt_flags & OS::TGT_MAP_ANONYMOUS) { 1846 // In general, we should zero the mapped area for anonymous mappings, 1847 // with something like: 1848 // tp.memsetBlob(start, 0, length); 1849 // However, given that we don't support sparse mappings, and 1850 // some applications can map a couple of gigabytes of space 1851 // (intending sparse usage), that can get painfully expensive. 1852 // Fortunately, since we don't properly implement munmap either, 1853 // there's no danger of remapping used memory, so for now all 1854 // newly mapped memory should already be zeroed so we can skip it. 1855 } else { 1856 // It is possible to mmap an area larger than a file, however 1857 // accessing unmapped portions the system triggers a "Bus error" 1858 // on the host. We must know when to stop copying the file from 1859 // the host into the target address space. 1860 struct stat file_stat; 1861 if (fstat(sim_fd, &file_stat) > 0) 1862 fatal("mmap: cannot stat file"); 1863 1864 // Copy the portion of the file that is resident. This requires 1865 // checking both the mmap size and the filesize that we are 1866 // trying to mmap into this space; the mmap size also depends 1867 // on the specified offset into the file. 1868 uint64_t size = std::min((uint64_t)file_stat.st_size - offset, 1869 length); 1870 tp.writeBlob(start, pmap, size); 1871 1872 // Cleanup the mmap region before exiting this function. 1873 munmap(pmap, length); 1874 1875 // Maintain the symbol table for dynamic executables. 1876 // The loader will call mmap to map the images into its address 1877 // space and we intercept that here. We can verify that we are 1878 // executing inside the loader by checking the program counter value. 1879 // XXX: with multiprogrammed workloads or multi-node configurations, 1880 // this will not work since there is a single global symbol table. 1881 ObjectFile *interpreter = p->getInterpreter(); 1882 if (interpreter) { 1883 Addr text_start = interpreter->textBase(); 1884 Addr text_end = text_start + interpreter->textSize(); 1885 1886 Addr pc = tc->pcState().pc(); 1887 1888 if (pc >= text_start && pc < text_end) { 1889 std::shared_ptr<FDEntry> fdep = (*p->fds)[tgt_fd]; 1890 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep); 1891 ObjectFile *lib = createObjectFile(ffdp->getFileName()); 1892 1893 if (lib) { 1894 lib->loadAllSymbols(debugSymbolTable, 1895 lib->textBase(), start); 1896 } 1897 } 1898 } 1899 1900 // Note that we do not zero out the remainder of the mapping. This 1901 // is done by a real system, but it probably will not affect 1902 // execution (hopefully). 1903 } 1904 1905 return start; 1906} 1907 1908template <class OS> 1909SyscallReturn 1910pwrite64Func(SyscallDesc *desc, int num, ThreadContext *tc) 1911{ 1912 int index = 0; 1913 auto p = tc->getProcessPtr(); 1914 int tgt_fd = p->getSyscallArg(tc, index); 1915 Addr bufPtr = p->getSyscallArg(tc, index); 1916 int nbytes = p->getSyscallArg(tc, index); 1917 int offset = p->getSyscallArg(tc, index); 1918 1919 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 1920 if (!ffdp) 1921 return -EBADF; 1922 int sim_fd = ffdp->getSimFD(); 1923 1924 BufferArg bufArg(bufPtr, nbytes); 1925 bufArg.copyIn(tc->getMemProxy()); 1926 1927 int bytes_written = pwrite(sim_fd, bufArg.bufferPtr(), nbytes, offset); 1928 1929 return (bytes_written == -1) ? -errno : bytes_written; 1930} 1931 1932/// Target mmap() handler. 1933template <class OS> 1934SyscallReturn 1935mmapFunc(SyscallDesc *desc, int num, ThreadContext *tc) 1936{ 1937 return mmapImpl<OS>(desc, num, tc, false); 1938} 1939 1940/// Target mmap2() handler. 1941template <class OS> 1942SyscallReturn 1943mmap2Func(SyscallDesc *desc, int num, ThreadContext *tc) 1944{ 1945 return mmapImpl<OS>(desc, num, tc, true); 1946} 1947 1948/// Target getrlimit() handler. 1949template <class OS> 1950SyscallReturn 1951getrlimitFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 1952{ 1953 int index = 0; 1954 auto process = tc->getProcessPtr(); 1955 unsigned resource = process->getSyscallArg(tc, index); 1956 TypedBufferArg<typename OS::rlimit> rlp(process->getSyscallArg(tc, index)); 1957 1958 switch (resource) { 1959 case OS::TGT_RLIMIT_STACK: 1960 // max stack size in bytes: make up a number (8MB for now) 1961 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; 1962 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1963 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1964 break; 1965 1966 case OS::TGT_RLIMIT_DATA: 1967 // max data segment size in bytes: make up a number 1968 rlp->rlim_cur = rlp->rlim_max = 256 * 1024 * 1024; 1969 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1970 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1971 break; 1972 1973 default: 1974 warn("getrlimit: unimplemented resource %d", resource); 1975 return -EINVAL; 1976 break; 1977 } 1978 1979 rlp.copyOut(tc->getMemProxy()); 1980 return 0; 1981} 1982 1983template <class OS> 1984SyscallReturn 1985prlimitFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 1986{ 1987 int index = 0; 1988 auto process = tc->getProcessPtr(); 1989 if (process->getSyscallArg(tc, index) != 0) 1990 { 1991 warn("prlimit: ignoring rlimits for nonzero pid"); 1992 return -EPERM; 1993 } 1994 int resource = process->getSyscallArg(tc, index); 1995 Addr n = process->getSyscallArg(tc, index); 1996 if (n != 0) 1997 warn("prlimit: ignoring new rlimit"); 1998 Addr o = process->getSyscallArg(tc, index); 1999 if (o != 0) 2000 { 2001 TypedBufferArg<typename OS::rlimit> rlp(o); 2002 switch (resource) { 2003 case OS::TGT_RLIMIT_STACK: 2004 // max stack size in bytes: make up a number (8MB for now) 2005 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; 2006 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 2007 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 2008 break; 2009 case OS::TGT_RLIMIT_DATA: 2010 // max data segment size in bytes: make up a number 2011 rlp->rlim_cur = rlp->rlim_max = 256*1024*1024; 2012 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 2013 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 2014 break; 2015 default: 2016 warn("prlimit: unimplemented resource %d", resource); 2017 return -EINVAL; 2018 break; 2019 } 2020 rlp.copyOut(tc->getMemProxy()); 2021 } 2022 return 0; 2023} 2024 2025/// Target clock_gettime() function. 2026template <class OS> 2027SyscallReturn 2028clock_gettimeFunc(SyscallDesc *desc, int num, ThreadContext *tc) 2029{ 2030 int index = 1; 2031 auto p = tc->getProcessPtr(); 2032 //int clk_id = p->getSyscallArg(tc, index); 2033 TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index)); 2034 2035 getElapsedTimeNano(tp->tv_sec, tp->tv_nsec); 2036 tp->tv_sec += seconds_since_epoch; 2037 tp->tv_sec = TheISA::htog(tp->tv_sec); 2038 tp->tv_nsec = TheISA::htog(tp->tv_nsec); 2039 2040 tp.copyOut(tc->getMemProxy()); 2041 2042 return 0; 2043} 2044 2045/// Target clock_getres() function. 2046template <class OS> 2047SyscallReturn 2048clock_getresFunc(SyscallDesc *desc, int num, ThreadContext *tc) 2049{ 2050 int index = 1; 2051 auto p = tc->getProcessPtr(); 2052 TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index)); 2053 2054 // Set resolution at ns, which is what clock_gettime() returns 2055 tp->tv_sec = 0; 2056 tp->tv_nsec = 1; 2057 2058 tp.copyOut(tc->getMemProxy()); 2059 2060 return 0; 2061} 2062 2063/// Target gettimeofday() handler. 2064template <class OS> 2065SyscallReturn 2066gettimeofdayFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 2067{ 2068 int index = 0; 2069 auto process = tc->getProcessPtr(); 2070 TypedBufferArg<typename OS::timeval> tp(process->getSyscallArg(tc, index)); 2071 2072 getElapsedTimeMicro(tp->tv_sec, tp->tv_usec); 2073 tp->tv_sec += seconds_since_epoch; 2074 tp->tv_sec = TheISA::htog(tp->tv_sec); 2075 tp->tv_usec = TheISA::htog(tp->tv_usec); 2076 2077 tp.copyOut(tc->getMemProxy()); 2078 2079 return 0; 2080} 2081 2082 2083/// Target utimes() handler. 2084template <class OS> 2085SyscallReturn 2086utimesFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 2087{ 2088 std::string path; 2089 auto process = tc->getProcessPtr(); 2090 2091 int index = 0; 2092 if (!tc->getMemProxy().tryReadString(path, 2093 process->getSyscallArg(tc, index))) { 2094 return -EFAULT; 2095 } 2096 2097 TypedBufferArg<typename OS::timeval [2]> 2098 tp(process->getSyscallArg(tc, index)); 2099 tp.copyIn(tc->getMemProxy()); 2100 2101 struct timeval hostTimeval[2]; 2102 for (int i = 0; i < 2; ++i) { 2103 hostTimeval[i].tv_sec = TheISA::gtoh((*tp)[i].tv_sec); 2104 hostTimeval[i].tv_usec = TheISA::gtoh((*tp)[i].tv_usec); 2105 } 2106 2107 // Adjust path for cwd and redirection 2108 path = process->checkPathRedirect(path); 2109 2110 int result = utimes(path.c_str(), hostTimeval); 2111 2112 if (result < 0) 2113 return -errno; 2114 2115 return 0; 2116} 2117 2118template <class OS> 2119SyscallReturn 2120execveFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 2121{ 2122 desc->setFlags(0); 2123 auto p = tc->getProcessPtr(); 2124 2125 int index = 0; 2126 std::string path; 2127 SETranslatingPortProxy & mem_proxy = tc->getMemProxy(); 2128 if (!mem_proxy.tryReadString(path, p->getSyscallArg(tc, index))) 2129 return -EFAULT; 2130 2131 if (access(path.c_str(), F_OK) == -1) 2132 return -EACCES; 2133 2134 auto read_in = [](std::vector<std::string> & vect, 2135 SETranslatingPortProxy & mem_proxy, 2136 Addr mem_loc) 2137 { 2138 for (int inc = 0; ; inc++) { 2139 BufferArg b((mem_loc + sizeof(Addr) * inc), sizeof(Addr)); 2140 b.copyIn(mem_proxy); 2141 2142 if (!*(Addr*)b.bufferPtr()) 2143 break; 2144 2145 vect.push_back(std::string()); 2146 mem_proxy.tryReadString(vect[inc], *(Addr*)b.bufferPtr()); 2147 } 2148 }; 2149 2150 /** 2151 * Note that ProcessParams is generated by swig and there are no other 2152 * examples of how to create anything but this default constructor. The 2153 * fields are manually initialized instead of passing parameters to the 2154 * constructor. 2155 */ 2156 ProcessParams *pp = new ProcessParams(); 2157 pp->executable = path; 2158 Addr argv_mem_loc = p->getSyscallArg(tc, index); 2159 read_in(pp->cmd, mem_proxy, argv_mem_loc); 2160 Addr envp_mem_loc = p->getSyscallArg(tc, index); 2161 read_in(pp->env, mem_proxy, envp_mem_loc); 2162 pp->uid = p->uid(); 2163 pp->egid = p->egid(); 2164 pp->euid = p->euid(); 2165 pp->gid = p->gid(); 2166 pp->ppid = p->ppid(); 2167 pp->pid = p->pid(); 2168 pp->input.assign("cin"); 2169 pp->output.assign("cout"); 2170 pp->errout.assign("cerr"); 2171 pp->cwd.assign(p->tgtCwd); 2172 pp->system = p->system; 2173 /** 2174 * Prevent process object creation with identical PIDs (which will trip 2175 * a fatal check in Process constructor). The execve call is supposed to 2176 * take over the currently executing process' identity but replace 2177 * whatever it is doing with a new process image. Instead of hijacking 2178 * the process object in the simulator, we create a new process object 2179 * and bind to the previous process' thread below (hijacking the thread). 2180 */ 2181 p->system->PIDs.erase(p->pid()); 2182 Process *new_p = pp->create(); 2183 delete pp; 2184 2185 /** 2186 * Work through the file descriptor array and close any files marked 2187 * close-on-exec. 2188 */ 2189 new_p->fds = p->fds; 2190 for (int i = 0; i < new_p->fds->getSize(); i++) { 2191 std::shared_ptr<FDEntry> fdep = (*new_p->fds)[i]; 2192 if (fdep && fdep->getCOE()) 2193 new_p->fds->closeFDEntry(i); 2194 } 2195 2196 *new_p->sigchld = true; 2197 2198 delete p; 2199 tc->clearArchRegs(); 2200 tc->setProcessPtr(new_p); 2201 new_p->assignThreadContext(tc->contextId()); 2202 new_p->initState(); 2203 tc->activate(); 2204 TheISA::PCState pcState = tc->pcState(); 2205 tc->setNPC(pcState.instAddr()); 2206 2207 desc->setFlags(SyscallDesc::SuppressReturnValue); 2208 return 0; 2209} 2210 2211/// Target getrusage() function. 2212template <class OS> 2213SyscallReturn 2214getrusageFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 2215{ 2216 int index = 0; 2217 auto process = tc->getProcessPtr(); 2218 int who = process->getSyscallArg(tc, index); // THREAD, SELF, or CHILDREN 2219 TypedBufferArg<typename OS::rusage> rup(process->getSyscallArg(tc, index)); 2220 2221 rup->ru_utime.tv_sec = 0; 2222 rup->ru_utime.tv_usec = 0; 2223 rup->ru_stime.tv_sec = 0; 2224 rup->ru_stime.tv_usec = 0; 2225 rup->ru_maxrss = 0; 2226 rup->ru_ixrss = 0; 2227 rup->ru_idrss = 0; 2228 rup->ru_isrss = 0; 2229 rup->ru_minflt = 0; 2230 rup->ru_majflt = 0; 2231 rup->ru_nswap = 0; 2232 rup->ru_inblock = 0; 2233 rup->ru_oublock = 0; 2234 rup->ru_msgsnd = 0; 2235 rup->ru_msgrcv = 0; 2236 rup->ru_nsignals = 0; 2237 rup->ru_nvcsw = 0; 2238 rup->ru_nivcsw = 0; 2239 2240 switch (who) { 2241 case OS::TGT_RUSAGE_SELF: 2242 getElapsedTimeMicro(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec); 2243 rup->ru_utime.tv_sec = TheISA::htog(rup->ru_utime.tv_sec); 2244 rup->ru_utime.tv_usec = TheISA::htog(rup->ru_utime.tv_usec); 2245 break; 2246 2247 case OS::TGT_RUSAGE_CHILDREN: 2248 // do nothing. We have no child processes, so they take no time. 2249 break; 2250 2251 default: 2252 // don't really handle THREAD or CHILDREN, but just warn and 2253 // plow ahead 2254 warn("getrusage() only supports RUSAGE_SELF. Parameter %d ignored.", 2255 who); 2256 } 2257 2258 rup.copyOut(tc->getMemProxy()); 2259 2260 return 0; 2261} 2262 2263/// Target times() function. 2264template <class OS> 2265SyscallReturn 2266timesFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 2267{ 2268 int index = 0; 2269 auto process = tc->getProcessPtr(); 2270 TypedBufferArg<typename OS::tms> bufp(process->getSyscallArg(tc, index)); 2271 2272 // Fill in the time structure (in clocks) 2273 int64_t clocks = curTick() * OS::M5_SC_CLK_TCK / SimClock::Int::s; 2274 bufp->tms_utime = clocks; 2275 bufp->tms_stime = 0; 2276 bufp->tms_cutime = 0; 2277 bufp->tms_cstime = 0; 2278 2279 // Convert to host endianness 2280 bufp->tms_utime = TheISA::htog(bufp->tms_utime); 2281 2282 // Write back 2283 bufp.copyOut(tc->getMemProxy()); 2284 2285 // Return clock ticks since system boot 2286 return clocks; 2287} 2288 2289/// Target time() function. 2290template <class OS> 2291SyscallReturn 2292timeFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 2293{ 2294 typename OS::time_t sec, usec; 2295 getElapsedTimeMicro(sec, usec); 2296 sec += seconds_since_epoch; 2297 2298 int index = 0; 2299 auto process = tc->getProcessPtr(); 2300 Addr taddr = (Addr)process->getSyscallArg(tc, index); 2301 if (taddr != 0) { 2302 typename OS::time_t t = sec; 2303 t = TheISA::htog(t); 2304 SETranslatingPortProxy &p = tc->getMemProxy(); 2305 p.writeBlob(taddr, &t, (int)sizeof(typename OS::time_t)); 2306 } 2307 return sec; 2308} 2309 2310template <class OS> 2311SyscallReturn 2312tgkillFunc(SyscallDesc *desc, int num, ThreadContext *tc) 2313{ 2314 int index = 0; 2315 auto process = tc->getProcessPtr(); 2316 int tgid = process->getSyscallArg(tc, index); 2317 int tid = process->getSyscallArg(tc, index); 2318 int sig = process->getSyscallArg(tc, index); 2319 2320 /** 2321 * This system call is intended to allow killing a specific thread 2322 * within an arbitrary thread group if sanctioned with permission checks. 2323 * It's usually true that threads share the termination signal as pointed 2324 * out by the pthread_kill man page and this seems to be the intended 2325 * usage. Due to this being an emulated environment, assume the following: 2326 * Threads are allowed to call tgkill because the EUID for all threads 2327 * should be the same. There is no signal handling mechanism for kernel 2328 * registration of signal handlers since signals are poorly supported in 2329 * emulation mode. Since signal handlers cannot be registered, all 2330 * threads within in a thread group must share the termination signal. 2331 * We never exhaust PIDs so there's no chance of finding the wrong one 2332 * due to PID rollover. 2333 */ 2334 2335 System *sys = tc->getSystemPtr(); 2336 Process *tgt_proc = nullptr; 2337 for (int i = 0; i < sys->numContexts(); i++) { 2338 Process *temp = sys->threadContexts[i]->getProcessPtr(); 2339 if (temp->pid() == tid) { 2340 tgt_proc = temp; 2341 break; 2342 } 2343 } 2344 2345 if (sig != 0 || sig != OS::TGT_SIGABRT) 2346 return -EINVAL; 2347 2348 if (tgt_proc == nullptr) 2349 return -ESRCH; 2350 2351 if (tgid != -1 && tgt_proc->tgid() != tgid) 2352 return -ESRCH; 2353 2354 if (sig == OS::TGT_SIGABRT) 2355 exitGroupFunc(desc, 252, tc); 2356 2357 return 0; 2358} 2359 2360template <class OS> 2361SyscallReturn 2362socketFunc(SyscallDesc *desc, int num, ThreadContext *tc) 2363{ 2364 int index = 0; 2365 auto p = tc->getProcessPtr(); 2366 int domain = p->getSyscallArg(tc, index); 2367 int type = p->getSyscallArg(tc, index); 2368 int prot = p->getSyscallArg(tc, index); 2369 2370 int sim_fd = socket(domain, type, prot); 2371 if (sim_fd == -1) 2372 return -errno; 2373 2374 auto sfdp = std::make_shared<SocketFDEntry>(sim_fd, domain, type, prot); 2375 int tgt_fd = p->fds->allocFD(sfdp); 2376 2377 return tgt_fd; 2378} 2379 2380template <class OS> 2381SyscallReturn 2382socketpairFunc(SyscallDesc *desc, int num, ThreadContext *tc) 2383{ 2384 int index = 0; 2385 auto p = tc->getProcessPtr(); 2386 int domain = p->getSyscallArg(tc, index); 2387 int type = p->getSyscallArg(tc, index); 2388 int prot = p->getSyscallArg(tc, index); 2389 Addr svPtr = p->getSyscallArg(tc, index); 2390 2391 BufferArg svBuf((Addr)svPtr, 2 * sizeof(int)); 2392 int status = socketpair(domain, type, prot, (int *)svBuf.bufferPtr()); 2393 if (status == -1) 2394 return -errno; 2395 2396 int *fds = (int *)svBuf.bufferPtr(); 2397 2398 auto sfdp1 = std::make_shared<SocketFDEntry>(fds[0], domain, type, prot); 2399 fds[0] = p->fds->allocFD(sfdp1); 2400 auto sfdp2 = std::make_shared<SocketFDEntry>(fds[1], domain, type, prot); 2401 fds[1] = p->fds->allocFD(sfdp2); 2402 svBuf.copyOut(tc->getMemProxy()); 2403 2404 return status; 2405} 2406 2407template <class OS> 2408SyscallReturn 2409selectFunc(SyscallDesc *desc, int callnum, ThreadContext *tc) 2410{ 2411 int retval; 2412 2413 int index = 0; 2414 auto p = tc->getProcessPtr(); 2415 int nfds_t = p->getSyscallArg(tc, index); 2416 Addr fds_read_ptr = p->getSyscallArg(tc, index); 2417 Addr fds_writ_ptr = p->getSyscallArg(tc, index); 2418 Addr fds_excp_ptr = p->getSyscallArg(tc, index); 2419 Addr time_val_ptr = p->getSyscallArg(tc, index); 2420 2421 TypedBufferArg<typename OS::fd_set> rd_t(fds_read_ptr); 2422 TypedBufferArg<typename OS::fd_set> wr_t(fds_writ_ptr); 2423 TypedBufferArg<typename OS::fd_set> ex_t(fds_excp_ptr); 2424 TypedBufferArg<typename OS::timeval> tp(time_val_ptr); 2425 2426 /** 2427 * Host fields. Notice that these use the definitions from the system 2428 * headers instead of the gem5 headers and libraries. If the host and 2429 * target have different header file definitions, this will not work. 2430 */ 2431 fd_set rd_h; 2432 FD_ZERO(&rd_h); 2433 fd_set wr_h; 2434 FD_ZERO(&wr_h); 2435 fd_set ex_h; 2436 FD_ZERO(&ex_h); 2437 2438 /** 2439 * Copy in the fd_set from the target. 2440 */ 2441 if (fds_read_ptr) 2442 rd_t.copyIn(tc->getMemProxy()); 2443 if (fds_writ_ptr) 2444 wr_t.copyIn(tc->getMemProxy()); 2445 if (fds_excp_ptr) 2446 ex_t.copyIn(tc->getMemProxy()); 2447 2448 /** 2449 * We need to translate the target file descriptor set into a host file 2450 * descriptor set. This involves both our internal process fd array 2451 * and the fd_set defined in Linux header files. The nfds field also 2452 * needs to be updated as it will be only target specific after 2453 * retrieving it from the target; the nfds value is expected to be the 2454 * highest file descriptor that needs to be checked, so we need to extend 2455 * it out for nfds_h when we do the update. 2456 */ 2457 int nfds_h = 0; 2458 std::map<int, int> trans_map; 2459 auto try_add_host_set = [&](fd_set *tgt_set_entry, 2460 fd_set *hst_set_entry, 2461 int iter) -> bool 2462 { 2463 /** 2464 * By this point, we know that we are looking at a valid file 2465 * descriptor set on the target. We need to check if the target file 2466 * descriptor value passed in as iter is part of the set. 2467 */ 2468 if (FD_ISSET(iter, tgt_set_entry)) { 2469 /** 2470 * We know that the target file descriptor belongs to the set, 2471 * but we do not yet know if the file descriptor is valid or 2472 * that we have a host mapping. Check that now. 2473 */ 2474 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[iter]); 2475 if (!hbfdp) 2476 return true; 2477 auto sim_fd = hbfdp->getSimFD(); 2478 2479 /** 2480 * Add the sim_fd to tgt_fd translation into trans_map for use 2481 * later when we need to zero the target fd_set structures and 2482 * then update them with hits returned from the host select call. 2483 */ 2484 trans_map[sim_fd] = iter; 2485 2486 /** 2487 * We know that the host file descriptor exists so now we check 2488 * if we need to update the max count for nfds_h before passing 2489 * the duplicated structure into the host. 2490 */ 2491 nfds_h = std::max(nfds_h - 1, sim_fd + 1); 2492 2493 /** 2494 * Add the host file descriptor to the set that we are going to 2495 * pass into the host. 2496 */ 2497 FD_SET(sim_fd, hst_set_entry); 2498 } 2499 return false; 2500 }; 2501 2502 for (int i = 0; i < nfds_t; i++) { 2503 if (fds_read_ptr) { 2504 bool ebadf = try_add_host_set((fd_set*)&*rd_t, &rd_h, i); 2505 if (ebadf) return -EBADF; 2506 } 2507 if (fds_writ_ptr) { 2508 bool ebadf = try_add_host_set((fd_set*)&*wr_t, &wr_h, i); 2509 if (ebadf) return -EBADF; 2510 } 2511 if (fds_excp_ptr) { 2512 bool ebadf = try_add_host_set((fd_set*)&*ex_t, &ex_h, i); 2513 if (ebadf) return -EBADF; 2514 } 2515 } 2516 2517 if (time_val_ptr) { 2518 /** 2519 * It might be possible to decrement the timeval based on some 2520 * derivation of wall clock determined from elapsed simulator ticks 2521 * but that seems like overkill. Rather, we just set the timeval with 2522 * zero timeout. (There is no reason to block during the simulation 2523 * as it only decreases simulator performance.) 2524 */ 2525 tp->tv_sec = 0; 2526 tp->tv_usec = 0; 2527 2528 retval = select(nfds_h, 2529 fds_read_ptr ? &rd_h : nullptr, 2530 fds_writ_ptr ? &wr_h : nullptr, 2531 fds_excp_ptr ? &ex_h : nullptr, 2532 (timeval*)&*tp); 2533 } else { 2534 /** 2535 * If the timeval pointer is null, setup a new timeval structure to 2536 * pass into the host select call. Unfortunately, we will need to 2537 * manually check the return value and throw a retry fault if the 2538 * return value is zero. Allowing the system call to block will 2539 * likely deadlock the event queue. 2540 */ 2541 struct timeval tv = { 0, 0 }; 2542 2543 retval = select(nfds_h, 2544 fds_read_ptr ? &rd_h : nullptr, 2545 fds_writ_ptr ? &wr_h : nullptr, 2546 fds_excp_ptr ? &ex_h : nullptr, 2547 &tv); 2548 2549 if (retval == 0) { 2550 /** 2551 * If blocking indefinitely, check the signal list to see if a 2552 * signal would break the poll out of the retry cycle and try to 2553 * return the signal interrupt instead. 2554 */ 2555 for (auto sig : tc->getSystemPtr()->signalList) 2556 if (sig.receiver == p) 2557 return -EINTR; 2558 return SyscallReturn::retry(); 2559 } 2560 } 2561 2562 if (retval == -1) 2563 return -errno; 2564 2565 FD_ZERO((fd_set*)&*rd_t); 2566 FD_ZERO((fd_set*)&*wr_t); 2567 FD_ZERO((fd_set*)&*ex_t); 2568 2569 /** 2570 * We need to translate the host file descriptor set into a target file 2571 * descriptor set. This involves both our internal process fd array 2572 * and the fd_set defined in header files. 2573 */ 2574 for (int i = 0; i < nfds_h; i++) { 2575 if (fds_read_ptr) { 2576 if (FD_ISSET(i, &rd_h)) 2577 FD_SET(trans_map[i], (fd_set*)&*rd_t); 2578 } 2579 2580 if (fds_writ_ptr) { 2581 if (FD_ISSET(i, &wr_h)) 2582 FD_SET(trans_map[i], (fd_set*)&*wr_t); 2583 } 2584 2585 if (fds_excp_ptr) { 2586 if (FD_ISSET(i, &ex_h)) 2587 FD_SET(trans_map[i], (fd_set*)&*ex_t); 2588 } 2589 } 2590 2591 if (fds_read_ptr) 2592 rd_t.copyOut(tc->getMemProxy()); 2593 if (fds_writ_ptr) 2594 wr_t.copyOut(tc->getMemProxy()); 2595 if (fds_excp_ptr) 2596 ex_t.copyOut(tc->getMemProxy()); 2597 if (time_val_ptr) 2598 tp.copyOut(tc->getMemProxy()); 2599 2600 return retval; 2601} 2602 2603template <class OS> 2604SyscallReturn 2605readFunc(SyscallDesc *desc, int num, ThreadContext *tc) 2606{ 2607 int index = 0; 2608 auto p = tc->getProcessPtr(); 2609 int tgt_fd = p->getSyscallArg(tc, index); 2610 Addr buf_ptr = p->getSyscallArg(tc, index); 2611 int nbytes = p->getSyscallArg(tc, index); 2612 2613 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 2614 if (!hbfdp) 2615 return -EBADF; 2616 int sim_fd = hbfdp->getSimFD(); 2617 2618 struct pollfd pfd; 2619 pfd.fd = sim_fd; 2620 pfd.events = POLLIN | POLLPRI; 2621 if ((poll(&pfd, 1, 0) == 0) 2622 && !(hbfdp->getFlags() & OS::TGT_O_NONBLOCK)) 2623 return SyscallReturn::retry(); 2624 2625 BufferArg buf_arg(buf_ptr, nbytes); 2626 int bytes_read = read(sim_fd, buf_arg.bufferPtr(), nbytes); 2627 2628 if (bytes_read > 0) 2629 buf_arg.copyOut(tc->getMemProxy()); 2630 2631 return (bytes_read == -1) ? -errno : bytes_read; 2632} 2633 2634template <class OS> 2635SyscallReturn 2636writeFunc(SyscallDesc *desc, int num, ThreadContext *tc) 2637{ 2638 int index = 0; 2639 auto p = tc->getProcessPtr(); 2640 int tgt_fd = p->getSyscallArg(tc, index); 2641 Addr buf_ptr = p->getSyscallArg(tc, index); 2642 int nbytes = p->getSyscallArg(tc, index); 2643 2644 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 2645 if (!hbfdp) 2646 return -EBADF; 2647 int sim_fd = hbfdp->getSimFD(); 2648 2649 BufferArg buf_arg(buf_ptr, nbytes); 2650 buf_arg.copyIn(tc->getMemProxy()); 2651 2652 struct pollfd pfd; 2653 pfd.fd = sim_fd; 2654 pfd.events = POLLOUT; 2655 2656 /** 2657 * We don't want to poll on /dev/random. The kernel will not enable the 2658 * file descriptor for writing unless the entropy in the system falls 2659 * below write_wakeup_threshold. This is not guaranteed to happen 2660 * depending on host settings. 2661 */ 2662 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(hbfdp); 2663 if (ffdp && (ffdp->getFileName() != "/dev/random")) { 2664 if (!poll(&pfd, 1, 0) && !(ffdp->getFlags() & OS::TGT_O_NONBLOCK)) 2665 return SyscallReturn::retry(); 2666 } 2667 2668 int bytes_written = write(sim_fd, buf_arg.bufferPtr(), nbytes); 2669 2670 if (bytes_written != -1) 2671 fsync(sim_fd); 2672 2673 return (bytes_written == -1) ? -errno : bytes_written; 2674} 2675 2676template <class OS> 2677SyscallReturn 2678wait4Func(SyscallDesc *desc, int num, ThreadContext *tc) 2679{ 2680 int index = 0; 2681 auto p = tc->getProcessPtr(); 2682 pid_t pid = p->getSyscallArg(tc, index); 2683 Addr statPtr = p->getSyscallArg(tc, index); 2684 int options = p->getSyscallArg(tc, index); 2685 Addr rusagePtr = p->getSyscallArg(tc, index); 2686 2687 if (rusagePtr) 2688 DPRINTF_SYSCALL(Verbose, "wait4: rusage pointer provided %lx, however " 2689 "functionality not supported. Ignoring rusage pointer.\n", 2690 rusagePtr); 2691 2692 /** 2693 * Currently, wait4 is only implemented so that it will wait for children 2694 * exit conditions which are denoted by a SIGCHLD signals posted into the 2695 * system signal list. We return no additional information via any of the 2696 * parameters supplied to wait4. If nothing is found in the system signal 2697 * list, we will wait indefinitely for SIGCHLD to post by retrying the 2698 * call. 2699 */ 2700 System *sysh = tc->getSystemPtr(); 2701 std::list<BasicSignal>::iterator iter; 2702 for (iter=sysh->signalList.begin(); iter!=sysh->signalList.end(); iter++) { 2703 if (iter->receiver == p) { 2704 if (pid < -1) { 2705 if ((iter->sender->pgid() == -pid) 2706 && (iter->signalValue == OS::TGT_SIGCHLD)) 2707 goto success; 2708 } else if (pid == -1) { 2709 if (iter->signalValue == OS::TGT_SIGCHLD) 2710 goto success; 2711 } else if (pid == 0) { 2712 if ((iter->sender->pgid() == p->pgid()) 2713 && (iter->signalValue == OS::TGT_SIGCHLD)) 2714 goto success; 2715 } else { 2716 if ((iter->sender->pid() == pid) 2717 && (iter->signalValue == OS::TGT_SIGCHLD)) 2718 goto success; 2719 } 2720 } 2721 } 2722 2723 return (options & OS::TGT_WNOHANG) ? 0 : SyscallReturn::retry(); 2724 2725success: 2726 // Set status to EXITED for WIFEXITED evaluations. 2727 const int EXITED = 0; 2728 BufferArg statusBuf(statPtr, sizeof(int)); 2729 *(int *)statusBuf.bufferPtr() = EXITED; 2730 statusBuf.copyOut(tc->getMemProxy()); 2731 2732 // Return the child PID. 2733 pid_t retval = iter->sender->pid(); 2734 sysh->signalList.erase(iter); 2735 return retval; 2736} 2737 2738template <class OS> 2739SyscallReturn 2740acceptFunc(SyscallDesc *desc, int num, ThreadContext *tc) 2741{ 2742 struct sockaddr sa; 2743 socklen_t addrLen; 2744 int host_fd; 2745 int index = 0; 2746 auto p = tc->getProcessPtr(); 2747 int tgt_fd = p->getSyscallArg(tc, index); 2748 Addr addrPtr = p->getSyscallArg(tc, index); 2749 Addr lenPtr = p->getSyscallArg(tc, index); 2750 2751 BufferArg *lenBufPtr = nullptr; 2752 BufferArg *addrBufPtr = nullptr; 2753 2754 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 2755 if (!sfdp) 2756 return -EBADF; 2757 int sim_fd = sfdp->getSimFD(); 2758 2759 /** 2760 * We poll the socket file descriptor first to guarantee that we do not 2761 * block on our accept call. The socket can be opened without the 2762 * non-blocking flag (it blocks). This will cause deadlocks between 2763 * communicating processes. 2764 */ 2765 struct pollfd pfd; 2766 pfd.fd = sim_fd; 2767 pfd.events = POLLIN | POLLPRI; 2768 if ((poll(&pfd, 1, 0) == 0) 2769 && !(sfdp->getFlags() & OS::TGT_O_NONBLOCK)) 2770 return SyscallReturn::retry(); 2771 2772 if (lenPtr) { 2773 lenBufPtr = new BufferArg(lenPtr, sizeof(socklen_t)); 2774 lenBufPtr->copyIn(tc->getMemProxy()); 2775 memcpy(&addrLen, (socklen_t *)lenBufPtr->bufferPtr(), 2776 sizeof(socklen_t)); 2777 } 2778 2779 if (addrPtr) { 2780 addrBufPtr = new BufferArg(addrPtr, sizeof(struct sockaddr)); 2781 addrBufPtr->copyIn(tc->getMemProxy()); 2782 memcpy(&sa, (struct sockaddr *)addrBufPtr->bufferPtr(), 2783 sizeof(struct sockaddr)); 2784 } 2785 2786 host_fd = accept(sim_fd, &sa, &addrLen); 2787 2788 if (host_fd == -1) 2789 return -errno; 2790 2791 if (addrPtr) { 2792 memcpy(addrBufPtr->bufferPtr(), &sa, sizeof(sa)); 2793 addrBufPtr->copyOut(tc->getMemProxy()); 2794 delete(addrBufPtr); 2795 } 2796 2797 if (lenPtr) { 2798 *(socklen_t *)lenBufPtr->bufferPtr() = addrLen; 2799 lenBufPtr->copyOut(tc->getMemProxy()); 2800 delete(lenBufPtr); 2801 } 2802 2803 auto afdp = std::make_shared<SocketFDEntry>(host_fd, sfdp->_domain, 2804 sfdp->_type, sfdp->_protocol); 2805 return p->fds->allocFD(afdp); 2806} 2807 2808/// Target eventfd() function. 2809template <class OS> 2810SyscallReturn 2811eventfdFunc(SyscallDesc *desc, int num, ThreadContext *tc) 2812{ 2813#if defined(__linux__) 2814 int index = 0; 2815 auto p = tc->getProcessPtr(); 2816 unsigned initval = p->getSyscallArg(tc, index); 2817 int in_flags = p->getSyscallArg(tc, index); 2818 2819 int sim_fd = eventfd(initval, in_flags); 2820 if (sim_fd == -1) 2821 return -errno; 2822 2823 bool cloexec = in_flags & OS::TGT_O_CLOEXEC; 2824 2825 int flags = cloexec ? OS::TGT_O_CLOEXEC : 0; 2826 flags |= (in_flags & OS::TGT_O_NONBLOCK) ? OS::TGT_O_NONBLOCK : 0; 2827 2828 auto hbfdp = std::make_shared<HBFDEntry>(flags, sim_fd, cloexec); 2829 int tgt_fd = p->fds->allocFD(hbfdp); 2830 return tgt_fd; 2831#else 2832 warnUnsupportedOS("eventfd"); 2833 return -1; 2834#endif 2835} 2836 2837#endif // __SIM_SYSCALL_EMUL_HH__ 2838