aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNils Fitinghoff <nils.fitinghoff@kiteshield.com>2024-10-16 13:04:23 +0200
committerNils Fitinghoff <nils.fitinghoff@kiteshield.com>2024-10-17 17:40:20 +0200
commit9138706b8a5e4469f33a7a826c08e6446b642a3c (patch)
tree1a530c8d1f96cf2193666f9ae595f8f399366899 /src
parentcb3af5ba736443adbf3dbf305f7a95aa23f3d26b (diff)
Support RT1180 family
The 1180 family uses a different boot header than previous families. The header is generated to support the default configuration where hash and signature errors are ignored. The XIP `__pre_init` strategy is still used, more for ease of getting something running than because of any known problems with the boot ROM's implementation of loading images to different memories. The boot ROM for the 1180 does not appear to allow the entry point to lie outside the (loaded or execute-in-place) image, so a new `.xip` section is added after the vector table to put the address inside the image while keeping VMA=LMA. This could cause problems for tools that manipulate binaries based on section names.
Diffstat (limited to 'src')
-rw-r--r--src/host.rs88
-rw-r--r--src/host/imxrt-boot-header-1180.x104
-rw-r--r--src/host/imxrt-boot-header.x2
-rw-r--r--src/host/imxrt-link.x15
-rw-r--r--src/target.rs10
5 files changed, 205 insertions, 14 deletions
diff --git a/src/host.rs b/src/host.rs
index dbe023f..de6afa3 100644
--- a/src/host.rs
+++ b/src/host.rs
@@ -66,7 +66,8 @@ impl FlexSpi {
| Family::Imxrt1020
| Family::Imxrt1050
| Family::Imxrt1060
- | Family::Imxrt1170 => FlexSpi::FlexSpi1,
+ | Family::Imxrt1170
+ | Family::Imxrt1180 => FlexSpi::FlexSpi1,
}
}
fn start_address(self, family: Family) -> Option<u32> {
@@ -91,6 +92,8 @@ impl FlexSpi {
// 11xx support
(FlexSpi::FlexSpi1, Family::Imxrt1170) => Some(0x3000_0000),
(FlexSpi::FlexSpi2, Family::Imxrt1170) => Some(0x6000_0000),
+ (FlexSpi::FlexSpi1, Family::Imxrt1180) => Some(0x2800_0000),
+ (FlexSpi::FlexSpi2, Family::Imxrt1180) => Some(0x0400_0000),
}
}
fn supported_for_family(self, family: Family) -> bool {
@@ -498,7 +501,16 @@ impl RuntimeBuilder {
if let Some(flash_opts) = &self.flash_opts {
write_flash_memory_map(writer, self.family, flash_opts, &self.flexram_banks)?;
- let boot_header_x = include_bytes!("host/imxrt-boot-header.x");
+ let boot_header_x = match self.family {
+ Family::Imxrt1010
+ | Family::Imxrt1015
+ | Family::Imxrt1020
+ | Family::Imxrt1050
+ | Family::Imxrt1060
+ | Family::Imxrt1064
+ | Family::Imxrt1170 => include_bytes!("host/imxrt-boot-header.x").as_slice(),
+ Family::Imxrt1180 => include_bytes!("host/imxrt-boot-header-1180.x").as_slice(),
+ };
writer.write_all(boot_header_x)?;
} else {
write_ram_memory_map(writer, self.family, &self.flexram_banks)?;
@@ -543,7 +555,7 @@ impl RuntimeBuilder {
writeln!(
writer,
"__flexram_config = {:#010X};",
- self.flexram_banks.config()
+ self.flexram_banks.config(self.family)
)?;
// The target runtime looks at this value to predicate some pre-init instructions.
// Could be helpful for binary identification, but it's an undocumented feature.
@@ -619,10 +631,20 @@ fn write_flexram_memories(
flexram_banks: &FlexRamBanks,
) -> io::Result<()> {
if flexram_banks.itcm > 0 {
+ let itcm_size = flexram_banks.itcm * family.flexram_bank_size();
+ let itcm_start = match family {
+ Family::Imxrt1010
+ | Family::Imxrt1015
+ | Family::Imxrt1020
+ | Family::Imxrt1050
+ | Family::Imxrt1060
+ | Family::Imxrt1064
+ | Family::Imxrt1170 => 0x00000000,
+ Family::Imxrt1180 => 0x10000000 - itcm_size,
+ };
writeln!(
output,
- "ITCM (RWX) : ORIGIN = 0x00000000, LENGTH = {:#X}",
- flexram_banks.itcm * family.flexram_bank_size(),
+ "ITCM (RWX) : ORIGIN = {itcm_start:#X}, LENGTH = {itcm_size:#X}"
)?;
}
if flexram_banks.dtcm > 0 {
@@ -708,6 +730,7 @@ pub enum Family {
Imxrt1060,
Imxrt1064,
Imxrt1170,
+ Imxrt1180,
}
impl Family {
@@ -725,6 +748,7 @@ impl Family {
Family::Imxrt1060 => 1060,
Family::Imxrt1064 => 1064,
Family::Imxrt1170 => 1170,
+ Family::Imxrt1180 => 1180,
}
}
/// How many FlexRAM banks are available?
@@ -735,11 +759,21 @@ impl Family {
Family::Imxrt1050 | Family::Imxrt1060 | Family::Imxrt1064 => 16,
// No ECC support; treating all banks as equal.
Family::Imxrt1170 => 16,
+ Family::Imxrt1180 => 2,
}
}
/// How large (bytes) is each FlexRAM bank?
const fn flexram_bank_size(self) -> u32 {
- 32 * 1024
+ match self {
+ Family::Imxrt1010
+ | Family::Imxrt1015
+ | Family::Imxrt1020
+ | Family::Imxrt1050
+ | Family::Imxrt1060
+ | Family::Imxrt1064
+ | Family::Imxrt1170 => 32 * 1024,
+ Family::Imxrt1180 => 128 * 1024,
+ }
}
/// How many OCRAM banks does the boot ROM need?
const fn bootrom_ocram_banks(self) -> u32 {
@@ -748,13 +782,13 @@ impl Family {
// 9.5.1. memory maps point at OCRAM2.
Family::Imxrt1060 | Family::Imxrt1064 => 0,
// Boot ROM uses dedicated OCRAM1.
- Family::Imxrt1170 => 0,
+ Family::Imxrt1170 | Family::Imxrt1180 => 0,
}
}
/// Where's the FlexSPI configuration bank located?
fn fcb_offset(self) -> usize {
match self {
- Family::Imxrt1010 | Family::Imxrt1170 => 0x400,
+ Family::Imxrt1010 | Family::Imxrt1170 | Family::Imxrt1180 => 0x400,
Family::Imxrt1015
| Family::Imxrt1020
| Family::Imxrt1050
@@ -770,6 +804,8 @@ impl Family {
match self {
// 256 KiB offset from the OCRAM M4 backdoor.
Family::Imxrt1170 => 0x2024_0000,
+ // Skip the first 16 KiB, "cannot be safely used by application images".
+ Family::Imxrt1180 => 0x2048_4000,
// Either starts the FlexRAM OCRAM banks, or the
// dedicated OCRAM regions (for supported devices).
Family::Imxrt1010
@@ -792,6 +828,8 @@ impl Family {
// - Two dedicated OCRAM ECC regions that aren't used for ECC
// - One FlexRAM OCRAM ECC region that's strictly OCRAM, without ECC
Family::Imxrt1170 => (2 * 512 + 2 * 64 + 128) * 1024,
+ // OCRAM1 (512k), OCRAM2 (256k), 16k reserved as a ROM patch area
+ Family::Imxrt1180 => (512 + 256 - 16) * 1024,
}
}
@@ -820,6 +858,11 @@ impl Family {
itcm: 8,
dtcm: 8,
},
+ Family::Imxrt1180 => FlexRamBanks {
+ ocram: 0,
+ itcm: 1,
+ dtcm: 1,
+ },
}
}
}
@@ -861,7 +904,21 @@ impl FlexRamBanks {
}
/// Produces the FlexRAM configuration.
- fn config(&self) -> u32 {
+ fn config(&self, family: Family) -> u32 {
+ match family {
+ Family::Imxrt1010
+ | Family::Imxrt1015
+ | Family::Imxrt1020
+ | Family::Imxrt1050
+ | Family::Imxrt1060
+ | Family::Imxrt1064
+ | Family::Imxrt1170 => self.config_gpr(),
+ Family::Imxrt1180 => self.config_1180(),
+ }
+ }
+
+ /// Produces the FlexRAM configuration for families using GPR17.
+ fn config_gpr(&self) -> u32 {
assert!(
self.bank_count() <= 16,
"Something is wrong; this should have been checked earlier."
@@ -888,6 +945,17 @@ impl FlexRamBanks {
(OCRAM & ocram_mask) | (DTCM & dtcm_mask) | (ITCM & itcm_mask)
}
+
+ fn config_1180(&self) -> u32 {
+ match (self.itcm, self.dtcm, self.ocram) {
+ (1, 1, 0) => 0b00_u32,
+ (2, 0, 0) => 0b10,
+ (0, 2, 0) => 0b01,
+ _ => panic!("Unsupported FlexRAM configuration"),
+ }
+ .checked_shl(2)
+ .unwrap()
+ }
}
#[cfg(test)]
@@ -996,7 +1064,7 @@ mod tests {
];
for (banks, expected) in TABLE {
- let actual = banks.config();
+ let actual = banks.config(Family::Imxrt1010);
assert!(
actual == *expected,
"\nActual: {actual:#034b}\nExpected: {expected:#034b}\nBanks: {banks:?}"
diff --git a/src/host/imxrt-boot-header-1180.x b/src/host/imxrt-boot-header-1180.x
new file mode 100644
index 0000000..101725a
--- /dev/null
+++ b/src/host/imxrt-boot-header-1180.x
@@ -0,0 +1,104 @@
+/* ===--- Begin imxrt-boot-header-1180.x ---===
+ * This extra content is injected into the linker script depending on the
+ * runtime configuration.
+ */
+
+__image_size = SIZEOF(.vector_table) + SIZEOF(.text) + SIZEOF(.xip) + SIZEOF(.rodata) + SIZEOF(.data);
+
+EXTERN(FLEXSPI_CONFIGURATION_BLOCK);
+
+/* # Sections */
+SECTIONS
+{
+ /* Boot header for serial NOR FlexSPI XIP.
+ *
+ * It's 'XIP' in that it starts executing instructions
+ * from flash immediately out of reset. The runtime then
+ * manually copies instructions (data, etc.), and we jump
+ * to that. After that jump, we're no longer XIP.
+ *
+ * The i.MX RT boot ROM also supports a way to copy the
+ * application image by changing the boot data configuration.
+ * Specifically, point the 'Image offset' to somewhere other
+ * than the start of flash, and specify how many bytes to copy.
+ * The boot ROM copies the image, then jumps to the entry point.
+ * It is currently not tested or used, mainly for consistency
+ * with the other iMXRT families.
+ */
+ .boot1 ORIGIN(FLASH):
+ {
+ FILL(0x00);
+ /* ------------------
+ * Memory configuration block
+ * ------------------
+ *
+ * The size and layout is different for different boot devices. Currently,
+ * only NOR flash is supported.
+ */
+ . += __fcb_offset; /* Can change based on boot source */
+ KEEP(*(.fcb));
+ . = ORIGIN(FLASH) + 0x1000;
+
+ /* ------------------
+ * Container 1
+ * ------------------
+ */
+ __container1_start = .;
+ LONG(0x87000000 | (__container1_len << 8)); /* Tag, length, version */
+ LONG(0); /* Flags */
+ LONG(0x01000000); /* 1 image, fuse version 0, SW version 0 */
+ LONG(__signature_block_start - __container1_start); /* Signature block offset */
+
+ /* Image array, image 0 */
+ LONG(0xa000); /* Image offset */
+ LONG(__image_size); /* Image size */
+ QUAD(LOADADDR(.vector_table)); /* Load address (execute in place) */
+ QUAD(Reset); /* Entry point */
+ LONG(0x213); /* Flags: Unencrypted, SHA512 hashed, executable image for Cortex-M33 */
+ LONG(0); /* Reserved (image meta data) */
+ } > FLASH
+
+ /* Put the hash in a separate section for easier replacement in a post-build step */
+ .image_hash :
+ {
+ QUAD(0); /* Hash 512 bytes */
+ QUAD(0);
+ QUAD(0);
+ QUAD(0);
+ QUAD(0);
+ QUAD(0);
+ QUAD(0);
+ QUAD(0);
+ } > FLASH
+
+ .boot2 :
+ {
+ FILL(0x00);
+ QUAD(0); /* IV 256 bytes, zero for unencrypted image */
+ QUAD(0);
+ QUAD(0);
+ QUAD(0);
+
+ /* ------------------
+ * Signature block
+ * ------------------
+ */
+ __signature_block_start = .;
+ LONG(0x90000000 | (__signature_block_len << 8)); /* Tag, length, version */
+ LONG(0); /* SRK Table offset, Certificate Offset */
+ LONG(0); /* Signature offset, Blob offset */
+ LONG(0); /* Reserved */
+ __signature_block_end = .;
+ __signature_block_len = __signature_block_end - __signature_block_start;
+ __container1_end = .;
+ __container1_len = __container1_end - __container1_start;
+
+ /* DCD is replaced by XMCD. Satisfy assertions intended for other families. */
+ __dcd_start = .;
+ __dcd_end = .;
+
+ . = ORIGIN(FLASH) + 0x2000; /* Pad to 8k alignment for the container/images boundary */
+ } > FLASH
+}
+
+/* ===--- End imxrt-boot-header-1180.x ---=== */
diff --git a/src/host/imxrt-boot-header.x b/src/host/imxrt-boot-header.x
index 615fc65..3f33603 100644
--- a/src/host/imxrt-boot-header.x
+++ b/src/host/imxrt-boot-header.x
@@ -8,7 +8,7 @@
* Note that it depends on the section layout! Need to represent contiguous
* sections starting from the boot header.
*/
-__image_size = SIZEOF(.boot) + SIZEOF(.vector_table) + SIZEOF(.text) + SIZEOF(.rodata);
+__image_size = SIZEOF(.boot) + SIZEOF(.vector_table) + SIZEOF(.xip) + SIZEOF(.text) + SIZEOF(.rodata);
/* END TODO */
EXTERN(FLEXSPI_CONFIGURATION_BLOCK);
diff --git a/src/host/imxrt-link.x b/src/host/imxrt-link.x
index 6c28f99..a389325 100644
--- a/src/host/imxrt-link.x
+++ b/src/host/imxrt-link.x
@@ -48,6 +48,7 @@ SECTIONS
.vector_table : ALIGN(1024)
{
+ FILL(0xff);
__vector_table = .;
__svector_table = .;
@@ -68,13 +69,19 @@ SECTIONS
} > REGION_VTABLE AT> REGION_LOAD_VTABLE
__sivector_table = LOADADDR(.vector_table);
+ /* This section guarantees VMA = LMA to allow the execute-in-place entry point to be inside the image. */
+ .xip :
+ {
+ /* Included here if not otherwise included in the boot header. */
+ *(.Reset);
+ *(.__pre_init);
+ } > REGION_LOAD_TEXT
+
.text :
{
+ FILL(0xff);
__stext = .;
*(.text .text.*);
- /* Included in .text if not otherwise included in the boot header. */
- *(.Reset);
- *(.__pre_init);
/* The HardFaultTrampoline uses the `b` instruction to enter `HardFault`,
so must be placed close to it. */
*(.HardFaultTrampoline);
@@ -86,6 +93,7 @@ SECTIONS
.rodata : ALIGN(4)
{
+ FILL(0xff);
. = ALIGN(4);
__srodata = .;
*(.rodata .rodata.*);
@@ -100,6 +108,7 @@ SECTIONS
.data : ALIGN(4)
{
+ FILL(0xff);
. = ALIGN(4);
__sdata = .;
*(.data .data.*);
diff --git a/src/target.rs b/src/target.rs
index 3a61584..765862d 100644
--- a/src/target.rs
+++ b/src/target.rs
@@ -41,6 +41,9 @@ global_asm! {r#"
__pre_init:
ldr r0, =__imxrt_family @ Need to know which chip family we're initializing.
+ ldr r1, =1180
+ cmp r0, r1 @ Is this an 1180?
+ beq flexram_1180
ldr r1, =1170
cmp r0, r1 @ Is this an 1170?
@@ -66,7 +69,14 @@ __pre_init:
ldr r1, [r0, #64] @ r1 = *(IMXRT_IOMUXC_GPR + 16)
orr r1, r1, #1<<2 @ r1 |= 1 << 2
str r1, [r0, #64] @ *(IMXRT_IOMUXC_GPR + 16) = r1
+ b copy_from_flash
+ flexram_1180:
+ ldr r0, =0x444F0060 @ M33_CONFIG
+ ldr r1, =__flexram_config
+ str r1, [r0, #0]
+
+ copy_from_flash:
# Conditionally copy text.
ldr r0, =__stext
ldr r2, =__sitext