syscall_emul.hh revision 11392
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#define NO_STAT64 (defined(__APPLE__) || defined(__OpenBSD__) || \ 49 defined(__FreeBSD__) || defined(__CYGWIN__) || \ 50 defined(__NetBSD__)) 51 52/// 53/// @file syscall_emul.hh 54/// 55/// This file defines objects used to emulate syscalls from the target 56/// application on the host machine. 57 58#ifdef __CYGWIN32__ 59#include <sys/fcntl.h> // for O_BINARY 60 61#endif 62#include <fcntl.h> 63#include <sys/mman.h> 64#include <sys/stat.h> 65#include <sys/time.h> 66#include <sys/uio.h> 67 68#include <cerrno> 69#include <string> 70 71#include "base/chunk_generator.hh" 72#include "base/intmath.hh" // for RoundUp 73#include "base/loader/object_file.hh" 74#include "base/misc.hh" 75#include "base/trace.hh" 76#include "base/types.hh" 77#include "config/the_isa.hh" 78#include "cpu/base.hh" 79#include "cpu/thread_context.hh" 80#include "debug/SyscallBase.hh" 81#include "debug/SyscallVerbose.hh" 82#include "mem/page_table.hh" 83#include "sim/byteswap.hh" 84#include "sim/emul_driver.hh" 85#include "sim/process.hh" 86#include "sim/syscall_emul_buf.hh" 87#include "sim/syscallreturn.hh" 88#include "sim/system.hh" 89 90// This wrapper macro helps out with readability a bit. FLAGEXT specifies 91// the verbosity and FMT is the message to be appended to the syscall 92// header information. The syscall header information contains the cpuid 93// and thread id. 94#define DPRINTF_SYSCALL(FLAGEXT, FMT, ...) \ 95 DPRINTFS(Syscall##FLAGEXT, tc->getCpuPtr(), "T%d : syscall " FMT, \ 96 tc->threadId(), __VA_ARGS__) 97 98/// 99/// System call descriptor. 100/// 101class SyscallDesc { 102 103 public: 104 105 /// Typedef for target syscall handler functions. 106 typedef SyscallReturn (*FuncPtr)(SyscallDesc *, int num, 107 LiveProcess *, ThreadContext *); 108 109 const char *name; //!< Syscall name (e.g., "open"). 110 FuncPtr funcPtr; //!< Pointer to emulation function. 111 int flags; //!< Flags (see Flags enum). 112 bool warned; //!< Have we warned about unimplemented syscall? 113 114 /// Flag values for controlling syscall behavior. 115 enum Flags { 116 /// Don't set return regs according to funcPtr return value. 117 /// Used for syscalls with non-standard return conventions 118 /// that explicitly set the ThreadContext regs (e.g., 119 /// sigreturn). 120 SuppressReturnValue = 1, 121 WarnOnce = 2 122 }; 123 124 /// Constructor. 125 SyscallDesc(const char *_name, FuncPtr _funcPtr, int _flags = 0) 126 : name(_name), funcPtr(_funcPtr), flags(_flags), warned(false) 127 { 128 } 129 130 /// Emulate the syscall. Public interface for calling through funcPtr. 131 void doSyscall(int callnum, LiveProcess *proc, ThreadContext *tc); 132 133 /// Is the WarnOnce flag set? 134 bool warnOnce() const { return (flags & WarnOnce); } 135}; 136 137 138////////////////////////////////////////////////////////////////////// 139// 140// The following emulation functions are generic enough that they 141// don't need to be recompiled for different emulated OS's. They are 142// defined in sim/syscall_emul.cc. 143// 144////////////////////////////////////////////////////////////////////// 145 146 147/// Handler for unimplemented syscalls that we haven't thought about. 148SyscallReturn unimplementedFunc(SyscallDesc *desc, int num, 149 LiveProcess *p, ThreadContext *tc); 150 151/// Handler for unimplemented syscalls that we never intend to 152/// implement (signal handling, etc.) and should not affect the correct 153/// behavior of the program. Print a warning only if the appropriate 154/// trace flag is enabled. Return success to the target program. 155SyscallReturn ignoreFunc(SyscallDesc *desc, int num, 156 LiveProcess *p, ThreadContext *tc); 157 158/// Target exit() handler: terminate current context. 159SyscallReturn exitFunc(SyscallDesc *desc, int num, 160 LiveProcess *p, ThreadContext *tc); 161 162/// Target exit_group() handler: terminate simulation. (exit all threads) 163SyscallReturn exitGroupFunc(SyscallDesc *desc, int num, 164 LiveProcess *p, ThreadContext *tc); 165 166/// Target getpagesize() handler. 167SyscallReturn getpagesizeFunc(SyscallDesc *desc, int num, 168 LiveProcess *p, ThreadContext *tc); 169 170/// Target brk() handler: set brk address. 171SyscallReturn brkFunc(SyscallDesc *desc, int num, 172 LiveProcess *p, ThreadContext *tc); 173 174/// Target close() handler. 175SyscallReturn closeFunc(SyscallDesc *desc, int num, 176 LiveProcess *p, ThreadContext *tc); 177 178/// Target read() handler. 179SyscallReturn readFunc(SyscallDesc *desc, int num, 180 LiveProcess *p, ThreadContext *tc); 181 182/// Target write() handler. 183SyscallReturn writeFunc(SyscallDesc *desc, int num, 184 LiveProcess *p, ThreadContext *tc); 185 186/// Target lseek() handler. 187SyscallReturn lseekFunc(SyscallDesc *desc, int num, 188 LiveProcess *p, ThreadContext *tc); 189 190/// Target _llseek() handler. 191SyscallReturn _llseekFunc(SyscallDesc *desc, int num, 192 LiveProcess *p, ThreadContext *tc); 193 194/// Target munmap() handler. 195SyscallReturn munmapFunc(SyscallDesc *desc, int num, 196 LiveProcess *p, ThreadContext *tc); 197 198/// Target gethostname() handler. 199SyscallReturn gethostnameFunc(SyscallDesc *desc, int num, 200 LiveProcess *p, ThreadContext *tc); 201 202/// Target getcwd() handler. 203SyscallReturn getcwdFunc(SyscallDesc *desc, int num, 204 LiveProcess *p, ThreadContext *tc); 205 206/// Target readlink() handler. 207SyscallReturn readlinkFunc(SyscallDesc *desc, int num, 208 LiveProcess *p, ThreadContext *tc, 209 int index = 0); 210SyscallReturn readlinkFunc(SyscallDesc *desc, int num, 211 LiveProcess *p, ThreadContext *tc); 212 213/// Target unlink() handler. 214SyscallReturn unlinkHelper(SyscallDesc *desc, int num, 215 LiveProcess *p, ThreadContext *tc, 216 int index); 217SyscallReturn unlinkFunc(SyscallDesc *desc, int num, 218 LiveProcess *p, ThreadContext *tc); 219 220/// Target mkdir() handler. 221SyscallReturn mkdirFunc(SyscallDesc *desc, int num, 222 LiveProcess *p, ThreadContext *tc); 223 224/// Target rename() handler. 225SyscallReturn renameFunc(SyscallDesc *desc, int num, 226 LiveProcess *p, ThreadContext *tc); 227 228 229/// Target truncate() handler. 230SyscallReturn truncateFunc(SyscallDesc *desc, int num, 231 LiveProcess *p, ThreadContext *tc); 232 233 234/// Target ftruncate() handler. 235SyscallReturn ftruncateFunc(SyscallDesc *desc, int num, 236 LiveProcess *p, ThreadContext *tc); 237 238 239/// Target truncate64() handler. 240SyscallReturn truncate64Func(SyscallDesc *desc, int num, 241 LiveProcess *p, ThreadContext *tc); 242 243/// Target ftruncate64() handler. 244SyscallReturn ftruncate64Func(SyscallDesc *desc, int num, 245 LiveProcess *p, ThreadContext *tc); 246 247 248/// Target umask() handler. 249SyscallReturn umaskFunc(SyscallDesc *desc, int num, 250 LiveProcess *p, ThreadContext *tc); 251 252 253/// Target chown() handler. 254SyscallReturn chownFunc(SyscallDesc *desc, int num, 255 LiveProcess *p, ThreadContext *tc); 256 257 258/// Target fchown() handler. 259SyscallReturn fchownFunc(SyscallDesc *desc, int num, 260 LiveProcess *p, ThreadContext *tc); 261 262/// Target dup() handler. 263SyscallReturn dupFunc(SyscallDesc *desc, int num, 264 LiveProcess *process, ThreadContext *tc); 265 266/// Target fnctl() handler. 267SyscallReturn fcntlFunc(SyscallDesc *desc, int num, 268 LiveProcess *process, ThreadContext *tc); 269 270/// Target fcntl64() handler. 271SyscallReturn fcntl64Func(SyscallDesc *desc, int num, 272 LiveProcess *process, ThreadContext *tc); 273 274/// Target setuid() handler. 275SyscallReturn setuidFunc(SyscallDesc *desc, int num, 276 LiveProcess *p, ThreadContext *tc); 277 278/// Target getpid() handler. 279SyscallReturn getpidFunc(SyscallDesc *desc, int num, 280 LiveProcess *p, ThreadContext *tc); 281 282/// Target getuid() handler. 283SyscallReturn getuidFunc(SyscallDesc *desc, int num, 284 LiveProcess *p, ThreadContext *tc); 285 286/// Target getgid() handler. 287SyscallReturn getgidFunc(SyscallDesc *desc, int num, 288 LiveProcess *p, ThreadContext *tc); 289 290/// Target getppid() handler. 291SyscallReturn getppidFunc(SyscallDesc *desc, int num, 292 LiveProcess *p, ThreadContext *tc); 293 294/// Target geteuid() handler. 295SyscallReturn geteuidFunc(SyscallDesc *desc, int num, 296 LiveProcess *p, ThreadContext *tc); 297 298/// Target getegid() handler. 299SyscallReturn getegidFunc(SyscallDesc *desc, int num, 300 LiveProcess *p, ThreadContext *tc); 301 302/// Target clone() handler. 303SyscallReturn cloneFunc(SyscallDesc *desc, int num, 304 LiveProcess *p, ThreadContext *tc); 305 306/// Target access() handler 307SyscallReturn accessFunc(SyscallDesc *desc, int num, 308 LiveProcess *p, ThreadContext *tc); 309SyscallReturn accessFunc(SyscallDesc *desc, int num, 310 LiveProcess *p, ThreadContext *tc, 311 int index); 312 313/// Futex system call 314/// Implemented by Daniel Sanchez 315/// Used by printf's in multi-threaded apps 316template <class OS> 317SyscallReturn 318futexFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 319 ThreadContext *tc) 320{ 321 int index_uaddr = 0; 322 int index_op = 1; 323 int index_val = 2; 324 int index_timeout = 3; 325 326 uint64_t uaddr = process->getSyscallArg(tc, index_uaddr); 327 int op = process->getSyscallArg(tc, index_op); 328 int val = process->getSyscallArg(tc, index_val); 329 uint64_t timeout = process->getSyscallArg(tc, index_timeout); 330 331 std::map<uint64_t, std::list<ThreadContext *> * > 332 &futex_map = tc->getSystemPtr()->futexMap; 333 334 DPRINTF(SyscallVerbose, "In sys_futex: Address=%llx, op=%d, val=%d\n", 335 uaddr, op, val); 336 337 op &= ~OS::TGT_FUTEX_PRIVATE_FLAG; 338 339 if (op == OS::TGT_FUTEX_WAIT) { 340 if (timeout != 0) { 341 warn("sys_futex: FUTEX_WAIT with non-null timeout unimplemented;" 342 "we'll wait indefinitely"); 343 } 344 345 uint8_t *buf = new uint8_t[sizeof(int)]; 346 tc->getMemProxy().readBlob((Addr)uaddr, buf, (int)sizeof(int)); 347 int mem_val = *((int *)buf); 348 delete[] buf; 349 350 if (val != mem_val) { 351 DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAKE, read: %d, " 352 "expected: %d\n", mem_val, val); 353 return -OS::TGT_EWOULDBLOCK; 354 } 355 356 // Queue the thread context 357 std::list<ThreadContext *> * tcWaitList; 358 if (futex_map.count(uaddr)) { 359 tcWaitList = futex_map.find(uaddr)->second; 360 } else { 361 tcWaitList = new std::list<ThreadContext *>(); 362 futex_map.insert(std::pair< uint64_t, 363 std::list<ThreadContext *> * >(uaddr, tcWaitList)); 364 } 365 tcWaitList->push_back(tc); 366 DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAIT, suspending calling " 367 "thread context\n"); 368 tc->suspend(); 369 return 0; 370 } else if (op == OS::TGT_FUTEX_WAKE){ 371 int wokenUp = 0; 372 std::list<ThreadContext *> * tcWaitList; 373 if (futex_map.count(uaddr)) { 374 tcWaitList = futex_map.find(uaddr)->second; 375 while (tcWaitList->size() > 0 && wokenUp < val) { 376 tcWaitList->front()->activate(); 377 tcWaitList->pop_front(); 378 wokenUp++; 379 } 380 if (tcWaitList->empty()) { 381 futex_map.erase(uaddr); 382 delete tcWaitList; 383 } 384 } 385 DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAKE, activated %d waiting " 386 "thread contexts\n", wokenUp); 387 return wokenUp; 388 } else { 389 warn("sys_futex: op %d is not implemented, just returning...", op); 390 return 0; 391 } 392 393} 394 395 396/// Pseudo Funcs - These functions use a different return convension, 397/// returning a second value in a register other than the normal return register 398SyscallReturn pipePseudoFunc(SyscallDesc *desc, int num, 399 LiveProcess *process, ThreadContext *tc); 400 401/// Target getpidPseudo() handler. 402SyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num, 403 LiveProcess *p, ThreadContext *tc); 404 405/// Target getuidPseudo() handler. 406SyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num, 407 LiveProcess *p, ThreadContext *tc); 408 409/// Target getgidPseudo() handler. 410SyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num, 411 LiveProcess *p, ThreadContext *tc); 412 413 414/// A readable name for 1,000,000, for converting microseconds to seconds. 415const int one_million = 1000000; 416/// A readable name for 1,000,000,000, for converting nanoseconds to seconds. 417const int one_billion = 1000000000; 418 419/// Approximate seconds since the epoch (1/1/1970). About a billion, 420/// by my reckoning. We want to keep this a constant (not use the 421/// real-world time) to keep simulations repeatable. 422const unsigned seconds_since_epoch = 1000000000; 423 424/// Helper function to convert current elapsed time to seconds and 425/// microseconds. 426template <class T1, class T2> 427void 428getElapsedTimeMicro(T1 &sec, T2 &usec) 429{ 430 uint64_t elapsed_usecs = curTick() / SimClock::Int::us; 431 sec = elapsed_usecs / one_million; 432 usec = elapsed_usecs % one_million; 433} 434 435/// Helper function to convert current elapsed time to seconds and 436/// nanoseconds. 437template <class T1, class T2> 438void 439getElapsedTimeNano(T1 &sec, T2 &nsec) 440{ 441 uint64_t elapsed_nsecs = curTick() / SimClock::Int::ns; 442 sec = elapsed_nsecs / one_billion; 443 nsec = elapsed_nsecs % one_billion; 444} 445 446////////////////////////////////////////////////////////////////////// 447// 448// The following emulation functions are generic, but need to be 449// templated to account for differences in types, constants, etc. 450// 451////////////////////////////////////////////////////////////////////// 452 453#if NO_STAT64 454 typedef struct stat hst_stat; 455 typedef struct stat hst_stat64; 456#else 457 typedef struct stat hst_stat; 458 typedef struct stat64 hst_stat64; 459#endif 460 461//// Helper function to convert a host stat buffer to a target stat 462//// buffer. Also copies the target buffer out to the simulated 463//// memory space. Used by stat(), fstat(), and lstat(). 464 465template <typename target_stat, typename host_stat> 466static void 467convertStatBuf(target_stat &tgt, host_stat *host, bool fakeTTY = false) 468{ 469 using namespace TheISA; 470 471 if (fakeTTY) 472 tgt->st_dev = 0xA; 473 else 474 tgt->st_dev = host->st_dev; 475 tgt->st_dev = TheISA::htog(tgt->st_dev); 476 tgt->st_ino = host->st_ino; 477 tgt->st_ino = TheISA::htog(tgt->st_ino); 478 tgt->st_mode = host->st_mode; 479 if (fakeTTY) { 480 // Claim to be a character device 481 tgt->st_mode &= ~S_IFMT; // Clear S_IFMT 482 tgt->st_mode |= S_IFCHR; // Set S_IFCHR 483 } 484 tgt->st_mode = TheISA::htog(tgt->st_mode); 485 tgt->st_nlink = host->st_nlink; 486 tgt->st_nlink = TheISA::htog(tgt->st_nlink); 487 tgt->st_uid = host->st_uid; 488 tgt->st_uid = TheISA::htog(tgt->st_uid); 489 tgt->st_gid = host->st_gid; 490 tgt->st_gid = TheISA::htog(tgt->st_gid); 491 if (fakeTTY) 492 tgt->st_rdev = 0x880d; 493 else 494 tgt->st_rdev = host->st_rdev; 495 tgt->st_rdev = TheISA::htog(tgt->st_rdev); 496 tgt->st_size = host->st_size; 497 tgt->st_size = TheISA::htog(tgt->st_size); 498 tgt->st_atimeX = host->st_atime; 499 tgt->st_atimeX = TheISA::htog(tgt->st_atimeX); 500 tgt->st_mtimeX = host->st_mtime; 501 tgt->st_mtimeX = TheISA::htog(tgt->st_mtimeX); 502 tgt->st_ctimeX = host->st_ctime; 503 tgt->st_ctimeX = TheISA::htog(tgt->st_ctimeX); 504 // Force the block size to be 8k. This helps to ensure buffered io works 505 // consistently across different hosts. 506 tgt->st_blksize = 0x2000; 507 tgt->st_blksize = TheISA::htog(tgt->st_blksize); 508 tgt->st_blocks = host->st_blocks; 509 tgt->st_blocks = TheISA::htog(tgt->st_blocks); 510} 511 512// Same for stat64 513 514template <typename target_stat, typename host_stat64> 515static void 516convertStat64Buf(target_stat &tgt, host_stat64 *host, bool fakeTTY = false) 517{ 518 using namespace TheISA; 519 520 convertStatBuf<target_stat, host_stat64>(tgt, host, fakeTTY); 521#if defined(STAT_HAVE_NSEC) 522 tgt->st_atime_nsec = host->st_atime_nsec; 523 tgt->st_atime_nsec = TheISA::htog(tgt->st_atime_nsec); 524 tgt->st_mtime_nsec = host->st_mtime_nsec; 525 tgt->st_mtime_nsec = TheISA::htog(tgt->st_mtime_nsec); 526 tgt->st_ctime_nsec = host->st_ctime_nsec; 527 tgt->st_ctime_nsec = TheISA::htog(tgt->st_ctime_nsec); 528#else 529 tgt->st_atime_nsec = 0; 530 tgt->st_mtime_nsec = 0; 531 tgt->st_ctime_nsec = 0; 532#endif 533} 534 535//Here are a couple convenience functions 536template<class OS> 537static void 538copyOutStatBuf(SETranslatingPortProxy &mem, Addr addr, 539 hst_stat *host, bool fakeTTY = false) 540{ 541 typedef TypedBufferArg<typename OS::tgt_stat> tgt_stat_buf; 542 tgt_stat_buf tgt(addr); 543 convertStatBuf<tgt_stat_buf, hst_stat>(tgt, host, fakeTTY); 544 tgt.copyOut(mem); 545} 546 547template<class OS> 548static void 549copyOutStat64Buf(SETranslatingPortProxy &mem, Addr addr, 550 hst_stat64 *host, bool fakeTTY = false) 551{ 552 typedef TypedBufferArg<typename OS::tgt_stat64> tgt_stat_buf; 553 tgt_stat_buf tgt(addr); 554 convertStat64Buf<tgt_stat_buf, hst_stat64>(tgt, host, fakeTTY); 555 tgt.copyOut(mem); 556} 557 558/// Target ioctl() handler. For the most part, programs call ioctl() 559/// only to find out if their stdout is a tty, to determine whether to 560/// do line or block buffering. We always claim that output fds are 561/// not TTYs to provide repeatable results. 562template <class OS> 563SyscallReturn 564ioctlFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 565 ThreadContext *tc) 566{ 567 int index = 0; 568 int tgt_fd = process->getSyscallArg(tc, index); 569 unsigned req = process->getSyscallArg(tc, index); 570 571 DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", tgt_fd, req); 572 573 FDEntry *fde = process->getFDEntry(tgt_fd); 574 575 if (fde == NULL) { 576 // doesn't map to any simulator fd: not a valid target fd 577 return -EBADF; 578 } 579 580 if (fde->driver != NULL) { 581 return fde->driver->ioctl(process, tc, req); 582 } 583 584 if (OS::isTtyReq(req)) { 585 return -ENOTTY; 586 } 587 588 warn("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ \n", 589 tgt_fd, req, tc->pcState()); 590 return -ENOTTY; 591} 592 593template <class OS> 594static SyscallReturn 595openFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 596 ThreadContext *tc, int index) 597{ 598 std::string path; 599 600 if (!tc->getMemProxy().tryReadString(path, 601 process->getSyscallArg(tc, index))) 602 return -EFAULT; 603 604 int tgtFlags = process->getSyscallArg(tc, index); 605 int mode = process->getSyscallArg(tc, index); 606 int hostFlags = 0; 607 608 // translate open flags 609 for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) { 610 if (tgtFlags & OS::openFlagTable[i].tgtFlag) { 611 tgtFlags &= ~OS::openFlagTable[i].tgtFlag; 612 hostFlags |= OS::openFlagTable[i].hostFlag; 613 } 614 } 615 616 // any target flags left? 617 if (tgtFlags != 0) 618 warn("Syscall: open: cannot decode flags 0x%x", tgtFlags); 619 620#ifdef __CYGWIN32__ 621 hostFlags |= O_BINARY; 622#endif 623 624 // Adjust path for current working directory 625 path = process->fullPath(path); 626 627 DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str()); 628 629 if (startswith(path, "/dev/")) { 630 std::string filename = path.substr(strlen("/dev/")); 631 if (filename == "sysdev0") { 632 // This is a memory-mapped high-resolution timer device on Alpha. 633 // We don't support it, so just punt. 634 warn("Ignoring open(%s, ...)\n", path); 635 return -ENOENT; 636 } 637 638 EmulatedDriver *drv = process->findDriver(filename); 639 if (drv != NULL) { 640 // the driver's open method will allocate a fd from the 641 // process if necessary. 642 return drv->open(process, tc, mode, hostFlags); 643 } 644 645 // fall through here for pass through to host devices, such as 646 // /dev/zero 647 } 648 649 int fd; 650 int local_errno; 651 if (startswith(path, "/proc/") || startswith(path, "/system/") || 652 startswith(path, "/platform/") || startswith(path, "/sys/")) { 653 // It's a proc/sys entry and requires special handling 654 fd = OS::openSpecialFile(path, process, tc); 655 local_errno = ENOENT; 656 } else { 657 // open the file 658 fd = open(path.c_str(), hostFlags, mode); 659 local_errno = errno; 660 } 661 662 if (fd == -1) 663 return -local_errno; 664 665 return process->allocFD(fd, path.c_str(), hostFlags, mode, false); 666} 667 668/// Target open() handler. 669template <class OS> 670SyscallReturn 671openFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 672 ThreadContext *tc) 673{ 674 return openFunc<OS>(desc, callnum, process, tc, 0); 675} 676 677/// Target openat() handler. 678template <class OS> 679SyscallReturn 680openatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 681 ThreadContext *tc) 682{ 683 int index = 0; 684 int dirfd = process->getSyscallArg(tc, index); 685 if (dirfd != OS::TGT_AT_FDCWD) 686 warn("openat: first argument not AT_FDCWD; unlikely to work"); 687 return openFunc<OS>(desc, callnum, process, tc, 1); 688} 689 690/// Target unlinkat() handler. 691template <class OS> 692SyscallReturn 693unlinkatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 694 ThreadContext *tc) 695{ 696 int index = 0; 697 int dirfd = process->getSyscallArg(tc, index); 698 if (dirfd != OS::TGT_AT_FDCWD) 699 warn("unlinkat: first argument not AT_FDCWD; unlikely to work"); 700 701 return unlinkHelper(desc, callnum, process, tc, 1); 702} 703 704/// Target facessat() handler 705template <class OS> 706SyscallReturn 707faccessatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 708 ThreadContext *tc) 709{ 710 int index = 0; 711 int dirfd = process->getSyscallArg(tc, index); 712 if (dirfd != OS::TGT_AT_FDCWD) 713 warn("faccessat: first argument not AT_FDCWD; unlikely to work"); 714 return accessFunc(desc, callnum, process, tc, 1); 715} 716 717/// Target readlinkat() handler 718template <class OS> 719SyscallReturn 720readlinkatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 721 ThreadContext *tc) 722{ 723 int index = 0; 724 int dirfd = process->getSyscallArg(tc, index); 725 if (dirfd != OS::TGT_AT_FDCWD) 726 warn("openat: first argument not AT_FDCWD; unlikely to work"); 727 return readlinkFunc(desc, callnum, process, tc, 1); 728} 729 730/// Target renameat() handler. 731template <class OS> 732SyscallReturn 733renameatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 734 ThreadContext *tc) 735{ 736 int index = 0; 737 738 int olddirfd = process->getSyscallArg(tc, index); 739 if (olddirfd != OS::TGT_AT_FDCWD) 740 warn("renameat: first argument not AT_FDCWD; unlikely to work"); 741 742 std::string old_name; 743 744 if (!tc->getMemProxy().tryReadString(old_name, 745 process->getSyscallArg(tc, index))) 746 return -EFAULT; 747 748 int newdirfd = process->getSyscallArg(tc, index); 749 if (newdirfd != OS::TGT_AT_FDCWD) 750 warn("renameat: third argument not AT_FDCWD; unlikely to work"); 751 752 std::string new_name; 753 754 if (!tc->getMemProxy().tryReadString(new_name, 755 process->getSyscallArg(tc, index))) 756 return -EFAULT; 757 758 // Adjust path for current working directory 759 old_name = process->fullPath(old_name); 760 new_name = process->fullPath(new_name); 761 762 int result = rename(old_name.c_str(), new_name.c_str()); 763 return (result == -1) ? -errno : result; 764} 765 766/// Target sysinfo() handler. 767template <class OS> 768SyscallReturn 769sysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 770 ThreadContext *tc) 771{ 772 773 int index = 0; 774 TypedBufferArg<typename OS::tgt_sysinfo> 775 sysinfo(process->getSyscallArg(tc, index)); 776 777 sysinfo->uptime=seconds_since_epoch; 778 sysinfo->totalram=process->system->memSize(); 779 780 sysinfo.copyOut(tc->getMemProxy()); 781 782 return 0; 783} 784 785/// Target chmod() handler. 786template <class OS> 787SyscallReturn 788chmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 789 ThreadContext *tc) 790{ 791 std::string path; 792 793 int index = 0; 794 if (!tc->getMemProxy().tryReadString(path, 795 process->getSyscallArg(tc, index))) { 796 return -EFAULT; 797 } 798 799 uint32_t mode = process->getSyscallArg(tc, index); 800 mode_t hostMode = 0; 801 802 // XXX translate mode flags via OS::something??? 803 hostMode = mode; 804 805 // Adjust path for current working directory 806 path = process->fullPath(path); 807 808 // do the chmod 809 int result = chmod(path.c_str(), hostMode); 810 if (result < 0) 811 return -errno; 812 813 return 0; 814} 815 816 817/// Target fchmod() handler. 818template <class OS> 819SyscallReturn 820fchmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 821 ThreadContext *tc) 822{ 823 int index = 0; 824 int tgt_fd = process->getSyscallArg(tc, index); 825 uint32_t mode = process->getSyscallArg(tc, index); 826 827 int sim_fd = process->getSimFD(tgt_fd); 828 if (sim_fd < 0) 829 return -EBADF; 830 831 mode_t hostMode = 0; 832 833 // XXX translate mode flags via OS::someting??? 834 hostMode = mode; 835 836 // do the fchmod 837 int result = fchmod(sim_fd, hostMode); 838 if (result < 0) 839 return -errno; 840 841 return 0; 842} 843 844/// Target mremap() handler. 845template <class OS> 846SyscallReturn 847mremapFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) 848{ 849 int index = 0; 850 Addr start = process->getSyscallArg(tc, index); 851 uint64_t old_length = process->getSyscallArg(tc, index); 852 uint64_t new_length = process->getSyscallArg(tc, index); 853 uint64_t flags = process->getSyscallArg(tc, index); 854 uint64_t provided_address = 0; 855 bool use_provided_address = flags & OS::TGT_MREMAP_FIXED; 856 857 if (use_provided_address) 858 provided_address = process->getSyscallArg(tc, index); 859 860 if ((start % TheISA::PageBytes != 0) || 861 (provided_address % TheISA::PageBytes != 0)) { 862 warn("mremap failing: arguments not page aligned"); 863 return -EINVAL; 864 } 865 866 new_length = roundUp(new_length, TheISA::PageBytes); 867 868 if (new_length > old_length) { 869 if ((start + old_length) == process->mmap_end && 870 (!use_provided_address || provided_address == start)) { 871 uint64_t diff = new_length - old_length; 872 process->allocateMem(process->mmap_end, diff); 873 process->mmap_end += diff; 874 return start; 875 } else { 876 if (!use_provided_address && !(flags & OS::TGT_MREMAP_MAYMOVE)) { 877 warn("can't remap here and MREMAP_MAYMOVE flag not set\n"); 878 return -ENOMEM; 879 } else { 880 uint64_t new_start = use_provided_address ? 881 provided_address : process->mmap_end; 882 process->pTable->remap(start, old_length, new_start); 883 warn("mremapping to new vaddr %08p-%08p, adding %d\n", 884 new_start, new_start + new_length, 885 new_length - old_length); 886 // add on the remaining unallocated pages 887 process->allocateMem(new_start + old_length, 888 new_length - old_length, 889 use_provided_address /* clobber */); 890 if (!use_provided_address) 891 process->mmap_end += new_length; 892 if (use_provided_address && 893 new_start + new_length > process->mmap_end) { 894 // something fishy going on here, at least notify the user 895 // @todo: increase mmap_end? 896 warn("mmap region limit exceeded with MREMAP_FIXED\n"); 897 } 898 warn("returning %08p as start\n", new_start); 899 return new_start; 900 } 901 } 902 } else { 903 if (use_provided_address && provided_address != start) 904 process->pTable->remap(start, new_length, provided_address); 905 process->pTable->unmap(start + new_length, old_length - new_length); 906 return use_provided_address ? provided_address : start; 907 } 908} 909 910/// Target stat() handler. 911template <class OS> 912SyscallReturn 913statFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 914 ThreadContext *tc) 915{ 916 std::string path; 917 918 int index = 0; 919 if (!tc->getMemProxy().tryReadString(path, 920 process->getSyscallArg(tc, index))) { 921 return -EFAULT; 922 } 923 Addr bufPtr = process->getSyscallArg(tc, index); 924 925 // Adjust path for current working directory 926 path = process->fullPath(path); 927 928 struct stat hostBuf; 929 int result = stat(path.c_str(), &hostBuf); 930 931 if (result < 0) 932 return -errno; 933 934 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 935 936 return 0; 937} 938 939 940/// Target stat64() handler. 941template <class OS> 942SyscallReturn 943stat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 944 ThreadContext *tc) 945{ 946 std::string path; 947 948 int index = 0; 949 if (!tc->getMemProxy().tryReadString(path, 950 process->getSyscallArg(tc, index))) 951 return -EFAULT; 952 Addr bufPtr = process->getSyscallArg(tc, index); 953 954 // Adjust path for current working directory 955 path = process->fullPath(path); 956 957#if NO_STAT64 958 struct stat hostBuf; 959 int result = stat(path.c_str(), &hostBuf); 960#else 961 struct stat64 hostBuf; 962 int result = stat64(path.c_str(), &hostBuf); 963#endif 964 965 if (result < 0) 966 return -errno; 967 968 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 969 970 return 0; 971} 972 973 974/// Target fstatat64() handler. 975template <class OS> 976SyscallReturn 977fstatat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 978 ThreadContext *tc) 979{ 980 int index = 0; 981 int dirfd = process->getSyscallArg(tc, index); 982 if (dirfd != OS::TGT_AT_FDCWD) 983 warn("fstatat64: first argument not AT_FDCWD; unlikely to work"); 984 985 std::string path; 986 if (!tc->getMemProxy().tryReadString(path, 987 process->getSyscallArg(tc, index))) 988 return -EFAULT; 989 Addr bufPtr = process->getSyscallArg(tc, index); 990 991 // Adjust path for current working directory 992 path = process->fullPath(path); 993 994#if NO_STAT64 995 struct stat hostBuf; 996 int result = stat(path.c_str(), &hostBuf); 997#else 998 struct stat64 hostBuf; 999 int result = stat64(path.c_str(), &hostBuf); 1000#endif 1001 1002 if (result < 0) 1003 return -errno; 1004 1005 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1006 1007 return 0; 1008} 1009 1010 1011/// Target fstat64() handler. 1012template <class OS> 1013SyscallReturn 1014fstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 1015 ThreadContext *tc) 1016{ 1017 int index = 0; 1018 int tgt_fd = process->getSyscallArg(tc, index); 1019 Addr bufPtr = process->getSyscallArg(tc, index); 1020 1021 int sim_fd = process->getSimFD(tgt_fd); 1022 if (sim_fd < 0) 1023 return -EBADF; 1024 1025#if NO_STAT64 1026 struct stat hostBuf; 1027 int result = fstat(sim_fd, &hostBuf); 1028#else 1029 struct stat64 hostBuf; 1030 int result = fstat64(sim_fd, &hostBuf); 1031#endif 1032 1033 if (result < 0) 1034 return -errno; 1035 1036 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (sim_fd == 1)); 1037 1038 return 0; 1039} 1040 1041 1042/// Target lstat() handler. 1043template <class OS> 1044SyscallReturn 1045lstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1046 ThreadContext *tc) 1047{ 1048 std::string path; 1049 1050 int index = 0; 1051 if (!tc->getMemProxy().tryReadString(path, 1052 process->getSyscallArg(tc, index))) { 1053 return -EFAULT; 1054 } 1055 Addr bufPtr = process->getSyscallArg(tc, index); 1056 1057 // Adjust path for current working directory 1058 path = process->fullPath(path); 1059 1060 struct stat hostBuf; 1061 int result = lstat(path.c_str(), &hostBuf); 1062 1063 if (result < 0) 1064 return -errno; 1065 1066 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1067 1068 return 0; 1069} 1070 1071/// Target lstat64() handler. 1072template <class OS> 1073SyscallReturn 1074lstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 1075 ThreadContext *tc) 1076{ 1077 std::string path; 1078 1079 int index = 0; 1080 if (!tc->getMemProxy().tryReadString(path, 1081 process->getSyscallArg(tc, index))) { 1082 return -EFAULT; 1083 } 1084 Addr bufPtr = process->getSyscallArg(tc, index); 1085 1086 // Adjust path for current working directory 1087 path = process->fullPath(path); 1088 1089#if NO_STAT64 1090 struct stat hostBuf; 1091 int result = lstat(path.c_str(), &hostBuf); 1092#else 1093 struct stat64 hostBuf; 1094 int result = lstat64(path.c_str(), &hostBuf); 1095#endif 1096 1097 if (result < 0) 1098 return -errno; 1099 1100 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1101 1102 return 0; 1103} 1104 1105/// Target fstat() handler. 1106template <class OS> 1107SyscallReturn 1108fstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1109 ThreadContext *tc) 1110{ 1111 int index = 0; 1112 int tgt_fd = process->getSyscallArg(tc, index); 1113 Addr bufPtr = process->getSyscallArg(tc, index); 1114 1115 DPRINTF_SYSCALL(Verbose, "fstat(%d, ...)\n", tgt_fd); 1116 1117 int sim_fd = process->getSimFD(tgt_fd); 1118 if (sim_fd < 0) 1119 return -EBADF; 1120 1121 struct stat hostBuf; 1122 int result = fstat(sim_fd, &hostBuf); 1123 1124 if (result < 0) 1125 return -errno; 1126 1127 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (sim_fd == 1)); 1128 1129 return 0; 1130} 1131 1132 1133/// Target statfs() handler. 1134template <class OS> 1135SyscallReturn 1136statfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1137 ThreadContext *tc) 1138{ 1139 std::string path; 1140 1141 int index = 0; 1142 if (!tc->getMemProxy().tryReadString(path, 1143 process->getSyscallArg(tc, index))) { 1144 return -EFAULT; 1145 } 1146 Addr bufPtr = process->getSyscallArg(tc, index); 1147 1148 // Adjust path for current working directory 1149 path = process->fullPath(path); 1150 1151 struct statfs hostBuf; 1152 int result = statfs(path.c_str(), &hostBuf); 1153 1154 if (result < 0) 1155 return -errno; 1156 1157 OS::copyOutStatfsBuf(tc->getMemProxy(), bufPtr, &hostBuf); 1158 1159 return 0; 1160} 1161 1162 1163/// Target fstatfs() handler. 1164template <class OS> 1165SyscallReturn 1166fstatfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1167 ThreadContext *tc) 1168{ 1169 int index = 0; 1170 int tgt_fd = process->getSyscallArg(tc, index); 1171 Addr bufPtr = process->getSyscallArg(tc, index); 1172 1173 int sim_fd = process->getSimFD(tgt_fd); 1174 if (sim_fd < 0) 1175 return -EBADF; 1176 1177 struct statfs hostBuf; 1178 int result = fstatfs(sim_fd, &hostBuf); 1179 1180 if (result < 0) 1181 return -errno; 1182 1183 OS::copyOutStatfsBuf(tc->getMemProxy(), bufPtr, &hostBuf); 1184 1185 return 0; 1186} 1187 1188 1189/// Target writev() handler. 1190template <class OS> 1191SyscallReturn 1192writevFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1193 ThreadContext *tc) 1194{ 1195 int index = 0; 1196 int tgt_fd = process->getSyscallArg(tc, index); 1197 1198 int sim_fd = process->getSimFD(tgt_fd); 1199 if (sim_fd < 0) 1200 return -EBADF; 1201 1202 SETranslatingPortProxy &p = tc->getMemProxy(); 1203 uint64_t tiov_base = process->getSyscallArg(tc, index); 1204 size_t count = process->getSyscallArg(tc, index); 1205 struct iovec hiov[count]; 1206 for (size_t i = 0; i < count; ++i) { 1207 typename OS::tgt_iovec tiov; 1208 1209 p.readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec), 1210 (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec)); 1211 hiov[i].iov_len = TheISA::gtoh(tiov.iov_len); 1212 hiov[i].iov_base = new char [hiov[i].iov_len]; 1213 p.readBlob(TheISA::gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base, 1214 hiov[i].iov_len); 1215 } 1216 1217 int result = writev(sim_fd, hiov, count); 1218 1219 for (size_t i = 0; i < count; ++i) 1220 delete [] (char *)hiov[i].iov_base; 1221 1222 if (result < 0) 1223 return -errno; 1224 1225 return result; 1226} 1227 1228/// Real mmap handler. 1229template <class OS> 1230SyscallReturn 1231mmapImpl(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc, 1232 bool is_mmap2) 1233{ 1234 int index = 0; 1235 Addr start = p->getSyscallArg(tc, index); 1236 uint64_t length = p->getSyscallArg(tc, index); 1237 int prot = p->getSyscallArg(tc, index); 1238 int tgt_flags = p->getSyscallArg(tc, index); 1239 int tgt_fd = p->getSyscallArg(tc, index); 1240 int offset = p->getSyscallArg(tc, index); 1241 1242 if (is_mmap2) 1243 offset *= TheISA::PageBytes; 1244 1245 if (start & (TheISA::PageBytes - 1) || 1246 offset & (TheISA::PageBytes - 1) || 1247 (tgt_flags & OS::TGT_MAP_PRIVATE && 1248 tgt_flags & OS::TGT_MAP_SHARED) || 1249 (!(tgt_flags & OS::TGT_MAP_PRIVATE) && 1250 !(tgt_flags & OS::TGT_MAP_SHARED)) || 1251 !length) { 1252 return -EINVAL; 1253 } 1254 1255 if ((prot & PROT_WRITE) && (tgt_flags & OS::TGT_MAP_SHARED)) { 1256 // With shared mmaps, there are two cases to consider: 1257 // 1) anonymous: writes should modify the mapping and this should be 1258 // visible to observers who share the mapping. Currently, it's 1259 // difficult to update the shared mapping because there's no 1260 // structure which maintains information about the which virtual 1261 // memory areas are shared. If that structure existed, it would be 1262 // possible to make the translations point to the same frames. 1263 // 2) file-backed: writes should modify the mapping and the file 1264 // which is backed by the mapping. The shared mapping problem is the 1265 // same as what was mentioned about the anonymous mappings. For 1266 // file-backed mappings, the writes to the file are difficult 1267 // because it requires syncing what the mapping holds with the file 1268 // that resides on the host system. So, any write on a real system 1269 // would cause the change to be propagated to the file mapping at 1270 // some point in the future (the inode is tracked along with the 1271 // mapping). This isn't guaranteed to always happen, but it usually 1272 // works well enough. The guarantee is provided by the msync system 1273 // call. We could force the change through with shared mappings with 1274 // a call to msync, but that again would require more information 1275 // than we currently maintain. 1276 warn("mmap: writing to shared mmap region is currently " 1277 "unsupported. The write succeeds on the target, but it " 1278 "will not be propagated to the host or shared mappings"); 1279 } 1280 1281 length = roundUp(length, TheISA::PageBytes); 1282 1283 int sim_fd = -1; 1284 uint8_t *pmap = nullptr; 1285 if (!(tgt_flags & OS::TGT_MAP_ANONYMOUS)) { 1286 sim_fd = p->getSimFD(tgt_fd); 1287 if (sim_fd < 0) 1288 return -EBADF; 1289 1290 pmap = (decltype(pmap))mmap(NULL, length, PROT_READ, MAP_PRIVATE, 1291 sim_fd, offset); 1292 1293 if (pmap == (decltype(pmap))-1) { 1294 warn("mmap: failed to map file into host address space"); 1295 return -errno; 1296 } 1297 } 1298 1299 // Extend global mmap region if necessary. Note that we ignore the 1300 // start address unless MAP_FIXED is specified. 1301 if (!(tgt_flags & OS::TGT_MAP_FIXED)) { 1302 start = p->mmapGrowsDown() ? p->mmap_end - length : p->mmap_end; 1303 p->mmap_end = p->mmapGrowsDown() ? start : p->mmap_end + length; 1304 } 1305 1306 DPRINTF_SYSCALL(Verbose, " mmap range is 0x%x - 0x%x\n", 1307 start, start + length - 1); 1308 1309 // We only allow mappings to overwrite existing mappings if 1310 // TGT_MAP_FIXED is set. Otherwise it shouldn't be a problem 1311 // because we ignore the start hint if TGT_MAP_FIXED is not set. 1312 int clobber = tgt_flags & OS::TGT_MAP_FIXED; 1313 if (clobber) { 1314 for (auto tc : p->system->threadContexts) { 1315 // If we might be overwriting old mappings, we need to 1316 // invalidate potentially stale mappings out of the TLBs. 1317 tc->getDTBPtr()->flushAll(); 1318 tc->getITBPtr()->flushAll(); 1319 } 1320 } 1321 1322 // Allocate physical memory and map it in. If the page table is already 1323 // mapped and clobber is not set, the simulator will issue throw a 1324 // fatal and bail out of the simulation. 1325 p->allocateMem(start, length, clobber); 1326 1327 // Transfer content into target address space. 1328 SETranslatingPortProxy &tp = tc->getMemProxy(); 1329 if (tgt_flags & OS::TGT_MAP_ANONYMOUS) { 1330 // In general, we should zero the mapped area for anonymous mappings, 1331 // with something like: 1332 // tp.memsetBlob(start, 0, length); 1333 // However, given that we don't support sparse mappings, and 1334 // some applications can map a couple of gigabytes of space 1335 // (intending sparse usage), that can get painfully expensive. 1336 // Fortunately, since we don't properly implement munmap either, 1337 // there's no danger of remapping used memory, so for now all 1338 // newly mapped memory should already be zeroed so we can skip it. 1339 } else { 1340 // It is possible to mmap an area larger than a file, however 1341 // accessing unmapped portions the system triggers a "Bus error" 1342 // on the host. We must know when to stop copying the file from 1343 // the host into the target address space. 1344 struct stat file_stat; 1345 if (fstat(sim_fd, &file_stat) > 0) 1346 fatal("mmap: cannot stat file"); 1347 1348 // Copy the portion of the file that is resident. This requires 1349 // checking both the mmap size and the filesize that we are 1350 // trying to mmap into this space; the mmap size also depends 1351 // on the specified offset into the file. 1352 uint64_t size = std::min((uint64_t)file_stat.st_size - offset, 1353 length); 1354 tp.writeBlob(start, pmap, size); 1355 1356 // Cleanup the mmap region before exiting this function. 1357 munmap(pmap, length); 1358 1359 // Maintain the symbol table for dynamic executables. 1360 // The loader will call mmap to map the images into its address 1361 // space and we intercept that here. We can verify that we are 1362 // executing inside the loader by checking the program counter value. 1363 // XXX: with multiprogrammed workloads or multi-node configurations, 1364 // this will not work since there is a single global symbol table. 1365 ObjectFile *interpreter = p->getInterpreter(); 1366 if (interpreter) { 1367 Addr text_start = interpreter->textBase(); 1368 Addr text_end = text_start + interpreter->textSize(); 1369 1370 Addr pc = tc->pcState().pc(); 1371 1372 if (pc >= text_start && pc < text_end) { 1373 FDEntry *fde = p->getFDEntry(tgt_fd); 1374 1375 ObjectFile *lib = createObjectFile(fde->filename); 1376 1377 if (lib) { 1378 lib->loadAllSymbols(debugSymbolTable, 1379 lib->textBase(), start); 1380 } 1381 } 1382 } 1383 1384 // Note that we do not zero out the remainder of the mapping. This 1385 // is done by a real system, but it probably will not affect 1386 // execution (hopefully). 1387 } 1388 1389 return start; 1390} 1391 1392/// Target mmap() handler. 1393template <class OS> 1394SyscallReturn 1395mmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 1396{ 1397 return mmapImpl<OS>(desc, num, p, tc, false); 1398} 1399 1400/// Target mmap2() handler. 1401template <class OS> 1402SyscallReturn 1403mmap2Func(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 1404{ 1405 return mmapImpl<OS>(desc, num, p, tc, true); 1406} 1407 1408/// Target getrlimit() handler. 1409template <class OS> 1410SyscallReturn 1411getrlimitFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1412 ThreadContext *tc) 1413{ 1414 int index = 0; 1415 unsigned resource = process->getSyscallArg(tc, index); 1416 TypedBufferArg<typename OS::rlimit> rlp(process->getSyscallArg(tc, index)); 1417 1418 switch (resource) { 1419 case OS::TGT_RLIMIT_STACK: 1420 // max stack size in bytes: make up a number (8MB for now) 1421 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; 1422 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1423 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1424 break; 1425 1426 case OS::TGT_RLIMIT_DATA: 1427 // max data segment size in bytes: make up a number 1428 rlp->rlim_cur = rlp->rlim_max = 256 * 1024 * 1024; 1429 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1430 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1431 break; 1432 1433 default: 1434 warn("getrlimit: unimplemented resource %d", resource); 1435 return -EINVAL; 1436 break; 1437 } 1438 1439 rlp.copyOut(tc->getMemProxy()); 1440 return 0; 1441} 1442 1443/// Target clock_gettime() function. 1444template <class OS> 1445SyscallReturn 1446clock_gettimeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 1447{ 1448 int index = 1; 1449 //int clk_id = p->getSyscallArg(tc, index); 1450 TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index)); 1451 1452 getElapsedTimeNano(tp->tv_sec, tp->tv_nsec); 1453 tp->tv_sec += seconds_since_epoch; 1454 tp->tv_sec = TheISA::htog(tp->tv_sec); 1455 tp->tv_nsec = TheISA::htog(tp->tv_nsec); 1456 1457 tp.copyOut(tc->getMemProxy()); 1458 1459 return 0; 1460} 1461 1462/// Target clock_getres() function. 1463template <class OS> 1464SyscallReturn 1465clock_getresFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 1466{ 1467 int index = 1; 1468 TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index)); 1469 1470 // Set resolution at ns, which is what clock_gettime() returns 1471 tp->tv_sec = 0; 1472 tp->tv_nsec = 1; 1473 1474 tp.copyOut(tc->getMemProxy()); 1475 1476 return 0; 1477} 1478 1479/// Target gettimeofday() handler. 1480template <class OS> 1481SyscallReturn 1482gettimeofdayFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1483 ThreadContext *tc) 1484{ 1485 int index = 0; 1486 TypedBufferArg<typename OS::timeval> tp(process->getSyscallArg(tc, index)); 1487 1488 getElapsedTimeMicro(tp->tv_sec, tp->tv_usec); 1489 tp->tv_sec += seconds_since_epoch; 1490 tp->tv_sec = TheISA::htog(tp->tv_sec); 1491 tp->tv_usec = TheISA::htog(tp->tv_usec); 1492 1493 tp.copyOut(tc->getMemProxy()); 1494 1495 return 0; 1496} 1497 1498 1499/// Target utimes() handler. 1500template <class OS> 1501SyscallReturn 1502utimesFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1503 ThreadContext *tc) 1504{ 1505 std::string path; 1506 1507 int index = 0; 1508 if (!tc->getMemProxy().tryReadString(path, 1509 process->getSyscallArg(tc, index))) { 1510 return -EFAULT; 1511 } 1512 1513 TypedBufferArg<typename OS::timeval [2]> 1514 tp(process->getSyscallArg(tc, index)); 1515 tp.copyIn(tc->getMemProxy()); 1516 1517 struct timeval hostTimeval[2]; 1518 for (int i = 0; i < 2; ++i) 1519 { 1520 hostTimeval[i].tv_sec = TheISA::gtoh((*tp)[i].tv_sec); 1521 hostTimeval[i].tv_usec = TheISA::gtoh((*tp)[i].tv_usec); 1522 } 1523 1524 // Adjust path for current working directory 1525 path = process->fullPath(path); 1526 1527 int result = utimes(path.c_str(), hostTimeval); 1528 1529 if (result < 0) 1530 return -errno; 1531 1532 return 0; 1533} 1534/// Target getrusage() function. 1535template <class OS> 1536SyscallReturn 1537getrusageFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1538 ThreadContext *tc) 1539{ 1540 int index = 0; 1541 int who = process->getSyscallArg(tc, index); // THREAD, SELF, or CHILDREN 1542 TypedBufferArg<typename OS::rusage> rup(process->getSyscallArg(tc, index)); 1543 1544 rup->ru_utime.tv_sec = 0; 1545 rup->ru_utime.tv_usec = 0; 1546 rup->ru_stime.tv_sec = 0; 1547 rup->ru_stime.tv_usec = 0; 1548 rup->ru_maxrss = 0; 1549 rup->ru_ixrss = 0; 1550 rup->ru_idrss = 0; 1551 rup->ru_isrss = 0; 1552 rup->ru_minflt = 0; 1553 rup->ru_majflt = 0; 1554 rup->ru_nswap = 0; 1555 rup->ru_inblock = 0; 1556 rup->ru_oublock = 0; 1557 rup->ru_msgsnd = 0; 1558 rup->ru_msgrcv = 0; 1559 rup->ru_nsignals = 0; 1560 rup->ru_nvcsw = 0; 1561 rup->ru_nivcsw = 0; 1562 1563 switch (who) { 1564 case OS::TGT_RUSAGE_SELF: 1565 getElapsedTimeMicro(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec); 1566 rup->ru_utime.tv_sec = TheISA::htog(rup->ru_utime.tv_sec); 1567 rup->ru_utime.tv_usec = TheISA::htog(rup->ru_utime.tv_usec); 1568 break; 1569 1570 case OS::TGT_RUSAGE_CHILDREN: 1571 // do nothing. We have no child processes, so they take no time. 1572 break; 1573 1574 default: 1575 // don't really handle THREAD or CHILDREN, but just warn and 1576 // plow ahead 1577 warn("getrusage() only supports RUSAGE_SELF. Parameter %d ignored.", 1578 who); 1579 } 1580 1581 rup.copyOut(tc->getMemProxy()); 1582 1583 return 0; 1584} 1585 1586/// Target times() function. 1587template <class OS> 1588SyscallReturn 1589timesFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1590 ThreadContext *tc) 1591{ 1592 int index = 0; 1593 TypedBufferArg<typename OS::tms> bufp(process->getSyscallArg(tc, index)); 1594 1595 // Fill in the time structure (in clocks) 1596 int64_t clocks = curTick() * OS::M5_SC_CLK_TCK / SimClock::Int::s; 1597 bufp->tms_utime = clocks; 1598 bufp->tms_stime = 0; 1599 bufp->tms_cutime = 0; 1600 bufp->tms_cstime = 0; 1601 1602 // Convert to host endianness 1603 bufp->tms_utime = TheISA::htog(bufp->tms_utime); 1604 1605 // Write back 1606 bufp.copyOut(tc->getMemProxy()); 1607 1608 // Return clock ticks since system boot 1609 return clocks; 1610} 1611 1612/// Target time() function. 1613template <class OS> 1614SyscallReturn 1615timeFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1616 ThreadContext *tc) 1617{ 1618 typename OS::time_t sec, usec; 1619 getElapsedTimeMicro(sec, usec); 1620 sec += seconds_since_epoch; 1621 1622 int index = 0; 1623 Addr taddr = (Addr)process->getSyscallArg(tc, index); 1624 if (taddr != 0) { 1625 typename OS::time_t t = sec; 1626 t = TheISA::htog(t); 1627 SETranslatingPortProxy &p = tc->getMemProxy(); 1628 p.writeBlob(taddr, (uint8_t*)&t, (int)sizeof(typename OS::time_t)); 1629 } 1630 return sec; 1631} 1632 1633 1634#endif // __SIM_SYSCALL_EMUL_HH__ 1635