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