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