summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/arch/alpha/linux/process.cc4
-rw-r--r--src/arch/arm/freebsd/process.cc4
-rw-r--r--src/arch/arm/linux/process.cc8
-rw-r--r--src/arch/mips/linux/process.cc4
-rw-r--r--src/arch/power/linux/process.cc4
-rw-r--r--src/arch/riscv/linux/process.cc4
-rw-r--r--src/arch/sparc/linux/syscalls.cc8
-rw-r--r--src/arch/sparc/solaris/process.cc4
-rw-r--r--src/arch/x86/linux/process.cc22
-rw-r--r--src/kern/linux/linux.hh17
-rw-r--r--src/sim/fd_entry.hh1
-rw-r--r--src/sim/syscall_emul.cc47
-rw-r--r--src/sim/syscall_emul.hh482
13 files changed, 521 insertions, 88 deletions
diff --git a/src/arch/alpha/linux/process.cc b/src/arch/alpha/linux/process.cc
index dbfbcaf6a..c1162bad0 100644
--- a/src/arch/alpha/linux/process.cc
+++ b/src/arch/alpha/linux/process.cc
@@ -128,8 +128,8 @@ SyscallDesc AlphaLinuxProcess::syscallDescs[] = {
/* 0 */ SyscallDesc("osf_syscall", unimplementedFunc),
/* 1 */ SyscallDesc("exit", exitFunc),
/* 2 */ SyscallDesc("fork", unimplementedFunc),
- /* 3 */ SyscallDesc("read", readFunc),
- /* 4 */ SyscallDesc("write", writeFunc),
+ /* 3 */ SyscallDesc("read", readFunc<AlphaLinux>),
+ /* 4 */ SyscallDesc("write", writeFunc<AlphaLinux>),
/* 5 */ SyscallDesc("osf_old_open", unimplementedFunc),
/* 6 */ SyscallDesc("close", closeFunc),
/* 7 */ SyscallDesc("osf_wait4", unimplementedFunc),
diff --git a/src/arch/arm/freebsd/process.cc b/src/arch/arm/freebsd/process.cc
index 1ecbdd678..e6aa74068 100644
--- a/src/arch/arm/freebsd/process.cc
+++ b/src/arch/arm/freebsd/process.cc
@@ -659,8 +659,8 @@ static SyscallDesc syscallDescs64[] = {
/* 0 */ SyscallDesc("unused#000", unimplementedFunc),
/* 1 */ SyscallDesc("exit", exitFunc),
/* 2 */ SyscallDesc("unused#002", unimplementedFunc),
- /* 3 */ SyscallDesc("read", readFunc),
- /* 4 */ SyscallDesc("write", writeFunc),
+ /* 3 */ SyscallDesc("read", readFunc<ArmFreebsd64>),
+ /* 4 */ SyscallDesc("write", writeFunc<ArmFreebsd64>),
/* 5 */ SyscallDesc("unused#005", unimplementedFunc),
/* 6 */ SyscallDesc("unused#006", unimplementedFunc),
/* 7 */ SyscallDesc("unused#007", unimplementedFunc),
diff --git a/src/arch/arm/linux/process.cc b/src/arch/arm/linux/process.cc
index 61caa456b..a7ec70e25 100644
--- a/src/arch/arm/linux/process.cc
+++ b/src/arch/arm/linux/process.cc
@@ -126,8 +126,8 @@ static SyscallDesc syscallDescs32[] = {
/* 0 */ SyscallDesc("syscall", unimplementedFunc),
/* 1 */ SyscallDesc("exit", exitFunc),
/* 2 */ SyscallDesc("fork", unimplementedFunc),
- /* 3 */ SyscallDesc("read", readFunc),
- /* 4 */ SyscallDesc("write", writeFunc),
+ /* 3 */ SyscallDesc("read", readFunc<ArmLinux32>),
+ /* 4 */ SyscallDesc("write", writeFunc<ArmLinux32>),
/* 5 */ SyscallDesc("open", openFunc<ArmLinux32>),
/* 6 */ SyscallDesc("close", closeFunc),
/* 7 */ SyscallDesc("unused#7", unimplementedFunc),
@@ -567,8 +567,8 @@ static SyscallDesc syscallDescs64[] = {
/* 61 */ SyscallDesc("getdents64", unimplementedFunc),
#endif
/* 62 */ SyscallDesc("llseek", lseekFunc),
- /* 63 */ SyscallDesc("read", readFunc),
- /* 64 */ SyscallDesc("write", writeFunc),
+ /* 63 */ SyscallDesc("read", readFunc<ArmLinux64>),
+ /* 64 */ SyscallDesc("write", writeFunc<ArmLinux64>),
/* 65 */ SyscallDesc("readv", unimplementedFunc),
/* 66 */ SyscallDesc("writev", writevFunc<ArmLinux64>),
/* 67 */ SyscallDesc("pread64", unimplementedFunc),
diff --git a/src/arch/mips/linux/process.cc b/src/arch/mips/linux/process.cc
index b36a26fbf..b1c09a5f1 100644
--- a/src/arch/mips/linux/process.cc
+++ b/src/arch/mips/linux/process.cc
@@ -141,8 +141,8 @@ SyscallDesc MipsLinuxProcess::syscallDescs[] = {
/* 0 */ SyscallDesc("syscall", unimplementedFunc),
/* 1 */ SyscallDesc("exit", exitFunc),
/* 2 */ SyscallDesc("fork", unimplementedFunc),
- /* 3 */ SyscallDesc("read", readFunc),
- /* 4 */ SyscallDesc("write", writeFunc),
+ /* 3 */ SyscallDesc("read", readFunc<MipsLinux>),
+ /* 4 */ SyscallDesc("write", writeFunc<MipsLinux>),
/* 5 */ SyscallDesc("open", openFunc<MipsLinux>),
/* 6 */ SyscallDesc("close", closeFunc),
/* 7 */ SyscallDesc("waitpid", unimplementedFunc),
diff --git a/src/arch/power/linux/process.cc b/src/arch/power/linux/process.cc
index 801274969..f219852f8 100644
--- a/src/arch/power/linux/process.cc
+++ b/src/arch/power/linux/process.cc
@@ -69,8 +69,8 @@ SyscallDesc PowerLinuxProcess::syscallDescs[] = {
/* 0 */ SyscallDesc("syscall", unimplementedFunc),
/* 1 */ SyscallDesc("exit", exitFunc),
/* 2 */ SyscallDesc("fork", unimplementedFunc),
- /* 3 */ SyscallDesc("read", readFunc),
- /* 4 */ SyscallDesc("write", writeFunc),
+ /* 3 */ SyscallDesc("read", readFunc<PowerLinux>),
+ /* 4 */ SyscallDesc("write", writeFunc<PowerLinux>),
/* 5 */ SyscallDesc("open", openFunc<PowerLinux>),
/* 6 */ SyscallDesc("close", closeFunc),
/* 7 */ SyscallDesc("waitpid", unimplementedFunc), //???
diff --git a/src/arch/riscv/linux/process.cc b/src/arch/riscv/linux/process.cc
index 0f540af9d..6806079a3 100644
--- a/src/arch/riscv/linux/process.cc
+++ b/src/arch/riscv/linux/process.cc
@@ -133,8 +133,8 @@ std::map<int, SyscallDesc> RiscvLinuxProcess::syscallDescs = {
{60, SyscallDesc("quotactl")},
{61, SyscallDesc("getdents64")},
{62, SyscallDesc("lseek", lseekFunc)},
- {63, SyscallDesc("read", readFunc)},
- {64, SyscallDesc("write", writeFunc)},
+ {63, SyscallDesc("read", readFunc<RiscvLinux>)},
+ {64, SyscallDesc("write", writeFunc<RiscvLinux>)},
{66, SyscallDesc("writev", writevFunc<RiscvLinux>)},
{67, SyscallDesc("pread64")},
{68, SyscallDesc("pwrite64", pwrite64Func<RiscvLinux>)},
diff --git a/src/arch/sparc/linux/syscalls.cc b/src/arch/sparc/linux/syscalls.cc
index 7fdc922ef..ee8c60c45 100644
--- a/src/arch/sparc/linux/syscalls.cc
+++ b/src/arch/sparc/linux/syscalls.cc
@@ -91,8 +91,8 @@ SyscallDesc SparcLinuxProcess::syscall32Descs[] = {
/* 0 */ SyscallDesc("restart_syscall", unimplementedFunc),
/* 1 */ SyscallDesc("exit", exitFunc), // 32 bit
/* 2 */ SyscallDesc("fork", unimplementedFunc),
- /* 3 */ SyscallDesc("read", readFunc),
- /* 4 */ SyscallDesc("write", writeFunc),
+ /* 3 */ SyscallDesc("read", readFunc<Sparc32Linux>),
+ /* 4 */ SyscallDesc("write", writeFunc<Sparc32Linux>),
/* 5 */ SyscallDesc("open", openFunc<Sparc32Linux>), // 32 bit
/* 6 */ SyscallDesc("close", closeFunc),
/* 7 */ SyscallDesc("wait4", unimplementedFunc), // 32 bit
@@ -397,8 +397,8 @@ SyscallDesc SparcLinuxProcess::syscallDescs[] = {
/* 0 */ SyscallDesc("restart_syscall", unimplementedFunc),
/* 1 */ SyscallDesc("exit", exitFunc),
/* 2 */ SyscallDesc("fork", unimplementedFunc),
- /* 3 */ SyscallDesc("read", readFunc),
- /* 4 */ SyscallDesc("write", writeFunc),
+ /* 3 */ SyscallDesc("read", readFunc<SparcLinux>),
+ /* 4 */ SyscallDesc("write", writeFunc<SparcLinux>),
/* 5 */ SyscallDesc("open", openFunc<SparcLinux>),
/* 6 */ SyscallDesc("close", closeFunc),
/* 7 */ SyscallDesc("wait4", unimplementedFunc),
diff --git a/src/arch/sparc/solaris/process.cc b/src/arch/sparc/solaris/process.cc
index 1afa35398..bcdd08814 100644
--- a/src/arch/sparc/solaris/process.cc
+++ b/src/arch/sparc/solaris/process.cc
@@ -67,8 +67,8 @@ SyscallDesc SparcSolarisProcess::syscallDescs[] = {
/* 0 */ SyscallDesc("syscall", unimplementedFunc),
/* 1 */ SyscallDesc("exit", exitFunc),
/* 2 */ SyscallDesc("fork", unimplementedFunc),
- /* 3 */ SyscallDesc("read", readFunc),
- /* 4 */ SyscallDesc("write", writeFunc),
+ /* 3 */ SyscallDesc("read", readFunc<SparcSolaris>),
+ /* 4 */ SyscallDesc("write", writeFunc<SparcSolaris>),
/* 5 */ SyscallDesc("open", openFunc<SparcSolaris>),
/* 6 */ SyscallDesc("close", closeFunc),
/* 7 */ SyscallDesc("wait", unimplementedFunc),
diff --git a/src/arch/x86/linux/process.cc b/src/arch/x86/linux/process.cc
index 65d0238f4..03a88fc6e 100644
--- a/src/arch/x86/linux/process.cc
+++ b/src/arch/x86/linux/process.cc
@@ -222,14 +222,14 @@ setThreadArea32Func(SyscallDesc *desc, int callnum,
}
static SyscallDesc syscallDescs64[] = {
- /* 0 */ SyscallDesc("read", readFunc),
- /* 1 */ SyscallDesc("write", writeFunc),
+ /* 0 */ SyscallDesc("read", readFunc<X86Linux64>),
+ /* 1 */ SyscallDesc("write", writeFunc<X86Linux64>),
/* 2 */ SyscallDesc("open", openFunc<X86Linux64>),
/* 3 */ SyscallDesc("close", closeFunc),
/* 4 */ SyscallDesc("stat", stat64Func<X86Linux64>),
/* 5 */ SyscallDesc("fstat", fstat64Func<X86Linux64>),
/* 6 */ SyscallDesc("lstat", lstat64Func<X86Linux64>),
- /* 7 */ SyscallDesc("poll", unimplementedFunc),
+ /* 7 */ SyscallDesc("poll", pollFunc<X86Linux64>),
/* 8 */ SyscallDesc("lseek", lseekFunc),
/* 9 */ SyscallDesc("mmap", mmapFunc<X86Linux64>),
/* 10 */ SyscallDesc("mprotect", ignoreFunc),
@@ -245,7 +245,7 @@ static SyscallDesc syscallDescs64[] = {
/* 20 */ SyscallDesc("writev", writevFunc<X86Linux64>),
/* 21 */ SyscallDesc("access", ignoreFunc),
/* 22 */ SyscallDesc("pipe", pipeFunc),
- /* 23 */ SyscallDesc("select", unimplementedFunc),
+ /* 23 */ SyscallDesc("select", selectFunc<X86Linux64>),
/* 24 */ SyscallDesc("sched_yield", ignoreFunc),
/* 25 */ SyscallDesc("mremap", mremapFunc<X86Linux64>),
/* 26 */ SyscallDesc("msync", unimplementedFunc),
@@ -265,7 +265,7 @@ static SyscallDesc syscallDescs64[] = {
/* 40 */ SyscallDesc("sendfile", unimplementedFunc),
/* 41 */ SyscallDesc("socket", socketFunc<X86Linux64>),
/* 42 */ SyscallDesc("connect", connectFunc),
- /* 43 */ SyscallDesc("accept", unimplementedFunc),
+ /* 43 */ SyscallDesc("accept", acceptFunc<X86Linux64>),
/* 44 */ SyscallDesc("sendto", sendtoFunc),
/* 45 */ SyscallDesc("recvfrom", recvfromFunc),
/* 46 */ SyscallDesc("sendmsg", sendmsgFunc),
@@ -283,7 +283,7 @@ static SyscallDesc syscallDescs64[] = {
/* 58 */ SyscallDesc("vfork", unimplementedFunc),
/* 59 */ SyscallDesc("execve", execveFunc<X86Linux64>),
/* 60 */ SyscallDesc("exit", exitFunc),
- /* 61 */ SyscallDesc("wait4", unimplementedFunc),
+ /* 61 */ SyscallDesc("wait4", wait4Func<X86Linux64>),
/* 62 */ SyscallDesc("kill", unimplementedFunc),
/* 63 */ SyscallDesc("uname", unameFunc),
/* 64 */ SyscallDesc("semget", unimplementedFunc),
@@ -558,8 +558,8 @@ static SyscallDesc syscallDescs32[] = {
/* 0 */ SyscallDesc("restart_syscall", unimplementedFunc),
/* 1 */ SyscallDesc("exit", exitFunc),
/* 2 */ SyscallDesc("fork", unimplementedFunc),
- /* 3 */ SyscallDesc("read", readFunc),
- /* 4 */ SyscallDesc("write", writeFunc),
+ /* 3 */ SyscallDesc("read", readFunc<X86Linux32>),
+ /* 4 */ SyscallDesc("write", writeFunc<X86Linux32>),
/* 5 */ SyscallDesc("open", openFunc<X86Linux32>),
/* 6 */ SyscallDesc("close", closeFunc),
/* 7 */ SyscallDesc("waitpid", unimplementedFunc),
@@ -637,7 +637,7 @@ static SyscallDesc syscallDescs32[] = {
/* 79 */ SyscallDesc("settimeofday", unimplementedFunc),
/* 80 */ SyscallDesc("getgroups", unimplementedFunc),
/* 81 */ SyscallDesc("setgroups", unimplementedFunc),
- /* 82 */ SyscallDesc("select", unimplementedFunc),
+ /* 82 */ SyscallDesc("select", selectFunc<X86Linux32>),
/* 83 */ SyscallDesc("symlink", unimplementedFunc),
/* 84 */ SyscallDesc("oldlstat", unimplementedFunc),
/* 85 */ SyscallDesc("readlink", readlinkFunc),
@@ -669,7 +669,7 @@ static SyscallDesc syscallDescs32[] = {
/* 111 */ SyscallDesc("vhangup", unimplementedFunc),
/* 112 */ SyscallDesc("idle", unimplementedFunc),
/* 113 */ SyscallDesc("vm86old", unimplementedFunc),
- /* 114 */ SyscallDesc("wait4", unimplementedFunc),
+ /* 114 */ SyscallDesc("wait4", wait4Func<X86Linux32>),
/* 115 */ SyscallDesc("swapoff", unimplementedFunc),
/* 116 */ SyscallDesc("sysinfo", sysinfoFunc<X86Linux32>),
/* 117 */ SyscallDesc("ipc", unimplementedFunc),
@@ -727,7 +727,7 @@ static SyscallDesc syscallDescs32[] = {
/* 165 */ SyscallDesc("getresuid", unimplementedFunc),
/* 166 */ SyscallDesc("vm86", unimplementedFunc),
/* 167 */ SyscallDesc("query_module", unimplementedFunc),
- /* 168 */ SyscallDesc("poll", unimplementedFunc),
+ /* 168 */ SyscallDesc("poll", pollFunc<X86Linux32>),
/* 169 */ SyscallDesc("nfsservctl", unimplementedFunc),
/* 170 */ SyscallDesc("setresgid", unimplementedFunc),
/* 171 */ SyscallDesc("getresgid", unimplementedFunc),
diff --git a/src/kern/linux/linux.hh b/src/kern/linux/linux.hh
index a1df99467..e559e0505 100644
--- a/src/kern/linux/linux.hh
+++ b/src/kern/linux/linux.hh
@@ -153,6 +153,15 @@ class Linux : public OperatingSystem
uint64_t iov_len;
};
+ // For select().
+ // linux-3.14-src/include/uapi/linux/posix_types.h
+ struct fd_set{
+#ifndef LINUX__FD_SETSIZE
+#define LINUX__FD_SETSIZE 1024
+ unsigned long fds_bits[LINUX__FD_SETSIZE / (8 * sizeof(long))];
+#endif
+ };
+
//@{
/// ioctl() command codes.
static const unsigned TGT_TCGETS = 0x5401;
@@ -265,6 +274,14 @@ class Linux : public OperatingSystem
static const unsigned TGT_CLONE_NEWPID = 0x20000000;
static const unsigned TGT_CLONE_NEWNET = 0x40000000;
static const unsigned TGT_CLONE_IO = 0x80000000;
+
+ // linux-3.13-src/include/uapi/linux/wait.h
+ static const unsigned TGT_WNOHANG = 0x00000001;
+ static const unsigned TGT_WUNTRACED = 0x00000002;
+ static const unsigned TGT_WSTOPPED = TGT_WUNTRACED;
+ static const unsigned TGT_WEXITED = 0x00000004;
+ static const unsigned TGT_WCONTINUED = 0x00000008;
+ static const unsigned TGT_WNOWAIT = 0x01000000;
}; // class Linux
#endif // __LINUX_HH__
diff --git a/src/sim/fd_entry.hh b/src/sim/fd_entry.hh
index 6b2b2daa8..15e174ae6 100644
--- a/src/sim/fd_entry.hh
+++ b/src/sim/fd_entry.hh
@@ -231,7 +231,6 @@ class SocketFDEntry: public HBFDEntry
return std::make_shared<SocketFDEntry>(*this);
}
- private:
int _domain;
int _type;
int _protocol;
diff --git a/src/sim/syscall_emul.cc b/src/sim/syscall_emul.cc
index 89f70a1cb..74ca1e924 100644
--- a/src/sim/syscall_emul.cc
+++ b/src/sim/syscall_emul.cc
@@ -279,53 +279,6 @@ closeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
return p->fds->closeFDEntry(tgt_fd);
}
-
-SyscallReturn
-readFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
-{
- int index = 0;
- int tgt_fd = p->getSyscallArg(tc, index);
- Addr buf_ptr = p->getSyscallArg(tc, index);
- int nbytes = p->getSyscallArg(tc, index);
-
- auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
- if (!hbfdp)
- return -EBADF;
- int sim_fd = hbfdp->getSimFD();
-
- BufferArg bufArg(buf_ptr, nbytes);
- int bytes_read = read(sim_fd, bufArg.bufferPtr(), nbytes);
-
- if (bytes_read > 0)
- bufArg.copyOut(tc->getMemProxy());
-
- return bytes_read;
-}
-
-SyscallReturn
-writeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
-{
- int index = 0;
- int tgt_fd = p->getSyscallArg(tc, index);
- Addr buf_ptr = p->getSyscallArg(tc, index);
- int nbytes = p->getSyscallArg(tc, index);
-
- auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
- if (!hbfdp)
- return -EBADF;
- int sim_fd = hbfdp->getSimFD();
-
- BufferArg bufArg(buf_ptr, nbytes);
- bufArg.copyIn(tc->getMemProxy());
-
- int bytes_written = write(sim_fd, bufArg.bufferPtr(), nbytes);
-
- fsync(sim_fd);
-
- return bytes_written;
-}
-
-
SyscallReturn
lseekFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
{
diff --git a/src/sim/syscall_emul.hh b/src/sim/syscall_emul.hh
index d882cf4fa..67fa9e3d3 100644
--- a/src/sim/syscall_emul.hh
+++ b/src/sim/syscall_emul.hh
@@ -78,6 +78,7 @@
#endif
#include <fcntl.h>
+#include <poll.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/stat.h>
@@ -87,6 +88,7 @@
#include <sys/mount.h>
#endif
#include <sys/time.h>
+#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
@@ -162,14 +164,6 @@ SyscallReturn brkFunc(SyscallDesc *desc, int num,
SyscallReturn closeFunc(SyscallDesc *desc, int num,
Process *p, ThreadContext *tc);
-// Target read() handler.
-SyscallReturn readFunc(SyscallDesc *desc, int num,
- Process *p, ThreadContext *tc);
-
-/// Target write() handler.
-SyscallReturn writeFunc(SyscallDesc *desc, int num,
- Process *p, ThreadContext *tc);
-
/// Target lseek() handler.
SyscallReturn lseekFunc(SyscallDesc *desc, int num,
Process *p, ThreadContext *tc);
@@ -946,6 +940,80 @@ chmodFunc(SyscallDesc *desc, int callnum, Process *process,
return 0;
}
+template <class OS>
+SyscallReturn
+pollFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
+{
+ int index = 0;
+ Addr fdsPtr = p->getSyscallArg(tc, index);
+ int nfds = p->getSyscallArg(tc, index);
+ int tmout = p->getSyscallArg(tc, index);
+
+ BufferArg fdsBuf(fdsPtr, sizeof(struct pollfd) * nfds);
+ fdsBuf.copyIn(tc->getMemProxy());
+
+ /**
+ * Record the target file descriptors in a local variable. We need to
+ * replace them with host file descriptors but we need a temporary copy
+ * for later. Afterwards, replace each target file descriptor in the
+ * poll_fd array with its host_fd.
+ */
+ int temp_tgt_fds[nfds];
+ for (index = 0; index < nfds; index++) {
+ temp_tgt_fds[index] = ((struct pollfd *)fdsBuf.bufferPtr())[index].fd;
+ auto tgt_fd = temp_tgt_fds[index];
+ auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
+ if (!hbfdp)
+ return -EBADF;
+ auto host_fd = hbfdp->getSimFD();
+ ((struct pollfd *)fdsBuf.bufferPtr())[index].fd = host_fd;
+ }
+
+ /**
+ * We cannot allow an infinite poll to occur or it will inevitably cause
+ * a deadlock in the gem5 simulator with clone. We must pass in tmout with
+ * a non-negative value, however it also makes no sense to poll on the
+ * underlying host for any other time than tmout a zero timeout.
+ */
+ int status;
+ if (tmout < 0) {
+ status = poll((struct pollfd *)fdsBuf.bufferPtr(), nfds, 0);
+ if (status == 0) {
+ /**
+ * If blocking indefinitely, check the signal list to see if a
+ * signal would break the poll out of the retry cycle and try
+ * to return the signal interrupt instead.
+ */
+ System *sysh = tc->getSystemPtr();
+ std::list<BasicSignal>::iterator it;
+ for (it=sysh->signalList.begin(); it!=sysh->signalList.end(); it++)
+ if (it->receiver == p)
+ return -EINTR;
+ return SyscallReturn::retry();
+ }
+ } else
+ status = poll((struct pollfd *)fdsBuf.bufferPtr(), nfds, 0);
+
+ if (status == -1)
+ return -errno;
+
+ /**
+ * Replace each host_fd in the returned poll_fd array with its original
+ * target file descriptor.
+ */
+ for (index = 0; index < nfds; index++) {
+ auto tgt_fd = temp_tgt_fds[index];
+ ((struct pollfd *)fdsBuf.bufferPtr())[index].fd = tgt_fd;
+ }
+
+ /**
+ * Copy out the pollfd struct because the host may have updated fields
+ * in the structure.
+ */
+ fdsBuf.copyOut(tc->getMemProxy());
+
+ return status;
+}
/// Target fchmod() handler.
template <class OS>
@@ -1269,7 +1337,6 @@ fstatFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
return 0;
}
-
/// Target statfs() handler.
template <class OS>
SyscallReturn
@@ -2158,4 +2225,401 @@ socketpairFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
return status;
}
+template <class OS>
+SyscallReturn
+selectFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
+{
+ int retval;
+
+ int index = 0;
+ int nfds_t = p->getSyscallArg(tc, index);
+ Addr fds_read_ptr = p->getSyscallArg(tc, index);
+ Addr fds_writ_ptr = p->getSyscallArg(tc, index);
+ Addr fds_excp_ptr = p->getSyscallArg(tc, index);
+ Addr time_val_ptr = p->getSyscallArg(tc, index);
+
+ TypedBufferArg<typename OS::fd_set> rd_t(fds_read_ptr);
+ TypedBufferArg<typename OS::fd_set> wr_t(fds_writ_ptr);
+ TypedBufferArg<typename OS::fd_set> ex_t(fds_excp_ptr);
+ TypedBufferArg<typename OS::timeval> tp(time_val_ptr);
+
+ /**
+ * Host fields. Notice that these use the definitions from the system
+ * headers instead of the gem5 headers and libraries. If the host and
+ * target have different header file definitions, this will not work.
+ */
+ fd_set rd_h;
+ FD_ZERO(&rd_h);
+ fd_set wr_h;
+ FD_ZERO(&wr_h);
+ fd_set ex_h;
+ FD_ZERO(&ex_h);
+
+ /**
+ * Copy in the fd_set from the target.
+ */
+ if (fds_read_ptr)
+ rd_t.copyIn(tc->getMemProxy());
+ if (fds_writ_ptr)
+ wr_t.copyIn(tc->getMemProxy());
+ if (fds_excp_ptr)
+ ex_t.copyIn(tc->getMemProxy());
+
+ /**
+ * We need to translate the target file descriptor set into a host file
+ * descriptor set. This involves both our internal process fd array
+ * and the fd_set defined in Linux header files. The nfds field also
+ * needs to be updated as it will be only target specific after
+ * retrieving it from the target; the nfds value is expected to be the
+ * highest file descriptor that needs to be checked, so we need to extend
+ * it out for nfds_h when we do the update.
+ */
+ int nfds_h = 0;
+ std::map<int, int> trans_map;
+ auto try_add_host_set = [&](fd_set *tgt_set_entry,
+ fd_set *hst_set_entry,
+ int iter) -> bool
+ {
+ /**
+ * By this point, we know that we are looking at a valid file
+ * descriptor set on the target. We need to check if the target file
+ * descriptor value passed in as iter is part of the set.
+ */
+ if (FD_ISSET(iter, tgt_set_entry)) {
+ /**
+ * We know that the target file descriptor belongs to the set,
+ * but we do not yet know if the file descriptor is valid or
+ * that we have a host mapping. Check that now.
+ */
+ auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[iter]);
+ if (!hbfdp)
+ return true;
+ auto sim_fd = hbfdp->getSimFD();
+
+ /**
+ * Add the sim_fd to tgt_fd translation into trans_map for use
+ * later when we need to zero the target fd_set structures and
+ * then update them with hits returned from the host select call.
+ */
+ trans_map[sim_fd] = iter;
+
+ /**
+ * We know that the host file descriptor exists so now we check
+ * if we need to update the max count for nfds_h before passing
+ * the duplicated structure into the host.
+ */
+ nfds_h = std::max(nfds_h - 1, sim_fd + 1);
+
+ /**
+ * Add the host file descriptor to the set that we are going to
+ * pass into the host.
+ */
+ FD_SET(sim_fd, hst_set_entry);
+ }
+ return false;
+ };
+
+ for (int i = 0; i < nfds_t; i++) {
+ if (fds_read_ptr) {
+ bool ebadf = try_add_host_set((fd_set*)&*rd_t, &rd_h, i);
+ if (ebadf) return -EBADF;
+ }
+ if (fds_writ_ptr) {
+ bool ebadf = try_add_host_set((fd_set*)&*wr_t, &wr_h, i);
+ if (ebadf) return -EBADF;
+ }
+ if (fds_excp_ptr) {
+ bool ebadf = try_add_host_set((fd_set*)&*ex_t, &ex_h, i);
+ if (ebadf) return -EBADF;
+ }
+ }
+
+ if (time_val_ptr) {
+ /**
+ * It might be possible to decrement the timeval based on some
+ * derivation of wall clock determined from elapsed simulator ticks
+ * but that seems like overkill. Rather, we just set the timeval with
+ * zero timeout. (There is no reason to block during the simulation
+ * as it only decreases simulator performance.)
+ */
+ tp->tv_sec = 0;
+ tp->tv_usec = 0;
+
+ retval = select(nfds_h,
+ fds_read_ptr ? &rd_h : nullptr,
+ fds_writ_ptr ? &wr_h : nullptr,
+ fds_excp_ptr ? &ex_h : nullptr,
+ (timeval*)&*tp);
+ } else {
+ /**
+ * If the timeval pointer is null, setup a new timeval structure to
+ * pass into the host select call. Unfortunately, we will need to
+ * manually check the return value and throw a retry fault if the
+ * return value is zero. Allowing the system call to block will
+ * likely deadlock the event queue.
+ */
+ struct timeval tv = { 0, 0 };
+
+ retval = select(nfds_h,
+ fds_read_ptr ? &rd_h : nullptr,
+ fds_writ_ptr ? &wr_h : nullptr,
+ fds_excp_ptr ? &ex_h : nullptr,
+ &tv);
+
+ if (retval == 0) {
+ /**
+ * If blocking indefinitely, check the signal list to see if a
+ * signal would break the poll out of the retry cycle and try to
+ * return the signal interrupt instead.
+ */
+ for (auto sig : tc->getSystemPtr()->signalList)
+ if (sig.receiver == p)
+ return -EINTR;
+ return SyscallReturn::retry();
+ }
+ }
+
+ if (retval == -1)
+ return -errno;
+
+ FD_ZERO((fd_set*)&*rd_t);
+ FD_ZERO((fd_set*)&*wr_t);
+ FD_ZERO((fd_set*)&*ex_t);
+
+ /**
+ * We need to translate the host file descriptor set into a target file
+ * descriptor set. This involves both our internal process fd array
+ * and the fd_set defined in header files.
+ */
+ for (int i = 0; i < nfds_h; i++) {
+ if (fds_read_ptr) {
+ if (FD_ISSET(i, &rd_h))
+ FD_SET(trans_map[i], (fd_set*)&*rd_t);
+ }
+
+ if (fds_writ_ptr) {
+ if (FD_ISSET(i, &wr_h))
+ FD_SET(trans_map[i], (fd_set*)&*wr_t);
+ }
+
+ if (fds_excp_ptr) {
+ if (FD_ISSET(i, &ex_h))
+ FD_SET(trans_map[i], (fd_set*)&*ex_t);
+ }
+ }
+
+ if (fds_read_ptr)
+ rd_t.copyOut(tc->getMemProxy());
+ if (fds_writ_ptr)
+ wr_t.copyOut(tc->getMemProxy());
+ if (fds_excp_ptr)
+ ex_t.copyOut(tc->getMemProxy());
+ if (time_val_ptr)
+ tp.copyOut(tc->getMemProxy());
+
+ return retval;
+}
+
+template <class OS>
+SyscallReturn
+readFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
+{
+ int index = 0;
+ int tgt_fd = p->getSyscallArg(tc, index);
+ Addr buf_ptr = p->getSyscallArg(tc, index);
+ int nbytes = p->getSyscallArg(tc, index);
+
+ auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
+ if (!hbfdp)
+ return -EBADF;
+ int sim_fd = hbfdp->getSimFD();
+
+ struct pollfd pfd;
+ pfd.fd = sim_fd;
+ pfd.events = POLLIN | POLLPRI;
+ if ((poll(&pfd, 1, 0) == 0)
+ && !(hbfdp->getFlags() & OS::TGT_O_NONBLOCK))
+ return SyscallReturn::retry();
+
+ BufferArg buf_arg(buf_ptr, nbytes);
+ int bytes_read = read(sim_fd, buf_arg.bufferPtr(), nbytes);
+
+ if (bytes_read > 0)
+ buf_arg.copyOut(tc->getMemProxy());
+
+ return (bytes_read == -1) ? -errno : bytes_read;
+}
+
+template <class OS>
+SyscallReturn
+writeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
+{
+ int index = 0;
+ int tgt_fd = p->getSyscallArg(tc, index);
+ Addr buf_ptr = p->getSyscallArg(tc, index);
+ int nbytes = p->getSyscallArg(tc, index);
+
+ auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]);
+ if (!hbfdp)
+ return -EBADF;
+ int sim_fd = hbfdp->getSimFD();
+
+ BufferArg buf_arg(buf_ptr, nbytes);
+ buf_arg.copyIn(tc->getMemProxy());
+
+ struct pollfd pfd;
+ pfd.fd = sim_fd;
+ pfd.events = POLLOUT;
+
+ /**
+ * We don't want to poll on /dev/random. The kernel will not enable the
+ * file descriptor for writing unless the entropy in the system falls
+ * below write_wakeup_threshold. This is not guaranteed to happen
+ * depending on host settings.
+ */
+ auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(hbfdp);
+ if (ffdp && (ffdp->getFileName() != "/dev/random")) {
+ if (!poll(&pfd, 1, 0) && !(ffdp->getFlags() & OS::TGT_O_NONBLOCK))
+ return SyscallReturn::retry();
+ }
+
+ int bytes_written = write(sim_fd, buf_arg.bufferPtr(), nbytes);
+
+ if (bytes_written != -1)
+ fsync(sim_fd);
+
+ return (bytes_written == -1) ? -errno : bytes_written;
+}
+
+template <class OS>
+SyscallReturn
+wait4Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
+{
+ int index = 0;
+ pid_t pid = p->getSyscallArg(tc, index);
+ Addr statPtr = p->getSyscallArg(tc, index);
+ int options = p->getSyscallArg(tc, index);
+ Addr rusagePtr = p->getSyscallArg(tc, index);
+
+ if (rusagePtr)
+ DPRINTFR(SyscallVerbose,
+ "%d: %s: syscall wait4: rusage pointer provided however "
+ "functionality not supported. Ignoring rusage pointer.\n",
+ curTick(), tc->getCpuPtr()->name());
+
+ /**
+ * Currently, wait4 is only implemented so that it will wait for children
+ * exit conditions which are denoted by a SIGCHLD signals posted into the
+ * system signal list. We return no additional information via any of the
+ * parameters supplied to wait4. If nothing is found in the system signal
+ * list, we will wait indefinitely for SIGCHLD to post by retrying the
+ * call.
+ */
+ System *sysh = tc->getSystemPtr();
+ std::list<BasicSignal>::iterator iter;
+ for (iter=sysh->signalList.begin(); iter!=sysh->signalList.end(); iter++) {
+ if (iter->receiver == p) {
+ if (pid < -1) {
+ if ((iter->sender->pgid() == -pid)
+ && (iter->signalValue == OS::TGT_SIGCHLD))
+ goto success;
+ } else if (pid == -1) {
+ if (iter->signalValue == OS::TGT_SIGCHLD)
+ goto success;
+ } else if (pid == 0) {
+ if ((iter->sender->pgid() == p->pgid())
+ && (iter->signalValue == OS::TGT_SIGCHLD))
+ goto success;
+ } else {
+ if ((iter->sender->pid() == pid)
+ && (iter->signalValue == OS::TGT_SIGCHLD))
+ goto success;
+ }
+ }
+ }
+
+ return (options & OS::TGT_WNOHANG) ? 0 : SyscallReturn::retry();
+
+success:
+ // Set status to EXITED for WIFEXITED evaluations.
+ const int EXITED = 0;
+ BufferArg statusBuf(statPtr, sizeof(int));
+ *(int *)statusBuf.bufferPtr() = EXITED;
+ statusBuf.copyOut(tc->getMemProxy());
+
+ // Return the child PID.
+ pid_t retval = iter->sender->pid();
+ sysh->signalList.erase(iter);
+ return retval;
+}
+
+template <class OS>
+SyscallReturn
+acceptFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
+{
+ struct sockaddr sa;
+ socklen_t addrLen;
+ int host_fd;
+ int index = 0;
+ int tgt_fd = p->getSyscallArg(tc, index);
+ Addr addrPtr = p->getSyscallArg(tc, index);
+ Addr lenPtr = p->getSyscallArg(tc, index);
+
+ BufferArg *lenBufPtr = nullptr;
+ BufferArg *addrBufPtr = nullptr;
+
+ auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
+ if (!sfdp)
+ return -EBADF;
+ int sim_fd = sfdp->getSimFD();
+
+ /**
+ * We poll the socket file descriptor first to guarantee that we do not
+ * block on our accept call. The socket can be opened without the
+ * non-blocking flag (it blocks). This will cause deadlocks between
+ * communicating processes.
+ */
+ struct pollfd pfd;
+ pfd.fd = sim_fd;
+ pfd.events = POLLIN | POLLPRI;
+ if ((poll(&pfd, 1, 0) == 0)
+ && !(sfdp->getFlags() & OS::TGT_O_NONBLOCK))
+ return SyscallReturn::retry();
+
+ if (lenPtr) {
+ lenBufPtr = new BufferArg(lenPtr, sizeof(socklen_t));
+ lenBufPtr->copyIn(tc->getMemProxy());
+ memcpy(&addrLen, (socklen_t *)lenBufPtr->bufferPtr(),
+ sizeof(socklen_t));
+ }
+
+ if (addrPtr) {
+ addrBufPtr = new BufferArg(addrPtr, sizeof(struct sockaddr));
+ addrBufPtr->copyIn(tc->getMemProxy());
+ memcpy(&sa, (struct sockaddr *)addrBufPtr->bufferPtr(),
+ sizeof(struct sockaddr));
+ }
+
+ host_fd = accept(sim_fd, &sa, &addrLen);
+
+ if (host_fd == -1)
+ return -errno;
+
+ if (addrPtr) {
+ memcpy(addrBufPtr->bufferPtr(), &sa, sizeof(sa));
+ addrBufPtr->copyOut(tc->getMemProxy());
+ delete(addrBufPtr);
+ }
+
+ if (lenPtr) {
+ *(socklen_t *)lenBufPtr->bufferPtr() = addrLen;
+ lenBufPtr->copyOut(tc->getMemProxy());
+ delete(lenBufPtr);
+ }
+
+ auto afdp = std::make_shared<SocketFDEntry>(host_fd, sfdp->_domain,
+ sfdp->_type, sfdp->_protocol);
+ return p->fds->allocFD(afdp);
+}
+
#endif // __SIM_SYSCALL_EMUL_HH__