Skip to content

Hardware crypto offload and secure key storage for PolarFire SoC MPFS250TS - #916

Draft
dgarske wants to merge 8 commits into
wolfSSL:masterfrom
dgarske:mpfs250_hss_replace
Draft

dgarske wants to merge 8 commits into
wolfSSL:masterfrom
dgarske:mpfs250_hss_replace

Conversation

@dgarske

@dgarske dgarske commented Sep 29, 2026 •

Copy link
Copy Markdown
Member

Hardware crypto offload and secure key storage for the PolarFire SoC MPFS250TS, plus three fixes to the existing M-mode target. The "S" grade part has a TeraFire F5200 User Cryptoprocessor and factory-provisioned SRAM-PUF, neither of which wolfBoot used before.

What it adds

  • hal/mpfs250_athena.c, hal/mpfs250.c - SHA-384 and AES-256-CTR offload to the Athena F5200 through wolfCrypt crypto callbacks, behind MPFS_ATHENA=1. The Microchip CAL library is referenced out-of-tree by path and never vendored; its licence is separate from the MIT HSS repository.
  • src/snvm_keystore.c, include/snvm_keystore.h - trust anchor served from secure NVM instead of being compiled into the image, spanning consecutive sNVM modules.
  • src/snvm_kek.c, include/snvm_kek.h - PUF-derived key-encryption key and RFC 3394 AES key-wrap.
  • src/encrypt_key_snvm_puf.c - disk image-encryption key wrapped by the PUF KEK, supplied through CUSTOM_ENCRYPT_KEY.
  • tools/unit-tests/unit-snvm-keystore.c, tools/unit-tests/unit-snvm-kek.c - host tests for the page-spanning offset arithmetic and header bounds, and for the KEK derivation, key-wrap round trip and provider failure paths against mocked PUF and sNVM services.

Every knob that writes sNVM requires a second confirming macro, WOLFBOOT_SNVM_WRITE_APPROVED: a brownout mid-write can leave the page permanently read-only, and only pages the Libero design leaves writable can be used at all.

Fixes to the existing target

  • src/boot_riscv_start.S - the scratchpad pin loop set the way mask for the .text copy only, so .data, .bss, the heap and the E51 stack allocated in evictable cache ways whose writeback is discarded. It now walks one way at a time, as HSS config_l2_cache() does.
  • hal/mpfs250_ddr.c - the controller register table was written in address order, programming the PHY training and MTC blocks before CTRLR_SOFT_RESET_N releases the controller; reordered to match HSS init_ddrc(). Separately, some trainings leave one lane with a one-tap DQ/DQS window, which HSS rejects at DQ_DQS_NUM_TAPS but wolfBoot accepted; a controller re-init tends to repeat it and a full MSS reset does not, so the driver now resets and retrains, bounded by a counter in the E51 DTIM that survives the reset. Debug builds dump the post-training PHY state in the column order of the Microchip DDR demo.
  • config/examples/polarfire_mpfs250.config - BOOT_PART_A is a 0-based GPT index, and index 1 is the ef02 partition HSS searches for its own payload, so the shipped value could not boot the standard card layout.
  • arch.mk - the U54 target builds soft-float lp64; the CAL archive is rv64imac soft-float and will not link against lp64d.
  • src/riscv_sbi.c - the shim advertised SBI v0.2, so Linux never registered the SRST reset handler and reboot spun in machine_restart; the handler also printed to a UART the OS owned by then. Console writes could hold a hart in M-mode long enough for fence IPIs to time out, which failed remote TLB flushes during shutdown. Now v0.3, silent reset, bounded console writes, fence wait that outlasts a console write, and a hart waiting for its remote-fence acknowledgements services the fences posted to it meanwhile, so two harts fencing each other no longer deadlock (seen as a soft lockup under module load/unload).
  • config/examples/polarfire_mpfs250_m_mldsa.config - the standalone M-mode target with ML-DSA-87 and SHA-384, built in CI.

Hardware / test status

Validated on an MPFS250TS-1FCG1152I Video Kit.

  • S-mode wolfBoot boots from SD under HSS and verifies an ECC384/SHA384 signed image. M-mode boots from eNVM, loads a Linux FIT from SD, hands off to S-mode and reaches the login prompt; reboot from the shell comes back through wolfBoot. ML-DSA-87 verifies on the E51. The trust anchor served from sNVM verifies a signed boot.
  • Athena offload confirmed with known-answer tests and callback-entry counters, since a correct digest alone does not prove the hardware ran - wolfCrypt falls back to software silently if registration fails. The control register reports MSS ownership and the stall countermeasure latched.
  • DDR: cold power cycles come up with every lane at 10-12 taps and dq_dqs_err_done at the 0x8 HSS requires; the post-training PHY state matches the Microchip DDR demo capture on every field except the eye width, which is narrower but well above the HSS minimum. Disk loads still go through the PDMA staging path; a plain CPU copy into DDR reads back wrong in the SD block path and that is not yet understood.
  • Encrypted boot end to end on both targets: the AES key is read from sNVM and unwrapped with the PUF-derived KEK, which is identical across cold power cycles, and the image is decrypted, verified and booted. Boot time on the standalone path is dominated by the SD load and the staged copies that the coherence workaround requires; the measured phases are in docs/Targets.md.

Scope

TeraFire has no lattice support, so ML-DSA verification stays in software on this silicon. The stock card layout has one usable boot slot, so A/B failover needs a second boot partition added. IAP reflash is designed but stubbed.

@dgarske dgarske self-assigned this Sep 29, 2026
Copilot AI balanced review requested due to automatic review settings September 29, 2026 23:20

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.

Copilot review overview

🟡 Changes recommended

Default sNVM ranges overlap, some option combinations fail to build, and diagnostics expose PUF-derived secret bytes.

Review effort: Balanced
Findings: 4 High severity · 3 Medium severity · 5 Low severity

Open (12)
What changed in this PR

Adds PolarFire SoC hardware crypto acceleration, PUF-backed key protection, and sNVM trust-anchor storage, alongside M-mode boot fixes.

Changes:

  • Adds Athena SHA-384/AES-CTR offload and System Controller services.
  • Adds sNVM keystore and PUF-wrapped encryption-key support.
  • Fixes scratchpad initialization, DDR ordering, partition selection, and RISC-V ABI settings.
File Description
Makefile Wires new sNVM objects and linker parameters.
arch.mk Updates MPFS DDR validation and ABI flags.
options.mk Adds sNVM, KEK, and Athena options.
include/​user_settings.h Enables AES for KEK support.
include/​snvm_keystore.h Defines the sNVM keystore layout.
include/​snvm_kek.h Defines KEK and wrapped-key APIs.
hal/​mpfs250.h Adds mailbox, sNVM, PUF, and Athena interfaces.
hal/​mpfs250.c Implements services and crypto callbacks.
hal/​mpfs250_athena.c Adapts the external CAL library.
hal/​mpfs250_ddr.c Reorders DDR controller programming.
hal/​mpfs250-m.ld Expands configurable scratchpad and stack sizing.
src/​boot_riscv_start.S Pins all scratchpad cache ways.
src/​snvm_keystore.c Implements the sNVM trust-anchor backend.
src/​snvm_kek.c Implements PUF KEK derivation and key wrap.
src/​encrypt_key_snvm_puf.c Supplies wrapped disk-encryption keys.
src/​update_disk.c Adds staged DDR decryption.
src/​libwolfboot.c Supports custom keys without partitions.
tools/​unit-tests/​unit-snvm-keystore.c Tests keystore bounds and paging.
tools/​unit-tests/​Makefile Registers the new unit test.
config/​examples/​polarfire_mpfs250.config Corrects stock GPT slot selection.
config/​examples/​polarfire_mpfs250_m.config Expands M-mode scratchpad and stack.
docs/​Targets.md Links hardware-root-of-trust documentation.
docs/​polarfire_snvm_puf.md Documents provisioning and validation.
docs/​keystore.md Documents the sNVM backend.
docs/​encrypted_partitions.md Documents PUF-wrapped custom keys.

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

Comment thread hal/mpfs250.c Outdated
Comment thread include/snvm_kek.h
Comment thread options.mk Outdated
Comment thread src/snvm_kek.c Outdated
Comment thread src/snvm_kek.c Outdated
Comment thread docs/polarfire_snvm_puf.md Outdated
Comment thread docs/polarfire_snvm_puf.md Outdated
Comment thread hal/mpfs250.c Outdated
Comment thread include/snvm_kek.h Outdated
Comment thread include/snvm_kek.h Outdated
@dgarske
dgarske force-pushed the mpfs250_hss_replace branch 4 times, most recently from de33a73 to 76f5e5f Compare September 30, 2026 21:19
@dgarske
dgarske requested a balanced review from Copilot September 30, 2026 23:12

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Comment thread include/snvm_kek.h
Comment thread include/snvm_keystore.h Outdated
Comment thread options.mk
Comment thread options.mk
Comment thread src/encrypt_key_snvm_puf.c Outdated
Comment thread include/snvm_keystore.h Outdated

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.

Comment thread docs/polarfire_snvm_puf.md Outdated
| `SNVM_KEK_SELFTEST` | KEK determinism and wrap/unwrap round trip, in RAM only |
| `SNVM_KEK_SELFTEST_WRITE` | Adds the sNVM store/read-back to the self-test (writes a page) |
| `SNVM_ENCKEY_PROVISION` | Add the one-time PUF-wrapped encryption-key writer |
| `SNVM_KEYSTORE_MODULE` / `SNVM_ENCKEY_MODULE` | sNVM module numbers (default 200 / 210; the key module must lie outside the keystore range) |
Comment thread options.mk Outdated
Comment on lines +120 to +132
ifeq ($(SNVM_KEK_SELFTEST),1)
CFLAGS+=-D"SNVM_KEK_SELFTEST"
endif
# Adds the sNVM store/read-back to the selftest above. Separate knob because
# it programs a page rather than just exercising the KEK in RAM.
ifeq ($(SNVM_KEK_SELFTEST_WRITE),1)
ifneq ($(WOLFBOOT_SNVM_WRITE_APPROVED),1)
$(error SNVM_KEK_SELFTEST_WRITE writes sNVM: irreversible, and a \
brownout mid-write can lock the page read-only. Re-run with \
WOLFBOOT_SNVM_WRITE_APPROVED=1 to confirm.)
endif
CFLAGS+=-D"SNVM_KEK_SELFTEST" -D"SNVM_KEK_SELFTEST_WRITE"
endif
Comment thread options.mk
Comment on lines +147 to +149
ifeq ($(SNVM_ENCKEY_INSECURE_TEST_KEY),1)
CFLAGS+=-D"SNVM_ENCKEY_INSECURE_TEST_KEY"
endif
Comment thread src/encrypt_key_snvm_puf.c Outdated
{
(void)key;
(void)nonce;
return 0;
Comment thread hal/mpfs250.c Outdated
#ifdef SNVM_KEYSTORE_PROVISION
/* One-time: write the compiled-in trust anchor into sNVM so a subsequent
* SNVM_KEYSTORE build serves its keys from sNVM. */
(void)snvm_keystore_provision();
Comment thread hal/mpfs250.c Outdated
Comment on lines +1373 to +1376
ret = mpfs_nonce(n1);
if (ret == 0) {
ret = mpfs_nonce(n2);
}
Comment thread options.mk Outdated
Comment on lines +1734 to +1735
ifeq ($(MPFS_ATHENA_AES_KAT),1)
CFLAGS += -DMPFS_ATHENA_AES_KAT
@dgarske
dgarske force-pushed the mpfs250_hss_replace branch 3 times, most recently from 1157ec6 to c1156a4 Compare October 2, 2026 22:58
@dgarske
dgarske force-pushed the mpfs250_hss_replace branch from c1156a4 to 9961f39 Compare October 3, 2026 01:35
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.

2 participants