aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32-wpan/src/wb55/unsafe_linked_list.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-stm32-wpan/src/wb55/unsafe_linked_list.rs')
-rw-r--r--embassy-stm32-wpan/src/wb55/unsafe_linked_list.rs358
1 files changed, 185 insertions, 173 deletions
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}