Skip to content

Commit 233b6ab

Browse files
committed
imx95_a55: add the Cortex-A55 target and a stage 1 replacing U-Boot SPL
1 parent 8b8d409 commit 233b6ab

25 files changed

Lines changed: 4810 additions & 75 deletions

‎.github/workflows/test-configs.yml‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,33 @@ jobs:
517517
config-file: ./config/examples/imx95-m7.config
518518
make-args: wolfboot.bin test-app/image_v1_signed.bin
519519

520+
imx95_a55_test:
521+
uses: ./.github/workflows/test-build.yml
522+
with:
523+
arch: aarch64
524+
# i.MX95 Cortex-A55 as BL33. The payload is a Linux FIT on the boot
525+
# medium, so there is no test app and no contiguous factory.bin.
526+
config-file: ./config/examples/imx95-a55.config
527+
make-args: wolfboot.bin CROSS_COMPILE=aarch64-linux-gnu-
528+
529+
imx95_a55_stage1_emmc_test:
530+
uses: ./.github/workflows/test-build.yml
531+
with:
532+
arch: aarch64
533+
# The stage 1 that replaces U-Boot SPL, reading the containers from the
534+
# eMMC boot partition. Nothing else compiles the AHAB parser or the
535+
# OCRAM link, so this keeps both from rotting.
536+
config-file: ./config/examples/imx95-a55.config
537+
make-args: -C stage1 DISK_EMMC=1 DISK_SDCARD=0 loader_stage1.bin CROSS_COMPILE=aarch64-linux-gnu-
538+
539+
imx95_a55_stage1_sd_test:
540+
uses: ./.github/workflows/test-build.yml
541+
with:
542+
arch: aarch64
543+
# Same stage 1 against the SD controller rather than the eMMC one.
544+
config-file: ./config/examples/imx95-a55.config
545+
make-args: -C stage1 DISK_SDCARD=1 DISK_EMMC=0 loader_stage1.bin CROSS_COMPILE=aarch64-linux-gnu-
546+
520547
tegra234_test:
521548
uses: ./.github/workflows/test-build.yml
522549
with:

‎.gitignore‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,7 @@ tools/unit-tests/unit-va416x0-fram
263263
tools/unit-tests/unit-wolfhsm_flash_hal
264264
tools/unit-tests/unit-ubootenv
265265
tools/unit-tests/unit-cm4-sdhci
266+
tools/unit-tests/unit-imx95-ahab
266267
tools/unit-tests/unit-cm4-rauc-slot
267268
tools/unit-tests/__pycache__/*
268269

‎Makefile‎

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

438+
# i.MX95 A55 is a RAM-resident BL33 loaded by SPL inside an AHAB container, so
439+
# there is no contiguous flash image to assemble into a factory.bin.
440+
ifeq ($(TARGET),imx95_a55)
441+
MAIN_TARGET:=wolfboot.bin
442+
endif
443+
438444
ifeq ($(TARGET),cm4)
439445
MAIN_TARGET:=wolfboot.bin
440446
endif

‎arch.mk‎

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ ifeq ($(ARCH),AARCH64)
7676
# Skip the bare-metal reset (boot_aarch64_start.S) and EL2/GIC glue.
7777
OBJS+=src/boot_aarch64_efi.o
7878
else
79-
OBJS+=src/boot_aarch64.o src/boot_aarch64_start.o
79+
OBJS+=src/boot_aarch64.o src/boot_aarch64_start.o src/boot_aarch64_cache.o
8080
endif
8181

8282
ifeq ($(TARGET),zynq)
@@ -309,6 +309,61 @@ ifeq ($(ARCH),AARCH64)
309309
endif
310310
endif
311311

312+
ifeq ($(TARGET),imx95_a55)
313+
# NXP i.MX95 Cortex-A55 cluster, running as BL33 in AHAB container 2.
314+
# -mstrict-align because this stage runs with the MMU off, so every access
315+
# is Device-nGnRnE and unaligned ones fault.
316+
ARCH_FLAGS=-mcpu=cortex-a55+crypto -march=armv8.2-a+crypto -mstrict-align
317+
CFLAGS+=$(ARCH_FLAGS) -DCORTEX_A55
318+
LDFLAGS+=$(ARCH_FLAGS)
319+
# BL31 loads and enters this image here; must match ORIGIN in
320+
# hal/imx95_a55.ld and IMX95_BL33_BASE in hal/imx95_a55.h.
321+
WOLFBOOT_ORIGIN=0x90200000
322+
# Console, SCMI client and uSDHC driver all live in hal/imx95_a55.c, so none
323+
# needs its own object; the switches below pick which paths compile in.
324+
# Bring-up aid: print the entry EL, SCTLR and handoff x0 that BL31 passed.
325+
ifeq ($(IMX95_HANDOFF_DUMP),1)
326+
CFLAGS+=-DIMX95_HANDOFF_DUMP
327+
endif
328+
# i.MX95 is GICv3 and BL31 already configured it. EL2_HYPERVISOR is not a
329+
# generic options.mk variable, so it is emitted here as tegra234 does.
330+
ifeq ($(EL2_HYPERVISOR),1)
331+
CFLAGS+=-DEL2_HYPERVISOR=1
332+
endif
333+
# i.MX uSDHC is not SDHCI-compatible: skip src/sdhci.c, use our driver.
334+
ifneq ($(filter 1,$(DISK_SDCARD) $(DISK_EMMC)),)
335+
DISK_DRIVER=usdhc
336+
# SCMI cold-init of uSDHC2 (clock+pinmux) when no prior stage did it.
337+
ifeq ($(IMX95_SCMI_COLD_INIT),1)
338+
CFLAGS+=-DIMX95_SCMI_COLD_INIT
339+
endif
340+
endif
341+
# SCMI M7 power-on + TCM ECC scrub (U-Boot's power_on_m7 equivalent) for a
342+
# Cortex-M7 that Linux launches later. Independent of the disk driver.
343+
ifeq ($(IMX95_INIT_M7),1)
344+
CFLAGS+=-DIMX95_INIT_M7
345+
endif
346+
# One-shot diagnostic: read the AHAB container out of the eMMC boot
347+
# partitions and report it, from inside an image that boots from SD.
348+
ifeq ($(IMX95_EMMC_PROBE),1)
349+
CFLAGS+=-DIMX95_EMMC_PROBE
350+
OBJS+=hal/imx95_ahab.o
351+
endif
352+
# Mirror the console into a DDR ring that survives the handoff to Linux.
353+
ifeq ($(IMX95_LOG_RING),1)
354+
CFLAGS+=-DIMX95_LOG_RING
355+
endif
356+
# Stage 1 and BL33 must agree on where the ring lives, and both read this
357+
# from arch.mk, which stage1/Makefile includes.
358+
ifneq ($(IMX95_LOG_RING_BASE),)
359+
CFLAGS+=-DIMX95_LOG_RING_BASE=$(IMX95_LOG_RING_BASE)
360+
endif
361+
# Verbose per-step trace of the SCMI cold-init and SD bring-up.
362+
ifeq ($(IMX95_SCMI_DEBUG),1)
363+
CFLAGS+=-DIMX95_SCMI_DEBUG
364+
endif
365+
endif
366+
312367
ifeq ($(TARGET),cm4)
313368
# Raspberry Pi Compute Module 4 - Broadcom BCM2711, Cortex-A72
314369
ARCH_FLAGS=-mcpu=cortex-a72+crypto -march=armv8-a+crypto -mtune=cortex-a72
@@ -335,7 +390,7 @@ ifeq ($(ARCH),AARCH64)
335390
# asm (sp_arm64.c / WOLFSSL_SP_ARM64_ASM); that is enabled independently on
336391
# __aarch64__ in include/user_settings.h, so a non-FIPS cm4 build still links
337392
# sp_arm64 asm.
338-
ifeq ($(filter zynq versal nxp_ls1028a,$(TARGET)),)
393+
ifeq ($(filter zynq versal nxp_ls1028a imx95_a55,$(TARGET)),)
339394
NO_ARM_ASM?=1
340395
endif
341396

‎config/examples/imx95-a55.config‎

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
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+
# `make stage1` from this same config also replaces SPL, and then the chain is
7+
# ROM -> ELE -> SM -> OEI -> wolfBoot [c1] -> BL31 -> OP-TEE -> wolfBoot
8+
# with stage 1 making the ELE call that authenticates container 2 that SPL used
9+
# to make (IMX95_AHAB_AUTH, on by default). See docs/Targets.md.
10+
11+
ARCH?=AARCH64
12+
TARGET?=imx95_a55
13+
14+
# ML-DSA-87, matching the imx95_m7 port. Header fits sig (4627) + pubkey.
15+
SIGN?=ML_DSA
16+
ML_DSA_LEVEL?=5
17+
HASH?=SHA256
18+
# Required: unset, ML_DSA_IMAGE_SIGNATURE_SIZE expands empty -> image.c errors.
19+
IMAGE_SIGNATURE_SIZE?=4627
20+
IMAGE_HEADER_SIZE?=12288
21+
22+
DEBUG?=0
23+
DEBUG_SYMBOLS=1
24+
DEBUG_UART?=1
25+
# Print entry EL, SCTLR, MPIDR, CNTFRQ and the handoff x0 pointer.
26+
IMX95_HANDOFF_DUMP?=1
27+
# Report how long each boot step takes, in ms, from the generic timer.
28+
BOOT_BENCHMARK?=1
29+
# Also mirror the console into a DDR ring, so the verified-boot log can be read
30+
# from Linux (and shown on a display) long after the UART output has scrolled.
31+
IMX95_LOG_RING?=1
32+
33+
V?=0
34+
SPMATH?=1
35+
NO_ASM?=0
36+
37+
# RAM-resident: BL31 loads and enters this image, so there is nothing to copy
38+
# from a stored .data and no XIP flash behind it.
39+
NO_XIP?=1
40+
41+
# GICv3, configured by BL31; gicv2_init_secure() would abort on an unmapped
42+
# ZynqMP address.
43+
SKIP_GIC_INIT?=1
44+
45+
# Stay at EL2 (Linux wants it for KVM). Do NOT set BOOT_EL1: el2_to_el1_boot
46+
# skips cache/MMU cleanup and would hand Linux stale DRAM.
47+
EL2_HYPERVISOR=1
48+
49+
# No flash: boot/update addresses come from the HAL.
50+
WOLFBOOT_NO_PARTITIONS=1
51+
52+
# Must match ORIGIN in hal/imx95_a55.ld and IMX95_BL33_BASE in hal/imx95_a55.h.
53+
WOLFBOOT_ORIGIN=0x90200000
54+
55+
# RAM staging at 0xA1000000: clear of the M7/BL31/OP-TEE/ELE/vpu carveouts;
56+
# hal_init() asserts this via imx95_check_load_ranges().
57+
WOLFBOOT_LOAD_ADDRESS?=0xA1000000
58+
WOLFBOOT_LOAD_DTS_ADDRESS?=0xA0800000
59+
60+
# Bounds the image before authentication; required without fixed partitions.
61+
WOLFBOOT_RAMBOOT_MAX_SIZE=0x10000000
62+
63+
# Required for the test-app link even with WOLFBOOT_NO_PARTITIONS=1.
64+
WOLFBOOT_SECTOR_SIZE?=0x4000
65+
WOLFBOOT_PARTITION_SIZE?=0x4000000
66+
WOLFBOOT_PARTITION_BOOT_ADDRESS?=0xA1000000
67+
68+
# Toolchain
69+
USE_GCC=1
70+
CROSS_COMPILE?=aarch64-none-elf-
71+
72+
# Storage: carrier SD on uSDHC2 (uSDHC driver in hal/imx95_a55.c; i.MX uSDHC, not SDHCI).
73+
# Boot containers stay on eMMC.
74+
DISK_SDCARD?=1
75+
# Cold start: with no U-Boot ahead of wolfBoot the uSDHC2 clock and pinmux are
76+
# still owned by the System Manager and must be requested over SCMI.
77+
IMX95_SCMI_COLD_INIT?=1
78+
# Power the Cortex-M7 mix and scrub its TCM, as U-Boot's board init does, for
79+
# boards that launch an M7 image from Linux.
80+
IMX95_INIT_M7?=1
81+
# A/B slots by 0-based index into the parsed partition table.
82+
CFLAGS_EXTRA+=-DBOOT_PART_A=1 -DBOOT_PART_B=2
83+
CFLAGS_EXTRA+=-DDISK_BLOCK_SIZE=0x10000
84+
# This module's ethernet MAC (OUI 00:14:2d, low bytes are the module serial),
85+
# from its Toradex config block. The ENETC ports are PCIe-enumerated and carry
86+
# no local-mac-address in the OS DTB, so without this Linux picks a random MAC
87+
# each boot and the DHCP address floats. Replace it for a different module.
88+
CFLAGS_EXTRA+=-DIMX95_ETH0_MAC=0x00142d888d20
89+
90+
# Linux FIT boot: kernel at 0xB2000000, ramdisk at 0xBA000000 - both above
91+
# the staging window so the copies cannot overlap the staged FIT.
92+
FIT_RAMDISK?=1
93+
WOLFBOOT_LOAD_RAMDISK_ADDRESS?=0xBA000000
94+
# OS cmdline plus serial console; ostree= pins the deployment. audit=0 because
95+
# the audit subsystem interleaves records with anything else on this console.
96+
CFLAGS_EXTRA+=-DLINUX_BOOTARGS='"earlycon console=ttyLP1,115200 audit=0 root=LABEL=otaroot rootfstype=ext4 logo.nologo ostree=/ostree/boot.1/torizon/d976a72bdc954405cfbe989bae393ad9da0b14b5dc0c1328c9b19e88201745a6/0"'
97+
98+
# --- Later phases (not yet implemented) -------------------------------------
99+
#ELF?=1
100+
#GZIP?=1

‎docs/Targets.md‎

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ This README describes configuration of supported targets.
2424
* [Nordic nRF54L15](#nordic-nrf54l15)
2525
* [NXP i.MX 8QuadMax](#nxp-imx-8quadmax)
2626
* [NXP i.MX95 Cortex-M7](#nxp-imx95-cortex-m7)
27+
* [NXP i.MX95 Cortex-A55 (BL33)](#nxp-imx95-cortex-a55-bl33)
2728
* [NXP iMX-RT](#nxp-imx-rt)
2829
* [NXP i.MX RT700](#nxp-imx-rt700)
2930
* [NXP Kinetis](#nxp-kinetis)
@@ -10302,6 +10303,73 @@ The difference between the two timestamps is the cost of everything wolfBoot doe
1030210303

1030310304
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.
1030410305

10306+
## NXP i.MX95 Cortex-A55 (BL33)
10307+
10308+
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. 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.
10309+
10310+
Which component authenticates the containers depends on which slot wolfBoot occupies, and the two cases are not the same:
10311+
10312+
- **wolfBoot as BL33 only** (this section). U-Boot SPL is still in container 0 and still calls the ELE to authenticate container 2 before BL31 runs, so the chain is ROM -> ELE -> SPL -> BL31 -> wolfBoot -> Linux once SRK fuses are programmed.
10313+
- **wolfBoot as stage 1 as well** (next section). SPL is gone, so wolfBoot performs that ELE call itself. `IMX95_AHAB_AUTH` is what does it, and it is on by default; the chain becomes ROM -> ELE -> wolfBoot stage 1 -> BL31 -> wolfBoot BL33 -> Linux.
10314+
10315+
In both cases the ROM and the ELE authenticate container 0 before any A55 code runs, so whichever image sits in the SPL slot is itself verified.
10316+
10317+
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, the uSDHC driver in `hal/imx95_a55.c` - i.MX uSDHC, not SDHCI-compatible).
10318+
10319+
Notes:
10320+
- 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.
10321+
- 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.
10322+
- Use plain `earlycon` (DTB-derived); an explicit `earlycon=lpuart32,mmio32,<addr>` uses the wrong register layout on i.MX and silences all console output.
10323+
- uSDHC2's clock, pinmux and card power are owned by the M33 System Manager, and its pad registers data-abort on direct access from BL33. `IMX95_SCMI_COLD_INIT=1` brings them up over SCMI (the SCMI client in `hal/imx95_a55.c`), which is what lets wolfBoot boot from SD on a cold power-on rather than only after a stage that already initialized the controller.
10324+
- `IMX95_INIT_M7=1` powers the Cortex-M7 mix and scrubs its TCM for ECC, matching what U-Boot's board init does, for boards that launch an M7 image from Linux later.
10325+
10326+
### Stage 1: replacing U-Boot SPL
10327+
10328+
The boot device holds a set of AHAB containers. The first one is what the boot ROM reads: it carries the ELE firmware, the M33 System Manager, the OEI that trains DDR, and one A55 image loaded into OCRAM at `0x20480000`. That last image is U-Boot SPL, and its whole job is to find the next container and load BL31, OP-TEE and BL33 out of it. wolfBoot can take that slot instead:
10329+
10330+
```
10331+
cp config/examples/imx95-a55.config .config
10332+
make # BL33, loaded into DRAM by BL31
10333+
make stage1 DISK_EMMC=1 # stage1/loader_stage1.bin, the SPL slot
10334+
```
10335+
10336+
DDR is up before stage 1 runs, because the OEI did it, so stage 1 only needs the boot device and the container walk. Nothing records where the next container starts: it is derived by taking the end of the first container - the furthest of its header, its images and its signature block - and rounding up to 1 KiB. `hal/imx95_ahab.c` is that walk, and `hal/imx95_a55_stage1.c` is the rest: the watchdog, GPIO and SMMU state a warm reset out of Linux leaves behind, the SCMI calls for the console clock and the A55 performance level, and the ELE call that starts its random generator.
10337+
10338+
Two things differ from the BL33 build. The console is programmed rather than inherited, since nothing has configured LPUART1 yet. And on eMMC the containers live in a boot partition, not the user area: `imx95_emmc_boot_partition()` reads back the same `PARTITION_CONFIG` field that told the ROM which one to load from, and reads follow it.
10339+
10340+
#### What stage 1 authenticates
10341+
10342+
Taking SPL's slot means taking over the step SPL performed. The boot ROM and the ELE authenticate container 0, so stage 1 is verified code, but the container it goes on to load BL31, OP-TEE and BL33 out of is a separate one that nothing has checked yet. `IMX95_AHAB_AUTH=1` (the default) makes stage 1 ask the ELE to check it, the same three calls U-Boot's SPL makes:
10343+
10344+
1. The container's header, image table and signature block are staged into DDR at `0x90000000` - NXP's own `IMG_CONTAINER_BASE` for this SoC - because the ELE reads the address it is given over its own master port and requires DDR. Every value stage 1 then acts on comes from those staged bytes; the medium is not consulted for the table again.
10345+
2. `ELE_OEM_CNTN_AUTH_REQ` authenticates the header.
10346+
3. Each image is loaded to its destination and then checked in place with `ELE_VERIFY_IMAGE_REQ`, one at a time so a failure names the image. `ELE_RELEASE_CONTAINER_REQ` follows, before the jump.
10347+
10348+
Any failure stops the boot. `IMX95_AHAB_AUTH=0` builds without those calls, for bring-up on a part whose containers are not signed. `IMX95_STAGE1_PASSTHROUGH` and `IMX95_STAGE1_ALLOW_SELF_OVERLAP` each carry on past a container the enclave refused, so both require `IMX95_AHAB_AUTH=0`; setting either while authentication is on fails the build.
10349+
10350+
Separately, and regardless of that flag, stage 1 bounds every destination *before* writing any of them. An image is streamed straight from the boot device into the address the container names, so a check made afterwards would come too late to matter: by then the bytes have landed. Destinations must lie inside DDR, must not overlap the staging window, this loader, the M7 carveout, the ELE shared-memory region or the VPU boot area, must not overlap each other once rounded up to the block size, and image 0 must be an A55 executable whose entry point lies inside its own bytes.
10351+
10352+
Two limits are worth stating plainly:
10353+
10354+
- **On an open part AHAB reports success without enforcing a signature.** That is why an unsigned container boots at all. What authentication buys there is an ELE-checked hash of each image against a table nobody signed - integrity, not authenticity. Build with `IMX95_AHAB_LIFECYCLE=1` to have stage 1 print the lifecycle, so the difference is visible rather than implied; it is off by default because nothing else on this platform reads the fuse shadow block from the slot SPL occupies. Enforcement begins when the SRK hash is fused; see the i.MX8QuadMax AHAB section above for what that costs and why it is irreversible.
10355+
- **Authenticating the container does not prevent rollback.** The offset of the next container is derived by walking container 0, which stage 1 reads off the medium and nothing re-authenticates, so a different but validly signed older container set would authenticate happily. That needs `sw_version`/`fuse_version` policy or the AHAB monotonic counter, neither of which is implemented here.
10356+
10357+
#### Stage 1 build options
10358+
10359+
Stage 1 is built by `make -C stage1` and takes its own options, separately from the BL33 build. Pass them on the command line.
10360+
10361+
| Option | Default | Effect |
10362+
|---|---|---|
10363+
| `IMX95_AHAB_AUTH` | `1` | Ask the ELE to authenticate the container set stage 1 loads BL31, OP-TEE and BL33 from, as described above. Setting it to `0` builds without those calls, for bring-up on a part whose containers are not signed. |
10364+
| `IMX95_AHAB_LIFECYCLE` | `0` | Read and print the part's lifecycle from the fuse shadow block. Off by default: U-Boot reads that block only from U-Boot proper and only under `CONFIG_AHAB_BOOT`, so whether it answers the A55 this early is untested per part, and a diagnostic must not be able to cost a boot. |
10365+
| `IMX95_STAGE1_PASSTHROUGH` | unset | Bring-up only. Enter BL31 even when the container load failed, for a board where some other loader has already staged the whole set and stage 1 only needs to be invisible when it cannot help. Requires `IMX95_AHAB_AUTH=0`, and is refused at compile time otherwise, because returning an error is then indistinguishable from the jump. |
10366+
| `IMX95_STAGE1_ALLOW_SELF_OVERLAP` | unset | Bring-up only. Skip an image whose destination lands on the running loader instead of refusing the boot, which a stage 1 linked into DRAM needs in order to skip its own entry. Requires `IMX95_AHAB_AUTH=0`, and is refused at compile time otherwise. |
10367+
| `IMX95_LOG_RING` | `0` | Mirror the console into a DDR ring that survives the handoff, so stage 1's output can be read back from Linux with `memtool con`. Stage 1 starts the ring and BL33 appends to it, so one address holds both. |
10368+
| `IMX95_LOG_RING_BASE` | `0x80F20000` | Where that ring lives. Change it only to move the ring out of the way of something else; stage 1 and BL33 must agree on it. |
10369+
| `IMX95_EMMC_PROBE` | `0` | One-shot diagnostic that walks the eMMC boot partitions and reports the AHAB containers it finds, from an image booting off SD. |
10370+
10371+
The two bring-up options exist to get a new board talking; neither belongs in a shipped configuration, and the build refuses to combine either with authentication rather than letting a boot continue past a refusal.
10372+
1030510373
## TI C2000 C28x (LAUNCHXL-F28P55X)
1030610374

1030710375
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)