Made Addr a global type
[gem5.git] / sim / syscall_emul.hh
index 831708a21b648ead6b657724f74cb61f8089c727..f49248dead18ea76e2e35741d596a2ffb5887bc2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003-2004 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
@@ -29,6 +29,9 @@
 #ifndef __SIM_SYSCALL_EMUL_HH__
 #define __SIM_SYSCALL_EMUL_HH__
 
+#define BSD_HOST (defined(__APPLE__) || defined(__OpenBSD__) || \
+                  defined(__FreeBSD__))
+
 ///
 /// @file syscall_emul.hh
 ///
 
 #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_mem/functional_memory.hh"
-#include "targetarch/isa_traits.hh"    // for Addr
+#include "mem/functional/functional.hh"
+#include "arch/isa_traits.hh"  // for Addr
 
 #include "base/trace.hh"
 #include "cpu/exec_context.hh"
@@ -54,7 +61,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").
@@ -158,46 +165,83 @@ 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);
+
+/// Target fnctl() handler.
+SyscallReturn fcntlFunc(SyscallDesc *desc, int num,
+                        Process *process, 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.
@@ -222,9 +266,7 @@ 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;
+    int elapsed_usecs = curTick / Clock::Int::us;
     sec = elapsed_usecs / one_million;
     usec = elapsed_usecs % one_million;
 }
@@ -240,14 +282,14 @@ getElapsedTime(T1 &sec, T2 &usec)
 /// 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
@@ -266,25 +308,26 @@ 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());
     }
 }
 
 /// Target open() handler.
 template <class OS>
-int
+SyscallReturn
 openFunc(SyscallDesc *desc, int callnum, Process *process,
          ExecContext *xc)
 {
     std::string path;
 
-    if (xc->mem->readString(path, xc->getSyscallArg(0)) != No_Fault)
+    if (xc->mem->readString(path, xc->getSyscallArg(0)) != NoFault)
         return -EFAULT;
 
     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 << ", ...)" << std::endl;
+        warn("Ignoring open(%s, ...)\n", path);
         return -ENOENT;
     }
 
@@ -302,35 +345,90 @@ openFunc(SyscallDesc *desc, int callnum, Process *process,
 
     // any target flags left?
     if (tgtFlags != 0)
-        std::cerr << "Syscall: open: cannot decode flags: " <<  tgtFlags << std::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)) != NoFault)
+        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)
 {
     std::string path;
 
-    if (xc->mem->readString(path, xc->getSyscallArg(0)) != No_Fault)
+    if (xc->mem->readString(path, xc->getSyscallArg(0)) != NoFault)
         return -EFAULT;
 
     struct stat hostBuf;
     int result = stat(path.c_str(), &hostBuf);
 
     if (result < 0)
-        return -errno;
+        return errno;
 
     OS::copyOutStatBuf(xc->mem, xc->getSyscallArg(1), &hostBuf);
 
@@ -338,15 +436,44 @@ 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;
+    }
+
+#if BSD_HOST
+    struct stat  hostBuf;
+    int result = fstat(process->sim_fd(fd), &hostBuf);
+#else
+    struct stat64  hostBuf;
+    int result = fstat64(process->sim_fd(fd), &hostBuf);
+#endif
+
+    if (result < 0)
+        return errno;
+
+    OS::copyOutStat64Buf(xc->mem, fd, xc->getSyscallArg(1), &hostBuf);
+
+    return 0;
+}
+
+
 /// Target lstat() handler.
 template <class OS>
-int
+SyscallReturn
 lstatFunc(SyscallDesc *desc, int callnum, Process *process,
           ExecContext *xc)
 {
     std::string path;
 
-    if (xc->mem->readString(path, xc->getSyscallArg(0)) != No_Fault)
+    if (xc->mem->readString(path, xc->getSyscallArg(0)) != NoFault)
         return -EFAULT;
 
     struct stat hostBuf;
@@ -360,15 +487,42 @@ 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)) != NoFault)
+        return -EFAULT;
+
+#if BSD_HOST
+    struct stat hostBuf;
+    int result = lstat(path.c_str(), &hostBuf);
+#else
+    struct stat64 hostBuf;
+    int result = lstat64(path.c_str(), &hostBuf);
+#endif
+
+    if (result < 0)
+        return -errno;
+
+    OS::copyOutStat64Buf(xc->mem, -1, 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;
@@ -380,6 +534,91 @@ fstatFunc(SyscallDesc *desc, int callnum, Process *process,
         return -errno;
 
     OS::copyOutStatBuf(xc->mem, xc->getSyscallArg(1), &hostBuf);
+    return 0;
+}
+
+
+/// 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)) != NoFault)
+        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 = gtoh(tiov.iov_len);
+        hiov[i].iov_base = new char [hiov[i].iov_len];
+        xc->mem->access(Read, gtoh(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;
 }
@@ -398,7 +637,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);
@@ -411,12 +650,16 @@ 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_end;
-        p->mmap_end += RoundUp<Addr>(length, VMPageSize);
+        p->mmap_end += roundUp(length, TheISA::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;
@@ -424,23 +667,26 @@ 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)
+        ExecContext *xc)
 {
     unsigned resource = xc->getSyscallArg(0);
     TypedBufferArg<typename OS::rlimit> rlp(xc->getSyscallArg(1));
 
     switch (resource) {
-      case OS::RLIMIT_STACK:
-        // max stack size in bytes: make up a number (2MB for now)
-        rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024;
-        break;
-
-      default:
-        std::cerr << "getrlimitFunc: unimplemented resource " << resource << std::endl;
-        abort();
-        break;
+        case OS::TGT_RLIMIT_STACK:
+            // max stack size in bytes: make up a number (2MB for now)
+            rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024;
+            rlp->rlim_cur = htog(rlp->rlim_cur);
+            rlp->rlim_max = htog(rlp->rlim_max);
+            break;
+
+        default:
+            std::cerr << "getrlimitFunc: unimplemented resource " << resource
+                << std::endl;
+            abort();
+            break;
     }
 
     rlp.copyOut(xc->mem);
@@ -449,14 +695,16 @@ getrlimitFunc(SyscallDesc *desc, int callnum, Process *process,
 
 /// Target gettimeofday() handler.
 template <class OS>
-int
+SyscallReturn
 gettimeofdayFunc(SyscallDesc *desc, int callnum, Process *process,
-                 ExecContext *xc)
+        ExecContext *xc)
 {
     TypedBufferArg<typename OS::timeval> tp(xc->getSyscallArg(0));
 
     getElapsedTime(tp->tv_sec, tp->tv_usec);
     tp->tv_sec += seconds_since_epoch;
+    tp->tv_sec = htog(tp->tv_sec);
+    tp->tv_usec = htog(tp->tv_usec);
 
     tp.copyOut(xc->mem);
 
@@ -464,24 +712,53 @@ 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)) != NoFault)
+        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 = gtoh((*tp)[i].tv_sec);
+        hostTimeval[i].tv_usec = gtoh((*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)
 {
     int who = xc->getSyscallArg(0);    // THREAD, SELF, or CHILDREN
     TypedBufferArg<typename OS::rusage> rup(xc->getSyscallArg(1));
 
-    if (who != OS::RUSAGE_SELF) {
+    if (who != OS::TGT_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." << std::endl;
+        warn("getrusage() only supports RUSAGE_SELF.  Parameter %d ignored.",
+             who);
     }
 
     getElapsedTime(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec);
+    rup->ru_utime.tv_sec = htog(rup->ru_utime.tv_sec);
+    rup->ru_utime.tv_usec = htog(rup->ru_utime.tv_usec);
+
     rup->ru_stime.tv_sec = 0;
     rup->ru_stime.tv_usec = 0;
     rup->ru_maxrss = 0;