syscall_emul.hh revision 2680
1/* 2 * Copyright (c) 2003-2005 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Authors: Steve Reinhardt 29 * Kevin Lim 30 */ 31 32#ifndef __SIM_SYSCALL_EMUL_HH__ 33#define __SIM_SYSCALL_EMUL_HH__ 34 35#define BSD_HOST (defined(__APPLE__) || defined(__OpenBSD__) || \ 36 defined(__FreeBSD__)) 37 38/// 39/// @file syscall_emul.hh 40/// 41/// This file defines objects used to emulate syscalls from the target 42/// application on the host machine. 43 44#include <errno.h> 45#include <string> 46#ifdef __CYGWIN32__ 47#include <sys/fcntl.h> // for O_BINARY 48#endif 49#include <sys/uio.h> 50 51#include "arch/isa_traits.hh" // for Addr 52#include "base/chunk_generator.hh" 53#include "base/intmath.hh" // for RoundUp 54#include "base/misc.hh" 55#include "base/trace.hh" 56#include "cpu/base.hh" 57#include "cpu/thread_context.hh" 58#include "mem/translating_port.hh" 59#include "mem/page_table.hh" 60#include "sim/process.hh" 61 62/// 63/// System call descriptor. 64/// 65class SyscallDesc { 66 67 public: 68 69 /// Typedef for target syscall handler functions. 70 typedef SyscallReturn (*FuncPtr)(SyscallDesc *, int num, 71 Process *, ThreadContext *); 72 73 const char *name; //!< Syscall name (e.g., "open"). 74 FuncPtr funcPtr; //!< Pointer to emulation function. 75 int flags; //!< Flags (see Flags enum). 76 77 /// Flag values for controlling syscall behavior. 78 enum Flags { 79 /// Don't set return regs according to funcPtr return value. 80 /// Used for syscalls with non-standard return conventions 81 /// that explicitly set the ThreadContext regs (e.g., 82 /// sigreturn). 83 SuppressReturnValue = 1 84 }; 85 86 /// Constructor. 87 SyscallDesc(const char *_name, FuncPtr _funcPtr, int _flags = 0) 88 : name(_name), funcPtr(_funcPtr), flags(_flags) 89 { 90 } 91 92 /// Emulate the syscall. Public interface for calling through funcPtr. 93 void doSyscall(int callnum, Process *proc, ThreadContext *tc); 94}; 95 96 97class BaseBufferArg { 98 99 public: 100 101 BaseBufferArg(Addr _addr, int _size) : addr(_addr), size(_size) 102 { 103 bufPtr = new uint8_t[size]; 104 // clear out buffer: in case we only partially populate this, 105 // and then do a copyOut(), we want to make sure we don't 106 // introduce any random junk into the simulated address space 107 memset(bufPtr, 0, size); 108 } 109 110 virtual ~BaseBufferArg() { delete [] bufPtr; } 111 112 // 113 // copy data into simulator space (read from target memory) 114 // 115 virtual bool copyIn(TranslatingPort *memport) 116 { 117 memport->readBlob(addr, bufPtr, size); 118 return true; // no EFAULT detection for now 119 } 120 121 // 122 // copy data out of simulator space (write to target memory) 123 // 124 virtual bool copyOut(TranslatingPort *memport) 125 { 126 memport->writeBlob(addr, bufPtr, size); 127 return true; // no EFAULT detection for now 128 } 129 130 protected: 131 Addr addr; 132 int size; 133 uint8_t *bufPtr; 134}; 135 136 137class BufferArg : public BaseBufferArg 138{ 139 public: 140 BufferArg(Addr _addr, int _size) : BaseBufferArg(_addr, _size) { } 141 void *bufferPtr() { return bufPtr; } 142}; 143 144template <class T> 145class TypedBufferArg : public BaseBufferArg 146{ 147 public: 148 // user can optionally specify a specific number of bytes to 149 // allocate to deal with those structs that have variable-size 150 // arrays at the end 151 TypedBufferArg(Addr _addr, int _size = sizeof(T)) 152 : BaseBufferArg(_addr, _size) 153 { } 154 155 // type case 156 operator T*() { return (T *)bufPtr; } 157 158 // dereference operators 159 T &operator*() { return *((T *)bufPtr); } 160 T* operator->() { return (T *)bufPtr; } 161 T &operator[](int i) { return ((T *)bufPtr)[i]; } 162}; 163 164////////////////////////////////////////////////////////////////////// 165// 166// The following emulation functions are generic enough that they 167// don't need to be recompiled for different emulated OS's. They are 168// defined in sim/syscall_emul.cc. 169// 170////////////////////////////////////////////////////////////////////// 171 172 173/// Handler for unimplemented syscalls that we haven't thought about. 174SyscallReturn unimplementedFunc(SyscallDesc *desc, int num, 175 Process *p, ThreadContext *tc); 176 177/// Handler for unimplemented syscalls that we never intend to 178/// implement (signal handling, etc.) and should not affect the correct 179/// behavior of the program. Print a warning only if the appropriate 180/// trace flag is enabled. Return success to the target program. 181SyscallReturn ignoreFunc(SyscallDesc *desc, int num, 182 Process *p, ThreadContext *tc); 183 184/// Target exit() handler: terminate simulation. 185SyscallReturn exitFunc(SyscallDesc *desc, int num, 186 Process *p, ThreadContext *tc); 187 188/// Target getpagesize() handler. 189SyscallReturn getpagesizeFunc(SyscallDesc *desc, int num, 190 Process *p, ThreadContext *tc); 191 192/// Target obreak() handler: set brk address. 193SyscallReturn obreakFunc(SyscallDesc *desc, int num, 194 Process *p, ThreadContext *tc); 195 196/// Target close() handler. 197SyscallReturn closeFunc(SyscallDesc *desc, int num, 198 Process *p, ThreadContext *tc); 199 200/// Target read() handler. 201SyscallReturn readFunc(SyscallDesc *desc, int num, 202 Process *p, ThreadContext *tc); 203 204/// Target write() handler. 205SyscallReturn writeFunc(SyscallDesc *desc, int num, 206 Process *p, ThreadContext *tc); 207 208/// Target lseek() handler. 209SyscallReturn lseekFunc(SyscallDesc *desc, int num, 210 Process *p, ThreadContext *tc); 211 212/// Target munmap() handler. 213SyscallReturn munmapFunc(SyscallDesc *desc, int num, 214 Process *p, ThreadContext *tc); 215 216/// Target gethostname() handler. 217SyscallReturn gethostnameFunc(SyscallDesc *desc, int num, 218 Process *p, ThreadContext *tc); 219 220/// Target unlink() handler. 221SyscallReturn unlinkFunc(SyscallDesc *desc, int num, 222 Process *p, ThreadContext *tc); 223 224/// Target rename() handler. 225SyscallReturn renameFunc(SyscallDesc *desc, int num, 226 Process *p, ThreadContext *tc); 227 228 229/// Target truncate() handler. 230SyscallReturn truncateFunc(SyscallDesc *desc, int num, 231 Process *p, ThreadContext *tc); 232 233 234/// Target ftruncate() handler. 235SyscallReturn ftruncateFunc(SyscallDesc *desc, int num, 236 Process *p, ThreadContext *tc); 237 238 239/// Target chown() handler. 240SyscallReturn chownFunc(SyscallDesc *desc, int num, 241 Process *p, ThreadContext *tc); 242 243 244/// Target fchown() handler. 245SyscallReturn fchownFunc(SyscallDesc *desc, int num, 246 Process *p, ThreadContext *tc); 247 248/// Target fnctl() handler. 249SyscallReturn fcntlFunc(SyscallDesc *desc, int num, 250 Process *process, ThreadContext *tc); 251 252/// Target setuid() handler. 253SyscallReturn setuidFunc(SyscallDesc *desc, int num, 254 Process *p, ThreadContext *tc); 255 256/// Target getpid() handler. 257SyscallReturn getpidFunc(SyscallDesc *desc, int num, 258 Process *p, ThreadContext *tc); 259 260/// Target getuid() handler. 261SyscallReturn getuidFunc(SyscallDesc *desc, int num, 262 Process *p, ThreadContext *tc); 263 264/// Target getgid() handler. 265SyscallReturn getgidFunc(SyscallDesc *desc, int num, 266 Process *p, ThreadContext *tc); 267 268/// Target getppid() handler. 269SyscallReturn getppidFunc(SyscallDesc *desc, int num, 270 Process *p, ThreadContext *tc); 271 272/// Target geteuid() handler. 273SyscallReturn geteuidFunc(SyscallDesc *desc, int num, 274 Process *p, ThreadContext *tc); 275 276/// Target getegid() handler. 277SyscallReturn getegidFunc(SyscallDesc *desc, int num, 278 Process *p, ThreadContext *tc); 279 280 281 282/// Pseudo Funcs - These functions use a different return convension, 283/// returning a second value in a register other than the normal return register 284SyscallReturn pipePseudoFunc(SyscallDesc *desc, int num, 285 Process *process, ThreadContext *tc); 286 287/// Target getpidPseudo() handler. 288SyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num, 289 Process *p, ThreadContext *tc); 290 291/// Target getuidPseudo() handler. 292SyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num, 293 Process *p, ThreadContext *tc); 294 295/// Target getgidPseudo() handler. 296SyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num, 297 Process *p, ThreadContext *tc); 298 299 300/// This struct is used to build an target-OS-dependent table that 301/// maps the target's open() flags to the host open() flags. 302struct OpenFlagTransTable { 303 int tgtFlag; //!< Target system flag value. 304 int hostFlag; //!< Corresponding host system flag value. 305}; 306 307 308 309/// A readable name for 1,000,000, for converting microseconds to seconds. 310const int one_million = 1000000; 311 312/// Approximate seconds since the epoch (1/1/1970). About a billion, 313/// by my reckoning. We want to keep this a constant (not use the 314/// real-world time) to keep simulations repeatable. 315const unsigned seconds_since_epoch = 1000000000; 316 317/// Helper function to convert current elapsed time to seconds and 318/// microseconds. 319template <class T1, class T2> 320void 321getElapsedTime(T1 &sec, T2 &usec) 322{ 323 int elapsed_usecs = curTick / Clock::Int::us; 324 sec = elapsed_usecs / one_million; 325 usec = elapsed_usecs % one_million; 326} 327 328////////////////////////////////////////////////////////////////////// 329// 330// The following emulation functions are generic, but need to be 331// templated to account for differences in types, constants, etc. 332// 333////////////////////////////////////////////////////////////////////// 334 335/// Target ioctl() handler. For the most part, programs call ioctl() 336/// only to find out if their stdout is a tty, to determine whether to 337/// do line or block buffering. 338template <class OS> 339SyscallReturn 340ioctlFunc(SyscallDesc *desc, int callnum, Process *process, 341 ThreadContext *tc) 342{ 343 int fd = tc->getSyscallArg(0); 344 unsigned req = tc->getSyscallArg(1); 345 346 DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", fd, req); 347 348 if (fd < 0 || process->sim_fd(fd) < 0) { 349 // doesn't map to any simulator fd: not a valid target fd 350 return -EBADF; 351 } 352 353 switch (req) { 354 case OS::TIOCISATTY: 355 case OS::TIOCGETP: 356 case OS::TIOCSETP: 357 case OS::TIOCSETN: 358 case OS::TIOCSETC: 359 case OS::TIOCGETC: 360 case OS::TIOCGETS: 361 case OS::TIOCGETA: 362 return -ENOTTY; 363 364 default: 365 fatal("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ 0x%llx\n", 366 fd, req, tc->readPC()); 367 } 368} 369 370/// Target open() handler. 371template <class OS> 372SyscallReturn 373openFunc(SyscallDesc *desc, int callnum, Process *process, 374 ThreadContext *tc) 375{ 376 std::string path; 377 378 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) 379 return -EFAULT; 380 381 if (path == "/dev/sysdev0") { 382 // This is a memory-mapped high-resolution timer device on Alpha. 383 // We don't support it, so just punt. 384 warn("Ignoring open(%s, ...)\n", path); 385 return -ENOENT; 386 } 387 388 int tgtFlags = tc->getSyscallArg(1); 389 int mode = tc->getSyscallArg(2); 390 int hostFlags = 0; 391 392 // translate open flags 393 for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) { 394 if (tgtFlags & OS::openFlagTable[i].tgtFlag) { 395 tgtFlags &= ~OS::openFlagTable[i].tgtFlag; 396 hostFlags |= OS::openFlagTable[i].hostFlag; 397 } 398 } 399 400 // any target flags left? 401 if (tgtFlags != 0) 402 warn("Syscall: open: cannot decode flags 0x%x", tgtFlags); 403 404#ifdef __CYGWIN32__ 405 hostFlags |= O_BINARY; 406#endif 407 408 DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str()); 409 410 // open the file 411 int fd = open(path.c_str(), hostFlags, mode); 412 413 return (fd == -1) ? -errno : process->alloc_fd(fd); 414} 415 416 417/// Target chmod() handler. 418template <class OS> 419SyscallReturn 420chmodFunc(SyscallDesc *desc, int callnum, Process *process, 421 ThreadContext *tc) 422{ 423 std::string path; 424 425 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) 426 return -EFAULT; 427 428 uint32_t mode = tc->getSyscallArg(1); 429 mode_t hostMode = 0; 430 431 // XXX translate mode flags via OS::something??? 432 hostMode = mode; 433 434 // do the chmod 435 int result = chmod(path.c_str(), hostMode); 436 if (result < 0) 437 return -errno; 438 439 return 0; 440} 441 442 443/// Target fchmod() handler. 444template <class OS> 445SyscallReturn 446fchmodFunc(SyscallDesc *desc, int callnum, Process *process, 447 ThreadContext *tc) 448{ 449 int fd = tc->getSyscallArg(0); 450 if (fd < 0 || process->sim_fd(fd) < 0) { 451 // doesn't map to any simulator fd: not a valid target fd 452 return -EBADF; 453 } 454 455 uint32_t mode = tc->getSyscallArg(1); 456 mode_t hostMode = 0; 457 458 // XXX translate mode flags via OS::someting??? 459 hostMode = mode; 460 461 // do the fchmod 462 int result = fchmod(process->sim_fd(fd), hostMode); 463 if (result < 0) 464 return -errno; 465 466 return 0; 467} 468 469 470/// Target stat() handler. 471template <class OS> 472SyscallReturn 473statFunc(SyscallDesc *desc, int callnum, Process *process, 474 ThreadContext *tc) 475{ 476 std::string path; 477 478 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) 479 return -EFAULT; 480 481 struct stat hostBuf; 482 int result = stat(path.c_str(), &hostBuf); 483 484 if (result < 0) 485 return -errno; 486 487 OS::copyOutStatBuf(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf); 488 489 return 0; 490} 491 492 493/// Target fstat64() handler. 494template <class OS> 495SyscallReturn 496fstat64Func(SyscallDesc *desc, int callnum, Process *process, 497 ThreadContext *tc) 498{ 499 int fd = tc->getSyscallArg(0); 500 if (fd < 0 || process->sim_fd(fd) < 0) { 501 // doesn't map to any simulator fd: not a valid target fd 502 return -EBADF; 503 } 504 505#if BSD_HOST 506 struct stat hostBuf; 507 int result = fstat(process->sim_fd(fd), &hostBuf); 508#else 509 struct stat64 hostBuf; 510 int result = fstat64(process->sim_fd(fd), &hostBuf); 511#endif 512 513 if (result < 0) 514 return -errno; 515 516 OS::copyOutStat64Buf(tc->getMemPort(), fd, tc->getSyscallArg(1), &hostBuf); 517 518 return 0; 519} 520 521 522/// Target lstat() handler. 523template <class OS> 524SyscallReturn 525lstatFunc(SyscallDesc *desc, int callnum, Process *process, 526 ThreadContext *tc) 527{ 528 std::string path; 529 530 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) 531 return -EFAULT; 532 533 struct stat hostBuf; 534 int result = lstat(path.c_str(), &hostBuf); 535 536 if (result < 0) 537 return -errno; 538 539 OS::copyOutStatBuf(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf); 540 541 return 0; 542} 543 544/// Target lstat64() handler. 545template <class OS> 546SyscallReturn 547lstat64Func(SyscallDesc *desc, int callnum, Process *process, 548 ThreadContext *tc) 549{ 550 std::string path; 551 552 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) 553 return -EFAULT; 554 555#if BSD_HOST 556 struct stat hostBuf; 557 int result = lstat(path.c_str(), &hostBuf); 558#else 559 struct stat64 hostBuf; 560 int result = lstat64(path.c_str(), &hostBuf); 561#endif 562 563 if (result < 0) 564 return -errno; 565 566 OS::copyOutStat64Buf(tc->getMemPort(), -1, tc->getSyscallArg(1), &hostBuf); 567 568 return 0; 569} 570 571/// Target fstat() handler. 572template <class OS> 573SyscallReturn 574fstatFunc(SyscallDesc *desc, int callnum, Process *process, 575 ThreadContext *tc) 576{ 577 int fd = process->sim_fd(tc->getSyscallArg(0)); 578 579 DPRINTF(SyscallVerbose, "fstat(%d, ...)\n", fd); 580 581 if (fd < 0) 582 return -EBADF; 583 584 struct stat hostBuf; 585 int result = fstat(fd, &hostBuf); 586 587 if (result < 0) 588 return -errno; 589 590 OS::copyOutStatBuf(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf); 591 592 return 0; 593} 594 595 596/// Target statfs() handler. 597template <class OS> 598SyscallReturn 599statfsFunc(SyscallDesc *desc, int callnum, Process *process, 600 ThreadContext *tc) 601{ 602 std::string path; 603 604 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) 605 return -EFAULT; 606 607 struct statfs hostBuf; 608 int result = statfs(path.c_str(), &hostBuf); 609 610 if (result < 0) 611 return -errno; 612 613 OS::copyOutStatfsBuf(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf); 614 615 return 0; 616} 617 618 619/// Target fstatfs() handler. 620template <class OS> 621SyscallReturn 622fstatfsFunc(SyscallDesc *desc, int callnum, Process *process, 623 ThreadContext *tc) 624{ 625 int fd = process->sim_fd(tc->getSyscallArg(0)); 626 627 if (fd < 0) 628 return -EBADF; 629 630 struct statfs hostBuf; 631 int result = fstatfs(fd, &hostBuf); 632 633 if (result < 0) 634 return -errno; 635 636 OS::copyOutStatfsBuf(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf); 637 638 return 0; 639} 640 641 642/// Target writev() handler. 643template <class OS> 644SyscallReturn 645writevFunc(SyscallDesc *desc, int callnum, Process *process, 646 ThreadContext *tc) 647{ 648 int fd = tc->getSyscallArg(0); 649 if (fd < 0 || process->sim_fd(fd) < 0) { 650 // doesn't map to any simulator fd: not a valid target fd 651 return -EBADF; 652 } 653 654 TranslatingPort *p = tc->getMemPort(); 655 uint64_t tiov_base = tc->getSyscallArg(1); 656 size_t count = tc->getSyscallArg(2); 657 struct iovec hiov[count]; 658 for (int i = 0; i < count; ++i) 659 { 660 typename OS::tgt_iovec tiov; 661 662 p->readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec), 663 (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec)); 664 hiov[i].iov_len = gtoh(tiov.iov_len); 665 hiov[i].iov_base = new char [hiov[i].iov_len]; 666 p->readBlob(gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base, 667 hiov[i].iov_len); 668 } 669 670 int result = writev(process->sim_fd(fd), hiov, count); 671 672 for (int i = 0; i < count; ++i) 673 { 674 delete [] (char *)hiov[i].iov_base; 675 } 676 677 if (result < 0) 678 return -errno; 679 680 return 0; 681} 682 683 684/// Target mmap() handler. 685/// 686/// We don't really handle mmap(). If the target is mmaping an 687/// anonymous region or /dev/zero, we can get away with doing basically 688/// nothing (since memory is initialized to zero and the simulator 689/// doesn't really check addresses anyway). Always print a warning, 690/// since this could be seriously broken if we're not mapping 691/// /dev/zero. 692// 693/// Someday we should explicitly check for /dev/zero in open, flag the 694/// file descriptor, and fail (or implement!) a non-anonymous mmap to 695/// anything else. 696template <class OS> 697SyscallReturn 698mmapFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 699{ 700 Addr start = tc->getSyscallArg(0); 701 uint64_t length = tc->getSyscallArg(1); 702 // int prot = tc->getSyscallArg(2); 703 int flags = tc->getSyscallArg(3); 704 // int fd = p->sim_fd(tc->getSyscallArg(4)); 705 // int offset = tc->getSyscallArg(5); 706 707 if ((start % TheISA::VMPageSize) != 0 || 708 (length % TheISA::VMPageSize) != 0) { 709 warn("mmap failing: arguments not page-aligned: " 710 "start 0x%x length 0x%x", 711 start, length); 712 return -EINVAL; 713 } 714 715 if (start != 0) { 716 warn("mmap: ignoring suggested map address 0x%x, using 0x%x", 717 start, p->mmap_end); 718 } 719 720 // pick next address from our "mmap region" 721 start = p->mmap_end; 722 p->pTable->allocate(start, length); 723 p->mmap_end += length; 724 725 if (!(flags & OS::TGT_MAP_ANONYMOUS)) { 726 warn("allowing mmap of file @ fd %d. " 727 "This will break if not /dev/zero.", tc->getSyscallArg(4)); 728 } 729 730 return start; 731} 732 733/// Target getrlimit() handler. 734template <class OS> 735SyscallReturn 736getrlimitFunc(SyscallDesc *desc, int callnum, Process *process, 737 ThreadContext *tc) 738{ 739 unsigned resource = tc->getSyscallArg(0); 740 TypedBufferArg<typename OS::rlimit> rlp(tc->getSyscallArg(1)); 741 742 switch (resource) { 743 case OS::TGT_RLIMIT_STACK: 744 // max stack size in bytes: make up a number (2MB for now) 745 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; 746 rlp->rlim_cur = htog(rlp->rlim_cur); 747 rlp->rlim_max = htog(rlp->rlim_max); 748 break; 749 750 default: 751 std::cerr << "getrlimitFunc: unimplemented resource " << resource 752 << std::endl; 753 abort(); 754 break; 755 } 756 757 rlp.copyOut(tc->getMemPort()); 758 return 0; 759} 760 761/// Target gettimeofday() handler. 762template <class OS> 763SyscallReturn 764gettimeofdayFunc(SyscallDesc *desc, int callnum, Process *process, 765 ThreadContext *tc) 766{ 767 TypedBufferArg<typename OS::timeval> tp(tc->getSyscallArg(0)); 768 769 getElapsedTime(tp->tv_sec, tp->tv_usec); 770 tp->tv_sec += seconds_since_epoch; 771 tp->tv_sec = htog(tp->tv_sec); 772 tp->tv_usec = htog(tp->tv_usec); 773 774 tp.copyOut(tc->getMemPort()); 775 776 return 0; 777} 778 779 780/// Target utimes() handler. 781template <class OS> 782SyscallReturn 783utimesFunc(SyscallDesc *desc, int callnum, Process *process, 784 ThreadContext *tc) 785{ 786 std::string path; 787 788 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) 789 return -EFAULT; 790 791 TypedBufferArg<typename OS::timeval [2]> tp(tc->getSyscallArg(1)); 792 tp.copyIn(tc->getMemPort()); 793 794 struct timeval hostTimeval[2]; 795 for (int i = 0; i < 2; ++i) 796 { 797 hostTimeval[i].tv_sec = gtoh((*tp)[i].tv_sec); 798 hostTimeval[i].tv_usec = gtoh((*tp)[i].tv_usec); 799 } 800 int result = utimes(path.c_str(), hostTimeval); 801 802 if (result < 0) 803 return -errno; 804 805 return 0; 806} 807/// Target getrusage() function. 808template <class OS> 809SyscallReturn 810getrusageFunc(SyscallDesc *desc, int callnum, Process *process, 811 ThreadContext *tc) 812{ 813 int who = tc->getSyscallArg(0); // THREAD, SELF, or CHILDREN 814 TypedBufferArg<typename OS::rusage> rup(tc->getSyscallArg(1)); 815 816 if (who != OS::TGT_RUSAGE_SELF) { 817 // don't really handle THREAD or CHILDREN, but just warn and 818 // plow ahead 819 warn("getrusage() only supports RUSAGE_SELF. Parameter %d ignored.", 820 who); 821 } 822 823 getElapsedTime(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec); 824 rup->ru_utime.tv_sec = htog(rup->ru_utime.tv_sec); 825 rup->ru_utime.tv_usec = htog(rup->ru_utime.tv_usec); 826 827 rup->ru_stime.tv_sec = 0; 828 rup->ru_stime.tv_usec = 0; 829 rup->ru_maxrss = 0; 830 rup->ru_ixrss = 0; 831 rup->ru_idrss = 0; 832 rup->ru_isrss = 0; 833 rup->ru_minflt = 0; 834 rup->ru_majflt = 0; 835 rup->ru_nswap = 0; 836 rup->ru_inblock = 0; 837 rup->ru_oublock = 0; 838 rup->ru_msgsnd = 0; 839 rup->ru_msgrcv = 0; 840 rup->ru_nsignals = 0; 841 rup->ru_nvcsw = 0; 842 rup->ru_nivcsw = 0; 843 844 rup.copyOut(tc->getMemPort()); 845 846 return 0; 847} 848 849 850 851 852#endif // __SIM_SYSCALL_EMUL_HH__ 853