merge alpha system files into tree
[gem5.git] / src / sim / syscall_emul.cc
index e72890612d5b9f556718e5f5cf7cd421757aeeb6..e0469744e51e48f7a9568e36c84ceb2ffff772c4 100644 (file)
 #include <fcntl.h>
 #include <unistd.h>
 
-#include <string>
+#include <cstdio>
 #include <iostream>
+#include <string>
 
+#include "arch/utility.hh"
 #include "sim/syscall_emul.hh"
 #include "base/chunk_generator.hh"
 #include "base/trace.hh"
+#include "config/the_isa.hh"
 #include "cpu/thread_context.hh"
 #include "cpu/base.hh"
 #include "mem/page_table.hh"
 #include "sim/process.hh"
-
+#include "sim/system.hh"
 #include "sim/sim_exit.hh"
 
 using namespace std;
 using namespace TheISA;
 
 void
-SyscallDesc::doSyscall(int callnum, Process *process, ThreadContext *tc)
+SyscallDesc::doSyscall(int callnum, LiveProcess *process, ThreadContext *tc)
 {
-    DPRINTFR(SyscallVerbose, "%d: %s: syscall %s called w/arguments %d,%d,%d,%d\n",
-             curTick,tc->getCpuPtr()->name(), name,
-             tc->getSyscallArg(0),tc->getSyscallArg(1),
-             tc->getSyscallArg(2),tc->getSyscallArg(3));
+#if TRACING_ON
+    int index = 0;
+#endif
+    DPRINTFR(SyscallVerbose,
+             "%d: %s: syscall %s called w/arguments %d,%d,%d,%d\n",
+             curTick(), tc->getCpuPtr()->name(), name,
+             process->getSyscallArg(tc, index),
+             process->getSyscallArg(tc, index),
+             process->getSyscallArg(tc, index),
+             process->getSyscallArg(tc, index));
 
     SyscallReturn retval = (*funcPtr)(this, callnum, process, tc);
 
     DPRINTFR(SyscallVerbose, "%d: %s: syscall %s returns %d\n",
-             curTick,tc->getCpuPtr()->name(), name, retval.value());
+             curTick(),tc->getCpuPtr()->name(), name, retval.value());
 
     if (!(flags & SyscallDesc::SuppressReturnValue))
-        tc->setSyscallReturn(retval);
+        process->setSyscallReturn(tc, retval);
 }
 
 
 SyscallReturn
-unimplementedFunc(SyscallDesc *desc, int callnum, Process *process,
+unimplementedFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
                   ThreadContext *tc)
 {
     fatal("syscall %s (#%d) unimplemented.", desc->name, callnum);
@@ -77,22 +86,29 @@ unimplementedFunc(SyscallDesc *desc, int callnum, Process *process,
 
 
 SyscallReturn
-ignoreFunc(SyscallDesc *desc, int callnum, Process *process,
+ignoreFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
            ThreadContext *tc)
 {
+    int index = 0;
     warn("ignoring syscall %s(%d, %d, ...)", desc->name,
-         tc->getSyscallArg(0), tc->getSyscallArg(1));
+         process->getSyscallArg(tc, index), process->getSyscallArg(tc, index));
 
     return 0;
 }
 
 
 SyscallReturn
-exitFunc(SyscallDesc *desc, int callnum, Process *process,
+exitFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
          ThreadContext *tc)
 {
-    if (tc->exit()) {
-        exitSimLoop("target called exit()", tc->getSyscallArg(0) & 0xff);
+    if (process->system->numRunningContexts() == 1) {
+        // Last running context... exit simulator
+        int index = 0;
+        exitSimLoop("target called exit()",
+                    process->getSyscallArg(tc, index) & 0xff);
+    } else {
+        // other running threads... just halt this one
+        tc->halt();
     }
 
     return 1;
@@ -100,38 +116,81 @@ exitFunc(SyscallDesc *desc, int callnum, Process *process,
 
 
 SyscallReturn
-getpagesizeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
+exitGroupFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
+              ThreadContext *tc)
 {
-    return (int)VMPageSize;
+    // really should just halt all thread contexts belonging to this
+    // process in case there's another process running...
+    int index = 0;
+    exitSimLoop("target called exit()",
+                process->getSyscallArg(tc, index) & 0xff);
+
+    return 1;
 }
 
 
 SyscallReturn
-obreakFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
+getpagesizeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
 {
-    Addr junk;
+    return (int)VMPageSize;
+}
 
+
+SyscallReturn
+brkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
+{
     // change brk addr to first arg
-    Addr new_brk = tc->getSyscallArg(0);
-    if (new_brk != 0) {
+    int index = 0;
+    Addr new_brk = p->getSyscallArg(tc, index);
+
+    // in Linux at least, brk(0) returns the current break value
+    // (note that the syscall and the glibc function have different behavior)
+    if (new_brk == 0)
+        return p->brk_point;
+
+    if (new_brk > p->brk_point) {
+        // might need to allocate some new pages
         for (ChunkGenerator gen(p->brk_point, new_brk - p->brk_point,
                                 VMPageSize); !gen.done(); gen.next()) {
-            if (!p->pTable->translate(gen.addr(), junk))
+            if (!p->pTable->translate(gen.addr()))
                 p->pTable->allocate(roundDown(gen.addr(), VMPageSize),
                                     VMPageSize);
+
+            // if the address is already there, zero it out
+            else {
+                uint8_t zero  = 0;
+                TranslatingPort *tp = tc->getMemPort();
+
+                // split non-page aligned accesses
+                Addr next_page = roundUp(gen.addr(), VMPageSize);
+                uint32_t size_needed = next_page - gen.addr();
+                tp->memsetBlob(gen.addr(), zero, size_needed);
+                if (gen.addr() + VMPageSize > next_page &&
+                    next_page < new_brk &&
+                    p->pTable->translate(next_page))
+                {
+                    size_needed = VMPageSize - size_needed;
+                    tp->memsetBlob(next_page, zero, size_needed);
+                }
+            }
         }
-        p->brk_point = new_brk;
     }
+
+    p->brk_point = new_brk;
     DPRINTF(SyscallVerbose, "Break Point changed to: %#X\n", p->brk_point);
     return p->brk_point;
 }
 
 
 SyscallReturn
-closeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
+closeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
 {
-    int target_fd = tc->getSyscallArg(0);
-    int status = close(p->sim_fd(target_fd));
+    int index = 0;
+    int target_fd = p->getSyscallArg(tc, index);
+    int sim_fd = p->sim_fd(target_fd);
+    int status = 0;
+    if (sim_fd > 2)
+        status = close(sim_fd);
     if (status >= 0)
         p->free_fd(target_fd);
     return status;
@@ -139,11 +198,13 @@ closeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
 
 
 SyscallReturn
-readFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
+readFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
 {
-    int fd = p->sim_fd(tc->getSyscallArg(0));
-    int nbytes = tc->getSyscallArg(2);
-    BufferArg bufArg(tc->getSyscallArg(1), nbytes);
+    int index = 0;
+    int fd = p->sim_fd(p->getSyscallArg(tc, index));
+    Addr bufPtr = p->getSyscallArg(tc, index);
+    int nbytes = p->getSyscallArg(tc, index);
+    BufferArg bufArg(bufPtr, nbytes);
 
     int bytes_read = read(fd, bufArg.bufferPtr(), nbytes);
 
@@ -154,11 +215,13 @@ readFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
 }
 
 SyscallReturn
-writeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
+writeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
 {
-    int fd = p->sim_fd(tc->getSyscallArg(0));
-    int nbytes = tc->getSyscallArg(2);
-    BufferArg bufArg(tc->getSyscallArg(1), nbytes);
+    int index = 0;
+    int fd = p->sim_fd(p->getSyscallArg(tc, index));
+    Addr bufPtr = p->getSyscallArg(tc, index);
+    int nbytes = p->getSyscallArg(tc, index);
+    BufferArg bufArg(bufPtr, nbytes);
 
     bufArg.copyIn(tc->getMemPort());
 
@@ -171,11 +234,12 @@ writeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
 
 
 SyscallReturn
-lseekFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
+lseekFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
 {
-    int fd = p->sim_fd(tc->getSyscallArg(0));
-    uint64_t offs = tc->getSyscallArg(1);
-    int whence = tc->getSyscallArg(2);
+    int index = 0;
+    int fd = p->sim_fd(p->getSyscallArg(tc, index));
+    uint64_t offs = p->getSyscallArg(tc, index);
+    int whence = p->getSyscallArg(tc, index);
 
     off_t result = lseek(fd, offs, whence);
 
@@ -184,7 +248,41 @@ lseekFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
 
 
 SyscallReturn
-munmapFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
+_llseekFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
+{
+    int index = 0;
+    int fd = p->sim_fd(p->getSyscallArg(tc, index));
+    uint64_t offset_high = p->getSyscallArg(tc, index);
+    uint32_t offset_low = p->getSyscallArg(tc, index);
+    Addr result_ptr = p->getSyscallArg(tc, index);
+    int whence = p->getSyscallArg(tc, index);
+
+    uint64_t offset = (offset_high << 32) | offset_low;
+
+    uint64_t result = lseek(fd, offset, whence);
+    result = TheISA::htog(result);
+
+    if (result == (off_t)-1) {
+        //The seek failed.
+        return -errno;
+    } else {
+        // The seek succeeded.
+        // Copy "result" to "result_ptr"
+        // XXX We'll assume that the size of loff_t is 64 bits on the
+        // target platform
+        BufferArg result_buf(result_ptr, sizeof(result));
+        memcpy(result_buf.bufferPtr(), &result, sizeof(result));
+        result_buf.copyOut(tc->getMemPort());
+        return 0;
+    }
+
+
+    return (result == (off_t)-1) ? -errno : result;
+}
+
+
+SyscallReturn
+munmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
 {
     // given that we don't really implement mmap, munmap is really easy
     return 0;
@@ -194,10 +292,12 @@ munmapFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
 const char *hostname = "m5.eecs.umich.edu";
 
 SyscallReturn
-gethostnameFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
+gethostnameFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
 {
-    int name_len = tc->getSyscallArg(1);
-    BufferArg name(tc->getSyscallArg(0), name_len);
+    int index = 0;
+    Addr bufPtr = p->getSyscallArg(tc, index);
+    int name_len = p->getSyscallArg(tc, index);
+    BufferArg name(bufPtr, name_len);
 
     strncpy((char *)name.bufferPtr(), hostname, name_len);
 
@@ -207,92 +307,243 @@ gethostnameFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
 }
 
 SyscallReturn
-unlinkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
+getcwdFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
+{
+    int result = 0;
+    int index = 0;
+    Addr bufPtr = p->getSyscallArg(tc, index);
+    unsigned long size = p->getSyscallArg(tc, index);
+    BufferArg buf(bufPtr, size);
+
+    // Is current working directory defined?
+    string cwd = p->getcwd();
+    if (!cwd.empty()) {
+        if (cwd.length() >= size) {
+            // Buffer too small
+            return -ERANGE;
+        }
+        strncpy((char *)buf.bufferPtr(), cwd.c_str(), size);
+        result = cwd.length();
+    }
+    else {
+        if (getcwd((char *)buf.bufferPtr(), size) != NULL) {
+            result = strlen((char *)buf.bufferPtr());
+        }
+        else {
+            result = -1;
+        }
+    }
+
+    buf.copyOut(tc->getMemPort());
+
+    return (result == -1) ? -errno : result;
+}
+
+
+SyscallReturn
+readlinkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
 {
     string path;
 
-    if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
+    int index = 0;
+    if (!tc->getMemPort()->tryReadString(path, p->getSyscallArg(tc, index)))
         return (TheISA::IntReg)-EFAULT;
 
+    // Adjust path for current working directory
+    path = p->fullPath(path);
+
+    Addr bufPtr = p->getSyscallArg(tc, index);
+    size_t bufsiz = p->getSyscallArg(tc, index);
+
+    BufferArg buf(bufPtr, bufsiz);
+
+    int result = readlink(path.c_str(), (char *)buf.bufferPtr(), bufsiz);
+
+    buf.copyOut(tc->getMemPort());
+
+    return (result == -1) ? -errno : result;
+}
+
+SyscallReturn
+unlinkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
+{
+    string path;
+
+    int index = 0;
+    if (!tc->getMemPort()->tryReadString(path, p->getSyscallArg(tc, index)))
+        return (TheISA::IntReg)-EFAULT;
+
+    // Adjust path for current working directory
+    path = p->fullPath(path);
+
     int result = unlink(path.c_str());
     return (result == -1) ? -errno : result;
 }
 
+
 SyscallReturn
-renameFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
+mkdirFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
+{
+    string path;
+
+    int index = 0;
+    if (!tc->getMemPort()->tryReadString(path, p->getSyscallArg(tc, index)))
+        return (TheISA::IntReg)-EFAULT;
+
+    // Adjust path for current working directory
+    path = p->fullPath(path);
+
+    mode_t mode = p->getSyscallArg(tc, index);
+
+    int result = mkdir(path.c_str(), mode);
+    return (result == -1) ? -errno : result;
+}
+
+SyscallReturn
+renameFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
 {
     string old_name;
 
-    if (!tc->getMemPort()->tryReadString(old_name, tc->getSyscallArg(0)))
+    int index = 0;
+    if (!tc->getMemPort()->tryReadString(old_name, p->getSyscallArg(tc, index)))
         return -EFAULT;
 
     string new_name;
 
-    if (!tc->getMemPort()->tryReadString(new_name, tc->getSyscallArg(1)))
+    if (!tc->getMemPort()->tryReadString(new_name, p->getSyscallArg(tc, index)))
         return -EFAULT;
 
+    // Adjust path for current working directory
+    old_name = p->fullPath(old_name);
+    new_name = p->fullPath(new_name);
+
     int64_t result = rename(old_name.c_str(), new_name.c_str());
     return (result == -1) ? -errno : result;
 }
 
 SyscallReturn
-truncateFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
+truncateFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
 {
     string path;
 
-    if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
+    int index = 0;
+    if (!tc->getMemPort()->tryReadString(path, p->getSyscallArg(tc, index)))
         return -EFAULT;
 
-    off_t length = tc->getSyscallArg(1);
+    off_t length = p->getSyscallArg(tc, index);
+
+    // Adjust path for current working directory
+    path = p->fullPath(path);
 
     int result = truncate(path.c_str(), length);
     return (result == -1) ? -errno : result;
 }
 
 SyscallReturn
-ftruncateFunc(SyscallDesc *desc, int num, Process *process, ThreadContext *tc)
+ftruncateFunc(SyscallDesc *desc, int num,
+              LiveProcess *process, ThreadContext *tc)
 {
-    int fd = process->sim_fd(tc->getSyscallArg(0));
+    int index = 0;
+    int fd = process->sim_fd(process->getSyscallArg(tc, index));
 
     if (fd < 0)
         return -EBADF;
 
-    off_t length = tc->getSyscallArg(1);
+    off_t length = process->getSyscallArg(tc, index);
 
     int result = ftruncate(fd, length);
     return (result == -1) ? -errno : result;
 }
 
 SyscallReturn
-chownFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
+truncate64Func(SyscallDesc *desc, int num,
+                LiveProcess *process, ThreadContext *tc)
 {
+    int index = 0;
     string path;
 
-    if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
+    if (!tc->getMemPort()->tryReadString(path, process->getSyscallArg(tc, index)))
+       return -EFAULT;
+
+    int64_t length = process->getSyscallArg(tc, index, 64);
+
+    // Adjust path for current working directory
+    path = process->fullPath(path);
+
+#if NO_STAT64
+    int result = truncate(path.c_str(), length);
+#else
+    int result = truncate64(path.c_str(), length);
+#endif
+    return (result == -1) ? -errno : result;
+}
+
+SyscallReturn
+ftruncate64Func(SyscallDesc *desc, int num,
+                LiveProcess *process, ThreadContext *tc)
+{
+    int index = 0;
+    int fd = process->sim_fd(process->getSyscallArg(tc, index));
+
+    if (fd < 0)
+        return -EBADF;
+
+    int64_t length = process->getSyscallArg(tc, index, 64);
+
+#if NO_STAT64
+    int result = ftruncate(fd, length);
+#else
+    int result = ftruncate64(fd, length);
+#endif
+    return (result == -1) ? -errno : result;
+}
+
+SyscallReturn
+umaskFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc)
+{
+    // Letting the simulated program change the simulator's umask seems like
+    // a bad idea.  Compromise by just returning the current umask but not
+    // changing anything.
+    mode_t oldMask = umask(0);
+    umask(oldMask);
+    return (int)oldMask;
+}
+
+SyscallReturn
+chownFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
+{
+    string path;
+
+    int index = 0;
+    if (!tc->getMemPort()->tryReadString(path, p->getSyscallArg(tc, index)))
         return -EFAULT;
 
     /* XXX endianess */
-    uint32_t owner = tc->getSyscallArg(1);
+    uint32_t owner = p->getSyscallArg(tc, index);
     uid_t hostOwner = owner;
-    uint32_t group = tc->getSyscallArg(2);
+    uint32_t group = p->getSyscallArg(tc, index);
     gid_t hostGroup = group;
 
+    // Adjust path for current working directory
+    path = p->fullPath(path);
+
     int result = chown(path.c_str(), hostOwner, hostGroup);
     return (result == -1) ? -errno : result;
 }
 
 SyscallReturn
-fchownFunc(SyscallDesc *desc, int num, Process *process, ThreadContext *tc)
+fchownFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc)
 {
-    int fd = process->sim_fd(tc->getSyscallArg(0));
+    int index = 0;
+    int fd = process->sim_fd(process->getSyscallArg(tc, index));
 
     if (fd < 0)
         return -EBADF;
 
     /* XXX endianess */
-    uint32_t owner = tc->getSyscallArg(1);
+    uint32_t owner = process->getSyscallArg(tc, index);
     uid_t hostOwner = owner;
-    uint32_t group = tc->getSyscallArg(2);
+    uint32_t group = process->getSyscallArg(tc, index);
     gid_t hostGroup = group;
 
     int result = fchown(fd, hostOwner, hostGroup);
@@ -301,15 +552,32 @@ fchownFunc(SyscallDesc *desc, int num, Process *process, ThreadContext *tc)
 
 
 SyscallReturn
-fcntlFunc(SyscallDesc *desc, int num, Process *process,
+dupFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc)
+{
+    int index = 0;
+    int fd = process->sim_fd(process->getSyscallArg(tc, index));
+    if (fd < 0)
+        return -EBADF;
+
+    Process::FdMap *fdo = process->sim_fd_obj(fd);
+
+    int result = dup(fd);
+    return (result == -1) ? -errno :
+        process->alloc_fd(result, fdo->filename, fdo->flags, fdo->mode, false);
+}
+
+
+SyscallReturn
+fcntlFunc(SyscallDesc *desc, int num, 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)
         return -EBADF;
 
-    int cmd = tc->getSyscallArg(1);
+    int cmd = process->getSyscallArg(tc, index);
     switch (cmd) {
       case 0: // F_DUPFD
         // if we really wanted to support this, we'd need to do it
@@ -343,15 +611,16 @@ fcntlFunc(SyscallDesc *desc, int num, Process *process,
 }
 
 SyscallReturn
-fcntl64Func(SyscallDesc *desc, int num, Process *process,
+fcntl64Func(SyscallDesc *desc, int num, 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)
         return -EBADF;
 
-    int cmd = tc->getSyscallArg(1);
+    int cmd = process->getSyscallArg(tc, index);
     switch (cmd) {
       case 33: //F_GETLK64
         warn("fcntl64(%d, F_GETLK64) not supported, error returned\n", fd);
@@ -372,7 +641,7 @@ fcntl64Func(SyscallDesc *desc, int num, Process *process,
 }
 
 SyscallReturn
-pipePseudoFunc(SyscallDesc *desc, int callnum, Process *process,
+pipePseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
          ThreadContext *tc)
 {
     int fds[2], sim_fds[2];
@@ -383,9 +652,10 @@ pipePseudoFunc(SyscallDesc *desc, int callnum, Process *process,
         return pipe_retval;
     }
 
-    sim_fds[0] = process->alloc_fd(fds[0]);
-    sim_fds[1] = process->alloc_fd(fds[1]);
+    sim_fds[0] = process->alloc_fd(fds[0], "PIPE-READ", O_WRONLY, -1, true);
+    sim_fds[1] = process->alloc_fd(fds[1], "PIPE-WRITE", O_RDONLY, -1, true);
 
+    process->setReadPipeSource(sim_fds[0], sim_fds[1]);
     // Alpha Linux convention for pipe() is that fd[0] is returned as
     // the return value of the function, and fd[1] is returned in r20.
     tc->setIntReg(SyscallPseudoReturnReg, sim_fds[1]);
@@ -394,95 +664,176 @@ pipePseudoFunc(SyscallDesc *desc, int callnum, Process *process,
 
 
 SyscallReturn
-getpidPseudoFunc(SyscallDesc *desc, int callnum, Process *process,
+getpidPseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
            ThreadContext *tc)
 {
     // Make up a PID.  There's no interprocess communication in
     // fake_syscall mode, so there's no way for a process to know it's
     // not getting a unique value.
 
-    tc->setIntReg(SyscallPseudoReturnReg, 99);
-    return 100;
+    tc->setIntReg(SyscallPseudoReturnReg, process->ppid());
+    return process->pid();
 }
 
 
 SyscallReturn
-getuidPseudoFunc(SyscallDesc *desc, int callnum, Process *process,
+getuidPseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
            ThreadContext *tc)
 {
     // Make up a UID and EUID... it shouldn't matter, and we want the
     // simulation to be deterministic.
 
     // EUID goes in r20.
-    tc->setIntReg(SyscallPseudoReturnReg, 100); //EUID
-    return 100;                // UID
+    tc->setIntReg(SyscallPseudoReturnReg, process->euid()); //EUID
+    return process->uid();              // UID
 }
 
 
 SyscallReturn
-getgidPseudoFunc(SyscallDesc *desc, int callnum, Process *process,
+getgidPseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
            ThreadContext *tc)
 {
     // Get current group ID.  EGID goes in r20.
-    tc->setIntReg(SyscallPseudoReturnReg, 100); //EGID
-    return 100;
+    tc->setIntReg(SyscallPseudoReturnReg, process->egid()); //EGID
+    return process->gid();
 }
 
 
 SyscallReturn
-setuidFunc(SyscallDesc *desc, int callnum, Process *process,
+setuidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
            ThreadContext *tc)
 {
     // can't fathom why a benchmark would call this.
-    warn("Ignoring call to setuid(%d)\n", tc->getSyscallArg(0));
+    int index = 0;
+    warn("Ignoring call to setuid(%d)\n", process->getSyscallArg(tc, index));
     return 0;
 }
 
 SyscallReturn
-getpidFunc(SyscallDesc *desc, int callnum, Process *process,
+getpidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
            ThreadContext *tc)
 {
     // Make up a PID.  There's no interprocess communication in
     // fake_syscall mode, so there's no way for a process to know it's
     // not getting a unique value.
 
-    tc->setIntReg(SyscallPseudoReturnReg, 99); //PID
-    return 100;
+    tc->setIntReg(SyscallPseudoReturnReg, process->ppid()); //PID
+    return process->pid();
 }
 
 SyscallReturn
-getppidFunc(SyscallDesc *desc, int callnum, Process *process,
+getppidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
            ThreadContext *tc)
 {
-    return 99;
+    return process->ppid();
 }
 
 SyscallReturn
-getuidFunc(SyscallDesc *desc, int callnum, Process *process,
+getuidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
            ThreadContext *tc)
 {
-    return 100;                // UID
+    return process->uid();              // UID
 }
 
 SyscallReturn
-geteuidFunc(SyscallDesc *desc, int callnum, Process *process,
+geteuidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
            ThreadContext *tc)
 {
-    return 100;                // UID
+    return process->euid();             // UID
 }
 
 SyscallReturn
-getgidFunc(SyscallDesc *desc, int callnum, Process *process,
+getgidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
            ThreadContext *tc)
 {
-    return 100;
+    return process->gid();
 }
 
 SyscallReturn
-getegidFunc(SyscallDesc *desc, int callnum, Process *process,
+getegidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
            ThreadContext *tc)
 {
-    return 100;
+    return process->egid();
 }
 
 
+SyscallReturn
+cloneFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
+           ThreadContext *tc)
+{
+    int index = 0;
+    IntReg flags = process->getSyscallArg(tc, index);
+    IntReg newStack = process->getSyscallArg(tc, index);
+
+    DPRINTF(SyscallVerbose, "In sys_clone:\n");
+    DPRINTF(SyscallVerbose, " Flags=%llx\n", flags);
+    DPRINTF(SyscallVerbose, " Child stack=%llx\n", newStack);
+
+
+    if (flags != 0x10f00) {
+        warn("This sys_clone implementation assumes flags "
+             "CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD "
+             "(0x10f00), and may not work correctly with given flags "
+             "0x%llx\n", flags);
+    }
+
+    ThreadContext* ctc; // child thread context
+    if ( ( ctc = process->findFreeContext() ) != NULL ) {
+        DPRINTF(SyscallVerbose, " Found unallocated thread context\n");
+
+        ctc->clearArchRegs();
+
+        // Arch-specific cloning code
+        #if THE_ISA == ALPHA_ISA or THE_ISA == X86_ISA
+            // Cloning the misc. regs for these archs is enough
+            TheISA::copyMiscRegs(tc, ctc);
+        #elif THE_ISA == SPARC_ISA
+            TheISA::copyRegs(tc, ctc);
+
+            // TODO: Explain what this code actually does :-)
+            ctc->setIntReg(NumIntArchRegs + 6, 0);
+            ctc->setIntReg(NumIntArchRegs + 4, 0);
+            ctc->setIntReg(NumIntArchRegs + 3, NWindows - 2);
+            ctc->setIntReg(NumIntArchRegs + 5, NWindows);
+            ctc->setMiscReg(MISCREG_CWP, 0);
+            ctc->setIntReg(NumIntArchRegs + 7, 0);
+            ctc->setMiscRegNoEffect(MISCREG_TL, 0);
+            ctc->setMiscRegNoEffect(MISCREG_ASI, ASI_PRIMARY);
+
+            for (int y = 8; y < 32; y++)
+                ctc->setIntReg(y, tc->readIntReg(y));
+        #else
+            fatal("sys_clone is not implemented for this ISA\n");
+        #endif
+
+        // Set up stack register
+        ctc->setIntReg(TheISA::StackPointerReg, newStack);
+
+        // Set up syscall return values in parent and child
+        ctc->setIntReg(ReturnValueReg, 0); // return value, child
+
+        // Alpha needs SyscallSuccessReg=0 in child
+        #if THE_ISA == ALPHA_ISA
+            ctc->setIntReg(TheISA::SyscallSuccessReg, 0);
+        #endif
+
+        // In SPARC/Linux, clone returns 0 on pseudo-return register if
+        // parent, non-zero if child
+        #if THE_ISA == SPARC_ISA
+            tc->setIntReg(TheISA::SyscallPseudoReturnReg, 0);
+            ctc->setIntReg(TheISA::SyscallPseudoReturnReg, 1);
+        #endif
+
+        ctc->pcState(tc->nextInstAddr());
+
+        ctc->activate();
+
+        // Should return nonzero child TID in parent's syscall return register,
+        // but for our pthread library any non-zero value will work
+        return 1;
+    } else {
+        fatal("Called sys_clone, but no unallocated thread contexts found!\n");
+        return 0;
+    }
+}
+