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>,
 }