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