Skip to content

Commit 6f329ba

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 <thomas.altenbach@legrand.com>
1 parent c333da9 commit 6f329ba

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
@@ -360,9 +360,14 @@ swap_status_source(struct boot_loader_state *state)
360360
BOOT_LOG_SWAP_STATE("Secondary image", &state_secondary_slot);
361361

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

368373
BOOT_LOG_INF("Boot source: primary slot");
@@ -378,8 +383,7 @@ swap_status_source(struct boot_loader_state *state)
378383
*/
379384
static void
380385
boot_move_sector_up(size_t idx, uint32_t sz, struct boot_loader_state *state,
381-
struct boot_status *bs, const struct flash_area *fap_pri,
382-
const struct flash_area *fap_sec)
386+
struct boot_status *bs, const struct flash_area *fap_pri)
383387
{
384388
uint32_t new_off;
385389
uint32_t old_off;
@@ -423,12 +427,6 @@ boot_move_sector_up(size_t idx, uint32_t sz, struct boot_loader_state *state,
423427
copy_sz = bs->swap_size % sz;
424428
sector_erased_with_trailer = true;
425429
}
426-
427-
/* Remove status from secondary slot trailer, in case of device with
428-
* erase requirement this will also prepare traier for write.
429-
*/
430-
rc = swap_scramble_trailer_sectors(state, fap_sec);
431-
assert(rc == 0);
432430
}
433431

434432
if (!sector_erased_with_trailer) {
@@ -446,7 +444,7 @@ boot_move_sector_up(size_t idx, uint32_t sz, struct boot_loader_state *state,
446444
}
447445

448446
static void
449-
boot_swap_sectors(int idx, uint32_t sz, struct boot_loader_state *state,
447+
boot_swap_sectors(size_t idx, size_t last_idx, uint32_t sz, struct boot_loader_state *state,
450448
struct boot_status *bs, const struct flash_area *fap_pri,
451449
const struct flash_area *fap_sec)
452450
{
@@ -472,10 +470,43 @@ boot_swap_sectors(int idx, uint32_t sz, struct boot_loader_state *state,
472470
}
473471

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

478-
rc = boot_copy_region(state, fap_pri, fap_sec, pri_up_off, sec_off, sz);
509+
rc = boot_copy_region(state, fap_pri, fap_sec, pri_up_off, sec_off, copy_sz);
479510
assert(rc == 0);
480511

481512
rc = boot_write_status(state, bs);
@@ -590,7 +621,7 @@ swap_run(struct boot_loader_state *state, struct boot_status *bs,
590621
idx = last_idx;
591622
while (idx > 0) {
592623
if (idx <= (last_idx - bs->idx + 1)) {
593-
boot_move_sector_up(idx, sector_sz, state, bs, fap_pri, fap_sec);
624+
boot_move_sector_up(idx, sector_sz, state, bs, fap_pri);
594625
}
595626
idx--;
596627
}
@@ -602,7 +633,7 @@ swap_run(struct boot_loader_state *state, struct boot_status *bs,
602633
idx = 1;
603634
while (idx <= last_idx) {
604635
if (idx >= bs->idx) {
605-
boot_swap_sectors(idx, sector_sz, state, bs, fap_pri, fap_sec);
636+
boot_swap_sectors(idx, last_idx, sector_sz, state, bs, fap_pri, fap_sec);
606637
}
607638
idx++;
608639
}

0 commit comments

Comments
 (0)