blob: 588bd288a27c00b32f3ef10a1529a1dd9e5dda3d [file] [log] [blame]
Fabio Utzig12d59162019-11-28 10:01:59 -03001/*
2 * Copyright (c) 2019 JUUL Labs
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <assert.h>
18#include <stddef.h>
19#include <stdbool.h>
20#include <inttypes.h>
21#include <stdlib.h>
22#include <string.h>
23#include "bootutil/bootutil.h"
24#include "bootutil_priv.h"
25#include "swap_priv.h"
26#include "bootutil/bootutil_log.h"
27
28#include "mcuboot_config/mcuboot_config.h"
29
30MCUBOOT_LOG_MODULE_DECLARE(mcuboot);
31
Fabio Utzig74aef312019-11-28 11:05:34 -030032#if !defined(MCUBOOT_SWAP_USING_MOVE)
Fabio Utzig12d59162019-11-28 10:01:59 -030033
34#if defined(MCUBOOT_VALIDATE_PRIMARY_SLOT)
35/*
36 * FIXME: this might have to be updated for threaded sim
37 */
38int boot_status_fails = 0;
39#define BOOT_STATUS_ASSERT(x) \
40 do { \
41 if (!(x)) { \
42 boot_status_fails++; \
43 } \
44 } while (0)
45#else
46#define BOOT_STATUS_ASSERT(x) ASSERT(x)
47#endif
48
49int
50boot_read_image_header(struct boot_loader_state *state, int slot,
51 struct image_header *out_hdr, struct boot_status *bs)
52{
53 const struct flash_area *fap;
54 int area_id;
55 int rc;
56
57 (void)bs;
58
59#if (BOOT_IMAGE_NUMBER == 1)
60 (void)state;
61#endif
62
63 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
64 rc = flash_area_open(area_id, &fap);
65 if (rc != 0) {
66 rc = BOOT_EFLASH;
67 goto done;
68 }
69
70 rc = flash_area_read(fap, 0, out_hdr, sizeof *out_hdr);
71 if (rc != 0) {
72 rc = BOOT_EFLASH;
73 goto done;
74 }
75
76 rc = 0;
77
78done:
79 flash_area_close(fap);
80 return rc;
81}
82
83/**
84 * Reads the status of a partially-completed swap, if any. This is necessary
85 * to recover in case the boot lodaer was reset in the middle of a swap
86 * operation.
87 */
88int
89swap_read_status_bytes(const struct flash_area *fap,
90 struct boot_loader_state *state, struct boot_status *bs)
91{
92 uint32_t off;
93 uint8_t status;
94 int max_entries;
95 int found;
96 int found_idx;
97 int invalid;
98 int rc;
99 int i;
100
101 off = boot_status_off(fap);
102 max_entries = boot_status_entries(BOOT_CURR_IMG(state), fap);
103 if (max_entries < 0) {
104 return BOOT_EBADARGS;
105 }
106
107 found = 0;
108 found_idx = 0;
109 invalid = 0;
110 for (i = 0; i < max_entries; i++) {
111 rc = flash_area_read_is_empty(fap, off + i * BOOT_WRITE_SZ(state),
112 &status, 1);
113 if (rc < 0) {
114 return BOOT_EFLASH;
115 }
116
117 if (rc == 1) {
118 if (found && !found_idx) {
119 found_idx = i;
120 }
121 } else if (!found) {
122 found = 1;
123 } else if (found_idx) {
124 invalid = 1;
125 break;
126 }
127 }
128
129 if (invalid) {
130 /* This means there was an error writing status on the last
131 * swap. Tell user and move on to validation!
132 */
133 BOOT_LOG_ERR("Detected inconsistent status!");
134
135#if !defined(MCUBOOT_VALIDATE_PRIMARY_SLOT)
136 /* With validation of the primary slot disabled, there is no way
137 * to be sure the swapped primary slot is OK, so abort!
138 */
139 assert(0);
140#endif
141 }
142
143 if (found) {
144 if (!found_idx) {
145 found_idx = i;
146 }
147 bs->idx = (found_idx / BOOT_STATUS_STATE_COUNT) + 1;
148 bs->state = (found_idx % BOOT_STATUS_STATE_COUNT) + 1;
149 }
150
151 return 0;
152}
153
154uint32_t
155boot_status_internal_off(const struct boot_status *bs, int elem_sz)
156{
157 int idx_sz;
158
159 idx_sz = elem_sz * BOOT_STATUS_STATE_COUNT;
160
161 return (bs->idx - BOOT_STATUS_IDX_0) * idx_sz +
162 (bs->state - BOOT_STATUS_STATE_0) * elem_sz;
163}
164
165/*
166 * Slots are compatible when all sectors that store up to to size of the image
167 * round up to sector size, in both slot's are able to fit in the scratch
168 * area, and have sizes that are a multiple of each other (powers of two
169 * presumably!).
170 */
171int
172boot_slots_compatible(struct boot_loader_state *state)
173{
174 size_t num_sectors_primary;
175 size_t num_sectors_secondary;
176 size_t sz0, sz1;
177 size_t primary_slot_sz, secondary_slot_sz;
Fabio Utzig74aef312019-11-28 11:05:34 -0300178#ifndef MCUBOOT_OVERWRITE_ONLY
Fabio Utzig12d59162019-11-28 10:01:59 -0300179 size_t scratch_sz;
Fabio Utzig74aef312019-11-28 11:05:34 -0300180#endif
Fabio Utzig12d59162019-11-28 10:01:59 -0300181 size_t i, j;
182 int8_t smaller;
183
184 num_sectors_primary = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT);
185 num_sectors_secondary = boot_img_num_sectors(state, BOOT_SECONDARY_SLOT);
186 if ((num_sectors_primary > BOOT_MAX_IMG_SECTORS) ||
187 (num_sectors_secondary > BOOT_MAX_IMG_SECTORS)) {
188 BOOT_LOG_WRN("Cannot upgrade: more sectors than allowed");
189 return 0;
190 }
191
Fabio Utzig74aef312019-11-28 11:05:34 -0300192#ifndef MCUBOOT_OVERWRITE_ONLY
Fabio Utzig12d59162019-11-28 10:01:59 -0300193 scratch_sz = boot_scratch_area_size(state);
Fabio Utzig74aef312019-11-28 11:05:34 -0300194#endif
Fabio Utzig12d59162019-11-28 10:01:59 -0300195
196 /*
197 * The following loop scans all sectors in a linear fashion, assuring that
198 * for each possible sector in each slot, it is able to fit in the other
199 * slot's sector or sectors. Slot's should be compatible as long as any
200 * number of a slot's sectors are able to fit into another, which only
201 * excludes cases where sector sizes are not a multiple of each other.
202 */
203 i = sz0 = primary_slot_sz = 0;
204 j = sz1 = secondary_slot_sz = 0;
205 smaller = 0;
206 while (i < num_sectors_primary || j < num_sectors_secondary) {
207 if (sz0 == sz1) {
208 sz0 += boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i);
209 sz1 += boot_img_sector_size(state, BOOT_SECONDARY_SLOT, j);
210 i++;
211 j++;
212 } else if (sz0 < sz1) {
213 sz0 += boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i);
214 /* Guarantee that multiple sectors of the secondary slot
215 * fit into the primary slot.
216 */
217 if (smaller == 2) {
218 BOOT_LOG_WRN("Cannot upgrade: slots have non-compatible sectors");
219 return 0;
220 }
221 smaller = 1;
222 i++;
223 } else {
224 sz1 += boot_img_sector_size(state, BOOT_SECONDARY_SLOT, j);
225 /* Guarantee that multiple sectors of the primary slot
226 * fit into the secondary slot.
227 */
228 if (smaller == 1) {
229 BOOT_LOG_WRN("Cannot upgrade: slots have non-compatible sectors");
230 return 0;
231 }
232 smaller = 2;
233 j++;
234 }
Fabio Utzig74aef312019-11-28 11:05:34 -0300235#ifndef MCUBOOT_OVERWRITE_ONLY
Fabio Utzig12d59162019-11-28 10:01:59 -0300236 if (sz0 == sz1) {
237 primary_slot_sz += sz0;
238 secondary_slot_sz += sz1;
239 /* Scratch has to fit each swap operation to the size of the larger
240 * sector among the primary slot and the secondary slot.
241 */
242 if (sz0 > scratch_sz || sz1 > scratch_sz) {
243 BOOT_LOG_WRN("Cannot upgrade: not all sectors fit inside scratch");
244 return 0;
245 }
246 smaller = sz0 = sz1 = 0;
247 }
Fabio Utzig74aef312019-11-28 11:05:34 -0300248#endif
Fabio Utzig12d59162019-11-28 10:01:59 -0300249 }
250
251 if ((i != num_sectors_primary) ||
252 (j != num_sectors_secondary) ||
253 (primary_slot_sz != secondary_slot_sz)) {
254 BOOT_LOG_WRN("Cannot upgrade: slots are not compatible");
255 return 0;
256 }
257
258 return 1;
259}
260
261#define BOOT_LOG_SWAP_STATE(area, state) \
262 BOOT_LOG_INF("%s: magic=%s, swap_type=0x%x, copy_done=0x%x, " \
263 "image_ok=0x%x", \
264 (area), \
265 ((state)->magic == BOOT_MAGIC_GOOD ? "good" : \
266 (state)->magic == BOOT_MAGIC_UNSET ? "unset" : \
267 "bad"), \
268 (state)->swap_type, \
269 (state)->copy_done, \
270 (state)->image_ok)
271
272struct boot_status_table {
273 uint8_t bst_magic_primary_slot;
274 uint8_t bst_magic_scratch;
275 uint8_t bst_copy_done_primary_slot;
276 uint8_t bst_status_source;
277};
278
279/**
280 * This set of tables maps swap state contents to boot status location.
281 * When searching for a match, these tables must be iterated in order.
282 */
283static const struct boot_status_table boot_status_tables[] = {
284 {
285 /* | primary slot | scratch |
286 * ----------+--------------+--------------|
287 * magic | Good | Any |
288 * copy-done | Set | N/A |
289 * ----------+--------------+--------------'
290 * source: none |
291 * ----------------------------------------'
292 */
293 .bst_magic_primary_slot = BOOT_MAGIC_GOOD,
294 .bst_magic_scratch = BOOT_MAGIC_NOTGOOD,
295 .bst_copy_done_primary_slot = BOOT_FLAG_SET,
296 .bst_status_source = BOOT_STATUS_SOURCE_NONE,
297 },
298
299 {
300 /* | primary slot | scratch |
301 * ----------+--------------+--------------|
302 * magic | Good | Any |
303 * copy-done | Unset | N/A |
304 * ----------+--------------+--------------'
305 * source: primary slot |
306 * ----------------------------------------'
307 */
308 .bst_magic_primary_slot = BOOT_MAGIC_GOOD,
309 .bst_magic_scratch = BOOT_MAGIC_NOTGOOD,
310 .bst_copy_done_primary_slot = BOOT_FLAG_UNSET,
311 .bst_status_source = BOOT_STATUS_SOURCE_PRIMARY_SLOT,
312 },
313
314 {
315 /* | primary slot | scratch |
316 * ----------+--------------+--------------|
317 * magic | Any | Good |
318 * copy-done | Any | N/A |
319 * ----------+--------------+--------------'
320 * source: scratch |
321 * ----------------------------------------'
322 */
323 .bst_magic_primary_slot = BOOT_MAGIC_ANY,
324 .bst_magic_scratch = BOOT_MAGIC_GOOD,
325 .bst_copy_done_primary_slot = BOOT_FLAG_ANY,
326 .bst_status_source = BOOT_STATUS_SOURCE_SCRATCH,
327 },
328 {
329 /* | primary slot | scratch |
330 * ----------+--------------+--------------|
331 * magic | Unset | Any |
332 * copy-done | Unset | N/A |
333 * ----------+--------------+--------------|
334 * source: varies |
335 * ----------------------------------------+--------------------------+
336 * This represents one of two cases: |
337 * o No swaps ever (no status to read, so no harm in checking). |
338 * o Mid-revert; status in primary slot. |
339 * -------------------------------------------------------------------'
340 */
341 .bst_magic_primary_slot = BOOT_MAGIC_UNSET,
342 .bst_magic_scratch = BOOT_MAGIC_ANY,
343 .bst_copy_done_primary_slot = BOOT_FLAG_UNSET,
344 .bst_status_source = BOOT_STATUS_SOURCE_PRIMARY_SLOT,
345 },
346};
347
348#define BOOT_STATUS_TABLES_COUNT \
349 (sizeof boot_status_tables / sizeof boot_status_tables[0])
350
351/**
352 * Determines where in flash the most recent boot status is stored. The boot
353 * status is necessary for completing a swap that was interrupted by a boot
354 * loader reset.
355 *
356 * @return A BOOT_STATUS_SOURCE_[...] code indicating where status should
357 * be read from.
358 */
359int
360swap_status_source(struct boot_loader_state *state)
361{
362 const struct boot_status_table *table;
363 struct boot_swap_state state_scratch;
364 struct boot_swap_state state_primary_slot;
365 int rc;
366 size_t i;
367 uint8_t source;
368 uint8_t image_index;
369
370#if (BOOT_IMAGE_NUMBER == 1)
371 (void)state;
372#endif
373
374 image_index = BOOT_CURR_IMG(state);
375 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_PRIMARY(image_index),
376 &state_primary_slot);
377 assert(rc == 0);
378
379 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SCRATCH, &state_scratch);
380 assert(rc == 0);
381
382 BOOT_LOG_SWAP_STATE("Primary image", &state_primary_slot);
383 BOOT_LOG_SWAP_STATE("Scratch", &state_scratch);
384
385 for (i = 0; i < BOOT_STATUS_TABLES_COUNT; i++) {
386 table = &boot_status_tables[i];
387
388 if (boot_magic_compatible_check(table->bst_magic_primary_slot,
389 state_primary_slot.magic) &&
390 boot_magic_compatible_check(table->bst_magic_scratch,
391 state_scratch.magic) &&
392 (table->bst_copy_done_primary_slot == BOOT_FLAG_ANY ||
393 table->bst_copy_done_primary_slot == state_primary_slot.copy_done))
394 {
395 source = table->bst_status_source;
396
397#if (BOOT_IMAGE_NUMBER > 1)
398 /* In case of multi-image boot it can happen that if boot status
399 * info is found on scratch area then it does not belong to the
400 * currently examined image.
401 */
402 if (source == BOOT_STATUS_SOURCE_SCRATCH &&
403 state_scratch.image_num != BOOT_CURR_IMG(state)) {
404 source = BOOT_STATUS_SOURCE_NONE;
405 }
406#endif
407
408 BOOT_LOG_INF("Boot source: %s",
409 source == BOOT_STATUS_SOURCE_NONE ? "none" :
410 source == BOOT_STATUS_SOURCE_SCRATCH ? "scratch" :
411 source == BOOT_STATUS_SOURCE_PRIMARY_SLOT ?
412 "primary slot" : "BUG; can't happen");
413 return source;
414 }
415 }
416
417 BOOT_LOG_INF("Boot source: none");
418 return BOOT_STATUS_SOURCE_NONE;
419}
420
Fabio Utzig74aef312019-11-28 11:05:34 -0300421#ifndef MCUBOOT_OVERWRITE_ONLY
Fabio Utzig12d59162019-11-28 10:01:59 -0300422/**
423 * Calculates the number of sectors the scratch area can contain. A "last"
424 * source sector is specified because images are copied backwards in flash
425 * (final index to index number 0).
426 *
427 * @param last_sector_idx The index of the last source sector
428 * (inclusive).
429 * @param out_first_sector_idx The index of the first source sector
430 * (inclusive) gets written here.
431 *
432 * @return The number of bytes comprised by the
433 * [first-sector, last-sector] range.
434 */
435static uint32_t
436boot_copy_sz(const struct boot_loader_state *state, int last_sector_idx,
437 int *out_first_sector_idx)
438{
439 size_t scratch_sz;
440 uint32_t new_sz;
441 uint32_t sz;
442 int i;
443
444 sz = 0;
445
446 scratch_sz = boot_scratch_area_size(state);
447 for (i = last_sector_idx; i >= 0; i--) {
448 new_sz = sz + boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i);
449 /*
450 * The secondary slot is not being checked here, because
451 * `boot_slots_compatible` already provides assurance that the copy size
452 * will be compatible with the primary slot and scratch.
453 */
454 if (new_sz > scratch_sz) {
455 break;
456 }
457 sz = new_sz;
458 }
459
460 /* i currently refers to a sector that doesn't fit or it is -1 because all
461 * sectors have been processed. In both cases, exclude sector i.
462 */
463 *out_first_sector_idx = i + 1;
464 return sz;
465}
466
467/**
468 * Swaps the contents of two flash regions within the two image slots.
469 *
470 * @param idx The index of the first sector in the range of
471 * sectors being swapped.
472 * @param sz The number of bytes to swap.
473 * @param bs The current boot status. This struct gets
474 * updated according to the outcome.
475 *
476 * @return 0 on success; nonzero on failure.
477 */
478static void
479boot_swap_sectors(int idx, uint32_t sz, struct boot_loader_state *state,
480 struct boot_status *bs)
481{
482 const struct flash_area *fap_primary_slot;
483 const struct flash_area *fap_secondary_slot;
484 const struct flash_area *fap_scratch;
485 uint32_t copy_sz;
486 uint32_t trailer_sz;
487 uint32_t img_off;
488 uint32_t scratch_trailer_off;
489 struct boot_swap_state swap_state;
490 size_t last_sector;
491 bool erase_scratch;
492 uint8_t image_index;
493 int rc;
494
495 /* Calculate offset from start of image area. */
496 img_off = boot_img_sector_off(state, BOOT_PRIMARY_SLOT, idx);
497
498 copy_sz = sz;
499 trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(state));
500
501 /* sz in this function is always sized on a multiple of the sector size.
502 * The check against the start offset of the last sector
503 * is to determine if we're swapping the last sector. The last sector
504 * needs special handling because it's where the trailer lives. If we're
505 * copying it, we need to use scratch to write the trailer temporarily.
506 *
507 * NOTE: `use_scratch` is a temporary flag (never written to flash) which
508 * controls if special handling is needed (swapping last sector).
509 */
510 last_sector = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT) - 1;
511 if ((img_off + sz) >
512 boot_img_sector_off(state, BOOT_PRIMARY_SLOT, last_sector)) {
513 copy_sz -= trailer_sz;
514 }
515
516 bs->use_scratch = (bs->idx == BOOT_STATUS_IDX_0 && copy_sz != sz);
517
518 image_index = BOOT_CURR_IMG(state);
519
520 rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index),
521 &fap_primary_slot);
522 assert (rc == 0);
523
524 rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY(image_index),
525 &fap_secondary_slot);
526 assert (rc == 0);
527
528 rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH, &fap_scratch);
529 assert (rc == 0);
530
531 if (bs->state == BOOT_STATUS_STATE_0) {
532 BOOT_LOG_DBG("erasing scratch area");
533 rc = boot_erase_region(fap_scratch, 0, fap_scratch->fa_size);
534 assert(rc == 0);
535
536 if (bs->idx == BOOT_STATUS_IDX_0) {
537 /* Write a trailer to the scratch area, even if we don't need the
538 * scratch area for status. We need a temporary place to store the
539 * `swap-type` while we erase the primary trailer.
540 */
541 rc = swap_status_init(state, fap_scratch, bs);
542 assert(rc == 0);
543
544 if (!bs->use_scratch) {
545 /* Prepare the primary status area... here it is known that the
546 * last sector is not being used by the image data so it's safe
547 * to erase.
548 */
549 rc = swap_erase_trailer_sectors(state, fap_primary_slot);
550 assert(rc == 0);
551
552 rc = swap_status_init(state, fap_primary_slot, bs);
553 assert(rc == 0);
554
555 /* Erase the temporary trailer from the scratch area. */
556 rc = boot_erase_region(fap_scratch, 0, fap_scratch->fa_size);
557 assert(rc == 0);
558 }
559 }
560
561 rc = boot_copy_region(state, fap_secondary_slot, fap_scratch,
562 img_off, 0, copy_sz);
563 assert(rc == 0);
564
565 rc = boot_write_status(state, bs);
566 bs->state = BOOT_STATUS_STATE_1;
567 BOOT_STATUS_ASSERT(rc == 0);
568 }
569
570 if (bs->state == BOOT_STATUS_STATE_1) {
571 rc = boot_erase_region(fap_secondary_slot, img_off, sz);
572 assert(rc == 0);
573
574 rc = boot_copy_region(state, fap_primary_slot, fap_secondary_slot,
575 img_off, img_off, copy_sz);
576 assert(rc == 0);
577
578 if (bs->idx == BOOT_STATUS_IDX_0 && !bs->use_scratch) {
579 /* If not all sectors of the slot are being swapped,
580 * guarantee here that only the primary slot will have the state.
581 */
582 rc = swap_erase_trailer_sectors(state, fap_secondary_slot);
583 assert(rc == 0);
584 }
585
586 rc = boot_write_status(state, bs);
587 bs->state = BOOT_STATUS_STATE_2;
588 BOOT_STATUS_ASSERT(rc == 0);
589 }
590
591 if (bs->state == BOOT_STATUS_STATE_2) {
592 rc = boot_erase_region(fap_primary_slot, img_off, sz);
593 assert(rc == 0);
594
595 /* NOTE: If this is the final sector, we exclude the image trailer from
596 * this copy (copy_sz was truncated earlier).
597 */
598 rc = boot_copy_region(state, fap_scratch, fap_primary_slot,
599 0, img_off, copy_sz);
600 assert(rc == 0);
601
602 if (bs->use_scratch) {
603 scratch_trailer_off = boot_status_off(fap_scratch);
604
605 /* copy current status that is being maintained in scratch */
606 rc = boot_copy_region(state, fap_scratch, fap_primary_slot,
607 scratch_trailer_off, img_off + copy_sz,
608 (BOOT_STATUS_STATE_COUNT - 1) * BOOT_WRITE_SZ(state));
609 BOOT_STATUS_ASSERT(rc == 0);
610
611 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SCRATCH,
612 &swap_state);
613 assert(rc == 0);
614
615 if (swap_state.image_ok == BOOT_FLAG_SET) {
616 rc = boot_write_image_ok(fap_primary_slot);
617 assert(rc == 0);
618 }
619
620 if (swap_state.swap_type != BOOT_SWAP_TYPE_NONE) {
621 rc = boot_write_swap_info(fap_primary_slot,
622 swap_state.swap_type, image_index);
623 assert(rc == 0);
624 }
625
626 rc = boot_write_swap_size(fap_primary_slot, bs->swap_size);
627 assert(rc == 0);
628
629#ifdef MCUBOOT_ENC_IMAGES
630 rc = boot_write_enc_key(fap_primary_slot, 0, bs->enckey[0]);
631 assert(rc == 0);
632
633 rc = boot_write_enc_key(fap_primary_slot, 1, bs->enckey[1]);
634 assert(rc == 0);
635#endif
636 rc = boot_write_magic(fap_primary_slot);
637 assert(rc == 0);
638 }
639
640 /* If we wrote a trailer to the scratch area, erase it after we persist
641 * a trailer to the primary slot. We do this to prevent mcuboot from
642 * reading a stale status from the scratch area in case of immediate
643 * reset.
644 */
645 erase_scratch = bs->use_scratch;
646 bs->use_scratch = 0;
647
648 rc = boot_write_status(state, bs);
649 bs->idx++;
650 bs->state = BOOT_STATUS_STATE_0;
651 BOOT_STATUS_ASSERT(rc == 0);
652
653 if (erase_scratch) {
654 rc = boot_erase_region(fap_scratch, 0, sz);
655 assert(rc == 0);
656 }
657 }
658
659 flash_area_close(fap_primary_slot);
660 flash_area_close(fap_secondary_slot);
661 flash_area_close(fap_scratch);
662}
663
664void
665swap_run(struct boot_loader_state *state, struct boot_status *bs,
666 uint32_t copy_size)
667{
668 uint32_t sz;
669 int first_sector_idx;
670 int last_sector_idx;
671 uint32_t swap_idx;
672 int last_idx_secondary_slot;
673 uint32_t primary_slot_size;
674 uint32_t secondary_slot_size;
675 primary_slot_size = 0;
676 secondary_slot_size = 0;
677 last_sector_idx = 0;
678 last_idx_secondary_slot = 0;
679
680 /*
681 * Knowing the size of the largest image between both slots, here we
682 * find what is the last sector in the primary slot that needs swapping.
683 * Since we already know that both slots are compatible, the secondary
684 * slot's last sector is not really required after this check is finished.
685 */
686 while (1) {
687 if ((primary_slot_size < copy_size) ||
688 (primary_slot_size < secondary_slot_size)) {
689 primary_slot_size += boot_img_sector_size(state,
690 BOOT_PRIMARY_SLOT,
691 last_sector_idx);
692 }
693 if ((secondary_slot_size < copy_size) ||
694 (secondary_slot_size < primary_slot_size)) {
695 secondary_slot_size += boot_img_sector_size(state,
696 BOOT_SECONDARY_SLOT,
697 last_idx_secondary_slot);
698 }
699 if (primary_slot_size >= copy_size &&
700 secondary_slot_size >= copy_size &&
701 primary_slot_size == secondary_slot_size) {
702 break;
703 }
704 last_sector_idx++;
705 last_idx_secondary_slot++;
706 }
707
708 swap_idx = 0;
709 while (last_sector_idx >= 0) {
710 sz = boot_copy_sz(state, last_sector_idx, &first_sector_idx);
711 if (swap_idx >= (bs->idx - BOOT_STATUS_IDX_0)) {
712 boot_swap_sectors(first_sector_idx, sz, state, bs);
713 }
714
715 last_sector_idx = first_sector_idx - 1;
716 swap_idx++;
717 }
718
719}
Fabio Utzig74aef312019-11-28 11:05:34 -0300720#endif
Fabio Utzig12d59162019-11-28 10:01:59 -0300721
722#endif