feat: implement basic timer

This commit is contained in:
Liam Kerr 2026-05-01 23:14:44 +01:00
parent f76ca1ee31
commit ebdd572f8e
6 changed files with 83 additions and 4 deletions

View file

@ -6,6 +6,8 @@
#include <kernel/plic.h>
#include <kernel/interrupts.h>
#include <kernel/memory.h>
#include <kernel/timer.h>
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);

View file

@ -5,11 +5,13 @@
#include <kernel/plic.h>
#include <kernel/interrupts.h>
#include <kernel/memory.h>
#include <kernel/timer.h>
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);
}
}

View file

@ -13,6 +13,12 @@ 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;

View file

@ -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();

39
src/kernel/timer.c Normal file
View file

@ -0,0 +1,39 @@
#include <stdint.h>
#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);
}

23
src/kernel/timer.h Normal file
View file

@ -0,0 +1,23 @@
#ifndef TIMER_H
#define TIMER_H
#include <stdint.h>
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