syscall_emul.hh revision 8149
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); 190SyscallReturn ignoreWarnOnceFunc(SyscallDesc *desc, int num, 191 LiveProcess *p, ThreadContext *tc); 192 193/// Target exit() handler: terminate current context. 194SyscallReturn exitFunc(SyscallDesc *desc, int num, 195 LiveProcess *p, ThreadContext *tc); 196 197/// Target exit_group() handler: terminate simulation. (exit all threads) 198SyscallReturn exitGroupFunc(SyscallDesc *desc, int num, 199 LiveProcess *p, ThreadContext *tc); 200 201/// Target getpagesize() handler. 202SyscallReturn getpagesizeFunc(SyscallDesc *desc, int num, 203 LiveProcess *p, ThreadContext *tc); 204 205/// Target brk() handler: set brk address. 206SyscallReturn brkFunc(SyscallDesc *desc, int num, 207 LiveProcess *p, ThreadContext *tc); 208 209/// Target close() handler. 210SyscallReturn closeFunc(SyscallDesc *desc, int num, 211 LiveProcess *p, ThreadContext *tc); 212 213/// Target read() handler. 214SyscallReturn readFunc(SyscallDesc *desc, int num, 215 LiveProcess *p, ThreadContext *tc); 216 217/// Target write() handler. 218SyscallReturn writeFunc(SyscallDesc *desc, int num, 219 LiveProcess *p, ThreadContext *tc); 220 221/// Target lseek() handler. 222SyscallReturn lseekFunc(SyscallDesc *desc, int num, 223 LiveProcess *p, ThreadContext *tc); 224 225/// Target _llseek() handler. 226SyscallReturn _llseekFunc(SyscallDesc *desc, int num, 227 LiveProcess *p, ThreadContext *tc); 228 229/// Target munmap() handler. 230SyscallReturn munmapFunc(SyscallDesc *desc, int num, 231 LiveProcess *p, ThreadContext *tc); 232 233/// Target gethostname() handler. 234SyscallReturn gethostnameFunc(SyscallDesc *desc, int num, 235 LiveProcess *p, ThreadContext *tc); 236 237/// Target getcwd() handler. 238SyscallReturn getcwdFunc(SyscallDesc *desc, int num, 239 LiveProcess *p, ThreadContext *tc); 240 241/// Target unlink() handler. 242SyscallReturn readlinkFunc(SyscallDesc *desc, int num, 243 LiveProcess *p, ThreadContext *tc); 244 245/// Target unlink() handler. 246SyscallReturn unlinkFunc(SyscallDesc *desc, int num, 247 LiveProcess *p, ThreadContext *tc); 248 249/// Target mkdir() handler. 250SyscallReturn mkdirFunc(SyscallDesc *desc, int num, 251 LiveProcess *p, ThreadContext *tc); 252 253/// Target rename() handler. 254SyscallReturn renameFunc(SyscallDesc *desc, int num, 255 LiveProcess *p, ThreadContext *tc); 256 257 258/// Target truncate() handler. 259SyscallReturn truncateFunc(SyscallDesc *desc, int num, 260 LiveProcess *p, ThreadContext *tc); 261 262 263/// Target ftruncate() handler. 264SyscallReturn ftruncateFunc(SyscallDesc *desc, int num, 265 LiveProcess *p, ThreadContext *tc); 266 267 268/// Target truncate64() handler. 269SyscallReturn truncate64Func(SyscallDesc *desc, int num, 270 LiveProcess *p, ThreadContext *tc); 271 272/// Target ftruncate64() handler. 273SyscallReturn ftruncate64Func(SyscallDesc *desc, int num, 274 LiveProcess *p, ThreadContext *tc); 275 276 277/// Target umask() handler. 278SyscallReturn umaskFunc(SyscallDesc *desc, int num, 279 LiveProcess *p, ThreadContext *tc); 280 281 282/// Target chown() handler. 283SyscallReturn chownFunc(SyscallDesc *desc, int num, 284 LiveProcess *p, ThreadContext *tc); 285 286 287/// Target fchown() handler. 288SyscallReturn fchownFunc(SyscallDesc *desc, int num, 289 LiveProcess *p, ThreadContext *tc); 290 291/// Target dup() handler. 292SyscallReturn dupFunc(SyscallDesc *desc, int num, 293 LiveProcess *process, ThreadContext *tc); 294 295/// Target fnctl() handler. 296SyscallReturn fcntlFunc(SyscallDesc *desc, int num, 297 LiveProcess *process, ThreadContext *tc); 298 299/// Target fcntl64() handler. 300SyscallReturn fcntl64Func(SyscallDesc *desc, int num, 301 LiveProcess *process, ThreadContext *tc); 302 303/// Target setuid() handler. 304SyscallReturn setuidFunc(SyscallDesc *desc, int num, 305 LiveProcess *p, ThreadContext *tc); 306 307/// Target getpid() handler. 308SyscallReturn getpidFunc(SyscallDesc *desc, int num, 309 LiveProcess *p, ThreadContext *tc); 310 311/// Target getuid() handler. 312SyscallReturn getuidFunc(SyscallDesc *desc, int num, 313 LiveProcess *p, ThreadContext *tc); 314 315/// Target getgid() handler. 316SyscallReturn getgidFunc(SyscallDesc *desc, int num, 317 LiveProcess *p, ThreadContext *tc); 318 319/// Target getppid() handler. 320SyscallReturn getppidFunc(SyscallDesc *desc, int num, 321 LiveProcess *p, ThreadContext *tc); 322 323/// Target geteuid() handler. 324SyscallReturn geteuidFunc(SyscallDesc *desc, int num, 325 LiveProcess *p, ThreadContext *tc); 326 327/// Target getegid() handler. 328SyscallReturn getegidFunc(SyscallDesc *desc, int num, 329 LiveProcess *p, ThreadContext *tc); 330 331/// Target clone() handler. 332SyscallReturn cloneFunc(SyscallDesc *desc, int num, 333 LiveProcess *p, ThreadContext *tc); 334 335 336/// Pseudo Funcs - These functions use a different return convension, 337/// returning a second value in a register other than the normal return register 338SyscallReturn pipePseudoFunc(SyscallDesc *desc, int num, 339 LiveProcess *process, ThreadContext *tc); 340 341/// Target getpidPseudo() handler. 342SyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num, 343 LiveProcess *p, ThreadContext *tc); 344 345/// Target getuidPseudo() handler. 346SyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num, 347 LiveProcess *p, ThreadContext *tc); 348 349/// Target getgidPseudo() handler. 350SyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num, 351 LiveProcess *p, ThreadContext *tc); 352 353 354/// A readable name for 1,000,000, for converting microseconds to seconds. 355const int one_million = 1000000; 356 357/// Approximate seconds since the epoch (1/1/1970). About a billion, 358/// by my reckoning. We want to keep this a constant (not use the 359/// real-world time) to keep simulations repeatable. 360const unsigned seconds_since_epoch = 1000000000; 361 362/// Helper function to convert current elapsed time to seconds and 363/// microseconds. 364template <class T1, class T2> 365void 366getElapsedTime(T1 &sec, T2 &usec) 367{ 368 int elapsed_usecs = curTick() / SimClock::Int::us; 369 sec = elapsed_usecs / one_million; 370 usec = elapsed_usecs % one_million; 371} 372 373////////////////////////////////////////////////////////////////////// 374// 375// The following emulation functions are generic, but need to be 376// templated to account for differences in types, constants, etc. 377// 378////////////////////////////////////////////////////////////////////// 379 380#if NO_STAT64 381 typedef struct stat hst_stat; 382 typedef struct stat hst_stat64; 383#else 384 typedef struct stat hst_stat; 385 typedef struct stat64 hst_stat64; 386#endif 387 388//// Helper function to convert a host stat buffer to a target stat 389//// buffer. Also copies the target buffer out to the simulated 390//// memory space. Used by stat(), fstat(), and lstat(). 391 392template <typename target_stat, typename host_stat> 393static void 394convertStatBuf(target_stat &tgt, host_stat *host, bool fakeTTY = false) 395{ 396 using namespace TheISA; 397 398 if (fakeTTY) 399 tgt->st_dev = 0xA; 400 else 401 tgt->st_dev = host->st_dev; 402 tgt->st_dev = htog(tgt->st_dev); 403 tgt->st_ino = host->st_ino; 404 tgt->st_ino = htog(tgt->st_ino); 405 tgt->st_mode = host->st_mode; 406 if (fakeTTY) { 407 // Claim to be a character device 408 tgt->st_mode &= ~S_IFMT; // Clear S_IFMT 409 tgt->st_mode |= S_IFCHR; // Set S_IFCHR 410 } 411 tgt->st_mode = htog(tgt->st_mode); 412 tgt->st_nlink = host->st_nlink; 413 tgt->st_nlink = htog(tgt->st_nlink); 414 tgt->st_uid = host->st_uid; 415 tgt->st_uid = htog(tgt->st_uid); 416 tgt->st_gid = host->st_gid; 417 tgt->st_gid = htog(tgt->st_gid); 418 if (fakeTTY) 419 tgt->st_rdev = 0x880d; 420 else 421 tgt->st_rdev = host->st_rdev; 422 tgt->st_rdev = htog(tgt->st_rdev); 423 tgt->st_size = host->st_size; 424 tgt->st_size = htog(tgt->st_size); 425 tgt->st_atimeX = host->st_atime; 426 tgt->st_atimeX = htog(tgt->st_atimeX); 427 tgt->st_mtimeX = host->st_mtime; 428 tgt->st_mtimeX = htog(tgt->st_mtimeX); 429 tgt->st_ctimeX = host->st_ctime; 430 tgt->st_ctimeX = htog(tgt->st_ctimeX); 431 // Force the block size to be 8k. This helps to ensure buffered io works 432 // consistently across different hosts. 433 tgt->st_blksize = 0x2000; 434 tgt->st_blksize = htog(tgt->st_blksize); 435 tgt->st_blocks = host->st_blocks; 436 tgt->st_blocks = htog(tgt->st_blocks); 437} 438 439// Same for stat64 440 441template <typename target_stat, typename host_stat64> 442static void 443convertStat64Buf(target_stat &tgt, host_stat64 *host, bool fakeTTY = false) 444{ 445 using namespace TheISA; 446 447 convertStatBuf<target_stat, host_stat64>(tgt, host, fakeTTY); 448#if defined(STAT_HAVE_NSEC) 449 tgt->st_atime_nsec = host->st_atime_nsec; 450 tgt->st_atime_nsec = htog(tgt->st_atime_nsec); 451 tgt->st_mtime_nsec = host->st_mtime_nsec; 452 tgt->st_mtime_nsec = htog(tgt->st_mtime_nsec); 453 tgt->st_ctime_nsec = host->st_ctime_nsec; 454 tgt->st_ctime_nsec = htog(tgt->st_ctime_nsec); 455#else 456 tgt->st_atime_nsec = 0; 457 tgt->st_mtime_nsec = 0; 458 tgt->st_ctime_nsec = 0; 459#endif 460} 461 462//Here are a couple convenience functions 463template<class OS> 464static void 465copyOutStatBuf(TranslatingPort * mem, Addr addr, 466 hst_stat *host, bool fakeTTY = false) 467{ 468 typedef TypedBufferArg<typename OS::tgt_stat> tgt_stat_buf; 469 tgt_stat_buf tgt(addr); 470 convertStatBuf<tgt_stat_buf, hst_stat>(tgt, host, fakeTTY); 471 tgt.copyOut(mem); 472} 473 474template<class OS> 475static void 476copyOutStat64Buf(TranslatingPort * mem, Addr addr, 477 hst_stat64 *host, bool fakeTTY = false) 478{ 479 typedef TypedBufferArg<typename OS::tgt_stat64> tgt_stat_buf; 480 tgt_stat_buf tgt(addr); 481 convertStat64Buf<tgt_stat_buf, hst_stat64>(tgt, host, fakeTTY); 482 tgt.copyOut(mem); 483} 484 485/// Target ioctl() handler. For the most part, programs call ioctl() 486/// only to find out if their stdout is a tty, to determine whether to 487/// do line or block buffering. 488template <class OS> 489SyscallReturn 490ioctlFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 491 ThreadContext *tc) 492{ 493 int index = 0; 494 int fd = process->getSyscallArg(tc, index); 495 unsigned req = process->getSyscallArg(tc, index); 496 497 DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", fd, req); 498 499 if (fd < 0 || process->sim_fd(fd) < 0) { 500 // doesn't map to any simulator fd: not a valid target fd 501 return -EBADF; 502 } 503 504 switch (req) { 505 case OS::TIOCISATTY_: 506 case OS::TIOCGETP_: 507 case OS::TIOCSETP_: 508 case OS::TIOCSETN_: 509 case OS::TIOCSETC_: 510 case OS::TIOCGETC_: 511 case OS::TIOCGETS_: 512 case OS::TIOCGETA_: 513 case OS::TCSETAW_: 514 return -ENOTTY; 515 516 default: 517 fatal("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ \n", 518 fd, req, tc->pcState()); 519 } 520} 521 522/// Target open() handler. 523template <class OS> 524SyscallReturn 525openFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 526 ThreadContext *tc) 527{ 528 std::string path; 529 530 int index = 0; 531 if (!tc->getMemPort()->tryReadString(path, 532 process->getSyscallArg(tc, index))) 533 return -EFAULT; 534 535 if (path == "/dev/sysdev0") { 536 // This is a memory-mapped high-resolution timer device on Alpha. 537 // We don't support it, so just punt. 538 warn("Ignoring open(%s, ...)\n", path); 539 return -ENOENT; 540 } 541 542 int tgtFlags = process->getSyscallArg(tc, index); 543 int mode = process->getSyscallArg(tc, index); 544 int hostFlags = 0; 545 546 // translate open flags 547 for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) { 548 if (tgtFlags & OS::openFlagTable[i].tgtFlag) { 549 tgtFlags &= ~OS::openFlagTable[i].tgtFlag; 550 hostFlags |= OS::openFlagTable[i].hostFlag; 551 } 552 } 553 554 // any target flags left? 555 if (tgtFlags != 0) 556 warn("Syscall: open: cannot decode flags 0x%x", tgtFlags); 557 558#ifdef __CYGWIN32__ 559 hostFlags |= O_BINARY; 560#endif 561 562 // Adjust path for current working directory 563 path = process->fullPath(path); 564 565 DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str()); 566 567 int fd; 568 if (!path.compare(0, 6, "/proc/") || !path.compare(0, 8, "/system/") || 569 !path.compare(0, 10, "/platform/") || !path.compare(0, 5, "/sys/")) { 570 // It's a proc/sys entery and requires special handling 571 fd = OS::openSpecialFile(path, process, tc); 572 return (fd == -1) ? -1 : process->alloc_fd(fd,path.c_str(),hostFlags,mode, false); 573 } else { 574 // open the file 575 fd = open(path.c_str(), hostFlags, mode); 576 return (fd == -1) ? -errno : process->alloc_fd(fd,path.c_str(),hostFlags,mode, false); 577 } 578 579} 580 581/// Target sysinfo() handler. 582template <class OS> 583SyscallReturn 584sysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 585 ThreadContext *tc) 586{ 587 588 int index = 0; 589 TypedBufferArg<typename OS::tgt_sysinfo> 590 sysinfo(process->getSyscallArg(tc, index)); 591 592 sysinfo->uptime=seconds_since_epoch; 593 sysinfo->totalram=process->system->memSize(); 594 595 sysinfo.copyOut(tc->getMemPort()); 596 597 return 0; 598} 599 600/// Target chmod() handler. 601template <class OS> 602SyscallReturn 603chmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 604 ThreadContext *tc) 605{ 606 std::string path; 607 608 int index = 0; 609 if (!tc->getMemPort()->tryReadString(path, 610 process->getSyscallArg(tc, index))) { 611 return -EFAULT; 612 } 613 614 uint32_t mode = process->getSyscallArg(tc, index); 615 mode_t hostMode = 0; 616 617 // XXX translate mode flags via OS::something??? 618 hostMode = mode; 619 620 // Adjust path for current working directory 621 path = process->fullPath(path); 622 623 // do the chmod 624 int result = chmod(path.c_str(), hostMode); 625 if (result < 0) 626 return -errno; 627 628 return 0; 629} 630 631 632/// Target fchmod() handler. 633template <class OS> 634SyscallReturn 635fchmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 636 ThreadContext *tc) 637{ 638 int index = 0; 639 int fd = process->getSyscallArg(tc, index); 640 if (fd < 0 || process->sim_fd(fd) < 0) { 641 // doesn't map to any simulator fd: not a valid target fd 642 return -EBADF; 643 } 644 645 uint32_t mode = process->getSyscallArg(tc, index); 646 mode_t hostMode = 0; 647 648 // XXX translate mode flags via OS::someting??? 649 hostMode = mode; 650 651 // do the fchmod 652 int result = fchmod(process->sim_fd(fd), hostMode); 653 if (result < 0) 654 return -errno; 655 656 return 0; 657} 658 659/// Target mremap() handler. 660template <class OS> 661SyscallReturn 662mremapFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) 663{ 664 int index = 0; 665 Addr start = process->getSyscallArg(tc, index); 666 uint64_t old_length = process->getSyscallArg(tc, index); 667 uint64_t new_length = process->getSyscallArg(tc, index); 668 uint64_t flags = process->getSyscallArg(tc, index); 669 670 if ((start % TheISA::VMPageSize != 0) || 671 (new_length % TheISA::VMPageSize != 0)) { 672 warn("mremap failing: arguments not page aligned"); 673 return -EINVAL; 674 } 675 676 if (new_length > old_length) { 677 if ((start + old_length) == process->mmap_end) { 678 uint64_t diff = new_length - old_length; 679 process->pTable->allocate(process->mmap_end, diff); 680 process->mmap_end += diff; 681 return start; 682 } else { 683 // sys/mman.h defined MREMAP_MAYMOVE 684 if (!(flags & 1)) { 685 warn("can't remap here and MREMAP_MAYMOVE flag not set\n"); 686 return -ENOMEM; 687 } else { 688 process->pTable->remap(start, old_length, process->mmap_end); 689 warn("mremapping to totally new vaddr %08p-%08p, adding %d\n", 690 process->mmap_end, process->mmap_end + new_length, new_length); 691 start = process->mmap_end; 692 // add on the remaining unallocated pages 693 process->pTable->allocate(start + old_length, new_length - old_length); 694 process->mmap_end += new_length; 695 warn("returning %08p as start\n", start); 696 return start; 697 } 698 } 699 } else { 700 process->pTable->deallocate(start + new_length, old_length - 701 new_length); 702 return start; 703 } 704} 705 706/// Target stat() handler. 707template <class OS> 708SyscallReturn 709statFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 710 ThreadContext *tc) 711{ 712 std::string path; 713 714 int index = 0; 715 if (!tc->getMemPort()->tryReadString(path, 716 process->getSyscallArg(tc, index))) { 717 return -EFAULT; 718 } 719 Addr bufPtr = process->getSyscallArg(tc, index); 720 721 // Adjust path for current working directory 722 path = process->fullPath(path); 723 724 struct stat hostBuf; 725 int result = stat(path.c_str(), &hostBuf); 726 727 if (result < 0) 728 return -errno; 729 730 copyOutStatBuf<OS>(tc->getMemPort(), bufPtr, &hostBuf); 731 732 return 0; 733} 734 735 736/// Target stat64() handler. 737template <class OS> 738SyscallReturn 739stat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 740 ThreadContext *tc) 741{ 742 std::string path; 743 744 int index = 0; 745 if (!tc->getMemPort()->tryReadString(path, 746 process->getSyscallArg(tc, index))) 747 return -EFAULT; 748 Addr bufPtr = process->getSyscallArg(tc, index); 749 750 // Adjust path for current working directory 751 path = process->fullPath(path); 752 753#if NO_STAT64 754 struct stat hostBuf; 755 int result = stat(path.c_str(), &hostBuf); 756#else 757 struct stat64 hostBuf; 758 int result = stat64(path.c_str(), &hostBuf); 759#endif 760 761 if (result < 0) 762 return -errno; 763 764 copyOutStat64Buf<OS>(tc->getMemPort(), bufPtr, &hostBuf); 765 766 return 0; 767} 768 769 770/// Target fstat64() handler. 771template <class OS> 772SyscallReturn 773fstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 774 ThreadContext *tc) 775{ 776 int index = 0; 777 int fd = process->getSyscallArg(tc, index); 778 Addr bufPtr = process->getSyscallArg(tc, index); 779 if (fd < 0 || process->sim_fd(fd) < 0) { 780 // doesn't map to any simulator fd: not a valid target fd 781 return -EBADF; 782 } 783 784#if NO_STAT64 785 struct stat hostBuf; 786 int result = fstat(process->sim_fd(fd), &hostBuf); 787#else 788 struct stat64 hostBuf; 789 int result = fstat64(process->sim_fd(fd), &hostBuf); 790#endif 791 792 if (result < 0) 793 return -errno; 794 795 copyOutStat64Buf<OS>(tc->getMemPort(), bufPtr, &hostBuf, (fd == 1)); 796 797 return 0; 798} 799 800 801/// Target lstat() handler. 802template <class OS> 803SyscallReturn 804lstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 805 ThreadContext *tc) 806{ 807 std::string path; 808 809 int index = 0; 810 if (!tc->getMemPort()->tryReadString(path, 811 process->getSyscallArg(tc, index))) { 812 return -EFAULT; 813 } 814 Addr bufPtr = process->getSyscallArg(tc, index); 815 816 // Adjust path for current working directory 817 path = process->fullPath(path); 818 819 struct stat hostBuf; 820 int result = lstat(path.c_str(), &hostBuf); 821 822 if (result < 0) 823 return -errno; 824 825 copyOutStatBuf<OS>(tc->getMemPort(), bufPtr, &hostBuf); 826 827 return 0; 828} 829 830/// Target lstat64() handler. 831template <class OS> 832SyscallReturn 833lstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 834 ThreadContext *tc) 835{ 836 std::string path; 837 838 int index = 0; 839 if (!tc->getMemPort()->tryReadString(path, 840 process->getSyscallArg(tc, index))) { 841 return -EFAULT; 842 } 843 Addr bufPtr = process->getSyscallArg(tc, index); 844 845 // Adjust path for current working directory 846 path = process->fullPath(path); 847 848#if NO_STAT64 849 struct stat hostBuf; 850 int result = lstat(path.c_str(), &hostBuf); 851#else 852 struct stat64 hostBuf; 853 int result = lstat64(path.c_str(), &hostBuf); 854#endif 855 856 if (result < 0) 857 return -errno; 858 859 copyOutStat64Buf<OS>(tc->getMemPort(), bufPtr, &hostBuf); 860 861 return 0; 862} 863 864/// Target fstat() handler. 865template <class OS> 866SyscallReturn 867fstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 868 ThreadContext *tc) 869{ 870 int index = 0; 871 int fd = process->sim_fd(process->getSyscallArg(tc, index)); 872 Addr bufPtr = process->getSyscallArg(tc, index); 873 874 DPRINTF(SyscallVerbose, "fstat(%d, ...)\n", fd); 875 876 if (fd < 0) 877 return -EBADF; 878 879 struct stat hostBuf; 880 int result = fstat(fd, &hostBuf); 881 882 if (result < 0) 883 return -errno; 884 885 copyOutStatBuf<OS>(tc->getMemPort(), bufPtr, &hostBuf, (fd == 1)); 886 887 return 0; 888} 889 890 891/// Target statfs() handler. 892template <class OS> 893SyscallReturn 894statfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 895 ThreadContext *tc) 896{ 897 std::string path; 898 899 int index = 0; 900 if (!tc->getMemPort()->tryReadString(path, 901 process->getSyscallArg(tc, index))) { 902 return -EFAULT; 903 } 904 Addr bufPtr = process->getSyscallArg(tc, index); 905 906 // Adjust path for current working directory 907 path = process->fullPath(path); 908 909 struct statfs hostBuf; 910 int result = statfs(path.c_str(), &hostBuf); 911 912 if (result < 0) 913 return -errno; 914 915 OS::copyOutStatfsBuf(tc->getMemPort(), bufPtr, &hostBuf); 916 917 return 0; 918} 919 920 921/// Target fstatfs() handler. 922template <class OS> 923SyscallReturn 924fstatfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 925 ThreadContext *tc) 926{ 927 int index = 0; 928 int fd = process->sim_fd(process->getSyscallArg(tc, index)); 929 Addr bufPtr = process->getSyscallArg(tc, index); 930 931 if (fd < 0) 932 return -EBADF; 933 934 struct statfs hostBuf; 935 int result = fstatfs(fd, &hostBuf); 936 937 if (result < 0) 938 return -errno; 939 940 OS::copyOutStatfsBuf(tc->getMemPort(), bufPtr, &hostBuf); 941 942 return 0; 943} 944 945 946/// Target writev() handler. 947template <class OS> 948SyscallReturn 949writevFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 950 ThreadContext *tc) 951{ 952 int index = 0; 953 int fd = process->getSyscallArg(tc, index); 954 if (fd < 0 || process->sim_fd(fd) < 0) { 955 // doesn't map to any simulator fd: not a valid target fd 956 return -EBADF; 957 } 958 959 TranslatingPort *p = tc->getMemPort(); 960 uint64_t tiov_base = process->getSyscallArg(tc, index); 961 size_t count = process->getSyscallArg(tc, index); 962 struct iovec hiov[count]; 963 for (size_t i = 0; i < count; ++i) { 964 typename OS::tgt_iovec tiov; 965 966 p->readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec), 967 (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec)); 968 hiov[i].iov_len = gtoh(tiov.iov_len); 969 hiov[i].iov_base = new char [hiov[i].iov_len]; 970 p->readBlob(gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base, 971 hiov[i].iov_len); 972 } 973 974 int result = writev(process->sim_fd(fd), hiov, count); 975 976 for (size_t i = 0; i < count; ++i) 977 delete [] (char *)hiov[i].iov_base; 978 979 if (result < 0) 980 return -errno; 981 982 return 0; 983} 984 985 986/// Target mmap() handler. 987/// 988/// We don't really handle mmap(). If the target is mmaping an 989/// anonymous region or /dev/zero, we can get away with doing basically 990/// nothing (since memory is initialized to zero and the simulator 991/// doesn't really check addresses anyway). Always print a warning, 992/// since this could be seriously broken if we're not mapping 993/// /dev/zero. 994// 995/// Someday we should explicitly check for /dev/zero in open, flag the 996/// file descriptor, and fail (or implement!) a non-anonymous mmap to 997/// anything else. 998template <class OS> 999SyscallReturn 1000mmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 1001{ 1002 int index = 0; 1003 Addr start = p->getSyscallArg(tc, index); 1004 uint64_t length = p->getSyscallArg(tc, index); 1005 index++; // int prot = p->getSyscallArg(tc, index); 1006 int flags = p->getSyscallArg(tc, index); 1007 int fd = p->sim_fd(p->getSyscallArg(tc, index)); 1008 // int offset = p->getSyscallArg(tc, index); 1009 1010 1011 if ((start % TheISA::VMPageSize) != 0 || 1012 (length % TheISA::VMPageSize) != 0) { 1013 warn("mmap failing: arguments not page-aligned: " 1014 "start 0x%x length 0x%x", 1015 start, length); 1016 return -EINVAL; 1017 } 1018 1019 if (start != 0) { 1020 warn("mmap: ignoring suggested map address 0x%x, using 0x%x", 1021 start, p->mmap_end); 1022 } 1023 1024 // pick next address from our "mmap region" 1025 if (OS::mmapGrowsDown()) { 1026 start = p->mmap_end - length; 1027 p->mmap_end = start; 1028 } else { 1029 start = p->mmap_end; 1030 p->mmap_end += length; 1031 } 1032 p->pTable->allocate(start, length); 1033 1034 if (!(flags & OS::TGT_MAP_ANONYMOUS)) { 1035 warn("allowing mmap of file @ fd %d. " 1036 "This will break if not /dev/zero.", fd); 1037 } 1038 1039 return start; 1040} 1041 1042/// Target getrlimit() handler. 1043template <class OS> 1044SyscallReturn 1045getrlimitFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1046 ThreadContext *tc) 1047{ 1048 int index = 0; 1049 unsigned resource = process->getSyscallArg(tc, index); 1050 TypedBufferArg<typename OS::rlimit> rlp(process->getSyscallArg(tc, index)); 1051 1052 switch (resource) { 1053 case OS::TGT_RLIMIT_STACK: 1054 // max stack size in bytes: make up a number (8MB for now) 1055 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; 1056 rlp->rlim_cur = htog(rlp->rlim_cur); 1057 rlp->rlim_max = htog(rlp->rlim_max); 1058 break; 1059 1060 case OS::TGT_RLIMIT_DATA: 1061 // max data segment size in bytes: make up a number 1062 rlp->rlim_cur = rlp->rlim_max = 256 * 1024 * 1024; 1063 rlp->rlim_cur = htog(rlp->rlim_cur); 1064 rlp->rlim_max = htog(rlp->rlim_max); 1065 break; 1066 1067 default: 1068 std::cerr << "getrlimitFunc: unimplemented resource " << resource 1069 << std::endl; 1070 abort(); 1071 break; 1072 } 1073 1074 rlp.copyOut(tc->getMemPort()); 1075 return 0; 1076} 1077 1078/// Target gettimeofday() handler. 1079template <class OS> 1080SyscallReturn 1081gettimeofdayFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1082 ThreadContext *tc) 1083{ 1084 int index = 0; 1085 TypedBufferArg<typename OS::timeval> tp(process->getSyscallArg(tc, index)); 1086 1087 getElapsedTime(tp->tv_sec, tp->tv_usec); 1088 tp->tv_sec += seconds_since_epoch; 1089 tp->tv_sec = TheISA::htog(tp->tv_sec); 1090 tp->tv_usec = TheISA::htog(tp->tv_usec); 1091 1092 tp.copyOut(tc->getMemPort()); 1093 1094 return 0; 1095} 1096 1097 1098/// Target utimes() handler. 1099template <class OS> 1100SyscallReturn 1101utimesFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1102 ThreadContext *tc) 1103{ 1104 std::string path; 1105 1106 int index = 0; 1107 if (!tc->getMemPort()->tryReadString(path, 1108 process->getSyscallArg(tc, index))) { 1109 return -EFAULT; 1110 } 1111 1112 TypedBufferArg<typename OS::timeval [2]> 1113 tp(process->getSyscallArg(tc, index)); 1114 tp.copyIn(tc->getMemPort()); 1115 1116 struct timeval hostTimeval[2]; 1117 for (int i = 0; i < 2; ++i) 1118 { 1119 hostTimeval[i].tv_sec = gtoh((*tp)[i].tv_sec); 1120 hostTimeval[i].tv_usec = gtoh((*tp)[i].tv_usec); 1121 } 1122 1123 // Adjust path for current working directory 1124 path = process->fullPath(path); 1125 1126 int result = utimes(path.c_str(), hostTimeval); 1127 1128 if (result < 0) 1129 return -errno; 1130 1131 return 0; 1132} 1133/// Target getrusage() function. 1134template <class OS> 1135SyscallReturn 1136getrusageFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1137 ThreadContext *tc) 1138{ 1139 int index = 0; 1140 int who = process->getSyscallArg(tc, index); // THREAD, SELF, or CHILDREN 1141 TypedBufferArg<typename OS::rusage> rup(process->getSyscallArg(tc, index)); 1142 1143 rup->ru_utime.tv_sec = 0; 1144 rup->ru_utime.tv_usec = 0; 1145 rup->ru_stime.tv_sec = 0; 1146 rup->ru_stime.tv_usec = 0; 1147 rup->ru_maxrss = 0; 1148 rup->ru_ixrss = 0; 1149 rup->ru_idrss = 0; 1150 rup->ru_isrss = 0; 1151 rup->ru_minflt = 0; 1152 rup->ru_majflt = 0; 1153 rup->ru_nswap = 0; 1154 rup->ru_inblock = 0; 1155 rup->ru_oublock = 0; 1156 rup->ru_msgsnd = 0; 1157 rup->ru_msgrcv = 0; 1158 rup->ru_nsignals = 0; 1159 rup->ru_nvcsw = 0; 1160 rup->ru_nivcsw = 0; 1161 1162 switch (who) { 1163 case OS::TGT_RUSAGE_SELF: 1164 getElapsedTime(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec); 1165 rup->ru_utime.tv_sec = htog(rup->ru_utime.tv_sec); 1166 rup->ru_utime.tv_usec = htog(rup->ru_utime.tv_usec); 1167 break; 1168 1169 case OS::TGT_RUSAGE_CHILDREN: 1170 // do nothing. We have no child processes, so they take no time. 1171 break; 1172 1173 default: 1174 // don't really handle THREAD or CHILDREN, but just warn and 1175 // plow ahead 1176 warn("getrusage() only supports RUSAGE_SELF. Parameter %d ignored.", 1177 who); 1178 } 1179 1180 rup.copyOut(tc->getMemPort()); 1181 1182 return 0; 1183} 1184 1185/// Target times() function. 1186template <class OS> 1187SyscallReturn 1188timesFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1189 ThreadContext *tc) 1190{ 1191 int index = 0; 1192 TypedBufferArg<typename OS::tms> bufp(process->getSyscallArg(tc, index)); 1193 1194 // Fill in the time structure (in clocks) 1195 int64_t clocks = curTick() * OS::M5_SC_CLK_TCK / SimClock::Int::s; 1196 bufp->tms_utime = clocks; 1197 bufp->tms_stime = 0; 1198 bufp->tms_cutime = 0; 1199 bufp->tms_cstime = 0; 1200 1201 // Convert to host endianness 1202 bufp->tms_utime = htog(bufp->tms_utime); 1203 1204 // Write back 1205 bufp.copyOut(tc->getMemPort()); 1206 1207 // Return clock ticks since system boot 1208 return clocks; 1209} 1210 1211/// Target time() function. 1212template <class OS> 1213SyscallReturn 1214timeFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1215 ThreadContext *tc) 1216{ 1217 typename OS::time_t sec, usec; 1218 getElapsedTime(sec, usec); 1219 sec += seconds_since_epoch; 1220 1221 int index = 0; 1222 Addr taddr = (Addr)process->getSyscallArg(tc, index); 1223 if(taddr != 0) { 1224 typename OS::time_t t = sec; 1225 t = htog(t); 1226 TranslatingPort *p = tc->getMemPort(); 1227 p->writeBlob(taddr, (uint8_t*)&t, (int)sizeof(typename OS::time_t)); 1228 } 1229 return sec; 1230} 1231 1232 1233#endif // __SIM_SYSCALL_EMUL_HH__ 1234