blob: a32817291d60381a391ee6a2bea9a2681e34ff99 [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
Marti Bolivarfd20c762017-02-07 16:52:50 -050038#define BOOT_LOG_LEVEL BOOT_LOG_LEVEL_INFO
39#include "bootutil/bootutil_log.h"
40
Fabio Utzigeed80b62017-06-10 08:03:05 -030041#ifdef APP_mynewt
42#include "mynewt/config.h"
43#endif
44
Christopher Collins92ea77f2016-12-12 15:59:26 -080045#define BOOT_MAX_IMG_SECTORS 120
46
47/** Number of image slots in flash; currently limited to two. */
48#define BOOT_NUM_SLOTS 2
49
50static struct {
51 struct {
52 struct image_header hdr;
53 struct flash_area *sectors;
Christopher Collins0ff3c6c2016-12-21 12:04:17 -080054 int num_sectors;
Christopher Collins92ea77f2016-12-12 15:59:26 -080055 } imgs[BOOT_NUM_SLOTS];
56
Christopher Collins92ea77f2016-12-12 15:59:26 -080057 struct flash_area scratch_sector;
58
59 uint8_t write_sz;
60} boot_data;
61
62struct boot_status_table {
63 /**
64 * For each field, a value of 0 means "any".
65 */
66 uint8_t bst_magic_slot0;
67 uint8_t bst_magic_scratch;
68 uint8_t bst_copy_done_slot0;
69 uint8_t bst_status_source;
70};
71
72/**
73 * This set of tables maps swap state contents to boot status location.
74 * When searching for a match, these tables must be iterated in order.
75 */
76static const struct boot_status_table boot_status_tables[] = {
77 {
78 /* | slot-0 | scratch |
79 * ----------+------------+------------|
80 * magic | Good | Any |
81 * copy-done | 0x01 | N/A |
82 * ----------+------------+------------'
83 * source: none |
84 * ------------------------------------'
85 */
86 .bst_magic_slot0 = BOOT_MAGIC_GOOD,
87 .bst_magic_scratch = 0,
88 .bst_copy_done_slot0 = 0x01,
89 .bst_status_source = BOOT_STATUS_SOURCE_NONE,
90 },
91
92 {
93 /* | slot-0 | scratch |
94 * ----------+------------+------------|
95 * magic | Good | Any |
96 * copy-done | 0xff | N/A |
97 * ----------+------------+------------'
98 * source: slot 0 |
99 * ------------------------------------'
100 */
101 .bst_magic_slot0 = BOOT_MAGIC_GOOD,
102 .bst_magic_scratch = 0,
103 .bst_copy_done_slot0 = 0xff,
104 .bst_status_source = BOOT_STATUS_SOURCE_SLOT0,
105 },
106
107 {
108 /* | slot-0 | scratch |
109 * ----------+------------+------------|
110 * magic | Any | Good |
111 * copy-done | Any | N/A |
112 * ----------+------------+------------'
113 * source: scratch |
114 * ------------------------------------'
115 */
116 .bst_magic_slot0 = 0,
117 .bst_magic_scratch = BOOT_MAGIC_GOOD,
118 .bst_copy_done_slot0 = 0,
119 .bst_status_source = BOOT_STATUS_SOURCE_SCRATCH,
120 },
121
122 {
123 /* | slot-0 | scratch |
124 * ----------+------------+------------|
125 * magic | Unset | Any |
126 * copy-done | 0xff | N/A |
127 * ----------+------------+------------|
128 * source: varies |
129 * ------------------------------------+------------------------------+
130 * This represents one of two cases: |
131 * o No swaps ever (no status to read, so no harm in checking). |
132 * o Mid-revert; status in slot 0. |
133 * -------------------------------------------------------------------'
134 */
135 .bst_magic_slot0 = BOOT_MAGIC_UNSET,
136 .bst_magic_scratch = 0,
137 .bst_copy_done_slot0 = 0xff,
138 .bst_status_source = BOOT_STATUS_SOURCE_SLOT0,
139 },
140};
141
142#define BOOT_STATUS_TABLES_COUNT \
143 (sizeof boot_status_tables / sizeof boot_status_tables[0])
144
145/**
146 * This table indicates the next swap type that should be performed. The first
147 * column contains the current swap type. The second column contains the swap
148 * type that should be effected after the first completes.
149 */
150static const uint8_t boot_swap_trans_table[][2] = {
151 /* From To */
152 { BOOT_SWAP_TYPE_REVERT, BOOT_SWAP_TYPE_NONE },
Christopher Collinsfd7eb5c2016-12-21 13:46:08 -0800153 { BOOT_SWAP_TYPE_PERM, BOOT_SWAP_TYPE_NONE },
Christopher Collins92ea77f2016-12-12 15:59:26 -0800154 { BOOT_SWAP_TYPE_TEST, BOOT_SWAP_TYPE_REVERT },
155};
156
157#define BOOT_SWAP_TRANS_TABLE_SIZE \
158 (sizeof boot_swap_trans_table / sizeof boot_swap_trans_table[0])
159
Marti Bolivarfd20c762017-02-07 16:52:50 -0500160#define BOOT_LOG_SWAP_STATE(area, state) \
161 BOOT_LOG_INF("%s: magic=%s, copy_done=0x%x, image_ok=0x%x", \
162 (area), \
163 ((state)->magic == BOOT_MAGIC_GOOD ? "good" : \
164 (state)->magic == BOOT_MAGIC_UNSET ? "unset" : \
165 "bad"), \
166 (state)->copy_done, \
167 (state)->image_ok)
168
Christopher Collins92ea77f2016-12-12 15:59:26 -0800169/**
170 * Determines where in flash the most recent boot status is stored. The boot
171 * status is necessary for completing a swap that was interrupted by a boot
172 * loader reset.
173 *
174 * @return A BOOT_STATUS_SOURCE_[...] code indicating where * status should be read from.
175 */
176static int
177boot_status_source(void)
178{
179 const struct boot_status_table *table;
180 struct boot_swap_state state_scratch;
181 struct boot_swap_state state_slot0;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800182 int rc;
183 int i;
Marti Bolivarfd20c762017-02-07 16:52:50 -0500184 uint8_t source;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800185
Fabio Utzig2473ac02017-05-02 12:45:02 -0300186 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_0, &state_slot0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800187 assert(rc == 0);
188
Fabio Utzig2473ac02017-05-02 12:45:02 -0300189 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SCRATCH, &state_scratch);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800190 assert(rc == 0);
191
Marti Bolivarfd20c762017-02-07 16:52:50 -0500192 BOOT_LOG_SWAP_STATE("Image 0", &state_slot0);
Marti Bolivarfd20c762017-02-07 16:52:50 -0500193 BOOT_LOG_SWAP_STATE("Scratch", &state_scratch);
194
Christopher Collins92ea77f2016-12-12 15:59:26 -0800195 for (i = 0; i < BOOT_STATUS_TABLES_COUNT; i++) {
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300196 table = &boot_status_tables[i];
Christopher Collins92ea77f2016-12-12 15:59:26 -0800197
198 if ((table->bst_magic_slot0 == 0 ||
199 table->bst_magic_slot0 == state_slot0.magic) &&
200 (table->bst_magic_scratch == 0 ||
201 table->bst_magic_scratch == state_scratch.magic) &&
202 (table->bst_copy_done_slot0 == 0 ||
203 table->bst_copy_done_slot0 == state_slot0.copy_done)) {
Marti Bolivarfd20c762017-02-07 16:52:50 -0500204 source = table->bst_status_source;
205 BOOT_LOG_INF("Boot source: %s",
206 source == BOOT_STATUS_SOURCE_NONE ? "none" :
207 source == BOOT_STATUS_SOURCE_SCRATCH ? "scratch" :
208 source == BOOT_STATUS_SOURCE_SLOT0 ? "slot 0" :
209 "BUG; can't happen");
210 return source;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800211 }
212 }
213
Marti Bolivarfd20c762017-02-07 16:52:50 -0500214 BOOT_LOG_INF("Boot source: none");
Christopher Collins92ea77f2016-12-12 15:59:26 -0800215 return BOOT_STATUS_SOURCE_NONE;
216}
217
218/**
219 * Calculates the type of swap that just completed.
220 */
221static int
222boot_previous_swap_type(void)
223{
224 int post_swap_type;
225 int i;
226
227 post_swap_type = boot_swap_type();
228
229 for (i = 0; i < BOOT_SWAP_TRANS_TABLE_SIZE; i++){
230 if (boot_swap_trans_table[i][1] == post_swap_type) {
231 return boot_swap_trans_table[i][0];
232 }
233 }
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300234
Christopher Collins92ea77f2016-12-12 15:59:26 -0800235 /* XXX: Temporary assert. */
236 assert(0);
237
238 return BOOT_SWAP_TYPE_REVERT;
239}
240
241static int
242boot_read_image_header(int slot, struct image_header *out_hdr)
243{
244 const struct flash_area *fap;
245 int area_id;
246 int rc;
247
248 area_id = flash_area_id_from_image_slot(slot);
249 rc = flash_area_open(area_id, &fap);
250 if (rc != 0) {
251 rc = BOOT_EFLASH;
252 goto done;
253 }
254
255 rc = flash_area_read(fap, 0, out_hdr, sizeof *out_hdr);
256 if (rc != 0) {
257 rc = BOOT_EFLASH;
258 goto done;
259 }
260
261 rc = 0;
262
263done:
264 flash_area_close(fap);
265 return rc;
266}
267
268static int
269boot_read_image_headers(void)
270{
271 int rc;
272 int i;
273
274 for (i = 0; i < BOOT_NUM_SLOTS; i++) {
275 rc = boot_read_image_header(i, &boot_data.imgs[i].hdr);
276 if (rc != 0) {
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300277 /* If at least the first slot's header was read successfully, then
278 * the boot loader can attempt a boot. Failure to read any headers
279 * is a fatal error.
Christopher Collins0ff3c6c2016-12-21 12:04:17 -0800280 */
281 if (i > 0) {
282 return 0;
283 } else {
284 return rc;
285 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800286 }
287 }
288
289 return 0;
290}
291
292static uint8_t
293boot_write_sz(void)
294{
295 uint8_t elem_sz;
296 uint8_t align;
297
298 /* Figure out what size to write update status update as. The size depends
299 * on what the minimum write size is for scratch area, active image slot.
300 * We need to use the bigger of those 2 values.
301 */
302 elem_sz = hal_flash_align(boot_data.imgs[0].sectors[0].fa_device_id);
303 align = hal_flash_align(boot_data.scratch_sector.fa_device_id);
304 if (align > elem_sz) {
305 elem_sz = align;
306 }
307
308 return elem_sz;
309}
310
Christopher Collins0ff3c6c2016-12-21 12:04:17 -0800311static int
312boot_slots_compatible(void)
313{
314 const struct flash_area *sector0;
315 const struct flash_area *sector1;
316 int i;
317
318 /* Ensure both image slots have identical sector layouts. */
319 if (boot_data.imgs[0].num_sectors != boot_data.imgs[1].num_sectors) {
320 return 0;
321 }
322 for (i = 0; i < boot_data.imgs[0].num_sectors; i++) {
323 sector0 = boot_data.imgs[0].sectors + i;
324 sector1 = boot_data.imgs[1].sectors + i;
325 if (sector0->fa_size != sector1->fa_size) {
326 return 0;
327 }
328 }
329
330 return 1;
331}
332
Christopher Collins92ea77f2016-12-12 15:59:26 -0800333/**
334 * Determines the sector layout of both image slots and the scratch area.
335 * This information is necessary for calculating the number of bytes to erase
336 * and copy during an image swap. The information collected during this
337 * function is used to populate the boot_data global.
338 */
339static int
340boot_read_sectors(void)
341{
Christopher Collins92ea77f2016-12-12 15:59:26 -0800342 const struct flash_area *scratch;
343 int num_sectors_slot0;
344 int num_sectors_slot1;
345 int rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800346
347 num_sectors_slot0 = BOOT_MAX_IMG_SECTORS;
348 rc = flash_area_to_sectors(FLASH_AREA_IMAGE_0, &num_sectors_slot0,
349 boot_data.imgs[0].sectors);
350 if (rc != 0) {
351 return BOOT_EFLASH;
352 }
Christopher Collins0ff3c6c2016-12-21 12:04:17 -0800353 boot_data.imgs[0].num_sectors = num_sectors_slot0;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800354
355 num_sectors_slot1 = BOOT_MAX_IMG_SECTORS;
356 rc = flash_area_to_sectors(FLASH_AREA_IMAGE_1, &num_sectors_slot1,
357 boot_data.imgs[1].sectors);
358 if (rc != 0) {
359 return BOOT_EFLASH;
360 }
Christopher Collins0ff3c6c2016-12-21 12:04:17 -0800361 boot_data.imgs[1].num_sectors = num_sectors_slot1;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800362
363 rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH, &scratch);
364 if (rc != 0) {
365 return BOOT_EFLASH;
366 }
367 boot_data.scratch_sector = *scratch;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800368
369 boot_data.write_sz = boot_write_sz();
370
371 return 0;
372}
373
374static uint32_t
375boot_status_internal_off(int idx, int state, int elem_sz)
376{
377 int idx_sz;
378
379 idx_sz = elem_sz * BOOT_STATUS_STATE_COUNT;
380
381 return idx * idx_sz + state * elem_sz;
382}
383
384/**
385 * Reads the status of a partially-completed swap, if any. This is necessary
386 * to recover in case the boot lodaer was reset in the middle of a swap
387 * operation.
388 */
389static int
390boot_read_status_bytes(const struct flash_area *fap, struct boot_status *bs)
391{
392 uint32_t off;
393 uint8_t status;
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300394 int max_entries;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800395 int found;
396 int rc;
397 int i;
398
399 off = boot_status_off(fap);
Fabio Utzig4cee4f72017-05-22 10:59:57 -0400400 max_entries = boot_status_entries(fap);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300401
Christopher Collins92ea77f2016-12-12 15:59:26 -0800402 found = 0;
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300403 for (i = 0; i < max_entries; i++) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800404 rc = flash_area_read(fap, off + i * boot_data.write_sz, &status, 1);
405 if (rc != 0) {
406 return BOOT_EFLASH;
407 }
408
409 if (status == 0xff) {
410 if (found) {
411 break;
412 }
413 } else if (!found) {
414 found = 1;
415 }
416 }
417
418 if (found) {
419 i--;
Fabio Utzig94d998c2017-05-22 11:02:41 -0400420 bs->idx = i / BOOT_STATUS_STATE_COUNT;
421 bs->state = i % BOOT_STATUS_STATE_COUNT;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800422 }
423
424 return 0;
425}
426
427/**
428 * Reads the boot status from the flash. The boot status contains
429 * the current state of an interrupted image copy operation. If the boot
430 * status is not present, or it indicates that previous copy finished,
431 * there is no operation in progress.
432 */
433static int
434boot_read_status(struct boot_status *bs)
435{
436 const struct flash_area *fap;
437 int status_loc;
438 int area_id;
439 int rc;
440
441 memset(bs, 0, sizeof *bs);
442
443 status_loc = boot_status_source();
444 switch (status_loc) {
445 case BOOT_STATUS_SOURCE_NONE:
446 return 0;
447
448 case BOOT_STATUS_SOURCE_SCRATCH:
449 area_id = FLASH_AREA_IMAGE_SCRATCH;
450 break;
451
452 case BOOT_STATUS_SOURCE_SLOT0:
453 area_id = FLASH_AREA_IMAGE_0;
454 break;
455
456 default:
457 assert(0);
458 return BOOT_EBADARGS;
459 }
460
461 rc = flash_area_open(area_id, &fap);
462 if (rc != 0) {
463 return BOOT_EFLASH;
464 }
465
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300466 return boot_read_status_bytes(fap, bs);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800467}
468
469/**
470 * Writes the supplied boot status to the flash file system. The boot status
471 * contains the current state of an in-progress image copy operation.
472 *
473 * @param bs The boot status to write.
474 *
475 * @return 0 on success; nonzero on failure.
476 */
477int
478boot_write_status(struct boot_status *bs)
479{
480 const struct flash_area *fap;
481 uint32_t off;
482 int area_id;
483 int rc;
David Brown9d725462017-01-23 15:50:58 -0700484 uint8_t buf[8];
485 uint8_t align;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800486
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300487 /* NOTE: The first sector copied (that is the last sector on slot) contains
488 * the trailer. Since in the last step SLOT 0 is erased, the first
489 * two status writes go to the scratch which will be copied to SLOT 0!
490 */
491
Fabio Utzig2473ac02017-05-02 12:45:02 -0300492 if (bs->use_scratch) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800493 /* Write to scratch. */
494 area_id = FLASH_AREA_IMAGE_SCRATCH;
495 } else {
496 /* Write to slot 0. */
497 area_id = FLASH_AREA_IMAGE_0;
498 }
499
500 rc = flash_area_open(area_id, &fap);
501 if (rc != 0) {
502 rc = BOOT_EFLASH;
503 goto done;
504 }
505
506 off = boot_status_off(fap) +
507 boot_status_internal_off(bs->idx, bs->state, boot_data.write_sz);
508
David Brown9d725462017-01-23 15:50:58 -0700509 align = hal_flash_align(fap->fa_device_id);
David Brown9d725462017-01-23 15:50:58 -0700510 memset(buf, 0xFF, 8);
511 buf[0] = bs->state;
512
513 rc = flash_area_write(fap, off, buf, align);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800514 if (rc != 0) {
515 rc = BOOT_EFLASH;
516 goto done;
517 }
518
519 rc = 0;
520
521done:
522 flash_area_close(fap);
523 return rc;
524}
525
526/*
527 * Validate image hash/signature in a slot.
528 */
529static int
530boot_image_check(struct image_header *hdr, const struct flash_area *fap)
531{
David Browndb1d9d32017-01-06 11:07:54 -0700532 static uint8_t tmpbuf[BOOT_TMPBUF_SZ];
Christopher Collins92ea77f2016-12-12 15:59:26 -0800533
Christopher Collins92ea77f2016-12-12 15:59:26 -0800534 if (bootutil_img_validate(hdr, fap, tmpbuf, BOOT_TMPBUF_SZ,
535 NULL, 0, NULL)) {
536 return BOOT_EBADIMAGE;
537 }
538 return 0;
539}
540
541static int
542split_image_check(struct image_header *app_hdr,
543 const struct flash_area *app_fap,
544 struct image_header *loader_hdr,
545 const struct flash_area *loader_fap)
546{
547 static void *tmpbuf;
548 uint8_t loader_hash[32];
549
550 if (!tmpbuf) {
551 tmpbuf = malloc(BOOT_TMPBUF_SZ);
552 if (!tmpbuf) {
553 return BOOT_ENOMEM;
554 }
555 }
556
557 if (bootutil_img_validate(loader_hdr, loader_fap, tmpbuf, BOOT_TMPBUF_SZ,
558 NULL, 0, loader_hash)) {
559 return BOOT_EBADIMAGE;
560 }
561
562 if (bootutil_img_validate(app_hdr, app_fap, tmpbuf, BOOT_TMPBUF_SZ,
563 loader_hash, 32, NULL)) {
564 return BOOT_EBADIMAGE;
565 }
566
567 return 0;
568}
569
570static int
David Brownd930ec62016-12-14 07:59:48 -0700571boot_validate_slot(int slot)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800572{
573 const struct flash_area *fap;
574 int rc;
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300575
David Brownd930ec62016-12-14 07:59:48 -0700576 if (boot_data.imgs[slot].hdr.ih_magic == 0xffffffff ||
577 boot_data.imgs[slot].hdr.ih_flags & IMAGE_F_NON_BOOTABLE) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800578
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300579 /* No bootable image in slot; continue booting from slot 0. */
Christopher Collins92ea77f2016-12-12 15:59:26 -0800580 return -1;
581 }
582
David Brownd930ec62016-12-14 07:59:48 -0700583 rc = flash_area_open(flash_area_id_from_image_slot(slot), &fap);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800584 if (rc != 0) {
585 return BOOT_EFLASH;
586 }
587
David Brownd930ec62016-12-14 07:59:48 -0700588 if ((boot_data.imgs[slot].hdr.ih_magic != IMAGE_MAGIC ||
David Brownb38e0442017-02-24 13:57:12 -0700589 boot_image_check(&boot_data.imgs[slot].hdr, fap) != 0)) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800590
David Brownb38e0442017-02-24 13:57:12 -0700591 if (slot != 0) {
592 flash_area_erase(fap, 0, fap->fa_size);
593 /* Image in slot 1 is invalid. Erase the image and
594 * continue booting from slot 0.
595 */
596 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800597 return -1;
598 }
599
600 flash_area_close(fap);
601
602 /* Image in slot 1 is valid. */
603 return 0;
604}
605
606/**
607 * Determines which swap operation to perform, if any. If it is determined
608 * that a swap operation is required, the image in the second slot is checked
609 * for validity. If the image in the second slot is invalid, it is erased, and
610 * a swap type of "none" is indicated.
611 *
612 * @return The type of swap to perform (BOOT_SWAP_TYPE...)
613 */
614static int
615boot_validated_swap_type(void)
616{
617 int swap_type;
618 int rc;
619
620 swap_type = boot_swap_type();
621 if (swap_type == BOOT_SWAP_TYPE_NONE) {
622 /* Continue using slot 0. */
623 return BOOT_SWAP_TYPE_NONE;
624 }
625
626 /* Boot loader wants to switch to slot 1. Ensure image is valid. */
David Brownd930ec62016-12-14 07:59:48 -0700627 rc = boot_validate_slot(1);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800628 if (rc != 0) {
629 return BOOT_SWAP_TYPE_FAIL;
630 }
631
632 return swap_type;
633}
634
635/**
636 * Calculates the number of sectors the scratch area can contain. A "last"
637 * source sector is specified because images are copied backwards in flash
638 * (final index to index number 0).
639 *
640 * @param last_sector_idx The index of the last source sector
641 * (inclusive).
642 * @param out_first_sector_idx The index of the first source sector
643 * (inclusive) gets written here.
644 *
645 * @return The number of bytes comprised by the
646 * [first-sector, last-sector] range.
647 */
David Brown17609d82017-05-05 09:41:34 -0600648#ifndef BOOTUTIL_OVERWRITE_ONLY
Christopher Collins92ea77f2016-12-12 15:59:26 -0800649static uint32_t
650boot_copy_sz(int last_sector_idx, int *out_first_sector_idx)
651{
652 uint32_t new_sz;
653 uint32_t sz;
654 int i;
655
656 sz = 0;
657
658 for (i = last_sector_idx; i >= 0; i--) {
659 new_sz = sz + boot_data.imgs[0].sectors[i].fa_size;
660 if (new_sz > boot_data.scratch_sector.fa_size) {
661 break;
662 }
663 sz = new_sz;
664 }
665
666 /* i currently refers to a sector that doesn't fit or it is -1 because all
667 * sectors have been processed. In both cases, exclude sector i.
668 */
669 *out_first_sector_idx = i + 1;
670 return sz;
671}
David Brown17609d82017-05-05 09:41:34 -0600672#endif /* not BOOTUTIL_OVERWRITE_ONLY */
Christopher Collins92ea77f2016-12-12 15:59:26 -0800673
674/**
675 * Erases a region of flash.
676 *
677 * @param flash_area_idx The ID of the flash area containing the region
678 * to erase.
679 * @param off The offset within the flash area to start the
680 * erase.
681 * @param sz The number of bytes to erase.
682 *
683 * @return 0 on success; nonzero on failure.
684 */
685static int
686boot_erase_sector(int flash_area_id, uint32_t off, uint32_t sz)
687{
688 const struct flash_area *fap;
689 int rc;
690
691 rc = flash_area_open(flash_area_id, &fap);
692 if (rc != 0) {
693 rc = BOOT_EFLASH;
694 goto done;
695 }
696
697 rc = flash_area_erase(fap, off, sz);
698 if (rc != 0) {
699 rc = BOOT_EFLASH;
700 goto done;
701 }
702
703 rc = 0;
704
705done:
706 flash_area_close(fap);
707 return rc;
708}
709
710/**
711 * Copies the contents of one flash region to another. You must erase the
712 * destination region prior to calling this function.
713 *
714 * @param flash_area_id_src The ID of the source flash area.
715 * @param flash_area_id_dst The ID of the destination flash area.
716 * @param off_src The offset within the source flash area to
717 * copy from.
718 * @param off_dst The offset within the destination flash area to
719 * copy to.
720 * @param sz The number of bytes to copy.
721 *
722 * @return 0 on success; nonzero on failure.
723 */
724static int
725boot_copy_sector(int flash_area_id_src, int flash_area_id_dst,
726 uint32_t off_src, uint32_t off_dst, uint32_t sz)
727{
728 const struct flash_area *fap_src;
729 const struct flash_area *fap_dst;
730 uint32_t bytes_copied;
731 int chunk_sz;
732 int rc;
733
734 static uint8_t buf[1024];
735
736 fap_src = NULL;
737 fap_dst = NULL;
738
739 rc = flash_area_open(flash_area_id_src, &fap_src);
740 if (rc != 0) {
741 rc = BOOT_EFLASH;
742 goto done;
743 }
744
745 rc = flash_area_open(flash_area_id_dst, &fap_dst);
746 if (rc != 0) {
747 rc = BOOT_EFLASH;
748 goto done;
749 }
750
751 bytes_copied = 0;
752 while (bytes_copied < sz) {
753 if (sz - bytes_copied > sizeof buf) {
754 chunk_sz = sizeof buf;
755 } else {
756 chunk_sz = sz - bytes_copied;
757 }
758
759 rc = flash_area_read(fap_src, off_src + bytes_copied, buf, chunk_sz);
760 if (rc != 0) {
761 rc = BOOT_EFLASH;
762 goto done;
763 }
764
765 rc = flash_area_write(fap_dst, off_dst + bytes_copied, buf, chunk_sz);
766 if (rc != 0) {
767 rc = BOOT_EFLASH;
768 goto done;
769 }
770
771 bytes_copied += chunk_sz;
772 }
773
774 rc = 0;
775
776done:
777 flash_area_close(fap_src);
778 flash_area_close(fap_dst);
779 return rc;
780}
781
Fabio Utzig2473ac02017-05-02 12:45:02 -0300782static inline int
783boot_status_init_by_id(int flash_area_id)
784{
785 const struct flash_area *fap;
786 struct boot_swap_state swap_state;
787 int rc;
788
789 rc = flash_area_open(flash_area_id, &fap);
790 assert(rc == 0);
791
792 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_1, &swap_state);
793 assert(rc == 0);
794
Fabio Utzigde8a38a2017-05-23 11:15:01 -0400795 if (swap_state.image_ok == BOOT_FLAG_SET) {
Fabio Utzig2473ac02017-05-02 12:45:02 -0300796 rc = boot_write_image_ok(fap);
797 assert(rc == 0);
798 }
799
800 rc = boot_write_magic(fap);
801 assert(rc == 0);
802
803 flash_area_close(fap);
804
805 return 0;
806}
807
808static int
809boot_erase_last_sector_by_id(int flash_area_id)
810{
811 uint8_t slot;
812 uint32_t last_sector;
813 struct flash_area *sectors;
814 int rc;
815
816 switch (flash_area_id) {
817 case FLASH_AREA_IMAGE_0:
818 slot = 0;
819 break;
820 case FLASH_AREA_IMAGE_1:
821 slot = 1;
822 break;
823 default:
824 return BOOT_EFLASH;
825 }
826
827 last_sector = boot_data.imgs[slot].num_sectors - 1;
828 sectors = boot_data.imgs[slot].sectors;
829 rc = boot_erase_sector(flash_area_id,
830 sectors[last_sector].fa_off - sectors[0].fa_off,
831 sectors[last_sector].fa_size);
832 assert(rc == 0);
833
834 return rc;
835}
836
Christopher Collins92ea77f2016-12-12 15:59:26 -0800837/**
838 * Swaps the contents of two flash regions within the two image slots.
839 *
840 * @param idx The index of the first sector in the range of
841 * sectors being swapped.
842 * @param sz The number of bytes to swap.
843 * @param bs The current boot status. This struct gets
844 * updated according to the outcome.
845 *
846 * @return 0 on success; nonzero on failure.
847 */
David Brown17609d82017-05-05 09:41:34 -0600848#ifndef BOOTUTIL_OVERWRITE_ONLY
Christopher Collins4772ac42017-02-27 20:08:01 -0800849static void
Christopher Collins92ea77f2016-12-12 15:59:26 -0800850boot_swap_sectors(int idx, uint32_t sz, struct boot_status *bs)
851{
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300852 const struct flash_area *fap;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800853 uint32_t copy_sz;
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300854 uint32_t trailer_sz;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800855 uint32_t img_off;
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300856 uint32_t scratch_trailer_off;
857 struct boot_swap_state swap_state;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800858 int rc;
859
860 /* Calculate offset from start of image area. */
861 img_off = boot_data.imgs[0].sectors[idx].fa_off -
862 boot_data.imgs[0].sectors[0].fa_off;
863
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300864 copy_sz = sz;
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300865 trailer_sz = boot_slots_trailer_sz(boot_data.write_sz);
Fabio Utzig9678c972017-05-23 11:28:56 -0400866
867 /* sz in this function is always is always sized on a multiple of the
868 * sector size. The check against the first address of the last sector
869 * is to determine if we're swapping the last sector. The last sector
870 * needs special handling because it's where the trailer lives. If we're
871 * copying it, we need to use scratch to write the trailer temporarily.
872 *
873 * NOTE: `use_scratch` is a temporary flag (never written to flash) which
874 * controls if special handling is needed (swapping last sector).
875 */
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300876 if (boot_data.imgs[0].sectors[idx].fa_off + sz >
877 boot_data.imgs[0].sectors[boot_data.imgs[0].num_sectors - 1].fa_off) {
878 copy_sz -= trailer_sz;
879 }
880
Fabio Utzig2473ac02017-05-02 12:45:02 -0300881 bs->use_scratch = (bs->idx == 0 && copy_sz != sz);
882
Christopher Collins92ea77f2016-12-12 15:59:26 -0800883 if (bs->state == 0) {
884 rc = boot_erase_sector(FLASH_AREA_IMAGE_SCRATCH, 0, sz);
Christopher Collins4772ac42017-02-27 20:08:01 -0800885 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800886
887 rc = boot_copy_sector(FLASH_AREA_IMAGE_1, FLASH_AREA_IMAGE_SCRATCH,
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300888 img_off, 0, copy_sz);
Christopher Collins4772ac42017-02-27 20:08:01 -0800889 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800890
Fabio Utzig2473ac02017-05-02 12:45:02 -0300891 if (bs->idx == 0) {
892 if (bs->use_scratch) {
893 boot_status_init_by_id(FLASH_AREA_IMAGE_SCRATCH);
894 } else {
895 /* Prepare the status area... here it is known that the
896 * last sector is not being used by the image data so it's
897 * safe to erase.
898 */
899 rc = boot_erase_last_sector_by_id(FLASH_AREA_IMAGE_0);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300900 assert(rc == 0);
Fabio Utzig2473ac02017-05-02 12:45:02 -0300901
902 boot_status_init_by_id(FLASH_AREA_IMAGE_0);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300903 }
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300904 }
905
Christopher Collins92ea77f2016-12-12 15:59:26 -0800906 bs->state = 1;
Christopher Collins4772ac42017-02-27 20:08:01 -0800907 rc = boot_write_status(bs);
908 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800909 }
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300910
Christopher Collins92ea77f2016-12-12 15:59:26 -0800911 if (bs->state == 1) {
912 rc = boot_erase_sector(FLASH_AREA_IMAGE_1, img_off, sz);
Christopher Collins4772ac42017-02-27 20:08:01 -0800913 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800914
Christopher Collins92ea77f2016-12-12 15:59:26 -0800915 rc = boot_copy_sector(FLASH_AREA_IMAGE_0, FLASH_AREA_IMAGE_1,
916 img_off, img_off, copy_sz);
Christopher Collins4772ac42017-02-27 20:08:01 -0800917 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800918
Fabio Utzig2473ac02017-05-02 12:45:02 -0300919 if (bs->idx == 0 && !bs->use_scratch) {
920 /* If not all sectors of the slot are being swapped,
921 * guarantee here that only slot0 will have the state.
922 */
923 rc = boot_erase_last_sector_by_id(FLASH_AREA_IMAGE_1);
924 assert(rc == 0);
925 }
926
Christopher Collins92ea77f2016-12-12 15:59:26 -0800927 bs->state = 2;
Christopher Collins4772ac42017-02-27 20:08:01 -0800928 rc = boot_write_status(bs);
929 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800930 }
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300931
Christopher Collins92ea77f2016-12-12 15:59:26 -0800932 if (bs->state == 2) {
933 rc = boot_erase_sector(FLASH_AREA_IMAGE_0, img_off, sz);
Christopher Collins4772ac42017-02-27 20:08:01 -0800934 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800935
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300936 /* NOTE: also copy trailer from scratch (has status info) */
Christopher Collins92ea77f2016-12-12 15:59:26 -0800937 rc = boot_copy_sector(FLASH_AREA_IMAGE_SCRATCH, FLASH_AREA_IMAGE_0,
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300938 0, img_off, copy_sz);
Christopher Collins4772ac42017-02-27 20:08:01 -0800939 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800940
Fabio Utzig94d998c2017-05-22 11:02:41 -0400941 if (bs->use_scratch) {
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300942 rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH, &fap);
943 assert(rc == 0);
944
945 scratch_trailer_off = boot_status_off(fap);
946
947 flash_area_close(fap);
948
949 rc = flash_area_open(FLASH_AREA_IMAGE_0, &fap);
950 assert(rc == 0);
951
952 /* copy current status that is being maintained in scratch */
953 rc = boot_copy_sector(FLASH_AREA_IMAGE_SCRATCH, FLASH_AREA_IMAGE_0,
954 scratch_trailer_off,
955 img_off + copy_sz + BOOT_MAGIC_SZ,
956 BOOT_STATUS_STATE_COUNT * boot_data.write_sz);
957 assert(rc == 0);
958
Fabio Utzig2473ac02017-05-02 12:45:02 -0300959 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SCRATCH,
960 &swap_state);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300961 assert(rc == 0);
962
Fabio Utzigde8a38a2017-05-23 11:15:01 -0400963 if (swap_state.image_ok == BOOT_FLAG_SET) {
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300964 rc = boot_write_image_ok(fap);
965 assert(rc == 0);
966 }
967
968 rc = boot_write_magic(fap);
969 assert(rc == 0);
970
971 flash_area_close(fap);
972 }
973
Christopher Collins92ea77f2016-12-12 15:59:26 -0800974 bs->idx++;
975 bs->state = 0;
Fabio Utzig2473ac02017-05-02 12:45:02 -0300976 bs->use_scratch = 0;
Christopher Collins4772ac42017-02-27 20:08:01 -0800977 rc = boot_write_status(bs);
978 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800979 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800980}
David Brown17609d82017-05-05 09:41:34 -0600981#endif /* not BOOTUTIL_OVERWRITE_ONLY */
Christopher Collins92ea77f2016-12-12 15:59:26 -0800982
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 */
David Brown17609d82017-05-05 09:41:34 -0600995#ifdef BOOTUTIL_OVERWRITE_ONLY
996static int
997boot_copy_image(struct boot_status *bs)
998{
999 int sect_count;
1000 int sect;
1001 int rc;
1002 uint32_t size = 0;
1003 uint32_t this_size;
1004
1005 BOOT_LOG_INF("Image upgrade slot1 -> slot0");
1006 BOOT_LOG_INF("Erasing slot0");
1007
1008 sect_count = boot_data.imgs[0].num_sectors;
1009 for (sect = 0; sect < sect_count; sect++) {
1010 this_size = boot_data.imgs[0].sectors[sect].fa_size;
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%x bytes",
1020 size);
1021 rc = boot_copy_sector(FLASH_AREA_IMAGE_1, FLASH_AREA_IMAGE_0,
1022 0, 0, size);
1023
1024 /* Erase slot 1 so that we don't do the upgrade on every boot.
1025 * TODO: Perhaps verify slot 0's signature again? */
1026 rc = boot_erase_sector(FLASH_AREA_IMAGE_1,
1027 0, boot_data.imgs[1].sectors[0].fa_size);
1028 assert(rc == 0);
1029
1030 return 0;
1031}
1032#else
Christopher Collins92ea77f2016-12-12 15:59:26 -08001033static int
1034boot_copy_image(struct boot_status *bs)
1035{
1036 uint32_t sz;
1037 int first_sector_idx;
1038 int last_sector_idx;
1039 int swap_idx;
Fabio Utzig2473ac02017-05-02 12:45:02 -03001040 struct image_header *hdr;
1041 uint32_t size;
1042 uint32_t copy_size;
1043 struct image_header tmp_hdr;
1044 int rc;
1045
1046 /* FIXME: just do this if asked by user? */
1047
1048 size = copy_size = 0;
1049
1050 hdr = &boot_data.imgs[0].hdr;
1051 if (hdr->ih_magic == IMAGE_MAGIC) {
1052 copy_size = hdr->ih_hdr_size + hdr->ih_img_size + hdr->ih_tlv_size;
1053 }
1054
1055 hdr = &boot_data.imgs[1].hdr;
1056 if (hdr->ih_magic == IMAGE_MAGIC) {
1057 size = hdr->ih_hdr_size + hdr->ih_img_size + hdr->ih_tlv_size;
1058 }
1059
1060 if (!size || !copy_size || size == copy_size) {
1061 rc = boot_read_image_header(2, &tmp_hdr);
1062 assert(rc == 0);
1063
1064 hdr = &tmp_hdr;
1065 if (hdr->ih_magic == IMAGE_MAGIC) {
1066 if (!size) {
1067 size = hdr->ih_hdr_size + hdr->ih_img_size + hdr->ih_tlv_size;
1068 } else {
1069 copy_size = hdr->ih_hdr_size + hdr->ih_img_size + hdr->ih_tlv_size;
1070 }
1071 }
1072 }
1073
1074 if (size > copy_size) {
1075 copy_size = size;
1076 }
1077
1078 size = 0;
1079 last_sector_idx = 0;
1080 while (1) {
1081 size += boot_data.imgs[0].sectors[last_sector_idx].fa_size;
1082 if (size >= copy_size) {
1083 break;
1084 }
1085 last_sector_idx++;
1086 }
Christopher Collins92ea77f2016-12-12 15:59:26 -08001087
1088 swap_idx = 0;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001089 while (last_sector_idx >= 0) {
1090 sz = boot_copy_sz(last_sector_idx, &first_sector_idx);
1091 if (swap_idx >= bs->idx) {
1092 boot_swap_sectors(first_sector_idx, sz, bs);
1093 }
1094
1095 last_sector_idx = first_sector_idx - 1;
1096 swap_idx++;
1097 }
1098
1099 return 0;
1100}
David Brown17609d82017-05-05 09:41:34 -06001101#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -08001102
1103/**
1104 * Marks a test image in slot 0 as fully copied.
1105 */
1106static int
1107boot_finalize_test_swap(void)
1108{
1109 const struct flash_area *fap;
1110 int rc;
1111
1112 rc = flash_area_open(FLASH_AREA_IMAGE_0, &fap);
1113 if (rc != 0) {
1114 return BOOT_EFLASH;
1115 }
1116
1117 rc = boot_write_copy_done(fap);
1118 if (rc != 0) {
1119 return rc;
1120 }
1121
1122 return 0;
1123}
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 */
1130static int
1131boot_finalize_revert_swap(void)
1132{
1133 const struct flash_area *fap;
1134 struct boot_swap_state state_slot0;
1135 int rc;
1136
1137 rc = flash_area_open(FLASH_AREA_IMAGE_0, &fap);
1138 if (rc != 0) {
1139 return BOOT_EFLASH;
1140 }
1141
1142 rc = boot_read_swap_state(fap, &state_slot0);
1143 if (rc != 0) {
1144 return BOOT_EFLASH;
1145 }
1146
1147 if (state_slot0.magic == BOOT_MAGIC_UNSET) {
1148 rc = boot_write_magic(fap);
1149 if (rc != 0) {
1150 return rc;
1151 }
1152 }
1153
Fabio Utzigde8a38a2017-05-23 11:15:01 -04001154 if (state_slot0.copy_done == BOOT_FLAG_UNSET) {
Christopher Collins92ea77f2016-12-12 15:59:26 -08001155 rc = boot_write_copy_done(fap);
1156 if (rc != 0) {
1157 return rc;
1158 }
1159 }
1160
Fabio Utzigde8a38a2017-05-23 11:15:01 -04001161 if (state_slot0.image_ok == BOOT_FLAG_UNSET) {
Christopher Collins92ea77f2016-12-12 15:59:26 -08001162 rc = boot_write_image_ok(fap);
1163 if (rc != 0) {
1164 return rc;
1165 }
1166 }
1167
1168 return 0;
1169}
1170
1171/**
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001172 * Performs an image swap if one is required.
1173 *
1174 * @param out_swap_type On success, the type of swap performed gets
1175 * written here.
1176 *
1177 * @return 0 on success; nonzero on failure.
1178 */
1179static int
1180boot_swap_if_needed(int *out_swap_type)
1181{
1182 struct boot_status bs;
1183 int swap_type;
1184 int rc;
1185
1186 /* Determine if we rebooted in the middle of an image swap
1187 * operation.
1188 */
1189 rc = boot_read_status(&bs);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001190 assert(rc == 0);
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001191 if (rc != 0) {
1192 return rc;
1193 }
1194
1195 /* If a partial swap was detected, complete it. */
1196 if (bs.idx != 0 || bs.state != 0) {
1197 rc = boot_copy_image(&bs);
1198 assert(rc == 0);
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:
Christopher Collinsfd7eb5c2016-12-21 13:46:08 -08001208 case BOOT_SWAP_TYPE_PERM:
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001209 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/**
Christopher Collins92ea77f2016-12-12 15:59:26 -08001221 * 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{
Christopher Collins92ea77f2016-12-12 15:59:26 -08001231 int swap_type;
1232 int slot;
1233 int rc;
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
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001238 * any effect in older gcc versions (e.g., 4.8.4).
Christopher Collins92ea77f2016-12-12 15:59:26 -08001239 */
1240 static struct flash_area slot0_sectors[BOOT_MAX_IMG_SECTORS];
1241 static struct flash_area slot1_sectors[BOOT_MAX_IMG_SECTORS];
1242 boot_data.imgs[0].sectors = slot0_sectors;
1243 boot_data.imgs[1].sectors = slot1_sectors;
1244
1245 /* Determine the sector layout of the image slots and scratch area. */
1246 rc = boot_read_sectors();
1247 if (rc != 0) {
1248 return rc;
1249 }
1250
1251 /* Attempt to read an image header from each slot. */
1252 rc = boot_read_image_headers();
1253 if (rc != 0) {
1254 return rc;
1255 }
1256
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001257 /* If the image slots aren't compatible, no swap is possible. Just boot
1258 * into slot 0.
1259 */
1260 if (boot_slots_compatible()) {
1261 rc = boot_swap_if_needed(&swap_type);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001262 assert(rc == 0);
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001263 if (rc != 0) {
1264 return rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001265 }
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001266 } else {
1267 swap_type = BOOT_SWAP_TYPE_NONE;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001268 }
1269
1270 switch (swap_type) {
1271 case BOOT_SWAP_TYPE_NONE:
Fabio Utzig19356bf2017-05-11 16:19:36 -03001272#ifdef MCUBOOT_VALIDATE_SLOT0
David Brownd930ec62016-12-14 07:59:48 -07001273 rc = boot_validate_slot(0);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001274 assert(rc == 0);
David Brownd930ec62016-12-14 07:59:48 -07001275 if (rc != 0) {
1276 return BOOT_EBADIMAGE;
1277 }
1278#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -08001279 slot = 0;
1280 break;
1281
1282 case BOOT_SWAP_TYPE_TEST:
Christopher Collinsfd7eb5c2016-12-21 13:46:08 -08001283 case BOOT_SWAP_TYPE_PERM:
Christopher Collins92ea77f2016-12-12 15:59:26 -08001284 slot = 1;
1285 boot_finalize_test_swap();
1286 break;
1287
1288 case BOOT_SWAP_TYPE_REVERT:
1289 slot = 1;
1290 boot_finalize_revert_swap();
1291 break;
1292
1293 case BOOT_SWAP_TYPE_FAIL:
1294 /* The image in slot 1 was invalid and is now erased. Ensure we don't
1295 * try to boot into it again on the next reboot. Do this by pretending
1296 * we just reverted back to slot 0.
1297 */
1298 slot = 0;
1299 boot_finalize_revert_swap();
1300 break;
1301
1302 default:
1303 assert(0);
1304 slot = 0;
1305 break;
1306 }
1307
1308 /* Always boot from the primary slot. */
1309 rsp->br_flash_id = boot_data.imgs[0].sectors[0].fa_device_id;
1310 rsp->br_image_addr = boot_data.imgs[0].sectors[0].fa_off;
1311 rsp->br_hdr = &boot_data.imgs[slot].hdr;
1312
1313 return 0;
1314}
1315
1316int
1317split_go(int loader_slot, int split_slot, void **entry)
1318{
1319 const struct flash_area *loader_fap;
1320 const struct flash_area *app_fap;
1321 struct flash_area *sectors;
Christopher Collins034a6202017-01-11 12:19:37 -08001322 uintptr_t entry_val;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001323 int loader_flash_id;
1324 int app_flash_id;
1325 int rc;
1326
1327 app_fap = NULL;
1328 loader_fap = NULL;
1329
1330 sectors = malloc(BOOT_MAX_IMG_SECTORS * 2 * sizeof *sectors);
1331 if (sectors == NULL) {
1332 rc = SPLIT_GO_ERR;
1333 goto done;
1334 }
1335 boot_data.imgs[0].sectors = sectors + 0;
1336 boot_data.imgs[1].sectors = sectors + BOOT_MAX_IMG_SECTORS;
1337
1338 /* Determine the sector layout of the image slots and scratch area. */
1339 rc = boot_read_sectors();
1340 if (rc != 0) {
1341 rc = SPLIT_GO_ERR;
1342 goto done;
1343 }
1344
1345 rc = boot_read_image_headers();
1346 if (rc != 0) {
1347 goto done;
1348 }
1349
1350 app_flash_id = flash_area_id_from_image_slot(split_slot);
1351 rc = flash_area_open(app_flash_id, &app_fap);
1352 if (rc != 0) {
1353 rc = BOOT_EFLASH;
1354 goto done;
1355 }
1356
1357 loader_flash_id = flash_area_id_from_image_slot(loader_slot);
1358 rc = flash_area_open(loader_flash_id, &loader_fap);
1359 if (rc != 0) {
1360 rc = BOOT_EFLASH;
1361 goto done;
1362 }
1363
1364 /* Don't check the bootable image flag because we could really call a
1365 * bootable or non-bootable image. Just validate that the image check
1366 * passes which is distinct from the normal check.
1367 */
1368 rc = split_image_check(&boot_data.imgs[split_slot].hdr,
1369 app_fap,
1370 &boot_data.imgs[loader_slot].hdr,
1371 loader_fap);
1372 if (rc != 0) {
1373 rc = SPLIT_GO_NON_MATCHING;
1374 goto done;
1375 }
1376
1377 entry_val = boot_data.imgs[split_slot].sectors[0].fa_off +
1378 boot_data.imgs[split_slot].hdr.ih_hdr_size;
Christopher Collins034a6202017-01-11 12:19:37 -08001379 *entry = (void *) entry_val;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001380 rc = SPLIT_GO_OK;
1381
1382done:
1383 free(sectors);
1384 flash_area_close(app_fap);
1385 flash_area_close(loader_fap);
1386 return rc;
1387}