syscall_emul.hh revision 11594:0d151793b2f3
13101Sstever@eecs.umich.edu/* 23101Sstever@eecs.umich.edu * Copyright (c) 2012-2013, 2015 ARM Limited 33101Sstever@eecs.umich.edu * Copyright (c) 2015 Advanced Micro Devices, Inc. 43101Sstever@eecs.umich.edu * All rights reserved 53101Sstever@eecs.umich.edu * 63101Sstever@eecs.umich.edu * The license below extends only to copyright in the software and shall 73101Sstever@eecs.umich.edu * not be construed as granting a license to any other intellectual 83101Sstever@eecs.umich.edu * property including but not limited to intellectual property relating 93101Sstever@eecs.umich.edu * to a hardware implementation of the functionality of the software 103101Sstever@eecs.umich.edu * licensed hereunder. You may use the software subject to the license 113101Sstever@eecs.umich.edu * terms below provided that you ensure that this notice is replicated 123101Sstever@eecs.umich.edu * unmodified and in its entirety in all distributions of the software, 133101Sstever@eecs.umich.edu * modified or unmodified, in source code or in binary form. 143101Sstever@eecs.umich.edu * 153101Sstever@eecs.umich.edu * Copyright (c) 2003-2005 The Regents of The University of Michigan 163101Sstever@eecs.umich.edu * All rights reserved. 173101Sstever@eecs.umich.edu * 183101Sstever@eecs.umich.edu * Redistribution and use in source and binary forms, with or without 193101Sstever@eecs.umich.edu * modification, are permitted provided that the following conditions are 203101Sstever@eecs.umich.edu * met: redistributions of source code must retain the above copyright 213101Sstever@eecs.umich.edu * notice, this list of conditions and the following disclaimer; 223101Sstever@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 233101Sstever@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 243101Sstever@eecs.umich.edu * documentation and/or other materials provided with the distribution; 253101Sstever@eecs.umich.edu * neither the name of the copyright holders nor the names of its 263101Sstever@eecs.umich.edu * contributors may be used to endorse or promote products derived from 273101Sstever@eecs.umich.edu * this software without specific prior written permission. 283101Sstever@eecs.umich.edu * 293101Sstever@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 303101Sstever@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 313101Sstever@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 323101Sstever@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 333101Sstever@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 343101Sstever@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 353101Sstever@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 363101Sstever@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 373101Sstever@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 383101Sstever@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 393101Sstever@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 403101Sstever@eecs.umich.edu * 413101Sstever@eecs.umich.edu * Authors: Steve Reinhardt 423101Sstever@eecs.umich.edu * Kevin Lim 433101Sstever@eecs.umich.edu */ 443101Sstever@eecs.umich.edu 453101Sstever@eecs.umich.edu#ifndef __SIM_SYSCALL_EMUL_HH__ 463101Sstever@eecs.umich.edu#define __SIM_SYSCALL_EMUL_HH__ 473885Sbinkertn@umich.edu 483885Sbinkertn@umich.edu#define NO_STAT64 (defined(__APPLE__) || defined(__OpenBSD__) || \ 494762Snate@binkert.org defined(__FreeBSD__) || defined(__CYGWIN__) || \ 503885Sbinkertn@umich.edu defined(__NetBSD__)) 513885Sbinkertn@umich.edu 523885Sbinkertn@umich.edu/// 533101Sstever@eecs.umich.edu/// @file syscall_emul.hh 544380Sbinkertn@umich.edu/// 554167Sbinkertn@umich.edu/// This file defines objects used to emulate syscalls from the target 563102Sstever@eecs.umich.edu/// application on the host machine. 573101Sstever@eecs.umich.edu 584762Snate@binkert.org#ifdef __CYGWIN32__ 594762Snate@binkert.org#include <sys/fcntl.h> // for O_BINARY 604762Snate@binkert.org 614762Snate@binkert.org#endif 624762Snate@binkert.org#include <fcntl.h> 634762Snate@binkert.org#include <sys/mman.h> 644762Snate@binkert.org#include <sys/stat.h> 654762Snate@binkert.org#include <sys/time.h> 664762Snate@binkert.org#include <sys/uio.h> 674762Snate@binkert.org#include <unistd.h> 684762Snate@binkert.org 695033Smilesck@eecs.umich.edu#include <cerrno> 705033Smilesck@eecs.umich.edu#include <string> 715033Smilesck@eecs.umich.edu 725033Smilesck@eecs.umich.edu#include "base/chunk_generator.hh" 735033Smilesck@eecs.umich.edu#include "base/intmath.hh" // for RoundUp 745033Smilesck@eecs.umich.edu#include "base/loader/object_file.hh" 755033Smilesck@eecs.umich.edu#include "base/misc.hh" 765033Smilesck@eecs.umich.edu#include "base/trace.hh" 775033Smilesck@eecs.umich.edu#include "base/types.hh" 785033Smilesck@eecs.umich.edu#include "config/the_isa.hh" 793101Sstever@eecs.umich.edu#include "cpu/base.hh" 803101Sstever@eecs.umich.edu#include "cpu/thread_context.hh" 813101Sstever@eecs.umich.edu#include "debug/SyscallBase.hh" 825033Smilesck@eecs.umich.edu#include "debug/SyscallVerbose.hh" 833101Sstever@eecs.umich.edu#include "mem/page_table.hh" 843101Sstever@eecs.umich.edu#include "sim/byteswap.hh" 853101Sstever@eecs.umich.edu#include "sim/emul_driver.hh" 863101Sstever@eecs.umich.edu#include "sim/process.hh" 873101Sstever@eecs.umich.edu#include "sim/syscall_emul_buf.hh" 883101Sstever@eecs.umich.edu#include "sim/syscallreturn.hh" 893101Sstever@eecs.umich.edu#include "sim/system.hh" 903101Sstever@eecs.umich.edu 913101Sstever@eecs.umich.edu// This wrapper macro helps out with readability a bit. FLAGEXT specifies 923101Sstever@eecs.umich.edu// the verbosity and FMT is the message to be appended to the syscall 933101Sstever@eecs.umich.edu// header information. The syscall header information contains the cpuid 943101Sstever@eecs.umich.edu// and thread id. 953101Sstever@eecs.umich.edu#define DPRINTF_SYSCALL(FLAGEXT, FMT, ...) \ 963101Sstever@eecs.umich.edu DPRINTFS(Syscall##FLAGEXT, tc->getCpuPtr(), "T%d : syscall " FMT, \ 973101Sstever@eecs.umich.edu tc->threadId(), __VA_ARGS__) 983101Sstever@eecs.umich.edu 993101Sstever@eecs.umich.edu/// 1003101Sstever@eecs.umich.edu/// System call descriptor. 1013101Sstever@eecs.umich.edu/// 1023101Sstever@eecs.umich.educlass SyscallDesc { 1033101Sstever@eecs.umich.edu 1043101Sstever@eecs.umich.edu public: 1053101Sstever@eecs.umich.edu 1063101Sstever@eecs.umich.edu /// Typedef for target syscall handler functions. 1073101Sstever@eecs.umich.edu typedef SyscallReturn (*FuncPtr)(SyscallDesc *, int num, 1083101Sstever@eecs.umich.edu LiveProcess *, ThreadContext *); 1093101Sstever@eecs.umich.edu 1103101Sstever@eecs.umich.edu const char *name; //!< Syscall name (e.g., "open"). 1113101Sstever@eecs.umich.edu FuncPtr funcPtr; //!< Pointer to emulation function. 1123101Sstever@eecs.umich.edu int flags; //!< Flags (see Flags enum). 1133101Sstever@eecs.umich.edu bool warned; //!< Have we warned about unimplemented syscall? 1143101Sstever@eecs.umich.edu 1153101Sstever@eecs.umich.edu /// Flag values for controlling syscall behavior. 1163101Sstever@eecs.umich.edu enum Flags { 1173101Sstever@eecs.umich.edu /// Don't set return regs according to funcPtr return value. 1183101Sstever@eecs.umich.edu /// Used for syscalls with non-standard return conventions 1193101Sstever@eecs.umich.edu /// that explicitly set the ThreadContext regs (e.g., 1203101Sstever@eecs.umich.edu /// sigreturn). 1213101Sstever@eecs.umich.edu SuppressReturnValue = 1, 1223101Sstever@eecs.umich.edu WarnOnce = 2 1233101Sstever@eecs.umich.edu }; 1243101Sstever@eecs.umich.edu 1253101Sstever@eecs.umich.edu /// Constructor. 1263101Sstever@eecs.umich.edu SyscallDesc(const char *_name, FuncPtr _funcPtr, int _flags = 0) 1273101Sstever@eecs.umich.edu : name(_name), funcPtr(_funcPtr), flags(_flags), warned(false) 1283101Sstever@eecs.umich.edu { 1293101Sstever@eecs.umich.edu } 1303101Sstever@eecs.umich.edu 1313101Sstever@eecs.umich.edu /// Emulate the syscall. Public interface for calling through funcPtr. 1325033Smilesck@eecs.umich.edu void doSyscall(int callnum, LiveProcess *proc, ThreadContext *tc); 1335033Smilesck@eecs.umich.edu 1345033Smilesck@eecs.umich.edu /// Is the WarnOnce flag set? 1355033Smilesck@eecs.umich.edu bool warnOnce() const { return (flags & WarnOnce); } 1365033Smilesck@eecs.umich.edu}; 1373101Sstever@eecs.umich.edu 1383101Sstever@eecs.umich.edu 1393101Sstever@eecs.umich.edu////////////////////////////////////////////////////////////////////// 1403101Sstever@eecs.umich.edu// 1413101Sstever@eecs.umich.edu// The following emulation functions are generic enough that they 1423101Sstever@eecs.umich.edu// don't need to be recompiled for different emulated OS's. They are 1433101Sstever@eecs.umich.edu// defined in sim/syscall_emul.cc. 1443101Sstever@eecs.umich.edu// 1453101Sstever@eecs.umich.edu////////////////////////////////////////////////////////////////////// 1463101Sstever@eecs.umich.edu 1473101Sstever@eecs.umich.edu 1483101Sstever@eecs.umich.edu/// Handler for unimplemented syscalls that we haven't thought about. 1493101Sstever@eecs.umich.eduSyscallReturn unimplementedFunc(SyscallDesc *desc, int num, 1503102Sstever@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 1513101Sstever@eecs.umich.edu 1523101Sstever@eecs.umich.edu/// Handler for unimplemented syscalls that we never intend to 1533101Sstever@eecs.umich.edu/// implement (signal handling, etc.) and should not affect the correct 1543101Sstever@eecs.umich.edu/// behavior of the program. Print a warning only if the appropriate 1553101Sstever@eecs.umich.edu/// trace flag is enabled. Return success to the target program. 1563101Sstever@eecs.umich.eduSyscallReturn ignoreFunc(SyscallDesc *desc, int num, 1573101Sstever@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 1583101Sstever@eecs.umich.edu 1593101Sstever@eecs.umich.edu/// Target exit() handler: terminate current context. 1603101Sstever@eecs.umich.eduSyscallReturn exitFunc(SyscallDesc *desc, int num, 1613101Sstever@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 1623101Sstever@eecs.umich.edu 1633101Sstever@eecs.umich.edu/// Target exit_group() handler: terminate simulation. (exit all threads) 1643101Sstever@eecs.umich.eduSyscallReturn exitGroupFunc(SyscallDesc *desc, int num, 1653101Sstever@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 1663101Sstever@eecs.umich.edu 1673101Sstever@eecs.umich.edu/// Target getpagesize() handler. 1685033Smilesck@eecs.umich.eduSyscallReturn getpagesizeFunc(SyscallDesc *desc, int num, 1693101Sstever@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 1703101Sstever@eecs.umich.edu 1713101Sstever@eecs.umich.edu/// Target brk() handler: set brk address. 1724762Snate@binkert.orgSyscallReturn brkFunc(SyscallDesc *desc, int num, 1734762Snate@binkert.org LiveProcess *p, ThreadContext *tc); 1744762Snate@binkert.org 1753101Sstever@eecs.umich.edu/// Target close() handler. 1763101Sstever@eecs.umich.eduSyscallReturn closeFunc(SyscallDesc *desc, int num, 1773101Sstever@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 1783101Sstever@eecs.umich.edu 1795037Smilesck@eecs.umich.edu/// Target read() handler. 1803101Sstever@eecs.umich.eduSyscallReturn readFunc(SyscallDesc *desc, int num, 1815037Smilesck@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 1823101Sstever@eecs.umich.edu 1833101Sstever@eecs.umich.edu/// Target write() handler. 1843101Sstever@eecs.umich.eduSyscallReturn writeFunc(SyscallDesc *desc, int num, 1853101Sstever@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 1863101Sstever@eecs.umich.edu 1873101Sstever@eecs.umich.edu/// Target lseek() handler. 1883101Sstever@eecs.umich.eduSyscallReturn lseekFunc(SyscallDesc *desc, int num, 1893101Sstever@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 1903101Sstever@eecs.umich.edu 1914762Snate@binkert.org/// Target _llseek() handler. 1924762Snate@binkert.orgSyscallReturn _llseekFunc(SyscallDesc *desc, int num, 1934762Snate@binkert.org LiveProcess *p, ThreadContext *tc); 1944762Snate@binkert.org 1954762Snate@binkert.org/// Target munmap() handler. 1964762Snate@binkert.orgSyscallReturn munmapFunc(SyscallDesc *desc, int num, 1974762Snate@binkert.org LiveProcess *p, ThreadContext *tc); 1984762Snate@binkert.org 1994762Snate@binkert.org/// Target gethostname() handler. 2004762Snate@binkert.orgSyscallReturn gethostnameFunc(SyscallDesc *desc, int num, 2014762Snate@binkert.org LiveProcess *p, ThreadContext *tc); 2024762Snate@binkert.org 2034762Snate@binkert.org/// Target getcwd() handler. 2044762Snate@binkert.orgSyscallReturn getcwdFunc(SyscallDesc *desc, int num, 2054762Snate@binkert.org LiveProcess *p, ThreadContext *tc); 2064762Snate@binkert.org 2073101Sstever@eecs.umich.edu/// Target readlink() handler. 2083101Sstever@eecs.umich.eduSyscallReturn readlinkFunc(SyscallDesc *desc, int num, 2093101Sstever@eecs.umich.edu LiveProcess *p, ThreadContext *tc, 2103101Sstever@eecs.umich.edu int index = 0); 2113101Sstever@eecs.umich.eduSyscallReturn readlinkFunc(SyscallDesc *desc, int num, 2123101Sstever@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 2133101Sstever@eecs.umich.edu 2143101Sstever@eecs.umich.edu/// Target unlink() handler. 2153101Sstever@eecs.umich.eduSyscallReturn unlinkHelper(SyscallDesc *desc, int num, 2163101Sstever@eecs.umich.edu LiveProcess *p, ThreadContext *tc, 2173101Sstever@eecs.umich.edu int index); 2183101Sstever@eecs.umich.eduSyscallReturn unlinkFunc(SyscallDesc *desc, int num, 2193101Sstever@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 2203101Sstever@eecs.umich.edu 2213101Sstever@eecs.umich.edu/// Target mkdir() handler. 2223101Sstever@eecs.umich.eduSyscallReturn mkdirFunc(SyscallDesc *desc, int num, 2233101Sstever@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 2243101Sstever@eecs.umich.edu 2253101Sstever@eecs.umich.edu/// Target rename() handler. 2263101Sstever@eecs.umich.eduSyscallReturn renameFunc(SyscallDesc *desc, int num, 2273101Sstever@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 2285033Smilesck@eecs.umich.edu 2295033Smilesck@eecs.umich.edu 2303101Sstever@eecs.umich.edu/// Target truncate() handler. 2313101Sstever@eecs.umich.eduSyscallReturn truncateFunc(SyscallDesc *desc, int num, 2323101Sstever@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 2333101Sstever@eecs.umich.edu 2343101Sstever@eecs.umich.edu 2353101Sstever@eecs.umich.edu/// Target ftruncate() handler. 2363101Sstever@eecs.umich.eduSyscallReturn ftruncateFunc(SyscallDesc *desc, int num, 2373101Sstever@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 2383101Sstever@eecs.umich.edu 2393101Sstever@eecs.umich.edu 2403101Sstever@eecs.umich.edu/// Target truncate64() handler. 2413101Sstever@eecs.umich.eduSyscallReturn truncate64Func(SyscallDesc *desc, int num, 2423101Sstever@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 2433101Sstever@eecs.umich.edu 2443101Sstever@eecs.umich.edu/// Target ftruncate64() handler. 2453101Sstever@eecs.umich.eduSyscallReturn ftruncate64Func(SyscallDesc *desc, int num, 2463101Sstever@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 2473101Sstever@eecs.umich.edu 2483101Sstever@eecs.umich.edu 2493101Sstever@eecs.umich.edu/// Target umask() handler. 2503101Sstever@eecs.umich.eduSyscallReturn umaskFunc(SyscallDesc *desc, int num, 2513101Sstever@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 2523101Sstever@eecs.umich.edu 2533101Sstever@eecs.umich.edu 2543101Sstever@eecs.umich.edu/// Target chown() handler. 2553101Sstever@eecs.umich.eduSyscallReturn chownFunc(SyscallDesc *desc, int num, 2563101Sstever@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 2573101Sstever@eecs.umich.edu 2584762Snate@binkert.org 2594762Snate@binkert.org/// Target fchown() handler. 2604762Snate@binkert.orgSyscallReturn fchownFunc(SyscallDesc *desc, int num, 2614762Snate@binkert.org LiveProcess *p, ThreadContext *tc); 2623101Sstever@eecs.umich.edu 2633101Sstever@eecs.umich.edu/// Target dup() handler. 2643101Sstever@eecs.umich.eduSyscallReturn dupFunc(SyscallDesc *desc, int num, 2653101Sstever@eecs.umich.edu LiveProcess *process, ThreadContext *tc); 2663101Sstever@eecs.umich.edu 2673101Sstever@eecs.umich.edu/// Target fnctl() handler. 2683101Sstever@eecs.umich.eduSyscallReturn fcntlFunc(SyscallDesc *desc, int num, 2693101Sstever@eecs.umich.edu LiveProcess *process, ThreadContext *tc); 2703101Sstever@eecs.umich.edu 2713101Sstever@eecs.umich.edu/// Target fcntl64() handler. 2723101Sstever@eecs.umich.eduSyscallReturn fcntl64Func(SyscallDesc *desc, int num, 2733714Sstever@eecs.umich.edu LiveProcess *process, ThreadContext *tc); 2743714Sstever@eecs.umich.edu 2753714Sstever@eecs.umich.edu/// Target setuid() handler. 2763714Sstever@eecs.umich.eduSyscallReturn setuidFunc(SyscallDesc *desc, int num, 2773714Sstever@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 2783714Sstever@eecs.umich.edu 2793101Sstever@eecs.umich.edu/// Target getpid() handler. 2803101Sstever@eecs.umich.eduSyscallReturn getpidFunc(SyscallDesc *desc, int num, 2813101Sstever@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 2823101Sstever@eecs.umich.edu 2833101Sstever@eecs.umich.edu/// Target getuid() handler. 2843101Sstever@eecs.umich.eduSyscallReturn getuidFunc(SyscallDesc *desc, int num, 2853101Sstever@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 2863101Sstever@eecs.umich.edu 2873101Sstever@eecs.umich.edu/// Target getgid() handler. 2883101Sstever@eecs.umich.eduSyscallReturn getgidFunc(SyscallDesc *desc, int num, 2893101Sstever@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 2903101Sstever@eecs.umich.edu 2913101Sstever@eecs.umich.edu/// Target getppid() handler. 2923101Sstever@eecs.umich.eduSyscallReturn getppidFunc(SyscallDesc *desc, int num, 2933101Sstever@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 2943101Sstever@eecs.umich.edu 2953101Sstever@eecs.umich.edu/// Target geteuid() handler. 2963101Sstever@eecs.umich.eduSyscallReturn geteuidFunc(SyscallDesc *desc, int num, 2973101Sstever@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 2983101Sstever@eecs.umich.edu 2993101Sstever@eecs.umich.edu/// Target getegid() handler. 3003101Sstever@eecs.umich.eduSyscallReturn getegidFunc(SyscallDesc *desc, int num, 3013101Sstever@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 3023101Sstever@eecs.umich.edu 3033101Sstever@eecs.umich.edu/// Target clone() handler. 3045033Smilesck@eecs.umich.eduSyscallReturn cloneFunc(SyscallDesc *desc, int num, 3053101Sstever@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 3063101Sstever@eecs.umich.edu 3073101Sstever@eecs.umich.edu/// Target access() handler 3083101Sstever@eecs.umich.eduSyscallReturn accessFunc(SyscallDesc *desc, int num, 3093101Sstever@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 3103101Sstever@eecs.umich.eduSyscallReturn accessFunc(SyscallDesc *desc, int num, 3113101Sstever@eecs.umich.edu LiveProcess *p, ThreadContext *tc, 3123101Sstever@eecs.umich.edu int index); 3133101Sstever@eecs.umich.edu 3143101Sstever@eecs.umich.edu/// Futex system call 3153101Sstever@eecs.umich.edu/// Implemented by Daniel Sanchez 3163101Sstever@eecs.umich.edu/// Used by printf's in multi-threaded apps 3173101Sstever@eecs.umich.edutemplate <class OS> 3183101Sstever@eecs.umich.eduSyscallReturn 3193101Sstever@eecs.umich.edufutexFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 3204762Snate@binkert.org ThreadContext *tc) 3213101Sstever@eecs.umich.edu{ 3223101Sstever@eecs.umich.edu int index_uaddr = 0; 3233101Sstever@eecs.umich.edu int index_op = 1; 3243101Sstever@eecs.umich.edu int index_val = 2; 3253101Sstever@eecs.umich.edu int index_timeout = 3; 3263101Sstever@eecs.umich.edu 3273101Sstever@eecs.umich.edu uint64_t uaddr = process->getSyscallArg(tc, index_uaddr); 3283101Sstever@eecs.umich.edu int op = process->getSyscallArg(tc, index_op); 3293101Sstever@eecs.umich.edu int val = process->getSyscallArg(tc, index_val); 3303101Sstever@eecs.umich.edu uint64_t timeout = process->getSyscallArg(tc, index_timeout); 3313101Sstever@eecs.umich.edu 3323101Sstever@eecs.umich.edu std::map<uint64_t, std::list<ThreadContext *> * > 3333101Sstever@eecs.umich.edu &futex_map = tc->getSystemPtr()->futexMap; 3343101Sstever@eecs.umich.edu 3353101Sstever@eecs.umich.edu DPRINTF(SyscallVerbose, "In sys_futex: Address=%llx, op=%d, val=%d\n", 3363101Sstever@eecs.umich.edu uaddr, op, val); 3373101Sstever@eecs.umich.edu 3383101Sstever@eecs.umich.edu op &= ~OS::TGT_FUTEX_PRIVATE_FLAG; 3393101Sstever@eecs.umich.edu 3403101Sstever@eecs.umich.edu if (op == OS::TGT_FUTEX_WAIT) { 3413101Sstever@eecs.umich.edu if (timeout != 0) { 3423101Sstever@eecs.umich.edu warn("sys_futex: FUTEX_WAIT with non-null timeout unimplemented;" 3433101Sstever@eecs.umich.edu "we'll wait indefinitely"); 3443101Sstever@eecs.umich.edu } 3453101Sstever@eecs.umich.edu 3463101Sstever@eecs.umich.edu uint8_t *buf = new uint8_t[sizeof(int)]; 3473101Sstever@eecs.umich.edu tc->getMemProxy().readBlob((Addr)uaddr, buf, (int)sizeof(int)); 3483101Sstever@eecs.umich.edu int mem_val = *((int *)buf); 3493102Sstever@eecs.umich.edu delete[] buf; 3503714Sstever@eecs.umich.edu 3513101Sstever@eecs.umich.edu if (val != mem_val) { 3523714Sstever@eecs.umich.edu DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAKE, read: %d, " 3533714Sstever@eecs.umich.edu "expected: %d\n", mem_val, val); 3543714Sstever@eecs.umich.edu return -OS::TGT_EWOULDBLOCK; 3553101Sstever@eecs.umich.edu } 3563101Sstever@eecs.umich.edu 3574762Snate@binkert.org // Queue the thread context 3584762Snate@binkert.org std::list<ThreadContext *> * tcWaitList; 3594762Snate@binkert.org if (futex_map.count(uaddr)) { 3603101Sstever@eecs.umich.edu tcWaitList = futex_map.find(uaddr)->second; 3613101Sstever@eecs.umich.edu } else { 3623101Sstever@eecs.umich.edu tcWaitList = new std::list<ThreadContext *>(); 3633101Sstever@eecs.umich.edu futex_map.insert(std::pair< uint64_t, 3643101Sstever@eecs.umich.edu std::list<ThreadContext *> * >(uaddr, tcWaitList)); 3653101Sstever@eecs.umich.edu } 3663101Sstever@eecs.umich.edu tcWaitList->push_back(tc); 3673101Sstever@eecs.umich.edu DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAIT, suspending calling " 3683101Sstever@eecs.umich.edu "thread context\n"); 3693101Sstever@eecs.umich.edu tc->suspend(); 3703101Sstever@eecs.umich.edu return 0; 3713101Sstever@eecs.umich.edu } else if (op == OS::TGT_FUTEX_WAKE){ 3723101Sstever@eecs.umich.edu int wokenUp = 0; 3733101Sstever@eecs.umich.edu std::list<ThreadContext *> * tcWaitList; 3743101Sstever@eecs.umich.edu if (futex_map.count(uaddr)) { 3753101Sstever@eecs.umich.edu tcWaitList = futex_map.find(uaddr)->second; 3763101Sstever@eecs.umich.edu while (tcWaitList->size() > 0 && wokenUp < val) { 3773101Sstever@eecs.umich.edu tcWaitList->front()->activate(); 3783101Sstever@eecs.umich.edu tcWaitList->pop_front(); 3793101Sstever@eecs.umich.edu wokenUp++; 3804446Sbinkertn@umich.edu } 3813101Sstever@eecs.umich.edu if (tcWaitList->empty()) { 3825468Snate@binkert.org futex_map.erase(uaddr); 3835468Snate@binkert.org delete tcWaitList; 3845468Snate@binkert.org } 3855468Snate@binkert.org } 3865468Snate@binkert.org DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAKE, activated %d waiting " 3875468Snate@binkert.org "thread contexts\n", wokenUp); 3885468Snate@binkert.org return wokenUp; 3894762Snate@binkert.org } else { 3904762Snate@binkert.org warn("sys_futex: op %d is not implemented, just returning...", op); 3914762Snate@binkert.org return 0; 3923101Sstever@eecs.umich.edu } 3933101Sstever@eecs.umich.edu 3943101Sstever@eecs.umich.edu} 3953101Sstever@eecs.umich.edu 3963101Sstever@eecs.umich.edu 3973101Sstever@eecs.umich.edu/// Pseudo Funcs - These functions use a different return convension, 3983101Sstever@eecs.umich.edu/// returning a second value in a register other than the normal return register 3993101Sstever@eecs.umich.eduSyscallReturn pipePseudoFunc(SyscallDesc *desc, int num, 4003102Sstever@eecs.umich.edu LiveProcess *process, ThreadContext *tc); 4013101Sstever@eecs.umich.edu 4023101Sstever@eecs.umich.edu/// Target getpidPseudo() handler. 4033101Sstever@eecs.umich.eduSyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num, 4044168Sbinkertn@umich.edu LiveProcess *p, ThreadContext *tc); 4053101Sstever@eecs.umich.edu 4063101Sstever@eecs.umich.edu/// Target getuidPseudo() handler. 4073101Sstever@eecs.umich.eduSyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num, 4083101Sstever@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 4093101Sstever@eecs.umich.edu 4103101Sstever@eecs.umich.edu/// Target getgidPseudo() handler. 4113102Sstever@eecs.umich.eduSyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num, 4123101Sstever@eecs.umich.edu LiveProcess *p, ThreadContext *tc); 4133101Sstever@eecs.umich.edu 4143101Sstever@eecs.umich.edu 4153101Sstever@eecs.umich.edu/// A readable name for 1,000,000, for converting microseconds to seconds. 4163101Sstever@eecs.umich.educonst int one_million = 1000000; 4173101Sstever@eecs.umich.edu/// A readable name for 1,000,000,000, for converting nanoseconds to seconds. 4183101Sstever@eecs.umich.educonst int one_billion = 1000000000; 4193101Sstever@eecs.umich.edu 4203101Sstever@eecs.umich.edu/// Approximate seconds since the epoch (1/1/1970). About a billion, 4213101Sstever@eecs.umich.edu/// by my reckoning. We want to keep this a constant (not use the 4223101Sstever@eecs.umich.edu/// real-world time) to keep simulations repeatable. 4233102Sstever@eecs.umich.educonst unsigned seconds_since_epoch = 1000000000; 4243101Sstever@eecs.umich.edu 4253101Sstever@eecs.umich.edu/// Helper function to convert current elapsed time to seconds and 4263101Sstever@eecs.umich.edu/// microseconds. 4273584Ssaidi@eecs.umich.edutemplate <class T1, class T2> 4283584Ssaidi@eecs.umich.eduvoid 4293584Ssaidi@eecs.umich.edugetElapsedTimeMicro(T1 &sec, T2 &usec) 4303584Ssaidi@eecs.umich.edu{ 4313584Ssaidi@eecs.umich.edu uint64_t elapsed_usecs = curTick() / SimClock::Int::us; 4323101Sstever@eecs.umich.edu sec = elapsed_usecs / one_million; 4333101Sstever@eecs.umich.edu usec = elapsed_usecs % one_million; 4345033Smilesck@eecs.umich.edu} 4353101Sstever@eecs.umich.edu 4363101Sstever@eecs.umich.edu/// Helper function to convert current elapsed time to seconds and 4373101Sstever@eecs.umich.edu/// nanoseconds. 4383101Sstever@eecs.umich.edutemplate <class T1, class T2> 4393101Sstever@eecs.umich.eduvoid 4403101Sstever@eecs.umich.edugetElapsedTimeNano(T1 &sec, T2 &nsec) 4413101Sstever@eecs.umich.edu{ 4423101Sstever@eecs.umich.edu uint64_t elapsed_nsecs = curTick() / SimClock::Int::ns; 4433101Sstever@eecs.umich.edu sec = elapsed_nsecs / one_billion; 4443101Sstever@eecs.umich.edu nsec = elapsed_nsecs % one_billion; 4453101Sstever@eecs.umich.edu} 4463101Sstever@eecs.umich.edu 4473101Sstever@eecs.umich.edu////////////////////////////////////////////////////////////////////// 4483101Sstever@eecs.umich.edu// 4493101Sstever@eecs.umich.edu// The following emulation functions are generic, but need to be 4503101Sstever@eecs.umich.edu// templated to account for differences in types, constants, etc. 4513101Sstever@eecs.umich.edu// 4523101Sstever@eecs.umich.edu////////////////////////////////////////////////////////////////////// 4533101Sstever@eecs.umich.edu 4543101Sstever@eecs.umich.edu#if NO_STAT64 4553101Sstever@eecs.umich.edu typedef struct stat hst_stat; 4563101Sstever@eecs.umich.edu typedef struct stat hst_stat64; 4573101Sstever@eecs.umich.edu#else 4583101Sstever@eecs.umich.edu typedef struct stat hst_stat; 4593101Sstever@eecs.umich.edu typedef struct stat64 hst_stat64; 4603101Sstever@eecs.umich.edu#endif 4613101Sstever@eecs.umich.edu 4623101Sstever@eecs.umich.edu//// Helper function to convert a host stat buffer to a target stat 4633101Sstever@eecs.umich.edu//// buffer. Also copies the target buffer out to the simulated 4643101Sstever@eecs.umich.edu//// memory space. Used by stat(), fstat(), and lstat(). 4653101Sstever@eecs.umich.edu 4665219Ssaidi@eecs.umich.edutemplate <typename target_stat, typename host_stat> 4675219Ssaidi@eecs.umich.edustatic void 4685219Ssaidi@eecs.umich.educonvertStatBuf(target_stat &tgt, host_stat *host, bool fakeTTY = false) 4693101Sstever@eecs.umich.edu{ 4703101Sstever@eecs.umich.edu using namespace TheISA; 4713101Sstever@eecs.umich.edu 4723101Sstever@eecs.umich.edu if (fakeTTY) 4733101Sstever@eecs.umich.edu tgt->st_dev = 0xA; 4743101Sstever@eecs.umich.edu else 4753101Sstever@eecs.umich.edu tgt->st_dev = host->st_dev; 4763101Sstever@eecs.umich.edu tgt->st_dev = TheISA::htog(tgt->st_dev); 4773101Sstever@eecs.umich.edu tgt->st_ino = host->st_ino; 4783101Sstever@eecs.umich.edu tgt->st_ino = TheISA::htog(tgt->st_ino); 4793101Sstever@eecs.umich.edu tgt->st_mode = host->st_mode; 4803101Sstever@eecs.umich.edu if (fakeTTY) { 4813101Sstever@eecs.umich.edu // Claim to be a character device 4823101Sstever@eecs.umich.edu tgt->st_mode &= ~S_IFMT; // Clear S_IFMT 4833101Sstever@eecs.umich.edu tgt->st_mode |= S_IFCHR; // Set S_IFCHR 4843101Sstever@eecs.umich.edu } 4853101Sstever@eecs.umich.edu tgt->st_mode = TheISA::htog(tgt->st_mode); 4863101Sstever@eecs.umich.edu tgt->st_nlink = host->st_nlink; 4874762Snate@binkert.org tgt->st_nlink = TheISA::htog(tgt->st_nlink); 4884762Snate@binkert.org tgt->st_uid = host->st_uid; 4894762Snate@binkert.org tgt->st_uid = TheISA::htog(tgt->st_uid); 4904762Snate@binkert.org tgt->st_gid = host->st_gid; 4914762Snate@binkert.org tgt->st_gid = TheISA::htog(tgt->st_gid); 4924762Snate@binkert.org if (fakeTTY) 4934762Snate@binkert.org tgt->st_rdev = 0x880d; 4944762Snate@binkert.org else 4954762Snate@binkert.org tgt->st_rdev = host->st_rdev; 4963101Sstever@eecs.umich.edu tgt->st_rdev = TheISA::htog(tgt->st_rdev); 4973101Sstever@eecs.umich.edu tgt->st_size = host->st_size; 4983101Sstever@eecs.umich.edu tgt->st_size = TheISA::htog(tgt->st_size); 4994762Snate@binkert.org tgt->st_atimeX = host->st_atime; 5004762Snate@binkert.org tgt->st_atimeX = TheISA::htog(tgt->st_atimeX); 5014762Snate@binkert.org tgt->st_mtimeX = host->st_mtime; 5024762Snate@binkert.org tgt->st_mtimeX = TheISA::htog(tgt->st_mtimeX); 5034762Snate@binkert.org tgt->st_ctimeX = host->st_ctime; 5044762Snate@binkert.org tgt->st_ctimeX = TheISA::htog(tgt->st_ctimeX); 5054762Snate@binkert.org // Force the block size to be 8k. This helps to ensure buffered io works 5064762Snate@binkert.org // consistently across different hosts. 5074762Snate@binkert.org tgt->st_blksize = 0x2000; 5083101Sstever@eecs.umich.edu tgt->st_blksize = TheISA::htog(tgt->st_blksize); 5093101Sstever@eecs.umich.edu tgt->st_blocks = host->st_blocks; 5103101Sstever@eecs.umich.edu tgt->st_blocks = TheISA::htog(tgt->st_blocks); 5113101Sstever@eecs.umich.edu} 5123101Sstever@eecs.umich.edu 5133101Sstever@eecs.umich.edu// Same for stat64 5143101Sstever@eecs.umich.edu 5153101Sstever@eecs.umich.edutemplate <typename target_stat, typename host_stat64> 5163102Sstever@eecs.umich.edustatic void 5173101Sstever@eecs.umich.educonvertStat64Buf(target_stat &tgt, host_stat64 *host, bool fakeTTY = false) 5183101Sstever@eecs.umich.edu{ 5193101Sstever@eecs.umich.edu using namespace TheISA; 5204762Snate@binkert.org 5214762Snate@binkert.org convertStatBuf<target_stat, host_stat64>(tgt, host, fakeTTY); 5224762Snate@binkert.org#if defined(STAT_HAVE_NSEC) 5233101Sstever@eecs.umich.edu tgt->st_atime_nsec = host->st_atime_nsec; 5243101Sstever@eecs.umich.edu tgt->st_atime_nsec = TheISA::htog(tgt->st_atime_nsec); 5253101Sstever@eecs.umich.edu tgt->st_mtime_nsec = host->st_mtime_nsec; 5263101Sstever@eecs.umich.edu tgt->st_mtime_nsec = TheISA::htog(tgt->st_mtime_nsec); 5273101Sstever@eecs.umich.edu tgt->st_ctime_nsec = host->st_ctime_nsec; 5283101Sstever@eecs.umich.edu tgt->st_ctime_nsec = TheISA::htog(tgt->st_ctime_nsec); 5293101Sstever@eecs.umich.edu#else 5303101Sstever@eecs.umich.edu tgt->st_atime_nsec = 0; 5313101Sstever@eecs.umich.edu tgt->st_mtime_nsec = 0; 5323101Sstever@eecs.umich.edu tgt->st_ctime_nsec = 0; 5333101Sstever@eecs.umich.edu#endif 5343101Sstever@eecs.umich.edu} 5353101Sstever@eecs.umich.edu 5363101Sstever@eecs.umich.edu//Here are a couple convenience functions 5373101Sstever@eecs.umich.edutemplate<class OS> 5383101Sstever@eecs.umich.edustatic void 5393101Sstever@eecs.umich.educopyOutStatBuf(SETranslatingPortProxy &mem, Addr addr, 5403101Sstever@eecs.umich.edu hst_stat *host, bool fakeTTY = false) 5413101Sstever@eecs.umich.edu{ 5423101Sstever@eecs.umich.edu typedef TypedBufferArg<typename OS::tgt_stat> tgt_stat_buf; 5434380Sbinkertn@umich.edu tgt_stat_buf tgt(addr); 5444380Sbinkertn@umich.edu convertStatBuf<tgt_stat_buf, hst_stat>(tgt, host, fakeTTY); 5454380Sbinkertn@umich.edu tgt.copyOut(mem); 5463101Sstever@eecs.umich.edu} 5474380Sbinkertn@umich.edu 5484380Sbinkertn@umich.edutemplate<class OS> 5494380Sbinkertn@umich.edustatic void 5503101Sstever@eecs.umich.educopyOutStat64Buf(SETranslatingPortProxy &mem, Addr addr, 5513101Sstever@eecs.umich.edu hst_stat64 *host, bool fakeTTY = false) 5523101Sstever@eecs.umich.edu{ 5533101Sstever@eecs.umich.edu typedef TypedBufferArg<typename OS::tgt_stat64> tgt_stat_buf; 5544762Snate@binkert.org tgt_stat_buf tgt(addr); 5553101Sstever@eecs.umich.edu convertStat64Buf<tgt_stat_buf, hst_stat64>(tgt, host, fakeTTY); 5563101Sstever@eecs.umich.edu tgt.copyOut(mem); 5573101Sstever@eecs.umich.edu} 5583101Sstever@eecs.umich.edu 5593101Sstever@eecs.umich.edu/// Target ioctl() handler. For the most part, programs call ioctl() 5603101Sstever@eecs.umich.edu/// only to find out if their stdout is a tty, to determine whether to 5613101Sstever@eecs.umich.edu/// do line or block buffering. We always claim that output fds are 5623101Sstever@eecs.umich.edu/// not TTYs to provide repeatable results. 5633101Sstever@eecs.umich.edutemplate <class OS> 5643101Sstever@eecs.umich.eduSyscallReturn 5653101Sstever@eecs.umich.eduioctlFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 5663101Sstever@eecs.umich.edu ThreadContext *tc) 5673101Sstever@eecs.umich.edu{ 5683101Sstever@eecs.umich.edu int index = 0; 5693101Sstever@eecs.umich.edu int tgt_fd = process->getSyscallArg(tc, index); 5703101Sstever@eecs.umich.edu unsigned req = process->getSyscallArg(tc, index); 5713101Sstever@eecs.umich.edu 5723101Sstever@eecs.umich.edu DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", tgt_fd, req); 5733101Sstever@eecs.umich.edu 5743101Sstever@eecs.umich.edu FDEntry *fde = process->getFDEntry(tgt_fd); 5754380Sbinkertn@umich.edu 5763101Sstever@eecs.umich.edu if (fde == NULL) { 5773101Sstever@eecs.umich.edu // doesn't map to any simulator fd: not a valid target fd 5784762Snate@binkert.org return -EBADF; 5794762Snate@binkert.org } 5804762Snate@binkert.org 5814762Snate@binkert.org if (fde->driver != NULL) { 5824380Sbinkertn@umich.edu return fde->driver->ioctl(process, tc, req); 5834380Sbinkertn@umich.edu } 5843101Sstever@eecs.umich.edu 5853932Sbinkertn@umich.edu if (OS::isTtyReq(req)) { 5863932Sbinkertn@umich.edu return -ENOTTY; 5873932Sbinkertn@umich.edu } 5883932Sbinkertn@umich.edu 5893932Sbinkertn@umich.edu warn("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ \n", 5903932Sbinkertn@umich.edu tgt_fd, req, tc->pcState()); 5913932Sbinkertn@umich.edu return -ENOTTY; 5923932Sbinkertn@umich.edu} 5933932Sbinkertn@umich.edu 5943932Sbinkertn@umich.edutemplate <class OS> 5953932Sbinkertn@umich.edustatic SyscallReturn 5963932Sbinkertn@umich.eduopenFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 5973932Sbinkertn@umich.edu ThreadContext *tc, int index) 5983885Sbinkertn@umich.edu{ 5993932Sbinkertn@umich.edu std::string path; 6003932Sbinkertn@umich.edu 6013885Sbinkertn@umich.edu if (!tc->getMemProxy().tryReadString(path, 6023932Sbinkertn@umich.edu process->getSyscallArg(tc, index))) 6033932Sbinkertn@umich.edu return -EFAULT; 6043932Sbinkertn@umich.edu 6053932Sbinkertn@umich.edu int tgtFlags = process->getSyscallArg(tc, index); 6063932Sbinkertn@umich.edu int mode = process->getSyscallArg(tc, index); 6073932Sbinkertn@umich.edu int hostFlags = 0; 6083932Sbinkertn@umich.edu 6093932Sbinkertn@umich.edu // translate open flags 6103932Sbinkertn@umich.edu for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) { 6113932Sbinkertn@umich.edu if (tgtFlags & OS::openFlagTable[i].tgtFlag) { 6123932Sbinkertn@umich.edu tgtFlags &= ~OS::openFlagTable[i].tgtFlag; 6133932Sbinkertn@umich.edu hostFlags |= OS::openFlagTable[i].hostFlag; 6143932Sbinkertn@umich.edu } 6153932Sbinkertn@umich.edu } 6163932Sbinkertn@umich.edu 6173932Sbinkertn@umich.edu // any target flags left? 6183932Sbinkertn@umich.edu if (tgtFlags != 0) 6193932Sbinkertn@umich.edu warn("Syscall: open: cannot decode flags 0x%x", tgtFlags); 6203885Sbinkertn@umich.edu 6213885Sbinkertn@umich.edu#ifdef __CYGWIN32__ 6223885Sbinkertn@umich.edu hostFlags |= O_BINARY; 6233885Sbinkertn@umich.edu#endif 6244762Snate@binkert.org 6254762Snate@binkert.org // Adjust path for current working directory 6264762Snate@binkert.org path = process->fullPath(path); 6273885Sbinkertn@umich.edu 6283932Sbinkertn@umich.edu DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str()); 6293885Sbinkertn@umich.edu 6304762Snate@binkert.org if (startswith(path, "/dev/")) { 6314762Snate@binkert.org std::string filename = path.substr(strlen("/dev/")); 6324762Snate@binkert.org if (filename == "sysdev0") { 6334762Snate@binkert.org // This is a memory-mapped high-resolution timer device on Alpha. 6344762Snate@binkert.org // We don't support it, so just punt. 6354762Snate@binkert.org warn("Ignoring open(%s, ...)\n", path); 6364762Snate@binkert.org return -ENOENT; 6374762Snate@binkert.org } 6384762Snate@binkert.org 6394762Snate@binkert.org EmulatedDriver *drv = process->findDriver(filename); 6404762Snate@binkert.org if (drv != NULL) { 6414762Snate@binkert.org // the driver's open method will allocate a fd from the 6424762Snate@binkert.org // process if necessary. 6434762Snate@binkert.org return drv->open(process, tc, mode, hostFlags); 6444762Snate@binkert.org } 6454762Snate@binkert.org 6464762Snate@binkert.org // fall through here for pass through to host devices, such as 6474762Snate@binkert.org // /dev/zero 6484762Snate@binkert.org } 6494762Snate@binkert.org 6504762Snate@binkert.org int fd; 6514762Snate@binkert.org int local_errno; 6524762Snate@binkert.org if (startswith(path, "/proc/") || startswith(path, "/system/") || 6534762Snate@binkert.org startswith(path, "/platform/") || startswith(path, "/sys/")) { 6544762Snate@binkert.org // It's a proc/sys entry and requires special handling 6554762Snate@binkert.org fd = OS::openSpecialFile(path, process, tc); 6563885Sbinkertn@umich.edu local_errno = ENOENT; 6574762Snate@binkert.org } else { 6583885Sbinkertn@umich.edu // open the file 6593885Sbinkertn@umich.edu fd = open(path.c_str(), hostFlags, mode); 6603932Sbinkertn@umich.edu local_errno = errno; 6613885Sbinkertn@umich.edu } 6623101Sstever@eecs.umich.edu 6633101Sstever@eecs.umich.edu if (fd == -1) 6643101Sstever@eecs.umich.edu return -local_errno; 6653101Sstever@eecs.umich.edu 6663101Sstever@eecs.umich.edu return process->allocFD(fd, path.c_str(), hostFlags, mode, false); 6673101Sstever@eecs.umich.edu} 6683101Sstever@eecs.umich.edu 6693101Sstever@eecs.umich.edu/// Target open() handler. 6703101Sstever@eecs.umich.edutemplate <class OS> 6713101Sstever@eecs.umich.eduSyscallReturn 6723101Sstever@eecs.umich.eduopenFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 6733101Sstever@eecs.umich.edu ThreadContext *tc) 6743101Sstever@eecs.umich.edu{ 6753101Sstever@eecs.umich.edu return openFunc<OS>(desc, callnum, process, tc, 0); 6764762Snate@binkert.org} 6773101Sstever@eecs.umich.edu 6785033Smilesck@eecs.umich.edu/// Target openat() handler. 6794762Snate@binkert.orgtemplate <class OS> 6804762Snate@binkert.orgSyscallReturn 6814762Snate@binkert.orgopenatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 6824762Snate@binkert.org ThreadContext *tc) 6834762Snate@binkert.org{ 6844762Snate@binkert.org int index = 0; 6854762Snate@binkert.org int dirfd = process->getSyscallArg(tc, index); 6863101Sstever@eecs.umich.edu if (dirfd != OS::TGT_AT_FDCWD) 6873101Sstever@eecs.umich.edu warn("openat: first argument not AT_FDCWD; unlikely to work"); 6883101Sstever@eecs.umich.edu return openFunc<OS>(desc, callnum, process, tc, 1); 6893101Sstever@eecs.umich.edu} 6903101Sstever@eecs.umich.edu 6913101Sstever@eecs.umich.edu/// Target unlinkat() handler. 6923101Sstever@eecs.umich.edutemplate <class OS> 6933101Sstever@eecs.umich.eduSyscallReturn 6943101Sstever@eecs.umich.eduunlinkatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 6953101Sstever@eecs.umich.edu ThreadContext *tc) 6963101Sstever@eecs.umich.edu{ 6973101Sstever@eecs.umich.edu int index = 0; 6983101Sstever@eecs.umich.edu int dirfd = process->getSyscallArg(tc, index); 6993101Sstever@eecs.umich.edu if (dirfd != OS::TGT_AT_FDCWD) 7003101Sstever@eecs.umich.edu warn("unlinkat: first argument not AT_FDCWD; unlikely to work"); 7013101Sstever@eecs.umich.edu 7023101Sstever@eecs.umich.edu return unlinkHelper(desc, callnum, process, tc, 1); 7033101Sstever@eecs.umich.edu} 7043101Sstever@eecs.umich.edu 7053101Sstever@eecs.umich.edu/// Target facessat() handler 7064762Snate@binkert.orgtemplate <class OS> 7073101Sstever@eecs.umich.eduSyscallReturn 7083101Sstever@eecs.umich.edufaccessatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 7093101Sstever@eecs.umich.edu ThreadContext *tc) 7104762Snate@binkert.org{ 7114762Snate@binkert.org int index = 0; 7124762Snate@binkert.org int dirfd = process->getSyscallArg(tc, index); 7133101Sstever@eecs.umich.edu if (dirfd != OS::TGT_AT_FDCWD) 7143101Sstever@eecs.umich.edu warn("faccessat: first argument not AT_FDCWD; unlikely to work"); 7153101Sstever@eecs.umich.edu return accessFunc(desc, callnum, process, tc, 1); 7163101Sstever@eecs.umich.edu} 7174762Snate@binkert.org 7184762Snate@binkert.org/// Target readlinkat() handler 7194762Snate@binkert.orgtemplate <class OS> 7204762Snate@binkert.orgSyscallReturn 7214762Snate@binkert.orgreadlinkatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 7224762Snate@binkert.org ThreadContext *tc) 7234762Snate@binkert.org{ 7244762Snate@binkert.org int index = 0; 7254762Snate@binkert.org int dirfd = process->getSyscallArg(tc, index); 7264762Snate@binkert.org if (dirfd != OS::TGT_AT_FDCWD) 7274762Snate@binkert.org warn("openat: first argument not AT_FDCWD; unlikely to work"); 7284762Snate@binkert.org return readlinkFunc(desc, callnum, process, tc, 1); 7294762Snate@binkert.org} 7304762Snate@binkert.org 7314762Snate@binkert.org/// Target renameat() handler. 7324762Snate@binkert.orgtemplate <class OS> 7334762Snate@binkert.orgSyscallReturn 7344762Snate@binkert.orgrenameatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 7354762Snate@binkert.org ThreadContext *tc) 7364762Snate@binkert.org{ 7374762Snate@binkert.org int index = 0; 7384762Snate@binkert.org 7394762Snate@binkert.org int olddirfd = process->getSyscallArg(tc, index); 7404762Snate@binkert.org if (olddirfd != OS::TGT_AT_FDCWD) 7414762Snate@binkert.org warn("renameat: first argument not AT_FDCWD; unlikely to work"); 7423101Sstever@eecs.umich.edu 7433101Sstever@eecs.umich.edu std::string old_name; 7443101Sstever@eecs.umich.edu 7453101Sstever@eecs.umich.edu if (!tc->getMemProxy().tryReadString(old_name, 7463101Sstever@eecs.umich.edu process->getSyscallArg(tc, index))) 7473101Sstever@eecs.umich.edu return -EFAULT; 7483101Sstever@eecs.umich.edu 7493101Sstever@eecs.umich.edu int newdirfd = process->getSyscallArg(tc, index); 7503101Sstever@eecs.umich.edu if (newdirfd != OS::TGT_AT_FDCWD) 7513101Sstever@eecs.umich.edu warn("renameat: third argument not AT_FDCWD; unlikely to work"); 7523101Sstever@eecs.umich.edu 7533101Sstever@eecs.umich.edu std::string new_name; 7544762Snate@binkert.org 7554762Snate@binkert.org if (!tc->getMemProxy().tryReadString(new_name, 7564762Snate@binkert.org process->getSyscallArg(tc, index))) 7573101Sstever@eecs.umich.edu return -EFAULT; 7583101Sstever@eecs.umich.edu 7593101Sstever@eecs.umich.edu // Adjust path for current working directory 7603101Sstever@eecs.umich.edu old_name = process->fullPath(old_name); 7613101Sstever@eecs.umich.edu new_name = process->fullPath(new_name); 7623101Sstever@eecs.umich.edu 7634167Sbinkertn@umich.edu int result = rename(old_name.c_str(), new_name.c_str()); 7643101Sstever@eecs.umich.edu return (result == -1) ? -errno : result; 7653101Sstever@eecs.umich.edu} 7664762Snate@binkert.org 7673101Sstever@eecs.umich.edu/// Target sysinfo() handler. 7684167Sbinkertn@umich.edutemplate <class OS> 7694762Snate@binkert.orgSyscallReturn 7704762Snate@binkert.orgsysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 7714762Snate@binkert.org ThreadContext *tc) 7724167Sbinkertn@umich.edu{ 7733101Sstever@eecs.umich.edu 7744167Sbinkertn@umich.edu int index = 0; 7754167Sbinkertn@umich.edu TypedBufferArg<typename OS::tgt_sysinfo> 7764167Sbinkertn@umich.edu sysinfo(process->getSyscallArg(tc, index)); 7774167Sbinkertn@umich.edu 7784167Sbinkertn@umich.edu sysinfo->uptime=seconds_since_epoch; 7794167Sbinkertn@umich.edu sysinfo->totalram=process->system->memSize(); 7804167Sbinkertn@umich.edu 7814167Sbinkertn@umich.edu sysinfo.copyOut(tc->getMemProxy()); 7824167Sbinkertn@umich.edu 7834167Sbinkertn@umich.edu return 0; 7844167Sbinkertn@umich.edu} 7854167Sbinkertn@umich.edu 7863101Sstever@eecs.umich.edu/// Target chmod() handler. 7873101Sstever@eecs.umich.edutemplate <class OS> 7883101Sstever@eecs.umich.eduSyscallReturn 7893101Sstever@eecs.umich.educhmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 7903101Sstever@eecs.umich.edu ThreadContext *tc) 7913101Sstever@eecs.umich.edu{ 7923101Sstever@eecs.umich.edu std::string path; 7933101Sstever@eecs.umich.edu 7944762Snate@binkert.org int index = 0; 7954762Snate@binkert.org if (!tc->getMemProxy().tryReadString(path, 7964762Snate@binkert.org process->getSyscallArg(tc, index))) { 7974762Snate@binkert.org return -EFAULT; 7984762Snate@binkert.org } 7994762Snate@binkert.org 8004762Snate@binkert.org uint32_t mode = process->getSyscallArg(tc, index); 8013101Sstever@eecs.umich.edu mode_t hostMode = 0; 8023101Sstever@eecs.umich.edu 8034762Snate@binkert.org // XXX translate mode flags via OS::something??? 8043101Sstever@eecs.umich.edu hostMode = mode; 8054167Sbinkertn@umich.edu 8063101Sstever@eecs.umich.edu // Adjust path for current working directory 8074167Sbinkertn@umich.edu path = process->fullPath(path); 8084167Sbinkertn@umich.edu 8094167Sbinkertn@umich.edu // do the chmod 8104167Sbinkertn@umich.edu int result = chmod(path.c_str(), hostMode); 8114167Sbinkertn@umich.edu if (result < 0) 8124167Sbinkertn@umich.edu return -errno; 8134167Sbinkertn@umich.edu 8144167Sbinkertn@umich.edu return 0; 8154167Sbinkertn@umich.edu} 8164167Sbinkertn@umich.edu 8174167Sbinkertn@umich.edu 8184167Sbinkertn@umich.edu/// Target fchmod() handler. 8193101Sstever@eecs.umich.edutemplate <class OS> 8203101Sstever@eecs.umich.eduSyscallReturn 8213101Sstever@eecs.umich.edufchmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 8223101Sstever@eecs.umich.edu ThreadContext *tc) 8233101Sstever@eecs.umich.edu{ 8243101Sstever@eecs.umich.edu int index = 0; 8253101Sstever@eecs.umich.edu int tgt_fd = process->getSyscallArg(tc, index); 8263101Sstever@eecs.umich.edu uint32_t mode = process->getSyscallArg(tc, index); 8274167Sbinkertn@umich.edu 8284762Snate@binkert.org int sim_fd = process->getSimFD(tgt_fd); 8294762Snate@binkert.org if (sim_fd < 0) 8304762Snate@binkert.org return -EBADF; 8314762Snate@binkert.org 8324762Snate@binkert.org mode_t hostMode = 0; 8334762Snate@binkert.org 8344762Snate@binkert.org // XXX translate mode flags via OS::someting??? 8353101Sstever@eecs.umich.edu hostMode = mode; 8364762Snate@binkert.org 8373101Sstever@eecs.umich.edu // do the fchmod 8383101Sstever@eecs.umich.edu int result = fchmod(sim_fd, hostMode); 8393101Sstever@eecs.umich.edu if (result < 0) 8403101Sstever@eecs.umich.edu return -errno; 8413101Sstever@eecs.umich.edu 8423101Sstever@eecs.umich.edu return 0; 8433101Sstever@eecs.umich.edu} 8444762Snate@binkert.org 8453101Sstever@eecs.umich.edu/// Target mremap() handler. 8463101Sstever@eecs.umich.edutemplate <class OS> 8474167Sbinkertn@umich.eduSyscallReturn 8484167Sbinkertn@umich.edumremapFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc) 8494167Sbinkertn@umich.edu{ 8504167Sbinkertn@umich.edu int index = 0; 8514167Sbinkertn@umich.edu Addr start = process->getSyscallArg(tc, index); 8524167Sbinkertn@umich.edu uint64_t old_length = process->getSyscallArg(tc, index); 8534167Sbinkertn@umich.edu uint64_t new_length = process->getSyscallArg(tc, index); 8544167Sbinkertn@umich.edu uint64_t flags = process->getSyscallArg(tc, index); 8554167Sbinkertn@umich.edu uint64_t provided_address = 0; 8564167Sbinkertn@umich.edu bool use_provided_address = flags & OS::TGT_MREMAP_FIXED; 8574167Sbinkertn@umich.edu 8584167Sbinkertn@umich.edu if (use_provided_address) 8593101Sstever@eecs.umich.edu provided_address = process->getSyscallArg(tc, index); 8603101Sstever@eecs.umich.edu 8613101Sstever@eecs.umich.edu if ((start % TheISA::PageBytes != 0) || 8623101Sstever@eecs.umich.edu (provided_address % TheISA::PageBytes != 0)) { 8633101Sstever@eecs.umich.edu warn("mremap failing: arguments not page aligned"); 8643101Sstever@eecs.umich.edu return -EINVAL; 8653101Sstever@eecs.umich.edu } 8663101Sstever@eecs.umich.edu 8674762Snate@binkert.org new_length = roundUp(new_length, TheISA::PageBytes); 8684762Snate@binkert.org 8694762Snate@binkert.org if (new_length > old_length) { 8703101Sstever@eecs.umich.edu if ((start + old_length) == process->mmap_end && 8713101Sstever@eecs.umich.edu (!use_provided_address || provided_address == start)) { 8723101Sstever@eecs.umich.edu uint64_t diff = new_length - old_length; 8733101Sstever@eecs.umich.edu process->allocateMem(process->mmap_end, diff); 8743101Sstever@eecs.umich.edu process->mmap_end += diff; 8753101Sstever@eecs.umich.edu return start; 8764167Sbinkertn@umich.edu } else { 8774167Sbinkertn@umich.edu if (!use_provided_address && !(flags & OS::TGT_MREMAP_MAYMOVE)) { 8783101Sstever@eecs.umich.edu warn("can't remap here and MREMAP_MAYMOVE flag not set\n"); 8793101Sstever@eecs.umich.edu return -ENOMEM; 8803101Sstever@eecs.umich.edu } else { 8813101Sstever@eecs.umich.edu uint64_t new_start = use_provided_address ? 8823101Sstever@eecs.umich.edu provided_address : process->mmap_end; 8834762Snate@binkert.org process->pTable->remap(start, old_length, new_start); 8844167Sbinkertn@umich.edu warn("mremapping to new vaddr %08p-%08p, adding %d\n", 8854167Sbinkertn@umich.edu new_start, new_start + new_length, 8864167Sbinkertn@umich.edu new_length - old_length); 8874762Snate@binkert.org // add on the remaining unallocated pages 8884762Snate@binkert.org process->allocateMem(new_start + old_length, 8894762Snate@binkert.org new_length - old_length, 8904762Snate@binkert.org use_provided_address /* clobber */); 8914762Snate@binkert.org if (!use_provided_address) 8923101Sstever@eecs.umich.edu process->mmap_end += new_length; 8933101Sstever@eecs.umich.edu if (use_provided_address && 8943101Sstever@eecs.umich.edu new_start + new_length > process->mmap_end) { 8955469Snate@binkert.org // something fishy going on here, at least notify the user 8964167Sbinkertn@umich.edu // @todo: increase mmap_end? 8973102Sstever@eecs.umich.edu warn("mmap region limit exceeded with MREMAP_FIXED\n"); 8983101Sstever@eecs.umich.edu } 8993101Sstever@eecs.umich.edu warn("returning %08p as start\n", new_start); 9003101Sstever@eecs.umich.edu return new_start; 9013101Sstever@eecs.umich.edu } 9023101Sstever@eecs.umich.edu } 9034762Snate@binkert.org } else { 9044167Sbinkertn@umich.edu if (use_provided_address && provided_address != start) 9055468Snate@binkert.org process->pTable->remap(start, new_length, provided_address); 9065468Snate@binkert.org process->pTable->unmap(start + new_length, old_length - new_length); 9075468Snate@binkert.org return use_provided_address ? provided_address : start; 9084167Sbinkertn@umich.edu } 9094762Snate@binkert.org} 9104762Snate@binkert.org 9114762Snate@binkert.org/// Target stat() handler. 9124762Snate@binkert.orgtemplate <class OS> 9134762Snate@binkert.orgSyscallReturn 9143101Sstever@eecs.umich.edustatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 9153101Sstever@eecs.umich.edu ThreadContext *tc) 9163101Sstever@eecs.umich.edu{ 9173101Sstever@eecs.umich.edu std::string path; 9183101Sstever@eecs.umich.edu 9193102Sstever@eecs.umich.edu int index = 0; 9203102Sstever@eecs.umich.edu if (!tc->getMemProxy().tryReadString(path, 9213102Sstever@eecs.umich.edu process->getSyscallArg(tc, index))) { 9223102Sstever@eecs.umich.edu return -EFAULT; 9233102Sstever@eecs.umich.edu } 9243102Sstever@eecs.umich.edu Addr bufPtr = process->getSyscallArg(tc, index); 9253102Sstever@eecs.umich.edu 9263102Sstever@eecs.umich.edu // Adjust path for current working directory 9273102Sstever@eecs.umich.edu path = process->fullPath(path); 9283102Sstever@eecs.umich.edu 9293102Sstever@eecs.umich.edu struct stat hostBuf; 9303102Sstever@eecs.umich.edu int result = stat(path.c_str(), &hostBuf); 9313102Sstever@eecs.umich.edu 9323102Sstever@eecs.umich.edu if (result < 0) 9333102Sstever@eecs.umich.edu return -errno; 9343102Sstever@eecs.umich.edu 9353102Sstever@eecs.umich.edu copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 9363102Sstever@eecs.umich.edu 9373102Sstever@eecs.umich.edu return 0; 9383102Sstever@eecs.umich.edu} 9393102Sstever@eecs.umich.edu 9404762Snate@binkert.org 9413102Sstever@eecs.umich.edu/// Target stat64() handler. 9423102Sstever@eecs.umich.edutemplate <class OS> 9433102Sstever@eecs.umich.eduSyscallReturn 9444762Snate@binkert.orgstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 9454762Snate@binkert.org ThreadContext *tc) 9464762Snate@binkert.org{ 9473102Sstever@eecs.umich.edu std::string path; 9483102Sstever@eecs.umich.edu 9493102Sstever@eecs.umich.edu int index = 0; 9503102Sstever@eecs.umich.edu if (!tc->getMemProxy().tryReadString(path, 9513102Sstever@eecs.umich.edu process->getSyscallArg(tc, index))) 9523102Sstever@eecs.umich.edu return -EFAULT; 9533101Sstever@eecs.umich.edu Addr bufPtr = process->getSyscallArg(tc, index); 9543101Sstever@eecs.umich.edu 9553101Sstever@eecs.umich.edu // Adjust path for current working directory 9563101Sstever@eecs.umich.edu path = process->fullPath(path); 9573101Sstever@eecs.umich.edu 9583101Sstever@eecs.umich.edu#if NO_STAT64 9593101Sstever@eecs.umich.edu struct stat hostBuf; 9603101Sstever@eecs.umich.edu int result = stat(path.c_str(), &hostBuf); 9613101Sstever@eecs.umich.edu#else 9623101Sstever@eecs.umich.edu struct stat64 hostBuf; 9633101Sstever@eecs.umich.edu int result = stat64(path.c_str(), &hostBuf); 9643101Sstever@eecs.umich.edu#endif 9653101Sstever@eecs.umich.edu 9663101Sstever@eecs.umich.edu if (result < 0) 9673101Sstever@eecs.umich.edu return -errno; 9683101Sstever@eecs.umich.edu 9693101Sstever@eecs.umich.edu copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 9703105Sstever@eecs.umich.edu 9713105Sstever@eecs.umich.edu return 0; 9723101Sstever@eecs.umich.edu} 9733101Sstever@eecs.umich.edu 9743101Sstever@eecs.umich.edu 9753101Sstever@eecs.umich.edu/// Target fstatat64() handler. 9763105Sstever@eecs.umich.edutemplate <class OS> 9773101Sstever@eecs.umich.eduSyscallReturn 9783103Sstever@eecs.umich.edufstatat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 9793105Sstever@eecs.umich.edu ThreadContext *tc) 9803103Sstever@eecs.umich.edu{ 9813105Sstever@eecs.umich.edu int index = 0; 9823105Sstever@eecs.umich.edu int dirfd = process->getSyscallArg(tc, index); 9833105Sstever@eecs.umich.edu if (dirfd != OS::TGT_AT_FDCWD) 9843105Sstever@eecs.umich.edu warn("fstatat64: first argument not AT_FDCWD; unlikely to work"); 9853105Sstever@eecs.umich.edu 9863105Sstever@eecs.umich.edu std::string path; 9873105Sstever@eecs.umich.edu if (!tc->getMemProxy().tryReadString(path, 9883105Sstever@eecs.umich.edu process->getSyscallArg(tc, index))) 9893105Sstever@eecs.umich.edu return -EFAULT; 9903105Sstever@eecs.umich.edu Addr bufPtr = process->getSyscallArg(tc, index); 9913105Sstever@eecs.umich.edu 9923105Sstever@eecs.umich.edu // Adjust path for current working directory 9933105Sstever@eecs.umich.edu path = process->fullPath(path); 9943109Sstever@eecs.umich.edu 9953105Sstever@eecs.umich.edu#if NO_STAT64 9963105Sstever@eecs.umich.edu struct stat hostBuf; 9973105Sstever@eecs.umich.edu int result = stat(path.c_str(), &hostBuf); 9983105Sstever@eecs.umich.edu#else 9993105Sstever@eecs.umich.edu struct stat64 hostBuf; 10003105Sstever@eecs.umich.edu int result = stat64(path.c_str(), &hostBuf); 10013105Sstever@eecs.umich.edu#endif 10023105Sstever@eecs.umich.edu 10033101Sstever@eecs.umich.edu if (result < 0) 10043109Sstever@eecs.umich.edu return -errno; 10053109Sstever@eecs.umich.edu 10063109Sstever@eecs.umich.edu copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 10073109Sstever@eecs.umich.edu 10083109Sstever@eecs.umich.edu return 0; 10093109Sstever@eecs.umich.edu} 10103109Sstever@eecs.umich.edu 10113109Sstever@eecs.umich.edu 10123109Sstever@eecs.umich.edu/// Target fstat64() handler. 10133101Sstever@eecs.umich.edutemplate <class OS> 10143105Sstever@eecs.umich.eduSyscallReturn 10153105Sstever@eecs.umich.edufstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 10163105Sstever@eecs.umich.edu ThreadContext *tc) 10173101Sstever@eecs.umich.edu{ 10183105Sstever@eecs.umich.edu int index = 0; 10193105Sstever@eecs.umich.edu int tgt_fd = process->getSyscallArg(tc, index); 10203101Sstever@eecs.umich.edu Addr bufPtr = process->getSyscallArg(tc, index); 10213105Sstever@eecs.umich.edu 10223179Sstever@eecs.umich.edu int sim_fd = process->getSimFD(tgt_fd); 10233105Sstever@eecs.umich.edu if (sim_fd < 0) 10243105Sstever@eecs.umich.edu return -EBADF; 10253101Sstever@eecs.umich.edu 10263101Sstever@eecs.umich.edu#if NO_STAT64 10273105Sstever@eecs.umich.edu struct stat hostBuf; 10283105Sstever@eecs.umich.edu int result = fstat(sim_fd, &hostBuf); 10293105Sstever@eecs.umich.edu#else 10303105Sstever@eecs.umich.edu struct stat64 hostBuf; 10313105Sstever@eecs.umich.edu int result = fstat64(sim_fd, &hostBuf); 10323105Sstever@eecs.umich.edu#endif 10333105Sstever@eecs.umich.edu 10343105Sstever@eecs.umich.edu if (result < 0) 10353105Sstever@eecs.umich.edu return -errno; 10363105Sstever@eecs.umich.edu 10373105Sstever@eecs.umich.edu copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (sim_fd == 1)); 10383101Sstever@eecs.umich.edu 10393101Sstever@eecs.umich.edu return 0; 10404859Snate@binkert.org} 10414762Snate@binkert.org 10423101Sstever@eecs.umich.edu 10433101Sstever@eecs.umich.edu/// Target lstat() handler. 10443101Sstever@eecs.umich.edutemplate <class OS> 10454859Snate@binkert.orgSyscallReturn 10464859Snate@binkert.orglstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 10473101Sstever@eecs.umich.edu ThreadContext *tc) 10483101Sstever@eecs.umich.edu{ 10493101Sstever@eecs.umich.edu std::string path; 10503105Sstever@eecs.umich.edu 10513105Sstever@eecs.umich.edu int index = 0; 10523105Sstever@eecs.umich.edu if (!tc->getMemProxy().tryReadString(path, 10533105Sstever@eecs.umich.edu process->getSyscallArg(tc, index))) { 10543105Sstever@eecs.umich.edu return -EFAULT; 10553105Sstever@eecs.umich.edu } 10563105Sstever@eecs.umich.edu Addr bufPtr = process->getSyscallArg(tc, index); 10573105Sstever@eecs.umich.edu 10583105Sstever@eecs.umich.edu // Adjust path for current working directory 10593105Sstever@eecs.umich.edu path = process->fullPath(path); 10603105Sstever@eecs.umich.edu 10613105Sstever@eecs.umich.edu struct stat hostBuf; 10623105Sstever@eecs.umich.edu int result = lstat(path.c_str(), &hostBuf); 10633105Sstever@eecs.umich.edu 10643105Sstever@eecs.umich.edu if (result < 0) 10653105Sstever@eecs.umich.edu return -errno; 10663105Sstever@eecs.umich.edu 10673105Sstever@eecs.umich.edu copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 10683105Sstever@eecs.umich.edu 10693109Sstever@eecs.umich.edu return 0; 10703109Sstever@eecs.umich.edu} 10713109Sstever@eecs.umich.edu 10723105Sstever@eecs.umich.edu/// Target lstat64() handler. 10733105Sstever@eecs.umich.edutemplate <class OS> 10743105Sstever@eecs.umich.eduSyscallReturn 10753105Sstever@eecs.umich.edulstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process, 10763105Sstever@eecs.umich.edu ThreadContext *tc) 10773105Sstever@eecs.umich.edu{ 10783105Sstever@eecs.umich.edu std::string path; 10793105Sstever@eecs.umich.edu 10803105Sstever@eecs.umich.edu int index = 0; 10813105Sstever@eecs.umich.edu if (!tc->getMemProxy().tryReadString(path, 10823105Sstever@eecs.umich.edu process->getSyscallArg(tc, index))) { 10833105Sstever@eecs.umich.edu return -EFAULT; 10843105Sstever@eecs.umich.edu } 10853105Sstever@eecs.umich.edu Addr bufPtr = process->getSyscallArg(tc, index); 10863105Sstever@eecs.umich.edu 10873105Sstever@eecs.umich.edu // Adjust path for current working directory 10883105Sstever@eecs.umich.edu path = process->fullPath(path); 10893105Sstever@eecs.umich.edu 10903105Sstever@eecs.umich.edu#if NO_STAT64 10913105Sstever@eecs.umich.edu struct stat hostBuf; 10923105Sstever@eecs.umich.edu int result = lstat(path.c_str(), &hostBuf); 10933105Sstever@eecs.umich.edu#else 10943105Sstever@eecs.umich.edu struct stat64 hostBuf; 10953109Sstever@eecs.umich.edu int result = lstat64(path.c_str(), &hostBuf); 10963109Sstever@eecs.umich.edu#endif 10973109Sstever@eecs.umich.edu 10983109Sstever@eecs.umich.edu if (result < 0) 10993109Sstever@eecs.umich.edu return -errno; 11003109Sstever@eecs.umich.edu 11013109Sstever@eecs.umich.edu copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf); 11023109Sstever@eecs.umich.edu 11033109Sstever@eecs.umich.edu return 0; 11043109Sstever@eecs.umich.edu} 11053109Sstever@eecs.umich.edu 11063109Sstever@eecs.umich.edu/// Target fstat() handler. 11073109Sstever@eecs.umich.edutemplate <class OS> 11083109Sstever@eecs.umich.eduSyscallReturn 11093109Sstever@eecs.umich.edufstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 11103109Sstever@eecs.umich.edu ThreadContext *tc) 11113109Sstever@eecs.umich.edu{ 11123109Sstever@eecs.umich.edu int index = 0; 11133109Sstever@eecs.umich.edu int tgt_fd = process->getSyscallArg(tc, index); 11143105Sstever@eecs.umich.edu Addr bufPtr = process->getSyscallArg(tc, index); 11153105Sstever@eecs.umich.edu 11163105Sstever@eecs.umich.edu DPRINTF_SYSCALL(Verbose, "fstat(%d, ...)\n", tgt_fd); 11173105Sstever@eecs.umich.edu 11183105Sstever@eecs.umich.edu int sim_fd = process->getSimFD(tgt_fd); 11193105Sstever@eecs.umich.edu if (sim_fd < 0) 11203105Sstever@eecs.umich.edu return -EBADF; 11213101Sstever@eecs.umich.edu 11223101Sstever@eecs.umich.edu struct stat hostBuf; 11233101Sstever@eecs.umich.edu int result = fstat(sim_fd, &hostBuf); 11243101Sstever@eecs.umich.edu 11253105Sstever@eecs.umich.edu if (result < 0) 11263105Sstever@eecs.umich.edu return -errno; 11273105Sstever@eecs.umich.edu 11283105Sstever@eecs.umich.edu copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (sim_fd == 1)); 11293105Sstever@eecs.umich.edu 11303105Sstever@eecs.umich.edu return 0; 11313105Sstever@eecs.umich.edu} 11323105Sstever@eecs.umich.edu 11333105Sstever@eecs.umich.edu 11343105Sstever@eecs.umich.edu/// Target statfs() handler. 11353105Sstever@eecs.umich.edutemplate <class OS> 11363101Sstever@eecs.umich.eduSyscallReturn 11373101Sstever@eecs.umich.edustatfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 11383101Sstever@eecs.umich.edu ThreadContext *tc) 11393105Sstever@eecs.umich.edu{ 11403105Sstever@eecs.umich.edu std::string path; 11413101Sstever@eecs.umich.edu 11423101Sstever@eecs.umich.edu int index = 0; 11433101Sstever@eecs.umich.edu if (!tc->getMemProxy().tryReadString(path, 11443105Sstever@eecs.umich.edu process->getSyscallArg(tc, index))) { 11453105Sstever@eecs.umich.edu return -EFAULT; 11463101Sstever@eecs.umich.edu } 11473101Sstever@eecs.umich.edu Addr bufPtr = process->getSyscallArg(tc, index); 11483101Sstever@eecs.umich.edu 11493101Sstever@eecs.umich.edu // Adjust path for current working directory 11503105Sstever@eecs.umich.edu path = process->fullPath(path); 11513105Sstever@eecs.umich.edu 11523101Sstever@eecs.umich.edu struct statfs hostBuf; 11533101Sstever@eecs.umich.edu int result = statfs(path.c_str(), &hostBuf); 11543105Sstever@eecs.umich.edu 11553105Sstever@eecs.umich.edu if (result < 0) 11563105Sstever@eecs.umich.edu return -errno; 11573109Sstever@eecs.umich.edu 11583109Sstever@eecs.umich.edu OS::copyOutStatfsBuf(tc->getMemProxy(), bufPtr, &hostBuf); 11593109Sstever@eecs.umich.edu 11603109Sstever@eecs.umich.edu return 0; 11613109Sstever@eecs.umich.edu} 11623109Sstever@eecs.umich.edu 11633109Sstever@eecs.umich.edu 11643109Sstever@eecs.umich.edu/// Target fstatfs() handler. 11653105Sstever@eecs.umich.edutemplate <class OS> 11663101Sstever@eecs.umich.eduSyscallReturn 11673101Sstever@eecs.umich.edufstatfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 11683101Sstever@eecs.umich.edu ThreadContext *tc) 11693101Sstever@eecs.umich.edu{ 11703101Sstever@eecs.umich.edu int index = 0; 11713101Sstever@eecs.umich.edu int tgt_fd = process->getSyscallArg(tc, index); 11723101Sstever@eecs.umich.edu Addr bufPtr = process->getSyscallArg(tc, index); 11734167Sbinkertn@umich.edu 11743101Sstever@eecs.umich.edu int sim_fd = process->getSimFD(tgt_fd); 11753101Sstever@eecs.umich.edu if (sim_fd < 0) 11763101Sstever@eecs.umich.edu return -EBADF; 11773885Sbinkertn@umich.edu 11783102Sstever@eecs.umich.edu struct statfs hostBuf; 11793101Sstever@eecs.umich.edu int result = fstatfs(sim_fd, &hostBuf); 1180 1181 if (result < 0) 1182 return -errno; 1183 1184 OS::copyOutStatfsBuf(tc->getMemProxy(), bufPtr, &hostBuf); 1185 1186 return 0; 1187} 1188 1189 1190/// Target writev() handler. 1191template <class OS> 1192SyscallReturn 1193writevFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1194 ThreadContext *tc) 1195{ 1196 int index = 0; 1197 int tgt_fd = process->getSyscallArg(tc, index); 1198 1199 int sim_fd = process->getSimFD(tgt_fd); 1200 if (sim_fd < 0) 1201 return -EBADF; 1202 1203 SETranslatingPortProxy &p = tc->getMemProxy(); 1204 uint64_t tiov_base = process->getSyscallArg(tc, index); 1205 size_t count = process->getSyscallArg(tc, index); 1206 struct iovec hiov[count]; 1207 for (size_t i = 0; i < count; ++i) { 1208 typename OS::tgt_iovec tiov; 1209 1210 p.readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec), 1211 (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec)); 1212 hiov[i].iov_len = TheISA::gtoh(tiov.iov_len); 1213 hiov[i].iov_base = new char [hiov[i].iov_len]; 1214 p.readBlob(TheISA::gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base, 1215 hiov[i].iov_len); 1216 } 1217 1218 int result = writev(sim_fd, hiov, count); 1219 1220 for (size_t i = 0; i < count; ++i) 1221 delete [] (char *)hiov[i].iov_base; 1222 1223 if (result < 0) 1224 return -errno; 1225 1226 return result; 1227} 1228 1229/// Real mmap handler. 1230template <class OS> 1231SyscallReturn 1232mmapImpl(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc, 1233 bool is_mmap2) 1234{ 1235 int index = 0; 1236 Addr start = p->getSyscallArg(tc, index); 1237 uint64_t length = p->getSyscallArg(tc, index); 1238 int prot = p->getSyscallArg(tc, index); 1239 int tgt_flags = p->getSyscallArg(tc, index); 1240 int tgt_fd = p->getSyscallArg(tc, index); 1241 int offset = p->getSyscallArg(tc, index); 1242 1243 if (is_mmap2) 1244 offset *= TheISA::PageBytes; 1245 1246 if (start & (TheISA::PageBytes - 1) || 1247 offset & (TheISA::PageBytes - 1) || 1248 (tgt_flags & OS::TGT_MAP_PRIVATE && 1249 tgt_flags & OS::TGT_MAP_SHARED) || 1250 (!(tgt_flags & OS::TGT_MAP_PRIVATE) && 1251 !(tgt_flags & OS::TGT_MAP_SHARED)) || 1252 !length) { 1253 return -EINVAL; 1254 } 1255 1256 if ((prot & PROT_WRITE) && (tgt_flags & OS::TGT_MAP_SHARED)) { 1257 // With shared mmaps, there are two cases to consider: 1258 // 1) anonymous: writes should modify the mapping and this should be 1259 // visible to observers who share the mapping. Currently, it's 1260 // difficult to update the shared mapping because there's no 1261 // structure which maintains information about the which virtual 1262 // memory areas are shared. If that structure existed, it would be 1263 // possible to make the translations point to the same frames. 1264 // 2) file-backed: writes should modify the mapping and the file 1265 // which is backed by the mapping. The shared mapping problem is the 1266 // same as what was mentioned about the anonymous mappings. For 1267 // file-backed mappings, the writes to the file are difficult 1268 // because it requires syncing what the mapping holds with the file 1269 // that resides on the host system. So, any write on a real system 1270 // would cause the change to be propagated to the file mapping at 1271 // some point in the future (the inode is tracked along with the 1272 // mapping). This isn't guaranteed to always happen, but it usually 1273 // works well enough. The guarantee is provided by the msync system 1274 // call. We could force the change through with shared mappings with 1275 // a call to msync, but that again would require more information 1276 // than we currently maintain. 1277 warn("mmap: writing to shared mmap region is currently " 1278 "unsupported. The write succeeds on the target, but it " 1279 "will not be propagated to the host or shared mappings"); 1280 } 1281 1282 length = roundUp(length, TheISA::PageBytes); 1283 1284 int sim_fd = -1; 1285 uint8_t *pmap = nullptr; 1286 if (!(tgt_flags & OS::TGT_MAP_ANONYMOUS)) { 1287 sim_fd = p->getSimFD(tgt_fd); 1288 if (sim_fd < 0) 1289 return -EBADF; 1290 1291 pmap = (decltype(pmap))mmap(NULL, length, PROT_READ, MAP_PRIVATE, 1292 sim_fd, offset); 1293 1294 if (pmap == (decltype(pmap))-1) { 1295 warn("mmap: failed to map file into host address space"); 1296 return -errno; 1297 } 1298 } 1299 1300 // Extend global mmap region if necessary. Note that we ignore the 1301 // start address unless MAP_FIXED is specified. 1302 if (!(tgt_flags & OS::TGT_MAP_FIXED)) { 1303 start = p->mmapGrowsDown() ? p->mmap_end - length : p->mmap_end; 1304 p->mmap_end = p->mmapGrowsDown() ? start : p->mmap_end + length; 1305 } 1306 1307 DPRINTF_SYSCALL(Verbose, " mmap range is 0x%x - 0x%x\n", 1308 start, start + length - 1); 1309 1310 // We only allow mappings to overwrite existing mappings if 1311 // TGT_MAP_FIXED is set. Otherwise it shouldn't be a problem 1312 // because we ignore the start hint if TGT_MAP_FIXED is not set. 1313 int clobber = tgt_flags & OS::TGT_MAP_FIXED; 1314 if (clobber) { 1315 for (auto tc : p->system->threadContexts) { 1316 // If we might be overwriting old mappings, we need to 1317 // invalidate potentially stale mappings out of the TLBs. 1318 tc->getDTBPtr()->flushAll(); 1319 tc->getITBPtr()->flushAll(); 1320 } 1321 } 1322 1323 // Allocate physical memory and map it in. If the page table is already 1324 // mapped and clobber is not set, the simulator will issue throw a 1325 // fatal and bail out of the simulation. 1326 p->allocateMem(start, length, clobber); 1327 1328 // Transfer content into target address space. 1329 SETranslatingPortProxy &tp = tc->getMemProxy(); 1330 if (tgt_flags & OS::TGT_MAP_ANONYMOUS) { 1331 // In general, we should zero the mapped area for anonymous mappings, 1332 // with something like: 1333 // tp.memsetBlob(start, 0, length); 1334 // However, given that we don't support sparse mappings, and 1335 // some applications can map a couple of gigabytes of space 1336 // (intending sparse usage), that can get painfully expensive. 1337 // Fortunately, since we don't properly implement munmap either, 1338 // there's no danger of remapping used memory, so for now all 1339 // newly mapped memory should already be zeroed so we can skip it. 1340 } else { 1341 // It is possible to mmap an area larger than a file, however 1342 // accessing unmapped portions the system triggers a "Bus error" 1343 // on the host. We must know when to stop copying the file from 1344 // the host into the target address space. 1345 struct stat file_stat; 1346 if (fstat(sim_fd, &file_stat) > 0) 1347 fatal("mmap: cannot stat file"); 1348 1349 // Copy the portion of the file that is resident. This requires 1350 // checking both the mmap size and the filesize that we are 1351 // trying to mmap into this space; the mmap size also depends 1352 // on the specified offset into the file. 1353 uint64_t size = std::min((uint64_t)file_stat.st_size - offset, 1354 length); 1355 tp.writeBlob(start, pmap, size); 1356 1357 // Cleanup the mmap region before exiting this function. 1358 munmap(pmap, length); 1359 1360 // Maintain the symbol table for dynamic executables. 1361 // The loader will call mmap to map the images into its address 1362 // space and we intercept that here. We can verify that we are 1363 // executing inside the loader by checking the program counter value. 1364 // XXX: with multiprogrammed workloads or multi-node configurations, 1365 // this will not work since there is a single global symbol table. 1366 ObjectFile *interpreter = p->getInterpreter(); 1367 if (interpreter) { 1368 Addr text_start = interpreter->textBase(); 1369 Addr text_end = text_start + interpreter->textSize(); 1370 1371 Addr pc = tc->pcState().pc(); 1372 1373 if (pc >= text_start && pc < text_end) { 1374 FDEntry *fde = p->getFDEntry(tgt_fd); 1375 1376 ObjectFile *lib = createObjectFile(fde->filename); 1377 1378 if (lib) { 1379 lib->loadAllSymbols(debugSymbolTable, 1380 lib->textBase(), start); 1381 } 1382 } 1383 } 1384 1385 // Note that we do not zero out the remainder of the mapping. This 1386 // is done by a real system, but it probably will not affect 1387 // execution (hopefully). 1388 } 1389 1390 return start; 1391} 1392 1393template <class OS> 1394SyscallReturn 1395pwrite64Func(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 1396{ 1397 int index = 0; 1398 int tgt_fd = p->getSyscallArg(tc, index); 1399 Addr bufPtr = p->getSyscallArg(tc, index); 1400 int nbytes = p->getSyscallArg(tc, index); 1401 int offset = p->getSyscallArg(tc, index); 1402 1403 int sim_fd = p->getSimFD(tgt_fd); 1404 if (sim_fd < 0) 1405 return -EBADF; 1406 1407 BufferArg bufArg(bufPtr, nbytes); 1408 bufArg.copyIn(tc->getMemProxy()); 1409 1410 int bytes_written = pwrite(sim_fd, bufArg.bufferPtr(), nbytes, offset); 1411 1412 return (bytes_written == -1) ? -errno : bytes_written; 1413} 1414 1415/// Target mmap() handler. 1416template <class OS> 1417SyscallReturn 1418mmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 1419{ 1420 return mmapImpl<OS>(desc, num, p, tc, false); 1421} 1422 1423/// Target mmap2() handler. 1424template <class OS> 1425SyscallReturn 1426mmap2Func(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 1427{ 1428 return mmapImpl<OS>(desc, num, p, tc, true); 1429} 1430 1431/// Target getrlimit() handler. 1432template <class OS> 1433SyscallReturn 1434getrlimitFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1435 ThreadContext *tc) 1436{ 1437 int index = 0; 1438 unsigned resource = process->getSyscallArg(tc, index); 1439 TypedBufferArg<typename OS::rlimit> rlp(process->getSyscallArg(tc, index)); 1440 1441 switch (resource) { 1442 case OS::TGT_RLIMIT_STACK: 1443 // max stack size in bytes: make up a number (8MB for now) 1444 rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024; 1445 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1446 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1447 break; 1448 1449 case OS::TGT_RLIMIT_DATA: 1450 // max data segment size in bytes: make up a number 1451 rlp->rlim_cur = rlp->rlim_max = 256 * 1024 * 1024; 1452 rlp->rlim_cur = TheISA::htog(rlp->rlim_cur); 1453 rlp->rlim_max = TheISA::htog(rlp->rlim_max); 1454 break; 1455 1456 default: 1457 warn("getrlimit: unimplemented resource %d", resource); 1458 return -EINVAL; 1459 break; 1460 } 1461 1462 rlp.copyOut(tc->getMemProxy()); 1463 return 0; 1464} 1465 1466/// Target clock_gettime() function. 1467template <class OS> 1468SyscallReturn 1469clock_gettimeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 1470{ 1471 int index = 1; 1472 //int clk_id = p->getSyscallArg(tc, index); 1473 TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index)); 1474 1475 getElapsedTimeNano(tp->tv_sec, tp->tv_nsec); 1476 tp->tv_sec += seconds_since_epoch; 1477 tp->tv_sec = TheISA::htog(tp->tv_sec); 1478 tp->tv_nsec = TheISA::htog(tp->tv_nsec); 1479 1480 tp.copyOut(tc->getMemProxy()); 1481 1482 return 0; 1483} 1484 1485/// Target clock_getres() function. 1486template <class OS> 1487SyscallReturn 1488clock_getresFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 1489{ 1490 int index = 1; 1491 TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index)); 1492 1493 // Set resolution at ns, which is what clock_gettime() returns 1494 tp->tv_sec = 0; 1495 tp->tv_nsec = 1; 1496 1497 tp.copyOut(tc->getMemProxy()); 1498 1499 return 0; 1500} 1501 1502/// Target gettimeofday() handler. 1503template <class OS> 1504SyscallReturn 1505gettimeofdayFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1506 ThreadContext *tc) 1507{ 1508 int index = 0; 1509 TypedBufferArg<typename OS::timeval> tp(process->getSyscallArg(tc, index)); 1510 1511 getElapsedTimeMicro(tp->tv_sec, tp->tv_usec); 1512 tp->tv_sec += seconds_since_epoch; 1513 tp->tv_sec = TheISA::htog(tp->tv_sec); 1514 tp->tv_usec = TheISA::htog(tp->tv_usec); 1515 1516 tp.copyOut(tc->getMemProxy()); 1517 1518 return 0; 1519} 1520 1521 1522/// Target utimes() handler. 1523template <class OS> 1524SyscallReturn 1525utimesFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1526 ThreadContext *tc) 1527{ 1528 std::string path; 1529 1530 int index = 0; 1531 if (!tc->getMemProxy().tryReadString(path, 1532 process->getSyscallArg(tc, index))) { 1533 return -EFAULT; 1534 } 1535 1536 TypedBufferArg<typename OS::timeval [2]> 1537 tp(process->getSyscallArg(tc, index)); 1538 tp.copyIn(tc->getMemProxy()); 1539 1540 struct timeval hostTimeval[2]; 1541 for (int i = 0; i < 2; ++i) 1542 { 1543 hostTimeval[i].tv_sec = TheISA::gtoh((*tp)[i].tv_sec); 1544 hostTimeval[i].tv_usec = TheISA::gtoh((*tp)[i].tv_usec); 1545 } 1546 1547 // Adjust path for current working directory 1548 path = process->fullPath(path); 1549 1550 int result = utimes(path.c_str(), hostTimeval); 1551 1552 if (result < 0) 1553 return -errno; 1554 1555 return 0; 1556} 1557/// Target getrusage() function. 1558template <class OS> 1559SyscallReturn 1560getrusageFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1561 ThreadContext *tc) 1562{ 1563 int index = 0; 1564 int who = process->getSyscallArg(tc, index); // THREAD, SELF, or CHILDREN 1565 TypedBufferArg<typename OS::rusage> rup(process->getSyscallArg(tc, index)); 1566 1567 rup->ru_utime.tv_sec = 0; 1568 rup->ru_utime.tv_usec = 0; 1569 rup->ru_stime.tv_sec = 0; 1570 rup->ru_stime.tv_usec = 0; 1571 rup->ru_maxrss = 0; 1572 rup->ru_ixrss = 0; 1573 rup->ru_idrss = 0; 1574 rup->ru_isrss = 0; 1575 rup->ru_minflt = 0; 1576 rup->ru_majflt = 0; 1577 rup->ru_nswap = 0; 1578 rup->ru_inblock = 0; 1579 rup->ru_oublock = 0; 1580 rup->ru_msgsnd = 0; 1581 rup->ru_msgrcv = 0; 1582 rup->ru_nsignals = 0; 1583 rup->ru_nvcsw = 0; 1584 rup->ru_nivcsw = 0; 1585 1586 switch (who) { 1587 case OS::TGT_RUSAGE_SELF: 1588 getElapsedTimeMicro(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec); 1589 rup->ru_utime.tv_sec = TheISA::htog(rup->ru_utime.tv_sec); 1590 rup->ru_utime.tv_usec = TheISA::htog(rup->ru_utime.tv_usec); 1591 break; 1592 1593 case OS::TGT_RUSAGE_CHILDREN: 1594 // do nothing. We have no child processes, so they take no time. 1595 break; 1596 1597 default: 1598 // don't really handle THREAD or CHILDREN, but just warn and 1599 // plow ahead 1600 warn("getrusage() only supports RUSAGE_SELF. Parameter %d ignored.", 1601 who); 1602 } 1603 1604 rup.copyOut(tc->getMemProxy()); 1605 1606 return 0; 1607} 1608 1609/// Target times() function. 1610template <class OS> 1611SyscallReturn 1612timesFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1613 ThreadContext *tc) 1614{ 1615 int index = 0; 1616 TypedBufferArg<typename OS::tms> bufp(process->getSyscallArg(tc, index)); 1617 1618 // Fill in the time structure (in clocks) 1619 int64_t clocks = curTick() * OS::M5_SC_CLK_TCK / SimClock::Int::s; 1620 bufp->tms_utime = clocks; 1621 bufp->tms_stime = 0; 1622 bufp->tms_cutime = 0; 1623 bufp->tms_cstime = 0; 1624 1625 // Convert to host endianness 1626 bufp->tms_utime = TheISA::htog(bufp->tms_utime); 1627 1628 // Write back 1629 bufp.copyOut(tc->getMemProxy()); 1630 1631 // Return clock ticks since system boot 1632 return clocks; 1633} 1634 1635/// Target time() function. 1636template <class OS> 1637SyscallReturn 1638timeFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1639 ThreadContext *tc) 1640{ 1641 typename OS::time_t sec, usec; 1642 getElapsedTimeMicro(sec, usec); 1643 sec += seconds_since_epoch; 1644 1645 int index = 0; 1646 Addr taddr = (Addr)process->getSyscallArg(tc, index); 1647 if (taddr != 0) { 1648 typename OS::time_t t = sec; 1649 t = TheISA::htog(t); 1650 SETranslatingPortProxy &p = tc->getMemProxy(); 1651 p.writeBlob(taddr, (uint8_t*)&t, (int)sizeof(typename OS::time_t)); 1652 } 1653 return sec; 1654} 1655 1656 1657#endif // __SIM_SYSCALL_EMUL_HH__ 1658