esp_sync/raw.rs
1//! TODO
2
3use core::sync::atomic::{Ordering, compiler_fence};
4
5use crate::RestoreState;
6
7/// Trait for single-core locks.
8pub trait RawLock {
9 /// Acquires the raw lock
10 ///
11 /// # Safety
12 ///
13 /// The returned tokens must be released in reverse order, on the same thread that they were
14 /// created on.
15 unsafe fn enter(&self) -> RestoreState;
16
17 /// Releases the raw lock
18 ///
19 /// # Safety
20 ///
21 /// - The `token` must be created by `self.enter()`
22 /// - Tokens must be released in reverse order to their creation, on the same thread that they
23 /// were created on.
24 unsafe fn exit(&self, token: RestoreState);
25}
26
27/// A lock that disables interrupts.
28pub struct SingleCoreInterruptLock;
29
30// Reserved bits in the PS register, these must be written as 0.
31#[cfg(all(xtensa, debug_assertions))]
32const RESERVED_MASK: u32 = 0b1111_1111_1111_1000_1111_0000_0000_0000;
33
34impl RawLock for SingleCoreInterruptLock {
35 #[inline]
36 unsafe fn enter(&self) -> RestoreState {
37 cfg_if::cfg_if! {
38 if #[cfg(riscv)] {
39 let mut mstatus = 0u32;
40 unsafe { core::arch::asm!("csrrci {0}, mstatus, 8", inout(reg) mstatus); }
41 let token = mstatus & 0b1000;
42 } else if #[cfg(xtensa)] {
43 let token: u32;
44 unsafe { core::arch::asm!("rsil {0}, 5", out(reg) token); }
45 #[cfg(debug_assertions)]
46 let token = token & !RESERVED_MASK;
47 } else {
48 compile_error!("Unsupported architecture")
49 }
50 };
51
52 // Ensure no subsequent memory accesses are reordered to before interrupts are
53 // disabled.
54 compiler_fence(Ordering::SeqCst);
55
56 unsafe { RestoreState::new(token) }
57 }
58
59 #[inline]
60 unsafe fn exit(&self, token: RestoreState) {
61 // Ensure no preceeding memory accesses are reordered to after interrupts are
62 // enabled.
63 compiler_fence(Ordering::SeqCst);
64
65 let token = token.inner();
66
67 cfg_if::cfg_if! {
68 if #[cfg(riscv)] {
69 if token != 0 {
70 unsafe {
71 riscv::interrupt::enable();
72 }
73 }
74 } else if #[cfg(xtensa)] {
75 #[cfg(debug_assertions)]
76 if token & RESERVED_MASK != 0 {
77 // We could do this transformation in fmt.rs automatically, but experiments
78 // show this is only worth it in terms of binary size for code inlined into many places.
79 #[cold]
80 #[inline(never)]
81 fn __assert_failed() {
82 panic!("Reserved bits in PS register must be written as 0");
83 }
84
85 __assert_failed();
86 }
87
88 unsafe {
89 core::arch::asm!(
90 "wsr.ps {0}",
91 "rsync", in(reg) token)
92 }
93 } else {
94 compile_error!("Unsupported architecture")
95 }
96 }
97 }
98}