diff --git a/.github/workflows/zephyr_build.yaml b/.github/workflows/zephyr_build.yaml index e1ef4631da..a3826fb31a 100644 --- a/.github/workflows/zephyr_build.yaml +++ b/.github/workflows/zephyr_build.yaml @@ -87,6 +87,7 @@ jobs: -T ../bootloader/mcuboot/boot/zephyr -T ./tests/subsys/dfu -T ./samples/subsys/mgmt/mcumgr/smp_svr + -T ../bootloader/mcuboot/samples/runtime-source/zephyr/app run: | export ZEPHYR_BASE=${PWD} export ZEPHYR_TOOLCHAIN_VARIANT=zephyr diff --git a/boot/bootutil/include/bootutil/boot_hooks.h b/boot/bootutil/include/bootutil/boot_hooks.h index 6d4a34e87a..ef7a89b289 100644 --- a/boot/bootutil/include/bootutil/boot_hooks.h +++ b/boot/bootutil/include/bootutil/boot_hooks.h @@ -34,25 +34,65 @@ #ifndef H_BOOTUTIL_HOOKS #define H_BOOTUTIL_HOOKS -#ifdef MCUBOOT_IMAGE_ACCESS_HOOKS +#include "bootutil/bootutil.h" +#include "bootutil/fault_injection_hardening.h" -#define BOOT_HOOK_CALL(f, ret_default, ...) f(__VA_ARGS__) +#define DO_HOOK_CALL(f, ret_default, ...) \ + f(__VA_ARGS__) -#define BOOT_HOOK_CALL_FIH(f, fih_ret_default, fih_rc, ...) \ +#define DO_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 HOOK_CALL_NOP(f, ret_default, ...) ret_default -#define BOOT_HOOK_CALL_FIH(f, fih_ret_default, fih_rc, ...) \ +#define HOOK_CALL_FIH_NOP(f, fih_ret_default, fih_rc, ...) \ do { \ fih_rc = fih_ret_default; \ } while(0); -#endif +#ifdef MCUBOOT_IMAGE_ACCESS_HOOKS + +#define BOOT_HOOK_CALL(f, ret_default, ...) \ + DO_HOOK_CALL(f, ret_default, __VA_ARGS__) + +#define BOOT_HOOK_CALL_FIH(f, fih_ret_default, fih_rc, ...) \ + DO_HOOK_CALL_FIH(f, fih_ret_default, fih_rc, __VA_ARGS__) + +#else + +#define BOOT_HOOK_CALL(f, ret_default, ...) \ + HOOK_CALL_NOP(f, ret_default, __VA_ARGS__) + +#define BOOT_HOOK_CALL_FIH(f, fih_ret_default, fih_rc, ...) \ + HOOK_CALL_FIH_NOP(f, fih_ret_default, fih_rc, __VA_ARGS__) + +#endif /* MCUBOOT_IMAGE_ACCESS_HOOKS */ + +#ifdef MCUBOOT_BOOT_GO_HOOKS + +#define BOOT_HOOK_GO_CALL_FIH(f, fih_ret_default, fih_rc, ...) \ + DO_HOOK_CALL_FIH(f, fih_ret_default, fih_rc, __VA_ARGS__); + +#else + +#define BOOT_HOOK_GO_CALL_FIH(f, fih_ret_default, fih_rc, ...) \ + HOOK_CALL_FIH_NOP(f, fih_ret_default, fih_rc, __VA_ARGS__) + +#endif /* MCUBOOT_BOOT_GO_HOOKS */ + +#ifdef MCUBOOT_FLASH_AREA_HOOKS + +#define BOOT_HOOK_FLASH_AREA_CALL(f, ret_default, ...) \ + DO_HOOK_CALL(f, ret_default, __VA_ARGS__) + +#else + +#define BOOT_HOOK_FLASH_AREA_CALL(f, ret_default, ...) \ + HOOK_CALL_NOP(f, ret_default, __VA_ARGS__) + +#endif /* MCUBOOT_FLASH_AREA_ID_HOOKS */ /** Hook for provide image header data. * @@ -173,6 +213,48 @@ int boot_img_install_stat_hook(int image_index, int slot, */ int boot_reset_request_hook(bool force); +/** + * Hook to implement custom action before boot_go() function. + * + * @param rsp boot response structure. + * + * @retval FIH_SUCCESS: boot_go() should be skipped, boot response is already + * filled. + * FIH_FAILURE: boot_go() should be skipped, boot response is already + * filled with error. + * FIH_BOOT_HOOK_REGULAR: follow the normal execution path. + */ +fih_ret boot_go_hook(struct boot_rsp *rsp); + +/** + * Hook to implement custom action before retrieving flash area ID. + * + * @param image_index the index of the image pair + * @param slot slot number + * @param area_id the flash area ID to be populated + * + * @retval 0 the flash area ID was fetched successfully; + * BOOT_HOOK_REGULAR follow the normal execution path to get the flash + * area ID; + * otherwise an error-code value. + */ +int flash_area_id_from_multi_image_slot_hook(int image_index, int slot, + int *area_id); + +/** + * Hook to implement custom action before retrieving flash area device ID. + * + * @param fa the flash area structure + * @param device_id the device ID to be populated + * + * @retval 0 the device ID was fetched successfully; + * BOOT_HOOK_REGULAR follow the normal execution path to get the device + * ID; + * otherwise an error-code value. + */ +int flash_area_get_device_id_hook(const struct flash_area *fa, + uint8_t *device_id); + #define BOOT_RESET_REQUEST_HOOK_BUSY 1 #define BOOT_RESET_REQUEST_HOOK_TIMEOUT 2 #define BOOT_RESET_REQUEST_HOOK_CHECK_FAILED 3 diff --git a/boot/bootutil/include/bootutil/bootutil.h b/boot/bootutil/include/bootutil/bootutil.h index cea5689b9b..babb62fdc8 100644 --- a/boot/bootutil/include/bootutil/bootutil.h +++ b/boot/bootutil/include/bootutil/bootutil.h @@ -86,9 +86,9 @@ struct image_max_size { fih_ret boot_go(struct boot_rsp *rsp); fih_ret boot_go_for_image_id(struct boot_rsp *rsp, uint32_t image_id); -struct boot_loader_state; void boot_state_clear(struct boot_loader_state *state); fih_ret context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp); +struct boot_loader_state *boot_get_loader_state(void); const struct image_max_size *boot_get_max_app_size(void); uint32_t boot_get_state_secondary_offset(struct boot_loader_state *state, const struct flash_area *fap); diff --git a/boot/bootutil/include/bootutil/bootutil_public.h b/boot/bootutil/include/bootutil/bootutil_public.h index ffd263591a..bbfb729a3c 100644 --- a/boot/bootutil/include/bootutil/bootutil_public.h +++ b/boot/bootutil/include/bootutil/bootutil_public.h @@ -145,6 +145,8 @@ _Static_assert(MCUBOOT_BOOT_MAX_ALIGN >= 8 && MCUBOOT_BOOT_MAX_ALIGN <= 32, #endif #endif +struct boot_loader_state; + struct boot_swap_state { uint8_t magic; /* One of the BOOT_MAGIC_[...] values. */ uint8_t swap_type; /* One of the BOOT_SWAP_TYPE_[...] values. */ @@ -309,6 +311,41 @@ int boot_image_load_header(const struct flash_area *fa_p, struct image_header *hdr); +#ifdef MCUBOOT_RAM_LOAD +/** + * Loads image with given header to RAM. + * + * Destination on RAM and size is described on image header. + * + * @param[in] state boot loader state + * @param[in] hdr image header + * + * @return 0 on success, error code otherwise + */ +int boot_load_image_from_flash_to_sram(struct boot_loader_state *state, + struct image_header *hdr); + +/** + * Removes an image from SRAM, by overwriting it with zeros. + * + * @param state Boot loader status information. + * + * @return 0 on success; nonzero on failure. + */ +int boot_remove_image_from_sram(struct boot_loader_state *state); + +/** + * Removes an image from flash by erasing the corresponding flash area + * + * @param state Boot loader status information. + * @param slot The flash slot of the image to be erased. + * + * @return 0 on success; nonzero on failure. + */ +int boot_remove_image_from_flash(struct boot_loader_state *state, + uint32_t slot); +#endif + #ifdef __cplusplus } #endif diff --git a/boot/bootutil/src/bootutil_priv.h b/boot/bootutil/src/bootutil_priv.h index bb8a79cc41..01ec23fc12 100644 --- a/boot/bootutil/src/bootutil_priv.h +++ b/boot/bootutil/src/bootutil_priv.h @@ -503,9 +503,6 @@ struct bootsim_ram_info *bootsim_get_ram_info(void); (size)), 0) int boot_load_image_to_sram(struct boot_loader_state *state); -int boot_remove_image_from_sram(struct boot_loader_state *state); -int boot_remove_image_from_flash(struct boot_loader_state *state, - uint32_t slot); #else #define IMAGE_RAM_BASE ((uintptr_t)0) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 43dcd3f22f..4efbe719af 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -118,6 +118,11 @@ static struct sector_buffer_t sector_buffers; boot_copy_region(state, fap_pri, fap_sec, pri_off, sec_off, sz) #endif +struct boot_loader_state *boot_get_loader_state(void) +{ + return &boot_data; +} + static int boot_read_image_headers(struct boot_loader_state *state, bool require_all, struct boot_status *bs) diff --git a/boot/bootutil/src/ram_load.c b/boot/bootutil/src/ram_load.c index dd74052a36..630af11709 100644 --- a/boot/bootutil/src/ram_load.c +++ b/boot/bootutil/src/ram_load.c @@ -438,3 +438,17 @@ boot_remove_image_from_flash(struct boot_loader_state *state, uint32_t slot) return rc; } + +int boot_load_image_from_flash_to_sram(struct boot_loader_state *state, + struct image_header *hdr) +{ + int active_slot; + + /* boot_load_image_to_sram will load the image from state active_slot, + * so force it before loading the image. + */ + active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot; + BOOT_IMG(state, active_slot).hdr = *hdr; + + return boot_load_image_to_sram(state); +} diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index d8bef2f21f..b332000dac 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -7,6 +7,12 @@ cmake_minimum_required(VERSION 3.13.1) +# This sample shows usage of an external module and we need to set the +# set the extra module path before calling find_package(Zephyr). +if(TEST_RUNTIME_SOURCE_HOOKS) + set(EXTRA_ZEPHYR_MODULES "${CMAKE_SOURCE_DIR}/../../samples/runtime-source/zephyr/hooks") +endif() + # find_package(Zephyr) in order to load application boilerplate: # http://docs.zephyrproject.org/application/application.html find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) @@ -125,15 +131,15 @@ zephyr_library_sources( ) endif() -if(CONFIG_SINGLE_APPLICATION_SLOT) +if(CONFIG_SINGLE_APPLICATION_SLOT_RAM_LOAD) zephyr_library_sources( ${BOOT_DIR}/zephyr/single_loader.c + ${BOOT_DIR}/bootutil/src/ram_load.c ) zephyr_library_include_directories(${BOOT_DIR}/bootutil/src) -elseif(CONFIG_SINGLE_APPLICATION_SLOT OR CONFIG_SINGLE_APPLICATION_SLOT_RAM_LOAD) +elseif(CONFIG_SINGLE_APPLICATION_SLOT) zephyr_library_sources( ${BOOT_DIR}/zephyr/single_loader.c - ${BOOT_DIR}/bootutil/src/ram_load.c ) zephyr_library_include_directories(${BOOT_DIR}/bootutil/src) elseif(CONFIG_BOOT_FIRMWARE_LOADER) @@ -161,7 +167,7 @@ else() ${BOOT_DIR}/bootutil/src/swap_scratch.c ) - if(CONFIG_BOOT_RAM_LOAD OR CONFIG_SINGLE_APPLICATION_SLOT_RAM_LOAD) + if(CONFIG_BOOT_RAM_LOAD) zephyr_library_sources( ${BOOT_DIR}/bootutil/src/ram_load.c ) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index f4b9a55f78..9afd292b01 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -472,6 +472,17 @@ config BOOT_IMAGE_EXECUTABLE_RAM_SIZE default $(dt_chosen_reg_size_int,$(DT_CHOSEN_Z_SRAM),0) endif +config FLASH_RUNTIME_SOURCES + bool "Images are read from flash partitions defined at runtime" + depends on SINGLE_APPLICATION_SLOT + help + Instead of using information on the flash slots to decide which images + to load/update, the application provides the information from which + flash slot to load in runtime. This is useful when the application + reads the state for hardware straps or other sources to decide which + image to load. Usually, application will provide a boot_go_hook() to + decide which image to load. + config BOOT_ENCRYPTION_SUPPORT bool help @@ -855,6 +866,20 @@ config BOOT_IMAGE_ACCESS_HOOKS update. It is up to the project customization to add required source files to the build. +config BOOT_GO_HOOKS + bool "Enable hooks for overriding MCUBOOT's boot_go routine" + help + Allow to provide procedures for override or extend native + MCUboot's boot_go routine. It is up to the project customization to + add required source files to the build. + +config BOOT_FLASH_AREA_HOOKS + bool "Enable hooks for overriding MCUboot's flash area routines" + help + Allow to provide procedures for override or extend native + MCUboot's flash area routines. It is up to the project customization to + add required source files to the build. + config MCUBOOT_ACTION_HOOKS bool "Enable hooks for responding to MCUboot status changes" help diff --git a/boot/zephyr/flash_map_extended.c b/boot/zephyr/flash_map_extended.c index bf0d8f191c..4a29750f75 100644 --- a/boot/zephyr/flash_map_extended.c +++ b/boot/zephyr/flash_map_extended.c @@ -14,7 +14,9 @@ #include #include +#include "bootutil/boot_hooks.h" #include "bootutil/bootutil_log.h" +#include "bootutil/bootutil_public.h" BOOT_LOG_MODULE_DECLARE(mcuboot); @@ -58,6 +60,14 @@ int flash_device_base(uint8_t fd_id, uintptr_t *ret) */ int flash_area_id_from_multi_image_slot(int image_index, int slot) { + int rc, id; + + rc = BOOT_HOOK_FLASH_AREA_CALL(flash_area_id_from_multi_image_slot_hook, + BOOT_HOOK_REGULAR, image_index, slot, &id); + if (rc != BOOT_HOOK_REGULAR) { + return id; + } + switch (slot) { case 0: return FLASH_AREA_IMAGE_PRIMARY(image_index); #if !defined(CONFIG_SINGLE_APPLICATION_SLOT) @@ -138,6 +148,15 @@ int flash_area_sector_from_off(off_t off, struct flash_sector *sector) uint8_t flash_area_get_device_id(const struct flash_area *fa) { + uint8_t device_id; + int rc; + + rc = BOOT_HOOK_FLASH_AREA_CALL(flash_area_get_device_id_hook, + BOOT_HOOK_REGULAR, fa, &device_id); + if (rc != BOOT_HOOK_REGULAR) { + return device_id; + } + #if defined(CONFIG_ARM) return fa->fa_id; #else diff --git a/boot/zephyr/include/mcuboot_config/mcuboot_config.h b/boot/zephyr/include/mcuboot_config/mcuboot_config.h index dc49c66880..b5fcf82b42 100644 --- a/boot/zephyr/include/mcuboot_config/mcuboot_config.h +++ b/boot/zephyr/include/mcuboot_config/mcuboot_config.h @@ -242,6 +242,14 @@ #define MCUBOOT_IMAGE_ACCESS_HOOKS #endif +#ifdef CONFIG_BOOT_GO_HOOKS +#define MCUBOOT_BOOT_GO_HOOKS +#endif + +#ifdef CONFIG_BOOT_FLASH_AREA_HOOKS +#define MCUBOOT_FLASH_AREA_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 c84f18a1db..683b2f7f5f 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -41,6 +41,7 @@ #include "bootutil/bootutil_log.h" #include "bootutil/image.h" #include "bootutil/bootutil.h" +#include "bootutil/boot_hooks.h" #include "bootutil/fault_injection_hardening.h" #include "bootutil/mcuboot_status.h" #include "flash_map_backend/flash_map_backend.h" @@ -525,7 +526,10 @@ int main(void) #endif #endif - FIH_CALL(boot_go, fih_rc, &rsp); + BOOT_HOOK_GO_CALL_FIH(boot_go_hook, FIH_BOOT_HOOK_REGULAR, fih_rc, &rsp); + if (FIH_EQ(fih_rc, FIH_BOOT_HOOK_REGULAR)) { + FIH_CALL(boot_go, fih_rc, &rsp); + } #ifdef CONFIG_BOOT_SERIAL_BOOT_MODE if (io_detect_boot_mode()) { diff --git a/boot/zephyr/sample.yaml b/boot/zephyr/sample.yaml index 924f950cab..bf5bc93eaa 100644 --- a/boot/zephyr/sample.yaml +++ b/boot/zephyr/sample.yaml @@ -96,3 +96,9 @@ tests: integration_platforms: - nrf52840dk/nrf52840 tags: bootloader_mcuboot + sample.bootloader.mcuboot.runtime_source.hooks: + extra_args: EXTRA_CONF_FILE=../../samples/runtime-source/zephyr/sample.conf + TEST_RUNTIME_SOURCE_HOOKS=y + tags: bootloader_mcuboot runtime_source + platform_allow: frdm_k64f + build_only: true diff --git a/boot/zephyr/single_loader.c b/boot/zephyr/single_loader.c index f4122783ca..382f81eaa4 100644 --- a/boot/zephyr/single_loader.c +++ b/boot/zephyr/single_loader.c @@ -21,6 +21,12 @@ BOOT_LOG_MODULE_DECLARE(mcuboot); /* Variables passed outside of unit via poiters. */ static const struct flash_area *_fa_p; static struct image_header _hdr = { 0 }; +static struct boot_loader_state boot_data; + +struct boot_loader_state *boot_get_loader_state(void) +{ + return &boot_data; +} #if defined(MCUBOOT_VALIDATE_PRIMARY_SLOT) || defined(MCUBOOT_VALIDATE_PRIMARY_SLOT_ONCE) /** diff --git a/samples/runtime-source/zephyr/README.md b/samples/runtime-source/zephyr/README.md new file mode 100644 index 0000000000..e30c0b9064 --- /dev/null +++ b/samples/runtime-source/zephyr/README.md @@ -0,0 +1,55 @@ +# Runtime chosen image sample application + +This sample demonstrates how to use a non flash storage to retrieve the image +being booted. It was tested on a FRDM K64F. Both slots are used to store two +different images. The image to be booted is selected based on a button press. + +## Build + +Build mcuboot. First, ensure ZEPHYR_SDK_INSTALL_DIR is defined. From the +sample directory, run the following commands: + +``` + source /zephyr-env.sh + + west build -p -b frdm_k64f ../../../boot/zephyr/ -- \ + -DEXTRA_ZEPHYR_MODULES=$PWD/hooks -DEXTRA_CONF_FILE="$PWD/sample.conf" + + west build -t flash +``` + +Then, build the sample application to be loaded. We need to build it twice, one +for each slot. From the sample +app directory (mcuboot/samples/non-flash-source/zephyr/app), run: + +``` + west build -p -b frdm_k64f . + west flash +``` + +Then change the overlay file to use the second slot. For instance, open +`boards/frdm_k64f.overlay` and change the line: + +``` + zephyr,code-partition = &slot0_partition; + +``` + +to: + +``` + zephyr,code-partition = &slot1_partition; +``` + +And build and flash again: + +``` + west build -b frdm_k64f . + west flash +``` + +## Run + +Open a serial terminal to see the output and reset the board. It shall boot the +image on slot0 by default. By keeping the SW2 button pressed during reset, the +bootloader will boot the one on slot1. diff --git a/samples/runtime-source/zephyr/app/CMakeLists.txt b/samples/runtime-source/zephyr/app/CMakeLists.txt new file mode 100644 index 0000000000..63d893340c --- /dev/null +++ b/samples/runtime-source/zephyr/app/CMakeLists.txt @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(non_flash_backend_app) + +if(NOT DEFINED FROM_WHO) + set(FROM_WHO Zephyr) +endif() + +target_compile_definitions(app PRIVATE "-DMCUBOOT_HELLO_WORLD_FROM=\"${FROM_WHO}\"") + +target_sources(app PRIVATE src/main.c) diff --git a/samples/runtime-source/zephyr/app/boards/frdm_k64f.overlay b/samples/runtime-source/zephyr/app/boards/frdm_k64f.overlay new file mode 100644 index 0000000000..364d7e35e3 --- /dev/null +++ b/samples/runtime-source/zephyr/app/boards/frdm_k64f.overlay @@ -0,0 +1,5 @@ +/ { + chosen { + zephyr,code-partition = &slot0_partition; + }; +}; diff --git a/samples/runtime-source/zephyr/app/prj.conf b/samples/runtime-source/zephyr/app/prj.conf new file mode 100644 index 0000000000..bf0ea6a28e --- /dev/null +++ b/samples/runtime-source/zephyr/app/prj.conf @@ -0,0 +1,3 @@ +CONFIG_BOOTLOADER_MCUBOOT=y + +CONFIG_MCUBOOT_SIGNATURE_KEY_FILE="./bootloader/mcuboot/root-rsa-2048.pem" diff --git a/samples/runtime-source/zephyr/app/sample.yaml b/samples/runtime-source/zephyr/app/sample.yaml new file mode 100644 index 0000000000..ed90d7d698 --- /dev/null +++ b/samples/runtime-source/zephyr/app/sample.yaml @@ -0,0 +1,10 @@ +sample: + name: Runtime source target + description: Application loaded from mcuboot using runtime source hooks +common: + build_only: true +tests: + sample.zephyr.runtime_source.app: + tags: samples tests runtime_source + platform_allow: + - frdm_k64f diff --git a/samples/runtime-source/zephyr/app/src/main.c b/samples/runtime-source/zephyr/app/src/main.c new file mode 100644 index 0000000000..03e16e2cf3 --- /dev/null +++ b/samples/runtime-source/zephyr/app/src/main.c @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2024 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +int main(void) +{ + printk("Hello World from %s on %s, slot %s!\n", + MCUBOOT_HELLO_WORLD_FROM, CONFIG_BOARD, + DT_PROP(DT_CHOSEN(zephyr_code_partition), label)); +} diff --git a/samples/runtime-source/zephyr/hooks/CMakeLists.txt b/samples/runtime-source/zephyr/hooks/CMakeLists.txt new file mode 100644 index 0000000000..d7d05669b6 --- /dev/null +++ b/samples/runtime-source/zephyr/hooks/CMakeLists.txt @@ -0,0 +1,3 @@ +zephyr_library() +zephyr_library_sources(hooks.c) +zephyr_library_link_libraries(MCUBOOT_BOOTUTIL) diff --git a/samples/runtime-source/zephyr/hooks/hooks.c b/samples/runtime-source/zephyr/hooks/hooks.c new file mode 100644 index 0000000000..849ce80141 --- /dev/null +++ b/samples/runtime-source/zephyr/hooks/hooks.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2024 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "bootutil/bootutil.h" +#include "bootutil/bootutil_public.h" +#include "bootutil/fault_injection_hardening.h" + +#define BOOT_TMPBUF_SZ 256 + +static struct image_header _hdr; +static uint8_t tmpbuf[BOOT_TMPBUF_SZ]; + +static uint8_t known_ids[] = { + FIXED_PARTITION_ID(slot0_partition), + FIXED_PARTITION_ID(slot1_partition), +}; + +static int current_id; + +#define SW1_NODE DT_ALIAS(sw1) +#if DT_NODE_HAS_STATUS(SW1_NODE, okay) +static struct gpio_dt_spec sw1_spec = GPIO_DT_SPEC_GET(SW1_NODE, gpios); +#endif + +fih_ret boot_go_hook(struct boot_rsp *rsp) +{ + int rc; +#ifdef MCUBOOT_RAM_LOAD + struct boot_loader_state *state; +#endif + FIH_DECLARE(fih_rc, FIH_FAILURE); + const struct flash_area *_fa_p; + + current_id = 0; + +#if DT_NODE_HAS_STATUS(SW1_NODE, okay) + if (gpio_pin_configure_dt(&sw1_spec, GPIO_INPUT) == 0) { + if (gpio_pin_get_dt(&sw1_spec) == 1) { + current_id = ARRAY_SIZE(known_ids) - 1; + printk("%s pressed, forcing boot from partition %u\n", + sw1_spec.port->name, known_ids[current_id]); + } else { + printk("%s not pressed, looping partitions to boot\n", + sw1_spec.port->name); + } + } +#else + printk("SW1 not defined, looping partitions to boot\n"); +#endif + + for ( ; current_id < ARRAY_SIZE(known_ids); current_id++) { + printk("Trying to boot from fixed partition %u\n", + known_ids[current_id]); + + rc = flash_area_open(known_ids[current_id], &_fa_p); + if (rc != 0) { + continue; + } + + rc = boot_image_load_header(_fa_p, &_hdr); + if (rc != 0) { + flash_area_close(_fa_p); + continue; + } + +#ifdef MCUBOOT_RAM_LOAD + state = boot_get_loader_state(); + + rc = boot_load_image_from_flash_to_sram(state, &_hdr); + if (rc != 0) { + flash_area_close(_fa_p); + continue; + } +#endif + + FIH_CALL(bootutil_img_validate, fih_rc, NULL, &_hdr, _fa_p, tmpbuf, + BOOT_TMPBUF_SZ, NULL, 0, NULL); + if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) { + flash_area_close(_fa_p); +#ifdef MCUBOOT_RAM_LOAD + boot_remove_image_from_sram(state); +#endif + continue; + } + + rsp->br_flash_dev_id = flash_area_get_device_id(_fa_p); + rsp->br_image_off = flash_area_get_off(_fa_p); + rsp->br_hdr = &_hdr; + + flash_area_close(_fa_p); + break; + } + + FIH_RET(fih_rc); +} + +int flash_area_id_from_multi_image_slot_hook(int image_index, int slot, + int *area_id) +{ + *area_id = known_ids[current_id]; + + return 0; +} + +int flash_area_get_device_id_hook(const struct flash_area *fa, uint8_t *dev_id) +{ + return BOOT_HOOK_REGULAR; +} diff --git a/samples/runtime-source/zephyr/hooks/zephyr/module.yml b/samples/runtime-source/zephyr/hooks/zephyr/module.yml new file mode 100644 index 0000000000..2beee397ca --- /dev/null +++ b/samples/runtime-source/zephyr/hooks/zephyr/module.yml @@ -0,0 +1,3 @@ +name: testmod +build: + cmake: . diff --git a/samples/runtime-source/zephyr/sample.conf b/samples/runtime-source/zephyr/sample.conf new file mode 100644 index 0000000000..fc9764ae06 --- /dev/null +++ b/samples/runtime-source/zephyr/sample.conf @@ -0,0 +1,8 @@ +CONFIG_FLASH_RUNTIME_SOURCES=y +CONFIG_SINGLE_APPLICATION_SLOT=y +CONFIG_BOOT_SIGNATURE_TYPE_RSA=y +CONFIG_TEST_RANDOM_GENERATOR=y +CONFIG_ENTROPY_GENERATOR=y + +CONFIG_BOOT_GO_HOOKS=y +CONFIG_BOOT_FLASH_AREA_HOOKS=y