From 454caeab290d4549fc9acf37f6fe726dd45c7c94 Mon Sep 17 00:00:00 2001 From: tom Date: Sun, 13 Oct 2019 20:31:13 -0500 Subject: [PATCH 1/5] WIP: dup2 implementation start --- arch/x86/kernel/isrs.c | 8 ++++ include/hermit/syscall.h | 1 + kernel/syscalls/dup2.c | 82 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+) create mode 100644 kernel/syscalls/dup2.c diff --git a/arch/x86/kernel/isrs.c b/arch/x86/kernel/isrs.c index 7131d839..9b3994f7 100644 --- a/arch/x86/kernel/isrs.c +++ b/arch/x86/kernel/isrs.c @@ -442,6 +442,14 @@ void syscall_handler(struct state *s) break; #endif /* DISABLE_SYS_MADVISE */ +#ifndef DISABLE_SYS_DUP2 + case 33: + /* dup2 */ + s->rax = sys_dup2(s->rdi, s->rsi); + break; +#endif /* DISABLE_SYS_DUP2 */ + + #ifndef DISABLE_SYS_NANOSLEEP case 35: /* nanosleep */ diff --git a/include/hermit/syscall.h b/include/hermit/syscall.h index 7f60a97c..c30a1295 100644 --- a/include/hermit/syscall.h +++ b/include/hermit/syscall.h @@ -146,6 +146,7 @@ size_t sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, int sys_mkdir(const char *pathname, umode_t mode); int sys_rmdir(const char *pathname); int sys_madvise(unsigned long start, size_t len_in, int behavior); +int sys_dup2(int oldfd, int newfd); int sys_geteuid(void); int sys_getuid(void); int sys_getgid(void); diff --git a/kernel/syscalls/dup2.c b/kernel/syscalls/dup2.c new file mode 100644 index 00000000..c00e8d51 --- /dev/null +++ b/kernel/syscalls/dup2.c @@ -0,0 +1,82 @@ +#include +#include +#include +#include +#include +#include + +typedef struct { + int fd; + unsigned int cmd; + unsigned long arg; + int ret; +} __attribute__((packed)) uhyve_fcntl_t; + +typedef struct { + int fd; + int ret; +} __attribute__((packed)) uhyve_close_t; + +static int invalid(int fd) +{ + return 0; +} + +/** + * if running under uhyve: + * - use hermit_fcntl (or sys_fcntl?) to check if newfd is in use already + * - if so, close it with either sys_close or hermit_close + * - copy data from oldfd to newfd + * else not uhyve: + * - check again if LwIP fd, but use lwip_close instead of hermit_close + * - else use lwip_write to write to libc_sd -- set up a sys_close + * + * TODO: + * - understand when to use syscall and when to use hermit/lwip interfaces + * - understand nuances of copying file descriptors + */ + +int sys_dup2(int oldfd, int newfd) +{ + + if (unlikely(newfd == oldfd)) + return newfd; + + if (invalid(oldfd)) + return -EBADF; + + if (likely(is_uhyve())) { + +#ifndef NO_NET + // not sure if correct to use hermit_fcntl, maybe use sys_fcntl? + if (newfd & LWIP_FD_BIT) { + int open_fd = hermit_fcntl(newfd, F_GETFL, 0); + if (open_fd >= 0) { + int ret = hermit_close(newfd); + if (ret < 0) + return -errno; + } + // dup it now? + } +#endif + uhyve_fcntl_t uhyve_fcntl = {newfd, F_GETFL, 0, -1}; + uhyve_send(UHYVE_PORT_FCNTL, (unsigned)virt_to_phys((size_t) &uhyve_fcntl)); + + if (uhyve_fcntl.ret >= 0) { + uhyve_close_t uhyve_close = {newfd, -1}; + uhyve_send(UHYVE_PORT_CLOSE, (unsigned)virt_to_phys((size_t) &uhyve_close)); + if (uhyve_close.ret < 0) { + return uhyve_close.ret; + } + // dup it now? + } + } + +#ifndef NO_NET + + + +#endif + + +} \ No newline at end of file From 51bc50bcf2f66e168c26c00cae9405acdc1b1253 Mon Sep 17 00:00:00 2001 From: tom Date: Tue, 15 Oct 2019 22:49:57 -0500 Subject: [PATCH 2/5] implement initial dup2 syscall --- include/hermit/stddef.h | 1 + include/hermit/syscall.h | 2 +- kernel/syscalls/dup2.c | 83 ++++++++++------------------------------ kernel/syscalls/fcntl.c | 2 + tools/uhyve-syscalls.h | 9 ++++- tools/uhyve.c | 8 ++++ 6 files changed, 40 insertions(+), 65 deletions(-) diff --git a/include/hermit/stddef.h b/include/hermit/stddef.h index c3f7df5d..3abe2b0a 100644 --- a/include/hermit/stddef.h +++ b/include/hermit/stddef.h @@ -95,6 +95,7 @@ extern uint64_t tux_start_address; #define UHYVE_PORT_FDATASYNC 0x527 #define UHYVE_PORT_SYNCFS 0x528 #define UHYVE_PORT_GETDENTS 0x529 +#define UHYVE_PORT_DUP2 0x530 // Networkports #define UHYVE_PORT_NETINFO 0x505 diff --git a/include/hermit/syscall.h b/include/hermit/syscall.h index c30a1295..5f75503b 100644 --- a/include/hermit/syscall.h +++ b/include/hermit/syscall.h @@ -146,7 +146,6 @@ size_t sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, int sys_mkdir(const char *pathname, umode_t mode); int sys_rmdir(const char *pathname); int sys_madvise(unsigned long start, size_t len_in, int behavior); -int sys_dup2(int oldfd, int newfd); int sys_geteuid(void); int sys_getuid(void); int sys_getgid(void); @@ -208,6 +207,7 @@ int sys_syncfs(int fd); long sys_set_tid_address(int *tidptr); int sys_getdents(unsigned int fd, struct linux_dirent *dirp, unsigned int count); +int sys_dup2(int oldfd, int newfd); struct ucontext; typedef struct ucontext ucontext_t; diff --git a/kernel/syscalls/dup2.c b/kernel/syscalls/dup2.c index c00e8d51..cea2fc79 100644 --- a/kernel/syscalls/dup2.c +++ b/kernel/syscalls/dup2.c @@ -1,82 +1,39 @@ -#include #include #include -#include +#include +#include #include -#include typedef struct { - int fd; - unsigned int cmd; - unsigned long arg; - int ret; -} __attribute__((packed)) uhyve_fcntl_t; + int oldfd; + int newfd; + int ret; +} __attribute__ ((packed)) uhyve_dup2_t; -typedef struct { - int fd; - int ret; -} __attribute__((packed)) uhyve_close_t; - -static int invalid(int fd) -{ - return 0; -} /** - * if running under uhyve: - * - use hermit_fcntl (or sys_fcntl?) to check if newfd is in use already - * - if so, close it with either sys_close or hermit_close - * - copy data from oldfd to newfd - * else not uhyve: - * - check again if LwIP fd, but use lwip_close instead of hermit_close - * - else use lwip_write to write to libc_sd -- set up a sys_close - * - * TODO: - * - understand when to use syscall and when to use hermit/lwip interfaces - * - understand nuances of copying file descriptors + * Currently this implementation does not support the following: + * - checking if oldfd is valid + * - minifs file descriptors + * - LwIP file descriptors */ - int sys_dup2(int oldfd, int newfd) { + if (minifs_enabled) { + LOG_ERROR("dup2: not supported with minifs\n"); + return -ENOSYS; + } + if (unlikely(newfd == oldfd)) return newfd; - if (invalid(oldfd)) - return -EBADF; - if (likely(is_uhyve())) { - -#ifndef NO_NET - // not sure if correct to use hermit_fcntl, maybe use sys_fcntl? - if (newfd & LWIP_FD_BIT) { - int open_fd = hermit_fcntl(newfd, F_GETFL, 0); - if (open_fd >= 0) { - int ret = hermit_close(newfd); - if (ret < 0) - return -errno; - } - // dup it now? - } -#endif - uhyve_fcntl_t uhyve_fcntl = {newfd, F_GETFL, 0, -1}; - uhyve_send(UHYVE_PORT_FCNTL, (unsigned)virt_to_phys((size_t) &uhyve_fcntl)); - - if (uhyve_fcntl.ret >= 0) { - uhyve_close_t uhyve_close = {newfd, -1}; - uhyve_send(UHYVE_PORT_CLOSE, (unsigned)virt_to_phys((size_t) &uhyve_close)); - if (uhyve_close.ret < 0) { - return uhyve_close.ret; - } - // dup it now? - } + uhyve_dup2_t uhyve_args = {oldfd, newfd, -1}; + uhyve_send(UHYVE_PORT_DUP2, (unsigned)virt_to_phys((size_t)&uhyve_args)); + return uhyve_args.ret; } -#ifndef NO_NET - - - -#endif - - + LOG_ERROR("dup2: not supported with qemu isle\n"); + return -ENOSYS; } \ No newline at end of file diff --git a/kernel/syscalls/fcntl.c b/kernel/syscalls/fcntl.c index 79d256d8..95537d55 100644 --- a/kernel/syscalls/fcntl.c +++ b/kernel/syscalls/fcntl.c @@ -48,6 +48,8 @@ int sys_fcntl(int fd, unsigned int cmd, unsigned long arg) { } switch(cmd) { + case F_GETFL: + case F_GETFD: case F_SETFD: u_arg.fd = fd; u_arg.cmd = cmd; diff --git a/tools/uhyve-syscalls.h b/tools/uhyve-syscalls.h index 10b0fd98..4f5e7225 100644 --- a/tools/uhyve-syscalls.h +++ b/tools/uhyve-syscalls.h @@ -49,7 +49,8 @@ typedef enum { UHYVE_PORT_FSYNC = 0x526, UHYVE_PORT_FDATASYNC = 0x527, UHYVE_PORT_SYNCFS = 0x528, - UHYVE_PORT_GETDENTS = 0x529 + UHYVE_PORT_GETDENTS = 0x529, + UHYVE_PORT_DUP2 = 0X530 } uhyve_syscall_t; typedef struct { @@ -195,4 +196,10 @@ typedef struct { int ret; } __attribute__((packed)) uhyve_getdeents_t; +typedef struct { + int oldfd; + int newfd; + int ret; +} __attribute__ ((packed)) uhyve_dup2_t; + #endif // UHYVE_SYSCALLS_H diff --git a/tools/uhyve.c b/tools/uhyve.c index 44af2f3a..56800ed1 100644 --- a/tools/uhyve.c +++ b/tools/uhyve.c @@ -1339,6 +1339,14 @@ static int vcpu_loop(void) break; } + case UHYVE_PORT_DUP2: { + unsigned data = *((unsigned*)((size_t)run+run->io.data_offset)); + uhyve_dup2_t *arg = (uhyve_dup2_t *)(guest_mem + data); + + arg->ret = dup2(arg->oldfd, arg->newfd); + break; + } + default: err(1, "KVM: unhandled KVM_EXIT_IO at port 0x%x, direction %d\n", run->io.port, run->io.direction); From 8359696e605ac4b0bb38a253d4d88356e3e83c39 Mon Sep 17 00:00:00 2001 From: tom Date: Fri, 18 Oct 2019 17:31:50 -0500 Subject: [PATCH 3/5] minifs implementation of dup2 --- include/hermit/minifs.h | 7 +++++++ kernel/minifs.c | 19 +++++++++++++++++++ kernel/syscalls/dup2.c | 9 ++++----- 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/include/hermit/minifs.h b/include/hermit/minifs.h index e07fa5aa..332955a1 100644 --- a/include/hermit/minifs.h +++ b/include/hermit/minifs.h @@ -18,5 +18,12 @@ int minifs_write(int fd, const void *buf, size_t count); uint64_t minifs_lseek(int fd, uint64_t offset, int whence); int minifs_mkdir(const char *pathname, mode_t mode); int minifs_rmdir(const char *pathname); +/** + * MiniFS implementation of dup2. + * Attempts to follow Linux convention of + * error handling with regards to + * bad file descriptors. +*/ +int minifs_dup2(int oldfd, int newfd); #endif /* MINI_FS_H */ diff --git a/kernel/minifs.c b/kernel/minifs.c index 884d7bb8..9d0e2f2b 100644 --- a/kernel/minifs.c +++ b/kernel/minifs.c @@ -23,6 +23,8 @@ #define SEEK_CUR 1 #define SEEK_END 2 +#define IS_OPEN(fd) fds && fds[fd].f != NULL + typedef struct s_file { char *name; uint64_t size; @@ -262,6 +264,23 @@ int meminfo_read(int fd, void *buf, uint64_t len) { return len; } +int minifs_dup2(int oldfd, int newfd) { + + if (!IS_OPEN(oldfd) || newfd > MAX_FDS) { + return -EBADF; + } + + if (IS_OPEN(newfd) && !minifs_close(newfd)) { + LOG_ERROR("minifs_dup2: failed to close open file with fd: %d\n", + newfd); + return -1; + } + + fds[newfd].f = fds[oldfd].f; + fds[newfd].offset = fds[oldfd].offset; + + return 0; +} int meminfo_write(int fd, const void *buf, uint64_t len) { return len; diff --git a/kernel/syscalls/dup2.c b/kernel/syscalls/dup2.c index cea2fc79..eaa5b61e 100644 --- a/kernel/syscalls/dup2.c +++ b/kernel/syscalls/dup2.c @@ -20,15 +20,14 @@ typedef struct { int sys_dup2(int oldfd, int newfd) { - if (minifs_enabled) { - LOG_ERROR("dup2: not supported with minifs\n"); - return -ENOSYS; - } - if (unlikely(newfd == oldfd)) return newfd; if (likely(is_uhyve())) { + + if (minifs_enabled) + return minifs_dup2(oldfd, newfd); + uhyve_dup2_t uhyve_args = {oldfd, newfd, -1}; uhyve_send(UHYVE_PORT_DUP2, (unsigned)virt_to_phys((size_t)&uhyve_args)); return uhyve_args.ret; From 4ab73fffe9559a82141cc1e3aa09f67bf5ee5818 Mon Sep 17 00:00:00 2001 From: tom Date: Sat, 19 Oct 2019 18:29:41 -0500 Subject: [PATCH 4/5] finish dup2; defer LwIP socket implementation --- kernel/syscalls/dup2.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/kernel/syscalls/dup2.c b/kernel/syscalls/dup2.c index eaa5b61e..b7d3384b 100644 --- a/kernel/syscalls/dup2.c +++ b/kernel/syscalls/dup2.c @@ -1,9 +1,12 @@ #include #include +#include #include #include #include +extern int hermit_dup2(int oldfd, int newfd); + typedef struct { int oldfd; int newfd; @@ -11,18 +14,18 @@ typedef struct { } __attribute__ ((packed)) uhyve_dup2_t; -/** - * Currently this implementation does not support the following: - * - checking if oldfd is valid - * - minifs file descriptors - * - LwIP file descriptors - */ int sys_dup2(int oldfd, int newfd) { - if (unlikely(newfd == oldfd)) return newfd; +#ifndef NO_NET + if ((oldfd & LWIP_FD_BIT) || (newfd & LWIP_FD_BIT)) { + LOG_ERROR("dup2: sockets not supported\n"); + return -ENOSYS; + } +#endif + if (likely(is_uhyve())) { if (minifs_enabled) From d28c588db3fa3b5959e32d96e65d46f67eaf45ca Mon Sep 17 00:00:00 2001 From: Tom Van Deusen Date: Sat, 19 Oct 2019 18:39:00 -0500 Subject: [PATCH 5/5] add proper parentheses in IS_OPEN macro --- kernel/minifs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/minifs.c b/kernel/minifs.c index 9d0e2f2b..78f0c06d 100644 --- a/kernel/minifs.c +++ b/kernel/minifs.c @@ -23,7 +23,7 @@ #define SEEK_CUR 1 #define SEEK_END 2 -#define IS_OPEN(fd) fds && fds[fd].f != NULL +#define IS_OPEN(fd) (fds && (fds[fd].f != NULL)) typedef struct s_file { char *name;