syscall_emul.hh revision 11594
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 781 sysinfo.copyOut(tc->getMemProxy()); 782 783 return 0; 784} 785 786/// Target chmod() handler. 787template <class OS> 788SyscallReturn 789chmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 790 ThreadContext *tc) 791{ 792 std::string path; 793 794 int index = 0; 795 if (!tc->getMemProxy().tryReadString(path, 796 process->getSyscallArg(tc, index))) { 797 return -EFAULT; 798 } 799 800 uint32_t mode = process->getSyscallArg(tc, index); 801 mode_t hostMode = 0; 802 803 // XXX translate mode flags via OS::something??? 804 hostMode = mode; 805 806 // Adjust path for current working directory 807 path = process->fullPath(path); 808 809 // do the chmod 810 int result = chmod(path.c_str(), hostMode); 811 if (result < 0) 812 return -errno; 813 814 return 0; 815} 816 817 818/// Target fchmod() handler. 819template <class OS> 820SyscallReturn 821fchmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 822 ThreadContext *tc) 823{ 824 int index = 0; 825 int tgt_fd = process->getSyscallArg(tc, index); 826 uint32_t mode = process->getSyscallArg(tc, index); 827 828 int sim_fd = process->getSimFD(tgt_fd); 829 if (sim_fd < 0) 830 return -EBADF; 831 832 mode_t hostMode = 0; 833 834 // XXX translate mode flags via OS::someting??? 835 hostMode = mode; 836 837 // do the fchmod 838 int result = fchmod(sim_fd, hostMode); 839 if (result < 0) 840 return -errno; 841 842 return 0; 843} 844 845/// Target mremap() handler. 846template <class OS> 847SyscallReturn 848mremapFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) 849{ 850 int index = 0; 851 Addr start = process->getSyscallArg(tc, index); 852 uint64_t old_length = process->getSyscallArg(tc, index); 853 uint64_t new_length = process->getSyscallArg(tc, index); 854 uint64_t flags = process->getSyscallArg(tc, index); 855 uint64_t provided_address = 0; 856 bool use_provided_address = flags & OS::TGT_MREMAP_FIXED; 857 858 if (use_provided_address) 859 provided_address = process->getSyscallArg(tc, index); 860 861 if ((start % TheISA::PageBytes != 0) || 862 (provided_address % TheISA::PageBytes != 0)) { 863 warn("mremap failing: arguments not page aligned"); 864 return -EINVAL; 865 } 866 867 new_length = roundUp(new_length, TheISA::PageBytes); 868 869 if (new_length > old_length) { 870 if ((start + old_length) == process->mmap_end && 871 (!use_provided_address || provided_address == start)) { 872 uint64_t diff = new_length - old_length; 873 process->allocateMem(process->mmap_end, diff); 874 process->mmap_end += diff; 875 return start; 876 } else { 877 if (!use_provided_address && !(flags & OS::TGT_MREMAP_MAYMOVE)) { 878 warn("can't remap here and MREMAP_MAYMOVE flag not set\n"); 879 return -ENOMEM; 880 } else { 881 uint64_t new_start = use_provided_address ? 882 provided_address : process->mmap_end; 883 process->pTable->remap(start, old_length, new_start); 884 warn("mremapping to new vaddr %08p-%08p, adding %d\n", 885 new_start, new_start + new_length, 886 new_length - old_length); 887 // add on the remaining unallocated pages 888 process->allocateMem(new_start + old_length, 889 new_length - old_length, 890 use_provided_address /* clobber */); 891 if (!use_provided_address) 892 process->mmap_end += new_length; 893 if (use_provided_address && 894 new_start + new_length > process->mmap_end) { 895 // something fishy going on here, at least notify the user 896 // @todo: increase mmap_end? 897 warn("mmap region limit exceeded with MREMAP_FIXED\n"); 898 } 899 warn("returning %08p as start\n", new_start); 900 return new_start; 901 } 902 } 903 } else { 904 if (use_provided_address && provided_address != start) 905 process->pTable->remap(start, new_length, provided_address); 906 process->pTable->unmap(start + new_length, old_length - new_length); 907 return use_provided_address ? provided_address : start; 908 } 909} 910 911/// Target stat() handler. 912template <class OS> 913SyscallReturn 914statFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 915 ThreadContext *tc) 916{ 917 std::string path; 918 919 int index = 0; 920 if (!tc->getMemProxy().tryReadString(path, 921 process->getSyscallArg(tc, index))) { 922 return -EFAULT; 923 } 924 Addr bufPtr = process->getSyscallArg(tc, index); 925 926 // Adjust path for current working directory 927 path = process->fullPath(path); 928 929 struct stat hostBuf; 930 int result = stat(path.c_str(), &hostBuf); 931 932 if (result < 0) 933 return -errno; 934 935 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 936 937 return 0; 938} 939 940 941/// Target stat64() handler. 942template <class OS> 943SyscallReturn 944stat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 945 ThreadContext *tc) 946{ 947 std::string path; 948 949 int index = 0; 950 if (!tc->getMemProxy().tryReadString(path, 951 process->getSyscallArg(tc, index))) 952 return -EFAULT; 953 Addr bufPtr = process->getSyscallArg(tc, index); 954 955 // Adjust path for current working directory 956 path = process->fullPath(path); 957 958#if NO_STAT64 959 struct stat hostBuf; 960 int result = stat(path.c_str(), &hostBuf); 961#else 962 struct stat64 hostBuf; 963 int result = stat64(path.c_str(), &hostBuf); 964#endif 965 966 if (result < 0) 967 return -errno; 968 969 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 970 971 return 0; 972} 973 974 975/// Target fstatat64() handler. 976template <class OS> 977SyscallReturn 978fstatat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 979 ThreadContext *tc) 980{ 981 int index = 0; 982 int dirfd = process->getSyscallArg(tc, index); 983 if (dirfd != OS::TGT_AT_FDCWD) 984 warn("fstatat64: first argument not AT_FDCWD; unlikely to work"); 985 986 std::string path; 987 if (!tc->getMemProxy().tryReadString(path, 988 process->getSyscallArg(tc, index))) 989 return -EFAULT; 990 Addr bufPtr = process->getSyscallArg(tc, index); 991 992 // Adjust path for current working directory 993 path = process->fullPath(path); 994 995#if NO_STAT64 996 struct stat hostBuf; 997 int result = stat(path.c_str(), &hostBuf); 998#else 999 struct stat64 hostBuf; 1000 int result = stat64(path.c_str(), &hostBuf); 1001#endif 1002 1003 if (result < 0) 1004 return -errno; 1005 1006 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1007 1008 return 0; 1009} 1010 1011 1012/// Target fstat64() handler. 1013template <class OS> 1014SyscallReturn 1015fstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 1016 ThreadContext *tc) 1017{ 1018 int index = 0; 1019 int tgt_fd = process->getSyscallArg(tc, index); 1020 Addr bufPtr = process->getSyscallArg(tc, index); 1021 1022 int sim_fd = process->getSimFD(tgt_fd); 1023 if (sim_fd < 0) 1024 return -EBADF; 1025 1026#if NO_STAT64 1027 struct stat hostBuf; 1028 int result = fstat(sim_fd, &hostBuf); 1029#else 1030 struct stat64 hostBuf; 1031 int result = fstat64(sim_fd, &hostBuf); 1032#endif 1033 1034 if (result < 0) 1035 return -errno; 1036 1037 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (sim_fd == 1)); 1038 1039 return 0; 1040} 1041 1042 1043/// Target lstat() handler. 1044template <class OS> 1045SyscallReturn 1046lstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1047 ThreadContext *tc) 1048{ 1049 std::string path; 1050 1051 int index = 0; 1052 if (!tc->getMemProxy().tryReadString(path, 1053 process->getSyscallArg(tc, index))) { 1054 return -EFAULT; 1055 } 1056 Addr bufPtr = process->getSyscallArg(tc, index); 1057 1058 // Adjust path for current working directory 1059 path = process->fullPath(path); 1060 1061 struct stat hostBuf; 1062 int result = lstat(path.c_str(), &hostBuf); 1063 1064 if (result < 0) 1065 return -errno; 1066 1067 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1068 1069 return 0; 1070} 1071 1072/// Target lstat64() handler. 1073template <class OS> 1074SyscallReturn 1075lstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 1076 ThreadContext *tc) 1077{ 1078 std::string path; 1079 1080 int index = 0; 1081 if (!tc->getMemProxy().tryReadString(path, 1082 process->getSyscallArg(tc, index))) { 1083 return -EFAULT; 1084 } 1085 Addr bufPtr = process->getSyscallArg(tc, index); 1086 1087 // Adjust path for current working directory 1088 path = process->fullPath(path); 1089 1090#if NO_STAT64 1091 struct stat hostBuf; 1092 int result = lstat(path.c_str(), &hostBuf); 1093#else 1094 struct stat64 hostBuf; 1095 int result = lstat64(path.c_str(), &hostBuf); 1096#endif 1097 1098 if (result < 0) 1099 return -errno; 1100 1101 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1102 1103 return 0; 1104} 1105 1106/// Target fstat() handler. 1107template <class OS> 1108SyscallReturn 1109fstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1110 ThreadContext *tc) 1111{ 1112 int index = 0; 1113 int tgt_fd = process->getSyscallArg(tc, index); 1114 Addr bufPtr = process->getSyscallArg(tc, index); 1115 1116 DPRINTF_SYSCALL(Verbose, "fstat(%d, ...)\n", tgt_fd); 1117 1118 int sim_fd = process->getSimFD(tgt_fd); 1119 if (sim_fd < 0) 1120 return -EBADF; 1121 1122 struct stat hostBuf; 1123 int result = fstat(sim_fd, &hostBuf); 1124 1125 if (result < 0) 1126 return -errno; 1127 1128 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (sim_fd == 1)); 1129 1130 return 0; 1131} 1132 1133 1134/// Target statfs() handler. 1135template <class OS> 1136SyscallReturn 1137statfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1138 ThreadContext *tc) 1139{ 1140 std::string path; 1141 1142 int index = 0; 1143 if (!tc->getMemProxy().tryReadString(path, 1144 process->getSyscallArg(tc, index))) { 1145 return -EFAULT; 1146 } 1147 Addr bufPtr = process->getSyscallArg(tc, index); 1148 1149 // Adjust path for current working directory 1150 path = process->fullPath(path); 1151 1152 struct statfs hostBuf; 1153 int result = statfs(path.c_str(), &hostBuf); 1154 1155 if (result < 0) 1156 return -errno; 1157 1158 OS::copyOutStatfsBuf(tc->getMemProxy(), bufPtr, &hostBuf); 1159 1160 return 0; 1161} 1162 1163 1164/// Target fstatfs() handler. 1165template <class OS> 1166SyscallReturn 1167fstatfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1168 ThreadContext *tc) 1169{ 1170 int index = 0; 1171 int tgt_fd = process->getSyscallArg(tc, index); 1172 Addr bufPtr = process->getSyscallArg(tc, index); 1173 1174 int sim_fd = process->getSimFD(tgt_fd); 1175 if (sim_fd < 0) 1176 return -EBADF; 1177 1178 struct statfs hostBuf; 1179 int result = fstatfs(sim_fd, &hostBuf); 1180 1181 if (result < 0) 1182 return -errno; 1183 1184 OS::copyOutStatfsBuf(tc->getMemProxy(), bufPtr, &hostBuf); 1185 1186 return 0; 1187} 1188 1189 1190/// Target writev() handler. 1191template <class OS> 1192SyscallReturn 1193writevFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1194 ThreadContext *tc) 1195{ 1196 int index = 0; 1197 int tgt_fd = process->getSyscallArg(tc, index); 1198 1199 int sim_fd = process->getSimFD(tgt_fd); 1200 if (sim_fd < 0) 1201 return -EBADF; 1202 1203 SETranslatingPortProxy &p = tc->getMemProxy(); 1204 uint64_t tiov_base = process->getSyscallArg(tc, index); 1205 size_t count = process->getSyscallArg(tc, index); 1206 struct iovec hiov[count]; 1207 for (size_t i = 0; i < count; ++i) { 1208 typename OS::tgt_iovec tiov; 1209 1210 p.readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec), 1211 (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec)); 1212 hiov[i].iov_len = TheISA::gtoh(tiov.iov_len); 1213 hiov[i].iov_base = new char [hiov[i].iov_len]; 1214 p.readBlob(TheISA::gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base, 1215 hiov[i].iov_len); 1216 } 1217 1218 int result = writev(sim_fd, hiov, count); 1219 1220 for (size_t i = 0; i < count; ++i) 1221 delete [] (char *)hiov[i].iov_base; 1222 1223 if (result < 0) 1224 return -errno; 1225 1226 return result; 1227} 1228 1229/// Real mmap handler. 1230template <class OS> 1231SyscallReturn 1232mmapImpl(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc, 1233 bool is_mmap2) 1234{ 1235 int index = 0; 1236 Addr start = p->getSyscallArg(tc, index); 1237 uint64_t length = p->getSyscallArg(tc, index); 1238 int prot = p->getSyscallArg(tc, index); 1239 int tgt_flags = p->getSyscallArg(tc, index); 1240 int tgt_fd = p->getSyscallArg(tc, index); 1241 int offset = p->getSyscallArg(tc, index); 1242 1243 if (is_mmap2) 1244 offset *= TheISA::PageBytes; 1245 1246 if (start & (TheISA::PageBytes - 1) || 1247 offset & (TheISA::PageBytes - 1) || 1248 (tgt_flags & OS::TGT_MAP_PRIVATE && 1249 tgt_flags & OS::TGT_MAP_SHARED) || 1250 (!(tgt_flags & OS::TGT_MAP_PRIVATE) && 1251 !(tgt_flags & OS::TGT_MAP_SHARED)) || 1252 !length) { 1253 return -EINVAL; 1254 } 1255 1256 if ((prot & PROT_WRITE) && (tgt_flags & OS::TGT_MAP_SHARED)) { 1257 // With shared mmaps, there are two cases to consider: 1258 // 1) anonymous: writes should modify the mapping and this should be 1259 // visible to observers who share the mapping. Currently, it's 1260 // difficult to update the shared mapping because there's no 1261 // structure which maintains information about the which virtual 1262 // memory areas are shared. If that structure existed, it would be 1263 // possible to make the translations point to the same frames. 1264 // 2) file-backed: writes should modify the mapping and the file 1265 // which is backed by the mapping. The shared mapping problem is the 1266 // same as what was mentioned about the anonymous mappings. For 1267 // file-backed mappings, the writes to the file are difficult 1268 // because it requires syncing what the mapping holds with the file 1269 // that resides on the host system. So, any write on a real system 1270 // would cause the change to be propagated to the file mapping at 1271 // some point in the future (the inode is tracked along with the 1272 // mapping). This isn't guaranteed to always happen, but it usually 1273 // works well enough. The guarantee is provided by the msync system 1274 // call. We could force the change through with shared mappings with 1275 // a call to msync, but that again would require more information 1276 // than we currently maintain. 1277 warn("mmap: writing to shared mmap region is currently " 1278 "unsupported. The write succeeds on the target, but it " 1279 "will not be propagated to the host or shared mappings"); 1280 } 1281 1282 length = roundUp(length, TheISA::PageBytes); 1283 1284 int sim_fd = -1; 1285 uint8_t *pmap = nullptr; 1286 if (!(tgt_flags & OS::TGT_MAP_ANONYMOUS)) { 1287 sim_fd = p->getSimFD(tgt_fd); 1288 if (sim_fd < 0) 1289 return -EBADF; 1290 1291 pmap = (decltype(pmap))mmap(NULL, length, PROT_READ, MAP_PRIVATE, 1292 sim_fd, offset); 1293 1294 if (pmap == (decltype(pmap))-1) { 1295 warn("mmap: failed to map file into host address space"); 1296 return -errno; 1297 } 1298 } 1299 1300 // Extend global mmap region if necessary. Note that we ignore the 1301 // start address unless MAP_FIXED is specified. 1302 if (!(tgt_flags & OS::TGT_MAP_FIXED)) { 1303 start = p->mmapGrowsDown() ? p->mmap_end - length : p->mmap_end; 1304 p->mmap_end = p->mmapGrowsDown() ? start : p->mmap_end + length; 1305 } 1306 1307 DPRINTF_SYSCALL(Verbose, " mmap range is 0x%x - 0x%x\n", 1308 start, start + length - 1); 1309 1310 // We only allow mappings to overwrite existing mappings if 1311 // TGT_MAP_FIXED is set. Otherwise it shouldn't be a problem 1312 // because we ignore the start hint if TGT_MAP_FIXED is not set. 1313 int clobber = tgt_flags & OS::TGT_MAP_FIXED; 1314 if (clobber) { 1315 for (auto tc : p->system->threadContexts) { 1316 // If we might be overwriting old mappings, we need to 1317 // invalidate potentially stale mappings out of the TLBs. 1318 tc->getDTBPtr()->flushAll(); 1319 tc->getITBPtr()->flushAll(); 1320 } 1321 } 1322 1323 // Allocate physical memory and map it in. If the page table is already 1324 // mapped and clobber is not set, the simulator will issue throw a 1325 // fatal and bail out of the simulation. 1326 p->allocateMem(start, length, clobber); 1327 1328 // Transfer content into target address space. 1329 SETranslatingPortProxy &tp = tc->getMemProxy(); 1330 if (tgt_flags & OS::TGT_MAP_ANONYMOUS) { 1331 // In general, we should zero the mapped area for anonymous mappings, 1332 // with something like: 1333 // tp.memsetBlob(start, 0, length); 1334 // However, given that we don't support sparse mappings, and 1335 // some applications can map a couple of gigabytes of space 1336 // (intending sparse usage), that can get painfully expensive. 1337 // Fortunately, since we don't properly implement munmap either, 1338 // there's no danger of remapping used memory, so for now all 1339 // newly mapped memory should already be zeroed so we can skip it. 1340 } else { 1341 // It is possible to mmap an area larger than a file, however 1342 // accessing unmapped portions the system triggers a "Bus error" 1343 // on the host. We must know when to stop copying the file from 1344 // the host into the target address space. 1345 struct stat file_stat; 1346 if (fstat(sim_fd, &file_stat) > 0) 1347 fatal("mmap: cannot stat file"); 1348 1349 // Copy the portion of the file that is resident. This requires 1350 // checking both the mmap size and the filesize that we are 1351 // trying to mmap into this space; the mmap size also depends 1352 // on the specified offset into the file. 1353 uint64_t size = std::min((uint64_t)file_stat.st_size - offset, 1354 length); 1355 tp.writeBlob(start, pmap, size); 1356 1357 // Cleanup the mmap region before exiting this function. 1358 munmap(pmap, length); 1359 1360 // Maintain the symbol table for dynamic executables. 1361 // The loader will call mmap to map the images into its address 1362 // space and we intercept that here. We can verify that we are 1363 // executing inside the loader by checking the program counter value. 1364 // XXX: with multiprogrammed workloads or multi-node configurations, 1365 // this will not work since there is a single global symbol table. 1366 ObjectFile *interpreter = p->getInterpreter(); 1367 if (interpreter) { 1368 Addr text_start = interpreter->textBase(); 1369 Addr text_end = text_start + interpreter->textSize(); 1370 1371 Addr pc = tc->pcState().pc(); 1372 1373 if (pc >= text_start && pc < text_end) { 1374 FDEntry *fde = p->getFDEntry(tgt_fd); 1375 1376 ObjectFile *lib = createObjectFile(fde->filename); 1377 1378 if (lib) { 1379 lib->loadAllSymbols(debugSymbolTable, 1380 lib->textBase(), start); 1381 } 1382 } 1383 } 1384 1385 // Note that we do not zero out the remainder of the mapping. This 1386 // is done by a real system, but it probably will not affect 1387 // execution (hopefully). 1388 } 1389 1390 return start; 1391} 1392 1393template <class OS> 1394SyscallReturn 1395pwrite64Func(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 1396{ 1397 int index = 0; 1398 int tgt_fd = p->getSyscallArg(tc, index); 1399 Addr bufPtr = p->getSyscallArg(tc, index); 1400 int nbytes = p->getSyscallArg(tc, index); 1401 int offset = p->getSyscallArg(tc, index); 1402 1403 int sim_fd = p->getSimFD(tgt_fd); 1404 if (sim_fd < 0) 1405 return -EBADF; 1406 1407 BufferArg bufArg(bufPtr, nbytes); 1408 bufArg.copyIn(tc->getMemProxy()); 1409 1410 int bytes_written = pwrite(sim_fd, bufArg.bufferPtr(), nbytes, offset); 1411 1412 return (bytes_written == -1) ? -errno : bytes_written; 1413} 1414 1415/// Target mmap() handler. 1416template <class OS> 1417SyscallReturn 1418mmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 1419{ 1420 return mmapImpl<OS>(desc, num, p, tc, false); 1421} 1422 1423/// Target mmap2() handler. 1424template <class OS> 1425SyscallReturn 1426mmap2Func(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 1427{ 1428 return mmapImpl<OS>(desc, num, p, tc, true); 1429} 1430 1431/// Target getrlimit() handler. 1432template <class OS> 1433SyscallReturn 1434getrlimitFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1435 ThreadContext *tc) 1436{ 1437 int index = 0; 1438 unsigned resource = process->getSyscallArg(tc, index); 1439 TypedBufferArg<typename OS::rlimit> rlp(process->getSyscallArg(tc, index)); 1440 1441 switch (resource) { 1442 case OS::TGT_RLIMIT_STACK: 1443 // max stack size in bytes: make up a number (8MB for now) 1444 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; 1445 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1446 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1447 break; 1448 1449 case OS::TGT_RLIMIT_DATA: 1450 // max data segment size in bytes: make up a number 1451 rlp->rlim_cur = rlp->rlim_max = 256 * 1024 * 1024; 1452 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1453 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1454 break; 1455 1456 default: 1457 warn("getrlimit: unimplemented resource %d", resource); 1458 return -EINVAL; 1459 break; 1460 } 1461 1462 rlp.copyOut(tc->getMemProxy()); 1463 return 0; 1464} 1465 1466/// Target clock_gettime() function. 1467template <class OS> 1468SyscallReturn 1469clock_gettimeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 1470{ 1471 int index = 1; 1472 //int clk_id = p->getSyscallArg(tc, index); 1473 TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index)); 1474 1475 getElapsedTimeNano(tp->tv_sec, tp->tv_nsec); 1476 tp->tv_sec += seconds_since_epoch; 1477 tp->tv_sec = TheISA::htog(tp->tv_sec); 1478 tp->tv_nsec = TheISA::htog(tp->tv_nsec); 1479 1480 tp.copyOut(tc->getMemProxy()); 1481 1482 return 0; 1483} 1484 1485/// Target clock_getres() function. 1486template <class OS> 1487SyscallReturn 1488clock_getresFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 1489{ 1490 int index = 1; 1491 TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index)); 1492 1493 // Set resolution at ns, which is what clock_gettime() returns 1494 tp->tv_sec = 0; 1495 tp->tv_nsec = 1; 1496 1497 tp.copyOut(tc->getMemProxy()); 1498 1499 return 0; 1500} 1501 1502/// Target gettimeofday() handler. 1503template <class OS> 1504SyscallReturn 1505gettimeofdayFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1506 ThreadContext *tc) 1507{ 1508 int index = 0; 1509 TypedBufferArg<typename OS::timeval> tp(process->getSyscallArg(tc, index)); 1510 1511 getElapsedTimeMicro(tp->tv_sec, tp->tv_usec); 1512 tp->tv_sec += seconds_since_epoch; 1513 tp->tv_sec = TheISA::htog(tp->tv_sec); 1514 tp->tv_usec = TheISA::htog(tp->tv_usec); 1515 1516 tp.copyOut(tc->getMemProxy()); 1517 1518 return 0; 1519} 1520 1521 1522/// Target utimes() handler. 1523template <class OS> 1524SyscallReturn 1525utimesFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1526 ThreadContext *tc) 1527{ 1528 std::string path; 1529 1530 int index = 0; 1531 if (!tc->getMemProxy().tryReadString(path, 1532 process->getSyscallArg(tc, index))) { 1533 return -EFAULT; 1534 } 1535 1536 TypedBufferArg<typename OS::timeval [2]> 1537 tp(process->getSyscallArg(tc, index)); 1538 tp.copyIn(tc->getMemProxy()); 1539 1540 struct timeval hostTimeval[2]; 1541 for (int i = 0; i < 2; ++i) 1542 { 1543 hostTimeval[i].tv_sec = TheISA::gtoh((*tp)[i].tv_sec); 1544 hostTimeval[i].tv_usec = TheISA::gtoh((*tp)[i].tv_usec); 1545 } 1546 1547 // Adjust path for current working directory 1548 path = process->fullPath(path); 1549 1550 int result = utimes(path.c_str(), hostTimeval); 1551 1552 if (result < 0) 1553 return -errno; 1554 1555 return 0; 1556} 1557/// Target getrusage() function. 1558template <class OS> 1559SyscallReturn 1560getrusageFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1561 ThreadContext *tc) 1562{ 1563 int index = 0; 1564 int who = process->getSyscallArg(tc, index); // THREAD, SELF, or CHILDREN 1565 TypedBufferArg<typename OS::rusage> rup(process->getSyscallArg(tc, index)); 1566 1567 rup->ru_utime.tv_sec = 0; 1568 rup->ru_utime.tv_usec = 0; 1569 rup->ru_stime.tv_sec = 0; 1570 rup->ru_stime.tv_usec = 0; 1571 rup->ru_maxrss = 0; 1572 rup->ru_ixrss = 0; 1573 rup->ru_idrss = 0; 1574 rup->ru_isrss = 0; 1575 rup->ru_minflt = 0; 1576 rup->ru_majflt = 0; 1577 rup->ru_nswap = 0; 1578 rup->ru_inblock = 0; 1579 rup->ru_oublock = 0; 1580 rup->ru_msgsnd = 0; 1581 rup->ru_msgrcv = 0; 1582 rup->ru_nsignals = 0; 1583 rup->ru_nvcsw = 0; 1584 rup->ru_nivcsw = 0; 1585 1586 switch (who) { 1587 case OS::TGT_RUSAGE_SELF: 1588 getElapsedTimeMicro(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec); 1589 rup->ru_utime.tv_sec = TheISA::htog(rup->ru_utime.tv_sec); 1590 rup->ru_utime.tv_usec = TheISA::htog(rup->ru_utime.tv_usec); 1591 break; 1592 1593 case OS::TGT_RUSAGE_CHILDREN: 1594 // do nothing. We have no child processes, so they take no time. 1595 break; 1596 1597 default: 1598 // don't really handle THREAD or CHILDREN, but just warn and 1599 // plow ahead 1600 warn("getrusage() only supports RUSAGE_SELF. Parameter %d ignored.", 1601 who); 1602 } 1603 1604 rup.copyOut(tc->getMemProxy()); 1605 1606 return 0; 1607} 1608 1609/// Target times() function. 1610template <class OS> 1611SyscallReturn 1612timesFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1613 ThreadContext *tc) 1614{ 1615 int index = 0; 1616 TypedBufferArg<typename OS::tms> bufp(process->getSyscallArg(tc, index)); 1617 1618 // Fill in the time structure (in clocks) 1619 int64_t clocks = curTick() * OS::M5_SC_CLK_TCK / SimClock::Int::s; 1620 bufp->tms_utime = clocks; 1621 bufp->tms_stime = 0; 1622 bufp->tms_cutime = 0; 1623 bufp->tms_cstime = 0; 1624 1625 // Convert to host endianness 1626 bufp->tms_utime = TheISA::htog(bufp->tms_utime); 1627 1628 // Write back 1629 bufp.copyOut(tc->getMemProxy()); 1630 1631 // Return clock ticks since system boot 1632 return clocks; 1633} 1634 1635/// Target time() function. 1636template <class OS> 1637SyscallReturn 1638timeFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1639 ThreadContext *tc) 1640{ 1641 typename OS::time_t sec, usec; 1642 getElapsedTimeMicro(sec, usec); 1643 sec += seconds_since_epoch; 1644 1645 int index = 0; 1646 Addr taddr = (Addr)process->getSyscallArg(tc, index); 1647 if (taddr != 0) { 1648 typename OS::time_t t = sec; 1649 t = TheISA::htog(t); 1650 SETranslatingPortProxy &p = tc->getMemProxy(); 1651 p.writeBlob(taddr, (uint8_t*)&t, (int)sizeof(typename OS::time_t)); 1652 } 1653 return sec; 1654} 1655 1656 1657#endif // __SIM_SYSCALL_EMUL_HH__ 1658