From 7b27fa6d5a75251f98f0810135738216ac040bbc Mon Sep 17 00:00:00 2001 From: Christopher Collins Date: Wed, 17 Jan 2018 17:40:36 -0800 Subject: [PATCH] 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 --- include/dfu/mcuboot.h | 23 ++++++ subsys/dfu/boot/mcuboot.c | 152 +++++++++++++++++++++++++++++++++++++- 2 files changed, 173 insertions(+), 2 deletions(-) diff --git a/include/dfu/mcuboot.h b/include/dfu/mcuboot.h index 301d7d9e092..27df47a83fb 100644 --- a/include/dfu/mcuboot.h +++ b/include/dfu/mcuboot.h @@ -13,6 +13,21 @@ #include +/** 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 * @@ -122,6 +137,14 @@ bool boot_is_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 * will perform a boot of the slot 1 image. diff --git a/subsys/dfu/boot/mcuboot.c b/subsys/dfu/boot/mcuboot.c index 8cb39861ef1..73249e8db85 100644 --- a/subsys/dfu/boot/mcuboot.c +++ b/subsys/dfu/boot/mcuboot.c @@ -5,6 +5,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include #include #include @@ -82,13 +83,87 @@ struct mcuboot_v1_raw_header { BOOT_MAX_ALIGN) #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, 0x7fefd260, 0x0f505235, 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 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) { 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); } +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) { u32_t offs; @@ -265,6 +344,75 @@ int boot_read_bank_header(u32_t bank_offset, 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 rc;