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/CommonConfig.cmake b/CommonConfig.cmake
index 4b9ff8b..b70ad71 100755
--- a/CommonConfig.cmake
+++ b/CommonConfig.cmake
@@ -169,6 +169,9 @@
 	if (MCUBOOT_NO_SWAP)
 		set(LINK_TO_BOTH_MEMORY_REGION ON)
 	endif()
+	if (MCUBOOT_NO_SWAP AND MCUBOOT_RAM_LOADING)
+		message (FATAL_ERROR "Bootloader: MCUBOOT_RAM_LOADING and MCUBOOT_NO_SWAP are not supported together")
+	endif()
 else()
 	if (MCUBOOT_NO_SWAP)
 		message (FATAL_ERROR "Bootloader build is turned off, not possible to specify bootloader behavior")
diff --git a/ConfigCoreTest.cmake b/ConfigCoreTest.cmake
index d6402b0..34c901a 100644
--- a/ConfigCoreTest.cmake
+++ b/ConfigCoreTest.cmake
@@ -26,7 +26,16 @@
 set (CORE_TEST True)
 
 #BL2 bootloader(MCUBoot) related settings
-set (BL2 True)
-set (MCUBOOT_NO_SWAP False)
+if(NOT DEFINED BL2)
+	set(BL2 True)
+endif()
+
+if(NOT DEFINED MCUBOOT_NO_SWAP)
+	set(MCUBOOT_NO_SWAP False)
+endif()
+
+if(NOT DEFINED MCUBOOT_RAM_LOADING)
+	set(MCUBOOT_RAM_LOADING False)
+endif()
 
 include ("${CMAKE_CURRENT_LIST_DIR}/CommonConfig.cmake")
diff --git a/ConfigDefault.cmake b/ConfigDefault.cmake
index 343d506..360e648 100755
--- a/ConfigDefault.cmake
+++ b/ConfigDefault.cmake
@@ -16,7 +16,7 @@
 elseif(${TARGET_PLATFORM} STREQUAL "AN519")
 	set (PLATFORM_CMAKE_FILE "${CMAKE_CURRENT_LIST_DIR}/platform/ext/Mps2AN519.cmake")
 elseif(${TARGET_PLATFORM} STREQUAL "MUSCA_A")
-        set(PLATFORM_CMAKE_FILE "${CMAKE_CURRENT_LIST_DIR}/platform/ext/musca_a.cmake")
+	set(PLATFORM_CMAKE_FILE "${CMAKE_CURRENT_LIST_DIR}/platform/ext/musca_a.cmake")
 else()
 	message(FATAL_ERROR "ERROR: Target \"${TARGET_PLATFORM}\" is not supported.")
 endif()
@@ -28,7 +28,16 @@
 set (CORE_TEST False)
 
 #BL2 bootloader(MCUBoot) related settings
-set (BL2 True)
-set (MCUBOOT_NO_SWAP False)
+if(NOT DEFINED BL2)
+	set(BL2 True)
+endif()
+
+if(NOT DEFINED MCUBOOT_NO_SWAP)
+	set(MCUBOOT_NO_SWAP False)
+endif()
+
+if(NOT DEFINED MCUBOOT_RAM_LOADING)
+	set(MCUBOOT_RAM_LOADING False)
+endif()
 
 include ("${CMAKE_CURRENT_LIST_DIR}/CommonConfig.cmake")
diff --git a/ConfigRegression.cmake b/ConfigRegression.cmake
index 975a173..306d850 100755
--- a/ConfigRegression.cmake
+++ b/ConfigRegression.cmake
@@ -28,7 +28,16 @@
 set (CORE_TEST False)
 
 #BL2 bootloader(MCUBoot) related settings
-set (BL2 True)
-set (MCUBOOT_NO_SWAP False)
+if(NOT DEFINED BL2)
+	set(BL2 True)
+endif()
+
+if(NOT DEFINED MCUBOOT_NO_SWAP)
+	set(MCUBOOT_NO_SWAP False)
+endif()
+
+if(NOT DEFINED MCUBOOT_RAM_LOADING)
+	set(MCUBOOT_RAM_LOADING False)
+endif()
 
 include ("${CMAKE_CURRENT_LIST_DIR}/CommonConfig.cmake")
diff --git a/bl2/ext/mcuboot/CMakeLists.txt b/bl2/ext/mcuboot/CMakeLists.txt
index dfe60a8..0d8258b 100644
--- a/bl2/ext/mcuboot/CMakeLists.txt
+++ b/bl2/ext/mcuboot/CMakeLists.txt
@@ -134,6 +134,10 @@
 	target_compile_definitions(${PROJECT_NAME} PRIVATE MCUBOOT_NO_SWAP)
 endif()
 
+if (MCUBOOT_RAM_LOADING)
+	target_compile_definitions(${PROJECT_NAME} PRIVATE MCUBOOT_RAM_LOADING)
+endif()
+
 #Set install location. Keep original value to avoid overriding command line settings.
 if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
 	set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/install" CACHE PATH "Default install location for MCUBoot." FORCE)
diff --git a/bl2/ext/mcuboot/bl2_main.c b/bl2/ext/mcuboot/bl2_main.c
index 9adc072..c556816 100644
--- a/bl2/ext/mcuboot/bl2_main.c
+++ b/bl2/ext/mcuboot/bl2_main.c
@@ -64,9 +64,19 @@
     rc = flash_device_base(rsp->br_flash_dev_id, &flash_base);
     assert(rc == 0);
 
-    vt = (struct arm_vector_table *)(flash_base +
-                                     rsp->br_image_off +
-                                     rsp->br_hdr->ih_hdr_size);
+    if (rsp->br_hdr->ih_flags & IMAGE_F_RAM_LOAD) {
+       /* The image has been copied to SRAM, find the vector table
+        * at the load address instead of image's address in flash
+        */
+        vt = (struct arm_vector_table *)(rsp->br_hdr->ih_load_addr +
+                                         rsp->br_hdr->ih_hdr_size);
+    } else {
+        /* Using the flash address as not executing in SRAM */
+        vt = (struct arm_vector_table *)(flash_base +
+                                         rsp->br_image_off +
+                                         rsp->br_hdr->ih_hdr_size);
+    }
+
     __disable_irq();
     __set_MSP(vt->msp);
     __DSB();
diff --git a/bl2/ext/mcuboot/bootutil/include/bootutil/image.h b/bl2/ext/mcuboot/bootutil/include/bootutil/image.h
index b6a472d..306ab31 100644
--- a/bl2/ext/mcuboot/bootutil/include/bootutil/image.h
+++ b/bl2/ext/mcuboot/bootutil/include/bootutil/image.h
@@ -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.
+ */
+
 #ifndef H_IMAGE_
 #define H_IMAGE_
 
@@ -61,6 +67,11 @@
 #define IMAGE_TLV_SHA256            0x10   /* SHA256 of image hdr and body */
 #define IMAGE_TLV_RSA2048_PSS       0x20   /* RSA2048 of hash output */
 
+#define IMAGE_VER_MAJOR_LENGTH      8
+#define IMAGE_VER_MINOR_LENGTH      8
+#define IMAGE_VER_REVISION_LENGTH   16
+#define IMAGE_VER_BUILD_NUM_LENGTH  32
+
 struct image_version {
     uint8_t iv_major;
     uint8_t iv_minor;
@@ -101,6 +112,10 @@
                           uint8_t *tmp_buf, uint32_t tmp_buf_sz,
                           uint8_t *seed, int seed_len, uint8_t *out_hash);
 
+#ifdef MCUBOOT_RAM_LOADING
+int bootutil_check_hash_after_loading(struct image_header *hdr);
+#endif
+
 #ifdef __cplusplus
 }
 #endif
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.
diff --git a/bl2/ext/mcuboot/bootutil/src/loader.c b/bl2/ext/mcuboot/bootutil/src/loader.c
index edab6bb..154cd7e 100644
--- a/bl2/ext/mcuboot/bootutil/src/loader.c
+++ b/bl2/ext/mcuboot/bootutil/src/loader.c
@@ -44,7 +44,7 @@
 
 static struct boot_loader_state boot_data;
 
-#ifndef MCUBOOT_NO_SWAP
+#if !defined(MCUBOOT_NO_SWAP) && !defined(MCUBOOT_RAM_LOADING)
 struct boot_status_table {
     /**
      * For each field, a value of 0 means "any".
@@ -136,7 +136,7 @@
                   "bad"),                                           \
                  (state)->copy_done,                                \
                  (state)->image_ok)
-#endif /* !MCUBOOT_NO_SWAP */
+#endif /* !MCUBOOT_NO_SWAP && !MCUBOOT_RAM_LOADING */
 
 
 static int
@@ -361,7 +361,46 @@
 }
 #endif /* !MCUBOOT_OVERWRITE_ONLY */
 
-#ifndef MCUBOOT_NO_SWAP
+#if !defined(MCUBOOT_NO_SWAP) && !defined(MCUBOOT_OVERWRITE_ONLY)
+/*
+ * Compute the total size of the given image.  Includes the size of
+ * the TLVs.
+ */
+static int
+boot_read_image_size(int slot, struct image_header *hdr, uint32_t *size)
+{
+    const struct flash_area *fap = NULL;
+    struct image_tlv_info info;
+    int area_id;
+    int rc;
+
+    area_id = flash_area_id_from_image_slot(slot);
+    rc = flash_area_open(area_id, &fap);
+    if (rc != 0) {
+        rc = BOOT_EFLASH;
+        goto done;
+    }
+
+    rc = flash_area_read(fap, hdr->ih_hdr_size + hdr->ih_img_size,
+                         &info, sizeof(info));
+    if (rc != 0) {
+        rc = BOOT_EFLASH;
+        goto done;
+    }
+    if (info.it_magic != IMAGE_TLV_INFO_MAGIC) {
+        rc = BOOT_EBADIMAGE;
+        goto done;
+    }
+    *size = hdr->ih_hdr_size + hdr->ih_img_size + info.it_tlv_tot;
+    rc = 0;
+
+done:
+    flash_area_close(fap);
+    return rc;
+}
+#endif /* !MCUBOOT_NO_SWAP && !MCUBOOT_OVERWRITE_ONLY */
+
+#if !defined(MCUBOOT_NO_SWAP) && !defined(MCUBOOT_RAM_LOADING)
 /**
  * Determines where in flash the most recent boot status is stored. The boot
  * status is necessary for completing a swap that was interrupted by a boot
@@ -434,45 +473,6 @@
     return BOOT_SWAP_TYPE_FAIL;
 }
 
-/*
- * Compute the total size of the given image.  Includes the size of
- * the TLVs.
- */
-#ifndef MCUBOOT_OVERWRITE_ONLY
-static int
-boot_read_image_size(int slot, struct image_header *hdr, uint32_t *size)
-{
-    const struct flash_area *fap = NULL;
-    struct image_tlv_info info;
-    int area_id;
-    int rc;
-
-    area_id = flash_area_id_from_image_slot(slot);
-    rc = flash_area_open(area_id, &fap);
-    if (rc != 0) {
-        rc = BOOT_EFLASH;
-        goto done;
-    }
-
-    rc = flash_area_read(fap, hdr->ih_hdr_size + hdr->ih_img_size,
-                         &info, sizeof(info));
-    if (rc != 0) {
-        rc = BOOT_EFLASH;
-        goto done;
-    }
-    if (info.it_magic != IMAGE_TLV_INFO_MAGIC) {
-        rc = BOOT_EBADIMAGE;
-        goto done;
-    }
-    *size = hdr->ih_hdr_size + hdr->ih_img_size + info.it_tlv_tot;
-    rc = 0;
-
-done:
-    flash_area_close(fap);
-    return rc;
-}
-#endif /* !MCUBOOT_OVERWRITE_ONLY */
-
 static int
 boot_slots_compatible(void)
 {
@@ -1370,7 +1370,7 @@
     return rc;
 }
 
-#else /* MCUBOOT_NO_SWAP */
+#else /* MCUBOOT_NO_SWAP || MCUBOOT_RAM_LOADING */
 
 #define BOOT_LOG_IMAGE_INFO(area, hdr, state)                           \
     BOOT_LOG_INF("Image %"PRIu32": version=%"PRIu8".%"PRIu8".%"PRIu16"" \
@@ -1396,12 +1396,20 @@
  *
  * @param hdr  Pointer to an image header structure
  *
- * @return     Version number casted to unit64_t
+ * @return     Version number casted to uint64_t
  */
 static uint64_t
 boot_get_version_number(struct image_header *hdr)
 {
-    return *((uint64_t *)(&hdr->ih_ver));
+    uint64_t version = 0;
+    version |= (uint64_t)hdr->ih_ver.iv_major << (IMAGE_VER_MINOR_LENGTH
+                                                + IMAGE_VER_REVISION_LENGTH
+                                                + IMAGE_VER_BUILD_NUM_LENGTH);
+    version |= (uint64_t)hdr->ih_ver.iv_minor << (IMAGE_VER_REVISION_LENGTH
+                                                + IMAGE_VER_BUILD_NUM_LENGTH);
+    version |= (uint64_t)hdr->ih_ver.iv_revision << IMAGE_VER_BUILD_NUM_LENGTH;
+    version |= hdr->ih_ver.iv_build_num;
+    return version;
 }
 
 /**
@@ -1486,7 +1494,7 @@
             }
             BOOT_LOG_IMAGE_INFO(slot, hdr, &slot_state);
         } else {
-            BOOT_LOG_INF("Image  %"PRIu32": No valid image", slot);
+            BOOT_LOG_INF("Image %"PRIu32": No valid image", slot);
         }
     }
 
@@ -1504,6 +1512,73 @@
     return image_cnt;
 }
 
+#ifdef MCUBOOT_RAM_LOADING
+/**
+ * Copies an image from a slot in the flash to an SRAM address, where the load
+ * address has already been inserted into the image header by this point and is
+ * extracted from it within this method. The copying is done sector-by-sector.
+ *
+ * @param slot            The flash slot of the image to be copied to SRAM.
+ *
+ * @param hdr             Pointer to the image header structure of the image
+ *                        that needs to be copid to SRAM
+ *
+ * @return                0 on success; nonzero on failure.
+ */
+static int
+boot_copy_image_to_sram(int slot, struct image_header *hdr)
+{
+    int rc;
+    uint32_t sect_sz;
+    uint32_t sect = 0;
+    uint32_t bytes_copied = 0;
+    const struct flash_area *fap_src = NULL;
+    uint32_t dst = (uint32_t) hdr->ih_load_addr;
+    uint32_t img_sz;
+
+    if (dst % 4 != 0) {
+        BOOT_LOG_INF("Cannot copy the image to the SRAM address 0x%"PRIx32" "
+        "- the load address must be aligned with 4 bytes due to SRAM "
+        "restrictions", dst);
+        return BOOT_EBADARGS;
+    }
+
+    rc = flash_area_open(flash_area_id_from_image_slot(slot), &fap_src);
+    if (rc != 0) {
+        return BOOT_EFLASH;
+    }
+
+    rc = boot_read_image_size(slot, hdr, &img_sz);
+    if (rc != 0) {
+        return BOOT_EFLASH;
+    }
+
+    while (bytes_copied < img_sz) {
+        sect_sz = boot_img_sector_size(&boot_data, slot, sect);
+        /*
+         * Direct copy from where the image sector resides in flash to its new
+         * location in SRAM
+         */
+        rc = flash_area_read(fap_src,
+                             bytes_copied,
+                             (void *)(dst + bytes_copied),
+                             sect_sz);
+        if (rc != 0) {
+            BOOT_LOG_INF("Error whilst copying image from Flash to SRAM");
+            break;
+        } else {
+            bytes_copied += sect_sz;
+        }
+        sect++;
+    }
+
+    if (fap_src) {
+        flash_area_close(fap_src);
+    }
+    return rc;
+}
+#endif /* MCUBOOT_RAM_LOADING */
+
 /**
  * Prepares the booting process. This function choose the newer image in flash
  * as appropriate, and returns the address to boot from.
@@ -1521,6 +1596,7 @@
     int fa_id;
     uint32_t boot_sequence[BOOT_NUM_SLOTS];
     uint32_t img_cnt;
+    struct image_header *newest_image_header;
 
     static boot_sector_t slot0_sectors[BOOT_MAX_IMG_SECTORS];
     static boot_sector_t slot1_sectors[BOOT_MAX_IMG_SECTORS];
@@ -1563,10 +1639,48 @@
             goto out;
         }
 
-        BOOT_LOG_INF("Booting image from slot %d", slot);
-        rsp->br_flash_dev_id = boot_img_fa_device_id(&boot_data, slot);
+        /* The slot variable now refers to the newest image's slot in flash */
+        newest_image_header = boot_img_hdr(&boot_data, slot);
+
+        #ifdef MCUBOOT_RAM_LOADING
+        if (newest_image_header->ih_flags & IMAGE_F_RAM_LOAD) {
+            /* Copy image to the load address from where it
+             * currently resides in flash */
+            rc = boot_copy_image_to_sram(slot, newest_image_header);
+            if (rc != 0) {
+                rc = BOOT_EBADIMAGE;
+                BOOT_LOG_INF("Could not copy image from slot 0x%"PRIx32" in "
+                             "the Flash to load address 0x%"PRIx32" in SRAM, "
+                             "aborting..",
+                             slot,
+                             newest_image_header->ih_load_addr);
+                goto out;
+            } else {
+                BOOT_LOG_INF("Image has been copied from slot %d in flash to "
+                             "SRAM address 0x%"PRIx32"",
+                             slot,
+                             newest_image_header->ih_load_addr);
+            }
+
+            /* Validate the image hash in SRAM after the copy was successful */
+            rc = bootutil_check_hash_after_loading(newest_image_header);
+            if (rc != 0) {
+                rc = BOOT_EBADIMAGE;
+                BOOT_LOG_INF("Cannot validate the hash of the image that was "
+                             "copied to SRAM, aborting..");
+                goto out;
+            }
+
+            BOOT_LOG_INF("Booting image from SRAM at address 0x%"PRIx32"",
+                         newest_image_header->ih_load_addr);
+        } else {
+            BOOT_LOG_INF("Booting image from slot %d", slot);
+        }
+        #endif /* MCUBOOT_RAM_LOADING */
+
+        rsp->br_hdr = newest_image_header;
         rsp->br_image_off = boot_img_slot_off(&boot_data, slot);
-        rsp->br_hdr = boot_img_hdr(&boot_data, slot);
+        rsp->br_flash_dev_id = boot_img_fa_device_id(&boot_data, slot);
     } else {
         /* No candidate image available */
         rc = BOOT_EBADIMAGE;
@@ -1578,4 +1692,4 @@
    }
    return rc;
 }
-#endif /* MCUBOOT_NO_SWAP */
+#endif /* MCUBOOT_NO_SWAP || MCUBOOT_RAM_LOADING */
diff --git a/docs/user_guides/tfm_secure_boot.md b/docs/user_guides/tfm_secure_boot.md
index 5322457..46ea366 100644
--- a/docs/user_guides/tfm_secure_boot.md
+++ b/docs/user_guides/tfm_secure_boot.md
@@ -99,6 +99,54 @@
 modes. If new image fails during authentication then MCUBoot erases the memory
 slot and starts the other image, after successful authentication.
 
+At build time automatically two binaries are generated:
+```
+<build_dir>/install/outputs/fvp/tfm_s_ns_signed_0.bin : Image linked for slot 0
+                                                        memory partition
+<build_dir>/install/outputs/fvp/tfm_s_ns_signed_1.bin : Image linked for slot 1
+                                                        memory partition
+```
+
+### RAM Loading firmware upgrade
+Musca A1 supports an image upgrade mode that is separate to both the swapping
+and non-swapping modes. This is the `RAM loading` mode (please refer to the
+table below). Like the non-swapping mode, this selects the newest image by
+reading the image version numbers in the image headers, but instead of
+executing it in place, the newest image is copied to RAM for execution. The
+load address, the location in RAM where the image is copied to, is stored
+in the image header.
+
+### Summary of different modes for image upgrade
+
+Different implementations of the image upgrade operation (whether through
+swapping, non-swapping, or loading into RAM and executing from there)
+are supported by the platforms. The table below shows which of these modes
+are supported by which platforms:
+
+|    -     | Without BL2 <sup>1</sup> | With BL2 <sup>2</sup> | With BL2 <sup>2</sup> |   With BL2 <sup>2</sup>  |
+|:--------:|:------------------------:|:---------------------:|:---------------------:|:------------------------:|
+|    -     |            XIP           |          XIP          |          XIP          |         Not XIP          |
+|    -     |             -            |   Swap <sup>3</sup>   |  No-swap <sup>4</sup> | RAM loading <sup>5</sup> |
+|  AN521   |            Yes           |          Yes          |          Yes          |            No            |
+|  AN519   |            Yes           |          Yes          |          Yes          |            No            |
+| Musca A1 |            No            |          No           |          No           |            Yes           |
+
+(1) To disable BL2, please turn off the `BL2` compiler switch in the
+top-level configuration files or in the command line
+
+(2) BL2 is enabled by default
+
+(3) The image executes in-place (XIP) and is in swapping mode for image update
+by default
+
+(4) To enable XIP No-swap, set the configuration variable `MCUBOOT_NO_SWAP` to
+`True` in the top-level configuration files, or include the `MCUBOOT_NO_SWAP`
+macro in the command line
+
+(5) To enable RAM loading, set the configuration variable `MCUBOOT_RAM_LOADING`
+to `True` in the top-level configuration files, or include the
+`MCUBOOT_RAM_LOADING` macro in the command line
+
 ## Build time configuration
 MCUBoot related compile time switches can be set in the high level build
 configuration files:
@@ -119,6 +167,11 @@
 - MCUBOOT\_NO\_SWAP (default: False):
   - **True:** Activate non-swapping firmware upgrade operation.
   - **False:** Original firmware upgrade operation with image swapping.
+- MCUBOOT\_RAM\_LOADING (default: False):
+  - **True:** Activate RAM loading firmware upgrade operation, where latest
+  image is copied to RAM and runs from there instead of being executed
+  in-place.
+  - **False:** Original firmware upgrade operation with image swapping.
 
 ### Image versioning
 An image version number is written to its header by one of the python scripts,
@@ -143,15 +196,8 @@
 stop incrementing. Any new version numbers that are provided will overwrite
 the previous one: 0.0.0+1 -> 0.0.0+2. Note: To re-apply automatic image
 versioning, please start a clean build without specifying the image version
-number at all
+number at all.
 
-At build time automatically two binaries are generated:
-```
-<build_dir>/install/outputs/fvp/tfm_s_ns_signed_0.bin : Image linked for slot 0
-                                                        memory partition
-<build_dir>/install/outputs/fvp/tfm_s_ns_signed_1.bin : Image linked for slot 1
-                                                        memory partition
-```
 ## Testing firmware upgrade
 As downloading the new firmware image is out of scope for MCUBoot, the update
 process is started from a state where the original and the new image are already
@@ -219,7 +265,7 @@
 - Set MCUBOOT\_NO\_SWAP compile time switch to true before build.
 - Increase the image version number between the two build run.
 
-### Executing firmware upgrade on FVP\_MPS2\_AEMv8M
+#### Executing firmware upgrade on FVP\_MPS2\_AEMv8M
 ```
 <DS5_PATH>/sw/models/bin/FVP_MPS2_AEMv8M  \
 --parameter fvp_mps2.platform_type=2 \
@@ -238,7 +284,7 @@
 --data cpu0=<regresssion_build_dir>/install/outputs/fvp/tfm_s_ns_signed_1.bin@0x10180000
 ```
 
-### Executing firmware upgrade on SSE 200 FPGA on MPS2 board
+#### Executing firmware upgrade on SSE 200 FPGA on MPS2 board
 ```
 TITLE: Versatile Express Images Configuration File
 [IMAGES]
@@ -267,7 +313,42 @@
 ...
 ```
 
-*Note* Firmware upgrade support for Musca-A1 board is not yet supported.
+#### Executing firmware upgrade on Musca-A1 board
+To enable RAM loading, please set `MCUBOOT_RAM_LOADING` to True (either in the
+configuration file or through the command line), and then specify a destination
+load address in RAM where the image can be copied to and executed from. The
+`IMAGE_LOAD_ADDRESS` macro must be specified in the target dependent files,
+for example with Musca A1, its `flash_layout.h` file in the `platform`
+folder should include `#define IMAGE_LOAD_ADDRESS #0x10020000`
+
+After two images have been built, they can be concatenated to create the
+combined image using srec_cat.exe
+
+```
+Windows:
+srec_cat.exe bl2\ext\mcuboot\mcuboot.bin -Binary -offset 0x200000
+tfm_sign_old.bin -Binary -offset 0x220000 tfm_sign_new.bin -Binary -offset
+0x320000 -o tfm.hex -Intel
+
+Linux:
+srec_cat bl2/ext/mcuboot/mcuboot.bin -Binary -offset 0x200000 tfm_sign_old.bin
+-Binary -offset 0x220000 tfm_sign_new.bin -Binary -offset
+0x320000 -o tfm.hex -Intel
+```
+
+The following message will be shown in case of successful firmware upgrade when,
+RAM loading is enabled, notice that image with higher version number
+(`version=0.0.0.2`) is executed:
+
+```
+[INF] Image 0: version=0.0.0.1, magic= good, image_ok=0xff
+[INF] Image 1: version=0.0.0.2, magic= good, image_ok=0xff
+[INF] Image has been copied from slot 1 in flash to SRAM address 0x10020000
+[INF] Booting image from SRAM at address 0x10020000
+[INF] Bootloader chainload address offset: 0x20000
+[INF] Jumping to the first image slot
+[Sec Thread] Secure image initializing!
+```
 
 --------------
 
diff --git a/platform/ext/Mps2AN519.cmake b/platform/ext/Mps2AN519.cmake
index 9ea34b8..a9d1144 100755
--- a/platform/ext/Mps2AN519.cmake
+++ b/platform/ext/Mps2AN519.cmake
@@ -148,3 +148,7 @@
   set(SST_RAM_FS True)
   embedded_include_directories(PATH "${PLATFORM_DIR}/target/mps2/an519/cmsis_drivers" ABSOLUTE)
 endif()
+
+if (MCUBOOT_RAM_LOADING)
+	message (FATAL_ERROR "MCUBOOT_RAM_LOADING is not supported on " ${TARGET_PLATFORM})
+endif()
\ No newline at end of file
diff --git a/platform/ext/Mps2AN521.cmake b/platform/ext/Mps2AN521.cmake
index 0b82a18..ec4d194 100755
--- a/platform/ext/Mps2AN521.cmake
+++ b/platform/ext/Mps2AN521.cmake
@@ -149,3 +149,7 @@
   set(SST_RAM_FS True)
   embedded_include_directories(PATH "${PLATFORM_DIR}/target/mps2/an521/cmsis_drivers" ABSOLUTE)
 endif()
+
+if (MCUBOOT_RAM_LOADING)
+	message (FATAL_ERROR "MCUBOOT_RAM_LOADING is not supported on " ${TARGET_PLATFORM})
+endif()
\ No newline at end of file
diff --git a/platform/ext/musca_a.cmake b/platform/ext/musca_a.cmake
index d0b76e9..9a17143 100755
--- a/platform/ext/musca_a.cmake
+++ b/platform/ext/musca_a.cmake
@@ -146,3 +146,17 @@
   set(SST_RAM_FS True)
   embedded_include_directories(PATH "${PLATFORM_DIR}/target/musca_a/CMSIS_Driver" ABSOLUTE)
 endif()
+
+if (NOT BL2)
+	message(STATUS "WARNING: BL2 is mandatory on target \"${TARGET_PLATFORM}\" Your choice was override.")
+	set(BL2 True)
+endif()
+
+if (NOT MCUBOOT_RAM_LOADING)
+	message(STATUS "WARNING: MCUBOOT_RAM_LOADING is mandatory on target \"${TARGET_PLATFORM}\" Your choice was override.")
+	set(MCUBOOT_RAM_LOADING True)
+endif()
+
+if (MCUBOOT_NO_SWAP)
+	message (FATAL_ERROR "MCUBOOT_NO_SWAP configuration is not supported on " ${TARGET_PLATFORM})
+endif()
\ No newline at end of file
diff --git a/platform/ext/target/musca_a/Device/Source/armclang/musca_s.sct b/platform/ext/target/musca_a/Device/Source/armclang/musca_s.sct
index ca2bea7..46fff6d 100755
--- a/platform/ext/target/musca_a/Device/Source/armclang/musca_s.sct
+++ b/platform/ext/target/musca_a/Device/Source/armclang/musca_s.sct
@@ -150,16 +150,3 @@
     ER_NS_PARTITION NS_PARTITION_START EMPTY NS_PARTITION_SIZE {
     }
 }
-
-#ifdef BL2
-LR_SECONDARY_PARTITION SECONDARY_PARTITION_START {
-    /* Reserved place for new image in case of firmware upgrade.
-     * No code will be placed here, just address of this region is used in the
-     * secure code to configure certain HW components.
-     */
-    ER_SECONDARY_PARTITION SECONDARY_PARTITION_START \
-        EMPTY SECONDARY_PARTITION_SIZE {
-    }
-}
-#endif /* BL2 */
-
diff --git a/platform/ext/target/musca_a/target_cfg.c b/platform/ext/target/musca_a/target_cfg.c
index 4d3ba6b..8bf4962 100755
--- a/platform/ext/target/musca_a/target_cfg.c
+++ b/platform/ext/target/musca_a/target_cfg.c
@@ -30,9 +30,7 @@
 REGION_DECLARE(Load$$LR$$, LR_NS_PARTITION, $$Base);
 REGION_DECLARE(Load$$LR$$, LR_VENEER, $$Base);
 REGION_DECLARE(Load$$LR$$, LR_VENEER, $$Limit);
-#ifdef BL2
 REGION_DECLARE(Load$$LR$$, LR_SECONDARY_PARTITION, $$Base);
-#endif /* BL2 */
 
 const struct memory_region_limits memory_regions = {
     .non_secure_code_start =
@@ -51,15 +49,6 @@
 
     .veneer_limit =
         (uint32_t)&REGION_NAME(Load$$LR$$, LR_VENEER, $$Limit),
-
-#ifdef BL2
-    .secondary_partition_base =
-        (uint32_t)&REGION_NAME(Load$$LR$$, LR_SECONDARY_PARTITION, $$Base),
-
-    .secondary_partition_limit =
-        (uint32_t)&REGION_NAME(Load$$LR$$, LR_SECONDARY_PARTITION, $$Base) +
-        SECONDARY_PARTITION_SIZE - 1,
-#endif /* BL2 */
 };
 
 /* Allows software, via SAU, to define the code region as a NSC */
@@ -157,13 +146,9 @@
     SAU->RLAR = (PERIPHERALS_BASE_NS_END & SAU_RLAR_LADDR_Msk)
                 | SAU_RLAR_ENABLE_Msk;
 
-#ifdef BL2
-    /* Secondary image partition */
-    SAU->RNR  = TFM_NS_SECONDARY_IMAGE_REGION;
-    SAU->RBAR = (memory_regions.secondary_partition_base  & SAU_RBAR_BADDR_Msk);
-    SAU->RLAR = (memory_regions.secondary_partition_limit & SAU_RLAR_LADDR_Msk)
-                | SAU_RLAR_ENABLE_Msk;
-#endif /* BL2 */
+    /* FIXME: Secondary image partition info comes from BL2. Configure SAU
+     * based on those limits.
+     */
 
     /* Allows SAU to define the code region as a NSC */
     struct spctrl_def* spctrl = CMSDK_SPCTRL;
diff --git a/platform/ext/target/musca_a/target_cfg.h b/platform/ext/target/musca_a/target_cfg.h
index a0d6560..c63b23d 100755
--- a/platform/ext/target/musca_a/target_cfg.h
+++ b/platform/ext/target/musca_a/target_cfg.h
@@ -53,10 +53,6 @@
     uint32_t non_secure_partition_limit;
     uint32_t veneer_base;
     uint32_t veneer_limit;
-#ifdef BL2
-    uint32_t secondary_partition_base;
-    uint32_t secondary_partition_limit;
-#endif /* BL2 */
 };
 
 /**