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