blob: fd21bfdec0823eac019c67ad302f0153ccb8be44 [file] [log] [blame]
David Brownde7729e2017-01-09 10:41:35 -07001/* Run the boot image. */
2
Fabio Utzig9b0ee902017-11-23 19:49:00 -02003#include <assert.h>
David Brownde7729e2017-01-09 10:41:35 -07004#include <setjmp.h>
5#include <stdio.h>
6#include <stdlib.h>
7#include <string.h>
8#include <bootutil/bootutil.h>
9#include <bootutil/image.h>
Andrzej Puzdrowskib788c712018-04-12 12:42:49 +020010
11#include <flash_map_backend/flash_map_backend.h>
David Brownde7729e2017-01-09 10:41:35 -070012
David Brownd2b18532017-07-12 09:51:31 -060013#include "../../../boot/bootutil/src/bootutil_priv.h"
Fabio Utzig57c40f72017-12-12 21:48:30 -020014#include "bootsim.h"
David Brownde7729e2017-01-09 10:41:35 -070015
Fabio Utzig1e48b912018-09-18 09:04:18 -030016#ifdef MCUBOOT_ENCRYPT_RSA
17#include "mbedtls/rsa.h"
18#include "mbedtls/asn1.h"
19#endif
20
21#ifdef MCUBOOT_ENCRYPT_KW
22#include "mbedtls/nist_kw.h"
23#endif
24
David Brown75fd5dc2017-05-04 09:04:47 -060025#include <bootutil/bootutil_log.h>
26
David Vincze6c9b4162019-03-21 19:18:08 +010027#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
28
Fabio Utzig8000e322019-08-05 08:14:32 -030029struct area_desc;
30extern struct area_desc *sim_get_flash_areas(void);
31extern void sim_set_flash_areas(struct area_desc *areas);
32extern void sim_reset_flash_areas(void);
33
34struct sim_context;
35extern struct sim_context *sim_get_context(void);
36extern void sim_set_context(struct sim_context *ctx);
37extern void sim_reset_context(void);
38
Fabio Utzig99dfc782018-10-15 15:10:55 -070039extern int sim_flash_erase(uint8_t flash_id, uint32_t offset, uint32_t size);
40extern int sim_flash_read(uint8_t flash_id, uint32_t offset, uint8_t *dest,
41 uint32_t size);
42extern int sim_flash_write(uint8_t flash_id, uint32_t offset, const uint8_t *src,
43 uint32_t size);
Fabio Utzig1edb7882020-10-04 11:51:53 -030044extern uint16_t sim_flash_align(uint8_t flash_id);
Fabio Utzig73ffc442018-10-24 21:49:09 -030045extern uint8_t sim_flash_erased_val(uint8_t flash_id);
David Brownde7729e2017-01-09 10:41:35 -070046
Fabio Utzig8000e322019-08-05 08:14:32 -030047struct sim_context {
48 int flash_counter;
49 int jumped;
50 uint8_t c_asserts;
51 uint8_t c_catch_asserts;
52 jmp_buf boot_jmpbuf;
53};
David Brownde7729e2017-01-09 10:41:35 -070054
Fabio Utzig1e48b912018-09-18 09:04:18 -030055#ifdef MCUBOOT_ENCRYPT_RSA
56static int
57parse_pubkey(mbedtls_rsa_context *ctx, uint8_t **p, uint8_t *end)
58{
59 int rc;
60 size_t len;
61
62 if ((rc = mbedtls_asn1_get_tag(p, end, &len,
63 MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
64 return -1;
65 }
66
67 if (*p + len != end) {
68 return -2;
69 }
70
71 if ((rc = mbedtls_asn1_get_tag(p, end, &len,
72 MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
73 return -3;
74 }
75
76 *p += len;
77
78 if ((rc = mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_BIT_STRING)) != 0) {
79 return -4;
80 }
81
82 if (**p != MBEDTLS_ASN1_PRIMITIVE) {
83 return -5;
84 }
85
86 *p += 1;
87
88 if ((rc = mbedtls_asn1_get_tag(p, end, &len,
89 MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
90 return -6;
91 }
92
93 if (mbedtls_asn1_get_mpi(p, end, &ctx->N) != 0) {
94 return -7;
95 }
96
97 if (mbedtls_asn1_get_mpi(p, end, &ctx->E) != 0) {
98 return -8;
99 }
100
101 ctx->len = mbedtls_mpi_size(&ctx->N);
102
103 if (*p != end) {
104 return -9;
105 }
106
107 if (mbedtls_rsa_check_pubkey(ctx) != 0) {
108 return -10;
109 }
110
111 return 0;
112}
113
114static int
115fake_rng(void *p_rng, unsigned char *output, size_t len)
116{
117 size_t i;
118
119 (void)p_rng;
120 for (i = 0; i < len; i++) {
121 output[i] = (char)i;
122 }
123
124 return 0;
125}
126#endif
127
128int mbedtls_platform_set_calloc_free(void * (*calloc_func)(size_t, size_t),
129 void (*free_func)(void *));
130
131int rsa_oaep_encrypt_(const uint8_t *pubkey, unsigned pubkey_len,
132 const uint8_t *seckey, unsigned seckey_len,
133 uint8_t *encbuf)
134{
135#ifdef MCUBOOT_ENCRYPT_RSA
136 mbedtls_rsa_context ctx;
137 uint8_t *cp;
138 uint8_t *cpend;
139 int rc;
140
141 mbedtls_platform_set_calloc_free(calloc, free);
142
143 mbedtls_rsa_init(&ctx, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256);
144
145 cp = (uint8_t *)pubkey;
146 cpend = cp + pubkey_len;
147
148 rc = parse_pubkey(&ctx, &cp, cpend);
149 if (rc) {
150 goto done;
151 }
152
153 rc = mbedtls_rsa_rsaes_oaep_encrypt(&ctx, fake_rng, NULL, MBEDTLS_RSA_PUBLIC,
154 NULL, 0, seckey_len, seckey, encbuf);
155 if (rc) {
156 goto done;
157 }
158
159done:
160 mbedtls_rsa_free(&ctx);
161 return rc;
162
163#else
164 (void)pubkey;
165 (void)pubkey_len;
166 (void)seckey;
167 (void)seckey_len;
168 (void)encbuf;
169 return 0;
170#endif
171}
172
173int kw_encrypt_(const uint8_t *kek, const uint8_t *seckey, uint8_t *encbuf)
174{
175#ifdef MCUBOOT_ENCRYPT_KW
176 mbedtls_nist_kw_context kw;
177 size_t olen;
178 int rc;
179
180 mbedtls_platform_set_calloc_free(calloc, free);
181
182 mbedtls_nist_kw_init(&kw);
183
184 rc = mbedtls_nist_kw_setkey(&kw, MBEDTLS_CIPHER_ID_AES, kek, 128, 1);
185 if (rc) {
186 goto done;
187 }
188
189 rc = mbedtls_nist_kw_wrap(&kw, MBEDTLS_KW_MODE_KW, seckey, 16, encbuf,
190 &olen, 24);
191
192done:
193 mbedtls_nist_kw_free(&kw);
194 return rc;
195
196#else
197 (void)kek;
198 (void)seckey;
199 (void)encbuf;
200 return 0;
201#endif
202}
203
Fabio Utzig1edb7882020-10-04 11:51:53 -0300204uint16_t flash_area_align(const struct flash_area *area)
David Brown5acda262017-01-23 15:42:19 -0700205{
Fabio Utzig73ffc442018-10-24 21:49:09 -0300206 return sim_flash_align(area->fa_device_id);
David Brown5acda262017-01-23 15:42:19 -0700207}
208
Fabio Utzigea0290b2018-08-09 14:23:01 -0300209uint8_t flash_area_erased_val(const struct flash_area *area)
210{
Fabio Utzig73ffc442018-10-24 21:49:09 -0300211 return sim_flash_erased_val(area->fa_device_id);
Fabio Utzigea0290b2018-08-09 14:23:01 -0300212}
213
David Brownde7729e2017-01-09 10:41:35 -0700214struct area {
David Brown7ad80882017-06-20 15:30:36 -0600215 struct flash_area whole;
216 struct flash_area *areas;
217 uint32_t num_areas;
218 uint8_t id;
David Brownde7729e2017-01-09 10:41:35 -0700219};
220
221struct area_desc {
David Brown7ad80882017-06-20 15:30:36 -0600222 struct area slots[16];
223 uint32_t num_slots;
David Brownde7729e2017-01-09 10:41:35 -0700224};
225
Fabio Utzig8000e322019-08-05 08:14:32 -0300226int invoke_boot_go(struct sim_context *ctx, struct area_desc *adesc)
David Brownde7729e2017-01-09 10:41:35 -0700227{
David Brown7ad80882017-06-20 15:30:36 -0600228 int res;
229 struct boot_rsp rsp;
Fabio Utzig8000e322019-08-05 08:14:32 -0300230 struct boot_loader_state *state;
David Brownde7729e2017-01-09 10:41:35 -0700231
David Brown641af452021-02-19 12:16:48 -0700232#if defined(MCUBOOT_SIGN_RSA) || \
233 (defined(MCUBOOT_SIGN_EC256) && defined(MCUBOOT_USE_MBED_TLS))
Fabio Utzigb04afa92018-09-12 15:27:04 -0300234 mbedtls_platform_set_calloc_free(calloc, free);
235#endif
David Brown7e701d82017-07-11 13:24:25 -0600236
Fabio Utzig8000e322019-08-05 08:14:32 -0300237 // NOTE: cleared internally by context_boot_go
238 state = malloc(sizeof(struct boot_loader_state));
239
240 sim_set_flash_areas(adesc);
241 sim_set_context(ctx);
242
243 if (setjmp(ctx->boot_jmpbuf) == 0) {
244 res = context_boot_go(state, &rsp);
245 sim_reset_flash_areas();
246 sim_reset_context();
247 free(state);
David Brown7ad80882017-06-20 15:30:36 -0600248 /* printf("boot_go off: %d (0x%08x)\n", res, rsp.br_image_off); */
249 return res;
250 } else {
Fabio Utzig8000e322019-08-05 08:14:32 -0300251 sim_reset_flash_areas();
252 sim_reset_context();
253 free(state);
David Brown7ad80882017-06-20 15:30:36 -0600254 return -0x13579;
255 }
David Brownde7729e2017-01-09 10:41:35 -0700256}
257
David Brownde7729e2017-01-09 10:41:35 -0700258void *os_malloc(size_t size)
259{
David Brown7ad80882017-06-20 15:30:36 -0600260 // printf("os_malloc 0x%x bytes\n", size);
261 return malloc(size);
David Brownde7729e2017-01-09 10:41:35 -0700262}
263
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200264void os_free(void *mem)
265{
266 free(mem);
267}
268
269void *os_realloc(void *ptr, size_t size)
270{
271 return realloc(ptr, size);
272}
273
Fabio Utzigb0f04732019-07-31 09:49:19 -0300274int flash_area_id_from_multi_image_slot(int image_index, int slot)
David Brownde7729e2017-01-09 10:41:35 -0700275{
Fabio Utzigb0f04732019-07-31 09:49:19 -0300276 switch (slot) {
277 case 0: return FLASH_AREA_IMAGE_PRIMARY(image_index);
278 case 1: return FLASH_AREA_IMAGE_SECONDARY(image_index);
279 case 2: return FLASH_AREA_IMAGE_SCRATCH;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200280
281 // case 7: return FLASH_AREA_IMAGE_SWAP_STATUS;
David Vincze6c9b4162019-03-21 19:18:08 +0100282 }
283
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200284 printf("Image flash area ID not found, image=%d, slot=%d\n", image_index, slot);
David Vincze6c9b4162019-03-21 19:18:08 +0100285 return -1; /* flash_area_open will fail on that */
David Brownde7729e2017-01-09 10:41:35 -0700286}
287
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200288int flash_area_id_from_image_slot(int slot)
289{
290 return flash_area_id_from_multi_image_slot(0, slot);
291}
292
David Brownde7729e2017-01-09 10:41:35 -0700293int flash_area_open(uint8_t id, const struct flash_area **area)
294{
Fabio Utzigcd5774b2017-11-29 10:18:26 -0200295 uint32_t i;
Fabio Utzig8000e322019-08-05 08:14:32 -0300296 struct area_desc *flash_areas;
David Brownde7729e2017-01-09 10:41:35 -0700297
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200298 // BOOT_LOG_SIM("%s: area id=%d, num_slots=%d", __func__, id, sim_get_flash_areas()->num_slots);
299
Fabio Utzig8000e322019-08-05 08:14:32 -0300300 flash_areas = sim_get_flash_areas();
David Brown7ad80882017-06-20 15:30:36 -0600301 for (i = 0; i < flash_areas->num_slots; i++) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200302 // BOOT_LOG_SIM(" * flash_areas->slots[%d].id=%d", i, flash_areas->slots[i].id);
David Brown7ad80882017-06-20 15:30:36 -0600303 if (flash_areas->slots[i].id == id)
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200304 {
305 // BOOT_LOG_SIM(" * found, i=%d, id=%d", i, id);
David Brown7ad80882017-06-20 15:30:36 -0600306 break;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200307 }
David Brown7ad80882017-06-20 15:30:36 -0600308 }
309 if (i == flash_areas->num_slots) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200310 printf("Unsupported area id=%d\n", id);
David Brown7ad80882017-06-20 15:30:36 -0600311 abort();
312 }
David Brownde7729e2017-01-09 10:41:35 -0700313
David Brown7ad80882017-06-20 15:30:36 -0600314 /* Unsure if this is right, just returning the first area. */
315 *area = &flash_areas->slots[i].whole;
316 return 0;
David Brownde7729e2017-01-09 10:41:35 -0700317}
318
319void flash_area_close(const struct flash_area *area)
320{
Fabio Utzigcd5774b2017-11-29 10:18:26 -0200321 (void)area;
David Brownde7729e2017-01-09 10:41:35 -0700322}
323
324/*
325 * Read/write/erase. Offset is relative from beginning of flash area.
326 */
327int flash_area_read(const struct flash_area *area, uint32_t off, void *dst,
David Brown7ad80882017-06-20 15:30:36 -0600328 uint32_t len)
David Brownde7729e2017-01-09 10:41:35 -0700329{
Fabio Utzig6fa2d402019-12-10 14:34:18 -0300330 BOOT_LOG_SIM("%s: area=%d, off=%x, len=%x",
David Brown7ad80882017-06-20 15:30:36 -0600331 __func__, area->fa_id, off, len);
Fabio Utzig99dfc782018-10-15 15:10:55 -0700332 return sim_flash_read(area->fa_device_id, area->fa_off + off, dst, len);
David Brownde7729e2017-01-09 10:41:35 -0700333}
334
335int flash_area_write(const struct flash_area *area, uint32_t off, const void *src,
David Brown7ad80882017-06-20 15:30:36 -0600336 uint32_t len)
David Brownde7729e2017-01-09 10:41:35 -0700337{
Fabio Utzig6fa2d402019-12-10 14:34:18 -0300338 BOOT_LOG_SIM("%s: area=%d, off=%x, len=%x", __func__,
David Brown7ad80882017-06-20 15:30:36 -0600339 area->fa_id, off, len);
Fabio Utzig8000e322019-08-05 08:14:32 -0300340 struct sim_context *ctx = sim_get_context();
341 if (--(ctx->flash_counter) == 0) {
342 ctx->jumped++;
343 longjmp(ctx->boot_jmpbuf, 1);
Fabio Utzig99dfc782018-10-15 15:10:55 -0700344 }
345 return sim_flash_write(area->fa_device_id, area->fa_off + off, src, len);
David Brownde7729e2017-01-09 10:41:35 -0700346}
347
348int flash_area_erase(const struct flash_area *area, uint32_t off, uint32_t len)
349{
Fabio Utzig6fa2d402019-12-10 14:34:18 -0300350 BOOT_LOG_SIM("%s: area=%d, off=%x, len=%x", __func__,
David Brown7ad80882017-06-20 15:30:36 -0600351 area->fa_id, off, len);
Fabio Utzig8000e322019-08-05 08:14:32 -0300352 struct sim_context *ctx = sim_get_context();
353 if (--(ctx->flash_counter) == 0) {
354 ctx->jumped++;
355 longjmp(ctx->boot_jmpbuf, 1);
Fabio Utzig99dfc782018-10-15 15:10:55 -0700356 }
357 return sim_flash_erase(area->fa_device_id, area->fa_off + off, len);
David Brownde7729e2017-01-09 10:41:35 -0700358}
359
360int flash_area_to_sectors(int idx, int *cnt, struct flash_area *ret)
361{
Fabio Utzigcd5774b2017-11-29 10:18:26 -0200362 uint32_t i;
David Brown7ad80882017-06-20 15:30:36 -0600363 struct area *slot;
Fabio Utzig8000e322019-08-05 08:14:32 -0300364 struct area_desc *flash_areas;
David Brownde7729e2017-01-09 10:41:35 -0700365
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200366 // BOOT_LOG_SIM("%s: idx=%d", __func__, idx);
367
Fabio Utzig8000e322019-08-05 08:14:32 -0300368 flash_areas = sim_get_flash_areas();
David Brown7ad80882017-06-20 15:30:36 -0600369 for (i = 0; i < flash_areas->num_slots; i++) {
370 if (flash_areas->slots[i].id == idx)
371 break;
372 }
373 if (i == flash_areas->num_slots) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200374 printf("flash_area_to_sectors: Unsupported area = %d\n", idx);
David Brown7ad80882017-06-20 15:30:36 -0600375 abort();
376 }
David Brownde7729e2017-01-09 10:41:35 -0700377
David Brown7ad80882017-06-20 15:30:36 -0600378 slot = &flash_areas->slots[i];
David Brownde7729e2017-01-09 10:41:35 -0700379
Fabio Utzigcd5774b2017-11-29 10:18:26 -0200380 if (slot->num_areas > (uint32_t)*cnt) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200381 printf("Too many areas in slot: %d > %d\n", slot->num_areas, *cnt);
David Brown7ad80882017-06-20 15:30:36 -0600382 abort();
383 }
David Brownde7729e2017-01-09 10:41:35 -0700384
David Brown7ad80882017-06-20 15:30:36 -0600385 *cnt = slot->num_areas;
386 memcpy(ret, slot->areas, slot->num_areas * sizeof(struct flash_area));
David Brownde7729e2017-01-09 10:41:35 -0700387
David Brown7ad80882017-06-20 15:30:36 -0600388 return 0;
David Brownde7729e2017-01-09 10:41:35 -0700389}
390
David Brown60399f62017-05-11 10:20:34 -0600391int flash_area_get_sectors(int fa_id, uint32_t *count,
392 struct flash_sector *sectors)
393{
Fabio Utzigcd5774b2017-11-29 10:18:26 -0200394 uint32_t i;
David Brown7ad80882017-06-20 15:30:36 -0600395 struct area *slot;
Fabio Utzig8000e322019-08-05 08:14:32 -0300396 struct area_desc *flash_areas;
David Brown60399f62017-05-11 10:20:34 -0600397
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200398 // BOOT_LOG_SIM("%s: area id=%d", __func__, fa_id);
399
Fabio Utzig8000e322019-08-05 08:14:32 -0300400 flash_areas = sim_get_flash_areas();
David Brown7ad80882017-06-20 15:30:36 -0600401 for (i = 0; i < flash_areas->num_slots; i++) {
402 if (flash_areas->slots[i].id == fa_id)
403 break;
404 }
405 if (i == flash_areas->num_slots) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200406 printf("flash_area_get_sectors: Unsupported area = %d\n", fa_id);
David Brown7ad80882017-06-20 15:30:36 -0600407 abort();
408 }
David Brown60399f62017-05-11 10:20:34 -0600409
David Brown7ad80882017-06-20 15:30:36 -0600410 slot = &flash_areas->slots[i];
David Brown60399f62017-05-11 10:20:34 -0600411
David Brown7ad80882017-06-20 15:30:36 -0600412 if (slot->num_areas > *count) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200413 printf("Too many areas in slot: %d > %d\n", slot->num_areas, *count);
David Brown7ad80882017-06-20 15:30:36 -0600414 abort();
415 }
David Brown60399f62017-05-11 10:20:34 -0600416
David Brown7ad80882017-06-20 15:30:36 -0600417 for (i = 0; i < slot->num_areas; i++) {
418 sectors[i].fs_off = slot->areas[i].fa_off -
419 slot->whole.fa_off;
420 sectors[i].fs_size = slot->areas[i].fa_size;
421 }
422 *count = slot->num_areas;
David Brown60399f62017-05-11 10:20:34 -0600423
David Brown7ad80882017-06-20 15:30:36 -0600424 return 0;
David Brown60399f62017-05-11 10:20:34 -0600425}
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200426
Fabio Utzigb0f04732019-07-31 09:49:19 -0300427int flash_area_id_to_multi_image_slot(int image_index, int area_id)
Andrzej Puzdrowskie575fe92019-03-14 12:20:19 +0100428{
Fabio Utzigb0f04732019-07-31 09:49:19 -0300429 if (area_id == FLASH_AREA_IMAGE_PRIMARY(image_index)) {
Andrzej Puzdrowskie575fe92019-03-14 12:20:19 +0100430 return 0;
Andrzej Puzdrowskie575fe92019-03-14 12:20:19 +0100431 }
Fabio Utzigb0f04732019-07-31 09:49:19 -0300432 if (area_id == FLASH_AREA_IMAGE_SECONDARY(image_index)) {
David Vinczeb75c12a2019-03-22 14:58:33 +0100433 return 1;
434 }
435
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200436 printf("Unsupported image area ID=%d\n", area_id);
David Vinczeb75c12a2019-03-22 14:58:33 +0100437 abort();
Andrzej Puzdrowskie575fe92019-03-14 12:20:19 +0100438}
439
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200440void sim_assert(int x, const char *assertion, const char *file, unsigned int line, const char *function)
441{
442 if (!(x)) {
Fabio Utzig8000e322019-08-05 08:14:32 -0300443 struct sim_context *ctx = sim_get_context();
444 if (ctx->c_catch_asserts) {
445 ctx->c_asserts++;
Fabio Utzig9b0ee902017-11-23 19:49:00 -0200446 } else {
447 BOOT_LOG_ERR("%s:%d: %s: Assertion `%s' failed.", file, line, function, assertion);
448
449 /* NOTE: if the assert below is triggered, the place where it was originally
450 * asserted is printed by the message above...
451 */
452 assert(x);
453 }
454 }
455}
David Browne0bb1f92019-10-01 15:57:01 -0600456
457uint32_t boot_max_align(void)
458{
459 return BOOT_MAX_ALIGN;
460}
David Brown2b8a6952019-10-01 16:14:53 -0600461
462uint32_t boot_magic_sz(void)
463{
464 return BOOT_MAGIC_SZ;
465}
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200466
467void mbedtls_platform_zeroize( void *buf, size_t len )
468{
469 memset( buf, 0, len );
470}
471
472int flash_area_read_is_empty(const struct flash_area *fa, uint32_t off,
473 void *dst, uint32_t len)
474{
475 uint8_t *mem_dest;
476 int rc;
477
478 mem_dest = (uint8_t *)dst;
479 rc = flash_area_read(fa, off, dst, len);
480 if (rc) {
481 return -1;
482 }
483
484 for (uint8_t i = 0; i < len; i++) {
485 if (mem_dest[i] != flash_area_erased_val(fa)) {
486 return 0;
487 }
488 }
489 return 1;
490}