Skip to content

Commit

Permalink
samples: Add a sample for runtime chosen image
Browse files Browse the repository at this point in the history
A sample for runtime chose image on FRDM K64F. It provides implementation
for boot_go and flash area id related hooks, showing how an external
module implementing hooks can influence which images end up being booted
on the platform.

In this sample, one can influence from which slot image will be loaded
by pressing a button on the board.

For more details on how to build and test the samples, check the
provided README.md.

Signed-off-by: Ederson de Souza <[email protected]>
Signed-off-by: Tom Burdick <[email protected]>
  • Loading branch information
edersondisouza committed Dec 23, 2024
1 parent 6bf8a0b commit a6a911c
Show file tree
Hide file tree
Showing 9 changed files with 222 additions and 0 deletions.
55 changes: 55 additions & 0 deletions samples/runtime-source/zephyr/README.md
Original file line number Diff line number Diff line change
@@ -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 <path-to-zephyr>/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.
14 changes: 14 additions & 0 deletions samples/runtime-source/zephyr/app/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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)
5 changes: 5 additions & 0 deletions samples/runtime-source/zephyr/app/boards/frdm_k64f.overlay
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/ {
chosen {
zephyr,code-partition = &slot1_partition;
};
};
3 changes: 3 additions & 0 deletions samples/runtime-source/zephyr/app/prj.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
CONFIG_BOOTLOADER_MCUBOOT=y

CONFIG_MCUBOOT_SIGNATURE_KEY_FILE="./bootloader/mcuboot/root-rsa-2048.pem"
15 changes: 15 additions & 0 deletions samples/runtime-source/zephyr/app/src/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* Copyright (c) 2017 Linaro, Ltd.
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>

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));
}
3 changes: 3 additions & 0 deletions samples/runtime-source/zephyr/hooks/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
zephyr_library()
zephyr_library_sources(hooks.c)
zephyr_library_link_libraries(MCUBOOT_BOOTUTIL)
116 changes: 116 additions & 0 deletions samples/runtime-source/zephyr/hooks/hooks.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/*
* Copyright (c) 2024 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <zephyr/drivers/gpio.h>
#include <zephyr/kernel.h>

#include "bootutil/bootutil.h"
#include "bootutil/bootutil_public.h"
#include "bootutil/fault_injection_hardening.h"

#define BOOT_TMPBUF_SZ 256

static const struct flash_area *_fa_p;
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);

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, 0, &_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)
{
*dev_id = fa->fa_id;

return 0;
}
3 changes: 3 additions & 0 deletions samples/runtime-source/zephyr/hooks/zephyr/module.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
name: testmod
build:
cmake: .
8 changes: 8 additions & 0 deletions samples/runtime-source/zephyr/sample.conf
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit a6a911c

Please sign in to comment.