2017-09-19 22:04:12 +08:00
|
|
|
//! Interrupts
|
|
|
|
|
|
|
|
// NOTE: Adapted from cortex-m/src/interrupt.rs
|
|
|
|
pub use bare_metal::{CriticalSection, Mutex, Nr};
|
2018-03-28 02:17:44 +08:00
|
|
|
use register::mstatus;
|
2017-09-19 22:04:12 +08:00
|
|
|
|
|
|
|
/// Disables all interrupts
|
2018-03-25 02:27:00 +08:00
|
|
|
#[inline]
|
2018-03-28 02:17:44 +08:00
|
|
|
pub unsafe fn disable() {
|
2017-09-19 22:04:12 +08:00
|
|
|
match () {
|
|
|
|
#[cfg(target_arch = "riscv")]
|
2018-03-28 02:17:44 +08:00
|
|
|
() => mstatus::clear_mie(),
|
2017-09-19 22:04:12 +08:00
|
|
|
#[cfg(not(target_arch = "riscv"))]
|
|
|
|
() => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Enables all the interrupts
|
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
///
|
|
|
|
/// - Do not call this function inside an `interrupt::free` critical section
|
2018-03-25 02:27:00 +08:00
|
|
|
#[inline]
|
2017-09-19 22:04:12 +08:00
|
|
|
pub unsafe fn enable() {
|
|
|
|
match () {
|
|
|
|
#[cfg(target_arch = "riscv")]
|
2018-03-28 02:17:44 +08:00
|
|
|
() => mstatus::set_mie(),
|
2017-09-19 22:04:12 +08:00
|
|
|
#[cfg(not(target_arch = "riscv"))]
|
|
|
|
() => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Execute closure `f` in an interrupt-free context.
|
|
|
|
///
|
|
|
|
/// This as also known as a "critical section".
|
|
|
|
pub fn free<F, R>(f: F) -> R
|
|
|
|
where
|
|
|
|
F: FnOnce(&CriticalSection) -> R,
|
|
|
|
{
|
2018-03-28 02:17:44 +08:00
|
|
|
let mstatus = mstatus::read();
|
2017-09-19 22:04:12 +08:00
|
|
|
|
|
|
|
// disable interrupts
|
2018-03-28 02:17:44 +08:00
|
|
|
unsafe { disable(); }
|
2017-09-19 22:04:12 +08:00
|
|
|
|
|
|
|
let r = f(unsafe { &CriticalSection::new() });
|
|
|
|
|
|
|
|
// If the interrupts were active before our `disable` call, then re-enable
|
|
|
|
// them. Otherwise, keep them disabled
|
|
|
|
if mstatus.mie() {
|
2018-03-28 02:17:44 +08:00
|
|
|
unsafe { enable(); }
|
2017-09-19 22:04:12 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
r
|
|
|
|
}
|