Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
4924cb2
Let a port carry its own secure owner map entries
aidangarske Oct 23, 2026
8487624
Add the MCXN947 port
aidangarske Oct 23, 2026
7d64a92
Prove the MCXN947 flash phrase mapping on the host
aidangarske Oct 23, 2026
32c79fb
Boot the MCXN947 chain under M33MU with both bare-metal guests
aidangarske Oct 23, 2026
d5ea728
Rehearse the MCXN947 life cycle in provisioning and test its PSA mapping
aidangarske Oct 23, 2026
9e77b2e
Run the MCXN947 port in CI and make test-target
aidangarske Oct 23, 2026
95f5f59
Document the MCXN947 port
aidangarske Oct 23, 2026
14085f9
Shorten the MCXN947 port comments
aidangarske Oct 23, 2026
a8c54fc
Claim only the MCXN947 scenarios run on M33MU
aidangarske Oct 23, 2026
3e9015b
Program MCXN947 flash from a page base as the ROM requires
aidangarske Oct 24, 2026
7da59db
Let the MCXN947 guest build name the Secure image build tree
aidangarske Oct 24, 2026
b6fc4a5
Add the FRDM-MCXN947 hardware runner
aidangarske Oct 24, 2026
5a4e02c
Add make test-hardware for the FRDM-MCXN947 suite
aidangarske Oct 24, 2026
96064fc
Model the MCXN947 ELS clock gate and executable ROM in M33MU
aidangarske Oct 24, 2026
a9ac856
Count ELS refusals and assert them in the MCXN947 hardware runner
aidangarske Oct 24, 2026
3ee9bd3
Build the MCXN947 life cycle hook outside wolfBoot's DICE-only block
aidangarske Oct 24, 2026
197fe1f
Check the PSA negatives mask and the handed life cycle in the MCXN947…
aidangarske Oct 24, 2026
e8aae05
Document the MCXN947 silicon bring-up and hardware runner
aidangarske Oct 24, 2026
71df3a1
List the MCXN947 hardware suite among the validation entry points
aidangarske Oct 24, 2026
710e445
Claim every MCXN947 scenario that passes on M33MU
aidangarske Oct 26, 2026
4ae5848
Keep the MCXN947 hardware evidence outside build and serialize batches
aidangarske Oct 26, 2026
f838154
Retain each MCXN947 hardware run's console and dumps by scenario and …
aidangarske Oct 26, 2026
56c8c6a
State why confboot is not claimed on the MCXN947 model
aidangarske Oct 26, 2026
dadfa35
Flash the MCXN947 board inside the park session
aidangarske Oct 26, 2026
e967c04
Bind the MCXN947 rehearsal to its probe and preview the lock from the…
aidangarske Oct 26, 2026
224b117
Document the MCXN947 lock preview and the vendor flow it was extracte…
aidangarske Oct 26, 2026
4b802e2
Reserve both write-once trailer sectors in the MCXN947 FWU backend
aidangarske Oct 26, 2026
743335b
Accept a padded final phrase when verifying an MCXN947 FWU candidate
aidangarske Oct 26, 2026
2a659c6
Name the generated secure owner map after its target
aidangarske Oct 26, 2026
c65cf9e
Stop MCXN947 board programming when pyOCD exits nonzero
aidangarske Oct 26, 2026
7cb8588
Keep the MCXN947 ELS RNG page off the stack and stop after a timeout
aidangarske Oct 26, 2026
3890e1d
Refuse a failed MCXN947 PFR page read instead of a stale file
aidangarske Oct 26, 2026
1adff2c
Match MCXN947 pyOCD errors without a pipe that pipefail can break
aidangarske Oct 26, 2026
ee61f03
Build the MCXN947 secure images under static analysis
aidangarske Oct 26, 2026
b71a211
Check the bytes the MCXN947 ELS RNG host test serves
aidangarske Oct 26, 2026
d98c1d0
Check where guest0 faulted in the MCXN947 hardware negatives
aidangarske Oct 26, 2026
e834a46
Release the sticky MCXN947 code cache clear after flash writes
aidangarske Oct 26, 2026
f036642
Bound the FWU probe tail to its write payload
aidangarske Oct 26, 2026
8e4257a
List the MCXN947 smoke scenarios without confboot
aidangarske Oct 26, 2026
e4e1469
Cover the MCXN947 ELS locked and failed request refusals
aidangarske Oct 26, 2026
6a81d29
Carry the M33MU decode of post-indexed LDRSH for the MCXN947 model
aidangarske Oct 26, 2026
fe84b63
Run the FF-M IPC conformance suite on the MCXN947 model
aidangarske Oct 26, 2026
2e2698a
Prove a fence-required MCXN947 build launches no guest
aidangarske Oct 26, 2026
69348da
Run the fence-required MCXN947 build on the board
aidangarske Oct 26, 2026
a097417
Place the MCXN947 NSPE test buffer in guest0, size the FWU probe payl…
aidangarske Nov 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions .github/workflows/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ matrix on labels, main pushes, and nightly.

`codeql.yml` runs C security queries. `coverity.yml` runs on Sundays at
00:00 UTC or by manual dispatch. Both build the host suites and secure images
for STM32H563 and MIMXRT700 with both crypto engines.
for STM32H563, MIMXRT700, and MCXN947 with both crypto engines.

Coverity scans wolfTrust runtime, ports, tests, and generated policy code.
`tools/ci-coverity-filter.py` removes dependency source units before upload
Expand All @@ -21,8 +21,8 @@ An accepted upload queues analysis; results appear after Coverity processes it.
| Tier | Trigger | Purpose |
|------|---------|---------|
| **Fast (per-PR)** | every PR; push to main | host unit suites, ISO C99, house style, bare-scope scan, Arm PSA-FF conformance, cross-compile, compiler matrix, sanitizers, valgrind, integrations, core/port split guard |
| **M33MU smoke** | every PR | per port, on both crypto engines: STM32H563 `positive gtzcneg crossdomain bothpsa confboot devcrypto`; MIMXRT700 `positive ahbscneg crossdomain bothpsa confboot devcrypto` |
| **M33MU full** | PR labels `ci:all`, `ci:h5`, `ci:rt700`; push to main; `cron: 0 8 * * *`; `workflow_dispatch` (port input) | every scenario of that port on both engines (see below) |
| **M33MU smoke** | every PR | per port, on both crypto engines: STM32H563 `positive gtzcneg crossdomain bothpsa confboot devcrypto`; MIMXRT700 `positive ahbscneg crossdomain bothpsa confboot devcrypto`; MCXN947 `positive sauneg crossdomain bothpsa confboot devcrypto` |
| **M33MU full** | PR labels `ci:all`, `ci:h5`, `ci:rt700`, `ci:mcxn947`; push to main; `cron: 0 8 * * *`; `workflow_dispatch` (port input) | every scenario of that port on both engines (see below) |

The M33MU workflow (`m33mu.yml`) is label-selected the way wolfProvider's
`pr-osp-select.yml` is: a `select` job checks the routing table
Expand All @@ -35,6 +35,7 @@ groups it picked, so a job that is not selected never appears as skipped.
| (no label) | each port's smoke tier on both engines |
| `ci:h5` | the STM32H563 full matrix (the change touched only that port) |
| `ci:rt700` | the MIMXRT700 full matrix (the change touched only that port) |
| `ci:mcxn947` | the MCXN947 full matrix (the change touched only that port) |
| `ci:all` / `ci:m33mu` | every scenario of every port (a core change) |

A label keeps applying on later pushes to the PR. Pushes to
Expand Down Expand Up @@ -74,10 +75,14 @@ test-target` also reads. The table below is a representative slice:
| `mimxrt700_devstorage_devattest_devattestqcbor_<engine>` | `devstorage devattest devattestqcbor` | PSA ITS/PS and Initial Attestation conformance (the token parses under wolfCOSE's shim and reference QCBOR) |
| `mimxrt700_devcrypto_vaultrecover_vaultrecoversec_<engine>` | `devcrypto vaultrecover vaultrecoversec` | PSA Crypto conformance on wolfPSA; a foreign vault pool self-heals in development and fails closed when SECURED |
| `mimxrt700_rollbackneg_remeasureneg_manifestneg_spbudgetneg_<engine>` | `rollbackneg remeasureneg manifestneg spbudgetneg` | shared Secure-verdict table: rollback refusal, re-measure tamper, corrupted manifest, restart budget |
| `mcxn947_positive_<engine>` | `positive` | MCXN947 chain under the MCXN947 model (internal flash, ROM flash API, EdgeLock entropy), both guests finish |
| `mcxn947_sauneg_<engine>` | `sauneg` | guest0's store into guest1's RAM refused by the SAU, contained |
| `mcxn947_<group>_<engine>` | as the MIMXRT700 groups above | the same scenario groups on the MCXN947 model; `tests/target/lib/scenario_matrix.py` is the list |

An unlabeled PR runs only each port's smoke tier; the full matrix needs a
`ci:` label. To run a single scenario locally, use `tests/target/run_m33mu_scenario.sh <key>` (the
RT700 checks use `tests/target/run_rt700_m33mu.sh <key>`); to run a port's
RT700 checks use `tests/target/run_rt700_m33mu.sh <key>`, the MCXN947 checks
`tests/target/run_mcxn947_m33mu.sh <key>`); to run a port's
full matrix on a PR, add its `ci:` label; off-PR against a branch,
`workflow_dispatch` on `m33mu.yml` with the `port` input.

Expand Down
21 changes: 20 additions & 1 deletion .github/workflows/cross-compile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ jobs:
echo "LTO flash: $no_lto_flash -> $lto_flash bytes"
- name: Verify an unimplemented isolation level stops the build
run: |
for target in stm32h563 mimxrt700; do
for target in stm32h563 mimxrt700 mcxn947; do
for level in 1 2; do
if make TARGET=$target WT_ISOLATION_LEVEL=$level \
BUILD_DIR=build-level-$level secure-image \
Expand Down Expand Up @@ -119,3 +119,22 @@ jobs:
WT_CONFORMANCE=1 secure-image TOOLPREFIX=arm-none-eabi- \
BUILD_DIR=build_rt700_conf_$engine
done
- name: Build the MCXN947 secure image (both engines, default layout)
run: |
for engine in native hsm; do
make TARGET=mcxn947 WT_ENGINE=$engine WT_ATTEST_COSE=0 \
secure-image TOOLPREFIX=arm-none-eabi- \
BUILD_DIR=build_mcxn947_$engine
# The default must leave wolfBoot's 0x400 header before the vectors.
vectors="$(arm-none-eabi-objdump -h build_mcxn947_$engine/wolftrust.elf \
| awk '$2 == ".vectors" { print $4 }')"
test "$vectors" = "10040400" || \
{ echo "MCXN947 .vectors at 0x$vectors, want 0x10040400"; exit 1; }
done
- name: Build the MCXN947 conformance secure image (both engines)
run: |
for engine in native hsm; do
make TARGET=mcxn947 WT_ENGINE=$engine WT_ATTEST_COSE=0 \
WT_CONFORMANCE=1 secure-image TOOLPREFIX=arm-none-eabi- \
BUILD_DIR=build_mcxn947_conf_$engine
done
31 changes: 17 additions & 14 deletions .github/workflows/m33mu.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
name: M33MU

on:
# Pull requests run each port's smoke tier; the ci:all, ci:h5, and ci:rt700
# labels, pushes to main, the nightly schedule (workflow_call from
# nightly.yml), and manual dispatch run a port's full matrix.
# Pull requests run each port's smoke tier; the ci:all, ci:h5, ci:rt700, and
# ci:mcxn947 labels, pushes to main, the nightly schedule (workflow_call
# from nightly.yml), and manual dispatch run a port's full matrix.
pull_request:
types: [opened, synchronize, reopened, labeled]
push:
Expand All @@ -13,7 +13,7 @@ on:
port:
description: Port whose full matrix to run
type: choice
options: [all, stm32h563, mimxrt700]
options: [all, stm32h563, mimxrt700, mcxn947]
default: all
workflow_call:

Expand Down Expand Up @@ -278,7 +278,7 @@ jobs:
fi

# Label-selected, the wolfProvider way: one select job reads the ci:* labels
# (ci:h5 or ci:rt700 for that port's full matrix when only that port
# (ci:h5, ci:rt700 or ci:mcxn947 for that port's full matrix when only that port
# changed, ci:all or ci:m33mu for everything after a core change, no label
# for each port's smoke tier), the event, and the dispatch input, then one
# matrix job runs exactly those scenario groups, so nothing shows up skipped.
Expand Down Expand Up @@ -324,40 +324,43 @@ jobs:
git config --global --add safe.directory "$GITHUB_WORKSPACE"
git config --global url."https://github.com/".insteadOf git@github.com:

# The RT700 wolfBoot first stage builds against the MCUXpresso SDK, staged
# the way wolfBoot's own imxrt700 emulator workflow stages it.
# The RT700 and MCXN947 wolfBoot first stages build against the
# MCUXpresso SDK, staged the way wolfBoot's own imxrt700 emulator
# workflow stages it, one board per port.
- uses: actions/checkout@v4
if: matrix.port == 'mimxrt700'
if: matrix.port == 'mimxrt700' || matrix.port == 'mcxn947'
with:
repository: nxp-mcuxpresso/CMSIS_5
ref: f9cf5df6d51a95f0146930d75af3d71977cf795a
path: CMSIS_5

- name: Cache MCUXpresso SDK
if: matrix.port == 'mimxrt700'
if: matrix.port == 'mimxrt700' || matrix.port == 'mcxn947'
id: cache-mcuxpresso
uses: actions/cache@v4
with:
path: |
mcuxpresso-sdk
venv
key: mcuxpresso-sdk-mimxrt700evk-${{ hashFiles('.github/workflows/m33mu.yml') }}
key: mcuxpresso-sdk-${{ matrix.port == 'mimxrt700' && 'mimxrt700evk' || 'frdmmcxn947' }}-${{ hashFiles('.github/workflows/m33mu.yml') }}

- name: Setup MCUXpresso SDK
if: matrix.port == 'mimxrt700' && steps.cache-mcuxpresso.outputs.cache-hit != 'true'
if: (matrix.port == 'mimxrt700' || matrix.port == 'mcxn947') && steps.cache-mcuxpresso.outputs.cache-hit != 'true'
env:
SDK_BOARD: ${{ matrix.port == 'mimxrt700' && 'mimxrt700evk' || 'frdmmcxn947' }}
run: |
python3 -m venv venv
. venv/bin/activate
pip install west==1.5.0
west init -m https://github.com/nxp-mcuxpresso/mcuxsdk-manifests.git \
--mr v26.06.00-LTS mcuxpresso-sdk
cd mcuxpresso-sdk
sed -i '/se_hostlib\|emwin/d' manifests/boards/mimxrt700evk.yml
west update_board --set board mimxrt700evk
sed -i '/se_hostlib\|emwin/d' "manifests/boards/$SDK_BOARD.yml"
west update_board --set board "$SDK_BOARD"

- name: Run target scenarios
env:
MCUXSDK: ${{ matrix.port == 'mimxrt700' && '1' || '' }}
MCUXSDK: ${{ (matrix.port == 'mimxrt700' || matrix.port == 'mcxn947') && '1' || '' }}
MCUXPRESSO: ${{ github.workspace }}/mcuxpresso-sdk/mcuxsdk
MCUXPRESSO_CMSIS: ${{ github.workspace }}/CMSIS_5/CMSIS
run: tests/target/run_suite.sh ${{ matrix.arm }} ${{ matrix.key }}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
tests/firmware/stm32h563/build/
tests/firmware/stm32h563-vnet/build/
tests/firmware/mimxrt700-baremetal/build/
tests/firmware/mcxn947-baremetal/build/
tests/firmware/stm32h563-vnet/stm32h563_OTP.bin
*.o
/wolftrust
Expand Down
9 changes: 7 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ test:
@python3 tests/scripts/test_m33mu_console.py
@$(MAKE) --no-print-directory -C tests/host test
@$(MAKE) --no-print-directory test-provisioning
@tests/target/test_mcxn947_suite_evidence.sh

# Production lock gates of both provisioning backends, against stub tools.
test-provisioning:
Expand Down Expand Up @@ -72,8 +73,8 @@ c99-check:

# FF-M target scenarios for one port under the M33MU emulator, separate from
# `make test` (host-only). TARGET picks the port (stm32h563 by default,
# mimxrt700 for the RT700 chain, whose runner builds its own pinned emulator
# and wolfBoot first stage); WT_TIER=smoke (default) runs the per-PR set,
# mimxrt700 or mcxn947 for the NXP chains, whose runners build their own
# pinned emulator and wolfBoot first stage); WT_TIER=smoke (default) runs the per-PR set,
# WT_TIER=full every scenario, both from tests/target/lib/scenario_matrix.py.
# The STM32H563 path auto-detects an M33MU (or WT_TARGET_SCENARIOS=1) and skips
# explicitly otherwise so it never silently passes. Runs inside the
Expand All @@ -84,6 +85,8 @@ WT_SCENARIOS = $(shell python3 tests/target/lib/scenario_matrix.py \
test-target:
ifeq ($(TARGET),mimxrt700)
@tests/target/run_suite.sh rt700-m33mu $(WT_SCENARIOS)
else ifeq ($(TARGET),mcxn947)
@tests/target/run_suite.sh mcxn947-m33mu $(WT_SCENARIOS)
else
@if ! tests/target/detect_m33mu.sh >/dev/null 2>&1; then \
echo "SKIP: FF-M target scenarios ($$(tests/target/detect_m33mu.sh 2>&1))"; \
Expand All @@ -99,6 +102,8 @@ endif
test-hardware:
ifeq ($(TARGET),mimxrt700)
@tests/target/run_rt700_suite.sh
else ifeq ($(TARGET),mcxn947)
@tests/target/run_mcxn947_suite.sh
else
@tests/target/run_h5_suite.sh
endif
Expand Down
11 changes: 7 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,14 @@ current reference port, not a requirement imposed on every intended port.

## Ports

wolfTrust currently supports two ports; each guide covers the board, the
wolfTrust currently supports three ports; each guide covers the board, the
first-stage loader contract, and the runners:

- STM32H563 (NUCLEO-H563ZI): [STM32H5 Guide](docs/STM32H5-Guide.md)
- NXP MIMXRT700 (MIMXRT700-EVK): [MIMXRT700 Guide](docs/MIMXRT700-Guide.md)
- NXP MCXN947 (FRDM-MCXN947): [MCXN947 Guide](docs/MCXN947-Guide.md)

Both build with `TARGET=<port>` (`stm32h563` is the default) and run the
All build with `TARGET=<port>` (`stm32h563` is the default) and run the
same scenario set under the M33MU emulator with `make test-target
TARGET=<port>`.

Expand Down Expand Up @@ -137,14 +138,16 @@ Common validation entry points:
make test
make test-target
make test-target TARGET=mimxrt700
make test-target TARGET=mcxn947
make test-conformance
WT_H5_DOCKER_IMAGE=ghcr.io/wolfssl/wolfboot-ci-m33mu:v1.15 make test-hardware
make test-hardware TARGET=mcxn947
```

`make test-target` runs the port's smoke tier under M33MU (`WT_TIER=full` for
every scenario): the STM32H563 default skips explicitly when M33MU is
unavailable, and `TARGET=mimxrt700` builds its pinned emulator and wolfBoot
first stage itself.
unavailable, and `TARGET=mimxrt700` or `TARGET=mcxn947` builds its pinned
emulator and wolfBoot first stage itself.
`make test-conformance` instead runs its 20-test host subset and warns that it
is not full emulator or hardware evidence. `make test-hardware` skips when
board detection fails; on hosts without `lsusb`, a missing ST-Link can instead
Expand Down
1 change: 1 addition & 0 deletions docs/Home.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,3 +118,4 @@ port's five CMSE gateway veneers.
| [Project Structure](Project-Structure.md) | Repository layout |
| [STM32H5 Guide](STM32H5-Guide.md) | STM32H563 provisioning, flashing, WRP, and recovery safety |
| [MIMXRT700 Guide](MIMXRT700-Guide.md) | MIMXRT700 provisioning, flashing, XSPI guest fence, and recovery safety |
| [MCXN947 Guide](MCXN947-Guide.md) | MCXN947 internal flash, ELS entropy, emulator runner, life cycle rehearsal, and open items |
Loading
Loading