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