Skip to content

Commit b428292

Browse files
committed
bootutil: swap-move: Erase secondary trailer during swap
When using the swap-move strategy, the secondary trailer was erased just after the primary trailer, when moving the sectors up in the primary slot. This was working because it was assumed the trailer is stored in dedicated sectors, so no sector could contain both trailer and firmware data. However, if this assumption is relaxed, it means it is no more possible to erase the secondary trailer before the last sector holding firmware data has been copied to the primary slot, since that sector might also contain trailer data. So the erasure of the secondary trailer has to occur at the time the last sector containing firmware data is swapped. Signed-off-by: Thomas Altenbach <[email protected]>
1 parent aba5f61 commit b428292

File tree

1 file changed

+48
-17
lines changed

1 file changed

+48
-17
lines changed

boot/bootutil/src/swap_move.c

Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -362,9 +362,14 @@ swap_status_source(struct boot_loader_state *state)
362362
BOOT_LOG_SWAP_STATE("Secondary image", &state_secondary_slot);
363363

364364
if (state_primary_slot.magic == BOOT_MAGIC_GOOD &&
365-
state_primary_slot.copy_done == BOOT_FLAG_UNSET &&
366-
state_secondary_slot.magic != BOOT_MAGIC_GOOD) {
367-
365+
state_primary_slot.copy_done == BOOT_FLAG_UNSET) {
366+
/* In this case, either:
367+
* - A swap operation was interrupted and can be resumed from the status stored in the
368+
* primary slot's trailer.
369+
* - No swap was ever made and the initial firmware image has been written with a MCUboot
370+
* trailer. In this case, the status in the primary slot's trailer is empty and there is
371+
* no harm in loading it.
372+
*/
368373
source = BOOT_STATUS_SOURCE_PRIMARY_SLOT;
369374

370375
BOOT_LOG_INF("Boot source: primary slot");
@@ -380,8 +385,7 @@ swap_status_source(struct boot_loader_state *state)
380385
*/
381386
static void
382387
boot_move_sector_up(size_t idx, uint32_t sz, struct boot_loader_state *state,
383-
struct boot_status *bs, const struct flash_area *fap_pri,
384-
const struct flash_area *fap_sec)
388+
struct boot_status *bs, const struct flash_area *fap_pri)
385389
{
386390
uint32_t new_off;
387391
uint32_t old_off;
@@ -425,12 +429,6 @@ boot_move_sector_up(size_t idx, uint32_t sz, struct boot_loader_state *state,
425429
copy_sz = bs->swap_size % sz;
426430
sector_erased_with_trailer = true;
427431
}
428-
429-
/* Remove status from secondary slot trailer, in case of device with
430-
* erase requirement this will also prepare traier for write.
431-
*/
432-
rc = swap_scramble_trailer_sectors(state, fap_sec);
433-
assert(rc == 0);
434432
}
435433

436434
if (!sector_erased_with_trailer) {
@@ -448,7 +446,7 @@ boot_move_sector_up(size_t idx, uint32_t sz, struct boot_loader_state *state,
448446
}
449447

450448
static void
451-
boot_swap_sectors(int idx, uint32_t sz, struct boot_loader_state *state,
449+
boot_swap_sectors(size_t idx, size_t last_idx, uint32_t sz, struct boot_loader_state *state,
452450
struct boot_status *bs, const struct flash_area *fap_pri,
453451
const struct flash_area *fap_sec)
454452
{
@@ -474,10 +472,43 @@ boot_swap_sectors(int idx, uint32_t sz, struct boot_loader_state *state,
474472
}
475473

476474
if (bs->state == BOOT_STATUS_STATE_1) {
477-
rc = boot_erase_region(fap_sec, sec_off, sz);
478-
assert(rc == 0);
475+
bool sector_erased_with_trailer = false;
476+
uint32_t copy_sz = sz;
477+
478+
if (idx == last_idx) {
479+
rc = swap_scramble_trailer_sectors(state, fap_sec);
480+
assert(rc == 0);
481+
482+
size_t first_trailer_sector_pri =
483+
boot_get_first_trailer_sector(state, BOOT_PRIMARY_SLOT);
484+
size_t first_trailer_sector_sec =
485+
boot_get_first_trailer_sector(state, BOOT_SECONDARY_SLOT);
486+
487+
if (first_trailer_sector_sec == idx - 1) {
488+
/* The destination sector was containing part of the trailer and has therefore
489+
* already been erased.
490+
*/
491+
sector_erased_with_trailer = true;
492+
}
493+
494+
if (first_trailer_sector_pri == idx) {
495+
/* The source sector contains both firmware and trailer data, so only the firmware
496+
* data must be copied to the destination sector.
497+
*
498+
* Swap-move => constant sector size, so 'sz' is the size of a sector and 'swap_size
499+
* % sz' gives the number of bytes used by the largest firmware image in the last
500+
* sector to be moved.
501+
*/
502+
copy_sz = bs->swap_size % sz;
503+
}
504+
}
505+
506+
if (!sector_erased_with_trailer) {
507+
rc = boot_erase_region(fap_sec, sec_off, sz);
508+
assert(rc == 0);
509+
}
479510

480-
rc = boot_copy_region(state, fap_pri, fap_sec, pri_up_off, sec_off, sz);
511+
rc = boot_copy_region(state, fap_pri, fap_sec, pri_up_off, sec_off, copy_sz);
481512
assert(rc == 0);
482513

483514
rc = boot_write_status(state, bs);
@@ -592,7 +623,7 @@ swap_run(struct boot_loader_state *state, struct boot_status *bs,
592623
idx = last_idx;
593624
while (idx > 0) {
594625
if (idx <= (last_idx - bs->idx + 1)) {
595-
boot_move_sector_up(idx, sector_sz, state, bs, fap_pri, fap_sec);
626+
boot_move_sector_up(idx, sector_sz, state, bs, fap_pri);
596627
}
597628
idx--;
598629
}
@@ -604,7 +635,7 @@ swap_run(struct boot_loader_state *state, struct boot_status *bs,
604635
idx = 1;
605636
while (idx <= last_idx) {
606637
if (idx >= bs->idx) {
607-
boot_swap_sectors(idx, sector_sz, state, bs, fap_pri, fap_sec);
638+
boot_swap_sectors(idx, last_idx, sector_sz, state, bs, fap_pri, fap_sec);
608639
}
609640
idx++;
610641
}

0 commit comments

Comments
 (0)