bootutil: Add active slot number and max app size to shared data

This allows the currently executing slot number to be checked by
the external function, which can be used by XIP images to know
which slot is currently being executed from to allow for correct
uploading/positioning of firmware files, and also provides the
maximum size of an upgrade that can be loaded so that applications
can reject images that are too large.

Signed-off-by: Jamie McCrae <jamie.mccrae@nordicsemi.no>
This commit is contained in:
Jamie McCrae 2023-03-14 12:35:51 +00:00 committed by Jamie
parent 0540d0fb3f
commit 3016d00cd7
5 changed files with 156 additions and 7 deletions

View File

@ -59,13 +59,17 @@ int boot_save_boot_status(uint8_t sw_module,
* Add application specific data to the shared memory area between the
* bootloader and runtime SW.
*
* @param[in] hdr Pointer to the image header stored in RAM.
* @param[in] fap Pointer to the flash area where image is stored.
* @param[in] hdr Pointer to the image header stored in RAM.
* @param[in] fap Pointer to the flash area where image is stored.
* @param[in] slot The currently active slot being booted.
* @param[in] max_app_size The maximum size of an image that can be loaded.
*
* @return 0 on success; nonzero on failure.
* @return 0 on success; nonzero on failure.
*/
int boot_save_shared_data(const struct image_header *hdr,
const struct flash_area *fap);
const struct flash_area *fap,
const uint8_t active_slot,
const int max_app_size);
#ifdef __cplusplus
}

View File

@ -129,11 +129,15 @@ boot_read_image_headers(struct boot_loader_state *state, bool require_all,
*/
static int
boot_add_shared_data(struct boot_loader_state *state,
uint32_t active_slot)
uint8_t active_slot)
{
#if defined(MCUBOOT_MEASURED_BOOT) || defined(MCUBOOT_DATA_SHARING)
int rc;
#ifdef MCUBOOT_DATA_SHARING
int max_app_size;
#endif
#ifdef MCUBOOT_MEASURED_BOOT
rc = boot_save_boot_status(BOOT_CURR_IMG(state),
boot_img_hdr(state, active_slot),
@ -145,8 +149,10 @@ boot_add_shared_data(struct boot_loader_state *state,
#endif /* MCUBOOT_MEASURED_BOOT */
#ifdef MCUBOOT_DATA_SHARING
max_app_size = app_max_size(state);
rc = boot_save_shared_data(boot_img_hdr(state, active_slot),
BOOT_IMG_AREA(state, active_slot));
BOOT_IMG_AREA(state, active_slot),
active_slot, max_app_size);
if (rc != 0) {
BOOT_LOG_ERR("Failed to add data to shared memory area.");
return rc;
@ -3278,7 +3284,7 @@ context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp)
goto out;
}
rc = boot_add_shared_data(state, state->slot_usage[BOOT_CURR_IMG(state)].active_slot);
rc = boot_add_shared_data(state, (uint8_t)state->slot_usage[BOOT_CURR_IMG(state)].active_slot);
if (rc != 0) {
FIH_SET(fih_rc, FIH_FAILURE);
goto out;

View File

@ -542,4 +542,26 @@ swap_run(struct boot_loader_state *state, struct boot_status *bs,
flash_area_close(fap_sec);
}
int app_max_size(struct boot_loader_state *state)
{
uint32_t sz = 0;
uint32_t sector_sz;
uint32_t trailer_sz;
uint32_t first_trailer_idx;
sector_sz = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, 0);
trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(state));
first_trailer_idx = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT) - 1;
while (1) {
sz += sector_sz;
if (sz >= trailer_sz) {
break;
}
first_trailer_idx--;
}
return (first_trailer_idx * sector_sz);
}
#endif

View File

@ -101,4 +101,9 @@ static inline size_t boot_scratch_area_size(const struct boot_loader_state *stat
#endif /* defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SWAP_USING_MOVE) */
/**
* Returns the maximum size of an application that can be loaded to a slot.
*/
int app_max_size(struct boot_loader_state *state);
#endif /* H_SWAP_PRIV_ */

View File

@ -743,6 +743,118 @@ swap_run(struct boot_loader_state *state, struct boot_status *bs,
}
#endif /* !MCUBOOT_OVERWRITE_ONLY */
int app_max_size(struct boot_loader_state *state)
{
size_t num_sectors_primary;
size_t num_sectors_secondary;
size_t sz0, sz1;
size_t primary_slot_sz, secondary_slot_sz;
#ifndef MCUBOOT_OVERWRITE_ONLY
size_t scratch_sz;
#endif
size_t i, j;
int8_t smaller;
num_sectors_primary = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT);
num_sectors_secondary = boot_img_num_sectors(state, BOOT_SECONDARY_SLOT);
#ifndef MCUBOOT_OVERWRITE_ONLY
scratch_sz = boot_scratch_area_size(state);
#endif
/*
* The following loop scans all sectors in a linear fashion, assuring that
* for each possible sector in each slot, it is able to fit in the other
* slot's sector or sectors. Slot's should be compatible as long as any
* number of a slot's sectors are able to fit into another, which only
* excludes cases where sector sizes are not a multiple of each other.
*/
i = sz0 = primary_slot_sz = 0;
j = sz1 = secondary_slot_sz = 0;
smaller = 0;
while (i < num_sectors_primary || j < num_sectors_secondary) {
if (sz0 == sz1) {
sz0 += boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i);
sz1 += boot_img_sector_size(state, BOOT_SECONDARY_SLOT, j);
i++;
j++;
} else if (sz0 < sz1) {
sz0 += boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i);
/* Guarantee that multiple sectors of the secondary slot
* fit into the primary slot.
*/
if (smaller == 2) {
BOOT_LOG_WRN("Cannot upgrade: slots have non-compatible sectors");
return 0;
}
smaller = 1;
i++;
} else {
sz1 += boot_img_sector_size(state, BOOT_SECONDARY_SLOT, j);
/* Guarantee that multiple sectors of the primary slot
* fit into the secondary slot.
*/
if (smaller == 1) {
BOOT_LOG_WRN("Cannot upgrade: slots have non-compatible sectors");
return 0;
}
smaller = 2;
j++;
}
#ifndef MCUBOOT_OVERWRITE_ONLY
if (sz0 == sz1) {
primary_slot_sz += sz0;
secondary_slot_sz += sz1;
/* Scratch has to fit each swap operation to the size of the larger
* sector among the primary slot and the secondary slot.
*/
if (sz0 > scratch_sz || sz1 > scratch_sz) {
BOOT_LOG_WRN("Cannot upgrade: not all sectors fit inside scratch");
return 0;
}
smaller = sz0 = sz1 = 0;
}
#endif
}
#ifdef MCUBOOT_OVERWRITE_ONLY
return (sz1 < sz0 ? sz1 : sz0);
#else
return (secondary_slot_sz < primary_slot_sz ? secondary_slot_sz : primary_slot_sz);
#endif
}
#else
int app_max_size(struct boot_loader_state *state)
{
const struct flash_area *fap;
int fa_id;
int rc;
uint32_t active_slot;
int primary_sz, secondary_sz;
active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot;
fa_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), active_slot);
rc = flash_area_open(fa_id, &fap);
assert(rc == 0);
primary_sz = flash_area_get_size(fap);
flash_area_close(fap);
if (active_slot == BOOT_PRIMARY_SLOT) {
active_slot = BOOT_SECONDARY_SLOT;
} else {
active_slot = BOOT_PRIMARY_SLOT;
}
fa_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), active_slot);
rc = flash_area_open(fa_id, &fap);
assert(rc == 0);
secondary_sz = flash_area_get_size(fap);
flash_area_close(fap);
return (secondary_sz < primary_sz ? secondary_sz : primary_sz);
}
#endif /* !MCUBOOT_DIRECT_XIP && !MCUBOOT_RAM_LOAD */
#endif /* !MCUBOOT_SWAP_USING_MOVE */