syscall_emul.hh revision 2474
12381SN/A/*
28853Sandreas.hansson@arm.com * Copyright (c) 2003-2005 The Regents of The University of Michigan
38711Sandreas.hansson@arm.com * All rights reserved.
48711Sandreas.hansson@arm.com *
58711Sandreas.hansson@arm.com * Redistribution and use in source and binary forms, with or without
68711Sandreas.hansson@arm.com * modification, are permitted provided that the following conditions are
78711Sandreas.hansson@arm.com * met: redistributions of source code must retain the above copyright
88711Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer;
98711Sandreas.hansson@arm.com * redistributions in binary form must reproduce the above copyright
108711Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer in the
118711Sandreas.hansson@arm.com * documentation and/or other materials provided with the distribution;
128711Sandreas.hansson@arm.com * neither the name of the copyright holders nor the names of its
138711Sandreas.hansson@arm.com * contributors may be used to endorse or promote products derived from
142381SN/A * this software without specific prior written permission.
152381SN/A *
162381SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172381SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182381SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192381SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202381SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212381SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222381SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232381SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242381SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252381SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262381SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272381SN/A */
282381SN/A
292381SN/A#ifndef __SIM_SYSCALL_EMUL_HH__
302381SN/A#define __SIM_SYSCALL_EMUL_HH__
312381SN/A
322381SN/A#define BSD_HOST (defined(__APPLE__) || defined(__OpenBSD__) || \
332381SN/A                  defined(__FreeBSD__))
342381SN/A
352381SN/A///
362381SN/A/// @file syscall_emul.hh
372381SN/A///
382381SN/A/// This file defines objects used to emulate syscalls from the target
392665Ssaidi@eecs.umich.edu/// application on the host machine.
402665Ssaidi@eecs.umich.edu
418853Sandreas.hansson@arm.com#include <errno.h>
428922Swilliam.wang@arm.com#include <string>
432381SN/A#ifdef __CYGWIN32__
442381SN/A#include <sys/fcntl.h>	// for O_BINARY
452381SN/A#endif
462381SN/A#include <sys/uio.h>
478922Swilliam.wang@arm.com
482381SN/A#include "arch/isa_traits.hh"	// for Addr
492381SN/A#include "base/chunk_generator.hh"
502381SN/A#include "base/intmath.hh"	// for RoundUp
512381SN/A#include "base/misc.hh"
522381SN/A#include "base/trace.hh"
532381SN/A#include "cpu/base.hh"
542381SN/A#include "cpu/exec_context.hh"
552381SN/A#include "mem/translating_port.hh"
562381SN/A#include "mem/page_table.hh"
572381SN/A#include "sim/process.hh"
588922Swilliam.wang@arm.com
598922Swilliam.wang@arm.com///
602407SN/A/// System call descriptor.
612407SN/A///
622407SN/Aclass SyscallDesc {
632407SN/A
642407SN/A  public:
652407SN/A
662521SN/A    /// Typedef for target syscall handler functions.
679090Sandreas.hansson@arm.com    typedef SyscallReturn (*FuncPtr)(SyscallDesc *, int num,
682407SN/A                           Process *, ExecContext *);
693401Sktlim@umich.edu
703401Sktlim@umich.edu    const char *name;	//!< Syscall name (e.g., "open").
712381SN/A    FuncPtr funcPtr;	//!< Pointer to emulation function.
728922Swilliam.wang@arm.com    int flags;		//!< Flags (see Flags enum).
738922Swilliam.wang@arm.com
749087Sandreas.hansson@arm.com    /// Flag values for controlling syscall behavior.
752381SN/A    enum Flags {
768708Sandreas.hansson@arm.com        /// Don't set return regs according to funcPtr return value.
772381SN/A        /// Used for syscalls with non-standard return conventions
788922Swilliam.wang@arm.com        /// that explicitly set the ExecContext regs (e.g.,
798922Swilliam.wang@arm.com        /// sigreturn).
808922Swilliam.wang@arm.com        SuppressReturnValue = 1
818922Swilliam.wang@arm.com    };
828922Swilliam.wang@arm.com
838922Swilliam.wang@arm.com    /// Constructor.
845476Snate@binkert.org    SyscallDesc(const char *_name, FuncPtr _funcPtr, int _flags = 0)
852640Sstever@eecs.umich.edu        : name(_name), funcPtr(_funcPtr), flags(_flags)
868965Sandreas.hansson@arm.com    {
878965Sandreas.hansson@arm.com    }
889031Sandreas.hansson@arm.com
898965Sandreas.hansson@arm.com    /// Emulate the syscall.  Public interface for calling through funcPtr.
909031Sandreas.hansson@arm.com    void doSyscall(int callnum, Process *proc, ExecContext *xc);
918965Sandreas.hansson@arm.com};
928922Swilliam.wang@arm.com
938922Swilliam.wang@arm.com
948922Swilliam.wang@arm.comclass BaseBufferArg {
958922Swilliam.wang@arm.com
968922Swilliam.wang@arm.com  public:
978922Swilliam.wang@arm.com
988922Swilliam.wang@arm.com    BaseBufferArg(Addr _addr, int _size) : addr(_addr), size(_size)
998922Swilliam.wang@arm.com    {
1008965Sandreas.hansson@arm.com        bufPtr = new uint8_t[size];
1018922Swilliam.wang@arm.com        // clear out buffer: in case we only partially populate this,
1029031Sandreas.hansson@arm.com        // and then do a copyOut(), we want to make sure we don't
1038922Swilliam.wang@arm.com        // introduce any random junk into the simulated address space
1048922Swilliam.wang@arm.com        memset(bufPtr, 0, size);
1058922Swilliam.wang@arm.com    }
1068922Swilliam.wang@arm.com
1078922Swilliam.wang@arm.com    virtual ~BaseBufferArg() { delete [] bufPtr; }
1083401Sktlim@umich.edu
1092381SN/A    //
1102640Sstever@eecs.umich.edu    // copy data into simulator space (read from target memory)
1112640Sstever@eecs.umich.edu    //
1128922Swilliam.wang@arm.com    virtual bool copyIn(TranslatingPort *memport)
1134190Ssaidi@eecs.umich.edu    {
1148965Sandreas.hansson@arm.com        memport->readBlob(addr, bufPtr, size);
1159031Sandreas.hansson@arm.com        return true;	// no EFAULT detection for now
1168965Sandreas.hansson@arm.com    }
1178922Swilliam.wang@arm.com
1188922Swilliam.wang@arm.com    //
1198922Swilliam.wang@arm.com    // copy data out of simulator space (write to target memory)
1208922Swilliam.wang@arm.com    //
1218922Swilliam.wang@arm.com    virtual bool copyOut(TranslatingPort *memport)
1228922Swilliam.wang@arm.com    {
1238922Swilliam.wang@arm.com        memport->writeBlob(addr, bufPtr, size);
1248922Swilliam.wang@arm.com        return true;	// no EFAULT detection for now
1258922Swilliam.wang@arm.com    }
1268922Swilliam.wang@arm.com
1278922Swilliam.wang@arm.com  protected:
1288922Swilliam.wang@arm.com    Addr addr;
1298922Swilliam.wang@arm.com    int size;
1308922Swilliam.wang@arm.com    uint8_t *bufPtr;
1318975Sandreas.hansson@arm.com};
1328975Sandreas.hansson@arm.com
1338922Swilliam.wang@arm.com
1348922Swilliam.wang@arm.comclass BufferArg : public BaseBufferArg
1358922Swilliam.wang@arm.com{
1368922Swilliam.wang@arm.com  public:
1378922Swilliam.wang@arm.com    BufferArg(Addr _addr, int _size) : BaseBufferArg(_addr, _size) { }
1388922Swilliam.wang@arm.com    void *bufferPtr()	{ return bufPtr; }
1398965Sandreas.hansson@arm.com};
1409031Sandreas.hansson@arm.com
1418922Swilliam.wang@arm.comtemplate <class T>
1428922Swilliam.wang@arm.comclass TypedBufferArg : public BaseBufferArg
1438922Swilliam.wang@arm.com{
1448922Swilliam.wang@arm.com  public:
1458922Swilliam.wang@arm.com    // user can optionally specify a specific number of bytes to
1468922Swilliam.wang@arm.com    // allocate to deal with those structs that have variable-size
1478922Swilliam.wang@arm.com    // arrays at the end
1488948Sandreas.hansson@arm.com    TypedBufferArg(Addr _addr, int _size = sizeof(T))
1498948Sandreas.hansson@arm.com        : BaseBufferArg(_addr, _size)
1508948Sandreas.hansson@arm.com    { }
1518948Sandreas.hansson@arm.com
1528948Sandreas.hansson@arm.com    // type case
1538948Sandreas.hansson@arm.com    operator T*() { return (T *)bufPtr; }
1548948Sandreas.hansson@arm.com
1558948Sandreas.hansson@arm.com    // dereference operators
1568948Sandreas.hansson@arm.com    T &operator*()	 { return *((T *)bufPtr); }
1578948Sandreas.hansson@arm.com    T* operator->()	 { return (T *)bufPtr; }
1588948Sandreas.hansson@arm.com    T &operator[](int i) { return ((T *)bufPtr)[i]; }
1598948Sandreas.hansson@arm.com};
1608948Sandreas.hansson@arm.com
1618948Sandreas.hansson@arm.com//////////////////////////////////////////////////////////////////////
1628948Sandreas.hansson@arm.com//
1638948Sandreas.hansson@arm.com// The following emulation functions are generic enough that they
1648948Sandreas.hansson@arm.com// don't need to be recompiled for different emulated OS's.  They are
1658948Sandreas.hansson@arm.com// defined in sim/syscall_emul.cc.
1668948Sandreas.hansson@arm.com//
1678948Sandreas.hansson@arm.com//////////////////////////////////////////////////////////////////////
1688975Sandreas.hansson@arm.com
1698975Sandreas.hansson@arm.com
1708975Sandreas.hansson@arm.com/// Handler for unimplemented syscalls that we haven't thought about.
1718975Sandreas.hansson@arm.comSyscallReturn unimplementedFunc(SyscallDesc *desc, int num,
1728975Sandreas.hansson@arm.com                                Process *p, ExecContext *xc);
1738975Sandreas.hansson@arm.com
1748975Sandreas.hansson@arm.com/// Handler for unimplemented syscalls that we never intend to
1758975Sandreas.hansson@arm.com/// implement (signal handling, etc.) and should not affect the correct
1768975Sandreas.hansson@arm.com/// behavior of the program.  Print a warning only if the appropriate
1778975Sandreas.hansson@arm.com/// trace flag is enabled.  Return success to the target program.
1788975Sandreas.hansson@arm.comSyscallReturn ignoreFunc(SyscallDesc *desc, int num,
1798948Sandreas.hansson@arm.com                         Process *p, ExecContext *xc);
1808948Sandreas.hansson@arm.com
1818975Sandreas.hansson@arm.com/// Target exit() handler: terminate simulation.
1828975Sandreas.hansson@arm.comSyscallReturn exitFunc(SyscallDesc *desc, int num,
1838975Sandreas.hansson@arm.com                       Process *p, ExecContext *xc);
1848975Sandreas.hansson@arm.com
1858975Sandreas.hansson@arm.com/// Target getpagesize() handler.
1868975Sandreas.hansson@arm.comSyscallReturn getpagesizeFunc(SyscallDesc *desc, int num,
1878975Sandreas.hansson@arm.com                              Process *p, ExecContext *xc);
1888948Sandreas.hansson@arm.com
1898975Sandreas.hansson@arm.com/// Target obreak() handler: set brk address.
1908922Swilliam.wang@arm.comSyscallReturn obreakFunc(SyscallDesc *desc, int num,
1918922Swilliam.wang@arm.com                         Process *p, ExecContext *xc);
1929087Sandreas.hansson@arm.com
1939087Sandreas.hansson@arm.com/// Target close() handler.
1949087Sandreas.hansson@arm.comSyscallReturn closeFunc(SyscallDesc *desc, int num,
1959087Sandreas.hansson@arm.com                        Process *p, ExecContext *xc);
1969087Sandreas.hansson@arm.com
1979087Sandreas.hansson@arm.com/// Target read() handler.
1988922Swilliam.wang@arm.comSyscallReturn readFunc(SyscallDesc *desc, int num,
1998711Sandreas.hansson@arm.com                       Process *p, ExecContext *xc);
2008922Swilliam.wang@arm.com
2018922Swilliam.wang@arm.com/// Target write() handler.
2028922Swilliam.wang@arm.comSyscallReturn writeFunc(SyscallDesc *desc, int num,
2038711Sandreas.hansson@arm.com                        Process *p, ExecContext *xc);
2048711Sandreas.hansson@arm.com
2058711Sandreas.hansson@arm.com/// Target lseek() handler.
2068922Swilliam.wang@arm.comSyscallReturn lseekFunc(SyscallDesc *desc, int num,
2072381SN/A                        Process *p, ExecContext *xc);
2088711Sandreas.hansson@arm.com
2098922Swilliam.wang@arm.com/// Target munmap() handler.
2108922Swilliam.wang@arm.comSyscallReturn munmapFunc(SyscallDesc *desc, int num,
2118711Sandreas.hansson@arm.com                         Process *p, ExecContext *xc);
2128922Swilliam.wang@arm.com
2132381SN/A/// Target gethostname() handler.
2142381SN/ASyscallReturn gethostnameFunc(SyscallDesc *desc, int num,
2152381SN/A                              Process *p, ExecContext *xc);
2162381SN/A
2178922Swilliam.wang@arm.com/// Target unlink() handler.
2182381SN/ASyscallReturn unlinkFunc(SyscallDesc *desc, int num,
2199089Sandreas.hansson@arm.com                         Process *p, ExecContext *xc);
2209089Sandreas.hansson@arm.com
2219089Sandreas.hansson@arm.com/// Target rename() handler.
2229089Sandreas.hansson@arm.comSyscallReturn renameFunc(SyscallDesc *desc, int num,
2239089Sandreas.hansson@arm.com                         Process *p, ExecContext *xc);
2245314Sstever@gmail.com
2255314Sstever@gmail.com
2265314Sstever@gmail.com/// Target truncate() handler.
2275314Sstever@gmail.comSyscallReturn truncateFunc(SyscallDesc *desc, int num,
2288975Sandreas.hansson@arm.com                           Process *p, ExecContext *xc);
2298975Sandreas.hansson@arm.com
2308975Sandreas.hansson@arm.com
2318975Sandreas.hansson@arm.com/// Target ftruncate() handler.
2328975Sandreas.hansson@arm.comSyscallReturn ftruncateFunc(SyscallDesc *desc, int num,
2338975Sandreas.hansson@arm.com                            Process *p, ExecContext *xc);
2348975Sandreas.hansson@arm.com
2358975Sandreas.hansson@arm.com
2368975Sandreas.hansson@arm.com/// Target chown() handler.
2378975Sandreas.hansson@arm.comSyscallReturn chownFunc(SyscallDesc *desc, int num,
2388975Sandreas.hansson@arm.com                        Process *p, ExecContext *xc);
2398975Sandreas.hansson@arm.com
2408975Sandreas.hansson@arm.com
2418975Sandreas.hansson@arm.com/// Target fchown() handler.
2428975Sandreas.hansson@arm.comSyscallReturn fchownFunc(SyscallDesc *desc, int num,
2438975Sandreas.hansson@arm.com                         Process *p, ExecContext *xc);
2448975Sandreas.hansson@arm.com
2458975Sandreas.hansson@arm.com/// Target fnctl() handler.
2468975Sandreas.hansson@arm.comSyscallReturn fcntlFunc(SyscallDesc *desc, int num,
2478975Sandreas.hansson@arm.com                        Process *process, ExecContext *xc);
2488975Sandreas.hansson@arm.com
2498975Sandreas.hansson@arm.com/// Target setuid() handler.
2508975Sandreas.hansson@arm.comSyscallReturn setuidFunc(SyscallDesc *desc, int num,
2518975Sandreas.hansson@arm.com                               Process *p, ExecContext *xc);
2528975Sandreas.hansson@arm.com
2538975Sandreas.hansson@arm.com/// Target getpid() handler.
2548975Sandreas.hansson@arm.comSyscallReturn getpidFunc(SyscallDesc *desc, int num,
2558975Sandreas.hansson@arm.com                               Process *p, ExecContext *xc);
2568975Sandreas.hansson@arm.com
2578975Sandreas.hansson@arm.com/// Target getuid() handler.
2588975Sandreas.hansson@arm.comSyscallReturn getuidFunc(SyscallDesc *desc, int num,
2598975Sandreas.hansson@arm.com                               Process *p, ExecContext *xc);
2608975Sandreas.hansson@arm.com
2618975Sandreas.hansson@arm.com/// Target getgid() handler.
2629087Sandreas.hansson@arm.comSyscallReturn getgidFunc(SyscallDesc *desc, int num,
2639087Sandreas.hansson@arm.com                               Process *p, ExecContext *xc);
2649087Sandreas.hansson@arm.com
2659087Sandreas.hansson@arm.com/// Target getppid() handler.
2669087Sandreas.hansson@arm.comSyscallReturn getppidFunc(SyscallDesc *desc, int num,
2679087Sandreas.hansson@arm.com                               Process *p, ExecContext *xc);
2689087Sandreas.hansson@arm.com
2699087Sandreas.hansson@arm.com/// Target geteuid() handler.
2708975Sandreas.hansson@arm.comSyscallReturn geteuidFunc(SyscallDesc *desc, int num,
2718975Sandreas.hansson@arm.com                               Process *p, ExecContext *xc);
2728975Sandreas.hansson@arm.com
2738975Sandreas.hansson@arm.com/// Target getegid() handler.
2748975Sandreas.hansson@arm.comSyscallReturn getegidFunc(SyscallDesc *desc, int num,
2758975Sandreas.hansson@arm.com                               Process *p, ExecContext *xc);
2768975Sandreas.hansson@arm.com
2772381SN/A
2782381SN/A
2798922Swilliam.wang@arm.com/// Pseudo Funcs  - These functions use a different return convension,
2808922Swilliam.wang@arm.com/// returning a second value in a register other than the normal return register
2818922Swilliam.wang@arm.comSyscallReturn pipePseudoFunc(SyscallDesc *desc, int num,
2828922Swilliam.wang@arm.com                             Process *process, ExecContext *xc);
2838922Swilliam.wang@arm.com
2848922Swilliam.wang@arm.com/// Target getpidPseudo() handler.
2858922Swilliam.wang@arm.comSyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num,
2868922Swilliam.wang@arm.com                               Process *p, ExecContext *xc);
2878922Swilliam.wang@arm.com
2888975Sandreas.hansson@arm.com/// Target getuidPseudo() handler.
2898975Sandreas.hansson@arm.comSyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num,
2908922Swilliam.wang@arm.com                               Process *p, ExecContext *xc);
2918922Swilliam.wang@arm.com
2928922Swilliam.wang@arm.com/// Target getgidPseudo() handler.
2938922Swilliam.wang@arm.comSyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num,
2948922Swilliam.wang@arm.com                               Process *p, ExecContext *xc);
2958922Swilliam.wang@arm.com
2968965Sandreas.hansson@arm.com
2979031Sandreas.hansson@arm.com/// This struct is used to build an target-OS-dependent table that
2988922Swilliam.wang@arm.com/// maps the target's open() flags to the host open() flags.
2998922Swilliam.wang@arm.comstruct OpenFlagTransTable {
3008922Swilliam.wang@arm.com    int tgtFlag;	//!< Target system flag value.
3018922Swilliam.wang@arm.com    int hostFlag;	//!< Corresponding host system flag value.
3028922Swilliam.wang@arm.com};
3038922Swilliam.wang@arm.com
3048922Swilliam.wang@arm.com
3058948Sandreas.hansson@arm.com
3068948Sandreas.hansson@arm.com/// A readable name for 1,000,000, for converting microseconds to seconds.
3078948Sandreas.hansson@arm.comconst int one_million = 1000000;
3088948Sandreas.hansson@arm.com
3098948Sandreas.hansson@arm.com/// Approximate seconds since the epoch (1/1/1970).  About a billion,
3108948Sandreas.hansson@arm.com/// by my reckoning.  We want to keep this a constant (not use the
3118948Sandreas.hansson@arm.com/// real-world time) to keep simulations repeatable.
3128948Sandreas.hansson@arm.comconst unsigned seconds_since_epoch = 1000000000;
3138948Sandreas.hansson@arm.com
3148948Sandreas.hansson@arm.com/// Helper function to convert current elapsed time to seconds and
3158948Sandreas.hansson@arm.com/// microseconds.
3168948Sandreas.hansson@arm.comtemplate <class T1, class T2>
3178948Sandreas.hansson@arm.comvoid
3188948Sandreas.hansson@arm.comgetElapsedTime(T1 &sec, T2 &usec)
3198948Sandreas.hansson@arm.com{
3208948Sandreas.hansson@arm.com    int elapsed_usecs = curTick / Clock::Int::us;
3218948Sandreas.hansson@arm.com    sec = elapsed_usecs / one_million;
3228948Sandreas.hansson@arm.com    usec = elapsed_usecs % one_million;
3238948Sandreas.hansson@arm.com}
3248948Sandreas.hansson@arm.com
3258975Sandreas.hansson@arm.com//////////////////////////////////////////////////////////////////////
3268975Sandreas.hansson@arm.com//
3278975Sandreas.hansson@arm.com// The following emulation functions are generic, but need to be
3288975Sandreas.hansson@arm.com// templated to account for differences in types, constants, etc.
3298975Sandreas.hansson@arm.com//
3308975Sandreas.hansson@arm.com//////////////////////////////////////////////////////////////////////
3318975Sandreas.hansson@arm.com
3328975Sandreas.hansson@arm.com/// Target ioctl() handler.  For the most part, programs call ioctl()
3338975Sandreas.hansson@arm.com/// only to find out if their stdout is a tty, to determine whether to
3348975Sandreas.hansson@arm.com/// do line or block buffering.
3358975Sandreas.hansson@arm.comtemplate <class OS>
3368948Sandreas.hansson@arm.comSyscallReturn
3378948Sandreas.hansson@arm.comioctlFunc(SyscallDesc *desc, int callnum, Process *process,
3388975Sandreas.hansson@arm.com          ExecContext *xc)
3398975Sandreas.hansson@arm.com{
3408975Sandreas.hansson@arm.com    int fd = xc->getSyscallArg(0);
3418975Sandreas.hansson@arm.com    unsigned req = xc->getSyscallArg(1);
3428975Sandreas.hansson@arm.com
3438948Sandreas.hansson@arm.com    DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", fd, req);
3448975Sandreas.hansson@arm.com
3458948Sandreas.hansson@arm.com    if (fd < 0 || process->sim_fd(fd) < 0) {
3468948Sandreas.hansson@arm.com        // doesn't map to any simulator fd: not a valid target fd
3479087Sandreas.hansson@arm.com        return -EBADF;
3489087Sandreas.hansson@arm.com    }
3499087Sandreas.hansson@arm.com
3509087Sandreas.hansson@arm.com    switch (req) {
3519087Sandreas.hansson@arm.com      case OS::TIOCISATTY:
3529087Sandreas.hansson@arm.com      case OS::TIOCGETP:
3539087Sandreas.hansson@arm.com      case OS::TIOCSETP:
3548922Swilliam.wang@arm.com      case OS::TIOCSETN:
3558922Swilliam.wang@arm.com      case OS::TIOCSETC:
3568922Swilliam.wang@arm.com      case OS::TIOCGETC:
3578922Swilliam.wang@arm.com      case OS::TIOCGETS:
3588922Swilliam.wang@arm.com      case OS::TIOCGETA:
3598922Swilliam.wang@arm.com        return -ENOTTY;
3608922Swilliam.wang@arm.com
3618922Swilliam.wang@arm.com      default:
3628922Swilliam.wang@arm.com        fatal("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ 0x%llx\n",
3638922Swilliam.wang@arm.com              fd, req, xc->readPC());
3648922Swilliam.wang@arm.com    }
3659088Sandreas.hansson@arm.com}
3669088Sandreas.hansson@arm.com
3679088Sandreas.hansson@arm.com/// Target open() handler.
3689088Sandreas.hansson@arm.comtemplate <class OS>
3699088Sandreas.hansson@arm.comSyscallReturn
3709088Sandreas.hansson@arm.comopenFunc(SyscallDesc *desc, int callnum, Process *process,
3719088Sandreas.hansson@arm.com         ExecContext *xc)
3728922Swilliam.wang@arm.com{
3738922Swilliam.wang@arm.com    std::string path;
3748922Swilliam.wang@arm.com
3758922Swilliam.wang@arm.com    if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
3768922Swilliam.wang@arm.com        return -EFAULT;
3778922Swilliam.wang@arm.com
3788922Swilliam.wang@arm.com    if (path == "/dev/sysdev0") {
3798922Swilliam.wang@arm.com        // This is a memory-mapped high-resolution timer device on Alpha.
3808922Swilliam.wang@arm.com        // We don't support it, so just punt.
3818922Swilliam.wang@arm.com        warn("Ignoring open(%s, ...)\n", path);
3828922Swilliam.wang@arm.com        return -ENOENT;
3839090Sandreas.hansson@arm.com    }
3848975Sandreas.hansson@arm.com
3858975Sandreas.hansson@arm.com    int tgtFlags = xc->getSyscallArg(1);
3868975Sandreas.hansson@arm.com    int mode = xc->getSyscallArg(2);
3878975Sandreas.hansson@arm.com    int hostFlags = 0;
3888975Sandreas.hansson@arm.com
3898975Sandreas.hansson@arm.com    // translate open flags
3908975Sandreas.hansson@arm.com    for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) {
3918975Sandreas.hansson@arm.com        if (tgtFlags & OS::openFlagTable[i].tgtFlag) {
3928975Sandreas.hansson@arm.com            tgtFlags &= ~OS::openFlagTable[i].tgtFlag;
3938975Sandreas.hansson@arm.com            hostFlags |= OS::openFlagTable[i].hostFlag;
3948975Sandreas.hansson@arm.com        }
3958975Sandreas.hansson@arm.com    }
3968975Sandreas.hansson@arm.com
3978975Sandreas.hansson@arm.com    // any target flags left?
3988975Sandreas.hansson@arm.com    if (tgtFlags != 0)
3998975Sandreas.hansson@arm.com        warn("Syscall: open: cannot decode flags 0x%x", tgtFlags);
4008975Sandreas.hansson@arm.com
4018975Sandreas.hansson@arm.com#ifdef __CYGWIN32__
4028975Sandreas.hansson@arm.com    hostFlags |= O_BINARY;
4038975Sandreas.hansson@arm.com#endif
4048975Sandreas.hansson@arm.com
4058975Sandreas.hansson@arm.com    DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str());
4068975Sandreas.hansson@arm.com
4078975Sandreas.hansson@arm.com    // open the file
4088975Sandreas.hansson@arm.com    int fd = open(path.c_str(), hostFlags, mode);
4098975Sandreas.hansson@arm.com
4109087Sandreas.hansson@arm.com    return (fd == -1) ? -errno : process->alloc_fd(fd);
4119087Sandreas.hansson@arm.com}
4129087Sandreas.hansson@arm.com
4139087Sandreas.hansson@arm.com
4149087Sandreas.hansson@arm.com/// Target chmod() handler.
4159087Sandreas.hansson@arm.comtemplate <class OS>
4169087Sandreas.hansson@arm.comSyscallReturn
4178922Swilliam.wang@arm.comchmodFunc(SyscallDesc *desc, int callnum, Process *process,
4188922Swilliam.wang@arm.com          ExecContext *xc)
4192381SN/A{
420    std::string path;
421
422    if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
423        return -EFAULT;
424
425    uint32_t mode = xc->getSyscallArg(1);
426    mode_t hostMode = 0;
427
428    // XXX translate mode flags via OS::something???
429    hostMode = mode;
430
431    // do the chmod
432    int result = chmod(path.c_str(), hostMode);
433    if (result < 0)
434        return -errno;
435
436    return 0;
437}
438
439
440/// Target fchmod() handler.
441template <class OS>
442SyscallReturn
443fchmodFunc(SyscallDesc *desc, int callnum, Process *process,
444           ExecContext *xc)
445{
446    int fd = xc->getSyscallArg(0);
447    if (fd < 0 || process->sim_fd(fd) < 0) {
448        // doesn't map to any simulator fd: not a valid target fd
449        return -EBADF;
450    }
451
452    uint32_t mode = xc->getSyscallArg(1);
453    mode_t hostMode = 0;
454
455    // XXX translate mode flags via OS::someting???
456    hostMode = mode;
457
458    // do the fchmod
459    int result = fchmod(process->sim_fd(fd), hostMode);
460    if (result < 0)
461        return -errno;
462
463    return 0;
464}
465
466
467/// Target stat() handler.
468template <class OS>
469SyscallReturn
470statFunc(SyscallDesc *desc, int callnum, Process *process,
471         ExecContext *xc)
472{
473    std::string path;
474
475    if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
476    return -EFAULT;
477
478    struct stat hostBuf;
479    int result = stat(path.c_str(), &hostBuf);
480
481    if (result < 0)
482        return -errno;
483
484    OS::copyOutStatBuf(xc->getMemPort(), xc->getSyscallArg(1), &hostBuf);
485
486    return 0;
487}
488
489
490/// Target fstat64() handler.
491template <class OS>
492SyscallReturn
493fstat64Func(SyscallDesc *desc, int callnum, Process *process,
494            ExecContext *xc)
495{
496    int fd = xc->getSyscallArg(0);
497    if (fd < 0 || process->sim_fd(fd) < 0) {
498        // doesn't map to any simulator fd: not a valid target fd
499        return -EBADF;
500    }
501
502#if BSD_HOST
503    struct stat  hostBuf;
504    int result = fstat(process->sim_fd(fd), &hostBuf);
505#else
506    struct stat64  hostBuf;
507    int result = fstat64(process->sim_fd(fd), &hostBuf);
508#endif
509
510    if (result < 0)
511        return -errno;
512
513    OS::copyOutStat64Buf(xc->getMemPort(), fd, xc->getSyscallArg(1), &hostBuf);
514
515    return 0;
516}
517
518
519/// Target lstat() handler.
520template <class OS>
521SyscallReturn
522lstatFunc(SyscallDesc *desc, int callnum, Process *process,
523          ExecContext *xc)
524{
525    std::string path;
526
527    if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
528      return -EFAULT;
529
530    struct stat hostBuf;
531    int result = lstat(path.c_str(), &hostBuf);
532
533    if (result < 0)
534        return -errno;
535
536    OS::copyOutStatBuf(xc->getMemPort(), xc->getSyscallArg(1), &hostBuf);
537
538    return 0;
539}
540
541/// Target lstat64() handler.
542template <class OS>
543SyscallReturn
544lstat64Func(SyscallDesc *desc, int callnum, Process *process,
545            ExecContext *xc)
546{
547    std::string path;
548
549    if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
550      return -EFAULT;
551
552#if BSD_HOST
553    struct stat hostBuf;
554    int result = lstat(path.c_str(), &hostBuf);
555#else
556    struct stat64 hostBuf;
557    int result = lstat64(path.c_str(), &hostBuf);
558#endif
559
560    if (result < 0)
561        return -errno;
562
563    OS::copyOutStat64Buf(xc->getMemPort(), -1, xc->getSyscallArg(1), &hostBuf);
564
565    return 0;
566}
567
568/// Target fstat() handler.
569template <class OS>
570SyscallReturn
571fstatFunc(SyscallDesc *desc, int callnum, Process *process,
572          ExecContext *xc)
573{
574    int fd = process->sim_fd(xc->getSyscallArg(0));
575
576    DPRINTF(SyscallVerbose, "fstat(%d, ...)\n", fd);
577
578    if (fd < 0)
579        return -EBADF;
580
581    struct stat hostBuf;
582    int result = fstat(fd, &hostBuf);
583
584    if (result < 0)
585        return -errno;
586
587    OS::copyOutStatBuf(xc->getMemPort(), xc->getSyscallArg(1), &hostBuf);
588
589    return 0;
590}
591
592
593/// Target statfs() handler.
594template <class OS>
595SyscallReturn
596statfsFunc(SyscallDesc *desc, int callnum, Process *process,
597           ExecContext *xc)
598{
599    std::string path;
600
601    if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
602      return -EFAULT;
603
604    struct statfs hostBuf;
605    int result = statfs(path.c_str(), &hostBuf);
606
607    if (result < 0)
608        return -errno;
609
610    OS::copyOutStatfsBuf(xc->getMemPort(), xc->getSyscallArg(1), &hostBuf);
611
612    return 0;
613}
614
615
616/// Target fstatfs() handler.
617template <class OS>
618SyscallReturn
619fstatfsFunc(SyscallDesc *desc, int callnum, Process *process,
620            ExecContext *xc)
621{
622    int fd = process->sim_fd(xc->getSyscallArg(0));
623
624    if (fd < 0)
625        return -EBADF;
626
627    struct statfs hostBuf;
628    int result = fstatfs(fd, &hostBuf);
629
630    if (result < 0)
631        return -errno;
632
633    OS::copyOutStatfsBuf(xc->getMemPort(), xc->getSyscallArg(1), &hostBuf);
634
635    return 0;
636}
637
638
639/// Target writev() handler.
640template <class OS>
641SyscallReturn
642writevFunc(SyscallDesc *desc, int callnum, Process *process,
643           ExecContext *xc)
644{
645    int fd = xc->getSyscallArg(0);
646    if (fd < 0 || process->sim_fd(fd) < 0) {
647        // doesn't map to any simulator fd: not a valid target fd
648        return -EBADF;
649    }
650
651    TranslatingPort *p = xc->getMemPort();
652    uint64_t tiov_base = xc->getSyscallArg(1);
653    size_t count = xc->getSyscallArg(2);
654    struct iovec hiov[count];
655    for (int i = 0; i < count; ++i)
656    {
657        typename OS::tgt_iovec tiov;
658
659        p->readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec),
660                    (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec));
661        hiov[i].iov_len = gtoh(tiov.iov_len);
662        hiov[i].iov_base = new char [hiov[i].iov_len];
663        p->readBlob(gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base,
664                    hiov[i].iov_len);
665    }
666
667    int result = writev(process->sim_fd(fd), hiov, count);
668
669    for (int i = 0; i < count; ++i)
670    {
671        delete [] (char *)hiov[i].iov_base;
672    }
673
674    if (result < 0)
675        return -errno;
676
677    return 0;
678}
679
680
681/// Target mmap() handler.
682///
683/// We don't really handle mmap().  If the target is mmaping an
684/// anonymous region or /dev/zero, we can get away with doing basically
685/// nothing (since memory is initialized to zero and the simulator
686/// doesn't really check addresses anyway).  Always print a warning,
687/// since this could be seriously broken if we're not mapping
688/// /dev/zero.
689//
690/// Someday we should explicitly check for /dev/zero in open, flag the
691/// file descriptor, and fail (or implement!) a non-anonymous mmap to
692/// anything else.
693template <class OS>
694SyscallReturn
695mmapFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
696{
697    Addr start = xc->getSyscallArg(0);
698    uint64_t length = xc->getSyscallArg(1);
699    // int prot = xc->getSyscallArg(2);
700    int flags = xc->getSyscallArg(3);
701    // int fd = p->sim_fd(xc->getSyscallArg(4));
702    // int offset = xc->getSyscallArg(5);
703    Addr junk;
704
705    if (start == 0) {
706        // user didn't give an address... pick one from our "mmap region"
707        start = p->mmap_end;
708        for (ChunkGenerator gen(start, roundUp(length, TheISA::VMPageSize), TheISA::VMPageSize); !gen.done(); gen.next()) {
709            if (!p->pTable->translate(gen.addr(), junk))
710                p->pTable->allocate(roundDown(gen.addr(), TheISA::VMPageSize), TheISA::VMPageSize);
711        }
712        p->mmap_end += roundUp(length, TheISA::VMPageSize);
713        if (p->nxm_start != 0) {
714            //If we have an nxm space, make sure we haven't colided
715            assert(p->mmap_end < p->nxm_start);
716        }
717    }
718
719    if (!(flags & OS::TGT_MAP_ANONYMOUS)) {
720        warn("allowing mmap of file @ fd %d. "
721             "This will break if not /dev/zero.", xc->getSyscallArg(4));
722    }
723
724    return start;
725}
726
727/// Target getrlimit() handler.
728template <class OS>
729SyscallReturn
730getrlimitFunc(SyscallDesc *desc, int callnum, Process *process,
731        ExecContext *xc)
732{
733    unsigned resource = xc->getSyscallArg(0);
734    TypedBufferArg<typename OS::rlimit> rlp(xc->getSyscallArg(1));
735
736    switch (resource) {
737        case OS::TGT_RLIMIT_STACK:
738            // max stack size in bytes: make up a number (2MB for now)
739            rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024;
740            rlp->rlim_cur = htog(rlp->rlim_cur);
741            rlp->rlim_max = htog(rlp->rlim_max);
742            break;
743
744        default:
745            std::cerr << "getrlimitFunc: unimplemented resource " << resource
746                << std::endl;
747            abort();
748            break;
749    }
750
751    rlp.copyOut(xc->getMemPort());
752    return 0;
753}
754
755/// Target gettimeofday() handler.
756template <class OS>
757SyscallReturn
758gettimeofdayFunc(SyscallDesc *desc, int callnum, Process *process,
759        ExecContext *xc)
760{
761    TypedBufferArg<typename OS::timeval> tp(xc->getSyscallArg(0));
762
763    getElapsedTime(tp->tv_sec, tp->tv_usec);
764    tp->tv_sec += seconds_since_epoch;
765    tp->tv_sec = htog(tp->tv_sec);
766    tp->tv_usec = htog(tp->tv_usec);
767
768    tp.copyOut(xc->getMemPort());
769
770    return 0;
771}
772
773
774/// Target utimes() handler.
775template <class OS>
776SyscallReturn
777utimesFunc(SyscallDesc *desc, int callnum, Process *process,
778           ExecContext *xc)
779{
780    std::string path;
781
782    if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
783      return -EFAULT;
784
785    TypedBufferArg<typename OS::timeval [2]> tp(xc->getSyscallArg(1));
786    tp.copyIn(xc->getMemPort());
787
788    struct timeval hostTimeval[2];
789    for (int i = 0; i < 2; ++i)
790    {
791        hostTimeval[i].tv_sec = gtoh((*tp)[i].tv_sec);
792        hostTimeval[i].tv_usec = gtoh((*tp)[i].tv_usec);
793    }
794    int result = utimes(path.c_str(), hostTimeval);
795
796    if (result < 0)
797        return -errno;
798
799    return 0;
800}
801/// Target getrusage() function.
802template <class OS>
803SyscallReturn
804getrusageFunc(SyscallDesc *desc, int callnum, Process *process,
805              ExecContext *xc)
806{
807    int who = xc->getSyscallArg(0);	// THREAD, SELF, or CHILDREN
808    TypedBufferArg<typename OS::rusage> rup(xc->getSyscallArg(1));
809
810    if (who != OS::TGT_RUSAGE_SELF) {
811        // don't really handle THREAD or CHILDREN, but just warn and
812        // plow ahead
813        warn("getrusage() only supports RUSAGE_SELF.  Parameter %d ignored.",
814             who);
815    }
816
817    getElapsedTime(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec);
818    rup->ru_utime.tv_sec = htog(rup->ru_utime.tv_sec);
819    rup->ru_utime.tv_usec = htog(rup->ru_utime.tv_usec);
820
821    rup->ru_stime.tv_sec = 0;
822    rup->ru_stime.tv_usec = 0;
823    rup->ru_maxrss = 0;
824    rup->ru_ixrss = 0;
825    rup->ru_idrss = 0;
826    rup->ru_isrss = 0;
827    rup->ru_minflt = 0;
828    rup->ru_majflt = 0;
829    rup->ru_nswap = 0;
830    rup->ru_inblock = 0;
831    rup->ru_oublock = 0;
832    rup->ru_msgsnd = 0;
833    rup->ru_msgrcv = 0;
834    rup->ru_nsignals = 0;
835    rup->ru_nvcsw = 0;
836    rup->ru_nivcsw = 0;
837
838    rup.copyOut(xc->getMemPort());
839
840    return 0;
841}
842
843#endif // __SIM_SYSCALL_EMUL_HH__
844