- hal/nxp_p1021.c: fix ONFI status polarity (bit 0 set = fail, bit 7
clear = protected; was checking bits 0+1 set = success)
- src/libwolfboot.c: move partition state APIs under HAVE_PARTITION_TRAILERS
so CUSTOM_PARTITION_TRAILER without WOLFBOOT_FIXED_PARTITIONS links
- src/x86/ata.c: do not zeroize DMA buffer when another async op is
in progress (buffer still owned by first command's transfer)
- unit-p1021-fcm-bytes/erase-advance: update mocks to ONFI status bytes
- unit-update-ram-custom-trailer: add BOOT selection assertion via
mock_max_read_addr, PID-suffixed temp files, unlink in cleanup
- unit-update-ram-nofixed-noramboot: unlink PID-specific temp files
The reliability gate is WRCALIB, not PHY_TRAINING_STATUS. MTC is a
secondary gate skipped when TIP completes full training, and the
retry budget is 3 inner x 6 outer (up to 18 attempts), not 5.
buffer_is_all_value() early-exited on the first byte differing from
the target, so the loop trip count leaked the length of the leading
0xFF/0x00 run of the UDS, the DICE root secret read in
hal_uds_derive_key().
Replace the early exit with a volatile |= accumulator over the full
buffer, matching the constant-time compare pattern already used by
image_CT_compare() and the other secret comparisons in the tree.
Verified: gcc -S -O2 shows a straight-line loop body with only the
data-independent i < len branch; arm-none-eabi-gcc (stm32h5 preset)
compiles the file clean.
Reported by Fenrir.
The F-12879 fix publishes SHM status with plain C stores before
IPC_TASKS_SEND; without a compiler memory barrier an optimized
build can reorder the stores past the dsb asm. Matches the
existing clobber in imx95_m7.h and stm32g4.h.
hal_shm_status_set() triggered the IPC event before storing the
magic/status fields, so the peer core could wake on the event, read
stale fields, and wait for a second event that never comes. Store
the fields first, order them with a DSB, then signal; the receiver
pairs it with a DSB after clearing the event, before re-reading the
fields. Not verified on real nRF5340 hardware.
The write/erase loops discarded the JEDEC status byte from MDR and
hal_flash_command ignored the PAR (uncorrectable ECC) and FCT (FCM
timeout) bits, so failed programs, erases and uncorrectable reads
all reported success. Check P/WPS in the status byte and stop the
loop, and fail the command on PAR/FCT. The small-page FCM sequence
now ends with the status command (CM3+RSW) so MDR holds a valid
status like the large-page path; not verified on real P1021
hardware. config_io_pin now uses a single masked store for CPDIR/
CPPAR (F-12880): the clear-then-set pair could drop a concurrent
update to another pin in the same register.
F-12880, F-12881, F-12882
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.
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.
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.
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.
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.
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.
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).
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.
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.
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.
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).
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.
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.
The H7 OTP memory is one-time programmable, so the keystore and UDS
are permanent once written; the H7 has no OTP block-lock register
(unlike the H5), so there is no write-protection step to perform.
Replace the misleading TODO with the reason the no-op is correct.
boot_x86_64.c declared x86_64_efi_do_boot(uint8_t *) while the HAL
defines (uint32_t *, uint8_t *): the linker connected the incompatible
pair and the call was undefined behavior, mostly latent because the
second parameter was discarded. Match the AArch64 sibling: single
const uint32_t *boot_addr in the declaration, definition and call,
and remove the unused dts_address parameter.
The UEFI MEMMAP_DEVICE_PATH EndingAddress is inclusive (last valid
byte), but x86_64_efi_do_boot() set it to boot_addr + size, describing
every image as one byte longer than it is; the AArch64 sibling already
uses size - 1. A zero-size image would underflow that computation and
hand an empty range to LoadImage, so reject it up front, as the
AArch64 sibling does. The local panic() returns to the unit test under
UNIT_TEST so the zero-size path is observable.
main() loaded a file of any size and parsed it as a manifest: header
fields (size, TLVs) were read past the end of the heap allocation, and
a header claiming a larger fw_size drove the image hash over an
unbounded range. Reject files smaller than IMAGE_HEADER_SIZE before
parsing and clamp fw_size to the bytes actually loaded.
When the bad-block marker is found on the block's second page, the
first page has already been copied to the caller's buffer and counted
in pos; the skip advanced only the source address, so the bad block's
page stayed in the output and the read returned len with the bad
block's content mixed into the image.
Record the output position at the start of each erase block and, on a
bad block, rewind both pos and the data pointer to it before advancing
the source address. This preserves the data = original + pos
invariant (no out-of-bounds write) and discards the bad block's
delivered pages.
test_bad_marker_second_page_dropped now asserts the bad block is fully
skipped (output starts at the next block's first page); it fails
against the previous code.
PR review (wolfSSL/wolfBoot#880, Fenrir bot) flagged that the
register offsets introduced by the F-12104 fix are wrong, and the
Linux kernel's Intel PCH SPI driver (drivers/spi/spi-intel.c)
confirms it:
FDATA(n) = 0x10 + 4n -> 0x48 is FDATA14, a scratch data register
FRACC = 0x50 -> not FREG0
FREG(n) = 0x54 + 4n -> FREG0 = 0x54, FREG1 = 0x58
FPR0-4 = 0x84-0x9C (BXT/CNL protection-range base)
Two consequences. First, the BIOS range source: Intel flash region
numbering is region 0 = flash descriptor, region 1 = BIOS, and the
kernel driver's partition code reflects that ("start from the
mandatory descriptor region", then iterate FREG(1..)). The original
pre-F-12104 code read FREG1 (0x58) for the BIOS range and was right
on that point; the F-12104 fix regressed it to FREG0 (0x50), which
is the FRACC register. Restore FREG1.
Second, FPR0: the original 0x48 came from the buggy PCI-config-space
write path and is a FDATA scratch register in the SPIBAR map, so the
readback check passed on a register that never programs protection.
FPR0 is 0x84 (BXT/CNL PR base; JSL is not in the kernel's platform
table but follows the same-generation layout). HSFSTS_CTL at 0x04
and the RPE (bit 15) / WPE (bit 31) / base / limit fields match the
kernel's PR_ definitions and are unchanged.
unit-kontron-tgl-spi.c: mirror the corrected offsets (FREG0 decoy at
0x54, FREG1 BIOS source at 0x58, FPR0 at 0x84) and assert FPR0
carries the FREG1 range; the test runs the real extracted
tgl_lock_bios_region(), so it fails if the HAL offsets drift.
Verification: unit-kontron-tgl-spi 4/4, full unit suite green, sim
build green, cstyle clean on changed hunks.
tgl_lock_bios_region() wrote the protected range and the FLOCKDN
value through PCI configuration space (offsets 0x48 and 0x04, the
status/command dword) instead of the SPI controller's
memory-mapped registers at the BAR0 base, and took the range from
FREG1 (non-BIOS) instead of FREG0 (BIOS). The lock now writes
FPR0 and BIOS/H SFSTS/CTL through mmio_write32(), verifies both
by readback, and returns an error if the bits do not stick.
The helper had no callers: no hal_flash_protect() override
existed, so the weak no-op default ran before handoff and the
BIOS region stayed writable. Add the override routing to
tgl_lock_bios_region().
Including <hal.h> for the hook signature also exposes the
hal_flash_write/hal_flash_erase stubs as mismatching the HAL
contract; fix their address parameter to haladdr_t.
Add unit-kontron-tgl-spi: runs the extracted
tgl_lock_bios_region() and hal_flash_protect() against mocked
PCI config space and an MMIO array at the BAR address (build
fails pre-fix - hal_flash_protect undefined - 4/4 pass
post-fix).
ext_flash_read() initialized its bad-block page counter once per
request, so the marker was inspected only on the first two pages
read and a bad erase block later in the request was delivered as
valid data. Restart the counter at the start of each erase block.
The skip path also rewound the logical position to a block
boundary without rewinding the output pointer, so a marker found
after some pages had been delivered continued the read past the
end of the caller's buffer. pos and data already agree
(data = original + pos) after any delivered pages, so the skip
only advances the source address.
Add unit-p1021-read-badblock: runs the extracted
ext_flash_read() against a mocked ELBC on a simulated NAND with
three 16 KiB blocks (2/5 checks fail pre-fix, 5/5 pass
post-fix).
The double-word fast path was selected on 'len - i > 3' but always
reads and programs two 32-bit words, so an aligned 4-7 byte tail
read up to four bytes past the caller's buffer and programmed them
into flash. Require at least eight remaining bytes; shorter tails
fall to the RMW branch, which rewrites the unit with the
out-of-range bytes read back from flash.
Add unit-stm32wb-write: runs the extracted hal_flash_write()
against a host register file with stale destination flash and a
source canary (3/5 checks fail pre-fix, 5/5 pass post-fix).
The double-word fast path of hal_flash_write() was selected on
"len - i > 3" but always reads and programs two 32-bit words, so
an aligned 4-7 byte tail read up to four bytes past the caller's
buffer and programmed them into flash. Require at least eight
remaining bytes before taking the fast path; shorter tails fall to
the RMW branch, which rewrites the unit with the out-of-range bytes
read back from flash. Same fix as the STM32G4 twin (F-11023).
Add unit-stm32l4-write: runs the extracted hal_flash_write()
against a host register/flash model with a canary after the source
(3/5 checks fail pre-fix, 5/5 pass post-fix).
flash_range_program() requires a page-aligned address and a
page-multiple length (pico-sdk ROM, invalid_params_if on both). The
partition-state path without NVM_FLASH_WRITEONCE issues 1-byte
(trailer) and 4-byte (magic) writes that violated the contract on
every state transition.
Keep the direct-program fast path for page-aligned page-multiple
writes; otherwise read the page back from XIP, merge the write, and
program the full page. The AND program keeps the trailer flag
accumulation intact.
Add unit-rp2350-flash-write: runs the extracted hal_flash_write
against a mock flash_range_program() that enforces the ROM contract
(4/6 checks fail pre-fix, 6/6 pass post-fix).