Skip to content

Commit

Permalink
zephyr: Allow user-defined boot serial extensions
Browse files Browse the repository at this point in the history
This allows for out-of-tree modules to define their own boot serial
functions by using iterable sections.
Note that this also removes the custom img list command, which was
not used in-tree.

Signed-off-by: Jamie McCrae <[email protected]>
  • Loading branch information
nordicjm committed Sep 26, 2023
1 parent e188dbb commit c26e4c9
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 145 deletions.
11 changes: 11 additions & 0 deletions boot/zephyr/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,17 @@ if(DEFINED CONFIG_ENABLE_MGMT_PERUSER)
zephyr_library_sources(
boot_serial_extensions.c
)

zephyr_linker_sources_ifdef(
CONFIG_ENABLE_MGMT_PERUSER
SECTIONS include/boot_serial/boot_serial.ld
)

if(DEFINED CONFIG_BOOT_MGMT_CUSTOM_STORAGE_ERASE OR DEFINED CONFIG_BOOT_MGMT_CUSTOM_IMG_LIST)
zephyr_library_sources(
boot_serial_extension_zephyr_basic.c
)
endif()
endif()

if(NOT DEFINED CONFIG_FLASH_PAGE_LAYOUT)
Expand Down
6 changes: 0 additions & 6 deletions boot/zephyr/Kconfig.serial_recovery
Original file line number Diff line number Diff line change
Expand Up @@ -128,12 +128,6 @@ config BOOT_MGMT_CUSTOM_STORAGE_ERASE
Note that the storage partition needs to be defined, in DTS, otherwise
enabling the option will cause a compilation to fail.

config BOOT_MGMT_CUSTOM_IMG_LIST
bool "Enable custom image list command"
help
The option enables command which returns versions and installation
statuses (custom property) for all images.

endif # ENABLE_MGMT_PERUSER

menu "Entrance methods"
Expand Down
71 changes: 71 additions & 0 deletions boot/zephyr/boot_serial_extension_zephyr_basic.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* Copyright (c) 2021-2023 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <stdio.h>
#include <zephyr/kernel.h>
#include <zephyr/drivers/flash.h>
#include <zephyr/mgmt/mcumgr/mgmt/mgmt_defines.h>
#include <zephyr/mgmt/mcumgr/grp/zephyr/zephyr_basic.h>
#include <../subsys/mgmt/mcumgr/transport/include/mgmt/mcumgr/transport/smp_internal.h>

#include <flash_map_backend/flash_map_backend.h>
#include <sysflash/sysflash.h>

#include "bootutil/bootutil_log.h"
#include "../boot_serial/src/boot_serial_priv.h"
#include <zcbor_encode.h>

#include "bootutil/image.h"
#include "bootutil/bootutil_public.h"
#include "bootutil/boot_hooks.h"

#include <boot_serial/boot_serial_extensions.h>

BOOT_LOG_MODULE_DECLARE(mcuboot);

#ifdef CONFIG_BOOT_MGMT_CUSTOM_STORAGE_ERASE
static int bs_custom_storage_erase(const struct nmgr_hdr *hdr,
const char *buffer, int len,
zcbor_state_t *cs)
{
int rc;
const struct flash_area *fa;

(void)buffer;
(void)len;

if (hdr->nh_group != ZEPHYR_MGMT_GRP_BASIC || hdr->nh_op != NMGR_OP_WRITE ||
hdr->nh_id != ZEPHYR_MGMT_GRP_BASIC_CMD_ERASE_STORAGE) {
return MGMT_ERR_ENOTSUP;
}

rc = flash_area_open(FIXED_PARTITION_ID(storage_partition), &fa);

if (rc < 0) {
BOOT_LOG_ERR("failed to open flash area");
} else {
rc = flash_area_erase(fa, 0, flash_area_get_size(fa));
if (rc < 0) {
BOOT_LOG_ERR("failed to erase flash area");
}
flash_area_close(fa);
}
if (rc == 0) {
rc = MGMT_ERR_OK;
} else {
rc = MGMT_ERR_EUNKNOWN;
}

zcbor_map_start_encode(cs, 10);
zcbor_tstr_put_lit(cs, "rc");
zcbor_uint32_put(cs, rc);
zcbor_map_end_encode(cs, 10);

return rc;
}

MCUMGR_HANDLER_DEFINE(storage_erase, bs_custom_storage_erase);
#endif
147 changes: 8 additions & 139 deletions boot/zephyr/boot_serial_extensions.c
Original file line number Diff line number Diff line change
@@ -1,161 +1,30 @@
/*
* Copyright (c) 2021 Nordic Semiconductor ASA
* Copyright (c) 2021-2023 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <stdio.h>
#include <zephyr/kernel.h>
#include <zephyr/drivers/flash.h>
#include <zephyr/mgmt/mcumgr/mgmt/mgmt_defines.h>
#include <zephyr/mgmt/mcumgr/grp/zephyr/zephyr_basic.h>
#include <../subsys/mgmt/mcumgr/transport/include/mgmt/mcumgr/transport/smp_internal.h>

#include <flash_map_backend/flash_map_backend.h>
#include <sysflash/sysflash.h>

#include "bootutil/bootutil_log.h"
#include "../boot_serial/src/boot_serial_priv.h"
#include <zcbor_encode.h>

#include "bootutil/image.h"
#include "bootutil/bootutil_public.h"
#include "bootutil/boot_hooks.h"
#include <boot_serial/boot_serial_extensions.h>

BOOT_LOG_MODULE_DECLARE(mcuboot);

#ifdef CONFIG_BOOT_MGMT_CUSTOM_STORAGE_ERASE
static int bs_custom_storage_erase(zcbor_state_t *cs)
{
int rc;

const struct flash_area *fa;

rc = flash_area_open(FIXED_PARTITION_ID(storage_partition), &fa);

if (rc < 0) {
BOOT_LOG_ERR("failed to open flash area");
} else {
rc = flash_area_erase(fa, 0, flash_area_get_size(fa));
if (rc < 0) {
BOOT_LOG_ERR("failed to erase flash area");
}
flash_area_close(fa);
}
if (rc == 0) {
rc = MGMT_ERR_OK;
} else {
rc = MGMT_ERR_EUNKNOWN;
}

zcbor_map_start_encode(cs, 10);
zcbor_tstr_put_lit(cs, "rc");
zcbor_uint32_put(cs, rc);
zcbor_map_end_encode(cs, 10);

return rc;
}
#endif

#ifdef MCUBOOT_MGMT_CUSTOM_IMG_LIST
static int custom_img_status(int image_index, uint32_t slot,char *buffer,
ssize_t len)
{
uint32_t area_id;
struct flash_area const *fap;
struct image_header hdr;
int rc;
int img_install_stat;

rc = BOOT_HOOK_CALL(boot_img_install_stat_hook, BOOT_HOOK_REGULAR,
image_index, slot, &img_install_stat);
if (rc == BOOT_HOOK_REGULAR)
{
img_install_stat = 0;
}

rc = BOOT_HOOK_CALL(boot_read_image_header_hook, BOOT_HOOK_REGULAR,
image_index, slot, &hdr);
if (rc == BOOT_HOOK_REGULAR)
{
area_id = flash_area_id_from_multi_image_slot(image_index, slot);

rc = flash_area_open(area_id, &fap);
if (rc) {
return rc;
}

rc = flash_area_read(fap, 0, &hdr, sizeof(hdr));

flash_area_close(fap);
}

if (rc == 0) {
if (hdr.ih_magic == IMAGE_MAGIC) {
snprintf(buffer, len, "ver=%d.%d.%d.%d,install_stat=%d",
hdr.ih_ver.iv_major,
hdr.ih_ver.iv_minor,
hdr.ih_ver.iv_revision,
hdr.ih_ver.iv_build_num,
img_install_stat);
} else {
rc = 1;
}
}

return rc;
}

static int bs_custom_img_list(zcbor_state_t *cs)
{
int rc = 0;
char tmpbuf[64]; /* Buffer should fit version and flags */

zcbor_map_start_encode(cs, 10);

for (int img = 0; img < MCUBOOT_IMAGE_NUMBER; img++) {
for (int slot = 0; slot < 2; slot++) {
rc = custom_img_status(img, slot, tmpbuf, sizeof(tmpbuf));

zcbor_int32_put(cs, img * 2 + slot + 1);
if (rc == 0) {
zcbor_tstr_put_term(cs, tmpbuf);
} else {
zcbor_tstr_put_lit(cs, "");
}
}
}

zcbor_tstr_put_lit(cs, "rc");
zcbor_uint32_put(cs, MGMT_ERR_OK);
zcbor_map_end_encode(cs, 10);

return rc;
}

#ifndef ZEPHYR_MGMT_GRP_BASIC_CMD_IMAGE_LIST
#define ZEPHYR_MGMT_GRP_BASIC_CMD_IMAGE_LIST 1
#endif
#endif /*MCUBOOT_MGMT_CUSTOM_IMG_LIST*/

int bs_peruser_system_specific(const struct nmgr_hdr *hdr, const char *buffer,
int len, zcbor_state_t *cs)
{
int mgmt_rc = MGMT_ERR_ENOTSUP;

if (hdr->nh_group == ZEPHYR_MGMT_GRP_BASIC) {
if (hdr->nh_op == NMGR_OP_WRITE) {
#ifdef CONFIG_BOOT_MGMT_CUSTOM_STORAGE_ERASE
if (hdr->nh_id == ZEPHYR_MGMT_GRP_BASIC_CMD_ERASE_STORAGE) {
mgmt_rc = bs_custom_storage_erase(cs);
}
#endif
} else if (hdr->nh_op == NMGR_OP_READ) {
#ifdef MCUBOOT_MGMT_CUSTOM_IMG_LIST
if (hdr->nh_id == ZEPHYR_MGMT_GRP_BASIC_CMD_IMAGE_LIST) {
mgmt_rc = bs_custom_img_list(cs);
STRUCT_SECTION_FOREACH(mcuboot_bs_custom_handlers, function) {
if (function->handler) {
mgmt_rc = function->handler(hdr, buffer, len, cs);

if (mgmt_rc != MGMT_ERR_ENOTSUP) {
break;
}
#endif
}
}

Expand Down
9 changes: 9 additions & 0 deletions boot/zephyr/include/boot_serial/boot_serial.ld
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
* Copyright (c) 2023 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <zephyr/linker/iterable_sections.h>

ITERABLE_SECTION_ROM(mcuboot_bs_custom_handlers, 4)
41 changes: 41 additions & 0 deletions boot/zephyr/include/boot_serial/boot_serial_extensions.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright (c) 2023 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef H_BOOT_SERIAL_EXTENTIONS_
#define H_BOOT_SERIAL_EXTENTIONS_

#include <zephyr/kernel.h>
#include <zephyr/sys/util_macro.h>
#include <zephyr/sys/iterable_sections.h>

/**
* Callback handler prototype for boot serial extensions.
*
* @param[in] hdr MCUmgr header
* @param[in] buffer Buffer with first MCUmgr message
* @param[in] len Length of data in buffer
* @param[out] cs Response
*
* @return MGMT_ERR_ENOTSUP to run other handlers, other MGMT_ERR_* value
* when expected handler has ran.
*/
typedef int (*bs_custom_handler_cb)(const struct nmgr_hdr *hdr,
const char *buffer, int len,
zcbor_state_t *cs);

struct mcuboot_bs_custom_handlers {
const bs_custom_handler_cb handler;
};

/* Used to create an iterable section containing a boot serial handler
* function
*/
#define MCUMGR_HANDLER_DEFINE(name, _handler) \
STRUCT_SECTION_ITERABLE(mcuboot_bs_custom_handlers, name) = { \
.handler = _handler, \
}

#endif /* H_BOOT_SERIAL_EXTENTIONS_ */

0 comments on commit c26e4c9

Please sign in to comment.