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