blob: 59f94458c0978fb2080cbbe5455b6804f5c1e1a7 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
|
use core::arch::asm;
use core::sync::atomic::{compiler_fence, AtomicBool, Ordering};
use crate::pac::{Interrupt, NVIC};
#[cfg(any(feature = "nrf52810", feature = "nrf52811"))]
const RESERVED_IRQS: u32 = (1 << (Interrupt::POWER_CLOCK as u8))
| (1 << (Interrupt::RADIO as u8))
| (1 << (Interrupt::RTC0 as u8))
| (1 << (Interrupt::TIMER0 as u8))
| (1 << (Interrupt::RNG as u8))
| (1 << (Interrupt::ECB as u8))
| (1 << (Interrupt::CCM_AAR as u8))
| (1 << (Interrupt::TEMP as u8))
| (1 << (Interrupt::SWI5 as u8));
#[cfg(not(any(feature = "nrf52810", feature = "nrf52811")))]
const RESERVED_IRQS: u32 = (1 << (Interrupt::POWER_CLOCK as u8))
| (1 << (Interrupt::RADIO as u8))
| (1 << (Interrupt::RTC0 as u8))
| (1 << (Interrupt::TIMER0 as u8))
| (1 << (Interrupt::RNG as u8))
| (1 << (Interrupt::ECB as u8))
| (1 << (Interrupt::CCM_AAR as u8))
| (1 << (Interrupt::TEMP as u8))
| (1 << (Interrupt::SWI5_EGU5 as u8));
static CS_FLAG: AtomicBool = AtomicBool::new(false);
static mut CS_MASK: u32 = 0;
#[inline]
unsafe fn raw_critical_section<R>(f: impl FnOnce() -> R) -> R {
// TODO: assert that we're in privileged level
// Needed because disabling irqs in non-privileged level is a noop, which would break safety.
let primask: u32;
asm!("mrs {}, PRIMASK", out(reg) primask);
asm!("cpsid i");
// Prevent compiler from reordering operations inside/outside the critical section.
compiler_fence(Ordering::SeqCst);
let r = f();
compiler_fence(Ordering::SeqCst);
if primask & 1 == 0 {
asm!("cpsie i");
}
r
}
struct CriticalSection;
critical_section::custom_impl!(CriticalSection);
unsafe impl critical_section::Impl for CriticalSection {
unsafe fn acquire() -> u8 {
let nvic = &*NVIC::PTR;
let nested_cs = CS_FLAG.load(Ordering::SeqCst);
if !nested_cs {
raw_critical_section(|| {
CS_FLAG.store(true, Ordering::Relaxed);
// Store the state of irqs.
CS_MASK = nvic.icer[0].read();
// Disable only not-reserved irqs.
nvic.icer[0].write(!RESERVED_IRQS);
});
}
compiler_fence(Ordering::SeqCst);
return nested_cs as u8;
}
unsafe fn release(token: u8) {
compiler_fence(Ordering::SeqCst);
let nvic = &*NVIC::PTR;
if token == 0 {
raw_critical_section(|| {
CS_FLAG.store(false, Ordering::Relaxed);
// restore only non-reserved irqs.
nvic.iser[0].write(CS_MASK & !RESERVED_IRQS);
});
}
}
}
|