Commit Graph

3685 Commits (b8254ba33f2ff6558a482a626844e96f5714b3cc)

Author SHA1 Message Date
Aidan Garske b8254ba33f Document the STM32H5 fwTPM secure RAM budget and stack reservation 2026-09-17 13:06:11 +02:00
Aidan Garske 670280e5b3 Assert the STM32H5 secure link leaves room for the stack 2026-09-17 13:06:11 +02:00
Aidan Garske 8b3e843495 Shrink unused fwTPM NV slots so the STM32H5 secure stack fits 2026-09-17 13:06:11 +02:00
Aidan Garske 16637119f8 Update wolfTPM submodule to v4.2.0 2026-09-17 13:06:11 +02:00
David Garske a8c8c19fe8 Add LS1028A eSDHC SD card disk boot support 2026-09-17 12:33:19 +02:00
David Garske 8eafe1ef76
Merge pull request #890 from bigbrett/tc4-wolfboot
AURIX TC4xx support
2026-09-14 14:22:21 -07:00
Brett Nicholas 7c88ae7413 add TC4 PVER retry 2026-09-14 10:55:07 -06:00
Brett Nicholas ade42b51fa add TC4 EVER retry 2026-09-14 10:40:31 -06:00
David Garske 0ca05cf9b4 Add m2354 secure and non-secure emulator tests 2026-09-14 18:08:40 +02:00
David Garske b0fe251747 Add Nuvoton NuMaker M2354 Cortex-M23 target with TrustZone 2026-09-14 18:08:40 +02:00
Marco Oliverio 1b99727d4c pic32cz: fix: use the right IMAGE_HEADER_SIZE value
otherwise the VTOR will be underaligned
2026-09-14 17:53:04 +02:00
Brett Nicholas 6d652d444f Support for AURIX TC4xx host and CSRM cores 2026-09-12 09:21:38 -06:00
David Garske bafa907e9a
Merge pull request #873 from danielinux/pkcs11-store-batch-commit
pkcs11 store: Improve Store performance through batch sector commits to Store_Close
2026-09-10 16:14:04 -07:00
David Garske 871ab86dc5
Merge pull request #886 from bigbrett/aurix-makefile-reorg
AURIX makefile housekeeping
2026-09-10 16:13:56 -07:00
Daniele Lacamera ba544022e2 pkcs11 store: cover torn flash ops and require a present, truncated header
The mock abandoned a faulting erase/program whole, so half-written sectors
went untested; it can now tear one part-way and the sweep runs every crash
point at 1/4, 1/2 and 3/4. An empty read must also leave the node in place
with size 8, so a lost or torn header no longer passes as an empty rewrite.
2026-09-10 21:39:18 +02:00
Daniele Lacamera 7919445c62 pkcs11 store: pin the no-fault control in the power-fail test
The crash == ops iteration injects nothing, so it must read back new_p; the
empty/absent branch was letting a silently lost complete rewrite pass. Also
assert the uninjected baseline write lands before measuring against it.
2026-09-10 21:17:52 +02:00
Daniele Lacamera b2d8200dd2 pkcs11 store: restore both mock flash views before each injected power fail
Under MOCK_STALE_CACHE the shadow is the flash array and vault_base only the
CPU's view, so restoring vault_base alone let the power cycle copy the last
iteration's result back: no crash case started from the old generation.
2026-09-10 20:57:53 +02:00
Daniele Lacamera 3d5bebeefe pkcs11 store: tighten power-fail assert, rebase F4 footprint limits
vault_obj_read() now separates "object absent" from a failed read, so the
power-fail test rejects a corrupted vault instead of accepting any negative.
hal_cache_invalidate() shrank 120 -> 44 bytes; the 48 it still costs every
STM32F407 build is folded into the test-size-all limits.
2026-09-10 19:23:57 +02:00
Daniele Lacamera 9b06b907f8 hal: always define hal_cache_invalidate(), implement it on F4 and G4
The weak no-op sat inside NVM_FLASH_WRITEONCE, so pkcs11_store.c failed to
link on the nrf5340/nrf54l TrustZone configs. STM32F4 and STM32G4 enable the
flash instruction/data caches and never reset them, so give them a real one.
2026-09-10 18:42:54 +02:00
Brett Nicholas 678781db39 AURIX tc3 ARCH/TARGET refactor anticipating TC4xx 2026-09-10 10:19:08 -06:00
Daniele Lacamera 42e6dba558 pkcs11 store: invalidate the flash read cache after every commit
The store commits sectors with hal_flash_erase()/hal_flash_write() and
then reads them back through the memory map - sector_ptr(),
cache_get_sector()'s refill, and the raw magic reads in check_vault().
On a part that caches flash reads (STM32 ICACHE) those reads can return
pre-erase bytes. check_vault() is the worst case: a stale magic there
does not merely read wrong, it triggers restore_backup() or a full vault
re-initialisation, losing the token.
2026-09-10 10:45:55 +02:00
Daniele Lacamera 1d3b576f03 pkcs11 store: pin the Open-time durability rule with a power-fail test
Adds power-fail injection to the flash mock and a test that cuts power at
every flash operation of a rewrite window, asserting the object always reads
back as the whole old payload, the whole new payload, or empty. Fails at
op 3 without this fix, passes with it.

unit-pkcs11_store 10/10; full unit-tests suite green.
2026-09-10 09:40:17 +02:00
Daniele Lacamera b9ef442faf pkcs11 store: harden sector cache (eviction, release scrub, open durability)
Three fixes from the 2026-08-31 Fenrir PR review round:

1. cache_get_sector() LRU eviction could pick the header sector (offset 0)
   as the victim, committing it to flash while the batch's payload sectors
   were still only in RAM - a mixed pre/post-batch state that breaks the
   header-last atomic commit point cache_flush_all() relies on. The header
   is now exempt from victim selection; if it is the only cached sector,
   flush the whole batch instead (header-last is then trivial).

2. cache_flush_all() and LRU eviction released a slot by clearing .sector
   without wiping the buffer, so private-key bytes staged by Store_Write
   lingered in secure-world SRAM until the slot was next reused. The single
   staging buffer this cache replaced self-cleaned (the header sector
   overwrote it on every size update); per-sector slots do not. A new
   cache_release() wc_ForceZero()s the buffer before freeing the slot.

3. Store_Open in write mode set the size to 8 (truncation) in the cache
   only; with batched commits the payload sectors are flushed before the
   header, so a power loss during the erase/rewrite left the old size over
   a partly erased payload. The truncated header is now committed to flash
   before erase_object_payload(), so the empty state is the crash fallback.

Addresses PR #873 review comments (wolfSSL-Fenrir-bot,
src/pkcs11_store.c:301, :333, :670, 2026-08-31).

Verification: tools/unit-tests unit-pkcs11_store 9/9 pass (incl.
test_concurrent_reader_sees_pending_writes,
test_shorter_overwrite_erases_residual_key_material,
test_interleaved_write_windows_both_persist).
2026-09-10 09:40:17 +02:00
Daniele Lacamera d6a5570f69 pkcs11 store: exercise the cached read path in the concurrent test
test_concurrent_reader_sees_pending_writes only ever read from flash:
the reader's Store_Open calls check_vault(), which flushes the sector
cache, so the sector_ptr() read path in Store_Read was never exercised
and the test passed identically against the pre-PR memcpy.

Write more on the still-open writer after the reader is open. That
batch lands only in the sector cache, so the reader can only see it
through the cached read path and the live header size; a flash-only or
snapshot-size read returns EOF here. Verified: the new assertion fails
against the pre-fix store (ret == 0) and passes with the live-size fix.

Addresses PR #873 review comments (wolfSSL-Fenrir-bot,
tools/unit-tests/unit-pkcs11_store.c:587, both near-duplicate findings).
2026-09-10 09:40:17 +02:00
Daniele Lacamera 241004367b pkcs11 store: read object size live from the cached header
Store_Read and Store_Write used handle->size, a snapshot taken at
Store_Open. The payload path reads through the sector cache, so once
another window's batch (e.g. a write-open truncation) sat pending in
the cache, the window saw live erased data under a stale size and
returned 0xFF bytes past the true end instead of EOF. Pre-PR the size
was read live from the flash header on every call, so the PR regressed
that case.

Read the size from the same (possibly cached) header sector the payload
comes from, via store_live_size(), so size and data share one source of
truth. Drop the now-dead handle->size snapshot; update_store_size()
only writes the cached header node.

Addresses PR #873 review comment (wolfSSL-Fenrir-bot,
src/pkcs11_store.c:711).
2026-09-10 09:40:17 +02:00
Daniele Lacamera b5c9c366f5 pkcs11 store: commit pending sectors in check_vault, read via cache
check_vault() dropped the shared sector cache on every vault
validation, silently losing the pending writes of any still-open
window when another handle was opened or an object removed
(MAX_OPEN_STORES allows 16). Flush instead - the atomic header-last
commit - so an in-flight batch only gets an earlier commit point;
its data is never discarded.

wolfPKCS11_Store_Read() now reads through sector_ptr() like every
other read in the file, so a sector still in the cache can never be
read stale against a live size.

Add unit tests covering the interleaved-window data loss and a
concurrent reader observing a pending write; both fail without the
check_vault fix.
2026-09-10 09:40:12 +02:00
Daniele Lacamera febf29ad61 pkcs11 store: batch sector commits to Store_Close
Every wolfPKCS11 field write flushed the payload sector and the header
sector to flash (2 erases + 2 programs of a full sector each), and the
token store re-serializes all objects per C_CreateObject/C_DestroyObject,
so those calls cost hundreds of sector erases and tens of seconds on
flash with slow erase times.

Cache modified sectors in RAM and commit them together when the store
window closes:

- sector cache sized to the worst-case span of one object plus the
  header sector (WOLFBOOT_PKCS11_STORE_CACHE_SECTORS), LRU eviction
  when exceeded
- header sector commits last, so a committed header is the atomic
  commit point of the batch: power failure during a flush leaves the
  flash in either the pre-batch or the post-batch state
- per-commit backup sector write preserved, keeping recovery of the
  sector in flight at failure time
- delete_object commits on return (durability contract, unit-tested)
- nodes table, bitmap, payload ids and the live object size
  (handle->size) are read from the cache when the sector is dirty

Measured on an STM32H5 with 8KB sectors, wolfPKCS11 in the secure
world: C_CreateObject 1.5s -> 0.15s, C_DestroyObject 1.3s -> 0.12s,
456 -> 40 sector erases per create, and the count no longer scales
with the number of objects in the token.

PKCS11_STORE_STATS (off by default) adds flash-activity counters and a
test-app bench to quantify store traffic: make PKCS11_STORE_STATS=1.
2026-09-10 09:40:02 +02:00
David Garske a2639e88f8 versal: report EL2 exceptions, fix FIT ramdisk fixup and the EL2->EL1 cache handoff 2026-09-10 08:17:21 +02:00
David Garske 24c23e767b Add T1040 eSDHC SD card disk boot support, first big-endian disk-boot target 2026-09-10 08:15:48 +02:00
David Garske ced2b1059c
Merge pull request #883 from danielinux/fenrir-fixes-2026-09-07
Fenrir fixes 2026 09 07
2026-09-08 16:21:42 -07:00
Daniele Lacamera 609294789f Address Fenrir PR review: make program-window observable in l5/u5 write tests
The new unaligned tests passed against the pre-fix HAL (identical
final bytes), so the alignment fix had no regression coverage. Mock
hal_flash_wait_complete now diffs the flash per program window and
asserts the changed bytes fit in one aligned unit; the 20-byte
unaligned test goes red on the pre-fix HAL (l5: bytes 4-11 across two
8-byte units, u5: bytes 4-19 across two 16-byte units).
2026-09-07 19:19:22 +02:00
Daniele Lacamera fc688f18c1 Address PR review: SWS macros + test decl style
hal/stm32wb.c: dedicated RCC_CFGR_SWS_{MSI,MASK} macros for the
clock-switch confirmation wait; SW/SWS encodings verified identical
in RM0434 6.4.3 and the STM32WB55 SVD.
unit-stm32u5-write.c: START_TEST brace on the next line, matching
the file and the unit-suite convention.
2026-09-07 17:43:22 +02:00
Daniele Lacamera 4751f89967 Merge branch 'wb-campaign-a4' into fenrir-fixes-2026-09-07 2026-09-07 16:38:42 +02:00
Daniele Lacamera 6f62fa0d4f Merge branch 'wb-campaign-a3' into fenrir-fixes-2026-09-07 2026-09-07 16:38:42 +02:00
Daniele Lacamera 33e5bed910 Merge branch 'wb-campaign-a2' into fenrir-fixes-2026-09-07 2026-09-07 16:38:42 +02:00
Daniele Lacamera cfd44bc5c1 F-12878: STM32U5: program the 16-byte unit through an aligned pointer
An unaligned starting address split the four word stores across two
16-byte program units, leaving partial quad-words that set
FLASH_SR_WDW and hang the wait for completion. Align the destination
down to the unit, read-modify-write the whole unit, and store through
the aligned pointer. The unit test gains unaligned-start cases.
2026-09-07 16:31:07 +02:00
Daniele Lacamera ca06782f42 F-12877: STM32L5: program the 8-byte unit through an aligned pointer
hal_flash_write() stored both words of the 64-bit program unit
relative to the caller's address, so a write starting inside a unit
split the two stores across two units: the flash has no 32-bit
program mode, so nothing is programmed and the second store faults
on alignment. Align the destination down to the unit, take the bytes
outside the requested span from the unit itself, and store through
the aligned pointer, as hal/stm32h5.c does. The TrustZone claim is
unchanged: it is page-granular and already covers every non-secure
byte the aligned program touches.

Extend unit-stm32l5-write with unaligned-start cases. The host data
model cannot observe the program-unit split (pre-fix the bytes land
identically), so these pin the fixed layout: bytes before the
request preserved, nothing past it touched.
2026-09-07 16:31:07 +02:00
Daniele Lacamera 8e86847c1f F-12870: STM32C0: program flash writes through absolute addresses
The HAL contract is absolute (0x08000000-based) addresses, as the
erase path and every NVM caller use, but the double-word fast path
added the flash base on top and targeted an address space past the
flash. The read-modify-write path located its unit from the request
base indexed by i/4, landing in the wrong 8-byte unit once a request
started inside one. Both paths now program the 8-byte unit at
(address + i), and the now-dead FLASHMEM_ADDRESS_SPACE define is
gone.

Add unit-stm32c0-write: runs the extracted hal_flash_write() against
a host register/flash model with a second mapping standing in for
the wrong address space (4/5 checks fail pre-fix, 5/5 pass post-fix).
2026-09-07 16:05:51 +02:00
Daniele Lacamera 376f9e124f F-12920: zero firmware-DTB initrd pointers in hal_get_boot_dts
The CM4 firmware DTB is unverified (unsigned FAT partition) and this
path never attaches an authenticated ramdisk, so a non-zero
linux,initrd-start/end in it would direct the signed kernel to an
unauthenticated initramfs in RAM. Zero both properties on the
relocated DTB (fail closed on fixup error) and update the SECURITY
comment to state the new behavior.
2026-09-07 15:49:31 +02:00
Daniele Lacamera 49c1fff186 F-12876: riscv_sbi: report remote-fence timeout as SBI error
sbi_wait_ipi_done() returned void, so a target hart that never
completed its fence within the bounded wait was invisible and both
the standard and legacy remote-fence interfaces reported success
while the caller kept relying on a fence that may not have run.
Return SBI_ERR_FAILED when any target does not complete within the
bound, and propagate it through both SBI interfaces (standard
RFENCE via err, legacy v0.1 remote fence via a0).
2026-09-07 14:54:57 +02:00
Daniele Lacamera 9475169bdc F-12875: stm32f7 fix non-dual-bank sector 11 start address
Sector 11 was at 0x818C000, inside sector 10's 256 KB range
(0x8180000-0x81C0000), so hal_flash_erase mapped the upper part of
sector 10 to sector 11 and erased the wrong sector. Sector 11 is
0x81C0000, contiguous after sector 10 and ending at FLASH_TOP.
2026-09-07 14:43:15 +02:00
Daniele Lacamera 22356e6d02 F-12874: stm32wb switch SYSCLK to MSI and confirm SWS before disabling PLL
The MSIRDY wait read RCC_CFGR (bit 1 is SW status) instead of RCC_CR,
so it never gated, and the MSI selection was cleared only in a local
variable, never written back to RCC_CFGR. The PLL was disabled while
still the SYSCLK source, dropping the system clock. Now: wait MSIRDY,
commit the MSI selection, wait for SWS to confirm, then turn off PLL.
2026-09-07 14:43:15 +02:00
Daniele Lacamera 394f160a83 F-12873: update_disk: FSP low-mem check reuses validated slot_max
The final image-size check re-derived the low-memory limit with a
uint32 subtraction and no ordering check, so an inverted tolum
wrapped into a near-2^32 limit and accepted any image. Compare the
tolum/load_address ordering in 32-bit (low-memory) form when
computing slot_max, and reuse that validated value in the check.
Add a unit test for the inverted-tolum case (fails closed, both
slots rejected).
2026-09-07 14:40:35 +02:00
Daniele Lacamera 194322ec73 F-12921: erase keyvault payload on object removal
The PKCS#11 and PSA store Remove paths invalidated the metadata and
freed the bitmap slot but left the payload in flash, so removed keys
stayed recoverable by a physical reader. Both Remove paths now call
erase_object_payload() before invalidating the metadata; the existing
sector read-modify-write preserves neighboring slots. Raw-flash
deletion tests added to both unit suites.
2026-09-07 14:36:29 +02:00
David Garske 173bb298e9
Merge pull request #882 from danielinux/fenrir-fixes-2026-09-04 2026-09-04 21:10:45 -07:00
Daniele Lacamera c2916395a9 x86_64_efi: early-return after remaining panic() sites under UNIT_TEST
do_boot() already returned after its panic() calls, but GetVolume() and
efi_main() did not: under UNIT_TEST panic() returns, so GetVolume() hit a
NULL deref / uninitialized return and efi_main() ran wolfBoot_start().
Return NULL / EFI_LOAD_ERROR at each site (unreachable on target).
2026-09-04 21:08:36 +02:00
Daniele Lacamera 2dbb8aea01 image: cast ELF scatter log fields to unsigned long
offset/filesz are uint64_t now; cast them for the %08lx/%lu
conversions so the varargs read matches on 32-bit targets, matching
the check function and the rejection messages above.
2026-09-04 20:02:10 +02:00
Daniele Lacamera faaad372cc Address minor PR 882 review nits
Cap the library fw_size clamp at UINT32_MAX (a > 4 GiB file would
otherwise truncate to a small value), say 'restore' not 'store' in the
scatter-restore error message, and print stdout as well as stderr in
the compile-check scripts on failure.
2026-09-04 16:39:26 +02:00
Daniele Lacamera b0209d0bf6 image: use uint64_t for ELF scatter program-header locals
paddr/filesz/offset were unsigned long, which is 32-bit on the
ELF-scatter targets (aurix-tc375, sim32). ELF64 program headers
truncate before the segment guards run, so filesz > UINT32_MAX is
never true and an out-of-range paddr wraps in-range. Use uint64_t to
match wolfBoot_check_flash_image_elf so the guards see untruncated
values.
2026-09-04 16:39:26 +02:00
Daniele Lacamera 01a71c7d39 x86_64_efi: return after LoadImage-failure panic under UNIT_TEST
panic() returns under UNIT_TEST, so the LoadImage-failure site fell
through to StartImage on a failed load. Add the return to match the
zero-size guard; on target panic() never returns, so behavior is
unchanged.
2026-09-04 15:52:27 +02:00