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_select! {
38 esp32p4 => {
39 // TODO: any with zcmp
40 // ESP32-P4 (v3.2/ECO7 etc.) Zcmp hardware bug workaround (IDF-14279 / DIG-661):
41 // Clearing mstatus.mie alone does not fully mask CLIC interrupts -- an
42 // interrupt can still fire mid-instruction on cm.push (and possibly on
43 // other multi-cycle sequences). Fix: raise mintthresh (CSR 0x347) to 0xFF
44 // while mie is cleared, then restore the previous mintthresh on exit.
45 // Ref: esp-idf commit c27c33a83 "fix(riscv): implement a workaround for
46 // Zcmp hardware bug".
47 let old_mintthresh: u32;
48 unsafe {
49 core::arch::asm!(
50 "li t0, 0xff",
51 "csrrw {0}, 0x347, t0",
52 out(reg) old_mintthresh,
53 out("t0") _,
54 );
55 }
56 let mut mstatus = 0u32;
57 unsafe {
58 core::arch::asm!("csrrci {0}, mstatus, 8", inout(reg) mstatus);
59 }
60 let mie_bit = mstatus & 0b1000;
61 let token = mie_bit | ((old_mintthresh & 0xff) << 8);
62 }
63 riscv => {
64 let mut mstatus = 0u32;
65 unsafe {
66 core::arch::asm!("csrrci {0}, mstatus, 8", inout(reg) mstatus);
67 }
68 let token = mstatus & 0b1000;
69 }
70 xtensa => {
71 let token: u32;
72 unsafe {
73 core::arch::asm!("rsil {0}, 5", out(reg) token);
74 }
75 #[cfg(debug_assertions)]
76 let token = token & !RESERVED_MASK;
77 }
78 _ => {
79 compile_error!("Unsupported architecture")
80 }
81 };
82
83 // Ensure no subsequent memory accesses are reordered to before interrupts are
84 // disabled.
85 compiler_fence(Ordering::SeqCst);
86
87 unsafe { RestoreState::new(token) }
88 }
89
90 #[inline]
91 unsafe fn exit(&self, token: RestoreState) {
92 // Ensure no preceeding memory accesses are reordered to after interrupts are
93 // enabled.
94 compiler_fence(Ordering::SeqCst);
95
96 let token = token.inner();
97
98 cfg_select! {
99 esp32p4 => {
100 if (token & 0b1000) != 0 {
101 unsafe {
102 riscv::interrupt::enable();
103 }
104 }
105 // Restore mintthresh AFTER re-enabling mie (P4 Zcmp workaround, see enter()).
106 let old_mintthresh = (token >> 8) & 0xff;
107 unsafe {
108 core::arch::asm!(
109 "csrw 0x347, {0}",
110 in(reg) old_mintthresh,
111 );
112 }
113
114 // The delay between the moment we unmask the interrupt threshold register
115 // and the moment the potential requested interrupt is triggered is not
116 // null: up to three machine cycles/instructions can be executed.
117 riscv::asm::nop();
118 riscv::asm::nop();
119 riscv::asm::nop();
120 }
121 riscv => {
122 if token != 0 {
123 unsafe {
124 riscv::interrupt::enable();
125 }
126 }
127 }
128 xtensa => {
129 #[cfg(debug_assertions)]
130 if token & RESERVED_MASK != 0 {
131 // We could do this transformation in fmt.rs automatically, but experiments
132 // show this is only worth it in terms of binary size for code inlined into many
133 // places.
134 #[cold]
135 #[inline(never)]
136 fn __assert_failed() {
137 panic!("Reserved bits in PS register must be written as 0");
138 }
139
140 __assert_failed();
141 }
142
143 unsafe {
144 core::arch::asm!(
145 "wsr.ps {0}",
146 "rsync", in(reg) token)
147 }
148 }
149 _ => {
150 compile_error!("Unsupported architecture")
151 }
152 }
153 }
154}