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