blob: f61a29fa93f765c268efa6f1d06dcc4b66708247 [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 <os/os_malloc.h>
32#include "bootutil/bootutil.h"
33#include "bootutil/image.h"
34#include "bootutil_priv.h"
Marti Bolivarfd20c762017-02-07 16:52:50 -050035#include "bootutil/bootutil_log.h"
36
Fabio Utzigba1fbe62017-07-21 14:01:20 -030037#include "mcuboot_config/mcuboot_config.h"
Fabio Utzigeed80b62017-06-10 08:03:05 -030038
Marti Bolivar9b1f8bb2017-06-12 15:24:13 -040039static struct boot_loader_state boot_data;
Christopher Collins92ea77f2016-12-12 15:59:26 -080040
Fabio Utzigf70e3022018-01-10 15:00:42 -020041#if defined(MCUBOOT_VALIDATE_SLOT0) && !defined(MCUBOOT_OVERWRITE_ONLY)
Fabio Utziga0e1cce2017-11-23 20:04:01 -020042static int boot_status_fails = 0;
43#define BOOT_STATUS_ASSERT(x) \
44 do { \
Johann Fischered8461b2018-02-15 16:50:31 +010045 if (!(x)) { \
Fabio Utziga0e1cce2017-11-23 20:04:01 -020046 boot_status_fails++; \
47 } \
48 } while (0)
49#else
Fabio Utzig57c40f72017-12-12 21:48:30 -020050#define BOOT_STATUS_ASSERT(x) ASSERT(x)
Fabio Utziga0e1cce2017-11-23 20:04:01 -020051#endif
52
Christopher Collins92ea77f2016-12-12 15:59:26 -080053struct boot_status_table {
Christopher Collins92ea77f2016-12-12 15:59:26 -080054 uint8_t bst_magic_slot0;
55 uint8_t bst_magic_scratch;
56 uint8_t bst_copy_done_slot0;
57 uint8_t bst_status_source;
58};
59
60/**
61 * This set of tables maps swap state contents to boot status location.
62 * When searching for a match, these tables must be iterated in order.
63 */
64static const struct boot_status_table boot_status_tables[] = {
65 {
66 /* | slot-0 | scratch |
67 * ----------+------------+------------|
68 * magic | Good | Any |
Fabio Utzig39000012018-07-30 12:40:20 -030069 * copy-done | Set | N/A |
Christopher Collins92ea77f2016-12-12 15:59:26 -080070 * ----------+------------+------------'
71 * source: none |
72 * ------------------------------------'
73 */
74 .bst_magic_slot0 = BOOT_MAGIC_GOOD,
Fabio Utzig39000012018-07-30 12:40:20 -030075 .bst_magic_scratch = BOOT_MAGIC_ANY,
76 .bst_copy_done_slot0 = BOOT_FLAG_SET,
Christopher Collins92ea77f2016-12-12 15:59:26 -080077 .bst_status_source = BOOT_STATUS_SOURCE_NONE,
78 },
79
80 {
81 /* | slot-0 | scratch |
82 * ----------+------------+------------|
83 * magic | Good | Any |
Fabio Utzig39000012018-07-30 12:40:20 -030084 * copy-done | Unset | N/A |
Christopher Collins92ea77f2016-12-12 15:59:26 -080085 * ----------+------------+------------'
86 * source: slot 0 |
87 * ------------------------------------'
88 */
89 .bst_magic_slot0 = BOOT_MAGIC_GOOD,
Fabio Utzig39000012018-07-30 12:40:20 -030090 .bst_magic_scratch = BOOT_MAGIC_ANY,
91 .bst_copy_done_slot0 = BOOT_FLAG_UNSET,
Christopher Collins92ea77f2016-12-12 15:59:26 -080092 .bst_status_source = BOOT_STATUS_SOURCE_SLOT0,
93 },
94
95 {
96 /* | slot-0 | scratch |
97 * ----------+------------+------------|
98 * magic | Any | Good |
99 * copy-done | Any | N/A |
100 * ----------+------------+------------'
101 * source: scratch |
102 * ------------------------------------'
103 */
Fabio Utzig39000012018-07-30 12:40:20 -0300104 .bst_magic_slot0 = BOOT_MAGIC_ANY,
Christopher Collins92ea77f2016-12-12 15:59:26 -0800105 .bst_magic_scratch = BOOT_MAGIC_GOOD,
Fabio Utzig39000012018-07-30 12:40:20 -0300106 .bst_copy_done_slot0 = BOOT_FLAG_ANY,
Christopher Collins92ea77f2016-12-12 15:59:26 -0800107 .bst_status_source = BOOT_STATUS_SOURCE_SCRATCH,
108 },
Christopher Collins92ea77f2016-12-12 15:59:26 -0800109 {
110 /* | slot-0 | scratch |
111 * ----------+------------+------------|
112 * magic | Unset | Any |
Fabio Utzig39000012018-07-30 12:40:20 -0300113 * copy-done | Unset | N/A |
Christopher Collins92ea77f2016-12-12 15:59:26 -0800114 * ----------+------------+------------|
115 * source: varies |
116 * ------------------------------------+------------------------------+
117 * This represents one of two cases: |
118 * o No swaps ever (no status to read, so no harm in checking). |
119 * o Mid-revert; status in slot 0. |
120 * -------------------------------------------------------------------'
121 */
122 .bst_magic_slot0 = BOOT_MAGIC_UNSET,
Fabio Utzig39000012018-07-30 12:40:20 -0300123 .bst_magic_scratch = BOOT_MAGIC_ANY,
124 .bst_copy_done_slot0 = BOOT_FLAG_UNSET,
Christopher Collins92ea77f2016-12-12 15:59:26 -0800125 .bst_status_source = BOOT_STATUS_SOURCE_SLOT0,
126 },
127};
128
129#define BOOT_STATUS_TABLES_COUNT \
130 (sizeof boot_status_tables / sizeof boot_status_tables[0])
131
Marti Bolivarfd20c762017-02-07 16:52:50 -0500132#define BOOT_LOG_SWAP_STATE(area, state) \
133 BOOT_LOG_INF("%s: magic=%s, copy_done=0x%x, image_ok=0x%x", \
134 (area), \
135 ((state)->magic == BOOT_MAGIC_GOOD ? "good" : \
136 (state)->magic == BOOT_MAGIC_UNSET ? "unset" : \
137 "bad"), \
138 (state)->copy_done, \
139 (state)->image_ok)
140
Christopher Collins92ea77f2016-12-12 15:59:26 -0800141/**
142 * Determines where in flash the most recent boot status is stored. The boot
143 * status is necessary for completing a swap that was interrupted by a boot
144 * loader reset.
145 *
146 * @return A BOOT_STATUS_SOURCE_[...] code indicating where * status should be read from.
147 */
148static int
149boot_status_source(void)
150{
151 const struct boot_status_table *table;
152 struct boot_swap_state state_scratch;
153 struct boot_swap_state state_slot0;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800154 int rc;
Fabio Utzigcd5774b2017-11-29 10:18:26 -0200155 size_t i;
Marti Bolivarfd20c762017-02-07 16:52:50 -0500156 uint8_t source;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800157
Fabio Utzig2473ac02017-05-02 12:45:02 -0300158 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_0, &state_slot0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800159 assert(rc == 0);
160
Fabio Utzig2473ac02017-05-02 12:45:02 -0300161 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SCRATCH, &state_scratch);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800162 assert(rc == 0);
163
Marti Bolivarfd20c762017-02-07 16:52:50 -0500164 BOOT_LOG_SWAP_STATE("Image 0", &state_slot0);
Marti Bolivarfd20c762017-02-07 16:52:50 -0500165 BOOT_LOG_SWAP_STATE("Scratch", &state_scratch);
166
Christopher Collins92ea77f2016-12-12 15:59:26 -0800167 for (i = 0; i < BOOT_STATUS_TABLES_COUNT; i++) {
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300168 table = &boot_status_tables[i];
Christopher Collins92ea77f2016-12-12 15:59:26 -0800169
Fabio Utzig39000012018-07-30 12:40:20 -0300170 if ((table->bst_magic_slot0 == BOOT_MAGIC_ANY ||
Christopher Collins92ea77f2016-12-12 15:59:26 -0800171 table->bst_magic_slot0 == state_slot0.magic) &&
Fabio Utzig39000012018-07-30 12:40:20 -0300172 (table->bst_magic_scratch == BOOT_MAGIC_ANY ||
Christopher Collins92ea77f2016-12-12 15:59:26 -0800173 table->bst_magic_scratch == state_scratch.magic) &&
Fabio Utzig39000012018-07-30 12:40:20 -0300174 (table->bst_copy_done_slot0 == BOOT_FLAG_ANY ||
Christopher Collins92ea77f2016-12-12 15:59:26 -0800175 table->bst_copy_done_slot0 == state_slot0.copy_done)) {
Marti Bolivarfd20c762017-02-07 16:52:50 -0500176 source = table->bst_status_source;
177 BOOT_LOG_INF("Boot source: %s",
178 source == BOOT_STATUS_SOURCE_NONE ? "none" :
179 source == BOOT_STATUS_SOURCE_SCRATCH ? "scratch" :
180 source == BOOT_STATUS_SOURCE_SLOT0 ? "slot 0" :
181 "BUG; can't happen");
182 return source;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800183 }
184 }
185
Marti Bolivarfd20c762017-02-07 16:52:50 -0500186 BOOT_LOG_INF("Boot source: none");
Christopher Collins92ea77f2016-12-12 15:59:26 -0800187 return BOOT_STATUS_SOURCE_NONE;
188}
189
190/**
191 * Calculates the type of swap that just completed.
Fabio Utzigb5b2f552017-06-30 10:03:47 -0300192 *
193 * This is used when a swap is interrupted by an external event. After
194 * finishing the swap operation determines what the initial request was.
Christopher Collins92ea77f2016-12-12 15:59:26 -0800195 */
196static int
197boot_previous_swap_type(void)
198{
199 int post_swap_type;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800200
201 post_swap_type = boot_swap_type();
202
Fabio Utzigb5b2f552017-06-30 10:03:47 -0300203 switch (post_swap_type) {
204 case BOOT_SWAP_TYPE_NONE : return BOOT_SWAP_TYPE_PERM;
205 case BOOT_SWAP_TYPE_REVERT : return BOOT_SWAP_TYPE_TEST;
206 case BOOT_SWAP_TYPE_PANIC : return BOOT_SWAP_TYPE_PANIC;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800207 }
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300208
Fabio Utzigb5b2f552017-06-30 10:03:47 -0300209 return BOOT_SWAP_TYPE_FAIL;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800210}
211
David Brownf5b33d82017-09-01 10:58:27 -0600212/*
213 * Compute the total size of the given image. Includes the size of
214 * the TLVs.
215 */
Fabio Utzig13d9e352017-10-05 20:32:31 -0300216#if !defined(MCUBOOT_OVERWRITE_ONLY) || defined(MCUBOOT_OVERWRITE_ONLY_FAST)
David Brownf5b33d82017-09-01 10:58:27 -0600217static int
218boot_read_image_size(int slot, struct image_header *hdr, uint32_t *size)
219{
220 const struct flash_area *fap;
221 struct image_tlv_info info;
222 int area_id;
223 int rc;
224
225 area_id = flash_area_id_from_image_slot(slot);
226 rc = flash_area_open(area_id, &fap);
227 if (rc != 0) {
228 rc = BOOT_EFLASH;
229 goto done;
230 }
231
232 rc = flash_area_read(fap, hdr->ih_hdr_size + hdr->ih_img_size,
233 &info, sizeof(info));
234 if (rc != 0) {
235 rc = BOOT_EFLASH;
236 goto done;
237 }
238 if (info.it_magic != IMAGE_TLV_INFO_MAGIC) {
239 rc = BOOT_EBADIMAGE;
240 goto done;
241 }
242 *size = hdr->ih_hdr_size + hdr->ih_img_size + info.it_tlv_tot;
243 rc = 0;
244
245done:
246 flash_area_close(fap);
Fabio Utzig2eebf112017-09-04 15:25:08 -0300247 return rc;
David Brownf5b33d82017-09-01 10:58:27 -0600248}
Fabio Utzig36ec0e72017-09-05 08:10:33 -0300249#endif /* !MCUBOOT_OVERWRITE_ONLY */
David Brownf5b33d82017-09-01 10:58:27 -0600250
Fabio Utzigc08ed212017-06-20 19:28:36 -0300251static int
Christopher Collins92ea77f2016-12-12 15:59:26 -0800252boot_read_image_header(int slot, struct image_header *out_hdr)
253{
254 const struct flash_area *fap;
255 int area_id;
256 int rc;
257
258 area_id = flash_area_id_from_image_slot(slot);
259 rc = flash_area_open(area_id, &fap);
260 if (rc != 0) {
261 rc = BOOT_EFLASH;
262 goto done;
263 }
264
265 rc = flash_area_read(fap, 0, out_hdr, sizeof *out_hdr);
266 if (rc != 0) {
267 rc = BOOT_EFLASH;
268 goto done;
269 }
270
271 rc = 0;
272
273done:
274 flash_area_close(fap);
275 return rc;
276}
277
278static int
Fabio Utzig9c25fa72017-12-12 14:57:20 -0200279boot_read_image_headers(bool require_all)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800280{
281 int rc;
282 int i;
283
284 for (i = 0; i < BOOT_NUM_SLOTS; i++) {
Marti Bolivarf804f622017-06-12 15:41:48 -0400285 rc = boot_read_image_header(i, boot_img_hdr(&boot_data, i));
Christopher Collins92ea77f2016-12-12 15:59:26 -0800286 if (rc != 0) {
Fabio Utzig9c25fa72017-12-12 14:57:20 -0200287 /* If `require_all` is set, fail on any single fail, otherwise
288 * if at least the first slot's header was read successfully,
289 * then the boot loader can attempt a boot.
290 *
291 * Failure to read any headers is a fatal error.
Christopher Collins0ff3c6c2016-12-21 12:04:17 -0800292 */
Fabio Utzig9c25fa72017-12-12 14:57:20 -0200293 if (i > 0 && !require_all) {
Christopher Collins0ff3c6c2016-12-21 12:04:17 -0800294 return 0;
295 } else {
296 return rc;
297 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800298 }
299 }
300
301 return 0;
302}
303
304static uint8_t
305boot_write_sz(void)
306{
307 uint8_t elem_sz;
308 uint8_t align;
309
310 /* Figure out what size to write update status update as. The size depends
311 * on what the minimum write size is for scratch area, active image slot.
312 * We need to use the bigger of those 2 values.
313 */
Andrzej Puzdrowskib788c712018-04-12 12:42:49 +0200314 elem_sz = flash_area_align(boot_data.imgs[0].area);
315 align = flash_area_align(boot_data.scratch_area);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800316 if (align > elem_sz) {
317 elem_sz = align;
318 }
319
320 return elem_sz;
321}
322
Christopher Collins0ff3c6c2016-12-21 12:04:17 -0800323static int
324boot_slots_compatible(void)
325{
Marti Bolivard3269fd2017-06-12 16:31:12 -0400326 size_t num_sectors_0 = boot_img_num_sectors(&boot_data, 0);
327 size_t num_sectors_1 = boot_img_num_sectors(&boot_data, 1);
328 size_t size_0, size_1;
329 size_t i;
Christopher Collins0ff3c6c2016-12-21 12:04:17 -0800330
Fabio Utziga1fae672018-03-30 10:52:38 -0300331 if (num_sectors_0 > BOOT_MAX_IMG_SECTORS || num_sectors_1 > BOOT_MAX_IMG_SECTORS) {
332 BOOT_LOG_WRN("Cannot upgrade: more sectors than allowed");
Christopher Collins0ff3c6c2016-12-21 12:04:17 -0800333 return 0;
334 }
Fabio Utziga1fae672018-03-30 10:52:38 -0300335
336 /* Ensure both image slots have identical sector layouts. */
337 if (num_sectors_0 != num_sectors_1) {
338 BOOT_LOG_WRN("Cannot upgrade: number of sectors differ between slots");
339 return 0;
340 }
341
Marti Bolivard3269fd2017-06-12 16:31:12 -0400342 for (i = 0; i < num_sectors_0; i++) {
343 size_0 = boot_img_sector_size(&boot_data, 0, i);
344 size_1 = boot_img_sector_size(&boot_data, 1, i);
345 if (size_0 != size_1) {
Fabio Utziga1fae672018-03-30 10:52:38 -0300346 BOOT_LOG_WRN("Cannot upgrade: an incompatible sector was found");
Christopher Collins0ff3c6c2016-12-21 12:04:17 -0800347 return 0;
348 }
349 }
350
351 return 1;
352}
353
Christopher Collins92ea77f2016-12-12 15:59:26 -0800354/**
355 * Determines the sector layout of both image slots and the scratch area.
356 * This information is necessary for calculating the number of bytes to erase
357 * and copy during an image swap. The information collected during this
358 * function is used to populate the boot_data global.
359 */
360static int
361boot_read_sectors(void)
362{
Christopher Collins92ea77f2016-12-12 15:59:26 -0800363 int rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800364
Marti Bolivarcca28a92017-06-12 16:52:22 -0400365 rc = boot_initialize_area(&boot_data, FLASH_AREA_IMAGE_0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800366 if (rc != 0) {
367 return BOOT_EFLASH;
368 }
369
Marti Bolivarcca28a92017-06-12 16:52:22 -0400370 rc = boot_initialize_area(&boot_data, FLASH_AREA_IMAGE_1);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800371 if (rc != 0) {
372 return BOOT_EFLASH;
373 }
374
Marti Bolivare10a7392017-06-14 16:20:07 -0400375 BOOT_WRITE_SZ(&boot_data) = boot_write_sz();
Christopher Collins92ea77f2016-12-12 15:59:26 -0800376
377 return 0;
378}
379
380static uint32_t
381boot_status_internal_off(int idx, int state, int elem_sz)
382{
383 int idx_sz;
384
385 idx_sz = elem_sz * BOOT_STATUS_STATE_COUNT;
386
Fabio Utzig39000012018-07-30 12:40:20 -0300387 return (idx - BOOT_STATUS_IDX_0) * idx_sz +
388 (state - BOOT_STATUS_STATE_0) * elem_sz;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800389}
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++) {
Fabio Utzig178be542018-09-19 08:12:56 -0300415 rc = flash_area_read_is_empty(fap, off + i * BOOT_WRITE_SZ(&boot_data),
416 &status, 1);
417 if (rc < 0) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800418 return BOOT_EFLASH;
419 }
420
Fabio Utzig178be542018-09-19 08:12:56 -0300421 if (rc == 1) {
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--;
Fabio Utzig39000012018-07-30 12:40:20 -0300452 bs->idx = (found_idx / BOOT_STATUS_STATE_COUNT) + 1;
453 bs->state = (found_idx % BOOT_STATUS_STATE_COUNT) + 1;
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);
Fabio Utzig39000012018-07-30 12:40:20 -0300474 bs->idx = BOOT_STATUS_IDX_0;
475 bs->state = BOOT_STATUS_STATE_0;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800476
Fabio Utzig03dc9a02018-06-11 12:24:07 -0700477#ifdef MCUBOOT_OVERWRITE_ONLY
478 /* Overwrite-only doesn't make use of the swap status area. */
479 return 0;
480#endif
481
Christopher Collins92ea77f2016-12-12 15:59:26 -0800482 status_loc = boot_status_source();
483 switch (status_loc) {
484 case BOOT_STATUS_SOURCE_NONE:
485 return 0;
486
487 case BOOT_STATUS_SOURCE_SCRATCH:
488 area_id = FLASH_AREA_IMAGE_SCRATCH;
489 break;
490
491 case BOOT_STATUS_SOURCE_SLOT0:
492 area_id = FLASH_AREA_IMAGE_0;
493 break;
494
495 default:
496 assert(0);
497 return BOOT_EBADARGS;
498 }
499
500 rc = flash_area_open(area_id, &fap);
501 if (rc != 0) {
502 return BOOT_EFLASH;
503 }
504
Fabio Utzig46490722017-09-04 15:34:32 -0300505 rc = boot_read_status_bytes(fap, bs);
506
507 flash_area_close(fap);
Fabio Utzig03dc9a02018-06-11 12:24:07 -0700508
Fabio Utzig46490722017-09-04 15:34:32 -0300509 return rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800510}
511
512/**
513 * Writes the supplied boot status to the flash file system. The boot status
514 * contains the current state of an in-progress image copy operation.
515 *
516 * @param bs The boot status to write.
517 *
518 * @return 0 on success; nonzero on failure.
519 */
520int
521boot_write_status(struct boot_status *bs)
522{
523 const struct flash_area *fap;
524 uint32_t off;
525 int area_id;
526 int rc;
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300527 uint8_t buf[BOOT_MAX_ALIGN];
David Brown9d725462017-01-23 15:50:58 -0700528 uint8_t align;
Fabio Utzig39000012018-07-30 12:40:20 -0300529 uint8_t erased_val;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800530
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300531 /* NOTE: The first sector copied (that is the last sector on slot) contains
532 * the trailer. Since in the last step SLOT 0 is erased, the first
533 * two status writes go to the scratch which will be copied to SLOT 0!
534 */
535
Fabio Utzig2473ac02017-05-02 12:45:02 -0300536 if (bs->use_scratch) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800537 /* Write to scratch. */
538 area_id = FLASH_AREA_IMAGE_SCRATCH;
539 } else {
540 /* Write to slot 0. */
541 area_id = FLASH_AREA_IMAGE_0;
542 }
543
544 rc = flash_area_open(area_id, &fap);
545 if (rc != 0) {
546 rc = BOOT_EFLASH;
547 goto done;
548 }
549
550 off = boot_status_off(fap) +
Marti Bolivare10a7392017-06-14 16:20:07 -0400551 boot_status_internal_off(bs->idx, bs->state,
552 BOOT_WRITE_SZ(&boot_data));
Andrzej Puzdrowskib788c712018-04-12 12:42:49 +0200553 align = flash_area_align(fap);
Fabio Utzig39000012018-07-30 12:40:20 -0300554 erased_val = flash_area_erased_val(fap);
555 memset(buf, erased_val, BOOT_MAX_ALIGN);
David Brown9d725462017-01-23 15:50:58 -0700556 buf[0] = bs->state;
557
558 rc = flash_area_write(fap, off, buf, align);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800559 if (rc != 0) {
560 rc = BOOT_EFLASH;
561 goto done;
562 }
563
564 rc = 0;
565
566done:
567 flash_area_close(fap);
568 return rc;
569}
570
571/*
572 * Validate image hash/signature in a slot.
573 */
574static int
575boot_image_check(struct image_header *hdr, const struct flash_area *fap)
576{
David Browndb1d9d32017-01-06 11:07:54 -0700577 static uint8_t tmpbuf[BOOT_TMPBUF_SZ];
Christopher Collins92ea77f2016-12-12 15:59:26 -0800578
Christopher Collins92ea77f2016-12-12 15:59:26 -0800579 if (bootutil_img_validate(hdr, fap, tmpbuf, BOOT_TMPBUF_SZ,
580 NULL, 0, NULL)) {
581 return BOOT_EBADIMAGE;
582 }
583 return 0;
584}
585
586static int
587split_image_check(struct image_header *app_hdr,
588 const struct flash_area *app_fap,
589 struct image_header *loader_hdr,
590 const struct flash_area *loader_fap)
591{
592 static void *tmpbuf;
593 uint8_t loader_hash[32];
594
595 if (!tmpbuf) {
596 tmpbuf = malloc(BOOT_TMPBUF_SZ);
597 if (!tmpbuf) {
598 return BOOT_ENOMEM;
599 }
600 }
601
602 if (bootutil_img_validate(loader_hdr, loader_fap, tmpbuf, BOOT_TMPBUF_SZ,
603 NULL, 0, loader_hash)) {
604 return BOOT_EBADIMAGE;
605 }
606
607 if (bootutil_img_validate(app_hdr, app_fap, tmpbuf, BOOT_TMPBUF_SZ,
608 loader_hash, 32, NULL)) {
609 return BOOT_EBADIMAGE;
610 }
611
612 return 0;
613}
614
Fabio Utzig39000012018-07-30 12:40:20 -0300615static inline int
616boot_magic_is_erased(uint8_t erased_val, uint32_t magic)
617{
618 uint8_t i;
619 for (i = 0; i < sizeof(magic); i++) {
620 if (erased_val != *(((uint8_t *)&magic) + i)) {
621 return 0;
622 }
623 }
624 return 1;
625}
626
Christopher Collins92ea77f2016-12-12 15:59:26 -0800627static int
David Brownd930ec62016-12-14 07:59:48 -0700628boot_validate_slot(int slot)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800629{
630 const struct flash_area *fap;
Marti Bolivarf804f622017-06-12 15:41:48 -0400631 struct image_header *hdr;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800632 int rc;
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300633
David Brownd930ec62016-12-14 07:59:48 -0700634 rc = flash_area_open(flash_area_id_from_image_slot(slot), &fap);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800635 if (rc != 0) {
636 return BOOT_EFLASH;
637 }
638
Fabio Utzig39000012018-07-30 12:40:20 -0300639 hdr = boot_img_hdr(&boot_data, slot);
640 if (boot_magic_is_erased(flash_area_erased_val(fap), hdr->ih_magic) ||
641 hdr->ih_flags & IMAGE_F_NON_BOOTABLE) {
642 /* No bootable image in slot; continue booting from slot 0. */
643 return -1;
644 }
645
Marti Bolivarf804f622017-06-12 15:41:48 -0400646 if ((hdr->ih_magic != IMAGE_MAGIC || boot_image_check(hdr, fap) != 0)) {
David Brownb38e0442017-02-24 13:57:12 -0700647 if (slot != 0) {
648 flash_area_erase(fap, 0, fap->fa_size);
649 /* Image in slot 1 is invalid. Erase the image and
650 * continue booting from slot 0.
651 */
652 }
Fabio Utzigb6297af2017-10-05 18:26:36 -0300653 BOOT_LOG_ERR("Image in slot %d is not valid!", slot);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800654 return -1;
655 }
656
657 flash_area_close(fap);
658
659 /* Image in slot 1 is valid. */
660 return 0;
661}
662
663/**
664 * Determines which swap operation to perform, if any. If it is determined
665 * that a swap operation is required, the image in the second slot is checked
666 * for validity. If the image in the second slot is invalid, it is erased, and
667 * a swap type of "none" is indicated.
668 *
669 * @return The type of swap to perform (BOOT_SWAP_TYPE...)
670 */
671static int
672boot_validated_swap_type(void)
673{
674 int swap_type;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800675
676 swap_type = boot_swap_type();
Fabio Utzigb5b2f552017-06-30 10:03:47 -0300677 switch (swap_type) {
678 case BOOT_SWAP_TYPE_TEST:
679 case BOOT_SWAP_TYPE_PERM:
680 case BOOT_SWAP_TYPE_REVERT:
681 /* Boot loader wants to switch to slot 1. Ensure image is valid. */
682 if (boot_validate_slot(1) != 0) {
683 swap_type = BOOT_SWAP_TYPE_FAIL;
684 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800685 }
686
687 return swap_type;
688}
689
690/**
691 * Calculates the number of sectors the scratch area can contain. A "last"
692 * source sector is specified because images are copied backwards in flash
693 * (final index to index number 0).
694 *
695 * @param last_sector_idx The index of the last source sector
696 * (inclusive).
697 * @param out_first_sector_idx The index of the first source sector
698 * (inclusive) gets written here.
699 *
700 * @return The number of bytes comprised by the
701 * [first-sector, last-sector] range.
702 */
Fabio Utzig3488eef2017-06-12 10:25:43 -0300703#ifndef MCUBOOT_OVERWRITE_ONLY
Christopher Collins92ea77f2016-12-12 15:59:26 -0800704static uint32_t
705boot_copy_sz(int last_sector_idx, int *out_first_sector_idx)
706{
Marti Bolivard3269fd2017-06-12 16:31:12 -0400707 size_t scratch_sz;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800708 uint32_t new_sz;
709 uint32_t sz;
710 int i;
711
712 sz = 0;
713
Marti Bolivard3269fd2017-06-12 16:31:12 -0400714 scratch_sz = boot_scratch_area_size(&boot_data);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800715 for (i = last_sector_idx; i >= 0; i--) {
Marti Bolivard3269fd2017-06-12 16:31:12 -0400716 new_sz = sz + boot_img_sector_size(&boot_data, 0, i);
717 if (new_sz > scratch_sz) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800718 break;
719 }
720 sz = new_sz;
721 }
722
723 /* i currently refers to a sector that doesn't fit or it is -1 because all
724 * sectors have been processed. In both cases, exclude sector i.
725 */
726 *out_first_sector_idx = i + 1;
727 return sz;
728}
Fabio Utzig3488eef2017-06-12 10:25:43 -0300729#endif /* !MCUBOOT_OVERWRITE_ONLY */
Christopher Collins92ea77f2016-12-12 15:59:26 -0800730
731/**
732 * Erases a region of flash.
733 *
734 * @param flash_area_idx The ID of the flash area containing the region
735 * to erase.
736 * @param off The offset within the flash area to start the
737 * erase.
738 * @param sz The number of bytes to erase.
739 *
740 * @return 0 on success; nonzero on failure.
741 */
742static int
743boot_erase_sector(int flash_area_id, uint32_t off, uint32_t sz)
744{
745 const struct flash_area *fap;
746 int rc;
747
748 rc = flash_area_open(flash_area_id, &fap);
749 if (rc != 0) {
750 rc = BOOT_EFLASH;
751 goto done;
752 }
753
754 rc = flash_area_erase(fap, off, sz);
755 if (rc != 0) {
756 rc = BOOT_EFLASH;
757 goto done;
758 }
759
760 rc = 0;
761
762done:
763 flash_area_close(fap);
764 return rc;
765}
766
767/**
768 * Copies the contents of one flash region to another. You must erase the
769 * destination region prior to calling this function.
770 *
771 * @param flash_area_id_src The ID of the source flash area.
772 * @param flash_area_id_dst The ID of the destination flash area.
773 * @param off_src The offset within the source flash area to
774 * copy from.
775 * @param off_dst The offset within the destination flash area to
776 * copy to.
777 * @param sz The number of bytes to copy.
778 *
779 * @return 0 on success; nonzero on failure.
780 */
781static int
782boot_copy_sector(int flash_area_id_src, int flash_area_id_dst,
783 uint32_t off_src, uint32_t off_dst, uint32_t sz)
784{
785 const struct flash_area *fap_src;
786 const struct flash_area *fap_dst;
787 uint32_t bytes_copied;
788 int chunk_sz;
789 int rc;
790
791 static uint8_t buf[1024];
792
793 fap_src = NULL;
794 fap_dst = NULL;
795
796 rc = flash_area_open(flash_area_id_src, &fap_src);
797 if (rc != 0) {
798 rc = BOOT_EFLASH;
799 goto done;
800 }
801
802 rc = flash_area_open(flash_area_id_dst, &fap_dst);
803 if (rc != 0) {
804 rc = BOOT_EFLASH;
805 goto done;
806 }
807
808 bytes_copied = 0;
809 while (bytes_copied < sz) {
810 if (sz - bytes_copied > sizeof buf) {
811 chunk_sz = sizeof buf;
812 } else {
813 chunk_sz = sz - bytes_copied;
814 }
815
816 rc = flash_area_read(fap_src, off_src + bytes_copied, buf, chunk_sz);
817 if (rc != 0) {
818 rc = BOOT_EFLASH;
819 goto done;
820 }
821
822 rc = flash_area_write(fap_dst, off_dst + bytes_copied, buf, chunk_sz);
823 if (rc != 0) {
824 rc = BOOT_EFLASH;
825 goto done;
826 }
827
828 bytes_copied += chunk_sz;
829 }
830
831 rc = 0;
832
833done:
Fabio Utzige7686262017-06-28 09:26:54 -0300834 if (fap_src) {
835 flash_area_close(fap_src);
836 }
837 if (fap_dst) {
838 flash_area_close(fap_dst);
839 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800840 return rc;
841}
842
David Brown6b1b3b92017-09-19 08:59:10 -0600843#ifndef MCUBOOT_OVERWRITE_ONLY
Fabio Utzig2473ac02017-05-02 12:45:02 -0300844static inline int
Fabio Utzig46490722017-09-04 15:34:32 -0300845boot_status_init_by_id(int flash_area_id, const struct boot_status *bs)
Fabio Utzig2473ac02017-05-02 12:45:02 -0300846{
847 const struct flash_area *fap;
848 struct boot_swap_state swap_state;
849 int rc;
850
851 rc = flash_area_open(flash_area_id, &fap);
852 assert(rc == 0);
853
854 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_1, &swap_state);
855 assert(rc == 0);
856
Fabio Utzigde8a38a2017-05-23 11:15:01 -0400857 if (swap_state.image_ok == BOOT_FLAG_SET) {
Fabio Utzig2473ac02017-05-02 12:45:02 -0300858 rc = boot_write_image_ok(fap);
859 assert(rc == 0);
860 }
861
Fabio Utzig46490722017-09-04 15:34:32 -0300862 rc = boot_write_swap_size(fap, bs->swap_size);
863 assert(rc == 0);
864
Fabio Utzig2473ac02017-05-02 12:45:02 -0300865 rc = boot_write_magic(fap);
866 assert(rc == 0);
867
868 flash_area_close(fap);
869
870 return 0;
871}
David Brown6b1b3b92017-09-19 08:59:10 -0600872#endif
Fabio Utzig2473ac02017-05-02 12:45:02 -0300873
Fabio Utzig358c9352017-07-25 22:10:45 -0300874#ifndef MCUBOOT_OVERWRITE_ONLY
Fabio Utzig2473ac02017-05-02 12:45:02 -0300875static int
876boot_erase_last_sector_by_id(int flash_area_id)
877{
878 uint8_t slot;
879 uint32_t last_sector;
Fabio Utzig2473ac02017-05-02 12:45:02 -0300880 int rc;
881
882 switch (flash_area_id) {
883 case FLASH_AREA_IMAGE_0:
884 slot = 0;
885 break;
886 case FLASH_AREA_IMAGE_1:
887 slot = 1;
888 break;
889 default:
890 return BOOT_EFLASH;
891 }
892
Marti Bolivard3269fd2017-06-12 16:31:12 -0400893 last_sector = boot_img_num_sectors(&boot_data, slot) - 1;
Fabio Utzig2473ac02017-05-02 12:45:02 -0300894 rc = boot_erase_sector(flash_area_id,
Marti Bolivarea088872017-06-12 17:10:49 -0400895 boot_img_sector_off(&boot_data, slot, last_sector),
Marti Bolivard3269fd2017-06-12 16:31:12 -0400896 boot_img_sector_size(&boot_data, slot, last_sector));
Fabio Utzig2473ac02017-05-02 12:45:02 -0300897 assert(rc == 0);
898
899 return rc;
900}
Fabio Utzig358c9352017-07-25 22:10:45 -0300901#endif /* !MCUBOOT_OVERWRITE_ONLY */
Fabio Utzig2473ac02017-05-02 12:45:02 -0300902
Christopher Collins92ea77f2016-12-12 15:59:26 -0800903/**
904 * Swaps the contents of two flash regions within the two image slots.
905 *
906 * @param idx The index of the first sector in the range of
907 * sectors being swapped.
908 * @param sz The number of bytes to swap.
909 * @param bs The current boot status. This struct gets
910 * updated according to the outcome.
911 *
912 * @return 0 on success; nonzero on failure.
913 */
Fabio Utzig3488eef2017-06-12 10:25:43 -0300914#ifndef MCUBOOT_OVERWRITE_ONLY
Christopher Collins4772ac42017-02-27 20:08:01 -0800915static void
Christopher Collins92ea77f2016-12-12 15:59:26 -0800916boot_swap_sectors(int idx, uint32_t sz, struct boot_status *bs)
917{
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300918 const struct flash_area *fap;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800919 uint32_t copy_sz;
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300920 uint32_t trailer_sz;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800921 uint32_t img_off;
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300922 uint32_t scratch_trailer_off;
923 struct boot_swap_state swap_state;
Marti Bolivard3269fd2017-06-12 16:31:12 -0400924 size_t last_sector;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800925 int rc;
926
927 /* Calculate offset from start of image area. */
Marti Bolivarea088872017-06-12 17:10:49 -0400928 img_off = boot_img_sector_off(&boot_data, 0, idx);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800929
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300930 copy_sz = sz;
Marti Bolivare10a7392017-06-14 16:20:07 -0400931 trailer_sz = boot_slots_trailer_sz(BOOT_WRITE_SZ(&boot_data));
Fabio Utzig9678c972017-05-23 11:28:56 -0400932
933 /* sz in this function is always is always sized on a multiple of the
Marti Bolivarea088872017-06-12 17:10:49 -0400934 * sector size. The check against the start offset of the last sector
Fabio Utzig9678c972017-05-23 11:28:56 -0400935 * is to determine if we're swapping the last sector. The last sector
936 * needs special handling because it's where the trailer lives. If we're
937 * copying it, we need to use scratch to write the trailer temporarily.
938 *
939 * NOTE: `use_scratch` is a temporary flag (never written to flash) which
940 * controls if special handling is needed (swapping last sector).
941 */
Marti Bolivard3269fd2017-06-12 16:31:12 -0400942 last_sector = boot_img_num_sectors(&boot_data, 0) - 1;
Marti Bolivarea088872017-06-12 17:10:49 -0400943 if (img_off + sz > boot_img_sector_off(&boot_data, 0, last_sector)) {
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300944 copy_sz -= trailer_sz;
945 }
946
Fabio Utzig39000012018-07-30 12:40:20 -0300947 bs->use_scratch = (bs->idx == BOOT_STATUS_IDX_0 && copy_sz != sz);
Fabio Utzig2473ac02017-05-02 12:45:02 -0300948
Fabio Utzig39000012018-07-30 12:40:20 -0300949 if (bs->state == BOOT_STATUS_STATE_0) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800950 rc = boot_erase_sector(FLASH_AREA_IMAGE_SCRATCH, 0, sz);
Christopher Collins4772ac42017-02-27 20:08:01 -0800951 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800952
953 rc = boot_copy_sector(FLASH_AREA_IMAGE_1, FLASH_AREA_IMAGE_SCRATCH,
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300954 img_off, 0, copy_sz);
Christopher Collins4772ac42017-02-27 20:08:01 -0800955 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800956
Fabio Utzig39000012018-07-30 12:40:20 -0300957 if (bs->idx == BOOT_STATUS_IDX_0) {
Fabio Utzig2473ac02017-05-02 12:45:02 -0300958 if (bs->use_scratch) {
Fabio Utzig46490722017-09-04 15:34:32 -0300959 boot_status_init_by_id(FLASH_AREA_IMAGE_SCRATCH, bs);
Fabio Utzig2473ac02017-05-02 12:45:02 -0300960 } else {
961 /* Prepare the status area... here it is known that the
962 * last sector is not being used by the image data so it's
963 * safe to erase.
964 */
965 rc = boot_erase_last_sector_by_id(FLASH_AREA_IMAGE_0);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300966 assert(rc == 0);
Fabio Utzig2473ac02017-05-02 12:45:02 -0300967
Fabio Utzig46490722017-09-04 15:34:32 -0300968 boot_status_init_by_id(FLASH_AREA_IMAGE_0, bs);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300969 }
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300970 }
971
Fabio Utzig39000012018-07-30 12:40:20 -0300972 bs->state = BOOT_STATUS_STATE_1;
Christopher Collins4772ac42017-02-27 20:08:01 -0800973 rc = boot_write_status(bs);
Fabio Utziga0e1cce2017-11-23 20:04:01 -0200974 BOOT_STATUS_ASSERT(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800975 }
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300976
Fabio Utzig39000012018-07-30 12:40:20 -0300977 if (bs->state == BOOT_STATUS_STATE_1) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800978 rc = boot_erase_sector(FLASH_AREA_IMAGE_1, img_off, sz);
Christopher Collins4772ac42017-02-27 20:08:01 -0800979 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800980
Christopher Collins92ea77f2016-12-12 15:59:26 -0800981 rc = boot_copy_sector(FLASH_AREA_IMAGE_0, FLASH_AREA_IMAGE_1,
982 img_off, img_off, copy_sz);
Christopher Collins4772ac42017-02-27 20:08:01 -0800983 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800984
Fabio Utzig39000012018-07-30 12:40:20 -0300985 if (bs->idx == BOOT_STATUS_IDX_0 && !bs->use_scratch) {
Fabio Utzig2473ac02017-05-02 12:45:02 -0300986 /* If not all sectors of the slot are being swapped,
987 * guarantee here that only slot0 will have the state.
988 */
989 rc = boot_erase_last_sector_by_id(FLASH_AREA_IMAGE_1);
990 assert(rc == 0);
991 }
992
Fabio Utzig39000012018-07-30 12:40:20 -0300993 bs->state = BOOT_STATUS_STATE_2;
Christopher Collins4772ac42017-02-27 20:08:01 -0800994 rc = boot_write_status(bs);
Fabio Utziga0e1cce2017-11-23 20:04:01 -0200995 BOOT_STATUS_ASSERT(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800996 }
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300997
Fabio Utzig39000012018-07-30 12:40:20 -0300998 if (bs->state == BOOT_STATUS_STATE_2) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800999 rc = boot_erase_sector(FLASH_AREA_IMAGE_0, img_off, sz);
Christopher Collins4772ac42017-02-27 20:08:01 -08001000 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001001
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001002 /* NOTE: also copy trailer from scratch (has status info) */
Christopher Collins92ea77f2016-12-12 15:59:26 -08001003 rc = boot_copy_sector(FLASH_AREA_IMAGE_SCRATCH, FLASH_AREA_IMAGE_0,
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001004 0, img_off, copy_sz);
Christopher Collins4772ac42017-02-27 20:08:01 -08001005 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001006
Fabio Utzig94d998c2017-05-22 11:02:41 -04001007 if (bs->use_scratch) {
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001008 rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH, &fap);
1009 assert(rc == 0);
1010
1011 scratch_trailer_off = boot_status_off(fap);
1012
1013 flash_area_close(fap);
1014
1015 rc = flash_area_open(FLASH_AREA_IMAGE_0, &fap);
1016 assert(rc == 0);
1017
1018 /* copy current status that is being maintained in scratch */
1019 rc = boot_copy_sector(FLASH_AREA_IMAGE_SCRATCH, FLASH_AREA_IMAGE_0,
Marti Bolivare10a7392017-06-14 16:20:07 -04001020 scratch_trailer_off,
Fabio Utziga0bc9b52017-06-28 09:19:55 -03001021 img_off + copy_sz,
Marti Bolivare10a7392017-06-14 16:20:07 -04001022 BOOT_STATUS_STATE_COUNT * BOOT_WRITE_SZ(&boot_data));
Fabio Utziga0e1cce2017-11-23 20:04:01 -02001023 BOOT_STATUS_ASSERT(rc == 0);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001024
Fabio Utzig2473ac02017-05-02 12:45:02 -03001025 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SCRATCH,
1026 &swap_state);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001027 assert(rc == 0);
1028
Fabio Utzigde8a38a2017-05-23 11:15:01 -04001029 if (swap_state.image_ok == BOOT_FLAG_SET) {
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001030 rc = boot_write_image_ok(fap);
1031 assert(rc == 0);
1032 }
1033
Fabio Utzig46490722017-09-04 15:34:32 -03001034 rc = boot_write_swap_size(fap, bs->swap_size);
1035 assert(rc == 0);
1036
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001037 rc = boot_write_magic(fap);
1038 assert(rc == 0);
1039
1040 flash_area_close(fap);
1041 }
1042
Christopher Collins92ea77f2016-12-12 15:59:26 -08001043 bs->idx++;
Fabio Utzig39000012018-07-30 12:40:20 -03001044 bs->state = BOOT_STATUS_STATE_0;
Fabio Utzig2473ac02017-05-02 12:45:02 -03001045 bs->use_scratch = 0;
Christopher Collins4772ac42017-02-27 20:08:01 -08001046 rc = boot_write_status(bs);
Fabio Utziga0e1cce2017-11-23 20:04:01 -02001047 BOOT_STATUS_ASSERT(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001048 }
Christopher Collins92ea77f2016-12-12 15:59:26 -08001049}
Fabio Utzig3488eef2017-06-12 10:25:43 -03001050#endif /* !MCUBOOT_OVERWRITE_ONLY */
Christopher Collins92ea77f2016-12-12 15:59:26 -08001051
1052/**
1053 * Swaps the two images in flash. If a prior copy operation was interrupted
1054 * by a system reset, this function completes that operation.
1055 *
1056 * @param bs The current boot status. This function reads
1057 * this struct to determine if it is resuming
1058 * an interrupted swap operation. This
1059 * function writes the updated status to this
1060 * function on return.
1061 *
1062 * @return 0 on success; nonzero on failure.
1063 */
Fabio Utzig3488eef2017-06-12 10:25:43 -03001064#ifdef MCUBOOT_OVERWRITE_ONLY
David Brown17609d82017-05-05 09:41:34 -06001065static int
1066boot_copy_image(struct boot_status *bs)
1067{
Marti Bolivard3269fd2017-06-12 16:31:12 -04001068 size_t sect_count;
1069 size_t sect;
David Brown17609d82017-05-05 09:41:34 -06001070 int rc;
Fabio Utzig13d9e352017-10-05 20:32:31 -03001071 size_t size;
Marti Bolivard3269fd2017-06-12 16:31:12 -04001072 size_t this_size;
Fabio Utzig13d9e352017-10-05 20:32:31 -03001073 size_t last_sector;
1074
Fabio Utzigaaf767c2017-12-05 10:22:46 -02001075 (void)bs;
1076
Fabio Utzig13d9e352017-10-05 20:32:31 -03001077#if defined(MCUBOOT_OVERWRITE_ONLY_FAST)
1078 uint32_t src_size = 0;
1079 rc = boot_read_image_size(1, boot_img_hdr(&boot_data, 1), &src_size);
1080 assert(rc == 0);
1081#endif
David Brown17609d82017-05-05 09:41:34 -06001082
1083 BOOT_LOG_INF("Image upgrade slot1 -> slot0");
1084 BOOT_LOG_INF("Erasing slot0");
1085
Marti Bolivard3269fd2017-06-12 16:31:12 -04001086 sect_count = boot_img_num_sectors(&boot_data, 0);
Fabio Utzig13d9e352017-10-05 20:32:31 -03001087 for (sect = 0, size = 0; sect < sect_count; sect++) {
Marti Bolivard3269fd2017-06-12 16:31:12 -04001088 this_size = boot_img_sector_size(&boot_data, 0, sect);
David Brown17609d82017-05-05 09:41:34 -06001089 rc = boot_erase_sector(FLASH_AREA_IMAGE_0,
1090 size,
1091 this_size);
1092 assert(rc == 0);
1093
1094 size += this_size;
Fabio Utzig13d9e352017-10-05 20:32:31 -03001095
1096#if defined(MCUBOOT_OVERWRITE_ONLY_FAST)
1097 if (size >= src_size) {
1098 break;
1099 }
1100#endif
David Brown17609d82017-05-05 09:41:34 -06001101 }
1102
Fabio Utzig6a537ee2017-09-13 17:31:44 -03001103 BOOT_LOG_INF("Copying slot 1 to slot 0: 0x%lx bytes", size);
David Brown17609d82017-05-05 09:41:34 -06001104 rc = boot_copy_sector(FLASH_AREA_IMAGE_1, FLASH_AREA_IMAGE_0,
1105 0, 0, size);
1106
Fabio Utzig13d9e352017-10-05 20:32:31 -03001107 /*
1108 * Erases header and trailer. The trailer is erased because when a new
1109 * image is written without a trailer as is the case when using newt, the
1110 * trailer that was left might trigger a new upgrade.
1111 */
David Brown17609d82017-05-05 09:41:34 -06001112 rc = boot_erase_sector(FLASH_AREA_IMAGE_1,
Fabio Utzig13d9e352017-10-05 20:32:31 -03001113 boot_img_sector_off(&boot_data, 1, 0),
1114 boot_img_sector_size(&boot_data, 1, 0));
David Brown17609d82017-05-05 09:41:34 -06001115 assert(rc == 0);
Fabio Utzig13d9e352017-10-05 20:32:31 -03001116 last_sector = boot_img_num_sectors(&boot_data, 1) - 1;
1117 rc = boot_erase_sector(FLASH_AREA_IMAGE_1,
1118 boot_img_sector_off(&boot_data, 1, last_sector),
1119 boot_img_sector_size(&boot_data, 1, last_sector));
1120 assert(rc == 0);
1121
1122 /* TODO: Perhaps verify slot 0's signature again? */
David Brown17609d82017-05-05 09:41:34 -06001123
1124 return 0;
1125}
1126#else
Christopher Collins92ea77f2016-12-12 15:59:26 -08001127static int
1128boot_copy_image(struct boot_status *bs)
1129{
1130 uint32_t sz;
1131 int first_sector_idx;
1132 int last_sector_idx;
Fabio Utzigcd5774b2017-11-29 10:18:26 -02001133 uint32_t swap_idx;
Fabio Utzig2473ac02017-05-02 12:45:02 -03001134 struct image_header *hdr;
1135 uint32_t size;
1136 uint32_t copy_size;
Fabio Utzig2473ac02017-05-02 12:45:02 -03001137 int rc;
1138
1139 /* FIXME: just do this if asked by user? */
1140
1141 size = copy_size = 0;
1142
Fabio Utzig39000012018-07-30 12:40:20 -03001143 if (bs->idx == BOOT_STATUS_IDX_0 && bs->state == BOOT_STATUS_STATE_0) {
Fabio Utzig46490722017-09-04 15:34:32 -03001144 /*
1145 * No swap ever happened, so need to find the largest image which
1146 * will be used to determine the amount of sectors to swap.
1147 */
1148 hdr = boot_img_hdr(&boot_data, 0);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001149 if (hdr->ih_magic == IMAGE_MAGIC) {
Fabio Utzig46490722017-09-04 15:34:32 -03001150 rc = boot_read_image_size(0, hdr, &copy_size);
David Brownf5b33d82017-09-01 10:58:27 -06001151 assert(rc == 0);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001152 }
Fabio Utzig2473ac02017-05-02 12:45:02 -03001153
Fabio Utzig46490722017-09-04 15:34:32 -03001154 hdr = boot_img_hdr(&boot_data, 1);
1155 if (hdr->ih_magic == IMAGE_MAGIC) {
1156 rc = boot_read_image_size(1, hdr, &size);
1157 assert(rc == 0);
1158 }
1159
1160 if (size > copy_size) {
1161 copy_size = size;
1162 }
1163
1164 bs->swap_size = copy_size;
1165 } else {
1166 /*
1167 * If a swap was under way, the swap_size should already be present
1168 * in the trailer...
1169 */
1170 rc = boot_read_swap_size(&bs->swap_size);
1171 assert(rc == 0);
1172
1173 copy_size = bs->swap_size;
Fabio Utzig2473ac02017-05-02 12:45:02 -03001174 }
1175
1176 size = 0;
1177 last_sector_idx = 0;
1178 while (1) {
Marti Bolivard3269fd2017-06-12 16:31:12 -04001179 size += boot_img_sector_size(&boot_data, 0, last_sector_idx);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001180 if (size >= copy_size) {
1181 break;
1182 }
1183 last_sector_idx++;
1184 }
Christopher Collins92ea77f2016-12-12 15:59:26 -08001185
1186 swap_idx = 0;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001187 while (last_sector_idx >= 0) {
1188 sz = boot_copy_sz(last_sector_idx, &first_sector_idx);
Fabio Utzig39000012018-07-30 12:40:20 -03001189 if (swap_idx >= (bs->idx - BOOT_STATUS_IDX_0)) {
Christopher Collins92ea77f2016-12-12 15:59:26 -08001190 boot_swap_sectors(first_sector_idx, sz, bs);
1191 }
1192
1193 last_sector_idx = first_sector_idx - 1;
1194 swap_idx++;
1195 }
1196
Fabio Utziga0e1cce2017-11-23 20:04:01 -02001197#ifdef MCUBOOT_VALIDATE_SLOT0
1198 if (boot_status_fails > 0) {
1199 BOOT_LOG_WRN("%d status write fails performing the swap", boot_status_fails);
1200 }
1201#endif
1202
Christopher Collins92ea77f2016-12-12 15:59:26 -08001203 return 0;
1204}
David Brown17609d82017-05-05 09:41:34 -06001205#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -08001206
1207/**
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03001208 * Marks the image in slot 0 as fully copied.
Christopher Collins92ea77f2016-12-12 15:59:26 -08001209 */
Fabio Utzig8d0e5882017-09-13 17:32:44 -03001210#ifndef MCUBOOT_OVERWRITE_ONLY
Christopher Collins92ea77f2016-12-12 15:59:26 -08001211static int
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03001212boot_set_copy_done(void)
Christopher Collins92ea77f2016-12-12 15:59:26 -08001213{
1214 const struct flash_area *fap;
1215 int rc;
1216
1217 rc = flash_area_open(FLASH_AREA_IMAGE_0, &fap);
1218 if (rc != 0) {
1219 return BOOT_EFLASH;
1220 }
1221
1222 rc = boot_write_copy_done(fap);
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03001223 flash_area_close(fap);
1224 return rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001225}
Fabio Utzig8d0e5882017-09-13 17:32:44 -03001226#endif /* !MCUBOOT_OVERWRITE_ONLY */
Christopher Collins92ea77f2016-12-12 15:59:26 -08001227
1228/**
1229 * Marks a reverted image in slot 0 as confirmed. This is necessary to ensure
1230 * the status bytes from the image revert operation don't get processed on a
1231 * subsequent boot.
Fabio Utzig1e56fcc2017-07-17 15:39:14 -03001232 *
1233 * NOTE: image_ok is tested before writing because if there's a valid permanent
1234 * image installed on slot0 and the new image to be upgrade to has a bad sig,
1235 * image_ok would be overwritten.
Christopher Collins92ea77f2016-12-12 15:59:26 -08001236 */
Fabio Utzig8d0e5882017-09-13 17:32:44 -03001237#ifndef MCUBOOT_OVERWRITE_ONLY
Christopher Collins92ea77f2016-12-12 15:59:26 -08001238static int
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03001239boot_set_image_ok(void)
Christopher Collins92ea77f2016-12-12 15:59:26 -08001240{
1241 const struct flash_area *fap;
Fabio Utzig1e56fcc2017-07-17 15:39:14 -03001242 struct boot_swap_state state;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001243 int rc;
1244
1245 rc = flash_area_open(FLASH_AREA_IMAGE_0, &fap);
1246 if (rc != 0) {
1247 return BOOT_EFLASH;
1248 }
1249
Fabio Utzig1e56fcc2017-07-17 15:39:14 -03001250 rc = boot_read_swap_state(fap, &state);
1251 if (rc != 0) {
1252 rc = BOOT_EFLASH;
1253 goto out;
1254 }
1255
1256 if (state.image_ok == BOOT_FLAG_UNSET) {
1257 rc = boot_write_image_ok(fap);
1258 }
1259
1260out:
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03001261 flash_area_close(fap);
1262 return rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001263}
Fabio Utzig8d0e5882017-09-13 17:32:44 -03001264#endif /* !MCUBOOT_OVERWRITE_ONLY */
Christopher Collins92ea77f2016-12-12 15:59:26 -08001265
1266/**
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001267 * Performs an image swap if one is required.
1268 *
1269 * @param out_swap_type On success, the type of swap performed gets
1270 * written here.
1271 *
1272 * @return 0 on success; nonzero on failure.
1273 */
1274static int
1275boot_swap_if_needed(int *out_swap_type)
1276{
1277 struct boot_status bs;
1278 int swap_type;
1279 int rc;
1280
1281 /* Determine if we rebooted in the middle of an image swap
1282 * operation.
1283 */
1284 rc = boot_read_status(&bs);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001285 assert(rc == 0);
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001286 if (rc != 0) {
1287 return rc;
1288 }
1289
1290 /* If a partial swap was detected, complete it. */
Fabio Utzig39000012018-07-30 12:40:20 -03001291 if (bs.idx != BOOT_STATUS_IDX_0 || bs.state != BOOT_STATUS_STATE_0) {
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001292 rc = boot_copy_image(&bs);
1293 assert(rc == 0);
1294
Fabio Utzigb5b2f552017-06-30 10:03:47 -03001295 /* NOTE: here we have finished a swap resume. The initial request
1296 * was either a TEST or PERM swap, which now after the completed
1297 * swap will be determined to be respectively REVERT (was TEST)
1298 * or NONE (was PERM).
1299 */
1300
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001301 /* Extrapolate the type of the partial swap. We need this
1302 * information to know how to mark the swap complete in flash.
1303 */
1304 swap_type = boot_previous_swap_type();
1305 } else {
1306 swap_type = boot_validated_swap_type();
1307 switch (swap_type) {
1308 case BOOT_SWAP_TYPE_TEST:
Christopher Collinsfd7eb5c2016-12-21 13:46:08 -08001309 case BOOT_SWAP_TYPE_PERM:
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001310 case BOOT_SWAP_TYPE_REVERT:
1311 rc = boot_copy_image(&bs);
1312 assert(rc == 0);
1313 break;
1314 }
1315 }
1316
1317 *out_swap_type = swap_type;
1318 return 0;
1319}
1320
1321/**
Christopher Collins92ea77f2016-12-12 15:59:26 -08001322 * Prepares the booting process. This function moves images around in flash as
1323 * appropriate, and tells you what address to boot from.
1324 *
1325 * @param rsp On success, indicates how booting should occur.
1326 *
1327 * @return 0 on success; nonzero on failure.
1328 */
1329int
1330boot_go(struct boot_rsp *rsp)
1331{
Christopher Collins92ea77f2016-12-12 15:59:26 -08001332 int swap_type;
Marti Bolivar84898652017-06-13 17:20:22 -04001333 size_t slot;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001334 int rc;
Marti Bolivarc0b47912017-06-13 17:18:09 -04001335 int fa_id;
David Brown52eee562017-07-05 11:25:09 -06001336 bool reload_headers = false;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001337
1338 /* The array of slot sectors are defined here (as opposed to file scope) so
1339 * that they don't get allocated for non-boot-loader apps. This is
1340 * necessary because the gcc option "-fdata-sections" doesn't seem to have
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001341 * any effect in older gcc versions (e.g., 4.8.4).
Christopher Collins92ea77f2016-12-12 15:59:26 -08001342 */
Marti Bolivarc50926f2017-06-14 09:35:40 -04001343 static boot_sector_t slot0_sectors[BOOT_MAX_IMG_SECTORS];
1344 static boot_sector_t slot1_sectors[BOOT_MAX_IMG_SECTORS];
Christopher Collins92ea77f2016-12-12 15:59:26 -08001345 boot_data.imgs[0].sectors = slot0_sectors;
1346 boot_data.imgs[1].sectors = slot1_sectors;
1347
Marti Bolivarc0b47912017-06-13 17:18:09 -04001348 /* Open boot_data image areas for the duration of this call. */
1349 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
1350 fa_id = flash_area_id_from_image_slot(slot);
1351 rc = flash_area_open(fa_id, &BOOT_IMG_AREA(&boot_data, slot));
1352 assert(rc == 0);
1353 }
1354 rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH,
1355 &BOOT_SCRATCH_AREA(&boot_data));
1356 assert(rc == 0);
1357
Christopher Collins92ea77f2016-12-12 15:59:26 -08001358 /* Determine the sector layout of the image slots and scratch area. */
1359 rc = boot_read_sectors();
1360 if (rc != 0) {
Fabio Utziga1fae672018-03-30 10:52:38 -03001361 BOOT_LOG_WRN("Failed reading sectors; BOOT_MAX_IMG_SECTORS=%d - too small?",
1362 BOOT_MAX_IMG_SECTORS);
Marti Bolivarc0b47912017-06-13 17:18:09 -04001363 goto out;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001364 }
1365
1366 /* Attempt to read an image header from each slot. */
Fabio Utzig9c25fa72017-12-12 14:57:20 -02001367 rc = boot_read_image_headers(false);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001368 if (rc != 0) {
Marti Bolivarc0b47912017-06-13 17:18:09 -04001369 goto out;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001370 }
1371
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001372 /* If the image slots aren't compatible, no swap is possible. Just boot
1373 * into slot 0.
1374 */
1375 if (boot_slots_compatible()) {
1376 rc = boot_swap_if_needed(&swap_type);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001377 assert(rc == 0);
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001378 if (rc != 0) {
Marti Bolivarc0b47912017-06-13 17:18:09 -04001379 goto out;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001380 }
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03001381
1382 /*
1383 * The following states need image_ok be explicitly set after the
1384 * swap was finished to avoid a new revert.
1385 */
1386 if (swap_type == BOOT_SWAP_TYPE_REVERT || swap_type == BOOT_SWAP_TYPE_FAIL) {
Fabio Utzig8d0e5882017-09-13 17:32:44 -03001387#ifndef MCUBOOT_OVERWRITE_ONLY
Fabio Utzig695d5642017-07-20 09:47:16 -03001388 rc = boot_set_image_ok();
1389 if (rc != 0) {
1390 swap_type = BOOT_SWAP_TYPE_PANIC;
1391 }
Fabio Utzig8d0e5882017-09-13 17:32:44 -03001392#endif /* !MCUBOOT_OVERWRITE_ONLY */
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03001393 }
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001394 } else {
1395 swap_type = BOOT_SWAP_TYPE_NONE;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001396 }
1397
1398 switch (swap_type) {
1399 case BOOT_SWAP_TYPE_NONE:
1400 slot = 0;
1401 break;
1402
Fabio Utzig695d5642017-07-20 09:47:16 -03001403 case BOOT_SWAP_TYPE_TEST: /* fallthrough */
1404 case BOOT_SWAP_TYPE_PERM: /* fallthrough */
Christopher Collins92ea77f2016-12-12 15:59:26 -08001405 case BOOT_SWAP_TYPE_REVERT:
1406 slot = 1;
David Brown52eee562017-07-05 11:25:09 -06001407 reload_headers = true;
Fabio Utzig8d0e5882017-09-13 17:32:44 -03001408#ifndef MCUBOOT_OVERWRITE_ONLY
Fabio Utzig695d5642017-07-20 09:47:16 -03001409 rc = boot_set_copy_done();
1410 if (rc != 0) {
1411 swap_type = BOOT_SWAP_TYPE_PANIC;
1412 }
Fabio Utzig8d0e5882017-09-13 17:32:44 -03001413#endif /* !MCUBOOT_OVERWRITE_ONLY */
Christopher Collins92ea77f2016-12-12 15:59:26 -08001414 break;
1415
1416 case BOOT_SWAP_TYPE_FAIL:
1417 /* The image in slot 1 was invalid and is now erased. Ensure we don't
1418 * try to boot into it again on the next reboot. Do this by pretending
1419 * we just reverted back to slot 0.
1420 */
1421 slot = 0;
David Brown52eee562017-07-05 11:25:09 -06001422 reload_headers = true;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001423 break;
1424
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03001425 default:
Fabio Utzig695d5642017-07-20 09:47:16 -03001426 swap_type = BOOT_SWAP_TYPE_PANIC;
1427 }
1428
1429 if (swap_type == BOOT_SWAP_TYPE_PANIC) {
1430 BOOT_LOG_ERR("panic!");
Fabio Utzigb5b2f552017-06-30 10:03:47 -03001431 assert(0);
Fabio Utzig695d5642017-07-20 09:47:16 -03001432
1433 /* Loop forever... */
1434 while (1) {}
Christopher Collins92ea77f2016-12-12 15:59:26 -08001435 }
1436
David Brown52eee562017-07-05 11:25:09 -06001437 if (reload_headers) {
Fabio Utzig9c25fa72017-12-12 14:57:20 -02001438 rc = boot_read_image_headers(false);
Fabio Utzigc6a7b0c2017-09-13 19:01:15 -03001439 if (rc != 0) {
1440 goto out;
1441 }
1442 /* Since headers were reloaded, it can be assumed we just performed a
1443 * swap or overwrite. Now the header info that should be used to
1444 * provide the data for the bootstrap, which previously was at Slot 1,
1445 * was updated to Slot 0.
1446 */
1447 slot = 0;
David Brown52eee562017-07-05 11:25:09 -06001448 }
1449
Marti Bolivarc1f939d2017-11-14 20:04:51 -05001450#ifdef MCUBOOT_VALIDATE_SLOT0
David Brown554c52e2017-06-30 16:01:07 -06001451 rc = boot_validate_slot(0);
Fabio Utzig57c40f72017-12-12 21:48:30 -02001452 ASSERT(rc == 0);
David Brown554c52e2017-06-30 16:01:07 -06001453 if (rc != 0) {
1454 rc = BOOT_EBADIMAGE;
1455 goto out;
1456 }
Fabio Utzig1e56fcc2017-07-17 15:39:14 -03001457#else
Marti Bolivarc1f939d2017-11-14 20:04:51 -05001458 /* Even if we're not re-validating slot 0, we could be booting
1459 * onto an empty flash chip. At least do a basic sanity check that
1460 * the magic number on the image is OK.
1461 */
1462 if (boot_data.imgs[0].hdr.ih_magic != IMAGE_MAGIC) {
Fabio Utzig67716012018-02-26 10:36:15 -03001463 BOOT_LOG_ERR("bad image magic 0x%lx", (unsigned long)boot_data.imgs[0].hdr.ih_magic);
Marti Bolivarc1f939d2017-11-14 20:04:51 -05001464 rc = BOOT_EBADIMAGE;
1465 goto out;
1466 }
David Brown554c52e2017-06-30 16:01:07 -06001467#endif
1468
Christopher Collins92ea77f2016-12-12 15:59:26 -08001469 /* Always boot from the primary slot. */
Andrzej Puzdrowskib788c712018-04-12 12:42:49 +02001470 rsp->br_flash_dev_id = boot_data.imgs[0].area->fa_device_id;
Marti Bolivar88f48d92017-05-01 22:30:02 -04001471 rsp->br_image_off = boot_img_slot_off(&boot_data, 0);
Marti Bolivarf804f622017-06-12 15:41:48 -04001472 rsp->br_hdr = boot_img_hdr(&boot_data, slot);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001473
Marti Bolivarc0b47912017-06-13 17:18:09 -04001474 out:
1475 flash_area_close(BOOT_SCRATCH_AREA(&boot_data));
1476 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
1477 flash_area_close(BOOT_IMG_AREA(&boot_data, BOOT_NUM_SLOTS - 1 - slot));
1478 }
1479 return rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001480}
1481
1482int
1483split_go(int loader_slot, int split_slot, void **entry)
1484{
Marti Bolivarc50926f2017-06-14 09:35:40 -04001485 boot_sector_t *sectors;
Christopher Collins034a6202017-01-11 12:19:37 -08001486 uintptr_t entry_val;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001487 int loader_flash_id;
Marti Bolivarc0b47912017-06-13 17:18:09 -04001488 int split_flash_id;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001489 int rc;
1490
Christopher Collins92ea77f2016-12-12 15:59:26 -08001491 sectors = malloc(BOOT_MAX_IMG_SECTORS * 2 * sizeof *sectors);
1492 if (sectors == NULL) {
Marti Bolivarc0b47912017-06-13 17:18:09 -04001493 return SPLIT_GO_ERR;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001494 }
Marti Bolivarc0b47912017-06-13 17:18:09 -04001495 boot_data.imgs[loader_slot].sectors = sectors + 0;
1496 boot_data.imgs[split_slot].sectors = sectors + BOOT_MAX_IMG_SECTORS;
1497
1498 loader_flash_id = flash_area_id_from_image_slot(loader_slot);
1499 rc = flash_area_open(loader_flash_id,
1500 &BOOT_IMG_AREA(&boot_data, split_slot));
1501 assert(rc == 0);
1502 split_flash_id = flash_area_id_from_image_slot(split_slot);
1503 rc = flash_area_open(split_flash_id,
1504 &BOOT_IMG_AREA(&boot_data, split_slot));
1505 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001506
1507 /* Determine the sector layout of the image slots and scratch area. */
1508 rc = boot_read_sectors();
1509 if (rc != 0) {
1510 rc = SPLIT_GO_ERR;
1511 goto done;
1512 }
1513
Fabio Utzig9c25fa72017-12-12 14:57:20 -02001514 rc = boot_read_image_headers(true);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001515 if (rc != 0) {
1516 goto done;
1517 }
1518
Christopher Collins92ea77f2016-12-12 15:59:26 -08001519 /* Don't check the bootable image flag because we could really call a
1520 * bootable or non-bootable image. Just validate that the image check
1521 * passes which is distinct from the normal check.
1522 */
Marti Bolivarf804f622017-06-12 15:41:48 -04001523 rc = split_image_check(boot_img_hdr(&boot_data, split_slot),
Marti Bolivarc0b47912017-06-13 17:18:09 -04001524 BOOT_IMG_AREA(&boot_data, split_slot),
Marti Bolivarf804f622017-06-12 15:41:48 -04001525 boot_img_hdr(&boot_data, loader_slot),
Marti Bolivarc0b47912017-06-13 17:18:09 -04001526 BOOT_IMG_AREA(&boot_data, loader_slot));
Christopher Collins92ea77f2016-12-12 15:59:26 -08001527 if (rc != 0) {
1528 rc = SPLIT_GO_NON_MATCHING;
1529 goto done;
1530 }
1531
Marti Bolivarea088872017-06-12 17:10:49 -04001532 entry_val = boot_img_slot_off(&boot_data, split_slot) +
Marti Bolivarf804f622017-06-12 15:41:48 -04001533 boot_img_hdr(&boot_data, split_slot)->ih_hdr_size;
Christopher Collins034a6202017-01-11 12:19:37 -08001534 *entry = (void *) entry_val;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001535 rc = SPLIT_GO_OK;
1536
1537done:
Marti Bolivarc0b47912017-06-13 17:18:09 -04001538 flash_area_close(BOOT_IMG_AREA(&boot_data, split_slot));
1539 flash_area_close(BOOT_IMG_AREA(&boot_data, loader_slot));
Christopher Collins92ea77f2016-12-12 15:59:26 -08001540 free(sectors);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001541 return rc;
1542}