blob: ab8ac7bf95850651221f1efb0a9aab5106161bc4 [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>
David Brown52eee562017-07-05 11:25:09 -060027#include <stdbool.h>
Christopher Collins92ea77f2016-12-12 15:59:26 -080028#include <inttypes.h>
29#include <stdlib.h>
30#include <string.h>
Christopher Collins92ea77f2016-12-12 15:59:26 -080031#include <hal/hal_flash.h>
32#include <os/os_malloc.h>
33#include "bootutil/bootutil.h"
34#include "bootutil/image.h"
35#include "bootutil_priv.h"
36
Marti Bolivarfd20c762017-02-07 16:52:50 -050037#define BOOT_LOG_LEVEL BOOT_LOG_LEVEL_INFO
38#include "bootutil/bootutil_log.h"
39
Fabio Utzigba1fbe62017-07-21 14:01:20 -030040#ifdef MCUBOOT_MYNEWT
41#include "mcuboot_config/mcuboot_config.h"
Fabio Utzigeed80b62017-06-10 08:03:05 -030042#endif
43
Marti Bolivar9b1f8bb2017-06-12 15:24:13 -040044static struct boot_loader_state boot_data;
Christopher Collins92ea77f2016-12-12 15:59:26 -080045
Fabio Utziga0e1cce2017-11-23 20:04:01 -020046#ifdef MCUBOOT_VALIDATE_SLOT0
47static int boot_status_fails = 0;
48#define BOOT_STATUS_ASSERT(x) \
49 do { \
50 if (x) { \
51 boot_status_fails++; \
52 } \
53 } while (0)
54#else
Fabio Utzig57c40f72017-12-12 21:48:30 -020055#define BOOT_STATUS_ASSERT(x) ASSERT(x)
Fabio Utziga0e1cce2017-11-23 20:04:01 -020056#endif
57
Christopher Collins92ea77f2016-12-12 15:59:26 -080058struct boot_status_table {
59 /**
60 * For each field, a value of 0 means "any".
61 */
62 uint8_t bst_magic_slot0;
63 uint8_t bst_magic_scratch;
64 uint8_t bst_copy_done_slot0;
65 uint8_t bst_status_source;
66};
67
68/**
69 * This set of tables maps swap state contents to boot status location.
70 * When searching for a match, these tables must be iterated in order.
71 */
72static const struct boot_status_table boot_status_tables[] = {
73 {
74 /* | slot-0 | scratch |
75 * ----------+------------+------------|
76 * magic | Good | Any |
77 * copy-done | 0x01 | N/A |
78 * ----------+------------+------------'
79 * source: none |
80 * ------------------------------------'
81 */
82 .bst_magic_slot0 = BOOT_MAGIC_GOOD,
83 .bst_magic_scratch = 0,
84 .bst_copy_done_slot0 = 0x01,
85 .bst_status_source = BOOT_STATUS_SOURCE_NONE,
86 },
87
88 {
89 /* | slot-0 | scratch |
90 * ----------+------------+------------|
91 * magic | Good | Any |
92 * copy-done | 0xff | N/A |
93 * ----------+------------+------------'
94 * source: slot 0 |
95 * ------------------------------------'
96 */
97 .bst_magic_slot0 = BOOT_MAGIC_GOOD,
98 .bst_magic_scratch = 0,
99 .bst_copy_done_slot0 = 0xff,
100 .bst_status_source = BOOT_STATUS_SOURCE_SLOT0,
101 },
102
103 {
104 /* | slot-0 | scratch |
105 * ----------+------------+------------|
106 * magic | Any | Good |
107 * copy-done | Any | N/A |
108 * ----------+------------+------------'
109 * source: scratch |
110 * ------------------------------------'
111 */
112 .bst_magic_slot0 = 0,
113 .bst_magic_scratch = BOOT_MAGIC_GOOD,
114 .bst_copy_done_slot0 = 0,
115 .bst_status_source = BOOT_STATUS_SOURCE_SCRATCH,
116 },
117
118 {
119 /* | slot-0 | scratch |
120 * ----------+------------+------------|
121 * magic | Unset | Any |
122 * copy-done | 0xff | N/A |
123 * ----------+------------+------------|
124 * source: varies |
125 * ------------------------------------+------------------------------+
126 * This represents one of two cases: |
127 * o No swaps ever (no status to read, so no harm in checking). |
128 * o Mid-revert; status in slot 0. |
129 * -------------------------------------------------------------------'
130 */
131 .bst_magic_slot0 = BOOT_MAGIC_UNSET,
132 .bst_magic_scratch = 0,
133 .bst_copy_done_slot0 = 0xff,
134 .bst_status_source = BOOT_STATUS_SOURCE_SLOT0,
135 },
136};
137
138#define BOOT_STATUS_TABLES_COUNT \
139 (sizeof boot_status_tables / sizeof boot_status_tables[0])
140
Marti Bolivarfd20c762017-02-07 16:52:50 -0500141#define BOOT_LOG_SWAP_STATE(area, state) \
142 BOOT_LOG_INF("%s: magic=%s, copy_done=0x%x, image_ok=0x%x", \
143 (area), \
144 ((state)->magic == BOOT_MAGIC_GOOD ? "good" : \
145 (state)->magic == BOOT_MAGIC_UNSET ? "unset" : \
146 "bad"), \
147 (state)->copy_done, \
148 (state)->image_ok)
149
Christopher Collins92ea77f2016-12-12 15:59:26 -0800150/**
151 * Determines where in flash the most recent boot status is stored. The boot
152 * status is necessary for completing a swap that was interrupted by a boot
153 * loader reset.
154 *
155 * @return A BOOT_STATUS_SOURCE_[...] code indicating where * status should be read from.
156 */
157static int
158boot_status_source(void)
159{
160 const struct boot_status_table *table;
161 struct boot_swap_state state_scratch;
162 struct boot_swap_state state_slot0;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800163 int rc;
Fabio Utzigcd5774b2017-11-29 10:18:26 -0200164 size_t i;
Marti Bolivarfd20c762017-02-07 16:52:50 -0500165 uint8_t source;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800166
Fabio Utzig2473ac02017-05-02 12:45:02 -0300167 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_0, &state_slot0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800168 assert(rc == 0);
169
Fabio Utzig2473ac02017-05-02 12:45:02 -0300170 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SCRATCH, &state_scratch);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800171 assert(rc == 0);
172
Marti Bolivarfd20c762017-02-07 16:52:50 -0500173 BOOT_LOG_SWAP_STATE("Image 0", &state_slot0);
Marti Bolivarfd20c762017-02-07 16:52:50 -0500174 BOOT_LOG_SWAP_STATE("Scratch", &state_scratch);
175
Christopher Collins92ea77f2016-12-12 15:59:26 -0800176 for (i = 0; i < BOOT_STATUS_TABLES_COUNT; i++) {
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300177 table = &boot_status_tables[i];
Christopher Collins92ea77f2016-12-12 15:59:26 -0800178
179 if ((table->bst_magic_slot0 == 0 ||
180 table->bst_magic_slot0 == state_slot0.magic) &&
181 (table->bst_magic_scratch == 0 ||
182 table->bst_magic_scratch == state_scratch.magic) &&
183 (table->bst_copy_done_slot0 == 0 ||
184 table->bst_copy_done_slot0 == state_slot0.copy_done)) {
Marti Bolivarfd20c762017-02-07 16:52:50 -0500185 source = table->bst_status_source;
186 BOOT_LOG_INF("Boot source: %s",
187 source == BOOT_STATUS_SOURCE_NONE ? "none" :
188 source == BOOT_STATUS_SOURCE_SCRATCH ? "scratch" :
189 source == BOOT_STATUS_SOURCE_SLOT0 ? "slot 0" :
190 "BUG; can't happen");
191 return source;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800192 }
193 }
194
Marti Bolivarfd20c762017-02-07 16:52:50 -0500195 BOOT_LOG_INF("Boot source: none");
Christopher Collins92ea77f2016-12-12 15:59:26 -0800196 return BOOT_STATUS_SOURCE_NONE;
197}
198
199/**
200 * Calculates the type of swap that just completed.
Fabio Utzigb5b2f552017-06-30 10:03:47 -0300201 *
202 * This is used when a swap is interrupted by an external event. After
203 * finishing the swap operation determines what the initial request was.
Christopher Collins92ea77f2016-12-12 15:59:26 -0800204 */
205static int
206boot_previous_swap_type(void)
207{
208 int post_swap_type;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800209
210 post_swap_type = boot_swap_type();
211
Fabio Utzigb5b2f552017-06-30 10:03:47 -0300212 switch (post_swap_type) {
213 case BOOT_SWAP_TYPE_NONE : return BOOT_SWAP_TYPE_PERM;
214 case BOOT_SWAP_TYPE_REVERT : return BOOT_SWAP_TYPE_TEST;
215 case BOOT_SWAP_TYPE_PANIC : return BOOT_SWAP_TYPE_PANIC;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800216 }
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300217
Fabio Utzigb5b2f552017-06-30 10:03:47 -0300218 return BOOT_SWAP_TYPE_FAIL;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800219}
220
David Brownf5b33d82017-09-01 10:58:27 -0600221/*
222 * Compute the total size of the given image. Includes the size of
223 * the TLVs.
224 */
Fabio Utzig13d9e352017-10-05 20:32:31 -0300225#if !defined(MCUBOOT_OVERWRITE_ONLY) || defined(MCUBOOT_OVERWRITE_ONLY_FAST)
David Brownf5b33d82017-09-01 10:58:27 -0600226static int
227boot_read_image_size(int slot, struct image_header *hdr, uint32_t *size)
228{
229 const struct flash_area *fap;
230 struct image_tlv_info info;
231 int area_id;
232 int rc;
233
234 area_id = flash_area_id_from_image_slot(slot);
235 rc = flash_area_open(area_id, &fap);
236 if (rc != 0) {
237 rc = BOOT_EFLASH;
238 goto done;
239 }
240
241 rc = flash_area_read(fap, hdr->ih_hdr_size + hdr->ih_img_size,
242 &info, sizeof(info));
243 if (rc != 0) {
244 rc = BOOT_EFLASH;
245 goto done;
246 }
247 if (info.it_magic != IMAGE_TLV_INFO_MAGIC) {
248 rc = BOOT_EBADIMAGE;
249 goto done;
250 }
251 *size = hdr->ih_hdr_size + hdr->ih_img_size + info.it_tlv_tot;
252 rc = 0;
253
254done:
255 flash_area_close(fap);
Fabio Utzig2eebf112017-09-04 15:25:08 -0300256 return rc;
David Brownf5b33d82017-09-01 10:58:27 -0600257}
Fabio Utzig36ec0e72017-09-05 08:10:33 -0300258#endif /* !MCUBOOT_OVERWRITE_ONLY */
David Brownf5b33d82017-09-01 10:58:27 -0600259
Fabio Utzigc08ed212017-06-20 19:28:36 -0300260static int
Christopher Collins92ea77f2016-12-12 15:59:26 -0800261boot_read_image_header(int slot, struct image_header *out_hdr)
262{
263 const struct flash_area *fap;
264 int area_id;
265 int rc;
266
267 area_id = flash_area_id_from_image_slot(slot);
268 rc = flash_area_open(area_id, &fap);
269 if (rc != 0) {
270 rc = BOOT_EFLASH;
271 goto done;
272 }
273
274 rc = flash_area_read(fap, 0, out_hdr, sizeof *out_hdr);
275 if (rc != 0) {
276 rc = BOOT_EFLASH;
277 goto done;
278 }
279
280 rc = 0;
281
282done:
283 flash_area_close(fap);
284 return rc;
285}
286
287static int
Fabio Utzig9c25fa72017-12-12 14:57:20 -0200288boot_read_image_headers(bool require_all)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800289{
290 int rc;
291 int i;
292
293 for (i = 0; i < BOOT_NUM_SLOTS; i++) {
Marti Bolivarf804f622017-06-12 15:41:48 -0400294 rc = boot_read_image_header(i, boot_img_hdr(&boot_data, i));
Christopher Collins92ea77f2016-12-12 15:59:26 -0800295 if (rc != 0) {
Fabio Utzig9c25fa72017-12-12 14:57:20 -0200296 /* If `require_all` is set, fail on any single fail, otherwise
297 * if at least the first slot's header was read successfully,
298 * then the boot loader can attempt a boot.
299 *
300 * Failure to read any headers is a fatal error.
Christopher Collins0ff3c6c2016-12-21 12:04:17 -0800301 */
Fabio Utzig9c25fa72017-12-12 14:57:20 -0200302 if (i > 0 && !require_all) {
Christopher Collins0ff3c6c2016-12-21 12:04:17 -0800303 return 0;
304 } else {
305 return rc;
306 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800307 }
308 }
309
310 return 0;
311}
312
313static uint8_t
314boot_write_sz(void)
315{
316 uint8_t elem_sz;
317 uint8_t align;
318
319 /* Figure out what size to write update status update as. The size depends
320 * on what the minimum write size is for scratch area, active image slot.
321 * We need to use the bigger of those 2 values.
322 */
Marti Bolivare2587152017-06-12 15:52:05 -0400323 elem_sz = hal_flash_align(boot_img_fa_device_id(&boot_data, 0));
324 align = hal_flash_align(boot_scratch_fa_device_id(&boot_data));
Christopher Collins92ea77f2016-12-12 15:59:26 -0800325 if (align > elem_sz) {
326 elem_sz = align;
327 }
328
329 return elem_sz;
330}
331
Christopher Collins0ff3c6c2016-12-21 12:04:17 -0800332static int
333boot_slots_compatible(void)
334{
Marti Bolivard3269fd2017-06-12 16:31:12 -0400335 size_t num_sectors_0 = boot_img_num_sectors(&boot_data, 0);
336 size_t num_sectors_1 = boot_img_num_sectors(&boot_data, 1);
337 size_t size_0, size_1;
338 size_t i;
Christopher Collins0ff3c6c2016-12-21 12:04:17 -0800339
340 /* Ensure both image slots have identical sector layouts. */
Marti Bolivard3269fd2017-06-12 16:31:12 -0400341 if (num_sectors_0 != num_sectors_1) {
Christopher Collins0ff3c6c2016-12-21 12:04:17 -0800342 return 0;
343 }
Marti Bolivard3269fd2017-06-12 16:31:12 -0400344 for (i = 0; i < num_sectors_0; i++) {
345 size_0 = boot_img_sector_size(&boot_data, 0, i);
346 size_1 = boot_img_sector_size(&boot_data, 1, i);
347 if (size_0 != size_1) {
Christopher Collins0ff3c6c2016-12-21 12:04:17 -0800348 return 0;
349 }
350 }
351
352 return 1;
353}
354
Christopher Collins92ea77f2016-12-12 15:59:26 -0800355/**
356 * Determines the sector layout of both image slots and the scratch area.
357 * This information is necessary for calculating the number of bytes to erase
358 * and copy during an image swap. The information collected during this
359 * function is used to populate the boot_data global.
360 */
361static int
362boot_read_sectors(void)
363{
Christopher Collins92ea77f2016-12-12 15:59:26 -0800364 int rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800365
Marti Bolivarcca28a92017-06-12 16:52:22 -0400366 rc = boot_initialize_area(&boot_data, FLASH_AREA_IMAGE_0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800367 if (rc != 0) {
368 return BOOT_EFLASH;
369 }
370
Marti Bolivarcca28a92017-06-12 16:52:22 -0400371 rc = boot_initialize_area(&boot_data, FLASH_AREA_IMAGE_1);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800372 if (rc != 0) {
373 return BOOT_EFLASH;
374 }
375
Marti Bolivare10a7392017-06-14 16:20:07 -0400376 BOOT_WRITE_SZ(&boot_data) = boot_write_sz();
Christopher Collins92ea77f2016-12-12 15:59:26 -0800377
378 return 0;
379}
380
381static uint32_t
382boot_status_internal_off(int idx, int state, int elem_sz)
383{
384 int idx_sz;
385
386 idx_sz = elem_sz * BOOT_STATUS_STATE_COUNT;
387
388 return idx * idx_sz + state * elem_sz;
389}
390
391/**
392 * Reads the status of a partially-completed swap, if any. This is necessary
393 * to recover in case the boot lodaer was reset in the middle of a swap
394 * operation.
395 */
396static int
397boot_read_status_bytes(const struct flash_area *fap, struct boot_status *bs)
398{
399 uint32_t off;
400 uint8_t status;
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300401 int max_entries;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800402 int found;
Fabio Utziga0e1cce2017-11-23 20:04:01 -0200403 int found_idx;
404 int invalid;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800405 int rc;
406 int i;
407
408 off = boot_status_off(fap);
Fabio Utzig4cee4f72017-05-22 10:59:57 -0400409 max_entries = boot_status_entries(fap);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300410
Christopher Collins92ea77f2016-12-12 15:59:26 -0800411 found = 0;
Fabio Utziga0e1cce2017-11-23 20:04:01 -0200412 found_idx = 0;
413 invalid = 0;
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300414 for (i = 0; i < max_entries; i++) {
Marti Bolivare10a7392017-06-14 16:20:07 -0400415 rc = flash_area_read(fap, off + i * BOOT_WRITE_SZ(&boot_data),
416 &status, 1);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800417 if (rc != 0) {
418 return BOOT_EFLASH;
419 }
420
421 if (status == 0xff) {
Fabio Utziga0e1cce2017-11-23 20:04:01 -0200422 if (found && !found_idx) {
423 found_idx = i;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800424 }
425 } else if (!found) {
426 found = 1;
Fabio Utziga0e1cce2017-11-23 20:04:01 -0200427 } else if (found_idx) {
428 invalid = 1;
429 break;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800430 }
431 }
432
Fabio Utziga0e1cce2017-11-23 20:04:01 -0200433 if (invalid) {
434 /* This means there was an error writing status on the last
435 * swap. Tell user and move on to validation!
436 */
437 BOOT_LOG_ERR("Detected inconsistent status!");
438
439#if !defined(MCUBOOT_VALIDATE_SLOT0)
440 /* With validation of slot0 disabled, there is no way to be sure the
441 * swapped slot0 is OK, so abort!
442 */
443 assert(0);
444#endif
445 }
446
Christopher Collins92ea77f2016-12-12 15:59:26 -0800447 if (found) {
Fabio Utziga0e1cce2017-11-23 20:04:01 -0200448 if (!found_idx) {
449 found_idx = i;
450 }
451 found_idx--;
452 bs->idx = found_idx / BOOT_STATUS_STATE_COUNT;
453 bs->state = found_idx % BOOT_STATUS_STATE_COUNT;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800454 }
455
456 return 0;
457}
458
459/**
460 * Reads the boot status from the flash. The boot status contains
461 * the current state of an interrupted image copy operation. If the boot
462 * status is not present, or it indicates that previous copy finished,
463 * there is no operation in progress.
464 */
465static int
466boot_read_status(struct boot_status *bs)
467{
468 const struct flash_area *fap;
469 int status_loc;
470 int area_id;
471 int rc;
472
473 memset(bs, 0, sizeof *bs);
474
475 status_loc = boot_status_source();
476 switch (status_loc) {
477 case BOOT_STATUS_SOURCE_NONE:
478 return 0;
479
480 case BOOT_STATUS_SOURCE_SCRATCH:
481 area_id = FLASH_AREA_IMAGE_SCRATCH;
482 break;
483
484 case BOOT_STATUS_SOURCE_SLOT0:
485 area_id = FLASH_AREA_IMAGE_0;
486 break;
487
488 default:
489 assert(0);
490 return BOOT_EBADARGS;
491 }
492
493 rc = flash_area_open(area_id, &fap);
494 if (rc != 0) {
495 return BOOT_EFLASH;
496 }
497
Fabio Utzig46490722017-09-04 15:34:32 -0300498 rc = boot_read_status_bytes(fap, bs);
499
500 flash_area_close(fap);
501 return rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800502}
503
504/**
505 * Writes the supplied boot status to the flash file system. The boot status
506 * contains the current state of an in-progress image copy operation.
507 *
508 * @param bs The boot status to write.
509 *
510 * @return 0 on success; nonzero on failure.
511 */
512int
513boot_write_status(struct boot_status *bs)
514{
515 const struct flash_area *fap;
516 uint32_t off;
517 int area_id;
518 int rc;
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300519 uint8_t buf[BOOT_MAX_ALIGN];
David Brown9d725462017-01-23 15:50:58 -0700520 uint8_t align;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800521
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300522 /* NOTE: The first sector copied (that is the last sector on slot) contains
523 * the trailer. Since in the last step SLOT 0 is erased, the first
524 * two status writes go to the scratch which will be copied to SLOT 0!
525 */
526
Fabio Utzig2473ac02017-05-02 12:45:02 -0300527 if (bs->use_scratch) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800528 /* Write to scratch. */
529 area_id = FLASH_AREA_IMAGE_SCRATCH;
530 } else {
531 /* Write to slot 0. */
532 area_id = FLASH_AREA_IMAGE_0;
533 }
534
535 rc = flash_area_open(area_id, &fap);
536 if (rc != 0) {
537 rc = BOOT_EFLASH;
538 goto done;
539 }
540
541 off = boot_status_off(fap) +
Marti Bolivare10a7392017-06-14 16:20:07 -0400542 boot_status_internal_off(bs->idx, bs->state,
543 BOOT_WRITE_SZ(&boot_data));
Christopher Collins92ea77f2016-12-12 15:59:26 -0800544
David Brown9d725462017-01-23 15:50:58 -0700545 align = hal_flash_align(fap->fa_device_id);
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300546 memset(buf, 0xFF, BOOT_MAX_ALIGN);
David Brown9d725462017-01-23 15:50:58 -0700547 buf[0] = bs->state;
548
549 rc = flash_area_write(fap, off, buf, align);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800550 if (rc != 0) {
551 rc = BOOT_EFLASH;
552 goto done;
553 }
554
555 rc = 0;
556
557done:
558 flash_area_close(fap);
559 return rc;
560}
561
562/*
563 * Validate image hash/signature in a slot.
564 */
565static int
566boot_image_check(struct image_header *hdr, const struct flash_area *fap)
567{
David Browndb1d9d32017-01-06 11:07:54 -0700568 static uint8_t tmpbuf[BOOT_TMPBUF_SZ];
Christopher Collins92ea77f2016-12-12 15:59:26 -0800569
Christopher Collins92ea77f2016-12-12 15:59:26 -0800570 if (bootutil_img_validate(hdr, fap, tmpbuf, BOOT_TMPBUF_SZ,
571 NULL, 0, NULL)) {
572 return BOOT_EBADIMAGE;
573 }
574 return 0;
575}
576
577static int
578split_image_check(struct image_header *app_hdr,
579 const struct flash_area *app_fap,
580 struct image_header *loader_hdr,
581 const struct flash_area *loader_fap)
582{
583 static void *tmpbuf;
584 uint8_t loader_hash[32];
585
586 if (!tmpbuf) {
587 tmpbuf = malloc(BOOT_TMPBUF_SZ);
588 if (!tmpbuf) {
589 return BOOT_ENOMEM;
590 }
591 }
592
593 if (bootutil_img_validate(loader_hdr, loader_fap, tmpbuf, BOOT_TMPBUF_SZ,
594 NULL, 0, loader_hash)) {
595 return BOOT_EBADIMAGE;
596 }
597
598 if (bootutil_img_validate(app_hdr, app_fap, tmpbuf, BOOT_TMPBUF_SZ,
599 loader_hash, 32, NULL)) {
600 return BOOT_EBADIMAGE;
601 }
602
603 return 0;
604}
605
606static int
David Brownd930ec62016-12-14 07:59:48 -0700607boot_validate_slot(int slot)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800608{
609 const struct flash_area *fap;
Marti Bolivarf804f622017-06-12 15:41:48 -0400610 struct image_header *hdr;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800611 int rc;
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300612
Marti Bolivarf804f622017-06-12 15:41:48 -0400613 hdr = boot_img_hdr(&boot_data, slot);
614 if (hdr->ih_magic == 0xffffffff || hdr->ih_flags & IMAGE_F_NON_BOOTABLE) {
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300615 /* No bootable image in slot; continue booting from slot 0. */
Christopher Collins92ea77f2016-12-12 15:59:26 -0800616 return -1;
617 }
618
David Brownd930ec62016-12-14 07:59:48 -0700619 rc = flash_area_open(flash_area_id_from_image_slot(slot), &fap);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800620 if (rc != 0) {
621 return BOOT_EFLASH;
622 }
623
Marti Bolivarf804f622017-06-12 15:41:48 -0400624 if ((hdr->ih_magic != IMAGE_MAGIC || boot_image_check(hdr, fap) != 0)) {
David Brownb38e0442017-02-24 13:57:12 -0700625 if (slot != 0) {
626 flash_area_erase(fap, 0, fap->fa_size);
627 /* Image in slot 1 is invalid. Erase the image and
628 * continue booting from slot 0.
629 */
630 }
Fabio Utzigb6297af2017-10-05 18:26:36 -0300631 BOOT_LOG_ERR("Image in slot %d is not valid!", slot);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800632 return -1;
633 }
634
635 flash_area_close(fap);
636
637 /* Image in slot 1 is valid. */
638 return 0;
639}
640
641/**
642 * Determines which swap operation to perform, if any. If it is determined
643 * that a swap operation is required, the image in the second slot is checked
644 * for validity. If the image in the second slot is invalid, it is erased, and
645 * a swap type of "none" is indicated.
646 *
647 * @return The type of swap to perform (BOOT_SWAP_TYPE...)
648 */
649static int
650boot_validated_swap_type(void)
651{
652 int swap_type;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800653
654 swap_type = boot_swap_type();
Fabio Utzigb5b2f552017-06-30 10:03:47 -0300655 switch (swap_type) {
656 case BOOT_SWAP_TYPE_TEST:
657 case BOOT_SWAP_TYPE_PERM:
658 case BOOT_SWAP_TYPE_REVERT:
659 /* Boot loader wants to switch to slot 1. Ensure image is valid. */
660 if (boot_validate_slot(1) != 0) {
661 swap_type = BOOT_SWAP_TYPE_FAIL;
662 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800663 }
664
665 return swap_type;
666}
667
668/**
669 * Calculates the number of sectors the scratch area can contain. A "last"
670 * source sector is specified because images are copied backwards in flash
671 * (final index to index number 0).
672 *
673 * @param last_sector_idx The index of the last source sector
674 * (inclusive).
675 * @param out_first_sector_idx The index of the first source sector
676 * (inclusive) gets written here.
677 *
678 * @return The number of bytes comprised by the
679 * [first-sector, last-sector] range.
680 */
Fabio Utzig3488eef2017-06-12 10:25:43 -0300681#ifndef MCUBOOT_OVERWRITE_ONLY
Christopher Collins92ea77f2016-12-12 15:59:26 -0800682static uint32_t
683boot_copy_sz(int last_sector_idx, int *out_first_sector_idx)
684{
Marti Bolivard3269fd2017-06-12 16:31:12 -0400685 size_t scratch_sz;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800686 uint32_t new_sz;
687 uint32_t sz;
688 int i;
689
690 sz = 0;
691
Marti Bolivard3269fd2017-06-12 16:31:12 -0400692 scratch_sz = boot_scratch_area_size(&boot_data);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800693 for (i = last_sector_idx; i >= 0; i--) {
Marti Bolivard3269fd2017-06-12 16:31:12 -0400694 new_sz = sz + boot_img_sector_size(&boot_data, 0, i);
695 if (new_sz > scratch_sz) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800696 break;
697 }
698 sz = new_sz;
699 }
700
701 /* i currently refers to a sector that doesn't fit or it is -1 because all
702 * sectors have been processed. In both cases, exclude sector i.
703 */
704 *out_first_sector_idx = i + 1;
705 return sz;
706}
Fabio Utzig3488eef2017-06-12 10:25:43 -0300707#endif /* !MCUBOOT_OVERWRITE_ONLY */
Christopher Collins92ea77f2016-12-12 15:59:26 -0800708
709/**
710 * Erases a region of flash.
711 *
712 * @param flash_area_idx The ID of the flash area containing the region
713 * to erase.
714 * @param off The offset within the flash area to start the
715 * erase.
716 * @param sz The number of bytes to erase.
717 *
718 * @return 0 on success; nonzero on failure.
719 */
720static int
721boot_erase_sector(int flash_area_id, uint32_t off, uint32_t sz)
722{
723 const struct flash_area *fap;
724 int rc;
725
726 rc = flash_area_open(flash_area_id, &fap);
727 if (rc != 0) {
728 rc = BOOT_EFLASH;
729 goto done;
730 }
731
732 rc = flash_area_erase(fap, off, sz);
733 if (rc != 0) {
734 rc = BOOT_EFLASH;
735 goto done;
736 }
737
738 rc = 0;
739
740done:
741 flash_area_close(fap);
742 return rc;
743}
744
745/**
746 * Copies the contents of one flash region to another. You must erase the
747 * destination region prior to calling this function.
748 *
749 * @param flash_area_id_src The ID of the source flash area.
750 * @param flash_area_id_dst The ID of the destination flash area.
751 * @param off_src The offset within the source flash area to
752 * copy from.
753 * @param off_dst The offset within the destination flash area to
754 * copy to.
755 * @param sz The number of bytes to copy.
756 *
757 * @return 0 on success; nonzero on failure.
758 */
759static int
760boot_copy_sector(int flash_area_id_src, int flash_area_id_dst,
761 uint32_t off_src, uint32_t off_dst, uint32_t sz)
762{
763 const struct flash_area *fap_src;
764 const struct flash_area *fap_dst;
765 uint32_t bytes_copied;
766 int chunk_sz;
767 int rc;
768
769 static uint8_t buf[1024];
770
771 fap_src = NULL;
772 fap_dst = NULL;
773
774 rc = flash_area_open(flash_area_id_src, &fap_src);
775 if (rc != 0) {
776 rc = BOOT_EFLASH;
777 goto done;
778 }
779
780 rc = flash_area_open(flash_area_id_dst, &fap_dst);
781 if (rc != 0) {
782 rc = BOOT_EFLASH;
783 goto done;
784 }
785
786 bytes_copied = 0;
787 while (bytes_copied < sz) {
788 if (sz - bytes_copied > sizeof buf) {
789 chunk_sz = sizeof buf;
790 } else {
791 chunk_sz = sz - bytes_copied;
792 }
793
794 rc = flash_area_read(fap_src, off_src + bytes_copied, buf, chunk_sz);
795 if (rc != 0) {
796 rc = BOOT_EFLASH;
797 goto done;
798 }
799
800 rc = flash_area_write(fap_dst, off_dst + bytes_copied, buf, chunk_sz);
801 if (rc != 0) {
802 rc = BOOT_EFLASH;
803 goto done;
804 }
805
806 bytes_copied += chunk_sz;
807 }
808
809 rc = 0;
810
811done:
Fabio Utzige7686262017-06-28 09:26:54 -0300812 if (fap_src) {
813 flash_area_close(fap_src);
814 }
815 if (fap_dst) {
816 flash_area_close(fap_dst);
817 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800818 return rc;
819}
820
David Brown6b1b3b92017-09-19 08:59:10 -0600821#ifndef MCUBOOT_OVERWRITE_ONLY
Fabio Utzig2473ac02017-05-02 12:45:02 -0300822static inline int
Fabio Utzig46490722017-09-04 15:34:32 -0300823boot_status_init_by_id(int flash_area_id, const struct boot_status *bs)
Fabio Utzig2473ac02017-05-02 12:45:02 -0300824{
825 const struct flash_area *fap;
826 struct boot_swap_state swap_state;
827 int rc;
828
829 rc = flash_area_open(flash_area_id, &fap);
830 assert(rc == 0);
831
832 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_1, &swap_state);
833 assert(rc == 0);
834
Fabio Utzigde8a38a2017-05-23 11:15:01 -0400835 if (swap_state.image_ok == BOOT_FLAG_SET) {
Fabio Utzig2473ac02017-05-02 12:45:02 -0300836 rc = boot_write_image_ok(fap);
837 assert(rc == 0);
838 }
839
Fabio Utzig46490722017-09-04 15:34:32 -0300840 rc = boot_write_swap_size(fap, bs->swap_size);
841 assert(rc == 0);
842
Fabio Utzig2473ac02017-05-02 12:45:02 -0300843 rc = boot_write_magic(fap);
844 assert(rc == 0);
845
846 flash_area_close(fap);
847
848 return 0;
849}
David Brown6b1b3b92017-09-19 08:59:10 -0600850#endif
Fabio Utzig2473ac02017-05-02 12:45:02 -0300851
Fabio Utzig358c9352017-07-25 22:10:45 -0300852#ifndef MCUBOOT_OVERWRITE_ONLY
Fabio Utzig2473ac02017-05-02 12:45:02 -0300853static int
854boot_erase_last_sector_by_id(int flash_area_id)
855{
856 uint8_t slot;
857 uint32_t last_sector;
Fabio Utzig2473ac02017-05-02 12:45:02 -0300858 int rc;
859
860 switch (flash_area_id) {
861 case FLASH_AREA_IMAGE_0:
862 slot = 0;
863 break;
864 case FLASH_AREA_IMAGE_1:
865 slot = 1;
866 break;
867 default:
868 return BOOT_EFLASH;
869 }
870
Marti Bolivard3269fd2017-06-12 16:31:12 -0400871 last_sector = boot_img_num_sectors(&boot_data, slot) - 1;
Fabio Utzig2473ac02017-05-02 12:45:02 -0300872 rc = boot_erase_sector(flash_area_id,
Marti Bolivarea088872017-06-12 17:10:49 -0400873 boot_img_sector_off(&boot_data, slot, last_sector),
Marti Bolivard3269fd2017-06-12 16:31:12 -0400874 boot_img_sector_size(&boot_data, slot, last_sector));
Fabio Utzig2473ac02017-05-02 12:45:02 -0300875 assert(rc == 0);
876
877 return rc;
878}
Fabio Utzig358c9352017-07-25 22:10:45 -0300879#endif /* !MCUBOOT_OVERWRITE_ONLY */
Fabio Utzig2473ac02017-05-02 12:45:02 -0300880
Christopher Collins92ea77f2016-12-12 15:59:26 -0800881/**
882 * Swaps the contents of two flash regions within the two image slots.
883 *
884 * @param idx The index of the first sector in the range of
885 * sectors being swapped.
886 * @param sz The number of bytes to swap.
887 * @param bs The current boot status. This struct gets
888 * updated according to the outcome.
889 *
890 * @return 0 on success; nonzero on failure.
891 */
Fabio Utzig3488eef2017-06-12 10:25:43 -0300892#ifndef MCUBOOT_OVERWRITE_ONLY
Christopher Collins4772ac42017-02-27 20:08:01 -0800893static void
Christopher Collins92ea77f2016-12-12 15:59:26 -0800894boot_swap_sectors(int idx, uint32_t sz, struct boot_status *bs)
895{
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300896 const struct flash_area *fap;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800897 uint32_t copy_sz;
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300898 uint32_t trailer_sz;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800899 uint32_t img_off;
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300900 uint32_t scratch_trailer_off;
901 struct boot_swap_state swap_state;
Marti Bolivard3269fd2017-06-12 16:31:12 -0400902 size_t last_sector;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800903 int rc;
904
905 /* Calculate offset from start of image area. */
Marti Bolivarea088872017-06-12 17:10:49 -0400906 img_off = boot_img_sector_off(&boot_data, 0, idx);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800907
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300908 copy_sz = sz;
Marti Bolivare10a7392017-06-14 16:20:07 -0400909 trailer_sz = boot_slots_trailer_sz(BOOT_WRITE_SZ(&boot_data));
Fabio Utzig9678c972017-05-23 11:28:56 -0400910
911 /* sz in this function is always is always sized on a multiple of the
Marti Bolivarea088872017-06-12 17:10:49 -0400912 * sector size. The check against the start offset of the last sector
Fabio Utzig9678c972017-05-23 11:28:56 -0400913 * is to determine if we're swapping the last sector. The last sector
914 * needs special handling because it's where the trailer lives. If we're
915 * copying it, we need to use scratch to write the trailer temporarily.
916 *
917 * NOTE: `use_scratch` is a temporary flag (never written to flash) which
918 * controls if special handling is needed (swapping last sector).
919 */
Marti Bolivard3269fd2017-06-12 16:31:12 -0400920 last_sector = boot_img_num_sectors(&boot_data, 0) - 1;
Marti Bolivarea088872017-06-12 17:10:49 -0400921 if (img_off + sz > boot_img_sector_off(&boot_data, 0, last_sector)) {
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300922 copy_sz -= trailer_sz;
923 }
924
Fabio Utzig2473ac02017-05-02 12:45:02 -0300925 bs->use_scratch = (bs->idx == 0 && copy_sz != sz);
926
Christopher Collins92ea77f2016-12-12 15:59:26 -0800927 if (bs->state == 0) {
928 rc = boot_erase_sector(FLASH_AREA_IMAGE_SCRATCH, 0, sz);
Christopher Collins4772ac42017-02-27 20:08:01 -0800929 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800930
931 rc = boot_copy_sector(FLASH_AREA_IMAGE_1, FLASH_AREA_IMAGE_SCRATCH,
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300932 img_off, 0, copy_sz);
Christopher Collins4772ac42017-02-27 20:08:01 -0800933 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800934
Fabio Utzig2473ac02017-05-02 12:45:02 -0300935 if (bs->idx == 0) {
936 if (bs->use_scratch) {
Fabio Utzig46490722017-09-04 15:34:32 -0300937 boot_status_init_by_id(FLASH_AREA_IMAGE_SCRATCH, bs);
Fabio Utzig2473ac02017-05-02 12:45:02 -0300938 } else {
939 /* Prepare the status area... here it is known that the
940 * last sector is not being used by the image data so it's
941 * safe to erase.
942 */
943 rc = boot_erase_last_sector_by_id(FLASH_AREA_IMAGE_0);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300944 assert(rc == 0);
Fabio Utzig2473ac02017-05-02 12:45:02 -0300945
Fabio Utzig46490722017-09-04 15:34:32 -0300946 boot_status_init_by_id(FLASH_AREA_IMAGE_0, bs);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300947 }
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300948 }
949
Christopher Collins92ea77f2016-12-12 15:59:26 -0800950 bs->state = 1;
Christopher Collins4772ac42017-02-27 20:08:01 -0800951 rc = boot_write_status(bs);
Fabio Utziga0e1cce2017-11-23 20:04:01 -0200952 BOOT_STATUS_ASSERT(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800953 }
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300954
Christopher Collins92ea77f2016-12-12 15:59:26 -0800955 if (bs->state == 1) {
956 rc = boot_erase_sector(FLASH_AREA_IMAGE_1, img_off, sz);
Christopher Collins4772ac42017-02-27 20:08:01 -0800957 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800958
Christopher Collins92ea77f2016-12-12 15:59:26 -0800959 rc = boot_copy_sector(FLASH_AREA_IMAGE_0, FLASH_AREA_IMAGE_1,
960 img_off, img_off, copy_sz);
Christopher Collins4772ac42017-02-27 20:08:01 -0800961 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800962
Fabio Utzig2473ac02017-05-02 12:45:02 -0300963 if (bs->idx == 0 && !bs->use_scratch) {
964 /* If not all sectors of the slot are being swapped,
965 * guarantee here that only slot0 will have the state.
966 */
967 rc = boot_erase_last_sector_by_id(FLASH_AREA_IMAGE_1);
968 assert(rc == 0);
969 }
970
Christopher Collins92ea77f2016-12-12 15:59:26 -0800971 bs->state = 2;
Christopher Collins4772ac42017-02-27 20:08:01 -0800972 rc = boot_write_status(bs);
Fabio Utziga0e1cce2017-11-23 20:04:01 -0200973 BOOT_STATUS_ASSERT(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800974 }
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300975
Christopher Collins92ea77f2016-12-12 15:59:26 -0800976 if (bs->state == 2) {
977 rc = boot_erase_sector(FLASH_AREA_IMAGE_0, img_off, sz);
Christopher Collins4772ac42017-02-27 20:08:01 -0800978 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800979
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300980 /* NOTE: also copy trailer from scratch (has status info) */
Christopher Collins92ea77f2016-12-12 15:59:26 -0800981 rc = boot_copy_sector(FLASH_AREA_IMAGE_SCRATCH, FLASH_AREA_IMAGE_0,
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300982 0, img_off, copy_sz);
Christopher Collins4772ac42017-02-27 20:08:01 -0800983 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800984
Fabio Utzig94d998c2017-05-22 11:02:41 -0400985 if (bs->use_scratch) {
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300986 rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH, &fap);
987 assert(rc == 0);
988
989 scratch_trailer_off = boot_status_off(fap);
990
991 flash_area_close(fap);
992
993 rc = flash_area_open(FLASH_AREA_IMAGE_0, &fap);
994 assert(rc == 0);
995
996 /* copy current status that is being maintained in scratch */
997 rc = boot_copy_sector(FLASH_AREA_IMAGE_SCRATCH, FLASH_AREA_IMAGE_0,
Marti Bolivare10a7392017-06-14 16:20:07 -0400998 scratch_trailer_off,
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300999 img_off + copy_sz,
Marti Bolivare10a7392017-06-14 16:20:07 -04001000 BOOT_STATUS_STATE_COUNT * BOOT_WRITE_SZ(&boot_data));
Fabio Utziga0e1cce2017-11-23 20:04:01 -02001001 BOOT_STATUS_ASSERT(rc == 0);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001002
Fabio Utzig2473ac02017-05-02 12:45:02 -03001003 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SCRATCH,
1004 &swap_state);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001005 assert(rc == 0);
1006
Fabio Utzigde8a38a2017-05-23 11:15:01 -04001007 if (swap_state.image_ok == BOOT_FLAG_SET) {
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001008 rc = boot_write_image_ok(fap);
1009 assert(rc == 0);
1010 }
1011
Fabio Utzig46490722017-09-04 15:34:32 -03001012 rc = boot_write_swap_size(fap, bs->swap_size);
1013 assert(rc == 0);
1014
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001015 rc = boot_write_magic(fap);
1016 assert(rc == 0);
1017
1018 flash_area_close(fap);
1019 }
1020
Christopher Collins92ea77f2016-12-12 15:59:26 -08001021 bs->idx++;
1022 bs->state = 0;
Fabio Utzig2473ac02017-05-02 12:45:02 -03001023 bs->use_scratch = 0;
Christopher Collins4772ac42017-02-27 20:08:01 -08001024 rc = boot_write_status(bs);
Fabio Utziga0e1cce2017-11-23 20:04:01 -02001025 BOOT_STATUS_ASSERT(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001026 }
Christopher Collins92ea77f2016-12-12 15:59:26 -08001027}
Fabio Utzig3488eef2017-06-12 10:25:43 -03001028#endif /* !MCUBOOT_OVERWRITE_ONLY */
Christopher Collins92ea77f2016-12-12 15:59:26 -08001029
1030/**
1031 * Swaps the two images in flash. If a prior copy operation was interrupted
1032 * by a system reset, this function completes that operation.
1033 *
1034 * @param bs The current boot status. This function reads
1035 * this struct to determine if it is resuming
1036 * an interrupted swap operation. This
1037 * function writes the updated status to this
1038 * function on return.
1039 *
1040 * @return 0 on success; nonzero on failure.
1041 */
Fabio Utzig3488eef2017-06-12 10:25:43 -03001042#ifdef MCUBOOT_OVERWRITE_ONLY
David Brown17609d82017-05-05 09:41:34 -06001043static int
1044boot_copy_image(struct boot_status *bs)
1045{
Marti Bolivard3269fd2017-06-12 16:31:12 -04001046 size_t sect_count;
1047 size_t sect;
David Brown17609d82017-05-05 09:41:34 -06001048 int rc;
Fabio Utzig13d9e352017-10-05 20:32:31 -03001049 size_t size;
Marti Bolivard3269fd2017-06-12 16:31:12 -04001050 size_t this_size;
Fabio Utzig13d9e352017-10-05 20:32:31 -03001051 size_t last_sector;
1052
Fabio Utzigaaf767c2017-12-05 10:22:46 -02001053 (void)bs;
1054
Fabio Utzig13d9e352017-10-05 20:32:31 -03001055#if defined(MCUBOOT_OVERWRITE_ONLY_FAST)
1056 uint32_t src_size = 0;
1057 rc = boot_read_image_size(1, boot_img_hdr(&boot_data, 1), &src_size);
1058 assert(rc == 0);
1059#endif
David Brown17609d82017-05-05 09:41:34 -06001060
1061 BOOT_LOG_INF("Image upgrade slot1 -> slot0");
1062 BOOT_LOG_INF("Erasing slot0");
1063
Marti Bolivard3269fd2017-06-12 16:31:12 -04001064 sect_count = boot_img_num_sectors(&boot_data, 0);
Fabio Utzig13d9e352017-10-05 20:32:31 -03001065 for (sect = 0, size = 0; sect < sect_count; sect++) {
Marti Bolivard3269fd2017-06-12 16:31:12 -04001066 this_size = boot_img_sector_size(&boot_data, 0, sect);
David Brown17609d82017-05-05 09:41:34 -06001067 rc = boot_erase_sector(FLASH_AREA_IMAGE_0,
1068 size,
1069 this_size);
1070 assert(rc == 0);
1071
1072 size += this_size;
Fabio Utzig13d9e352017-10-05 20:32:31 -03001073
1074#if defined(MCUBOOT_OVERWRITE_ONLY_FAST)
1075 if (size >= src_size) {
1076 break;
1077 }
1078#endif
David Brown17609d82017-05-05 09:41:34 -06001079 }
1080
Fabio Utzig6a537ee2017-09-13 17:31:44 -03001081 BOOT_LOG_INF("Copying slot 1 to slot 0: 0x%lx bytes", size);
David Brown17609d82017-05-05 09:41:34 -06001082 rc = boot_copy_sector(FLASH_AREA_IMAGE_1, FLASH_AREA_IMAGE_0,
1083 0, 0, size);
1084
Fabio Utzig13d9e352017-10-05 20:32:31 -03001085 /*
1086 * Erases header and trailer. The trailer is erased because when a new
1087 * image is written without a trailer as is the case when using newt, the
1088 * trailer that was left might trigger a new upgrade.
1089 */
David Brown17609d82017-05-05 09:41:34 -06001090 rc = boot_erase_sector(FLASH_AREA_IMAGE_1,
Fabio Utzig13d9e352017-10-05 20:32:31 -03001091 boot_img_sector_off(&boot_data, 1, 0),
1092 boot_img_sector_size(&boot_data, 1, 0));
David Brown17609d82017-05-05 09:41:34 -06001093 assert(rc == 0);
Fabio Utzig13d9e352017-10-05 20:32:31 -03001094 last_sector = boot_img_num_sectors(&boot_data, 1) - 1;
1095 rc = boot_erase_sector(FLASH_AREA_IMAGE_1,
1096 boot_img_sector_off(&boot_data, 1, last_sector),
1097 boot_img_sector_size(&boot_data, 1, last_sector));
1098 assert(rc == 0);
1099
1100 /* TODO: Perhaps verify slot 0's signature again? */
David Brown17609d82017-05-05 09:41:34 -06001101
1102 return 0;
1103}
1104#else
Christopher Collins92ea77f2016-12-12 15:59:26 -08001105static int
1106boot_copy_image(struct boot_status *bs)
1107{
1108 uint32_t sz;
1109 int first_sector_idx;
1110 int last_sector_idx;
Fabio Utzigcd5774b2017-11-29 10:18:26 -02001111 uint32_t swap_idx;
Fabio Utzig2473ac02017-05-02 12:45:02 -03001112 struct image_header *hdr;
1113 uint32_t size;
1114 uint32_t copy_size;
Fabio Utzig2473ac02017-05-02 12:45:02 -03001115 int rc;
1116
1117 /* FIXME: just do this if asked by user? */
1118
1119 size = copy_size = 0;
1120
Fabio Utzig46490722017-09-04 15:34:32 -03001121 if (bs->idx == 0 && bs->state == 0) {
1122 /*
1123 * No swap ever happened, so need to find the largest image which
1124 * will be used to determine the amount of sectors to swap.
1125 */
1126 hdr = boot_img_hdr(&boot_data, 0);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001127 if (hdr->ih_magic == IMAGE_MAGIC) {
Fabio Utzig46490722017-09-04 15:34:32 -03001128 rc = boot_read_image_size(0, hdr, &copy_size);
David Brownf5b33d82017-09-01 10:58:27 -06001129 assert(rc == 0);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001130 }
Fabio Utzig2473ac02017-05-02 12:45:02 -03001131
Fabio Utzig46490722017-09-04 15:34:32 -03001132 hdr = boot_img_hdr(&boot_data, 1);
1133 if (hdr->ih_magic == IMAGE_MAGIC) {
1134 rc = boot_read_image_size(1, hdr, &size);
1135 assert(rc == 0);
1136 }
1137
1138 if (size > copy_size) {
1139 copy_size = size;
1140 }
1141
1142 bs->swap_size = copy_size;
1143 } else {
1144 /*
1145 * If a swap was under way, the swap_size should already be present
1146 * in the trailer...
1147 */
1148 rc = boot_read_swap_size(&bs->swap_size);
1149 assert(rc == 0);
1150
1151 copy_size = bs->swap_size;
Fabio Utzig2473ac02017-05-02 12:45:02 -03001152 }
1153
1154 size = 0;
1155 last_sector_idx = 0;
1156 while (1) {
Marti Bolivard3269fd2017-06-12 16:31:12 -04001157 size += boot_img_sector_size(&boot_data, 0, last_sector_idx);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001158 if (size >= copy_size) {
1159 break;
1160 }
1161 last_sector_idx++;
1162 }
Christopher Collins92ea77f2016-12-12 15:59:26 -08001163
1164 swap_idx = 0;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001165 while (last_sector_idx >= 0) {
1166 sz = boot_copy_sz(last_sector_idx, &first_sector_idx);
1167 if (swap_idx >= bs->idx) {
1168 boot_swap_sectors(first_sector_idx, sz, bs);
1169 }
1170
1171 last_sector_idx = first_sector_idx - 1;
1172 swap_idx++;
1173 }
1174
Fabio Utziga0e1cce2017-11-23 20:04:01 -02001175#ifdef MCUBOOT_VALIDATE_SLOT0
1176 if (boot_status_fails > 0) {
1177 BOOT_LOG_WRN("%d status write fails performing the swap", boot_status_fails);
1178 }
1179#endif
1180
Christopher Collins92ea77f2016-12-12 15:59:26 -08001181 return 0;
1182}
David Brown17609d82017-05-05 09:41:34 -06001183#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -08001184
1185/**
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03001186 * Marks the image in slot 0 as fully copied.
Christopher Collins92ea77f2016-12-12 15:59:26 -08001187 */
Fabio Utzig8d0e5882017-09-13 17:32:44 -03001188#ifndef MCUBOOT_OVERWRITE_ONLY
Christopher Collins92ea77f2016-12-12 15:59:26 -08001189static int
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03001190boot_set_copy_done(void)
Christopher Collins92ea77f2016-12-12 15:59:26 -08001191{
1192 const struct flash_area *fap;
1193 int rc;
1194
1195 rc = flash_area_open(FLASH_AREA_IMAGE_0, &fap);
1196 if (rc != 0) {
1197 return BOOT_EFLASH;
1198 }
1199
1200 rc = boot_write_copy_done(fap);
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03001201 flash_area_close(fap);
1202 return rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001203}
Fabio Utzig8d0e5882017-09-13 17:32:44 -03001204#endif /* !MCUBOOT_OVERWRITE_ONLY */
Christopher Collins92ea77f2016-12-12 15:59:26 -08001205
1206/**
1207 * Marks a reverted image in slot 0 as confirmed. This is necessary to ensure
1208 * the status bytes from the image revert operation don't get processed on a
1209 * subsequent boot.
Fabio Utzig1e56fcc2017-07-17 15:39:14 -03001210 *
1211 * NOTE: image_ok is tested before writing because if there's a valid permanent
1212 * image installed on slot0 and the new image to be upgrade to has a bad sig,
1213 * image_ok would be overwritten.
Christopher Collins92ea77f2016-12-12 15:59:26 -08001214 */
Fabio Utzig8d0e5882017-09-13 17:32:44 -03001215#ifndef MCUBOOT_OVERWRITE_ONLY
Christopher Collins92ea77f2016-12-12 15:59:26 -08001216static int
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03001217boot_set_image_ok(void)
Christopher Collins92ea77f2016-12-12 15:59:26 -08001218{
1219 const struct flash_area *fap;
Fabio Utzig1e56fcc2017-07-17 15:39:14 -03001220 struct boot_swap_state state;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001221 int rc;
1222
1223 rc = flash_area_open(FLASH_AREA_IMAGE_0, &fap);
1224 if (rc != 0) {
1225 return BOOT_EFLASH;
1226 }
1227
Fabio Utzig1e56fcc2017-07-17 15:39:14 -03001228 rc = boot_read_swap_state(fap, &state);
1229 if (rc != 0) {
1230 rc = BOOT_EFLASH;
1231 goto out;
1232 }
1233
1234 if (state.image_ok == BOOT_FLAG_UNSET) {
1235 rc = boot_write_image_ok(fap);
1236 }
1237
1238out:
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03001239 flash_area_close(fap);
1240 return rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001241}
Fabio Utzig8d0e5882017-09-13 17:32:44 -03001242#endif /* !MCUBOOT_OVERWRITE_ONLY */
Christopher Collins92ea77f2016-12-12 15:59:26 -08001243
1244/**
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001245 * Performs an image swap if one is required.
1246 *
1247 * @param out_swap_type On success, the type of swap performed gets
1248 * written here.
1249 *
1250 * @return 0 on success; nonzero on failure.
1251 */
1252static int
1253boot_swap_if_needed(int *out_swap_type)
1254{
1255 struct boot_status bs;
1256 int swap_type;
1257 int rc;
1258
1259 /* Determine if we rebooted in the middle of an image swap
1260 * operation.
1261 */
1262 rc = boot_read_status(&bs);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001263 assert(rc == 0);
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001264 if (rc != 0) {
1265 return rc;
1266 }
1267
1268 /* If a partial swap was detected, complete it. */
1269 if (bs.idx != 0 || bs.state != 0) {
1270 rc = boot_copy_image(&bs);
1271 assert(rc == 0);
1272
Fabio Utzigb5b2f552017-06-30 10:03:47 -03001273 /* NOTE: here we have finished a swap resume. The initial request
1274 * was either a TEST or PERM swap, which now after the completed
1275 * swap will be determined to be respectively REVERT (was TEST)
1276 * or NONE (was PERM).
1277 */
1278
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001279 /* Extrapolate the type of the partial swap. We need this
1280 * information to know how to mark the swap complete in flash.
1281 */
1282 swap_type = boot_previous_swap_type();
1283 } else {
1284 swap_type = boot_validated_swap_type();
1285 switch (swap_type) {
1286 case BOOT_SWAP_TYPE_TEST:
Christopher Collinsfd7eb5c2016-12-21 13:46:08 -08001287 case BOOT_SWAP_TYPE_PERM:
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001288 case BOOT_SWAP_TYPE_REVERT:
1289 rc = boot_copy_image(&bs);
1290 assert(rc == 0);
1291 break;
1292 }
1293 }
1294
1295 *out_swap_type = swap_type;
1296 return 0;
1297}
1298
1299/**
Christopher Collins92ea77f2016-12-12 15:59:26 -08001300 * Prepares the booting process. This function moves images around in flash as
1301 * appropriate, and tells you what address to boot from.
1302 *
1303 * @param rsp On success, indicates how booting should occur.
1304 *
1305 * @return 0 on success; nonzero on failure.
1306 */
1307int
1308boot_go(struct boot_rsp *rsp)
1309{
Christopher Collins92ea77f2016-12-12 15:59:26 -08001310 int swap_type;
Marti Bolivar84898652017-06-13 17:20:22 -04001311 size_t slot;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001312 int rc;
Marti Bolivarc0b47912017-06-13 17:18:09 -04001313 int fa_id;
David Brown52eee562017-07-05 11:25:09 -06001314 bool reload_headers = false;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001315
1316 /* The array of slot sectors are defined here (as opposed to file scope) so
1317 * that they don't get allocated for non-boot-loader apps. This is
1318 * necessary because the gcc option "-fdata-sections" doesn't seem to have
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001319 * any effect in older gcc versions (e.g., 4.8.4).
Christopher Collins92ea77f2016-12-12 15:59:26 -08001320 */
Marti Bolivarc50926f2017-06-14 09:35:40 -04001321 static boot_sector_t slot0_sectors[BOOT_MAX_IMG_SECTORS];
1322 static boot_sector_t slot1_sectors[BOOT_MAX_IMG_SECTORS];
Christopher Collins92ea77f2016-12-12 15:59:26 -08001323 boot_data.imgs[0].sectors = slot0_sectors;
1324 boot_data.imgs[1].sectors = slot1_sectors;
1325
Marti Bolivarc0b47912017-06-13 17:18:09 -04001326 /* Open boot_data image areas for the duration of this call. */
1327 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
1328 fa_id = flash_area_id_from_image_slot(slot);
1329 rc = flash_area_open(fa_id, &BOOT_IMG_AREA(&boot_data, slot));
1330 assert(rc == 0);
1331 }
1332 rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH,
1333 &BOOT_SCRATCH_AREA(&boot_data));
1334 assert(rc == 0);
1335
Christopher Collins92ea77f2016-12-12 15:59:26 -08001336 /* Determine the sector layout of the image slots and scratch area. */
1337 rc = boot_read_sectors();
1338 if (rc != 0) {
Marti Bolivarc0b47912017-06-13 17:18:09 -04001339 goto out;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001340 }
1341
1342 /* Attempt to read an image header from each slot. */
Fabio Utzig9c25fa72017-12-12 14:57:20 -02001343 rc = boot_read_image_headers(false);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001344 if (rc != 0) {
Marti Bolivarc0b47912017-06-13 17:18:09 -04001345 goto out;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001346 }
1347
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001348 /* If the image slots aren't compatible, no swap is possible. Just boot
1349 * into slot 0.
1350 */
1351 if (boot_slots_compatible()) {
1352 rc = boot_swap_if_needed(&swap_type);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001353 assert(rc == 0);
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001354 if (rc != 0) {
Marti Bolivarc0b47912017-06-13 17:18:09 -04001355 goto out;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001356 }
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03001357
1358 /*
1359 * The following states need image_ok be explicitly set after the
1360 * swap was finished to avoid a new revert.
1361 */
1362 if (swap_type == BOOT_SWAP_TYPE_REVERT || swap_type == BOOT_SWAP_TYPE_FAIL) {
Fabio Utzig8d0e5882017-09-13 17:32:44 -03001363#ifndef MCUBOOT_OVERWRITE_ONLY
Fabio Utzig695d5642017-07-20 09:47:16 -03001364 rc = boot_set_image_ok();
1365 if (rc != 0) {
1366 swap_type = BOOT_SWAP_TYPE_PANIC;
1367 }
Fabio Utzig8d0e5882017-09-13 17:32:44 -03001368#endif /* !MCUBOOT_OVERWRITE_ONLY */
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03001369 }
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001370 } else {
1371 swap_type = BOOT_SWAP_TYPE_NONE;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001372 }
1373
1374 switch (swap_type) {
1375 case BOOT_SWAP_TYPE_NONE:
1376 slot = 0;
1377 break;
1378
Fabio Utzig695d5642017-07-20 09:47:16 -03001379 case BOOT_SWAP_TYPE_TEST: /* fallthrough */
1380 case BOOT_SWAP_TYPE_PERM: /* fallthrough */
Christopher Collins92ea77f2016-12-12 15:59:26 -08001381 case BOOT_SWAP_TYPE_REVERT:
1382 slot = 1;
David Brown52eee562017-07-05 11:25:09 -06001383 reload_headers = true;
Fabio Utzig8d0e5882017-09-13 17:32:44 -03001384#ifndef MCUBOOT_OVERWRITE_ONLY
Fabio Utzig695d5642017-07-20 09:47:16 -03001385 rc = boot_set_copy_done();
1386 if (rc != 0) {
1387 swap_type = BOOT_SWAP_TYPE_PANIC;
1388 }
Fabio Utzig8d0e5882017-09-13 17:32:44 -03001389#endif /* !MCUBOOT_OVERWRITE_ONLY */
Christopher Collins92ea77f2016-12-12 15:59:26 -08001390 break;
1391
1392 case BOOT_SWAP_TYPE_FAIL:
1393 /* The image in slot 1 was invalid and is now erased. Ensure we don't
1394 * try to boot into it again on the next reboot. Do this by pretending
1395 * we just reverted back to slot 0.
1396 */
1397 slot = 0;
David Brown52eee562017-07-05 11:25:09 -06001398 reload_headers = true;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001399 break;
1400
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03001401 default:
Fabio Utzig695d5642017-07-20 09:47:16 -03001402 swap_type = BOOT_SWAP_TYPE_PANIC;
1403 }
1404
1405 if (swap_type == BOOT_SWAP_TYPE_PANIC) {
1406 BOOT_LOG_ERR("panic!");
Fabio Utzigb5b2f552017-06-30 10:03:47 -03001407 assert(0);
Fabio Utzig695d5642017-07-20 09:47:16 -03001408
1409 /* Loop forever... */
1410 while (1) {}
Christopher Collins92ea77f2016-12-12 15:59:26 -08001411 }
1412
David Brown52eee562017-07-05 11:25:09 -06001413 if (reload_headers) {
Fabio Utzig9c25fa72017-12-12 14:57:20 -02001414 rc = boot_read_image_headers(false);
Fabio Utzigc6a7b0c2017-09-13 19:01:15 -03001415 if (rc != 0) {
1416 goto out;
1417 }
1418 /* Since headers were reloaded, it can be assumed we just performed a
1419 * swap or overwrite. Now the header info that should be used to
1420 * provide the data for the bootstrap, which previously was at Slot 1,
1421 * was updated to Slot 0.
1422 */
1423 slot = 0;
David Brown52eee562017-07-05 11:25:09 -06001424 }
1425
Marti Bolivarc1f939d2017-11-14 20:04:51 -05001426#ifdef MCUBOOT_VALIDATE_SLOT0
David Brown554c52e2017-06-30 16:01:07 -06001427 rc = boot_validate_slot(0);
Fabio Utzig57c40f72017-12-12 21:48:30 -02001428 ASSERT(rc == 0);
David Brown554c52e2017-06-30 16:01:07 -06001429 if (rc != 0) {
1430 rc = BOOT_EBADIMAGE;
1431 goto out;
1432 }
Fabio Utzig1e56fcc2017-07-17 15:39:14 -03001433#else
Marti Bolivarc1f939d2017-11-14 20:04:51 -05001434 /* Even if we're not re-validating slot 0, we could be booting
1435 * onto an empty flash chip. At least do a basic sanity check that
1436 * the magic number on the image is OK.
1437 */
1438 if (boot_data.imgs[0].hdr.ih_magic != IMAGE_MAGIC) {
1439 BOOT_LOG_ERR("bad image magic 0x%x", boot_data.imgs[0].hdr.ih_magic);
1440 rc = BOOT_EBADIMAGE;
1441 goto out;
1442 }
David Brown554c52e2017-06-30 16:01:07 -06001443#endif
1444
Christopher Collins92ea77f2016-12-12 15:59:26 -08001445 /* Always boot from the primary slot. */
Marti Bolivar428cdbf2017-05-01 22:32:42 -04001446 rsp->br_flash_dev_id = boot_img_fa_device_id(&boot_data, 0);
Marti Bolivar88f48d92017-05-01 22:30:02 -04001447 rsp->br_image_off = boot_img_slot_off(&boot_data, 0);
Marti Bolivarf804f622017-06-12 15:41:48 -04001448 rsp->br_hdr = boot_img_hdr(&boot_data, slot);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001449
Marti Bolivarc0b47912017-06-13 17:18:09 -04001450 out:
1451 flash_area_close(BOOT_SCRATCH_AREA(&boot_data));
1452 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
1453 flash_area_close(BOOT_IMG_AREA(&boot_data, BOOT_NUM_SLOTS - 1 - slot));
1454 }
1455 return rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001456}
1457
1458int
1459split_go(int loader_slot, int split_slot, void **entry)
1460{
Marti Bolivarc50926f2017-06-14 09:35:40 -04001461 boot_sector_t *sectors;
Christopher Collins034a6202017-01-11 12:19:37 -08001462 uintptr_t entry_val;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001463 int loader_flash_id;
Marti Bolivarc0b47912017-06-13 17:18:09 -04001464 int split_flash_id;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001465 int rc;
1466
Christopher Collins92ea77f2016-12-12 15:59:26 -08001467 sectors = malloc(BOOT_MAX_IMG_SECTORS * 2 * sizeof *sectors);
1468 if (sectors == NULL) {
Marti Bolivarc0b47912017-06-13 17:18:09 -04001469 return SPLIT_GO_ERR;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001470 }
Marti Bolivarc0b47912017-06-13 17:18:09 -04001471 boot_data.imgs[loader_slot].sectors = sectors + 0;
1472 boot_data.imgs[split_slot].sectors = sectors + BOOT_MAX_IMG_SECTORS;
1473
1474 loader_flash_id = flash_area_id_from_image_slot(loader_slot);
1475 rc = flash_area_open(loader_flash_id,
1476 &BOOT_IMG_AREA(&boot_data, split_slot));
1477 assert(rc == 0);
1478 split_flash_id = flash_area_id_from_image_slot(split_slot);
1479 rc = flash_area_open(split_flash_id,
1480 &BOOT_IMG_AREA(&boot_data, split_slot));
1481 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001482
1483 /* Determine the sector layout of the image slots and scratch area. */
1484 rc = boot_read_sectors();
1485 if (rc != 0) {
1486 rc = SPLIT_GO_ERR;
1487 goto done;
1488 }
1489
Fabio Utzig9c25fa72017-12-12 14:57:20 -02001490 rc = boot_read_image_headers(true);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001491 if (rc != 0) {
1492 goto done;
1493 }
1494
Christopher Collins92ea77f2016-12-12 15:59:26 -08001495 /* Don't check the bootable image flag because we could really call a
1496 * bootable or non-bootable image. Just validate that the image check
1497 * passes which is distinct from the normal check.
1498 */
Marti Bolivarf804f622017-06-12 15:41:48 -04001499 rc = split_image_check(boot_img_hdr(&boot_data, split_slot),
Marti Bolivarc0b47912017-06-13 17:18:09 -04001500 BOOT_IMG_AREA(&boot_data, split_slot),
Marti Bolivarf804f622017-06-12 15:41:48 -04001501 boot_img_hdr(&boot_data, loader_slot),
Marti Bolivarc0b47912017-06-13 17:18:09 -04001502 BOOT_IMG_AREA(&boot_data, loader_slot));
Christopher Collins92ea77f2016-12-12 15:59:26 -08001503 if (rc != 0) {
1504 rc = SPLIT_GO_NON_MATCHING;
1505 goto done;
1506 }
1507
Marti Bolivarea088872017-06-12 17:10:49 -04001508 entry_val = boot_img_slot_off(&boot_data, split_slot) +
Marti Bolivarf804f622017-06-12 15:41:48 -04001509 boot_img_hdr(&boot_data, split_slot)->ih_hdr_size;
Christopher Collins034a6202017-01-11 12:19:37 -08001510 *entry = (void *) entry_val;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001511 rc = SPLIT_GO_OK;
1512
1513done:
Marti Bolivarc0b47912017-06-13 17:18:09 -04001514 flash_area_close(BOOT_IMG_AREA(&boot_data, split_slot));
1515 flash_area_close(BOOT_IMG_AREA(&boot_data, loader_slot));
Christopher Collins92ea77f2016-12-12 15:59:26 -08001516 free(sectors);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001517 return rc;
1518}