syscall_emul.hh revision 3113
19651SAndreas.Sandberg@ARM.com/*
210858Sandreas.sandberg@arm.com * Copyright (c) 2003-2005 The Regents of The University of Michigan
39651SAndreas.Sandberg@ARM.com * All rights reserved.
49651SAndreas.Sandberg@ARM.com *
59651SAndreas.Sandberg@ARM.com * Redistribution and use in source and binary forms, with or without
69651SAndreas.Sandberg@ARM.com * modification, are permitted provided that the following conditions are
79651SAndreas.Sandberg@ARM.com * met: redistributions of source code must retain the above copyright
89651SAndreas.Sandberg@ARM.com * notice, this list of conditions and the following disclaimer;
99651SAndreas.Sandberg@ARM.com * redistributions in binary form must reproduce the above copyright
109651SAndreas.Sandberg@ARM.com * notice, this list of conditions and the following disclaimer in the
119651SAndreas.Sandberg@ARM.com * documentation and/or other materials provided with the distribution;
129651SAndreas.Sandberg@ARM.com * neither the name of the copyright holders nor the names of its
139651SAndreas.Sandberg@ARM.com * contributors may be used to endorse or promote products derived from
149651SAndreas.Sandberg@ARM.com * this software without specific prior written permission.
159651SAndreas.Sandberg@ARM.com *
169651SAndreas.Sandberg@ARM.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
179651SAndreas.Sandberg@ARM.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
189651SAndreas.Sandberg@ARM.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
199651SAndreas.Sandberg@ARM.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
209651SAndreas.Sandberg@ARM.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
219651SAndreas.Sandberg@ARM.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
229651SAndreas.Sandberg@ARM.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
239651SAndreas.Sandberg@ARM.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
249651SAndreas.Sandberg@ARM.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
259651SAndreas.Sandberg@ARM.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
269651SAndreas.Sandberg@ARM.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
279651SAndreas.Sandberg@ARM.com *
289651SAndreas.Sandberg@ARM.com * Authors: Steve Reinhardt
299651SAndreas.Sandberg@ARM.com *          Kevin Lim
309651SAndreas.Sandberg@ARM.com */
319651SAndreas.Sandberg@ARM.com
329651SAndreas.Sandberg@ARM.com#ifndef __SIM_SYSCALL_EMUL_HH__
339651SAndreas.Sandberg@ARM.com#define __SIM_SYSCALL_EMUL_HH__
349651SAndreas.Sandberg@ARM.com
359651SAndreas.Sandberg@ARM.com#define NO_STAT64 (defined(__APPLE__) || defined(__OpenBSD__) || \
369651SAndreas.Sandberg@ARM.com                   defined(__FreeBSD__) || defined(__CYGWIN__))
379651SAndreas.Sandberg@ARM.com
389651SAndreas.Sandberg@ARM.com///
399651SAndreas.Sandberg@ARM.com/// @file syscall_emul.hh
4011793Sbrandon.potter@amd.com///
4111793Sbrandon.potter@amd.com/// This file defines objects used to emulate syscalls from the target
429651SAndreas.Sandberg@ARM.com/// application on the host machine.
439651SAndreas.Sandberg@ARM.com
449651SAndreas.Sandberg@ARM.com#include <errno.h>
459651SAndreas.Sandberg@ARM.com#include <string>
469651SAndreas.Sandberg@ARM.com#ifdef __CYGWIN32__
479651SAndreas.Sandberg@ARM.com#include <sys/fcntl.h>	// for O_BINARY
489651SAndreas.Sandberg@ARM.com#endif
499651SAndreas.Sandberg@ARM.com#include <sys/stat.h>
509651SAndreas.Sandberg@ARM.com#include <fcntl.h>
519760Sandreas@sandberg.pp.se#include <sys/uio.h>
529651SAndreas.Sandberg@ARM.com
539683Sandreas@sandberg.pp.se#include "sim/host.hh"	// for Addr
549753Sandreas@sandberg.pp.se#include "base/chunk_generator.hh"
559651SAndreas.Sandberg@ARM.com#include "base/intmath.hh"	// for RoundUp
569651SAndreas.Sandberg@ARM.com#include "base/misc.hh"
579651SAndreas.Sandberg@ARM.com#include "base/trace.hh"
589651SAndreas.Sandberg@ARM.com#include "cpu/base.hh"
599651SAndreas.Sandberg@ARM.com#include "cpu/thread_context.hh"
609651SAndreas.Sandberg@ARM.com#include "mem/translating_port.hh"
619651SAndreas.Sandberg@ARM.com#include "mem/page_table.hh"
629651SAndreas.Sandberg@ARM.com#include "sim/process.hh"
639651SAndreas.Sandberg@ARM.com
649651SAndreas.Sandberg@ARM.com///
659651SAndreas.Sandberg@ARM.com/// System call descriptor.
669651SAndreas.Sandberg@ARM.com///
6711839SCurtis.Dunham@arm.comclass SyscallDesc {
689651SAndreas.Sandberg@ARM.com
699651SAndreas.Sandberg@ARM.com  public:
709651SAndreas.Sandberg@ARM.com
7111399Sandreas.sandberg@arm.com    /// Typedef for target syscall handler functions.
729652SAndreas.Sandberg@ARM.com    typedef SyscallReturn (*FuncPtr)(SyscallDesc *, int num,
739652SAndreas.Sandberg@ARM.com                           Process *, ThreadContext *);
749651SAndreas.Sandberg@ARM.com
759651SAndreas.Sandberg@ARM.com    const char *name;	//!< Syscall name (e.g., "open").
769651SAndreas.Sandberg@ARM.com    FuncPtr funcPtr;	//!< Pointer to emulation function.
779651SAndreas.Sandberg@ARM.com    int flags;		//!< Flags (see Flags enum).
789892Sandreas@sandberg.pp.se
799655SAndreas.Sandberg@ARM.com    /// Flag values for controlling syscall behavior.
809752Sandreas@sandberg.pp.se    enum Flags {
819752Sandreas@sandberg.pp.se        /// Don't set return regs according to funcPtr return value.
829651SAndreas.Sandberg@ARM.com        /// Used for syscalls with non-standard return conventions
839651SAndreas.Sandberg@ARM.com        /// that explicitly set the ThreadContext regs (e.g.,
849651SAndreas.Sandberg@ARM.com        /// sigreturn).
859651SAndreas.Sandberg@ARM.com        SuppressReturnValue = 1
869651SAndreas.Sandberg@ARM.com    };
8710553Salexandru.dutu@amd.com
8810553Salexandru.dutu@amd.com    /// Constructor.
8910553Salexandru.dutu@amd.com    SyscallDesc(const char *_name, FuncPtr _funcPtr, int _flags = 0)
9010553Salexandru.dutu@amd.com        : name(_name), funcPtr(_funcPtr), flags(_flags)
9110553Salexandru.dutu@amd.com    {
9210553Salexandru.dutu@amd.com    }
9310553Salexandru.dutu@amd.com
9410553Salexandru.dutu@amd.com    /// Emulate the syscall.  Public interface for calling through funcPtr.
959651SAndreas.Sandberg@ARM.com    void doSyscall(int callnum, Process *proc, ThreadContext *tc);
969651SAndreas.Sandberg@ARM.com};
979651SAndreas.Sandberg@ARM.com
989651SAndreas.Sandberg@ARM.com
999651SAndreas.Sandberg@ARM.comclass BaseBufferArg {
1009651SAndreas.Sandberg@ARM.com
1019651SAndreas.Sandberg@ARM.com  public:
1029651SAndreas.Sandberg@ARM.com
1039651SAndreas.Sandberg@ARM.com    BaseBufferArg(Addr _addr, int _size) : addr(_addr), size(_size)
1049651SAndreas.Sandberg@ARM.com    {
1059651SAndreas.Sandberg@ARM.com        bufPtr = new uint8_t[size];
1069651SAndreas.Sandberg@ARM.com        // clear out buffer: in case we only partially populate this,
1079651SAndreas.Sandberg@ARM.com        // and then do a copyOut(), we want to make sure we don't
1089651SAndreas.Sandberg@ARM.com        // introduce any random junk into the simulated address space
1099651SAndreas.Sandberg@ARM.com        memset(bufPtr, 0, size);
1109651SAndreas.Sandberg@ARM.com    }
1119651SAndreas.Sandberg@ARM.com
1129651SAndreas.Sandberg@ARM.com    virtual ~BaseBufferArg() { delete [] bufPtr; }
1139651SAndreas.Sandberg@ARM.com
1149651SAndreas.Sandberg@ARM.com    //
1159651SAndreas.Sandberg@ARM.com    // copy data into simulator space (read from target memory)
1169651SAndreas.Sandberg@ARM.com    //
1179651SAndreas.Sandberg@ARM.com    virtual bool copyIn(TranslatingPort *memport)
1189651SAndreas.Sandberg@ARM.com    {
1199651SAndreas.Sandberg@ARM.com        memport->readBlob(addr, bufPtr, size);
1209651SAndreas.Sandberg@ARM.com        return true;	// no EFAULT detection for now
1219651SAndreas.Sandberg@ARM.com    }
1229651SAndreas.Sandberg@ARM.com
1239651SAndreas.Sandberg@ARM.com    //
1249651SAndreas.Sandberg@ARM.com    // copy data out of simulator space (write to target memory)
1259690Sandreas@sandberg.pp.se    //
1269690Sandreas@sandberg.pp.se    virtual bool copyOut(TranslatingPort *memport)
1279690Sandreas@sandberg.pp.se    {
12811363Sandreas@sandberg.pp.se        memport->writeBlob(addr, bufPtr, size);
1299651SAndreas.Sandberg@ARM.com        return true;	// no EFAULT detection for now
1309651SAndreas.Sandberg@ARM.com    }
1319651SAndreas.Sandberg@ARM.com
1329651SAndreas.Sandberg@ARM.com  protected:
1339651SAndreas.Sandberg@ARM.com    Addr addr;
1349651SAndreas.Sandberg@ARM.com    int size;
1359651SAndreas.Sandberg@ARM.com    uint8_t *bufPtr;
1369651SAndreas.Sandberg@ARM.com};
1379651SAndreas.Sandberg@ARM.com
1389651SAndreas.Sandberg@ARM.com
1399651SAndreas.Sandberg@ARM.comclass BufferArg : public BaseBufferArg
1409651SAndreas.Sandberg@ARM.com{
1419651SAndreas.Sandberg@ARM.com  public:
1429651SAndreas.Sandberg@ARM.com    BufferArg(Addr _addr, int _size) : BaseBufferArg(_addr, _size) { }
1439651SAndreas.Sandberg@ARM.com    void *bufferPtr()	{ return bufPtr; }
1449651SAndreas.Sandberg@ARM.com};
1459651SAndreas.Sandberg@ARM.com
1469651SAndreas.Sandberg@ARM.comtemplate <class T>
1479651SAndreas.Sandberg@ARM.comclass TypedBufferArg : public BaseBufferArg
1489651SAndreas.Sandberg@ARM.com{
1499651SAndreas.Sandberg@ARM.com  public:
1509651SAndreas.Sandberg@ARM.com    // user can optionally specify a specific number of bytes to
1519651SAndreas.Sandberg@ARM.com    // allocate to deal with those structs that have variable-size
1529651SAndreas.Sandberg@ARM.com    // arrays at the end
1539651SAndreas.Sandberg@ARM.com    TypedBufferArg(Addr _addr, int _size = sizeof(T))
1549690Sandreas@sandberg.pp.se        : BaseBufferArg(_addr, _size)
1559690Sandreas@sandberg.pp.se    { }
1569690Sandreas@sandberg.pp.se
1579651SAndreas.Sandberg@ARM.com    // type case
1589651SAndreas.Sandberg@ARM.com    operator T*() { return (T *)bufPtr; }
1599651SAndreas.Sandberg@ARM.com
1609651SAndreas.Sandberg@ARM.com    // dereference operators
1619651SAndreas.Sandberg@ARM.com    T &operator*()	 { return *((T *)bufPtr); }
1629651SAndreas.Sandberg@ARM.com    T* operator->()	 { return (T *)bufPtr; }
1639732Sandreas@sandberg.pp.se    T &operator[](int i) { return ((T *)bufPtr)[i]; }
1649732Sandreas@sandberg.pp.se};
16510073Sandreas@sandberg.pp.se
16610073Sandreas@sandberg.pp.se//////////////////////////////////////////////////////////////////////
16712085Sspwilson2@wisc.edu//
16810073Sandreas@sandberg.pp.se// The following emulation functions are generic enough that they
16910073Sandreas@sandberg.pp.se// don't need to be recompiled for different emulated OS's.  They are
17010073Sandreas@sandberg.pp.se// defined in sim/syscall_emul.cc.
17111629Smichael.lebeane@amd.com//
17211629Smichael.lebeane@amd.com//////////////////////////////////////////////////////////////////////
17311629Smichael.lebeane@amd.com
17411629Smichael.lebeane@amd.com
17511629Smichael.lebeane@amd.com/// Handler for unimplemented syscalls that we haven't thought about.
17611629Smichael.lebeane@amd.comSyscallReturn unimplementedFunc(SyscallDesc *desc, int num,
17711629Smichael.lebeane@amd.com                                Process *p, ThreadContext *tc);
17811629Smichael.lebeane@amd.com
17911629Smichael.lebeane@amd.com/// Handler for unimplemented syscalls that we never intend to
18011629Smichael.lebeane@amd.com/// implement (signal handling, etc.) and should not affect the correct
18111629Smichael.lebeane@amd.com/// behavior of the program.  Print a warning only if the appropriate
18211629Smichael.lebeane@amd.com/// trace flag is enabled.  Return success to the target program.
18311629Smichael.lebeane@amd.comSyscallReturn ignoreFunc(SyscallDesc *desc, int num,
18411629Smichael.lebeane@amd.com                         Process *p, ThreadContext *tc);
18511629Smichael.lebeane@amd.com
18611629Smichael.lebeane@amd.com/// Target exit() handler: terminate simulation.
18711629Smichael.lebeane@amd.comSyscallReturn exitFunc(SyscallDesc *desc, int num,
18811629Smichael.lebeane@amd.com                       Process *p, ThreadContext *tc);
18911629Smichael.lebeane@amd.com
19011629Smichael.lebeane@amd.com/// Target getpagesize() handler.
19111629Smichael.lebeane@amd.comSyscallReturn getpagesizeFunc(SyscallDesc *desc, int num,
19211629Smichael.lebeane@amd.com                              Process *p, ThreadContext *tc);
19311629Smichael.lebeane@amd.com
19411629Smichael.lebeane@amd.com/// Target obreak() handler: set brk address.
19511629Smichael.lebeane@amd.comSyscallReturn obreakFunc(SyscallDesc *desc, int num,
19611629Smichael.lebeane@amd.com                         Process *p, ThreadContext *tc);
19711629Smichael.lebeane@amd.com
19811629Smichael.lebeane@amd.com/// Target close() handler.
19911629Smichael.lebeane@amd.comSyscallReturn closeFunc(SyscallDesc *desc, int num,
20011629Smichael.lebeane@amd.com                        Process *p, ThreadContext *tc);
20111629Smichael.lebeane@amd.com
20211629Smichael.lebeane@amd.com/// Target read() handler.
20311629Smichael.lebeane@amd.comSyscallReturn readFunc(SyscallDesc *desc, int num,
20411629Smichael.lebeane@amd.com                       Process *p, ThreadContext *tc);
20511629Smichael.lebeane@amd.com
20611629Smichael.lebeane@amd.com/// Target write() handler.
20711629Smichael.lebeane@amd.comSyscallReturn writeFunc(SyscallDesc *desc, int num,
20811629Smichael.lebeane@amd.com                        Process *p, ThreadContext *tc);
20911629Smichael.lebeane@amd.com
21011629Smichael.lebeane@amd.com/// Target lseek() handler.
21111629Smichael.lebeane@amd.comSyscallReturn lseekFunc(SyscallDesc *desc, int num,
21211629Smichael.lebeane@amd.com                        Process *p, ThreadContext *tc);
21311629Smichael.lebeane@amd.com
21411629Smichael.lebeane@amd.com/// Target munmap() handler.
21511629Smichael.lebeane@amd.comSyscallReturn munmapFunc(SyscallDesc *desc, int num,
21611629Smichael.lebeane@amd.com                         Process *p, ThreadContext *tc);
21711629Smichael.lebeane@amd.com
21811629Smichael.lebeane@amd.com/// Target gethostname() handler.
21911629Smichael.lebeane@amd.comSyscallReturn gethostnameFunc(SyscallDesc *desc, int num,
22011629Smichael.lebeane@amd.com                              Process *p, ThreadContext *tc);
22111629Smichael.lebeane@amd.com
22211629Smichael.lebeane@amd.com/// Target unlink() handler.
22311629Smichael.lebeane@amd.comSyscallReturn unlinkFunc(SyscallDesc *desc, int num,
22411629Smichael.lebeane@amd.com                         Process *p, ThreadContext *tc);
22511629Smichael.lebeane@amd.com
22611629Smichael.lebeane@amd.com/// Target rename() handler.
22711629Smichael.lebeane@amd.comSyscallReturn renameFunc(SyscallDesc *desc, int num,
22811629Smichael.lebeane@amd.com                         Process *p, ThreadContext *tc);
22911629Smichael.lebeane@amd.com
23011629Smichael.lebeane@amd.com
23111629Smichael.lebeane@amd.com/// Target truncate() handler.
23211629Smichael.lebeane@amd.comSyscallReturn truncateFunc(SyscallDesc *desc, int num,
23311629Smichael.lebeane@amd.com                           Process *p, ThreadContext *tc);
23411629Smichael.lebeane@amd.com
23511629Smichael.lebeane@amd.com
23611629Smichael.lebeane@amd.com/// Target ftruncate() handler.
23711629Smichael.lebeane@amd.comSyscallReturn ftruncateFunc(SyscallDesc *desc, int num,
23811629Smichael.lebeane@amd.com                            Process *p, ThreadContext *tc);
23911629Smichael.lebeane@amd.com
24011629Smichael.lebeane@amd.com
24110073Sandreas@sandberg.pp.se/// Target chown() handler.
24210073Sandreas@sandberg.pp.seSyscallReturn chownFunc(SyscallDesc *desc, int num,
24310073Sandreas@sandberg.pp.se                        Process *p, ThreadContext *tc);
24410073Sandreas@sandberg.pp.se
24510073Sandreas@sandberg.pp.se
24610073Sandreas@sandberg.pp.se/// Target fchown() handler.
24710073Sandreas@sandberg.pp.seSyscallReturn fchownFunc(SyscallDesc *desc, int num,
24810073Sandreas@sandberg.pp.se                         Process *p, ThreadContext *tc);
24910073Sandreas@sandberg.pp.se
25010073Sandreas@sandberg.pp.se/// Target dup() handler.
25110114Sandreas@sandberg.pp.seSyscallReturn dupFunc(SyscallDesc *desc, int num,
25210114Sandreas@sandberg.pp.se                      Process *process, ThreadContext *tc);
25310098Sandreas@sandberg.pp.se
25410098Sandreas@sandberg.pp.se/// Target fnctl() handler.
25510098Sandreas@sandberg.pp.seSyscallReturn fcntlFunc(SyscallDesc *desc, int num,
25610098Sandreas@sandberg.pp.se                        Process *process, ThreadContext *tc);
25710073Sandreas@sandberg.pp.se
25810073Sandreas@sandberg.pp.se/// Target fcntl64() handler.
25910073Sandreas@sandberg.pp.seSyscallReturn fcntl64Func(SyscallDesc *desc, int num,
26010073Sandreas@sandberg.pp.se                        Process *process, ThreadContext *tc);
26110114Sandreas@sandberg.pp.se
26210073Sandreas@sandberg.pp.se/// Target setuid() handler.
26310073Sandreas@sandberg.pp.seSyscallReturn setuidFunc(SyscallDesc *desc, int num,
26410073Sandreas@sandberg.pp.se                               Process *p, ThreadContext *tc);
26510114Sandreas@sandberg.pp.se
26610073Sandreas@sandberg.pp.se/// Target getpid() handler.
26710073Sandreas@sandberg.pp.seSyscallReturn getpidFunc(SyscallDesc *desc, int num,
26810073Sandreas@sandberg.pp.se                               Process *p, ThreadContext *tc);
2699651SAndreas.Sandberg@ARM.com
2709651SAndreas.Sandberg@ARM.com/// Target getuid() handler.
2719651SAndreas.Sandberg@ARM.comSyscallReturn getuidFunc(SyscallDesc *desc, int num,
2729651SAndreas.Sandberg@ARM.com                               Process *p, ThreadContext *tc);
2739651SAndreas.Sandberg@ARM.com
2749651SAndreas.Sandberg@ARM.com/// Target getgid() handler.
2759651SAndreas.Sandberg@ARM.comSyscallReturn getgidFunc(SyscallDesc *desc, int num,
2769651SAndreas.Sandberg@ARM.com                               Process *p, ThreadContext *tc);
2779651SAndreas.Sandberg@ARM.com
2789684Sandreas@sandberg.pp.se/// Target getppid() handler.
2799684Sandreas@sandberg.pp.seSyscallReturn getppidFunc(SyscallDesc *desc, int num,
2809684Sandreas@sandberg.pp.se                               Process *p, ThreadContext *tc);
2819684Sandreas@sandberg.pp.se
2829684Sandreas@sandberg.pp.se/// Target geteuid() handler.
2839651SAndreas.Sandberg@ARM.comSyscallReturn geteuidFunc(SyscallDesc *desc, int num,
2849651SAndreas.Sandberg@ARM.com                               Process *p, ThreadContext *tc);
2859651SAndreas.Sandberg@ARM.com
2869651SAndreas.Sandberg@ARM.com/// Target getegid() handler.
2879651SAndreas.Sandberg@ARM.comSyscallReturn getegidFunc(SyscallDesc *desc, int num,
2889755Sandreas@sandberg.pp.se                               Process *p, ThreadContext *tc);
2899755Sandreas@sandberg.pp.se
2909755Sandreas@sandberg.pp.se
2919755Sandreas@sandberg.pp.se
2929755Sandreas@sandberg.pp.se/// Pseudo Funcs  - These functions use a different return convension,
2939755Sandreas@sandberg.pp.se/// returning a second value in a register other than the normal return register
2949755Sandreas@sandberg.pp.seSyscallReturn pipePseudoFunc(SyscallDesc *desc, int num,
2959755Sandreas@sandberg.pp.se                             Process *process, ThreadContext *tc);
2969755Sandreas@sandberg.pp.se
2979755Sandreas@sandberg.pp.se/// Target getpidPseudo() handler.
2989651SAndreas.Sandberg@ARM.comSyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num,
2999651SAndreas.Sandberg@ARM.com                               Process *p, ThreadContext *tc);
3009651SAndreas.Sandberg@ARM.com
3019651SAndreas.Sandberg@ARM.com/// Target getuidPseudo() handler.
3029651SAndreas.Sandberg@ARM.comSyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num,
3039651SAndreas.Sandberg@ARM.com                               Process *p, ThreadContext *tc);
3049651SAndreas.Sandberg@ARM.com
3059651SAndreas.Sandberg@ARM.com/// Target getgidPseudo() handler.
3069651SAndreas.Sandberg@ARM.comSyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num,
3079651SAndreas.Sandberg@ARM.com                               Process *p, ThreadContext *tc);
3089651SAndreas.Sandberg@ARM.com
3099651SAndreas.Sandberg@ARM.com
3109651SAndreas.Sandberg@ARM.com/// A readable name for 1,000,000, for converting microseconds to seconds.
3119651SAndreas.Sandberg@ARM.comconst int one_million = 1000000;
3129651SAndreas.Sandberg@ARM.com
3139651SAndreas.Sandberg@ARM.com/// Approximate seconds since the epoch (1/1/1970).  About a billion,
3149651SAndreas.Sandberg@ARM.com/// by my reckoning.  We want to keep this a constant (not use the
3159651SAndreas.Sandberg@ARM.com/// real-world time) to keep simulations repeatable.
3169651SAndreas.Sandberg@ARM.comconst unsigned seconds_since_epoch = 1000000000;
3179651SAndreas.Sandberg@ARM.com
3189651SAndreas.Sandberg@ARM.com/// Helper function to convert current elapsed time to seconds and
3199651SAndreas.Sandberg@ARM.com/// microseconds.
3209651SAndreas.Sandberg@ARM.comtemplate <class T1, class T2>
3219651SAndreas.Sandberg@ARM.comvoid
3229651SAndreas.Sandberg@ARM.comgetElapsedTime(T1 &sec, T2 &usec)
3239651SAndreas.Sandberg@ARM.com{
3249651SAndreas.Sandberg@ARM.com    int elapsed_usecs = curTick / Clock::Int::us;
3259651SAndreas.Sandberg@ARM.com    sec = elapsed_usecs / one_million;
3269651SAndreas.Sandberg@ARM.com    usec = elapsed_usecs % one_million;
3279651SAndreas.Sandberg@ARM.com}
3289651SAndreas.Sandberg@ARM.com
3299651SAndreas.Sandberg@ARM.com//////////////////////////////////////////////////////////////////////
33010905Sandreas.sandberg@arm.com//
3319651SAndreas.Sandberg@ARM.com// The following emulation functions are generic, but need to be
3329683Sandreas@sandberg.pp.se// templated to account for differences in types, constants, etc.
3339683Sandreas@sandberg.pp.se//
3349683Sandreas@sandberg.pp.se//////////////////////////////////////////////////////////////////////
3359683Sandreas@sandberg.pp.se
3369683Sandreas@sandberg.pp.se#if NO_STAT64
3379651SAndreas.Sandberg@ARM.com    typedef struct stat hst_stat;
3389651SAndreas.Sandberg@ARM.com    typedef struct stat hst_stat64;
33910905Sandreas.sandberg@arm.com#else
3409651SAndreas.Sandberg@ARM.com    typedef struct stat hst_stat;
3419651SAndreas.Sandberg@ARM.com    typedef struct stat64 hst_stat64;
3429651SAndreas.Sandberg@ARM.com#endif
34310905Sandreas.sandberg@arm.com
3449651SAndreas.Sandberg@ARM.com//// Helper function to convert a host stat buffer to a target stat
3459683Sandreas@sandberg.pp.se//// buffer.  Also copies the target buffer out to the simulated
3469683Sandreas@sandberg.pp.se//// memory space.  Used by stat(), fstat(), and lstat().
3479651SAndreas.Sandberg@ARM.com
3489651SAndreas.Sandberg@ARM.comtemplate <typename target_stat, typename host_stat>
34910905Sandreas.sandberg@arm.comstatic void
3509652SAndreas.Sandberg@ARM.comconvertStatBuf(target_stat &tgt, host_stat *host, bool fakeTTY = false)
3519651SAndreas.Sandberg@ARM.com{
3529651SAndreas.Sandberg@ARM.com    if (fakeTTY)
35310913Sandreas.sandberg@arm.com        tgt->st_dev = 0xA;
35410913Sandreas.sandberg@arm.com    else
3559651SAndreas.Sandberg@ARM.com        tgt->st_dev = host->st_dev;
3569651SAndreas.Sandberg@ARM.com    tgt->st_dev = htog(tgt->st_dev);
35710913Sandreas.sandberg@arm.com    tgt->st_ino = host->st_ino;
3589651SAndreas.Sandberg@ARM.com    tgt->st_ino = htog(tgt->st_ino);
3599753Sandreas@sandberg.pp.se    if (fakeTTY)
3609753Sandreas@sandberg.pp.se        tgt->st_rdev = 0x880d;
3619753Sandreas@sandberg.pp.se    else
3629753Sandreas@sandberg.pp.se        tgt->st_rdev = host->st_rdev;
3639753Sandreas@sandberg.pp.se    tgt->st_rdev = htog(tgt->st_rdev);
3649753Sandreas@sandberg.pp.se    tgt->st_size = host->st_size;
3659753Sandreas@sandberg.pp.se    tgt->st_size = htog(tgt->st_size);
3669753Sandreas@sandberg.pp.se    tgt->st_atimeX = host->st_atimeX;
36710913Sandreas.sandberg@arm.com    tgt->st_atimeX = htog(tgt->st_atimeX);
36810913Sandreas.sandberg@arm.com    tgt->st_mtimeX = host->st_mtimeX;
3699651SAndreas.Sandberg@ARM.com    tgt->st_mtimeX = htog(tgt->st_mtimeX);
3709753Sandreas@sandberg.pp.se    tgt->st_ctimeX = host->st_ctimeX;
3719753Sandreas@sandberg.pp.se    tgt->st_ctimeX = htog(tgt->st_ctimeX);
3729753Sandreas@sandberg.pp.se    tgt->st_blksize = host->st_blksize;
3739753Sandreas@sandberg.pp.se    tgt->st_blksize = htog(tgt->st_blksize);
3749753Sandreas@sandberg.pp.se    tgt->st_blocks = host->st_blocks;
3759753Sandreas@sandberg.pp.se    tgt->st_blocks = htog(tgt->st_blocks);
3769753Sandreas@sandberg.pp.se}
3779651SAndreas.Sandberg@ARM.com
3789753Sandreas@sandberg.pp.se// Same for stat64
3799753Sandreas@sandberg.pp.se
3809753Sandreas@sandberg.pp.setemplate <typename target_stat, typename host_stat64>
3819753Sandreas@sandberg.pp.sestatic void
3829753Sandreas@sandberg.pp.seconvertStat64Buf(target_stat &tgt, host_stat64 *host, bool fakeTTY = false)
3839753Sandreas@sandberg.pp.se{
3849753Sandreas@sandberg.pp.se    convertStatBuf<target_stat, host_stat64>(tgt, host, fakeTTY);
3859753Sandreas@sandberg.pp.se#if defined(STAT_HAVE_NSEC)
3869753Sandreas@sandberg.pp.se    tgt->st_atime_nsec = host->st_atime_nsec;
38710913Sandreas.sandberg@arm.com    tgt->st_atime_nsec = htog(tgt->st_atime_nsec);
3889753Sandreas@sandberg.pp.se    tgt->st_mtime_nsec = host->st_mtime_nsec;
3899753Sandreas@sandberg.pp.se    tgt->st_mtime_nsec = htog(tgt->st_mtime_nsec);
3909753Sandreas@sandberg.pp.se    tgt->st_ctime_nsec = host->st_ctime_nsec;
3919753Sandreas@sandberg.pp.se    tgt->st_ctime_nsec = htog(tgt->st_ctime_nsec);
3929753Sandreas@sandberg.pp.se#else
3939753Sandreas@sandberg.pp.se    tgt->st_atime_nsec = 0;
3949753Sandreas@sandberg.pp.se    tgt->st_mtime_nsec = 0;
3959753Sandreas@sandberg.pp.se    tgt->st_ctime_nsec = 0;
3969753Sandreas@sandberg.pp.se#endif
3979753Sandreas@sandberg.pp.se}
39810913Sandreas.sandberg@arm.com
3999753Sandreas@sandberg.pp.se//Here are a couple convenience functions
40011629Smichael.lebeane@amd.comtemplate<class OS>
40111629Smichael.lebeane@amd.comstatic void
40211629Smichael.lebeane@amd.comcopyOutStatBuf(TranslatingPort * mem, Addr addr,
40311629Smichael.lebeane@amd.com        hst_stat *host, bool fakeTTY = false)
40411629Smichael.lebeane@amd.com{
40511629Smichael.lebeane@amd.com    typedef TypedBufferArg<typename OS::tgt_stat> tgt_stat_buf;
4069753Sandreas@sandberg.pp.se    tgt_stat_buf tgt(addr);
4079753Sandreas@sandberg.pp.se    convertStatBuf<tgt_stat_buf, hst_stat>(tgt, host, fakeTTY);
4089753Sandreas@sandberg.pp.se    tgt.copyOut(mem);
40910913Sandreas.sandberg@arm.com}
4109753Sandreas@sandberg.pp.se
4119753Sandreas@sandberg.pp.setemplate<class OS>
4129753Sandreas@sandberg.pp.sestatic void
41310913Sandreas.sandberg@arm.comcopyOutStat64Buf(TranslatingPort * mem, Addr addr,
4149753Sandreas@sandberg.pp.se        hst_stat64 *host, bool fakeTTY = false)
4159651SAndreas.Sandberg@ARM.com{
4169651SAndreas.Sandberg@ARM.com    typedef TypedBufferArg<typename OS::tgt_stat64> tgt_stat_buf;
4179651SAndreas.Sandberg@ARM.com    tgt_stat_buf tgt(addr);
4189651SAndreas.Sandberg@ARM.com    convertStatBuf<tgt_stat_buf, hst_stat64>(tgt, host, fakeTTY);
4199651SAndreas.Sandberg@ARM.com    tgt.copyOut(mem);
4209651SAndreas.Sandberg@ARM.com}
4219651SAndreas.Sandberg@ARM.com
4229651SAndreas.Sandberg@ARM.com/// Target ioctl() handler.  For the most part, programs call ioctl()
4239651SAndreas.Sandberg@ARM.com/// only to find out if their stdout is a tty, to determine whether to
4249651SAndreas.Sandberg@ARM.com/// do line or block buffering.
4259651SAndreas.Sandberg@ARM.comtemplate <class OS>
4269651SAndreas.Sandberg@ARM.comSyscallReturn
4279651SAndreas.Sandberg@ARM.comioctlFunc(SyscallDesc *desc, int callnum, Process *process,
4289651SAndreas.Sandberg@ARM.com          ThreadContext *tc)
4299651SAndreas.Sandberg@ARM.com{
4309651SAndreas.Sandberg@ARM.com    int fd = tc->getSyscallArg(0);
4319651SAndreas.Sandberg@ARM.com    unsigned req = tc->getSyscallArg(1);
4329651SAndreas.Sandberg@ARM.com
4339651SAndreas.Sandberg@ARM.com    DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", fd, req);
4349651SAndreas.Sandberg@ARM.com
4359651SAndreas.Sandberg@ARM.com    if (fd < 0 || process->sim_fd(fd) < 0) {
4369651SAndreas.Sandberg@ARM.com        // doesn't map to any simulator fd: not a valid target fd
4379651SAndreas.Sandberg@ARM.com        return -EBADF;
4389651SAndreas.Sandberg@ARM.com    }
4399651SAndreas.Sandberg@ARM.com
4409651SAndreas.Sandberg@ARM.com    switch (req) {
44111363Sandreas@sandberg.pp.se      case OS::TIOCISATTY:
44211363Sandreas@sandberg.pp.se      case OS::TIOCGETP:
44311363Sandreas@sandberg.pp.se      case OS::TIOCSETP:
44411363Sandreas@sandberg.pp.se      case OS::TIOCSETN:
44511363Sandreas@sandberg.pp.se      case OS::TIOCSETC:
44611363Sandreas@sandberg.pp.se      case OS::TIOCGETC:
44711363Sandreas@sandberg.pp.se      case OS::TIOCGETS:
44811363Sandreas@sandberg.pp.se      case OS::TIOCGETA:
44911363Sandreas@sandberg.pp.se        return -ENOTTY;
45011363Sandreas@sandberg.pp.se
45111363Sandreas@sandberg.pp.se      default:
45211363Sandreas@sandberg.pp.se        fatal("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ 0x%llx\n",
45311363Sandreas@sandberg.pp.se              fd, req, tc->readPC());
45411363Sandreas@sandberg.pp.se    }
45511363Sandreas@sandberg.pp.se}
45611363Sandreas@sandberg.pp.se
45711363Sandreas@sandberg.pp.se/// Target open() handler.
45811363Sandreas@sandberg.pp.setemplate <class OS>
45911363Sandreas@sandberg.pp.seSyscallReturn
46011363Sandreas@sandberg.pp.seopenFunc(SyscallDesc *desc, int callnum, Process *process,
46111363Sandreas@sandberg.pp.se         ThreadContext *tc)
46211363Sandreas@sandberg.pp.se{
46311363Sandreas@sandberg.pp.se    std::string path;
4649651SAndreas.Sandberg@ARM.com
4659651SAndreas.Sandberg@ARM.com    if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
4669652SAndreas.Sandberg@ARM.com        return -EFAULT;
4679652SAndreas.Sandberg@ARM.com
4689651SAndreas.Sandberg@ARM.com    if (path == "/dev/sysdev0") {
4699651SAndreas.Sandberg@ARM.com        // This is a memory-mapped high-resolution timer device on Alpha.
4709651SAndreas.Sandberg@ARM.com        // We don't support it, so just punt.
4719651SAndreas.Sandberg@ARM.com        warn("Ignoring open(%s, ...)\n", path);
4729651SAndreas.Sandberg@ARM.com        return -ENOENT;
4739651SAndreas.Sandberg@ARM.com    }
4749651SAndreas.Sandberg@ARM.com
4759651SAndreas.Sandberg@ARM.com    int tgtFlags = tc->getSyscallArg(1);
4769651SAndreas.Sandberg@ARM.com    int mode = tc->getSyscallArg(2);
4779651SAndreas.Sandberg@ARM.com    int hostFlags = 0;
4789651SAndreas.Sandberg@ARM.com
4799651SAndreas.Sandberg@ARM.com    // translate open flags
4809651SAndreas.Sandberg@ARM.com    for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) {
4819651SAndreas.Sandberg@ARM.com        if (tgtFlags & OS::openFlagTable[i].tgtFlag) {
4829651SAndreas.Sandberg@ARM.com            tgtFlags &= ~OS::openFlagTable[i].tgtFlag;
4839651SAndreas.Sandberg@ARM.com            hostFlags |= OS::openFlagTable[i].hostFlag;
4849651SAndreas.Sandberg@ARM.com        }
4859651SAndreas.Sandberg@ARM.com    }
4869651SAndreas.Sandberg@ARM.com
4879651SAndreas.Sandberg@ARM.com    // any target flags left?
4889651SAndreas.Sandberg@ARM.com    if (tgtFlags != 0)
4899651SAndreas.Sandberg@ARM.com        warn("Syscall: open: cannot decode flags 0x%x", tgtFlags);
4909651SAndreas.Sandberg@ARM.com
4919753Sandreas@sandberg.pp.se#ifdef __CYGWIN32__
4929753Sandreas@sandberg.pp.se    hostFlags |= O_BINARY;
4939753Sandreas@sandberg.pp.se#endif
4949753Sandreas@sandberg.pp.se
4959753Sandreas@sandberg.pp.se    DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str());
4969753Sandreas@sandberg.pp.se
4979651SAndreas.Sandberg@ARM.com    // open the file
4989651SAndreas.Sandberg@ARM.com    int fd = open(path.c_str(), hostFlags, mode);
4999651SAndreas.Sandberg@ARM.com
5009651SAndreas.Sandberg@ARM.com    return (fd == -1) ? -errno : process->alloc_fd(fd);
5019651SAndreas.Sandberg@ARM.com}
50211629Smichael.lebeane@amd.com
5039651SAndreas.Sandberg@ARM.com
50411629Smichael.lebeane@amd.com/// Target chmod() handler.
5059651SAndreas.Sandberg@ARM.comtemplate <class OS>
5069651SAndreas.Sandberg@ARM.comSyscallReturn
5079651SAndreas.Sandberg@ARM.comchmodFunc(SyscallDesc *desc, int callnum, Process *process,
5089651SAndreas.Sandberg@ARM.com          ThreadContext *tc)
50911151Smitch.hayenga@arm.com{
5109651SAndreas.Sandberg@ARM.com    std::string path;
5119651SAndreas.Sandberg@ARM.com
51210157Sandreas@sandberg.pp.se    if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
51310157Sandreas@sandberg.pp.se        return -EFAULT;
51410157Sandreas@sandberg.pp.se
51510157Sandreas@sandberg.pp.se    uint32_t mode = tc->getSyscallArg(1);
51610157Sandreas@sandberg.pp.se    mode_t hostMode = 0;
51710157Sandreas@sandberg.pp.se
51810157Sandreas@sandberg.pp.se    // XXX translate mode flags via OS::something???
5199651SAndreas.Sandberg@ARM.com    hostMode = mode;
5209651SAndreas.Sandberg@ARM.com
5219651SAndreas.Sandberg@ARM.com    // do the chmod
5229651SAndreas.Sandberg@ARM.com    int result = chmod(path.c_str(), hostMode);
5239651SAndreas.Sandberg@ARM.com    if (result < 0)
5249651SAndreas.Sandberg@ARM.com        return -errno;
5259651SAndreas.Sandberg@ARM.com
5269651SAndreas.Sandberg@ARM.com    return 0;
52710407Smitch.hayenga@arm.com}
5289651SAndreas.Sandberg@ARM.com
52910407Smitch.hayenga@arm.com
5309651SAndreas.Sandberg@ARM.com/// Target fchmod() handler.
5319651SAndreas.Sandberg@ARM.comtemplate <class OS>
5329651SAndreas.Sandberg@ARM.comSyscallReturn
5339651SAndreas.Sandberg@ARM.comfchmodFunc(SyscallDesc *desc, int callnum, Process *process,
5349651SAndreas.Sandberg@ARM.com           ThreadContext *tc)
5359651SAndreas.Sandberg@ARM.com{
5369651SAndreas.Sandberg@ARM.com    int fd = tc->getSyscallArg(0);
5379754Sandreas@sandberg.pp.se    if (fd < 0 || process->sim_fd(fd) < 0) {
5389651SAndreas.Sandberg@ARM.com        // doesn't map to any simulator fd: not a valid target fd
53910407Smitch.hayenga@arm.com        return -EBADF;
5409651SAndreas.Sandberg@ARM.com    }
5419651SAndreas.Sandberg@ARM.com
5429651SAndreas.Sandberg@ARM.com    uint32_t mode = tc->getSyscallArg(1);
5439651SAndreas.Sandberg@ARM.com    mode_t hostMode = 0;
5449651SAndreas.Sandberg@ARM.com
5459651SAndreas.Sandberg@ARM.com    // XXX translate mode flags via OS::someting???
5469651SAndreas.Sandberg@ARM.com    hostMode = mode;
5479651SAndreas.Sandberg@ARM.com
5489651SAndreas.Sandberg@ARM.com    // do the fchmod
5499651SAndreas.Sandberg@ARM.com    int result = fchmod(process->sim_fd(fd), hostMode);
5509651SAndreas.Sandberg@ARM.com    if (result < 0)
5519651SAndreas.Sandberg@ARM.com        return -errno;
5529651SAndreas.Sandberg@ARM.com
5539651SAndreas.Sandberg@ARM.com    return 0;
5549651SAndreas.Sandberg@ARM.com}
55510553Salexandru.dutu@amd.com
5569651SAndreas.Sandberg@ARM.com
5579651SAndreas.Sandberg@ARM.com/// Target stat() handler.
5589651SAndreas.Sandberg@ARM.comtemplate <class OS>
5599651SAndreas.Sandberg@ARM.comSyscallReturn
5609651SAndreas.Sandberg@ARM.comstatFunc(SyscallDesc *desc, int callnum, Process *process,
5619651SAndreas.Sandberg@ARM.com         ThreadContext *tc)
5629651SAndreas.Sandberg@ARM.com{
5639651SAndreas.Sandberg@ARM.com    std::string path;
5649651SAndreas.Sandberg@ARM.com
5659651SAndreas.Sandberg@ARM.com    if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
5669651SAndreas.Sandberg@ARM.com    return -EFAULT;
5679651SAndreas.Sandberg@ARM.com
5689651SAndreas.Sandberg@ARM.com    struct stat hostBuf;
5699651SAndreas.Sandberg@ARM.com    int result = stat(path.c_str(), &hostBuf);
5709651SAndreas.Sandberg@ARM.com
5719651SAndreas.Sandberg@ARM.com    if (result < 0)
5729651SAndreas.Sandberg@ARM.com        return -errno;
5739651SAndreas.Sandberg@ARM.com
5749651SAndreas.Sandberg@ARM.com    copyOutStatBuf<OS>(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf);
5759651SAndreas.Sandberg@ARM.com
5769651SAndreas.Sandberg@ARM.com    return 0;
5779651SAndreas.Sandberg@ARM.com}
5789651SAndreas.Sandberg@ARM.com
5799651SAndreas.Sandberg@ARM.com
5809651SAndreas.Sandberg@ARM.com/// Target fstat64() handler.
5819652SAndreas.Sandberg@ARM.comtemplate <class OS>
5829652SAndreas.Sandberg@ARM.comSyscallReturn
5839652SAndreas.Sandberg@ARM.comfstat64Func(SyscallDesc *desc, int callnum, Process *process,
5849652SAndreas.Sandberg@ARM.com            ThreadContext *tc)
5859652SAndreas.Sandberg@ARM.com{
5869652SAndreas.Sandberg@ARM.com    int fd = tc->getSyscallArg(0);
5879652SAndreas.Sandberg@ARM.com    if (fd < 0 || process->sim_fd(fd) < 0) {
5889652SAndreas.Sandberg@ARM.com        // doesn't map to any simulator fd: not a valid target fd
5899652SAndreas.Sandberg@ARM.com        return -EBADF;
5909651SAndreas.Sandberg@ARM.com    }
5919651SAndreas.Sandberg@ARM.com
5929651SAndreas.Sandberg@ARM.com#if NO_STAT64
5939752Sandreas@sandberg.pp.se    struct stat  hostBuf;
5949651SAndreas.Sandberg@ARM.com    int result = fstat(process->sim_fd(fd), &hostBuf);
5959651SAndreas.Sandberg@ARM.com#else
5969651SAndreas.Sandberg@ARM.com    struct stat64  hostBuf;
5979651SAndreas.Sandberg@ARM.com    int result = fstat64(process->sim_fd(fd), &hostBuf);
5989651SAndreas.Sandberg@ARM.com#endif
5999651SAndreas.Sandberg@ARM.com
6009752Sandreas@sandberg.pp.se    if (result < 0)
6019651SAndreas.Sandberg@ARM.com        return -errno;
6029651SAndreas.Sandberg@ARM.com
6039651SAndreas.Sandberg@ARM.com    copyOutStat64Buf<OS>(tc->getMemPort(), fd, tc->getSyscallArg(1), &hostBuf);
60410905Sandreas.sandberg@arm.com
6059651SAndreas.Sandberg@ARM.com    return 0;
6069651SAndreas.Sandberg@ARM.com}
6079651SAndreas.Sandberg@ARM.com
6089651SAndreas.Sandberg@ARM.com
6099651SAndreas.Sandberg@ARM.com/// Target lstat() handler.
6109651SAndreas.Sandberg@ARM.comtemplate <class OS>
6119651SAndreas.Sandberg@ARM.comSyscallReturn
6129753Sandreas@sandberg.pp.selstatFunc(SyscallDesc *desc, int callnum, Process *process,
61311629Smichael.lebeane@amd.com          ThreadContext *tc)
6149651SAndreas.Sandberg@ARM.com{
6159651SAndreas.Sandberg@ARM.com    std::string path;
6169753Sandreas@sandberg.pp.se
6179753Sandreas@sandberg.pp.se    if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
6189753Sandreas@sandberg.pp.se      return -EFAULT;
6199753Sandreas@sandberg.pp.se
6209753Sandreas@sandberg.pp.se    struct stat hostBuf;
6219753Sandreas@sandberg.pp.se    int result = lstat(path.c_str(), &hostBuf);
6229651SAndreas.Sandberg@ARM.com
6239651SAndreas.Sandberg@ARM.com    if (result < 0)
6249753Sandreas@sandberg.pp.se        return -errno;
6259753Sandreas@sandberg.pp.se
62610858Sandreas.sandberg@arm.com    copyOutStatBuf<OS>(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf);
62710858Sandreas.sandberg@arm.com
62810858Sandreas.sandberg@arm.com    return 0;
62910858Sandreas.sandberg@arm.com}
63010858Sandreas.sandberg@arm.com
63110858Sandreas.sandberg@arm.com/// Target lstat64() handler.
63210858Sandreas.sandberg@arm.comtemplate <class OS>
63310858Sandreas.sandberg@arm.comSyscallReturn
6349753Sandreas@sandberg.pp.selstat64Func(SyscallDesc *desc, int callnum, Process *process,
63511399Sandreas.sandberg@arm.com            ThreadContext *tc)
63611399Sandreas.sandberg@arm.com{
63711399Sandreas.sandberg@arm.com    std::string path;
6389753Sandreas@sandberg.pp.se
6399753Sandreas@sandberg.pp.se    if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
6409753Sandreas@sandberg.pp.se      return -EFAULT;
6419892Sandreas@sandberg.pp.se
64210858Sandreas.sandberg@arm.com#if NO_STAT64
64310858Sandreas.sandberg@arm.com    struct stat hostBuf;
64410858Sandreas.sandberg@arm.com    int result = lstat(path.c_str(), &hostBuf);
64510858Sandreas.sandberg@arm.com#else
6469892Sandreas@sandberg.pp.se    struct stat64 hostBuf;
6479753Sandreas@sandberg.pp.se    int result = lstat64(path.c_str(), &hostBuf);
64810913Sandreas.sandberg@arm.com#endif
6499753Sandreas@sandberg.pp.se
6509753Sandreas@sandberg.pp.se    if (result < 0)
6519753Sandreas@sandberg.pp.se        return -errno;
6529753Sandreas@sandberg.pp.se
6539753Sandreas@sandberg.pp.se    copyOutStat64Buf<OS>(tc->getMemPort(), -1, tc->getSyscallArg(1), &hostBuf);
6549753Sandreas@sandberg.pp.se
6559753Sandreas@sandberg.pp.se    return 0;
6569753Sandreas@sandberg.pp.se}
6579753Sandreas@sandberg.pp.se
65810112Sandreas@sandberg.pp.se/// Target fstat() handler.
65910112Sandreas@sandberg.pp.setemplate <class OS>
66010112Sandreas@sandberg.pp.seSyscallReturn
66110112Sandreas@sandberg.pp.sefstatFunc(SyscallDesc *desc, int callnum, Process *process,
66210112Sandreas@sandberg.pp.se          ThreadContext *tc)
66310112Sandreas@sandberg.pp.se{
6649753Sandreas@sandberg.pp.se    int fd = process->sim_fd(tc->getSyscallArg(0));
6659753Sandreas@sandberg.pp.se
6669753Sandreas@sandberg.pp.se    DPRINTF(SyscallVerbose, "fstat(%d, ...)\n", fd);
6679753Sandreas@sandberg.pp.se
6689753Sandreas@sandberg.pp.se    if (fd < 0)
66911399Sandreas.sandberg@arm.com        return -EBADF;
67011399Sandreas.sandberg@arm.com
67111399Sandreas.sandberg@arm.com    struct stat hostBuf;
6729753Sandreas@sandberg.pp.se    int result = fstat(fd, &hostBuf);
6739753Sandreas@sandberg.pp.se
6749755Sandreas@sandberg.pp.se    if (result < 0)
6759753Sandreas@sandberg.pp.se        return -errno;
6769755Sandreas@sandberg.pp.se
6779755Sandreas@sandberg.pp.se    copyOutStatBuf<OS>(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf);
6789753Sandreas@sandberg.pp.se
6799755Sandreas@sandberg.pp.se    return 0;
6809753Sandreas@sandberg.pp.se}
6819904Sandreas@sandberg.pp.se
6829904Sandreas@sandberg.pp.se
6839904Sandreas@sandberg.pp.se/// Target statfs() handler.
6849904Sandreas@sandberg.pp.setemplate <class OS>
6859904Sandreas@sandberg.pp.seSyscallReturn
6869904Sandreas@sandberg.pp.sestatfsFunc(SyscallDesc *desc, int callnum, Process *process,
6879753Sandreas@sandberg.pp.se           ThreadContext *tc)
6889753Sandreas@sandberg.pp.se{
6899753Sandreas@sandberg.pp.se    std::string path;
6909753Sandreas@sandberg.pp.se
6919651SAndreas.Sandberg@ARM.com    if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
6929753Sandreas@sandberg.pp.se      return -EFAULT;
6939753Sandreas@sandberg.pp.se
6949651SAndreas.Sandberg@ARM.com    struct statfs hostBuf;
6959753Sandreas@sandberg.pp.se    int result = statfs(path.c_str(), &hostBuf);
6969753Sandreas@sandberg.pp.se
69711629Smichael.lebeane@amd.com    if (result < 0)
6989753Sandreas@sandberg.pp.se        return -errno;
6999753Sandreas@sandberg.pp.se
7009753Sandreas@sandberg.pp.se    copyOutStatfsBuf<OS>(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf);
7019753Sandreas@sandberg.pp.se
7029753Sandreas@sandberg.pp.se    return 0;
7039753Sandreas@sandberg.pp.se}
7049753Sandreas@sandberg.pp.se
7059753Sandreas@sandberg.pp.se
70611629Smichael.lebeane@amd.com/// Target fstatfs() handler.
70711629Smichael.lebeane@amd.comtemplate <class OS>
70811629Smichael.lebeane@amd.comSyscallReturn
7099753Sandreas@sandberg.pp.sefstatfsFunc(SyscallDesc *desc, int callnum, Process *process,
7109753Sandreas@sandberg.pp.se            ThreadContext *tc)
7119753Sandreas@sandberg.pp.se{
7129753Sandreas@sandberg.pp.se    int fd = process->sim_fd(tc->getSyscallArg(0));
7139651SAndreas.Sandberg@ARM.com
7149651SAndreas.Sandberg@ARM.com    if (fd < 0)
7159735Sandreas@sandberg.pp.se        return -EBADF;
7169735Sandreas@sandberg.pp.se
7179735Sandreas@sandberg.pp.se    struct statfs hostBuf;
7189735Sandreas@sandberg.pp.se    int result = fstatfs(fd, &hostBuf);
7199735Sandreas@sandberg.pp.se
7209735Sandreas@sandberg.pp.se    if (result < 0)
7219651SAndreas.Sandberg@ARM.com        return -errno;
7229651SAndreas.Sandberg@ARM.com
7239651SAndreas.Sandberg@ARM.com    copyOutStatfsBuf<OS>(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf);
7249753Sandreas@sandberg.pp.se
72511363Sandreas@sandberg.pp.se    return 0;
72611363Sandreas@sandberg.pp.se}
72711363Sandreas@sandberg.pp.se
7289651SAndreas.Sandberg@ARM.com
7299655SAndreas.Sandberg@ARM.com/// Target writev() handler.
7309753Sandreas@sandberg.pp.setemplate <class OS>
7319753Sandreas@sandberg.pp.seSyscallReturn
7329753Sandreas@sandberg.pp.sewritevFunc(SyscallDesc *desc, int callnum, Process *process,
7339753Sandreas@sandberg.pp.se           ThreadContext *tc)
7349753Sandreas@sandberg.pp.se{
7359735Sandreas@sandberg.pp.se    int fd = tc->getSyscallArg(0);
7369755Sandreas@sandberg.pp.se    if (fd < 0 || process->sim_fd(fd) < 0) {
7379755Sandreas@sandberg.pp.se        // doesn't map to any simulator fd: not a valid target fd
73810114Sandreas@sandberg.pp.se        return -EBADF;
73910114Sandreas@sandberg.pp.se    }
74010114Sandreas@sandberg.pp.se
7419753Sandreas@sandberg.pp.se    TranslatingPort *p = tc->getMemPort();
74210114Sandreas@sandberg.pp.se    uint64_t tiov_base = tc->getSyscallArg(1);
7439655SAndreas.Sandberg@ARM.com    size_t count = tc->getSyscallArg(2);
74410114Sandreas@sandberg.pp.se    struct iovec hiov[count];
74510114Sandreas@sandberg.pp.se    for (int i = 0; i < count; ++i)
74610114Sandreas@sandberg.pp.se    {
7479753Sandreas@sandberg.pp.se        typename OS::tgt_iovec tiov;
74810114Sandreas@sandberg.pp.se
74910114Sandreas@sandberg.pp.se        p->readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec),
7509753Sandreas@sandberg.pp.se                    (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec));
7519753Sandreas@sandberg.pp.se        hiov[i].iov_len = gtoh(tiov.iov_len);
7529753Sandreas@sandberg.pp.se        hiov[i].iov_base = new char [hiov[i].iov_len];
7539753Sandreas@sandberg.pp.se        p->readBlob(gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base,
7549753Sandreas@sandberg.pp.se                    hiov[i].iov_len);
7559753Sandreas@sandberg.pp.se    }
7569753Sandreas@sandberg.pp.se
75710157Sandreas@sandberg.pp.se    int result = writev(process->sim_fd(fd), hiov, count);
75810157Sandreas@sandberg.pp.se
75910157Sandreas@sandberg.pp.se    for (int i = 0; i < count; ++i)
76010157Sandreas@sandberg.pp.se    {
76110157Sandreas@sandberg.pp.se        delete [] (char *)hiov[i].iov_base;
76210157Sandreas@sandberg.pp.se    }
76310157Sandreas@sandberg.pp.se
76410157Sandreas@sandberg.pp.se    if (result < 0)
7659753Sandreas@sandberg.pp.se        return -errno;
7669753Sandreas@sandberg.pp.se
7679753Sandreas@sandberg.pp.se    return 0;
7689753Sandreas@sandberg.pp.se}
7699753Sandreas@sandberg.pp.se
7709753Sandreas@sandberg.pp.se
7719753Sandreas@sandberg.pp.se/// Target mmap() handler.
7729753Sandreas@sandberg.pp.se///
7739753Sandreas@sandberg.pp.se/// We don't really handle mmap().  If the target is mmaping an
7749753Sandreas@sandberg.pp.se/// anonymous region or /dev/zero, we can get away with doing basically
7759753Sandreas@sandberg.pp.se/// nothing (since memory is initialized to zero and the simulator
7769753Sandreas@sandberg.pp.se/// doesn't really check addresses anyway).  Always print a warning,
7779753Sandreas@sandberg.pp.se/// since this could be seriously broken if we're not mapping
7789753Sandreas@sandberg.pp.se/// /dev/zero.
7799753Sandreas@sandberg.pp.se//
7809753Sandreas@sandberg.pp.se/// Someday we should explicitly check for /dev/zero in open, flag the
7819753Sandreas@sandberg.pp.se/// file descriptor, and fail (or implement!) a non-anonymous mmap to
7829753Sandreas@sandberg.pp.se/// anything else.
7839753Sandreas@sandberg.pp.setemplate <class OS>
7849753Sandreas@sandberg.pp.seSyscallReturn
7859753Sandreas@sandberg.pp.semmapFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
7869753Sandreas@sandberg.pp.se{
7879753Sandreas@sandberg.pp.se    Addr start = tc->getSyscallArg(0);
7889753Sandreas@sandberg.pp.se    uint64_t length = tc->getSyscallArg(1);
7899753Sandreas@sandberg.pp.se    // int prot = tc->getSyscallArg(2);
79010114Sandreas@sandberg.pp.se    int flags = tc->getSyscallArg(3);
7919753Sandreas@sandberg.pp.se    // int fd = p->sim_fd(tc->getSyscallArg(4));
7929753Sandreas@sandberg.pp.se    // int offset = tc->getSyscallArg(5);
7939753Sandreas@sandberg.pp.se
7949753Sandreas@sandberg.pp.se    if ((start  % TheISA::VMPageSize) != 0 ||
79510114Sandreas@sandberg.pp.se        (length % TheISA::VMPageSize) != 0) {
7969753Sandreas@sandberg.pp.se        warn("mmap failing: arguments not page-aligned: "
7979753Sandreas@sandberg.pp.se             "start 0x%x length 0x%x",
7989753Sandreas@sandberg.pp.se             start, length);
7999753Sandreas@sandberg.pp.se        return -EINVAL;
8009753Sandreas@sandberg.pp.se    }
8019753Sandreas@sandberg.pp.se
8029753Sandreas@sandberg.pp.se    if (start != 0) {
8039753Sandreas@sandberg.pp.se        warn("mmap: ignoring suggested map address 0x%x, using 0x%x",
8049753Sandreas@sandberg.pp.se             start, p->mmap_end);
8059753Sandreas@sandberg.pp.se    }
8069753Sandreas@sandberg.pp.se
8079753Sandreas@sandberg.pp.se    // pick next address from our "mmap region"
8089753Sandreas@sandberg.pp.se    start = p->mmap_end;
8099753Sandreas@sandberg.pp.se    p->pTable->allocate(start, length);
8109753Sandreas@sandberg.pp.se    p->mmap_end += length;
8119753Sandreas@sandberg.pp.se
8129651SAndreas.Sandberg@ARM.com    if (!(flags & OS::TGT_MAP_ANONYMOUS)) {
8139655SAndreas.Sandberg@ARM.com        warn("allowing mmap of file @ fd %d. "
8149651SAndreas.Sandberg@ARM.com             "This will break if not /dev/zero.", tc->getSyscallArg(4));
8159651SAndreas.Sandberg@ARM.com    }
8169651SAndreas.Sandberg@ARM.com
8179651SAndreas.Sandberg@ARM.com    return start;
8189651SAndreas.Sandberg@ARM.com}
8199651SAndreas.Sandberg@ARM.com
8209651SAndreas.Sandberg@ARM.com/// Target getrlimit() handler.
8219651SAndreas.Sandberg@ARM.comtemplate <class OS>
8229651SAndreas.Sandberg@ARM.comSyscallReturn
8239651SAndreas.Sandberg@ARM.comgetrlimitFunc(SyscallDesc *desc, int callnum, Process *process,
8249651SAndreas.Sandberg@ARM.com        ThreadContext *tc)
8259651SAndreas.Sandberg@ARM.com{
8269651SAndreas.Sandberg@ARM.com    unsigned resource = tc->getSyscallArg(0);
8279651SAndreas.Sandberg@ARM.com    TypedBufferArg<typename OS::rlimit> rlp(tc->getSyscallArg(1));
8289651SAndreas.Sandberg@ARM.com
8299651SAndreas.Sandberg@ARM.com    switch (resource) {
8309651SAndreas.Sandberg@ARM.com        case OS::TGT_RLIMIT_STACK:
8319651SAndreas.Sandberg@ARM.com            // max stack size in bytes: make up a number (2MB for now)
8329651SAndreas.Sandberg@ARM.com            rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024;
8339651SAndreas.Sandberg@ARM.com            rlp->rlim_cur = htog(rlp->rlim_cur);
8349651SAndreas.Sandberg@ARM.com            rlp->rlim_max = htog(rlp->rlim_max);
8359651SAndreas.Sandberg@ARM.com            break;
8369651SAndreas.Sandberg@ARM.com
8379651SAndreas.Sandberg@ARM.com        default:
8389651SAndreas.Sandberg@ARM.com            std::cerr << "getrlimitFunc: unimplemented resource " << resource
8399651SAndreas.Sandberg@ARM.com                << std::endl;
8409651SAndreas.Sandberg@ARM.com            abort();
8419651SAndreas.Sandberg@ARM.com            break;
8429651SAndreas.Sandberg@ARM.com    }
8439651SAndreas.Sandberg@ARM.com
8449651SAndreas.Sandberg@ARM.com    rlp.copyOut(tc->getMemPort());
8459651SAndreas.Sandberg@ARM.com    return 0;
8469651SAndreas.Sandberg@ARM.com}
8479651SAndreas.Sandberg@ARM.com
8489651SAndreas.Sandberg@ARM.com/// Target gettimeofday() handler.
8499651SAndreas.Sandberg@ARM.comtemplate <class OS>
8509651SAndreas.Sandberg@ARM.comSyscallReturn
8519651SAndreas.Sandberg@ARM.comgettimeofdayFunc(SyscallDesc *desc, int callnum, Process *process,
8529651SAndreas.Sandberg@ARM.com        ThreadContext *tc)
8539651SAndreas.Sandberg@ARM.com{
8549651SAndreas.Sandberg@ARM.com    TypedBufferArg<typename OS::timeval> tp(tc->getSyscallArg(0));
8559651SAndreas.Sandberg@ARM.com
8569651SAndreas.Sandberg@ARM.com    getElapsedTime(tp->tv_sec, tp->tv_usec);
8579651SAndreas.Sandberg@ARM.com    tp->tv_sec += seconds_since_epoch;
8589651SAndreas.Sandberg@ARM.com    tp->tv_sec = htog(tp->tv_sec);
8599651SAndreas.Sandberg@ARM.com    tp->tv_usec = htog(tp->tv_usec);
8609651SAndreas.Sandberg@ARM.com
8619651SAndreas.Sandberg@ARM.com    tp.copyOut(tc->getMemPort());
8629651SAndreas.Sandberg@ARM.com
8639651SAndreas.Sandberg@ARM.com    return 0;
8649651SAndreas.Sandberg@ARM.com}
8659651SAndreas.Sandberg@ARM.com
8669651SAndreas.Sandberg@ARM.com
8679651SAndreas.Sandberg@ARM.com/// Target utimes() handler.
8689651SAndreas.Sandberg@ARM.comtemplate <class OS>
8699651SAndreas.Sandberg@ARM.comSyscallReturn
8709651SAndreas.Sandberg@ARM.comutimesFunc(SyscallDesc *desc, int callnum, Process *process,
8719651SAndreas.Sandberg@ARM.com           ThreadContext *tc)
8729651SAndreas.Sandberg@ARM.com{
8739651SAndreas.Sandberg@ARM.com    std::string path;
8749651SAndreas.Sandberg@ARM.com
8759651SAndreas.Sandberg@ARM.com    if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
8769651SAndreas.Sandberg@ARM.com      return -EFAULT;
8779651SAndreas.Sandberg@ARM.com
8789651SAndreas.Sandberg@ARM.com    TypedBufferArg<typename OS::timeval [2]> tp(tc->getSyscallArg(1));
8799651SAndreas.Sandberg@ARM.com    tp.copyIn(tc->getMemPort());
8809651SAndreas.Sandberg@ARM.com
8819651SAndreas.Sandberg@ARM.com    struct timeval hostTimeval[2];
8829651SAndreas.Sandberg@ARM.com    for (int i = 0; i < 2; ++i)
8839651SAndreas.Sandberg@ARM.com    {
8849651SAndreas.Sandberg@ARM.com        hostTimeval[i].tv_sec = gtoh((*tp)[i].tv_sec);
8859651SAndreas.Sandberg@ARM.com        hostTimeval[i].tv_usec = gtoh((*tp)[i].tv_usec);
8869651SAndreas.Sandberg@ARM.com    }
8879651SAndreas.Sandberg@ARM.com    int result = utimes(path.c_str(), hostTimeval);
8889651SAndreas.Sandberg@ARM.com
8899651SAndreas.Sandberg@ARM.com    if (result < 0)
8909651SAndreas.Sandberg@ARM.com        return -errno;
8919651SAndreas.Sandberg@ARM.com
8929651SAndreas.Sandberg@ARM.com    return 0;
8939651SAndreas.Sandberg@ARM.com}
8949651SAndreas.Sandberg@ARM.com/// Target getrusage() function.
8959651SAndreas.Sandberg@ARM.comtemplate <class OS>
8969651SAndreas.Sandberg@ARM.comSyscallReturn
8979651SAndreas.Sandberg@ARM.comgetrusageFunc(SyscallDesc *desc, int callnum, Process *process,
8989651SAndreas.Sandberg@ARM.com              ThreadContext *tc)
8999651SAndreas.Sandberg@ARM.com{
9009651SAndreas.Sandberg@ARM.com    int who = tc->getSyscallArg(0);	// THREAD, SELF, or CHILDREN
9019651SAndreas.Sandberg@ARM.com    TypedBufferArg<typename OS::rusage> rup(tc->getSyscallArg(1));
9029651SAndreas.Sandberg@ARM.com
9039651SAndreas.Sandberg@ARM.com    if (who != OS::TGT_RUSAGE_SELF) {
9049651SAndreas.Sandberg@ARM.com        // don't really handle THREAD or CHILDREN, but just warn and
9059651SAndreas.Sandberg@ARM.com        // plow ahead
9069651SAndreas.Sandberg@ARM.com        warn("getrusage() only supports RUSAGE_SELF.  Parameter %d ignored.",
9079651SAndreas.Sandberg@ARM.com             who);
9089651SAndreas.Sandberg@ARM.com    }
9099651SAndreas.Sandberg@ARM.com
9109651SAndreas.Sandberg@ARM.com    getElapsedTime(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec);
9119651SAndreas.Sandberg@ARM.com    rup->ru_utime.tv_sec = htog(rup->ru_utime.tv_sec);
9129651SAndreas.Sandberg@ARM.com    rup->ru_utime.tv_usec = htog(rup->ru_utime.tv_usec);
9139651SAndreas.Sandberg@ARM.com
9149651SAndreas.Sandberg@ARM.com    rup->ru_stime.tv_sec = 0;
9159651SAndreas.Sandberg@ARM.com    rup->ru_stime.tv_usec = 0;
9169651SAndreas.Sandberg@ARM.com    rup->ru_maxrss = 0;
9179651SAndreas.Sandberg@ARM.com    rup->ru_ixrss = 0;
9189651SAndreas.Sandberg@ARM.com    rup->ru_idrss = 0;
9199651SAndreas.Sandberg@ARM.com    rup->ru_isrss = 0;
9209651SAndreas.Sandberg@ARM.com    rup->ru_minflt = 0;
9219651SAndreas.Sandberg@ARM.com    rup->ru_majflt = 0;
9229651SAndreas.Sandberg@ARM.com    rup->ru_nswap = 0;
9239651SAndreas.Sandberg@ARM.com    rup->ru_inblock = 0;
9249651SAndreas.Sandberg@ARM.com    rup->ru_oublock = 0;
9259651SAndreas.Sandberg@ARM.com    rup->ru_msgsnd = 0;
9269651SAndreas.Sandberg@ARM.com    rup->ru_msgrcv = 0;
92710843Sandreas.sandberg@arm.com    rup->ru_nsignals = 0;
92810843Sandreas.sandberg@arm.com    rup->ru_nvcsw = 0;
92910843Sandreas.sandberg@arm.com    rup->ru_nivcsw = 0;
93010843Sandreas.sandberg@arm.com
93110843Sandreas.sandberg@arm.com    rup.copyOut(tc->getMemPort());
93210843Sandreas.sandberg@arm.com
93310843Sandreas.sandberg@arm.com    return 0;
93410843Sandreas.sandberg@arm.com}
9359651SAndreas.Sandberg@ARM.com
9369651SAndreas.Sandberg@ARM.com
9379651SAndreas.Sandberg@ARM.com
9389651SAndreas.Sandberg@ARM.com
9399651SAndreas.Sandberg@ARM.com#endif // __SIM_SYSCALL_EMUL_HH__
9409651SAndreas.Sandberg@ARM.com