Boot: Sync MCUBoot code base
This patch performs a partial synchronization between the MCUBoot files
in TF-M and in the original repository. The hash of the source commit
in the original MCUBoot repo: 3c469bc698a9767859ed73cd0201c44161204d5c.
Change-Id: I244b47f21ebdfc73381accc007ee88737f7ccdf7
Signed-off-by: David Vincze <david.vincze@arm.com>
diff --git a/bl2/ext/mcuboot/bootutil/include/bootutil/bootutil.h b/bl2/ext/mcuboot/bootutil/include/bootutil/bootutil.h
index b674823..33a6634 100644
--- a/bl2/ext/mcuboot/bootutil/include/bootutil/bootutil.h
+++ b/bl2/ext/mcuboot/bootutil/include/bootutil/bootutil.h
@@ -74,10 +74,12 @@
* when attempting to read/write a trailer.
*/
struct image_trailer {
- uint8_t copy_done;
+ uint8_t swap_type;
uint8_t pad1[MAX_FLASH_ALIGN - 1];
- uint8_t image_ok;
+ uint8_t copy_done;
uint8_t pad2[MAX_FLASH_ALIGN - 1];
+ uint8_t image_ok;
+ uint8_t pad3[MAX_FLASH_ALIGN - 1];
uint8_t magic[16];
};
diff --git a/bl2/ext/mcuboot/bootutil/include/bootutil/image.h b/bl2/ext/mcuboot/bootutil/include/bootutil/image.h
index b9954f0..d9eb5320 100644
--- a/bl2/ext/mcuboot/bootutil/include/bootutil/image.h
+++ b/bl2/ext/mcuboot/bootutil/include/bootutil/image.h
@@ -20,7 +20,7 @@
/*
* Original code taken from mcuboot project at:
* https://github.com/JuulLabs-OSS/mcuboot
- * Git SHA of the original version: b5b59f16a5768c5175cf6c7ab082e84a5843f06f
+ * Git SHA of the original version: 3c469bc698a9767859ed73cd0201c44161204d5c
* Modifications are Copyright (c) 2018-2019 Arm Limited.
*/
diff --git a/bl2/ext/mcuboot/bootutil/src/bootutil_misc.c b/bl2/ext/mcuboot/bootutil/src/bootutil_misc.c
index b4c6ee7..5ad8bcf 100644
--- a/bl2/ext/mcuboot/bootutil/src/bootutil_misc.c
+++ b/bl2/ext/mcuboot/bootutil/src/bootutil_misc.c
@@ -112,27 +112,45 @@
return BOOT_FLAG_SET;
}
+/**
+ * Determines if a status source table is satisfied by the specified magic
+ * code.
+ *
+ * @param tbl_val A magic field from a status source table.
+ * @param val The magic value in a trailer, encoded as a
+ * BOOT_MAGIC_[...].
+ *
+ * @return 1 if the two values are compatible;
+ * 0 otherwise.
+ */
+int
+boot_magic_compatible_check(uint8_t tbl_val, uint8_t val)
+{
+ switch (tbl_val) {
+ case BOOT_MAGIC_ANY:
+ return 1;
+
+ case BOOT_MAGIC_NOTGOOD:
+ return val != BOOT_MAGIC_GOOD;
+
+ default:
+ return tbl_val == val;
+ }
+}
+
uint32_t
-boot_slots_trailer_sz(uint8_t min_write_sz)
+boot_trailer_sz(uint8_t min_write_sz)
{
return /* state for all sectors */
BOOT_STATUS_MAX_ENTRIES * BOOT_STATUS_STATE_COUNT * min_write_sz +
- BOOT_MAX_ALIGN * 3 /* copy_done + image_ok + swap_size */ +
- BOOT_MAGIC_SZ;
-}
-
-static uint32_t
-boot_scratch_trailer_sz(uint8_t min_write_sz)
-{
- return BOOT_STATUS_STATE_COUNT * min_write_sz + /* state for one sector */
- BOOT_MAX_ALIGN * 2 + /* image_ok + swap_size */
+ /* swap_type + copy_done + image_ok + swap_size */
+ BOOT_MAX_ALIGN * 4 +
BOOT_MAGIC_SZ;
}
static uint32_t
boot_magic_off(const struct flash_area *fap)
{
- assert(offsetof(struct image_trailer, magic) == 16);
return fap->fa_size - BOOT_MAGIC_SZ;
}
@@ -158,43 +176,34 @@
elem_sz = flash_area_align(fap);
- if (fap->fa_id == FLASH_AREA_IMAGE_SCRATCH) {
- off_from_end = boot_scratch_trailer_sz(elem_sz);
- } else {
- off_from_end = boot_slots_trailer_sz(elem_sz);
- }
+ off_from_end = boot_trailer_sz(elem_sz);
assert(off_from_end <= fap->fa_size);
return fap->fa_size - off_from_end;
}
+uint32_t
+boot_swap_type_off(const struct flash_area *fap)
+{
+ return fap->fa_size - BOOT_MAGIC_SZ - BOOT_MAX_ALIGN * 3;
+}
+
static uint32_t
boot_copy_done_off(const struct flash_area *fap)
{
- assert(fap->fa_id != FLASH_AREA_IMAGE_SCRATCH);
- assert(offsetof(struct image_trailer, copy_done) == 0);
return fap->fa_size - BOOT_MAGIC_SZ - BOOT_MAX_ALIGN * 2;
}
static uint32_t
boot_image_ok_off(const struct flash_area *fap)
{
- assert(offsetof(struct image_trailer, image_ok) == 8);
return fap->fa_size - BOOT_MAGIC_SZ - BOOT_MAX_ALIGN;
}
static uint32_t
boot_swap_size_off(const struct flash_area *fap)
{
- /*
- * The "swap_size" field if located just before the trailer.
- * The scratch slot doesn't store "copy_done"...
- */
- if (fap->fa_id == FLASH_AREA_IMAGE_SCRATCH) {
- return fap->fa_size - BOOT_MAGIC_SZ - BOOT_MAX_ALIGN * 2;
- }
-
- return fap->fa_size - BOOT_MAGIC_SZ - BOOT_MAX_ALIGN * 3;
+ return fap->fa_size - BOOT_MAGIC_SZ - BOOT_MAX_ALIGN * 4;
}
int
@@ -216,22 +225,31 @@
state->magic = boot_magic_decode(magic);
}
- if (fap->fa_id != FLASH_AREA_IMAGE_SCRATCH) {
- off = boot_copy_done_off(fap);
- rc = flash_area_read_is_empty(fap, off, &state->copy_done,
- sizeof state->copy_done);
- if (rc < 0) {
- return BOOT_EFLASH;
- }
- if (rc == 1) {
- state->copy_done = BOOT_FLAG_UNSET;
- } else {
- state->copy_done = boot_flag_decode(state->copy_done);
- }
+ off = boot_swap_type_off(fap);
+ rc = flash_area_read_is_empty(fap, off, &state->swap_type,
+ sizeof state->swap_type);
+ if (rc < 0) {
+ return BOOT_EFLASH;
+ }
+ if (rc == 1 || state->swap_type > BOOT_SWAP_TYPE_REVERT) {
+ state->swap_type = BOOT_SWAP_TYPE_NONE;
+ }
+
+ off = boot_copy_done_off(fap);
+ rc = flash_area_read_is_empty(fap, off, &state->copy_done,
+ sizeof state->copy_done);
+ if (rc < 0) {
+ return BOOT_EFLASH;
+ }
+ if (rc == 1) {
+ state->copy_done = BOOT_FLAG_UNSET;
+ } else {
+ state->copy_done = boot_flag_decode(state->copy_done);
}
off = boot_image_ok_off(fap);
- rc = flash_area_read_is_empty(fap, off, &state->image_ok, sizeof state->image_ok);
+ rc = flash_area_read_is_empty(fap, off, &state->image_ok,
+ sizeof state->image_ok);
if (rc < 0) {
return BOOT_EFLASH;
}
@@ -341,6 +359,8 @@
off = boot_magic_off(fap);
+ BOOT_LOG_DBG("writing magic; fa_id=%d off=0x%x (0x%x)",
+ fap->fa_id, off, fap->fa_off + off);
rc = flash_area_write(fap, off, boot_img_magic, BOOT_MAGIC_SZ);
if (rc != 0) {
return BOOT_EFLASH;
@@ -350,30 +370,19 @@
}
static int
-boot_write_flag(int flag, const struct flash_area *fap)
+boot_write_trailer_byte(const struct flash_area *fap, uint32_t off,
+ uint8_t val)
{
- uint32_t off;
- int rc;
uint8_t buf[BOOT_MAX_ALIGN];
uint8_t align;
uint8_t erased_val;
-
- switch (flag) {
- case BOOT_FLAG_COPY_DONE:
- off = boot_copy_done_off(fap);
- break;
- case BOOT_FLAG_IMAGE_OK:
- off = boot_image_ok_off(fap);
- break;
- default:
- return BOOT_EBADARGS;
- }
+ int rc;
align = flash_area_align(fap);
assert(align <= BOOT_MAX_ALIGN);
erased_val = flash_area_erased_val(fap);
memset(buf, erased_val, BOOT_MAX_ALIGN);
- buf[0] = BOOT_FLAG_SET;
+ buf[0] = val;
rc = flash_area_write(fap, off, buf, align);
if (rc != 0) {
@@ -386,13 +395,39 @@
int
boot_write_copy_done(const struct flash_area *fap)
{
- return boot_write_flag(BOOT_FLAG_COPY_DONE, fap);
+ uint32_t off;
+
+ off = boot_copy_done_off(fap);
+ BOOT_LOG_DBG("writing copy_done; fa_id=%d off=0x%x (0x%x)",
+ fap->fa_id, off, fap->fa_off + off);
+ return boot_write_trailer_byte(fap, off, BOOT_FLAG_SET);
}
int
boot_write_image_ok(const struct flash_area *fap)
{
- return boot_write_flag(BOOT_FLAG_IMAGE_OK, fap);
+ uint32_t off;
+
+ off = boot_image_ok_off(fap);
+ BOOT_LOG_DBG("writing image_ok; fa_id=%d off=0x%x (0x%x)",
+ fap->fa_id, off, fap->fa_off + off);
+ return boot_write_trailer_byte(fap, off, BOOT_FLAG_SET);
+}
+
+/**
+ * Writes the specified value to the `swap-type` field of an image trailer.
+ * This value is persisted so that the boot loader knows what swap operation to
+ * resume in case of an unexpected reset.
+ */
+int
+boot_write_swap_type(const struct flash_area *fap, uint8_t swap_type)
+{
+ uint32_t off;
+
+ off = boot_swap_type_off(fap);
+ BOOT_LOG_DBG("writing swap_type; fa_id=%d off=0x%x (0x%x), swap_type=0x%x",
+ fap->fa_id, off, fap->fa_off + off, swap_type);
+ return boot_write_trailer_byte(fap, off, swap_type);
}
int
@@ -414,6 +449,9 @@
memset(buf, erased_val, BOOT_MAX_ALIGN);
memcpy(buf, (uint8_t *)&swap_size, sizeof(swap_size));
+ BOOT_LOG_DBG("writing swap_size; fa_id=%d off=0x%x (0x%x)",
+ fap->fa_id, off, fap->fa_off + off);
+
rc = flash_area_write(fap, off, buf, align);
if (rc != 0) {
return BOOT_EFLASH;
@@ -445,10 +483,10 @@
for (i = 0; i < BOOT_SWAP_TABLES_COUNT; i++) {
table = boot_swap_tables + i;
- if ((table->magic_primary_slot == BOOT_MAGIC_ANY ||
- table->magic_primary_slot == primary_slot.magic) &&
- (table->magic_secondary_slot == BOOT_MAGIC_ANY ||
- table->magic_secondary_slot == secondary_slot.magic) &&
+ if (boot_magic_compatible_check(table->magic_primary_slot,
+ primary_slot.magic) &&
+ boot_magic_compatible_check(table->magic_secondary_slot,
+ secondary_slot.magic) &&
(table->image_ok_primary_slot == BOOT_FLAG_ANY ||
table->image_ok_primary_slot == primary_slot.image_ok) &&
(table->image_ok_secondary_slot == BOOT_FLAG_ANY ||
@@ -487,6 +525,7 @@
{
const struct flash_area *fap = NULL;
struct boot_swap_state state_secondary_slot;
+ uint8_t swap_type;
int rc;
rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SECONDARY,
@@ -512,13 +551,34 @@
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_type(fap, swap_type);
+ }
+
flash_area_close(fap);
return rc;
+ case BOOT_MAGIC_BAD:
+ /* The image slot is corrupt. There is no way to recover, so erase the
+ * slot to allow future upgrades.
+ */
+ rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY, &fap);
+ if (rc != 0) {
+ return BOOT_EFLASH;
+ }
+
+ flash_area_erase(fap, 0, fap->fa_size);
+ flash_area_close(fap);
+ return BOOT_EBADIMAGE;
+
default:
- /* XXX: Temporary assert. */
assert(0);
- return -1;
+ return BOOT_EBADIMAGE;
}
}
diff --git a/bl2/ext/mcuboot/bootutil/src/bootutil_priv.h b/bl2/ext/mcuboot/bootutil/src/bootutil_priv.h
index c8a1c8a..5d70e0c 100644
--- a/bl2/ext/mcuboot/bootutil/src/bootutil_priv.h
+++ b/bl2/ext/mcuboot/bootutil/src/bootutil_priv.h
@@ -20,7 +20,7 @@
/*
* Original code taken from mcuboot project at:
* https://github.com/JuulLabs-OSS/mcuboot
- * Git SHA of the original version: 178be54bd6e5f035cc60e98205535682acd26e64
+ * Git SHA of the original version: 3c469bc698a9767859ed73cd0201c44161204d5c
* Modifications are Copyright (c) 2018-2019 Arm Limited.
*/
@@ -28,6 +28,7 @@
#define H_BOOTUTIL_PRIV_
#include "flash_map/flash_map.h"
+#include "bootutil/bootutil.h"
#include "bootutil/image.h"
#include "flash_layout.h"
@@ -35,6 +36,12 @@
extern "C" {
#endif
+#ifdef MCUBOOT_HAVE_ASSERT_H
+#include "mcuboot_config/mcuboot_assert.h"
+#else
+#define ASSERT assert
+#endif
+
struct flash_area;
#define BOOT_EFLASH 1
@@ -55,6 +62,7 @@
uint32_t idx; /* Which area we're operating on */
uint8_t state; /* Which part of the swapping process are we at */
uint8_t use_scratch; /* Are status bytes ever written to scratch? */
+ uint8_t swap_type; /* The type of swap in effect */
uint32_t swap_size; /* Total size of swapped image */
};
@@ -62,6 +70,7 @@
#define BOOT_MAGIC_BAD 2
#define BOOT_MAGIC_UNSET 3
#define BOOT_MAGIC_ANY 4 /* NOTE: control only, not dependent on sector */
+#define BOOT_MAGIC_NOTGOOD 5 /* NOTE: control only, not dependent on sector */
/*
* NOTE: leave BOOT_FLAG_SET equal to one, this is written to flash!
@@ -80,31 +89,33 @@
/**
* End-of-image slot structure.
*
- * 0 1 2 3
- * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * ~ ~
- * ~ Swap status (variable, aligned) ~
- * ~ ~
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Swap size |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * ~ padding with erased val (MAX ALIGN - 4) ~
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Copy done | padding with erased val (MAX ALIGN - 1) ~
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Image OK | padding with erased val (MAX ALIGN - 1) ~
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * ~ MAGIC (16 octets) ~
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * ~ ~
+ * ~ Swap status (BOOT_MAX_IMG_SECTORS * min-write-size * 3) ~
+ * ~ ~
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Swap size (4 octets) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Swap type | 0xff padding (7 octets) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Copy done | 0xff padding (7 octets) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Image OK | 0xff padding (7 octets) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | MAGIC (16 octets) |
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
extern const uint32_t boot_img_magic[4];
struct boot_swap_state {
- uint8_t magic; /* One of the BOOT_MAGIC_[...] values. */
- uint8_t copy_done;
- uint8_t image_ok;
+ uint8_t magic; /* One of the BOOT_MAGIC_[...] values. */
+ uint8_t swap_type; /* One of the BOOT_SWAP_TYPE_[...] values. */
+ uint8_t copy_done; /* One of the BOOT_FLAG_[...] values. */
+ uint8_t image_ok; /* One of the BOOT_FLAG_[...] values. */
};
/*
@@ -131,9 +142,6 @@
#define BOOT_STATUS_SOURCE_SCRATCH 1
#define BOOT_STATUS_SOURCE_PRIMARY_SLOT 2
-#define BOOT_FLAG_IMAGE_OK 0
-#define BOOT_FLAG_COPY_DONE 1
-
extern const uint32_t BOOT_MAGIC_SZ;
/**
@@ -156,7 +164,11 @@
size_t num_sectors;
} imgs[BOOT_NUM_SLOTS];
- const struct flash_area *scratch_area;
+ struct {
+ const struct flash_area *area;
+ boot_sector_t *sectors;
+ size_t num_sectors;
+ } scratch;
uint8_t write_sz;
};
@@ -164,9 +176,11 @@
int bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig,
size_t slen, uint8_t key_id);
-uint32_t boot_slots_trailer_sz(uint8_t min_write_sz);
+int boot_magic_compatible_check(uint8_t tbl_val, uint8_t val);
+uint32_t boot_trailer_sz(uint8_t min_write_sz);
int boot_status_entries(const struct flash_area *fap);
uint32_t boot_status_off(const struct flash_area *fap);
+uint32_t boot_swap_type_off(const struct flash_area *fap);
int boot_read_swap_state(const struct flash_area *fap,
struct boot_swap_state *state);
int boot_read_swap_state_by_id(int flash_area_id,
@@ -176,6 +190,7 @@
int boot_schedule_test_swap(void);
int boot_write_copy_done(const struct flash_area *fap);
int boot_write_image_ok(const struct flash_area *fap);
+int boot_write_swap_type(const struct flash_area *fap, uint8_t swap_type);
int boot_write_swap_size(const struct flash_area *fap, uint32_t swap_size);
int boot_read_swap_size(uint32_t *swap_size);
@@ -185,7 +200,7 @@
/* These are macros so they can be used as lvalues. */
#define BOOT_IMG_AREA(state, slot) ((state)->imgs[(slot)].area)
-#define BOOT_SCRATCH_AREA(state) ((state)->scratch_area)
+#define BOOT_SCRATCH_AREA(state) ((state)->scratch.area)
#define BOOT_WRITE_SZ(state) ((state)->write_sz)
static inline struct image_header*
@@ -194,24 +209,18 @@
return &state->imgs[slot].hdr;
}
-static inline uint8_t
-boot_img_fa_device_id(struct boot_loader_state *state, size_t slot)
-{
- return state->imgs[slot].area->fa_device_id;
-}
-
-static inline uint8_t
-boot_scratch_fa_device_id(struct boot_loader_state *state)
-{
- return state->scratch_area->fa_device_id;
-}
-
static inline size_t
boot_img_num_sectors(struct boot_loader_state *state, size_t slot)
{
return state->imgs[slot].num_sectors;
}
+static inline size_t
+boot_scratch_num_sectors(struct boot_loader_state *state)
+{
+ return state->scratch.num_sectors;
+}
+
/*
* Offset of the slot from the beginning of the flash device.
*/
@@ -223,7 +232,7 @@
static inline size_t boot_scratch_area_size(struct boot_loader_state *state)
{
- return state->scratch_area->fa_size;
+ return BOOT_SCRATCH_AREA(state)->fa_size;
}
#ifndef MCUBOOT_USE_FLASH_AREA_GET_SECTORS
@@ -251,27 +260,29 @@
boot_initialize_area(struct boot_loader_state *state, int flash_area)
{
int num_sectors = BOOT_MAX_IMG_SECTORS;
- size_t slot;
int rc;
switch (flash_area) {
case FLASH_AREA_IMAGE_PRIMARY:
- slot = BOOT_PRIMARY_SLOT;
+ rc = flash_area_to_sectors(flash_area, &num_sectors,
+ state->imgs[BOOT_PRIMARY_SLOT].sectors);
+ state->imgs[BOOT_PRIMARY_SLOT].num_sectors = (size_t)num_sectors;
break;
case FLASH_AREA_IMAGE_SECONDARY:
- slot = BOOT_SECONDARY_SLOT;
+ rc = flash_area_to_sectors(flash_area, &num_sectors,
+ state->imgs[BOOT_SECONDARY_SLOT].sectors);
+ state->imgs[BOOT_SECONDARY_SLOT].num_sectors = (size_t)num_sectors;
+ break;
+ case FLASH_AREA_IMAGE_SCRATCH:
+ rc = flash_area_to_sectors(flash_area, &num_sectors,
+ state->scratch.sectors);
+ state->scratch.num_sectors = (size_t)num_sectors;
break;
default:
return BOOT_EFLASH;
}
- rc = flash_area_to_sectors(flash_area, &num_sectors,
- state->imgs[slot].sectors);
- if (rc != 0) {
- return rc;
- }
- state->imgs[slot].num_sectors = (size_t)num_sectors;
- return 0;
+ return rc;
}
#else /* defined(MCUBOOT_USE_FLASH_AREA_GET_SECTORS) */
@@ -310,6 +321,11 @@
out_sectors = state->imgs[BOOT_SECONDARY_SLOT].sectors;
out_num_sectors = &state->imgs[BOOT_SECONDARY_SLOT].num_sectors;
break;
+ case FLASH_AREA_IMAGE_SCRATCH:
+ num_sectors = BOOT_MAX_IMG_SECTORS;
+ out_sectors = state->scratch.sectors;
+ out_num_sectors = &state->scratch.num_sectors;
+ break;
default:
return -1;
}
diff --git a/bl2/ext/mcuboot/bootutil/src/image_rsa.c b/bl2/ext/mcuboot/bootutil/src/image_rsa.c
index a9f2393..22dc6e3 100644
--- a/bl2/ext/mcuboot/bootutil/src/image_rsa.c
+++ b/bl2/ext/mcuboot/bootutil/src/image_rsa.c
@@ -20,7 +20,7 @@
/*
* Original code taken from mcuboot project at:
* https://github.com/JuulLabs-OSS/mcuboot
- * Git SHA of the original version: 178be54bd6e5f035cc60e98205535682acd26e64
+ * Git SHA of the original version: 3c469bc698a9767859ed73cd0201c44161204d5c
* Modifications are Copyright (c) 2018-2019 Arm Limited.
*/
diff --git a/bl2/ext/mcuboot/bootutil/src/image_validate.c b/bl2/ext/mcuboot/bootutil/src/image_validate.c
index b329ea8..20a89ed 100644
--- a/bl2/ext/mcuboot/bootutil/src/image_validate.c
+++ b/bl2/ext/mcuboot/bootutil/src/image_validate.c
@@ -20,7 +20,7 @@
/*
* Original code taken from mcuboot project at:
* https://github.com/JuulLabs-OSS/mcuboot
- * Git SHA of the original version: 178be54bd6e5f035cc60e98205535682acd26e64
+ * Git SHA of the original version: 3c469bc698a9767859ed73cd0201c44161204d5c
* Modifications are Copyright (c) 2018-2019 Arm Limited.
*/
diff --git a/bl2/ext/mcuboot/bootutil/src/loader.c b/bl2/ext/mcuboot/bootutil/src/loader.c
index 9fe012a..3631018 100644
--- a/bl2/ext/mcuboot/bootutil/src/loader.c
+++ b/bl2/ext/mcuboot/bootutil/src/loader.c
@@ -20,7 +20,7 @@
/*
* Original code taken from mcuboot project at:
* https://github.com/JuulLabs-OSS/mcuboot
- * Git SHA of the original version: 178be54bd6e5f035cc60e98205535682acd26e64
+ * Git SHA of the original version: 3c469bc698a9767859ed73cd0201c44161204d5c
* Modifications are Copyright (c) 2018-2019 Arm Limited.
*/
@@ -59,7 +59,7 @@
} \
} while (0)
#else
-#define BOOT_STATUS_ASSERT(x) assert(x)
+#define BOOT_STATUS_ASSERT(x) ASSERT(x)
#endif
struct boot_status_table {
@@ -84,7 +84,7 @@
* ----------------------------------------'
*/
.bst_magic_primary_slot = BOOT_MAGIC_GOOD,
- .bst_magic_scratch = BOOT_MAGIC_ANY,
+ .bst_magic_scratch = BOOT_MAGIC_NOTGOOD,
.bst_copy_done_primary_slot = BOOT_FLAG_SET,
.bst_status_source = BOOT_STATUS_SOURCE_NONE,
},
@@ -99,7 +99,7 @@
* ----------------------------------------'
*/
.bst_magic_primary_slot = BOOT_MAGIC_GOOD,
- .bst_magic_scratch = BOOT_MAGIC_ANY,
+ .bst_magic_scratch = BOOT_MAGIC_NOTGOOD,
.bst_copy_done_primary_slot = BOOT_FLAG_UNSET,
.bst_status_source = BOOT_STATUS_SOURCE_PRIMARY_SLOT,
},
@@ -143,11 +143,13 @@
(sizeof(boot_status_tables) / sizeof(boot_status_tables[0]))
#define BOOT_LOG_SWAP_STATE(area, state) \
- BOOT_LOG_INF("%s: magic=%5s, copy_done=0x%x, image_ok=0x%x", \
+ BOOT_LOG_INF("%s: magic=%5s, swap_type=0x%x, copy_done=0x%x, " \
+ "image_ok=0x%x", \
(area), \
((state)->magic == BOOT_MAGIC_GOOD ? "good" : \
(state)->magic == BOOT_MAGIC_UNSET ? "unset" : \
"bad"), \
+ (state)->swap_type, \
(state)->copy_done, \
(state)->image_ok)
#endif /* !MCUBOOT_NO_SWAP && !MCUBOOT_RAM_LOADING */
@@ -209,25 +211,15 @@
static uint8_t
boot_write_sz(void)
{
- const struct flash_area *fap;
uint8_t elem_sz;
uint8_t align;
- int rc;
/* Figure out what size to write update status update as. The size depends
* on what the minimum write size is for scratch area, active image slot.
* We need to use the bigger of those 2 values.
*/
- rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY, &fap);
- assert(rc == 0);
- elem_sz = flash_area_align(fap);
- flash_area_close(fap);
-
- rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH, &fap);
- assert(rc == 0);
- align = flash_area_align(fap);
- flash_area_close(fap);
-
+ elem_sz = flash_area_align(boot_data.imgs[BOOT_PRIMARY_SLOT].area);
+ align = flash_area_align(boot_data.scratch.area);
if (align > elem_sz) {
elem_sz = align;
}
@@ -256,6 +248,11 @@
return BOOT_EFLASH;
}
+ rc = boot_initialize_area(&boot_data, FLASH_AREA_IMAGE_SCRATCH);
+ if (rc != 0) {
+ return BOOT_EFLASH;
+ }
+
BOOT_WRITE_SZ(&boot_data) = boot_write_sz();
return 0;
@@ -265,10 +262,13 @@
* Validate image hash/signature and security counter in a slot.
*/
static int
-boot_image_check(struct image_header *hdr, const struct flash_area *fap)
+boot_image_check(struct image_header *hdr, const struct flash_area *fap,
+ struct boot_status *bs)
{
static uint8_t tmpbuf[BOOT_TMPBUF_SZ];
+ (void)bs;
+
if (bootutil_img_validate(hdr, fap, tmpbuf, BOOT_TMPBUF_SZ,
NULL, 0, NULL)) {
return BOOT_EBADIMAGE;
@@ -276,20 +276,49 @@
return 0;
}
-static inline int
-boot_magic_is_erased(uint8_t erased_val, uint32_t magic)
+/*
+ * Check that a memory area consists of a given value.
+ */
+static inline bool
+boot_data_is_set_to(uint8_t val, void *data, size_t len)
{
uint8_t i;
- for (i = 0; i < sizeof(magic); i++) {
- if (erased_val != *(((uint8_t *)&magic) + i)) {
- return 0;
+ uint8_t *p = (uint8_t *)data;
+ for (i = 0; i < len; i++) {
+ if (val != p[i]) {
+ return false;
}
}
- return 1;
+ return true;
}
static int
-boot_validate_slot(int slot)
+boot_check_header_erased(int slot)
+{
+ const struct flash_area *fap;
+ struct image_header *hdr;
+ uint8_t erased_val;
+ int rc;
+
+ rc = flash_area_open(flash_area_id_from_image_slot(slot), &fap);
+ if (rc != 0) {
+ return -1;
+ }
+
+ erased_val = flash_area_erased_val(fap);
+ flash_area_close(fap);
+
+ hdr = boot_img_hdr(&boot_data, slot);
+ if (!boot_data_is_set_to(erased_val, &hdr->ih_magic,
+ sizeof(hdr->ih_magic))) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+boot_validate_slot(int slot, struct boot_status *bs)
{
const struct flash_area *fap;
struct image_header *hdr;
@@ -301,19 +330,20 @@
}
hdr = boot_img_hdr(&boot_data, slot);
- if (boot_magic_is_erased(flash_area_erased_val(fap), hdr->ih_magic) ||
- (hdr->ih_flags & IMAGE_F_NON_BOOTABLE)) {
+ if ((boot_check_header_erased(slot) == 0) ||
+ (hdr->ih_flags & IMAGE_F_NON_BOOTABLE)) {
/* No bootable image in slot; continue booting from the primary slot. */
- return -1;
+ rc = -1;
+ goto out;
}
if ((hdr->ih_magic != IMAGE_MAGIC ||
- boot_image_check(hdr, fap) != 0)) {
- if (slot != 0) {
+ boot_image_check(hdr, fap, bs) != 0)) {
+ if (slot != BOOT_PRIMARY_SLOT) {
rc = flash_area_erase(fap, 0, fap->fa_size);
if(rc != 0) {
- flash_area_close(fap);
- return BOOT_EFLASH;
+ rc = BOOT_EFLASH;
+ goto out;
}
/* Image in the secondary slot is invalid. Erase the image and
* continue booting from the primary slot.
@@ -321,14 +351,16 @@
}
BOOT_LOG_ERR("Authentication failed! Image in the %s slot is not valid."
, (slot == BOOT_PRIMARY_SLOT) ? "primary" : "secondary");
- flash_area_close(fap);
- return -1;
+ rc = -1;
+ goto out;
}
- flash_area_close(fap);
-
/* Image in the secondary slot is valid. */
- return 0;
+ rc = 0;
+
+out:
+ flash_area_close(fap);
+ return rc;
}
/**
@@ -414,8 +446,8 @@
* status is necessary for completing a swap that was interrupted by a boot
* loader reset.
*
- * @return BOOT_STATUS_SOURCE_[...] code indicating where
- * status should be read from.
+ * @return A BOOT_STATUS_SOURCE_[...] code indicating where status should
+ * be read from.
*/
static int
boot_status_source(void)
@@ -434,16 +466,16 @@
rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SCRATCH, &state_scratch);
assert(rc == 0);
- BOOT_LOG_SWAP_STATE("Image 0", &state_primary_slot);
+ BOOT_LOG_SWAP_STATE("Primary image", &state_primary_slot);
BOOT_LOG_SWAP_STATE("Scratch", &state_scratch);
for (i = 0; i < BOOT_STATUS_TABLES_COUNT; i++) {
table = &boot_status_tables[i];
- if ((table->bst_magic_primary_slot == BOOT_MAGIC_ANY ||
- table->bst_magic_primary_slot == state_primary_slot.magic) &&
- (table->bst_magic_scratch == BOOT_MAGIC_ANY ||
- table->bst_magic_scratch == state_scratch.magic) &&
+ if (boot_magic_compatible_check(table->bst_magic_primary_slot,
+ state_primary_slot.magic) &&
+ boot_magic_compatible_check(table->bst_magic_scratch,
+ state_scratch.magic) &&
(table->bst_copy_done_primary_slot == BOOT_FLAG_ANY ||
table->bst_copy_done_primary_slot == state_primary_slot.copy_done))
{
@@ -461,56 +493,96 @@
return BOOT_STATUS_SOURCE_NONE;
}
-/**
- * Calculates the type of swap that just completed.
- *
- * This is used when a swap is interrupted by an external event. After
- * finishing the swap operation determines what the initial request was.
+/*
+ * Slots are compatible when all sectors that store upto to size of the image
+ * round up to sector size, in both slot's are able to fit in the scratch
+ * area, and have sizes that are a multiple of each other (powers of two
+ * presumably!).
*/
static int
-boot_previous_swap_type(void)
-{
- int post_swap_type;
-
- post_swap_type = boot_swap_type();
-
- switch (post_swap_type) {
- case BOOT_SWAP_TYPE_NONE : return BOOT_SWAP_TYPE_PERM;
- case BOOT_SWAP_TYPE_REVERT : return BOOT_SWAP_TYPE_TEST;
- case BOOT_SWAP_TYPE_PANIC : return BOOT_SWAP_TYPE_PANIC;
- }
-
- return BOOT_SWAP_TYPE_FAIL;
-}
-
-static int
boot_slots_compatible(void)
{
- size_t num_sectors_0 = boot_img_num_sectors(&boot_data,
- BOOT_PRIMARY_SLOT);
- size_t num_sectors_1 = boot_img_num_sectors(&boot_data,
- BOOT_SECONDARY_SLOT);
- size_t size_0, size_1;
- size_t i;
+ size_t num_sectors_primary;
+ size_t num_sectors_secondary;
+ size_t sz0, sz1;
+ size_t primary_slot_sz, secondary_slot_sz;
+ size_t scratch_sz;
+ size_t i, j;
+ int8_t smaller;
- if (num_sectors_0 > BOOT_MAX_IMG_SECTORS || num_sectors_1 > BOOT_MAX_IMG_SECTORS) {
+ num_sectors_primary =
+ boot_img_num_sectors(&boot_data, BOOT_PRIMARY_SLOT);
+ num_sectors_secondary =
+ boot_img_num_sectors(&boot_data, BOOT_SECONDARY_SLOT);
+ if ((num_sectors_primary > BOOT_MAX_IMG_SECTORS) ||
+ (num_sectors_secondary > BOOT_MAX_IMG_SECTORS)) {
BOOT_LOG_WRN("Cannot upgrade: more sectors than allowed");
return 0;
}
- /* Ensure both image slots have identical sector layouts. */
- if (num_sectors_0 != num_sectors_1) {
- BOOT_LOG_WRN("Cannot upgrade: number of sectors differ between slots");
- return 0;
+ scratch_sz = boot_scratch_area_size(&boot_data);
+
+ /*
+ * The following loop scans all sectors in a linear fashion, assuring that
+ * for each possible sector in each slot, it is able to fit in the other
+ * slot's sector or sectors. Slot's should be compatible as long as any
+ * number of a slot's sectors are able to fit into another, which only
+ * excludes cases where sector sizes are not a multiple of each other.
+ */
+ i = sz0 = primary_slot_sz = 0;
+ j = sz1 = secondary_slot_sz = 0;
+ smaller = 0;
+ while (i < num_sectors_primary || j < num_sectors_secondary) {
+ if (sz0 == sz1) {
+ sz0 += boot_img_sector_size(&boot_data, BOOT_PRIMARY_SLOT, i);
+ sz1 += boot_img_sector_size(&boot_data, BOOT_SECONDARY_SLOT, j);
+ i++;
+ j++;
+ } else if (sz0 < sz1) {
+ sz0 += boot_img_sector_size(&boot_data, BOOT_PRIMARY_SLOT, i);
+ /* Guarantee that multiple sectors of the secondary slot
+ * fit into the primary slot.
+ */
+ if (smaller == 2) {
+ BOOT_LOG_WRN("Cannot upgrade: slots have non-compatible"
+ " sectors");
+ return 0;
+ }
+ smaller = 1;
+ i++;
+ } else {
+ sz1 += boot_img_sector_size(&boot_data, BOOT_SECONDARY_SLOT, j);
+ /* Guarantee that multiple sectors of the primary slot
+ * fit into the secondary slot.
+ */
+ if (smaller == 1) {
+ BOOT_LOG_WRN("Cannot upgrade: slots have non-compatible"
+ " sectors");
+ return 0;
+ }
+ smaller = 2;
+ j++;
+ }
+ if (sz0 == sz1) {
+ primary_slot_sz += sz0;
+ secondary_slot_sz += sz1;
+ /* Scratch has to fit each swap operation to the size of the larger
+ * sector among the primary slot and the secondary slot.
+ */
+ if (sz0 > scratch_sz || sz1 > scratch_sz) {
+ BOOT_LOG_WRN("Cannot upgrade: not all sectors fit inside"
+ " scratch");
+ return 0;
+ }
+ smaller = sz0 = sz1 = 0;
+ }
}
- for (i = 0; i < num_sectors_0; i++) {
- size_0 = boot_img_sector_size(&boot_data, BOOT_PRIMARY_SLOT, i);
- size_1 = boot_img_sector_size(&boot_data, BOOT_SECONDARY_SLOT, i);
- if (size_0 != size_1) {
- BOOT_LOG_WRN("Cannot upgrade: an incompatible sector was found");
- return 0;
- }
+ if ((i != num_sectors_primary) ||
+ (j != num_sectors_secondary) ||
+ (primary_slot_sz != secondary_slot_sz)) {
+ BOOT_LOG_WRN("Cannot upgrade: slots are not compatible");
+ return 0;
}
return 1;
@@ -605,6 +677,7 @@
boot_read_status(struct boot_status *bs)
{
const struct flash_area *fap;
+ uint32_t off;
int status_loc;
int area_id;
int rc;
@@ -612,6 +685,7 @@
memset(bs, 0, sizeof *bs);
bs->idx = BOOT_STATUS_IDX_0;
bs->state = BOOT_STATUS_STATE_0;
+ bs->swap_type = BOOT_SWAP_TYPE_NONE;
#ifdef MCUBOOT_OVERWRITE_ONLY
/* Overwrite-only doesn't make use of the swap status area. */
@@ -642,6 +716,15 @@
}
rc = boot_read_status_bytes(fap, bs);
+ if (rc == 0) {
+ off = boot_swap_type_off(fap);
+ rc = flash_area_read_is_empty(fap, off, &bs->swap_type,
+ sizeof bs->swap_type);
+ if (rc == 1) {
+ bs->swap_type = BOOT_SWAP_TYPE_NONE;
+ rc = 0;
+ }
+ }
flash_area_close(fap);
@@ -718,7 +801,7 @@
* @return The type of swap to perform (BOOT_SWAP_TYPE...)
*/
static int
-boot_validated_swap_type(void)
+boot_validated_swap_type(struct boot_status *bs)
{
int swap_type;
@@ -730,7 +813,7 @@
/* Boot loader wants to switch to the secondary slot.
* Ensure image is valid.
*/
- if (boot_validate_slot(BOOT_SECONDARY_SLOT) != 0) {
+ if (boot_validate_slot(BOOT_SECONDARY_SLOT, bs) != 0) {
swap_type = BOOT_SWAP_TYPE_FAIL;
}
}
@@ -765,6 +848,11 @@
scratch_sz = boot_scratch_area_size(&boot_data);
for (i = last_sector_idx; i >= 0; i--) {
new_sz = sz + boot_img_sector_size(&boot_data, BOOT_PRIMARY_SLOT, i);
+ /*
+ * The secondary slot is not being checked here, because
+ * `boot_slots_compatible` already provides assurance that the copy size
+ * will be compatible with the primary slot and scratch.
+ */
if (new_sz > scratch_sz) {
break;
}
@@ -782,37 +870,17 @@
/**
* Erases a region of flash.
*
- * @param flash_area_idx The ID of the flash area containing the region
- * to erase.
+ * @param flash_area The flash_area containing the region to erase.
* @param off The offset within the flash area to start the
* erase.
* @param sz The number of bytes to erase.
*
* @return 0 on success; nonzero on failure.
*/
-static int
-boot_erase_sector(int flash_area_id, uint32_t off, uint32_t sz)
+static inline int
+boot_erase_sector(const struct flash_area *fap, uint32_t off, uint32_t sz)
{
- const struct flash_area *fap = NULL;
- int rc;
-
- rc = flash_area_open(flash_area_id, &fap);
- if (rc != 0) {
- rc = BOOT_EFLASH;
- goto done;
- }
-
- rc = flash_area_erase(fap, off, sz);
- if (rc != 0) {
- rc = BOOT_EFLASH;
- goto done;
- }
-
- rc = 0;
-
-done:
- flash_area_close(fap);
- return rc;
+ return flash_area_erase(fap, off, sz);
}
/**
@@ -830,32 +898,16 @@
* @return 0 on success; nonzero on failure.
*/
static int
-boot_copy_sector(int flash_area_id_src, int flash_area_id_dst,
+boot_copy_sector(const struct flash_area *fap_src,
+ const struct flash_area *fap_dst,
uint32_t off_src, uint32_t off_dst, uint32_t sz)
{
- const struct flash_area *fap_src;
- const struct flash_area *fap_dst;
uint32_t bytes_copied;
int chunk_sz;
int rc;
static uint8_t buf[1024];
- fap_src = NULL;
- fap_dst = NULL;
-
- rc = flash_area_open(flash_area_id_src, &fap_src);
- if (rc != 0) {
- rc = BOOT_EFLASH;
- goto done;
- }
-
- rc = flash_area_open(flash_area_id_dst, &fap_dst);
- if (rc != 0) {
- rc = BOOT_EFLASH;
- goto done;
- }
-
bytes_copied = 0;
while (bytes_copied < sz) {
if (sz - bytes_copied > sizeof(buf)) {
@@ -866,45 +918,37 @@
rc = flash_area_read(fap_src, off_src + bytes_copied, buf, chunk_sz);
if (rc != 0) {
- rc = BOOT_EFLASH;
- goto done;
+ return BOOT_EFLASH;
}
rc = flash_area_write(fap_dst, off_dst + bytes_copied, buf, chunk_sz);
if (rc != 0) {
- rc = BOOT_EFLASH;
- goto done;
+ return BOOT_EFLASH;
}
bytes_copied += chunk_sz;
}
- rc = 0;
-
-done:
- if (fap_src) {
- flash_area_close(fap_src);
- }
- if (fap_dst) {
- flash_area_close(fap_dst);
- }
- return rc;
+ return 0;
}
#ifndef MCUBOOT_OVERWRITE_ONLY
static inline int
-boot_status_init_by_id(int flash_area_id, const struct boot_status *bs)
+boot_status_init(const struct flash_area *fap, const struct boot_status *bs)
{
- const struct flash_area *fap;
struct boot_swap_state swap_state;
int rc;
- rc = flash_area_open(flash_area_id, &fap);
- assert(rc == 0);
+ BOOT_LOG_DBG("initializing status; fa_id=%d", fap->fa_id);
rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SECONDARY, &swap_state);
assert(rc == 0);
+ if (bs->swap_type != BOOT_SWAP_TYPE_NONE) {
+ rc = boot_write_swap_type(fap, bs->swap_type);
+ assert(rc == 0);
+ }
+
if (swap_state.image_ok == BOOT_FLAG_SET) {
rc = boot_write_image_ok(fap);
assert(rc == 0);
@@ -916,19 +960,23 @@
rc = boot_write_magic(fap);
assert(rc == 0);
- flash_area_close(fap);
-
return 0;
}
static int
-boot_erase_last_sector_by_id(int flash_area_id)
+boot_erase_trailer_sectors(const struct flash_area *fap)
{
uint8_t slot;
- uint32_t last_sector;
+ uint32_t sector;
+ uint32_t trailer_sz;
+ uint32_t total_sz;
+ uint32_t off;
+ uint32_t sz;
int rc;
- switch (flash_area_id) {
+ BOOT_LOG_DBG("erasing trailer; fa_id=%d", fap->fa_id);
+
+ switch (fap->fa_id) {
case FLASH_AREA_IMAGE_PRIMARY:
slot = BOOT_PRIMARY_SLOT;
break;
@@ -939,11 +987,19 @@
return BOOT_EFLASH;
}
- last_sector = boot_img_num_sectors(&boot_data, slot) - 1;
- rc = boot_erase_sector(flash_area_id,
- boot_img_sector_off(&boot_data, slot, last_sector),
- boot_img_sector_size(&boot_data, slot, last_sector));
- assert(rc == 0);
+ /* delete starting from last sector and moving to beginning */
+ sector = boot_img_num_sectors(&boot_data, slot) - 1;
+ trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(&boot_data));
+ total_sz = 0;
+ do {
+ sz = boot_img_sector_size(&boot_data, slot, sector);
+ off = boot_img_sector_off(&boot_data, slot, sector);
+ rc = boot_erase_sector(fap, off, sz);
+ assert(rc == 0);
+
+ sector--;
+ total_sz += sz;
+ } while (total_sz < trailer_sz);
return rc;
}
@@ -964,23 +1020,26 @@
static void
boot_swap_sectors(int idx, uint32_t sz, struct boot_status *bs)
{
- const struct flash_area *fap;
+ const struct flash_area *fap_primary_slot;
+ const struct flash_area *fap_secondary_slot;
+ const struct flash_area *fap_scratch;
uint32_t copy_sz;
uint32_t trailer_sz;
uint32_t img_off;
uint32_t scratch_trailer_off;
struct boot_swap_state swap_state;
size_t last_sector;
+ bool erase_scratch;
int rc;
/* Calculate offset from start of image area. */
img_off = boot_img_sector_off(&boot_data, BOOT_PRIMARY_SLOT, idx);
copy_sz = sz;
- trailer_sz = boot_slots_trailer_sz(BOOT_WRITE_SZ(&boot_data));
+ trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(&boot_data));
- /* sz in this function is always is always sized on a multiple of the
- * sector size. The check against the start offset of the last sector
+ /* sz in this function is always sized on a multiple of the sector size.
+ * The check against the start offset of the last sector
* is to determine if we're swapping the last sector. The last sector
* needs special handling because it's where the trailer lives. If we're
* copying it, we need to use scratch to write the trailer temporarily.
@@ -996,40 +1055,59 @@
bs->use_scratch = (bs->idx == BOOT_STATUS_IDX_0 && copy_sz != sz);
- if (bs->state == BOOT_STATUS_STATE_0) {
- rc = boot_erase_sector(FLASH_AREA_IMAGE_SCRATCH, 0, sz);
- assert(rc == 0);
+ rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY, &fap_primary_slot);
+ assert (rc == 0);
- rc = boot_copy_sector(FLASH_AREA_IMAGE_SECONDARY, FLASH_AREA_IMAGE_SCRATCH,
- img_off, 0, copy_sz);
+ rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY, &fap_secondary_slot);
+ assert (rc == 0);
+
+ rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH, &fap_scratch);
+ assert (rc == 0);
+
+ if (bs->state == BOOT_STATUS_STATE_0) {
+ BOOT_LOG_DBG("erasing scratch area");
+ rc = boot_erase_sector(fap_scratch, 0, fap_scratch->fa_size);
assert(rc == 0);
if (bs->idx == BOOT_STATUS_IDX_0) {
- if (bs->use_scratch) {
- boot_status_init_by_id(FLASH_AREA_IMAGE_SCRATCH, bs);
- } else {
- /* Prepare the status area... here it is known that the
- * last sector is not being used by the image data so it's
- * safe to erase.
+ /* Write a trailer to the scratch area, even if we don't need the
+ * scratch area for status. We need a temporary place to store the
+ * `swap-type` while we erase the primary trailer.
+ */
+ rc = boot_status_init(fap_scratch, bs);
+ assert(rc == 0);
+
+ if (!bs->use_scratch) {
+ /* Prepare the primary status area... here it is known that the
+ * last sector is not being used by the image data so it's safe
+ * to erase.
*/
- rc = boot_erase_last_sector_by_id(FLASH_AREA_IMAGE_PRIMARY);
+ rc = boot_erase_trailer_sectors(fap_primary_slot);
assert(rc == 0);
- boot_status_init_by_id(FLASH_AREA_IMAGE_PRIMARY, bs);
+ rc = boot_status_init(fap_primary_slot, bs);
+ assert(rc == 0);
+
+ /* Erase the temporary trailer from the scratch area. */
+ rc = boot_erase_sector(fap_scratch, 0, fap_scratch->fa_size);
+ assert(rc == 0);
}
}
+ rc = boot_copy_sector(fap_secondary_slot, fap_scratch,
+ img_off, 0, copy_sz);
+ assert(rc == 0);
+
bs->state = BOOT_STATUS_STATE_1;
rc = boot_write_status(bs);
BOOT_STATUS_ASSERT(rc == 0);
}
if (bs->state == BOOT_STATUS_STATE_1) {
- rc = boot_erase_sector(FLASH_AREA_IMAGE_SECONDARY, img_off, sz);
+ rc = boot_erase_sector(fap_secondary_slot, img_off, sz);
assert(rc == 0);
- rc = boot_copy_sector(FLASH_AREA_IMAGE_PRIMARY,
- FLASH_AREA_IMAGE_SECONDARY,
+ rc = boot_copy_sector(fap_primary_slot, fap_secondary_slot,
img_off, img_off, copy_sz);
assert(rc == 0);
@@ -1037,7 +1115,7 @@
/* If not all sectors of the slot are being swapped,
* guarantee here that only the primary slot will have the state.
*/
- rc = boot_erase_last_sector_by_id(FLASH_AREA_IMAGE_SECONDARY);
+ rc = boot_erase_trailer_sectors(fap_secondary_slot);
assert(rc == 0);
}
@@ -1047,31 +1125,22 @@
}
if (bs->state == BOOT_STATUS_STATE_2) {
- rc = boot_erase_sector(FLASH_AREA_IMAGE_PRIMARY, img_off, sz);
+ rc = boot_erase_sector(fap_primary_slot, img_off, sz);
assert(rc == 0);
- /* NOTE: also copy trailer from scratch (has status info) */
- rc = boot_copy_sector(FLASH_AREA_IMAGE_SCRATCH,
- FLASH_AREA_IMAGE_PRIMARY,
+ /* NOTE: If this is the final sector, we exclude the image trailer from
+ * this copy (copy_sz was truncated earlier).
+ */
+ rc = boot_copy_sector(fap_scratch, fap_primary_slot,
0, img_off, copy_sz);
assert(rc == 0);
if (bs->use_scratch) {
- rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH, &fap);
- assert(rc == 0);
-
- scratch_trailer_off = boot_status_off(fap);
-
- flash_area_close(fap);
-
- rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY, &fap);
- assert(rc == 0);
+ scratch_trailer_off = boot_status_off(fap_scratch);
/* copy current status that is being maintained in scratch */
- rc = boot_copy_sector(FLASH_AREA_IMAGE_SCRATCH,
- FLASH_AREA_IMAGE_PRIMARY,
- scratch_trailer_off,
- img_off + copy_sz,
+ rc = boot_copy_sector(fap_scratch, fap_primary_slot,
+ scratch_trailer_off, img_off + copy_sz,
BOOT_STATUS_STATE_COUNT * BOOT_WRITE_SZ(&boot_data));
BOOT_STATUS_ASSERT(rc == 0);
@@ -1080,31 +1149,52 @@
assert(rc == 0);
if (swap_state.image_ok == BOOT_FLAG_SET) {
- rc = boot_write_image_ok(fap);
+ rc = boot_write_image_ok(fap_primary_slot);
assert(rc == 0);
}
- rc = boot_write_swap_size(fap, bs->swap_size);
+ if (swap_state.swap_type != BOOT_SWAP_TYPE_NONE) {
+ rc = boot_write_swap_type(fap_primary_slot,
+ swap_state.swap_type);
+ assert(rc == 0);
+ }
+
+ rc = boot_write_swap_size(fap_primary_slot, bs->swap_size);
assert(rc == 0);
- rc = boot_write_magic(fap);
+ rc = boot_write_magic(fap_primary_slot);
assert(rc == 0);
-
- flash_area_close(fap);
}
+ /* If we wrote a trailer to the scratch area, erase it after we persist
+ * a trailer to the primary slot. We do this to prevent mcuboot from
+ * reading a stale status from the scratch area in case of immediate
+ * reset.
+ */
+ erase_scratch = bs->use_scratch;
+ bs->use_scratch = 0;
+
bs->idx++;
bs->state = BOOT_STATUS_STATE_0;
- bs->use_scratch = 0;
rc = boot_write_status(bs);
BOOT_STATUS_ASSERT(rc == 0);
+
+ if (erase_scratch) {
+ rc = boot_erase_sector(fap_scratch, 0, sz);
+ assert(rc == 0);
+ }
}
+
+ flash_area_close(fap_primary_slot);
+ flash_area_close(fap_secondary_slot);
+ flash_area_close(fap_scratch);
}
#endif /* !MCUBOOT_OVERWRITE_ONLY */
/**
- * Swaps the two images in flash. If a prior copy operation was interrupted
- * by a system reset, this function completes that operation.
+ * Overwrite primary slot with the image contained in the secondary slot.
+ * If a prior copy operation was interrupted by a system reset, this function
+ * redos the copy.
*
* @param bs The current boot status. This function reads
* this struct to determine if it is resuming
@@ -1124,18 +1214,24 @@
size_t size = 0;
size_t this_size;
size_t last_sector;
+ const struct flash_area *fap_primary_slot;
+ const struct flash_area *fap_secondary_slot;
(void)bs;
BOOT_LOG_INF("Image upgrade secondary slot -> primary slot");
BOOT_LOG_INF("Erasing the primary slot");
+ rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY, &fap_primary_slot);
+ assert (rc == 0);
+
+ rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY, &fap_secondary_slot);
+ assert (rc == 0);
+
sect_count = boot_img_num_sectors(&boot_data, BOOT_PRIMARY_SLOT);
for (sect = 0; sect < sect_count; sect++) {
this_size = boot_img_sector_size(&boot_data, BOOT_PRIMARY_SLOT, sect);
- rc = boot_erase_sector(FLASH_AREA_IMAGE_PRIMARY,
- size,
- this_size);
+ rc = boot_erase_sector(fap_primary_slot, size, this_size);
assert(rc == 0);
size += this_size;
@@ -1143,8 +1239,7 @@
BOOT_LOG_INF("Copying the secondary slot to the primary slot: 0x%zx bytes",
size);
- rc = boot_copy_sector(FLASH_AREA_IMAGE_SECONDARY, FLASH_AREA_IMAGE_PRIMARY,
- 0, 0, size);
+ rc = boot_copy_sector(fap_secondary_slot, fap_primary_slot, 0, 0, size);
/* Update the stored security counter with the new image's security counter
* value. Both slots hold the new image at this point, but the secondary
@@ -1163,35 +1258,55 @@
* image is written without a trailer as is the case when using newt, the
* trailer that was left might trigger a new upgrade.
*/
- rc = boot_erase_sector(FLASH_AREA_IMAGE_SECONDARY,
+ BOOT_LOG_DBG("erasing secondary header");
+ rc = boot_erase_sector(fap_secondary_slot,
boot_img_sector_off(&boot_data,
BOOT_SECONDARY_SLOT, 0),
boot_img_sector_size(&boot_data,
BOOT_SECONDARY_SLOT, 0));
assert(rc == 0);
last_sector = boot_img_num_sectors(&boot_data, BOOT_SECONDARY_SLOT) - 1;
- rc = boot_erase_sector(FLASH_AREA_IMAGE_SECONDARY,
+ BOOT_LOG_DBG("erasing secondary trailer");
+ rc = boot_erase_sector(fap_secondary_slot,
boot_img_sector_off(&boot_data, BOOT_SECONDARY_SLOT,
last_sector),
boot_img_sector_size(&boot_data, BOOT_SECONDARY_SLOT,
last_sector));
assert(rc == 0);
+ flash_area_close(fap_primary_slot);
+ flash_area_close(fap_secondary_slot);
+
/* TODO: Perhaps verify the primary slot's signature again? */
return 0;
}
#else
+/**
+ * Swaps the two images in flash. If a prior copy operation was interrupted
+ * by a system reset, this function completes that operation.
+ *
+ * @param bs The current boot status. This function reads
+ * this struct to determine if it is resuming
+ * an interrupted swap operation. This
+ * function writes the updated status to this
+ * function on return.
+ *
+ * @return 0 on success; nonzero on failure.
+ */
static int
-boot_copy_image(struct boot_status *bs)
+boot_swap_image(struct boot_status *bs)
{
uint32_t sz;
int first_sector_idx;
int last_sector_idx;
+ int last_idx_secondary_slot;
uint32_t swap_idx;
struct image_header *hdr;
uint32_t size;
uint32_t copy_size;
+ uint32_t primary_slot_size;
+ uint32_t secondary_slot_size;
int rc;
/* FIXME: just do this if asked by user? */
@@ -1231,15 +1346,37 @@
copy_size = bs->swap_size;
}
- size = 0;
+ primary_slot_size = 0;
+ secondary_slot_size = 0;
last_sector_idx = 0;
+ last_idx_secondary_slot = 0;
+
+ /*
+ * Knowing the size of the largest image between both slots, here we
+ * find what is the last sector in the primary slot that needs swapping.
+ * Since we already know that both slots are compatible, the secondary
+ * slot's last sector is not really required after this check is finished.
+ */
while (1) {
- size += boot_img_sector_size(&boot_data, BOOT_PRIMARY_SLOT,
- last_sector_idx);
- if (size >= copy_size) {
+ if ((primary_slot_size < copy_size) ||
+ (primary_slot_size < secondary_slot_size)) {
+ primary_slot_size += boot_img_sector_size(&boot_data,
+ BOOT_PRIMARY_SLOT,
+ last_sector_idx);
+ }
+ if ((secondary_slot_size < copy_size) ||
+ (secondary_slot_size < primary_slot_size)) {
+ secondary_slot_size += boot_img_sector_size(&boot_data,
+ BOOT_SECONDARY_SLOT,
+ last_idx_secondary_slot);
+ }
+ if (primary_slot_size >= copy_size &&
+ secondary_slot_size >= copy_size &&
+ primary_slot_size == secondary_slot_size) {
break;
}
last_sector_idx++;
+ last_idx_secondary_slot++;
}
swap_idx = 0;
@@ -1255,7 +1392,8 @@
#ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT
if (boot_status_fails > 0) {
- BOOT_LOG_WRN("%d status write fails performing the swap", boot_status_fails);
+ BOOT_LOG_WRN("%d status write fails performing the swap",
+ boot_status_fails);
}
#endif
@@ -1334,7 +1472,6 @@
boot_swap_if_needed(int *out_swap_type)
{
struct boot_status bs;
- int swap_type;
int rc;
/* Determine if we rebooted in the middle of an image swap
@@ -1348,32 +1485,38 @@
/* If a partial swap was detected, complete it. */
if (bs.idx != BOOT_STATUS_IDX_0 || bs.state != BOOT_STATUS_STATE_0) {
- rc = boot_copy_image(&bs);
+#ifdef MCUBOOT_OVERWRITE_ONLY
+ /* Should never arrive here, overwrite-only mode has no swap state. */
+ assert(0);
+#else
+ /* Determine the type of swap operation being resumed from the
+ * `swap-type` trailer field.
+ */
+ rc = boot_swap_image(&bs);
assert(rc == 0);
+#endif
- /* NOTE: here we have finished a swap resume. The initial request
- * was either a TEST or PERM swap, which now after the completed
- * swap will be determined to be respectively REVERT (was TEST)
- * or NONE (was PERM).
- */
-
- /* Extrapolate the type of the partial swap. We need this
- * information to know how to mark the swap complete in flash.
- */
- swap_type = boot_previous_swap_type();
} else {
- swap_type = boot_validated_swap_type();
- switch (swap_type) {
+ if (bs.swap_type == BOOT_SWAP_TYPE_NONE) {
+ bs.swap_type = boot_validated_swap_type(&bs);
+ } else if (boot_validate_slot(BOOT_SECONDARY_SLOT, &bs) != 0) {
+ bs.swap_type = BOOT_SWAP_TYPE_FAIL;
+ }
+ switch (bs.swap_type) {
case BOOT_SWAP_TYPE_TEST:
case BOOT_SWAP_TYPE_PERM:
case BOOT_SWAP_TYPE_REVERT:
+#ifdef MCUBOOT_OVERWRITE_ONLY
rc = boot_copy_image(&bs);
+#else
+ rc = boot_swap_image(&bs);
+#endif
assert(rc == 0);
break;
}
}
- *out_swap_type = swap_type;
+ *out_swap_type = bs.swap_type;
return 0;
}
@@ -1401,9 +1544,10 @@
*/
static boot_sector_t primary_slot_sectors[BOOT_MAX_IMG_SECTORS];
static boot_sector_t secondary_slot_sectors[BOOT_MAX_IMG_SECTORS];
-
+ static boot_sector_t scratch_sectors[BOOT_MAX_IMG_SECTORS];
boot_data.imgs[BOOT_PRIMARY_SLOT].sectors = primary_slot_sectors;
boot_data.imgs[BOOT_SECONDARY_SLOT].sectors = secondary_slot_sectors;
+ boot_data.scratch.sectors = scratch_sectors;
/* Open boot_data image areas for the duration of this call. */
for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
@@ -1445,7 +1589,8 @@
* swap was finished to avoid a new revert.
*/
if (swap_type == BOOT_SWAP_TYPE_REVERT ||
- swap_type == BOOT_SWAP_TYPE_FAIL) {
+ swap_type == BOOT_SWAP_TYPE_FAIL ||
+ swap_type == BOOT_SWAP_TYPE_PERM) {
#ifndef MCUBOOT_OVERWRITE_ONLY
rc = boot_set_image_ok();
if (rc != 0) {
@@ -1530,8 +1675,7 @@
}
#ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT
- rc = boot_validate_slot(BOOT_PRIMARY_SLOT);
- assert(rc == 0);
+ rc = boot_validate_slot(BOOT_PRIMARY_SLOT, NULL);
if (rc != 0) {
rc = BOOT_EBADIMAGE;
goto out;
@@ -1569,7 +1713,7 @@
}
/* Always boot from the primary slot. */
- rsp->br_flash_dev_id = boot_img_fa_device_id(&boot_data, BOOT_PRIMARY_SLOT);
+ rsp->br_flash_dev_id = boot_data.imgs[BOOT_PRIMARY_SLOT].area->fa_device_id;
rsp->br_image_off = boot_img_slot_off(&boot_data, BOOT_PRIMARY_SLOT);
rsp->br_hdr = boot_img_hdr(&boot_data, slot);
@@ -1839,7 +1983,7 @@
if (img_cnt) {
/* Authenticate images */
for (i = 0; i < img_cnt; i++) {
- rc = boot_validate_slot(boot_sequence[i]);
+ rc = boot_validate_slot(boot_sequence[i], NULL);
if (rc == 0) {
slot = boot_sequence[i];
break;
@@ -1906,7 +2050,7 @@
rsp->br_hdr = newest_image_header;
rsp->br_image_off = boot_img_slot_off(&boot_data, slot);
- rsp->br_flash_dev_id = boot_img_fa_device_id(&boot_data, slot);
+ rsp->br_flash_dev_id = boot_data.imgs[slot].area->fa_device_id;
} else {
/* No candidate image available */
rc = BOOT_EBADIMAGE;