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:
parent
7356cb2e45
commit
0e769c1a36
5 changed files with 266 additions and 40 deletions
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
50
subsys/dfu/boot/mcuboot_priv.h
Normal file
50
subsys/dfu/boot/mcuboot_priv.h
Normal 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_ */
|
202
subsys/dfu/boot/mcuboot_shell.c
Normal file
202
subsys/dfu/boot/mcuboot_shell.c
Normal 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);
|
Loading…
Add table
Add a link
Reference in a new issue