238 lines
5.0 KiB
C
238 lines
5.0 KiB
C
/*
|
|
* Copyright (c) 2020 Grinn
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include "bootutil/bootutil_public.h"
|
|
#include <zephyr/dfu/mcuboot.h>
|
|
#include <zephyr/init.h>
|
|
#include <zephyr/shell/shell.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "mcuboot_priv.h"
|
|
|
|
#ifdef CONFIG_RETENTION_BOOT_MODE
|
|
#include <zephyr/retention/bootmode.h>
|
|
#ifdef CONFIG_REBOOT
|
|
#include <zephyr/sys/reboot.h>
|
|
#endif
|
|
#endif
|
|
|
|
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 *sh, 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(sh, "failed to erase bank %u", id);
|
|
return err;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int cmd_mcuboot_confirm(const struct shell *sh, size_t argc,
|
|
char **argv)
|
|
{
|
|
int err;
|
|
|
|
err = boot_write_img_confirmed();
|
|
if (err) {
|
|
shell_error(sh, "failed to confirm: %d", err);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
static int cmd_mcuboot_request_upgrade(const struct shell *sh, size_t argc,
|
|
char **argv)
|
|
{
|
|
int permanent = 0;
|
|
int err;
|
|
|
|
if (argc > 1) {
|
|
if (!strcmp(argv[1], "permanent")) {
|
|
permanent = 1;
|
|
} else {
|
|
shell_warn(sh, "invalid argument!");
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
err = boot_request_upgrade(permanent);
|
|
if (err) {
|
|
shell_error(sh, "failed to request upgrade: %d", err);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
#ifdef CONFIG_RETENTION_BOOT_MODE
|
|
static int cmd_mcuboot_serial_recovery(const struct shell *sh, size_t argc,
|
|
char **argv)
|
|
{
|
|
int rc;
|
|
|
|
rc = bootmode_set(BOOT_MODE_TYPE_BOOTLOADER);
|
|
|
|
if (rc) {
|
|
shell_error(sh, "Failed to set serial recovery mode: %d", rc);
|
|
|
|
return rc;
|
|
}
|
|
|
|
#ifdef CONFIG_REBOOT
|
|
sys_reboot(SYS_REBOOT_COLD);
|
|
#else
|
|
shell_error(sh, "mcuboot serial recovery mode set, please reboot your device");
|
|
#endif
|
|
|
|
return rc;
|
|
}
|
|
#endif
|
|
|
|
static int cmd_mcuboot_info_area(const struct shell *sh,
|
|
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(sh, "failed to read %s area (%u) %s: %d",
|
|
area->name, area->id, "header", err);
|
|
return err;
|
|
}
|
|
|
|
shell_print(sh, "%s area (%u):", area->name, area->id);
|
|
shell_print(sh, " 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(sh, " 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(sh, "failed to read %s area (%u) %s: %d",
|
|
area->name, area->id, "swap state", err);
|
|
return err;
|
|
}
|
|
|
|
shell_print(sh, " magic: %s",
|
|
swap_state_magic_str(swap_state.magic));
|
|
|
|
if (IS_ENABLED(CONFIG_MCUBOOT_TRAILER_SWAP_TYPE)) {
|
|
shell_print(sh, " swap type: %s",
|
|
swap_type_str(swap_state.swap_type));
|
|
}
|
|
|
|
shell_print(sh, " copy done: %s",
|
|
swap_state_flag_str(swap_state.copy_done));
|
|
shell_print(sh, " image ok: %s",
|
|
swap_state_flag_str(swap_state.image_ok));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int cmd_mcuboot_info(const struct shell *sh, size_t argc,
|
|
char **argv)
|
|
{
|
|
int i;
|
|
|
|
shell_print(sh, "swap type: %s", swap_type_str(mcuboot_swap_type()));
|
|
shell_print(sh, "confirmed: %d", boot_is_img_confirmed());
|
|
|
|
for (i = 0; i < ARRAY_SIZE(areas); i++) {
|
|
shell_print(sh, "");
|
|
cmd_mcuboot_info_area(sh, &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),
|
|
#ifdef CONFIG_RETENTION_BOOT_MODE
|
|
SHELL_CMD_ARG(serial_recovery, NULL, "serial_recovery", cmd_mcuboot_serial_recovery, 1, 0),
|
|
#endif
|
|
SHELL_SUBCMD_SET_END /* Array terminated. */
|
|
);
|
|
|
|
SHELL_CMD_REGISTER(mcuboot, &mcuboot_cmds, "MCUboot commands",
|
|
cmd_mcuboot_info);
|