use core::arch::asm;
const MSTATUS_MIE: usize = 1 << 3;
const MIE_MEIE: usize = 1 << 11;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[repr(transparent)]
pub struct RestoreState {
bits: usize,
}
impl RestoreState {
#[inline]
pub const fn machine_interrupts_enabled(self) -> bool {
self.bits & MSTATUS_MIE != 0
}
#[inline]
pub const fn machine_external_interrupt_enabled(self) -> bool {
self.bits & MIE_MEIE != 0
}
#[inline]
const fn from_raw_parts(mstatus: usize, mie: usize) -> Self {
Self {
bits: (mstatus & MSTATUS_MIE) | (mie & MIE_MEIE),
}
}
#[inline]
#[cfg(feature = "critical-section")]
const fn bits(self) -> usize {
self.bits
}
#[inline]
#[cfg(feature = "critical-section")]
const unsafe fn from_bits(bits: usize) -> Self {
Self {
bits: bits & (MSTATUS_MIE | MIE_MEIE),
}
}
}
#[inline]
pub fn disable() -> RestoreState {
let mstatus: usize;
let mie: usize;
unsafe {
asm!(
"csrrc {mstatus}, mstatus, {mstatus_mie}",
"csrrc {mie}, mie, {mie_meie}",
mstatus = out(reg) mstatus,
mie = out(reg) mie,
mstatus_mie = in(reg) MSTATUS_MIE,
mie_meie = in(reg) MIE_MEIE,
options(nostack),
);
}
RestoreState::from_raw_parts(mstatus, mie)
}
#[inline]
pub unsafe fn enable() {
unsafe {
asm!(
"csrrs zero, mie, {mie_meie}",
"csrrs zero, mstatus, {mstatus_mie}",
mstatus_mie = in(reg) MSTATUS_MIE,
mie_meie = in(reg) MIE_MEIE,
options(nostack),
);
}
}
#[inline]
pub unsafe fn restore(state: RestoreState) {
if state.machine_external_interrupt_enabled() {
unsafe {
asm!(
"csrrs zero, mie, {mask}",
mask = in(reg) MIE_MEIE,
options(nostack),
);
}
} else {
unsafe {
asm!(
"csrrc zero, mie, {mask}",
mask = in(reg) MIE_MEIE,
options(nostack),
);
}
}
if state.machine_interrupts_enabled() {
unsafe {
asm!(
"csrrs zero, mstatus, {mask}",
mask = in(reg) MSTATUS_MIE,
options(nostack),
);
}
} else {
unsafe {
asm!(
"csrrc zero, mstatus, {mask}",
mask = in(reg) MSTATUS_MIE,
options(nostack),
);
}
}
}
#[inline]
pub fn free<R>(f: impl FnOnce() -> R) -> R {
let state = disable();
let result = f();
unsafe {
restore(state);
}
result
}
#[cfg(feature = "critical-section")]
mod critical_section_impl {
use super::{RestoreState, disable, restore};
use critical_section::{Impl, RawRestoreState, set_impl};
struct SingleHartCriticalSection;
set_impl!(SingleHartCriticalSection);
unsafe impl Impl for SingleHartCriticalSection {
unsafe fn acquire() -> RawRestoreState {
disable().bits()
}
unsafe fn release(state: RawRestoreState) {
unsafe {
restore(RestoreState::from_bits(state));
}
}
}
}