1#![no_std]
8
9use core::fmt::Write;
10
11pub mod dcb;
12pub mod dwt;
13pub mod mpu;
14pub mod nvic;
15pub mod scb;
16pub mod support;
17pub mod syscall;
18pub mod systick;
19
20extern "C" {
22 static _szero: *const u32;
23 static _ezero: *const u32;
24 static _etext: *const u32;
25 static _srelocate: *const u32;
26 static _erelocate: *const u32;
27}
28
29pub trait CortexMVariant {
74 const GENERIC_ISR: unsafe extern "C" fn();
84
85 const SYSTICK_HANDLER: unsafe extern "C" fn();
92
93 const SVC_HANDLER: unsafe extern "C" fn();
96
97 const HARD_FAULT_HANDLER: unsafe extern "C" fn();
99
100 unsafe fn switch_to_user(
104 user_stack: *const usize,
105 process_regs: &mut [usize; 8],
106 ) -> *const usize;
107
108 unsafe fn print_cortexm_state(writer: &mut dyn Write);
112}
113
114#[cfg(any(doc, all(target_arch = "arm", target_os = "none")))]
115pub unsafe extern "C" fn unhandled_interrupt() {
116 use core::arch::asm;
117 let mut interrupt_number: u32;
118
119 asm!(
121 "mrs r0, ipsr",
122 out("r0") interrupt_number,
123 options(nomem, nostack, preserves_flags)
124 );
125
126 interrupt_number &= 0x1ff;
127
128 panic!("Unhandled Interrupt. ISR {} is active.", interrupt_number);
129}
130
131#[cfg(any(doc, all(target_arch = "arm", target_os = "none")))]
132extern "C" {
133 pub fn initialize_ram_jump_to_main();
140}
141
142#[cfg(any(doc, all(target_arch = "arm", target_os = "none")))]
143core::arch::global_asm!(
144"
145 .section .initialize_ram_jump_to_main, \"ax\"
146 .global initialize_ram_jump_to_main
147 .thumb_func
148 initialize_ram_jump_to_main:
149 // Start by initializing .bss memory. The Tock linker script defines
150 // `_szero` and `_ezero` to mark the .bss segment.
151 ldr r0, ={sbss} // r0 = first address of .bss
152 ldr r1, ={ebss} // r1 = first address after .bss
153
154 movs r2, #0 // r2 = 0
155
156 100: // bss_init_loop
157 cmp r1, r0 // We increment r0. Check if we have reached r1
158 // (end of .bss), and stop if so.
159 beq 101f // If r0 == r1, we are done.
160 stm r0!, {{r2}} // Write a word to the address in r0, and increment r0.
161 // Since r2 contains zero, this will clear the memory
162 // pointed to by r0. Using `stm` (store multiple) with the
163 // bang allows us to also increment r0 automatically.
164 b 100b // Continue the loop.
165
166 101: // bss_init_done
167
168 // Now initialize .data memory. This involves coping the values right at the
169 // end of the .text section (in flash) into the .data section (in RAM).
170 ldr r0, ={sdata} // r0 = first address of data section in RAM
171 ldr r1, ={edata} // r1 = first address after data section in RAM
172 ldr r2, ={etext} // r2 = address of stored data initial values
173
174 200: // data_init_loop
175 cmp r1, r0 // We increment r0. Check if we have reached the end
176 // of the data section, and if so we are done.
177 beq 201f // r0 == r1, and we have iterated through the .data section
178 ldm r2!, {{r3}} // r3 = *(r2), r2 += 1. Load the initial value into r3,
179 // and use the bang to increment r2.
180 stm r0!, {{r3}} // *(r0) = r3, r0 += 1. Store the value to memory, and
181 // increment r0.
182 b 200b // Continue the loop.
183
184 201: // data_init_done
185
186 // Now that memory has been initialized, we can jump to main() where the
187 // board initialization takes place and Rust code starts.
188 bl main
189 ",
190 sbss = sym _szero,
191 ebss = sym _ezero,
192 sdata = sym _srelocate,
193 edata = sym _erelocate,
194 etext = sym _etext,
195);
196
197pub unsafe fn print_cortexm_state(writer: &mut dyn Write) {
198 let _ccr = syscall::SCB_REGISTERS[0];
199 let cfsr = syscall::SCB_REGISTERS[1];
200 let hfsr = syscall::SCB_REGISTERS[2];
201 let mmfar = syscall::SCB_REGISTERS[3];
202 let bfar = syscall::SCB_REGISTERS[4];
203
204 let iaccviol = (cfsr & 0x01) == 0x01;
205 let daccviol = (cfsr & 0x02) == 0x02;
206 let munstkerr = (cfsr & 0x08) == 0x08;
207 let mstkerr = (cfsr & 0x10) == 0x10;
208 let mlsperr = (cfsr & 0x20) == 0x20;
209 let mmfarvalid = (cfsr & 0x80) == 0x80;
210
211 let ibuserr = ((cfsr >> 8) & 0x01) == 0x01;
212 let preciserr = ((cfsr >> 8) & 0x02) == 0x02;
213 let impreciserr = ((cfsr >> 8) & 0x04) == 0x04;
214 let unstkerr = ((cfsr >> 8) & 0x08) == 0x08;
215 let stkerr = ((cfsr >> 8) & 0x10) == 0x10;
216 let lsperr = ((cfsr >> 8) & 0x20) == 0x20;
217 let bfarvalid = ((cfsr >> 8) & 0x80) == 0x80;
218
219 let undefinstr = ((cfsr >> 16) & 0x01) == 0x01;
220 let invstate = ((cfsr >> 16) & 0x02) == 0x02;
221 let invpc = ((cfsr >> 16) & 0x04) == 0x04;
222 let nocp = ((cfsr >> 16) & 0x08) == 0x08;
223 let unaligned = ((cfsr >> 16) & 0x100) == 0x100;
224 let divbyzero = ((cfsr >> 16) & 0x200) == 0x200;
225
226 let vecttbl = (hfsr & 0x02) == 0x02;
227 let forced = (hfsr & 0x40000000) == 0x40000000;
228
229 let _ = writer.write_fmt(format_args!("\r\n---| Cortex-M Fault Status |---\r\n"));
230
231 if iaccviol {
232 let _ = writer.write_fmt(format_args!(
233 "Instruction Access Violation: {}\r\n",
234 iaccviol
235 ));
236 }
237 if daccviol {
238 let _ = writer.write_fmt(format_args!(
239 "Data Access Violation: {}\r\n",
240 daccviol
241 ));
242 }
243 if munstkerr {
244 let _ = writer.write_fmt(format_args!(
245 "Memory Management Unstacking Fault: {}\r\n",
246 munstkerr
247 ));
248 }
249 if mstkerr {
250 let _ = writer.write_fmt(format_args!(
251 "Memory Management Stacking Fault: {}\r\n",
252 mstkerr
253 ));
254 }
255 if mlsperr {
256 let _ = writer.write_fmt(format_args!(
257 "Memory Management Lazy FP Fault: {}\r\n",
258 mlsperr
259 ));
260 }
261
262 if ibuserr {
263 let _ = writer.write_fmt(format_args!(
264 "Instruction Bus Error: {}\r\n",
265 ibuserr
266 ));
267 }
268 if preciserr {
269 let _ = writer.write_fmt(format_args!(
270 "Precise Data Bus Error: {}\r\n",
271 preciserr
272 ));
273 }
274 if impreciserr {
275 let _ = writer.write_fmt(format_args!(
276 "Imprecise Data Bus Error: {}\r\n",
277 impreciserr
278 ));
279 }
280 if unstkerr {
281 let _ = writer.write_fmt(format_args!(
282 "Bus Unstacking Fault: {}\r\n",
283 unstkerr
284 ));
285 }
286 if stkerr {
287 let _ = writer.write_fmt(format_args!(
288 "Bus Stacking Fault: {}\r\n",
289 stkerr
290 ));
291 }
292 if lsperr {
293 let _ = writer.write_fmt(format_args!(
294 "Bus Lazy FP Fault: {}\r\n",
295 lsperr
296 ));
297 }
298 if undefinstr {
299 let _ = writer.write_fmt(format_args!(
300 "Undefined Instruction Usage Fault: {}\r\n",
301 undefinstr
302 ));
303 }
304 if invstate {
305 let _ = writer.write_fmt(format_args!(
306 "Invalid State Usage Fault: {}\r\n",
307 invstate
308 ));
309 }
310 if invpc {
311 let _ = writer.write_fmt(format_args!(
312 "Invalid PC Load Usage Fault: {}\r\n",
313 invpc
314 ));
315 }
316 if nocp {
317 let _ = writer.write_fmt(format_args!(
318 "No Coprocessor Usage Fault: {}\r\n",
319 nocp
320 ));
321 }
322 if unaligned {
323 let _ = writer.write_fmt(format_args!(
324 "Unaligned Access Usage Fault: {}\r\n",
325 unaligned
326 ));
327 }
328 if divbyzero {
329 let _ = writer.write_fmt(format_args!(
330 "Divide By Zero: {}\r\n",
331 divbyzero
332 ));
333 }
334
335 if vecttbl {
336 let _ = writer.write_fmt(format_args!(
337 "Bus Fault on Vector Table Read: {}\r\n",
338 vecttbl
339 ));
340 }
341 if forced {
342 let _ = writer.write_fmt(format_args!(
343 "Forced Hard Fault: {}\r\n",
344 forced
345 ));
346 }
347
348 if mmfarvalid {
349 let _ = writer.write_fmt(format_args!(
350 "Faulting Memory Address: {:#010X}\r\n",
351 mmfar
352 ));
353 }
354 if bfarvalid {
355 let _ = writer.write_fmt(format_args!(
356 "Bus Fault Address: {:#010X}\r\n",
357 bfar
358 ));
359 }
360
361 if cfsr == 0 && hfsr == 0 {
362 let _ = writer.write_fmt(format_args!("No Cortex-M faults detected.\r\n"));
363 } else {
364 let _ = writer.write_fmt(format_args!(
365 "Fault Status Register (CFSR): {:#010X}\r\n",
366 cfsr
367 ));
368 let _ = writer.write_fmt(format_args!(
369 "Hard Fault Status Register (HFSR): {:#010X}\r\n",
370 hfsr
371 ));
372 }
373}
374
375#[cfg(not(any(doc, all(target_arch = "arm", target_os = "none"))))]
383pub unsafe extern "C" fn unhandled_interrupt() {
384 unimplemented!()
385}
386
387#[cfg(not(any(doc, all(target_arch = "arm", target_os = "none"))))]
388pub unsafe extern "C" fn initialize_ram_jump_to_main() {
389 unimplemented!()
390}