Skip to content

Commit 08985c9

Browse files
committed
boot: bootutil: Take into account scratch trailer when computing max image size
When using swap-scratch and the trailer is larger than a single sector, the sector containing the last part of the firmware data might only contain a very small part of the trailer and some padding might be necessary between the end of the firmware image and the beginning of the trailer to ensure the scratch trailer won't be overwritten when copying that sector to the scratch area. This commit updates the 'bootutil_max_image_size' routine to take that padding into account. Signed-off-by: Thomas Altenbach <[email protected]>
1 parent e35461d commit 08985c9

File tree

4 files changed

+100
-34
lines changed

4 files changed

+100
-34
lines changed

boot/bootutil/src/bootutil_misc.c

+81-3
Original file line numberDiff line numberDiff line change
@@ -331,12 +331,87 @@ boot_write_enc_key(const struct flash_area *fap, uint8_t slot,
331331
}
332332
#endif
333333

334-
uint32_t bootutil_max_image_size(const struct flash_area *fap)
334+
#ifdef MCUBOOT_SWAP_USING_SCRATCH
335+
size_t
336+
boot_get_first_trailer_sector(struct boot_loader_state *state, size_t slot, size_t trailer_sz)
335337
{
336-
#if defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SINGLE_APPLICATION_SLOT) || \
337-
defined(MCUBOOT_FIRMWARE_LOADER) || defined(MCUBOOT_SINGLE_APPLICATION_SLOT_RAM_LOAD)
338+
size_t first_trailer_sector = boot_img_num_sectors(state, slot) - 1;
339+
size_t sector_sz = boot_img_sector_size(state, slot, first_trailer_sector);
340+
size_t trailer_sector_sz = sector_sz;
341+
342+
while (trailer_sector_sz < trailer_sz) {
343+
/* Consider that the image trailer may span across sectors of different sizes */
344+
--first_trailer_sector;
345+
sector_sz = boot_img_sector_size(state, slot, first_trailer_sector);
346+
347+
trailer_sector_sz += sector_sz;
348+
}
349+
350+
return first_trailer_sector;
351+
}
352+
353+
/**
354+
* Returns the offset to the end of the first sector of a given slot that holds image trailer data.
355+
*
356+
* @param state Current bootloader's state.
357+
* @param slot The index of the slot to consider.
358+
* @param trailer_sz The size of the trailer, in bytes.
359+
*
360+
* @return The offset to the end of the first sector of the slot that holds image trailer data.
361+
*/
362+
static uint32_t
363+
get_first_trailer_sector_end_off(struct boot_loader_state *state, size_t slot, size_t trailer_sz)
364+
{
365+
size_t first_trailer_sector = boot_get_first_trailer_sector(state, slot, trailer_sz);
366+
367+
return boot_img_sector_off(state, slot, first_trailer_sector) +
368+
boot_img_sector_size(state, slot, first_trailer_sector);
369+
}
370+
#endif /* MCUBOOT_SWAP_USING_SCRATCH */
371+
372+
uint32_t bootutil_max_image_size(struct boot_loader_state *state, const struct flash_area *fap)
373+
{
374+
#if defined(MCUBOOT_SINGLE_APPLICATION_SLOT) || \
375+
defined(MCUBOOT_FIRMWARE_LOADER) || \
376+
defined(MCUBOOT_SINGLE_APPLICATION_SLOT_RAM_LOAD)
377+
(void) state;
338378
return boot_status_off(fap);
379+
#elif defined(MCUBOOT_SWAP_USING_SCRATCH)
380+
size_t slot_trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(state));
381+
size_t slot_trailer_off = flash_area_get_size(fap) - slot_trailer_sz;
382+
383+
/* If the trailer doesn't fit in the last sector of the primary or secondary slot, some padding
384+
* might have to be inserted between the end of the firmware image and the beginning of the
385+
* trailer to ensure there is enough space for the trailer in the scratch area when the last
386+
* sector of the secondary will be copied to the scratch area.
387+
*
388+
* The value of the padding depends on the amount of trailer data that is contained in the first
389+
* trailer containing part of the trailer in the primary and secondary slot.
390+
*/
391+
size_t trailer_sector_primary_end_off =
392+
get_first_trailer_sector_end_off(state, BOOT_PRIMARY_SLOT, slot_trailer_sz);
393+
size_t trailer_sector_secondary_end_off =
394+
get_first_trailer_sector_end_off(state, BOOT_SECONDARY_SLOT, slot_trailer_sz);
395+
396+
size_t trailer_sz_in_first_sector;
397+
398+
if (trailer_sector_primary_end_off > trailer_sector_secondary_end_off) {
399+
trailer_sz_in_first_sector = trailer_sector_primary_end_off - slot_trailer_off;
400+
} else {
401+
trailer_sz_in_first_sector = trailer_sector_secondary_end_off - slot_trailer_off;
402+
}
403+
404+
size_t trailer_padding = 0;
405+
size_t scratch_trailer_sz = boot_scratch_trailer_sz(BOOT_WRITE_SZ(state));
406+
407+
if (scratch_trailer_sz > trailer_sz_in_first_sector) {
408+
trailer_padding = scratch_trailer_sz - trailer_sz_in_first_sector;
409+
}
410+
411+
return slot_trailer_off - trailer_padding;
339412
#elif defined(MCUBOOT_SWAP_USING_MOVE) || defined(MCUBOOT_SWAP_USING_OFFSET)
413+
(void) state;
414+
340415
struct flash_sector sector;
341416
/* get the last sector offset */
342417
int rc = flash_area_get_sector(fap, boot_status_off(fap), &sector);
@@ -348,10 +423,13 @@ uint32_t bootutil_max_image_size(const struct flash_area *fap)
348423
}
349424
return flash_sector_get_off(&sector);
350425
#elif defined(MCUBOOT_OVERWRITE_ONLY)
426+
(void) state;
351427
return boot_swap_info_off(fap);
352428
#elif defined(MCUBOOT_DIRECT_XIP)
429+
(void) state;
353430
return boot_swap_info_off(fap);
354431
#elif defined(MCUBOOT_RAM_LOAD)
432+
(void) state;
355433
return boot_swap_info_off(fap);
356434
#endif
357435
}

boot/bootutil/src/bootutil_priv.h

+15-1
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,20 @@ int boot_read_enc_key(const struct flash_area *fap, uint8_t slot,
344344
struct boot_status *bs);
345345
#endif
346346

347+
#ifdef MCUBOOT_SWAP_USING_SCRATCH
348+
/**
349+
* Finds the first sector of a given slot that holds image trailer data.
350+
*
351+
* @param state Current bootloader's state.
352+
* @param slot The index of the slot to consider.
353+
* @param trailer_sz The size of the trailer, in bytes.
354+
*
355+
* @return The index of the first sector of the slot that holds image trailer data.
356+
*/
357+
size_t
358+
boot_get_first_trailer_sector(struct boot_loader_state *state, size_t slot, size_t trailer_sz);
359+
#endif
360+
347361
/**
348362
* Checks that a buffer is erased according to what the erase value for the
349363
* flash device provided in `flash_area` is.
@@ -511,7 +525,7 @@ int boot_load_image_to_sram(struct boot_loader_state *state);
511525

512526
#endif /* MCUBOOT_RAM_LOAD */
513527

514-
uint32_t bootutil_max_image_size(const struct flash_area *fap);
528+
uint32_t bootutil_max_image_size(struct boot_loader_state *state, const struct flash_area *fap);
515529

516530
int boot_read_image_size(struct boot_loader_state *state, int slot,
517531
uint32_t *size);

boot/bootutil/src/image_validate.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -555,7 +555,7 @@ bootutil_img_validate(struct boot_loader_state *state,
555555
goto out;
556556
}
557557

558-
if (it.tlv_end > bootutil_max_image_size(fap)) {
558+
if (it.tlv_end > bootutil_max_image_size(state, fap)) {
559559
rc = -1;
560560
goto out;
561561
}

boot/bootutil/src/swap_scratch.c

+3-29
Original file line numberDiff line numberDiff line change
@@ -531,33 +531,6 @@ find_swap_count(const struct boot_loader_state *state, uint32_t copy_size)
531531
return swap_count;
532532
}
533533

534-
/**
535-
* Finds the first sector of a given slot that holds image trailer data.
536-
*
537-
* @param state Current bootloader's state.
538-
* @param slot The index of the slot to consider.
539-
* @param trailer_sz The size of the trailer, in bytes.
540-
*
541-
* @return The index of the first sector of the slot that holds image trailer data.
542-
*/
543-
static size_t
544-
get_first_trailer_sector(struct boot_loader_state *state, size_t slot, size_t trailer_sz)
545-
{
546-
size_t first_trailer_sector = boot_img_num_sectors(state, slot) - 1;
547-
size_t sector_sz = boot_img_sector_size(state, slot, first_trailer_sector);
548-
size_t trailer_sector_sz = sector_sz;
549-
550-
while (trailer_sector_sz < trailer_sz) {
551-
/* Consider that the image trailer may span across sectors of different sizes */
552-
--first_trailer_sector;
553-
sector_sz = boot_img_sector_size(state, slot, first_trailer_sector);
554-
555-
trailer_sector_sz += sector_sz;
556-
}
557-
558-
return first_trailer_sector;
559-
}
560-
561534
/**
562535
* Swaps the contents of two flash regions within the two image slots.
563536
*
@@ -616,7 +589,8 @@ boot_swap_sectors(int idx, uint32_t sz, struct boot_loader_state *state,
616589
* NOTE: `use_scratch` is a temporary flag (never written to flash) which
617590
* controls if special handling is needed (swapping the first trailer sector).
618591
*/
619-
first_trailer_sector_primary = get_first_trailer_sector(state, BOOT_PRIMARY_SLOT, trailer_sz);
592+
first_trailer_sector_primary =
593+
boot_get_first_trailer_sector(state, BOOT_PRIMARY_SLOT, trailer_sz);
620594

621595
/* Check if the currently swapped sector(s) contain the trailer or part of it */
622596
if ((img_off + sz) >
@@ -696,7 +670,7 @@ boot_swap_sectors(int idx, uint32_t sz, struct boot_loader_state *state,
696670
* sector(s) containing the beginning of the trailer won't be erased again.
697671
*/
698672
size_t trailer_sector_secondary =
699-
get_first_trailer_sector(state, BOOT_SECONDARY_SLOT, trailer_sz);
673+
boot_get_first_trailer_sector(state, BOOT_SECONDARY_SLOT, trailer_sz);
700674

701675
uint32_t trailer_sector_offset =
702676
boot_img_sector_off(state, BOOT_SECONDARY_SLOT, trailer_sector_secondary);

0 commit comments

Comments
 (0)