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