From 0b4228645a8e9ab78ef04e491070b309af18e6c9 Mon Sep 17 00:00:00 2001 From: pennam Date: Wed, 15 Mar 2023 09:54:03 +0100 Subject: [PATCH 1/4] MCUboot library: remove precompiled library and add source code --- libraries/MCUboot/library.properties | 2 - libraries/MCUboot/src/MCUboot.cpp | 14 +- libraries/MCUboot/src/bootutil.h | 16 - libraries/MCUboot/src/bootutil/boot_hooks.h | 160 +++++ .../MCUboot/src/bootutil/boot_public_hooks.h | 52 ++ libraries/MCUboot/src/bootutil/bootutil.h | 88 +++ libraries/MCUboot/src/bootutil/bootutil_log.h | 59 ++ .../MCUboot/src/bootutil/bootutil_priv.h | 442 ++++++++++++ .../MCUboot/src/bootutil/bootutil_public.c | 659 ++++++++++++++++++ .../MCUboot/src/bootutil/bootutil_public.h | 284 ++++++++ .../src/bootutil/fault_injection_hardening.h | 377 ++++++++++ libraries/MCUboot/src/bootutil/ignore.h | 70 ++ libraries/MCUboot/src/bootutil/image.h | 191 +++++ libraries/MCUboot/src/cortex-m7/libbootutil.a | Bin 46134 -> 0 bytes .../src/fileblockdevice/FileBlockDevice.cpp | 220 ++++++ .../src/fileblockdevice/FileBlockDevice.h | 203 ++++++ .../flash_map_backend/flash_map_backend.cpp | 244 +++++++ .../src/flash_map_backend/flash_map_backend.h | 178 +++++ .../src/flash_map_backend/secondary_bd.cpp | 64 ++ .../src/flash_map_backend/secondary_bd.h | 56 ++ .../src/mcuboot_config/mcuboot_config.h | 106 +++ .../src/mcuboot_config/mcuboot_logging.h | 117 ++++ libraries/MCUboot/src/sysflash/sysflash.h | 14 + 23 files changed, 3596 insertions(+), 20 deletions(-) delete mode 100644 libraries/MCUboot/src/bootutil.h create mode 100644 libraries/MCUboot/src/bootutil/boot_hooks.h create mode 100644 libraries/MCUboot/src/bootutil/boot_public_hooks.h create mode 100644 libraries/MCUboot/src/bootutil/bootutil.h create mode 100644 libraries/MCUboot/src/bootutil/bootutil_log.h create mode 100644 libraries/MCUboot/src/bootutil/bootutil_priv.h create mode 100644 libraries/MCUboot/src/bootutil/bootutil_public.c create mode 100644 libraries/MCUboot/src/bootutil/bootutil_public.h create mode 100644 libraries/MCUboot/src/bootutil/fault_injection_hardening.h create mode 100644 libraries/MCUboot/src/bootutil/ignore.h create mode 100644 libraries/MCUboot/src/bootutil/image.h delete mode 100644 libraries/MCUboot/src/cortex-m7/libbootutil.a create mode 100644 libraries/MCUboot/src/fileblockdevice/FileBlockDevice.cpp create mode 100644 libraries/MCUboot/src/fileblockdevice/FileBlockDevice.h create mode 100644 libraries/MCUboot/src/flash_map_backend/flash_map_backend.cpp create mode 100644 libraries/MCUboot/src/flash_map_backend/flash_map_backend.h create mode 100644 libraries/MCUboot/src/flash_map_backend/secondary_bd.cpp create mode 100644 libraries/MCUboot/src/flash_map_backend/secondary_bd.h create mode 100644 libraries/MCUboot/src/mcuboot_config/mcuboot_config.h create mode 100644 libraries/MCUboot/src/mcuboot_config/mcuboot_logging.h create mode 100644 libraries/MCUboot/src/sysflash/sysflash.h diff --git a/libraries/MCUboot/library.properties b/libraries/MCUboot/library.properties index 74cc8f801..a443e4677 100644 --- a/libraries/MCUboot/library.properties +++ b/libraries/MCUboot/library.properties @@ -7,5 +7,3 @@ paragraph= category=Other url= architectures=mbed,mbed_portenta -precompiled=true -ldflags=-lbootutil \ No newline at end of file diff --git a/libraries/MCUboot/src/MCUboot.cpp b/libraries/MCUboot/src/MCUboot.cpp index 1346c45e1..29528f4b1 100644 --- a/libraries/MCUboot/src/MCUboot.cpp +++ b/libraries/MCUboot/src/MCUboot.cpp @@ -1,5 +1,7 @@ #include "MCUboot.h" -#include "bootutil.h" +#include "bootutil/bootutil_public.h" +#include "STM32H747_System.h" + void MCUboot::confirmSketch() { @@ -13,5 +15,13 @@ void MCUboot::applyUpdate(int permanent) void MCUboot::bootDebug(int enable) { - boot_set_debug(enable); + unsigned int rtc_reg = STM32H747::readBackupRegister(RTCBackup::DR7); + + if(enable) { + rtc_reg |= 0x00000001; + } else { + rtc_reg &= ~0x00000001; + } + + return STM32H747::writeBackupRegister(RTCBackup::DR7, rtc_reg); } diff --git a/libraries/MCUboot/src/bootutil.h b/libraries/MCUboot/src/bootutil.h deleted file mode 100644 index 4068d021e..000000000 --- a/libraries/MCUboot/src/bootutil.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef __BOOTUTIL_H -#define __BOOTUTIL_H - -#ifdef __cplusplus -extern "C" { -#endif - -int boot_set_confirmed(void); -int boot_set_pending(int permanent); -int boot_set_debug(int enable); - -#ifdef __cplusplus -} -#endif - -#endif /* __BOOTUTIL_H */ \ No newline at end of file diff --git a/libraries/MCUboot/src/bootutil/boot_hooks.h b/libraries/MCUboot/src/bootutil/boot_hooks.h new file mode 100644 index 000000000..61de3c44c --- /dev/null +++ b/libraries/MCUboot/src/bootutil/boot_hooks.h @@ -0,0 +1,160 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2021 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. + */ + +/** + * @file + * @brief Hooks definition implementation API + * + * This file contains API interface definition for hooks which can be + * implemented to overide or to amend some of MCUboot's native routines. + */ + +#ifndef H_BOOTUTIL_HOOKS +#define H_BOOTUTIL_HOOKS + +#ifdef MCUBOOT_IMAGE_ACCESS_HOOKS + +#define BOOT_HOOK_CALL(f, ret_default, ...) f(__VA_ARGS__) + +#define BOOT_HOOK_CALL_FIH(f, fih_ret_default, fih_rc, ...) \ + do { \ + FIH_CALL(f, fih_rc, __VA_ARGS__); \ + } while(0); + +#else + +#define BOOT_HOOK_CALL(f, ret_default, ...) ret_default + +#define BOOT_HOOK_CALL_FIH(f, fih_ret_default, fih_rc, ...) \ + do { \ + fih_rc = fih_ret_default; \ + } while(0); + +#endif + +/** Hook for provide image header data. + * + * This Hook may be used to overide image header read implementation or doing + * a custom action before. + * + * @param img_index the index of the image pair + * @param slot slot number + * @param img_head image header structure to be populated + * + * @retval 0: header was read/populated, skip direct header data read + * BOOT_HOOK_REGULAR: follow the normal execution path, + * otherwise an error-code value. + */ +int boot_read_image_header_hook(int img_index, int slot, + struct image_header *img_head); + +/** Hook for Validate image hash/signature + * + * This Hook may be used to overide image validation procedure or doing + * a custom action before. + * + * @param img_index the index of the image pair + * @param slot slot number + * + * @retval FIH_SUCCESS: image is valid, skip direct validation + * FIH_FAILURE: image is invalid, skip direct validation + * fih encoded BOOT_HOOK_REGULAR: follow the normal execution path. + */ +fih_int boot_image_check_hook(int img_index, int slot); + +/** Hook for implement image update + * + * This hook is for for implementing an alternative mechanism of image update or + * doing a custom action before. + * + * @param img_index the index of the image pair + * @param img_head the image header of the secondary image + * @param area the flash area of the secondary image. + * + * @retval 0: update was done, skip performing the update + * BOOT_HOOK_REGULAR: follow the normal execution path, + * otherwise an error-code value. + */ +int boot_perform_update_hook(int img_index, struct image_header *img_head, + const struct flash_area *area); + +/** Hook for implement image's post copying action + * + * This hook is for implement action which might be done right after image was + * copied to the primary slot. This hook is called in MCUBOOT_OVERWRITE_ONLY + * mode only. + * + * @param img_index the index of the image pair + * @param area the flash area of the primary image. + * @param size size of copied image. + * + * @retval 0: success, mcuboot will follow normal code execution flow after + * execution of this call. + * non-zero: an error, mcuboot will return from + * boot_copy_image() with error. + * Update will be undone so might be resume on the next boot. + */ +int boot_copy_region_post_hook(int img_index, const struct flash_area *area, + size_t size); + +/** Hook for implement image's post recovery upload action + * + * This hook is for implement action which might be done right after image was + * copied to the primary slot. This hook is called in serial recovery upload + * operation. + * + * @param img_index the index of the image pair + * @param area the flash area of the primary image. + * @param size size of copied image. + * + * @retval 0: success, mcuboot will follow normal code execution flow after + * execution of this call. + * non-zero: an error, will be transferred as part of comand response + * as "rc" entry. + */ +int boot_serial_uploaded_hook(int img_index, const struct flash_area *area, + size_t size); + +/** Hook for implement the image's slot installation status fetch operation for + * the MGMT custom command. + * + * The image's slot installation status is custom property. It's detailed + * definition depends on user implementation. It is only defined that the status + * will be set to 0 if this hook not provides another value. + * + * @param img_index the index of the image pair + * @param slot slot number + * @param img_install_stat the image installation status to be populated + * + * @retval 0: the installaton status was fetched successfully, + * BOOT_HOOK_REGULAR: follow the normal execution path, status will be + * set to 0 + * otherwise an error-code value. Error-code is ignored, but it is up to + * the implementation to reflect this error in img_install_stat. + */ +int boot_img_install_stat_hook(int image_index, int slot, + int *img_install_stat); + +#endif /*H_BOOTUTIL_HOOKS*/ diff --git a/libraries/MCUboot/src/bootutil/boot_public_hooks.h b/libraries/MCUboot/src/bootutil/boot_public_hooks.h new file mode 100644 index 000000000..453edf2cd --- /dev/null +++ b/libraries/MCUboot/src/bootutil/boot_public_hooks.h @@ -0,0 +1,52 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2021 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. + */ + +/** + * @file + * @brief Hooks definition implementation API + * + * This file contains API interface definition for hooks which can be + * implemented for overide some of MCUboot's native routines. + */ + +#ifndef H_BOOTUTIL_PUBLIC_HOOKS +#define H_BOOTUTIL_PUBLIC_HOOKS + +#include "bootutil/boot_hooks.h" + +/** Hook for provide primary image swap state. + * + * @param img_index the index of the image pair + * @param state image swap state structure to be populated + * + * @retval 0: header was read/populated + * FIH_FAILURE: image is invalid, + * BOOT_HOOK_REGULAR if hook not implemented for the image-slot, + * othervise an error-code value. + */ +int boot_read_swap_state_primary_slot_hook(int image_index, + struct boot_swap_state *state); + +#endif /*H_BOOTUTIL_PUBLIC_HOOKS*/ diff --git a/libraries/MCUboot/src/bootutil/bootutil.h b/libraries/MCUboot/src/bootutil/bootutil.h new file mode 100644 index 000000000..528740547 --- /dev/null +++ b/libraries/MCUboot/src/bootutil/bootutil.h @@ -0,0 +1,88 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2017-2019 Linaro LTD + * Copyright (c) 2016-2019 JUUL Labs + * Copyright (c) 2019-2020 Arm Limited + * + * 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. + */ + +#ifndef H_BOOTUTIL_ +#define H_BOOTUTIL_ + +#include +#include "bootutil/fault_injection_hardening.h" +#include "bootutil/bootutil_public.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct image_header; +/** + * A response object provided by the boot loader code; indicates where to jump + * to execute the main image. + */ +struct boot_rsp { + /** A pointer to the header of the image to be executed. */ + const struct image_header *br_hdr; + + /** + * The flash offset of the image to execute. Indicates the position of + * the image header within its flash device. + */ + uint8_t br_flash_dev_id; + uint32_t br_image_off; +}; + +/* This is not actually used by mcuboot's code but can be used by apps + * when attempting to read/write a trailer. + */ +struct image_trailer { + uint8_t swap_type; + uint8_t pad1[BOOT_MAX_ALIGN - 1]; + uint8_t copy_done; + uint8_t pad2[BOOT_MAX_ALIGN - 1]; + uint8_t image_ok; + uint8_t pad3[BOOT_MAX_ALIGN - 1]; +#if BOOT_MAX_ALIGN > BOOT_MAGIC_SZ + uint8_t pad4[BOOT_MAGIC_ALIGN_SIZE - BOOT_MAGIC_SZ]; +#endif + uint8_t magic[BOOT_MAGIC_SZ]; +}; + +/* you must have pre-allocated all the entries within this structure */ +fih_int boot_go(struct boot_rsp *rsp); + +struct boot_loader_state; +fih_int context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp); + +#define SPLIT_GO_OK (0) +#define SPLIT_GO_NON_MATCHING (-1) +#define SPLIT_GO_ERR (-2) + +fih_int split_go(int loader_slot, int split_slot, void **entry); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libraries/MCUboot/src/bootutil/bootutil_log.h b/libraries/MCUboot/src/bootutil/bootutil_log.h new file mode 100644 index 000000000..f2c70b9d4 --- /dev/null +++ b/libraries/MCUboot/src/bootutil/bootutil_log.h @@ -0,0 +1,59 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2017 Linaro Limited + * + * Licensed 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. + */ + +#ifndef H_BOOTUTIL_LOG_H_ +#define H_BOOTUTIL_LOG_H_ + +#include "ignore.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifdef MCUBOOT_HAVE_LOGGING +#include + +#define BOOT_LOG_ERR(...) MCUBOOT_LOG_ERR(__VA_ARGS__) +#define BOOT_LOG_WRN(...) MCUBOOT_LOG_WRN(__VA_ARGS__) +#define BOOT_LOG_INF(...) MCUBOOT_LOG_INF(__VA_ARGS__) +#define BOOT_LOG_DBG(...) MCUBOOT_LOG_DBG(__VA_ARGS__) +#define BOOT_LOG_SIM(...) MCUBOOT_LOG_SIM(__VA_ARGS__) + +#define BOOT_LOG_MODULE_DECLARE(module) MCUBOOT_LOG_MODULE_DECLARE(module) +#define BOOT_LOG_MODULE_REGISTER(module) MCUBOOT_LOG_MODULE_REGISTER(module) + +#else + +#define BOOT_LOG_ERR(...) IGNORE(__VA_ARGS__) +#define BOOT_LOG_WRN(...) IGNORE(__VA_ARGS__) +#define BOOT_LOG_INF(...) IGNORE(__VA_ARGS__) +#define BOOT_LOG_DBG(...) IGNORE(__VA_ARGS__) +#define BOOT_LOG_SIM(...) IGNORE(__VA_ARGS__) + +#define BOOT_LOG_MODULE_DECLARE(module) +#define BOOT_LOG_MODULE_REGISTER(module) + +#endif /* MCUBOOT_HAVE_LOGGING */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libraries/MCUboot/src/bootutil/bootutil_priv.h b/libraries/MCUboot/src/bootutil/bootutil_priv.h new file mode 100644 index 000000000..b59326d77 --- /dev/null +++ b/libraries/MCUboot/src/bootutil/bootutil_priv.h @@ -0,0 +1,442 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2017-2020 Linaro LTD + * Copyright (c) 2017-2019 JUUL Labs + * Copyright (c) 2019-2021 Arm Limited + * + * 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. + */ + +#ifndef H_BOOTUTIL_PRIV_ +#define H_BOOTUTIL_PRIV_ + +#include + +#include "sysflash/sysflash.h" + +#include + +#include "bootutil/bootutil.h" +#include "bootutil/image.h" +#include "bootutil/fault_injection_hardening.h" +#include "mcuboot_config/mcuboot_config.h" + +#ifdef MCUBOOT_ENC_IMAGES +#include "bootutil/enc_key.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +struct flash_area; + +#define BOOT_TMPBUF_SZ 256 + +/** Number of image slots in flash; currently limited to two. */ +#define BOOT_NUM_SLOTS 2 + +#if (defined(MCUBOOT_OVERWRITE_ONLY) + \ + defined(MCUBOOT_SWAP_USING_MOVE) + \ + defined(MCUBOOT_DIRECT_XIP) + \ + defined(MCUBOOT_RAM_LOAD)) > 1 +#error "Please enable only one of MCUBOOT_OVERWRITE_ONLY, MCUBOOT_SWAP_USING_MOVE, MCUBOOT_DIRECT_XIP or MCUBOOT_RAM_LOAD" +#endif + +#if !defined(MCUBOOT_OVERWRITE_ONLY) && \ + !defined(MCUBOOT_SWAP_USING_MOVE) && \ + !defined(MCUBOOT_DIRECT_XIP) && \ + !defined(MCUBOOT_RAM_LOAD) +#define MCUBOOT_SWAP_USING_SCRATCH 1 +#endif + +#define BOOT_STATUS_OP_MOVE 1 +#define BOOT_STATUS_OP_SWAP 2 + +/* + * Maintain state of copy progress. + */ +struct boot_status { + uint32_t idx; /* Which area we're operating on */ + uint8_t state; /* Which part of the swapping process are we at */ + uint8_t op; /* What operation are we performing? */ + uint8_t use_scratch; /* Are status bytes ever written to scratch? */ + uint8_t swap_type; /* The type of swap in effect */ + uint32_t swap_size; /* Total size of swapped image */ +#ifdef MCUBOOT_ENC_IMAGES + uint8_t enckey[BOOT_NUM_SLOTS][BOOT_ENC_KEY_SIZE]; +#if MCUBOOT_SWAP_SAVE_ENCTLV + uint8_t enctlv[BOOT_NUM_SLOTS][BOOT_ENC_TLV_ALIGN_SIZE]; +#endif +#endif + int source; /* Which slot contains swap status metadata */ +}; + +#define BOOT_STATUS_IDX_0 1 + +#define BOOT_STATUS_STATE_0 1 +#define BOOT_STATUS_STATE_1 2 +#define BOOT_STATUS_STATE_2 3 + +/** + * End-of-image slot structure. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * ~ ~ + * ~ Swap status (BOOT_MAX_IMG_SECTORS * min-write-size * 3) ~ + * ~ ~ + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Encryption key 0 (16 octets) [*] | + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | 0xff padding as needed (BOOT_MAX_ALIGN - 16 EK0 octets) [*] | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Encryption key 1 (16 octets) [*] | + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | 0xff padding as needed (BOOT_MAX_ALIGN - 16 EK1 octets) [*] | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Swap size (4 octets) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | 0xff padding as needed (BOOT_MAX_ALIGN - 4 Swap Size octets) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Swap info | 0xff padding (BOOT_MAX_ALIGN - 1 octets) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Copy done | 0xff padding (BOOT_MAX_ALIGN - 1 octets) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Image OK | 0xff padding (BOOT_MAX_ALIGN - 1 octets) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | 0xff padding as needed (BOOT_MAX_ALIGN - 16 MAGIC octets) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | MAGIC (16 octets) | + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * [*]: Only present if the encryption option is enabled + * (`MCUBOOT_ENC_IMAGES`). + */ + +extern const uint32_t boot_img_magic[4]; + +#ifdef MCUBOOT_IMAGE_NUMBER +#define BOOT_IMAGE_NUMBER MCUBOOT_IMAGE_NUMBER +#else +#define BOOT_IMAGE_NUMBER 1 +#endif + +_Static_assert(BOOT_IMAGE_NUMBER > 0, "Invalid value for BOOT_IMAGE_NUMBER"); + +#if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD) +#define ARE_SLOTS_EQUIVALENT() 0 +#else +#define ARE_SLOTS_EQUIVALENT() 1 + +#if defined(MCUBOOT_DIRECT_XIP) && defined(MCUBOOT_ENC_IMAGES) +#error "Image encryption (MCUBOOT_ENC_IMAGES) is not supported when MCUBOOT_DIRECT_XIP is selected." +#endif /* MCUBOOT_DIRECT_XIP && MCUBOOT_ENC_IMAGES */ +#endif /* MCUBOOT_DIRECT_XIP || MCUBOOT_RAM_LOAD */ + +#define BOOT_MAX_IMG_SECTORS MCUBOOT_MAX_IMG_SECTORS + +#define BOOT_LOG_IMAGE_INFO(slot, hdr) \ + BOOT_LOG_INF("%-9s slot: version=%u.%u.%u+%u", \ + ((slot) == BOOT_PRIMARY_SLOT) ? "Primary" : "Secondary", \ + (hdr)->ih_ver.iv_major, \ + (hdr)->ih_ver.iv_minor, \ + (hdr)->ih_ver.iv_revision, \ + (hdr)->ih_ver.iv_build_num) + +#if MCUBOOT_SWAP_USING_MOVE +#define BOOT_STATUS_MOVE_STATE_COUNT 1 +#define BOOT_STATUS_SWAP_STATE_COUNT 2 +#define BOOT_STATUS_STATE_COUNT (BOOT_STATUS_MOVE_STATE_COUNT + BOOT_STATUS_SWAP_STATE_COUNT) +#else +#define BOOT_STATUS_STATE_COUNT 3 +#endif + +/** Maximum number of image sectors supported by the bootloader. */ +#define BOOT_STATUS_MAX_ENTRIES BOOT_MAX_IMG_SECTORS + +#define BOOT_PRIMARY_SLOT 0 +#define BOOT_SECONDARY_SLOT 1 + +#define BOOT_STATUS_SOURCE_NONE 0 +#define BOOT_STATUS_SOURCE_SCRATCH 1 +#define BOOT_STATUS_SOURCE_PRIMARY_SLOT 2 + +/** + * Compatibility shim for flash sector type. + * + * This can be deleted when flash_area_to_sectors() is removed. + */ +#ifdef MCUBOOT_USE_FLASH_AREA_GET_SECTORS +typedef struct flash_sector boot_sector_t; +#else +typedef struct flash_area boot_sector_t; +#endif + +/** Private state maintained during boot. */ +struct boot_loader_state { + struct { + struct image_header hdr; + const struct flash_area *area; + boot_sector_t *sectors; + uint32_t num_sectors; + } imgs[BOOT_IMAGE_NUMBER][BOOT_NUM_SLOTS]; + +#if MCUBOOT_SWAP_USING_SCRATCH + struct { + const struct flash_area *area; + boot_sector_t *sectors; + uint32_t num_sectors; + } scratch; +#endif + + uint8_t swap_type[BOOT_IMAGE_NUMBER]; + uint32_t write_sz; + +#if defined(MCUBOOT_ENC_IMAGES) +#ifdef MCUBOOT_ENC_SCRATCH + struct enc_key_data enc[BOOT_IMAGE_NUMBER][BOOT_NUM_SLOTS + 1]; +#else + struct enc_key_data enc[BOOT_IMAGE_NUMBER][BOOT_NUM_SLOTS]; +#endif +#endif + +#if (BOOT_IMAGE_NUMBER > 1) + uint8_t curr_img_idx; +#endif +}; + +fih_int bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig, + size_t slen, uint8_t key_id); + +fih_int boot_fih_memequal(const void *s1, const void *s2, size_t n); + +int boot_magic_compatible_check(uint8_t tbl_val, uint8_t val); +uint32_t boot_status_sz(uint32_t min_write_sz); +uint32_t boot_trailer_sz(uint32_t min_write_sz); +int boot_status_entries(int image_index, const struct flash_area *fap); +uint32_t boot_status_off(const struct flash_area *fap); +int boot_read_swap_state(const struct flash_area *fap, + struct boot_swap_state *state); +int boot_read_swap_state_by_id(int flash_area_id, + struct boot_swap_state *state); +int boot_write_magic(const struct flash_area *fap); +int boot_write_status(const struct boot_loader_state *state, struct boot_status *bs); +int boot_write_copy_done(const struct flash_area *fap); +int boot_write_image_ok(const struct flash_area *fap); +int boot_write_swap_info(const struct flash_area *fap, uint8_t swap_type, + uint8_t image_num); +int boot_write_swap_size(const struct flash_area *fap, uint32_t swap_size); +int boot_write_trailer(const struct flash_area *fap, uint32_t off, + const uint8_t *inbuf, uint8_t inlen); +int boot_write_trailer_flag(const struct flash_area *fap, uint32_t off, + uint8_t flag_val); +int boot_read_swap_size(int image_index, uint32_t *swap_size); +int boot_slots_compatible(struct boot_loader_state *state); +uint32_t boot_status_internal_off(const struct boot_status *bs, int elem_sz); +int boot_read_image_header(struct boot_loader_state *state, int slot, + struct image_header *out_hdr, struct boot_status *bs); +int boot_copy_region(struct boot_loader_state *state, + const struct flash_area *fap_src, + const struct flash_area *fap_dst, + uint32_t off_src, uint32_t off_dst, uint32_t sz); +int boot_erase_region(const struct flash_area *fap, uint32_t off, uint32_t sz); +bool boot_status_is_reset(const struct boot_status *bs); + +#ifdef MCUBOOT_ENC_IMAGES +int boot_write_enc_key(const struct flash_area *fap, uint8_t slot, + const struct boot_status *bs); +int boot_read_enc_key(int image_index, uint8_t slot, struct boot_status *bs); +#endif + +/** + * Checks that a buffer is erased according to what the erase value for the + * flash device provided in `flash_area` is. + * + * @returns true if the buffer is erased; false if any of the bytes is not + * erased, or when buffer is NULL, or when len == 0. + */ +bool bootutil_buffer_is_erased(const struct flash_area *area, + const void *buffer, size_t len); + +/** + * Safe (non-overflowing) uint32_t addition. Returns true, and stores + * the result in *dest if it can be done without overflow. Otherwise, + * returns false. + */ +static inline bool boot_u32_safe_add(uint32_t *dest, uint32_t a, uint32_t b) +{ + /* + * "a + b <= UINT32_MAX", subtract 'b' from both sides to avoid + * the overflow. + */ + if (a > UINT32_MAX - b) { + return false; + } else { + *dest = a + b; + return true; + } +} + +/** + * Safe (non-overflowing) uint16_t addition. Returns true, and stores + * the result in *dest if it can be done without overflow. Otherwise, + * returns false. + */ +static inline bool boot_u16_safe_add(uint16_t *dest, uint16_t a, uint16_t b) +{ + uint32_t tmp = a + b; + if (tmp > UINT16_MAX) { + return false; + } else { + *dest = tmp; + return true; + } +} + +/* + * Accessors for the contents of struct boot_loader_state. + */ + +/* These are macros so they can be used as lvalues. */ +#if (BOOT_IMAGE_NUMBER > 1) +#define BOOT_CURR_IMG(state) ((state)->curr_img_idx) +#else +#define BOOT_CURR_IMG(state) 0 +#endif +#ifdef MCUBOOT_ENC_IMAGES +#define BOOT_CURR_ENC(state) ((state)->enc[BOOT_CURR_IMG(state)]) +#else +#define BOOT_CURR_ENC(state) NULL +#endif +#define BOOT_IMG(state, slot) ((state)->imgs[BOOT_CURR_IMG(state)][(slot)]) +#define BOOT_IMG_AREA(state, slot) (BOOT_IMG(state, slot).area) +#define BOOT_WRITE_SZ(state) ((state)->write_sz) +#define BOOT_SWAP_TYPE(state) ((state)->swap_type[BOOT_CURR_IMG(state)]) +#define BOOT_TLV_OFF(hdr) ((hdr)->ih_hdr_size + (hdr)->ih_img_size) + +#define BOOT_IS_UPGRADE(swap_type) \ + (((swap_type) == BOOT_SWAP_TYPE_TEST) || \ + ((swap_type) == BOOT_SWAP_TYPE_REVERT) || \ + ((swap_type) == BOOT_SWAP_TYPE_PERM)) + +static inline struct image_header* +boot_img_hdr(struct boot_loader_state *state, size_t slot) +{ + return &BOOT_IMG(state, slot).hdr; +} + +static inline size_t +boot_img_num_sectors(const struct boot_loader_state *state, size_t slot) +{ + return BOOT_IMG(state, slot).num_sectors; +} + +/* + * Offset of the slot from the beginning of the flash device. + */ +static inline uint32_t +boot_img_slot_off(struct boot_loader_state *state, size_t slot) +{ + return flash_area_get_off(BOOT_IMG(state, slot).area); +} + +#ifndef MCUBOOT_USE_FLASH_AREA_GET_SECTORS + +static inline size_t +boot_img_sector_size(const struct boot_loader_state *state, + size_t slot, size_t sector) +{ + return flash_area_get_size(&BOOT_IMG(state, slot).sectors[sector]); +} + +/* + * Offset of the sector from the beginning of the image, NOT the flash + * device. + */ +static inline uint32_t +boot_img_sector_off(const struct boot_loader_state *state, size_t slot, + size_t sector) +{ + return flash_area_get_off(&BOOT_IMG(state, slot).sectors[sector]) - + flash_area_get_off(&BOOT_IMG(state, slot).sectors[0]); +} + +#else /* defined(MCUBOOT_USE_FLASH_AREA_GET_SECTORS) */ + +static inline size_t +boot_img_sector_size(const struct boot_loader_state *state, + size_t slot, size_t sector) +{ + return flash_sector_get_size(&BOOT_IMG(state, slot).sectors[sector]); +} + +static inline uint32_t +boot_img_sector_off(const struct boot_loader_state *state, size_t slot, + size_t sector) +{ + return flash_sector_get_off(&BOOT_IMG(state, slot).sectors[sector]) - + flash_sector_get_off(&BOOT_IMG(state, slot).sectors[0]); +} + +#endif /* !defined(MCUBOOT_USE_FLASH_AREA_GET_SECTORS) */ + +#ifdef MCUBOOT_RAM_LOAD +# ifdef __BOOTSIM__ + +/* Query for the layout of a RAM buffer appropriate for holding the + * image. This will be per-test-thread, and therefore must be queried + * through this call. */ +struct bootsim_ram_info { + uint32_t start; + uint32_t size; + uintptr_t base; +}; +struct bootsim_ram_info *bootsim_get_ram_info(void); + +#define IMAGE_GET_FIELD(field) (bootsim_get_ram_info()->field) +#define IMAGE_RAM_BASE IMAGE_GET_FIELD(base) +#define IMAGE_EXECUTABLE_RAM_START IMAGE_GET_FIELD(start) +#define IMAGE_EXECUTABLE_RAM_SIZE IMAGE_GET_FIELD(size) + +# else +# define IMAGE_RAM_BASE ((uintptr_t)0) +# endif + +#define LOAD_IMAGE_DATA(hdr, fap, start, output, size) \ + (memcpy((output),(void*)(IMAGE_RAM_BASE + (hdr)->ih_load_addr + (start)), \ + (size)), 0) +#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 */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libraries/MCUboot/src/bootutil/bootutil_public.c b/libraries/MCUboot/src/bootutil/bootutil_public.c new file mode 100644 index 000000000..01fde44d8 --- /dev/null +++ b/libraries/MCUboot/src/bootutil/bootutil_public.c @@ -0,0 +1,659 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2017-2019 Linaro LTD + * Copyright (c) 2016-2019 JUUL Labs + * Copyright (c) 2019-2021 Arm Limited + * Copyright (c) 2020 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. + */ + +/** + * @file + * @brief Public MCUBoot interface API implementation + * + * This file contains API implementation which can be combined with + * the application in order to interact with the MCUBoot bootloader. + * This file contains shared code-base betwen MCUBoot and the application + * which controls DFU process. + */ + +#include +#include +#include + +#include "sysflash/sysflash.h" +#include "flash_map_backend/flash_map_backend.h" + +#include "bootutil/image.h" +#include "bootutil/bootutil_public.h" +#include "bootutil/bootutil_log.h" +#ifdef MCUBOOT_ENC_IMAGES +#include "bootutil/enc_key_public.h" +#endif + +#include "bootutil/boot_public_hooks.h" + +#ifdef CONFIG_MCUBOOT +BOOT_LOG_MODULE_DECLARE(mcuboot); +#else +BOOT_LOG_MODULE_REGISTER(mcuboot_util); +#endif + +const uint32_t boot_img_magic[] = { + 0xf395c277, + 0x7fefd260, + 0x0f505235, + 0x8079b62c, +}; + +#define BOOT_MAGIC_ARR_SZ \ + (sizeof boot_img_magic / sizeof boot_img_magic[0]) + +struct boot_swap_table { + uint8_t magic_primary_slot; + uint8_t magic_secondary_slot; + uint8_t image_ok_primary_slot; + uint8_t image_ok_secondary_slot; + uint8_t copy_done_primary_slot; + + uint8_t swap_type; +}; + +/** + * This set of tables maps image trailer contents to swap operation type. + * When searching for a match, these tables must be iterated sequentially. + * + * NOTE: the table order is very important. The settings in the secondary + * slot always are priority to the primary slot and should be located + * earlier in the table. + * + * The table lists only states where there is action needs to be taken by + * the bootloader, as in starting/finishing a swap operation. + */ +static const struct boot_swap_table boot_swap_tables[] = { + { + .magic_primary_slot = BOOT_MAGIC_ANY, + .magic_secondary_slot = BOOT_MAGIC_GOOD, + .image_ok_primary_slot = BOOT_FLAG_ANY, + .image_ok_secondary_slot = BOOT_FLAG_UNSET, + .copy_done_primary_slot = BOOT_FLAG_ANY, + .swap_type = BOOT_SWAP_TYPE_TEST, + }, + { + .magic_primary_slot = BOOT_MAGIC_ANY, + .magic_secondary_slot = BOOT_MAGIC_GOOD, + .image_ok_primary_slot = BOOT_FLAG_ANY, + .image_ok_secondary_slot = BOOT_FLAG_SET, + .copy_done_primary_slot = BOOT_FLAG_ANY, + .swap_type = BOOT_SWAP_TYPE_PERM, + }, + { + .magic_primary_slot = BOOT_MAGIC_GOOD, + .magic_secondary_slot = BOOT_MAGIC_UNSET, + .image_ok_primary_slot = BOOT_FLAG_UNSET, + .image_ok_secondary_slot = BOOT_FLAG_ANY, + .copy_done_primary_slot = BOOT_FLAG_SET, + .swap_type = BOOT_SWAP_TYPE_REVERT, + }, +}; + +#define BOOT_SWAP_TABLES_COUNT \ + (sizeof boot_swap_tables / sizeof boot_swap_tables[0]) + +static int +boot_magic_decode(const uint32_t *magic) +{ + if (memcmp(magic, boot_img_magic, BOOT_MAGIC_SZ) == 0) { + return BOOT_MAGIC_GOOD; + } + return BOOT_MAGIC_BAD; +} + +static int +boot_flag_decode(uint8_t flag) +{ + if (flag != BOOT_FLAG_SET) { + return BOOT_FLAG_BAD; + } + return BOOT_FLAG_SET; +} + +static inline uint32_t +boot_magic_off(const struct flash_area *fap) +{ + return flash_area_get_size(fap) - BOOT_MAGIC_ALIGN_SIZE; +} + +static inline uint32_t +boot_image_ok_off(const struct flash_area *fap) +{ + return boot_magic_off(fap) - BOOT_MAX_ALIGN; +} + +static inline uint32_t +boot_copy_done_off(const struct flash_area *fap) +{ + return boot_image_ok_off(fap) - BOOT_MAX_ALIGN; +} + +static inline uint32_t +boot_swap_size_off(const struct flash_area *fap) +{ + return boot_swap_info_off(fap) - BOOT_MAX_ALIGN; +} + +uint32_t +boot_swap_info_off(const struct flash_area *fap) +{ + return boot_copy_done_off(fap) - BOOT_MAX_ALIGN; +} + +/** + * Determines if a status source table is satisfied by the specified magic + * code. + * + * @param tbl_val A magic field from a status source table. + * @param val The magic value in a trailer, encoded as a + * BOOT_MAGIC_[...]. + * + * @return 1 if the two values are compatible; + * 0 otherwise. + */ +int +boot_magic_compatible_check(uint8_t tbl_val, uint8_t val) +{ + switch (tbl_val) { + case BOOT_MAGIC_ANY: + return 1; + + case BOOT_MAGIC_NOTGOOD: + return val != BOOT_MAGIC_GOOD; + + default: + return tbl_val == val; + } +} + +#ifdef MCUBOOT_ENC_IMAGES +static inline uint32_t +boot_enc_key_off(const struct flash_area *fap, uint8_t slot) +{ +#if MCUBOOT_SWAP_SAVE_ENCTLV + return boot_swap_size_off(fap) - ((slot + 1) * + ((((BOOT_ENC_TLV_SIZE - 1) / BOOT_MAX_ALIGN) + 1) * BOOT_MAX_ALIGN)); +#else + return boot_swap_size_off(fap) - ((slot + 1) * BOOT_ENC_KEY_SIZE); +#endif +} +#endif + +bool bootutil_buffer_is_erased(const struct flash_area *area, + const void *buffer, size_t len) +{ + size_t i; + uint8_t *u8b; + uint8_t erased_val; + + if (buffer == NULL || len == 0) { + return false; + } + + erased_val = flash_area_erased_val(area); + for (i = 0, u8b = (uint8_t *)buffer; i < len; i++) { + if (u8b[i] != erased_val) { + return false; + } + } + + return true; +} + +static int +boot_read_flag(const struct flash_area *fap, uint8_t *flag, uint32_t off) +{ + int rc; + + rc = flash_area_read(fap, off, flag, sizeof *flag); + if (rc < 0) { + return BOOT_EFLASH; + } + if (bootutil_buffer_is_erased(fap, flag, sizeof *flag)) { + *flag = BOOT_FLAG_UNSET; + } else { + *flag = boot_flag_decode(*flag); + } + + return 0; +} + +static inline int +boot_read_copy_done(const struct flash_area *fap, uint8_t *copy_done) +{ + return boot_read_flag(fap, copy_done, boot_copy_done_off(fap)); +} + + +int +boot_read_swap_state(const struct flash_area *fap, + struct boot_swap_state *state) +{ + uint32_t magic[BOOT_MAGIC_ARR_SZ] = {0xFF}; + uint32_t off; + uint8_t swap_info; + int rc; + + off = boot_magic_off(fap); + rc = flash_area_read(fap, off, magic, BOOT_MAGIC_SZ); + if (rc < 0) { + return BOOT_EFLASH; + } + if (bootutil_buffer_is_erased(fap, magic, BOOT_MAGIC_SZ)) { + state->magic = BOOT_MAGIC_UNSET; + } else { + state->magic = boot_magic_decode(magic); + } + + off = boot_swap_info_off(fap); + rc = flash_area_read(fap, off, &swap_info, sizeof swap_info); + if (rc < 0) { + return BOOT_EFLASH; + } + + /* Extract the swap type and image number */ + state->swap_type = BOOT_GET_SWAP_TYPE(swap_info); + state->image_num = BOOT_GET_IMAGE_NUM(swap_info); + + if (bootutil_buffer_is_erased(fap, &swap_info, sizeof swap_info) || + state->swap_type > BOOT_SWAP_TYPE_REVERT) { + state->swap_type = BOOT_SWAP_TYPE_NONE; + state->image_num = 0; + } + + rc = boot_read_copy_done(fap, &state->copy_done); + if (rc) { + return BOOT_EFLASH; + } + + return boot_read_image_ok(fap, &state->image_ok); +} + +int +boot_read_swap_state_by_id(int flash_area_id, struct boot_swap_state *state) +{ + const struct flash_area *fap; + int rc; + + rc = flash_area_open(flash_area_id, &fap); + if (rc != 0) { + return BOOT_EFLASH; + } + + rc = boot_read_swap_state(fap, state); + flash_area_close(fap); + return rc; +} + +int +boot_write_magic(const struct flash_area *fap) +{ + uint8_t buf[BOOT_MAX_ALIGN]; + uint32_t off; + uint8_t erased_val; + int rc; + + off = boot_magic_off(fap); + + MCUBOOT_LOG_DBG("writing magic; fa_id=%d off=0x%lx (0x%lx)", + flash_area_get_id(fap), (unsigned long)off, + (unsigned long)(flash_area_get_off(fap) + off)); + + erased_val = flash_area_erased_val(fap); + + memcpy(buf, boot_img_magic, BOOT_MAGIC_SZ); + memset(&buf[BOOT_MAGIC_SZ], erased_val, BOOT_MAX_ALIGN - BOOT_MAGIC_SZ); + + rc = flash_area_write(fap, off, buf, BOOT_MAGIC_ALIGN_SIZE); + if (rc != 0) { + return BOOT_EFLASH; + } + + return 0; +} + +/** + * Write trailer data; status bytes, swap_size, etc + * + * @returns 0 on success, != 0 on error. + */ +int +boot_write_trailer(const struct flash_area *fap, uint32_t off, + const uint8_t *inbuf, uint8_t inlen) +{ + uint8_t buf[BOOT_MAX_ALIGN]; + uint8_t align; + uint8_t erased_val; + int rc; + + align = flash_area_align(fap); + align = (inlen + align - 1) & ~(align - 1); + if (align > BOOT_MAX_ALIGN) { + return -1; + } + erased_val = flash_area_erased_val(fap); + + memcpy(buf, inbuf, inlen); + memset(&buf[inlen], erased_val, align - inlen); + + rc = flash_area_write(fap, off, buf, align); + if (rc != 0) { + return BOOT_EFLASH; + } + + return 0; +} + +int +boot_write_trailer_flag(const struct flash_area *fap, uint32_t off, + uint8_t flag_val) +{ + const uint8_t buf[1] = { flag_val }; + return boot_write_trailer(fap, off, buf, 1); +} + +int +boot_write_image_ok(const struct flash_area *fap) +{ + uint32_t off; + + off = boot_image_ok_off(fap); + MCUBOOT_LOG_DBG("writing image_ok; fa_id=%d off=0x%lx (0x%lx)", + flash_area_get_id(fap), (unsigned long)off, + (unsigned long)(flash_area_get_off(fap) + off)); + return boot_write_trailer_flag(fap, off, BOOT_FLAG_SET); +} + +int +boot_read_image_ok(const struct flash_area *fap, uint8_t *image_ok) +{ + return boot_read_flag(fap, image_ok, boot_image_ok_off(fap)); +} + +/** + * Writes the specified value to the `swap-type` field of an image trailer. + * This value is persisted so that the boot loader knows what swap operation to + * resume in case of an unexpected reset. + */ +int +boot_write_swap_info(const struct flash_area *fap, uint8_t swap_type, + uint8_t image_num) +{ + uint32_t off; + uint8_t swap_info; + + BOOT_SET_SWAP_INFO(swap_info, image_num, swap_type); + off = boot_swap_info_off(fap); + MCUBOOT_LOG_DBG("writing swap_info; fa_id=%d off=0x%lx (0x%lx), swap_type=0x%x" + " image_num=0x%x", + flash_area_get_id(fap), (unsigned long)off, + (unsigned long)(flash_area_get_off(fap) + off), + swap_type, image_num); + return boot_write_trailer(fap, off, (const uint8_t *) &swap_info, 1); +} + +int +boot_swap_type_multi(int image_index) +{ + const struct boot_swap_table *table; + struct boot_swap_state primary_slot; + struct boot_swap_state secondary_slot; + int rc; + size_t i; + + rc = BOOT_HOOK_CALL(boot_read_swap_state_primary_slot_hook, + BOOT_HOOK_REGULAR, image_index, &primary_slot); + if (rc == BOOT_HOOK_REGULAR) + { + rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_PRIMARY(image_index), + &primary_slot); + } + if (rc) { + return BOOT_SWAP_TYPE_PANIC; + } + + rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SECONDARY(image_index), + &secondary_slot); + if (rc == BOOT_EFLASH) { + MCUBOOT_LOG_INF("Secondary image of image pair (%d.) " + "is unreachable. Treat it as empty", image_index); + secondary_slot.magic = BOOT_MAGIC_UNSET; + secondary_slot.swap_type = BOOT_SWAP_TYPE_NONE; + secondary_slot.copy_done = BOOT_FLAG_UNSET; + secondary_slot.image_ok = BOOT_FLAG_UNSET; + secondary_slot.image_num = 0; + } else if (rc) { + return BOOT_SWAP_TYPE_PANIC; + } + + for (i = 0; i < BOOT_SWAP_TABLES_COUNT; i++) { + table = boot_swap_tables + i; + + if (boot_magic_compatible_check(table->magic_primary_slot, + primary_slot.magic) && + boot_magic_compatible_check(table->magic_secondary_slot, + secondary_slot.magic) && + (table->image_ok_primary_slot == BOOT_FLAG_ANY || + table->image_ok_primary_slot == primary_slot.image_ok) && + (table->image_ok_secondary_slot == BOOT_FLAG_ANY || + table->image_ok_secondary_slot == secondary_slot.image_ok) && + (table->copy_done_primary_slot == BOOT_FLAG_ANY || + table->copy_done_primary_slot == primary_slot.copy_done)) { + MCUBOOT_LOG_INF("Swap type: %s", + table->swap_type == BOOT_SWAP_TYPE_TEST ? "test" : + table->swap_type == BOOT_SWAP_TYPE_PERM ? "perm" : + table->swap_type == BOOT_SWAP_TYPE_REVERT ? "revert" : + "BUG; can't happen"); + if (table->swap_type != BOOT_SWAP_TYPE_TEST && + table->swap_type != BOOT_SWAP_TYPE_PERM && + table->swap_type != BOOT_SWAP_TYPE_REVERT) { + return BOOT_SWAP_TYPE_PANIC; + } + return table->swap_type; + } + } + + BOOT_LOG_INF("Swap type: none"); + return BOOT_SWAP_TYPE_NONE; +} + +/* + * This function is not used by the bootloader itself, but its required API + * by external tooling like mcumgr. + */ +int +boot_swap_type(void) +{ + return boot_swap_type_multi(0); +} + +/** + * Marks the image with the given index in the secondary slot as pending. On the + * next reboot, the system will perform a one-time boot of the the secondary + * slot image. + * + * @param image_index Image pair index. + * + * @param permanent Whether the image should be used permanently or + * only tested once: + * 0=run image once, then confirm or revert. + * 1=run image forever. + * + * @return 0 on success; nonzero on failure. + */ +int +boot_set_pending_multi(int image_index, int permanent) +{ + const struct flash_area *fap; + struct boot_swap_state state_secondary_slot; + uint8_t swap_type; + int rc; + + rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY(image_index), &fap); + if (rc != 0) { + return BOOT_EFLASH; + } + + rc = boot_read_swap_state(fap, &state_secondary_slot); + if (rc != 0) { + goto done; + } + + switch (state_secondary_slot.magic) { + case BOOT_MAGIC_GOOD: + /* Swap already scheduled. */ + break; + + case BOOT_MAGIC_UNSET: + rc = boot_write_magic(fap); + + if (rc == 0 && permanent) { + rc = boot_write_image_ok(fap); + } + + if (rc == 0) { + if (permanent) { + swap_type = BOOT_SWAP_TYPE_PERM; + } else { + swap_type = BOOT_SWAP_TYPE_TEST; + } + rc = boot_write_swap_info(fap, swap_type, 0); + } + + break; + + case BOOT_MAGIC_BAD: + /* The image slot is corrupt. There is no way to recover, so erase the + * slot to allow future upgrades. + */ + flash_area_erase(fap, 0, flash_area_get_size(fap)); + rc = BOOT_EBADIMAGE; + break; + + default: + assert(0); + rc = BOOT_EBADIMAGE; + } + +done: + flash_area_close(fap); + return rc; +} + +/** + * Marks the image with index 0 in the secondary slot as pending. On the next + * reboot, the system will perform a one-time boot of the the secondary slot + * image. Note that this API is kept for compatibility. The + * boot_set_pending_multi() API is recommended. + * + * @param permanent Whether the image should be used permanently or + * only tested once: + * 0=run image once, then confirm or revert. + * 1=run image forever. + * + * @return 0 on success; nonzero on failure. + */ +int +boot_set_pending(int permanent) +{ + return boot_set_pending_multi(0, permanent); +} + +/** + * Marks the image with the given index in the primary slot as confirmed. The + * system will continue booting into the image in the primary slot until told to + * boot from a different slot. + * + * @param image_index Image pair index. + * + * @return 0 on success; nonzero on failure. + */ +int +boot_set_confirmed_multi(int image_index) +{ + const struct flash_area *fap = NULL; + struct boot_swap_state state_primary_slot; + int rc; + + rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index), &fap); + if (rc != 0) { + return BOOT_EFLASH; + } + + rc = boot_read_swap_state(fap, &state_primary_slot); + if (rc != 0) { + goto done; + } + + switch (state_primary_slot.magic) { + case BOOT_MAGIC_GOOD: + /* Confirm needed; proceed. */ + break; + + case BOOT_MAGIC_UNSET: + /* Already confirmed. */ + goto done; + + case BOOT_MAGIC_BAD: + /* Unexpected state. */ + rc = BOOT_EBADVECT; + goto done; + } + + /* Intentionally do not check copy_done flag + * so can confirm a padded image which was programed using a programing + * interface. + */ + + if (state_primary_slot.image_ok != BOOT_FLAG_UNSET) { + /* Already confirmed. */ + goto done; + } + + rc = boot_write_image_ok(fap); + +done: + flash_area_close(fap); + return rc; +} + +/** + * Marks the image with index 0 in the primary slot as confirmed. The system + * will continue booting into the image in the primary slot until told to boot + * from a different slot. Note that this API is kept for compatibility. The + * boot_set_confirmed_multi() API is recommended. + * + * @return 0 on success; nonzero on failure. + */ +int +boot_set_confirmed(void) +{ + return boot_set_confirmed_multi(0); +} diff --git a/libraries/MCUboot/src/bootutil/bootutil_public.h b/libraries/MCUboot/src/bootutil/bootutil_public.h new file mode 100644 index 000000000..e539eded7 --- /dev/null +++ b/libraries/MCUboot/src/bootutil/bootutil_public.h @@ -0,0 +1,284 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2017-2019 Linaro LTD + * Copyright (c) 2016-2019 JUUL Labs + * Copyright (c) 2019-2021 Arm Limited + * Copyright (c) 2020-2021 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. + */ + +/** + * @file + * @brief Public MCUBoot interface API + * + * This file contains API which can be combined with the application in order + * to interact with the MCUBoot bootloader. This API are shared code-base betwen + * MCUBoot and the application which controls DFU process. + */ + +#ifndef H_BOOTUTIL_PUBLIC +#define H_BOOTUTIL_PUBLIC + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** Attempt to boot the contents of the primary slot. */ +#define BOOT_SWAP_TYPE_NONE 1 + +/** + * Swap to the secondary slot. + * Absent a confirm command, revert back on next boot. + */ +#define BOOT_SWAP_TYPE_TEST 2 + +/** + * Swap to the secondary slot, + * and permanently switch to booting its contents. + */ +#define BOOT_SWAP_TYPE_PERM 3 + +/** Swap back to alternate slot. A confirm changes this state to NONE. */ +#define BOOT_SWAP_TYPE_REVERT 4 + +/** Swap failed because image to be run is not valid */ +#define BOOT_SWAP_TYPE_FAIL 5 + +/** Swapping encountered an unrecoverable error */ +#define BOOT_SWAP_TYPE_PANIC 0xff + +#define BOOT_MAGIC_SZ 16 + +#ifdef MCUBOOT_BOOT_MAX_ALIGN +#define BOOT_MAX_ALIGN MCUBOOT_BOOT_MAX_ALIGN +#define BOOT_MAGIC_ALIGN_SIZE \ + ((((BOOT_MAGIC_SZ - 1) / BOOT_MAX_ALIGN) + 1) * BOOT_MAX_ALIGN) +#else +#define BOOT_MAX_ALIGN 8 +#define BOOT_MAGIC_ALIGN_SIZE BOOT_MAGIC_SZ +#endif + +#ifdef MCUBOOT_SWAP_BUF_SIZE +#define BOOT_SWAP_BUF_SIZE MCUBOOT_SWAP_BUF_SIZE +#elif BOOT_MAX_ALIGN > 1024 +#define BOOT_SWAP_BUF_SIZE BOOT_MAX_ALIGN +#else +#define BOOT_SWAP_BUF_SIZE 1024 +#endif + +#define BOOT_MAGIC_GOOD 1 +#define BOOT_MAGIC_BAD 2 +#define BOOT_MAGIC_UNSET 3 +#define BOOT_MAGIC_ANY 4 /* NOTE: control only, not dependent on sector */ +#define BOOT_MAGIC_NOTGOOD 5 /* NOTE: control only, not dependent on sector */ + +/* + * NOTE: leave BOOT_FLAG_SET equal to one, this is written to flash! + */ +#define BOOT_FLAG_SET 1 +#define BOOT_FLAG_BAD 2 +#define BOOT_FLAG_UNSET 3 +#define BOOT_FLAG_ANY 4 /* NOTE: control only, not dependent on sector */ + +#define BOOT_EFLASH 1 +#define BOOT_EFILE 2 +#define BOOT_EBADIMAGE 3 +#define BOOT_EBADVECT 4 +#define BOOT_EBADSTATUS 5 +#define BOOT_ENOMEM 6 +#define BOOT_EBADARGS 7 +#define BOOT_EBADVERSION 8 +#define BOOT_EFLASH_SEC 9 + +#define BOOT_HOOK_REGULAR 1 +/* + * Extract the swap type and image number from image trailers's swap_info + * filed. + */ +#define BOOT_GET_SWAP_TYPE(swap_info) ((swap_info) & 0x0F) +#define BOOT_GET_IMAGE_NUM(swap_info) ((swap_info) >> 4) + +/* Construct the swap_info field from swap type and image number */ +#define BOOT_SET_SWAP_INFO(swap_info, image, type) { \ + assert((image) < 0xF); \ + assert((type) < 0xF); \ + (swap_info) = (image) << 4 \ + | (type); \ + } +#ifdef MCUBOOT_HAVE_ASSERT_H +#include "mcuboot_config/mcuboot_assert.h" +#else +#include +#ifndef ASSERT +#define ASSERT assert +#endif +#endif + +struct boot_swap_state { + uint8_t magic; /* One of the BOOT_MAGIC_[...] values. */ + uint8_t swap_type; /* One of the BOOT_SWAP_TYPE_[...] values. */ + uint8_t copy_done; /* One of the BOOT_FLAG_[...] values. */ + uint8_t image_ok; /* One of the BOOT_FLAG_[...] values. */ + uint8_t image_num; /* Boot status belongs to this image */ +}; + +/** + * @brief Determines the action, if any, that mcuboot will take on a image pair. + * + * @param image_index Image pair index. + * + * @return a BOOT_SWAP_TYPE_[...] constant on success, negative errno code on + * fail. + */ +int boot_swap_type_multi(int image_index); + +/** + * @brief Determines the action, if any, that mcuboot will take. + * + * Works the same as a boot_swap_type_multi(0) call; + * + * @return a BOOT_SWAP_TYPE_[...] constant on success, negative errno code on + * fail. + */ +int boot_swap_type(void); + +/** + * Marks the image with the given index in the secondary slot as pending. On the + * next reboot, the system will perform a one-time boot of the the secondary + * slot image. + * + * @param image_index Image pair index. + * + * @param permanent Whether the image should be used permanently or + * only tested once: + * 0=run image once, then confirm or revert. + * 1=run image forever. + * + * @return 0 on success; nonzero on failure. + */ +int boot_set_pending_multi(int image_index, int permanent); + +/** + * Marks the image with index 0 in the secondary slot as pending. On the next + * reboot, the system will perform a one-time boot of the the secondary slot + * image. Note that this API is kept for compatibility. The + * boot_set_pending_multi() API is recommended. + * + * @param permanent Whether the image should be used permanently or + * only tested once: + * 0=run image once, then confirm or revert. + * 1=run image forever. + * + * @return 0 on success; nonzero on failure. + */ +int boot_set_pending(int permanent); + +/** + * Marks the image with the given index in the primary slot as confirmed. The + * system will continue booting into the image in the primary slot until told to + * boot from a different slot. + * + * @param image_index Image pair index. + * + * @return 0 on success; nonzero on failure. + */ +int boot_set_confirmed_multi(int image_index); + +/** + * Marks the image with index 0 in the primary slot as confirmed. The system + * will continue booting into the image in the primary slot until told to boot + * from a different slot. Note that this API is kept for compatibility. The + * boot_set_confirmed_multi() API is recommended. + * + * @return 0 on success; nonzero on failure. + */ +int boot_set_confirmed(void); + +/** + * @brief Get offset of the swap info field in the image trailer. + * + * @param fap Flash are for which offset is determined. + * + * @retval offset of the swap info field. + */ +uint32_t boot_swap_info_off(const struct flash_area *fap); + +/** + * @brief Get value of image-ok flag of the image. + * + * If called from chin-loaded image the image-ok flag value can be used to check + * whether application itself is already confirmed. + * + * @param fap Flash area of the image. + * @param image_ok[out] image-ok value. + * + * @return 0 on success; nonzero on failure. + */ +int boot_read_image_ok(const struct flash_area *fap, uint8_t *image_ok); + +/** + * @brief Read the image swap state + * + * @param flash_area_id id of flash partition from which state will be read; + * @param state pointer to structure for storing swap state. + * + * @return 0 on success; non-zero error code on failure; + */ +int +boot_read_swap_state_by_id(int flash_area_id, struct boot_swap_state *state); + +/** + * @brief Read the image swap state + * + * @param fa pointer to flash_area object; + * @param state pointer to structure for storing swap state. + * + * @return 0 on success; non-zero error code on failure. + */ +int +boot_read_swap_state(const struct flash_area *fa, + struct boot_swap_state *state); + +/** + * Populates the version information of the + * currently installed primary application + * + * @param[in] version Destination version structure buffer + * @return 0 on success; nonzero on failure. + */ +int boot_get_current_version(struct image_version *version); + +#define BOOT_MAGIC_ARR_SZ \ + (sizeof boot_img_magic / sizeof boot_img_magic[0]) + +extern const uint32_t boot_img_magic[4]; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libraries/MCUboot/src/bootutil/fault_injection_hardening.h b/libraries/MCUboot/src/bootutil/fault_injection_hardening.h new file mode 100644 index 000000000..05ec6c264 --- /dev/null +++ b/libraries/MCUboot/src/bootutil/fault_injection_hardening.h @@ -0,0 +1,377 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2020 Arm Limited + */ + +#ifndef __FAULT_INJECTION_HARDENING_H__ +#define __FAULT_INJECTION_HARDENING_H__ + +/* Fault injection mitigation library. + * + * Has support for different measures, which can either be enabled/disabled + * separately or by defining one of the MCUBOOT_FIH_PROFILEs. + * + * NOTE: These constructs against fault injection attacks are not guaranteed to + * be secure for all compilers, but execution is going to be correct and + * including them will certainly help to harden the code. + * + * FIH_ENABLE_DOUBLE_VARS makes critical variables into a tuple (x, x ^ msk). + * Then the correctness of x can be checked by XORing the two tuple values + * together. This also means that comparisons between fih_ints can be verified + * by doing x == y && x_msk == y_msk. + * + * FIH_ENABLE_GLOBAL_FAIL makes all while(1) failure loops redirect to a global + * failure loop. This loop has mitigations against loop escapes / unlooping. + * This also means that any unlooping won't immediately continue executing the + * function that was executing before the failure. + * + * FIH_ENABLE_CFI (Control Flow Integrity) creates a global counter that is + * incremented before every FIH_CALL of vulnerable functions. On the function + * return the counter is decremented, and after the return it is verified that + * the counter has the same value as before this process. This can be used to + * verify that the function has actually been called. This protection is + * intended to discover that important functions are called in an expected + * sequence and neither of them is missed due to an instruction skip which could + * be a result of glitching attack. It does not provide protection against ROP + * or JOP attacks. + * + * FIH_ENABLE_DELAY causes random delays. This makes it hard to cause faults + * precisely. It requires an RNG. An mbedtls integration is provided in + * fault_injection_hardening_delay_mbedtls.h, but any RNG that has an entropy + * source can be used by implementing the fih_delay_random_uchar function. + * + * The basic call pattern is: + * + * fih_int fih_rc = FIH_FAILURE; + * FIH_CALL(vulnerable_function, fih_rc, arg1, arg2); + * if (fih_not_eq(fih_rc, FIH_SUCCESS)) { + * FIH_PANIC; + * } + * + * Note that any function called by FIH_CALL must only return using FIH_RETURN, + * as otherwise the CFI counter will not be decremented and the CFI check will + * fail causing a panic. + */ + +#include "mcuboot_config/mcuboot_config.h" + +#if defined(MCUBOOT_FIH_PROFILE_HIGH) + +#define FIH_ENABLE_DELAY /* Requires an entropy source */ +#define FIH_ENABLE_DOUBLE_VARS +#define FIH_ENABLE_GLOBAL_FAIL +#define FIH_ENABLE_CFI + +#elif defined(MCUBOOT_FIH_PROFILE_MEDIUM) + +#define FIH_ENABLE_DOUBLE_VARS +#define FIH_ENABLE_GLOBAL_FAIL +#define FIH_ENABLE_CFI + +#elif defined(MCUBOOT_FIH_PROFILE_LOW) + +#define FIH_ENABLE_GLOBAL_FAIL +#define FIH_ENABLE_CFI + +#elif !defined(MCUBOOT_FIH_PROFILE_OFF) +#define MCUBOOT_FIH_PROFILE_OFF +#endif /* MCUBOOT_FIH_PROFILE */ + +#ifdef FIH_ENABLE_DELAY +#include "fault_injection_hardening_delay_rng.h" +#endif /* FIH_ENABLE_DELAY */ + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Non-zero success value to defend against register resets. Zero is the most + * common value for a corrupted register so complex bit-patterns are used + */ +#ifndef MCUBOOT_FIH_PROFILE_OFF +#define FIH_POSITIVE_VALUE 0x1AAAAAAA +#define FIH_NEGATIVE_VALUE 0x15555555 +#else +#define FIH_POSITIVE_VALUE 0 +#define FIH_NEGATIVE_VALUE -1 +#endif + +/* A volatile mask is used to prevent compiler optimization - the mask is xored + * with the variable to create the backup and the integrity can be checked with + * another xor. The mask value doesn't _really_ matter that much, as long as + * it has reasonably high hamming weight. + */ +#define _FIH_MASK_VALUE 0xBEEF + +#ifdef FIH_ENABLE_DOUBLE_VARS + +/* All ints are replaced with two int - the normal one and a backup which is + * XORed with the mask. + */ +extern volatile int _fih_mask; +typedef volatile struct { + volatile int val; + volatile int msk; +} fih_int; + +#else + +typedef int fih_int; + +#endif /* FIH_ENABLE_DOUBLE_VARS */ + +extern fih_int FIH_SUCCESS; +extern fih_int FIH_FAILURE; + +#ifdef FIH_ENABLE_GLOBAL_FAIL +/* Global failure handler - more resistant to unlooping. noinline and used are + * used to prevent optimization + */ +__attribute__((noinline)) __attribute__((used)) +void fih_panic_loop(void); +#define FIH_PANIC fih_panic_loop() +#else +#define FIH_PANIC while (1) {} +#endif /* FIH_ENABLE_GLOBAL_FAIL */ + +/* NOTE: For functions to be inlined outside their compilation unit they have to + * have the body in the header file. This is required as function calls are easy + * to skip. + */ +#ifdef FIH_ENABLE_DELAY + +/* Delaying logic, with randomness from a CSPRNG */ +__attribute__((always_inline)) inline +int fih_delay(void) +{ + unsigned char delay; + int foo = 0; + volatile int rc; + + delay = fih_delay_random_uchar(); + + for (volatile int i = 0; i < delay; i++) { + foo++; + } + + rc = 1; + + /* rc is volatile so if it is the return value then the function cannot be + * optimized + */ + return rc; +} + +#else + +__attribute__((always_inline)) inline +int fih_delay_init(void) +{ + return 1; +} + +__attribute__((always_inline)) inline +int fih_delay(void) +{ + return 1; +} +#endif /* FIH_ENABLE_DELAY */ + +#ifdef FIH_ENABLE_DOUBLE_VARS + +__attribute__((always_inline)) inline +void fih_int_validate(fih_int x) +{ + if (x.val != (x.msk ^ _fih_mask)) { + FIH_PANIC; + } +} + +/* Convert a fih_int to an int. Validate for tampering. */ +__attribute__((always_inline)) inline +int fih_int_decode(fih_int x) +{ + fih_int_validate(x); + return x.val; +} + +/* Convert an int to a fih_int, can be used to encode specific error codes. */ +__attribute__((always_inline)) inline +fih_int fih_int_encode(int x) +{ + fih_int ret = {x, x ^ _fih_mask}; + return ret; +} + +/* Standard equality. If A == B then 1, else 0 */ +__attribute__((always_inline)) inline +int fih_eq(fih_int x, fih_int y) +{ + fih_int_validate(x); + fih_int_validate(y); + return (x.val == y.val) && fih_delay() && (x.msk == y.msk); +} + +__attribute__((always_inline)) inline +int fih_not_eq(fih_int x, fih_int y) +{ + fih_int_validate(x); + fih_int_validate(y); + return (x.val != y.val) && fih_delay() && (x.msk != y.msk); +} + +#else + +/* NOOP */ +__attribute__((always_inline)) inline +void fih_int_validate(fih_int x) +{ + (void) x; + return; +} + +/* NOOP */ +__attribute__((always_inline)) inline +int fih_int_decode(fih_int x) +{ + return x; +} + +/* NOOP */ +__attribute__((always_inline)) inline +fih_int fih_int_encode(int x) +{ + return x; +} + +__attribute__((always_inline)) inline +int fih_eq(fih_int x, fih_int y) +{ + return x == y; +} + +__attribute__((always_inline)) inline +int fih_not_eq(fih_int x, fih_int y) +{ + return x != y; +} +#endif /* FIH_ENABLE_DOUBLE_VARS */ + +/* C has a common return pattern where 0 is a correct value and all others are + * errors. This function converts 0 to FIH_SUCCESS and any other number to a + * value that is not FIH_SUCCESS + */ +__attribute__((always_inline)) inline +fih_int fih_int_encode_zero_equality(int x) +{ + if (x) { + return FIH_FAILURE; + } else { + return FIH_SUCCESS; + } +} + +#ifdef FIH_ENABLE_CFI +extern fih_int _fih_cfi_ctr; +#endif /* FIH_ENABLE_CFI */ + +fih_int fih_cfi_get_and_increment(void); +void fih_cfi_validate(fih_int saved); +void fih_cfi_decrement(void); + +/* Label for interacting with FIH testing tool. Can be parsed from the elf file + * after compilation. Does not require debug symbols. + */ +#if defined(__ICCARM__) +#define FIH_LABEL(str, lin, cnt) __asm volatile ("FIH_LABEL_" str "_" #lin "_" #cnt "::" ::); +#else +#define FIH_LABEL(str) __asm volatile ("FIH_LABEL_" str "_%=:" ::); +#endif + +/* Main FIH calling macro. return variable is second argument. Does some setup + * before and validation afterwards. Inserts labels for use with testing script. + * + * First perform the precall step - this gets the current value of the CFI + * counter and saves it to a local variable, and then increments the counter. + * + * Then set the return variable to FIH_FAILURE as a base case. + * + * Then perform the function call. As part of the funtion FIH_RET must be called + * which will decrement the counter. + * + * The postcall step gets the value of the counter and compares it to the + * previously saved value. If this is equal then the function call and all child + * function calls were performed. + */ +#if defined(__ICCARM__) +#define FIH_CALL(f, ret, ...) FIH_CALL2(f, ret, __LINE__, __COUNTER__, __VA_ARGS__) + +#define FIH_CALL2(f, ret, l, c, ...) \ + do { \ + FIH_LABEL("FIH_CALL_START", l, c); \ + FIH_CFI_PRECALL_BLOCK; \ + ret = FIH_FAILURE; \ + if (fih_delay()) { \ + ret = f(__VA_ARGS__); \ + } \ + FIH_CFI_POSTCALL_BLOCK; \ + FIH_LABEL("FIH_CALL_END", l, c); \ + } while (0) + +#else + +#define FIH_CALL(f, ret, ...) \ + do { \ + FIH_LABEL("FIH_CALL_START"); \ + FIH_CFI_PRECALL_BLOCK; \ + ret = FIH_FAILURE; \ + if (fih_delay()) { \ + ret = f(__VA_ARGS__); \ + } \ + FIH_CFI_POSTCALL_BLOCK; \ + FIH_LABEL("FIH_CALL_END"); \ + } while (0) +#endif + +/* FIH return changes the state of the internal state machine. If you do a + * FIH_CALL then you need to do a FIH_RET else the state machine will detect + * tampering and panic. + */ +#define FIH_RET(ret) \ + do { \ + FIH_CFI_PRERET; \ + return ret; \ + } while (0) + + +#ifdef FIH_ENABLE_CFI +/* Macro wrappers for functions - Even when the functions have zero body this + * saves a few bytes on noop functions as it doesn't generate the call/ret + * + * CFI precall function saves the CFI counter and then increments it - the + * postcall then checks if the counter is equal to the saved value. In order for + * this to be the case a FIH_RET must have been performed inside the called + * function in order to decrement the counter, so the function must have been + * called. + */ +#define FIH_CFI_PRECALL_BLOCK \ + fih_int _fih_cfi_saved_value = fih_cfi_get_and_increment() + +#define FIH_CFI_POSTCALL_BLOCK \ + fih_cfi_validate(_fih_cfi_saved_value) + +#define FIH_CFI_PRERET \ + fih_cfi_decrement() +#else +#define FIH_CFI_PRECALL_BLOCK +#define FIH_CFI_POSTCALL_BLOCK +#define FIH_CFI_PRERET +#endif /* FIH_ENABLE_CFI */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __FAULT_INJECTION_HARDENING_H__ */ diff --git a/libraries/MCUboot/src/bootutil/ignore.h b/libraries/MCUboot/src/bootutil/ignore.h new file mode 100644 index 000000000..1684c056c --- /dev/null +++ b/libraries/MCUboot/src/bootutil/ignore.h @@ -0,0 +1,70 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2017 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. + */ + +#ifndef H_IGNORE_ +#define H_IGNORE_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * These macros prevent the "set but not used" warnings for log writes below + * the log level. + */ + +#define IGN_1(X) ((void)(X)) +#define IGN_2(X, ...) ((void)(X));IGN_1(__VA_ARGS__) +#define IGN_3(X, ...) ((void)(X));IGN_2(__VA_ARGS__) +#define IGN_4(X, ...) ((void)(X));IGN_3(__VA_ARGS__) +#define IGN_5(X, ...) ((void)(X));IGN_4(__VA_ARGS__) +#define IGN_6(X, ...) ((void)(X));IGN_5(__VA_ARGS__) +#define IGN_7(X, ...) ((void)(X));IGN_6(__VA_ARGS__) +#define IGN_8(X, ...) ((void)(X));IGN_7(__VA_ARGS__) +#define IGN_9(X, ...) ((void)(X));IGN_8(__VA_ARGS__) +#define IGN_10(X, ...) ((void)(X));IGN_9(__VA_ARGS__) +#define IGN_11(X, ...) ((void)(X));IGN_10(__VA_ARGS__) +#define IGN_12(X, ...) ((void)(X));IGN_11(__VA_ARGS__) +#define IGN_13(X, ...) ((void)(X));IGN_12(__VA_ARGS__) +#define IGN_14(X, ...) ((void)(X));IGN_13(__VA_ARGS__) +#define IGN_15(X, ...) ((void)(X));IGN_14(__VA_ARGS__) +#define IGN_16(X, ...) ((void)(X));IGN_15(__VA_ARGS__) +#define IGN_17(X, ...) ((void)(X));IGN_16(__VA_ARGS__) +#define IGN_18(X, ...) ((void)(X));IGN_17(__VA_ARGS__) +#define IGN_19(X, ...) ((void)(X));IGN_18(__VA_ARGS__) +#define IGN_20(X, ...) ((void)(X));IGN_19(__VA_ARGS__) + +#define GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, \ + _13, _14, _15, _16, _17, _18, _19, _20, NAME, ...) NAME +#define IGNORE(...) \ + GET_MACRO(__VA_ARGS__, IGN_20, IGN_19, IGN_18, IGN_17, IGN_16, IGN_15, \ + IGN_14, IGN_13, IGN_12, IGN_11, IGN_10, IGN_9, IGN_8, IGN_7, \ + IGN_6, IGN_5, IGN_4, IGN_3, IGN_2, IGN_1)(__VA_ARGS__) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libraries/MCUboot/src/bootutil/image.h b/libraries/MCUboot/src/bootutil/image.h new file mode 100644 index 000000000..7a2a56c83 --- /dev/null +++ b/libraries/MCUboot/src/bootutil/image.h @@ -0,0 +1,191 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2016-2019 Linaro LTD + * Copyright (c) 2016-2019 JUUL Labs + * Copyright (c) 2019-2021 Arm Limited + * + * 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. + */ + +#ifndef H_IMAGE_ +#define H_IMAGE_ + +#include +#include +#include "bootutil/fault_injection_hardening.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct flash_area; + +#define IMAGE_MAGIC 0x96f3b83d +#define IMAGE_MAGIC_V1 0x96f3b83c +#define IMAGE_MAGIC_NONE 0xffffffff +#define IMAGE_TLV_INFO_MAGIC 0x6907 +#define IMAGE_TLV_PROT_INFO_MAGIC 0x6908 + +#define IMAGE_HEADER_SIZE 32 + +/* + * Image header flags. + */ +#define IMAGE_F_PIC 0x00000001 /* Not supported. */ +#define IMAGE_F_ENCRYPTED_AES128 0x00000004 /* Encrypted using AES128. */ +#define IMAGE_F_ENCRYPTED_AES256 0x00000008 /* Encrypted using AES256. */ +#define IMAGE_F_NON_BOOTABLE 0x00000010 /* Split image app. */ +/* + * Indicates that this image should be loaded into RAM instead of run + * directly from flash. The address to load should be in the + * ih_load_addr field of the header. + */ +#define IMAGE_F_RAM_LOAD 0x00000020 + +/* + * Indicates that ih_load_addr stores information on flash/ROM address the + * image has been built for. + */ +#define IMAGE_F_ROM_FIXED 0x00000100 + +/* + * ECSDA224 is with NIST P-224 + * ECSDA256 is with NIST P-256 + */ + +/* + * Image trailer TLV types. + * + * Signature is generated by computing signature over the image hash. + * Currently the only image hash type is SHA256. + * + * Signature comes in the form of 2 TLVs. + * 1st on identifies the public key which should be used to verify it. + * 2nd one is the actual signature. + */ +#define IMAGE_TLV_KEYHASH 0x01 /* hash of the public key */ +#define IMAGE_TLV_PUBKEY 0x02 /* public key */ +#define IMAGE_TLV_SHA256 0x10 /* SHA256 of image hdr and body */ +#define IMAGE_TLV_RSA2048_PSS 0x20 /* RSA2048 of hash output */ +#define IMAGE_TLV_ECDSA224 0x21 /* ECDSA of hash output */ +#define IMAGE_TLV_ECDSA256 0x22 /* ECDSA of hash output */ +#define IMAGE_TLV_RSA3072_PSS 0x23 /* RSA3072 of hash output */ +#define IMAGE_TLV_ED25519 0x24 /* ed25519 of hash output */ +#define IMAGE_TLV_ENC_RSA2048 0x30 /* Key encrypted with RSA-OAEP-2048 */ +#define IMAGE_TLV_ENC_KW 0x31 /* Key encrypted with AES-KW 128 or 256*/ +#define IMAGE_TLV_ENC_EC256 0x32 /* Key encrypted with ECIES-EC256 */ +#define IMAGE_TLV_ENC_X25519 0x33 /* Key encrypted with ECIES-X25519 */ +#define IMAGE_TLV_DEPENDENCY 0x40 /* Image depends on other image */ +#define IMAGE_TLV_SEC_CNT 0x50 /* security counter */ +#define IMAGE_TLV_BOOT_RECORD 0x60 /* measured boot record */ + /* + * vendor reserved TLVs at xxA0-xxFF, + * where xx denotes the upper byte + * range. Examples: + * 0x00a0 - 0x00ff + * 0x01a0 - 0x01ff + * 0x02a0 - 0x02ff + * ... + * 0xffa0 - 0xfffe + */ +#define IMAGE_TLV_ANY 0xffff /* Used to iterate over all TLV */ + +struct image_version { + uint8_t iv_major; + uint8_t iv_minor; + uint16_t iv_revision; + uint32_t iv_build_num; +}; + +struct image_dependency { + uint8_t image_id; /* Image index (from 0) */ + uint8_t _pad1; + uint16_t _pad2; + struct image_version image_min_version; /* Indicates at minimum which + * version of firmware must be + * available to satisfy compliance + */ +}; + +/** Image header. All fields are in little endian byte order. */ +struct image_header { + uint32_t ih_magic; + uint32_t ih_load_addr; + uint32_t ih_hdr_size; /* Size of image header (bytes). */ + uint32_t ih_protect_tlv_size; /* Size of protected TLV area (bytes). */ + uint32_t ih_img_size; /* Does not include header. */ + uint32_t ih_flags; /* IMAGE_F_[...]. */ + struct image_version ih_ver; +}; + +/** Image TLV header. All fields in little endian. */ +struct image_tlv_info { + uint16_t it_magic; + uint16_t it_tlv_tot; /* size of TLV area (including tlv_info header) */ +}; + +/** Image trailer TLV format. All fields in little endian. */ +struct image_tlv { + uint16_t it_type; /* IMAGE_TLV_[...]. */ + uint16_t it_len; /* Data length (not including TLV header). */ +}; + +#define IS_ENCRYPTED(hdr) (((hdr)->ih_flags & IMAGE_F_ENCRYPTED_AES128) \ + || ((hdr)->ih_flags & IMAGE_F_ENCRYPTED_AES256)) +#define MUST_DECRYPT(fap, idx, hdr) \ + (flash_area_get_id(fap) == FLASH_AREA_IMAGE_SECONDARY(idx) && IS_ENCRYPTED(hdr)) + +_Static_assert(sizeof(struct image_header) == IMAGE_HEADER_SIZE, + "struct image_header not required size"); + +struct enc_key_data; +fih_int bootutil_img_validate(struct enc_key_data *enc_state, int image_index, + struct image_header *hdr, + const struct flash_area *fap, + uint8_t *tmp_buf, uint32_t tmp_buf_sz, + uint8_t *seed, int seed_len, uint8_t *out_hash); + +struct image_tlv_iter { + const struct image_header *hdr; + const struct flash_area *fap; + uint16_t type; + bool prot; + uint32_t prot_end; + uint32_t tlv_off; + uint32_t tlv_end; +}; + +int bootutil_tlv_iter_begin(struct image_tlv_iter *it, + const struct image_header *hdr, + const struct flash_area *fap, uint16_t type, + bool prot); +int bootutil_tlv_iter_next(struct image_tlv_iter *it, uint32_t *off, + uint16_t *len, uint16_t *type); + +int32_t bootutil_get_img_security_cnt(struct image_header *hdr, + const struct flash_area *fap, + uint32_t *security_cnt); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libraries/MCUboot/src/cortex-m7/libbootutil.a b/libraries/MCUboot/src/cortex-m7/libbootutil.a deleted file mode 100644 index fecf030aa12b2bf7d8720c599785d5e76923f16c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 46134 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 U?=U=See*2b2=e&`!=uLiKa-w-{r~^~ diff --git a/libraries/MCUboot/src/fileblockdevice/FileBlockDevice.cpp b/libraries/MCUboot/src/fileblockdevice/FileBlockDevice.cpp new file mode 100644 index 000000000..52b82ccb7 --- /dev/null +++ b/libraries/MCUboot/src/fileblockdevice/FileBlockDevice.cpp @@ -0,0 +1,220 @@ +/* + Copyright (c) 2022 Arduino SA. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "FileBlockDevice.h" +#include "platform/mbed_assert.h" +#include "mcuboot_config/mcuboot_logging.h" +#include "stddef.h" +#include + +#ifndef MBED_CONF_MBED_TRACE_ENABLE +#define MBED_CONF_MBED_TRACE_ENABLE 0 +#endif + +#include "mbed_trace.h" +#define TRACE_GROUP "FILEBD" + +namespace mbed { + +FileBlockDevice::FileBlockDevice(const char *path, const char *flags, bd_size_t bd_size, bd_size_t r_size, bd_size_t w_size, bd_size_t e_size) + :_path(path), _oflag(flags), _bd_size(bd_size), _r_size(r_size), _w_size(w_size), _e_size(e_size) +{ + +} + +int FileBlockDevice::init() +{ + tr_debug("Opening file block device %s", _path); + + _file[0] = fopen(_path, _oflag); + if (_file[0] == NULL) { + MCUBOOT_LOG_ERR("Cannot open file block device %s %s", _path, _oflag); + return BD_ERROR_DEVICE_ERROR; + } + + int err = fseek (_file[0] , 0 , SEEK_END); + if (err) { + MCUBOOT_LOG_ERR("Init:fseek"); + return BD_ERROR_DEVICE_ERROR; + } + + uint32_t f_size = ftell (_file[0]); + if (f_size != _bd_size) { + MCUBOOT_LOG_WRN("File %s size (0x%zx) should be the same of underlying block device (0x%zx)", _path, f_size, _bd_size); + } + + tr_debug("Opened file block device handle %d file size 0x%zx", _file[0], f_size); + + _is_initialized = true; + + return BD_ERROR_OK; +} + +int FileBlockDevice::deinit() +{ + tr_debug("Closing file block handle %d", _file[0]); + fclose(_file[0]); + return BD_ERROR_OK; +} + +int FileBlockDevice::sync() +{ + return BD_ERROR_OK; +} + +int FileBlockDevice::read(void *buffer, bd_addr_t addr, bd_size_t size) +{ + if (_file[0] == NULL) { + MCUBOOT_LOG_ERR("Read:invalid handle"); + return BD_ERROR_DEVICE_ERROR; + } + + tr_debug("reading addr 0x%x", (long)addr); + tr_debug("reading size %d", (int)size); + int err = fseek(_file[0], addr, SEEK_SET); + if (err) { + MCUBOOT_LOG_ERR("Read:fseek"); + return BD_ERROR_DEVICE_ERROR; + } + size_t count = fread(buffer, 1u, size, _file[0]); + tr_debug("reading count %d", (int)count); + if (count != size) { + MCUBOOT_LOG_ERR("Read:handle %d count 0x%zx", _file[0], count); + return BD_ERROR_DEVICE_ERROR; + } + + return BD_ERROR_OK; +} + +int FileBlockDevice::program(const void *buffer, bd_addr_t addr, bd_size_t size) +{ + if (_file[0] == NULL) { + MCUBOOT_LOG_ERR("Program:invalid handle"); + return BD_ERROR_DEVICE_ERROR; + } + + tr_debug("program addr 0x%x", (long)addr); + tr_debug("program size %d", (int)size); + int err = fseek(_file[0], addr, SEEK_SET); + if (err) { + MCUBOOT_LOG_ERR("Program:fseek"); + return BD_ERROR_DEVICE_ERROR; + } + + int count = fwrite(buffer, size, 1u, _file[0]); + if (count != 1u) { + MCUBOOT_LOG_ERR("Program:handle %d count 0x%zx", _file[0], count); + return BD_ERROR_DEVICE_ERROR; + } + + err = fflush(_file[0]); + if (err != 0u) { + MCUBOOT_LOG_ERR("Program:flush"); + return BD_ERROR_DEVICE_ERROR; + } + + return BD_ERROR_OK; +} + +int FileBlockDevice::erase(bd_addr_t addr, bd_size_t size) +{ + if (_file[0] == NULL) { + MCUBOOT_LOG_ERR("Erase:invalid handle"); + return BD_ERROR_DEVICE_ERROR; + } + + tr_debug("program addr 0x%x", (long)addr); + tr_debug("program size %d", (int)size); + bd_size_t len; + for (len = 0; len < size; len++) { + int err = fseek(_file[0], addr + len, SEEK_SET); + if (err) { + MCUBOOT_LOG_ERR("Erase:fseek"); + return BD_ERROR_DEVICE_ERROR; + } + uint8_t erase_val = 0xFF; + int count = fwrite(&erase_val, 1u, 1u, _file[0]); + if (count != 1u) { + MCUBOOT_LOG_ERR("Erase:handle %d count 0x%zx", _file[0], count); + return BD_ERROR_DEVICE_ERROR; + } + } + + int err = fflush(_file[0]); + if (err != 0u) { + MCUBOOT_LOG_ERR("Erase:flush"); + return BD_ERROR_DEVICE_ERROR; + } + + return BD_ERROR_OK; +} + +bool FileBlockDevice::is_valid_read(bd_addr_t addr, bd_size_t size) const +{ + return ((addr + size) <= _bd_size); +} + +bool FileBlockDevice::is_valid_program(bd_addr_t addr, bd_size_t size) const +{ + return ((addr + size) <= _bd_size); +} + +bool FileBlockDevice::is_valid_erase(bd_addr_t addr, bd_size_t size) const +{ + return ((addr + size) <= _bd_size); +} + +bd_size_t FileBlockDevice::get_read_size() const +{ + // Return minimum read size in bytes for the device + return _r_size; +} + +bd_size_t FileBlockDevice::get_program_size() const +{ + // Return minimum program/write size in bytes for the device + return _w_size; +} + +bd_size_t FileBlockDevice::get_erase_size() const +{ + // return minimal erase size supported by all regions (0 if none exists) + return _e_size; +} + +bd_size_t FileBlockDevice::get_erase_size(bd_addr_t addr) const +{ + return _e_size; +} + +int FileBlockDevice::get_erase_value() const +{ + return 0xFF; +} + +bd_size_t FileBlockDevice::size() const +{ + return _bd_size; +} + +const char *FileBlockDevice::get_type() const +{ + return "FILEBD"; +} + +} // namespace mbed diff --git a/libraries/MCUboot/src/fileblockdevice/FileBlockDevice.h b/libraries/MCUboot/src/fileblockdevice/FileBlockDevice.h new file mode 100644 index 000000000..eadf6397f --- /dev/null +++ b/libraries/MCUboot/src/fileblockdevice/FileBlockDevice.h @@ -0,0 +1,203 @@ +/* + Copyright (c) 2022 Arduino SA. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/** \addtogroup storage */ +/** @{*/ + +#ifndef MBED_FILE_BLOCK_DEVICE_H +#define MBED_FILE_BLOCK_DEVICE_H + +#include "mbed.h" +#include "BlockDevice.h" +#include "platform/mbed_assert.h" +#include + +namespace mbed { + +/** BlockDevice for mapping a file into a Blockdevice + * + */ +class FileBlockDevice : public BlockDevice { +public: + /** Create FileBlockDevice - An SFDP based Flash Block Device over QSPI bus + * + */ + FileBlockDevice(const char *path, const char * flags, bd_size_t bd_size, bd_size_t r_size, bd_size_t w_size, bd_size_t e_size); + + /** Lifetime of a block device + */ + ~FileBlockDevice() {}; + + /** Initialize a block device + * + * @return QSPIF_BD_ERROR_OK(0) - success + * QSPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed + * QSPIF_BD_ERROR_READY_FAILED - Waiting for Memory ready failed or timedout + * QSPIF_BD_ERROR_PARSING_FAILED - unexpected format or values in one of the SFDP tables + */ + virtual int init(); + + /** Deinitialize a block device + * + * @return QSPIF_BD_ERROR_OK(0) - success + * QSPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed + */ + virtual int deinit(); + + /** Ensure data on storage is in sync with the driver + * + * @return 0 on success or a negative error code on failure + */ + virtual int sync(); + + /** Read blocks from a block device + * + * @param buffer Buffer to write blocks to + * @param addr Address of block to begin reading from + * @param size Size to read in bytes, must be a multiple of read block size + * @return QSPIF_BD_ERROR_OK(0) - success + * QSPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed + */ + virtual int read(void *buffer, bd_addr_t addr, bd_size_t size); + + /** Program blocks to a block device + * + * The blocks must have been erased prior to being programmed + * + * @param buffer Buffer of data to write to blocks + * @param addr Address of block to begin writing to + * @param size Size to write in bytes, must be a multiple of program block size + * @return QSPIF_BD_ERROR_OK(0) - success + * QSPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed + * QSPIF_BD_ERROR_READY_FAILED - Waiting for Memory ready failed or timed out + * QSPIF_BD_ERROR_WREN_FAILED - Write Enable failed + * QSPIF_BD_ERROR_PARSING_FAILED - unexpected format or values in one of the SFDP tables + */ + virtual int program(const void *buffer, bd_addr_t addr, bd_size_t size); + + /** Erase blocks on a block device + * + * The state of an erased block is undefined until it has been programmed + * + * @param addr Address of block to begin erasing + * @param size Size to erase in bytes, must be a multiple of erase block size + * @return QSPIF_BD_ERROR_OK(0) - success + * QSPIF_BD_ERROR_DEVICE_ERROR - device driver transaction failed + * QSPIF_BD_ERROR_READY_FAILED - Waiting for Memory ready failed or timed out + * QSPIF_BD_ERROR_WREN_FAILED - Write Enable failed + * QSPIF_BD_ERROR_PARSING_FAILED - unexpected format or values in one of the SFDP tables + * QSPIF_BD_ERROR_INVALID_ERASE_PARAMS - Trying to erase unaligned address or size + */ + virtual int erase(bd_addr_t addr, bd_size_t size); + + /** Get the size of a readable block + * + * @return Size of a readable block in bytes + */ + virtual bd_size_t get_read_size() const; + + /** Get the size of a programable block + * + * @return Size of a program block size in bytes + * @note Must be a multiple of the read size + */ + virtual bd_size_t get_program_size() const; + + /** Get the size of a eraseable block + * + * @return Size of a minimal erase block, common to all regions, in bytes + * @note Must be a multiple of the program size + */ + virtual bd_size_t get_erase_size() const; + + /** Get the size of minimal eraseable sector size of given address + * + * @param addr Any address within block queried for erase sector size (can be any address within flash size offset) + * @return Size of minimal erase sector size, in given address region, in bytes + * @note Must be a multiple of the program size + */ + virtual bd_size_t get_erase_size(bd_addr_t addr) const; + + /** Get the value of storage byte after it was erased + * + * If get_erase_value returns a non-negative byte value, the underlying + * storage is set to that value when erased, and storage containing + * that value can be programmed without another erase. + * + * @return The value of storage when erased, or -1 if you can't + * rely on the value of erased storage + */ + virtual int get_erase_value() const; + + /** Get the total size of the underlying device + * + * @return Size of the underlying device in bytes + */ + virtual mbed::bd_size_t size() const; + + /** Get the BlockDevice class type. + * + * @return A string represent the BlockDevice class type. + */ + virtual const char *get_type() const; + + /** Convenience function for checking block program validity + * + * @param addr Address of block to begin writing to + * @param size Size to write in bytes + * @return True if program is valid for underlying block device + */ + virtual bool is_valid_program(bd_addr_t addr, bd_size_t size) const; + + /** Convenience function for checking block read validity + * + * @param addr Address of block to begin reading from + * @param size Size to read in bytes + * @return True if read is valid for underlying block device + */ + virtual bool is_valid_read(bd_addr_t addr, bd_size_t size) const; + + /** Convenience function for checking block erase validity + * + * @param addr Address of block to begin erasing + * @param size Size to erase in bytes + * @return True if erase is valid for underlying block device + */ + virtual bool is_valid_erase(bd_addr_t addr, bd_size_t size) const; + +private: + FILE *_file[1]; + const char *_path; + const char *_oflag; + bd_size_t _bd_size; + bd_size_t _r_size; + bd_size_t _w_size; + bd_size_t _e_size; + bool _is_initialized; +}; + +} // namespace mbed + +// Added "using" for backwards compatibility +#ifndef MBED_NO_GLOBAL_USING_DIRECTIVE +using mbed::FileBlockDevice; +#endif + +#endif + +/** @}*/ diff --git a/libraries/MCUboot/src/flash_map_backend/flash_map_backend.cpp b/libraries/MCUboot/src/flash_map_backend/flash_map_backend.cpp new file mode 100644 index 000000000..fa5307be0 --- /dev/null +++ b/libraries/MCUboot/src/flash_map_backend/flash_map_backend.cpp @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2020 Embedded Planet + * Copyright (c) 2020 ARM Limited + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed 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 +#include +#include "flash_map_backend/flash_map_backend.h" +#include "flash_map_backend/secondary_bd.h" +#include "sysflash/sysflash.h" + +#include "mbed.h" +#include "blockdevice/BlockDevice.h" +#include "FlashIAP/FlashIAPBlockDevice.h" + +#include "mcuboot_config/mcuboot_logging.h" + +#include "bootutil/bootutil_priv.h" + +#define FLASH_DEVICE_INTERNAL_FLASH 0 +#define FLASH_AREAS 3 + +/** Application defined secondary block device */ +mbed::BlockDevice* mcuboot_secondary_bd = get_secondary_bd(); + +/** Internal application block device */ +static FlashIAPBlockDevice mcuboot_primary_bd(MCUBOOT_PRIMARY_SLOT_START_ADDR, MCUBOOT_SLOT_SIZE); + +#if MCUBOOT_SWAP_USING_SCRATCH +mbed::BlockDevice* mcuboot_scratch_bd = get_scratch_bd(); +#endif + +static mbed::BlockDevice* flash_map_bd[FLASH_AREAS] = { + (mbed::BlockDevice*) &mcuboot_primary_bd, /** Primary (loadable) image area */ + mcuboot_secondary_bd, /** Secondary (update candidate) image area */ +#if MCUBOOT_SWAP_USING_SCRATCH + mcuboot_scratch_bd /** Scratch space for swapping images */ +#else + nullptr +#endif +}; + +static struct flash_area flash_areas[FLASH_AREAS]; + +static unsigned int open_count[FLASH_AREAS] = {0}; + +int flash_area_open(uint8_t id, const struct flash_area** fapp) { + + *fapp = &flash_areas[id]; + struct flash_area* fap = (struct flash_area*)*fapp; + + // The offset of the slot is from the beginning of the flash device. + switch (id) { + case PRIMARY_ID: + fap->fa_off = MCUBOOT_PRIMARY_SLOT_START_ADDR; + break; + case SECONDARY_ID: +#if MCUBOOT_DIRECT_XIP + fap->fa_off = MBED_CONF_MCUBOOT_XIP_SECONDARY_SLOT_ADDRESS; +#else + fap->fa_off = 0; +#endif + break; +#if MCUBOOT_SWAP_USING_SCRATCH + case SCRATCH_ID: + fap->fa_off = MCUBOOT_SCRATCH_START_ADDR; + break; +#endif + default: + MCUBOOT_LOG_ERR("flash_area_open, unknown id %d", id); + return -1; + } + + open_count[id]++; + MCUBOOT_LOG_DBG("flash area %d open count: %d (+)", id, open_count[id]); + + fap->fa_id = id; + fap->fa_device_id = 0; // not relevant + + mbed::BlockDevice* bd = flash_map_bd[id]; + fap->fa_size = (uint32_t) bd->size(); + + /* Only initialize if this isn't a nested call to open the flash area */ + if (open_count[id] == 1) { + MCUBOOT_LOG_DBG("initializing flash area %d...", id); + return bd->init(); + } else { + return 0; + } +} + +void flash_area_close(const struct flash_area* fap) { + uint8_t id = fap->fa_id; + /* No need to close an unopened flash area, avoid an overflow of the counter */ + if (!open_count[id]) { + return; + } + + open_count[id]--; + MCUBOOT_LOG_DBG("flash area %d open count: %d (-)", id, open_count[id]); + if (!open_count[id]) { + /* mcuboot is not currently consistent in opening/closing flash areas only once at a time + * so only deinitialize the BlockDevice if all callers have closed the flash area. */ + MCUBOOT_LOG_DBG("deinitializing flash area block device %d...", id); + mbed::BlockDevice* bd = flash_map_bd[id]; + bd->deinit(); + } +} + +/* + * Read/write/erase. Offset is relative from beginning of flash area. + */ +int flash_area_read(const struct flash_area* fap, uint32_t off, void* dst, uint32_t len) { + mbed::BlockDevice* bd = flash_map_bd[fap->fa_id]; + + /* Note: The address must be aligned to bd->get_read_size(). If MCUBOOT_READ_GRANULARITY + is defined, the length does not need to be aligned. */ +#ifdef MCUBOOT_READ_GRANULARITY + uint32_t read_size = bd->get_read_size(); + if (read_size == 0) { + MCUBOOT_LOG_ERR("Invalid read size: must be non-zero"); + return -1; + } + if (MCUBOOT_READ_GRANULARITY < read_size) { + MCUBOOT_LOG_ERR("Please increase MCUBOOT_READ_GRANULARITY (currently %u) to be at least %u", + MCUBOOT_READ_GRANULARITY, read_size); + return -1; + } + + uint32_t remainder = len % read_size; + len -= remainder; + if (len != 0) { +#endif + if (!bd->is_valid_read(off, len)) { + MCUBOOT_LOG_ERR("Invalid read: fa_id %d offset 0x%x len 0x%x", fap->fa_id, + (unsigned int) off, (unsigned int) len); + return -1; + } + else { + int ret = bd->read(dst, off, len); + if (ret != 0) { + MCUBOOT_LOG_ERR("Read failed: fa_id %d offset 0x%x len 0x%x", fap->fa_id, + (unsigned int) off, (unsigned int) len); + return ret; + } + } +#ifdef MCUBOOT_READ_GRANULARITY + } + + if (remainder) { + if (!bd->is_valid_read(off + len, read_size)) { + MCUBOOT_LOG_ERR("Invalid read: fa_id %d offset 0x%x len 0x%x", fap->fa_id, + (unsigned int) (off + len), (unsigned int) read_size); + return -1; + } + else { + uint8_t buffer[MCUBOOT_READ_GRANULARITY]; + int ret = bd->read(buffer, off + len, read_size); + if (ret != 0) { + MCUBOOT_LOG_ERR("Read failed: %d", ret); + return ret; + } + memcpy((uint8_t *)dst + len, buffer, remainder); + } + } +#endif + + return 0; +} + +int flash_area_write(const struct flash_area* fap, uint32_t off, const void* src, uint32_t len) { + mbed::BlockDevice* bd = flash_map_bd[fap->fa_id]; + return bd->program(src, off, len); +} + +int flash_area_erase(const struct flash_area* fap, uint32_t off, uint32_t len) { + mbed::BlockDevice* bd = flash_map_bd[fap->fa_id]; + return bd->erase(off, len); +} + +uint8_t flash_area_align(const struct flash_area* fap) { + mbed::BlockDevice* bd = flash_map_bd[fap->fa_id]; + return bd->get_program_size(); +} + +uint8_t flash_area_erased_val(const struct flash_area* fap) { + mbed::BlockDevice* bd = flash_map_bd[fap->fa_id]; + return bd->get_erase_value(); +} + +int flash_area_get_sectors(int fa_id, uint32_t* count, struct flash_sector* sectors) { + mbed::BlockDevice* bd = flash_map_bd[fa_id]; + + /* Loop through sectors and collect information on them */ + mbed::bd_addr_t offset = 0; + *count = 0; + while (*count < MCUBOOT_MAX_IMG_SECTORS && bd->is_valid_read(offset, bd->get_read_size())) { + + sectors[*count].fs_off = offset; + mbed::bd_size_t erase_size = bd->get_erase_size(offset); + sectors[*count].fs_size = erase_size; + + offset += erase_size; + *count += 1; + } + + return 0; +} + +int flash_area_id_from_image_slot(int slot) { + return slot; +} + +int flash_area_id_to_image_slot(int area_id) { + return area_id; +} + +/** + * Multi images support not implemented yet + */ +int flash_area_id_from_multi_image_slot(int image_index, int slot) +{ + assert(image_index == 0); + return slot; +} + +int flash_area_id_to_multi_image_slot(int image_index, int area_id) +{ + assert(image_index == 0); + return area_id; +} diff --git a/libraries/MCUboot/src/flash_map_backend/flash_map_backend.h b/libraries/MCUboot/src/flash_map_backend/flash_map_backend.h new file mode 100644 index 000000000..f2bad169e --- /dev/null +++ b/libraries/MCUboot/src/flash_map_backend/flash_map_backend.h @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2018 Nordic Semiconductor ASA + * Copyright (c) 2015 Runtime Inc + * Copyright (c) 2020 Embedded Planet + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed 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 Licens + */ + +#ifndef H_UTIL_FLASH_MAP_ +#define H_UTIL_FLASH_MAP_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * + * Provides abstraction of flash regions for type of use. + * I.e. dude where's my image? + * + * System will contain a map which contains flash areas. Every + * region will contain flash identifier, offset within flash and length. + * + * 1. This system map could be in a file within filesystem (Initializer + * must know/figure out where the filesystem is at). + * 2. Map could be at fixed location for project (compiled to code) + * 3. Map could be at specific place in flash (put in place at mfg time). + * + * Note that the map you use must be valid for BSP it's for, + * match the linker scripts when platform executes from flash, + * and match the target offset specified in download script. + */ +#include + +/** + * @brief Structure describing an area on a flash device. + * + * Multiple flash devices may be available in the system, each of + * which may have its own areas. For this reason, flash areas track + * which flash device they are part of. + */ +struct flash_area { + /** + * This flash area's ID; unique in the system. + */ + uint8_t fa_id; + + /** + * ID of the flash device this area is a part of. + */ + uint8_t fa_device_id; + + uint16_t pad16; + + /** + * This area's offset, relative to the beginning of its flash + * device's storage. + */ + uint32_t fa_off; + + /** + * This area's size, in bytes. + */ + uint32_t fa_size; +}; + +static inline uint8_t flash_area_get_id(const struct flash_area *fa) +{ + return fa->fa_id; +} + +static inline uint8_t flash_area_get_device_id(const struct flash_area *fa) +{ + return fa->fa_device_id; +} + +static inline uint32_t flash_area_get_off(const struct flash_area *fa) +{ + return fa->fa_off; +} + +static inline uint32_t flash_area_get_size(const struct flash_area *fa) +{ + return fa->fa_size; +} + +/** + * @brief Structure describing a sector within a flash area. + * + * Each sector has an offset relative to the start of its flash area + * (NOT relative to the start of its flash device), and a size. A + * flash area may contain sectors with different sizes. + */ +struct flash_sector { + /** + * Offset of this sector, from the start of its flash area (not device). + */ + uint32_t fs_off; + + /** + * Size of this sector, in bytes. + */ + uint32_t fs_size; +}; + +static inline uint32_t flash_sector_get_off(const struct flash_sector *fs) +{ + return fs->fs_off; +} + +static inline uint32_t flash_sector_get_size(const struct flash_sector *fs) +{ + return fs->fs_size; +} + +/* + * Start using flash area. + */ +int flash_area_open(uint8_t id, const struct flash_area ** fapp); + +void flash_area_close(const struct flash_area * fap); + +/* + * Read/write/erase. Offset is relative from beginning of flash area. + */ +int flash_area_read(const struct flash_area * fap, uint32_t off, void *dst, + uint32_t len); +int flash_area_write(const struct flash_area * fap, uint32_t off, const void *src, + uint32_t len); +int flash_area_erase(const struct flash_area * fap, uint32_t off, uint32_t len); + +/* + * Alignment restriction for flash writes. + */ +uint8_t flash_area_align(const struct flash_area * fap); + +/* + * What is value is read from erased flash bytes. + */ +uint8_t flash_area_erased_val(const struct flash_area * fap); + +/* + * Given flash area ID, return info about sectors within the area. + */ +int flash_area_get_sectors(int fa_id, uint32_t *count, + struct flash_sector *sectors); + + +int flash_area_id_from_image_slot(int slot); +int flash_area_id_from_multi_image_slot(int image_index, int slot); + + +int flash_area_id_to_image_slot(int area_id); +/** + * Converts the specified flash area ID and image index (in multi-image setup) + * to an image slot index. + * + * Returns image slot index (0 or 1), or -1 if ID doesn't correspond to an image + * slot. + */ +int flash_area_id_to_multi_image_slot(int image_index, int area_id); + +#ifdef __cplusplus +} +#endif + +#endif /* H_UTIL_FLASH_MAP_ */ diff --git a/libraries/MCUboot/src/flash_map_backend/secondary_bd.cpp b/libraries/MCUboot/src/flash_map_backend/secondary_bd.cpp new file mode 100644 index 000000000..bdbfaeb67 --- /dev/null +++ b/libraries/MCUboot/src/flash_map_backend/secondary_bd.cpp @@ -0,0 +1,64 @@ +/* + * Mbed-OS Microcontroller Library + * Copyright (c) 2020 Embedded Planet + * Copyright (c) 2020 ARM Limited + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed 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 "flash_map_backend/secondary_bd.h" +#include "mcuboot_config/mcuboot_logging.h" +#include "platform/mbed_toolchain.h" +#include "MBRBlockDevice.h" +#include "fileblockdevice/FileBlockDevice.h" +#include "FATFileSystem.h" +#include "bootutil/bootutil_priv.h" + +mbed::FATFileSystem* get_filesystem(void) { + mbed::BlockDevice* raw = mbed::BlockDevice::get_default_instance(); + static mbed::MBRBlockDevice mbr = mbed::MBRBlockDevice(raw, 2); + static mbed::FATFileSystem fs("fs"); + + int err = mbr.init(); + if(err) { + MCUBOOT_LOG_ERR("Cannot initialize Block Device"); + return nullptr; + } + + // Mount can fail if filerystem already mounted + fs.mount(&mbr); + return &fs; +} + +mbed::BlockDevice* get_secondary_bd(void) { + mbed::FATFileSystem* fs = get_filesystem(); + if(fs == nullptr) { + MCUBOOT_LOG_ERR("Cannot initialize secondary fs"); + } + + // TODO: This is the default configuration, check RTC registers to allow custom settings + static mbed::FileBlockDevice secondary_bd = mbed::FileBlockDevice("/fs/update.bin", "rb+", MCUBOOT_SLOT_SIZE, 0x01, 0x01, 0x1000); + return &secondary_bd; +} + +mbed::BlockDevice* get_scratch_bd(void) { + mbed::FATFileSystem* fs = get_filesystem(); + if(fs == nullptr) { + MCUBOOT_LOG_ERR("Cannot initialize scratch fs"); + } + + // TODO: This is the default configuration, check RTC registers to allow custom settings + static mbed::FileBlockDevice scratch_bd = mbed::FileBlockDevice("/fs/scratch.bin", "rb+", MCUBOOT_SCRATCH_SIZE, 0x01, 0x01, 0x1000); + return &scratch_bd; +} diff --git a/libraries/MCUboot/src/flash_map_backend/secondary_bd.h b/libraries/MCUboot/src/flash_map_backend/secondary_bd.h new file mode 100644 index 000000000..35ca14daf --- /dev/null +++ b/libraries/MCUboot/src/flash_map_backend/secondary_bd.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2020 Embedded Planet + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed 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 Licens + * + * Created on: Jul 30, 2020 + * Author: gdbeckstein + */ + +#ifndef MCUBOOT_BOOT_MBED_INCLUDE_FLASH_MAP_BACKEND_SECONDARY_BD_H_ +#define MCUBOOT_BOOT_MBED_INCLUDE_FLASH_MAP_BACKEND_SECONDARY_BD_H_ + +#include "blockdevice/BlockDevice.h" + +/** + * This is implemented as a weak function and may be redefined + * by the application. The default case is to return the + * BlockDevice object returned by BlockDevice::get_default_instance(); + * + * For an XIP build, the secondary BD is provided by mcuboot by default. + * + * This is implemented as a weak symbol so the user can override it. + * + * @retval secondary_bd Secondary BlockDevice where update candidates are stored + */ +mbed::BlockDevice* get_secondary_bd(void); + +/** + * This is implemented as a weak function and may be redefined + * by the application. By default, scratch space is at the end of + * internal flash, after the main application. + * + * This is implemented as a weak symbol so the user can override it. + * + * Security warning: Using an external scratch memory might compromise + * the security of encrypted images. In this case, the scratch and + * slot 0 are encrypted. If the swap is moved to external memory, + * it could be read if the swap were interrupted. Done enough + * times, this could be used to extract the plaintext image. + * + * @retval scratch_bd BlockDevice containing the scratch region + */ +mbed::BlockDevice* get_scratch_bd(void); + +#endif /* MCUBOOT_BOOT_MBED_INCLUDE_FLASH_MAP_BACKEND_SECONDARY_BD_H_ */ diff --git a/libraries/MCUboot/src/mcuboot_config/mcuboot_config.h b/libraries/MCUboot/src/mcuboot_config/mcuboot_config.h new file mode 100644 index 000000000..943633e35 --- /dev/null +++ b/libraries/MCUboot/src/mcuboot_config/mcuboot_config.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2018 Open Source Foundries Limited + * Copyright (c) 2019-2020 Arm Limited + * Copyright (c) 2019-2020 Linaro Limited + * Copyright (c) 2020 Embedded Planet + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __MCUBOOT_CONFIG_H__ +#define __MCUBOOT_CONFIG_H__ + +/* + * Primary slot start address (Internal flash) + */ +#define MCUBOOT_PRIMARY_SLOT_START_ADDR 0x8020000 + +/* + * Primary/Secondary slot size + */ +#define MCUBOOT_SLOT_SIZE 0x1E0000 + +/* + * Scratch slot start address (QSPI flash FS "virtual" address) + */ +#define MCUBOOT_SCRATCH_START_ADDR 0x9000000 + +/* + * Scratch slot size + */ +#define MCUBOOT_SCRATCH_SIZE 0x20000 + +/* + * Maximum number of flash sector per slot + */ +#define MCUBOOT_MAX_IMG_SECTORS 0x3C0 + +/* + * STM32H7 flash read alignment + */ +#define MCUBOOT_BOOT_MAX_ALIGN 32 + +/* + * MCUboot swaps slots using scratch partition + */ +#define MCUBOOT_SWAP_USING_SCRATCH 1 + +/* + * LOG level: 0 OFF, 1 ERROR, 2 WARNING, 3 DEBUG, 4 INFO + */ +#define MCUBOOT_LOG_LEVEL 4 + +/* + * Signature algorithm + */ +#define MCUBOOT_SIGN_EC256 + +/* + * Crypto backend + */ +#define MCUBOOT_USE_MBED_TLS + +/* + * Only one image (two slots) supported for now + */ +#define MCUBOOT_IMAGE_NUMBER 1 + +/* + * Currently there is no configuration option, for this platform, + * that enables the system specific mcumgr commands in mcuboot + */ +#define MCUBOOT_PERUSER_MGMT_GROUP_ENABLED 0 + +/* + * Encrypted Images + */ +#if defined(MCUBOOT_ENCRYPT_RSA) || defined(MCUBOOT_ENCRYPT_EC256) || defined(MCUBOOT_ENCRYPT_X25519) +#define MCUBOOT_ENC_IMAGES +#endif + +/* + * Enabling this option uses newer flash map APIs. This saves RAM and + * avoids deprecated API usage. + */ +#define MCUBOOT_USE_FLASH_AREA_GET_SECTORS + +/* + * No watchdog integration for now + */ +#define MCUBOOT_WATCHDOG_FEED() \ + do { \ + } while (0) + +/* + * No direct idle call implemented + */ +#define MCUBOOT_CPU_IDLE() \ + do { \ + } while (0) + +/* + * Enable MCUBoot logging + */ +#define MCUBOOT_HAVE_LOGGING + +#endif /* __MCUBOOT_CONFIG_H__ */ diff --git a/libraries/MCUboot/src/mcuboot_config/mcuboot_logging.h b/libraries/MCUboot/src/mcuboot_config/mcuboot_logging.h new file mode 100644 index 000000000..e9f31c390 --- /dev/null +++ b/libraries/MCUboot/src/mcuboot_config/mcuboot_logging.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2018 Nordic Semiconductor ASA + * Copyright (c) 2015 Runtime Inc + * Copyright (c) 2020 Cypress Semiconductor Corporation + * Copyright (c) 2020 Embedded Planet + * Copyright (c) 2020 ARM Limited + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed 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 Licens. + */ + +#ifndef __MCUBOOT_LOGGING_H__ +#define __MCUBOOT_LOGGING_H__ + +#include + +#define MCUBOOT_LOG_LEVEL_OFF 0 +#define MCUBOOT_LOG_LEVEL_ERROR 1 +#define MCUBOOT_LOG_LEVEL_WARNING 2 +#define MCUBOOT_LOG_LEVEL_INFO 3 +#define MCUBOOT_LOG_LEVEL_DEBUG 4 + +/* + * The compiled log level determines the maximum level that can be + * printed. + */ +#ifndef MCUBOOT_LOG_LEVEL +#define MCUBOOT_LOG_LEVEL MCUBOOT_LOG_LEVEL_OFF +#endif + +#if MCUBOOT_LOG_LEVEL == MCUBOOT_LOG_LEVEL_OFF +#define MBED_CONF_MBED_TRACE_ENABLE 0 +#else +#define MCUBOOT_HAVE_LOGGING +#endif + +#if MCUBOOT_LOG_LEVEL == MCUBOOT_LOG_LEVEL_ERROR +#define MBED_TRACE_MAX_LEVEL TRACE_LEVEL_ERROR +#elif MCUBOOT_LOG_LEVEL == MCUBOOT_LOG_LEVEL_WARNING +#define MBED_TRACE_MAX_LEVEL TRACE_LEVEL_WARN +#elif MCUBOOT_LOG_LEVEL == MCUBOOT_LOG_LEVEL_INFO +#define MBED_TRACE_MAX_LEVEL TRACE_LEVEL_INFO +#elif MCUBOOT_LOG_LEVEL == MCUBOOT_LOG_LEVEL_DEBUG +#define MBED_TRACE_MAX_LEVEL TRACE_LEVEL_DEBUG +#endif + +#define TRACE_GROUP "MCUb" +#include "mbed_trace.h" +#include "bootutil/ignore.h" +#include "mcuboot_config/mcuboot_config.h" + +#define MCUBOOT_LOG_MODULE_DECLARE(domain) /* ignore */ +#define MCUBOOT_LOG_MODULE_REGISTER(domain) /* ignore */ + +#if MCUBOOT_LOG_LEVEL >= MCUBOOT_LOG_LEVEL_ERROR +#if MBED_CONF_MBED_TRACE_ENABLE +#define MCUBOOT_LOG_ERR tr_error +#else +#define MCUBOOT_LOG_ERR(_fmt, ...) \ + do { \ + printf( "E-" _fmt "\n", ##__VA_ARGS__); \ + } while (0) +#endif +#else +#define MCUBOOT_LOG_ERR(...) IGNORE(__VA_ARGS__) +#endif + +#if MCUBOOT_LOG_LEVEL >= MCUBOOT_LOG_LEVEL_WARNING +#if MBED_CONF_MBED_TRACE_ENABLE +#define MCUBOOT_LOG_WRN tr_warn +#else +#define MCUBOOT_LOG_WRN(_fmt, ...) \ + do { \ + printf("W-" _fmt "\n", ##__VA_ARGS__); \ + } while (0) +#endif +#else +#define MCUBOOT_LOG_WRN(...) IGNORE(__VA_ARGS__) +#endif + +#if MCUBOOT_LOG_LEVEL >= MCUBOOT_LOG_LEVEL_INFO +#if MBED_CONF_MBED_TRACE_ENABLE +#define MCUBOOT_LOG_INF tr_info +#else +#define MCUBOOT_LOG_INF(_fmt, ...) \ + do { \ + printf( "I-" _fmt "\n", ##__VA_ARGS__); \ + } while (0) +#endif +#else +#define MCUBOOT_LOG_INF(...) IGNORE(__VA_ARGS__) +#endif + +#if MCUBOOT_LOG_LEVEL >= MCUBOOT_LOG_LEVEL_DEBUG +#if MBED_CONF_MBED_TRACE_ENABLE +#define MCUBOOT_LOG_DBG tr_debug +#else +#define MCUBOOT_LOG_DBG(_fmt, ...) \ + do { \ + printf( "D-" _fmt "\n", ##__VA_ARGS__); \ + } while (0) +#endif +#else +#define MCUBOOT_LOG_DBG(...) IGNORE(__VA_ARGS__) +#endif + +#endif /* __MCUBOOT_LOGGING_H__ */ diff --git a/libraries/MCUboot/src/sysflash/sysflash.h b/libraries/MCUboot/src/sysflash/sysflash.h new file mode 100644 index 000000000..e19945b3f --- /dev/null +++ b/libraries/MCUboot/src/sysflash/sysflash.h @@ -0,0 +1,14 @@ +/* Manual version of auto-generated version. */ + +#ifndef __SYSFLASH_H__ +#define __SYSFLASH_H__ + +#define PRIMARY_ID 0 +#define SECONDARY_ID 1 +#define SCRATCH_ID 2 + +#define FLASH_AREA_IMAGE_PRIMARY(x) PRIMARY_ID +#define FLASH_AREA_IMAGE_SECONDARY(x) SECONDARY_ID +#define FLASH_AREA_IMAGE_SCRATCH SCRATCH_ID + +#endif /* __SYSFLASH_H__ */ From 2cad923ef443638d2d31716f5205a58f0eee57c7 Mon Sep 17 00:00:00 2001 From: pennam Date: Wed, 15 Mar 2023 09:55:11 +0100 Subject: [PATCH 2/4] MCUboot library: use bool flags instead of int --- libraries/MCUboot/src/MCUboot.cpp | 6 +++--- libraries/MCUboot/src/MCUboot.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/MCUboot/src/MCUboot.cpp b/libraries/MCUboot/src/MCUboot.cpp index 29528f4b1..35f32b143 100644 --- a/libraries/MCUboot/src/MCUboot.cpp +++ b/libraries/MCUboot/src/MCUboot.cpp @@ -8,12 +8,12 @@ void MCUboot::confirmSketch() boot_set_confirmed(); } -void MCUboot::applyUpdate(int permanent) +void MCUboot::applyUpdate(bool permanent) { - boot_set_pending(permanent); + boot_set_pending(permanent == true ? 1 : 0); } -void MCUboot::bootDebug(int enable) +void MCUboot::bootDebug(bool enable) { unsigned int rtc_reg = STM32H747::readBackupRegister(RTCBackup::DR7); diff --git a/libraries/MCUboot/src/MCUboot.h b/libraries/MCUboot/src/MCUboot.h index 57d6b91c0..3ea6b4842 100644 --- a/libraries/MCUboot/src/MCUboot.h +++ b/libraries/MCUboot/src/MCUboot.h @@ -6,8 +6,8 @@ class MCUboot public: static void confirmSketch(void); - static void applyUpdate(int permanent); - static void bootDebug(int enable); + static void applyUpdate(bool permanent); + static void bootDebug(bool enable); }; From 7f00608c9cff5b9124dc485ce31d869485962e6e Mon Sep 17 00:00:00 2001 From: pennam Date: Wed, 15 Mar 2023 09:55:50 +0100 Subject: [PATCH 3/4] Bump library version to v0.1.0 --- libraries/MCUboot/library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/MCUboot/library.properties b/libraries/MCUboot/library.properties index a443e4677..6121ba877 100644 --- a/libraries/MCUboot/library.properties +++ b/libraries/MCUboot/library.properties @@ -1,5 +1,5 @@ name=MCUboot -version=0.0.1 +version=0.1.0 author=Arduino maintainer=Arduino sentence=Wrapper library for MCUboot From da11900b14470c98036b3758c67944339a47de2d Mon Sep 17 00:00:00 2001 From: pennam Date: Wed, 15 Mar 2023 09:56:43 +0100 Subject: [PATCH 4/4] MCUboot library: add examples --- .../examples/enableDebug/enableDebug.ino | 23 +++ .../MCUboot/examples/secureOTA/secureOTA.ino | 171 ++++++++++++++++++ 2 files changed, 194 insertions(+) create mode 100644 libraries/MCUboot/examples/enableDebug/enableDebug.ino create mode 100644 libraries/MCUboot/examples/secureOTA/secureOTA.ino diff --git a/libraries/MCUboot/examples/enableDebug/enableDebug.ino b/libraries/MCUboot/examples/enableDebug/enableDebug.ino new file mode 100644 index 000000000..f0b41bcfe --- /dev/null +++ b/libraries/MCUboot/examples/enableDebug/enableDebug.ino @@ -0,0 +1,23 @@ +/* + This example shows how to enable/disable bootloader debug + using MCUboot library. The used debug output is Serial1 + + Circuit: + - Arduino Portenta H7 board + + This example code is in the public domain. +*/ + +#include + +// the setup function runs once when you press reset or power the board +void setup() { + // set RTC register DR7 + MCUboot::bootDebug(true); +} + +// the loop function runs over and over again forever +void loop() { + + +} diff --git a/libraries/MCUboot/examples/secureOTA/secureOTA.ino b/libraries/MCUboot/examples/secureOTA/secureOTA.ino new file mode 100644 index 000000000..273dccba0 --- /dev/null +++ b/libraries/MCUboot/examples/secureOTA/secureOTA.ino @@ -0,0 +1,171 @@ +/* + This example shows how to perform an OTA with MCUboot + using MCUboot library. + + WARNING: The ota binary is signed and encrypted with default keys. + The example will work only if default keys are flashed within the + bootloader otherwise MCUboot will refuse to boot the OTA binary + + Circuit: + - Arduino Portenta H7 board + + This example code is in the public domain. +*/ + +#include "BlockDevice.h" +#include "MBRBlockDevice.h" +#include "FATFileSystem.h" +#include +#include + +static char const SSID[] = "SECRET_SSID"; /* your network SSID (name) */ +static char const PASS[] = "SECRET_PASS"; /* your network password (use for WPA, or use as key for WEP) */ + +static char const OTA_FILE_LOCATION[] = "https://downloads.arduino.cc/ota/OTA_Usage_Portenta.ino.PORTENTA_H7_M7.MCUboot.slot"; + +static const int MCUBOOT_SLOT_SIZE = 0x1E0000; + +bool applyUpdate = false; +bool confirmUpdate = false; + +// the setup function runs once when you press reset or power the board +void setup() { + Serial.begin(9600); + while(!Serial); + + if (WiFi.status() == WL_NO_SHIELD) + return; + + int status = WL_IDLE_STATUS; + while (status != WL_CONNECTED) + { + Serial.print("Attempting to connect to SSID: "); + Serial.println(SSID); + status = WiFi.begin(SSID, PASS); + delay(3000); + } + Serial.println("Connected to wifi"); + + Serial.println("Are you ready to apply a new update? Y/[n]"); + applyUpdate = waitResponse(); + + if (applyUpdate) { + + // Mount filesystem and download the OTA file + mbed::BlockDevice * raw = mbed::BlockDevice::get_default_instance(); + mbed::MBRBlockDevice * mbr = new mbed::MBRBlockDevice(raw, 2); + int err = mbr->init(); + if (err < 0) { + Serial.print("Error initializing Block Device "); + Serial.println(err); + return; + } + + mbed::FATFileSystem * fs = new mbed::FATFileSystem("ota"); + err = fs->mount(mbr); + if (err < 0) { + Serial.print("Error mounting filesystem "); + Serial.println(err); + return; + } + + Serial.println("Downloading update file"); + err = WiFi.download((char*)OTA_FILE_LOCATION, "/ota/update.bin", true); + if (err < 0) { + Serial.print("Error downloading file "); + Serial.println(err); + return; + } + + // OTA file is not padded to reduce download time, + // but MCUboot needs update file to be padded + FILE* update_file = fopen("/ota/update.bin", "rb+"); + fseek(update_file, 0, SEEK_END); + int fsize = ftell(update_file); + + Serial.print("File update.bin size "); + Serial.println( fsize ); + + if (fsize < MCUBOOT_SLOT_SIZE) { + const char buffer[1] = {0xFF}; + + Serial.println("Padding update file"); + printProgress(fsize, MCUBOOT_SLOT_SIZE, 10, true); + while (fsize < MCUBOOT_SLOT_SIZE) { + int ret = fwrite(buffer, 1, 1, update_file); + if (ret != 1) { + Serial.println("Error writing update file"); + break; + } + fsize += 1; + printProgress(fsize, MCUBOOT_SLOT_SIZE, 10, false); + } + } + Serial.println("Flashed 100%"); + + fseek(update_file, 0, SEEK_END); + Serial.print("File update.bin size "); + Serial.println( fsize ); + + if(fsize != 0x1E0000) { + Serial.print("Error padding file "); + return; + } + + fclose(update_file); + fs->unmount(); + + // Is it possible to pre-confirm padded OTA file to prevent rollback + Serial.println("Do you want to make the update permanent? Y/[n]"); + confirmUpdate = waitResponse(); + + // Set update pending and image OK flags + MCUboot::applyUpdate(confirmUpdate); + Serial.println("Done, waiting reset"); + } else { + Serial.println("No update pending. It's now safe to reboot or disconnect your board."); + } +} + +bool waitResponse() { + bool confirmation = false; + while (confirmation == false) { + if (Serial.available()) { + char choice = Serial.read(); + switch (choice) { + case 'y': + case 'Y': + confirmation = true; + return true; + break; + case 'n': + case 'N': + confirmation = true; + return false; + break; + default: + continue; + } + } + } +} + +void printProgress(uint32_t offset, uint32_t size, uint32_t threshold, bool reset) { + static int percent_done = 0; + if (reset == true) { + percent_done = 0; + Serial.println("Flashed " + String(percent_done) + "%"); + } else { + uint32_t percent_done_new = offset * 100 / size; + if (percent_done_new >= percent_done + threshold) { + percent_done = percent_done_new; + Serial.println("Flashed " + String(percent_done) + "%"); + } + } +} + +// the loop function runs over and over again forever +void loop() { + // wait 100ms + delay(100); +}