Commit 918da26a authored by Dominik Ermel's avatar Dominik Ermel Committed by Andrzej Puzdrowski
Browse files

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: default avatarDominik Ermel <dominik.ermel@nordicsemi.no>
parent 6902abba
Loading
Loading
Loading
Loading
+28 −0
Original line number Diff line number Diff line
@@ -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 @@ 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
+74 −77
Original line number Diff line number Diff line
@@ -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,85 +458,114 @@ boot_swap_type_multi(int image_index)
    return BOOT_SWAP_TYPE_NONE;
}

/*
 * This function is not used by the bootloader itself, but its required API
 * by external tooling like mcumgr.
 */
int
boot_swap_type(void)
{
    return boot_swap_type_multi(0);
}

/**
 * Marks the image with the given index in the secondary slot as pending. On the
 * next reboot, the system will perform a one-time boot of the the secondary
 * slot image.
 *
 * @param image_index       Image pair index.
 *
 * @param permanent         Whether the image should be used permanently or
 *                          only tested once:
 *                               0=run image once, then confirm or revert.
 *                               1=run image forever.
 *
 * @return                  0 on success; nonzero on failure.
 */
int
boot_set_pending_multi(int image_index, int permanent)
boot_set_next(const struct flash_area *fa, bool active, bool confirm)
{
    const struct flash_area *fap;
    struct boot_swap_state state_secondary_slot;
    uint8_t swap_type;
    struct boot_swap_state slot_state;
    int rc;

    rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY(image_index), &fap);
    if (rc != 0) {
        return BOOT_EFLASH;
    if (active) {
        confirm = true;
    }

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

    switch (state_secondary_slot.magic) {
    switch (slot_state.magic) {
    case BOOT_MAGIC_GOOD:
        /* Swap already scheduled. */
        /* 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:
        rc = boot_write_magic(fap);
        if (!active) {
            rc = boot_write_magic(fa);

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

            if (rc == 0) {
            if (permanent) {
                uint8_t swap_type;

                if (confirm) {
                    swap_type = BOOT_SWAP_TYPE_PERM;
                } else {
                    swap_type = BOOT_SWAP_TYPE_TEST;
                }
            rc = boot_write_swap_info(fap, swap_type, 0);
                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(fap, 0, flash_area_get_size(fap));
            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;
    }

done:
    return rc;
}

/*
 * This function is not used by the bootloader itself, but its required API
 * by external tooling like mcumgr.
 */
int
boot_swap_type(void)
{
    return boot_swap_type_multi(0);
}

/**
 * Marks the image with the given index in the secondary slot as pending. On the
 * next reboot, the system will perform a one-time boot of the the secondary
 * slot image.
 *
 * @param image_index       Image pair index.
 *
 * @param permanent         Whether the image should be used permanently or
 *                          only tested once:
 *                               0=run image once, then confirm or revert.
 *                               1=run image forever.
 *
 * @return                  0 on success; nonzero on failure.
 */
int
boot_set_pending_multi(int image_index, int permanent)
{
    const struct flash_area *fap;
    int rc;

    rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY(image_index), &fap);
    if (rc != 0) {
        return BOOT_EFLASH;
    }

    rc = boot_set_next(fap, false, !(permanent == 0));

    flash_area_close(fap);
    return rc;
}
@@ -573,7 +602,6 @@ 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);
@@ -581,39 +609,8 @@ boot_set_confirmed_multi(int image_index)
        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;
}