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