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