From 25c6610a653c172f89a17b8104602f609ac54a56 Mon Sep 17 00:00:00 2001 From: Andrzej Puzdrowski Date: Tue, 4 Jul 2017 11:55:06 +0200 Subject: [PATCH] DFU: add module for store the image Store image in sequence of certain blocks. Module is intended to be use by a higher-level image management protocol module Signed-off-by: Michael Scott Signed-off-by: Marti Bolivar Signed-off-by: Andrzej Puzdrowski --- include/dfu/flash_img.h | 63 +++++++++++++++ subsys/dfu/Kconfig | 27 +++++++ subsys/dfu/Makefile | 1 + subsys/dfu/img_util/Makefile | 3 + subsys/dfu/img_util/flash_img.c | 137 ++++++++++++++++++++++++++++++++ 5 files changed, 231 insertions(+) create mode 100644 include/dfu/flash_img.h create mode 100644 subsys/dfu/img_util/Makefile create mode 100644 subsys/dfu/img_util/flash_img.c diff --git a/include/dfu/flash_img.h b/include/dfu/flash_img.h new file mode 100644 index 00000000000..0862baf2920 --- /dev/null +++ b/include/dfu/flash_img.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2017 Nordic Semiconductor ASA + * Copyright (c) 2017 Linaro Limited + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __FLASH_IMG_H__ +#define __FLASH_IMG_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +struct flash_img_context { + u8_t buf[CONFIG_IMG_BLOCK_BUF_SIZE]; + struct device *dev; + size_t bytes_written; + u16_t buf_bytes; +}; + +/** + * @brief Initialize context needed for writing the image to the flash. + * + * @param ctx context to be initialized + * @param dev flash driver to used while writing the image + */ +void flash_img_init(struct flash_img_context *ctx, struct device *dev); + +/** + * @brief Read number of bytes of the image written to the flash. + * + * @param ctx context + * + * @return Number of bytes written to the image flash. + */ +size_t flash_img_bytes_written(struct flash_img_context *ctx); + +/** + * @brief Process input buffers to be written to the image slot 1. flash + * memory in single blocks. Will store remainder between calls. + * + * A final call to this function with flush set to true + * will write out the remaining block buffer to flash. Since flash is written to + * in blocks, the contents of flash from the last byte written up to the next + * multiple of CONFIG_IMG_BLOCK_BUF_SIZE is padded with 0xff. + * + * @param ctx context + * @param data data to write + * @param len Number of bytes to write + * @param flush when true this forces any buffered + * data to be written to flash + * + * @return 0 on success, negative errno code on fail + */ +int flash_img_buffered_write(struct flash_img_context *ctx, u8_t *data, + size_t len, bool flush); + +#ifdef __cplusplus +} +#endif + +#endif /* __FLASH_IMG_H__ */ diff --git a/subsys/dfu/Kconfig b/subsys/dfu/Kconfig index 3409dca0a4a..b4c453d28d6 100644 --- a/subsys/dfu/Kconfig +++ b/subsys/dfu/Kconfig @@ -32,4 +32,31 @@ config MCUBOOT_IMG_MANAGER Enable support for managing DFU image downloaded using mcuboot. endchoice +config IMG_BLOCK_BUF_SIZE + int + depends on MCUBOOT_IMG_MANAGER + prompt "Image writer buffer size" + default 512 + help + Size (in Bytes) of buffer for image writer. Must be a multiple of + the access alignment required by used flash driver. + +config SYS_LOG_IMG_MANAGER_LEVEL + int "Image manager Log level" + depends on SYS_LOG && MCUBOOT_IMG_MANAGER + default 0 + range 0 4 + help + Sets log level for the image manager. + Levels are: + + - 0 OFF: do not write + + - 1 ERROR: only write SYS_LOG_ERR + + - 2 WARNING: write SYS_LOG_WRN in addition to previous level + + - 3 INFO: write SYS_LOG_INF in addition to previous levels + + - 4 DEBUG: write SYS_LOG_DBG in addition to previous levels endmenu diff --git a/subsys/dfu/Makefile b/subsys/dfu/Makefile index b2238c8072c..fa6346ac950 100644 --- a/subsys/dfu/Makefile +++ b/subsys/dfu/Makefile @@ -1 +1,2 @@ obj-$(CONFIG_MCUBOOT_IMG_MANAGER) += boot/ +obj-$(CONFIG_MCUBOOT_IMG_MANAGER) += img_util/ diff --git a/subsys/dfu/img_util/Makefile b/subsys/dfu/img_util/Makefile new file mode 100644 index 00000000000..41fd3c3f9c8 --- /dev/null +++ b/subsys/dfu/img_util/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_MCUBOOT_IMG_MANAGER) += flash_img.o +ccflags-$(CONFIG_MCUBOOT_IMG_MANAGER) += -I${ZEPHYR_BASE}/include/dfu +ccflags-$(CONFIG_MCUBOOT_IMG_MANAGER) += -I${ZEPHYR_BASE}/subsys/dfu diff --git a/subsys/dfu/img_util/flash_img.c b/subsys/dfu/img_util/flash_img.c new file mode 100644 index 00000000000..5800aa0c904 --- /dev/null +++ b/subsys/dfu/img_util/flash_img.c @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2017 Nordic Semiconductor ASA + * Copyright (c) 2017 Linaro Limited + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define SYS_LOG_DOMAIN "fota/flash_block" +#define SYS_LOG_LEVEL CONFIG_SYS_LOG_IMG_MANAGER_LEVEL +#include + +#include +#include +#include +#include +#include +#include +#include "boot/mcuboot_constraints.h" +#include "flash_img.h" + +BUILD_ASSERT_MSG((CONFIG_IMG_BLOCK_BUF_SIZE % FLASH_ALIGN == 0), + "CONFIG_IMG_BLOCK_BUF_SIZE is not multiple of FLASH_ALIGN"); + +static bool flash_verify(struct device *dev, 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_read(dev, offset, &temp, size); + if (rc) { + SYS_LOG_ERR("flash_read error %d offset=0x%08x", + rc, offset); + break; + } + + if (memcmp(data, &temp, size)) { + SYS_LOG_ERR("offset=0x%08x VERIFY FAIL. " + "expected: 0x%08x, actual: 0x%08x", + offset, temp, *(__packed u32_t*)data); + break; + } + len -= size; + offset += size; + data += size; + } + + return (len == 0) ? true : false; +} + +/* buffer data into block writes */ +static int flash_block_write(struct flash_img_context *ctx, off_t offset, + u8_t *data, size_t len, bool finished) +{ + int processed = 0; + int rc = 0; + + while ((len - processed) > + (CONFIG_IMG_BLOCK_BUF_SIZE - ctx->buf_bytes)) { + memcpy(ctx->buf + ctx->buf_bytes, data + processed, + (CONFIG_IMG_BLOCK_BUF_SIZE - ctx->buf_bytes)); + + flash_write_protection_set(ctx->dev, false); + rc = flash_write(ctx->dev, offset + ctx->bytes_written, + ctx->buf, CONFIG_IMG_BLOCK_BUF_SIZE); + flash_write_protection_set(ctx->dev, true); + if (rc) { + SYS_LOG_ERR("flash_write error %d offset=0x%08x", + rc, offset + ctx->bytes_written); + return rc; + } + + if (!flash_verify(ctx->dev, offset + ctx->bytes_written, + ctx->buf, CONFIG_IMG_BLOCK_BUF_SIZE)) { + return -EIO; + } + + ctx->bytes_written += CONFIG_IMG_BLOCK_BUF_SIZE; + processed += (CONFIG_IMG_BLOCK_BUF_SIZE - ctx->buf_bytes); + ctx->buf_bytes = 0; + } + + /* 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; + } + + if (finished && ctx->buf_bytes > 0) { + /* pad the rest of ctx->buf and write it out */ + memset(ctx->buf + ctx->buf_bytes, 0xFF, + CONFIG_IMG_BLOCK_BUF_SIZE - ctx->buf_bytes); + + flash_write_protection_set(ctx->dev, false); + rc = flash_write(ctx->dev, offset + ctx->bytes_written, + ctx->buf, CONFIG_IMG_BLOCK_BUF_SIZE); + flash_write_protection_set(ctx->dev, true); + if (rc) { + SYS_LOG_ERR("flash_write error %d offset=0x%08x", + rc, offset + ctx->bytes_written); + return rc; + } + + if (!flash_verify(ctx->dev, offset + ctx->bytes_written, + ctx->buf, CONFIG_IMG_BLOCK_BUF_SIZE)) { + return -EIO; + } + + ctx->bytes_written = ctx->bytes_written + ctx->buf_bytes; + ctx->buf_bytes = 0; + } + + return rc; +} + +size_t flash_img_bytes_written(struct flash_img_context *ctx) +{ + return ctx->bytes_written; +} + +void flash_img_init(struct flash_img_context *ctx, struct device *dev) +{ + ctx->dev = dev; + ctx->bytes_written = 0; + ctx->buf_bytes = 0; +} + +int flash_img_buffered_write(struct flash_img_context *ctx, u8_t *data, + size_t len, bool flush) +{ + return flash_block_write(ctx, FLASH_AREA_IMAGE_1_OFFSET, data, len, + flush); +}