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