Boot: Load image to SRAM for execution

Check the newest image's header for an SRAM load address, and if it
is present then copy the image to that address. This allows for faster
execution as well as the potential for larger images.

Signed-off-by: Oliver Swede <oli.swede@arm.com>
Change-Id: Ifbe868cb35d217086918ebeb5bb41690065b9f46
diff --git a/bl2/ext/mcuboot/bootutil/src/image_validate.c b/bl2/ext/mcuboot/bootutil/src/image_validate.c
index d7fb7cd..f6ae619 100644
--- a/bl2/ext/mcuboot/bootutil/src/image_validate.c
+++ b/bl2/ext/mcuboot/bootutil/src/image_validate.c
@@ -17,6 +17,12 @@
  * under the License.
  */
 
+/*
+ * Original code taken from mcuboot project at:
+ * https://github.com/runtimeco/mcuboot
+ * Modifications are Copyright (c) 2018 Arm Limited.
+ */
+
 #include <assert.h>
 #include <stddef.h>
 #include <inttypes.h>
@@ -47,7 +53,6 @@
     uint32_t blk_sz;
     uint32_t size;
     uint32_t off;
-    int rc;
 
     bootutil_sha256_init(&sha256_ctx);
 
@@ -63,16 +68,24 @@
      * Hash is computed over image header and image itself. No TLV is
      * included ATM.
      */
-    size = hdr->ih_img_size + hdr->ih_hdr_size;
     for (off = 0; off < size; off += blk_sz) {
         blk_sz = size - off;
         if (blk_sz > tmp_buf_sz) {
             blk_sz = tmp_buf_sz;
         }
-        rc = flash_area_read(fap, off, tmp_buf, blk_sz);
-        if (rc) {
-            return rc;
+
+#ifdef MCUBOOT_RAM_LOADING
+        if (fap == NULL) { /* The image is in SRAM */
+            memcpy(tmp_buf, (uint32_t *)(hdr->ih_load_addr + off), blk_sz);
+        } else { /* The image is in flash */
+#endif
+            if(flash_area_read(fap, off, tmp_buf, blk_sz)) {
+                return -1;
+            }
+#ifdef MCUBOOT_RAM_LOADING
         }
+#endif
+
         bootutil_sha256_update(&sha256_ctx, tmp_buf, blk_sz);
     }
     bootutil_sha256_finish(&sha256_ctx, hash_result);
@@ -115,6 +128,74 @@
 }
 #endif
 
+#ifdef MCUBOOT_RAM_LOADING
+/* Check the hash of an image after it has been copied to SRAM */
+int
+bootutil_check_hash_after_loading(struct image_header *hdr)
+{
+    uint32_t off;
+    uint32_t end;
+    int sha256_valid = 0;
+    struct image_tlv_info info;
+    struct image_tlv tlv;
+    uint8_t tmp_buf[BOOT_TMPBUF_SZ];
+    uint8_t hash[32] = {0};
+    int rc;
+    uint32_t load_address;
+    uint32_t tlv_sz;
+
+    rc = bootutil_img_hash(hdr, NULL, tmp_buf, BOOT_TMPBUF_SZ, hash, NULL, 0);
+
+    if (rc) {
+        return rc;
+    }
+
+    load_address = (uint32_t) hdr->ih_load_addr;
+
+    /* The TLVs come after the image. */
+    off = hdr->ih_img_size + hdr->ih_hdr_size;
+
+    info = *((struct image_tlv_info *)(load_address + off));
+
+    if (info.it_magic != IMAGE_TLV_INFO_MAGIC) {
+        return -1;
+    }
+    end = off + info.it_tlv_tot;
+    off += sizeof(info);
+
+    /*
+     * Traverse through all of the TLVs, performing any checks we know
+     * and are able to do.
+     */
+    for (; off < end; off += sizeof(tlv) + tlv.it_len) {
+        tlv = *((struct image_tlv *)(load_address + off));
+        tlv_sz = sizeof(tlv);
+
+        if (tlv.it_type == IMAGE_TLV_SHA256) {
+            /*
+             * Verify the SHA256 image hash. This must always be present.
+             */
+            if (tlv.it_len != sizeof(hash)) {
+                return -1;
+            }
+
+            if (memcmp(hash, (uint32_t *)(load_address + off + tlv_sz),
+                       sizeof(hash))) {
+                return -1;
+            }
+
+            sha256_valid = 1;
+        }
+    }
+
+    if (!sha256_valid) {
+        return -1;
+    }
+
+    return 0;
+}
+#endif /* MCUBOOT_RAM_LOADING */
+
 /*
  * Verify the integrity of the image.
  * Return non-zero if image could not be validated/does not validate.