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