syscall_emul.hh revision 11383
19651SAndreas.Sandberg@ARM.com/*
29651SAndreas.Sandberg@ARM.com * Copyright (c) 2012-2013, 2015 ARM Limited
39651SAndreas.Sandberg@ARM.com * Copyright (c) 2015 Advanced Micro Devices, Inc.
49651SAndreas.Sandberg@ARM.com * All rights reserved
59651SAndreas.Sandberg@ARM.com *
69651SAndreas.Sandberg@ARM.com * The license below extends only to copyright in the software and shall
79651SAndreas.Sandberg@ARM.com * not be construed as granting a license to any other intellectual
89651SAndreas.Sandberg@ARM.com * property including but not limited to intellectual property relating
99651SAndreas.Sandberg@ARM.com * to a hardware implementation of the functionality of the software
109651SAndreas.Sandberg@ARM.com * licensed hereunder.  You may use the software subject to the license
119651SAndreas.Sandberg@ARM.com * terms below provided that you ensure that this notice is replicated
129651SAndreas.Sandberg@ARM.com * unmodified and in its entirety in all distributions of the software,
139651SAndreas.Sandberg@ARM.com * modified or unmodified, in source code or in binary form.
149651SAndreas.Sandberg@ARM.com *
159651SAndreas.Sandberg@ARM.com * Copyright (c) 2003-2005 The Regents of The University of Michigan
169651SAndreas.Sandberg@ARM.com * All rights reserved.
179651SAndreas.Sandberg@ARM.com *
189651SAndreas.Sandberg@ARM.com * Redistribution and use in source and binary forms, with or without
199651SAndreas.Sandberg@ARM.com * modification, are permitted provided that the following conditions are
209651SAndreas.Sandberg@ARM.com * met: redistributions of source code must retain the above copyright
219651SAndreas.Sandberg@ARM.com * notice, this list of conditions and the following disclaimer;
229651SAndreas.Sandberg@ARM.com * redistributions in binary form must reproduce the above copyright
239651SAndreas.Sandberg@ARM.com * notice, this list of conditions and the following disclaimer in the
249651SAndreas.Sandberg@ARM.com * documentation and/or other materials provided with the distribution;
259651SAndreas.Sandberg@ARM.com * neither the name of the copyright holders nor the names of its
269651SAndreas.Sandberg@ARM.com * contributors may be used to endorse or promote products derived from
279651SAndreas.Sandberg@ARM.com * this software without specific prior written permission.
289651SAndreas.Sandberg@ARM.com *
299651SAndreas.Sandberg@ARM.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
309651SAndreas.Sandberg@ARM.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
319651SAndreas.Sandberg@ARM.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
329651SAndreas.Sandberg@ARM.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
339651SAndreas.Sandberg@ARM.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
349651SAndreas.Sandberg@ARM.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
359651SAndreas.Sandberg@ARM.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
369651SAndreas.Sandberg@ARM.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
379651SAndreas.Sandberg@ARM.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
389651SAndreas.Sandberg@ARM.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
399651SAndreas.Sandberg@ARM.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
409651SAndreas.Sandberg@ARM.com *
419651SAndreas.Sandberg@ARM.com * Authors: Steve Reinhardt
429651SAndreas.Sandberg@ARM.com *          Kevin Lim
439651SAndreas.Sandberg@ARM.com */
449651SAndreas.Sandberg@ARM.com
459651SAndreas.Sandberg@ARM.com#ifndef __SIM_SYSCALL_EMUL_HH__
469651SAndreas.Sandberg@ARM.com#define __SIM_SYSCALL_EMUL_HH__
479651SAndreas.Sandberg@ARM.com
489651SAndreas.Sandberg@ARM.com#define NO_STAT64 (defined(__APPLE__) || defined(__OpenBSD__) || \
499760Sandreas@sandberg.pp.se  defined(__FreeBSD__) || defined(__CYGWIN__) || \
509651SAndreas.Sandberg@ARM.com  defined(__NetBSD__))
519651SAndreas.Sandberg@ARM.com
529683Sandreas@sandberg.pp.se///
539753Sandreas@sandberg.pp.se/// @file syscall_emul.hh
549651SAndreas.Sandberg@ARM.com///
559651SAndreas.Sandberg@ARM.com/// This file defines objects used to emulate syscalls from the target
569651SAndreas.Sandberg@ARM.com/// application on the host machine.
579651SAndreas.Sandberg@ARM.com
589651SAndreas.Sandberg@ARM.com#ifdef __CYGWIN32__
599651SAndreas.Sandberg@ARM.com#include <sys/fcntl.h>  // for O_BINARY
609651SAndreas.Sandberg@ARM.com#endif
619753Sandreas@sandberg.pp.se#include <sys/mman.h>
629753Sandreas@sandberg.pp.se#include <sys/stat.h>
639651SAndreas.Sandberg@ARM.com#include <sys/time.h>
649651SAndreas.Sandberg@ARM.com#include <sys/uio.h>
659651SAndreas.Sandberg@ARM.com#include <fcntl.h>
669651SAndreas.Sandberg@ARM.com
679651SAndreas.Sandberg@ARM.com#include <cerrno>
689651SAndreas.Sandberg@ARM.com#include <string>
699651SAndreas.Sandberg@ARM.com
709651SAndreas.Sandberg@ARM.com#include "base/chunk_generator.hh"
719651SAndreas.Sandberg@ARM.com#include "base/intmath.hh"      // for RoundUp
729651SAndreas.Sandberg@ARM.com#include "base/misc.hh"
739651SAndreas.Sandberg@ARM.com#include "base/trace.hh"
749651SAndreas.Sandberg@ARM.com#include "base/types.hh"
759651SAndreas.Sandberg@ARM.com#include "config/the_isa.hh"
769651SAndreas.Sandberg@ARM.com#include "cpu/base.hh"
779651SAndreas.Sandberg@ARM.com#include "cpu/thread_context.hh"
789651SAndreas.Sandberg@ARM.com#include "debug/SyscallBase.hh"
799651SAndreas.Sandberg@ARM.com#include "debug/SyscallVerbose.hh"
809652SAndreas.Sandberg@ARM.com#include "mem/page_table.hh"
819652SAndreas.Sandberg@ARM.com#include "sim/byteswap.hh"
829651SAndreas.Sandberg@ARM.com#include "sim/emul_driver.hh"
839651SAndreas.Sandberg@ARM.com#include "sim/process.hh"
849651SAndreas.Sandberg@ARM.com#include "sim/syscall_emul_buf.hh"
859651SAndreas.Sandberg@ARM.com#include "sim/syscallreturn.hh"
869655SAndreas.Sandberg@ARM.com#include "sim/system.hh"
879754Sandreas@sandberg.pp.se
889752Sandreas@sandberg.pp.se// This wrapper macro helps out with readability a bit. FLAGEXT specifies
899753Sandreas@sandberg.pp.se// the verbosity and FMT is the message to be appended to the syscall
909752Sandreas@sandberg.pp.se// header information. The syscall header information contains the cpuid
919651SAndreas.Sandberg@ARM.com// and thread id.
929651SAndreas.Sandberg@ARM.com#define DPRINTF_SYSCALL(FLAGEXT, FMT, ...)                                  \
939651SAndreas.Sandberg@ARM.com    DPRINTFS(Syscall##FLAGEXT, tc->getCpuPtr(), "T%d : syscall " FMT,       \
949651SAndreas.Sandberg@ARM.com             tc->threadId(), __VA_ARGS__)
959651SAndreas.Sandberg@ARM.com
969651SAndreas.Sandberg@ARM.com///
979651SAndreas.Sandberg@ARM.com/// System call descriptor.
989651SAndreas.Sandberg@ARM.com///
999651SAndreas.Sandberg@ARM.comclass SyscallDesc {
1009651SAndreas.Sandberg@ARM.com
1019651SAndreas.Sandberg@ARM.com  public:
1029651SAndreas.Sandberg@ARM.com
1039651SAndreas.Sandberg@ARM.com    /// Typedef for target syscall handler functions.
1049655SAndreas.Sandberg@ARM.com    typedef SyscallReturn (*FuncPtr)(SyscallDesc *, int num,
1059655SAndreas.Sandberg@ARM.com                           LiveProcess *, ThreadContext *);
1069655SAndreas.Sandberg@ARM.com
1079655SAndreas.Sandberg@ARM.com    const char *name;   //!< Syscall name (e.g., "open").
1089754Sandreas@sandberg.pp.se    FuncPtr funcPtr;    //!< Pointer to emulation function.
1099655SAndreas.Sandberg@ARM.com    int flags;          //!< Flags (see Flags enum).
1109655SAndreas.Sandberg@ARM.com    bool warned;        //!< Have we warned about unimplemented syscall?
1119655SAndreas.Sandberg@ARM.com
1129754Sandreas@sandberg.pp.se    /// Flag values for controlling syscall behavior.
1139651SAndreas.Sandberg@ARM.com    enum Flags {
1149651SAndreas.Sandberg@ARM.com        /// Don't set return regs according to funcPtr return value.
1159651SAndreas.Sandberg@ARM.com        /// Used for syscalls with non-standard return conventions
1169651SAndreas.Sandberg@ARM.com        /// that explicitly set the ThreadContext regs (e.g.,
1179651SAndreas.Sandberg@ARM.com        /// sigreturn).
1189651SAndreas.Sandberg@ARM.com        SuppressReturnValue = 1,
1199651SAndreas.Sandberg@ARM.com        WarnOnce = 2
1209651SAndreas.Sandberg@ARM.com    };
1219651SAndreas.Sandberg@ARM.com
1229651SAndreas.Sandberg@ARM.com    /// Constructor.
1239651SAndreas.Sandberg@ARM.com    SyscallDesc(const char *_name, FuncPtr _funcPtr, int _flags = 0)
1249651SAndreas.Sandberg@ARM.com        : name(_name), funcPtr(_funcPtr), flags(_flags), warned(false)
1259651SAndreas.Sandberg@ARM.com    {
1269651SAndreas.Sandberg@ARM.com    }
1279651SAndreas.Sandberg@ARM.com
1289651SAndreas.Sandberg@ARM.com    /// Emulate the syscall.  Public interface for calling through funcPtr.
1299651SAndreas.Sandberg@ARM.com    void doSyscall(int callnum, LiveProcess *proc, ThreadContext *tc);
1309651SAndreas.Sandberg@ARM.com
1319651SAndreas.Sandberg@ARM.com    /// Is the WarnOnce flag set?
1329651SAndreas.Sandberg@ARM.com    bool warnOnce() const {  return (flags & WarnOnce); }
1339651SAndreas.Sandberg@ARM.com};
1349651SAndreas.Sandberg@ARM.com
1359651SAndreas.Sandberg@ARM.com
1369651SAndreas.Sandberg@ARM.com//////////////////////////////////////////////////////////////////////
1379651SAndreas.Sandberg@ARM.com//
1389651SAndreas.Sandberg@ARM.com// The following emulation functions are generic enough that they
1399651SAndreas.Sandberg@ARM.com// don't need to be recompiled for different emulated OS's.  They are
1409651SAndreas.Sandberg@ARM.com// defined in sim/syscall_emul.cc.
1419651SAndreas.Sandberg@ARM.com//
1429690Sandreas@sandberg.pp.se//////////////////////////////////////////////////////////////////////
1439690Sandreas@sandberg.pp.se
1449690Sandreas@sandberg.pp.se
1459651SAndreas.Sandberg@ARM.com/// Handler for unimplemented syscalls that we haven't thought about.
1469651SAndreas.Sandberg@ARM.comSyscallReturn unimplementedFunc(SyscallDesc *desc, int num,
1479651SAndreas.Sandberg@ARM.com                                LiveProcess *p, ThreadContext *tc);
1489651SAndreas.Sandberg@ARM.com
1499651SAndreas.Sandberg@ARM.com/// Handler for unimplemented syscalls that we never intend to
1509651SAndreas.Sandberg@ARM.com/// implement (signal handling, etc.) and should not affect the correct
1519651SAndreas.Sandberg@ARM.com/// behavior of the program.  Print a warning only if the appropriate
1529651SAndreas.Sandberg@ARM.com/// trace flag is enabled.  Return success to the target program.
1539651SAndreas.Sandberg@ARM.comSyscallReturn ignoreFunc(SyscallDesc *desc, int num,
1549651SAndreas.Sandberg@ARM.com                         LiveProcess *p, ThreadContext *tc);
1559651SAndreas.Sandberg@ARM.com
1569651SAndreas.Sandberg@ARM.com/// Target exit() handler: terminate current context.
1579651SAndreas.Sandberg@ARM.comSyscallReturn exitFunc(SyscallDesc *desc, int num,
1589651SAndreas.Sandberg@ARM.com                       LiveProcess *p, ThreadContext *tc);
1599753Sandreas@sandberg.pp.se
1609753Sandreas@sandberg.pp.se/// Target exit_group() handler: terminate simulation. (exit all threads)
1619753Sandreas@sandberg.pp.seSyscallReturn exitGroupFunc(SyscallDesc *desc, int num,
1629753Sandreas@sandberg.pp.se                       LiveProcess *p, ThreadContext *tc);
1639651SAndreas.Sandberg@ARM.com
1649651SAndreas.Sandberg@ARM.com/// Target getpagesize() handler.
1659651SAndreas.Sandberg@ARM.comSyscallReturn getpagesizeFunc(SyscallDesc *desc, int num,
1669651SAndreas.Sandberg@ARM.com                              LiveProcess *p, ThreadContext *tc);
1679651SAndreas.Sandberg@ARM.com
1689651SAndreas.Sandberg@ARM.com/// Target brk() handler: set brk address.
1699651SAndreas.Sandberg@ARM.comSyscallReturn brkFunc(SyscallDesc *desc, int num,
1709651SAndreas.Sandberg@ARM.com                      LiveProcess *p, ThreadContext *tc);
1719651SAndreas.Sandberg@ARM.com
1729651SAndreas.Sandberg@ARM.com/// Target close() handler.
1739651SAndreas.Sandberg@ARM.comSyscallReturn closeFunc(SyscallDesc *desc, int num,
1749651SAndreas.Sandberg@ARM.com                        LiveProcess *p, ThreadContext *tc);
1759690Sandreas@sandberg.pp.se
1769690Sandreas@sandberg.pp.se/// Target read() handler.
1779690Sandreas@sandberg.pp.seSyscallReturn readFunc(SyscallDesc *desc, int num,
1789651SAndreas.Sandberg@ARM.com                       LiveProcess *p, ThreadContext *tc);
1799651SAndreas.Sandberg@ARM.com
1809651SAndreas.Sandberg@ARM.com/// Target write() handler.
1819651SAndreas.Sandberg@ARM.comSyscallReturn writeFunc(SyscallDesc *desc, int num,
1829651SAndreas.Sandberg@ARM.com                        LiveProcess *p, ThreadContext *tc);
1839651SAndreas.Sandberg@ARM.com
1849732Sandreas@sandberg.pp.se/// Target lseek() handler.
1859732Sandreas@sandberg.pp.seSyscallReturn lseekFunc(SyscallDesc *desc, int num,
1869651SAndreas.Sandberg@ARM.com                        LiveProcess *p, ThreadContext *tc);
1879651SAndreas.Sandberg@ARM.com
1889651SAndreas.Sandberg@ARM.com/// Target _llseek() handler.
1899651SAndreas.Sandberg@ARM.comSyscallReturn _llseekFunc(SyscallDesc *desc, int num,
1909651SAndreas.Sandberg@ARM.com                        LiveProcess *p, ThreadContext *tc);
1919651SAndreas.Sandberg@ARM.com
1929651SAndreas.Sandberg@ARM.com/// Target munmap() handler.
1939651SAndreas.Sandberg@ARM.comSyscallReturn munmapFunc(SyscallDesc *desc, int num,
1949651SAndreas.Sandberg@ARM.com                         LiveProcess *p, ThreadContext *tc);
1959684Sandreas@sandberg.pp.se
1969684Sandreas@sandberg.pp.se/// Target gethostname() handler.
1979684Sandreas@sandberg.pp.seSyscallReturn gethostnameFunc(SyscallDesc *desc, int num,
1989684Sandreas@sandberg.pp.se                              LiveProcess *p, ThreadContext *tc);
1999684Sandreas@sandberg.pp.se
2009651SAndreas.Sandberg@ARM.com/// Target getcwd() handler.
2019651SAndreas.Sandberg@ARM.comSyscallReturn getcwdFunc(SyscallDesc *desc, int num,
2029651SAndreas.Sandberg@ARM.com                         LiveProcess *p, ThreadContext *tc);
2039651SAndreas.Sandberg@ARM.com
2049651SAndreas.Sandberg@ARM.com/// Target readlink() handler.
2059755Sandreas@sandberg.pp.seSyscallReturn readlinkFunc(SyscallDesc *desc, int num,
2069755Sandreas@sandberg.pp.se                           LiveProcess *p, ThreadContext *tc,
2079755Sandreas@sandberg.pp.se                           int index = 0);
2089755Sandreas@sandberg.pp.seSyscallReturn readlinkFunc(SyscallDesc *desc, int num,
2099755Sandreas@sandberg.pp.se                           LiveProcess *p, ThreadContext *tc);
2109755Sandreas@sandberg.pp.se
2119755Sandreas@sandberg.pp.se/// Target unlink() handler.
2129755Sandreas@sandberg.pp.seSyscallReturn unlinkHelper(SyscallDesc *desc, int num,
2139755Sandreas@sandberg.pp.se                           LiveProcess *p, ThreadContext *tc,
2149755Sandreas@sandberg.pp.se                           int index);
2159651SAndreas.Sandberg@ARM.comSyscallReturn unlinkFunc(SyscallDesc *desc, int num,
2169651SAndreas.Sandberg@ARM.com                         LiveProcess *p, ThreadContext *tc);
2179651SAndreas.Sandberg@ARM.com
2189651SAndreas.Sandberg@ARM.com/// Target mkdir() handler.
2199651SAndreas.Sandberg@ARM.comSyscallReturn mkdirFunc(SyscallDesc *desc, int num,
2209651SAndreas.Sandberg@ARM.com                        LiveProcess *p, ThreadContext *tc);
2219651SAndreas.Sandberg@ARM.com
2229651SAndreas.Sandberg@ARM.com/// Target rename() handler.
2239651SAndreas.Sandberg@ARM.comSyscallReturn renameFunc(SyscallDesc *desc, int num,
2249651SAndreas.Sandberg@ARM.com                         LiveProcess *p, ThreadContext *tc);
2259651SAndreas.Sandberg@ARM.com
2269651SAndreas.Sandberg@ARM.com
2279651SAndreas.Sandberg@ARM.com/// Target truncate() handler.
2289651SAndreas.Sandberg@ARM.comSyscallReturn truncateFunc(SyscallDesc *desc, int num,
2299651SAndreas.Sandberg@ARM.com                           LiveProcess *p, ThreadContext *tc);
2309651SAndreas.Sandberg@ARM.com
2319651SAndreas.Sandberg@ARM.com
2329651SAndreas.Sandberg@ARM.com/// Target ftruncate() handler.
2339651SAndreas.Sandberg@ARM.comSyscallReturn ftruncateFunc(SyscallDesc *desc, int num,
2349651SAndreas.Sandberg@ARM.com                            LiveProcess *p, ThreadContext *tc);
2359651SAndreas.Sandberg@ARM.com
2369651SAndreas.Sandberg@ARM.com
2379651SAndreas.Sandberg@ARM.com/// Target truncate64() handler.
2389651SAndreas.Sandberg@ARM.comSyscallReturn truncate64Func(SyscallDesc *desc, int num,
2399651SAndreas.Sandberg@ARM.com                             LiveProcess *p, ThreadContext *tc);
2409651SAndreas.Sandberg@ARM.com
2419651SAndreas.Sandberg@ARM.com/// Target ftruncate64() handler.
2429651SAndreas.Sandberg@ARM.comSyscallReturn ftruncate64Func(SyscallDesc *desc, int num,
2439651SAndreas.Sandberg@ARM.com                              LiveProcess *p, ThreadContext *tc);
2449651SAndreas.Sandberg@ARM.com
2459651SAndreas.Sandberg@ARM.com
2469651SAndreas.Sandberg@ARM.com/// Target umask() handler.
2479651SAndreas.Sandberg@ARM.comSyscallReturn umaskFunc(SyscallDesc *desc, int num,
2489651SAndreas.Sandberg@ARM.com                        LiveProcess *p, ThreadContext *tc);
2499683Sandreas@sandberg.pp.se
2509683Sandreas@sandberg.pp.se
2519683Sandreas@sandberg.pp.se/// Target chown() handler.
2529683Sandreas@sandberg.pp.seSyscallReturn chownFunc(SyscallDesc *desc, int num,
2539683Sandreas@sandberg.pp.se                        LiveProcess *p, ThreadContext *tc);
2549651SAndreas.Sandberg@ARM.com
2559651SAndreas.Sandberg@ARM.com
2569651SAndreas.Sandberg@ARM.com/// Target fchown() handler.
2579651SAndreas.Sandberg@ARM.comSyscallReturn fchownFunc(SyscallDesc *desc, int num,
2589651SAndreas.Sandberg@ARM.com                         LiveProcess *p, ThreadContext *tc);
2599651SAndreas.Sandberg@ARM.com
2609651SAndreas.Sandberg@ARM.com/// Target dup() handler.
2619651SAndreas.Sandberg@ARM.comSyscallReturn dupFunc(SyscallDesc *desc, int num,
2629651SAndreas.Sandberg@ARM.com                      LiveProcess *process, ThreadContext *tc);
2639683Sandreas@sandberg.pp.se
2649683Sandreas@sandberg.pp.se/// Target fnctl() handler.
2659651SAndreas.Sandberg@ARM.comSyscallReturn fcntlFunc(SyscallDesc *desc, int num,
2669651SAndreas.Sandberg@ARM.com                        LiveProcess *process, ThreadContext *tc);
2679651SAndreas.Sandberg@ARM.com
2689652SAndreas.Sandberg@ARM.com/// Target fcntl64() handler.
2699651SAndreas.Sandberg@ARM.comSyscallReturn fcntl64Func(SyscallDesc *desc, int num,
2709651SAndreas.Sandberg@ARM.com                        LiveProcess *process, ThreadContext *tc);
2719651SAndreas.Sandberg@ARM.com
2729651SAndreas.Sandberg@ARM.com/// Target setuid() handler.
2739651SAndreas.Sandberg@ARM.comSyscallReturn setuidFunc(SyscallDesc *desc, int num,
2749651SAndreas.Sandberg@ARM.com                               LiveProcess *p, ThreadContext *tc);
2759651SAndreas.Sandberg@ARM.com
2769651SAndreas.Sandberg@ARM.com/// Target getpid() handler.
2779753Sandreas@sandberg.pp.seSyscallReturn getpidFunc(SyscallDesc *desc, int num,
2789753Sandreas@sandberg.pp.se                               LiveProcess *p, ThreadContext *tc);
2799753Sandreas@sandberg.pp.se
2809753Sandreas@sandberg.pp.se/// Target getuid() handler.
2819753Sandreas@sandberg.pp.seSyscallReturn getuidFunc(SyscallDesc *desc, int num,
2829753Sandreas@sandberg.pp.se                               LiveProcess *p, ThreadContext *tc);
2839753Sandreas@sandberg.pp.se
2849753Sandreas@sandberg.pp.se/// Target getgid() handler.
2859753Sandreas@sandberg.pp.seSyscallReturn getgidFunc(SyscallDesc *desc, int num,
2869753Sandreas@sandberg.pp.se                               LiveProcess *p, ThreadContext *tc);
2879753Sandreas@sandberg.pp.se
2889753Sandreas@sandberg.pp.se/// Target getppid() handler.
2899651SAndreas.Sandberg@ARM.comSyscallReturn getppidFunc(SyscallDesc *desc, int num,
2909753Sandreas@sandberg.pp.se                               LiveProcess *p, ThreadContext *tc);
2919753Sandreas@sandberg.pp.se
2929753Sandreas@sandberg.pp.se/// Target geteuid() handler.
2939753Sandreas@sandberg.pp.seSyscallReturn geteuidFunc(SyscallDesc *desc, int num,
2949753Sandreas@sandberg.pp.se                               LiveProcess *p, ThreadContext *tc);
2959753Sandreas@sandberg.pp.se
2969753Sandreas@sandberg.pp.se/// Target getegid() handler.
2979651SAndreas.Sandberg@ARM.comSyscallReturn getegidFunc(SyscallDesc *desc, int num,
2989753Sandreas@sandberg.pp.se                               LiveProcess *p, ThreadContext *tc);
2999753Sandreas@sandberg.pp.se
3009753Sandreas@sandberg.pp.se/// Target clone() handler.
3019753Sandreas@sandberg.pp.seSyscallReturn cloneFunc(SyscallDesc *desc, int num,
3029753Sandreas@sandberg.pp.se                               LiveProcess *p, ThreadContext *tc);
3039753Sandreas@sandberg.pp.se
3049753Sandreas@sandberg.pp.se/// Target access() handler
3059753Sandreas@sandberg.pp.seSyscallReturn accessFunc(SyscallDesc *desc, int num,
3069753Sandreas@sandberg.pp.se                               LiveProcess *p, ThreadContext *tc);
3079753Sandreas@sandberg.pp.seSyscallReturn accessFunc(SyscallDesc *desc, int num,
3089753Sandreas@sandberg.pp.se                               LiveProcess *p, ThreadContext *tc,
3099753Sandreas@sandberg.pp.se                               int index);
3109753Sandreas@sandberg.pp.se
3119753Sandreas@sandberg.pp.se/// Futex system call
3129753Sandreas@sandberg.pp.se///  Implemented by Daniel Sanchez
3139753Sandreas@sandberg.pp.se///  Used by printf's in multi-threaded apps
3149753Sandreas@sandberg.pp.setemplate <class OS>
3159753Sandreas@sandberg.pp.seSyscallReturn
3169753Sandreas@sandberg.pp.sefutexFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
3179753Sandreas@sandberg.pp.se          ThreadContext *tc)
3189753Sandreas@sandberg.pp.se{
3199753Sandreas@sandberg.pp.se    int index_uaddr = 0;
3209753Sandreas@sandberg.pp.se    int index_op = 1;
3219753Sandreas@sandberg.pp.se    int index_val = 2;
3229753Sandreas@sandberg.pp.se    int index_timeout = 3;
3239753Sandreas@sandberg.pp.se
3249753Sandreas@sandberg.pp.se    uint64_t uaddr = process->getSyscallArg(tc, index_uaddr);
3259753Sandreas@sandberg.pp.se    int op = process->getSyscallArg(tc, index_op);
3269753Sandreas@sandberg.pp.se    int val = process->getSyscallArg(tc, index_val);
3279753Sandreas@sandberg.pp.se    uint64_t timeout = process->getSyscallArg(tc, index_timeout);
3289753Sandreas@sandberg.pp.se
3299753Sandreas@sandberg.pp.se    std::map<uint64_t, std::list<ThreadContext *> * >
3309753Sandreas@sandberg.pp.se        &futex_map = tc->getSystemPtr()->futexMap;
3319753Sandreas@sandberg.pp.se
3329753Sandreas@sandberg.pp.se    DPRINTF(SyscallVerbose, "In sys_futex: Address=%llx, op=%d, val=%d\n",
3339651SAndreas.Sandberg@ARM.com            uaddr, op, val);
3349651SAndreas.Sandberg@ARM.com
3359651SAndreas.Sandberg@ARM.com    op &= ~OS::TGT_FUTEX_PRIVATE_FLAG;
3369651SAndreas.Sandberg@ARM.com
3379651SAndreas.Sandberg@ARM.com    if (op == OS::TGT_FUTEX_WAIT) {
3389651SAndreas.Sandberg@ARM.com        if (timeout != 0) {
3399651SAndreas.Sandberg@ARM.com            warn("sys_futex: FUTEX_WAIT with non-null timeout unimplemented;"
3409651SAndreas.Sandberg@ARM.com                 "we'll wait indefinitely");
3419651SAndreas.Sandberg@ARM.com        }
3429651SAndreas.Sandberg@ARM.com
3439651SAndreas.Sandberg@ARM.com        uint8_t *buf = new uint8_t[sizeof(int)];
3449651SAndreas.Sandberg@ARM.com        tc->getMemProxy().readBlob((Addr)uaddr, buf, (int)sizeof(int));
3459651SAndreas.Sandberg@ARM.com        int mem_val = *((int *)buf);
3469651SAndreas.Sandberg@ARM.com        delete[] buf;
3479651SAndreas.Sandberg@ARM.com
3489651SAndreas.Sandberg@ARM.com        if (val != mem_val) {
3499651SAndreas.Sandberg@ARM.com            DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAKE, read: %d, "
3509651SAndreas.Sandberg@ARM.com                                    "expected: %d\n", mem_val, val);
3519651SAndreas.Sandberg@ARM.com            return -OS::TGT_EWOULDBLOCK;
3529651SAndreas.Sandberg@ARM.com        }
3539651SAndreas.Sandberg@ARM.com
3549651SAndreas.Sandberg@ARM.com        // Queue the thread context
3559651SAndreas.Sandberg@ARM.com        std::list<ThreadContext *> * tcWaitList;
3569651SAndreas.Sandberg@ARM.com        if (futex_map.count(uaddr)) {
3579651SAndreas.Sandberg@ARM.com            tcWaitList = futex_map.find(uaddr)->second;
3589651SAndreas.Sandberg@ARM.com        } else {
3599651SAndreas.Sandberg@ARM.com            tcWaitList = new std::list<ThreadContext *>();
3609651SAndreas.Sandberg@ARM.com            futex_map.insert(std::pair< uint64_t,
3619652SAndreas.Sandberg@ARM.com                            std::list<ThreadContext *> * >(uaddr, tcWaitList));
3629652SAndreas.Sandberg@ARM.com        }
3639651SAndreas.Sandberg@ARM.com        tcWaitList->push_back(tc);
3649651SAndreas.Sandberg@ARM.com        DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAIT, suspending calling "
3659651SAndreas.Sandberg@ARM.com                                "thread context\n");
3669651SAndreas.Sandberg@ARM.com        tc->suspend();
3679651SAndreas.Sandberg@ARM.com        return 0;
3689651SAndreas.Sandberg@ARM.com    } else if (op == OS::TGT_FUTEX_WAKE){
3699651SAndreas.Sandberg@ARM.com        int wokenUp = 0;
3709651SAndreas.Sandberg@ARM.com        std::list<ThreadContext *> * tcWaitList;
3719651SAndreas.Sandberg@ARM.com        if (futex_map.count(uaddr)) {
3729651SAndreas.Sandberg@ARM.com            tcWaitList = futex_map.find(uaddr)->second;
3739651SAndreas.Sandberg@ARM.com            while (tcWaitList->size() > 0 && wokenUp < val) {
3749651SAndreas.Sandberg@ARM.com                tcWaitList->front()->activate();
3759651SAndreas.Sandberg@ARM.com                tcWaitList->pop_front();
3769651SAndreas.Sandberg@ARM.com                wokenUp++;
3779651SAndreas.Sandberg@ARM.com            }
3789651SAndreas.Sandberg@ARM.com            if (tcWaitList->empty()) {
3799651SAndreas.Sandberg@ARM.com                futex_map.erase(uaddr);
3809651SAndreas.Sandberg@ARM.com                delete tcWaitList;
3819651SAndreas.Sandberg@ARM.com            }
3829651SAndreas.Sandberg@ARM.com        }
3839651SAndreas.Sandberg@ARM.com        DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAKE, activated %d waiting "
3849651SAndreas.Sandberg@ARM.com                                "thread contexts\n", wokenUp);
3859651SAndreas.Sandberg@ARM.com        return wokenUp;
3869753Sandreas@sandberg.pp.se    } else {
3879753Sandreas@sandberg.pp.se        warn("sys_futex: op %d is not implemented, just returning...", op);
3889753Sandreas@sandberg.pp.se        return 0;
3899753Sandreas@sandberg.pp.se    }
3909753Sandreas@sandberg.pp.se
3919753Sandreas@sandberg.pp.se}
3929651SAndreas.Sandberg@ARM.com
3939651SAndreas.Sandberg@ARM.com
3949651SAndreas.Sandberg@ARM.com/// Pseudo Funcs  - These functions use a different return convension,
3959651SAndreas.Sandberg@ARM.com/// returning a second value in a register other than the normal return register
3969651SAndreas.Sandberg@ARM.comSyscallReturn pipePseudoFunc(SyscallDesc *desc, int num,
3979651SAndreas.Sandberg@ARM.com                             LiveProcess *process, ThreadContext *tc);
3989651SAndreas.Sandberg@ARM.com
3999651SAndreas.Sandberg@ARM.com/// Target getpidPseudo() handler.
4009651SAndreas.Sandberg@ARM.comSyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num,
4019651SAndreas.Sandberg@ARM.com                               LiveProcess *p, ThreadContext *tc);
4029651SAndreas.Sandberg@ARM.com
4039651SAndreas.Sandberg@ARM.com/// Target getuidPseudo() handler.
4049651SAndreas.Sandberg@ARM.comSyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num,
4059651SAndreas.Sandberg@ARM.com                               LiveProcess *p, ThreadContext *tc);
4069651SAndreas.Sandberg@ARM.com
4079651SAndreas.Sandberg@ARM.com/// Target getgidPseudo() handler.
4089651SAndreas.Sandberg@ARM.comSyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num,
4099651SAndreas.Sandberg@ARM.com                               LiveProcess *p, ThreadContext *tc);
4109651SAndreas.Sandberg@ARM.com
4119651SAndreas.Sandberg@ARM.com
4129651SAndreas.Sandberg@ARM.com/// A readable name for 1,000,000, for converting microseconds to seconds.
4139651SAndreas.Sandberg@ARM.comconst int one_million = 1000000;
4149651SAndreas.Sandberg@ARM.com/// A readable name for 1,000,000,000, for converting nanoseconds to seconds.
4159651SAndreas.Sandberg@ARM.comconst int one_billion = 1000000000;
4169651SAndreas.Sandberg@ARM.com
4179651SAndreas.Sandberg@ARM.com/// Approximate seconds since the epoch (1/1/1970).  About a billion,
4189651SAndreas.Sandberg@ARM.com/// by my reckoning.  We want to keep this a constant (not use the
4199651SAndreas.Sandberg@ARM.com/// real-world time) to keep simulations repeatable.
4209651SAndreas.Sandberg@ARM.comconst unsigned seconds_since_epoch = 1000000000;
4219651SAndreas.Sandberg@ARM.com
4229651SAndreas.Sandberg@ARM.com/// Helper function to convert current elapsed time to seconds and
4239651SAndreas.Sandberg@ARM.com/// microseconds.
4249651SAndreas.Sandberg@ARM.comtemplate <class T1, class T2>
4259754Sandreas@sandberg.pp.sevoid
4269651SAndreas.Sandberg@ARM.comgetElapsedTimeMicro(T1 &sec, T2 &usec)
4279651SAndreas.Sandberg@ARM.com{
4289651SAndreas.Sandberg@ARM.com    uint64_t elapsed_usecs = curTick() / SimClock::Int::us;
4299651SAndreas.Sandberg@ARM.com    sec = elapsed_usecs / one_million;
4309651SAndreas.Sandberg@ARM.com    usec = elapsed_usecs % one_million;
4319651SAndreas.Sandberg@ARM.com}
4329651SAndreas.Sandberg@ARM.com
4339651SAndreas.Sandberg@ARM.com/// Helper function to convert current elapsed time to seconds and
4349651SAndreas.Sandberg@ARM.com/// nanoseconds.
4359651SAndreas.Sandberg@ARM.comtemplate <class T1, class T2>
4369651SAndreas.Sandberg@ARM.comvoid
4379651SAndreas.Sandberg@ARM.comgetElapsedTimeNano(T1 &sec, T2 &nsec)
4389651SAndreas.Sandberg@ARM.com{
4399651SAndreas.Sandberg@ARM.com    uint64_t elapsed_nsecs = curTick() / SimClock::Int::ns;
4409651SAndreas.Sandberg@ARM.com    sec = elapsed_nsecs / one_billion;
4419651SAndreas.Sandberg@ARM.com    nsec = elapsed_nsecs % one_billion;
4429651SAndreas.Sandberg@ARM.com}
4439651SAndreas.Sandberg@ARM.com
4449651SAndreas.Sandberg@ARM.com//////////////////////////////////////////////////////////////////////
4459651SAndreas.Sandberg@ARM.com//
4469651SAndreas.Sandberg@ARM.com// The following emulation functions are generic, but need to be
4479651SAndreas.Sandberg@ARM.com// templated to account for differences in types, constants, etc.
4489651SAndreas.Sandberg@ARM.com//
4499651SAndreas.Sandberg@ARM.com//////////////////////////////////////////////////////////////////////
4509651SAndreas.Sandberg@ARM.com
4519651SAndreas.Sandberg@ARM.com#if NO_STAT64
4529651SAndreas.Sandberg@ARM.com    typedef struct stat hst_stat;
4539651SAndreas.Sandberg@ARM.com    typedef struct stat hst_stat64;
4549651SAndreas.Sandberg@ARM.com#else
4559651SAndreas.Sandberg@ARM.com    typedef struct stat hst_stat;
4569651SAndreas.Sandberg@ARM.com    typedef struct stat64 hst_stat64;
4579651SAndreas.Sandberg@ARM.com#endif
4589651SAndreas.Sandberg@ARM.com
4599651SAndreas.Sandberg@ARM.com//// Helper function to convert a host stat buffer to a target stat
4609651SAndreas.Sandberg@ARM.com//// buffer.  Also copies the target buffer out to the simulated
4619651SAndreas.Sandberg@ARM.com//// memory space.  Used by stat(), fstat(), and lstat().
4629651SAndreas.Sandberg@ARM.com
4639651SAndreas.Sandberg@ARM.comtemplate <typename target_stat, typename host_stat>
4649651SAndreas.Sandberg@ARM.comstatic void
4659651SAndreas.Sandberg@ARM.comconvertStatBuf(target_stat &tgt, host_stat *host, bool fakeTTY = false)
4669651SAndreas.Sandberg@ARM.com{
4679651SAndreas.Sandberg@ARM.com    using namespace TheISA;
4689651SAndreas.Sandberg@ARM.com
4699652SAndreas.Sandberg@ARM.com    if (fakeTTY)
4709652SAndreas.Sandberg@ARM.com        tgt->st_dev = 0xA;
4719652SAndreas.Sandberg@ARM.com    else
4729652SAndreas.Sandberg@ARM.com        tgt->st_dev = host->st_dev;
4739652SAndreas.Sandberg@ARM.com    tgt->st_dev = TheISA::htog(tgt->st_dev);
4749652SAndreas.Sandberg@ARM.com    tgt->st_ino = host->st_ino;
4759652SAndreas.Sandberg@ARM.com    tgt->st_ino = TheISA::htog(tgt->st_ino);
4769652SAndreas.Sandberg@ARM.com    tgt->st_mode = host->st_mode;
4779652SAndreas.Sandberg@ARM.com    if (fakeTTY) {
4789651SAndreas.Sandberg@ARM.com        // Claim to be a character device
4799651SAndreas.Sandberg@ARM.com        tgt->st_mode &= ~S_IFMT;    // Clear S_IFMT
4809651SAndreas.Sandberg@ARM.com        tgt->st_mode |= S_IFCHR;    // Set S_IFCHR
4819752Sandreas@sandberg.pp.se    }
4829651SAndreas.Sandberg@ARM.com    tgt->st_mode = TheISA::htog(tgt->st_mode);
4839651SAndreas.Sandberg@ARM.com    tgt->st_nlink = host->st_nlink;
4849651SAndreas.Sandberg@ARM.com    tgt->st_nlink = TheISA::htog(tgt->st_nlink);
4859651SAndreas.Sandberg@ARM.com    tgt->st_uid = host->st_uid;
4869651SAndreas.Sandberg@ARM.com    tgt->st_uid = TheISA::htog(tgt->st_uid);
4879651SAndreas.Sandberg@ARM.com    tgt->st_gid = host->st_gid;
4889752Sandreas@sandberg.pp.se    tgt->st_gid = TheISA::htog(tgt->st_gid);
4899651SAndreas.Sandberg@ARM.com    if (fakeTTY)
4909651SAndreas.Sandberg@ARM.com        tgt->st_rdev = 0x880d;
4919651SAndreas.Sandberg@ARM.com    else
4929651SAndreas.Sandberg@ARM.com        tgt->st_rdev = host->st_rdev;
4939651SAndreas.Sandberg@ARM.com    tgt->st_rdev = TheISA::htog(tgt->st_rdev);
4949651SAndreas.Sandberg@ARM.com    tgt->st_size = host->st_size;
4959651SAndreas.Sandberg@ARM.com    tgt->st_size = TheISA::htog(tgt->st_size);
4969651SAndreas.Sandberg@ARM.com    tgt->st_atimeX = host->st_atime;
4979651SAndreas.Sandberg@ARM.com    tgt->st_atimeX = TheISA::htog(tgt->st_atimeX);
4989651SAndreas.Sandberg@ARM.com    tgt->st_mtimeX = host->st_mtime;
4999651SAndreas.Sandberg@ARM.com    tgt->st_mtimeX = TheISA::htog(tgt->st_mtimeX);
5009753Sandreas@sandberg.pp.se    tgt->st_ctimeX = host->st_ctime;
5019753Sandreas@sandberg.pp.se    tgt->st_ctimeX = TheISA::htog(tgt->st_ctimeX);
5029651SAndreas.Sandberg@ARM.com    // Force the block size to be 8k. This helps to ensure buffered io works
5039651SAndreas.Sandberg@ARM.com    // consistently across different hosts.
5049753Sandreas@sandberg.pp.se    tgt->st_blksize = 0x2000;
5059753Sandreas@sandberg.pp.se    tgt->st_blksize = TheISA::htog(tgt->st_blksize);
5069753Sandreas@sandberg.pp.se    tgt->st_blocks = host->st_blocks;
5079753Sandreas@sandberg.pp.se    tgt->st_blocks = TheISA::htog(tgt->st_blocks);
5089753Sandreas@sandberg.pp.se}
5099753Sandreas@sandberg.pp.se
5109651SAndreas.Sandberg@ARM.com// Same for stat64
5119651SAndreas.Sandberg@ARM.com
5129753Sandreas@sandberg.pp.setemplate <typename target_stat, typename host_stat64>
5139753Sandreas@sandberg.pp.sestatic void
5149753Sandreas@sandberg.pp.seconvertStat64Buf(target_stat &tgt, host_stat64 *host, bool fakeTTY = false)
5159753Sandreas@sandberg.pp.se{
5169753Sandreas@sandberg.pp.se    using namespace TheISA;
5179753Sandreas@sandberg.pp.se
5189753Sandreas@sandberg.pp.se    convertStatBuf<target_stat, host_stat64>(tgt, host, fakeTTY);
5199753Sandreas@sandberg.pp.se#if defined(STAT_HAVE_NSEC)
5209753Sandreas@sandberg.pp.se    tgt->st_atime_nsec = host->st_atime_nsec;
5219753Sandreas@sandberg.pp.se    tgt->st_atime_nsec = TheISA::htog(tgt->st_atime_nsec);
5229753Sandreas@sandberg.pp.se    tgt->st_mtime_nsec = host->st_mtime_nsec;
5239753Sandreas@sandberg.pp.se    tgt->st_mtime_nsec = TheISA::htog(tgt->st_mtime_nsec);
5249753Sandreas@sandberg.pp.se    tgt->st_ctime_nsec = host->st_ctime_nsec;
5259753Sandreas@sandberg.pp.se    tgt->st_ctime_nsec = TheISA::htog(tgt->st_ctime_nsec);
5269753Sandreas@sandberg.pp.se#else
5279753Sandreas@sandberg.pp.se    tgt->st_atime_nsec = 0;
5289753Sandreas@sandberg.pp.se    tgt->st_mtime_nsec = 0;
5299753Sandreas@sandberg.pp.se    tgt->st_ctime_nsec = 0;
5309753Sandreas@sandberg.pp.se#endif
5319753Sandreas@sandberg.pp.se}
5329753Sandreas@sandberg.pp.se
5339753Sandreas@sandberg.pp.se//Here are a couple convenience functions
5349753Sandreas@sandberg.pp.setemplate<class OS>
5359753Sandreas@sandberg.pp.sestatic void
5369753Sandreas@sandberg.pp.secopyOutStatBuf(SETranslatingPortProxy &mem, Addr addr,
5379755Sandreas@sandberg.pp.se        hst_stat *host, bool fakeTTY = false)
5389753Sandreas@sandberg.pp.se{
5399755Sandreas@sandberg.pp.se    typedef TypedBufferArg<typename OS::tgt_stat> tgt_stat_buf;
5409755Sandreas@sandberg.pp.se    tgt_stat_buf tgt(addr);
5419753Sandreas@sandberg.pp.se    convertStatBuf<tgt_stat_buf, hst_stat>(tgt, host, fakeTTY);
5429755Sandreas@sandberg.pp.se    tgt.copyOut(mem);
5439753Sandreas@sandberg.pp.se}
5449753Sandreas@sandberg.pp.se
5459753Sandreas@sandberg.pp.setemplate<class OS>
5469753Sandreas@sandberg.pp.sestatic void
5479753Sandreas@sandberg.pp.secopyOutStat64Buf(SETranslatingPortProxy &mem, Addr addr,
5489651SAndreas.Sandberg@ARM.com        hst_stat64 *host, bool fakeTTY = false)
5499753Sandreas@sandberg.pp.se{
5509753Sandreas@sandberg.pp.se    typedef TypedBufferArg<typename OS::tgt_stat64> tgt_stat_buf;
5519651SAndreas.Sandberg@ARM.com    tgt_stat_buf tgt(addr);
5529753Sandreas@sandberg.pp.se    convertStat64Buf<tgt_stat_buf, hst_stat64>(tgt, host, fakeTTY);
5539753Sandreas@sandberg.pp.se    tgt.copyOut(mem);
5549753Sandreas@sandberg.pp.se}
5559753Sandreas@sandberg.pp.se
5569753Sandreas@sandberg.pp.se/// Target ioctl() handler.  For the most part, programs call ioctl()
5579753Sandreas@sandberg.pp.se/// only to find out if their stdout is a tty, to determine whether to
5589753Sandreas@sandberg.pp.se/// do line or block buffering.  We always claim that output fds are
5599753Sandreas@sandberg.pp.se/// not TTYs to provide repeatable results.
5609753Sandreas@sandberg.pp.setemplate <class OS>
5619753Sandreas@sandberg.pp.seSyscallReturn
5629753Sandreas@sandberg.pp.seioctlFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
5639753Sandreas@sandberg.pp.se          ThreadContext *tc)
5649753Sandreas@sandberg.pp.se{
5659753Sandreas@sandberg.pp.se    int index = 0;
5669753Sandreas@sandberg.pp.se    int tgt_fd = process->getSyscallArg(tc, index);
5679753Sandreas@sandberg.pp.se    unsigned req = process->getSyscallArg(tc, index);
5689753Sandreas@sandberg.pp.se
5699651SAndreas.Sandberg@ARM.com    DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", tgt_fd, req);
5709651SAndreas.Sandberg@ARM.com
5719735Sandreas@sandberg.pp.se    FDEntry *fde = process->getFDEntry(tgt_fd);
5729735Sandreas@sandberg.pp.se
5739735Sandreas@sandberg.pp.se    if (fde == NULL) {
5749735Sandreas@sandberg.pp.se        // doesn't map to any simulator fd: not a valid target fd
5759735Sandreas@sandberg.pp.se        return -EBADF;
5769735Sandreas@sandberg.pp.se    }
5779651SAndreas.Sandberg@ARM.com
5789651SAndreas.Sandberg@ARM.com    if (fde->driver != NULL) {
5799651SAndreas.Sandberg@ARM.com        return fde->driver->ioctl(process, tc, req);
5809753Sandreas@sandberg.pp.se    }
5819651SAndreas.Sandberg@ARM.com
5829651SAndreas.Sandberg@ARM.com    if (OS::isTtyReq(req)) {
5839655SAndreas.Sandberg@ARM.com        return -ENOTTY;
5849753Sandreas@sandberg.pp.se    }
5859753Sandreas@sandberg.pp.se
5869753Sandreas@sandberg.pp.se    warn("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ \n",
5879753Sandreas@sandberg.pp.se         tgt_fd, req, tc->pcState());
5889753Sandreas@sandberg.pp.se    return -ENOTTY;
5899735Sandreas@sandberg.pp.se}
5909755Sandreas@sandberg.pp.se
5919755Sandreas@sandberg.pp.setemplate <class OS>
5929753Sandreas@sandberg.pp.sestatic SyscallReturn
5939753Sandreas@sandberg.pp.seopenFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
5949753Sandreas@sandberg.pp.se         ThreadContext *tc, int index)
5959753Sandreas@sandberg.pp.se{
5969655SAndreas.Sandberg@ARM.com    std::string path;
5979753Sandreas@sandberg.pp.se
5989753Sandreas@sandberg.pp.se    if (!tc->getMemProxy().tryReadString(path,
5999753Sandreas@sandberg.pp.se                process->getSyscallArg(tc, index)))
6009753Sandreas@sandberg.pp.se        return -EFAULT;
6019753Sandreas@sandberg.pp.se
6029753Sandreas@sandberg.pp.se    int tgtFlags = process->getSyscallArg(tc, index);
6039753Sandreas@sandberg.pp.se    int mode = process->getSyscallArg(tc, index);
6049753Sandreas@sandberg.pp.se    int hostFlags = 0;
6059753Sandreas@sandberg.pp.se
6069753Sandreas@sandberg.pp.se    // translate open flags
6079753Sandreas@sandberg.pp.se    for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) {
6089753Sandreas@sandberg.pp.se        if (tgtFlags & OS::openFlagTable[i].tgtFlag) {
6099753Sandreas@sandberg.pp.se            tgtFlags &= ~OS::openFlagTable[i].tgtFlag;
6109753Sandreas@sandberg.pp.se            hostFlags |= OS::openFlagTable[i].hostFlag;
6119753Sandreas@sandberg.pp.se        }
6129753Sandreas@sandberg.pp.se    }
6139753Sandreas@sandberg.pp.se
6149753Sandreas@sandberg.pp.se    // any target flags left?
6159753Sandreas@sandberg.pp.se    if (tgtFlags != 0)
6169753Sandreas@sandberg.pp.se        warn("Syscall: open: cannot decode flags 0x%x", tgtFlags);
6179753Sandreas@sandberg.pp.se
6189753Sandreas@sandberg.pp.se#ifdef __CYGWIN32__
6199753Sandreas@sandberg.pp.se    hostFlags |= O_BINARY;
6209753Sandreas@sandberg.pp.se#endif
6219753Sandreas@sandberg.pp.se
6229753Sandreas@sandberg.pp.se    // Adjust path for current working directory
6239753Sandreas@sandberg.pp.se    path = process->fullPath(path);
6249753Sandreas@sandberg.pp.se
6259753Sandreas@sandberg.pp.se    DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str());
6269753Sandreas@sandberg.pp.se
6279753Sandreas@sandberg.pp.se    if (startswith(path, "/dev/")) {
6289753Sandreas@sandberg.pp.se        std::string filename = path.substr(strlen("/dev/"));
6299753Sandreas@sandberg.pp.se        if (filename == "sysdev0") {
6309753Sandreas@sandberg.pp.se            // This is a memory-mapped high-resolution timer device on Alpha.
6319753Sandreas@sandberg.pp.se            // We don't support it, so just punt.
6329753Sandreas@sandberg.pp.se            warn("Ignoring open(%s, ...)\n", path);
6339753Sandreas@sandberg.pp.se            return -ENOENT;
6349753Sandreas@sandberg.pp.se        }
6359753Sandreas@sandberg.pp.se
6369753Sandreas@sandberg.pp.se        EmulatedDriver *drv = process->findDriver(filename);
6379753Sandreas@sandberg.pp.se        if (drv != NULL) {
6389753Sandreas@sandberg.pp.se            // the driver's open method will allocate a fd from the
6399753Sandreas@sandberg.pp.se            // process if necessary.
6409753Sandreas@sandberg.pp.se            return drv->open(process, tc, mode, hostFlags);
6419753Sandreas@sandberg.pp.se        }
6429753Sandreas@sandberg.pp.se
6439753Sandreas@sandberg.pp.se        // fall through here for pass through to host devices, such as
6449753Sandreas@sandberg.pp.se        // /dev/zero
6459753Sandreas@sandberg.pp.se    }
6469753Sandreas@sandberg.pp.se
6479753Sandreas@sandberg.pp.se    int fd;
6489753Sandreas@sandberg.pp.se    int local_errno;
6499753Sandreas@sandberg.pp.se    if (startswith(path, "/proc/") || startswith(path, "/system/") ||
6509753Sandreas@sandberg.pp.se        startswith(path, "/platform/") || startswith(path, "/sys/")) {
6519753Sandreas@sandberg.pp.se        // It's a proc/sys entry and requires special handling
6529753Sandreas@sandberg.pp.se        fd = OS::openSpecialFile(path, process, tc);
6539753Sandreas@sandberg.pp.se        local_errno = ENOENT;
6549753Sandreas@sandberg.pp.se     } else {
6559753Sandreas@sandberg.pp.se        // open the file
6569753Sandreas@sandberg.pp.se        fd = open(path.c_str(), hostFlags, mode);
6579753Sandreas@sandberg.pp.se        local_errno = errno;
6589753Sandreas@sandberg.pp.se     }
6599753Sandreas@sandberg.pp.se
6609753Sandreas@sandberg.pp.se    if (fd == -1)
6619753Sandreas@sandberg.pp.se        return -local_errno;
6629753Sandreas@sandberg.pp.se
6639753Sandreas@sandberg.pp.se    return process->allocFD(fd, path.c_str(), hostFlags, mode, false);
6649651SAndreas.Sandberg@ARM.com}
6659655SAndreas.Sandberg@ARM.com
6669651SAndreas.Sandberg@ARM.com/// Target open() handler.
6679651SAndreas.Sandberg@ARM.comtemplate <class OS>
6689651SAndreas.Sandberg@ARM.comSyscallReturn
6699651SAndreas.Sandberg@ARM.comopenFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
6709651SAndreas.Sandberg@ARM.com         ThreadContext *tc)
6719651SAndreas.Sandberg@ARM.com{
6729651SAndreas.Sandberg@ARM.com    return openFunc<OS>(desc, callnum, process, tc, 0);
6739651SAndreas.Sandberg@ARM.com}
6749651SAndreas.Sandberg@ARM.com
6759651SAndreas.Sandberg@ARM.com/// Target openat() handler.
6769651SAndreas.Sandberg@ARM.comtemplate <class OS>
6779651SAndreas.Sandberg@ARM.comSyscallReturn
6789651SAndreas.Sandberg@ARM.comopenatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
6799651SAndreas.Sandberg@ARM.com         ThreadContext *tc)
6809651SAndreas.Sandberg@ARM.com{
6819651SAndreas.Sandberg@ARM.com    int index = 0;
6829651SAndreas.Sandberg@ARM.com    int dirfd = process->getSyscallArg(tc, index);
6839651SAndreas.Sandberg@ARM.com    if (dirfd != OS::TGT_AT_FDCWD)
6849651SAndreas.Sandberg@ARM.com        warn("openat: first argument not AT_FDCWD; unlikely to work");
6859651SAndreas.Sandberg@ARM.com    return openFunc<OS>(desc, callnum, process, tc, 1);
6869651SAndreas.Sandberg@ARM.com}
6879651SAndreas.Sandberg@ARM.com
6889651SAndreas.Sandberg@ARM.com/// Target unlinkat() handler.
6899651SAndreas.Sandberg@ARM.comtemplate <class OS>
6909651SAndreas.Sandberg@ARM.comSyscallReturn
6919651SAndreas.Sandberg@ARM.comunlinkatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
6929651SAndreas.Sandberg@ARM.com             ThreadContext *tc)
6939651SAndreas.Sandberg@ARM.com{
6949651SAndreas.Sandberg@ARM.com    int index = 0;
6959651SAndreas.Sandberg@ARM.com    int dirfd = process->getSyscallArg(tc, index);
6969651SAndreas.Sandberg@ARM.com    if (dirfd != OS::TGT_AT_FDCWD)
6979651SAndreas.Sandberg@ARM.com        warn("unlinkat: first argument not AT_FDCWD; unlikely to work");
6989651SAndreas.Sandberg@ARM.com
6999651SAndreas.Sandberg@ARM.com    return unlinkHelper(desc, callnum, process, tc, 1);
7009651SAndreas.Sandberg@ARM.com}
7019651SAndreas.Sandberg@ARM.com
7029651SAndreas.Sandberg@ARM.com/// Target facessat() handler
7039651SAndreas.Sandberg@ARM.comtemplate <class OS>
7049651SAndreas.Sandberg@ARM.comSyscallReturn
7059651SAndreas.Sandberg@ARM.comfaccessatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
7069651SAndreas.Sandberg@ARM.com        ThreadContext *tc)
7079651SAndreas.Sandberg@ARM.com{
7089651SAndreas.Sandberg@ARM.com    int index = 0;
7099651SAndreas.Sandberg@ARM.com    int dirfd = process->getSyscallArg(tc, index);
7109651SAndreas.Sandberg@ARM.com    if (dirfd != OS::TGT_AT_FDCWD)
7119651SAndreas.Sandberg@ARM.com        warn("faccessat: first argument not AT_FDCWD; unlikely to work");
7129651SAndreas.Sandberg@ARM.com    return accessFunc(desc, callnum, process, tc, 1);
7139651SAndreas.Sandberg@ARM.com}
7149651SAndreas.Sandberg@ARM.com
7159651SAndreas.Sandberg@ARM.com/// Target readlinkat() handler
7169651SAndreas.Sandberg@ARM.comtemplate <class OS>
7179651SAndreas.Sandberg@ARM.comSyscallReturn
7189651SAndreas.Sandberg@ARM.comreadlinkatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
7199651SAndreas.Sandberg@ARM.com        ThreadContext *tc)
7209651SAndreas.Sandberg@ARM.com{
7219651SAndreas.Sandberg@ARM.com    int index = 0;
7229651SAndreas.Sandberg@ARM.com    int dirfd = process->getSyscallArg(tc, index);
7239651SAndreas.Sandberg@ARM.com    if (dirfd != OS::TGT_AT_FDCWD)
7249651SAndreas.Sandberg@ARM.com        warn("openat: first argument not AT_FDCWD; unlikely to work");
7259651SAndreas.Sandberg@ARM.com    return readlinkFunc(desc, callnum, process, tc, 1);
7269651SAndreas.Sandberg@ARM.com}
7279651SAndreas.Sandberg@ARM.com
7289651SAndreas.Sandberg@ARM.com/// Target renameat() handler.
7299651SAndreas.Sandberg@ARM.comtemplate <class OS>
7309651SAndreas.Sandberg@ARM.comSyscallReturn
7319651SAndreas.Sandberg@ARM.comrenameatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
7329651SAndreas.Sandberg@ARM.com             ThreadContext *tc)
7339651SAndreas.Sandberg@ARM.com{
7349651SAndreas.Sandberg@ARM.com    int index = 0;
7359651SAndreas.Sandberg@ARM.com
7369651SAndreas.Sandberg@ARM.com    int olddirfd = process->getSyscallArg(tc, index);
7379651SAndreas.Sandberg@ARM.com    if (olddirfd != OS::TGT_AT_FDCWD)
7389651SAndreas.Sandberg@ARM.com        warn("renameat: first argument not AT_FDCWD; unlikely to work");
7399651SAndreas.Sandberg@ARM.com
7409651SAndreas.Sandberg@ARM.com    std::string old_name;
7419651SAndreas.Sandberg@ARM.com
7429651SAndreas.Sandberg@ARM.com    if (!tc->getMemProxy().tryReadString(old_name,
7439651SAndreas.Sandberg@ARM.com                                         process->getSyscallArg(tc, index)))
7449651SAndreas.Sandberg@ARM.com        return -EFAULT;
7459651SAndreas.Sandberg@ARM.com
7469651SAndreas.Sandberg@ARM.com    int newdirfd = process->getSyscallArg(tc, index);
7479651SAndreas.Sandberg@ARM.com    if (newdirfd != OS::TGT_AT_FDCWD)
7489651SAndreas.Sandberg@ARM.com        warn("renameat: third argument not AT_FDCWD; unlikely to work");
7499651SAndreas.Sandberg@ARM.com
7509651SAndreas.Sandberg@ARM.com    std::string new_name;
7519651SAndreas.Sandberg@ARM.com
7529651SAndreas.Sandberg@ARM.com    if (!tc->getMemProxy().tryReadString(new_name,
7539651SAndreas.Sandberg@ARM.com                                         process->getSyscallArg(tc, index)))
7549651SAndreas.Sandberg@ARM.com        return -EFAULT;
7559651SAndreas.Sandberg@ARM.com
7569651SAndreas.Sandberg@ARM.com    // Adjust path for current working directory
7579651SAndreas.Sandberg@ARM.com    old_name = process->fullPath(old_name);
7589651SAndreas.Sandberg@ARM.com    new_name = process->fullPath(new_name);
7599651SAndreas.Sandberg@ARM.com
7609651SAndreas.Sandberg@ARM.com    int result = rename(old_name.c_str(), new_name.c_str());
7619651SAndreas.Sandberg@ARM.com    return (result == -1) ? -errno : result;
7629651SAndreas.Sandberg@ARM.com}
7639651SAndreas.Sandberg@ARM.com
7649651SAndreas.Sandberg@ARM.com/// Target sysinfo() handler.
7659651SAndreas.Sandberg@ARM.comtemplate <class OS>
7669651SAndreas.Sandberg@ARM.comSyscallReturn
7679651SAndreas.Sandberg@ARM.comsysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
7689651SAndreas.Sandberg@ARM.com         ThreadContext *tc)
7699651SAndreas.Sandberg@ARM.com{
7709651SAndreas.Sandberg@ARM.com
7719651SAndreas.Sandberg@ARM.com    int index = 0;
7729651SAndreas.Sandberg@ARM.com    TypedBufferArg<typename OS::tgt_sysinfo>
7739651SAndreas.Sandberg@ARM.com        sysinfo(process->getSyscallArg(tc, index));
7749651SAndreas.Sandberg@ARM.com
7759651SAndreas.Sandberg@ARM.com    sysinfo->uptime=seconds_since_epoch;
7769651SAndreas.Sandberg@ARM.com    sysinfo->totalram=process->system->memSize();
7779651SAndreas.Sandberg@ARM.com
7789651SAndreas.Sandberg@ARM.com    sysinfo.copyOut(tc->getMemProxy());
7799651SAndreas.Sandberg@ARM.com
7809651SAndreas.Sandberg@ARM.com    return 0;
7819651SAndreas.Sandberg@ARM.com}
7829651SAndreas.Sandberg@ARM.com
7839651SAndreas.Sandberg@ARM.com/// Target chmod() handler.
7849651SAndreas.Sandberg@ARM.comtemplate <class OS>
7859651SAndreas.Sandberg@ARM.comSyscallReturn
7869651SAndreas.Sandberg@ARM.comchmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
7879651SAndreas.Sandberg@ARM.com          ThreadContext *tc)
7889651SAndreas.Sandberg@ARM.com{
7899651SAndreas.Sandberg@ARM.com    std::string path;
7909651SAndreas.Sandberg@ARM.com
7919651SAndreas.Sandberg@ARM.com    int index = 0;
7929651SAndreas.Sandberg@ARM.com    if (!tc->getMemProxy().tryReadString(path,
7939651SAndreas.Sandberg@ARM.com                process->getSyscallArg(tc, index))) {
7949651SAndreas.Sandberg@ARM.com        return -EFAULT;
7959651SAndreas.Sandberg@ARM.com    }
7969651SAndreas.Sandberg@ARM.com
7979651SAndreas.Sandberg@ARM.com    uint32_t mode = process->getSyscallArg(tc, index);
7989651SAndreas.Sandberg@ARM.com    mode_t hostMode = 0;
7999651SAndreas.Sandberg@ARM.com
8009651SAndreas.Sandberg@ARM.com    // XXX translate mode flags via OS::something???
8019651SAndreas.Sandberg@ARM.com    hostMode = mode;
8029651SAndreas.Sandberg@ARM.com
8039651SAndreas.Sandberg@ARM.com    // Adjust path for current working directory
8049651SAndreas.Sandberg@ARM.com    path = process->fullPath(path);
8059651SAndreas.Sandberg@ARM.com
8069651SAndreas.Sandberg@ARM.com    // do the chmod
8079651SAndreas.Sandberg@ARM.com    int result = chmod(path.c_str(), hostMode);
8089651SAndreas.Sandberg@ARM.com    if (result < 0)
8099651SAndreas.Sandberg@ARM.com        return -errno;
8109651SAndreas.Sandberg@ARM.com
8119652SAndreas.Sandberg@ARM.com    return 0;
8129652SAndreas.Sandberg@ARM.com}
8139652SAndreas.Sandberg@ARM.com
8149652SAndreas.Sandberg@ARM.com
8159652SAndreas.Sandberg@ARM.com/// Target fchmod() handler.
8169652SAndreas.Sandberg@ARM.comtemplate <class OS>
8179652SAndreas.Sandberg@ARM.comSyscallReturn
8189652SAndreas.Sandberg@ARM.comfchmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
8199652SAndreas.Sandberg@ARM.com           ThreadContext *tc)
8209652SAndreas.Sandberg@ARM.com{
8219652SAndreas.Sandberg@ARM.com    int index = 0;
8229652SAndreas.Sandberg@ARM.com    int tgt_fd = process->getSyscallArg(tc, index);
8239652SAndreas.Sandberg@ARM.com    uint32_t mode = process->getSyscallArg(tc, index);
8249652SAndreas.Sandberg@ARM.com
8259652SAndreas.Sandberg@ARM.com    int sim_fd = process->getSimFD(tgt_fd);
8269652SAndreas.Sandberg@ARM.com    if (sim_fd < 0)
8279652SAndreas.Sandberg@ARM.com        return -EBADF;
8289652SAndreas.Sandberg@ARM.com
8299652SAndreas.Sandberg@ARM.com    mode_t hostMode = 0;
8309652SAndreas.Sandberg@ARM.com
8319652SAndreas.Sandberg@ARM.com    // XXX translate mode flags via OS::someting???
8329652SAndreas.Sandberg@ARM.com    hostMode = mode;
8339652SAndreas.Sandberg@ARM.com
8349652SAndreas.Sandberg@ARM.com    // do the fchmod
8359651SAndreas.Sandberg@ARM.com    int result = fchmod(sim_fd, hostMode);
8369651SAndreas.Sandberg@ARM.com    if (result < 0)
8379651SAndreas.Sandberg@ARM.com        return -errno;
8389651SAndreas.Sandberg@ARM.com
8399753Sandreas@sandberg.pp.se    return 0;
8409651SAndreas.Sandberg@ARM.com}
8419753Sandreas@sandberg.pp.se
8429753Sandreas@sandberg.pp.se/// Target mremap() handler.
8439753Sandreas@sandberg.pp.setemplate <class OS>
8449651SAndreas.Sandberg@ARM.comSyscallReturn
8459651SAndreas.Sandberg@ARM.commremapFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc)
8469651SAndreas.Sandberg@ARM.com{
8479651SAndreas.Sandberg@ARM.com    int index = 0;
8489651SAndreas.Sandberg@ARM.com    Addr start = process->getSyscallArg(tc, index);
8499651SAndreas.Sandberg@ARM.com    uint64_t old_length = process->getSyscallArg(tc, index);
8509651SAndreas.Sandberg@ARM.com    uint64_t new_length = process->getSyscallArg(tc, index);
8519651SAndreas.Sandberg@ARM.com    uint64_t flags = process->getSyscallArg(tc, index);
8529753Sandreas@sandberg.pp.se    uint64_t provided_address = 0;
8539651SAndreas.Sandberg@ARM.com    bool use_provided_address = flags & OS::TGT_MREMAP_FIXED;
8549651SAndreas.Sandberg@ARM.com
8559651SAndreas.Sandberg@ARM.com    if (use_provided_address)
8569651SAndreas.Sandberg@ARM.com        provided_address = process->getSyscallArg(tc, index);
8579651SAndreas.Sandberg@ARM.com
8589651SAndreas.Sandberg@ARM.com    if ((start % TheISA::PageBytes != 0) ||
8599651SAndreas.Sandberg@ARM.com        (provided_address % TheISA::PageBytes != 0)) {
8609651SAndreas.Sandberg@ARM.com        warn("mremap failing: arguments not page aligned");
8619651SAndreas.Sandberg@ARM.com        return -EINVAL;
8629651SAndreas.Sandberg@ARM.com    }
8639651SAndreas.Sandberg@ARM.com
8649651SAndreas.Sandberg@ARM.com    new_length = roundUp(new_length, TheISA::PageBytes);
8659651SAndreas.Sandberg@ARM.com
8669651SAndreas.Sandberg@ARM.com    if (new_length > old_length) {
8679651SAndreas.Sandberg@ARM.com        if ((start + old_length) == process->mmap_end &&
8689651SAndreas.Sandberg@ARM.com            (!use_provided_address || provided_address == start)) {
8699651SAndreas.Sandberg@ARM.com            uint64_t diff = new_length - old_length;
8709651SAndreas.Sandberg@ARM.com            process->allocateMem(process->mmap_end, diff);
8719651SAndreas.Sandberg@ARM.com            process->mmap_end += diff;
8729753Sandreas@sandberg.pp.se            return start;
8739651SAndreas.Sandberg@ARM.com        } else {
8749651SAndreas.Sandberg@ARM.com            if (!use_provided_address && !(flags & OS::TGT_MREMAP_MAYMOVE)) {
8759651SAndreas.Sandberg@ARM.com                warn("can't remap here and MREMAP_MAYMOVE flag not set\n");
8769651SAndreas.Sandberg@ARM.com                return -ENOMEM;
8779651SAndreas.Sandberg@ARM.com            } else {
8789651SAndreas.Sandberg@ARM.com                uint64_t new_start = use_provided_address ?
8799651SAndreas.Sandberg@ARM.com                    provided_address : process->mmap_end;
8809651SAndreas.Sandberg@ARM.com                process->pTable->remap(start, old_length, new_start);
8819651SAndreas.Sandberg@ARM.com                warn("mremapping to new vaddr %08p-%08p, adding %d\n",
8829651SAndreas.Sandberg@ARM.com                     new_start, new_start + new_length,
8839651SAndreas.Sandberg@ARM.com                     new_length - old_length);
8849651SAndreas.Sandberg@ARM.com                // add on the remaining unallocated pages
8859651SAndreas.Sandberg@ARM.com                process->allocateMem(new_start + old_length,
8869651SAndreas.Sandberg@ARM.com                                     new_length - old_length,
8879651SAndreas.Sandberg@ARM.com                                     use_provided_address /* clobber */);
8889651SAndreas.Sandberg@ARM.com                if (!use_provided_address)
8899651SAndreas.Sandberg@ARM.com                    process->mmap_end += new_length;
8909651SAndreas.Sandberg@ARM.com                if (use_provided_address &&
8919651SAndreas.Sandberg@ARM.com                    new_start + new_length > process->mmap_end) {
8929651SAndreas.Sandberg@ARM.com                    // something fishy going on here, at least notify the user
8939651SAndreas.Sandberg@ARM.com                    // @todo: increase mmap_end?
8949651SAndreas.Sandberg@ARM.com                    warn("mmap region limit exceeded with MREMAP_FIXED\n");
8959651SAndreas.Sandberg@ARM.com                }
8969651SAndreas.Sandberg@ARM.com                warn("returning %08p as start\n", new_start);
8979651SAndreas.Sandberg@ARM.com                return new_start;
8989689Sandreas@sandberg.pp.se            }
8999651SAndreas.Sandberg@ARM.com        }
9009651SAndreas.Sandberg@ARM.com    } else {
9019651SAndreas.Sandberg@ARM.com        if (use_provided_address && provided_address != start)
9029651SAndreas.Sandberg@ARM.com            process->pTable->remap(start, new_length, provided_address);
9039651SAndreas.Sandberg@ARM.com        process->pTable->unmap(start + new_length, old_length - new_length);
9049651SAndreas.Sandberg@ARM.com        return use_provided_address ? provided_address : start;
9059651SAndreas.Sandberg@ARM.com    }
9069651SAndreas.Sandberg@ARM.com}
9079651SAndreas.Sandberg@ARM.com
9089651SAndreas.Sandberg@ARM.com/// Target stat() handler.
9099651SAndreas.Sandberg@ARM.comtemplate <class OS>
9109651SAndreas.Sandberg@ARM.comSyscallReturn
9119651SAndreas.Sandberg@ARM.comstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
9129651SAndreas.Sandberg@ARM.com         ThreadContext *tc)
9139651SAndreas.Sandberg@ARM.com{
9149651SAndreas.Sandberg@ARM.com    std::string path;
9159651SAndreas.Sandberg@ARM.com
9169651SAndreas.Sandberg@ARM.com    int index = 0;
9179651SAndreas.Sandberg@ARM.com    if (!tc->getMemProxy().tryReadString(path,
9189651SAndreas.Sandberg@ARM.com                process->getSyscallArg(tc, index))) {
9199651SAndreas.Sandberg@ARM.com        return -EFAULT;
9209651SAndreas.Sandberg@ARM.com    }
9219651SAndreas.Sandberg@ARM.com    Addr bufPtr = process->getSyscallArg(tc, index);
9229651SAndreas.Sandberg@ARM.com
9239651SAndreas.Sandberg@ARM.com    // Adjust path for current working directory
9249651SAndreas.Sandberg@ARM.com    path = process->fullPath(path);
9259651SAndreas.Sandberg@ARM.com
9269651SAndreas.Sandberg@ARM.com    struct stat hostBuf;
9279651SAndreas.Sandberg@ARM.com    int result = stat(path.c_str(), &hostBuf);
9289689Sandreas@sandberg.pp.se
9299651SAndreas.Sandberg@ARM.com    if (result < 0)
9309651SAndreas.Sandberg@ARM.com        return -errno;
9319651SAndreas.Sandberg@ARM.com
9329651SAndreas.Sandberg@ARM.com    copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
9339651SAndreas.Sandberg@ARM.com
9349651SAndreas.Sandberg@ARM.com    return 0;
9359651SAndreas.Sandberg@ARM.com}
9369689Sandreas@sandberg.pp.se
9379651SAndreas.Sandberg@ARM.com
9389651SAndreas.Sandberg@ARM.com/// Target stat64() handler.
9399651SAndreas.Sandberg@ARM.comtemplate <class OS>
9409651SAndreas.Sandberg@ARM.comSyscallReturn
9419651SAndreas.Sandberg@ARM.comstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process,
9429651SAndreas.Sandberg@ARM.com           ThreadContext *tc)
9439651SAndreas.Sandberg@ARM.com{
9449651SAndreas.Sandberg@ARM.com    std::string path;
9459689Sandreas@sandberg.pp.se
9469651SAndreas.Sandberg@ARM.com    int index = 0;
9479651SAndreas.Sandberg@ARM.com    if (!tc->getMemProxy().tryReadString(path,
9489651SAndreas.Sandberg@ARM.com                process->getSyscallArg(tc, index)))
9499651SAndreas.Sandberg@ARM.com        return -EFAULT;
9509651SAndreas.Sandberg@ARM.com    Addr bufPtr = process->getSyscallArg(tc, index);
9519651SAndreas.Sandberg@ARM.com
9529651SAndreas.Sandberg@ARM.com    // Adjust path for current working directory
9539760Sandreas@sandberg.pp.se    path = process->fullPath(path);
9549760Sandreas@sandberg.pp.se
9559760Sandreas@sandberg.pp.se#if NO_STAT64
9569682Sandreas@sandberg.pp.se    struct stat  hostBuf;
9579760Sandreas@sandberg.pp.se    int result = stat(path.c_str(), &hostBuf);
9589760Sandreas@sandberg.pp.se#else
9599760Sandreas@sandberg.pp.se    struct stat64 hostBuf;
9609760Sandreas@sandberg.pp.se    int result = stat64(path.c_str(), &hostBuf);
9619760Sandreas@sandberg.pp.se#endif
9629760Sandreas@sandberg.pp.se
9639760Sandreas@sandberg.pp.se    if (result < 0)
9649760Sandreas@sandberg.pp.se        return -errno;
9659760Sandreas@sandberg.pp.se
9669651SAndreas.Sandberg@ARM.com    copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
9679651SAndreas.Sandberg@ARM.com
9689651SAndreas.Sandberg@ARM.com    return 0;
9699651SAndreas.Sandberg@ARM.com}
9709760Sandreas@sandberg.pp.se
9719760Sandreas@sandberg.pp.se
9729882Sandreas@sandberg.pp.se/// Target fstatat64() handler.
9739882Sandreas@sandberg.pp.setemplate <class OS>
9749882Sandreas@sandberg.pp.seSyscallReturn
9759882Sandreas@sandberg.pp.sefstatat64Func(SyscallDesc *desc, int callnum, LiveProcess *process,
9769760Sandreas@sandberg.pp.se              ThreadContext *tc)
9779760Sandreas@sandberg.pp.se{
9789760Sandreas@sandberg.pp.se    int index = 0;
9799651SAndreas.Sandberg@ARM.com    int dirfd = process->getSyscallArg(tc, index);
9809651SAndreas.Sandberg@ARM.com    if (dirfd != OS::TGT_AT_FDCWD)
9819753Sandreas@sandberg.pp.se        warn("fstatat64: first argument not AT_FDCWD; unlikely to work");
9829753Sandreas@sandberg.pp.se
9839753Sandreas@sandberg.pp.se    std::string path;
9849753Sandreas@sandberg.pp.se    if (!tc->getMemProxy().tryReadString(path,
9859753Sandreas@sandberg.pp.se                process->getSyscallArg(tc, index)))
9869753Sandreas@sandberg.pp.se        return -EFAULT;
9879753Sandreas@sandberg.pp.se    Addr bufPtr = process->getSyscallArg(tc, index);
9889753Sandreas@sandberg.pp.se
9899753Sandreas@sandberg.pp.se    // Adjust path for current working directory
9909753Sandreas@sandberg.pp.se    path = process->fullPath(path);
9919753Sandreas@sandberg.pp.se
9929753Sandreas@sandberg.pp.se#if NO_STAT64
9939753Sandreas@sandberg.pp.se    struct stat  hostBuf;
9949753Sandreas@sandberg.pp.se    int result = stat(path.c_str(), &hostBuf);
9959753Sandreas@sandberg.pp.se#else
9969753Sandreas@sandberg.pp.se    struct stat64 hostBuf;
9979753Sandreas@sandberg.pp.se    int result = stat64(path.c_str(), &hostBuf);
9989753Sandreas@sandberg.pp.se#endif
9999753Sandreas@sandberg.pp.se
10009753Sandreas@sandberg.pp.se    if (result < 0)
10019753Sandreas@sandberg.pp.se        return -errno;
10029651SAndreas.Sandberg@ARM.com
10039651SAndreas.Sandberg@ARM.com    copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
10049651SAndreas.Sandberg@ARM.com
10059651SAndreas.Sandberg@ARM.com    return 0;
10069651SAndreas.Sandberg@ARM.com}
10079651SAndreas.Sandberg@ARM.com
10089651SAndreas.Sandberg@ARM.com
10099651SAndreas.Sandberg@ARM.com/// Target fstat64() handler.
10109651SAndreas.Sandberg@ARM.comtemplate <class OS>
10119651SAndreas.Sandberg@ARM.comSyscallReturn
10129651SAndreas.Sandberg@ARM.comfstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process,
10139651SAndreas.Sandberg@ARM.com            ThreadContext *tc)
10149651SAndreas.Sandberg@ARM.com{
10159651SAndreas.Sandberg@ARM.com    int index = 0;
10169651SAndreas.Sandberg@ARM.com    int tgt_fd = process->getSyscallArg(tc, index);
10179651SAndreas.Sandberg@ARM.com    Addr bufPtr = process->getSyscallArg(tc, index);
10189651SAndreas.Sandberg@ARM.com
10199651SAndreas.Sandberg@ARM.com    int sim_fd = process->getSimFD(tgt_fd);
10209651SAndreas.Sandberg@ARM.com    if (sim_fd < 0)
10219651SAndreas.Sandberg@ARM.com        return -EBADF;
10229651SAndreas.Sandberg@ARM.com
10239651SAndreas.Sandberg@ARM.com#if NO_STAT64
10249651SAndreas.Sandberg@ARM.com    struct stat  hostBuf;
10259651SAndreas.Sandberg@ARM.com    int result = fstat(sim_fd, &hostBuf);
10269651SAndreas.Sandberg@ARM.com#else
10279651SAndreas.Sandberg@ARM.com    struct stat64  hostBuf;
10289651SAndreas.Sandberg@ARM.com    int result = fstat64(sim_fd, &hostBuf);
10299651SAndreas.Sandberg@ARM.com#endif
10309651SAndreas.Sandberg@ARM.com
10319651SAndreas.Sandberg@ARM.com    if (result < 0)
10329651SAndreas.Sandberg@ARM.com        return -errno;
10339651SAndreas.Sandberg@ARM.com
10349651SAndreas.Sandberg@ARM.com    copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (sim_fd == 1));
10359651SAndreas.Sandberg@ARM.com
10369651SAndreas.Sandberg@ARM.com    return 0;
10379651SAndreas.Sandberg@ARM.com}
10389651SAndreas.Sandberg@ARM.com
10399651SAndreas.Sandberg@ARM.com
10409651SAndreas.Sandberg@ARM.com/// Target lstat() handler.
10419651SAndreas.Sandberg@ARM.comtemplate <class OS>
10429651SAndreas.Sandberg@ARM.comSyscallReturn
10439651SAndreas.Sandberg@ARM.comlstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
10449651SAndreas.Sandberg@ARM.com          ThreadContext *tc)
10459651SAndreas.Sandberg@ARM.com{
10469651SAndreas.Sandberg@ARM.com    std::string path;
10479651SAndreas.Sandberg@ARM.com
10489753Sandreas@sandberg.pp.se    int index = 0;
10499753Sandreas@sandberg.pp.se    if (!tc->getMemProxy().tryReadString(path,
10509753Sandreas@sandberg.pp.se                process->getSyscallArg(tc, index))) {
10519753Sandreas@sandberg.pp.se        return -EFAULT;
10529753Sandreas@sandberg.pp.se    }
10539753Sandreas@sandberg.pp.se    Addr bufPtr = process->getSyscallArg(tc, index);
10549753Sandreas@sandberg.pp.se
10559753Sandreas@sandberg.pp.se    // Adjust path for current working directory
10569753Sandreas@sandberg.pp.se    path = process->fullPath(path);
10579753Sandreas@sandberg.pp.se
10589753Sandreas@sandberg.pp.se    struct stat hostBuf;
10599753Sandreas@sandberg.pp.se    int result = lstat(path.c_str(), &hostBuf);
10609753Sandreas@sandberg.pp.se
10619753Sandreas@sandberg.pp.se    if (result < 0)
10629753Sandreas@sandberg.pp.se        return -errno;
10639753Sandreas@sandberg.pp.se
10649753Sandreas@sandberg.pp.se    copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
10659753Sandreas@sandberg.pp.se
10669753Sandreas@sandberg.pp.se    return 0;
10679753Sandreas@sandberg.pp.se}
10689753Sandreas@sandberg.pp.se
10699753Sandreas@sandberg.pp.se/// Target lstat64() handler.
10709753Sandreas@sandberg.pp.setemplate <class OS>
10719753Sandreas@sandberg.pp.seSyscallReturn
10729753Sandreas@sandberg.pp.selstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process,
10739753Sandreas@sandberg.pp.se            ThreadContext *tc)
10749753Sandreas@sandberg.pp.se{
10759753Sandreas@sandberg.pp.se    std::string path;
10769753Sandreas@sandberg.pp.se
10779753Sandreas@sandberg.pp.se    int index = 0;
10789753Sandreas@sandberg.pp.se    if (!tc->getMemProxy().tryReadString(path,
10799753Sandreas@sandberg.pp.se                process->getSyscallArg(tc, index))) {
10809753Sandreas@sandberg.pp.se        return -EFAULT;
10819753Sandreas@sandberg.pp.se    }
10829753Sandreas@sandberg.pp.se    Addr bufPtr = process->getSyscallArg(tc, index);
10839753Sandreas@sandberg.pp.se
10849753Sandreas@sandberg.pp.se    // Adjust path for current working directory
10859753Sandreas@sandberg.pp.se    path = process->fullPath(path);
10869753Sandreas@sandberg.pp.se
10879753Sandreas@sandberg.pp.se#if NO_STAT64
10889753Sandreas@sandberg.pp.se    struct stat hostBuf;
10899753Sandreas@sandberg.pp.se    int result = lstat(path.c_str(), &hostBuf);
10909753Sandreas@sandberg.pp.se#else
10919753Sandreas@sandberg.pp.se    struct stat64 hostBuf;
10929651SAndreas.Sandberg@ARM.com    int result = lstat64(path.c_str(), &hostBuf);
10939651SAndreas.Sandberg@ARM.com#endif
10949651SAndreas.Sandberg@ARM.com
10959651SAndreas.Sandberg@ARM.com    if (result < 0)
10969651SAndreas.Sandberg@ARM.com        return -errno;
10979651SAndreas.Sandberg@ARM.com
10989651SAndreas.Sandberg@ARM.com    copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
10999651SAndreas.Sandberg@ARM.com
11009651SAndreas.Sandberg@ARM.com    return 0;
11019651SAndreas.Sandberg@ARM.com}
11029655SAndreas.Sandberg@ARM.com
11039655SAndreas.Sandberg@ARM.com/// Target fstat() handler.
11049655SAndreas.Sandberg@ARM.comtemplate <class OS>
11059655SAndreas.Sandberg@ARM.comSyscallReturn
11069655SAndreas.Sandberg@ARM.comfstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
11079655SAndreas.Sandberg@ARM.com          ThreadContext *tc)
11089655SAndreas.Sandberg@ARM.com{
11099655SAndreas.Sandberg@ARM.com    int index = 0;
11109655SAndreas.Sandberg@ARM.com    int tgt_fd = process->getSyscallArg(tc, index);
11119655SAndreas.Sandberg@ARM.com    Addr bufPtr = process->getSyscallArg(tc, index);
11129655SAndreas.Sandberg@ARM.com
11139651SAndreas.Sandberg@ARM.com    DPRINTF_SYSCALL(Verbose, "fstat(%d, ...)\n", tgt_fd);
11149651SAndreas.Sandberg@ARM.com
11159651SAndreas.Sandberg@ARM.com    int sim_fd = process->getSimFD(tgt_fd);
11169651SAndreas.Sandberg@ARM.com    if (sim_fd < 0)
11179651SAndreas.Sandberg@ARM.com        return -EBADF;
11189651SAndreas.Sandberg@ARM.com
11199651SAndreas.Sandberg@ARM.com    struct stat hostBuf;
11209651SAndreas.Sandberg@ARM.com    int result = fstat(sim_fd, &hostBuf);
11219651SAndreas.Sandberg@ARM.com
11229651SAndreas.Sandberg@ARM.com    if (result < 0)
11239753Sandreas@sandberg.pp.se        return -errno;
11249753Sandreas@sandberg.pp.se
11259753Sandreas@sandberg.pp.se    copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (sim_fd == 1));
11269753Sandreas@sandberg.pp.se
11279753Sandreas@sandberg.pp.se    return 0;
11289753Sandreas@sandberg.pp.se}
11299753Sandreas@sandberg.pp.se
11309753Sandreas@sandberg.pp.se
11319753Sandreas@sandberg.pp.se/// Target statfs() handler.
11329753Sandreas@sandberg.pp.setemplate <class OS>
11339753Sandreas@sandberg.pp.seSyscallReturn
11349753Sandreas@sandberg.pp.sestatfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
11359753Sandreas@sandberg.pp.se           ThreadContext *tc)
11369753Sandreas@sandberg.pp.se{
11379753Sandreas@sandberg.pp.se    std::string path;
11389753Sandreas@sandberg.pp.se
11399753Sandreas@sandberg.pp.se    int index = 0;
11409753Sandreas@sandberg.pp.se    if (!tc->getMemProxy().tryReadString(path,
11419753Sandreas@sandberg.pp.se                process->getSyscallArg(tc, index))) {
11429753Sandreas@sandberg.pp.se        return -EFAULT;
11439753Sandreas@sandberg.pp.se    }
11449753Sandreas@sandberg.pp.se    Addr bufPtr = process->getSyscallArg(tc, index);
11459753Sandreas@sandberg.pp.se
11469753Sandreas@sandberg.pp.se    // Adjust path for current working directory
11479753Sandreas@sandberg.pp.se    path = process->fullPath(path);
11489753Sandreas@sandberg.pp.se
11499753Sandreas@sandberg.pp.se    struct statfs hostBuf;
11509753Sandreas@sandberg.pp.se    int result = statfs(path.c_str(), &hostBuf);
11519753Sandreas@sandberg.pp.se
11529753Sandreas@sandberg.pp.se    if (result < 0)
11539753Sandreas@sandberg.pp.se        return -errno;
11549753Sandreas@sandberg.pp.se
11559753Sandreas@sandberg.pp.se    OS::copyOutStatfsBuf(tc->getMemProxy(), bufPtr, &hostBuf);
1156
1157    return 0;
1158}
1159
1160
1161/// Target fstatfs() handler.
1162template <class OS>
1163SyscallReturn
1164fstatfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1165            ThreadContext *tc)
1166{
1167    int index = 0;
1168    int tgt_fd = process->getSyscallArg(tc, index);
1169    Addr bufPtr = process->getSyscallArg(tc, index);
1170
1171    int sim_fd = process->getSimFD(tgt_fd);
1172    if (sim_fd < 0)
1173        return -EBADF;
1174
1175    struct statfs hostBuf;
1176    int result = fstatfs(sim_fd, &hostBuf);
1177
1178    if (result < 0)
1179        return -errno;
1180
1181    OS::copyOutStatfsBuf(tc->getMemProxy(), bufPtr, &hostBuf);
1182
1183    return 0;
1184}
1185
1186
1187/// Target writev() handler.
1188template <class OS>
1189SyscallReturn
1190writevFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1191           ThreadContext *tc)
1192{
1193    int index = 0;
1194    int tgt_fd = process->getSyscallArg(tc, index);
1195
1196    int sim_fd = process->getSimFD(tgt_fd);
1197    if (sim_fd < 0)
1198        return -EBADF;
1199
1200    SETranslatingPortProxy &p = tc->getMemProxy();
1201    uint64_t tiov_base = process->getSyscallArg(tc, index);
1202    size_t count = process->getSyscallArg(tc, index);
1203    struct iovec hiov[count];
1204    for (size_t i = 0; i < count; ++i) {
1205        typename OS::tgt_iovec tiov;
1206
1207        p.readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec),
1208                   (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec));
1209        hiov[i].iov_len = TheISA::gtoh(tiov.iov_len);
1210        hiov[i].iov_base = new char [hiov[i].iov_len];
1211        p.readBlob(TheISA::gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base,
1212                   hiov[i].iov_len);
1213    }
1214
1215    int result = writev(sim_fd, hiov, count);
1216
1217    for (size_t i = 0; i < count; ++i)
1218        delete [] (char *)hiov[i].iov_base;
1219
1220    if (result < 0)
1221        return -errno;
1222
1223    return result;
1224}
1225
1226
1227/// Target mmap() handler.
1228template <class OS>
1229SyscallReturn
1230mmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
1231{
1232    int index = 0;
1233    Addr start = p->getSyscallArg(tc, index);
1234    uint64_t length = p->getSyscallArg(tc, index);
1235    int prot = p->getSyscallArg(tc, index);
1236    int tgt_flags = p->getSyscallArg(tc, index);
1237    int tgt_fd = p->getSyscallArg(tc, index);
1238    int offset = p->getSyscallArg(tc, index);
1239
1240    DPRINTF_SYSCALL(Verbose, "mmap(0x%x, len %d, prot %d, flags %d, fd %d, "
1241                    "offs %d)\n", start, length, prot, tgt_flags, tgt_fd,
1242                    offset);
1243
1244    if (start & (TheISA::PageBytes - 1) ||
1245        offset & (TheISA::PageBytes - 1) ||
1246        (tgt_flags & OS::TGT_MAP_PRIVATE &&
1247         tgt_flags & OS::TGT_MAP_SHARED) ||
1248        (!(tgt_flags & OS::TGT_MAP_PRIVATE) &&
1249         !(tgt_flags & OS::TGT_MAP_SHARED)) ||
1250        !length) {
1251        return -EINVAL;
1252    }
1253
1254    if ((prot & PROT_WRITE) && (tgt_flags & OS::TGT_MAP_SHARED)) {
1255        // With shared mmaps, there are two cases to consider:
1256        // 1) anonymous: writes should modify the mapping and this should be
1257        // visible to observers who share the mapping. Currently, it's
1258        // difficult to update the shared mapping because there's no
1259        // structure which maintains information about the which virtual
1260        // memory areas are shared. If that structure existed, it would be
1261        // possible to make the translations point to the same frames.
1262        // 2) file-backed: writes should modify the mapping and the file
1263        // which is backed by the mapping. The shared mapping problem is the
1264        // same as what was mentioned about the anonymous mappings. For
1265        // file-backed mappings, the writes to the file are difficult
1266        // because it requires syncing what the mapping holds with the file
1267        // that resides on the host system. So, any write on a real system
1268        // would cause the change to be propagated to the file mapping at
1269        // some point in the future (the inode is tracked along with the
1270        // mapping). This isn't guaranteed to always happen, but it usually
1271        // works well enough. The guarantee is provided by the msync system
1272        // call. We could force the change through with shared mappings with
1273        // a call to msync, but that again would require more information
1274        // than we currently maintain.
1275        warn("mmap: writing to shared mmap region is currently "
1276             "unsupported. The write succeeds on the target, but it "
1277             "will not be propagated to the host or shared mappings");
1278    }
1279
1280    length = roundUp(length, TheISA::PageBytes);
1281
1282    int sim_fd = -1;
1283    uint8_t *pmap = nullptr;
1284    if (!(tgt_flags & OS::TGT_MAP_ANONYMOUS)) {
1285        sim_fd = p->getSimFD(tgt_fd);
1286        if (sim_fd < 0)
1287            return -EBADF;
1288
1289        pmap = (decltype(pmap))mmap(NULL, length, PROT_READ, MAP_PRIVATE,
1290                                    sim_fd, offset);
1291
1292        if (pmap == (decltype(pmap))-1) {
1293            warn("mmap: failed to map file into host address space");
1294            return -errno;
1295        }
1296    }
1297
1298    // Extend global mmap region if necessary. Note that we ignore the
1299    // start address unless MAP_FIXED is specified.
1300    if (!(tgt_flags & OS::TGT_MAP_FIXED)) {
1301        start = (OS::mmapGrowsDown()) ? p->mmap_end - length : p->mmap_end;
1302        p->mmap_end = (OS::mmapGrowsDown()) ? start : p->mmap_end + length;
1303    }
1304
1305    DPRINTF_SYSCALL(Verbose, " mmap range is 0x%x - 0x%x\n",
1306                    start, start + length - 1);
1307
1308    // We only allow mappings to overwrite existing mappings if
1309    // TGT_MAP_FIXED is set. Otherwise it shouldn't be a problem
1310    // because we ignore the start hint if TGT_MAP_FIXED is not set.
1311    int clobber = tgt_flags & OS::TGT_MAP_FIXED;
1312    if (clobber) {
1313        for (auto tc : p->system->threadContexts) {
1314            // If we might be overwriting old mappings, we need to
1315            // invalidate potentially stale mappings out of the TLBs.
1316            tc->getDTBPtr()->flushAll();
1317            tc->getITBPtr()->flushAll();
1318        }
1319    }
1320
1321    // Allocate physical memory and map it in. If the page table is already
1322    // mapped and clobber is not set, the simulator will issue throw a
1323    // fatal and bail out of the simulation.
1324    p->allocateMem(start, length, clobber);
1325
1326    // Transfer content into target address space.
1327    SETranslatingPortProxy &tp = tc->getMemProxy();
1328    if (tgt_flags & OS::TGT_MAP_ANONYMOUS) {
1329        // In general, we should zero the mapped area for anonymous mappings,
1330        // with something like:
1331        //     tp.memsetBlob(start, 0, length);
1332        // However, given that we don't support sparse mappings, and
1333        // some applications can map a couple of gigabytes of space
1334        // (intending sparse usage), that can get painfully expensive.
1335        // Fortunately, since we don't properly implement munmap either,
1336        // there's no danger of remapping used memory, so for now all
1337        // newly mapped memory should already be zeroed so we can skip it.
1338    } else {
1339        // It is possible to mmap an area larger than a file, however
1340        // accessing unmapped portions the system triggers a "Bus error"
1341        // on the host. We must know when to stop copying the file from
1342        // the host into the target address space.
1343        struct stat file_stat;
1344        if (fstat(sim_fd, &file_stat) > 0)
1345            fatal("mmap: cannot stat file");
1346
1347        // Copy the portion of the file that is resident. This requires
1348        // checking both the mmap size and the filesize that we are
1349        // trying to mmap into this space; the mmap size also depends
1350        // on the specified offset into the file.
1351        uint64_t size = std::min((uint64_t)file_stat.st_size - offset,
1352                                 length);
1353        tp.writeBlob(start, pmap, size);
1354
1355        // Cleanup the mmap region before exiting this function.
1356        munmap(pmap, length);
1357
1358        // Note that we do not zero out the remainder of the mapping. This
1359        // is done by a real system, but it probably will not affect
1360        // execution (hopefully).
1361    }
1362
1363    return start;
1364}
1365
1366/// Target getrlimit() handler.
1367template <class OS>
1368SyscallReturn
1369getrlimitFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1370        ThreadContext *tc)
1371{
1372    int index = 0;
1373    unsigned resource = process->getSyscallArg(tc, index);
1374    TypedBufferArg<typename OS::rlimit> rlp(process->getSyscallArg(tc, index));
1375
1376    switch (resource) {
1377        case OS::TGT_RLIMIT_STACK:
1378            // max stack size in bytes: make up a number (8MB for now)
1379            rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024;
1380            rlp->rlim_cur = TheISA::htog(rlp->rlim_cur);
1381            rlp->rlim_max = TheISA::htog(rlp->rlim_max);
1382            break;
1383
1384        case OS::TGT_RLIMIT_DATA:
1385            // max data segment size in bytes: make up a number
1386            rlp->rlim_cur = rlp->rlim_max = 256 * 1024 * 1024;
1387            rlp->rlim_cur = TheISA::htog(rlp->rlim_cur);
1388            rlp->rlim_max = TheISA::htog(rlp->rlim_max);
1389            break;
1390
1391        default:
1392            warn("getrlimit: unimplemented resource %d", resource);
1393            return -EINVAL;
1394            break;
1395    }
1396
1397    rlp.copyOut(tc->getMemProxy());
1398    return 0;
1399}
1400
1401/// Target clock_gettime() function.
1402template <class OS>
1403SyscallReturn
1404clock_gettimeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
1405{
1406    int index = 1;
1407    //int clk_id = p->getSyscallArg(tc, index);
1408    TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index));
1409
1410    getElapsedTimeNano(tp->tv_sec, tp->tv_nsec);
1411    tp->tv_sec += seconds_since_epoch;
1412    tp->tv_sec = TheISA::htog(tp->tv_sec);
1413    tp->tv_nsec = TheISA::htog(tp->tv_nsec);
1414
1415    tp.copyOut(tc->getMemProxy());
1416
1417    return 0;
1418}
1419
1420/// Target clock_getres() function.
1421template <class OS>
1422SyscallReturn
1423clock_getresFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
1424{
1425    int index = 1;
1426    TypedBufferArg<typename OS::timespec> tp(p->getSyscallArg(tc, index));
1427
1428    // Set resolution at ns, which is what clock_gettime() returns
1429    tp->tv_sec = 0;
1430    tp->tv_nsec = 1;
1431
1432    tp.copyOut(tc->getMemProxy());
1433
1434    return 0;
1435}
1436
1437/// Target gettimeofday() handler.
1438template <class OS>
1439SyscallReturn
1440gettimeofdayFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1441        ThreadContext *tc)
1442{
1443    int index = 0;
1444    TypedBufferArg<typename OS::timeval> tp(process->getSyscallArg(tc, index));
1445
1446    getElapsedTimeMicro(tp->tv_sec, tp->tv_usec);
1447    tp->tv_sec += seconds_since_epoch;
1448    tp->tv_sec = TheISA::htog(tp->tv_sec);
1449    tp->tv_usec = TheISA::htog(tp->tv_usec);
1450
1451    tp.copyOut(tc->getMemProxy());
1452
1453    return 0;
1454}
1455
1456
1457/// Target utimes() handler.
1458template <class OS>
1459SyscallReturn
1460utimesFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1461           ThreadContext *tc)
1462{
1463    std::string path;
1464
1465    int index = 0;
1466    if (!tc->getMemProxy().tryReadString(path,
1467                process->getSyscallArg(tc, index))) {
1468        return -EFAULT;
1469    }
1470
1471    TypedBufferArg<typename OS::timeval [2]>
1472        tp(process->getSyscallArg(tc, index));
1473    tp.copyIn(tc->getMemProxy());
1474
1475    struct timeval hostTimeval[2];
1476    for (int i = 0; i < 2; ++i)
1477    {
1478        hostTimeval[i].tv_sec = TheISA::gtoh((*tp)[i].tv_sec);
1479        hostTimeval[i].tv_usec = TheISA::gtoh((*tp)[i].tv_usec);
1480    }
1481
1482    // Adjust path for current working directory
1483    path = process->fullPath(path);
1484
1485    int result = utimes(path.c_str(), hostTimeval);
1486
1487    if (result < 0)
1488        return -errno;
1489
1490    return 0;
1491}
1492/// Target getrusage() function.
1493template <class OS>
1494SyscallReturn
1495getrusageFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1496              ThreadContext *tc)
1497{
1498    int index = 0;
1499    int who = process->getSyscallArg(tc, index); // THREAD, SELF, or CHILDREN
1500    TypedBufferArg<typename OS::rusage> rup(process->getSyscallArg(tc, index));
1501
1502    rup->ru_utime.tv_sec = 0;
1503    rup->ru_utime.tv_usec = 0;
1504    rup->ru_stime.tv_sec = 0;
1505    rup->ru_stime.tv_usec = 0;
1506    rup->ru_maxrss = 0;
1507    rup->ru_ixrss = 0;
1508    rup->ru_idrss = 0;
1509    rup->ru_isrss = 0;
1510    rup->ru_minflt = 0;
1511    rup->ru_majflt = 0;
1512    rup->ru_nswap = 0;
1513    rup->ru_inblock = 0;
1514    rup->ru_oublock = 0;
1515    rup->ru_msgsnd = 0;
1516    rup->ru_msgrcv = 0;
1517    rup->ru_nsignals = 0;
1518    rup->ru_nvcsw = 0;
1519    rup->ru_nivcsw = 0;
1520
1521    switch (who) {
1522      case OS::TGT_RUSAGE_SELF:
1523        getElapsedTimeMicro(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec);
1524        rup->ru_utime.tv_sec = TheISA::htog(rup->ru_utime.tv_sec);
1525        rup->ru_utime.tv_usec = TheISA::htog(rup->ru_utime.tv_usec);
1526        break;
1527
1528      case OS::TGT_RUSAGE_CHILDREN:
1529        // do nothing.  We have no child processes, so they take no time.
1530        break;
1531
1532      default:
1533        // don't really handle THREAD or CHILDREN, but just warn and
1534        // plow ahead
1535        warn("getrusage() only supports RUSAGE_SELF.  Parameter %d ignored.",
1536             who);
1537    }
1538
1539    rup.copyOut(tc->getMemProxy());
1540
1541    return 0;
1542}
1543
1544/// Target times() function.
1545template <class OS>
1546SyscallReturn
1547timesFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1548           ThreadContext *tc)
1549{
1550    int index = 0;
1551    TypedBufferArg<typename OS::tms> bufp(process->getSyscallArg(tc, index));
1552
1553    // Fill in the time structure (in clocks)
1554    int64_t clocks = curTick() * OS::M5_SC_CLK_TCK / SimClock::Int::s;
1555    bufp->tms_utime = clocks;
1556    bufp->tms_stime = 0;
1557    bufp->tms_cutime = 0;
1558    bufp->tms_cstime = 0;
1559
1560    // Convert to host endianness
1561    bufp->tms_utime = TheISA::htog(bufp->tms_utime);
1562
1563    // Write back
1564    bufp.copyOut(tc->getMemProxy());
1565
1566    // Return clock ticks since system boot
1567    return clocks;
1568}
1569
1570/// Target time() function.
1571template <class OS>
1572SyscallReturn
1573timeFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1574           ThreadContext *tc)
1575{
1576    typename OS::time_t sec, usec;
1577    getElapsedTimeMicro(sec, usec);
1578    sec += seconds_since_epoch;
1579
1580    int index = 0;
1581    Addr taddr = (Addr)process->getSyscallArg(tc, index);
1582    if (taddr != 0) {
1583        typename OS::time_t t = sec;
1584        t = TheISA::htog(t);
1585        SETranslatingPortProxy &p = tc->getMemProxy();
1586        p.writeBlob(taddr, (uint8_t*)&t, (int)sizeof(typename OS::time_t));
1587    }
1588    return sec;
1589}
1590
1591
1592#endif // __SIM_SYSCALL_EMUL_HH__
1593