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/Makefile | 3 +- kernel/drivers/int.c | 21 +++++++-- kernel/drivers/pit.c | 20 ++++++++ kernel/drivers/rtc.c | 2 +- kernel/drivers/timer.c | 76 ------------------------------ kernel/features/dev.c | 2 +- kernel/features/proc.c | 13 ++++- kernel/features/syscall.c | 2 +- kernel/features/timer.c | 115 +++++++++++++++++++++++++++++++++++++++++++++ kernel/inc/drivers/int.h | 2 + kernel/inc/drivers/pit.h | 8 ++++ kernel/inc/drivers/timer.h | 12 ----- kernel/inc/proc.h | 7 +++ kernel/inc/timer.h | 19 ++++++++ 14 files changed, 205 insertions(+), 97 deletions(-) create mode 100644 kernel/drivers/pit.c delete mode 100644 kernel/drivers/timer.c create mode 100644 kernel/features/timer.c create mode 100644 kernel/inc/drivers/pit.h delete mode 100644 kernel/inc/drivers/timer.h create mode 100644 kernel/inc/timer.h (limited to 'kernel') diff --git a/kernel/Makefile b/kernel/Makefile index 9fed3f1..85ff419 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -15,7 +15,7 @@ COBJS = entry_asm.o \ drivers/ide.o \ drivers/vbe.o \ drivers/bga.o \ - drivers/timer.o \ + drivers/pit.o \ drivers/vmware.o \ drivers/ps2/ps2.o \ drivers/ps2/mouse.o \ @@ -27,6 +27,7 @@ COBJS = entry_asm.o \ features/fb.o \ features/logger.o \ features/load.o \ + features/timer.o \ features/proc.o \ features/proc_asm.o \ features/syscall.o diff --git a/kernel/drivers/int.c b/kernel/drivers/int.c index f6a5134..d5f0a67 100644 --- a/kernel/drivers/int.c +++ b/kernel/drivers/int.c @@ -172,19 +172,32 @@ static u32 int_special_handler(struct int_frame *frame) * Universal handler */ +static u8 int_enabled = 1; + u32 int_handler(u32 esp); u32 int_handler(u32 esp) { struct int_frame *frame = (struct int_frame *)esp; - if (frame->int_no < 32) + if (frame->int_no < 32) { int_trap_handler(frame); - else if (frame->int_no < 48) + } else if (int_enabled && frame->int_no < 48) { esp = int_event_handler(frame); - else if (frame->int_no >= 128 && frame->int_no < 144) + } else if (frame->int_no >= 128 && frame->int_no < 144) { esp = int_special_handler(frame); - else + } else if (frame->int_no >= 48) { panic("Unknown interrupt: %d\n", frame->int_no); + } pic_ack(frame->int_no); return esp; } + +void int_disable(void) +{ + int_enabled = 0; +} + +void int_enable(void) +{ + int_enabled = 1; +} diff --git a/kernel/drivers/pit.c b/kernel/drivers/pit.c new file mode 100644 index 0000000..abba5e8 --- /dev/null +++ b/kernel/drivers/pit.c @@ -0,0 +1,20 @@ +// MIT License, Copyright (c) 2021 Marvin Borner + +#include +#include +#include +#include + +CLEAR static void pit_phase(u32 hz) +{ + u32 divisor = 3579545 / 3 / hz; + outb(0x43, 0x36); // 01 10 11 0b // CTR, RW, MODE, BCD + outb(0x40, (u8)(divisor & 0xFF)); + outb(0x40, (u8)(divisor >> 8)); +} + +CLEAR void pit_install(void) +{ + pit_phase(1000); + timer_install_handler(); +} diff --git a/kernel/drivers/rtc.c b/kernel/drivers/rtc.c index b67829e..0a9a3fd 100644 --- a/kernel/drivers/rtc.c +++ b/kernel/drivers/rtc.c @@ -3,10 +3,10 @@ #include #include #include -#include #include #include #include +#include static u8 rtc_busy(void) { diff --git a/kernel/drivers/timer.c b/kernel/drivers/timer.c deleted file mode 100644 index 977647c..0000000 --- a/kernel/drivers/timer.c +++ /dev/null @@ -1,76 +0,0 @@ -// MIT License, Copyright (c) 2020 Marvin Borner - -#include -#include -#include -#include -#include -#include -#include -#include - -static u32 timer_ticks = 0; - -CLEAR static void timer_phase(int hz) -{ - int divisor = 3579545 / 3 / hz; - outb(0x43, 0x36); // 01 10 11 0b // CTR, RW, MODE, BCD - outb(0x40, (u8)(divisor & 0xFF)); - outb(0x40, (u8)(divisor >> 8)); -} - -u32 timer_get(void) -{ - return timer_ticks; -} - -static void timer_handler(void) -{ - if (timer_ticks >= U32_MAX) - timer_ticks = 0; - else - timer_ticks++; -} - -// "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); - - struct timer timer = timer_struct(); - memcpy_user(buf, &timer, MIN(count, sizeof(timer))); - - return MIN(count, sizeof(timer)); -} - -// Install timer handler into IRQ0 -CLEAR void timer_install(void) -{ - /* hpet_install(10000); // TODO: Find optimal femtosecond period */ - /* if (!hpet) */ - timer_phase(1000); - int_event_handler_add(0, timer_handler); - - struct dev_dev *dev = zalloc(sizeof(*dev)); - dev->read = timer_read; - dev_add(DEV_TIMER, dev); -} 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); +} diff --git a/kernel/inc/drivers/int.h b/kernel/inc/drivers/int.h index 8146898..9dd4a6f 100644 --- a/kernel/inc/drivers/int.h +++ b/kernel/inc/drivers/int.h @@ -44,6 +44,8 @@ struct idt_ptr { } PACKED; void idt_install(void); +void int_enable(void); +void int_disable(void); void int_trap_handler_add(u32 int_no, void (*handler)(u32 esp)); void int_event_handler_add(u32 int_no, void (*handler)(void)); diff --git a/kernel/inc/drivers/pit.h b/kernel/inc/drivers/pit.h new file mode 100644 index 0000000..b3cd507 --- /dev/null +++ b/kernel/inc/drivers/pit.h @@ -0,0 +1,8 @@ +// MIT License, Copyright (c) 2021 Marvin Borner + +#ifndef PIT_H +#define PIT_H + +void pit_install(void); + +#endif diff --git a/kernel/inc/drivers/timer.h b/kernel/inc/drivers/timer.h deleted file mode 100644 index ea1643b..0000000 --- a/kernel/inc/drivers/timer.h +++ /dev/null @@ -1,12 +0,0 @@ -// MIT License, Copyright (c) 2020 Marvin Borner - -#ifndef TIMER_H -#define TIMER_H - -#include - -u32 timer_get(void); -void timer_wait(u32 ticks); -void timer_install(void); - -#endif diff --git a/kernel/inc/proc.h b/kernel/inc/proc.h index 42ff75d..5cc1fef 100644 --- a/kernel/inc/proc.h +++ b/kernel/inc/proc.h @@ -8,6 +8,7 @@ #include #include #include +#include #define PROC_QUANTUM 15 // Milliseconds or something // TODO #define PROC_STACK_SIZE 0x4000 // 16KiB @@ -51,6 +52,11 @@ struct proc { u8 val; u8 cnt; } quantum; + + struct { + enum timer_mode mode; + u32 data; + } timer; }; u32 scheduler(u32 esp); @@ -62,6 +68,7 @@ u8 proc_idle(void); struct proc *proc_from_pid(u32 pid); void proc_exit(s32 status); void proc_yield(void); +void proc_timer_check(u32 time); void proc_set_quantum(struct proc *proc, u32 value) NONNULL; void proc_reset_quantum(struct proc *proc) NONNULL; void proc_state(struct proc *proc, enum proc_state state) NONNULL; diff --git a/kernel/inc/timer.h b/kernel/inc/timer.h new file mode 100644 index 0000000..1233f6e --- /dev/null +++ b/kernel/inc/timer.h @@ -0,0 +1,19 @@ +// MIT License, Copyright (c) 2020 Marvin Borner + +#ifndef TIMER_H +#define TIMER_H + +#include + +enum timer_mode { + TIMER_MODE_DEFAULT, + TIMER_MODE_SLEEP, +}; + +void timer_install_handler(void); + +u32 timer_get(void); +void timer_wait(u32 ticks); +void timer_install(void); + +#endif -- cgit v1.2.3