syscall-emul: Add or extend dup, dup2, and pipe
authorBrandon Potter <Brandon.Potter@amd.com>
Wed, 1 Mar 2017 19:35:02 +0000 (13:35 -0600)
committerBrandon Potter <Brandon.Potter@amd.com>
Thu, 9 Mar 2017 22:42:45 +0000 (22:42 +0000)
This changeset extends the pipe system call to work with
architectures other than Alpha (and enables the syscall for
x86). For the dup system call, it sets the clone-on-exec
flag by default. For the dup2 system call, the changeset
adds an implementation (and enables it for x86).

Change-Id: I00ddb416744ee7dd61a5cd02c4c3d97f30543878
Reviewed-on: https://gem5-review.googlesource.com/2266
Maintainer: Jason Lowe-Power <jason@lowepower.com>
Reviewed-by: Tony Gutierrez <anthony.gutierrez@amd.com>
Reviewed-by: Michael LeBeane <Michael.Lebeane@amd.com>
src/arch/x86/linux/process.cc
src/sim/syscall_emul.cc
src/sim/syscall_emul.hh

index f90022bdd6876c7b3364ac6e6601179610c6a421..aad5151f6ebc7b946a224e9112b4bdffb42f84e7 100644 (file)
@@ -242,7 +242,7 @@ static SyscallDesc syscallDescs64[] = {
     /*  19 */ SyscallDesc("readv", unimplementedFunc),
     /*  20 */ SyscallDesc("writev", writevFunc<X86Linux64>),
     /*  21 */ SyscallDesc("access", ignoreFunc),
-    /*  22 */ SyscallDesc("pipe", unimplementedFunc),
+    /*  22 */ SyscallDesc("pipe", pipeFunc),
     /*  23 */ SyscallDesc("select", unimplementedFunc),
     /*  24 */ SyscallDesc("sched_yield", unimplementedFunc),
     /*  25 */ SyscallDesc("mremap", mremapFunc<X86Linux64>),
@@ -253,7 +253,7 @@ static SyscallDesc syscallDescs64[] = {
     /*  30 */ SyscallDesc("shmat", unimplementedFunc),
     /*  31 */ SyscallDesc("shmctl", unimplementedFunc),
     /*  32 */ SyscallDesc("dup", dupFunc),
-    /*  33 */ SyscallDesc("dup2", unimplementedFunc),
+    /*  33 */ SyscallDesc("dup2", dup2Func),
     /*  34 */ SyscallDesc("pause", unimplementedFunc),
     /*  35 */ SyscallDesc("nanosleep", ignoreFunc, SyscallDesc::WarnOnce),
     /*  36 */ SyscallDesc("getitimer", unimplementedFunc),
@@ -591,7 +591,7 @@ static SyscallDesc syscallDescs32[] = {
     /*  39 */ SyscallDesc("mkdir", unimplementedFunc),
     /*  40 */ SyscallDesc("rmdir", unimplementedFunc),
     /*  41 */ SyscallDesc("dup", dupFunc),
-    /*  42 */ SyscallDesc("pipe", unimplementedFunc),
+    /*  42 */ SyscallDesc("pipe", pipeFunc),
     /*  43 */ SyscallDesc("times", timesFunc<X86Linux32>),
     /*  44 */ SyscallDesc("prof", unimplementedFunc),
     /*  45 */ SyscallDesc("brk", brkFunc),
@@ -612,7 +612,7 @@ static SyscallDesc syscallDescs32[] = {
     /*  60 */ SyscallDesc("umask", unimplementedFunc),
     /*  61 */ SyscallDesc("chroot", unimplementedFunc),
     /*  62 */ SyscallDesc("ustat", unimplementedFunc),
-    /*  63 */ SyscallDesc("dup2", unimplementedFunc),
+    /*  63 */ SyscallDesc("dup2", dup2Func),
     /*  64 */ SyscallDesc("getppid", unimplementedFunc),
     /*  65 */ SyscallDesc("getpgrp", unimplementedFunc),
     /*  66 */ SyscallDesc("setsid", unimplementedFunc),
index 9680193235091e4254dbd5861db637c57b518ef4..1441592a8c4c02550e8142ed4b3f33e847cd9452 100644 (file)
@@ -626,13 +626,11 @@ fchownFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
     return (result == -1) ? -errno : result;
 }
 
-
 /**
- * TODO: there's a bit more involved here since file descriptors created with
- * dup are supposed to share a file description. So, there is a problem with
- * maintaining fields like file offset or flags since an update to such a
- * field won't be reflected in the metadata for the fd entries that we
- * maintain to hold metadata for checkpoint restoration.
+ * FIXME: The file description is not shared among file descriptors created
+ * with dup. Really, it's difficult to maintain fields like file offset or
+ * flags since an update to such a field won't be reflected in the metadata
+ * for the fd entries that we maintain for checkpoint restoration.
  */
 SyscallReturn
 dupFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
@@ -646,13 +644,44 @@ dupFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
     int sim_fd = old_hbfdp->getSimFD();
 
     int result = dup(sim_fd);
-    int local_errno = errno;
+    if (result == -1)
+        return -errno;
 
-    std::shared_ptr<FDEntry> new_fdep = old_hbfdp->clone();
-    auto new_hbfdp = std::dynamic_pointer_cast<HBFDEntry>(new_fdep);
+    auto new_hbfdp = std::dynamic_pointer_cast<HBFDEntry>(old_hbfdp->clone());
     new_hbfdp->setSimFD(result);
+    new_hbfdp->setCOE(false);
+    return p->fds->allocFD(new_hbfdp);
+}
+
+SyscallReturn
+dup2Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
+{
+    int index = 0;
+
+    int old_tgt_fd = p->getSyscallArg(tc, index);
+    auto old_hbp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[old_tgt_fd]);
+    if (!old_hbp)
+        return -EBADF;
+    int old_sim_fd = old_hbp->getSimFD();
 
-    return (result == -1) ? -local_errno : p->fds->allocFD(new_fdep);
+    /**
+     * We need a valid host file descriptor number to be able to pass into
+     * the second parameter for dup2 (newfd), but we don't know what the
+     * viable numbers are; we execute the open call to retrieve one.
+     */
+    int res_fd = dup2(old_sim_fd, open("/dev/null", O_RDONLY));
+    if (res_fd == -1)
+        return -errno;
+
+    int new_tgt_fd = p->getSyscallArg(tc, index);
+    auto new_hbp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[new_tgt_fd]);
+    if (new_hbp)
+        p->fds->closeFDEntry(new_tgt_fd);
+    new_hbp = std::dynamic_pointer_cast<HBFDEntry>(old_hbp->clone());
+    new_hbp->setSimFD(res_fd);
+    new_hbp->setCOE(false);
+
+    return p->fds->allocFD(new_hbp);
 }
 
 SyscallReturn
@@ -731,23 +760,28 @@ fcntl64Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
 }
 
 SyscallReturn
-pipePseudoFunc(SyscallDesc *desc, int callnum, Process *process,
-               ThreadContext *tc)
+pipeImpl(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc,
+         bool pseudoPipe)
 {
+    Addr tgt_addr = 0;
+    if (!pseudoPipe) {
+        int index = 0;
+        tgt_addr = p->getSyscallArg(tc, index);
+    }
+
     int sim_fds[2], tgt_fds[2];
 
     int pipe_retval = pipe(sim_fds);
-    if (pipe_retval < 0)
-        return pipe_retval;
+    if (pipe_retval == -1)
+        return -errno;
 
     auto rend = PipeFDEntry::EndType::read;
     auto rpfd = std::make_shared<PipeFDEntry>(sim_fds[0], O_WRONLY, rend);
+    tgt_fds[0] = p->fds->allocFD(rpfd);
 
     auto wend = PipeFDEntry::EndType::write;
     auto wpfd = std::make_shared<PipeFDEntry>(sim_fds[1], O_RDONLY, wend);
-
-    tgt_fds[0] = process->fds->allocFD(rpfd);
-    tgt_fds[1] = process->fds->allocFD(wpfd);
+    tgt_fds[1] = p->fds->allocFD(wpfd);
 
     /**
      * Now patch the read object to record the target file descriptor chosen
@@ -759,8 +793,34 @@ pipePseudoFunc(SyscallDesc *desc, int callnum, Process *process,
      * 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, tgt_fds[1]);
-    return sim_fds[0];
+    if (pseudoPipe) {
+        tc->setIntReg(SyscallPseudoReturnReg, tgt_fds[1]);
+        return tgt_fds[0];
+    }
+
+    /**
+     * Copy the target file descriptors into buffer space and then copy
+     * the buffer space back into the target address space.
+     */
+    BufferArg tgt_handle(tgt_addr, sizeof(int[2]));
+    int *buf_ptr = (int*)tgt_handle.bufferPtr();
+    buf_ptr[0] = tgt_fds[0];
+    buf_ptr[1] = tgt_fds[1];
+    tgt_handle.copyOut(tc->getMemProxy());
+    return 0;
+}
+
+SyscallReturn
+pipePseudoFunc(SyscallDesc *desc, int callnum, Process *process,
+               ThreadContext *tc)
+{
+    return pipeImpl(desc, callnum, process, tc, true);
+}
+
+SyscallReturn
+pipeFunc(SyscallDesc *desc, int callnum, Process *process, ThreadContext *tc)
+{
+    return pipeImpl(desc, callnum, process, tc, false);
 }
 
 SyscallReturn
index d379bbe85e89c8aa5aa1a87a2ea09cb26571bd4c..d75841cc6d5b9b322d901c5cd3f2137e730566b6 100644 (file)
@@ -241,6 +241,10 @@ SyscallReturn fchownFunc(SyscallDesc *desc, int num,
 SyscallReturn dupFunc(SyscallDesc *desc, int num,
                       Process *process, ThreadContext *tc);
 
+/// Target dup2() handler.
+SyscallReturn dup2Func(SyscallDesc *desc, int num,
+                       Process *process, ThreadContext *tc);
+
 /// Target fcntl() handler.
 SyscallReturn fcntlFunc(SyscallDesc *desc, int num,
                         Process *process, ThreadContext *tc);
@@ -253,6 +257,14 @@ SyscallReturn fcntl64Func(SyscallDesc *desc, int num,
 SyscallReturn setuidFunc(SyscallDesc *desc, int num,
                          Process *p, ThreadContext *tc);
 
+/// Target pipe() handler.
+SyscallReturn pipeFunc(SyscallDesc *desc, int num,
+                       Process *p, ThreadContext *tc);
+
+/// Internal pipe() handler.
+SyscallReturn pipeImpl(SyscallDesc *desc, int num, Process *p,
+                       ThreadContext *tc, bool pseudoPipe);
+
 /// Target getpid() handler.
 SyscallReturn getpidFunc(SyscallDesc *desc, int num,
                          Process *p, ThreadContext *tc);