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