diff options
Diffstat (limited to 'kernel/src/arch')
-rw-r--r-- | kernel/src/arch/hosted/mod.rs | 19 | ||||
-rw-r--r-- | kernel/src/arch/mod.rs | 9 | ||||
-rw-r--r-- | kernel/src/arch/riscv64/interrupts.rs | 82 | ||||
-rw-r--r-- | kernel/src/arch/riscv64/mod.rs | 8 |
4 files changed, 118 insertions, 0 deletions
diff --git a/kernel/src/arch/hosted/mod.rs b/kernel/src/arch/hosted/mod.rs new file mode 100644 index 0000000..c1fb0ff --- /dev/null +++ b/kernel/src/arch/hosted/mod.rs @@ -0,0 +1,19 @@ +//! Support for running under an operating system that provides libstd, for testing. + +extern crate std; + +use std::{thread::sleep, time::Duration}; + +/// No-opped interrupt support. +/// +/// TODO: Should this use Unix signals? +pub mod interrupts { + pub fn disable_interrupts() {} +} + +/// Sleeps forever, in one-second chunks. +pub fn sleep_forever() -> ! { + loop { + sleep(Duration::from_secs(1)); + } +} diff --git a/kernel/src/arch/mod.rs b/kernel/src/arch/mod.rs new file mode 100644 index 0000000..d23dd81 --- /dev/null +++ b/kernel/src/arch/mod.rs @@ -0,0 +1,9 @@ +cfg_if::cfg_if! { + if #[cfg(not(target_os = "none"))] { + mod hosted; + pub use self::hosted::*; + } else if #[cfg(target_arch = "riscv64")] { + mod riscv64; + pub use self::riscv64::*; + } +} diff --git a/kernel/src/arch/riscv64/interrupts.rs b/kernel/src/arch/riscv64/interrupts.rs new file mode 100644 index 0000000..302fc4f --- /dev/null +++ b/kernel/src/arch/riscv64/interrupts.rs @@ -0,0 +1,82 @@ +use crate::{ + drivers::riscv_timer::{set_timer, Instant}, + prelude::*, +}; +use core::{ + arch::{asm, global_asm}, + time::Duration, +}; + +/// 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(); +} diff --git a/kernel/src/arch/riscv64/mod.rs b/kernel/src/arch/riscv64/mod.rs new file mode 100644 index 0000000..32731e8 --- /dev/null +++ b/kernel/src/arch/riscv64/mod.rs @@ -0,0 +1,8 @@ +pub mod interrupts; + +/// Halts the hart. +pub fn sleep_forever() -> ! { + loop { + unsafe { core::arch::asm!("wfi") } + } +} |