rp2040_panic_usb_boot/
lib.rs1#![no_std]
2
3use core::fmt::Write;
4use core::panic::PanicInfo;
5
6struct Cursor<'a> {
7 buf: &'a mut [u8],
8 pos: usize,
9}
10
11impl<'a> Cursor<'a> {
12 fn new(buf: &'a mut [u8]) -> Cursor<'a> {
13 Cursor { buf, pos: 0 }
14 }
15}
16
17impl core::fmt::Write for Cursor<'_> {
18 fn write_str(&mut self, s: &str) -> core::fmt::Result {
19 let len = s.len();
20 if len < self.buf.len() - self.pos {
21 self.buf[self.pos..self.pos + len].clone_from_slice(s.as_bytes());
22 self.pos += len;
23 Ok(())
24 } else {
25 Err(core::fmt::Error)
26 }
27 }
28}
29
30#[inline(never)]
31#[panic_handler]
32fn panic(info: &PanicInfo) -> ! {
33 cortex_m::interrupt::disable();
34 disable_xip_cache();
36
37 let buf: &mut [u8] = unsafe { core::slice::from_raw_parts_mut(0x15000000 as *mut u8, 0x4000) };
39 let written = {
40 let mut cur = Cursor::new(buf);
41 write!(&mut cur, "{}\n\0", info).ok();
42 cur.pos
43 };
44
45 buf[written..0x4000].fill(0);
47
48 if !xosc_is_running() {
50 xosc_start_delay((12_000 + 128) / 256);
51 xosc_enable(true);
52 while !(xosc_is_running()) {}
53 }
54
55 (ROMFuncs::load().unwrap().reset_to_usb_boot)(0, 0);
57 loop {}
58}
59
60fn find_func<T>(tag: [u8; 2]) -> Option<T> {
63 let tag = u16::from_le_bytes(tag) as u32;
64 type RomTableLookupFn = unsafe extern "C" fn(table: *const u16, code: u32) -> usize;
65 const ROM_TABLE_LOOKUP_PTR: *const u16 = 0x0000_0018 as _;
67 const FUNC_TABLE: *const u16 = 0x0000_0014 as _;
70 unsafe {
71 let lookup_func = ROM_TABLE_LOOKUP_PTR.read() as usize;
72 let lookup_func: RomTableLookupFn = core::mem::transmute(lookup_func);
73 let table = FUNC_TABLE.read() as usize;
74 let result = lookup_func(table as *const u16, tag);
75 if result == 0 {
76 return None;
77 }
78 Some(core::mem::transmute_copy(&result))
79 }
80}
81
82struct ROMFuncs {
83 reset_to_usb_boot: extern "C" fn(gpio_activity_pin_mask: u32, disable_interface_mask: u32),
84}
85
86impl ROMFuncs {
87 fn load() -> Option<Self> {
88 Some(ROMFuncs {
89 reset_to_usb_boot: find_func(*b"UB")?,
90 })
91 }
92}
93
94struct Reg {
98 address: *mut u32,
99}
100
101impl Reg {
102 const fn new(address: u32) -> Self {
103 Self {
104 address: address as *mut u32,
105 }
106 }
107
108 fn read(&self) -> u32 {
109 unsafe { self.address.read_volatile() }
110 }
111
112 fn write(&self, value: u32) {
113 unsafe {
114 self.address.write_volatile(value);
115 }
116 }
117}
118
119const XIP_CTRL: Reg = Reg::new(0x1400_0000);
125
126const XOSC_CTRL: Reg = Reg::new(0x4002_4000);
132
133const XOSC_STATUS: Reg = Reg::new(0x4002_4004);
140
141const XOSC_STARTUP: Reg = Reg::new(0x4002_400c);
146
147fn disable_xip_cache() {
150 XIP_CTRL.write(0);
152}
153
154fn xosc_is_running() -> bool {
155 (XOSC_STATUS.read() & (1 << 31)) == (1 << 31)
157}
158
159fn xosc_start_delay(delay: u32) {
160 debug_assert!(delay < (1 << 14));
162 let delay = delay & (1 << 14);
163 XOSC_STARTUP.write(delay);
164}
165
166fn xosc_enable(enable: bool) {
167 let freq_range = 0xaa0;
169 let enable_val = match enable {
170 true => 0xfab,
171 false => 0xd1e,
172 };
173 XOSC_CTRL.write(freq_range | (enable_val << 12));
174}