Skip to content

Commit aba5f61

Browse files
committed
bootutil: swap-move: Allow unaligned trailer sector during move
The swap-move strategy is currently assuming the trailer is stored in dedicated sector, meaning the size of the area allocated to the trailer must be a multiple of the sector size. This commit relaxes this assumption when moving sectors up in the primary slot by allowing the last sector containing firmware data to also hold part of the trailer (or the whole trailer if it is small enough). Signed-off-by: Thomas Altenbach <[email protected]>
1 parent 94610b8 commit aba5f61

File tree

1 file changed

+32
-10
lines changed

1 file changed

+32
-10
lines changed

boot/bootutil/src/swap_move.c

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -379,13 +379,15 @@ swap_status_source(struct boot_loader_state *state)
379379
* "Moves" the sector located at idx - 1 to idx.
380380
*/
381381
static void
382-
boot_move_sector_up(int idx, uint32_t sz, struct boot_loader_state *state,
382+
boot_move_sector_up(size_t idx, uint32_t sz, struct boot_loader_state *state,
383383
struct boot_status *bs, const struct flash_area *fap_pri,
384384
const struct flash_area *fap_sec)
385385
{
386386
uint32_t new_off;
387387
uint32_t old_off;
388+
uint32_t copy_sz;
388389
int rc;
390+
bool sector_erased_with_trailer;
389391

390392
/*
391393
* FIXME: assuming sectors of size == sz, a single off variable
@@ -396,14 +398,32 @@ boot_move_sector_up(int idx, uint32_t sz, struct boot_loader_state *state,
396398
new_off = boot_img_sector_off(state, BOOT_PRIMARY_SLOT, idx);
397399
old_off = boot_img_sector_off(state, BOOT_PRIMARY_SLOT, idx - 1);
398400

401+
copy_sz = sz;
402+
sector_erased_with_trailer = false;
403+
399404
if (bs->idx == BOOT_STATUS_IDX_0) {
400-
if (bs->source != BOOT_STATUS_SOURCE_PRIMARY_SLOT) {
401-
/* Remove data and prepare for write on devices requiring erase */
402-
rc = swap_scramble_trailer_sectors(state, fap_pri);
403-
assert(rc == 0);
405+
rc = swap_scramble_trailer_sectors(state, fap_pri);
406+
assert(rc == 0);
407+
408+
rc = swap_status_init(state, fap_pri, bs);
409+
assert(rc == 0);
404410

405-
rc = swap_status_init(state, fap_pri, bs);
406-
assert(rc == 0);
411+
/* The first sector to be moved is the last sector containing part of the firmware image. If
412+
* the trailer size is not a multiple of the sector size, the destination sector will
413+
* contain both firmware and trailer data. In that case:
414+
* - Only the firmware data must be copied to the destination sector to avoid overwriting
415+
* the trailer data.
416+
* - The destination sector has already been erased with the trailer.
417+
*/
418+
size_t first_trailer_idx = boot_get_first_trailer_sector(state, BOOT_PRIMARY_SLOT);
419+
420+
if (idx == first_trailer_idx) {
421+
/* Swap-move => constant sector size, so 'sz' is the size of a sector and 'swap_size %
422+
* sz' gives the number of bytes used by the largest firmware image in the last sector
423+
* to be moved.
424+
*/
425+
copy_sz = bs->swap_size % sz;
426+
sector_erased_with_trailer = true;
407427
}
408428

409429
/* Remove status from secondary slot trailer, in case of device with
@@ -413,10 +433,12 @@ boot_move_sector_up(int idx, uint32_t sz, struct boot_loader_state *state,
413433
assert(rc == 0);
414434
}
415435

416-
rc = boot_erase_region(fap_pri, new_off, sz);
417-
assert(rc == 0);
436+
if (!sector_erased_with_trailer) {
437+
rc = boot_erase_region(fap_pri, new_off, sz);
438+
assert(rc == 0);
439+
}
418440

419-
rc = boot_copy_region(state, fap_pri, fap_pri, old_off, new_off, sz);
441+
rc = boot_copy_region(state, fap_pri, fap_pri, old_off, new_off, copy_sz);
420442
assert(rc == 0);
421443

422444
rc = boot_write_status(state, bs);

0 commit comments

Comments
 (0)