Skip to content

Commit

Permalink
mgmt: mcumgr: grp: img_mgmt: Add optional max image size reduction
Browse files Browse the repository at this point in the history
Adds an optional feature that can be used to reduce the maximum
allowed image upload file size whereby an image could be uploaded
that would be too large to swap even if it could fit the partition

Signed-off-by: Jamie McCrae <[email protected]>
  • Loading branch information
nordicjm committed Jan 29, 2024
1 parent b7ebf84 commit 6071453
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 0 deletions.
3 changes: 3 additions & 0 deletions include/zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,9 @@ enum img_mgmt_err_code_t {

/** Setting test to active slot is not allowed */
IMG_MGMT_ERR_IMAGE_SETTING_TEST_TO_ACTIVE_DENIED,

/** Current active slot for image cannot be determined */
IMG_MGMT_ERR_ACTIVE_SLOT_NOT_KNOWN,
};

/**
Expand Down
32 changes: 32 additions & 0 deletions subsys/mgmt/mcumgr/grp/img_mgmt/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,38 @@ config MCUMGR_GRP_IMG_MUTEX
can be used by applications to reset the image management state (useful if there are
multiple ways that firmware updates can be loaded).

choice MCUMGR_GRP_IMG_TOO_LARGE_CHECK
prompt "Image size check overhead"
default MCUMGR_GRP_IMG_TOO_LARGE_DISABLED
help
MCUboot images should be limited to the maximum size that the bootloader can swap, in
order to know this size, additional information is needed from the MCUboot
configuration, otherwise an image can be uploaded that is too large for the bootloader
to swap, this selects which method to use.

Note: setting this to a non-disabled option will prevent uploading of padded and
confirmed images, if support for that is required then this feature should be left as
disabled.

config MCUMGR_GRP_IMG_TOO_LARGE_DISABLED
bool "Disabled"
help
Will not take MCUboot configuration into account when checking for maximum file size.

config MCUMGR_GRP_IMG_TOO_LARGE_SYSBUILD
bool "Via Sysbuild from MCUboot configuration"
depends on ROM_END_OFFSET > 0
help
Will use the image overhead size calculated during Sysbuild image configuration.

config MCUMGR_GRP_IMG_TOO_LARGE_BOOTLOADER_INFO
bool "Via retention bootloader info"
depends on RETENTION_BOOTLOADER_INFO_OUTPUT_FUNCTION
help
Will fetch the maximum image size from the bootloader info retention subsystem module.

endchoice

module = MCUMGR_GRP_IMG
module-str = mcumgr_grp_img
source "subsys/logging/Kconfig.template.log_config"
Expand Down
84 changes: 84 additions & 0 deletions subsys/mgmt/mcumgr/grp/img_mgmt/src/zephyr_img_mgmt.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@

#include <mgmt/mcumgr/grp/img_mgmt/img_mgmt_priv.h>

#if defined(CONFIG_MCUMGR_GRP_IMG_TOO_LARGE_BOOTLOADER_INFO)
#include <zephyr/retention/retention.h>
#include <zephyr/retention/blinfo.h>
#endif

LOG_MODULE_DECLARE(mcumgr_img_grp, CONFIG_MCUMGR_GRP_IMG_LOG_LEVEL);

#define SLOT0_PARTITION slot0_partition
Expand Down Expand Up @@ -564,6 +569,18 @@ int img_mgmt_upload_inspect(const struct img_mgmt_upload_req *req,
if (req->off == 0) {
/* First upload chunk. */
const struct flash_area *fa;
#if defined(CONFIG_MCUMGR_GRP_IMG_TOO_LARGE_SYSBUILD) && \
(defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_SWAP_WITHOUT_SCRATCH) || \
defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_SWAP_SCRATCH) || \
defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_OVERWRITE_ONLY) || \
defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP) || \
defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP_WITH_REVERT)) && \
CONFIG_MCUBOOT_UPDATE_FOOTER_SIZE > 0
const struct flash_area *fa_current;
int current_img_area;
#elif defined(CONFIG_MCUMGR_GRP_IMG_TOO_LARGE_BOOTLOADER_INFO)
int max_image_size;
#endif

if (req->img_data.len < sizeof(struct image_header)) {
/* Image header is the first thing in the image */
Expand All @@ -576,6 +593,7 @@ int img_mgmt_upload_inspect(const struct img_mgmt_upload_req *req,
IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(action, img_mgmt_err_str_hdr_malformed);
return IMG_MGMT_ERR_INVALID_LENGTH;
}

action->size = req->size;

hdr = (struct image_header *)req->img_data.value;
Expand Down Expand Up @@ -626,6 +644,72 @@ int img_mgmt_upload_inspect(const struct img_mgmt_upload_req *req,
return IMG_MGMT_ERR_INVALID_IMAGE_TOO_LARGE;
}

#if defined(CONFIG_MCUMGR_GRP_IMG_TOO_LARGE_SYSBUILD) && \
(defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_SWAP_WITHOUT_SCRATCH) || \
defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_SWAP_SCRATCH) || \
defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_OVERWRITE_ONLY) || \
defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP) || \
defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP_WITH_REVERT)) && \
CONFIG_MCUBOOT_UPDATE_FOOTER_SIZE > 0
/* Check if slot1 is larger than slot0 by the update size, if so then the size
* check can be skipped because the devicetree partitions are okay
*/
current_img_area = img_mgmt_flash_area_id(req->image);

if (current_img_area < 0) {
/* Current slot cannot be determined */
LOG_ERR("Failed to determine active slot for image %d: %d", req->image,
current_img_area);
return IMG_MGMT_ERR_ACTIVE_SLOT_NOT_KNOWN;
}

rc = flash_area_open(current_img_area, &fa_current);
if (rc) {
IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(action,
img_mgmt_err_str_flash_open_failed);
LOG_ERR("Failed to open flash area ID %u: %d", current_img_area, rc);
flash_area_close(fa);
return IMG_MGMT_ERR_FLASH_OPEN_FAILED;
}

flash_area_close(fa_current);

LOG_DBG("Primary size: %d, secondary size: %d, overhead: %d, max update size: %d",
fa_current->fa_size, fa->fa_size, CONFIG_MCUBOOT_UPDATE_FOOTER_SIZE,
(fa->fa_size + CONFIG_MCUBOOT_UPDATE_FOOTER_SIZE));

if (fa_current->fa_size >= (fa->fa_size + CONFIG_MCUBOOT_UPDATE_FOOTER_SIZE)) {
/* Upgrade slot is of sufficient size, nothing to check */
LOG_INF("Upgrade slots already sized appropriately, "
"CONFIG_MCUMGR_GRP_IMG_TOO_LARGE_SYSBUILD is not needed");
goto skip_size_check;
}

if (req->size > (fa->fa_size - CONFIG_MCUBOOT_UPDATE_FOOTER_SIZE)) {
IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(action,
img_mgmt_err_str_image_too_large);
flash_area_close(fa);
LOG_ERR("Upload too large for slot (with end offset): %u > %u", req->size,
(fa->fa_size - CONFIG_MCUBOOT_UPDATE_FOOTER_SIZE));
return IMG_MGMT_ERR_INVALID_IMAGE_TOO_LARGE;
}

skip_size_check:
#elif defined(CONFIG_MCUMGR_GRP_IMG_TOO_LARGE_BOOTLOADER_INFO)
rc = blinfo_lookup(BLINFO_MAX_APPLICATION_SIZE, (char *)&max_image_size,
sizeof(max_image_size));

if (rc == sizeof(max_image_size) && max_image_size > 0 &&
req->size > max_image_size) {
IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(action,
img_mgmt_err_str_image_too_large);
flash_area_close(fa);
LOG_ERR("Upload too large for slot (with max image size): %u > %u",
req->size, max_image_size);
return IMG_MGMT_ERR_INVALID_IMAGE_TOO_LARGE;
}
#endif

#if defined(CONFIG_MCUMGR_GRP_IMG_REJECT_DIRECT_XIP_MISMATCHED_SLOT)
if (hdr->ih_flags & IMAGE_F_ROM_FIXED) {
if (fa->fa_off != hdr->ih_load_addr) {
Expand Down

0 comments on commit 6071453

Please sign in to comment.