Skip to content

Commit c333da9

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

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
@@ -377,13 +377,15 @@ swap_status_source(struct boot_loader_state *state)
377377
* "Moves" the sector located at idx - 1 to idx.
378378
*/
379379
static void
380-
boot_move_sector_up(int idx, uint32_t sz, struct boot_loader_state *state,
380+
boot_move_sector_up(size_t idx, uint32_t sz, struct boot_loader_state *state,
381381
struct boot_status *bs, const struct flash_area *fap_pri,
382382
const struct flash_area *fap_sec)
383383
{
384384
uint32_t new_off;
385385
uint32_t old_off;
386+
uint32_t copy_sz;
386387
int rc;
388+
bool sector_erased_with_trailer;
387389

388390
/*
389391
* FIXME: assuming sectors of size == sz, a single off variable
@@ -394,14 +396,32 @@ boot_move_sector_up(int idx, uint32_t sz, struct boot_loader_state *state,
394396
new_off = boot_img_sector_off(state, BOOT_PRIMARY_SLOT, idx);
395397
old_off = boot_img_sector_off(state, BOOT_PRIMARY_SLOT, idx - 1);
396398

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

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

407427
/* Remove status from secondary slot trailer, in case of device with
@@ -411,10 +431,12 @@ boot_move_sector_up(int idx, uint32_t sz, struct boot_loader_state *state,
411431
assert(rc == 0);
412432
}
413433

414-
rc = boot_erase_region(fap_pri, new_off, sz);
415-
assert(rc == 0);
434+
if (!sector_erased_with_trailer) {
435+
rc = boot_erase_region(fap_pri, new_off, sz);
436+
assert(rc == 0);
437+
}
416438

417-
rc = boot_copy_region(state, fap_pri, fap_pri, old_off, new_off, sz);
439+
rc = boot_copy_region(state, fap_pri, fap_pri, old_off, new_off, copy_sz);
418440
assert(rc == 0);
419441

420442
rc = boot_write_status(state, bs);

0 commit comments

Comments
 (0)