mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-11-01 06:58: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_nanosleep
|
||||||
extern syscall_fchmod
|
extern syscall_fchmod
|
||||||
extern syscall_linkat
|
extern syscall_linkat
|
||||||
func_count equ 42
|
extern syscall_recvmsg
|
||||||
|
extern syscall_futex
|
||||||
|
func_count equ 44
|
||||||
|
|
||||||
|
|
||||||
func_table:
|
func_table:
|
||||||
@@ -89,6 +91,8 @@ func_table:
|
|||||||
dq syscall_nanosleep
|
dq syscall_nanosleep
|
||||||
dq syscall_fchmod
|
dq syscall_fchmod
|
||||||
dq syscall_linkat
|
dq syscall_linkat
|
||||||
|
dq syscall_recvmsg
|
||||||
|
dq syscall_futex
|
||||||
section .text
|
section .text
|
||||||
global asm_syscall_entry
|
global asm_syscall_entry
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,9 @@ static char* syscalls[] = {
|
|||||||
"syscall_accept",
|
"syscall_accept",
|
||||||
"syscall_nanosleep",
|
"syscall_nanosleep",
|
||||||
"syscall_fchmod",
|
"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