mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-10-27 12:48:22 +00:00
syscalls: recvmsg and futex system calls
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -45,7 +45,9 @@ static char* syscalls[] = {
|
||||
"syscall_accept",
|
||||
"syscall_nanosleep",
|
||||
"syscall_fchmod",
|
||||
"syscall_linkat"
|
||||
"syscall_linkat",
|
||||
"syscall_recvmsg",
|
||||
"syscall_futex"
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user