util: implements "writefile" gem5 op to export file from guest to host filesystem
[gem5.git] / src / sim / syscall_emul.cc
index 811bdb73a8766018bafaddb5f7fad35484b541b7..dc8a9a5c884a9830cd26cb203c6643e62b7412a5 100644 (file)
 #include <fcntl.h>
 #include <unistd.h>
 
-#include <string>
+#include <cstdio>
 #include <iostream>
+#include <string>
 
-#include "sim/syscall_emul.hh"
+#include "arch/utility.hh"
 #include "base/chunk_generator.hh"
 #include "base/trace.hh"
-#include "cpu/thread_context.hh"
+#include "config/the_isa.hh"
 #include "cpu/base.hh"
+#include "cpu/thread_context.hh"
+#include "debug/SyscallVerbose.hh"
 #include "mem/page_table.hh"
 #include "sim/process.hh"
-#include "sim/system.hh"
-
 #include "sim/sim_exit.hh"
+#include "sim/syscall_emul.hh"
+#include "sim/system.hh"
 
 using namespace std;
 using namespace TheISA;
@@ -52,16 +55,21 @@ using namespace TheISA;
 void
 SyscallDesc::doSyscall(int callnum, LiveProcess *process, ThreadContext *tc)
 {
+#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, 0), process->getSyscallArg(tc, 1),
-             process->getSyscallArg(tc, 2), process->getSyscallArg(tc, 3));
+             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))
         process->setSyscallReturn(tc, retval);
@@ -82,8 +90,21 @@ SyscallReturn
 ignoreFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
            ThreadContext *tc)
 {
+    int index = 0;
     warn("ignoring syscall %s(%d, %d, ...)", desc->name,
-         process->getSyscallArg(tc, 0), process->getSyscallArg(tc, 1));
+         process->getSyscallArg(tc, index), process->getSyscallArg(tc, index));
+
+    return 0;
+}
+
+
+SyscallReturn
+ignoreWarnOnceFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
+           ThreadContext *tc)
+{
+    int index = 0;
+    warn_once("ignoring syscall %s(%d, %d, ...)", desc->name,
+         process->getSyscallArg(tc, index), process->getSyscallArg(tc, index));
 
     return 0;
 }
@@ -95,8 +116,9 @@ exitFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
 {
     if (process->system->numRunningContexts() == 1) {
         // Last running context... exit simulator
+        int index = 0;
         exitSimLoop("target called exit()",
-                    process->getSyscallArg(tc, 0) & 0xff);
+                    process->getSyscallArg(tc, index) & 0xff);
     } else {
         // other running threads... just halt this one
         tc->halt();
@@ -112,8 +134,9 @@ exitGroupFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
 {
     // 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, 0) & 0xff);
+                process->getSyscallArg(tc, index) & 0xff);
 
     return 1;
 }
@@ -130,7 +153,8 @@ SyscallReturn
 brkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
 {
     // change brk addr to first arg
-    Addr new_brk = p->getSyscallArg(tc, 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)
@@ -142,8 +166,25 @@ brkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
         for (ChunkGenerator gen(p->brk_point, new_brk - p->brk_point,
                                 VMPageSize); !gen.done(); gen.next()) {
             if (!p->pTable->translate(gen.addr()))
-                p->pTable->allocate(roundDown(gen.addr(), VMPageSize),
-                                    VMPageSize);
+                p->allocateMem(roundDown(gen.addr(), VMPageSize), VMPageSize);
+
+            // if the address is already there, zero it out
+            else {
+                uint8_t zero  = 0;
+                SETranslatingPortProxy *tp = tc->getMemProxy();
+
+                // 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);
+                }
+            }
         }
     }
 
@@ -156,8 +197,12 @@ brkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
 SyscallReturn
 closeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
 {
-    int target_fd = p->getSyscallArg(tc, 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;
@@ -167,14 +212,16 @@ closeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
 SyscallReturn
 readFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
 {
-    int fd = p->sim_fd(p->getSyscallArg(tc, 0));
-    int nbytes = p->getSyscallArg(tc, 2);
-    BufferArg bufArg(p->getSyscallArg(tc, 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);
 
     if (bytes_read != -1)
-        bufArg.copyOut(tc->getMemPort());
+        bufArg.copyOut(tc->getMemProxy());
 
     return bytes_read;
 }
@@ -182,11 +229,13 @@ readFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
 SyscallReturn
 writeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
 {
-    int fd = p->sim_fd(p->getSyscallArg(tc, 0));
-    int nbytes = p->getSyscallArg(tc, 2);
-    BufferArg bufArg(p->getSyscallArg(tc, 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());
+    bufArg.copyIn(tc->getMemProxy());
 
     int bytes_written = write(fd, bufArg.bufferPtr(), nbytes);
 
@@ -199,9 +248,10 @@ writeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
 SyscallReturn
 lseekFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
 {
-    int fd = p->sim_fd(p->getSyscallArg(tc, 0));
-    uint64_t offs = p->getSyscallArg(tc, 1);
-    int whence = p->getSyscallArg(tc, 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);
 
@@ -212,11 +262,12 @@ lseekFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
 SyscallReturn
 _llseekFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
 {
-    int fd = p->sim_fd(p->getSyscallArg(tc, 0));
-    uint64_t offset_high = p->getSyscallArg(tc, 1);
-    uint32_t offset_low = p->getSyscallArg(tc, 2);
-    Addr result_ptr = p->getSyscallArg(tc, 3);
-    int whence = p->getSyscallArg(tc, 4);
+    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;
 
@@ -233,7 +284,7 @@ _llseekFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
         // target platform
         BufferArg result_buf(result_ptr, sizeof(result));
         memcpy(result_buf.bufferPtr(), &result, sizeof(result));
-        result_buf.copyOut(tc->getMemPort());
+        result_buf.copyOut(tc->getMemProxy());
         return 0;
     }
 
@@ -255,12 +306,14 @@ const char *hostname = "m5.eecs.umich.edu";
 SyscallReturn
 gethostnameFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
 {
-    int name_len = p->getSyscallArg(tc, 1);
-    BufferArg name(p->getSyscallArg(tc, 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);
 
-    name.copyOut(tc->getMemPort());
+    name.copyOut(tc->getMemProxy());
 
     return 0;
 }
@@ -269,8 +322,10 @@ SyscallReturn
 getcwdFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
 {
     int result = 0;
-    unsigned long size = p->getSyscallArg(tc, 1);
-    BufferArg buf(p->getSyscallArg(tc, 0), size);
+    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();
@@ -291,7 +346,7 @@ getcwdFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
         }
     }
 
-    buf.copyOut(tc->getMemPort());
+    buf.copyOut(tc->getMemProxy());
 
     return (result == -1) ? -errno : result;
 }
@@ -302,18 +357,21 @@ readlinkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
 {
     string path;
 
-    if (!tc->getMemPort()->tryReadString(path, p->getSyscallArg(tc, 0)))
+    int index = 0;
+    if (!tc->getMemProxy()->tryReadString(path, p->getSyscallArg(tc, index)))
         return (TheISA::IntReg)-EFAULT;
 
     // Adjust path for current working directory
     path = p->fullPath(path);
 
-    size_t bufsiz = p->getSyscallArg(tc, 2);
-    BufferArg buf(p->getSyscallArg(tc, 1), bufsiz);
+    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());
+    buf.copyOut(tc->getMemProxy());
 
     return (result == -1) ? -errno : result;
 }
@@ -323,7 +381,8 @@ unlinkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
 {
     string path;
 
-    if (!tc->getMemPort()->tryReadString(path, p->getSyscallArg(tc, 0)))
+    int index = 0;
+    if (!tc->getMemProxy()->tryReadString(path, p->getSyscallArg(tc, index)))
         return (TheISA::IntReg)-EFAULT;
 
     // Adjust path for current working directory
@@ -339,13 +398,14 @@ mkdirFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
 {
     string path;
 
-    if (!tc->getMemPort()->tryReadString(path, p->getSyscallArg(tc, 0)))
+    int index = 0;
+    if (!tc->getMemProxy()->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, 1);
+    mode_t mode = p->getSyscallArg(tc, index);
 
     int result = mkdir(path.c_str(), mode);
     return (result == -1) ? -errno : result;
@@ -356,12 +416,13 @@ renameFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
 {
     string old_name;
 
-    if (!tc->getMemPort()->tryReadString(old_name, p->getSyscallArg(tc, 0)))
+    int index = 0;
+    if (!tc->getMemProxy()->tryReadString(old_name, p->getSyscallArg(tc, index)))
         return -EFAULT;
 
     string new_name;
 
-    if (!tc->getMemPort()->tryReadString(new_name, p->getSyscallArg(tc, 1)))
+    if (!tc->getMemProxy()->tryReadString(new_name, p->getSyscallArg(tc, index)))
         return -EFAULT;
 
     // Adjust path for current working directory
@@ -377,10 +438,11 @@ truncateFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
 {
     string path;
 
-    if (!tc->getMemPort()->tryReadString(path, p->getSyscallArg(tc, 0)))
+    int index = 0;
+    if (!tc->getMemProxy()->tryReadString(path, p->getSyscallArg(tc, index)))
         return -EFAULT;
 
-    off_t length = p->getSyscallArg(tc, 1);
+    off_t length = p->getSyscallArg(tc, index);
 
     // Adjust path for current working directory
     path = p->fullPath(path);
@@ -393,17 +455,61 @@ SyscallReturn
 ftruncateFunc(SyscallDesc *desc, int num,
               LiveProcess *process, ThreadContext *tc)
 {
-    int fd = process->sim_fd(process->getSyscallArg(tc, 0));
+    int index = 0;
+    int fd = process->sim_fd(process->getSyscallArg(tc, index));
 
     if (fd < 0)
         return -EBADF;
 
-    off_t length = process->getSyscallArg(tc, 1);
+    off_t length = process->getSyscallArg(tc, index);
 
     int result = ftruncate(fd, length);
     return (result == -1) ? -errno : result;
 }
 
+SyscallReturn
+truncate64Func(SyscallDesc *desc, int num,
+                LiveProcess *process, ThreadContext *tc)
+{
+    int index = 0;
+    string path;
+
+    if (!tc->getMemProxy()->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)
 {
@@ -420,13 +526,14 @@ chownFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
 {
     string path;
 
-    if (!tc->getMemPort()->tryReadString(path, p->getSyscallArg(tc, 0)))
+    int index = 0;
+    if (!tc->getMemProxy()->tryReadString(path, p->getSyscallArg(tc, index)))
         return -EFAULT;
 
     /* XXX endianess */
-    uint32_t owner = p->getSyscallArg(tc, 1);
+    uint32_t owner = p->getSyscallArg(tc, index);
     uid_t hostOwner = owner;
-    uint32_t group = p->getSyscallArg(tc, 2);
+    uint32_t group = p->getSyscallArg(tc, index);
     gid_t hostGroup = group;
 
     // Adjust path for current working directory
@@ -439,15 +546,16 @@ chownFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
 SyscallReturn
 fchownFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc)
 {
-    int fd = process->sim_fd(process->getSyscallArg(tc, 0));
+    int index = 0;
+    int fd = process->sim_fd(process->getSyscallArg(tc, index));
 
     if (fd < 0)
         return -EBADF;
 
     /* XXX endianess */
-    uint32_t owner = process->getSyscallArg(tc, 1);
+    uint32_t owner = process->getSyscallArg(tc, index);
     uid_t hostOwner = owner;
-    uint32_t group = process->getSyscallArg(tc, 2);
+    uint32_t group = process->getSyscallArg(tc, index);
     gid_t hostGroup = group;
 
     int result = fchown(fd, hostOwner, hostGroup);
@@ -458,11 +566,12 @@ fchownFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc)
 SyscallReturn
 dupFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc)
 {
-    int fd = process->sim_fd(process->getSyscallArg(tc, 0));
+    int index = 0;
+    int fd = process->sim_fd(process->getSyscallArg(tc, index));
     if (fd < 0)
         return -EBADF;
 
-    Process::FdMap *fdo = process->sim_fd_obj(process->getSyscallArg(tc, 0));
+    Process::FdMap *fdo = process->sim_fd_obj(fd);
 
     int result = dup(fd);
     return (result == -1) ? -errno :
@@ -474,12 +583,13 @@ SyscallReturn
 fcntlFunc(SyscallDesc *desc, int num, LiveProcess *process,
           ThreadContext *tc)
 {
-    int fd = process->getSyscallArg(tc, 0);
+    int index = 0;
+    int fd = process->getSyscallArg(tc, index);
 
     if (fd < 0 || process->sim_fd(fd) < 0)
         return -EBADF;
 
-    int cmd = process->getSyscallArg(tc, 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
@@ -516,12 +626,13 @@ SyscallReturn
 fcntl64Func(SyscallDesc *desc, int num, LiveProcess *process,
             ThreadContext *tc)
 {
-    int fd = process->getSyscallArg(tc, 0);
+    int index = 0;
+    int fd = process->getSyscallArg(tc, index);
 
     if (fd < 0 || process->sim_fd(fd) < 0)
         return -EBADF;
 
-    int cmd = process->getSyscallArg(tc, 1);
+    int cmd = process->getSyscallArg(tc, index);
     switch (cmd) {
       case 33: //F_GETLK64
         warn("fcntl64(%d, F_GETLK64) not supported, error returned\n", fd);
@@ -605,7 +716,8 @@ 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", process->getSyscallArg(tc, 0));
+    int index = 0;
+    warn("Ignoring call to setuid(%d)\n", process->getSyscallArg(tc, index));
     return 0;
 }
 
@@ -661,17 +773,20 @@ 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", process->getSyscallArg(tc, 0));
-    DPRINTF(SyscallVerbose, " Child stack=%llx\n",
-            process->getSyscallArg(tc, 1));
+    DPRINTF(SyscallVerbose, " Flags=%llx\n", flags);
+    DPRINTF(SyscallVerbose, " Child stack=%llx\n", newStack);
 
 
-    if (process->getSyscallArg(tc, 0) != 0x10f00) {
+    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", process->getSyscallArg(tc, 0));
+             "0x%llx\n", flags);
     }
 
     ThreadContext* ctc; // child thread context
@@ -699,12 +814,14 @@ cloneFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
 
             for (int y = 8; y < 32; y++)
                 ctc->setIntReg(y, tc->readIntReg(y));
+        #elif THE_ISA == ARM_ISA
+            TheISA::copyRegs(tc, ctc);
         #else
             fatal("sys_clone is not implemented for this ISA\n");
         #endif
 
         // Set up stack register
-        ctc->setIntReg(TheISA::StackPointerReg, process->getSyscallArg(tc, 1));
+        ctc->setIntReg(TheISA::StackPointerReg, newStack);
 
         // Set up syscall return values in parent and child
         ctc->setIntReg(ReturnValueReg, 0); // return value, child
@@ -721,9 +838,7 @@ cloneFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
             ctc->setIntReg(TheISA::SyscallPseudoReturnReg, 1);
         #endif
 
-        ctc->setPC(tc->readNextPC());
-        ctc->setNextPC(tc->readNextPC() + sizeof(TheISA::MachInst));
-        ctc->setNextNPC(tc->readNextNPC() + sizeof(TheISA::MachInst));
+        ctc->pcState(tc->nextInstAddr());
 
         ctc->activate();