dfu: mcuboot: add shell module

Add new shell module for mcuboot enabled application. It provides
information about image slots and allows to perform such operations as:
confirm, erase and request upgrade.

Signed-off-by: Marcin Niestroj <m.niestroj@grinn-global.com>
This commit is contained in:
Marcin Niestroj 2020-10-30 19:26:14 +01:00 committed by Carles Cufí
commit 0e769c1a36
5 changed files with 266 additions and 40 deletions

View file

@ -30,6 +30,16 @@ config MCUBOOT_IMG_MANAGER
endchoice
config MCUBOOT_SHELL
bool "MCUboot shell"
default y
depends on MCUBOOT_IMG_MANAGER
depends on SHELL
help
Enable shell module, which provides information about image slots and
allows to perform such operations as: confirm, erase and request
upgrade.
config MCUBOOT_TRAILER_SWAP_TYPE
bool "use trailer's swap_type field"
default y

View file

@ -1,3 +1,4 @@
# SPDX-License-Identifier: Apache-2.0
zephyr_sources_ifdef(CONFIG_MCUBOOT_IMG_MANAGER mcuboot.c)
zephyr_sources_ifdef(CONFIG_MCUBOOT_SHELL mcuboot_shell.c)

View file

@ -17,6 +17,8 @@
#include <sys/byteorder.h>
#include <dfu/mcuboot.h>
#include "mcuboot_priv.h"
/*
* Helpers for image headers and trailers, as defined by mcuboot.
*/
@ -30,12 +32,6 @@
#define BOOT_HEADER_MAGIC_V1 0x96f3b83d
#define BOOT_HEADER_SIZE_V1 32
/* Trailer: */
#define BOOT_FLAG_SET 1
#define BOOT_FLAG_BAD 2
#define BOOT_FLAG_UNSET 3
#define BOOT_FLAG_ANY 4 /* NOTE: control only, not dependent on sector */
/*
* Raw (on-flash) representation of the v1 image header.
*/
@ -59,33 +55,12 @@ struct mcuboot_v1_raw_header {
* End of strict defines
*/
#define BOOT_MAGIC_GOOD 1
#define BOOT_MAGIC_BAD 2
#define BOOT_MAGIC_UNSET 3
#define BOOT_MAGIC_ANY 4 /* NOTE: control only, not dependent on sector */
#define BOOT_MAGIC_NOTGOOD 5 /* NOTE: control only, not dependent on sector */
#define BOOT_FLAG_IMAGE_OK 0
#define BOOT_FLAG_COPY_DONE 1
#define FLASH_MIN_WRITE_SIZE \
DT_PROP(DT_CHOSEN(zephyr_flash), write_block_size)
/* FLASH_AREA_ID() values used below are auto-generated by DT */
#ifdef CONFIG_TRUSTED_EXECUTION_NONSECURE
#define FLASH_AREA_IMAGE_PRIMARY FLASH_AREA_ID(image_0_nonsecure)
#define FLASH_AREA_IMAGE_SECONDARY FLASH_AREA_ID(image_1_nonsecure)
#else
#define FLASH_AREA_IMAGE_PRIMARY FLASH_AREA_ID(image_0)
#if FLASH_AREA_LABEL_EXISTS(image_1)
#define FLASH_AREA_IMAGE_SECONDARY FLASH_AREA_ID(image_1)
#endif
#endif /* CONFIG_TRUSTED_EXECUTION_NONSECURE */
#if FLASH_AREA_LABEL_EXISTS(image_scratch)
#define FLASH_AREA_IMAGE_SCRATCH FLASH_AREA_ID(image_scratch)
#endif
#ifdef CONFIG_MCUBOOT_TRAILER_SWAP_TYPE
#define SWAP_TYPE_OFFS(bank_area) ((bank_area)->fa_size -\
BOOT_MAGIC_SZ - BOOT_MAX_ALIGN * 3)
@ -120,14 +95,6 @@ struct boot_swap_table {
uint8_t swap_type;
};
/** Represents the management state of a single image slot. */
struct boot_swap_state {
uint8_t magic; /* One of the BOOT_MAGIC_[...] values. */
uint8_t swap_type; /* One of the BOOT_SWAP_TYPE_[...] values. */
uint8_t copy_done; /* One of the BOOT_FLAG_[...] values. */
uint8_t image_ok; /* One of the BOOT_FLAG_[...] values. */
};
#ifdef FLASH_AREA_IMAGE_SECONDARY
/**
* This set of tables maps image trailer contents to swap operation type.
@ -579,11 +546,7 @@ static int boot_read_swap_state(const struct flash_area *fa,
}
#endif
#if !defined(CONFIG_BOOTLOADER_MCUBOOT) && !defined(CONFIG_ZTEST)
/* provided by MCUBoot */
int
boot_read_swap_state_by_id(int flash_area_id, struct boot_swap_state *state);
#else
#if defined(CONFIG_BOOTLOADER_MCUBOOT) || defined(CONFIG_ZTEST)
/**
* Reads the image trailer from the scratch area.
*/

View file

@ -0,0 +1,50 @@
/*
* Copyright (c) 2017 Nordic Semiconductor ASA
* Copyright (c) 2016-2017 Linaro Limited
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_DFU_BOOT_MCUBOOT_H_
#define ZEPHYR_DFU_BOOT_MCUBOOT_H_
#include <storage/flash_map.h>
/* FLASH_AREA_ID() values used below are auto-generated by DT */
#ifdef CONFIG_TRUSTED_EXECUTION_NONSECURE
#define FLASH_AREA_IMAGE_PRIMARY FLASH_AREA_ID(image_0_nonsecure)
#define FLASH_AREA_IMAGE_SECONDARY FLASH_AREA_ID(image_1_nonsecure)
#else
#define FLASH_AREA_IMAGE_PRIMARY FLASH_AREA_ID(image_0)
#if FLASH_AREA_LABEL_EXISTS(image_1)
#define FLASH_AREA_IMAGE_SECONDARY FLASH_AREA_ID(image_1)
#endif
#endif /* CONFIG_TRUSTED_EXECUTION_NONSECURE */
#if FLASH_AREA_LABEL_EXISTS(image_scratch)
#define FLASH_AREA_IMAGE_SCRATCH FLASH_AREA_ID(image_scratch)
#endif
#define BOOT_MAGIC_GOOD 1
#define BOOT_MAGIC_BAD 2
#define BOOT_MAGIC_UNSET 3
#define BOOT_MAGIC_ANY 4 /* NOTE: control only, not dependent on sector */
#define BOOT_MAGIC_NOTGOOD 5 /* NOTE: control only, not dependent on sector */
#define BOOT_FLAG_SET 1
#define BOOT_FLAG_BAD 2
#define BOOT_FLAG_UNSET 3
#define BOOT_FLAG_ANY 4 /* NOTE: control only, not dependent on sector */
/** Represents the management state of a single image slot. */
struct boot_swap_state {
uint8_t magic; /* One of the BOOT_MAGIC_[...] values. */
uint8_t swap_type; /* One of the BOOT_SWAP_TYPE_[...] values. */
uint8_t copy_done; /* One of the BOOT_FLAG_[...] values. */
uint8_t image_ok; /* One of the BOOT_FLAG_[...] values. */
};
int
boot_read_swap_state_by_id(int flash_area_id, struct boot_swap_state *state);
#endif /* ZEPHYR_DFU_BOOT_MCUBOOT_H_ */

View file

@ -0,0 +1,202 @@
/*
* Copyright (c) 2020 Grinn
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <dfu/mcuboot.h>
#include <init.h>
#include <shell/shell.h>
#include <stdlib.h>
#include "mcuboot_priv.h"
struct area_desc {
const char *name;
unsigned int id;
};
static const struct area_desc areas[] = {
{"primary", FLASH_AREA_IMAGE_PRIMARY},
#ifdef FLASH_AREA_IMAGE_SECONDARY
{"secondary", FLASH_AREA_IMAGE_SECONDARY},
#endif
};
static const char *swap_state_magic_str(uint8_t magic)
{
switch (magic) {
case BOOT_MAGIC_GOOD:
return "good";
case BOOT_MAGIC_BAD:
return "bad";
case BOOT_MAGIC_UNSET:
return "unset";
case BOOT_MAGIC_ANY:
return "any";
case BOOT_MAGIC_NOTGOOD:
return "notgood";
}
return "unknown";
}
static const char *swap_type_str(uint8_t type)
{
switch (type) {
case BOOT_SWAP_TYPE_NONE:
return "none";
case BOOT_SWAP_TYPE_TEST:
return "test";
case BOOT_SWAP_TYPE_PERM:
return "perm";
case BOOT_SWAP_TYPE_REVERT:
return "revert";
case BOOT_SWAP_TYPE_FAIL:
return "fail";
}
return "unknown";
}
static const char *swap_state_flag_str(uint8_t flag)
{
switch (flag) {
case BOOT_FLAG_SET:
return "set";
case BOOT_FLAG_BAD:
return "bad";
case BOOT_FLAG_UNSET:
return "unset";
case BOOT_FLAG_ANY:
return "any";
}
return "unknown";
}
static int cmd_mcuboot_erase(const struct shell *shell, size_t argc,
char **argv)
{
unsigned int id;
int err;
id = strtoul(argv[1], NULL, 0);
err = boot_erase_img_bank(id);
if (err) {
shell_error(shell, "failed to erase bank %u", id);
return err;
}
return 0;
}
static int cmd_mcuboot_confirm(const struct shell *shell, size_t argc,
char **argv)
{
int err;
err = boot_write_img_confirmed();
if (err) {
shell_error(shell, "failed to confirm: %d", err);
}
return err;
}
static int cmd_mcuboot_request_upgrade(const struct shell *shell, size_t argc,
char **argv)
{
int permanent = 0;
int err;
if (argc > 1) {
if (!strcmp(argv[1], "permanent")) {
permanent = 1;
} else {
shell_warn(shell, "invalid argument!");
return -EINVAL;
}
}
err = boot_request_upgrade(permanent);
if (err) {
shell_error(shell, "failed to request upgrade: %d", err);
}
return err;
}
static int cmd_mcuboot_info_area(const struct shell *shell,
const struct area_desc *area)
{
struct mcuboot_img_header hdr;
struct boot_swap_state swap_state;
int err;
err = boot_read_bank_header(area->id, &hdr, sizeof(hdr));
if (err) {
shell_error(shell, "failed to read %s area (%u) %s: %d",
area->name, area->id, "header", err);
return err;
}
shell_print(shell, "%s area (%u):", area->name, area->id);
shell_print(shell, " version: %u.%u.%u+%u",
(unsigned int) hdr.h.v1.sem_ver.major,
(unsigned int) hdr.h.v1.sem_ver.minor,
(unsigned int) hdr.h.v1.sem_ver.revision,
(unsigned int) hdr.h.v1.sem_ver.build_num);
shell_print(shell, " image size: %u",
(unsigned int) hdr.h.v1.image_size);
err = boot_read_swap_state_by_id(area->id, &swap_state);
if (err) {
shell_error(shell, "failed to read %s area (%u) %s: %d",
area->name, area->id, "swap state", err);
return err;
}
shell_print(shell, " magic: %s",
swap_state_magic_str(swap_state.magic));
if (IS_ENABLED(CONFIG_MCUBOOT_TRAILER_SWAP_TYPE)) {
shell_print(shell, " swap type: %s",
swap_type_str(swap_state.swap_type));
}
shell_print(shell, " copy done: %s",
swap_state_flag_str(swap_state.copy_done));
shell_print(shell, " image ok: %s",
swap_state_flag_str(swap_state.image_ok));
return 0;
}
static int cmd_mcuboot_info(const struct shell *shell, size_t argc,
char **argv)
{
int i;
shell_print(shell, "swap type: %s", swap_type_str(mcuboot_swap_type()));
shell_print(shell, "confirmed: %d", boot_is_img_confirmed());
for (i = 0; i < ARRAY_SIZE(areas); i++) {
shell_print(shell, "");
cmd_mcuboot_info_area(shell, &areas[i]);
}
return 0;
}
SHELL_STATIC_SUBCMD_SET_CREATE(mcuboot_cmds,
SHELL_CMD_ARG(confirm, NULL, "confirm", cmd_mcuboot_confirm, 1, 0),
SHELL_CMD_ARG(erase, NULL, "erase <area_id>", cmd_mcuboot_erase, 2, 0),
SHELL_CMD_ARG(request_upgrade, NULL, "request_upgrade [permanent]",
cmd_mcuboot_request_upgrade, 1, 1),
SHELL_SUBCMD_SET_END /* Array terminated. */
);
SHELL_CMD_REGISTER(mcuboot, &mcuboot_cmds, "MCUboot commands",
cmd_mcuboot_info);