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