234 lines
6.0 KiB
C
234 lines
6.0 KiB
C
/*
|
|
* 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 -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);
|
|
}
|