syscall_emul.hh revision 3079
1/* 2 * Copyright (c) 2003-2005 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Authors: Steve Reinhardt 29 * Kevin Lim 30 */ 31 32#ifndef __SIM_SYSCALL_EMUL_HH__ 33#define __SIM_SYSCALL_EMUL_HH__ 34 35#define NO_STAT64 (defined(__APPLE__) || defined(__OpenBSD__) || \ 36 defined(__FreeBSD__) || defined(__CYGWIN__)) 37 38/// 39/// @file syscall_emul.hh 40/// 41/// This file defines objects used to emulate syscalls from the target 42/// application on the host machine. 43 44#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 dup() handler. 249SyscallReturn dupFunc(SyscallDesc *desc, int num, 250 Process *process, ThreadContext *tc); 251 252/// Target fnctl() handler. 253SyscallReturn fcntlFunc(SyscallDesc *desc, int num, 254 Process *process, ThreadContext *tc); 255 256/// Target fcntl64() handler. 257SyscallReturn fcntl64Func(SyscallDesc *desc, int num, 258 Process *process, ThreadContext *tc); 259 260/// Target setuid() handler. 261SyscallReturn setuidFunc(SyscallDesc *desc, int num, 262 Process *p, ThreadContext *tc); 263 264/// Target getpid() handler. 265SyscallReturn getpidFunc(SyscallDesc *desc, int num, 266 Process *p, ThreadContext *tc); 267 268/// Target getuid() handler. 269SyscallReturn getuidFunc(SyscallDesc *desc, int num, 270 Process *p, ThreadContext *tc); 271 272/// Target getgid() handler. 273SyscallReturn getgidFunc(SyscallDesc *desc, int num, 274 Process *p, ThreadContext *tc); 275 276/// Target getppid() handler. 277SyscallReturn getppidFunc(SyscallDesc *desc, int num, 278 Process *p, ThreadContext *tc); 279 280/// Target geteuid() handler. 281SyscallReturn geteuidFunc(SyscallDesc *desc, int num, 282 Process *p, ThreadContext *tc); 283 284/// Target getegid() handler. 285SyscallReturn getegidFunc(SyscallDesc *desc, int num, 286 Process *p, ThreadContext *tc); 287 288 289 290/// Pseudo Funcs - These functions use a different return convension, 291/// returning a second value in a register other than the normal return register 292SyscallReturn pipePseudoFunc(SyscallDesc *desc, int num, 293 Process *process, ThreadContext *tc); 294 295/// Target getpidPseudo() handler. 296SyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num, 297 Process *p, ThreadContext *tc); 298 299/// Target getuidPseudo() handler. 300SyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num, 301 Process *p, ThreadContext *tc); 302 303/// Target getgidPseudo() handler. 304SyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num, 305 Process *p, ThreadContext *tc); 306 307 308/// This struct is used to build an target-OS-dependent table that 309/// maps the target's open() flags to the host open() flags. 310struct OpenFlagTransTable { 311 int tgtFlag; //!< Target system flag value. 312 int hostFlag; //!< Corresponding host system flag value. 313}; 314 315 316 317/// A readable name for 1,000,000, for converting microseconds to seconds. 318const int one_million = 1000000; 319 320/// Approximate seconds since the epoch (1/1/1970). About a billion, 321/// by my reckoning. We want to keep this a constant (not use the 322/// real-world time) to keep simulations repeatable. 323const unsigned seconds_since_epoch = 1000000000; 324 325/// Helper function to convert current elapsed time to seconds and 326/// microseconds. 327template <class T1, class T2> 328void 329getElapsedTime(T1 &sec, T2 &usec) 330{ 331 int elapsed_usecs = curTick / Clock::Int::us; 332 sec = elapsed_usecs / one_million; 333 usec = elapsed_usecs % one_million; 334} 335 336////////////////////////////////////////////////////////////////////// 337// 338// The following emulation functions are generic, but need to be 339// templated to account for differences in types, constants, etc. 340// 341////////////////////////////////////////////////////////////////////// 342 343/// Target ioctl() handler. For the most part, programs call ioctl() 344/// only to find out if their stdout is a tty, to determine whether to 345/// do line or block buffering. 346template <class OS> 347SyscallReturn 348ioctlFunc(SyscallDesc *desc, int callnum, Process *process, 349 ThreadContext *tc) 350{ 351 int fd = tc->getSyscallArg(0); 352 unsigned req = tc->getSyscallArg(1); 353 354 DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", fd, req); 355 356 if (fd < 0 || process->sim_fd(fd) < 0) { 357 // doesn't map to any simulator fd: not a valid target fd 358 return -EBADF; 359 } 360 361 switch (req) { 362 case OS::TIOCISATTY: 363 case OS::TIOCGETP: 364 case OS::TIOCSETP: 365 case OS::TIOCSETN: 366 case OS::TIOCSETC: 367 case OS::TIOCGETC: 368 case OS::TIOCGETS: 369 case OS::TIOCGETA: 370 return -ENOTTY; 371 372 default: 373 fatal("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ 0x%llx\n", 374 fd, req, tc->readPC()); 375 } 376} 377 378/// Target open() handler. 379template <class OS> 380SyscallReturn 381openFunc(SyscallDesc *desc, int callnum, Process *process, 382 ThreadContext *tc) 383{ 384 std::string path; 385 386 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) 387 return -EFAULT; 388 389 if (path == "/dev/sysdev0") { 390 // This is a memory-mapped high-resolution timer device on Alpha. 391 // We don't support it, so just punt. 392 warn("Ignoring open(%s, ...)\n", path); 393 return -ENOENT; 394 } 395 396 int tgtFlags = tc->getSyscallArg(1); 397 int mode = tc->getSyscallArg(2); 398 int hostFlags = 0; 399 400 // translate open flags 401 for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) { 402 if (tgtFlags & OS::openFlagTable[i].tgtFlag) { 403 tgtFlags &= ~OS::openFlagTable[i].tgtFlag; 404 hostFlags |= OS::openFlagTable[i].hostFlag; 405 } 406 } 407 408 // any target flags left? 409 if (tgtFlags != 0) 410 warn("Syscall: open: cannot decode flags 0x%x", tgtFlags); 411 412#ifdef __CYGWIN32__ 413 hostFlags |= O_BINARY; 414#endif 415 416 DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str()); 417 418 // open the file 419 int fd = open(path.c_str(), hostFlags, mode); 420 421 return (fd == -1) ? -errno : process->alloc_fd(fd); 422} 423 424 425/// Target chmod() handler. 426template <class OS> 427SyscallReturn 428chmodFunc(SyscallDesc *desc, int callnum, Process *process, 429 ThreadContext *tc) 430{ 431 std::string path; 432 433 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) 434 return -EFAULT; 435 436 uint32_t mode = tc->getSyscallArg(1); 437 mode_t hostMode = 0; 438 439 // XXX translate mode flags via OS::something??? 440 hostMode = mode; 441 442 // do the chmod 443 int result = chmod(path.c_str(), hostMode); 444 if (result < 0) 445 return -errno; 446 447 return 0; 448} 449 450 451/// Target fchmod() handler. 452template <class OS> 453SyscallReturn 454fchmodFunc(SyscallDesc *desc, int callnum, Process *process, 455 ThreadContext *tc) 456{ 457 int fd = tc->getSyscallArg(0); 458 if (fd < 0 || process->sim_fd(fd) < 0) { 459 // doesn't map to any simulator fd: not a valid target fd 460 return -EBADF; 461 } 462 463 uint32_t mode = tc->getSyscallArg(1); 464 mode_t hostMode = 0; 465 466 // XXX translate mode flags via OS::someting??? 467 hostMode = mode; 468 469 // do the fchmod 470 int result = fchmod(process->sim_fd(fd), hostMode); 471 if (result < 0) 472 return -errno; 473 474 return 0; 475} 476 477 478/// Target stat() handler. 479template <class OS> 480SyscallReturn 481statFunc(SyscallDesc *desc, int callnum, Process *process, 482 ThreadContext *tc) 483{ 484 std::string path; 485 486 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) 487 return -EFAULT; 488 489 struct stat hostBuf; 490 int result = stat(path.c_str(), &hostBuf); 491 492 if (result < 0) 493 return -errno; 494 495 OS::copyOutStatBuf(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf); 496 497 return 0; 498} 499 500 501/// Target fstat64() handler. 502template <class OS> 503SyscallReturn 504fstat64Func(SyscallDesc *desc, int callnum, Process *process, 505 ThreadContext *tc) 506{ 507 int fd = tc->getSyscallArg(0); 508 if (fd < 0 || process->sim_fd(fd) < 0) { 509 // doesn't map to any simulator fd: not a valid target fd 510 return -EBADF; 511 } 512 513#if NO_STAT64 514 struct stat hostBuf; 515 int result = fstat(process->sim_fd(fd), &hostBuf); 516#else 517 struct stat64 hostBuf; 518 int result = fstat64(process->sim_fd(fd), &hostBuf); 519#endif 520 521 if (result < 0) 522 return -errno; 523 524 OS::copyOutStat64Buf(tc->getMemPort(), fd, tc->getSyscallArg(1), &hostBuf); 525 526 return 0; 527} 528 529 530/// Target lstat() handler. 531template <class OS> 532SyscallReturn 533lstatFunc(SyscallDesc *desc, int callnum, Process *process, 534 ThreadContext *tc) 535{ 536 std::string path; 537 538 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) 539 return -EFAULT; 540 541 struct stat hostBuf; 542 int result = lstat(path.c_str(), &hostBuf); 543 544 if (result < 0) 545 return -errno; 546 547 OS::copyOutStatBuf(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf); 548 549 return 0; 550} 551 552/// Target lstat64() handler. 553template <class OS> 554SyscallReturn 555lstat64Func(SyscallDesc *desc, int callnum, Process *process, 556 ThreadContext *tc) 557{ 558 std::string path; 559 560 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) 561 return -EFAULT; 562 563#if NO_STAT64 564 struct stat hostBuf; 565 int result = lstat(path.c_str(), &hostBuf); 566#else 567 struct stat64 hostBuf; 568 int result = lstat64(path.c_str(), &hostBuf); 569#endif 570 571 if (result < 0) 572 return -errno; 573 574 OS::copyOutStat64Buf(tc->getMemPort(), -1, tc->getSyscallArg(1), &hostBuf); 575 576 return 0; 577} 578 579/// Target fstat() handler. 580template <class OS> 581SyscallReturn 582fstatFunc(SyscallDesc *desc, int callnum, Process *process, 583 ThreadContext *tc) 584{ 585 int fd = process->sim_fd(tc->getSyscallArg(0)); 586 587 DPRINTF(SyscallVerbose, "fstat(%d, ...)\n", fd); 588 589 if (fd < 0) 590 return -EBADF; 591 592 struct stat hostBuf; 593 int result = fstat(fd, &hostBuf); 594 595 if (result < 0) 596 return -errno; 597 598 OS::copyOutStatBuf(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf); 599 600 return 0; 601} 602 603 604/// Target statfs() handler. 605template <class OS> 606SyscallReturn 607statfsFunc(SyscallDesc *desc, int callnum, Process *process, 608 ThreadContext *tc) 609{ 610 std::string path; 611 612 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) 613 return -EFAULT; 614 615 struct statfs hostBuf; 616 int result = statfs(path.c_str(), &hostBuf); 617 618 if (result < 0) 619 return -errno; 620 621 OS::copyOutStatfsBuf(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf); 622 623 return 0; 624} 625 626 627/// Target fstatfs() handler. 628template <class OS> 629SyscallReturn 630fstatfsFunc(SyscallDesc *desc, int callnum, Process *process, 631 ThreadContext *tc) 632{ 633 int fd = process->sim_fd(tc->getSyscallArg(0)); 634 635 if (fd < 0) 636 return -EBADF; 637 638 struct statfs hostBuf; 639 int result = fstatfs(fd, &hostBuf); 640 641 if (result < 0) 642 return -errno; 643 644 OS::copyOutStatfsBuf(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf); 645 646 return 0; 647} 648 649 650/// Target writev() handler. 651template <class OS> 652SyscallReturn 653writevFunc(SyscallDesc *desc, int callnum, Process *process, 654 ThreadContext *tc) 655{ 656 int fd = tc->getSyscallArg(0); 657 if (fd < 0 || process->sim_fd(fd) < 0) { 658 // doesn't map to any simulator fd: not a valid target fd 659 return -EBADF; 660 } 661 662 TranslatingPort *p = tc->getMemPort(); 663 uint64_t tiov_base = tc->getSyscallArg(1); 664 size_t count = tc->getSyscallArg(2); 665 struct iovec hiov[count]; 666 for (int i = 0; i < count; ++i) 667 { 668 typename OS::tgt_iovec tiov; 669 670 p->readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec), 671 (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec)); 672 hiov[i].iov_len = gtoh(tiov.iov_len); 673 hiov[i].iov_base = new char [hiov[i].iov_len]; 674 p->readBlob(gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base, 675 hiov[i].iov_len); 676 } 677 678 int result = writev(process->sim_fd(fd), hiov, count); 679 680 for (int i = 0; i < count; ++i) 681 { 682 delete [] (char *)hiov[i].iov_base; 683 } 684 685 if (result < 0) 686 return -errno; 687 688 return 0; 689} 690 691 692/// Target mmap() handler. 693/// 694/// We don't really handle mmap(). If the target is mmaping an 695/// anonymous region or /dev/zero, we can get away with doing basically 696/// nothing (since memory is initialized to zero and the simulator 697/// doesn't really check addresses anyway). Always print a warning, 698/// since this could be seriously broken if we're not mapping 699/// /dev/zero. 700// 701/// Someday we should explicitly check for /dev/zero in open, flag the 702/// file descriptor, and fail (or implement!) a non-anonymous mmap to 703/// anything else. 704template <class OS> 705SyscallReturn 706mmapFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 707{ 708 Addr start = tc->getSyscallArg(0); 709 uint64_t length = tc->getSyscallArg(1); 710 // int prot = tc->getSyscallArg(2); 711 int flags = tc->getSyscallArg(3); 712 // int fd = p->sim_fd(tc->getSyscallArg(4)); 713 // int offset = tc->getSyscallArg(5); 714 715 if ((start % TheISA::VMPageSize) != 0 || 716 (length % TheISA::VMPageSize) != 0) { 717 warn("mmap failing: arguments not page-aligned: " 718 "start 0x%x length 0x%x", 719 start, length); 720 return -EINVAL; 721 } 722 723 if (start != 0) { 724 warn("mmap: ignoring suggested map address 0x%x, using 0x%x", 725 start, p->mmap_end); 726 } 727 728 // pick next address from our "mmap region" 729 start = p->mmap_end; 730 p->pTable->allocate(start, length); 731 p->mmap_end += length; 732 733 if (!(flags & OS::TGT_MAP_ANONYMOUS)) { 734 warn("allowing mmap of file @ fd %d. " 735 "This will break if not /dev/zero.", tc->getSyscallArg(4)); 736 } 737 738 return start; 739} 740 741/// Target getrlimit() handler. 742template <class OS> 743SyscallReturn 744getrlimitFunc(SyscallDesc *desc, int callnum, Process *process, 745 ThreadContext *tc) 746{ 747 unsigned resource = tc->getSyscallArg(0); 748 TypedBufferArg<typename OS::rlimit> rlp(tc->getSyscallArg(1)); 749 750 switch (resource) { 751 case OS::TGT_RLIMIT_STACK: 752 // max stack size in bytes: make up a number (2MB for now) 753 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; 754 rlp->rlim_cur = htog(rlp->rlim_cur); 755 rlp->rlim_max = htog(rlp->rlim_max); 756 break; 757 758 default: 759 std::cerr << "getrlimitFunc: unimplemented resource " << resource 760 << std::endl; 761 abort(); 762 break; 763 } 764 765 rlp.copyOut(tc->getMemPort()); 766 return 0; 767} 768 769/// Target gettimeofday() handler. 770template <class OS> 771SyscallReturn 772gettimeofdayFunc(SyscallDesc *desc, int callnum, Process *process, 773 ThreadContext *tc) 774{ 775 TypedBufferArg<typename OS::timeval> tp(tc->getSyscallArg(0)); 776 777 getElapsedTime(tp->tv_sec, tp->tv_usec); 778 tp->tv_sec += seconds_since_epoch; 779 tp->tv_sec = htog(tp->tv_sec); 780 tp->tv_usec = htog(tp->tv_usec); 781 782 tp.copyOut(tc->getMemPort()); 783 784 return 0; 785} 786 787 788/// Target utimes() handler. 789template <class OS> 790SyscallReturn 791utimesFunc(SyscallDesc *desc, int callnum, Process *process, 792 ThreadContext *tc) 793{ 794 std::string path; 795 796 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) 797 return -EFAULT; 798 799 TypedBufferArg<typename OS::timeval [2]> tp(tc->getSyscallArg(1)); 800 tp.copyIn(tc->getMemPort()); 801 802 struct timeval hostTimeval[2]; 803 for (int i = 0; i < 2; ++i) 804 { 805 hostTimeval[i].tv_sec = gtoh((*tp)[i].tv_sec); 806 hostTimeval[i].tv_usec = gtoh((*tp)[i].tv_usec); 807 } 808 int result = utimes(path.c_str(), hostTimeval); 809 810 if (result < 0) 811 return -errno; 812 813 return 0; 814} 815/// Target getrusage() function. 816template <class OS> 817SyscallReturn 818getrusageFunc(SyscallDesc *desc, int callnum, Process *process, 819 ThreadContext *tc) 820{ 821 int who = tc->getSyscallArg(0); // THREAD, SELF, or CHILDREN 822 TypedBufferArg<typename OS::rusage> rup(tc->getSyscallArg(1)); 823 824 if (who != OS::TGT_RUSAGE_SELF) { 825 // don't really handle THREAD or CHILDREN, but just warn and 826 // plow ahead 827 warn("getrusage() only supports RUSAGE_SELF. Parameter %d ignored.", 828 who); 829 } 830 831 getElapsedTime(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec); 832 rup->ru_utime.tv_sec = htog(rup->ru_utime.tv_sec); 833 rup->ru_utime.tv_usec = htog(rup->ru_utime.tv_usec); 834 835 rup->ru_stime.tv_sec = 0; 836 rup->ru_stime.tv_usec = 0; 837 rup->ru_maxrss = 0; 838 rup->ru_ixrss = 0; 839 rup->ru_idrss = 0; 840 rup->ru_isrss = 0; 841 rup->ru_minflt = 0; 842 rup->ru_majflt = 0; 843 rup->ru_nswap = 0; 844 rup->ru_inblock = 0; 845 rup->ru_oublock = 0; 846 rup->ru_msgsnd = 0; 847 rup->ru_msgrcv = 0; 848 rup->ru_nsignals = 0; 849 rup->ru_nvcsw = 0; 850 rup->ru_nivcsw = 0; 851 852 rup.copyOut(tc->getMemPort()); 853 854 return 0; 855} 856 857 858 859 860#endif // __SIM_SYSCALL_EMUL_HH__ 861