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