F-14487/F-14488 scrubbed the TRNG staging buffers with wc_ForceZero,
which links the hal objects to wolfCrypt's memory.c. The OTP keystore
primer links the hal without wolfCrypt and failed to build
(undefined reference to wc_ForceZero) in the stm32h5_tz_dualbank_otp
and trustzone-emulator configs. Scrub with a local volatile loop, the
same pattern nvm_cache_scrub uses for the same reason.
The secure-mode TRNG seed helper (shared by the STM32L5/U5/H5
TrustZone ports) staged each TRNG_DR word in a stack local and
returned without clearing it. Force-zero the local before the
return, mirroring the existing scrub in hal/cm4.c.
The secure-mode TRNG seed helper copied each 24-byte CryptoCell EHR
batch into a stack array and returned without clearing it, leaving
raw TRNG output in the retired secure frame. Force-zero the batch at
the end of each iteration, mirroring the existing scrub in hal/cm4.c.
- hal/nxp_ls1028a.c: ext_flash_erase/write return len on success, not
0, so the F-12067 follow-up guards (ret != 0) always tripped and
test_flash could never pass; check ret < 0
- src/x86/qemu_fsp.c: the F-12885 stop-bit guard rejects the in-tree
uart_init(115200, 8, 'N', 0) call, leaving the FSP QEMU debug UART
unprogrammed; pass 1 stop bit
The write loop cast len to uint32_t, so a negative length became
a huge iteration count and read past the source buffer; a zero
length is a no-op success, matching the erase side.
Erase was the only ext_flash op without the layout check, so an
out-of-range request reached the SDK. Also replace the lone
_Static_assert with the tree's typedef char idiom.
The MCXA ROM API (fsl_romapi.h) takes lengthInBytes, not a sector
count, so the original pass-through was already correct and the
sector-count conversion erased almost nothing. It also called
FLASH_GetFlashConfig, which does not exist in the MCXA ROM API and
only compiled against the unit-test stub. Restore the byte length,
keep the len guard, and drop the invented call from the stub.
The dispatcher split cross-bank requests at FLASH_BANK2_BASE_REL
(0x00100000), but callers pass absolute flash addresses in
FLASHMEM_ADDRESS_SPACE, so the split never fired and the whole
request was programmed on the bank of the start address. Compare
against FLASH_BANK2_BASE (0x08100000); the test now drives
absolute addresses so it exercises the real call convention.
For len <= 0 the inclusive end (address + len - 1) underflows and
the sector loop runs through address wraparound. Treat a
non-positive length as a no-op before computing the end.
A mismatch at index zero returned -0 (success-looking), and a
successful test returned the ext_flash_read() byte count. Return a
fixed -1 on mismatch and 0 on success, and have the hal_init
diagnostic caller log a failure.
hal_flash_erase() selected the bank geometry from the start address
only; a range extending past the end of that bank was partially
erased and reported as success. Derive the bank end from the sector
geometry and reject cross-bank requests before erasing anything.
New unit test extracts the real hal_flash_erase() and runs it against
an emulated two-bank FAPI.
- The seven RAM start-table scratch slots sit at hard-coded 256-byte
strides (last one 512 bytes); nothing checked the 2048-byte buffer
still covers them if the layout or the buffer is edited.
- Add a _Static_assert on the slot budget plus a comment recording the
per-slot contract and the sizeof() re-derivation owed when SPIC
adaptor reuse lands (SDK struct sizes are only visible in the SDK
backend, so full sizeof-based slots are deferred to that toolchain).
- Verified: host -fsyntax-only clean at 2048; shrinking the buffer to
1024 fails with the assertion message; make -C tools/unit-tests run
passes.
- ext_flash_read/ext_flash_write forwarded unvalidated (address, len)
to the SDK flash_stream_* primitives; a request past the 16 MB
device end reached the driver unchecked, unlike the overflow guard
already in ext_flash_erase.
- Add ext_flash_in_layout(): reject negative len, base at/past the
16 MB device end, and any end offset beyond it (the base check
keeps the size subtraction from wrapping).
- Verified: host -fsyntax-only of the bare backend compiles clean;
make -C tools/unit-tests run passes.
HFROSCCFG_DIV_SHIFT(d) masked the shifted value with HFROSCCFG_TRIM
(bits 16-23) instead of HFROSCCFG_DIV (bits 0-3), so the divider
always programmed zero.
- mask with HFROSCCFG_DIV
- add unit-hifive1-hfrosccfg pinning the field macros (value,
overlap, and the composed init register value)
uart_init() initialized a local to zero and tested that local, so the
LCR stop-bit field was always zero (one stop bit) and stop values
other than 1/2 were silently accepted. Validate stop against 1/2 and
derive the field from the parameter.
Add unit-x86-uart (linked real driver, io_write8/io_read8 mocked)
covering 8N1/8N2/5O2 LCR encodings plus stop-count and existing
argument rejection; 3 of 5 tests fail pre-fix.
The not-found sentinel is -1, so the early-exit test must be
start >= 0 && end >= 0; with '> 0' any range involving sector zero
scanned the whole table. Behavior-preserving: each address falls in
exactly one bucket, so the full scan produced the same result.
hal_flash_write() cleared errors before programming and waited for
completion but never read the post-program status register, so
OPERR/PROGERR/WRPERR/PGAERR/SIZERR/PGSERR faults were swallowed and a
failed program was reported as success. Check FLASH_NS_SR after the
wait, clear the flags, and return -1 on fault; reject addresses not
aligned to the 8-byte double-word programming unit.
Unit test extracts the writer with stubbed registers: success,
PROGERR, WRPERR and misaligned-address cases; fails pre-fix.
hal_flash_write() picked the bank from the start address and
programmed the whole request on that bank, so a request crossing
into bank 2 wrote its tail to the wrong bank. The exported writer
now splits at FLASH_BANK2_BASE_REL into two per-bank passes; a
failure in the first pass stops the split.
Unit test extracts the dispatcher and mocks the per-bank pass:
cross-boundary split, single-bank pass-through, and first-pass
failure all covered; fails pre-fix.
Input longer than the 128-byte conversion buffer was silently
truncated: the loop stopped at the buffer edge and one raw write
dropped the rest. Flush on full (and before a newline that no longer
fits) and keep converting.
Verification: new unit-nrf54l-uart-write fails pre-fix 3/4 (output
capped at 128 bytes), 4/4 post-fix; full make -C tools/unit-tests run
green.
With matched-but-unaligned address/data residues the byte-wise prefix
leaves i % 4 != 0, so dst[i >> 2] stored the word below the intended
address, dropped the tail bytes of the unit, and issued an unaligned
NVM store (HardFault on M0+). Derive src/dst from address + i, matching
the already-correct else branch.
Verification: new matched-alignment test fails pre-fix in both
unit-flash-write-samr21 and unit-flash-write-same51 (tail bytes stay
0xFF), 3/3 post-fix; full make -C tools/unit-tests run green.
With an unaligned start address the byte-wise prefix leaves i % 4 != 0,
so dst[i >> 2] programmed the double word below the intended address
and left the tail bytes of the unit unprogrammed. Derive src/dst from
address + i, matching the already-fixed else branch.
Verification: new unit-stm32g4-write test_write_unaligned_start fails
pre-fix (memcmp mismatch), 5/5 post-fix; full make -C tools/unit-tests
run green.