118 lines
2.9 KiB
Rust
118 lines
2.9 KiB
Rust
//! 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
|
|
"
|
|
)
|
|
}
|