subsys: dfu: boot: Allow inspection of boot state.
Exposes the operation that MCUboot will perform on the next reboot (e.g., stay on current image, swap to alternate image, etc.). Signed-off-by: Christopher Collins <ccollins@apache.org>
This commit is contained in:
parent
41646dbeee
commit
7b27fa6d5a
2 changed files with 173 additions and 2 deletions
|
@ -13,6 +13,21 @@
|
||||||
|
|
||||||
#include <zephyr/types.h>
|
#include <zephyr/types.h>
|
||||||
|
|
||||||
|
/** Attempt to boot the contents of slot 0. */
|
||||||
|
#define BOOT_SWAP_TYPE_NONE 1
|
||||||
|
|
||||||
|
/** Swap to slot 1. Absent a confirm command, revert back on next boot. */
|
||||||
|
#define BOOT_SWAP_TYPE_TEST 2
|
||||||
|
|
||||||
|
/** Swap to slot 1, and permanently switch to booting its contents. */
|
||||||
|
#define BOOT_SWAP_TYPE_PERM 3
|
||||||
|
|
||||||
|
/** Swap back to alternate slot. A confirm changes this state to NONE. */
|
||||||
|
#define BOOT_SWAP_TYPE_REVERT 4
|
||||||
|
|
||||||
|
/** Swap failed because image to be run is not valid */
|
||||||
|
#define BOOT_SWAP_TYPE_FAIL 5
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief MCUboot image header representation for image version
|
* @brief MCUboot image header representation for image version
|
||||||
*
|
*
|
||||||
|
@ -122,6 +137,14 @@ bool boot_is_img_confirmed(void);
|
||||||
*/
|
*/
|
||||||
int boot_write_img_confirmed(void);
|
int boot_write_img_confirmed(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Determines the action, if any, that mcuboot will take on the next
|
||||||
|
* reboot.
|
||||||
|
* @return a BOOT_SWAP_TYPE_[...] constant on success, negative errno code on
|
||||||
|
* fail.
|
||||||
|
*/
|
||||||
|
int boot_swap_type(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Marks the image in slot 1 as pending. On the next reboot, the system
|
* @brief Marks the image in slot 1 as pending. On the next reboot, the system
|
||||||
* will perform a boot of the slot 1 image.
|
* will perform a boot of the slot 1 image.
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -82,13 +83,87 @@ struct mcuboot_v1_raw_header {
|
||||||
BOOT_MAX_ALIGN)
|
BOOT_MAX_ALIGN)
|
||||||
#define MAGIC_OFFS(bank_offs) (bank_offs + FLASH_BANK_SIZE - BOOT_MAGIC_SZ)
|
#define MAGIC_OFFS(bank_offs) (bank_offs + FLASH_BANK_SIZE - BOOT_MAGIC_SZ)
|
||||||
|
|
||||||
const u32_t boot_img_magic[4] = {
|
static const u32_t boot_img_magic[4] = {
|
||||||
0xf395c277,
|
0xf395c277,
|
||||||
0x7fefd260,
|
0x7fefd260,
|
||||||
0x0f505235,
|
0x0f505235,
|
||||||
0x8079b62c,
|
0x8079b62c,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct boot_swap_table {
|
||||||
|
/** * For each field, a value of 0 means "any". */
|
||||||
|
u8_t magic_slot0;
|
||||||
|
u8_t magic_slot1;
|
||||||
|
u8_t image_ok_slot0;
|
||||||
|
u8_t image_ok_slot1;
|
||||||
|
u8_t copy_done_slot0;
|
||||||
|
|
||||||
|
u8_t swap_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Represents the management state of a single image slot. */
|
||||||
|
struct boot_swap_state {
|
||||||
|
u8_t magic; /* One of the BOOT_MAGIC_[...] values. */
|
||||||
|
u8_t copy_done;
|
||||||
|
u8_t image_ok;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This set of tables maps image trailer contents to swap operation type.
|
||||||
|
* When searching for a match, these tables must be iterated sequentially.
|
||||||
|
*/
|
||||||
|
static const struct boot_swap_table boot_swap_tables[] = {
|
||||||
|
{
|
||||||
|
/* | slot-0 | slot-1 |
|
||||||
|
*----------+------------+------------|
|
||||||
|
* magic | Any | Good |
|
||||||
|
* image-ok | Any | Unset |
|
||||||
|
* ---------+------------+------------+
|
||||||
|
* swap: test |
|
||||||
|
* -----------------------------------'
|
||||||
|
*/
|
||||||
|
.magic_slot0 = 0,
|
||||||
|
.magic_slot1 = BOOT_MAGIC_GOOD,
|
||||||
|
.image_ok_slot0 = 0,
|
||||||
|
.image_ok_slot1 = 0xff,
|
||||||
|
.copy_done_slot0 = 0,
|
||||||
|
.swap_type = BOOT_SWAP_TYPE_TEST,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
/* | slot-0 | slot-1 |
|
||||||
|
*----------+------------+------------|
|
||||||
|
* magic | Any | Good |
|
||||||
|
* image-ok | Any | 0x01 |
|
||||||
|
* ---------+------------+------------+
|
||||||
|
* swap: permanent |
|
||||||
|
* -----------------------------------'
|
||||||
|
*/
|
||||||
|
.magic_slot0 = 0,
|
||||||
|
.magic_slot1 = BOOT_MAGIC_GOOD,
|
||||||
|
.image_ok_slot0 = 0,
|
||||||
|
.image_ok_slot1 = 0x01,
|
||||||
|
.copy_done_slot0 = 0,
|
||||||
|
.swap_type = BOOT_SWAP_TYPE_PERM,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
/* | slot-0 | slot-1 |
|
||||||
|
*----------+------------+------------|
|
||||||
|
* magic | Good | Unset |
|
||||||
|
* image-ok | Unset | Any |
|
||||||
|
* ---------+------------+------------+
|
||||||
|
* swap: revert (test image running) |
|
||||||
|
* -----------------------------------'
|
||||||
|
*/
|
||||||
|
.magic_slot0 = BOOT_MAGIC_GOOD,
|
||||||
|
.magic_slot1 = BOOT_MAGIC_UNSET,
|
||||||
|
.image_ok_slot0 = 0xff,
|
||||||
|
.image_ok_slot1 = 0,
|
||||||
|
.copy_done_slot0 = 0x01,
|
||||||
|
.swap_type = BOOT_SWAP_TYPE_REVERT,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
#define BOOT_SWAP_TABLES_COUNT (ARRAY_SIZE(boot_swap_tables))
|
||||||
|
|
||||||
static struct device *flash_dev;
|
static struct device *flash_dev;
|
||||||
|
|
||||||
static int boot_flag_offs(int flag, u32_t bank_offs, u32_t *offs)
|
static int boot_flag_offs(int flag, u32_t bank_offs, u32_t *offs)
|
||||||
|
@ -105,7 +180,6 @@ static int boot_flag_offs(int flag, u32_t bank_offs, u32_t *offs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int boot_flash_write(off_t offs, const void *data, size_t len)
|
static int boot_flash_write(off_t offs, const void *data, size_t len)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
@ -173,6 +247,11 @@ static int boot_image_ok_write(u32_t bank_offs)
|
||||||
return boot_flag_write(BOOT_FLAG_IMAGE_OK, bank_offs);
|
return boot_flag_write(BOOT_FLAG_IMAGE_OK, bank_offs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int boot_copy_done_read(u32_t bank_offs)
|
||||||
|
{
|
||||||
|
return boot_flag_read(BOOT_FLAG_COPY_DONE, bank_offs);
|
||||||
|
}
|
||||||
|
|
||||||
static int boot_magic_write(u32_t bank_offs)
|
static int boot_magic_write(u32_t bank_offs)
|
||||||
{
|
{
|
||||||
u32_t offs;
|
u32_t offs;
|
||||||
|
@ -265,6 +344,75 @@ int boot_read_bank_header(u32_t bank_offset,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int boot_read_swap_state(u32_t bank_offs, struct boot_swap_state *state)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = boot_magic_state_read(bank_offs);
|
||||||
|
if (rc < 0) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
state->magic = rc;
|
||||||
|
|
||||||
|
if (bank_offs != FLASH_AREA_IMAGE_SCRATCH_OFFSET) {
|
||||||
|
rc = boot_copy_done_read(bank_offs);
|
||||||
|
if (rc < 0) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
state->copy_done = rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = boot_image_ok_read(bank_offs);
|
||||||
|
if (rc < 0) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
state->image_ok = rc;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int boot_swap_type(void)
|
||||||
|
{
|
||||||
|
const struct boot_swap_table *table;
|
||||||
|
struct boot_swap_state state_slot0;
|
||||||
|
struct boot_swap_state state_slot1;
|
||||||
|
int rc;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
rc = boot_read_swap_state(FLASH_BANK0_OFFSET, &state_slot0);
|
||||||
|
if (rc != 0) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = boot_read_swap_state(FLASH_BANK1_OFFSET, &state_slot1);
|
||||||
|
if (rc != 0) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < BOOT_SWAP_TABLES_COUNT; i++) {
|
||||||
|
table = boot_swap_tables + i;
|
||||||
|
|
||||||
|
if ((table->magic_slot0 == 0 ||
|
||||||
|
table->magic_slot0 == state_slot0.magic) &&
|
||||||
|
(table->magic_slot1 == 0 ||
|
||||||
|
table->magic_slot1 == state_slot1.magic) &&
|
||||||
|
(table->image_ok_slot0 == 0 ||
|
||||||
|
table->image_ok_slot0 == state_slot0.image_ok) &&
|
||||||
|
(table->image_ok_slot1 == 0 ||
|
||||||
|
table->image_ok_slot1 == state_slot1.image_ok) &&
|
||||||
|
(table->copy_done_slot0 == 0 ||
|
||||||
|
table->copy_done_slot0 == state_slot0.copy_done)) {
|
||||||
|
|
||||||
|
assert(table->swap_type == BOOT_SWAP_TYPE_TEST ||
|
||||||
|
table->swap_type == BOOT_SWAP_TYPE_PERM ||
|
||||||
|
table->swap_type == BOOT_SWAP_TYPE_REVERT);
|
||||||
|
return table->swap_type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return BOOT_SWAP_TYPE_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
int boot_request_upgrade(int permanent)
|
int boot_request_upgrade(int permanent)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue