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