2023-03-14 20:37:49 +08:00
|
|
|
/*
|
|
|
|
* 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);
|
2023-10-12 14:50:48 +08:00
|
|
|
static int blinfo_handle_set(const char *name, size_t len, settings_read_cb read_cb, void *cb_arg);
|
2023-03-14 20:37:49 +08:00
|
|
|
|
|
|
|
static struct settings_handler blinfo_handler = {
|
|
|
|
.name = "blinfo",
|
|
|
|
.h_get = blinfo_handle_get,
|
2023-10-12 14:50:48 +08:00
|
|
|
.h_set = blinfo_handle_set,
|
2023-03-14 20:37:49 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
2023-10-12 14:50:48 +08:00
|
|
|
|
|
|
|
static int blinfo_handle_set(const char *name, size_t len, settings_read_cb read_cb, void *cb_arg)
|
|
|
|
{
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
2023-03-14 20:37:49 +08:00
|
|
|
#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);
|