diff --git a/include/dfu/flash_img.h b/include/dfu/flash_img.h index 104e94d8162..46bb51cba8b 100644 --- a/include/dfu/flash_img.h +++ b/include/dfu/flash_img.h @@ -19,6 +19,9 @@ struct flash_img_context { const struct flash_area *flash_area; size_t bytes_written; u16_t buf_bytes; +#ifdef CONFIG_IMG_ERASE_PROGRESSIVELY + off_t off_last; +#endif }; /** diff --git a/include/dfu/mcuboot.h b/include/dfu/mcuboot.h index 7bc003d20c3..a153d6fd9f1 100644 --- a/include/dfu/mcuboot.h +++ b/include/dfu/mcuboot.h @@ -30,6 +30,13 @@ #define BOOT_IMG_VER_STRLEN_MAX 25 /* 255.255.65535.4294967295\0 */ +/* Trailer: */ +#define BOOT_MAX_ALIGN 8 +#define BOOT_MAGIC_SZ 16 + +#define BOOT_TRAILER_IMG_STATUS_OFFS(bank_area) ((bank_area)->fa_size -\ + BOOT_MAGIC_SZ -\ + BOOT_MAX_ALIGN * 2) /** * @brief MCUboot image header representation for image version * diff --git a/subsys/dfu/Kconfig b/subsys/dfu/Kconfig index a8dfd6d7d16..abfdda68850 100644 --- a/subsys/dfu/Kconfig +++ b/subsys/dfu/Kconfig @@ -41,6 +41,16 @@ config IMG_BLOCK_BUF_SIZE Size (in Bytes) of buffer for image writer. Must be a multiple of the access alignment required by used flash driver. +config IMG_ERASE_PROGRESSIVELY + bool "Erase flash progressively when receiving new firmware" + depends on MCUBOOT_IMG_MANAGER + select FLASH_PAGE_LAYOUT + help + If enabled, flash is erased as necessary when receiving new firmware, + instead of erasing the whole image slot at once. This is necessary + on some hardware that has long erase times, to prevent long wait + times at the beginning of the DFU process. + module = IMG_MANAGER module-str = image manager source "subsys/logging/Kconfig.template.log_config" diff --git a/subsys/dfu/boot/mcuboot.c b/subsys/dfu/boot/mcuboot.c index a905331e1ee..fbb9c23aa09 100644 --- a/subsys/dfu/boot/mcuboot.c +++ b/subsys/dfu/boot/mcuboot.c @@ -32,8 +32,6 @@ #define BOOT_HEADER_SIZE_V1 32 /* Trailer: */ -#define BOOT_MAX_ALIGN 8 -#define BOOT_MAGIC_SZ 16 #define BOOT_FLAG_SET 0x01 #define BOOT_FLAG_UNSET 0xff diff --git a/subsys/dfu/img_util/flash_img.c b/subsys/dfu/img_util/flash_img.c index 055801e9c4a..50e9e28ad09 100644 --- a/subsys/dfu/img_util/flash_img.c +++ b/subsys/dfu/img_util/flash_img.c @@ -18,6 +18,11 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include #include +#ifdef CONFIG_IMG_ERASE_PROGRESSIVELY +#include +#include +#endif + BUILD_ASSERT_MSG((CONFIG_IMG_BLOCK_BUF_SIZE % DT_FLASH_WRITE_BLOCK_SIZE == 0), "CONFIG_IMG_BLOCK_BUF_SIZE is not a multiple of " "DT_FLASH_WRITE_BLOCK_SIZE"); @@ -52,6 +57,63 @@ static bool flash_verify(const struct flash_area *fa, off_t offset, return (len == 0) ? true : false; } +#ifdef CONFIG_IMG_ERASE_PROGRESSIVELY + +static int flash_sector_from_off(struct flash_area const *fap, off_t off, + struct flash_sector *sector) +{ + struct flash_pages_info page; + struct device *flash_dev; + int rc = -ENODEV; + + flash_dev = flash_area_get_device(fap); + if (flash_dev) { + rc = flash_get_page_info_by_offs(flash_dev, off, &page); + if (rc == 0) { + sector->fs_off = page.start_offset; + sector->fs_size = page.size; + } + } + + return rc; +} + +/** + * Erase the image slot progressively + * + * This function erases a flash page to which offset belongs if only this page + * wasn't erased before. + * + * @param[in] ctx context of the image collection process. + * @param[in] off offset from the beginning of the image flash area beginning + * + * @return 0 on success, negative errno code on fail. + */ +static int flash_progressive_erase(struct flash_img_context *ctx, off_t off) +{ + struct flash_sector sector; + int rc; + + rc = flash_sector_from_off(ctx->flash_area, off, §or); + if (rc) { + LOG_ERR("Unable to determine flash sector size"); + } else { + if (ctx->off_last != sector.fs_off) { + ctx->off_last = sector.fs_off; + LOG_INF("Erasing sector at offset 0x%x", sector.fs_off); + rc = flash_area_erase(ctx->flash_area, sector.fs_off, + sector.fs_size); + if (rc) { + LOG_ERR("Error %d while erasing sector", rc); + } + } + } + + return rc; +} + +#endif /* CONFIG_IMG_ERASE_PROGRESSIVELY */ + static int flash_sync(struct flash_img_context *ctx) { int rc = 0; @@ -61,6 +123,11 @@ static int flash_sync(struct flash_img_context *ctx) CONFIG_IMG_BLOCK_BUF_SIZE - ctx->buf_bytes); } +#ifdef CONFIG_IMG_ERASE_PROGRESSIVELY + flash_progressive_erase(ctx, ctx->bytes_written + + CONFIG_IMG_BLOCK_BUF_SIZE); +#endif + rc = flash_area_write(ctx->flash_area, ctx->bytes_written, ctx->buf, CONFIG_IMG_BLOCK_BUF_SIZE); if (rc) { @@ -121,6 +188,11 @@ int flash_img_buffered_write(struct flash_img_context *ctx, u8_t *data, return rc; } } +#ifdef CONFIG_IMG_ERASE_PROGRESSIVELY + /* erase the image trailer area if it was not erased */ + flash_progressive_erase(ctx, + BOOT_TRAILER_IMG_STATUS_OFFS(ctx->flash_area)); +#endif flash_area_close(ctx->flash_area); ctx->flash_area = NULL; @@ -137,6 +209,9 @@ int flash_img_init(struct flash_img_context *ctx) { ctx->bytes_written = 0; ctx->buf_bytes = 0U; +#ifdef CONFIG_IMG_ERASE_PROGRESSIVELY + ctx->off_last = -1; +#endif return flash_area_open(DT_FLASH_AREA_IMAGE_1_ID, (const struct flash_area **)&(ctx->flash_area)); }