diff options
-rw-r--r-- | src/arch/alpha/linux/process.cc | 4 | ||||
-rw-r--r-- | src/arch/arm/freebsd/process.cc | 4 | ||||
-rw-r--r-- | src/arch/arm/linux/process.cc | 8 | ||||
-rw-r--r-- | src/arch/mips/linux/process.cc | 4 | ||||
-rw-r--r-- | src/arch/power/linux/process.cc | 4 | ||||
-rw-r--r-- | src/arch/riscv/linux/process.cc | 4 | ||||
-rw-r--r-- | src/arch/sparc/linux/syscalls.cc | 8 | ||||
-rw-r--r-- | src/arch/sparc/solaris/process.cc | 4 | ||||
-rw-r--r-- | src/arch/x86/linux/process.cc | 22 | ||||
-rw-r--r-- | src/kern/linux/linux.hh | 17 | ||||
-rw-r--r-- | src/sim/fd_entry.hh | 1 | ||||
-rw-r--r-- | src/sim/syscall_emul.cc | 47 | ||||
-rw-r--r-- | src/sim/syscall_emul.hh | 482 |
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__ |