Compare commits
6 commits
feature/ti
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 57a21bd4e2 | |||
| 40333f1a37 | |||
| 5f09049765 | |||
| ebdd572f8e | |||
| f76ca1ee31 | |||
| 0176b636c5 |
10 changed files with 224 additions and 47 deletions
115
src/boot/traps.S
115
src/boot/traps.S
|
|
@ -4,10 +4,10 @@
|
||||||
.global trap_entry
|
.global trap_entry
|
||||||
|
|
||||||
trap_entry:
|
trap_entry:
|
||||||
# Create space on the stack for 32 registers (32 * 8 = 256 bytes)
|
# Allocate stack space for GPRs (256 bytes) + FPU registers (512 bytes)
|
||||||
addi sp, sp, -256
|
addi sp, sp, -768 # Total: 256 (GPRs) + 512 (FPU)
|
||||||
|
|
||||||
# Save all General Purpose Registers (GPRs)
|
# --- Save GPRs ---
|
||||||
sd ra, 0(sp)
|
sd ra, 0(sp)
|
||||||
sd gp, 8(sp)
|
sd gp, 8(sp)
|
||||||
sd tp, 16(sp)
|
sd tp, 16(sp)
|
||||||
|
|
@ -39,19 +39,112 @@ trap_entry:
|
||||||
sd t5, 224(sp)
|
sd t5, 224(sp)
|
||||||
sd t6, 232(sp)
|
sd t6, 232(sp)
|
||||||
|
|
||||||
# Save mepc to the stack (using offset 240)
|
# --- Save mepc/mcause/mstatus ---
|
||||||
csrr t0, mepc
|
csrr t0, mepc
|
||||||
sd t0, 240(sp)
|
sd t0, 240(sp)
|
||||||
|
csrr t0, mcause
|
||||||
|
sd t0, 248(sp)
|
||||||
|
csrr t0, mstatus
|
||||||
|
sd t0, 256(sp)
|
||||||
|
|
||||||
# Call trap handler
|
# --- Check FPU Status (mstatus.FS) ---
|
||||||
mv a0, sp # put the stack pointer to the first arg
|
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
|
call handle_trap
|
||||||
|
|
||||||
# restore mepc
|
# --- Restore mepc ---
|
||||||
ld t0, 240(sp)
|
ld t0, 240(sp)
|
||||||
csrw mepc, t0
|
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 ra, 0(sp)
|
||||||
ld gp, 8(sp)
|
ld gp, 8(sp)
|
||||||
ld tp, 16(sp)
|
ld tp, 16(sp)
|
||||||
|
|
@ -83,8 +176,6 @@ trap_entry:
|
||||||
ld t5, 224(sp)
|
ld t5, 224(sp)
|
||||||
ld t6, 232(sp)
|
ld t6, 232(sp)
|
||||||
|
|
||||||
# Shrink the stack back
|
# Restore stack pointer
|
||||||
addi sp, sp, 256
|
addi sp, sp, 768
|
||||||
|
|
||||||
# Return from Machine-mode trap
|
|
||||||
mret
|
mret
|
||||||
|
|
@ -137,7 +137,8 @@ void kprintf_internal(const char *format, va_list args)
|
||||||
if (*p == '%')
|
if (*p == '%')
|
||||||
{
|
{
|
||||||
p++;
|
p++;
|
||||||
if(*p == '\0') break;
|
if (*p == '\0')
|
||||||
|
break;
|
||||||
switch (*p)
|
switch (*p)
|
||||||
{
|
{
|
||||||
case 'c':
|
case 'c':
|
||||||
|
|
@ -149,7 +150,8 @@ void kprintf_internal(const char *format, va_list args)
|
||||||
case 's':
|
case 's':
|
||||||
{
|
{
|
||||||
char *s = va_arg(args, char *);
|
char *s = va_arg(args, char *);
|
||||||
if (!s) s = "(null)";
|
if (!s)
|
||||||
|
s = "(null)";
|
||||||
kprint(s);
|
kprint(s);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -174,11 +176,11 @@ void kprintf_internal(const char *format, va_list args)
|
||||||
case 'x': // Hex
|
case 'x': // Hex
|
||||||
case 'p': // Pointer
|
case 'p': // Pointer
|
||||||
{
|
{
|
||||||
#if UINTPTR_MAX == 0xffffffffULL
|
#if UINTPTR_MAX == 0xffffffffULL
|
||||||
unsigned int x = va_arg(args, unsigned int);
|
unsigned int x = va_arg(args, unsigned int);
|
||||||
#else
|
#else
|
||||||
uint64_t x = va_arg(args, uint64_t);
|
uint64_t x = va_arg(args, uint64_t);
|
||||||
#endif
|
#endif
|
||||||
kprint_hex(x);
|
kprint_hex(x);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
#include <kernel/memory.h>
|
#include <kernel/memory.h>
|
||||||
#include <kernel/timer.h>
|
#include <kernel/timer.h>
|
||||||
|
|
||||||
|
|
||||||
void interrupt_init()
|
void interrupt_init()
|
||||||
{
|
{
|
||||||
kprint("Initialising Interrupts...");
|
kprint("Initialising Interrupts...");
|
||||||
|
|
@ -22,6 +23,17 @@ void interrupt_init()
|
||||||
mie_val |= (1 << MIE_BIT_MEIE) | (1 << MIE_BIT_MTIE);
|
mie_val |= (1 << MIE_BIT_MEIE) | (1 << MIE_BIT_MTIE);
|
||||||
asm volatile("csrw mie, %0" ::"r"(mie_val));
|
asm volatile("csrw mie, %0" ::"r"(mie_val));
|
||||||
kputs("OK");
|
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, ...)
|
void kpanic(const char *reason, ...)
|
||||||
|
|
@ -55,15 +67,11 @@ void kpanic_force()
|
||||||
|
|
||||||
void handle_trap(trap_frame_t *registers)
|
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)
|
// Check if the top bit is 1 (Interrupt) or 0 (Exception)
|
||||||
// For 64-bit RISC-V, the bit is 63
|
// 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)
|
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);
|
kprintf("\n[EXCEPTION] Code: %d | Instruction: %x | Fault Address: %x\n", code, registers->mepc, mtval);
|
||||||
|
|
||||||
switch (cause)
|
switch (registers->mcause)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
kpanic("Reason: Instruction Address Misaligned\n");
|
kpanic("Reason: Instruction Address Misaligned\n");
|
||||||
|
|
@ -105,7 +113,7 @@ void handle_trap(trap_frame_t *registers)
|
||||||
kpanic("Reason: Store/AMO Access Fault\n");
|
kpanic("Reason: Store/AMO Access Fault\n");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
kpanic("Reason: Unknown Exception Code %d\n", cause);
|
kpanic("Reason: Unknown Exception Code %d\n", registers->mcause);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -116,8 +124,7 @@ void handle_interrupt(unsigned long code)
|
||||||
switch (code)
|
switch (code)
|
||||||
{
|
{
|
||||||
case 7:
|
case 7:
|
||||||
timer_handle_interrupt();
|
timer_tick();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 11:
|
case 11:
|
||||||
volatile uint32_t *claim_reg = (uint32_t *)PLIC_CLAIM(0);
|
volatile uint32_t *claim_reg = (uint32_t *)PLIC_CLAIM(0);
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#define MSTATUS 0x300
|
#define MSTATUS 0x300
|
||||||
#define MIE 0x304
|
#define MIE 0x304
|
||||||
|
#define MCAUSE 0x342
|
||||||
|
#define MEPC 0x341
|
||||||
#define MSTATUS_BIT_MIE 3
|
#define MSTATUS_BIT_MIE 3
|
||||||
#define MIE_BIT_MTIE 7
|
#define MIE_BIT_MTIE 7
|
||||||
#define MIE_BIT_MEIE 11
|
#define MIE_BIT_MEIE 11
|
||||||
|
|
@ -56,8 +58,10 @@ typedef struct {
|
||||||
uint64_t t5; // x30
|
uint64_t t5; // x30
|
||||||
uint64_t t6; // x31
|
uint64_t t6; // x31
|
||||||
|
|
||||||
// Control and Status Register state
|
// Control and Status Register state (Saved in traps.S)
|
||||||
uint64_t mepc; // offset 240 (Saved in traps.S)
|
uint64_t mepc; // offset 240
|
||||||
|
uint64_t mcause; // offset 248
|
||||||
|
uint64_t mstatus; // offset 256
|
||||||
} trap_frame_t;
|
} trap_frame_t;
|
||||||
|
|
||||||
void interrupt_init();
|
void interrupt_init();
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,13 @@
|
||||||
#include <kernel/plic.h>
|
#include <kernel/plic.h>
|
||||||
#include <kernel/interrupts.h>
|
#include <kernel/interrupts.h>
|
||||||
#include <kernel/memory.h>
|
#include <kernel/memory.h>
|
||||||
|
#include <kernel/timer.h>
|
||||||
|
|
||||||
void kmain()
|
void kmain()
|
||||||
{
|
{
|
||||||
zero_bss();
|
zero_bss();
|
||||||
plic_init();
|
plic_init();
|
||||||
|
timer_init();
|
||||||
uart_init();
|
uart_init();
|
||||||
page_init();
|
page_init();
|
||||||
interrupt_init();
|
interrupt_init();
|
||||||
|
|
@ -17,4 +19,12 @@ void kmain()
|
||||||
kprintf("Hello, from %s!", "SquidgeOS");
|
kprintf("Hello, from %s!", "SquidgeOS");
|
||||||
kputs("----------------------");
|
kputs("----------------------");
|
||||||
knewline();
|
knewline();
|
||||||
|
while (1) {
|
||||||
|
uint64_t ticks = timer_get_ms();
|
||||||
|
kputchar('T');
|
||||||
|
kputchar(':'); // Print "T:1234" every second
|
||||||
|
kprint_int(ticks);
|
||||||
|
knewline();
|
||||||
|
delay_ms(1000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,12 @@ void plic_init()
|
||||||
// This is a bitmask, so we shift 1 by the IRQ number.
|
// This is a bitmask, so we shift 1 by the IRQ number.
|
||||||
*PLIC_ENABLE(hart) = (1 << UART_IRQ);
|
*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
|
// 3. Set the priority threshold for Hart 0
|
||||||
// We set this to 0 so that ANY interrupt with priority > 0 gets through.
|
// We set this to 0 so that ANY interrupt with priority > 0 gets through.
|
||||||
*PLIC_THRESHOLD(hart) = 0;
|
*PLIC_THRESHOLD(hart) = 0;
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
#define PLIC_CLAIM(hart) ((volatile uint32_t *)(PLIC_BASE + 0x200004 + (hart) * 0x1000))
|
#define PLIC_CLAIM(hart) ((volatile uint32_t *)(PLIC_BASE + 0x200004 + (hart) * 0x1000))
|
||||||
|
|
||||||
#define UART_IRQ 10
|
#define UART_IRQ 10
|
||||||
|
#define TIMER_IRQ 7
|
||||||
|
|
||||||
void plic_init();
|
void plic_init();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,43 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <kernel/interrupts.h>
|
#include <stddef.h>
|
||||||
#include <kernel/plic.h>
|
#include "timer.h"
|
||||||
#include <kernel/timer.h>
|
#include "plic.h"
|
||||||
|
#include "interrupts.h"
|
||||||
|
#include "drivers/uart.h"
|
||||||
|
|
||||||
void timer_handle_interrupt()
|
_Atomic uint64_t sys_ticks = 0;
|
||||||
{
|
const uint64_t tick_delta = TICKS_PER_MS;
|
||||||
|
|
||||||
|
void timer_init() {
|
||||||
|
timer_tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
void timer_tick() {
|
||||||
static volatile uint64_t *mtime = (uint64_t *)CLINT_MTIME;
|
static volatile uint64_t *mtime = (uint64_t *)CLINT_MTIME;
|
||||||
static volatile uint64_t *mtimecmp = (uint64_t *)CLINT_MTIMECMP(0);
|
static volatile uint64_t *mtimecmp = (uint64_t *)CLINT_MTIMECMP(0);
|
||||||
|
uint64_t current_mtime = *mtime;
|
||||||
*mtimecmp = *mtime + TIMER_FREQ;
|
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);
|
||||||
}
|
}
|
||||||
|
|
@ -1,8 +1,30 @@
|
||||||
#ifndef KTIMER_H
|
#ifndef TIMER_H
|
||||||
#define KTIMER_H
|
#define TIMER_H
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#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
|
#endif
|
||||||
|
|
@ -2,5 +2,8 @@
|
||||||
#define STRING_H
|
#define STRING_H
|
||||||
|
|
||||||
void *memset(void *s, int c, size_t n);
|
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
|
#endif
|
||||||
Loading…
Add table
Add a link
Reference in a new issue