| /* |
| * 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 int blinfo_handle_set(const char *name, size_t len, settings_read_cb read_cb, void *cb_arg); |
| |
| static struct settings_handler blinfo_handler = { |
| .name = "blinfo", |
| .h_get = blinfo_handle_get, |
| .h_set = blinfo_handle_set, |
| }; |
| |
| 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); |
| } |
| |
| static int blinfo_handle_set(const char *name, size_t len, settings_read_cb read_cb, void *cb_arg) |
| { |
| return -ENOTSUP; |
| } |
| #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); |