syscall_emul.hh revision 12795
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 <sys/mman.h> 82#include <sys/stat.h> 83#if (NO_STATFS == 0) 84#include <sys/statfs.h> 85#else 86#include <sys/mount.h> 87#endif 88#include <sys/time.h> 89#include <sys/uio.h> 90#include <unistd.h> 91 92#include <cerrno> 93#include <memory> 94#include <string> 95 96#include "arch/generic/tlb.hh" 97#include "arch/utility.hh" 98#include "base/intmath.hh" 99#include "base/loader/object_file.hh" 100#include "base/logging.hh" 101#include "base/trace.hh" 102#include "base/types.hh" 103#include "config/the_isa.hh" 104#include "cpu/base.hh" 105#include "cpu/thread_context.hh" 106#include "mem/page_table.hh" 107#include "params/Process.hh" 108#include "sim/emul_driver.hh" 109#include "sim/futex_map.hh" 110#include "sim/process.hh" 111#include "sim/syscall_debug_macros.hh" 112#include "sim/syscall_desc.hh" 113#include "sim/syscall_emul_buf.hh" 114#include "sim/syscall_return.hh" 115 116////////////////////////////////////////////////////////////////////// 117// 118// The following emulation functions are generic enough that they 119// don't need to be recompiled for different emulated OS's. They are 120// defined in sim/syscall_emul.cc. 121// 122////////////////////////////////////////////////////////////////////// 123 124 125/// Handler for unimplemented syscalls that we haven't thought about. 126SyscallReturn unimplementedFunc(SyscallDesc *desc, int num, 127 Process *p, ThreadContext *tc); 128 129/// Handler for unimplemented syscalls that we never intend to 130/// implement (signal handling, etc.) and should not affect the correct 131/// behavior of the program. Print a warning only if the appropriate 132/// trace flag is enabled. Return success to the target program. 133SyscallReturn ignoreFunc(SyscallDesc *desc, int num, 134 Process *p, ThreadContext *tc); 135 136// Target fallocateFunc() handler. 137SyscallReturn fallocateFunc(SyscallDesc *desc, int num, 138 Process *p, ThreadContext *tc); 139 140/// Target exit() handler: terminate current context. 141SyscallReturn exitFunc(SyscallDesc *desc, int num, 142 Process *p, ThreadContext *tc); 143 144/// Target exit_group() handler: terminate simulation. (exit all threads) 145SyscallReturn exitGroupFunc(SyscallDesc *desc, int num, 146 Process *p, ThreadContext *tc); 147 148/// Target set_tid_address() handler. 149SyscallReturn setTidAddressFunc(SyscallDesc *desc, int num, 150 Process *p, ThreadContext *tc); 151 152/// Target getpagesize() handler. 153SyscallReturn getpagesizeFunc(SyscallDesc *desc, int num, 154 Process *p, ThreadContext *tc); 155 156/// Target brk() handler: set brk address. 157SyscallReturn brkFunc(SyscallDesc *desc, int num, 158 Process *p, ThreadContext *tc); 159 160/// Target close() handler. 161SyscallReturn closeFunc(SyscallDesc *desc, int num, 162 Process *p, ThreadContext *tc); 163 164// Target read() handler. 165SyscallReturn readFunc(SyscallDesc *desc, int num, 166 Process *p, ThreadContext *tc); 167 168/// Target write() handler. 169SyscallReturn writeFunc(SyscallDesc *desc, int num, 170 Process *p, ThreadContext *tc); 171 172/// Target lseek() handler. 173SyscallReturn lseekFunc(SyscallDesc *desc, int num, 174 Process *p, ThreadContext *tc); 175 176/// Target _llseek() handler. 177SyscallReturn _llseekFunc(SyscallDesc *desc, int num, 178 Process *p, ThreadContext *tc); 179 180/// Target munmap() handler. 181SyscallReturn munmapFunc(SyscallDesc *desc, int num, 182 Process *p, ThreadContext *tc); 183 184/// Target gethostname() handler. 185SyscallReturn gethostnameFunc(SyscallDesc *desc, int num, 186 Process *p, ThreadContext *tc); 187 188/// Target getcwd() handler. 189SyscallReturn getcwdFunc(SyscallDesc *desc, int num, 190 Process *p, ThreadContext *tc); 191 192/// Target readlink() handler. 193SyscallReturn readlinkFunc(SyscallDesc *desc, int num, 194 Process *p, ThreadContext *tc, 195 int index = 0); 196SyscallReturn readlinkFunc(SyscallDesc *desc, int num, 197 Process *p, ThreadContext *tc); 198 199/// Target unlink() handler. 200SyscallReturn unlinkHelper(SyscallDesc *desc, int num, 201 Process *p, ThreadContext *tc, 202 int index); 203SyscallReturn unlinkFunc(SyscallDesc *desc, int num, 204 Process *p, ThreadContext *tc); 205 206/// Target link() handler 207SyscallReturn linkFunc(SyscallDesc *desc, int num, Process *p, 208 ThreadContext *tc); 209 210/// Target mkdir() handler. 211SyscallReturn mkdirFunc(SyscallDesc *desc, int num, 212 Process *p, ThreadContext *tc); 213 214/// Target rename() handler. 215SyscallReturn renameFunc(SyscallDesc *desc, int num, 216 Process *p, ThreadContext *tc); 217 218 219/// Target truncate() handler. 220SyscallReturn truncateFunc(SyscallDesc *desc, int num, 221 Process *p, ThreadContext *tc); 222 223 224/// Target ftruncate() handler. 225SyscallReturn ftruncateFunc(SyscallDesc *desc, int num, 226 Process *p, ThreadContext *tc); 227 228 229/// Target truncate64() handler. 230SyscallReturn truncate64Func(SyscallDesc *desc, int num, 231 Process *p, ThreadContext *tc); 232 233/// Target ftruncate64() handler. 234SyscallReturn ftruncate64Func(SyscallDesc *desc, int num, 235 Process *p, ThreadContext *tc); 236 237 238/// Target umask() handler. 239SyscallReturn umaskFunc(SyscallDesc *desc, int num, 240 Process *p, ThreadContext *tc); 241 242/// Target gettid() handler. 243SyscallReturn gettidFunc(SyscallDesc *desc, int num, 244 Process *p, ThreadContext *tc); 245 246/// Target chown() handler. 247SyscallReturn chownFunc(SyscallDesc *desc, int num, 248 Process *p, ThreadContext *tc); 249 250/// Target setpgid() handler. 251SyscallReturn setpgidFunc(SyscallDesc *desc, int num, 252 Process *p, ThreadContext *tc); 253 254/// Target fchown() handler. 255SyscallReturn fchownFunc(SyscallDesc *desc, int num, 256 Process *p, ThreadContext *tc); 257 258/// Target dup() handler. 259SyscallReturn dupFunc(SyscallDesc *desc, int num, 260 Process *process, ThreadContext *tc); 261 262/// Target dup2() handler. 263SyscallReturn dup2Func(SyscallDesc *desc, int num, 264 Process *process, ThreadContext *tc); 265 266/// Target fcntl() handler. 267SyscallReturn fcntlFunc(SyscallDesc *desc, int num, 268 Process *process, ThreadContext *tc); 269 270/// Target fcntl64() handler. 271SyscallReturn fcntl64Func(SyscallDesc *desc, int num, 272 Process *process, ThreadContext *tc); 273 274/// Target setuid() handler. 275SyscallReturn setuidFunc(SyscallDesc *desc, int num, 276 Process *p, ThreadContext *tc); 277 278/// Target pipe() handler. 279SyscallReturn pipeFunc(SyscallDesc *desc, int num, 280 Process *p, ThreadContext *tc); 281 282/// Internal pipe() handler. 283SyscallReturn pipeImpl(SyscallDesc *desc, int num, Process *p, 284 ThreadContext *tc, bool pseudoPipe); 285 286/// Target getpid() handler. 287SyscallReturn getpidFunc(SyscallDesc *desc, int num, 288 Process *p, ThreadContext *tc); 289 290/// Target getuid() handler. 291SyscallReturn getuidFunc(SyscallDesc *desc, int num, 292 Process *p, ThreadContext *tc); 293 294/// Target getgid() handler. 295SyscallReturn getgidFunc(SyscallDesc *desc, int num, 296 Process *p, ThreadContext *tc); 297 298/// Target getppid() handler. 299SyscallReturn getppidFunc(SyscallDesc *desc, int num, 300 Process *p, ThreadContext *tc); 301 302/// Target geteuid() handler. 303SyscallReturn geteuidFunc(SyscallDesc *desc, int num, 304 Process *p, ThreadContext *tc); 305 306/// Target getegid() handler. 307SyscallReturn getegidFunc(SyscallDesc *desc, int num, 308 Process *p, ThreadContext *tc); 309 310/// Target access() handler 311SyscallReturn accessFunc(SyscallDesc *desc, int num, 312 Process *p, ThreadContext *tc); 313SyscallReturn accessFunc(SyscallDesc *desc, int num, 314 Process *p, ThreadContext *tc, 315 int index); 316 317/// Futex system call 318/// Implemented by Daniel Sanchez 319/// Used by printf's in multi-threaded apps 320template <class OS> 321SyscallReturn 322futexFunc(SyscallDesc *desc, int callnum, Process *process, 323 ThreadContext *tc) 324{ 325 using namespace std; 326 327 int index = 0; 328 Addr uaddr = process->getSyscallArg(tc, index); 329 int op = process->getSyscallArg(tc, index); 330 int val = process->getSyscallArg(tc, index); 331 332 /* 333 * Unsupported option that does not affect the correctness of the 334 * application. This is a performance optimization utilized by Linux. 335 */ 336 op &= ~OS::TGT_FUTEX_PRIVATE_FLAG; 337 338 FutexMap &futex_map = tc->getSystemPtr()->futexMap; 339 340 if (OS::TGT_FUTEX_WAIT == op) { 341 // Ensure futex system call accessed atomically. 342 BufferArg buf(uaddr, sizeof(int)); 343 buf.copyIn(tc->getMemProxy()); 344 int mem_val = *(int*)buf.bufferPtr(); 345 346 /* 347 * The value in memory at uaddr is not equal with the expected val 348 * (a different thread must have changed it before the system call was 349 * invoked). In this case, we need to throw an error. 350 */ 351 if (val != mem_val) 352 return -OS::TGT_EWOULDBLOCK; 353 354 futex_map.suspend(uaddr, process->tgid(), tc); 355 356 return 0; 357 } else if (OS::TGT_FUTEX_WAKE == op) { 358 return futex_map.wakeup(uaddr, process->tgid(), val); 359 } 360 361 warn("futex: op %d not implemented; ignoring.", op); 362 return -ENOSYS; 363} 364 365 366/// Pseudo Funcs - These functions use a different return convension, 367/// returning a second value in a register other than the normal return register 368SyscallReturn pipePseudoFunc(SyscallDesc *desc, int num, 369 Process *process, ThreadContext *tc); 370 371/// Target getpidPseudo() handler. 372SyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num, 373 Process *p, ThreadContext *tc); 374 375/// Target getuidPseudo() handler. 376SyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num, 377 Process *p, ThreadContext *tc); 378 379/// Target getgidPseudo() handler. 380SyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num, 381 Process *p, ThreadContext *tc); 382 383 384/// A readable name for 1,000,000, for converting microseconds to seconds. 385const int one_million = 1000000; 386/// A readable name for 1,000,000,000, for converting nanoseconds to seconds. 387const int one_billion = 1000000000; 388 389/// Approximate seconds since the epoch (1/1/1970). About a billion, 390/// by my reckoning. We want to keep this a constant (not use the 391/// real-world time) to keep simulations repeatable. 392const unsigned seconds_since_epoch = 1000000000; 393 394/// Helper function to convert current elapsed time to seconds and 395/// microseconds. 396template <class T1, class T2> 397void 398getElapsedTimeMicro(T1 &sec, T2 &usec) 399{ 400 uint64_t elapsed_usecs = curTick() / SimClock::Int::us; 401 sec = elapsed_usecs / one_million; 402 usec = elapsed_usecs % one_million; 403} 404 405/// Helper function to convert current elapsed time to seconds and 406/// nanoseconds. 407template <class T1, class T2> 408void 409getElapsedTimeNano(T1 &sec, T2 &nsec) 410{ 411 uint64_t elapsed_nsecs = curTick() / SimClock::Int::ns; 412 sec = elapsed_nsecs / one_billion; 413 nsec = elapsed_nsecs % one_billion; 414} 415 416////////////////////////////////////////////////////////////////////// 417// 418// The following emulation functions are generic, but need to be 419// templated to account for differences in types, constants, etc. 420// 421////////////////////////////////////////////////////////////////////// 422 423 typedef struct statfs hst_statfs; 424#if NO_STAT64 425 typedef struct stat hst_stat; 426 typedef struct stat hst_stat64; 427#else 428 typedef struct stat hst_stat; 429 typedef struct stat64 hst_stat64; 430#endif 431 432//// Helper function to convert a host stat buffer to a target stat 433//// buffer. Also copies the target buffer out to the simulated 434//// memory space. Used by stat(), fstat(), and lstat(). 435 436template <typename target_stat, typename host_stat> 437void 438convertStatBuf(target_stat &tgt, host_stat *host, bool fakeTTY = false) 439{ 440 using namespace TheISA; 441 442 if (fakeTTY) 443 tgt->st_dev = 0xA; 444 else 445 tgt->st_dev = host->st_dev; 446 tgt->st_dev = TheISA::htog(tgt->st_dev); 447 tgt->st_ino = host->st_ino; 448 tgt->st_ino = TheISA::htog(tgt->st_ino); 449 tgt->st_mode = host->st_mode; 450 if (fakeTTY) { 451 // Claim to be a character device 452 tgt->st_mode &= ~S_IFMT; // Clear S_IFMT 453 tgt->st_mode |= S_IFCHR; // Set S_IFCHR 454 } 455 tgt->st_mode = TheISA::htog(tgt->st_mode); 456 tgt->st_nlink = host->st_nlink; 457 tgt->st_nlink = TheISA::htog(tgt->st_nlink); 458 tgt->st_uid = host->st_uid; 459 tgt->st_uid = TheISA::htog(tgt->st_uid); 460 tgt->st_gid = host->st_gid; 461 tgt->st_gid = TheISA::htog(tgt->st_gid); 462 if (fakeTTY) 463 tgt->st_rdev = 0x880d; 464 else 465 tgt->st_rdev = host->st_rdev; 466 tgt->st_rdev = TheISA::htog(tgt->st_rdev); 467 tgt->st_size = host->st_size; 468 tgt->st_size = TheISA::htog(tgt->st_size); 469 tgt->st_atimeX = host->st_atime; 470 tgt->st_atimeX = TheISA::htog(tgt->st_atimeX); 471 tgt->st_mtimeX = host->st_mtime; 472 tgt->st_mtimeX = TheISA::htog(tgt->st_mtimeX); 473 tgt->st_ctimeX = host->st_ctime; 474 tgt->st_ctimeX = TheISA::htog(tgt->st_ctimeX); 475 // Force the block size to be 8KB. This helps to ensure buffered io works 476 // consistently across different hosts. 477 tgt->st_blksize = 0x2000; 478 tgt->st_blksize = TheISA::htog(tgt->st_blksize); 479 tgt->st_blocks = host->st_blocks; 480 tgt->st_blocks = TheISA::htog(tgt->st_blocks); 481} 482 483// Same for stat64 484 485template <typename target_stat, typename host_stat64> 486void 487convertStat64Buf(target_stat &tgt, host_stat64 *host, bool fakeTTY = false) 488{ 489 using namespace TheISA; 490 491 convertStatBuf<target_stat, host_stat64>(tgt, host, fakeTTY); 492#if defined(STAT_HAVE_NSEC) 493 tgt->st_atime_nsec = host->st_atime_nsec; 494 tgt->st_atime_nsec = TheISA::htog(tgt->st_atime_nsec); 495 tgt->st_mtime_nsec = host->st_mtime_nsec; 496 tgt->st_mtime_nsec = TheISA::htog(tgt->st_mtime_nsec); 497 tgt->st_ctime_nsec = host->st_ctime_nsec; 498 tgt->st_ctime_nsec = TheISA::htog(tgt->st_ctime_nsec); 499#else 500 tgt->st_atime_nsec = 0; 501 tgt->st_mtime_nsec = 0; 502 tgt->st_ctime_nsec = 0; 503#endif 504} 505 506// Here are a couple of convenience functions 507template<class OS> 508void 509copyOutStatBuf(SETranslatingPortProxy &mem, Addr addr, 510 hst_stat *host, bool fakeTTY = false) 511{ 512 typedef TypedBufferArg<typename OS::tgt_stat> tgt_stat_buf; 513 tgt_stat_buf tgt(addr); 514 convertStatBuf<tgt_stat_buf, hst_stat>(tgt, host, fakeTTY); 515 tgt.copyOut(mem); 516} 517 518template<class OS> 519void 520copyOutStat64Buf(SETranslatingPortProxy &mem, Addr addr, 521 hst_stat64 *host, bool fakeTTY = false) 522{ 523 typedef TypedBufferArg<typename OS::tgt_stat64> tgt_stat_buf; 524 tgt_stat_buf tgt(addr); 525 convertStat64Buf<tgt_stat_buf, hst_stat64>(tgt, host, fakeTTY); 526 tgt.copyOut(mem); 527} 528 529template <class OS> 530void 531copyOutStatfsBuf(SETranslatingPortProxy &mem, Addr addr, 532 hst_statfs *host) 533{ 534 TypedBufferArg<typename OS::tgt_statfs> tgt(addr); 535 536 tgt->f_type = TheISA::htog(host->f_type); 537#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) 538 tgt->f_bsize = TheISA::htog(host->f_iosize); 539#else 540 tgt->f_bsize = TheISA::htog(host->f_bsize); 541#endif 542 tgt->f_blocks = TheISA::htog(host->f_blocks); 543 tgt->f_bfree = TheISA::htog(host->f_bfree); 544 tgt->f_bavail = TheISA::htog(host->f_bavail); 545 tgt->f_files = TheISA::htog(host->f_files); 546 tgt->f_ffree = TheISA::htog(host->f_ffree); 547 memcpy(&tgt->f_fsid, &host->f_fsid, sizeof(host->f_fsid)); 548#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) 549 tgt->f_namelen = TheISA::htog(host->f_namemax); 550 tgt->f_frsize = TheISA::htog(host->f_bsize); 551#elif defined(__APPLE__) 552 tgt->f_namelen = 0; 553 tgt->f_frsize = 0; 554#else 555 tgt->f_namelen = TheISA::htog(host->f_namelen); 556 tgt->f_frsize = TheISA::htog(host->f_frsize); 557#endif 558#if defined(__linux__) 559 memcpy(&tgt->f_spare, &host->f_spare, sizeof(host->f_spare)); 560#else 561 /* 562 * The fields are different sizes per OS. Don't bother with 563 * f_spare or f_reserved on non-Linux for now. 564 */ 565 memset(&tgt->f_spare, 0, sizeof(tgt->f_spare)); 566#endif 567 568 tgt.copyOut(mem); 569} 570 571/// Target ioctl() handler. For the most part, programs call ioctl() 572/// only to find out if their stdout is a tty, to determine whether to 573/// do line or block buffering. We always claim that output fds are 574/// not TTYs to provide repeatable results. 575template <class OS> 576SyscallReturn 577ioctlFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 578{ 579 int index = 0; 580 int tgt_fd = p->getSyscallArg(tc, index); 581 unsigned req = p->getSyscallArg(tc, index); 582 583 DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", tgt_fd, req); 584 585 if (OS::isTtyReq(req)) 586 return -ENOTTY; 587 588 auto dfdp = std::dynamic_pointer_cast<DeviceFDEntry>((*p->fds)[tgt_fd]); 589 if (!dfdp) 590 return -EBADF; 591 592 /** 593 * If the driver is valid, issue the ioctl through it. Otherwise, 594 * there's an implicit assumption that the device is a TTY type and we 595 * return that we do not have a valid TTY. 596 */ 597 EmulatedDriver *emul_driver = dfdp->getDriver(); 598 if (emul_driver) 599 return emul_driver->ioctl(p, tc, req); 600 601 /** 602 * For lack of a better return code, return ENOTTY. Ideally, we should 603 * return something better here, but at least we issue the warning. 604 */ 605 warn("Unsupported ioctl call (return ENOTTY): ioctl(%d, 0x%x, ...) @ \n", 606 tgt_fd, req, tc->pcState()); 607 return -ENOTTY; 608} 609 610template <class OS> 611SyscallReturn 612openImpl(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc, 613 bool isopenat) 614{ 615 int index = 0; 616 int tgt_dirfd = -1; 617 618 /** 619 * If using the openat variant, read in the target directory file 620 * descriptor from the simulated process. 621 */ 622 if (isopenat) 623 tgt_dirfd = p->getSyscallArg(tc, index); 624 625 /** 626 * Retrieve the simulated process' memory proxy and then read in the path 627 * string from that memory space into the host's working memory space. 628 */ 629 std::string path; 630 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 631 return -EFAULT; 632 633#ifdef __CYGWIN32__ 634 int host_flags = O_BINARY; 635#else 636 int host_flags = 0; 637#endif 638 /** 639 * Translate target flags into host flags. Flags exist which are not 640 * ported between architectures which can cause check failures. 641 */ 642 int tgt_flags = p->getSyscallArg(tc, index); 643 for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) { 644 if (tgt_flags & OS::openFlagTable[i].tgtFlag) { 645 tgt_flags &= ~OS::openFlagTable[i].tgtFlag; 646 host_flags |= OS::openFlagTable[i].hostFlag; 647 } 648 } 649 if (tgt_flags) { 650 warn("open%s: cannot decode flags 0x%x", 651 isopenat ? "at" : "", tgt_flags); 652 } 653#ifdef __CYGWIN32__ 654 host_flags |= O_BINARY; 655#endif 656 657 int mode = p->getSyscallArg(tc, index); 658 659 /** 660 * If the simulated process called open or openat with AT_FDCWD specified, 661 * take the current working directory value which was passed into the 662 * process class as a Python parameter and append the current path to 663 * create a full path. 664 * Otherwise, openat with a valid target directory file descriptor has 665 * been called. If the path option, which was passed in as a parameter, 666 * is not absolute, retrieve the directory file descriptor's path and 667 * prepend it to the path passed in as a parameter. 668 * In every case, we should have a full path (which is relevant to the 669 * host) to work with after this block has been passed. 670 */ 671 if (!isopenat || (isopenat && tgt_dirfd == OS::TGT_AT_FDCWD)) { 672 path = p->fullPath(path); 673 } else if (!startswith(path, "/")) { 674 std::shared_ptr<FDEntry> fdep = ((*p->fds)[tgt_dirfd]); 675 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep); 676 if (!ffdp) 677 return -EBADF; 678 path.insert(0, ffdp->getFileName()); 679 } 680 681 /** 682 * Since this is an emulated environment, we create pseudo file 683 * descriptors for device requests that have been registered with 684 * the process class through Python; this allows us to create a file 685 * descriptor for subsequent ioctl or mmap calls. 686 */ 687 if (startswith(path, "/dev/")) { 688 std::string filename = path.substr(strlen("/dev/")); 689 EmulatedDriver *drv = p->findDriver(filename); 690 if (drv) { 691 DPRINTF_SYSCALL(Verbose, "open%s: passing call to " 692 "driver open with path[%s]\n", 693 isopenat ? "at" : "", path.c_str()); 694 return drv->open(p, tc, mode, host_flags); 695 } 696 /** 697 * Fall through here for pass through to host devices, such 698 * as /dev/zero 699 */ 700 } 701 702 /** 703 * Some special paths and files cannot be called on the host and need 704 * to be handled as special cases inside the simulator. 705 * If the full path that was created above does not match any of the 706 * special cases, pass it through to the open call on the host to let 707 * the host open the file on our behalf. 708 * If the host cannot open the file, return the host's error code back 709 * through the system call to the simulated process. 710 */ 711 int sim_fd = -1; 712 std::vector<std::string> special_paths = 713 { "/proc/", "/system/", "/sys/", "/platform/", "/etc/passwd" }; 714 for (auto entry : special_paths) { 715 if (startswith(path, entry)) 716 sim_fd = OS::openSpecialFile(path, p, tc); 717 } 718 if (sim_fd == -1) { 719 sim_fd = open(path.c_str(), host_flags, mode); 720 } 721 if (sim_fd == -1) { 722 int local = -errno; 723 DPRINTF_SYSCALL(Verbose, "open%s: failed -> path:%s\n", 724 isopenat ? "at" : "", path.c_str()); 725 return local; 726 } 727 728 /** 729 * The file was opened successfully and needs to be recorded in the 730 * process' file descriptor array so that it can be retrieved later. 731 * The target file descriptor that is chosen will be the lowest unused 732 * file descriptor. 733 * Return the indirect target file descriptor back to the simulated 734 * process to act as a handle for the opened file. 735 */ 736 auto ffdp = std::make_shared<FileFDEntry>(sim_fd, host_flags, path, 0); 737 int tgt_fd = p->fds->allocFD(ffdp); 738 DPRINTF_SYSCALL(Verbose, "open%s: sim_fd[%d], target_fd[%d] -> path:%s\n", 739 isopenat ? "at" : "", sim_fd, tgt_fd, path.c_str()); 740 return tgt_fd; 741} 742 743/// Target open() handler. 744template <class OS> 745SyscallReturn 746openFunc(SyscallDesc *desc, int callnum, Process *process, 747 ThreadContext *tc) 748{ 749 return openImpl<OS>(desc, callnum, process, tc, false); 750} 751 752/// Target openat() handler. 753template <class OS> 754SyscallReturn 755openatFunc(SyscallDesc *desc, int callnum, Process *process, 756 ThreadContext *tc) 757{ 758 return openImpl<OS>(desc, callnum, process, tc, true); 759} 760 761/// Target unlinkat() handler. 762template <class OS> 763SyscallReturn 764unlinkatFunc(SyscallDesc *desc, int callnum, Process *process, 765 ThreadContext *tc) 766{ 767 int index = 0; 768 int dirfd = process->getSyscallArg(tc, index); 769 if (dirfd != OS::TGT_AT_FDCWD) 770 warn("unlinkat: first argument not AT_FDCWD; unlikely to work"); 771 772 return unlinkHelper(desc, callnum, process, tc, 1); 773} 774 775/// Target facessat() handler 776template <class OS> 777SyscallReturn 778faccessatFunc(SyscallDesc *desc, int callnum, Process *process, 779 ThreadContext *tc) 780{ 781 int index = 0; 782 int dirfd = process->getSyscallArg(tc, index); 783 if (dirfd != OS::TGT_AT_FDCWD) 784 warn("faccessat: first argument not AT_FDCWD; unlikely to work"); 785 return accessFunc(desc, callnum, process, tc, 1); 786} 787 788/// Target readlinkat() handler 789template <class OS> 790SyscallReturn 791readlinkatFunc(SyscallDesc *desc, int callnum, Process *process, 792 ThreadContext *tc) 793{ 794 int index = 0; 795 int dirfd = process->getSyscallArg(tc, index); 796 if (dirfd != OS::TGT_AT_FDCWD) 797 warn("openat: first argument not AT_FDCWD; unlikely to work"); 798 return readlinkFunc(desc, callnum, process, tc, 1); 799} 800 801/// Target renameat() handler. 802template <class OS> 803SyscallReturn 804renameatFunc(SyscallDesc *desc, int callnum, Process *process, 805 ThreadContext *tc) 806{ 807 int index = 0; 808 809 int olddirfd = process->getSyscallArg(tc, index); 810 if (olddirfd != OS::TGT_AT_FDCWD) 811 warn("renameat: first argument not AT_FDCWD; unlikely to work"); 812 813 std::string old_name; 814 815 if (!tc->getMemProxy().tryReadString(old_name, 816 process->getSyscallArg(tc, index))) 817 return -EFAULT; 818 819 int newdirfd = process->getSyscallArg(tc, index); 820 if (newdirfd != OS::TGT_AT_FDCWD) 821 warn("renameat: third argument not AT_FDCWD; unlikely to work"); 822 823 std::string new_name; 824 825 if (!tc->getMemProxy().tryReadString(new_name, 826 process->getSyscallArg(tc, index))) 827 return -EFAULT; 828 829 // Adjust path for current working directory 830 old_name = process->fullPath(old_name); 831 new_name = process->fullPath(new_name); 832 833 int result = rename(old_name.c_str(), new_name.c_str()); 834 return (result == -1) ? -errno : result; 835} 836 837/// Target sysinfo() handler. 838template <class OS> 839SyscallReturn 840sysinfoFunc(SyscallDesc *desc, int callnum, Process *process, 841 ThreadContext *tc) 842{ 843 844 int index = 0; 845 TypedBufferArg<typename OS::tgt_sysinfo> 846 sysinfo(process->getSyscallArg(tc, index)); 847 848 sysinfo->uptime = seconds_since_epoch; 849 sysinfo->totalram = process->system->memSize(); 850 sysinfo->mem_unit = 1; 851 852 sysinfo.copyOut(tc->getMemProxy()); 853 854 return 0; 855} 856 857/// Target chmod() handler. 858template <class OS> 859SyscallReturn 860chmodFunc(SyscallDesc *desc, int callnum, Process *process, 861 ThreadContext *tc) 862{ 863 std::string path; 864 865 int index = 0; 866 if (!tc->getMemProxy().tryReadString(path, 867 process->getSyscallArg(tc, index))) { 868 return -EFAULT; 869 } 870 871 uint32_t mode = process->getSyscallArg(tc, index); 872 mode_t hostMode = 0; 873 874 // XXX translate mode flags via OS::something??? 875 hostMode = mode; 876 877 // Adjust path for current working directory 878 path = process->fullPath(path); 879 880 // do the chmod 881 int result = chmod(path.c_str(), hostMode); 882 if (result < 0) 883 return -errno; 884 885 return 0; 886} 887 888 889/// Target fchmod() handler. 890template <class OS> 891SyscallReturn 892fchmodFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 893{ 894 int index = 0; 895 int tgt_fd = p->getSyscallArg(tc, index); 896 uint32_t mode = p->getSyscallArg(tc, index); 897 898 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 899 if (!ffdp) 900 return -EBADF; 901 int sim_fd = ffdp->getSimFD(); 902 903 mode_t hostMode = mode; 904 905 int result = fchmod(sim_fd, hostMode); 906 907 return (result < 0) ? -errno : 0; 908} 909 910/// Target mremap() handler. 911template <class OS> 912SyscallReturn 913mremapFunc(SyscallDesc *desc, int callnum, Process *process, ThreadContext *tc) 914{ 915 int index = 0; 916 Addr start = process->getSyscallArg(tc, index); 917 uint64_t old_length = process->getSyscallArg(tc, index); 918 uint64_t new_length = process->getSyscallArg(tc, index); 919 uint64_t flags = process->getSyscallArg(tc, index); 920 uint64_t provided_address = 0; 921 bool use_provided_address = flags & OS::TGT_MREMAP_FIXED; 922 923 if (use_provided_address) 924 provided_address = process->getSyscallArg(tc, index); 925 926 if ((start % TheISA::PageBytes != 0) || 927 (provided_address % TheISA::PageBytes != 0)) { 928 warn("mremap failing: arguments not page aligned"); 929 return -EINVAL; 930 } 931 932 new_length = roundUp(new_length, TheISA::PageBytes); 933 934 if (new_length > old_length) { 935 std::shared_ptr<MemState> mem_state = process->memState; 936 Addr mmap_end = mem_state->getMmapEnd(); 937 938 if ((start + old_length) == mmap_end && 939 (!use_provided_address || provided_address == start)) { 940 // This case cannot occur when growing downward, as 941 // start is greater than or equal to mmap_end. 942 uint64_t diff = new_length - old_length; 943 process->allocateMem(mmap_end, diff); 944 mem_state->setMmapEnd(mmap_end + diff); 945 return start; 946 } else { 947 if (!use_provided_address && !(flags & OS::TGT_MREMAP_MAYMOVE)) { 948 warn("can't remap here and MREMAP_MAYMOVE flag not set\n"); 949 return -ENOMEM; 950 } else { 951 uint64_t new_start = provided_address; 952 if (!use_provided_address) { 953 new_start = process->mmapGrowsDown() ? 954 mmap_end - new_length : mmap_end; 955 mmap_end = process->mmapGrowsDown() ? 956 new_start : mmap_end + new_length; 957 mem_state->setMmapEnd(mmap_end); 958 } 959 960 process->pTable->remap(start, old_length, new_start); 961 warn("mremapping to new vaddr %08p-%08p, adding %d\n", 962 new_start, new_start + new_length, 963 new_length - old_length); 964 // add on the remaining unallocated pages 965 process->allocateMem(new_start + old_length, 966 new_length - old_length, 967 use_provided_address /* clobber */); 968 if (use_provided_address && 969 ((new_start + new_length > mem_state->getMmapEnd() && 970 !process->mmapGrowsDown()) || 971 (new_start < mem_state->getMmapEnd() && 972 process->mmapGrowsDown()))) { 973 // something fishy going on here, at least notify the user 974 // @todo: increase mmap_end? 975 warn("mmap region limit exceeded with MREMAP_FIXED\n"); 976 } 977 warn("returning %08p as start\n", new_start); 978 return new_start; 979 } 980 } 981 } else { 982 if (use_provided_address && provided_address != start) 983 process->pTable->remap(start, new_length, provided_address); 984 process->pTable->unmap(start + new_length, old_length - new_length); 985 return use_provided_address ? provided_address : start; 986 } 987} 988 989/// Target stat() handler. 990template <class OS> 991SyscallReturn 992statFunc(SyscallDesc *desc, int callnum, Process *process, 993 ThreadContext *tc) 994{ 995 std::string path; 996 997 int index = 0; 998 if (!tc->getMemProxy().tryReadString(path, 999 process->getSyscallArg(tc, index))) { 1000 return -EFAULT; 1001 } 1002 Addr bufPtr = process->getSyscallArg(tc, index); 1003 1004 // Adjust path for current working directory 1005 path = process->fullPath(path); 1006 1007 struct stat hostBuf; 1008 int result = stat(path.c_str(), &hostBuf); 1009 1010 if (result < 0) 1011 return -errno; 1012 1013 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1014 1015 return 0; 1016} 1017 1018 1019/// Target stat64() handler. 1020template <class OS> 1021SyscallReturn 1022stat64Func(SyscallDesc *desc, int callnum, Process *process, 1023 ThreadContext *tc) 1024{ 1025 std::string path; 1026 1027 int index = 0; 1028 if (!tc->getMemProxy().tryReadString(path, 1029 process->getSyscallArg(tc, index))) 1030 return -EFAULT; 1031 Addr bufPtr = process->getSyscallArg(tc, index); 1032 1033 // Adjust path for current working directory 1034 path = process->fullPath(path); 1035 1036#if NO_STAT64 1037 struct stat hostBuf; 1038 int result = stat(path.c_str(), &hostBuf); 1039#else 1040 struct stat64 hostBuf; 1041 int result = stat64(path.c_str(), &hostBuf); 1042#endif 1043 1044 if (result < 0) 1045 return -errno; 1046 1047 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1048 1049 return 0; 1050} 1051 1052 1053/// Target fstatat64() handler. 1054template <class OS> 1055SyscallReturn 1056fstatat64Func(SyscallDesc *desc, int callnum, Process *process, 1057 ThreadContext *tc) 1058{ 1059 int index = 0; 1060 int dirfd = process->getSyscallArg(tc, index); 1061 if (dirfd != OS::TGT_AT_FDCWD) 1062 warn("fstatat64: first argument not AT_FDCWD; unlikely to work"); 1063 1064 std::string path; 1065 if (!tc->getMemProxy().tryReadString(path, 1066 process->getSyscallArg(tc, index))) 1067 return -EFAULT; 1068 Addr bufPtr = process->getSyscallArg(tc, index); 1069 1070 // Adjust path for current working directory 1071 path = process->fullPath(path); 1072 1073#if NO_STAT64 1074 struct stat hostBuf; 1075 int result = stat(path.c_str(), &hostBuf); 1076#else 1077 struct stat64 hostBuf; 1078 int result = stat64(path.c_str(), &hostBuf); 1079#endif 1080 1081 if (result < 0) 1082 return -errno; 1083 1084 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1085 1086 return 0; 1087} 1088 1089 1090/// Target fstat64() handler. 1091template <class OS> 1092SyscallReturn 1093fstat64Func(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1094{ 1095 int index = 0; 1096 int tgt_fd = p->getSyscallArg(tc, index); 1097 Addr bufPtr = p->getSyscallArg(tc, index); 1098 1099 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 1100 if (!ffdp) 1101 return -EBADF; 1102 int sim_fd = ffdp->getSimFD(); 1103 1104#if NO_STAT64 1105 struct stat hostBuf; 1106 int result = fstat(sim_fd, &hostBuf); 1107#else 1108 struct stat64 hostBuf; 1109 int result = fstat64(sim_fd, &hostBuf); 1110#endif 1111 1112 if (result < 0) 1113 return -errno; 1114 1115 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (sim_fd == 1)); 1116 1117 return 0; 1118} 1119 1120 1121/// Target lstat() handler. 1122template <class OS> 1123SyscallReturn 1124lstatFunc(SyscallDesc *desc, int callnum, Process *process, 1125 ThreadContext *tc) 1126{ 1127 std::string path; 1128 1129 int index = 0; 1130 if (!tc->getMemProxy().tryReadString(path, 1131 process->getSyscallArg(tc, index))) { 1132 return -EFAULT; 1133 } 1134 Addr bufPtr = process->getSyscallArg(tc, index); 1135 1136 // Adjust path for current working directory 1137 path = process->fullPath(path); 1138 1139 struct stat hostBuf; 1140 int result = lstat(path.c_str(), &hostBuf); 1141 1142 if (result < 0) 1143 return -errno; 1144 1145 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1146 1147 return 0; 1148} 1149 1150/// Target lstat64() handler. 1151template <class OS> 1152SyscallReturn 1153lstat64Func(SyscallDesc *desc, int callnum, Process *process, 1154 ThreadContext *tc) 1155{ 1156 std::string path; 1157 1158 int index = 0; 1159 if (!tc->getMemProxy().tryReadString(path, 1160 process->getSyscallArg(tc, index))) { 1161 return -EFAULT; 1162 } 1163 Addr bufPtr = process->getSyscallArg(tc, index); 1164 1165 // Adjust path for current working directory 1166 path = process->fullPath(path); 1167 1168#if NO_STAT64 1169 struct stat hostBuf; 1170 int result = lstat(path.c_str(), &hostBuf); 1171#else 1172 struct stat64 hostBuf; 1173 int result = lstat64(path.c_str(), &hostBuf); 1174#endif 1175 1176 if (result < 0) 1177 return -errno; 1178 1179 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1180 1181 return 0; 1182} 1183 1184/// Target fstat() handler. 1185template <class OS> 1186SyscallReturn 1187fstatFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1188{ 1189 int index = 0; 1190 int tgt_fd = p->getSyscallArg(tc, index); 1191 Addr bufPtr = p->getSyscallArg(tc, index); 1192 1193 DPRINTF_SYSCALL(Verbose, "fstat(%d, ...)\n", tgt_fd); 1194 1195 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 1196 if (!ffdp) 1197 return -EBADF; 1198 int sim_fd = ffdp->getSimFD(); 1199 1200 struct stat hostBuf; 1201 int result = fstat(sim_fd, &hostBuf); 1202 1203 if (result < 0) 1204 return -errno; 1205 1206 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (sim_fd == 1)); 1207 1208 return 0; 1209} 1210 1211 1212/// Target statfs() handler. 1213template <class OS> 1214SyscallReturn 1215statfsFunc(SyscallDesc *desc, int callnum, Process *process, 1216 ThreadContext *tc) 1217{ 1218#if NO_STATFS 1219 warn("Host OS cannot support calls to statfs. Ignoring syscall"); 1220#else 1221 std::string path; 1222 1223 int index = 0; 1224 if (!tc->getMemProxy().tryReadString(path, 1225 process->getSyscallArg(tc, index))) { 1226 return -EFAULT; 1227 } 1228 Addr bufPtr = process->getSyscallArg(tc, index); 1229 1230 // Adjust path for current working directory 1231 path = process->fullPath(path); 1232 1233 struct statfs hostBuf; 1234 int result = statfs(path.c_str(), &hostBuf); 1235 1236 if (result < 0) 1237 return -errno; 1238 1239 copyOutStatfsBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1240#endif 1241 return 0; 1242} 1243 1244template <class OS> 1245SyscallReturn 1246cloneFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1247{ 1248 int index = 0; 1249 1250 TheISA::IntReg flags = p->getSyscallArg(tc, index); 1251 TheISA::IntReg newStack = p->getSyscallArg(tc, index); 1252 Addr ptidPtr = p->getSyscallArg(tc, index); 1253 1254#if THE_ISA == RISCV_ISA 1255 /** 1256 * Linux kernel 4.15 sets CLONE_BACKWARDS flag for RISC-V. 1257 * The flag defines the list of clone() arguments in the following 1258 * order: flags -> newStack -> ptidPtr -> tlsPtr -> ctidPtr 1259 */ 1260 Addr tlsPtr M5_VAR_USED = p->getSyscallArg(tc, index); 1261 Addr ctidPtr = p->getSyscallArg(tc, index); 1262#else 1263 Addr ctidPtr = p->getSyscallArg(tc, index); 1264 Addr tlsPtr M5_VAR_USED = p->getSyscallArg(tc, index); 1265#endif 1266 1267 if (((flags & OS::TGT_CLONE_SIGHAND)&& !(flags & OS::TGT_CLONE_VM)) || 1268 ((flags & OS::TGT_CLONE_THREAD) && !(flags & OS::TGT_CLONE_SIGHAND)) || 1269 ((flags & OS::TGT_CLONE_FS) && (flags & OS::TGT_CLONE_NEWNS)) || 1270 ((flags & OS::TGT_CLONE_NEWIPC) && (flags & OS::TGT_CLONE_SYSVSEM)) || 1271 ((flags & OS::TGT_CLONE_NEWPID) && (flags & OS::TGT_CLONE_THREAD)) || 1272 ((flags & OS::TGT_CLONE_VM) && !(newStack))) 1273 return -EINVAL; 1274 1275 ThreadContext *ctc; 1276 if (!(ctc = p->findFreeContext())) 1277 fatal("clone: no spare thread context in system"); 1278 1279 /** 1280 * Note that ProcessParams is generated by swig and there are no other 1281 * examples of how to create anything but this default constructor. The 1282 * fields are manually initialized instead of passing parameters to the 1283 * constructor. 1284 */ 1285 ProcessParams *pp = new ProcessParams(); 1286 pp->executable.assign(*(new std::string(p->progName()))); 1287 pp->cmd.push_back(*(new std::string(p->progName()))); 1288 pp->system = p->system; 1289 pp->cwd.assign(p->getcwd()); 1290 pp->input.assign("stdin"); 1291 pp->output.assign("stdout"); 1292 pp->errout.assign("stderr"); 1293 pp->uid = p->uid(); 1294 pp->euid = p->euid(); 1295 pp->gid = p->gid(); 1296 pp->egid = p->egid(); 1297 1298 /* Find the first free PID that's less than the maximum */ 1299 std::set<int> const& pids = p->system->PIDs; 1300 int temp_pid = *pids.begin(); 1301 do { 1302 temp_pid++; 1303 } while (pids.find(temp_pid) != pids.end()); 1304 if (temp_pid >= System::maxPID) 1305 fatal("temp_pid is too large: %d", temp_pid); 1306 1307 pp->pid = temp_pid; 1308 pp->ppid = (flags & OS::TGT_CLONE_THREAD) ? p->ppid() : p->pid(); 1309 Process *cp = pp->create(); 1310 delete pp; 1311 1312 Process *owner = ctc->getProcessPtr(); 1313 ctc->setProcessPtr(cp); 1314 cp->assignThreadContext(ctc->contextId()); 1315 owner->revokeThreadContext(ctc->contextId()); 1316 1317 if (flags & OS::TGT_CLONE_PARENT_SETTID) { 1318 BufferArg ptidBuf(ptidPtr, sizeof(long)); 1319 long *ptid = (long *)ptidBuf.bufferPtr(); 1320 *ptid = cp->pid(); 1321 ptidBuf.copyOut(tc->getMemProxy()); 1322 } 1323 1324 cp->initState(); 1325 p->clone(tc, ctc, cp, flags); 1326 1327 if (flags & OS::TGT_CLONE_THREAD) { 1328 delete cp->sigchld; 1329 cp->sigchld = p->sigchld; 1330 } else if (flags & OS::TGT_SIGCHLD) { 1331 *cp->sigchld = true; 1332 } 1333 1334 if (flags & OS::TGT_CLONE_CHILD_SETTID) { 1335 BufferArg ctidBuf(ctidPtr, sizeof(long)); 1336 long *ctid = (long *)ctidBuf.bufferPtr(); 1337 *ctid = cp->pid(); 1338 ctidBuf.copyOut(ctc->getMemProxy()); 1339 } 1340 1341 if (flags & OS::TGT_CLONE_CHILD_CLEARTID) 1342 cp->childClearTID = (uint64_t)ctidPtr; 1343 1344 ctc->clearArchRegs(); 1345 1346#if THE_ISA == ALPHA_ISA 1347 TheISA::copyMiscRegs(tc, ctc); 1348#elif THE_ISA == SPARC_ISA 1349 TheISA::copyRegs(tc, ctc); 1350 ctc->setIntReg(TheISA::NumIntArchRegs + 6, 0); 1351 ctc->setIntReg(TheISA::NumIntArchRegs + 4, 0); 1352 ctc->setIntReg(TheISA::NumIntArchRegs + 3, TheISA::NWindows - 2); 1353 ctc->setIntReg(TheISA::NumIntArchRegs + 5, TheISA::NWindows); 1354 ctc->setMiscReg(TheISA::MISCREG_CWP, 0); 1355 ctc->setIntReg(TheISA::NumIntArchRegs + 7, 0); 1356 ctc->setMiscRegNoEffect(TheISA::MISCREG_TL, 0); 1357 ctc->setMiscReg(TheISA::MISCREG_ASI, TheISA::ASI_PRIMARY); 1358 for (int y = 8; y < 32; y++) 1359 ctc->setIntReg(y, tc->readIntReg(y)); 1360#elif THE_ISA == ARM_ISA or THE_ISA == X86_ISA or THE_ISA == RISCV_ISA 1361 TheISA::copyRegs(tc, ctc); 1362#endif 1363 1364#if THE_ISA == X86_ISA 1365 if (flags & OS::TGT_CLONE_SETTLS) { 1366 ctc->setMiscRegNoEffect(TheISA::MISCREG_FS_BASE, tlsPtr); 1367 ctc->setMiscRegNoEffect(TheISA::MISCREG_FS_EFF_BASE, tlsPtr); 1368 } 1369#endif 1370 1371 if (newStack) 1372 ctc->setIntReg(TheISA::StackPointerReg, newStack); 1373 1374 cp->setSyscallReturn(ctc, 0); 1375 1376#if THE_ISA == ALPHA_ISA 1377 ctc->setIntReg(TheISA::SyscallSuccessReg, 0); 1378#elif THE_ISA == SPARC_ISA 1379 tc->setIntReg(TheISA::SyscallPseudoReturnReg, 0); 1380 ctc->setIntReg(TheISA::SyscallPseudoReturnReg, 1); 1381#endif 1382 1383 ctc->pcState(tc->nextInstAddr()); 1384 ctc->activate(); 1385 1386 return cp->pid(); 1387} 1388 1389/// Target fstatfs() handler. 1390template <class OS> 1391SyscallReturn 1392fstatfsFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1393{ 1394 int index = 0; 1395 int tgt_fd = p->getSyscallArg(tc, index); 1396 Addr bufPtr = p->getSyscallArg(tc, index); 1397 1398 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 1399 if (!ffdp) 1400 return -EBADF; 1401 int sim_fd = ffdp->getSimFD(); 1402 1403 struct statfs hostBuf; 1404 int result = fstatfs(sim_fd, &hostBuf); 1405 1406 if (result < 0) 1407 return -errno; 1408 1409 copyOutStatfsBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1410 1411 return 0; 1412} 1413 1414 1415/// Target writev() handler. 1416template <class OS> 1417SyscallReturn 1418writevFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1419{ 1420 int index = 0; 1421 int tgt_fd = p->getSyscallArg(tc, index); 1422 1423 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 1424 if (!hbfdp) 1425 return -EBADF; 1426 int sim_fd = hbfdp->getSimFD(); 1427 1428 SETranslatingPortProxy &prox = tc->getMemProxy(); 1429 uint64_t tiov_base = p->getSyscallArg(tc, index); 1430 size_t count = p->getSyscallArg(tc, index); 1431 struct iovec hiov[count]; 1432 for (size_t i = 0; i < count; ++i) { 1433 typename OS::tgt_iovec tiov; 1434 1435 prox.readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec), 1436 (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec)); 1437 hiov[i].iov_len = TheISA::gtoh(tiov.iov_len); 1438 hiov[i].iov_base = new char [hiov[i].iov_len]; 1439 prox.readBlob(TheISA::gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base, 1440 hiov[i].iov_len); 1441 } 1442 1443 int result = writev(sim_fd, hiov, count); 1444 1445 for (size_t i = 0; i < count; ++i) 1446 delete [] (char *)hiov[i].iov_base; 1447 1448 if (result < 0) 1449 return -errno; 1450 1451 return result; 1452} 1453 1454/// Real mmap handler. 1455template <class OS> 1456SyscallReturn 1457mmapImpl(SyscallDesc *desc, int num, Process *p, ThreadContext *tc, 1458 bool is_mmap2) 1459{ 1460 int index = 0; 1461 Addr start = p->getSyscallArg(tc, index); 1462 uint64_t length = p->getSyscallArg(tc, index); 1463 int prot = p->getSyscallArg(tc, index); 1464 int tgt_flags = p->getSyscallArg(tc, index); 1465 int tgt_fd = p->getSyscallArg(tc, index); 1466 int offset = p->getSyscallArg(tc, index); 1467 1468 if (is_mmap2) 1469 offset *= TheISA::PageBytes; 1470 1471 if (start & (TheISA::PageBytes - 1) || 1472 offset & (TheISA::PageBytes - 1) || 1473 (tgt_flags & OS::TGT_MAP_PRIVATE && 1474 tgt_flags & OS::TGT_MAP_SHARED) || 1475 (!(tgt_flags & OS::TGT_MAP_PRIVATE) && 1476 !(tgt_flags & OS::TGT_MAP_SHARED)) || 1477 !length) { 1478 return -EINVAL; 1479 } 1480 1481 if ((prot & PROT_WRITE) && (tgt_flags & OS::TGT_MAP_SHARED)) { 1482 // With shared mmaps, there are two cases to consider: 1483 // 1) anonymous: writes should modify the mapping and this should be 1484 // visible to observers who share the mapping. Currently, it's 1485 // difficult to update the shared mapping because there's no 1486 // structure which maintains information about the which virtual 1487 // memory areas are shared. If that structure existed, it would be 1488 // possible to make the translations point to the same frames. 1489 // 2) file-backed: writes should modify the mapping and the file 1490 // which is backed by the mapping. The shared mapping problem is the 1491 // same as what was mentioned about the anonymous mappings. For 1492 // file-backed mappings, the writes to the file are difficult 1493 // because it requires syncing what the mapping holds with the file 1494 // that resides on the host system. So, any write on a real system 1495 // would cause the change to be propagated to the file mapping at 1496 // some point in the future (the inode is tracked along with the 1497 // mapping). This isn't guaranteed to always happen, but it usually 1498 // works well enough. The guarantee is provided by the msync system 1499 // call. We could force the change through with shared mappings with 1500 // a call to msync, but that again would require more information 1501 // than we currently maintain. 1502 warn("mmap: writing to shared mmap region is currently " 1503 "unsupported. The write succeeds on the target, but it " 1504 "will not be propagated to the host or shared mappings"); 1505 } 1506 1507 length = roundUp(length, TheISA::PageBytes); 1508 1509 int sim_fd = -1; 1510 uint8_t *pmap = nullptr; 1511 if (!(tgt_flags & OS::TGT_MAP_ANONYMOUS)) { 1512 std::shared_ptr<FDEntry> fdep = (*p->fds)[tgt_fd]; 1513 1514 auto dfdp = std::dynamic_pointer_cast<DeviceFDEntry>(fdep); 1515 if (dfdp) { 1516 EmulatedDriver *emul_driver = dfdp->getDriver(); 1517 return emul_driver->mmap(p, tc, start, length, prot, 1518 tgt_flags, tgt_fd, offset); 1519 } 1520 1521 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep); 1522 if (!ffdp) 1523 return -EBADF; 1524 sim_fd = ffdp->getSimFD(); 1525 1526 pmap = (decltype(pmap))mmap(nullptr, length, PROT_READ, MAP_PRIVATE, 1527 sim_fd, offset); 1528 1529 if (pmap == (decltype(pmap))-1) { 1530 warn("mmap: failed to map file into host address space"); 1531 return -errno; 1532 } 1533 } 1534 1535 // Extend global mmap region if necessary. Note that we ignore the 1536 // start address unless MAP_FIXED is specified. 1537 if (!(tgt_flags & OS::TGT_MAP_FIXED)) { 1538 std::shared_ptr<MemState> mem_state = p->memState; 1539 Addr mmap_end = mem_state->getMmapEnd(); 1540 1541 start = p->mmapGrowsDown() ? mmap_end - length : mmap_end; 1542 mmap_end = p->mmapGrowsDown() ? start : mmap_end + length; 1543 1544 mem_state->setMmapEnd(mmap_end); 1545 } 1546 1547 DPRINTF_SYSCALL(Verbose, " mmap range is 0x%x - 0x%x\n", 1548 start, start + length - 1); 1549 1550 // We only allow mappings to overwrite existing mappings if 1551 // TGT_MAP_FIXED is set. Otherwise it shouldn't be a problem 1552 // because we ignore the start hint if TGT_MAP_FIXED is not set. 1553 int clobber = tgt_flags & OS::TGT_MAP_FIXED; 1554 if (clobber) { 1555 for (auto tc : p->system->threadContexts) { 1556 // If we might be overwriting old mappings, we need to 1557 // invalidate potentially stale mappings out of the TLBs. 1558 tc->getDTBPtr()->flushAll(); 1559 tc->getITBPtr()->flushAll(); 1560 } 1561 } 1562 1563 // Allocate physical memory and map it in. If the page table is already 1564 // mapped and clobber is not set, the simulator will issue throw a 1565 // fatal and bail out of the simulation. 1566 p->allocateMem(start, length, clobber); 1567 1568 // Transfer content into target address space. 1569 SETranslatingPortProxy &tp = tc->getMemProxy(); 1570 if (tgt_flags & OS::TGT_MAP_ANONYMOUS) { 1571 // In general, we should zero the mapped area for anonymous mappings, 1572 // with something like: 1573 // tp.memsetBlob(start, 0, length); 1574 // However, given that we don't support sparse mappings, and 1575 // some applications can map a couple of gigabytes of space 1576 // (intending sparse usage), that can get painfully expensive. 1577 // Fortunately, since we don't properly implement munmap either, 1578 // there's no danger of remapping used memory, so for now all 1579 // newly mapped memory should already be zeroed so we can skip it. 1580 } else { 1581 // It is possible to mmap an area larger than a file, however 1582 // accessing unmapped portions the system triggers a "Bus error" 1583 // on the host. We must know when to stop copying the file from 1584 // the host into the target address space. 1585 struct stat file_stat; 1586 if (fstat(sim_fd, &file_stat) > 0) 1587 fatal("mmap: cannot stat file"); 1588 1589 // Copy the portion of the file that is resident. This requires 1590 // checking both the mmap size and the filesize that we are 1591 // trying to mmap into this space; the mmap size also depends 1592 // on the specified offset into the file. 1593 uint64_t size = std::min((uint64_t)file_stat.st_size - offset, 1594 length); 1595 tp.writeBlob(start, pmap, size); 1596 1597 // Cleanup the mmap region before exiting this function. 1598 munmap(pmap, length); 1599 1600 // Maintain the symbol table for dynamic executables. 1601 // The loader will call mmap to map the images into its address 1602 // space and we intercept that here. We can verify that we are 1603 // executing inside the loader by checking the program counter value. 1604 // XXX: with multiprogrammed workloads or multi-node configurations, 1605 // this will not work since there is a single global symbol table. 1606 ObjectFile *interpreter = p->getInterpreter(); 1607 if (interpreter) { 1608 Addr text_start = interpreter->textBase(); 1609 Addr text_end = text_start + interpreter->textSize(); 1610 1611 Addr pc = tc->pcState().pc(); 1612 1613 if (pc >= text_start && pc < text_end) { 1614 std::shared_ptr<FDEntry> fdep = (*p->fds)[tgt_fd]; 1615 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep); 1616 ObjectFile *lib = createObjectFile(ffdp->getFileName()); 1617 1618 if (lib) { 1619 lib->loadAllSymbols(debugSymbolTable, 1620 lib->textBase(), start); 1621 } 1622 } 1623 } 1624 1625 // Note that we do not zero out the remainder of the mapping. This 1626 // is done by a real system, but it probably will not affect 1627 // execution (hopefully). 1628 } 1629 1630 return start; 1631} 1632 1633template <class OS> 1634SyscallReturn 1635pwrite64Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1636{ 1637 int index = 0; 1638 int tgt_fd = p->getSyscallArg(tc, index); 1639 Addr bufPtr = p->getSyscallArg(tc, index); 1640 int nbytes = p->getSyscallArg(tc, index); 1641 int offset = p->getSyscallArg(tc, index); 1642 1643 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 1644 if (!ffdp) 1645 return -EBADF; 1646 int sim_fd = ffdp->getSimFD(); 1647 1648 BufferArg bufArg(bufPtr, nbytes); 1649 bufArg.copyIn(tc->getMemProxy()); 1650 1651 int bytes_written = pwrite(sim_fd, bufArg.bufferPtr(), nbytes, offset); 1652 1653 return (bytes_written == -1) ? -errno : bytes_written; 1654} 1655 1656/// Target mmap() handler. 1657template <class OS> 1658SyscallReturn 1659mmapFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1660{ 1661 return mmapImpl<OS>(desc, num, p, tc, false); 1662} 1663 1664/// Target mmap2() handler. 1665template <class OS> 1666SyscallReturn 1667mmap2Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1668{ 1669 return mmapImpl<OS>(desc, num, p, tc, true); 1670} 1671 1672/// Target getrlimit() handler. 1673template <class OS> 1674SyscallReturn 1675getrlimitFunc(SyscallDesc *desc, int callnum, Process *process, 1676 ThreadContext *tc) 1677{ 1678 int index = 0; 1679 unsigned resource = process->getSyscallArg(tc, index); 1680 TypedBufferArg<typename OS::rlimit> rlp(process->getSyscallArg(tc, index)); 1681 1682 switch (resource) { 1683 case OS::TGT_RLIMIT_STACK: 1684 // max stack size in bytes: make up a number (8MB for now) 1685 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; 1686 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1687 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1688 break; 1689 1690 case OS::TGT_RLIMIT_DATA: 1691 // max data segment size in bytes: make up a number 1692 rlp->rlim_cur = rlp->rlim_max = 256 * 1024 * 1024; 1693 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1694 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1695 break; 1696 1697 default: 1698 warn("getrlimit: unimplemented resource %d", resource); 1699 return -EINVAL; 1700 break; 1701 } 1702 1703 rlp.copyOut(tc->getMemProxy()); 1704 return 0; 1705} 1706 1707template <class OS> 1708SyscallReturn 1709prlimitFunc(SyscallDesc *desc, int callnum, Process *process, 1710 ThreadContext *tc) 1711{ 1712 int index = 0; 1713 if (process->getSyscallArg(tc, index) != 0) 1714 { 1715 warn("prlimit: ignoring rlimits for nonzero pid"); 1716 return -EPERM; 1717 } 1718 int resource = process->getSyscallArg(tc, index); 1719 Addr n = process->getSyscallArg(tc, index); 1720 if (n != 0) 1721 warn("prlimit: ignoring new rlimit"); 1722 Addr o = process->getSyscallArg(tc, index); 1723 if (o != 0) 1724 { 1725 TypedBufferArg<typename OS::rlimit> rlp(o); 1726 switch (resource) { 1727 case OS::TGT_RLIMIT_STACK: 1728 // max stack size in bytes: make up a number (8MB for now) 1729 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; 1730 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1731 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1732 break; 1733 case OS::TGT_RLIMIT_DATA: 1734 // max data segment size in bytes: make up a number 1735 rlp->rlim_cur = rlp->rlim_max = 256*1024*1024; 1736 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1737 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1738 break; 1739 default: 1740 warn("prlimit: unimplemented resource %d", resource); 1741 return -EINVAL; 1742 break; 1743 } 1744 rlp.copyOut(tc->getMemProxy()); 1745 } 1746 return 0; 1747} 1748 1749/// Target clock_gettime() function. 1750template <class OS> 1751SyscallReturn 1752clock_gettimeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1753{ 1754 int index = 1; 1755 //int clk_id = p->getSyscallArg(tc, index); 1756 TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index)); 1757 1758 getElapsedTimeNano(tp->tv_sec, tp->tv_nsec); 1759 tp->tv_sec += seconds_since_epoch; 1760 tp->tv_sec = TheISA::htog(tp->tv_sec); 1761 tp->tv_nsec = TheISA::htog(tp->tv_nsec); 1762 1763 tp.copyOut(tc->getMemProxy()); 1764 1765 return 0; 1766} 1767 1768/// Target clock_getres() function. 1769template <class OS> 1770SyscallReturn 1771clock_getresFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1772{ 1773 int index = 1; 1774 TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index)); 1775 1776 // Set resolution at ns, which is what clock_gettime() returns 1777 tp->tv_sec = 0; 1778 tp->tv_nsec = 1; 1779 1780 tp.copyOut(tc->getMemProxy()); 1781 1782 return 0; 1783} 1784 1785/// Target gettimeofday() handler. 1786template <class OS> 1787SyscallReturn 1788gettimeofdayFunc(SyscallDesc *desc, int callnum, Process *process, 1789 ThreadContext *tc) 1790{ 1791 int index = 0; 1792 TypedBufferArg<typename OS::timeval> tp(process->getSyscallArg(tc, index)); 1793 1794 getElapsedTimeMicro(tp->tv_sec, tp->tv_usec); 1795 tp->tv_sec += seconds_since_epoch; 1796 tp->tv_sec = TheISA::htog(tp->tv_sec); 1797 tp->tv_usec = TheISA::htog(tp->tv_usec); 1798 1799 tp.copyOut(tc->getMemProxy()); 1800 1801 return 0; 1802} 1803 1804 1805/// Target utimes() handler. 1806template <class OS> 1807SyscallReturn 1808utimesFunc(SyscallDesc *desc, int callnum, Process *process, 1809 ThreadContext *tc) 1810{ 1811 std::string path; 1812 1813 int index = 0; 1814 if (!tc->getMemProxy().tryReadString(path, 1815 process->getSyscallArg(tc, index))) { 1816 return -EFAULT; 1817 } 1818 1819 TypedBufferArg<typename OS::timeval [2]> 1820 tp(process->getSyscallArg(tc, index)); 1821 tp.copyIn(tc->getMemProxy()); 1822 1823 struct timeval hostTimeval[2]; 1824 for (int i = 0; i < 2; ++i) { 1825 hostTimeval[i].tv_sec = TheISA::gtoh((*tp)[i].tv_sec); 1826 hostTimeval[i].tv_usec = TheISA::gtoh((*tp)[i].tv_usec); 1827 } 1828 1829 // Adjust path for current working directory 1830 path = process->fullPath(path); 1831 1832 int result = utimes(path.c_str(), hostTimeval); 1833 1834 if (result < 0) 1835 return -errno; 1836 1837 return 0; 1838} 1839 1840template <class OS> 1841SyscallReturn 1842execveFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1843{ 1844 desc->setFlags(0); 1845 1846 int index = 0; 1847 std::string path; 1848 SETranslatingPortProxy & mem_proxy = tc->getMemProxy(); 1849 if (!mem_proxy.tryReadString(path, p->getSyscallArg(tc, index))) 1850 return -EFAULT; 1851 1852 if (access(path.c_str(), F_OK) == -1) 1853 return -EACCES; 1854 1855 auto read_in = [](std::vector<std::string> & vect, 1856 SETranslatingPortProxy & mem_proxy, 1857 Addr mem_loc) 1858 { 1859 for (int inc = 0; ; inc++) { 1860 BufferArg b((mem_loc + sizeof(Addr) * inc), sizeof(Addr)); 1861 b.copyIn(mem_proxy); 1862 1863 if (!*(Addr*)b.bufferPtr()) 1864 break; 1865 1866 vect.push_back(std::string()); 1867 mem_proxy.tryReadString(vect[inc], *(Addr*)b.bufferPtr()); 1868 } 1869 }; 1870 1871 /** 1872 * Note that ProcessParams is generated by swig and there are no other 1873 * examples of how to create anything but this default constructor. The 1874 * fields are manually initialized instead of passing parameters to the 1875 * constructor. 1876 */ 1877 ProcessParams *pp = new ProcessParams(); 1878 pp->executable = path; 1879 Addr argv_mem_loc = p->getSyscallArg(tc, index); 1880 read_in(pp->cmd, mem_proxy, argv_mem_loc); 1881 Addr envp_mem_loc = p->getSyscallArg(tc, index); 1882 read_in(pp->env, mem_proxy, envp_mem_loc); 1883 pp->uid = p->uid(); 1884 pp->egid = p->egid(); 1885 pp->euid = p->euid(); 1886 pp->gid = p->gid(); 1887 pp->ppid = p->ppid(); 1888 pp->pid = p->pid(); 1889 pp->input.assign("cin"); 1890 pp->output.assign("cout"); 1891 pp->errout.assign("cerr"); 1892 pp->cwd.assign(p->getcwd()); 1893 pp->system = p->system; 1894 /** 1895 * Prevent process object creation with identical PIDs (which will trip 1896 * a fatal check in Process constructor). The execve call is supposed to 1897 * take over the currently executing process' identity but replace 1898 * whatever it is doing with a new process image. Instead of hijacking 1899 * the process object in the simulator, we create a new process object 1900 * and bind to the previous process' thread below (hijacking the thread). 1901 */ 1902 p->system->PIDs.erase(p->pid()); 1903 Process *new_p = pp->create(); 1904 delete pp; 1905 1906 /** 1907 * Work through the file descriptor array and close any files marked 1908 * close-on-exec. 1909 */ 1910 new_p->fds = p->fds; 1911 for (int i = 0; i < new_p->fds->getSize(); i++) { 1912 std::shared_ptr<FDEntry> fdep = (*new_p->fds)[i]; 1913 if (fdep && fdep->getCOE()) 1914 new_p->fds->closeFDEntry(i); 1915 } 1916 1917 *new_p->sigchld = true; 1918 1919 delete p; 1920 tc->clearArchRegs(); 1921 tc->setProcessPtr(new_p); 1922 new_p->assignThreadContext(tc->contextId()); 1923 new_p->initState(); 1924 tc->activate(); 1925 TheISA::PCState pcState = tc->pcState(); 1926 tc->setNPC(pcState.instAddr()); 1927 1928 desc->setFlags(SyscallDesc::SuppressReturnValue); 1929 return 0; 1930} 1931 1932/// Target getrusage() function. 1933template <class OS> 1934SyscallReturn 1935getrusageFunc(SyscallDesc *desc, int callnum, Process *process, 1936 ThreadContext *tc) 1937{ 1938 int index = 0; 1939 int who = process->getSyscallArg(tc, index); // THREAD, SELF, or CHILDREN 1940 TypedBufferArg<typename OS::rusage> rup(process->getSyscallArg(tc, index)); 1941 1942 rup->ru_utime.tv_sec = 0; 1943 rup->ru_utime.tv_usec = 0; 1944 rup->ru_stime.tv_sec = 0; 1945 rup->ru_stime.tv_usec = 0; 1946 rup->ru_maxrss = 0; 1947 rup->ru_ixrss = 0; 1948 rup->ru_idrss = 0; 1949 rup->ru_isrss = 0; 1950 rup->ru_minflt = 0; 1951 rup->ru_majflt = 0; 1952 rup->ru_nswap = 0; 1953 rup->ru_inblock = 0; 1954 rup->ru_oublock = 0; 1955 rup->ru_msgsnd = 0; 1956 rup->ru_msgrcv = 0; 1957 rup->ru_nsignals = 0; 1958 rup->ru_nvcsw = 0; 1959 rup->ru_nivcsw = 0; 1960 1961 switch (who) { 1962 case OS::TGT_RUSAGE_SELF: 1963 getElapsedTimeMicro(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec); 1964 rup->ru_utime.tv_sec = TheISA::htog(rup->ru_utime.tv_sec); 1965 rup->ru_utime.tv_usec = TheISA::htog(rup->ru_utime.tv_usec); 1966 break; 1967 1968 case OS::TGT_RUSAGE_CHILDREN: 1969 // do nothing. We have no child processes, so they take no time. 1970 break; 1971 1972 default: 1973 // don't really handle THREAD or CHILDREN, but just warn and 1974 // plow ahead 1975 warn("getrusage() only supports RUSAGE_SELF. Parameter %d ignored.", 1976 who); 1977 } 1978 1979 rup.copyOut(tc->getMemProxy()); 1980 1981 return 0; 1982} 1983 1984/// Target times() function. 1985template <class OS> 1986SyscallReturn 1987timesFunc(SyscallDesc *desc, int callnum, Process *process, 1988 ThreadContext *tc) 1989{ 1990 int index = 0; 1991 TypedBufferArg<typename OS::tms> bufp(process->getSyscallArg(tc, index)); 1992 1993 // Fill in the time structure (in clocks) 1994 int64_t clocks = curTick() * OS::M5_SC_CLK_TCK / SimClock::Int::s; 1995 bufp->tms_utime = clocks; 1996 bufp->tms_stime = 0; 1997 bufp->tms_cutime = 0; 1998 bufp->tms_cstime = 0; 1999 2000 // Convert to host endianness 2001 bufp->tms_utime = TheISA::htog(bufp->tms_utime); 2002 2003 // Write back 2004 bufp.copyOut(tc->getMemProxy()); 2005 2006 // Return clock ticks since system boot 2007 return clocks; 2008} 2009 2010/// Target time() function. 2011template <class OS> 2012SyscallReturn 2013timeFunc(SyscallDesc *desc, int callnum, Process *process, ThreadContext *tc) 2014{ 2015 typename OS::time_t sec, usec; 2016 getElapsedTimeMicro(sec, usec); 2017 sec += seconds_since_epoch; 2018 2019 int index = 0; 2020 Addr taddr = (Addr)process->getSyscallArg(tc, index); 2021 if (taddr != 0) { 2022 typename OS::time_t t = sec; 2023 t = TheISA::htog(t); 2024 SETranslatingPortProxy &p = tc->getMemProxy(); 2025 p.writeBlob(taddr, (uint8_t*)&t, (int)sizeof(typename OS::time_t)); 2026 } 2027 return sec; 2028} 2029 2030template <class OS> 2031SyscallReturn 2032tgkillFunc(SyscallDesc *desc, int num, Process *process, ThreadContext *tc) 2033{ 2034 int index = 0; 2035 int tgid = process->getSyscallArg(tc, index); 2036 int tid = process->getSyscallArg(tc, index); 2037 int sig = process->getSyscallArg(tc, index); 2038 2039 /** 2040 * This system call is intended to allow killing a specific thread 2041 * within an arbitrary thread group if sanctioned with permission checks. 2042 * It's usually true that threads share the termination signal as pointed 2043 * out by the pthread_kill man page and this seems to be the intended 2044 * usage. Due to this being an emulated environment, assume the following: 2045 * Threads are allowed to call tgkill because the EUID for all threads 2046 * should be the same. There is no signal handling mechanism for kernel 2047 * registration of signal handlers since signals are poorly supported in 2048 * emulation mode. Since signal handlers cannot be registered, all 2049 * threads within in a thread group must share the termination signal. 2050 * We never exhaust PIDs so there's no chance of finding the wrong one 2051 * due to PID rollover. 2052 */ 2053 2054 System *sys = tc->getSystemPtr(); 2055 Process *tgt_proc = nullptr; 2056 for (int i = 0; i < sys->numContexts(); i++) { 2057 Process *temp = sys->threadContexts[i]->getProcessPtr(); 2058 if (temp->pid() == tid) { 2059 tgt_proc = temp; 2060 break; 2061 } 2062 } 2063 2064 if (sig != 0 || sig != OS::TGT_SIGABRT) 2065 return -EINVAL; 2066 2067 if (tgt_proc == nullptr) 2068 return -ESRCH; 2069 2070 if (tgid != -1 && tgt_proc->tgid() != tgid) 2071 return -ESRCH; 2072 2073 if (sig == OS::TGT_SIGABRT) 2074 exitGroupFunc(desc, 252, process, tc); 2075 2076 return 0; 2077} 2078 2079 2080#endif // __SIM_SYSCALL_EMUL_HH__ 2081