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