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