1 /*
2  * Copyright (c) 2017 Nordic Semiconductor ASA
3  * Copyright (c) 2015 Runtime Inc
4  * Copyright (c) 2017 Linaro Ltd
5  * Copyright (c) 2020 Gerson Fernando Budke <nandojve@gmail.com>
6  *
7  * SPDX-License-Identifier: Apache-2.0
8  */
9 
10 #include <zephyr/types.h>
11 #include <stddef.h>
12 #include <sys/types.h>
13 #include <device.h>
14 #include <storage/flash_map.h>
15 #include <drivers/flash.h>
16 #include <soc.h>
17 #include <init.h>
18 
19 #if defined(CONFIG_FLASH_AREA_CHECK_INTEGRITY)
20 #include <tinycrypt/constants.h>
21 #include <tinycrypt/sha256.h>
22 #include <string.h>
23 #endif
24 
25 #if defined(CONFIG_FLASH_PAGE_LAYOUT)
26 struct layout_data {
27 	uint32_t area_idx;
28 	uint32_t area_off;
29 	uint32_t area_len;
30 	void *ret;        /* struct flash_area* or struct flash_sector* */
31 	uint32_t ret_idx;
32 	uint32_t ret_len;
33 	int status;
34 };
35 #endif /* CONFIG_FLASH_PAGE_LAYOUT */
36 
37 extern const struct flash_area *flash_map;
38 extern const int flash_map_entries;
39 
get_flash_area_from_id(int idx)40 static struct flash_area const *get_flash_area_from_id(int idx)
41 {
42 	for (int i = 0; i < flash_map_entries; i++) {
43 		if (flash_map[i].fa_id == idx) {
44 			return &flash_map[i];
45 		}
46 	}
47 
48 	return NULL;
49 }
50 
flash_area_foreach(flash_area_cb_t user_cb,void * user_data)51 void flash_area_foreach(flash_area_cb_t user_cb, void *user_data)
52 {
53 	for (int i = 0; i < flash_map_entries; i++) {
54 		user_cb(&flash_map[i], user_data);
55 	}
56 }
57 
flash_area_open(uint8_t id,const struct flash_area ** fap)58 int flash_area_open(uint8_t id, const struct flash_area **fap)
59 {
60 	const struct flash_area *area;
61 
62 	if (flash_map == NULL) {
63 		return -EACCES;
64 	}
65 
66 	area = get_flash_area_from_id(id);
67 	if (area == NULL) {
68 		return -ENOENT;
69 	}
70 
71 	*fap = area;
72 	return 0;
73 }
74 
flash_area_close(const struct flash_area * fa)75 void flash_area_close(const struct flash_area *fa)
76 {
77 	/* nothing to do for now */
78 }
79 
is_in_flash_area_bounds(const struct flash_area * fa,off_t off,size_t len)80 static inline bool is_in_flash_area_bounds(const struct flash_area *fa,
81 					   off_t off, size_t len)
82 {
83 	return (off >= 0) && ((off + len) <= fa->fa_size);
84 }
85 
86 #if defined(CONFIG_FLASH_PAGE_LAYOUT)
87 /*
88  * Check if a flash_page_foreach() callback should exit early, due to
89  * one of the following conditions:
90  *
91  * - The flash page described by "info" is before the area of interest
92  *   described in "data"
93  * - The flash page is after the end of the area
94  * - There are too many flash pages on the device to fit in the array
95  *   held in data->ret. In this case, data->status is set to -ENOMEM.
96  *
97  * The value to return to flash_page_foreach() is stored in
98  * "bail_value" if the callback should exit early.
99  */
should_bail(const struct flash_pages_info * info,struct layout_data * data,bool * bail_value)100 static bool should_bail(const struct flash_pages_info *info,
101 						struct layout_data *data,
102 						bool *bail_value)
103 {
104 	if (info->start_offset < data->area_off) {
105 		*bail_value = true;
106 		return true;
107 	} else if (info->start_offset >= data->area_off + data->area_len) {
108 		*bail_value = false;
109 		return true;
110 	} else if (data->ret_idx >= data->ret_len) {
111 		data->status = -ENOMEM;
112 		*bail_value = false;
113 		return true;
114 	}
115 
116 	return false;
117 }
118 
119 /*
120  * Generic page layout discovery routine. This is kept separate to
121  * support both the deprecated flash_area_to_sectors() and the current
122  * flash_area_get_sectors(). A lot of this can be inlined once
123  * flash_area_to_sectors() is removed.
124  */
flash_area_layout(int idx,uint32_t * cnt,void * ret,flash_page_cb cb,struct layout_data * cb_data)125 static int flash_area_layout(int idx, uint32_t *cnt, void *ret,
126 flash_page_cb cb, struct layout_data *cb_data)
127 {
128 	const struct device *flash_dev;
129 
130 	cb_data->area_idx = idx;
131 
132 	const struct flash_area *fa;
133 
134 	fa = get_flash_area_from_id(idx);
135 	if (fa == NULL) {
136 		return -EINVAL;
137 	}
138 
139 	cb_data->area_idx = idx;
140 	cb_data->area_off = fa->fa_off;
141 	cb_data->area_len = fa->fa_size;
142 
143 	cb_data->ret = ret;
144 	cb_data->ret_idx = 0U;
145 	cb_data->ret_len = *cnt;
146 	cb_data->status = 0;
147 
148 	flash_dev = device_get_binding(fa->fa_dev_name);
149 	if (flash_dev == NULL) {
150 		return -ENODEV;
151 	}
152 
153 	flash_page_foreach(flash_dev, cb, cb_data);
154 
155 	if (cb_data->status == 0) {
156 		*cnt = cb_data->ret_idx;
157 	}
158 
159 	return cb_data->status;
160 }
161 
get_sectors_cb(const struct flash_pages_info * info,void * datav)162 static bool get_sectors_cb(const struct flash_pages_info *info, void *datav)
163 {
164 	struct layout_data *data = datav;
165 	struct flash_sector *ret = data->ret;
166 	bool bail;
167 
168 	if (should_bail(info, data, &bail)) {
169 		return bail;
170 	}
171 
172 	ret[data->ret_idx].fs_off = info->start_offset - data->area_off;
173 	ret[data->ret_idx].fs_size = info->size;
174 	data->ret_idx++;
175 
176 	return true;
177 }
178 
flash_area_get_sectors(int idx,uint32_t * cnt,struct flash_sector * ret)179 int flash_area_get_sectors(int idx, uint32_t *cnt, struct flash_sector *ret)
180 {
181 	struct layout_data data;
182 
183 	return flash_area_layout(idx, cnt, ret, get_sectors_cb, &data);
184 }
185 #endif /* CONFIG_FLASH_PAGE_LAYOUT */
186 
flash_area_read(const struct flash_area * fa,off_t off,void * dst,size_t len)187 int flash_area_read(const struct flash_area *fa, off_t off, void *dst,
188 		    size_t len)
189 {
190 	const struct device *dev;
191 
192 	if (!is_in_flash_area_bounds(fa, off, len)) {
193 		return -EINVAL;
194 	}
195 
196 	dev = device_get_binding(fa->fa_dev_name);
197 
198 	return flash_read(dev, fa->fa_off + off, dst, len);
199 }
200 
flash_area_write(const struct flash_area * fa,off_t off,const void * src,size_t len)201 int flash_area_write(const struct flash_area *fa, off_t off, const void *src,
202 		     size_t len)
203 {
204 	const struct device *flash_dev;
205 	int rc;
206 
207 	if (!is_in_flash_area_bounds(fa, off, len)) {
208 		return -EINVAL;
209 	}
210 
211 	flash_dev = device_get_binding(fa->fa_dev_name);
212 
213 	rc = flash_write(flash_dev, fa->fa_off + off, (void *)src, len);
214 
215 	return rc;
216 }
217 
flash_area_erase(const struct flash_area * fa,off_t off,size_t len)218 int flash_area_erase(const struct flash_area *fa, off_t off, size_t len)
219 {
220 	const struct device *flash_dev;
221 	int rc;
222 
223 	if (!is_in_flash_area_bounds(fa, off, len)) {
224 		return -EINVAL;
225 	}
226 
227 	flash_dev = device_get_binding(fa->fa_dev_name);
228 
229 	rc = flash_erase(flash_dev, fa->fa_off + off, len);
230 
231 	return rc;
232 }
233 
flash_area_align(const struct flash_area * fa)234 uint8_t flash_area_align(const struct flash_area *fa)
235 {
236 	const struct device *dev;
237 
238 	dev = device_get_binding(fa->fa_dev_name);
239 
240 	return flash_get_write_block_size(dev);
241 }
242 
flash_area_has_driver(const struct flash_area * fa)243 int flash_area_has_driver(const struct flash_area *fa)
244 {
245 	if (device_get_binding(fa->fa_dev_name) == NULL) {
246 		return -ENODEV;
247 	}
248 
249 	return 1;
250 }
251 
flash_area_get_device(const struct flash_area * fa)252 const struct device *flash_area_get_device(const struct flash_area *fa)
253 {
254 	return device_get_binding(fa->fa_dev_name);
255 }
256 
flash_area_erased_val(const struct flash_area * fa)257 uint8_t flash_area_erased_val(const struct flash_area *fa)
258 {
259 	const struct flash_parameters *param;
260 
261 	param = flash_get_parameters(device_get_binding(fa->fa_dev_name));
262 
263 	return param->erase_value;
264 }
265 
266 #if defined(CONFIG_FLASH_AREA_CHECK_INTEGRITY)
flash_area_check_int_sha256(const struct flash_area * fa,const struct flash_area_check * fac)267 int flash_area_check_int_sha256(const struct flash_area *fa,
268 				const struct flash_area_check *fac)
269 {
270 	unsigned char hash[TC_SHA256_DIGEST_SIZE];
271 	struct tc_sha256_state_struct sha;
272 	const struct device *dev;
273 	int to_read;
274 	int pos;
275 	int rc;
276 
277 	if (fa == NULL || fac == NULL || fac->match == NULL ||
278 	    fac->rbuf == NULL || fac->clen == 0 || fac->rblen == 0) {
279 		return -EINVAL;
280 	}
281 
282 	if (!is_in_flash_area_bounds(fa, fac->off, fac->clen)) {
283 		return -EINVAL;
284 	}
285 
286 	if (tc_sha256_init(&sha) != TC_CRYPTO_SUCCESS) {
287 		return -ESRCH;
288 	}
289 
290 	dev = device_get_binding(fa->fa_dev_name);
291 	to_read = fac->rblen;
292 
293 	for (pos = 0; pos < fac->clen; pos += to_read) {
294 		if (pos + to_read > fac->clen) {
295 			to_read = fac->clen - pos;
296 		}
297 
298 		rc = flash_read(dev, (fa->fa_off + fac->off + pos),
299 				fac->rbuf, to_read);
300 		if (rc != 0) {
301 			return rc;
302 		}
303 
304 		if (tc_sha256_update(&sha,
305 				     fac->rbuf,
306 				     to_read) != TC_CRYPTO_SUCCESS) {
307 			return -ESRCH;
308 		}
309 	}
310 
311 	if (tc_sha256_final(hash, &sha) != TC_CRYPTO_SUCCESS) {
312 		return -ESRCH;
313 	}
314 
315 	if (memcmp(hash, fac->match, TC_SHA256_DIGEST_SIZE)) {
316 		return -EILSEQ;
317 	}
318 
319 	return 0;
320 }
321 #endif /* CONFIG_FLASH_AREA_CHECK_INTEGRITY */
322