blob: edab6bb65f7711b5061a69bfc16059e5ae180788 [file] [log] [blame]
Tamas Banf70ef8c2017-12-19 15:35:09 +00001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. 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,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
Tamas Ban581034a2017-12-19 19:54:37 +000020/*
Tamas Ban4fb8e9d2018-02-23 14:22:03 +000021 * Original code taken from mcuboot project at:
22 * https://github.com/runtimeco/mcuboot
23 * Modifications are Copyright (c) 2018 Arm Limited.
Tamas Ban581034a2017-12-19 19:54:37 +000024 */
25
Tamas Banf70ef8c2017-12-19 15:35:09 +000026/**
27 * This file provides an interface to the boot loader. Functions defined in
28 * this file should only be called while the boot loader is running.
29 */
30
31#include <assert.h>
32#include <stddef.h>
33#include <stdbool.h>
34#include <inttypes.h>
35#include <stdlib.h>
36#include <string.h>
Tamas Banc3828852018-02-01 12:24:16 +000037#include "flash_map/flash_map.h"
Tamas Banf70ef8c2017-12-19 15:35:09 +000038#include "bootutil/bootutil.h"
39#include "bootutil/image.h"
40#include "bootutil_priv.h"
41
42#define BOOT_LOG_LEVEL BOOT_LOG_LEVEL_INFO
43#include "bootutil/bootutil_log.h"
44
Tamas Banf70ef8c2017-12-19 15:35:09 +000045static struct boot_loader_state boot_data;
46
Tamas Ban4fb8e9d2018-02-23 14:22:03 +000047#ifndef MCUBOOT_NO_SWAP
Tamas Banf70ef8c2017-12-19 15:35:09 +000048struct boot_status_table {
49 /**
50 * For each field, a value of 0 means "any".
51 */
52 uint8_t bst_magic_slot0;
53 uint8_t bst_magic_scratch;
54 uint8_t bst_copy_done_slot0;
55 uint8_t bst_status_source;
56};
57
58/**
59 * This set of tables maps swap state contents to boot status location.
60 * When searching for a match, these tables must be iterated in order.
61 */
62static const struct boot_status_table boot_status_tables[] = {
63 {
64 /* | slot-0 | scratch |
65 * ----------+------------+------------|
66 * magic | Good | Any |
67 * copy-done | 0x01 | N/A |
68 * ----------+------------+------------'
69 * source: none |
70 * ------------------------------------'
71 */
72 .bst_magic_slot0 = BOOT_MAGIC_GOOD,
73 .bst_magic_scratch = 0,
74 .bst_copy_done_slot0 = 0x01,
75 .bst_status_source = BOOT_STATUS_SOURCE_NONE,
76 },
77
78 {
79 /* | slot-0 | scratch |
80 * ----------+------------+------------|
81 * magic | Good | Any |
82 * copy-done | 0xff | N/A |
83 * ----------+------------+------------'
84 * source: slot 0 |
85 * ------------------------------------'
86 */
87 .bst_magic_slot0 = BOOT_MAGIC_GOOD,
88 .bst_magic_scratch = 0,
89 .bst_copy_done_slot0 = 0xff,
90 .bst_status_source = BOOT_STATUS_SOURCE_SLOT0,
91 },
92
93 {
94 /* | slot-0 | scratch |
95 * ----------+------------+------------|
96 * magic | Any | Good |
97 * copy-done | Any | N/A |
98 * ----------+------------+------------'
99 * source: scratch |
100 * ------------------------------------'
101 */
102 .bst_magic_slot0 = 0,
103 .bst_magic_scratch = BOOT_MAGIC_GOOD,
104 .bst_copy_done_slot0 = 0,
105 .bst_status_source = BOOT_STATUS_SOURCE_SCRATCH,
106 },
107
108 {
109 /* | slot-0 | scratch |
110 * ----------+------------+------------|
111 * magic | Unset | Any |
112 * copy-done | 0xff | N/A |
113 * ----------+------------+------------|
114 * source: varies |
115 * ------------------------------------+------------------------------+
116 * This represents one of two cases: |
117 * o No swaps ever (no status to read, so no harm in checking). |
118 * o Mid-revert; status in slot 0. |
119 * -------------------------------------------------------------------'
120 */
121 .bst_magic_slot0 = BOOT_MAGIC_UNSET,
122 .bst_magic_scratch = 0,
123 .bst_copy_done_slot0 = 0xff,
124 .bst_status_source = BOOT_STATUS_SOURCE_SLOT0,
125 },
126};
127
128#define BOOT_STATUS_TABLES_COUNT \
Tamas Ban581034a2017-12-19 19:54:37 +0000129 (sizeof(boot_status_tables) / sizeof(boot_status_tables[0]))
Tamas Banf70ef8c2017-12-19 15:35:09 +0000130
131#define BOOT_LOG_SWAP_STATE(area, state) \
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000132 BOOT_LOG_INF("%s: magic=%5s, copy_done=0x%x, image_ok=0x%x", \
Tamas Banf70ef8c2017-12-19 15:35:09 +0000133 (area), \
134 ((state)->magic == BOOT_MAGIC_GOOD ? "good" : \
135 (state)->magic == BOOT_MAGIC_UNSET ? "unset" : \
136 "bad"), \
137 (state)->copy_done, \
138 (state)->image_ok)
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000139#endif /* !MCUBOOT_NO_SWAP */
Tamas Banf70ef8c2017-12-19 15:35:09 +0000140
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000141
142static int
143boot_read_image_header(int slot, struct image_header *out_hdr)
144{
145 const struct flash_area *fap = NULL;
146 int area_id;
147 int rc;
148
149 area_id = flash_area_id_from_image_slot(slot);
150 rc = flash_area_open(area_id, &fap);
151 if (rc != 0) {
152 rc = BOOT_EFLASH;
153 goto done;
154 }
155
156 rc = flash_area_read(fap, 0, out_hdr, sizeof(*out_hdr));
157 if (rc != 0) {
158 rc = BOOT_EFLASH;
159 goto done;
160 }
161
162 rc = 0;
163
164done:
165 flash_area_close(fap);
166 return rc;
167}
168
169static int
170boot_read_image_headers(void)
171{
172 int rc;
173 int i;
174
175 for (i = 0; i < BOOT_NUM_SLOTS; i++) {
176 rc = boot_read_image_header(i, boot_img_hdr(&boot_data, i));
177 if (rc != 0) {
178 /* If at least the first slot's header was read successfully, then
179 * the boot loader can attempt a boot. Failure to read any headers
180 * is a fatal error.
181 */
182 if (i > 0) {
183 return 0;
184 } else {
185 return rc;
186 }
187 }
188 }
189
190 return 0;
191}
192
193static uint8_t
194boot_write_sz(void)
195{
196 const struct flash_area *fap;
197 uint8_t elem_sz;
198 uint8_t align;
199 int rc;
200
201 /* Figure out what size to write update status update as. The size depends
202 * on what the minimum write size is for scratch area, active image slot.
203 * We need to use the bigger of those 2 values.
204 */
205 rc = flash_area_open(FLASH_AREA_IMAGE_0, &fap);
206 assert(rc == 0);
207 elem_sz = flash_area_align(fap);
208 flash_area_close(fap);
209
210 rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH, &fap);
211 assert(rc == 0);
212 align = flash_area_align(fap);
213 flash_area_close(fap);
214
215 if (align > elem_sz) {
216 elem_sz = align;
217 }
218
219 return elem_sz;
220}
221
222/**
223 * Determines the sector layout of both image slots and the scratch area.
224 * This information is necessary for calculating the number of bytes to erase
225 * and copy during an image swap. The information collected during this
226 * function is used to populate the boot_data global.
227 */
228static int
229boot_read_sectors(void)
230{
231 int rc;
232
233 rc = boot_initialize_area(&boot_data, FLASH_AREA_IMAGE_0);
234 if (rc != 0) {
235 return BOOT_EFLASH;
236 }
237
238 rc = boot_initialize_area(&boot_data, FLASH_AREA_IMAGE_1);
239 if (rc != 0) {
240 return BOOT_EFLASH;
241 }
242
243 BOOT_WRITE_SZ(&boot_data) = boot_write_sz();
244
245 return 0;
246}
247
248/*
249 * Validate image hash/signature in a slot.
250 */
251static int
252boot_image_check(struct image_header *hdr, const struct flash_area *fap)
253{
254 static uint8_t tmpbuf[BOOT_TMPBUF_SZ];
255
256 if (bootutil_img_validate(hdr, fap, tmpbuf, BOOT_TMPBUF_SZ,
257 NULL, 0, NULL)) {
258 return BOOT_EBADIMAGE;
259 }
260 return 0;
261}
262
263static int
264boot_validate_slot(int slot)
265{
266 const struct flash_area *fap;
267 struct image_header *hdr;
268 int rc;
269
270 hdr = boot_img_hdr(&boot_data, slot);
271 if (hdr->ih_magic == 0xffffffff || hdr->ih_flags & IMAGE_F_NON_BOOTABLE) {
272 /* No bootable image in slot; continue booting from slot 0. */
273 return -1;
274 }
275
276 rc = flash_area_open(flash_area_id_from_image_slot(slot), &fap);
277 if (rc != 0) {
278 return BOOT_EFLASH;
279 }
280
281 if ((hdr->ih_magic != IMAGE_MAGIC || boot_image_check(hdr, fap) != 0)) {
282 if (slot != 0) {
283 flash_area_erase(fap, 0, fap->fa_size);
284 /* Image in slot 1 is invalid. Erase the image and
285 * continue booting from slot 0.
286 */
287 }
288 BOOT_LOG_ERR("Authentication failed! Image in slot %d is not valid.",
289 slot);
290 return -1;
291 }
292
293 flash_area_close(fap);
294
295 /* Image in slot 1 is valid. */
296 return 0;
297}
298
299/**
300 * Erases a region of flash.
301 *
302 * @param flash_area_idx The ID of the flash area containing the region
303 * to erase.
304 * @param off The offset within the flash area to start the
305 * erase.
306 * @param sz The number of bytes to erase.
307 *
308 * @return 0 on success; nonzero on failure.
309 */
310static int
311boot_erase_sector(int flash_area_id, uint32_t off, uint32_t sz)
312{
313 const struct flash_area *fap = NULL;
314 int rc;
315
316 rc = flash_area_open(flash_area_id, &fap);
317 if (rc != 0) {
318 rc = BOOT_EFLASH;
319 goto done;
320 }
321
322 rc = flash_area_erase(fap, off, sz);
323 if (rc != 0) {
324 rc = BOOT_EFLASH;
325 goto done;
326 }
327
328 rc = 0;
329
330done:
331 flash_area_close(fap);
332 return rc;
333}
334
335#ifndef MCUBOOT_OVERWRITE_ONLY
336static int
337boot_erase_last_sector_by_id(int flash_area_id)
338{
339 uint8_t slot;
340 uint32_t last_sector;
341 int rc;
342
343 switch (flash_area_id) {
344 case FLASH_AREA_IMAGE_0:
345 slot = 0;
346 break;
347 case FLASH_AREA_IMAGE_1:
348 slot = 1;
349 break;
350 default:
351 return BOOT_EFLASH;
352 }
353
354 last_sector = boot_img_num_sectors(&boot_data, slot) - 1;
355 rc = boot_erase_sector(flash_area_id,
356 boot_img_sector_off(&boot_data, slot, last_sector),
357 boot_img_sector_size(&boot_data, slot, last_sector));
358 assert(rc == 0);
359
360 return rc;
361}
362#endif /* !MCUBOOT_OVERWRITE_ONLY */
363
364#ifndef MCUBOOT_NO_SWAP
Tamas Banf70ef8c2017-12-19 15:35:09 +0000365/**
Tamas Ban581034a2017-12-19 19:54:37 +0000366 * Determines where in flash the most recent boot status is stored. The boot
Tamas Banf70ef8c2017-12-19 15:35:09 +0000367 * status is necessary for completing a swap that was interrupted by a boot
368 * loader reset.
369 *
Tamas Ban581034a2017-12-19 19:54:37 +0000370 * @return BOOT_STATUS_SOURCE_[...] code indicating where
371 * status should be read from.
Tamas Banf70ef8c2017-12-19 15:35:09 +0000372 */
373static int
374boot_status_source(void)
375{
376 const struct boot_status_table *table;
377 struct boot_swap_state state_scratch;
378 struct boot_swap_state state_slot0;
379 int rc;
380 int i;
381 uint8_t source;
382
383 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_0, &state_slot0);
384 assert(rc == 0);
385
386 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SCRATCH, &state_scratch);
387 assert(rc == 0);
388
389 BOOT_LOG_SWAP_STATE("Image 0", &state_slot0);
390 BOOT_LOG_SWAP_STATE("Scratch", &state_scratch);
391
392 for (i = 0; i < BOOT_STATUS_TABLES_COUNT; i++) {
393 table = &boot_status_tables[i];
394
395 if ((table->bst_magic_slot0 == 0 ||
396 table->bst_magic_slot0 == state_slot0.magic) &&
397 (table->bst_magic_scratch == 0 ||
398 table->bst_magic_scratch == state_scratch.magic) &&
399 (table->bst_copy_done_slot0 == 0 ||
400 table->bst_copy_done_slot0 == state_slot0.copy_done)) {
401 source = table->bst_status_source;
402 BOOT_LOG_INF("Boot source: %s",
403 source == BOOT_STATUS_SOURCE_NONE ? "none" :
404 source == BOOT_STATUS_SOURCE_SCRATCH ? "scratch" :
405 source == BOOT_STATUS_SOURCE_SLOT0 ? "slot 0" :
406 "BUG; can't happen");
407 return source;
408 }
409 }
410
411 BOOT_LOG_INF("Boot source: none");
412 return BOOT_STATUS_SOURCE_NONE;
413}
414
415/**
416 * Calculates the type of swap that just completed.
417 *
418 * This is used when a swap is interrupted by an external event. After
419 * finishing the swap operation determines what the initial request was.
420 */
421static int
422boot_previous_swap_type(void)
423{
424 int post_swap_type;
425
426 post_swap_type = boot_swap_type();
427
428 switch (post_swap_type) {
Tamas Ban581034a2017-12-19 19:54:37 +0000429 case BOOT_SWAP_TYPE_NONE: return BOOT_SWAP_TYPE_PERM;
430 case BOOT_SWAP_TYPE_REVERT: return BOOT_SWAP_TYPE_TEST;
431 case BOOT_SWAP_TYPE_PANIC: return BOOT_SWAP_TYPE_PANIC;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000432 }
433
434 return BOOT_SWAP_TYPE_FAIL;
435}
436
437/*
438 * Compute the total size of the given image. Includes the size of
439 * the TLVs.
440 */
441#ifndef MCUBOOT_OVERWRITE_ONLY
442static int
443boot_read_image_size(int slot, struct image_header *hdr, uint32_t *size)
444{
Tamas Ban581034a2017-12-19 19:54:37 +0000445 const struct flash_area *fap = NULL;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000446 struct image_tlv_info info;
447 int area_id;
448 int rc;
449
450 area_id = flash_area_id_from_image_slot(slot);
451 rc = flash_area_open(area_id, &fap);
452 if (rc != 0) {
453 rc = BOOT_EFLASH;
454 goto done;
455 }
456
457 rc = flash_area_read(fap, hdr->ih_hdr_size + hdr->ih_img_size,
458 &info, sizeof(info));
459 if (rc != 0) {
460 rc = BOOT_EFLASH;
461 goto done;
462 }
463 if (info.it_magic != IMAGE_TLV_INFO_MAGIC) {
464 rc = BOOT_EBADIMAGE;
465 goto done;
466 }
467 *size = hdr->ih_hdr_size + hdr->ih_img_size + info.it_tlv_tot;
468 rc = 0;
469
470done:
471 flash_area_close(fap);
472 return rc;
473}
474#endif /* !MCUBOOT_OVERWRITE_ONLY */
475
476static int
Tamas Banf70ef8c2017-12-19 15:35:09 +0000477boot_slots_compatible(void)
478{
479 size_t num_sectors_0 = boot_img_num_sectors(&boot_data, 0);
480 size_t num_sectors_1 = boot_img_num_sectors(&boot_data, 1);
481 size_t size_0, size_1;
482 size_t i;
483
484 /* Ensure both image slots have identical sector layouts. */
485 if (num_sectors_0 != num_sectors_1) {
486 return 0;
487 }
488 for (i = 0; i < num_sectors_0; i++) {
489 size_0 = boot_img_sector_size(&boot_data, 0, i);
490 size_1 = boot_img_sector_size(&boot_data, 1, i);
491 if (size_0 != size_1) {
492 return 0;
493 }
494 }
495
496 return 1;
497}
498
Tamas Banf70ef8c2017-12-19 15:35:09 +0000499
500static uint32_t
501boot_status_internal_off(int idx, int state, int elem_sz)
502{
503 int idx_sz;
504
505 idx_sz = elem_sz * BOOT_STATUS_STATE_COUNT;
506
507 return idx * idx_sz + state * elem_sz;
508}
509
510/**
511 * Reads the status of a partially-completed swap, if any. This is necessary
512 * to recover in case the boot lodaer was reset in the middle of a swap
513 * operation.
514 */
515static int
516boot_read_status_bytes(const struct flash_area *fap, struct boot_status *bs)
517{
518 uint32_t off;
519 uint8_t status;
520 int max_entries;
521 int found;
522 int rc;
523 int i;
524
525 off = boot_status_off(fap);
526 max_entries = boot_status_entries(fap);
527
528 found = 0;
529 for (i = 0; i < max_entries; i++) {
530 rc = flash_area_read(fap, off + i * BOOT_WRITE_SZ(&boot_data),
531 &status, 1);
532 if (rc != 0) {
533 return BOOT_EFLASH;
534 }
535
536 if (status == 0xff) {
537 if (found) {
538 break;
539 }
540 } else if (!found) {
541 found = 1;
542 }
543 }
544
545 if (found) {
546 i--;
547 bs->idx = i / BOOT_STATUS_STATE_COUNT;
548 bs->state = i % BOOT_STATUS_STATE_COUNT;
549 }
550
551 return 0;
552}
553
554/**
555 * Reads the boot status from the flash. The boot status contains
556 * the current state of an interrupted image copy operation. If the boot
557 * status is not present, or it indicates that previous copy finished,
558 * there is no operation in progress.
559 */
560static int
561boot_read_status(struct boot_status *bs)
562{
563 const struct flash_area *fap;
564 int status_loc;
565 int area_id;
566 int rc;
567
Tamas Ban581034a2017-12-19 19:54:37 +0000568 memset(bs, 0, sizeof(*bs));
Tamas Banf70ef8c2017-12-19 15:35:09 +0000569
570 status_loc = boot_status_source();
571 switch (status_loc) {
572 case BOOT_STATUS_SOURCE_NONE:
573 return 0;
574
575 case BOOT_STATUS_SOURCE_SCRATCH:
576 area_id = FLASH_AREA_IMAGE_SCRATCH;
577 break;
578
579 case BOOT_STATUS_SOURCE_SLOT0:
580 area_id = FLASH_AREA_IMAGE_0;
581 break;
582
583 default:
584 assert(0);
585 return BOOT_EBADARGS;
586 }
587
588 rc = flash_area_open(area_id, &fap);
589 if (rc != 0) {
590 return BOOT_EFLASH;
591 }
592
593 rc = boot_read_status_bytes(fap, bs);
594
595 flash_area_close(fap);
596 return rc;
597}
598
599/**
600 * Writes the supplied boot status to the flash file system. The boot status
601 * contains the current state of an in-progress image copy operation.
602 *
603 * @param bs The boot status to write.
604 *
605 * @return 0 on success; nonzero on failure.
606 */
607int
608boot_write_status(struct boot_status *bs)
609{
Tamas Ban581034a2017-12-19 19:54:37 +0000610 const struct flash_area *fap = NULL;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000611 uint32_t off;
612 int area_id;
613 int rc;
614 uint8_t buf[BOOT_MAX_ALIGN];
615 uint8_t align;
616
617 /* NOTE: The first sector copied (that is the last sector on slot) contains
618 * the trailer. Since in the last step SLOT 0 is erased, the first
619 * two status writes go to the scratch which will be copied to SLOT 0!
620 */
621
622 if (bs->use_scratch) {
623 /* Write to scratch. */
624 area_id = FLASH_AREA_IMAGE_SCRATCH;
625 } else {
626 /* Write to slot 0. */
627 area_id = FLASH_AREA_IMAGE_0;
628 }
629
630 rc = flash_area_open(area_id, &fap);
631 if (rc != 0) {
632 rc = BOOT_EFLASH;
633 goto done;
634 }
635
636 off = boot_status_off(fap) +
637 boot_status_internal_off(bs->idx, bs->state,
638 BOOT_WRITE_SZ(&boot_data));
639
Tamas Banc3828852018-02-01 12:24:16 +0000640 align = flash_area_align(fap);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000641 memset(buf, 0xFF, BOOT_MAX_ALIGN);
642 buf[0] = bs->state;
643
644 rc = flash_area_write(fap, off, buf, align);
645 if (rc != 0) {
646 rc = BOOT_EFLASH;
647 goto done;
648 }
649
650 rc = 0;
651
652done:
653 flash_area_close(fap);
654 return rc;
655}
656
Tamas Banf70ef8c2017-12-19 15:35:09 +0000657/**
658 * Determines which swap operation to perform, if any. If it is determined
659 * that a swap operation is required, the image in the second slot is checked
660 * for validity. If the image in the second slot is invalid, it is erased, and
661 * a swap type of "none" is indicated.
662 *
663 * @return The type of swap to perform (BOOT_SWAP_TYPE...)
664 */
665static int
666boot_validated_swap_type(void)
667{
668 int swap_type;
669
670 swap_type = boot_swap_type();
671 switch (swap_type) {
672 case BOOT_SWAP_TYPE_TEST:
673 case BOOT_SWAP_TYPE_PERM:
674 case BOOT_SWAP_TYPE_REVERT:
675 /* Boot loader wants to switch to slot 1. Ensure image is valid. */
676 if (boot_validate_slot(1) != 0) {
677 swap_type = BOOT_SWAP_TYPE_FAIL;
678 }
679 }
680
681 return swap_type;
682}
683
684/**
685 * Calculates the number of sectors the scratch area can contain. A "last"
686 * source sector is specified because images are copied backwards in flash
687 * (final index to index number 0).
688 *
689 * @param last_sector_idx The index of the last source sector
690 * (inclusive).
691 * @param out_first_sector_idx The index of the first source sector
692 * (inclusive) gets written here.
693 *
694 * @return The number of bytes comprised by the
695 * [first-sector, last-sector] range.
696 */
697#ifndef MCUBOOT_OVERWRITE_ONLY
698static uint32_t
699boot_copy_sz(int last_sector_idx, int *out_first_sector_idx)
700{
701 size_t scratch_sz;
702 uint32_t new_sz;
703 uint32_t sz;
704 int i;
705
706 sz = 0;
707
708 scratch_sz = boot_scratch_area_size(&boot_data);
709 for (i = last_sector_idx; i >= 0; i--) {
710 new_sz = sz + boot_img_sector_size(&boot_data, 0, i);
711 if (new_sz > scratch_sz) {
712 break;
713 }
714 sz = new_sz;
715 }
716
717 /* i currently refers to a sector that doesn't fit or it is -1 because all
718 * sectors have been processed. In both cases, exclude sector i.
719 */
720 *out_first_sector_idx = i + 1;
721 return sz;
722}
723#endif /* !MCUBOOT_OVERWRITE_ONLY */
724
725/**
Tamas Banf70ef8c2017-12-19 15:35:09 +0000726 * Copies the contents of one flash region to another. You must erase the
727 * destination region prior to calling this function.
728 *
729 * @param flash_area_id_src The ID of the source flash area.
730 * @param flash_area_id_dst The ID of the destination flash area.
731 * @param off_src The offset within the source flash area to
732 * copy from.
733 * @param off_dst The offset within the destination flash area to
734 * copy to.
735 * @param sz The number of bytes to copy.
736 *
737 * @return 0 on success; nonzero on failure.
738 */
739static int
740boot_copy_sector(int flash_area_id_src, int flash_area_id_dst,
741 uint32_t off_src, uint32_t off_dst, uint32_t sz)
742{
743 const struct flash_area *fap_src;
744 const struct flash_area *fap_dst;
745 uint32_t bytes_copied;
746 int chunk_sz;
747 int rc;
748
749 static uint8_t buf[1024];
750
751 fap_src = NULL;
752 fap_dst = NULL;
753
754 rc = flash_area_open(flash_area_id_src, &fap_src);
755 if (rc != 0) {
756 rc = BOOT_EFLASH;
757 goto done;
758 }
759
760 rc = flash_area_open(flash_area_id_dst, &fap_dst);
761 if (rc != 0) {
762 rc = BOOT_EFLASH;
763 goto done;
764 }
765
766 bytes_copied = 0;
767 while (bytes_copied < sz) {
Tamas Ban581034a2017-12-19 19:54:37 +0000768 if (sz - bytes_copied > sizeof(buf)) {
769 chunk_sz = sizeof(buf);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000770 } else {
771 chunk_sz = sz - bytes_copied;
772 }
773
774 rc = flash_area_read(fap_src, off_src + bytes_copied, buf, chunk_sz);
775 if (rc != 0) {
776 rc = BOOT_EFLASH;
777 goto done;
778 }
779
780 rc = flash_area_write(fap_dst, off_dst + bytes_copied, buf, chunk_sz);
781 if (rc != 0) {
782 rc = BOOT_EFLASH;
783 goto done;
784 }
785
786 bytes_copied += chunk_sz;
787 }
788
789 rc = 0;
790
791done:
792 if (fap_src) {
793 flash_area_close(fap_src);
794 }
795 if (fap_dst) {
796 flash_area_close(fap_dst);
797 }
798 return rc;
799}
800
801#ifndef MCUBOOT_OVERWRITE_ONLY
802static inline int
803boot_status_init_by_id(int flash_area_id, const struct boot_status *bs)
804{
805 const struct flash_area *fap;
806 struct boot_swap_state swap_state;
807 int rc;
808
809 rc = flash_area_open(flash_area_id, &fap);
810 assert(rc == 0);
811
812 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_1, &swap_state);
813 assert(rc == 0);
814
815 if (swap_state.image_ok == BOOT_FLAG_SET) {
816 rc = boot_write_image_ok(fap);
817 assert(rc == 0);
818 }
819
820 rc = boot_write_swap_size(fap, bs->swap_size);
821 assert(rc == 0);
822
823 rc = boot_write_magic(fap);
824 assert(rc == 0);
825
826 flash_area_close(fap);
827
828 return 0;
829}
830#endif
831
Tamas Banf70ef8c2017-12-19 15:35:09 +0000832/**
833 * Swaps the contents of two flash regions within the two image slots.
834 *
835 * @param idx The index of the first sector in the range of
836 * sectors being swapped.
837 * @param sz The number of bytes to swap.
838 * @param bs The current boot status. This struct gets
839 * updated according to the outcome.
840 *
841 * @return 0 on success; nonzero on failure.
842 */
843#ifndef MCUBOOT_OVERWRITE_ONLY
844static void
845boot_swap_sectors(int idx, uint32_t sz, struct boot_status *bs)
846{
847 const struct flash_area *fap;
848 uint32_t copy_sz;
849 uint32_t trailer_sz;
850 uint32_t img_off;
851 uint32_t scratch_trailer_off;
852 struct boot_swap_state swap_state;
853 size_t last_sector;
854 int rc;
855
856 /* Calculate offset from start of image area. */
857 img_off = boot_img_sector_off(&boot_data, 0, idx);
858
859 copy_sz = sz;
860 trailer_sz = boot_slots_trailer_sz(BOOT_WRITE_SZ(&boot_data));
861
862 /* sz in this function is always is always sized on a multiple of the
863 * sector size. The check against the start offset of the last sector
864 * is to determine if we're swapping the last sector. The last sector
865 * needs special handling because it's where the trailer lives. If we're
866 * copying it, we need to use scratch to write the trailer temporarily.
867 *
868 * NOTE: `use_scratch` is a temporary flag (never written to flash) which
869 * controls if special handling is needed (swapping last sector).
870 */
871 last_sector = boot_img_num_sectors(&boot_data, 0) - 1;
872 if (img_off + sz > boot_img_sector_off(&boot_data, 0, last_sector)) {
873 copy_sz -= trailer_sz;
874 }
875
876 bs->use_scratch = (bs->idx == 0 && copy_sz != sz);
877
878 if (bs->state == 0) {
879 rc = boot_erase_sector(FLASH_AREA_IMAGE_SCRATCH, 0, sz);
880 assert(rc == 0);
881
882 rc = boot_copy_sector(FLASH_AREA_IMAGE_1, FLASH_AREA_IMAGE_SCRATCH,
883 img_off, 0, copy_sz);
884 assert(rc == 0);
885
886 if (bs->idx == 0) {
887 if (bs->use_scratch) {
888 boot_status_init_by_id(FLASH_AREA_IMAGE_SCRATCH, bs);
889 } else {
890 /* Prepare the status area... here it is known that the
891 * last sector is not being used by the image data so it's
892 * safe to erase.
893 */
894 rc = boot_erase_last_sector_by_id(FLASH_AREA_IMAGE_0);
895 assert(rc == 0);
896
897 boot_status_init_by_id(FLASH_AREA_IMAGE_0, bs);
898 }
899 }
900
901 bs->state = 1;
902 rc = boot_write_status(bs);
903 assert(rc == 0);
904 }
905
906 if (bs->state == 1) {
907 rc = boot_erase_sector(FLASH_AREA_IMAGE_1, img_off, sz);
908 assert(rc == 0);
909
910 rc = boot_copy_sector(FLASH_AREA_IMAGE_0, FLASH_AREA_IMAGE_1,
911 img_off, img_off, copy_sz);
912 assert(rc == 0);
913
914 if (bs->idx == 0 && !bs->use_scratch) {
915 /* If not all sectors of the slot are being swapped,
916 * guarantee here that only slot0 will have the state.
917 */
918 rc = boot_erase_last_sector_by_id(FLASH_AREA_IMAGE_1);
919 assert(rc == 0);
920 }
921
922 bs->state = 2;
923 rc = boot_write_status(bs);
924 assert(rc == 0);
925 }
926
927 if (bs->state == 2) {
928 rc = boot_erase_sector(FLASH_AREA_IMAGE_0, img_off, sz);
929 assert(rc == 0);
930
931 /* NOTE: also copy trailer from scratch (has status info) */
932 rc = boot_copy_sector(FLASH_AREA_IMAGE_SCRATCH, FLASH_AREA_IMAGE_0,
933 0, img_off, copy_sz);
934 assert(rc == 0);
935
936 if (bs->use_scratch) {
937 rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH, &fap);
938 assert(rc == 0);
939
940 scratch_trailer_off = boot_status_off(fap);
941
942 flash_area_close(fap);
943
944 rc = flash_area_open(FLASH_AREA_IMAGE_0, &fap);
945 assert(rc == 0);
946
947 /* copy current status that is being maintained in scratch */
948 rc = boot_copy_sector(FLASH_AREA_IMAGE_SCRATCH, FLASH_AREA_IMAGE_0,
949 scratch_trailer_off,
950 img_off + copy_sz,
951 BOOT_STATUS_STATE_COUNT * BOOT_WRITE_SZ(&boot_data));
952 assert(rc == 0);
953
954 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SCRATCH,
955 &swap_state);
956 assert(rc == 0);
957
958 if (swap_state.image_ok == BOOT_FLAG_SET) {
959 rc = boot_write_image_ok(fap);
960 assert(rc == 0);
961 }
962
963 rc = boot_write_swap_size(fap, bs->swap_size);
964 assert(rc == 0);
965
966 rc = boot_write_magic(fap);
967 assert(rc == 0);
968
969 flash_area_close(fap);
970 }
971
972 bs->idx++;
973 bs->state = 0;
974 bs->use_scratch = 0;
975 rc = boot_write_status(bs);
976 assert(rc == 0);
977 }
978}
979#endif /* !MCUBOOT_OVERWRITE_ONLY */
980
981/**
982 * Swaps the two images in flash. If a prior copy operation was interrupted
983 * by a system reset, this function completes that operation.
984 *
985 * @param bs The current boot status. This function reads
986 * this struct to determine if it is resuming
987 * an interrupted swap operation. This
988 * function writes the updated status to this
989 * function on return.
990 *
991 * @return 0 on success; nonzero on failure.
992 */
993#ifdef MCUBOOT_OVERWRITE_ONLY
994static int
995boot_copy_image(struct boot_status *bs)
996{
997 size_t sect_count;
998 size_t sect;
999 int rc;
1000 size_t size = 0;
1001 size_t this_size;
1002
1003 BOOT_LOG_INF("Image upgrade slot1 -> slot0");
1004 BOOT_LOG_INF("Erasing slot0");
1005
1006 sect_count = boot_img_num_sectors(&boot_data, 0);
1007 for (sect = 0; sect < sect_count; sect++) {
1008 this_size = boot_img_sector_size(&boot_data, 0, sect);
1009 rc = boot_erase_sector(FLASH_AREA_IMAGE_0,
1010 size,
1011 this_size);
1012 assert(rc == 0);
1013
1014 size += this_size;
1015 }
1016
1017 BOOT_LOG_INF("Copying slot 1 to slot 0: 0x%lx bytes", size);
1018 rc = boot_copy_sector(FLASH_AREA_IMAGE_1, FLASH_AREA_IMAGE_0,
1019 0, 0, size);
1020
1021 /* Erase slot 1 so that we don't do the upgrade on every boot.
1022 * TODO: Perhaps verify slot 0's signature again? */
1023 rc = boot_erase_sector(FLASH_AREA_IMAGE_1,
1024 0, boot_img_sector_size(&boot_data, 1, 0));
1025 assert(rc == 0);
1026
1027 return 0;
1028}
1029#else
1030static int
1031boot_copy_image(struct boot_status *bs)
1032{
1033 uint32_t sz;
1034 int first_sector_idx;
1035 int last_sector_idx;
1036 int swap_idx;
1037 struct image_header *hdr;
1038 uint32_t size;
1039 uint32_t copy_size;
1040 int rc;
1041
1042 /* FIXME: just do this if asked by user? */
1043
1044 size = copy_size = 0;
1045
1046 if (bs->idx == 0 && bs->state == 0) {
1047 /*
1048 * No swap ever happened, so need to find the largest image which
1049 * will be used to determine the amount of sectors to swap.
1050 */
1051 hdr = boot_img_hdr(&boot_data, 0);
1052 if (hdr->ih_magic == IMAGE_MAGIC) {
1053 rc = boot_read_image_size(0, hdr, &copy_size);
1054 assert(rc == 0);
1055 }
1056
1057 hdr = boot_img_hdr(&boot_data, 1);
1058 if (hdr->ih_magic == IMAGE_MAGIC) {
1059 rc = boot_read_image_size(1, hdr, &size);
1060 assert(rc == 0);
1061 }
1062
1063 if (size > copy_size) {
1064 copy_size = size;
1065 }
1066
1067 bs->swap_size = copy_size;
1068 } else {
1069 /*
1070 * If a swap was under way, the swap_size should already be present
1071 * in the trailer...
1072 */
1073 rc = boot_read_swap_size(&bs->swap_size);
1074 assert(rc == 0);
1075
1076 copy_size = bs->swap_size;
1077 }
1078
1079 size = 0;
1080 last_sector_idx = 0;
1081 while (1) {
1082 size += boot_img_sector_size(&boot_data, 0, last_sector_idx);
1083 if (size >= copy_size) {
1084 break;
1085 }
1086 last_sector_idx++;
1087 }
1088
1089 swap_idx = 0;
1090 while (last_sector_idx >= 0) {
1091 sz = boot_copy_sz(last_sector_idx, &first_sector_idx);
1092 if (swap_idx >= bs->idx) {
1093 boot_swap_sectors(first_sector_idx, sz, bs);
1094 }
1095
1096 last_sector_idx = first_sector_idx - 1;
1097 swap_idx++;
1098 }
1099
1100 return 0;
1101}
1102#endif
1103
1104/**
1105 * Marks the image in slot 0 as fully copied.
1106 */
1107#ifndef MCUBOOT_OVERWRITE_ONLY
1108static int
1109boot_set_copy_done(void)
1110{
1111 const struct flash_area *fap;
1112 int rc;
1113
1114 rc = flash_area_open(FLASH_AREA_IMAGE_0, &fap);
1115 if (rc != 0) {
1116 return BOOT_EFLASH;
1117 }
1118
1119 rc = boot_write_copy_done(fap);
1120 flash_area_close(fap);
1121 return rc;
1122}
1123#endif /* !MCUBOOT_OVERWRITE_ONLY */
1124
1125/**
1126 * Marks a reverted image in slot 0 as confirmed. This is necessary to ensure
1127 * the status bytes from the image revert operation don't get processed on a
1128 * subsequent boot.
1129 *
1130 * NOTE: image_ok is tested before writing because if there's a valid permanent
1131 * image installed on slot0 and the new image to be upgrade to has a bad sig,
1132 * image_ok would be overwritten.
1133 */
1134#ifndef MCUBOOT_OVERWRITE_ONLY
1135static int
1136boot_set_image_ok(void)
1137{
1138 const struct flash_area *fap;
1139 struct boot_swap_state state;
1140 int rc;
1141
1142 rc = flash_area_open(FLASH_AREA_IMAGE_0, &fap);
1143 if (rc != 0) {
1144 return BOOT_EFLASH;
1145 }
1146
1147 rc = boot_read_swap_state(fap, &state);
1148 if (rc != 0) {
1149 rc = BOOT_EFLASH;
1150 goto out;
1151 }
1152
1153 if (state.image_ok == BOOT_FLAG_UNSET) {
1154 rc = boot_write_image_ok(fap);
1155 }
1156
1157out:
1158 flash_area_close(fap);
1159 return rc;
1160}
1161#endif /* !MCUBOOT_OVERWRITE_ONLY */
1162
1163/**
1164 * Performs an image swap if one is required.
1165 *
1166 * @param out_swap_type On success, the type of swap performed gets
1167 * written here.
1168 *
1169 * @return 0 on success; nonzero on failure.
1170 */
1171static int
1172boot_swap_if_needed(int *out_swap_type)
1173{
1174 struct boot_status bs;
1175 int swap_type;
1176 int rc;
1177
1178 /* Determine if we rebooted in the middle of an image swap
1179 * operation.
1180 */
1181 rc = boot_read_status(&bs);
1182 assert(rc == 0);
1183 if (rc != 0) {
1184 return rc;
1185 }
1186
1187 /* If a partial swap was detected, complete it. */
1188 if (bs.idx != 0 || bs.state != 0) {
1189 rc = boot_copy_image(&bs);
1190 assert(rc == 0);
1191
1192 /* NOTE: here we have finished a swap resume. The initial request
1193 * was either a TEST or PERM swap, which now after the completed
1194 * swap will be determined to be respectively REVERT (was TEST)
1195 * or NONE (was PERM).
1196 */
1197
1198 /* Extrapolate the type of the partial swap. We need this
1199 * information to know how to mark the swap complete in flash.
1200 */
1201 swap_type = boot_previous_swap_type();
1202 } else {
1203 swap_type = boot_validated_swap_type();
1204 switch (swap_type) {
1205 case BOOT_SWAP_TYPE_TEST:
1206 case BOOT_SWAP_TYPE_PERM:
1207 case BOOT_SWAP_TYPE_REVERT:
1208 rc = boot_copy_image(&bs);
1209 assert(rc == 0);
1210 break;
1211 }
1212 }
1213
1214 *out_swap_type = swap_type;
1215 return 0;
1216}
1217
1218/**
1219 * Prepares the booting process. This function moves images around in flash as
1220 * appropriate, and tells you what address to boot from.
1221 *
1222 * @param rsp On success, indicates how booting should occur.
1223 *
1224 * @return 0 on success; nonzero on failure.
1225 */
1226int
1227boot_go(struct boot_rsp *rsp)
1228{
1229 int swap_type;
1230 size_t slot;
1231 int rc;
1232 int fa_id;
1233 bool reload_headers = false;
1234
1235 /* The array of slot sectors are defined here (as opposed to file scope) so
1236 * that they don't get allocated for non-boot-loader apps. This is
1237 * necessary because the gcc option "-fdata-sections" doesn't seem to have
1238 * any effect in older gcc versions (e.g., 4.8.4).
1239 */
1240 static boot_sector_t slot0_sectors[BOOT_MAX_IMG_SECTORS];
1241 static boot_sector_t slot1_sectors[BOOT_MAX_IMG_SECTORS];
Tamas Ban581034a2017-12-19 19:54:37 +00001242
Tamas Banf70ef8c2017-12-19 15:35:09 +00001243 boot_data.imgs[0].sectors = slot0_sectors;
1244 boot_data.imgs[1].sectors = slot1_sectors;
1245
1246 /* Open boot_data image areas for the duration of this call. */
1247 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
1248 fa_id = flash_area_id_from_image_slot(slot);
1249 rc = flash_area_open(fa_id, &BOOT_IMG_AREA(&boot_data, slot));
1250 assert(rc == 0);
1251 }
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00001252
Tamas Banf70ef8c2017-12-19 15:35:09 +00001253 rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH,
1254 &BOOT_SCRATCH_AREA(&boot_data));
1255 assert(rc == 0);
1256
1257 /* Determine the sector layout of the image slots and scratch area. */
1258 rc = boot_read_sectors();
1259 if (rc != 0) {
1260 goto out;
1261 }
1262
1263 /* Attempt to read an image header from each slot. */
1264 rc = boot_read_image_headers();
1265 if (rc != 0) {
1266 goto out;
1267 }
1268
1269 /* If the image slots aren't compatible, no swap is possible. Just boot
1270 * into slot 0.
1271 */
1272 if (boot_slots_compatible()) {
1273 rc = boot_swap_if_needed(&swap_type);
1274 assert(rc == 0);
1275 if (rc != 0) {
1276 goto out;
1277 }
1278
1279 /*
1280 * The following states need image_ok be explicitly set after the
1281 * swap was finished to avoid a new revert.
1282 */
Tamas Ban581034a2017-12-19 19:54:37 +00001283 if (swap_type == BOOT_SWAP_TYPE_REVERT ||
1284 swap_type == BOOT_SWAP_TYPE_FAIL) {
Tamas Banf70ef8c2017-12-19 15:35:09 +00001285#ifndef MCUBOOT_OVERWRITE_ONLY
1286 rc = boot_set_image_ok();
1287 if (rc != 0) {
1288 swap_type = BOOT_SWAP_TYPE_PANIC;
1289 }
1290#endif /* !MCUBOOT_OVERWRITE_ONLY */
1291 }
1292 } else {
1293 swap_type = BOOT_SWAP_TYPE_NONE;
1294 }
1295
1296 switch (swap_type) {
1297 case BOOT_SWAP_TYPE_NONE:
1298 slot = 0;
1299 break;
1300
1301 case BOOT_SWAP_TYPE_TEST: /* fallthrough */
1302 case BOOT_SWAP_TYPE_PERM: /* fallthrough */
1303 case BOOT_SWAP_TYPE_REVERT:
1304 slot = 1;
1305 reload_headers = true;
1306#ifndef MCUBOOT_OVERWRITE_ONLY
1307 rc = boot_set_copy_done();
1308 if (rc != 0) {
1309 swap_type = BOOT_SWAP_TYPE_PANIC;
1310 }
1311#endif /* !MCUBOOT_OVERWRITE_ONLY */
1312 break;
1313
1314 case BOOT_SWAP_TYPE_FAIL:
1315 /* The image in slot 1 was invalid and is now erased. Ensure we don't
1316 * try to boot into it again on the next reboot. Do this by pretending
1317 * we just reverted back to slot 0.
1318 */
1319 slot = 0;
1320 reload_headers = true;
1321 break;
1322
1323 default:
1324 swap_type = BOOT_SWAP_TYPE_PANIC;
1325 }
1326
1327 if (swap_type == BOOT_SWAP_TYPE_PANIC) {
1328 BOOT_LOG_ERR("panic!");
1329 assert(0);
1330
1331 /* Loop forever... */
Tamas Ban581034a2017-12-19 19:54:37 +00001332 while (1)
1333 ;
Tamas Banf70ef8c2017-12-19 15:35:09 +00001334 }
1335
1336#ifdef MCUBOOT_VALIDATE_SLOT0
1337 if (reload_headers) {
1338 rc = boot_read_image_headers();
1339 if (rc != 0) {
1340 goto out;
1341 }
1342 /* Since headers were reloaded, it can be assumed we just performed a
1343 * swap or overwrite. Now the header info that should be used to
1344 * provide the data for the bootstrap, which previously was at Slot 1,
1345 * was updated to Slot 0.
1346 */
1347 slot = 0;
1348 }
1349
1350 rc = boot_validate_slot(0);
1351 assert(rc == 0);
1352 if (rc != 0) {
1353 rc = BOOT_EBADIMAGE;
1354 goto out;
1355 }
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00001356#else /* MCUBOOT_VALIDATE_SLOT0 */
Tamas Banf70ef8c2017-12-19 15:35:09 +00001357 (void)reload_headers;
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00001358#endif /* MCUBOOT_VALIDATE_SLOT0 */
Tamas Banf70ef8c2017-12-19 15:35:09 +00001359
1360 /* Always boot from the primary slot. */
1361 rsp->br_flash_dev_id = boot_img_fa_device_id(&boot_data, 0);
1362 rsp->br_image_off = boot_img_slot_off(&boot_data, 0);
1363 rsp->br_hdr = boot_img_hdr(&boot_data, slot);
1364
1365 out:
1366 flash_area_close(BOOT_SCRATCH_AREA(&boot_data));
1367 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
1368 flash_area_close(BOOT_IMG_AREA(&boot_data, BOOT_NUM_SLOTS - 1 - slot));
1369 }
1370 return rc;
1371}
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00001372
1373#else /* MCUBOOT_NO_SWAP */
1374
1375#define BOOT_LOG_IMAGE_INFO(area, hdr, state) \
1376 BOOT_LOG_INF("Image %"PRIu32": version=%"PRIu8".%"PRIu8".%"PRIu16"" \
1377 ".%"PRIu32", magic=%5s, image_ok=0x%x", \
1378 (area), \
1379 (hdr)->ih_ver.iv_major, \
1380 (hdr)->ih_ver.iv_minor, \
1381 (hdr)->ih_ver.iv_revision, \
1382 (hdr)->ih_ver.iv_build_num, \
1383 ((state)->magic == BOOT_MAGIC_GOOD ? "good" : \
1384 (state)->magic == BOOT_MAGIC_UNSET ? "unset" : \
1385 "bad"), \
1386 (state)->image_ok)
1387
1388struct image_slot_version {
1389 uint64_t version;
1390 uint32_t slot_number;
1391};
1392
1393/**
1394 * Extract the version number from the image header. This function must be
1395 * ported if version number format has changed in the image header.
1396 *
1397 * @param hdr Pointer to an image header structure
1398 *
1399 * @return Version number casted to unit64_t
1400 */
1401static uint64_t
1402boot_get_version_number(struct image_header *hdr)
1403{
1404 return *((uint64_t *)(&hdr->ih_ver));
1405}
1406
1407/**
1408 * Comparator function for `qsort` to compare version numbers. This function
1409 * must be ported if version number format has changed in the image header.
1410 *
1411 * @param ver1 Pointer to an array element which holds the version number
1412 * @param ver2 Pointer to another array element which holds the version
1413 * number
1414 *
1415 * @return if version1 > version2 -1
1416 * if version1 == version2 0
1417 * if version1 < version2 1
1418 */
1419static int
1420boot_compare_version_numbers(const void *ver1, const void *ver2)
1421{
1422 if (((struct image_slot_version *)ver1)->version <
1423 ((struct image_slot_version *)ver2)->version) {
1424 return 1;
1425 }
1426
1427 if (((struct image_slot_version *)ver1)->version ==
1428 ((struct image_slot_version *)ver2)->version) {
1429 return 0;
1430 }
1431
1432 return -1;
1433}
1434
1435/**
1436 * Sort the available images based on the version number and puts them in
1437 * a list.
1438 *
1439 * @param boot_sequence A pointer to an array, whose aim is to carry
1440 * the boot order of candidate images.
1441 * @param slot_cnt The number of flash areas, which can contains firmware
1442 * images.
1443 *
1444 * @return The number of valid images.
1445 */
1446uint32_t
1447boot_get_boot_sequence(uint32_t *boot_sequence, uint32_t slot_cnt)
1448{
1449 struct boot_swap_state slot_state;
1450 struct image_header *hdr;
1451 struct image_slot_version image_versions[BOOT_NUM_SLOTS] = {{0}};
1452 uint32_t image_cnt = 0;
1453 uint32_t slot;
1454 int32_t rc;
1455 int32_t fa_id;
1456
1457 for (slot = 0; slot < slot_cnt; slot++) {
1458 hdr = boot_img_hdr(&boot_data, slot);
1459 fa_id = flash_area_id_from_image_slot(slot);
1460 rc = boot_read_swap_state_by_id(fa_id, &slot_state);
1461 if (rc != 0) {
1462 BOOT_LOG_ERR("Error during reading image trailer from slot:"
1463 " %"PRIu32"", slot);
1464 continue;
1465 }
1466
1467 if (hdr->ih_magic == IMAGE_MAGIC) {
1468 if (slot_state.magic == BOOT_MAGIC_GOOD ||
1469 slot_state.image_ok == 0x01) {
1470 /* Valid cases:
1471 * - Test mode: magic is OK in image trailer
1472 * - Permanent mode: image_ok flag has previously set
1473 */
1474 image_versions[slot].slot_number = slot;
1475 image_versions[slot].version = boot_get_version_number(hdr);
1476 image_cnt++;
1477 }
1478
1479 if (slot_state.magic == BOOT_MAGIC_GOOD &&
1480 slot_state.image_ok == 0xFF) {
1481 /* Delete trailer in test mode in order to avoid booting it
1482 * again without confirmation by runtime in case of subsequent
1483 * boot.
1484 */
1485 boot_erase_last_sector_by_id(fa_id);
1486 }
1487 BOOT_LOG_IMAGE_INFO(slot, hdr, &slot_state);
1488 } else {
1489 BOOT_LOG_INF("Image %"PRIu32": No valid image", slot);
1490 }
1491 }
1492
1493 /* Sort the images based on version number */
1494 qsort(&image_versions[0],
1495 slot_cnt,
1496 sizeof(struct image_slot_version),
1497 boot_compare_version_numbers);
1498
1499 /* Copy the calculated boot sequence to boot_sequence array */
1500 for (slot = 0; slot < slot_cnt; slot++) {
1501 boot_sequence[slot] = image_versions[slot].slot_number;
1502 }
1503
1504 return image_cnt;
1505}
1506
1507/**
1508 * Prepares the booting process. This function choose the newer image in flash
1509 * as appropriate, and returns the address to boot from.
1510 *
1511 * @param rsp On success, indicates how booting should occur.
1512 *
1513 * @return 0 on success; nonzero on failure.
1514 */
1515int
1516boot_go(struct boot_rsp *rsp)
1517{
1518 size_t slot = 0;
1519 int32_t i;
1520 int rc;
1521 int fa_id;
1522 uint32_t boot_sequence[BOOT_NUM_SLOTS];
1523 uint32_t img_cnt;
1524
1525 static boot_sector_t slot0_sectors[BOOT_MAX_IMG_SECTORS];
1526 static boot_sector_t slot1_sectors[BOOT_MAX_IMG_SECTORS];
1527
1528 boot_data.imgs[0].sectors = &slot0_sectors[0];
1529 boot_data.imgs[1].sectors = &slot1_sectors[0];
1530
1531 /* Open boot_data image areas for the duration of this call. */
1532 for (i = 0; i < BOOT_NUM_SLOTS; i++) {
1533 fa_id = flash_area_id_from_image_slot(i);
1534 rc = flash_area_open(fa_id, &BOOT_IMG_AREA(&boot_data, i));
1535 assert(rc == 0);
1536 }
1537
1538 /* Determine the sector layout of the image slots. */
1539 rc = boot_read_sectors();
1540 if (rc != 0) {
1541 goto out;
1542 }
1543
1544 /* Attempt to read an image header from each slot. */
1545 rc = boot_read_image_headers();
1546 if (rc != 0) {
1547 goto out;
1548 }
1549
1550 img_cnt = boot_get_boot_sequence(boot_sequence, BOOT_NUM_SLOTS);
1551 if (img_cnt) {
1552 /* Authenticate images */
1553 for (i = 0; i < img_cnt; i++) {
1554 rc = boot_validate_slot(boot_sequence[i]);
1555 if (rc == 0) {
1556 slot = boot_sequence[i];
1557 break;
1558 }
1559 }
1560 if (rc) {
1561 /* If there was no valid image at all */
1562 rc = BOOT_EBADIMAGE;
1563 goto out;
1564 }
1565
1566 BOOT_LOG_INF("Booting image from slot %d", slot);
1567 rsp->br_flash_dev_id = boot_img_fa_device_id(&boot_data, slot);
1568 rsp->br_image_off = boot_img_slot_off(&boot_data, slot);
1569 rsp->br_hdr = boot_img_hdr(&boot_data, slot);
1570 } else {
1571 /* No candidate image available */
1572 rc = BOOT_EBADIMAGE;
1573 }
1574
1575out:
1576 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
1577 flash_area_close(BOOT_IMG_AREA(&boot_data, BOOT_NUM_SLOTS - 1 - slot));
1578 }
1579 return rc;
1580}
1581#endif /* MCUBOOT_NO_SWAP */