|
|
@ -1,19 +1,24 @@ |
|
|
|
/*
|
|
|
|
/*
|
|
|
|
* Copyright (c) 2017, 2020 Nordic Semiconductor ASA |
|
|
|
* Copyright (c) 2017-2025 Nordic Semiconductor ASA |
|
|
|
* Copyright (c) 2017 Linaro Limited |
|
|
|
* Copyright (c) 2017 Linaro Limited |
|
|
|
* Copyright (c) 2020 Gerson Fernando Budke <nandojve@gmail.com> |
|
|
|
* Copyright (c) 2020 Gerson Fernando Budke <nandojve@gmail.com> |
|
|
|
* |
|
|
|
* |
|
|
|
* SPDX-License-Identifier: Apache-2.0 |
|
|
|
* SPDX-License-Identifier: Apache-2.0 |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
#include <zephyr/types.h> |
|
|
|
#include <zephyr/types.h> |
|
|
|
|
|
|
|
#include <assert.h> |
|
|
|
#include <stddef.h> |
|
|
|
#include <stddef.h> |
|
|
|
#include <stdio.h> |
|
|
|
#include <stdio.h> |
|
|
|
#include <string.h> |
|
|
|
#include <string.h> |
|
|
|
|
|
|
|
#include <zephyr/logging/log.h> |
|
|
|
|
|
|
|
#include <zephyr/dfu/mcuboot.h> |
|
|
|
#include <zephyr/dfu/flash_img.h> |
|
|
|
#include <zephyr/dfu/flash_img.h> |
|
|
|
#include <zephyr/dfu/mcuboot.h> |
|
|
|
#include <zephyr/dfu/mcuboot.h> |
|
|
|
#include <zephyr/storage/flash_map.h> |
|
|
|
#include <zephyr/storage/flash_map.h> |
|
|
|
#include <zephyr/storage/stream_flash.h> |
|
|
|
#include <zephyr/storage/stream_flash.h> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LOG_MODULE_REGISTER(flash_img, CONFIG_IMG_MANAGER_LOG_LEVEL); |
|
|
|
|
|
|
|
|
|
|
|
#ifdef CONFIG_IMG_ERASE_PROGRESSIVELY |
|
|
|
#ifdef CONFIG_IMG_ERASE_PROGRESSIVELY |
|
|
|
#include <bootutil/bootutil_public.h> |
|
|
|
#include <bootutil/bootutil_public.h> |
|
|
|
#endif |
|
|
|
#endif |
|
|
@ -48,6 +53,9 @@ BUILD_ASSERT((CONFIG_IMG_BLOCK_BUF_SIZE % FLASH_WRITE_BLOCK_SIZE == 0), |
|
|
|
"FLASH_WRITE_BLOCK_SIZE"); |
|
|
|
"FLASH_WRITE_BLOCK_SIZE"); |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define FLASH_CHECK_ERASED_BUFFER_SIZE 16 |
|
|
|
|
|
|
|
#define ERASED_VAL_32(x) (((x) << 24) | ((x) << 16) | ((x) << 8) | (x)) |
|
|
|
|
|
|
|
|
|
|
|
static int scramble_mcuboot_trailer(struct flash_img_context *ctx) |
|
|
|
static int scramble_mcuboot_trailer(struct flash_img_context *ctx) |
|
|
|
{ |
|
|
|
{ |
|
|
|
int rc = 0; |
|
|
|
int rc = 0; |
|
|
@ -132,10 +140,64 @@ size_t flash_img_bytes_written(struct flash_img_context *ctx) |
|
|
|
return stream_flash_bytes_written(&ctx->stream); |
|
|
|
return stream_flash_bytes_written(&ctx->stream); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_SWAP_USING_OFFSET) |
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Determines if the specified area of flash is completely unwritten. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param fa pointer to flash area to scan |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @return 0 when not empty, 1 when empty, negative errno code on error. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
static int flash_check_erased(const struct flash_area *fa) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
uint32_t data[FLASH_CHECK_ERASED_BUFFER_SIZE]; |
|
|
|
|
|
|
|
off_t addr; |
|
|
|
|
|
|
|
off_t end; |
|
|
|
|
|
|
|
int bytes_to_read; |
|
|
|
|
|
|
|
int rc; |
|
|
|
|
|
|
|
int i; |
|
|
|
|
|
|
|
uint8_t erased_val; |
|
|
|
|
|
|
|
uint32_t erased_val_32; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assert(fa->fa_size % sizeof(erased_val_32) == 0); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
erased_val = flash_area_erased_val(fa); |
|
|
|
|
|
|
|
erased_val_32 = ERASED_VAL_32(erased_val); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
end = fa->fa_size; |
|
|
|
|
|
|
|
for (addr = 0; addr < end; addr += sizeof(data)) { |
|
|
|
|
|
|
|
if (end - addr < sizeof(data)) { |
|
|
|
|
|
|
|
bytes_to_read = end - addr; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
bytes_to_read = sizeof(data); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
rc = flash_area_read(fa, addr, data, bytes_to_read); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (rc < 0) { |
|
|
|
|
|
|
|
LOG_ERR("Failed to read data from flash area: %d", rc); |
|
|
|
|
|
|
|
return rc; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < bytes_to_read / sizeof(erased_val_32); i++) { |
|
|
|
|
|
|
|
if (data[i] != erased_val_32) { |
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return 1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
int flash_img_init_id(struct flash_img_context *ctx, uint8_t area_id) |
|
|
|
int flash_img_init_id(struct flash_img_context *ctx, uint8_t area_id) |
|
|
|
{ |
|
|
|
{ |
|
|
|
int rc; |
|
|
|
int rc; |
|
|
|
const struct device *flash_dev; |
|
|
|
const struct device *flash_dev; |
|
|
|
|
|
|
|
#if defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_SWAP_USING_OFFSET) |
|
|
|
|
|
|
|
uint32_t sector_count = SWAP_USING_OFFSET_SECTOR_UPDATE_BEGIN; |
|
|
|
|
|
|
|
struct flash_sector sector_data; |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
rc = 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)); |
|
|
@ -145,9 +207,45 @@ int flash_img_init_id(struct flash_img_context *ctx, uint8_t area_id) |
|
|
|
|
|
|
|
|
|
|
|
flash_dev = flash_area_get_device(ctx->flash_area); |
|
|
|
flash_dev = flash_area_get_device(ctx->flash_area); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_SWAP_USING_OFFSET) |
|
|
|
|
|
|
|
/* Query size of first sector in flash for upgrade slot, so it can be erased, and begin
|
|
|
|
|
|
|
|
* upload started at the second sector |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
rc = flash_area_sectors((const struct flash_area *)ctx->flash_area, §or_count, |
|
|
|
|
|
|
|
§or_data); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (rc && rc != -ENOMEM) { |
|
|
|
|
|
|
|
flash_area_close(ctx->flash_area); |
|
|
|
|
|
|
|
ctx->flash_area = NULL; |
|
|
|
|
|
|
|
return rc; |
|
|
|
|
|
|
|
} else if (sector_count != SWAP_USING_OFFSET_SECTOR_UPDATE_BEGIN) { |
|
|
|
|
|
|
|
flash_area_close(ctx->flash_area); |
|
|
|
|
|
|
|
ctx->flash_area = NULL; |
|
|
|
|
|
|
|
return -ENOENT; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!flash_check_erased((const struct flash_area *)ctx->flash_area)) { |
|
|
|
|
|
|
|
/* Flash is not empty, therefore flatten/erase the area to prevent issues when
|
|
|
|
|
|
|
|
* the firmware update process begins |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
rc = flash_area_flatten((const struct flash_area *)ctx->flash_area, 0, |
|
|
|
|
|
|
|
sector_data.fs_size); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (rc) { |
|
|
|
|
|
|
|
flash_area_close(ctx->flash_area); |
|
|
|
|
|
|
|
ctx->flash_area = NULL; |
|
|
|
|
|
|
|
return rc; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return stream_flash_init(&ctx->stream, flash_dev, ctx->buf, CONFIG_IMG_BLOCK_BUF_SIZE, |
|
|
|
|
|
|
|
(ctx->flash_area->fa_off + sector_data.fs_size), |
|
|
|
|
|
|
|
(ctx->flash_area->fa_size - sector_data.fs_size), NULL); |
|
|
|
|
|
|
|
#else |
|
|
|
return stream_flash_init(&ctx->stream, flash_dev, ctx->buf, |
|
|
|
return stream_flash_init(&ctx->stream, flash_dev, ctx->buf, |
|
|
|
CONFIG_IMG_BLOCK_BUF_SIZE, ctx->flash_area->fa_off, |
|
|
|
CONFIG_IMG_BLOCK_BUF_SIZE, ctx->flash_area->fa_off, |
|
|
|
ctx->flash_area->fa_size, NULL); |
|
|
|
ctx->flash_area->fa_size, NULL); |
|
|
|
|
|
|
|
#endif |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#ifdef CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD |
|
|
|
#ifdef CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD |
|
|
@ -194,7 +292,7 @@ int flash_img_check(struct flash_img_context *ctx, |
|
|
|
|
|
|
|
|
|
|
|
fac.match = fic->match; |
|
|
|
fac.match = fic->match; |
|
|
|
fac.clen = fic->clen; |
|
|
|
fac.clen = fic->clen; |
|
|
|
fac.off = 0; |
|
|
|
fac.off = boot_get_image_start_offset(area_id); |
|
|
|
fac.rbuf = ctx->buf; |
|
|
|
fac.rbuf = ctx->buf; |
|
|
|
fac.rblen = sizeof(ctx->buf); |
|
|
|
fac.rblen = sizeof(ctx->buf); |
|
|
|
|
|
|
|
|
|
|
|