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