diff --git a/boot/bootutil/CMakeLists.txt b/boot/bootutil/CMakeLists.txt index 90977064f..3d1b32717 100644 --- a/boot/bootutil/CMakeLists.txt +++ b/boot/bootutil/CMakeLists.txt @@ -33,3 +33,9 @@ target_sources(bootutil src/swap_scratch.c src/tlv.c ) +if(CONFIG_BOOT_RAM_LOAD) + target_sources(bootutil + PRIVATE + src/ram_load.c + ) +endif() diff --git a/boot/bootutil/pkg.yml b/boot/bootutil/pkg.yml index e91978589..ed6f35810 100644 --- a/boot/bootutil/pkg.yml +++ b/boot/bootutil/pkg.yml @@ -45,6 +45,9 @@ pkg.ign_files.BOOTUTIL_SINGLE_APPLICATION_SLOT: - "loader.c" - "swap_scratch.c" +pkg.ign_files: + - "ram_load.c" + pkg.deps.BOOTUTIL_USE_MBED_TLS: - "@apache-mynewt-core/crypto/mbedtls" diff --git a/boot/bootutil/src/bootutil_misc.c b/boot/bootutil/src/bootutil_misc.c index 46202135c..09fbe8948 100644 --- a/boot/bootutil/src/bootutil_misc.c +++ b/boot/bootutil/src/bootutil_misc.c @@ -355,3 +355,68 @@ uint32_t bootutil_max_image_size(const struct flash_area *fap) return boot_swap_info_off(fap); #endif } + +/* + * Compute the total size of the given image. Includes the size of + * the TLVs. + */ +#if !defined(MCUBOOT_DIRECT_XIP) && \ + (!defined(MCUBOOT_OVERWRITE_ONLY) || \ + defined(MCUBOOT_OVERWRITE_ONLY_FAST)) +int +boot_read_image_size(struct boot_loader_state *state, int slot, uint32_t *size) +{ + const struct flash_area *fap; + struct image_tlv_info info; + uint32_t off; + uint32_t protect_tlv_size; + int area_id; + int rc; + +#if (BOOT_IMAGE_NUMBER == 1) + (void)state; +#endif + + area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot); + rc = flash_area_open(area_id, &fap); + if (rc != 0) { + rc = BOOT_EFLASH; + goto done; + } + + off = BOOT_TLV_OFF(boot_img_hdr(state, slot)); + + if (flash_area_read(fap, off, &info, sizeof(info))) { + rc = BOOT_EFLASH; + goto done; + } + + protect_tlv_size = boot_img_hdr(state, slot)->ih_protect_tlv_size; + if (info.it_magic == IMAGE_TLV_PROT_INFO_MAGIC) { + if (protect_tlv_size != info.it_tlv_tot) { + rc = BOOT_EBADIMAGE; + goto done; + } + + if (flash_area_read(fap, off + info.it_tlv_tot, &info, sizeof(info))) { + rc = BOOT_EFLASH; + goto done; + } + } else if (protect_tlv_size != 0) { + rc = BOOT_EBADIMAGE; + goto done; + } + + if (info.it_magic != IMAGE_TLV_INFO_MAGIC) { + rc = BOOT_EBADIMAGE; + goto done; + } + + *size = off + protect_tlv_size + info.it_tlv_tot; + rc = 0; + +done: + flash_area_close(fap); + return rc; +} +#endif /* !MCUBOOT_OVERWRITE_ONLY */ diff --git a/boot/bootutil/src/bootutil_priv.h b/boot/bootutil/src/bootutil_priv.h index 208d189b9..345933a5f 100644 --- a/boot/bootutil/src/bootutil_priv.h +++ b/boot/bootutil/src/bootutil_priv.h @@ -51,6 +51,8 @@ struct flash_area; #define BOOT_TMPBUF_SZ 256 +#define NO_ACTIVE_SLOT UINT32_MAX + /** Number of image slots in flash; currently limited to two. */ #define BOOT_NUM_SLOTS 2 @@ -467,15 +469,24 @@ struct bootsim_ram_info *bootsim_get_ram_info(void); #define LOAD_IMAGE_DATA(hdr, fap, start, output, size) \ (memcpy((output),(void*)(IMAGE_RAM_BASE + (hdr)->ih_load_addr + (start)), \ (size)), 0) + +int boot_load_image_to_sram(struct boot_loader_state *state); +int boot_remove_image_from_sram(struct boot_loader_state *state); +int boot_remove_image_from_flash(struct boot_loader_state *state, + uint32_t slot); #else #define IMAGE_RAM_BASE ((uintptr_t)0) #define LOAD_IMAGE_DATA(hdr, fap, start, output, size) \ (flash_area_read((fap), (start), (output), (size))) + #endif /* MCUBOOT_RAM_LOAD */ uint32_t bootutil_max_image_size(const struct flash_area *fap); +int boot_read_image_size(struct boot_loader_state *state, int slot, + uint32_t *size); + #ifdef __cplusplus } #endif diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 12d4abf40..1303394ad 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -110,8 +110,6 @@ static struct sector_buffer_t sector_buffers; #define BUF_SZ 1024 #endif -#define NO_ACTIVE_SLOT UINT32_MAX - static int boot_read_image_headers(struct boot_loader_state *state, bool require_all, struct boot_status *bs) @@ -482,11 +480,6 @@ boot_verify_dependencies(struct boot_loader_state *state) } #else -#if defined MCUBOOT_RAM_LOAD -static inline int -boot_remove_image_from_sram(struct boot_loader_state *state); -#endif - /** * Checks the dependency of all the active slots. If an image found with * invalid or not satisfied dependencies the image is removed from SRAM (in @@ -600,68 +593,6 @@ boot_verify_slot_dependencies(struct boot_loader_state *state, uint32_t slot) #endif /* (BOOT_IMAGE_NUMBER > 1) */ #if !defined(MCUBOOT_DIRECT_XIP) -/* - * Compute the total size of the given image. Includes the size of - * the TLVs. - */ -#if !defined(MCUBOOT_OVERWRITE_ONLY) || defined(MCUBOOT_OVERWRITE_ONLY_FAST) -static int -boot_read_image_size(struct boot_loader_state *state, int slot, uint32_t *size) -{ - const struct flash_area *fap; - struct image_tlv_info info; - uint32_t off; - uint32_t protect_tlv_size; - int area_id; - int rc; - -#if (BOOT_IMAGE_NUMBER == 1) - (void)state; -#endif - - area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot); - rc = flash_area_open(area_id, &fap); - if (rc != 0) { - rc = BOOT_EFLASH; - goto done; - } - - off = BOOT_TLV_OFF(boot_img_hdr(state, slot)); - - if (flash_area_read(fap, off, &info, sizeof(info))) { - rc = BOOT_EFLASH; - goto done; - } - - protect_tlv_size = boot_img_hdr(state, slot)->ih_protect_tlv_size; - if (info.it_magic == IMAGE_TLV_PROT_INFO_MAGIC) { - if (protect_tlv_size != info.it_tlv_tot) { - rc = BOOT_EBADIMAGE; - goto done; - } - - if (flash_area_read(fap, off + info.it_tlv_tot, &info, sizeof(info))) { - rc = BOOT_EFLASH; - goto done; - } - } else if (protect_tlv_size != 0) { - rc = BOOT_EBADIMAGE; - goto done; - } - - if (info.it_magic != IMAGE_TLV_INFO_MAGIC) { - rc = BOOT_EBADIMAGE; - goto done; - } - - *size = off + protect_tlv_size + info.it_tlv_tot; - rc = 0; - -done: - flash_area_close(fap); - return rc; -} -#endif /* !MCUBOOT_OVERWRITE_ONLY */ #if !defined(MCUBOOT_RAM_LOAD) static uint32_t @@ -2764,406 +2695,6 @@ boot_select_or_erase(struct boot_loader_state *state) } #endif /* MCUBOOT_DIRECT_XIP && MCUBOOT_DIRECT_XIP_REVERT */ -#ifdef MCUBOOT_RAM_LOAD - -#ifndef MULTIPLE_EXECUTABLE_RAM_REGIONS -#if !defined(IMAGE_EXECUTABLE_RAM_START) || !defined(IMAGE_EXECUTABLE_RAM_SIZE) -#error "Platform MUST define executable RAM bounds in case of RAM_LOAD" -#endif -#endif - -/** - * Verifies that the active slot of the current image can be loaded within the - * predefined bounds that are allowed to be used by executable images. - * - * @param state Boot loader status information. - * - * @return 0 on success; nonzero on failure. - */ -static int -boot_verify_ram_load_address(struct boot_loader_state *state) -{ - uint32_t img_dst; - uint32_t img_sz; - uint32_t img_end_addr; - uint32_t exec_ram_start; - uint32_t exec_ram_size; - - (void)state; - -#ifdef MULTIPLE_EXECUTABLE_RAM_REGIONS - int rc; - - rc = boot_get_image_exec_ram_info(BOOT_CURR_IMG(state), &exec_ram_start, - &exec_ram_size); - if (rc != 0) { - return BOOT_EBADSTATUS; - } -#else - exec_ram_start = IMAGE_EXECUTABLE_RAM_START; - exec_ram_size = IMAGE_EXECUTABLE_RAM_SIZE; -#endif - - img_dst = state->slot_usage[BOOT_CURR_IMG(state)].img_dst; - img_sz = state->slot_usage[BOOT_CURR_IMG(state)].img_sz; - - if (img_dst < exec_ram_start) { - return BOOT_EBADIMAGE; - } - - if (!boot_u32_safe_add(&img_end_addr, img_dst, img_sz)) { - return BOOT_EBADIMAGE; - } - - if (img_end_addr > (exec_ram_start + exec_ram_size)) { - return BOOT_EBADIMAGE; - } - - return 0; -} - -#ifdef MCUBOOT_ENC_IMAGES - -/** - * Copies and decrypts an image from a slot in the flash to an SRAM address. - * - * @param state Boot loader status information. - * @param slot The flash slot of the image to be copied to SRAM. - * @param hdr The image header. - * @param src_sz Size of the image. - * @param img_dst Pointer to the address at which the image needs to be - * copied to SRAM. - * - * @return 0 on success; nonzero on failure. - */ -static int -boot_decrypt_and_copy_image_to_sram(struct boot_loader_state *state, - uint32_t slot, struct image_header *hdr, - uint32_t src_sz, uint32_t img_dst) -{ - /* The flow for the decryption and copy of the image is as follows : - * 1. The whole image is copied to the RAM (header + payload + TLV). - * 2. The encryption key is loaded from the TLV in flash. - * 3. The image is then decrypted chunk by chunk in RAM (1 chunk - * is 1024 bytes). Only the payload section is decrypted. - * 4. The image is authenticated in RAM. - */ - const struct flash_area *fap_src = NULL; - struct boot_status bs; - uint32_t blk_off; - uint32_t tlv_off; - uint32_t blk_sz; - uint32_t bytes_copied = hdr->ih_hdr_size; - uint32_t chunk_sz; - uint32_t max_sz = 1024; - uint16_t idx; - uint8_t * cur_dst; - int area_id; - int rc; - uint8_t * ram_dst = (void *)(IMAGE_RAM_BASE + img_dst); - - area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot); - rc = flash_area_open(area_id, &fap_src); - if (rc != 0){ - return BOOT_EFLASH; - } - - tlv_off = BOOT_TLV_OFF(hdr); - - /* Copying the whole image in RAM */ - rc = flash_area_read(fap_src, 0, ram_dst, src_sz); - if (rc != 0) { - goto done; - } - - rc = boot_enc_load(BOOT_CURR_ENC(state), slot, hdr, fap_src, &bs); - if (rc < 0) { - goto done; - } - - /* if rc > 0 then the key has already been loaded */ - if (rc == 0 && boot_enc_set_key(BOOT_CURR_ENC(state), slot, &bs)) { - goto done; - } - - /* Starting at the end of the header as the header section is not encrypted */ - while (bytes_copied < tlv_off) { /* TLV section copied previously */ - if (src_sz - bytes_copied > max_sz) { - chunk_sz = max_sz; - } else { - chunk_sz = src_sz - bytes_copied; - } - - cur_dst = ram_dst + bytes_copied; - blk_sz = chunk_sz; - idx = 0; - blk_off = ((bytes_copied) - hdr->ih_hdr_size) & 0xf; - if (bytes_copied + chunk_sz > tlv_off) { - /* Going over TLV section - * Part of the chunk is encrypted payload */ - blk_sz = tlv_off - (bytes_copied); - } - boot_enc_decrypt(BOOT_CURR_ENC(state), slot, - (bytes_copied + idx) - hdr->ih_hdr_size, blk_sz, - blk_off, cur_dst); - bytes_copied += chunk_sz; - } - rc = 0; - -done: - flash_area_close(fap_src); - - return rc; -} - -#endif /* MCUBOOT_ENC_IMAGES */ -/** - * Copies a slot of the current image into SRAM. - * - * @param state Boot loader status information. - * @param slot The flash slot of the image to be copied to SRAM. - * @param img_dst The address at which the image needs to be copied to - * SRAM. - * @param img_sz The size of the image that needs to be copied to SRAM. - * - * @return 0 on success; nonzero on failure. - */ -static int -boot_copy_image_to_sram(struct boot_loader_state *state, int slot, - uint32_t img_dst, uint32_t img_sz) -{ - int rc; - const struct flash_area *fap_src = NULL; - int area_id; - -#if (BOOT_IMAGE_NUMBER == 1) - (void)state; -#endif - - area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot); - - rc = flash_area_open(area_id, &fap_src); - if (rc != 0) { - return BOOT_EFLASH; - } - - /* Direct copy from flash to its new location in SRAM. */ - rc = flash_area_read(fap_src, 0, (void *)(IMAGE_RAM_BASE + img_dst), img_sz); - if (rc != 0) { - BOOT_LOG_INF("Error whilst copying image %d from Flash to SRAM: %d", - BOOT_CURR_IMG(state), rc); - } - - flash_area_close(fap_src); - - return rc; -} - -#if (BOOT_IMAGE_NUMBER > 1) -/** - * Checks if two memory regions (A and B) are overlap or not. - * - * @param start_a Start of the A region. - * @param end_a End of the A region. - * @param start_b Start of the B region. - * @param end_b End of the B region. - * - * @return true if there is overlap; false otherwise. - */ -static bool -do_regions_overlap(uint32_t start_a, uint32_t end_a, - uint32_t start_b, uint32_t end_b) -{ - if (start_b > end_a) { - return false; - } else if (start_b >= start_a) { - return true; - } else if (end_b > start_a) { - return true; - } - - return false; -} - -/** - * Checks if the image we want to load to memory overlap with an already - * ramloaded image. - * - * @param state Boot loader status information. - * - * @return 0 if there is no overlap; nonzero otherwise. - */ -static int -boot_check_ram_load_overlapping(struct boot_loader_state *state) -{ - uint32_t i; - - uint32_t start_a; - uint32_t end_a; - uint32_t start_b; - uint32_t end_b; - uint32_t image_id_to_check = BOOT_CURR_IMG(state); - - start_a = state->slot_usage[image_id_to_check].img_dst; - /* Safe to add here, values are already verified in - * boot_verify_ram_load_address() */ - end_a = start_a + state->slot_usage[image_id_to_check].img_sz; - - for (i = 0; i < BOOT_IMAGE_NUMBER; i++) { - if (state->slot_usage[i].active_slot == NO_ACTIVE_SLOT - || i == image_id_to_check) { - continue; - } - - start_b = state->slot_usage[i].img_dst; - /* Safe to add here, values are already verified in - * boot_verify_ram_load_address() */ - end_b = start_b + state->slot_usage[i].img_sz; - - if (do_regions_overlap(start_a, end_a, start_b, end_b)) { - return -1; - } - } - - return 0; -} -#endif - -/** - * Loads the active slot of the current image into SRAM. The load address and - * image size is extracted from the image header. - * - * @param state Boot loader status information. - * - * @return 0 on success; nonzero on failure. - */ -static int -boot_load_image_to_sram(struct boot_loader_state *state) -{ - uint32_t active_slot; - struct image_header *hdr = NULL; - uint32_t img_dst; - uint32_t img_sz; - int rc; - - active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot; - hdr = boot_img_hdr(state, active_slot); - - if (hdr->ih_flags & IMAGE_F_RAM_LOAD) { - - img_dst = hdr->ih_load_addr; - - rc = boot_read_image_size(state, active_slot, &img_sz); - if (rc != 0) { - return rc; - } - - state->slot_usage[BOOT_CURR_IMG(state)].img_dst = img_dst; - state->slot_usage[BOOT_CURR_IMG(state)].img_sz = img_sz; - - rc = boot_verify_ram_load_address(state); - if (rc != 0) { - BOOT_LOG_INF("Image %d RAM load address 0x%x is invalid.", BOOT_CURR_IMG(state), img_dst); - return rc; - } - -#if (BOOT_IMAGE_NUMBER > 1) - rc = boot_check_ram_load_overlapping(state); - if (rc != 0) { - BOOT_LOG_INF("Image %d RAM loading to address 0x%x would overlap with\ - another image.", BOOT_CURR_IMG(state), img_dst); - return rc; - } -#endif -#ifdef MCUBOOT_ENC_IMAGES - /* decrypt image if encrypted and copy it to RAM */ - if (IS_ENCRYPTED(hdr)) { - rc = boot_decrypt_and_copy_image_to_sram(state, active_slot, hdr, img_sz, img_dst); - } else { - rc = boot_copy_image_to_sram(state, active_slot, img_dst, img_sz); - } -#else - /* Copy image to the load address from where it currently resides in - * flash. - */ - rc = boot_copy_image_to_sram(state, active_slot, img_dst, img_sz); -#endif - if (rc != 0) { - BOOT_LOG_INF("Image %d RAM loading to 0x%x is failed.", BOOT_CURR_IMG(state), img_dst); - } else { - BOOT_LOG_INF("Image %d RAM loading to 0x%x is succeeded.", BOOT_CURR_IMG(state), img_dst); - } - } else { - /* Only images that support IMAGE_F_RAM_LOAD are allowed if - * MCUBOOT_RAM_LOAD is set. - */ - rc = BOOT_EBADIMAGE; - } - - if (rc != 0) { - state->slot_usage[BOOT_CURR_IMG(state)].img_dst = 0; - state->slot_usage[BOOT_CURR_IMG(state)].img_sz = 0; - } - - return rc; -} - -/** - * Removes an image from SRAM, by overwriting it with zeros. - * - * @param state Boot loader status information. - * - * @return 0 on success; nonzero on failure. - */ -static inline int -boot_remove_image_from_sram(struct boot_loader_state *state) -{ - (void)state; - - BOOT_LOG_INF("Removing image %d from SRAM at address 0x%x", - BOOT_CURR_IMG(state), - state->slot_usage[BOOT_CURR_IMG(state)].img_dst); - - memset((void*)(IMAGE_RAM_BASE + state->slot_usage[BOOT_CURR_IMG(state)].img_dst), - 0, state->slot_usage[BOOT_CURR_IMG(state)].img_sz); - - state->slot_usage[BOOT_CURR_IMG(state)].img_dst = 0; - state->slot_usage[BOOT_CURR_IMG(state)].img_sz = 0; - - return 0; -} - -/** - * Removes an image from flash by erasing the corresponding flash area - * - * @param state Boot loader status information. - * @param slot The flash slot of the image to be erased. - * - * @return 0 on success; nonzero on failure. - */ -static inline int -boot_remove_image_from_flash(struct boot_loader_state *state, uint32_t slot) -{ - int area_id; - int rc; - const struct flash_area *fap; - - (void)state; - - BOOT_LOG_INF("Removing image %d slot %d from flash", BOOT_CURR_IMG(state), - slot); - area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot); - rc = flash_area_open(area_id, &fap); - if (rc == 0) { - flash_area_erase(fap, 0, flash_area_get_size(fap)); - flash_area_close(fap); - } - - return rc; -} -#endif /* MCUBOOT_RAM_LOAD */ - - /** * Tries to load a slot for all the images with validation. * diff --git a/boot/bootutil/src/ram_load.c b/boot/bootutil/src/ram_load.c new file mode 100644 index 000000000..72255367a --- /dev/null +++ b/boot/bootutil/src/ram_load.c @@ -0,0 +1,440 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2016-2020 Linaro LTD + * Copyright (c) 2016-2019 JUUL Labs + * Copyright (c) 2019-2023 Arm Limited + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * Original license: + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "bootutil/bootutil.h" +#include "bootutil/bootutil_log.h" +#include "bootutil/bootutil_public.h" +#include "bootutil/image.h" +#include "bootutil_priv.h" +#include "bootutil/fault_injection_hardening.h" +#include "bootutil/ramload.h" +#include "bootutil/mcuboot_status.h" + +#ifdef MCUBOOT_ENC_IMAGES +#include "bootutil/enc_key.h" +#endif + +#include "mcuboot_config/mcuboot_config.h" + +BOOT_LOG_MODULE_DECLARE(mcuboot); + +#ifndef MULTIPLE_EXECUTABLE_RAM_REGIONS +#if !defined(IMAGE_EXECUTABLE_RAM_START) || !defined(IMAGE_EXECUTABLE_RAM_SIZE) +#error "Platform MUST define executable RAM bounds in case of RAM_LOAD" +#endif +#endif + +/** + * Verifies that the active slot of the current image can be loaded within the + * predefined bounds that are allowed to be used by executable images. + * + * @param state Boot loader status information. + * + * @return 0 on success; nonzero on failure. + */ +static int +boot_verify_ram_load_address(struct boot_loader_state *state) +{ + uint32_t img_dst; + uint32_t img_sz; + uint32_t img_end_addr; + uint32_t exec_ram_start; + uint32_t exec_ram_size; + + (void)state; + +#ifdef MULTIPLE_EXECUTABLE_RAM_REGIONS + int rc; + + rc = boot_get_image_exec_ram_info(BOOT_CURR_IMG(state), &exec_ram_start, + &exec_ram_size); + if (rc != 0) { + return BOOT_EBADSTATUS; + } +#else + exec_ram_start = IMAGE_EXECUTABLE_RAM_START; + exec_ram_size = IMAGE_EXECUTABLE_RAM_SIZE; +#endif + + img_dst = state->slot_usage[BOOT_CURR_IMG(state)].img_dst; + img_sz = state->slot_usage[BOOT_CURR_IMG(state)].img_sz; + + if (img_dst < exec_ram_start) { + return BOOT_EBADIMAGE; + } + + if (!boot_u32_safe_add(&img_end_addr, img_dst, img_sz)) { + return BOOT_EBADIMAGE; + } + + if (img_end_addr > (exec_ram_start + exec_ram_size)) { + return BOOT_EBADIMAGE; + } + + return 0; +} + +#ifdef MCUBOOT_ENC_IMAGES + +/** + * Copies and decrypts an image from a slot in the flash to an SRAM address. + * + * @param state Boot loader status information. + * @param slot The flash slot of the image to be copied to SRAM. + * @param hdr The image header. + * @param src_sz Size of the image. + * @param img_dst Pointer to the address at which the image needs to be + * copied to SRAM. + * + * @return 0 on success; nonzero on failure. + */ +static int +boot_decrypt_and_copy_image_to_sram(struct boot_loader_state *state, + uint32_t slot, struct image_header *hdr, + uint32_t src_sz, uint32_t img_dst) +{ + /* The flow for the decryption and copy of the image is as follows : + * 1. The whole image is copied to the RAM (header + payload + TLV). + * 2. The encryption key is loaded from the TLV in flash. + * 3. The image is then decrypted chunk by chunk in RAM (1 chunk + * is 1024 bytes). Only the payload section is decrypted. + * 4. The image is authenticated in RAM. + */ + const struct flash_area *fap_src = NULL; + struct boot_status bs; + uint32_t blk_off; + uint32_t tlv_off; + uint32_t blk_sz; + uint32_t bytes_copied = hdr->ih_hdr_size; + uint32_t chunk_sz; + uint32_t max_sz = 1024; + uint16_t idx; + uint8_t * cur_dst; + int area_id; + int rc; + uint8_t * ram_dst = (void *)(IMAGE_RAM_BASE + img_dst); + + area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot); + rc = flash_area_open(area_id, &fap_src); + if (rc != 0){ + return BOOT_EFLASH; + } + + tlv_off = BOOT_TLV_OFF(hdr); + + /* Copying the whole image in RAM */ + rc = flash_area_read(fap_src, 0, ram_dst, src_sz); + if (rc != 0) { + goto done; + } + + rc = boot_enc_load(BOOT_CURR_ENC(state), slot, hdr, fap_src, &bs); + if (rc < 0) { + goto done; + } + + /* if rc > 0 then the key has already been loaded */ + if (rc == 0 && boot_enc_set_key(BOOT_CURR_ENC(state), slot, &bs)) { + goto done; + } + + /* Starting at the end of the header as the header section is not encrypted */ + while (bytes_copied < tlv_off) { /* TLV section copied previously */ + if (src_sz - bytes_copied > max_sz) { + chunk_sz = max_sz; + } else { + chunk_sz = src_sz - bytes_copied; + } + + cur_dst = ram_dst + bytes_copied; + blk_sz = chunk_sz; + idx = 0; + blk_off = ((bytes_copied) - hdr->ih_hdr_size) & 0xf; + if (bytes_copied + chunk_sz > tlv_off) { + /* Going over TLV section + * Part of the chunk is encrypted payload */ + blk_sz = tlv_off - (bytes_copied); + } + boot_enc_decrypt(BOOT_CURR_ENC(state), slot, + (bytes_copied + idx) - hdr->ih_hdr_size, blk_sz, + blk_off, cur_dst); + bytes_copied += chunk_sz; + } + rc = 0; + +done: + flash_area_close(fap_src); + + return rc; +} + +#endif /* MCUBOOT_ENC_IMAGES */ +/** + * Copies a slot of the current image into SRAM. + * + * @param state Boot loader status information. + * @param slot The flash slot of the image to be copied to SRAM. + * @param img_dst The address at which the image needs to be copied to + * SRAM. + * @param img_sz The size of the image that needs to be copied to SRAM. + * + * @return 0 on success; nonzero on failure. + */ +static int +boot_copy_image_to_sram(struct boot_loader_state *state, int slot, + uint32_t img_dst, uint32_t img_sz) +{ + int rc; + const struct flash_area *fap_src = NULL; + int area_id; + +#if (BOOT_IMAGE_NUMBER == 1) + (void)state; +#endif + + area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot); + + rc = flash_area_open(area_id, &fap_src); + if (rc != 0) { + return BOOT_EFLASH; + } + + /* Direct copy from flash to its new location in SRAM. */ + rc = flash_area_read(fap_src, 0, (void *)(IMAGE_RAM_BASE + img_dst), img_sz); + if (rc != 0) { + BOOT_LOG_INF("Error whilst copying image %d from Flash to SRAM: %d", + BOOT_CURR_IMG(state), rc); + } + + flash_area_close(fap_src); + + return rc; +} + +#if (BOOT_IMAGE_NUMBER > 1) +/** + * Checks if two memory regions (A and B) are overlap or not. + * + * @param start_a Start of the A region. + * @param end_a End of the A region. + * @param start_b Start of the B region. + * @param end_b End of the B region. + * + * @return true if there is overlap; false otherwise. + */ +static bool +do_regions_overlap(uint32_t start_a, uint32_t end_a, + uint32_t start_b, uint32_t end_b) +{ + if (start_b > end_a) { + return false; + } else if (start_b >= start_a) { + return true; + } else if (end_b > start_a) { + return true; + } + + return false; +} + +/** + * Checks if the image we want to load to memory overlap with an already + * ramloaded image. + * + * @param state Boot loader status information. + * + * @return 0 if there is no overlap; nonzero otherwise. + */ +static int +boot_check_ram_load_overlapping(struct boot_loader_state *state) +{ + uint32_t i; + + uint32_t start_a; + uint32_t end_a; + uint32_t start_b; + uint32_t end_b; + uint32_t image_id_to_check = BOOT_CURR_IMG(state); + + start_a = state->slot_usage[image_id_to_check].img_dst; + /* Safe to add here, values are already verified in + * boot_verify_ram_load_address() */ + end_a = start_a + state->slot_usage[image_id_to_check].img_sz; + + for (i = 0; i < BOOT_IMAGE_NUMBER; i++) { + if (state->slot_usage[i].active_slot == NO_ACTIVE_SLOT + || i == image_id_to_check) { + continue; + } + + start_b = state->slot_usage[i].img_dst; + /* Safe to add here, values are already verified in + * boot_verify_ram_load_address() */ + end_b = start_b + state->slot_usage[i].img_sz; + + if (do_regions_overlap(start_a, end_a, start_b, end_b)) { + return -1; + } + } + + return 0; +} +#endif + +/** + * Loads the active slot of the current image into SRAM. The load address and + * image size is extracted from the image header. + * + * @param state Boot loader status information. + * + * @return 0 on success; nonzero on failure. + */ +int +boot_load_image_to_sram(struct boot_loader_state *state) +{ + uint32_t active_slot; + struct image_header *hdr = NULL; + uint32_t img_dst; + uint32_t img_sz; + int rc; + + active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot; + hdr = boot_img_hdr(state, active_slot); + + if (hdr->ih_flags & IMAGE_F_RAM_LOAD) { + + img_dst = hdr->ih_load_addr; + + rc = boot_read_image_size(state, active_slot, &img_sz); + if (rc != 0) { + return rc; + } + + state->slot_usage[BOOT_CURR_IMG(state)].img_dst = img_dst; + state->slot_usage[BOOT_CURR_IMG(state)].img_sz = img_sz; + + rc = boot_verify_ram_load_address(state); + if (rc != 0) { + BOOT_LOG_INF("Image %d RAM load address 0x%x is invalid.", BOOT_CURR_IMG(state), img_dst); + return rc; + } + +#if (BOOT_IMAGE_NUMBER > 1) + rc = boot_check_ram_load_overlapping(state); + if (rc != 0) { + BOOT_LOG_INF("Image %d RAM loading to address 0x%x would overlap with\ + another image.", BOOT_CURR_IMG(state), img_dst); + return rc; + } +#endif +#ifdef MCUBOOT_ENC_IMAGES + /* decrypt image if encrypted and copy it to RAM */ + if (IS_ENCRYPTED(hdr)) { + rc = boot_decrypt_and_copy_image_to_sram(state, active_slot, hdr, img_sz, img_dst); + } else { + rc = boot_copy_image_to_sram(state, active_slot, img_dst, img_sz); + } +#else + /* Copy image to the load address from where it currently resides in + * flash. + */ + rc = boot_copy_image_to_sram(state, active_slot, img_dst, img_sz); +#endif + if (rc != 0) { + BOOT_LOG_INF("Image %d RAM loading to 0x%x is failed.", BOOT_CURR_IMG(state), img_dst); + } else { + BOOT_LOG_INF("Image %d RAM loading to 0x%x is succeeded.", BOOT_CURR_IMG(state), img_dst); + } + } else { + /* Only images that support IMAGE_F_RAM_LOAD are allowed if + * MCUBOOT_RAM_LOAD is set. + */ + rc = BOOT_EBADIMAGE; + } + + if (rc != 0) { + state->slot_usage[BOOT_CURR_IMG(state)].img_dst = 0; + state->slot_usage[BOOT_CURR_IMG(state)].img_sz = 0; + } + + return rc; +} + +/** + * Removes an image from SRAM, by overwriting it with zeros. + * + * @param state Boot loader status information. + * + * @return 0 on success; nonzero on failure. + */ +int +boot_remove_image_from_sram(struct boot_loader_state *state) +{ + (void)state; + + BOOT_LOG_INF("Removing image %d from SRAM at address 0x%x", + BOOT_CURR_IMG(state), + state->slot_usage[BOOT_CURR_IMG(state)].img_dst); + + memset((void*)(IMAGE_RAM_BASE + state->slot_usage[BOOT_CURR_IMG(state)].img_dst), + 0, state->slot_usage[BOOT_CURR_IMG(state)].img_sz); + + state->slot_usage[BOOT_CURR_IMG(state)].img_dst = 0; + state->slot_usage[BOOT_CURR_IMG(state)].img_sz = 0; + + return 0; +} + +/** + * Removes an image from flash by erasing the corresponding flash area + * + * @param state Boot loader status information. + * @param slot The flash slot of the image to be erased. + * + * @return 0 on success; nonzero on failure. + */ +int +boot_remove_image_from_flash(struct boot_loader_state *state, uint32_t slot) +{ + int area_id; + int rc; + const struct flash_area *fap; + + (void)state; + + BOOT_LOG_INF("Removing image %d slot %d from flash", BOOT_CURR_IMG(state), + slot); + area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot); + rc = flash_area_open(area_id, &fap); + if (rc == 0) { + flash_area_erase(fap, 0, flash_area_get_size(fap)); + flash_area_close(fap); + } + + return rc; +} diff --git a/boot/espressif/CMakeLists.txt b/boot/espressif/CMakeLists.txt index bc703fc24..d1e18d2da 100644 --- a/boot/espressif/CMakeLists.txt +++ b/boot/espressif/CMakeLists.txt @@ -231,6 +231,12 @@ set(bootutil_srcs ${BOOTUTIL_DIR}/src/swap_scratch.c ${BOOTUTIL_DIR}/src/tlv.c ) + +if(CONFIG_BOOT_RAM_LOAD) + list(APPEND bootutil_srcs + ${BOOTUTIL_DIR}/src/ram_load.c + ) +endif() set(bootutil_paths) set(CFLAGS diff --git a/boot/espressif/hal/include/mcuboot_config/mcuboot_config.h b/boot/espressif/hal/include/mcuboot_config/mcuboot_config.h index a7058e747..a299e3cfc 100644 --- a/boot/espressif/hal/include/mcuboot_config/mcuboot_config.h +++ b/boot/espressif/hal/include/mcuboot_config/mcuboot_config.h @@ -57,8 +57,10 @@ /* Uncomment to enable the direct-xip code path. */ /* #define MCUBOOT_DIRECT_XIP */ -/* Uncomment to enable the ram-load code path. */ -/* #define MCUBOOT_RAM_LOAD */ +/* Define to enable the ram-load code path. */ +#if defined(CONFIG_BOOT_RAM_LOAD) +#define MCUBOOT_RAM_LOAD +#endif /* * Cryptographic settings diff --git a/boot/mynewt/pkg.yml b/boot/mynewt/pkg.yml index e0b313275..9645a5e90 100644 --- a/boot/mynewt/pkg.yml +++ b/boot/mynewt/pkg.yml @@ -39,6 +39,8 @@ pkg.ign_files.!BOOTUTIL_SINGLE_APPLICATION_SLOT: - "single_loader.c" pkg.ign_files.BOOTUTIL_SINGLE_APPLICATION_SLOT: - "swap_scratch.c" +pkg.ign_files: + - "ram_load.c" pkg.deps.BOOTUTIL_NO_LOGGING: - "@apache-mynewt-core/sys/console/stub" diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index 144dabd9e..ba62d2bc8 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -143,6 +143,12 @@ zephyr_library_sources( ) endif() +if(CONFIG_BOOT_RAM_LOAD) + zephyr_library_sources( + ${BOOT_DIR}/bootutil/src/ram_load.c + ) +endif() + if(CONFIG_BOOT_SIGNATURE_TYPE_ECDSA_P256 OR CONFIG_BOOT_ENCRYPT_EC256) zephyr_library_include_directories( ${MBEDTLS_ASN1_DIR}/include diff --git a/sim/mcuboot-sys/build.rs b/sim/mcuboot-sys/build.rs index ea17d8014..47ee880c5 100644 --- a/sim/mcuboot-sys/build.rs +++ b/sim/mcuboot-sys/build.rs @@ -455,6 +455,9 @@ fn main() { } conf.file("../../boot/bootutil/src/loader.c"); + if ram_load { + conf.file("../../boot/bootutil/src/ram_load.c"); + } conf.file("../../boot/bootutil/src/swap_misc.c"); conf.file("../../boot/bootutil/src/swap_scratch.c"); conf.file("../../boot/bootutil/src/swap_move.c");