syscall_emul.hh revision 2474
1/*
2 * Copyright (c) 2003-2005 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#ifndef __SIM_SYSCALL_EMUL_HH__
30#define __SIM_SYSCALL_EMUL_HH__
31
32#define BSD_HOST (defined(__APPLE__) || defined(__OpenBSD__) || \
33                  defined(__FreeBSD__))
34
35///
36/// @file syscall_emul.hh
37///
38/// This file defines objects used to emulate syscalls from the target
39/// application on the host machine.
40
41#include <errno.h>
42#include <string>
43#ifdef __CYGWIN32__
44#include <sys/fcntl.h>	// for O_BINARY
45#endif
46#include <sys/uio.h>
47
48#include "arch/isa_traits.hh"	// for Addr
49#include "base/chunk_generator.hh"
50#include "base/intmath.hh"	// for RoundUp
51#include "base/misc.hh"
52#include "base/trace.hh"
53#include "cpu/base.hh"
54#include "cpu/exec_context.hh"
55#include "mem/translating_port.hh"
56#include "mem/page_table.hh"
57#include "sim/process.hh"
58
59///
60/// System call descriptor.
61///
62class SyscallDesc {
63
64  public:
65
66    /// Typedef for target syscall handler functions.
67    typedef SyscallReturn (*FuncPtr)(SyscallDesc *, int num,
68                           Process *, ExecContext *);
69
70    const char *name;	//!< Syscall name (e.g., "open").
71    FuncPtr funcPtr;	//!< Pointer to emulation function.
72    int flags;		//!< Flags (see Flags enum).
73
74    /// Flag values for controlling syscall behavior.
75    enum Flags {
76        /// Don't set return regs according to funcPtr return value.
77        /// Used for syscalls with non-standard return conventions
78        /// that explicitly set the ExecContext regs (e.g.,
79        /// sigreturn).
80        SuppressReturnValue = 1
81    };
82
83    /// Constructor.
84    SyscallDesc(const char *_name, FuncPtr _funcPtr, int _flags = 0)
85        : name(_name), funcPtr(_funcPtr), flags(_flags)
86    {
87    }
88
89    /// Emulate the syscall.  Public interface for calling through funcPtr.
90    void doSyscall(int callnum, Process *proc, ExecContext *xc);
91};
92
93
94class BaseBufferArg {
95
96  public:
97
98    BaseBufferArg(Addr _addr, int _size) : addr(_addr), size(_size)
99    {
100        bufPtr = new uint8_t[size];
101        // clear out buffer: in case we only partially populate this,
102        // and then do a copyOut(), we want to make sure we don't
103        // introduce any random junk into the simulated address space
104        memset(bufPtr, 0, size);
105    }
106
107    virtual ~BaseBufferArg() { delete [] bufPtr; }
108
109    //
110    // copy data into simulator space (read from target memory)
111    //
112    virtual bool copyIn(TranslatingPort *memport)
113    {
114        memport->readBlob(addr, bufPtr, size);
115        return true;	// no EFAULT detection for now
116    }
117
118    //
119    // copy data out of simulator space (write to target memory)
120    //
121    virtual bool copyOut(TranslatingPort *memport)
122    {
123        memport->writeBlob(addr, bufPtr, size);
124        return true;	// no EFAULT detection for now
125    }
126
127  protected:
128    Addr addr;
129    int size;
130    uint8_t *bufPtr;
131};
132
133
134class BufferArg : public BaseBufferArg
135{
136  public:
137    BufferArg(Addr _addr, int _size) : BaseBufferArg(_addr, _size) { }
138    void *bufferPtr()	{ return bufPtr; }
139};
140
141template <class T>
142class TypedBufferArg : public BaseBufferArg
143{
144  public:
145    // user can optionally specify a specific number of bytes to
146    // allocate to deal with those structs that have variable-size
147    // arrays at the end
148    TypedBufferArg(Addr _addr, int _size = sizeof(T))
149        : BaseBufferArg(_addr, _size)
150    { }
151
152    // type case
153    operator T*() { return (T *)bufPtr; }
154
155    // dereference operators
156    T &operator*()	 { return *((T *)bufPtr); }
157    T* operator->()	 { return (T *)bufPtr; }
158    T &operator[](int i) { return ((T *)bufPtr)[i]; }
159};
160
161//////////////////////////////////////////////////////////////////////
162//
163// The following emulation functions are generic enough that they
164// don't need to be recompiled for different emulated OS's.  They are
165// defined in sim/syscall_emul.cc.
166//
167//////////////////////////////////////////////////////////////////////
168
169
170/// Handler for unimplemented syscalls that we haven't thought about.
171SyscallReturn unimplementedFunc(SyscallDesc *desc, int num,
172                                Process *p, ExecContext *xc);
173
174/// Handler for unimplemented syscalls that we never intend to
175/// implement (signal handling, etc.) and should not affect the correct
176/// behavior of the program.  Print a warning only if the appropriate
177/// trace flag is enabled.  Return success to the target program.
178SyscallReturn ignoreFunc(SyscallDesc *desc, int num,
179                         Process *p, ExecContext *xc);
180
181/// Target exit() handler: terminate simulation.
182SyscallReturn exitFunc(SyscallDesc *desc, int num,
183                       Process *p, ExecContext *xc);
184
185/// Target getpagesize() handler.
186SyscallReturn getpagesizeFunc(SyscallDesc *desc, int num,
187                              Process *p, ExecContext *xc);
188
189/// Target obreak() handler: set brk address.
190SyscallReturn obreakFunc(SyscallDesc *desc, int num,
191                         Process *p, ExecContext *xc);
192
193/// Target close() handler.
194SyscallReturn closeFunc(SyscallDesc *desc, int num,
195                        Process *p, ExecContext *xc);
196
197/// Target read() handler.
198SyscallReturn readFunc(SyscallDesc *desc, int num,
199                       Process *p, ExecContext *xc);
200
201/// Target write() handler.
202SyscallReturn writeFunc(SyscallDesc *desc, int num,
203                        Process *p, ExecContext *xc);
204
205/// Target lseek() handler.
206SyscallReturn lseekFunc(SyscallDesc *desc, int num,
207                        Process *p, ExecContext *xc);
208
209/// Target munmap() handler.
210SyscallReturn munmapFunc(SyscallDesc *desc, int num,
211                         Process *p, ExecContext *xc);
212
213/// Target gethostname() handler.
214SyscallReturn gethostnameFunc(SyscallDesc *desc, int num,
215                              Process *p, ExecContext *xc);
216
217/// Target unlink() handler.
218SyscallReturn unlinkFunc(SyscallDesc *desc, int num,
219                         Process *p, ExecContext *xc);
220
221/// Target rename() handler.
222SyscallReturn renameFunc(SyscallDesc *desc, int num,
223                         Process *p, ExecContext *xc);
224
225
226/// Target truncate() handler.
227SyscallReturn truncateFunc(SyscallDesc *desc, int num,
228                           Process *p, ExecContext *xc);
229
230
231/// Target ftruncate() handler.
232SyscallReturn ftruncateFunc(SyscallDesc *desc, int num,
233                            Process *p, ExecContext *xc);
234
235
236/// Target chown() handler.
237SyscallReturn chownFunc(SyscallDesc *desc, int num,
238                        Process *p, ExecContext *xc);
239
240
241/// Target fchown() handler.
242SyscallReturn fchownFunc(SyscallDesc *desc, int num,
243                         Process *p, ExecContext *xc);
244
245/// Target fnctl() handler.
246SyscallReturn fcntlFunc(SyscallDesc *desc, int num,
247                        Process *process, ExecContext *xc);
248
249/// Target setuid() handler.
250SyscallReturn setuidFunc(SyscallDesc *desc, int num,
251                               Process *p, ExecContext *xc);
252
253/// Target getpid() handler.
254SyscallReturn getpidFunc(SyscallDesc *desc, int num,
255                               Process *p, ExecContext *xc);
256
257/// Target getuid() handler.
258SyscallReturn getuidFunc(SyscallDesc *desc, int num,
259                               Process *p, ExecContext *xc);
260
261/// Target getgid() handler.
262SyscallReturn getgidFunc(SyscallDesc *desc, int num,
263                               Process *p, ExecContext *xc);
264
265/// Target getppid() handler.
266SyscallReturn getppidFunc(SyscallDesc *desc, int num,
267                               Process *p, ExecContext *xc);
268
269/// Target geteuid() handler.
270SyscallReturn geteuidFunc(SyscallDesc *desc, int num,
271                               Process *p, ExecContext *xc);
272
273/// Target getegid() handler.
274SyscallReturn getegidFunc(SyscallDesc *desc, int num,
275                               Process *p, ExecContext *xc);
276
277
278
279/// Pseudo Funcs  - These functions use a different return convension,
280/// returning a second value in a register other than the normal return register
281SyscallReturn pipePseudoFunc(SyscallDesc *desc, int num,
282                             Process *process, ExecContext *xc);
283
284/// Target getpidPseudo() handler.
285SyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num,
286                               Process *p, ExecContext *xc);
287
288/// Target getuidPseudo() handler.
289SyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num,
290                               Process *p, ExecContext *xc);
291
292/// Target getgidPseudo() handler.
293SyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num,
294                               Process *p, ExecContext *xc);
295
296
297/// This struct is used to build an target-OS-dependent table that
298/// maps the target's open() flags to the host open() flags.
299struct OpenFlagTransTable {
300    int tgtFlag;	//!< Target system flag value.
301    int hostFlag;	//!< Corresponding host system flag value.
302};
303
304
305
306/// A readable name for 1,000,000, for converting microseconds to seconds.
307const int one_million = 1000000;
308
309/// Approximate seconds since the epoch (1/1/1970).  About a billion,
310/// by my reckoning.  We want to keep this a constant (not use the
311/// real-world time) to keep simulations repeatable.
312const unsigned seconds_since_epoch = 1000000000;
313
314/// Helper function to convert current elapsed time to seconds and
315/// microseconds.
316template <class T1, class T2>
317void
318getElapsedTime(T1 &sec, T2 &usec)
319{
320    int elapsed_usecs = curTick / Clock::Int::us;
321    sec = elapsed_usecs / one_million;
322    usec = elapsed_usecs % one_million;
323}
324
325//////////////////////////////////////////////////////////////////////
326//
327// The following emulation functions are generic, but need to be
328// templated to account for differences in types, constants, etc.
329//
330//////////////////////////////////////////////////////////////////////
331
332/// Target ioctl() handler.  For the most part, programs call ioctl()
333/// only to find out if their stdout is a tty, to determine whether to
334/// do line or block buffering.
335template <class OS>
336SyscallReturn
337ioctlFunc(SyscallDesc *desc, int callnum, Process *process,
338          ExecContext *xc)
339{
340    int fd = xc->getSyscallArg(0);
341    unsigned req = xc->getSyscallArg(1);
342
343    DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", fd, req);
344
345    if (fd < 0 || process->sim_fd(fd) < 0) {
346        // doesn't map to any simulator fd: not a valid target fd
347        return -EBADF;
348    }
349
350    switch (req) {
351      case OS::TIOCISATTY:
352      case OS::TIOCGETP:
353      case OS::TIOCSETP:
354      case OS::TIOCSETN:
355      case OS::TIOCSETC:
356      case OS::TIOCGETC:
357      case OS::TIOCGETS:
358      case OS::TIOCGETA:
359        return -ENOTTY;
360
361      default:
362        fatal("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ 0x%llx\n",
363              fd, req, xc->readPC());
364    }
365}
366
367/// Target open() handler.
368template <class OS>
369SyscallReturn
370openFunc(SyscallDesc *desc, int callnum, Process *process,
371         ExecContext *xc)
372{
373    std::string path;
374
375    if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
376        return -EFAULT;
377
378    if (path == "/dev/sysdev0") {
379        // This is a memory-mapped high-resolution timer device on Alpha.
380        // We don't support it, so just punt.
381        warn("Ignoring open(%s, ...)\n", path);
382        return -ENOENT;
383    }
384
385    int tgtFlags = xc->getSyscallArg(1);
386    int mode = xc->getSyscallArg(2);
387    int hostFlags = 0;
388
389    // translate open flags
390    for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) {
391        if (tgtFlags & OS::openFlagTable[i].tgtFlag) {
392            tgtFlags &= ~OS::openFlagTable[i].tgtFlag;
393            hostFlags |= OS::openFlagTable[i].hostFlag;
394        }
395    }
396
397    // any target flags left?
398    if (tgtFlags != 0)
399        warn("Syscall: open: cannot decode flags 0x%x", tgtFlags);
400
401#ifdef __CYGWIN32__
402    hostFlags |= O_BINARY;
403#endif
404
405    DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str());
406
407    // open the file
408    int fd = open(path.c_str(), hostFlags, mode);
409
410    return (fd == -1) ? -errno : process->alloc_fd(fd);
411}
412
413
414/// Target chmod() handler.
415template <class OS>
416SyscallReturn
417chmodFunc(SyscallDesc *desc, int callnum, Process *process,
418          ExecContext *xc)
419{
420    std::string path;
421
422    if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
423        return -EFAULT;
424
425    uint32_t mode = xc->getSyscallArg(1);
426    mode_t hostMode = 0;
427
428    // XXX translate mode flags via OS::something???
429    hostMode = mode;
430
431    // do the chmod
432    int result = chmod(path.c_str(), hostMode);
433    if (result < 0)
434        return -errno;
435
436    return 0;
437}
438
439
440/// Target fchmod() handler.
441template <class OS>
442SyscallReturn
443fchmodFunc(SyscallDesc *desc, int callnum, Process *process,
444           ExecContext *xc)
445{
446    int fd = xc->getSyscallArg(0);
447    if (fd < 0 || process->sim_fd(fd) < 0) {
448        // doesn't map to any simulator fd: not a valid target fd
449        return -EBADF;
450    }
451
452    uint32_t mode = xc->getSyscallArg(1);
453    mode_t hostMode = 0;
454
455    // XXX translate mode flags via OS::someting???
456    hostMode = mode;
457
458    // do the fchmod
459    int result = fchmod(process->sim_fd(fd), hostMode);
460    if (result < 0)
461        return -errno;
462
463    return 0;
464}
465
466
467/// Target stat() handler.
468template <class OS>
469SyscallReturn
470statFunc(SyscallDesc *desc, int callnum, Process *process,
471         ExecContext *xc)
472{
473    std::string path;
474
475    if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
476    return -EFAULT;
477
478    struct stat hostBuf;
479    int result = stat(path.c_str(), &hostBuf);
480
481    if (result < 0)
482        return -errno;
483
484    OS::copyOutStatBuf(xc->getMemPort(), xc->getSyscallArg(1), &hostBuf);
485
486    return 0;
487}
488
489
490/// Target fstat64() handler.
491template <class OS>
492SyscallReturn
493fstat64Func(SyscallDesc *desc, int callnum, Process *process,
494            ExecContext *xc)
495{
496    int fd = xc->getSyscallArg(0);
497    if (fd < 0 || process->sim_fd(fd) < 0) {
498        // doesn't map to any simulator fd: not a valid target fd
499        return -EBADF;
500    }
501
502#if BSD_HOST
503    struct stat  hostBuf;
504    int result = fstat(process->sim_fd(fd), &hostBuf);
505#else
506    struct stat64  hostBuf;
507    int result = fstat64(process->sim_fd(fd), &hostBuf);
508#endif
509
510    if (result < 0)
511        return -errno;
512
513    OS::copyOutStat64Buf(xc->getMemPort(), fd, xc->getSyscallArg(1), &hostBuf);
514
515    return 0;
516}
517
518
519/// Target lstat() handler.
520template <class OS>
521SyscallReturn
522lstatFunc(SyscallDesc *desc, int callnum, Process *process,
523          ExecContext *xc)
524{
525    std::string path;
526
527    if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
528      return -EFAULT;
529
530    struct stat hostBuf;
531    int result = lstat(path.c_str(), &hostBuf);
532
533    if (result < 0)
534        return -errno;
535
536    OS::copyOutStatBuf(xc->getMemPort(), xc->getSyscallArg(1), &hostBuf);
537
538    return 0;
539}
540
541/// Target lstat64() handler.
542template <class OS>
543SyscallReturn
544lstat64Func(SyscallDesc *desc, int callnum, Process *process,
545            ExecContext *xc)
546{
547    std::string path;
548
549    if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
550      return -EFAULT;
551
552#if BSD_HOST
553    struct stat hostBuf;
554    int result = lstat(path.c_str(), &hostBuf);
555#else
556    struct stat64 hostBuf;
557    int result = lstat64(path.c_str(), &hostBuf);
558#endif
559
560    if (result < 0)
561        return -errno;
562
563    OS::copyOutStat64Buf(xc->getMemPort(), -1, xc->getSyscallArg(1), &hostBuf);
564
565    return 0;
566}
567
568/// Target fstat() handler.
569template <class OS>
570SyscallReturn
571fstatFunc(SyscallDesc *desc, int callnum, Process *process,
572          ExecContext *xc)
573{
574    int fd = process->sim_fd(xc->getSyscallArg(0));
575
576    DPRINTF(SyscallVerbose, "fstat(%d, ...)\n", fd);
577
578    if (fd < 0)
579        return -EBADF;
580
581    struct stat hostBuf;
582    int result = fstat(fd, &hostBuf);
583
584    if (result < 0)
585        return -errno;
586
587    OS::copyOutStatBuf(xc->getMemPort(), xc->getSyscallArg(1), &hostBuf);
588
589    return 0;
590}
591
592
593/// Target statfs() handler.
594template <class OS>
595SyscallReturn
596statfsFunc(SyscallDesc *desc, int callnum, Process *process,
597           ExecContext *xc)
598{
599    std::string path;
600
601    if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
602      return -EFAULT;
603
604    struct statfs hostBuf;
605    int result = statfs(path.c_str(), &hostBuf);
606
607    if (result < 0)
608        return -errno;
609
610    OS::copyOutStatfsBuf(xc->getMemPort(), xc->getSyscallArg(1), &hostBuf);
611
612    return 0;
613}
614
615
616/// Target fstatfs() handler.
617template <class OS>
618SyscallReturn
619fstatfsFunc(SyscallDesc *desc, int callnum, Process *process,
620            ExecContext *xc)
621{
622    int fd = process->sim_fd(xc->getSyscallArg(0));
623
624    if (fd < 0)
625        return -EBADF;
626
627    struct statfs hostBuf;
628    int result = fstatfs(fd, &hostBuf);
629
630    if (result < 0)
631        return -errno;
632
633    OS::copyOutStatfsBuf(xc->getMemPort(), xc->getSyscallArg(1), &hostBuf);
634
635    return 0;
636}
637
638
639/// Target writev() handler.
640template <class OS>
641SyscallReturn
642writevFunc(SyscallDesc *desc, int callnum, Process *process,
643           ExecContext *xc)
644{
645    int fd = xc->getSyscallArg(0);
646    if (fd < 0 || process->sim_fd(fd) < 0) {
647        // doesn't map to any simulator fd: not a valid target fd
648        return -EBADF;
649    }
650
651    TranslatingPort *p = xc->getMemPort();
652    uint64_t tiov_base = xc->getSyscallArg(1);
653    size_t count = xc->getSyscallArg(2);
654    struct iovec hiov[count];
655    for (int i = 0; i < count; ++i)
656    {
657        typename OS::tgt_iovec tiov;
658
659        p->readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec),
660                    (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec));
661        hiov[i].iov_len = gtoh(tiov.iov_len);
662        hiov[i].iov_base = new char [hiov[i].iov_len];
663        p->readBlob(gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base,
664                    hiov[i].iov_len);
665    }
666
667    int result = writev(process->sim_fd(fd), hiov, count);
668
669    for (int i = 0; i < count; ++i)
670    {
671        delete [] (char *)hiov[i].iov_base;
672    }
673
674    if (result < 0)
675        return -errno;
676
677    return 0;
678}
679
680
681/// Target mmap() handler.
682///
683/// We don't really handle mmap().  If the target is mmaping an
684/// anonymous region or /dev/zero, we can get away with doing basically
685/// nothing (since memory is initialized to zero and the simulator
686/// doesn't really check addresses anyway).  Always print a warning,
687/// since this could be seriously broken if we're not mapping
688/// /dev/zero.
689//
690/// Someday we should explicitly check for /dev/zero in open, flag the
691/// file descriptor, and fail (or implement!) a non-anonymous mmap to
692/// anything else.
693template <class OS>
694SyscallReturn
695mmapFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
696{
697    Addr start = xc->getSyscallArg(0);
698    uint64_t length = xc->getSyscallArg(1);
699    // int prot = xc->getSyscallArg(2);
700    int flags = xc->getSyscallArg(3);
701    // int fd = p->sim_fd(xc->getSyscallArg(4));
702    // int offset = xc->getSyscallArg(5);
703    Addr junk;
704
705    if (start == 0) {
706        // user didn't give an address... pick one from our "mmap region"
707        start = p->mmap_end;
708        for (ChunkGenerator gen(start, roundUp(length, TheISA::VMPageSize), TheISA::VMPageSize); !gen.done(); gen.next()) {
709            if (!p->pTable->translate(gen.addr(), junk))
710                p->pTable->allocate(roundDown(gen.addr(), TheISA::VMPageSize), TheISA::VMPageSize);
711        }
712        p->mmap_end += roundUp(length, TheISA::VMPageSize);
713        if (p->nxm_start != 0) {
714            //If we have an nxm space, make sure we haven't colided
715            assert(p->mmap_end < p->nxm_start);
716        }
717    }
718
719    if (!(flags & OS::TGT_MAP_ANONYMOUS)) {
720        warn("allowing mmap of file @ fd %d. "
721             "This will break if not /dev/zero.", xc->getSyscallArg(4));
722    }
723
724    return start;
725}
726
727/// Target getrlimit() handler.
728template <class OS>
729SyscallReturn
730getrlimitFunc(SyscallDesc *desc, int callnum, Process *process,
731        ExecContext *xc)
732{
733    unsigned resource = xc->getSyscallArg(0);
734    TypedBufferArg<typename OS::rlimit> rlp(xc->getSyscallArg(1));
735
736    switch (resource) {
737        case OS::TGT_RLIMIT_STACK:
738            // max stack size in bytes: make up a number (2MB for now)
739            rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024;
740            rlp->rlim_cur = htog(rlp->rlim_cur);
741            rlp->rlim_max = htog(rlp->rlim_max);
742            break;
743
744        default:
745            std::cerr << "getrlimitFunc: unimplemented resource " << resource
746                << std::endl;
747            abort();
748            break;
749    }
750
751    rlp.copyOut(xc->getMemPort());
752    return 0;
753}
754
755/// Target gettimeofday() handler.
756template <class OS>
757SyscallReturn
758gettimeofdayFunc(SyscallDesc *desc, int callnum, Process *process,
759        ExecContext *xc)
760{
761    TypedBufferArg<typename OS::timeval> tp(xc->getSyscallArg(0));
762
763    getElapsedTime(tp->tv_sec, tp->tv_usec);
764    tp->tv_sec += seconds_since_epoch;
765    tp->tv_sec = htog(tp->tv_sec);
766    tp->tv_usec = htog(tp->tv_usec);
767
768    tp.copyOut(xc->getMemPort());
769
770    return 0;
771}
772
773
774/// Target utimes() handler.
775template <class OS>
776SyscallReturn
777utimesFunc(SyscallDesc *desc, int callnum, Process *process,
778           ExecContext *xc)
779{
780    std::string path;
781
782    if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
783      return -EFAULT;
784
785    TypedBufferArg<typename OS::timeval [2]> tp(xc->getSyscallArg(1));
786    tp.copyIn(xc->getMemPort());
787
788    struct timeval hostTimeval[2];
789    for (int i = 0; i < 2; ++i)
790    {
791        hostTimeval[i].tv_sec = gtoh((*tp)[i].tv_sec);
792        hostTimeval[i].tv_usec = gtoh((*tp)[i].tv_usec);
793    }
794    int result = utimes(path.c_str(), hostTimeval);
795
796    if (result < 0)
797        return -errno;
798
799    return 0;
800}
801/// Target getrusage() function.
802template <class OS>
803SyscallReturn
804getrusageFunc(SyscallDesc *desc, int callnum, Process *process,
805              ExecContext *xc)
806{
807    int who = xc->getSyscallArg(0);	// THREAD, SELF, or CHILDREN
808    TypedBufferArg<typename OS::rusage> rup(xc->getSyscallArg(1));
809
810    if (who != OS::TGT_RUSAGE_SELF) {
811        // don't really handle THREAD or CHILDREN, but just warn and
812        // plow ahead
813        warn("getrusage() only supports RUSAGE_SELF.  Parameter %d ignored.",
814             who);
815    }
816
817    getElapsedTime(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec);
818    rup->ru_utime.tv_sec = htog(rup->ru_utime.tv_sec);
819    rup->ru_utime.tv_usec = htog(rup->ru_utime.tv_usec);
820
821    rup->ru_stime.tv_sec = 0;
822    rup->ru_stime.tv_usec = 0;
823    rup->ru_maxrss = 0;
824    rup->ru_ixrss = 0;
825    rup->ru_idrss = 0;
826    rup->ru_isrss = 0;
827    rup->ru_minflt = 0;
828    rup->ru_majflt = 0;
829    rup->ru_nswap = 0;
830    rup->ru_inblock = 0;
831    rup->ru_oublock = 0;
832    rup->ru_msgsnd = 0;
833    rup->ru_msgrcv = 0;
834    rup->ru_nsignals = 0;
835    rup->ru_nvcsw = 0;
836    rup->ru_nivcsw = 0;
837
838    rup.copyOut(xc->getMemPort());
839
840    return 0;
841}
842
843#endif // __SIM_SYSCALL_EMUL_HH__
844