From ebdd572f8ee6493dd8e61d8d82c1d3ad5f10ac9f Mon Sep 17 00:00:00 2001 From: Liam Kerr Date: Fri, 1 May 2026 23:14:44 +0100 Subject: [PATCH] feat: implement basic timer --- src/kernel/interrupts.c | 6 +++--- src/kernel/kernel.c | 10 ++++++++++ src/kernel/plic.c | 8 +++++++- src/kernel/plic.h | 1 + src/kernel/timer.c | 39 +++++++++++++++++++++++++++++++++++++++ src/kernel/timer.h | 23 +++++++++++++++++++++++ 6 files changed, 83 insertions(+), 4 deletions(-) create mode 100644 src/kernel/timer.c create mode 100644 src/kernel/timer.h diff --git a/src/kernel/interrupts.c b/src/kernel/interrupts.c index 479e7c3..366f1c3 100644 --- a/src/kernel/interrupts.c +++ b/src/kernel/interrupts.c @@ -6,6 +6,8 @@ #include #include #include +#include + void interrupt_init() { @@ -111,9 +113,7 @@ void handle_interrupt(unsigned long code) switch (code) { case 7: - static volatile uint64_t *mtime = (uint64_t *)CLINT_MTIME; - static volatile uint64_t *mtimecmp = (uint64_t *)CLINT_MTIMECMP(0); - *mtimecmp = *mtime + 100000; + timer_tick(); break; case 11: volatile uint32_t *claim_reg = (uint32_t *)PLIC_CLAIM(0); diff --git a/src/kernel/kernel.c b/src/kernel/kernel.c index 1d935c3..da2a669 100644 --- a/src/kernel/kernel.c +++ b/src/kernel/kernel.c @@ -5,11 +5,13 @@ #include #include #include +#include void kmain() { zero_bss(); plic_init(); + timer_init(); uart_init(); page_init(); interrupt_init(); @@ -17,4 +19,12 @@ void kmain() kprintf("Hello, from %s!", "SquidgeOS"); kputs("----------------------"); knewline(); + while (1) { + uint64_t ticks = timer_get_ms(); + kputchar('T'); + kputchar(':'); // Print "T:1234" every second + kprint_int(ticks); + knewline(); + delay_ms(1000); + } } diff --git a/src/kernel/plic.c b/src/kernel/plic.c index 5a14838..86e6792 100644 --- a/src/kernel/plic.c +++ b/src/kernel/plic.c @@ -13,7 +13,13 @@ void plic_init() // This is a bitmask, so we shift 1 by the IRQ number. *PLIC_ENABLE(hart) = (1 << UART_IRQ); + // Set priority for CLINT timer interrupt (IRQ 5) + *PLIC_PRIORITY(TIMER_IRQ) = 1; // Lowest priority + + // Enable CLINT timer interrupt for Hart 0 + *PLIC_ENABLE(hart) |= (1 << TIMER_IRQ); + // 3. Set the priority threshold for Hart 0 // We set this to 0 so that ANY interrupt with priority > 0 gets through. *PLIC_THRESHOLD(hart) = 0; -} \ No newline at end of file +} diff --git a/src/kernel/plic.h b/src/kernel/plic.h index 9235164..3e72087 100644 --- a/src/kernel/plic.h +++ b/src/kernel/plic.h @@ -16,6 +16,7 @@ #define PLIC_CLAIM(hart) ((volatile uint32_t *)(PLIC_BASE + 0x200004 + (hart) * 0x1000)) #define UART_IRQ 10 +#define TIMER_IRQ 5 void plic_init(); diff --git a/src/kernel/timer.c b/src/kernel/timer.c new file mode 100644 index 0000000..2267aef --- /dev/null +++ b/src/kernel/timer.c @@ -0,0 +1,39 @@ +#include +#include "timer.h" +#include "plic.h" +#include "interrupts.h" + +_Atomic uint64_t sys_ticks = 0; +const uint64_t tick_delta = 1000; + +void timer_init() { + timer_tick(); +} + +void timer_tick() { + // Set the first timer interrupt to fire after 1ms + static volatile uint64_t *mtime = (uint64_t *)CLINT_MTIME; + static volatile uint64_t *mtimecmp = (uint64_t *)CLINT_MTIMECMP(0); + *mtimecmp = *mtime + tick_delta; + sys_ticks++; +} + +// Get current time in milliseconds +uint64_t timer_get_ms() { + return sys_ticks; +} + +// Delay for 'ms' milliseconds (blocking) +void delay_ms(uint64_t ms) { + if (ms == 0) return; + uint64_t end = sys_ticks + ms; + while (sys_ticks < end) { + asm volatile("wfi"); + } +} + +// Sleep for 'ms' milliseconds (non-blocking, if possible) +// For now, just call delay_ms (can be improved later) +void sleep_ms(uint64_t ms) { + delay_ms(ms); +} \ No newline at end of file diff --git a/src/kernel/timer.h b/src/kernel/timer.h new file mode 100644 index 0000000..ac0a2af --- /dev/null +++ b/src/kernel/timer.h @@ -0,0 +1,23 @@ +#ifndef TIMER_H +#define TIMER_H +#include + +extern _Atomic uint64_t sys_ticks; +extern const uint64_t tick_delta; + +// Initialize timer (1ms ticks) +void timer_init(); + +// Increment the system tick counter +void timer_tick(); + +// Get current time in milliseconds +uint64_t timer_get_ms(); + +// Delay for 'ms' milliseconds (blocking) +void delay_ms(uint64_t ms); + +// Sleep for 'ms' milliseconds (non-blocking, if possible) +void sleep_ms(uint64_t ms); + +#endif \ No newline at end of file