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