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