syscall-emul: Add or extend dup, dup2, and pipe
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>
This commit is contained in:
parent
acce7b0dc0
commit
198c515b97
3 changed files with 95 additions and 23 deletions
|
@ -242,7 +242,7 @@ static SyscallDesc syscallDescs64[] = {
|
||||||
/* 19 */ SyscallDesc("readv", unimplementedFunc),
|
/* 19 */ SyscallDesc("readv", unimplementedFunc),
|
||||||
/* 20 */ SyscallDesc("writev", writevFunc<X86Linux64>),
|
/* 20 */ SyscallDesc("writev", writevFunc<X86Linux64>),
|
||||||
/* 21 */ SyscallDesc("access", ignoreFunc),
|
/* 21 */ SyscallDesc("access", ignoreFunc),
|
||||||
/* 22 */ SyscallDesc("pipe", unimplementedFunc),
|
/* 22 */ SyscallDesc("pipe", pipeFunc),
|
||||||
/* 23 */ SyscallDesc("select", unimplementedFunc),
|
/* 23 */ SyscallDesc("select", unimplementedFunc),
|
||||||
/* 24 */ SyscallDesc("sched_yield", unimplementedFunc),
|
/* 24 */ SyscallDesc("sched_yield", unimplementedFunc),
|
||||||
/* 25 */ SyscallDesc("mremap", mremapFunc<X86Linux64>),
|
/* 25 */ SyscallDesc("mremap", mremapFunc<X86Linux64>),
|
||||||
|
@ -253,7 +253,7 @@ static SyscallDesc syscallDescs64[] = {
|
||||||
/* 30 */ SyscallDesc("shmat", unimplementedFunc),
|
/* 30 */ SyscallDesc("shmat", unimplementedFunc),
|
||||||
/* 31 */ SyscallDesc("shmctl", unimplementedFunc),
|
/* 31 */ SyscallDesc("shmctl", unimplementedFunc),
|
||||||
/* 32 */ SyscallDesc("dup", dupFunc),
|
/* 32 */ SyscallDesc("dup", dupFunc),
|
||||||
/* 33 */ SyscallDesc("dup2", unimplementedFunc),
|
/* 33 */ SyscallDesc("dup2", dup2Func),
|
||||||
/* 34 */ SyscallDesc("pause", unimplementedFunc),
|
/* 34 */ SyscallDesc("pause", unimplementedFunc),
|
||||||
/* 35 */ SyscallDesc("nanosleep", ignoreFunc, SyscallDesc::WarnOnce),
|
/* 35 */ SyscallDesc("nanosleep", ignoreFunc, SyscallDesc::WarnOnce),
|
||||||
/* 36 */ SyscallDesc("getitimer", unimplementedFunc),
|
/* 36 */ SyscallDesc("getitimer", unimplementedFunc),
|
||||||
|
@ -591,7 +591,7 @@ static SyscallDesc syscallDescs32[] = {
|
||||||
/* 39 */ SyscallDesc("mkdir", unimplementedFunc),
|
/* 39 */ SyscallDesc("mkdir", unimplementedFunc),
|
||||||
/* 40 */ SyscallDesc("rmdir", unimplementedFunc),
|
/* 40 */ SyscallDesc("rmdir", unimplementedFunc),
|
||||||
/* 41 */ SyscallDesc("dup", dupFunc),
|
/* 41 */ SyscallDesc("dup", dupFunc),
|
||||||
/* 42 */ SyscallDesc("pipe", unimplementedFunc),
|
/* 42 */ SyscallDesc("pipe", pipeFunc),
|
||||||
/* 43 */ SyscallDesc("times", timesFunc<X86Linux32>),
|
/* 43 */ SyscallDesc("times", timesFunc<X86Linux32>),
|
||||||
/* 44 */ SyscallDesc("prof", unimplementedFunc),
|
/* 44 */ SyscallDesc("prof", unimplementedFunc),
|
||||||
/* 45 */ SyscallDesc("brk", brkFunc),
|
/* 45 */ SyscallDesc("brk", brkFunc),
|
||||||
|
@ -612,7 +612,7 @@ static SyscallDesc syscallDescs32[] = {
|
||||||
/* 60 */ SyscallDesc("umask", unimplementedFunc),
|
/* 60 */ SyscallDesc("umask", unimplementedFunc),
|
||||||
/* 61 */ SyscallDesc("chroot", unimplementedFunc),
|
/* 61 */ SyscallDesc("chroot", unimplementedFunc),
|
||||||
/* 62 */ SyscallDesc("ustat", unimplementedFunc),
|
/* 62 */ SyscallDesc("ustat", unimplementedFunc),
|
||||||
/* 63 */ SyscallDesc("dup2", unimplementedFunc),
|
/* 63 */ SyscallDesc("dup2", dup2Func),
|
||||||
/* 64 */ SyscallDesc("getppid", unimplementedFunc),
|
/* 64 */ SyscallDesc("getppid", unimplementedFunc),
|
||||||
/* 65 */ SyscallDesc("getpgrp", unimplementedFunc),
|
/* 65 */ SyscallDesc("getpgrp", unimplementedFunc),
|
||||||
/* 66 */ SyscallDesc("setsid", unimplementedFunc),
|
/* 66 */ SyscallDesc("setsid", unimplementedFunc),
|
||||||
|
|
|
@ -626,13 +626,11 @@ fchownFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
|
||||||
return (result == -1) ? -errno : result;
|
return (result == -1) ? -errno : result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: there's a bit more involved here since file descriptors created with
|
* FIXME: The file description is not shared among file descriptors created
|
||||||
* dup are supposed to share a file description. So, there is a problem with
|
* with dup. Really, it's difficult to maintain fields like file offset or
|
||||||
* maintaining fields like file offset or flags since an update to such a
|
* flags since an update to such a field won't be reflected in the metadata
|
||||||
* field won't be reflected in the metadata for the fd entries that we
|
* for the fd entries that we maintain for checkpoint restoration.
|
||||||
* maintain to hold metadata for checkpoint restoration.
|
|
||||||
*/
|
*/
|
||||||
SyscallReturn
|
SyscallReturn
|
||||||
dupFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
|
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 sim_fd = old_hbfdp->getSimFD();
|
||||||
|
|
||||||
int result = dup(sim_fd);
|
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>(old_hbfdp->clone());
|
||||||
auto new_hbfdp = std::dynamic_pointer_cast<HBFDEntry>(new_fdep);
|
|
||||||
new_hbfdp->setSimFD(result);
|
new_hbfdp->setSimFD(result);
|
||||||
|
new_hbfdp->setCOE(false);
|
||||||
|
return p->fds->allocFD(new_hbfdp);
|
||||||
|
}
|
||||||
|
|
||||||
return (result == -1) ? -local_errno : p->fds->allocFD(new_fdep);
|
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();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
SyscallReturn
|
||||||
|
@ -731,23 +760,28 @@ fcntl64Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
|
||||||
}
|
}
|
||||||
|
|
||||||
SyscallReturn
|
SyscallReturn
|
||||||
pipePseudoFunc(SyscallDesc *desc, int callnum, Process *process,
|
pipeImpl(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc,
|
||||||
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 sim_fds[2], tgt_fds[2];
|
||||||
|
|
||||||
int pipe_retval = pipe(sim_fds);
|
int pipe_retval = pipe(sim_fds);
|
||||||
if (pipe_retval < 0)
|
if (pipe_retval == -1)
|
||||||
return pipe_retval;
|
return -errno;
|
||||||
|
|
||||||
auto rend = PipeFDEntry::EndType::read;
|
auto rend = PipeFDEntry::EndType::read;
|
||||||
auto rpfd = std::make_shared<PipeFDEntry>(sim_fds[0], O_WRONLY, rend);
|
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 wend = PipeFDEntry::EndType::write;
|
||||||
auto wpfd = std::make_shared<PipeFDEntry>(sim_fds[1], O_RDONLY, wend);
|
auto wpfd = std::make_shared<PipeFDEntry>(sim_fds[1], O_RDONLY, wend);
|
||||||
|
tgt_fds[1] = p->fds->allocFD(wpfd);
|
||||||
tgt_fds[0] = process->fds->allocFD(rpfd);
|
|
||||||
tgt_fds[1] = process->fds->allocFD(wpfd);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Now patch the read object to record the target file descriptor chosen
|
* 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
|
* 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.
|
* the return value of the function, and fd[1] is returned in r20.
|
||||||
*/
|
*/
|
||||||
tc->setIntReg(SyscallPseudoReturnReg, tgt_fds[1]);
|
if (pseudoPipe) {
|
||||||
return sim_fds[0];
|
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
|
SyscallReturn
|
||||||
|
|
|
@ -241,6 +241,10 @@ SyscallReturn fchownFunc(SyscallDesc *desc, int num,
|
||||||
SyscallReturn dupFunc(SyscallDesc *desc, int num,
|
SyscallReturn dupFunc(SyscallDesc *desc, int num,
|
||||||
Process *process, ThreadContext *tc);
|
Process *process, ThreadContext *tc);
|
||||||
|
|
||||||
|
/// Target dup2() handler.
|
||||||
|
SyscallReturn dup2Func(SyscallDesc *desc, int num,
|
||||||
|
Process *process, ThreadContext *tc);
|
||||||
|
|
||||||
/// Target fcntl() handler.
|
/// Target fcntl() handler.
|
||||||
SyscallReturn fcntlFunc(SyscallDesc *desc, int num,
|
SyscallReturn fcntlFunc(SyscallDesc *desc, int num,
|
||||||
Process *process, ThreadContext *tc);
|
Process *process, ThreadContext *tc);
|
||||||
|
@ -253,6 +257,14 @@ SyscallReturn fcntl64Func(SyscallDesc *desc, int num,
|
||||||
SyscallReturn setuidFunc(SyscallDesc *desc, int num,
|
SyscallReturn setuidFunc(SyscallDesc *desc, int num,
|
||||||
Process *p, ThreadContext *tc);
|
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.
|
/// Target getpid() handler.
|
||||||
SyscallReturn getpidFunc(SyscallDesc *desc, int num,
|
SyscallReturn getpidFunc(SyscallDesc *desc, int num,
|
||||||
Process *p, ThreadContext *tc);
|
Process *p, ThreadContext *tc);
|
||||||
|
|
Loading…
Reference in a new issue