1 /*
2 * Copyright (c) 2023 Yonatan Schachter
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/bindesc.h>
8 #include <zephyr/sys/util.h>
9 #include <zephyr/logging/log.h>
10 #include <zephyr/drivers/flash.h>
11
12 LOG_MODULE_REGISTER(bindesc_read, CONFIG_BINDESC_READ_LOG_LEVEL);
13
14 struct find_user_data {
15 const void *result;
16 size_t size;
17 uint16_t tag;
18 };
19
20 /**
21 * A callback used by the bindesc_find_* functions.
22 */
find_callback(const struct bindesc_entry * entry,void * user_data)23 static int find_callback(const struct bindesc_entry *entry, void *user_data)
24 {
25 struct find_user_data *data = (struct find_user_data *)user_data;
26
27 if (data->tag == entry->tag) {
28 data->result = (const void *)&(entry->data);
29 data->size = entry->len;
30 return 1;
31 }
32
33 return 0;
34 }
35
36 /**
37 * A callback used by the bindesc_get_size function.
38 */
get_size_callback(const struct bindesc_entry * entry,void * user_data)39 static int get_size_callback(const struct bindesc_entry *entry, void *user_data)
40 {
41 size_t *result = (size_t *)user_data;
42
43 *result += WB_UP(BINDESC_ENTRY_HEADER_SIZE + entry->len);
44
45 return 0;
46 }
47
48 /**
49 * This helper function is used to abstract the different methods of reading
50 * data from the binary descriptors.
51 * For RAM and memory mapped flash, the implementation is very simple, as both
52 * are memory mapped and can simply return a pointer to the data.
53 * Flash is more complex because it needs to read the data from flash, and do
54 * error checking.
55 */
get_entry(struct bindesc_handle * handle,const uint8_t * address,const struct bindesc_entry ** entry)56 static inline int get_entry(struct bindesc_handle *handle, const uint8_t *address,
57 const struct bindesc_entry **entry)
58 {
59 int retval = 0;
60 int flash_retval;
61
62 /* Check if reading from flash is enabled, if not, this if/else will be optimized out */
63 if (IS_ENABLED(CONFIG_BINDESC_READ_FLASH) && handle->type == BINDESC_HANDLE_TYPE_FLASH) {
64 flash_retval = flash_read(handle->flash_device, (size_t)address,
65 handle->buffer, BINDESC_ENTRY_HEADER_SIZE);
66 if (flash_retval) {
67 LOG_ERR("Flash read error: %d", flash_retval);
68 return -EIO;
69 }
70
71 /* Make sure buffer is large enough for the data */
72 if (((const struct bindesc_entry *)handle->buffer)->len + BINDESC_ENTRY_HEADER_SIZE
73 > sizeof(handle->buffer)) {
74 LOG_WRN("Descriptor too large to copy, skipping");
75 retval = -ENOMEM;
76 } else {
77 flash_retval = flash_read(handle->flash_device,
78 (size_t)address + BINDESC_ENTRY_HEADER_SIZE,
79 handle->buffer + BINDESC_ENTRY_HEADER_SIZE,
80 ((const struct bindesc_entry *)handle->buffer)->len);
81 if (flash_retval) {
82 LOG_ERR("Flash read error: %d", flash_retval);
83 return -EIO;
84 }
85 }
86 *entry = (const struct bindesc_entry *)handle->buffer;
87 } else {
88 *entry = (const struct bindesc_entry *)address;
89 }
90
91 return retval;
92 }
93
94 #if IS_ENABLED(CONFIG_BINDESC_READ_MEMORY_MAPPED_FLASH)
bindesc_open_memory_mapped_flash(struct bindesc_handle * handle,size_t offset)95 int bindesc_open_memory_mapped_flash(struct bindesc_handle *handle, size_t offset)
96 {
97 uint8_t *address = (uint8_t *)CONFIG_FLASH_BASE_ADDRESS + offset;
98
99 if (*(uint64_t *)address != BINDESC_MAGIC) {
100 LOG_ERR("Magic not found in given address");
101 return -ENOENT;
102 }
103
104 handle->address = address;
105 handle->type = BINDESC_HANDLE_TYPE_MEMORY_MAPPED_FLASH;
106 handle->size_limit = UINT16_MAX;
107 return 0;
108 }
109 #endif /* IS_ENABLED(CONFIG_BINDESC_READ_RAM) */
110
111 #if IS_ENABLED(CONFIG_BINDESC_READ_RAM)
bindesc_open_ram(struct bindesc_handle * handle,const uint8_t * address,size_t max_size)112 int bindesc_open_ram(struct bindesc_handle *handle, const uint8_t *address, size_t max_size)
113 {
114 if (!IS_ALIGNED(address, BINDESC_ALIGNMENT)) {
115 LOG_ERR("Given address is not aligned");
116 return -EINVAL;
117 }
118
119 if (*(uint64_t *)address != BINDESC_MAGIC) {
120 LOG_ERR("Magic not found in given address");
121 return -ENONET;
122 }
123
124 handle->address = address;
125 handle->type = BINDESC_HANDLE_TYPE_RAM;
126 handle->size_limit = max_size;
127 return 0;
128 }
129 #endif /* IS_ENABLED(CONFIG_BINDESC_READ_RAM) */
130
131 #if IS_ENABLED(CONFIG_BINDESC_READ_FLASH)
bindesc_open_flash(struct bindesc_handle * handle,size_t offset,const struct device * flash_device)132 int bindesc_open_flash(struct bindesc_handle *handle, size_t offset,
133 const struct device *flash_device)
134 {
135 int retval;
136
137 retval = flash_read(flash_device, offset, handle->buffer, sizeof(BINDESC_MAGIC));
138 if (retval) {
139 LOG_ERR("Flash read error: %d", retval);
140 return -EIO;
141 }
142
143 if (*(uint64_t *)handle->buffer != BINDESC_MAGIC) {
144 LOG_ERR("Magic not found in given address");
145 return -ENOENT;
146 }
147
148 handle->address = (uint8_t *)offset;
149 handle->type = BINDESC_HANDLE_TYPE_FLASH;
150 handle->flash_device = flash_device;
151 handle->size_limit = UINT16_MAX;
152 return 0;
153 }
154 #endif /* IS_ENABLED(CONFIG_BINDESC_READ_FLASH) */
155
bindesc_foreach(struct bindesc_handle * handle,bindesc_callback_t callback,void * user_data)156 int bindesc_foreach(struct bindesc_handle *handle, bindesc_callback_t callback, void *user_data)
157 {
158 const struct bindesc_entry *entry;
159 const uint8_t *address = handle->address;
160 int retval;
161
162 address += sizeof(BINDESC_MAGIC);
163
164 do {
165 retval = get_entry(handle, address, &entry);
166 if (retval == -EIO) {
167 return -EIO;
168 }
169 address += WB_UP(BINDESC_ENTRY_HEADER_SIZE + entry->len);
170 if (retval) {
171 continue;
172 }
173
174 retval = callback(entry, user_data);
175 if (retval) {
176 return retval;
177 }
178 } while ((entry->tag != BINDESC_TAG_DESCRIPTORS_END) &&
179 ((address - handle->address) <= handle->size_limit));
180
181 return 0;
182 }
183
bindesc_find_str(struct bindesc_handle * handle,uint16_t id,const char ** result)184 int bindesc_find_str(struct bindesc_handle *handle, uint16_t id, const char **result)
185 {
186 struct find_user_data data = {
187 .tag = BINDESC_TAG(STR, id),
188 };
189
190 if (!bindesc_foreach(handle, find_callback, &data)) {
191 LOG_WRN("The requested descriptor was not found");
192 return -ENOENT;
193 }
194 *result = (char *)data.result;
195 return 0;
196 }
197
bindesc_find_uint(struct bindesc_handle * handle,uint16_t id,const uint32_t ** result)198 int bindesc_find_uint(struct bindesc_handle *handle, uint16_t id, const uint32_t **result)
199 {
200 struct find_user_data data = {
201 .tag = BINDESC_TAG(UINT, id),
202 };
203
204 if (!bindesc_foreach(handle, find_callback, &data)) {
205 LOG_WRN("The requested descriptor was not found");
206 return -ENOENT;
207 }
208 *result = (const uint32_t *)data.result;
209 return 0;
210 }
211
bindesc_find_bytes(struct bindesc_handle * handle,uint16_t id,const uint8_t ** result,size_t * result_size)212 int bindesc_find_bytes(struct bindesc_handle *handle, uint16_t id, const uint8_t **result,
213 size_t *result_size)
214 {
215 struct find_user_data data = {
216 .tag = BINDESC_TAG(BYTES, id),
217 };
218
219 if (!bindesc_foreach(handle, find_callback, &data)) {
220 LOG_WRN("The requested descriptor was not found");
221 return -ENOENT;
222 }
223 *result = (const uint8_t *)data.result;
224 *result_size = data.size;
225 return 0;
226 }
227
bindesc_get_size(struct bindesc_handle * handle,size_t * result)228 int bindesc_get_size(struct bindesc_handle *handle, size_t *result)
229 {
230 *result = sizeof(BINDESC_MAGIC);
231
232 return bindesc_foreach(handle, get_size_callback, result);
233 }
234