syscalls: recvmsg and futex system calls

This commit is contained in:
Matheus
2022-10-24 15:44:01 -03:00
parent a9a15e04bf
commit 8356c27239
4 changed files with 265 additions and 2 deletions
+5 -1
View File
@@ -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
+3 -1
View File
@@ -45,7 +45,9 @@ static char* syscalls[] = {
"syscall_accept",
"syscall_nanosleep",
"syscall_fchmod",
"syscall_linkat"
"syscall_linkat",
"syscall_recvmsg",
"syscall_futex"
};
+153
View File
@@ -0,0 +1,153 @@
#include <kernel/syscalls.h>
#include <kernel/vmm.h>
#include <errno.h>
#include <kernel/event.h>
#include <arch/spinlock.h>
#include <arch/interrupt.h>
#include <kernel/alloc.h>
#include <arch/timekeeper.h>
#include <time.h>
#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;
}
+104
View File
@@ -0,0 +1,104 @@
#include <kernel/syscalls.h>
#include <kernel/fd.h>
#include <arch/panic.h>
#include <kernel/socket.h>
#include <kernel/vmm.h>
#include <arch/cls.h>
#include <kernel/alloc.h>
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;
}