From 49fccdd2ea02cf524ee74571fb8b76d1a1b311e2 Mon Sep 17 00:00:00 2001 From: Andrzej Puzdrowski Date: Tue, 4 Jul 2017 11:54:11 +0200 Subject: [PATCH] DFU: add module for interact with mcuboot read, update status trigger flashing erase image bank Module is intended to be use by a higher-level image management protocol module. Signed-off-by: Fabio Utzig Signed-off-by: Andrzej Puzdrowski --- include/dfu/mcuboot.h | 41 ++++ subsys/Kconfig | 2 + subsys/Makefile | 1 + subsys/dfu/Kconfig | 35 ++++ subsys/dfu/Makefile | 1 + subsys/dfu/boot/Makefile | 3 + subsys/dfu/boot/mcuboot.c | 266 ++++++++++++++++++++++++++ subsys/dfu/boot/mcuboot_constraints.h | 22 +++ 8 files changed, 371 insertions(+) create mode 100644 include/dfu/mcuboot.h create mode 100644 subsys/dfu/Kconfig create mode 100644 subsys/dfu/Makefile create mode 100644 subsys/dfu/boot/Makefile create mode 100644 subsys/dfu/boot/mcuboot.c create mode 100644 subsys/dfu/boot/mcuboot_constraints.h diff --git a/include/dfu/mcuboot.h b/include/dfu/mcuboot.h new file mode 100644 index 00000000000..141e25336ba --- /dev/null +++ b/include/dfu/mcuboot.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2017 Nordic Semiconductor ASA + * Copyright (c) 2016 Linaro Limited + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __MCUBOOT_H__ +#define __MCUBOOT_H__ + +/** + * @brief Marks the image in slot 0 as confirmed. The system will continue + * booting into the image in slot 0 until told to boot from a different slot. + * + * This call is expected to be used by the application running on trial. + * + * @return 0 on success, negative errno code on fail. + */ +int boot_write_img_confirmed(void); + +/** + * @brief Marks the image in slot 1 as pending. On the next reboot, the system + * will perform a boot of the slot 1 image. + * + * @param permanent Whether the image should be used permanently or + * only tested once: + * 0=run image once, then confirm or revert. + * 1=run image forever. + * @return 0 on success, negative errno code on fail. + */ +int boot_request_upgrade(int permanent); + +/** + * @brief Erase the image Bank. + * + * @param bank_offset address of the image bank + * @return 0 on success, negative errno code on fail. + */ +int boot_erase_img_bank(u32_t bank_offset); + +#endif /* __MCUBOOT_H__ */ diff --git a/subsys/Kconfig b/subsys/Kconfig index 4966a0b8114..e3b4f74c3eb 100644 --- a/subsys/Kconfig +++ b/subsys/Kconfig @@ -24,3 +24,5 @@ source "subsys/net/Kconfig" source "subsys/shell/Kconfig" source "subsys/usb/Kconfig" + +source "subsys/dfu/Kconfig" diff --git a/subsys/Makefile b/subsys/Makefile index a9a2aa153d3..0fd04f7b7e0 100644 --- a/subsys/Makefile +++ b/subsys/Makefile @@ -8,3 +8,4 @@ obj-$(CONFIG_DISK_ACCESS) += disk/ obj-$(CONFIG_CPLUSPLUS) += cpp/ obj-y += logging/ obj-y += debug/ +obj-$(CONFIG_MCUBOOT_IMG_MANAGER) += dfu/ diff --git a/subsys/dfu/Kconfig b/subsys/dfu/Kconfig new file mode 100644 index 00000000000..3409dca0a4a --- /dev/null +++ b/subsys/dfu/Kconfig @@ -0,0 +1,35 @@ +# Kconfig - DFU support configuration options +# +# Copyright (c) 2017 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +# +# DFU +# + +menu "DFU options" + +config IMG_MANAGER + bool + prompt "DFU image manager" + default n + help + Enable support for managing DFU image. + +choice + prompt "Image manager" + default MCUBOOT_IMG_MANAGER + depends on IMG_MANAGER + help + Choice support for managing DFU image. + So far only mcuboot support is available. + +config MCUBOOT_IMG_MANAGER + bool "Image manager for mcuboot" + help + Enable support for managing DFU image downloaded using mcuboot. +endchoice + +endmenu diff --git a/subsys/dfu/Makefile b/subsys/dfu/Makefile new file mode 100644 index 00000000000..b2238c8072c --- /dev/null +++ b/subsys/dfu/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_MCUBOOT_IMG_MANAGER) += boot/ diff --git a/subsys/dfu/boot/Makefile b/subsys/dfu/boot/Makefile new file mode 100644 index 00000000000..ef97739402d --- /dev/null +++ b/subsys/dfu/boot/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_MCUBOOT_IMG_MANAGER) += mcuboot.o +ccflags-$(CONFIG_MCUBOOT_IMG_MANAGER) += -I${ZEPHYR_BASE}/include/dfu +ccflags-$(CONFIG_MCUBOOT_IMG_MANAGER) += -I${ZEPHYR_BASE}/subsys/dfu diff --git a/subsys/dfu/boot/mcuboot.c b/subsys/dfu/boot/mcuboot.c new file mode 100644 index 00000000000..4e7079b8a49 --- /dev/null +++ b/subsys/dfu/boot/mcuboot.c @@ -0,0 +1,266 @@ +/* + * Copyright (c) 2017 Nordic Semiconductor ASA + * Copyright (c) 2016-2017 Linaro Limited + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include +#include "boot/mcuboot_constraints.h" +#include "mcuboot.h" + +/* + * Helpers for image trailer, as defined by mcuboot. + * Image trailer consists of sequence of fields: + * u8_t copy_done + * u8_t padding_1[BOOT_MAX_ALIGN - 1] + * u8_t image_ok + * u8_t padding_2[BOOT_MAX_ALIGN - 1] + * u8_t magic[16] + */ + +/* + * Strict defines: Defines in block below must be equal to coresponding + * mcuboot defines + */ +#define BOOT_MAX_ALIGN 8 +#define BOOT_MAGIC_SZ 16 +#define BOOT_FLAG_SET 0x01 +#define BOOT_FLAG_UNSET 0xff +/* end_of Strict defines */ + +#define BOOT_MAGIC_GOOD 1 +#define BOOT_MAGIC_BAD 2 +#define BOOT_MAGIC_UNSET 3 + +#define BOOT_FLAG_IMAGE_OK 0 +#define BOOT_FLAG_COPY_DONE 1 + +#define FLASH_MIN_WRITE_SIZE FLASH_ALIGN +#define FLASH_BANK0_OFFSET FLASH_AREA_IMAGE_0_OFFSET + +/* FLASH_AREA_IMAGE_XX_YY values used below are auto-generated thanks to DT */ +#define FLASH_BANK_SIZE FLASH_AREA_IMAGE_0_SIZE +#define FLASH_BANK1_OFFSET FLASH_AREA_IMAGE_1_OFFSET +#define FLASH_STATE_OFFSET (FLASH_AREA_IMAGE_SCRATCH_OFFSET +\ + FLASH_AREA_IMAGE_SCRATCH_SIZE) + +#define COPY_DONE_OFFS(bank_offs) (bank_offs + FLASH_BANK_SIZE -\ + BOOT_MAGIC_SZ - BOOT_MAX_ALIGN * 2) + +#define IMAGE_OK_OFFS(bank_offs) (bank_offs + FLASH_BANK_SIZE - BOOT_MAGIC_SZ -\ + BOOT_MAX_ALIGN) +#define MAGIC_OFFS(bank_offs) (bank_offs + FLASH_BANK_SIZE - BOOT_MAGIC_SZ) + +const u32_t boot_img_magic[4] = { + 0xf395c277, + 0x7fefd260, + 0x0f505235, + 0x8079b62c, +}; + +static struct device *flash_dev; + +static int boot_flag_offs(int flag, u32_t bank_offs, u32_t *offs) +{ + switch (flag) { + case BOOT_FLAG_COPY_DONE: + *offs = COPY_DONE_OFFS(bank_offs); + return 0; + case BOOT_FLAG_IMAGE_OK: + *offs = IMAGE_OK_OFFS(bank_offs); + return 0; + default: + return -ENOTSUP; + } +} + + +static int boot_flash_write(off_t offs, const void *data, size_t len) +{ + int rc; + + rc = flash_write_protection_set(flash_dev, false); + if (rc) { + return rc; + } + + rc = flash_write(flash_dev, offs, data, len); + if (rc) { + return rc; + } + + rc = flash_write_protection_set(flash_dev, true); + + return rc; +} + +static int boot_flag_write(int flag, u32_t bank_offs) +{ + u8_t buf[FLASH_MIN_WRITE_SIZE]; + u32_t offs; + int rc; + + rc = boot_flag_offs(flag, bank_offs, &offs); + if (rc != 0) { + return rc; + } + + memset(buf, BOOT_FLAG_UNSET, sizeof(buf)); + buf[0] = BOOT_FLAG_SET; + + rc = boot_flash_write(offs, buf, sizeof(buf)); + + return rc; +} + +static int boot_flag_read(int flag, u32_t bank_offs) +{ + u32_t offs; + int rc; + u8_t flag_val; + + rc = boot_flag_offs(flag, bank_offs, &offs); + if (rc != 0) { + return rc; + } + + rc = flash_read(flash_dev, offs, &flag_val, sizeof(flag_val)); + if (rc != 0) { + return rc; + } + + return flag_val; +} + +static int boot_image_ok_read(u32_t bank_offs) +{ + return boot_flag_read(BOOT_FLAG_IMAGE_OK, bank_offs); +} + +static int boot_image_ok_write(u32_t bank_offs) +{ + return boot_flag_write(BOOT_FLAG_IMAGE_OK, bank_offs); +} + +static int boot_magic_write(u32_t bank_offs) +{ + u32_t offs; + int rc; + + offs = MAGIC_OFFS(bank_offs); + + rc = boot_flash_write(offs, boot_img_magic, BOOT_MAGIC_SZ); + + return rc; +} + +static int boot_magic_code_check(const u32_t *magic) +{ + int i; + + if (memcmp(magic, boot_img_magic, sizeof(boot_img_magic)) == 0) { + return BOOT_MAGIC_GOOD; + } + + for (i = 0; i < ARRAY_SIZE(boot_img_magic); i++) { + if (magic[i] != 0xffffffff) { + return BOOT_MAGIC_BAD; + } + } + + return BOOT_MAGIC_UNSET; +} + +static int boot_magic_state_read(u32_t bank_offs) +{ + u32_t magic[4]; + u32_t offs; + int rc; + + offs = MAGIC_OFFS(bank_offs); + rc = flash_read(flash_dev, offs, magic, sizeof(magic)); + if (rc != 0) { + return rc; + } + + return boot_magic_code_check(magic); +} + +int boot_request_upgrade(int permanent) +{ + int rc; + + rc = boot_magic_write(FLASH_BANK1_OFFSET); + if (rc == 0 && permanent) { + rc = boot_image_ok_write(FLASH_BANK1_OFFSET); + } + + return rc; +} + +int boot_write_img_confirmed(void) +{ + int rc; + + switch (boot_magic_state_read(FLASH_BANK0_OFFSET)) { + case BOOT_MAGIC_GOOD: + /* Confirm needed; proceed. */ + break; + + case BOOT_MAGIC_UNSET: + /* Already confirmed. */ + return 0; + + case BOOT_MAGIC_BAD: + /* Unexpected state. */ + return -EFAULT; + } + + if (boot_image_ok_read(FLASH_BANK0_OFFSET) != BOOT_FLAG_UNSET) { + /* Already confirmed. */ + return 0; + } + + rc = boot_image_ok_write(FLASH_BANK0_OFFSET); + + return rc; +} + +int boot_erase_img_bank(u32_t bank_offset) +{ + int rc; + + rc = flash_write_protection_set(flash_dev, false); + if (rc) { + return rc; + } + + rc = flash_erase(flash_dev, bank_offset, FLASH_BANK_SIZE); + if (rc) { + return rc; + } + + rc = flash_write_protection_set(flash_dev, true); + + return rc; +} + +static int boot_init(struct device *dev) +{ + ARG_UNUSED(dev); + flash_dev = device_get_binding(FLASH_DRIVER_NAME); + if (!flash_dev) { + return -ENODEV; + } + return 0; +} + +SYS_INIT(boot_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); diff --git a/subsys/dfu/boot/mcuboot_constraints.h b/subsys/dfu/boot/mcuboot_constraints.h new file mode 100644 index 00000000000..dd514363939 --- /dev/null +++ b/subsys/dfu/boot/mcuboot_constraints.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2017 Nordic Semiconductor ASA + * Copyright (c) 2016 Linaro Limited + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* Headers target/devboard.h are copies of board headers form mcuboot sources */ +/* see /boot/zephyr/targets/ */ + +#ifndef __MCUBOOT_CONSTRAINS_H__ +#define __MCUBOOT_CONSTRAINS_H__ + +/* Flash specific configs */ +#if defined(CONFIG_SOC_SERIES_NRF52X) +#define FLASH_DRIVER_NAME CONFIG_SOC_FLASH_NRF5_DEV_NAME +#define FLASH_ALIGN 4 +#else +#error Unknown SoC family +#endif /* CONFIG_SOC_SERIES_NRF52X */ + +#endif /* __MCUBOOT_CONSTRAINS_H__ */