Skip to main content

rp235x_hal/
rom_data.rs

1//! Functions and data from the RPI Bootrom.
2//!
3//! From [Section 5.4](https://rptl.io/rp2350-datasheet#section_bootrom) of the
4//! RP2350 datasheet:
5//!
6//! > Whilst some ROM space is dedicated to the implementation of the boot
7//! > sequence and USB/UART boot interfaces, the bootrom also contains public
8//! > functions that provide useful RP2350 functionality that may be useful for
9//! > any code or runtime running on the device
10
11/// A bootrom function table code.
12pub type RomFnTableCode = [u8; 2];
13
14/// This function searches for the tag which matches the mask.
15type RomTableLookupFn = unsafe extern "C" fn(code: u32, mask: u32) -> usize;
16
17/// Pointer to the value lookup function supplied by the ROM.
18///
19/// This address is described at `5.5.1. Locating the API Functions`
20#[cfg(all(target_arch = "arm", target_os = "none"))]
21const ROM_TABLE_LOOKUP_A2: *const u16 = 0x0000_0016 as _;
22
23/// Pointer to the value lookup function supplied by the ROM.
24///
25/// This address is described at `5.5.1. Locating the API Functions`
26#[cfg(all(target_arch = "arm", target_os = "none"))]
27const ROM_TABLE_LOOKUP_A1: *const u32 = 0x0000_0018 as _;
28
29/// Pointer to the data lookup function supplied by the ROM.
30///
31/// On Arm, the same function is used to look up code and data.
32#[cfg(all(target_arch = "arm", target_os = "none"))]
33const ROM_DATA_LOOKUP_A2: *const u16 = ROM_TABLE_LOOKUP_A2;
34
35/// Pointer to the data lookup function supplied by the ROM.
36///
37/// On Arm, the same function is used to look up code and data.
38#[cfg(all(target_arch = "arm", target_os = "none"))]
39const ROM_DATA_LOOKUP_A1: *const u32 = ROM_TABLE_LOOKUP_A1;
40
41/// Pointer to the value lookup function supplied by the ROM.
42///
43/// This address is described at `5.5.1. Locating the API Functions`
44#[cfg(not(all(target_arch = "arm", target_os = "none")))]
45const ROM_TABLE_LOOKUP_A2: *const u16 = 0x0000_7DFA as _;
46
47/// Pointer to the value lookup function supplied by the ROM.
48///
49/// This address is described at `5.5.1. Locating the API Functions`
50#[cfg(not(all(target_arch = "arm", target_os = "none")))]
51const ROM_TABLE_LOOKUP_A1: *const u32 = 0x0000_7DF8 as _;
52
53/// Pointer to the data lookup function supplied by the ROM.
54///
55/// On RISC-V, a different function is used to look up data.
56#[cfg(not(all(target_arch = "arm", target_os = "none")))]
57const ROM_DATA_LOOKUP_A2: *const u16 = 0x0000_7DF8 as _;
58
59/// Pointer to the data lookup function supplied by the ROM.
60///
61/// On RISC-V, a different function is used to look up data.
62#[cfg(not(all(target_arch = "arm", target_os = "none")))]
63const ROM_DATA_LOOKUP_A1: *const u32 = 0x0000_7DF4 as _;
64
65/// Address of the version number of the ROM.
66const VERSION_NUMBER: *const u8 = 0x0000_0013 as _;
67
68#[allow(unused)]
69mod rt_flags {
70    pub const FUNC_RISCV: u32 = 0x0001;
71    pub const FUNC_RISCV_FAR: u32 = 0x0003;
72    pub const FUNC_ARM_SEC: u32 = 0x0004;
73    // reserved for 32-bit pointer: 0x0008
74    pub const FUNC_ARM_NONSEC: u32 = 0x0010;
75    // reserved for 32-bit pointer: 0x0020
76    pub const DATA: u32 = 0x0040;
77    // reserved for 32-bit pointer: 0x0080
78    #[cfg(all(target_arch = "arm", target_os = "none"))]
79    pub const FUNC_ARM_SEC_RISCV: u32 = FUNC_ARM_SEC;
80    #[cfg(not(all(target_arch = "arm", target_os = "none")))]
81    pub const FUNC_ARM_SEC_RISCV: u32 = FUNC_RISCV;
82}
83
84/// Retrieve rom content from a table using a code.
85pub fn rom_table_lookup(tag: RomFnTableCode, mask: u32) -> usize {
86    let tag = u16::from_le_bytes(tag) as u32;
87    unsafe {
88        let lookup_func = if rom_version_number() == 1 {
89            ROM_TABLE_LOOKUP_A1.read() as usize
90        } else {
91            ROM_TABLE_LOOKUP_A2.read() as usize
92        };
93        let lookup_func: RomTableLookupFn = core::mem::transmute(lookup_func);
94        lookup_func(tag, mask)
95    }
96}
97
98/// Retrieve rom data content from a table using a code.
99pub fn rom_data_lookup(tag: RomFnTableCode, mask: u32) -> usize {
100    let tag = u16::from_le_bytes(tag) as u32;
101    unsafe {
102        let lookup_func = if rom_version_number() == 1 {
103            ROM_DATA_LOOKUP_A1.read() as usize
104        } else {
105            ROM_DATA_LOOKUP_A2.read() as usize
106        };
107        let lookup_func: RomTableLookupFn = core::mem::transmute(lookup_func);
108        lookup_func(tag, mask)
109    }
110}
111
112/// bootrom API function return codes as defined by section 5.4.3 in the rp2350 data sheet
113/// See: https://datasheets.raspberrypi.com/rp2350/rp2350-datasheet.pdf
114#[repr(i32)]
115#[derive(Debug)]
116pub enum BootRomApiErrorCode {
117    /// The operation was disallowed by a security constraint
118    NotPermitted = -4,
119    /// One or more parameters passed to the function is outside the range of
120    /// supported values; [`BootRomApiErrorCode::InvalidAddress`] and
121    /// [`BootRomApiErrorCode::BadAlignment`] are more specific errors.
122    InvalidArg = -5,
123    /// An address argument was out-of-bounds or was determined to be an address
124    /// that the caller may not access
125    InvalidAddress = -10,
126    /// An address passed to the function was not correctly aligned
127    BadAlignment = -11,
128    /// Something happened or failed to happen in the past, and consequently the
129    /// request cannot currently be serviced.
130    InvalidState = -12,
131    /// A user-allocated buffer was too small to hold the result or working state
132    /// of the function
133    BufferTooSmall = -13,
134    /// The call failed because another bootrom function must be called first.
135    PreconditionNotMet = -14,
136    /// Cached data was determined to be inconsistent with the full version of
137    /// the data it was copied from
138    ModifiedData = -15,
139    /// The contents of a data structure are invalid
140    InvalidData = -16,
141    /// An attempt was made to access something that does not exist; or, a search failed
142    NotFound = -17,
143    /// Modification is impossible based on current state; e.g. attempted to clear
144    /// an OTP bit.
145    UnsupportedModification = -18,
146    /// A required lock is not owned. See Section 5.4.4.
147    LockRequired = -19,
148    /// An unknown error
149    Unknown = -1,
150}
151
152impl From<i32> for BootRomApiErrorCode {
153    fn from(value: i32) -> Self {
154        match value {
155            -4 => Self::NotPermitted,
156            -5 => Self::InvalidArg,
157            -10 => Self::InvalidAddress,
158            -11 => Self::BadAlignment,
159            -12 => Self::InvalidState,
160            -13 => Self::BufferTooSmall,
161            -14 => Self::PreconditionNotMet,
162            -15 => Self::ModifiedData,
163            -16 => Self::InvalidData,
164            -17 => Self::NotFound,
165            -18 => Self::UnsupportedModification,
166            -19 => Self::LockRequired,
167            _ => Self::Unknown,
168        }
169    }
170}
171
172/// This module defines a safe api to access the `get_sys_info` bootrom function
173#[allow(unused)]
174pub mod sys_info_api {
175    use super::BootRomApiErrorCode;
176
177    /// Flags that the `get_sys_info`/ rom function can take
178    #[repr(u32)]
179    pub enum GetSysInfoFlag {
180        /// The flag used to get a chip's unique identifier
181        ChipInfo = 0x0001,
182        /// The flag used to get the critical register's value
183        Critical = 0x0002,
184        /// The flag used to get the current running CPU Architecture
185        CpuInfo = 0x0004,
186        /// The flag used to get flash device info
187        FlashDevInfo = 0x0008,
188        /// The flag used to get the random 128 bit integer generated on boot
189        BootRandom = 0x0010,
190        // Ignore nonce for now since it can't/shouldn't be called anyway?
191        // Nonce = 0x0020,
192        /// The flag used to get boot diagnostic info
193        BootInfo = 0x0040,
194    }
195
196    impl GetSysInfoFlag {
197        /// Returns the length of the buffer needed to hold the data for the related operation returned
198        /// by [`super::get_sys_info()`]. This includes the initial segment to indicate which flags
199        /// were supported. The underlying enum represent a bitmask and these masks can be OR'd
200        /// together, however the safe API only uses one at a time so adding sizes is not a concern.
201        const fn buffer_length(&self) -> usize {
202            match self {
203                GetSysInfoFlag::ChipInfo => 4,
204                GetSysInfoFlag::Critical
205                | GetSysInfoFlag::CpuInfo
206                | GetSysInfoFlag::FlashDevInfo => 2,
207                GetSysInfoFlag::BootRandom | GetSysInfoFlag::BootInfo => 5,
208            }
209        }
210    }
211
212    /// The unqiue identifier for each chip as reported by [`chip_info`]
213    pub struct ChipInfo {
214        /// The value of the `CHIP_INFO_PACKAGE_SEL` register
215        pub package_sel: u32,
216        /// The device's id
217        pub device_id: u32,
218        /// The wafer's id
219        pub wafer_id: u32,
220    }
221
222    impl From<[u32; 3]> for ChipInfo {
223        fn from(value: [u32; 3]) -> Self {
224            ChipInfo {
225                package_sel: value[0],
226                device_id: value[1],
227                wafer_id: value[2],
228            }
229        }
230    }
231
232    /// The value held within the critical register as reported by [`otp_critical_register`]
233    pub struct OtpCriticalReg(u32);
234
235    impl OtpCriticalReg {
236        /// Check if secure boot is enabled
237        pub fn secure_boot_enabled(&self) -> bool {
238            (self.0 & 0x1) == 1
239        }
240
241        /// Check if secure debug is disabled
242        pub fn secure_debug_disabled(&self) -> bool {
243            (self.0 & 0x2) >> 1 == 1
244        }
245
246        /// Check if debug is disabled
247        pub fn debug_disabled(&self) -> bool {
248            (self.0 & 0x4) >> 2 == 1
249        }
250
251        /// Check the value of `DEFAULT_ARCHSEL`
252        pub fn default_arch_sel(&self) -> bool {
253            (self.0 & 0x8) >> 3 == 1
254        }
255
256        /// Check if the glitch detector is enabled
257        pub fn glitch_detector_enabled(&self) -> bool {
258            (self.0 & 0x10) >> 4 == 1
259        }
260
261        /// Value of `GLITCH_DETECTOR_SENS
262        pub fn glitch_detector_sens(&self) -> u8 {
263            ((self.0 & 0x60) >> 5) as _
264        }
265
266        /// Check if ARM is disabled
267        pub fn arm_disabled(&self) -> bool {
268            (self.0 & 0x10000) >> 16 == 1
269        }
270
271        /// Check if Risc-V is disabled
272        pub fn risc_disabled(&self) -> bool {
273            (self.0 & 0x20000) >> 17 == 1
274        }
275    }
276
277    impl From<[u32; 1]> for OtpCriticalReg {
278        fn from(value: [u32; 1]) -> OtpCriticalReg {
279            OtpCriticalReg(value[0])
280        }
281    }
282
283    #[repr(u32)]
284    /// CPU architectures that might be running as reported by [`cpu_info`]
285    pub enum CpuInfo {
286        /// Arm CPU
287        Arm,
288        /// Risc-V CPU
289        Risc,
290    }
291
292    impl From<[u32; 1]> for CpuInfo {
293        fn from(value: [u32; 1]) -> CpuInfo {
294            if value[0] == 0 {
295                CpuInfo::Arm
296            } else {
297                CpuInfo::Risc
298            }
299        }
300    }
301
302    /// Flash device information as reported by [`flash_dev_info`]
303    pub struct FlashDevInfo(u32);
304
305    /// A struct to represent possible byte sizes that may be reported in [`FlashDevInfo`]
306    #[repr(u32)]
307    pub enum FlashDevInfoSize {
308        /// 0 bytes
309        None,
310        /// 8 KiB
311        K8,
312        /// 16 KiB
313        K16,
314        /// 32 KiB
315        K32,
316        /// 64 KiB
317        K64,
318        /// 128 KiB
319        K128,
320        /// 256 KiB
321        K256,
322        /// 512 KiB
323        K512,
324        /// 1 MiB
325        M1,
326        /// 2 MiB
327        M2,
328        /// 4 Mib
329        M4,
330        /// 8 MiB
331        M8,
332        /// 16 MiB
333        M16,
334        /// Unknown size
335        Unknown,
336    }
337
338    impl From<u32> for FlashDevInfoSize {
339        fn from(value: u32) -> Self {
340            if value > 0xc {
341                return Self::Unknown;
342            }
343
344            unsafe { core::mem::transmute::<u32, FlashDevInfoSize>(value) }
345        }
346    }
347
348    impl FlashDevInfo {
349        /// GPIO Number to be used for the secondary flash chip. See datasheet section 13.9
350        pub fn cs1_gpio(&self) -> u8 {
351            (self.0 & 0x1f) as _
352        }
353
354        /// Check if all attached devices support a block erase command with a command prefix of
355        /// `D8h``
356        pub fn d8h_erase_supported(&self) -> bool {
357            (self.0 & 0x80) != 0
358        }
359
360        /// Flash/PSRAM size on chip select 0
361        pub fn cs0_size(&self) -> FlashDevInfoSize {
362            FlashDevInfoSize::from((self.0 & 0xf00) >> 8)
363        }
364
365        /// Flash/PSRAM size on chip select 1
366        pub fn cs1_size(&self) -> FlashDevInfoSize {
367            FlashDevInfoSize::from((self.0 & 0xf000) >> 12)
368        }
369    }
370
371    impl From<[u32; 1]> for FlashDevInfo {
372        fn from(value: [u32; 1]) -> FlashDevInfo {
373            FlashDevInfo(value[0])
374        }
375    }
376
377    /// 128 bit random integer generated per boot as reported by [`boot_random`]
378    pub struct BootRandom(pub u128);
379
380    impl From<[u32; 4]> for BootRandom {
381        fn from(value: [u32; 4]) -> BootRandom {
382            let mut result = 0;
383            for word in value {
384                result = (result << 32) | u128::from(word);
385            }
386            BootRandom(result)
387        }
388    }
389
390    // based on https://github.com/raspberrypi/pico-sdk/blob/master/src/rp2_common/pico_bootrom/include/pico/bootrom.h
391    /// Boot diagnostic info as described in 5.4 under the `get_sys_info` function
392    pub struct BootInfo {
393        /// Information about which partition is being diagnosed
394        pub diagnostic_partition: PartitionIndex,
395        /// Type of boot that occurred
396        pub boot_type: BootType,
397        /// Whether it was a chained boot
398        pub chained: bool,
399        /// What partition the boot came from
400        pub partition: i8,
401        // could probably make a nicer api for tbyb, but documentation is eh so im holding off for now
402        /// Try Before You Buy info
403        pub tbyb_update_info: u8,
404        /// boot diagnostic flags for section A and section B
405        pub boot_diagnostic: u32,
406        /// Boot parameters 0 and 1
407        pub boot_params: [u32; 2],
408    }
409
410    /// Recen boot diagnostic partition
411    pub enum PartitionIndex {
412        /// A partition along with its number
413        Partition(u8),
414        /// None
415        None,
416        /// Slot0
417        Slot0,
418        /// Slot1
419        Slot1,
420        /// Image
421        Image,
422        /// Unknown
423        Unknown,
424    }
425
426    impl From<i8> for PartitionIndex {
427        fn from(value: i8) -> Self {
428            if !(-4..=15).contains(&value) {
429                return Self::Unknown;
430            }
431
432            match value {
433                -1 => Self::None,
434                -2 => Self::Slot0,
435                -3 => Self::Slot1,
436                -4 => Self::Image,
437                _ => Self::Partition(value as u8),
438            }
439        }
440    }
441
442    /// The type of boot that occurred
443    pub enum BootType {
444        /// Normal
445        Normal,
446        /// bootsel
447        BootSel,
448        /// Ram image
449        RamImage,
450        /// Flash update
451        FlashUpdate,
452        /// pc_sp
453        PcSp,
454        /// Unknown
455        Unknown,
456    }
457
458    impl From<u8> for BootType {
459        fn from(value: u8) -> Self {
460            match value {
461                0 => Self::Normal,
462                2 => Self::BootSel,
463                3 => Self::RamImage,
464                4 => Self::FlashUpdate,
465                8..=15 => Self::PcSp,
466                _ => Self::Unknown,
467            }
468        }
469    }
470
471    #[repr(u16)]
472    /// Diagnostic flags reported by the upper and lower words in [`BootInfo::boot_diagnostic`]
473    pub enum BootDiagnosticFlags {
474        /// The region was searched for a block loop
475        RegionSearched = 0x0001,
476        /// A block loop was found but it was invalid
477        InvalidBlockLoop = 0x0002,
478        /// A valid block loop was found (Blocks from a loop wholly contained within the region, and
479        /// the blocks have the correct structure. Each block consists of items whose sizes sum to
480        /// the size of the block)
481        ValidBlockLoop = 0x0004,
482        /// A valid IMAGE_DEF was found in the region. A valid IMAGE_DEF must parse correctly and must
483        /// be executable
484        ValidImageDef = 0x0008,
485        /// Whether a partition table is present. This partition table must have a correct structure
486        /// formed if [`BootDiagnosticFlags::ValidBlockLoop`] is set. If the partition table turns
487        /// out to be invalid, then [`BootDiagnosticFlags::InvalidBlockLoop`] is set too (thus both
488        /// [`BootDiagnosticFlags::ValidBlockLoop`] and [`BootDiagnosticFlags::InvalidBlockLoop`]
489        /// will both be set)
490        HasPartitionTable = 0x0010,
491        /// There was a choice of partition/slot and this one was considered. The first slot/partition
492        /// is chosen based on a number of factors. If the first choice fails verification, then the
493        /// other choice will be considered.
494        ///
495        /// * the version of the PARTITION_TABLE/IMAGE_DEF present in the slot/partition respectively.
496        /// * whether the slot/partition is the "update region" as per a FLASH_UPDATE reboot.
497        /// * whether an IMAGE_DEF is marked as "explicit buy"
498        Considered = 0x0020,
499        /// This slot/partition was chosen (or was the only choice)
500        Chosen = 0x0040,
501        /// if a signature is required for the PARTITION_TABLE (via OTP setting), then whether the
502        /// PARTITION_TABLE is signed with a key matching one of the four stored in OTP
503        PartitionTableMatchingKeyForVerify = 0x0080,
504        /// set if a hash value check could be performed. In the case a signature is required, this
505        /// value is identical to [`BootDiagnosticFlags::PartitionTableMatchingKeyForVerify`]
506        PartitionTableHashForVerify = 0x0100,
507        /// whether the PARTITION_TABLE passed verification (signature/hash if present/required)
508        PartitionTableVerifiedOk = 0x0200,
509        /// if a signature is required for the IMAGE_DEF due to secure boot, then whether the
510        /// IMAGE_DEF is signed with a key matching one of the four stored in OTP
511        ImageDefMatchingKeyForVerify = 0x0400,
512        /// set if a hash value check could be performed. In the case a signature is required, this
513        /// value is identical to [`BootDiagnosticFlags::ImageDefMatchingKeyForVerify`]
514        ImageDefHashForVerify = 0x0800,
515        /// whether the PARTITION_TABLE passed verification (signature/hash if present/required) and
516        /// any LOAD_MAP is valid
517        ImageDefVerifiedOk = 0x1000,
518        /// whether any code was copied into RAM due to a LOAD_MAP
519        LoadMapEntriesLoaded = 0x2000,
520        /// whether an IMAGE_DEF from this region was launched
521        ImageLaunched = 0x4000,
522        /// whether the IMAGE_DEF failed final checks before launching; these checks include
523        ///
524        /// * verification failed (if it hasn’t been verified earlier in the CONSIDERED phase).
525        /// * a problem occurred setting up any rolling window.
526        /// * the rollback version could not be set in OTP (if required in Secure mode)
527        /// * the image was marked as Non-secure
528        /// * the image was marked as "explicit buy", and this was a flash boot, but then region was
529        ///   not the "flash update" region
530        /// * the image has the wrong architecture, but architecture auto-switch is disabled (or the
531        ///   correct architecture is disabled)
532        ImageConditionFailure = 0x8000,
533    }
534
535    impl From<[u32; 4]> for BootInfo {
536        fn from(value: [u32; 4]) -> Self {
537            let word0 = value[0];
538
539            BootInfo {
540                diagnostic_partition: PartitionIndex::from((word0 & 0xFF) as i8),
541                boot_type: BootType::from((word0 >> 8) as u8),
542                chained: (word0 >> 8) & 0x80 > 0,
543                partition: (word0 >> 16) as _,
544                tbyb_update_info: (word0 >> 24) as _,
545                boot_diagnostic: value[1],
546                boot_params: [value[2], value[3]],
547            }
548        }
549    }
550
551    impl BootInfo {
552        fn check_flag(diagnostics: u16, flag: BootDiagnosticFlags) -> bool {
553            (diagnostics & flag as u16) != 0
554        }
555
556        /// Check if the diagnostic flag in section A (the lower word) is set
557        pub fn check_section_a_flag(&self, flag: BootDiagnosticFlags) -> bool {
558            Self::check_flag(self.boot_diagnostic as u16, flag)
559        }
560
561        /// Check if the diagnostic flag in section B (the upper word) is set
562        pub fn check_section_b_flag(&self, flag: BootDiagnosticFlags) -> bool {
563            Self::check_flag((self.boot_diagnostic >> 8) as u16, flag)
564        }
565    }
566
567    #[macro_export]
568    /// Generates a function with the following signature:
569    ///
570    /// ```rs
571    /// pub fn $function_name() -> Result<Option<$ok_ret_type>, BootRomApiErrorCode>
572    /// ```
573    ///
574    /// Which safely calls [`get_sys_info`](super::get_sys_info()) using the flag provided via
575    /// the `flag` argument. `flag` is an expression that must resolve to a const variant of
576    /// [`GetSysInfoFlag`]
577    macro_rules! declare_get_sys_info_function {
578        ($(#[$meta:meta])* $function_name:ident, $ok_ret_type:ty, $flag:expr) => {
579            $(#[$meta])*
580            pub fn $function_name() -> Result<Option<$ok_ret_type>, BootRomApiErrorCode> {
581                const FLAG: GetSysInfoFlag = $flag;
582                const BUFFER_LEN: usize = FLAG.buffer_length();
583                let mut buffer = [0u32; FLAG.buffer_length()];
584                let result =
585                    unsafe { super::get_sys_info(buffer.as_mut_ptr(), buffer.len(), FLAG as u32) };
586
587                if result < 0 {
588                    return Err(BootRomApiErrorCode::from(result));
589                } else if buffer[0] == 0 {
590                    // The operation returned successfully but the flag wasn't supported
591                    // for one reason or another
592                    return Ok(None);
593                }
594
595                Ok(Some(<$ok_ret_type>::from(
596                    TryInto::<[u32; BUFFER_LEN - 1]>::try_into(&buffer[1..]).unwrap(),
597                )))
598            }
599        };
600    }
601
602    #[macro_export]
603    #[cfg(all(target_arch = "arm", target_os = "none"))]
604    /// Generates a function with the following signature:
605    ///
606    /// ```rs
607    /// pub fn $function_name() -> Result<Option<$ok_ret_type>, BootRomApiErrorCode>
608    /// ```
609    ///
610    /// Which safely calls [`get_sys_info_ns`](super::get_sys_info_ns()) using the flag provided via
611    /// the `flag` argument. `flag` is an expression that must resolve to a const variant of
612    /// [`GetSysInfoFlag`]
613    macro_rules! declare_get_sys_info_ns_function {
614        ($(#[$meta:meta])* $function_name:ident, $ok_ret_type:ty, $flag:expr) => {
615            $(#[$meta])*
616            pub fn $function_name() -> Result<Option<$ok_ret_type>, BootRomApiErrorCode> {
617                const FLAG: GetSysInfoFlag = $flag;
618                const BUFFER_LEN: usize = FLAG.buffer_length();
619                let mut buffer = [0u32; FLAG.buffer_length()];
620                let result =
621                    unsafe { super::get_sys_info_ns(buffer.as_mut_ptr(), buffer.len(), FLAG as u32) };
622
623                if result < 0 {
624                    return Err(BootRomApiErrorCode::from(result));
625                } else if buffer[0] == 0 {
626                    // The operation returned successfully but the flag wasn't supported
627                    // for one reason or another
628                    return Ok(None);
629                }
630
631                Ok(Some(<$ok_ret_type>::from(
632                    TryInto::<[u32; BUFFER_LEN - 1]>::try_into(&buffer[1..]).unwrap(),
633                )))
634            }
635        };
636    }
637
638    declare_get_sys_info_function!(
639        /// Get the unique identifier for the chip
640        chip_info, ChipInfo, GetSysInfoFlag::ChipInfo
641    );
642
643    declare_get_sys_info_function!(
644        /// Get the value of the OTP critical register
645        otp_critical_register,
646        OtpCriticalReg,
647        GetSysInfoFlag::Critical
648    );
649
650    declare_get_sys_info_function!(
651        /// Get the current running CPU's info
652        cpu_info, CpuInfo, GetSysInfoFlag::CpuInfo
653    );
654
655    declare_get_sys_info_function!(
656        /// Get flash device info in the format of OTP FLASH_DEVINFO
657        flash_dev_info, FlashDevInfo, GetSysInfoFlag::FlashDevInfo
658    );
659
660    declare_get_sys_info_function!(
661        /// Get a 128-bit random number generated on each boot
662        boot_random, BootRandom, GetSysInfoFlag::BootRandom
663    );
664
665    declare_get_sys_info_function!(
666        /// Get diagnostic boot info
667        boot_info, BootInfo, GetSysInfoFlag::BootInfo
668    );
669
670    #[cfg(all(target_arch = "arm", target_os = "none"))]
671    declare_get_sys_info_ns_function!(
672        /// Get the unique identifier for the chip
673        chip_info_ns, ChipInfo, GetSysInfoFlag::ChipInfo
674    );
675
676    #[cfg(all(target_arch = "arm", target_os = "none"))]
677    declare_get_sys_info_ns_function!(
678        /// Get the value of the OTP critical register
679        otp_critical_register_ns,
680        OtpCriticalReg,
681        GetSysInfoFlag::Critical
682    );
683
684    #[cfg(all(target_arch = "arm", target_os = "none"))]
685    declare_get_sys_info_ns_function!(
686        /// Get the current running CPU's info
687        cpu_info_ns, CpuInfo, GetSysInfoFlag::CpuInfo
688    );
689
690    #[cfg(all(target_arch = "arm", target_os = "none"))]
691    declare_get_sys_info_ns_function!(
692        /// Get flash device info in the format of OTP FLASH_DEVINFO
693        flash_dev_info_ns, FlashDevInfo, GetSysInfoFlag::FlashDevInfo
694    );
695
696    #[cfg(all(target_arch = "arm", target_os = "none"))]
697    declare_get_sys_info_ns_function!(
698        /// Get a 128-bit random number generated on each boot
699        boot_random_ns, BootRandom, GetSysInfoFlag::BootRandom
700    );
701
702    #[cfg(all(target_arch = "arm", target_os = "none"))]
703    declare_get_sys_info_ns_function!(
704        /// Get diagnostic boot info
705        boot_info_ns, BootInfo, GetSysInfoFlag::BootInfo
706    );
707}
708
709macro_rules! declare_rom_function {
710    (
711        $(#[$outer:meta])*
712        fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty
713        $lookup:block
714    ) => {
715        #[doc = r"Additional access for the `"]
716        #[doc = stringify!($name)]
717        #[doc = r"` ROM function."]
718        pub mod $name {
719            /// Retrieve a function pointer.
720            #[cfg(not(feature = "rom-func-cache"))]
721            pub fn ptr() -> extern "C" fn( $($argname: $ty),* ) -> $ret {
722                let p: usize = $lookup;
723                unsafe {
724                    let func : extern "C" fn( $($argname: $ty),* ) -> $ret = core::mem::transmute(p);
725                    func
726                }
727            }
728
729            /// Retrieve a function pointer.
730            #[cfg(feature = "rom-func-cache")]
731            pub fn ptr() -> extern "C" fn( $($argname: $ty),* ) -> $ret {
732                use core::sync::atomic::{AtomicU16, Ordering};
733
734                // All pointers in the ROM fit in 16 bits, so we don't need a
735                // full width word to store the cached value.
736                static CACHED_PTR: AtomicU16 = AtomicU16::new(0);
737                // This is safe because the lookup will always resolve
738                // to the same value.  So even if an interrupt or another
739                // core starts at the same time, it just repeats some
740                // work and eventually writes back the correct value.
741                let p: usize = match CACHED_PTR.load(Ordering::Relaxed) {
742                    0 => {
743                        let raw: usize = $lookup;
744                        CACHED_PTR.store(raw as u16, Ordering::Relaxed);
745                        raw
746                    },
747                    val => val as usize,
748                };
749                unsafe {
750                    let func : extern "C" fn( $($argname: $ty),* ) -> $ret = core::mem::transmute(p);
751                    func
752                }
753            }
754        }
755
756        $(#[$outer])*
757        pub extern "C" fn $name( $($argname: $ty),* ) -> $ret {
758            $name::ptr()($($argname),*)
759        }
760    };
761
762    (
763        $(#[$outer:meta])*
764        unsafe fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty
765        $lookup:block
766    ) => {
767        #[doc = r"Additional access for the `"]
768        #[doc = stringify!($name)]
769        #[doc = r"` ROM function."]
770        pub mod $name {
771            /// Retrieve a function pointer.
772            #[cfg(not(feature = "rom-func-cache"))]
773            pub fn ptr() -> unsafe extern "C" fn( $($argname: $ty),* ) -> $ret {
774                let p: usize = $lookup;
775                unsafe {
776                    let func : unsafe extern "C" fn( $($argname: $ty),* ) -> $ret = core::mem::transmute(p);
777                    func
778                }
779            }
780
781            /// Retrieve a function pointer.
782            #[cfg(feature = "rom-func-cache")]
783            pub fn ptr() -> unsafe extern "C" fn( $($argname: $ty),* ) -> $ret {
784                use core::sync::atomic::{AtomicU16, Ordering};
785
786                // All pointers in the ROM fit in 16 bits, so we don't need a
787                // full width word to store the cached value.
788                static CACHED_PTR: AtomicU16 = AtomicU16::new(0);
789                // This is safe because the lookup will always resolve
790                // to the same value.  So even if an interrupt or another
791                // core starts at the same time, it just repeats some
792                // work and eventually writes back the correct value.
793                let p: usize = match CACHED_PTR.load(Ordering::Relaxed) {
794                    0 => {
795                        let raw: usize = $lookup;
796                        CACHED_PTR.store(raw as u16, Ordering::Relaxed);
797                        raw
798                    },
799                    val => val as usize,
800                };
801                unsafe {
802                    let func : unsafe extern "C" fn( $($argname: $ty),* ) -> $ret = core::mem::transmute(p);
803                    func
804                }
805            }
806        }
807
808        $(#[$outer])*
809        /// # Safety
810        ///
811        /// This is a low-level C function. It may be difficult to call safely from
812        /// Rust. If in doubt, check the rp235x datasheet for details and do your own
813        /// safety evaluation.
814        pub unsafe extern "C" fn $name( $($argname: $ty),* ) -> $ret {
815            $name::ptr()($($argname),*)
816        }
817    };
818}
819
820// **************** 5.5.7 Low-level Flash Commands ****************
821
822declare_rom_function! {
823    /// Restore all QSPI pad controls to their default state, and connect the
824    /// QMI peripheral to the QSPI pads.
825    ///
826    /// Supported architectures: ARM-S, RISC-V
827    unsafe fn connect_internal_flash() -> () {
828        crate::rom_data::rom_table_lookup(*b"IF", crate::rom_data::rt_flags::FUNC_ARM_SEC_RISCV)
829    }
830}
831
832declare_rom_function! {
833    /// Initialise the QMI for serial operations (direct mode)
834    ///
835    /// Also initialise a basic XIP mode, where the QMI will perform 03h serial
836    /// read commands at low speed (CLKDIV=12) in response to XIP reads.
837    ///
838    /// Then, issue a sequence to the QSPI device on chip select 0, designed to
839    /// return it from continuous read mode ("XIP mode") and/or QPI mode to a
840    /// state where it will accept serial commands. This is necessary after
841    /// system reset to restore the QSPI device to a known state, because
842    /// resetting RP2350 does not reset attached QSPI devices. It is also
843    /// necessary when user code, having already performed some
844    /// continuous-read-mode or QPI-mode accesses, wishes to return the QSPI
845    /// device to a state where it will accept the serial erase and programming
846    /// commands issued by the bootrom’s flash access functions.
847    ///
848    /// If a GPIO for the secondary chip select is configured via FLASH_DEVINFO,
849    /// then the XIP exit sequence is also issued to chip select 1.
850    ///
851    /// The QSPI device should be accessible for XIP reads after calling this
852    /// function; the name flash_exit_xip refers to returning the QSPI device
853    /// from its XIP state to a serial command state.
854    ///
855    /// Supported architectures: ARM-S, RISC-V
856    unsafe fn flash_exit_xip() -> () {
857        crate::rom_data::rom_table_lookup(*b"EX", crate::rom_data::rt_flags::FUNC_ARM_SEC_RISCV)
858    }
859}
860
861declare_rom_function! {
862    /// Erase count bytes, starting at addr (offset from start of flash).
863    ///
864    /// Optionally, pass a block erase command e.g. D8h block erase, and the
865    /// size of the block erased by this command — this function will use the
866    /// larger block erase where possible, for much higher erase speed. addr
867    /// must be aligned to a 4096-byte sector, and count must be a multiple of
868    /// 4096 bytes.
869    ///
870    /// This is a low-level flash API, and no validation of the arguments is
871    /// performed. See flash_op() for a higher-level API which checks alignment,
872    /// flash bounds and partition permissions, and can transparently apply a
873    /// runtime-to-storage address translation.
874    ///
875    /// The QSPI device must be in a serial command state before calling this
876    /// API, which can be achieved by calling connect_internal_flash() followed
877    /// by flash_exit_xip(). After the erase, the flash cache should be flushed
878    /// via flash_flush_cache() to ensure the modified flash data is visible to
879    /// cached XIP accesses.
880    ///
881    /// Finally, the original XIP mode should be restored by copying the saved
882    /// XIP setup function from bootram into SRAM, and executing it: the bootrom
883    /// provides a default function which restores the flash mode/clkdiv
884    /// discovered during flash scanning, and user programs can override this
885    /// with their own XIP setup function.
886    ///
887    /// For the duration of the erase operation, QMI is in direct mode (Section
888    /// 12.14.5) and attempting to access XIP from DMA, the debugger or the
889    /// other core will return a bus fault. XIP becomes accessible again once
890    /// the function returns.
891    ///
892    /// Supported architectures: ARM-S, RISC-V
893    unsafe fn flash_range_erase(addr: u32, count: usize, block_size: u32, block_cmd: u8) -> () {
894        crate::rom_data::rom_table_lookup(*b"RE", crate::rom_data::rt_flags::FUNC_ARM_SEC_RISCV)
895    }
896}
897
898declare_rom_function! {
899    /// Program data to a range of flash storage addresses starting at addr
900    /// (offset from the start of flash) and count bytes in size.
901    ///
902    /// `addr` must be aligned to a 256-byte boundary, and count must be a
903    /// multiple of 256.
904    ///
905    /// This is a low-level flash API, and no validation of the arguments is
906    /// performed. See flash_op() for a higher-level API which checks alignment,
907    /// flash bounds and partition permissions, and can transparently apply a
908    /// runtime-to-storage address translation.
909    ///
910    /// The QSPI device must be in a serial command state before calling this
911    /// API — see notes on flash_range_erase().
912    ///
913    /// Supported architectures: ARM-S, RISC-V
914    unsafe fn flash_range_program(addr: u32, data: *const u8, count: usize) -> () {
915        crate::rom_data::rom_table_lookup(*b"RP", crate::rom_data::rt_flags::FUNC_ARM_SEC_RISCV)
916    }
917}
918
919declare_rom_function! {
920    /// Flush the entire XIP cache, by issuing an invalidate by set/way
921    /// maintenance operation to every cache line (Section 4.4.1).
922    ///
923    /// This ensures that flash program/erase operations are visible to
924    /// subsequent cached XIP reads.
925    ///
926    /// Note that this unpins pinned cache lines, which may interfere with
927    /// cache-as-SRAM use of the XIP cache.
928    ///
929    /// No other operations are performed.
930    ///
931    /// Supported architectures: ARM-S, RISC-V
932    unsafe fn flash_flush_cache() -> () {
933        crate::rom_data::rom_table_lookup(*b"FC", crate::rom_data::rt_flags::FUNC_ARM_SEC_RISCV)
934    }
935}
936
937declare_rom_function! {
938    /// Configure the QMI to generate a standard 03h serial read command, with
939    /// 24 address bits, upon each XIP access.
940    ///
941    /// This is a slow XIP configuration, but is widely supported. CLKDIV is set
942    /// to 12. The debugger may call this function to ensure that flash is
943    /// readable following a program/erase operation.
944    ///
945    /// Note that the same setup is performed by flash_exit_xip(), and the
946    /// RP2350 flash program/erase functions do not leave XIP in an inaccessible
947    /// state, so calls to this function are largely redundant. It is provided
948    /// for compatibility with RP2040.
949    ///
950    /// Supported architectures: ARM-S, RISC-V
951    unsafe fn flash_enter_cmd_xip() -> () {
952        crate::rom_data::rom_table_lookup(*b"CX", crate::rom_data::rt_flags::FUNC_ARM_SEC_RISCV)
953    }
954}
955
956declare_rom_function! {
957    /// Configure QMI for one of a small menu of XIP read modes supported by the
958    /// bootrom.
959    ///
960    /// This mode is configured for both memory windows (both chip
961    /// selects), and the clock divisor is also applied to direct mode.
962    ///
963    /// The available modes are:
964    ///
965    /// * 0: `03h` serial read: serial address, serial data, no wait cycles
966    /// * 1: `0Bh` serial read: serial address, serial data, 8 wait cycles
967    /// * 2: `BBh` dual-IO read: dual address, dual data, 4 wait cycles
968    ///   (including MODE bits, which are driven to 0)
969    /// * 3: `EBh` quad-IO read: quad address, quad data, 6 wait cycles
970    ///   (including MODE bits, which are driven to 0)
971    ///
972    /// The XIP write command/format are not configured by this function. When
973    /// booting from flash, the bootrom tries each of these modes in turn, from
974    /// 3 down to 0. The first mode that is found to work is remembered, and a
975    /// default XIP setup function is written into bootram that calls this
976    /// function (flash_select_xip_read_mode) with the parameters discovered
977    /// during flash scanning. This can be called at any time to restore the
978    /// flash parameters discovered during flash boot.
979    ///
980    /// All XIP modes configured by the bootrom have an 8-bit serial command
981    /// prefix, so that the flash can remain in a serial command state, meaning
982    /// XIP accesses can be mixed more freely with program/erase serial
983    /// operations. This has a performance penalty, so users can perform their
984    /// own flash setup after flash boot using continuous read mode or QPI mode
985    /// to avoid or alleviate the command prefix cost.
986    ///
987    /// Supported architectures: ARM-S, RISC-V
988    unsafe fn flash_select_xip_read_mode(bootrom_xip_mode: u8, clkdiv: u8) -> () {
989        crate::rom_data::rom_table_lookup(*b"XM", crate::rom_data::rt_flags::FUNC_ARM_SEC_RISCV)
990    }
991}
992
993declare_rom_function! {
994    /// Restore the QMI address translation registers, ATRANS0 through ATRANS7,
995    /// to their reset state.
996    ///
997    /// This makes the runtime- to-storage address map an identity map, i.e. the
998    /// mapped and unmapped address are equal, and the entire space is fully mapped.
999    ///
1000    /// See [Section 12.14.4](https://rptl.io/rp2350-datasheet#section_bootrom) of the RP2350
1001    /// datasheet.
1002    ///
1003    /// Supported architectures: ARM-S, RISC-V
1004    unsafe fn flash_reset_address_trans() -> () {
1005        crate::rom_data::rom_table_lookup(*b"RA", crate::rom_data::rt_flags::FUNC_ARM_SEC_RISCV)
1006    }
1007}
1008
1009// **************** High-level Flash Commands ****************
1010
1011declare_rom_function! {
1012    /// Applies the address translation currently configured by QMI address
1013    /// translation registers, ATRANS0 through ATRANS7.
1014    ///
1015    /// See [Section 12.14.4](https://rptl.io/rp2350-datasheet#section_bootrom) of the RP2350
1016    /// datasheet.
1017    ///
1018    /// Translating an address outside of the XIP runtime address window, or
1019    /// beyond the bounds of an ATRANSx_SIZE field, returns
1020    /// BOOTROM_ERROR_INVALID_ADDRESS, which is not a valid flash storage
1021    /// address. Otherwise, return the storage address which QMI would access
1022    /// when presented with the runtime address addr. This is effectively a
1023    /// virtual-to-physical address translation for QMI.
1024    ///
1025    /// Supported architectures: ARM-S, RISC-V
1026    unsafe fn flash_runtime_to_storage_addr(addr: u32) -> i32 {
1027        crate::rom_data::rom_table_lookup(*b"FA", crate::rom_data::rt_flags::FUNC_ARM_SEC_RISCV)
1028    }
1029}
1030
1031declare_rom_function! {
1032    /// Non-secure version of [flash_runtime_to_storage_addr()]
1033    ///
1034    /// Supported architectures: ARM-NS
1035    #[cfg(all(target_arch = "arm", target_os = "none"))]
1036    unsafe fn flash_runtime_to_storage_addr_ns(addr: u32) -> i32 {
1037        crate::rom_data::rom_table_lookup(*b"FA", crate::rom_data::rt_flags::FUNC_ARM_NONSEC)
1038    }
1039}
1040
1041declare_rom_function! {
1042    /// Perform a flash read, erase, or program operation.
1043    ///
1044    /// Erase operations must be sector-aligned (4096 bytes) and sector-
1045    /// multiple-sized, and program operations must be page-aligned (256 bytes)
1046    /// and page-multiple-sized; misaligned erase and program operations will
1047    /// return BOOTROM_ERROR_BAD_ALIGNMENT. The operation — erase, read, program
1048    /// — is selected by the CFLASH_OP_BITS bitfield of the flags argument.
1049    ///
1050    /// See datasheet section 5.5.8.2 for more details.
1051    ///
1052    /// Supported architectures: ARM-S, RISC-V
1053    unsafe fn flash_op(flags: u32, addr: u32, size_bytes: u32, buffer: *mut u8) -> i32 {
1054        crate::rom_data::rom_table_lookup(*b"FO", crate::rom_data::rt_flags::FUNC_ARM_SEC_RISCV)
1055    }
1056}
1057
1058declare_rom_function! {
1059    /// Non-secure version of [flash_op()]
1060    ///
1061    /// Supported architectures: ARM-NS
1062    #[cfg(all(target_arch = "arm", target_os = "none"))]
1063    unsafe fn flash_op_ns(flags: u32, addr: u32, size_bytes: u32, buffer: *mut u8) -> i32 {
1064        crate::rom_data::rom_table_lookup(*b"FO", crate::rom_data::rt_flags::FUNC_ARM_NONSEC)
1065    }
1066}
1067
1068// **************** Security Related Functions ****************
1069
1070declare_rom_function! {
1071    /// Allow or disallow the specific NS API (note all NS APIs default to
1072    /// disabled).
1073    ///
1074    /// See datasheet section 5.5.9.1 for more details.
1075    ///
1076    /// Supported architectures: ARM-S
1077    #[cfg(all(target_arch = "arm", target_os = "none"))]
1078    unsafe fn set_ns_api_permission(ns_api_num: u32, allowed: u8) -> i32 {
1079        crate::rom_data::rom_table_lookup(*b"SP", crate::rom_data::rt_flags::FUNC_ARM_SEC)
1080    }
1081}
1082
1083declare_rom_function! {
1084    /// Utility method that can be used by secure ARM code to validate a buffer
1085    /// passed to it from Non-secure code.
1086    ///
1087    /// See datasheet section 5.5.9.2 for more details.
1088    ///
1089    /// Supported architectures: ARM-S, RISC-V
1090    unsafe fn validate_ns_buffer() -> () {
1091        crate::rom_data::rom_table_lookup(*b"VB", crate::rom_data::rt_flags::FUNC_ARM_SEC_RISCV)
1092    }
1093}
1094
1095// **************** Miscellaneous Functions ****************
1096
1097declare_rom_function! {
1098    /// Resets the RP2350 and uses the watchdog facility to restart.
1099    ///
1100    /// See datasheet section 5.5.10.1 for more details.
1101    ///
1102    /// Supported architectures: ARM-S, RISC-V
1103    fn reboot(flags: u32, delay_ms: u32, p0: u32, p1: u32) -> i32 {
1104        crate::rom_data::rom_table_lookup(*b"RB", crate::rom_data::rt_flags::FUNC_ARM_SEC_RISCV)
1105    }
1106}
1107
1108declare_rom_function! {
1109    /// Non-secure version of [reboot()]
1110    ///
1111    /// Supported architectures: ARM-NS
1112    #[cfg(all(target_arch = "arm", target_os = "none"))]
1113    fn reboot_ns(flags: u32, delay_ms: u32, p0: u32, p1: u32) -> i32 {
1114        crate::rom_data::rom_table_lookup(*b"RB", crate::rom_data::rt_flags::FUNC_ARM_NONSEC)
1115    }
1116}
1117
1118declare_rom_function! {
1119    /// Resets internal bootrom state.
1120    ///
1121    /// See datasheet section 5.5.10.2 for more details.
1122    ///
1123    /// Supported architectures: ARM-S, RISC-V
1124    unsafe fn bootrom_state_reset(flags: u32) -> () {
1125        crate::rom_data::rom_table_lookup(*b"SR", crate::rom_data::rt_flags::FUNC_ARM_SEC_RISCV)
1126    }
1127}
1128
1129declare_rom_function! {
1130    /// Set a boot ROM callback.
1131    ///
1132    /// The only supported callback_number is 0 which sets the callback used for
1133    /// the secure_call API.
1134    ///
1135    /// See datasheet section 5.5.10.3 for more details.
1136    ///
1137    /// Supported architectures: ARM-S, RISC-V
1138    unsafe fn set_rom_callback(callback_number: i32, callback_fn: *const ()) -> i32 {
1139        crate::rom_data::rom_table_lookup(*b"RC", crate::rom_data::rt_flags::FUNC_ARM_SEC_RISCV)
1140    }
1141}
1142
1143// **************** System Information Functions ****************
1144
1145declare_rom_function! {
1146    /// Fills a buffer with various system information.
1147    ///
1148    /// Note that this API is also used to return information over the PICOBOOT
1149    /// interface.
1150    ///
1151    /// See datasheet section 5.5.11.1 for more details.
1152    ///
1153    /// Supported architectures: ARM-S, RISC-V
1154    unsafe fn get_sys_info(out_buffer: *mut u32, out_buffer_word_size: usize, flags: u32) -> i32 {
1155        crate::rom_data::rom_table_lookup(*b"GS", crate::rom_data::rt_flags::FUNC_ARM_SEC_RISCV)
1156    }
1157}
1158
1159declare_rom_function! {
1160    /// Non-secure version of [get_sys_info()]
1161    ///
1162    /// Supported architectures: ARM-NS
1163    #[cfg(all(target_arch = "arm", target_os = "none"))]
1164    unsafe fn get_sys_info_ns(out_buffer: *mut u32, out_buffer_word_size: usize, flags: u32) -> i32 {
1165        crate::rom_data::rom_table_lookup(*b"GS", crate::rom_data::rt_flags::FUNC_ARM_NONSEC)
1166    }
1167}
1168
1169declare_rom_function! {
1170    /// Fills a buffer with information from the partition table.
1171    ///
1172    /// Note that this API is also used to return information over the PICOBOOT
1173    /// interface.
1174    ///
1175    /// See datasheet section 5.5.11.2 for more details.
1176    ///
1177    /// Supported architectures: ARM-S, RISC-V
1178    unsafe fn get_partition_table_info(out_buffer: *mut u32, out_buffer_word_size: usize, flags_and_partition: u32) -> i32 {
1179        crate::rom_data::rom_table_lookup(*b"GP", crate::rom_data::rt_flags::FUNC_ARM_SEC_RISCV)
1180    }
1181}
1182
1183declare_rom_function! {
1184    /// Non-secure version of [get_partition_table_info()]
1185    ///
1186    /// Supported architectures: ARM-NS
1187    #[cfg(all(target_arch = "arm", target_os = "none"))]
1188    unsafe fn get_partition_table_info_ns(out_buffer: *mut u32, out_buffer_word_size: usize, flags_and_partition: u32) -> i32 {
1189        crate::rom_data::rom_table_lookup(*b"GP", crate::rom_data::rt_flags::FUNC_ARM_NONSEC)
1190    }
1191}
1192
1193declare_rom_function! {
1194    /// Loads the current partition table from flash, if present.
1195    ///
1196    /// See datasheet section 5.5.11.3 for more details.
1197    ///
1198    /// Supported architectures: ARM-S, RISC-V
1199    unsafe fn load_partition_table(workarea_base: *mut u8, workarea_size: usize, force_reload: bool) -> i32 {
1200        crate::rom_data::rom_table_lookup(*b"LP", crate::rom_data::rt_flags::FUNC_ARM_SEC_RISCV)
1201    }
1202}
1203
1204declare_rom_function! {
1205    /// Writes data from a buffer into OTP, or reads data from OTP into a buffer.
1206    ///
1207    /// See datasheet section 5.5.11.4 for more details.
1208    ///
1209    /// Supported architectures: ARM-S, RISC-V
1210    unsafe fn otp_access(buf: *mut u8, buf_len: usize, row_and_flags: u32) -> i32 {
1211        crate::rom_data::rom_table_lookup(*b"OA", crate::rom_data::rt_flags::FUNC_ARM_SEC_RISCV)
1212    }
1213}
1214
1215declare_rom_function! {
1216    /// Non-secure version of [otp_access()]
1217    ///
1218    /// Supported architectures: ARM-NS
1219    #[cfg(all(target_arch = "arm", target_os = "none"))]
1220    unsafe fn otp_access_ns(buf: *mut u8, buf_len: usize, row_and_flags: u32) -> i32 {
1221        crate::rom_data::rom_table_lookup(*b"OA", crate::rom_data::rt_flags::FUNC_ARM_NONSEC)
1222    }
1223}
1224
1225// **************** Boot Related Functions ****************
1226
1227declare_rom_function! {
1228    /// Determines which of the partitions has the "better" IMAGE_DEF. In the
1229    /// case of executable images, this is the one that would be booted.
1230    ///
1231    /// See datasheet section 5.5.12.1 for more details.
1232    ///
1233    /// Supported architectures: ARM-S, RISC-V
1234    unsafe fn pick_ab_parition(workarea_base: *mut u8, workarea_size: usize, partition_a_num: u32) -> i32 {
1235        crate::rom_data::rom_table_lookup(*b"AB", crate::rom_data::rt_flags::FUNC_ARM_SEC_RISCV)
1236    }
1237}
1238
1239declare_rom_function! {
1240    /// Searches a memory region for a launchable image, and executes it if
1241    /// possible.
1242    ///
1243    /// See datasheet section 5.5.12.2 for more details.
1244    ///
1245    /// Supported architectures: ARM-S, RISC-V
1246    unsafe fn chain_image(workarea_base: *mut u8, workarea_size: usize, region_base: i32, region_size: u32) -> i32 {
1247        crate::rom_data::rom_table_lookup(*b"CI", crate::rom_data::rt_flags::FUNC_ARM_SEC_RISCV)
1248    }
1249}
1250
1251declare_rom_function! {
1252    /// Perform an "explicit" buy of an executable launched via an IMAGE_DEF
1253    /// which was "explicit buy" flagged.
1254    ///
1255    /// See datasheet section 5.5.12.3 for more details.
1256    ///
1257    /// Supported architectures: ARM-S, RISC-V
1258    unsafe fn explicit_buy(buffer: *mut u8, buffer_size: u32) -> i32 {
1259        crate::rom_data::rom_table_lookup(*b"EB", crate::rom_data::rt_flags::FUNC_ARM_SEC_RISCV)
1260    }
1261}
1262
1263declare_rom_function! {
1264    /// Not yet documented.
1265    ///
1266    /// See datasheet section 5.5.12.4 for more details.
1267    ///
1268    /// Supported architectures: ARM-S, RISC-V
1269    unsafe fn get_uf2_target_partition(workarea_base: *mut u8, workarea_size: usize, family_id: u32, partition_out: *mut u32) -> i32 {
1270        crate::rom_data::rom_table_lookup(*b"GU", crate::rom_data::rt_flags::FUNC_ARM_SEC_RISCV)
1271    }
1272}
1273
1274declare_rom_function! {
1275    /// Returns: The index of the B partition of partition A if a partition
1276    /// table is present and loaded, and there is a partition A with a B
1277    /// partition; otherwise returns BOOTROM_ERROR_NOT_FOUND.
1278    ///
1279    /// See datasheet section 5.5.12.5 for more details.
1280    ///
1281    /// Supported architectures: ARM-S, RISC-V
1282    unsafe fn get_b_partition(partition_a: u32) -> i32 {
1283        crate::rom_data::rom_table_lookup(*b"GB", crate::rom_data::rt_flags::FUNC_ARM_SEC_RISCV)
1284    }
1285}
1286
1287// **************** Non-secure-specific Functions ****************
1288
1289// NB: The "secure_call" function should be here, but it doesn't have a fixed
1290// function signature as it is designed to let you bounce into any secure
1291// function from non-secure mode.
1292
1293// **************** RISC-V Functions ****************
1294
1295declare_rom_function! {
1296    /// Set stack for RISC-V bootrom functions to use.
1297    ///
1298    /// See datasheet section 5.5.14.1 for more details.
1299    ///
1300    /// Supported architectures: RISC-V
1301    #[cfg(not(all(target_arch = "arm", target_os = "none")))]
1302    unsafe fn set_bootrom_stack(base_size: *mut u32) -> i32 {
1303        crate::rom_data::rom_table_lookup(*b"SS", crate::rom_data::rt_flags::FUNC_RISCV)
1304    }
1305}
1306
1307/// The version number of the rom.
1308pub fn rom_version_number() -> u8 {
1309    unsafe { *VERSION_NUMBER }
1310}
1311
1312/// The 8 most significant hex digits of the Bootrom git revision.
1313pub fn git_revision() -> u32 {
1314    let ptr = rom_data_lookup(*b"GR", rt_flags::DATA) as *const u32;
1315    unsafe { ptr.read() }
1316}
1317
1318/// A pointer to the resident partition table info.
1319///
1320/// The resident partition table is the subset of the full partition table that
1321/// is kept in memory, and used for flash permissions.
1322pub fn partition_table_pointer() -> *const u32 {
1323    let ptr = rom_data_lookup(*b"PT", rt_flags::DATA) as *const *const u32;
1324    unsafe { ptr.read() }
1325}
1326
1327/// Determine if we are in secure mode
1328///
1329/// Returns `true` if we are in secure mode and `false` if we are in non-secure
1330/// mode.
1331#[cfg(all(target_arch = "arm", target_os = "none"))]
1332pub fn is_secure_mode() -> bool {
1333    // Look at the start of ROM, which is always readable
1334    #[allow(clippy::zero_ptr)]
1335    let rom_base: *mut u32 = 0x0000_0000 as *mut u32;
1336    // Use the 'tt' instruction to check the permissions for that address
1337    let tt = cortex_m::asm::tt(rom_base);
1338    // Is the secure bit set? => secure mode
1339    (tt & (1 << 22)) != 0
1340}
1341
1342/// Determine if we are in secure mode
1343///
1344/// Always returns `false` on RISC-V as it is impossible to determine if
1345/// you are in Machine Mode or User Mode by design.
1346#[cfg(not(all(target_arch = "arm", target_os = "none")))]
1347pub fn is_secure_mode() -> bool {
1348    false
1349}