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