Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

zephyr: Allow user-defined boot serial extensions #1788

Merged
merged 2 commits into from
Sep 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
Comment on lines +21 to +26
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't this mean that there might be more than one handler called for the same buffer and mutiple responses being sent for one?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it would be a 1:1 mapping, if there are 3 handlers registered, the first one will be called, if it is not valid for that then it must return MGMT_ERR_ENOTSUP, it will then check the next handler, if the next handler is valid, it will return something else (i.e. usually EOK but could return EINVAL or anything) and then the loop here will be broken out, the final handler would not be called

}
#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_ */
3 changes: 3 additions & 0 deletions docs/release-notes.d/zephyr-bs-extensions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- Reworked boot serial extensions so that they can be used by modules
or from user repositories by switching to iterable sections.
- Removed Zephyr custom img list boot serial extension support.
Loading