From 5f7791cd08b5093b16c52812948f903ead1f5942 Mon Sep 17 00:00:00 2001 From: Matheus Date: Wed, 29 May 2024 11:10:24 -0300 Subject: [PATCH] syscalls: fchdir, setitimer, getitimer --- kernel-src/arch/x86-64/syscall.asm | 8 ++- kernel-src/arch/x86-64/syscalllog.c | 12 +++- kernel-src/include/kernel/itimer.h | 23 ++++++ kernel-src/include/kernel/scheduler.h | 8 +++ kernel-src/include/time.h | 6 ++ kernel-src/sys/itimer.c | 88 +++++++++++++++++++++++ kernel-src/sys/scheduler.c | 32 ++++++++- kernel-src/sys/syscalls/chdir.c | 24 +++++++ kernel-src/sys/syscalls/futex.c | 4 +- kernel-src/sys/syscalls/setitimer.c | 96 ++++++++++++++++++++++++++ patches/mlibc/jinx-working-patch.patch | 25 +++++-- 11 files changed, 313 insertions(+), 13 deletions(-) create mode 100644 kernel-src/include/kernel/itimer.h create mode 100644 kernel-src/sys/itimer.c create mode 100644 kernel-src/sys/syscalls/setitimer.c diff --git a/kernel-src/arch/x86-64/syscall.asm b/kernel-src/arch/x86-64/syscall.asm index e3f39975..cdd13880 100644 --- a/kernel-src/arch/x86-64/syscall.asm +++ b/kernel-src/arch/x86-64/syscall.asm @@ -66,6 +66,9 @@ extern syscall_uname extern syscall_hostname extern syscall_sync extern syscall_fsync +extern syscall_fchdir +extern syscall_getitimer +extern syscall_setitimer syscalltab: dq syscall_print dq syscall_mmap @@ -134,7 +137,10 @@ dq syscall_uname dq syscall_hostname dq syscall_sync dq syscall_fsync -syscallcount equ 67 +dq syscall_fchdir +dq syscall_setitimer +dq syscall_getitimer +syscallcount equ 70 section .text global arch_syscall_entry ; on entry: diff --git a/kernel-src/arch/x86-64/syscalllog.c b/kernel-src/arch/x86-64/syscalllog.c index f1eaa7f2..fb57a755 100644 --- a/kernel-src/arch/x86-64/syscalllog.c +++ b/kernel-src/arch/x86-64/syscalllog.c @@ -5,7 +5,7 @@ #ifdef SYSCALL_LOGGING -#define SYSCALL_COUNT 67 +#define SYSCALL_COUNT 68 #define LOGSTR(x) arch_e9_puts(x) static char *name[] = { @@ -75,7 +75,10 @@ static char *name[] = { "uname", "hostname", "sync", - "fsync" + "fsync", + "fchdir", + "getitimer", + "setitimer" }; static char *args[] = { @@ -145,7 +148,10 @@ static char *args[] = { "utsname %p", // uname "new %p newsize %lu old %p oldsize %lu", // hostname "N/A", // sync - "fd %d" // fsync + "fd %d", // fsync + "fd %d", // fchdir + "which %d new %p old %p\n", // setitimer + "which %d value %p\n", // getitimer }; #endif diff --git a/kernel-src/include/kernel/itimer.h b/kernel-src/include/kernel/itimer.h new file mode 100644 index 00000000..09fa2b22 --- /dev/null +++ b/kernel-src/include/kernel/itimer.h @@ -0,0 +1,23 @@ +#ifndef _ITIMER_H +#define _ITIMER_H + +#include +#include + +typedef struct { + struct cpu_t *cpu; + timerentry_t entry; + uintmax_t remainingus; + uintmax_t repeatus; + dpcfn_t fn; + dpcarg_t arg; + bool paused; + spinlock_t lock; +} itimer_t; + +void itimer_init(itimer_t *itimer, dpcfn_t fn, dpcarg_t arg); +void itimer_pause(itimer_t *itimer, uintmax_t *remainingus, uintmax_t *repeatus); +void itimer_set(itimer_t *itimer, uintmax_t timerus, uintmax_t repeatus); +void itimer_resume(itimer_t *itimer); + +#endif diff --git a/kernel-src/include/kernel/scheduler.h b/kernel-src/include/kernel/scheduler.h index f7852832..2b6583e6 100644 --- a/kernel-src/include/kernel/scheduler.h +++ b/kernel-src/include/kernel/scheduler.h @@ -8,6 +8,7 @@ #include #include #include +#include #define SCHED_THREAD_FLAGS_QUEUED 1 #define SCHED_THREAD_FLAGS_RUNNING 2 @@ -112,6 +113,13 @@ typedef struct proc_t { bool stopunwaited; bool continueunwaited; } signals; + + struct { + mutex_t mutex; + itimer_t realtime; + itimer_t virtualtime; + itimer_t profiling; + } timer; } proc_t; #include diff --git a/kernel-src/include/time.h b/kernel-src/include/time.h index 22787f95..5b721c95 100644 --- a/kernel-src/include/time.h +++ b/kernel-src/include/time.h @@ -4,12 +4,18 @@ #include typedef long time_t; +typedef long suseconds_t; typedef struct { time_t s; time_t ns; } timespec_t; +typedef struct { + time_t s; + suseconds_t us; +} timeval_t; + static inline timespec_t timespec_add(timespec_t a, timespec_t b) { timespec_t ts; ts.ns = (a.ns + b.ns) % 1000000000; diff --git a/kernel-src/sys/itimer.c b/kernel-src/sys/itimer.c new file mode 100644 index 00000000..812f5b26 --- /dev/null +++ b/kernel-src/sys/itimer.c @@ -0,0 +1,88 @@ +#include +#include + +static void itimer_dpc(context_t *context, dpcarg_t arg) { + itimer_t *itimer = arg; + spinlock_acquire(&itimer->lock); + if (itimer->paused) + goto leave; + + itimer->remainingus = itimer->repeatus ? itimer->repeatus : 0; + itimer->paused = itimer->repeatus == 0; + itimer->fn(context, itimer->arg); + if (itimer->repeatus) { + timer_insert(_cpu()->timer, &itimer->entry, itimer_dpc, itimer, itimer->remainingus, false); + } + + leave: + spinlock_release(&itimer->lock); +} + +void itimer_init(itimer_t *itimer, dpcfn_t fn, dpcarg_t arg) { + memset(itimer, 0, sizeof(itimer_t)); + itimer->fn = fn; + itimer->arg = arg; + itimer->paused = true; + SPINLOCK_INIT(itimer->lock); +} + +void itimer_pause(itimer_t *itimer, uintmax_t *remainingus, uintmax_t *repeatus) { + bool intstatus = interrupt_set(false); + spinlock_acquire(&itimer->lock); + + while (itimer->cpu && itimer->cpu != _cpu()) { + // schedule on the itimer cpu + sched_targetcpu(itimer->cpu); + spinlock_release(&itimer->lock); + sched_yield(); + sched_targetcpu(NULL); + spinlock_acquire(&itimer->lock); + } + + if (itimer->paused) + goto cleanup; + + itimer->cpu = NULL; + itimer->remainingus = timer_remove(_cpu()->timer, &itimer->entry); + if (itimer->remainingus == 0) { + // while we were running in the cpu, the timer fired. + // the dpc won't be handled because the timer entry + // has already been removed from the queue. + // this will be handled as a ''timer was one microsecond away from firing'' + // situation as its the cleanest way of doing this. + itimer->remainingus = 1; + } + itimer->paused = true; + cleanup: + + spinlock_release(&itimer->lock); + interrupt_set(intstatus); + if (remainingus) + *remainingus = itimer->remainingus; + if (repeatus) + *repeatus = itimer->repeatus; +} + +void itimer_set(itimer_t *itimer, uintmax_t timerus, uintmax_t repeatus) { + bool intstatus = interrupt_set(false); + spinlock_acquire(&itimer->lock); + + itimer->remainingus = timerus; + itimer->repeatus = repeatus; + + spinlock_release(&itimer->lock); + interrupt_set(intstatus); +} + +void itimer_resume(itimer_t *itimer) { + bool intstatus = interrupt_set(false); + spinlock_acquire(&itimer->lock); + + __assert(itimer->paused && itimer->remainingus); + itimer->cpu = _cpu(); + itimer->paused = false; + timer_insert(_cpu()->timer, &itimer->entry, itimer_dpc, itimer, itimer->remainingus, false); + + spinlock_release(&itimer->lock); + interrupt_set(intstatus); +} diff --git a/kernel-src/sys/scheduler.c b/kernel-src/sys/scheduler.c index 6ba224dd..c50c49a2 100644 --- a/kernel-src/sys/scheduler.c +++ b/kernel-src/sys/scheduler.c @@ -49,6 +49,27 @@ proc_t *sched_getprocfrompid(int pid) { return proc; } +static void rtdpc(context_t *, dpcarg_t arg) { + proc_t *proc = arg; + // XXX this can sleep and if it does the entire system burns down sooooooo yeah fix this for the love of god + __assert(proc->threadtablesize == 1); + signal_signalproc(arg, SIGALRM); +} + +static void vtdpc(context_t *, dpcarg_t arg) { + proc_t *proc = arg; + // XXX this can sleep and if it does the entire system burns down sooooooo yeah fix this for the love of god + __assert(proc->threadtablesize == 1); + signal_signalproc(arg, SIGVTALRM); +} + +static void profdpc(context_t *, dpcarg_t arg) { + proc_t *proc = arg; + // XXX this can sleep and if it does the entire system burns down sooooooo yeah fix this for the love of god + __assert(proc->threadtablesize == 1); + signal_signalproc(arg, SIGPROF); +} + proc_t *sched_newproc() { proc_t *proc = slab_allocate(processcache); if (proc == NULL) @@ -76,6 +97,10 @@ proc_t *sched_newproc() { SPINLOCK_INIT(proc->jobctllock); SPINLOCK_INIT(proc->pgrp.lock); SPINLOCK_INIT(proc->signals.lock); + MUTEX_INIT(&proc->timer.mutex); + itimer_init(&proc->timer.realtime, rtdpc, proc); + itimer_init(&proc->timer.virtualtime, vtdpc, proc); + itimer_init(&proc->timer.profiling, profdpc, proc); proc->fd = alloc(sizeof(fd_t) * 3); if (proc->fd == NULL) { @@ -127,7 +152,6 @@ thread_t *sched_newthread(void *ip, size_t kstacksize, int priority, proc_t *pro thread->tid = __atomic_fetch_add(&currpid, 1, __ATOMIC_SEQ_CST); } - CTX_INIT(&thread->context, proc != NULL, true); CTX_XINIT(&thread->extracontext, proc != NULL); CTX_SP(&thread->context) = proc ? (ctxreg_t)ustack : (ctxreg_t)thread->kernelstacktop; @@ -291,6 +315,11 @@ void sched_procexit() { for (int fd = 0; fd < proc->fdcount; ++fd) fd_close(fd); + // turn off interval timers + itimer_pause(&proc->timer.realtime, NULL, NULL); + itimer_pause(&proc->timer.virtualtime, NULL, NULL); + itimer_pause(&proc->timer.profiling, NULL, NULL); + // zombify the proc MUTEX_ACQUIRE(&proc->mutex, false); @@ -392,7 +421,6 @@ typedef struct { // SHOULD NOT BE CALLED WITH THE SCHEDULER STACK static void userspacecheck(void *_args) { checkargs_t *args = _args; - __assert(_cpu() >= (cpu_t *)0xffffffff80000000); thread_t *thread = _cpu()->thread; if (thread->shouldexit) { diff --git a/kernel-src/sys/syscalls/chdir.c b/kernel-src/sys/syscalls/chdir.c index 3d8930d0..0852faa3 100644 --- a/kernel-src/sys/syscalls/chdir.c +++ b/kernel-src/sys/syscalls/chdir.c @@ -42,3 +42,27 @@ syscallret_t syscall_chdir(context_t *, const char *upath) { return ret; } + +syscallret_t syscall_fchdir(context_t *, int fd) { + syscallret_t ret = { + .ret = -1 + }; + + file_t *file = fd_get(fd); + if (file == NULL) { + ret.errno = EBADF; + return ret; + } + + if (file->vnode->type != V_TYPE_DIR) { + ret.errno = ENOTDIR; + goto cleanup; + } + + sched_setcwd(file->vnode); + ret.errno = 0; + + cleanup: + fd_release(file); + return ret; +} diff --git a/kernel-src/sys/syscalls/futex.c b/kernel-src/sys/syscalls/futex.c index 65e10122..0e5625fc 100644 --- a/kernel-src/sys/syscalls/futex.c +++ b/kernel-src/sys/syscalls/futex.c @@ -124,7 +124,9 @@ syscallret_t syscall_futex(context_t *, uint32_t *futexp, int op, uint32_t value MUTEX_RELEASE(&futexmutex); ret.errno = poll_dowait(&desc, us); - int revents = desc.event->revents; + int revents = 0; + if (desc.event) + revents = desc.event->revents; MUTEX_ACQUIRE(&futexmutex, false); diff --git a/kernel-src/sys/syscalls/setitimer.c b/kernel-src/sys/syscalls/setitimer.c new file mode 100644 index 00000000..9652d4a5 --- /dev/null +++ b/kernel-src/sys/syscalls/setitimer.c @@ -0,0 +1,96 @@ +#include +#include +#include +#include + +#define ITIMER_REAL 0 +#define ITIMER_VIRTUAL 1 +#define ITIMER_PROF 2 + +typedef struct { + timeval_t interval; + timeval_t value; +} itimerval_t; + +static itimer_t *selectitimer(int which) { + itimer_t *itimer = NULL; + if (which == ITIMER_REAL) + itimer = &_cpu()->thread->proc->timer.realtime; + else if (which == ITIMER_VIRTUAL) + itimer = &_cpu()->thread->proc->timer.virtualtime; + else if (which == ITIMER_PROF) + itimer = &_cpu()->thread->proc->timer.profiling; + + return itimer; +} + +syscallret_t syscall_getitimer(context_t *context, int which, itimerval_t *value) { + syscallret_t ret = { + .ret = -1 + }; + + __assert(which == ITIMER_REAL); + itimer_t *itimer = selectitimer(which); + if (itimer == NULL) { + ret.errno = EINVAL; + return ret; + } + + MUTEX_ACQUIRE(&_cpu()->thread->proc->timer.mutex, false); + + uintmax_t oldremaining, oldrepeat; + itimer_pause(itimer, &oldremaining, &oldrepeat); + if (oldremaining) + itimer_resume(itimer); + + MUTEX_RELEASE(&_cpu()->thread->proc->timer.mutex); + + value->interval.s = oldrepeat / 1000000; + value->interval.us = oldrepeat % 1000000; + value->value.s = oldremaining / 1000000; + value->value.us = oldremaining % 1000000; + ret.errno = 0; + return ret; +} + +syscallret_t syscall_setitimer(context_t *context, int which, itimerval_t *unew, itimerval_t *uold) { + syscallret_t ret = { + .ret = -1 + }; + + __assert(which == ITIMER_REAL); + + itimer_t *itimer = selectitimer(which); + if (itimer == NULL) { + ret.errno = EINVAL; + return ret; + } + + itimerval_t val = {0}; + if (unew) + val = *unew; + + MUTEX_ACQUIRE(&_cpu()->thread->proc->timer.mutex, false); + uintmax_t oldremaining, oldrepeat; + itimer_pause(itimer, &oldremaining, &oldrepeat); + + // TODO overflow check + uintmax_t repeatus = val.interval.s * 1000000 + val.interval.us; + uintmax_t newus = val.value.s * 1000000 + val.value.us; + itimer_set(itimer, newus, repeatus); + + if (newus) + itimer_resume(itimer); + + MUTEX_RELEASE(&_cpu()->thread->proc->timer.mutex); + + if (uold) { + uold->interval.s = oldrepeat / 1000000; + uold->interval.us = oldrepeat % 1000000; + uold->value.s = oldremaining / 1000000; + uold->value.us = oldremaining % 1000000; + } + + ret.errno = 0; + return ret; +} diff --git a/patches/mlibc/jinx-working-patch.patch b/patches/mlibc/jinx-working-patch.patch index 3f1e49d4..d4bbf28d 100644 --- a/patches/mlibc/jinx-working-patch.patch +++ b/patches/mlibc/jinx-working-patch.patch @@ -192,10 +192,10 @@ index 0000000..e5b087a + diff --git mlibc-workdir/sysdeps/astral/generic/generic.cpp mlibc-workdir/sysdeps/astral/generic/generic.cpp new file mode 100644 -index 0000000..0755fba +index 0000000..b150712 --- /dev/null +++ mlibc-workdir/sysdeps/astral/generic/generic.cpp -@@ -0,0 +1,714 @@ +@@ -0,0 +1,724 @@ +#include +#include +#include @@ -279,9 +279,14 @@ index 0000000..0755fba + return 0; + } + ++ int sys_getitimer(int which, struct itimerval *curr_value) { ++ long ret; ++ return syscall(SYSCALL_SETITIMER, &ret, which, (uint64_t)curr_value); ++ } ++ + int sys_setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value) { -+ // TODO unstub -+ return ENOSYS; ++ long ret; ++ return syscall(SYSCALL_SETITIMER, &ret, which, (uint64_t)new_value, (uint64_t)old_value); + } + + #ifndef MLIBC_BUILDING_RTLD @@ -728,6 +733,11 @@ index 0000000..0755fba + return syscall(SYSCALL_CHDIR, &ret, (uint64_t)path); + } + ++ int sys_fchdir(int fd) { ++ long ret; ++ return syscall(SYSCALL_FCHDIR, &ret, fd); ++ } ++ + int sys_fcntl(int fd, int request, va_list args, int *result) { + long arg = va_arg(args, uint64_t); + long ret; @@ -929,10 +939,10 @@ index 0000000..990eca0 +#endif diff --git mlibc-workdir/sysdeps/astral/include/astral/syscall.h mlibc-workdir/sysdeps/astral/include/astral/syscall.h new file mode 100644 -index 0000000..5148ce4 +index 0000000..956a10b --- /dev/null +++ mlibc-workdir/sysdeps/astral/include/astral/syscall.h -@@ -0,0 +1,90 @@ +@@ -0,0 +1,93 @@ +#ifndef _SYSCALL_H_INCLUDE +#define _SYSCALL_H_INCLUDE + @@ -1003,6 +1013,9 @@ index 0000000..5148ce4 +#define SYSCALL_HOSTNAME 64 +#define SYSCALL_SYNC 65 +#define SYSCALL_FSYNC 66 ++#define SYSCALL_FCHDIR 67 ++#define SYSCALL_SETITIMER 68 ++#define SYSCALL_GETITIMER 69 + +#include +#include