zephyr: Allow user-defined boot serial extensions
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 <jamie.mccrae@nordicsemi.no>
diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt
index 638bd91..159ef5d 100644
--- a/boot/zephyr/CMakeLists.txt
+++ b/boot/zephyr/CMakeLists.txt
@@ -85,6 +85,17 @@
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)
diff --git a/boot/zephyr/Kconfig.serial_recovery b/boot/zephyr/Kconfig.serial_recovery
index 52ec3b0..c73badd 100644
--- a/boot/zephyr/Kconfig.serial_recovery
+++ b/boot/zephyr/Kconfig.serial_recovery
@@ -128,12 +128,6 @@
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"
diff --git a/boot/zephyr/boot_serial_extension_zephyr_basic.c b/boot/zephyr/boot_serial_extension_zephyr_basic.c
new file mode 100644
index 0000000..b0c75f4
--- /dev/null
+++ b/boot/zephyr/boot_serial_extension_zephyr_basic.c
@@ -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
diff --git a/boot/zephyr/boot_serial_extensions.c b/boot/zephyr/boot_serial_extensions.c
index b8bcd3e..abbb651 100644
--- a/boot/zephyr/boot_serial_extensions.c
+++ b/boot/zephyr/boot_serial_extensions.c
@@ -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);
+ 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
- } 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);
- }
-#endif
}
}
diff --git a/boot/zephyr/include/boot_serial/boot_serial.ld b/boot/zephyr/include/boot_serial/boot_serial.ld
new file mode 100644
index 0000000..c0e82ad
--- /dev/null
+++ b/boot/zephyr/include/boot_serial/boot_serial.ld
@@ -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)
diff --git a/boot/zephyr/include/boot_serial/boot_serial_extensions.h b/boot/zephyr/include/boot_serial/boot_serial_extensions.h
new file mode 100644
index 0000000..6eea574
--- /dev/null
+++ b/boot/zephyr/include/boot_serial/boot_serial_extensions.h
@@ -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_ */