diff --git a/boot/bootutil/include/bootutil/boot_record.h b/boot/bootutil/include/bootutil/boot_record.h index e6aaa716..e89ea0ae 100644 --- a/boot/bootutil/include/bootutil/boot_record.h +++ b/boot/bootutil/include/bootutil/boot_record.h @@ -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 } diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 374d140e..270b0d60 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -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; diff --git a/boot/bootutil/src/swap_move.c b/boot/bootutil/src/swap_move.c index d7b51080..61246b9e 100644 --- a/boot/bootutil/src/swap_move.c +++ b/boot/bootutil/src/swap_move.c @@ -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 diff --git a/boot/bootutil/src/swap_priv.h b/boot/bootutil/src/swap_priv.h index 86d0b721..960c7225 100644 --- a/boot/bootutil/src/swap_priv.h +++ b/boot/bootutil/src/swap_priv.h @@ -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_ */ diff --git a/boot/bootutil/src/swap_scratch.c b/boot/bootutil/src/swap_scratch.c index bb0d12d5..66cbdce5 100644 --- a/boot/bootutil/src/swap_scratch.c +++ b/boot/bootutil/src/swap_scratch.c @@ -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 */