aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32-wpan
diff options
context:
space:
mode:
authorxoviat <[email protected]>2025-12-12 18:51:36 -0600
committerxoviat <[email protected]>2025-12-12 18:51:36 -0600
commite8d0b69e8c416cc2b9922acbf277b520d80f3134 (patch)
tree6ec06ae94b382f06fa3819fa7a084accc96797c4 /embassy-stm32-wpan
parent92058fd5328eb85e741222d72721ffb9777de188 (diff)
wpan: update aligned, critical_section
Diffstat (limited to 'embassy-stm32-wpan')
-rw-r--r--embassy-stm32-wpan/Cargo.toml4
-rw-r--r--embassy-stm32-wpan/src/wb55/sub/ble.rs4
-rw-r--r--embassy-stm32-wpan/src/wb55/sub/mm.rs14
-rw-r--r--embassy-stm32-wpan/src/wb55/sub/sys.rs6
-rw-r--r--embassy-stm32-wpan/src/wb55/unsafe_linked_list.rs358
5 files changed, 200 insertions, 186 deletions
diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml
index 103dedead..9624c7932 100644
--- a/embassy-stm32-wpan/Cargo.toml
+++ b/embassy-stm32-wpan/Cargo.toml
@@ -41,8 +41,8 @@ log = { version = "0.4.17", optional = true }
41 41
42cortex-m = "0.7.6" 42cortex-m = "0.7.6"
43heapless = "0.8" 43heapless = "0.8"
44aligned = "0.4.1" 44aligned = "0.4.2"
45critical-section = "1.1" 45critical-section = "1.2"
46 46
47bit_field = "0.10.2" 47bit_field = "0.10.2"
48stm32-device-signature = { version = "0.3.3", features = ["stm32wb5x"] } 48stm32-device-signature = { version = "0.3.3", features = ["stm32wb5x"] }
diff --git a/embassy-stm32-wpan/src/wb55/sub/ble.rs b/embassy-stm32-wpan/src/wb55/sub/ble.rs
index afc4a510a..a2558d735 100644
--- a/embassy-stm32-wpan/src/wb55/sub/ble.rs
+++ b/embassy-stm32-wpan/src/wb55/sub/ble.rs
@@ -73,7 +73,9 @@ impl<'a> Ble<'a> {
73 pub async fn tl_read(&mut self) -> EvtBox<Self> { 73 pub async fn tl_read(&mut self) -> EvtBox<Self> {
74 self.ipcc_ble_event_channel 74 self.ipcc_ble_event_channel
75 .receive(|| unsafe { 75 .receive(|| unsafe {
76 if let Some(node_ptr) = LinkedListNode::remove_head(EVT_QUEUE.as_mut_ptr()) { 76 if let Some(node_ptr) =
77 critical_section::with(|cs| LinkedListNode::remove_head(cs, EVT_QUEUE.as_mut_ptr()))
78 {
77 Some(EvtBox::new(node_ptr.cast())) 79 Some(EvtBox::new(node_ptr.cast()))
78 } else { 80 } else {
79 None 81 None
diff --git a/embassy-stm32-wpan/src/wb55/sub/mm.rs b/embassy-stm32-wpan/src/wb55/sub/mm.rs
index cbb5f130b..0ca7d1835 100644
--- a/embassy-stm32-wpan/src/wb55/sub/mm.rs
+++ b/embassy-stm32-wpan/src/wb55/sub/mm.rs
@@ -4,7 +4,6 @@ use core::mem::MaybeUninit;
4use core::task::Poll; 4use core::task::Poll;
5 5
6use aligned::{A4, Aligned}; 6use aligned::{A4, Aligned};
7use cortex_m::interrupt;
8use embassy_stm32::ipcc::IpccTxChannel; 7use embassy_stm32::ipcc::IpccTxChannel;
9use embassy_sync::waitqueue::AtomicWaker; 8use embassy_sync::waitqueue::AtomicWaker;
10 9
@@ -52,7 +51,7 @@ impl<'a> MemoryManager<'a> {
52 loop { 51 loop {
53 poll_fn(|cx| unsafe { 52 poll_fn(|cx| unsafe {
54 MM_WAKER.register(cx.waker()); 53 MM_WAKER.register(cx.waker());
55 if LinkedListNode::is_empty(LOCAL_FREE_BUF_QUEUE.as_mut_ptr()) { 54 if critical_section::with(|cs| LinkedListNode::is_empty(cs, LOCAL_FREE_BUF_QUEUE.as_mut_ptr())) {
56 Poll::Pending 55 Poll::Pending
57 } else { 56 } else {
58 Poll::Ready(()) 57 Poll::Ready(())
@@ -62,10 +61,9 @@ impl<'a> MemoryManager<'a> {
62 61
63 self.ipcc_mm_release_buffer_channel 62 self.ipcc_mm_release_buffer_channel
64 .send(|| { 63 .send(|| {
65 interrupt::free(|_| unsafe { 64 critical_section::with(|cs| unsafe {
66 // CS required while moving nodes 65 while let Some(node_ptr) = LinkedListNode::remove_head(cs, LOCAL_FREE_BUF_QUEUE.as_mut_ptr()) {
67 while let Some(node_ptr) = LinkedListNode::remove_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr()) { 66 LinkedListNode::insert_head(cs, FREE_BUF_QUEUE.as_mut_ptr(), node_ptr);
68 LinkedListNode::insert_head(FREE_BUF_QUEUE.as_mut_ptr(), node_ptr);
69 } 67 }
70 }) 68 })
71 }) 69 })
@@ -77,8 +75,8 @@ impl<'a> MemoryManager<'a> {
77impl<'a> evt::MemoryManager for MemoryManager<'a> { 75impl<'a> evt::MemoryManager for MemoryManager<'a> {
78 /// SAFETY: passing a pointer to something other than a managed event packet is UB 76 /// SAFETY: passing a pointer to something other than a managed event packet is UB
79 unsafe fn drop_event_packet(evt: *mut EvtPacket) { 77 unsafe fn drop_event_packet(evt: *mut EvtPacket) {
80 interrupt::free(|_| unsafe { 78 critical_section::with(|cs| unsafe {
81 LinkedListNode::insert_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr(), evt as *mut _); 79 LinkedListNode::insert_head(cs, LOCAL_FREE_BUF_QUEUE.as_mut_ptr(), evt as *mut _);
82 }); 80 });
83 81
84 MM_WAKER.wake(); 82 MM_WAKER.wake();
diff --git a/embassy-stm32-wpan/src/wb55/sub/sys.rs b/embassy-stm32-wpan/src/wb55/sub/sys.rs
index 4376314c7..2e625a677 100644
--- a/embassy-stm32-wpan/src/wb55/sub/sys.rs
+++ b/embassy-stm32-wpan/src/wb55/sub/sys.rs
@@ -87,10 +87,12 @@ impl<'a> Sys<'a> {
87 /// This method takes the place of the `HW_IPCC_SYS_EvtNot`/`SysUserEvtRx`/`APPE_SysUserEvtRx`, 87 /// This method takes the place of the `HW_IPCC_SYS_EvtNot`/`SysUserEvtRx`/`APPE_SysUserEvtRx`,
88 /// as the embassy implementation avoids the need to call C public bindings, and instead 88 /// as the embassy implementation avoids the need to call C public bindings, and instead
89 /// handles the event channels directly. 89 /// handles the event channels directly.
90 pub async fn read<'b>(&mut self) -> EvtBox<mm::MemoryManager<'b>> { 90 pub async fn read(&mut self) -> EvtBox<mm::MemoryManager<'_>> {
91 self.ipcc_system_event_channel 91 self.ipcc_system_event_channel
92 .receive(|| unsafe { 92 .receive(|| unsafe {
93 if let Some(node_ptr) = LinkedListNode::remove_head(SYSTEM_EVT_QUEUE.as_mut_ptr()) { 93 if let Some(node_ptr) =
94 critical_section::with(|cs| LinkedListNode::remove_head(cs, SYSTEM_EVT_QUEUE.as_mut_ptr()))
95 {
94 Some(EvtBox::new(node_ptr.cast())) 96 Some(EvtBox::new(node_ptr.cast()))
95 } else { 97 } else {
96 None 98 None
diff --git a/embassy-stm32-wpan/src/wb55/unsafe_linked_list.rs b/embassy-stm32-wpan/src/wb55/unsafe_linked_list.rs
index d8bc29763..c84ee1bb6 100644
--- a/embassy-stm32-wpan/src/wb55/unsafe_linked_list.rs
+++ b/embassy-stm32-wpan/src/wb55/unsafe_linked_list.rs
@@ -11,9 +11,10 @@
11 unused_mut 11 unused_mut
12)] 12)]
13 13
14use core::fmt::Debug;
14use core::ptr; 15use core::ptr;
15 16
16use cortex_m::interrupt; 17use critical_section::CriticalSection;
17 18
18#[derive(Copy, Clone)] 19#[derive(Copy, Clone)]
19#[repr(C, packed(4))] 20#[repr(C, packed(4))]
@@ -42,216 +43,227 @@ impl LinkedListNode {
42 ); 43 );
43 } 44 }
44 45
45 pub unsafe fn is_empty(mut p_list_head: *mut LinkedListNode) -> bool { 46 pub unsafe fn is_empty(_cs: CriticalSection, mut p_list_head: *mut LinkedListNode) -> bool {
46 interrupt::free(|_| ptr::read_volatile(p_list_head).next == p_list_head) 47 ptr::read_volatile(p_list_head).next == p_list_head
47 } 48 }
48 49
49 /// Insert `node` after `list_head` and before the next node 50 /// Insert `node` after `list_head` and before the next node
50 pub unsafe fn insert_head(mut p_list_head: *mut LinkedListNode, mut p_node: *mut LinkedListNode) { 51 pub unsafe fn insert_head(
51 interrupt::free(|_| { 52 _cs: CriticalSection,
52 let mut list_head = ptr::read_volatile(p_list_head); 53 mut p_list_head: *mut LinkedListNode,
53 if p_list_head != list_head.next { 54 mut p_node: *mut LinkedListNode,
54 let mut node_next = ptr::read_volatile(list_head.next); 55 ) {
55 let node = LinkedListNode { 56 let mut list_head = ptr::read_volatile(p_list_head);
56 next: list_head.next, 57 if p_list_head != list_head.next {
57 prev: p_list_head, 58 let mut node_next = ptr::read_volatile(list_head.next);
58 }; 59 let node = LinkedListNode {
59 60 next: list_head.next,
60 list_head.next = p_node; 61 prev: p_list_head,
61 node_next.prev = p_node; 62 };
62 63
63 // All nodes must be written because they will all be seen by another core 64 list_head.next = p_node;
64 ptr::write_volatile(p_node, node); 65 node_next.prev = p_node;
65 ptr::write_volatile(node.next, node_next); 66
66 ptr::write_volatile(p_list_head, list_head); 67 // All nodes must be written because they will all be seen by another core
67 } else { 68 ptr::write_volatile(p_node, node);
68 let node = LinkedListNode { 69 ptr::write_volatile(node.next, node_next);
69 next: list_head.next, 70 ptr::write_volatile(p_list_head, list_head);
70 prev: p_list_head, 71 } else {
71 }; 72 let node = LinkedListNode {
72 73 next: list_head.next,
73 list_head.next = p_node; 74 prev: p_list_head,
74 list_head.prev = p_node; 75 };
75 76
76 // All nodes must be written because they will all be seen by another core 77 list_head.next = p_node;
77 ptr::write_volatile(p_node, node); 78 list_head.prev = p_node;
78 ptr::write_volatile(p_list_head, list_head); 79
79 } 80 // All nodes must be written because they will all be seen by another core
80 }); 81 ptr::write_volatile(p_node, node);
82 ptr::write_volatile(p_list_head, list_head);
83 }
81 } 84 }
82 85
83 /// Insert `node` before `list_tail` and after the second-to-last node 86 /// Insert `node` before `list_tail` and after the second-to-last node
84 pub unsafe fn insert_tail(mut p_list_tail: *mut LinkedListNode, mut p_node: *mut LinkedListNode) { 87 pub unsafe fn insert_tail(
85 interrupt::free(|_| { 88 _cs: CriticalSection,
86 let mut list_tail = ptr::read_volatile(p_list_tail); 89 mut p_list_tail: *mut LinkedListNode,
87 if p_list_tail != list_tail.prev { 90 mut p_node: *mut LinkedListNode,
88 let mut node_prev = ptr::read_volatile(list_tail.prev); 91 ) {
89 let node = LinkedListNode { 92 let mut list_tail = ptr::read_volatile(p_list_tail);
90 next: p_list_tail, 93 if p_list_tail != list_tail.prev {
91 prev: list_tail.prev, 94 let mut node_prev = ptr::read_volatile(list_tail.prev);
92 }; 95 let node = LinkedListNode {
93 96 next: p_list_tail,
94 list_tail.prev = p_node; 97 prev: list_tail.prev,
95 node_prev.next = p_node; 98 };
96 99
97 // All nodes must be written because they will all be seen by another core 100 list_tail.prev = p_node;
98 ptr::write_volatile(p_node, node); 101 node_prev.next = p_node;
99 ptr::write_volatile(node.prev, node_prev); 102
100 ptr::write_volatile(p_list_tail, list_tail); 103 // All nodes must be written because they will all be seen by another core
101 } else { 104 ptr::write_volatile(p_node, node);
102 let node = LinkedListNode { 105 ptr::write_volatile(node.prev, node_prev);
103 next: p_list_tail, 106 ptr::write_volatile(p_list_tail, list_tail);
104 prev: list_tail.prev, 107 } else {
105 }; 108 let node = LinkedListNode {
106 109 next: p_list_tail,
107 list_tail.prev = p_node; 110 prev: list_tail.prev,
108 list_tail.next = p_node; 111 };
109 112
110 // All nodes must be written because they will all be seen by another core 113 list_tail.prev = p_node;
111 ptr::write_volatile(p_node, node); 114 list_tail.next = p_node;
112 ptr::write_volatile(p_list_tail, list_tail); 115
113 } 116 // All nodes must be written because they will all be seen by another core
114 }); 117 ptr::write_volatile(p_node, node);
118 ptr::write_volatile(p_list_tail, list_tail);
119 }
115 } 120 }
116 121
117 /// Remove `node` from the linked list 122 /// Remove `node` from the linked list
118 pub unsafe fn remove_node(mut p_node: *mut LinkedListNode) { 123 pub unsafe fn remove_node(_cs: CriticalSection, mut p_node: *mut LinkedListNode) {
119 interrupt::free(|_| { 124 let node = ptr::read_unaligned(p_node);
120 // trace!("remove node: {:x}", p_node); 125
121 // apparently linked list nodes are not always aligned. 126 if node.next != node.prev {
122 // if more hardfaults occur, more of these may need to be converted to unaligned. 127 let mut node_next = ptr::read_volatile(node.next);
123 let node = ptr::read_unaligned(p_node); 128 let mut node_prev = ptr::read_volatile(node.prev);
124 // trace!("remove node: prev/next {:x}/{:x}", node.prev, node.next); 129
125 130 node_prev.next = node.next;
126 if node.next != node.prev { 131 node_next.prev = node.prev;
127 let mut node_next = ptr::read_volatile(node.next); 132
128 let mut node_prev = ptr::read_volatile(node.prev); 133 ptr::write_volatile(node.next, node_next);
129 134 ptr::write_volatile(node.prev, node_prev);
130 node_prev.next = node.next; 135 } else {
131 node_next.prev = node.prev; 136 let mut node_next = ptr::read_volatile(node.next);
132 137
133 ptr::write_volatile(node.next, node_next); 138 node_next.next = node.next;
134 ptr::write_volatile(node.prev, node_prev); 139 node_next.prev = node.prev;
135 } else { 140
136 let mut node_next = ptr::read_volatile(node.next); 141 ptr::write_volatile(node.next, node_next);
137 142 }
138 node_next.next = node.next;
139 node_next.prev = node.prev;
140
141 ptr::write_volatile(node.next, node_next);
142 }
143 });
144 } 143 }
145 144
146 /// Remove `list_head` and return a pointer to the `node`. 145 /// Remove `list_head` and return a pointer to the `node`.
147 pub unsafe fn remove_head(mut p_list_head: *mut LinkedListNode) -> Option<*mut LinkedListNode> { 146 pub unsafe fn remove_head(
148 interrupt::free(|_| { 147 _cs: CriticalSection,
149 let list_head = ptr::read_volatile(p_list_head); 148 mut p_list_head: *mut LinkedListNode,
150 149 ) -> Option<*mut LinkedListNode> {
151 if list_head.next == p_list_head { 150 let list_head = ptr::read_volatile(p_list_head);
152 None 151
153 } else { 152 if list_head.next == p_list_head {
154 // Allowed because a removed node is not seen by another core 153 None
155 let p_node = list_head.next; 154 } else {
156 Self::remove_node(p_node); 155 // Allowed because a removed node is not seen by another core
157 156 let p_node = list_head.next;
158 Some(p_node) 157 Self::remove_node(_cs, p_node);
159 } 158
160 }) 159 Some(p_node)
160 }
161 } 161 }
162 162
163 /// Remove `list_tail` and return a pointer to the `node`. 163 /// Remove `list_tail` and return a pointer to the `node`.
164 pub unsafe fn remove_tail(mut p_list_tail: *mut LinkedListNode) -> Option<*mut LinkedListNode> { 164 pub unsafe fn remove_tail(
165 interrupt::free(|_| { 165 _cs: CriticalSection,
166 let list_tail = ptr::read_volatile(p_list_tail); 166 mut p_list_tail: *mut LinkedListNode,
167 167 ) -> Option<*mut LinkedListNode> {
168 if list_tail.prev == p_list_tail { 168 let list_tail = ptr::read_volatile(p_list_tail);
169 None 169
170 } else { 170 if list_tail.prev == p_list_tail {
171 // Allowed because a removed node is not seen by another core 171 None
172 let p_node = list_tail.prev; 172 } else {
173 Self::remove_node(p_node); 173 // Allowed because a removed node is not seen by another core
174 174 let p_node = list_tail.prev;
175 Some(p_node) 175 Self::remove_node(_cs, p_node);
176 }
177 })
178 }
179 176
180 pub unsafe fn insert_node_after(mut node: *mut LinkedListNode, mut ref_node: *mut LinkedListNode) { 177 Some(p_node)
181 interrupt::free(|_| { 178 }
182 (*node).next = (*ref_node).next; 179 }
183 (*node).prev = ref_node;
184 (*ref_node).next = node;
185 (*(*node).next).prev = node;
186 });
187 180
188 todo!("this function has not been converted to volatile semantics"); 181 pub unsafe fn insert_node_after(
182 _cs: CriticalSection,
183 mut p_node: *mut LinkedListNode,
184 mut p_ref_node: *mut LinkedListNode,
185 ) {
186 let mut node = ptr::read_volatile(p_node);
187 let mut ref_node = ptr::read_volatile(p_ref_node);
188 let mut prev_node = ptr::read_volatile(ref_node.next);
189
190 node.next = ref_node.next;
191 node.prev = p_ref_node;
192 ref_node.next = p_node;
193 prev_node.prev = p_node;
194
195 ptr::write_volatile(p_node, node);
196 ptr::write_volatile(p_ref_node, ref_node);
197 ptr::write_volatile(node.next, prev_node);
189 } 198 }
190 199
191 pub unsafe fn insert_node_before(mut node: *mut LinkedListNode, mut ref_node: *mut LinkedListNode) { 200 pub unsafe fn insert_node_before(
192 interrupt::free(|_| { 201 _cs: CriticalSection,
193 (*node).next = ref_node; 202 mut node: *mut LinkedListNode,
194 (*node).prev = (*ref_node).prev; 203 mut ref_node: *mut LinkedListNode,
195 (*ref_node).prev = node; 204 ) {
196 (*(*node).prev).next = node; 205 (*node).next = ref_node;
197 }); 206 (*node).prev = (*ref_node).prev;
207 (*ref_node).prev = node;
208 (*(*node).prev).next = node;
198 209
199 todo!("this function has not been converted to volatile semantics"); 210 todo!("this function has not been converted to volatile semantics");
200 } 211 }
201 212
202 pub unsafe fn get_size(mut list_head: *mut LinkedListNode) -> usize { 213 pub unsafe fn get_size(_cs: CriticalSection, mut list_head: *mut LinkedListNode) -> usize {
203 interrupt::free(|_| { 214 let mut size = 0;
204 let mut size = 0; 215 let mut temp: *mut LinkedListNode = core::ptr::null_mut::<LinkedListNode>();
205 let mut temp: *mut LinkedListNode = core::ptr::null_mut::<LinkedListNode>();
206 216
207 temp = (*list_head).next; 217 temp = (*list_head).next;
208 while temp != list_head { 218 while temp != list_head {
209 size += 1; 219 size += 1;
210 temp = (*temp).next 220 temp = (*temp).next
211 } 221 }
212 222
213 size 223 let _ = size;
214 });
215 224
216 todo!("this function has not been converted to volatile semantics"); 225 todo!("this function has not been converted to volatile semantics");
217 } 226 }
218 227
219 pub unsafe fn get_next_node(mut p_ref_node: *mut LinkedListNode) -> *mut LinkedListNode { 228 pub unsafe fn get_next_node(_cs: CriticalSection, mut p_ref_node: *mut LinkedListNode) -> *mut LinkedListNode {
220 interrupt::free(|_| { 229 let ref_node = ptr::read_volatile(p_ref_node);
221 let ref_node = ptr::read_volatile(p_ref_node);
222 230
223 // Allowed because a removed node is not seen by another core 231 // Allowed because a removed node is not seen by another core
224 ref_node.next 232 ref_node.next
225 })
226 } 233 }
227 234
228 pub unsafe fn get_prev_node(mut p_ref_node: *mut LinkedListNode) -> *mut LinkedListNode { 235 pub unsafe fn get_prev_node(_cs: CriticalSection, mut p_ref_node: *mut LinkedListNode) -> *mut LinkedListNode {
229 interrupt::free(|_| { 236 let ref_node = ptr::read_volatile(p_ref_node);
230 let ref_node = ptr::read_volatile(p_ref_node);
231 237
232 // Allowed because a removed node is not seen by another core 238 // Allowed because a removed node is not seen by another core
233 ref_node.prev 239 ref_node.prev
234 })
235 } 240 }
236} 241}
237 242
238#[allow(dead_code)] 243pub struct DebuggableLinkedListNode(*const LinkedListNode);
239unsafe fn debug_linked_list(mut p_node: *mut LinkedListNode) { 244
240 info!("iterating list from node: {:x}", p_node); 245impl Debug for DebuggableLinkedListNode {
241 let mut p_current_node = p_node; 246 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
242 let mut i = 0; 247 // Safe because this is just reading memory, and using unaligned to do it
243 loop { 248 let p_node = self.0;
244 let current_node = ptr::read_volatile(p_current_node); 249
245 info!( 250 f.write_fmt(format_args!("iterating list from node: {:x}", p_node as usize))?;
246 "node (prev, current, next): {:x}, {:x}, {:x}", 251
247 current_node.prev, p_current_node, current_node.next 252 let mut p_current_node = p_node;
248 ); 253 for _ in 0..30 {
254 let current_node = unsafe { ptr::read_unaligned(p_current_node) };
255 f.write_fmt(format_args!(
256 "node (prev, current, next): {:x}, {:x}, {:x}",
257 current_node.prev as usize, p_current_node as usize, current_node.next as usize
258 ))?;
259
260 if current_node.next == p_node as *mut _ {
261 break;
262 }
249 263
250 i += 1; 264 p_current_node = current_node.next;
251 if i > 10 || current_node.next == p_node {
252 break;
253 } 265 }
254 266
255 p_current_node = current_node.next; 267 Ok(())
256 } 268 }
257} 269}