/* * Copyright (c) 2023 Yonatan Schachter * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include LOG_MODULE_REGISTER(bindesc_read, CONFIG_BINDESC_READ_LOG_LEVEL); struct find_user_data { const void *result; size_t size; uint16_t tag; }; /** * A callback used by the bindesc_find_* functions. */ static int find_callback(const struct bindesc_entry *entry, void *user_data) { struct find_user_data *data = (struct find_user_data *)user_data; if (data->tag == entry->tag) { data->result = (const void *)&(entry->data); data->size = entry->len; return 1; } return 0; } /** * A callback used by the bindesc_get_size function. */ static int get_size_callback(const struct bindesc_entry *entry, void *user_data) { size_t *result = (size_t *)user_data; *result += WB_UP(BINDESC_ENTRY_HEADER_SIZE + entry->len); return 0; } /** * This helper function is used to abstract the different methods of reading * data from the binary descriptors. * For RAM and memory mapped flash, the implementation is very simple, as both * are memory mapped and can simply return a pointer to the data. * Flash is more complex because it needs to read the data from flash, and do * error checking. */ static inline int get_entry(struct bindesc_handle *handle, const uint8_t *address, const struct bindesc_entry **entry) { int retval = 0; int flash_retval; /* Check if reading from flash is enabled, if not, this if/else will be optimized out */ if (IS_ENABLED(CONFIG_BINDESC_READ_FLASH) && handle->type == BINDESC_HANDLE_TYPE_FLASH) { flash_retval = flash_read(handle->flash_device, (size_t)address, handle->buffer, BINDESC_ENTRY_HEADER_SIZE); if (flash_retval) { LOG_ERR("Flash read error: %d", flash_retval); return -EIO; } /* Make sure buffer is large enough for the data */ if (((const struct bindesc_entry *)handle->buffer)->len + BINDESC_ENTRY_HEADER_SIZE > sizeof(handle->buffer)) { LOG_WRN("Descriptor too large to copy, skipping"); retval = -ENOMEM; } else { flash_retval = flash_read(handle->flash_device, (size_t)address + BINDESC_ENTRY_HEADER_SIZE, handle->buffer + BINDESC_ENTRY_HEADER_SIZE, ((const struct bindesc_entry *)handle->buffer)->len); if (flash_retval) { LOG_ERR("Flash read error: %d", flash_retval); return -EIO; } } *entry = (const struct bindesc_entry *)handle->buffer; } else { *entry = (const struct bindesc_entry *)address; } return retval; } #if IS_ENABLED(CONFIG_BINDESC_READ_MEMORY_MAPPED_FLASH) int bindesc_open_memory_mapped_flash(struct bindesc_handle *handle, size_t offset) { uint8_t *address = (uint8_t *)CONFIG_FLASH_BASE_ADDRESS + offset; if (*(uint64_t *)address != BINDESC_MAGIC) { LOG_ERR("Magic not found in given address"); return -ENOENT; } handle->address = address; handle->type = BINDESC_HANDLE_TYPE_MEMORY_MAPPED_FLASH; handle->size_limit = UINT16_MAX; return 0; } #endif /* IS_ENABLED(CONFIG_BINDESC_READ_RAM) */ #if IS_ENABLED(CONFIG_BINDESC_READ_RAM) int bindesc_open_ram(struct bindesc_handle *handle, const uint8_t *address, size_t max_size) { if (!IS_ALIGNED(address, BINDESC_ALIGNMENT)) { LOG_ERR("Given address is not aligned"); return -EINVAL; } if (*(uint64_t *)address != BINDESC_MAGIC) { LOG_ERR("Magic not found in given address"); return -ENONET; } handle->address = address; handle->type = BINDESC_HANDLE_TYPE_RAM; handle->size_limit = max_size; return 0; } #endif /* IS_ENABLED(CONFIG_BINDESC_READ_RAM) */ #if IS_ENABLED(CONFIG_BINDESC_READ_FLASH) int bindesc_open_flash(struct bindesc_handle *handle, size_t offset, const struct device *flash_device) { int retval; retval = flash_read(flash_device, offset, handle->buffer, sizeof(BINDESC_MAGIC)); if (retval) { LOG_ERR("Flash read error: %d", retval); return -EIO; } if (*(uint64_t *)handle->buffer != BINDESC_MAGIC) { LOG_ERR("Magic not found in given address"); return -ENOENT; } handle->address = (uint8_t *)offset; handle->type = BINDESC_HANDLE_TYPE_FLASH; handle->flash_device = flash_device; handle->size_limit = UINT16_MAX; return 0; } #endif /* IS_ENABLED(CONFIG_BINDESC_READ_FLASH) */ int bindesc_foreach(struct bindesc_handle *handle, bindesc_callback_t callback, void *user_data) { const struct bindesc_entry *entry; const uint8_t *address = handle->address; int retval; address += sizeof(BINDESC_MAGIC); do { retval = get_entry(handle, address, &entry); if (retval == -EIO) { return -EIO; } address += WB_UP(BINDESC_ENTRY_HEADER_SIZE + entry->len); if (retval) { continue; } retval = callback(entry, user_data); if (retval) { return retval; } } while ((entry->tag != BINDESC_TAG_DESCRIPTORS_END) && ((address - handle->address) <= handle->size_limit)); return 0; } int bindesc_find_str(struct bindesc_handle *handle, uint16_t id, const char **result) { struct find_user_data data = { .tag = BINDESC_TAG(STR, id), }; if (!bindesc_foreach(handle, find_callback, &data)) { LOG_WRN("The requested descriptor was not found"); return -ENOENT; } *result = (char *)data.result; return 0; } int bindesc_find_uint(struct bindesc_handle *handle, uint16_t id, const uint32_t **result) { struct find_user_data data = { .tag = BINDESC_TAG(UINT, id), }; if (!bindesc_foreach(handle, find_callback, &data)) { LOG_WRN("The requested descriptor was not found"); return -ENOENT; } *result = (const uint32_t *)data.result; return 0; } int bindesc_find_bytes(struct bindesc_handle *handle, uint16_t id, const uint8_t **result, size_t *result_size) { struct find_user_data data = { .tag = BINDESC_TAG(BYTES, id), }; if (!bindesc_foreach(handle, find_callback, &data)) { LOG_WRN("The requested descriptor was not found"); return -ENOENT; } *result = (const uint8_t *)data.result; *result_size = data.size; return 0; } int bindesc_get_size(struct bindesc_handle *handle, size_t *result) { *result = sizeof(BINDESC_MAGIC); return bindesc_foreach(handle, get_size_callback, result); }