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