1/* 2 * Copyright (c) 2012-2013, 2015 ARM Limited 3 * Copyright (c) 2015 Advanced Micro Devices, Inc. 4 * All rights reserved 5 * 6 * The license below extends only to copyright in the software and shall 7 * not be construed as granting a license to any other intellectual 8 * property including but not limited to intellectual property relating 9 * to a hardware implementation of the functionality of the software 10 * licensed hereunder. You may use the software subject to the license 11 * terms below provided that you ensure that this notice is replicated 12 * unmodified and in its entirety in all distributions of the software, 13 * modified or unmodified, in source code or in binary form. 14 * 15 * Copyright (c) 2003-2005 The Regents of The University of Michigan 16 * All rights reserved. 17 * 18 * Redistribution and use in source and binary forms, with or without 19 * modification, are permitted provided that the following conditions are 20 * met: redistributions of source code must retain the above copyright 21 * notice, this list of conditions and the following disclaimer; 22 * redistributions in binary form must reproduce the above copyright 23 * notice, this list of conditions and the following disclaimer in the 24 * documentation and/or other materials provided with the distribution; 25 * neither the name of the copyright holders nor the names of its 26 * contributors may be used to endorse or promote products derived from 27 * this software without specific prior written permission. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 30 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 31 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 32 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 33 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 34 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 35 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 36 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 37 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 38 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 39 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 40 * 41 * Authors: Steve Reinhardt 42 * Kevin Lim 43 */ 44 45#ifndef __SIM_SYSCALL_EMUL_HH__ 46#define __SIM_SYSCALL_EMUL_HH__ 47 48#if (defined(__APPLE__) || defined(__OpenBSD__) || \ 49 defined(__FreeBSD__) || defined(__CYGWIN__) || \ 50 defined(__NetBSD__)) 51#define NO_STAT64 1 52#else 53#define NO_STAT64 0 54#endif 55 56#if (defined(__APPLE__) || defined(__OpenBSD__) || \ 57 defined(__FreeBSD__) || defined(__NetBSD__)) 58#define NO_STATFS 1 59#else 60#define NO_STATFS 0 61#endif 62 63#if (defined(__APPLE__) || defined(__OpenBSD__) || \ 64 defined(__FreeBSD__) || defined(__NetBSD__)) 65#define NO_FALLOCATE 1 66#else 67#define NO_FALLOCATE 0 68#endif 69 70/// 71/// @file syscall_emul.hh 72/// 73/// This file defines objects used to emulate syscalls from the target 74/// application on the host machine. 75 76#ifdef __CYGWIN32__ 77#include <sys/fcntl.h> 78 79#endif 80#include <fcntl.h>
| 1/* 2 * Copyright (c) 2012-2013, 2015 ARM Limited 3 * Copyright (c) 2015 Advanced Micro Devices, Inc. 4 * All rights reserved 5 * 6 * The license below extends only to copyright in the software and shall 7 * not be construed as granting a license to any other intellectual 8 * property including but not limited to intellectual property relating 9 * to a hardware implementation of the functionality of the software 10 * licensed hereunder. You may use the software subject to the license 11 * terms below provided that you ensure that this notice is replicated 12 * unmodified and in its entirety in all distributions of the software, 13 * modified or unmodified, in source code or in binary form. 14 * 15 * Copyright (c) 2003-2005 The Regents of The University of Michigan 16 * All rights reserved. 17 * 18 * Redistribution and use in source and binary forms, with or without 19 * modification, are permitted provided that the following conditions are 20 * met: redistributions of source code must retain the above copyright 21 * notice, this list of conditions and the following disclaimer; 22 * redistributions in binary form must reproduce the above copyright 23 * notice, this list of conditions and the following disclaimer in the 24 * documentation and/or other materials provided with the distribution; 25 * neither the name of the copyright holders nor the names of its 26 * contributors may be used to endorse or promote products derived from 27 * this software without specific prior written permission. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 30 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 31 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 32 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 33 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 34 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 35 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 36 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 37 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 38 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 39 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 40 * 41 * Authors: Steve Reinhardt 42 * Kevin Lim 43 */ 44 45#ifndef __SIM_SYSCALL_EMUL_HH__ 46#define __SIM_SYSCALL_EMUL_HH__ 47 48#if (defined(__APPLE__) || defined(__OpenBSD__) || \ 49 defined(__FreeBSD__) || defined(__CYGWIN__) || \ 50 defined(__NetBSD__)) 51#define NO_STAT64 1 52#else 53#define NO_STAT64 0 54#endif 55 56#if (defined(__APPLE__) || defined(__OpenBSD__) || \ 57 defined(__FreeBSD__) || defined(__NetBSD__)) 58#define NO_STATFS 1 59#else 60#define NO_STATFS 0 61#endif 62 63#if (defined(__APPLE__) || defined(__OpenBSD__) || \ 64 defined(__FreeBSD__) || defined(__NetBSD__)) 65#define NO_FALLOCATE 1 66#else 67#define NO_FALLOCATE 0 68#endif 69 70/// 71/// @file syscall_emul.hh 72/// 73/// This file defines objects used to emulate syscalls from the target 74/// application on the host machine. 75 76#ifdef __CYGWIN32__ 77#include <sys/fcntl.h> 78 79#endif 80#include <fcntl.h>
|
| 81#include <poll.h>
|
81#include <sys/mman.h> 82#include <sys/socket.h> 83#include <sys/stat.h> 84#if (NO_STATFS == 0) 85#include <sys/statfs.h> 86#else 87#include <sys/mount.h> 88#endif 89#include <sys/time.h>
| 82#include <sys/mman.h> 83#include <sys/socket.h> 84#include <sys/stat.h> 85#if (NO_STATFS == 0) 86#include <sys/statfs.h> 87#else 88#include <sys/mount.h> 89#endif 90#include <sys/time.h>
|
| 91#include <sys/types.h>
|
90#include <sys/uio.h> 91#include <unistd.h> 92 93#include <cerrno> 94#include <memory> 95#include <string> 96 97#include "arch/generic/tlb.hh" 98#include "arch/utility.hh" 99#include "base/intmath.hh" 100#include "base/loader/object_file.hh" 101#include "base/logging.hh" 102#include "base/trace.hh" 103#include "base/types.hh" 104#include "config/the_isa.hh" 105#include "cpu/base.hh" 106#include "cpu/thread_context.hh" 107#include "mem/page_table.hh" 108#include "params/Process.hh" 109#include "sim/emul_driver.hh" 110#include "sim/futex_map.hh" 111#include "sim/process.hh" 112#include "sim/syscall_debug_macros.hh" 113#include "sim/syscall_desc.hh" 114#include "sim/syscall_emul_buf.hh" 115#include "sim/syscall_return.hh" 116 117////////////////////////////////////////////////////////////////////// 118// 119// The following emulation functions are generic enough that they 120// don't need to be recompiled for different emulated OS's. They are 121// defined in sim/syscall_emul.cc. 122// 123////////////////////////////////////////////////////////////////////// 124 125 126/// Handler for unimplemented syscalls that we haven't thought about. 127SyscallReturn unimplementedFunc(SyscallDesc *desc, int num, 128 Process *p, ThreadContext *tc); 129 130/// Handler for unimplemented syscalls that we never intend to 131/// implement (signal handling, etc.) and should not affect the correct 132/// behavior of the program. Print a warning only if the appropriate 133/// trace flag is enabled. Return success to the target program. 134SyscallReturn ignoreFunc(SyscallDesc *desc, int num, 135 Process *p, ThreadContext *tc); 136 137// Target fallocateFunc() handler. 138SyscallReturn fallocateFunc(SyscallDesc *desc, int num, 139 Process *p, ThreadContext *tc); 140 141/// Target exit() handler: terminate current context. 142SyscallReturn exitFunc(SyscallDesc *desc, int num, 143 Process *p, ThreadContext *tc); 144 145/// Target exit_group() handler: terminate simulation. (exit all threads) 146SyscallReturn exitGroupFunc(SyscallDesc *desc, int num, 147 Process *p, ThreadContext *tc); 148 149/// Target set_tid_address() handler. 150SyscallReturn setTidAddressFunc(SyscallDesc *desc, int num, 151 Process *p, ThreadContext *tc); 152 153/// Target getpagesize() handler. 154SyscallReturn getpagesizeFunc(SyscallDesc *desc, int num, 155 Process *p, ThreadContext *tc); 156 157/// Target brk() handler: set brk address. 158SyscallReturn brkFunc(SyscallDesc *desc, int num, 159 Process *p, ThreadContext *tc); 160 161/// Target close() handler. 162SyscallReturn closeFunc(SyscallDesc *desc, int num, 163 Process *p, ThreadContext *tc); 164
| 92#include <sys/uio.h> 93#include <unistd.h> 94 95#include <cerrno> 96#include <memory> 97#include <string> 98 99#include "arch/generic/tlb.hh" 100#include "arch/utility.hh" 101#include "base/intmath.hh" 102#include "base/loader/object_file.hh" 103#include "base/logging.hh" 104#include "base/trace.hh" 105#include "base/types.hh" 106#include "config/the_isa.hh" 107#include "cpu/base.hh" 108#include "cpu/thread_context.hh" 109#include "mem/page_table.hh" 110#include "params/Process.hh" 111#include "sim/emul_driver.hh" 112#include "sim/futex_map.hh" 113#include "sim/process.hh" 114#include "sim/syscall_debug_macros.hh" 115#include "sim/syscall_desc.hh" 116#include "sim/syscall_emul_buf.hh" 117#include "sim/syscall_return.hh" 118 119////////////////////////////////////////////////////////////////////// 120// 121// The following emulation functions are generic enough that they 122// don't need to be recompiled for different emulated OS's. They are 123// defined in sim/syscall_emul.cc. 124// 125////////////////////////////////////////////////////////////////////// 126 127 128/// Handler for unimplemented syscalls that we haven't thought about. 129SyscallReturn unimplementedFunc(SyscallDesc *desc, int num, 130 Process *p, ThreadContext *tc); 131 132/// Handler for unimplemented syscalls that we never intend to 133/// implement (signal handling, etc.) and should not affect the correct 134/// behavior of the program. Print a warning only if the appropriate 135/// trace flag is enabled. Return success to the target program. 136SyscallReturn ignoreFunc(SyscallDesc *desc, int num, 137 Process *p, ThreadContext *tc); 138 139// Target fallocateFunc() handler. 140SyscallReturn fallocateFunc(SyscallDesc *desc, int num, 141 Process *p, ThreadContext *tc); 142 143/// Target exit() handler: terminate current context. 144SyscallReturn exitFunc(SyscallDesc *desc, int num, 145 Process *p, ThreadContext *tc); 146 147/// Target exit_group() handler: terminate simulation. (exit all threads) 148SyscallReturn exitGroupFunc(SyscallDesc *desc, int num, 149 Process *p, ThreadContext *tc); 150 151/// Target set_tid_address() handler. 152SyscallReturn setTidAddressFunc(SyscallDesc *desc, int num, 153 Process *p, ThreadContext *tc); 154 155/// Target getpagesize() handler. 156SyscallReturn getpagesizeFunc(SyscallDesc *desc, int num, 157 Process *p, ThreadContext *tc); 158 159/// Target brk() handler: set brk address. 160SyscallReturn brkFunc(SyscallDesc *desc, int num, 161 Process *p, ThreadContext *tc); 162 163/// Target close() handler. 164SyscallReturn closeFunc(SyscallDesc *desc, int num, 165 Process *p, ThreadContext *tc); 166
|
165// Target read() handler. 166SyscallReturn readFunc(SyscallDesc *desc, int num, 167 Process *p, ThreadContext *tc); 168 169/// Target write() handler. 170SyscallReturn writeFunc(SyscallDesc *desc, int num, 171 Process *p, ThreadContext *tc); 172
| |
173/// Target lseek() handler. 174SyscallReturn lseekFunc(SyscallDesc *desc, int num, 175 Process *p, ThreadContext *tc); 176 177/// Target _llseek() handler. 178SyscallReturn _llseekFunc(SyscallDesc *desc, int num, 179 Process *p, ThreadContext *tc); 180 181/// Target munmap() handler. 182SyscallReturn munmapFunc(SyscallDesc *desc, int num, 183 Process *p, ThreadContext *tc); 184 185/// Target shutdown() handler. 186SyscallReturn shutdownFunc(SyscallDesc *desc, int num, 187 Process *p, ThreadContext *tc); 188 189/// Target gethostname() handler. 190SyscallReturn gethostnameFunc(SyscallDesc *desc, int num, 191 Process *p, ThreadContext *tc); 192 193/// Target getcwd() handler. 194SyscallReturn getcwdFunc(SyscallDesc *desc, int num, 195 Process *p, ThreadContext *tc); 196 197/// Target readlink() handler. 198SyscallReturn readlinkFunc(SyscallDesc *desc, int num, 199 Process *p, ThreadContext *tc, 200 int index = 0); 201SyscallReturn readlinkFunc(SyscallDesc *desc, int num, 202 Process *p, ThreadContext *tc); 203 204/// Target unlink() handler. 205SyscallReturn unlinkHelper(SyscallDesc *desc, int num, 206 Process *p, ThreadContext *tc, 207 int index); 208SyscallReturn unlinkFunc(SyscallDesc *desc, int num, 209 Process *p, ThreadContext *tc); 210 211/// Target link() handler 212SyscallReturn linkFunc(SyscallDesc *desc, int num, Process *p, 213 ThreadContext *tc); 214 215/// Target symlink() handler. 216SyscallReturn symlinkFunc(SyscallDesc *desc, int num, Process *p, 217 ThreadContext *tc); 218 219/// Target mkdir() handler. 220SyscallReturn mkdirFunc(SyscallDesc *desc, int num, 221 Process *p, ThreadContext *tc); 222 223/// Target mknod() handler. 224SyscallReturn mknodFunc(SyscallDesc *desc, int num, 225 Process *p, ThreadContext *tc); 226 227/// Target chdir() handler. 228SyscallReturn chdirFunc(SyscallDesc *desc, int num, 229 Process *p, ThreadContext *tc); 230 231// Target rmdir() handler. 232SyscallReturn rmdirFunc(SyscallDesc *desc, int num, 233 Process *p, ThreadContext *tc); 234 235/// Target rename() handler. 236SyscallReturn renameFunc(SyscallDesc *desc, int num, 237 Process *p, ThreadContext *tc); 238 239 240/// Target truncate() handler. 241SyscallReturn truncateFunc(SyscallDesc *desc, int num, 242 Process *p, ThreadContext *tc); 243 244 245/// Target ftruncate() handler. 246SyscallReturn ftruncateFunc(SyscallDesc *desc, int num, 247 Process *p, ThreadContext *tc); 248 249 250/// Target truncate64() handler. 251SyscallReturn truncate64Func(SyscallDesc *desc, int num, 252 Process *p, ThreadContext *tc); 253 254/// Target ftruncate64() handler. 255SyscallReturn ftruncate64Func(SyscallDesc *desc, int num, 256 Process *p, ThreadContext *tc); 257 258 259/// Target umask() handler. 260SyscallReturn umaskFunc(SyscallDesc *desc, int num, 261 Process *p, ThreadContext *tc); 262 263/// Target gettid() handler. 264SyscallReturn gettidFunc(SyscallDesc *desc, int num, 265 Process *p, ThreadContext *tc); 266 267/// Target chown() handler. 268SyscallReturn chownFunc(SyscallDesc *desc, int num, 269 Process *p, ThreadContext *tc); 270 271/// Target setpgid() handler. 272SyscallReturn setpgidFunc(SyscallDesc *desc, int num, 273 Process *p, ThreadContext *tc); 274 275/// Target fchown() handler. 276SyscallReturn fchownFunc(SyscallDesc *desc, int num, 277 Process *p, ThreadContext *tc); 278 279/// Target dup() handler. 280SyscallReturn dupFunc(SyscallDesc *desc, int num, 281 Process *process, ThreadContext *tc); 282 283/// Target dup2() handler. 284SyscallReturn dup2Func(SyscallDesc *desc, int num, 285 Process *process, ThreadContext *tc); 286 287/// Target fcntl() handler. 288SyscallReturn fcntlFunc(SyscallDesc *desc, int num, 289 Process *process, ThreadContext *tc); 290 291/// Target fcntl64() handler. 292SyscallReturn fcntl64Func(SyscallDesc *desc, int num, 293 Process *process, ThreadContext *tc); 294 295/// Target setuid() handler. 296SyscallReturn setuidFunc(SyscallDesc *desc, int num, 297 Process *p, ThreadContext *tc); 298 299/// Target pipe() handler. 300SyscallReturn pipeFunc(SyscallDesc *desc, int num, 301 Process *p, ThreadContext *tc); 302 303/// Internal pipe() handler. 304SyscallReturn pipeImpl(SyscallDesc *desc, int num, Process *p, 305 ThreadContext *tc, bool pseudoPipe); 306 307/// Target getpid() handler. 308SyscallReturn getpidFunc(SyscallDesc *desc, int num, 309 Process *p, ThreadContext *tc); 310 311// Target bind() handler. 312SyscallReturn bindFunc(SyscallDesc *desc, int num, 313 Process *p, ThreadContext *tc); 314 315// Target listen() handler. 316SyscallReturn listenFunc(SyscallDesc *desc, int num, 317 Process *p, ThreadContext *tc); 318 319// Target connect() handler. 320SyscallReturn connectFunc(SyscallDesc *desc, int num, 321 Process *p, ThreadContext *tc); 322 323#if defined(SYS_getdents) 324// Target getdents() handler. 325SyscallReturn getdentsFunc(SyscallDesc *desc, int num, 326 Process *p, ThreadContext *tc); 327#endif 328 329#if defined(SYS_getdents64) 330// Target getdents() handler. 331SyscallReturn getdents64Func(SyscallDesc *desc, int num, 332 Process *p, ThreadContext *tc); 333#endif 334 335// Target sendto() handler. 336SyscallReturn sendtoFunc(SyscallDesc *desc, int num, 337 Process *p, ThreadContext *tc); 338 339// Target recvfrom() handler. 340SyscallReturn recvfromFunc(SyscallDesc *desc, int num, 341 Process *p, ThreadContext *tc); 342 343// Target recvmsg() handler. 344SyscallReturn recvmsgFunc(SyscallDesc *desc, int num, 345 Process *p, ThreadContext *tc); 346 347// Target sendmsg() handler. 348SyscallReturn sendmsgFunc(SyscallDesc *desc, int num, 349 Process *p, ThreadContext *tc); 350 351// Target getuid() handler. 352SyscallReturn getuidFunc(SyscallDesc *desc, int num, 353 Process *p, ThreadContext *tc); 354 355/// Target getgid() handler. 356SyscallReturn getgidFunc(SyscallDesc *desc, int num, 357 Process *p, ThreadContext *tc); 358 359/// Target getppid() handler. 360SyscallReturn getppidFunc(SyscallDesc *desc, int num, 361 Process *p, ThreadContext *tc); 362 363/// Target geteuid() handler. 364SyscallReturn geteuidFunc(SyscallDesc *desc, int num, 365 Process *p, ThreadContext *tc); 366 367/// Target getegid() handler. 368SyscallReturn getegidFunc(SyscallDesc *desc, int num, 369 Process *p, ThreadContext *tc); 370 371/// Target access() handler 372SyscallReturn accessFunc(SyscallDesc *desc, int num, 373 Process *p, ThreadContext *tc); 374SyscallReturn accessFunc(SyscallDesc *desc, int num, 375 Process *p, ThreadContext *tc, 376 int index); 377 378/// Futex system call 379/// Implemented by Daniel Sanchez 380/// Used by printf's in multi-threaded apps 381template <class OS> 382SyscallReturn 383futexFunc(SyscallDesc *desc, int callnum, Process *process, 384 ThreadContext *tc) 385{ 386 using namespace std; 387 388 int index = 0; 389 Addr uaddr = process->getSyscallArg(tc, index); 390 int op = process->getSyscallArg(tc, index); 391 int val = process->getSyscallArg(tc, index); 392 393 /* 394 * Unsupported option that does not affect the correctness of the 395 * application. This is a performance optimization utilized by Linux. 396 */ 397 op &= ~OS::TGT_FUTEX_PRIVATE_FLAG; 398 399 FutexMap &futex_map = tc->getSystemPtr()->futexMap; 400 401 if (OS::TGT_FUTEX_WAIT == op) { 402 // Ensure futex system call accessed atomically. 403 BufferArg buf(uaddr, sizeof(int)); 404 buf.copyIn(tc->getMemProxy()); 405 int mem_val = *(int*)buf.bufferPtr(); 406 407 /* 408 * The value in memory at uaddr is not equal with the expected val 409 * (a different thread must have changed it before the system call was 410 * invoked). In this case, we need to throw an error. 411 */ 412 if (val != mem_val) 413 return -OS::TGT_EWOULDBLOCK; 414 415 futex_map.suspend(uaddr, process->tgid(), tc); 416 417 return 0; 418 } else if (OS::TGT_FUTEX_WAKE == op) { 419 return futex_map.wakeup(uaddr, process->tgid(), val); 420 } 421 422 warn("futex: op %d not implemented; ignoring.", op); 423 return -ENOSYS; 424} 425 426 427/// Pseudo Funcs - These functions use a different return convension, 428/// returning a second value in a register other than the normal return register 429SyscallReturn pipePseudoFunc(SyscallDesc *desc, int num, 430 Process *process, ThreadContext *tc); 431 432/// Target getpidPseudo() handler. 433SyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num, 434 Process *p, ThreadContext *tc); 435 436/// Target getuidPseudo() handler. 437SyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num, 438 Process *p, ThreadContext *tc); 439 440/// Target getgidPseudo() handler. 441SyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num, 442 Process *p, ThreadContext *tc); 443 444 445/// A readable name for 1,000,000, for converting microseconds to seconds. 446const int one_million = 1000000; 447/// A readable name for 1,000,000,000, for converting nanoseconds to seconds. 448const int one_billion = 1000000000; 449 450/// Approximate seconds since the epoch (1/1/1970). About a billion, 451/// by my reckoning. We want to keep this a constant (not use the 452/// real-world time) to keep simulations repeatable. 453const unsigned seconds_since_epoch = 1000000000; 454 455/// Helper function to convert current elapsed time to seconds and 456/// microseconds. 457template <class T1, class T2> 458void 459getElapsedTimeMicro(T1 &sec, T2 &usec) 460{ 461 uint64_t elapsed_usecs = curTick() / SimClock::Int::us; 462 sec = elapsed_usecs / one_million; 463 usec = elapsed_usecs % one_million; 464} 465 466/// Helper function to convert current elapsed time to seconds and 467/// nanoseconds. 468template <class T1, class T2> 469void 470getElapsedTimeNano(T1 &sec, T2 &nsec) 471{ 472 uint64_t elapsed_nsecs = curTick() / SimClock::Int::ns; 473 sec = elapsed_nsecs / one_billion; 474 nsec = elapsed_nsecs % one_billion; 475} 476 477////////////////////////////////////////////////////////////////////// 478// 479// The following emulation functions are generic, but need to be 480// templated to account for differences in types, constants, etc. 481// 482////////////////////////////////////////////////////////////////////// 483 484 typedef struct statfs hst_statfs; 485#if NO_STAT64 486 typedef struct stat hst_stat; 487 typedef struct stat hst_stat64; 488#else 489 typedef struct stat hst_stat; 490 typedef struct stat64 hst_stat64; 491#endif 492 493//// Helper function to convert a host stat buffer to a target stat 494//// buffer. Also copies the target buffer out to the simulated 495//// memory space. Used by stat(), fstat(), and lstat(). 496 497template <typename target_stat, typename host_stat> 498void 499convertStatBuf(target_stat &tgt, host_stat *host, bool fakeTTY = false) 500{ 501 using namespace TheISA; 502 503 if (fakeTTY) 504 tgt->st_dev = 0xA; 505 else 506 tgt->st_dev = host->st_dev; 507 tgt->st_dev = TheISA::htog(tgt->st_dev); 508 tgt->st_ino = host->st_ino; 509 tgt->st_ino = TheISA::htog(tgt->st_ino); 510 tgt->st_mode = host->st_mode; 511 if (fakeTTY) { 512 // Claim to be a character device 513 tgt->st_mode &= ~S_IFMT; // Clear S_IFMT 514 tgt->st_mode |= S_IFCHR; // Set S_IFCHR 515 } 516 tgt->st_mode = TheISA::htog(tgt->st_mode); 517 tgt->st_nlink = host->st_nlink; 518 tgt->st_nlink = TheISA::htog(tgt->st_nlink); 519 tgt->st_uid = host->st_uid; 520 tgt->st_uid = TheISA::htog(tgt->st_uid); 521 tgt->st_gid = host->st_gid; 522 tgt->st_gid = TheISA::htog(tgt->st_gid); 523 if (fakeTTY) 524 tgt->st_rdev = 0x880d; 525 else 526 tgt->st_rdev = host->st_rdev; 527 tgt->st_rdev = TheISA::htog(tgt->st_rdev); 528 tgt->st_size = host->st_size; 529 tgt->st_size = TheISA::htog(tgt->st_size); 530 tgt->st_atimeX = host->st_atime; 531 tgt->st_atimeX = TheISA::htog(tgt->st_atimeX); 532 tgt->st_mtimeX = host->st_mtime; 533 tgt->st_mtimeX = TheISA::htog(tgt->st_mtimeX); 534 tgt->st_ctimeX = host->st_ctime; 535 tgt->st_ctimeX = TheISA::htog(tgt->st_ctimeX); 536 // Force the block size to be 8KB. This helps to ensure buffered io works 537 // consistently across different hosts. 538 tgt->st_blksize = 0x2000; 539 tgt->st_blksize = TheISA::htog(tgt->st_blksize); 540 tgt->st_blocks = host->st_blocks; 541 tgt->st_blocks = TheISA::htog(tgt->st_blocks); 542} 543 544// Same for stat64 545 546template <typename target_stat, typename host_stat64> 547void 548convertStat64Buf(target_stat &tgt, host_stat64 *host, bool fakeTTY = false) 549{ 550 using namespace TheISA; 551 552 convertStatBuf<target_stat, host_stat64>(tgt, host, fakeTTY); 553#if defined(STAT_HAVE_NSEC) 554 tgt->st_atime_nsec = host->st_atime_nsec; 555 tgt->st_atime_nsec = TheISA::htog(tgt->st_atime_nsec); 556 tgt->st_mtime_nsec = host->st_mtime_nsec; 557 tgt->st_mtime_nsec = TheISA::htog(tgt->st_mtime_nsec); 558 tgt->st_ctime_nsec = host->st_ctime_nsec; 559 tgt->st_ctime_nsec = TheISA::htog(tgt->st_ctime_nsec); 560#else 561 tgt->st_atime_nsec = 0; 562 tgt->st_mtime_nsec = 0; 563 tgt->st_ctime_nsec = 0; 564#endif 565} 566 567// Here are a couple of convenience functions 568template<class OS> 569void 570copyOutStatBuf(SETranslatingPortProxy &mem, Addr addr, 571 hst_stat *host, bool fakeTTY = false) 572{ 573 typedef TypedBufferArg<typename OS::tgt_stat> tgt_stat_buf; 574 tgt_stat_buf tgt(addr); 575 convertStatBuf<tgt_stat_buf, hst_stat>(tgt, host, fakeTTY); 576 tgt.copyOut(mem); 577} 578 579template<class OS> 580void 581copyOutStat64Buf(SETranslatingPortProxy &mem, Addr addr, 582 hst_stat64 *host, bool fakeTTY = false) 583{ 584 typedef TypedBufferArg<typename OS::tgt_stat64> tgt_stat_buf; 585 tgt_stat_buf tgt(addr); 586 convertStat64Buf<tgt_stat_buf, hst_stat64>(tgt, host, fakeTTY); 587 tgt.copyOut(mem); 588} 589 590template <class OS> 591void 592copyOutStatfsBuf(SETranslatingPortProxy &mem, Addr addr, 593 hst_statfs *host) 594{ 595 TypedBufferArg<typename OS::tgt_statfs> tgt(addr); 596 597 tgt->f_type = TheISA::htog(host->f_type); 598#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) 599 tgt->f_bsize = TheISA::htog(host->f_iosize); 600#else 601 tgt->f_bsize = TheISA::htog(host->f_bsize); 602#endif 603 tgt->f_blocks = TheISA::htog(host->f_blocks); 604 tgt->f_bfree = TheISA::htog(host->f_bfree); 605 tgt->f_bavail = TheISA::htog(host->f_bavail); 606 tgt->f_files = TheISA::htog(host->f_files); 607 tgt->f_ffree = TheISA::htog(host->f_ffree); 608 memcpy(&tgt->f_fsid, &host->f_fsid, sizeof(host->f_fsid)); 609#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) 610 tgt->f_namelen = TheISA::htog(host->f_namemax); 611 tgt->f_frsize = TheISA::htog(host->f_bsize); 612#elif defined(__APPLE__) 613 tgt->f_namelen = 0; 614 tgt->f_frsize = 0; 615#else 616 tgt->f_namelen = TheISA::htog(host->f_namelen); 617 tgt->f_frsize = TheISA::htog(host->f_frsize); 618#endif 619#if defined(__linux__) 620 memcpy(&tgt->f_spare, &host->f_spare, sizeof(host->f_spare)); 621#else 622 /* 623 * The fields are different sizes per OS. Don't bother with 624 * f_spare or f_reserved on non-Linux for now. 625 */ 626 memset(&tgt->f_spare, 0, sizeof(tgt->f_spare)); 627#endif 628 629 tgt.copyOut(mem); 630} 631 632/// Target ioctl() handler. For the most part, programs call ioctl() 633/// only to find out if their stdout is a tty, to determine whether to 634/// do line or block buffering. We always claim that output fds are 635/// not TTYs to provide repeatable results. 636template <class OS> 637SyscallReturn 638ioctlFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 639{ 640 int index = 0; 641 int tgt_fd = p->getSyscallArg(tc, index); 642 unsigned req = p->getSyscallArg(tc, index); 643 644 DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", tgt_fd, req); 645 646 if (OS::isTtyReq(req)) 647 return -ENOTTY; 648 649 auto dfdp = std::dynamic_pointer_cast<DeviceFDEntry>((*p->fds)[tgt_fd]); 650 if (!dfdp) 651 return -EBADF; 652 653 /** 654 * If the driver is valid, issue the ioctl through it. Otherwise, 655 * there's an implicit assumption that the device is a TTY type and we 656 * return that we do not have a valid TTY. 657 */ 658 EmulatedDriver *emul_driver = dfdp->getDriver(); 659 if (emul_driver) 660 return emul_driver->ioctl(p, tc, req); 661 662 /** 663 * For lack of a better return code, return ENOTTY. Ideally, we should 664 * return something better here, but at least we issue the warning. 665 */ 666 warn("Unsupported ioctl call (return ENOTTY): ioctl(%d, 0x%x, ...) @ \n", 667 tgt_fd, req, tc->pcState()); 668 return -ENOTTY; 669} 670 671template <class OS> 672SyscallReturn 673openImpl(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc, 674 bool isopenat) 675{ 676 int index = 0; 677 int tgt_dirfd = -1; 678 679 /** 680 * If using the openat variant, read in the target directory file 681 * descriptor from the simulated process. 682 */ 683 if (isopenat) 684 tgt_dirfd = p->getSyscallArg(tc, index); 685 686 /** 687 * Retrieve the simulated process' memory proxy and then read in the path 688 * string from that memory space into the host's working memory space. 689 */ 690 std::string path; 691 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 692 return -EFAULT; 693 694#ifdef __CYGWIN32__ 695 int host_flags = O_BINARY; 696#else 697 int host_flags = 0; 698#endif 699 /** 700 * Translate target flags into host flags. Flags exist which are not 701 * ported between architectures which can cause check failures. 702 */ 703 int tgt_flags = p->getSyscallArg(tc, index); 704 for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) { 705 if (tgt_flags & OS::openFlagTable[i].tgtFlag) { 706 tgt_flags &= ~OS::openFlagTable[i].tgtFlag; 707 host_flags |= OS::openFlagTable[i].hostFlag; 708 } 709 } 710 if (tgt_flags) { 711 warn("open%s: cannot decode flags 0x%x", 712 isopenat ? "at" : "", tgt_flags); 713 } 714#ifdef __CYGWIN32__ 715 host_flags |= O_BINARY; 716#endif 717 718 int mode = p->getSyscallArg(tc, index); 719 720 /** 721 * If the simulated process called open or openat with AT_FDCWD specified, 722 * take the current working directory value which was passed into the 723 * process class as a Python parameter and append the current path to 724 * create a full path. 725 * Otherwise, openat with a valid target directory file descriptor has 726 * been called. If the path option, which was passed in as a parameter, 727 * is not absolute, retrieve the directory file descriptor's path and 728 * prepend it to the path passed in as a parameter. 729 * In every case, we should have a full path (which is relevant to the 730 * host) to work with after this block has been passed. 731 */ 732 if (!isopenat || (isopenat && tgt_dirfd == OS::TGT_AT_FDCWD)) { 733 path = p->fullPath(path); 734 } else if (!startswith(path, "/")) { 735 std::shared_ptr<FDEntry> fdep = ((*p->fds)[tgt_dirfd]); 736 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep); 737 if (!ffdp) 738 return -EBADF; 739 path.insert(0, ffdp->getFileName() + "/"); 740 } 741 742 /** 743 * Since this is an emulated environment, we create pseudo file 744 * descriptors for device requests that have been registered with 745 * the process class through Python; this allows us to create a file 746 * descriptor for subsequent ioctl or mmap calls. 747 */ 748 if (startswith(path, "/dev/")) { 749 std::string filename = path.substr(strlen("/dev/")); 750 EmulatedDriver *drv = p->findDriver(filename); 751 if (drv) { 752 DPRINTF_SYSCALL(Verbose, "open%s: passing call to " 753 "driver open with path[%s]\n", 754 isopenat ? "at" : "", path.c_str()); 755 return drv->open(p, tc, mode, host_flags); 756 } 757 /** 758 * Fall through here for pass through to host devices, such 759 * as /dev/zero 760 */ 761 } 762 763 /** 764 * Some special paths and files cannot be called on the host and need 765 * to be handled as special cases inside the simulator. 766 * If the full path that was created above does not match any of the 767 * special cases, pass it through to the open call on the host to let 768 * the host open the file on our behalf. 769 * If the host cannot open the file, return the host's error code back 770 * through the system call to the simulated process. 771 */ 772 int sim_fd = -1; 773 std::vector<std::string> special_paths = 774 { "/proc/", "/system/", "/sys/", "/platform/", "/etc/passwd" }; 775 for (auto entry : special_paths) { 776 if (startswith(path, entry)) 777 sim_fd = OS::openSpecialFile(path, p, tc); 778 } 779 if (sim_fd == -1) { 780 sim_fd = open(path.c_str(), host_flags, mode); 781 } 782 if (sim_fd == -1) { 783 int local = -errno; 784 DPRINTF_SYSCALL(Verbose, "open%s: failed -> path:%s\n", 785 isopenat ? "at" : "", path.c_str()); 786 return local; 787 } 788 789 /** 790 * The file was opened successfully and needs to be recorded in the 791 * process' file descriptor array so that it can be retrieved later. 792 * The target file descriptor that is chosen will be the lowest unused 793 * file descriptor. 794 * Return the indirect target file descriptor back to the simulated 795 * process to act as a handle for the opened file. 796 */ 797 auto ffdp = std::make_shared<FileFDEntry>(sim_fd, host_flags, path, 0); 798 int tgt_fd = p->fds->allocFD(ffdp); 799 DPRINTF_SYSCALL(Verbose, "open%s: sim_fd[%d], target_fd[%d] -> path:%s\n", 800 isopenat ? "at" : "", sim_fd, tgt_fd, path.c_str()); 801 return tgt_fd; 802} 803 804/// Target open() handler. 805template <class OS> 806SyscallReturn 807openFunc(SyscallDesc *desc, int callnum, Process *process, 808 ThreadContext *tc) 809{ 810 return openImpl<OS>(desc, callnum, process, tc, false); 811} 812 813/// Target openat() handler. 814template <class OS> 815SyscallReturn 816openatFunc(SyscallDesc *desc, int callnum, Process *process, 817 ThreadContext *tc) 818{ 819 return openImpl<OS>(desc, callnum, process, tc, true); 820} 821 822/// Target unlinkat() handler. 823template <class OS> 824SyscallReturn 825unlinkatFunc(SyscallDesc *desc, int callnum, Process *process, 826 ThreadContext *tc) 827{ 828 int index = 0; 829 int dirfd = process->getSyscallArg(tc, index); 830 if (dirfd != OS::TGT_AT_FDCWD) 831 warn("unlinkat: first argument not AT_FDCWD; unlikely to work"); 832 833 return unlinkHelper(desc, callnum, process, tc, 1); 834} 835 836/// Target facessat() handler 837template <class OS> 838SyscallReturn 839faccessatFunc(SyscallDesc *desc, int callnum, Process *process, 840 ThreadContext *tc) 841{ 842 int index = 0; 843 int dirfd = process->getSyscallArg(tc, index); 844 if (dirfd != OS::TGT_AT_FDCWD) 845 warn("faccessat: first argument not AT_FDCWD; unlikely to work"); 846 return accessFunc(desc, callnum, process, tc, 1); 847} 848 849/// Target readlinkat() handler 850template <class OS> 851SyscallReturn 852readlinkatFunc(SyscallDesc *desc, int callnum, Process *process, 853 ThreadContext *tc) 854{ 855 int index = 0; 856 int dirfd = process->getSyscallArg(tc, index); 857 if (dirfd != OS::TGT_AT_FDCWD) 858 warn("openat: first argument not AT_FDCWD; unlikely to work"); 859 return readlinkFunc(desc, callnum, process, tc, 1); 860} 861 862/// Target renameat() handler. 863template <class OS> 864SyscallReturn 865renameatFunc(SyscallDesc *desc, int callnum, Process *process, 866 ThreadContext *tc) 867{ 868 int index = 0; 869 870 int olddirfd = process->getSyscallArg(tc, index); 871 if (olddirfd != OS::TGT_AT_FDCWD) 872 warn("renameat: first argument not AT_FDCWD; unlikely to work"); 873 874 std::string old_name; 875 876 if (!tc->getMemProxy().tryReadString(old_name, 877 process->getSyscallArg(tc, index))) 878 return -EFAULT; 879 880 int newdirfd = process->getSyscallArg(tc, index); 881 if (newdirfd != OS::TGT_AT_FDCWD) 882 warn("renameat: third argument not AT_FDCWD; unlikely to work"); 883 884 std::string new_name; 885 886 if (!tc->getMemProxy().tryReadString(new_name, 887 process->getSyscallArg(tc, index))) 888 return -EFAULT; 889 890 // Adjust path for current working directory 891 old_name = process->fullPath(old_name); 892 new_name = process->fullPath(new_name); 893 894 int result = rename(old_name.c_str(), new_name.c_str()); 895 return (result == -1) ? -errno : result; 896} 897 898/// Target sysinfo() handler. 899template <class OS> 900SyscallReturn 901sysinfoFunc(SyscallDesc *desc, int callnum, Process *process, 902 ThreadContext *tc) 903{ 904 905 int index = 0; 906 TypedBufferArg<typename OS::tgt_sysinfo> 907 sysinfo(process->getSyscallArg(tc, index)); 908 909 sysinfo->uptime = seconds_since_epoch; 910 sysinfo->totalram = process->system->memSize(); 911 sysinfo->mem_unit = 1; 912 913 sysinfo.copyOut(tc->getMemProxy()); 914 915 return 0; 916} 917 918/// Target chmod() handler. 919template <class OS> 920SyscallReturn 921chmodFunc(SyscallDesc *desc, int callnum, Process *process, 922 ThreadContext *tc) 923{ 924 std::string path; 925 926 int index = 0; 927 if (!tc->getMemProxy().tryReadString(path, 928 process->getSyscallArg(tc, index))) { 929 return -EFAULT; 930 } 931 932 uint32_t mode = process->getSyscallArg(tc, index); 933 mode_t hostMode = 0; 934 935 // XXX translate mode flags via OS::something??? 936 hostMode = mode; 937 938 // Adjust path for current working directory 939 path = process->fullPath(path); 940 941 // do the chmod 942 int result = chmod(path.c_str(), hostMode); 943 if (result < 0) 944 return -errno; 945 946 return 0; 947} 948
| 167/// Target lseek() handler. 168SyscallReturn lseekFunc(SyscallDesc *desc, int num, 169 Process *p, ThreadContext *tc); 170 171/// Target _llseek() handler. 172SyscallReturn _llseekFunc(SyscallDesc *desc, int num, 173 Process *p, ThreadContext *tc); 174 175/// Target munmap() handler. 176SyscallReturn munmapFunc(SyscallDesc *desc, int num, 177 Process *p, ThreadContext *tc); 178 179/// Target shutdown() handler. 180SyscallReturn shutdownFunc(SyscallDesc *desc, int num, 181 Process *p, ThreadContext *tc); 182 183/// Target gethostname() handler. 184SyscallReturn gethostnameFunc(SyscallDesc *desc, int num, 185 Process *p, ThreadContext *tc); 186 187/// Target getcwd() handler. 188SyscallReturn getcwdFunc(SyscallDesc *desc, int num, 189 Process *p, ThreadContext *tc); 190 191/// Target readlink() handler. 192SyscallReturn readlinkFunc(SyscallDesc *desc, int num, 193 Process *p, ThreadContext *tc, 194 int index = 0); 195SyscallReturn readlinkFunc(SyscallDesc *desc, int num, 196 Process *p, ThreadContext *tc); 197 198/// Target unlink() handler. 199SyscallReturn unlinkHelper(SyscallDesc *desc, int num, 200 Process *p, ThreadContext *tc, 201 int index); 202SyscallReturn unlinkFunc(SyscallDesc *desc, int num, 203 Process *p, ThreadContext *tc); 204 205/// Target link() handler 206SyscallReturn linkFunc(SyscallDesc *desc, int num, Process *p, 207 ThreadContext *tc); 208 209/// Target symlink() handler. 210SyscallReturn symlinkFunc(SyscallDesc *desc, int num, Process *p, 211 ThreadContext *tc); 212 213/// Target mkdir() handler. 214SyscallReturn mkdirFunc(SyscallDesc *desc, int num, 215 Process *p, ThreadContext *tc); 216 217/// Target mknod() handler. 218SyscallReturn mknodFunc(SyscallDesc *desc, int num, 219 Process *p, ThreadContext *tc); 220 221/// Target chdir() handler. 222SyscallReturn chdirFunc(SyscallDesc *desc, int num, 223 Process *p, ThreadContext *tc); 224 225// Target rmdir() handler. 226SyscallReturn rmdirFunc(SyscallDesc *desc, int num, 227 Process *p, ThreadContext *tc); 228 229/// Target rename() handler. 230SyscallReturn renameFunc(SyscallDesc *desc, int num, 231 Process *p, ThreadContext *tc); 232 233 234/// Target truncate() handler. 235SyscallReturn truncateFunc(SyscallDesc *desc, int num, 236 Process *p, ThreadContext *tc); 237 238 239/// Target ftruncate() handler. 240SyscallReturn ftruncateFunc(SyscallDesc *desc, int num, 241 Process *p, ThreadContext *tc); 242 243 244/// Target truncate64() handler. 245SyscallReturn truncate64Func(SyscallDesc *desc, int num, 246 Process *p, ThreadContext *tc); 247 248/// Target ftruncate64() handler. 249SyscallReturn ftruncate64Func(SyscallDesc *desc, int num, 250 Process *p, ThreadContext *tc); 251 252 253/// Target umask() handler. 254SyscallReturn umaskFunc(SyscallDesc *desc, int num, 255 Process *p, ThreadContext *tc); 256 257/// Target gettid() handler. 258SyscallReturn gettidFunc(SyscallDesc *desc, int num, 259 Process *p, ThreadContext *tc); 260 261/// Target chown() handler. 262SyscallReturn chownFunc(SyscallDesc *desc, int num, 263 Process *p, ThreadContext *tc); 264 265/// Target setpgid() handler. 266SyscallReturn setpgidFunc(SyscallDesc *desc, int num, 267 Process *p, ThreadContext *tc); 268 269/// Target fchown() handler. 270SyscallReturn fchownFunc(SyscallDesc *desc, int num, 271 Process *p, ThreadContext *tc); 272 273/// Target dup() handler. 274SyscallReturn dupFunc(SyscallDesc *desc, int num, 275 Process *process, ThreadContext *tc); 276 277/// Target dup2() handler. 278SyscallReturn dup2Func(SyscallDesc *desc, int num, 279 Process *process, ThreadContext *tc); 280 281/// Target fcntl() handler. 282SyscallReturn fcntlFunc(SyscallDesc *desc, int num, 283 Process *process, ThreadContext *tc); 284 285/// Target fcntl64() handler. 286SyscallReturn fcntl64Func(SyscallDesc *desc, int num, 287 Process *process, ThreadContext *tc); 288 289/// Target setuid() handler. 290SyscallReturn setuidFunc(SyscallDesc *desc, int num, 291 Process *p, ThreadContext *tc); 292 293/// Target pipe() handler. 294SyscallReturn pipeFunc(SyscallDesc *desc, int num, 295 Process *p, ThreadContext *tc); 296 297/// Internal pipe() handler. 298SyscallReturn pipeImpl(SyscallDesc *desc, int num, Process *p, 299 ThreadContext *tc, bool pseudoPipe); 300 301/// Target getpid() handler. 302SyscallReturn getpidFunc(SyscallDesc *desc, int num, 303 Process *p, ThreadContext *tc); 304 305// Target bind() handler. 306SyscallReturn bindFunc(SyscallDesc *desc, int num, 307 Process *p, ThreadContext *tc); 308 309// Target listen() handler. 310SyscallReturn listenFunc(SyscallDesc *desc, int num, 311 Process *p, ThreadContext *tc); 312 313// Target connect() handler. 314SyscallReturn connectFunc(SyscallDesc *desc, int num, 315 Process *p, ThreadContext *tc); 316 317#if defined(SYS_getdents) 318// Target getdents() handler. 319SyscallReturn getdentsFunc(SyscallDesc *desc, int num, 320 Process *p, ThreadContext *tc); 321#endif 322 323#if defined(SYS_getdents64) 324// Target getdents() handler. 325SyscallReturn getdents64Func(SyscallDesc *desc, int num, 326 Process *p, ThreadContext *tc); 327#endif 328 329// Target sendto() handler. 330SyscallReturn sendtoFunc(SyscallDesc *desc, int num, 331 Process *p, ThreadContext *tc); 332 333// Target recvfrom() handler. 334SyscallReturn recvfromFunc(SyscallDesc *desc, int num, 335 Process *p, ThreadContext *tc); 336 337// Target recvmsg() handler. 338SyscallReturn recvmsgFunc(SyscallDesc *desc, int num, 339 Process *p, ThreadContext *tc); 340 341// Target sendmsg() handler. 342SyscallReturn sendmsgFunc(SyscallDesc *desc, int num, 343 Process *p, ThreadContext *tc); 344 345// Target getuid() handler. 346SyscallReturn getuidFunc(SyscallDesc *desc, int num, 347 Process *p, ThreadContext *tc); 348 349/// Target getgid() handler. 350SyscallReturn getgidFunc(SyscallDesc *desc, int num, 351 Process *p, ThreadContext *tc); 352 353/// Target getppid() handler. 354SyscallReturn getppidFunc(SyscallDesc *desc, int num, 355 Process *p, ThreadContext *tc); 356 357/// Target geteuid() handler. 358SyscallReturn geteuidFunc(SyscallDesc *desc, int num, 359 Process *p, ThreadContext *tc); 360 361/// Target getegid() handler. 362SyscallReturn getegidFunc(SyscallDesc *desc, int num, 363 Process *p, ThreadContext *tc); 364 365/// Target access() handler 366SyscallReturn accessFunc(SyscallDesc *desc, int num, 367 Process *p, ThreadContext *tc); 368SyscallReturn accessFunc(SyscallDesc *desc, int num, 369 Process *p, ThreadContext *tc, 370 int index); 371 372/// Futex system call 373/// Implemented by Daniel Sanchez 374/// Used by printf's in multi-threaded apps 375template <class OS> 376SyscallReturn 377futexFunc(SyscallDesc *desc, int callnum, Process *process, 378 ThreadContext *tc) 379{ 380 using namespace std; 381 382 int index = 0; 383 Addr uaddr = process->getSyscallArg(tc, index); 384 int op = process->getSyscallArg(tc, index); 385 int val = process->getSyscallArg(tc, index); 386 387 /* 388 * Unsupported option that does not affect the correctness of the 389 * application. This is a performance optimization utilized by Linux. 390 */ 391 op &= ~OS::TGT_FUTEX_PRIVATE_FLAG; 392 393 FutexMap &futex_map = tc->getSystemPtr()->futexMap; 394 395 if (OS::TGT_FUTEX_WAIT == op) { 396 // Ensure futex system call accessed atomically. 397 BufferArg buf(uaddr, sizeof(int)); 398 buf.copyIn(tc->getMemProxy()); 399 int mem_val = *(int*)buf.bufferPtr(); 400 401 /* 402 * The value in memory at uaddr is not equal with the expected val 403 * (a different thread must have changed it before the system call was 404 * invoked). In this case, we need to throw an error. 405 */ 406 if (val != mem_val) 407 return -OS::TGT_EWOULDBLOCK; 408 409 futex_map.suspend(uaddr, process->tgid(), tc); 410 411 return 0; 412 } else if (OS::TGT_FUTEX_WAKE == op) { 413 return futex_map.wakeup(uaddr, process->tgid(), val); 414 } 415 416 warn("futex: op %d not implemented; ignoring.", op); 417 return -ENOSYS; 418} 419 420 421/// Pseudo Funcs - These functions use a different return convension, 422/// returning a second value in a register other than the normal return register 423SyscallReturn pipePseudoFunc(SyscallDesc *desc, int num, 424 Process *process, ThreadContext *tc); 425 426/// Target getpidPseudo() handler. 427SyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num, 428 Process *p, ThreadContext *tc); 429 430/// Target getuidPseudo() handler. 431SyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num, 432 Process *p, ThreadContext *tc); 433 434/// Target getgidPseudo() handler. 435SyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num, 436 Process *p, ThreadContext *tc); 437 438 439/// A readable name for 1,000,000, for converting microseconds to seconds. 440const int one_million = 1000000; 441/// A readable name for 1,000,000,000, for converting nanoseconds to seconds. 442const int one_billion = 1000000000; 443 444/// Approximate seconds since the epoch (1/1/1970). About a billion, 445/// by my reckoning. We want to keep this a constant (not use the 446/// real-world time) to keep simulations repeatable. 447const unsigned seconds_since_epoch = 1000000000; 448 449/// Helper function to convert current elapsed time to seconds and 450/// microseconds. 451template <class T1, class T2> 452void 453getElapsedTimeMicro(T1 &sec, T2 &usec) 454{ 455 uint64_t elapsed_usecs = curTick() / SimClock::Int::us; 456 sec = elapsed_usecs / one_million; 457 usec = elapsed_usecs % one_million; 458} 459 460/// Helper function to convert current elapsed time to seconds and 461/// nanoseconds. 462template <class T1, class T2> 463void 464getElapsedTimeNano(T1 &sec, T2 &nsec) 465{ 466 uint64_t elapsed_nsecs = curTick() / SimClock::Int::ns; 467 sec = elapsed_nsecs / one_billion; 468 nsec = elapsed_nsecs % one_billion; 469} 470 471////////////////////////////////////////////////////////////////////// 472// 473// The following emulation functions are generic, but need to be 474// templated to account for differences in types, constants, etc. 475// 476////////////////////////////////////////////////////////////////////// 477 478 typedef struct statfs hst_statfs; 479#if NO_STAT64 480 typedef struct stat hst_stat; 481 typedef struct stat hst_stat64; 482#else 483 typedef struct stat hst_stat; 484 typedef struct stat64 hst_stat64; 485#endif 486 487//// Helper function to convert a host stat buffer to a target stat 488//// buffer. Also copies the target buffer out to the simulated 489//// memory space. Used by stat(), fstat(), and lstat(). 490 491template <typename target_stat, typename host_stat> 492void 493convertStatBuf(target_stat &tgt, host_stat *host, bool fakeTTY = false) 494{ 495 using namespace TheISA; 496 497 if (fakeTTY) 498 tgt->st_dev = 0xA; 499 else 500 tgt->st_dev = host->st_dev; 501 tgt->st_dev = TheISA::htog(tgt->st_dev); 502 tgt->st_ino = host->st_ino; 503 tgt->st_ino = TheISA::htog(tgt->st_ino); 504 tgt->st_mode = host->st_mode; 505 if (fakeTTY) { 506 // Claim to be a character device 507 tgt->st_mode &= ~S_IFMT; // Clear S_IFMT 508 tgt->st_mode |= S_IFCHR; // Set S_IFCHR 509 } 510 tgt->st_mode = TheISA::htog(tgt->st_mode); 511 tgt->st_nlink = host->st_nlink; 512 tgt->st_nlink = TheISA::htog(tgt->st_nlink); 513 tgt->st_uid = host->st_uid; 514 tgt->st_uid = TheISA::htog(tgt->st_uid); 515 tgt->st_gid = host->st_gid; 516 tgt->st_gid = TheISA::htog(tgt->st_gid); 517 if (fakeTTY) 518 tgt->st_rdev = 0x880d; 519 else 520 tgt->st_rdev = host->st_rdev; 521 tgt->st_rdev = TheISA::htog(tgt->st_rdev); 522 tgt->st_size = host->st_size; 523 tgt->st_size = TheISA::htog(tgt->st_size); 524 tgt->st_atimeX = host->st_atime; 525 tgt->st_atimeX = TheISA::htog(tgt->st_atimeX); 526 tgt->st_mtimeX = host->st_mtime; 527 tgt->st_mtimeX = TheISA::htog(tgt->st_mtimeX); 528 tgt->st_ctimeX = host->st_ctime; 529 tgt->st_ctimeX = TheISA::htog(tgt->st_ctimeX); 530 // Force the block size to be 8KB. This helps to ensure buffered io works 531 // consistently across different hosts. 532 tgt->st_blksize = 0x2000; 533 tgt->st_blksize = TheISA::htog(tgt->st_blksize); 534 tgt->st_blocks = host->st_blocks; 535 tgt->st_blocks = TheISA::htog(tgt->st_blocks); 536} 537 538// Same for stat64 539 540template <typename target_stat, typename host_stat64> 541void 542convertStat64Buf(target_stat &tgt, host_stat64 *host, bool fakeTTY = false) 543{ 544 using namespace TheISA; 545 546 convertStatBuf<target_stat, host_stat64>(tgt, host, fakeTTY); 547#if defined(STAT_HAVE_NSEC) 548 tgt->st_atime_nsec = host->st_atime_nsec; 549 tgt->st_atime_nsec = TheISA::htog(tgt->st_atime_nsec); 550 tgt->st_mtime_nsec = host->st_mtime_nsec; 551 tgt->st_mtime_nsec = TheISA::htog(tgt->st_mtime_nsec); 552 tgt->st_ctime_nsec = host->st_ctime_nsec; 553 tgt->st_ctime_nsec = TheISA::htog(tgt->st_ctime_nsec); 554#else 555 tgt->st_atime_nsec = 0; 556 tgt->st_mtime_nsec = 0; 557 tgt->st_ctime_nsec = 0; 558#endif 559} 560 561// Here are a couple of convenience functions 562template<class OS> 563void 564copyOutStatBuf(SETranslatingPortProxy &mem, Addr addr, 565 hst_stat *host, bool fakeTTY = false) 566{ 567 typedef TypedBufferArg<typename OS::tgt_stat> tgt_stat_buf; 568 tgt_stat_buf tgt(addr); 569 convertStatBuf<tgt_stat_buf, hst_stat>(tgt, host, fakeTTY); 570 tgt.copyOut(mem); 571} 572 573template<class OS> 574void 575copyOutStat64Buf(SETranslatingPortProxy &mem, Addr addr, 576 hst_stat64 *host, bool fakeTTY = false) 577{ 578 typedef TypedBufferArg<typename OS::tgt_stat64> tgt_stat_buf; 579 tgt_stat_buf tgt(addr); 580 convertStat64Buf<tgt_stat_buf, hst_stat64>(tgt, host, fakeTTY); 581 tgt.copyOut(mem); 582} 583 584template <class OS> 585void 586copyOutStatfsBuf(SETranslatingPortProxy &mem, Addr addr, 587 hst_statfs *host) 588{ 589 TypedBufferArg<typename OS::tgt_statfs> tgt(addr); 590 591 tgt->f_type = TheISA::htog(host->f_type); 592#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) 593 tgt->f_bsize = TheISA::htog(host->f_iosize); 594#else 595 tgt->f_bsize = TheISA::htog(host->f_bsize); 596#endif 597 tgt->f_blocks = TheISA::htog(host->f_blocks); 598 tgt->f_bfree = TheISA::htog(host->f_bfree); 599 tgt->f_bavail = TheISA::htog(host->f_bavail); 600 tgt->f_files = TheISA::htog(host->f_files); 601 tgt->f_ffree = TheISA::htog(host->f_ffree); 602 memcpy(&tgt->f_fsid, &host->f_fsid, sizeof(host->f_fsid)); 603#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) 604 tgt->f_namelen = TheISA::htog(host->f_namemax); 605 tgt->f_frsize = TheISA::htog(host->f_bsize); 606#elif defined(__APPLE__) 607 tgt->f_namelen = 0; 608 tgt->f_frsize = 0; 609#else 610 tgt->f_namelen = TheISA::htog(host->f_namelen); 611 tgt->f_frsize = TheISA::htog(host->f_frsize); 612#endif 613#if defined(__linux__) 614 memcpy(&tgt->f_spare, &host->f_spare, sizeof(host->f_spare)); 615#else 616 /* 617 * The fields are different sizes per OS. Don't bother with 618 * f_spare or f_reserved on non-Linux for now. 619 */ 620 memset(&tgt->f_spare, 0, sizeof(tgt->f_spare)); 621#endif 622 623 tgt.copyOut(mem); 624} 625 626/// Target ioctl() handler. For the most part, programs call ioctl() 627/// only to find out if their stdout is a tty, to determine whether to 628/// do line or block buffering. We always claim that output fds are 629/// not TTYs to provide repeatable results. 630template <class OS> 631SyscallReturn 632ioctlFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 633{ 634 int index = 0; 635 int tgt_fd = p->getSyscallArg(tc, index); 636 unsigned req = p->getSyscallArg(tc, index); 637 638 DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", tgt_fd, req); 639 640 if (OS::isTtyReq(req)) 641 return -ENOTTY; 642 643 auto dfdp = std::dynamic_pointer_cast<DeviceFDEntry>((*p->fds)[tgt_fd]); 644 if (!dfdp) 645 return -EBADF; 646 647 /** 648 * If the driver is valid, issue the ioctl through it. Otherwise, 649 * there's an implicit assumption that the device is a TTY type and we 650 * return that we do not have a valid TTY. 651 */ 652 EmulatedDriver *emul_driver = dfdp->getDriver(); 653 if (emul_driver) 654 return emul_driver->ioctl(p, tc, req); 655 656 /** 657 * For lack of a better return code, return ENOTTY. Ideally, we should 658 * return something better here, but at least we issue the warning. 659 */ 660 warn("Unsupported ioctl call (return ENOTTY): ioctl(%d, 0x%x, ...) @ \n", 661 tgt_fd, req, tc->pcState()); 662 return -ENOTTY; 663} 664 665template <class OS> 666SyscallReturn 667openImpl(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc, 668 bool isopenat) 669{ 670 int index = 0; 671 int tgt_dirfd = -1; 672 673 /** 674 * If using the openat variant, read in the target directory file 675 * descriptor from the simulated process. 676 */ 677 if (isopenat) 678 tgt_dirfd = p->getSyscallArg(tc, index); 679 680 /** 681 * Retrieve the simulated process' memory proxy and then read in the path 682 * string from that memory space into the host's working memory space. 683 */ 684 std::string path; 685 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 686 return -EFAULT; 687 688#ifdef __CYGWIN32__ 689 int host_flags = O_BINARY; 690#else 691 int host_flags = 0; 692#endif 693 /** 694 * Translate target flags into host flags. Flags exist which are not 695 * ported between architectures which can cause check failures. 696 */ 697 int tgt_flags = p->getSyscallArg(tc, index); 698 for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) { 699 if (tgt_flags & OS::openFlagTable[i].tgtFlag) { 700 tgt_flags &= ~OS::openFlagTable[i].tgtFlag; 701 host_flags |= OS::openFlagTable[i].hostFlag; 702 } 703 } 704 if (tgt_flags) { 705 warn("open%s: cannot decode flags 0x%x", 706 isopenat ? "at" : "", tgt_flags); 707 } 708#ifdef __CYGWIN32__ 709 host_flags |= O_BINARY; 710#endif 711 712 int mode = p->getSyscallArg(tc, index); 713 714 /** 715 * If the simulated process called open or openat with AT_FDCWD specified, 716 * take the current working directory value which was passed into the 717 * process class as a Python parameter and append the current path to 718 * create a full path. 719 * Otherwise, openat with a valid target directory file descriptor has 720 * been called. If the path option, which was passed in as a parameter, 721 * is not absolute, retrieve the directory file descriptor's path and 722 * prepend it to the path passed in as a parameter. 723 * In every case, we should have a full path (which is relevant to the 724 * host) to work with after this block has been passed. 725 */ 726 if (!isopenat || (isopenat && tgt_dirfd == OS::TGT_AT_FDCWD)) { 727 path = p->fullPath(path); 728 } else if (!startswith(path, "/")) { 729 std::shared_ptr<FDEntry> fdep = ((*p->fds)[tgt_dirfd]); 730 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep); 731 if (!ffdp) 732 return -EBADF; 733 path.insert(0, ffdp->getFileName() + "/"); 734 } 735 736 /** 737 * Since this is an emulated environment, we create pseudo file 738 * descriptors for device requests that have been registered with 739 * the process class through Python; this allows us to create a file 740 * descriptor for subsequent ioctl or mmap calls. 741 */ 742 if (startswith(path, "/dev/")) { 743 std::string filename = path.substr(strlen("/dev/")); 744 EmulatedDriver *drv = p->findDriver(filename); 745 if (drv) { 746 DPRINTF_SYSCALL(Verbose, "open%s: passing call to " 747 "driver open with path[%s]\n", 748 isopenat ? "at" : "", path.c_str()); 749 return drv->open(p, tc, mode, host_flags); 750 } 751 /** 752 * Fall through here for pass through to host devices, such 753 * as /dev/zero 754 */ 755 } 756 757 /** 758 * Some special paths and files cannot be called on the host and need 759 * to be handled as special cases inside the simulator. 760 * If the full path that was created above does not match any of the 761 * special cases, pass it through to the open call on the host to let 762 * the host open the file on our behalf. 763 * If the host cannot open the file, return the host's error code back 764 * through the system call to the simulated process. 765 */ 766 int sim_fd = -1; 767 std::vector<std::string> special_paths = 768 { "/proc/", "/system/", "/sys/", "/platform/", "/etc/passwd" }; 769 for (auto entry : special_paths) { 770 if (startswith(path, entry)) 771 sim_fd = OS::openSpecialFile(path, p, tc); 772 } 773 if (sim_fd == -1) { 774 sim_fd = open(path.c_str(), host_flags, mode); 775 } 776 if (sim_fd == -1) { 777 int local = -errno; 778 DPRINTF_SYSCALL(Verbose, "open%s: failed -> path:%s\n", 779 isopenat ? "at" : "", path.c_str()); 780 return local; 781 } 782 783 /** 784 * The file was opened successfully and needs to be recorded in the 785 * process' file descriptor array so that it can be retrieved later. 786 * The target file descriptor that is chosen will be the lowest unused 787 * file descriptor. 788 * Return the indirect target file descriptor back to the simulated 789 * process to act as a handle for the opened file. 790 */ 791 auto ffdp = std::make_shared<FileFDEntry>(sim_fd, host_flags, path, 0); 792 int tgt_fd = p->fds->allocFD(ffdp); 793 DPRINTF_SYSCALL(Verbose, "open%s: sim_fd[%d], target_fd[%d] -> path:%s\n", 794 isopenat ? "at" : "", sim_fd, tgt_fd, path.c_str()); 795 return tgt_fd; 796} 797 798/// Target open() handler. 799template <class OS> 800SyscallReturn 801openFunc(SyscallDesc *desc, int callnum, Process *process, 802 ThreadContext *tc) 803{ 804 return openImpl<OS>(desc, callnum, process, tc, false); 805} 806 807/// Target openat() handler. 808template <class OS> 809SyscallReturn 810openatFunc(SyscallDesc *desc, int callnum, Process *process, 811 ThreadContext *tc) 812{ 813 return openImpl<OS>(desc, callnum, process, tc, true); 814} 815 816/// Target unlinkat() handler. 817template <class OS> 818SyscallReturn 819unlinkatFunc(SyscallDesc *desc, int callnum, Process *process, 820 ThreadContext *tc) 821{ 822 int index = 0; 823 int dirfd = process->getSyscallArg(tc, index); 824 if (dirfd != OS::TGT_AT_FDCWD) 825 warn("unlinkat: first argument not AT_FDCWD; unlikely to work"); 826 827 return unlinkHelper(desc, callnum, process, tc, 1); 828} 829 830/// Target facessat() handler 831template <class OS> 832SyscallReturn 833faccessatFunc(SyscallDesc *desc, int callnum, Process *process, 834 ThreadContext *tc) 835{ 836 int index = 0; 837 int dirfd = process->getSyscallArg(tc, index); 838 if (dirfd != OS::TGT_AT_FDCWD) 839 warn("faccessat: first argument not AT_FDCWD; unlikely to work"); 840 return accessFunc(desc, callnum, process, tc, 1); 841} 842 843/// Target readlinkat() handler 844template <class OS> 845SyscallReturn 846readlinkatFunc(SyscallDesc *desc, int callnum, Process *process, 847 ThreadContext *tc) 848{ 849 int index = 0; 850 int dirfd = process->getSyscallArg(tc, index); 851 if (dirfd != OS::TGT_AT_FDCWD) 852 warn("openat: first argument not AT_FDCWD; unlikely to work"); 853 return readlinkFunc(desc, callnum, process, tc, 1); 854} 855 856/// Target renameat() handler. 857template <class OS> 858SyscallReturn 859renameatFunc(SyscallDesc *desc, int callnum, Process *process, 860 ThreadContext *tc) 861{ 862 int index = 0; 863 864 int olddirfd = process->getSyscallArg(tc, index); 865 if (olddirfd != OS::TGT_AT_FDCWD) 866 warn("renameat: first argument not AT_FDCWD; unlikely to work"); 867 868 std::string old_name; 869 870 if (!tc->getMemProxy().tryReadString(old_name, 871 process->getSyscallArg(tc, index))) 872 return -EFAULT; 873 874 int newdirfd = process->getSyscallArg(tc, index); 875 if (newdirfd != OS::TGT_AT_FDCWD) 876 warn("renameat: third argument not AT_FDCWD; unlikely to work"); 877 878 std::string new_name; 879 880 if (!tc->getMemProxy().tryReadString(new_name, 881 process->getSyscallArg(tc, index))) 882 return -EFAULT; 883 884 // Adjust path for current working directory 885 old_name = process->fullPath(old_name); 886 new_name = process->fullPath(new_name); 887 888 int result = rename(old_name.c_str(), new_name.c_str()); 889 return (result == -1) ? -errno : result; 890} 891 892/// Target sysinfo() handler. 893template <class OS> 894SyscallReturn 895sysinfoFunc(SyscallDesc *desc, int callnum, Process *process, 896 ThreadContext *tc) 897{ 898 899 int index = 0; 900 TypedBufferArg<typename OS::tgt_sysinfo> 901 sysinfo(process->getSyscallArg(tc, index)); 902 903 sysinfo->uptime = seconds_since_epoch; 904 sysinfo->totalram = process->system->memSize(); 905 sysinfo->mem_unit = 1; 906 907 sysinfo.copyOut(tc->getMemProxy()); 908 909 return 0; 910} 911 912/// Target chmod() handler. 913template <class OS> 914SyscallReturn 915chmodFunc(SyscallDesc *desc, int callnum, Process *process, 916 ThreadContext *tc) 917{ 918 std::string path; 919 920 int index = 0; 921 if (!tc->getMemProxy().tryReadString(path, 922 process->getSyscallArg(tc, index))) { 923 return -EFAULT; 924 } 925 926 uint32_t mode = process->getSyscallArg(tc, index); 927 mode_t hostMode = 0; 928 929 // XXX translate mode flags via OS::something??? 930 hostMode = mode; 931 932 // Adjust path for current working directory 933 path = process->fullPath(path); 934 935 // do the chmod 936 int result = chmod(path.c_str(), hostMode); 937 if (result < 0) 938 return -errno; 939 940 return 0; 941} 942
|
| 943template <class OS> 944SyscallReturn 945pollFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 946{ 947 int index = 0; 948 Addr fdsPtr = p->getSyscallArg(tc, index); 949 int nfds = p->getSyscallArg(tc, index); 950 int tmout = p->getSyscallArg(tc, index);
|
949
| 951
|
| 952 BufferArg fdsBuf(fdsPtr, sizeof(struct pollfd) * nfds); 953 fdsBuf.copyIn(tc->getMemProxy()); 954 955 /** 956 * Record the target file descriptors in a local variable. We need to 957 * replace them with host file descriptors but we need a temporary copy 958 * for later. Afterwards, replace each target file descriptor in the 959 * poll_fd array with its host_fd. 960 */ 961 int temp_tgt_fds[nfds]; 962 for (index = 0; index < nfds; index++) { 963 temp_tgt_fds[index] = ((struct pollfd *)fdsBuf.bufferPtr())[index].fd; 964 auto tgt_fd = temp_tgt_fds[index]; 965 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 966 if (!hbfdp) 967 return -EBADF; 968 auto host_fd = hbfdp->getSimFD(); 969 ((struct pollfd *)fdsBuf.bufferPtr())[index].fd = host_fd; 970 } 971 972 /** 973 * We cannot allow an infinite poll to occur or it will inevitably cause 974 * a deadlock in the gem5 simulator with clone. We must pass in tmout with 975 * a non-negative value, however it also makes no sense to poll on the 976 * underlying host for any other time than tmout a zero timeout. 977 */ 978 int status; 979 if (tmout < 0) { 980 status = poll((struct pollfd *)fdsBuf.bufferPtr(), nfds, 0); 981 if (status == 0) { 982 /** 983 * If blocking indefinitely, check the signal list to see if a 984 * signal would break the poll out of the retry cycle and try 985 * to return the signal interrupt instead. 986 */ 987 System *sysh = tc->getSystemPtr(); 988 std::list<BasicSignal>::iterator it; 989 for (it=sysh->signalList.begin(); it!=sysh->signalList.end(); it++) 990 if (it->receiver == p) 991 return -EINTR; 992 return SyscallReturn::retry(); 993 } 994 } else 995 status = poll((struct pollfd *)fdsBuf.bufferPtr(), nfds, 0); 996 997 if (status == -1) 998 return -errno; 999 1000 /** 1001 * Replace each host_fd in the returned poll_fd array with its original 1002 * target file descriptor. 1003 */ 1004 for (index = 0; index < nfds; index++) { 1005 auto tgt_fd = temp_tgt_fds[index]; 1006 ((struct pollfd *)fdsBuf.bufferPtr())[index].fd = tgt_fd; 1007 } 1008 1009 /** 1010 * Copy out the pollfd struct because the host may have updated fields 1011 * in the structure. 1012 */ 1013 fdsBuf.copyOut(tc->getMemProxy()); 1014 1015 return status; 1016} 1017
|
950/// Target fchmod() handler. 951template <class OS> 952SyscallReturn 953fchmodFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 954{ 955 int index = 0; 956 int tgt_fd = p->getSyscallArg(tc, index); 957 uint32_t mode = p->getSyscallArg(tc, index); 958 959 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 960 if (!ffdp) 961 return -EBADF; 962 int sim_fd = ffdp->getSimFD(); 963 964 mode_t hostMode = mode; 965 966 int result = fchmod(sim_fd, hostMode); 967 968 return (result < 0) ? -errno : 0; 969} 970 971/// Target mremap() handler. 972template <class OS> 973SyscallReturn 974mremapFunc(SyscallDesc *desc, int callnum, Process *process, ThreadContext *tc) 975{ 976 int index = 0; 977 Addr start = process->getSyscallArg(tc, index); 978 uint64_t old_length = process->getSyscallArg(tc, index); 979 uint64_t new_length = process->getSyscallArg(tc, index); 980 uint64_t flags = process->getSyscallArg(tc, index); 981 uint64_t provided_address = 0; 982 bool use_provided_address = flags & OS::TGT_MREMAP_FIXED; 983 984 if (use_provided_address) 985 provided_address = process->getSyscallArg(tc, index); 986 987 if ((start % TheISA::PageBytes != 0) || 988 (provided_address % TheISA::PageBytes != 0)) { 989 warn("mremap failing: arguments not page aligned"); 990 return -EINVAL; 991 } 992 993 new_length = roundUp(new_length, TheISA::PageBytes); 994 995 if (new_length > old_length) { 996 std::shared_ptr<MemState> mem_state = process->memState; 997 Addr mmap_end = mem_state->getMmapEnd(); 998 999 if ((start + old_length) == mmap_end && 1000 (!use_provided_address || provided_address == start)) { 1001 // This case cannot occur when growing downward, as 1002 // start is greater than or equal to mmap_end. 1003 uint64_t diff = new_length - old_length; 1004 process->allocateMem(mmap_end, diff); 1005 mem_state->setMmapEnd(mmap_end + diff); 1006 return start; 1007 } else { 1008 if (!use_provided_address && !(flags & OS::TGT_MREMAP_MAYMOVE)) { 1009 warn("can't remap here and MREMAP_MAYMOVE flag not set\n"); 1010 return -ENOMEM; 1011 } else { 1012 uint64_t new_start = provided_address; 1013 if (!use_provided_address) { 1014 new_start = process->mmapGrowsDown() ? 1015 mmap_end - new_length : mmap_end; 1016 mmap_end = process->mmapGrowsDown() ? 1017 new_start : mmap_end + new_length; 1018 mem_state->setMmapEnd(mmap_end); 1019 } 1020 1021 process->pTable->remap(start, old_length, new_start); 1022 warn("mremapping to new vaddr %08p-%08p, adding %d\n", 1023 new_start, new_start + new_length, 1024 new_length - old_length); 1025 // add on the remaining unallocated pages 1026 process->allocateMem(new_start + old_length, 1027 new_length - old_length, 1028 use_provided_address /* clobber */); 1029 if (use_provided_address && 1030 ((new_start + new_length > mem_state->getMmapEnd() && 1031 !process->mmapGrowsDown()) || 1032 (new_start < mem_state->getMmapEnd() && 1033 process->mmapGrowsDown()))) { 1034 // something fishy going on here, at least notify the user 1035 // @todo: increase mmap_end? 1036 warn("mmap region limit exceeded with MREMAP_FIXED\n"); 1037 } 1038 warn("returning %08p as start\n", new_start); 1039 return new_start; 1040 } 1041 } 1042 } else { 1043 if (use_provided_address && provided_address != start) 1044 process->pTable->remap(start, new_length, provided_address); 1045 process->pTable->unmap(start + new_length, old_length - new_length); 1046 return use_provided_address ? provided_address : start; 1047 } 1048} 1049 1050/// Target stat() handler. 1051template <class OS> 1052SyscallReturn 1053statFunc(SyscallDesc *desc, int callnum, Process *process, 1054 ThreadContext *tc) 1055{ 1056 std::string path; 1057 1058 int index = 0; 1059 if (!tc->getMemProxy().tryReadString(path, 1060 process->getSyscallArg(tc, index))) { 1061 return -EFAULT; 1062 } 1063 Addr bufPtr = process->getSyscallArg(tc, index); 1064 1065 // Adjust path for current working directory 1066 path = process->fullPath(path); 1067 1068 struct stat hostBuf; 1069 int result = stat(path.c_str(), &hostBuf); 1070 1071 if (result < 0) 1072 return -errno; 1073 1074 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1075 1076 return 0; 1077} 1078 1079 1080/// Target stat64() handler. 1081template <class OS> 1082SyscallReturn 1083stat64Func(SyscallDesc *desc, int callnum, Process *process, 1084 ThreadContext *tc) 1085{ 1086 std::string path; 1087 1088 int index = 0; 1089 if (!tc->getMemProxy().tryReadString(path, 1090 process->getSyscallArg(tc, index))) 1091 return -EFAULT; 1092 Addr bufPtr = process->getSyscallArg(tc, index); 1093 1094 // Adjust path for current working directory 1095 path = process->fullPath(path); 1096 1097#if NO_STAT64 1098 struct stat hostBuf; 1099 int result = stat(path.c_str(), &hostBuf); 1100#else 1101 struct stat64 hostBuf; 1102 int result = stat64(path.c_str(), &hostBuf); 1103#endif 1104 1105 if (result < 0) 1106 return -errno; 1107 1108 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1109 1110 return 0; 1111} 1112 1113 1114/// Target fstatat64() handler. 1115template <class OS> 1116SyscallReturn 1117fstatat64Func(SyscallDesc *desc, int callnum, Process *process, 1118 ThreadContext *tc) 1119{ 1120 int index = 0; 1121 int dirfd = process->getSyscallArg(tc, index); 1122 if (dirfd != OS::TGT_AT_FDCWD) 1123 warn("fstatat64: first argument not AT_FDCWD; unlikely to work"); 1124 1125 std::string path; 1126 if (!tc->getMemProxy().tryReadString(path, 1127 process->getSyscallArg(tc, index))) 1128 return -EFAULT; 1129 Addr bufPtr = process->getSyscallArg(tc, index); 1130 1131 // Adjust path for current working directory 1132 path = process->fullPath(path); 1133 1134#if NO_STAT64 1135 struct stat hostBuf; 1136 int result = stat(path.c_str(), &hostBuf); 1137#else 1138 struct stat64 hostBuf; 1139 int result = stat64(path.c_str(), &hostBuf); 1140#endif 1141 1142 if (result < 0) 1143 return -errno; 1144 1145 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1146 1147 return 0; 1148} 1149 1150 1151/// Target fstat64() handler. 1152template <class OS> 1153SyscallReturn 1154fstat64Func(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1155{ 1156 int index = 0; 1157 int tgt_fd = p->getSyscallArg(tc, index); 1158 Addr bufPtr = p->getSyscallArg(tc, index); 1159 1160 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 1161 if (!ffdp) 1162 return -EBADF; 1163 int sim_fd = ffdp->getSimFD(); 1164 1165#if NO_STAT64 1166 struct stat hostBuf; 1167 int result = fstat(sim_fd, &hostBuf); 1168#else 1169 struct stat64 hostBuf; 1170 int result = fstat64(sim_fd, &hostBuf); 1171#endif 1172 1173 if (result < 0) 1174 return -errno; 1175 1176 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (sim_fd == 1)); 1177 1178 return 0; 1179} 1180 1181 1182/// Target lstat() handler. 1183template <class OS> 1184SyscallReturn 1185lstatFunc(SyscallDesc *desc, int callnum, Process *process, 1186 ThreadContext *tc) 1187{ 1188 std::string path; 1189 1190 int index = 0; 1191 if (!tc->getMemProxy().tryReadString(path, 1192 process->getSyscallArg(tc, index))) { 1193 return -EFAULT; 1194 } 1195 Addr bufPtr = process->getSyscallArg(tc, index); 1196 1197 // Adjust path for current working directory 1198 path = process->fullPath(path); 1199 1200 struct stat hostBuf; 1201 int result = lstat(path.c_str(), &hostBuf); 1202 1203 if (result < 0) 1204 return -errno; 1205 1206 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1207 1208 return 0; 1209} 1210 1211/// Target lstat64() handler. 1212template <class OS> 1213SyscallReturn 1214lstat64Func(SyscallDesc *desc, int callnum, Process *process, 1215 ThreadContext *tc) 1216{ 1217 std::string path; 1218 1219 int index = 0; 1220 if (!tc->getMemProxy().tryReadString(path, 1221 process->getSyscallArg(tc, index))) { 1222 return -EFAULT; 1223 } 1224 Addr bufPtr = process->getSyscallArg(tc, index); 1225 1226 // Adjust path for current working directory 1227 path = process->fullPath(path); 1228 1229#if NO_STAT64 1230 struct stat hostBuf; 1231 int result = lstat(path.c_str(), &hostBuf); 1232#else 1233 struct stat64 hostBuf; 1234 int result = lstat64(path.c_str(), &hostBuf); 1235#endif 1236 1237 if (result < 0) 1238 return -errno; 1239 1240 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1241 1242 return 0; 1243} 1244 1245/// Target fstat() handler. 1246template <class OS> 1247SyscallReturn 1248fstatFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1249{ 1250 int index = 0; 1251 int tgt_fd = p->getSyscallArg(tc, index); 1252 Addr bufPtr = p->getSyscallArg(tc, index); 1253 1254 DPRINTF_SYSCALL(Verbose, "fstat(%d, ...)\n", tgt_fd); 1255 1256 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 1257 if (!ffdp) 1258 return -EBADF; 1259 int sim_fd = ffdp->getSimFD(); 1260 1261 struct stat hostBuf; 1262 int result = fstat(sim_fd, &hostBuf); 1263 1264 if (result < 0) 1265 return -errno; 1266 1267 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (sim_fd == 1)); 1268 1269 return 0; 1270} 1271
| 1018/// Target fchmod() handler. 1019template <class OS> 1020SyscallReturn 1021fchmodFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1022{ 1023 int index = 0; 1024 int tgt_fd = p->getSyscallArg(tc, index); 1025 uint32_t mode = p->getSyscallArg(tc, index); 1026 1027 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 1028 if (!ffdp) 1029 return -EBADF; 1030 int sim_fd = ffdp->getSimFD(); 1031 1032 mode_t hostMode = mode; 1033 1034 int result = fchmod(sim_fd, hostMode); 1035 1036 return (result < 0) ? -errno : 0; 1037} 1038 1039/// Target mremap() handler. 1040template <class OS> 1041SyscallReturn 1042mremapFunc(SyscallDesc *desc, int callnum, Process *process, ThreadContext *tc) 1043{ 1044 int index = 0; 1045 Addr start = process->getSyscallArg(tc, index); 1046 uint64_t old_length = process->getSyscallArg(tc, index); 1047 uint64_t new_length = process->getSyscallArg(tc, index); 1048 uint64_t flags = process->getSyscallArg(tc, index); 1049 uint64_t provided_address = 0; 1050 bool use_provided_address = flags & OS::TGT_MREMAP_FIXED; 1051 1052 if (use_provided_address) 1053 provided_address = process->getSyscallArg(tc, index); 1054 1055 if ((start % TheISA::PageBytes != 0) || 1056 (provided_address % TheISA::PageBytes != 0)) { 1057 warn("mremap failing: arguments not page aligned"); 1058 return -EINVAL; 1059 } 1060 1061 new_length = roundUp(new_length, TheISA::PageBytes); 1062 1063 if (new_length > old_length) { 1064 std::shared_ptr<MemState> mem_state = process->memState; 1065 Addr mmap_end = mem_state->getMmapEnd(); 1066 1067 if ((start + old_length) == mmap_end && 1068 (!use_provided_address || provided_address == start)) { 1069 // This case cannot occur when growing downward, as 1070 // start is greater than or equal to mmap_end. 1071 uint64_t diff = new_length - old_length; 1072 process->allocateMem(mmap_end, diff); 1073 mem_state->setMmapEnd(mmap_end + diff); 1074 return start; 1075 } else { 1076 if (!use_provided_address && !(flags & OS::TGT_MREMAP_MAYMOVE)) { 1077 warn("can't remap here and MREMAP_MAYMOVE flag not set\n"); 1078 return -ENOMEM; 1079 } else { 1080 uint64_t new_start = provided_address; 1081 if (!use_provided_address) { 1082 new_start = process->mmapGrowsDown() ? 1083 mmap_end - new_length : mmap_end; 1084 mmap_end = process->mmapGrowsDown() ? 1085 new_start : mmap_end + new_length; 1086 mem_state->setMmapEnd(mmap_end); 1087 } 1088 1089 process->pTable->remap(start, old_length, new_start); 1090 warn("mremapping to new vaddr %08p-%08p, adding %d\n", 1091 new_start, new_start + new_length, 1092 new_length - old_length); 1093 // add on the remaining unallocated pages 1094 process->allocateMem(new_start + old_length, 1095 new_length - old_length, 1096 use_provided_address /* clobber */); 1097 if (use_provided_address && 1098 ((new_start + new_length > mem_state->getMmapEnd() && 1099 !process->mmapGrowsDown()) || 1100 (new_start < mem_state->getMmapEnd() && 1101 process->mmapGrowsDown()))) { 1102 // something fishy going on here, at least notify the user 1103 // @todo: increase mmap_end? 1104 warn("mmap region limit exceeded with MREMAP_FIXED\n"); 1105 } 1106 warn("returning %08p as start\n", new_start); 1107 return new_start; 1108 } 1109 } 1110 } else { 1111 if (use_provided_address && provided_address != start) 1112 process->pTable->remap(start, new_length, provided_address); 1113 process->pTable->unmap(start + new_length, old_length - new_length); 1114 return use_provided_address ? provided_address : start; 1115 } 1116} 1117 1118/// Target stat() handler. 1119template <class OS> 1120SyscallReturn 1121statFunc(SyscallDesc *desc, int callnum, Process *process, 1122 ThreadContext *tc) 1123{ 1124 std::string path; 1125 1126 int index = 0; 1127 if (!tc->getMemProxy().tryReadString(path, 1128 process->getSyscallArg(tc, index))) { 1129 return -EFAULT; 1130 } 1131 Addr bufPtr = process->getSyscallArg(tc, index); 1132 1133 // Adjust path for current working directory 1134 path = process->fullPath(path); 1135 1136 struct stat hostBuf; 1137 int result = stat(path.c_str(), &hostBuf); 1138 1139 if (result < 0) 1140 return -errno; 1141 1142 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1143 1144 return 0; 1145} 1146 1147 1148/// Target stat64() handler. 1149template <class OS> 1150SyscallReturn 1151stat64Func(SyscallDesc *desc, int callnum, Process *process, 1152 ThreadContext *tc) 1153{ 1154 std::string path; 1155 1156 int index = 0; 1157 if (!tc->getMemProxy().tryReadString(path, 1158 process->getSyscallArg(tc, index))) 1159 return -EFAULT; 1160 Addr bufPtr = process->getSyscallArg(tc, index); 1161 1162 // Adjust path for current working directory 1163 path = process->fullPath(path); 1164 1165#if NO_STAT64 1166 struct stat hostBuf; 1167 int result = stat(path.c_str(), &hostBuf); 1168#else 1169 struct stat64 hostBuf; 1170 int result = stat64(path.c_str(), &hostBuf); 1171#endif 1172 1173 if (result < 0) 1174 return -errno; 1175 1176 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1177 1178 return 0; 1179} 1180 1181 1182/// Target fstatat64() handler. 1183template <class OS> 1184SyscallReturn 1185fstatat64Func(SyscallDesc *desc, int callnum, Process *process, 1186 ThreadContext *tc) 1187{ 1188 int index = 0; 1189 int dirfd = process->getSyscallArg(tc, index); 1190 if (dirfd != OS::TGT_AT_FDCWD) 1191 warn("fstatat64: first argument not AT_FDCWD; unlikely to work"); 1192 1193 std::string path; 1194 if (!tc->getMemProxy().tryReadString(path, 1195 process->getSyscallArg(tc, index))) 1196 return -EFAULT; 1197 Addr bufPtr = process->getSyscallArg(tc, index); 1198 1199 // Adjust path for current working directory 1200 path = process->fullPath(path); 1201 1202#if NO_STAT64 1203 struct stat hostBuf; 1204 int result = stat(path.c_str(), &hostBuf); 1205#else 1206 struct stat64 hostBuf; 1207 int result = stat64(path.c_str(), &hostBuf); 1208#endif 1209 1210 if (result < 0) 1211 return -errno; 1212 1213 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1214 1215 return 0; 1216} 1217 1218 1219/// Target fstat64() handler. 1220template <class OS> 1221SyscallReturn 1222fstat64Func(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1223{ 1224 int index = 0; 1225 int tgt_fd = p->getSyscallArg(tc, index); 1226 Addr bufPtr = p->getSyscallArg(tc, index); 1227 1228 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 1229 if (!ffdp) 1230 return -EBADF; 1231 int sim_fd = ffdp->getSimFD(); 1232 1233#if NO_STAT64 1234 struct stat hostBuf; 1235 int result = fstat(sim_fd, &hostBuf); 1236#else 1237 struct stat64 hostBuf; 1238 int result = fstat64(sim_fd, &hostBuf); 1239#endif 1240 1241 if (result < 0) 1242 return -errno; 1243 1244 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (sim_fd == 1)); 1245 1246 return 0; 1247} 1248 1249 1250/// Target lstat() handler. 1251template <class OS> 1252SyscallReturn 1253lstatFunc(SyscallDesc *desc, int callnum, Process *process, 1254 ThreadContext *tc) 1255{ 1256 std::string path; 1257 1258 int index = 0; 1259 if (!tc->getMemProxy().tryReadString(path, 1260 process->getSyscallArg(tc, index))) { 1261 return -EFAULT; 1262 } 1263 Addr bufPtr = process->getSyscallArg(tc, index); 1264 1265 // Adjust path for current working directory 1266 path = process->fullPath(path); 1267 1268 struct stat hostBuf; 1269 int result = lstat(path.c_str(), &hostBuf); 1270 1271 if (result < 0) 1272 return -errno; 1273 1274 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1275 1276 return 0; 1277} 1278 1279/// Target lstat64() handler. 1280template <class OS> 1281SyscallReturn 1282lstat64Func(SyscallDesc *desc, int callnum, Process *process, 1283 ThreadContext *tc) 1284{ 1285 std::string path; 1286 1287 int index = 0; 1288 if (!tc->getMemProxy().tryReadString(path, 1289 process->getSyscallArg(tc, index))) { 1290 return -EFAULT; 1291 } 1292 Addr bufPtr = process->getSyscallArg(tc, index); 1293 1294 // Adjust path for current working directory 1295 path = process->fullPath(path); 1296 1297#if NO_STAT64 1298 struct stat hostBuf; 1299 int result = lstat(path.c_str(), &hostBuf); 1300#else 1301 struct stat64 hostBuf; 1302 int result = lstat64(path.c_str(), &hostBuf); 1303#endif 1304 1305 if (result < 0) 1306 return -errno; 1307 1308 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1309 1310 return 0; 1311} 1312 1313/// Target fstat() handler. 1314template <class OS> 1315SyscallReturn 1316fstatFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1317{ 1318 int index = 0; 1319 int tgt_fd = p->getSyscallArg(tc, index); 1320 Addr bufPtr = p->getSyscallArg(tc, index); 1321 1322 DPRINTF_SYSCALL(Verbose, "fstat(%d, ...)\n", tgt_fd); 1323 1324 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 1325 if (!ffdp) 1326 return -EBADF; 1327 int sim_fd = ffdp->getSimFD(); 1328 1329 struct stat hostBuf; 1330 int result = fstat(sim_fd, &hostBuf); 1331 1332 if (result < 0) 1333 return -errno; 1334 1335 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (sim_fd == 1)); 1336 1337 return 0; 1338} 1339
|
1272
| |
1273/// Target statfs() handler. 1274template <class OS> 1275SyscallReturn 1276statfsFunc(SyscallDesc *desc, int callnum, Process *process, 1277 ThreadContext *tc) 1278{ 1279#if NO_STATFS 1280 warn("Host OS cannot support calls to statfs. Ignoring syscall"); 1281#else 1282 std::string path; 1283 1284 int index = 0; 1285 if (!tc->getMemProxy().tryReadString(path, 1286 process->getSyscallArg(tc, index))) { 1287 return -EFAULT; 1288 } 1289 Addr bufPtr = process->getSyscallArg(tc, index); 1290 1291 // Adjust path for current working directory 1292 path = process->fullPath(path); 1293 1294 struct statfs hostBuf; 1295 int result = statfs(path.c_str(), &hostBuf); 1296 1297 if (result < 0) 1298 return -errno; 1299 1300 copyOutStatfsBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1301#endif 1302 return 0; 1303} 1304 1305template <class OS> 1306SyscallReturn 1307cloneFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1308{ 1309 int index = 0; 1310 1311 RegVal flags = p->getSyscallArg(tc, index); 1312 RegVal newStack = p->getSyscallArg(tc, index); 1313 Addr ptidPtr = p->getSyscallArg(tc, index); 1314 1315#if THE_ISA == RISCV_ISA or THE_ISA == ARM_ISA 1316 /** 1317 * Linux sets CLONE_BACKWARDS flag for RISC-V and Arm. 1318 * The flag defines the list of clone() arguments in the following 1319 * order: flags -> newStack -> ptidPtr -> tlsPtr -> ctidPtr 1320 */ 1321 Addr tlsPtr = p->getSyscallArg(tc, index); 1322 Addr ctidPtr = p->getSyscallArg(tc, index); 1323#else 1324 Addr ctidPtr = p->getSyscallArg(tc, index); 1325 Addr tlsPtr = p->getSyscallArg(tc, index); 1326#endif 1327 1328 if (((flags & OS::TGT_CLONE_SIGHAND)&& !(flags & OS::TGT_CLONE_VM)) || 1329 ((flags & OS::TGT_CLONE_THREAD) && !(flags & OS::TGT_CLONE_SIGHAND)) || 1330 ((flags & OS::TGT_CLONE_FS) && (flags & OS::TGT_CLONE_NEWNS)) || 1331 ((flags & OS::TGT_CLONE_NEWIPC) && (flags & OS::TGT_CLONE_SYSVSEM)) || 1332 ((flags & OS::TGT_CLONE_NEWPID) && (flags & OS::TGT_CLONE_THREAD)) || 1333 ((flags & OS::TGT_CLONE_VM) && !(newStack))) 1334 return -EINVAL; 1335 1336 ThreadContext *ctc; 1337 if (!(ctc = p->findFreeContext())) 1338 fatal("clone: no spare thread context in system"); 1339 1340 /** 1341 * Note that ProcessParams is generated by swig and there are no other 1342 * examples of how to create anything but this default constructor. The 1343 * fields are manually initialized instead of passing parameters to the 1344 * constructor. 1345 */ 1346 ProcessParams *pp = new ProcessParams(); 1347 pp->executable.assign(*(new std::string(p->progName()))); 1348 pp->cmd.push_back(*(new std::string(p->progName()))); 1349 pp->system = p->system; 1350 pp->cwd.assign(p->getcwd()); 1351 pp->input.assign("stdin"); 1352 pp->output.assign("stdout"); 1353 pp->errout.assign("stderr"); 1354 pp->uid = p->uid(); 1355 pp->euid = p->euid(); 1356 pp->gid = p->gid(); 1357 pp->egid = p->egid(); 1358 1359 /* Find the first free PID that's less than the maximum */ 1360 std::set<int> const& pids = p->system->PIDs; 1361 int temp_pid = *pids.begin(); 1362 do { 1363 temp_pid++; 1364 } while (pids.find(temp_pid) != pids.end()); 1365 if (temp_pid >= System::maxPID) 1366 fatal("temp_pid is too large: %d", temp_pid); 1367 1368 pp->pid = temp_pid; 1369 pp->ppid = (flags & OS::TGT_CLONE_THREAD) ? p->ppid() : p->pid(); 1370 Process *cp = pp->create(); 1371 delete pp; 1372 1373 Process *owner = ctc->getProcessPtr(); 1374 ctc->setProcessPtr(cp); 1375 cp->assignThreadContext(ctc->contextId()); 1376 owner->revokeThreadContext(ctc->contextId()); 1377 1378 if (flags & OS::TGT_CLONE_PARENT_SETTID) { 1379 BufferArg ptidBuf(ptidPtr, sizeof(long)); 1380 long *ptid = (long *)ptidBuf.bufferPtr(); 1381 *ptid = cp->pid(); 1382 ptidBuf.copyOut(tc->getMemProxy()); 1383 } 1384 1385 cp->initState(); 1386 p->clone(tc, ctc, cp, flags); 1387 1388 if (flags & OS::TGT_CLONE_THREAD) { 1389 delete cp->sigchld; 1390 cp->sigchld = p->sigchld; 1391 } else if (flags & OS::TGT_SIGCHLD) { 1392 *cp->sigchld = true; 1393 } 1394 1395 if (flags & OS::TGT_CLONE_CHILD_SETTID) { 1396 BufferArg ctidBuf(ctidPtr, sizeof(long)); 1397 long *ctid = (long *)ctidBuf.bufferPtr(); 1398 *ctid = cp->pid(); 1399 ctidBuf.copyOut(ctc->getMemProxy()); 1400 } 1401 1402 if (flags & OS::TGT_CLONE_CHILD_CLEARTID) 1403 cp->childClearTID = (uint64_t)ctidPtr; 1404 1405 ctc->clearArchRegs(); 1406 1407 OS::archClone(flags, p, cp, tc, ctc, newStack, tlsPtr); 1408 1409 cp->setSyscallReturn(ctc, 0); 1410 1411#if THE_ISA == ALPHA_ISA 1412 ctc->setIntReg(TheISA::SyscallSuccessReg, 0); 1413#elif THE_ISA == SPARC_ISA 1414 tc->setIntReg(TheISA::SyscallPseudoReturnReg, 0); 1415 ctc->setIntReg(TheISA::SyscallPseudoReturnReg, 1); 1416#endif 1417 1418 TheISA::PCState cpc = tc->pcState(); 1419 cpc.advance(); 1420 ctc->pcState(cpc); 1421 ctc->activate(); 1422 1423 return cp->pid(); 1424} 1425 1426/// Target fstatfs() handler. 1427template <class OS> 1428SyscallReturn 1429fstatfsFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1430{ 1431 int index = 0; 1432 int tgt_fd = p->getSyscallArg(tc, index); 1433 Addr bufPtr = p->getSyscallArg(tc, index); 1434 1435 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 1436 if (!ffdp) 1437 return -EBADF; 1438 int sim_fd = ffdp->getSimFD(); 1439 1440 struct statfs hostBuf; 1441 int result = fstatfs(sim_fd, &hostBuf); 1442 1443 if (result < 0) 1444 return -errno; 1445 1446 copyOutStatfsBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1447 1448 return 0; 1449} 1450 1451 1452/// Target writev() handler. 1453template <class OS> 1454SyscallReturn 1455writevFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1456{ 1457 int index = 0; 1458 int tgt_fd = p->getSyscallArg(tc, index); 1459 1460 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 1461 if (!hbfdp) 1462 return -EBADF; 1463 int sim_fd = hbfdp->getSimFD(); 1464 1465 SETranslatingPortProxy &prox = tc->getMemProxy(); 1466 uint64_t tiov_base = p->getSyscallArg(tc, index); 1467 size_t count = p->getSyscallArg(tc, index); 1468 struct iovec hiov[count]; 1469 for (size_t i = 0; i < count; ++i) { 1470 typename OS::tgt_iovec tiov; 1471 1472 prox.readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec), 1473 (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec)); 1474 hiov[i].iov_len = TheISA::gtoh(tiov.iov_len); 1475 hiov[i].iov_base = new char [hiov[i].iov_len]; 1476 prox.readBlob(TheISA::gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base, 1477 hiov[i].iov_len); 1478 } 1479 1480 int result = writev(sim_fd, hiov, count); 1481 1482 for (size_t i = 0; i < count; ++i) 1483 delete [] (char *)hiov[i].iov_base; 1484 1485 if (result < 0) 1486 return -errno; 1487 1488 return result; 1489} 1490 1491/// Real mmap handler. 1492template <class OS> 1493SyscallReturn 1494mmapImpl(SyscallDesc *desc, int num, Process *p, ThreadContext *tc, 1495 bool is_mmap2) 1496{ 1497 int index = 0; 1498 Addr start = p->getSyscallArg(tc, index); 1499 uint64_t length = p->getSyscallArg(tc, index); 1500 int prot = p->getSyscallArg(tc, index); 1501 int tgt_flags = p->getSyscallArg(tc, index); 1502 int tgt_fd = p->getSyscallArg(tc, index); 1503 int offset = p->getSyscallArg(tc, index); 1504 1505 if (is_mmap2) 1506 offset *= TheISA::PageBytes; 1507 1508 if (start & (TheISA::PageBytes - 1) || 1509 offset & (TheISA::PageBytes - 1) || 1510 (tgt_flags & OS::TGT_MAP_PRIVATE && 1511 tgt_flags & OS::TGT_MAP_SHARED) || 1512 (!(tgt_flags & OS::TGT_MAP_PRIVATE) && 1513 !(tgt_flags & OS::TGT_MAP_SHARED)) || 1514 !length) { 1515 return -EINVAL; 1516 } 1517 1518 if ((prot & PROT_WRITE) && (tgt_flags & OS::TGT_MAP_SHARED)) { 1519 // With shared mmaps, there are two cases to consider: 1520 // 1) anonymous: writes should modify the mapping and this should be 1521 // visible to observers who share the mapping. Currently, it's 1522 // difficult to update the shared mapping because there's no 1523 // structure which maintains information about the which virtual 1524 // memory areas are shared. If that structure existed, it would be 1525 // possible to make the translations point to the same frames. 1526 // 2) file-backed: writes should modify the mapping and the file 1527 // which is backed by the mapping. The shared mapping problem is the 1528 // same as what was mentioned about the anonymous mappings. For 1529 // file-backed mappings, the writes to the file are difficult 1530 // because it requires syncing what the mapping holds with the file 1531 // that resides on the host system. So, any write on a real system 1532 // would cause the change to be propagated to the file mapping at 1533 // some point in the future (the inode is tracked along with the 1534 // mapping). This isn't guaranteed to always happen, but it usually 1535 // works well enough. The guarantee is provided by the msync system 1536 // call. We could force the change through with shared mappings with 1537 // a call to msync, but that again would require more information 1538 // than we currently maintain. 1539 warn("mmap: writing to shared mmap region is currently " 1540 "unsupported. The write succeeds on the target, but it " 1541 "will not be propagated to the host or shared mappings"); 1542 } 1543 1544 length = roundUp(length, TheISA::PageBytes); 1545 1546 int sim_fd = -1; 1547 uint8_t *pmap = nullptr; 1548 if (!(tgt_flags & OS::TGT_MAP_ANONYMOUS)) { 1549 std::shared_ptr<FDEntry> fdep = (*p->fds)[tgt_fd]; 1550 1551 auto dfdp = std::dynamic_pointer_cast<DeviceFDEntry>(fdep); 1552 if (dfdp) { 1553 EmulatedDriver *emul_driver = dfdp->getDriver(); 1554 return emul_driver->mmap(p, tc, start, length, prot, 1555 tgt_flags, tgt_fd, offset); 1556 } 1557 1558 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep); 1559 if (!ffdp) 1560 return -EBADF; 1561 sim_fd = ffdp->getSimFD(); 1562 1563 pmap = (decltype(pmap))mmap(nullptr, length, PROT_READ, MAP_PRIVATE, 1564 sim_fd, offset); 1565 1566 if (pmap == (decltype(pmap))-1) { 1567 warn("mmap: failed to map file into host address space"); 1568 return -errno; 1569 } 1570 } 1571 1572 // Extend global mmap region if necessary. Note that we ignore the 1573 // start address unless MAP_FIXED is specified. 1574 if (!(tgt_flags & OS::TGT_MAP_FIXED)) { 1575 std::shared_ptr<MemState> mem_state = p->memState; 1576 Addr mmap_end = mem_state->getMmapEnd(); 1577 1578 start = p->mmapGrowsDown() ? mmap_end - length : mmap_end; 1579 mmap_end = p->mmapGrowsDown() ? start : mmap_end + length; 1580 1581 mem_state->setMmapEnd(mmap_end); 1582 } 1583 1584 DPRINTF_SYSCALL(Verbose, " mmap range is 0x%x - 0x%x\n", 1585 start, start + length - 1); 1586 1587 // We only allow mappings to overwrite existing mappings if 1588 // TGT_MAP_FIXED is set. Otherwise it shouldn't be a problem 1589 // because we ignore the start hint if TGT_MAP_FIXED is not set. 1590 int clobber = tgt_flags & OS::TGT_MAP_FIXED; 1591 if (clobber) { 1592 for (auto tc : p->system->threadContexts) { 1593 // If we might be overwriting old mappings, we need to 1594 // invalidate potentially stale mappings out of the TLBs. 1595 tc->getDTBPtr()->flushAll(); 1596 tc->getITBPtr()->flushAll(); 1597 } 1598 } 1599 1600 // Allocate physical memory and map it in. If the page table is already 1601 // mapped and clobber is not set, the simulator will issue throw a 1602 // fatal and bail out of the simulation. 1603 p->allocateMem(start, length, clobber); 1604 1605 // Transfer content into target address space. 1606 SETranslatingPortProxy &tp = tc->getMemProxy(); 1607 if (tgt_flags & OS::TGT_MAP_ANONYMOUS) { 1608 // In general, we should zero the mapped area for anonymous mappings, 1609 // with something like: 1610 // tp.memsetBlob(start, 0, length); 1611 // However, given that we don't support sparse mappings, and 1612 // some applications can map a couple of gigabytes of space 1613 // (intending sparse usage), that can get painfully expensive. 1614 // Fortunately, since we don't properly implement munmap either, 1615 // there's no danger of remapping used memory, so for now all 1616 // newly mapped memory should already be zeroed so we can skip it. 1617 } else { 1618 // It is possible to mmap an area larger than a file, however 1619 // accessing unmapped portions the system triggers a "Bus error" 1620 // on the host. We must know when to stop copying the file from 1621 // the host into the target address space. 1622 struct stat file_stat; 1623 if (fstat(sim_fd, &file_stat) > 0) 1624 fatal("mmap: cannot stat file"); 1625 1626 // Copy the portion of the file that is resident. This requires 1627 // checking both the mmap size and the filesize that we are 1628 // trying to mmap into this space; the mmap size also depends 1629 // on the specified offset into the file. 1630 uint64_t size = std::min((uint64_t)file_stat.st_size - offset, 1631 length); 1632 tp.writeBlob(start, pmap, size); 1633 1634 // Cleanup the mmap region before exiting this function. 1635 munmap(pmap, length); 1636 1637 // Maintain the symbol table for dynamic executables. 1638 // The loader will call mmap to map the images into its address 1639 // space and we intercept that here. We can verify that we are 1640 // executing inside the loader by checking the program counter value. 1641 // XXX: with multiprogrammed workloads or multi-node configurations, 1642 // this will not work since there is a single global symbol table. 1643 ObjectFile *interpreter = p->getInterpreter(); 1644 if (interpreter) { 1645 Addr text_start = interpreter->textBase(); 1646 Addr text_end = text_start + interpreter->textSize(); 1647 1648 Addr pc = tc->pcState().pc(); 1649 1650 if (pc >= text_start && pc < text_end) { 1651 std::shared_ptr<FDEntry> fdep = (*p->fds)[tgt_fd]; 1652 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep); 1653 ObjectFile *lib = createObjectFile(ffdp->getFileName()); 1654 1655 if (lib) { 1656 lib->loadAllSymbols(debugSymbolTable, 1657 lib->textBase(), start); 1658 } 1659 } 1660 } 1661 1662 // Note that we do not zero out the remainder of the mapping. This 1663 // is done by a real system, but it probably will not affect 1664 // execution (hopefully). 1665 } 1666 1667 return start; 1668} 1669 1670template <class OS> 1671SyscallReturn 1672pwrite64Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1673{ 1674 int index = 0; 1675 int tgt_fd = p->getSyscallArg(tc, index); 1676 Addr bufPtr = p->getSyscallArg(tc, index); 1677 int nbytes = p->getSyscallArg(tc, index); 1678 int offset = p->getSyscallArg(tc, index); 1679 1680 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 1681 if (!ffdp) 1682 return -EBADF; 1683 int sim_fd = ffdp->getSimFD(); 1684 1685 BufferArg bufArg(bufPtr, nbytes); 1686 bufArg.copyIn(tc->getMemProxy()); 1687 1688 int bytes_written = pwrite(sim_fd, bufArg.bufferPtr(), nbytes, offset); 1689 1690 return (bytes_written == -1) ? -errno : bytes_written; 1691} 1692 1693/// Target mmap() handler. 1694template <class OS> 1695SyscallReturn 1696mmapFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1697{ 1698 return mmapImpl<OS>(desc, num, p, tc, false); 1699} 1700 1701/// Target mmap2() handler. 1702template <class OS> 1703SyscallReturn 1704mmap2Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1705{ 1706 return mmapImpl<OS>(desc, num, p, tc, true); 1707} 1708 1709/// Target getrlimit() handler. 1710template <class OS> 1711SyscallReturn 1712getrlimitFunc(SyscallDesc *desc, int callnum, Process *process, 1713 ThreadContext *tc) 1714{ 1715 int index = 0; 1716 unsigned resource = process->getSyscallArg(tc, index); 1717 TypedBufferArg<typename OS::rlimit> rlp(process->getSyscallArg(tc, index)); 1718 1719 switch (resource) { 1720 case OS::TGT_RLIMIT_STACK: 1721 // max stack size in bytes: make up a number (8MB for now) 1722 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; 1723 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1724 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1725 break; 1726 1727 case OS::TGT_RLIMIT_DATA: 1728 // max data segment size in bytes: make up a number 1729 rlp->rlim_cur = rlp->rlim_max = 256 * 1024 * 1024; 1730 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1731 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1732 break; 1733 1734 default: 1735 warn("getrlimit: unimplemented resource %d", resource); 1736 return -EINVAL; 1737 break; 1738 } 1739 1740 rlp.copyOut(tc->getMemProxy()); 1741 return 0; 1742} 1743 1744template <class OS> 1745SyscallReturn 1746prlimitFunc(SyscallDesc *desc, int callnum, Process *process, 1747 ThreadContext *tc) 1748{ 1749 int index = 0; 1750 if (process->getSyscallArg(tc, index) != 0) 1751 { 1752 warn("prlimit: ignoring rlimits for nonzero pid"); 1753 return -EPERM; 1754 } 1755 int resource = process->getSyscallArg(tc, index); 1756 Addr n = process->getSyscallArg(tc, index); 1757 if (n != 0) 1758 warn("prlimit: ignoring new rlimit"); 1759 Addr o = process->getSyscallArg(tc, index); 1760 if (o != 0) 1761 { 1762 TypedBufferArg<typename OS::rlimit> rlp(o); 1763 switch (resource) { 1764 case OS::TGT_RLIMIT_STACK: 1765 // max stack size in bytes: make up a number (8MB for now) 1766 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; 1767 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1768 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1769 break; 1770 case OS::TGT_RLIMIT_DATA: 1771 // max data segment size in bytes: make up a number 1772 rlp->rlim_cur = rlp->rlim_max = 256*1024*1024; 1773 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1774 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1775 break; 1776 default: 1777 warn("prlimit: unimplemented resource %d", resource); 1778 return -EINVAL; 1779 break; 1780 } 1781 rlp.copyOut(tc->getMemProxy()); 1782 } 1783 return 0; 1784} 1785 1786/// Target clock_gettime() function. 1787template <class OS> 1788SyscallReturn 1789clock_gettimeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1790{ 1791 int index = 1; 1792 //int clk_id = p->getSyscallArg(tc, index); 1793 TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index)); 1794 1795 getElapsedTimeNano(tp->tv_sec, tp->tv_nsec); 1796 tp->tv_sec += seconds_since_epoch; 1797 tp->tv_sec = TheISA::htog(tp->tv_sec); 1798 tp->tv_nsec = TheISA::htog(tp->tv_nsec); 1799 1800 tp.copyOut(tc->getMemProxy()); 1801 1802 return 0; 1803} 1804 1805/// Target clock_getres() function. 1806template <class OS> 1807SyscallReturn 1808clock_getresFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1809{ 1810 int index = 1; 1811 TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index)); 1812 1813 // Set resolution at ns, which is what clock_gettime() returns 1814 tp->tv_sec = 0; 1815 tp->tv_nsec = 1; 1816 1817 tp.copyOut(tc->getMemProxy()); 1818 1819 return 0; 1820} 1821 1822/// Target gettimeofday() handler. 1823template <class OS> 1824SyscallReturn 1825gettimeofdayFunc(SyscallDesc *desc, int callnum, Process *process, 1826 ThreadContext *tc) 1827{ 1828 int index = 0; 1829 TypedBufferArg<typename OS::timeval> tp(process->getSyscallArg(tc, index)); 1830 1831 getElapsedTimeMicro(tp->tv_sec, tp->tv_usec); 1832 tp->tv_sec += seconds_since_epoch; 1833 tp->tv_sec = TheISA::htog(tp->tv_sec); 1834 tp->tv_usec = TheISA::htog(tp->tv_usec); 1835 1836 tp.copyOut(tc->getMemProxy()); 1837 1838 return 0; 1839} 1840 1841 1842/// Target utimes() handler. 1843template <class OS> 1844SyscallReturn 1845utimesFunc(SyscallDesc *desc, int callnum, Process *process, 1846 ThreadContext *tc) 1847{ 1848 std::string path; 1849 1850 int index = 0; 1851 if (!tc->getMemProxy().tryReadString(path, 1852 process->getSyscallArg(tc, index))) { 1853 return -EFAULT; 1854 } 1855 1856 TypedBufferArg<typename OS::timeval [2]> 1857 tp(process->getSyscallArg(tc, index)); 1858 tp.copyIn(tc->getMemProxy()); 1859 1860 struct timeval hostTimeval[2]; 1861 for (int i = 0; i < 2; ++i) { 1862 hostTimeval[i].tv_sec = TheISA::gtoh((*tp)[i].tv_sec); 1863 hostTimeval[i].tv_usec = TheISA::gtoh((*tp)[i].tv_usec); 1864 } 1865 1866 // Adjust path for current working directory 1867 path = process->fullPath(path); 1868 1869 int result = utimes(path.c_str(), hostTimeval); 1870 1871 if (result < 0) 1872 return -errno; 1873 1874 return 0; 1875} 1876 1877template <class OS> 1878SyscallReturn 1879execveFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1880{ 1881 desc->setFlags(0); 1882 1883 int index = 0; 1884 std::string path; 1885 SETranslatingPortProxy & mem_proxy = tc->getMemProxy(); 1886 if (!mem_proxy.tryReadString(path, p->getSyscallArg(tc, index))) 1887 return -EFAULT; 1888 1889 if (access(path.c_str(), F_OK) == -1) 1890 return -EACCES; 1891 1892 auto read_in = [](std::vector<std::string> & vect, 1893 SETranslatingPortProxy & mem_proxy, 1894 Addr mem_loc) 1895 { 1896 for (int inc = 0; ; inc++) { 1897 BufferArg b((mem_loc + sizeof(Addr) * inc), sizeof(Addr)); 1898 b.copyIn(mem_proxy); 1899 1900 if (!*(Addr*)b.bufferPtr()) 1901 break; 1902 1903 vect.push_back(std::string()); 1904 mem_proxy.tryReadString(vect[inc], *(Addr*)b.bufferPtr()); 1905 } 1906 }; 1907 1908 /** 1909 * Note that ProcessParams is generated by swig and there are no other 1910 * examples of how to create anything but this default constructor. The 1911 * fields are manually initialized instead of passing parameters to the 1912 * constructor. 1913 */ 1914 ProcessParams *pp = new ProcessParams(); 1915 pp->executable = path; 1916 Addr argv_mem_loc = p->getSyscallArg(tc, index); 1917 read_in(pp->cmd, mem_proxy, argv_mem_loc); 1918 Addr envp_mem_loc = p->getSyscallArg(tc, index); 1919 read_in(pp->env, mem_proxy, envp_mem_loc); 1920 pp->uid = p->uid(); 1921 pp->egid = p->egid(); 1922 pp->euid = p->euid(); 1923 pp->gid = p->gid(); 1924 pp->ppid = p->ppid(); 1925 pp->pid = p->pid(); 1926 pp->input.assign("cin"); 1927 pp->output.assign("cout"); 1928 pp->errout.assign("cerr"); 1929 pp->cwd.assign(p->getcwd()); 1930 pp->system = p->system; 1931 /** 1932 * Prevent process object creation with identical PIDs (which will trip 1933 * a fatal check in Process constructor). The execve call is supposed to 1934 * take over the currently executing process' identity but replace 1935 * whatever it is doing with a new process image. Instead of hijacking 1936 * the process object in the simulator, we create a new process object 1937 * and bind to the previous process' thread below (hijacking the thread). 1938 */ 1939 p->system->PIDs.erase(p->pid()); 1940 Process *new_p = pp->create(); 1941 delete pp; 1942 1943 /** 1944 * Work through the file descriptor array and close any files marked 1945 * close-on-exec. 1946 */ 1947 new_p->fds = p->fds; 1948 for (int i = 0; i < new_p->fds->getSize(); i++) { 1949 std::shared_ptr<FDEntry> fdep = (*new_p->fds)[i]; 1950 if (fdep && fdep->getCOE()) 1951 new_p->fds->closeFDEntry(i); 1952 } 1953 1954 *new_p->sigchld = true; 1955 1956 delete p; 1957 tc->clearArchRegs(); 1958 tc->setProcessPtr(new_p); 1959 new_p->assignThreadContext(tc->contextId()); 1960 new_p->initState(); 1961 tc->activate(); 1962 TheISA::PCState pcState = tc->pcState(); 1963 tc->setNPC(pcState.instAddr()); 1964 1965 desc->setFlags(SyscallDesc::SuppressReturnValue); 1966 return 0; 1967} 1968 1969/// Target getrusage() function. 1970template <class OS> 1971SyscallReturn 1972getrusageFunc(SyscallDesc *desc, int callnum, Process *process, 1973 ThreadContext *tc) 1974{ 1975 int index = 0; 1976 int who = process->getSyscallArg(tc, index); // THREAD, SELF, or CHILDREN 1977 TypedBufferArg<typename OS::rusage> rup(process->getSyscallArg(tc, index)); 1978 1979 rup->ru_utime.tv_sec = 0; 1980 rup->ru_utime.tv_usec = 0; 1981 rup->ru_stime.tv_sec = 0; 1982 rup->ru_stime.tv_usec = 0; 1983 rup->ru_maxrss = 0; 1984 rup->ru_ixrss = 0; 1985 rup->ru_idrss = 0; 1986 rup->ru_isrss = 0; 1987 rup->ru_minflt = 0; 1988 rup->ru_majflt = 0; 1989 rup->ru_nswap = 0; 1990 rup->ru_inblock = 0; 1991 rup->ru_oublock = 0; 1992 rup->ru_msgsnd = 0; 1993 rup->ru_msgrcv = 0; 1994 rup->ru_nsignals = 0; 1995 rup->ru_nvcsw = 0; 1996 rup->ru_nivcsw = 0; 1997 1998 switch (who) { 1999 case OS::TGT_RUSAGE_SELF: 2000 getElapsedTimeMicro(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec); 2001 rup->ru_utime.tv_sec = TheISA::htog(rup->ru_utime.tv_sec); 2002 rup->ru_utime.tv_usec = TheISA::htog(rup->ru_utime.tv_usec); 2003 break; 2004 2005 case OS::TGT_RUSAGE_CHILDREN: 2006 // do nothing. We have no child processes, so they take no time. 2007 break; 2008 2009 default: 2010 // don't really handle THREAD or CHILDREN, but just warn and 2011 // plow ahead 2012 warn("getrusage() only supports RUSAGE_SELF. Parameter %d ignored.", 2013 who); 2014 } 2015 2016 rup.copyOut(tc->getMemProxy()); 2017 2018 return 0; 2019} 2020 2021/// Target times() function. 2022template <class OS> 2023SyscallReturn 2024timesFunc(SyscallDesc *desc, int callnum, Process *process, 2025 ThreadContext *tc) 2026{ 2027 int index = 0; 2028 TypedBufferArg<typename OS::tms> bufp(process->getSyscallArg(tc, index)); 2029 2030 // Fill in the time structure (in clocks) 2031 int64_t clocks = curTick() * OS::M5_SC_CLK_TCK / SimClock::Int::s; 2032 bufp->tms_utime = clocks; 2033 bufp->tms_stime = 0; 2034 bufp->tms_cutime = 0; 2035 bufp->tms_cstime = 0; 2036 2037 // Convert to host endianness 2038 bufp->tms_utime = TheISA::htog(bufp->tms_utime); 2039 2040 // Write back 2041 bufp.copyOut(tc->getMemProxy()); 2042 2043 // Return clock ticks since system boot 2044 return clocks; 2045} 2046 2047/// Target time() function. 2048template <class OS> 2049SyscallReturn 2050timeFunc(SyscallDesc *desc, int callnum, Process *process, ThreadContext *tc) 2051{ 2052 typename OS::time_t sec, usec; 2053 getElapsedTimeMicro(sec, usec); 2054 sec += seconds_since_epoch; 2055 2056 int index = 0; 2057 Addr taddr = (Addr)process->getSyscallArg(tc, index); 2058 if (taddr != 0) { 2059 typename OS::time_t t = sec; 2060 t = TheISA::htog(t); 2061 SETranslatingPortProxy &p = tc->getMemProxy(); 2062 p.writeBlob(taddr, (uint8_t*)&t, (int)sizeof(typename OS::time_t)); 2063 } 2064 return sec; 2065} 2066 2067template <class OS> 2068SyscallReturn 2069tgkillFunc(SyscallDesc *desc, int num, Process *process, ThreadContext *tc) 2070{ 2071 int index = 0; 2072 int tgid = process->getSyscallArg(tc, index); 2073 int tid = process->getSyscallArg(tc, index); 2074 int sig = process->getSyscallArg(tc, index); 2075 2076 /** 2077 * This system call is intended to allow killing a specific thread 2078 * within an arbitrary thread group if sanctioned with permission checks. 2079 * It's usually true that threads share the termination signal as pointed 2080 * out by the pthread_kill man page and this seems to be the intended 2081 * usage. Due to this being an emulated environment, assume the following: 2082 * Threads are allowed to call tgkill because the EUID for all threads 2083 * should be the same. There is no signal handling mechanism for kernel 2084 * registration of signal handlers since signals are poorly supported in 2085 * emulation mode. Since signal handlers cannot be registered, all 2086 * threads within in a thread group must share the termination signal. 2087 * We never exhaust PIDs so there's no chance of finding the wrong one 2088 * due to PID rollover. 2089 */ 2090 2091 System *sys = tc->getSystemPtr(); 2092 Process *tgt_proc = nullptr; 2093 for (int i = 0; i < sys->numContexts(); i++) { 2094 Process *temp = sys->threadContexts[i]->getProcessPtr(); 2095 if (temp->pid() == tid) { 2096 tgt_proc = temp; 2097 break; 2098 } 2099 } 2100 2101 if (sig != 0 || sig != OS::TGT_SIGABRT) 2102 return -EINVAL; 2103 2104 if (tgt_proc == nullptr) 2105 return -ESRCH; 2106 2107 if (tgid != -1 && tgt_proc->tgid() != tgid) 2108 return -ESRCH; 2109 2110 if (sig == OS::TGT_SIGABRT) 2111 exitGroupFunc(desc, 252, process, tc); 2112 2113 return 0; 2114} 2115 2116template <class OS> 2117SyscallReturn 2118socketFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 2119{ 2120 int index = 0; 2121 int domain = p->getSyscallArg(tc, index); 2122 int type = p->getSyscallArg(tc, index); 2123 int prot = p->getSyscallArg(tc, index); 2124 2125 int sim_fd = socket(domain, type, prot); 2126 if (sim_fd == -1) 2127 return -errno; 2128 2129 auto sfdp = std::make_shared<SocketFDEntry>(sim_fd, domain, type, prot); 2130 int tgt_fd = p->fds->allocFD(sfdp); 2131 2132 return tgt_fd; 2133} 2134 2135template <class OS> 2136SyscallReturn 2137socketpairFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 2138{ 2139 int index = 0; 2140 int domain = p->getSyscallArg(tc, index); 2141 int type = p->getSyscallArg(tc, index); 2142 int prot = p->getSyscallArg(tc, index); 2143 Addr svPtr = p->getSyscallArg(tc, index); 2144 2145 BufferArg svBuf((Addr)svPtr, 2 * sizeof(int)); 2146 int status = socketpair(domain, type, prot, (int *)svBuf.bufferPtr()); 2147 if (status == -1) 2148 return -errno; 2149 2150 int *fds = (int *)svBuf.bufferPtr(); 2151 2152 auto sfdp1 = std::make_shared<SocketFDEntry>(fds[0], domain, type, prot); 2153 fds[0] = p->fds->allocFD(sfdp1); 2154 auto sfdp2 = std::make_shared<SocketFDEntry>(fds[1], domain, type, prot); 2155 fds[1] = p->fds->allocFD(sfdp2); 2156 svBuf.copyOut(tc->getMemProxy()); 2157 2158 return status; 2159} 2160
| 1340/// Target statfs() handler. 1341template <class OS> 1342SyscallReturn 1343statfsFunc(SyscallDesc *desc, int callnum, Process *process, 1344 ThreadContext *tc) 1345{ 1346#if NO_STATFS 1347 warn("Host OS cannot support calls to statfs. Ignoring syscall"); 1348#else 1349 std::string path; 1350 1351 int index = 0; 1352 if (!tc->getMemProxy().tryReadString(path, 1353 process->getSyscallArg(tc, index))) { 1354 return -EFAULT; 1355 } 1356 Addr bufPtr = process->getSyscallArg(tc, index); 1357 1358 // Adjust path for current working directory 1359 path = process->fullPath(path); 1360 1361 struct statfs hostBuf; 1362 int result = statfs(path.c_str(), &hostBuf); 1363 1364 if (result < 0) 1365 return -errno; 1366 1367 copyOutStatfsBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1368#endif 1369 return 0; 1370} 1371 1372template <class OS> 1373SyscallReturn 1374cloneFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1375{ 1376 int index = 0; 1377 1378 RegVal flags = p->getSyscallArg(tc, index); 1379 RegVal newStack = p->getSyscallArg(tc, index); 1380 Addr ptidPtr = p->getSyscallArg(tc, index); 1381 1382#if THE_ISA == RISCV_ISA or THE_ISA == ARM_ISA 1383 /** 1384 * Linux sets CLONE_BACKWARDS flag for RISC-V and Arm. 1385 * The flag defines the list of clone() arguments in the following 1386 * order: flags -> newStack -> ptidPtr -> tlsPtr -> ctidPtr 1387 */ 1388 Addr tlsPtr = p->getSyscallArg(tc, index); 1389 Addr ctidPtr = p->getSyscallArg(tc, index); 1390#else 1391 Addr ctidPtr = p->getSyscallArg(tc, index); 1392 Addr tlsPtr = p->getSyscallArg(tc, index); 1393#endif 1394 1395 if (((flags & OS::TGT_CLONE_SIGHAND)&& !(flags & OS::TGT_CLONE_VM)) || 1396 ((flags & OS::TGT_CLONE_THREAD) && !(flags & OS::TGT_CLONE_SIGHAND)) || 1397 ((flags & OS::TGT_CLONE_FS) && (flags & OS::TGT_CLONE_NEWNS)) || 1398 ((flags & OS::TGT_CLONE_NEWIPC) && (flags & OS::TGT_CLONE_SYSVSEM)) || 1399 ((flags & OS::TGT_CLONE_NEWPID) && (flags & OS::TGT_CLONE_THREAD)) || 1400 ((flags & OS::TGT_CLONE_VM) && !(newStack))) 1401 return -EINVAL; 1402 1403 ThreadContext *ctc; 1404 if (!(ctc = p->findFreeContext())) 1405 fatal("clone: no spare thread context in system"); 1406 1407 /** 1408 * Note that ProcessParams is generated by swig and there are no other 1409 * examples of how to create anything but this default constructor. The 1410 * fields are manually initialized instead of passing parameters to the 1411 * constructor. 1412 */ 1413 ProcessParams *pp = new ProcessParams(); 1414 pp->executable.assign(*(new std::string(p->progName()))); 1415 pp->cmd.push_back(*(new std::string(p->progName()))); 1416 pp->system = p->system; 1417 pp->cwd.assign(p->getcwd()); 1418 pp->input.assign("stdin"); 1419 pp->output.assign("stdout"); 1420 pp->errout.assign("stderr"); 1421 pp->uid = p->uid(); 1422 pp->euid = p->euid(); 1423 pp->gid = p->gid(); 1424 pp->egid = p->egid(); 1425 1426 /* Find the first free PID that's less than the maximum */ 1427 std::set<int> const& pids = p->system->PIDs; 1428 int temp_pid = *pids.begin(); 1429 do { 1430 temp_pid++; 1431 } while (pids.find(temp_pid) != pids.end()); 1432 if (temp_pid >= System::maxPID) 1433 fatal("temp_pid is too large: %d", temp_pid); 1434 1435 pp->pid = temp_pid; 1436 pp->ppid = (flags & OS::TGT_CLONE_THREAD) ? p->ppid() : p->pid(); 1437 Process *cp = pp->create(); 1438 delete pp; 1439 1440 Process *owner = ctc->getProcessPtr(); 1441 ctc->setProcessPtr(cp); 1442 cp->assignThreadContext(ctc->contextId()); 1443 owner->revokeThreadContext(ctc->contextId()); 1444 1445 if (flags & OS::TGT_CLONE_PARENT_SETTID) { 1446 BufferArg ptidBuf(ptidPtr, sizeof(long)); 1447 long *ptid = (long *)ptidBuf.bufferPtr(); 1448 *ptid = cp->pid(); 1449 ptidBuf.copyOut(tc->getMemProxy()); 1450 } 1451 1452 cp->initState(); 1453 p->clone(tc, ctc, cp, flags); 1454 1455 if (flags & OS::TGT_CLONE_THREAD) { 1456 delete cp->sigchld; 1457 cp->sigchld = p->sigchld; 1458 } else if (flags & OS::TGT_SIGCHLD) { 1459 *cp->sigchld = true; 1460 } 1461 1462 if (flags & OS::TGT_CLONE_CHILD_SETTID) { 1463 BufferArg ctidBuf(ctidPtr, sizeof(long)); 1464 long *ctid = (long *)ctidBuf.bufferPtr(); 1465 *ctid = cp->pid(); 1466 ctidBuf.copyOut(ctc->getMemProxy()); 1467 } 1468 1469 if (flags & OS::TGT_CLONE_CHILD_CLEARTID) 1470 cp->childClearTID = (uint64_t)ctidPtr; 1471 1472 ctc->clearArchRegs(); 1473 1474 OS::archClone(flags, p, cp, tc, ctc, newStack, tlsPtr); 1475 1476 cp->setSyscallReturn(ctc, 0); 1477 1478#if THE_ISA == ALPHA_ISA 1479 ctc->setIntReg(TheISA::SyscallSuccessReg, 0); 1480#elif THE_ISA == SPARC_ISA 1481 tc->setIntReg(TheISA::SyscallPseudoReturnReg, 0); 1482 ctc->setIntReg(TheISA::SyscallPseudoReturnReg, 1); 1483#endif 1484 1485 TheISA::PCState cpc = tc->pcState(); 1486 cpc.advance(); 1487 ctc->pcState(cpc); 1488 ctc->activate(); 1489 1490 return cp->pid(); 1491} 1492 1493/// Target fstatfs() handler. 1494template <class OS> 1495SyscallReturn 1496fstatfsFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1497{ 1498 int index = 0; 1499 int tgt_fd = p->getSyscallArg(tc, index); 1500 Addr bufPtr = p->getSyscallArg(tc, index); 1501 1502 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 1503 if (!ffdp) 1504 return -EBADF; 1505 int sim_fd = ffdp->getSimFD(); 1506 1507 struct statfs hostBuf; 1508 int result = fstatfs(sim_fd, &hostBuf); 1509 1510 if (result < 0) 1511 return -errno; 1512 1513 copyOutStatfsBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1514 1515 return 0; 1516} 1517 1518 1519/// Target writev() handler. 1520template <class OS> 1521SyscallReturn 1522writevFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1523{ 1524 int index = 0; 1525 int tgt_fd = p->getSyscallArg(tc, index); 1526 1527 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 1528 if (!hbfdp) 1529 return -EBADF; 1530 int sim_fd = hbfdp->getSimFD(); 1531 1532 SETranslatingPortProxy &prox = tc->getMemProxy(); 1533 uint64_t tiov_base = p->getSyscallArg(tc, index); 1534 size_t count = p->getSyscallArg(tc, index); 1535 struct iovec hiov[count]; 1536 for (size_t i = 0; i < count; ++i) { 1537 typename OS::tgt_iovec tiov; 1538 1539 prox.readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec), 1540 (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec)); 1541 hiov[i].iov_len = TheISA::gtoh(tiov.iov_len); 1542 hiov[i].iov_base = new char [hiov[i].iov_len]; 1543 prox.readBlob(TheISA::gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base, 1544 hiov[i].iov_len); 1545 } 1546 1547 int result = writev(sim_fd, hiov, count); 1548 1549 for (size_t i = 0; i < count; ++i) 1550 delete [] (char *)hiov[i].iov_base; 1551 1552 if (result < 0) 1553 return -errno; 1554 1555 return result; 1556} 1557 1558/// Real mmap handler. 1559template <class OS> 1560SyscallReturn 1561mmapImpl(SyscallDesc *desc, int num, Process *p, ThreadContext *tc, 1562 bool is_mmap2) 1563{ 1564 int index = 0; 1565 Addr start = p->getSyscallArg(tc, index); 1566 uint64_t length = p->getSyscallArg(tc, index); 1567 int prot = p->getSyscallArg(tc, index); 1568 int tgt_flags = p->getSyscallArg(tc, index); 1569 int tgt_fd = p->getSyscallArg(tc, index); 1570 int offset = p->getSyscallArg(tc, index); 1571 1572 if (is_mmap2) 1573 offset *= TheISA::PageBytes; 1574 1575 if (start & (TheISA::PageBytes - 1) || 1576 offset & (TheISA::PageBytes - 1) || 1577 (tgt_flags & OS::TGT_MAP_PRIVATE && 1578 tgt_flags & OS::TGT_MAP_SHARED) || 1579 (!(tgt_flags & OS::TGT_MAP_PRIVATE) && 1580 !(tgt_flags & OS::TGT_MAP_SHARED)) || 1581 !length) { 1582 return -EINVAL; 1583 } 1584 1585 if ((prot & PROT_WRITE) && (tgt_flags & OS::TGT_MAP_SHARED)) { 1586 // With shared mmaps, there are two cases to consider: 1587 // 1) anonymous: writes should modify the mapping and this should be 1588 // visible to observers who share the mapping. Currently, it's 1589 // difficult to update the shared mapping because there's no 1590 // structure which maintains information about the which virtual 1591 // memory areas are shared. If that structure existed, it would be 1592 // possible to make the translations point to the same frames. 1593 // 2) file-backed: writes should modify the mapping and the file 1594 // which is backed by the mapping. The shared mapping problem is the 1595 // same as what was mentioned about the anonymous mappings. For 1596 // file-backed mappings, the writes to the file are difficult 1597 // because it requires syncing what the mapping holds with the file 1598 // that resides on the host system. So, any write on a real system 1599 // would cause the change to be propagated to the file mapping at 1600 // some point in the future (the inode is tracked along with the 1601 // mapping). This isn't guaranteed to always happen, but it usually 1602 // works well enough. The guarantee is provided by the msync system 1603 // call. We could force the change through with shared mappings with 1604 // a call to msync, but that again would require more information 1605 // than we currently maintain. 1606 warn("mmap: writing to shared mmap region is currently " 1607 "unsupported. The write succeeds on the target, but it " 1608 "will not be propagated to the host or shared mappings"); 1609 } 1610 1611 length = roundUp(length, TheISA::PageBytes); 1612 1613 int sim_fd = -1; 1614 uint8_t *pmap = nullptr; 1615 if (!(tgt_flags & OS::TGT_MAP_ANONYMOUS)) { 1616 std::shared_ptr<FDEntry> fdep = (*p->fds)[tgt_fd]; 1617 1618 auto dfdp = std::dynamic_pointer_cast<DeviceFDEntry>(fdep); 1619 if (dfdp) { 1620 EmulatedDriver *emul_driver = dfdp->getDriver(); 1621 return emul_driver->mmap(p, tc, start, length, prot, 1622 tgt_flags, tgt_fd, offset); 1623 } 1624 1625 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep); 1626 if (!ffdp) 1627 return -EBADF; 1628 sim_fd = ffdp->getSimFD(); 1629 1630 pmap = (decltype(pmap))mmap(nullptr, length, PROT_READ, MAP_PRIVATE, 1631 sim_fd, offset); 1632 1633 if (pmap == (decltype(pmap))-1) { 1634 warn("mmap: failed to map file into host address space"); 1635 return -errno; 1636 } 1637 } 1638 1639 // Extend global mmap region if necessary. Note that we ignore the 1640 // start address unless MAP_FIXED is specified. 1641 if (!(tgt_flags & OS::TGT_MAP_FIXED)) { 1642 std::shared_ptr<MemState> mem_state = p->memState; 1643 Addr mmap_end = mem_state->getMmapEnd(); 1644 1645 start = p->mmapGrowsDown() ? mmap_end - length : mmap_end; 1646 mmap_end = p->mmapGrowsDown() ? start : mmap_end + length; 1647 1648 mem_state->setMmapEnd(mmap_end); 1649 } 1650 1651 DPRINTF_SYSCALL(Verbose, " mmap range is 0x%x - 0x%x\n", 1652 start, start + length - 1); 1653 1654 // We only allow mappings to overwrite existing mappings if 1655 // TGT_MAP_FIXED is set. Otherwise it shouldn't be a problem 1656 // because we ignore the start hint if TGT_MAP_FIXED is not set. 1657 int clobber = tgt_flags & OS::TGT_MAP_FIXED; 1658 if (clobber) { 1659 for (auto tc : p->system->threadContexts) { 1660 // If we might be overwriting old mappings, we need to 1661 // invalidate potentially stale mappings out of the TLBs. 1662 tc->getDTBPtr()->flushAll(); 1663 tc->getITBPtr()->flushAll(); 1664 } 1665 } 1666 1667 // Allocate physical memory and map it in. If the page table is already 1668 // mapped and clobber is not set, the simulator will issue throw a 1669 // fatal and bail out of the simulation. 1670 p->allocateMem(start, length, clobber); 1671 1672 // Transfer content into target address space. 1673 SETranslatingPortProxy &tp = tc->getMemProxy(); 1674 if (tgt_flags & OS::TGT_MAP_ANONYMOUS) { 1675 // In general, we should zero the mapped area for anonymous mappings, 1676 // with something like: 1677 // tp.memsetBlob(start, 0, length); 1678 // However, given that we don't support sparse mappings, and 1679 // some applications can map a couple of gigabytes of space 1680 // (intending sparse usage), that can get painfully expensive. 1681 // Fortunately, since we don't properly implement munmap either, 1682 // there's no danger of remapping used memory, so for now all 1683 // newly mapped memory should already be zeroed so we can skip it. 1684 } else { 1685 // It is possible to mmap an area larger than a file, however 1686 // accessing unmapped portions the system triggers a "Bus error" 1687 // on the host. We must know when to stop copying the file from 1688 // the host into the target address space. 1689 struct stat file_stat; 1690 if (fstat(sim_fd, &file_stat) > 0) 1691 fatal("mmap: cannot stat file"); 1692 1693 // Copy the portion of the file that is resident. This requires 1694 // checking both the mmap size and the filesize that we are 1695 // trying to mmap into this space; the mmap size also depends 1696 // on the specified offset into the file. 1697 uint64_t size = std::min((uint64_t)file_stat.st_size - offset, 1698 length); 1699 tp.writeBlob(start, pmap, size); 1700 1701 // Cleanup the mmap region before exiting this function. 1702 munmap(pmap, length); 1703 1704 // Maintain the symbol table for dynamic executables. 1705 // The loader will call mmap to map the images into its address 1706 // space and we intercept that here. We can verify that we are 1707 // executing inside the loader by checking the program counter value. 1708 // XXX: with multiprogrammed workloads or multi-node configurations, 1709 // this will not work since there is a single global symbol table. 1710 ObjectFile *interpreter = p->getInterpreter(); 1711 if (interpreter) { 1712 Addr text_start = interpreter->textBase(); 1713 Addr text_end = text_start + interpreter->textSize(); 1714 1715 Addr pc = tc->pcState().pc(); 1716 1717 if (pc >= text_start && pc < text_end) { 1718 std::shared_ptr<FDEntry> fdep = (*p->fds)[tgt_fd]; 1719 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep); 1720 ObjectFile *lib = createObjectFile(ffdp->getFileName()); 1721 1722 if (lib) { 1723 lib->loadAllSymbols(debugSymbolTable, 1724 lib->textBase(), start); 1725 } 1726 } 1727 } 1728 1729 // Note that we do not zero out the remainder of the mapping. This 1730 // is done by a real system, but it probably will not affect 1731 // execution (hopefully). 1732 } 1733 1734 return start; 1735} 1736 1737template <class OS> 1738SyscallReturn 1739pwrite64Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1740{ 1741 int index = 0; 1742 int tgt_fd = p->getSyscallArg(tc, index); 1743 Addr bufPtr = p->getSyscallArg(tc, index); 1744 int nbytes = p->getSyscallArg(tc, index); 1745 int offset = p->getSyscallArg(tc, index); 1746 1747 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 1748 if (!ffdp) 1749 return -EBADF; 1750 int sim_fd = ffdp->getSimFD(); 1751 1752 BufferArg bufArg(bufPtr, nbytes); 1753 bufArg.copyIn(tc->getMemProxy()); 1754 1755 int bytes_written = pwrite(sim_fd, bufArg.bufferPtr(), nbytes, offset); 1756 1757 return (bytes_written == -1) ? -errno : bytes_written; 1758} 1759 1760/// Target mmap() handler. 1761template <class OS> 1762SyscallReturn 1763mmapFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1764{ 1765 return mmapImpl<OS>(desc, num, p, tc, false); 1766} 1767 1768/// Target mmap2() handler. 1769template <class OS> 1770SyscallReturn 1771mmap2Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1772{ 1773 return mmapImpl<OS>(desc, num, p, tc, true); 1774} 1775 1776/// Target getrlimit() handler. 1777template <class OS> 1778SyscallReturn 1779getrlimitFunc(SyscallDesc *desc, int callnum, Process *process, 1780 ThreadContext *tc) 1781{ 1782 int index = 0; 1783 unsigned resource = process->getSyscallArg(tc, index); 1784 TypedBufferArg<typename OS::rlimit> rlp(process->getSyscallArg(tc, index)); 1785 1786 switch (resource) { 1787 case OS::TGT_RLIMIT_STACK: 1788 // max stack size in bytes: make up a number (8MB for now) 1789 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; 1790 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1791 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1792 break; 1793 1794 case OS::TGT_RLIMIT_DATA: 1795 // max data segment size in bytes: make up a number 1796 rlp->rlim_cur = rlp->rlim_max = 256 * 1024 * 1024; 1797 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1798 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1799 break; 1800 1801 default: 1802 warn("getrlimit: unimplemented resource %d", resource); 1803 return -EINVAL; 1804 break; 1805 } 1806 1807 rlp.copyOut(tc->getMemProxy()); 1808 return 0; 1809} 1810 1811template <class OS> 1812SyscallReturn 1813prlimitFunc(SyscallDesc *desc, int callnum, Process *process, 1814 ThreadContext *tc) 1815{ 1816 int index = 0; 1817 if (process->getSyscallArg(tc, index) != 0) 1818 { 1819 warn("prlimit: ignoring rlimits for nonzero pid"); 1820 return -EPERM; 1821 } 1822 int resource = process->getSyscallArg(tc, index); 1823 Addr n = process->getSyscallArg(tc, index); 1824 if (n != 0) 1825 warn("prlimit: ignoring new rlimit"); 1826 Addr o = process->getSyscallArg(tc, index); 1827 if (o != 0) 1828 { 1829 TypedBufferArg<typename OS::rlimit> rlp(o); 1830 switch (resource) { 1831 case OS::TGT_RLIMIT_STACK: 1832 // max stack size in bytes: make up a number (8MB for now) 1833 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; 1834 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1835 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1836 break; 1837 case OS::TGT_RLIMIT_DATA: 1838 // max data segment size in bytes: make up a number 1839 rlp->rlim_cur = rlp->rlim_max = 256*1024*1024; 1840 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1841 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1842 break; 1843 default: 1844 warn("prlimit: unimplemented resource %d", resource); 1845 return -EINVAL; 1846 break; 1847 } 1848 rlp.copyOut(tc->getMemProxy()); 1849 } 1850 return 0; 1851} 1852 1853/// Target clock_gettime() function. 1854template <class OS> 1855SyscallReturn 1856clock_gettimeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1857{ 1858 int index = 1; 1859 //int clk_id = p->getSyscallArg(tc, index); 1860 TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index)); 1861 1862 getElapsedTimeNano(tp->tv_sec, tp->tv_nsec); 1863 tp->tv_sec += seconds_since_epoch; 1864 tp->tv_sec = TheISA::htog(tp->tv_sec); 1865 tp->tv_nsec = TheISA::htog(tp->tv_nsec); 1866 1867 tp.copyOut(tc->getMemProxy()); 1868 1869 return 0; 1870} 1871 1872/// Target clock_getres() function. 1873template <class OS> 1874SyscallReturn 1875clock_getresFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1876{ 1877 int index = 1; 1878 TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index)); 1879 1880 // Set resolution at ns, which is what clock_gettime() returns 1881 tp->tv_sec = 0; 1882 tp->tv_nsec = 1; 1883 1884 tp.copyOut(tc->getMemProxy()); 1885 1886 return 0; 1887} 1888 1889/// Target gettimeofday() handler. 1890template <class OS> 1891SyscallReturn 1892gettimeofdayFunc(SyscallDesc *desc, int callnum, Process *process, 1893 ThreadContext *tc) 1894{ 1895 int index = 0; 1896 TypedBufferArg<typename OS::timeval> tp(process->getSyscallArg(tc, index)); 1897 1898 getElapsedTimeMicro(tp->tv_sec, tp->tv_usec); 1899 tp->tv_sec += seconds_since_epoch; 1900 tp->tv_sec = TheISA::htog(tp->tv_sec); 1901 tp->tv_usec = TheISA::htog(tp->tv_usec); 1902 1903 tp.copyOut(tc->getMemProxy()); 1904 1905 return 0; 1906} 1907 1908 1909/// Target utimes() handler. 1910template <class OS> 1911SyscallReturn 1912utimesFunc(SyscallDesc *desc, int callnum, Process *process, 1913 ThreadContext *tc) 1914{ 1915 std::string path; 1916 1917 int index = 0; 1918 if (!tc->getMemProxy().tryReadString(path, 1919 process->getSyscallArg(tc, index))) { 1920 return -EFAULT; 1921 } 1922 1923 TypedBufferArg<typename OS::timeval [2]> 1924 tp(process->getSyscallArg(tc, index)); 1925 tp.copyIn(tc->getMemProxy()); 1926 1927 struct timeval hostTimeval[2]; 1928 for (int i = 0; i < 2; ++i) { 1929 hostTimeval[i].tv_sec = TheISA::gtoh((*tp)[i].tv_sec); 1930 hostTimeval[i].tv_usec = TheISA::gtoh((*tp)[i].tv_usec); 1931 } 1932 1933 // Adjust path for current working directory 1934 path = process->fullPath(path); 1935 1936 int result = utimes(path.c_str(), hostTimeval); 1937 1938 if (result < 0) 1939 return -errno; 1940 1941 return 0; 1942} 1943 1944template <class OS> 1945SyscallReturn 1946execveFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1947{ 1948 desc->setFlags(0); 1949 1950 int index = 0; 1951 std::string path; 1952 SETranslatingPortProxy & mem_proxy = tc->getMemProxy(); 1953 if (!mem_proxy.tryReadString(path, p->getSyscallArg(tc, index))) 1954 return -EFAULT; 1955 1956 if (access(path.c_str(), F_OK) == -1) 1957 return -EACCES; 1958 1959 auto read_in = [](std::vector<std::string> & vect, 1960 SETranslatingPortProxy & mem_proxy, 1961 Addr mem_loc) 1962 { 1963 for (int inc = 0; ; inc++) { 1964 BufferArg b((mem_loc + sizeof(Addr) * inc), sizeof(Addr)); 1965 b.copyIn(mem_proxy); 1966 1967 if (!*(Addr*)b.bufferPtr()) 1968 break; 1969 1970 vect.push_back(std::string()); 1971 mem_proxy.tryReadString(vect[inc], *(Addr*)b.bufferPtr()); 1972 } 1973 }; 1974 1975 /** 1976 * Note that ProcessParams is generated by swig and there are no other 1977 * examples of how to create anything but this default constructor. The 1978 * fields are manually initialized instead of passing parameters to the 1979 * constructor. 1980 */ 1981 ProcessParams *pp = new ProcessParams(); 1982 pp->executable = path; 1983 Addr argv_mem_loc = p->getSyscallArg(tc, index); 1984 read_in(pp->cmd, mem_proxy, argv_mem_loc); 1985 Addr envp_mem_loc = p->getSyscallArg(tc, index); 1986 read_in(pp->env, mem_proxy, envp_mem_loc); 1987 pp->uid = p->uid(); 1988 pp->egid = p->egid(); 1989 pp->euid = p->euid(); 1990 pp->gid = p->gid(); 1991 pp->ppid = p->ppid(); 1992 pp->pid = p->pid(); 1993 pp->input.assign("cin"); 1994 pp->output.assign("cout"); 1995 pp->errout.assign("cerr"); 1996 pp->cwd.assign(p->getcwd()); 1997 pp->system = p->system; 1998 /** 1999 * Prevent process object creation with identical PIDs (which will trip 2000 * a fatal check in Process constructor). The execve call is supposed to 2001 * take over the currently executing process' identity but replace 2002 * whatever it is doing with a new process image. Instead of hijacking 2003 * the process object in the simulator, we create a new process object 2004 * and bind to the previous process' thread below (hijacking the thread). 2005 */ 2006 p->system->PIDs.erase(p->pid()); 2007 Process *new_p = pp->create(); 2008 delete pp; 2009 2010 /** 2011 * Work through the file descriptor array and close any files marked 2012 * close-on-exec. 2013 */ 2014 new_p->fds = p->fds; 2015 for (int i = 0; i < new_p->fds->getSize(); i++) { 2016 std::shared_ptr<FDEntry> fdep = (*new_p->fds)[i]; 2017 if (fdep && fdep->getCOE()) 2018 new_p->fds->closeFDEntry(i); 2019 } 2020 2021 *new_p->sigchld = true; 2022 2023 delete p; 2024 tc->clearArchRegs(); 2025 tc->setProcessPtr(new_p); 2026 new_p->assignThreadContext(tc->contextId()); 2027 new_p->initState(); 2028 tc->activate(); 2029 TheISA::PCState pcState = tc->pcState(); 2030 tc->setNPC(pcState.instAddr()); 2031 2032 desc->setFlags(SyscallDesc::SuppressReturnValue); 2033 return 0; 2034} 2035 2036/// Target getrusage() function. 2037template <class OS> 2038SyscallReturn 2039getrusageFunc(SyscallDesc *desc, int callnum, Process *process, 2040 ThreadContext *tc) 2041{ 2042 int index = 0; 2043 int who = process->getSyscallArg(tc, index); // THREAD, SELF, or CHILDREN 2044 TypedBufferArg<typename OS::rusage> rup(process->getSyscallArg(tc, index)); 2045 2046 rup->ru_utime.tv_sec = 0; 2047 rup->ru_utime.tv_usec = 0; 2048 rup->ru_stime.tv_sec = 0; 2049 rup->ru_stime.tv_usec = 0; 2050 rup->ru_maxrss = 0; 2051 rup->ru_ixrss = 0; 2052 rup->ru_idrss = 0; 2053 rup->ru_isrss = 0; 2054 rup->ru_minflt = 0; 2055 rup->ru_majflt = 0; 2056 rup->ru_nswap = 0; 2057 rup->ru_inblock = 0; 2058 rup->ru_oublock = 0; 2059 rup->ru_msgsnd = 0; 2060 rup->ru_msgrcv = 0; 2061 rup->ru_nsignals = 0; 2062 rup->ru_nvcsw = 0; 2063 rup->ru_nivcsw = 0; 2064 2065 switch (who) { 2066 case OS::TGT_RUSAGE_SELF: 2067 getElapsedTimeMicro(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec); 2068 rup->ru_utime.tv_sec = TheISA::htog(rup->ru_utime.tv_sec); 2069 rup->ru_utime.tv_usec = TheISA::htog(rup->ru_utime.tv_usec); 2070 break; 2071 2072 case OS::TGT_RUSAGE_CHILDREN: 2073 // do nothing. We have no child processes, so they take no time. 2074 break; 2075 2076 default: 2077 // don't really handle THREAD or CHILDREN, but just warn and 2078 // plow ahead 2079 warn("getrusage() only supports RUSAGE_SELF. Parameter %d ignored.", 2080 who); 2081 } 2082 2083 rup.copyOut(tc->getMemProxy()); 2084 2085 return 0; 2086} 2087 2088/// Target times() function. 2089template <class OS> 2090SyscallReturn 2091timesFunc(SyscallDesc *desc, int callnum, Process *process, 2092 ThreadContext *tc) 2093{ 2094 int index = 0; 2095 TypedBufferArg<typename OS::tms> bufp(process->getSyscallArg(tc, index)); 2096 2097 // Fill in the time structure (in clocks) 2098 int64_t clocks = curTick() * OS::M5_SC_CLK_TCK / SimClock::Int::s; 2099 bufp->tms_utime = clocks; 2100 bufp->tms_stime = 0; 2101 bufp->tms_cutime = 0; 2102 bufp->tms_cstime = 0; 2103 2104 // Convert to host endianness 2105 bufp->tms_utime = TheISA::htog(bufp->tms_utime); 2106 2107 // Write back 2108 bufp.copyOut(tc->getMemProxy()); 2109 2110 // Return clock ticks since system boot 2111 return clocks; 2112} 2113 2114/// Target time() function. 2115template <class OS> 2116SyscallReturn 2117timeFunc(SyscallDesc *desc, int callnum, Process *process, ThreadContext *tc) 2118{ 2119 typename OS::time_t sec, usec; 2120 getElapsedTimeMicro(sec, usec); 2121 sec += seconds_since_epoch; 2122 2123 int index = 0; 2124 Addr taddr = (Addr)process->getSyscallArg(tc, index); 2125 if (taddr != 0) { 2126 typename OS::time_t t = sec; 2127 t = TheISA::htog(t); 2128 SETranslatingPortProxy &p = tc->getMemProxy(); 2129 p.writeBlob(taddr, (uint8_t*)&t, (int)sizeof(typename OS::time_t)); 2130 } 2131 return sec; 2132} 2133 2134template <class OS> 2135SyscallReturn 2136tgkillFunc(SyscallDesc *desc, int num, Process *process, ThreadContext *tc) 2137{ 2138 int index = 0; 2139 int tgid = process->getSyscallArg(tc, index); 2140 int tid = process->getSyscallArg(tc, index); 2141 int sig = process->getSyscallArg(tc, index); 2142 2143 /** 2144 * This system call is intended to allow killing a specific thread 2145 * within an arbitrary thread group if sanctioned with permission checks. 2146 * It's usually true that threads share the termination signal as pointed 2147 * out by the pthread_kill man page and this seems to be the intended 2148 * usage. Due to this being an emulated environment, assume the following: 2149 * Threads are allowed to call tgkill because the EUID for all threads 2150 * should be the same. There is no signal handling mechanism for kernel 2151 * registration of signal handlers since signals are poorly supported in 2152 * emulation mode. Since signal handlers cannot be registered, all 2153 * threads within in a thread group must share the termination signal. 2154 * We never exhaust PIDs so there's no chance of finding the wrong one 2155 * due to PID rollover. 2156 */ 2157 2158 System *sys = tc->getSystemPtr(); 2159 Process *tgt_proc = nullptr; 2160 for (int i = 0; i < sys->numContexts(); i++) { 2161 Process *temp = sys->threadContexts[i]->getProcessPtr(); 2162 if (temp->pid() == tid) { 2163 tgt_proc = temp; 2164 break; 2165 } 2166 } 2167 2168 if (sig != 0 || sig != OS::TGT_SIGABRT) 2169 return -EINVAL; 2170 2171 if (tgt_proc == nullptr) 2172 return -ESRCH; 2173 2174 if (tgid != -1 && tgt_proc->tgid() != tgid) 2175 return -ESRCH; 2176 2177 if (sig == OS::TGT_SIGABRT) 2178 exitGroupFunc(desc, 252, process, tc); 2179 2180 return 0; 2181} 2182 2183template <class OS> 2184SyscallReturn 2185socketFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 2186{ 2187 int index = 0; 2188 int domain = p->getSyscallArg(tc, index); 2189 int type = p->getSyscallArg(tc, index); 2190 int prot = p->getSyscallArg(tc, index); 2191 2192 int sim_fd = socket(domain, type, prot); 2193 if (sim_fd == -1) 2194 return -errno; 2195 2196 auto sfdp = std::make_shared<SocketFDEntry>(sim_fd, domain, type, prot); 2197 int tgt_fd = p->fds->allocFD(sfdp); 2198 2199 return tgt_fd; 2200} 2201 2202template <class OS> 2203SyscallReturn 2204socketpairFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 2205{ 2206 int index = 0; 2207 int domain = p->getSyscallArg(tc, index); 2208 int type = p->getSyscallArg(tc, index); 2209 int prot = p->getSyscallArg(tc, index); 2210 Addr svPtr = p->getSyscallArg(tc, index); 2211 2212 BufferArg svBuf((Addr)svPtr, 2 * sizeof(int)); 2213 int status = socketpair(domain, type, prot, (int *)svBuf.bufferPtr()); 2214 if (status == -1) 2215 return -errno; 2216 2217 int *fds = (int *)svBuf.bufferPtr(); 2218 2219 auto sfdp1 = std::make_shared<SocketFDEntry>(fds[0], domain, type, prot); 2220 fds[0] = p->fds->allocFD(sfdp1); 2221 auto sfdp2 = std::make_shared<SocketFDEntry>(fds[1], domain, type, prot); 2222 fds[1] = p->fds->allocFD(sfdp2); 2223 svBuf.copyOut(tc->getMemProxy()); 2224 2225 return status; 2226} 2227
|
| 2228template <class OS> 2229SyscallReturn 2230selectFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 2231{ 2232 int retval; 2233 2234 int index = 0; 2235 int nfds_t = p->getSyscallArg(tc, index); 2236 Addr fds_read_ptr = p->getSyscallArg(tc, index); 2237 Addr fds_writ_ptr = p->getSyscallArg(tc, index); 2238 Addr fds_excp_ptr = p->getSyscallArg(tc, index); 2239 Addr time_val_ptr = p->getSyscallArg(tc, index); 2240 2241 TypedBufferArg<typename OS::fd_set> rd_t(fds_read_ptr); 2242 TypedBufferArg<typename OS::fd_set> wr_t(fds_writ_ptr); 2243 TypedBufferArg<typename OS::fd_set> ex_t(fds_excp_ptr); 2244 TypedBufferArg<typename OS::timeval> tp(time_val_ptr); 2245 2246 /** 2247 * Host fields. Notice that these use the definitions from the system 2248 * headers instead of the gem5 headers and libraries. If the host and 2249 * target have different header file definitions, this will not work. 2250 */ 2251 fd_set rd_h; 2252 FD_ZERO(&rd_h); 2253 fd_set wr_h; 2254 FD_ZERO(&wr_h); 2255 fd_set ex_h; 2256 FD_ZERO(&ex_h); 2257 2258 /** 2259 * Copy in the fd_set from the target. 2260 */ 2261 if (fds_read_ptr) 2262 rd_t.copyIn(tc->getMemProxy()); 2263 if (fds_writ_ptr) 2264 wr_t.copyIn(tc->getMemProxy()); 2265 if (fds_excp_ptr) 2266 ex_t.copyIn(tc->getMemProxy()); 2267 2268 /** 2269 * We need to translate the target file descriptor set into a host file 2270 * descriptor set. This involves both our internal process fd array 2271 * and the fd_set defined in Linux header files. The nfds field also 2272 * needs to be updated as it will be only target specific after 2273 * retrieving it from the target; the nfds value is expected to be the 2274 * highest file descriptor that needs to be checked, so we need to extend 2275 * it out for nfds_h when we do the update. 2276 */ 2277 int nfds_h = 0; 2278 std::map<int, int> trans_map; 2279 auto try_add_host_set = [&](fd_set *tgt_set_entry, 2280 fd_set *hst_set_entry, 2281 int iter) -> bool 2282 { 2283 /** 2284 * By this point, we know that we are looking at a valid file 2285 * descriptor set on the target. We need to check if the target file 2286 * descriptor value passed in as iter is part of the set. 2287 */ 2288 if (FD_ISSET(iter, tgt_set_entry)) { 2289 /** 2290 * We know that the target file descriptor belongs to the set, 2291 * but we do not yet know if the file descriptor is valid or 2292 * that we have a host mapping. Check that now. 2293 */ 2294 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[iter]); 2295 if (!hbfdp) 2296 return true; 2297 auto sim_fd = hbfdp->getSimFD(); 2298 2299 /** 2300 * Add the sim_fd to tgt_fd translation into trans_map for use 2301 * later when we need to zero the target fd_set structures and 2302 * then update them with hits returned from the host select call. 2303 */ 2304 trans_map[sim_fd] = iter; 2305 2306 /** 2307 * We know that the host file descriptor exists so now we check 2308 * if we need to update the max count for nfds_h before passing 2309 * the duplicated structure into the host. 2310 */ 2311 nfds_h = std::max(nfds_h - 1, sim_fd + 1); 2312 2313 /** 2314 * Add the host file descriptor to the set that we are going to 2315 * pass into the host. 2316 */ 2317 FD_SET(sim_fd, hst_set_entry); 2318 } 2319 return false; 2320 }; 2321 2322 for (int i = 0; i < nfds_t; i++) { 2323 if (fds_read_ptr) { 2324 bool ebadf = try_add_host_set((fd_set*)&*rd_t, &rd_h, i); 2325 if (ebadf) return -EBADF; 2326 } 2327 if (fds_writ_ptr) { 2328 bool ebadf = try_add_host_set((fd_set*)&*wr_t, &wr_h, i); 2329 if (ebadf) return -EBADF; 2330 } 2331 if (fds_excp_ptr) { 2332 bool ebadf = try_add_host_set((fd_set*)&*ex_t, &ex_h, i); 2333 if (ebadf) return -EBADF; 2334 } 2335 } 2336 2337 if (time_val_ptr) { 2338 /** 2339 * It might be possible to decrement the timeval based on some 2340 * derivation of wall clock determined from elapsed simulator ticks 2341 * but that seems like overkill. Rather, we just set the timeval with 2342 * zero timeout. (There is no reason to block during the simulation 2343 * as it only decreases simulator performance.) 2344 */ 2345 tp->tv_sec = 0; 2346 tp->tv_usec = 0; 2347 2348 retval = select(nfds_h, 2349 fds_read_ptr ? &rd_h : nullptr, 2350 fds_writ_ptr ? &wr_h : nullptr, 2351 fds_excp_ptr ? &ex_h : nullptr, 2352 (timeval*)&*tp); 2353 } else { 2354 /** 2355 * If the timeval pointer is null, setup a new timeval structure to 2356 * pass into the host select call. Unfortunately, we will need to 2357 * manually check the return value and throw a retry fault if the 2358 * return value is zero. Allowing the system call to block will 2359 * likely deadlock the event queue. 2360 */ 2361 struct timeval tv = { 0, 0 }; 2362 2363 retval = select(nfds_h, 2364 fds_read_ptr ? &rd_h : nullptr, 2365 fds_writ_ptr ? &wr_h : nullptr, 2366 fds_excp_ptr ? &ex_h : nullptr, 2367 &tv); 2368 2369 if (retval == 0) { 2370 /** 2371 * If blocking indefinitely, check the signal list to see if a 2372 * signal would break the poll out of the retry cycle and try to 2373 * return the signal interrupt instead. 2374 */ 2375 for (auto sig : tc->getSystemPtr()->signalList) 2376 if (sig.receiver == p) 2377 return -EINTR; 2378 return SyscallReturn::retry(); 2379 } 2380 } 2381 2382 if (retval == -1) 2383 return -errno; 2384 2385 FD_ZERO((fd_set*)&*rd_t); 2386 FD_ZERO((fd_set*)&*wr_t); 2387 FD_ZERO((fd_set*)&*ex_t); 2388 2389 /** 2390 * We need to translate the host file descriptor set into a target file 2391 * descriptor set. This involves both our internal process fd array 2392 * and the fd_set defined in header files. 2393 */ 2394 for (int i = 0; i < nfds_h; i++) { 2395 if (fds_read_ptr) { 2396 if (FD_ISSET(i, &rd_h)) 2397 FD_SET(trans_map[i], (fd_set*)&*rd_t); 2398 } 2399 2400 if (fds_writ_ptr) { 2401 if (FD_ISSET(i, &wr_h)) 2402 FD_SET(trans_map[i], (fd_set*)&*wr_t); 2403 } 2404 2405 if (fds_excp_ptr) { 2406 if (FD_ISSET(i, &ex_h)) 2407 FD_SET(trans_map[i], (fd_set*)&*ex_t); 2408 } 2409 } 2410 2411 if (fds_read_ptr) 2412 rd_t.copyOut(tc->getMemProxy()); 2413 if (fds_writ_ptr) 2414 wr_t.copyOut(tc->getMemProxy()); 2415 if (fds_excp_ptr) 2416 ex_t.copyOut(tc->getMemProxy()); 2417 if (time_val_ptr) 2418 tp.copyOut(tc->getMemProxy()); 2419 2420 return retval; 2421} 2422 2423template <class OS> 2424SyscallReturn 2425readFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 2426{ 2427 int index = 0; 2428 int tgt_fd = p->getSyscallArg(tc, index); 2429 Addr buf_ptr = p->getSyscallArg(tc, index); 2430 int nbytes = p->getSyscallArg(tc, index); 2431 2432 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 2433 if (!hbfdp) 2434 return -EBADF; 2435 int sim_fd = hbfdp->getSimFD(); 2436 2437 struct pollfd pfd; 2438 pfd.fd = sim_fd; 2439 pfd.events = POLLIN | POLLPRI; 2440 if ((poll(&pfd, 1, 0) == 0) 2441 && !(hbfdp->getFlags() & OS::TGT_O_NONBLOCK)) 2442 return SyscallReturn::retry(); 2443 2444 BufferArg buf_arg(buf_ptr, nbytes); 2445 int bytes_read = read(sim_fd, buf_arg.bufferPtr(), nbytes); 2446 2447 if (bytes_read > 0) 2448 buf_arg.copyOut(tc->getMemProxy()); 2449 2450 return (bytes_read == -1) ? -errno : bytes_read; 2451} 2452 2453template <class OS> 2454SyscallReturn 2455writeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 2456{ 2457 int index = 0; 2458 int tgt_fd = p->getSyscallArg(tc, index); 2459 Addr buf_ptr = p->getSyscallArg(tc, index); 2460 int nbytes = p->getSyscallArg(tc, index); 2461 2462 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 2463 if (!hbfdp) 2464 return -EBADF; 2465 int sim_fd = hbfdp->getSimFD(); 2466 2467 BufferArg buf_arg(buf_ptr, nbytes); 2468 buf_arg.copyIn(tc->getMemProxy()); 2469 2470 struct pollfd pfd; 2471 pfd.fd = sim_fd; 2472 pfd.events = POLLOUT; 2473 2474 /** 2475 * We don't want to poll on /dev/random. The kernel will not enable the 2476 * file descriptor for writing unless the entropy in the system falls 2477 * below write_wakeup_threshold. This is not guaranteed to happen 2478 * depending on host settings. 2479 */ 2480 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(hbfdp); 2481 if (ffdp && (ffdp->getFileName() != "/dev/random")) { 2482 if (!poll(&pfd, 1, 0) && !(ffdp->getFlags() & OS::TGT_O_NONBLOCK)) 2483 return SyscallReturn::retry(); 2484 } 2485 2486 int bytes_written = write(sim_fd, buf_arg.bufferPtr(), nbytes); 2487 2488 if (bytes_written != -1) 2489 fsync(sim_fd); 2490 2491 return (bytes_written == -1) ? -errno : bytes_written; 2492} 2493 2494template <class OS> 2495SyscallReturn 2496wait4Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 2497{ 2498 int index = 0; 2499 pid_t pid = p->getSyscallArg(tc, index); 2500 Addr statPtr = p->getSyscallArg(tc, index); 2501 int options = p->getSyscallArg(tc, index); 2502 Addr rusagePtr = p->getSyscallArg(tc, index); 2503 2504 if (rusagePtr) 2505 DPRINTFR(SyscallVerbose, 2506 "%d: %s: syscall wait4: rusage pointer provided however " 2507 "functionality not supported. Ignoring rusage pointer.\n", 2508 curTick(), tc->getCpuPtr()->name()); 2509 2510 /** 2511 * Currently, wait4 is only implemented so that it will wait for children 2512 * exit conditions which are denoted by a SIGCHLD signals posted into the 2513 * system signal list. We return no additional information via any of the 2514 * parameters supplied to wait4. If nothing is found in the system signal 2515 * list, we will wait indefinitely for SIGCHLD to post by retrying the 2516 * call. 2517 */ 2518 System *sysh = tc->getSystemPtr(); 2519 std::list<BasicSignal>::iterator iter; 2520 for (iter=sysh->signalList.begin(); iter!=sysh->signalList.end(); iter++) { 2521 if (iter->receiver == p) { 2522 if (pid < -1) { 2523 if ((iter->sender->pgid() == -pid) 2524 && (iter->signalValue == OS::TGT_SIGCHLD)) 2525 goto success; 2526 } else if (pid == -1) { 2527 if (iter->signalValue == OS::TGT_SIGCHLD) 2528 goto success; 2529 } else if (pid == 0) { 2530 if ((iter->sender->pgid() == p->pgid()) 2531 && (iter->signalValue == OS::TGT_SIGCHLD)) 2532 goto success; 2533 } else { 2534 if ((iter->sender->pid() == pid) 2535 && (iter->signalValue == OS::TGT_SIGCHLD)) 2536 goto success; 2537 } 2538 } 2539 } 2540 2541 return (options & OS::TGT_WNOHANG) ? 0 : SyscallReturn::retry(); 2542 2543success: 2544 // Set status to EXITED for WIFEXITED evaluations. 2545 const int EXITED = 0; 2546 BufferArg statusBuf(statPtr, sizeof(int)); 2547 *(int *)statusBuf.bufferPtr() = EXITED; 2548 statusBuf.copyOut(tc->getMemProxy()); 2549 2550 // Return the child PID. 2551 pid_t retval = iter->sender->pid(); 2552 sysh->signalList.erase(iter); 2553 return retval; 2554} 2555 2556template <class OS> 2557SyscallReturn 2558acceptFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 2559{ 2560 struct sockaddr sa; 2561 socklen_t addrLen; 2562 int host_fd; 2563 int index = 0; 2564 int tgt_fd = p->getSyscallArg(tc, index); 2565 Addr addrPtr = p->getSyscallArg(tc, index); 2566 Addr lenPtr = p->getSyscallArg(tc, index); 2567 2568 BufferArg *lenBufPtr = nullptr; 2569 BufferArg *addrBufPtr = nullptr; 2570 2571 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 2572 if (!sfdp) 2573 return -EBADF; 2574 int sim_fd = sfdp->getSimFD(); 2575 2576 /** 2577 * We poll the socket file descriptor first to guarantee that we do not 2578 * block on our accept call. The socket can be opened without the 2579 * non-blocking flag (it blocks). This will cause deadlocks between 2580 * communicating processes. 2581 */ 2582 struct pollfd pfd; 2583 pfd.fd = sim_fd; 2584 pfd.events = POLLIN | POLLPRI; 2585 if ((poll(&pfd, 1, 0) == 0) 2586 && !(sfdp->getFlags() & OS::TGT_O_NONBLOCK)) 2587 return SyscallReturn::retry(); 2588 2589 if (lenPtr) { 2590 lenBufPtr = new BufferArg(lenPtr, sizeof(socklen_t)); 2591 lenBufPtr->copyIn(tc->getMemProxy()); 2592 memcpy(&addrLen, (socklen_t *)lenBufPtr->bufferPtr(), 2593 sizeof(socklen_t)); 2594 } 2595 2596 if (addrPtr) { 2597 addrBufPtr = new BufferArg(addrPtr, sizeof(struct sockaddr)); 2598 addrBufPtr->copyIn(tc->getMemProxy()); 2599 memcpy(&sa, (struct sockaddr *)addrBufPtr->bufferPtr(), 2600 sizeof(struct sockaddr)); 2601 } 2602 2603 host_fd = accept(sim_fd, &sa, &addrLen); 2604 2605 if (host_fd == -1) 2606 return -errno; 2607 2608 if (addrPtr) { 2609 memcpy(addrBufPtr->bufferPtr(), &sa, sizeof(sa)); 2610 addrBufPtr->copyOut(tc->getMemProxy()); 2611 delete(addrBufPtr); 2612 } 2613 2614 if (lenPtr) { 2615 *(socklen_t *)lenBufPtr->bufferPtr() = addrLen; 2616 lenBufPtr->copyOut(tc->getMemProxy()); 2617 delete(lenBufPtr); 2618 } 2619 2620 auto afdp = std::make_shared<SocketFDEntry>(host_fd, sfdp->_domain, 2621 sfdp->_type, sfdp->_protocol); 2622 return p->fds->allocFD(afdp); 2623} 2624
|
2161#endif // __SIM_SYSCALL_EMUL_HH__
| 2625#endif // __SIM_SYSCALL_EMUL_HH__
|