diff --git a/src/boot/traps.S b/src/boot/traps.S index 9c2f024..ed84028 100644 --- a/src/boot/traps.S +++ b/src/boot/traps.S @@ -4,10 +4,10 @@ .global trap_entry trap_entry: - # Create space on the stack for 32 registers (32 * 8 = 256 bytes) - addi sp, sp, -256 + # Allocate stack space for GPRs (256 bytes) + FPU registers (512 bytes) + addi sp, sp, -768 # Total: 256 (GPRs) + 512 (FPU) - # Save all General Purpose Registers (GPRs) + # --- Save GPRs --- sd ra, 0(sp) sd gp, 8(sp) sd tp, 16(sp) @@ -39,19 +39,112 @@ trap_entry: sd t5, 224(sp) sd t6, 232(sp) - # Save mepc to the stack (using offset 240) + # --- Save mepc/mcause/mstatus --- csrr t0, mepc sd t0, 240(sp) + csrr t0, mcause + sd t0, 248(sp) + csrr t0, mstatus + sd t0, 256(sp) - # Call trap handler - mv a0, sp # put the stack pointer to the first arg + # --- Check FPU Status (mstatus.FS) --- + csrr t1, mstatus + li t2, 0x6000 + and t1, t1, t2 + bnez t1, save_fpu + + # If no FPU, skip to handler + j call_handler + +save_fpu: + # Save FPU registers (f0-f31) starting at offset 256 + fsd f0, 256(sp) + fsd f1, 264(sp) + fsd f2, 272(sp) + fsd f3, 280(sp) + fsd f4, 288(sp) + fsd f5, 296(sp) + fsd f6, 304(sp) + fsd f7, 312(sp) + fsd f8, 320(sp) + fsd f9, 328(sp) + fsd f10, 336(sp) + fsd f11, 344(sp) + fsd f12, 352(sp) + fsd f13, 360(sp) + fsd f14, 368(sp) + fsd f15, 376(sp) + fsd f16, 384(sp) + fsd f17, 392(sp) + fsd f18, 400(sp) + fsd f19, 408(sp) + fsd f20, 416(sp) + fsd f21, 424(sp) + fsd f22, 432(sp) + fsd f23, 440(sp) + fsd f24, 448(sp) + fsd f25, 456(sp) + fsd f26, 464(sp) + fsd f27, 472(sp) + fsd f28, 480(sp) + fsd f29, 488(sp) + fsd f30, 496(sp) + fsd f31, 504(sp) + +call_handler: + # Pass stack pointer to C handler + mv a0, sp call handle_trap - # restore mepc + # --- Restore mepc --- ld t0, 240(sp) csrw mepc, t0 - # Restore all GPRs + # --- Restore FPU (if it was saved) --- + csrr t1, mstatus + li t2, 0x6000 + and t1, t1, t2 + bnez t1, restore_fpu + + j restore_gpr + +restore_fpu: + # Restore FPU registers + fld f0, 256(sp) + fld f1, 264(sp) + fld f2, 272(sp) + fld f3, 280(sp) + fld f4, 288(sp) + fld f5, 296(sp) + fld f6, 304(sp) + fld f7, 312(sp) + fld f8, 320(sp) + fld f9, 328(sp) + fld f10, 336(sp) + fld f11, 344(sp) + fld f12, 352(sp) + fld f13, 360(sp) + fld f14, 368(sp) + fld f15, 376(sp) + fld f16, 384(sp) + fld f17, 392(sp) + fld f18, 400(sp) + fld f19, 408(sp) + fld f20, 416(sp) + fld f21, 424(sp) + fld f22, 432(sp) + fld f23, 440(sp) + fld f24, 448(sp) + fld f25, 456(sp) + fld f26, 464(sp) + fld f27, 472(sp) + fld f28, 480(sp) + fld f29, 488(sp) + fld f30, 496(sp) + fld f31, 504(sp) + +restore_gpr: + # Restore GPRs ld ra, 0(sp) ld gp, 8(sp) ld tp, 16(sp) @@ -83,8 +176,6 @@ trap_entry: ld t5, 224(sp) ld t6, 232(sp) - # Shrink the stack back - addi sp, sp, 256 - - # Return from Machine-mode trap + # Restore stack pointer + addi sp, sp, 768 mret \ No newline at end of file diff --git a/src/drivers/uart.c b/src/drivers/uart.c index a2c216a..df5d4fd 100644 --- a/src/drivers/uart.c +++ b/src/drivers/uart.c @@ -137,7 +137,8 @@ void kprintf_internal(const char *format, va_list args) if (*p == '%') { p++; - if(*p == '\0') break; + if (*p == '\0') + break; switch (*p) { case 'c': @@ -149,7 +150,8 @@ void kprintf_internal(const char *format, va_list args) case 's': { char *s = va_arg(args, char *); - if (!s) s = "(null)"; + if (!s) + s = "(null)"; kprint(s); break; } @@ -159,12 +161,12 @@ void kprintf_internal(const char *format, va_list args) kprint_int(d); break; } - case 'u': - { + case 'u': + { unsigned int u = va_arg(args, unsigned int); kprint_int((int)u); break; - } + } case 'f': { double f = va_arg(args, double); @@ -174,11 +176,11 @@ void kprintf_internal(const char *format, va_list args) case 'x': // Hex case 'p': // Pointer { - #if UINTPTR_MAX == 0xffffffffULL - unsigned int x = va_arg(args, unsigned int); - #else - uint64_t x = va_arg(args, uint64_t); - #endif +#if UINTPTR_MAX == 0xffffffffULL + unsigned int x = va_arg(args, unsigned int); +#else + uint64_t x = va_arg(args, uint64_t); +#endif kprint_hex(x); break; } diff --git a/src/kernel/interrupts.c b/src/kernel/interrupts.c index ac14bb2..c700b19 100644 --- a/src/kernel/interrupts.c +++ b/src/kernel/interrupts.c @@ -8,6 +8,7 @@ #include #include + void interrupt_init() { kprint("Initialising Interrupts..."); @@ -22,6 +23,17 @@ void interrupt_init() mie_val |= (1 << MIE_BIT_MEIE) | (1 << MIE_BIT_MTIE); asm volatile("csrw mie, %0" ::"r"(mie_val)); kputs("OK"); + + uint32_t mie, sie, mstatus; + asm volatile ("csrr %0, mie" : "=r"(mie)); + asm volatile ("csrr %0, sie" : "=r"(sie)); + asm volatile ("csrr %0, mstatus" : "=r"(mstatus)); + kprintf("mie: 0x%X, sie: 0x%X, mstatus: 0x%X\n", mie, sie, mstatus); + + // Enable timer and global interrupts + asm volatile ("csrs mie, %0" : : "r"(mie | (1 << 7) | (1 << 3))); // Enable timer and global + asm volatile ("csrs sie, %0" : : "r"(sie | (1 << 7) | (1 << 3))); // Enable timer and global + asm volatile ("csrs mstatus, %0" : : "r"(mstatus | (1 << 3))); // Set MIE bit } void kpanic(const char *reason, ...) @@ -55,15 +67,11 @@ void kpanic_force() void handle_trap(trap_frame_t *registers) { - // Read the 'mcause' register to see WHY we trapped - unsigned long cause; - __asm__ volatile("csrr %0, mcause" : "=r"(cause)); - // Check if the top bit is 1 (Interrupt) or 0 (Exception) // For 64-bit RISC-V, the bit is 63 - int is_interrupt = (cause >> 63) & 1; + int is_interrupt = (registers->mcause >> 63) & 1; - unsigned long code = cause & 0xfff; + unsigned long code = registers->mcause & 0xfff; if (is_interrupt) { @@ -78,7 +86,7 @@ void handle_trap(trap_frame_t *registers) kprintf("\n[EXCEPTION] Code: %d | Instruction: %x | Fault Address: %x\n", code, registers->mepc, mtval); - switch (cause) + switch (registers->mcause) { case 0: kpanic("Reason: Instruction Address Misaligned\n"); @@ -105,7 +113,7 @@ void handle_trap(trap_frame_t *registers) kpanic("Reason: Store/AMO Access Fault\n"); break; default: - kpanic("Reason: Unknown Exception Code %d\n", cause); + kpanic("Reason: Unknown Exception Code %d\n", registers->mcause); break; } } @@ -116,8 +124,7 @@ void handle_interrupt(unsigned long code) switch (code) { case 7: - timer_handle_interrupt(); - + timer_tick(); break; case 11: volatile uint32_t *claim_reg = (uint32_t *)PLIC_CLAIM(0); diff --git a/src/kernel/interrupts.h b/src/kernel/interrupts.h index 0bd683d..8d108fb 100644 --- a/src/kernel/interrupts.h +++ b/src/kernel/interrupts.h @@ -3,6 +3,8 @@ #define MSTATUS 0x300 #define MIE 0x304 +#define MCAUSE 0x342 +#define MEPC 0x341 #define MSTATUS_BIT_MIE 3 #define MIE_BIT_MTIE 7 #define MIE_BIT_MEIE 11 @@ -56,8 +58,10 @@ typedef struct { uint64_t t5; // x30 uint64_t t6; // x31 - // Control and Status Register state - uint64_t mepc; // offset 240 (Saved in traps.S) + // Control and Status Register state (Saved in traps.S) + uint64_t mepc; // offset 240 + uint64_t mcause; // offset 248 + uint64_t mstatus; // offset 256 } trap_frame_t; void interrupt_init(); 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..f482fa8 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 7) + *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..cca2c60 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 7 void plic_init(); diff --git a/src/kernel/timer.c b/src/kernel/timer.c index 530c6fd..03320da 100644 --- a/src/kernel/timer.c +++ b/src/kernel/timer.c @@ -1,12 +1,43 @@ #include -#include -#include -#include +#include +#include "timer.h" +#include "plic.h" +#include "interrupts.h" +#include "drivers/uart.h" -void timer_handle_interrupt() -{ - static volatile uint64_t *mtime = (uint64_t *)CLINT_MTIME; - static volatile uint64_t *mtimecmp = (uint64_t *)CLINT_MTIMECMP(0); +_Atomic uint64_t sys_ticks = 0; +const uint64_t tick_delta = TICKS_PER_MS; - *mtimecmp = *mtime + TIMER_FREQ; +void timer_init() { + timer_tick(); +} + +void timer_tick() { + static volatile uint64_t *mtime = (uint64_t *)CLINT_MTIME; + static volatile uint64_t *mtimecmp = (uint64_t *)CLINT_MTIMECMP(0); + uint64_t current_mtime = *mtime; + uint64_t new_mtimecmp = current_mtime + tick_delta; + *mtimecmp = new_mtimecmp; + //kprintf("Set mtimecmp: %u (mtime: %u, delta: %u)\n", new_mtimecmp, current_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 index 3b6f452..089010f 100644 --- a/src/kernel/timer.h +++ b/src/kernel/timer.h @@ -1,8 +1,30 @@ -#ifndef KTIMER_H -#define KTIMER_H +#ifndef TIMER_H +#define TIMER_H +#include -#define TIMER_FREQ 100000 +/* Define your clock frequency here based on your hardware */ +/* Example: 12.5 MHz for QEMU virt machine */ +#define CLOCK_FREQ_HZ 12500000 -void timer_handle_interrupt(); +/* Calculate ticks per millisecond */ +#define TICKS_PER_MS (CLOCK_FREQ_HZ / 1000) + +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 diff --git a/src/lib/string.h b/src/lib/string.h index 78ae169..5ad4eee 100644 --- a/src/lib/string.h +++ b/src/lib/string.h @@ -2,5 +2,8 @@ #define STRING_H void *memset(void *s, int c, size_t n); +void *memcpy(void *dest, const void *src, size_t n); +int strcmp(const char *str1, const char *str2); +size_t strlen(const char *s); #endif \ No newline at end of file