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