Skip to content

Commit d5591d0

Browse files
committed
also for interrupt::free; revert register::primask API changes
1 parent 02ec04a commit d5591d0

File tree

4 files changed

+64
-26
lines changed

4 files changed

+64
-26
lines changed

cortex-m/src/critical_section.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use core::sync::atomic::{compiler_fence, Ordering};
21
use critical_section::{set_impl, Impl, RawRestoreState};
32

43
use crate::interrupt;
@@ -9,15 +8,17 @@ set_impl!(SingleCoreCriticalSection);
98

109
unsafe impl Impl for SingleCoreCriticalSection {
1110
unsafe fn acquire() -> RawRestoreState {
12-
let restore_state = primask::read();
11+
// Backup previous state of PRIMASK register. We access the entire register directly as a
12+
// u32 instead of using the primask::read() function to minimize the number of processor
13+
// cycles during which interrupts are disabled.
14+
let restore_state = primask::read_raw();
1315
// NOTE: Fence guarantees are provided by interrupt::disable(), which performs a `compiler_fence(SeqCst)`.
1416
interrupt::disable();
15-
restore_state.0
17+
restore_state
1618
}
1719

1820
unsafe fn release(restore_state: RawRestoreState) {
19-
// Ensure no preceeding memory accesses are reordered to after interrupts are enabled.
20-
compiler_fence(Ordering::SeqCst);
21-
primask::write(restore_state);
21+
// NOTE: Fence guarantees are provided by primask::write_raw(), which performs a `compiler_fence(SeqCst)`.
22+
primask::write_raw(restore_state);
2223
}
2324
}

cortex-m/src/interrupt.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,18 +66,17 @@ pub fn free<F, R>(f: F) -> R
6666
where
6767
F: FnOnce() -> R,
6868
{
69-
let primask = crate::register::primask::read();
69+
// Backup previous state of PRIMASK register. We access the entire register directly as a
70+
// u32 instead of using the primask::read() function to minimize the number of processor
71+
// cycles during which interrupts are disabled.
72+
let primask = crate::register::primask::read_raw();
7073

7174
// disable interrupts
7275
disable();
7376

7477
let r = f();
7578

76-
// If the interrupts were active before our `disable` call, then re-enable
77-
// them. Otherwise, keep them disabled
78-
if primask.is_active() {
79-
unsafe { enable() }
80-
}
79+
crate::register::primask::write_raw(primask);
8180

8281
r
8382
}

cortex-m/src/register/primask.rs

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,36 +2,60 @@
22
33
#[cfg(cortex_m)]
44
use core::arch::asm;
5+
use core::sync::atomic::{compiler_fence, Ordering};
56

6-
/// Priority mask register
7-
pub struct Primask(pub u32);
7+
/// All exceptions with configurable priority are ...
8+
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
9+
pub enum Primask {
10+
/// Active
11+
Active,
12+
/// Inactive
13+
Inactive,
14+
}
815

916
impl Primask {
1017
/// All exceptions with configurable priority are active
1118
#[inline]
1219
pub fn is_active(self) -> bool {
13-
!self.is_inactive()
20+
self == Primask::Active
1421
}
1522

1623
/// All exceptions with configurable priority are inactive
1724
#[inline]
1825
pub fn is_inactive(self) -> bool {
19-
self.0 & (1 << 0) == (1 << 0)
26+
self == Primask::Inactive
2027
}
2128
}
2229

23-
/// Reads the CPU register
30+
/// Reads the prioritizable interrupt mask
2431
#[cfg(cortex_m)]
2532
#[inline]
2633
pub fn read() -> Primask {
34+
if read_raw() & (1 << 0) == (1 << 0) {
35+
Primask::Inactive
36+
} else {
37+
Primask::Active
38+
}
39+
}
40+
41+
/// Reads the entire PRIMASK register
42+
/// Note that bits [31:1] are reserved and UNK (Unknown)
43+
#[cfg(cortex_m)]
44+
#[inline]
45+
pub fn read_raw() -> u32 {
2746
let r: u32;
2847
unsafe { asm!("mrs {}, PRIMASK", out(reg) r, options(nomem, nostack, preserves_flags)) };
29-
Primask(r)
48+
r
3049
}
3150

32-
/// Writes the CPU register
51+
/// Writes the entire PRIMASK register
52+
/// Note that bits [31:1] are reserved and SBZP (Should-Be-Zero-or-Preserved)
3353
#[cfg(cortex_m)]
3454
#[inline]
35-
pub fn write(r: u32) {
55+
pub fn write_raw(r: u32) {
56+
// Ensure no preceeding memory accesses are reordered to after interrupts are possibly enabled.
57+
compiler_fence(Ordering::SeqCst);
3658
unsafe { asm!("msr PRIMASK, {}", in(reg) r, options(nomem, nostack, preserves_flags)) };
59+
// Ensure no subsequent memory accesses are reordered to before interrupts are possibly disabled.
60+
compiler_fence(Ordering::SeqCst);
3761
}

testsuite/src/main.rs

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,16 @@ fn panic(info: &core::panic::PanicInfo) -> ! {
1212
minitest::fail()
1313
}
1414

15-
static CRITICAL_SECTION_FLAG: AtomicBool = AtomicBool::new(false);
15+
static EXCEPTION_FLAG: AtomicBool = AtomicBool::new(false);
1616

1717
#[cortex_m_rt::exception]
1818
fn PendSV() {
19-
CRITICAL_SECTION_FLAG.store(true, Ordering::SeqCst);
19+
EXCEPTION_FLAG.store(true, Ordering::SeqCst);
2020
}
2121

2222
#[minitest::tests]
2323
mod tests {
24-
use crate::{Ordering, CRITICAL_SECTION_FLAG};
24+
use crate::{Ordering, EXCEPTION_FLAG};
2525
use minitest::log;
2626

2727
#[init]
@@ -63,13 +63,27 @@ mod tests {
6363

6464
#[test]
6565
fn critical_section_nesting() {
66+
EXCEPTION_FLAG.store(false, Ordering::SeqCst);
6667
critical_section::with(|_| {
6768
critical_section::with(|_| {
6869
cortex_m::peripheral::SCB::set_pendsv();
69-
assert!(!CRITICAL_SECTION_FLAG.load(Ordering::SeqCst));
70+
assert!(!EXCEPTION_FLAG.load(Ordering::SeqCst));
7071
});
71-
assert!(!CRITICAL_SECTION_FLAG.load(Ordering::SeqCst));
72+
assert!(!EXCEPTION_FLAG.load(Ordering::SeqCst));
7273
});
73-
assert!(CRITICAL_SECTION_FLAG.load(Ordering::SeqCst));
74+
assert!(EXCEPTION_FLAG.load(Ordering::SeqCst));
75+
}
76+
77+
#[test]
78+
fn interrupt_free_nesting() {
79+
EXCEPTION_FLAG.store(false, Ordering::SeqCst);
80+
cortex_m::interrupt::free(|| {
81+
cortex_m::interrupt::free(|| {
82+
cortex_m::peripheral::SCB::set_pendsv();
83+
assert!(!EXCEPTION_FLAG.load(Ordering::SeqCst));
84+
});
85+
assert!(!EXCEPTION_FLAG.load(Ordering::SeqCst));
86+
});
87+
assert!(EXCEPTION_FLAG.load(Ordering::SeqCst));
7488
}
7589
}

0 commit comments

Comments
 (0)