retention: Add bootloader configuration interface
Adds a bootloader configuration interface which allows for a bootloader (e.g. MCUboot) to set configuration in a shared data area which is then read by the application. Signed-off-by: Jamie McCrae <jamie.mccrae@nordicsemi.no>
This commit is contained in:
parent
59c501c6df
commit
db4febc584
58
include/zephyr/retention/blinfo.h
Normal file
58
include/zephyr/retention/blinfo.h
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Public API for boot mode interface
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_INCLUDE_RETENTION_BLINFO_
|
||||
#define ZEPHYR_INCLUDE_RETENTION_BLINFO_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <zephyr/kernel.h>
|
||||
|
||||
#if defined(CONFIG_RETENTION_BOOTLOADER_INFO_TYPE_MCUBOOT)
|
||||
#include <bootutil/boot_status.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Bootloader info interface
|
||||
* @defgroup bootloader_info_interface Bootloader info interface
|
||||
* @ingroup retention_api
|
||||
* @{
|
||||
*/
|
||||
|
||||
#if IS_ENABLED(CONFIG_RETENTION_BOOTLOADER_INFO_OUTPUT_FUNCTION) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Returns bootinfo information.
|
||||
*
|
||||
* @param key The information to return (for MCUboot: minor TLV).
|
||||
* @param val Where the return information will be placed.
|
||||
* @param val_len_max The maximum size of the provided buffer.
|
||||
*
|
||||
* @retval 0 If successful.
|
||||
* @retval -EOVERFLOW If the data is too large to fit the supplied buffer.
|
||||
* @retval -EIO If the requested key was not found.
|
||||
* @retval -errno Error code.
|
||||
*/
|
||||
int blinfo_lookup(uint16_t key, char *val, int val_len_max);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_RETENTION_BLINFO_ */
|
|
@ -624,6 +624,8 @@ flagged.
|
|||
"BOOT_SERIAL_CDC_ACM", # Used in (sysbuild-based) test
|
||||
"BOOT_SERIAL_ENTRANCE_GPIO", # Used in (sysbuild-based) test
|
||||
"BOOT_SERIAL_IMG_GRP_HASH", # Used in documentation
|
||||
"BOOT_SHARE_DATA", # Used in Kconfig text
|
||||
"BOOT_SHARE_BACKEND_RETENTION", # Used in Kconfig text
|
||||
"BOOT_SIGNATURE_KEY_FILE", # MCUboot setting used by sysbuild
|
||||
"BOOT_SIGNATURE_TYPE_ECDSA_P256", # MCUboot setting used by sysbuild
|
||||
"BOOT_SIGNATURE_TYPE_ED25519", # MCUboot setting used by sysbuild
|
||||
|
|
|
@ -3,3 +3,8 @@
|
|||
zephyr_library()
|
||||
zephyr_library_sources(retention.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_RETENTION_BOOT_MODE bootmode.c)
|
||||
|
||||
if(CONFIG_RETENTION_BOOTLOADER_INFO_TYPE_MCUBOOT)
|
||||
zephyr_library_sources(blinfo_mcuboot.c)
|
||||
zephyr_link_libraries(MCUBOOT_BOOTUTIL)
|
||||
endif()
|
||||
|
|
|
@ -17,7 +17,7 @@ config RETENTION_INIT_PRIORITY
|
|||
default 86
|
||||
help
|
||||
Retention device initialization priority (must be higher than init
|
||||
priorities for retained memory drivers.
|
||||
priorities for retained memory drivers).
|
||||
|
||||
config RETENTION_MUTEXES
|
||||
bool
|
||||
|
@ -55,6 +55,8 @@ config RETENTION_BOOT_MODE
|
|||
byte must be created and set as the "zephyr,boot-mode" chosen node
|
||||
via device tree.
|
||||
|
||||
source "subsys/retention/Kconfig.blinfo"
|
||||
|
||||
endmenu
|
||||
|
||||
module = RETENTION
|
||||
|
|
55
subsys/retention/Kconfig.blinfo
Normal file
55
subsys/retention/Kconfig.blinfo
Normal file
|
@ -0,0 +1,55 @@
|
|||
# Copyright (c) 2023, Nordic Semiconductor ASA
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
menuconfig RETENTION_BOOTLOADER_INFO
|
||||
bool "Bootloader info"
|
||||
help
|
||||
Adds a bootloader information sharing system which allows for
|
||||
retreiving data from the bootloader when data sharing is enabled.
|
||||
|
||||
if RETENTION_BOOTLOADER_INFO
|
||||
|
||||
# Workaround for not being able to have commas in macro arguments
|
||||
DT_CHOSEN_BOOTLOADER_INFO := zephyr,bootloader-info
|
||||
|
||||
config RETENTION_BOOTLOADER_INFO_TYPE_MCUBOOT
|
||||
bool "MCUboot"
|
||||
depends on !MCUBOOT && BOOTLOADER_MCUBOOT
|
||||
depends on $(dt_chosen_enabled,$(DT_CHOSEN_BOOTLOADER_INFO))
|
||||
select MCUBOOT_BOOTUTIL_LIB
|
||||
help
|
||||
Adds a bootloader information sharing system for MCUboot and
|
||||
applications which allows applications to read the configuration of
|
||||
MCUboot and the running image. This can be used by applications so
|
||||
that they know how to e.g. handle firmware updates and place them
|
||||
into the correct slot.
|
||||
|
||||
In order to use this, a retention area must be created and set as
|
||||
the "zephyr,bootloader-info" chosen node via device tree, MCUboot
|
||||
must be built with the same "zephyr,bootloader-info" DTS node and
|
||||
have CONFIG_BOOT_SHARE_DATA, CONFIG_BOOT_SHARE_DATA_BOOTINFO and
|
||||
CONFIG_BOOT_SHARE_BACKEND_RETENTION enabled, or the shared
|
||||
information will not be accessible.
|
||||
|
||||
config RETENTION_BOOTLOADER_INFO_INIT_PRIORITY
|
||||
int "Bootloader info init priority"
|
||||
default 87
|
||||
help
|
||||
Bootloader info initialization priority (must be higher than init
|
||||
priorities for for retention subsystem).
|
||||
|
||||
config RETENTION_BOOTLOADER_INFO_OUTPUT_FUNCTION
|
||||
bool "Function"
|
||||
default y
|
||||
help
|
||||
Allows bootloader settings to be fetched by calling a function which
|
||||
will update a buffer with the requested data.
|
||||
|
||||
config RETENTION_BOOTLOADER_INFO_OUTPUT_SETTINGS
|
||||
bool "Settings"
|
||||
depends on SETTINGS
|
||||
help
|
||||
Allows bootloader settings to be fetched using settings with the
|
||||
"blinfo" prefix.
|
||||
|
||||
endif
|
143
subsys/retention/blinfo_mcuboot.c
Normal file
143
subsys/retention/blinfo_mcuboot.c
Normal file
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/init.h>
|
||||
#include <zephyr/devicetree.h>
|
||||
#include <zephyr/retention/retention.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/settings/settings.h>
|
||||
#include <zephyr/retention/blinfo.h>
|
||||
#include <bootutil/boot_status.h>
|
||||
|
||||
LOG_MODULE_REGISTER(blinfo_mcuboot, CONFIG_RETENTION_LOG_LEVEL);
|
||||
|
||||
static const struct device *bootloader_info_dev =
|
||||
DEVICE_DT_GET(DT_CHOSEN(zephyr_bootloader_info));
|
||||
|
||||
#if !defined(CONFIG_RETENTION_BOOTLOADER_INFO_OUTPUT_FUNCTION)
|
||||
static
|
||||
#endif
|
||||
int blinfo_lookup(uint16_t key, char *val, int val_len_max)
|
||||
{
|
||||
struct shared_data_tlv_header header;
|
||||
struct shared_data_tlv_entry tlv_entry = {0};
|
||||
uintptr_t offset = SHARED_DATA_HEADER_SIZE;
|
||||
int rc;
|
||||
|
||||
rc = retention_read(bootloader_info_dev, 0, (void *)&header, sizeof(header));
|
||||
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Iterate over the whole shared MCUboot data section and look for a TLV with
|
||||
* the required tag.
|
||||
*/
|
||||
while (offset < header.tlv_tot_len) {
|
||||
rc = retention_read(bootloader_info_dev, offset, (void *)&tlv_entry,
|
||||
sizeof(tlv_entry));
|
||||
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (GET_MAJOR(tlv_entry.tlv_type) == TLV_MAJOR_BLINFO &&
|
||||
GET_MINOR(tlv_entry.tlv_type) == key) {
|
||||
/* Return an error if the provided buffer is too small to fit the
|
||||
* value in it, bootloader values are small and concise and should
|
||||
* be able to fit in a single buffer.
|
||||
*/
|
||||
if (tlv_entry.tlv_len > val_len_max) {
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
|
||||
offset += SHARED_DATA_ENTRY_HEADER_SIZE;
|
||||
rc = retention_read(bootloader_info_dev, offset, val,
|
||||
tlv_entry.tlv_len);
|
||||
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
return tlv_entry.tlv_len;
|
||||
}
|
||||
|
||||
offset += SHARED_DATA_ENTRY_SIZE(tlv_entry.tlv_len);
|
||||
}
|
||||
|
||||
/* Return IO error as a valid key name was provided but the TLV was not found in
|
||||
* the shared data section.
|
||||
*/
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_RETENTION_BOOTLOADER_INFO_OUTPUT_SETTINGS)
|
||||
static int blinfo_handle_get(const char *name, char *val, int val_len_max);
|
||||
|
||||
static struct settings_handler blinfo_handler = {
|
||||
.name = "blinfo",
|
||||
.h_get = blinfo_handle_get,
|
||||
};
|
||||
|
||||
static int blinfo_handle_get(const char *name, char *val, int val_len_max)
|
||||
{
|
||||
const char *next;
|
||||
uint16_t index;
|
||||
|
||||
/* Allowed keys are mode, signature_type, recovery, running_slot, bootloader_version
|
||||
* and max_application_size which cannot contain any additional entries
|
||||
*/
|
||||
if (settings_name_steq(name, "mode", &next) && !next) {
|
||||
index = BLINFO_MODE;
|
||||
} else if (settings_name_steq(name, "signature_type", &next) && !next) {
|
||||
index = BLINFO_SIGNATURE_TYPE;
|
||||
} else if (settings_name_steq(name, "recovery", &next) && !next) {
|
||||
index = BLINFO_RECOVERY;
|
||||
} else if (settings_name_steq(name, "running_slot", &next) && !next) {
|
||||
index = BLINFO_RUNNING_SLOT;
|
||||
} else if (settings_name_steq(name, "bootloader_version", &next) && !next) {
|
||||
index = BLINFO_BOOTLOADER_VERSION;
|
||||
} else if (settings_name_steq(name, "max_application_size", &next) && !next) {
|
||||
index = BLINFO_MAX_APPLICATION_SIZE;
|
||||
} else {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
return blinfo_lookup(index, val, val_len_max);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int blinfo_init(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = retention_is_valid(bootloader_info_dev);
|
||||
|
||||
if (rc == 1 || rc == -ENOTSUP) {
|
||||
struct shared_data_tlv_header header;
|
||||
|
||||
rc = retention_read(bootloader_info_dev, 0, (void *)&header, sizeof(header));
|
||||
|
||||
if (rc == 0 && header.tlv_magic != SHARED_DATA_TLV_INFO_MAGIC) {
|
||||
/* Unknown data present */
|
||||
LOG_ERR("MCUboot data load failed, expected magic value: 0x%x, got: 0x%x",
|
||||
SHARED_DATA_TLV_INFO_MAGIC, header.tlv_magic);
|
||||
rc = -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(CONFIG_RETENTION_BOOTLOADER_INFO_OUTPUT_SETTINGS)
|
||||
if (rc == 0) {
|
||||
settings_register(&blinfo_handler);
|
||||
}
|
||||
#endif
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
SYS_INIT(blinfo_init, APPLICATION, CONFIG_RETENTION_BOOTLOADER_INFO_INIT_PRIORITY);
|
Loading…
Reference in a new issue