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 <utzig@apache.org> Signed-off-by: Andrzej Puzdrowski <andrzej.puzdrowski@nordicsemi.no>
This commit is contained in:
parent
d868a0be9a
commit
49fccdd2ea
8 changed files with 371 additions and 0 deletions
41
include/dfu/mcuboot.h
Normal file
41
include/dfu/mcuboot.h
Normal file
|
@ -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__ */
|
|
@ -24,3 +24,5 @@ source "subsys/net/Kconfig"
|
|||
source "subsys/shell/Kconfig"
|
||||
|
||||
source "subsys/usb/Kconfig"
|
||||
|
||||
source "subsys/dfu/Kconfig"
|
||||
|
|
|
@ -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/
|
||||
|
|
35
subsys/dfu/Kconfig
Normal file
35
subsys/dfu/Kconfig
Normal file
|
@ -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
|
1
subsys/dfu/Makefile
Normal file
1
subsys/dfu/Makefile
Normal file
|
@ -0,0 +1 @@
|
|||
obj-$(CONFIG_MCUBOOT_IMG_MANAGER) += boot/
|
3
subsys/dfu/boot/Makefile
Normal file
3
subsys/dfu/boot/Makefile
Normal file
|
@ -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
|
266
subsys/dfu/boot/mcuboot.c
Normal file
266
subsys/dfu/boot/mcuboot.c
Normal file
|
@ -0,0 +1,266 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2016-2017 Linaro Limited
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <flash.h>
|
||||
#include <zephyr.h>
|
||||
#include <init.h>
|
||||
|
||||
#include <misc/__assert.h>
|
||||
#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);
|
22
subsys/dfu/boot/mcuboot_constraints.h
Normal file
22
subsys/dfu/boot/mcuboot_constraints.h
Normal file
|
@ -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 <mcuboot>/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__ */
|
Loading…
Add table
Add a link
Reference in a new issue