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