feat(adapter-riscv): add trap handling, timer via SBI, and S/U-mode trap vector
This commit is contained in:
@@ -2,6 +2,8 @@
|
|||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
mod page_table;
|
mod page_table;
|
||||||
|
mod timer;
|
||||||
|
mod trap;
|
||||||
mod uart;
|
mod uart;
|
||||||
|
|
||||||
use core::arch::global_asm;
|
use core::arch::global_asm;
|
||||||
@@ -48,6 +50,10 @@ extern "C" fn kmain() -> ! {
|
|||||||
page_table::activate(kernel_pt);
|
page_table::activate(kernel_pt);
|
||||||
uart.write_str("k-os: MMU enabled (Sv39)\n");
|
uart.write_str("k-os: MMU enabled (Sv39)\n");
|
||||||
|
|
||||||
|
trap::init_trap();
|
||||||
|
timer::init_timer();
|
||||||
|
uart.write_str("k-os: traps and timer initialized\n");
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
unsafe { core::arch::asm!("wfi") };
|
unsafe { core::arch::asm!("wfi") };
|
||||||
}
|
}
|
||||||
|
|||||||
28
crates/adapter-riscv/src/timer.rs
Normal file
28
crates/adapter-riscv/src/timer.rs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
const TICK_INTERVAL: u64 = 10_000_000; // 1 second at 10MHz
|
||||||
|
|
||||||
|
pub fn read_time() -> u64 {
|
||||||
|
let time: u64;
|
||||||
|
unsafe { core::arch::asm!("rdtime {0}", out(reg) time) };
|
||||||
|
time
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sbi_set_timer(stime: u64) {
|
||||||
|
unsafe {
|
||||||
|
core::arch::asm!(
|
||||||
|
"ecall",
|
||||||
|
in("a0") stime,
|
||||||
|
in("a6") 0usize,
|
||||||
|
in("a7") 0x54494D45usize, // SBI Timer extension ID
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init_timer() {
|
||||||
|
let now = read_time();
|
||||||
|
sbi_set_timer(now + TICK_INTERVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_timer_interrupt() {
|
||||||
|
let now = read_time();
|
||||||
|
sbi_set_timer(now + TICK_INTERVAL);
|
||||||
|
}
|
||||||
203
crates/adapter-riscv/src/trap.rs
Normal file
203
crates/adapter-riscv/src/trap.rs
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
use core::arch::global_asm;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct TrapFrame {
|
||||||
|
pub regs: [usize; 32], // x0-x31
|
||||||
|
pub sepc: usize,
|
||||||
|
pub sstatus: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TrapFrame {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
regs: [0; 32],
|
||||||
|
sepc: 0,
|
||||||
|
sstatus: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// sscratch = 0 when in S-mode, = kernel_stack_top when in U-mode
|
||||||
|
// On trap: swap sp/sscratch. If sp==0 after swap, we came from S-mode (undo swap).
|
||||||
|
global_asm!(r#"
|
||||||
|
.align 4
|
||||||
|
.globl trap_vector
|
||||||
|
trap_vector:
|
||||||
|
csrrw sp, sscratch, sp
|
||||||
|
bnez sp, _from_user
|
||||||
|
# came from S-mode: sscratch had 0, sp is now 0, old sp is in sscratch
|
||||||
|
csrrw sp, sscratch, sp # undo: sp = old kernel sp, sscratch = 0
|
||||||
|
_from_user:
|
||||||
|
# sp is now a valid kernel stack (either kept or swapped in)
|
||||||
|
addi sp, sp, -272
|
||||||
|
|
||||||
|
sd x1, 8(sp)
|
||||||
|
sd x3, 24(sp)
|
||||||
|
sd x4, 32(sp)
|
||||||
|
sd x5, 40(sp)
|
||||||
|
sd x6, 48(sp)
|
||||||
|
sd x7, 56(sp)
|
||||||
|
sd x8, 64(sp)
|
||||||
|
sd x9, 72(sp)
|
||||||
|
sd x10, 80(sp)
|
||||||
|
sd x11, 88(sp)
|
||||||
|
sd x12, 96(sp)
|
||||||
|
sd x13, 104(sp)
|
||||||
|
sd x14, 112(sp)
|
||||||
|
sd x15, 120(sp)
|
||||||
|
sd x16, 128(sp)
|
||||||
|
sd x17, 136(sp)
|
||||||
|
sd x18, 144(sp)
|
||||||
|
sd x19, 152(sp)
|
||||||
|
sd x20, 160(sp)
|
||||||
|
sd x21, 168(sp)
|
||||||
|
sd x22, 176(sp)
|
||||||
|
sd x23, 184(sp)
|
||||||
|
sd x24, 192(sp)
|
||||||
|
sd x25, 200(sp)
|
||||||
|
sd x26, 208(sp)
|
||||||
|
sd x27, 216(sp)
|
||||||
|
sd x28, 224(sp)
|
||||||
|
sd x29, 232(sp)
|
||||||
|
sd x30, 240(sp)
|
||||||
|
sd x31, 248(sp)
|
||||||
|
|
||||||
|
# save user sp from sscratch (0 if from S-mode, user sp if from U-mode)
|
||||||
|
csrr t0, sscratch
|
||||||
|
sd t0, 16(sp)
|
||||||
|
|
||||||
|
csrr t0, sepc
|
||||||
|
sd t0, 256(sp)
|
||||||
|
csrr t0, sstatus
|
||||||
|
sd t0, 264(sp)
|
||||||
|
|
||||||
|
mv a0, sp
|
||||||
|
call trap_handler_rust
|
||||||
|
|
||||||
|
ld t0, 256(sp)
|
||||||
|
csrw sepc, t0
|
||||||
|
ld t0, 264(sp)
|
||||||
|
csrw sstatus, t0
|
||||||
|
|
||||||
|
# check if returning to U-mode: sstatus.SPP (bit 8)
|
||||||
|
# if SPP=0 (user mode), restore sscratch with user sp
|
||||||
|
andi t1, t0, 0x100
|
||||||
|
bnez t1, _restore_smode
|
||||||
|
|
||||||
|
# returning to U-mode: put user sp in sscratch
|
||||||
|
ld t0, 16(sp)
|
||||||
|
csrw sscratch, t0
|
||||||
|
|
||||||
|
_restore_smode:
|
||||||
|
ld x1, 8(sp)
|
||||||
|
ld x3, 24(sp)
|
||||||
|
ld x4, 32(sp)
|
||||||
|
ld x5, 40(sp)
|
||||||
|
ld x6, 48(sp)
|
||||||
|
ld x7, 56(sp)
|
||||||
|
ld x8, 64(sp)
|
||||||
|
ld x9, 72(sp)
|
||||||
|
ld x10, 80(sp)
|
||||||
|
ld x11, 88(sp)
|
||||||
|
ld x12, 96(sp)
|
||||||
|
ld x13, 104(sp)
|
||||||
|
ld x14, 112(sp)
|
||||||
|
ld x15, 120(sp)
|
||||||
|
ld x16, 128(sp)
|
||||||
|
ld x17, 136(sp)
|
||||||
|
ld x18, 144(sp)
|
||||||
|
ld x19, 152(sp)
|
||||||
|
ld x20, 160(sp)
|
||||||
|
ld x21, 168(sp)
|
||||||
|
ld x22, 176(sp)
|
||||||
|
ld x23, 184(sp)
|
||||||
|
ld x24, 192(sp)
|
||||||
|
ld x25, 200(sp)
|
||||||
|
ld x26, 208(sp)
|
||||||
|
ld x27, 216(sp)
|
||||||
|
ld x28, 224(sp)
|
||||||
|
ld x29, 232(sp)
|
||||||
|
ld x30, 240(sp)
|
||||||
|
ld x31, 248(sp)
|
||||||
|
|
||||||
|
addi sp, sp, 272
|
||||||
|
|
||||||
|
# if returning to U-mode, swap sp/sscratch to restore user sp
|
||||||
|
csrr t0, sstatus
|
||||||
|
andi t0, t0, 0x100
|
||||||
|
bnez t0, _sret_smode
|
||||||
|
csrrw sp, sscratch, sp # sp = user sp, sscratch = kernel sp (for next trap)
|
||||||
|
_sret_smode:
|
||||||
|
sret
|
||||||
|
"#);
|
||||||
|
|
||||||
|
const CAUSE_INTERRUPT_BIT: usize = 1 << 63;
|
||||||
|
const CAUSE_S_TIMER: usize = 5;
|
||||||
|
const CAUSE_S_EXTERNAL: usize = 9;
|
||||||
|
const CAUSE_ECALL_U: usize = 8;
|
||||||
|
|
||||||
|
pub fn init_trap() {
|
||||||
|
unsafe extern "C" {
|
||||||
|
fn trap_vector();
|
||||||
|
}
|
||||||
|
unsafe {
|
||||||
|
let addr = trap_vector as usize;
|
||||||
|
core::arch::asm!("csrw stvec, {0}", in(reg) addr);
|
||||||
|
|
||||||
|
// sscratch = 0 means "currently in S-mode"
|
||||||
|
core::arch::asm!("csrw sscratch, zero");
|
||||||
|
|
||||||
|
// enable supervisor interrupts
|
||||||
|
core::arch::asm!("csrs sstatus, {0}", in(reg) 1usize << 1);
|
||||||
|
|
||||||
|
// enable timer + external + software interrupts in sie
|
||||||
|
let sie_bits = (1usize << 5) | (1usize << 9) | (1usize << 1);
|
||||||
|
core::arch::asm!("csrs sie, {0}", in(reg) sie_bits);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_kernel_stack(kernel_sp: usize) {
|
||||||
|
unsafe {
|
||||||
|
core::arch::asm!("csrw sscratch, {0}", in(reg) kernel_sp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
extern "C" fn trap_handler_rust(frame: &mut TrapFrame) {
|
||||||
|
let scause: usize;
|
||||||
|
unsafe { core::arch::asm!("csrr {0}, scause", out(reg) scause) };
|
||||||
|
|
||||||
|
let uart = crate::uart::Uart::new();
|
||||||
|
|
||||||
|
if scause & CAUSE_INTERRUPT_BIT != 0 {
|
||||||
|
let cause = scause & !CAUSE_INTERRUPT_BIT;
|
||||||
|
match cause {
|
||||||
|
CAUSE_S_TIMER => {
|
||||||
|
crate::timer::handle_timer_interrupt();
|
||||||
|
}
|
||||||
|
CAUSE_S_EXTERNAL => {
|
||||||
|
uart.write_str("[EXT]");
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match scause {
|
||||||
|
CAUSE_ECALL_U => {
|
||||||
|
frame.sepc += 4;
|
||||||
|
uart.write_str("[ecall]\n");
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
uart.write_str("FAULT: scause=");
|
||||||
|
uart.write_hex(scause);
|
||||||
|
let stval: usize;
|
||||||
|
unsafe { core::arch::asm!("csrr {0}, stval", out(reg) stval) };
|
||||||
|
uart.write_str(" stval=");
|
||||||
|
uart.write_hex(stval);
|
||||||
|
uart.write_str(" sepc=");
|
||||||
|
uart.write_hex(frame.sepc);
|
||||||
|
uart.put_char(b'\n');
|
||||||
|
loop { unsafe { core::arch::asm!("wfi") }; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user