diff options
author | 2022-08-11 01:49:33 +0200 | |
---|---|---|
committer | 2022-08-11 23:31:08 +0200 | |
commit | 3a15a6b4b320fa328e8ab99c31f81536960dd280 (patch) | |
tree | 4c3ef55e91988845873479460e438afea445c919 /src | |
parent | 4e908625204a1e95dd3fd5bdcd8d66d6bc11c3bc (diff) | |
download | cortex-m-3a15a6b4b320fa328e8ab99c31f81536960dd280.tar.gz cortex-m-3a15a6b4b320fa328e8ab99c31f81536960dd280.tar.zst cortex-m-3a15a6b4b320fa328e8ab99c31f81536960dd280.zip |
Add implementation for critical-section 1.0
Co-Authored-By: Markus Reiter <me@reitermark.us>
Diffstat (limited to 'src')
-rw-r--r-- | src/critical_section.rs | 27 | ||||
-rw-r--r-- | src/interrupt.rs | 22 | ||||
-rw-r--r-- | src/lib.rs | 7 | ||||
-rw-r--r-- | src/macros.rs | 2 | ||||
-rw-r--r-- | src/peripheral/mod.rs | 3 | ||||
-rw-r--r-- | src/peripheral/sau.rs | 5 |
6 files changed, 48 insertions, 18 deletions
diff --git a/src/critical_section.rs b/src/critical_section.rs new file mode 100644 index 0000000..688058d --- /dev/null +++ b/src/critical_section.rs @@ -0,0 +1,27 @@ +#[cfg(all(cortex_m, feature = "critical-section-single-core"))] +mod single_core_critical_section { + use critical_section::{set_impl, Impl, RawRestoreState}; + + use crate::interrupt; + use crate::register::primask; + + struct SingleCoreCriticalSection; + set_impl!(SingleCoreCriticalSection); + + unsafe impl Impl for SingleCoreCriticalSection { + unsafe fn acquire() -> RawRestoreState { + let was_active = primask::read().is_active(); + 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 { + interrupt::enable() + } + } + } +} + +pub use critical_section::with; diff --git a/src/interrupt.rs b/src/interrupt.rs index 72450c4..f6ce990 100644 --- a/src/interrupt.rs +++ b/src/interrupt.rs @@ -1,6 +1,5 @@ //! Interrupts -pub use bare_metal::{CriticalSection, Mutex}; #[cfg(cortex_m)] use core::arch::asm; #[cfg(cortex_m)] @@ -27,7 +26,7 @@ pub unsafe trait InterruptNumber: Copy { fn number(self) -> u16; } -/// Disables all interrupts +/// Disables all interrupts in the current core. #[cfg(cortex_m)] #[inline] pub fn disable() { @@ -39,11 +38,11 @@ pub fn disable() { compiler_fence(Ordering::SeqCst); } -/// Enables all the interrupts +/// Enables all the interrupts in the current core. /// /// # Safety /// -/// - Do not call this function inside an `interrupt::free` critical section +/// - Do not call this function inside a critical section. #[cfg(cortex_m)] #[inline] pub unsafe fn enable() { @@ -53,21 +52,26 @@ pub unsafe fn enable() { asm!("cpsie i", options(nomem, nostack, preserves_flags)); } -/// Execute closure `f` in an interrupt-free context. +/// Execute closure `f` with interrupts disabled in the current core. /// -/// This as also known as a "critical section". +/// This method does not synchronise multiple cores and may disable required +/// interrupts on some platforms; see the `critical-section` crate for a cross-platform +/// way to enter a critical section which provides a `CriticalSection` token. +/// +/// This crate provides an implementation for `critical-section` suitable for single-core systems, +/// based on disabling all interrupts. It can be enabled with the `critical-section-single-core` feature. #[cfg(cortex_m)] #[inline] pub fn free<F, R>(f: F) -> R where - F: FnOnce(&CriticalSection) -> R, + F: FnOnce() -> R, { let primask = crate::register::primask::read(); // disable interrupts disable(); - let r = f(unsafe { &CriticalSection::new() }); + let r = f(); // If the interrupts were active before our `disable` call, then re-enable // them. Otherwise, keep them disabled @@ -85,7 +89,7 @@ where #[inline] pub fn free<F, R>(_: F) -> R where - F: FnOnce(&CriticalSection) -> R, + F: FnOnce() -> R, { panic!("cortex_m::interrupt::free() is only functional on cortex-m platforms"); } @@ -43,15 +43,16 @@ // Don't warn about feature(asm) being stable on Rust >= 1.59.0 #![allow(stable_features)] -extern crate bare_metal; -extern crate volatile_register; - #[macro_use] mod macros; pub mod asm; #[cfg(armv8m)] pub mod cmse; +// This is only public so the `singleton` macro does not require depending on +// the `critical-section` crate separately. +#[doc(hidden)] +pub mod critical_section; pub mod delay; pub mod interrupt; #[cfg(all(not(armv6m), not(armv8m_base)))] diff --git a/src/macros.rs b/src/macros.rs index 512c932..21bf78b 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -62,7 +62,7 @@ macro_rules! iprintln { #[macro_export] macro_rules! singleton { ($name:ident: $ty:ty = $expr:expr) => { - $crate::interrupt::free(|_| { + $crate::critical_section::with(|_| { // this is a tuple of a MaybeUninit and a bool because using an Option here is // problematic: Due to niche-optimization, an Option could end up producing a non-zero // initializer value which would move the entire static from `.bss` into `.data`... diff --git a/src/peripheral/mod.rs b/src/peripheral/mod.rs index c316886..bf18151 100644 --- a/src/peripheral/mod.rs +++ b/src/peripheral/mod.rs @@ -57,7 +57,6 @@ //! //! - ARMv7-M Architecture Reference Manual (Issue E.b) - Chapter B3 -use crate::interrupt; use core::marker::PhantomData; use core::ops; @@ -164,7 +163,7 @@ impl Peripherals { /// Returns all the core peripherals *once* #[inline] pub fn take() -> Option<Self> { - interrupt::free(|_| { + critical_section::with(|_| { if unsafe { TAKEN } { None } else { diff --git a/src/peripheral/sau.rs b/src/peripheral/sau.rs index da91aca..6b8477f 100644 --- a/src/peripheral/sau.rs +++ b/src/peripheral/sau.rs @@ -7,7 +7,6 @@ //! //! For reference please check the section B8.3 of the Armv8-M Architecture Reference Manual. -use crate::interrupt; use crate::peripheral::SAU; use bitfield::bitfield; use volatile_register::{RO, RW}; @@ -162,7 +161,7 @@ impl SAU { /// This function is executed under a critical section to prevent having inconsistent results. #[inline] pub fn set_region(&mut self, region_number: u8, region: SauRegion) -> Result<(), SauError> { - interrupt::free(|_| { + critical_section::with(|_| { let base_address = region.base_address; let limit_address = region.limit_address; let attribute = region.attribute; @@ -215,7 +214,7 @@ impl SAU { /// This function is executed under a critical section to prevent having inconsistent results. #[inline] pub fn get_region(&mut self, region_number: u8) -> Result<SauRegion, SauError> { - interrupt::free(|_| { + critical_section::with(|_| { if region_number >= self.region_numbers() { Err(SauError::RegionNumberTooBig) } else { |