210/// Target mkdir() handler. 211SyscallReturn mkdirFunc(SyscallDesc *desc, int num, 212 Process *p, ThreadContext *tc); 213 214/// Target rename() handler. 215SyscallReturn renameFunc(SyscallDesc *desc, int num, 216 Process *p, ThreadContext *tc); 217 218 219/// Target truncate() handler. 220SyscallReturn truncateFunc(SyscallDesc *desc, int num, 221 Process *p, ThreadContext *tc); 222 223 224/// Target ftruncate() handler. 225SyscallReturn ftruncateFunc(SyscallDesc *desc, int num, 226 Process *p, ThreadContext *tc); 227 228 229/// Target truncate64() handler. 230SyscallReturn truncate64Func(SyscallDesc *desc, int num, 231 Process *p, ThreadContext *tc); 232 233/// Target ftruncate64() handler. 234SyscallReturn ftruncate64Func(SyscallDesc *desc, int num, 235 Process *p, ThreadContext *tc); 236 237 238/// Target umask() handler. 239SyscallReturn umaskFunc(SyscallDesc *desc, int num, 240 Process *p, ThreadContext *tc); 241 242/// Target gettid() handler. 243SyscallReturn gettidFunc(SyscallDesc *desc, int num, 244 Process *p, ThreadContext *tc); 245 246/// Target chown() handler. 247SyscallReturn chownFunc(SyscallDesc *desc, int num, 248 Process *p, ThreadContext *tc); 249 250/// Target setpgid() handler. 251SyscallReturn setpgidFunc(SyscallDesc *desc, int num, 252 Process *p, ThreadContext *tc); 253 254/// Target fchown() handler. 255SyscallReturn fchownFunc(SyscallDesc *desc, int num, 256 Process *p, ThreadContext *tc); 257 258/// Target dup() handler. 259SyscallReturn dupFunc(SyscallDesc *desc, int num, 260 Process *process, ThreadContext *tc); 261 262/// Target dup2() handler. 263SyscallReturn dup2Func(SyscallDesc *desc, int num, 264 Process *process, ThreadContext *tc); 265 266/// Target fcntl() handler. 267SyscallReturn fcntlFunc(SyscallDesc *desc, int num, 268 Process *process, ThreadContext *tc); 269 270/// Target fcntl64() handler. 271SyscallReturn fcntl64Func(SyscallDesc *desc, int num, 272 Process *process, ThreadContext *tc); 273 274/// Target setuid() handler. 275SyscallReturn setuidFunc(SyscallDesc *desc, int num, 276 Process *p, ThreadContext *tc); 277 278/// Target pipe() handler. 279SyscallReturn pipeFunc(SyscallDesc *desc, int num, 280 Process *p, ThreadContext *tc); 281 282/// Internal pipe() handler. 283SyscallReturn pipeImpl(SyscallDesc *desc, int num, Process *p, 284 ThreadContext *tc, bool pseudoPipe); 285 286/// Target getpid() handler. 287SyscallReturn getpidFunc(SyscallDesc *desc, int num, 288 Process *p, ThreadContext *tc); 289 290/// Target getuid() handler. 291SyscallReturn getuidFunc(SyscallDesc *desc, int num, 292 Process *p, ThreadContext *tc); 293 294/// Target getgid() handler. 295SyscallReturn getgidFunc(SyscallDesc *desc, int num, 296 Process *p, ThreadContext *tc); 297 298/// Target getppid() handler. 299SyscallReturn getppidFunc(SyscallDesc *desc, int num, 300 Process *p, ThreadContext *tc); 301 302/// Target geteuid() handler. 303SyscallReturn geteuidFunc(SyscallDesc *desc, int num, 304 Process *p, ThreadContext *tc); 305 306/// Target getegid() handler. 307SyscallReturn getegidFunc(SyscallDesc *desc, int num, 308 Process *p, ThreadContext *tc); 309 310/// Target access() handler 311SyscallReturn accessFunc(SyscallDesc *desc, int num, 312 Process *p, ThreadContext *tc); 313SyscallReturn accessFunc(SyscallDesc *desc, int num, 314 Process *p, ThreadContext *tc, 315 int index); 316 317/// Futex system call 318/// Implemented by Daniel Sanchez 319/// Used by printf's in multi-threaded apps 320template <class OS> 321SyscallReturn 322futexFunc(SyscallDesc *desc, int callnum, Process *process, 323 ThreadContext *tc) 324{ 325 using namespace std; 326 327 int index = 0; 328 Addr uaddr = process->getSyscallArg(tc, index); 329 int op = process->getSyscallArg(tc, index); 330 int val = process->getSyscallArg(tc, index); 331 332 /* 333 * Unsupported option that does not affect the correctness of the 334 * application. This is a performance optimization utilized by Linux. 335 */ 336 op &= ~OS::TGT_FUTEX_PRIVATE_FLAG; 337 338 FutexMap &futex_map = tc->getSystemPtr()->futexMap; 339 340 if (OS::TGT_FUTEX_WAIT == op) { 341 // Ensure futex system call accessed atomically. 342 BufferArg buf(uaddr, sizeof(int)); 343 buf.copyIn(tc->getMemProxy()); 344 int mem_val = *(int*)buf.bufferPtr(); 345 346 /* 347 * The value in memory at uaddr is not equal with the expected val 348 * (a different thread must have changed it before the system call was 349 * invoked). In this case, we need to throw an error. 350 */ 351 if (val != mem_val) 352 return -OS::TGT_EWOULDBLOCK; 353 354 futex_map.suspend(uaddr, process->tgid(), tc); 355 356 return 0; 357 } else if (OS::TGT_FUTEX_WAKE == op) { 358 return futex_map.wakeup(uaddr, process->tgid(), val); 359 } 360 361 warn("futex: op %d not implemented; ignoring.", op); 362 return -ENOSYS; 363} 364 365 366/// Pseudo Funcs - These functions use a different return convension, 367/// returning a second value in a register other than the normal return register 368SyscallReturn pipePseudoFunc(SyscallDesc *desc, int num, 369 Process *process, ThreadContext *tc); 370 371/// Target getpidPseudo() handler. 372SyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num, 373 Process *p, ThreadContext *tc); 374 375/// Target getuidPseudo() handler. 376SyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num, 377 Process *p, ThreadContext *tc); 378 379/// Target getgidPseudo() handler. 380SyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num, 381 Process *p, ThreadContext *tc); 382 383 384/// A readable name for 1,000,000, for converting microseconds to seconds. 385const int one_million = 1000000; 386/// A readable name for 1,000,000,000, for converting nanoseconds to seconds. 387const int one_billion = 1000000000; 388 389/// Approximate seconds since the epoch (1/1/1970). About a billion, 390/// by my reckoning. We want to keep this a constant (not use the 391/// real-world time) to keep simulations repeatable. 392const unsigned seconds_since_epoch = 1000000000; 393 394/// Helper function to convert current elapsed time to seconds and 395/// microseconds. 396template <class T1, class T2> 397void 398getElapsedTimeMicro(T1 &sec, T2 &usec) 399{ 400 uint64_t elapsed_usecs = curTick() / SimClock::Int::us; 401 sec = elapsed_usecs / one_million; 402 usec = elapsed_usecs % one_million; 403} 404 405/// Helper function to convert current elapsed time to seconds and 406/// nanoseconds. 407template <class T1, class T2> 408void 409getElapsedTimeNano(T1 &sec, T2 &nsec) 410{ 411 uint64_t elapsed_nsecs = curTick() / SimClock::Int::ns; 412 sec = elapsed_nsecs / one_billion; 413 nsec = elapsed_nsecs % one_billion; 414} 415 416////////////////////////////////////////////////////////////////////// 417// 418// The following emulation functions are generic, but need to be 419// templated to account for differences in types, constants, etc. 420// 421////////////////////////////////////////////////////////////////////// 422 423 typedef struct statfs hst_statfs; 424#if NO_STAT64 425 typedef struct stat hst_stat; 426 typedef struct stat hst_stat64; 427#else 428 typedef struct stat hst_stat; 429 typedef struct stat64 hst_stat64; 430#endif 431 432//// Helper function to convert a host stat buffer to a target stat 433//// buffer. Also copies the target buffer out to the simulated 434//// memory space. Used by stat(), fstat(), and lstat(). 435 436template <typename target_stat, typename host_stat> 437void 438convertStatBuf(target_stat &tgt, host_stat *host, bool fakeTTY = false) 439{ 440 using namespace TheISA; 441 442 if (fakeTTY) 443 tgt->st_dev = 0xA; 444 else 445 tgt->st_dev = host->st_dev; 446 tgt->st_dev = TheISA::htog(tgt->st_dev); 447 tgt->st_ino = host->st_ino; 448 tgt->st_ino = TheISA::htog(tgt->st_ino); 449 tgt->st_mode = host->st_mode; 450 if (fakeTTY) { 451 // Claim to be a character device 452 tgt->st_mode &= ~S_IFMT; // Clear S_IFMT 453 tgt->st_mode |= S_IFCHR; // Set S_IFCHR 454 } 455 tgt->st_mode = TheISA::htog(tgt->st_mode); 456 tgt->st_nlink = host->st_nlink; 457 tgt->st_nlink = TheISA::htog(tgt->st_nlink); 458 tgt->st_uid = host->st_uid; 459 tgt->st_uid = TheISA::htog(tgt->st_uid); 460 tgt->st_gid = host->st_gid; 461 tgt->st_gid = TheISA::htog(tgt->st_gid); 462 if (fakeTTY) 463 tgt->st_rdev = 0x880d; 464 else 465 tgt->st_rdev = host->st_rdev; 466 tgt->st_rdev = TheISA::htog(tgt->st_rdev); 467 tgt->st_size = host->st_size; 468 tgt->st_size = TheISA::htog(tgt->st_size); 469 tgt->st_atimeX = host->st_atime; 470 tgt->st_atimeX = TheISA::htog(tgt->st_atimeX); 471 tgt->st_mtimeX = host->st_mtime; 472 tgt->st_mtimeX = TheISA::htog(tgt->st_mtimeX); 473 tgt->st_ctimeX = host->st_ctime; 474 tgt->st_ctimeX = TheISA::htog(tgt->st_ctimeX); 475 // Force the block size to be 8KB. This helps to ensure buffered io works 476 // consistently across different hosts. 477 tgt->st_blksize = 0x2000; 478 tgt->st_blksize = TheISA::htog(tgt->st_blksize); 479 tgt->st_blocks = host->st_blocks; 480 tgt->st_blocks = TheISA::htog(tgt->st_blocks); 481} 482 483// Same for stat64 484 485template <typename target_stat, typename host_stat64> 486void 487convertStat64Buf(target_stat &tgt, host_stat64 *host, bool fakeTTY = false) 488{ 489 using namespace TheISA; 490 491 convertStatBuf<target_stat, host_stat64>(tgt, host, fakeTTY); 492#if defined(STAT_HAVE_NSEC) 493 tgt->st_atime_nsec = host->st_atime_nsec; 494 tgt->st_atime_nsec = TheISA::htog(tgt->st_atime_nsec); 495 tgt->st_mtime_nsec = host->st_mtime_nsec; 496 tgt->st_mtime_nsec = TheISA::htog(tgt->st_mtime_nsec); 497 tgt->st_ctime_nsec = host->st_ctime_nsec; 498 tgt->st_ctime_nsec = TheISA::htog(tgt->st_ctime_nsec); 499#else 500 tgt->st_atime_nsec = 0; 501 tgt->st_mtime_nsec = 0; 502 tgt->st_ctime_nsec = 0; 503#endif 504} 505 506// Here are a couple of convenience functions 507template<class OS> 508void 509copyOutStatBuf(SETranslatingPortProxy &mem, Addr addr, 510 hst_stat *host, bool fakeTTY = false) 511{ 512 typedef TypedBufferArg<typename OS::tgt_stat> tgt_stat_buf; 513 tgt_stat_buf tgt(addr); 514 convertStatBuf<tgt_stat_buf, hst_stat>(tgt, host, fakeTTY); 515 tgt.copyOut(mem); 516} 517 518template<class OS> 519void 520copyOutStat64Buf(SETranslatingPortProxy &mem, Addr addr, 521 hst_stat64 *host, bool fakeTTY = false) 522{ 523 typedef TypedBufferArg<typename OS::tgt_stat64> tgt_stat_buf; 524 tgt_stat_buf tgt(addr); 525 convertStat64Buf<tgt_stat_buf, hst_stat64>(tgt, host, fakeTTY); 526 tgt.copyOut(mem); 527} 528 529template <class OS> 530void 531copyOutStatfsBuf(SETranslatingPortProxy &mem, Addr addr, 532 hst_statfs *host) 533{ 534 TypedBufferArg<typename OS::tgt_statfs> tgt(addr); 535 536 tgt->f_type = TheISA::htog(host->f_type); 537#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) 538 tgt->f_bsize = TheISA::htog(host->f_iosize); 539#else 540 tgt->f_bsize = TheISA::htog(host->f_bsize); 541#endif 542 tgt->f_blocks = TheISA::htog(host->f_blocks); 543 tgt->f_bfree = TheISA::htog(host->f_bfree); 544 tgt->f_bavail = TheISA::htog(host->f_bavail); 545 tgt->f_files = TheISA::htog(host->f_files); 546 tgt->f_ffree = TheISA::htog(host->f_ffree); 547 memcpy(&tgt->f_fsid, &host->f_fsid, sizeof(host->f_fsid)); 548#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) 549 tgt->f_namelen = TheISA::htog(host->f_namemax); 550 tgt->f_frsize = TheISA::htog(host->f_bsize); 551#elif defined(__APPLE__) 552 tgt->f_namelen = 0; 553 tgt->f_frsize = 0; 554#else 555 tgt->f_namelen = TheISA::htog(host->f_namelen); 556 tgt->f_frsize = TheISA::htog(host->f_frsize); 557#endif 558#if defined(__linux__) 559 memcpy(&tgt->f_spare, &host->f_spare, sizeof(host->f_spare)); 560#else 561 /* 562 * The fields are different sizes per OS. Don't bother with 563 * f_spare or f_reserved on non-Linux for now. 564 */ 565 memset(&tgt->f_spare, 0, sizeof(tgt->f_spare)); 566#endif 567 568 tgt.copyOut(mem); 569} 570 571/// Target ioctl() handler. For the most part, programs call ioctl() 572/// only to find out if their stdout is a tty, to determine whether to 573/// do line or block buffering. We always claim that output fds are 574/// not TTYs to provide repeatable results. 575template <class OS> 576SyscallReturn 577ioctlFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 578{ 579 int index = 0; 580 int tgt_fd = p->getSyscallArg(tc, index); 581 unsigned req = p->getSyscallArg(tc, index); 582 583 DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", tgt_fd, req); 584 585 if (OS::isTtyReq(req)) 586 return -ENOTTY; 587 588 auto dfdp = std::dynamic_pointer_cast<DeviceFDEntry>((*p->fds)[tgt_fd]); 589 if (!dfdp) 590 return -EBADF; 591 592 /** 593 * If the driver is valid, issue the ioctl through it. Otherwise, 594 * there's an implicit assumption that the device is a TTY type and we 595 * return that we do not have a valid TTY. 596 */ 597 EmulatedDriver *emul_driver = dfdp->getDriver(); 598 if (emul_driver) 599 return emul_driver->ioctl(p, tc, req); 600 601 /** 602 * For lack of a better return code, return ENOTTY. Ideally, we should 603 * return something better here, but at least we issue the warning. 604 */ 605 warn("Unsupported ioctl call (return ENOTTY): ioctl(%d, 0x%x, ...) @ \n", 606 tgt_fd, req, tc->pcState()); 607 return -ENOTTY; 608} 609 610template <class OS> 611SyscallReturn 612openImpl(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc, 613 bool isopenat) 614{ 615 int index = 0; 616 int tgt_dirfd = -1; 617 618 /** 619 * If using the openat variant, read in the target directory file 620 * descriptor from the simulated process. 621 */ 622 if (isopenat) 623 tgt_dirfd = p->getSyscallArg(tc, index); 624 625 /** 626 * Retrieve the simulated process' memory proxy and then read in the path 627 * string from that memory space into the host's working memory space. 628 */ 629 std::string path; 630 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 631 return -EFAULT; 632 633#ifdef __CYGWIN32__ 634 int host_flags = O_BINARY; 635#else 636 int host_flags = 0; 637#endif 638 /** 639 * Translate target flags into host flags. Flags exist which are not 640 * ported between architectures which can cause check failures. 641 */ 642 int tgt_flags = p->getSyscallArg(tc, index); 643 for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) { 644 if (tgt_flags & OS::openFlagTable[i].tgtFlag) { 645 tgt_flags &= ~OS::openFlagTable[i].tgtFlag; 646 host_flags |= OS::openFlagTable[i].hostFlag; 647 } 648 } 649 if (tgt_flags) { 650 warn("open%s: cannot decode flags 0x%x", 651 isopenat ? "at" : "", tgt_flags); 652 } 653#ifdef __CYGWIN32__ 654 host_flags |= O_BINARY; 655#endif 656 657 int mode = p->getSyscallArg(tc, index); 658 659 /** 660 * If the simulated process called open or openat with AT_FDCWD specified, 661 * take the current working directory value which was passed into the 662 * process class as a Python parameter and append the current path to 663 * create a full path. 664 * Otherwise, openat with a valid target directory file descriptor has 665 * been called. If the path option, which was passed in as a parameter, 666 * is not absolute, retrieve the directory file descriptor's path and 667 * prepend it to the path passed in as a parameter. 668 * In every case, we should have a full path (which is relevant to the 669 * host) to work with after this block has been passed. 670 */ 671 if (!isopenat || (isopenat && tgt_dirfd == OS::TGT_AT_FDCWD)) { 672 path = p->fullPath(path); 673 } else if (!startswith(path, "/")) { 674 std::shared_ptr<FDEntry> fdep = ((*p->fds)[tgt_dirfd]); 675 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep); 676 if (!ffdp) 677 return -EBADF; 678 path.insert(0, ffdp->getFileName()); 679 } 680 681 /** 682 * Since this is an emulated environment, we create pseudo file 683 * descriptors for device requests that have been registered with 684 * the process class through Python; this allows us to create a file 685 * descriptor for subsequent ioctl or mmap calls. 686 */ 687 if (startswith(path, "/dev/")) { 688 std::string filename = path.substr(strlen("/dev/")); 689 EmulatedDriver *drv = p->findDriver(filename); 690 if (drv) { 691 DPRINTF_SYSCALL(Verbose, "open%s: passing call to " 692 "driver open with path[%s]\n", 693 isopenat ? "at" : "", path.c_str()); 694 return drv->open(p, tc, mode, host_flags); 695 } 696 /** 697 * Fall through here for pass through to host devices, such 698 * as /dev/zero 699 */ 700 } 701 702 /** 703 * Some special paths and files cannot be called on the host and need 704 * to be handled as special cases inside the simulator. 705 * If the full path that was created above does not match any of the 706 * special cases, pass it through to the open call on the host to let 707 * the host open the file on our behalf. 708 * If the host cannot open the file, return the host's error code back 709 * through the system call to the simulated process. 710 */ 711 int sim_fd = -1; 712 std::vector<std::string> special_paths = 713 { "/proc/", "/system/", "/sys/", "/platform/", "/etc/passwd" }; 714 for (auto entry : special_paths) { 715 if (startswith(path, entry)) 716 sim_fd = OS::openSpecialFile(path, p, tc); 717 } 718 if (sim_fd == -1) { 719 sim_fd = open(path.c_str(), host_flags, mode); 720 } 721 if (sim_fd == -1) { 722 int local = -errno; 723 DPRINTF_SYSCALL(Verbose, "open%s: failed -> path:%s\n", 724 isopenat ? "at" : "", path.c_str()); 725 return local; 726 } 727 728 /** 729 * The file was opened successfully and needs to be recorded in the 730 * process' file descriptor array so that it can be retrieved later. 731 * The target file descriptor that is chosen will be the lowest unused 732 * file descriptor. 733 * Return the indirect target file descriptor back to the simulated 734 * process to act as a handle for the opened file. 735 */ 736 auto ffdp = std::make_shared<FileFDEntry>(sim_fd, host_flags, path, 0); 737 int tgt_fd = p->fds->allocFD(ffdp); 738 DPRINTF_SYSCALL(Verbose, "open%s: sim_fd[%d], target_fd[%d] -> path:%s\n", 739 isopenat ? "at" : "", sim_fd, tgt_fd, path.c_str()); 740 return tgt_fd; 741} 742 743/// Target open() handler. 744template <class OS> 745SyscallReturn 746openFunc(SyscallDesc *desc, int callnum, Process *process, 747 ThreadContext *tc) 748{ 749 return openImpl<OS>(desc, callnum, process, tc, false); 750} 751 752/// Target openat() handler. 753template <class OS> 754SyscallReturn 755openatFunc(SyscallDesc *desc, int callnum, Process *process, 756 ThreadContext *tc) 757{ 758 return openImpl<OS>(desc, callnum, process, tc, true); 759} 760 761/// Target unlinkat() handler. 762template <class OS> 763SyscallReturn 764unlinkatFunc(SyscallDesc *desc, int callnum, Process *process, 765 ThreadContext *tc) 766{ 767 int index = 0; 768 int dirfd = process->getSyscallArg(tc, index); 769 if (dirfd != OS::TGT_AT_FDCWD) 770 warn("unlinkat: first argument not AT_FDCWD; unlikely to work"); 771 772 return unlinkHelper(desc, callnum, process, tc, 1); 773} 774 775/// Target facessat() handler 776template <class OS> 777SyscallReturn 778faccessatFunc(SyscallDesc *desc, int callnum, Process *process, 779 ThreadContext *tc) 780{ 781 int index = 0; 782 int dirfd = process->getSyscallArg(tc, index); 783 if (dirfd != OS::TGT_AT_FDCWD) 784 warn("faccessat: first argument not AT_FDCWD; unlikely to work"); 785 return accessFunc(desc, callnum, process, tc, 1); 786} 787 788/// Target readlinkat() handler 789template <class OS> 790SyscallReturn 791readlinkatFunc(SyscallDesc *desc, int callnum, Process *process, 792 ThreadContext *tc) 793{ 794 int index = 0; 795 int dirfd = process->getSyscallArg(tc, index); 796 if (dirfd != OS::TGT_AT_FDCWD) 797 warn("openat: first argument not AT_FDCWD; unlikely to work"); 798 return readlinkFunc(desc, callnum, process, tc, 1); 799} 800 801/// Target renameat() handler. 802template <class OS> 803SyscallReturn 804renameatFunc(SyscallDesc *desc, int callnum, Process *process, 805 ThreadContext *tc) 806{ 807 int index = 0; 808 809 int olddirfd = process->getSyscallArg(tc, index); 810 if (olddirfd != OS::TGT_AT_FDCWD) 811 warn("renameat: first argument not AT_FDCWD; unlikely to work"); 812 813 std::string old_name; 814 815 if (!tc->getMemProxy().tryReadString(old_name, 816 process->getSyscallArg(tc, index))) 817 return -EFAULT; 818 819 int newdirfd = process->getSyscallArg(tc, index); 820 if (newdirfd != OS::TGT_AT_FDCWD) 821 warn("renameat: third argument not AT_FDCWD; unlikely to work"); 822 823 std::string new_name; 824 825 if (!tc->getMemProxy().tryReadString(new_name, 826 process->getSyscallArg(tc, index))) 827 return -EFAULT; 828 829 // Adjust path for current working directory 830 old_name = process->fullPath(old_name); 831 new_name = process->fullPath(new_name); 832 833 int result = rename(old_name.c_str(), new_name.c_str()); 834 return (result == -1) ? -errno : result; 835} 836 837/// Target sysinfo() handler. 838template <class OS> 839SyscallReturn 840sysinfoFunc(SyscallDesc *desc, int callnum, Process *process, 841 ThreadContext *tc) 842{ 843 844 int index = 0; 845 TypedBufferArg<typename OS::tgt_sysinfo> 846 sysinfo(process->getSyscallArg(tc, index)); 847 848 sysinfo->uptime = seconds_since_epoch; 849 sysinfo->totalram = process->system->memSize(); 850 sysinfo->mem_unit = 1; 851 852 sysinfo.copyOut(tc->getMemProxy()); 853 854 return 0; 855} 856 857/// Target chmod() handler. 858template <class OS> 859SyscallReturn 860chmodFunc(SyscallDesc *desc, int callnum, Process *process, 861 ThreadContext *tc) 862{ 863 std::string path; 864 865 int index = 0; 866 if (!tc->getMemProxy().tryReadString(path, 867 process->getSyscallArg(tc, index))) { 868 return -EFAULT; 869 } 870 871 uint32_t mode = process->getSyscallArg(tc, index); 872 mode_t hostMode = 0; 873 874 // XXX translate mode flags via OS::something??? 875 hostMode = mode; 876 877 // Adjust path for current working directory 878 path = process->fullPath(path); 879 880 // do the chmod 881 int result = chmod(path.c_str(), hostMode); 882 if (result < 0) 883 return -errno; 884 885 return 0; 886} 887 888 889/// Target fchmod() handler. 890template <class OS> 891SyscallReturn 892fchmodFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 893{ 894 int index = 0; 895 int tgt_fd = p->getSyscallArg(tc, index); 896 uint32_t mode = p->getSyscallArg(tc, index); 897 898 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 899 if (!ffdp) 900 return -EBADF; 901 int sim_fd = ffdp->getSimFD(); 902 903 mode_t hostMode = mode; 904 905 int result = fchmod(sim_fd, hostMode); 906 907 return (result < 0) ? -errno : 0; 908} 909 910/// Target mremap() handler. 911template <class OS> 912SyscallReturn 913mremapFunc(SyscallDesc *desc, int callnum, Process *process, ThreadContext *tc) 914{ 915 int index = 0; 916 Addr start = process->getSyscallArg(tc, index); 917 uint64_t old_length = process->getSyscallArg(tc, index); 918 uint64_t new_length = process->getSyscallArg(tc, index); 919 uint64_t flags = process->getSyscallArg(tc, index); 920 uint64_t provided_address = 0; 921 bool use_provided_address = flags & OS::TGT_MREMAP_FIXED; 922 923 if (use_provided_address) 924 provided_address = process->getSyscallArg(tc, index); 925 926 if ((start % TheISA::PageBytes != 0) || 927 (provided_address % TheISA::PageBytes != 0)) { 928 warn("mremap failing: arguments not page aligned"); 929 return -EINVAL; 930 } 931 932 new_length = roundUp(new_length, TheISA::PageBytes); 933 934 if (new_length > old_length) { 935 std::shared_ptr<MemState> mem_state = process->memState; 936 Addr mmap_end = mem_state->getMmapEnd(); 937 938 if ((start + old_length) == mmap_end && 939 (!use_provided_address || provided_address == start)) { 940 // This case cannot occur when growing downward, as 941 // start is greater than or equal to mmap_end. 942 uint64_t diff = new_length - old_length; 943 process->allocateMem(mmap_end, diff); 944 mem_state->setMmapEnd(mmap_end + diff); 945 return start; 946 } else { 947 if (!use_provided_address && !(flags & OS::TGT_MREMAP_MAYMOVE)) { 948 warn("can't remap here and MREMAP_MAYMOVE flag not set\n"); 949 return -ENOMEM; 950 } else { 951 uint64_t new_start = provided_address; 952 if (!use_provided_address) { 953 new_start = process->mmapGrowsDown() ? 954 mmap_end - new_length : mmap_end; 955 mmap_end = process->mmapGrowsDown() ? 956 new_start : mmap_end + new_length; 957 mem_state->setMmapEnd(mmap_end); 958 } 959 960 process->pTable->remap(start, old_length, new_start); 961 warn("mremapping to new vaddr %08p-%08p, adding %d\n", 962 new_start, new_start + new_length, 963 new_length - old_length); 964 // add on the remaining unallocated pages 965 process->allocateMem(new_start + old_length, 966 new_length - old_length, 967 use_provided_address /* clobber */); 968 if (use_provided_address && 969 ((new_start + new_length > mem_state->getMmapEnd() && 970 !process->mmapGrowsDown()) || 971 (new_start < mem_state->getMmapEnd() && 972 process->mmapGrowsDown()))) { 973 // something fishy going on here, at least notify the user 974 // @todo: increase mmap_end? 975 warn("mmap region limit exceeded with MREMAP_FIXED\n"); 976 } 977 warn("returning %08p as start\n", new_start); 978 return new_start; 979 } 980 } 981 } else { 982 if (use_provided_address && provided_address != start) 983 process->pTable->remap(start, new_length, provided_address); 984 process->pTable->unmap(start + new_length, old_length - new_length); 985 return use_provided_address ? provided_address : start; 986 } 987} 988 989/// Target stat() handler. 990template <class OS> 991SyscallReturn 992statFunc(SyscallDesc *desc, int callnum, Process *process, 993 ThreadContext *tc) 994{ 995 std::string path; 996 997 int index = 0; 998 if (!tc->getMemProxy().tryReadString(path, 999 process->getSyscallArg(tc, index))) { 1000 return -EFAULT; 1001 } 1002 Addr bufPtr = process->getSyscallArg(tc, index); 1003 1004 // Adjust path for current working directory 1005 path = process->fullPath(path); 1006 1007 struct stat hostBuf; 1008 int result = stat(path.c_str(), &hostBuf); 1009 1010 if (result < 0) 1011 return -errno; 1012 1013 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1014 1015 return 0; 1016} 1017 1018 1019/// Target stat64() handler. 1020template <class OS> 1021SyscallReturn 1022stat64Func(SyscallDesc *desc, int callnum, Process *process, 1023 ThreadContext *tc) 1024{ 1025 std::string path; 1026 1027 int index = 0; 1028 if (!tc->getMemProxy().tryReadString(path, 1029 process->getSyscallArg(tc, index))) 1030 return -EFAULT; 1031 Addr bufPtr = process->getSyscallArg(tc, index); 1032 1033 // Adjust path for current working directory 1034 path = process->fullPath(path); 1035 1036#if NO_STAT64 1037 struct stat hostBuf; 1038 int result = stat(path.c_str(), &hostBuf); 1039#else 1040 struct stat64 hostBuf; 1041 int result = stat64(path.c_str(), &hostBuf); 1042#endif 1043 1044 if (result < 0) 1045 return -errno; 1046 1047 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1048 1049 return 0; 1050} 1051 1052 1053/// Target fstatat64() handler. 1054template <class OS> 1055SyscallReturn 1056fstatat64Func(SyscallDesc *desc, int callnum, Process *process, 1057 ThreadContext *tc) 1058{ 1059 int index = 0; 1060 int dirfd = process->getSyscallArg(tc, index); 1061 if (dirfd != OS::TGT_AT_FDCWD) 1062 warn("fstatat64: first argument not AT_FDCWD; unlikely to work"); 1063 1064 std::string path; 1065 if (!tc->getMemProxy().tryReadString(path, 1066 process->getSyscallArg(tc, index))) 1067 return -EFAULT; 1068 Addr bufPtr = process->getSyscallArg(tc, index); 1069 1070 // Adjust path for current working directory 1071 path = process->fullPath(path); 1072 1073#if NO_STAT64 1074 struct stat hostBuf; 1075 int result = stat(path.c_str(), &hostBuf); 1076#else 1077 struct stat64 hostBuf; 1078 int result = stat64(path.c_str(), &hostBuf); 1079#endif 1080 1081 if (result < 0) 1082 return -errno; 1083 1084 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1085 1086 return 0; 1087} 1088 1089 1090/// Target fstat64() handler. 1091template <class OS> 1092SyscallReturn 1093fstat64Func(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1094{ 1095 int index = 0; 1096 int tgt_fd = p->getSyscallArg(tc, index); 1097 Addr bufPtr = p->getSyscallArg(tc, index); 1098 1099 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 1100 if (!ffdp) 1101 return -EBADF; 1102 int sim_fd = ffdp->getSimFD(); 1103 1104#if NO_STAT64 1105 struct stat hostBuf; 1106 int result = fstat(sim_fd, &hostBuf); 1107#else 1108 struct stat64 hostBuf; 1109 int result = fstat64(sim_fd, &hostBuf); 1110#endif 1111 1112 if (result < 0) 1113 return -errno; 1114 1115 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (sim_fd == 1)); 1116 1117 return 0; 1118} 1119 1120 1121/// Target lstat() handler. 1122template <class OS> 1123SyscallReturn 1124lstatFunc(SyscallDesc *desc, int callnum, Process *process, 1125 ThreadContext *tc) 1126{ 1127 std::string path; 1128 1129 int index = 0; 1130 if (!tc->getMemProxy().tryReadString(path, 1131 process->getSyscallArg(tc, index))) { 1132 return -EFAULT; 1133 } 1134 Addr bufPtr = process->getSyscallArg(tc, index); 1135 1136 // Adjust path for current working directory 1137 path = process->fullPath(path); 1138 1139 struct stat hostBuf; 1140 int result = lstat(path.c_str(), &hostBuf); 1141 1142 if (result < 0) 1143 return -errno; 1144 1145 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1146 1147 return 0; 1148} 1149 1150/// Target lstat64() handler. 1151template <class OS> 1152SyscallReturn 1153lstat64Func(SyscallDesc *desc, int callnum, Process *process, 1154 ThreadContext *tc) 1155{ 1156 std::string path; 1157 1158 int index = 0; 1159 if (!tc->getMemProxy().tryReadString(path, 1160 process->getSyscallArg(tc, index))) { 1161 return -EFAULT; 1162 } 1163 Addr bufPtr = process->getSyscallArg(tc, index); 1164 1165 // Adjust path for current working directory 1166 path = process->fullPath(path); 1167 1168#if NO_STAT64 1169 struct stat hostBuf; 1170 int result = lstat(path.c_str(), &hostBuf); 1171#else 1172 struct stat64 hostBuf; 1173 int result = lstat64(path.c_str(), &hostBuf); 1174#endif 1175 1176 if (result < 0) 1177 return -errno; 1178 1179 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1180 1181 return 0; 1182} 1183 1184/// Target fstat() handler. 1185template <class OS> 1186SyscallReturn 1187fstatFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1188{ 1189 int index = 0; 1190 int tgt_fd = p->getSyscallArg(tc, index); 1191 Addr bufPtr = p->getSyscallArg(tc, index); 1192 1193 DPRINTF_SYSCALL(Verbose, "fstat(%d, ...)\n", tgt_fd); 1194 1195 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 1196 if (!ffdp) 1197 return -EBADF; 1198 int sim_fd = ffdp->getSimFD(); 1199 1200 struct stat hostBuf; 1201 int result = fstat(sim_fd, &hostBuf); 1202 1203 if (result < 0) 1204 return -errno; 1205 1206 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (sim_fd == 1)); 1207 1208 return 0; 1209} 1210 1211 1212/// Target statfs() handler. 1213template <class OS> 1214SyscallReturn 1215statfsFunc(SyscallDesc *desc, int callnum, Process *process, 1216 ThreadContext *tc) 1217{ 1218#if NO_STATFS 1219 warn("Host OS cannot support calls to statfs. Ignoring syscall"); 1220#else 1221 std::string path; 1222 1223 int index = 0; 1224 if (!tc->getMemProxy().tryReadString(path, 1225 process->getSyscallArg(tc, index))) { 1226 return -EFAULT; 1227 } 1228 Addr bufPtr = process->getSyscallArg(tc, index); 1229 1230 // Adjust path for current working directory 1231 path = process->fullPath(path); 1232 1233 struct statfs hostBuf; 1234 int result = statfs(path.c_str(), &hostBuf); 1235 1236 if (result < 0) 1237 return -errno; 1238 1239 copyOutStatfsBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1240#endif 1241 return 0; 1242} 1243 1244template <class OS> 1245SyscallReturn 1246cloneFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1247{ 1248 int index = 0; 1249 1250 TheISA::IntReg flags = p->getSyscallArg(tc, index); 1251 TheISA::IntReg newStack = p->getSyscallArg(tc, index); 1252 Addr ptidPtr = p->getSyscallArg(tc, index); 1253 1254#if THE_ISA == RISCV_ISA 1255 /** 1256 * Linux kernel 4.15 sets CLONE_BACKWARDS flag for RISC-V. 1257 * The flag defines the list of clone() arguments in the following 1258 * order: flags -> newStack -> ptidPtr -> tlsPtr -> ctidPtr 1259 */ 1260 Addr tlsPtr M5_VAR_USED = p->getSyscallArg(tc, index); 1261 Addr ctidPtr = p->getSyscallArg(tc, index); 1262#else 1263 Addr ctidPtr = p->getSyscallArg(tc, index); 1264 Addr tlsPtr M5_VAR_USED = p->getSyscallArg(tc, index); 1265#endif 1266 1267 if (((flags & OS::TGT_CLONE_SIGHAND)&& !(flags & OS::TGT_CLONE_VM)) || 1268 ((flags & OS::TGT_CLONE_THREAD) && !(flags & OS::TGT_CLONE_SIGHAND)) || 1269 ((flags & OS::TGT_CLONE_FS) && (flags & OS::TGT_CLONE_NEWNS)) || 1270 ((flags & OS::TGT_CLONE_NEWIPC) && (flags & OS::TGT_CLONE_SYSVSEM)) || 1271 ((flags & OS::TGT_CLONE_NEWPID) && (flags & OS::TGT_CLONE_THREAD)) || 1272 ((flags & OS::TGT_CLONE_VM) && !(newStack))) 1273 return -EINVAL; 1274 1275 ThreadContext *ctc; 1276 if (!(ctc = p->findFreeContext())) 1277 fatal("clone: no spare thread context in system"); 1278 1279 /** 1280 * Note that ProcessParams is generated by swig and there are no other 1281 * examples of how to create anything but this default constructor. The 1282 * fields are manually initialized instead of passing parameters to the 1283 * constructor. 1284 */ 1285 ProcessParams *pp = new ProcessParams(); 1286 pp->executable.assign(*(new std::string(p->progName()))); 1287 pp->cmd.push_back(*(new std::string(p->progName()))); 1288 pp->system = p->system; 1289 pp->cwd.assign(p->getcwd()); 1290 pp->input.assign("stdin"); 1291 pp->output.assign("stdout"); 1292 pp->errout.assign("stderr"); 1293 pp->uid = p->uid(); 1294 pp->euid = p->euid(); 1295 pp->gid = p->gid(); 1296 pp->egid = p->egid(); 1297 1298 /* Find the first free PID that's less than the maximum */ 1299 std::set<int> const& pids = p->system->PIDs; 1300 int temp_pid = *pids.begin(); 1301 do { 1302 temp_pid++; 1303 } while (pids.find(temp_pid) != pids.end()); 1304 if (temp_pid >= System::maxPID) 1305 fatal("temp_pid is too large: %d", temp_pid); 1306 1307 pp->pid = temp_pid; 1308 pp->ppid = (flags & OS::TGT_CLONE_THREAD) ? p->ppid() : p->pid(); 1309 Process *cp = pp->create(); 1310 delete pp; 1311 1312 Process *owner = ctc->getProcessPtr(); 1313 ctc->setProcessPtr(cp); 1314 cp->assignThreadContext(ctc->contextId()); 1315 owner->revokeThreadContext(ctc->contextId()); 1316 1317 if (flags & OS::TGT_CLONE_PARENT_SETTID) { 1318 BufferArg ptidBuf(ptidPtr, sizeof(long)); 1319 long *ptid = (long *)ptidBuf.bufferPtr(); 1320 *ptid = cp->pid(); 1321 ptidBuf.copyOut(tc->getMemProxy()); 1322 } 1323 1324 cp->initState(); 1325 p->clone(tc, ctc, cp, flags); 1326 1327 if (flags & OS::TGT_CLONE_THREAD) { 1328 delete cp->sigchld; 1329 cp->sigchld = p->sigchld; 1330 } else if (flags & OS::TGT_SIGCHLD) { 1331 *cp->sigchld = true; 1332 } 1333 1334 if (flags & OS::TGT_CLONE_CHILD_SETTID) { 1335 BufferArg ctidBuf(ctidPtr, sizeof(long)); 1336 long *ctid = (long *)ctidBuf.bufferPtr(); 1337 *ctid = cp->pid(); 1338 ctidBuf.copyOut(ctc->getMemProxy()); 1339 } 1340 1341 if (flags & OS::TGT_CLONE_CHILD_CLEARTID) 1342 cp->childClearTID = (uint64_t)ctidPtr; 1343 1344 ctc->clearArchRegs(); 1345 1346#if THE_ISA == ALPHA_ISA 1347 TheISA::copyMiscRegs(tc, ctc); 1348#elif THE_ISA == SPARC_ISA 1349 TheISA::copyRegs(tc, ctc); 1350 ctc->setIntReg(TheISA::NumIntArchRegs + 6, 0); 1351 ctc->setIntReg(TheISA::NumIntArchRegs + 4, 0); 1352 ctc->setIntReg(TheISA::NumIntArchRegs + 3, TheISA::NWindows - 2); 1353 ctc->setIntReg(TheISA::NumIntArchRegs + 5, TheISA::NWindows); 1354 ctc->setMiscReg(TheISA::MISCREG_CWP, 0); 1355 ctc->setIntReg(TheISA::NumIntArchRegs + 7, 0); 1356 ctc->setMiscRegNoEffect(TheISA::MISCREG_TL, 0); 1357 ctc->setMiscReg(TheISA::MISCREG_ASI, TheISA::ASI_PRIMARY); 1358 for (int y = 8; y < 32; y++) 1359 ctc->setIntReg(y, tc->readIntReg(y)); 1360#elif THE_ISA == ARM_ISA or THE_ISA == X86_ISA or THE_ISA == RISCV_ISA 1361 TheISA::copyRegs(tc, ctc); 1362#endif 1363 1364#if THE_ISA == X86_ISA 1365 if (flags & OS::TGT_CLONE_SETTLS) { 1366 ctc->setMiscRegNoEffect(TheISA::MISCREG_FS_BASE, tlsPtr); 1367 ctc->setMiscRegNoEffect(TheISA::MISCREG_FS_EFF_BASE, tlsPtr); 1368 } 1369#endif 1370 1371 if (newStack) 1372 ctc->setIntReg(TheISA::StackPointerReg, newStack); 1373 1374 cp->setSyscallReturn(ctc, 0); 1375 1376#if THE_ISA == ALPHA_ISA 1377 ctc->setIntReg(TheISA::SyscallSuccessReg, 0); 1378#elif THE_ISA == SPARC_ISA 1379 tc->setIntReg(TheISA::SyscallPseudoReturnReg, 0); 1380 ctc->setIntReg(TheISA::SyscallPseudoReturnReg, 1); 1381#endif 1382 1383 ctc->pcState(tc->nextInstAddr()); 1384 ctc->activate(); 1385 1386 return cp->pid(); 1387} 1388 1389/// Target fstatfs() handler. 1390template <class OS> 1391SyscallReturn 1392fstatfsFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1393{ 1394 int index = 0; 1395 int tgt_fd = p->getSyscallArg(tc, index); 1396 Addr bufPtr = p->getSyscallArg(tc, index); 1397 1398 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 1399 if (!ffdp) 1400 return -EBADF; 1401 int sim_fd = ffdp->getSimFD(); 1402 1403 struct statfs hostBuf; 1404 int result = fstatfs(sim_fd, &hostBuf); 1405 1406 if (result < 0) 1407 return -errno; 1408 1409 copyOutStatfsBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1410 1411 return 0; 1412} 1413 1414 1415/// Target writev() handler. 1416template <class OS> 1417SyscallReturn 1418writevFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1419{ 1420 int index = 0; 1421 int tgt_fd = p->getSyscallArg(tc, index); 1422 1423 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 1424 if (!hbfdp) 1425 return -EBADF; 1426 int sim_fd = hbfdp->getSimFD(); 1427 1428 SETranslatingPortProxy &prox = tc->getMemProxy(); 1429 uint64_t tiov_base = p->getSyscallArg(tc, index); 1430 size_t count = p->getSyscallArg(tc, index); 1431 struct iovec hiov[count]; 1432 for (size_t i = 0; i < count; ++i) { 1433 typename OS::tgt_iovec tiov; 1434 1435 prox.readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec), 1436 (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec)); 1437 hiov[i].iov_len = TheISA::gtoh(tiov.iov_len); 1438 hiov[i].iov_base = new char [hiov[i].iov_len]; 1439 prox.readBlob(TheISA::gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base, 1440 hiov[i].iov_len); 1441 } 1442 1443 int result = writev(sim_fd, hiov, count); 1444 1445 for (size_t i = 0; i < count; ++i) 1446 delete [] (char *)hiov[i].iov_base; 1447 1448 if (result < 0) 1449 return -errno; 1450 1451 return result; 1452} 1453 1454/// Real mmap handler. 1455template <class OS> 1456SyscallReturn 1457mmapImpl(SyscallDesc *desc, int num, Process *p, ThreadContext *tc, 1458 bool is_mmap2) 1459{ 1460 int index = 0; 1461 Addr start = p->getSyscallArg(tc, index); 1462 uint64_t length = p->getSyscallArg(tc, index); 1463 int prot = p->getSyscallArg(tc, index); 1464 int tgt_flags = p->getSyscallArg(tc, index); 1465 int tgt_fd = p->getSyscallArg(tc, index); 1466 int offset = p->getSyscallArg(tc, index); 1467 1468 if (is_mmap2) 1469 offset *= TheISA::PageBytes; 1470 1471 if (start & (TheISA::PageBytes - 1) || 1472 offset & (TheISA::PageBytes - 1) || 1473 (tgt_flags & OS::TGT_MAP_PRIVATE && 1474 tgt_flags & OS::TGT_MAP_SHARED) || 1475 (!(tgt_flags & OS::TGT_MAP_PRIVATE) && 1476 !(tgt_flags & OS::TGT_MAP_SHARED)) || 1477 !length) { 1478 return -EINVAL; 1479 } 1480 1481 if ((prot & PROT_WRITE) && (tgt_flags & OS::TGT_MAP_SHARED)) { 1482 // With shared mmaps, there are two cases to consider: 1483 // 1) anonymous: writes should modify the mapping and this should be 1484 // visible to observers who share the mapping. Currently, it's 1485 // difficult to update the shared mapping because there's no 1486 // structure which maintains information about the which virtual 1487 // memory areas are shared. If that structure existed, it would be 1488 // possible to make the translations point to the same frames. 1489 // 2) file-backed: writes should modify the mapping and the file 1490 // which is backed by the mapping. The shared mapping problem is the 1491 // same as what was mentioned about the anonymous mappings. For 1492 // file-backed mappings, the writes to the file are difficult 1493 // because it requires syncing what the mapping holds with the file 1494 // that resides on the host system. So, any write on a real system 1495 // would cause the change to be propagated to the file mapping at 1496 // some point in the future (the inode is tracked along with the 1497 // mapping). This isn't guaranteed to always happen, but it usually 1498 // works well enough. The guarantee is provided by the msync system 1499 // call. We could force the change through with shared mappings with 1500 // a call to msync, but that again would require more information 1501 // than we currently maintain. 1502 warn("mmap: writing to shared mmap region is currently " 1503 "unsupported. The write succeeds on the target, but it " 1504 "will not be propagated to the host or shared mappings"); 1505 } 1506 1507 length = roundUp(length, TheISA::PageBytes); 1508 1509 int sim_fd = -1; 1510 uint8_t *pmap = nullptr; 1511 if (!(tgt_flags & OS::TGT_MAP_ANONYMOUS)) { 1512 std::shared_ptr<FDEntry> fdep = (*p->fds)[tgt_fd]; 1513 1514 auto dfdp = std::dynamic_pointer_cast<DeviceFDEntry>(fdep); 1515 if (dfdp) { 1516 EmulatedDriver *emul_driver = dfdp->getDriver(); 1517 return emul_driver->mmap(p, tc, start, length, prot, 1518 tgt_flags, tgt_fd, offset); 1519 } 1520 1521 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep); 1522 if (!ffdp) 1523 return -EBADF; 1524 sim_fd = ffdp->getSimFD(); 1525 1526 pmap = (decltype(pmap))mmap(nullptr, length, PROT_READ, MAP_PRIVATE, 1527 sim_fd, offset); 1528 1529 if (pmap == (decltype(pmap))-1) { 1530 warn("mmap: failed to map file into host address space"); 1531 return -errno; 1532 } 1533 } 1534 1535 // Extend global mmap region if necessary. Note that we ignore the 1536 // start address unless MAP_FIXED is specified. 1537 if (!(tgt_flags & OS::TGT_MAP_FIXED)) { 1538 std::shared_ptr<MemState> mem_state = p->memState; 1539 Addr mmap_end = mem_state->getMmapEnd(); 1540 1541 start = p->mmapGrowsDown() ? mmap_end - length : mmap_end; 1542 mmap_end = p->mmapGrowsDown() ? start : mmap_end + length; 1543 1544 mem_state->setMmapEnd(mmap_end); 1545 } 1546 1547 DPRINTF_SYSCALL(Verbose, " mmap range is 0x%x - 0x%x\n", 1548 start, start + length - 1); 1549 1550 // We only allow mappings to overwrite existing mappings if 1551 // TGT_MAP_FIXED is set. Otherwise it shouldn't be a problem 1552 // because we ignore the start hint if TGT_MAP_FIXED is not set. 1553 int clobber = tgt_flags & OS::TGT_MAP_FIXED; 1554 if (clobber) { 1555 for (auto tc : p->system->threadContexts) { 1556 // If we might be overwriting old mappings, we need to 1557 // invalidate potentially stale mappings out of the TLBs. 1558 tc->getDTBPtr()->flushAll(); 1559 tc->getITBPtr()->flushAll(); 1560 } 1561 } 1562 1563 // Allocate physical memory and map it in. If the page table is already 1564 // mapped and clobber is not set, the simulator will issue throw a 1565 // fatal and bail out of the simulation. 1566 p->allocateMem(start, length, clobber); 1567 1568 // Transfer content into target address space. 1569 SETranslatingPortProxy &tp = tc->getMemProxy(); 1570 if (tgt_flags & OS::TGT_MAP_ANONYMOUS) { 1571 // In general, we should zero the mapped area for anonymous mappings, 1572 // with something like: 1573 // tp.memsetBlob(start, 0, length); 1574 // However, given that we don't support sparse mappings, and 1575 // some applications can map a couple of gigabytes of space 1576 // (intending sparse usage), that can get painfully expensive. 1577 // Fortunately, since we don't properly implement munmap either, 1578 // there's no danger of remapping used memory, so for now all 1579 // newly mapped memory should already be zeroed so we can skip it. 1580 } else { 1581 // It is possible to mmap an area larger than a file, however 1582 // accessing unmapped portions the system triggers a "Bus error" 1583 // on the host. We must know when to stop copying the file from 1584 // the host into the target address space. 1585 struct stat file_stat; 1586 if (fstat(sim_fd, &file_stat) > 0) 1587 fatal("mmap: cannot stat file"); 1588 1589 // Copy the portion of the file that is resident. This requires 1590 // checking both the mmap size and the filesize that we are 1591 // trying to mmap into this space; the mmap size also depends 1592 // on the specified offset into the file. 1593 uint64_t size = std::min((uint64_t)file_stat.st_size - offset, 1594 length); 1595 tp.writeBlob(start, pmap, size); 1596 1597 // Cleanup the mmap region before exiting this function. 1598 munmap(pmap, length); 1599 1600 // Maintain the symbol table for dynamic executables. 1601 // The loader will call mmap to map the images into its address 1602 // space and we intercept that here. We can verify that we are 1603 // executing inside the loader by checking the program counter value. 1604 // XXX: with multiprogrammed workloads or multi-node configurations, 1605 // this will not work since there is a single global symbol table. 1606 ObjectFile *interpreter = p->getInterpreter(); 1607 if (interpreter) { 1608 Addr text_start = interpreter->textBase(); 1609 Addr text_end = text_start + interpreter->textSize(); 1610 1611 Addr pc = tc->pcState().pc(); 1612 1613 if (pc >= text_start && pc < text_end) { 1614 std::shared_ptr<FDEntry> fdep = (*p->fds)[tgt_fd]; 1615 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep); 1616 ObjectFile *lib = createObjectFile(ffdp->getFileName()); 1617 1618 if (lib) { 1619 lib->loadAllSymbols(debugSymbolTable, 1620 lib->textBase(), start); 1621 } 1622 } 1623 } 1624 1625 // Note that we do not zero out the remainder of the mapping. This 1626 // is done by a real system, but it probably will not affect 1627 // execution (hopefully). 1628 } 1629 1630 return start; 1631} 1632 1633template <class OS> 1634SyscallReturn 1635pwrite64Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1636{ 1637 int index = 0; 1638 int tgt_fd = p->getSyscallArg(tc, index); 1639 Addr bufPtr = p->getSyscallArg(tc, index); 1640 int nbytes = p->getSyscallArg(tc, index); 1641 int offset = p->getSyscallArg(tc, index); 1642 1643 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 1644 if (!ffdp) 1645 return -EBADF; 1646 int sim_fd = ffdp->getSimFD(); 1647 1648 BufferArg bufArg(bufPtr, nbytes); 1649 bufArg.copyIn(tc->getMemProxy()); 1650 1651 int bytes_written = pwrite(sim_fd, bufArg.bufferPtr(), nbytes, offset); 1652 1653 return (bytes_written == -1) ? -errno : bytes_written; 1654} 1655 1656/// Target mmap() handler. 1657template <class OS> 1658SyscallReturn 1659mmapFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1660{ 1661 return mmapImpl<OS>(desc, num, p, tc, false); 1662} 1663 1664/// Target mmap2() handler. 1665template <class OS> 1666SyscallReturn 1667mmap2Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1668{ 1669 return mmapImpl<OS>(desc, num, p, tc, true); 1670} 1671 1672/// Target getrlimit() handler. 1673template <class OS> 1674SyscallReturn 1675getrlimitFunc(SyscallDesc *desc, int callnum, Process *process, 1676 ThreadContext *tc) 1677{ 1678 int index = 0; 1679 unsigned resource = process->getSyscallArg(tc, index); 1680 TypedBufferArg<typename OS::rlimit> rlp(process->getSyscallArg(tc, index)); 1681 1682 switch (resource) { 1683 case OS::TGT_RLIMIT_STACK: 1684 // max stack size in bytes: make up a number (8MB for now) 1685 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; 1686 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1687 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1688 break; 1689 1690 case OS::TGT_RLIMIT_DATA: 1691 // max data segment size in bytes: make up a number 1692 rlp->rlim_cur = rlp->rlim_max = 256 * 1024 * 1024; 1693 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1694 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1695 break; 1696 1697 default: 1698 warn("getrlimit: unimplemented resource %d", resource); 1699 return -EINVAL; 1700 break; 1701 } 1702 1703 rlp.copyOut(tc->getMemProxy()); 1704 return 0; 1705} 1706 1707template <class OS> 1708SyscallReturn 1709prlimitFunc(SyscallDesc *desc, int callnum, Process *process, 1710 ThreadContext *tc) 1711{ 1712 int index = 0; 1713 if (process->getSyscallArg(tc, index) != 0) 1714 { 1715 warn("prlimit: ignoring rlimits for nonzero pid"); 1716 return -EPERM; 1717 } 1718 int resource = process->getSyscallArg(tc, index); 1719 Addr n = process->getSyscallArg(tc, index); 1720 if (n != 0) 1721 warn("prlimit: ignoring new rlimit"); 1722 Addr o = process->getSyscallArg(tc, index); 1723 if (o != 0) 1724 { 1725 TypedBufferArg<typename OS::rlimit> rlp(o); 1726 switch (resource) { 1727 case OS::TGT_RLIMIT_STACK: 1728 // max stack size in bytes: make up a number (8MB for now) 1729 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; 1730 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1731 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1732 break; 1733 case OS::TGT_RLIMIT_DATA: 1734 // max data segment size in bytes: make up a number 1735 rlp->rlim_cur = rlp->rlim_max = 256*1024*1024; 1736 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1737 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1738 break; 1739 default: 1740 warn("prlimit: unimplemented resource %d", resource); 1741 return -EINVAL; 1742 break; 1743 } 1744 rlp.copyOut(tc->getMemProxy()); 1745 } 1746 return 0; 1747} 1748 1749/// Target clock_gettime() function. 1750template <class OS> 1751SyscallReturn 1752clock_gettimeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1753{ 1754 int index = 1; 1755 //int clk_id = p->getSyscallArg(tc, index); 1756 TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index)); 1757 1758 getElapsedTimeNano(tp->tv_sec, tp->tv_nsec); 1759 tp->tv_sec += seconds_since_epoch; 1760 tp->tv_sec = TheISA::htog(tp->tv_sec); 1761 tp->tv_nsec = TheISA::htog(tp->tv_nsec); 1762 1763 tp.copyOut(tc->getMemProxy()); 1764 1765 return 0; 1766} 1767 1768/// Target clock_getres() function. 1769template <class OS> 1770SyscallReturn 1771clock_getresFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1772{ 1773 int index = 1; 1774 TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index)); 1775 1776 // Set resolution at ns, which is what clock_gettime() returns 1777 tp->tv_sec = 0; 1778 tp->tv_nsec = 1; 1779 1780 tp.copyOut(tc->getMemProxy()); 1781 1782 return 0; 1783} 1784 1785/// Target gettimeofday() handler. 1786template <class OS> 1787SyscallReturn 1788gettimeofdayFunc(SyscallDesc *desc, int callnum, Process *process, 1789 ThreadContext *tc) 1790{ 1791 int index = 0; 1792 TypedBufferArg<typename OS::timeval> tp(process->getSyscallArg(tc, index)); 1793 1794 getElapsedTimeMicro(tp->tv_sec, tp->tv_usec); 1795 tp->tv_sec += seconds_since_epoch; 1796 tp->tv_sec = TheISA::htog(tp->tv_sec); 1797 tp->tv_usec = TheISA::htog(tp->tv_usec); 1798 1799 tp.copyOut(tc->getMemProxy()); 1800 1801 return 0; 1802} 1803 1804 1805/// Target utimes() handler. 1806template <class OS> 1807SyscallReturn 1808utimesFunc(SyscallDesc *desc, int callnum, Process *process, 1809 ThreadContext *tc) 1810{ 1811 std::string path; 1812 1813 int index = 0; 1814 if (!tc->getMemProxy().tryReadString(path, 1815 process->getSyscallArg(tc, index))) { 1816 return -EFAULT; 1817 } 1818 1819 TypedBufferArg<typename OS::timeval [2]> 1820 tp(process->getSyscallArg(tc, index)); 1821 tp.copyIn(tc->getMemProxy()); 1822 1823 struct timeval hostTimeval[2]; 1824 for (int i = 0; i < 2; ++i) { 1825 hostTimeval[i].tv_sec = TheISA::gtoh((*tp)[i].tv_sec); 1826 hostTimeval[i].tv_usec = TheISA::gtoh((*tp)[i].tv_usec); 1827 } 1828 1829 // Adjust path for current working directory 1830 path = process->fullPath(path); 1831 1832 int result = utimes(path.c_str(), hostTimeval); 1833 1834 if (result < 0) 1835 return -errno; 1836 1837 return 0; 1838} 1839 1840template <class OS> 1841SyscallReturn 1842execveFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1843{ 1844 desc->setFlags(0); 1845 1846 int index = 0; 1847 std::string path; 1848 SETranslatingPortProxy & mem_proxy = tc->getMemProxy(); 1849 if (!mem_proxy.tryReadString(path, p->getSyscallArg(tc, index))) 1850 return -EFAULT; 1851 1852 if (access(path.c_str(), F_OK) == -1) 1853 return -EACCES; 1854 1855 auto read_in = [](std::vector<std::string> & vect, 1856 SETranslatingPortProxy & mem_proxy, 1857 Addr mem_loc) 1858 { 1859 for (int inc = 0; ; inc++) { 1860 BufferArg b((mem_loc + sizeof(Addr) * inc), sizeof(Addr)); 1861 b.copyIn(mem_proxy); 1862 1863 if (!*(Addr*)b.bufferPtr()) 1864 break; 1865 1866 vect.push_back(std::string()); 1867 mem_proxy.tryReadString(vect[inc], *(Addr*)b.bufferPtr()); 1868 } 1869 }; 1870 1871 /** 1872 * Note that ProcessParams is generated by swig and there are no other 1873 * examples of how to create anything but this default constructor. The 1874 * fields are manually initialized instead of passing parameters to the 1875 * constructor. 1876 */ 1877 ProcessParams *pp = new ProcessParams(); 1878 pp->executable = path; 1879 Addr argv_mem_loc = p->getSyscallArg(tc, index); 1880 read_in(pp->cmd, mem_proxy, argv_mem_loc); 1881 Addr envp_mem_loc = p->getSyscallArg(tc, index); 1882 read_in(pp->env, mem_proxy, envp_mem_loc); 1883 pp->uid = p->uid(); 1884 pp->egid = p->egid(); 1885 pp->euid = p->euid(); 1886 pp->gid = p->gid(); 1887 pp->ppid = p->ppid(); 1888 pp->pid = p->pid(); 1889 pp->input.assign("cin"); 1890 pp->output.assign("cout"); 1891 pp->errout.assign("cerr"); 1892 pp->cwd.assign(p->getcwd()); 1893 pp->system = p->system; 1894 /** 1895 * Prevent process object creation with identical PIDs (which will trip 1896 * a fatal check in Process constructor). The execve call is supposed to 1897 * take over the currently executing process' identity but replace 1898 * whatever it is doing with a new process image. Instead of hijacking 1899 * the process object in the simulator, we create a new process object 1900 * and bind to the previous process' thread below (hijacking the thread). 1901 */ 1902 p->system->PIDs.erase(p->pid()); 1903 Process *new_p = pp->create(); 1904 delete pp; 1905 1906 /** 1907 * Work through the file descriptor array and close any files marked 1908 * close-on-exec. 1909 */ 1910 new_p->fds = p->fds; 1911 for (int i = 0; i < new_p->fds->getSize(); i++) { 1912 std::shared_ptr<FDEntry> fdep = (*new_p->fds)[i]; 1913 if (fdep && fdep->getCOE()) 1914 new_p->fds->closeFDEntry(i); 1915 } 1916 1917 *new_p->sigchld = true; 1918 1919 delete p; 1920 tc->clearArchRegs(); 1921 tc->setProcessPtr(new_p); 1922 new_p->assignThreadContext(tc->contextId()); 1923 new_p->initState(); 1924 tc->activate(); 1925 TheISA::PCState pcState = tc->pcState(); 1926 tc->setNPC(pcState.instAddr()); 1927 1928 desc->setFlags(SyscallDesc::SuppressReturnValue); 1929 return 0; 1930} 1931 1932/// Target getrusage() function. 1933template <class OS> 1934SyscallReturn 1935getrusageFunc(SyscallDesc *desc, int callnum, Process *process, 1936 ThreadContext *tc) 1937{ 1938 int index = 0; 1939 int who = process->getSyscallArg(tc, index); // THREAD, SELF, or CHILDREN 1940 TypedBufferArg<typename OS::rusage> rup(process->getSyscallArg(tc, index)); 1941 1942 rup->ru_utime.tv_sec = 0; 1943 rup->ru_utime.tv_usec = 0; 1944 rup->ru_stime.tv_sec = 0; 1945 rup->ru_stime.tv_usec = 0; 1946 rup->ru_maxrss = 0; 1947 rup->ru_ixrss = 0; 1948 rup->ru_idrss = 0; 1949 rup->ru_isrss = 0; 1950 rup->ru_minflt = 0; 1951 rup->ru_majflt = 0; 1952 rup->ru_nswap = 0; 1953 rup->ru_inblock = 0; 1954 rup->ru_oublock = 0; 1955 rup->ru_msgsnd = 0; 1956 rup->ru_msgrcv = 0; 1957 rup->ru_nsignals = 0; 1958 rup->ru_nvcsw = 0; 1959 rup->ru_nivcsw = 0; 1960 1961 switch (who) { 1962 case OS::TGT_RUSAGE_SELF: 1963 getElapsedTimeMicro(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec); 1964 rup->ru_utime.tv_sec = TheISA::htog(rup->ru_utime.tv_sec); 1965 rup->ru_utime.tv_usec = TheISA::htog(rup->ru_utime.tv_usec); 1966 break; 1967 1968 case OS::TGT_RUSAGE_CHILDREN: 1969 // do nothing. We have no child processes, so they take no time. 1970 break; 1971 1972 default: 1973 // don't really handle THREAD or CHILDREN, but just warn and 1974 // plow ahead 1975 warn("getrusage() only supports RUSAGE_SELF. Parameter %d ignored.", 1976 who); 1977 } 1978 1979 rup.copyOut(tc->getMemProxy()); 1980 1981 return 0; 1982} 1983 1984/// Target times() function. 1985template <class OS> 1986SyscallReturn 1987timesFunc(SyscallDesc *desc, int callnum, Process *process, 1988 ThreadContext *tc) 1989{ 1990 int index = 0; 1991 TypedBufferArg<typename OS::tms> bufp(process->getSyscallArg(tc, index)); 1992 1993 // Fill in the time structure (in clocks) 1994 int64_t clocks = curTick() * OS::M5_SC_CLK_TCK / SimClock::Int::s; 1995 bufp->tms_utime = clocks; 1996 bufp->tms_stime = 0; 1997 bufp->tms_cutime = 0; 1998 bufp->tms_cstime = 0; 1999 2000 // Convert to host endianness 2001 bufp->tms_utime = TheISA::htog(bufp->tms_utime); 2002 2003 // Write back 2004 bufp.copyOut(tc->getMemProxy()); 2005 2006 // Return clock ticks since system boot 2007 return clocks; 2008} 2009 2010/// Target time() function. 2011template <class OS> 2012SyscallReturn 2013timeFunc(SyscallDesc *desc, int callnum, Process *process, ThreadContext *tc) 2014{ 2015 typename OS::time_t sec, usec; 2016 getElapsedTimeMicro(sec, usec); 2017 sec += seconds_since_epoch; 2018 2019 int index = 0; 2020 Addr taddr = (Addr)process->getSyscallArg(tc, index); 2021 if (taddr != 0) { 2022 typename OS::time_t t = sec; 2023 t = TheISA::htog(t); 2024 SETranslatingPortProxy &p = tc->getMemProxy(); 2025 p.writeBlob(taddr, (uint8_t*)&t, (int)sizeof(typename OS::time_t)); 2026 } 2027 return sec; 2028} 2029 2030template <class OS> 2031SyscallReturn 2032tgkillFunc(SyscallDesc *desc, int num, Process *process, ThreadContext *tc) 2033{ 2034 int index = 0; 2035 int tgid = process->getSyscallArg(tc, index); 2036 int tid = process->getSyscallArg(tc, index); 2037 int sig = process->getSyscallArg(tc, index); 2038 2039 /** 2040 * This system call is intended to allow killing a specific thread 2041 * within an arbitrary thread group if sanctioned with permission checks. 2042 * It's usually true that threads share the termination signal as pointed 2043 * out by the pthread_kill man page and this seems to be the intended 2044 * usage. Due to this being an emulated environment, assume the following: 2045 * Threads are allowed to call tgkill because the EUID for all threads 2046 * should be the same. There is no signal handling mechanism for kernel 2047 * registration of signal handlers since signals are poorly supported in 2048 * emulation mode. Since signal handlers cannot be registered, all 2049 * threads within in a thread group must share the termination signal. 2050 * We never exhaust PIDs so there's no chance of finding the wrong one 2051 * due to PID rollover. 2052 */ 2053 2054 System *sys = tc->getSystemPtr(); 2055 Process *tgt_proc = nullptr; 2056 for (int i = 0; i < sys->numContexts(); i++) { 2057 Process *temp = sys->threadContexts[i]->getProcessPtr(); 2058 if (temp->pid() == tid) { 2059 tgt_proc = temp; 2060 break; 2061 } 2062 } 2063 2064 if (sig != 0 || sig != OS::TGT_SIGABRT) 2065 return -EINVAL; 2066 2067 if (tgt_proc == nullptr) 2068 return -ESRCH; 2069 2070 if (tgid != -1 && tgt_proc->tgid() != tgid) 2071 return -ESRCH; 2072 2073 if (sig == OS::TGT_SIGABRT) 2074 exitGroupFunc(desc, 252, process, tc); 2075 2076 return 0; 2077} 2078 2079 2080#endif // __SIM_SYSCALL_EMUL_HH__
| 214/// Target mkdir() handler. 215SyscallReturn mkdirFunc(SyscallDesc *desc, int num, 216 Process *p, ThreadContext *tc); 217 218/// Target rename() handler. 219SyscallReturn renameFunc(SyscallDesc *desc, int num, 220 Process *p, ThreadContext *tc); 221 222 223/// Target truncate() handler. 224SyscallReturn truncateFunc(SyscallDesc *desc, int num, 225 Process *p, ThreadContext *tc); 226 227 228/// Target ftruncate() handler. 229SyscallReturn ftruncateFunc(SyscallDesc *desc, int num, 230 Process *p, ThreadContext *tc); 231 232 233/// Target truncate64() handler. 234SyscallReturn truncate64Func(SyscallDesc *desc, int num, 235 Process *p, ThreadContext *tc); 236 237/// Target ftruncate64() handler. 238SyscallReturn ftruncate64Func(SyscallDesc *desc, int num, 239 Process *p, ThreadContext *tc); 240 241 242/// Target umask() handler. 243SyscallReturn umaskFunc(SyscallDesc *desc, int num, 244 Process *p, ThreadContext *tc); 245 246/// Target gettid() handler. 247SyscallReturn gettidFunc(SyscallDesc *desc, int num, 248 Process *p, ThreadContext *tc); 249 250/// Target chown() handler. 251SyscallReturn chownFunc(SyscallDesc *desc, int num, 252 Process *p, ThreadContext *tc); 253 254/// Target setpgid() handler. 255SyscallReturn setpgidFunc(SyscallDesc *desc, int num, 256 Process *p, ThreadContext *tc); 257 258/// Target fchown() handler. 259SyscallReturn fchownFunc(SyscallDesc *desc, int num, 260 Process *p, ThreadContext *tc); 261 262/// Target dup() handler. 263SyscallReturn dupFunc(SyscallDesc *desc, int num, 264 Process *process, ThreadContext *tc); 265 266/// Target dup2() handler. 267SyscallReturn dup2Func(SyscallDesc *desc, int num, 268 Process *process, ThreadContext *tc); 269 270/// Target fcntl() handler. 271SyscallReturn fcntlFunc(SyscallDesc *desc, int num, 272 Process *process, ThreadContext *tc); 273 274/// Target fcntl64() handler. 275SyscallReturn fcntl64Func(SyscallDesc *desc, int num, 276 Process *process, ThreadContext *tc); 277 278/// Target setuid() handler. 279SyscallReturn setuidFunc(SyscallDesc *desc, int num, 280 Process *p, ThreadContext *tc); 281 282/// Target pipe() handler. 283SyscallReturn pipeFunc(SyscallDesc *desc, int num, 284 Process *p, ThreadContext *tc); 285 286/// Internal pipe() handler. 287SyscallReturn pipeImpl(SyscallDesc *desc, int num, Process *p, 288 ThreadContext *tc, bool pseudoPipe); 289 290/// Target getpid() handler. 291SyscallReturn getpidFunc(SyscallDesc *desc, int num, 292 Process *p, ThreadContext *tc); 293 294/// Target getuid() handler. 295SyscallReturn getuidFunc(SyscallDesc *desc, int num, 296 Process *p, ThreadContext *tc); 297 298/// Target getgid() handler. 299SyscallReturn getgidFunc(SyscallDesc *desc, int num, 300 Process *p, ThreadContext *tc); 301 302/// Target getppid() handler. 303SyscallReturn getppidFunc(SyscallDesc *desc, int num, 304 Process *p, ThreadContext *tc); 305 306/// Target geteuid() handler. 307SyscallReturn geteuidFunc(SyscallDesc *desc, int num, 308 Process *p, ThreadContext *tc); 309 310/// Target getegid() handler. 311SyscallReturn getegidFunc(SyscallDesc *desc, int num, 312 Process *p, ThreadContext *tc); 313 314/// Target access() handler 315SyscallReturn accessFunc(SyscallDesc *desc, int num, 316 Process *p, ThreadContext *tc); 317SyscallReturn accessFunc(SyscallDesc *desc, int num, 318 Process *p, ThreadContext *tc, 319 int index); 320 321/// Futex system call 322/// Implemented by Daniel Sanchez 323/// Used by printf's in multi-threaded apps 324template <class OS> 325SyscallReturn 326futexFunc(SyscallDesc *desc, int callnum, Process *process, 327 ThreadContext *tc) 328{ 329 using namespace std; 330 331 int index = 0; 332 Addr uaddr = process->getSyscallArg(tc, index); 333 int op = process->getSyscallArg(tc, index); 334 int val = process->getSyscallArg(tc, index); 335 336 /* 337 * Unsupported option that does not affect the correctness of the 338 * application. This is a performance optimization utilized by Linux. 339 */ 340 op &= ~OS::TGT_FUTEX_PRIVATE_FLAG; 341 342 FutexMap &futex_map = tc->getSystemPtr()->futexMap; 343 344 if (OS::TGT_FUTEX_WAIT == op) { 345 // Ensure futex system call accessed atomically. 346 BufferArg buf(uaddr, sizeof(int)); 347 buf.copyIn(tc->getMemProxy()); 348 int mem_val = *(int*)buf.bufferPtr(); 349 350 /* 351 * The value in memory at uaddr is not equal with the expected val 352 * (a different thread must have changed it before the system call was 353 * invoked). In this case, we need to throw an error. 354 */ 355 if (val != mem_val) 356 return -OS::TGT_EWOULDBLOCK; 357 358 futex_map.suspend(uaddr, process->tgid(), tc); 359 360 return 0; 361 } else if (OS::TGT_FUTEX_WAKE == op) { 362 return futex_map.wakeup(uaddr, process->tgid(), val); 363 } 364 365 warn("futex: op %d not implemented; ignoring.", op); 366 return -ENOSYS; 367} 368 369 370/// Pseudo Funcs - These functions use a different return convension, 371/// returning a second value in a register other than the normal return register 372SyscallReturn pipePseudoFunc(SyscallDesc *desc, int num, 373 Process *process, ThreadContext *tc); 374 375/// Target getpidPseudo() handler. 376SyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num, 377 Process *p, ThreadContext *tc); 378 379/// Target getuidPseudo() handler. 380SyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num, 381 Process *p, ThreadContext *tc); 382 383/// Target getgidPseudo() handler. 384SyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num, 385 Process *p, ThreadContext *tc); 386 387 388/// A readable name for 1,000,000, for converting microseconds to seconds. 389const int one_million = 1000000; 390/// A readable name for 1,000,000,000, for converting nanoseconds to seconds. 391const int one_billion = 1000000000; 392 393/// Approximate seconds since the epoch (1/1/1970). About a billion, 394/// by my reckoning. We want to keep this a constant (not use the 395/// real-world time) to keep simulations repeatable. 396const unsigned seconds_since_epoch = 1000000000; 397 398/// Helper function to convert current elapsed time to seconds and 399/// microseconds. 400template <class T1, class T2> 401void 402getElapsedTimeMicro(T1 &sec, T2 &usec) 403{ 404 uint64_t elapsed_usecs = curTick() / SimClock::Int::us; 405 sec = elapsed_usecs / one_million; 406 usec = elapsed_usecs % one_million; 407} 408 409/// Helper function to convert current elapsed time to seconds and 410/// nanoseconds. 411template <class T1, class T2> 412void 413getElapsedTimeNano(T1 &sec, T2 &nsec) 414{ 415 uint64_t elapsed_nsecs = curTick() / SimClock::Int::ns; 416 sec = elapsed_nsecs / one_billion; 417 nsec = elapsed_nsecs % one_billion; 418} 419 420////////////////////////////////////////////////////////////////////// 421// 422// The following emulation functions are generic, but need to be 423// templated to account for differences in types, constants, etc. 424// 425////////////////////////////////////////////////////////////////////// 426 427 typedef struct statfs hst_statfs; 428#if NO_STAT64 429 typedef struct stat hst_stat; 430 typedef struct stat hst_stat64; 431#else 432 typedef struct stat hst_stat; 433 typedef struct stat64 hst_stat64; 434#endif 435 436//// Helper function to convert a host stat buffer to a target stat 437//// buffer. Also copies the target buffer out to the simulated 438//// memory space. Used by stat(), fstat(), and lstat(). 439 440template <typename target_stat, typename host_stat> 441void 442convertStatBuf(target_stat &tgt, host_stat *host, bool fakeTTY = false) 443{ 444 using namespace TheISA; 445 446 if (fakeTTY) 447 tgt->st_dev = 0xA; 448 else 449 tgt->st_dev = host->st_dev; 450 tgt->st_dev = TheISA::htog(tgt->st_dev); 451 tgt->st_ino = host->st_ino; 452 tgt->st_ino = TheISA::htog(tgt->st_ino); 453 tgt->st_mode = host->st_mode; 454 if (fakeTTY) { 455 // Claim to be a character device 456 tgt->st_mode &= ~S_IFMT; // Clear S_IFMT 457 tgt->st_mode |= S_IFCHR; // Set S_IFCHR 458 } 459 tgt->st_mode = TheISA::htog(tgt->st_mode); 460 tgt->st_nlink = host->st_nlink; 461 tgt->st_nlink = TheISA::htog(tgt->st_nlink); 462 tgt->st_uid = host->st_uid; 463 tgt->st_uid = TheISA::htog(tgt->st_uid); 464 tgt->st_gid = host->st_gid; 465 tgt->st_gid = TheISA::htog(tgt->st_gid); 466 if (fakeTTY) 467 tgt->st_rdev = 0x880d; 468 else 469 tgt->st_rdev = host->st_rdev; 470 tgt->st_rdev = TheISA::htog(tgt->st_rdev); 471 tgt->st_size = host->st_size; 472 tgt->st_size = TheISA::htog(tgt->st_size); 473 tgt->st_atimeX = host->st_atime; 474 tgt->st_atimeX = TheISA::htog(tgt->st_atimeX); 475 tgt->st_mtimeX = host->st_mtime; 476 tgt->st_mtimeX = TheISA::htog(tgt->st_mtimeX); 477 tgt->st_ctimeX = host->st_ctime; 478 tgt->st_ctimeX = TheISA::htog(tgt->st_ctimeX); 479 // Force the block size to be 8KB. This helps to ensure buffered io works 480 // consistently across different hosts. 481 tgt->st_blksize = 0x2000; 482 tgt->st_blksize = TheISA::htog(tgt->st_blksize); 483 tgt->st_blocks = host->st_blocks; 484 tgt->st_blocks = TheISA::htog(tgt->st_blocks); 485} 486 487// Same for stat64 488 489template <typename target_stat, typename host_stat64> 490void 491convertStat64Buf(target_stat &tgt, host_stat64 *host, bool fakeTTY = false) 492{ 493 using namespace TheISA; 494 495 convertStatBuf<target_stat, host_stat64>(tgt, host, fakeTTY); 496#if defined(STAT_HAVE_NSEC) 497 tgt->st_atime_nsec = host->st_atime_nsec; 498 tgt->st_atime_nsec = TheISA::htog(tgt->st_atime_nsec); 499 tgt->st_mtime_nsec = host->st_mtime_nsec; 500 tgt->st_mtime_nsec = TheISA::htog(tgt->st_mtime_nsec); 501 tgt->st_ctime_nsec = host->st_ctime_nsec; 502 tgt->st_ctime_nsec = TheISA::htog(tgt->st_ctime_nsec); 503#else 504 tgt->st_atime_nsec = 0; 505 tgt->st_mtime_nsec = 0; 506 tgt->st_ctime_nsec = 0; 507#endif 508} 509 510// Here are a couple of convenience functions 511template<class OS> 512void 513copyOutStatBuf(SETranslatingPortProxy &mem, Addr addr, 514 hst_stat *host, bool fakeTTY = false) 515{ 516 typedef TypedBufferArg<typename OS::tgt_stat> tgt_stat_buf; 517 tgt_stat_buf tgt(addr); 518 convertStatBuf<tgt_stat_buf, hst_stat>(tgt, host, fakeTTY); 519 tgt.copyOut(mem); 520} 521 522template<class OS> 523void 524copyOutStat64Buf(SETranslatingPortProxy &mem, Addr addr, 525 hst_stat64 *host, bool fakeTTY = false) 526{ 527 typedef TypedBufferArg<typename OS::tgt_stat64> tgt_stat_buf; 528 tgt_stat_buf tgt(addr); 529 convertStat64Buf<tgt_stat_buf, hst_stat64>(tgt, host, fakeTTY); 530 tgt.copyOut(mem); 531} 532 533template <class OS> 534void 535copyOutStatfsBuf(SETranslatingPortProxy &mem, Addr addr, 536 hst_statfs *host) 537{ 538 TypedBufferArg<typename OS::tgt_statfs> tgt(addr); 539 540 tgt->f_type = TheISA::htog(host->f_type); 541#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) 542 tgt->f_bsize = TheISA::htog(host->f_iosize); 543#else 544 tgt->f_bsize = TheISA::htog(host->f_bsize); 545#endif 546 tgt->f_blocks = TheISA::htog(host->f_blocks); 547 tgt->f_bfree = TheISA::htog(host->f_bfree); 548 tgt->f_bavail = TheISA::htog(host->f_bavail); 549 tgt->f_files = TheISA::htog(host->f_files); 550 tgt->f_ffree = TheISA::htog(host->f_ffree); 551 memcpy(&tgt->f_fsid, &host->f_fsid, sizeof(host->f_fsid)); 552#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) 553 tgt->f_namelen = TheISA::htog(host->f_namemax); 554 tgt->f_frsize = TheISA::htog(host->f_bsize); 555#elif defined(__APPLE__) 556 tgt->f_namelen = 0; 557 tgt->f_frsize = 0; 558#else 559 tgt->f_namelen = TheISA::htog(host->f_namelen); 560 tgt->f_frsize = TheISA::htog(host->f_frsize); 561#endif 562#if defined(__linux__) 563 memcpy(&tgt->f_spare, &host->f_spare, sizeof(host->f_spare)); 564#else 565 /* 566 * The fields are different sizes per OS. Don't bother with 567 * f_spare or f_reserved on non-Linux for now. 568 */ 569 memset(&tgt->f_spare, 0, sizeof(tgt->f_spare)); 570#endif 571 572 tgt.copyOut(mem); 573} 574 575/// Target ioctl() handler. For the most part, programs call ioctl() 576/// only to find out if their stdout is a tty, to determine whether to 577/// do line or block buffering. We always claim that output fds are 578/// not TTYs to provide repeatable results. 579template <class OS> 580SyscallReturn 581ioctlFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 582{ 583 int index = 0; 584 int tgt_fd = p->getSyscallArg(tc, index); 585 unsigned req = p->getSyscallArg(tc, index); 586 587 DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", tgt_fd, req); 588 589 if (OS::isTtyReq(req)) 590 return -ENOTTY; 591 592 auto dfdp = std::dynamic_pointer_cast<DeviceFDEntry>((*p->fds)[tgt_fd]); 593 if (!dfdp) 594 return -EBADF; 595 596 /** 597 * If the driver is valid, issue the ioctl through it. Otherwise, 598 * there's an implicit assumption that the device is a TTY type and we 599 * return that we do not have a valid TTY. 600 */ 601 EmulatedDriver *emul_driver = dfdp->getDriver(); 602 if (emul_driver) 603 return emul_driver->ioctl(p, tc, req); 604 605 /** 606 * For lack of a better return code, return ENOTTY. Ideally, we should 607 * return something better here, but at least we issue the warning. 608 */ 609 warn("Unsupported ioctl call (return ENOTTY): ioctl(%d, 0x%x, ...) @ \n", 610 tgt_fd, req, tc->pcState()); 611 return -ENOTTY; 612} 613 614template <class OS> 615SyscallReturn 616openImpl(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc, 617 bool isopenat) 618{ 619 int index = 0; 620 int tgt_dirfd = -1; 621 622 /** 623 * If using the openat variant, read in the target directory file 624 * descriptor from the simulated process. 625 */ 626 if (isopenat) 627 tgt_dirfd = p->getSyscallArg(tc, index); 628 629 /** 630 * Retrieve the simulated process' memory proxy and then read in the path 631 * string from that memory space into the host's working memory space. 632 */ 633 std::string path; 634 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 635 return -EFAULT; 636 637#ifdef __CYGWIN32__ 638 int host_flags = O_BINARY; 639#else 640 int host_flags = 0; 641#endif 642 /** 643 * Translate target flags into host flags. Flags exist which are not 644 * ported between architectures which can cause check failures. 645 */ 646 int tgt_flags = p->getSyscallArg(tc, index); 647 for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) { 648 if (tgt_flags & OS::openFlagTable[i].tgtFlag) { 649 tgt_flags &= ~OS::openFlagTable[i].tgtFlag; 650 host_flags |= OS::openFlagTable[i].hostFlag; 651 } 652 } 653 if (tgt_flags) { 654 warn("open%s: cannot decode flags 0x%x", 655 isopenat ? "at" : "", tgt_flags); 656 } 657#ifdef __CYGWIN32__ 658 host_flags |= O_BINARY; 659#endif 660 661 int mode = p->getSyscallArg(tc, index); 662 663 /** 664 * If the simulated process called open or openat with AT_FDCWD specified, 665 * take the current working directory value which was passed into the 666 * process class as a Python parameter and append the current path to 667 * create a full path. 668 * Otherwise, openat with a valid target directory file descriptor has 669 * been called. If the path option, which was passed in as a parameter, 670 * is not absolute, retrieve the directory file descriptor's path and 671 * prepend it to the path passed in as a parameter. 672 * In every case, we should have a full path (which is relevant to the 673 * host) to work with after this block has been passed. 674 */ 675 if (!isopenat || (isopenat && tgt_dirfd == OS::TGT_AT_FDCWD)) { 676 path = p->fullPath(path); 677 } else if (!startswith(path, "/")) { 678 std::shared_ptr<FDEntry> fdep = ((*p->fds)[tgt_dirfd]); 679 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep); 680 if (!ffdp) 681 return -EBADF; 682 path.insert(0, ffdp->getFileName()); 683 } 684 685 /** 686 * Since this is an emulated environment, we create pseudo file 687 * descriptors for device requests that have been registered with 688 * the process class through Python; this allows us to create a file 689 * descriptor for subsequent ioctl or mmap calls. 690 */ 691 if (startswith(path, "/dev/")) { 692 std::string filename = path.substr(strlen("/dev/")); 693 EmulatedDriver *drv = p->findDriver(filename); 694 if (drv) { 695 DPRINTF_SYSCALL(Verbose, "open%s: passing call to " 696 "driver open with path[%s]\n", 697 isopenat ? "at" : "", path.c_str()); 698 return drv->open(p, tc, mode, host_flags); 699 } 700 /** 701 * Fall through here for pass through to host devices, such 702 * as /dev/zero 703 */ 704 } 705 706 /** 707 * Some special paths and files cannot be called on the host and need 708 * to be handled as special cases inside the simulator. 709 * If the full path that was created above does not match any of the 710 * special cases, pass it through to the open call on the host to let 711 * the host open the file on our behalf. 712 * If the host cannot open the file, return the host's error code back 713 * through the system call to the simulated process. 714 */ 715 int sim_fd = -1; 716 std::vector<std::string> special_paths = 717 { "/proc/", "/system/", "/sys/", "/platform/", "/etc/passwd" }; 718 for (auto entry : special_paths) { 719 if (startswith(path, entry)) 720 sim_fd = OS::openSpecialFile(path, p, tc); 721 } 722 if (sim_fd == -1) { 723 sim_fd = open(path.c_str(), host_flags, mode); 724 } 725 if (sim_fd == -1) { 726 int local = -errno; 727 DPRINTF_SYSCALL(Verbose, "open%s: failed -> path:%s\n", 728 isopenat ? "at" : "", path.c_str()); 729 return local; 730 } 731 732 /** 733 * The file was opened successfully and needs to be recorded in the 734 * process' file descriptor array so that it can be retrieved later. 735 * The target file descriptor that is chosen will be the lowest unused 736 * file descriptor. 737 * Return the indirect target file descriptor back to the simulated 738 * process to act as a handle for the opened file. 739 */ 740 auto ffdp = std::make_shared<FileFDEntry>(sim_fd, host_flags, path, 0); 741 int tgt_fd = p->fds->allocFD(ffdp); 742 DPRINTF_SYSCALL(Verbose, "open%s: sim_fd[%d], target_fd[%d] -> path:%s\n", 743 isopenat ? "at" : "", sim_fd, tgt_fd, path.c_str()); 744 return tgt_fd; 745} 746 747/// Target open() handler. 748template <class OS> 749SyscallReturn 750openFunc(SyscallDesc *desc, int callnum, Process *process, 751 ThreadContext *tc) 752{ 753 return openImpl<OS>(desc, callnum, process, tc, false); 754} 755 756/// Target openat() handler. 757template <class OS> 758SyscallReturn 759openatFunc(SyscallDesc *desc, int callnum, Process *process, 760 ThreadContext *tc) 761{ 762 return openImpl<OS>(desc, callnum, process, tc, true); 763} 764 765/// Target unlinkat() handler. 766template <class OS> 767SyscallReturn 768unlinkatFunc(SyscallDesc *desc, int callnum, Process *process, 769 ThreadContext *tc) 770{ 771 int index = 0; 772 int dirfd = process->getSyscallArg(tc, index); 773 if (dirfd != OS::TGT_AT_FDCWD) 774 warn("unlinkat: first argument not AT_FDCWD; unlikely to work"); 775 776 return unlinkHelper(desc, callnum, process, tc, 1); 777} 778 779/// Target facessat() handler 780template <class OS> 781SyscallReturn 782faccessatFunc(SyscallDesc *desc, int callnum, Process *process, 783 ThreadContext *tc) 784{ 785 int index = 0; 786 int dirfd = process->getSyscallArg(tc, index); 787 if (dirfd != OS::TGT_AT_FDCWD) 788 warn("faccessat: first argument not AT_FDCWD; unlikely to work"); 789 return accessFunc(desc, callnum, process, tc, 1); 790} 791 792/// Target readlinkat() handler 793template <class OS> 794SyscallReturn 795readlinkatFunc(SyscallDesc *desc, int callnum, Process *process, 796 ThreadContext *tc) 797{ 798 int index = 0; 799 int dirfd = process->getSyscallArg(tc, index); 800 if (dirfd != OS::TGT_AT_FDCWD) 801 warn("openat: first argument not AT_FDCWD; unlikely to work"); 802 return readlinkFunc(desc, callnum, process, tc, 1); 803} 804 805/// Target renameat() handler. 806template <class OS> 807SyscallReturn 808renameatFunc(SyscallDesc *desc, int callnum, Process *process, 809 ThreadContext *tc) 810{ 811 int index = 0; 812 813 int olddirfd = process->getSyscallArg(tc, index); 814 if (olddirfd != OS::TGT_AT_FDCWD) 815 warn("renameat: first argument not AT_FDCWD; unlikely to work"); 816 817 std::string old_name; 818 819 if (!tc->getMemProxy().tryReadString(old_name, 820 process->getSyscallArg(tc, index))) 821 return -EFAULT; 822 823 int newdirfd = process->getSyscallArg(tc, index); 824 if (newdirfd != OS::TGT_AT_FDCWD) 825 warn("renameat: third argument not AT_FDCWD; unlikely to work"); 826 827 std::string new_name; 828 829 if (!tc->getMemProxy().tryReadString(new_name, 830 process->getSyscallArg(tc, index))) 831 return -EFAULT; 832 833 // Adjust path for current working directory 834 old_name = process->fullPath(old_name); 835 new_name = process->fullPath(new_name); 836 837 int result = rename(old_name.c_str(), new_name.c_str()); 838 return (result == -1) ? -errno : result; 839} 840 841/// Target sysinfo() handler. 842template <class OS> 843SyscallReturn 844sysinfoFunc(SyscallDesc *desc, int callnum, Process *process, 845 ThreadContext *tc) 846{ 847 848 int index = 0; 849 TypedBufferArg<typename OS::tgt_sysinfo> 850 sysinfo(process->getSyscallArg(tc, index)); 851 852 sysinfo->uptime = seconds_since_epoch; 853 sysinfo->totalram = process->system->memSize(); 854 sysinfo->mem_unit = 1; 855 856 sysinfo.copyOut(tc->getMemProxy()); 857 858 return 0; 859} 860 861/// Target chmod() handler. 862template <class OS> 863SyscallReturn 864chmodFunc(SyscallDesc *desc, int callnum, Process *process, 865 ThreadContext *tc) 866{ 867 std::string path; 868 869 int index = 0; 870 if (!tc->getMemProxy().tryReadString(path, 871 process->getSyscallArg(tc, index))) { 872 return -EFAULT; 873 } 874 875 uint32_t mode = process->getSyscallArg(tc, index); 876 mode_t hostMode = 0; 877 878 // XXX translate mode flags via OS::something??? 879 hostMode = mode; 880 881 // Adjust path for current working directory 882 path = process->fullPath(path); 883 884 // do the chmod 885 int result = chmod(path.c_str(), hostMode); 886 if (result < 0) 887 return -errno; 888 889 return 0; 890} 891 892 893/// Target fchmod() handler. 894template <class OS> 895SyscallReturn 896fchmodFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 897{ 898 int index = 0; 899 int tgt_fd = p->getSyscallArg(tc, index); 900 uint32_t mode = p->getSyscallArg(tc, index); 901 902 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 903 if (!ffdp) 904 return -EBADF; 905 int sim_fd = ffdp->getSimFD(); 906 907 mode_t hostMode = mode; 908 909 int result = fchmod(sim_fd, hostMode); 910 911 return (result < 0) ? -errno : 0; 912} 913 914/// Target mremap() handler. 915template <class OS> 916SyscallReturn 917mremapFunc(SyscallDesc *desc, int callnum, Process *process, ThreadContext *tc) 918{ 919 int index = 0; 920 Addr start = process->getSyscallArg(tc, index); 921 uint64_t old_length = process->getSyscallArg(tc, index); 922 uint64_t new_length = process->getSyscallArg(tc, index); 923 uint64_t flags = process->getSyscallArg(tc, index); 924 uint64_t provided_address = 0; 925 bool use_provided_address = flags & OS::TGT_MREMAP_FIXED; 926 927 if (use_provided_address) 928 provided_address = process->getSyscallArg(tc, index); 929 930 if ((start % TheISA::PageBytes != 0) || 931 (provided_address % TheISA::PageBytes != 0)) { 932 warn("mremap failing: arguments not page aligned"); 933 return -EINVAL; 934 } 935 936 new_length = roundUp(new_length, TheISA::PageBytes); 937 938 if (new_length > old_length) { 939 std::shared_ptr<MemState> mem_state = process->memState; 940 Addr mmap_end = mem_state->getMmapEnd(); 941 942 if ((start + old_length) == mmap_end && 943 (!use_provided_address || provided_address == start)) { 944 // This case cannot occur when growing downward, as 945 // start is greater than or equal to mmap_end. 946 uint64_t diff = new_length - old_length; 947 process->allocateMem(mmap_end, diff); 948 mem_state->setMmapEnd(mmap_end + diff); 949 return start; 950 } else { 951 if (!use_provided_address && !(flags & OS::TGT_MREMAP_MAYMOVE)) { 952 warn("can't remap here and MREMAP_MAYMOVE flag not set\n"); 953 return -ENOMEM; 954 } else { 955 uint64_t new_start = provided_address; 956 if (!use_provided_address) { 957 new_start = process->mmapGrowsDown() ? 958 mmap_end - new_length : mmap_end; 959 mmap_end = process->mmapGrowsDown() ? 960 new_start : mmap_end + new_length; 961 mem_state->setMmapEnd(mmap_end); 962 } 963 964 process->pTable->remap(start, old_length, new_start); 965 warn("mremapping to new vaddr %08p-%08p, adding %d\n", 966 new_start, new_start + new_length, 967 new_length - old_length); 968 // add on the remaining unallocated pages 969 process->allocateMem(new_start + old_length, 970 new_length - old_length, 971 use_provided_address /* clobber */); 972 if (use_provided_address && 973 ((new_start + new_length > mem_state->getMmapEnd() && 974 !process->mmapGrowsDown()) || 975 (new_start < mem_state->getMmapEnd() && 976 process->mmapGrowsDown()))) { 977 // something fishy going on here, at least notify the user 978 // @todo: increase mmap_end? 979 warn("mmap region limit exceeded with MREMAP_FIXED\n"); 980 } 981 warn("returning %08p as start\n", new_start); 982 return new_start; 983 } 984 } 985 } else { 986 if (use_provided_address && provided_address != start) 987 process->pTable->remap(start, new_length, provided_address); 988 process->pTable->unmap(start + new_length, old_length - new_length); 989 return use_provided_address ? provided_address : start; 990 } 991} 992 993/// Target stat() handler. 994template <class OS> 995SyscallReturn 996statFunc(SyscallDesc *desc, int callnum, Process *process, 997 ThreadContext *tc) 998{ 999 std::string path; 1000 1001 int index = 0; 1002 if (!tc->getMemProxy().tryReadString(path, 1003 process->getSyscallArg(tc, index))) { 1004 return -EFAULT; 1005 } 1006 Addr bufPtr = process->getSyscallArg(tc, index); 1007 1008 // Adjust path for current working directory 1009 path = process->fullPath(path); 1010 1011 struct stat hostBuf; 1012 int result = stat(path.c_str(), &hostBuf); 1013 1014 if (result < 0) 1015 return -errno; 1016 1017 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1018 1019 return 0; 1020} 1021 1022 1023/// Target stat64() handler. 1024template <class OS> 1025SyscallReturn 1026stat64Func(SyscallDesc *desc, int callnum, Process *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 Addr bufPtr = process->getSyscallArg(tc, index); 1036 1037 // Adjust path for current working directory 1038 path = process->fullPath(path); 1039 1040#if NO_STAT64 1041 struct stat hostBuf; 1042 int result = stat(path.c_str(), &hostBuf); 1043#else 1044 struct stat64 hostBuf; 1045 int result = stat64(path.c_str(), &hostBuf); 1046#endif 1047 1048 if (result < 0) 1049 return -errno; 1050 1051 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1052 1053 return 0; 1054} 1055 1056 1057/// Target fstatat64() handler. 1058template <class OS> 1059SyscallReturn 1060fstatat64Func(SyscallDesc *desc, int callnum, Process *process, 1061 ThreadContext *tc) 1062{ 1063 int index = 0; 1064 int dirfd = process->getSyscallArg(tc, index); 1065 if (dirfd != OS::TGT_AT_FDCWD) 1066 warn("fstatat64: first argument not AT_FDCWD; unlikely to work"); 1067 1068 std::string path; 1069 if (!tc->getMemProxy().tryReadString(path, 1070 process->getSyscallArg(tc, index))) 1071 return -EFAULT; 1072 Addr bufPtr = process->getSyscallArg(tc, index); 1073 1074 // Adjust path for current working directory 1075 path = process->fullPath(path); 1076 1077#if NO_STAT64 1078 struct stat hostBuf; 1079 int result = stat(path.c_str(), &hostBuf); 1080#else 1081 struct stat64 hostBuf; 1082 int result = stat64(path.c_str(), &hostBuf); 1083#endif 1084 1085 if (result < 0) 1086 return -errno; 1087 1088 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1089 1090 return 0; 1091} 1092 1093 1094/// Target fstat64() handler. 1095template <class OS> 1096SyscallReturn 1097fstat64Func(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1098{ 1099 int index = 0; 1100 int tgt_fd = p->getSyscallArg(tc, index); 1101 Addr bufPtr = p->getSyscallArg(tc, index); 1102 1103 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 1104 if (!ffdp) 1105 return -EBADF; 1106 int sim_fd = ffdp->getSimFD(); 1107 1108#if NO_STAT64 1109 struct stat hostBuf; 1110 int result = fstat(sim_fd, &hostBuf); 1111#else 1112 struct stat64 hostBuf; 1113 int result = fstat64(sim_fd, &hostBuf); 1114#endif 1115 1116 if (result < 0) 1117 return -errno; 1118 1119 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (sim_fd == 1)); 1120 1121 return 0; 1122} 1123 1124 1125/// Target lstat() handler. 1126template <class OS> 1127SyscallReturn 1128lstatFunc(SyscallDesc *desc, int callnum, Process *process, 1129 ThreadContext *tc) 1130{ 1131 std::string path; 1132 1133 int index = 0; 1134 if (!tc->getMemProxy().tryReadString(path, 1135 process->getSyscallArg(tc, index))) { 1136 return -EFAULT; 1137 } 1138 Addr bufPtr = process->getSyscallArg(tc, index); 1139 1140 // Adjust path for current working directory 1141 path = process->fullPath(path); 1142 1143 struct stat hostBuf; 1144 int result = lstat(path.c_str(), &hostBuf); 1145 1146 if (result < 0) 1147 return -errno; 1148 1149 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1150 1151 return 0; 1152} 1153 1154/// Target lstat64() handler. 1155template <class OS> 1156SyscallReturn 1157lstat64Func(SyscallDesc *desc, int callnum, Process *process, 1158 ThreadContext *tc) 1159{ 1160 std::string path; 1161 1162 int index = 0; 1163 if (!tc->getMemProxy().tryReadString(path, 1164 process->getSyscallArg(tc, index))) { 1165 return -EFAULT; 1166 } 1167 Addr bufPtr = process->getSyscallArg(tc, index); 1168 1169 // Adjust path for current working directory 1170 path = process->fullPath(path); 1171 1172#if NO_STAT64 1173 struct stat hostBuf; 1174 int result = lstat(path.c_str(), &hostBuf); 1175#else 1176 struct stat64 hostBuf; 1177 int result = lstat64(path.c_str(), &hostBuf); 1178#endif 1179 1180 if (result < 0) 1181 return -errno; 1182 1183 copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1184 1185 return 0; 1186} 1187 1188/// Target fstat() handler. 1189template <class OS> 1190SyscallReturn 1191fstatFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1192{ 1193 int index = 0; 1194 int tgt_fd = p->getSyscallArg(tc, index); 1195 Addr bufPtr = p->getSyscallArg(tc, index); 1196 1197 DPRINTF_SYSCALL(Verbose, "fstat(%d, ...)\n", tgt_fd); 1198 1199 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 1200 if (!ffdp) 1201 return -EBADF; 1202 int sim_fd = ffdp->getSimFD(); 1203 1204 struct stat hostBuf; 1205 int result = fstat(sim_fd, &hostBuf); 1206 1207 if (result < 0) 1208 return -errno; 1209 1210 copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (sim_fd == 1)); 1211 1212 return 0; 1213} 1214 1215 1216/// Target statfs() handler. 1217template <class OS> 1218SyscallReturn 1219statfsFunc(SyscallDesc *desc, int callnum, Process *process, 1220 ThreadContext *tc) 1221{ 1222#if NO_STATFS 1223 warn("Host OS cannot support calls to statfs. Ignoring syscall"); 1224#else 1225 std::string path; 1226 1227 int index = 0; 1228 if (!tc->getMemProxy().tryReadString(path, 1229 process->getSyscallArg(tc, index))) { 1230 return -EFAULT; 1231 } 1232 Addr bufPtr = process->getSyscallArg(tc, index); 1233 1234 // Adjust path for current working directory 1235 path = process->fullPath(path); 1236 1237 struct statfs hostBuf; 1238 int result = statfs(path.c_str(), &hostBuf); 1239 1240 if (result < 0) 1241 return -errno; 1242 1243 copyOutStatfsBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1244#endif 1245 return 0; 1246} 1247 1248template <class OS> 1249SyscallReturn 1250cloneFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1251{ 1252 int index = 0; 1253 1254 TheISA::IntReg flags = p->getSyscallArg(tc, index); 1255 TheISA::IntReg newStack = p->getSyscallArg(tc, index); 1256 Addr ptidPtr = p->getSyscallArg(tc, index); 1257 1258#if THE_ISA == RISCV_ISA 1259 /** 1260 * Linux kernel 4.15 sets CLONE_BACKWARDS flag for RISC-V. 1261 * The flag defines the list of clone() arguments in the following 1262 * order: flags -> newStack -> ptidPtr -> tlsPtr -> ctidPtr 1263 */ 1264 Addr tlsPtr M5_VAR_USED = p->getSyscallArg(tc, index); 1265 Addr ctidPtr = p->getSyscallArg(tc, index); 1266#else 1267 Addr ctidPtr = p->getSyscallArg(tc, index); 1268 Addr tlsPtr M5_VAR_USED = p->getSyscallArg(tc, index); 1269#endif 1270 1271 if (((flags & OS::TGT_CLONE_SIGHAND)&& !(flags & OS::TGT_CLONE_VM)) || 1272 ((flags & OS::TGT_CLONE_THREAD) && !(flags & OS::TGT_CLONE_SIGHAND)) || 1273 ((flags & OS::TGT_CLONE_FS) && (flags & OS::TGT_CLONE_NEWNS)) || 1274 ((flags & OS::TGT_CLONE_NEWIPC) && (flags & OS::TGT_CLONE_SYSVSEM)) || 1275 ((flags & OS::TGT_CLONE_NEWPID) && (flags & OS::TGT_CLONE_THREAD)) || 1276 ((flags & OS::TGT_CLONE_VM) && !(newStack))) 1277 return -EINVAL; 1278 1279 ThreadContext *ctc; 1280 if (!(ctc = p->findFreeContext())) 1281 fatal("clone: no spare thread context in system"); 1282 1283 /** 1284 * Note that ProcessParams is generated by swig and there are no other 1285 * examples of how to create anything but this default constructor. The 1286 * fields are manually initialized instead of passing parameters to the 1287 * constructor. 1288 */ 1289 ProcessParams *pp = new ProcessParams(); 1290 pp->executable.assign(*(new std::string(p->progName()))); 1291 pp->cmd.push_back(*(new std::string(p->progName()))); 1292 pp->system = p->system; 1293 pp->cwd.assign(p->getcwd()); 1294 pp->input.assign("stdin"); 1295 pp->output.assign("stdout"); 1296 pp->errout.assign("stderr"); 1297 pp->uid = p->uid(); 1298 pp->euid = p->euid(); 1299 pp->gid = p->gid(); 1300 pp->egid = p->egid(); 1301 1302 /* Find the first free PID that's less than the maximum */ 1303 std::set<int> const& pids = p->system->PIDs; 1304 int temp_pid = *pids.begin(); 1305 do { 1306 temp_pid++; 1307 } while (pids.find(temp_pid) != pids.end()); 1308 if (temp_pid >= System::maxPID) 1309 fatal("temp_pid is too large: %d", temp_pid); 1310 1311 pp->pid = temp_pid; 1312 pp->ppid = (flags & OS::TGT_CLONE_THREAD) ? p->ppid() : p->pid(); 1313 Process *cp = pp->create(); 1314 delete pp; 1315 1316 Process *owner = ctc->getProcessPtr(); 1317 ctc->setProcessPtr(cp); 1318 cp->assignThreadContext(ctc->contextId()); 1319 owner->revokeThreadContext(ctc->contextId()); 1320 1321 if (flags & OS::TGT_CLONE_PARENT_SETTID) { 1322 BufferArg ptidBuf(ptidPtr, sizeof(long)); 1323 long *ptid = (long *)ptidBuf.bufferPtr(); 1324 *ptid = cp->pid(); 1325 ptidBuf.copyOut(tc->getMemProxy()); 1326 } 1327 1328 cp->initState(); 1329 p->clone(tc, ctc, cp, flags); 1330 1331 if (flags & OS::TGT_CLONE_THREAD) { 1332 delete cp->sigchld; 1333 cp->sigchld = p->sigchld; 1334 } else if (flags & OS::TGT_SIGCHLD) { 1335 *cp->sigchld = true; 1336 } 1337 1338 if (flags & OS::TGT_CLONE_CHILD_SETTID) { 1339 BufferArg ctidBuf(ctidPtr, sizeof(long)); 1340 long *ctid = (long *)ctidBuf.bufferPtr(); 1341 *ctid = cp->pid(); 1342 ctidBuf.copyOut(ctc->getMemProxy()); 1343 } 1344 1345 if (flags & OS::TGT_CLONE_CHILD_CLEARTID) 1346 cp->childClearTID = (uint64_t)ctidPtr; 1347 1348 ctc->clearArchRegs(); 1349 1350#if THE_ISA == ALPHA_ISA 1351 TheISA::copyMiscRegs(tc, ctc); 1352#elif THE_ISA == SPARC_ISA 1353 TheISA::copyRegs(tc, ctc); 1354 ctc->setIntReg(TheISA::NumIntArchRegs + 6, 0); 1355 ctc->setIntReg(TheISA::NumIntArchRegs + 4, 0); 1356 ctc->setIntReg(TheISA::NumIntArchRegs + 3, TheISA::NWindows - 2); 1357 ctc->setIntReg(TheISA::NumIntArchRegs + 5, TheISA::NWindows); 1358 ctc->setMiscReg(TheISA::MISCREG_CWP, 0); 1359 ctc->setIntReg(TheISA::NumIntArchRegs + 7, 0); 1360 ctc->setMiscRegNoEffect(TheISA::MISCREG_TL, 0); 1361 ctc->setMiscReg(TheISA::MISCREG_ASI, TheISA::ASI_PRIMARY); 1362 for (int y = 8; y < 32; y++) 1363 ctc->setIntReg(y, tc->readIntReg(y)); 1364#elif THE_ISA == ARM_ISA or THE_ISA == X86_ISA or THE_ISA == RISCV_ISA 1365 TheISA::copyRegs(tc, ctc); 1366#endif 1367 1368#if THE_ISA == X86_ISA 1369 if (flags & OS::TGT_CLONE_SETTLS) { 1370 ctc->setMiscRegNoEffect(TheISA::MISCREG_FS_BASE, tlsPtr); 1371 ctc->setMiscRegNoEffect(TheISA::MISCREG_FS_EFF_BASE, tlsPtr); 1372 } 1373#endif 1374 1375 if (newStack) 1376 ctc->setIntReg(TheISA::StackPointerReg, newStack); 1377 1378 cp->setSyscallReturn(ctc, 0); 1379 1380#if THE_ISA == ALPHA_ISA 1381 ctc->setIntReg(TheISA::SyscallSuccessReg, 0); 1382#elif THE_ISA == SPARC_ISA 1383 tc->setIntReg(TheISA::SyscallPseudoReturnReg, 0); 1384 ctc->setIntReg(TheISA::SyscallPseudoReturnReg, 1); 1385#endif 1386 1387 ctc->pcState(tc->nextInstAddr()); 1388 ctc->activate(); 1389 1390 return cp->pid(); 1391} 1392 1393/// Target fstatfs() handler. 1394template <class OS> 1395SyscallReturn 1396fstatfsFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1397{ 1398 int index = 0; 1399 int tgt_fd = p->getSyscallArg(tc, index); 1400 Addr bufPtr = p->getSyscallArg(tc, index); 1401 1402 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 1403 if (!ffdp) 1404 return -EBADF; 1405 int sim_fd = ffdp->getSimFD(); 1406 1407 struct statfs hostBuf; 1408 int result = fstatfs(sim_fd, &hostBuf); 1409 1410 if (result < 0) 1411 return -errno; 1412 1413 copyOutStatfsBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 1414 1415 return 0; 1416} 1417 1418 1419/// Target writev() handler. 1420template <class OS> 1421SyscallReturn 1422writevFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1423{ 1424 int index = 0; 1425 int tgt_fd = p->getSyscallArg(tc, index); 1426 1427 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 1428 if (!hbfdp) 1429 return -EBADF; 1430 int sim_fd = hbfdp->getSimFD(); 1431 1432 SETranslatingPortProxy &prox = tc->getMemProxy(); 1433 uint64_t tiov_base = p->getSyscallArg(tc, index); 1434 size_t count = p->getSyscallArg(tc, index); 1435 struct iovec hiov[count]; 1436 for (size_t i = 0; i < count; ++i) { 1437 typename OS::tgt_iovec tiov; 1438 1439 prox.readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec), 1440 (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec)); 1441 hiov[i].iov_len = TheISA::gtoh(tiov.iov_len); 1442 hiov[i].iov_base = new char [hiov[i].iov_len]; 1443 prox.readBlob(TheISA::gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base, 1444 hiov[i].iov_len); 1445 } 1446 1447 int result = writev(sim_fd, hiov, count); 1448 1449 for (size_t i = 0; i < count; ++i) 1450 delete [] (char *)hiov[i].iov_base; 1451 1452 if (result < 0) 1453 return -errno; 1454 1455 return result; 1456} 1457 1458/// Real mmap handler. 1459template <class OS> 1460SyscallReturn 1461mmapImpl(SyscallDesc *desc, int num, Process *p, ThreadContext *tc, 1462 bool is_mmap2) 1463{ 1464 int index = 0; 1465 Addr start = p->getSyscallArg(tc, index); 1466 uint64_t length = p->getSyscallArg(tc, index); 1467 int prot = p->getSyscallArg(tc, index); 1468 int tgt_flags = p->getSyscallArg(tc, index); 1469 int tgt_fd = p->getSyscallArg(tc, index); 1470 int offset = p->getSyscallArg(tc, index); 1471 1472 if (is_mmap2) 1473 offset *= TheISA::PageBytes; 1474 1475 if (start & (TheISA::PageBytes - 1) || 1476 offset & (TheISA::PageBytes - 1) || 1477 (tgt_flags & OS::TGT_MAP_PRIVATE && 1478 tgt_flags & OS::TGT_MAP_SHARED) || 1479 (!(tgt_flags & OS::TGT_MAP_PRIVATE) && 1480 !(tgt_flags & OS::TGT_MAP_SHARED)) || 1481 !length) { 1482 return -EINVAL; 1483 } 1484 1485 if ((prot & PROT_WRITE) && (tgt_flags & OS::TGT_MAP_SHARED)) { 1486 // With shared mmaps, there are two cases to consider: 1487 // 1) anonymous: writes should modify the mapping and this should be 1488 // visible to observers who share the mapping. Currently, it's 1489 // difficult to update the shared mapping because there's no 1490 // structure which maintains information about the which virtual 1491 // memory areas are shared. If that structure existed, it would be 1492 // possible to make the translations point to the same frames. 1493 // 2) file-backed: writes should modify the mapping and the file 1494 // which is backed by the mapping. The shared mapping problem is the 1495 // same as what was mentioned about the anonymous mappings. For 1496 // file-backed mappings, the writes to the file are difficult 1497 // because it requires syncing what the mapping holds with the file 1498 // that resides on the host system. So, any write on a real system 1499 // would cause the change to be propagated to the file mapping at 1500 // some point in the future (the inode is tracked along with the 1501 // mapping). This isn't guaranteed to always happen, but it usually 1502 // works well enough. The guarantee is provided by the msync system 1503 // call. We could force the change through with shared mappings with 1504 // a call to msync, but that again would require more information 1505 // than we currently maintain. 1506 warn("mmap: writing to shared mmap region is currently " 1507 "unsupported. The write succeeds on the target, but it " 1508 "will not be propagated to the host or shared mappings"); 1509 } 1510 1511 length = roundUp(length, TheISA::PageBytes); 1512 1513 int sim_fd = -1; 1514 uint8_t *pmap = nullptr; 1515 if (!(tgt_flags & OS::TGT_MAP_ANONYMOUS)) { 1516 std::shared_ptr<FDEntry> fdep = (*p->fds)[tgt_fd]; 1517 1518 auto dfdp = std::dynamic_pointer_cast<DeviceFDEntry>(fdep); 1519 if (dfdp) { 1520 EmulatedDriver *emul_driver = dfdp->getDriver(); 1521 return emul_driver->mmap(p, tc, start, length, prot, 1522 tgt_flags, tgt_fd, offset); 1523 } 1524 1525 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep); 1526 if (!ffdp) 1527 return -EBADF; 1528 sim_fd = ffdp->getSimFD(); 1529 1530 pmap = (decltype(pmap))mmap(nullptr, length, PROT_READ, MAP_PRIVATE, 1531 sim_fd, offset); 1532 1533 if (pmap == (decltype(pmap))-1) { 1534 warn("mmap: failed to map file into host address space"); 1535 return -errno; 1536 } 1537 } 1538 1539 // Extend global mmap region if necessary. Note that we ignore the 1540 // start address unless MAP_FIXED is specified. 1541 if (!(tgt_flags & OS::TGT_MAP_FIXED)) { 1542 std::shared_ptr<MemState> mem_state = p->memState; 1543 Addr mmap_end = mem_state->getMmapEnd(); 1544 1545 start = p->mmapGrowsDown() ? mmap_end - length : mmap_end; 1546 mmap_end = p->mmapGrowsDown() ? start : mmap_end + length; 1547 1548 mem_state->setMmapEnd(mmap_end); 1549 } 1550 1551 DPRINTF_SYSCALL(Verbose, " mmap range is 0x%x - 0x%x\n", 1552 start, start + length - 1); 1553 1554 // We only allow mappings to overwrite existing mappings if 1555 // TGT_MAP_FIXED is set. Otherwise it shouldn't be a problem 1556 // because we ignore the start hint if TGT_MAP_FIXED is not set. 1557 int clobber = tgt_flags & OS::TGT_MAP_FIXED; 1558 if (clobber) { 1559 for (auto tc : p->system->threadContexts) { 1560 // If we might be overwriting old mappings, we need to 1561 // invalidate potentially stale mappings out of the TLBs. 1562 tc->getDTBPtr()->flushAll(); 1563 tc->getITBPtr()->flushAll(); 1564 } 1565 } 1566 1567 // Allocate physical memory and map it in. If the page table is already 1568 // mapped and clobber is not set, the simulator will issue throw a 1569 // fatal and bail out of the simulation. 1570 p->allocateMem(start, length, clobber); 1571 1572 // Transfer content into target address space. 1573 SETranslatingPortProxy &tp = tc->getMemProxy(); 1574 if (tgt_flags & OS::TGT_MAP_ANONYMOUS) { 1575 // In general, we should zero the mapped area for anonymous mappings, 1576 // with something like: 1577 // tp.memsetBlob(start, 0, length); 1578 // However, given that we don't support sparse mappings, and 1579 // some applications can map a couple of gigabytes of space 1580 // (intending sparse usage), that can get painfully expensive. 1581 // Fortunately, since we don't properly implement munmap either, 1582 // there's no danger of remapping used memory, so for now all 1583 // newly mapped memory should already be zeroed so we can skip it. 1584 } else { 1585 // It is possible to mmap an area larger than a file, however 1586 // accessing unmapped portions the system triggers a "Bus error" 1587 // on the host. We must know when to stop copying the file from 1588 // the host into the target address space. 1589 struct stat file_stat; 1590 if (fstat(sim_fd, &file_stat) > 0) 1591 fatal("mmap: cannot stat file"); 1592 1593 // Copy the portion of the file that is resident. This requires 1594 // checking both the mmap size and the filesize that we are 1595 // trying to mmap into this space; the mmap size also depends 1596 // on the specified offset into the file. 1597 uint64_t size = std::min((uint64_t)file_stat.st_size - offset, 1598 length); 1599 tp.writeBlob(start, pmap, size); 1600 1601 // Cleanup the mmap region before exiting this function. 1602 munmap(pmap, length); 1603 1604 // Maintain the symbol table for dynamic executables. 1605 // The loader will call mmap to map the images into its address 1606 // space and we intercept that here. We can verify that we are 1607 // executing inside the loader by checking the program counter value. 1608 // XXX: with multiprogrammed workloads or multi-node configurations, 1609 // this will not work since there is a single global symbol table. 1610 ObjectFile *interpreter = p->getInterpreter(); 1611 if (interpreter) { 1612 Addr text_start = interpreter->textBase(); 1613 Addr text_end = text_start + interpreter->textSize(); 1614 1615 Addr pc = tc->pcState().pc(); 1616 1617 if (pc >= text_start && pc < text_end) { 1618 std::shared_ptr<FDEntry> fdep = (*p->fds)[tgt_fd]; 1619 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep); 1620 ObjectFile *lib = createObjectFile(ffdp->getFileName()); 1621 1622 if (lib) { 1623 lib->loadAllSymbols(debugSymbolTable, 1624 lib->textBase(), start); 1625 } 1626 } 1627 } 1628 1629 // Note that we do not zero out the remainder of the mapping. This 1630 // is done by a real system, but it probably will not affect 1631 // execution (hopefully). 1632 } 1633 1634 return start; 1635} 1636 1637template <class OS> 1638SyscallReturn 1639pwrite64Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1640{ 1641 int index = 0; 1642 int tgt_fd = p->getSyscallArg(tc, index); 1643 Addr bufPtr = p->getSyscallArg(tc, index); 1644 int nbytes = p->getSyscallArg(tc, index); 1645 int offset = p->getSyscallArg(tc, index); 1646 1647 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 1648 if (!ffdp) 1649 return -EBADF; 1650 int sim_fd = ffdp->getSimFD(); 1651 1652 BufferArg bufArg(bufPtr, nbytes); 1653 bufArg.copyIn(tc->getMemProxy()); 1654 1655 int bytes_written = pwrite(sim_fd, bufArg.bufferPtr(), nbytes, offset); 1656 1657 return (bytes_written == -1) ? -errno : bytes_written; 1658} 1659 1660/// Target mmap() handler. 1661template <class OS> 1662SyscallReturn 1663mmapFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1664{ 1665 return mmapImpl<OS>(desc, num, p, tc, false); 1666} 1667 1668/// Target mmap2() handler. 1669template <class OS> 1670SyscallReturn 1671mmap2Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1672{ 1673 return mmapImpl<OS>(desc, num, p, tc, true); 1674} 1675 1676/// Target getrlimit() handler. 1677template <class OS> 1678SyscallReturn 1679getrlimitFunc(SyscallDesc *desc, int callnum, Process *process, 1680 ThreadContext *tc) 1681{ 1682 int index = 0; 1683 unsigned resource = process->getSyscallArg(tc, index); 1684 TypedBufferArg<typename OS::rlimit> rlp(process->getSyscallArg(tc, index)); 1685 1686 switch (resource) { 1687 case OS::TGT_RLIMIT_STACK: 1688 // max stack size in bytes: make up a number (8MB for now) 1689 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; 1690 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1691 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1692 break; 1693 1694 case OS::TGT_RLIMIT_DATA: 1695 // max data segment size in bytes: make up a number 1696 rlp->rlim_cur = rlp->rlim_max = 256 * 1024 * 1024; 1697 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1698 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1699 break; 1700 1701 default: 1702 warn("getrlimit: unimplemented resource %d", resource); 1703 return -EINVAL; 1704 break; 1705 } 1706 1707 rlp.copyOut(tc->getMemProxy()); 1708 return 0; 1709} 1710 1711template <class OS> 1712SyscallReturn 1713prlimitFunc(SyscallDesc *desc, int callnum, Process *process, 1714 ThreadContext *tc) 1715{ 1716 int index = 0; 1717 if (process->getSyscallArg(tc, index) != 0) 1718 { 1719 warn("prlimit: ignoring rlimits for nonzero pid"); 1720 return -EPERM; 1721 } 1722 int resource = process->getSyscallArg(tc, index); 1723 Addr n = process->getSyscallArg(tc, index); 1724 if (n != 0) 1725 warn("prlimit: ignoring new rlimit"); 1726 Addr o = process->getSyscallArg(tc, index); 1727 if (o != 0) 1728 { 1729 TypedBufferArg<typename OS::rlimit> rlp(o); 1730 switch (resource) { 1731 case OS::TGT_RLIMIT_STACK: 1732 // max stack size in bytes: make up a number (8MB for now) 1733 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; 1734 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1735 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1736 break; 1737 case OS::TGT_RLIMIT_DATA: 1738 // max data segment size in bytes: make up a number 1739 rlp->rlim_cur = rlp->rlim_max = 256*1024*1024; 1740 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1741 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1742 break; 1743 default: 1744 warn("prlimit: unimplemented resource %d", resource); 1745 return -EINVAL; 1746 break; 1747 } 1748 rlp.copyOut(tc->getMemProxy()); 1749 } 1750 return 0; 1751} 1752 1753/// Target clock_gettime() function. 1754template <class OS> 1755SyscallReturn 1756clock_gettimeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1757{ 1758 int index = 1; 1759 //int clk_id = p->getSyscallArg(tc, index); 1760 TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index)); 1761 1762 getElapsedTimeNano(tp->tv_sec, tp->tv_nsec); 1763 tp->tv_sec += seconds_since_epoch; 1764 tp->tv_sec = TheISA::htog(tp->tv_sec); 1765 tp->tv_nsec = TheISA::htog(tp->tv_nsec); 1766 1767 tp.copyOut(tc->getMemProxy()); 1768 1769 return 0; 1770} 1771 1772/// Target clock_getres() function. 1773template <class OS> 1774SyscallReturn 1775clock_getresFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1776{ 1777 int index = 1; 1778 TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index)); 1779 1780 // Set resolution at ns, which is what clock_gettime() returns 1781 tp->tv_sec = 0; 1782 tp->tv_nsec = 1; 1783 1784 tp.copyOut(tc->getMemProxy()); 1785 1786 return 0; 1787} 1788 1789/// Target gettimeofday() handler. 1790template <class OS> 1791SyscallReturn 1792gettimeofdayFunc(SyscallDesc *desc, int callnum, Process *process, 1793 ThreadContext *tc) 1794{ 1795 int index = 0; 1796 TypedBufferArg<typename OS::timeval> tp(process->getSyscallArg(tc, index)); 1797 1798 getElapsedTimeMicro(tp->tv_sec, tp->tv_usec); 1799 tp->tv_sec += seconds_since_epoch; 1800 tp->tv_sec = TheISA::htog(tp->tv_sec); 1801 tp->tv_usec = TheISA::htog(tp->tv_usec); 1802 1803 tp.copyOut(tc->getMemProxy()); 1804 1805 return 0; 1806} 1807 1808 1809/// Target utimes() handler. 1810template <class OS> 1811SyscallReturn 1812utimesFunc(SyscallDesc *desc, int callnum, Process *process, 1813 ThreadContext *tc) 1814{ 1815 std::string path; 1816 1817 int index = 0; 1818 if (!tc->getMemProxy().tryReadString(path, 1819 process->getSyscallArg(tc, index))) { 1820 return -EFAULT; 1821 } 1822 1823 TypedBufferArg<typename OS::timeval [2]> 1824 tp(process->getSyscallArg(tc, index)); 1825 tp.copyIn(tc->getMemProxy()); 1826 1827 struct timeval hostTimeval[2]; 1828 for (int i = 0; i < 2; ++i) { 1829 hostTimeval[i].tv_sec = TheISA::gtoh((*tp)[i].tv_sec); 1830 hostTimeval[i].tv_usec = TheISA::gtoh((*tp)[i].tv_usec); 1831 } 1832 1833 // Adjust path for current working directory 1834 path = process->fullPath(path); 1835 1836 int result = utimes(path.c_str(), hostTimeval); 1837 1838 if (result < 0) 1839 return -errno; 1840 1841 return 0; 1842} 1843 1844template <class OS> 1845SyscallReturn 1846execveFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1847{ 1848 desc->setFlags(0); 1849 1850 int index = 0; 1851 std::string path; 1852 SETranslatingPortProxy & mem_proxy = tc->getMemProxy(); 1853 if (!mem_proxy.tryReadString(path, p->getSyscallArg(tc, index))) 1854 return -EFAULT; 1855 1856 if (access(path.c_str(), F_OK) == -1) 1857 return -EACCES; 1858 1859 auto read_in = [](std::vector<std::string> & vect, 1860 SETranslatingPortProxy & mem_proxy, 1861 Addr mem_loc) 1862 { 1863 for (int inc = 0; ; inc++) { 1864 BufferArg b((mem_loc + sizeof(Addr) * inc), sizeof(Addr)); 1865 b.copyIn(mem_proxy); 1866 1867 if (!*(Addr*)b.bufferPtr()) 1868 break; 1869 1870 vect.push_back(std::string()); 1871 mem_proxy.tryReadString(vect[inc], *(Addr*)b.bufferPtr()); 1872 } 1873 }; 1874 1875 /** 1876 * Note that ProcessParams is generated by swig and there are no other 1877 * examples of how to create anything but this default constructor. The 1878 * fields are manually initialized instead of passing parameters to the 1879 * constructor. 1880 */ 1881 ProcessParams *pp = new ProcessParams(); 1882 pp->executable = path; 1883 Addr argv_mem_loc = p->getSyscallArg(tc, index); 1884 read_in(pp->cmd, mem_proxy, argv_mem_loc); 1885 Addr envp_mem_loc = p->getSyscallArg(tc, index); 1886 read_in(pp->env, mem_proxy, envp_mem_loc); 1887 pp->uid = p->uid(); 1888 pp->egid = p->egid(); 1889 pp->euid = p->euid(); 1890 pp->gid = p->gid(); 1891 pp->ppid = p->ppid(); 1892 pp->pid = p->pid(); 1893 pp->input.assign("cin"); 1894 pp->output.assign("cout"); 1895 pp->errout.assign("cerr"); 1896 pp->cwd.assign(p->getcwd()); 1897 pp->system = p->system; 1898 /** 1899 * Prevent process object creation with identical PIDs (which will trip 1900 * a fatal check in Process constructor). The execve call is supposed to 1901 * take over the currently executing process' identity but replace 1902 * whatever it is doing with a new process image. Instead of hijacking 1903 * the process object in the simulator, we create a new process object 1904 * and bind to the previous process' thread below (hijacking the thread). 1905 */ 1906 p->system->PIDs.erase(p->pid()); 1907 Process *new_p = pp->create(); 1908 delete pp; 1909 1910 /** 1911 * Work through the file descriptor array and close any files marked 1912 * close-on-exec. 1913 */ 1914 new_p->fds = p->fds; 1915 for (int i = 0; i < new_p->fds->getSize(); i++) { 1916 std::shared_ptr<FDEntry> fdep = (*new_p->fds)[i]; 1917 if (fdep && fdep->getCOE()) 1918 new_p->fds->closeFDEntry(i); 1919 } 1920 1921 *new_p->sigchld = true; 1922 1923 delete p; 1924 tc->clearArchRegs(); 1925 tc->setProcessPtr(new_p); 1926 new_p->assignThreadContext(tc->contextId()); 1927 new_p->initState(); 1928 tc->activate(); 1929 TheISA::PCState pcState = tc->pcState(); 1930 tc->setNPC(pcState.instAddr()); 1931 1932 desc->setFlags(SyscallDesc::SuppressReturnValue); 1933 return 0; 1934} 1935 1936/// Target getrusage() function. 1937template <class OS> 1938SyscallReturn 1939getrusageFunc(SyscallDesc *desc, int callnum, Process *process, 1940 ThreadContext *tc) 1941{ 1942 int index = 0; 1943 int who = process->getSyscallArg(tc, index); // THREAD, SELF, or CHILDREN 1944 TypedBufferArg<typename OS::rusage> rup(process->getSyscallArg(tc, index)); 1945 1946 rup->ru_utime.tv_sec = 0; 1947 rup->ru_utime.tv_usec = 0; 1948 rup->ru_stime.tv_sec = 0; 1949 rup->ru_stime.tv_usec = 0; 1950 rup->ru_maxrss = 0; 1951 rup->ru_ixrss = 0; 1952 rup->ru_idrss = 0; 1953 rup->ru_isrss = 0; 1954 rup->ru_minflt = 0; 1955 rup->ru_majflt = 0; 1956 rup->ru_nswap = 0; 1957 rup->ru_inblock = 0; 1958 rup->ru_oublock = 0; 1959 rup->ru_msgsnd = 0; 1960 rup->ru_msgrcv = 0; 1961 rup->ru_nsignals = 0; 1962 rup->ru_nvcsw = 0; 1963 rup->ru_nivcsw = 0; 1964 1965 switch (who) { 1966 case OS::TGT_RUSAGE_SELF: 1967 getElapsedTimeMicro(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec); 1968 rup->ru_utime.tv_sec = TheISA::htog(rup->ru_utime.tv_sec); 1969 rup->ru_utime.tv_usec = TheISA::htog(rup->ru_utime.tv_usec); 1970 break; 1971 1972 case OS::TGT_RUSAGE_CHILDREN: 1973 // do nothing. We have no child processes, so they take no time. 1974 break; 1975 1976 default: 1977 // don't really handle THREAD or CHILDREN, but just warn and 1978 // plow ahead 1979 warn("getrusage() only supports RUSAGE_SELF. Parameter %d ignored.", 1980 who); 1981 } 1982 1983 rup.copyOut(tc->getMemProxy()); 1984 1985 return 0; 1986} 1987 1988/// Target times() function. 1989template <class OS> 1990SyscallReturn 1991timesFunc(SyscallDesc *desc, int callnum, Process *process, 1992 ThreadContext *tc) 1993{ 1994 int index = 0; 1995 TypedBufferArg<typename OS::tms> bufp(process->getSyscallArg(tc, index)); 1996 1997 // Fill in the time structure (in clocks) 1998 int64_t clocks = curTick() * OS::M5_SC_CLK_TCK / SimClock::Int::s; 1999 bufp->tms_utime = clocks; 2000 bufp->tms_stime = 0; 2001 bufp->tms_cutime = 0; 2002 bufp->tms_cstime = 0; 2003 2004 // Convert to host endianness 2005 bufp->tms_utime = TheISA::htog(bufp->tms_utime); 2006 2007 // Write back 2008 bufp.copyOut(tc->getMemProxy()); 2009 2010 // Return clock ticks since system boot 2011 return clocks; 2012} 2013 2014/// Target time() function. 2015template <class OS> 2016SyscallReturn 2017timeFunc(SyscallDesc *desc, int callnum, Process *process, ThreadContext *tc) 2018{ 2019 typename OS::time_t sec, usec; 2020 getElapsedTimeMicro(sec, usec); 2021 sec += seconds_since_epoch; 2022 2023 int index = 0; 2024 Addr taddr = (Addr)process->getSyscallArg(tc, index); 2025 if (taddr != 0) { 2026 typename OS::time_t t = sec; 2027 t = TheISA::htog(t); 2028 SETranslatingPortProxy &p = tc->getMemProxy(); 2029 p.writeBlob(taddr, (uint8_t*)&t, (int)sizeof(typename OS::time_t)); 2030 } 2031 return sec; 2032} 2033 2034template <class OS> 2035SyscallReturn 2036tgkillFunc(SyscallDesc *desc, int num, Process *process, ThreadContext *tc) 2037{ 2038 int index = 0; 2039 int tgid = process->getSyscallArg(tc, index); 2040 int tid = process->getSyscallArg(tc, index); 2041 int sig = process->getSyscallArg(tc, index); 2042 2043 /** 2044 * This system call is intended to allow killing a specific thread 2045 * within an arbitrary thread group if sanctioned with permission checks. 2046 * It's usually true that threads share the termination signal as pointed 2047 * out by the pthread_kill man page and this seems to be the intended 2048 * usage. Due to this being an emulated environment, assume the following: 2049 * Threads are allowed to call tgkill because the EUID for all threads 2050 * should be the same. There is no signal handling mechanism for kernel 2051 * registration of signal handlers since signals are poorly supported in 2052 * emulation mode. Since signal handlers cannot be registered, all 2053 * threads within in a thread group must share the termination signal. 2054 * We never exhaust PIDs so there's no chance of finding the wrong one 2055 * due to PID rollover. 2056 */ 2057 2058 System *sys = tc->getSystemPtr(); 2059 Process *tgt_proc = nullptr; 2060 for (int i = 0; i < sys->numContexts(); i++) { 2061 Process *temp = sys->threadContexts[i]->getProcessPtr(); 2062 if (temp->pid() == tid) { 2063 tgt_proc = temp; 2064 break; 2065 } 2066 } 2067 2068 if (sig != 0 || sig != OS::TGT_SIGABRT) 2069 return -EINVAL; 2070 2071 if (tgt_proc == nullptr) 2072 return -ESRCH; 2073 2074 if (tgid != -1 && tgt_proc->tgid() != tgid) 2075 return -ESRCH; 2076 2077 if (sig == OS::TGT_SIGABRT) 2078 exitGroupFunc(desc, 252, process, tc); 2079 2080 return 0; 2081} 2082 2083 2084#endif // __SIM_SYSCALL_EMUL_HH__
|