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