//! RISC-V CSR helpers and interrupt utilities. //! //! Small helpers to read/modify control and status registers and manage //! interrupt enable/disable states. #![allow(unused)] use core::arch::naked_asm; use crate::clear_csr; use crate::read_csr; use crate::set_csr; pub struct MStatus; pub struct SStatus; impl MStatus { pub const MIE: usize = 1 << 3; pub const MPIE: usize = 1 << 7; } impl SStatus { pub const SIE: usize = 1 << 1; pub const SPIE: usize = 1 << 5; } /// Return the current machine interrupt enable state. pub fn get_interrupt_state() -> bool { (read_csr!(mstatus) & MStatus::MIE as u64) != 0 } /// Return whether supervisor interrupts are currently enabled. pub fn get_supervisor_interrupt_state() -> bool { (read_csr!(sstatus) & SStatus::SIE as u64) != 0 } /// Enable machine-level interrupts. pub fn enable_interrupt() { set_csr!(mstatus, MStatus::MIE); } /// Enable supervisor-level interrupts. pub fn enable_supervisor_interrupt() { set_csr!(sstatus, SStatus::SIE); } /// Disable machine-level interrupts. pub fn disable_interrupt() { clear_csr!(mstatus, MStatus::MIE); } /// Disable supervisor-level interrupts. pub fn disable_supervisor_interrupt() { clear_csr!(sstatus, SStatus::SIE); } /// Restore machine interrupt state from `previous_state`. pub fn restore_interrupt(previous_state: bool) { if previous_state { enable_interrupt(); } else { disable_interrupt(); } } /// Restore supervisor interrupt state from `previous_state`. pub fn restore_supervisor_interrupt(previous_state: bool) { if previous_state { enable_supervisor_interrupt(); } else { disable_supervisor_interrupt(); } } #[macro_export] macro_rules! read_csr { ($name:ident) => {{ let res: u64; unsafe { core::arch::asm!(concat!("csrr {}, ", stringify!($name)), out(reg) res, options(nomem, nostack)) }; res }}; } #[macro_export] macro_rules! write_csr { ($name:ident, $value:expr) => { let val = $value; unsafe { core::arch::asm!(concat!("csrw ", stringify!($name), ", {}"), in(reg) val, options(nomem, nostack)) }; }; } #[macro_export] macro_rules! set_csr { ($name:ident, $value:expr) => { let val = $value; unsafe { core::arch::asm!(concat!("csrs ", stringify!($name), ", {}"), in(reg) val, options(nomem, nostack)) }; }; } #[macro_export] macro_rules! clear_csr { ($name:ident, $value:expr) => { let val = $value; unsafe { core::arch::asm!(concat!("csrc ", stringify!($name), ", {}"), in(reg) val, options(nomem, nostack)) }; }; } #[macro_export] macro_rules! mret { () => { unsafe { core::arch::asm!("mret", options(noreturn)) } }; } #[unsafe(naked)] pub extern "C" fn exit_qemu() -> ! { naked_asm!( " li a0, 0x100000 li a1, 0x5555 sw a1, 0(a0) wfi " ) }