Merge pull request #87 from utzig/update-docs
Update docs
diff --git a/README-RIOT.rst b/README-RIOT.rst
new file mode 100644
index 0000000..d343210
--- /dev/null
+++ b/README-RIOT.rst
@@ -0,0 +1,51 @@
+Building and using mcuboot with RIOT
+######################################
+
+*mcuboot* began its life as the bootloader for Mynewt. It has since
+acquired the ability to be used as a bootloader for RIOT as well.
+Currently the support is limited to the nrf52dk platform.
+
+Building the bootloader itself
+==============================
+
+In this first version, a prebuilt Mynewt binary is downloaded at
+compile time. This binary was compiled to do an integrity check, but
+not a signature check. In order to configure the bootloader for
+signature check it is necessary to re-compile it either with Mynewt
+or Zephyr, following the provided instructions.
+
+In the next version, it is planned to compile mcuboot using RIOT,
+which should be able to boot any of the supported OS images.
+
+Building Applications for the bootloader
+========================================
+
+A compatible mcuboot image can be compiled by typing: :code:`make mcuboot`.
+
+The only variable which needs to be set is :code:`IMAGE_VERSION` loaded
+with a valid formatted value. The format is :code:`major.minor.patch+other`
+(e.g. :code:`export IMAGE_VERSION= 1.1.1+1`. This variable can be either
+exported in the Makefile or manually, prior to the compilation process.
+
+The goal is to produce an ELF file which is linked to be flashed at a
+:code:`BOOTLOADER_OFFSET` offset rather than the beginning of ROM. mcuboot
+also expects an image padded with some specific headers containing the
+version information, and trailer type-length-value records (TLVs) with
+hash and signing information. This is done through the imgtool.py
+application, which is executed automatically by the RIOT build system.
+
+Signing the application
+-----------------------
+
+The application will be automatically signed with the provided key.
+If no key is provided, a new key will be automatically generated. The
+default key type is RSA-2048.
+
+In order to use your provided key, you need to recompile the bootloader
+using you public key, either in Zephyr or Mynewt by following the
+provided procedure for the selected OS.
+
+Flashing the application
+------------------------
+The application can be flashed by typing: :code:`make flash-mcuboot`.
+This will flash both the bootloader and the application.
diff --git a/boot/bootutil/include/bootutil/bootutil.h b/boot/bootutil/include/bootutil/bootutil.h
index f128d74..04411ff 100644
--- a/boot/bootutil/include/bootutil/bootutil.h
+++ b/boot/bootutil/include/bootutil/bootutil.h
@@ -38,7 +38,11 @@
/** Swap back to alternate slot. A confirm changes this state to NONE. */
#define BOOT_SWAP_TYPE_REVERT 4
-#define BOOT_SWAP_TYPE_FAIL 0xff
+/** Swap failed because image to be run is not valid */
+#define BOOT_SWAP_TYPE_FAIL 5
+
+/** Swapping encountered an unrecoverable error */
+#define BOOT_SWAP_TYPE_PANIC 0xff
#define MAX_FLASH_ALIGN 8
extern const uint32_t BOOT_MAX_ALIGN;
diff --git a/boot/bootutil/src/bootutil_misc.c b/boot/bootutil/src/bootutil_misc.c
index 5c04c2f..a71df72 100644
--- a/boot/bootutil/src/bootutil_misc.c
+++ b/boot/bootutil/src/bootutil_misc.c
@@ -48,97 +48,49 @@
struct boot_swap_table {
/** * For each field, a value of 0 means "any". */
- uint8_t bsw_magic_slot0;
- uint8_t bsw_magic_slot1;
- uint8_t bsw_image_ok_slot0;
- uint8_t bsw_image_ok_slot1;
+ uint8_t magic_slot0;
+ uint8_t magic_slot1;
+ uint8_t image_ok_slot0;
+ uint8_t image_ok_slot1;
+ uint8_t copy_done_slot0;
- uint8_t bsw_swap_type;
+ uint8_t swap_type;
};
/**
* This set of tables maps image trailer contents to swap operation type.
* When searching for a match, these tables must be iterated sequentially.
+ *
+ * NOTE: the table order is very important. The settings in Slot 1 always
+ * are priority to Slot 0 and should be located earlier in the table.
+ *
+ * The table lists only states where there is action needs to be taken by
+ * the bootloader, as in starting/finishing a swap operation.
*/
static const struct boot_swap_table boot_swap_tables[] = {
{
- /* | slot-0 | slot-1 |
- *----------+------------+------------|
- * magic | Unset | Unset |
- * image-ok | Any | Any |
- * ---------+------------+------------'
- * swap: none |
- * -----------------------------------'
- */
- .bsw_magic_slot0 = BOOT_MAGIC_UNSET,
- .bsw_magic_slot1 = BOOT_MAGIC_UNSET,
- .bsw_image_ok_slot0 = 0,
- .bsw_image_ok_slot1 = 0,
- .bsw_swap_type = BOOT_SWAP_TYPE_NONE,
+ .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 | Unset |
- * ---------+------------+------------`
- * swap: test |
- * -----------------------------------'
- */
- .bsw_magic_slot0 = 0,
- .bsw_magic_slot1 = BOOT_MAGIC_GOOD,
- .bsw_image_ok_slot0 = 0,
- .bsw_image_ok_slot1 = 0xff,
- .bsw_swap_type = BOOT_SWAP_TYPE_TEST,
+ .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 | Any | Good |
- * image-ok | Any | 0x01 |
- * ---------+------------+------------`
- * swap: permanent |
- * -----------------------------------'
- */
- .bsw_magic_slot0 = 0,
- .bsw_magic_slot1 = BOOT_MAGIC_GOOD,
- .bsw_image_ok_slot0 = 0,
- .bsw_image_ok_slot1 = 0x01,
- .bsw_swap_type = BOOT_SWAP_TYPE_PERM,
- },
-
- {
- /* | slot-0 | slot-1 |
- *----------+------------+------------|
- * magic | Good | Unset |
- * image-ok | 0xff | Any |
- * ---------+------------+------------'
- * swap: revert (test image running) |
- * -----------------------------------'
- */
- .bsw_magic_slot0 = BOOT_MAGIC_GOOD,
- .bsw_magic_slot1 = BOOT_MAGIC_UNSET,
- .bsw_image_ok_slot0 = 0xff,
- .bsw_image_ok_slot1 = 0,
- .bsw_swap_type = BOOT_SWAP_TYPE_REVERT,
- },
-
- {
- /* | slot-0 | slot-1 |
- *----------+------------+------------|
- * magic | Good | Unset |
- * image-ok | 0x01 | Any |
- * ---------+------------+------------'
- * swap: none (confirmed test image) |
- * -----------------------------------'
- */
- .bsw_magic_slot0 = BOOT_MAGIC_GOOD,
- .bsw_magic_slot1 = BOOT_MAGIC_UNSET,
- .bsw_image_ok_slot0 = 0x01,
- .bsw_image_ok_slot1 = 0,
- .bsw_swap_type = BOOT_SWAP_TYPE_NONE,
+ .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,
},
};
@@ -357,40 +309,42 @@
boot_swap_type(void)
{
const struct boot_swap_table *table;
- struct boot_swap_state state_slot0;
- struct boot_swap_state state_slot1;
+ struct boot_swap_state slot0;
+ struct boot_swap_state slot1;
int rc;
int i;
- rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_0, &state_slot0);
- assert(rc == 0);
+ rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_0, &slot0);
+ if (rc) {
+ return BOOT_SWAP_TYPE_PANIC;
+ }
- rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_1, &state_slot1);
- assert(rc == 0);
+ rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_1, &slot1);
+ if (rc) {
+ return BOOT_SWAP_TYPE_PANIC;
+ }
for (i = 0; i < BOOT_SWAP_TABLES_COUNT; i++) {
table = boot_swap_tables + i;
- if ((table->bsw_magic_slot0 == 0 ||
- table->bsw_magic_slot0 == state_slot0.magic) &&
- (table->bsw_magic_slot1 == 0 ||
- table->bsw_magic_slot1 == state_slot1.magic) &&
- (table->bsw_image_ok_slot0 == 0 ||
- table->bsw_image_ok_slot0 == state_slot0.image_ok) &&
- (table->bsw_image_ok_slot1 == 0 ||
- table->bsw_image_ok_slot1 == state_slot1.image_ok)) {
+ if ((!table->magic_slot0 || table->magic_slot0 == slot0.magic ) &&
+ (!table->magic_slot1 || table->magic_slot1 == slot1.magic ) &&
+ (!table->image_ok_slot0 || table->image_ok_slot0 == slot0.image_ok ) &&
+ (!table->image_ok_slot1 || table->image_ok_slot1 == slot1.image_ok ) &&
+ (!table->copy_done_slot0 || table->copy_done_slot0 == slot0.copy_done)) {
BOOT_LOG_INF("Swap type: %s",
- table->bsw_swap_type == BOOT_SWAP_TYPE_NONE ? "none" :
- table->bsw_swap_type == BOOT_SWAP_TYPE_TEST ? "test" :
- table->bsw_swap_type == BOOT_SWAP_TYPE_PERM ? "perm" :
- table->bsw_swap_type == BOOT_SWAP_TYPE_REVERT ? "revert" :
- table->bsw_swap_type == BOOT_SWAP_TYPE_FAIL ? "fail" :
- "BUG; can't happen");
- return table->bsw_swap_type;
+ table->swap_type == BOOT_SWAP_TYPE_TEST ? "test" :
+ table->swap_type == BOOT_SWAP_TYPE_PERM ? "perm" :
+ table->swap_type == BOOT_SWAP_TYPE_REVERT ? "revert" :
+ "BUG; can't happen");
+ 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;
}
}
- assert(0);
+ BOOT_LOG_INF("Swap type: none");
return BOOT_SWAP_TYPE_NONE;
}
diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c
index 178a9c7..ca75a96 100644
--- a/boot/bootutil/src/loader.c
+++ b/boot/bootutil/src/loader.c
@@ -126,21 +126,6 @@
#define BOOT_STATUS_TABLES_COUNT \
(sizeof boot_status_tables / sizeof boot_status_tables[0])
-/**
- * This table indicates the next swap type that should be performed. The first
- * column contains the current swap type. The second column contains the swap
- * type that should be effected after the first completes.
- */
-static const uint8_t boot_swap_trans_table[][2] = {
- /* From To */
- { BOOT_SWAP_TYPE_REVERT, BOOT_SWAP_TYPE_NONE },
- { BOOT_SWAP_TYPE_PERM, BOOT_SWAP_TYPE_NONE },
- { BOOT_SWAP_TYPE_TEST, BOOT_SWAP_TYPE_REVERT },
-};
-
-#define BOOT_SWAP_TRANS_TABLE_SIZE \
- (sizeof boot_swap_trans_table / sizeof boot_swap_trans_table[0])
-
#define BOOT_LOG_SWAP_STATE(area, state) \
BOOT_LOG_INF("%s: magic=%s, copy_done=0x%x, image_ok=0x%x", \
(area), \
@@ -201,25 +186,24 @@
/**
* 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.
*/
static int
boot_previous_swap_type(void)
{
int post_swap_type;
- int i;
post_swap_type = boot_swap_type();
- for (i = 0; i < BOOT_SWAP_TRANS_TABLE_SIZE; i++){
- if (boot_swap_trans_table[i][1] == post_swap_type) {
- return boot_swap_trans_table[i][0];
- }
+ 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;
}
- /* XXX: Temporary assert. */
- assert(0);
-
- return BOOT_SWAP_TYPE_REVERT;
+ return BOOT_SWAP_TYPE_FAIL;
}
static int
@@ -605,18 +589,16 @@
boot_validated_swap_type(void)
{
int swap_type;
- int rc;
swap_type = boot_swap_type();
- if (swap_type == BOOT_SWAP_TYPE_NONE) {
- /* Continue using slot 0. */
- return BOOT_SWAP_TYPE_NONE;
- }
-
- /* Boot loader wants to switch to slot 1. Ensure image is valid. */
- rc = boot_validate_slot(1);
- if (rc != 0) {
- return BOOT_SWAP_TYPE_FAIL;
+ switch (swap_type) {
+ case BOOT_SWAP_TYPE_TEST:
+ case BOOT_SWAP_TYPE_PERM:
+ case BOOT_SWAP_TYPE_REVERT:
+ /* Boot loader wants to switch to slot 1. Ensure image is valid. */
+ if (boot_validate_slot(1) != 0) {
+ swap_type = BOOT_SWAP_TYPE_FAIL;
+ }
}
return swap_type;
@@ -1095,10 +1077,10 @@
#endif
/**
- * Marks a test image in slot 0 as fully copied.
+ * Marks the image in slot 0 as fully copied.
*/
static int
-boot_finalize_test_swap(void)
+boot_set_copy_done(void)
{
const struct flash_area *fap;
int rc;
@@ -1109,23 +1091,24 @@
}
rc = boot_write_copy_done(fap);
- if (rc != 0) {
- return rc;
- }
-
- return 0;
+ flash_area_close(fap);
+ return rc;
}
/**
* Marks a reverted image in slot 0 as confirmed. This is necessary to ensure
* the status bytes from the image revert operation don't get processed on a
* subsequent boot.
+ *
+ * NOTE: image_ok is tested before writing because if there's a valid permanent
+ * image installed on slot0 and the new image to be upgrade to has a bad sig,
+ * image_ok would be overwritten.
*/
static int
-boot_finalize_revert_swap(void)
+boot_set_image_ok(void)
{
const struct flash_area *fap;
- struct boot_swap_state state_slot0;
+ struct boot_swap_state state;
int rc;
rc = flash_area_open(FLASH_AREA_IMAGE_0, &fap);
@@ -1133,33 +1116,19 @@
return BOOT_EFLASH;
}
- rc = boot_read_swap_state(fap, &state_slot0);
+ rc = boot_read_swap_state(fap, &state);
if (rc != 0) {
- return BOOT_EFLASH;
+ rc = BOOT_EFLASH;
+ goto out;
}
- if (state_slot0.magic == BOOT_MAGIC_UNSET) {
- rc = boot_write_magic(fap);
- if (rc != 0) {
- return rc;
- }
- }
-
- if (state_slot0.copy_done == BOOT_FLAG_UNSET) {
- rc = boot_write_copy_done(fap);
- if (rc != 0) {
- return rc;
- }
- }
-
- if (state_slot0.image_ok == BOOT_FLAG_UNSET) {
+ if (state.image_ok == BOOT_FLAG_UNSET) {
rc = boot_write_image_ok(fap);
- if (rc != 0) {
- return rc;
- }
}
- return 0;
+out:
+ flash_area_close(fap);
+ return rc;
}
/**
@@ -1191,6 +1160,12 @@
rc = boot_copy_image(&bs);
assert(rc == 0);
+ /* 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.
*/
@@ -1269,6 +1244,17 @@
if (rc != 0) {
goto out;
}
+
+ /*
+ * The following states need image_ok be explicitly set after the
+ * swap was finished to avoid a new revert.
+ */
+ if (swap_type == BOOT_SWAP_TYPE_REVERT || swap_type == BOOT_SWAP_TYPE_FAIL) {
+ rc = boot_set_image_ok();
+ if (rc != 0) {
+ swap_type = BOOT_SWAP_TYPE_PANIC;
+ }
+ }
} else {
swap_type = BOOT_SWAP_TYPE_NONE;
}
@@ -1278,17 +1264,15 @@
slot = 0;
break;
- case BOOT_SWAP_TYPE_TEST:
- case BOOT_SWAP_TYPE_PERM:
- slot = 1;
- boot_finalize_test_swap();
- reload_headers = true;
- break;
-
+ case BOOT_SWAP_TYPE_TEST: /* fallthrough */
+ case BOOT_SWAP_TYPE_PERM: /* fallthrough */
case BOOT_SWAP_TYPE_REVERT:
slot = 1;
- boot_finalize_revert_swap();
reload_headers = true;
+ rc = boot_set_copy_done();
+ if (rc != 0) {
+ swap_type = BOOT_SWAP_TYPE_PANIC;
+ }
break;
case BOOT_SWAP_TYPE_FAIL:
@@ -1297,14 +1281,19 @@
* we just reverted back to slot 0.
*/
slot = 0;
- boot_finalize_revert_swap();
reload_headers = true;
break;
default:
+ swap_type = BOOT_SWAP_TYPE_PANIC;
+ }
+
+ if (swap_type == BOOT_SWAP_TYPE_PANIC) {
+ BOOT_LOG_ERR("panic!");
assert(0);
- slot = 0;
- break;
+
+ /* Loop forever... */
+ while (1) {}
}
#ifdef MCUBOOT_VALIDATE_SLOT0
@@ -1321,6 +1310,8 @@
rc = BOOT_EBADIMAGE;
goto out;
}
+#else
+ (void)reload_headers;
#endif
/* Always boot from the primary slot. */
diff --git a/boot/zephyr/targets/96b_carbon.h b/boot/zephyr/targets/96b_carbon.h
index 8f52f54..b61cebf 100644
--- a/boot/zephyr/targets/96b_carbon.h
+++ b/boot/zephyr/targets/96b_carbon.h
@@ -26,13 +26,10 @@
#define FLASH_DRIVER_NAME CONFIG_SOC_FLASH_STM32_DEV_NAME
#endif
#define FLASH_ALIGN 1
-#define FLASH_AREA_IMAGE_0_OFFSET 0x20000
-#define FLASH_AREA_IMAGE_0_SIZE 0x20000
-#define FLASH_AREA_IMAGE_1_OFFSET 0x40000
-#define FLASH_AREA_IMAGE_1_SIZE 0x20000
-#define FLASH_AREA_IMAGE_SCRATCH_OFFSET 0x60000
-#define FLASH_AREA_IMAGE_SCRATCH_SIZE 0x20000
-/* Though sectors have variable size on this part, we've chosen
- * three sectors with uniform size here. */
+/*
+ * Though sectors have variable size on this part, we require Zephyr
+ * to choose image and flash sectors with uniform size, each one
+ * sector in size.
+ */
#define FLASH_AREA_IMAGE_SECTOR_SIZE 0x20000
diff --git a/boot/zephyr/targets/96b_nitrogen.h b/boot/zephyr/targets/96b_nitrogen.h
index 9c2777c..71e554a 100644
--- a/boot/zephyr/targets/96b_nitrogen.h
+++ b/boot/zephyr/targets/96b_nitrogen.h
@@ -21,10 +21,4 @@
#define FLASH_DRIVER_NAME CONFIG_SOC_FLASH_NRF5_DEV_NAME
#define FLASH_ALIGN 4
-#define FLASH_AREA_IMAGE_0_OFFSET 0x08000
-#define FLASH_AREA_IMAGE_0_SIZE 0x34000
-#define FLASH_AREA_IMAGE_1_OFFSET 0x3C000
-#define FLASH_AREA_IMAGE_1_SIZE 0x34000
-#define FLASH_AREA_IMAGE_SCRATCH_OFFSET 0x70000
-#define FLASH_AREA_IMAGE_SCRATCH_SIZE 0x0D000
/* Flash sector size is provided by SoC family include */
diff --git a/boot/zephyr/targets/nrf52840_pca10056.h b/boot/zephyr/targets/nrf52840_pca10056.h
index f56c287..df12989 100644
--- a/boot/zephyr/targets/nrf52840_pca10056.h
+++ b/boot/zephyr/targets/nrf52840_pca10056.h
@@ -5,10 +5,4 @@
#define FLASH_DRIVER_NAME CONFIG_SOC_FLASH_NRF5_DEV_NAME
#define FLASH_ALIGN 4
-#define FLASH_AREA_IMAGE_0_OFFSET 0x08000
-#define FLASH_AREA_IMAGE_0_SIZE 0x6C000
-#define FLASH_AREA_IMAGE_1_OFFSET 0x74000
-#define FLASH_AREA_IMAGE_1_SIZE 0x6C000
-#define FLASH_AREA_IMAGE_SCRATCH_OFFSET 0xE0000
-#define FLASH_AREA_IMAGE_SCRATCH_SIZE 0x1D000
/* Flash sector size is provided by SoC include */
diff --git a/boot/zephyr/targets/nucleo_f401re.h b/boot/zephyr/targets/nucleo_f401re.h
index c7fe17a..4be77e0 100644
--- a/boot/zephyr/targets/nucleo_f401re.h
+++ b/boot/zephyr/targets/nucleo_f401re.h
@@ -21,12 +21,6 @@
#define FLASH_DRIVER_NAME CONFIG_SOC_FLASH_STM32_DEV_NAME
#define FLASH_ALIGN 1
-#define FLASH_AREA_IMAGE_0_OFFSET 0x20000
-#define FLASH_AREA_IMAGE_0_SIZE 0x20000
-#define FLASH_AREA_IMAGE_1_OFFSET 0x40000
-#define FLASH_AREA_IMAGE_1_SIZE 0x20000
-#define FLASH_AREA_IMAGE_SCRATCH_OFFSET 0x60000
-#define FLASH_AREA_IMAGE_SCRATCH_SIZE 0x20000
/* Though sectors have variable size on this part, we've chosen
* three sectors with uniform size here. */
diff --git a/sim/simflash/src/lib.rs b/sim/simflash/src/lib.rs
index 991bbe4..5683595 100644
--- a/sim/simflash/src/lib.rs
+++ b/sim/simflash/src/lib.rs
@@ -39,6 +39,7 @@
ErrorKind::OutOfBounds(message.as_ref().to_owned())
}
+#[allow(dead_code)]
fn ewrite<T: AsRef<str>>(message: T) -> ErrorKind {
ErrorKind::Write(message.as_ref().to_owned())
}
@@ -148,8 +149,7 @@
for (i, x) in &mut self.write_safe[offset .. offset + payload.len()].iter_mut().enumerate() {
if !(*x) {
- bail!(ewrite(format!("Write to unerased location at 0x{:x}",
- offset + i)));
+ panic!("Write to unerased location at 0x{:x}", offset + i);
}
*x = false;
}
diff --git a/sim/src/main.rs b/sim/src/main.rs
index eed9855..a2b1a93 100644
--- a/sim/src/main.rs
+++ b/sim/src/main.rs
@@ -150,7 +150,7 @@
error!("{} Tests ran with {} failures", status.failures + status.passes, status.failures);
process::exit(1);
} else {
- warn!("{} Tests ran successfully", status.passes);
+ error!("{} Tests ran successfully", status.passes);
process::exit(0);
}
}
@@ -245,17 +245,31 @@
trailer_off: scratch_base - offset_from_end,
};
- let images = Images {
- slot0: slot0,
- slot1: slot1,
- primary: install_image(&mut flash, slot0_base, 32784),
- upgrade: install_image(&mut flash, slot1_base, 41928),
- };
+ // Set an alignment, and position the magic value.
+ c::set_sim_flash_align(align);
let mut failed = false;
- // Set an alignment, and position the magic value.
- c::set_sim_flash_align(align);
+ // Creates a badly signed image in slot1 to check that it is not
+ // upgraded to
+ let mut bad_flash = flash.clone();
+ let bad_slot1_image = Images {
+ slot0: &slot0,
+ slot1: &slot1,
+ primary: install_image(&mut bad_flash, slot0_base, 32784, false),
+ upgrade: install_image(&mut bad_flash, slot1_base, 41928, true),
+ };
+
+ failed |= run_signfail_upgrade(&bad_flash, &areadesc, &bad_slot1_image);
+
+ let images = Images {
+ slot0: &slot0,
+ slot1: &slot1,
+ primary: install_image(&mut flash, slot0_base, 32784, false),
+ upgrade: install_image(&mut flash, slot1_base, 41928, false),
+ };
+
+ failed |= run_norevert_newimage(&flash, &areadesc, &images);
mark_upgrade(&mut flash, &images.slot1);
@@ -272,7 +286,7 @@
failed |= run_revert_with_fails(&flash, &areadesc, &images, total_count);
failed |= run_perm_with_fails(&flash, &areadesc, &images, total_count);
failed |= run_perm_with_random_fails(&flash, &areadesc, &images,
- total_count, 5);
+ total_count, 5);
failed |= run_norevert(&flash, &areadesc, &images);
//show_flash(&flash);
@@ -305,12 +319,13 @@
fn run_basic_revert(flash: &SimFlash, areadesc: &AreaDesc, images: &Images) -> bool {
let mut fails = 0;
+ // FIXME: this test would also pass if no swap is ever performed???
if Caps::SwapUpgrade.present() {
for count in 2 .. 5 {
info!("Try revert: {}", count);
let fl = try_revert(&flash, &areadesc, count);
if !verify_image(&fl, images.slot0.base_off, &images.primary) {
- warn!("Revert failure on count {}", count);
+ error!("Revert failure on count {}", count);
fails += 1;
}
}
@@ -353,8 +368,10 @@
}
}
- info!("{} out of {} failed {:.2}%", fails, total_flash_ops,
- fails as f32 * 100.0 / total_flash_ops as f32);
+ if fails > 0 {
+ error!("{} out of {} failed {:.2}%", fails, total_flash_ops,
+ fails as f32 * 100.0 / total_flash_ops as f32);
+ }
fails > 0
}
@@ -390,6 +407,10 @@
fails += 1;
}
+ if fails > 0 {
+ error!("Error testing perm upgrade with {} fails", total_fails);
+ }
+
fails > 0
}
@@ -401,6 +422,7 @@
for i in 1 .. (total_count - 1) {
info!("Try interruption at {}", i);
if try_revert_with_fail_at(&flash, &areadesc, &images, i) {
+ error!("Revert failed at interruption {}", i);
fails += 1;
}
}
@@ -422,6 +444,9 @@
fails += 1;
}
+ //FIXME: copy_done is written by boot_go, is it ok if no copy
+ // was ever done?
+
if !verify_image(&fl, images.slot0.base_off, &images.upgrade) {
warn!("Slot 0 image verification FAIL");
fails += 1;
@@ -440,6 +465,12 @@
// Marks image in slot0 as permanent, no revert should happen...
mark_permanent_upgrade(&mut fl, &images.slot0);
+ if !verify_trailer(&fl, images.slot0.trailer_off, MAGIC_VALID, IMAGE_OK,
+ COPY_DONE) {
+ warn!("Mismatched trailer for Slot 0");
+ fails += 1;
+ }
+
if c::boot_go(&mut fl, &areadesc) != 0 {
warn!("Failed second boot");
fails += 1;
@@ -455,6 +486,101 @@
fails += 1;
}
+ if fails > 0 {
+ error!("Error running upgrade without revert");
+ }
+
+ fails > 0
+}
+
+// Tests a new image written to slot0 that already has magic and image_ok set
+// while there is no image on slot1, so no revert should ever happen...
+fn run_norevert_newimage(flash: &SimFlash, areadesc: &AreaDesc,
+ images: &Images) -> bool {
+ let mut fl = flash.clone();
+ let mut fails = 0;
+
+ info!("Try non-revert on imgtool generated image");
+ c::set_flash_counter(0);
+
+ mark_upgrade(&mut fl, &images.slot0);
+
+ // This simulates writing an image created by imgtool to Slot 0
+ if !verify_trailer(&fl, images.slot0.trailer_off, MAGIC_VALID, UNSET, UNSET) {
+ warn!("Mismatched trailer for Slot 0");
+ fails += 1;
+ }
+
+ // Run the bootloader...
+ if c::boot_go(&mut fl, &areadesc) != 0 {
+ warn!("Failed first boot");
+ fails += 1;
+ }
+
+ // State should not have changed
+ if !verify_image(&fl, images.slot0.base_off, &images.primary) {
+ warn!("Failed image verification");
+ fails += 1;
+ }
+ if !verify_trailer(&fl, images.slot0.trailer_off, MAGIC_VALID, UNSET,
+ UNSET) {
+ warn!("Mismatched trailer for Slot 0");
+ fails += 1;
+ }
+ if !verify_trailer(&fl, images.slot1.trailer_off, MAGIC_UNSET, UNSET,
+ UNSET) {
+ warn!("Mismatched trailer for Slot 1");
+ fails += 1;
+ }
+
+ if fails > 0 {
+ error!("Expected a non revert with new image");
+ }
+
+ fails > 0
+}
+
+// Tests a new image written to slot0 that already has magic and image_ok set
+// while there is no image on slot1, so no revert should ever happen...
+fn run_signfail_upgrade(flash: &SimFlash, areadesc: &AreaDesc,
+ images: &Images) -> bool {
+ let mut fl = flash.clone();
+ let mut fails = 0;
+
+ info!("Try upgrade image with bad signature");
+ c::set_flash_counter(0);
+
+ mark_upgrade(&mut fl, &images.slot0);
+ mark_permanent_upgrade(&mut fl, &images.slot0);
+ mark_upgrade(&mut fl, &images.slot1);
+
+ if !verify_trailer(&fl, images.slot0.trailer_off, MAGIC_VALID, IMAGE_OK,
+ UNSET) {
+ warn!("Mismatched trailer for Slot 0");
+ fails += 1;
+ }
+
+ // Run the bootloader...
+ if c::boot_go(&mut fl, &areadesc) != 0 {
+ warn!("Failed first boot");
+ fails += 1;
+ }
+
+ // State should not have changed
+ if !verify_image(&fl, images.slot0.base_off, &images.primary) {
+ warn!("Failed image verification");
+ fails += 1;
+ }
+ if !verify_trailer(&fl, images.slot0.trailer_off, MAGIC_VALID, IMAGE_OK,
+ UNSET) {
+ warn!("Mismatched trailer for Slot 0");
+ fails += 1;
+ }
+
+ if fails > 0 {
+ error!("Expected an upgrade failure when image has bad signature");
+ }
+
fails > 0
}
@@ -617,7 +743,8 @@
/// Install a "program" into the given image. This fakes the image header, or at least all of the
/// fields used by the given code. Returns a copy of the image that was written.
-fn install_image(flash: &mut Flash, offset: usize, len: usize) -> Vec<u8> {
+fn install_image(flash: &mut Flash, offset: usize, len: usize,
+ bad_sig: bool) -> Vec<u8> {
let offset0 = offset;
let mut tlv = make_tlv();
@@ -657,7 +784,12 @@
tlv.add_bytes(&buf);
// Get and append the TLV itself.
- buf.append(&mut tlv.make_tlv());
+ if bad_sig {
+ let good_sig = &mut tlv.make_tlv();
+ buf.append(&mut vec![0; good_sig.len()]);
+ } else {
+ buf.append(&mut tlv.make_tlv());
+ }
// Pad the block to a flash alignment (8 bytes).
while buf.len() % 8 != 0 {
@@ -780,9 +912,9 @@
trailer_off: usize,
}
-struct Images {
- slot0: SlotInfo,
- slot1: SlotInfo,
+struct Images<'a> {
+ slot0: &'a SlotInfo,
+ slot1: &'a SlotInfo,
primary: Vec<u8>,
upgrade: Vec<u8>,
}