142 143/// Target exit() handler: terminate current context. 144SyscallReturn exitFunc(SyscallDesc *desc, int num, 145 LiveProcess *p, ThreadContext *tc); 146 147/// Target exit_group() handler: terminate simulation. (exit all threads) 148SyscallReturn exitGroupFunc(SyscallDesc *desc, int num, 149 LiveProcess *p, ThreadContext *tc); 150 151/// Target getpagesize() handler. 152SyscallReturn getpagesizeFunc(SyscallDesc *desc, int num, 153 LiveProcess *p, ThreadContext *tc); 154 155/// Target brk() handler: set brk address. 156SyscallReturn brkFunc(SyscallDesc *desc, int num, 157 LiveProcess *p, ThreadContext *tc); 158 159/// Target close() handler. 160SyscallReturn closeFunc(SyscallDesc *desc, int num, 161 LiveProcess *p, ThreadContext *tc); 162 163/// Target read() handler. 164SyscallReturn readFunc(SyscallDesc *desc, int num, 165 LiveProcess *p, ThreadContext *tc); 166 167/// Target write() handler. 168SyscallReturn writeFunc(SyscallDesc *desc, int num, 169 LiveProcess *p, ThreadContext *tc); 170 171/// Target lseek() handler. 172SyscallReturn lseekFunc(SyscallDesc *desc, int num, 173 LiveProcess *p, ThreadContext *tc); 174 175/// Target _llseek() handler. 176SyscallReturn _llseekFunc(SyscallDesc *desc, int num, 177 LiveProcess *p, ThreadContext *tc); 178 179/// Target munmap() handler. 180SyscallReturn munmapFunc(SyscallDesc *desc, int num, 181 LiveProcess *p, ThreadContext *tc); 182 183/// Target gethostname() handler. 184SyscallReturn gethostnameFunc(SyscallDesc *desc, int num, 185 LiveProcess *p, ThreadContext *tc); 186 187/// Target getcwd() handler. 188SyscallReturn getcwdFunc(SyscallDesc *desc, int num, 189 LiveProcess *p, ThreadContext *tc); 190 191/// Target readlink() handler. 192SyscallReturn readlinkFunc(SyscallDesc *desc, int num, 193 LiveProcess *p, ThreadContext *tc, 194 int index = 0); 195SyscallReturn readlinkFunc(SyscallDesc *desc, int num, 196 LiveProcess *p, ThreadContext *tc); 197 198/// Target unlink() handler. 199SyscallReturn unlinkHelper(SyscallDesc *desc, int num, 200 LiveProcess *p, ThreadContext *tc, 201 int index); 202SyscallReturn unlinkFunc(SyscallDesc *desc, int num, 203 LiveProcess *p, ThreadContext *tc); 204 205/// Target mkdir() handler. 206SyscallReturn mkdirFunc(SyscallDesc *desc, int num, 207 LiveProcess *p, ThreadContext *tc); 208 209/// Target rename() handler. 210SyscallReturn renameFunc(SyscallDesc *desc, int num, 211 LiveProcess *p, ThreadContext *tc); 212 213 214/// Target truncate() handler. 215SyscallReturn truncateFunc(SyscallDesc *desc, int num, 216 LiveProcess *p, ThreadContext *tc); 217 218 219/// Target ftruncate() handler. 220SyscallReturn ftruncateFunc(SyscallDesc *desc, int num, 221 LiveProcess *p, ThreadContext *tc); 222 223 224/// Target truncate64() handler. 225SyscallReturn truncate64Func(SyscallDesc *desc, int num, 226 LiveProcess *p, ThreadContext *tc); 227 228/// Target ftruncate64() handler. 229SyscallReturn ftruncate64Func(SyscallDesc *desc, int num, 230 LiveProcess *p, ThreadContext *tc); 231 232 233/// Target umask() handler. 234SyscallReturn umaskFunc(SyscallDesc *desc, int num, 235 LiveProcess *p, ThreadContext *tc); 236 237 238/// Target chown() handler. 239SyscallReturn chownFunc(SyscallDesc *desc, int num, 240 LiveProcess *p, ThreadContext *tc); 241 242 243/// Target fchown() handler. 244SyscallReturn fchownFunc(SyscallDesc *desc, int num, 245 LiveProcess *p, ThreadContext *tc); 246 247/// Target dup() handler. 248SyscallReturn dupFunc(SyscallDesc *desc, int num, 249 LiveProcess *process, ThreadContext *tc); 250 251/// Target fnctl() handler. 252SyscallReturn fcntlFunc(SyscallDesc *desc, int num, 253 LiveProcess *process, ThreadContext *tc); 254 255/// Target fcntl64() handler. 256SyscallReturn fcntl64Func(SyscallDesc *desc, int num, 257 LiveProcess *process, ThreadContext *tc); 258 259/// Target setuid() handler. 260SyscallReturn setuidFunc(SyscallDesc *desc, int num, 261 LiveProcess *p, ThreadContext *tc); 262 263/// Target getpid() handler. 264SyscallReturn getpidFunc(SyscallDesc *desc, int num, 265 LiveProcess *p, ThreadContext *tc); 266 267/// Target getuid() handler. 268SyscallReturn getuidFunc(SyscallDesc *desc, int num, 269 LiveProcess *p, ThreadContext *tc); 270 271/// Target getgid() handler. 272SyscallReturn getgidFunc(SyscallDesc *desc, int num, 273 LiveProcess *p, ThreadContext *tc); 274 275/// Target getppid() handler. 276SyscallReturn getppidFunc(SyscallDesc *desc, int num, 277 LiveProcess *p, ThreadContext *tc); 278 279/// Target geteuid() handler. 280SyscallReturn geteuidFunc(SyscallDesc *desc, int num, 281 LiveProcess *p, ThreadContext *tc); 282 283/// Target getegid() handler. 284SyscallReturn getegidFunc(SyscallDesc *desc, int num, 285 LiveProcess *p, ThreadContext *tc); 286 287/// Target clone() handler. 288SyscallReturn cloneFunc(SyscallDesc *desc, int num, 289 LiveProcess *p, ThreadContext *tc); 290 291/// Target access() handler 292SyscallReturn accessFunc(SyscallDesc *desc, int num, 293 LiveProcess *p, ThreadContext *tc); 294SyscallReturn accessFunc(SyscallDesc *desc, int num, 295 LiveProcess *p, ThreadContext *tc, 296 int index); 297 298/// Futex system call 299/// Implemented by Daniel Sanchez 300/// Used by printf's in multi-threaded apps 301template <class OS> 302SyscallReturn 303futexFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 304 ThreadContext *tc) 305{ 306 int index_uaddr = 0; 307 int index_op = 1; 308 int index_val = 2; 309 int index_timeout = 3; 310 311 uint64_t uaddr = process->getSyscallArg(tc, index_uaddr); 312 int op = process->getSyscallArg(tc, index_op); 313 int val = process->getSyscallArg(tc, index_val); 314 uint64_t timeout = process->getSyscallArg(tc, index_timeout); 315 316 std::map<uint64_t, std::list<ThreadContext *> * > 317 &futex_map = tc->getSystemPtr()->futexMap; 318 319 DPRINTF(SyscallVerbose, "In sys_futex: Address=%llx, op=%d, val=%d\n", 320 uaddr, op, val); 321 322 op &= ~OS::TGT_FUTEX_PRIVATE_FLAG; 323 324 if (op == OS::TGT_FUTEX_WAIT) { 325 if (timeout != 0) { 326 warn("sys_futex: FUTEX_WAIT with non-null timeout unimplemented;" 327 "we'll wait indefinitely"); 328 } 329 330 uint8_t *buf = new uint8_t[sizeof(int)]; 331 tc->getMemProxy().readBlob((Addr)uaddr, buf, (int)sizeof(int)); 332 int mem_val = *((int *)buf); 333 delete buf; 334 335 if(val != mem_val) { 336 DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAKE, read: %d, " 337 "expected: %d\n", mem_val, val); 338 return -OS::TGT_EWOULDBLOCK; 339 } 340 341 // Queue the thread context 342 std::list<ThreadContext *> * tcWaitList; 343 if (futex_map.count(uaddr)) { 344 tcWaitList = futex_map.find(uaddr)->second; 345 } else { 346 tcWaitList = new std::list<ThreadContext *>(); 347 futex_map.insert(std::pair< uint64_t, 348 std::list<ThreadContext *> * >(uaddr, tcWaitList)); 349 } 350 tcWaitList->push_back(tc); 351 DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAIT, suspending calling " 352 "thread context\n"); 353 tc->suspend(); 354 return 0; 355 } else if (op == OS::TGT_FUTEX_WAKE){ 356 int wokenUp = 0; 357 std::list<ThreadContext *> * tcWaitList; 358 if (futex_map.count(uaddr)) { 359 tcWaitList = futex_map.find(uaddr)->second; 360 while (tcWaitList->size() > 0 && wokenUp < val) { 361 tcWaitList->front()->activate(); 362 tcWaitList->pop_front(); 363 wokenUp++; 364 } 365 if(tcWaitList->empty()) { 366 futex_map.erase(uaddr); 367 delete tcWaitList; 368 } 369 } 370 DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAKE, activated %d waiting " 371 "thread contexts\n", wokenUp); 372 return wokenUp; 373 } else { 374 warn("sys_futex: op %d is not implemented, just returning...", op); 375 return 0; 376 } 377 378} 379 380 381/// Pseudo Funcs - These functions use a different return convension, 382/// returning a second value in a register other than the normal return register 383SyscallReturn pipePseudoFunc(SyscallDesc *desc, int num, 384 LiveProcess *process, ThreadContext *tc); 385 386/// Target getpidPseudo() handler. 387SyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num, 388 LiveProcess *p, ThreadContext *tc); 389 390/// Target getuidPseudo() handler. 391SyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num, 392 LiveProcess *p, ThreadContext *tc); 393 394/// Target getgidPseudo() handler. 395SyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num, 396 LiveProcess *p, ThreadContext *tc); 397 398 399/// A readable name for 1,000,000, for converting microseconds to seconds. 400const int one_million = 1000000; 401/// A readable name for 1,000,000,000, for converting nanoseconds to seconds. 402const int one_billion = 1000000000; 403 404/// Approximate seconds since the epoch (1/1/1970). About a billion, 405/// by my reckoning. We want to keep this a constant (not use the 406/// real-world time) to keep simulations repeatable. 407const unsigned seconds_since_epoch = 1000000000; 408 409/// Helper function to convert current elapsed time to seconds and 410/// microseconds. 411template <class T1, class T2> 412void 413getElapsedTimeMicro(T1 &sec, T2 &usec) 414{ 415 uint64_t elapsed_usecs = curTick() / SimClock::Int::us; 416 sec = elapsed_usecs / one_million; 417 usec = elapsed_usecs % one_million; 418} 419 420/// Helper function to convert current elapsed time to seconds and 421/// nanoseconds. 422template <class T1, class T2> 423void 424getElapsedTimeNano(T1 &sec, T2 &nsec) 425{ 426 uint64_t elapsed_nsecs = curTick() / SimClock::Int::ns; 427 sec = elapsed_nsecs / one_billion; 428 nsec = elapsed_nsecs % one_billion; 429} 430 431////////////////////////////////////////////////////////////////////// 432// 433// The following emulation functions are generic, but need to be 434// templated to account for differences in types, constants, etc. 435// 436////////////////////////////////////////////////////////////////////// 437 438#if NO_STAT64 439 typedef struct stat hst_stat; 440 typedef struct stat hst_stat64; 441#else 442 typedef struct stat hst_stat; 443 typedef struct stat64 hst_stat64; 444#endif 445 446//// Helper function to convert a host stat buffer to a target stat 447//// buffer. Also copies the target buffer out to the simulated 448//// memory space. Used by stat(), fstat(), and lstat(). 449 450template <typename target_stat, typename host_stat> 451static void 452convertStatBuf(target_stat &tgt, host_stat *host, bool fakeTTY = false) 453{ 454 using namespace TheISA; 455 456 if (fakeTTY) 457 tgt->st_dev = 0xA; 458 else 459 tgt->st_dev = host->st_dev; 460 tgt->st_dev = TheISA::htog(tgt->st_dev); 461 tgt->st_ino = host->st_ino; 462 tgt->st_ino = TheISA::htog(tgt->st_ino); 463 tgt->st_mode = host->st_mode; 464 if (fakeTTY) { 465 // Claim to be a character device 466 tgt->st_mode &= ~S_IFMT; // Clear S_IFMT 467 tgt->st_mode |= S_IFCHR; // Set S_IFCHR 468 } 469 tgt->st_mode = TheISA::htog(tgt->st_mode); 470 tgt->st_nlink = host->st_nlink; 471 tgt->st_nlink = TheISA::htog(tgt->st_nlink); 472 tgt->st_uid = host->st_uid; 473 tgt->st_uid = TheISA::htog(tgt->st_uid); 474 tgt->st_gid = host->st_gid; 475 tgt->st_gid = TheISA::htog(tgt->st_gid); 476 if (fakeTTY) 477 tgt->st_rdev = 0x880d; 478 else 479 tgt->st_rdev = host->st_rdev; 480 tgt->st_rdev = TheISA::htog(tgt->st_rdev); 481 tgt->st_size = host->st_size; 482 tgt->st_size = TheISA::htog(tgt->st_size); 483 tgt->st_atimeX = host->st_atime; 484 tgt->st_atimeX = TheISA::htog(tgt->st_atimeX); 485 tgt->st_mtimeX = host->st_mtime; 486 tgt->st_mtimeX = TheISA::htog(tgt->st_mtimeX); 487 tgt->st_ctimeX = host->st_ctime; 488 tgt->st_ctimeX = TheISA::htog(tgt->st_ctimeX); 489 // Force the block size to be 8k. This helps to ensure buffered io works 490 // consistently across different hosts. 491 tgt->st_blksize = 0x2000; 492 tgt->st_blksize = TheISA::htog(tgt->st_blksize); 493 tgt->st_blocks = host->st_blocks; 494 tgt->st_blocks = TheISA::htog(tgt->st_blocks); 495} 496 497// Same for stat64 498 499template <typename target_stat, typename host_stat64> 500static void 501convertStat64Buf(target_stat &tgt, host_stat64 *host, bool fakeTTY = false) 502{ 503 using namespace TheISA; 504 505 convertStatBuf<target_stat, host_stat64>(tgt, host, fakeTTY); 506#if defined(STAT_HAVE_NSEC) 507 tgt->st_atime_nsec = host->st_atime_nsec; 508 tgt->st_atime_nsec = TheISA::htog(tgt->st_atime_nsec); 509 tgt->st_mtime_nsec = host->st_mtime_nsec; 510 tgt->st_mtime_nsec = TheISA::htog(tgt->st_mtime_nsec); 511 tgt->st_ctime_nsec = host->st_ctime_nsec; 512 tgt->st_ctime_nsec = TheISA::htog(tgt->st_ctime_nsec); 513#else 514 tgt->st_atime_nsec = 0; 515 tgt->st_mtime_nsec = 0; 516 tgt->st_ctime_nsec = 0; 517#endif 518} 519 520//Here are a couple convenience functions 521template<class OS> 522static void 523copyOutStatBuf(SETranslatingPortProxy &mem, Addr addr, 524 hst_stat *host, bool fakeTTY = false) 525{ 526 typedef TypedBufferArg<typename OS::tgt_stat> tgt_stat_buf; 527 tgt_stat_buf tgt(addr); 528 convertStatBuf<tgt_stat_buf, hst_stat>(tgt, host, fakeTTY); 529 tgt.copyOut(mem); 530} 531 532template<class OS> 533static void 534copyOutStat64Buf(SETranslatingPortProxy &mem, Addr addr, 535 hst_stat64 *host, bool fakeTTY = false) 536{ 537 typedef TypedBufferArg<typename OS::tgt_stat64> tgt_stat_buf; 538 tgt_stat_buf tgt(addr); 539 convertStat64Buf<tgt_stat_buf, hst_stat64>(tgt, host, fakeTTY); 540 tgt.copyOut(mem); 541} 542 543/// Target ioctl() handler. For the most part, programs call ioctl() 544/// only to find out if their stdout is a tty, to determine whether to 545/// do line or block buffering. We always claim that output fds are 546/// not TTYs to provide repeatable results. 547template <class OS> 548SyscallReturn 549ioctlFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 550 ThreadContext *tc) 551{ 552 int index = 0; 553 int fd = process->getSyscallArg(tc, index); 554 unsigned req = process->getSyscallArg(tc, index); 555 556 DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", fd, req); 557 558 Process::FdMap *fdObj = process->sim_fd_obj(fd); 559 560 if (fdObj == NULL) { 561 // doesn't map to any simulator fd: not a valid target fd 562 return -EBADF; 563 } 564 565 if (fdObj->driver != NULL) { 566 return fdObj->driver->ioctl(process, tc, req); 567 } 568 569 if (OS::isTtyReq(req)) { 570 return -ENOTTY; 571 } 572 573 warn("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ \n", 574 fd, req, tc->pcState()); 575 return -ENOTTY; 576} 577 578template <class OS> 579static SyscallReturn 580openFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 581 ThreadContext *tc, int index) 582{ 583 std::string path; 584 585 if (!tc->getMemProxy().tryReadString(path, 586 process->getSyscallArg(tc, index))) 587 return -EFAULT; 588 589 int tgtFlags = process->getSyscallArg(tc, index); 590 int mode = process->getSyscallArg(tc, index); 591 int hostFlags = 0; 592 593 // translate open flags 594 for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) { 595 if (tgtFlags & OS::openFlagTable[i].tgtFlag) { 596 tgtFlags &= ~OS::openFlagTable[i].tgtFlag; 597 hostFlags |= OS::openFlagTable[i].hostFlag; 598 } 599 } 600 601 // any target flags left? 602 if (tgtFlags != 0) 603 warn("Syscall: open: cannot decode flags 0x%x", tgtFlags); 604 605#ifdef __CYGWIN32__ 606 hostFlags |= O_BINARY; 607#endif 608 609 // Adjust path for current working directory 610 path = process->fullPath(path); 611 612 DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str()); 613 614 if (startswith(path, "/dev/")) { 615 std::string filename = path.substr(strlen("/dev/")); 616 if (filename == "sysdev0") { 617 // This is a memory-mapped high-resolution timer device on Alpha. 618 // We don't support it, so just punt. 619 warn("Ignoring open(%s, ...)\n", path); 620 return -ENOENT; 621 } 622 623 EmulatedDriver *drv = process->findDriver(filename); 624 if (drv != NULL) { 625 // the driver's open method will allocate a fd from the 626 // process if necessary. 627 return drv->open(process, tc, mode, hostFlags); 628 } 629 630 // fall through here for pass through to host devices, such as 631 // /dev/zero 632 } 633 634 int fd; 635 int local_errno; 636 if (startswith(path, "/proc/") || startswith(path, "/system/") || 637 startswith(path, "/platform/") || startswith(path, "/sys/")) { 638 // It's a proc/sys entry and requires special handling 639 fd = OS::openSpecialFile(path, process, tc); 640 local_errno = ENOENT; 641 } else { 642 // open the file 643 fd = open(path.c_str(), hostFlags, mode); 644 local_errno = errno; 645 } 646 647 if (fd == -1) 648 return -local_errno; 649 650 return process->alloc_fd(fd, path.c_str(), hostFlags, mode, false); 651} 652 653/// Target open() handler. 654template <class OS> 655SyscallReturn 656openFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 657 ThreadContext *tc) 658{ 659 return openFunc<OS>(desc, callnum, process, tc, 0); 660} 661 662/// Target openat() handler. 663template <class OS> 664SyscallReturn 665openatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 666 ThreadContext *tc) 667{ 668 int index = 0; 669 int dirfd = process->getSyscallArg(tc, index); 670 if (dirfd != OS::TGT_AT_FDCWD) 671 warn("openat: first argument not AT_FDCWD; unlikely to work"); 672 return openFunc<OS>(desc, callnum, process, tc, 1); 673} 674 675/// Target unlinkat() handler. 676template <class OS> 677SyscallReturn 678unlinkatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 679 ThreadContext *tc) 680{ 681 int index = 0; 682 int dirfd = process->getSyscallArg(tc, index); 683 if (dirfd != OS::TGT_AT_FDCWD) 684 warn("unlinkat: first argument not AT_FDCWD; unlikely to work"); 685 686 return unlinkHelper(desc, callnum, process, tc, 1); 687} 688 689/// Target facessat() handler 690template <class OS> 691SyscallReturn 692faccessatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 693 ThreadContext *tc) 694{ 695 int index = 0; 696 int dirfd = process->getSyscallArg(tc, index); 697 if (dirfd != OS::TGT_AT_FDCWD) 698 warn("faccessat: first argument not AT_FDCWD; unlikely to work"); 699 return accessFunc(desc, callnum, process, tc, 1); 700} 701 702/// Target readlinkat() handler 703template <class OS> 704SyscallReturn 705readlinkatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 706 ThreadContext *tc) 707{ 708 int index = 0; 709 int dirfd = process->getSyscallArg(tc, index); 710 if (dirfd != OS::TGT_AT_FDCWD) 711 warn("openat: first argument not AT_FDCWD; unlikely to work"); 712 return readlinkFunc(desc, callnum, process, tc, 1); 713} 714 715/// Target sysinfo() handler. 716template <class OS> 717SyscallReturn 718sysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 719 ThreadContext *tc) 720{ 721 722 int index = 0; 723 TypedBufferArg<typename OS::tgt_sysinfo> 724 sysinfo(process->getSyscallArg(tc, index)); 725 726 sysinfo->uptime=seconds_since_epoch; 727 sysinfo->totalram=process->system->memSize(); 728 729 sysinfo.copyOut(tc->getMemProxy()); 730 731 return 0; 732} 733 734/// Target chmod() handler. 735template <class OS> 736SyscallReturn 737chmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 738 ThreadContext *tc) 739{ 740 std::string path; 741 742 int index = 0; 743 if (!tc->getMemProxy().tryReadString(path, 744 process->getSyscallArg(tc, index))) { 745 return -EFAULT; 746 } 747 748 uint32_t mode = process->getSyscallArg(tc, index); 749 mode_t hostMode = 0; 750 751 // XXX translate mode flags via OS::something??? 752 hostMode = mode; 753 754 // Adjust path for current working directory 755 path = process->fullPath(path); 756 757 // do the chmod 758 int result = chmod(path.c_str(), hostMode); 759 if (result < 0) 760 return -errno; 761 762 return 0; 763} 764 765 766/// Target fchmod() handler. 767template <class OS> 768SyscallReturn 769fchmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 770 ThreadContext *tc) 771{ 772 int index = 0; 773 int fd = process->getSyscallArg(tc, index); 774 if (fd < 0 || process->sim_fd(fd) < 0) { 775 // doesn't map to any simulator fd: not a valid target fd 776 return -EBADF; 777 } 778 779 uint32_t mode = process->getSyscallArg(tc, index); 780 mode_t hostMode = 0; 781 782 // XXX translate mode flags via OS::someting??? 783 hostMode = mode; 784 785 // do the fchmod 786 int result = fchmod(process->sim_fd(fd), hostMode); 787 if (result < 0) 788 return -errno; 789 790 return 0; 791} 792 793/// Target mremap() handler. 794template <class OS> 795SyscallReturn 796mremapFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) 797{ 798 int index = 0; 799 Addr start = process->getSyscallArg(tc, index); 800 uint64_t old_length = process->getSyscallArg(tc, index); 801 uint64_t new_length = process->getSyscallArg(tc, index); 802 uint64_t flags = process->getSyscallArg(tc, index); 803 uint64_t provided_address = 0; 804 bool use_provided_address = flags & OS::TGT_MREMAP_FIXED; 805 806 if (use_provided_address) 807 provided_address = process->getSyscallArg(tc, index); 808 809 if ((start % TheISA::PageBytes != 0) || 810 (provided_address % TheISA::PageBytes != 0)) { 811 warn("mremap failing: arguments not page aligned"); 812 return -EINVAL; 813 } 814 815 new_length = roundUp(new_length, TheISA::PageBytes); 816 817 if (new_length > old_length) { 818 if ((start + old_length) == process->mmap_end && 819 (!use_provided_address || provided_address == start)) { 820 uint64_t diff = new_length - old_length; 821 process->allocateMem(process->mmap_end, diff); 822 process->mmap_end += diff; 823 return start; 824 } else { 825 if (!use_provided_address && !(flags & OS::TGT_MREMAP_MAYMOVE)) { 826 warn("can't remap here and MREMAP_MAYMOVE flag not set\n"); 827 return -ENOMEM; 828 } else { 829 uint64_t new_start = use_provided_address ? 830 provided_address : process->mmap_end; 831 process->pTable->remap(start, old_length, new_start); 832 warn("mremapping to new vaddr %08p-%08p, adding %d\n", 833 new_start, new_start + new_length, 834 new_length - old_length); 835 // add on the remaining unallocated pages 836 process->allocateMem(new_start + old_length, 837 new_length - old_length, 838 use_provided_address /* clobber */); 839 if (!use_provided_address) 840 process->mmap_end += new_length; 841 if (use_provided_address && 842 new_start + new_length > process->mmap_end) { 843 // something fishy going on here, at least notify the user 844 // @todo: increase mmap_end? 845 warn("mmap region limit exceeded with MREMAP_FIXED\n"); 846 } 847 warn("returning %08p as start\n", new_start); 848 return new_start; 849 } 850 } 851 } else { 852 if (use_provided_address && provided_address != start) 853 process->pTable->remap(start, new_length, provided_address); 854 process->pTable->unmap(start + new_length, old_length - new_length); 855 return use_provided_address ? provided_address : start; 856 } 857} 858 859/// Target stat() handler. 860template <class OS> 861SyscallReturn 862statFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 863 ThreadContext *tc) 864{ 865 std::string path; 866 867 int index = 0; 868 if (!tc->getMemProxy().tryReadString(path, 869 process->getSyscallArg(tc, index))) { 870 return -EFAULT; 871 } 872 Addr bufPtr = process->getSyscallArg(tc, index); 873 874 // Adjust path for current working directory 875 path = process->fullPath(path); 876 877 struct stat hostBuf; 878 int result = stat(path.c_str(), &hostBuf); 879 880 if (result < 0) 881 return -errno; 882 883 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 884 885 return 0; 886} 887 888 889/// Target stat64() handler. 890template <class OS> 891SyscallReturn 892stat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 893 ThreadContext *tc) 894{ 895 std::string path; 896 897 int index = 0; 898 if (!tc->getMemProxy().tryReadString(path, 899 process->getSyscallArg(tc, index))) 900 return -EFAULT; 901 Addr bufPtr = process->getSyscallArg(tc, index); 902 903 // Adjust path for current working directory 904 path = process->fullPath(path); 905 906#if NO_STAT64 907 struct stat hostBuf; 908 int result = stat(path.c_str(), &hostBuf); 909#else 910 struct stat64 hostBuf; 911 int result = stat64(path.c_str(), &hostBuf); 912#endif 913 914 if (result < 0) 915 return -errno; 916 917 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 918 919 return 0; 920} 921 922 923/// Target fstatat64() handler. 924template <class OS> 925SyscallReturn 926fstatat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 927 ThreadContext *tc) 928{ 929 int index = 0; 930 int dirfd = process->getSyscallArg(tc, index); 931 if (dirfd != OS::TGT_AT_FDCWD) 932 warn("fstatat64: first argument not AT_FDCWD; unlikely to work"); 933 934 std::string path; 935 if (!tc->getMemProxy().tryReadString(path, 936 process->getSyscallArg(tc, index))) 937 return -EFAULT; 938 Addr bufPtr = process->getSyscallArg(tc, index); 939 940 // Adjust path for current working directory 941 path = process->fullPath(path); 942 943#if NO_STAT64 944 struct stat hostBuf; 945 int result = stat(path.c_str(), &hostBuf); 946#else 947 struct stat64 hostBuf; 948 int result = stat64(path.c_str(), &hostBuf); 949#endif 950 951 if (result < 0) 952 return -errno; 953 954 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 955 956 return 0; 957} 958 959 960/// Target fstat64() handler. 961template <class OS> 962SyscallReturn 963fstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 964 ThreadContext *tc) 965{ 966 int index = 0; 967 int fd = process->getSyscallArg(tc, index); 968 Addr bufPtr = process->getSyscallArg(tc, index); 969 if (fd < 0 || process->sim_fd(fd) < 0) { 970 // doesn't map to any simulator fd: not a valid target fd 971 return -EBADF; 972 } 973 974#if NO_STAT64 975 struct stat hostBuf; 976 int result = fstat(process->sim_fd(fd), &hostBuf); 977#else 978 struct stat64 hostBuf; 979 int result = fstat64(process->sim_fd(fd), &hostBuf); 980#endif 981 982 if (result < 0) 983 return -errno; 984 985 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (fd == 1)); 986 987 return 0; 988} 989 990 991/// Target lstat() handler. 992template <class OS> 993SyscallReturn 994lstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 995 ThreadContext *tc) 996{ 997 std::string path; 998 999 int index = 0; 1000 if (!tc->getMemProxy().tryReadString(path, 1001 process->getSyscallArg(tc, index))) { 1002 return -EFAULT; 1003 } 1004 Addr bufPtr = process->getSyscallArg(tc, index); 1005 1006 // Adjust path for current working directory 1007 path = process->fullPath(path); 1008 1009 struct stat hostBuf; 1010 int result = lstat(path.c_str(), &hostBuf); 1011 1012 if (result < 0) 1013 return -errno; 1014 1015 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1016 1017 return 0; 1018} 1019 1020/// Target lstat64() handler. 1021template <class OS> 1022SyscallReturn 1023lstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 1024 ThreadContext *tc) 1025{ 1026 std::string path; 1027 1028 int index = 0; 1029 if (!tc->getMemProxy().tryReadString(path, 1030 process->getSyscallArg(tc, index))) { 1031 return -EFAULT; 1032 } 1033 Addr bufPtr = process->getSyscallArg(tc, index); 1034 1035 // Adjust path for current working directory 1036 path = process->fullPath(path); 1037 1038#if NO_STAT64 1039 struct stat hostBuf; 1040 int result = lstat(path.c_str(), &hostBuf); 1041#else 1042 struct stat64 hostBuf; 1043 int result = lstat64(path.c_str(), &hostBuf); 1044#endif 1045 1046 if (result < 0) 1047 return -errno; 1048 1049 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1050 1051 return 0; 1052} 1053 1054/// Target fstat() handler. 1055template <class OS> 1056SyscallReturn 1057fstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1058 ThreadContext *tc) 1059{ 1060 int index = 0; 1061 int fd = process->sim_fd(process->getSyscallArg(tc, index)); 1062 Addr bufPtr = process->getSyscallArg(tc, index); 1063 1064 DPRINTF(SyscallVerbose, "fstat(%d, ...)\n", fd); 1065 1066 if (fd < 0) 1067 return -EBADF; 1068 1069 struct stat hostBuf; 1070 int result = fstat(fd, &hostBuf); 1071 1072 if (result < 0) 1073 return -errno; 1074 1075 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (fd == 1)); 1076 1077 return 0; 1078} 1079 1080 1081/// Target statfs() handler. 1082template <class OS> 1083SyscallReturn 1084statfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1085 ThreadContext *tc) 1086{ 1087 std::string path; 1088 1089 int index = 0; 1090 if (!tc->getMemProxy().tryReadString(path, 1091 process->getSyscallArg(tc, index))) { 1092 return -EFAULT; 1093 } 1094 Addr bufPtr = process->getSyscallArg(tc, index); 1095 1096 // Adjust path for current working directory 1097 path = process->fullPath(path); 1098 1099 struct statfs hostBuf; 1100 int result = statfs(path.c_str(), &hostBuf); 1101 1102 if (result < 0) 1103 return -errno; 1104 1105 OS::copyOutStatfsBuf(tc->getMemProxy(), bufPtr, &hostBuf); 1106 1107 return 0; 1108} 1109 1110 1111/// Target fstatfs() handler. 1112template <class OS> 1113SyscallReturn 1114fstatfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1115 ThreadContext *tc) 1116{ 1117 int index = 0; 1118 int fd = process->sim_fd(process->getSyscallArg(tc, index)); 1119 Addr bufPtr = process->getSyscallArg(tc, index); 1120 1121 if (fd < 0) 1122 return -EBADF; 1123 1124 struct statfs hostBuf; 1125 int result = fstatfs(fd, &hostBuf); 1126 1127 if (result < 0) 1128 return -errno; 1129 1130 OS::copyOutStatfsBuf(tc->getMemProxy(), bufPtr, &hostBuf); 1131 1132 return 0; 1133} 1134 1135 1136/// Target writev() handler. 1137template <class OS> 1138SyscallReturn 1139writevFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1140 ThreadContext *tc) 1141{ 1142 int index = 0; 1143 int fd = process->getSyscallArg(tc, index); 1144 if (fd < 0 || process->sim_fd(fd) < 0) { 1145 // doesn't map to any simulator fd: not a valid target fd 1146 return -EBADF; 1147 } 1148 1149 SETranslatingPortProxy &p = tc->getMemProxy(); 1150 uint64_t tiov_base = process->getSyscallArg(tc, index); 1151 size_t count = process->getSyscallArg(tc, index); 1152 struct iovec hiov[count]; 1153 for (size_t i = 0; i < count; ++i) { 1154 typename OS::tgt_iovec tiov; 1155 1156 p.readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec), 1157 (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec)); 1158 hiov[i].iov_len = TheISA::gtoh(tiov.iov_len); 1159 hiov[i].iov_base = new char [hiov[i].iov_len]; 1160 p.readBlob(TheISA::gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base, 1161 hiov[i].iov_len); 1162 } 1163 1164 int result = writev(process->sim_fd(fd), hiov, count); 1165 1166 for (size_t i = 0; i < count; ++i) 1167 delete [] (char *)hiov[i].iov_base; 1168 1169 if (result < 0) 1170 return -errno; 1171 1172 return result; 1173} 1174 1175 1176/// Target mmap() handler. 1177/// 1178/// We don't really handle mmap(). If the target is mmaping an 1179/// anonymous region or /dev/zero, we can get away with doing basically 1180/// nothing (since memory is initialized to zero and the simulator 1181/// doesn't really check addresses anyway). 1182/// 1183template <class OS> 1184SyscallReturn 1185mmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 1186{ 1187 int index = 0; 1188 Addr start = p->getSyscallArg(tc, index); 1189 uint64_t length = p->getSyscallArg(tc, index); 1190 index++; // int prot = p->getSyscallArg(tc, index); 1191 int flags = p->getSyscallArg(tc, index); 1192 int tgt_fd = p->getSyscallArg(tc, index); 1193 int offset = p->getSyscallArg(tc, index); 1194 1195 if (length > 0x100000000ULL) 1196 warn("mmap length argument %#x is unreasonably large.\n", length); 1197 1198 if (!(flags & OS::TGT_MAP_ANONYMOUS)) { 1199 Process::FdMap *fd_map = p->sim_fd_obj(tgt_fd); 1200 if (!fd_map || fd_map->fd < 0) { 1201 warn("mmap failing: target fd %d is not valid\n", tgt_fd); 1202 return -EBADF; 1203 } 1204 1205 if (fd_map->filename != "/dev/zero") { 1206 // This is very likely broken, but leave a warning here 1207 // (rather than panic) in case /dev/zero is known by 1208 // another name on some platform 1209 warn("allowing mmap of file %s; mmap not supported on files" 1210 " other than /dev/zero\n", fd_map->filename); 1211 } 1212 } 1213 1214 length = roundUp(length, TheISA::PageBytes); 1215 1216 if ((start % TheISA::PageBytes) != 0 || 1217 (offset % TheISA::PageBytes) != 0) { 1218 warn("mmap failing: arguments not page-aligned: " 1219 "start 0x%x offset 0x%x", 1220 start, offset); 1221 return -EINVAL; 1222 } 1223 1224 // are we ok with clobbering existing mappings? only set this to 1225 // true if the user has been warned. 1226 bool clobber = false; 1227 1228 // try to use the caller-provided address if there is one 1229 bool use_provided_address = (start != 0); 1230 1231 if (use_provided_address) { 1232 // check to see if the desired address is already in use 1233 if (!p->pTable->isUnmapped(start, length)) { 1234 // there are existing mappings in the desired range 1235 // whether we clobber them or not depends on whether the caller 1236 // specified MAP_FIXED 1237 if (flags & OS::TGT_MAP_FIXED) { 1238 // MAP_FIXED specified: map attempt fails 1239 return -EINVAL; 1240 } else { 1241 // MAP_FIXED not specified: ignore suggested start address 1242 warn("mmap: ignoring suggested map address 0x%x\n", start); 1243 use_provided_address = false; 1244 } 1245 } 1246 } 1247 1248 if (!use_provided_address) { 1249 // no address provided, or provided address unusable: 1250 // pick next address from our "mmap region" 1251 if (OS::mmapGrowsDown()) { 1252 start = p->mmap_end - length; 1253 p->mmap_end = start; 1254 } else { 1255 start = p->mmap_end; 1256 p->mmap_end += length; 1257 } 1258 } 1259 1260 p->allocateMem(start, length, clobber); 1261 1262 return start; 1263} 1264 1265/// Target getrlimit() handler. 1266template <class OS> 1267SyscallReturn 1268getrlimitFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1269 ThreadContext *tc) 1270{ 1271 int index = 0; 1272 unsigned resource = process->getSyscallArg(tc, index); 1273 TypedBufferArg<typename OS::rlimit> rlp(process->getSyscallArg(tc, index)); 1274 1275 switch (resource) { 1276 case OS::TGT_RLIMIT_STACK: 1277 // max stack size in bytes: make up a number (8MB for now) 1278 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; 1279 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1280 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1281 break; 1282 1283 case OS::TGT_RLIMIT_DATA: 1284 // max data segment size in bytes: make up a number 1285 rlp->rlim_cur = rlp->rlim_max = 256 * 1024 * 1024; 1286 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1287 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1288 break; 1289 1290 default: 1291 warn("getrlimit: unimplemented resource %d", resource); 1292 return -EINVAL; 1293 break; 1294 } 1295 1296 rlp.copyOut(tc->getMemProxy()); 1297 return 0; 1298} 1299 1300/// Target clock_gettime() function. 1301template <class OS> 1302SyscallReturn 1303clock_gettimeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 1304{ 1305 int index = 1; 1306 //int clk_id = p->getSyscallArg(tc, index); 1307 TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index)); 1308 1309 getElapsedTimeNano(tp->tv_sec, tp->tv_nsec); 1310 tp->tv_sec += seconds_since_epoch; 1311 tp->tv_sec = TheISA::htog(tp->tv_sec); 1312 tp->tv_nsec = TheISA::htog(tp->tv_nsec); 1313 1314 tp.copyOut(tc->getMemProxy()); 1315 1316 return 0; 1317} 1318 1319/// Target gettimeofday() handler. 1320template <class OS> 1321SyscallReturn 1322gettimeofdayFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1323 ThreadContext *tc) 1324{ 1325 int index = 0; 1326 TypedBufferArg<typename OS::timeval> tp(process->getSyscallArg(tc, index)); 1327 1328 getElapsedTimeMicro(tp->tv_sec, tp->tv_usec); 1329 tp->tv_sec += seconds_since_epoch; 1330 tp->tv_sec = TheISA::htog(tp->tv_sec); 1331 tp->tv_usec = TheISA::htog(tp->tv_usec); 1332 1333 tp.copyOut(tc->getMemProxy()); 1334 1335 return 0; 1336} 1337 1338 1339/// Target utimes() handler. 1340template <class OS> 1341SyscallReturn 1342utimesFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1343 ThreadContext *tc) 1344{ 1345 std::string path; 1346 1347 int index = 0; 1348 if (!tc->getMemProxy().tryReadString(path, 1349 process->getSyscallArg(tc, index))) { 1350 return -EFAULT; 1351 } 1352 1353 TypedBufferArg<typename OS::timeval [2]> 1354 tp(process->getSyscallArg(tc, index)); 1355 tp.copyIn(tc->getMemProxy()); 1356 1357 struct timeval hostTimeval[2]; 1358 for (int i = 0; i < 2; ++i) 1359 { 1360 hostTimeval[i].tv_sec = TheISA::gtoh((*tp)[i].tv_sec); 1361 hostTimeval[i].tv_usec = TheISA::gtoh((*tp)[i].tv_usec); 1362 } 1363 1364 // Adjust path for current working directory 1365 path = process->fullPath(path); 1366 1367 int result = utimes(path.c_str(), hostTimeval); 1368 1369 if (result < 0) 1370 return -errno; 1371 1372 return 0; 1373} 1374/// Target getrusage() function. 1375template <class OS> 1376SyscallReturn 1377getrusageFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1378 ThreadContext *tc) 1379{ 1380 int index = 0; 1381 int who = process->getSyscallArg(tc, index); // THREAD, SELF, or CHILDREN 1382 TypedBufferArg<typename OS::rusage> rup(process->getSyscallArg(tc, index)); 1383 1384 rup->ru_utime.tv_sec = 0; 1385 rup->ru_utime.tv_usec = 0; 1386 rup->ru_stime.tv_sec = 0; 1387 rup->ru_stime.tv_usec = 0; 1388 rup->ru_maxrss = 0; 1389 rup->ru_ixrss = 0; 1390 rup->ru_idrss = 0; 1391 rup->ru_isrss = 0; 1392 rup->ru_minflt = 0; 1393 rup->ru_majflt = 0; 1394 rup->ru_nswap = 0; 1395 rup->ru_inblock = 0; 1396 rup->ru_oublock = 0; 1397 rup->ru_msgsnd = 0; 1398 rup->ru_msgrcv = 0; 1399 rup->ru_nsignals = 0; 1400 rup->ru_nvcsw = 0; 1401 rup->ru_nivcsw = 0; 1402 1403 switch (who) { 1404 case OS::TGT_RUSAGE_SELF: 1405 getElapsedTimeMicro(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec); 1406 rup->ru_utime.tv_sec = TheISA::htog(rup->ru_utime.tv_sec); 1407 rup->ru_utime.tv_usec = TheISA::htog(rup->ru_utime.tv_usec); 1408 break; 1409 1410 case OS::TGT_RUSAGE_CHILDREN: 1411 // do nothing. We have no child processes, so they take no time. 1412 break; 1413 1414 default: 1415 // don't really handle THREAD or CHILDREN, but just warn and 1416 // plow ahead 1417 warn("getrusage() only supports RUSAGE_SELF. Parameter %d ignored.", 1418 who); 1419 } 1420 1421 rup.copyOut(tc->getMemProxy()); 1422 1423 return 0; 1424} 1425 1426/// Target times() function. 1427template <class OS> 1428SyscallReturn 1429timesFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1430 ThreadContext *tc) 1431{ 1432 int index = 0; 1433 TypedBufferArg<typename OS::tms> bufp(process->getSyscallArg(tc, index)); 1434 1435 // Fill in the time structure (in clocks) 1436 int64_t clocks = curTick() * OS::M5_SC_CLK_TCK / SimClock::Int::s; 1437 bufp->tms_utime = clocks; 1438 bufp->tms_stime = 0; 1439 bufp->tms_cutime = 0; 1440 bufp->tms_cstime = 0; 1441 1442 // Convert to host endianness 1443 bufp->tms_utime = TheISA::htog(bufp->tms_utime); 1444 1445 // Write back 1446 bufp.copyOut(tc->getMemProxy()); 1447 1448 // Return clock ticks since system boot 1449 return clocks; 1450} 1451 1452/// Target time() function. 1453template <class OS> 1454SyscallReturn 1455timeFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1456 ThreadContext *tc) 1457{ 1458 typename OS::time_t sec, usec; 1459 getElapsedTimeMicro(sec, usec); 1460 sec += seconds_since_epoch; 1461 1462 int index = 0; 1463 Addr taddr = (Addr)process->getSyscallArg(tc, index); 1464 if(taddr != 0) { 1465 typename OS::time_t t = sec; 1466 t = TheISA::htog(t); 1467 SETranslatingPortProxy &p = tc->getMemProxy(); 1468 p.writeBlob(taddr, (uint8_t*)&t, (int)sizeof(typename OS::time_t)); 1469 } 1470 return sec; 1471} 1472 1473 1474#endif // __SIM_SYSCALL_EMUL_HH__
| 145 146/// Target exit() handler: terminate current context. 147SyscallReturn exitFunc(SyscallDesc *desc, int num, 148 LiveProcess *p, ThreadContext *tc); 149 150/// Target exit_group() handler: terminate simulation. (exit all threads) 151SyscallReturn exitGroupFunc(SyscallDesc *desc, int num, 152 LiveProcess *p, ThreadContext *tc); 153 154/// Target getpagesize() handler. 155SyscallReturn getpagesizeFunc(SyscallDesc *desc, int num, 156 LiveProcess *p, ThreadContext *tc); 157 158/// Target brk() handler: set brk address. 159SyscallReturn brkFunc(SyscallDesc *desc, int num, 160 LiveProcess *p, ThreadContext *tc); 161 162/// Target close() handler. 163SyscallReturn closeFunc(SyscallDesc *desc, int num, 164 LiveProcess *p, ThreadContext *tc); 165 166/// Target read() handler. 167SyscallReturn readFunc(SyscallDesc *desc, int num, 168 LiveProcess *p, ThreadContext *tc); 169 170/// Target write() handler. 171SyscallReturn writeFunc(SyscallDesc *desc, int num, 172 LiveProcess *p, ThreadContext *tc); 173 174/// Target lseek() handler. 175SyscallReturn lseekFunc(SyscallDesc *desc, int num, 176 LiveProcess *p, ThreadContext *tc); 177 178/// Target _llseek() handler. 179SyscallReturn _llseekFunc(SyscallDesc *desc, int num, 180 LiveProcess *p, ThreadContext *tc); 181 182/// Target munmap() handler. 183SyscallReturn munmapFunc(SyscallDesc *desc, int num, 184 LiveProcess *p, ThreadContext *tc); 185 186/// Target gethostname() handler. 187SyscallReturn gethostnameFunc(SyscallDesc *desc, int num, 188 LiveProcess *p, ThreadContext *tc); 189 190/// Target getcwd() handler. 191SyscallReturn getcwdFunc(SyscallDesc *desc, int num, 192 LiveProcess *p, ThreadContext *tc); 193 194/// Target readlink() handler. 195SyscallReturn readlinkFunc(SyscallDesc *desc, int num, 196 LiveProcess *p, ThreadContext *tc, 197 int index = 0); 198SyscallReturn readlinkFunc(SyscallDesc *desc, int num, 199 LiveProcess *p, ThreadContext *tc); 200 201/// Target unlink() handler. 202SyscallReturn unlinkHelper(SyscallDesc *desc, int num, 203 LiveProcess *p, ThreadContext *tc, 204 int index); 205SyscallReturn unlinkFunc(SyscallDesc *desc, int num, 206 LiveProcess *p, ThreadContext *tc); 207 208/// Target mkdir() handler. 209SyscallReturn mkdirFunc(SyscallDesc *desc, int num, 210 LiveProcess *p, ThreadContext *tc); 211 212/// Target rename() handler. 213SyscallReturn renameFunc(SyscallDesc *desc, int num, 214 LiveProcess *p, ThreadContext *tc); 215 216 217/// Target truncate() handler. 218SyscallReturn truncateFunc(SyscallDesc *desc, int num, 219 LiveProcess *p, ThreadContext *tc); 220 221 222/// Target ftruncate() handler. 223SyscallReturn ftruncateFunc(SyscallDesc *desc, int num, 224 LiveProcess *p, ThreadContext *tc); 225 226 227/// Target truncate64() handler. 228SyscallReturn truncate64Func(SyscallDesc *desc, int num, 229 LiveProcess *p, ThreadContext *tc); 230 231/// Target ftruncate64() handler. 232SyscallReturn ftruncate64Func(SyscallDesc *desc, int num, 233 LiveProcess *p, ThreadContext *tc); 234 235 236/// Target umask() handler. 237SyscallReturn umaskFunc(SyscallDesc *desc, int num, 238 LiveProcess *p, ThreadContext *tc); 239 240 241/// Target chown() handler. 242SyscallReturn chownFunc(SyscallDesc *desc, int num, 243 LiveProcess *p, ThreadContext *tc); 244 245 246/// Target fchown() handler. 247SyscallReturn fchownFunc(SyscallDesc *desc, int num, 248 LiveProcess *p, ThreadContext *tc); 249 250/// Target dup() handler. 251SyscallReturn dupFunc(SyscallDesc *desc, int num, 252 LiveProcess *process, ThreadContext *tc); 253 254/// Target fnctl() handler. 255SyscallReturn fcntlFunc(SyscallDesc *desc, int num, 256 LiveProcess *process, ThreadContext *tc); 257 258/// Target fcntl64() handler. 259SyscallReturn fcntl64Func(SyscallDesc *desc, int num, 260 LiveProcess *process, ThreadContext *tc); 261 262/// Target setuid() handler. 263SyscallReturn setuidFunc(SyscallDesc *desc, int num, 264 LiveProcess *p, ThreadContext *tc); 265 266/// Target getpid() handler. 267SyscallReturn getpidFunc(SyscallDesc *desc, int num, 268 LiveProcess *p, ThreadContext *tc); 269 270/// Target getuid() handler. 271SyscallReturn getuidFunc(SyscallDesc *desc, int num, 272 LiveProcess *p, ThreadContext *tc); 273 274/// Target getgid() handler. 275SyscallReturn getgidFunc(SyscallDesc *desc, int num, 276 LiveProcess *p, ThreadContext *tc); 277 278/// Target getppid() handler. 279SyscallReturn getppidFunc(SyscallDesc *desc, int num, 280 LiveProcess *p, ThreadContext *tc); 281 282/// Target geteuid() handler. 283SyscallReturn geteuidFunc(SyscallDesc *desc, int num, 284 LiveProcess *p, ThreadContext *tc); 285 286/// Target getegid() handler. 287SyscallReturn getegidFunc(SyscallDesc *desc, int num, 288 LiveProcess *p, ThreadContext *tc); 289 290/// Target clone() handler. 291SyscallReturn cloneFunc(SyscallDesc *desc, int num, 292 LiveProcess *p, ThreadContext *tc); 293 294/// Target access() handler 295SyscallReturn accessFunc(SyscallDesc *desc, int num, 296 LiveProcess *p, ThreadContext *tc); 297SyscallReturn accessFunc(SyscallDesc *desc, int num, 298 LiveProcess *p, ThreadContext *tc, 299 int index); 300 301/// Futex system call 302/// Implemented by Daniel Sanchez 303/// Used by printf's in multi-threaded apps 304template <class OS> 305SyscallReturn 306futexFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 307 ThreadContext *tc) 308{ 309 int index_uaddr = 0; 310 int index_op = 1; 311 int index_val = 2; 312 int index_timeout = 3; 313 314 uint64_t uaddr = process->getSyscallArg(tc, index_uaddr); 315 int op = process->getSyscallArg(tc, index_op); 316 int val = process->getSyscallArg(tc, index_val); 317 uint64_t timeout = process->getSyscallArg(tc, index_timeout); 318 319 std::map<uint64_t, std::list<ThreadContext *> * > 320 &futex_map = tc->getSystemPtr()->futexMap; 321 322 DPRINTF(SyscallVerbose, "In sys_futex: Address=%llx, op=%d, val=%d\n", 323 uaddr, op, val); 324 325 op &= ~OS::TGT_FUTEX_PRIVATE_FLAG; 326 327 if (op == OS::TGT_FUTEX_WAIT) { 328 if (timeout != 0) { 329 warn("sys_futex: FUTEX_WAIT with non-null timeout unimplemented;" 330 "we'll wait indefinitely"); 331 } 332 333 uint8_t *buf = new uint8_t[sizeof(int)]; 334 tc->getMemProxy().readBlob((Addr)uaddr, buf, (int)sizeof(int)); 335 int mem_val = *((int *)buf); 336 delete buf; 337 338 if(val != mem_val) { 339 DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAKE, read: %d, " 340 "expected: %d\n", mem_val, val); 341 return -OS::TGT_EWOULDBLOCK; 342 } 343 344 // Queue the thread context 345 std::list<ThreadContext *> * tcWaitList; 346 if (futex_map.count(uaddr)) { 347 tcWaitList = futex_map.find(uaddr)->second; 348 } else { 349 tcWaitList = new std::list<ThreadContext *>(); 350 futex_map.insert(std::pair< uint64_t, 351 std::list<ThreadContext *> * >(uaddr, tcWaitList)); 352 } 353 tcWaitList->push_back(tc); 354 DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAIT, suspending calling " 355 "thread context\n"); 356 tc->suspend(); 357 return 0; 358 } else if (op == OS::TGT_FUTEX_WAKE){ 359 int wokenUp = 0; 360 std::list<ThreadContext *> * tcWaitList; 361 if (futex_map.count(uaddr)) { 362 tcWaitList = futex_map.find(uaddr)->second; 363 while (tcWaitList->size() > 0 && wokenUp < val) { 364 tcWaitList->front()->activate(); 365 tcWaitList->pop_front(); 366 wokenUp++; 367 } 368 if(tcWaitList->empty()) { 369 futex_map.erase(uaddr); 370 delete tcWaitList; 371 } 372 } 373 DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAKE, activated %d waiting " 374 "thread contexts\n", wokenUp); 375 return wokenUp; 376 } else { 377 warn("sys_futex: op %d is not implemented, just returning...", op); 378 return 0; 379 } 380 381} 382 383 384/// Pseudo Funcs - These functions use a different return convension, 385/// returning a second value in a register other than the normal return register 386SyscallReturn pipePseudoFunc(SyscallDesc *desc, int num, 387 LiveProcess *process, ThreadContext *tc); 388 389/// Target getpidPseudo() handler. 390SyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num, 391 LiveProcess *p, ThreadContext *tc); 392 393/// Target getuidPseudo() handler. 394SyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num, 395 LiveProcess *p, ThreadContext *tc); 396 397/// Target getgidPseudo() handler. 398SyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num, 399 LiveProcess *p, ThreadContext *tc); 400 401 402/// A readable name for 1,000,000, for converting microseconds to seconds. 403const int one_million = 1000000; 404/// A readable name for 1,000,000,000, for converting nanoseconds to seconds. 405const int one_billion = 1000000000; 406 407/// Approximate seconds since the epoch (1/1/1970). About a billion, 408/// by my reckoning. We want to keep this a constant (not use the 409/// real-world time) to keep simulations repeatable. 410const unsigned seconds_since_epoch = 1000000000; 411 412/// Helper function to convert current elapsed time to seconds and 413/// microseconds. 414template <class T1, class T2> 415void 416getElapsedTimeMicro(T1 &sec, T2 &usec) 417{ 418 uint64_t elapsed_usecs = curTick() / SimClock::Int::us; 419 sec = elapsed_usecs / one_million; 420 usec = elapsed_usecs % one_million; 421} 422 423/// Helper function to convert current elapsed time to seconds and 424/// nanoseconds. 425template <class T1, class T2> 426void 427getElapsedTimeNano(T1 &sec, T2 &nsec) 428{ 429 uint64_t elapsed_nsecs = curTick() / SimClock::Int::ns; 430 sec = elapsed_nsecs / one_billion; 431 nsec = elapsed_nsecs % one_billion; 432} 433 434////////////////////////////////////////////////////////////////////// 435// 436// The following emulation functions are generic, but need to be 437// templated to account for differences in types, constants, etc. 438// 439////////////////////////////////////////////////////////////////////// 440 441#if NO_STAT64 442 typedef struct stat hst_stat; 443 typedef struct stat hst_stat64; 444#else 445 typedef struct stat hst_stat; 446 typedef struct stat64 hst_stat64; 447#endif 448 449//// Helper function to convert a host stat buffer to a target stat 450//// buffer. Also copies the target buffer out to the simulated 451//// memory space. Used by stat(), fstat(), and lstat(). 452 453template <typename target_stat, typename host_stat> 454static void 455convertStatBuf(target_stat &tgt, host_stat *host, bool fakeTTY = false) 456{ 457 using namespace TheISA; 458 459 if (fakeTTY) 460 tgt->st_dev = 0xA; 461 else 462 tgt->st_dev = host->st_dev; 463 tgt->st_dev = TheISA::htog(tgt->st_dev); 464 tgt->st_ino = host->st_ino; 465 tgt->st_ino = TheISA::htog(tgt->st_ino); 466 tgt->st_mode = host->st_mode; 467 if (fakeTTY) { 468 // Claim to be a character device 469 tgt->st_mode &= ~S_IFMT; // Clear S_IFMT 470 tgt->st_mode |= S_IFCHR; // Set S_IFCHR 471 } 472 tgt->st_mode = TheISA::htog(tgt->st_mode); 473 tgt->st_nlink = host->st_nlink; 474 tgt->st_nlink = TheISA::htog(tgt->st_nlink); 475 tgt->st_uid = host->st_uid; 476 tgt->st_uid = TheISA::htog(tgt->st_uid); 477 tgt->st_gid = host->st_gid; 478 tgt->st_gid = TheISA::htog(tgt->st_gid); 479 if (fakeTTY) 480 tgt->st_rdev = 0x880d; 481 else 482 tgt->st_rdev = host->st_rdev; 483 tgt->st_rdev = TheISA::htog(tgt->st_rdev); 484 tgt->st_size = host->st_size; 485 tgt->st_size = TheISA::htog(tgt->st_size); 486 tgt->st_atimeX = host->st_atime; 487 tgt->st_atimeX = TheISA::htog(tgt->st_atimeX); 488 tgt->st_mtimeX = host->st_mtime; 489 tgt->st_mtimeX = TheISA::htog(tgt->st_mtimeX); 490 tgt->st_ctimeX = host->st_ctime; 491 tgt->st_ctimeX = TheISA::htog(tgt->st_ctimeX); 492 // Force the block size to be 8k. This helps to ensure buffered io works 493 // consistently across different hosts. 494 tgt->st_blksize = 0x2000; 495 tgt->st_blksize = TheISA::htog(tgt->st_blksize); 496 tgt->st_blocks = host->st_blocks; 497 tgt->st_blocks = TheISA::htog(tgt->st_blocks); 498} 499 500// Same for stat64 501 502template <typename target_stat, typename host_stat64> 503static void 504convertStat64Buf(target_stat &tgt, host_stat64 *host, bool fakeTTY = false) 505{ 506 using namespace TheISA; 507 508 convertStatBuf<target_stat, host_stat64>(tgt, host, fakeTTY); 509#if defined(STAT_HAVE_NSEC) 510 tgt->st_atime_nsec = host->st_atime_nsec; 511 tgt->st_atime_nsec = TheISA::htog(tgt->st_atime_nsec); 512 tgt->st_mtime_nsec = host->st_mtime_nsec; 513 tgt->st_mtime_nsec = TheISA::htog(tgt->st_mtime_nsec); 514 tgt->st_ctime_nsec = host->st_ctime_nsec; 515 tgt->st_ctime_nsec = TheISA::htog(tgt->st_ctime_nsec); 516#else 517 tgt->st_atime_nsec = 0; 518 tgt->st_mtime_nsec = 0; 519 tgt->st_ctime_nsec = 0; 520#endif 521} 522 523//Here are a couple convenience functions 524template<class OS> 525static void 526copyOutStatBuf(SETranslatingPortProxy &mem, Addr addr, 527 hst_stat *host, bool fakeTTY = false) 528{ 529 typedef TypedBufferArg<typename OS::tgt_stat> tgt_stat_buf; 530 tgt_stat_buf tgt(addr); 531 convertStatBuf<tgt_stat_buf, hst_stat>(tgt, host, fakeTTY); 532 tgt.copyOut(mem); 533} 534 535template<class OS> 536static void 537copyOutStat64Buf(SETranslatingPortProxy &mem, Addr addr, 538 hst_stat64 *host, bool fakeTTY = false) 539{ 540 typedef TypedBufferArg<typename OS::tgt_stat64> tgt_stat_buf; 541 tgt_stat_buf tgt(addr); 542 convertStat64Buf<tgt_stat_buf, hst_stat64>(tgt, host, fakeTTY); 543 tgt.copyOut(mem); 544} 545 546/// Target ioctl() handler. For the most part, programs call ioctl() 547/// only to find out if their stdout is a tty, to determine whether to 548/// do line or block buffering. We always claim that output fds are 549/// not TTYs to provide repeatable results. 550template <class OS> 551SyscallReturn 552ioctlFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 553 ThreadContext *tc) 554{ 555 int index = 0; 556 int fd = process->getSyscallArg(tc, index); 557 unsigned req = process->getSyscallArg(tc, index); 558 559 DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", fd, req); 560 561 Process::FdMap *fdObj = process->sim_fd_obj(fd); 562 563 if (fdObj == NULL) { 564 // doesn't map to any simulator fd: not a valid target fd 565 return -EBADF; 566 } 567 568 if (fdObj->driver != NULL) { 569 return fdObj->driver->ioctl(process, tc, req); 570 } 571 572 if (OS::isTtyReq(req)) { 573 return -ENOTTY; 574 } 575 576 warn("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ \n", 577 fd, req, tc->pcState()); 578 return -ENOTTY; 579} 580 581template <class OS> 582static SyscallReturn 583openFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 584 ThreadContext *tc, int index) 585{ 586 std::string path; 587 588 if (!tc->getMemProxy().tryReadString(path, 589 process->getSyscallArg(tc, index))) 590 return -EFAULT; 591 592 int tgtFlags = process->getSyscallArg(tc, index); 593 int mode = process->getSyscallArg(tc, index); 594 int hostFlags = 0; 595 596 // translate open flags 597 for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) { 598 if (tgtFlags & OS::openFlagTable[i].tgtFlag) { 599 tgtFlags &= ~OS::openFlagTable[i].tgtFlag; 600 hostFlags |= OS::openFlagTable[i].hostFlag; 601 } 602 } 603 604 // any target flags left? 605 if (tgtFlags != 0) 606 warn("Syscall: open: cannot decode flags 0x%x", tgtFlags); 607 608#ifdef __CYGWIN32__ 609 hostFlags |= O_BINARY; 610#endif 611 612 // Adjust path for current working directory 613 path = process->fullPath(path); 614 615 DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str()); 616 617 if (startswith(path, "/dev/")) { 618 std::string filename = path.substr(strlen("/dev/")); 619 if (filename == "sysdev0") { 620 // This is a memory-mapped high-resolution timer device on Alpha. 621 // We don't support it, so just punt. 622 warn("Ignoring open(%s, ...)\n", path); 623 return -ENOENT; 624 } 625 626 EmulatedDriver *drv = process->findDriver(filename); 627 if (drv != NULL) { 628 // the driver's open method will allocate a fd from the 629 // process if necessary. 630 return drv->open(process, tc, mode, hostFlags); 631 } 632 633 // fall through here for pass through to host devices, such as 634 // /dev/zero 635 } 636 637 int fd; 638 int local_errno; 639 if (startswith(path, "/proc/") || startswith(path, "/system/") || 640 startswith(path, "/platform/") || startswith(path, "/sys/")) { 641 // It's a proc/sys entry and requires special handling 642 fd = OS::openSpecialFile(path, process, tc); 643 local_errno = ENOENT; 644 } else { 645 // open the file 646 fd = open(path.c_str(), hostFlags, mode); 647 local_errno = errno; 648 } 649 650 if (fd == -1) 651 return -local_errno; 652 653 return process->alloc_fd(fd, path.c_str(), hostFlags, mode, false); 654} 655 656/// Target open() handler. 657template <class OS> 658SyscallReturn 659openFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 660 ThreadContext *tc) 661{ 662 return openFunc<OS>(desc, callnum, process, tc, 0); 663} 664 665/// Target openat() handler. 666template <class OS> 667SyscallReturn 668openatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 669 ThreadContext *tc) 670{ 671 int index = 0; 672 int dirfd = process->getSyscallArg(tc, index); 673 if (dirfd != OS::TGT_AT_FDCWD) 674 warn("openat: first argument not AT_FDCWD; unlikely to work"); 675 return openFunc<OS>(desc, callnum, process, tc, 1); 676} 677 678/// Target unlinkat() handler. 679template <class OS> 680SyscallReturn 681unlinkatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 682 ThreadContext *tc) 683{ 684 int index = 0; 685 int dirfd = process->getSyscallArg(tc, index); 686 if (dirfd != OS::TGT_AT_FDCWD) 687 warn("unlinkat: first argument not AT_FDCWD; unlikely to work"); 688 689 return unlinkHelper(desc, callnum, process, tc, 1); 690} 691 692/// Target facessat() handler 693template <class OS> 694SyscallReturn 695faccessatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 696 ThreadContext *tc) 697{ 698 int index = 0; 699 int dirfd = process->getSyscallArg(tc, index); 700 if (dirfd != OS::TGT_AT_FDCWD) 701 warn("faccessat: first argument not AT_FDCWD; unlikely to work"); 702 return accessFunc(desc, callnum, process, tc, 1); 703} 704 705/// Target readlinkat() handler 706template <class OS> 707SyscallReturn 708readlinkatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 709 ThreadContext *tc) 710{ 711 int index = 0; 712 int dirfd = process->getSyscallArg(tc, index); 713 if (dirfd != OS::TGT_AT_FDCWD) 714 warn("openat: first argument not AT_FDCWD; unlikely to work"); 715 return readlinkFunc(desc, callnum, process, tc, 1); 716} 717 718/// Target sysinfo() handler. 719template <class OS> 720SyscallReturn 721sysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 722 ThreadContext *tc) 723{ 724 725 int index = 0; 726 TypedBufferArg<typename OS::tgt_sysinfo> 727 sysinfo(process->getSyscallArg(tc, index)); 728 729 sysinfo->uptime=seconds_since_epoch; 730 sysinfo->totalram=process->system->memSize(); 731 732 sysinfo.copyOut(tc->getMemProxy()); 733 734 return 0; 735} 736 737/// Target chmod() handler. 738template <class OS> 739SyscallReturn 740chmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 741 ThreadContext *tc) 742{ 743 std::string path; 744 745 int index = 0; 746 if (!tc->getMemProxy().tryReadString(path, 747 process->getSyscallArg(tc, index))) { 748 return -EFAULT; 749 } 750 751 uint32_t mode = process->getSyscallArg(tc, index); 752 mode_t hostMode = 0; 753 754 // XXX translate mode flags via OS::something??? 755 hostMode = mode; 756 757 // Adjust path for current working directory 758 path = process->fullPath(path); 759 760 // do the chmod 761 int result = chmod(path.c_str(), hostMode); 762 if (result < 0) 763 return -errno; 764 765 return 0; 766} 767 768 769/// Target fchmod() handler. 770template <class OS> 771SyscallReturn 772fchmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 773 ThreadContext *tc) 774{ 775 int index = 0; 776 int fd = process->getSyscallArg(tc, index); 777 if (fd < 0 || process->sim_fd(fd) < 0) { 778 // doesn't map to any simulator fd: not a valid target fd 779 return -EBADF; 780 } 781 782 uint32_t mode = process->getSyscallArg(tc, index); 783 mode_t hostMode = 0; 784 785 // XXX translate mode flags via OS::someting??? 786 hostMode = mode; 787 788 // do the fchmod 789 int result = fchmod(process->sim_fd(fd), hostMode); 790 if (result < 0) 791 return -errno; 792 793 return 0; 794} 795 796/// Target mremap() handler. 797template <class OS> 798SyscallReturn 799mremapFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) 800{ 801 int index = 0; 802 Addr start = process->getSyscallArg(tc, index); 803 uint64_t old_length = process->getSyscallArg(tc, index); 804 uint64_t new_length = process->getSyscallArg(tc, index); 805 uint64_t flags = process->getSyscallArg(tc, index); 806 uint64_t provided_address = 0; 807 bool use_provided_address = flags & OS::TGT_MREMAP_FIXED; 808 809 if (use_provided_address) 810 provided_address = process->getSyscallArg(tc, index); 811 812 if ((start % TheISA::PageBytes != 0) || 813 (provided_address % TheISA::PageBytes != 0)) { 814 warn("mremap failing: arguments not page aligned"); 815 return -EINVAL; 816 } 817 818 new_length = roundUp(new_length, TheISA::PageBytes); 819 820 if (new_length > old_length) { 821 if ((start + old_length) == process->mmap_end && 822 (!use_provided_address || provided_address == start)) { 823 uint64_t diff = new_length - old_length; 824 process->allocateMem(process->mmap_end, diff); 825 process->mmap_end += diff; 826 return start; 827 } else { 828 if (!use_provided_address && !(flags & OS::TGT_MREMAP_MAYMOVE)) { 829 warn("can't remap here and MREMAP_MAYMOVE flag not set\n"); 830 return -ENOMEM; 831 } else { 832 uint64_t new_start = use_provided_address ? 833 provided_address : process->mmap_end; 834 process->pTable->remap(start, old_length, new_start); 835 warn("mremapping to new vaddr %08p-%08p, adding %d\n", 836 new_start, new_start + new_length, 837 new_length - old_length); 838 // add on the remaining unallocated pages 839 process->allocateMem(new_start + old_length, 840 new_length - old_length, 841 use_provided_address /* clobber */); 842 if (!use_provided_address) 843 process->mmap_end += new_length; 844 if (use_provided_address && 845 new_start + new_length > process->mmap_end) { 846 // something fishy going on here, at least notify the user 847 // @todo: increase mmap_end? 848 warn("mmap region limit exceeded with MREMAP_FIXED\n"); 849 } 850 warn("returning %08p as start\n", new_start); 851 return new_start; 852 } 853 } 854 } else { 855 if (use_provided_address && provided_address != start) 856 process->pTable->remap(start, new_length, provided_address); 857 process->pTable->unmap(start + new_length, old_length - new_length); 858 return use_provided_address ? provided_address : start; 859 } 860} 861 862/// Target stat() handler. 863template <class OS> 864SyscallReturn 865statFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 866 ThreadContext *tc) 867{ 868 std::string path; 869 870 int index = 0; 871 if (!tc->getMemProxy().tryReadString(path, 872 process->getSyscallArg(tc, index))) { 873 return -EFAULT; 874 } 875 Addr bufPtr = process->getSyscallArg(tc, index); 876 877 // Adjust path for current working directory 878 path = process->fullPath(path); 879 880 struct stat hostBuf; 881 int result = stat(path.c_str(), &hostBuf); 882 883 if (result < 0) 884 return -errno; 885 886 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 887 888 return 0; 889} 890 891 892/// Target stat64() handler. 893template <class OS> 894SyscallReturn 895stat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 896 ThreadContext *tc) 897{ 898 std::string path; 899 900 int index = 0; 901 if (!tc->getMemProxy().tryReadString(path, 902 process->getSyscallArg(tc, index))) 903 return -EFAULT; 904 Addr bufPtr = process->getSyscallArg(tc, index); 905 906 // Adjust path for current working directory 907 path = process->fullPath(path); 908 909#if NO_STAT64 910 struct stat hostBuf; 911 int result = stat(path.c_str(), &hostBuf); 912#else 913 struct stat64 hostBuf; 914 int result = stat64(path.c_str(), &hostBuf); 915#endif 916 917 if (result < 0) 918 return -errno; 919 920 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 921 922 return 0; 923} 924 925 926/// Target fstatat64() handler. 927template <class OS> 928SyscallReturn 929fstatat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 930 ThreadContext *tc) 931{ 932 int index = 0; 933 int dirfd = process->getSyscallArg(tc, index); 934 if (dirfd != OS::TGT_AT_FDCWD) 935 warn("fstatat64: first argument not AT_FDCWD; unlikely to work"); 936 937 std::string path; 938 if (!tc->getMemProxy().tryReadString(path, 939 process->getSyscallArg(tc, index))) 940 return -EFAULT; 941 Addr bufPtr = process->getSyscallArg(tc, index); 942 943 // Adjust path for current working directory 944 path = process->fullPath(path); 945 946#if NO_STAT64 947 struct stat hostBuf; 948 int result = stat(path.c_str(), &hostBuf); 949#else 950 struct stat64 hostBuf; 951 int result = stat64(path.c_str(), &hostBuf); 952#endif 953 954 if (result < 0) 955 return -errno; 956 957 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 958 959 return 0; 960} 961 962 963/// Target fstat64() handler. 964template <class OS> 965SyscallReturn 966fstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 967 ThreadContext *tc) 968{ 969 int index = 0; 970 int fd = process->getSyscallArg(tc, index); 971 Addr bufPtr = process->getSyscallArg(tc, index); 972 if (fd < 0 || process->sim_fd(fd) < 0) { 973 // doesn't map to any simulator fd: not a valid target fd 974 return -EBADF; 975 } 976 977#if NO_STAT64 978 struct stat hostBuf; 979 int result = fstat(process->sim_fd(fd), &hostBuf); 980#else 981 struct stat64 hostBuf; 982 int result = fstat64(process->sim_fd(fd), &hostBuf); 983#endif 984 985 if (result < 0) 986 return -errno; 987 988 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (fd == 1)); 989 990 return 0; 991} 992 993 994/// Target lstat() handler. 995template <class OS> 996SyscallReturn 997lstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 998 ThreadContext *tc) 999{ 1000 std::string path; 1001 1002 int index = 0; 1003 if (!tc->getMemProxy().tryReadString(path, 1004 process->getSyscallArg(tc, index))) { 1005 return -EFAULT; 1006 } 1007 Addr bufPtr = process->getSyscallArg(tc, index); 1008 1009 // Adjust path for current working directory 1010 path = process->fullPath(path); 1011 1012 struct stat hostBuf; 1013 int result = lstat(path.c_str(), &hostBuf); 1014 1015 if (result < 0) 1016 return -errno; 1017 1018 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1019 1020 return 0; 1021} 1022 1023/// Target lstat64() handler. 1024template <class OS> 1025SyscallReturn 1026lstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 1027 ThreadContext *tc) 1028{ 1029 std::string path; 1030 1031 int index = 0; 1032 if (!tc->getMemProxy().tryReadString(path, 1033 process->getSyscallArg(tc, index))) { 1034 return -EFAULT; 1035 } 1036 Addr bufPtr = process->getSyscallArg(tc, index); 1037 1038 // Adjust path for current working directory 1039 path = process->fullPath(path); 1040 1041#if NO_STAT64 1042 struct stat hostBuf; 1043 int result = lstat(path.c_str(), &hostBuf); 1044#else 1045 struct stat64 hostBuf; 1046 int result = lstat64(path.c_str(), &hostBuf); 1047#endif 1048 1049 if (result < 0) 1050 return -errno; 1051 1052 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1053 1054 return 0; 1055} 1056 1057/// Target fstat() handler. 1058template <class OS> 1059SyscallReturn 1060fstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1061 ThreadContext *tc) 1062{ 1063 int index = 0; 1064 int fd = process->sim_fd(process->getSyscallArg(tc, index)); 1065 Addr bufPtr = process->getSyscallArg(tc, index); 1066 1067 DPRINTF(SyscallVerbose, "fstat(%d, ...)\n", fd); 1068 1069 if (fd < 0) 1070 return -EBADF; 1071 1072 struct stat hostBuf; 1073 int result = fstat(fd, &hostBuf); 1074 1075 if (result < 0) 1076 return -errno; 1077 1078 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (fd == 1)); 1079 1080 return 0; 1081} 1082 1083 1084/// Target statfs() handler. 1085template <class OS> 1086SyscallReturn 1087statfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1088 ThreadContext *tc) 1089{ 1090 std::string path; 1091 1092 int index = 0; 1093 if (!tc->getMemProxy().tryReadString(path, 1094 process->getSyscallArg(tc, index))) { 1095 return -EFAULT; 1096 } 1097 Addr bufPtr = process->getSyscallArg(tc, index); 1098 1099 // Adjust path for current working directory 1100 path = process->fullPath(path); 1101 1102 struct statfs hostBuf; 1103 int result = statfs(path.c_str(), &hostBuf); 1104 1105 if (result < 0) 1106 return -errno; 1107 1108 OS::copyOutStatfsBuf(tc->getMemProxy(), bufPtr, &hostBuf); 1109 1110 return 0; 1111} 1112 1113 1114/// Target fstatfs() handler. 1115template <class OS> 1116SyscallReturn 1117fstatfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1118 ThreadContext *tc) 1119{ 1120 int index = 0; 1121 int fd = process->sim_fd(process->getSyscallArg(tc, index)); 1122 Addr bufPtr = process->getSyscallArg(tc, index); 1123 1124 if (fd < 0) 1125 return -EBADF; 1126 1127 struct statfs hostBuf; 1128 int result = fstatfs(fd, &hostBuf); 1129 1130 if (result < 0) 1131 return -errno; 1132 1133 OS::copyOutStatfsBuf(tc->getMemProxy(), bufPtr, &hostBuf); 1134 1135 return 0; 1136} 1137 1138 1139/// Target writev() handler. 1140template <class OS> 1141SyscallReturn 1142writevFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1143 ThreadContext *tc) 1144{ 1145 int index = 0; 1146 int fd = process->getSyscallArg(tc, index); 1147 if (fd < 0 || process->sim_fd(fd) < 0) { 1148 // doesn't map to any simulator fd: not a valid target fd 1149 return -EBADF; 1150 } 1151 1152 SETranslatingPortProxy &p = tc->getMemProxy(); 1153 uint64_t tiov_base = process->getSyscallArg(tc, index); 1154 size_t count = process->getSyscallArg(tc, index); 1155 struct iovec hiov[count]; 1156 for (size_t i = 0; i < count; ++i) { 1157 typename OS::tgt_iovec tiov; 1158 1159 p.readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec), 1160 (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec)); 1161 hiov[i].iov_len = TheISA::gtoh(tiov.iov_len); 1162 hiov[i].iov_base = new char [hiov[i].iov_len]; 1163 p.readBlob(TheISA::gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base, 1164 hiov[i].iov_len); 1165 } 1166 1167 int result = writev(process->sim_fd(fd), hiov, count); 1168 1169 for (size_t i = 0; i < count; ++i) 1170 delete [] (char *)hiov[i].iov_base; 1171 1172 if (result < 0) 1173 return -errno; 1174 1175 return result; 1176} 1177 1178 1179/// Target mmap() handler. 1180/// 1181/// We don't really handle mmap(). If the target is mmaping an 1182/// anonymous region or /dev/zero, we can get away with doing basically 1183/// nothing (since memory is initialized to zero and the simulator 1184/// doesn't really check addresses anyway). 1185/// 1186template <class OS> 1187SyscallReturn 1188mmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 1189{ 1190 int index = 0; 1191 Addr start = p->getSyscallArg(tc, index); 1192 uint64_t length = p->getSyscallArg(tc, index); 1193 index++; // int prot = p->getSyscallArg(tc, index); 1194 int flags = p->getSyscallArg(tc, index); 1195 int tgt_fd = p->getSyscallArg(tc, index); 1196 int offset = p->getSyscallArg(tc, index); 1197 1198 if (length > 0x100000000ULL) 1199 warn("mmap length argument %#x is unreasonably large.\n", length); 1200 1201 if (!(flags & OS::TGT_MAP_ANONYMOUS)) { 1202 Process::FdMap *fd_map = p->sim_fd_obj(tgt_fd); 1203 if (!fd_map || fd_map->fd < 0) { 1204 warn("mmap failing: target fd %d is not valid\n", tgt_fd); 1205 return -EBADF; 1206 } 1207 1208 if (fd_map->filename != "/dev/zero") { 1209 // This is very likely broken, but leave a warning here 1210 // (rather than panic) in case /dev/zero is known by 1211 // another name on some platform 1212 warn("allowing mmap of file %s; mmap not supported on files" 1213 " other than /dev/zero\n", fd_map->filename); 1214 } 1215 } 1216 1217 length = roundUp(length, TheISA::PageBytes); 1218 1219 if ((start % TheISA::PageBytes) != 0 || 1220 (offset % TheISA::PageBytes) != 0) { 1221 warn("mmap failing: arguments not page-aligned: " 1222 "start 0x%x offset 0x%x", 1223 start, offset); 1224 return -EINVAL; 1225 } 1226 1227 // are we ok with clobbering existing mappings? only set this to 1228 // true if the user has been warned. 1229 bool clobber = false; 1230 1231 // try to use the caller-provided address if there is one 1232 bool use_provided_address = (start != 0); 1233 1234 if (use_provided_address) { 1235 // check to see if the desired address is already in use 1236 if (!p->pTable->isUnmapped(start, length)) { 1237 // there are existing mappings in the desired range 1238 // whether we clobber them or not depends on whether the caller 1239 // specified MAP_FIXED 1240 if (flags & OS::TGT_MAP_FIXED) { 1241 // MAP_FIXED specified: map attempt fails 1242 return -EINVAL; 1243 } else { 1244 // MAP_FIXED not specified: ignore suggested start address 1245 warn("mmap: ignoring suggested map address 0x%x\n", start); 1246 use_provided_address = false; 1247 } 1248 } 1249 } 1250 1251 if (!use_provided_address) { 1252 // no address provided, or provided address unusable: 1253 // pick next address from our "mmap region" 1254 if (OS::mmapGrowsDown()) { 1255 start = p->mmap_end - length; 1256 p->mmap_end = start; 1257 } else { 1258 start = p->mmap_end; 1259 p->mmap_end += length; 1260 } 1261 } 1262 1263 p->allocateMem(start, length, clobber); 1264 1265 return start; 1266} 1267 1268/// Target getrlimit() handler. 1269template <class OS> 1270SyscallReturn 1271getrlimitFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1272 ThreadContext *tc) 1273{ 1274 int index = 0; 1275 unsigned resource = process->getSyscallArg(tc, index); 1276 TypedBufferArg<typename OS::rlimit> rlp(process->getSyscallArg(tc, index)); 1277 1278 switch (resource) { 1279 case OS::TGT_RLIMIT_STACK: 1280 // max stack size in bytes: make up a number (8MB for now) 1281 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; 1282 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1283 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1284 break; 1285 1286 case OS::TGT_RLIMIT_DATA: 1287 // max data segment size in bytes: make up a number 1288 rlp->rlim_cur = rlp->rlim_max = 256 * 1024 * 1024; 1289 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1290 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1291 break; 1292 1293 default: 1294 warn("getrlimit: unimplemented resource %d", resource); 1295 return -EINVAL; 1296 break; 1297 } 1298 1299 rlp.copyOut(tc->getMemProxy()); 1300 return 0; 1301} 1302 1303/// Target clock_gettime() function. 1304template <class OS> 1305SyscallReturn 1306clock_gettimeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 1307{ 1308 int index = 1; 1309 //int clk_id = p->getSyscallArg(tc, index); 1310 TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index)); 1311 1312 getElapsedTimeNano(tp->tv_sec, tp->tv_nsec); 1313 tp->tv_sec += seconds_since_epoch; 1314 tp->tv_sec = TheISA::htog(tp->tv_sec); 1315 tp->tv_nsec = TheISA::htog(tp->tv_nsec); 1316 1317 tp.copyOut(tc->getMemProxy()); 1318 1319 return 0; 1320} 1321 1322/// Target gettimeofday() handler. 1323template <class OS> 1324SyscallReturn 1325gettimeofdayFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1326 ThreadContext *tc) 1327{ 1328 int index = 0; 1329 TypedBufferArg<typename OS::timeval> tp(process->getSyscallArg(tc, index)); 1330 1331 getElapsedTimeMicro(tp->tv_sec, tp->tv_usec); 1332 tp->tv_sec += seconds_since_epoch; 1333 tp->tv_sec = TheISA::htog(tp->tv_sec); 1334 tp->tv_usec = TheISA::htog(tp->tv_usec); 1335 1336 tp.copyOut(tc->getMemProxy()); 1337 1338 return 0; 1339} 1340 1341 1342/// Target utimes() handler. 1343template <class OS> 1344SyscallReturn 1345utimesFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1346 ThreadContext *tc) 1347{ 1348 std::string path; 1349 1350 int index = 0; 1351 if (!tc->getMemProxy().tryReadString(path, 1352 process->getSyscallArg(tc, index))) { 1353 return -EFAULT; 1354 } 1355 1356 TypedBufferArg<typename OS::timeval [2]> 1357 tp(process->getSyscallArg(tc, index)); 1358 tp.copyIn(tc->getMemProxy()); 1359 1360 struct timeval hostTimeval[2]; 1361 for (int i = 0; i < 2; ++i) 1362 { 1363 hostTimeval[i].tv_sec = TheISA::gtoh((*tp)[i].tv_sec); 1364 hostTimeval[i].tv_usec = TheISA::gtoh((*tp)[i].tv_usec); 1365 } 1366 1367 // Adjust path for current working directory 1368 path = process->fullPath(path); 1369 1370 int result = utimes(path.c_str(), hostTimeval); 1371 1372 if (result < 0) 1373 return -errno; 1374 1375 return 0; 1376} 1377/// Target getrusage() function. 1378template <class OS> 1379SyscallReturn 1380getrusageFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1381 ThreadContext *tc) 1382{ 1383 int index = 0; 1384 int who = process->getSyscallArg(tc, index); // THREAD, SELF, or CHILDREN 1385 TypedBufferArg<typename OS::rusage> rup(process->getSyscallArg(tc, index)); 1386 1387 rup->ru_utime.tv_sec = 0; 1388 rup->ru_utime.tv_usec = 0; 1389 rup->ru_stime.tv_sec = 0; 1390 rup->ru_stime.tv_usec = 0; 1391 rup->ru_maxrss = 0; 1392 rup->ru_ixrss = 0; 1393 rup->ru_idrss = 0; 1394 rup->ru_isrss = 0; 1395 rup->ru_minflt = 0; 1396 rup->ru_majflt = 0; 1397 rup->ru_nswap = 0; 1398 rup->ru_inblock = 0; 1399 rup->ru_oublock = 0; 1400 rup->ru_msgsnd = 0; 1401 rup->ru_msgrcv = 0; 1402 rup->ru_nsignals = 0; 1403 rup->ru_nvcsw = 0; 1404 rup->ru_nivcsw = 0; 1405 1406 switch (who) { 1407 case OS::TGT_RUSAGE_SELF: 1408 getElapsedTimeMicro(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec); 1409 rup->ru_utime.tv_sec = TheISA::htog(rup->ru_utime.tv_sec); 1410 rup->ru_utime.tv_usec = TheISA::htog(rup->ru_utime.tv_usec); 1411 break; 1412 1413 case OS::TGT_RUSAGE_CHILDREN: 1414 // do nothing. We have no child processes, so they take no time. 1415 break; 1416 1417 default: 1418 // don't really handle THREAD or CHILDREN, but just warn and 1419 // plow ahead 1420 warn("getrusage() only supports RUSAGE_SELF. Parameter %d ignored.", 1421 who); 1422 } 1423 1424 rup.copyOut(tc->getMemProxy()); 1425 1426 return 0; 1427} 1428 1429/// Target times() function. 1430template <class OS> 1431SyscallReturn 1432timesFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1433 ThreadContext *tc) 1434{ 1435 int index = 0; 1436 TypedBufferArg<typename OS::tms> bufp(process->getSyscallArg(tc, index)); 1437 1438 // Fill in the time structure (in clocks) 1439 int64_t clocks = curTick() * OS::M5_SC_CLK_TCK / SimClock::Int::s; 1440 bufp->tms_utime = clocks; 1441 bufp->tms_stime = 0; 1442 bufp->tms_cutime = 0; 1443 bufp->tms_cstime = 0; 1444 1445 // Convert to host endianness 1446 bufp->tms_utime = TheISA::htog(bufp->tms_utime); 1447 1448 // Write back 1449 bufp.copyOut(tc->getMemProxy()); 1450 1451 // Return clock ticks since system boot 1452 return clocks; 1453} 1454 1455/// Target time() function. 1456template <class OS> 1457SyscallReturn 1458timeFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1459 ThreadContext *tc) 1460{ 1461 typename OS::time_t sec, usec; 1462 getElapsedTimeMicro(sec, usec); 1463 sec += seconds_since_epoch; 1464 1465 int index = 0; 1466 Addr taddr = (Addr)process->getSyscallArg(tc, index); 1467 if(taddr != 0) { 1468 typename OS::time_t t = sec; 1469 t = TheISA::htog(t); 1470 SETranslatingPortProxy &p = tc->getMemProxy(); 1471 p.writeBlob(taddr, (uint8_t*)&t, (int)sizeof(typename OS::time_t)); 1472 } 1473 return sec; 1474} 1475 1476 1477#endif // __SIM_SYSCALL_EMUL_HH__
|