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.rs257
1 files changed, 257 insertions, 0 deletions
diff --git a/embassy-stm32-wpan/src/wb55/unsafe_linked_list.rs b/embassy-stm32-wpan/src/wb55/unsafe_linked_list.rs
new file mode 100644
index 000000000..d8bc29763
--- /dev/null
+++ b/embassy-stm32-wpan/src/wb55/unsafe_linked_list.rs
@@ -0,0 +1,257 @@
1//! Unsafe linked list.
2//! Translated from ST's C by `c2rust` tool.
3
4#![allow(
5 dead_code,
6 mutable_transmutes,
7 non_camel_case_types,
8 non_snake_case,
9 non_upper_case_globals,
10 unused_assignments,
11 unused_mut
12)]
13
14use core::ptr;
15
16use cortex_m::interrupt;
17
18#[derive(Copy, Clone)]
19#[repr(C, packed(4))]
20pub struct LinkedListNode {
21 pub next: *mut LinkedListNode,
22 pub prev: *mut LinkedListNode,
23}
24
25impl Default for LinkedListNode {
26 fn default() -> Self {
27 LinkedListNode {
28 next: core::ptr::null_mut(),
29 prev: core::ptr::null_mut(),
30 }
31 }
32}
33
34impl LinkedListNode {
35 pub unsafe fn init_head(mut p_list_head: *mut LinkedListNode) {
36 ptr::write_volatile(
37 p_list_head,
38 LinkedListNode {
39 next: p_list_head,
40 prev: p_list_head,
41 },
42 );
43 }
44
45 pub unsafe fn is_empty(mut p_list_head: *mut LinkedListNode) -> bool {
46 interrupt::free(|_| ptr::read_volatile(p_list_head).next == p_list_head)
47 }
48
49 /// 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 interrupt::free(|_| {
52 let mut list_head = ptr::read_volatile(p_list_head);
53 if p_list_head != list_head.next {
54 let mut node_next = ptr::read_volatile(list_head.next);
55 let node = LinkedListNode {
56 next: list_head.next,
57 prev: p_list_head,
58 };
59
60 list_head.next = p_node;
61 node_next.prev = p_node;
62
63 // All nodes must be written because they will all be seen by another core
64 ptr::write_volatile(p_node, node);
65 ptr::write_volatile(node.next, node_next);
66 ptr::write_volatile(p_list_head, list_head);
67 } else {
68 let node = LinkedListNode {
69 next: list_head.next,
70 prev: p_list_head,
71 };
72
73 list_head.next = p_node;
74 list_head.prev = p_node;
75
76 // All nodes must be written because they will all be seen by another core
77 ptr::write_volatile(p_node, node);
78 ptr::write_volatile(p_list_head, list_head);
79 }
80 });
81 }
82
83 /// 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) {
85 interrupt::free(|_| {
86 let mut list_tail = ptr::read_volatile(p_list_tail);
87 if p_list_tail != list_tail.prev {
88 let mut node_prev = ptr::read_volatile(list_tail.prev);
89 let node = LinkedListNode {
90 next: p_list_tail,
91 prev: list_tail.prev,
92 };
93
94 list_tail.prev = p_node;
95 node_prev.next = p_node;
96
97 // All nodes must be written because they will all be seen by another core
98 ptr::write_volatile(p_node, node);
99 ptr::write_volatile(node.prev, node_prev);
100 ptr::write_volatile(p_list_tail, list_tail);
101 } else {
102 let node = LinkedListNode {
103 next: p_list_tail,
104 prev: list_tail.prev,
105 };
106
107 list_tail.prev = p_node;
108 list_tail.next = p_node;
109
110 // All nodes must be written because they will all be seen by another core
111 ptr::write_volatile(p_node, node);
112 ptr::write_volatile(p_list_tail, list_tail);
113 }
114 });
115 }
116
117 /// Remove `node` from the linked list
118 pub unsafe fn remove_node(mut p_node: *mut LinkedListNode) {
119 interrupt::free(|_| {
120 // trace!("remove node: {:x}", p_node);
121 // apparently linked list nodes are not always aligned.
122 // if more hardfaults occur, more of these may need to be converted to unaligned.
123 let node = ptr::read_unaligned(p_node);
124 // trace!("remove node: prev/next {:x}/{:x}", node.prev, node.next);
125
126 if node.next != node.prev {
127 let mut node_next = ptr::read_volatile(node.next);
128 let mut node_prev = ptr::read_volatile(node.prev);
129
130 node_prev.next = node.next;
131 node_next.prev = node.prev;
132
133 ptr::write_volatile(node.next, node_next);
134 ptr::write_volatile(node.prev, node_prev);
135 } else {
136 let mut node_next = ptr::read_volatile(node.next);
137
138 node_next.next = node.next;
139 node_next.prev = node.prev;
140
141 ptr::write_volatile(node.next, node_next);
142 }
143 });
144 }
145
146 /// 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> {
148 interrupt::free(|_| {
149 let list_head = ptr::read_volatile(p_list_head);
150
151 if list_head.next == p_list_head {
152 None
153 } else {
154 // Allowed because a removed node is not seen by another core
155 let p_node = list_head.next;
156 Self::remove_node(p_node);
157
158 Some(p_node)
159 }
160 })
161 }
162
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> {
165 interrupt::free(|_| {
166 let list_tail = ptr::read_volatile(p_list_tail);
167
168 if list_tail.prev == p_list_tail {
169 None
170 } else {
171 // Allowed because a removed node is not seen by another core
172 let p_node = list_tail.prev;
173 Self::remove_node(p_node);
174
175 Some(p_node)
176 }
177 })
178 }
179
180 pub unsafe fn insert_node_after(mut node: *mut LinkedListNode, mut ref_node: *mut LinkedListNode) {
181 interrupt::free(|_| {
182 (*node).next = (*ref_node).next;
183 (*node).prev = ref_node;
184 (*ref_node).next = node;
185 (*(*node).next).prev = node;
186 });
187
188 todo!("this function has not been converted to volatile semantics");
189 }
190
191 pub unsafe fn insert_node_before(mut node: *mut LinkedListNode, mut ref_node: *mut LinkedListNode) {
192 interrupt::free(|_| {
193 (*node).next = ref_node;
194 (*node).prev = (*ref_node).prev;
195 (*ref_node).prev = node;
196 (*(*node).prev).next = node;
197 });
198
199 todo!("this function has not been converted to volatile semantics");
200 }
201
202 pub unsafe fn get_size(mut list_head: *mut LinkedListNode) -> usize {
203 interrupt::free(|_| {
204 let mut size = 0;
205 let mut temp: *mut LinkedListNode = core::ptr::null_mut::<LinkedListNode>();
206
207 temp = (*list_head).next;
208 while temp != list_head {
209 size += 1;
210 temp = (*temp).next
211 }
212
213 size
214 });
215
216 todo!("this function has not been converted to volatile semantics");
217 }
218
219 pub unsafe fn get_next_node(mut p_ref_node: *mut LinkedListNode) -> *mut LinkedListNode {
220 interrupt::free(|_| {
221 let ref_node = ptr::read_volatile(p_ref_node);
222
223 // Allowed because a removed node is not seen by another core
224 ref_node.next
225 })
226 }
227
228 pub unsafe fn get_prev_node(mut p_ref_node: *mut LinkedListNode) -> *mut LinkedListNode {
229 interrupt::free(|_| {
230 let ref_node = ptr::read_volatile(p_ref_node);
231
232 // Allowed because a removed node is not seen by another core
233 ref_node.prev
234 })
235 }
236}
237
238#[allow(dead_code)]
239unsafe fn debug_linked_list(mut p_node: *mut LinkedListNode) {
240 info!("iterating list from node: {:x}", p_node);
241 let mut p_current_node = p_node;
242 let mut i = 0;
243 loop {
244 let current_node = ptr::read_volatile(p_current_node);
245 info!(
246 "node (prev, current, next): {:x}, {:x}, {:x}",
247 current_node.prev, p_current_node, current_node.next
248 );
249
250 i += 1;
251 if i > 10 || current_node.next == p_node {
252 break;
253 }
254
255 p_current_node = current_node.next;
256 }
257}