diff --git a/Cargo.toml b/Cargo.toml index 5917e3c..a46a4b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,3 +21,8 @@ exclude = [ [dependencies] tock-registers = { version = "0.9.0", default-features = false } # Use it as interface-only library. +critical-section = "1.1.2" + +[features] +critical-section-single-core = ["critical-section/restore-state-bool"] + diff --git a/src/critical_section.rs b/src/critical_section.rs new file mode 100644 index 0000000..c84aa0c --- /dev/null +++ b/src/critical_section.rs @@ -0,0 +1,24 @@ +use critical_section::{set_impl, Impl, RawRestoreState}; + +use crate::interrupt; + +struct SingleCoreCriticalSection; +set_impl!(SingleCoreCriticalSection); + +unsafe impl Impl for SingleCoreCriticalSection { + unsafe fn acquire() -> RawRestoreState { + let was_active = interrupt::enabled(); + // NOTE: Fence guarantees are provided by interrupt::disable(), which performs a `compiler_fence(SeqCst)`. + interrupt::disable(); + was_active + } + + unsafe fn release(was_active: RawRestoreState) { + // Only re-enable interrupts if they were enabled before the critical section. + if was_active { + // NOTE: Fence guarantees are provided by interrupt::enable(), which performs a + // `compiler_fence(SeqCst)`. + interrupt::enable() + } + } +} diff --git a/src/interrupt.rs b/src/interrupt.rs new file mode 100644 index 0000000..0c761b2 --- /dev/null +++ b/src/interrupt.rs @@ -0,0 +1,37 @@ +//! Interrupts + +#[cfg(target_arch = "aarch64")] +use crate::registers::{Readable, Writeable, DAIF}; +#[cfg(target_arch = "aarch64")] +use core::sync::atomic::{compiler_fence, Ordering}; + +/// Disables all interrupts in the current core. +#[cfg(target_arch = "aarch64")] +#[inline] +pub fn disable() { + compiler_fence(Ordering::SeqCst); + DAIF.write(DAIF::I::Masked + DAIF::F::Masked); + compiler_fence(Ordering::SeqCst); +} + +/// Enables all the interrupts in the current core. +/// +/// # Safety +/// +/// - Do not call this function inside a critical section. +#[cfg(target_arch = "aarch64")] +#[inline] +pub unsafe fn enable() { + compiler_fence(Ordering::SeqCst); + DAIF.write(DAIF::I::Unmasked + DAIF::F::Unmasked); + compiler_fence(Ordering::SeqCst); +} + +#[cfg(target_arch = "aarch64")] +#[inline] +pub unsafe fn enabled() -> bool { + if DAIF.read(DAIF::I) == 0 || DAIF.read(DAIF::F) == 0 { + return true; + } + false +} diff --git a/src/lib.rs b/src/lib.rs index 52c7402..37c7be3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -56,4 +56,15 @@ #![no_std] pub mod asm; +pub mod interrupt; pub mod registers; + +#[cfg(all(target_arch = "aarch64", feature = "critical-section-single-core"))] +mod critical_section; + +/// Used to reexport items for use in macros. Do not use directly. +/// Not covered by semver guarantees. +#[doc(hidden)] +pub mod _export { + pub use critical_section; +}