use core::{ arch::{asm, global_asm}, time::Duration, }; use log::info; use vernos_driver_riscv_timer::{set_timer, Instant}; /// Sets up the timer interrupt. #[inline(never)] pub(crate) fn example_timer() { let now = Instant::now(); info!("now = {now:?}"); let in_a_sec = now + Duration::from_secs(1); info!("in_a_sec = {in_a_sec:?}"); info!("setting a timer for 1s..."); set_timer(in_a_sec); enable_interrupts(); } /// Disables interrupts. pub fn disable_interrupts() { // Set SSTATUS.SIE to 0, which disables interrupts. // // SAFETY: Not running interrupts shouldn't be able to compromise safety. unsafe { asm!( "csrc sstatus, {sie}", sie = in(reg) (1 << 1), options(nomem, nostack) ); } } /// Enables interrupts. pub fn enable_interrupts() { // Set STVEC.BASE to the handler function, and STVEC.MODE to Direct. Since the trap_handler_asm // has a `.align 4` before it, the lower two bits of its address should already be zero. // // SAFETY: Even if interrupts were already enabled, this is a valid handler. unsafe { asm!( "csrw stvec, {stvec}", stvec = in(reg) trap_handler_asm, options(nomem, nostack) ); } // Set SSTATUS.SIE to 1, which enables interrupts. // // SAFETY: We just initialized STVEC, so it should be able to handle interrupts. unsafe { asm!( "csrs sstatus, {sie}", sie = in(reg) (1 << 1), options(nomem, nostack) ); } } fn trap_handler() { todo!("trap_handler") } // The assembly code that calls the Rust trap handler, after saving all caller-save registers // to the stack. global_asm! { // Declare the handler's symbol. ".align 4", "trap_handler_asm:", // TODO "nop", "call {trap_handler}", trap_handler = sym trap_handler } extern "C" { fn trap_handler_asm(); }