syscall_emul.hh revision 2474
16911SBrad.Beckmann@amd.com/*
26911SBrad.Beckmann@amd.com * Copyright (c) 2003-2005 The Regents of The University of Michigan
36911SBrad.Beckmann@amd.com * All rights reserved.
46911SBrad.Beckmann@amd.com *
56911SBrad.Beckmann@amd.com * Redistribution and use in source and binary forms, with or without
66911SBrad.Beckmann@amd.com * modification, are permitted provided that the following conditions are
76911SBrad.Beckmann@amd.com * met: redistributions of source code must retain the above copyright
86911SBrad.Beckmann@amd.com * notice, this list of conditions and the following disclaimer;
96911SBrad.Beckmann@amd.com * redistributions in binary form must reproduce the above copyright
106911SBrad.Beckmann@amd.com * notice, this list of conditions and the following disclaimer in the
116911SBrad.Beckmann@amd.com * documentation and/or other materials provided with the distribution;
126911SBrad.Beckmann@amd.com * neither the name of the copyright holders nor the names of its
136911SBrad.Beckmann@amd.com * contributors may be used to endorse or promote products derived from
146911SBrad.Beckmann@amd.com * this software without specific prior written permission.
156911SBrad.Beckmann@amd.com *
166911SBrad.Beckmann@amd.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
176911SBrad.Beckmann@amd.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
186911SBrad.Beckmann@amd.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
196911SBrad.Beckmann@amd.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
206911SBrad.Beckmann@amd.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
216911SBrad.Beckmann@amd.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
226911SBrad.Beckmann@amd.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
236911SBrad.Beckmann@amd.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
246911SBrad.Beckmann@amd.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
256911SBrad.Beckmann@amd.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
266911SBrad.Beckmann@amd.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
276911SBrad.Beckmann@amd.com */
286911SBrad.Beckmann@amd.com
296911SBrad.Beckmann@amd.com#ifndef __SIM_SYSCALL_EMUL_HH__
306911SBrad.Beckmann@amd.com#define __SIM_SYSCALL_EMUL_HH__
316911SBrad.Beckmann@amd.com
326911SBrad.Beckmann@amd.com#define BSD_HOST (defined(__APPLE__) || defined(__OpenBSD__) || \
336911SBrad.Beckmann@amd.com                  defined(__FreeBSD__))
346911SBrad.Beckmann@amd.com
356911SBrad.Beckmann@amd.com///
366911SBrad.Beckmann@amd.com/// @file syscall_emul.hh
376911SBrad.Beckmann@amd.com///
386911SBrad.Beckmann@amd.com/// This file defines objects used to emulate syscalls from the target
396911SBrad.Beckmann@amd.com/// application on the host machine.
406911SBrad.Beckmann@amd.com
416911SBrad.Beckmann@amd.com#include <errno.h>
426911SBrad.Beckmann@amd.com#include <string>
436911SBrad.Beckmann@amd.com#ifdef __CYGWIN32__
446911SBrad.Beckmann@amd.com#include <sys/fcntl.h>	// for O_BINARY
456911SBrad.Beckmann@amd.com#endif
466911SBrad.Beckmann@amd.com#include <sys/uio.h>
477538SBrad.Beckmann@amd.com
487538SBrad.Beckmann@amd.com#include "arch/isa_traits.hh"	// for Addr
497538SBrad.Beckmann@amd.com#include "base/chunk_generator.hh"
507541SBrad.Beckmann@amd.com#include "base/intmath.hh"	// for RoundUp
516911SBrad.Beckmann@amd.com#include "base/misc.hh"
526911SBrad.Beckmann@amd.com#include "base/trace.hh"
536911SBrad.Beckmann@amd.com#include "cpu/base.hh"
546911SBrad.Beckmann@amd.com#include "cpu/exec_context.hh"
556911SBrad.Beckmann@amd.com#include "mem/translating_port.hh"
566911SBrad.Beckmann@amd.com#include "mem/page_table.hh"
576911SBrad.Beckmann@amd.com#include "sim/process.hh"
586911SBrad.Beckmann@amd.com
596911SBrad.Beckmann@amd.com///
606911SBrad.Beckmann@amd.com/// System call descriptor.
616911SBrad.Beckmann@amd.com///
626911SBrad.Beckmann@amd.comclass SyscallDesc {
636911SBrad.Beckmann@amd.com
646911SBrad.Beckmann@amd.com  public:
656911SBrad.Beckmann@amd.com
666911SBrad.Beckmann@amd.com    /// Typedef for target syscall handler functions.
676911SBrad.Beckmann@amd.com    typedef SyscallReturn (*FuncPtr)(SyscallDesc *, int num,
686911SBrad.Beckmann@amd.com                           Process *, ExecContext *);
696911SBrad.Beckmann@amd.com
706911SBrad.Beckmann@amd.com    const char *name;	//!< Syscall name (e.g., "open").
718180SBrad.Beckmann@amd.com    FuncPtr funcPtr;	//!< Pointer to emulation function.
728180SBrad.Beckmann@amd.com    int flags;		//!< Flags (see Flags enum).
738257SBrad.Beckmann@amd.com
748257SBrad.Beckmann@amd.com    /// Flag values for controlling syscall behavior.
756911SBrad.Beckmann@amd.com    enum Flags {
766911SBrad.Beckmann@amd.com        /// Don't set return regs according to funcPtr return value.
776911SBrad.Beckmann@amd.com        /// Used for syscalls with non-standard return conventions
786911SBrad.Beckmann@amd.com        /// that explicitly set the ExecContext regs (e.g.,
796911SBrad.Beckmann@amd.com        /// sigreturn).
806911SBrad.Beckmann@amd.com        SuppressReturnValue = 1
818180SBrad.Beckmann@amd.com    };
828180SBrad.Beckmann@amd.com
836911SBrad.Beckmann@amd.com    /// Constructor.
848180SBrad.Beckmann@amd.com    SyscallDesc(const char *_name, FuncPtr _funcPtr, int _flags = 0)
858180SBrad.Beckmann@amd.com        : name(_name), funcPtr(_funcPtr), flags(_flags)
866911SBrad.Beckmann@amd.com    {
877015SBrad.Beckmann@amd.com    }
887015SBrad.Beckmann@amd.com
896911SBrad.Beckmann@amd.com    /// Emulate the syscall.  Public interface for calling through funcPtr.
907541SBrad.Beckmann@amd.com    void doSyscall(int callnum, Process *proc, ExecContext *xc);
917541SBrad.Beckmann@amd.com};
926911SBrad.Beckmann@amd.com
936911SBrad.Beckmann@amd.com
946911SBrad.Beckmann@amd.comclass BaseBufferArg {
956911SBrad.Beckmann@amd.com
966911SBrad.Beckmann@amd.com  public:
978257SBrad.Beckmann@amd.com
986911SBrad.Beckmann@amd.com    BaseBufferArg(Addr _addr, int _size) : addr(_addr), size(_size)
996911SBrad.Beckmann@amd.com    {
1006911SBrad.Beckmann@amd.com        bufPtr = new uint8_t[size];
1018180SBrad.Beckmann@amd.com        // clear out buffer: in case we only partially populate this,
1027541SBrad.Beckmann@amd.com        // and then do a copyOut(), we want to make sure we don't
1037541SBrad.Beckmann@amd.com        // introduce any random junk into the simulated address space
1046911SBrad.Beckmann@amd.com        memset(bufPtr, 0, size);
1056911SBrad.Beckmann@amd.com    }
1066911SBrad.Beckmann@amd.com
1076911SBrad.Beckmann@amd.com    virtual ~BaseBufferArg() { delete [] bufPtr; }
1086911SBrad.Beckmann@amd.com
1096911SBrad.Beckmann@amd.com    //
1108257SBrad.Beckmann@amd.com    // copy data into simulator space (read from target memory)
1118257SBrad.Beckmann@amd.com    //
1128180SBrad.Beckmann@amd.com    virtual bool copyIn(TranslatingPort *memport)
1138180SBrad.Beckmann@amd.com    {
1146911SBrad.Beckmann@amd.com        memport->readBlob(addr, bufPtr, size);
1156911SBrad.Beckmann@amd.com        return true;	// no EFAULT detection for now
1166911SBrad.Beckmann@amd.com    }
1176911SBrad.Beckmann@amd.com
1186911SBrad.Beckmann@amd.com    //
1198180SBrad.Beckmann@amd.com    // copy data out of simulator space (write to target memory)
1208180SBrad.Beckmann@amd.com    //
1216911SBrad.Beckmann@amd.com    virtual bool copyOut(TranslatingPort *memport)
1226911SBrad.Beckmann@amd.com    {
1238257SBrad.Beckmann@amd.com        memport->writeBlob(addr, bufPtr, size);
1246911SBrad.Beckmann@amd.com        return true;	// no EFAULT detection for now
1256911SBrad.Beckmann@amd.com    }
1267541SBrad.Beckmann@amd.com
1276911SBrad.Beckmann@amd.com  protected:
1288257SBrad.Beckmann@amd.com    Addr addr;
1298257SBrad.Beckmann@amd.com    int size;
1306911SBrad.Beckmann@amd.com    uint8_t *bufPtr;
1317541SBrad.Beckmann@amd.com};
1327541SBrad.Beckmann@amd.com
1336911SBrad.Beckmann@amd.com
1346911SBrad.Beckmann@amd.comclass BufferArg : public BaseBufferArg
1356911SBrad.Beckmann@amd.com{
1366911SBrad.Beckmann@amd.com  public:
1376911SBrad.Beckmann@amd.com    BufferArg(Addr _addr, int _size) : BaseBufferArg(_addr, _size) { }
1386911SBrad.Beckmann@amd.com    void *bufferPtr()	{ return bufPtr; }
1396911SBrad.Beckmann@amd.com};
1406911SBrad.Beckmann@amd.com
1416911SBrad.Beckmann@amd.comtemplate <class T>
1426911SBrad.Beckmann@amd.comclass TypedBufferArg : public BaseBufferArg
1436911SBrad.Beckmann@amd.com{
1446911SBrad.Beckmann@amd.com  public:
1456911SBrad.Beckmann@amd.com    // user can optionally specify a specific number of bytes to
1468257SBrad.Beckmann@amd.com    // allocate to deal with those structs that have variable-size
1476911SBrad.Beckmann@amd.com    // arrays at the end
1486911SBrad.Beckmann@amd.com    TypedBufferArg(Addr _addr, int _size = sizeof(T))
1497541SBrad.Beckmann@amd.com        : BaseBufferArg(_addr, _size)
1507541SBrad.Beckmann@amd.com    { }
1516911SBrad.Beckmann@amd.com
1526911SBrad.Beckmann@amd.com    // type case
1537541SBrad.Beckmann@amd.com    operator T*() { return (T *)bufPtr; }
1546911SBrad.Beckmann@amd.com
1556911SBrad.Beckmann@amd.com    // dereference operators
1568257SBrad.Beckmann@amd.com    T &operator*()	 { return *((T *)bufPtr); }
1578257SBrad.Beckmann@amd.com    T* operator->()	 { return (T *)bufPtr; }
1586911SBrad.Beckmann@amd.com    T &operator[](int i) { return ((T *)bufPtr)[i]; }
1596911SBrad.Beckmann@amd.com};
1606911SBrad.Beckmann@amd.com
1616911SBrad.Beckmann@amd.com//////////////////////////////////////////////////////////////////////
1626911SBrad.Beckmann@amd.com//
1637541SBrad.Beckmann@amd.com// The following emulation functions are generic enough that they
1647541SBrad.Beckmann@amd.com// don't need to be recompiled for different emulated OS's.  They are
1656911SBrad.Beckmann@amd.com// defined in sim/syscall_emul.cc.
1666911SBrad.Beckmann@amd.com//
1678257SBrad.Beckmann@amd.com//////////////////////////////////////////////////////////////////////
1686911SBrad.Beckmann@amd.com
1696911SBrad.Beckmann@amd.com
1707541SBrad.Beckmann@amd.com/// Handler for unimplemented syscalls that we haven't thought about.
1717544SBrad.Beckmann@amd.comSyscallReturn unimplementedFunc(SyscallDesc *desc, int num,
1727633SBrad.Beckmann@amd.com                                Process *p, ExecContext *xc);
1737544SBrad.Beckmann@amd.com
1747633SBrad.Beckmann@amd.com/// Handler for unimplemented syscalls that we never intend to
1756911SBrad.Beckmann@amd.com/// implement (signal handling, etc.) and should not affect the correct
1766911SBrad.Beckmann@amd.com/// behavior of the program.  Print a warning only if the appropriate
1778257SBrad.Beckmann@amd.com/// trace flag is enabled.  Return success to the target program.
1788257SBrad.Beckmann@amd.comSyscallReturn ignoreFunc(SyscallDesc *desc, int num,
1796911SBrad.Beckmann@amd.com                         Process *p, ExecContext *xc);
1806911SBrad.Beckmann@amd.com
1816911SBrad.Beckmann@amd.com/// Target exit() handler: terminate simulation.
1826911SBrad.Beckmann@amd.comSyscallReturn exitFunc(SyscallDesc *desc, int num,
1836911SBrad.Beckmann@amd.com                       Process *p, ExecContext *xc);
1846911SBrad.Beckmann@amd.com
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