dfu: use stream_flash in flash_img

Leverage strem_flash in flash_img.c to reduce code size.

Signed-off-by: Håkon Øye Amundsen <haakon.amundsen@nordicsemi.no>
This commit is contained in:
Håkon Øye Amundsen 2020-03-05 12:46:39 +00:00 committed by Carles Cufí
commit 0aa21a632a
3 changed files with 26 additions and 200 deletions

View file

@ -8,7 +8,7 @@
#ifndef ZEPHYR_INCLUDE_DFU_FLASH_IMG_H_ #ifndef ZEPHYR_INCLUDE_DFU_FLASH_IMG_H_
#define ZEPHYR_INCLUDE_DFU_FLASH_IMG_H_ #define ZEPHYR_INCLUDE_DFU_FLASH_IMG_H_
#include <storage/flash_map.h> #include <storage/stream_flash.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -17,11 +17,7 @@ extern "C" {
struct flash_img_context { struct flash_img_context {
u8_t buf[CONFIG_IMG_BLOCK_BUF_SIZE]; u8_t buf[CONFIG_IMG_BLOCK_BUF_SIZE];
const struct flash_area *flash_area; const struct flash_area *flash_area;
size_t bytes_written; struct stream_flash_ctx stream;
u16_t buf_bytes;
#ifdef CONFIG_IMG_ERASE_PROGRESSIVELY
off_t off_last;
#endif
}; };
/** /**

View file

@ -9,6 +9,7 @@
menuconfig IMG_MANAGER menuconfig IMG_MANAGER
bool "DFU image manager" bool "DFU image manager"
select STREAM_FLASH
help help
Enable support for managing DFU image. Enable support for managing DFU image.
@ -51,7 +52,7 @@ config IMG_BLOCK_BUF_SIZE
config IMG_ERASE_PROGRESSIVELY config IMG_ERASE_PROGRESSIVELY
bool "Erase flash progressively when receiving new firmware" bool "Erase flash progressively when receiving new firmware"
depends on MCUBOOT_IMG_MANAGER depends on MCUBOOT_IMG_MANAGER
select FLASH_PAGE_LAYOUT select STREAM_FLASH_ERASE
help help
If enabled, flash is erased as necessary when receiving new firmware, If enabled, flash is erased as necessary when receiving new firmware,
instead of erasing the whole image slot at once. This is necessary instead of erasing the whole image slot at once. This is necessary

View file

@ -1,26 +1,19 @@
/* /*
* Copyright (c) 2017 Nordic Semiconductor ASA * Copyright (c) 2017, 2020 Nordic Semiconductor ASA
* Copyright (c) 2017 Linaro Limited * Copyright (c) 2017 Linaro Limited
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
#define LOG_MODULE_NAME fota_flash_block
#define LOG_LEVEL CONFIG_IMG_MANAGER_LOG_LEVEL
#include <logging/log.h>
LOG_MODULE_REGISTER(LOG_MODULE_NAME);
#include <zephyr/types.h> #include <zephyr/types.h>
#include <stddef.h> #include <stddef.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <errno.h>
#include <dfu/flash_img.h> #include <dfu/flash_img.h>
#include <inttypes.h> #include <storage/flash_map.h>
#include <storage/stream_flash.h>
#ifdef CONFIG_IMG_ERASE_PROGRESSIVELY #ifdef CONFIG_IMG_ERASE_PROGRESSIVELY
#include <dfu/mcuboot.h> #include <dfu/mcuboot.h>
#include <drivers/flash.h>
#endif #endif
#include <devicetree.h> #include <devicetree.h>
@ -38,181 +31,19 @@ BUILD_ASSERT((CONFIG_IMG_BLOCK_BUF_SIZE % FLASH_WRITE_BLOCK_SIZE == 0),
"CONFIG_IMG_BLOCK_BUF_SIZE is not a multiple of " "CONFIG_IMG_BLOCK_BUF_SIZE is not a multiple of "
"FLASH_WRITE_BLOCK_SIZE"); "FLASH_WRITE_BLOCK_SIZE");
static bool flash_verify(const struct flash_area *fa, off_t offset,
u8_t *data, size_t len)
{
size_t size;
u32_t temp;
int rc;
while (len) {
size = (len >= sizeof(temp)) ? sizeof(temp) : len;
rc = flash_area_read(fa, offset, &temp, size);
if (rc) {
LOG_ERR("flash_read error %d offset=0x%08lx",
rc, (long)offset);
break;
}
if (memcmp(data, &temp, size)) {
LOG_ERR("offset=0x%08lx VERIFY FAIL. "
"expected: 0x%08x, actual: 0x%08x",
(long)offset, temp, UNALIGNED_GET(data));
break;
}
len -= size;
offset += size;
data += size;
}
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);
off += fap->fa_off; /* flash driver uses offset from memory beginning */
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, &sector);
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%08lx",
(long)sector.fs_off);
rc = flash_area_erase(ctx->flash_area,
sector.fs_off -
ctx->flash_area->fa_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;
if (ctx->buf_bytes < CONFIG_IMG_BLOCK_BUF_SIZE) {
(void)memset(ctx->buf + ctx->buf_bytes, 0xFF,
CONFIG_IMG_BLOCK_BUF_SIZE - ctx->buf_bytes);
}
#ifdef CONFIG_IMG_ERASE_PROGRESSIVELY
rc = flash_progressive_erase(ctx, ctx->bytes_written +
CONFIG_IMG_BLOCK_BUF_SIZE);
if (rc) {
LOG_ERR("flash_progressive_erase error %d offset=0x%08zx", rc,
ctx->bytes_written);
return rc;
}
#endif
rc = flash_area_write(ctx->flash_area, ctx->bytes_written, ctx->buf,
CONFIG_IMG_BLOCK_BUF_SIZE);
if (rc) {
LOG_ERR("flash_write error %d offset=0x%08zx", rc,
ctx->bytes_written);
return rc;
}
if (!flash_verify(ctx->flash_area, ctx->bytes_written, ctx->buf,
CONFIG_IMG_BLOCK_BUF_SIZE)) {
return -EIO;
}
ctx->bytes_written += ctx->buf_bytes;
ctx->buf_bytes = 0U;
return rc;
}
int flash_img_buffered_write(struct flash_img_context *ctx, u8_t *data, int flash_img_buffered_write(struct flash_img_context *ctx, u8_t *data,
size_t len, bool flush) size_t len, bool flush)
{ {
int processed = 0; int rc;
int rc = 0;
int buf_empty_bytes;
while ((len - processed) >=
(buf_empty_bytes = CONFIG_IMG_BLOCK_BUF_SIZE - ctx->buf_bytes)) {
memcpy(ctx->buf + ctx->buf_bytes, data + processed,
buf_empty_bytes);
ctx->buf_bytes = CONFIG_IMG_BLOCK_BUF_SIZE;
rc = flash_sync(ctx);
if (rc) {
return rc;
}
processed += buf_empty_bytes;
}
/* place rest of the data into ctx->buf */
if (processed < len) {
memcpy(ctx->buf + ctx->buf_bytes,
data + processed, len - processed);
ctx->buf_bytes += len - processed;
}
rc = stream_flash_buffered_write(&ctx->stream, data, len, flush);
if (!flush) { if (!flush) {
return rc; return rc;
} }
if (ctx->buf_bytes > 0) {
/* pad the rest of ctx->buf and write it out */
rc = flash_sync(ctx);
if (rc) {
return rc;
}
}
#ifdef CONFIG_IMG_ERASE_PROGRESSIVELY #ifdef CONFIG_IMG_ERASE_PROGRESSIVELY
/* erase the image trailer area if it was not erased */ rc = stream_flash_erase_page(&ctx->stream,
rc = flash_progressive_erase(ctx, ctx->flash_area->fa_off +
BOOT_TRAILER_IMG_STATUS_OFFS(ctx->flash_area)); BOOT_TRAILER_IMG_STATUS_OFFS(ctx->flash_area));
if (rc) { if (rc) {
return rc; return rc;
@ -227,30 +58,28 @@ int flash_img_buffered_write(struct flash_img_context *ctx, u8_t *data,
size_t flash_img_bytes_written(struct flash_img_context *ctx) size_t flash_img_bytes_written(struct flash_img_context *ctx)
{ {
return ctx->bytes_written; return stream_flash_bytes_written(&ctx->stream);
}
static void init_ctx(struct flash_img_context *ctx)
{
ctx->bytes_written = 0;
ctx->buf_bytes = 0U;
#ifdef CONFIG_IMG_ERASE_PROGRESSIVELY
ctx->off_last = -1;
#endif
} }
int flash_img_init_id(struct flash_img_context *ctx, u8_t area_id) int flash_img_init_id(struct flash_img_context *ctx, u8_t area_id)
{ {
init_ctx(ctx); int rc;
struct device *flash_dev;
return flash_area_open(area_id, rc = flash_area_open(area_id,
(const struct flash_area **)&(ctx->flash_area)); (const struct flash_area **)&(ctx->flash_area));
if (rc) {
return rc;
}
flash_dev = flash_area_get_device(ctx->flash_area);
return stream_flash_init(&ctx->stream, flash_dev, ctx->buf,
CONFIG_IMG_BLOCK_BUF_SIZE, ctx->flash_area->fa_off,
ctx->flash_area->fa_size, NULL);
} }
int flash_img_init(struct flash_img_context *ctx) int flash_img_init(struct flash_img_context *ctx)
{ {
init_ctx(ctx); return flash_img_init_id(ctx, FLASH_AREA_IMAGE_SECONDARY);
return flash_area_open(FLASH_AREA_IMAGE_SECONDARY,
(const struct flash_area **)&(ctx->flash_area));
} }