syscall_emul.hh revision 10496:0a5a8ecd0ec6
1/*
2 * Copyright (c) 2012-2013 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder.  You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Copyright (c) 2003-2005 The Regents of The University of Michigan
15 * All rights reserved.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are
19 * met: redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer;
21 * redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution;
24 * neither the name of the copyright holders nor the names of its
25 * contributors may be used to endorse or promote products derived from
26 * this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 *
40 * Authors: Steve Reinhardt
41 *          Kevin Lim
42 */
43
44#ifndef __SIM_SYSCALL_EMUL_HH__
45#define __SIM_SYSCALL_EMUL_HH__
46
47#define NO_STAT64 (defined(__APPLE__) || defined(__OpenBSD__) || \
48  defined(__FreeBSD__) || defined(__CYGWIN__) || \
49  defined(__NetBSD__))
50
51///
52/// @file syscall_emul.hh
53///
54/// This file defines objects used to emulate syscalls from the target
55/// application on the host machine.
56
57#ifdef __CYGWIN32__
58#include <sys/fcntl.h>  // for O_BINARY
59#endif
60#include <sys/stat.h>
61#include <sys/time.h>
62#include <sys/uio.h>
63#include <fcntl.h>
64
65#include <cerrno>
66#include <string>
67
68#include "base/chunk_generator.hh"
69#include "base/intmath.hh"      // for RoundUp
70#include "base/misc.hh"
71#include "base/trace.hh"
72#include "base/types.hh"
73#include "config/the_isa.hh"
74#include "cpu/base.hh"
75#include "cpu/thread_context.hh"
76#include "debug/SyscallVerbose.hh"
77#include "mem/page_table.hh"
78#include "mem/se_translating_port_proxy.hh"
79#include "sim/byteswap.hh"
80#include "sim/emul_driver.hh"
81#include "sim/process.hh"
82#include "sim/syscallreturn.hh"
83#include "sim/system.hh"
84
85///
86/// System call descriptor.
87///
88class SyscallDesc {
89
90  public:
91
92    /// Typedef for target syscall handler functions.
93    typedef SyscallReturn (*FuncPtr)(SyscallDesc *, int num,
94                           LiveProcess *, ThreadContext *);
95
96    const char *name;   //!< Syscall name (e.g., "open").
97    FuncPtr funcPtr;    //!< Pointer to emulation function.
98    int flags;          //!< Flags (see Flags enum).
99
100    /// Flag values for controlling syscall behavior.
101    enum Flags {
102        /// Don't set return regs according to funcPtr return value.
103        /// Used for syscalls with non-standard return conventions
104        /// that explicitly set the ThreadContext regs (e.g.,
105        /// sigreturn).
106        SuppressReturnValue = 1
107    };
108
109    /// Constructor.
110    SyscallDesc(const char *_name, FuncPtr _funcPtr, int _flags = 0)
111        : name(_name), funcPtr(_funcPtr), flags(_flags)
112    {
113    }
114
115    /// Emulate the syscall.  Public interface for calling through funcPtr.
116    void doSyscall(int callnum, LiveProcess *proc, ThreadContext *tc);
117};
118
119
120class BaseBufferArg {
121
122  public:
123
124    BaseBufferArg(Addr _addr, int _size) : addr(_addr), size(_size)
125    {
126        bufPtr = new uint8_t[size];
127        // clear out buffer: in case we only partially populate this,
128        // and then do a copyOut(), we want to make sure we don't
129        // introduce any random junk into the simulated address space
130        memset(bufPtr, 0, size);
131    }
132
133    virtual ~BaseBufferArg() { delete [] bufPtr; }
134
135    //
136    // copy data into simulator space (read from target memory)
137    //
138    virtual bool copyIn(SETranslatingPortProxy &memproxy)
139    {
140        memproxy.readBlob(addr, bufPtr, size);
141        return true;    // no EFAULT detection for now
142    }
143
144    //
145    // copy data out of simulator space (write to target memory)
146    //
147    virtual bool copyOut(SETranslatingPortProxy &memproxy)
148    {
149        memproxy.writeBlob(addr, bufPtr, size);
150        return true;    // no EFAULT detection for now
151    }
152
153  protected:
154    Addr addr;
155    int size;
156    uint8_t *bufPtr;
157};
158
159
160class BufferArg : public BaseBufferArg
161{
162  public:
163    BufferArg(Addr _addr, int _size) : BaseBufferArg(_addr, _size) { }
164    void *bufferPtr()   { return bufPtr; }
165};
166
167template <class T>
168class TypedBufferArg : public BaseBufferArg
169{
170  public:
171    // user can optionally specify a specific number of bytes to
172    // allocate to deal with those structs that have variable-size
173    // arrays at the end
174    TypedBufferArg(Addr _addr, int _size = sizeof(T))
175        : BaseBufferArg(_addr, _size)
176    { }
177
178    // type case
179    operator T*() { return (T *)bufPtr; }
180
181    // dereference operators
182    T &operator*()       { return *((T *)bufPtr); }
183    T* operator->()      { return (T *)bufPtr; }
184    T &operator[](int i) { return ((T *)bufPtr)[i]; }
185};
186
187//////////////////////////////////////////////////////////////////////
188//
189// The following emulation functions are generic enough that they
190// don't need to be recompiled for different emulated OS's.  They are
191// defined in sim/syscall_emul.cc.
192//
193//////////////////////////////////////////////////////////////////////
194
195
196/// Handler for unimplemented syscalls that we haven't thought about.
197SyscallReturn unimplementedFunc(SyscallDesc *desc, int num,
198                                LiveProcess *p, ThreadContext *tc);
199
200/// Handler for unimplemented syscalls that we never intend to
201/// implement (signal handling, etc.) and should not affect the correct
202/// behavior of the program.  Print a warning only if the appropriate
203/// trace flag is enabled.  Return success to the target program.
204SyscallReturn ignoreFunc(SyscallDesc *desc, int num,
205                         LiveProcess *p, ThreadContext *tc);
206SyscallReturn ignoreWarnOnceFunc(SyscallDesc *desc, int num,
207                         LiveProcess *p, ThreadContext *tc);
208
209/// Target exit() handler: terminate current context.
210SyscallReturn exitFunc(SyscallDesc *desc, int num,
211                       LiveProcess *p, ThreadContext *tc);
212
213/// Target exit_group() handler: terminate simulation. (exit all threads)
214SyscallReturn exitGroupFunc(SyscallDesc *desc, int num,
215                       LiveProcess *p, ThreadContext *tc);
216
217/// Target getpagesize() handler.
218SyscallReturn getpagesizeFunc(SyscallDesc *desc, int num,
219                              LiveProcess *p, ThreadContext *tc);
220
221/// Target brk() handler: set brk address.
222SyscallReturn brkFunc(SyscallDesc *desc, int num,
223                      LiveProcess *p, ThreadContext *tc);
224
225/// Target close() handler.
226SyscallReturn closeFunc(SyscallDesc *desc, int num,
227                        LiveProcess *p, ThreadContext *tc);
228
229/// Target read() handler.
230SyscallReturn readFunc(SyscallDesc *desc, int num,
231                       LiveProcess *p, ThreadContext *tc);
232
233/// Target write() handler.
234SyscallReturn writeFunc(SyscallDesc *desc, int num,
235                        LiveProcess *p, ThreadContext *tc);
236
237/// Target lseek() handler.
238SyscallReturn lseekFunc(SyscallDesc *desc, int num,
239                        LiveProcess *p, ThreadContext *tc);
240
241/// Target _llseek() handler.
242SyscallReturn _llseekFunc(SyscallDesc *desc, int num,
243                        LiveProcess *p, ThreadContext *tc);
244
245/// Target munmap() handler.
246SyscallReturn munmapFunc(SyscallDesc *desc, int num,
247                         LiveProcess *p, ThreadContext *tc);
248
249/// Target gethostname() handler.
250SyscallReturn gethostnameFunc(SyscallDesc *desc, int num,
251                              LiveProcess *p, ThreadContext *tc);
252
253/// Target getcwd() handler.
254SyscallReturn getcwdFunc(SyscallDesc *desc, int num,
255                         LiveProcess *p, ThreadContext *tc);
256
257/// Target readlink() handler.
258SyscallReturn readlinkFunc(SyscallDesc *desc, int num,
259                           LiveProcess *p, ThreadContext *tc,
260                           int index = 0);
261SyscallReturn readlinkFunc(SyscallDesc *desc, int num,
262                           LiveProcess *p, ThreadContext *tc);
263
264/// Target unlink() handler.
265SyscallReturn unlinkFunc(SyscallDesc *desc, int num,
266                         LiveProcess *p, ThreadContext *tc);
267
268/// Target mkdir() handler.
269SyscallReturn mkdirFunc(SyscallDesc *desc, int num,
270                        LiveProcess *p, ThreadContext *tc);
271
272/// Target rename() handler.
273SyscallReturn renameFunc(SyscallDesc *desc, int num,
274                         LiveProcess *p, ThreadContext *tc);
275
276
277/// Target truncate() handler.
278SyscallReturn truncateFunc(SyscallDesc *desc, int num,
279                           LiveProcess *p, ThreadContext *tc);
280
281
282/// Target ftruncate() handler.
283SyscallReturn ftruncateFunc(SyscallDesc *desc, int num,
284                            LiveProcess *p, ThreadContext *tc);
285
286
287/// Target truncate64() handler.
288SyscallReturn truncate64Func(SyscallDesc *desc, int num,
289                             LiveProcess *p, ThreadContext *tc);
290
291/// Target ftruncate64() handler.
292SyscallReturn ftruncate64Func(SyscallDesc *desc, int num,
293                              LiveProcess *p, ThreadContext *tc);
294
295
296/// Target umask() handler.
297SyscallReturn umaskFunc(SyscallDesc *desc, int num,
298                        LiveProcess *p, ThreadContext *tc);
299
300
301/// Target chown() handler.
302SyscallReturn chownFunc(SyscallDesc *desc, int num,
303                        LiveProcess *p, ThreadContext *tc);
304
305
306/// Target fchown() handler.
307SyscallReturn fchownFunc(SyscallDesc *desc, int num,
308                         LiveProcess *p, ThreadContext *tc);
309
310/// Target dup() handler.
311SyscallReturn dupFunc(SyscallDesc *desc, int num,
312                      LiveProcess *process, ThreadContext *tc);
313
314/// Target fnctl() handler.
315SyscallReturn fcntlFunc(SyscallDesc *desc, int num,
316                        LiveProcess *process, ThreadContext *tc);
317
318/// Target fcntl64() handler.
319SyscallReturn fcntl64Func(SyscallDesc *desc, int num,
320                        LiveProcess *process, ThreadContext *tc);
321
322/// Target setuid() handler.
323SyscallReturn setuidFunc(SyscallDesc *desc, int num,
324                               LiveProcess *p, ThreadContext *tc);
325
326/// Target getpid() handler.
327SyscallReturn getpidFunc(SyscallDesc *desc, int num,
328                               LiveProcess *p, ThreadContext *tc);
329
330/// Target getuid() handler.
331SyscallReturn getuidFunc(SyscallDesc *desc, int num,
332                               LiveProcess *p, ThreadContext *tc);
333
334/// Target getgid() handler.
335SyscallReturn getgidFunc(SyscallDesc *desc, int num,
336                               LiveProcess *p, ThreadContext *tc);
337
338/// Target getppid() handler.
339SyscallReturn getppidFunc(SyscallDesc *desc, int num,
340                               LiveProcess *p, ThreadContext *tc);
341
342/// Target geteuid() handler.
343SyscallReturn geteuidFunc(SyscallDesc *desc, int num,
344                               LiveProcess *p, ThreadContext *tc);
345
346/// Target getegid() handler.
347SyscallReturn getegidFunc(SyscallDesc *desc, int num,
348                               LiveProcess *p, ThreadContext *tc);
349
350/// Target clone() handler.
351SyscallReturn cloneFunc(SyscallDesc *desc, int num,
352                               LiveProcess *p, ThreadContext *tc);
353
354/// Target access() handler
355SyscallReturn accessFunc(SyscallDesc *desc, int num,
356                               LiveProcess *p, ThreadContext *tc);
357SyscallReturn accessFunc(SyscallDesc *desc, int num,
358                               LiveProcess *p, ThreadContext *tc,
359                               int index);
360
361/// Futex system call
362///  Implemented by Daniel Sanchez
363///  Used by printf's in multi-threaded apps
364template <class OS>
365SyscallReturn
366futexFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
367          ThreadContext *tc)
368{
369    int index_uaddr = 0;
370    int index_op = 1;
371    int index_val = 2;
372    int index_timeout = 3;
373
374    uint64_t uaddr = process->getSyscallArg(tc, index_uaddr);
375    int op = process->getSyscallArg(tc, index_op);
376    int val = process->getSyscallArg(tc, index_val);
377    uint64_t timeout = process->getSyscallArg(tc, index_timeout);
378
379    std::map<uint64_t, std::list<ThreadContext *> * >
380        &futex_map = tc->getSystemPtr()->futexMap;
381
382    DPRINTF(SyscallVerbose, "In sys_futex: Address=%llx, op=%d, val=%d\n",
383            uaddr, op, val);
384
385    op &= ~OS::TGT_FUTEX_PRIVATE_FLAG;
386
387    if (op == OS::TGT_FUTEX_WAIT) {
388        if (timeout != 0) {
389            warn("sys_futex: FUTEX_WAIT with non-null timeout unimplemented;"
390                 "we'll wait indefinitely");
391        }
392
393        uint8_t *buf = new uint8_t[sizeof(int)];
394        tc->getMemProxy().readBlob((Addr)uaddr, buf, (int)sizeof(int));
395        int mem_val = *((int *)buf);
396        delete buf;
397
398        if(val != mem_val) {
399            DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAKE, read: %d, "
400                                    "expected: %d\n", mem_val, val);
401            return -OS::TGT_EWOULDBLOCK;
402        }
403
404        // Queue the thread context
405        std::list<ThreadContext *> * tcWaitList;
406        if (futex_map.count(uaddr)) {
407            tcWaitList = futex_map.find(uaddr)->second;
408        } else {
409            tcWaitList = new std::list<ThreadContext *>();
410            futex_map.insert(std::pair< uint64_t,
411                            std::list<ThreadContext *> * >(uaddr, tcWaitList));
412        }
413        tcWaitList->push_back(tc);
414        DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAIT, suspending calling "
415                                "thread context\n");
416        tc->suspend();
417        return 0;
418    } else if (op == OS::TGT_FUTEX_WAKE){
419        int wokenUp = 0;
420        std::list<ThreadContext *> * tcWaitList;
421        if (futex_map.count(uaddr)) {
422            tcWaitList = futex_map.find(uaddr)->second;
423            while (tcWaitList->size() > 0 && wokenUp < val) {
424                tcWaitList->front()->activate();
425                tcWaitList->pop_front();
426                wokenUp++;
427            }
428            if(tcWaitList->empty()) {
429                futex_map.erase(uaddr);
430                delete tcWaitList;
431            }
432        }
433        DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAKE, activated %d waiting "
434                                "thread contexts\n", wokenUp);
435        return wokenUp;
436    } else {
437        warn("sys_futex: op %d is not implemented, just returning...", op);
438        return 0;
439    }
440
441}
442
443
444/// Pseudo Funcs  - These functions use a different return convension,
445/// returning a second value in a register other than the normal return register
446SyscallReturn pipePseudoFunc(SyscallDesc *desc, int num,
447                             LiveProcess *process, ThreadContext *tc);
448
449/// Target getpidPseudo() handler.
450SyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num,
451                               LiveProcess *p, ThreadContext *tc);
452
453/// Target getuidPseudo() handler.
454SyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num,
455                               LiveProcess *p, ThreadContext *tc);
456
457/// Target getgidPseudo() handler.
458SyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num,
459                               LiveProcess *p, ThreadContext *tc);
460
461
462/// A readable name for 1,000,000, for converting microseconds to seconds.
463const int one_million = 1000000;
464
465/// Approximate seconds since the epoch (1/1/1970).  About a billion,
466/// by my reckoning.  We want to keep this a constant (not use the
467/// real-world time) to keep simulations repeatable.
468const unsigned seconds_since_epoch = 1000000000;
469
470/// Helper function to convert current elapsed time to seconds and
471/// microseconds.
472template <class T1, class T2>
473void
474getElapsedTime(T1 &sec, T2 &usec)
475{
476    int elapsed_usecs = curTick() / SimClock::Int::us;
477    sec = elapsed_usecs / one_million;
478    usec = elapsed_usecs % one_million;
479}
480
481//////////////////////////////////////////////////////////////////////
482//
483// The following emulation functions are generic, but need to be
484// templated to account for differences in types, constants, etc.
485//
486//////////////////////////////////////////////////////////////////////
487
488#if NO_STAT64
489    typedef struct stat hst_stat;
490    typedef struct stat hst_stat64;
491#else
492    typedef struct stat hst_stat;
493    typedef struct stat64 hst_stat64;
494#endif
495
496//// Helper function to convert a host stat buffer to a target stat
497//// buffer.  Also copies the target buffer out to the simulated
498//// memory space.  Used by stat(), fstat(), and lstat().
499
500template <typename target_stat, typename host_stat>
501static void
502convertStatBuf(target_stat &tgt, host_stat *host, bool fakeTTY = false)
503{
504    using namespace TheISA;
505
506    if (fakeTTY)
507        tgt->st_dev = 0xA;
508    else
509        tgt->st_dev = host->st_dev;
510    tgt->st_dev = TheISA::htog(tgt->st_dev);
511    tgt->st_ino = host->st_ino;
512    tgt->st_ino = TheISA::htog(tgt->st_ino);
513    tgt->st_mode = host->st_mode;
514    if (fakeTTY) {
515        // Claim to be a character device
516        tgt->st_mode &= ~S_IFMT;    // Clear S_IFMT
517        tgt->st_mode |= S_IFCHR;    // Set S_IFCHR
518    }
519    tgt->st_mode = TheISA::htog(tgt->st_mode);
520    tgt->st_nlink = host->st_nlink;
521    tgt->st_nlink = TheISA::htog(tgt->st_nlink);
522    tgt->st_uid = host->st_uid;
523    tgt->st_uid = TheISA::htog(tgt->st_uid);
524    tgt->st_gid = host->st_gid;
525    tgt->st_gid = TheISA::htog(tgt->st_gid);
526    if (fakeTTY)
527        tgt->st_rdev = 0x880d;
528    else
529        tgt->st_rdev = host->st_rdev;
530    tgt->st_rdev = TheISA::htog(tgt->st_rdev);
531    tgt->st_size = host->st_size;
532    tgt->st_size = TheISA::htog(tgt->st_size);
533    tgt->st_atimeX = host->st_atime;
534    tgt->st_atimeX = TheISA::htog(tgt->st_atimeX);
535    tgt->st_mtimeX = host->st_mtime;
536    tgt->st_mtimeX = TheISA::htog(tgt->st_mtimeX);
537    tgt->st_ctimeX = host->st_ctime;
538    tgt->st_ctimeX = TheISA::htog(tgt->st_ctimeX);
539    // Force the block size to be 8k. This helps to ensure buffered io works
540    // consistently across different hosts.
541    tgt->st_blksize = 0x2000;
542    tgt->st_blksize = TheISA::htog(tgt->st_blksize);
543    tgt->st_blocks = host->st_blocks;
544    tgt->st_blocks = TheISA::htog(tgt->st_blocks);
545}
546
547// Same for stat64
548
549template <typename target_stat, typename host_stat64>
550static void
551convertStat64Buf(target_stat &tgt, host_stat64 *host, bool fakeTTY = false)
552{
553    using namespace TheISA;
554
555    convertStatBuf<target_stat, host_stat64>(tgt, host, fakeTTY);
556#if defined(STAT_HAVE_NSEC)
557    tgt->st_atime_nsec = host->st_atime_nsec;
558    tgt->st_atime_nsec = TheISA::htog(tgt->st_atime_nsec);
559    tgt->st_mtime_nsec = host->st_mtime_nsec;
560    tgt->st_mtime_nsec = TheISA::htog(tgt->st_mtime_nsec);
561    tgt->st_ctime_nsec = host->st_ctime_nsec;
562    tgt->st_ctime_nsec = TheISA::htog(tgt->st_ctime_nsec);
563#else
564    tgt->st_atime_nsec = 0;
565    tgt->st_mtime_nsec = 0;
566    tgt->st_ctime_nsec = 0;
567#endif
568}
569
570//Here are a couple convenience functions
571template<class OS>
572static void
573copyOutStatBuf(SETranslatingPortProxy &mem, Addr addr,
574        hst_stat *host, bool fakeTTY = false)
575{
576    typedef TypedBufferArg<typename OS::tgt_stat> tgt_stat_buf;
577    tgt_stat_buf tgt(addr);
578    convertStatBuf<tgt_stat_buf, hst_stat>(tgt, host, fakeTTY);
579    tgt.copyOut(mem);
580}
581
582template<class OS>
583static void
584copyOutStat64Buf(SETranslatingPortProxy &mem, Addr addr,
585        hst_stat64 *host, bool fakeTTY = false)
586{
587    typedef TypedBufferArg<typename OS::tgt_stat64> tgt_stat_buf;
588    tgt_stat_buf tgt(addr);
589    convertStat64Buf<tgt_stat_buf, hst_stat64>(tgt, host, fakeTTY);
590    tgt.copyOut(mem);
591}
592
593/// Target ioctl() handler.  For the most part, programs call ioctl()
594/// only to find out if their stdout is a tty, to determine whether to
595/// do line or block buffering.  We always claim that output fds are
596/// not TTYs to provide repeatable results.
597template <class OS>
598SyscallReturn
599ioctlFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
600          ThreadContext *tc)
601{
602    int index = 0;
603    int fd = process->getSyscallArg(tc, index);
604    unsigned req = process->getSyscallArg(tc, index);
605
606    DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", fd, req);
607
608    Process::FdMap *fdObj = process->sim_fd_obj(fd);
609
610    if (fdObj == NULL) {
611        // doesn't map to any simulator fd: not a valid target fd
612        return -EBADF;
613    }
614
615    if (fdObj->driver != NULL) {
616        return fdObj->driver->ioctl(process, tc, req);
617    }
618
619    if (OS::isTtyReq(req)) {
620        return -ENOTTY;
621    }
622
623    warn("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ \n",
624         fd, req, tc->pcState());
625    return -ENOTTY;
626}
627
628template <class OS>
629static SyscallReturn
630openFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
631         ThreadContext *tc, int index)
632{
633    std::string path;
634
635    if (!tc->getMemProxy().tryReadString(path,
636                process->getSyscallArg(tc, index)))
637        return -EFAULT;
638
639    int tgtFlags = process->getSyscallArg(tc, index);
640    int mode = process->getSyscallArg(tc, index);
641    int hostFlags = 0;
642
643    // translate open flags
644    for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) {
645        if (tgtFlags & OS::openFlagTable[i].tgtFlag) {
646            tgtFlags &= ~OS::openFlagTable[i].tgtFlag;
647            hostFlags |= OS::openFlagTable[i].hostFlag;
648        }
649    }
650
651    // any target flags left?
652    if (tgtFlags != 0)
653        warn("Syscall: open: cannot decode flags 0x%x", tgtFlags);
654
655#ifdef __CYGWIN32__
656    hostFlags |= O_BINARY;
657#endif
658
659    // Adjust path for current working directory
660    path = process->fullPath(path);
661
662    DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str());
663
664    if (startswith(path, "/dev/")) {
665        std::string filename = path.substr(strlen("/dev/"));
666        if (filename == "sysdev0") {
667            // This is a memory-mapped high-resolution timer device on Alpha.
668            // We don't support it, so just punt.
669            warn("Ignoring open(%s, ...)\n", path);
670            return -ENOENT;
671        }
672
673        EmulatedDriver *drv = process->findDriver(filename);
674        if (drv != NULL) {
675            // the driver's open method will allocate a fd from the
676            // process if necessary.
677            return drv->open(process, tc, mode, hostFlags);
678        }
679
680        // fall through here for pass through to host devices, such as
681        // /dev/zero
682    }
683
684    int fd;
685    int local_errno;
686    if (startswith(path, "/proc/") || startswith(path, "/system/") ||
687        startswith(path, "/platform/") || startswith(path, "/sys/")) {
688        // It's a proc/sys entry and requires special handling
689        fd = OS::openSpecialFile(path, process, tc);
690        local_errno = ENOENT;
691     } else {
692        // open the file
693        fd = open(path.c_str(), hostFlags, mode);
694        local_errno = errno;
695     }
696
697    if (fd == -1)
698        return -local_errno;
699
700    return process->alloc_fd(fd, path.c_str(), hostFlags, mode, false);
701}
702
703/// Target open() handler.
704template <class OS>
705SyscallReturn
706openFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
707         ThreadContext *tc)
708{
709    return openFunc<OS>(desc, callnum, process, tc, 0);
710}
711
712/// Target openat() handler.
713template <class OS>
714SyscallReturn
715openatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
716         ThreadContext *tc)
717{
718    int index = 0;
719    int dirfd = process->getSyscallArg(tc, index);
720    if (dirfd != OS::TGT_AT_FDCWD)
721        warn("openat: first argument not AT_FDCWD; unlikely to work");
722    return openFunc<OS>(desc, callnum, process, tc, 1);
723}
724
725/// Target facessat() handler
726template <class OS>
727SyscallReturn
728faccessatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
729        ThreadContext *tc)
730{
731    int index = 0;
732    int dirfd = process->getSyscallArg(tc, index);
733    if (dirfd != OS::TGT_AT_FDCWD)
734        warn("faccessat: first argument not AT_FDCWD; unlikely to work");
735    return accessFunc(desc, callnum, process, tc, 1);
736}
737
738/// Target readlinkat() handler
739template <class OS>
740SyscallReturn
741readlinkatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
742        ThreadContext *tc)
743{
744    int index = 0;
745    int dirfd = process->getSyscallArg(tc, index);
746    if (dirfd != OS::TGT_AT_FDCWD)
747        warn("openat: first argument not AT_FDCWD; unlikely to work");
748    return readlinkFunc(desc, callnum, process, tc, 1);
749}
750
751/// Target sysinfo() handler.
752template <class OS>
753SyscallReturn
754sysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
755         ThreadContext *tc)
756{
757
758    int index = 0;
759    TypedBufferArg<typename OS::tgt_sysinfo>
760        sysinfo(process->getSyscallArg(tc, index));
761
762    sysinfo->uptime=seconds_since_epoch;
763    sysinfo->totalram=process->system->memSize();
764
765    sysinfo.copyOut(tc->getMemProxy());
766
767    return 0;
768}
769
770/// Target chmod() handler.
771template <class OS>
772SyscallReturn
773chmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
774          ThreadContext *tc)
775{
776    std::string path;
777
778    int index = 0;
779    if (!tc->getMemProxy().tryReadString(path,
780                process->getSyscallArg(tc, index))) {
781        return -EFAULT;
782    }
783
784    uint32_t mode = process->getSyscallArg(tc, index);
785    mode_t hostMode = 0;
786
787    // XXX translate mode flags via OS::something???
788    hostMode = mode;
789
790    // Adjust path for current working directory
791    path = process->fullPath(path);
792
793    // do the chmod
794    int result = chmod(path.c_str(), hostMode);
795    if (result < 0)
796        return -errno;
797
798    return 0;
799}
800
801
802/// Target fchmod() handler.
803template <class OS>
804SyscallReturn
805fchmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
806           ThreadContext *tc)
807{
808    int index = 0;
809    int fd = process->getSyscallArg(tc, index);
810    if (fd < 0 || process->sim_fd(fd) < 0) {
811        // doesn't map to any simulator fd: not a valid target fd
812        return -EBADF;
813    }
814
815    uint32_t mode = process->getSyscallArg(tc, index);
816    mode_t hostMode = 0;
817
818    // XXX translate mode flags via OS::someting???
819    hostMode = mode;
820
821    // do the fchmod
822    int result = fchmod(process->sim_fd(fd), hostMode);
823    if (result < 0)
824        return -errno;
825
826    return 0;
827}
828
829/// Target mremap() handler.
830template <class OS>
831SyscallReturn
832mremapFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc)
833{
834    int index = 0;
835    Addr start = process->getSyscallArg(tc, index);
836    uint64_t old_length = process->getSyscallArg(tc, index);
837    uint64_t new_length = process->getSyscallArg(tc, index);
838    uint64_t flags = process->getSyscallArg(tc, index);
839    uint64_t provided_address = 0;
840    bool use_provided_address = flags & OS::TGT_MREMAP_FIXED;
841
842    if (use_provided_address)
843        provided_address = process->getSyscallArg(tc, index);
844
845    if ((start % TheISA::PageBytes != 0) ||
846        (provided_address % TheISA::PageBytes != 0)) {
847        warn("mremap failing: arguments not page aligned");
848        return -EINVAL;
849    }
850
851    new_length = roundUp(new_length, TheISA::PageBytes);
852
853    if (new_length > old_length) {
854        if ((start + old_length) == process->mmap_end &&
855            (!use_provided_address || provided_address == start)) {
856            uint64_t diff = new_length - old_length;
857            process->allocateMem(process->mmap_end, diff);
858            process->mmap_end += diff;
859            return start;
860        } else {
861            if (!use_provided_address && !(flags & OS::TGT_MREMAP_MAYMOVE)) {
862                warn("can't remap here and MREMAP_MAYMOVE flag not set\n");
863                return -ENOMEM;
864            } else {
865                uint64_t new_start = use_provided_address ?
866                    provided_address : process->mmap_end;
867                process->pTable->remap(start, old_length, new_start);
868                warn("mremapping to new vaddr %08p-%08p, adding %d\n",
869                     new_start, new_start + new_length,
870                     new_length - old_length);
871                // add on the remaining unallocated pages
872                process->allocateMem(new_start + old_length,
873                                     new_length - old_length,
874                                     use_provided_address /* clobber */);
875                if (!use_provided_address)
876                    process->mmap_end += new_length;
877                if (use_provided_address &&
878                    new_start + new_length > process->mmap_end) {
879                    // something fishy going on here, at least notify the user
880                    // @todo: increase mmap_end?
881                    warn("mmap region limit exceeded with MREMAP_FIXED\n");
882                }
883                warn("returning %08p as start\n", new_start);
884                return new_start;
885            }
886        }
887    } else {
888        if (use_provided_address && provided_address != start)
889            process->pTable->remap(start, new_length, provided_address);
890        process->pTable->unmap(start + new_length, old_length - new_length);
891        return use_provided_address ? provided_address : start;
892    }
893}
894
895/// Target stat() handler.
896template <class OS>
897SyscallReturn
898statFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
899         ThreadContext *tc)
900{
901    std::string path;
902
903    int index = 0;
904    if (!tc->getMemProxy().tryReadString(path,
905                process->getSyscallArg(tc, index))) {
906        return -EFAULT;
907    }
908    Addr bufPtr = process->getSyscallArg(tc, index);
909
910    // Adjust path for current working directory
911    path = process->fullPath(path);
912
913    struct stat hostBuf;
914    int result = stat(path.c_str(), &hostBuf);
915
916    if (result < 0)
917        return -errno;
918
919    copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
920
921    return 0;
922}
923
924
925/// Target stat64() handler.
926template <class OS>
927SyscallReturn
928stat64Func(SyscallDesc *desc, int callnum, LiveProcess *process,
929           ThreadContext *tc)
930{
931    std::string path;
932
933    int index = 0;
934    if (!tc->getMemProxy().tryReadString(path,
935                process->getSyscallArg(tc, index)))
936        return -EFAULT;
937    Addr bufPtr = process->getSyscallArg(tc, index);
938
939    // Adjust path for current working directory
940    path = process->fullPath(path);
941
942#if NO_STAT64
943    struct stat  hostBuf;
944    int result = stat(path.c_str(), &hostBuf);
945#else
946    struct stat64 hostBuf;
947    int result = stat64(path.c_str(), &hostBuf);
948#endif
949
950    if (result < 0)
951        return -errno;
952
953    copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
954
955    return 0;
956}
957
958
959/// Target fstatat64() handler.
960template <class OS>
961SyscallReturn
962fstatat64Func(SyscallDesc *desc, int callnum, LiveProcess *process,
963              ThreadContext *tc)
964{
965    int index = 0;
966    int dirfd = process->getSyscallArg(tc, index);
967    if (dirfd != OS::TGT_AT_FDCWD)
968        warn("openat: first argument not AT_FDCWD; unlikely to work");
969
970    std::string path;
971    if (!tc->getMemProxy().tryReadString(path,
972                process->getSyscallArg(tc, index)))
973        return -EFAULT;
974    Addr bufPtr = process->getSyscallArg(tc, index);
975
976    // Adjust path for current working directory
977    path = process->fullPath(path);
978
979#if NO_STAT64
980    struct stat  hostBuf;
981    int result = stat(path.c_str(), &hostBuf);
982#else
983    struct stat64 hostBuf;
984    int result = stat64(path.c_str(), &hostBuf);
985#endif
986
987    if (result < 0)
988        return -errno;
989
990    copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
991
992    return 0;
993}
994
995
996/// Target fstat64() handler.
997template <class OS>
998SyscallReturn
999fstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process,
1000            ThreadContext *tc)
1001{
1002    int index = 0;
1003    int fd = process->getSyscallArg(tc, index);
1004    Addr bufPtr = process->getSyscallArg(tc, index);
1005    if (fd < 0 || process->sim_fd(fd) < 0) {
1006        // doesn't map to any simulator fd: not a valid target fd
1007        return -EBADF;
1008    }
1009
1010#if NO_STAT64
1011    struct stat  hostBuf;
1012    int result = fstat(process->sim_fd(fd), &hostBuf);
1013#else
1014    struct stat64  hostBuf;
1015    int result = fstat64(process->sim_fd(fd), &hostBuf);
1016#endif
1017
1018    if (result < 0)
1019        return -errno;
1020
1021    copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (fd == 1));
1022
1023    return 0;
1024}
1025
1026
1027/// Target lstat() handler.
1028template <class OS>
1029SyscallReturn
1030lstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1031          ThreadContext *tc)
1032{
1033    std::string path;
1034
1035    int index = 0;
1036    if (!tc->getMemProxy().tryReadString(path,
1037                process->getSyscallArg(tc, index))) {
1038        return -EFAULT;
1039    }
1040    Addr bufPtr = process->getSyscallArg(tc, index);
1041
1042    // Adjust path for current working directory
1043    path = process->fullPath(path);
1044
1045    struct stat hostBuf;
1046    int result = lstat(path.c_str(), &hostBuf);
1047
1048    if (result < 0)
1049        return -errno;
1050
1051    copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
1052
1053    return 0;
1054}
1055
1056/// Target lstat64() handler.
1057template <class OS>
1058SyscallReturn
1059lstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process,
1060            ThreadContext *tc)
1061{
1062    std::string path;
1063
1064    int index = 0;
1065    if (!tc->getMemProxy().tryReadString(path,
1066                process->getSyscallArg(tc, index))) {
1067        return -EFAULT;
1068    }
1069    Addr bufPtr = process->getSyscallArg(tc, index);
1070
1071    // Adjust path for current working directory
1072    path = process->fullPath(path);
1073
1074#if NO_STAT64
1075    struct stat hostBuf;
1076    int result = lstat(path.c_str(), &hostBuf);
1077#else
1078    struct stat64 hostBuf;
1079    int result = lstat64(path.c_str(), &hostBuf);
1080#endif
1081
1082    if (result < 0)
1083        return -errno;
1084
1085    copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
1086
1087    return 0;
1088}
1089
1090/// Target fstat() handler.
1091template <class OS>
1092SyscallReturn
1093fstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1094          ThreadContext *tc)
1095{
1096    int index = 0;
1097    int fd = process->sim_fd(process->getSyscallArg(tc, index));
1098    Addr bufPtr = process->getSyscallArg(tc, index);
1099
1100    DPRINTF(SyscallVerbose, "fstat(%d, ...)\n", fd);
1101
1102    if (fd < 0)
1103        return -EBADF;
1104
1105    struct stat hostBuf;
1106    int result = fstat(fd, &hostBuf);
1107
1108    if (result < 0)
1109        return -errno;
1110
1111    copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (fd == 1));
1112
1113    return 0;
1114}
1115
1116
1117/// Target statfs() handler.
1118template <class OS>
1119SyscallReturn
1120statfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1121           ThreadContext *tc)
1122{
1123    std::string path;
1124
1125    int index = 0;
1126    if (!tc->getMemProxy().tryReadString(path,
1127                process->getSyscallArg(tc, index))) {
1128        return -EFAULT;
1129    }
1130    Addr bufPtr = process->getSyscallArg(tc, index);
1131
1132    // Adjust path for current working directory
1133    path = process->fullPath(path);
1134
1135    struct statfs hostBuf;
1136    int result = statfs(path.c_str(), &hostBuf);
1137
1138    if (result < 0)
1139        return -errno;
1140
1141    OS::copyOutStatfsBuf(tc->getMemProxy(), bufPtr, &hostBuf);
1142
1143    return 0;
1144}
1145
1146
1147/// Target fstatfs() handler.
1148template <class OS>
1149SyscallReturn
1150fstatfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1151            ThreadContext *tc)
1152{
1153    int index = 0;
1154    int fd = process->sim_fd(process->getSyscallArg(tc, index));
1155    Addr bufPtr = process->getSyscallArg(tc, index);
1156
1157    if (fd < 0)
1158        return -EBADF;
1159
1160    struct statfs hostBuf;
1161    int result = fstatfs(fd, &hostBuf);
1162
1163    if (result < 0)
1164        return -errno;
1165
1166    OS::copyOutStatfsBuf(tc->getMemProxy(), bufPtr, &hostBuf);
1167
1168    return 0;
1169}
1170
1171
1172/// Target writev() handler.
1173template <class OS>
1174SyscallReturn
1175writevFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1176           ThreadContext *tc)
1177{
1178    int index = 0;
1179    int fd = process->getSyscallArg(tc, index);
1180    if (fd < 0 || process->sim_fd(fd) < 0) {
1181        // doesn't map to any simulator fd: not a valid target fd
1182        return -EBADF;
1183    }
1184
1185    SETranslatingPortProxy &p = tc->getMemProxy();
1186    uint64_t tiov_base = process->getSyscallArg(tc, index);
1187    size_t count = process->getSyscallArg(tc, index);
1188    struct iovec hiov[count];
1189    for (size_t i = 0; i < count; ++i) {
1190        typename OS::tgt_iovec tiov;
1191
1192        p.readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec),
1193                   (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec));
1194        hiov[i].iov_len = TheISA::gtoh(tiov.iov_len);
1195        hiov[i].iov_base = new char [hiov[i].iov_len];
1196        p.readBlob(TheISA::gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base,
1197                   hiov[i].iov_len);
1198    }
1199
1200    int result = writev(process->sim_fd(fd), hiov, count);
1201
1202    for (size_t i = 0; i < count; ++i)
1203        delete [] (char *)hiov[i].iov_base;
1204
1205    if (result < 0)
1206        return -errno;
1207
1208    return 0;
1209}
1210
1211
1212/// Target mmap() handler.
1213///
1214/// We don't really handle mmap().  If the target is mmaping an
1215/// anonymous region or /dev/zero, we can get away with doing basically
1216/// nothing (since memory is initialized to zero and the simulator
1217/// doesn't really check addresses anyway).
1218///
1219template <class OS>
1220SyscallReturn
1221mmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
1222{
1223    int index = 0;
1224    Addr start = p->getSyscallArg(tc, index);
1225    uint64_t length = p->getSyscallArg(tc, index);
1226    index++; // int prot = p->getSyscallArg(tc, index);
1227    int flags = p->getSyscallArg(tc, index);
1228    int tgt_fd = p->getSyscallArg(tc, index);
1229    int offset = p->getSyscallArg(tc, index);
1230
1231    if (length > 0x100000000ULL)
1232        warn("mmap length argument %#x is unreasonably large.\n", length);
1233
1234    if (!(flags & OS::TGT_MAP_ANONYMOUS)) {
1235        Process::FdMap *fd_map = p->sim_fd_obj(tgt_fd);
1236        if (!fd_map || fd_map->fd < 0) {
1237            warn("mmap failing: target fd %d is not valid\n", tgt_fd);
1238            return -EBADF;
1239        }
1240
1241        if (fd_map->filename != "/dev/zero") {
1242            // This is very likely broken, but leave a warning here
1243            // (rather than panic) in case /dev/zero is known by
1244            // another name on some platform
1245            warn("allowing mmap of file %s; mmap not supported on files"
1246                 " other than /dev/zero\n", fd_map->filename);
1247        }
1248    }
1249
1250    length = roundUp(length, TheISA::PageBytes);
1251
1252    if ((start  % TheISA::PageBytes) != 0 ||
1253        (offset % TheISA::PageBytes) != 0) {
1254        warn("mmap failing: arguments not page-aligned: "
1255             "start 0x%x offset 0x%x",
1256             start, offset);
1257        return -EINVAL;
1258    }
1259
1260    // are we ok with clobbering existing mappings?  only set this to
1261    // true if the user has been warned.
1262    bool clobber = false;
1263
1264    // try to use the caller-provided address if there is one
1265    bool use_provided_address = (start != 0);
1266
1267    if (use_provided_address) {
1268        // check to see if the desired address is already in use
1269        if (!p->pTable->isUnmapped(start, length)) {
1270            // there are existing mappings in the desired range
1271            // whether we clobber them or not depends on whether the caller
1272            // specified MAP_FIXED
1273            if (flags & OS::TGT_MAP_FIXED) {
1274                // MAP_FIXED specified: map attempt fails
1275                return -EINVAL;
1276            } else {
1277                // MAP_FIXED not specified: ignore suggested start address
1278                warn("mmap: ignoring suggested map address 0x%x\n", start);
1279                use_provided_address = false;
1280            }
1281        }
1282    }
1283
1284    if (!use_provided_address) {
1285        // no address provided, or provided address unusable:
1286        // pick next address from our "mmap region"
1287        if (OS::mmapGrowsDown()) {
1288            start = p->mmap_end - length;
1289            p->mmap_end = start;
1290        } else {
1291            start = p->mmap_end;
1292            p->mmap_end += length;
1293        }
1294    }
1295
1296    p->allocateMem(start, length, clobber);
1297
1298    return start;
1299}
1300
1301/// Target getrlimit() handler.
1302template <class OS>
1303SyscallReturn
1304getrlimitFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1305        ThreadContext *tc)
1306{
1307    int index = 0;
1308    unsigned resource = process->getSyscallArg(tc, index);
1309    TypedBufferArg<typename OS::rlimit> rlp(process->getSyscallArg(tc, index));
1310
1311    switch (resource) {
1312        case OS::TGT_RLIMIT_STACK:
1313            // max stack size in bytes: make up a number (8MB for now)
1314            rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024;
1315            rlp->rlim_cur = TheISA::htog(rlp->rlim_cur);
1316            rlp->rlim_max = TheISA::htog(rlp->rlim_max);
1317            break;
1318
1319        case OS::TGT_RLIMIT_DATA:
1320            // max data segment size in bytes: make up a number
1321            rlp->rlim_cur = rlp->rlim_max = 256 * 1024 * 1024;
1322            rlp->rlim_cur = TheISA::htog(rlp->rlim_cur);
1323            rlp->rlim_max = TheISA::htog(rlp->rlim_max);
1324            break;
1325
1326        default:
1327            std::cerr << "getrlimitFunc: unimplemented resource " << resource
1328                << std::endl;
1329            abort();
1330            break;
1331    }
1332
1333    rlp.copyOut(tc->getMemProxy());
1334    return 0;
1335}
1336
1337/// Target gettimeofday() handler.
1338template <class OS>
1339SyscallReturn
1340gettimeofdayFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1341        ThreadContext *tc)
1342{
1343    int index = 0;
1344    TypedBufferArg<typename OS::timeval> tp(process->getSyscallArg(tc, index));
1345
1346    getElapsedTime(tp->tv_sec, tp->tv_usec);
1347    tp->tv_sec += seconds_since_epoch;
1348    tp->tv_sec = TheISA::htog(tp->tv_sec);
1349    tp->tv_usec = TheISA::htog(tp->tv_usec);
1350
1351    tp.copyOut(tc->getMemProxy());
1352
1353    return 0;
1354}
1355
1356
1357/// Target utimes() handler.
1358template <class OS>
1359SyscallReturn
1360utimesFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1361           ThreadContext *tc)
1362{
1363    std::string path;
1364
1365    int index = 0;
1366    if (!tc->getMemProxy().tryReadString(path,
1367                process->getSyscallArg(tc, index))) {
1368        return -EFAULT;
1369    }
1370
1371    TypedBufferArg<typename OS::timeval [2]>
1372        tp(process->getSyscallArg(tc, index));
1373    tp.copyIn(tc->getMemProxy());
1374
1375    struct timeval hostTimeval[2];
1376    for (int i = 0; i < 2; ++i)
1377    {
1378        hostTimeval[i].tv_sec = TheISA::gtoh((*tp)[i].tv_sec);
1379        hostTimeval[i].tv_usec = TheISA::gtoh((*tp)[i].tv_usec);
1380    }
1381
1382    // Adjust path for current working directory
1383    path = process->fullPath(path);
1384
1385    int result = utimes(path.c_str(), hostTimeval);
1386
1387    if (result < 0)
1388        return -errno;
1389
1390    return 0;
1391}
1392/// Target getrusage() function.
1393template <class OS>
1394SyscallReturn
1395getrusageFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1396              ThreadContext *tc)
1397{
1398    int index = 0;
1399    int who = process->getSyscallArg(tc, index); // THREAD, SELF, or CHILDREN
1400    TypedBufferArg<typename OS::rusage> rup(process->getSyscallArg(tc, index));
1401
1402    rup->ru_utime.tv_sec = 0;
1403    rup->ru_utime.tv_usec = 0;
1404    rup->ru_stime.tv_sec = 0;
1405    rup->ru_stime.tv_usec = 0;
1406    rup->ru_maxrss = 0;
1407    rup->ru_ixrss = 0;
1408    rup->ru_idrss = 0;
1409    rup->ru_isrss = 0;
1410    rup->ru_minflt = 0;
1411    rup->ru_majflt = 0;
1412    rup->ru_nswap = 0;
1413    rup->ru_inblock = 0;
1414    rup->ru_oublock = 0;
1415    rup->ru_msgsnd = 0;
1416    rup->ru_msgrcv = 0;
1417    rup->ru_nsignals = 0;
1418    rup->ru_nvcsw = 0;
1419    rup->ru_nivcsw = 0;
1420
1421    switch (who) {
1422      case OS::TGT_RUSAGE_SELF:
1423        getElapsedTime(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec);
1424        rup->ru_utime.tv_sec = TheISA::htog(rup->ru_utime.tv_sec);
1425        rup->ru_utime.tv_usec = TheISA::htog(rup->ru_utime.tv_usec);
1426        break;
1427
1428      case OS::TGT_RUSAGE_CHILDREN:
1429        // do nothing.  We have no child processes, so they take no time.
1430        break;
1431
1432      default:
1433        // don't really handle THREAD or CHILDREN, but just warn and
1434        // plow ahead
1435        warn("getrusage() only supports RUSAGE_SELF.  Parameter %d ignored.",
1436             who);
1437    }
1438
1439    rup.copyOut(tc->getMemProxy());
1440
1441    return 0;
1442}
1443
1444/// Target times() function.
1445template <class OS>
1446SyscallReturn
1447timesFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1448           ThreadContext *tc)
1449{
1450    int index = 0;
1451    TypedBufferArg<typename OS::tms> bufp(process->getSyscallArg(tc, index));
1452
1453    // Fill in the time structure (in clocks)
1454    int64_t clocks = curTick() * OS::M5_SC_CLK_TCK / SimClock::Int::s;
1455    bufp->tms_utime = clocks;
1456    bufp->tms_stime = 0;
1457    bufp->tms_cutime = 0;
1458    bufp->tms_cstime = 0;
1459
1460    // Convert to host endianness
1461    bufp->tms_utime = TheISA::htog(bufp->tms_utime);
1462
1463    // Write back
1464    bufp.copyOut(tc->getMemProxy());
1465
1466    // Return clock ticks since system boot
1467    return clocks;
1468}
1469
1470/// Target time() function.
1471template <class OS>
1472SyscallReturn
1473timeFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1474           ThreadContext *tc)
1475{
1476    typename OS::time_t sec, usec;
1477    getElapsedTime(sec, usec);
1478    sec += seconds_since_epoch;
1479
1480    int index = 0;
1481    Addr taddr = (Addr)process->getSyscallArg(tc, index);
1482    if(taddr != 0) {
1483        typename OS::time_t t = sec;
1484        t = TheISA::htog(t);
1485        SETranslatingPortProxy &p = tc->getMemProxy();
1486        p.writeBlob(taddr, (uint8_t*)&t, (int)sizeof(typename OS::time_t));
1487    }
1488    return sec;
1489}
1490
1491
1492#endif // __SIM_SYSCALL_EMUL_HH__
1493