/* * Copyright (c) 2017, 2020 Nordic Semiconductor ASA * Copyright (c) 2017 Linaro Limited * Copyright (c) 2020 Gerson Fernando Budke * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #include #include #ifdef CONFIG_IMG_ERASE_PROGRESSIVELY #include #include #endif #include #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