SysCalls: Implement truncate64 system call
[gem5.git] / src / sim / syscall_emul.hh
index 5ca2f6be5f641e6806686df2a7a70bff287a261f..27c26afb0f08714bf015cf33b0a54fdf2cddc3b0 100644 (file)
 #include <errno.h>
 #include <string>
 #ifdef __CYGWIN32__
-#include <sys/fcntl.h> // for O_BINARY
+#include <sys/fcntl.h>  // for O_BINARY
 #endif
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <sys/uio.h>
 
-#include "sim/host.hh" // for Addr
 #include "base/chunk_generator.hh"
-#include "base/intmath.hh"     // for RoundUp
+#include "base/intmath.hh"      // for RoundUp
 #include "base/misc.hh"
 #include "base/trace.hh"
+#include "base/types.hh"
+#include "config/the_isa.hh"
 #include "cpu/base.hh"
 #include "cpu/thread_context.hh"
 #include "mem/translating_port.hh"
 #include "mem/page_table.hh"
+#include "sim/system.hh"
 #include "sim/process.hh"
 
 ///
@@ -72,9 +74,9 @@ class SyscallDesc {
     typedef SyscallReturn (*FuncPtr)(SyscallDesc *, int num,
                            LiveProcess *, ThreadContext *);
 
-    const char *name;  //!< Syscall name (e.g., "open").
-    FuncPtr funcPtr;   //!< Pointer to emulation function.
-    int flags;         //!< Flags (see Flags enum).
+    const char *name;   //!< Syscall name (e.g., "open").
+    FuncPtr funcPtr;    //!< Pointer to emulation function.
+    int flags;          //!< Flags (see Flags enum).
 
     /// Flag values for controlling syscall behavior.
     enum Flags {
@@ -117,7 +119,7 @@ class BaseBufferArg {
     virtual bool copyIn(TranslatingPort *memport)
     {
         memport->readBlob(addr, bufPtr, size);
-        return true;   // no EFAULT detection for now
+        return true;    // no EFAULT detection for now
     }
 
     //
@@ -126,7 +128,7 @@ class BaseBufferArg {
     virtual bool copyOut(TranslatingPort *memport)
     {
         memport->writeBlob(addr, bufPtr, size);
-        return true;   // no EFAULT detection for now
+        return true;    // no EFAULT detection for now
     }
 
   protected:
@@ -140,7 +142,7 @@ class BufferArg : public BaseBufferArg
 {
   public:
     BufferArg(Addr _addr, int _size) : BaseBufferArg(_addr, _size) { }
-    void *bufferPtr()  { return bufPtr; }
+    void *bufferPtr()   { return bufPtr; }
 };
 
 template <class T>
@@ -158,8 +160,8 @@ class TypedBufferArg : public BaseBufferArg
     operator T*() { return (T *)bufPtr; }
 
     // dereference operators
-    T &operator*()      { return *((T *)bufPtr); }
-    T* operator->()     { return (T *)bufPtr; }
+    T &operator*()       { return *((T *)bufPtr); }
+    T* operator->()      { return (T *)bufPtr; }
     T &operator[](int i) { return ((T *)bufPtr)[i]; }
 };
 
@@ -183,17 +185,21 @@ SyscallReturn unimplementedFunc(SyscallDesc *desc, int num,
 SyscallReturn ignoreFunc(SyscallDesc *desc, int num,
                          LiveProcess *p, ThreadContext *tc);
 
-/// Target exit() handler: terminate simulation.
+/// Target exit() handler: terminate current context.
 SyscallReturn exitFunc(SyscallDesc *desc, int num,
                        LiveProcess *p, ThreadContext *tc);
 
+/// Target exit_group() handler: terminate simulation. (exit all threads)
+SyscallReturn exitGroupFunc(SyscallDesc *desc, int num,
+                       LiveProcess *p, ThreadContext *tc);
+
 /// Target getpagesize() handler.
 SyscallReturn getpagesizeFunc(SyscallDesc *desc, int num,
                               LiveProcess *p, ThreadContext *tc);
 
-/// Target obreak() handler: set brk address.
-SyscallReturn obreakFunc(SyscallDesc *desc, int num,
-                         LiveProcess *p, ThreadContext *tc);
+/// Target brk() handler: set brk address.
+SyscallReturn brkFunc(SyscallDesc *desc, int num,
+                      LiveProcess *p, ThreadContext *tc);
 
 /// Target close() handler.
 SyscallReturn closeFunc(SyscallDesc *desc, int num,
@@ -223,10 +229,22 @@ SyscallReturn munmapFunc(SyscallDesc *desc, int num,
 SyscallReturn gethostnameFunc(SyscallDesc *desc, int num,
                               LiveProcess *p, ThreadContext *tc);
 
+/// Target getcwd() handler.
+SyscallReturn getcwdFunc(SyscallDesc *desc, int num,
+                         LiveProcess *p, ThreadContext *tc);
+
+/// Target unlink() handler.
+SyscallReturn readlinkFunc(SyscallDesc *desc, int num,
+                           LiveProcess *p, ThreadContext *tc);
+
 /// Target unlink() handler.
 SyscallReturn unlinkFunc(SyscallDesc *desc, int num,
                          LiveProcess *p, ThreadContext *tc);
 
+/// Target mkdir() handler.
+SyscallReturn mkdirFunc(SyscallDesc *desc, int num,
+                        LiveProcess *p, ThreadContext *tc);
+
 /// Target rename() handler.
 SyscallReturn renameFunc(SyscallDesc *desc, int num,
                          LiveProcess *p, ThreadContext *tc);
@@ -242,6 +260,20 @@ SyscallReturn ftruncateFunc(SyscallDesc *desc, int num,
                             LiveProcess *p, ThreadContext *tc);
 
 
+/// Target truncate64() handler.
+SyscallReturn truncate64Func(SyscallDesc *desc, int num,
+                             LiveProcess *p, ThreadContext *tc);
+
+/// Target ftruncate64() handler.
+SyscallReturn ftruncate64Func(SyscallDesc *desc, int num,
+                              LiveProcess *p, ThreadContext *tc);
+
+
+/// Target umask() handler.
+SyscallReturn umaskFunc(SyscallDesc *desc, int num,
+                        LiveProcess *p, ThreadContext *tc);
+
+
 /// Target chown() handler.
 SyscallReturn chownFunc(SyscallDesc *desc, int num,
                         LiveProcess *p, ThreadContext *tc);
@@ -291,6 +323,9 @@ SyscallReturn geteuidFunc(SyscallDesc *desc, int num,
 SyscallReturn getegidFunc(SyscallDesc *desc, int num,
                                LiveProcess *p, ThreadContext *tc);
 
+/// Target clone() handler.
+SyscallReturn cloneFunc(SyscallDesc *desc, int num,
+                               LiveProcess *p, ThreadContext *tc);
 
 
 /// Pseudo Funcs  - These functions use a different return convension,
@@ -353,6 +388,8 @@ template <typename target_stat, typename host_stat>
 static void
 convertStatBuf(target_stat &tgt, host_stat *host, bool fakeTTY = false)
 {
+    using namespace TheISA;
+
     if (fakeTTY)
         tgt->st_dev = 0xA;
     else
@@ -361,6 +398,11 @@ convertStatBuf(target_stat &tgt, host_stat *host, bool fakeTTY = false)
     tgt->st_ino = host->st_ino;
     tgt->st_ino = htog(tgt->st_ino);
     tgt->st_mode = host->st_mode;
+    if (fakeTTY) {
+        // Claim to be a character device
+        tgt->st_mode &= ~S_IFMT;    // Clear S_IFMT
+        tgt->st_mode |= S_IFCHR;    // Set S_IFCHR
+    }
     tgt->st_mode = htog(tgt->st_mode);
     tgt->st_nlink = host->st_nlink;
     tgt->st_nlink = htog(tgt->st_nlink);
@@ -395,6 +437,8 @@ template <typename target_stat, typename host_stat64>
 static void
 convertStat64Buf(target_stat &tgt, host_stat64 *host, bool fakeTTY = false)
 {
+    using namespace TheISA;
+
     convertStatBuf<target_stat, host_stat64>(tgt, host, fakeTTY);
 #if defined(STAT_HAVE_NSEC)
     tgt->st_atime_nsec = host->st_atime_nsec;
@@ -429,7 +473,7 @@ copyOutStat64Buf(TranslatingPort * mem, Addr addr,
 {
     typedef TypedBufferArg<typename OS::tgt_stat64> tgt_stat_buf;
     tgt_stat_buf tgt(addr);
-    convertStatBuf<tgt_stat_buf, hst_stat64>(tgt, host, fakeTTY);
+    convertStat64Buf<tgt_stat_buf, hst_stat64>(tgt, host, fakeTTY);
     tgt.copyOut(mem);
 }
 
@@ -441,8 +485,9 @@ SyscallReturn
 ioctlFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
           ThreadContext *tc)
 {
-    int fd = tc->getSyscallArg(0);
-    unsigned req = tc->getSyscallArg(1);
+    int index = 0;
+    int fd = process->getSyscallArg(tc, index);
+    unsigned req = process->getSyscallArg(tc, index);
 
     DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", fd, req);
 
@@ -452,14 +497,15 @@ ioctlFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
     }
 
     switch (req) {
-      case OS::TIOCISATTY:
-      case OS::TIOCGETP:
-      case OS::TIOCSETP:
-      case OS::TIOCSETN:
-      case OS::TIOCSETC:
-      case OS::TIOCGETC:
-      case OS::TIOCGETS:
-      case OS::TIOCGETA:
+      case OS::TIOCISATTY_:
+      case OS::TIOCGETP_:
+      case OS::TIOCSETP_:
+      case OS::TIOCSETN_:
+      case OS::TIOCSETC_:
+      case OS::TIOCGETC_:
+      case OS::TIOCGETS_:
+      case OS::TIOCGETA_:
+      case OS::TCSETAW_:
         return -ENOTTY;
 
       default:
@@ -476,7 +522,9 @@ openFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
 {
     std::string path;
 
-    if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
+    int index = 0;
+    if (!tc->getMemPort()->tryReadString(path,
+                process->getSyscallArg(tc, index)))
         return -EFAULT;
 
     if (path == "/dev/sysdev0") {
@@ -486,8 +534,8 @@ openFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
         return -ENOENT;
     }
 
-    int tgtFlags = tc->getSyscallArg(1);
-    int mode = tc->getSyscallArg(2);
+    int tgtFlags = process->getSyscallArg(tc, index);
+    int mode = process->getSyscallArg(tc, index);
     int hostFlags = 0;
 
     // translate open flags
@@ -511,12 +559,38 @@ openFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
 
     DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str());
 
-    // open the file
-    int fd = open(path.c_str(), hostFlags, mode);
+    int fd;
+    if (!path.compare(0, 6, "/proc/") || !path.compare(0, 8, "/system/") ||
+        !path.compare(0, 10, "/platform/") || !path.compare(0, 5, "/sys/")) {
+        // It's a proc/sys entery and requires special handling
+        fd = OS::openSpecialFile(path, process, tc);
+        return (fd == -1) ? -1 : process->alloc_fd(fd,path.c_str(),hostFlags,mode, false);
+     } else {
+        // open the file
+        fd = open(path.c_str(), hostFlags, mode);
+        return (fd == -1) ? -errno : process->alloc_fd(fd,path.c_str(),hostFlags,mode, false);
+     }
 
-    return (fd == -1) ? -errno : process->alloc_fd(fd);
 }
 
+/// Target sysinfo() handler.
+template <class OS>
+SyscallReturn
+sysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
+         ThreadContext *tc)
+{
+
+    int index = 0;
+    TypedBufferArg<typename OS::tgt_sysinfo>
+        sysinfo(process->getSyscallArg(tc, index));   
+
+    sysinfo->uptime=seconds_since_epoch;
+    sysinfo->totalram=process->system->memSize();
+
+    sysinfo.copyOut(tc->getMemPort());
+
+    return 0;
+}
 
 /// Target chmod() handler.
 template <class OS>
@@ -526,10 +600,13 @@ chmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
 {
     std::string path;
 
-    if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
+    int index = 0;
+    if (!tc->getMemPort()->tryReadString(path,
+                process->getSyscallArg(tc, index))) {
         return -EFAULT;
+    }
 
-    uint32_t mode = tc->getSyscallArg(1);
+    uint32_t mode = process->getSyscallArg(tc, index);
     mode_t hostMode = 0;
 
     // XXX translate mode flags via OS::something???
@@ -553,13 +630,14 @@ SyscallReturn
 fchmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
            ThreadContext *tc)
 {
-    int fd = tc->getSyscallArg(0);
+    int index = 0;
+    int fd = process->getSyscallArg(tc, index);
     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 = tc->getSyscallArg(1);
+    uint32_t mode = process->getSyscallArg(tc, index);
     mode_t hostMode = 0;
 
     // XXX translate mode flags via OS::someting???
@@ -573,6 +651,52 @@ fchmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
     return 0;
 }
 
+/// Target mremap() handler.
+template <class OS>
+SyscallReturn
+mremapFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc)
+{
+    int index = 0;
+    Addr start = process->getSyscallArg(tc, index);
+    uint64_t old_length = process->getSyscallArg(tc, index);
+    uint64_t new_length = process->getSyscallArg(tc, index);
+    uint64_t flags = process->getSyscallArg(tc, index);
+
+    if ((start % TheISA::VMPageSize != 0) ||
+            (new_length % TheISA::VMPageSize != 0)) {
+        warn("mremap failing: arguments not page aligned");
+        return -EINVAL;
+    }
+
+    if (new_length > old_length) {
+        if ((start + old_length) == process->mmap_end) {
+            uint64_t diff = new_length - old_length;
+            process->pTable->allocate(process->mmap_end, diff);
+            process->mmap_end += diff;
+            return start;
+        } else {
+            // sys/mman.h defined MREMAP_MAYMOVE
+            if (!(flags & 1)) {
+                warn("can't remap here and MREMAP_MAYMOVE flag not set\n");
+                return -ENOMEM;
+            } else {
+                process->pTable->remap(start, old_length, process->mmap_end);
+                warn("mremapping to totally new vaddr %08p-%08p, adding %d\n", 
+                        process->mmap_end, process->mmap_end + new_length, new_length);
+                start = process->mmap_end;
+                // add on the remaining unallocated pages
+                process->pTable->allocate(start + old_length, new_length - old_length);
+                process->mmap_end += new_length;
+                warn("returning %08p as start\n", start);
+                return start;
+            }
+        }
+    } else {
+        process->pTable->deallocate(start + new_length, old_length -
+                new_length);
+        return start;
+    }
+}
 
 /// Target stat() handler.
 template <class OS>
@@ -582,8 +706,12 @@ statFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
 {
     std::string path;
 
-    if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
-    return -EFAULT;
+    int index = 0;
+    if (!tc->getMemPort()->tryReadString(path,
+                process->getSyscallArg(tc, index))) {
+        return -EFAULT;
+    }
+    Addr bufPtr = process->getSyscallArg(tc, index);
 
     // Adjust path for current working directory
     path = process->fullPath(path);
@@ -594,7 +722,41 @@ statFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
     if (result < 0)
         return -errno;
 
-    copyOutStatBuf<OS>(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf);
+    copyOutStatBuf<OS>(tc->getMemPort(), bufPtr, &hostBuf);
+
+    return 0;
+}
+
+
+/// Target stat64() handler.
+template <class OS>
+SyscallReturn
+stat64Func(SyscallDesc *desc, int callnum, LiveProcess *process,
+           ThreadContext *tc)
+{
+    std::string path;
+
+    int index = 0;
+    if (!tc->getMemPort()->tryReadString(path,
+                process->getSyscallArg(tc, index)))
+        return -EFAULT;
+    Addr bufPtr = process->getSyscallArg(tc, index);
+
+    // Adjust path for current working directory
+    path = process->fullPath(path);
+
+#if NO_STAT64
+    struct stat  hostBuf;
+    int result = stat(path.c_str(), &hostBuf);
+#else
+    struct stat64 hostBuf;
+    int result = stat64(path.c_str(), &hostBuf);
+#endif
+
+    if (result < 0)
+        return -errno;
+
+    copyOutStat64Buf<OS>(tc->getMemPort(), bufPtr, &hostBuf);
 
     return 0;
 }
@@ -606,7 +768,9 @@ SyscallReturn
 fstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process,
             ThreadContext *tc)
 {
-    int fd = tc->getSyscallArg(0);
+    int index = 0;
+    int fd = process->getSyscallArg(tc, index);
+    Addr bufPtr = process->getSyscallArg(tc, index);
     if (fd < 0 || process->sim_fd(fd) < 0) {
         // doesn't map to any simulator fd: not a valid target fd
         return -EBADF;
@@ -623,8 +787,7 @@ fstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process,
     if (result < 0)
         return -errno;
 
-    copyOutStat64Buf<OS>(tc->getMemPort(), tc->getSyscallArg(1),
-        &hostBuf, (fd == 1));
+    copyOutStat64Buf<OS>(tc->getMemPort(), bufPtr, &hostBuf, (fd == 1));
 
     return 0;
 }
@@ -638,8 +801,12 @@ lstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
 {
     std::string path;
 
-    if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
-      return -EFAULT;
+    int index = 0;
+    if (!tc->getMemPort()->tryReadString(path,
+                process->getSyscallArg(tc, index))) {
+        return -EFAULT;
+    }
+    Addr bufPtr = process->getSyscallArg(tc, index);
 
     // Adjust path for current working directory
     path = process->fullPath(path);
@@ -650,7 +817,7 @@ lstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
     if (result < 0)
         return -errno;
 
-    copyOutStatBuf<OS>(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf);
+    copyOutStatBuf<OS>(tc->getMemPort(), bufPtr, &hostBuf);
 
     return 0;
 }
@@ -663,8 +830,12 @@ lstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process,
 {
     std::string path;
 
-    if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
-      return -EFAULT;
+    int index = 0;
+    if (!tc->getMemPort()->tryReadString(path,
+                process->getSyscallArg(tc, index))) {
+        return -EFAULT;
+    }
+    Addr bufPtr = process->getSyscallArg(tc, index);
 
     // Adjust path for current working directory
     path = process->fullPath(path);
@@ -680,7 +851,7 @@ lstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process,
     if (result < 0)
         return -errno;
 
-    copyOutStat64Buf<OS>(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf);
+    copyOutStat64Buf<OS>(tc->getMemPort(), bufPtr, &hostBuf);
 
     return 0;
 }
@@ -691,7 +862,9 @@ SyscallReturn
 fstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
           ThreadContext *tc)
 {
-    int fd = process->sim_fd(tc->getSyscallArg(0));
+    int index = 0;
+    int fd = process->sim_fd(process->getSyscallArg(tc, index));
+    Addr bufPtr = process->getSyscallArg(tc, index);
 
     DPRINTF(SyscallVerbose, "fstat(%d, ...)\n", fd);
 
@@ -704,8 +877,7 @@ fstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
     if (result < 0)
         return -errno;
 
-    copyOutStatBuf<OS>(tc->getMemPort(), tc->getSyscallArg(1),
-        &hostBuf, (fd == 1));
+    copyOutStatBuf<OS>(tc->getMemPort(), bufPtr, &hostBuf, (fd == 1));
 
     return 0;
 }
@@ -719,8 +891,12 @@ statfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
 {
     std::string path;
 
-    if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
-      return -EFAULT;
+    int index = 0;
+    if (!tc->getMemPort()->tryReadString(path,
+                process->getSyscallArg(tc, index))) {
+        return -EFAULT;
+    }
+    Addr bufPtr = process->getSyscallArg(tc, index);
 
     // Adjust path for current working directory
     path = process->fullPath(path);
@@ -731,8 +907,7 @@ statfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
     if (result < 0)
         return -errno;
 
-    OS::copyOutStatfsBuf(tc->getMemPort(),
-            (Addr)(tc->getSyscallArg(1)), &hostBuf);
+    OS::copyOutStatfsBuf(tc->getMemPort(), bufPtr, &hostBuf);
 
     return 0;
 }
@@ -744,7 +919,9 @@ SyscallReturn
 fstatfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
             ThreadContext *tc)
 {
-    int fd = process->sim_fd(tc->getSyscallArg(0));
+    int index = 0;
+    int fd = process->sim_fd(process->getSyscallArg(tc, index));
+    Addr bufPtr = process->getSyscallArg(tc, index);
 
     if (fd < 0)
         return -EBADF;
@@ -755,8 +932,7 @@ fstatfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
     if (result < 0)
         return -errno;
 
-    OS::copyOutStatfsBuf(tc->getMemPort(), tc->getSyscallArg(1),
-        &hostBuf);
+    OS::copyOutStatfsBuf(tc->getMemPort(), bufPtr, &hostBuf);
 
     return 0;
 }
@@ -768,18 +944,18 @@ SyscallReturn
 writevFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
            ThreadContext *tc)
 {
-    int fd = tc->getSyscallArg(0);
+    int index = 0;
+    int fd = process->getSyscallArg(tc, index);
     if (fd < 0 || process->sim_fd(fd) < 0) {
         // doesn't map to any simulator fd: not a valid target fd
         return -EBADF;
     }
 
     TranslatingPort *p = tc->getMemPort();
-    uint64_t tiov_base = tc->getSyscallArg(1);
-    size_t count = tc->getSyscallArg(2);
+    uint64_t tiov_base = process->getSyscallArg(tc, index);
+    size_t count = process->getSyscallArg(tc, index);
     struct iovec hiov[count];
-    for (int i = 0; i < count; ++i)
-    {
+    for (size_t i = 0; i < count; ++i) {
         typename OS::tgt_iovec tiov;
 
         p->readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec),
@@ -792,10 +968,8 @@ writevFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
 
     int result = writev(process->sim_fd(fd), hiov, count);
 
-    for (int i = 0; i < count; ++i)
-    {
+    for (size_t i = 0; i < count; ++i)
         delete [] (char *)hiov[i].iov_base;
-    }
 
     if (result < 0)
         return -errno;
@@ -820,12 +994,14 @@ template <class OS>
 SyscallReturn
 mmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
 {
-    Addr start = tc->getSyscallArg(0);
-    uint64_t length = tc->getSyscallArg(1);
-    // int prot = tc->getSyscallArg(2);
-    int flags = tc->getSyscallArg(3);
-    // int fd = p->sim_fd(tc->getSyscallArg(4));
-    // int offset = tc->getSyscallArg(5);
+    int index = 0;
+    Addr start = p->getSyscallArg(tc, index);
+    uint64_t length = p->getSyscallArg(tc, index);
+    index++; // int prot = p->getSyscallArg(tc, index);
+    int flags = p->getSyscallArg(tc, index);
+    int fd = p->sim_fd(p->getSyscallArg(tc, index));
+    // int offset = p->getSyscallArg(tc, index);
+
 
     if ((start  % TheISA::VMPageSize) != 0 ||
         (length % TheISA::VMPageSize) != 0) {
@@ -841,13 +1017,18 @@ mmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
     }
 
     // pick next address from our "mmap region"
-    start = p->mmap_end;
+    if (OS::mmapGrowsDown()) {
+        start = p->mmap_end - length;
+        p->mmap_end = start;
+    } else {
+        start = p->mmap_end;
+        p->mmap_end += length;
+    }
     p->pTable->allocate(start, length);
-    p->mmap_end += length;
 
     if (!(flags & OS::TGT_MAP_ANONYMOUS)) {
         warn("allowing mmap of file @ fd %d. "
-             "This will break if not /dev/zero.", tc->getSyscallArg(4));
+             "This will break if not /dev/zero.", fd);
     }
 
     return start;
@@ -859,17 +1040,25 @@ SyscallReturn
 getrlimitFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
         ThreadContext *tc)
 {
-    unsigned resource = tc->getSyscallArg(0);
-    TypedBufferArg<typename OS::rlimit> rlp(tc->getSyscallArg(1));
+    int index = 0;
+    unsigned resource = process->getSyscallArg(tc, index);
+    TypedBufferArg<typename OS::rlimit> rlp(process->getSyscallArg(tc, index));
 
     switch (resource) {
         case OS::TGT_RLIMIT_STACK:
-            // max stack size in bytes: make up a number (2MB for now)
+            // max stack size in bytes: make up a number (8MB 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;
 
+        case OS::TGT_RLIMIT_DATA:
+            // max data segment size in bytes: make up a number
+            rlp->rlim_cur = rlp->rlim_max = 256 * 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;
@@ -887,12 +1076,13 @@ SyscallReturn
 gettimeofdayFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
         ThreadContext *tc)
 {
-    TypedBufferArg<typename OS::timeval> tp(tc->getSyscallArg(0));
+    int index = 0;
+    TypedBufferArg<typename OS::timeval> tp(process->getSyscallArg(tc, index));
 
     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->tv_sec = TheISA::htog(tp->tv_sec);
+    tp->tv_usec = TheISA::htog(tp->tv_usec);
 
     tp.copyOut(tc->getMemPort());
 
@@ -908,10 +1098,14 @@ utimesFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
 {
     std::string path;
 
-    if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
-      return -EFAULT;
+    int index = 0;
+    if (!tc->getMemPort()->tryReadString(path,
+                process->getSyscallArg(tc, index))) {
+        return -EFAULT;
+    }
 
-    TypedBufferArg<typename OS::timeval [2]> tp(tc->getSyscallArg(1));
+    TypedBufferArg<typename OS::timeval [2]>
+        tp(process->getSyscallArg(tc, index));
     tp.copyIn(tc->getMemPort());
 
     struct timeval hostTimeval[2];
@@ -937,8 +1131,9 @@ SyscallReturn
 getrusageFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
               ThreadContext *tc)
 {
-    int who = tc->getSyscallArg(0);    // THREAD, SELF, or CHILDREN
-    TypedBufferArg<typename OS::rusage> rup(tc->getSyscallArg(1));
+    int index = 0;
+    int who = process->getSyscallArg(tc, index); // THREAD, SELF, or CHILDREN
+    TypedBufferArg<typename OS::rusage> rup(process->getSyscallArg(tc, index));
 
     rup->ru_utime.tv_sec = 0;
     rup->ru_utime.tv_usec = 0;
@@ -982,7 +1177,52 @@ getrusageFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
     return 0;
 }
 
+/// Target times() function.
+template <class OS>
+SyscallReturn
+timesFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
+           ThreadContext *tc)
+{
+    int index = 0;
+    TypedBufferArg<typename OS::tms> bufp(process->getSyscallArg(tc, index));
+
+    // Fill in the time structure (in clocks)
+    int64_t clocks = curTick * OS::_SC_CLK_TCK / Clock::Int::s;
+    bufp->tms_utime = clocks;
+    bufp->tms_stime = 0;
+    bufp->tms_cutime = 0;
+    bufp->tms_cstime = 0;
+
+    // Convert to host endianness
+    bufp->tms_utime = htog(bufp->tms_utime);
+
+    // Write back
+    bufp.copyOut(tc->getMemPort());
+
+    // Return clock ticks since system boot
+    return clocks;
+}
 
+/// Target time() function.
+template <class OS>
+SyscallReturn
+timeFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
+           ThreadContext *tc)
+{
+    typename OS::time_t sec, usec;
+    getElapsedTime(sec, usec);
+    sec += seconds_since_epoch;
+
+    int index = 0;
+    Addr taddr = (Addr)process->getSyscallArg(tc, index);
+    if(taddr != 0) {
+        typename OS::time_t t = sec;
+        t = htog(t);
+        TranslatingPort *p = tc->getMemPort();
+        p->writeBlob(taddr, (uint8_t*)&t, (int)sizeof(typename OS::time_t));
+    }
+    return sec;
+}
 
 
 #endif // __SIM_SYSCALL_EMUL_HH__