boot: Add ram-load upgrade mode
This patch introduces the ram-load mode in addition to the other
upgrade modes (swap strategies, overwrite-only, direct-XIP). When
ram-load is enabled with the MCUBOOT_RAM_LOAD option, mcuboot
selects the newest valid image based on the image version numbers from
the image header, thereafter the selected image loaded to the RAM and
executed from there. Load address is extracted from the image header.
Therefore the images must be linked to the RAM memory region.
The ram-load mode is very similar to the direct-XIP mode, main
difference is to load the newest image to the RAM beforehand the
authentication and execution. Similar to direct-XIP mode either
of the primary and the secondary slots can hold the active image.
Ram-load can be useful in case of a bit more powerful SoC, which
is not constrained in terms of internal RAM. It could be that image
is stored in external and therefore untrusted flash. Loading image
to internal (trusted) RAM is essential from the security point
of view the system. Furthermore execution from internal RAM is much
faster than from external flash.
This patch is based on the RAM_LOADING upgrade strategy which was
first introduced in the Trusted Firmware-M project.
Source TF-M version: TF-Mv1.0.
Change-Id: I95f02ff07c1dee51244ac372284f449c2efab362
Signed-off-by: Tamas Ban <tamas.ban@arm.com>
diff --git a/boot/bootutil/src/bootutil_priv.h b/boot/bootutil/src/bootutil_priv.h
index 171b409..fe96113 100644
--- a/boot/bootutil/src/bootutil_priv.h
+++ b/boot/bootutil/src/bootutil_priv.h
@@ -28,6 +28,8 @@
#ifndef H_BOOTUTIL_PRIV_
#define H_BOOTUTIL_PRIV_
+#include <string.h>
+
#include "sysflash/sysflash.h"
#include <flash_map_backend/flash_map_backend.h>
@@ -68,13 +70,15 @@
#if (defined(MCUBOOT_OVERWRITE_ONLY) + \
defined(MCUBOOT_SWAP_USING_MOVE) + \
- defined(MCUBOOT_DIRECT_XIP)) > 1
-#error "Please enable only one of MCUBOOT_OVERWRITE_ONLY, MCUBOOT_SWAP_USING_MOVE or MCUBOOT_DIRECT_XIP"
+ defined(MCUBOOT_DIRECT_XIP) + \
+ defined(MCUBOOT_RAM_LOAD)) > 1
+#error "Please enable only one of MCUBOOT_OVERWRITE_ONLY, MCUBOOT_SWAP_USING_MOVE, MCUBOOT_DIRECT_XIP or MCUBOOT_RAM_LOAD"
#endif
#if !defined(MCUBOOT_OVERWRITE_ONLY) && \
!defined(MCUBOOT_SWAP_USING_MOVE) && \
- !defined(MCUBOOT_DIRECT_XIP)
+ !defined(MCUBOOT_DIRECT_XIP) && \
+ !defined(MCUBOOT_RAM_LOAD)
#define MCUBOOT_SWAP_USING_SCRATCH 1
#endif
@@ -170,18 +174,18 @@
_Static_assert(BOOT_IMAGE_NUMBER > 0, "Invalid value for BOOT_IMAGE_NUMBER");
-#if !defined(MCUBOOT_DIRECT_XIP)
-#define IS_IN_XIP_MODE() 0
+#if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)
+#define ARE_SLOTS_EQUIVALENT() 0
#else
-#define IS_IN_XIP_MODE() 1
+#define ARE_SLOTS_EQUIVALENT() 1
#if (BOOT_IMAGE_NUMBER != 1)
-#error "The MCUBOOT_DIRECT_XIP mode only supports single-image boot (MCUBOOT_IMAGE_NUMBER=1)."
+#error "The MCUBOOT_DIRECT_XIP and MCUBOOT_RAM_LOAD mode only supports single-image boot (MCUBOOT_IMAGE_NUMBER=1)."
#endif
#ifdef MCUBOOT_ENC_IMAGES
-#error "Image encryption (MCUBOOT_ENC_IMAGES) is not supported when MCUBOOT_DIRECT_XIP mode is selected."
+#error "Image encryption (MCUBOOT_ENC_IMAGES) is not supported when MCUBOOT_DIRECT_XIP or MCUBOOT_RAM_LOAD mode is selected."
#endif
-#endif /* MCUBOOT_DIRECT_XIP */
+#endif /* MCUBOOT_DIRECT_XIP || MCUBOOT_RAM_LOAD */
#define BOOT_MAX_IMG_SECTORS MCUBOOT_MAX_IMG_SECTORS
@@ -439,6 +443,15 @@
#endif /* !defined(MCUBOOT_USE_FLASH_AREA_GET_SECTORS) */
+#ifdef MCUBOOT_RAM_LOAD
+#define LOAD_IMAGE_DATA(hdr, fap, start, output, size) \
+ (memcpy((output),(void*)((hdr)->ih_load_addr + (start)), \
+ (size)) != (output))
+#else
+#define LOAD_IMAGE_DATA(hdr, fap, start, output, size) \
+ (flash_area_read((fap), (start), (output), (size)))
+#endif /* MCUBOOT_RAM_LOAD */
+
#ifdef __cplusplus
}
#endif
diff --git a/boot/bootutil/src/image_validate.c b/boot/bootutil/src/image_validate.c
index 7071d7d..b5d259a 100644
--- a/boot/bootutil/src/image_validate.c
+++ b/boot/bootutil/src/image_validate.c
@@ -73,12 +73,18 @@
uint32_t blk_off;
uint32_t tlv_off;
-#if (BOOT_IMAGE_NUMBER == 1) || !defined(MCUBOOT_ENC_IMAGES)
+#if (BOOT_IMAGE_NUMBER == 1) || !defined(MCUBOOT_ENC_IMAGES) || \
+ defined(MCUBOOT_RAM_LOAD)
(void)enc_state;
(void)image_index;
(void)hdr_size;
(void)blk_off;
(void)tlv_off;
+#ifdef MCUBOOT_RAM_LOAD
+ (void)blk_sz;
+ (void)off;
+ (void)rc;
+#endif
#endif
#ifdef MCUBOOT_ENC_IMAGES
@@ -105,6 +111,9 @@
/* If protected TLVs are present they are also hashed. */
size += hdr->ih_protect_tlv_size;
+#ifdef MCUBOOT_RAM_LOAD
+ bootutil_sha256_update(&sha256_ctx,(void*)(hdr->ih_load_addr), size);
+#else
for (off = 0; off < size; off += blk_sz) {
blk_sz = size - off;
if (blk_sz > tmp_buf_sz) {
@@ -139,6 +148,7 @@
#endif
bootutil_sha256_update(&sha256_ctx, tmp_buf, blk_sz);
}
+#endif /* MCUBOOT_RAM_LOAD */
bootutil_sha256_finish(&sha256_ctx, hash_result);
return 0;
@@ -291,7 +301,7 @@
return BOOT_EBADIMAGE;
}
- rc = flash_area_read(fap, off, img_security_cnt, len);
+ rc = LOAD_IMAGE_DATA(hdr, fap, off, img_security_cnt, len);
if (rc != 0) {
return BOOT_EFLASH;
}
@@ -367,7 +377,7 @@
if (len != sizeof(hash)) {
return -1;
}
- rc = flash_area_read(fap, off, buf, sizeof hash);
+ rc = LOAD_IMAGE_DATA(hdr, fap, off, buf, sizeof(hash));
if (rc) {
return rc;
}
@@ -385,7 +395,7 @@
if (len > 32) {
return -1;
}
- rc = flash_area_read(fap, off, buf, len);
+ rc = LOAD_IMAGE_DATA(hdr, fap, off, buf, len);
if (rc) {
return rc;
}
@@ -402,7 +412,7 @@
if (len > sizeof(key_buf)) {
return -1;
}
- rc = flash_area_read(fap, off, key_buf, len);
+ rc = LOAD_IMAGE_DATA(hdr, fap, off, key_buf, len);
if (rc) {
return rc;
}
@@ -421,7 +431,7 @@
if (!EXPECTED_SIG_LEN(len) || len > sizeof(buf)) {
return -1;
}
- rc = flash_area_read(fap, off, buf, len);
+ rc = LOAD_IMAGE_DATA(hdr, fap, off, buf, len);
if (rc) {
return -1;
}
@@ -442,7 +452,7 @@
return -1;
}
- rc = flash_area_read(fap, off, &img_security_cnt, len);
+ rc = LOAD_IMAGE_DATA(hdr, fap, off, &img_security_cnt, len);
if (rc) {
return rc;
}
diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c
index c98b841..5a3de4f 100644
--- a/boot/bootutil/src/loader.c
+++ b/boot/bootutil/src/loader.c
@@ -101,12 +101,12 @@
return 0;
}
-#ifndef MCUBOOT_DIRECT_XIP
+#if !defined(MCUBOOT_DIRECT_XIP)
/*
* Compute the total size of the given image. Includes the size of
* the TLVs.
*/
-#if !defined(MCUBOOT_OVERWRITE_ONLY) || defined(MCUBOOT_OVERWRITE_ONLY_FAST)
+#if !defined(MCUBOOT_OVERWRITE_ONLY) || defined(MCUBOOT_OVERWRITE_ONLY_FAST)
static int
boot_read_image_size(struct boot_loader_state *state, int slot, uint32_t *size)
{
@@ -165,6 +165,7 @@
}
#endif /* !MCUBOOT_OVERWRITE_ONLY */
+#if !defined(MCUBOOT_RAM_LOAD)
static uint32_t
boot_write_sz(struct boot_loader_state *state)
{
@@ -379,6 +380,7 @@
flash_area_close(fap);
return rc;
}
+#endif /* !MCUBOOT_RAM_LOAD */
#endif /* !MCUBOOT_DIRECT_XIP */
/*
@@ -421,7 +423,7 @@
return 0;
}
-#ifndef MCUBOOT_DIRECT_XIP
+#if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)
static int
split_image_check(struct image_header *app_hdr,
const struct flash_area *app_fap,
@@ -450,7 +452,7 @@
return 0;
}
-#endif /* !MCUBOOT_DIRECT_XIP */
+#endif /* !MCUBOOT_DIRECT_XIP && !MCUBOOT_RAM_LOAD */
/*
* Check that this is a valid header. Valid means that the magic is
@@ -522,6 +524,7 @@
#if (BOOT_IMAGE_NUMBER > 1) || \
defined(MCUBOOT_DIRECT_XIP) || \
+ defined(MCUBOOT_RAM_LOAD) || \
(defined(MCUBOOT_OVERWRITE_ONLY) && defined(MCUBOOT_DOWNGRADE_PREVENTION))
/**
* Compare image version numbers not including the build number
@@ -630,7 +633,7 @@
#endif
if (!boot_is_header_valid(hdr, fap) || boot_image_check(state, hdr, fap, bs)) {
- if ((slot != BOOT_PRIMARY_SLOT) || IS_IN_XIP_MODE()) {
+ if ((slot != BOOT_PRIMARY_SLOT) || ARE_SLOTS_EQUIVALENT()) {
flash_area_erase(fap, 0, fap->fa_size);
/* Image is invalid, erase it to prevent further unnecessary
* attempts to validate and boot it.
@@ -697,7 +700,7 @@
}
#endif /* MCUBOOT_HW_ROLLBACK_PROT */
-#ifndef MCUBOOT_DIRECT_XIP
+#if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)
/**
* Determines which swap operation to perform, if any. If it is determined
* that a swap operation is required, the image in the secondary slot is checked
@@ -1932,7 +1935,7 @@
return rc;
}
-#else /* MCUBOOT_DIRECT_XIP */
+#else /* MCUBOOT_DIRECT_XIP || MCUBOOT_RAM_LOAD */
/**
* Iterates over all slots and determines which contain a firmware image.
@@ -1975,6 +1978,149 @@
return image_cnt;
}
+#ifdef MCUBOOT_RAM_LOAD
+
+#if !defined(IMAGE_EXECUTABLE_RAM_START) || !defined(IMAGE_EXECUTABLE_RAM_SIZE)
+#error "Platform MUST define executable RAM bounds in case of RAM_LOAD"
+#endif
+
+/**
+ * Verifies that the image in a slot will be loaded within the predefined bounds
+ * that are allowed to be used by executable images.
+ *
+ * @param img_dst The address to which the image is going to be copied.
+ * @param img_sz The size of the image.
+ *
+ * @return 0 on success; nonzero on failure.
+ */
+static int
+boot_verify_ram_load_address(uint32_t img_dst, uint32_t img_sz)
+{
+ uint32_t img_end_addr;
+
+ if (img_dst < IMAGE_EXECUTABLE_RAM_START) {
+ return BOOT_EBADIMAGE;
+ }
+
+ if (!boot_u32_safe_add(&img_end_addr, img_dst, img_sz)) {
+ return BOOT_EBADIMAGE;
+ }
+
+ if (img_end_addr > (IMAGE_EXECUTABLE_RAM_START +
+ IMAGE_EXECUTABLE_RAM_SIZE)) {
+ return BOOT_EBADIMAGE;
+ }
+
+ return 0;
+}
+
+/**
+ * Copies an image from a slot in the flash to an SRAM address.
+ *
+ * @param slot The flash slot of the image to be copied to SRAM.
+ * @param img_dst The address at which the image needs to be copied to
+ * SRAM.
+ * @param img_sz The size of the image that needs to be copied to SRAM.
+ *
+ * @return 0 on success; nonzero on failure.
+ */
+static int
+boot_copy_image_to_sram(int slot, uint32_t img_dst, uint32_t img_sz)
+{
+ int rc;
+ const struct flash_area *fap_src = NULL;
+
+ rc = flash_area_open(flash_area_id_from_image_slot(slot), &fap_src);
+ if (rc != 0) {
+ return BOOT_EFLASH;
+ }
+
+ /* Direct copy from flash to its new location in SRAM. */
+ rc = flash_area_read(fap_src, 0, (void *)img_dst, img_sz);
+ if (rc != 0) {
+ BOOT_LOG_INF("Error whilst copying image from Flash to SRAM: %d", rc);
+ }
+
+ flash_area_close(fap_src);
+
+ return rc;
+}
+
+/**
+ * Copies an image from a slot in the flash to an SRAM address. The load
+ * address and image size is extracted from the image header.
+ *
+ * @param state Boot loader status information.
+ * @param slot The flash slot of the image to be copied to SRAM.
+ * @param hdr Pointer to the image header structure of the image
+ * @param img_dst Pointer to the address at which the image needs to be
+ * copied to SRAM.
+ * @param img_sz Pointer to the size of the image that needs to be
+ * copied to SRAM.
+ *
+ * @return 0 on success; nonzero on failure.
+ */
+static int
+boot_load_image_to_sram(struct boot_loader_state *state, uint32_t slot,
+ struct image_header *hdr, uint32_t *img_dst,
+ uint32_t *img_sz)
+{
+ int rc;
+
+ if (hdr->ih_flags & IMAGE_F_RAM_LOAD) {
+
+ *img_dst = hdr->ih_load_addr;
+
+ rc = boot_read_image_size(state, slot, img_sz);
+ if (rc != 0) {
+ return rc;
+ }
+
+ rc = boot_verify_ram_load_address(*img_dst, *img_sz);
+ if (rc != 0) {
+ BOOT_LOG_INF("Image RAM load address 0x%x is invalid.", *img_dst);
+ return rc;
+ }
+
+ /* Copy image to the load address from where it currently resides in
+ * flash.
+ */
+ rc = boot_copy_image_to_sram(slot, *img_dst, *img_sz);
+ if (rc != 0) {
+ BOOT_LOG_INF("RAM loading to 0x%x is failed.", *img_dst);
+ } else {
+ BOOT_LOG_INF("RAM loading to 0x%x is succeeded.", *img_dst);
+ }
+ } else {
+ /* Only images that support IMAGE_F_RAM_LOAD are allowed if
+ * MCUBOOT_RAM_LOAD is set.
+ */
+ rc = BOOT_EBADIMAGE;
+ }
+
+ return rc;
+}
+
+/**
+ * Removes an image from SRAM, by overwriting it with zeros.
+ *
+ * @param img_dst The address of the image that needs to be removed from
+ * SRAM.
+ * @param img_sz The size of the image that needs to be removed from
+ * SRAM.
+ *
+ * @return 0 on success; nonzero on failure.
+ */
+static inline int
+boot_remove_image_from_sram(uint32_t img_dst, uint32_t img_sz)
+{
+ BOOT_LOG_INF("Removing image from SRAM at address 0x%x", img_dst);
+ memset((void*)img_dst, 0, img_sz);
+
+ return 0;
+}
+#endif /* MCUBOOT_RAM_LOAD */
+
int
context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp)
{
@@ -1987,6 +2133,11 @@
uint32_t i;
int fa_id;
int rc;
+#ifdef MCUBOOT_RAM_LOAD
+ uint32_t img_dst;
+ uint32_t img_sz;
+ uint32_t img_loaded = 0;
+#endif /* MCUBOOT_RAM_LOAD */
memset(state, 0, sizeof(struct boot_loader_state));
@@ -2036,7 +2187,22 @@
selected_image_header = hdr;
}
}
-
+#ifdef MCUBOOT_RAM_LOAD
+ /* Image is first loaded to RAM and authenticated there in order to
+ * prevent TOCTOU attack during image copy. This could be applied
+ * when loading images from external (untrusted) flash to internal
+ * (trusted) RAM and image is authenticated before copying.
+ */
+ rc = boot_load_image_to_sram(state, selected_slot,
+ selected_image_header, &img_dst,
+ &img_sz);
+ if (rc != 0 ) {
+ /* Image loading failed try the next one. */
+ continue;
+ } else {
+ img_loaded = 1;
+ }
+#endif /* MCUBOOT_RAM_LOAD */
rc = boot_validate_slot(state, selected_slot, NULL);
if (rc == 0) {
/* If a valid image is found then there is no reason to check
@@ -2045,6 +2211,15 @@
*/
break;
}
+#ifdef MCUBOOT_RAM_LOAD
+ else if (img_loaded) {
+ /* If an image is found to be invalid then it is removed from
+ * RAM to prevent it being a shellcode vector.
+ */
+ boot_remove_image_from_sram(img_dst, img_sz);
+ img_loaded = 0;
+ }
+#endif /* MCUBOOT_RAM_LOAD */
/* The selected image is invalid, mark its slot as "unused"
* and start over.
*/
@@ -2106,7 +2281,7 @@
}
return rc;
}
-#endif /* MCUBOOT_DIRECT_XIP */
+#endif /* MCUBOOT_DIRECT_XIP || MCUBOOT_RAM_LOAD */
/**
* Prepares the booting process. This function moves images around in flash as
diff --git a/boot/bootutil/src/swap_misc.c b/boot/bootutil/src/swap_misc.c
index 4c19d56..44b364d 100644
--- a/boot/bootutil/src/swap_misc.c
+++ b/boot/bootutil/src/swap_misc.c
@@ -32,7 +32,6 @@
MCUBOOT_LOG_MODULE_DECLARE(mcuboot);
#if defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SWAP_USING_MOVE)
-
int
swap_erase_trailer_sectors(const struct boot_loader_state *state,
const struct flash_area *fap)
diff --git a/boot/bootutil/src/swap_scratch.c b/boot/bootutil/src/swap_scratch.c
index e60d93d..ed88dc8 100644
--- a/boot/bootutil/src/swap_scratch.c
+++ b/boot/bootutil/src/swap_scratch.c
@@ -82,7 +82,7 @@
return rc;
}
-#if !defined(MCUBOOT_DIRECT_XIP)
+#if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)
/**
* Reads the status of a partially-completed swap, if any. This is necessary
* to recover in case the boot lodaer was reset in the middle of a swap
@@ -724,6 +724,6 @@
}
#endif /* !MCUBOOT_OVERWRITE_ONLY */
-#endif /* !MCUBOOT_DIRECT_XIP */
+#endif /* !MCUBOOT_DIRECT_XIP && !MCUBOOT_RAM_LOAD */
#endif /* !MCUBOOT_SWAP_USING_MOVE */
diff --git a/boot/bootutil/src/tlv.c b/boot/bootutil/src/tlv.c
index 514121b..37d12a3 100644
--- a/boot/bootutil/src/tlv.c
+++ b/boot/bootutil/src/tlv.c
@@ -2,6 +2,7 @@
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2019 JUUL Labs
+ * Copyright (c) 2020 Arm Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -46,7 +47,7 @@
}
off_ = BOOT_TLV_OFF(hdr);
- if (flash_area_read(fap, off_, &info, sizeof(info))) {
+ if (LOAD_IMAGE_DATA(hdr, fap, off_, &info, sizeof(info))) {
return -1;
}
@@ -55,7 +56,8 @@
return -1;
}
- if (flash_area_read(fap, off_ + info.it_tlv_tot, &info, sizeof(info))) {
+ if (LOAD_IMAGE_DATA(hdr, fap, off_ + info.it_tlv_tot,
+ &info, sizeof(info))) {
return -1;
}
} else if (hdr->ih_protect_tlv_size != 0) {
@@ -105,7 +107,7 @@
it->tlv_off += sizeof(struct image_tlv_info);
}
- rc = flash_area_read(it->fap, it->tlv_off, &tlv, sizeof tlv);
+ rc = LOAD_IMAGE_DATA(it->hdr, it->fap, it->tlv_off, &tlv, sizeof tlv);
if (rc) {
return -1;
}
diff --git a/samples/mcuboot_config/mcuboot_config.template.h b/samples/mcuboot_config/mcuboot_config.template.h
index 72e33eb..048ab18 100644
--- a/samples/mcuboot_config/mcuboot_config.template.h
+++ b/samples/mcuboot_config/mcuboot_config.template.h
@@ -58,6 +58,9 @@
/* Uncomment to enable the direct-xip code path. */
/* #define MCUBOOT_DIRECT_XIP */
+/* Uncomment to enable the ram-load code path. */
+/* #define MCUBOOT_RAM_LOAD */
+
/*
* Cryptographic settings
*
diff --git a/docs/design.md b/scripts/imgtool/design.md
similarity index 95%
rename from docs/design.md
rename to scripts/imgtool/design.md
index 697243a..f0a856e 100644
--- a/docs/design.md
+++ b/scripts/imgtool/design.md
@@ -168,12 +168,13 @@
contains two image slots: a primary slot and a secondary slot.
Normally, the boot loader will only run an image from the primary slot, so
images must be built such that they can run from that fixed location in flash
-(the exception to this is the [direct-xip](#direct-xip) upgrade mode). If the
-boot loader needs to run the image resident in the secondary slot, it must copy
-its contents into the primary slot before doing so, either by swapping the two
-images or by overwriting the contents of the primary slot. The bootloader
-supports either swap- or overwrite-based image upgrades, but must be configured
-at build time to choose one of these two strategies.
+(the exception to this is the [direct-xip](#direct-xip) and the
+[ram-load](#ram-load) upgrade mode). If the boot loader needs to run the
+image resident in the secondary slot, it must copy its contents into the primary
+slot before doing so, either by swapping the two images or by overwriting the
+contents of the primary slot. The bootloader supports either swap- or
+overwrite-based image upgrades, but must be configured at build time to choose
+one of these two strategies.
In addition to the slots of image areas, the boot loader requires a scratch
area to allow for reliable image swapping. The scratch area must have a size
@@ -244,6 +245,35 @@
reason, the rest of the document describes its behavior when configured to swap
images during an upgrade.
+### [RAM Loading](#ram-load)
+
+In ram-load mode the slots are equal. Like the direct-xip mode, this mode
+also 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 the
+RAM for execution. The load address, the location in RAM where the image is
+copied to, is stored in the image header. The ram-load upgrade mode can be
+useful when there is no internal flash in the SoC, but there is a big enough
+internal RAM to hold the images. Usually in this case the images are stored
+in an external storage device. Execution from external storage has some
+drawbacks (lower execution speed, image is exposed to attacks) therefore the
+image is always copied to the internal RAM before the authentication and
+execution. Ram-load mode requires the image to be built to be executed from
+the RAM address range instead of the storage device address range. If
+ram-load is enabled then platform must define the following parameters:
+
+```c
+#define IMAGE_EXECUTABLE_RAM_START <area_base_addr>
+#define IMAGE_EXECUTABLE_RAM_SIZE <area_size_in_bytes>
+```
+
+When ram-load is enabled, the `--load-addr <addr>` option of the `imgtool`
+script must also be used when signing the images. This option set the `RAM_LOAD`
+flag in the image header which indicates that the image should be loaded to the
+RAM and also set the load address in the image header.
+
+The ram-load mode currently supports only the single image boot and the image
+encryption feature is not supported.
+
## [Boot Swap Types](#boot-swap-types)
When the device first boots under normal circumstances, there is an up-to-date
@@ -913,8 +943,8 @@
If you want to enable and use encrypted images, see:
[encrypted_images](encrypted_images.md).
-Note: Image encryption is not supported when the direct-xip upgrade strategy
-is selected.
+Note: Image encryption is not supported when the direct-xip or the ram-load
+upgrade strategy is selected.
### [Using Hardware Keys for Verification](#hw-key-support)
diff --git a/scripts/imgtool/main.py b/scripts/imgtool/main.py
index 8fee864..e01a26c 100755
--- a/scripts/imgtool/main.py
+++ b/scripts/imgtool/main.py
@@ -245,7 +245,7 @@
'was set.')
@click.option('-E', '--encrypt', metavar='filename',
help='Encrypt image using the provided public key. '
- '(Not supported in direct-xip mode.)')
+ '(Not supported in direct-xip or ram-load mode.)')
@click.option('-e', '--endian', type=click.Choice(['little', 'big']),
default='little', help="Select little or big endian")
@click.option('--overwrite-only', default=False, is_flag=True,