You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
233 lines
6.0 KiB
233 lines
6.0 KiB
/* |
|
* Copyright (c) 2023 Yonatan Schachter |
|
* |
|
* SPDX-License-Identifier: Apache-2.0 |
|
*/ |
|
|
|
#include <zephyr/bindesc.h> |
|
#include <zephyr/sys/util.h> |
|
#include <zephyr/logging/log.h> |
|
#include <zephyr/drivers/flash.h> |
|
|
|
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 -ENOENT; |
|
} |
|
|
|
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); |
|
}
|
|
|