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