Skip to content

Commit 793b63a

Browse files
committed
Add wolfBoot target for NXP i.MX95 Cortex-A55 as BL33 booting a Linux FIT from SD
1 parent bafa907 commit 793b63a

11 files changed

Lines changed: 1243 additions & 11 deletions

File tree

‎Makefile‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,12 @@ ifeq ($(TARGET),tegra234)
396396
MAIN_TARGET:=wolfboot.bin test-app/image_v1_signed.bin
397397
endif
398398

399+
# i.MX95 A55 is a RAM-resident BL33 loaded by SPL inside an AHAB container, so
400+
# there is no contiguous flash image to assemble into a factory.bin.
401+
ifeq ($(TARGET),imx95_a55)
402+
MAIN_TARGET:=wolfboot.bin
403+
endif
404+
399405
ifeq ($(TARGET),cm4)
400406
MAIN_TARGET:=wolfboot.bin
401407
endif

‎arch.mk‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,32 @@ ifeq ($(ARCH),AARCH64)
219219
# BOOT_EL1 itself is emitted by options.mk; nothing to add here.
220220
endif
221221

222+
ifeq ($(TARGET),imx95_a55)
223+
# NXP i.MX95 Cortex-A55 cluster, running as BL33 in AHAB container 2.
224+
# -mstrict-align because this stage runs with the MMU off, so every access
225+
# is Device-nGnRnE and unaligned ones fault.
226+
ARCH_FLAGS=-mcpu=cortex-a55+crypto -march=armv8.2-a+crypto -mstrict-align
227+
CFLAGS+=$(ARCH_FLAGS) -DCORTEX_A55
228+
LDFLAGS+=$(ARCH_FLAGS)
229+
# BL31 loads and enters this image here; must match ORIGIN in
230+
# hal/imx95_a55.ld and IMX95_BL33_BASE in hal/imx95_a55.h.
231+
WOLFBOOT_ORIGIN=0x90200000
232+
# Bring-up aid: print the entry EL, SCTLR and handoff x0 that BL31 passed.
233+
ifeq ($(IMX95_HANDOFF_DUMP),1)
234+
CFLAGS+=-DIMX95_HANDOFF_DUMP
235+
endif
236+
# i.MX95 is GICv3 and BL31 already configured it. EL2_HYPERVISOR is not a
237+
# generic options.mk variable, so it is emitted here as tegra234 does.
238+
ifeq ($(EL2_HYPERVISOR),1)
239+
CFLAGS+=-DEL2_HYPERVISOR=1
240+
endif
241+
# i.MX uSDHC is not SDHCI-compatible: skip src/sdhci.c, use our driver.
242+
ifneq ($(filter 1,$(DISK_SDCARD) $(DISK_EMMC)),)
243+
DISK_DRIVER=usdhc
244+
OBJS+=hal/imx95_usdhc.o
245+
endif
246+
endif
247+
222248
ifeq ($(TARGET),cm4)
223249
# Raspberry Pi Compute Module 4 - Broadcom BCM2711, Cortex-A72
224250
ARCH_FLAGS=-mcpu=cortex-a72+crypto -march=armv8-a+crypto -mtune=cortex-a72

‎config/examples/imx95-a55.config‎

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# NXP i.MX95 Cortex-A55 - wolfBoot as BL33 (replaces U-Boot proper):
2+
# ROM -> ELE -> SM -> OEI -> SPL [c1] -> BL31 -> OP-TEE -> wolfBoot -> Linux
3+
# wolfBoot takes U-Boot's slot in AHAB container 2 at 0x90200000; the other
4+
# container images are the vendor's, reused verbatim.
5+
6+
ARCH?=AARCH64
7+
TARGET?=imx95_a55
8+
9+
# ML-DSA-87, matching the imx95_m7 port. Header fits sig (4627) + pubkey.
10+
SIGN?=ML_DSA
11+
ML_DSA_LEVEL?=5
12+
HASH?=SHA256
13+
# Required: unset, ML_DSA_IMAGE_SIGNATURE_SIZE expands empty -> image.c errors.
14+
IMAGE_SIGNATURE_SIZE?=4627
15+
IMAGE_HEADER_SIZE?=12288
16+
17+
DEBUG?=0
18+
DEBUG_SYMBOLS=1
19+
DEBUG_UART?=1
20+
# Print entry EL, SCTLR, MPIDR, CNTFRQ and the handoff x0 pointer.
21+
IMX95_HANDOFF_DUMP?=1
22+
23+
V?=0
24+
SPMATH?=1
25+
NO_ASM?=0
26+
27+
# RAM-resident: BL31 loads and enters this image, so there is nothing to copy
28+
# from a stored .data and no XIP flash behind it.
29+
NO_XIP?=1
30+
31+
# GICv3, configured by BL31; gicv2_init_secure() would abort on an unmapped
32+
# ZynqMP address.
33+
SKIP_GIC_INIT?=1
34+
35+
# Stay at EL2 (Linux wants it for KVM). Do NOT set BOOT_EL1: el2_to_el1_boot
36+
# skips cache/MMU cleanup and would hand Linux stale DRAM.
37+
EL2_HYPERVISOR=1
38+
39+
# No flash: boot/update addresses come from the HAL.
40+
WOLFBOOT_NO_PARTITIONS=1
41+
42+
# Must match ORIGIN in hal/imx95_a55.ld and IMX95_BL33_BASE in hal/imx95_a55.h.
43+
WOLFBOOT_ORIGIN=0x90200000
44+
45+
# RAM staging at 0xA1000000: clear of the M7/BL31/OP-TEE/ELE/vpu carveouts;
46+
# hal_init() asserts this via imx95_check_load_ranges().
47+
WOLFBOOT_LOAD_ADDRESS?=0xA1000000
48+
WOLFBOOT_LOAD_DTS_ADDRESS?=0xA0800000
49+
50+
# Bounds the image before authentication; required without fixed partitions.
51+
WOLFBOOT_RAMBOOT_MAX_SIZE=0x10000000
52+
53+
# Required for the test-app link even with WOLFBOOT_NO_PARTITIONS=1.
54+
WOLFBOOT_SECTOR_SIZE?=0x4000
55+
WOLFBOOT_PARTITION_SIZE?=0x4000000
56+
WOLFBOOT_PARTITION_BOOT_ADDRESS?=0xA1000000
57+
58+
# Toolchain
59+
USE_GCC=1
60+
CROSS_COMPILE?=aarch64-none-elf-
61+
62+
# Storage: carrier SD on uSDHC2 (hal/imx95_usdhc.c; i.MX uSDHC, not SDHCI).
63+
# Boot containers stay on eMMC.
64+
DISK_SDCARD?=1
65+
# A/B slots by 0-based index into the parsed partition table.
66+
CFLAGS_EXTRA+=-DBOOT_PART_A=1 -DBOOT_PART_B=2
67+
CFLAGS_EXTRA+=-DDISK_BLOCK_SIZE=0x10000
68+
69+
# Linux FIT boot: kernel at 0xB2000000, ramdisk at 0xBA000000 - both above
70+
# the staging window so the copies cannot overlap the staged FIT.
71+
FIT_RAMDISK?=1
72+
WOLFBOOT_LOAD_RAMDISK_ADDRESS?=0xBA000000
73+
# OS cmdline plus serial console; the ostree= path pins the deployment.
74+
CFLAGS_EXTRA+=-DLINUX_BOOTARGS='"earlycon console=ttyLP1,115200 root=LABEL=otaroot rootfstype=ext4 logo.nologo ostree=/ostree/boot.1/torizon/d976a72bdc954405cfbe989bae393ad9da0b14b5dc0c1328c9b19e88201745a6/0"'
75+
76+
# --- Later phases (not yet implemented) -------------------------------------
77+
#ELF?=1
78+
#GZIP?=1

‎docs/Targets.md‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ This README describes configuration of supported targets.
2121
* [Nordic nRF5340](#nordic-nrf5340)
2222
* [Nordic nRF54L15](#nordic-nrf54l15)
2323
* [NXP i.MX95 Cortex-M7](#nxp-imx95-cortex-m7)
24+
* [NXP i.MX95 Cortex-A55 (BL33)](#nxp-imx95-cortex-a55-bl33)
2425
* [NXP iMX-RT](#nxp-imx-rt)
2526
* [NXP Kinetis](#nxp-kinetis)
2627
* [NXP Kinetis KL26Z](#nxp-kinetis-kl26z)
@@ -9276,6 +9277,18 @@ The difference between the two timestamps is the cost of everything wolfBoot doe
92769277
92779278
Both caches are enabled by `hal_init()`, which matters because verifying an image means hashing megabytes resident in DDR. The ARMv7-M default memory map marks `0x80000000-0x9FFFFFFF` as Normal write-through, so no MPU region is needed and M7 stores to the shared window still reach DDR; the HAL nevertheless cleans the affected lines explicitly so that behaviour is not left depending on an inherited attribute.
92789279
9280+
## NXP i.MX95 Cortex-A55 (BL33)
9281+
9282+
wolfBoot replaces U-Boot proper on the i.MX95's Cortex-A55 cluster: it is the third image in AHAB container 2 (after BL31 and OP-TEE), entered by BL31 at `0x90200000` in NS-EL2, where it verifies a Linux FIT (kernel + DTB + initramfs) with ML-DSA-87 and boots it at EL2. SPL/ELE authenticate the container itself (AHAB), so the chain is ROM -> ELE -> SPL -> BL31 -> wolfBoot -> Linux once SRK fuses are programmed. NXP also documents an OEM PQC SRK hybrid (ML-DSA) AHAB flow, so the container half of the chain can be post-quantum as well.
9283+
9284+
Validated on a Toradex SMARC iMX95 with `TARGET=imx95_a55` (`config/examples/imx95-a55.config`): full boot to Linux userspace with the FIT on the carrier SD (uSDHC2, `hal/imx95_usdhc.c` - i.MX uSDHC, not SDHCI-compatible).
9285+
9286+
Notes:
9287+
- The FIT DTB gets `/chosen` bootargs, initrd properties and a `/memory` node from `hal_dts_fixup()`; deployment DTBs commonly ship without `/memory` (the bootloader is expected to add it) and the kernel hangs silently without one.
9288+
- The EL2 exit is a fused asm routine (flush, DAIF mask, TLB invalidate, jump) that touches no memory after the D-cache goes off; set/way cleaning does not reach the A55 cluster's DSU system cache, so payload ranges are also cleaned by VA.
9289+
- Use plain `earlycon` (DTB-derived); an explicit `earlycon=lpuart32,mmio32,<addr>` uses the wrong register layout on i.MX and silences all console output.
9290+
- Storage requires the prior stage to have brought up uSDHC2 (clock/pinmux/card power are System Manager-owned via SCMI); a cold-boot SCMI client is follow-on work.
9291+
92799292
## TI C2000 C28x (LAUNCHXL-F28P55X)
92809293
92819294
wolfBoot runs on the Texas Instruments C2000 C28x DSP (TMS320F28P550SJ, 150 MHz) as a secure execute-in-place (XIP) bootloader. The C28x is word-addressed with `CHAR_BIT == 16` (no 8-bit type -- each octet occupies one 16-bit cell), built with the TI `cl2000` toolchain against wolfSSL's wide-byte (`CHAR_BIT != 8`) support.

0 commit comments

Comments
 (0)