rp2040_rom/lib.rs
1#![no_std]
2
3//! This module provides the ability to call Raspberry Pi ROM functions.
4//!
5//! The RP2040 ROM contains several useful functions that can be called
6//! directly from user code, including functions to reset the device and
7//! enter the USB bootloader.
8//!
9//! # Safety
10//!
11//! All functions in this crate are marked as `unsafe` because they involve
12//! direct hardware manipulation and can reset the device.
13//!
14//! # Example
15//!
16//! ```rust,no_run
17//! use rp2040_rom::ROM;
18//!
19//! // Reset into USB bootloader mode
20//! unsafe {
21//! ROM::reset_usb_boot(0, 0);
22//! }
23//! ```
24
25// Copyright (c) 2025 Piers Finlayson <piers@piers.rocks>
26//
27// MIT licensed - see https://opensource.org/licenses/MIT
28
29/// ROM function table offset for the RP2040
30/// From the datasheet:
31/// Pointer to a public function lookup table (rom_func_table)
32const BOOTROM_FUNC_TABLE_OFFSET: u16 = 0x14;
33
34/// ROM lookup table offset for the RP2040
35/// From the datasheet:
36/// Pointer to a helper function (rom_table_lookup())
37const BOOTROM_TABLE_LOOKUP_OFFSET: u16 = 0x18;
38
39/// Object containing exposed ROM functions
40#[allow(clippy::upper_case_acronyms)]
41pub struct ROM {}
42
43/// Public functions
44impl ROM {
45 /// Resets the device and enters USB bootloader mode.
46 ///
47 /// # Parameters
48 ///
49 /// * `usb_activity_gpio_pin_mask` - Bitmask of GPIO pins to check for USB activity
50 /// * `disable_interface_mask` - Bitmask to disable specific interfaces
51 ///
52 /// # Safety
53 ///
54 /// This function will reset the device and not return.
55 pub unsafe fn reset_usb_boot(usb_activity_gpio_pin_mask: u32, disable_interface_mask: u32) -> ! {
56 // ROM reset_usb_boot function definition
57 type RomResetUsbBootFn =
58 unsafe extern "C" fn(usb_activity_gpio_pin_mask: u32, disable_interface_mask: u32) -> !;
59
60 // The two character code for the reset_usb_boot function in the
61 // lookup table
62 const ROM_FUNC_RESET_USB_BOOT: (u8, u8) = (b'U', b'B');
63
64 // Get the function pointer for reset_usb_boot and turn it into a
65 // function we can call
66 let func_ptr = Self::rom_func_lookup(ROM_FUNC_RESET_USB_BOOT);
67 let func: RomResetUsbBootFn = core::mem::transmute(func_ptr);
68
69 // Call the function
70 func(usb_activity_gpio_pin_mask, disable_interface_mask);
71 }
72}
73
74// Private functions
75impl ROM {
76 // Get the lookup code for a function, based on the two characters
77 // While the lookup table technically takes a u16, the lookup function
78 // takes a u32, so we'll use a u32 internally.
79 const fn rom_table_code(c1: u8, c2: u8) -> u32 {
80 (c1 as u32) | ((c2 as u32) << 8)
81 }
82
83 // Convert a u16 provided by the ROM lookup table to a pointer
84 unsafe fn rom_hword_as_ptr(rom_address: u16) -> *mut core::ffi::c_void {
85 // Convert to usize first
86 let addr_val = rom_address as usize;
87
88 // Create pointer AND dereference it
89 let value = unsafe { *(addr_val as *const u16) };
90
91 // Convert value to pointer size then to void pointer
92 value as usize as *mut core::ffi::c_void
93 }
94
95 // Get the pointer for a function, based on the two characters used to
96 // index it
97 unsafe fn rom_func_lookup(code: (u8, u8)) -> *mut core::ffi::c_void {
98 // The ROM reset_usb_boot function definition
99 type RomTableLookupFn =
100 unsafe extern "C" fn(table: *const u16, code: u32) -> *mut core::ffi::c_void;
101
102 // Get the 32-bit code for the two characters that we need to pass
103 // into the lookup function
104 let (c1, c2) = code;
105 let code = Self::rom_table_code(c1, c2);
106
107 // Get the function table address
108 let func_table_addr = Self::rom_hword_as_ptr(BOOTROM_FUNC_TABLE_OFFSET);
109 let func_table = func_table_addr as *const u16;
110
111 // Get the lookup function address
112 let lookup_addr = Self::rom_hword_as_ptr(BOOTROM_TABLE_LOOKUP_OFFSET);
113 let rom_table_lookup: RomTableLookupFn = core::mem::transmute(lookup_addr);
114
115 // Use the lookup function to lookup this code
116 rom_table_lookup(func_table, code)
117 }
118}