185 lines
4.5 KiB
C
185 lines
4.5 KiB
C
/*
|
|
* Copyright (c) 2017, 2020 Nordic Semiconductor ASA
|
|
* Copyright (c) 2017 Linaro Limited
|
|
* Copyright (c) 2020 Gerson Fernando Budke <nandojve@gmail.com>
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
#include <zephyr/types.h>
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <zephyr/dfu/flash_img.h>
|
|
#include <zephyr/storage/flash_map.h>
|
|
#include <zephyr/storage/stream_flash.h>
|
|
|
|
#ifdef CONFIG_IMG_ERASE_PROGRESSIVELY
|
|
#include <bootutil/bootutil_public.h>
|
|
#include <zephyr/dfu/mcuboot.h>
|
|
#endif
|
|
|
|
#include <zephyr/devicetree.h>
|
|
#ifdef CONFIG_TRUSTED_EXECUTION_NONSECURE
|
|
#define UPLOAD_FLASH_AREA_LABEL slot1_ns_partition
|
|
#else
|
|
#if FIXED_PARTITION_EXISTS(slot1_partition)
|
|
#define UPLOAD_FLASH_AREA_LABEL slot1_partition
|
|
#else
|
|
#define UPLOAD_FLASH_AREA_LABEL slot0_partition
|
|
#endif
|
|
#endif
|
|
|
|
/* FIXED_PARTITION_ID() values used below are auto-generated by DT */
|
|
#define UPLOAD_FLASH_AREA_ID FIXED_PARTITION_ID(UPLOAD_FLASH_AREA_LABEL)
|
|
#define UPLOAD_FLASH_AREA_CONTROLLER \
|
|
DT_GPARENT(DT_NODELABEL(UPLOAD_FLASH_AREA_LABEL))
|
|
|
|
#if DT_NODE_HAS_PROP(UPLOAD_FLASH_AREA_CONTROLLER, write_block_size)
|
|
#define FLASH_WRITE_BLOCK_SIZE \
|
|
DT_PROP(UPLOAD_FLASH_AREA_CONTROLLER, write_block_size)
|
|
|
|
BUILD_ASSERT((CONFIG_IMG_BLOCK_BUF_SIZE % FLASH_WRITE_BLOCK_SIZE == 0),
|
|
"CONFIG_IMG_BLOCK_BUF_SIZE is not a multiple of "
|
|
"FLASH_WRITE_BLOCK_SIZE");
|
|
#endif
|
|
|
|
static int scramble_mcuboot_trailer(struct flash_img_context *ctx)
|
|
{
|
|
int rc = 0;
|
|
|
|
#ifdef CONFIG_IMG_ERASE_PROGRESSIVELY
|
|
if (stream_flash_bytes_written(&ctx->stream) == 0) {
|
|
off_t toff = boot_get_trailer_status_offset(ctx->flash_area->fa_size);
|
|
off_t offset;
|
|
size_t size;
|
|
const struct flash_parameters *fparams =
|
|
flash_get_parameters(flash_area_get_device(ctx->flash_area));
|
|
#ifdef CONFIG_STREAM_FLASH_ERASE
|
|
/* for erasable devices prgressive-erase works only along with
|
|
* CONFIG_STREAM_FLASH_ERASE option.
|
|
*/
|
|
if (flash_params_get_erase_cap(fparams) & FLASH_ERASE_C_EXPLICIT) {
|
|
/* On devices with explicit erase we are aligning to page
|
|
* layout.
|
|
*/
|
|
struct flash_pages_info info;
|
|
|
|
rc = flash_get_page_info_by_offs(flash_area_get_device(ctx->flash_area),
|
|
toff, &info);
|
|
if (rc != 0) {
|
|
return rc;
|
|
}
|
|
offset = info.start_offset;
|
|
size = info.size;
|
|
|
|
} else
|
|
#endif
|
|
{
|
|
/* On devices with no erase, we are aligning to write block
|
|
* size.
|
|
*/
|
|
offset = (toff + fparams->write_block_size - 1) &
|
|
~(fparams->write_block_size - 1);
|
|
/* No alignment correction needed here, offset is corrected already
|
|
* and, size should be aligned.
|
|
*/
|
|
size = ctx->flash_area->fa_size - offset;
|
|
}
|
|
|
|
rc = flash_area_flatten(ctx->flash_area, offset, size);
|
|
}
|
|
#endif
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
int flash_img_buffered_write(struct flash_img_context *ctx, const uint8_t *data,
|
|
size_t len, bool flush)
|
|
{
|
|
int rc;
|
|
|
|
/* If there is a need to erase the trailer, that should happen before any
|
|
* write is done to partition.
|
|
*/
|
|
rc = scramble_mcuboot_trailer(ctx);
|
|
if (rc != 0) {
|
|
return rc;
|
|
}
|
|
|
|
|
|
/* if CONFIG_IMG_ERASE_PROGRESSIVELY is enabled the enabled CONFIG_STREAM_FLASH_ERASE
|
|
* ensures that stream_flash erases flash progresively.
|
|
*/
|
|
rc = stream_flash_buffered_write(&ctx->stream, data, len, flush);
|
|
if (!flush) {
|
|
return rc;
|
|
}
|
|
|
|
flash_area_close(ctx->flash_area);
|
|
ctx->flash_area = NULL;
|
|
|
|
return rc;
|
|
}
|
|
|
|
size_t flash_img_bytes_written(struct flash_img_context *ctx)
|
|
{
|
|
return stream_flash_bytes_written(&ctx->stream);
|
|
}
|
|
|
|
int flash_img_init_id(struct flash_img_context *ctx, uint8_t area_id)
|
|
{
|
|
int rc;
|
|
const struct device *flash_dev;
|
|
|
|
rc = flash_area_open(area_id,
|
|
(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)
|
|
{
|
|
return flash_img_init_id(ctx, UPLOAD_FLASH_AREA_ID);
|
|
}
|
|
|
|
#if defined(CONFIG_IMG_ENABLE_IMAGE_CHECK)
|
|
int flash_img_check(struct flash_img_context *ctx,
|
|
const struct flash_img_check *fic,
|
|
uint8_t area_id)
|
|
{
|
|
struct flash_area_check fac;
|
|
int rc;
|
|
|
|
if (!ctx || !fic) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
rc = flash_area_open(area_id,
|
|
(const struct flash_area **)&(ctx->flash_area));
|
|
if (rc) {
|
|
return rc;
|
|
}
|
|
|
|
fac.match = fic->match;
|
|
fac.clen = fic->clen;
|
|
fac.off = 0;
|
|
fac.rbuf = ctx->buf;
|
|
fac.rblen = sizeof(ctx->buf);
|
|
|
|
rc = flash_area_check_int_sha256(ctx->flash_area, &fac);
|
|
|
|
flash_area_close(ctx->flash_area);
|
|
ctx->flash_area = NULL;
|
|
|
|
return rc;
|
|
}
|
|
#endif
|