boot/zephyr: Allow single image applications
The change enables usage of single image applications. This can be used
when user does not need multiple boot images and wants to use more flash
are for main application or other purposes.
Signed-off-by: Dominik Ermel <dominik.ermel@nordicsemi.no>
diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt
index 3737157..121e584 100644
--- a/boot/zephyr/CMakeLists.txt
+++ b/boot/zephyr/CMakeLists.txt
@@ -93,19 +93,30 @@
# Generic bootutil sources and includes.
zephyr_library_include_directories(${BOOT_DIR}/bootutil/include)
zephyr_library_sources(
+ ${BOOT_DIR}/bootutil/src/image_validate.c
+ ${BOOT_DIR}/bootutil/src/tlv.c
+ ${BOOT_DIR}/bootutil/src/encrypted.c
+ ${BOOT_DIR}/bootutil/src/image_rsa.c
+ ${BOOT_DIR}/bootutil/src/image_ec256.c
+ ${BOOT_DIR}/bootutil/src/image_ed25519.c
+ )
+
+if(CONFIG_SINGLE_IMAGE_DFU)
+zephyr_library_sources(
+ ${BOOT_DIR}/zephyr/single_loader.c
+ )
+zephyr_library_include_directories(${BOOT_DIR}/bootutil/src)
+else()
+zephyr_library_sources(
${BOOT_DIR}/bootutil/src/loader.c
${BOOT_DIR}/bootutil/src/swap_misc.c
${BOOT_DIR}/bootutil/src/swap_scratch.c
${BOOT_DIR}/bootutil/src/swap_move.c
${BOOT_DIR}/bootutil/src/bootutil_misc.c
- ${BOOT_DIR}/bootutil/src/image_validate.c
- ${BOOT_DIR}/bootutil/src/encrypted.c
- ${BOOT_DIR}/bootutil/src/image_rsa.c
- ${BOOT_DIR}/bootutil/src/image_ec256.c
- ${BOOT_DIR}/bootutil/src/image_ed25519.c
${BOOT_DIR}/bootutil/src/caps.c
- ${BOOT_DIR}/bootutil/src/tlv.c
)
+endif()
+
if(CONFIG_BOOT_SIGNATURE_TYPE_ECDSA_P256 OR CONFIG_BOOT_ENCRYPT_EC256)
zephyr_library_include_directories(
diff --git a/boot/zephyr/flash_map_extended.c b/boot/zephyr/flash_map_extended.c
index 4723af1..c77f96c 100644
--- a/boot/zephyr/flash_map_extended.c
+++ b/boot/zephyr/flash_map_extended.c
@@ -57,10 +57,12 @@
{
switch (slot) {
case 0: return FLASH_AREA_IMAGE_PRIMARY(image_index);
+#if !defined(CONFIG_SINGLE_IMAGE_DFU)
case 1: return FLASH_AREA_IMAGE_SECONDARY(image_index);
#if !defined(CONFIG_BOOT_SWAP_USING_MOVE)
case 2: return FLASH_AREA_IMAGE_SCRATCH;
#endif
+#endif
}
return -EINVAL; /* flash_area_open will fail on that */
@@ -76,9 +78,11 @@
if (area_id == FLASH_AREA_IMAGE_PRIMARY(image_index)) {
return 0;
}
+#if !defined(CONFIG_SINGLE_IMAGE_DFU)
if (area_id == FLASH_AREA_IMAGE_SECONDARY(image_index)) {
return 1;
}
+#endif
BOOT_LOG_ERR("invalid flash area ID");
return -1;
diff --git a/boot/zephyr/include/mcuboot_config/mcuboot_config.h b/boot/zephyr/include/mcuboot_config/mcuboot_config.h
index a642088..044ec3d 100644
--- a/boot/zephyr/include/mcuboot_config/mcuboot_config.h
+++ b/boot/zephyr/include/mcuboot_config/mcuboot_config.h
@@ -58,18 +58,30 @@
#define MCUBOOT_OVERWRITE_ONLY_FAST
#endif
+#ifdef CONFIG_SINGLE_IMAGE_DFU
+#define MCUBOOT_SINGLE_IMAGE_DFU 1
+#else
+
#ifdef CONFIG_BOOT_SWAP_USING_MOVE
#define MCUBOOT_SWAP_USING_MOVE 1
#endif
-#ifdef CONFIG_LOG
-#define MCUBOOT_HAVE_LOGGING 1
+#ifdef CONFIG_UPDATEABLE_IMAGE_NUMBER
+#define MCUBOOT_IMAGE_NUMBER CONFIG_UPDATEABLE_IMAGE_NUMBER
+#else
+#define MCUBOOT_IMAGE_NUMBER 1
#endif
#ifdef CONFIG_BOOT_SWAP_SAVE_ENCTLV
#define MCUBOOT_SWAP_SAVE_ENCTLV 1
#endif
+#endif /* CONFIG_SINGLE_IMAGE_DFU */
+
+#ifdef CONFIG_LOG
+#define MCUBOOT_HAVE_LOGGING 1
+#endif
+
#ifdef CONFIG_BOOT_ENCRYPT_RSA
#define MCUBOOT_ENC_IMAGES
#define MCUBOOT_ENCRYPT_RSA
@@ -93,12 +105,6 @@
#define MCUBOOT_USE_BENCH 1
#endif
-#ifdef CONFIG_UPDATEABLE_IMAGE_NUMBER
-#define MCUBOOT_IMAGE_NUMBER CONFIG_UPDATEABLE_IMAGE_NUMBER
-#else
-#define MCUBOOT_IMAGE_NUMBER 1
-#endif
-
#ifdef CONFIG_MCUBOOT_DOWNGRADE_PREVENTION
#define MCUBOOT_DOWNGRADE_PREVENTION 1
#endif
diff --git a/boot/zephyr/include/sysflash/sysflash.h b/boot/zephyr/include/sysflash/sysflash.h
index 66dce1d..f651779 100644
--- a/boot/zephyr/include/sysflash/sysflash.h
+++ b/boot/zephyr/include/sysflash/sysflash.h
@@ -6,6 +6,8 @@
#include <devicetree.h>
#include <mcuboot_config/mcuboot_config.h>
+#ifndef CONFIG_SINGLE_IMAGE_DFU
+
#if (MCUBOOT_IMAGE_NUMBER == 1)
/*
* NOTE: the definition below returns the same values for true/false on
@@ -41,4 +43,16 @@
#define FLASH_AREA_IMAGE_SCRATCH FLASH_AREA_ID(image_scratch)
#endif
+#else /* CONFIG_SINGLE_IMAGE_DFU */
+
+#define FLASH_AREA_IMAGE_PRIMARY(x) FLASH_AREA_ID(image_0)
+#define FLASH_AREA_IMAGE_SECONDARY(x) FLASH_AREA_ID(image_0)
+/* NOTE: Scratch parition is not used by single image DFU but some of
+ * functions in common files reference it, so the definitions has been
+ * provided to allow compilation of common units.
+ */
+#define FLASH_AREA_IMAGE_SCRATCH 0
+
+#endif /* CONFIG_SINGLE_IMAGE_DFU */
+
#endif /* __SYSFLASH_H__ */
diff --git a/boot/zephyr/include/target.h b/boot/zephyr/include/target.h
index 2e0f5fd..d585b9c 100644
--- a/boot/zephyr/include/target.h
+++ b/boot/zephyr/include/target.h
@@ -37,8 +37,8 @@
(defined(CONFIG_XTENSA) && !defined(JEDEC_SPI_NOR_0_LABEL)) || \
!defined(FLASH_ALIGN) || \
!(FLASH_AREA_LABEL_EXISTS(image_0)) || \
- !(FLASH_AREA_LABEL_EXISTS(image_1)) || \
- (!defined(CONFIG_BOOT_SWAP_USING_MOVE) && !(FLASH_AREA_LABEL_EXISTS(image_scratch)))
+ !(FLASH_AREA_LABEL_EXISTS(image_1) || CONFIG_SINGLE_IMAGE_DFU) || \
+ (!defined(CONFIG_BOOT_SWAP_USING_MOVE) && !FLASH_AREA_LABEL_EXISTS(image_scratch) && !defined(CONFIG_SINGLE_IMAGE_DFU))
#error "Target support is incomplete; cannot build mcuboot."
#endif
diff --git a/boot/zephyr/single_loader.c b/boot/zephyr/single_loader.c
new file mode 100644
index 0000000..258d38b
--- /dev/null
+++ b/boot/zephyr/single_loader.c
@@ -0,0 +1,126 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Copyright (c) 2020 Nordic Semiconductor ASA
+ */
+
+#include <assert.h>
+#include "bootutil/image.h"
+#include "bootutil_priv.h"
+#include "bootutil/bootutil_log.h"
+
+#include "mcuboot_config/mcuboot_config.h"
+
+MCUBOOT_LOG_MODULE_DECLARE(mcuboot);
+
+/* Variables passed outside of unit via poiters. */
+static const struct flash_area *_fa_p;
+static struct image_header _hdr = { 0 };
+
+#ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT
+/**
+ * Validate hash of a primary boot image.
+ *
+ * @param[in] fa_p flash area pointer
+ * @param[in] hdr boot image header pointer
+ *
+ * @return 0 on success, error code otherwise
+ */
+inline static int
+boot_image_validate(const struct flash_area *fa_p,
+ struct image_header *hdr)
+{
+ static uint8_t tmpbuf[BOOT_TMPBUF_SZ];
+
+ /* NOTE: The enc-state pointer may be NULL only because when there is
+ * only one image (BOOT_IMAGE_NUMBER == 1), the code that uses the
+ * pointer, within bootutil_img_validate and down the call path,
+ * is excluded from compilation.
+ */
+ /* Validate hash */
+ if (bootutil_img_validate(NULL, 0, hdr, fa_p, tmpbuf,
+ BOOT_TMPBUF_SZ, NULL, 0, NULL)) {
+ return BOOT_EBADIMAGE;
+ }
+
+ return 0;
+}
+#endif /* MCUBOOT_VALIDATE_PRIMARY_SLOT */
+
+
+/**
+ * Attempts to load image header from flash; verifies flash header fields.
+ *
+ * @param[in] fa_p flash area pointer
+ * @param[out] hdr buffer for image header
+ *
+ * @return 0 on success, error code otherwise
+ */
+static int
+boot_image_load_header(const struct flash_area *fa_p,
+ struct image_header *hdr)
+{
+ uint32_t size;
+ int rc = flash_area_read(fa_p, 0, hdr, sizeof *hdr);
+
+ if (rc != 0) {
+ rc = BOOT_EFLASH;
+ BOOT_LOG_ERR("Failed reading image header");
+ return BOOT_EFLASH;
+ }
+
+ if (hdr->ih_magic != IMAGE_MAGIC) {
+ BOOT_LOG_ERR("Bad image magic 0x%lx", (unsigned long)hdr->ih_magic);
+
+ return BOOT_EBADIMAGE;
+ }
+
+ if (hdr->ih_flags & IMAGE_F_NON_BOOTABLE) {
+ BOOT_LOG_ERR("Image not bootable");
+
+ return BOOT_EBADIMAGE;
+ }
+
+ if (!boot_u32_safe_add(&size, hdr->ih_img_size, hdr->ih_hdr_size) ||
+ size >= fa_p->fa_size) {
+ return BOOT_EBADIMAGE;
+ }
+
+ return 0;
+}
+
+
+/**
+ * Gather information on image and prepare for booting.
+ *
+ * @parami[out] rsp Parameters for booting image, on success
+ *
+ * @return 0 on success, error code otherwise.
+ */
+int
+boot_go(struct boot_rsp *rsp)
+{
+ int rc = -1;
+
+ rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(0), &_fa_p);
+ assert(rc == 0);
+
+ rc = boot_image_load_header(_fa_p, &_hdr);
+ if (rc != 0)
+ goto out;
+
+#ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT
+ rc = boot_image_validate(_fa_p, &_hdr);
+ if (rc != 0) {
+ goto out;
+ }
+#endif /* MCUBOOT_VALIDATE_PRIMARY_SLOT */
+
+ rsp->br_flash_dev_id = _fa_p->fa_device_id;
+ rsp->br_image_off = _fa_p->fa_off;
+ rsp->br_hdr = &_hdr;
+
+out:
+ flash_area_close(_fa_p);
+ return rc;
+}