diff --git a/boot/bootutil/include/bootutil/boot_hooks.h b/boot/bootutil/include/bootutil/boot_hooks.h index ef7a89b28..f5b10e8c7 100644 --- a/boot/bootutil/include/bootutil/boot_hooks.h +++ b/boot/bootutil/include/bootutil/boot_hooks.h @@ -82,6 +82,18 @@ #endif /* MCUBOOT_BOOT_GO_HOOKS */ +#ifdef MCUBOOT_FIND_NEXT_SLOT_HOOKS + +#define BOOT_HOOK_FIND_SLOT_CALL(f, ret_default, ...) \ + DO_HOOK_CALL(f, ret_default, __VA_ARGS__) + +#else + +#define BOOT_HOOK_FIND_SLOT_CALL(f, ret_default, ...) \ + HOOK_CALL_NOP(f, ret_default, __VA_ARGS__) + +#endif /* MCUBOOT_FIND_NEXT_SLOT_HOOKS */ + #ifdef MCUBOOT_FLASH_AREA_HOOKS #define BOOT_HOOK_FLASH_AREA_CALL(f, ret_default, ...) \ @@ -260,4 +272,16 @@ int flash_area_get_device_id_hook(const struct flash_area *fa, #define BOOT_RESET_REQUEST_HOOK_CHECK_FAILED 3 #define BOOT_RESET_REQUEST_HOOK_INTERNAL_ERROR 4 +/** + * Finds the preferred slot containing the image. + * + * @param[in] state Boot loader status information. + * @param[in] image Image, for which the slot should be found. + * @param[out] active_slot Number of the preferred slot. + * + * @return 0 if a slot was requested; + * BOOT_HOOK_REGULAR follow the normal execution path. + */ +int boot_find_next_slot_hook(struct boot_loader_state *state, uint8_t image, uint32_t *active_slot); + #endif /*H_BOOTUTIL_HOOKS*/ diff --git a/boot/bootutil/include/bootutil/boot_request.h b/boot/bootutil/include/bootutil/boot_request.h new file mode 100644 index 000000000..b1e8f891e --- /dev/null +++ b/boot/bootutil/include/bootutil/boot_request.h @@ -0,0 +1,105 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2025 Nordic Semiconductor ASA + */ + +#ifndef __BOOT_REQUEST_H__ +#define __BOOT_REQUEST_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +/** Special value, indicating that there is no preferred slot. */ +#define BOOT_REQUEST_NO_PREFERRED_SLOT UINT32_MAX + +/** + * @brief Request a bootloader to confirm the specified slot of an image. + * + * @param[in] image Image number. + * @param[in] slot Slot number. + * + * @return 0 if requested, negative error code otherwise. + */ +int boot_request_confirm_slot(uint8_t image, uint32_t slot); + +/** + * @brief Request a bootloader to boot the specified slot of an image. + * + * @param[in] image Image number. + * @param[in] slot Slot number. + * + * @return 0 if requested, negative error code otherwise. + */ +int boot_request_set_preferred_slot(uint8_t image, uint32_t slot); + +/** + * @brief Request a bootloader to boot recovery image. + * + * @return 0 if requested, negative error code otherwise. + */ +int boot_request_enter_recovery(void); + +/** + * @brief Request a bootloader to boot firmware loader image. + * + * @return 0 if requested, negative error code otherwise. + */ +int boot_request_enter_firmware_loader(void); + +/** + * @brief Check if there is a request to confirm the specified slot of an image. + * + * @param[in] image Image number. + * @param[in] slot Slot number. + * + * @return true if requested, false otherwise. + */ +bool boot_request_check_confirmed_slot(uint8_t image, uint32_t slot); + +/** + * @brief Find if there is a request to boot certain slot of the specified image. + * + * @param[in] image Image number. + * + * @return slot number if requested, BOOT_REQUEST_NO_PREFERRED_SLOT otherwise. + */ +uint32_t boot_request_get_preferred_slot(uint8_t image); + +/** + * @brief Check if there is a request to boot recovery image. + * + * @return true if requested, false otherwise. + */ +bool boot_request_detect_recovery(void); + +/** + * @brief Check if there is a request to boot firmware loader image. + * + * @return true if requested, false otherwise. + */ +bool boot_request_detect_firmware_loader(void); + +/** + * @brief Initialize boot requests module. + * + * @return 0 if successful, negative error code otherwise. + */ +int boot_request_init(void); + +/** + * @brief Clear/drop all requests. + * + * @return 0 if successful, negative error code otherwise. + */ +int boot_request_clear(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __BOOT_REQUEST_H__ */ diff --git a/boot/bootutil/src/bootutil_public.c b/boot/bootutil/src/bootutil_public.c index 8860fca41..7371a9fe9 100644 --- a/boot/bootutil/src/bootutil_public.c +++ b/boot/bootutil/src/bootutil_public.c @@ -51,6 +51,11 @@ #include "bootutil_priv.h" #include "bootutil_misc.h" +#if defined(CONFIG_NRF_MCUBOOT_BOOT_REQUEST) && !defined(CONFIG_MCUBOOT) +#include +#define SEND_BOOT_REQUEST +#endif /* CONFIG_NRF_MCUBOOT_BOOT_REQUEST && !CONFIG_MCUBOOT */ + #ifdef CONFIG_MCUBOOT BOOT_LOG_MODULE_DECLARE(mcuboot); #else @@ -503,16 +508,47 @@ boot_write_copy_done(const struct flash_area *fap) return boot_write_trailer_flag(fap, off, BOOT_FLAG_SET); } -#ifndef MCUBOOT_BOOTUTIL_LIB_FOR_DIRECT_XIP +#ifdef SEND_BOOT_REQUEST +static int +send_boot_request(uint8_t magic, bool confirm, int image_id, uint32_t slot_id) +{ + int rc = BOOT_EBADIMAGE; -static int flash_area_to_image(const struct flash_area *fa) + /* Handle write-protected active image. */ + if ((magic == BOOT_MAGIC_GOOD) || (magic == BOOT_MAGIC_UNSET)) { + if (confirm) { + BOOT_LOG_DBG("Confirm image: %d, %d", image_id, slot_id); + rc = boot_request_confirm_slot(image_id, slot_id); + } else { + BOOT_LOG_DBG("Set image preference: %d, %d", image_id, slot_id); + rc = boot_request_set_preferred_slot(image_id, slot_id); + } + if (rc != 0) { + rc = BOOT_EBADIMAGE; + } + } + + return rc; +} +#endif /* SEND_BOOT_REQUEST */ + +#if defined(SEND_BOOT_REQUEST) || (!defined(MCUBOOT_BOOTUTIL_LIB_FOR_DIRECT_XIP)) +static int flash_area_to_image_slot(const struct flash_area *fa, uint32_t *slot) { + int id = flash_area_get_id(fa); #if BOOT_IMAGE_NUMBER > 1 uint8_t i = 0; - int id = flash_area_get_id(fa); while (i < BOOT_IMAGE_NUMBER) { - if (FLASH_AREA_IMAGE_PRIMARY(i) == id || (FLASH_AREA_IMAGE_SECONDARY(i) == id)) { + if (FLASH_AREA_IMAGE_PRIMARY(i) == id) { + if (slot != NULL) { + *slot = 0; + } + return i; + } else if (FLASH_AREA_IMAGE_SECONDARY(i) == id) { + if (slot != NULL) { + *slot = 1; + } return i; } @@ -520,15 +556,31 @@ static int flash_area_to_image(const struct flash_area *fa) } #else (void)fa; + if (slot != NULL) { + if (FLASH_AREA_IMAGE_PRIMARY(0) == id) { + *slot = 0; + } else if (FLASH_AREA_IMAGE_SECONDARY(0) == id) { + *slot = 1; + } else { + *slot = UINT32_MAX; + } + } #endif return 0; } +#endif /* defined(SEND_BOOT_REQUEST) || (!defined(MCUBOOT_BOOTUTIL_LIB_FOR_DIRECT_XIP)) */ +#ifndef MCUBOOT_BOOTUTIL_LIB_FOR_DIRECT_XIP int boot_set_next(const struct flash_area *fa, bool active, bool confirm) { struct boot_swap_state slot_state; int rc; + int image_id; + uint32_t slot_id; + + BOOT_LOG_DBG("boot_set_next: fa %p active == %d, confirm == %d", + fa, (int)active, (int)confirm); if (active) { confirm = true; @@ -539,6 +591,15 @@ boot_set_next(const struct flash_area *fa, bool active, bool confirm) return rc; } + image_id = flash_area_to_image_slot(fa, &slot_id); + +#ifdef SEND_BOOT_REQUEST + rc = send_boot_request(slot_state.magic, confirm, image_id, slot_id); + if ((rc != 0) || active) { + return rc; + } +#endif + switch (slot_state.magic) { case BOOT_MAGIC_GOOD: /* If non-active then swap already scheduled, else confirm needed.*/ @@ -569,7 +630,7 @@ boot_set_next(const struct flash_area *fa, bool active, bool confirm) } else { swap_type = BOOT_SWAP_TYPE_TEST; } - rc = boot_write_swap_info(fa, swap_type, flash_area_to_image(fa)); + rc = boot_write_swap_info(fa, swap_type, image_id); } } break; @@ -600,6 +661,10 @@ boot_set_next(const struct flash_area *fa, bool active, bool confirm) { struct boot_swap_state slot_state; int rc; +#ifdef SEND_BOOT_REQUEST + int image_id; + uint32_t slot_id; +#endif BOOT_LOG_DBG("boot_set_next: fa %p active == %d, confirm == %d", fa, (int)active, (int)confirm); @@ -618,6 +683,15 @@ boot_set_next(const struct flash_area *fa, bool active, bool confirm) return rc; } +#ifdef SEND_BOOT_REQUEST + image_id = flash_area_to_image_slot(fa, &slot_id); + + rc = send_boot_request(slot_state.magic, confirm, image_id, slot_id); + if ((rc != 0) || active) { + return rc; + } +#endif + switch (slot_state.magic) { case BOOT_MAGIC_UNSET: /* Magic is needed for MCUboot to even consider booting an image */ diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 23a65d1ec..1a2290769 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -3605,7 +3605,12 @@ boot_load_and_validate_images(struct boot_loader_state *state) break; } - active_slot = find_slot_with_highest_version(state); + rc = BOOT_HOOK_FIND_SLOT_CALL(boot_find_next_slot_hook, BOOT_HOOK_REGULAR, + state, BOOT_CURR_IMG(state), &active_slot); + if (rc == BOOT_HOOK_REGULAR) { + active_slot = find_slot_with_highest_version(state); + } + if (active_slot == NO_ACTIVE_SLOT) { BOOT_LOG_INF("No slot to load for image %d", BOOT_CURR_IMG(state)); @@ -3652,7 +3657,12 @@ boot_load_and_validate_images(struct boot_loader_state *state) break; } - active_slot = find_slot_with_highest_version(state); + rc = BOOT_HOOK_FIND_SLOT_CALL(boot_find_next_slot_hook, BOOT_HOOK_REGULAR, + state, BOOT_CURR_IMG(state), &active_slot); + if (rc == BOOT_HOOK_REGULAR) { + active_slot = find_slot_with_highest_version(state); + } + if (active_slot == NO_ACTIVE_SLOT) { BOOT_LOG_INF("No slot to load for image %d", BOOT_CURR_IMG(state)); diff --git a/boot/bootutil/zephyr/CMakeLists.txt b/boot/bootutil/zephyr/CMakeLists.txt index 44f78f395..111cf4f1d 100644 --- a/boot/bootutil/zephyr/CMakeLists.txt +++ b/boot/bootutil/zephyr/CMakeLists.txt @@ -16,6 +16,11 @@ zephyr_library_named(mcuboot_util) zephyr_library_sources( ../src/bootutil_public.c ) +if(CONFIG_NRF_MCUBOOT_BOOT_REQUEST) + zephyr_library_sources_ifdef(CONFIG_NRF_MCUBOOT_BOOT_REQUEST_IMPL_RETENTION + src/boot_request_retention.c + ) +endif() # Sensitivity to the TEST_BOOT_IMAGE_ACCESS_HOOKS define is implemented for # allowing the test-build with the hooks feature enabled. diff --git a/boot/bootutil/zephyr/src/boot_request_retention.c b/boot/bootutil/zephyr/src/boot_request_retention.c new file mode 100644 index 000000000..1c814e2fb --- /dev/null +++ b/boot/bootutil/zephyr/src/boot_request_retention.c @@ -0,0 +1,346 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2025 Nordic Semiconductor ASA + */ +#include + +#include "bootutil/bootutil_log.h" +#include + +/** Special value of image number, indicating a request to the bootloader. */ +#define BOOT_REQUEST_IMG_BOOTLOADER 0xFF + +/** Additional memory used by the retention subsystem (2B - prefix, 4B - CRC).*/ +#define BOOT_REQUEST_ENTRY_METADATA_SIZE (2 + 4) + +MCUBOOT_LOG_MODULE_REGISTER(bootloader_request); + +static const struct device *bootloader_request_dev = + DEVICE_DT_GET(DT_CHOSEN(nrf_bootloader_request)); + +enum boot_request_type { + /** Invalid request. */ + BOOT_REQUEST_INVALID = 0, + + /** Request a change in the bootloader boot mode. + * + * @details Use @p boot_request_mode as argument. + * @p BOOT_REQUEST_IMG_BOOTLOADER as image number. + * + * @note Used to trigger recovery through i.e. retention sybsystem. + */ + BOOT_REQUEST_BOOT_MODE = 1, + + /** Select the preferred image to be selected during boot or update. + * + * @details Use @p boot_request_slot_t as argument. + * + * @note Used in the Direct XIP mode. + */ + BOOT_REQUEST_IMG_PREFERENCE = 2, + + /** Request a confirmation of an image. + * + * @details Use @p boot_request_slot_t as argument. + * + * @note Used if the code cannot modify the image trailer directly. + */ + BOOT_REQUEST_IMG_CONFIRM = 3, +}; + +/* Entries inside the boot request shared memory. */ +enum boot_request_entry { + BOOT_REQUEST_ENTRY_BOOT_MODE = 0, + BOOT_REQUEST_ENTRY_PRIMARY_IMG_PREFERENCE = 1, + BOOT_REQUEST_ENTRY_PRIMARY_IMG_CONFIRM = 2, + BOOT_REQUEST_ENTRY_SECONDARY_IMG_PREFERENCE = 3, + BOOT_REQUEST_ENTRY_SECONDARY_IMG_CONFIRM = 4, + BOOT_REQUEST_ENTRY_MAX = 5, +}; + +/* Assert that all requests will fit within the retention area. */ +BUILD_ASSERT((BOOT_REQUEST_ENTRY_METADATA_SIZE + BOOT_REQUEST_ENTRY_MAX * sizeof(uint8_t)) < + DT_REG_SIZE_BY_IDX(DT_CHOSEN(nrf_bootloader_request), 0), + "nrf,bootloader-request area is too small for bootloader request struct"); + +enum boot_request_slot { + /** Unsupported value. */ + BOOT_REQUEST_SLOT_INVALID = 0, + /** Primary slot. */ + BOOT_REQUEST_SLOT_PRIMARY = 1, + /** Secondary slot. */ + BOOT_REQUEST_SLOT_SECONDARY = 2, +}; + +/** Alias type for the image and number. */ +typedef uint8_t boot_request_slot_t; + +enum boot_request_mode { + /** Execute a regular boot logic. */ + BOOT_REQUEST_MODE_REGULAR = 0, + /** Execute the recovery boot logic. */ + BOOT_REQUEST_MODE_RECOVERY = 1, + /** Execute the firmware loader logic. */ + BOOT_REQUEST_MODE_FIRMWARE_LOADER = 2, + /** Unsupported value. */ + BOOT_REQUEST_MODE_INVALID = 0xFF, +}; + +/** Alias type for the image number. */ +typedef uint8_t boot_request_img_t; + +/** + * @brief Find an entry for a given request. + * + * @param[in] type Type of request. + * @param[in] image Image number. Use @p BOOT_REQUEST_IMG_BOOTLOADER for generic requests. + * @param[out] entry Entry to use. + * + * @return 0 on success; nonzero on failure. + */ +static int boot_request_entry_find(enum boot_request_type type, boot_request_img_t image, + size_t *entry) +{ + if (entry == NULL) { + return -EINVAL; + } + + switch (type) { + case BOOT_REQUEST_BOOT_MODE: + *entry = BOOT_REQUEST_ENTRY_BOOT_MODE; + break; + case BOOT_REQUEST_IMG_PREFERENCE: + switch (image) { + case BOOT_REQUEST_SLOT_PRIMARY: + *entry = BOOT_REQUEST_ENTRY_PRIMARY_IMG_PREFERENCE; + break; + case BOOT_REQUEST_SLOT_SECONDARY: + *entry = BOOT_REQUEST_ENTRY_SECONDARY_IMG_PREFERENCE; + break; + default: + return -EINVAL; + } + break; + case BOOT_REQUEST_IMG_CONFIRM: + switch (image) { + case BOOT_REQUEST_SLOT_PRIMARY: + *entry = BOOT_REQUEST_ENTRY_PRIMARY_IMG_CONFIRM; + break; + case BOOT_REQUEST_SLOT_SECONDARY: + *entry = BOOT_REQUEST_ENTRY_SECONDARY_IMG_CONFIRM; + break; + default: + return -EINVAL; + } + break; + default: + return -EINVAL; + } + + return 0; +} + +int boot_request_init(void) +{ + if (!device_is_ready(bootloader_request_dev)) { + return -EIO; + } + + return 0; +} + +int boot_request_clear(void) +{ + return retention_clear(bootloader_request_dev); +} + +int boot_request_confirm_slot(uint8_t image, uint32_t slot) +{ + uint8_t value = BOOT_REQUEST_SLOT_INVALID; + size_t req_entry; + int ret; + + ret = boot_request_entry_find(BOOT_REQUEST_IMG_CONFIRM, image, &req_entry); + if (ret != 0) { + return ret; + } + + switch (slot) { + case 0: + value = BOOT_REQUEST_SLOT_PRIMARY; + break; + case 1: + value = BOOT_REQUEST_SLOT_SECONDARY; + break; + default: + return -EINVAL; + } + + return retention_write(bootloader_request_dev, req_entry * sizeof(value), (void *)&value, + sizeof(value)); +} + +bool boot_request_check_confirmed_slot(uint8_t image, uint32_t slot) +{ + uint8_t value = BOOT_REQUEST_SLOT_INVALID; + size_t req_entry; + int ret; + + ret = boot_request_entry_find(BOOT_REQUEST_IMG_CONFIRM, image, &req_entry); + if (ret != 0) { + return false; + } + + ret = retention_read(bootloader_request_dev, req_entry * sizeof(value), (void *)&value, + sizeof(value)); + if (ret != 0) { + return false; + } + + switch (value) { + case BOOT_REQUEST_SLOT_PRIMARY: + return (slot == 0); + case BOOT_REQUEST_SLOT_SECONDARY: + return (slot == 1); + default: + break; + } + + return false; +} + +int boot_request_set_preferred_slot(uint8_t image, uint32_t slot) +{ + uint8_t value = BOOT_REQUEST_SLOT_INVALID; + size_t req_entry; + int ret; + + ret = boot_request_entry_find(BOOT_REQUEST_IMG_PREFERENCE, image, &req_entry); + if (ret != 0) { + return ret; + } + + switch (slot) { + case 0: + value = BOOT_REQUEST_SLOT_PRIMARY; + break; + case 1: + value = BOOT_REQUEST_SLOT_SECONDARY; + break; + default: + return -EINVAL; + } + + return retention_write(bootloader_request_dev, req_entry * sizeof(value), (void *)&value, + sizeof(value)); +} + +#ifdef CONFIG_FIND_NEXT_SLOT_HOOKS +uint32_t boot_request_get_preferred_slot(uint8_t image) +{ + uint8_t value = BOOT_REQUEST_SLOT_INVALID; + size_t req_entry; + int ret; + + ret = boot_request_entry_find(BOOT_REQUEST_IMG_PREFERENCE, image, &req_entry); + if (ret != 0) { + return BOOT_REQUEST_NO_PREFERRED_SLOT; + } + + ret = retention_read(bootloader_request_dev, req_entry * sizeof(value), (void *)&value, + sizeof(value)); + if (ret != 0) { + return BOOT_REQUEST_NO_PREFERRED_SLOT; + } + + switch (value) { + case BOOT_REQUEST_SLOT_PRIMARY: + return 0; + case BOOT_REQUEST_SLOT_SECONDARY: + return 1; + default: + break; + } + + return BOOT_REQUEST_NO_PREFERRED_SLOT; +} +#endif /* CONFIG_FIND_NEXT_SLOT_HOOKS */ + +int boot_request_enter_recovery(void) +{ + uint8_t value = BOOT_REQUEST_MODE_RECOVERY; + size_t req_entry; + int ret; + + ret = boot_request_entry_find(BOOT_REQUEST_BOOT_MODE, BOOT_REQUEST_IMG_BOOTLOADER, + &req_entry); + if (ret != 0) { + return ret; + } + + return retention_write(bootloader_request_dev, req_entry * sizeof(value), (void *)&value, + sizeof(value)); +} + +#ifdef CONFIG_NRF_BOOT_SERIAL_BOOT_REQ +bool boot_request_detect_recovery(void) +{ + uint8_t value = BOOT_REQUEST_MODE_INVALID; + size_t req_entry; + int ret; + + ret = boot_request_entry_find(BOOT_REQUEST_BOOT_MODE, BOOT_REQUEST_IMG_BOOTLOADER, + &req_entry); + if (ret != 0) { + return false; + } + + ret = retention_read(bootloader_request_dev, req_entry * sizeof(value), (void *)&value, + sizeof(value)); + if ((ret == 0) && (value == BOOT_REQUEST_MODE_RECOVERY)) { + return true; + } + + return false; +} +#endif /* CONFIG_NRF_BOOT_SERIAL_BOOT_REQ */ + +int boot_request_enter_firmware_loader(void) +{ + uint8_t value = BOOT_REQUEST_MODE_FIRMWARE_LOADER; + size_t req_entry; + int ret; + + ret = boot_request_entry_find(BOOT_REQUEST_BOOT_MODE, BOOT_REQUEST_IMG_BOOTLOADER, + &req_entry); + if (ret != 0) { + return ret; + } + + return retention_write(bootloader_request_dev, req_entry * sizeof(value), (void *)&value, + sizeof(value)); +} + +#ifdef CONFIG_NRF_BOOT_FIRMWARE_LOADER_BOOT_REQ +bool boot_request_detect_firmware_loader(void) +{ + uint8_t value = BOOT_REQUEST_MODE_INVALID; + size_t req_entry; + int ret; + + ret = boot_request_entry_find(BOOT_REQUEST_BOOT_MODE, BOOT_REQUEST_IMG_BOOTLOADER, + &req_entry); + if (ret != 0) { + return false; + } + + ret = retention_read(bootloader_request_dev, req_entry * sizeof(value), (void *)&value, + sizeof(value)); + if ((ret == 0) && (value == BOOT_REQUEST_MODE_FIRMWARE_LOADER)) { + return true; + } + + return false; +} +#endif /* CONFIG_NRF_BOOT_FIRMWARE_LOADER_BOOT_REQ */ diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 4ddd138d7..1e2bb535b 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -1130,6 +1130,13 @@ config MCUBOOT_ACTION_HOOKS 'mcuboot_status_type_t' is listed in boot/bootutil/include/bootutil/mcuboot_status.h +config FIND_NEXT_SLOT_HOOKS + bool "Enable hooks for finding the next active slot" + help + Allow to provide procedures for override or extend the search policy + for the best slot to boot in the Direct XIP mode. + By default a slot with the highest version is selected. + config BOOT_DISABLE_CACHES bool "Disable I/D caches before chain-loading application" depends on CPU_HAS_ICACHE || CPU_HAS_DCACHE @@ -1291,6 +1298,10 @@ config USB_DEVICE_PRODUCT config MCUBOOT_BOOTUTIL_LIB_OWN_LOG bool +config NRF_MCUBOOT_BOOT_REQUEST + bool + imply FIND_NEXT_SLOT_HOOKS if BOOT_DIRECT_XIP || BOOT_RAM_LOAD + config MCUBOOT_VERIFY_IMG_ADDRESS bool "Verify reset address of image in secondary slot" depends on UPDATEABLE_IMAGE_NUMBER > 1 diff --git a/boot/zephyr/Kconfig.firmware_loader b/boot/zephyr/Kconfig.firmware_loader index 1ba223949..3ef70ed16 100644 --- a/boot/zephyr/Kconfig.firmware_loader +++ b/boot/zephyr/Kconfig.firmware_loader @@ -42,6 +42,12 @@ config BOOT_FIRMWARE_LOADER_PIN_RESET Checks if the module reset was caused by the reset pin and will remain in bootloader firmware loader mode if it was. +config NRF_BOOT_FIRMWARE_LOADER_BOOT_REQ + bool "Check boot mode via bootloader request" + depends on NRF_MCUBOOT_BOOT_REQUEST + help + Allows for entering firmware loader mode by using bootloader rquests. + endmenu endif diff --git a/boot/zephyr/Kconfig.serial_recovery b/boot/zephyr/Kconfig.serial_recovery index 5b4ba3e11..b6c71e5e0 100644 --- a/boot/zephyr/Kconfig.serial_recovery +++ b/boot/zephyr/Kconfig.serial_recovery @@ -191,6 +191,12 @@ config BOOT_SERIAL_PIN_RESET Checks if the module reset was caused by the reset pin and will remain in bootloader serial recovery mode if it was. +config NRF_BOOT_SERIAL_BOOT_REQ + bool "Check boot mode via bootloader request subsystem" + depends on NRF_MCUBOOT_BOOT_REQUEST + help + Allows for entering serial recovery mode by using bootloader requests. + endmenu config BOOT_SERIAL_IMG_GRP_HASH diff --git a/boot/zephyr/firmware_loader.c b/boot/zephyr/firmware_loader.c index 1df848634..834dc6341 100644 --- a/boot/zephyr/firmware_loader.c +++ b/boot/zephyr/firmware_loader.c @@ -17,6 +17,9 @@ #include "io/io.h" #include "mcuboot_config/mcuboot_config.h" +#ifdef CONFIG_NRF_MCUBOOT_BOOT_REQUEST +#include +#endif /* CONFIG_NRF_MCUBOOT_BOOT_REQUEST */ BOOT_LOG_MODULE_DECLARE(mcuboot); @@ -183,6 +186,12 @@ boot_go(struct boot_rsp *rsp) } #endif +#ifdef CONFIG_NRF_BOOT_FIRMWARE_LOADER_BOOT_REQ + if (boot_request_detect_firmware_loader()) { + boot_firmware_loader = true; + } +#endif + /* Check if firmware loader button is pressed. TODO: check all entrance methods */ if (boot_firmware_loader == true) { FIH_CALL(validate_image_slot, fih_rc, FLASH_AREA_IMAGE_SECONDARY(0), rsp); diff --git a/boot/zephyr/hooks_sample.c b/boot/zephyr/hooks_sample.c index a5a729314..fc7bd2fa4 100644 --- a/boot/zephyr/hooks_sample.c +++ b/boot/zephyr/hooks_sample.c @@ -93,3 +93,8 @@ int boot_img_install_stat_hook(int image_index, int slot, int *img_install_stat) { return BOOT_HOOK_REGULAR; } + +int boot_find_next_slot_hook(struct boot_loader_state *state, uint8_t image, uint32_t *active_slot) +{ + return BOOT_HOOK_REGULAR; +} diff --git a/boot/zephyr/include/mcuboot_config/mcuboot_config.h b/boot/zephyr/include/mcuboot_config/mcuboot_config.h index 8ba030738..0cc86ad4c 100644 --- a/boot/zephyr/include/mcuboot_config/mcuboot_config.h +++ b/boot/zephyr/include/mcuboot_config/mcuboot_config.h @@ -271,6 +271,10 @@ #define MCUBOOT_FLASH_AREA_HOOKS #endif +#ifdef CONFIG_FIND_NEXT_SLOT_HOOKS +#define MCUBOOT_FIND_NEXT_SLOT_HOOKS +#endif + #ifdef CONFIG_MCUBOOT_VERIFY_IMG_ADDRESS #define MCUBOOT_VERIFY_IMG_ADDRESS #endif diff --git a/boot/zephyr/main.c b/boot/zephyr/main.c index c51616dda..257f7a26c 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -46,6 +46,12 @@ #include "bootutil/fault_injection_hardening.h" #include "bootutil/mcuboot_status.h" #include "flash_map_backend/flash_map_backend.h" +#ifdef CONFIG_NRF_MCUBOOT_BOOT_REQUEST +#include + +/** Number of image slots. */ +#define BOOT_REQUEST_NUM_SLOTS 2 +#endif /* CONFIG_NRF_MCUBOOT_BOOT_REQUEST */ /* Check if Espressif target is supported */ #ifdef CONFIG_SOC_FAMILY_ESPRESSIF_ESP32 @@ -479,6 +485,37 @@ static void boot_serial_enter() } #endif +static int boot_prevalidate(void) +{ +#ifdef CONFIG_NRF_MCUBOOT_BOOT_REQUEST + uint8_t image_index; + uint32_t slot; + uint32_t area_id; + const struct flash_area *fap; + int rc = boot_request_init(); + + if (rc != 0) { + return rc; + } + + for (image_index = 0; image_index < BOOT_IMAGE_NUMBER; ++image_index) { + for (slot = 0; slot < BOOT_REQUEST_NUM_SLOTS; slot++) { + if (boot_request_check_confirmed_slot(image_index, slot)) { + BOOT_LOG_DBG("Confirm image: %d slot: %d due to bootloader request.", + image_index, slot); + + area_id = flash_area_id_from_multi_image_slot(image_index, slot); + rc = flash_area_open(area_id, &fap); + if (rc == 0) { + rc = boot_set_next(fap, true, true); + } + } + } + } +#endif + return 0; +} + int main(void) { struct boot_rsp rsp; @@ -510,6 +547,11 @@ int main(void) mcuboot_status_change(MCUBOOT_STATUS_STARTUP); + rc = boot_prevalidate(); + if (rc) { + BOOT_LOG_ERR("Failed to prevalidate the state: %d", rc); + } + #ifdef CONFIG_BOOT_SERIAL_ENTRANCE_GPIO BOOT_LOG_DBG("Checking GPIO for serial recovery"); if (io_detect_pin() && @@ -525,6 +567,13 @@ int main(void) } #endif +#ifdef CONFIG_NRF_BOOT_SERIAL_BOOT_REQ + if (boot_request_detect_recovery()) { + BOOT_LOG_DBG("Staying in serial recovery"); + boot_serial_enter(); + } +#endif + #if defined(CONFIG_BOOT_USB_DFU_GPIO) BOOT_LOG_DBG("Checking GPIO for USB DFU request"); if (io_detect_pin()) { @@ -585,6 +634,10 @@ int main(void) } BOOT_LOG_DBG("Left boot_go with success == %d", FIH_EQ(fih_rc, FIH_SUCCESS) ? 1 : 0); +#ifdef CONFIG_NRF_MCUBOOT_BOOT_REQUEST + (void)boot_request_clear(); +#endif + #ifdef CONFIG_BOOT_SERIAL_BOOT_MODE if (io_detect_boot_mode()) { /* Boot mode to stay in bootloader, clear status and enter serial