syscall_emul.hh revision 1450
19651SAndreas.Sandberg@ARM.com/*
29651SAndreas.Sandberg@ARM.com * Copyright (c) 2003-2004 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
299651SAndreas.Sandberg@ARM.com#ifndef __SIM_SYSCALL_EMUL_HH__
309651SAndreas.Sandberg@ARM.com#define __SIM_SYSCALL_EMUL_HH__
319651SAndreas.Sandberg@ARM.com
329651SAndreas.Sandberg@ARM.com///
339651SAndreas.Sandberg@ARM.com/// @file syscall_emul.hh
349651SAndreas.Sandberg@ARM.com///
359651SAndreas.Sandberg@ARM.com/// This file defines objects used to emulate syscalls from the target
369651SAndreas.Sandberg@ARM.com/// application on the host machine.
379651SAndreas.Sandberg@ARM.com
389651SAndreas.Sandberg@ARM.com#include <errno.h>
399651SAndreas.Sandberg@ARM.com#include <string>
409651SAndreas.Sandberg@ARM.com
419651SAndreas.Sandberg@ARM.com#include "base/intmath.hh"	// for RoundUp
429651SAndreas.Sandberg@ARM.com#include "mem/functional_mem/functional_memory.hh"
439651SAndreas.Sandberg@ARM.com#include "targetarch/isa_traits.hh"	// for Addr
449651SAndreas.Sandberg@ARM.com
459651SAndreas.Sandberg@ARM.com#include "base/trace.hh"
469651SAndreas.Sandberg@ARM.com#include "cpu/exec_context.hh"
479651SAndreas.Sandberg@ARM.com#include "sim/process.hh"
489651SAndreas.Sandberg@ARM.com
499651SAndreas.Sandberg@ARM.com///
509651SAndreas.Sandberg@ARM.com/// System call descriptor.
519683Sandreas@sandberg.pp.se///
529753Sandreas@sandberg.pp.seclass SyscallDesc {
539651SAndreas.Sandberg@ARM.com
549651SAndreas.Sandberg@ARM.com  public:
559651SAndreas.Sandberg@ARM.com
569651SAndreas.Sandberg@ARM.com    /// Typedef for target syscall handler functions.
579651SAndreas.Sandberg@ARM.com    typedef SyscallReturn (*FuncPtr)(SyscallDesc *, int num,
589651SAndreas.Sandberg@ARM.com                           Process *, ExecContext *);
599651SAndreas.Sandberg@ARM.com
609753Sandreas@sandberg.pp.se    const char *name;	//!< Syscall name (e.g., "open").
619753Sandreas@sandberg.pp.se    FuncPtr funcPtr;	//!< Pointer to emulation function.
629651SAndreas.Sandberg@ARM.com    int flags;		//!< Flags (see Flags enum).
639651SAndreas.Sandberg@ARM.com
649651SAndreas.Sandberg@ARM.com    /// Flag values for controlling syscall behavior.
659651SAndreas.Sandberg@ARM.com    enum Flags {
669651SAndreas.Sandberg@ARM.com        /// Don't set return regs according to funcPtr return value.
679651SAndreas.Sandberg@ARM.com        /// Used for syscalls with non-standard return conventions
689651SAndreas.Sandberg@ARM.com        /// that explicitly set the ExecContext regs (e.g.,
699651SAndreas.Sandberg@ARM.com        /// sigreturn).
709651SAndreas.Sandberg@ARM.com        SuppressReturnValue = 1
719651SAndreas.Sandberg@ARM.com    };
729651SAndreas.Sandberg@ARM.com
739651SAndreas.Sandberg@ARM.com    /// Constructor.
749651SAndreas.Sandberg@ARM.com    SyscallDesc(const char *_name, FuncPtr _funcPtr, int _flags = 0)
759651SAndreas.Sandberg@ARM.com        : name(_name), funcPtr(_funcPtr), flags(_flags)
769651SAndreas.Sandberg@ARM.com    {
779651SAndreas.Sandberg@ARM.com    }
789651SAndreas.Sandberg@ARM.com
799652SAndreas.Sandberg@ARM.com    /// Emulate the syscall.  Public interface for calling through funcPtr.
809652SAndreas.Sandberg@ARM.com    void doSyscall(int callnum, Process *proc, ExecContext *xc);
819651SAndreas.Sandberg@ARM.com};
829651SAndreas.Sandberg@ARM.com
839651SAndreas.Sandberg@ARM.com
849651SAndreas.Sandberg@ARM.comclass BaseBufferArg {
859655SAndreas.Sandberg@ARM.com
869754Sandreas@sandberg.pp.se  public:
879752Sandreas@sandberg.pp.se
889753Sandreas@sandberg.pp.se    BaseBufferArg(Addr _addr, int _size) : addr(_addr), size(_size)
899752Sandreas@sandberg.pp.se    {
909651SAndreas.Sandberg@ARM.com        bufPtr = new uint8_t[size];
919651SAndreas.Sandberg@ARM.com        // clear out buffer: in case we only partially populate this,
929651SAndreas.Sandberg@ARM.com        // and then do a copyOut(), we want to make sure we don't
939651SAndreas.Sandberg@ARM.com        // introduce any random junk into the simulated address space
949651SAndreas.Sandberg@ARM.com        memset(bufPtr, 0, size);
959651SAndreas.Sandberg@ARM.com    }
969651SAndreas.Sandberg@ARM.com
979651SAndreas.Sandberg@ARM.com    virtual ~BaseBufferArg() { delete [] bufPtr; }
989651SAndreas.Sandberg@ARM.com
999651SAndreas.Sandberg@ARM.com    //
1009651SAndreas.Sandberg@ARM.com    // copy data into simulator space (read from target memory)
1019651SAndreas.Sandberg@ARM.com    //
1029651SAndreas.Sandberg@ARM.com    virtual bool copyIn(FunctionalMemory *mem)
1039655SAndreas.Sandberg@ARM.com    {
1049655SAndreas.Sandberg@ARM.com        mem->access(Read, addr, bufPtr, size);
1059655SAndreas.Sandberg@ARM.com        return true;	// no EFAULT detection for now
1069655SAndreas.Sandberg@ARM.com    }
1079754Sandreas@sandberg.pp.se
1089655SAndreas.Sandberg@ARM.com    //
1099655SAndreas.Sandberg@ARM.com    // copy data out of simulator space (write to target memory)
1109655SAndreas.Sandberg@ARM.com    //
1119754Sandreas@sandberg.pp.se    virtual bool copyOut(FunctionalMemory *mem)
1129651SAndreas.Sandberg@ARM.com    {
1139651SAndreas.Sandberg@ARM.com        mem->access(Write, addr, bufPtr, size);
1149651SAndreas.Sandberg@ARM.com        return true;	// no EFAULT detection for now
1159651SAndreas.Sandberg@ARM.com    }
1169651SAndreas.Sandberg@ARM.com
1179651SAndreas.Sandberg@ARM.com  protected:
1189651SAndreas.Sandberg@ARM.com    Addr addr;
1199651SAndreas.Sandberg@ARM.com    int size;
1209651SAndreas.Sandberg@ARM.com    uint8_t *bufPtr;
1219651SAndreas.Sandberg@ARM.com};
1229651SAndreas.Sandberg@ARM.com
1239651SAndreas.Sandberg@ARM.com
1249651SAndreas.Sandberg@ARM.comclass BufferArg : public BaseBufferArg
1259651SAndreas.Sandberg@ARM.com{
1269651SAndreas.Sandberg@ARM.com  public:
1279651SAndreas.Sandberg@ARM.com    BufferArg(Addr _addr, int _size) : BaseBufferArg(_addr, _size) { }
1289651SAndreas.Sandberg@ARM.com    void *bufferPtr()	{ return bufPtr; }
1299651SAndreas.Sandberg@ARM.com};
1309651SAndreas.Sandberg@ARM.com
1319651SAndreas.Sandberg@ARM.comtemplate <class T>
1329651SAndreas.Sandberg@ARM.comclass TypedBufferArg : public BaseBufferArg
1339651SAndreas.Sandberg@ARM.com{
1349651SAndreas.Sandberg@ARM.com  public:
1359651SAndreas.Sandberg@ARM.com    // user can optionally specify a specific number of bytes to
1369651SAndreas.Sandberg@ARM.com    // allocate to deal with those structs that have variable-size
1379651SAndreas.Sandberg@ARM.com    // arrays at the end
1389651SAndreas.Sandberg@ARM.com    TypedBufferArg(Addr _addr, int _size = sizeof(T))
1399651SAndreas.Sandberg@ARM.com        : BaseBufferArg(_addr, _size)
1409651SAndreas.Sandberg@ARM.com    { }
1419690Sandreas@sandberg.pp.se
1429690Sandreas@sandberg.pp.se    // type case
1439690Sandreas@sandberg.pp.se    operator T*() { return (T *)bufPtr; }
1449651SAndreas.Sandberg@ARM.com
1459651SAndreas.Sandberg@ARM.com    // dereference operators
1469651SAndreas.Sandberg@ARM.com    T &operator*()	 { return *((T *)bufPtr); }
1479651SAndreas.Sandberg@ARM.com    T* operator->()	 { return (T *)bufPtr; }
1489651SAndreas.Sandberg@ARM.com    T &operator[](int i) { return ((T *)bufPtr)[i]; }
1499651SAndreas.Sandberg@ARM.com};
1509651SAndreas.Sandberg@ARM.com
1519651SAndreas.Sandberg@ARM.com//////////////////////////////////////////////////////////////////////
1529651SAndreas.Sandberg@ARM.com//
1539651SAndreas.Sandberg@ARM.com// The following emulation functions are generic enough that they
1549651SAndreas.Sandberg@ARM.com// don't need to be recompiled for different emulated OS's.  They are
1559651SAndreas.Sandberg@ARM.com// defined in sim/syscall_emul.cc.
1569651SAndreas.Sandberg@ARM.com//
1579651SAndreas.Sandberg@ARM.com//////////////////////////////////////////////////////////////////////
1589753Sandreas@sandberg.pp.se
1599753Sandreas@sandberg.pp.se
1609753Sandreas@sandberg.pp.se/// Handler for unimplemented syscalls that we haven't thought about.
1619753Sandreas@sandberg.pp.seSyscallReturn unimplementedFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
1629651SAndreas.Sandberg@ARM.com
1639651SAndreas.Sandberg@ARM.com/// Handler for unimplemented syscalls that we never intend to
1649651SAndreas.Sandberg@ARM.com/// implement (signal handling, etc.) and should not affect the correct
1659651SAndreas.Sandberg@ARM.com/// behavior of the program.  Print a warning only if the appropriate
1669651SAndreas.Sandberg@ARM.com/// trace flag is enabled.  Return success to the target program.
1679651SAndreas.Sandberg@ARM.comSyscallReturn ignoreFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
1689651SAndreas.Sandberg@ARM.com
1699651SAndreas.Sandberg@ARM.com/// Target exit() handler: terminate simulation.
1709651SAndreas.Sandberg@ARM.comSyscallReturn exitFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
1719651SAndreas.Sandberg@ARM.com
1729651SAndreas.Sandberg@ARM.com/// Target getpagesize() handler.
1739651SAndreas.Sandberg@ARM.comSyscallReturn getpagesizeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
1749690Sandreas@sandberg.pp.se
1759690Sandreas@sandberg.pp.se/// Target obreak() handler: set brk address.
1769690Sandreas@sandberg.pp.seSyscallReturn obreakFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
1779651SAndreas.Sandberg@ARM.com
1789651SAndreas.Sandberg@ARM.com/// Target close() handler.
1799651SAndreas.Sandberg@ARM.comSyscallReturn closeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
1809651SAndreas.Sandberg@ARM.com
1819651SAndreas.Sandberg@ARM.com/// Target read() handler.
1829651SAndreas.Sandberg@ARM.comSyscallReturn readFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
1839732Sandreas@sandberg.pp.se
1849732Sandreas@sandberg.pp.se/// Target write() handler.
1859651SAndreas.Sandberg@ARM.comSyscallReturn writeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
1869651SAndreas.Sandberg@ARM.com
1879651SAndreas.Sandberg@ARM.com/// Target lseek() handler.
1889651SAndreas.Sandberg@ARM.comSyscallReturn lseekFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
1899651SAndreas.Sandberg@ARM.com
1909651SAndreas.Sandberg@ARM.com/// Target munmap() handler.
1919651SAndreas.Sandberg@ARM.comSyscallReturn munmapFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
1929651SAndreas.Sandberg@ARM.com
1939651SAndreas.Sandberg@ARM.com/// Target gethostname() handler.
1949684Sandreas@sandberg.pp.seSyscallReturn gethostnameFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
1959684Sandreas@sandberg.pp.se
1969684Sandreas@sandberg.pp.se/// Target unlink() handler.
1979684Sandreas@sandberg.pp.seSyscallReturn unlinkFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
1989684Sandreas@sandberg.pp.se
1999651SAndreas.Sandberg@ARM.com/// Target rename() handler.
2009651SAndreas.Sandberg@ARM.comSyscallReturn renameFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
2019651SAndreas.Sandberg@ARM.com
2029651SAndreas.Sandberg@ARM.com/// This struct is used to build an target-OS-dependent table that
2039651SAndreas.Sandberg@ARM.com/// maps the target's open() flags to the host open() flags.
2049755Sandreas@sandberg.pp.sestruct OpenFlagTransTable {
2059755Sandreas@sandberg.pp.se    int tgtFlag;	//!< Target system flag value.
2069755Sandreas@sandberg.pp.se    int hostFlag;	//!< Corresponding host system flag value.
2079755Sandreas@sandberg.pp.se};
2089755Sandreas@sandberg.pp.se
2099755Sandreas@sandberg.pp.se
2109755Sandreas@sandberg.pp.se
2119755Sandreas@sandberg.pp.se/// A readable name for 1,000,000, for converting microseconds to seconds.
2129755Sandreas@sandberg.pp.seconst int one_million = 1000000;
2139755Sandreas@sandberg.pp.se
2149651SAndreas.Sandberg@ARM.com/// Approximate seconds since the epoch (1/1/1970).  About a billion,
2159651SAndreas.Sandberg@ARM.com/// by my reckoning.  We want to keep this a constant (not use the
2169651SAndreas.Sandberg@ARM.com/// real-world time) to keep simulations repeatable.
2179651SAndreas.Sandberg@ARM.comconst unsigned seconds_since_epoch = 1000000000;
2189651SAndreas.Sandberg@ARM.com
2199651SAndreas.Sandberg@ARM.com/// Helper function to convert current elapsed time to seconds and
2209651SAndreas.Sandberg@ARM.com/// microseconds.
2219651SAndreas.Sandberg@ARM.comtemplate <class T1, class T2>
2229651SAndreas.Sandberg@ARM.comvoid
2239651SAndreas.Sandberg@ARM.comgetElapsedTime(T1 &sec, T2 &usec)
2249651SAndreas.Sandberg@ARM.com{
2259651SAndreas.Sandberg@ARM.com    int cycles_per_usec = ticksPerSecond / one_million;
2269651SAndreas.Sandberg@ARM.com
2279651SAndreas.Sandberg@ARM.com    int elapsed_usecs = curTick / cycles_per_usec;
2289651SAndreas.Sandberg@ARM.com    sec = elapsed_usecs / one_million;
2299651SAndreas.Sandberg@ARM.com    usec = elapsed_usecs % one_million;
2309651SAndreas.Sandberg@ARM.com}
2319651SAndreas.Sandberg@ARM.com
2329651SAndreas.Sandberg@ARM.com//////////////////////////////////////////////////////////////////////
2339651SAndreas.Sandberg@ARM.com//
2349651SAndreas.Sandberg@ARM.com// The following emulation functions are generic, but need to be
2359651SAndreas.Sandberg@ARM.com// templated to account for differences in types, constants, etc.
2369651SAndreas.Sandberg@ARM.com//
2379651SAndreas.Sandberg@ARM.com//////////////////////////////////////////////////////////////////////
2389651SAndreas.Sandberg@ARM.com
2399651SAndreas.Sandberg@ARM.com/// Target ioctl() handler.  For the most part, programs call ioctl()
2409651SAndreas.Sandberg@ARM.com/// only to find out if their stdout is a tty, to determine whether to
2419651SAndreas.Sandberg@ARM.com/// do line or block buffering.
2429651SAndreas.Sandberg@ARM.comtemplate <class OS>
2439651SAndreas.Sandberg@ARM.comSyscallReturn
2449651SAndreas.Sandberg@ARM.comioctlFunc(SyscallDesc *desc, int callnum, Process *process,
2459651SAndreas.Sandberg@ARM.com          ExecContext *xc)
2469651SAndreas.Sandberg@ARM.com{
2479651SAndreas.Sandberg@ARM.com    int fd = xc->getSyscallArg(0);
2489683Sandreas@sandberg.pp.se    unsigned req = xc->getSyscallArg(1);
2499683Sandreas@sandberg.pp.se
2509683Sandreas@sandberg.pp.se    // DPRINTFR(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", fd, req);
2519683Sandreas@sandberg.pp.se
2529683Sandreas@sandberg.pp.se    if (fd < 0 || process->sim_fd(fd) < 0) {
2539651SAndreas.Sandberg@ARM.com        // doesn't map to any simulator fd: not a valid target fd
2549651SAndreas.Sandberg@ARM.com        return SyscallReturn(-EBADF);
2559651SAndreas.Sandberg@ARM.com    }
2569651SAndreas.Sandberg@ARM.com
2579651SAndreas.Sandberg@ARM.com    switch (req) {
2589651SAndreas.Sandberg@ARM.com      case OS::TIOCISATTY:
2599651SAndreas.Sandberg@ARM.com      case OS::TIOCGETP:
2609651SAndreas.Sandberg@ARM.com      case OS::TIOCSETP:
2619651SAndreas.Sandberg@ARM.com      case OS::TIOCSETN:
2629683Sandreas@sandberg.pp.se      case OS::TIOCSETC:
2639683Sandreas@sandberg.pp.se      case OS::TIOCGETC:
2649651SAndreas.Sandberg@ARM.com      case OS::TIOCGETS:
2659651SAndreas.Sandberg@ARM.com      case OS::TIOCGETA:
2669651SAndreas.Sandberg@ARM.com        return SyscallReturn(-ENOTTY);
2679652SAndreas.Sandberg@ARM.com
2689651SAndreas.Sandberg@ARM.com      default:
2699651SAndreas.Sandberg@ARM.com        fatal("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ 0x%llx\n", fd, req, xc->readPC());
2709651SAndreas.Sandberg@ARM.com    }
2719651SAndreas.Sandberg@ARM.com}
2729651SAndreas.Sandberg@ARM.com
2739651SAndreas.Sandberg@ARM.com/// Target open() handler.
2749651SAndreas.Sandberg@ARM.comtemplate <class OS>
2759651SAndreas.Sandberg@ARM.comSyscallReturn
2769753Sandreas@sandberg.pp.seopenFunc(SyscallDesc *desc, int callnum, Process *process,
2779753Sandreas@sandberg.pp.se         ExecContext *xc)
2789753Sandreas@sandberg.pp.se{
2799753Sandreas@sandberg.pp.se    std::string path;
2809753Sandreas@sandberg.pp.se
2819753Sandreas@sandberg.pp.se    if (xc->mem->readString(path, xc->getSyscallArg(0)) != No_Fault)
2829753Sandreas@sandberg.pp.se        return SyscallReturn(-EFAULT);
2839753Sandreas@sandberg.pp.se
2849753Sandreas@sandberg.pp.se    if (path == "/dev/sysdev0") {
2859753Sandreas@sandberg.pp.se        // This is a memory-mapped high-resolution timer device on Alpha.
2869753Sandreas@sandberg.pp.se        // We don't support it, so just punt.
2879753Sandreas@sandberg.pp.se        DCOUT(SyscallWarnings) << "Ignoring open(" << path << ", ...)" << std::endl;
2889651SAndreas.Sandberg@ARM.com        return SyscallReturn(-ENOENT);
2899753Sandreas@sandberg.pp.se    }
2909753Sandreas@sandberg.pp.se
2919753Sandreas@sandberg.pp.se    int tgtFlags = xc->getSyscallArg(1);
2929753Sandreas@sandberg.pp.se    int mode = xc->getSyscallArg(2);
2939753Sandreas@sandberg.pp.se    int hostFlags = 0;
2949753Sandreas@sandberg.pp.se
2959753Sandreas@sandberg.pp.se    // translate open flags
2969651SAndreas.Sandberg@ARM.com    for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) {
2979753Sandreas@sandberg.pp.se        if (tgtFlags & OS::openFlagTable[i].tgtFlag) {
2989753Sandreas@sandberg.pp.se            tgtFlags &= ~OS::openFlagTable[i].tgtFlag;
2999753Sandreas@sandberg.pp.se            hostFlags |= OS::openFlagTable[i].hostFlag;
3009753Sandreas@sandberg.pp.se        }
3019753Sandreas@sandberg.pp.se    }
3029753Sandreas@sandberg.pp.se
3039753Sandreas@sandberg.pp.se    // any target flags left?
3049753Sandreas@sandberg.pp.se    if (tgtFlags != 0)
3059753Sandreas@sandberg.pp.se        std::cerr << "Syscall: open: cannot decode flags: " <<  tgtFlags << std::endl;
3069753Sandreas@sandberg.pp.se
3079753Sandreas@sandberg.pp.se#ifdef __CYGWIN32__
3089753Sandreas@sandberg.pp.se    hostFlags |= O_BINARY;
3099753Sandreas@sandberg.pp.se#endif
3109753Sandreas@sandberg.pp.se
3119753Sandreas@sandberg.pp.se    // open the file
3129753Sandreas@sandberg.pp.se    int fd = open(path.c_str(), hostFlags, mode);
3139753Sandreas@sandberg.pp.se
3149753Sandreas@sandberg.pp.se    return (fd == -1) ? SyscallReturn(-errno) : SyscallReturn(process->open_fd(fd));
3159753Sandreas@sandberg.pp.se}
3169753Sandreas@sandberg.pp.se
3179753Sandreas@sandberg.pp.se
3189753Sandreas@sandberg.pp.se/// Target stat() handler.
3199753Sandreas@sandberg.pp.setemplate <class OS>
3209753Sandreas@sandberg.pp.seSyscallReturn
3219753Sandreas@sandberg.pp.sestatFunc(SyscallDesc *desc, int callnum, Process *process,
3229753Sandreas@sandberg.pp.se         ExecContext *xc)
3239753Sandreas@sandberg.pp.se{
3249753Sandreas@sandberg.pp.se    std::string path;
3259753Sandreas@sandberg.pp.se
3269753Sandreas@sandberg.pp.se    if (xc->mem->readString(path, xc->getSyscallArg(0)) != No_Fault)
3279753Sandreas@sandberg.pp.se        return SyscallReturn(-EFAULT);
3289753Sandreas@sandberg.pp.se
3299753Sandreas@sandberg.pp.se    struct stat hostBuf;
3309753Sandreas@sandberg.pp.se    int result = stat(path.c_str(), &hostBuf);
3319753Sandreas@sandberg.pp.se
3329651SAndreas.Sandberg@ARM.com    if (result < 0)
3339651SAndreas.Sandberg@ARM.com        return SyscallReturn(errno);
3349651SAndreas.Sandberg@ARM.com
3359651SAndreas.Sandberg@ARM.com    OS::copyOutStatBuf(xc->mem, xc->getSyscallArg(1), &hostBuf);
3369651SAndreas.Sandberg@ARM.com
3379651SAndreas.Sandberg@ARM.com    return SyscallReturn(0);
3389651SAndreas.Sandberg@ARM.com}
3399651SAndreas.Sandberg@ARM.com
3409651SAndreas.Sandberg@ARM.com
3419651SAndreas.Sandberg@ARM.com/// Target lstat() handler.
3429651SAndreas.Sandberg@ARM.comtemplate <class OS>
3439651SAndreas.Sandberg@ARM.comSyscallReturn
3449651SAndreas.Sandberg@ARM.comlstatFunc(SyscallDesc *desc, int callnum, Process *process,
3459651SAndreas.Sandberg@ARM.com          ExecContext *xc)
3469651SAndreas.Sandberg@ARM.com{
3479651SAndreas.Sandberg@ARM.com    std::string path;
3489651SAndreas.Sandberg@ARM.com
3499651SAndreas.Sandberg@ARM.com    if (xc->mem->readString(path, xc->getSyscallArg(0)) != No_Fault)
3509651SAndreas.Sandberg@ARM.com        return SyscallReturn(-EFAULT);
3519651SAndreas.Sandberg@ARM.com
3529651SAndreas.Sandberg@ARM.com    struct stat hostBuf;
3539651SAndreas.Sandberg@ARM.com    int result = lstat(path.c_str(), &hostBuf);
3549651SAndreas.Sandberg@ARM.com
3559651SAndreas.Sandberg@ARM.com    if (result < 0)
3569651SAndreas.Sandberg@ARM.com        return SyscallReturn(-errno);
3579651SAndreas.Sandberg@ARM.com
3589651SAndreas.Sandberg@ARM.com    OS::copyOutStatBuf(xc->mem, xc->getSyscallArg(1), &hostBuf);
3599651SAndreas.Sandberg@ARM.com
3609652SAndreas.Sandberg@ARM.com    return SyscallReturn(0);
3619652SAndreas.Sandberg@ARM.com}
3629651SAndreas.Sandberg@ARM.com
3639651SAndreas.Sandberg@ARM.com/// Target fstat() handler.
3649651SAndreas.Sandberg@ARM.comtemplate <class OS>
3659651SAndreas.Sandberg@ARM.comSyscallReturn
3669651SAndreas.Sandberg@ARM.comfstatFunc(SyscallDesc *desc, int callnum, Process *process,
3679651SAndreas.Sandberg@ARM.com          ExecContext *xc)
3689651SAndreas.Sandberg@ARM.com{
3699651SAndreas.Sandberg@ARM.com    int fd = process->sim_fd(xc->getSyscallArg(0));
3709651SAndreas.Sandberg@ARM.com
3719651SAndreas.Sandberg@ARM.com    // DPRINTFR(SyscallVerbose, "fstat(%d, ...)\n", fd);
3729651SAndreas.Sandberg@ARM.com
3739651SAndreas.Sandberg@ARM.com    if (fd < 0)
3749651SAndreas.Sandberg@ARM.com        return SyscallReturn(-EBADF);
3759651SAndreas.Sandberg@ARM.com
3769651SAndreas.Sandberg@ARM.com    struct stat hostBuf;
3779651SAndreas.Sandberg@ARM.com    int result = fstat(fd, &hostBuf);
3789651SAndreas.Sandberg@ARM.com
3799651SAndreas.Sandberg@ARM.com    if (result < 0)
3809651SAndreas.Sandberg@ARM.com        return SyscallReturn(-errno);
3819651SAndreas.Sandberg@ARM.com
3829651SAndreas.Sandberg@ARM.com    OS::copyOutStatBuf(xc->mem, xc->getSyscallArg(1), &hostBuf);
3839651SAndreas.Sandberg@ARM.com
3849651SAndreas.Sandberg@ARM.com    return SyscallReturn(0);
3859753Sandreas@sandberg.pp.se}
3869753Sandreas@sandberg.pp.se
3879753Sandreas@sandberg.pp.se
3889753Sandreas@sandberg.pp.se/// Target mmap() handler.
3899753Sandreas@sandberg.pp.se///
3909753Sandreas@sandberg.pp.se/// We don't really handle mmap().  If the target is mmaping an
3919651SAndreas.Sandberg@ARM.com/// anonymous region or /dev/zero, we can get away with doing basically
3929651SAndreas.Sandberg@ARM.com/// nothing (since memory is initialized to zero and the simulator
3939651SAndreas.Sandberg@ARM.com/// doesn't really check addresses anyway).  Always print a warning,
3949651SAndreas.Sandberg@ARM.com/// since this could be seriously broken if we're not mapping
3959651SAndreas.Sandberg@ARM.com/// /dev/zero.
3969651SAndreas.Sandberg@ARM.com//
3979651SAndreas.Sandberg@ARM.com/// Someday we should explicitly check for /dev/zero in open, flag the
3989651SAndreas.Sandberg@ARM.com/// file descriptor, and fail (or implement!) a non-anonymous mmap to
3999651SAndreas.Sandberg@ARM.com/// anything else.
4009651SAndreas.Sandberg@ARM.comtemplate <class OS>
4019651SAndreas.Sandberg@ARM.comSyscallReturn
4029651SAndreas.Sandberg@ARM.commmapFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
4039651SAndreas.Sandberg@ARM.com{
4049651SAndreas.Sandberg@ARM.com    Addr start = xc->getSyscallArg(0);
4059651SAndreas.Sandberg@ARM.com    uint64_t length = xc->getSyscallArg(1);
4069651SAndreas.Sandberg@ARM.com    // int prot = xc->getSyscallArg(2);
4079651SAndreas.Sandberg@ARM.com    int flags = xc->getSyscallArg(3);
4089651SAndreas.Sandberg@ARM.com    // int fd = p->sim_fd(xc->getSyscallArg(4));
4099651SAndreas.Sandberg@ARM.com    // int offset = xc->getSyscallArg(5);
4109651SAndreas.Sandberg@ARM.com
4119651SAndreas.Sandberg@ARM.com    if (start == 0) {
4129651SAndreas.Sandberg@ARM.com        // user didn't give an address... pick one from our "mmap region"
4139651SAndreas.Sandberg@ARM.com        start = p->mmap_end;
4149651SAndreas.Sandberg@ARM.com        p->mmap_end += RoundUp<Addr>(length, VMPageSize);
4159651SAndreas.Sandberg@ARM.com    }
4169651SAndreas.Sandberg@ARM.com
4179651SAndreas.Sandberg@ARM.com    if (!(flags & OS::TGT_MAP_ANONYMOUS)) {
4189651SAndreas.Sandberg@ARM.com        DPRINTF(SyscallWarnings, "Warning: allowing mmap of file @ fd %d.  "
4199651SAndreas.Sandberg@ARM.com                "This will break if not /dev/zero.", xc->getSyscallArg(4));
4209651SAndreas.Sandberg@ARM.com    }
4219651SAndreas.Sandberg@ARM.com
4229651SAndreas.Sandberg@ARM.com    return SyscallReturn(start);
4239651SAndreas.Sandberg@ARM.com}
4249754Sandreas@sandberg.pp.se
4259651SAndreas.Sandberg@ARM.com/// Target getrlimit() handler.
4269651SAndreas.Sandberg@ARM.comtemplate <class OS>
4279651SAndreas.Sandberg@ARM.comSyscallReturn
4289651SAndreas.Sandberg@ARM.comgetrlimitFunc(SyscallDesc *desc, int callnum, Process *process,
4299651SAndreas.Sandberg@ARM.com              ExecContext *xc)
4309651SAndreas.Sandberg@ARM.com{
4319651SAndreas.Sandberg@ARM.com    unsigned resource = xc->getSyscallArg(0);
4329651SAndreas.Sandberg@ARM.com    TypedBufferArg<typename OS::rlimit> rlp(xc->getSyscallArg(1));
4339651SAndreas.Sandberg@ARM.com
4349651SAndreas.Sandberg@ARM.com    switch (resource) {
4359651SAndreas.Sandberg@ARM.com      case OS::RLIMIT_STACK:
4369651SAndreas.Sandberg@ARM.com        // max stack size in bytes: make up a number (2MB for now)
4379651SAndreas.Sandberg@ARM.com        rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024;
4389651SAndreas.Sandberg@ARM.com        break;
4399651SAndreas.Sandberg@ARM.com
4409651SAndreas.Sandberg@ARM.com      default:
4419651SAndreas.Sandberg@ARM.com        std::cerr << "getrlimitFunc: unimplemented resource " << resource << std::endl;
4429651SAndreas.Sandberg@ARM.com        abort();
4439651SAndreas.Sandberg@ARM.com        break;
4449651SAndreas.Sandberg@ARM.com    }
4459651SAndreas.Sandberg@ARM.com
4469651SAndreas.Sandberg@ARM.com    rlp.copyOut(xc->mem);
4479651SAndreas.Sandberg@ARM.com    return SyscallReturn(0);
4489651SAndreas.Sandberg@ARM.com}
4499651SAndreas.Sandberg@ARM.com
4509651SAndreas.Sandberg@ARM.com/// Target gettimeofday() handler.
4519651SAndreas.Sandberg@ARM.comtemplate <class OS>
4529651SAndreas.Sandberg@ARM.comSyscallReturn
4539651SAndreas.Sandberg@ARM.comgettimeofdayFunc(SyscallDesc *desc, int callnum, Process *process,
4549651SAndreas.Sandberg@ARM.com                 ExecContext *xc)
4559651SAndreas.Sandberg@ARM.com{
4569651SAndreas.Sandberg@ARM.com    TypedBufferArg<typename OS::timeval> tp(xc->getSyscallArg(0));
4579651SAndreas.Sandberg@ARM.com
4589651SAndreas.Sandberg@ARM.com    getElapsedTime(tp->tv_sec, tp->tv_usec);
4599651SAndreas.Sandberg@ARM.com    tp->tv_sec += seconds_since_epoch;
4609651SAndreas.Sandberg@ARM.com
4619651SAndreas.Sandberg@ARM.com    tp.copyOut(xc->mem);
4629651SAndreas.Sandberg@ARM.com
4639651SAndreas.Sandberg@ARM.com    return SyscallReturn(0);
4649651SAndreas.Sandberg@ARM.com}
4659651SAndreas.Sandberg@ARM.com
4669651SAndreas.Sandberg@ARM.com
4679651SAndreas.Sandberg@ARM.com/// Target getrusage() function.
4689652SAndreas.Sandberg@ARM.comtemplate <class OS>
4699652SAndreas.Sandberg@ARM.comSyscallReturn
4709652SAndreas.Sandberg@ARM.comgetrusageFunc(SyscallDesc *desc, int callnum, Process *process,
4719652SAndreas.Sandberg@ARM.com              ExecContext *xc)
4729652SAndreas.Sandberg@ARM.com{
4739652SAndreas.Sandberg@ARM.com    int who = xc->getSyscallArg(0);	// THREAD, SELF, or CHILDREN
4749652SAndreas.Sandberg@ARM.com    TypedBufferArg<typename OS::rusage> rup(xc->getSyscallArg(1));
4759652SAndreas.Sandberg@ARM.com
4769652SAndreas.Sandberg@ARM.com    if (who != OS::RUSAGE_SELF) {
4779651SAndreas.Sandberg@ARM.com        // don't really handle THREAD or CHILDREN, but just warn and
4789651SAndreas.Sandberg@ARM.com        // plow ahead
4799651SAndreas.Sandberg@ARM.com        DCOUT(SyscallWarnings)
4809752Sandreas@sandberg.pp.se            << "Warning: getrusage() only supports RUSAGE_SELF."
4819651SAndreas.Sandberg@ARM.com            << "  Parameter " << who << " ignored." << std::endl;
4829651SAndreas.Sandberg@ARM.com    }
4839651SAndreas.Sandberg@ARM.com
4849651SAndreas.Sandberg@ARM.com    getElapsedTime(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec);
4859651SAndreas.Sandberg@ARM.com    rup->ru_stime.tv_sec = 0;
4869651SAndreas.Sandberg@ARM.com    rup->ru_stime.tv_usec = 0;
4879752Sandreas@sandberg.pp.se    rup->ru_maxrss = 0;
4889651SAndreas.Sandberg@ARM.com    rup->ru_ixrss = 0;
4899651SAndreas.Sandberg@ARM.com    rup->ru_idrss = 0;
4909651SAndreas.Sandberg@ARM.com    rup->ru_isrss = 0;
4919651SAndreas.Sandberg@ARM.com    rup->ru_minflt = 0;
4929651SAndreas.Sandberg@ARM.com    rup->ru_majflt = 0;
4939651SAndreas.Sandberg@ARM.com    rup->ru_nswap = 0;
4949651SAndreas.Sandberg@ARM.com    rup->ru_inblock = 0;
4959651SAndreas.Sandberg@ARM.com    rup->ru_oublock = 0;
4969651SAndreas.Sandberg@ARM.com    rup->ru_msgsnd = 0;
4979651SAndreas.Sandberg@ARM.com    rup->ru_msgrcv = 0;
4989651SAndreas.Sandberg@ARM.com    rup->ru_nsignals = 0;
4999753Sandreas@sandberg.pp.se    rup->ru_nvcsw = 0;
5009753Sandreas@sandberg.pp.se    rup->ru_nivcsw = 0;
5019651SAndreas.Sandberg@ARM.com
5029651SAndreas.Sandberg@ARM.com    rup.copyOut(xc->mem);
5039753Sandreas@sandberg.pp.se
5049753Sandreas@sandberg.pp.se    return SyscallReturn(0);
5059753Sandreas@sandberg.pp.se}
5069753Sandreas@sandberg.pp.se
5079753Sandreas@sandberg.pp.se#endif // __SIM_SYSCALL_EMUL_HH__
5089753Sandreas@sandberg.pp.se