Skip to content

Commit

Permalink
boot/zephyr: Support for loading images from arbitrary flash slots
Browse files Browse the repository at this point in the history
Instead of normal MCUboot flow, that checks flash slots to find update
images, this patch enables an MCUboot application to chose from which
available slots to load an image.

This allows an application, for instance, to check hardware
configuration at runtime (by checking hardware straps, state of GPIOs,
etc) and decide from where to load an image to boot.

MCUboot will basically loop through provided image sources (flash slots)
and boot the first one that succed signature/validation. To provide the
image sources, the application need to provide strong implementation for
functions flash_map_id_get_next() and flash_map_id_get_current(). The
default, weak, implementations just keep current behaviour for single
loader, i.e. just load from FLASH_AREA_IMAGE_PRIMARY(0).

Note that in this case, MCUboot won't try to record if image succeeded
boot, it will only boot the image provided.

Signed-off-by: Ederson de Souza <[email protected]>
  • Loading branch information
edersondisouza committed Sep 11, 2024
1 parent 63b0dfe commit 50cfb16
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 24 deletions.
12 changes: 12 additions & 0 deletions boot/zephyr/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,18 @@ 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"
select 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. The application must provide `flash_map_id_get_next`
and `flash_map_id_get_next` functions to tell mcuboot where to find
the images.

config BOOT_ENCRYPTION_SUPPORT
bool
help
Expand Down
11 changes: 10 additions & 1 deletion boot/zephyr/flash_map_extended.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,15 @@ int flash_device_base(uint8_t fd_id, uintptr_t *ret)
*/
int flash_area_id_from_multi_image_slot(int image_index, int slot)
{
#if defined(CONFIG_FLASH_RUNTIME_SOURCES)
uint8_t id;

if (flash_map_id_get_current(&id)) {
return id;
}
return -1;
#endif

switch (slot) {
case 0: return FLASH_AREA_IMAGE_PRIMARY(image_index);
#if !defined(CONFIG_SINGLE_APPLICATION_SLOT)
Expand Down Expand Up @@ -141,7 +150,7 @@ 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)
{
#if defined(CONFIG_ARM)
#if defined(CONFIG_ARM) || defined(CONFIG_FLASH_RUNTIME_SOURCES)
return fa->fa_id;
#else
(void)fa;
Expand Down
46 changes: 46 additions & 0 deletions boot/zephyr/include/flash_runtime_sources.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright (c) 2024 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef __FLASH_RUNTIME_SOURCES_H__
#define __FLASH_RUNTIME_SOURCES_H__

#include <inttypes.h>

#ifdef __cplusplus
extern "C" {
#endif

/*
* Get next flash map id.
*
* Implement this function to get the next flash map id. The function should
* return true if the flash map id was successfully updated. If the reset
* parameter is true, the function should reset the flash map id to the first
* one.
*
* @param id Pointer to the flash map id.
* @param reset If true, the function will reset the flash map id to the first
* one.
* @retval true If the flash map id was successfully updated.
*/
bool flash_map_id_get_next(uint8_t *id, bool reset);

/*
* Get current flash map id.
*
* Implement this function to get the current flash map id. The function should
* return true if the flash map id was successfully read.
*
* @param id Pointer to the flash map id.
* @retval true If the flash map id was successfully read.
*/
bool flash_map_id_get_current(uint8_t *id);

#ifdef __cplusplus
}
#endif

#endif /* __FLASH_RUNTIME_SOURCES_H__ */
85 changes: 62 additions & 23 deletions boot/zephyr/single_loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,30 @@ BOOT_LOG_MODULE_DECLARE(mcuboot);
static const struct flash_area *_fa_p;
static struct image_header _hdr = { 0 };

__weak bool
flash_map_id_get_next(uint8_t *id, bool reset)
{
if (!reset || !id) {
return false;
}

*id = FLASH_AREA_IMAGE_PRIMARY(0);

return true;
}

__weak bool
flash_map_id_get_current(uint8_t *id)
{
if (!id) {
return false;
}

*id = FLASH_AREA_IMAGE_PRIMARY(0);

return true;
}

#if defined(MCUBOOT_VALIDATE_PRIMARY_SLOT) || defined(MCUBOOT_VALIDATE_PRIMARY_SLOT_ONCE)
/**
* Validate hash of a primary boot image.
Expand Down Expand Up @@ -102,50 +126,65 @@ fih_ret
boot_go(struct boot_rsp *rsp)
{
int rc = -1;
uint8_t flash_id;
bool reset = true;
FIH_DECLARE(fih_rc, FIH_FAILURE);

rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(0), &_fa_p);
assert(rc == 0);
while (flash_map_id_get_next(&flash_id, reset)) {
reset = false;
rc = flash_area_open(flash_id, &_fa_p);
if (rc != 0) {
continue;
}

rc = boot_image_load_header(_fa_p, &_hdr);
if (rc != 0)
goto out;
rc = boot_image_load_header(_fa_p, &_hdr);
if (rc != 0) {
flash_area_close(_fa_p);
continue;
}

#ifdef MCUBOOT_RAM_LOAD
static struct boot_loader_state state;
state.imgs[0][0].hdr = _hdr;

rc = boot_load_image_to_sram(&state);
if (rc != 0)
goto out;
if (rc != 0) {
flash_area_close(_fa_p);
continue;
}
#endif

#ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT
FIH_CALL(boot_image_validate, fih_rc, _fa_p, &_hdr);
if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
FIH_CALL(boot_image_validate, fih_rc, _fa_p, &_hdr);
if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
flash_area_close(_fa_p);
#ifdef MCUBOOT_RAM_LOAD
boot_remove_image_from_sram(&state);
boot_remove_image_from_sram(&state);
#endif
goto out;
}
continue;
}
#elif defined(MCUBOOT_VALIDATE_PRIMARY_SLOT_ONCE)
FIH_CALL(boot_image_validate_once, fih_rc, _fa_p, &_hdr);
if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
FIH_CALL(boot_image_validate_once, fih_rc, _fa_p, &_hdr);
if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
flash_area_close(_fa_p);
#ifdef MCUBOOT_RAM_LOAD
boot_remove_image_from_sram(&state);
boot_remove_image_from_sram(&state);
#endif
goto out;
}
continue;
}
#else
fih_rc = FIH_SUCCESS;
fih_rc = FIH_SUCCESS;
#endif /* MCUBOOT_VALIDATE_PRIMARY_SLOT */

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;
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;
}

out:
flash_area_close(_fa_p);

FIH_RET(fih_rc);
}

0 comments on commit 50cfb16

Please sign in to comment.