syscall_emul.hh revision 11856
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 220/// Target chown() handler. 221SyscallReturn chownFunc(SyscallDesc *desc, int num, 222 Process *p, ThreadContext *tc); 223 224 225/// Target fchown() handler. 226SyscallReturn fchownFunc(SyscallDesc *desc, int num, 227 Process *p, ThreadContext *tc); 228 229/// Target dup() handler. 230SyscallReturn dupFunc(SyscallDesc *desc, int num, 231 Process *process, ThreadContext *tc); 232 233/// Target fnctl() handler. 234SyscallReturn fcntlFunc(SyscallDesc *desc, int num, 235 Process *process, ThreadContext *tc); 236 237/// Target fcntl64() handler. 238SyscallReturn fcntl64Func(SyscallDesc *desc, int num, 239 Process *process, ThreadContext *tc); 240 241/// Target setuid() handler. 242SyscallReturn setuidFunc(SyscallDesc *desc, int num, 243 Process *p, ThreadContext *tc); 244 245/// Target getpid() handler. 246SyscallReturn getpidFunc(SyscallDesc *desc, int num, 247 Process *p, ThreadContext *tc); 248 249/// Target getuid() handler. 250SyscallReturn getuidFunc(SyscallDesc *desc, int num, 251 Process *p, ThreadContext *tc); 252 253/// Target getgid() handler. 254SyscallReturn getgidFunc(SyscallDesc *desc, int num, 255 Process *p, ThreadContext *tc); 256 257/// Target getppid() handler. 258SyscallReturn getppidFunc(SyscallDesc *desc, int num, 259 Process *p, ThreadContext *tc); 260 261/// Target geteuid() handler. 262SyscallReturn geteuidFunc(SyscallDesc *desc, int num, 263 Process *p, ThreadContext *tc); 264 265/// Target getegid() handler. 266SyscallReturn getegidFunc(SyscallDesc *desc, int num, 267 Process *p, ThreadContext *tc); 268 269/// Target clone() handler. 270SyscallReturn cloneFunc(SyscallDesc *desc, int num, 271 Process *p, ThreadContext *tc); 272 273/// Target access() handler 274SyscallReturn accessFunc(SyscallDesc *desc, int num, 275 Process *p, ThreadContext *tc); 276SyscallReturn accessFunc(SyscallDesc *desc, int num, 277 Process *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, Process *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 Process *process, ThreadContext *tc); 367 368/// Target getpidPseudo() handler. 369SyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num, 370 Process *p, ThreadContext *tc); 371 372/// Target getuidPseudo() handler. 373SyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num, 374 Process *p, ThreadContext *tc); 375 376/// Target getgidPseudo() handler. 377SyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num, 378 Process *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 tgt->f_type = TheISA::htog(host->f_type); 534#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) 535 tgt->f_bsize = TheISA::htog(host->f_iosize); 536#else 537 tgt->f_bsize = TheISA::htog(host->f_bsize); 538#endif 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#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) 546 tgt->f_namelen = TheISA::htog(host->f_namemax); 547 tgt->f_frsize = TheISA::htog(host->f_bsize); 548#elif defined(__APPLE__) 549 tgt->f_namelen = 0; 550 tgt->f_frsize = 0; 551#else 552 tgt->f_namelen = TheISA::htog(host->f_namelen); 553 tgt->f_frsize = TheISA::htog(host->f_frsize); 554#endif 555#if defined(__linux__) 556 memcpy(&tgt->f_spare, &host->f_spare, sizeof(host->f_spare)); 557#else 558 /* 559 * The fields are different sizes per OS. Don't bother with 560 * f_spare or f_reserved on non-Linux for now. 561 */ 562 memset(&tgt->f_spare, 0, sizeof(tgt->f_spare)); 563#endif 564 565 tgt.copyOut(mem); 566} 567 568/// Target ioctl() handler. For the most part, programs call ioctl() 569/// only to find out if their stdout is a tty, to determine whether to 570/// do line or block buffering. We always claim that output fds are 571/// not TTYs to provide repeatable results. 572template <class OS> 573SyscallReturn 574ioctlFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 575{ 576 int index = 0; 577 int tgt_fd = p->getSyscallArg(tc, index); 578 unsigned req = p->getSyscallArg(tc, index); 579 580 DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", tgt_fd, req); 581 582 if (OS::isTtyReq(req)) 583 return -ENOTTY; 584 585 auto dfdp = std::dynamic_pointer_cast<DeviceFDEntry>((*p->fds)[tgt_fd]); 586 if (!dfdp) 587 return -EBADF; 588 589 /** 590 * If the driver is valid, issue the ioctl through it. Otherwise, 591 * there's an implicit assumption that the device is a TTY type and we 592 * return that we do not have a valid TTY. 593 */ 594 EmulatedDriver *emul_driver = dfdp->getDriver(); 595 if (emul_driver) 596 return emul_driver->ioctl(p, tc, req); 597 598 /** 599 * For lack of a better return code, return ENOTTY. Ideally, we should 600 * return something better here, but at least we issue the warning. 601 */ 602 warn("Unsupported ioctl call (return ENOTTY): ioctl(%d, 0x%x, ...) @ \n", 603 tgt_fd, req, tc->pcState()); 604 return -ENOTTY; 605} 606 607template <class OS> 608static SyscallReturn 609openFunc(SyscallDesc *desc, int callnum, Process *process, 610 ThreadContext *tc, int index) 611{ 612 std::string path; 613 614 if (!tc->getMemProxy().tryReadString(path, 615 process->getSyscallArg(tc, index))) 616 return -EFAULT; 617 618 int tgtFlags = process->getSyscallArg(tc, index); 619 int mode = process->getSyscallArg(tc, index); 620 int hostFlags = 0; 621 622 // translate open flags 623 for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) { 624 if (tgtFlags & OS::openFlagTable[i].tgtFlag) { 625 tgtFlags &= ~OS::openFlagTable[i].tgtFlag; 626 hostFlags |= OS::openFlagTable[i].hostFlag; 627 } 628 } 629 630 // any target flags left? 631 if (tgtFlags != 0) 632 warn("Syscall: open: cannot decode flags 0x%x", tgtFlags); 633 634#ifdef __CYGWIN32__ 635 hostFlags |= O_BINARY; 636#endif 637 638 // Adjust path for current working directory 639 path = process->fullPath(path); 640 641 DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str()); 642 643 if (startswith(path, "/dev/")) { 644 std::string filename = path.substr(strlen("/dev/")); 645 if (filename == "sysdev0") { 646 // This is a memory-mapped high-resolution timer device on Alpha. 647 // We don't support it, so just punt. 648 warn("Ignoring open(%s, ...)\n", path); 649 return -ENOENT; 650 } 651 652 EmulatedDriver *drv = process->findDriver(filename); 653 if (drv) { 654 // the driver's open method will allocate a fd from the 655 // process if necessary. 656 return drv->open(process, tc, mode, hostFlags); 657 } 658 659 // fall through here for pass through to host devices, such as 660 // /dev/zero 661 } 662 663 int fd; 664 int local_errno; 665 if (startswith(path, "/proc/") || startswith(path, "/system/") || 666 startswith(path, "/platform/") || startswith(path, "/sys/")) { 667 // It's a proc/sys entry and requires special handling 668 fd = OS::openSpecialFile(path, process, tc); 669 local_errno = ENOENT; 670 } else { 671 // open the file 672 fd = open(path.c_str(), hostFlags, mode); 673 local_errno = errno; 674 } 675 676 if (fd == -1) 677 return -local_errno; 678 679 std::shared_ptr<FileFDEntry> ffdp = 680 std::make_shared<FileFDEntry>(fd, hostFlags, path.c_str(), false); 681 return process->fds->allocFD(ffdp); 682} 683 684/// Target open() handler. 685template <class OS> 686SyscallReturn 687openFunc(SyscallDesc *desc, int callnum, Process *process, 688 ThreadContext *tc) 689{ 690 return openFunc<OS>(desc, callnum, process, tc, 0); 691} 692 693/// Target openat() handler. 694template <class OS> 695SyscallReturn 696openatFunc(SyscallDesc *desc, int callnum, Process *process, 697 ThreadContext *tc) 698{ 699 int index = 0; 700 int dirfd = process->getSyscallArg(tc, index); 701 if (dirfd != OS::TGT_AT_FDCWD) 702 warn("openat: first argument not AT_FDCWD; unlikely to work"); 703 return openFunc<OS>(desc, callnum, process, tc, 1); 704} 705 706/// Target unlinkat() handler. 707template <class OS> 708SyscallReturn 709unlinkatFunc(SyscallDesc *desc, int callnum, Process *process, 710 ThreadContext *tc) 711{ 712 int index = 0; 713 int dirfd = process->getSyscallArg(tc, index); 714 if (dirfd != OS::TGT_AT_FDCWD) 715 warn("unlinkat: first argument not AT_FDCWD; unlikely to work"); 716 717 return unlinkHelper(desc, callnum, process, tc, 1); 718} 719 720/// Target facessat() handler 721template <class OS> 722SyscallReturn 723faccessatFunc(SyscallDesc *desc, int callnum, Process *process, 724 ThreadContext *tc) 725{ 726 int index = 0; 727 int dirfd = process->getSyscallArg(tc, index); 728 if (dirfd != OS::TGT_AT_FDCWD) 729 warn("faccessat: first argument not AT_FDCWD; unlikely to work"); 730 return accessFunc(desc, callnum, process, tc, 1); 731} 732 733/// Target readlinkat() handler 734template <class OS> 735SyscallReturn 736readlinkatFunc(SyscallDesc *desc, int callnum, Process *process, 737 ThreadContext *tc) 738{ 739 int index = 0; 740 int dirfd = process->getSyscallArg(tc, index); 741 if (dirfd != OS::TGT_AT_FDCWD) 742 warn("openat: first argument not AT_FDCWD; unlikely to work"); 743 return readlinkFunc(desc, callnum, process, tc, 1); 744} 745 746/// Target renameat() handler. 747template <class OS> 748SyscallReturn 749renameatFunc(SyscallDesc *desc, int callnum, Process *process, 750 ThreadContext *tc) 751{ 752 int index = 0; 753 754 int olddirfd = process->getSyscallArg(tc, index); 755 if (olddirfd != OS::TGT_AT_FDCWD) 756 warn("renameat: first argument not AT_FDCWD; unlikely to work"); 757 758 std::string old_name; 759 760 if (!tc->getMemProxy().tryReadString(old_name, 761 process->getSyscallArg(tc, index))) 762 return -EFAULT; 763 764 int newdirfd = process->getSyscallArg(tc, index); 765 if (newdirfd != OS::TGT_AT_FDCWD) 766 warn("renameat: third argument not AT_FDCWD; unlikely to work"); 767 768 std::string new_name; 769 770 if (!tc->getMemProxy().tryReadString(new_name, 771 process->getSyscallArg(tc, index))) 772 return -EFAULT; 773 774 // Adjust path for current working directory 775 old_name = process->fullPath(old_name); 776 new_name = process->fullPath(new_name); 777 778 int result = rename(old_name.c_str(), new_name.c_str()); 779 return (result == -1) ? -errno : result; 780} 781 782/// Target sysinfo() handler. 783template <class OS> 784SyscallReturn 785sysinfoFunc(SyscallDesc *desc, int callnum, Process *process, 786 ThreadContext *tc) 787{ 788 789 int index = 0; 790 TypedBufferArg<typename OS::tgt_sysinfo> 791 sysinfo(process->getSyscallArg(tc, index)); 792 793 sysinfo->uptime = seconds_since_epoch; 794 sysinfo->totalram = process->system->memSize(); 795 sysinfo->mem_unit = 1; 796 797 sysinfo.copyOut(tc->getMemProxy()); 798 799 return 0; 800} 801 802/// Target chmod() handler. 803template <class OS> 804SyscallReturn 805chmodFunc(SyscallDesc *desc, int callnum, Process *process, 806 ThreadContext *tc) 807{ 808 std::string path; 809 810 int index = 0; 811 if (!tc->getMemProxy().tryReadString(path, 812 process->getSyscallArg(tc, index))) { 813 return -EFAULT; 814 } 815 816 uint32_t mode = process->getSyscallArg(tc, index); 817 mode_t hostMode = 0; 818 819 // XXX translate mode flags via OS::something??? 820 hostMode = mode; 821 822 // Adjust path for current working directory 823 path = process->fullPath(path); 824 825 // do the chmod 826 int result = chmod(path.c_str(), hostMode); 827 if (result < 0) 828 return -errno; 829 830 return 0; 831} 832 833 834/// Target fchmod() handler. 835template <class OS> 836SyscallReturn 837fchmodFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 838{ 839 int index = 0; 840 int tgt_fd = p->getSyscallArg(tc, index); 841 uint32_t mode = p->getSyscallArg(tc, index); 842 843 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 844 if (!ffdp) 845 return -EBADF; 846 int sim_fd = ffdp->getSimFD(); 847 848 mode_t hostMode = mode; 849 850 int result = fchmod(sim_fd, hostMode); 851 852 return (result < 0) ? -errno : 0; 853} 854 855/// Target mremap() handler. 856template <class OS> 857SyscallReturn 858mremapFunc(SyscallDesc *desc, int callnum, Process *process, ThreadContext *tc) 859{ 860 int index = 0; 861 Addr start = process->getSyscallArg(tc, index); 862 uint64_t old_length = process->getSyscallArg(tc, index); 863 uint64_t new_length = process->getSyscallArg(tc, index); 864 uint64_t flags = process->getSyscallArg(tc, index); 865 uint64_t provided_address = 0; 866 bool use_provided_address = flags & OS::TGT_MREMAP_FIXED; 867 868 if (use_provided_address) 869 provided_address = process->getSyscallArg(tc, index); 870 871 if ((start % TheISA::PageBytes != 0) || 872 (provided_address % TheISA::PageBytes != 0)) { 873 warn("mremap failing: arguments not page aligned"); 874 return -EINVAL; 875 } 876 877 new_length = roundUp(new_length, TheISA::PageBytes); 878 879 if (new_length > old_length) { 880 if ((start + old_length) == process->mmap_end && 881 (!use_provided_address || provided_address == start)) { 882 uint64_t diff = new_length - old_length; 883 process->allocateMem(process->mmap_end, diff); 884 process->mmap_end += diff; 885 return start; 886 } else { 887 if (!use_provided_address && !(flags & OS::TGT_MREMAP_MAYMOVE)) { 888 warn("can't remap here and MREMAP_MAYMOVE flag not set\n"); 889 return -ENOMEM; 890 } else { 891 uint64_t new_start = use_provided_address ? 892 provided_address : process->mmap_end; 893 process->pTable->remap(start, old_length, new_start); 894 warn("mremapping to new vaddr %08p-%08p, adding %d\n", 895 new_start, new_start + new_length, 896 new_length - old_length); 897 // add on the remaining unallocated pages 898 process->allocateMem(new_start + old_length, 899 new_length - old_length, 900 use_provided_address /* clobber */); 901 if (!use_provided_address) 902 process->mmap_end += new_length; 903 if (use_provided_address && 904 new_start + new_length > process->mmap_end) { 905 // something fishy going on here, at least notify the user 906 // @todo: increase mmap_end? 907 warn("mmap region limit exceeded with MREMAP_FIXED\n"); 908 } 909 warn("returning %08p as start\n", new_start); 910 return new_start; 911 } 912 } 913 } else { 914 if (use_provided_address && provided_address != start) 915 process->pTable->remap(start, new_length, provided_address); 916 process->pTable->unmap(start + new_length, old_length - new_length); 917 return use_provided_address ? provided_address : start; 918 } 919} 920 921/// Target stat() handler. 922template <class OS> 923SyscallReturn 924statFunc(SyscallDesc *desc, int callnum, Process *process, 925 ThreadContext *tc) 926{ 927 std::string path; 928 929 int index = 0; 930 if (!tc->getMemProxy().tryReadString(path, 931 process->getSyscallArg(tc, index))) { 932 return -EFAULT; 933 } 934 Addr bufPtr = process->getSyscallArg(tc, index); 935 936 // Adjust path for current working directory 937 path = process->fullPath(path); 938 939 struct stat hostBuf; 940 int result = stat(path.c_str(), &hostBuf); 941 942 if (result < 0) 943 return -errno; 944 945 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 946 947 return 0; 948} 949 950 951/// Target stat64() handler. 952template <class OS> 953SyscallReturn 954stat64Func(SyscallDesc *desc, int callnum, Process *process, 955 ThreadContext *tc) 956{ 957 std::string path; 958 959 int index = 0; 960 if (!tc->getMemProxy().tryReadString(path, 961 process->getSyscallArg(tc, index))) 962 return -EFAULT; 963 Addr bufPtr = process->getSyscallArg(tc, index); 964 965 // Adjust path for current working directory 966 path = process->fullPath(path); 967 968#if NO_STAT64 969 struct stat hostBuf; 970 int result = stat(path.c_str(), &hostBuf); 971#else 972 struct stat64 hostBuf; 973 int result = stat64(path.c_str(), &hostBuf); 974#endif 975 976 if (result < 0) 977 return -errno; 978 979 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 980 981 return 0; 982} 983 984 985/// Target fstatat64() handler. 986template <class OS> 987SyscallReturn 988fstatat64Func(SyscallDesc *desc, int callnum, Process *process, 989 ThreadContext *tc) 990{ 991 int index = 0; 992 int dirfd = process->getSyscallArg(tc, index); 993 if (dirfd != OS::TGT_AT_FDCWD) 994 warn("fstatat64: first argument not AT_FDCWD; unlikely to work"); 995 996 std::string path; 997 if (!tc->getMemProxy().tryReadString(path, 998 process->getSyscallArg(tc, index))) 999 return -EFAULT; 1000 Addr bufPtr = process->getSyscallArg(tc, index); 1001 1002 // Adjust path for current working directory 1003 path = process->fullPath(path); 1004 1005#if NO_STAT64 1006 struct stat hostBuf; 1007 int result = stat(path.c_str(), &hostBuf); 1008#else 1009 struct stat64 hostBuf; 1010 int result = stat64(path.c_str(), &hostBuf); 1011#endif 1012 1013 if (result < 0) 1014 return -errno; 1015 1016 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1017 1018 return 0; 1019} 1020 1021 1022/// Target fstat64() handler. 1023template <class OS> 1024SyscallReturn 1025fstat64Func(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1026{ 1027 int index = 0; 1028 int tgt_fd = p->getSyscallArg(tc, index); 1029 Addr bufPtr = p->getSyscallArg(tc, index); 1030 1031 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 1032 if (!ffdp) 1033 return -EBADF; 1034 int sim_fd = ffdp->getSimFD(); 1035 1036#if NO_STAT64 1037 struct stat hostBuf; 1038 int result = fstat(sim_fd, &hostBuf); 1039#else 1040 struct stat64 hostBuf; 1041 int result = fstat64(sim_fd, &hostBuf); 1042#endif 1043 1044 if (result < 0) 1045 return -errno; 1046 1047 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (sim_fd == 1)); 1048 1049 return 0; 1050} 1051 1052 1053/// Target lstat() handler. 1054template <class OS> 1055SyscallReturn 1056lstatFunc(SyscallDesc *desc, int callnum, Process *process, 1057 ThreadContext *tc) 1058{ 1059 std::string path; 1060 1061 int index = 0; 1062 if (!tc->getMemProxy().tryReadString(path, 1063 process->getSyscallArg(tc, index))) { 1064 return -EFAULT; 1065 } 1066 Addr bufPtr = process->getSyscallArg(tc, index); 1067 1068 // Adjust path for current working directory 1069 path = process->fullPath(path); 1070 1071 struct stat hostBuf; 1072 int result = lstat(path.c_str(), &hostBuf); 1073 1074 if (result < 0) 1075 return -errno; 1076 1077 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1078 1079 return 0; 1080} 1081 1082/// Target lstat64() handler. 1083template <class OS> 1084SyscallReturn 1085lstat64Func(SyscallDesc *desc, int callnum, Process *process, 1086 ThreadContext *tc) 1087{ 1088 std::string path; 1089 1090 int index = 0; 1091 if (!tc->getMemProxy().tryReadString(path, 1092 process->getSyscallArg(tc, index))) { 1093 return -EFAULT; 1094 } 1095 Addr bufPtr = process->getSyscallArg(tc, index); 1096 1097 // Adjust path for current working directory 1098 path = process->fullPath(path); 1099 1100#if NO_STAT64 1101 struct stat hostBuf; 1102 int result = lstat(path.c_str(), &hostBuf); 1103#else 1104 struct stat64 hostBuf; 1105 int result = lstat64(path.c_str(), &hostBuf); 1106#endif 1107 1108 if (result < 0) 1109 return -errno; 1110 1111 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1112 1113 return 0; 1114} 1115 1116/// Target fstat() handler. 1117template <class OS> 1118SyscallReturn 1119fstatFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1120{ 1121 int index = 0; 1122 int tgt_fd = p->getSyscallArg(tc, index); 1123 Addr bufPtr = p->getSyscallArg(tc, index); 1124 1125 DPRINTF_SYSCALL(Verbose, "fstat(%d, ...)\n", tgt_fd); 1126 1127 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 1128 if (!ffdp) 1129 return -EBADF; 1130 int sim_fd = ffdp->getSimFD(); 1131 1132 struct stat hostBuf; 1133 int result = fstat(sim_fd, &hostBuf); 1134 1135 if (result < 0) 1136 return -errno; 1137 1138 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (sim_fd == 1)); 1139 1140 return 0; 1141} 1142 1143 1144/// Target statfs() handler. 1145template <class OS> 1146SyscallReturn 1147statfsFunc(SyscallDesc *desc, int callnum, Process *process, 1148 ThreadContext *tc) 1149{ 1150#if NO_STATFS 1151 warn("Host OS cannot support calls to statfs. Ignoring syscall"); 1152#else 1153 std::string path; 1154 1155 int index = 0; 1156 if (!tc->getMemProxy().tryReadString(path, 1157 process->getSyscallArg(tc, index))) { 1158 return -EFAULT; 1159 } 1160 Addr bufPtr = process->getSyscallArg(tc, index); 1161 1162 // Adjust path for current working directory 1163 path = process->fullPath(path); 1164 1165 struct statfs hostBuf; 1166 int result = statfs(path.c_str(), &hostBuf); 1167 1168 if (result < 0) 1169 return -errno; 1170 1171 copyOutStatfsBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1172#endif 1173 return 0; 1174} 1175 1176 1177/// Target fstatfs() handler. 1178template <class OS> 1179SyscallReturn 1180fstatfsFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1181{ 1182 int index = 0; 1183 int tgt_fd = p->getSyscallArg(tc, index); 1184 Addr bufPtr = p->getSyscallArg(tc, index); 1185 1186 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 1187 if (!ffdp) 1188 return -EBADF; 1189 int sim_fd = ffdp->getSimFD(); 1190 1191 struct statfs hostBuf; 1192 int result = fstatfs(sim_fd, &hostBuf); 1193 1194 if (result < 0) 1195 return -errno; 1196 1197 copyOutStatfsBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1198 1199 return 0; 1200} 1201 1202 1203/// Target writev() handler. 1204template <class OS> 1205SyscallReturn 1206writevFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1207{ 1208 int index = 0; 1209 int tgt_fd = p->getSyscallArg(tc, index); 1210 1211 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 1212 if (!hbfdp) 1213 return -EBADF; 1214 int sim_fd = hbfdp->getSimFD(); 1215 1216 SETranslatingPortProxy &prox = tc->getMemProxy(); 1217 uint64_t tiov_base = p->getSyscallArg(tc, index); 1218 size_t count = p->getSyscallArg(tc, index); 1219 struct iovec hiov[count]; 1220 for (size_t i = 0; i < count; ++i) { 1221 typename OS::tgt_iovec tiov; 1222 1223 prox.readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec), 1224 (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec)); 1225 hiov[i].iov_len = TheISA::gtoh(tiov.iov_len); 1226 hiov[i].iov_base = new char [hiov[i].iov_len]; 1227 prox.readBlob(TheISA::gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base, 1228 hiov[i].iov_len); 1229 } 1230 1231 int result = writev(sim_fd, hiov, count); 1232 1233 for (size_t i = 0; i < count; ++i) 1234 delete [] (char *)hiov[i].iov_base; 1235 1236 if (result < 0) 1237 return -errno; 1238 1239 return result; 1240} 1241 1242/// Real mmap handler. 1243template <class OS> 1244SyscallReturn 1245mmapImpl(SyscallDesc *desc, int num, Process *p, ThreadContext *tc, 1246 bool is_mmap2) 1247{ 1248 int index = 0; 1249 Addr start = p->getSyscallArg(tc, index); 1250 uint64_t length = p->getSyscallArg(tc, index); 1251 int prot = p->getSyscallArg(tc, index); 1252 int tgt_flags = p->getSyscallArg(tc, index); 1253 int tgt_fd = p->getSyscallArg(tc, index); 1254 int offset = p->getSyscallArg(tc, index); 1255 1256 if (is_mmap2) 1257 offset *= TheISA::PageBytes; 1258 1259 if (start & (TheISA::PageBytes - 1) || 1260 offset & (TheISA::PageBytes - 1) || 1261 (tgt_flags & OS::TGT_MAP_PRIVATE && 1262 tgt_flags & OS::TGT_MAP_SHARED) || 1263 (!(tgt_flags & OS::TGT_MAP_PRIVATE) && 1264 !(tgt_flags & OS::TGT_MAP_SHARED)) || 1265 !length) { 1266 return -EINVAL; 1267 } 1268 1269 if ((prot & PROT_WRITE) && (tgt_flags & OS::TGT_MAP_SHARED)) { 1270 // With shared mmaps, there are two cases to consider: 1271 // 1) anonymous: writes should modify the mapping and this should be 1272 // visible to observers who share the mapping. Currently, it's 1273 // difficult to update the shared mapping because there's no 1274 // structure which maintains information about the which virtual 1275 // memory areas are shared. If that structure existed, it would be 1276 // possible to make the translations point to the same frames. 1277 // 2) file-backed: writes should modify the mapping and the file 1278 // which is backed by the mapping. The shared mapping problem is the 1279 // same as what was mentioned about the anonymous mappings. For 1280 // file-backed mappings, the writes to the file are difficult 1281 // because it requires syncing what the mapping holds with the file 1282 // that resides on the host system. So, any write on a real system 1283 // would cause the change to be propagated to the file mapping at 1284 // some point in the future (the inode is tracked along with the 1285 // mapping). This isn't guaranteed to always happen, but it usually 1286 // works well enough. The guarantee is provided by the msync system 1287 // call. We could force the change through with shared mappings with 1288 // a call to msync, but that again would require more information 1289 // than we currently maintain. 1290 warn("mmap: writing to shared mmap region is currently " 1291 "unsupported. The write succeeds on the target, but it " 1292 "will not be propagated to the host or shared mappings"); 1293 } 1294 1295 length = roundUp(length, TheISA::PageBytes); 1296 1297 int sim_fd = -1; 1298 uint8_t *pmap = nullptr; 1299 if (!(tgt_flags & OS::TGT_MAP_ANONYMOUS)) { 1300 std::shared_ptr<FDEntry> fdep = (*p->fds)[tgt_fd]; 1301 1302 auto dfdp = std::dynamic_pointer_cast<DeviceFDEntry>(fdep); 1303 if (dfdp) { 1304 EmulatedDriver *emul_driver = dfdp->getDriver(); 1305 return emul_driver->mmap(p, tc, start, length, prot, 1306 tgt_flags, tgt_fd, offset); 1307 } 1308 1309 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep); 1310 if (!ffdp) 1311 return -EBADF; 1312 sim_fd = ffdp->getSimFD(); 1313 1314 pmap = (decltype(pmap))mmap(NULL, length, PROT_READ, MAP_PRIVATE, 1315 sim_fd, offset); 1316 1317 if (pmap == (decltype(pmap))-1) { 1318 warn("mmap: failed to map file into host address space"); 1319 return -errno; 1320 } 1321 } 1322 1323 // Extend global mmap region if necessary. Note that we ignore the 1324 // start address unless MAP_FIXED is specified. 1325 if (!(tgt_flags & OS::TGT_MAP_FIXED)) { 1326 start = p->mmapGrowsDown() ? p->mmap_end - length : p->mmap_end; 1327 p->mmap_end = p->mmapGrowsDown() ? start : p->mmap_end + length; 1328 } 1329 1330 DPRINTF_SYSCALL(Verbose, " mmap range is 0x%x - 0x%x\n", 1331 start, start + length - 1); 1332 1333 // We only allow mappings to overwrite existing mappings if 1334 // TGT_MAP_FIXED is set. Otherwise it shouldn't be a problem 1335 // because we ignore the start hint if TGT_MAP_FIXED is not set. 1336 int clobber = tgt_flags & OS::TGT_MAP_FIXED; 1337 if (clobber) { 1338 for (auto tc : p->system->threadContexts) { 1339 // If we might be overwriting old mappings, we need to 1340 // invalidate potentially stale mappings out of the TLBs. 1341 tc->getDTBPtr()->flushAll(); 1342 tc->getITBPtr()->flushAll(); 1343 } 1344 } 1345 1346 // Allocate physical memory and map it in. If the page table is already 1347 // mapped and clobber is not set, the simulator will issue throw a 1348 // fatal and bail out of the simulation. 1349 p->allocateMem(start, length, clobber); 1350 1351 // Transfer content into target address space. 1352 SETranslatingPortProxy &tp = tc->getMemProxy(); 1353 if (tgt_flags & OS::TGT_MAP_ANONYMOUS) { 1354 // In general, we should zero the mapped area for anonymous mappings, 1355 // with something like: 1356 // tp.memsetBlob(start, 0, length); 1357 // However, given that we don't support sparse mappings, and 1358 // some applications can map a couple of gigabytes of space 1359 // (intending sparse usage), that can get painfully expensive. 1360 // Fortunately, since we don't properly implement munmap either, 1361 // there's no danger of remapping used memory, so for now all 1362 // newly mapped memory should already be zeroed so we can skip it. 1363 } else { 1364 // It is possible to mmap an area larger than a file, however 1365 // accessing unmapped portions the system triggers a "Bus error" 1366 // on the host. We must know when to stop copying the file from 1367 // the host into the target address space. 1368 struct stat file_stat; 1369 if (fstat(sim_fd, &file_stat) > 0) 1370 fatal("mmap: cannot stat file"); 1371 1372 // Copy the portion of the file that is resident. This requires 1373 // checking both the mmap size and the filesize that we are 1374 // trying to mmap into this space; the mmap size also depends 1375 // on the specified offset into the file. 1376 uint64_t size = std::min((uint64_t)file_stat.st_size - offset, 1377 length); 1378 tp.writeBlob(start, pmap, size); 1379 1380 // Cleanup the mmap region before exiting this function. 1381 munmap(pmap, length); 1382 1383 // Maintain the symbol table for dynamic executables. 1384 // The loader will call mmap to map the images into its address 1385 // space and we intercept that here. We can verify that we are 1386 // executing inside the loader by checking the program counter value. 1387 // XXX: with multiprogrammed workloads or multi-node configurations, 1388 // this will not work since there is a single global symbol table. 1389 ObjectFile *interpreter = p->getInterpreter(); 1390 if (interpreter) { 1391 Addr text_start = interpreter->textBase(); 1392 Addr text_end = text_start + interpreter->textSize(); 1393 1394 Addr pc = tc->pcState().pc(); 1395 1396 if (pc >= text_start && pc < text_end) { 1397 std::shared_ptr<FDEntry> fdep = (*p->fds)[tgt_fd]; 1398 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep); 1399 ObjectFile *lib = createObjectFile(ffdp->getFileName()); 1400 1401 if (lib) { 1402 lib->loadAllSymbols(debugSymbolTable, 1403 lib->textBase(), start); 1404 } 1405 } 1406 } 1407 1408 // Note that we do not zero out the remainder of the mapping. This 1409 // is done by a real system, but it probably will not affect 1410 // execution (hopefully). 1411 } 1412 1413 return start; 1414} 1415 1416template <class OS> 1417SyscallReturn 1418pwrite64Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1419{ 1420 int index = 0; 1421 int tgt_fd = p->getSyscallArg(tc, index); 1422 Addr bufPtr = p->getSyscallArg(tc, index); 1423 int nbytes = p->getSyscallArg(tc, index); 1424 int offset = p->getSyscallArg(tc, index); 1425 1426 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 1427 if (!ffdp) 1428 return -EBADF; 1429 int sim_fd = ffdp->getSimFD(); 1430 1431 BufferArg bufArg(bufPtr, nbytes); 1432 bufArg.copyIn(tc->getMemProxy()); 1433 1434 int bytes_written = pwrite(sim_fd, bufArg.bufferPtr(), nbytes, offset); 1435 1436 return (bytes_written == -1) ? -errno : bytes_written; 1437} 1438 1439/// Target mmap() handler. 1440template <class OS> 1441SyscallReturn 1442mmapFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1443{ 1444 return mmapImpl<OS>(desc, num, p, tc, false); 1445} 1446 1447/// Target mmap2() handler. 1448template <class OS> 1449SyscallReturn 1450mmap2Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1451{ 1452 return mmapImpl<OS>(desc, num, p, tc, true); 1453} 1454 1455/// Target getrlimit() handler. 1456template <class OS> 1457SyscallReturn 1458getrlimitFunc(SyscallDesc *desc, int callnum, Process *process, 1459 ThreadContext *tc) 1460{ 1461 int index = 0; 1462 unsigned resource = process->getSyscallArg(tc, index); 1463 TypedBufferArg<typename OS::rlimit> rlp(process->getSyscallArg(tc, index)); 1464 1465 switch (resource) { 1466 case OS::TGT_RLIMIT_STACK: 1467 // max stack size in bytes: make up a number (8MB for now) 1468 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; 1469 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1470 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1471 break; 1472 1473 case OS::TGT_RLIMIT_DATA: 1474 // max data segment size in bytes: make up a number 1475 rlp->rlim_cur = rlp->rlim_max = 256 * 1024 * 1024; 1476 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1477 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1478 break; 1479 1480 default: 1481 warn("getrlimit: unimplemented resource %d", resource); 1482 return -EINVAL; 1483 break; 1484 } 1485 1486 rlp.copyOut(tc->getMemProxy()); 1487 return 0; 1488} 1489 1490/// Target clock_gettime() function. 1491template <class OS> 1492SyscallReturn 1493clock_gettimeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1494{ 1495 int index = 1; 1496 //int clk_id = p->getSyscallArg(tc, index); 1497 TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index)); 1498 1499 getElapsedTimeNano(tp->tv_sec, tp->tv_nsec); 1500 tp->tv_sec += seconds_since_epoch; 1501 tp->tv_sec = TheISA::htog(tp->tv_sec); 1502 tp->tv_nsec = TheISA::htog(tp->tv_nsec); 1503 1504 tp.copyOut(tc->getMemProxy()); 1505 1506 return 0; 1507} 1508 1509/// Target clock_getres() function. 1510template <class OS> 1511SyscallReturn 1512clock_getresFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1513{ 1514 int index = 1; 1515 TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index)); 1516 1517 // Set resolution at ns, which is what clock_gettime() returns 1518 tp->tv_sec = 0; 1519 tp->tv_nsec = 1; 1520 1521 tp.copyOut(tc->getMemProxy()); 1522 1523 return 0; 1524} 1525 1526/// Target gettimeofday() handler. 1527template <class OS> 1528SyscallReturn 1529gettimeofdayFunc(SyscallDesc *desc, int callnum, Process *process, 1530 ThreadContext *tc) 1531{ 1532 int index = 0; 1533 TypedBufferArg<typename OS::timeval> tp(process->getSyscallArg(tc, index)); 1534 1535 getElapsedTimeMicro(tp->tv_sec, tp->tv_usec); 1536 tp->tv_sec += seconds_since_epoch; 1537 tp->tv_sec = TheISA::htog(tp->tv_sec); 1538 tp->tv_usec = TheISA::htog(tp->tv_usec); 1539 1540 tp.copyOut(tc->getMemProxy()); 1541 1542 return 0; 1543} 1544 1545 1546/// Target utimes() handler. 1547template <class OS> 1548SyscallReturn 1549utimesFunc(SyscallDesc *desc, int callnum, Process *process, 1550 ThreadContext *tc) 1551{ 1552 std::string path; 1553 1554 int index = 0; 1555 if (!tc->getMemProxy().tryReadString(path, 1556 process->getSyscallArg(tc, index))) { 1557 return -EFAULT; 1558 } 1559 1560 TypedBufferArg<typename OS::timeval [2]> 1561 tp(process->getSyscallArg(tc, index)); 1562 tp.copyIn(tc->getMemProxy()); 1563 1564 struct timeval hostTimeval[2]; 1565 for (int i = 0; i < 2; ++i) 1566 { 1567 hostTimeval[i].tv_sec = TheISA::gtoh((*tp)[i].tv_sec); 1568 hostTimeval[i].tv_usec = TheISA::gtoh((*tp)[i].tv_usec); 1569 } 1570 1571 // Adjust path for current working directory 1572 path = process->fullPath(path); 1573 1574 int result = utimes(path.c_str(), hostTimeval); 1575 1576 if (result < 0) 1577 return -errno; 1578 1579 return 0; 1580} 1581/// Target getrusage() function. 1582template <class OS> 1583SyscallReturn 1584getrusageFunc(SyscallDesc *desc, int callnum, Process *process, 1585 ThreadContext *tc) 1586{ 1587 int index = 0; 1588 int who = process->getSyscallArg(tc, index); // THREAD, SELF, or CHILDREN 1589 TypedBufferArg<typename OS::rusage> rup(process->getSyscallArg(tc, index)); 1590 1591 rup->ru_utime.tv_sec = 0; 1592 rup->ru_utime.tv_usec = 0; 1593 rup->ru_stime.tv_sec = 0; 1594 rup->ru_stime.tv_usec = 0; 1595 rup->ru_maxrss = 0; 1596 rup->ru_ixrss = 0; 1597 rup->ru_idrss = 0; 1598 rup->ru_isrss = 0; 1599 rup->ru_minflt = 0; 1600 rup->ru_majflt = 0; 1601 rup->ru_nswap = 0; 1602 rup->ru_inblock = 0; 1603 rup->ru_oublock = 0; 1604 rup->ru_msgsnd = 0; 1605 rup->ru_msgrcv = 0; 1606 rup->ru_nsignals = 0; 1607 rup->ru_nvcsw = 0; 1608 rup->ru_nivcsw = 0; 1609 1610 switch (who) { 1611 case OS::TGT_RUSAGE_SELF: 1612 getElapsedTimeMicro(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec); 1613 rup->ru_utime.tv_sec = TheISA::htog(rup->ru_utime.tv_sec); 1614 rup->ru_utime.tv_usec = TheISA::htog(rup->ru_utime.tv_usec); 1615 break; 1616 1617 case OS::TGT_RUSAGE_CHILDREN: 1618 // do nothing. We have no child processes, so they take no time. 1619 break; 1620 1621 default: 1622 // don't really handle THREAD or CHILDREN, but just warn and 1623 // plow ahead 1624 warn("getrusage() only supports RUSAGE_SELF. Parameter %d ignored.", 1625 who); 1626 } 1627 1628 rup.copyOut(tc->getMemProxy()); 1629 1630 return 0; 1631} 1632 1633/// Target times() function. 1634template <class OS> 1635SyscallReturn 1636timesFunc(SyscallDesc *desc, int callnum, Process *process, 1637 ThreadContext *tc) 1638{ 1639 int index = 0; 1640 TypedBufferArg<typename OS::tms> bufp(process->getSyscallArg(tc, index)); 1641 1642 // Fill in the time structure (in clocks) 1643 int64_t clocks = curTick() * OS::M5_SC_CLK_TCK / SimClock::Int::s; 1644 bufp->tms_utime = clocks; 1645 bufp->tms_stime = 0; 1646 bufp->tms_cutime = 0; 1647 bufp->tms_cstime = 0; 1648 1649 // Convert to host endianness 1650 bufp->tms_utime = TheISA::htog(bufp->tms_utime); 1651 1652 // Write back 1653 bufp.copyOut(tc->getMemProxy()); 1654 1655 // Return clock ticks since system boot 1656 return clocks; 1657} 1658 1659/// Target time() function. 1660template <class OS> 1661SyscallReturn 1662timeFunc(SyscallDesc *desc, int callnum, Process *process, ThreadContext *tc) 1663{ 1664 typename OS::time_t sec, usec; 1665 getElapsedTimeMicro(sec, usec); 1666 sec += seconds_since_epoch; 1667 1668 int index = 0; 1669 Addr taddr = (Addr)process->getSyscallArg(tc, index); 1670 if (taddr != 0) { 1671 typename OS::time_t t = sec; 1672 t = TheISA::htog(t); 1673 SETranslatingPortProxy &p = tc->getMemProxy(); 1674 p.writeBlob(taddr, (uint8_t*)&t, (int)sizeof(typename OS::time_t)); 1675 } 1676 return sec; 1677} 1678 1679 1680#endif // __SIM_SYSCALL_EMUL_HH__ 1681