blob: c268d937b2b5513ccc91b497d69ede1ab564ddf5 [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
Oliver Swedef9982442018-08-24 18:37:44 +010047#if !defined(MCUBOOT_NO_SWAP) && !defined(MCUBOOT_RAM_LOADING)
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)
Oliver Swedef9982442018-08-24 18:37:44 +0100139#endif /* !MCUBOOT_NO_SWAP && !MCUBOOT_RAM_LOADING */
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) {
David Vincze26e8c8a2018-08-28 16:59:41 +0200283 rc = flash_area_erase(fap, 0, fap->fa_size);
284 if(rc != 0) {
285 flash_area_close(fap);
286 return BOOT_EFLASH;
287 }
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000288 /* Image in slot 1 is invalid. Erase the image and
289 * continue booting from slot 0.
290 */
291 }
292 BOOT_LOG_ERR("Authentication failed! Image in slot %d is not valid.",
293 slot);
294 return -1;
295 }
296
297 flash_area_close(fap);
298
299 /* Image in slot 1 is valid. */
300 return 0;
301}
302
Oliver Swedef9982442018-08-24 18:37:44 +0100303#if !defined(MCUBOOT_NO_SWAP) && !defined(MCUBOOT_OVERWRITE_ONLY)
304/*
305 * Compute the total size of the given image. Includes the size of
306 * the TLVs.
307 */
308static int
309boot_read_image_size(int slot, struct image_header *hdr, uint32_t *size)
310{
311 const struct flash_area *fap = NULL;
312 struct image_tlv_info info;
313 int area_id;
314 int rc;
315
316 area_id = flash_area_id_from_image_slot(slot);
317 rc = flash_area_open(area_id, &fap);
318 if (rc != 0) {
319 rc = BOOT_EFLASH;
320 goto done;
321 }
322
323 rc = flash_area_read(fap, hdr->ih_hdr_size + hdr->ih_img_size,
324 &info, sizeof(info));
325 if (rc != 0) {
326 rc = BOOT_EFLASH;
327 goto done;
328 }
329 if (info.it_magic != IMAGE_TLV_INFO_MAGIC) {
330 rc = BOOT_EBADIMAGE;
331 goto done;
332 }
333 *size = hdr->ih_hdr_size + hdr->ih_img_size + info.it_tlv_tot;
334 rc = 0;
335
336done:
337 flash_area_close(fap);
338 return rc;
339}
340#endif /* !MCUBOOT_NO_SWAP && !MCUBOOT_OVERWRITE_ONLY */
341
342#if !defined(MCUBOOT_NO_SWAP) && !defined(MCUBOOT_RAM_LOADING)
Tamas Banf70ef8c2017-12-19 15:35:09 +0000343/**
Tamas Ban581034a2017-12-19 19:54:37 +0000344 * Determines where in flash the most recent boot status is stored. The boot
Tamas Banf70ef8c2017-12-19 15:35:09 +0000345 * status is necessary for completing a swap that was interrupted by a boot
346 * loader reset.
347 *
Tamas Ban581034a2017-12-19 19:54:37 +0000348 * @return BOOT_STATUS_SOURCE_[...] code indicating where
349 * status should be read from.
Tamas Banf70ef8c2017-12-19 15:35:09 +0000350 */
351static int
352boot_status_source(void)
353{
354 const struct boot_status_table *table;
355 struct boot_swap_state state_scratch;
356 struct boot_swap_state state_slot0;
357 int rc;
358 int i;
359 uint8_t source;
360
361 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_0, &state_slot0);
362 assert(rc == 0);
363
364 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SCRATCH, &state_scratch);
365 assert(rc == 0);
366
367 BOOT_LOG_SWAP_STATE("Image 0", &state_slot0);
368 BOOT_LOG_SWAP_STATE("Scratch", &state_scratch);
369
370 for (i = 0; i < BOOT_STATUS_TABLES_COUNT; i++) {
371 table = &boot_status_tables[i];
372
373 if ((table->bst_magic_slot0 == 0 ||
374 table->bst_magic_slot0 == state_slot0.magic) &&
375 (table->bst_magic_scratch == 0 ||
376 table->bst_magic_scratch == state_scratch.magic) &&
377 (table->bst_copy_done_slot0 == 0 ||
378 table->bst_copy_done_slot0 == state_slot0.copy_done)) {
379 source = table->bst_status_source;
380 BOOT_LOG_INF("Boot source: %s",
381 source == BOOT_STATUS_SOURCE_NONE ? "none" :
382 source == BOOT_STATUS_SOURCE_SCRATCH ? "scratch" :
383 source == BOOT_STATUS_SOURCE_SLOT0 ? "slot 0" :
384 "BUG; can't happen");
385 return source;
386 }
387 }
388
389 BOOT_LOG_INF("Boot source: none");
390 return BOOT_STATUS_SOURCE_NONE;
391}
392
393/**
394 * Calculates the type of swap that just completed.
395 *
396 * This is used when a swap is interrupted by an external event. After
397 * finishing the swap operation determines what the initial request was.
398 */
399static int
400boot_previous_swap_type(void)
401{
402 int post_swap_type;
403
404 post_swap_type = boot_swap_type();
405
406 switch (post_swap_type) {
Tamas Ban581034a2017-12-19 19:54:37 +0000407 case BOOT_SWAP_TYPE_NONE: return BOOT_SWAP_TYPE_PERM;
408 case BOOT_SWAP_TYPE_REVERT: return BOOT_SWAP_TYPE_TEST;
409 case BOOT_SWAP_TYPE_PANIC: return BOOT_SWAP_TYPE_PANIC;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000410 }
411
412 return BOOT_SWAP_TYPE_FAIL;
413}
414
Tamas Banf70ef8c2017-12-19 15:35:09 +0000415static int
Tamas Banf70ef8c2017-12-19 15:35:09 +0000416boot_slots_compatible(void)
417{
418 size_t num_sectors_0 = boot_img_num_sectors(&boot_data, 0);
419 size_t num_sectors_1 = boot_img_num_sectors(&boot_data, 1);
420 size_t size_0, size_1;
421 size_t i;
422
423 /* Ensure both image slots have identical sector layouts. */
424 if (num_sectors_0 != num_sectors_1) {
425 return 0;
426 }
427 for (i = 0; i < num_sectors_0; i++) {
428 size_0 = boot_img_sector_size(&boot_data, 0, i);
429 size_1 = boot_img_sector_size(&boot_data, 1, i);
430 if (size_0 != size_1) {
431 return 0;
432 }
433 }
434
435 return 1;
436}
437
Tamas Banf70ef8c2017-12-19 15:35:09 +0000438
439static uint32_t
440boot_status_internal_off(int idx, int state, int elem_sz)
441{
442 int idx_sz;
443
444 idx_sz = elem_sz * BOOT_STATUS_STATE_COUNT;
445
446 return idx * idx_sz + state * elem_sz;
447}
448
449/**
450 * Reads the status of a partially-completed swap, if any. This is necessary
451 * to recover in case the boot lodaer was reset in the middle of a swap
452 * operation.
453 */
454static int
455boot_read_status_bytes(const struct flash_area *fap, struct boot_status *bs)
456{
457 uint32_t off;
458 uint8_t status;
459 int max_entries;
460 int found;
461 int rc;
462 int i;
463
464 off = boot_status_off(fap);
465 max_entries = boot_status_entries(fap);
466
467 found = 0;
468 for (i = 0; i < max_entries; i++) {
469 rc = flash_area_read(fap, off + i * BOOT_WRITE_SZ(&boot_data),
470 &status, 1);
471 if (rc != 0) {
472 return BOOT_EFLASH;
473 }
474
475 if (status == 0xff) {
476 if (found) {
477 break;
478 }
479 } else if (!found) {
480 found = 1;
481 }
482 }
483
484 if (found) {
485 i--;
486 bs->idx = i / BOOT_STATUS_STATE_COUNT;
487 bs->state = i % BOOT_STATUS_STATE_COUNT;
488 }
489
490 return 0;
491}
492
493/**
494 * Reads the boot status from the flash. The boot status contains
495 * the current state of an interrupted image copy operation. If the boot
496 * status is not present, or it indicates that previous copy finished,
497 * there is no operation in progress.
498 */
499static int
500boot_read_status(struct boot_status *bs)
501{
502 const struct flash_area *fap;
503 int status_loc;
504 int area_id;
505 int rc;
506
Tamas Ban581034a2017-12-19 19:54:37 +0000507 memset(bs, 0, sizeof(*bs));
Tamas Banf70ef8c2017-12-19 15:35:09 +0000508
509 status_loc = boot_status_source();
510 switch (status_loc) {
511 case BOOT_STATUS_SOURCE_NONE:
512 return 0;
513
514 case BOOT_STATUS_SOURCE_SCRATCH:
515 area_id = FLASH_AREA_IMAGE_SCRATCH;
516 break;
517
518 case BOOT_STATUS_SOURCE_SLOT0:
519 area_id = FLASH_AREA_IMAGE_0;
520 break;
521
522 default:
523 assert(0);
524 return BOOT_EBADARGS;
525 }
526
527 rc = flash_area_open(area_id, &fap);
528 if (rc != 0) {
529 return BOOT_EFLASH;
530 }
531
532 rc = boot_read_status_bytes(fap, bs);
533
534 flash_area_close(fap);
535 return rc;
536}
537
538/**
539 * Writes the supplied boot status to the flash file system. The boot status
540 * contains the current state of an in-progress image copy operation.
541 *
542 * @param bs The boot status to write.
543 *
544 * @return 0 on success; nonzero on failure.
545 */
546int
547boot_write_status(struct boot_status *bs)
548{
Tamas Ban581034a2017-12-19 19:54:37 +0000549 const struct flash_area *fap = NULL;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000550 uint32_t off;
551 int area_id;
552 int rc;
553 uint8_t buf[BOOT_MAX_ALIGN];
554 uint8_t align;
555
556 /* NOTE: The first sector copied (that is the last sector on slot) contains
557 * the trailer. Since in the last step SLOT 0 is erased, the first
558 * two status writes go to the scratch which will be copied to SLOT 0!
559 */
560
561 if (bs->use_scratch) {
562 /* Write to scratch. */
563 area_id = FLASH_AREA_IMAGE_SCRATCH;
564 } else {
565 /* Write to slot 0. */
566 area_id = FLASH_AREA_IMAGE_0;
567 }
568
569 rc = flash_area_open(area_id, &fap);
570 if (rc != 0) {
571 rc = BOOT_EFLASH;
572 goto done;
573 }
574
575 off = boot_status_off(fap) +
576 boot_status_internal_off(bs->idx, bs->state,
577 BOOT_WRITE_SZ(&boot_data));
578
Tamas Banc3828852018-02-01 12:24:16 +0000579 align = flash_area_align(fap);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000580 memset(buf, 0xFF, BOOT_MAX_ALIGN);
581 buf[0] = bs->state;
582
583 rc = flash_area_write(fap, off, buf, align);
584 if (rc != 0) {
585 rc = BOOT_EFLASH;
586 goto done;
587 }
588
589 rc = 0;
590
591done:
592 flash_area_close(fap);
593 return rc;
594}
595
Tamas Banf70ef8c2017-12-19 15:35:09 +0000596/**
597 * Determines which swap operation to perform, if any. If it is determined
598 * that a swap operation is required, the image in the second slot is checked
599 * for validity. If the image in the second slot is invalid, it is erased, and
600 * a swap type of "none" is indicated.
601 *
602 * @return The type of swap to perform (BOOT_SWAP_TYPE...)
603 */
604static int
605boot_validated_swap_type(void)
606{
607 int swap_type;
608
609 swap_type = boot_swap_type();
610 switch (swap_type) {
611 case BOOT_SWAP_TYPE_TEST:
612 case BOOT_SWAP_TYPE_PERM:
613 case BOOT_SWAP_TYPE_REVERT:
614 /* Boot loader wants to switch to slot 1. Ensure image is valid. */
615 if (boot_validate_slot(1) != 0) {
616 swap_type = BOOT_SWAP_TYPE_FAIL;
617 }
618 }
619
620 return swap_type;
621}
622
623/**
624 * Calculates the number of sectors the scratch area can contain. A "last"
625 * source sector is specified because images are copied backwards in flash
626 * (final index to index number 0).
627 *
628 * @param last_sector_idx The index of the last source sector
629 * (inclusive).
630 * @param out_first_sector_idx The index of the first source sector
631 * (inclusive) gets written here.
632 *
633 * @return The number of bytes comprised by the
634 * [first-sector, last-sector] range.
635 */
636#ifndef MCUBOOT_OVERWRITE_ONLY
637static uint32_t
638boot_copy_sz(int last_sector_idx, int *out_first_sector_idx)
639{
640 size_t scratch_sz;
641 uint32_t new_sz;
642 uint32_t sz;
643 int i;
644
645 sz = 0;
646
647 scratch_sz = boot_scratch_area_size(&boot_data);
648 for (i = last_sector_idx; i >= 0; i--) {
649 new_sz = sz + boot_img_sector_size(&boot_data, 0, i);
650 if (new_sz > scratch_sz) {
651 break;
652 }
653 sz = new_sz;
654 }
655
656 /* i currently refers to a sector that doesn't fit or it is -1 because all
657 * sectors have been processed. In both cases, exclude sector i.
658 */
659 *out_first_sector_idx = i + 1;
660 return sz;
661}
662#endif /* !MCUBOOT_OVERWRITE_ONLY */
663
664/**
David Vinczef7641fa2018-09-04 18:29:46 +0200665 * Erases a region of flash.
666 *
667 * @param flash_area_idx The ID of the flash area containing the region
668 * to erase.
669 * @param off The offset within the flash area to start the
670 * erase.
671 * @param sz The number of bytes to erase.
672 *
673 * @return 0 on success; nonzero on failure.
674 */
675static int
676boot_erase_sector(int flash_area_id, uint32_t off, uint32_t sz)
677{
678 const struct flash_area *fap = NULL;
679 int rc;
680
681 rc = flash_area_open(flash_area_id, &fap);
682 if (rc != 0) {
683 rc = BOOT_EFLASH;
684 goto done;
685 }
686
687 rc = flash_area_erase(fap, off, sz);
688 if (rc != 0) {
689 rc = BOOT_EFLASH;
690 goto done;
691 }
692
693 rc = 0;
694
695done:
696 flash_area_close(fap);
697 return rc;
698}
699
700/**
Tamas Banf70ef8c2017-12-19 15:35:09 +0000701 * Copies the contents of one flash region to another. You must erase the
702 * destination region prior to calling this function.
703 *
704 * @param flash_area_id_src The ID of the source flash area.
705 * @param flash_area_id_dst The ID of the destination flash area.
706 * @param off_src The offset within the source flash area to
707 * copy from.
708 * @param off_dst The offset within the destination flash area to
709 * copy to.
710 * @param sz The number of bytes to copy.
711 *
712 * @return 0 on success; nonzero on failure.
713 */
714static int
715boot_copy_sector(int flash_area_id_src, int flash_area_id_dst,
716 uint32_t off_src, uint32_t off_dst, uint32_t sz)
717{
718 const struct flash_area *fap_src;
719 const struct flash_area *fap_dst;
720 uint32_t bytes_copied;
721 int chunk_sz;
722 int rc;
723
724 static uint8_t buf[1024];
725
726 fap_src = NULL;
727 fap_dst = NULL;
728
729 rc = flash_area_open(flash_area_id_src, &fap_src);
730 if (rc != 0) {
731 rc = BOOT_EFLASH;
732 goto done;
733 }
734
735 rc = flash_area_open(flash_area_id_dst, &fap_dst);
736 if (rc != 0) {
737 rc = BOOT_EFLASH;
738 goto done;
739 }
740
741 bytes_copied = 0;
742 while (bytes_copied < sz) {
Tamas Ban581034a2017-12-19 19:54:37 +0000743 if (sz - bytes_copied > sizeof(buf)) {
744 chunk_sz = sizeof(buf);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000745 } else {
746 chunk_sz = sz - bytes_copied;
747 }
748
749 rc = flash_area_read(fap_src, off_src + bytes_copied, buf, chunk_sz);
750 if (rc != 0) {
751 rc = BOOT_EFLASH;
752 goto done;
753 }
754
755 rc = flash_area_write(fap_dst, off_dst + bytes_copied, buf, chunk_sz);
756 if (rc != 0) {
757 rc = BOOT_EFLASH;
758 goto done;
759 }
760
761 bytes_copied += chunk_sz;
762 }
763
764 rc = 0;
765
766done:
767 if (fap_src) {
768 flash_area_close(fap_src);
769 }
770 if (fap_dst) {
771 flash_area_close(fap_dst);
772 }
773 return rc;
774}
775
776#ifndef MCUBOOT_OVERWRITE_ONLY
777static inline int
778boot_status_init_by_id(int flash_area_id, const struct boot_status *bs)
779{
780 const struct flash_area *fap;
781 struct boot_swap_state swap_state;
782 int rc;
783
784 rc = flash_area_open(flash_area_id, &fap);
785 assert(rc == 0);
786
787 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_1, &swap_state);
788 assert(rc == 0);
789
790 if (swap_state.image_ok == BOOT_FLAG_SET) {
791 rc = boot_write_image_ok(fap);
792 assert(rc == 0);
793 }
794
795 rc = boot_write_swap_size(fap, bs->swap_size);
796 assert(rc == 0);
797
798 rc = boot_write_magic(fap);
799 assert(rc == 0);
800
801 flash_area_close(fap);
802
803 return 0;
804}
David Vinczef7641fa2018-09-04 18:29:46 +0200805
806static int
807boot_erase_last_sector_by_id(int flash_area_id)
808{
809 uint8_t slot;
810 uint32_t last_sector;
811 int rc;
812
813 switch (flash_area_id) {
814 case FLASH_AREA_IMAGE_0:
815 slot = 0;
816 break;
817 case FLASH_AREA_IMAGE_1:
818 slot = 1;
819 break;
820 default:
821 return BOOT_EFLASH;
822 }
823
824 last_sector = boot_img_num_sectors(&boot_data, slot) - 1;
825 rc = boot_erase_sector(flash_area_id,
826 boot_img_sector_off(&boot_data, slot, last_sector),
827 boot_img_sector_size(&boot_data, slot, last_sector));
828 assert(rc == 0);
829
830 return rc;
831}
832#endif /* !MCUBOOT_OVERWRITE_ONLY */
Tamas Banf70ef8c2017-12-19 15:35:09 +0000833
Tamas Banf70ef8c2017-12-19 15:35:09 +0000834/**
835 * Swaps the contents of two flash regions within the two image slots.
836 *
837 * @param idx The index of the first sector in the range of
838 * sectors being swapped.
839 * @param sz The number of bytes to swap.
840 * @param bs The current boot status. This struct gets
841 * updated according to the outcome.
842 *
843 * @return 0 on success; nonzero on failure.
844 */
845#ifndef MCUBOOT_OVERWRITE_ONLY
846static void
847boot_swap_sectors(int idx, uint32_t sz, struct boot_status *bs)
848{
849 const struct flash_area *fap;
850 uint32_t copy_sz;
851 uint32_t trailer_sz;
852 uint32_t img_off;
853 uint32_t scratch_trailer_off;
854 struct boot_swap_state swap_state;
855 size_t last_sector;
856 int rc;
857
858 /* Calculate offset from start of image area. */
859 img_off = boot_img_sector_off(&boot_data, 0, idx);
860
861 copy_sz = sz;
862 trailer_sz = boot_slots_trailer_sz(BOOT_WRITE_SZ(&boot_data));
863
864 /* sz in this function is always is always sized on a multiple of the
865 * sector size. The check against the start offset of the last sector
866 * is to determine if we're swapping the last sector. The last sector
867 * needs special handling because it's where the trailer lives. If we're
868 * copying it, we need to use scratch to write the trailer temporarily.
869 *
870 * NOTE: `use_scratch` is a temporary flag (never written to flash) which
871 * controls if special handling is needed (swapping last sector).
872 */
873 last_sector = boot_img_num_sectors(&boot_data, 0) - 1;
874 if (img_off + sz > boot_img_sector_off(&boot_data, 0, last_sector)) {
875 copy_sz -= trailer_sz;
876 }
877
878 bs->use_scratch = (bs->idx == 0 && copy_sz != sz);
879
880 if (bs->state == 0) {
881 rc = boot_erase_sector(FLASH_AREA_IMAGE_SCRATCH, 0, sz);
882 assert(rc == 0);
883
884 rc = boot_copy_sector(FLASH_AREA_IMAGE_1, FLASH_AREA_IMAGE_SCRATCH,
885 img_off, 0, copy_sz);
886 assert(rc == 0);
887
888 if (bs->idx == 0) {
889 if (bs->use_scratch) {
890 boot_status_init_by_id(FLASH_AREA_IMAGE_SCRATCH, bs);
891 } else {
892 /* Prepare the status area... here it is known that the
893 * last sector is not being used by the image data so it's
894 * safe to erase.
895 */
896 rc = boot_erase_last_sector_by_id(FLASH_AREA_IMAGE_0);
897 assert(rc == 0);
898
899 boot_status_init_by_id(FLASH_AREA_IMAGE_0, bs);
900 }
901 }
902
903 bs->state = 1;
904 rc = boot_write_status(bs);
905 assert(rc == 0);
906 }
907
908 if (bs->state == 1) {
909 rc = boot_erase_sector(FLASH_AREA_IMAGE_1, img_off, sz);
910 assert(rc == 0);
911
912 rc = boot_copy_sector(FLASH_AREA_IMAGE_0, FLASH_AREA_IMAGE_1,
913 img_off, img_off, copy_sz);
914 assert(rc == 0);
915
916 if (bs->idx == 0 && !bs->use_scratch) {
917 /* If not all sectors of the slot are being swapped,
918 * guarantee here that only slot0 will have the state.
919 */
920 rc = boot_erase_last_sector_by_id(FLASH_AREA_IMAGE_1);
921 assert(rc == 0);
922 }
923
924 bs->state = 2;
925 rc = boot_write_status(bs);
926 assert(rc == 0);
927 }
928
929 if (bs->state == 2) {
930 rc = boot_erase_sector(FLASH_AREA_IMAGE_0, img_off, sz);
931 assert(rc == 0);
932
933 /* NOTE: also copy trailer from scratch (has status info) */
934 rc = boot_copy_sector(FLASH_AREA_IMAGE_SCRATCH, FLASH_AREA_IMAGE_0,
935 0, img_off, copy_sz);
936 assert(rc == 0);
937
938 if (bs->use_scratch) {
939 rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH, &fap);
940 assert(rc == 0);
941
942 scratch_trailer_off = boot_status_off(fap);
943
944 flash_area_close(fap);
945
946 rc = flash_area_open(FLASH_AREA_IMAGE_0, &fap);
947 assert(rc == 0);
948
949 /* copy current status that is being maintained in scratch */
950 rc = boot_copy_sector(FLASH_AREA_IMAGE_SCRATCH, FLASH_AREA_IMAGE_0,
951 scratch_trailer_off,
952 img_off + copy_sz,
953 BOOT_STATUS_STATE_COUNT * BOOT_WRITE_SZ(&boot_data));
954 assert(rc == 0);
955
956 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SCRATCH,
957 &swap_state);
958 assert(rc == 0);
959
960 if (swap_state.image_ok == BOOT_FLAG_SET) {
961 rc = boot_write_image_ok(fap);
962 assert(rc == 0);
963 }
964
965 rc = boot_write_swap_size(fap, bs->swap_size);
966 assert(rc == 0);
967
968 rc = boot_write_magic(fap);
969 assert(rc == 0);
970
971 flash_area_close(fap);
972 }
973
974 bs->idx++;
975 bs->state = 0;
976 bs->use_scratch = 0;
977 rc = boot_write_status(bs);
978 assert(rc == 0);
979 }
980}
981#endif /* !MCUBOOT_OVERWRITE_ONLY */
982
983/**
984 * Swaps the two images in flash. If a prior copy operation was interrupted
985 * by a system reset, this function completes that operation.
986 *
987 * @param bs The current boot status. This function reads
988 * this struct to determine if it is resuming
989 * an interrupted swap operation. This
990 * function writes the updated status to this
991 * function on return.
992 *
993 * @return 0 on success; nonzero on failure.
994 */
995#ifdef MCUBOOT_OVERWRITE_ONLY
996static int
997boot_copy_image(struct boot_status *bs)
998{
999 size_t sect_count;
1000 size_t sect;
1001 int rc;
1002 size_t size = 0;
1003 size_t this_size;
1004
1005 BOOT_LOG_INF("Image upgrade slot1 -> slot0");
1006 BOOT_LOG_INF("Erasing slot0");
1007
1008 sect_count = boot_img_num_sectors(&boot_data, 0);
1009 for (sect = 0; sect < sect_count; sect++) {
1010 this_size = boot_img_sector_size(&boot_data, 0, sect);
1011 rc = boot_erase_sector(FLASH_AREA_IMAGE_0,
1012 size,
1013 this_size);
1014 assert(rc == 0);
1015
1016 size += this_size;
1017 }
1018
1019 BOOT_LOG_INF("Copying slot 1 to slot 0: 0x%lx bytes", size);
1020 rc = boot_copy_sector(FLASH_AREA_IMAGE_1, FLASH_AREA_IMAGE_0,
1021 0, 0, size);
1022
1023 /* Erase slot 1 so that we don't do the upgrade on every boot.
1024 * TODO: Perhaps verify slot 0's signature again? */
1025 rc = boot_erase_sector(FLASH_AREA_IMAGE_1,
1026 0, boot_img_sector_size(&boot_data, 1, 0));
1027 assert(rc == 0);
1028
1029 return 0;
1030}
1031#else
1032static int
1033boot_copy_image(struct boot_status *bs)
1034{
1035 uint32_t sz;
1036 int first_sector_idx;
1037 int last_sector_idx;
1038 int swap_idx;
1039 struct image_header *hdr;
1040 uint32_t size;
1041 uint32_t copy_size;
1042 int rc;
1043
1044 /* FIXME: just do this if asked by user? */
1045
1046 size = copy_size = 0;
1047
1048 if (bs->idx == 0 && bs->state == 0) {
1049 /*
1050 * No swap ever happened, so need to find the largest image which
1051 * will be used to determine the amount of sectors to swap.
1052 */
1053 hdr = boot_img_hdr(&boot_data, 0);
1054 if (hdr->ih_magic == IMAGE_MAGIC) {
1055 rc = boot_read_image_size(0, hdr, &copy_size);
1056 assert(rc == 0);
1057 }
1058
1059 hdr = boot_img_hdr(&boot_data, 1);
1060 if (hdr->ih_magic == IMAGE_MAGIC) {
1061 rc = boot_read_image_size(1, hdr, &size);
1062 assert(rc == 0);
1063 }
1064
1065 if (size > copy_size) {
1066 copy_size = size;
1067 }
1068
1069 bs->swap_size = copy_size;
1070 } else {
1071 /*
1072 * If a swap was under way, the swap_size should already be present
1073 * in the trailer...
1074 */
1075 rc = boot_read_swap_size(&bs->swap_size);
1076 assert(rc == 0);
1077
1078 copy_size = bs->swap_size;
1079 }
1080
1081 size = 0;
1082 last_sector_idx = 0;
1083 while (1) {
1084 size += boot_img_sector_size(&boot_data, 0, last_sector_idx);
1085 if (size >= copy_size) {
1086 break;
1087 }
1088 last_sector_idx++;
1089 }
1090
1091 swap_idx = 0;
1092 while (last_sector_idx >= 0) {
1093 sz = boot_copy_sz(last_sector_idx, &first_sector_idx);
1094 if (swap_idx >= bs->idx) {
1095 boot_swap_sectors(first_sector_idx, sz, bs);
1096 }
1097
1098 last_sector_idx = first_sector_idx - 1;
1099 swap_idx++;
1100 }
1101
1102 return 0;
1103}
1104#endif
1105
1106/**
1107 * Marks the image in slot 0 as fully copied.
1108 */
1109#ifndef MCUBOOT_OVERWRITE_ONLY
1110static int
1111boot_set_copy_done(void)
1112{
1113 const struct flash_area *fap;
1114 int rc;
1115
1116 rc = flash_area_open(FLASH_AREA_IMAGE_0, &fap);
1117 if (rc != 0) {
1118 return BOOT_EFLASH;
1119 }
1120
1121 rc = boot_write_copy_done(fap);
1122 flash_area_close(fap);
1123 return rc;
1124}
1125#endif /* !MCUBOOT_OVERWRITE_ONLY */
1126
1127/**
1128 * Marks a reverted image in slot 0 as confirmed. This is necessary to ensure
1129 * the status bytes from the image revert operation don't get processed on a
1130 * subsequent boot.
1131 *
1132 * NOTE: image_ok is tested before writing because if there's a valid permanent
1133 * image installed on slot0 and the new image to be upgrade to has a bad sig,
1134 * image_ok would be overwritten.
1135 */
1136#ifndef MCUBOOT_OVERWRITE_ONLY
1137static int
1138boot_set_image_ok(void)
1139{
1140 const struct flash_area *fap;
1141 struct boot_swap_state state;
1142 int rc;
1143
1144 rc = flash_area_open(FLASH_AREA_IMAGE_0, &fap);
1145 if (rc != 0) {
1146 return BOOT_EFLASH;
1147 }
1148
1149 rc = boot_read_swap_state(fap, &state);
1150 if (rc != 0) {
1151 rc = BOOT_EFLASH;
1152 goto out;
1153 }
1154
1155 if (state.image_ok == BOOT_FLAG_UNSET) {
1156 rc = boot_write_image_ok(fap);
1157 }
1158
1159out:
1160 flash_area_close(fap);
1161 return rc;
1162}
1163#endif /* !MCUBOOT_OVERWRITE_ONLY */
1164
1165/**
1166 * Performs an image swap if one is required.
1167 *
1168 * @param out_swap_type On success, the type of swap performed gets
1169 * written here.
1170 *
1171 * @return 0 on success; nonzero on failure.
1172 */
1173static int
1174boot_swap_if_needed(int *out_swap_type)
1175{
1176 struct boot_status bs;
1177 int swap_type;
1178 int rc;
1179
1180 /* Determine if we rebooted in the middle of an image swap
1181 * operation.
1182 */
1183 rc = boot_read_status(&bs);
1184 assert(rc == 0);
1185 if (rc != 0) {
1186 return rc;
1187 }
1188
1189 /* If a partial swap was detected, complete it. */
1190 if (bs.idx != 0 || bs.state != 0) {
1191 rc = boot_copy_image(&bs);
1192 assert(rc == 0);
1193
1194 /* NOTE: here we have finished a swap resume. The initial request
1195 * was either a TEST or PERM swap, which now after the completed
1196 * swap will be determined to be respectively REVERT (was TEST)
1197 * or NONE (was PERM).
1198 */
1199
1200 /* Extrapolate the type of the partial swap. We need this
1201 * information to know how to mark the swap complete in flash.
1202 */
1203 swap_type = boot_previous_swap_type();
1204 } else {
1205 swap_type = boot_validated_swap_type();
1206 switch (swap_type) {
1207 case BOOT_SWAP_TYPE_TEST:
1208 case BOOT_SWAP_TYPE_PERM:
1209 case BOOT_SWAP_TYPE_REVERT:
1210 rc = boot_copy_image(&bs);
1211 assert(rc == 0);
1212 break;
1213 }
1214 }
1215
1216 *out_swap_type = swap_type;
1217 return 0;
1218}
1219
1220/**
1221 * Prepares the booting process. This function moves images around in flash as
1222 * appropriate, and tells you what address to boot from.
1223 *
1224 * @param rsp On success, indicates how booting should occur.
1225 *
1226 * @return 0 on success; nonzero on failure.
1227 */
1228int
1229boot_go(struct boot_rsp *rsp)
1230{
1231 int swap_type;
1232 size_t slot;
1233 int rc;
1234 int fa_id;
1235 bool reload_headers = false;
1236
1237 /* The array of slot sectors are defined here (as opposed to file scope) so
1238 * that they don't get allocated for non-boot-loader apps. This is
1239 * necessary because the gcc option "-fdata-sections" doesn't seem to have
1240 * any effect in older gcc versions (e.g., 4.8.4).
1241 */
1242 static boot_sector_t slot0_sectors[BOOT_MAX_IMG_SECTORS];
1243 static boot_sector_t slot1_sectors[BOOT_MAX_IMG_SECTORS];
Tamas Ban581034a2017-12-19 19:54:37 +00001244
Tamas Banf70ef8c2017-12-19 15:35:09 +00001245 boot_data.imgs[0].sectors = slot0_sectors;
1246 boot_data.imgs[1].sectors = slot1_sectors;
1247
1248 /* Open boot_data image areas for the duration of this call. */
1249 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
1250 fa_id = flash_area_id_from_image_slot(slot);
1251 rc = flash_area_open(fa_id, &BOOT_IMG_AREA(&boot_data, slot));
1252 assert(rc == 0);
1253 }
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00001254
Tamas Banf70ef8c2017-12-19 15:35:09 +00001255 rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH,
1256 &BOOT_SCRATCH_AREA(&boot_data));
1257 assert(rc == 0);
1258
1259 /* Determine the sector layout of the image slots and scratch area. */
1260 rc = boot_read_sectors();
1261 if (rc != 0) {
1262 goto out;
1263 }
1264
1265 /* Attempt to read an image header from each slot. */
1266 rc = boot_read_image_headers();
1267 if (rc != 0) {
1268 goto out;
1269 }
1270
1271 /* If the image slots aren't compatible, no swap is possible. Just boot
1272 * into slot 0.
1273 */
1274 if (boot_slots_compatible()) {
1275 rc = boot_swap_if_needed(&swap_type);
1276 assert(rc == 0);
1277 if (rc != 0) {
1278 goto out;
1279 }
1280
1281 /*
1282 * The following states need image_ok be explicitly set after the
1283 * swap was finished to avoid a new revert.
1284 */
Tamas Ban581034a2017-12-19 19:54:37 +00001285 if (swap_type == BOOT_SWAP_TYPE_REVERT ||
1286 swap_type == BOOT_SWAP_TYPE_FAIL) {
Tamas Banf70ef8c2017-12-19 15:35:09 +00001287#ifndef MCUBOOT_OVERWRITE_ONLY
1288 rc = boot_set_image_ok();
1289 if (rc != 0) {
1290 swap_type = BOOT_SWAP_TYPE_PANIC;
1291 }
1292#endif /* !MCUBOOT_OVERWRITE_ONLY */
1293 }
1294 } else {
1295 swap_type = BOOT_SWAP_TYPE_NONE;
1296 }
1297
1298 switch (swap_type) {
1299 case BOOT_SWAP_TYPE_NONE:
1300 slot = 0;
1301 break;
1302
1303 case BOOT_SWAP_TYPE_TEST: /* fallthrough */
1304 case BOOT_SWAP_TYPE_PERM: /* fallthrough */
1305 case BOOT_SWAP_TYPE_REVERT:
1306 slot = 1;
1307 reload_headers = true;
1308#ifndef MCUBOOT_OVERWRITE_ONLY
1309 rc = boot_set_copy_done();
1310 if (rc != 0) {
1311 swap_type = BOOT_SWAP_TYPE_PANIC;
1312 }
1313#endif /* !MCUBOOT_OVERWRITE_ONLY */
1314 break;
1315
1316 case BOOT_SWAP_TYPE_FAIL:
1317 /* The image in slot 1 was invalid and is now erased. Ensure we don't
1318 * try to boot into it again on the next reboot. Do this by pretending
1319 * we just reverted back to slot 0.
1320 */
1321 slot = 0;
1322 reload_headers = true;
1323 break;
1324
1325 default:
1326 swap_type = BOOT_SWAP_TYPE_PANIC;
1327 }
1328
1329 if (swap_type == BOOT_SWAP_TYPE_PANIC) {
1330 BOOT_LOG_ERR("panic!");
1331 assert(0);
1332
1333 /* Loop forever... */
Tamas Ban581034a2017-12-19 19:54:37 +00001334 while (1)
1335 ;
Tamas Banf70ef8c2017-12-19 15:35:09 +00001336 }
1337
1338#ifdef MCUBOOT_VALIDATE_SLOT0
1339 if (reload_headers) {
1340 rc = boot_read_image_headers();
1341 if (rc != 0) {
1342 goto out;
1343 }
1344 /* Since headers were reloaded, it can be assumed we just performed a
1345 * swap or overwrite. Now the header info that should be used to
1346 * provide the data for the bootstrap, which previously was at Slot 1,
1347 * was updated to Slot 0.
1348 */
1349 slot = 0;
1350 }
1351
1352 rc = boot_validate_slot(0);
1353 assert(rc == 0);
1354 if (rc != 0) {
1355 rc = BOOT_EBADIMAGE;
1356 goto out;
1357 }
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00001358#else /* MCUBOOT_VALIDATE_SLOT0 */
Tamas Banf70ef8c2017-12-19 15:35:09 +00001359 (void)reload_headers;
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00001360#endif /* MCUBOOT_VALIDATE_SLOT0 */
Tamas Banf70ef8c2017-12-19 15:35:09 +00001361
1362 /* Always boot from the primary slot. */
1363 rsp->br_flash_dev_id = boot_img_fa_device_id(&boot_data, 0);
1364 rsp->br_image_off = boot_img_slot_off(&boot_data, 0);
1365 rsp->br_hdr = boot_img_hdr(&boot_data, slot);
1366
1367 out:
1368 flash_area_close(BOOT_SCRATCH_AREA(&boot_data));
1369 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
1370 flash_area_close(BOOT_IMG_AREA(&boot_data, BOOT_NUM_SLOTS - 1 - slot));
1371 }
1372 return rc;
1373}
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00001374
Oliver Swedef9982442018-08-24 18:37:44 +01001375#else /* MCUBOOT_NO_SWAP || MCUBOOT_RAM_LOADING */
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00001376
1377#define BOOT_LOG_IMAGE_INFO(area, hdr, state) \
1378 BOOT_LOG_INF("Image %"PRIu32": version=%"PRIu8".%"PRIu8".%"PRIu16"" \
1379 ".%"PRIu32", magic=%5s, image_ok=0x%x", \
1380 (area), \
1381 (hdr)->ih_ver.iv_major, \
1382 (hdr)->ih_ver.iv_minor, \
1383 (hdr)->ih_ver.iv_revision, \
1384 (hdr)->ih_ver.iv_build_num, \
1385 ((state)->magic == BOOT_MAGIC_GOOD ? "good" : \
1386 (state)->magic == BOOT_MAGIC_UNSET ? "unset" : \
1387 "bad"), \
1388 (state)->image_ok)
1389
1390struct image_slot_version {
1391 uint64_t version;
1392 uint32_t slot_number;
1393};
1394
1395/**
1396 * Extract the version number from the image header. This function must be
1397 * ported if version number format has changed in the image header.
1398 *
1399 * @param hdr Pointer to an image header structure
1400 *
Oliver Swedef9982442018-08-24 18:37:44 +01001401 * @return Version number casted to uint64_t
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00001402 */
1403static uint64_t
1404boot_get_version_number(struct image_header *hdr)
1405{
Oliver Swedef9982442018-08-24 18:37:44 +01001406 uint64_t version = 0;
1407 version |= (uint64_t)hdr->ih_ver.iv_major << (IMAGE_VER_MINOR_LENGTH
1408 + IMAGE_VER_REVISION_LENGTH
1409 + IMAGE_VER_BUILD_NUM_LENGTH);
1410 version |= (uint64_t)hdr->ih_ver.iv_minor << (IMAGE_VER_REVISION_LENGTH
1411 + IMAGE_VER_BUILD_NUM_LENGTH);
1412 version |= (uint64_t)hdr->ih_ver.iv_revision << IMAGE_VER_BUILD_NUM_LENGTH;
1413 version |= hdr->ih_ver.iv_build_num;
1414 return version;
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00001415}
1416
1417/**
1418 * Comparator function for `qsort` to compare version numbers. This function
1419 * must be ported if version number format has changed in the image header.
1420 *
1421 * @param ver1 Pointer to an array element which holds the version number
1422 * @param ver2 Pointer to another array element which holds the version
1423 * number
1424 *
1425 * @return if version1 > version2 -1
1426 * if version1 == version2 0
1427 * if version1 < version2 1
1428 */
1429static int
1430boot_compare_version_numbers(const void *ver1, const void *ver2)
1431{
1432 if (((struct image_slot_version *)ver1)->version <
1433 ((struct image_slot_version *)ver2)->version) {
1434 return 1;
1435 }
1436
1437 if (((struct image_slot_version *)ver1)->version ==
1438 ((struct image_slot_version *)ver2)->version) {
1439 return 0;
1440 }
1441
1442 return -1;
1443}
1444
1445/**
1446 * Sort the available images based on the version number and puts them in
1447 * a list.
1448 *
1449 * @param boot_sequence A pointer to an array, whose aim is to carry
1450 * the boot order of candidate images.
1451 * @param slot_cnt The number of flash areas, which can contains firmware
1452 * images.
1453 *
1454 * @return The number of valid images.
1455 */
1456uint32_t
1457boot_get_boot_sequence(uint32_t *boot_sequence, uint32_t slot_cnt)
1458{
1459 struct boot_swap_state slot_state;
1460 struct image_header *hdr;
1461 struct image_slot_version image_versions[BOOT_NUM_SLOTS] = {{0}};
1462 uint32_t image_cnt = 0;
1463 uint32_t slot;
1464 int32_t rc;
1465 int32_t fa_id;
1466
1467 for (slot = 0; slot < slot_cnt; slot++) {
1468 hdr = boot_img_hdr(&boot_data, slot);
1469 fa_id = flash_area_id_from_image_slot(slot);
1470 rc = boot_read_swap_state_by_id(fa_id, &slot_state);
1471 if (rc != 0) {
1472 BOOT_LOG_ERR("Error during reading image trailer from slot:"
1473 " %"PRIu32"", slot);
1474 continue;
1475 }
1476
1477 if (hdr->ih_magic == IMAGE_MAGIC) {
1478 if (slot_state.magic == BOOT_MAGIC_GOOD ||
1479 slot_state.image_ok == 0x01) {
1480 /* Valid cases:
1481 * - Test mode: magic is OK in image trailer
1482 * - Permanent mode: image_ok flag has previously set
1483 */
1484 image_versions[slot].slot_number = slot;
1485 image_versions[slot].version = boot_get_version_number(hdr);
1486 image_cnt++;
1487 }
1488
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00001489 BOOT_LOG_IMAGE_INFO(slot, hdr, &slot_state);
1490 } else {
Oliver Swedef9982442018-08-24 18:37:44 +01001491 BOOT_LOG_INF("Image %"PRIu32": No valid image", slot);
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00001492 }
1493 }
1494
1495 /* Sort the images based on version number */
1496 qsort(&image_versions[0],
1497 slot_cnt,
1498 sizeof(struct image_slot_version),
1499 boot_compare_version_numbers);
1500
1501 /* Copy the calculated boot sequence to boot_sequence array */
1502 for (slot = 0; slot < slot_cnt; slot++) {
1503 boot_sequence[slot] = image_versions[slot].slot_number;
1504 }
1505
1506 return image_cnt;
1507}
1508
Oliver Swedef9982442018-08-24 18:37:44 +01001509#ifdef MCUBOOT_RAM_LOADING
1510/**
1511 * Copies an image from a slot in the flash to an SRAM address, where the load
1512 * address has already been inserted into the image header by this point and is
1513 * extracted from it within this method. The copying is done sector-by-sector.
1514 *
1515 * @param slot The flash slot of the image to be copied to SRAM.
1516 *
1517 * @param hdr Pointer to the image header structure of the image
1518 * that needs to be copid to SRAM
1519 *
1520 * @return 0 on success; nonzero on failure.
1521 */
1522static int
1523boot_copy_image_to_sram(int slot, struct image_header *hdr)
1524{
1525 int rc;
1526 uint32_t sect_sz;
1527 uint32_t sect = 0;
1528 uint32_t bytes_copied = 0;
1529 const struct flash_area *fap_src = NULL;
1530 uint32_t dst = (uint32_t) hdr->ih_load_addr;
1531 uint32_t img_sz;
1532
1533 if (dst % 4 != 0) {
1534 BOOT_LOG_INF("Cannot copy the image to the SRAM address 0x%"PRIx32" "
1535 "- the load address must be aligned with 4 bytes due to SRAM "
1536 "restrictions", dst);
1537 return BOOT_EBADARGS;
1538 }
1539
1540 rc = flash_area_open(flash_area_id_from_image_slot(slot), &fap_src);
1541 if (rc != 0) {
1542 return BOOT_EFLASH;
1543 }
1544
1545 rc = boot_read_image_size(slot, hdr, &img_sz);
1546 if (rc != 0) {
1547 return BOOT_EFLASH;
1548 }
1549
1550 while (bytes_copied < img_sz) {
1551 sect_sz = boot_img_sector_size(&boot_data, slot, sect);
1552 /*
1553 * Direct copy from where the image sector resides in flash to its new
1554 * location in SRAM
1555 */
1556 rc = flash_area_read(fap_src,
1557 bytes_copied,
1558 (void *)(dst + bytes_copied),
1559 sect_sz);
1560 if (rc != 0) {
1561 BOOT_LOG_INF("Error whilst copying image from Flash to SRAM");
1562 break;
1563 } else {
1564 bytes_copied += sect_sz;
1565 }
1566 sect++;
1567 }
1568
1569 if (fap_src) {
1570 flash_area_close(fap_src);
1571 }
1572 return rc;
1573}
1574#endif /* MCUBOOT_RAM_LOADING */
1575
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00001576/**
1577 * Prepares the booting process. This function choose the newer image in flash
1578 * as appropriate, and returns the address to boot from.
1579 *
1580 * @param rsp On success, indicates how booting should occur.
1581 *
1582 * @return 0 on success; nonzero on failure.
1583 */
1584int
1585boot_go(struct boot_rsp *rsp)
1586{
1587 size_t slot = 0;
1588 int32_t i;
1589 int rc;
1590 int fa_id;
1591 uint32_t boot_sequence[BOOT_NUM_SLOTS];
1592 uint32_t img_cnt;
Oliver Swedef9982442018-08-24 18:37:44 +01001593 struct image_header *newest_image_header;
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00001594
1595 static boot_sector_t slot0_sectors[BOOT_MAX_IMG_SECTORS];
1596 static boot_sector_t slot1_sectors[BOOT_MAX_IMG_SECTORS];
1597
1598 boot_data.imgs[0].sectors = &slot0_sectors[0];
1599 boot_data.imgs[1].sectors = &slot1_sectors[0];
1600
1601 /* Open boot_data image areas for the duration of this call. */
1602 for (i = 0; i < BOOT_NUM_SLOTS; i++) {
1603 fa_id = flash_area_id_from_image_slot(i);
1604 rc = flash_area_open(fa_id, &BOOT_IMG_AREA(&boot_data, i));
1605 assert(rc == 0);
1606 }
1607
1608 /* Determine the sector layout of the image slots. */
1609 rc = boot_read_sectors();
1610 if (rc != 0) {
1611 goto out;
1612 }
1613
1614 /* Attempt to read an image header from each slot. */
1615 rc = boot_read_image_headers();
1616 if (rc != 0) {
1617 goto out;
1618 }
1619
1620 img_cnt = boot_get_boot_sequence(boot_sequence, BOOT_NUM_SLOTS);
1621 if (img_cnt) {
1622 /* Authenticate images */
1623 for (i = 0; i < img_cnt; i++) {
1624 rc = boot_validate_slot(boot_sequence[i]);
1625 if (rc == 0) {
1626 slot = boot_sequence[i];
1627 break;
1628 }
1629 }
1630 if (rc) {
1631 /* If there was no valid image at all */
1632 rc = BOOT_EBADIMAGE;
1633 goto out;
1634 }
1635
Oliver Swedef9982442018-08-24 18:37:44 +01001636 /* The slot variable now refers to the newest image's slot in flash */
1637 newest_image_header = boot_img_hdr(&boot_data, slot);
1638
1639 #ifdef MCUBOOT_RAM_LOADING
1640 if (newest_image_header->ih_flags & IMAGE_F_RAM_LOAD) {
1641 /* Copy image to the load address from where it
1642 * currently resides in flash */
1643 rc = boot_copy_image_to_sram(slot, newest_image_header);
1644 if (rc != 0) {
1645 rc = BOOT_EBADIMAGE;
1646 BOOT_LOG_INF("Could not copy image from slot 0x%"PRIx32" in "
1647 "the Flash to load address 0x%"PRIx32" in SRAM, "
1648 "aborting..",
1649 slot,
1650 newest_image_header->ih_load_addr);
1651 goto out;
1652 } else {
1653 BOOT_LOG_INF("Image has been copied from slot %d in flash to "
1654 "SRAM address 0x%"PRIx32"",
1655 slot,
1656 newest_image_header->ih_load_addr);
1657 }
1658
1659 /* Validate the image hash in SRAM after the copy was successful */
1660 rc = bootutil_check_hash_after_loading(newest_image_header);
1661 if (rc != 0) {
1662 rc = BOOT_EBADIMAGE;
1663 BOOT_LOG_INF("Cannot validate the hash of the image that was "
1664 "copied to SRAM, aborting..");
1665 goto out;
1666 }
1667
1668 BOOT_LOG_INF("Booting image from SRAM at address 0x%"PRIx32"",
1669 newest_image_header->ih_load_addr);
1670 } else {
1671 BOOT_LOG_INF("Booting image from slot %d", slot);
1672 }
1673 #endif /* MCUBOOT_RAM_LOADING */
1674
1675 rsp->br_hdr = newest_image_header;
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00001676 rsp->br_image_off = boot_img_slot_off(&boot_data, slot);
Oliver Swedef9982442018-08-24 18:37:44 +01001677 rsp->br_flash_dev_id = boot_img_fa_device_id(&boot_data, slot);
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00001678 } else {
1679 /* No candidate image available */
1680 rc = BOOT_EBADIMAGE;
1681 }
1682
1683out:
1684 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
1685 flash_area_close(BOOT_IMG_AREA(&boot_data, BOOT_NUM_SLOTS - 1 - slot));
1686 }
1687 return rc;
1688}
Oliver Swedef9982442018-08-24 18:37:44 +01001689#endif /* MCUBOOT_NO_SWAP || MCUBOOT_RAM_LOADING */