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