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