add asymmetric partition sizing for monolithic updates

pull/849/merge
Brett Nicholas 2026-08-12 08:50:34 -06:00 committed by Daniele Lacamera
parent d42109c843
commit 25aa151f0b
15 changed files with 284 additions and 33 deletions

View File

@ -302,6 +302,7 @@ endif
# Environment variables for sign tool # Environment variables for sign tool
SIGN_ENV=IMAGE_HEADER_SIZE=$(IMAGE_HEADER_SIZE) \ SIGN_ENV=IMAGE_HEADER_SIZE=$(IMAGE_HEADER_SIZE) \
WOLFBOOT_PARTITION_SIZE=$(WOLFBOOT_PARTITION_SIZE) \ WOLFBOOT_PARTITION_SIZE=$(WOLFBOOT_PARTITION_SIZE) \
WOLFBOOT_PARTITION_UPDATE_SIZE=$(WOLFBOOT_PARTITION_UPDATE_SIZE) \
WOLFBOOT_SECTOR_SIZE=$(WOLFBOOT_SECTOR_SIZE) \ WOLFBOOT_SECTOR_SIZE=$(WOLFBOOT_SECTOR_SIZE) \
NVM_FLASH_WRITEONCE=$(NVM_FLASH_WRITEONCE) \ NVM_FLASH_WRITEONCE=$(NVM_FLASH_WRITEONCE) \
ML_DSA_LEVEL=$(ML_DSA_LEVEL) \ ML_DSA_LEVEL=$(ML_DSA_LEVEL) \
@ -760,6 +761,7 @@ distclean: clean keysclean utilsclean
include/target.h: $(TARGET_H_TEMPLATE) FORCE include/target.h: $(TARGET_H_TEMPLATE) FORCE
$(Q)cat $(TARGET_H_TEMPLATE) | \ $(Q)cat $(TARGET_H_TEMPLATE) | \
sed -e "s/@WOLFBOOT_PARTITION_SIZE@/$(WOLFBOOT_PARTITION_SIZE)/g" | \ sed -e "s/@WOLFBOOT_PARTITION_SIZE@/$(WOLFBOOT_PARTITION_SIZE)/g" | \
sed -e "s|@WOLFBOOT_PARTITION_UPDATE_SIZE_DEFINE@|$(if $(strip $(WOLFBOOT_PARTITION_UPDATE_SIZE)),#define WOLFBOOT_PARTITION_UPDATE_SIZE $(WOLFBOOT_PARTITION_UPDATE_SIZE),/* WOLFBOOT_PARTITION_UPDATE_SIZE not set */)|g" | \
sed -e "s/@WOLFBOOT_SECTOR_SIZE@/$(WOLFBOOT_SECTOR_SIZE)/g" | \ sed -e "s/@WOLFBOOT_SECTOR_SIZE@/$(WOLFBOOT_SECTOR_SIZE)/g" | \
sed -e "s/@WOLFBOOT_NSC_ADDRESS@/$(WOLFBOOT_NSC_ADDRESS)/g" | \ sed -e "s/@WOLFBOOT_NSC_ADDRESS@/$(WOLFBOOT_NSC_ADDRESS)/g" | \
sed -e "s/@WOLFBOOT_NSC_SIZE@/$(WOLFBOOT_NSC_SIZE)/g" | \ sed -e "s/@WOLFBOOT_NSC_SIZE@/$(WOLFBOOT_NSC_SIZE)/g" | \

View File

@ -0,0 +1,49 @@
ARCH?=AURIX_TC3
TARGET?=aurix_tc3xx
AURIX_TC3_HSM=1
SIGN?=RSA4096
HASH?=SHA256
DEBUG?=0
WOLFBOOT_VERSION?=1
V?=0
SPMATH?=1
RAM_CODE?=1
SELF_UPDATE_MONOLITHIC=1
EXT_FLASH?=1
EXT_BOOT=1
EXT_UPDATE=1
EXT_SWAP=1
FLAGS_INVERT=1
FLASH_MULTI_SECTOR_ERASE=1
DEBUG_UART=1
PRINTF_ENABLED=1
WOLFBOOT_IMG_HASH_ONESHOT=1
# wolfHSM options
WOLFHSM_SERVER=1
# Cert chain options
CERT_CHAIN_VERIFY=1
# RSA4096 cert chains need the larger header and stack
WOLFBOOT_HUGE_STACK=1
IMAGE_HEADER_SIZE=4096
# self-header feature (persist header in external flash)
WOLFBOOT_SELF_HEADER=1
SELF_HEADER_EXT=1
# Asymmetric monolithic layout: BOOT (0x28000) only holds the app; UPDATE
# (0x38000) stages the monolithic payload. UPDATE matches the install span
# (bootloader region 0x10000 + BOOT 0x28000), so staging overhead
# (IMAGE_HEADER_SIZE plus one trailer sector) comes out of the app's
# share; see "Independent partition sizing" in docs/firmware_update.md.
# No SWAP partition in monolithic mode; 0 marks it not present.
ARCH_FLASH_OFFSET=0x80028000
WOLFBOOT_SECTOR_SIZE=0x4000
WOLFBOOT_PARTITION_SIZE=0x28000
WOLFBOOT_PARTITION_UPDATE_SIZE=0x38000
WOLFBOOT_PARTITION_BOOT_ADDRESS=0x80038000
WOLFBOOT_PARTITION_UPDATE_ADDRESS=0x80060000
WOLFBOOT_PARTITION_SWAP_ADDRESS=0
WOLFBOOT_PARTITION_SELF_HEADER_ADDRESS=0x8009C000

View File

@ -9,12 +9,16 @@ RAM_CODE=1
SELF_UPDATE_MONOLITHIC=1 SELF_UPDATE_MONOLITHIC=1
WOLFBOOT_VERSION=1 WOLFBOOT_VERSION=1
# Partition size 512KB so the monolithic payload (bootloader region + app) # Asymmetric layout: BOOT only holds the app; UPDATE stages the monolithic
# fits in the UPDATE partition. # payload. UPDATE (0x80000) matches the install span (bootloader region
WOLFBOOT_PARTITION_SIZE=0x80000 # 0x20000 + BOOT 0x60000), so staging overhead (IMAGE_HEADER_SIZE plus one
# trailer sector) comes out of the app's share; see "Independent partition
# sizing" in docs/firmware_update.md.
WOLFBOOT_PARTITION_SIZE=0x60000
WOLFBOOT_PARTITION_UPDATE_SIZE=0x80000
WOLFBOOT_SECTOR_SIZE=0x1000 WOLFBOOT_SECTOR_SIZE=0x1000
WOLFBOOT_PARTITION_BOOT_ADDRESS=0x20000 WOLFBOOT_PARTITION_BOOT_ADDRESS=0x20000
WOLFBOOT_PARTITION_UPDATE_ADDRESS=0xA0000 WOLFBOOT_PARTITION_UPDATE_ADDRESS=0x80000
# required for keytools # required for keytools
WOLFBOOT_FIXED_PARTITIONS=1 WOLFBOOT_FIXED_PARTITIONS=1

View File

@ -100,7 +100,19 @@ of its addressable space.
- `WOLFBOOT_PARTITION_SIZE` - `WOLFBOOT_PARTITION_SIZE`
The size of the BOOT and UPDATE partition. The size is the same for both partitions. The size of the BOOT and UPDATE partitions. The size is the same for both partitions unless using the monolithic
self-update mode, in which case the UPDATE partition can optionally be sized independently.
- `WOLFBOOT_PARTITION_UPDATE_SIZE`
Optional. Sizes the UPDATE partition independently of BOOT; defaults to
`WOLFBOOT_PARTITION_SIZE`. A different value is only allowed together with
`SELF_UPDATE_MONOLITHIC=1`, so the UPDATE partition can stage a monolithic
payload (bootloader region + application) without inflating the BOOT
partition. The staged payload also needs `IMAGE_HEADER_SIZE` plus one
trailer sector of room on top — see the sizing guide in
[firmware_update.md](firmware_update.md#independent-partition-sizing).
Not supported with `ENCRYPT` or `PULL_LINKER_DEFINES`.
## Bootloader features ## Bootloader features

View File

@ -274,11 +274,111 @@ partition.
- **Payload must fit in the UPDATE partition.** The signed monolithic - **Payload must fit in the UPDATE partition.** The signed monolithic
image (header + bootloader + signed application) plus the 5-byte image (header + bootloader + signed application) plus the 5-byte
`pBOOT` trailer must not exceed `WOLFBOOT_PARTITION_SIZE`. `pBOOT` trailer must not exceed the UPDATE partition size
(`WOLFBOOT_PARTITION_SIZE`, or `WOLFBOOT_PARTITION_UPDATE_SIZE` when
set — see below). When the update is triggered with
`wolfBoot_update_trigger()`, the trigger erases the whole last sector
of the UPDATE partition, so the staged payload must also leave that
sector free.
- **Payload must not reach the BOOT trailer sector when installed.** The
installed span (`fw_size` bytes written at `ARCH_FLASH_OFFSET`) must
not exceed the bootloader region plus the BOOT partition minus the
BOOT partition's last sector, which is reserved for the partition
state trailer (and, with `FLAGS_HOME`, the UPDATE partition flags).
wolfBoot rejects larger payloads before erasing anything.
##### Independent partition sizing
In monolithic mode the BOOT partition only ever holds the application,
but the UPDATE partition has to stage the whole payload (bootloader
region + application). By default both partitions share
`WOLFBOOT_PARTITION_SIZE`, which forces BOOT to be as large as the
payload. Set `WOLFBOOT_PARTITION_UPDATE_SIZE` to size the UPDATE
partition independently and keep BOOT small:
```
WOLFBOOT_PARTITION_SIZE=0x60000 # BOOT: just the application slot
WOLFBOOT_PARTITION_UPDATE_SIZE=0x80000 # UPDATE: bootloader region + BOOT
```
###### Sizing the UPDATE partition
Just like with a regular application update, a staged monolithic update needs
more room than the installed payload, because two extra regions share the
UPDATE partition with it:
```
UPDATE partition layout while an update is staged
(total size = WOLFBOOT_PARTITION_UPDATE_SIZE):
+---------------------+--------------------------------+----------------+
| signed image header | payload: bootloader region | trailer sector |
| (IMAGE_HEADER_SIZE) | + application image | (last sector) |
+---------------------+--------------------------------+----------------+
```
- **Signed image header** (`IMAGE_HEADER_SIZE`): the signing tool
prepends the signed manifest to the payload. It is not part of the
installed span (with `WOLFBOOT_SELF_HEADER` it is persisted
separately), but it occupies staging space while the update is
pending.
- **Trailer sector** (one `WOLFBOOT_SECTOR_SIZE`): the last sector of
the partition holds the partition state trailer, and
`wolfBoot_update_trigger()` erases the whole sector when arming the
update. The staged image must not extend into it.
The largest payload that can be staged is therefore:
```
max_staged_payload = WOLFBOOT_PARTITION_UPDATE_SIZE
- IMAGE_HEADER_SIZE - WOLFBOOT_SECTOR_SIZE
```
while the largest payload that can be installed (the install span:
bootloader region plus BOOT partition, minus BOOT's own trailer
sector) is:
```
max_install = (WOLFBOOT_PARTITION_BOOT_ADDRESS - ARCH_FLASH_OFFSET)
+ WOLFBOOT_PARTITION_SIZE - WOLFBOOT_SECTOR_SIZE
```
The last sector of the BOOT partition is reserved for the partition
state trailer (with `FLAGS_HOME` it also holds the UPDATE partition
flags, and `wolfBoot_update_trigger()` erases the whole sector), so
wolfBoot's oversize check rejects any payload that would reach it.
To be able to deliver any payload the install span allows, including
an application as large as the BOOT partition can hold, size the
UPDATE partition so that `max_staged_payload >= max_install`:
```
WOLFBOOT_PARTITION_UPDATE_SIZE >=
(WOLFBOOT_PARTITION_BOOT_ADDRESS - ARCH_FLASH_OFFSET)
+ WOLFBOOT_PARTITION_SIZE + IMAGE_HEADER_SIZE
```
(the UPDATE trailer sector and the BOOT trailer sector cancel out:
staging reserves one extra sector, installing needs one less.)
Notes:
- Only valid together with `SELF_UPDATE_MONOLITHIC=1`; the swap-based
update modes require equal-size partitions and fail to compile
otherwise.
- Not supported with `ENCRYPT` or `PULL_LINKER_DEFINES`.
- The partition state trailer sits at the end of the (now larger) UPDATE
partition (with `FLAGS_HOME` it stays at the end of the BOOT
partition), so the bootloader and the application must be built from
the same configuration to agree on its location.
##### Simulator test ##### Simulator test
A simulator test is provided in `tools/test.mk` to exercise this use case: A simulator test is provided in `tools/test.mk` to exercise this use case.
The example config uses the asymmetric layout shown above: the UPDATE
partition is sized for the monolithic payload while BOOT stays
application-sized:
``` ```
cp config/examples/sim-self-update-monolithic.config .config cp config/examples/sim-self-update-monolithic.config .config

View File

@ -13,6 +13,8 @@ For this reason, before proceeding with partitioning on a target system, the
following aspects must be considered: following aspects must be considered:
- BOOT partition and UPDATE partition must have the same size, and be able to contain the running system - BOOT partition and UPDATE partition must have the same size, and be able to contain the running system
- exception: in monolithic self-update mode the UPDATE partition may be larger than BOOT, see
`WOLFBOOT_PARTITION_UPDATE_SIZE` in [firmware_update.md](firmware_update.md#independent-partition-sizing)
- SWAP partition must be as big as the largest sector in both BOOT and UPDATE partition. - SWAP partition must be as big as the largest sector in both BOOT and UPDATE partition.
The flash memory of the target is partitioned into the following areas: The flash memory of the target is partitioned into the following areas:
@ -20,7 +22,8 @@ The flash memory of the target is partitioned into the following areas:
- Bootloader partition, at the beginning of the flash, generally very small (16-32KB) - Bootloader partition, at the beginning of the flash, generally very small (16-32KB)
- Primary slot (BOOT partition) starting at address `WOLFBOOT_PARTITION_BOOT_ADDRESS` - Primary slot (BOOT partition) starting at address `WOLFBOOT_PARTITION_BOOT_ADDRESS`
- Secondary slot (UPDATE partition) starting at address `WOLFBOOT_PARTITION_UPDATE_ADDRESS` - Secondary slot (UPDATE partition) starting at address `WOLFBOOT_PARTITION_UPDATE_ADDRESS`
- both partitions share the same size, defined as `WOLFBOOT_PARTITION_SIZE` - both partitions share the same size, defined as `WOLFBOOT_PARTITION_SIZE` (unless
`WOLFBOOT_PARTITION_UPDATE_SIZE` is set, only allowed in monolithic self-update mode)
- Swapping space (SWAP partition) starting at address `WOLFBOOT_PARTITION_SWAP_ADDRESS` - Swapping space (SWAP partition) starting at address `WOLFBOOT_PARTITION_SWAP_ADDRESS`
- the swap space size is defined as `WOLFBOOT_SECTOR_SIZE` and must be as big as the - the swap space size is defined as `WOLFBOOT_SECTOR_SIZE` and must be as big as the
largest sector used in either BOOT/UPDATE partitions. largest sector used in either BOOT/UPDATE partitions.

View File

@ -84,7 +84,8 @@ EOF
``` ```
Change `WOLFBOOT_PARTITION_SIZE` accordingly. `wolfBoot_open_image_address()` will discard images larger than Change `WOLFBOOT_PARTITION_SIZE` accordingly. `wolfBoot_open_image_address()` will discard images larger than
`WOLFBOOT_PARTITION_SIZE` - `IMAGE_HEADER_SIZE`. the target slot size (`WOLFBOOT_PARTITION_SIZE`, or `WOLFBOOT_PARTITION_UPDATE_SIZE` for the update slot)
minus `IMAGE_HEADER_SIZE`.
Step 3: compile keytools and create keys. Step 3: compile keytools and create keys.

View File

@ -95,6 +95,15 @@
#ifndef WOLFBOOT_PARTITION_SIZE #ifndef WOLFBOOT_PARTITION_SIZE
#define WOLFBOOT_PARTITION_SIZE @WOLFBOOT_PARTITION_SIZE@ #define WOLFBOOT_PARTITION_SIZE @WOLFBOOT_PARTITION_SIZE@
#endif #endif
/* Optional independently sized UPDATE partition (requires
* WOLFBOOT_SELF_UPDATE_MONOLITHIC when different from
* WOLFBOOT_PARTITION_SIZE) */
#ifndef WOLFBOOT_PARTITION_UPDATE_SIZE
@WOLFBOOT_PARTITION_UPDATE_SIZE_DEFINE@
#endif
#ifndef WOLFBOOT_PARTITION_UPDATE_SIZE
#define WOLFBOOT_PARTITION_UPDATE_SIZE WOLFBOOT_PARTITION_SIZE
#endif
#ifdef WOLFBOOT_SELF_HEADER #ifdef WOLFBOOT_SELF_HEADER
#if defined(WOLFBOOT_PART_USE_ARCH_OFFSET) #if defined(WOLFBOOT_PART_USE_ARCH_OFFSET)
#if !defined(EXT_FLASH) || (defined(EXT_FLASH) && !defined(WOLFBOOT_SELF_HEADER_EXT)) #if !defined(EXT_FLASH) || (defined(EXT_FLASH) && !defined(WOLFBOOT_SELF_HEADER_EXT))
@ -122,7 +131,7 @@
((WOLFBOOT_PARTITION_BOOT_ADDRESS + 0 + WOLFBOOT_PARTITION_SIZE + 0) > \ ((WOLFBOOT_PARTITION_BOOT_ADDRESS + 0 + WOLFBOOT_PARTITION_SIZE + 0) > \
(WOLFBOOT_PARTITION_UPDATE_ADDRESS + 0)) && \ (WOLFBOOT_PARTITION_UPDATE_ADDRESS + 0)) && \
((WOLFBOOT_PARTITION_BOOT_ADDRESS + 0) < \ ((WOLFBOOT_PARTITION_BOOT_ADDRESS + 0) < \
(WOLFBOOT_PARTITION_UPDATE_ADDRESS + 0 + WOLFBOOT_PARTITION_SIZE + 0)) (WOLFBOOT_PARTITION_UPDATE_ADDRESS + 0 + WOLFBOOT_PARTITION_UPDATE_SIZE + 0))
#error "Boot and update partitions overlap" #error "Boot and update partitions overlap"
#endif #endif
@ -138,7 +147,7 @@
#if !defined(PART_UPDATE_EXT) && !defined(PART_SWAP_EXT) && \ #if !defined(PART_UPDATE_EXT) && !defined(PART_SWAP_EXT) && \
((WOLFBOOT_PARTITION_UPDATE_ADDRESS + 0) != 0) && \ ((WOLFBOOT_PARTITION_UPDATE_ADDRESS + 0) != 0) && \
((WOLFBOOT_PARTITION_SWAP_ADDRESS + 0) != 0) && \ ((WOLFBOOT_PARTITION_SWAP_ADDRESS + 0) != 0) && \
((WOLFBOOT_PARTITION_UPDATE_ADDRESS + 0 + WOLFBOOT_PARTITION_SIZE + 0) > \ ((WOLFBOOT_PARTITION_UPDATE_ADDRESS + 0 + WOLFBOOT_PARTITION_UPDATE_SIZE + 0) > \
(WOLFBOOT_PARTITION_SWAP_ADDRESS + 0)) && \ (WOLFBOOT_PARTITION_SWAP_ADDRESS + 0)) && \
((WOLFBOOT_PARTITION_UPDATE_ADDRESS + 0) < \ ((WOLFBOOT_PARTITION_UPDATE_ADDRESS + 0) < \
(WOLFBOOT_PARTITION_SWAP_ADDRESS + 0 + WOLFBOOT_SECTOR_SIZE)) (WOLFBOOT_PARTITION_SWAP_ADDRESS + 0 + WOLFBOOT_SECTOR_SIZE))
@ -173,7 +182,7 @@
WOLFBOOT_DIAGNOSTICS_SECTORS * WOLFBOOT_SECTOR_SIZE) > \ WOLFBOOT_DIAGNOSTICS_SECTORS * WOLFBOOT_SECTOR_SIZE) > \
(WOLFBOOT_PARTITION_UPDATE_ADDRESS + 0)) && \ (WOLFBOOT_PARTITION_UPDATE_ADDRESS + 0)) && \
((WOLFBOOT_DIAGNOSTICS_ADDRESS + 0) < \ ((WOLFBOOT_DIAGNOSTICS_ADDRESS + 0) < \
(WOLFBOOT_PARTITION_UPDATE_ADDRESS + 0 + WOLFBOOT_PARTITION_SIZE + 0)) (WOLFBOOT_PARTITION_UPDATE_ADDRESS + 0 + WOLFBOOT_PARTITION_UPDATE_SIZE + 0))
#error "Diagnostics region overlaps the update partition" #error "Diagnostics region overlaps the update partition"
#endif #endif

View File

@ -547,6 +547,21 @@ extern "C" {
#endif #endif
#endif #endif
/* The UPDATE partition may be sized independently of BOOT, but only in
* monolithic self-update mode: the swap-based update machinery requires
* equal-size partitions. Defaults to the symmetric layout. */
#ifndef WOLFBOOT_PARTITION_UPDATE_SIZE
#define WOLFBOOT_PARTITION_UPDATE_SIZE WOLFBOOT_PARTITION_SIZE
#endif
#if !defined(WOLFBOOT_SELF_UPDATE_MONOLITHIC) && \
((WOLFBOOT_PARTITION_UPDATE_SIZE + 0) != (WOLFBOOT_PARTITION_SIZE + 0))
#error "WOLFBOOT_PARTITION_UPDATE_SIZE != WOLFBOOT_PARTITION_SIZE requires SELF_UPDATE_MONOLITHIC=1"
#endif
#if defined(EXT_ENCRYPTED) && \
((WOLFBOOT_PARTITION_UPDATE_SIZE + 0) != (WOLFBOOT_PARTITION_SIZE + 0))
#error "Asymmetric WOLFBOOT_PARTITION_UPDATE_SIZE is not supported with ENCRYPT"
#endif
#if defined(DISABLE_BACKUP) && defined(DELTA_UPDATES) #if defined(DISABLE_BACKUP) && defined(DELTA_UPDATES)
#error "DELTA_UPDATES requires swap partition (incompatible with DISABLE_BACKUP)" #error "DELTA_UPDATES requires swap partition (incompatible with DISABLE_BACKUP)"
#endif #endif

View File

@ -1482,6 +1482,11 @@ uint32_t wolfBoot_image_size(uint8_t *image)
int wolfBoot_open_image_address(struct wolfBoot_image *img, uint8_t *image) int wolfBoot_open_image_address(struct wolfBoot_image *img, uint8_t *image)
{ {
uint32_t *magic = (uint32_t *)(image); uint32_t *magic = (uint32_t *)(image);
#ifdef WOLFBOOT_FIXED_PARTITIONS
/* The UPDATE slot may be larger than BOOT (monolithic self-update) */
uint32_t part_size = (img->part == PART_UPDATE) ?
WOLFBOOT_PARTITION_UPDATE_SIZE : WOLFBOOT_PARTITION_SIZE;
#endif
if (*magic != WOLFBOOT_MAGIC) { if (*magic != WOLFBOOT_MAGIC) {
wolfBoot_printf("Partition %d header magic 0x%08x invalid at %p\n", wolfBoot_printf("Partition %d header magic 0x%08x invalid at %p\n",
img->part, (unsigned int)*magic, img->hdr); img->part, (unsigned int)*magic, img->hdr);
@ -1490,17 +1495,17 @@ int wolfBoot_open_image_address(struct wolfBoot_image *img, uint8_t *image)
img->fw_size = wolfBoot_image_size(image); img->fw_size = wolfBoot_image_size(image);
#ifdef WOLFBOOT_FIXED_PARTITIONS #ifdef WOLFBOOT_FIXED_PARTITIONS
if (img->fw_size > (WOLFBOOT_PARTITION_SIZE - IMAGE_HEADER_SIZE)) { if (img->fw_size > (part_size - IMAGE_HEADER_SIZE)) {
wolfBoot_printf("Image size %u > max %u\n", wolfBoot_printf("Image size %u > max %u\n",
(unsigned int)img->fw_size, (unsigned int)img->fw_size,
(unsigned int)(WOLFBOOT_PARTITION_SIZE - IMAGE_HEADER_SIZE)); (unsigned int)(part_size - IMAGE_HEADER_SIZE));
img->fw_size = WOLFBOOT_PARTITION_SIZE - IMAGE_HEADER_SIZE; img->fw_size = part_size - IMAGE_HEADER_SIZE;
return -1; return -1;
} }
if (!img->hdr_ok) { if (!img->hdr_ok) {
img->hdr = image; img->hdr = image;
} }
img->trailer = img->hdr + WOLFBOOT_PARTITION_SIZE; img->trailer = img->hdr + part_size;
#else #else
#ifdef WOLFBOOT_RAMBOOT_MAX_SIZE #ifdef WOLFBOOT_RAMBOOT_MAX_SIZE
if (img->fw_size > WOLFBOOT_RAMBOOT_MAX_SIZE) { if (img->fw_size > WOLFBOOT_RAMBOOT_MAX_SIZE) {
@ -1792,10 +1797,25 @@ int wolfBoot_open_self_address(struct wolfBoot_image* img, uint8_t* hdr,
img->hdr = hdr; img->hdr = hdr;
img->fw_size = wolfBoot_image_size(hdr); img->fw_size = wolfBoot_image_size(hdr);
#ifdef WOLFBOOT_FIXED_PARTITIONS #ifdef WOLFBOOT_FIXED_PARTITIONS
#ifdef WOLFBOOT_SELF_UPDATE_MONOLITHIC
/* A monolithic self image spans the bootloader region and the BOOT
* partition minus its trailer sector (header persisted separately,
* not part of the span) */
{
uint32_t max_span = (uint32_t)(WOLFBOOT_PARTITION_BOOT_ADDRESS -
ARCH_FLASH_OFFSET) + WOLFBOOT_PARTITION_SIZE -
WOLFBOOT_SECTOR_SIZE;
if (img->fw_size > max_span) {
img->fw_size = max_span;
return -1;
}
}
#else
if (img->fw_size > (WOLFBOOT_PARTITION_SIZE - IMAGE_HEADER_SIZE)) { if (img->fw_size > (WOLFBOOT_PARTITION_SIZE - IMAGE_HEADER_SIZE)) {
img->fw_size = WOLFBOOT_PARTITION_SIZE - IMAGE_HEADER_SIZE; img->fw_size = WOLFBOOT_PARTITION_SIZE - IMAGE_HEADER_SIZE;
return -1; return -1;
} }
#endif
#endif #endif
wolfBoot_image_set_fw_base(img, image); wolfBoot_image_set_fw_base(img, image);
img->part = PART_SELF; img->part = PART_SELF;

View File

@ -138,9 +138,15 @@ int wolfBoot_initialize_encryption(void)
/* Despite the name, ENCRYPT_TMP_SECRET_OFFSET* set the end-of-partition
* trailer position for all builds (PART_*_ENDFLAGS derive from them); only
* encrypted builds also keep the tmp key/nonce there. */
#if defined(EXT_FLASH) && defined(EXT_ENCRYPTED) #if defined(EXT_FLASH) && defined(EXT_ENCRYPTED)
#define ENCRYPT_TMP_SECRET_OFFSET (WOLFBOOT_PARTITION_SIZE - \ #define ENCRYPT_TMP_SECRET_OFFSET (WOLFBOOT_PARTITION_SIZE - \
(TRAILER_SKIP + ENCRYPT_KEY_SIZE + ENCRYPT_NONCE_SIZE)) (TRAILER_SKIP + ENCRYPT_KEY_SIZE + ENCRYPT_NONCE_SIZE))
/* Same trailer layout at the end of the (possibly larger) UPDATE slot */
#define ENCRYPT_TMP_SECRET_OFFSET_UPDATE (WOLFBOOT_PARTITION_UPDATE_SIZE - \
(TRAILER_SKIP + ENCRYPT_KEY_SIZE + ENCRYPT_NONCE_SIZE))
#define TRAILER_OVERHEAD (4 + 1 + (WOLFBOOT_PARTITION_SIZE / \ #define TRAILER_OVERHEAD (4 + 1 + (WOLFBOOT_PARTITION_SIZE / \
(2 * WOLFBOOT_SECTOR_SIZE))) (2 * WOLFBOOT_SECTOR_SIZE)))
/* MAGIC (4B) + PART_FLAG (1B) + (N_SECTORS / 2) */ /* MAGIC (4B) + PART_FLAG (1B) + (N_SECTORS / 2) */
@ -150,6 +156,8 @@ int wolfBoot_initialize_encryption(void)
/* MAGIC (4B) + PART_FLAG (1B) + ENCRYPT_KEY_SIZE + ENCRYPT_NONCE_SIZE */ /* MAGIC (4B) + PART_FLAG (1B) + ENCRYPT_KEY_SIZE + ENCRYPT_NONCE_SIZE */
#else #else
#define ENCRYPT_TMP_SECRET_OFFSET (WOLFBOOT_PARTITION_SIZE - (TRAILER_SKIP)) #define ENCRYPT_TMP_SECRET_OFFSET (WOLFBOOT_PARTITION_SIZE - (TRAILER_SKIP))
#define ENCRYPT_TMP_SECRET_OFFSET_UPDATE \
(WOLFBOOT_PARTITION_UPDATE_SIZE - (TRAILER_SKIP))
#define SECTOR_FLAGS_SIZE (WOLFBOOT_SECTOR_SIZE - (4 + 1)) #define SECTOR_FLAGS_SIZE (WOLFBOOT_SECTOR_SIZE - (4 + 1))
/* MAGIC (4B) + PART_FLAG (1B) */ /* MAGIC (4B) + PART_FLAG (1B) */
#endif /* EXT_FLASH && EXT_ENCRYPTED */ #endif /* EXT_FLASH && EXT_ENCRYPTED */
@ -232,7 +240,7 @@ static const uint32_t wolfboot_magic_trail = WOLFBOOT_MAGIC_TRAIL;
#define FLAGS_UPDATE_EXT() PARTN_IS_EXT(PART_BOOT) #define FLAGS_UPDATE_EXT() PARTN_IS_EXT(PART_BOOT)
#else #else
/* FLAGS are at the end of each partition */ /* FLAGS are at the end of each partition */
#define PART_UPDATE_ENDFLAGS (WOLFBOOT_PARTITION_UPDATE_ADDRESS + ENCRYPT_TMP_SECRET_OFFSET) #define PART_UPDATE_ENDFLAGS (WOLFBOOT_PARTITION_UPDATE_ADDRESS + ENCRYPT_TMP_SECRET_OFFSET_UPDATE)
#define FLAGS_UPDATE_EXT() PARTN_IS_EXT(PART_UPDATE) #define FLAGS_UPDATE_EXT() PARTN_IS_EXT(PART_UPDATE)
#endif #endif
@ -828,7 +836,7 @@ void RAMFUNCTION wolfBoot_erase_partition(uint8_t part)
break; break;
case PART_UPDATE: case PART_UPDATE:
address = (uintptr_t)WOLFBOOT_PARTITION_UPDATE_ADDRESS; address = (uintptr_t)WOLFBOOT_PARTITION_UPDATE_ADDRESS;
size = WOLFBOOT_PARTITION_SIZE; size = WOLFBOOT_PARTITION_UPDATE_SIZE;
break; break;
case PART_SWAP: case PART_SWAP:
address = (uintptr_t)WOLFBOOT_PARTITION_SWAP_ADDRESS; address = (uintptr_t)WOLFBOOT_PARTITION_SWAP_ADDRESS;
@ -2583,7 +2591,7 @@ static uint8_t RAMFUNCTION part_address(uintptr_t a)
(a >= WOLFBOOT_PARTITION_UPDATE_ADDRESS) && (a >= WOLFBOOT_PARTITION_UPDATE_ADDRESS) &&
#endif #endif
#endif #endif
(a < WOLFBOOT_PARTITION_UPDATE_ADDRESS + WOLFBOOT_PARTITION_SIZE)) (a < WOLFBOOT_PARTITION_UPDATE_ADDRESS + WOLFBOOT_PARTITION_UPDATE_SIZE))
return PART_UPDATE; return PART_UPDATE;
if ( 1 && if ( 1 &&
#if !defined(WOLFBOOT_PART_USE_ARCH_OFFSET) && !defined(PULL_LINKER_DEFINES) #if !defined(WOLFBOOT_PART_USE_ARCH_OFFSET) && !defined(PULL_LINKER_DEFINES)
@ -2980,9 +2988,9 @@ int wolfBoot_nsc_erase_update(uint32_t address, uint32_t len)
{ {
int ret; int ret;
if (address > WOLFBOOT_PARTITION_SIZE) if (address > WOLFBOOT_PARTITION_UPDATE_SIZE)
return -1; return -1;
if (len > WOLFBOOT_PARTITION_SIZE - address) if (len > WOLFBOOT_PARTITION_UPDATE_SIZE - address)
return -1; return -1;
#ifdef PART_UPDATE_EXT #ifdef PART_UPDATE_EXT
@ -3002,9 +3010,9 @@ int wolfBoot_nsc_write_update(uint32_t address, const uint8_t *buf, uint32_t len
{ {
int ret; int ret;
if (address > WOLFBOOT_PARTITION_SIZE) if (address > WOLFBOOT_PARTITION_UPDATE_SIZE)
return -1; return -1;
if (len > WOLFBOOT_PARTITION_SIZE - address) if (len > WOLFBOOT_PARTITION_UPDATE_SIZE - address)
return -1; return -1;
if (len > 0 && WOLFBOOT_NSC_NS_RW(buf, len) == NULL) if (len > 0 && WOLFBOOT_NSC_NS_RW(buf, len) == NULL)
return -1; return -1;

View File

@ -236,6 +236,18 @@ void RAMFUNCTION wolfBoot_check_self_update(void)
wolfBoot_erase_partition(PART_UPDATE); wolfBoot_erase_partition(PART_UPDATE);
return; return;
} }
#ifdef WOLFBOOT_SELF_UPDATE_MONOLITHIC
/* Payload installs at ARCH_FLASH_OFFSET and may spill into the BOOT
* partition, but must never reach BOOT's last sector (reserved for
* the state trailer) or the UPDATE partition staging it */
if (update.fw_size > (uint32_t)(WOLFBOOT_PARTITION_BOOT_ADDRESS -
ARCH_FLASH_OFFSET) + WOLFBOOT_PARTITION_SIZE -
WOLFBOOT_SECTOR_SIZE) {
wolfBoot_printf("Self update image too large: %u\n",
(unsigned int)update.fw_size);
return;
}
#endif
if (wolfBoot_verify_integrity(&update) < 0) { if (wolfBoot_verify_integrity(&update) < 0) {
#ifdef WOLFBOOT_PERSIST_FAILURE_STATUS #ifdef WOLFBOOT_PERSIST_FAILURE_STATUS
wolfBoot_record_verify_failure(WOLFBOOT_FAILURE_PHASE_SELF_UPDATE, wolfBoot_record_verify_failure(WOLFBOOT_FAILURE_PHASE_SELF_UPDATE,

View File

@ -185,6 +185,7 @@ $(LSCRIPT): $(LSCRIPT_IN) FORCE
sed -e "s/@WOLFBOOT_DTS_UPDATE_ADDRESS@/$(WOLFBOOT_DTS_UPDATE_ADDRESS)/g" | \ sed -e "s/@WOLFBOOT_DTS_UPDATE_ADDRESS@/$(WOLFBOOT_DTS_UPDATE_ADDRESS)/g" | \
sed -e "s/@WOLFBOOT_LOAD_ADDRESS@/$(WOLFBOOT_LOAD_ADDRESS)/g" | \ sed -e "s/@WOLFBOOT_LOAD_ADDRESS@/$(WOLFBOOT_LOAD_ADDRESS)/g" | \
sed -e "s/@WOLFBOOT_LOAD_DTS_ADDRESS@/$(WOLFBOOT_LOAD_DTS_ADDRESS)/g" | \ sed -e "s/@WOLFBOOT_LOAD_DTS_ADDRESS@/$(WOLFBOOT_LOAD_DTS_ADDRESS)/g" | \
sed -e "s|@WOLFBOOT_PARTITION_UPDATE_SIZE_DEFINE@|$(if $(strip $(WOLFBOOT_PARTITION_UPDATE_SIZE)),#define WOLFBOOT_PARTITION_UPDATE_SIZE $(WOLFBOOT_PARTITION_UPDATE_SIZE),/* WOLFBOOT_PARTITION_UPDATE_SIZE not set */)|g" | \
sed -e "s|@WOLFBOOT_RAMBOOT_MAX_SIZE_DEFINE@|$(if $(strip $(WOLFBOOT_RAMBOOT_MAX_SIZE)),#define WOLFBOOT_RAMBOOT_MAX_SIZE $(WOLFBOOT_RAMBOOT_MAX_SIZE),/* WOLFBOOT_RAMBOOT_MAX_SIZE undefined */)|g" \ sed -e "s|@WOLFBOOT_RAMBOOT_MAX_SIZE_DEFINE@|$(if $(strip $(WOLFBOOT_RAMBOOT_MAX_SIZE)),#define WOLFBOOT_RAMBOOT_MAX_SIZE $(WOLFBOOT_RAMBOOT_MAX_SIZE),/* WOLFBOOT_RAMBOOT_MAX_SIZE undefined */)|g" \
> $@ > $@

View File

@ -1947,6 +1947,7 @@ static int make_header_ex(int is_diff, uint8_t *pubkey, uint32_t pubkey_sz,
pos += read_sz; pos += read_sz;
} }
fclose(f); fclose(f);
f = NULL;
if (ret == 0) { if (ret == 0) {
wc_Sha256Final(&sha, digest); wc_Sha256Final(&sha, digest);
digest_sz = HDR_SHA256_LEN; digest_sz = HDR_SHA256_LEN;
@ -2023,6 +2024,7 @@ static int make_header_ex(int is_diff, uint8_t *pubkey, uint32_t pubkey_sz,
pos += read_sz; pos += read_sz;
} }
fclose(f); fclose(f);
f = NULL;
if (ret == 0) { if (ret == 0) {
wc_Sha384Final(&sha, digest); wc_Sha384Final(&sha, digest);
digest_sz = HDR_SHA384_LEN; digest_sz = HDR_SHA384_LEN;
@ -2097,6 +2099,7 @@ static int make_header_ex(int is_diff, uint8_t *pubkey, uint32_t pubkey_sz,
pos += read_sz; pos += read_sz;
} }
fclose(f); fclose(f);
f = NULL;
if (ret == 0) { if (ret == 0) {
ret = wc_Sha3_384_Final(&sha, digest); ret = wc_Sha3_384_Final(&sha, digest);
digest_sz = HDR_SHA3_384_LEN; digest_sz = HDR_SHA3_384_LEN;
@ -2311,8 +2314,18 @@ static int make_header_ex(int is_diff, uint8_t *pubkey, uint32_t pubkey_sz,
/* Check if signed image fits in partition */ /* Check if signed image fits in partition */
{ {
const char *psize_name = "WOLFBOOT_PARTITION_SIZE";
const char *env_psize = getenv("WOLFBOOT_PARTITION_SIZE"); const char *env_psize = getenv("WOLFBOOT_PARTITION_SIZE");
const char *env_ssize = getenv("WOLFBOOT_SECTOR_SIZE"); const char *env_ssize = getenv("WOLFBOOT_SECTOR_SIZE");
if (CMD.self_update) {
/* self-update images are staged in the UPDATE partition, which
* may be larger than BOOT (monolithic self-update) */
const char *env_usize = getenv("WOLFBOOT_PARTITION_UPDATE_SIZE");
if (env_usize && *env_usize) {
env_psize = env_usize;
psize_name = "WOLFBOOT_PARTITION_UPDATE_SIZE";
}
}
if (env_psize && *env_psize) { if (env_psize && *env_psize) {
char *endptr; char *endptr;
unsigned long tmp; unsigned long tmp;
@ -2325,8 +2338,8 @@ static int make_header_ex(int is_diff, uint8_t *pubkey, uint32_t pubkey_sz,
tmp = strtoul(env_psize, &endptr, 0); tmp = strtoul(env_psize, &endptr, 0);
if (endptr == env_psize || *endptr != '\0' || if (endptr == env_psize || *endptr != '\0' ||
errno == ERANGE || tmp == 0 || tmp > UINT32_MAX) { errno == ERANGE || tmp == 0 || tmp > UINT32_MAX) {
printf("Error: Invalid WOLFBOOT_PARTITION_SIZE '%s'\n", printf("Error: Invalid %s '%s'\n", psize_name, env_psize);
env_psize); ret = -1;
goto failure; goto failure;
} }
partition_sz = (uint32_t)tmp; partition_sz = (uint32_t)tmp;
@ -2338,6 +2351,7 @@ static int make_header_ex(int is_diff, uint8_t *pubkey, uint32_t pubkey_sz,
errno == ERANGE || tmp == 0 || tmp > UINT32_MAX) { errno == ERANGE || tmp == 0 || tmp > UINT32_MAX) {
printf("Error: Invalid WOLFBOOT_SECTOR_SIZE '%s'\n", printf("Error: Invalid WOLFBOOT_SECTOR_SIZE '%s'\n",
env_ssize); env_ssize);
ret = -1;
goto failure; goto failure;
} }
sector_sz = (uint32_t)tmp; sector_sz = (uint32_t)tmp;
@ -2359,17 +2373,18 @@ static int make_header_ex(int is_diff, uint8_t *pubkey, uint32_t pubkey_sz,
if (total_img_sz > max_img_sz) { if (total_img_sz > max_img_sz) {
if (sector_sz < partition_sz) { if (sector_sz < partition_sz) {
printf("Error: Image size %u (header %u + firmware %u) " printf("Error: Image size %u (header %u + firmware %u) "
"exceeds max %u (partition %u - %d x sector %u)\n", "exceeds max %u (%s %u - %d x sector %u)\n",
total_img_sz, CMD.header_sz, image_sz, total_img_sz, CMD.header_sz, image_sz,
max_img_sz, partition_sz, max_img_sz, psize_name, partition_sz,
nvm_writeonce ? 2 : 1, nvm_writeonce ? 2 : 1,
sector_sz); sector_sz);
} else { } else {
printf("Error: Image size %u (header %u + firmware %u) " printf("Error: Image size %u (header %u + firmware %u) "
"exceeds max %u (partition %u)\n", "exceeds max %u (%s %u)\n",
total_img_sz, CMD.header_sz, image_sz, total_img_sz, CMD.header_sz, image_sz,
max_img_sz, partition_sz); max_img_sz, psize_name, partition_sz);
} }
ret = -1;
goto failure; goto failure;
} }
} }

View File

@ -279,9 +279,9 @@ test-sim-self-update-monolithic: wolfboot.bin test-app/image_v1_signed.bin FORCE
@# Sign monolithic payload as wolfBoot self-update v2 @# Sign monolithic payload as wolfBoot self-update v2
$(Q)$(SIGN_ENV) $(SIGN_TOOL) $(SIGN_OPTIONS) --wolfboot-update monolithic_payload.bin $(PRIVATE_KEY) 2 $(Q)$(SIGN_ENV) $(SIGN_TOOL) $(SIGN_OPTIONS) --wolfboot-update monolithic_payload.bin $(PRIVATE_KEY) 2
@# Create update partition with signed monolithic image and "pBOOT" trailer @# Create update partition with signed monolithic image and "pBOOT" trailer
$(Q)dd if=/dev/zero bs=$$(($(WOLFBOOT_PARTITION_SIZE))) count=1 2>/dev/null | tr '\000' '\377' > update_part.dd $(Q)dd if=/dev/zero bs=$$(($(or $(WOLFBOOT_PARTITION_UPDATE_SIZE),$(WOLFBOOT_PARTITION_SIZE)))) count=1 2>/dev/null | tr '\000' '\377' > update_part.dd
$(Q)dd if=monolithic_payload_v2_signed.bin of=update_part.dd bs=1 conv=notrunc $(Q)dd if=monolithic_payload_v2_signed.bin of=update_part.dd bs=1 conv=notrunc
$(Q)printf "pBOOT" | dd of=update_part.dd bs=1 seek=$$(($(WOLFBOOT_PARTITION_SIZE) - 5)) conv=notrunc $(Q)printf "pBOOT" | dd of=update_part.dd bs=1 seek=$$(($(or $(WOLFBOOT_PARTITION_UPDATE_SIZE),$(WOLFBOOT_PARTITION_SIZE)) - 5)) conv=notrunc
@# Create erased boot partition @# Create erased boot partition
$(Q)dd if=/dev/zero bs=$$(($(WOLFBOOT_PARTITION_SIZE))) count=1 2>/dev/null | tr '\000' '\377' > boot_part.dd $(Q)dd if=/dev/zero bs=$$(($(WOLFBOOT_PARTITION_SIZE))) count=1 2>/dev/null | tr '\000' '\377' > boot_part.dd
@# Assemble flash: wolfboot.bin at 0, empty boot partition, update partition @# Assemble flash: wolfboot.bin at 0, empty boot partition, update partition
@ -315,9 +315,9 @@ test-sim-self-update-monolithic-self-header: wolfboot.bin test-app/image_v1_sign
$(Q)$(SIGN_ENV) $(SIGN_TOOL) $(SIGN_OPTIONS) --wolfboot-update monolithic_payload.bin $(PRIVATE_KEY) 2 $(Q)$(SIGN_ENV) $(SIGN_TOOL) $(SIGN_OPTIONS) --wolfboot-update monolithic_payload.bin $(PRIVATE_KEY) 2
$(Q)$(SIGN_ENV) $(SIGN_TOOL) $(SIGN_OPTIONS) --wolfboot-update --header-only monolithic_payload.bin $(PRIVATE_KEY) 2 $(Q)$(SIGN_ENV) $(SIGN_TOOL) $(SIGN_OPTIONS) --wolfboot-update --header-only monolithic_payload.bin $(PRIVATE_KEY) 2
@# Create update partition with signed monolithic image and "pBOOT" trailer @# Create update partition with signed monolithic image and "pBOOT" trailer
$(Q)dd if=/dev/zero bs=$$(($(WOLFBOOT_PARTITION_SIZE))) count=1 2>/dev/null | tr '\000' '\377' > update_part.dd $(Q)dd if=/dev/zero bs=$$(($(or $(WOLFBOOT_PARTITION_UPDATE_SIZE),$(WOLFBOOT_PARTITION_SIZE)))) count=1 2>/dev/null | tr '\000' '\377' > update_part.dd
$(Q)dd if=monolithic_payload_v2_signed.bin of=update_part.dd bs=1 conv=notrunc $(Q)dd if=monolithic_payload_v2_signed.bin of=update_part.dd bs=1 conv=notrunc
$(Q)printf "pBOOT" | dd of=update_part.dd bs=1 seek=$$(($(WOLFBOOT_PARTITION_SIZE) - 5)) conv=notrunc $(Q)printf "pBOOT" | dd of=update_part.dd bs=1 seek=$$(($(or $(WOLFBOOT_PARTITION_UPDATE_SIZE),$(WOLFBOOT_PARTITION_SIZE)) - 5)) conv=notrunc
@# Create erased boot partition and self-header sector @# Create erased boot partition and self-header sector
$(Q)dd if=/dev/zero bs=$$(($(WOLFBOOT_PARTITION_SIZE))) count=1 2>/dev/null | tr '\000' '\377' > boot_part.dd $(Q)dd if=/dev/zero bs=$$(($(WOLFBOOT_PARTITION_SIZE))) count=1 2>/dev/null | tr '\000' '\377' > boot_part.dd
$(Q)dd if=/dev/zero bs=$$(($(WOLFBOOT_SECTOR_SIZE))) count=1 2>/dev/null | tr '\000' '\377' > self_hdr.dd $(Q)dd if=/dev/zero bs=$$(($(WOLFBOOT_SECTOR_SIZE))) count=1 2>/dev/null | tr '\000' '\377' > self_hdr.dd