1 /*
2  * SPDX-License-Identifier: Apache-2.0
3  *
4  * 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 <stddef.h>
20 #include <stdbool.h>
21 #include <inttypes.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include "bootutil/bootutil.h"
25 #include "bootutil_priv.h"
26 #include "swap_priv.h"
27 #include "bootutil/bootutil_log.h"
28 
29 #include "mcuboot_config/mcuboot_config.h"
30 
31 BOOT_LOG_MODULE_DECLARE(mcuboot);
32 
33 #if !defined(MCUBOOT_SWAP_USING_MOVE)
34 
35 #if defined(MCUBOOT_VALIDATE_PRIMARY_SLOT)
36 /*
37  * FIXME: this might have to be updated for threaded sim
38  */
39 int boot_status_fails = 0;
40 #define BOOT_STATUS_ASSERT(x)                \
41     do {                                     \
42         if (!(x)) {                          \
43             boot_status_fails++;             \
44         }                                    \
45     } while (0)
46 #else
47 #define BOOT_STATUS_ASSERT(x) ASSERT(x)
48 #endif
49 
50 #if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)
51 /**
52  * Reads the status of a partially-completed swap, if any.  This is necessary
53  * to recover in case the boot lodaer was reset in the middle of a swap
54  * operation.
55  */
56 int
swap_read_status_bytes(const struct flash_area * fap,struct boot_loader_state * state,struct boot_status * bs)57 swap_read_status_bytes(const struct flash_area *fap,
58         struct boot_loader_state *state, struct boot_status *bs)
59 {
60     uint32_t off;
61     uint8_t status;
62     int max_entries;
63     int found;
64     int found_idx;
65     int invalid;
66     int rc;
67     int i;
68 
69     off = boot_status_off(fap);
70     max_entries = boot_status_entries(BOOT_CURR_IMG(state), fap);
71     if (max_entries < 0) {
72         return BOOT_EBADARGS;
73     }
74 
75     found = 0;
76     found_idx = 0;
77     invalid = 0;
78     for (i = 0; i < max_entries; i++) {
79         rc = flash_area_read(fap, off + i * BOOT_WRITE_SZ(state),
80                 &status, 1);
81         if (rc < 0) {
82             return BOOT_EFLASH;
83         }
84 
85         if (bootutil_buffer_is_erased(fap, &status, 1)) {
86             if (found && !found_idx) {
87                 found_idx = i;
88             }
89         } else if (!found) {
90             found = 1;
91         } else if (found_idx) {
92             invalid = 1;
93             break;
94         }
95     }
96 
97     if (invalid) {
98         /* This means there was an error writing status on the last
99          * swap. Tell user and move on to validation!
100          */
101 #if !defined(__BOOTSIM__)
102         BOOT_LOG_ERR("Detected inconsistent status!");
103 #endif
104 
105 #if !defined(MCUBOOT_VALIDATE_PRIMARY_SLOT)
106         /* With validation of the primary slot disabled, there is no way
107          * to be sure the swapped primary slot is OK, so abort!
108          */
109         assert(0);
110 #endif
111     }
112 
113     if (found) {
114         if (!found_idx) {
115             found_idx = i;
116         }
117         bs->idx = (found_idx / BOOT_STATUS_STATE_COUNT) + 1;
118         bs->state = (found_idx % BOOT_STATUS_STATE_COUNT) + 1;
119     }
120 
121     return 0;
122 }
123 
124 uint32_t
boot_status_internal_off(const struct boot_status * bs,int elem_sz)125 boot_status_internal_off(const struct boot_status *bs, int elem_sz)
126 {
127     int idx_sz;
128 
129     idx_sz = elem_sz * BOOT_STATUS_STATE_COUNT;
130 
131     return (bs->idx - BOOT_STATUS_IDX_0) * idx_sz +
132            (bs->state - BOOT_STATUS_STATE_0) * elem_sz;
133 }
134 
135 /*
136  * Slots are compatible when all sectors that store up to to size of the image
137  * round up to sector size, in both slot's are able to fit in the scratch
138  * area, and have sizes that are a multiple of each other (powers of two
139  * presumably!).
140  */
141 int
boot_slots_compatible(struct boot_loader_state * state)142 boot_slots_compatible(struct boot_loader_state *state)
143 {
144     size_t num_sectors_primary;
145     size_t num_sectors_secondary;
146     size_t sz0, sz1;
147     size_t primary_slot_sz, secondary_slot_sz;
148 #ifndef MCUBOOT_OVERWRITE_ONLY
149     size_t scratch_sz;
150 #endif
151     size_t i, j;
152     int8_t smaller;
153 
154     num_sectors_primary = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT);
155     num_sectors_secondary = boot_img_num_sectors(state, BOOT_SECONDARY_SLOT);
156     if ((num_sectors_primary > BOOT_MAX_IMG_SECTORS) ||
157         (num_sectors_secondary > BOOT_MAX_IMG_SECTORS)) {
158         BOOT_LOG_WRN("Cannot upgrade: more sectors than allowed");
159         return 0;
160     }
161 
162 #ifndef MCUBOOT_OVERWRITE_ONLY
163     scratch_sz = boot_scratch_area_size(state);
164 #endif
165 
166     /*
167      * The following loop scans all sectors in a linear fashion, assuring that
168      * for each possible sector in each slot, it is able to fit in the other
169      * slot's sector or sectors. Slot's should be compatible as long as any
170      * number of a slot's sectors are able to fit into another, which only
171      * excludes cases where sector sizes are not a multiple of each other.
172      */
173     i = sz0 = primary_slot_sz = 0;
174     j = sz1 = secondary_slot_sz = 0;
175     smaller = 0;
176     while (i < num_sectors_primary || j < num_sectors_secondary) {
177         if (sz0 == sz1) {
178             sz0 += boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i);
179             sz1 += boot_img_sector_size(state, BOOT_SECONDARY_SLOT, j);
180             i++;
181             j++;
182         } else if (sz0 < sz1) {
183             sz0 += boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i);
184             /* Guarantee that multiple sectors of the secondary slot
185              * fit into the primary slot.
186              */
187             if (smaller == 2) {
188                 BOOT_LOG_WRN("Cannot upgrade: slots have non-compatible sectors");
189                 return 0;
190             }
191             smaller = 1;
192             i++;
193         } else {
194             size_t sector_size = boot_img_sector_size(state, BOOT_SECONDARY_SLOT, j);
195 
196 #ifdef MCUBOOT_DECOMPRESS_IMAGES
197             if (sector_size == 0) {
198                 /* Since this supports decompressed images, we can safely exit if slot1 is
199                  * smaller than slot0.
200                  */
201                 break;
202             }
203 #endif
204             sz1 += sector_size;
205             /* Guarantee that multiple sectors of the primary slot
206              * fit into the secondary slot.
207              */
208             if (smaller == 1) {
209                 BOOT_LOG_WRN("Cannot upgrade: slots have non-compatible sectors");
210                 return 0;
211             }
212             smaller = 2;
213             j++;
214         }
215 #ifndef MCUBOOT_OVERWRITE_ONLY
216         if (sz0 == sz1) {
217             primary_slot_sz += sz0;
218             secondary_slot_sz += sz1;
219             /* Scratch has to fit each swap operation to the size of the larger
220              * sector among the primary slot and the secondary slot.
221              */
222             if (sz0 > scratch_sz || sz1 > scratch_sz) {
223                 BOOT_LOG_WRN("Cannot upgrade: not all sectors fit inside scratch");
224                 return 0;
225             }
226             smaller = sz0 = sz1 = 0;
227         }
228 #endif
229     }
230 
231 #ifndef MCUBOOT_DECOMPRESS_IMAGES
232     if ((i != num_sectors_primary) ||
233         (j != num_sectors_secondary) ||
234         (primary_slot_sz != secondary_slot_sz)) {
235         BOOT_LOG_WRN("Cannot upgrade: slots are not compatible");
236         return 0;
237     }
238 #endif
239 
240     return 1;
241 }
242 
243 #define BOOT_LOG_SWAP_STATE(area, state)                            \
244     BOOT_LOG_INF("%s: magic=%s, swap_type=0x%x, copy_done=0x%x, "   \
245                  "image_ok=0x%x",                                   \
246                  (area),                                            \
247                  ((state)->magic == BOOT_MAGIC_GOOD ? "good" :      \
248                   (state)->magic == BOOT_MAGIC_UNSET ? "unset" :    \
249                   "bad"),                                           \
250                  (state)->swap_type,                                \
251                  (state)->copy_done,                                \
252                  (state)->image_ok)
253 
254 struct boot_status_table {
255     uint8_t bst_magic_primary_slot;
256     uint8_t bst_magic_scratch;
257     uint8_t bst_copy_done_primary_slot;
258     uint8_t bst_status_source;
259 };
260 
261 /**
262  * This set of tables maps swap state contents to boot status location.
263  * When searching for a match, these tables must be iterated in order.
264  */
265 static const struct boot_status_table boot_status_tables[] = {
266     {
267         /*           | primary slot | scratch      |
268          * ----------+--------------+--------------|
269          *     magic | Good         | Any          |
270          * copy-done | Set          | N/A          |
271          * ----------+--------------+--------------'
272          * source: none                            |
273          * ----------------------------------------'
274          */
275         .bst_magic_primary_slot =     BOOT_MAGIC_GOOD,
276         .bst_magic_scratch =          BOOT_MAGIC_NOTGOOD,
277         .bst_copy_done_primary_slot = BOOT_FLAG_SET,
278         .bst_status_source =          BOOT_STATUS_SOURCE_NONE,
279     },
280 
281     {
282         /*           | primary slot | scratch      |
283          * ----------+--------------+--------------|
284          *     magic | Good         | Any          |
285          * copy-done | Unset        | N/A          |
286          * ----------+--------------+--------------'
287          * source: primary slot                    |
288          * ----------------------------------------'
289          */
290         .bst_magic_primary_slot =     BOOT_MAGIC_GOOD,
291         .bst_magic_scratch =          BOOT_MAGIC_NOTGOOD,
292         .bst_copy_done_primary_slot = BOOT_FLAG_UNSET,
293         .bst_status_source =          BOOT_STATUS_SOURCE_PRIMARY_SLOT,
294     },
295 
296     {
297         /*           | primary slot | scratch      |
298          * ----------+--------------+--------------|
299          *     magic | Any          | Good         |
300          * copy-done | Any          | N/A          |
301          * ----------+--------------+--------------'
302          * source: scratch                         |
303          * ----------------------------------------'
304          */
305         .bst_magic_primary_slot =     BOOT_MAGIC_ANY,
306         .bst_magic_scratch =          BOOT_MAGIC_GOOD,
307         .bst_copy_done_primary_slot = BOOT_FLAG_ANY,
308         .bst_status_source =          BOOT_STATUS_SOURCE_SCRATCH,
309     },
310     {
311         /*           | primary slot | scratch      |
312          * ----------+--------------+--------------|
313          *     magic | Unset        | Any          |
314          * copy-done | Unset        | N/A          |
315          * ----------+--------------+--------------|
316          * source: varies                          |
317          * ----------------------------------------+--------------------------+
318          * This represents one of two cases:                                  |
319          * o No swaps ever (no status to read, so no harm in checking).       |
320          * o Mid-revert; status in primary slot.                              |
321          * -------------------------------------------------------------------'
322          */
323         .bst_magic_primary_slot =     BOOT_MAGIC_UNSET,
324         .bst_magic_scratch =          BOOT_MAGIC_ANY,
325         .bst_copy_done_primary_slot = BOOT_FLAG_UNSET,
326         .bst_status_source =          BOOT_STATUS_SOURCE_PRIMARY_SLOT,
327     },
328 };
329 
330 #define BOOT_STATUS_TABLES_COUNT \
331     (sizeof boot_status_tables / sizeof boot_status_tables[0])
332 
333 /**
334  * Determines where in flash the most recent boot status is stored. The boot
335  * status is necessary for completing a swap that was interrupted by a boot
336  * loader reset.
337  *
338  * @return      A BOOT_STATUS_SOURCE_[...] code indicating where status should
339  *              be read from.
340  */
341 int
swap_status_source(struct boot_loader_state * state)342 swap_status_source(struct boot_loader_state *state)
343 {
344     const struct boot_status_table *table;
345 #if MCUBOOT_SWAP_USING_SCRATCH
346     struct boot_swap_state state_scratch;
347 #endif
348     struct boot_swap_state state_primary_slot;
349     int rc;
350     size_t i;
351     uint8_t source;
352     uint8_t image_index;
353 
354 #if (BOOT_IMAGE_NUMBER == 1)
355     (void)state;
356 #endif
357 
358     image_index = BOOT_CURR_IMG(state);
359     rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_PRIMARY(image_index),
360             &state_primary_slot);
361     assert(rc == 0);
362 
363 #if MCUBOOT_SWAP_USING_SCRATCH
364     rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SCRATCH, &state_scratch);
365     assert(rc == 0);
366 #endif
367 
368     BOOT_LOG_SWAP_STATE("Primary image", &state_primary_slot);
369 #if MCUBOOT_SWAP_USING_SCRATCH
370     BOOT_LOG_SWAP_STATE("Scratch", &state_scratch);
371 #endif
372     for (i = 0; i < BOOT_STATUS_TABLES_COUNT; i++) {
373         table = &boot_status_tables[i];
374 
375         if (boot_magic_compatible_check(table->bst_magic_primary_slot,
376                           state_primary_slot.magic) &&
377 #if MCUBOOT_SWAP_USING_SCRATCH
378             boot_magic_compatible_check(table->bst_magic_scratch,
379                           state_scratch.magic) &&
380 #endif
381             (table->bst_copy_done_primary_slot == BOOT_FLAG_ANY ||
382              table->bst_copy_done_primary_slot == state_primary_slot.copy_done))
383         {
384             source = table->bst_status_source;
385 
386 #if (BOOT_IMAGE_NUMBER > 1) && MCUBOOT_SWAP_USING_SCRATCH
387             /* In case of multi-image boot it can happen that if boot status
388              * info is found on scratch area then it does not belong to the
389              * currently examined image.
390              */
391             if (source == BOOT_STATUS_SOURCE_SCRATCH &&
392                 state_scratch.image_num != BOOT_CURR_IMG(state)) {
393                 source = BOOT_STATUS_SOURCE_NONE;
394             }
395 #endif
396 
397             BOOT_LOG_INF("Boot source: %s",
398                          source == BOOT_STATUS_SOURCE_NONE ? "none" :
399                          source == BOOT_STATUS_SOURCE_SCRATCH ? "scratch" :
400                          source == BOOT_STATUS_SOURCE_PRIMARY_SLOT ?
401                                    "primary slot" : "BUG; can't happen");
402             return source;
403         }
404     }
405 
406     BOOT_LOG_INF("Boot source: none");
407     return BOOT_STATUS_SOURCE_NONE;
408 }
409 
410 #ifndef MCUBOOT_OVERWRITE_ONLY
411 /**
412  * Calculates the number of sectors the scratch area can contain.  A "last"
413  * source sector is specified because images are copied backwards in flash
414  * (final index to index number 0).
415  *
416  * @param last_sector_idx       The index of the last source sector
417  *                                  (inclusive).
418  * @param out_first_sector_idx  The index of the first source sector
419  *                                  (inclusive) gets written here.
420  *
421  * @return                      The number of bytes comprised by the
422  *                                  [first-sector, last-sector] range.
423  */
424 static uint32_t
boot_copy_sz(const struct boot_loader_state * state,int last_sector_idx,int * out_first_sector_idx)425 boot_copy_sz(const struct boot_loader_state *state, int last_sector_idx,
426              int *out_first_sector_idx)
427 {
428     size_t scratch_sz;
429     uint32_t new_sz;
430     uint32_t sz;
431     int i;
432 
433     sz = 0;
434 
435     scratch_sz = boot_scratch_area_size(state);
436     for (i = last_sector_idx; i >= 0; i--) {
437         new_sz = sz + boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i);
438         /*
439          * The secondary slot is not being checked here, because
440          * `boot_slots_compatible` already provides assurance that the copy size
441          * will be compatible with the primary slot and scratch.
442          */
443         if (new_sz > scratch_sz) {
444             break;
445         }
446         sz = new_sz;
447     }
448 
449     /* i currently refers to a sector that doesn't fit or it is -1 because all
450      * sectors have been processed.  In both cases, exclude sector i.
451      */
452     *out_first_sector_idx = i + 1;
453     return sz;
454 }
455 
456 /**
457  * Finds the index of the last sector in the primary slot that needs swapping.
458  *
459  * @param state     Current bootloader's state.
460  * @param copy_size Total number of bytes to swap.
461  *
462  * @return          Index of the last sector in the primary slot that needs swapping.
463  */
464 static int
find_last_sector_idx(const struct boot_loader_state * state,uint32_t copy_size)465 find_last_sector_idx(const struct boot_loader_state *state, uint32_t copy_size)
466 {
467     int last_sector_idx;
468     uint32_t primary_slot_size;
469     uint32_t secondary_slot_size;
470 
471     primary_slot_size = 0;
472     secondary_slot_size = 0;
473     last_sector_idx = 0;
474 
475     /*
476      * Knowing the size of the largest image between both slots, here we
477      * find what is the last sector in the primary slot that needs swapping.
478      * Since we already know that both slots are compatible, the secondary
479      * slot's last sector is not really required after this check is finished.
480      */
481     while (1) {
482         if ((primary_slot_size < copy_size) ||
483             (primary_slot_size < secondary_slot_size)) {
484            primary_slot_size += boot_img_sector_size(state,
485                                                      BOOT_PRIMARY_SLOT,
486                                                      last_sector_idx);
487         }
488         if ((secondary_slot_size < copy_size) ||
489             (secondary_slot_size < primary_slot_size)) {
490            secondary_slot_size += boot_img_sector_size(state,
491                                                        BOOT_SECONDARY_SLOT,
492                                                        last_sector_idx);
493         }
494         if (primary_slot_size >= copy_size &&
495                 secondary_slot_size >= copy_size &&
496                 primary_slot_size == secondary_slot_size) {
497             break;
498         }
499         last_sector_idx++;
500     }
501 
502     return last_sector_idx;
503 }
504 
505 /**
506  * Finds the number of swap operations that have to be performed to swap the two images.
507  *
508  * @param state     Current bootloader's state.
509  * @param copy_size Total number of bytes to swap.
510  *
511  * @return          The number of swap operations that have to be performed.
512 */
513 static uint32_t
find_swap_count(const struct boot_loader_state * state,uint32_t copy_size)514 find_swap_count(const struct boot_loader_state *state, uint32_t copy_size)
515 {
516     int first_sector_idx;
517     int last_sector_idx;
518     uint32_t swap_count;
519 
520     last_sector_idx = find_last_sector_idx(state, copy_size);
521 
522     swap_count = 0;
523 
524     while (last_sector_idx >= 0) {
525         boot_copy_sz(state, last_sector_idx, &first_sector_idx);
526 
527         last_sector_idx = first_sector_idx - 1;
528         swap_count++;
529     }
530 
531     return swap_count;
532 }
533 
534 /**
535  * Swaps the contents of two flash regions within the two image slots.
536  *
537  * @param idx                   The index of the first sector in the range of
538  *                                  sectors being swapped.
539  * @param sz                    The number of bytes to swap.
540  * @param bs                    The current boot status.  This struct gets
541  *                                  updated according to the outcome.
542  *
543  * @return                      0 on success; nonzero on failure.
544  */
545 static void
boot_swap_sectors(int idx,uint32_t sz,struct boot_loader_state * state,struct boot_status * bs)546 boot_swap_sectors(int idx, uint32_t sz, struct boot_loader_state *state,
547         struct boot_status *bs)
548 {
549     const struct flash_area *fap_primary_slot;
550     const struct flash_area *fap_secondary_slot;
551     const struct flash_area *fap_scratch;
552     uint32_t copy_sz;
553     uint32_t trailer_sz;
554     uint32_t sector_sz;
555     uint32_t img_off;
556     uint32_t scratch_trailer_off;
557     struct boot_swap_state swap_state;
558     size_t last_sector;
559     bool erase_scratch;
560     uint8_t image_index;
561     int rc;
562 
563     /* Calculate offset from start of image area. */
564     img_off = boot_img_sector_off(state, BOOT_PRIMARY_SLOT, idx);
565 
566     copy_sz = sz;
567     trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(state));
568 
569     /* sz in this function is always sized on a multiple of the sector size.
570      * The check against the start offset of the last sector
571      * is to determine if we're swapping the last sector. The last sector
572      * needs special handling because it's where the trailer lives. If we're
573      * copying it, we need to use scratch to write the trailer temporarily.
574      *
575      * NOTE: `use_scratch` is a temporary flag (never written to flash) which
576      * controls if special handling is needed (swapping last sector).
577      */
578     last_sector = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT) - 1;
579     sector_sz = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, last_sector);
580 
581     if (sector_sz < trailer_sz) {
582         uint32_t trailer_sector_sz = sector_sz;
583 
584         while (trailer_sector_sz < trailer_sz) {
585             /* Consider that the image trailer may span across sectors of
586              * different sizes.
587              */
588             sector_sz = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, --last_sector);
589 
590             trailer_sector_sz += sector_sz;
591         }
592     }
593 
594     if ((img_off + sz) >
595         boot_img_sector_off(state, BOOT_PRIMARY_SLOT, last_sector)) {
596         copy_sz -= trailer_sz;
597     }
598 
599     bs->use_scratch = (bs->idx == BOOT_STATUS_IDX_0 && copy_sz != sz);
600 
601     image_index = BOOT_CURR_IMG(state);
602 
603     rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index),
604             &fap_primary_slot);
605     assert (rc == 0);
606 
607     rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY(image_index),
608             &fap_secondary_slot);
609     assert (rc == 0);
610 
611     rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH, &fap_scratch);
612     assert (rc == 0);
613 
614     if (bs->state == BOOT_STATUS_STATE_0) {
615         BOOT_LOG_DBG("erasing scratch area");
616         rc = boot_erase_region(fap_scratch, 0, flash_area_get_size(fap_scratch));
617         assert(rc == 0);
618 
619         if (bs->idx == BOOT_STATUS_IDX_0) {
620             /* Write a trailer to the scratch area, even if we don't need the
621              * scratch area for status.  We need a temporary place to store the
622              * `swap-type` while we erase the primary trailer.
623              */
624             rc = swap_status_init(state, fap_scratch, bs);
625             assert(rc == 0);
626 
627             if (!bs->use_scratch) {
628                 /* Prepare the primary status area... here it is known that the
629                  * last sector is not being used by the image data so it's safe
630                  * to erase.
631                  */
632                 rc = swap_erase_trailer_sectors(state, fap_primary_slot);
633                 assert(rc == 0);
634 
635                 rc = swap_status_init(state, fap_primary_slot, bs);
636                 assert(rc == 0);
637 
638                 /* Erase the temporary trailer from the scratch area. */
639                 rc = boot_erase_region(fap_scratch, 0,
640                         flash_area_get_size(fap_scratch));
641                 assert(rc == 0);
642             }
643         }
644 
645         rc = boot_copy_region(state, fap_secondary_slot, fap_scratch,
646                               img_off, 0, copy_sz);
647         assert(rc == 0);
648 
649         rc = boot_write_status(state, bs);
650         bs->state = BOOT_STATUS_STATE_1;
651         BOOT_STATUS_ASSERT(rc == 0);
652     }
653 
654     if (bs->state == BOOT_STATUS_STATE_1) {
655         rc = boot_erase_region(fap_secondary_slot, img_off, sz);
656         assert(rc == 0);
657 
658         rc = boot_copy_region(state, fap_primary_slot, fap_secondary_slot,
659                               img_off, img_off, copy_sz);
660         assert(rc == 0);
661 
662         if (bs->idx == BOOT_STATUS_IDX_0 && !bs->use_scratch) {
663             /* If not all sectors of the slot are being swapped,
664              * guarantee here that only the primary slot will have the state.
665              */
666             rc = swap_erase_trailer_sectors(state, fap_secondary_slot);
667             assert(rc == 0);
668         }
669 
670         rc = boot_write_status(state, bs);
671         bs->state = BOOT_STATUS_STATE_2;
672         BOOT_STATUS_ASSERT(rc == 0);
673     }
674 
675     if (bs->state == BOOT_STATUS_STATE_2) {
676         rc = boot_erase_region(fap_primary_slot, img_off, sz);
677         assert(rc == 0);
678 
679         /* NOTE: If this is the final sector, we exclude the image trailer from
680          * this copy (copy_sz was truncated earlier).
681          */
682         rc = boot_copy_region(state, fap_scratch, fap_primary_slot,
683                               0, img_off, copy_sz);
684         assert(rc == 0);
685 
686         if (bs->use_scratch) {
687             scratch_trailer_off = boot_status_off(fap_scratch);
688 
689             /* copy current status that is being maintained in scratch */
690             rc = boot_copy_region(state, fap_scratch, fap_primary_slot,
691                         scratch_trailer_off, img_off + copy_sz,
692                         (BOOT_STATUS_STATE_COUNT - 1) * BOOT_WRITE_SZ(state));
693             BOOT_STATUS_ASSERT(rc == 0);
694 
695             rc = boot_read_swap_state(fap_scratch, &swap_state);
696             assert(rc == 0);
697 
698             if (swap_state.image_ok == BOOT_FLAG_SET) {
699                 rc = boot_write_image_ok(fap_primary_slot);
700                 assert(rc == 0);
701             }
702 
703             if (swap_state.swap_type != BOOT_SWAP_TYPE_NONE) {
704                 rc = boot_write_swap_info(fap_primary_slot,
705                         swap_state.swap_type, image_index);
706                 assert(rc == 0);
707             }
708 
709             rc = boot_write_swap_size(fap_primary_slot, bs->swap_size);
710             assert(rc == 0);
711 
712 #ifdef MCUBOOT_ENC_IMAGES
713             rc = boot_write_enc_key(fap_primary_slot, 0, bs);
714             assert(rc == 0);
715 
716             rc = boot_write_enc_key(fap_primary_slot, 1, bs);
717             assert(rc == 0);
718 #endif
719             rc = boot_write_magic(fap_primary_slot);
720             assert(rc == 0);
721         }
722 
723         /* If we wrote a trailer to the scratch area, erase it after we persist
724          * a trailer to the primary slot.  We do this to prevent mcuboot from
725          * reading a stale status from the scratch area in case of immediate
726          * reset.
727          */
728         erase_scratch = bs->use_scratch;
729         bs->use_scratch = 0;
730 
731         rc = boot_write_status(state, bs);
732         bs->idx++;
733         bs->state = BOOT_STATUS_STATE_0;
734         BOOT_STATUS_ASSERT(rc == 0);
735 
736         if (erase_scratch) {
737             rc = boot_erase_region(fap_scratch, 0, flash_area_get_size(fap_scratch));
738             assert(rc == 0);
739         }
740     }
741 
742     flash_area_close(fap_primary_slot);
743     flash_area_close(fap_secondary_slot);
744     flash_area_close(fap_scratch);
745 }
746 
747 void
swap_run(struct boot_loader_state * state,struct boot_status * bs,uint32_t copy_size)748 swap_run(struct boot_loader_state *state, struct boot_status *bs,
749          uint32_t copy_size)
750 {
751     uint32_t sz;
752     int first_sector_idx;
753     int last_sector_idx;
754     uint32_t swap_idx;
755 
756     BOOT_LOG_INF("Starting swap using scratch algorithm.");
757 
758     last_sector_idx = find_last_sector_idx(state, copy_size);
759 
760     swap_idx = 0;
761     while (last_sector_idx >= 0) {
762         sz = boot_copy_sz(state, last_sector_idx, &first_sector_idx);
763         if (swap_idx >= (bs->idx - BOOT_STATUS_IDX_0)) {
764             boot_swap_sectors(first_sector_idx, sz, state, bs);
765         }
766 
767         last_sector_idx = first_sector_idx - 1;
768         swap_idx++;
769     }
770 
771 }
772 #endif /* !MCUBOOT_OVERWRITE_ONLY */
773 
app_max_size(struct boot_loader_state * state)774 int app_max_size(struct boot_loader_state *state)
775 {
776     size_t num_sectors_primary;
777     size_t num_sectors_secondary;
778     size_t sz0, sz1;
779     size_t primary_slot_sz, secondary_slot_sz;
780 #ifndef MCUBOOT_OVERWRITE_ONLY
781     size_t scratch_sz;
782 #endif
783     size_t i, j;
784     int8_t smaller;
785 
786     num_sectors_primary = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT);
787     num_sectors_secondary = boot_img_num_sectors(state, BOOT_SECONDARY_SLOT);
788 
789 #ifndef MCUBOOT_OVERWRITE_ONLY
790     scratch_sz = boot_scratch_area_size(state);
791 #endif
792 
793     /*
794      * The following loop scans all sectors in a linear fashion, assuring that
795      * for each possible sector in each slot, it is able to fit in the other
796      * slot's sector or sectors. Slot's should be compatible as long as any
797      * number of a slot's sectors are able to fit into another, which only
798      * excludes cases where sector sizes are not a multiple of each other.
799      */
800     i = sz0 = primary_slot_sz = 0;
801     j = sz1 = secondary_slot_sz = 0;
802     smaller = 0;
803     while (i < num_sectors_primary || j < num_sectors_secondary) {
804         if (sz0 == sz1) {
805             sz0 += boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i);
806             sz1 += boot_img_sector_size(state, BOOT_SECONDARY_SLOT, j);
807             i++;
808             j++;
809         } else if (sz0 < sz1) {
810             sz0 += boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i);
811             /* Guarantee that multiple sectors of the secondary slot
812              * fit into the primary slot.
813              */
814             if (smaller == 2) {
815                 BOOT_LOG_WRN("Cannot upgrade: slots have non-compatible sectors");
816                 return 0;
817             }
818             smaller = 1;
819             i++;
820         } else {
821             sz1 += boot_img_sector_size(state, BOOT_SECONDARY_SLOT, j);
822             /* Guarantee that multiple sectors of the primary slot
823              * fit into the secondary slot.
824              */
825             if (smaller == 1) {
826                 BOOT_LOG_WRN("Cannot upgrade: slots have non-compatible sectors");
827                 return 0;
828             }
829             smaller = 2;
830             j++;
831         }
832 #ifndef MCUBOOT_OVERWRITE_ONLY
833         if (sz0 == sz1) {
834             primary_slot_sz += sz0;
835             secondary_slot_sz += sz1;
836             /* Scratch has to fit each swap operation to the size of the larger
837              * sector among the primary slot and the secondary slot.
838              */
839             if (sz0 > scratch_sz || sz1 > scratch_sz) {
840                 BOOT_LOG_WRN("Cannot upgrade: not all sectors fit inside scratch");
841                 return 0;
842             }
843             smaller = sz0 = sz1 = 0;
844         }
845 #endif
846     }
847 
848 #ifdef MCUBOOT_OVERWRITE_ONLY
849     return (sz1 < sz0 ? sz1 : sz0);
850 #else
851     return (secondary_slot_sz < primary_slot_sz ? secondary_slot_sz : primary_slot_sz);
852 #endif
853 }
854 #else
app_max_size(struct boot_loader_state * state)855 int app_max_size(struct boot_loader_state *state)
856 {
857     const struct flash_area *fap;
858     int fa_id;
859     int rc;
860     uint32_t active_slot;
861     int primary_sz, secondary_sz;
862 
863     active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot;
864 
865     fa_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), active_slot);
866     rc = flash_area_open(fa_id, &fap);
867     assert(rc == 0);
868     primary_sz = flash_area_get_size(fap);
869     flash_area_close(fap);
870 
871     if (active_slot == BOOT_PRIMARY_SLOT) {
872         active_slot = BOOT_SECONDARY_SLOT;
873     } else {
874         active_slot = BOOT_PRIMARY_SLOT;
875     }
876 
877     fa_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), active_slot);
878     rc = flash_area_open(fa_id, &fap);
879     assert(rc == 0);
880     secondary_sz = flash_area_get_size(fap);
881     flash_area_close(fap);
882 
883     return (secondary_sz < primary_sz ? secondary_sz : primary_sz);
884 }
885 
886 #endif /* !MCUBOOT_DIRECT_XIP && !MCUBOOT_RAM_LOAD */
887 
888 int
boot_read_image_header(struct boot_loader_state * state,int slot,struct image_header * out_hdr,struct boot_status * bs)889 boot_read_image_header(struct boot_loader_state *state, int slot,
890                        struct image_header *out_hdr, struct boot_status *bs)
891 {
892     const struct flash_area *fap;
893 #ifdef MCUBOOT_SWAP_USING_SCRATCH
894     uint32_t swap_count;
895     uint32_t swap_size;
896 #endif
897     int area_id;
898     int hdr_slot;
899     int rc = 0;
900 
901 #ifndef MCUBOOT_SWAP_USING_SCRATCH
902     (void)bs;
903 #endif
904 
905 #if (BOOT_IMAGE_NUMBER == 1)
906     (void)state;
907 #endif
908 
909     hdr_slot = slot;
910 
911 #ifdef MCUBOOT_SWAP_USING_SCRATCH
912     /* If the slots are being swapped, the headers might have been moved to scratch area or to the
913      * other slot depending on the progress of the swap process.
914      */
915     if (bs && !boot_status_is_reset(bs)) {
916         rc = boot_find_status(BOOT_CURR_IMG(state), &fap);
917 
918         if (rc != 0) {
919             rc = BOOT_EFLASH;
920             goto done;
921         }
922 
923         rc = boot_read_swap_size(fap, &swap_size);
924         flash_area_close(fap);
925 
926         if (rc != 0) {
927             rc = BOOT_EFLASH;
928             goto done;
929         }
930 
931         swap_count = find_swap_count(state, swap_size);
932 
933         if (bs->idx - BOOT_STATUS_IDX_0 >= swap_count) {
934             /* If all segments have been swapped, the header is located in the other slot */
935             hdr_slot = (slot == BOOT_PRIMARY_SLOT) ? BOOT_SECONDARY_SLOT : BOOT_PRIMARY_SLOT;
936         } else if (bs->idx - BOOT_STATUS_IDX_0 == swap_count - 1) {
937             /* If the last swap operation is in progress, the headers are currently being swapped
938              * since the first segment of each slot is the last to be processed.
939              */
940 
941             if (slot == BOOT_SECONDARY_SLOT && bs->state >= BOOT_STATUS_STATE_1) {
942                 /* After BOOT_STATUS_STATE_1, the secondary image's header has been moved to the
943                  * scratch area.
944                  */
945                 hdr_slot = BOOT_NUM_SLOTS;
946             } else if (slot == BOOT_PRIMARY_SLOT && bs->state >= BOOT_STATUS_STATE_2) {
947                 /* After BOOT_STATUS_STATE_2, the primary image's header has been moved to the
948                  * secondary slot.
949                  */
950                 hdr_slot = BOOT_SECONDARY_SLOT;
951             }
952         }
953     }
954 
955     if (hdr_slot == BOOT_NUM_SLOTS) {
956         area_id = FLASH_AREA_IMAGE_SCRATCH;
957     } else {
958         area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), hdr_slot);
959     }
960 #else
961     area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), hdr_slot);
962 #endif
963 
964     rc = flash_area_open(area_id, &fap);
965     if (rc == 0) {
966         rc = flash_area_read(fap, 0, out_hdr, sizeof *out_hdr);
967         flash_area_close(fap);
968     }
969 
970     if (rc != 0) {
971         rc = BOOT_EFLASH;
972         goto done;
973     }
974 
975 done:
976     return rc;
977 }
978 
979 #endif /* !MCUBOOT_SWAP_USING_MOVE */
980