vptr.hh:
[gem5.git] / sim / syscall_emul.hh
index b425ef83c6d2c73b13d6300712757853eebaed75..185ada2c51bd10753cbfb4ce83a4ff1c2e217dd2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003 The Regents of The University of Michigan
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -26,8 +26,8 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef __SYSCALL_EMUL_HH__
-#define __SYSCALL_EMUL_HH__
+#ifndef __SIM_SYSCALL_EMUL_HH__
+#define __SIM_SYSCALL_EMUL_HH__
 
 ///
 /// @file syscall_emul.hh
 /// This file defines objects used to emulate syscalls from the target
 /// application on the host machine.
 
+#include <errno.h>
 #include <string>
+#ifdef __CYGWIN32__
+#include <sys/fcntl.h> // for O_BINARY
+#endif
+#include <sys/uio.h>
 
 #include "base/intmath.hh"     // for RoundUp
+#include "mem/functional/functional.hh"
 #include "targetarch/isa_traits.hh"    // for Addr
-#include "mem/functional_mem/functional_memory.hh"
 
-class Process;
-class ExecContext;
+#include "base/trace.hh"
+#include "cpu/exec_context.hh"
+#include "sim/process.hh"
 
 ///
 /// System call descriptor.
@@ -52,7 +58,7 @@ class SyscallDesc {
   public:
 
     /// Typedef for target syscall handler functions.
-    typedef int (*FuncPtr)(SyscallDesc *, int num,
+    typedef SyscallReturn (*FuncPtr)(SyscallDesc *, int num,
                            Process *, ExecContext *);
 
     const char *name;  //!< Syscall name (e.g., "open").
@@ -156,46 +162,107 @@ class TypedBufferArg : public BaseBufferArg
 
 
 /// Handler for unimplemented syscalls that we haven't thought about.
-int unimplementedFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
+SyscallReturn unimplementedFunc(SyscallDesc *desc, int num,
+                                Process *p, ExecContext *xc);
 
 /// Handler for unimplemented syscalls that we never intend to
 /// implement (signal handling, etc.) and should not affect the correct
 /// behavior of the program.  Print a warning only if the appropriate
 /// trace flag is enabled.  Return success to the target program.
-int ignoreFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
+SyscallReturn ignoreFunc(SyscallDesc *desc, int num,
+                         Process *p, ExecContext *xc);
 
 /// Target exit() handler: terminate simulation.
-int exitFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
+SyscallReturn exitFunc(SyscallDesc *desc, int num,
+                       Process *p, ExecContext *xc);
 
 /// Target getpagesize() handler.
-int getpagesizeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
+SyscallReturn getpagesizeFunc(SyscallDesc *desc, int num,
+                              Process *p, ExecContext *xc);
 
 /// Target obreak() handler: set brk address.
-int obreakFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
+SyscallReturn obreakFunc(SyscallDesc *desc, int num,
+                         Process *p, ExecContext *xc);
 
 /// Target close() handler.
-int closeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
+SyscallReturn closeFunc(SyscallDesc *desc, int num,
+                        Process *p, ExecContext *xc);
 
 /// Target read() handler.
-int readFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
+SyscallReturn readFunc(SyscallDesc *desc, int num,
+                       Process *p, ExecContext *xc);
 
 /// Target write() handler.
-int writeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
+SyscallReturn writeFunc(SyscallDesc *desc, int num,
+                        Process *p, ExecContext *xc);
 
 /// Target lseek() handler.
-int lseekFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
+SyscallReturn lseekFunc(SyscallDesc *desc, int num,
+                        Process *p, ExecContext *xc);
 
 /// Target munmap() handler.
-int munmapFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
+SyscallReturn munmapFunc(SyscallDesc *desc, int num,
+                         Process *p, ExecContext *xc);
 
 /// Target gethostname() handler.
-int gethostnameFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
+SyscallReturn gethostnameFunc(SyscallDesc *desc, int num,
+                              Process *p, ExecContext *xc);
 
 /// Target unlink() handler.
-int unlinkFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
+SyscallReturn unlinkFunc(SyscallDesc *desc, int num,
+                         Process *p, ExecContext *xc);
 
 /// Target rename() handler.
-int renameFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
+SyscallReturn renameFunc(SyscallDesc *desc, int num,
+                         Process *p, ExecContext *xc);
+
+
+/// Target truncate() handler.
+SyscallReturn truncateFunc(SyscallDesc *desc, int num,
+                           Process *p, ExecContext *xc);
+
+
+/// Target ftruncate() handler.
+SyscallReturn ftruncateFunc(SyscallDesc *desc, int num,
+                            Process *p, ExecContext *xc);
+
+
+/// Target chown() handler.
+SyscallReturn chownFunc(SyscallDesc *desc, int num,
+                        Process *p, ExecContext *xc);
+
+
+/// Target fchown() handler.
+SyscallReturn fchownFunc(SyscallDesc *desc, int num,
+                         Process *p, ExecContext *xc);
+
+/// This struct is used to build an target-OS-dependent table that
+/// maps the target's open() flags to the host open() flags.
+struct OpenFlagTransTable {
+    int tgtFlag;       //!< Target system flag value.
+    int hostFlag;      //!< Corresponding host system flag value.
+};
+
+
+
+/// A readable name for 1,000,000, for converting microseconds to seconds.
+const int one_million = 1000000;
+
+/// Approximate seconds since the epoch (1/1/1970).  About a billion,
+/// by my reckoning.  We want to keep this a constant (not use the
+/// real-world time) to keep simulations repeatable.
+const unsigned seconds_since_epoch = 1000000000;
+
+/// Helper function to convert current elapsed time to seconds and
+/// microseconds.
+template <class T1, class T2>
+void
+getElapsedTime(T1 &sec, T2 &usec)
+{
+    int elapsed_usecs = curTick / Clock::Int::us;
+    sec = elapsed_usecs / one_million;
+    usec = elapsed_usecs % one_million;
+}
 
 //////////////////////////////////////////////////////////////////////
 //
@@ -208,14 +275,14 @@ int renameFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc);
 /// only to find out if their stdout is a tty, to determine whether to
 /// do line or block buffering.
 template <class OS>
-int
+SyscallReturn
 ioctlFunc(SyscallDesc *desc, int callnum, Process *process,
           ExecContext *xc)
 {
     int fd = xc->getSyscallArg(0);
     unsigned req = xc->getSyscallArg(1);
 
-    // DPRINTFR(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", fd, req);
+    DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", fd, req);
 
     if (fd < 0 || process->sim_fd(fd) < 0) {
         // doesn't map to any simulator fd: not a valid target fd
@@ -234,21 +301,14 @@ ioctlFunc(SyscallDesc *desc, int callnum, Process *process,
         return -ENOTTY;
 
       default:
-        fatal("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ 0x%llx\n", fd, req, xc->readPC());
+        fatal("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ 0x%llx\n",
+              fd, req, xc->readPC());
     }
 }
 
-/// This struct is used to build an target-OS-dependent table that
-/// maps the target's open() flags to the host open() flags.
-struct OpenFlagTransTable {
-    int tgtFlag;       //!< Target system flag value.
-    int hostFlag;      //!< Corresponding host system flag value.
-};
-
-
 /// Target open() handler.
 template <class OS>
-int
+SyscallReturn
 openFunc(SyscallDesc *desc, int callnum, Process *process,
          ExecContext *xc)
 {
@@ -260,7 +320,7 @@ openFunc(SyscallDesc *desc, int callnum, Process *process,
     if (path == "/dev/sysdev0") {
         // This is a memory-mapped high-resolution timer device on Alpha.
         // We don't support it, so just punt.
-        DCOUT(SyscallWarnings) << "Ignoring open(" << path << ", ...)" << endl;
+        warn("Ignoring open(%s, ...)\n", path);
         return -ENOENT;
     }
 
@@ -278,22 +338,77 @@ openFunc(SyscallDesc *desc, int callnum, Process *process,
 
     // any target flags left?
     if (tgtFlags != 0)
-        cerr << "Syscall: open: cannot decode flags: " <<  tgtFlags << endl;
+        warn("Syscall: open: cannot decode flags 0x%x", tgtFlags);
 
 #ifdef __CYGWIN32__
     hostFlags |= O_BINARY;
 #endif
 
+    DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str());
+
     // open the file
     int fd = open(path.c_str(), hostFlags, mode);
 
-    return (fd == -1) ? -errno : process->open_fd(fd);
+    return (fd == -1) ? -errno : process->alloc_fd(fd);
+}
+
+
+/// Target chmod() handler.
+template <class OS>
+SyscallReturn
+chmodFunc(SyscallDesc *desc, int callnum, Process *process,
+          ExecContext *xc)
+{
+    std::string path;
+
+    if (xc->mem->readString(path, xc->getSyscallArg(0)) != No_Fault)
+        return -EFAULT;
+
+    uint32_t mode = xc->getSyscallArg(1);
+    mode_t hostMode = 0;
+
+    // XXX translate mode flags via OS::something???
+    hostMode = mode;
+
+    // do the chmod
+    int result = chmod(path.c_str(), hostMode);
+    if (result < 0)
+        return errno;
+
+    return 0;
+}
+
+
+/// Target fchmod() handler.
+template <class OS>
+SyscallReturn
+fchmodFunc(SyscallDesc *desc, int callnum, Process *process,
+           ExecContext *xc)
+{
+    int fd = xc->getSyscallArg(0);
+    if (fd < 0 || process->sim_fd(fd) < 0) {
+        // doesn't map to any simulator fd: not a valid target fd
+        return -EBADF;
+    }
+
+    uint32_t mode = xc->getSyscallArg(1);
+    mode_t hostMode = 0;
+
+    // XXX translate mode flags via OS::someting???
+    hostMode = mode;
+
+    // do the fchmod
+    int result = fchmod(process->sim_fd(fd), hostMode);
+    if (result < 0)
+        return errno;
+
+    return 0;
 }
 
 
 /// Target stat() handler.
 template <class OS>
-int
+SyscallReturn
 statFunc(SyscallDesc *desc, int callnum, Process *process,
          ExecContext *xc)
 {
@@ -306,7 +421,7 @@ statFunc(SyscallDesc *desc, int callnum, Process *process,
     int result = stat(path.c_str(), &hostBuf);
 
     if (result < 0)
-        return -errno;
+        return errno;
 
     OS::copyOutStatBuf(xc->mem, xc->getSyscallArg(1), &hostBuf);
 
@@ -314,9 +429,33 @@ statFunc(SyscallDesc *desc, int callnum, Process *process,
 }
 
 
+/// Target fstat64() handler.
+template <class OS>
+SyscallReturn
+fstat64Func(SyscallDesc *desc, int callnum, Process *process,
+            ExecContext *xc)
+{
+    int fd = xc->getSyscallArg(0);
+    if (fd < 0 || process->sim_fd(fd) < 0) {
+        // doesn't map to any simulator fd: not a valid target fd
+        return -EBADF;
+    }
+
+    struct stat64 hostBuf;
+    int result = fstat64(process->sim_fd(fd), &hostBuf);
+
+    if (result < 0)
+        return errno;
+
+    OS::copyOutStat64Buf(xc->mem, xc->getSyscallArg(1), &hostBuf);
+
+    return 0;
+}
+
+
 /// Target lstat() handler.
 template <class OS>
-int
+SyscallReturn
 lstatFunc(SyscallDesc *desc, int callnum, Process *process,
           ExecContext *xc)
 {
@@ -336,15 +475,37 @@ lstatFunc(SyscallDesc *desc, int callnum, Process *process,
     return 0;
 }
 
+/// Target lstat64() handler.
+template <class OS>
+SyscallReturn
+lstat64Func(SyscallDesc *desc, int callnum, Process *process,
+            ExecContext *xc)
+{
+    std::string path;
+
+    if (xc->mem->readString(path, xc->getSyscallArg(0)) != No_Fault)
+        return -EFAULT;
+
+    struct stat64 hostBuf;
+    int result = lstat64(path.c_str(), &hostBuf);
+
+    if (result < 0)
+        return -errno;
+
+    OS::copyOutStat64Buf(xc->mem, xc->getSyscallArg(1), &hostBuf);
+
+    return 0;
+}
+
 /// Target fstat() handler.
 template <class OS>
-int
+SyscallReturn
 fstatFunc(SyscallDesc *desc, int callnum, Process *process,
           ExecContext *xc)
 {
     int fd = process->sim_fd(xc->getSyscallArg(0));
 
-    // DPRINTFR(SyscallVerbose, "fstat(%d, ...)\n", fd);
+    DPRINTF(SyscallVerbose, "fstat(%d, ...)\n", fd);
 
     if (fd < 0)
         return -EBADF;
@@ -361,6 +522,92 @@ fstatFunc(SyscallDesc *desc, int callnum, Process *process,
 }
 
 
+/// Target statfs() handler.
+template <class OS>
+SyscallReturn
+statfsFunc(SyscallDesc *desc, int callnum, Process *process,
+           ExecContext *xc)
+{
+    std::string path;
+
+    if (xc->mem->readString(path, xc->getSyscallArg(0)) != No_Fault)
+        return -EFAULT;
+
+    struct statfs hostBuf;
+    int result = statfs(path.c_str(), &hostBuf);
+
+    if (result < 0)
+        return errno;
+
+    OS::copyOutStatfsBuf(xc->mem, xc->getSyscallArg(1), &hostBuf);
+
+    return 0;
+}
+
+
+/// Target fstatfs() handler.
+template <class OS>
+SyscallReturn
+fstatfsFunc(SyscallDesc *desc, int callnum, Process *process,
+            ExecContext *xc)
+{
+    int fd = process->sim_fd(xc->getSyscallArg(0));
+
+    if (fd < 0)
+        return -EBADF;
+
+    struct statfs hostBuf;
+    int result = fstatfs(fd, &hostBuf);
+
+    if (result < 0)
+        return errno;
+
+    OS::copyOutStatfsBuf(xc->mem, xc->getSyscallArg(1), &hostBuf);
+
+    return 0;
+}
+
+
+/// Target writev() handler.
+template <class OS>
+SyscallReturn
+writevFunc(SyscallDesc *desc, int callnum, Process *process,
+           ExecContext *xc)
+{
+    int fd = xc->getSyscallArg(0);
+    if (fd < 0 || process->sim_fd(fd) < 0) {
+        // doesn't map to any simulator fd: not a valid target fd
+        return -EBADF;
+    }
+
+    uint64_t tiov_base = xc->getSyscallArg(1);
+    size_t count = xc->getSyscallArg(2);
+    struct iovec hiov[count];
+    for (int i = 0; i < count; ++i)
+    {
+        typename OS::tgt_iovec tiov;
+        xc->mem->access(Read, tiov_base + i*sizeof(typename OS::tgt_iovec),
+                        &tiov, sizeof(typename OS::tgt_iovec));
+        hiov[i].iov_len = tiov.iov_len;
+        hiov[i].iov_base = new char [hiov[i].iov_len];
+        xc->mem->access(Read, tiov.iov_base,
+                        hiov[i].iov_base, hiov[i].iov_len);
+    }
+
+    int result = writev(process->sim_fd(fd), hiov, count);
+
+    for (int i = 0; i < count; ++i)
+    {
+        delete [] (char *)hiov[i].iov_base;
+    }
+
+    if (result < 0)
+        return errno;
+
+    return 0;
+}
+
+
 /// Target mmap() handler.
 ///
 /// We don't really handle mmap().  If the target is mmaping an
@@ -374,7 +621,7 @@ fstatFunc(SyscallDesc *desc, int callnum, Process *process,
 /// file descriptor, and fail (or implement!) a non-anonymous mmap to
 /// anything else.
 template <class OS>
-int
+SyscallReturn
 mmapFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
 {
     Addr start = xc->getSyscallArg(0);
@@ -386,13 +633,17 @@ mmapFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
 
     if (start == 0) {
         // user didn't give an address... pick one from our "mmap region"
-        start = p->mmap_base;
-        p->mmap_base += RoundUp<Addr>(length, VMPageSize);
+        start = p->mmap_end;
+        p->mmap_end += roundUp(length, VMPageSize);
+        if (p->nxm_start != 0) {
+            //If we have an nxm space, make sure we haven't colided
+            assert(p->mmap_end < p->nxm_start);
+        }
     }
 
     if (!(flags & OS::TGT_MAP_ANONYMOUS)) {
-        DPRINTF(SyscallWarnings, "Warning: allowing mmap of file @ fd %d.  "
-                "This will break if not /dev/zero.", xc->getSyscallArg(4));
+        warn("allowing mmap of file @ fd %d. "
+             "This will break if not /dev/zero.", xc->getSyscallArg(4));
     }
 
     return start;
@@ -400,7 +651,7 @@ mmapFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
 
 /// Target getrlimit() handler.
 template <class OS>
-int
+SyscallReturn
 getrlimitFunc(SyscallDesc *desc, int callnum, Process *process,
               ExecContext *xc)
 {
@@ -414,7 +665,8 @@ getrlimitFunc(SyscallDesc *desc, int callnum, Process *process,
         break;
 
       default:
-        cerr << "getrlimitFunc: unimplemented resource " << resource << endl;
+        std::cerr << "getrlimitFunc: unimplemented resource " << resource
+                  << std::endl;
         abort();
         break;
     }
@@ -423,31 +675,9 @@ getrlimitFunc(SyscallDesc *desc, int callnum, Process *process,
     return 0;
 }
 
-/// A readable name for 1,000,000, for converting microseconds to seconds.
-const int one_million = 1000000;
-
-/// Approximate seconds since the epoch (1/1/1970).  About a billion,
-/// by my reckoning.  We want to keep this a constant (not use the
-/// real-world time) to keep simulations repeatable.
-const unsigned seconds_since_epoch = 1000000000;
-
-/// Helper function to convert current elapsed time to seconds and
-/// microseconds.
-template <class T1, class T2>
-void
-getElapsedTime(T1 &sec, T2 &usec)
-{
-    int cycles_per_usec = ticksPerSecond / one_million;
-
-    int elapsed_usecs = curTick / cycles_per_usec;
-    sec = elapsed_usecs / one_million;
-    usec = elapsed_usecs % one_million;
-}
-
-
 /// Target gettimeofday() handler.
 template <class OS>
-int
+SyscallReturn
 gettimeofdayFunc(SyscallDesc *desc, int callnum, Process *process,
                  ExecContext *xc)
 {
@@ -462,9 +692,37 @@ gettimeofdayFunc(SyscallDesc *desc, int callnum, Process *process,
 }
 
 
+/// Target utimes() handler.
+template <class OS>
+SyscallReturn
+utimesFunc(SyscallDesc *desc, int callnum, Process *process,
+           ExecContext *xc)
+{
+    std::string path;
+
+    if (xc->mem->readString(path, xc->getSyscallArg(0)) != No_Fault)
+        return -EFAULT;
+
+    TypedBufferArg<typename OS::timeval [2]> tp(xc->getSyscallArg(1));
+    tp.copyIn(xc->mem);
+
+    struct timeval hostTimeval[2];
+    for (int i = 0; i < 2; ++i)
+    {
+        hostTimeval[i].tv_sec = (*tp)[i].tv_sec;
+        hostTimeval[i].tv_usec = (*tp)[i].tv_usec;
+    }
+    int result = utimes(path.c_str(), hostTimeval);
+
+    if (result < 0)
+        return -errno;
+
+    return 0;
+}
+
 /// Target getrusage() function.
 template <class OS>
-int
+SyscallReturn
 getrusageFunc(SyscallDesc *desc, int callnum, Process *process,
               ExecContext *xc)
 {
@@ -474,9 +732,8 @@ getrusageFunc(SyscallDesc *desc, int callnum, Process *process,
     if (who != OS::RUSAGE_SELF) {
         // don't really handle THREAD or CHILDREN, but just warn and
         // plow ahead
-        DCOUT(SyscallWarnings)
-            << "Warning: getrusage() only supports RUSAGE_SELF."
-            << "  Parameter " << who << " ignored." << endl;
+        warn("getrusage() only supports RUSAGE_SELF.  Parameter %d ignored.",
+             who);
     }
 
     getElapsedTime(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec);
@@ -502,6 +759,4 @@ getrusageFunc(SyscallDesc *desc, int callnum, Process *process,
     return 0;
 }
 
-
-
-#endif // __SYSCALL_EMUL_HH__
+#endif // __SIM_SYSCALL_EMUL_HH__