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