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