blob: 8ce56a671c065dda462e4fa639b1a999875ecc2d [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"
Marti Bolivarfd20c762017-02-07 16:52:50 -050036#include "bootutil/bootutil_log.h"
37
Fabio Utzigba1fbe62017-07-21 14:01:20 -030038#include "mcuboot_config/mcuboot_config.h"
Fabio Utzigeed80b62017-06-10 08:03:05 -030039
Marti Bolivar9b1f8bb2017-06-12 15:24:13 -040040static struct boot_loader_state boot_data;
Christopher Collins92ea77f2016-12-12 15:59:26 -080041
Fabio Utzigf70e3022018-01-10 15:00:42 -020042#if defined(MCUBOOT_VALIDATE_SLOT0) && !defined(MCUBOOT_OVERWRITE_ONLY)
Fabio Utziga0e1cce2017-11-23 20:04:01 -020043static int boot_status_fails = 0;
44#define BOOT_STATUS_ASSERT(x) \
45 do { \
Johann Fischered8461b2018-02-15 16:50:31 +010046 if (!(x)) { \
Fabio Utziga0e1cce2017-11-23 20:04:01 -020047 boot_status_fails++; \
48 } \
49 } while (0)
50#else
Fabio Utzig57c40f72017-12-12 21:48:30 -020051#define BOOT_STATUS_ASSERT(x) ASSERT(x)
Fabio Utziga0e1cce2017-11-23 20:04:01 -020052#endif
53
Christopher Collins92ea77f2016-12-12 15:59:26 -080054struct boot_status_table {
55 /**
56 * For each field, a value of 0 means "any".
57 */
58 uint8_t bst_magic_slot0;
59 uint8_t bst_magic_scratch;
60 uint8_t bst_copy_done_slot0;
61 uint8_t bst_status_source;
62};
63
64/**
65 * This set of tables maps swap state contents to boot status location.
66 * When searching for a match, these tables must be iterated in order.
67 */
68static const struct boot_status_table boot_status_tables[] = {
69 {
70 /* | slot-0 | scratch |
71 * ----------+------------+------------|
72 * magic | Good | Any |
73 * copy-done | 0x01 | N/A |
74 * ----------+------------+------------'
75 * source: none |
76 * ------------------------------------'
77 */
78 .bst_magic_slot0 = BOOT_MAGIC_GOOD,
79 .bst_magic_scratch = 0,
80 .bst_copy_done_slot0 = 0x01,
81 .bst_status_source = BOOT_STATUS_SOURCE_NONE,
82 },
83
84 {
85 /* | slot-0 | scratch |
86 * ----------+------------+------------|
87 * magic | Good | Any |
88 * copy-done | 0xff | N/A |
89 * ----------+------------+------------'
90 * source: slot 0 |
91 * ------------------------------------'
92 */
93 .bst_magic_slot0 = BOOT_MAGIC_GOOD,
94 .bst_magic_scratch = 0,
95 .bst_copy_done_slot0 = 0xff,
96 .bst_status_source = BOOT_STATUS_SOURCE_SLOT0,
97 },
98
99 {
100 /* | slot-0 | scratch |
101 * ----------+------------+------------|
102 * magic | Any | Good |
103 * copy-done | Any | N/A |
104 * ----------+------------+------------'
105 * source: scratch |
106 * ------------------------------------'
107 */
108 .bst_magic_slot0 = 0,
109 .bst_magic_scratch = BOOT_MAGIC_GOOD,
110 .bst_copy_done_slot0 = 0,
111 .bst_status_source = BOOT_STATUS_SOURCE_SCRATCH,
112 },
113
114 {
115 /* | slot-0 | scratch |
116 * ----------+------------+------------|
117 * magic | Unset | Any |
118 * copy-done | 0xff | N/A |
119 * ----------+------------+------------|
120 * source: varies |
121 * ------------------------------------+------------------------------+
122 * This represents one of two cases: |
123 * o No swaps ever (no status to read, so no harm in checking). |
124 * o Mid-revert; status in slot 0. |
125 * -------------------------------------------------------------------'
126 */
127 .bst_magic_slot0 = BOOT_MAGIC_UNSET,
128 .bst_magic_scratch = 0,
129 .bst_copy_done_slot0 = 0xff,
130 .bst_status_source = BOOT_STATUS_SOURCE_SLOT0,
131 },
132};
133
134#define BOOT_STATUS_TABLES_COUNT \
135 (sizeof boot_status_tables / sizeof boot_status_tables[0])
136
Marti Bolivarfd20c762017-02-07 16:52:50 -0500137#define BOOT_LOG_SWAP_STATE(area, state) \
138 BOOT_LOG_INF("%s: magic=%s, copy_done=0x%x, image_ok=0x%x", \
139 (area), \
140 ((state)->magic == BOOT_MAGIC_GOOD ? "good" : \
141 (state)->magic == BOOT_MAGIC_UNSET ? "unset" : \
142 "bad"), \
143 (state)->copy_done, \
144 (state)->image_ok)
145
Christopher Collins92ea77f2016-12-12 15:59:26 -0800146/**
147 * Determines where in flash the most recent boot status is stored. The boot
148 * status is necessary for completing a swap that was interrupted by a boot
149 * loader reset.
150 *
151 * @return A BOOT_STATUS_SOURCE_[...] code indicating where * status should be read from.
152 */
153static int
154boot_status_source(void)
155{
156 const struct boot_status_table *table;
157 struct boot_swap_state state_scratch;
158 struct boot_swap_state state_slot0;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800159 int rc;
Fabio Utzigcd5774b2017-11-29 10:18:26 -0200160 size_t i;
Marti Bolivarfd20c762017-02-07 16:52:50 -0500161 uint8_t source;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800162
Fabio Utzig2473ac02017-05-02 12:45:02 -0300163 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_0, &state_slot0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800164 assert(rc == 0);
165
Fabio Utzig2473ac02017-05-02 12:45:02 -0300166 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SCRATCH, &state_scratch);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800167 assert(rc == 0);
168
Marti Bolivarfd20c762017-02-07 16:52:50 -0500169 BOOT_LOG_SWAP_STATE("Image 0", &state_slot0);
Marti Bolivarfd20c762017-02-07 16:52:50 -0500170 BOOT_LOG_SWAP_STATE("Scratch", &state_scratch);
171
Christopher Collins92ea77f2016-12-12 15:59:26 -0800172 for (i = 0; i < BOOT_STATUS_TABLES_COUNT; i++) {
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300173 table = &boot_status_tables[i];
Christopher Collins92ea77f2016-12-12 15:59:26 -0800174
175 if ((table->bst_magic_slot0 == 0 ||
176 table->bst_magic_slot0 == state_slot0.magic) &&
177 (table->bst_magic_scratch == 0 ||
178 table->bst_magic_scratch == state_scratch.magic) &&
179 (table->bst_copy_done_slot0 == 0 ||
180 table->bst_copy_done_slot0 == state_slot0.copy_done)) {
Marti Bolivarfd20c762017-02-07 16:52:50 -0500181 source = table->bst_status_source;
182 BOOT_LOG_INF("Boot source: %s",
183 source == BOOT_STATUS_SOURCE_NONE ? "none" :
184 source == BOOT_STATUS_SOURCE_SCRATCH ? "scratch" :
185 source == BOOT_STATUS_SOURCE_SLOT0 ? "slot 0" :
186 "BUG; can't happen");
187 return source;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800188 }
189 }
190
Marti Bolivarfd20c762017-02-07 16:52:50 -0500191 BOOT_LOG_INF("Boot source: none");
Christopher Collins92ea77f2016-12-12 15:59:26 -0800192 return BOOT_STATUS_SOURCE_NONE;
193}
194
195/**
196 * Calculates the type of swap that just completed.
Fabio Utzigb5b2f552017-06-30 10:03:47 -0300197 *
198 * This is used when a swap is interrupted by an external event. After
199 * finishing the swap operation determines what the initial request was.
Christopher Collins92ea77f2016-12-12 15:59:26 -0800200 */
201static int
202boot_previous_swap_type(void)
203{
204 int post_swap_type;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800205
206 post_swap_type = boot_swap_type();
207
Fabio Utzigb5b2f552017-06-30 10:03:47 -0300208 switch (post_swap_type) {
209 case BOOT_SWAP_TYPE_NONE : return BOOT_SWAP_TYPE_PERM;
210 case BOOT_SWAP_TYPE_REVERT : return BOOT_SWAP_TYPE_TEST;
211 case BOOT_SWAP_TYPE_PANIC : return BOOT_SWAP_TYPE_PANIC;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800212 }
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300213
Fabio Utzigb5b2f552017-06-30 10:03:47 -0300214 return BOOT_SWAP_TYPE_FAIL;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800215}
216
David Brownf5b33d82017-09-01 10:58:27 -0600217/*
218 * Compute the total size of the given image. Includes the size of
219 * the TLVs.
220 */
Fabio Utzig13d9e352017-10-05 20:32:31 -0300221#if !defined(MCUBOOT_OVERWRITE_ONLY) || defined(MCUBOOT_OVERWRITE_ONLY_FAST)
David Brownf5b33d82017-09-01 10:58:27 -0600222static int
223boot_read_image_size(int slot, struct image_header *hdr, uint32_t *size)
224{
225 const struct flash_area *fap;
226 struct image_tlv_info info;
227 int area_id;
228 int rc;
229
230 area_id = flash_area_id_from_image_slot(slot);
231 rc = flash_area_open(area_id, &fap);
232 if (rc != 0) {
233 rc = BOOT_EFLASH;
234 goto done;
235 }
236
237 rc = flash_area_read(fap, hdr->ih_hdr_size + hdr->ih_img_size,
238 &info, sizeof(info));
239 if (rc != 0) {
240 rc = BOOT_EFLASH;
241 goto done;
242 }
243 if (info.it_magic != IMAGE_TLV_INFO_MAGIC) {
244 rc = BOOT_EBADIMAGE;
245 goto done;
246 }
247 *size = hdr->ih_hdr_size + hdr->ih_img_size + info.it_tlv_tot;
248 rc = 0;
249
250done:
251 flash_area_close(fap);
Fabio Utzig2eebf112017-09-04 15:25:08 -0300252 return rc;
David Brownf5b33d82017-09-01 10:58:27 -0600253}
Fabio Utzig36ec0e72017-09-05 08:10:33 -0300254#endif /* !MCUBOOT_OVERWRITE_ONLY */
David Brownf5b33d82017-09-01 10:58:27 -0600255
Fabio Utzigc08ed212017-06-20 19:28:36 -0300256static int
Christopher Collins92ea77f2016-12-12 15:59:26 -0800257boot_read_image_header(int slot, struct image_header *out_hdr)
258{
259 const struct flash_area *fap;
260 int area_id;
261 int rc;
262
263 area_id = flash_area_id_from_image_slot(slot);
264 rc = flash_area_open(area_id, &fap);
265 if (rc != 0) {
266 rc = BOOT_EFLASH;
267 goto done;
268 }
269
270 rc = flash_area_read(fap, 0, out_hdr, sizeof *out_hdr);
271 if (rc != 0) {
272 rc = BOOT_EFLASH;
273 goto done;
274 }
275
276 rc = 0;
277
278done:
279 flash_area_close(fap);
280 return rc;
281}
282
283static int
Fabio Utzig9c25fa72017-12-12 14:57:20 -0200284boot_read_image_headers(bool require_all)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800285{
286 int rc;
287 int i;
288
289 for (i = 0; i < BOOT_NUM_SLOTS; i++) {
Marti Bolivarf804f622017-06-12 15:41:48 -0400290 rc = boot_read_image_header(i, boot_img_hdr(&boot_data, i));
Christopher Collins92ea77f2016-12-12 15:59:26 -0800291 if (rc != 0) {
Fabio Utzig9c25fa72017-12-12 14:57:20 -0200292 /* If `require_all` is set, fail on any single fail, otherwise
293 * if at least the first slot's header was read successfully,
294 * then the boot loader can attempt a boot.
295 *
296 * Failure to read any headers is a fatal error.
Christopher Collins0ff3c6c2016-12-21 12:04:17 -0800297 */
Fabio Utzig9c25fa72017-12-12 14:57:20 -0200298 if (i > 0 && !require_all) {
Christopher Collins0ff3c6c2016-12-21 12:04:17 -0800299 return 0;
300 } else {
301 return rc;
302 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800303 }
304 }
305
306 return 0;
307}
308
309static uint8_t
310boot_write_sz(void)
311{
312 uint8_t elem_sz;
313 uint8_t align;
314
315 /* Figure out what size to write update status update as. The size depends
316 * on what the minimum write size is for scratch area, active image slot.
317 * We need to use the bigger of those 2 values.
318 */
Andrzej Puzdrowskib788c712018-04-12 12:42:49 +0200319 elem_sz = flash_area_align(boot_data.imgs[0].area);
320 align = flash_area_align(boot_data.scratch_area);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800321 if (align > elem_sz) {
322 elem_sz = align;
323 }
324
325 return elem_sz;
326}
327
Christopher Collins0ff3c6c2016-12-21 12:04:17 -0800328static int
329boot_slots_compatible(void)
330{
Marti Bolivard3269fd2017-06-12 16:31:12 -0400331 size_t num_sectors_0 = boot_img_num_sectors(&boot_data, 0);
332 size_t num_sectors_1 = boot_img_num_sectors(&boot_data, 1);
333 size_t size_0, size_1;
334 size_t i;
Christopher Collins0ff3c6c2016-12-21 12:04:17 -0800335
Fabio Utziga1fae672018-03-30 10:52:38 -0300336 if (num_sectors_0 > BOOT_MAX_IMG_SECTORS || num_sectors_1 > BOOT_MAX_IMG_SECTORS) {
337 BOOT_LOG_WRN("Cannot upgrade: more sectors than allowed");
Christopher Collins0ff3c6c2016-12-21 12:04:17 -0800338 return 0;
339 }
Fabio Utziga1fae672018-03-30 10:52:38 -0300340
341 /* Ensure both image slots have identical sector layouts. */
342 if (num_sectors_0 != num_sectors_1) {
343 BOOT_LOG_WRN("Cannot upgrade: number of sectors differ between slots");
344 return 0;
345 }
346
Marti Bolivard3269fd2017-06-12 16:31:12 -0400347 for (i = 0; i < num_sectors_0; i++) {
348 size_0 = boot_img_sector_size(&boot_data, 0, i);
349 size_1 = boot_img_sector_size(&boot_data, 1, i);
350 if (size_0 != size_1) {
Fabio Utziga1fae672018-03-30 10:52:38 -0300351 BOOT_LOG_WRN("Cannot upgrade: an incompatible sector was found");
Christopher Collins0ff3c6c2016-12-21 12:04:17 -0800352 return 0;
353 }
354 }
355
356 return 1;
357}
358
Christopher Collins92ea77f2016-12-12 15:59:26 -0800359/**
360 * Determines the sector layout of both image slots and the scratch area.
361 * This information is necessary for calculating the number of bytes to erase
362 * and copy during an image swap. The information collected during this
363 * function is used to populate the boot_data global.
364 */
365static int
366boot_read_sectors(void)
367{
Christopher Collins92ea77f2016-12-12 15:59:26 -0800368 int rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800369
Marti Bolivarcca28a92017-06-12 16:52:22 -0400370 rc = boot_initialize_area(&boot_data, FLASH_AREA_IMAGE_0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800371 if (rc != 0) {
372 return BOOT_EFLASH;
373 }
374
Marti Bolivarcca28a92017-06-12 16:52:22 -0400375 rc = boot_initialize_area(&boot_data, FLASH_AREA_IMAGE_1);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800376 if (rc != 0) {
377 return BOOT_EFLASH;
378 }
379
Marti Bolivare10a7392017-06-14 16:20:07 -0400380 BOOT_WRITE_SZ(&boot_data) = boot_write_sz();
Christopher Collins92ea77f2016-12-12 15:59:26 -0800381
382 return 0;
383}
384
385static uint32_t
386boot_status_internal_off(int idx, int state, int elem_sz)
387{
388 int idx_sz;
389
390 idx_sz = elem_sz * BOOT_STATUS_STATE_COUNT;
391
392 return idx * idx_sz + state * elem_sz;
393}
394
395/**
396 * Reads the status of a partially-completed swap, if any. This is necessary
397 * to recover in case the boot lodaer was reset in the middle of a swap
398 * operation.
399 */
400static int
401boot_read_status_bytes(const struct flash_area *fap, struct boot_status *bs)
402{
403 uint32_t off;
404 uint8_t status;
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300405 int max_entries;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800406 int found;
Fabio Utziga0e1cce2017-11-23 20:04:01 -0200407 int found_idx;
408 int invalid;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800409 int rc;
410 int i;
411
412 off = boot_status_off(fap);
Fabio Utzig4cee4f72017-05-22 10:59:57 -0400413 max_entries = boot_status_entries(fap);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300414
Christopher Collins92ea77f2016-12-12 15:59:26 -0800415 found = 0;
Fabio Utziga0e1cce2017-11-23 20:04:01 -0200416 found_idx = 0;
417 invalid = 0;
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300418 for (i = 0; i < max_entries; i++) {
Marti Bolivare10a7392017-06-14 16:20:07 -0400419 rc = flash_area_read(fap, off + i * BOOT_WRITE_SZ(&boot_data),
420 &status, 1);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800421 if (rc != 0) {
422 return BOOT_EFLASH;
423 }
424
425 if (status == 0xff) {
Fabio Utziga0e1cce2017-11-23 20:04:01 -0200426 if (found && !found_idx) {
427 found_idx = i;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800428 }
429 } else if (!found) {
430 found = 1;
Fabio Utziga0e1cce2017-11-23 20:04:01 -0200431 } else if (found_idx) {
432 invalid = 1;
433 break;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800434 }
435 }
436
Fabio Utziga0e1cce2017-11-23 20:04:01 -0200437 if (invalid) {
438 /* This means there was an error writing status on the last
439 * swap. Tell user and move on to validation!
440 */
441 BOOT_LOG_ERR("Detected inconsistent status!");
442
443#if !defined(MCUBOOT_VALIDATE_SLOT0)
444 /* With validation of slot0 disabled, there is no way to be sure the
445 * swapped slot0 is OK, so abort!
446 */
447 assert(0);
448#endif
449 }
450
Christopher Collins92ea77f2016-12-12 15:59:26 -0800451 if (found) {
Fabio Utziga0e1cce2017-11-23 20:04:01 -0200452 if (!found_idx) {
453 found_idx = i;
454 }
455 found_idx--;
456 bs->idx = found_idx / BOOT_STATUS_STATE_COUNT;
457 bs->state = found_idx % BOOT_STATUS_STATE_COUNT;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800458 }
459
460 return 0;
461}
462
463/**
464 * Reads the boot status from the flash. The boot status contains
465 * the current state of an interrupted image copy operation. If the boot
466 * status is not present, or it indicates that previous copy finished,
467 * there is no operation in progress.
468 */
469static int
470boot_read_status(struct boot_status *bs)
471{
472 const struct flash_area *fap;
473 int status_loc;
474 int area_id;
475 int rc;
476
477 memset(bs, 0, sizeof *bs);
478
479 status_loc = boot_status_source();
480 switch (status_loc) {
481 case BOOT_STATUS_SOURCE_NONE:
482 return 0;
483
484 case BOOT_STATUS_SOURCE_SCRATCH:
485 area_id = FLASH_AREA_IMAGE_SCRATCH;
486 break;
487
488 case BOOT_STATUS_SOURCE_SLOT0:
489 area_id = FLASH_AREA_IMAGE_0;
490 break;
491
492 default:
493 assert(0);
494 return BOOT_EBADARGS;
495 }
496
497 rc = flash_area_open(area_id, &fap);
498 if (rc != 0) {
499 return BOOT_EFLASH;
500 }
501
Fabio Utzig46490722017-09-04 15:34:32 -0300502 rc = boot_read_status_bytes(fap, bs);
503
504 flash_area_close(fap);
505 return rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800506}
507
508/**
509 * Writes the supplied boot status to the flash file system. The boot status
510 * contains the current state of an in-progress image copy operation.
511 *
512 * @param bs The boot status to write.
513 *
514 * @return 0 on success; nonzero on failure.
515 */
516int
517boot_write_status(struct boot_status *bs)
518{
519 const struct flash_area *fap;
520 uint32_t off;
521 int area_id;
522 int rc;
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300523 uint8_t buf[BOOT_MAX_ALIGN];
David Brown9d725462017-01-23 15:50:58 -0700524 uint8_t align;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800525
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300526 /* NOTE: The first sector copied (that is the last sector on slot) contains
527 * the trailer. Since in the last step SLOT 0 is erased, the first
528 * two status writes go to the scratch which will be copied to SLOT 0!
529 */
530
Fabio Utzig2473ac02017-05-02 12:45:02 -0300531 if (bs->use_scratch) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800532 /* Write to scratch. */
533 area_id = FLASH_AREA_IMAGE_SCRATCH;
534 } else {
535 /* Write to slot 0. */
536 area_id = FLASH_AREA_IMAGE_0;
537 }
538
539 rc = flash_area_open(area_id, &fap);
540 if (rc != 0) {
541 rc = BOOT_EFLASH;
542 goto done;
543 }
544
545 off = boot_status_off(fap) +
Marti Bolivare10a7392017-06-14 16:20:07 -0400546 boot_status_internal_off(bs->idx, bs->state,
547 BOOT_WRITE_SZ(&boot_data));
Andrzej Puzdrowskib788c712018-04-12 12:42:49 +0200548 align = flash_area_align(fap);
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300549 memset(buf, 0xFF, BOOT_MAX_ALIGN);
David Brown9d725462017-01-23 15:50:58 -0700550 buf[0] = bs->state;
551
552 rc = flash_area_write(fap, off, buf, align);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800553 if (rc != 0) {
554 rc = BOOT_EFLASH;
555 goto done;
556 }
557
558 rc = 0;
559
560done:
561 flash_area_close(fap);
562 return rc;
563}
564
565/*
566 * Validate image hash/signature in a slot.
567 */
568static int
569boot_image_check(struct image_header *hdr, const struct flash_area *fap)
570{
David Browndb1d9d32017-01-06 11:07:54 -0700571 static uint8_t tmpbuf[BOOT_TMPBUF_SZ];
Christopher Collins92ea77f2016-12-12 15:59:26 -0800572
Christopher Collins92ea77f2016-12-12 15:59:26 -0800573 if (bootutil_img_validate(hdr, fap, tmpbuf, BOOT_TMPBUF_SZ,
574 NULL, 0, NULL)) {
575 return BOOT_EBADIMAGE;
576 }
577 return 0;
578}
579
580static int
581split_image_check(struct image_header *app_hdr,
582 const struct flash_area *app_fap,
583 struct image_header *loader_hdr,
584 const struct flash_area *loader_fap)
585{
586 static void *tmpbuf;
587 uint8_t loader_hash[32];
588
589 if (!tmpbuf) {
590 tmpbuf = malloc(BOOT_TMPBUF_SZ);
591 if (!tmpbuf) {
592 return BOOT_ENOMEM;
593 }
594 }
595
596 if (bootutil_img_validate(loader_hdr, loader_fap, tmpbuf, BOOT_TMPBUF_SZ,
597 NULL, 0, loader_hash)) {
598 return BOOT_EBADIMAGE;
599 }
600
601 if (bootutil_img_validate(app_hdr, app_fap, tmpbuf, BOOT_TMPBUF_SZ,
602 loader_hash, 32, NULL)) {
603 return BOOT_EBADIMAGE;
604 }
605
606 return 0;
607}
608
609static int
David Brownd930ec62016-12-14 07:59:48 -0700610boot_validate_slot(int slot)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800611{
612 const struct flash_area *fap;
Marti Bolivarf804f622017-06-12 15:41:48 -0400613 struct image_header *hdr;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800614 int rc;
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300615
Marti Bolivarf804f622017-06-12 15:41:48 -0400616 hdr = boot_img_hdr(&boot_data, slot);
617 if (hdr->ih_magic == 0xffffffff || hdr->ih_flags & IMAGE_F_NON_BOOTABLE) {
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300618 /* No bootable image in slot; continue booting from slot 0. */
Christopher Collins92ea77f2016-12-12 15:59:26 -0800619 return -1;
620 }
621
David Brownd930ec62016-12-14 07:59:48 -0700622 rc = flash_area_open(flash_area_id_from_image_slot(slot), &fap);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800623 if (rc != 0) {
624 return BOOT_EFLASH;
625 }
626
Marti Bolivarf804f622017-06-12 15:41:48 -0400627 if ((hdr->ih_magic != IMAGE_MAGIC || boot_image_check(hdr, fap) != 0)) {
David Brownb38e0442017-02-24 13:57:12 -0700628 if (slot != 0) {
629 flash_area_erase(fap, 0, fap->fa_size);
630 /* Image in slot 1 is invalid. Erase the image and
631 * continue booting from slot 0.
632 */
633 }
Fabio Utzigb6297af2017-10-05 18:26:36 -0300634 BOOT_LOG_ERR("Image in slot %d is not valid!", slot);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800635 return -1;
636 }
637
638 flash_area_close(fap);
639
640 /* Image in slot 1 is valid. */
641 return 0;
642}
643
644/**
645 * Determines which swap operation to perform, if any. If it is determined
646 * that a swap operation is required, the image in the second slot is checked
647 * for validity. If the image in the second slot is invalid, it is erased, and
648 * a swap type of "none" is indicated.
649 *
650 * @return The type of swap to perform (BOOT_SWAP_TYPE...)
651 */
652static int
653boot_validated_swap_type(void)
654{
655 int swap_type;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800656
657 swap_type = boot_swap_type();
Fabio Utzigb5b2f552017-06-30 10:03:47 -0300658 switch (swap_type) {
659 case BOOT_SWAP_TYPE_TEST:
660 case BOOT_SWAP_TYPE_PERM:
661 case BOOT_SWAP_TYPE_REVERT:
662 /* Boot loader wants to switch to slot 1. Ensure image is valid. */
663 if (boot_validate_slot(1) != 0) {
664 swap_type = BOOT_SWAP_TYPE_FAIL;
665 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800666 }
667
668 return swap_type;
669}
670
671/**
672 * Calculates the number of sectors the scratch area can contain. A "last"
673 * source sector is specified because images are copied backwards in flash
674 * (final index to index number 0).
675 *
676 * @param last_sector_idx The index of the last source sector
677 * (inclusive).
678 * @param out_first_sector_idx The index of the first source sector
679 * (inclusive) gets written here.
680 *
681 * @return The number of bytes comprised by the
682 * [first-sector, last-sector] range.
683 */
Fabio Utzig3488eef2017-06-12 10:25:43 -0300684#ifndef MCUBOOT_OVERWRITE_ONLY
Christopher Collins92ea77f2016-12-12 15:59:26 -0800685static uint32_t
686boot_copy_sz(int last_sector_idx, int *out_first_sector_idx)
687{
Marti Bolivard3269fd2017-06-12 16:31:12 -0400688 size_t scratch_sz;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800689 uint32_t new_sz;
690 uint32_t sz;
691 int i;
692
693 sz = 0;
694
Marti Bolivard3269fd2017-06-12 16:31:12 -0400695 scratch_sz = boot_scratch_area_size(&boot_data);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800696 for (i = last_sector_idx; i >= 0; i--) {
Marti Bolivard3269fd2017-06-12 16:31:12 -0400697 new_sz = sz + boot_img_sector_size(&boot_data, 0, i);
698 if (new_sz > scratch_sz) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800699 break;
700 }
701 sz = new_sz;
702 }
703
704 /* i currently refers to a sector that doesn't fit or it is -1 because all
705 * sectors have been processed. In both cases, exclude sector i.
706 */
707 *out_first_sector_idx = i + 1;
708 return sz;
709}
Fabio Utzig3488eef2017-06-12 10:25:43 -0300710#endif /* !MCUBOOT_OVERWRITE_ONLY */
Christopher Collins92ea77f2016-12-12 15:59:26 -0800711
712/**
713 * Erases a region of flash.
714 *
715 * @param flash_area_idx The ID of the flash area containing the region
716 * to erase.
717 * @param off The offset within the flash area to start the
718 * erase.
719 * @param sz The number of bytes to erase.
720 *
721 * @return 0 on success; nonzero on failure.
722 */
723static int
724boot_erase_sector(int flash_area_id, uint32_t off, uint32_t sz)
725{
726 const struct flash_area *fap;
727 int rc;
728
729 rc = flash_area_open(flash_area_id, &fap);
730 if (rc != 0) {
731 rc = BOOT_EFLASH;
732 goto done;
733 }
734
735 rc = flash_area_erase(fap, off, sz);
736 if (rc != 0) {
737 rc = BOOT_EFLASH;
738 goto done;
739 }
740
741 rc = 0;
742
743done:
744 flash_area_close(fap);
745 return rc;
746}
747
748/**
749 * Copies the contents of one flash region to another. You must erase the
750 * destination region prior to calling this function.
751 *
752 * @param flash_area_id_src The ID of the source flash area.
753 * @param flash_area_id_dst The ID of the destination flash area.
754 * @param off_src The offset within the source flash area to
755 * copy from.
756 * @param off_dst The offset within the destination flash area to
757 * copy to.
758 * @param sz The number of bytes to copy.
759 *
760 * @return 0 on success; nonzero on failure.
761 */
762static int
763boot_copy_sector(int flash_area_id_src, int flash_area_id_dst,
764 uint32_t off_src, uint32_t off_dst, uint32_t sz)
765{
766 const struct flash_area *fap_src;
767 const struct flash_area *fap_dst;
768 uint32_t bytes_copied;
769 int chunk_sz;
770 int rc;
771
772 static uint8_t buf[1024];
773
774 fap_src = NULL;
775 fap_dst = NULL;
776
777 rc = flash_area_open(flash_area_id_src, &fap_src);
778 if (rc != 0) {
779 rc = BOOT_EFLASH;
780 goto done;
781 }
782
783 rc = flash_area_open(flash_area_id_dst, &fap_dst);
784 if (rc != 0) {
785 rc = BOOT_EFLASH;
786 goto done;
787 }
788
789 bytes_copied = 0;
790 while (bytes_copied < sz) {
791 if (sz - bytes_copied > sizeof buf) {
792 chunk_sz = sizeof buf;
793 } else {
794 chunk_sz = sz - bytes_copied;
795 }
796
797 rc = flash_area_read(fap_src, off_src + bytes_copied, buf, chunk_sz);
798 if (rc != 0) {
799 rc = BOOT_EFLASH;
800 goto done;
801 }
802
803 rc = flash_area_write(fap_dst, off_dst + bytes_copied, buf, chunk_sz);
804 if (rc != 0) {
805 rc = BOOT_EFLASH;
806 goto done;
807 }
808
809 bytes_copied += chunk_sz;
810 }
811
812 rc = 0;
813
814done:
Fabio Utzige7686262017-06-28 09:26:54 -0300815 if (fap_src) {
816 flash_area_close(fap_src);
817 }
818 if (fap_dst) {
819 flash_area_close(fap_dst);
820 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800821 return rc;
822}
823
David Brown6b1b3b92017-09-19 08:59:10 -0600824#ifndef MCUBOOT_OVERWRITE_ONLY
Fabio Utzig2473ac02017-05-02 12:45:02 -0300825static inline int
Fabio Utzig46490722017-09-04 15:34:32 -0300826boot_status_init_by_id(int flash_area_id, const struct boot_status *bs)
Fabio Utzig2473ac02017-05-02 12:45:02 -0300827{
828 const struct flash_area *fap;
829 struct boot_swap_state swap_state;
830 int rc;
831
832 rc = flash_area_open(flash_area_id, &fap);
833 assert(rc == 0);
834
835 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_1, &swap_state);
836 assert(rc == 0);
837
Fabio Utzigde8a38a2017-05-23 11:15:01 -0400838 if (swap_state.image_ok == BOOT_FLAG_SET) {
Fabio Utzig2473ac02017-05-02 12:45:02 -0300839 rc = boot_write_image_ok(fap);
840 assert(rc == 0);
841 }
842
Fabio Utzig46490722017-09-04 15:34:32 -0300843 rc = boot_write_swap_size(fap, bs->swap_size);
844 assert(rc == 0);
845
Fabio Utzig2473ac02017-05-02 12:45:02 -0300846 rc = boot_write_magic(fap);
847 assert(rc == 0);
848
849 flash_area_close(fap);
850
851 return 0;
852}
David Brown6b1b3b92017-09-19 08:59:10 -0600853#endif
Fabio Utzig2473ac02017-05-02 12:45:02 -0300854
Fabio Utzig358c9352017-07-25 22:10:45 -0300855#ifndef MCUBOOT_OVERWRITE_ONLY
Fabio Utzig2473ac02017-05-02 12:45:02 -0300856static int
857boot_erase_last_sector_by_id(int flash_area_id)
858{
859 uint8_t slot;
860 uint32_t last_sector;
Fabio Utzig2473ac02017-05-02 12:45:02 -0300861 int rc;
862
863 switch (flash_area_id) {
864 case FLASH_AREA_IMAGE_0:
865 slot = 0;
866 break;
867 case FLASH_AREA_IMAGE_1:
868 slot = 1;
869 break;
870 default:
871 return BOOT_EFLASH;
872 }
873
Marti Bolivard3269fd2017-06-12 16:31:12 -0400874 last_sector = boot_img_num_sectors(&boot_data, slot) - 1;
Fabio Utzig2473ac02017-05-02 12:45:02 -0300875 rc = boot_erase_sector(flash_area_id,
Marti Bolivarea088872017-06-12 17:10:49 -0400876 boot_img_sector_off(&boot_data, slot, last_sector),
Marti Bolivard3269fd2017-06-12 16:31:12 -0400877 boot_img_sector_size(&boot_data, slot, last_sector));
Fabio Utzig2473ac02017-05-02 12:45:02 -0300878 assert(rc == 0);
879
880 return rc;
881}
Fabio Utzig358c9352017-07-25 22:10:45 -0300882#endif /* !MCUBOOT_OVERWRITE_ONLY */
Fabio Utzig2473ac02017-05-02 12:45:02 -0300883
Christopher Collins92ea77f2016-12-12 15:59:26 -0800884/**
885 * Swaps the contents of two flash regions within the two image slots.
886 *
887 * @param idx The index of the first sector in the range of
888 * sectors being swapped.
889 * @param sz The number of bytes to swap.
890 * @param bs The current boot status. This struct gets
891 * updated according to the outcome.
892 *
893 * @return 0 on success; nonzero on failure.
894 */
Fabio Utzig3488eef2017-06-12 10:25:43 -0300895#ifndef MCUBOOT_OVERWRITE_ONLY
Christopher Collins4772ac42017-02-27 20:08:01 -0800896static void
Christopher Collins92ea77f2016-12-12 15:59:26 -0800897boot_swap_sectors(int idx, uint32_t sz, struct boot_status *bs)
898{
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300899 const struct flash_area *fap;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800900 uint32_t copy_sz;
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300901 uint32_t trailer_sz;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800902 uint32_t img_off;
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300903 uint32_t scratch_trailer_off;
904 struct boot_swap_state swap_state;
Marti Bolivard3269fd2017-06-12 16:31:12 -0400905 size_t last_sector;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800906 int rc;
907
908 /* Calculate offset from start of image area. */
Marti Bolivarea088872017-06-12 17:10:49 -0400909 img_off = boot_img_sector_off(&boot_data, 0, idx);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800910
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300911 copy_sz = sz;
Marti Bolivare10a7392017-06-14 16:20:07 -0400912 trailer_sz = boot_slots_trailer_sz(BOOT_WRITE_SZ(&boot_data));
Fabio Utzig9678c972017-05-23 11:28:56 -0400913
914 /* sz in this function is always is always sized on a multiple of the
Marti Bolivarea088872017-06-12 17:10:49 -0400915 * sector size. The check against the start offset of the last sector
Fabio Utzig9678c972017-05-23 11:28:56 -0400916 * is to determine if we're swapping the last sector. The last sector
917 * needs special handling because it's where the trailer lives. If we're
918 * copying it, we need to use scratch to write the trailer temporarily.
919 *
920 * NOTE: `use_scratch` is a temporary flag (never written to flash) which
921 * controls if special handling is needed (swapping last sector).
922 */
Marti Bolivard3269fd2017-06-12 16:31:12 -0400923 last_sector = boot_img_num_sectors(&boot_data, 0) - 1;
Marti Bolivarea088872017-06-12 17:10:49 -0400924 if (img_off + sz > boot_img_sector_off(&boot_data, 0, last_sector)) {
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300925 copy_sz -= trailer_sz;
926 }
927
Fabio Utzig2473ac02017-05-02 12:45:02 -0300928 bs->use_scratch = (bs->idx == 0 && copy_sz != sz);
929
Christopher Collins92ea77f2016-12-12 15:59:26 -0800930 if (bs->state == 0) {
931 rc = boot_erase_sector(FLASH_AREA_IMAGE_SCRATCH, 0, sz);
Christopher Collins4772ac42017-02-27 20:08:01 -0800932 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800933
934 rc = boot_copy_sector(FLASH_AREA_IMAGE_1, FLASH_AREA_IMAGE_SCRATCH,
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300935 img_off, 0, copy_sz);
Christopher Collins4772ac42017-02-27 20:08:01 -0800936 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800937
Fabio Utzig2473ac02017-05-02 12:45:02 -0300938 if (bs->idx == 0) {
939 if (bs->use_scratch) {
Fabio Utzig46490722017-09-04 15:34:32 -0300940 boot_status_init_by_id(FLASH_AREA_IMAGE_SCRATCH, bs);
Fabio Utzig2473ac02017-05-02 12:45:02 -0300941 } else {
942 /* Prepare the status area... here it is known that the
943 * last sector is not being used by the image data so it's
944 * safe to erase.
945 */
946 rc = boot_erase_last_sector_by_id(FLASH_AREA_IMAGE_0);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300947 assert(rc == 0);
Fabio Utzig2473ac02017-05-02 12:45:02 -0300948
Fabio Utzig46490722017-09-04 15:34:32 -0300949 boot_status_init_by_id(FLASH_AREA_IMAGE_0, bs);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300950 }
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300951 }
952
Christopher Collins92ea77f2016-12-12 15:59:26 -0800953 bs->state = 1;
Christopher Collins4772ac42017-02-27 20:08:01 -0800954 rc = boot_write_status(bs);
Fabio Utziga0e1cce2017-11-23 20:04:01 -0200955 BOOT_STATUS_ASSERT(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800956 }
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300957
Christopher Collins92ea77f2016-12-12 15:59:26 -0800958 if (bs->state == 1) {
959 rc = boot_erase_sector(FLASH_AREA_IMAGE_1, img_off, sz);
Christopher Collins4772ac42017-02-27 20:08:01 -0800960 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800961
Christopher Collins92ea77f2016-12-12 15:59:26 -0800962 rc = boot_copy_sector(FLASH_AREA_IMAGE_0, FLASH_AREA_IMAGE_1,
963 img_off, img_off, copy_sz);
Christopher Collins4772ac42017-02-27 20:08:01 -0800964 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800965
Fabio Utzig2473ac02017-05-02 12:45:02 -0300966 if (bs->idx == 0 && !bs->use_scratch) {
967 /* If not all sectors of the slot are being swapped,
968 * guarantee here that only slot0 will have the state.
969 */
970 rc = boot_erase_last_sector_by_id(FLASH_AREA_IMAGE_1);
971 assert(rc == 0);
972 }
973
Christopher Collins92ea77f2016-12-12 15:59:26 -0800974 bs->state = 2;
Christopher Collins4772ac42017-02-27 20:08:01 -0800975 rc = boot_write_status(bs);
Fabio Utziga0e1cce2017-11-23 20:04:01 -0200976 BOOT_STATUS_ASSERT(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800977 }
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300978
Christopher Collins92ea77f2016-12-12 15:59:26 -0800979 if (bs->state == 2) {
980 rc = boot_erase_sector(FLASH_AREA_IMAGE_0, img_off, sz);
Christopher Collins4772ac42017-02-27 20:08:01 -0800981 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800982
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300983 /* NOTE: also copy trailer from scratch (has status info) */
Christopher Collins92ea77f2016-12-12 15:59:26 -0800984 rc = boot_copy_sector(FLASH_AREA_IMAGE_SCRATCH, FLASH_AREA_IMAGE_0,
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300985 0, img_off, copy_sz);
Christopher Collins4772ac42017-02-27 20:08:01 -0800986 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800987
Fabio Utzig94d998c2017-05-22 11:02:41 -0400988 if (bs->use_scratch) {
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300989 rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH, &fap);
990 assert(rc == 0);
991
992 scratch_trailer_off = boot_status_off(fap);
993
994 flash_area_close(fap);
995
996 rc = flash_area_open(FLASH_AREA_IMAGE_0, &fap);
997 assert(rc == 0);
998
999 /* copy current status that is being maintained in scratch */
1000 rc = boot_copy_sector(FLASH_AREA_IMAGE_SCRATCH, FLASH_AREA_IMAGE_0,
Marti Bolivare10a7392017-06-14 16:20:07 -04001001 scratch_trailer_off,
Fabio Utziga0bc9b52017-06-28 09:19:55 -03001002 img_off + copy_sz,
Marti Bolivare10a7392017-06-14 16:20:07 -04001003 BOOT_STATUS_STATE_COUNT * BOOT_WRITE_SZ(&boot_data));
Fabio Utziga0e1cce2017-11-23 20:04:01 -02001004 BOOT_STATUS_ASSERT(rc == 0);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001005
Fabio Utzig2473ac02017-05-02 12:45:02 -03001006 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SCRATCH,
1007 &swap_state);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001008 assert(rc == 0);
1009
Fabio Utzigde8a38a2017-05-23 11:15:01 -04001010 if (swap_state.image_ok == BOOT_FLAG_SET) {
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001011 rc = boot_write_image_ok(fap);
1012 assert(rc == 0);
1013 }
1014
Fabio Utzig46490722017-09-04 15:34:32 -03001015 rc = boot_write_swap_size(fap, bs->swap_size);
1016 assert(rc == 0);
1017
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001018 rc = boot_write_magic(fap);
1019 assert(rc == 0);
1020
1021 flash_area_close(fap);
1022 }
1023
Christopher Collins92ea77f2016-12-12 15:59:26 -08001024 bs->idx++;
1025 bs->state = 0;
Fabio Utzig2473ac02017-05-02 12:45:02 -03001026 bs->use_scratch = 0;
Christopher Collins4772ac42017-02-27 20:08:01 -08001027 rc = boot_write_status(bs);
Fabio Utziga0e1cce2017-11-23 20:04:01 -02001028 BOOT_STATUS_ASSERT(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001029 }
Christopher Collins92ea77f2016-12-12 15:59:26 -08001030}
Fabio Utzig3488eef2017-06-12 10:25:43 -03001031#endif /* !MCUBOOT_OVERWRITE_ONLY */
Christopher Collins92ea77f2016-12-12 15:59:26 -08001032
1033/**
1034 * Swaps the two images in flash. If a prior copy operation was interrupted
1035 * by a system reset, this function completes that operation.
1036 *
1037 * @param bs The current boot status. This function reads
1038 * this struct to determine if it is resuming
1039 * an interrupted swap operation. This
1040 * function writes the updated status to this
1041 * function on return.
1042 *
1043 * @return 0 on success; nonzero on failure.
1044 */
Fabio Utzig3488eef2017-06-12 10:25:43 -03001045#ifdef MCUBOOT_OVERWRITE_ONLY
David Brown17609d82017-05-05 09:41:34 -06001046static int
1047boot_copy_image(struct boot_status *bs)
1048{
Marti Bolivard3269fd2017-06-12 16:31:12 -04001049 size_t sect_count;
1050 size_t sect;
David Brown17609d82017-05-05 09:41:34 -06001051 int rc;
Fabio Utzig13d9e352017-10-05 20:32:31 -03001052 size_t size;
Marti Bolivard3269fd2017-06-12 16:31:12 -04001053 size_t this_size;
Fabio Utzig13d9e352017-10-05 20:32:31 -03001054 size_t last_sector;
1055
Fabio Utzigaaf767c2017-12-05 10:22:46 -02001056 (void)bs;
1057
Fabio Utzig13d9e352017-10-05 20:32:31 -03001058#if defined(MCUBOOT_OVERWRITE_ONLY_FAST)
1059 uint32_t src_size = 0;
1060 rc = boot_read_image_size(1, boot_img_hdr(&boot_data, 1), &src_size);
1061 assert(rc == 0);
1062#endif
David Brown17609d82017-05-05 09:41:34 -06001063
1064 BOOT_LOG_INF("Image upgrade slot1 -> slot0");
1065 BOOT_LOG_INF("Erasing slot0");
1066
Marti Bolivard3269fd2017-06-12 16:31:12 -04001067 sect_count = boot_img_num_sectors(&boot_data, 0);
Fabio Utzig13d9e352017-10-05 20:32:31 -03001068 for (sect = 0, size = 0; sect < sect_count; sect++) {
Marti Bolivard3269fd2017-06-12 16:31:12 -04001069 this_size = boot_img_sector_size(&boot_data, 0, sect);
David Brown17609d82017-05-05 09:41:34 -06001070 rc = boot_erase_sector(FLASH_AREA_IMAGE_0,
1071 size,
1072 this_size);
1073 assert(rc == 0);
1074
1075 size += this_size;
Fabio Utzig13d9e352017-10-05 20:32:31 -03001076
1077#if defined(MCUBOOT_OVERWRITE_ONLY_FAST)
1078 if (size >= src_size) {
1079 break;
1080 }
1081#endif
David Brown17609d82017-05-05 09:41:34 -06001082 }
1083
Fabio Utzig6a537ee2017-09-13 17:31:44 -03001084 BOOT_LOG_INF("Copying slot 1 to slot 0: 0x%lx bytes", size);
David Brown17609d82017-05-05 09:41:34 -06001085 rc = boot_copy_sector(FLASH_AREA_IMAGE_1, FLASH_AREA_IMAGE_0,
1086 0, 0, size);
1087
Fabio Utzig13d9e352017-10-05 20:32:31 -03001088 /*
1089 * Erases header and trailer. The trailer is erased because when a new
1090 * image is written without a trailer as is the case when using newt, the
1091 * trailer that was left might trigger a new upgrade.
1092 */
David Brown17609d82017-05-05 09:41:34 -06001093 rc = boot_erase_sector(FLASH_AREA_IMAGE_1,
Fabio Utzig13d9e352017-10-05 20:32:31 -03001094 boot_img_sector_off(&boot_data, 1, 0),
1095 boot_img_sector_size(&boot_data, 1, 0));
David Brown17609d82017-05-05 09:41:34 -06001096 assert(rc == 0);
Fabio Utzig13d9e352017-10-05 20:32:31 -03001097 last_sector = boot_img_num_sectors(&boot_data, 1) - 1;
1098 rc = boot_erase_sector(FLASH_AREA_IMAGE_1,
1099 boot_img_sector_off(&boot_data, 1, last_sector),
1100 boot_img_sector_size(&boot_data, 1, last_sector));
1101 assert(rc == 0);
1102
1103 /* TODO: Perhaps verify slot 0's signature again? */
David Brown17609d82017-05-05 09:41:34 -06001104
1105 return 0;
1106}
1107#else
Christopher Collins92ea77f2016-12-12 15:59:26 -08001108static int
1109boot_copy_image(struct boot_status *bs)
1110{
1111 uint32_t sz;
1112 int first_sector_idx;
1113 int last_sector_idx;
Fabio Utzigcd5774b2017-11-29 10:18:26 -02001114 uint32_t swap_idx;
Fabio Utzig2473ac02017-05-02 12:45:02 -03001115 struct image_header *hdr;
1116 uint32_t size;
1117 uint32_t copy_size;
Fabio Utzig2473ac02017-05-02 12:45:02 -03001118 int rc;
1119
1120 /* FIXME: just do this if asked by user? */
1121
1122 size = copy_size = 0;
1123
Fabio Utzig46490722017-09-04 15:34:32 -03001124 if (bs->idx == 0 && bs->state == 0) {
1125 /*
1126 * No swap ever happened, so need to find the largest image which
1127 * will be used to determine the amount of sectors to swap.
1128 */
1129 hdr = boot_img_hdr(&boot_data, 0);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001130 if (hdr->ih_magic == IMAGE_MAGIC) {
Fabio Utzig46490722017-09-04 15:34:32 -03001131 rc = boot_read_image_size(0, hdr, &copy_size);
David Brownf5b33d82017-09-01 10:58:27 -06001132 assert(rc == 0);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001133 }
Fabio Utzig2473ac02017-05-02 12:45:02 -03001134
Fabio Utzig46490722017-09-04 15:34:32 -03001135 hdr = boot_img_hdr(&boot_data, 1);
1136 if (hdr->ih_magic == IMAGE_MAGIC) {
1137 rc = boot_read_image_size(1, hdr, &size);
1138 assert(rc == 0);
1139 }
1140
1141 if (size > copy_size) {
1142 copy_size = size;
1143 }
1144
1145 bs->swap_size = copy_size;
1146 } else {
1147 /*
1148 * If a swap was under way, the swap_size should already be present
1149 * in the trailer...
1150 */
1151 rc = boot_read_swap_size(&bs->swap_size);
1152 assert(rc == 0);
1153
1154 copy_size = bs->swap_size;
Fabio Utzig2473ac02017-05-02 12:45:02 -03001155 }
1156
1157 size = 0;
1158 last_sector_idx = 0;
1159 while (1) {
Marti Bolivard3269fd2017-06-12 16:31:12 -04001160 size += boot_img_sector_size(&boot_data, 0, last_sector_idx);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001161 if (size >= copy_size) {
1162 break;
1163 }
1164 last_sector_idx++;
1165 }
Christopher Collins92ea77f2016-12-12 15:59:26 -08001166
1167 swap_idx = 0;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001168 while (last_sector_idx >= 0) {
1169 sz = boot_copy_sz(last_sector_idx, &first_sector_idx);
1170 if (swap_idx >= bs->idx) {
1171 boot_swap_sectors(first_sector_idx, sz, bs);
1172 }
1173
1174 last_sector_idx = first_sector_idx - 1;
1175 swap_idx++;
1176 }
1177
Fabio Utziga0e1cce2017-11-23 20:04:01 -02001178#ifdef MCUBOOT_VALIDATE_SLOT0
1179 if (boot_status_fails > 0) {
1180 BOOT_LOG_WRN("%d status write fails performing the swap", boot_status_fails);
1181 }
1182#endif
1183
Christopher Collins92ea77f2016-12-12 15:59:26 -08001184 return 0;
1185}
David Brown17609d82017-05-05 09:41:34 -06001186#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -08001187
1188/**
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03001189 * Marks the image in slot 0 as fully copied.
Christopher Collins92ea77f2016-12-12 15:59:26 -08001190 */
Fabio Utzig8d0e5882017-09-13 17:32:44 -03001191#ifndef MCUBOOT_OVERWRITE_ONLY
Christopher Collins92ea77f2016-12-12 15:59:26 -08001192static int
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03001193boot_set_copy_done(void)
Christopher Collins92ea77f2016-12-12 15:59:26 -08001194{
1195 const struct flash_area *fap;
1196 int rc;
1197
1198 rc = flash_area_open(FLASH_AREA_IMAGE_0, &fap);
1199 if (rc != 0) {
1200 return BOOT_EFLASH;
1201 }
1202
1203 rc = boot_write_copy_done(fap);
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03001204 flash_area_close(fap);
1205 return rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001206}
Fabio Utzig8d0e5882017-09-13 17:32:44 -03001207#endif /* !MCUBOOT_OVERWRITE_ONLY */
Christopher Collins92ea77f2016-12-12 15:59:26 -08001208
1209/**
1210 * Marks a reverted image in slot 0 as confirmed. This is necessary to ensure
1211 * the status bytes from the image revert operation don't get processed on a
1212 * subsequent boot.
Fabio Utzig1e56fcc2017-07-17 15:39:14 -03001213 *
1214 * NOTE: image_ok is tested before writing because if there's a valid permanent
1215 * image installed on slot0 and the new image to be upgrade to has a bad sig,
1216 * image_ok would be overwritten.
Christopher Collins92ea77f2016-12-12 15:59:26 -08001217 */
Fabio Utzig8d0e5882017-09-13 17:32:44 -03001218#ifndef MCUBOOT_OVERWRITE_ONLY
Christopher Collins92ea77f2016-12-12 15:59:26 -08001219static int
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03001220boot_set_image_ok(void)
Christopher Collins92ea77f2016-12-12 15:59:26 -08001221{
1222 const struct flash_area *fap;
Fabio Utzig1e56fcc2017-07-17 15:39:14 -03001223 struct boot_swap_state state;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001224 int rc;
1225
1226 rc = flash_area_open(FLASH_AREA_IMAGE_0, &fap);
1227 if (rc != 0) {
1228 return BOOT_EFLASH;
1229 }
1230
Fabio Utzig1e56fcc2017-07-17 15:39:14 -03001231 rc = boot_read_swap_state(fap, &state);
1232 if (rc != 0) {
1233 rc = BOOT_EFLASH;
1234 goto out;
1235 }
1236
1237 if (state.image_ok == BOOT_FLAG_UNSET) {
1238 rc = boot_write_image_ok(fap);
1239 }
1240
1241out:
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03001242 flash_area_close(fap);
1243 return rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001244}
Fabio Utzig8d0e5882017-09-13 17:32:44 -03001245#endif /* !MCUBOOT_OVERWRITE_ONLY */
Christopher Collins92ea77f2016-12-12 15:59:26 -08001246
1247/**
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001248 * Performs an image swap if one is required.
1249 *
1250 * @param out_swap_type On success, the type of swap performed gets
1251 * written here.
1252 *
1253 * @return 0 on success; nonzero on failure.
1254 */
1255static int
1256boot_swap_if_needed(int *out_swap_type)
1257{
1258 struct boot_status bs;
1259 int swap_type;
1260 int rc;
1261
1262 /* Determine if we rebooted in the middle of an image swap
1263 * operation.
1264 */
1265 rc = boot_read_status(&bs);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001266 assert(rc == 0);
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001267 if (rc != 0) {
1268 return rc;
1269 }
1270
1271 /* If a partial swap was detected, complete it. */
1272 if (bs.idx != 0 || bs.state != 0) {
1273 rc = boot_copy_image(&bs);
1274 assert(rc == 0);
1275
Fabio Utzigb5b2f552017-06-30 10:03:47 -03001276 /* NOTE: here we have finished a swap resume. The initial request
1277 * was either a TEST or PERM swap, which now after the completed
1278 * swap will be determined to be respectively REVERT (was TEST)
1279 * or NONE (was PERM).
1280 */
1281
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001282 /* Extrapolate the type of the partial swap. We need this
1283 * information to know how to mark the swap complete in flash.
1284 */
1285 swap_type = boot_previous_swap_type();
1286 } else {
1287 swap_type = boot_validated_swap_type();
1288 switch (swap_type) {
1289 case BOOT_SWAP_TYPE_TEST:
Christopher Collinsfd7eb5c2016-12-21 13:46:08 -08001290 case BOOT_SWAP_TYPE_PERM:
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001291 case BOOT_SWAP_TYPE_REVERT:
1292 rc = boot_copy_image(&bs);
1293 assert(rc == 0);
1294 break;
1295 }
1296 }
1297
1298 *out_swap_type = swap_type;
1299 return 0;
1300}
1301
1302/**
Christopher Collins92ea77f2016-12-12 15:59:26 -08001303 * Prepares the booting process. This function moves images around in flash as
1304 * appropriate, and tells you what address to boot from.
1305 *
1306 * @param rsp On success, indicates how booting should occur.
1307 *
1308 * @return 0 on success; nonzero on failure.
1309 */
1310int
1311boot_go(struct boot_rsp *rsp)
1312{
Christopher Collins92ea77f2016-12-12 15:59:26 -08001313 int swap_type;
Marti Bolivar84898652017-06-13 17:20:22 -04001314 size_t slot;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001315 int rc;
Marti Bolivarc0b47912017-06-13 17:18:09 -04001316 int fa_id;
David Brown52eee562017-07-05 11:25:09 -06001317 bool reload_headers = false;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001318
1319 /* The array of slot sectors are defined here (as opposed to file scope) so
1320 * that they don't get allocated for non-boot-loader apps. This is
1321 * necessary because the gcc option "-fdata-sections" doesn't seem to have
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001322 * any effect in older gcc versions (e.g., 4.8.4).
Christopher Collins92ea77f2016-12-12 15:59:26 -08001323 */
Marti Bolivarc50926f2017-06-14 09:35:40 -04001324 static boot_sector_t slot0_sectors[BOOT_MAX_IMG_SECTORS];
1325 static boot_sector_t slot1_sectors[BOOT_MAX_IMG_SECTORS];
Christopher Collins92ea77f2016-12-12 15:59:26 -08001326 boot_data.imgs[0].sectors = slot0_sectors;
1327 boot_data.imgs[1].sectors = slot1_sectors;
1328
Marti Bolivarc0b47912017-06-13 17:18:09 -04001329 /* Open boot_data image areas for the duration of this call. */
1330 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
1331 fa_id = flash_area_id_from_image_slot(slot);
1332 rc = flash_area_open(fa_id, &BOOT_IMG_AREA(&boot_data, slot));
1333 assert(rc == 0);
1334 }
1335 rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH,
1336 &BOOT_SCRATCH_AREA(&boot_data));
1337 assert(rc == 0);
1338
Christopher Collins92ea77f2016-12-12 15:59:26 -08001339 /* Determine the sector layout of the image slots and scratch area. */
1340 rc = boot_read_sectors();
1341 if (rc != 0) {
Fabio Utziga1fae672018-03-30 10:52:38 -03001342 BOOT_LOG_WRN("Failed reading sectors; BOOT_MAX_IMG_SECTORS=%d - too small?",
1343 BOOT_MAX_IMG_SECTORS);
Marti Bolivarc0b47912017-06-13 17:18:09 -04001344 goto out;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001345 }
1346
1347 /* Attempt to read an image header from each slot. */
Fabio Utzig9c25fa72017-12-12 14:57:20 -02001348 rc = boot_read_image_headers(false);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001349 if (rc != 0) {
Marti Bolivarc0b47912017-06-13 17:18:09 -04001350 goto out;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001351 }
1352
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001353 /* If the image slots aren't compatible, no swap is possible. Just boot
1354 * into slot 0.
1355 */
1356 if (boot_slots_compatible()) {
1357 rc = boot_swap_if_needed(&swap_type);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001358 assert(rc == 0);
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001359 if (rc != 0) {
Marti Bolivarc0b47912017-06-13 17:18:09 -04001360 goto out;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001361 }
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03001362
1363 /*
1364 * The following states need image_ok be explicitly set after the
1365 * swap was finished to avoid a new revert.
1366 */
1367 if (swap_type == BOOT_SWAP_TYPE_REVERT || swap_type == BOOT_SWAP_TYPE_FAIL) {
Fabio Utzig8d0e5882017-09-13 17:32:44 -03001368#ifndef MCUBOOT_OVERWRITE_ONLY
Fabio Utzig695d5642017-07-20 09:47:16 -03001369 rc = boot_set_image_ok();
1370 if (rc != 0) {
1371 swap_type = BOOT_SWAP_TYPE_PANIC;
1372 }
Fabio Utzig8d0e5882017-09-13 17:32:44 -03001373#endif /* !MCUBOOT_OVERWRITE_ONLY */
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03001374 }
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001375 } else {
1376 swap_type = BOOT_SWAP_TYPE_NONE;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001377 }
1378
1379 switch (swap_type) {
1380 case BOOT_SWAP_TYPE_NONE:
1381 slot = 0;
1382 break;
1383
Fabio Utzig695d5642017-07-20 09:47:16 -03001384 case BOOT_SWAP_TYPE_TEST: /* fallthrough */
1385 case BOOT_SWAP_TYPE_PERM: /* fallthrough */
Christopher Collins92ea77f2016-12-12 15:59:26 -08001386 case BOOT_SWAP_TYPE_REVERT:
1387 slot = 1;
David Brown52eee562017-07-05 11:25:09 -06001388 reload_headers = true;
Fabio Utzig8d0e5882017-09-13 17:32:44 -03001389#ifndef MCUBOOT_OVERWRITE_ONLY
Fabio Utzig695d5642017-07-20 09:47:16 -03001390 rc = boot_set_copy_done();
1391 if (rc != 0) {
1392 swap_type = BOOT_SWAP_TYPE_PANIC;
1393 }
Fabio Utzig8d0e5882017-09-13 17:32:44 -03001394#endif /* !MCUBOOT_OVERWRITE_ONLY */
Christopher Collins92ea77f2016-12-12 15:59:26 -08001395 break;
1396
1397 case BOOT_SWAP_TYPE_FAIL:
1398 /* The image in slot 1 was invalid and is now erased. Ensure we don't
1399 * try to boot into it again on the next reboot. Do this by pretending
1400 * we just reverted back to slot 0.
1401 */
1402 slot = 0;
David Brown52eee562017-07-05 11:25:09 -06001403 reload_headers = true;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001404 break;
1405
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03001406 default:
Fabio Utzig695d5642017-07-20 09:47:16 -03001407 swap_type = BOOT_SWAP_TYPE_PANIC;
1408 }
1409
1410 if (swap_type == BOOT_SWAP_TYPE_PANIC) {
1411 BOOT_LOG_ERR("panic!");
Fabio Utzigb5b2f552017-06-30 10:03:47 -03001412 assert(0);
Fabio Utzig695d5642017-07-20 09:47:16 -03001413
1414 /* Loop forever... */
1415 while (1) {}
Christopher Collins92ea77f2016-12-12 15:59:26 -08001416 }
1417
David Brown52eee562017-07-05 11:25:09 -06001418 if (reload_headers) {
Fabio Utzig9c25fa72017-12-12 14:57:20 -02001419 rc = boot_read_image_headers(false);
Fabio Utzigc6a7b0c2017-09-13 19:01:15 -03001420 if (rc != 0) {
1421 goto out;
1422 }
1423 /* Since headers were reloaded, it can be assumed we just performed a
1424 * swap or overwrite. Now the header info that should be used to
1425 * provide the data for the bootstrap, which previously was at Slot 1,
1426 * was updated to Slot 0.
1427 */
1428 slot = 0;
David Brown52eee562017-07-05 11:25:09 -06001429 }
1430
Marti Bolivarc1f939d2017-11-14 20:04:51 -05001431#ifdef MCUBOOT_VALIDATE_SLOT0
David Brown554c52e2017-06-30 16:01:07 -06001432 rc = boot_validate_slot(0);
Fabio Utzig57c40f72017-12-12 21:48:30 -02001433 ASSERT(rc == 0);
David Brown554c52e2017-06-30 16:01:07 -06001434 if (rc != 0) {
1435 rc = BOOT_EBADIMAGE;
1436 goto out;
1437 }
Fabio Utzig1e56fcc2017-07-17 15:39:14 -03001438#else
Marti Bolivarc1f939d2017-11-14 20:04:51 -05001439 /* Even if we're not re-validating slot 0, we could be booting
1440 * onto an empty flash chip. At least do a basic sanity check that
1441 * the magic number on the image is OK.
1442 */
1443 if (boot_data.imgs[0].hdr.ih_magic != IMAGE_MAGIC) {
Fabio Utzig67716012018-02-26 10:36:15 -03001444 BOOT_LOG_ERR("bad image magic 0x%lx", (unsigned long)boot_data.imgs[0].hdr.ih_magic);
Marti Bolivarc1f939d2017-11-14 20:04:51 -05001445 rc = BOOT_EBADIMAGE;
1446 goto out;
1447 }
David Brown554c52e2017-06-30 16:01:07 -06001448#endif
1449
Christopher Collins92ea77f2016-12-12 15:59:26 -08001450 /* Always boot from the primary slot. */
Andrzej Puzdrowskib788c712018-04-12 12:42:49 +02001451 rsp->br_flash_dev_id = boot_data.imgs[0].area->fa_device_id;
Marti Bolivar88f48d92017-05-01 22:30:02 -04001452 rsp->br_image_off = boot_img_slot_off(&boot_data, 0);
Marti Bolivarf804f622017-06-12 15:41:48 -04001453 rsp->br_hdr = boot_img_hdr(&boot_data, slot);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001454
Marti Bolivarc0b47912017-06-13 17:18:09 -04001455 out:
1456 flash_area_close(BOOT_SCRATCH_AREA(&boot_data));
1457 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
1458 flash_area_close(BOOT_IMG_AREA(&boot_data, BOOT_NUM_SLOTS - 1 - slot));
1459 }
1460 return rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001461}
1462
1463int
1464split_go(int loader_slot, int split_slot, void **entry)
1465{
Marti Bolivarc50926f2017-06-14 09:35:40 -04001466 boot_sector_t *sectors;
Christopher Collins034a6202017-01-11 12:19:37 -08001467 uintptr_t entry_val;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001468 int loader_flash_id;
Marti Bolivarc0b47912017-06-13 17:18:09 -04001469 int split_flash_id;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001470 int rc;
1471
Christopher Collins92ea77f2016-12-12 15:59:26 -08001472 sectors = malloc(BOOT_MAX_IMG_SECTORS * 2 * sizeof *sectors);
1473 if (sectors == NULL) {
Marti Bolivarc0b47912017-06-13 17:18:09 -04001474 return SPLIT_GO_ERR;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001475 }
Marti Bolivarc0b47912017-06-13 17:18:09 -04001476 boot_data.imgs[loader_slot].sectors = sectors + 0;
1477 boot_data.imgs[split_slot].sectors = sectors + BOOT_MAX_IMG_SECTORS;
1478
1479 loader_flash_id = flash_area_id_from_image_slot(loader_slot);
1480 rc = flash_area_open(loader_flash_id,
1481 &BOOT_IMG_AREA(&boot_data, split_slot));
1482 assert(rc == 0);
1483 split_flash_id = flash_area_id_from_image_slot(split_slot);
1484 rc = flash_area_open(split_flash_id,
1485 &BOOT_IMG_AREA(&boot_data, split_slot));
1486 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001487
1488 /* Determine the sector layout of the image slots and scratch area. */
1489 rc = boot_read_sectors();
1490 if (rc != 0) {
1491 rc = SPLIT_GO_ERR;
1492 goto done;
1493 }
1494
Fabio Utzig9c25fa72017-12-12 14:57:20 -02001495 rc = boot_read_image_headers(true);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001496 if (rc != 0) {
1497 goto done;
1498 }
1499
Christopher Collins92ea77f2016-12-12 15:59:26 -08001500 /* Don't check the bootable image flag because we could really call a
1501 * bootable or non-bootable image. Just validate that the image check
1502 * passes which is distinct from the normal check.
1503 */
Marti Bolivarf804f622017-06-12 15:41:48 -04001504 rc = split_image_check(boot_img_hdr(&boot_data, split_slot),
Marti Bolivarc0b47912017-06-13 17:18:09 -04001505 BOOT_IMG_AREA(&boot_data, split_slot),
Marti Bolivarf804f622017-06-12 15:41:48 -04001506 boot_img_hdr(&boot_data, loader_slot),
Marti Bolivarc0b47912017-06-13 17:18:09 -04001507 BOOT_IMG_AREA(&boot_data, loader_slot));
Christopher Collins92ea77f2016-12-12 15:59:26 -08001508 if (rc != 0) {
1509 rc = SPLIT_GO_NON_MATCHING;
1510 goto done;
1511 }
1512
Marti Bolivarea088872017-06-12 17:10:49 -04001513 entry_val = boot_img_slot_off(&boot_data, split_slot) +
Marti Bolivarf804f622017-06-12 15:41:48 -04001514 boot_img_hdr(&boot_data, split_slot)->ih_hdr_size;
Christopher Collins034a6202017-01-11 12:19:37 -08001515 *entry = (void *) entry_val;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001516 rc = SPLIT_GO_OK;
1517
1518done:
Marti Bolivarc0b47912017-06-13 17:18:09 -04001519 flash_area_close(BOOT_IMG_AREA(&boot_data, split_slot));
1520 flash_area_close(BOOT_IMG_AREA(&boot_data, loader_slot));
Christopher Collins92ea77f2016-12-12 15:59:26 -08001521 free(sectors);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001522 return rc;
1523}