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