bootutil: Provide boot_set_next function
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>
diff --git a/boot/bootutil/include/bootutil/bootutil_public.h b/boot/bootutil/include/bootutil/bootutil_public.h
index a2bf9b2..90b1a1c 100644
--- a/boot/bootutil/include/bootutil/bootutil_public.h
+++ b/boot/bootutil/include/bootutil/bootutil_public.h
@@ -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>
@@ -266,6 +267,33 @@
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
diff --git a/boot/bootutil/src/bootutil_public.c b/boot/bootutil/src/bootutil_public.c
index e26cc09..464ebd9 100644
--- a/boot/bootutil/src/bootutil_public.c
+++ b/boot/bootutil/src/bootutil_public.c
@@ -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:
*
@@ -458,6 +458,77 @@
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.
@@ -486,8 +557,6 @@
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);
@@ -495,48 +564,8 @@
return BOOT_EFLASH;
}
- rc = boot_read_swap_state(fap, &state_secondary_slot);
- if (rc != 0) {
- goto done;
- }
+ rc = boot_set_next(fap, false, !(permanent == 0));
- 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);
- }
-
- 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;
}
@@ -573,7 +602,6 @@
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);
@@ -581,39 +609,8 @@
return BOOT_EFLASH;
}
- rc = boot_read_swap_state(fap, &state_primary_slot);
- if (rc != 0) {
- goto done;
- }
+ rc = boot_set_next(fap, true, true);
- 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);
-
-done:
flash_area_close(fap);
return rc;
}