blob: 84ce78f437a17d6c81f1a5f4d7728afa4f0d8f86 [file] [log] [blame]
Christopher Collins92ea77f2016-12-12 15:59:26 -08001/*
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
20/**
21 * This file provides an interface to the boot loader. Functions defined in
22 * this file should only be called while the boot loader is running.
23 */
24
25#include <assert.h>
26#include <stddef.h>
27#include <inttypes.h>
28#include <stdlib.h>
29#include <string.h>
30#include "sysflash/sysflash.h"
31#include "flash_map/flash_map.h"
32#include <hal/hal_flash.h>
33#include <os/os_malloc.h>
34#include "bootutil/bootutil.h"
35#include "bootutil/image.h"
36#include "bootutil_priv.h"
37
38#define BOOT_MAX_IMG_SECTORS 120
39
40/** Number of image slots in flash; currently limited to two. */
41#define BOOT_NUM_SLOTS 2
42
43static struct {
44 struct {
45 struct image_header hdr;
46 struct flash_area *sectors;
Christopher Collins0ff3c6c2016-12-21 12:04:17 -080047 int num_sectors;
Christopher Collins92ea77f2016-12-12 15:59:26 -080048 } imgs[BOOT_NUM_SLOTS];
49
Christopher Collins92ea77f2016-12-12 15:59:26 -080050 struct flash_area scratch_sector;
51
52 uint8_t write_sz;
53} boot_data;
54
55struct boot_status_table {
56 /**
57 * For each field, a value of 0 means "any".
58 */
59 uint8_t bst_magic_slot0;
60 uint8_t bst_magic_scratch;
61 uint8_t bst_copy_done_slot0;
62 uint8_t bst_status_source;
63};
64
65/**
66 * This set of tables maps swap state contents to boot status location.
67 * When searching for a match, these tables must be iterated in order.
68 */
69static const struct boot_status_table boot_status_tables[] = {
70 {
71 /* | slot-0 | scratch |
72 * ----------+------------+------------|
73 * magic | Good | Any |
74 * copy-done | 0x01 | N/A |
75 * ----------+------------+------------'
76 * source: none |
77 * ------------------------------------'
78 */
79 .bst_magic_slot0 = BOOT_MAGIC_GOOD,
80 .bst_magic_scratch = 0,
81 .bst_copy_done_slot0 = 0x01,
82 .bst_status_source = BOOT_STATUS_SOURCE_NONE,
83 },
84
85 {
86 /* | slot-0 | scratch |
87 * ----------+------------+------------|
88 * magic | Good | Any |
89 * copy-done | 0xff | N/A |
90 * ----------+------------+------------'
91 * source: slot 0 |
92 * ------------------------------------'
93 */
94 .bst_magic_slot0 = BOOT_MAGIC_GOOD,
95 .bst_magic_scratch = 0,
96 .bst_copy_done_slot0 = 0xff,
97 .bst_status_source = BOOT_STATUS_SOURCE_SLOT0,
98 },
99
100 {
101 /* | slot-0 | scratch |
102 * ----------+------------+------------|
103 * magic | Any | Good |
104 * copy-done | Any | N/A |
105 * ----------+------------+------------'
106 * source: scratch |
107 * ------------------------------------'
108 */
109 .bst_magic_slot0 = 0,
110 .bst_magic_scratch = BOOT_MAGIC_GOOD,
111 .bst_copy_done_slot0 = 0,
112 .bst_status_source = BOOT_STATUS_SOURCE_SCRATCH,
113 },
114
115 {
116 /* | slot-0 | scratch |
117 * ----------+------------+------------|
118 * magic | Unset | Any |
119 * copy-done | 0xff | N/A |
120 * ----------+------------+------------|
121 * source: varies |
122 * ------------------------------------+------------------------------+
123 * This represents one of two cases: |
124 * o No swaps ever (no status to read, so no harm in checking). |
125 * o Mid-revert; status in slot 0. |
126 * -------------------------------------------------------------------'
127 */
128 .bst_magic_slot0 = BOOT_MAGIC_UNSET,
129 .bst_magic_scratch = 0,
130 .bst_copy_done_slot0 = 0xff,
131 .bst_status_source = BOOT_STATUS_SOURCE_SLOT0,
132 },
133};
134
135#define BOOT_STATUS_TABLES_COUNT \
136 (sizeof boot_status_tables / sizeof boot_status_tables[0])
137
138/**
139 * This table indicates the next swap type that should be performed. The first
140 * column contains the current swap type. The second column contains the swap
141 * type that should be effected after the first completes.
142 */
143static const uint8_t boot_swap_trans_table[][2] = {
144 /* From To */
145 { BOOT_SWAP_TYPE_REVERT, BOOT_SWAP_TYPE_NONE },
Christopher Collinsfd7eb5c2016-12-21 13:46:08 -0800146 { BOOT_SWAP_TYPE_PERM, BOOT_SWAP_TYPE_NONE },
Christopher Collins92ea77f2016-12-12 15:59:26 -0800147 { BOOT_SWAP_TYPE_TEST, BOOT_SWAP_TYPE_REVERT },
148};
149
150#define BOOT_SWAP_TRANS_TABLE_SIZE \
151 (sizeof boot_swap_trans_table / sizeof boot_swap_trans_table[0])
152
153/**
154 * Determines where in flash the most recent boot status is stored. The boot
155 * status is necessary for completing a swap that was interrupted by a boot
156 * loader reset.
157 *
158 * @return A BOOT_STATUS_SOURCE_[...] code indicating where * status should be read from.
159 */
160static int
161boot_status_source(void)
162{
163 const struct boot_status_table *table;
164 struct boot_swap_state state_scratch;
165 struct boot_swap_state state_slot0;
166 struct boot_swap_state state_slot1;
167 int rc;
168 int i;
169
170 rc = boot_read_swap_state_img(0, &state_slot0);
171 assert(rc == 0);
172
173 rc = boot_read_swap_state_img(1, &state_slot1);
174 assert(rc == 0);
175
176 rc = boot_read_swap_state_scratch(&state_scratch);
177 assert(rc == 0);
178
179 for (i = 0; i < BOOT_STATUS_TABLES_COUNT; i++) {
180 table = boot_status_tables + i;
181
182 if ((table->bst_magic_slot0 == 0 ||
183 table->bst_magic_slot0 == state_slot0.magic) &&
184 (table->bst_magic_scratch == 0 ||
185 table->bst_magic_scratch == state_scratch.magic) &&
186 (table->bst_copy_done_slot0 == 0 ||
187 table->bst_copy_done_slot0 == state_slot0.copy_done)) {
188
189 return table->bst_status_source;
190 }
191 }
192
193 return BOOT_STATUS_SOURCE_NONE;
194}
195
196/**
197 * Calculates the type of swap that just completed.
198 */
199static int
200boot_previous_swap_type(void)
201{
202 int post_swap_type;
203 int i;
204
205 post_swap_type = boot_swap_type();
206
207 for (i = 0; i < BOOT_SWAP_TRANS_TABLE_SIZE; i++){
208 if (boot_swap_trans_table[i][1] == post_swap_type) {
209 return boot_swap_trans_table[i][0];
210 }
211 }
212
213 /* XXX: Temporary assert. */
214 assert(0);
215
216 return BOOT_SWAP_TYPE_REVERT;
217}
218
219static int
220boot_read_image_header(int slot, struct image_header *out_hdr)
221{
222 const struct flash_area *fap;
223 int area_id;
224 int rc;
225
226 area_id = flash_area_id_from_image_slot(slot);
227 rc = flash_area_open(area_id, &fap);
228 if (rc != 0) {
229 rc = BOOT_EFLASH;
230 goto done;
231 }
232
233 rc = flash_area_read(fap, 0, out_hdr, sizeof *out_hdr);
234 if (rc != 0) {
235 rc = BOOT_EFLASH;
236 goto done;
237 }
238
239 rc = 0;
240
241done:
242 flash_area_close(fap);
243 return rc;
244}
245
246static int
247boot_read_image_headers(void)
248{
249 int rc;
250 int i;
251
252 for (i = 0; i < BOOT_NUM_SLOTS; i++) {
253 rc = boot_read_image_header(i, &boot_data.imgs[i].hdr);
254 if (rc != 0) {
Christopher Collins0ff3c6c2016-12-21 12:04:17 -0800255 /* If at least one header was read successfully, then the boot
256 * loader can attempt a boot. Failure to read any headers is a
257 * fatal error.
258 */
259 if (i > 0) {
260 return 0;
261 } else {
262 return rc;
263 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800264 }
265 }
266
267 return 0;
268}
269
270static uint8_t
271boot_write_sz(void)
272{
273 uint8_t elem_sz;
274 uint8_t align;
275
276 /* Figure out what size to write update status update as. The size depends
277 * on what the minimum write size is for scratch area, active image slot.
278 * We need to use the bigger of those 2 values.
279 */
280 elem_sz = hal_flash_align(boot_data.imgs[0].sectors[0].fa_device_id);
281 align = hal_flash_align(boot_data.scratch_sector.fa_device_id);
282 if (align > elem_sz) {
283 elem_sz = align;
284 }
285
286 return elem_sz;
287}
288
Christopher Collins0ff3c6c2016-12-21 12:04:17 -0800289static int
290boot_slots_compatible(void)
291{
292 const struct flash_area *sector0;
293 const struct flash_area *sector1;
294 int i;
295
296 /* Ensure both image slots have identical sector layouts. */
297 if (boot_data.imgs[0].num_sectors != boot_data.imgs[1].num_sectors) {
298 return 0;
299 }
300 for (i = 0; i < boot_data.imgs[0].num_sectors; i++) {
301 sector0 = boot_data.imgs[0].sectors + i;
302 sector1 = boot_data.imgs[1].sectors + i;
303 if (sector0->fa_size != sector1->fa_size) {
304 return 0;
305 }
306 }
307
308 return 1;
309}
310
Christopher Collins92ea77f2016-12-12 15:59:26 -0800311/**
312 * Determines the sector layout of both image slots and the scratch area.
313 * This information is necessary for calculating the number of bytes to erase
314 * and copy during an image swap. The information collected during this
315 * function is used to populate the boot_data global.
316 */
317static int
318boot_read_sectors(void)
319{
Christopher Collins92ea77f2016-12-12 15:59:26 -0800320 const struct flash_area *scratch;
321 int num_sectors_slot0;
322 int num_sectors_slot1;
323 int rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800324
325 num_sectors_slot0 = BOOT_MAX_IMG_SECTORS;
326 rc = flash_area_to_sectors(FLASH_AREA_IMAGE_0, &num_sectors_slot0,
327 boot_data.imgs[0].sectors);
328 if (rc != 0) {
329 return BOOT_EFLASH;
330 }
Christopher Collins0ff3c6c2016-12-21 12:04:17 -0800331 boot_data.imgs[0].num_sectors = num_sectors_slot0;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800332
333 num_sectors_slot1 = BOOT_MAX_IMG_SECTORS;
334 rc = flash_area_to_sectors(FLASH_AREA_IMAGE_1, &num_sectors_slot1,
335 boot_data.imgs[1].sectors);
336 if (rc != 0) {
337 return BOOT_EFLASH;
338 }
Christopher Collins0ff3c6c2016-12-21 12:04:17 -0800339 boot_data.imgs[1].num_sectors = num_sectors_slot1;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800340
341 rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH, &scratch);
342 if (rc != 0) {
343 return BOOT_EFLASH;
344 }
345 boot_data.scratch_sector = *scratch;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800346
347 boot_data.write_sz = boot_write_sz();
348
349 return 0;
350}
351
352static uint32_t
353boot_status_internal_off(int idx, int state, int elem_sz)
354{
355 int idx_sz;
356
357 idx_sz = elem_sz * BOOT_STATUS_STATE_COUNT;
358
359 return idx * idx_sz + state * elem_sz;
360}
361
362/**
363 * Reads the status of a partially-completed swap, if any. This is necessary
364 * to recover in case the boot lodaer was reset in the middle of a swap
365 * operation.
366 */
367static int
368boot_read_status_bytes(const struct flash_area *fap, struct boot_status *bs)
369{
370 uint32_t off;
371 uint8_t status;
372 int found;
373 int rc;
374 int i;
375
376 off = boot_status_off(fap);
377
378 found = 0;
379 for (i = 0; i < BOOT_STATUS_MAX_ENTRIES; i++) {
380 rc = flash_area_read(fap, off + i * boot_data.write_sz, &status, 1);
381 if (rc != 0) {
382 return BOOT_EFLASH;
383 }
384
385 if (status == 0xff) {
386 if (found) {
387 break;
388 }
389 } else if (!found) {
390 found = 1;
391 }
392 }
393
394 if (found) {
395 i--;
396 bs->idx = i / BOOT_STATUS_STATE_COUNT;
397 bs->state = i % BOOT_STATUS_STATE_COUNT;
398 }
399
400 return 0;
401}
402
403/**
404 * Reads the boot status from the flash. The boot status contains
405 * the current state of an interrupted image copy operation. If the boot
406 * status is not present, or it indicates that previous copy finished,
407 * there is no operation in progress.
408 */
409static int
410boot_read_status(struct boot_status *bs)
411{
412 const struct flash_area *fap;
413 int status_loc;
414 int area_id;
415 int rc;
416
417 memset(bs, 0, sizeof *bs);
418
419 status_loc = boot_status_source();
420 switch (status_loc) {
421 case BOOT_STATUS_SOURCE_NONE:
422 return 0;
423
424 case BOOT_STATUS_SOURCE_SCRATCH:
425 area_id = FLASH_AREA_IMAGE_SCRATCH;
426 break;
427
428 case BOOT_STATUS_SOURCE_SLOT0:
429 area_id = FLASH_AREA_IMAGE_0;
430 break;
431
432 default:
433 assert(0);
434 return BOOT_EBADARGS;
435 }
436
437 rc = flash_area_open(area_id, &fap);
438 if (rc != 0) {
439 return BOOT_EFLASH;
440 }
441
442 rc = boot_read_status_bytes(fap, bs);
443 if (rc != 0) {
444 return rc;
445 }
446
447 return 0;
448}
449
450/**
451 * Writes the supplied boot status to the flash file system. The boot status
452 * contains the current state of an in-progress image copy operation.
453 *
454 * @param bs The boot status to write.
455 *
456 * @return 0 on success; nonzero on failure.
457 */
458int
459boot_write_status(struct boot_status *bs)
460{
461 const struct flash_area *fap;
462 uint32_t off;
463 int area_id;
464 int rc;
David Brown9d725462017-01-23 15:50:58 -0700465 uint8_t buf[8];
466 uint8_t align;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800467
468 if (bs->idx == 0) {
469 /* Write to scratch. */
470 area_id = FLASH_AREA_IMAGE_SCRATCH;
471 } else {
472 /* Write to slot 0. */
473 area_id = FLASH_AREA_IMAGE_0;
474 }
475
476 rc = flash_area_open(area_id, &fap);
477 if (rc != 0) {
478 rc = BOOT_EFLASH;
479 goto done;
480 }
481
482 off = boot_status_off(fap) +
483 boot_status_internal_off(bs->idx, bs->state, boot_data.write_sz);
484
David Brown9d725462017-01-23 15:50:58 -0700485 align = hal_flash_align(fap->fa_device_id);
486 // ASSERT(align <= 8);
487 memset(buf, 0xFF, 8);
488 buf[0] = bs->state;
489
490 rc = flash_area_write(fap, off, buf, align);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800491 if (rc != 0) {
492 rc = BOOT_EFLASH;
493 goto done;
494 }
495
496 rc = 0;
497
498done:
499 flash_area_close(fap);
500 return rc;
501}
502
503/*
504 * Validate image hash/signature in a slot.
505 */
506static int
507boot_image_check(struct image_header *hdr, const struct flash_area *fap)
508{
David Browndb1d9d32017-01-06 11:07:54 -0700509 static uint8_t tmpbuf[BOOT_TMPBUF_SZ];
Christopher Collins92ea77f2016-12-12 15:59:26 -0800510
Christopher Collins92ea77f2016-12-12 15:59:26 -0800511 if (bootutil_img_validate(hdr, fap, tmpbuf, BOOT_TMPBUF_SZ,
512 NULL, 0, NULL)) {
513 return BOOT_EBADIMAGE;
514 }
515 return 0;
516}
517
518static int
519split_image_check(struct image_header *app_hdr,
520 const struct flash_area *app_fap,
521 struct image_header *loader_hdr,
522 const struct flash_area *loader_fap)
523{
524 static void *tmpbuf;
525 uint8_t loader_hash[32];
526
527 if (!tmpbuf) {
528 tmpbuf = malloc(BOOT_TMPBUF_SZ);
529 if (!tmpbuf) {
530 return BOOT_ENOMEM;
531 }
532 }
533
534 if (bootutil_img_validate(loader_hdr, loader_fap, tmpbuf, BOOT_TMPBUF_SZ,
535 NULL, 0, loader_hash)) {
536 return BOOT_EBADIMAGE;
537 }
538
539 if (bootutil_img_validate(app_hdr, app_fap, tmpbuf, BOOT_TMPBUF_SZ,
540 loader_hash, 32, NULL)) {
541 return BOOT_EBADIMAGE;
542 }
543
544 return 0;
545}
546
547static int
David Brownd930ec62016-12-14 07:59:48 -0700548boot_validate_slot(int slot)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800549{
550 const struct flash_area *fap;
551 int rc;
552
David Brownd930ec62016-12-14 07:59:48 -0700553 if (boot_data.imgs[slot].hdr.ih_magic == 0xffffffff ||
554 boot_data.imgs[slot].hdr.ih_flags & IMAGE_F_NON_BOOTABLE) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800555
556 /* No bootable image in slot 1; continue booting from slot 0. */
557 return -1;
558 }
559
560 /* Image in slot 1 is invalid. Erase the image and continue booting
561 * from slot 0.
562 */
David Brownd930ec62016-12-14 07:59:48 -0700563 rc = flash_area_open(flash_area_id_from_image_slot(slot), &fap);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800564 if (rc != 0) {
565 return BOOT_EFLASH;
566 }
567
David Brownd930ec62016-12-14 07:59:48 -0700568 if ((boot_data.imgs[slot].hdr.ih_magic != IMAGE_MAGIC ||
569 boot_image_check(&boot_data.imgs[slot].hdr, fap) != 0) &&
570 slot == 1) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800571
572 /* Image in slot 1 is invalid. Erase the image and continue booting
573 * from slot 0.
574 */
575 flash_area_erase(fap, 0, fap->fa_size);
576 return -1;
577 }
578
579 flash_area_close(fap);
580
581 /* Image in slot 1 is valid. */
582 return 0;
583}
584
585/**
586 * Determines which swap operation to perform, if any. If it is determined
587 * that a swap operation is required, the image in the second slot is checked
588 * for validity. If the image in the second slot is invalid, it is erased, and
589 * a swap type of "none" is indicated.
590 *
591 * @return The type of swap to perform (BOOT_SWAP_TYPE...)
592 */
593static int
594boot_validated_swap_type(void)
595{
596 int swap_type;
597 int rc;
598
599 swap_type = boot_swap_type();
600 if (swap_type == BOOT_SWAP_TYPE_NONE) {
601 /* Continue using slot 0. */
602 return BOOT_SWAP_TYPE_NONE;
603 }
604
605 /* Boot loader wants to switch to slot 1. Ensure image is valid. */
David Brownd930ec62016-12-14 07:59:48 -0700606 rc = boot_validate_slot(1);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800607 if (rc != 0) {
608 return BOOT_SWAP_TYPE_FAIL;
609 }
610
611 return swap_type;
612}
613
614/**
615 * Calculates the number of sectors the scratch area can contain. A "last"
616 * source sector is specified because images are copied backwards in flash
617 * (final index to index number 0).
618 *
619 * @param last_sector_idx The index of the last source sector
620 * (inclusive).
621 * @param out_first_sector_idx The index of the first source sector
622 * (inclusive) gets written here.
623 *
624 * @return The number of bytes comprised by the
625 * [first-sector, last-sector] range.
626 */
627static uint32_t
628boot_copy_sz(int last_sector_idx, int *out_first_sector_idx)
629{
630 uint32_t new_sz;
631 uint32_t sz;
632 int i;
633
634 sz = 0;
635
636 for (i = last_sector_idx; i >= 0; i--) {
637 new_sz = sz + boot_data.imgs[0].sectors[i].fa_size;
638 if (new_sz > boot_data.scratch_sector.fa_size) {
639 break;
640 }
641 sz = new_sz;
642 }
643
644 /* i currently refers to a sector that doesn't fit or it is -1 because all
645 * sectors have been processed. In both cases, exclude sector i.
646 */
647 *out_first_sector_idx = i + 1;
648 return sz;
649}
650
651/**
652 * Erases a region of flash.
653 *
654 * @param flash_area_idx The ID of the flash area containing the region
655 * to erase.
656 * @param off The offset within the flash area to start the
657 * erase.
658 * @param sz The number of bytes to erase.
659 *
660 * @return 0 on success; nonzero on failure.
661 */
662static int
663boot_erase_sector(int flash_area_id, uint32_t off, uint32_t sz)
664{
665 const struct flash_area *fap;
666 int rc;
667
668 rc = flash_area_open(flash_area_id, &fap);
669 if (rc != 0) {
670 rc = BOOT_EFLASH;
671 goto done;
672 }
673
674 rc = flash_area_erase(fap, off, sz);
675 if (rc != 0) {
676 rc = BOOT_EFLASH;
677 goto done;
678 }
679
680 rc = 0;
681
682done:
683 flash_area_close(fap);
684 return rc;
685}
686
687/**
688 * Copies the contents of one flash region to another. You must erase the
689 * destination region prior to calling this function.
690 *
691 * @param flash_area_id_src The ID of the source flash area.
692 * @param flash_area_id_dst The ID of the destination flash area.
693 * @param off_src The offset within the source flash area to
694 * copy from.
695 * @param off_dst The offset within the destination flash area to
696 * copy to.
697 * @param sz The number of bytes to copy.
698 *
699 * @return 0 on success; nonzero on failure.
700 */
701static int
702boot_copy_sector(int flash_area_id_src, int flash_area_id_dst,
703 uint32_t off_src, uint32_t off_dst, uint32_t sz)
704{
705 const struct flash_area *fap_src;
706 const struct flash_area *fap_dst;
707 uint32_t bytes_copied;
708 int chunk_sz;
709 int rc;
710
711 static uint8_t buf[1024];
712
713 fap_src = NULL;
714 fap_dst = NULL;
715
716 rc = flash_area_open(flash_area_id_src, &fap_src);
717 if (rc != 0) {
718 rc = BOOT_EFLASH;
719 goto done;
720 }
721
722 rc = flash_area_open(flash_area_id_dst, &fap_dst);
723 if (rc != 0) {
724 rc = BOOT_EFLASH;
725 goto done;
726 }
727
728 bytes_copied = 0;
729 while (bytes_copied < sz) {
730 if (sz - bytes_copied > sizeof buf) {
731 chunk_sz = sizeof buf;
732 } else {
733 chunk_sz = sz - bytes_copied;
734 }
735
736 rc = flash_area_read(fap_src, off_src + bytes_copied, buf, chunk_sz);
737 if (rc != 0) {
738 rc = BOOT_EFLASH;
739 goto done;
740 }
741
742 rc = flash_area_write(fap_dst, off_dst + bytes_copied, buf, chunk_sz);
743 if (rc != 0) {
744 rc = BOOT_EFLASH;
745 goto done;
746 }
747
748 bytes_copied += chunk_sz;
749 }
750
751 rc = 0;
752
753done:
754 flash_area_close(fap_src);
755 flash_area_close(fap_dst);
756 return rc;
757}
758
759/**
760 * Swaps the contents of two flash regions within the two image slots.
761 *
762 * @param idx The index of the first sector in the range of
763 * sectors being swapped.
764 * @param sz The number of bytes to swap.
765 * @param bs The current boot status. This struct gets
766 * updated according to the outcome.
767 *
768 * @return 0 on success; nonzero on failure.
769 */
770static int
771boot_swap_sectors(int idx, uint32_t sz, struct boot_status *bs)
772{
773 uint32_t copy_sz;
774 uint32_t img_off;
775 int rc;
776
777 /* Calculate offset from start of image area. */
778 img_off = boot_data.imgs[0].sectors[idx].fa_off -
779 boot_data.imgs[0].sectors[0].fa_off;
780
781 if (bs->state == 0) {
782 rc = boot_erase_sector(FLASH_AREA_IMAGE_SCRATCH, 0, sz);
783 if (rc != 0) {
784 return rc;
785 }
786
787 rc = boot_copy_sector(FLASH_AREA_IMAGE_1, FLASH_AREA_IMAGE_SCRATCH,
788 img_off, 0, sz);
789 if (rc != 0) {
790 return rc;
791 }
792
793 bs->state = 1;
794 (void)boot_write_status(bs);
795 }
796 if (bs->state == 1) {
797 rc = boot_erase_sector(FLASH_AREA_IMAGE_1, img_off, sz);
798 if (rc != 0) {
799 return rc;
800 }
801
802 copy_sz = sz;
803 if (boot_data.imgs[0].sectors[idx].fa_off + sz >=
804 boot_data.imgs[1].sectors[0].fa_off) {
805
806 /* This is the end of the area. Don't copy the image state into
807 * slot 1.
808 */
809 copy_sz -= boot_trailer_sz(boot_data.write_sz);
810 }
811
812 rc = boot_copy_sector(FLASH_AREA_IMAGE_0, FLASH_AREA_IMAGE_1,
813 img_off, img_off, copy_sz);
814 if (rc != 0) {
815 return rc;
816 }
817
818 bs->state = 2;
819 (void)boot_write_status(bs);
820 }
821 if (bs->state == 2) {
822 rc = boot_erase_sector(FLASH_AREA_IMAGE_0, img_off, sz);
823 if (rc != 0) {
824 return rc;
825 }
826
827 rc = boot_copy_sector(FLASH_AREA_IMAGE_SCRATCH, FLASH_AREA_IMAGE_0,
828 0, img_off, sz);
829 if (rc != 0) {
830 return rc;
831 }
832
833 bs->idx++;
834 bs->state = 0;
835 (void)boot_write_status(bs);
836 }
837
838 return 0;
839}
840
841/**
842 * Swaps the two images in flash. If a prior copy operation was interrupted
843 * by a system reset, this function completes that operation.
844 *
845 * @param bs The current boot status. This function reads
846 * this struct to determine if it is resuming
847 * an interrupted swap operation. This
848 * function writes the updated status to this
849 * function on return.
850 *
851 * @return 0 on success; nonzero on failure.
852 */
853static int
854boot_copy_image(struct boot_status *bs)
855{
856 uint32_t sz;
857 int first_sector_idx;
858 int last_sector_idx;
859 int swap_idx;
860
861 swap_idx = 0;
Christopher Collins0ff3c6c2016-12-21 12:04:17 -0800862 last_sector_idx = boot_data.imgs[0].num_sectors - 1;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800863 while (last_sector_idx >= 0) {
864 sz = boot_copy_sz(last_sector_idx, &first_sector_idx);
865 if (swap_idx >= bs->idx) {
866 boot_swap_sectors(first_sector_idx, sz, bs);
867 }
868
869 last_sector_idx = first_sector_idx - 1;
870 swap_idx++;
871 }
872
873 return 0;
874}
875
876/**
877 * Marks a test image in slot 0 as fully copied.
878 */
879static int
880boot_finalize_test_swap(void)
881{
882 const struct flash_area *fap;
883 int rc;
884
885 rc = flash_area_open(FLASH_AREA_IMAGE_0, &fap);
886 if (rc != 0) {
887 return BOOT_EFLASH;
888 }
889
890 rc = boot_write_copy_done(fap);
891 if (rc != 0) {
892 return rc;
893 }
894
895 return 0;
896}
897
898/**
899 * Marks a reverted image in slot 0 as confirmed. This is necessary to ensure
900 * the status bytes from the image revert operation don't get processed on a
901 * subsequent boot.
902 */
903static int
904boot_finalize_revert_swap(void)
905{
906 const struct flash_area *fap;
907 struct boot_swap_state state_slot0;
908 int rc;
909
910 rc = flash_area_open(FLASH_AREA_IMAGE_0, &fap);
911 if (rc != 0) {
912 return BOOT_EFLASH;
913 }
914
915 rc = boot_read_swap_state(fap, &state_slot0);
916 if (rc != 0) {
917 return BOOT_EFLASH;
918 }
919
920 if (state_slot0.magic == BOOT_MAGIC_UNSET) {
921 rc = boot_write_magic(fap);
922 if (rc != 0) {
923 return rc;
924 }
925 }
926
927 if (state_slot0.copy_done == 0xff) {
928 rc = boot_write_copy_done(fap);
929 if (rc != 0) {
930 return rc;
931 }
932 }
933
934 if (state_slot0.image_ok == 0xff) {
935 rc = boot_write_image_ok(fap);
936 if (rc != 0) {
937 return rc;
938 }
939 }
940
941 return 0;
942}
943
944/**
Christopher Collins0ff3c6c2016-12-21 12:04:17 -0800945 * Performs an image swap if one is required.
946 *
947 * @param out_swap_type On success, the type of swap performed gets
948 * written here.
949 *
950 * @return 0 on success; nonzero on failure.
951 */
952static int
953boot_swap_if_needed(int *out_swap_type)
954{
955 struct boot_status bs;
956 int swap_type;
957 int rc;
958
959 /* Determine if we rebooted in the middle of an image swap
960 * operation.
961 */
962 rc = boot_read_status(&bs);
963 if (rc != 0) {
964 return rc;
965 }
966
967 /* If a partial swap was detected, complete it. */
968 if (bs.idx != 0 || bs.state != 0) {
969 rc = boot_copy_image(&bs);
970 assert(rc == 0);
971
972 /* Extrapolate the type of the partial swap. We need this
973 * information to know how to mark the swap complete in flash.
974 */
975 swap_type = boot_previous_swap_type();
976 } else {
977 swap_type = boot_validated_swap_type();
978 switch (swap_type) {
979 case BOOT_SWAP_TYPE_TEST:
Christopher Collinsfd7eb5c2016-12-21 13:46:08 -0800980 case BOOT_SWAP_TYPE_PERM:
Christopher Collins0ff3c6c2016-12-21 12:04:17 -0800981 case BOOT_SWAP_TYPE_REVERT:
982 rc = boot_copy_image(&bs);
983 assert(rc == 0);
984 break;
985 }
986 }
987
988 *out_swap_type = swap_type;
989 return 0;
990}
991
992/**
Christopher Collins92ea77f2016-12-12 15:59:26 -0800993 * Prepares the booting process. This function moves images around in flash as
994 * appropriate, and tells you what address to boot from.
995 *
996 * @param rsp On success, indicates how booting should occur.
997 *
998 * @return 0 on success; nonzero on failure.
999 */
1000int
1001boot_go(struct boot_rsp *rsp)
1002{
Christopher Collins92ea77f2016-12-12 15:59:26 -08001003 int swap_type;
1004 int slot;
1005 int rc;
1006
1007 /* The array of slot sectors are defined here (as opposed to file scope) so
1008 * that they don't get allocated for non-boot-loader apps. This is
1009 * necessary because the gcc option "-fdata-sections" doesn't seem to have
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001010 * any effect in older gcc versions (e.g., 4.8.4).
Christopher Collins92ea77f2016-12-12 15:59:26 -08001011 */
1012 static struct flash_area slot0_sectors[BOOT_MAX_IMG_SECTORS];
1013 static struct flash_area slot1_sectors[BOOT_MAX_IMG_SECTORS];
1014 boot_data.imgs[0].sectors = slot0_sectors;
1015 boot_data.imgs[1].sectors = slot1_sectors;
1016
1017 /* Determine the sector layout of the image slots and scratch area. */
1018 rc = boot_read_sectors();
1019 if (rc != 0) {
1020 return rc;
1021 }
1022
1023 /* Attempt to read an image header from each slot. */
1024 rc = boot_read_image_headers();
1025 if (rc != 0) {
1026 return rc;
1027 }
1028
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001029 /* If the image slots aren't compatible, no swap is possible. Just boot
1030 * into slot 0.
1031 */
1032 if (boot_slots_compatible()) {
1033 rc = boot_swap_if_needed(&swap_type);
1034 if (rc != 0) {
1035 return rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001036 }
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001037 } else {
1038 swap_type = BOOT_SWAP_TYPE_NONE;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001039 }
1040
1041 switch (swap_type) {
1042 case BOOT_SWAP_TYPE_NONE:
David Brownd930ec62016-12-14 07:59:48 -07001043#ifdef BOOTUTIL_VALIDATE_SLOT0
1044 rc = boot_validate_slot(0);
1045 if (rc != 0) {
1046 return BOOT_EBADIMAGE;
1047 }
1048#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -08001049 slot = 0;
1050 break;
1051
1052 case BOOT_SWAP_TYPE_TEST:
Christopher Collinsfd7eb5c2016-12-21 13:46:08 -08001053 case BOOT_SWAP_TYPE_PERM:
Christopher Collins92ea77f2016-12-12 15:59:26 -08001054 slot = 1;
1055 boot_finalize_test_swap();
1056 break;
1057
1058 case BOOT_SWAP_TYPE_REVERT:
1059 slot = 1;
1060 boot_finalize_revert_swap();
1061 break;
1062
1063 case BOOT_SWAP_TYPE_FAIL:
1064 /* The image in slot 1 was invalid and is now erased. Ensure we don't
1065 * try to boot into it again on the next reboot. Do this by pretending
1066 * we just reverted back to slot 0.
1067 */
1068 slot = 0;
1069 boot_finalize_revert_swap();
1070 break;
1071
1072 default:
1073 assert(0);
1074 slot = 0;
1075 break;
1076 }
1077
1078 /* Always boot from the primary slot. */
1079 rsp->br_flash_id = boot_data.imgs[0].sectors[0].fa_device_id;
1080 rsp->br_image_addr = boot_data.imgs[0].sectors[0].fa_off;
1081 rsp->br_hdr = &boot_data.imgs[slot].hdr;
1082
1083 return 0;
1084}
1085
1086int
1087split_go(int loader_slot, int split_slot, void **entry)
1088{
1089 const struct flash_area *loader_fap;
1090 const struct flash_area *app_fap;
1091 struct flash_area *sectors;
Christopher Collins034a6202017-01-11 12:19:37 -08001092 uintptr_t entry_val;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001093 int loader_flash_id;
1094 int app_flash_id;
1095 int rc;
1096
1097 app_fap = NULL;
1098 loader_fap = NULL;
1099
1100 sectors = malloc(BOOT_MAX_IMG_SECTORS * 2 * sizeof *sectors);
1101 if (sectors == NULL) {
1102 rc = SPLIT_GO_ERR;
1103 goto done;
1104 }
1105 boot_data.imgs[0].sectors = sectors + 0;
1106 boot_data.imgs[1].sectors = sectors + BOOT_MAX_IMG_SECTORS;
1107
1108 /* Determine the sector layout of the image slots and scratch area. */
1109 rc = boot_read_sectors();
1110 if (rc != 0) {
1111 rc = SPLIT_GO_ERR;
1112 goto done;
1113 }
1114
1115 rc = boot_read_image_headers();
1116 if (rc != 0) {
1117 goto done;
1118 }
1119
1120 app_flash_id = flash_area_id_from_image_slot(split_slot);
1121 rc = flash_area_open(app_flash_id, &app_fap);
1122 if (rc != 0) {
1123 rc = BOOT_EFLASH;
1124 goto done;
1125 }
1126
1127 loader_flash_id = flash_area_id_from_image_slot(loader_slot);
1128 rc = flash_area_open(loader_flash_id, &loader_fap);
1129 if (rc != 0) {
1130 rc = BOOT_EFLASH;
1131 goto done;
1132 }
1133
1134 /* Don't check the bootable image flag because we could really call a
1135 * bootable or non-bootable image. Just validate that the image check
1136 * passes which is distinct from the normal check.
1137 */
1138 rc = split_image_check(&boot_data.imgs[split_slot].hdr,
1139 app_fap,
1140 &boot_data.imgs[loader_slot].hdr,
1141 loader_fap);
1142 if (rc != 0) {
1143 rc = SPLIT_GO_NON_MATCHING;
1144 goto done;
1145 }
1146
1147 entry_val = boot_data.imgs[split_slot].sectors[0].fa_off +
1148 boot_data.imgs[split_slot].hdr.ih_hdr_size;
Christopher Collins034a6202017-01-11 12:19:37 -08001149 *entry = (void *) entry_val;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001150 rc = SPLIT_GO_OK;
1151
1152done:
1153 free(sectors);
1154 flash_area_close(app_fap);
1155 flash_area_close(loader_fap);
1156 return rc;
1157}