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