syscall_emul.hh revision 7678
1/* 2 * Copyright (c) 2003-2005 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Authors: Steve Reinhardt 29 * Kevin Lim 30 */ 31 32#ifndef __SIM_SYSCALL_EMUL_HH__ 33#define __SIM_SYSCALL_EMUL_HH__ 34 35#define NO_STAT64 (defined(__APPLE__) || defined(__OpenBSD__) || \ 36 defined(__FreeBSD__) || defined(__CYGWIN__)) 37 38/// 39/// @file syscall_emul.hh 40/// 41/// This file defines objects used to emulate syscalls from the target 42/// application on the host machine. 43 44#ifdef __CYGWIN32__ 45#include <sys/fcntl.h> // for O_BINARY 46#endif 47#include <sys/stat.h> 48#include <errno.h> 49#include <fcntl.h> 50#include <sys/uio.h> 51#include <sys/time.h> 52 53#include <string> 54 55#include "base/chunk_generator.hh" 56#include "base/intmath.hh" // for RoundUp 57#include "base/misc.hh" 58#include "base/trace.hh" 59#include "base/types.hh" 60#include "config/the_isa.hh" 61#include "cpu/base.hh" 62#include "cpu/thread_context.hh" 63#include "mem/translating_port.hh" 64#include "mem/page_table.hh" 65#include "sim/byteswap.hh" 66#include "sim/system.hh" 67#include "sim/process.hh" 68 69/// 70/// System call descriptor. 71/// 72class SyscallDesc { 73 74 public: 75 76 /// Typedef for target syscall handler functions. 77 typedef SyscallReturn (*FuncPtr)(SyscallDesc *, int num, 78 LiveProcess *, ThreadContext *); 79 80 const char *name; //!< Syscall name (e.g., "open"). 81 FuncPtr funcPtr; //!< Pointer to emulation function. 82 int flags; //!< Flags (see Flags enum). 83 84 /// Flag values for controlling syscall behavior. 85 enum Flags { 86 /// Don't set return regs according to funcPtr return value. 87 /// Used for syscalls with non-standard return conventions 88 /// that explicitly set the ThreadContext regs (e.g., 89 /// sigreturn). 90 SuppressReturnValue = 1 91 }; 92 93 /// Constructor. 94 SyscallDesc(const char *_name, FuncPtr _funcPtr, int _flags = 0) 95 : name(_name), funcPtr(_funcPtr), flags(_flags) 96 { 97 } 98 99 /// Emulate the syscall. Public interface for calling through funcPtr. 100 void doSyscall(int callnum, LiveProcess *proc, ThreadContext *tc); 101}; 102 103 104class BaseBufferArg { 105 106 public: 107 108 BaseBufferArg(Addr _addr, int _size) : addr(_addr), size(_size) 109 { 110 bufPtr = new uint8_t[size]; 111 // clear out buffer: in case we only partially populate this, 112 // and then do a copyOut(), we want to make sure we don't 113 // introduce any random junk into the simulated address space 114 memset(bufPtr, 0, size); 115 } 116 117 virtual ~BaseBufferArg() { delete [] bufPtr; } 118 119 // 120 // copy data into simulator space (read from target memory) 121 // 122 virtual bool copyIn(TranslatingPort *memport) 123 { 124 memport->readBlob(addr, bufPtr, size); 125 return true; // no EFAULT detection for now 126 } 127 128 // 129 // copy data out of simulator space (write to target memory) 130 // 131 virtual bool copyOut(TranslatingPort *memport) 132 { 133 memport->writeBlob(addr, bufPtr, size); 134 return true; // no EFAULT detection for now 135 } 136 137 protected: 138 Addr addr; 139 int size; 140 uint8_t *bufPtr; 141}; 142 143 144class BufferArg : public BaseBufferArg 145{ 146 public: 147 BufferArg(Addr _addr, int _size) : BaseBufferArg(_addr, _size) { } 148 void *bufferPtr() { return bufPtr; } 149}; 150 151template <class T> 152class TypedBufferArg : public BaseBufferArg 153{ 154 public: 155 // user can optionally specify a specific number of bytes to 156 // allocate to deal with those structs that have variable-size 157 // arrays at the end 158 TypedBufferArg(Addr _addr, int _size = sizeof(T)) 159 : BaseBufferArg(_addr, _size) 160 { } 161 162 // type case 163 operator T*() { return (T *)bufPtr; } 164 165 // dereference operators 166 T &operator*() { return *((T *)bufPtr); } 167 T* operator->() { return (T *)bufPtr; } 168 T &operator[](int i) { return ((T *)bufPtr)[i]; } 169}; 170 171////////////////////////////////////////////////////////////////////// 172// 173// The following emulation functions are generic enough that they 174// don't need to be recompiled for different emulated OS's. They are 175// defined in sim/syscall_emul.cc. 176// 177////////////////////////////////////////////////////////////////////// 178 179 180/// Handler for unimplemented syscalls that we haven't thought about. 181SyscallReturn unimplementedFunc(SyscallDesc *desc, int num, 182 LiveProcess *p, ThreadContext *tc); 183 184/// Handler for unimplemented syscalls that we never intend to 185/// implement (signal handling, etc.) and should not affect the correct 186/// behavior of the program. Print a warning only if the appropriate 187/// trace flag is enabled. Return success to the target program. 188SyscallReturn ignoreFunc(SyscallDesc *desc, int num, 189 LiveProcess *p, ThreadContext *tc); 190 191/// Target exit() handler: terminate current context. 192SyscallReturn exitFunc(SyscallDesc *desc, int num, 193 LiveProcess *p, ThreadContext *tc); 194 195/// Target exit_group() handler: terminate simulation. (exit all threads) 196SyscallReturn exitGroupFunc(SyscallDesc *desc, int num, 197 LiveProcess *p, ThreadContext *tc); 198 199/// Target getpagesize() handler. 200SyscallReturn getpagesizeFunc(SyscallDesc *desc, int num, 201 LiveProcess *p, ThreadContext *tc); 202 203/// Target brk() handler: set brk address. 204SyscallReturn brkFunc(SyscallDesc *desc, int num, 205 LiveProcess *p, ThreadContext *tc); 206 207/// Target close() handler. 208SyscallReturn closeFunc(SyscallDesc *desc, int num, 209 LiveProcess *p, ThreadContext *tc); 210 211/// Target read() handler. 212SyscallReturn readFunc(SyscallDesc *desc, int num, 213 LiveProcess *p, ThreadContext *tc); 214 215/// Target write() handler. 216SyscallReturn writeFunc(SyscallDesc *desc, int num, 217 LiveProcess *p, ThreadContext *tc); 218 219/// Target lseek() handler. 220SyscallReturn lseekFunc(SyscallDesc *desc, int num, 221 LiveProcess *p, ThreadContext *tc); 222 223/// Target _llseek() handler. 224SyscallReturn _llseekFunc(SyscallDesc *desc, int num, 225 LiveProcess *p, ThreadContext *tc); 226 227/// Target munmap() handler. 228SyscallReturn munmapFunc(SyscallDesc *desc, int num, 229 LiveProcess *p, ThreadContext *tc); 230 231/// Target gethostname() handler. 232SyscallReturn gethostnameFunc(SyscallDesc *desc, int num, 233 LiveProcess *p, ThreadContext *tc); 234 235/// Target getcwd() handler. 236SyscallReturn getcwdFunc(SyscallDesc *desc, int num, 237 LiveProcess *p, ThreadContext *tc); 238 239/// Target unlink() handler. 240SyscallReturn readlinkFunc(SyscallDesc *desc, int num, 241 LiveProcess *p, ThreadContext *tc); 242 243/// Target unlink() handler. 244SyscallReturn unlinkFunc(SyscallDesc *desc, int num, 245 LiveProcess *p, ThreadContext *tc); 246 247/// Target mkdir() handler. 248SyscallReturn mkdirFunc(SyscallDesc *desc, int num, 249 LiveProcess *p, ThreadContext *tc); 250 251/// Target rename() handler. 252SyscallReturn renameFunc(SyscallDesc *desc, int num, 253 LiveProcess *p, ThreadContext *tc); 254 255 256/// Target truncate() handler. 257SyscallReturn truncateFunc(SyscallDesc *desc, int num, 258 LiveProcess *p, ThreadContext *tc); 259 260 261/// Target ftruncate() handler. 262SyscallReturn ftruncateFunc(SyscallDesc *desc, int num, 263 LiveProcess *p, ThreadContext *tc); 264 265 266/// Target truncate64() handler. 267SyscallReturn truncate64Func(SyscallDesc *desc, int num, 268 LiveProcess *p, ThreadContext *tc); 269 270/// Target ftruncate64() handler. 271SyscallReturn ftruncate64Func(SyscallDesc *desc, int num, 272 LiveProcess *p, ThreadContext *tc); 273 274 275/// Target umask() handler. 276SyscallReturn umaskFunc(SyscallDesc *desc, int num, 277 LiveProcess *p, ThreadContext *tc); 278 279 280/// Target chown() handler. 281SyscallReturn chownFunc(SyscallDesc *desc, int num, 282 LiveProcess *p, ThreadContext *tc); 283 284 285/// Target fchown() handler. 286SyscallReturn fchownFunc(SyscallDesc *desc, int num, 287 LiveProcess *p, ThreadContext *tc); 288 289/// Target dup() handler. 290SyscallReturn dupFunc(SyscallDesc *desc, int num, 291 LiveProcess *process, ThreadContext *tc); 292 293/// Target fnctl() handler. 294SyscallReturn fcntlFunc(SyscallDesc *desc, int num, 295 LiveProcess *process, ThreadContext *tc); 296 297/// Target fcntl64() handler. 298SyscallReturn fcntl64Func(SyscallDesc *desc, int num, 299 LiveProcess *process, ThreadContext *tc); 300 301/// Target setuid() handler. 302SyscallReturn setuidFunc(SyscallDesc *desc, int num, 303 LiveProcess *p, ThreadContext *tc); 304 305/// Target getpid() handler. 306SyscallReturn getpidFunc(SyscallDesc *desc, int num, 307 LiveProcess *p, ThreadContext *tc); 308 309/// Target getuid() handler. 310SyscallReturn getuidFunc(SyscallDesc *desc, int num, 311 LiveProcess *p, ThreadContext *tc); 312 313/// Target getgid() handler. 314SyscallReturn getgidFunc(SyscallDesc *desc, int num, 315 LiveProcess *p, ThreadContext *tc); 316 317/// Target getppid() handler. 318SyscallReturn getppidFunc(SyscallDesc *desc, int num, 319 LiveProcess *p, ThreadContext *tc); 320 321/// Target geteuid() handler. 322SyscallReturn geteuidFunc(SyscallDesc *desc, int num, 323 LiveProcess *p, ThreadContext *tc); 324 325/// Target getegid() handler. 326SyscallReturn getegidFunc(SyscallDesc *desc, int num, 327 LiveProcess *p, ThreadContext *tc); 328 329/// Target clone() handler. 330SyscallReturn cloneFunc(SyscallDesc *desc, int num, 331 LiveProcess *p, ThreadContext *tc); 332 333 334/// Pseudo Funcs - These functions use a different return convension, 335/// returning a second value in a register other than the normal return register 336SyscallReturn pipePseudoFunc(SyscallDesc *desc, int num, 337 LiveProcess *process, ThreadContext *tc); 338 339/// Target getpidPseudo() handler. 340SyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num, 341 LiveProcess *p, ThreadContext *tc); 342 343/// Target getuidPseudo() handler. 344SyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num, 345 LiveProcess *p, ThreadContext *tc); 346 347/// Target getgidPseudo() handler. 348SyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num, 349 LiveProcess *p, ThreadContext *tc); 350 351 352/// A readable name for 1,000,000, for converting microseconds to seconds. 353const int one_million = 1000000; 354 355/// Approximate seconds since the epoch (1/1/1970). About a billion, 356/// by my reckoning. We want to keep this a constant (not use the 357/// real-world time) to keep simulations repeatable. 358const unsigned seconds_since_epoch = 1000000000; 359 360/// Helper function to convert current elapsed time to seconds and 361/// microseconds. 362template <class T1, class T2> 363void 364getElapsedTime(T1 &sec, T2 &usec) 365{ 366 int elapsed_usecs = curTick / SimClock::Int::us; 367 sec = elapsed_usecs / one_million; 368 usec = elapsed_usecs % one_million; 369} 370 371////////////////////////////////////////////////////////////////////// 372// 373// The following emulation functions are generic, but need to be 374// templated to account for differences in types, constants, etc. 375// 376////////////////////////////////////////////////////////////////////// 377 378#if NO_STAT64 379 typedef struct stat hst_stat; 380 typedef struct stat hst_stat64; 381#else 382 typedef struct stat hst_stat; 383 typedef struct stat64 hst_stat64; 384#endif 385 386//// Helper function to convert a host stat buffer to a target stat 387//// buffer. Also copies the target buffer out to the simulated 388//// memory space. Used by stat(), fstat(), and lstat(). 389 390template <typename target_stat, typename host_stat> 391static void 392convertStatBuf(target_stat &tgt, host_stat *host, bool fakeTTY = false) 393{ 394 using namespace TheISA; 395 396 if (fakeTTY) 397 tgt->st_dev = 0xA; 398 else 399 tgt->st_dev = host->st_dev; 400 tgt->st_dev = htog(tgt->st_dev); 401 tgt->st_ino = host->st_ino; 402 tgt->st_ino = htog(tgt->st_ino); 403 tgt->st_mode = host->st_mode; 404 if (fakeTTY) { 405 // Claim to be a character device 406 tgt->st_mode &= ~S_IFMT; // Clear S_IFMT 407 tgt->st_mode |= S_IFCHR; // Set S_IFCHR 408 } 409 tgt->st_mode = htog(tgt->st_mode); 410 tgt->st_nlink = host->st_nlink; 411 tgt->st_nlink = htog(tgt->st_nlink); 412 tgt->st_uid = host->st_uid; 413 tgt->st_uid = htog(tgt->st_uid); 414 tgt->st_gid = host->st_gid; 415 tgt->st_gid = htog(tgt->st_gid); 416 if (fakeTTY) 417 tgt->st_rdev = 0x880d; 418 else 419 tgt->st_rdev = host->st_rdev; 420 tgt->st_rdev = htog(tgt->st_rdev); 421 tgt->st_size = host->st_size; 422 tgt->st_size = htog(tgt->st_size); 423 tgt->st_atimeX = host->st_atime; 424 tgt->st_atimeX = htog(tgt->st_atimeX); 425 tgt->st_mtimeX = host->st_mtime; 426 tgt->st_mtimeX = htog(tgt->st_mtimeX); 427 tgt->st_ctimeX = host->st_ctime; 428 tgt->st_ctimeX = htog(tgt->st_ctimeX); 429 // Force the block size to be 8k. This helps to ensure buffered io works 430 // consistently across different hosts. 431 tgt->st_blksize = 0x2000; 432 tgt->st_blksize = htog(tgt->st_blksize); 433 tgt->st_blocks = host->st_blocks; 434 tgt->st_blocks = htog(tgt->st_blocks); 435} 436 437// Same for stat64 438 439template <typename target_stat, typename host_stat64> 440static void 441convertStat64Buf(target_stat &tgt, host_stat64 *host, bool fakeTTY = false) 442{ 443 using namespace TheISA; 444 445 convertStatBuf<target_stat, host_stat64>(tgt, host, fakeTTY); 446#if defined(STAT_HAVE_NSEC) 447 tgt->st_atime_nsec = host->st_atime_nsec; 448 tgt->st_atime_nsec = htog(tgt->st_atime_nsec); 449 tgt->st_mtime_nsec = host->st_mtime_nsec; 450 tgt->st_mtime_nsec = htog(tgt->st_mtime_nsec); 451 tgt->st_ctime_nsec = host->st_ctime_nsec; 452 tgt->st_ctime_nsec = htog(tgt->st_ctime_nsec); 453#else 454 tgt->st_atime_nsec = 0; 455 tgt->st_mtime_nsec = 0; 456 tgt->st_ctime_nsec = 0; 457#endif 458} 459 460//Here are a couple convenience functions 461template<class OS> 462static void 463copyOutStatBuf(TranslatingPort * mem, Addr addr, 464 hst_stat *host, bool fakeTTY = false) 465{ 466 typedef TypedBufferArg<typename OS::tgt_stat> tgt_stat_buf; 467 tgt_stat_buf tgt(addr); 468 convertStatBuf<tgt_stat_buf, hst_stat>(tgt, host, fakeTTY); 469 tgt.copyOut(mem); 470} 471 472template<class OS> 473static void 474copyOutStat64Buf(TranslatingPort * mem, Addr addr, 475 hst_stat64 *host, bool fakeTTY = false) 476{ 477 typedef TypedBufferArg<typename OS::tgt_stat64> tgt_stat_buf; 478 tgt_stat_buf tgt(addr); 479 convertStat64Buf<tgt_stat_buf, hst_stat64>(tgt, host, fakeTTY); 480 tgt.copyOut(mem); 481} 482 483/// Target ioctl() handler. For the most part, programs call ioctl() 484/// only to find out if their stdout is a tty, to determine whether to 485/// do line or block buffering. 486template <class OS> 487SyscallReturn 488ioctlFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 489 ThreadContext *tc) 490{ 491 int index = 0; 492 int fd = process->getSyscallArg(tc, index); 493 unsigned req = process->getSyscallArg(tc, index); 494 495 DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", fd, req); 496 497 if (fd < 0 || process->sim_fd(fd) < 0) { 498 // doesn't map to any simulator fd: not a valid target fd 499 return -EBADF; 500 } 501 502 switch (req) { 503 case OS::TIOCISATTY_: 504 case OS::TIOCGETP_: 505 case OS::TIOCSETP_: 506 case OS::TIOCSETN_: 507 case OS::TIOCSETC_: 508 case OS::TIOCGETC_: 509 case OS::TIOCGETS_: 510 case OS::TIOCGETA_: 511 case OS::TCSETAW_: 512 return -ENOTTY; 513 514 default: 515 fatal("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ 0x%llx\n", 516 fd, req, tc->readPC()); 517 } 518} 519 520/// Target open() handler. 521template <class OS> 522SyscallReturn 523openFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 524 ThreadContext *tc) 525{ 526 std::string path; 527 528 int index = 0; 529 if (!tc->getMemPort()->tryReadString(path, 530 process->getSyscallArg(tc, index))) 531 return -EFAULT; 532 533 if (path == "/dev/sysdev0") { 534 // This is a memory-mapped high-resolution timer device on Alpha. 535 // We don't support it, so just punt. 536 warn("Ignoring open(%s, ...)\n", path); 537 return -ENOENT; 538 } 539 540 int tgtFlags = process->getSyscallArg(tc, index); 541 int mode = process->getSyscallArg(tc, index); 542 int hostFlags = 0; 543 544 // translate open flags 545 for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) { 546 if (tgtFlags & OS::openFlagTable[i].tgtFlag) { 547 tgtFlags &= ~OS::openFlagTable[i].tgtFlag; 548 hostFlags |= OS::openFlagTable[i].hostFlag; 549 } 550 } 551 552 // any target flags left? 553 if (tgtFlags != 0) 554 warn("Syscall: open: cannot decode flags 0x%x", tgtFlags); 555 556#ifdef __CYGWIN32__ 557 hostFlags |= O_BINARY; 558#endif 559 560 // Adjust path for current working directory 561 path = process->fullPath(path); 562 563 DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str()); 564 565 int fd; 566 if (!path.compare(0, 6, "/proc/") || !path.compare(0, 8, "/system/") || 567 !path.compare(0, 10, "/platform/") || !path.compare(0, 5, "/sys/")) { 568 // It's a proc/sys entery and requires special handling 569 fd = OS::openSpecialFile(path, process, tc); 570 return (fd == -1) ? -1 : process->alloc_fd(fd,path.c_str(),hostFlags,mode, false); 571 } else { 572 // open the file 573 fd = open(path.c_str(), hostFlags, mode); 574 return (fd == -1) ? -errno : process->alloc_fd(fd,path.c_str(),hostFlags,mode, false); 575 } 576 577} 578 579/// Target sysinfo() handler. 580template <class OS> 581SyscallReturn 582sysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 583 ThreadContext *tc) 584{ 585 586 int index = 0; 587 TypedBufferArg<typename OS::tgt_sysinfo> 588 sysinfo(process->getSyscallArg(tc, index)); 589 590 sysinfo->uptime=seconds_since_epoch; 591 sysinfo->totalram=process->system->memSize(); 592 593 sysinfo.copyOut(tc->getMemPort()); 594 595 return 0; 596} 597 598/// Target chmod() handler. 599template <class OS> 600SyscallReturn 601chmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 602 ThreadContext *tc) 603{ 604 std::string path; 605 606 int index = 0; 607 if (!tc->getMemPort()->tryReadString(path, 608 process->getSyscallArg(tc, index))) { 609 return -EFAULT; 610 } 611 612 uint32_t mode = process->getSyscallArg(tc, index); 613 mode_t hostMode = 0; 614 615 // XXX translate mode flags via OS::something??? 616 hostMode = mode; 617 618 // Adjust path for current working directory 619 path = process->fullPath(path); 620 621 // do the chmod 622 int result = chmod(path.c_str(), hostMode); 623 if (result < 0) 624 return -errno; 625 626 return 0; 627} 628 629 630/// Target fchmod() handler. 631template <class OS> 632SyscallReturn 633fchmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 634 ThreadContext *tc) 635{ 636 int index = 0; 637 int fd = process->getSyscallArg(tc, index); 638 if (fd < 0 || process->sim_fd(fd) < 0) { 639 // doesn't map to any simulator fd: not a valid target fd 640 return -EBADF; 641 } 642 643 uint32_t mode = process->getSyscallArg(tc, index); 644 mode_t hostMode = 0; 645 646 // XXX translate mode flags via OS::someting??? 647 hostMode = mode; 648 649 // do the fchmod 650 int result = fchmod(process->sim_fd(fd), hostMode); 651 if (result < 0) 652 return -errno; 653 654 return 0; 655} 656 657/// Target mremap() handler. 658template <class OS> 659SyscallReturn 660mremapFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) 661{ 662 int index = 0; 663 Addr start = process->getSyscallArg(tc, index); 664 uint64_t old_length = process->getSyscallArg(tc, index); 665 uint64_t new_length = process->getSyscallArg(tc, index); 666 uint64_t flags = process->getSyscallArg(tc, index); 667 668 if ((start % TheISA::VMPageSize != 0) || 669 (new_length % TheISA::VMPageSize != 0)) { 670 warn("mremap failing: arguments not page aligned"); 671 return -EINVAL; 672 } 673 674 if (new_length > old_length) { 675 if ((start + old_length) == process->mmap_end) { 676 uint64_t diff = new_length - old_length; 677 process->pTable->allocate(process->mmap_end, diff); 678 process->mmap_end += diff; 679 return start; 680 } else { 681 // sys/mman.h defined MREMAP_MAYMOVE 682 if (!(flags & 1)) { 683 warn("can't remap here and MREMAP_MAYMOVE flag not set\n"); 684 return -ENOMEM; 685 } else { 686 process->pTable->remap(start, old_length, process->mmap_end); 687 warn("mremapping to totally new vaddr %08p-%08p, adding %d\n", 688 process->mmap_end, process->mmap_end + new_length, new_length); 689 start = process->mmap_end; 690 // add on the remaining unallocated pages 691 process->pTable->allocate(start + old_length, new_length - old_length); 692 process->mmap_end += new_length; 693 warn("returning %08p as start\n", start); 694 return start; 695 } 696 } 697 } else { 698 process->pTable->deallocate(start + new_length, old_length - 699 new_length); 700 return start; 701 } 702} 703 704/// Target stat() handler. 705template <class OS> 706SyscallReturn 707statFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 708 ThreadContext *tc) 709{ 710 std::string path; 711 712 int index = 0; 713 if (!tc->getMemPort()->tryReadString(path, 714 process->getSyscallArg(tc, index))) { 715 return -EFAULT; 716 } 717 Addr bufPtr = process->getSyscallArg(tc, index); 718 719 // Adjust path for current working directory 720 path = process->fullPath(path); 721 722 struct stat hostBuf; 723 int result = stat(path.c_str(), &hostBuf); 724 725 if (result < 0) 726 return -errno; 727 728 copyOutStatBuf<OS>(tc->getMemPort(), bufPtr, &hostBuf); 729 730 return 0; 731} 732 733 734/// Target stat64() handler. 735template <class OS> 736SyscallReturn 737stat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 738 ThreadContext *tc) 739{ 740 std::string path; 741 742 int index = 0; 743 if (!tc->getMemPort()->tryReadString(path, 744 process->getSyscallArg(tc, index))) 745 return -EFAULT; 746 Addr bufPtr = process->getSyscallArg(tc, index); 747 748 // Adjust path for current working directory 749 path = process->fullPath(path); 750 751#if NO_STAT64 752 struct stat hostBuf; 753 int result = stat(path.c_str(), &hostBuf); 754#else 755 struct stat64 hostBuf; 756 int result = stat64(path.c_str(), &hostBuf); 757#endif 758 759 if (result < 0) 760 return -errno; 761 762 copyOutStat64Buf<OS>(tc->getMemPort(), bufPtr, &hostBuf); 763 764 return 0; 765} 766 767 768/// Target fstat64() handler. 769template <class OS> 770SyscallReturn 771fstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 772 ThreadContext *tc) 773{ 774 int index = 0; 775 int fd = process->getSyscallArg(tc, index); 776 Addr bufPtr = process->getSyscallArg(tc, index); 777 if (fd < 0 || process->sim_fd(fd) < 0) { 778 // doesn't map to any simulator fd: not a valid target fd 779 return -EBADF; 780 } 781 782#if NO_STAT64 783 struct stat hostBuf; 784 int result = fstat(process->sim_fd(fd), &hostBuf); 785#else 786 struct stat64 hostBuf; 787 int result = fstat64(process->sim_fd(fd), &hostBuf); 788#endif 789 790 if (result < 0) 791 return -errno; 792 793 copyOutStat64Buf<OS>(tc->getMemPort(), bufPtr, &hostBuf, (fd == 1)); 794 795 return 0; 796} 797 798 799/// Target lstat() handler. 800template <class OS> 801SyscallReturn 802lstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 803 ThreadContext *tc) 804{ 805 std::string path; 806 807 int index = 0; 808 if (!tc->getMemPort()->tryReadString(path, 809 process->getSyscallArg(tc, index))) { 810 return -EFAULT; 811 } 812 Addr bufPtr = process->getSyscallArg(tc, index); 813 814 // Adjust path for current working directory 815 path = process->fullPath(path); 816 817 struct stat hostBuf; 818 int result = lstat(path.c_str(), &hostBuf); 819 820 if (result < 0) 821 return -errno; 822 823 copyOutStatBuf<OS>(tc->getMemPort(), bufPtr, &hostBuf); 824 825 return 0; 826} 827 828/// Target lstat64() handler. 829template <class OS> 830SyscallReturn 831lstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 832 ThreadContext *tc) 833{ 834 std::string path; 835 836 int index = 0; 837 if (!tc->getMemPort()->tryReadString(path, 838 process->getSyscallArg(tc, index))) { 839 return -EFAULT; 840 } 841 Addr bufPtr = process->getSyscallArg(tc, index); 842 843 // Adjust path for current working directory 844 path = process->fullPath(path); 845 846#if NO_STAT64 847 struct stat hostBuf; 848 int result = lstat(path.c_str(), &hostBuf); 849#else 850 struct stat64 hostBuf; 851 int result = lstat64(path.c_str(), &hostBuf); 852#endif 853 854 if (result < 0) 855 return -errno; 856 857 copyOutStat64Buf<OS>(tc->getMemPort(), bufPtr, &hostBuf); 858 859 return 0; 860} 861 862/// Target fstat() handler. 863template <class OS> 864SyscallReturn 865fstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 866 ThreadContext *tc) 867{ 868 int index = 0; 869 int fd = process->sim_fd(process->getSyscallArg(tc, index)); 870 Addr bufPtr = process->getSyscallArg(tc, index); 871 872 DPRINTF(SyscallVerbose, "fstat(%d, ...)\n", fd); 873 874 if (fd < 0) 875 return -EBADF; 876 877 struct stat hostBuf; 878 int result = fstat(fd, &hostBuf); 879 880 if (result < 0) 881 return -errno; 882 883 copyOutStatBuf<OS>(tc->getMemPort(), bufPtr, &hostBuf, (fd == 1)); 884 885 return 0; 886} 887 888 889/// Target statfs() handler. 890template <class OS> 891SyscallReturn 892statfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 893 ThreadContext *tc) 894{ 895 std::string path; 896 897 int index = 0; 898 if (!tc->getMemPort()->tryReadString(path, 899 process->getSyscallArg(tc, index))) { 900 return -EFAULT; 901 } 902 Addr bufPtr = process->getSyscallArg(tc, index); 903 904 // Adjust path for current working directory 905 path = process->fullPath(path); 906 907 struct statfs hostBuf; 908 int result = statfs(path.c_str(), &hostBuf); 909 910 if (result < 0) 911 return -errno; 912 913 OS::copyOutStatfsBuf(tc->getMemPort(), bufPtr, &hostBuf); 914 915 return 0; 916} 917 918 919/// Target fstatfs() handler. 920template <class OS> 921SyscallReturn 922fstatfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 923 ThreadContext *tc) 924{ 925 int index = 0; 926 int fd = process->sim_fd(process->getSyscallArg(tc, index)); 927 Addr bufPtr = process->getSyscallArg(tc, index); 928 929 if (fd < 0) 930 return -EBADF; 931 932 struct statfs hostBuf; 933 int result = fstatfs(fd, &hostBuf); 934 935 if (result < 0) 936 return -errno; 937 938 OS::copyOutStatfsBuf(tc->getMemPort(), bufPtr, &hostBuf); 939 940 return 0; 941} 942 943 944/// Target writev() handler. 945template <class OS> 946SyscallReturn 947writevFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 948 ThreadContext *tc) 949{ 950 int index = 0; 951 int fd = process->getSyscallArg(tc, index); 952 if (fd < 0 || process->sim_fd(fd) < 0) { 953 // doesn't map to any simulator fd: not a valid target fd 954 return -EBADF; 955 } 956 957 TranslatingPort *p = tc->getMemPort(); 958 uint64_t tiov_base = process->getSyscallArg(tc, index); 959 size_t count = process->getSyscallArg(tc, index); 960 struct iovec hiov[count]; 961 for (size_t i = 0; i < count; ++i) { 962 typename OS::tgt_iovec tiov; 963 964 p->readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec), 965 (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec)); 966 hiov[i].iov_len = gtoh(tiov.iov_len); 967 hiov[i].iov_base = new char [hiov[i].iov_len]; 968 p->readBlob(gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base, 969 hiov[i].iov_len); 970 } 971 972 int result = writev(process->sim_fd(fd), hiov, count); 973 974 for (size_t i = 0; i < count; ++i) 975 delete [] (char *)hiov[i].iov_base; 976 977 if (result < 0) 978 return -errno; 979 980 return 0; 981} 982 983 984/// Target mmap() handler. 985/// 986/// We don't really handle mmap(). If the target is mmaping an 987/// anonymous region or /dev/zero, we can get away with doing basically 988/// nothing (since memory is initialized to zero and the simulator 989/// doesn't really check addresses anyway). Always print a warning, 990/// since this could be seriously broken if we're not mapping 991/// /dev/zero. 992// 993/// Someday we should explicitly check for /dev/zero in open, flag the 994/// file descriptor, and fail (or implement!) a non-anonymous mmap to 995/// anything else. 996template <class OS> 997SyscallReturn 998mmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 999{ 1000 int index = 0; 1001 Addr start = p->getSyscallArg(tc, index); 1002 uint64_t length = p->getSyscallArg(tc, index); 1003 index++; // int prot = p->getSyscallArg(tc, index); 1004 int flags = p->getSyscallArg(tc, index); 1005 int fd = p->sim_fd(p->getSyscallArg(tc, index)); 1006 // int offset = p->getSyscallArg(tc, index); 1007 1008 1009 if ((start % TheISA::VMPageSize) != 0 || 1010 (length % TheISA::VMPageSize) != 0) { 1011 warn("mmap failing: arguments not page-aligned: " 1012 "start 0x%x length 0x%x", 1013 start, length); 1014 return -EINVAL; 1015 } 1016 1017 if (start != 0) { 1018 warn("mmap: ignoring suggested map address 0x%x, using 0x%x", 1019 start, p->mmap_end); 1020 } 1021 1022 // pick next address from our "mmap region" 1023 if (OS::mmapGrowsDown()) { 1024 start = p->mmap_end - length; 1025 p->mmap_end = start; 1026 } else { 1027 start = p->mmap_end; 1028 p->mmap_end += length; 1029 } 1030 p->pTable->allocate(start, length); 1031 1032 if (!(flags & OS::TGT_MAP_ANONYMOUS)) { 1033 warn("allowing mmap of file @ fd %d. " 1034 "This will break if not /dev/zero.", fd); 1035 } 1036 1037 return start; 1038} 1039 1040/// Target getrlimit() handler. 1041template <class OS> 1042SyscallReturn 1043getrlimitFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1044 ThreadContext *tc) 1045{ 1046 int index = 0; 1047 unsigned resource = process->getSyscallArg(tc, index); 1048 TypedBufferArg<typename OS::rlimit> rlp(process->getSyscallArg(tc, index)); 1049 1050 switch (resource) { 1051 case OS::TGT_RLIMIT_STACK: 1052 // max stack size in bytes: make up a number (8MB for now) 1053 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; 1054 rlp->rlim_cur = htog(rlp->rlim_cur); 1055 rlp->rlim_max = htog(rlp->rlim_max); 1056 break; 1057 1058 case OS::TGT_RLIMIT_DATA: 1059 // max data segment size in bytes: make up a number 1060 rlp->rlim_cur = rlp->rlim_max = 256 * 1024 * 1024; 1061 rlp->rlim_cur = htog(rlp->rlim_cur); 1062 rlp->rlim_max = htog(rlp->rlim_max); 1063 break; 1064 1065 default: 1066 std::cerr << "getrlimitFunc: unimplemented resource " << resource 1067 << std::endl; 1068 abort(); 1069 break; 1070 } 1071 1072 rlp.copyOut(tc->getMemPort()); 1073 return 0; 1074} 1075 1076/// Target gettimeofday() handler. 1077template <class OS> 1078SyscallReturn 1079gettimeofdayFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1080 ThreadContext *tc) 1081{ 1082 int index = 0; 1083 TypedBufferArg<typename OS::timeval> tp(process->getSyscallArg(tc, index)); 1084 1085 getElapsedTime(tp->tv_sec, tp->tv_usec); 1086 tp->tv_sec += seconds_since_epoch; 1087 tp->tv_sec = TheISA::htog(tp->tv_sec); 1088 tp->tv_usec = TheISA::htog(tp->tv_usec); 1089 1090 tp.copyOut(tc->getMemPort()); 1091 1092 return 0; 1093} 1094 1095 1096/// Target utimes() handler. 1097template <class OS> 1098SyscallReturn 1099utimesFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1100 ThreadContext *tc) 1101{ 1102 std::string path; 1103 1104 int index = 0; 1105 if (!tc->getMemPort()->tryReadString(path, 1106 process->getSyscallArg(tc, index))) { 1107 return -EFAULT; 1108 } 1109 1110 TypedBufferArg<typename OS::timeval [2]> 1111 tp(process->getSyscallArg(tc, index)); 1112 tp.copyIn(tc->getMemPort()); 1113 1114 struct timeval hostTimeval[2]; 1115 for (int i = 0; i < 2; ++i) 1116 { 1117 hostTimeval[i].tv_sec = gtoh((*tp)[i].tv_sec); 1118 hostTimeval[i].tv_usec = gtoh((*tp)[i].tv_usec); 1119 } 1120 1121 // Adjust path for current working directory 1122 path = process->fullPath(path); 1123 1124 int result = utimes(path.c_str(), hostTimeval); 1125 1126 if (result < 0) 1127 return -errno; 1128 1129 return 0; 1130} 1131/// Target getrusage() function. 1132template <class OS> 1133SyscallReturn 1134getrusageFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1135 ThreadContext *tc) 1136{ 1137 int index = 0; 1138 int who = process->getSyscallArg(tc, index); // THREAD, SELF, or CHILDREN 1139 TypedBufferArg<typename OS::rusage> rup(process->getSyscallArg(tc, index)); 1140 1141 rup->ru_utime.tv_sec = 0; 1142 rup->ru_utime.tv_usec = 0; 1143 rup->ru_stime.tv_sec = 0; 1144 rup->ru_stime.tv_usec = 0; 1145 rup->ru_maxrss = 0; 1146 rup->ru_ixrss = 0; 1147 rup->ru_idrss = 0; 1148 rup->ru_isrss = 0; 1149 rup->ru_minflt = 0; 1150 rup->ru_majflt = 0; 1151 rup->ru_nswap = 0; 1152 rup->ru_inblock = 0; 1153 rup->ru_oublock = 0; 1154 rup->ru_msgsnd = 0; 1155 rup->ru_msgrcv = 0; 1156 rup->ru_nsignals = 0; 1157 rup->ru_nvcsw = 0; 1158 rup->ru_nivcsw = 0; 1159 1160 switch (who) { 1161 case OS::TGT_RUSAGE_SELF: 1162 getElapsedTime(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec); 1163 rup->ru_utime.tv_sec = htog(rup->ru_utime.tv_sec); 1164 rup->ru_utime.tv_usec = htog(rup->ru_utime.tv_usec); 1165 break; 1166 1167 case OS::TGT_RUSAGE_CHILDREN: 1168 // do nothing. We have no child processes, so they take no time. 1169 break; 1170 1171 default: 1172 // don't really handle THREAD or CHILDREN, but just warn and 1173 // plow ahead 1174 warn("getrusage() only supports RUSAGE_SELF. Parameter %d ignored.", 1175 who); 1176 } 1177 1178 rup.copyOut(tc->getMemPort()); 1179 1180 return 0; 1181} 1182 1183/// Target times() function. 1184template <class OS> 1185SyscallReturn 1186timesFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1187 ThreadContext *tc) 1188{ 1189 int index = 0; 1190 TypedBufferArg<typename OS::tms> bufp(process->getSyscallArg(tc, index)); 1191 1192 // Fill in the time structure (in clocks) 1193 int64_t clocks = curTick * OS::M5_SC_CLK_TCK / SimClock::Int::s; 1194 bufp->tms_utime = clocks; 1195 bufp->tms_stime = 0; 1196 bufp->tms_cutime = 0; 1197 bufp->tms_cstime = 0; 1198 1199 // Convert to host endianness 1200 bufp->tms_utime = htog(bufp->tms_utime); 1201 1202 // Write back 1203 bufp.copyOut(tc->getMemPort()); 1204 1205 // Return clock ticks since system boot 1206 return clocks; 1207} 1208 1209/// Target time() function. 1210template <class OS> 1211SyscallReturn 1212timeFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1213 ThreadContext *tc) 1214{ 1215 typename OS::time_t sec, usec; 1216 getElapsedTime(sec, usec); 1217 sec += seconds_since_epoch; 1218 1219 int index = 0; 1220 Addr taddr = (Addr)process->getSyscallArg(tc, index); 1221 if(taddr != 0) { 1222 typename OS::time_t t = sec; 1223 t = htog(t); 1224 TranslatingPort *p = tc->getMemPort(); 1225 p->writeBlob(taddr, (uint8_t*)&t, (int)sizeof(typename OS::time_t)); 1226 } 1227 return sec; 1228} 1229 1230 1231#endif // __SIM_SYSCALL_EMUL_HH__ 1232