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