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