Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
5c22c27
F-12061: RP2350: RMW partial pages in hal_flash_write
danielinux Sep 1, 2026
40d448b
F-12062: STM32L4: require a full double word in the fast write path
danielinux Sep 1, 2026
6792b5d
F-12063: STM32WB: require a full double word in the fast write path
danielinux Sep 1, 2026
20c9031
F-12064: P1021: check bad-block markers per erase block
danielinux Sep 1, 2026
4c447f4
F-12104: Kontron TGL: apply the SPI BIOS-region lock through the BAR
danielinux Sep 1, 2026
c55795b
F-12065: update_ram: reject short ext flash reads on the RAM load
danielinux Sep 1, 2026
7736d97
F-12060: multiboot2: terminate the boot info tag list with an end tag
danielinux Sep 1, 2026
0da4114
F-12066: pci: restore original COMMAND and clear windows on bridge error
danielinux Sep 1, 2026
6dabdad
F-12114: pkcs11: wipe the login PIN in crypto deinit
danielinux Sep 1, 2026
b548341
F-12114: pkcs11: wipe the login PIN on all pre-handoff paths
danielinux Sep 1, 2026
1c57f8c
F-12114: pkcs11: wipe the PIN even when no session was established
danielinux Sep 2, 2026
65cab0a
F-12104: unit test: model the TGL SPI MMIO as 32-bit registers
danielinux Sep 2, 2026
5e80903
F-12104: kontron tgl: correct the SPIBAR FREG/FPR register offsets
danielinux Sep 2, 2026
634d679
F-12061: unit test: keep the XIP fast-path source in the flash model
danielinux Sep 2, 2026
a504552
unit test: match wolfBoot_get_dts_size mock to the 2-arg signature
danielinux Sep 2, 2026
fa0c329
F-12064: p1021: drop already-delivered pages of a bad block
danielinux Sep 2, 2026
80e92ea
F-12065: update_ram: type-safe short-read check for -Wsign-compare
danielinux Sep 2, 2026
931d224
F-12065: unit test: clear the short-read mock before the assertion
danielinux Sep 3, 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
49 changes: 38 additions & 11 deletions hal/kontron_vx3060_s2.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
*/

#include <wolfboot/wolfboot.h>
#include <hal.h>
#include <stdint.h>
#include <uart_drv.h>
#include <printf.h>
Expand All @@ -33,12 +34,19 @@
#define SPI_PCI_DEV 31
#define SPI_PCI_FUN 5
#define SPI_BAR_OFF 0x10
/* Tiger Lake SPI controller register offsets, memory-mapped at the
* BAR0 base. FREG1 holds the BIOS flash region base/limit (region 0
* is the flash descriptor); FPR0 is the protected range register
* with the same base/limit layout. Offsets per the Intel PCH SPI
* register map (see drivers/spi/spi-intel.c in the Linux kernel):
* FDATA0-15 at 0x10-0x4C, FRACC at 0x50, FREG0-7 at 0x54-0x74,
* FPR0-4 at 0x84-0x9C. */
#define SPI_FREG1 0x58
#define SPI_FREG_BASE_MASK (0x7fffU << 0)
#define SPI_FREG_LIMIT_MASK (0x7fffU << 16)
#define SPI_FREG_LIMIT_SHIFT (16)
#define SPI_FREG_ADDR_SHIFT (12)
#define SPI_FPR0 (0x48)
#define SPI_FPR0 (0x84)
#define SPI_FPR_WPE (1U << 31)
#define SPI_FPR_RPE (1U << 15)
#define SPI_BIOS_HSFSTS_CTL (0x4)
Expand All @@ -48,6 +56,7 @@ int tgl_lock_bios_region()
{
uint32_t spi_bar, spi_cmd;
uint32_t reg;
int ret = 0;

#if defined(DEBUG)
uint32_t bios_reg_base, bios_reg_lim;
Expand All @@ -60,6 +69,11 @@ int tgl_lock_bios_region()
pci_config_write32(0, SPI_PCI_DEV, SPI_PCI_FUN, PCI_COMMAND_OFFSET,
spi_cmd | PCI_COMMAND_MEM_SPACE);

/* The Flash Protected Range register has the same base/limit
* layout as the Flash Region register: take the BIOS region
* (FREG1, flash region 1) and enable read and write protection
* on it. The SPI registers live in the BAR's memory-mapped
* space, not in PCI configuration space. */
reg = mmio_read32(spi_bar + SPI_FREG1);
#if defined(DEBUG)
bios_reg_base = (reg & SPI_FREG_BASE_MASK) << SPI_FREG_ADDR_SHIFT;
Expand All @@ -68,21 +82,34 @@ int tgl_lock_bios_region()
wolfBoot_printf("Bios reg base: 0x%x lim: 0x%x\r\n", bios_reg_base,
bios_reg_lim);
#endif
/* Flash Protected Range register has very similar layout of the Flash
* Region Register, so we can reuse it and just enable read and write
* protection
*/
reg |= (SPI_FPR_RPE) | (SPI_FPR_WPE);
pci_config_write32(0, SPI_PCI_DEV, SPI_PCI_FUN, SPI_FPR0, reg);
mmio_write32(spi_bar + SPI_FPR0, reg);
Comment thread
danielinux marked this conversation as resolved.
Comment thread
danielinux marked this conversation as resolved.
if ((mmio_read32(spi_bar + SPI_FPR0) &
(SPI_FPR_RPE | SPI_FPR_WPE)) != (SPI_FPR_RPE | SPI_FPR_WPE)) {
ret = -1;
}

/* lock down BIOS register configuration */
reg = pci_config_read32(0, SPI_PCI_DEV, SPI_PCI_FUN, SPI_BIOS_HSFSTS_CTL);
reg = mmio_read32(spi_bar + SPI_BIOS_HSFSTS_CTL);
reg |= SPI_FLOCKDN;
pci_config_write32(0, SPI_PCI_DEV, SPI_PCI_FUN, SPI_BIOS_HSFSTS_CTL, reg);
mmio_write32(spi_bar + SPI_BIOS_HSFSTS_CTL, reg);
if ((mmio_read32(spi_bar + SPI_BIOS_HSFSTS_CTL) & SPI_FLOCKDN) == 0) {
ret = -1;
}

/* restore original cmd */
pci_config_write32(0, SPI_PCI_DEV, SPI_PCI_FUN, PCI_COMMAND_OFFSET, spi_cmd);
return 0;
return ret;
}

int hal_flash_protect(haladdr_t address, int len)
{
(void)address;
(void)len;

/* The TGL BIOS region covers the bootloader partition, so the
* hook's address/len are the same range FREG1 describes. */
return tgl_lock_bios_region();
}

void hal_init(void)
Expand All @@ -97,7 +124,7 @@ void hal_prepare_boot(void)
}
#endif

int hal_flash_write(uint32_t address, const uint8_t *data, int len)
int hal_flash_write(haladdr_t address, const uint8_t *data, int len)
{
return 0;
}
Expand All @@ -110,7 +137,7 @@ void hal_flash_lock(void)
{
}

int hal_flash_erase(uint32_t address, int len)
int hal_flash_erase(haladdr_t address, int len)
{
return 0;
}
Expand Down
21 changes: 19 additions & 2 deletions hal/nxp_p1021.c
Original file line number Diff line number Diff line change
Expand Up @@ -1706,6 +1706,8 @@ int ext_flash_read(uintptr_t address, uint8_t *data, int len)
uint32_t block_size, page_size, read_size;
int ret = 0, pos = 0, i = 0;
int bad_marker;
uint8_t *block_start_data;
int block_start_pos;

#ifdef DEBUG_EXT_FLASH
wolfBoot_printf("ext read: addr 0x%x, dst 0x%x, len %d\n",
Expand Down Expand Up @@ -1738,6 +1740,15 @@ int ext_flash_read(uintptr_t address, uint8_t *data, int len)

/* total download loop */
while (pos < len) {
/* the bad-block marker only exists on the first pages of each
* erase block: restart the per-block page counter. Record the
* output position at the start of the block so that, if the
* block turns out to be bad, the pages already copied from it
* can be discarded. */
i = 0;
block_start_data = data;
block_start_pos = pos;

/* block loop */
do {
/* Calculate page address */
Expand Down Expand Up @@ -1765,9 +1776,15 @@ int ext_flash_read(uintptr_t address, uint8_t *data, int len)
/* check for bad page. if either of the first two pages are bad then
* skip to next block */
if (i++ < 2 && flash_buf[bad_marker] != 0xFF) {
/* skip block - advance address by block and restart position */
/* bad block: discard the pages already copied from it
* (the marker is only checked on the first two pages, so
* a page may have been delivered before detection) and
* continue at the next block. Rewind pos and data to the
* block start (data = original + pos is preserved) and
* move the source address past the bad block. */
pos = block_start_pos;
data = block_start_data;
address = (address + block_size) & ~(block_size - 1);
Comment thread
danielinux marked this conversation as resolved.
pos &= ~(block_size - 1);
break;
}

Expand Down
59 changes: 48 additions & 11 deletions hal/rp2350.c
Original file line number Diff line number Diff line change
Expand Up @@ -225,20 +225,57 @@ void hal_prepare_boot(void)
int RAMFUNCTION hal_flash_write(uint32_t address, const uint8_t *data, int len)
{
uint8_t cache[WOLFBOOT_SECTOR_SIZE];
uint32_t flash_addr = address - XIP_BASE;
uint32_t written = 0;
uint32_t sz;
if (((uintptr_t)data & 0x20000000UL) == 0) {
/* Not in RAM: copy to cache before writing */
while (written < len) {
sz = WOLFBOOT_SECTOR_SIZE;
if (sz > (len - written))
sz = len - written;
memcpy(cache, data + written, sz);
flash_range_program(address - XIP_BASE + written, cache, sz);
written += sz;
uint32_t addr;
uint32_t page_off;
uint32_t page_addr;
uint32_t remaining;

if (len > 0) {
if ((flash_addr & (FLASH_PAGE_SIZE - 1)) == 0 &&
((uint32_t)len & (FLASH_PAGE_SIZE - 1)) == 0) {
/* Page aligned start, page multiple length: program
* directly. */
if (((uintptr_t)data & 0x20000000UL) == 0) {
/* Not in RAM: copy to cache before writing, XIP is
* disabled while the flash is programmed. */
while (written < (uint32_t)len) {
sz = WOLFBOOT_SECTOR_SIZE;
if (sz > (uint32_t)len - written)
sz = (uint32_t)len - written;
memcpy(cache, data + written, sz);
flash_range_program(flash_addr + written, cache, sz);
written += sz;
}
} else {
flash_range_program(flash_addr, data, len);
}
} else {
/* Partial page at the start and/or end: read the page
* back from XIP, merge in the write, program the whole
* page. flash_range_program() only accepts page aligned
* addresses and page multiple lengths. The AND program
* keeps the trailer flag accumulation intact. */
while (written < (uint32_t)len) {
addr = flash_addr + written;
page_off = addr & (FLASH_PAGE_SIZE - 1);
page_addr = addr & ~(FLASH_PAGE_SIZE - 1);
remaining = (uint32_t)len - written;

sz = FLASH_PAGE_SIZE - page_off;
if (sz > remaining)
sz = remaining;

memcpy(cache, (const uint8_t *)(XIP_BASE + page_addr),
FLASH_PAGE_SIZE);
memcpy(cache + page_off, data + written, sz);
flash_range_program(page_addr, cache, FLASH_PAGE_SIZE);
written += sz;
}
}
} else
flash_range_program(address - XIP_BASE, data, len);
}
return 0;
}

Expand Down
3 changes: 2 additions & 1 deletion hal/stm32l4.c
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,8 @@ int RAMFUNCTION hal_flash_write(uint32_t address, const uint8_t *data, int len)

while (i < len) {
flash_clear_errors();
if ((len - i > 3) && ((((address + i) & 0x07) == 0) && ((((uint32_t)data) + i) & 0x07) == 0)) {
if ((len - i >= 8) && ((((address + i) & 0x07) == 0) &&
((((uint32_t)data) + i) & 0x07) == 0)) {
uint32_t idx = i >> 2;
src = (uint32_t *)data;
dst = (uint32_t *)(address);
Expand Down
3 changes: 2 additions & 1 deletion hal/stm32wb.c
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,8 @@ int RAMFUNCTION hal_flash_write(uint32_t address, const uint8_t *data, int len)

while (i < len) {
flash_clear_errors();
if ((len - i > 3) && ((((address + i) & 0x07) == 0) && ((((uint32_t)data) + i) & 0x07) == 0)) {
if ((len - i >= 8) && ((((address + i) & 0x07) == 0) &&
((((uint32_t)data) + i) & 0x07) == 0)) {
uint32_t idx = i >> 2;
src = (uint32_t *)data;
dst = (uint32_t *)(address);
Expand Down
19 changes: 19 additions & 0 deletions src/libwolfboot.c
Original file line number Diff line number Diff line change
Expand Up @@ -2585,12 +2585,31 @@ int pkcs11_crypto_decrypt(uint8_t *out, uint8_t *in, size_t size)
return 0;
}

/* Erase the live copy of the login credential: bootloader memory is
* retained after the handoff, and the credential must not survive in
* it. The volatile store keeps the zeroize from being optimized
* away. */
static void pkcs11_pin_wipe(void)
{
volatile uint8_t *pin;
size_t i;

pin = (volatile uint8_t *)pkcs11_pin;
for (i = 0; i < sizeof(pkcs11_pin); i++) {
pin[i] = 0;
}
}

void pkcs11_crypto_deinit(void)
{
if (encrypt_initialized) {
pkcs11_function_list->C_CloseSession(pkcs11_session);
encrypt_initialized = 0;
}
/* pkcs11_pin is pre-populated from the compile-time credential,
* so wipe it even when no session was ever established: the
* pre-handoff paths must not leave it in retained memory. */
pkcs11_pin_wipe();
}
Comment thread
danielinux marked this conversation as resolved.

#endif
Expand Down
15 changes: 15 additions & 0 deletions src/multiboot.c
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ int mb2_build_boot_info_header(uint8_t *mb2_boot_info,
struct mb2_boot_info_header *hdr =
(struct mb2_boot_info_header *)mb2_boot_info;
struct mb2_tag_info_req *info_req_tag;
struct mb2_tag *end_tag;
int requested_tags, i, r;
uint32_t header_length;
uint8_t *idx;
Expand Down Expand Up @@ -299,6 +300,20 @@ int mb2_build_boot_info_header(uint8_t *mb2_boot_info,
}
}

/* The Multiboot2 spec requires the tag list to be terminated by an
* end tag (type 0, size 8); reserve its space and include it in
* total_size. */
if (max_size < sizeof(struct mb2_tag)) {
MB2_DEBUG_PRINTF("Not enough size to build mb2 end tag\r\n");
return -1;
}
max_size -= sizeof(struct mb2_tag);
end_tag = (struct mb2_tag *)idx;
end_tag->type = 0;
end_tag->flags = 0;
end_tag->size = sizeof(*end_tag);
idx += sizeof(*end_tag);

hdr->total_size = idx - (uint8_t*)hdr;

return 0;
Expand Down
32 changes: 24 additions & 8 deletions src/pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -623,7 +623,8 @@ static int pci_program_bridge(uint8_t bus, uint8_t dev, uint8_t fun,
uint64_t prefetch_start;
uint64_t mem_start;
uint64_t io_start;
uint32_t orig_cmd;
uint32_t saved_cmd;
uint32_t new_cmd;
uint8_t saved_bus;
uint64_t saved_mem;
uint64_t saved_pf;
Expand All @@ -635,8 +636,12 @@ static int pci_program_bridge(uint8_t bus, uint8_t dev, uint8_t fun,
saved_pf = info->mem_pf;
saved_io = info->io;

orig_cmd = pci_config_read16(bus, dev, fun, PCI_COMMAND_OFFSET);
saved_cmd = pci_config_read16(bus, dev, fun, PCI_COMMAND_OFFSET);
pci_config_write16(bus, dev, fun, PCI_COMMAND_OFFSET, 0);
/* decode bits are accumulated from the original value so the
* success path preserves the bits it did not manage; the error
* path restores saved_cmd itself */
new_cmd = saved_cmd;

/* curr_bus_number is one bus per bridge level; at 0xFF the next
* increment wraps to 0, which would write SECONDARY_BUS 0 and
Expand Down Expand Up @@ -699,7 +704,7 @@ static int pci_program_bridge(uint8_t bus, uint8_t dev, uint8_t fun,
prefetch_start >> 16);
pci_config_write16(bus, dev, fun, PCI_PREFETCH_LIMIT_OFF,
(info->mem_pf - 1) >> 16);
orig_cmd |= PCI_COMMAND_MEM_SPACE;
new_cmd |= PCI_COMMAND_MEM_SPACE;
} else {
/* disable prefetch */
pci_config_write16(bus, dev, fun, PCI_PREFETCH_BASE_OFF,
Expand All @@ -719,7 +724,7 @@ static int pci_program_bridge(uint8_t bus, uint8_t dev, uint8_t fun,
mem_start >> 16);
pci_config_write16(bus, dev, fun, PCI_MMIO_LIMIT_OFF,
(info->mem - 1) >> 16);
orig_cmd |= PCI_COMMAND_MEM_SPACE;
new_cmd |= PCI_COMMAND_MEM_SPACE;
} else {
/* disable mem */
pci_config_write16(bus, dev, fun, PCI_MMIO_BASE_OFF,
Expand All @@ -739,7 +744,7 @@ static int pci_program_bridge(uint8_t bus, uint8_t dev, uint8_t fun,
io_start >> 8);
pci_config_write8(bus, dev, fun, PCI_IO_LIMIT_OFF,
(info->io - 1) >> 8);
orig_cmd |= PCI_COMMAND_IO_SPACE;
new_cmd |= PCI_COMMAND_IO_SPACE;
}
else {
pci_config_write8(bus, dev, fun, PCI_IO_BASE_OFF,
Expand All @@ -748,8 +753,8 @@ static int pci_program_bridge(uint8_t bus, uint8_t dev, uint8_t fun,
0x0);
}

orig_cmd |= PCI_COMMAND_BUS_MASTER;
pci_config_write16(bus, dev, fun, PCI_COMMAND_OFFSET, orig_cmd);
new_cmd |= PCI_COMMAND_BUS_MASTER;
pci_config_write16(bus, dev, fun, PCI_COMMAND_OFFSET, new_cmd);

pci_dump_bridge(bus,dev,fun);
return 0;
Expand All @@ -759,10 +764,21 @@ static int pci_program_bridge(uint8_t bus, uint8_t dev, uint8_t fun,
info->mem = saved_mem;
info->mem_pf = saved_pf;
info->io = saved_io;
/* Disable every window that may have been programmed before the
* error: the allocator cursors are rolled back, so the bridge must
* not keep decoding the returned address ranges. */
pci_config_write16(bus, dev, fun, PCI_PREFETCH_BASE_OFF, 0xffff);
pci_config_write16(bus, dev, fun, PCI_PREFETCH_LIMIT_OFF, 0x0);
pci_config_write16(bus, dev, fun, PCI_MMIO_BASE_OFF, 0xffff);
pci_config_write16(bus, dev, fun, PCI_MMIO_LIMIT_OFF, 0x0);
pci_config_write8(bus, dev, fun, PCI_IO_BASE_OFF, 0xff);
pci_config_write8(bus, dev, fun, PCI_IO_LIMIT_OFF, 0x0);
pci_config_write8(bus, dev, fun, PCI_PRIMARY_BUS, 0);
pci_config_write8(bus, dev, fun, PCI_SECONDARY_BUS, 0);
pci_config_write8(bus, dev, fun, PCI_SUB_SEC_BUS, 0);
pci_config_write16(bus, dev, fun, PCI_COMMAND_OFFSET, orig_cmd);
/* restore the original COMMAND value, not the decode bits
* accumulated for the discarded windows */
pci_config_write16(bus, dev, fun, PCI_COMMAND_OFFSET, saved_cmd);
return -1;
}

Expand Down
4 changes: 4 additions & 0 deletions src/update_disk.c
Original file line number Diff line number Diff line change
Expand Up @@ -928,6 +928,10 @@ void RAMFUNCTION wolfBoot_start(void)
#elif defined(WOLFBOOT_ENABLE_WOLFHSM_SERVER)
(void)hal_hsm_server_cleanup();
#endif

#ifdef ENCRYPT_PKCS11
pkcs11_crypto_deinit();
#endif
#ifndef TZEN
if (hal_flash_protect(WOLFBOOT_ORIGIN, BOOTLOADER_PARTITION_SIZE) < 0) {
wolfBoot_printf("Error protecting bootloader flash region\r\n");
Expand Down
Loading
Loading