From f3e85eedc434da973267f360abdbb79cb6f24100 Mon Sep 17 00:00:00 2001 From: Marvin Borner Date: Thu, 1 Jul 2021 21:13:01 +0200 Subject: Timing is everything --- kernel/features/dev.c | 2 +- kernel/features/proc.c | 13 +++++- kernel/features/syscall.c | 2 +- kernel/features/timer.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 129 insertions(+), 3 deletions(-) create mode 100644 kernel/features/timer.c (limited to 'kernel/features') diff --git a/kernel/features/dev.c b/kernel/features/dev.c index 0e082f9..c190a8a 100644 --- a/kernel/features/dev.c +++ b/kernel/features/dev.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -21,6 +20,7 @@ #include #include #include +#include struct dev_listener { u32 group; diff --git a/kernel/features/proc.c b/kernel/features/proc.c index 03f45c9..9f4b38b 100644 --- a/kernel/features/proc.c +++ b/kernel/features/proc.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include @@ -14,6 +13,7 @@ #include #include #include +#include #define PROC(node) ((struct proc *)node->data) @@ -133,6 +133,17 @@ struct proc *proc_from_pid(u32 pid) return NULL; } +void proc_timer_check(u32 time) +{ + struct node *iterator = proc_list_blocked->head; + while (iterator) { + struct proc *proc = PROC(iterator); + if (proc->timer.mode == TIMER_MODE_SLEEP && time >= proc->timer.data) + dev_unblock_pid(proc->pid); + iterator = iterator->next; + } +} + CLEAR void proc_set_quantum(struct proc *proc, u32 value) { proc->quantum.val = value; diff --git a/kernel/features/syscall.c b/kernel/features/syscall.c index 16a83d6..86b675c 100644 --- a/kernel/features/syscall.c +++ b/kernel/features/syscall.c @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include @@ -14,6 +13,7 @@ #include #include #include +#include static u32 syscall_handler(u32 esp) { diff --git a/kernel/features/timer.c b/kernel/features/timer.c new file mode 100644 index 0000000..674dd1a --- /dev/null +++ b/kernel/features/timer.c @@ -0,0 +1,115 @@ +// MIT License, Copyright (c) 2020 Marvin Borner + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static u32 timer_ticks = 0; + +u32 timer_get(void) +{ + return timer_ticks; +} + +static void timer_handler(void) +{ + int_disable(); + if (timer_ticks >= U32_MAX) + timer_ticks = 0; + else + timer_ticks++; + proc_timer_check(timer_ticks); + int_enable(); +} + +CLEAR void timer_install_handler(void) +{ + static u8 check = 0; + assert(check++ == 0); + int_event_handler_add(0, timer_handler); +} + +// "Delay" function with CPU sleep +void timer_wait(u32 ticks) +{ + u32 eticks = timer_ticks + ticks; + while (timer_ticks < eticks) + __asm__ volatile("sti\nhlt\ncli"); +} + +static struct timer timer_struct(void) +{ + struct proc *proc = proc_current(); + struct timer timer = { + .rtc = rtc_stamp(), + .ticks.user = proc->ticks.user, + .ticks.kernel = proc->ticks.kernel, + .time = timer_get(), + }; + return timer; +} + +static res timer_read(void *buf, u32 offset, u32 count) +{ + UNUSED(offset); + + // TODO: Make sleeping more accurate + struct proc *proc = proc_current(); + if (proc->timer.mode == TIMER_MODE_SLEEP) { + dev_block(DEV_TIMER, proc); + proc->timer.mode = TIMER_MODE_DEFAULT; + } + + struct timer timer = timer_struct(); + memcpy_user(buf, &timer, MIN(count, sizeof(timer))); + + return MIN(count, sizeof(timer)); +} + +static res timer_control(u32 request, void *arg1, void *arg2, void *arg3) +{ + UNUSED(arg2); + UNUSED(arg3); + + switch (request) { + case DEVCTL_TIMER_SLEEP: { + struct proc *proc = proc_current(); + proc->timer.mode = TIMER_MODE_SLEEP; + proc->timer.data = timer_ticks + (u32)arg1; + return EOK; + } + default: + return -EINVAL; + } +} + +static res timer_ready(void) +{ + struct proc *proc = proc_current(); + if (proc->timer.mode == TIMER_MODE_SLEEP) { + if (timer_ticks >= proc->timer.data) + return EOK; + return -EAGAIN; + } + return EOK; +} + +// Install timer handler into IRQ0 +CLEAR void timer_install(void) +{ + // hpet_install(10000); // TODO: Reimplement hpet + pit_install(); + + struct dev_dev *dev = zalloc(sizeof(*dev)); + dev->read = timer_read; + dev->control = timer_control; + dev->ready = timer_ready; + dev_add(DEV_TIMER, dev); +} -- cgit v1.2.3