Skip to content

Add wolfBoot target for NXP i.MX95 Cortex-M7 - #863

Open
dgarske wants to merge 3 commits into
wolfSSL:masterfrom
dgarske:imx95_m7
Open

Add wolfBoot target for NXP i.MX95 Cortex-M7#863
dgarske wants to merge 3 commits into
wolfSSL:masterfrom
dgarske:imx95_m7

Conversation

@dgarske

@dgarske dgarske commented Aug 18, 2026

Copy link
Copy Markdown
Member

New target for the Cortex-M7 real-time core on the NXP i.MX95, including post-quantum verified boot with ML-DSA-87.

What it adds

  • hal/imx95_m7.c, hal/imx95_m7.ld - HAL and linker script
  • hal/uart/uart_drv_imx95_m7.c - console over a shared-memory ring buffer
  • config/examples/imx95-m7.config - example configuration
  • test-app/app_imx95_m7.c, test-app/ARM-imx95_m7.ld, test-app/wolfcrypt_support.c
  • arch.mk - TARGET=imx95_m7 -> CORTEX_M7=1

Design notes

  • The M7 has no dedicated flash. wolfBoot is loaded into TCM by the Linux remoteproc driver on the A55 cluster, and partitions live in the M7's reserved DDR window (memory@80000000), so hal_flash_write/hal_flash_erase are bounds-checked copy and fill.
  • Linked for the TCM core view (ITCM 0x00000000, DTCM 0x20000000); imx_rproc translates to the system view (0x203C0000 / 0x20400000). Linking for the system view produces an image that loads cleanly and faults on first fetch.
  • No M7 UART is routed on this carrier, so the console is a ring buffer at the top of the M7's DDR carveout, behind wolfBoot's standard uart_init/uart_tx/uart_write interface. A small status block sits just above it at 0x80F10000 carrying a magic, a progress code and DWT timestamps, so the A55 can tell "bootloader ran" from "payload ran" with no peripheral wired up. Both live inside the M7's own reserved DDR window and deliberately clear of 0x88000000, which the device tree reserves for RPMsg vrings and a 1 MiB vdevbuffer.
  • Both M7 caches are disabled out of reset. hal_cache_enable() turns them on in hal_init(); no MPU region is needed, since the ARMv7-M default memory map already marks the DDR window normal cacheable. This matters enormously for anything running from DDR - the bare-metal wolfCrypt benchmark moved 25x on SHA-256 and 51x on AES-128-CBC once they were on.

Measured on hardware (Toradex SMARC iMX95, M7 at 800 MHz confirmed from clk_summary, DWT cycle counter, caches enabled):

wolfBoot text verify + boot at 800 MHz
ECDSA P-256 22,268 B 1,733,591 cycles 2.166 ms
ML-DSA-87 21,232 B 4,129,175 cycles 5.162 ms
delta -1,036 B 2.383x +2.996 ms

Two results worth calling out. Post-quantum verified boot costs 5.16 ms, which is 2.4x the cycles of ECDSA P-256 and irrelevant against any real boot time. And the ML-DSA-87 bootloader is 1,036 bytes smaller than the ECDSA one - ML-DSA verification is SHAKE plus polynomial arithmetic and never pulls in the big-integer math that P-256 verification needs, so for a verify-only workload post-quantum can cost less flash.

wolfBoot itself barely benefits from the caches (5%) because it runs its text from ITCM, which is already zero-wait; the payload runs from DDR, where they do everything.

ML-DSA-87 verify runs entirely within the default 256 KB DTCM with no spill to DDR. The real cost is per-image header: a 4,627-byte signature and 2,592-byte public key against 64 bytes each for ECDSA. Both builds above used a fixed IMAGE_HEADER_SIZE=12288 to hold the partition layout constant, so the signed images are identically sized; that is an artifact of the layout, not a result. An ECDSA-only design could use a much smaller header, so the honest figure is ~12 KB of extra header per image.

Both cases are verified on hardware: the positive case (valid image boots, progress code reaches hal_prepare_boot, app heartbeat advances) and the negative case (no valid image - wolfBoot stops at hal_init and does not jump).

Build

cp config/examples/imx95-m7.config .config
make                                                  # ECDSA P-256
make keysclean && make SIGN=ML_DSA ML_DSA_LEVEL=5 \
     IMAGE_SIGNATURE_SIZE=4627                        # ML-DSA-87

factory.bin is not usable on this target: wolfBoot runs from ITCM at 0x00000000 while the BOOT partition is in DDR at 0x80100000, and those are not contiguous. Load wolfboot.elf via remoteproc and place the signed image in DDR separately.

@dgarske dgarske self-assigned this Aug 18, 2026
Copilot AI lite review requested due to automatic review settings August 18, 2026 19:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Adds a new wolfBoot target for the NXP i.MX95 Cortex-M7 (remoteproc-loaded into TCM) with a DDR-backed “pseudo-flash” and shared-memory console, plus a test application and example configuration.

Changes:

  • Introduces i.MX95 M7 HAL + linker script and enables CORTEX_M7 for TARGET=imx95_m7.
  • Implements a shared-memory ring-buffer console (no physical UART) and an M7 test app + linker script.
  • Adds an example config and M7-specific timing support using the DWT cycle counter.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
hal/imx95_m7.c New i.MX95 M7 HAL with DDR “flash”, cache enablement, and status reporting
hal/imx95_m7.ld New wolfBoot linker script for ITCM/DTCM (core view)
hal/uart/uart_drv_imx95_m7.c Shared-memory console implementation
test-app/app_imx95_m7.c New M7 test application with shared-memory liveness markers
test-app/ARM-imx95_m7.ld Test-app linker script with explicit heap/stack sizing in DTCM
test-app/Makefile Adds TARGET=imx95_m7 test-app integration
test-app/wolfcrypt_support.c Adds M7 timing via DWT cycle counter
config/examples/imx95-m7.config Example build/partition layout for i.MX95 M7
arch.mk Sets CORTEX_M7=1 for TARGET=imx95_m7

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread hal/uart/uart_drv_imx95_m7.c
Comment thread hal/imx95_m7.c Outdated
Comment thread hal/imx95_m7.c Outdated
Comment thread hal/imx95_m7.c Outdated
Comment thread test-app/wolfcrypt_support.c Outdated
Comment thread test-app/wolfcrypt_support.c Outdated
Comment thread hal/imx95_m7.ld
Comment thread test-app/ARM-imx95_m7.ld
@dgarske
dgarske marked this pull request as ready for review August 18, 2026 23:37
@dgarske dgarske assigned danielinux and wolfSSL-Bot and unassigned dgarske Aug 18, 2026
@dgarske
dgarske requested a review from danielinux August 18, 2026 23:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants