From dec13e7f367801655feba0e0ef9cdd31994fdbe0 Mon Sep 17 00:00:00 2001 From: Fabian Otto Date: Mon, 27 Jul 2026 11:09:20 +0200 Subject: [PATCH] boot: bootutil: Do not panic on unreadable primary slot trailer boot_swap_type_multi() returns BOOT_SWAP_TYPE_PANIC whenever the swap state of the primary slot cannot be read. On devices whose flash controller reports a read error for pages that have never been programmed, this happens as soon as part of the primary trailer is still erased, which permanently blocks both booting and firmware recovery. In overwrite-only mode the bootloader never resumes an interrupted swap from the primary trailer and never sets its copy_done flag, so no entry of boot_swap_tables can match on the primary state. An unreachable primary trailer is therefore treated as empty there, the same way an unreachable secondary slot already is. The swap based modes keep returning BOOT_SWAP_TYPE_PANIC, because they do need the primary trailer to resume a swap safely. Signed-off-by: Fabian Otto --- boot/bootutil/src/bootutil_public.c | 34 ++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/boot/bootutil/src/bootutil_public.c b/boot/bootutil/src/bootutil_public.c index 6982edfa62..74aff0c916 100644 --- a/boot/bootutil/src/bootutil_public.c +++ b/boot/bootutil/src/bootutil_public.c @@ -421,6 +421,16 @@ boot_write_swap_info(const struct flash_area *fap, uint8_t swap_type, return boot_write_trailer(fap, off, (const uint8_t *) &swap_info, 1); } +static void +boot_swap_state_set_empty(struct boot_swap_state *state) +{ + state->magic = BOOT_MAGIC_UNSET; + state->swap_type = BOOT_SWAP_TYPE_NONE; + state->copy_done = BOOT_FLAG_UNSET; + state->image_ok = BOOT_FLAG_UNSET; + state->image_num = 0; +} + int boot_swap_type_multi(int image_index) { @@ -437,7 +447,23 @@ boot_swap_type_multi(int image_index) rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_PRIMARY(image_index), &primary_slot); } - if (rc) { + if (rc == BOOT_EFLASH) { +#if defined(MCUBOOT_OVERWRITE_ONLY) + /* No swap is ever resumed from the primary trailer in this mode, so + * its content cannot influence the swap type. Flash controllers that + * report a read error for never programmed pages must therefore not + * be able to block booting and recovery here. + */ + BOOT_LOG_INF("Primary image of image pair (%d) is unreachable. " + "Treat it as empty", image_index); + boot_swap_state_set_empty(&primary_slot); +#else + /* A swap may need to be resumed from the primary trailer, which is + * not possible if it cannot be read. + */ + return BOOT_SWAP_TYPE_PANIC; +#endif + } else if (rc) { return BOOT_SWAP_TYPE_PANIC; } @@ -446,11 +472,7 @@ boot_swap_type_multi(int image_index) if (rc == BOOT_EFLASH) { BOOT_LOG_INF("Secondary image of image pair (%d) is unreachable. Treat it as empty", image_index); - secondary_slot.magic = BOOT_MAGIC_UNSET; - secondary_slot.swap_type = BOOT_SWAP_TYPE_NONE; - secondary_slot.copy_done = BOOT_FLAG_UNSET; - secondary_slot.image_ok = BOOT_FLAG_UNSET; - secondary_slot.image_num = 0; + boot_swap_state_set_empty(&secondary_slot); } else if (rc) { return BOOT_SWAP_TYPE_PANIC; }