From 1715133d49d42abcf8268225252dfc17ffb24d27 Mon Sep 17 00:00:00 2001 From: Laczen JMS Date: Mon, 19 Jun 2023 15:50:54 +0200 Subject: [PATCH] boot_info: A subsystem to share bootloader info boot_info is a simple subsystem to share information between a bootloader and an application. It can store the info in a bbram device or a zephyr,memory-region (RAM). Signed-off-by: Laczen JMS --- dts/bindings/misc/zephyr,boot-info-bbram.yaml | 15 +++ dts/bindings/misc/zephyr,boot-info-ram.yaml | 15 +++ include/zephyr/boot_info/boot_info.h | 102 ++++++++++++++++++ subsys/CMakeLists.txt | 1 + subsys/Kconfig | 1 + subsys/boot_info/CMakeLists.txt | 4 + subsys/boot_info/Kconfig | 16 +++ subsys/boot_info/boot_info.c | 101 +++++++++++++++++ tests/subsys/boot_info/CMakeLists.txt | 9 ++ .../subsys/boot_info/boards/native_posix.conf | 4 + .../boot_info/boards/native_posix.overlay | 21 ++++ .../boot_info/boards/nucleo_f411re.conf | 5 + .../boot_info/boards/nucleo_f411re.overlay | 20 ++++ .../boot_info/boards/qemu_cortex_m3.conf | 3 + .../boot_info/boards/qemu_cortex_m3.overlay | 28 +++++ tests/subsys/boot_info/boards/qemu_x86.conf | 4 + .../subsys/boot_info/boards/qemu_x86.overlay | 21 ++++ tests/subsys/boot_info/prj.conf | 5 + tests/subsys/boot_info/src/main.c | 44 ++++++++ tests/subsys/boot_info/testcase.yaml | 15 +++ 20 files changed, 434 insertions(+) create mode 100644 dts/bindings/misc/zephyr,boot-info-bbram.yaml create mode 100644 dts/bindings/misc/zephyr,boot-info-ram.yaml create mode 100644 include/zephyr/boot_info/boot_info.h create mode 100644 subsys/boot_info/CMakeLists.txt create mode 100644 subsys/boot_info/Kconfig create mode 100644 subsys/boot_info/boot_info.c create mode 100644 tests/subsys/boot_info/CMakeLists.txt create mode 100644 tests/subsys/boot_info/boards/native_posix.conf create mode 100644 tests/subsys/boot_info/boards/native_posix.overlay create mode 100644 tests/subsys/boot_info/boards/nucleo_f411re.conf create mode 100644 tests/subsys/boot_info/boards/nucleo_f411re.overlay create mode 100644 tests/subsys/boot_info/boards/qemu_cortex_m3.conf create mode 100644 tests/subsys/boot_info/boards/qemu_cortex_m3.overlay create mode 100644 tests/subsys/boot_info/boards/qemu_x86.conf create mode 100644 tests/subsys/boot_info/boards/qemu_x86.overlay create mode 100644 tests/subsys/boot_info/prj.conf create mode 100644 tests/subsys/boot_info/src/main.c create mode 100644 tests/subsys/boot_info/testcase.yaml diff --git a/dts/bindings/misc/zephyr,boot-info-bbram.yaml b/dts/bindings/misc/zephyr,boot-info-bbram.yaml new file mode 100644 index 000000000000000..bc9fa8eef549e0f --- /dev/null +++ b/dts/bindings/misc/zephyr,boot-info-bbram.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2023 Laczen +# SPDX-License-Identifier: Apache-2.0 + +description: Boot information area stored on bbram + +compatible: "zephyr,boot-info-bbram" + +include: base.yaml + +properties: + backend: + type: phandle + required: true + description: | + Battery backend-up ram used to store the bootinfo. diff --git a/dts/bindings/misc/zephyr,boot-info-ram.yaml b/dts/bindings/misc/zephyr,boot-info-ram.yaml new file mode 100644 index 000000000000000..0eedf94d34b9c23 --- /dev/null +++ b/dts/bindings/misc/zephyr,boot-info-ram.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2023 Laczen +# SPDX-License-Identifier: Apache-2.0 + +description: Boot information area stored on ram + +compatible: "zephyr,boot-info-ram" + +include: base.yaml + +properties: + backend: + type: phandle + required: true + description: | + Memory region used to store the bootinfo. diff --git a/include/zephyr/boot_info/boot_info.h b/include/zephyr/boot_info/boot_info.h new file mode 100644 index 000000000000000..117e972a8a08fdc --- /dev/null +++ b/include/zephyr/boot_info/boot_info.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2023 Laczen + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Public API for boot_info subsys + */ + +#ifndef ZEPHYR_INCLUDE_BOOT_INFO_BOOT_INFO_H_ +#define ZEPHYR_INCLUDE_BOOT_INFO_BOOT_INFO_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief boot_info api + * + * @defgroup boot_info_api boot_info Interface + * @ingroup storage_apis + * @{ + */ + +/** + * @brief boot_info: subsystem to share information between a bootloader and + * and application started from the bootloader. The boot_info subsystem uses + * stores it information in a area of RAM (a zephyr, memory-region) or a bbram + * device. To save valuable rom space this subsystem does not create devices. + * + * The usage pattern of the boot_info system is: + * a. Create a array for the boot_info data: + * uint8_t data[boot_info_get_size(DT_NODELABEL(boot_info))]; + * b. Get the boot_info data: + * int rc = boot_info_get(DT_NODELABEL(boot_info), data); + * c. Modify the data (optional) + * d. Write back the data (optional): + * int rc = boot_info_set(DT_NODELABEL(boot_info), data); + * + * For bbram storage the boot_info is defined in the dts as: + * / { + * boot_info: boot_info { + * compatible = "zephyr, boot-info-bbram"; + * backend = <&bbram>; # bbram node: bbram + * }; + * } + * + * For ram storage the boot_info is defined in the dts as: + * / { + * boot_info: boot_info { + * compatible = "zephyr, boot-info-ram"; + * backend = <&mem-region>; # mem-region: mem-region node + * }; + */ + +/** + * @brief boot_info_get_size: Get the size of the boot_info area. + * + * @param _node: nodelabel of the boot_info area (e.g. DT_NODELABEL(boot_info)). + * @retval size of the boot_info area. + */ +#define boot_info_get_size(_node) _CONCAT(bi_get_size_, _node)() + +/** + * @brief boot_info_get: Get the boot_info area. + * + * @param _node: nodelabel of the boot_info area (e.g. DT_NODELABEL(boot_info)). + * @param [out] _data: buffer for the boot_info area. + * @retval 0 on success, negative error code if error. + */ +#define boot_info_get(_node, _data) _CONCAT(bi_get_, _node)(_data) + +/** + * @brief boot_info_set: Set the boot_info area. + * + * @param _node: nodelabel of the boot_info area (e.g. DT_NODELABEL(boot_info)). + * @param [in] _data: buffer for the boot_info area. + * @retval 0 on success, negative error code if error. + */ +#define boot_info_set(_node, _data) _CONCAT(bi_set_, _node)(_data) + +/** + * @} + */ + +#define DEFINE_BOOT_INFO_PROTO(inst) \ + size_t bi_get_size_##inst(void); \ + int bi_get_##inst(void *data); \ + int bi_set_##inst(const void *data); + +DT_FOREACH_STATUS_OKAY(zephyr_boot_info_ram, DEFINE_BOOT_INFO_PROTO) + +DT_FOREACH_STATUS_OKAY(zephyr_boot_info_bbram, DEFINE_BOOT_INFO_PROTO) + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_BOOT_INFO_BOOT_INFO_H_ */ diff --git a/subsys/CMakeLists.txt b/subsys/CMakeLists.txt index 53ee9f96c816609..41850a1802912dc 100644 --- a/subsys/CMakeLists.txt +++ b/subsys/CMakeLists.txt @@ -37,3 +37,4 @@ add_subdirectory_ifdef(CONFIG_SHELL shell) add_subdirectory_ifdef(CONFIG_TIMING_FUNCTIONS timing) add_subdirectory_ifdef(CONFIG_ZBUS zbus) add_subdirectory_ifdef(CONFIG_ARM_SIP_SVC_SUBSYS sip_svc) +add_subdirectory_ifdef(CONFIG_BOOT_INFO boot_info) diff --git a/subsys/Kconfig b/subsys/Kconfig index 0bf699da96ce60b..9da38baaa54ffd2 100644 --- a/subsys/Kconfig +++ b/subsys/Kconfig @@ -7,6 +7,7 @@ menu "Subsystems and OS Services" source "subsys/bluetooth/Kconfig" +source "subsys/boot_info/Kconfig" source "subsys/canbus/Kconfig" source "subsys/console/Kconfig" source "subsys/debug/Kconfig" diff --git a/subsys/boot_info/CMakeLists.txt b/subsys/boot_info/CMakeLists.txt new file mode 100644 index 000000000000000..a38e730b966df01 --- /dev/null +++ b/subsys/boot_info/CMakeLists.txt @@ -0,0 +1,4 @@ +# Copyright (c) 2023 Laczen +# SPDX-License-Identifier: Apache-2.0 + +zephyr_sources_ifdef(CONFIG_BOOT_INFO boot_info.c) diff --git a/subsys/boot_info/Kconfig b/subsys/boot_info/Kconfig new file mode 100644 index 000000000000000..7943d0fc2a3e8fc --- /dev/null +++ b/subsys/boot_info/Kconfig @@ -0,0 +1,16 @@ +# Copyright (c) 2023 Laczen +# SPDX-License-Identifier: Apache-2.0 + +menuconfig BOOT_INFO + bool "Boot Information Area" + help + Enable boot information area access with different backend solutions. + The boot information area can be stored on bbram, ram, ... + +if BOOT_INFO + +module = BOOT_INFO +module-str = boot_info +source "subsys/logging/Kconfig.template.log_config" + +endif # BOOT_INFO diff --git a/subsys/boot_info/boot_info.c b/subsys/boot_info/boot_info.c new file mode 100644 index 000000000000000..cfdf0daf04b0307 --- /dev/null +++ b/subsys/boot_info/boot_info.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2023 Laczen + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#define BACKEND_PHANDLE(inst) DT_PHANDLE(inst, backend) + +#define BACKEND_K_SEM_DEFINE(inst) \ + COND_CODE_1(CONFIG_MULTITHREADING, \ + (static K_SEM_DEFINE(k_sem_##inst, 1, 1)), ()) + +#define BACKEND_K_SEM_TAKE(inst) \ + COND_CODE_1(CONFIG_MULTITHREADING, \ + (k_sem_take(&k_sem_##inst, K_FOREVER)), ()) + +#define BACKEND_K_SEM_GIVE(inst) \ + COND_CODE_1(CONFIG_MULTITHREADING, (k_sem_give(&k_sem_##inst)), ()) + +#define RAM_BACKEND_FCNTS(inst) \ + BACKEND_K_SEM_DEFINE(inst); \ + size_t bi_get_size_##inst(void) \ + { \ + return DT_REG_SIZE(BACKEND_PHANDLE(inst)); \ + } \ + int bi_get_##inst(void *data) \ + { \ + BACKEND_K_SEM_TAKE(inst); \ + memcpy(data, (uint8_t *)DT_REG_ADDR(BACKEND_PHANDLE(inst)), \ + DT_REG_SIZE(BACKEND_PHANDLE(inst))); \ + BACKEND_K_SEM_GIVE(inst); \ + return 0; \ + } \ + int bi_set_##inst(const void *data) \ + { \ + BACKEND_K_SEM_TAKE(inst); \ + memcpy((uint8_t *)DT_REG_ADDR(BACKEND_PHANDLE(inst)), data, \ + DT_REG_SIZE(BACKEND_PHANDLE(inst))); \ + BACKEND_K_SEM_GIVE(inst); \ + return 0; \ + } + +DT_FOREACH_STATUS_OKAY(zephyr_boot_info_ram, RAM_BACKEND_FCNTS) + +#define BBRAM_BACKEND_FCNTS(inst) \ + BACKEND_K_SEM_DEFINE(inst); \ + const struct device *const bi_dev_##inst = \ + DEVICE_DT_GET_OR_NULL(BACKEND_PHANDLE(inst)); \ + size_t bi_get_size_##inst(void) \ + { \ + if (!device_is_ready(bi_dev_##inst)) { \ + return 0U; \ + } \ + \ + size_t bbram_size = 0; \ + int rc; \ + BACKEND_K_SEM_TAKE(inst); \ + rc = bbram_get_size(bi_dev_##inst, &bbram_size); \ + BACKEND_K_SEM_GIVE(inst); \ + return (rc == 0) ? bbram_size : 0U; \ + } \ + int bi_get_##inst(void *data) \ + { \ + if (!device_is_ready(bi_dev_##inst)) { \ + return -ENODEV; \ + } \ + \ + size_t bbram_size = 0; \ + int rc; \ + BACKEND_K_SEM_TAKE(inst); \ + rc = bbram_get_size(bi_dev_##inst, &bbram_size); \ + if (rc == 0) { \ + rc = bbram_read(bi_dev_##inst, 0, bbram_size, data); \ + } \ + BACKEND_K_SEM_GIVE(inst); \ + return rc; \ + } \ + int bi_set_##inst(const void *data) \ + { \ + if (!device_is_ready(bi_dev_##inst)) { \ + return -ENODEV; \ + } \ + \ + size_t bbram_size = 0; \ + int rc; \ + BACKEND_K_SEM_TAKE(inst); \ + rc = bbram_get_size(bi_dev_##inst, &bbram_size); \ + if (rc == 0) { \ + rc = bbram_write(bi_dev_##inst, 0, bbram_size, data); \ + } \ + BACKEND_K_SEM_GIVE(inst); \ + return rc; \ + } + +DT_FOREACH_STATUS_OKAY(zephyr_boot_info_bbram, BBRAM_BACKEND_FCNTS) diff --git a/tests/subsys/boot_info/CMakeLists.txt b/tests/subsys/boot_info/CMakeLists.txt new file mode 100644 index 000000000000000..4246e29fc87a144 --- /dev/null +++ b/tests/subsys/boot_info/CMakeLists.txt @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Laczen +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(boot_info_test) + +target_sources(app PRIVATE src/main.c) diff --git a/tests/subsys/boot_info/boards/native_posix.conf b/tests/subsys/boot_info/boards/native_posix.conf new file mode 100644 index 000000000000000..cdee167d5233e70 --- /dev/null +++ b/tests/subsys/boot_info/boards/native_posix.conf @@ -0,0 +1,4 @@ +# Copyright (c) 2023 Laczen +# SPDX-License-Identifier: Apache-2.0 +CONFIG_BBRAM=y +CONFIG_BBRAM_EMUL=y diff --git a/tests/subsys/boot_info/boards/native_posix.overlay b/tests/subsys/boot_info/boards/native_posix.overlay new file mode 100644 index 000000000000000..a199023ec39f0c7 --- /dev/null +++ b/tests/subsys/boot_info/boards/native_posix.overlay @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2023 Laczen + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + bbram_emu: bbram_emu { + compatible = "zephyr,bbram-emul"; + size = <0x20>; + }; + + boot_info: boot_info { + compatible = "zephyr,boot-info-bbram"; + backend = <&bbram_emu>; + }; + + aliases { + bi = &boot_info; + }; + +}; diff --git a/tests/subsys/boot_info/boards/nucleo_f411re.conf b/tests/subsys/boot_info/boards/nucleo_f411re.conf new file mode 100644 index 000000000000000..2746f0827d0f750 --- /dev/null +++ b/tests/subsys/boot_info/boards/nucleo_f411re.conf @@ -0,0 +1,5 @@ +# Copyright (c) 2023 Laczen +# SPDX-License-Identifier: Apache-2.0 +CONFIG_BBRAM=y +CONFIG_COUNTER=y +CONFIG_BBRAM_STM32=y diff --git a/tests/subsys/boot_info/boards/nucleo_f411re.overlay b/tests/subsys/boot_info/boards/nucleo_f411re.overlay new file mode 100644 index 000000000000000..098d0d9f12901b9 --- /dev/null +++ b/tests/subsys/boot_info/boards/nucleo_f411re.overlay @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Laczen + * SPDX-License-Identifier: Apache-2.0 + */ + +&bbram { + status = "okay"; +}; + +/ { + boot_info: boot_info { + compatible = "zephyr,boot-info-bbram"; + backend = <&bbram>; + }; + + aliases { + bi = &boot_info; + }; + +}; diff --git a/tests/subsys/boot_info/boards/qemu_cortex_m3.conf b/tests/subsys/boot_info/boards/qemu_cortex_m3.conf new file mode 100644 index 000000000000000..bb0c087bb7612b8 --- /dev/null +++ b/tests/subsys/boot_info/boards/qemu_cortex_m3.conf @@ -0,0 +1,3 @@ +# Copyright (c) 2023 Laczen +# SPDX-License-Identifier: Apache-2.0 +CONFIG_USERSPACE=y diff --git a/tests/subsys/boot_info/boards/qemu_cortex_m3.overlay b/tests/subsys/boot_info/boards/qemu_cortex_m3.overlay new file mode 100644 index 000000000000000..a0f7ff925bd11a4 --- /dev/null +++ b/tests/subsys/boot_info/boards/qemu_cortex_m3.overlay @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023 Laczen + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + bi_region: sram@2000FFE0 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x2000FFE0 0x20>; + zephyr,memory-region = "BI_REGION"; + }; + + boot_info: boot_info { + compatible = "zephyr,boot-info-ram"; + backend = <&bi_region>; + }; + + aliases { + bi = &boot_info; + }; + +}; + +&sram0 { + reg = <0x20000000 0xFFE0>; +}; diff --git a/tests/subsys/boot_info/boards/qemu_x86.conf b/tests/subsys/boot_info/boards/qemu_x86.conf new file mode 100644 index 000000000000000..cdee167d5233e70 --- /dev/null +++ b/tests/subsys/boot_info/boards/qemu_x86.conf @@ -0,0 +1,4 @@ +# Copyright (c) 2023 Laczen +# SPDX-License-Identifier: Apache-2.0 +CONFIG_BBRAM=y +CONFIG_BBRAM_EMUL=y diff --git a/tests/subsys/boot_info/boards/qemu_x86.overlay b/tests/subsys/boot_info/boards/qemu_x86.overlay new file mode 100644 index 000000000000000..a199023ec39f0c7 --- /dev/null +++ b/tests/subsys/boot_info/boards/qemu_x86.overlay @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2023 Laczen + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + bbram_emu: bbram_emu { + compatible = "zephyr,bbram-emul"; + size = <0x20>; + }; + + boot_info: boot_info { + compatible = "zephyr,boot-info-bbram"; + backend = <&bbram_emu>; + }; + + aliases { + bi = &boot_info; + }; + +}; diff --git a/tests/subsys/boot_info/prj.conf b/tests/subsys/boot_info/prj.conf new file mode 100644 index 000000000000000..cb39cc7212c3497 --- /dev/null +++ b/tests/subsys/boot_info/prj.conf @@ -0,0 +1,5 @@ +# Copyright (c) 2023 Laczen +# SPDX-License-Identifier: Apache-2.0 +CONFIG_BOOT_INFO=y +CONFIG_ZTEST=y +CONFIG_ZTEST_NEW_API=y diff --git a/tests/subsys/boot_info/src/main.c b/tests/subsys/boot_info/src/main.c new file mode 100644 index 000000000000000..a34ddfa893da64d --- /dev/null +++ b/tests/subsys/boot_info/src/main.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2012-2014 Wind River Systems, Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#define BOOT_INFO DT_NODELABEL(boot_info) +#define BOOT_INFO_ALIAS DT_ALIAS(bi) + +ZTEST_USER(boot_info_api, test_get_size) +{ + size_t bi_size = boot_info_get_size(BOOT_INFO); + + zassert_not_equal(bi_size, 0U, "Get size returned invalid value"); +} + +ZTEST_USER(boot_info_api, test_get_set) +{ + uint8_t wr[boot_info_get_size(BOOT_INFO)]; + uint8_t rd[boot_info_get_size(BOOT_INFO)]; + int rc = 0; + + memset(wr, 0, sizeof(wr)); + memset(rd, 0, sizeof(rd)); + + rc = boot_info_get(BOOT_INFO, wr); + zassert_equal(rc, 0, "boot_info_get returned [%d]", rc); + + memset(wr, 0xa, sizeof(wr)); + rc = boot_info_set(BOOT_INFO, wr); + zassert_equal(rc, 0, "boot_info_set returned [%d]", rc); + + rc = boot_info_get(BOOT_INFO, rd); + zassert_equal(rc, 0, "boot_info_get returned [%d]", rc); + + zassert_equal(memcmp(rd, wr, sizeof(wr)), 0, "data mismatch"); +} + +ZTEST_SUITE(boot_info_api, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/subsys/boot_info/testcase.yaml b/tests/subsys/boot_info/testcase.yaml new file mode 100644 index 000000000000000..5067a0a33400c52 --- /dev/null +++ b/tests/subsys/boot_info/testcase.yaml @@ -0,0 +1,15 @@ +common: + depends_on: boot_info + tags: boot_info + platform_allow: + - qemu_cortex_m3 + - qemu_x86 + - native_posix + - nucleo_f411re +tests: + boot_info.cortex_m3.api: + platform_allow: qemu_cortex_m3 + timeout: 60 + boot_info.qemu_x86.api: + platform_allow: qemu_x86 + timeout: 60