use core::sync::atomic::{Ordering, compiler_fence};
use crate::RestoreState;
pub trait RawLock {
unsafe fn enter(&self) -> RestoreState;
unsafe fn exit(&self, token: RestoreState);
}
pub struct SingleCoreInterruptLock;
#[cfg(all(xtensa, debug_assertions))]
const RESERVED_MASK: u32 = 0b1111_1111_1111_1000_1111_0000_0000_0000;
impl RawLock for SingleCoreInterruptLock {
#[inline]
unsafe fn enter(&self) -> RestoreState {
cfg_if::cfg_if! {
if #[cfg(riscv)] {
let mut mstatus = 0u32;
unsafe { core::arch::asm!("csrrci {0}, mstatus, 8", inout(reg) mstatus); }
let token = mstatus & 0b1000;
} else if #[cfg(xtensa)] {
let token: u32;
unsafe { core::arch::asm!("rsil {0}, 5", out(reg) token); }
#[cfg(debug_assertions)]
let token = token & !RESERVED_MASK;
} else {
compile_error!("Unsupported architecture")
}
};
compiler_fence(Ordering::SeqCst);
unsafe { RestoreState::new(token) }
}
#[inline]
unsafe fn exit(&self, token: RestoreState) {
compiler_fence(Ordering::SeqCst);
let token = token.inner();
cfg_if::cfg_if! {
if #[cfg(riscv)] {
if token != 0 {
unsafe {
riscv::interrupt::enable();
}
}
} else if #[cfg(xtensa)] {
#[cfg(debug_assertions)]
if token & RESERVED_MASK != 0 {
#[cold]
#[inline(never)]
fn __assert_failed() {
panic!("Reserved bits in PS register must be written as 0");
}
__assert_failed();
}
unsafe {
core::arch::asm!(
"wsr.ps {0}",
"rsync", in(reg) token)
}
} else {
compile_error!("Unsupported architecture")
}
}
}
}