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