From 8356c272390fe6cd263ba855a3d7babb591cebf8 Mon Sep 17 00:00:00 2001 From: Matheus Date: Mon, 24 Oct 2022 15:44:01 -0300 Subject: [PATCH] syscalls: recvmsg and futex system calls --- src/arch/x86_64/syscall.asm | 6 +- src/arch/x86_64/syscalllog.c | 4 +- src/sys/syscalls/futex.c | 153 +++++++++++++++++++++++++++++++++++ src/sys/syscalls/recvmsg.c | 104 ++++++++++++++++++++++++ 4 files changed, 265 insertions(+), 2 deletions(-) create mode 100644 src/sys/syscalls/futex.c create mode 100644 src/sys/syscalls/recvmsg.c diff --git a/src/arch/x86_64/syscall.asm b/src/arch/x86_64/syscall.asm index fd84f634..38da0f7c 100644 --- a/src/arch/x86_64/syscall.asm +++ b/src/arch/x86_64/syscall.asm @@ -43,7 +43,9 @@ extern syscall_accept extern syscall_nanosleep extern syscall_fchmod extern syscall_linkat -func_count equ 42 +extern syscall_recvmsg +extern syscall_futex +func_count equ 44 func_table: @@ -89,6 +91,8 @@ func_table: dq syscall_nanosleep dq syscall_fchmod dq syscall_linkat + dq syscall_recvmsg + dq syscall_futex section .text global asm_syscall_entry diff --git a/src/arch/x86_64/syscalllog.c b/src/arch/x86_64/syscalllog.c index b63b2d45..be1144c9 100644 --- a/src/arch/x86_64/syscalllog.c +++ b/src/arch/x86_64/syscalllog.c @@ -45,7 +45,9 @@ static char* syscalls[] = { "syscall_accept", "syscall_nanosleep", "syscall_fchmod", - "syscall_linkat" + "syscall_linkat", + "syscall_recvmsg", + "syscall_futex" }; diff --git a/src/sys/syscalls/futex.c b/src/sys/syscalls/futex.c new file mode 100644 index 00000000..25927444 --- /dev/null +++ b/src/sys/syscalls/futex.c @@ -0,0 +1,153 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 + +static int lock; +typedef struct _futex{ + struct _futex* next; + void* phyaddr; + size_t waitercount; + size_t waitersleft; + event_t event; +} futex_t; + +static futex_t* first; + +static inline futex_t* getfutex(void *addr){ + futex_t* iter = first; + + while(iter){ + if(iter->phyaddr == addr) + break; + iter = iter->next; + } + + return iter; + +} + +static inline void setfutex(futex_t* futex){ + futex->next = first; + first = futex; +} + +syscallret syscall_futex(uint32_t *futex, int op, uint32_t v, const struct timespec* tm){ + + syscallret retv; + retv.ret = -1; + + if(futex > USER_SPACE_END || tm > USER_SPACE_END){ + retv.errno = EFAULT; + return retv; + } + + uint32_t word; + + __atomic_load(futex, &word, __ATOMIC_RELAXED); + + spinlock_acquire(&lock); + + // TODO safer way of getting the address from userspace while inside the lock + + uint32_t* phyfutex = vmm_tophysical(futex); + futex_t* f = getfutex(phyfutex); + + switch(op){ + case FUTEX_WAKE: + // add to waiters left + retv.errno = 0; + + if(!f){ + retv.ret = 0; + break; + } + + retv.ret = v > f->waitercount ? f->waitercount : v; + + + f->waitercount -= retv.ret; + f->waitersleft += retv.ret; + + break; + + + case FUTEX_WAIT: + if(word != v){ + retv.errno = EAGAIN; + break; + } + + if(!f){ + f = alloc(sizeof(futex_t)); + if(!f){ + retv.errno = ENOMEM; + break; + } + setfutex(f); + } + + struct timespec target = arch_timekeeper_gettime(); + + if(tm){ + target.tv_sec += tm->tv_sec; + target.tv_nsec += tm->tv_nsec; + if(target.tv_nsec > 1000000000){ + target.tv_sec++; + target.tv_nsec %= 1000000000; + } + } + + // XXX probably should use events here + + for(;;){ + + if(spinlock_trytoacquire(&lock)){ + + if(tm != NULL){ + struct timespec now = arch_timekeeper_gettime(); + if(now.tv_sec > target.tv_sec) + break; + + if(now.tv_sec == target.tv_sec && now.tv_nsec >= target.tv_sec) + break; + + } + + if(f->waitersleft != 0){ + --f->waitersleft; + --f->waitercount; + break; + } + + spinlock_release(&lock); + } + + arch_interrupt_disable(); + + sched_yield(); + + arch_interrupt_enable(); + + } + + retv.ret = 0; + retv.errno = 0; + break; + default: + retv.errno = ENOSYS; + } + + spinlock_release(&lock); + + return retv; + +} diff --git a/src/sys/syscalls/recvmsg.c b/src/sys/syscalls/recvmsg.c new file mode 100644 index 00000000..087ef64e --- /dev/null +++ b/src/sys/syscalls/recvmsg.c @@ -0,0 +1,104 @@ +#include +#include +#include +#include +#include +#include +#include + + +syscallret syscall_recvmsg(int ifd, msghdr *msg, int flags){ + + if(flags) + _panic("No flags support for recvmsg yet", 0); + + syscallret retv; + retv.ret = -1; + + if(msg > USER_SPACE_END || msg->msg_iov > USER_SPACE_END){ + retv.errno = EFAULT; + return retv; + } + + // get len of iovecs + + size_t totallen = 0; + + for(uintmax_t i = 0; i < msg->msg_iovlen; ++i){ + if(msg->msg_iov[i].iov_base > USER_SPACE_END){ + retv.errno = EFAULT; + return retv; + } + + totallen += msg->msg_iov[i].iov_len; + + } + + // open fd + + proc_t* proc = arch_getcls()->thread->proc; + + fd_t* fd; + + int err = fd_access(&proc->fdtable, &fd, ifd); + + if(err){ + retv.errno = err; + return retv; + } + + void* buff = alloc(totallen); + + if(!buff){ + retv.errno = ENOMEM; + goto _return; + } + + if((!fd->node) || GETTYPE(fd->node->st.st_mode) != TYPE_SOCKET){ + retv.errno = ENOTSOCK; + goto _return; + } + + int readcount = socket_recv(fd->node->objdata, buff, totallen, flags, &err, fd); + + retv.errno = err; + + if(retv.errno) + goto _return; + + // now copy the data into the proper locations + + void* buffptr = buff; + + if(msg->msg_iov > USER_SPACE_END){ + retv.errno = EFAULT; + goto _return; + } + + for(size_t i = 0; i < msg->msg_iovlen; ++i){ + if(msg->msg_iov[i].iov_base > USER_SPACE_END){ + retv.errno = EFAULT; + goto _return; + } + + size_t iovlen = msg->msg_iov[i].iov_len; + void* iovbuf = msg->msg_iov[i].iov_base; + + memcpy(iovbuf, buffptr, iovlen); + + buffptr += iovlen; + } + + retv.errno = 0; + retv.ret = readcount; + + _return: + + if(buff) + free(buff); + + fd_release(fd); + + return retv; + +}