From a0dd354bdc299d7d089bd4ed143f6a213852a905 Mon Sep 17 00:00:00 2001 From: Ian McIntyre Date: Thu, 3 Apr 2025 16:44:15 -0400 Subject: [PATCH] Add section for boot ROM reservations The boot ROM is allowed to use allocations of OCRAM as scratch space. If you interact with the boot ROM -- using it to interact with FlexSPI, for instance -- then you cannot also use these OCRAM regions. See the system boot chapter in the reference manual for more info. The boot ROM typically reserves the start of OCRAM. The size varies by chip. This commit describes a new section, .bootrom_reservation, at the start of OCRAM. Users are encouraged to place a MaybeUninit buffer that's sized for your ROM's requirements. If users don't place anything in this section, then the new directive is a no-op. On the other hand, the section is defined before other RAM regions, so that it takes precedence over other sections users might want to place in OCRAM. Tested using the runtime's test suite. I'm testing with the Teensy 4 binary, since the test suite can support features in this build. The updated test suite shows that the linker will place the boot ROM reservation before placing the stack, suggesting that we're respecting section priority. --- CHANGELOG.md | 4 +++ board/Cargo.toml | 1 + board/build.rs | 1 + board/src/teensy4.rs | 8 ++++++ src/host/imxrt-link.x | 5 ++++ src/lib.rs | 22 +++++++++++++++++ tests/inspect_elf.rs | 57 +++++++++++++++++++++++++++++++++++-------- 7 files changed, 88 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8187edb..afae79a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,10 @@ Relax cortex-m-rt version specification, providing support for cortex-m-rt after 0.7.3. However, it's not guaranteed that this package supports all feature flags available in newer versions of cortex-m-rt. +Add a `.bootrom_reservation` section in OCRAM. If you need to reserve this +OCRAM allocation, you may allocate your own `MaybeUninit` buffer sized for +your boot ROM's requirements. + ### FlexRAM bank layouts The runtime builder lets users specify the _layout_, or assignment, of FlexRAM diff --git a/board/Cargo.toml b/board/Cargo.toml index f9ef9aa..2bbc956 100644 --- a/board/Cargo.toml +++ b/board/Cargo.toml @@ -61,3 +61,4 @@ imxrt1170evk-cm7 = [ # Don't try running these on hardware; they might not work. __dcd = ["teensy4"] __dcd_missize = ["teensy4"] +__bootrom_reservation = ["teensy4"] diff --git a/board/build.rs b/board/build.rs index d86d287..af17a95 100644 --- a/board/build.rs +++ b/board/build.rs @@ -40,6 +40,7 @@ fn main() { .data(imxrt_rt::Memory::Dtcm) .bss(imxrt_rt::Memory::Dtcm) .uninit(imxrt_rt::Memory::Dtcm) + .stack(imxrt_rt::Memory::Ocram) .stack_size_env_override("THIS_WONT_BE_CONSIDERED") .stack_size_env_override("BOARD_STACK") .heap_size_env_override("BOARD_HEAP") diff --git a/board/src/teensy4.rs b/board/src/teensy4.rs index cf1f734..426fbfa 100644 --- a/board/src/teensy4.rs +++ b/board/src/teensy4.rs @@ -50,3 +50,11 @@ pub static DEVICE_CONFIGURATION_DATA: [u8; 8] = [0xD2, 0x00, 0x08, 0x41, 0xC0, 0 #[unsafe(no_mangle)] #[used] pub static DEVICE_CONFIGURATION_DATA: [u8; 7] = [0xD2, 0x00, 0x08, 0x41, 0xC0, 0x00, 0x04]; + +/// Make sure this reservation appears at the start of OCRAM. +#[cfg(feature = "__bootrom_reservation")] +#[unsafe(link_section = ".bootrom_reservation")] +#[unsafe(no_mangle)] +#[used] +pub static BOOTROM_RESERVATION: core::mem::MaybeUninit<[u8; 48 * 1024]> = + core::mem::MaybeUninit::new([0; 48 * 1024]); diff --git a/src/host/imxrt-link.x b/src/host/imxrt-link.x index 7fcd76c..f07601b 100644 --- a/src/host/imxrt-link.x +++ b/src/host/imxrt-link.x @@ -37,6 +37,11 @@ EXTERN(__INTERRUPTS); /* `static` variable similar to `__EXCEPTIONS` */ /* # Sections */ SECTIONS { + .bootrom ORIGIN(OCRAM) (NOLOAD) : + { + KEEP(*(.bootrom_reservation)); + } > OCRAM + .stack (NOLOAD) : ALIGN(8) { __estack = .; diff --git a/src/lib.rs b/src/lib.rs index ab55627..40d2789 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -176,6 +176,28 @@ //! //! With this in place, your package should be able to use the `#[exception]` macro //! exported by `imxrt-rt`. See the `imxrt-rt` package examples for a demonstration. +//! +//! # Extras +//! +//! The runtime package has extra features to support i.MX RT programs. +//! +//! ## Reserving OCRAM for NXP's boot ROM +//! +//! If you're using NXP's boot ROM, you may need to reserve a region at the start of +//! OCRAM for API calls. You can achieve that by placing a buffer into `.bootrom_reservation`. +//! You're responsible for sizing this buffer depending chip's ROM. +//! +//! Here's an example of how to reserve the first 48KiB of OCRAM for the boot ROM. +//! The example assumes the boot ROM requires at most 48KiB. +//! +//! ``` +//! # use core::mem::MaybeUninit; +//! #[unsafe(link_section = ".bootrom_reservation")] +//! static ROM_RESERVATION: MaybeUninit<[u8; 48 * 1024]> = MaybeUninit::uninit(); +//! ``` +//! +//! Without this reservation, this program is allowed to use the lower addresses of +//! OCRAM without concern for the boot ROM. #![cfg_attr(all(target_arch = "arm", target_os = "none"), no_std)] diff --git a/tests/inspect_elf.rs b/tests/inspect_elf.rs index 928ddb3..654c632 100644 --- a/tests/inspect_elf.rs +++ b/tests/inspect_elf.rs @@ -217,12 +217,22 @@ struct Fcb { size: u64, } -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Clone, Copy, PartialEq, Eq)] struct Section { address: u64, size: u64, } +impl std::fmt::Debug for Section { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Section") + .field("address", &format!("{:#010X}", self.address)) + .field("size", &self.size) + .finish()?; + Ok(()) + } +} + // No top-level constant for OCRAM, since placement varies // across 1000 and 1100 MCUs. const DTCM: u64 = 0x2000_0000; @@ -467,7 +477,13 @@ fn imxrt1010evk_ram() { assert!(binary.symbol("Reset").is_some()); } -fn baseline_teensy4(binary: &ImxrtBinary, dcd_at_runtime: u32, stack_size: u64, heap_size: u64) { +fn baseline_teensy4( + binary: &ImxrtBinary, + dcd_at_runtime: u32, + stack_start: u64, + stack_size: u64, + heap_size: u64, +) { assert_eq!( Fcb { address: 0x6000_0000, @@ -492,11 +508,11 @@ fn baseline_teensy4(binary: &ImxrtBinary, dcd_at_runtime: u32, stack_size: u64, let stack = binary.section(".stack").unwrap(); assert_eq!( Section { - address: DTCM, + address: stack_start, size: stack_size }, stack, - "stack not at ORIGIN(DTCM), or not {stack_size} bytes large" + "stack not at {stack_start:#010X}, or not {stack_size} bytes large" ); assert_eq!(binary.section_lma(".stack"), stack.address); @@ -504,11 +520,11 @@ fn baseline_teensy4(binary: &ImxrtBinary, dcd_at_runtime: u32, stack_size: u64, let xip = binary.section(".xip").unwrap(); assert_eq!( Section { - address: stack.address + stack.size, + address: DTCM, size: 16 * 4 + IMXRT1060_INTERRUPTS * 4 }, vector_table, - "vector table not at expected VMA behind the stack" + "vector table not at expected VMA in DTCM" ); assert!( vector_table.address.is_multiple_of(1024), @@ -605,7 +621,28 @@ fn teensy4() { binary.symbol_value("__dcd_end") ); assert_eq!(binary.symbol_value("__dcd"), Some(0)); - baseline_teensy4(&binary, 0, 8 * 1024, 1024); + baseline_teensy4(&binary, 0, 0x2020_0000, 8 * 1024, 1024); +} + +#[test] +#[ignore = "building an example can take time"] +fn teensy4_bootrom_reservation() { + let path = cargo_build("__bootrom_reservation").expect("Unable to build example"); + let contents = fs::read(path).expect("Could not read ELF file"); + let elf = Elf::parse(&contents).expect("Could not parse ELF"); + + let binary = ImxrtBinary::new(&elf, &contents); + let bootrom_reservation = binary.symbol("BOOTROM_RESERVATION").unwrap(); + assert_eq!(bootrom_reservation.st_value, 0x2020_0000); + assert_eq!(bootrom_reservation.st_size, 48 * 1024); + + baseline_teensy4( + &binary, + 0, + bootrom_reservation.st_value + bootrom_reservation.st_size, + 8 * 1024, + 1024, + ); } #[test] @@ -627,7 +664,7 @@ fn teensy4_fake_dcd() { binary.symbol_value("__dcd_start"), ); assert_eq!(dcd.st_size % 4, 0); - baseline_teensy4(&binary, dcd_start as u32, 8 * 1024, 1024); + baseline_teensy4(&binary, dcd_start as u32, 0x2020_0000, 8 * 1024, 1024); } #[test] @@ -654,7 +691,7 @@ fn teensy4_env_overrides() { let elf = Elf::parse(&contents).expect("Could not parse ELF"); let binary = ImxrtBinary::new(&elf, &contents); - baseline_teensy4(&binary, 0, 4 * 1024, 8 * 1024); + baseline_teensy4(&binary, 0, 0x2020_0000, 4 * 1024, 8 * 1024); } #[test] @@ -666,7 +703,7 @@ fn teensy4_env_overrides_kib() { let elf = Elf::parse(&contents).expect("Could not parse ELF"); let binary = ImxrtBinary::new(&elf, &contents); - baseline_teensy4(&binary, 0, 5 * 1024, 9 * 1024); + baseline_teensy4(&binary, 0, 0x2020_0000, 5 * 1024, 9 * 1024); } #[test]