Conversation
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved critical and moderate findings remain in uSDHC initialization and selection, FIT memory bounds, and DT fixups.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Adds an i.MX95 Cortex-A55 BL33 target that verifies signed Linux FIT images from SD and boots them at EL2.
Changes:
- Adds i.MX95 HAL, linker layout, configuration, documentation, and build integration.
- Adds a polled uSDHC SD-card driver with controller selection.
- Adds AArch64 handoff, cache/MMU teardown, DTB fixups, and crash diagnostics.
File summaries
| File | Summary and final findings |
|---|---|
src/boot_aarch64.c |
Invokes the fused EL2 handoff. |
src/boot_aarch64_start.S |
Implements startup, cache teardown, and crash vectors. Nit (1): Correct the reversed x0/x1 ABI comment. |
options.mk |
Adds selectable disk-controller configuration. |
Makefile |
Configures the target artifact build. |
hal/imx95_usdhc.c |
Implements uSDHC SD reads. Critical (3): CMD0 uses an incorrect response type. Critical (1): Required controller clocks are not enabled safely. Moderate (2): eMMC selects the SD-slot controller. Critical (1): Startup clocks are not emitted after reset. Moderate (1): 64-bit offsets are narrowed without overflow validation. |
hal/imx95_a55.ld |
Defines the BL33 memory layout and stack. |
hal/imx95_a55.h |
Defines i.MX95 hardware addresses and constants. |
hal/imx95_a55.c |
Provides platform HAL, FIT loading, cache handling, and DTB fixups. Moderate (3): Kernel and ramdisk cache-clean ranges do not cover permitted destinations and sizes. Moderate (2): /chosen lookup must be restricted to the root child. Moderate (3): DT fixup errors must abort the handoff. Moderate (1): /memory lookup must be restricted to the root child. |
docs/Targets.md |
Documents the new target. |
config/examples/imx95-a55.config |
Configures FIT boot and memory addresses. Moderate (1): The kernel-to-ramdisk gap is smaller than the default kernel allowance and can permit overlap. |
arch.mk |
Integrates target flags and drivers. Moderate (1): The SD-only driver is selected for eMMC configurations. |
Review details
Suppressed comments (5)
arch.mk:244
DISK_EMMC=1selects this object, buthal/imx95_usdhc.cis explicitly an SD-only protocol implementation (CMD8/ACMD41/ACMD6); an eMMC uses CMD1 and has no SD-card initialization. This configuration will link the driver and fail atdisk_init; reject eMMC or only select this object forDISK_SDCARD.
ifneq ($(filter 1,$(DISK_SDCARD) $(DISK_EMMC)),)
DISK_DRIVER=usdhc
OBJS+=hal/imx95_usdhc.o
config/examples/imx95-a55.config:72
- This layout leaves only 0x08000000 (128 MiB) between the kernel destination 0xB2000000 and ramdisk 0xBA000000, but
fit_load_image()accepts the default 256 MiB kernel output. A valid signed FIT with a kernel larger than 128 MiB will be overwritten when the ramdisk is loaded. Cap the kernel to the available gap or validate non-overlapping actual ranges before loading.
# Linux FIT boot: kernel at 0xB2000000, ramdisk at 0xBA000000 - both above
# the staging window so the copies cannot overlap the staged FIT.
FIT_RAMDISK?=1
WOLFBOOT_LOAD_RAMDISK_ADDRESS?=0xBA000000
hal/imx95_a55.c:334
- This whole-tree
device_typesearch can select a nested memory node and update itsreg, leaving the root/memorynode absent or unchanged. Since this fixup is specifically for/memory, use the direct root-child lookup before creating it.
off = fdt_find_devtype(&ctx, -1, "memory");
hal/imx95_usdhc.c:424
disk_read()receives a 64-bit byte offset, butlbais narrowed touint32_tbefore being used as the SD command argument. A GPT partition at or above 2 TiB therefore wraps to a different sector instead of failing;src/sdhci.cexplicitly rejects this case. Keep the calculation 64-bit until validating the controller's 32-bit LBA limit, then return an error on overflow.
uint32_t lba, off, chunk, blocks;
src/boot_aarch64_start.S:1759
- The ABI comment says
x0 = dts, but the caller passesentryin x0 anddtsin x1; the implementation itself copies those values into x20/x21 in that order. Keeping the reversed documentation makes future callers liable to branch to the DTB or pass the kernel entry as x0.
/* el2_flush_disable_mmu_and_boot(entry, dts): fused flush + MMU-off + jump
* (x0 = dts, x1-x3 zeroed) touching NO memory after the disable. With the
* D-cache off, a stack reload of entry/dts between a flush call and a
* separate C jump can read stale DRAM (set/way misses a DSU system cache).
* The set/way loop clobbers x0-x11 only; x20/x21 carry the values. */
- Files reviewed: 11/11 changed files
- Comments generated: 8
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
793b63a to
869ae18
Compare
There was a problem hiding this comment.
🟡 Changes recommended
The new uSDHC disk_read() truncates 64-bit byte offsets into 32-bit command arguments without bounds checks, which can wrap and read incorrect sectors on attacker-controlled partition tables.
Get a fresh assessment by requesting another Copilot review.
Review details
- Files reviewed: 13/13 changed files
- Comments generated: 1
- Review effort level: Lite
6ad9497 to
30f6cee
Compare
30f6cee to
5a630fc
Compare
wolfBoot runs on the i.MX95 Cortex-A55 in two positions. As BL33 it is entered by BL31 in NS-EL2, verifies a Linux FIT (kernel, DTB, initramfs) with ML-DSA-87 and boots it at EL2. As a stage 1 it takes the place of U-Boot SPL in AHAB container 0, where the boot ROM loads it into OCRAM, and it brings up the boot device, walks the container set and loads BL31, OP-TEE and BL33. The EdgeLock Enclave (ELE) firmware, the M33 System Manager and the Optional Executable Image (OEI) that trains DDR are untouched and still the SoC's own.
What it adds
hal/imx95_a55.{c,h,ld}- HAL, memory map and linker scripthal/imx95_lpuart.c- LPUART1 console, shared by both positionshal/imx95_usdhc.c- uSDHC driver for the carrier SD and the on-module eMMC including its boot partitions; the i.MX uSDHC is not SDHCI-register-compatible, sosrc/sdhci.cdoes not applyhal/imx95_scmi.c- SCMI-over-MU client for the clocks, pinmux and power domains the System Manager ownshal/imx95_ahab.{c,h}- AHAB container-set parser, with unit tests intools/unit-tests/unit-imx95-ahab.chal/imx95_a55_stage1.{c,ld},hal/imx95_a55_stage1_start.S- the stage 1 and its OCRAM entryconfig/examples/imx95-a55.configand CI entries for the target and both stage-1 variantsTouches shared code
src/boot_aarch64_start.S- identity translation tables and an EL2 MMU enable for this target, so DRAM is mapped Normal cacheable and the wolfCrypt ARM assembly is usable; the carveout shared with the Cortex-M7 is mapped Normal Non-Cacheable because a core outside this cluster's coherency reads itstage1/Makefile- build freestanding and without the C runtime startup files. Without-ffreestandingthe compiler recognizes the byte-scan loop insrc/string.cas thestrlenidiom and rewrites it into a call tostrlenitself, sostrlenbecomes a branch to itselfhal/imx95_m7.{c,h}- do not issue a cache clean by address while the D-cache is disabled. The Cortex-M7 performs maintenance by address regardless, and out of a cold reset the cache RAMs hold random tags and dirty bits, so a hit writes to an arbitrary addressHardware / test status
Validated on a Toradex SMARC i.MX95 (LPUART1, 115200 8N1). Both positions boot cold to Torizon Linux userspace over repeated power cycles, with the FIT on the carrier SD and the boot containers in an eMMC boot partition. The uSDHC driver is also exercised against the state the boot ROM leaves behind, which differs from the state U-Boot leaves: the ROM reads the boot partition in the controller's fast-boot mode with HS400 tuning applied, and
SYS_CTRL_RSTAclears none of it.Scope
The driver is PIO; ADMA2 is follow-on work. Stage 1 does not itself authenticate the containers it loads - AHAB verification belongs to the ELE, which does it in hardware.