From f46f3ddc313c01c8333e0ba778149c884712175d Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Fri, 17 Jan 2025 03:28:00 +0200 Subject: [PATCH] rv64: implement M-/S-mode trap stubs --- kernel/arch/riscv64/src/registers.rs | 130 +++++++++++++++++++++++++++ kernel/src/arch/riscv64/boot/mod.rs | 16 +++- kernel/src/arch/riscv64/exception.rs | 28 ++++++ kernel/src/arch/riscv64/mod.rs | 1 + kernel/src/arch/riscv64/vectors.S | 62 +++++++++++++ 5 files changed, 236 insertions(+), 1 deletion(-) create mode 100644 kernel/src/arch/riscv64/exception.rs create mode 100644 kernel/src/arch/riscv64/vectors.S diff --git a/kernel/arch/riscv64/src/registers.rs b/kernel/arch/riscv64/src/registers.rs index d6964093..95143d48 100644 --- a/kernel/arch/riscv64/src/registers.rs +++ b/kernel/arch/riscv64/src/registers.rs @@ -149,6 +149,63 @@ pub mod mepc { pub const MEPC: Reg = Reg; } +pub mod mtvec { + use tock_registers::{interfaces::ReadWriteable, register_bitfields}; + + use super::{impl_csr_read, impl_csr_write}; + + pub struct Reg; + + register_bitfields!( + u64, + pub MTVEC [ + MODE OFFSET(0) NUMBITS(2) [ + Direct = 0, + Vectored = 1 + ], + BASE OFFSET(2) NUMBITS(62) [], + ] + ); + + impl_csr_read!(Reg, u64, mtvec, MTVEC::Register); + impl_csr_write!(Reg, u64, mtvec, MTVEC::Register); + + impl Reg { + pub fn set_base(&self, base: usize) { + debug_assert_eq!(base & 0xF, 0); + let mask = match base & 63 != 0 { + false => 0, + true => 0x3 << 62, + }; + self.modify(MTVEC::BASE.val(((base as u64) >> 2) | mask)); + } + } + + pub const MTVEC: Reg = Reg; +} + +pub mod medeleg { + use super::{impl_csr_read, impl_csr_write}; + + pub struct Reg; + + impl_csr_read!(Reg, u64, medeleg, ()); + impl_csr_write!(Reg, u64, medeleg, ()); + + pub const MEDELEG: Reg = Reg; +} + +pub mod mideleg { + use super::{impl_csr_read, impl_csr_write}; + + pub struct Reg; + + impl_csr_read!(Reg, u64, mideleg, ()); + impl_csr_write!(Reg, u64, mideleg, ()); + + pub const MIDELEG: Reg = Reg; +} + pub mod satp { use tock_registers::register_bitfields; @@ -177,7 +234,80 @@ pub mod satp { pub const SATP: Reg = Reg; } +pub mod stvec { + use tock_registers::{interfaces::ReadWriteable, register_bitfields}; + + use super::{impl_csr_read, impl_csr_write}; + + register_bitfields!( + u64, + pub STVEC [ + MODE OFFSET(0) NUMBITS(2) [ + Direct = 0, + Vectored = 1 + ], + BASE OFFSET(2) NUMBITS(62) [], + ] + ); + + pub struct Reg; + + impl_csr_read!(Reg, u64, stvec, STVEC::Register); + impl_csr_write!(Reg, u64, stvec, STVEC::Register); + + impl Reg { + pub fn set_base(&self, base: usize) { + debug_assert_eq!(base & 0xF, 0); + let mask = match base & 63 != 0 { + false => 0, + true => 0x3 << 62, + }; + self.modify(STVEC::BASE.val(((base as u64) >> 2) | mask)); + } + } + + pub const STVEC: Reg = Reg; +} + +pub mod scause { + use tock_registers::register_bitfields; + + use super::{impl_csr_read, impl_csr_write}; + + register_bitfields!( + u64, + pub SCAUSE [ + CODE OFFSET(0) NUMBITS(63) [], + INTERRUPT OFFSET(63) NUMBITS(1) [], + ] + ); + + pub struct Reg; + + impl_csr_read!(Reg, u64, scause, SCAUSE::Register); + impl_csr_write!(Reg, u64, scause, SCAUSE::Register); + + pub const SCAUSE: Reg = Reg; +} + +pub mod sepc { + use super::{impl_csr_read, impl_csr_write}; + + pub struct Reg; + + impl_csr_read!(Reg, u64, sepc, ()); + impl_csr_write!(Reg, u64, sepc, ()); + + pub const SEPC: Reg = Reg; +} + +pub use medeleg::MEDELEG; pub use mepc::MEPC; +pub use mideleg::MIDELEG; pub use misa::MISA; pub use mstatus::MSTATUS; +pub use mtvec::MTVEC; pub use satp::SATP; +pub use scause::SCAUSE; +pub use sepc::SEPC; +pub use stvec::STVEC; diff --git a/kernel/src/arch/riscv64/boot/mod.rs b/kernel/src/arch/riscv64/boot/mod.rs index 73330640..a45d48fb 100644 --- a/kernel/src/arch/riscv64/boot/mod.rs +++ b/kernel/src/arch/riscv64/boot/mod.rs @@ -5,11 +5,13 @@ use kernel_arch_riscv64::{ table::{PageAttributes, PageEntry, PageTable, L1}, KERNEL_VIRT_OFFSET, }, - registers::{MEPC, MSTATUS, SATP}, + registers::{MEDELEG, MEPC, MIDELEG, MSTATUS, MTVEC, SATP}, }; use libk_mm::{address::PhysicalAddress, table::EntryLevel}; use tock_registers::interfaces::{ReadWriteable, Writeable}; +use super::exception; + const BOOT_STACK_SIZE: usize = 65536; #[repr(C, align(0x10))] @@ -64,6 +66,8 @@ unsafe extern "C" fn __rv64_bsp_smode_entry_lower() -> ! { } unsafe extern "C" fn __rv64_bsp_entry_upper() -> ! { + // TODO set up per-CPU pointer, pass DTB from M-mode, figure out the rest of the boot process + exception::init_smode_exceptions(); loop {} } @@ -71,8 +75,18 @@ unsafe extern "C" fn __rv64_bsp_entry_upper() -> ! { unsafe extern "C" fn __rv64_bsp_mmode_entry_lower() -> ! { extern "C" { fn __rv64_smode_entry() -> !; + static __rv64_mmode_trap_vectors: u8; } + // Setup trap vector for M-mode + let mtvec = (&raw const __rv64_mmode_trap_vectors).addr() - KERNEL_VIRT_OFFSET; + MTVEC.set_base(mtvec); + MTVEC.modify(MTVEC::MODE::Direct); + + // Setup trap delegation to S-mode + MIDELEG.set(u64::MAX); + MEDELEG.set(u64::MAX); + MSTATUS.modify( // Mask S-mode interrupts MSTATUS::SIE::CLEAR diff --git a/kernel/src/arch/riscv64/exception.rs b/kernel/src/arch/riscv64/exception.rs new file mode 100644 index 00000000..7b70f80f --- /dev/null +++ b/kernel/src/arch/riscv64/exception.rs @@ -0,0 +1,28 @@ +use core::arch::global_asm; + +use tock_registers::interfaces::{ReadWriteable, Readable}; + +use kernel_arch_riscv64::registers::{SCAUSE, SEPC, STVEC}; + +pub fn init_smode_exceptions() { + extern "C" { + static __rv64_smode_trap_vectors: u8; + } + let address = (&raw const __rv64_smode_trap_vectors).addr(); + + STVEC.set_base(address); + STVEC.modify(STVEC::MODE::Vectored); +} + +unsafe extern "C" fn smode_trap_handler() { + let cause = SCAUSE.read(SCAUSE::CODE); + let pc = SEPC.get(); + // Just put these into t0/t1 until I complete the rest of the kernel, lol + core::arch::asm!("j .", in("t0") cause, in("t1") pc); + loop {} +} + +global_asm!( + include_str!("vectors.S"), + smode_handler = sym smode_trap_handler +); diff --git a/kernel/src/arch/riscv64/mod.rs b/kernel/src/arch/riscv64/mod.rs index ae2a7d9a..9fbf69db 100644 --- a/kernel/src/arch/riscv64/mod.rs +++ b/kernel/src/arch/riscv64/mod.rs @@ -11,6 +11,7 @@ use libk_mm::table::EntryLevel; use super::Platform; pub mod boot; +pub mod exception; pub struct Riscv64; diff --git a/kernel/src/arch/riscv64/vectors.S b/kernel/src/arch/riscv64/vectors.S new file mode 100644 index 00000000..1263213f --- /dev/null +++ b/kernel/src/arch/riscv64/vectors.S @@ -0,0 +1,62 @@ +.section .text + +.macro SMODE_TRAP n +.type __rv64_smode_trap_\n, @function +__rv64_smode_trap_\n: + // TODO store registers + j {smode_handler} + // TODO restore registers and return +.size __rv64_smode_trap_\n, . - __rv64_smode_trap_\n +.endm + +.option push +.option norvc + +.global __rv64_smode_trap_vectors +.global __rv64_mmode_trap_vectors + +.type __rv64_smode_trap_vectors, @function +.p2align 4 +__rv64_smode_trap_vectors: + j __rv64_smode_trap_0 + j __rv64_smode_trap_1 + j __rv64_smode_trap_2 + j __rv64_smode_trap_3 + j __rv64_smode_trap_4 + j __rv64_smode_trap_5 + j __rv64_smode_trap_6 + j __rv64_smode_trap_7 + j __rv64_smode_trap_8 + j __rv64_smode_trap_9 + j __rv64_smode_trap_10 + j __rv64_smode_trap_11 + j __rv64_smode_trap_12 + j __rv64_smode_trap_13 + j __rv64_smode_trap_14 + j __rv64_smode_trap_15 +.size __rv64_smode_trap_vectors, . - __rv64_smode_trap_vectors + +.type __rv64_mmode_trap_vectors, @function +.p2align 4 +__rv64_mmode_trap_vectors: + j . +.size __rv64_mmode_trap_vectors, . - __rv64_mmode_trap_vectors + +SMODE_TRAP 0 +SMODE_TRAP 1 +SMODE_TRAP 2 +SMODE_TRAP 3 +SMODE_TRAP 4 +SMODE_TRAP 5 +SMODE_TRAP 6 +SMODE_TRAP 7 +SMODE_TRAP 8 +SMODE_TRAP 9 +SMODE_TRAP 10 +SMODE_TRAP 11 +SMODE_TRAP 12 +SMODE_TRAP 13 +SMODE_TRAP 14 +SMODE_TRAP 15 + +.option pop