Skip to content

Commit

Permalink
bootutil: Provide boot_set_next function
Browse files Browse the repository at this point in the history
Commit provides boot_set_next function that allows to set next
application slot to boot by flash area object pointer, describing
the slot.
The function also takes active which is supposed to indicate whether
running application is being set for next boot and confirm parameter
that allows to confirm the image.

Signed-off-by: Dominik Ermel <dominik.ermel@nordicsemi.no>
  • Loading branch information
de-nordic authored and nvlsianpu committed Apr 14, 2023
1 parent 6902abb commit 918da26
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 77 deletions.
28 changes: 28 additions & 0 deletions boot/bootutil/include/bootutil/bootutil_public.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#define H_BOOTUTIL_PUBLIC

#include <inttypes.h>
#include <stdbool.h>
#include <string.h>
#include <flash_map_backend/flash_map_backend.h>
#include <mcuboot_config/mcuboot_config.h>
Expand Down Expand Up @@ -266,6 +267,33 @@ int
boot_read_swap_state(const struct flash_area *fa,
struct boot_swap_state *state);

/**
* @brief Set next image application slot by flash area pointer
*
* @param fa pointer to flash_area representing image to set for next boot;
* @param active should be true if @fa points to currently running image
* slot, false otherwise;
* @param confirm confirms image; when @p active is true, this is considered
* true, regardless of passed value.
*
* It is users responsibility to identify whether @p fa provided as parameter
* is currently running/active image and provide proper value to @p active.
* Failing to do so may render device non-upgradeable.
*
* Note that in multi-image setup running/active application is the one
* that is currently being executed by any MCU core, from the pair of
* slots dedicated to that MCU core. As confirming application currently
* running on a given slot should be, preferably, done after functional
* tests prove application to function correctly, it may not be a good idea
* to cross-confirm running images.
* An application should only confirm slots designated to MCU core it is
* running on.
*
* @return 0 on success; non-zero error code on failure.
*/
int
boot_set_next(const struct flash_area *fa, bool active, bool confirm);

#ifdef __cplusplus
}
#endif
Expand Down
151 changes: 74 additions & 77 deletions boot/bootutil/src/bootutil_public.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* Copyright (c) 2017-2019 Linaro LTD
* Copyright (c) 2016-2019 JUUL Labs
* Copyright (c) 2019-2021 Arm Limited
* Copyright (c) 2020 Nordic Semiconductor ASA
* Copyright (c) 2020-2023 Nordic Semiconductor ASA
*
* Original license:
*
Expand Down Expand Up @@ -458,6 +458,77 @@ boot_swap_type_multi(int image_index)
return BOOT_SWAP_TYPE_NONE;
}

int
boot_set_next(const struct flash_area *fa, bool active, bool confirm)
{
struct boot_swap_state slot_state;
int rc;

if (active) {
confirm = true;
}

rc = boot_read_swap_state(fa, &slot_state);
if (rc != 0) {
return rc;
}

switch (slot_state.magic) {
case BOOT_MAGIC_GOOD:
/* If non-active then swap already scheduled, else confirm needed.*/

if (active && slot_state.image_ok == BOOT_FLAG_UNSET) {
/* Intentionally do not check copy_done flag to be able to
* confirm a padded image which has been programmed using
* a programming interface.
*/
rc = boot_write_image_ok(fa);
}

break;

case BOOT_MAGIC_UNSET:
if (!active) {
rc = boot_write_magic(fa);

if (rc == 0 && confirm) {
rc = boot_write_image_ok(fa);
}

if (rc == 0) {
uint8_t swap_type;

if (confirm) {
swap_type = BOOT_SWAP_TYPE_PERM;
} else {
swap_type = BOOT_SWAP_TYPE_TEST;
}
rc = boot_write_swap_info(fa, swap_type, 0);
}
}
break;

case BOOT_MAGIC_BAD:
if (active) {
rc = BOOT_EBADVECT;
} else {
/* The image slot is corrupt. There is no way to recover, so erase the
* slot to allow future upgrades.
*/
flash_area_erase(fa, 0, flash_area_get_size(fa));
rc = BOOT_EBADIMAGE;
}
break;

default:
/* Something is not OK, this should never happen */
assert(0);
rc = BOOT_EBADIMAGE;
}

return rc;
}

/*
* This function is not used by the bootloader itself, but its required API
* by external tooling like mcumgr.
Expand Down Expand Up @@ -486,57 +557,15 @@ 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);
}
rc = boot_set_next(fap, false, !(permanent == 0));

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;
}
Expand Down Expand Up @@ -573,47 +602,15 @@ 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);
rc = boot_set_next(fap, true, true);

done:
flash_area_close(fap);
return rc;
}
Expand Down

0 comments on commit 918da26

Please sign in to comment.