|
1 | 1 | #![no_std]
|
2 | 2 | #![no_main]
|
3 | 3 |
|
| 4 | +use core::sync::atomic::{compiler_fence, Ordering}; |
| 5 | + |
4 | 6 | use stage0::{romapi, sha256, SLOT_SIZE_WORDS};
|
5 | 7 |
|
6 |
| -use cortex_m_rt::entry; |
| 8 | +use cortex_m_rt::{entry, exception, ExceptionFrame}; |
7 | 9 | use lpc55_pac::interrupt;
|
8 | 10 |
|
9 | 11 | /// Bootloader entry point. These are not the first instructions executed, since
|
@@ -50,15 +52,29 @@ fn main() -> ! {
|
50 | 52 |
|
51 | 53 | #[panic_handler]
|
52 | 54 | fn panic_handler(_: &core::panic::PanicInfo) -> ! {
|
| 55 | + // We use a BKPT instruction to wake any attached debugger. If no debugger |
| 56 | + // is attached, BKPT escalates into a HardFault, falling to the handler |
| 57 | + // below. This way we can reuse its fault indication code. |
| 58 | + loop { |
| 59 | + cortex_m::asm::bkpt(); |
| 60 | + } |
| 61 | +} |
| 62 | + |
| 63 | +#[exception] |
| 64 | +unsafe fn HardFault(_ef: &ExceptionFrame) -> ! { |
53 | 65 | // Safety: the GPIO peripheral is static, and we're not racing anyone by
|
54 |
| - // definition since we're in the process of panicking to a halt. |
| 66 | + // definition since we're handling a HardFault. So we win. |
55 | 67 | let gpio = unsafe { &*lpc55_pac::GPIO::ptr() };
|
56 | 68 | // Turn on the RED LED on the xpresso board.
|
57 | 69 | gpio.dir[1].write(|w| unsafe { w.bits(1 << 6) });
|
58 | 70 |
|
59 |
| - // Park! |
| 71 | + // Spin -- don't use BKPT here because if no debugger is attached it'll |
| 72 | + // escalate to another HardFault and lock the processor. |
60 | 73 | loop {
|
61 |
| - cortex_m::asm::bkpt(); |
| 74 | + // This is enough to force LLVM to compile the infinite loop as |
| 75 | + // something other than a UDF, but not enough to generate instructions; |
| 76 | + // using an explicit nop here costs two bytes more. |
| 77 | + compiler_fence(Ordering::SeqCst); |
62 | 78 | }
|
63 | 79 | }
|
64 | 80 |
|
|
0 commit comments