Add support for flash devices erased at 0
This extends mcuboot to allow use on devices which don't follow the
typical erased at 0xff. This was tested on some previously supported
devices (erased at 0xff) and STM32L1/L0 which are erased at 0.
Signed-off-by: Fabio Utzig <utzig@apache.org>
diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c
index 9ddf82d..66c8843 100644
--- a/boot/bootutil/src/loader.c
+++ b/boot/bootutil/src/loader.c
@@ -28,7 +28,6 @@
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
-#include <hal/hal_flash.h>
#include <os/os_malloc.h>
#include "bootutil/bootutil.h"
#include "bootutil/image.h"
@@ -52,9 +51,6 @@
#endif
struct boot_status_table {
- /**
- * For each field, a value of 0 means "any".
- */
uint8_t bst_magic_slot0;
uint8_t bst_magic_scratch;
uint8_t bst_copy_done_slot0;
@@ -70,14 +66,14 @@
/* | slot-0 | scratch |
* ----------+------------+------------|
* magic | Good | Any |
- * copy-done | 0x01 | N/A |
+ * copy-done | Set | N/A |
* ----------+------------+------------'
* source: none |
* ------------------------------------'
*/
.bst_magic_slot0 = BOOT_MAGIC_GOOD,
- .bst_magic_scratch = 0,
- .bst_copy_done_slot0 = 0x01,
+ .bst_magic_scratch = BOOT_MAGIC_ANY,
+ .bst_copy_done_slot0 = BOOT_FLAG_SET,
.bst_status_source = BOOT_STATUS_SOURCE_NONE,
},
@@ -85,14 +81,14 @@
/* | slot-0 | scratch |
* ----------+------------+------------|
* magic | Good | Any |
- * copy-done | 0xff | N/A |
+ * copy-done | Unset | N/A |
* ----------+------------+------------'
* source: slot 0 |
* ------------------------------------'
*/
.bst_magic_slot0 = BOOT_MAGIC_GOOD,
- .bst_magic_scratch = 0,
- .bst_copy_done_slot0 = 0xff,
+ .bst_magic_scratch = BOOT_MAGIC_ANY,
+ .bst_copy_done_slot0 = BOOT_FLAG_UNSET,
.bst_status_source = BOOT_STATUS_SOURCE_SLOT0,
},
@@ -105,17 +101,16 @@
* source: scratch |
* ------------------------------------'
*/
- .bst_magic_slot0 = 0,
+ .bst_magic_slot0 = BOOT_MAGIC_ANY,
.bst_magic_scratch = BOOT_MAGIC_GOOD,
- .bst_copy_done_slot0 = 0,
+ .bst_copy_done_slot0 = BOOT_FLAG_ANY,
.bst_status_source = BOOT_STATUS_SOURCE_SCRATCH,
},
-
{
/* | slot-0 | scratch |
* ----------+------------+------------|
* magic | Unset | Any |
- * copy-done | 0xff | N/A |
+ * copy-done | Unset | N/A |
* ----------+------------+------------|
* source: varies |
* ------------------------------------+------------------------------+
@@ -125,8 +120,8 @@
* -------------------------------------------------------------------'
*/
.bst_magic_slot0 = BOOT_MAGIC_UNSET,
- .bst_magic_scratch = 0,
- .bst_copy_done_slot0 = 0xff,
+ .bst_magic_scratch = BOOT_MAGIC_ANY,
+ .bst_copy_done_slot0 = BOOT_FLAG_UNSET,
.bst_status_source = BOOT_STATUS_SOURCE_SLOT0,
},
};
@@ -172,11 +167,11 @@
for (i = 0; i < BOOT_STATUS_TABLES_COUNT; i++) {
table = &boot_status_tables[i];
- if ((table->bst_magic_slot0 == 0 ||
+ if ((table->bst_magic_slot0 == BOOT_MAGIC_ANY ||
table->bst_magic_slot0 == state_slot0.magic) &&
- (table->bst_magic_scratch == 0 ||
+ (table->bst_magic_scratch == BOOT_MAGIC_ANY ||
table->bst_magic_scratch == state_scratch.magic) &&
- (table->bst_copy_done_slot0 == 0 ||
+ (table->bst_copy_done_slot0 == BOOT_FLAG_ANY ||
table->bst_copy_done_slot0 == state_slot0.copy_done)) {
source = table->bst_status_source;
BOOT_LOG_INF("Boot source: %s",
@@ -389,7 +384,8 @@
idx_sz = elem_sz * BOOT_STATUS_STATE_COUNT;
- return idx * idx_sz + state * elem_sz;
+ return (idx - BOOT_STATUS_IDX_0) * idx_sz +
+ (state - BOOT_STATUS_STATE_0) * elem_sz;
}
/**
@@ -408,9 +404,11 @@
int invalid;
int rc;
int i;
+ uint8_t erased_val;
off = boot_status_off(fap);
max_entries = boot_status_entries(fap);
+ erased_val = flash_area_erased_val(fap);
found = 0;
found_idx = 0;
@@ -422,7 +420,7 @@
return BOOT_EFLASH;
}
- if (status == 0xff) {
+ if (status == erased_val) {
if (found && !found_idx) {
found_idx = i;
}
@@ -453,8 +451,8 @@
found_idx = i;
}
found_idx--;
- bs->idx = found_idx / BOOT_STATUS_STATE_COUNT;
- bs->state = found_idx % BOOT_STATUS_STATE_COUNT;
+ bs->idx = (found_idx / BOOT_STATUS_STATE_COUNT) + 1;
+ bs->state = (found_idx % BOOT_STATUS_STATE_COUNT) + 1;
}
return 0;
@@ -475,6 +473,8 @@
int rc;
memset(bs, 0, sizeof *bs);
+ bs->idx = BOOT_STATUS_IDX_0;
+ bs->state = BOOT_STATUS_STATE_0;
#ifdef MCUBOOT_OVERWRITE_ONLY
/* Overwrite-only doesn't make use of the swap status area. */
@@ -528,6 +528,7 @@
int rc;
uint8_t buf[BOOT_MAX_ALIGN];
uint8_t align;
+ uint8_t erased_val;
/* NOTE: The first sector copied (that is the last sector on slot) contains
* the trailer. Since in the last step SLOT 0 is erased, the first
@@ -552,7 +553,8 @@
boot_status_internal_off(bs->idx, bs->state,
BOOT_WRITE_SZ(&boot_data));
align = flash_area_align(fap);
- memset(buf, 0xFF, BOOT_MAX_ALIGN);
+ erased_val = flash_area_erased_val(fap);
+ memset(buf, erased_val, BOOT_MAX_ALIGN);
buf[0] = bs->state;
rc = flash_area_write(fap, off, buf, align);
@@ -612,6 +614,18 @@
return 0;
}
+static inline int
+boot_magic_is_erased(uint8_t erased_val, uint32_t magic)
+{
+ uint8_t i;
+ for (i = 0; i < sizeof(magic); i++) {
+ if (erased_val != *(((uint8_t *)&magic) + i)) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
static int
boot_validate_slot(int slot)
{
@@ -619,17 +633,18 @@
struct image_header *hdr;
int rc;
- hdr = boot_img_hdr(&boot_data, slot);
- if (hdr->ih_magic == 0xffffffff || hdr->ih_flags & IMAGE_F_NON_BOOTABLE) {
- /* No bootable image in slot; continue booting from slot 0. */
- return -1;
- }
-
rc = flash_area_open(flash_area_id_from_image_slot(slot), &fap);
if (rc != 0) {
return BOOT_EFLASH;
}
+ 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) {
+ /* No bootable image in slot; continue booting from slot 0. */
+ return -1;
+ }
+
if ((hdr->ih_magic != IMAGE_MAGIC || boot_image_check(hdr, fap) != 0)) {
if (slot != 0) {
flash_area_erase(fap, 0, fap->fa_size);
@@ -931,9 +946,9 @@
copy_sz -= trailer_sz;
}
- bs->use_scratch = (bs->idx == 0 && copy_sz != sz);
+ bs->use_scratch = (bs->idx == BOOT_STATUS_IDX_0 && copy_sz != sz);
- if (bs->state == 0) {
+ if (bs->state == BOOT_STATUS_STATE_0) {
rc = boot_erase_sector(FLASH_AREA_IMAGE_SCRATCH, 0, sz);
assert(rc == 0);
@@ -941,7 +956,7 @@
img_off, 0, copy_sz);
assert(rc == 0);
- if (bs->idx == 0) {
+ if (bs->idx == BOOT_STATUS_IDX_0) {
if (bs->use_scratch) {
boot_status_init_by_id(FLASH_AREA_IMAGE_SCRATCH, bs);
} else {
@@ -956,12 +971,12 @@
}
}
- bs->state = 1;
+ bs->state = BOOT_STATUS_STATE_1;
rc = boot_write_status(bs);
BOOT_STATUS_ASSERT(rc == 0);
}
- if (bs->state == 1) {
+ if (bs->state == BOOT_STATUS_STATE_1) {
rc = boot_erase_sector(FLASH_AREA_IMAGE_1, img_off, sz);
assert(rc == 0);
@@ -969,7 +984,7 @@
img_off, img_off, copy_sz);
assert(rc == 0);
- if (bs->idx == 0 && !bs->use_scratch) {
+ if (bs->idx == BOOT_STATUS_IDX_0 && !bs->use_scratch) {
/* If not all sectors of the slot are being swapped,
* guarantee here that only slot0 will have the state.
*/
@@ -977,12 +992,12 @@
assert(rc == 0);
}
- bs->state = 2;
+ bs->state = BOOT_STATUS_STATE_2;
rc = boot_write_status(bs);
BOOT_STATUS_ASSERT(rc == 0);
}
- if (bs->state == 2) {
+ if (bs->state == BOOT_STATUS_STATE_2) {
rc = boot_erase_sector(FLASH_AREA_IMAGE_0, img_off, sz);
assert(rc == 0);
@@ -1028,7 +1043,7 @@
}
bs->idx++;
- bs->state = 0;
+ bs->state = BOOT_STATUS_STATE_0;
bs->use_scratch = 0;
rc = boot_write_status(bs);
BOOT_STATUS_ASSERT(rc == 0);
@@ -1127,7 +1142,7 @@
size = copy_size = 0;
- if (bs->idx == 0 && bs->state == 0) {
+ if (bs->idx == BOOT_STATUS_IDX_0 && bs->state == BOOT_STATUS_STATE_0) {
/*
* No swap ever happened, so need to find the largest image which
* will be used to determine the amount of sectors to swap.
@@ -1173,7 +1188,7 @@
swap_idx = 0;
while (last_sector_idx >= 0) {
sz = boot_copy_sz(last_sector_idx, &first_sector_idx);
- if (swap_idx >= bs->idx) {
+ if (swap_idx >= (bs->idx - BOOT_STATUS_IDX_0)) {
boot_swap_sectors(first_sector_idx, sz, bs);
}
@@ -1275,7 +1290,7 @@
}
/* If a partial swap was detected, complete it. */
- if (bs.idx != 0 || bs.state != 0) {
+ if (bs.idx != BOOT_STATUS_IDX_0 || bs.state != BOOT_STATUS_STATE_0) {
rc = boot_copy_image(&bs);
assert(rc == 0);