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