blob: 66c884318efabb8ba55d56e8047b9e0e5e0fa4a8 [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;
Fabio Utzig39000012018-07-30 12:40:20 -0300407 uint8_t erased_val;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800408
409 off = boot_status_off(fap);
Fabio Utzig4cee4f72017-05-22 10:59:57 -0400410 max_entries = boot_status_entries(fap);
Fabio Utzig39000012018-07-30 12:40:20 -0300411 erased_val = flash_area_erased_val(fap);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300412
Christopher Collins92ea77f2016-12-12 15:59:26 -0800413 found = 0;
Fabio Utziga0e1cce2017-11-23 20:04:01 -0200414 found_idx = 0;
415 invalid = 0;
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300416 for (i = 0; i < max_entries; i++) {
Marti Bolivare10a7392017-06-14 16:20:07 -0400417 rc = flash_area_read(fap, off + i * BOOT_WRITE_SZ(&boot_data),
418 &status, 1);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800419 if (rc != 0) {
420 return BOOT_EFLASH;
421 }
422
Fabio Utzig39000012018-07-30 12:40:20 -0300423 if (status == erased_val) {
Fabio Utziga0e1cce2017-11-23 20:04:01 -0200424 if (found && !found_idx) {
425 found_idx = i;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800426 }
427 } else if (!found) {
428 found = 1;
Fabio Utziga0e1cce2017-11-23 20:04:01 -0200429 } else if (found_idx) {
430 invalid = 1;
431 break;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800432 }
433 }
434
Fabio Utziga0e1cce2017-11-23 20:04:01 -0200435 if (invalid) {
436 /* This means there was an error writing status on the last
437 * swap. Tell user and move on to validation!
438 */
439 BOOT_LOG_ERR("Detected inconsistent status!");
440
441#if !defined(MCUBOOT_VALIDATE_SLOT0)
442 /* With validation of slot0 disabled, there is no way to be sure the
443 * swapped slot0 is OK, so abort!
444 */
445 assert(0);
446#endif
447 }
448
Christopher Collins92ea77f2016-12-12 15:59:26 -0800449 if (found) {
Fabio Utziga0e1cce2017-11-23 20:04:01 -0200450 if (!found_idx) {
451 found_idx = i;
452 }
453 found_idx--;
Fabio Utzig39000012018-07-30 12:40:20 -0300454 bs->idx = (found_idx / BOOT_STATUS_STATE_COUNT) + 1;
455 bs->state = (found_idx % BOOT_STATUS_STATE_COUNT) + 1;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800456 }
457
458 return 0;
459}
460
461/**
462 * Reads the boot status from the flash. The boot status contains
463 * the current state of an interrupted image copy operation. If the boot
464 * status is not present, or it indicates that previous copy finished,
465 * there is no operation in progress.
466 */
467static int
468boot_read_status(struct boot_status *bs)
469{
470 const struct flash_area *fap;
471 int status_loc;
472 int area_id;
473 int rc;
474
475 memset(bs, 0, sizeof *bs);
Fabio Utzig39000012018-07-30 12:40:20 -0300476 bs->idx = BOOT_STATUS_IDX_0;
477 bs->state = BOOT_STATUS_STATE_0;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800478
Fabio Utzig03dc9a02018-06-11 12:24:07 -0700479#ifdef MCUBOOT_OVERWRITE_ONLY
480 /* Overwrite-only doesn't make use of the swap status area. */
481 return 0;
482#endif
483
Christopher Collins92ea77f2016-12-12 15:59:26 -0800484 status_loc = boot_status_source();
485 switch (status_loc) {
486 case BOOT_STATUS_SOURCE_NONE:
487 return 0;
488
489 case BOOT_STATUS_SOURCE_SCRATCH:
490 area_id = FLASH_AREA_IMAGE_SCRATCH;
491 break;
492
493 case BOOT_STATUS_SOURCE_SLOT0:
494 area_id = FLASH_AREA_IMAGE_0;
495 break;
496
497 default:
498 assert(0);
499 return BOOT_EBADARGS;
500 }
501
502 rc = flash_area_open(area_id, &fap);
503 if (rc != 0) {
504 return BOOT_EFLASH;
505 }
506
Fabio Utzig46490722017-09-04 15:34:32 -0300507 rc = boot_read_status_bytes(fap, bs);
508
509 flash_area_close(fap);
Fabio Utzig03dc9a02018-06-11 12:24:07 -0700510
Fabio Utzig46490722017-09-04 15:34:32 -0300511 return rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800512}
513
514/**
515 * Writes the supplied boot status to the flash file system. The boot status
516 * contains the current state of an in-progress image copy operation.
517 *
518 * @param bs The boot status to write.
519 *
520 * @return 0 on success; nonzero on failure.
521 */
522int
523boot_write_status(struct boot_status *bs)
524{
525 const struct flash_area *fap;
526 uint32_t off;
527 int area_id;
528 int rc;
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300529 uint8_t buf[BOOT_MAX_ALIGN];
David Brown9d725462017-01-23 15:50:58 -0700530 uint8_t align;
Fabio Utzig39000012018-07-30 12:40:20 -0300531 uint8_t erased_val;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800532
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300533 /* NOTE: The first sector copied (that is the last sector on slot) contains
534 * the trailer. Since in the last step SLOT 0 is erased, the first
535 * two status writes go to the scratch which will be copied to SLOT 0!
536 */
537
Fabio Utzig2473ac02017-05-02 12:45:02 -0300538 if (bs->use_scratch) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800539 /* Write to scratch. */
540 area_id = FLASH_AREA_IMAGE_SCRATCH;
541 } else {
542 /* Write to slot 0. */
543 area_id = FLASH_AREA_IMAGE_0;
544 }
545
546 rc = flash_area_open(area_id, &fap);
547 if (rc != 0) {
548 rc = BOOT_EFLASH;
549 goto done;
550 }
551
552 off = boot_status_off(fap) +
Marti Bolivare10a7392017-06-14 16:20:07 -0400553 boot_status_internal_off(bs->idx, bs->state,
554 BOOT_WRITE_SZ(&boot_data));
Andrzej Puzdrowskib788c712018-04-12 12:42:49 +0200555 align = flash_area_align(fap);
Fabio Utzig39000012018-07-30 12:40:20 -0300556 erased_val = flash_area_erased_val(fap);
557 memset(buf, erased_val, BOOT_MAX_ALIGN);
David Brown9d725462017-01-23 15:50:58 -0700558 buf[0] = bs->state;
559
560 rc = flash_area_write(fap, off, buf, align);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800561 if (rc != 0) {
562 rc = BOOT_EFLASH;
563 goto done;
564 }
565
566 rc = 0;
567
568done:
569 flash_area_close(fap);
570 return rc;
571}
572
573/*
574 * Validate image hash/signature in a slot.
575 */
576static int
577boot_image_check(struct image_header *hdr, const struct flash_area *fap)
578{
David Browndb1d9d32017-01-06 11:07:54 -0700579 static uint8_t tmpbuf[BOOT_TMPBUF_SZ];
Christopher Collins92ea77f2016-12-12 15:59:26 -0800580
Christopher Collins92ea77f2016-12-12 15:59:26 -0800581 if (bootutil_img_validate(hdr, fap, tmpbuf, BOOT_TMPBUF_SZ,
582 NULL, 0, NULL)) {
583 return BOOT_EBADIMAGE;
584 }
585 return 0;
586}
587
588static int
589split_image_check(struct image_header *app_hdr,
590 const struct flash_area *app_fap,
591 struct image_header *loader_hdr,
592 const struct flash_area *loader_fap)
593{
594 static void *tmpbuf;
595 uint8_t loader_hash[32];
596
597 if (!tmpbuf) {
598 tmpbuf = malloc(BOOT_TMPBUF_SZ);
599 if (!tmpbuf) {
600 return BOOT_ENOMEM;
601 }
602 }
603
604 if (bootutil_img_validate(loader_hdr, loader_fap, tmpbuf, BOOT_TMPBUF_SZ,
605 NULL, 0, loader_hash)) {
606 return BOOT_EBADIMAGE;
607 }
608
609 if (bootutil_img_validate(app_hdr, app_fap, tmpbuf, BOOT_TMPBUF_SZ,
610 loader_hash, 32, NULL)) {
611 return BOOT_EBADIMAGE;
612 }
613
614 return 0;
615}
616
Fabio Utzig39000012018-07-30 12:40:20 -0300617static inline int
618boot_magic_is_erased(uint8_t erased_val, uint32_t magic)
619{
620 uint8_t i;
621 for (i = 0; i < sizeof(magic); i++) {
622 if (erased_val != *(((uint8_t *)&magic) + i)) {
623 return 0;
624 }
625 }
626 return 1;
627}
628
Christopher Collins92ea77f2016-12-12 15:59:26 -0800629static int
David Brownd930ec62016-12-14 07:59:48 -0700630boot_validate_slot(int slot)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800631{
632 const struct flash_area *fap;
Marti Bolivarf804f622017-06-12 15:41:48 -0400633 struct image_header *hdr;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800634 int rc;
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300635
David Brownd930ec62016-12-14 07:59:48 -0700636 rc = flash_area_open(flash_area_id_from_image_slot(slot), &fap);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800637 if (rc != 0) {
638 return BOOT_EFLASH;
639 }
640
Fabio Utzig39000012018-07-30 12:40:20 -0300641 hdr = boot_img_hdr(&boot_data, slot);
642 if (boot_magic_is_erased(flash_area_erased_val(fap), hdr->ih_magic) ||
643 hdr->ih_flags & IMAGE_F_NON_BOOTABLE) {
644 /* No bootable image in slot; continue booting from slot 0. */
645 return -1;
646 }
647
Marti Bolivarf804f622017-06-12 15:41:48 -0400648 if ((hdr->ih_magic != IMAGE_MAGIC || boot_image_check(hdr, fap) != 0)) {
David Brownb38e0442017-02-24 13:57:12 -0700649 if (slot != 0) {
650 flash_area_erase(fap, 0, fap->fa_size);
651 /* Image in slot 1 is invalid. Erase the image and
652 * continue booting from slot 0.
653 */
654 }
Fabio Utzigb6297af2017-10-05 18:26:36 -0300655 BOOT_LOG_ERR("Image in slot %d is not valid!", slot);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800656 return -1;
657 }
658
659 flash_area_close(fap);
660
661 /* Image in slot 1 is valid. */
662 return 0;
663}
664
665/**
666 * Determines which swap operation to perform, if any. If it is determined
667 * that a swap operation is required, the image in the second slot is checked
668 * for validity. If the image in the second slot is invalid, it is erased, and
669 * a swap type of "none" is indicated.
670 *
671 * @return The type of swap to perform (BOOT_SWAP_TYPE...)
672 */
673static int
674boot_validated_swap_type(void)
675{
676 int swap_type;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800677
678 swap_type = boot_swap_type();
Fabio Utzigb5b2f552017-06-30 10:03:47 -0300679 switch (swap_type) {
680 case BOOT_SWAP_TYPE_TEST:
681 case BOOT_SWAP_TYPE_PERM:
682 case BOOT_SWAP_TYPE_REVERT:
683 /* Boot loader wants to switch to slot 1. Ensure image is valid. */
684 if (boot_validate_slot(1) != 0) {
685 swap_type = BOOT_SWAP_TYPE_FAIL;
686 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800687 }
688
689 return swap_type;
690}
691
692/**
693 * Calculates the number of sectors the scratch area can contain. A "last"
694 * source sector is specified because images are copied backwards in flash
695 * (final index to index number 0).
696 *
697 * @param last_sector_idx The index of the last source sector
698 * (inclusive).
699 * @param out_first_sector_idx The index of the first source sector
700 * (inclusive) gets written here.
701 *
702 * @return The number of bytes comprised by the
703 * [first-sector, last-sector] range.
704 */
Fabio Utzig3488eef2017-06-12 10:25:43 -0300705#ifndef MCUBOOT_OVERWRITE_ONLY
Christopher Collins92ea77f2016-12-12 15:59:26 -0800706static uint32_t
707boot_copy_sz(int last_sector_idx, int *out_first_sector_idx)
708{
Marti Bolivard3269fd2017-06-12 16:31:12 -0400709 size_t scratch_sz;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800710 uint32_t new_sz;
711 uint32_t sz;
712 int i;
713
714 sz = 0;
715
Marti Bolivard3269fd2017-06-12 16:31:12 -0400716 scratch_sz = boot_scratch_area_size(&boot_data);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800717 for (i = last_sector_idx; i >= 0; i--) {
Marti Bolivard3269fd2017-06-12 16:31:12 -0400718 new_sz = sz + boot_img_sector_size(&boot_data, 0, i);
719 if (new_sz > scratch_sz) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800720 break;
721 }
722 sz = new_sz;
723 }
724
725 /* i currently refers to a sector that doesn't fit or it is -1 because all
726 * sectors have been processed. In both cases, exclude sector i.
727 */
728 *out_first_sector_idx = i + 1;
729 return sz;
730}
Fabio Utzig3488eef2017-06-12 10:25:43 -0300731#endif /* !MCUBOOT_OVERWRITE_ONLY */
Christopher Collins92ea77f2016-12-12 15:59:26 -0800732
733/**
734 * Erases a region of flash.
735 *
736 * @param flash_area_idx The ID of the flash area containing the region
737 * to erase.
738 * @param off The offset within the flash area to start the
739 * erase.
740 * @param sz The number of bytes to erase.
741 *
742 * @return 0 on success; nonzero on failure.
743 */
744static int
745boot_erase_sector(int flash_area_id, uint32_t off, uint32_t sz)
746{
747 const struct flash_area *fap;
748 int rc;
749
750 rc = flash_area_open(flash_area_id, &fap);
751 if (rc != 0) {
752 rc = BOOT_EFLASH;
753 goto done;
754 }
755
756 rc = flash_area_erase(fap, off, sz);
757 if (rc != 0) {
758 rc = BOOT_EFLASH;
759 goto done;
760 }
761
762 rc = 0;
763
764done:
765 flash_area_close(fap);
766 return rc;
767}
768
769/**
770 * Copies the contents of one flash region to another. You must erase the
771 * destination region prior to calling this function.
772 *
773 * @param flash_area_id_src The ID of the source flash area.
774 * @param flash_area_id_dst The ID of the destination flash area.
775 * @param off_src The offset within the source flash area to
776 * copy from.
777 * @param off_dst The offset within the destination flash area to
778 * copy to.
779 * @param sz The number of bytes to copy.
780 *
781 * @return 0 on success; nonzero on failure.
782 */
783static int
784boot_copy_sector(int flash_area_id_src, int flash_area_id_dst,
785 uint32_t off_src, uint32_t off_dst, uint32_t sz)
786{
787 const struct flash_area *fap_src;
788 const struct flash_area *fap_dst;
789 uint32_t bytes_copied;
790 int chunk_sz;
791 int rc;
792
793 static uint8_t buf[1024];
794
795 fap_src = NULL;
796 fap_dst = NULL;
797
798 rc = flash_area_open(flash_area_id_src, &fap_src);
799 if (rc != 0) {
800 rc = BOOT_EFLASH;
801 goto done;
802 }
803
804 rc = flash_area_open(flash_area_id_dst, &fap_dst);
805 if (rc != 0) {
806 rc = BOOT_EFLASH;
807 goto done;
808 }
809
810 bytes_copied = 0;
811 while (bytes_copied < sz) {
812 if (sz - bytes_copied > sizeof buf) {
813 chunk_sz = sizeof buf;
814 } else {
815 chunk_sz = sz - bytes_copied;
816 }
817
818 rc = flash_area_read(fap_src, off_src + bytes_copied, buf, chunk_sz);
819 if (rc != 0) {
820 rc = BOOT_EFLASH;
821 goto done;
822 }
823
824 rc = flash_area_write(fap_dst, off_dst + bytes_copied, buf, chunk_sz);
825 if (rc != 0) {
826 rc = BOOT_EFLASH;
827 goto done;
828 }
829
830 bytes_copied += chunk_sz;
831 }
832
833 rc = 0;
834
835done:
Fabio Utzige7686262017-06-28 09:26:54 -0300836 if (fap_src) {
837 flash_area_close(fap_src);
838 }
839 if (fap_dst) {
840 flash_area_close(fap_dst);
841 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800842 return rc;
843}
844
David Brown6b1b3b92017-09-19 08:59:10 -0600845#ifndef MCUBOOT_OVERWRITE_ONLY
Fabio Utzig2473ac02017-05-02 12:45:02 -0300846static inline int
Fabio Utzig46490722017-09-04 15:34:32 -0300847boot_status_init_by_id(int flash_area_id, const struct boot_status *bs)
Fabio Utzig2473ac02017-05-02 12:45:02 -0300848{
849 const struct flash_area *fap;
850 struct boot_swap_state swap_state;
851 int rc;
852
853 rc = flash_area_open(flash_area_id, &fap);
854 assert(rc == 0);
855
856 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_1, &swap_state);
857 assert(rc == 0);
858
Fabio Utzigde8a38a2017-05-23 11:15:01 -0400859 if (swap_state.image_ok == BOOT_FLAG_SET) {
Fabio Utzig2473ac02017-05-02 12:45:02 -0300860 rc = boot_write_image_ok(fap);
861 assert(rc == 0);
862 }
863
Fabio Utzig46490722017-09-04 15:34:32 -0300864 rc = boot_write_swap_size(fap, bs->swap_size);
865 assert(rc == 0);
866
Fabio Utzig2473ac02017-05-02 12:45:02 -0300867 rc = boot_write_magic(fap);
868 assert(rc == 0);
869
870 flash_area_close(fap);
871
872 return 0;
873}
David Brown6b1b3b92017-09-19 08:59:10 -0600874#endif
Fabio Utzig2473ac02017-05-02 12:45:02 -0300875
Fabio Utzig358c9352017-07-25 22:10:45 -0300876#ifndef MCUBOOT_OVERWRITE_ONLY
Fabio Utzig2473ac02017-05-02 12:45:02 -0300877static int
878boot_erase_last_sector_by_id(int flash_area_id)
879{
880 uint8_t slot;
881 uint32_t last_sector;
Fabio Utzig2473ac02017-05-02 12:45:02 -0300882 int rc;
883
884 switch (flash_area_id) {
885 case FLASH_AREA_IMAGE_0:
886 slot = 0;
887 break;
888 case FLASH_AREA_IMAGE_1:
889 slot = 1;
890 break;
891 default:
892 return BOOT_EFLASH;
893 }
894
Marti Bolivard3269fd2017-06-12 16:31:12 -0400895 last_sector = boot_img_num_sectors(&boot_data, slot) - 1;
Fabio Utzig2473ac02017-05-02 12:45:02 -0300896 rc = boot_erase_sector(flash_area_id,
Marti Bolivarea088872017-06-12 17:10:49 -0400897 boot_img_sector_off(&boot_data, slot, last_sector),
Marti Bolivard3269fd2017-06-12 16:31:12 -0400898 boot_img_sector_size(&boot_data, slot, last_sector));
Fabio Utzig2473ac02017-05-02 12:45:02 -0300899 assert(rc == 0);
900
901 return rc;
902}
Fabio Utzig358c9352017-07-25 22:10:45 -0300903#endif /* !MCUBOOT_OVERWRITE_ONLY */
Fabio Utzig2473ac02017-05-02 12:45:02 -0300904
Christopher Collins92ea77f2016-12-12 15:59:26 -0800905/**
906 * Swaps the contents of two flash regions within the two image slots.
907 *
908 * @param idx The index of the first sector in the range of
909 * sectors being swapped.
910 * @param sz The number of bytes to swap.
911 * @param bs The current boot status. This struct gets
912 * updated according to the outcome.
913 *
914 * @return 0 on success; nonzero on failure.
915 */
Fabio Utzig3488eef2017-06-12 10:25:43 -0300916#ifndef MCUBOOT_OVERWRITE_ONLY
Christopher Collins4772ac42017-02-27 20:08:01 -0800917static void
Christopher Collins92ea77f2016-12-12 15:59:26 -0800918boot_swap_sectors(int idx, uint32_t sz, struct boot_status *bs)
919{
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300920 const struct flash_area *fap;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800921 uint32_t copy_sz;
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300922 uint32_t trailer_sz;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800923 uint32_t img_off;
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300924 uint32_t scratch_trailer_off;
925 struct boot_swap_state swap_state;
Marti Bolivard3269fd2017-06-12 16:31:12 -0400926 size_t last_sector;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800927 int rc;
928
929 /* Calculate offset from start of image area. */
Marti Bolivarea088872017-06-12 17:10:49 -0400930 img_off = boot_img_sector_off(&boot_data, 0, idx);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800931
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300932 copy_sz = sz;
Marti Bolivare10a7392017-06-14 16:20:07 -0400933 trailer_sz = boot_slots_trailer_sz(BOOT_WRITE_SZ(&boot_data));
Fabio Utzig9678c972017-05-23 11:28:56 -0400934
935 /* sz in this function is always is always sized on a multiple of the
Marti Bolivarea088872017-06-12 17:10:49 -0400936 * sector size. The check against the start offset of the last sector
Fabio Utzig9678c972017-05-23 11:28:56 -0400937 * is to determine if we're swapping the last sector. The last sector
938 * needs special handling because it's where the trailer lives. If we're
939 * copying it, we need to use scratch to write the trailer temporarily.
940 *
941 * NOTE: `use_scratch` is a temporary flag (never written to flash) which
942 * controls if special handling is needed (swapping last sector).
943 */
Marti Bolivard3269fd2017-06-12 16:31:12 -0400944 last_sector = boot_img_num_sectors(&boot_data, 0) - 1;
Marti Bolivarea088872017-06-12 17:10:49 -0400945 if (img_off + sz > boot_img_sector_off(&boot_data, 0, last_sector)) {
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300946 copy_sz -= trailer_sz;
947 }
948
Fabio Utzig39000012018-07-30 12:40:20 -0300949 bs->use_scratch = (bs->idx == BOOT_STATUS_IDX_0 && copy_sz != sz);
Fabio Utzig2473ac02017-05-02 12:45:02 -0300950
Fabio Utzig39000012018-07-30 12:40:20 -0300951 if (bs->state == BOOT_STATUS_STATE_0) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800952 rc = boot_erase_sector(FLASH_AREA_IMAGE_SCRATCH, 0, sz);
Christopher Collins4772ac42017-02-27 20:08:01 -0800953 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800954
955 rc = boot_copy_sector(FLASH_AREA_IMAGE_1, FLASH_AREA_IMAGE_SCRATCH,
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300956 img_off, 0, copy_sz);
Christopher Collins4772ac42017-02-27 20:08:01 -0800957 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800958
Fabio Utzig39000012018-07-30 12:40:20 -0300959 if (bs->idx == BOOT_STATUS_IDX_0) {
Fabio Utzig2473ac02017-05-02 12:45:02 -0300960 if (bs->use_scratch) {
Fabio Utzig46490722017-09-04 15:34:32 -0300961 boot_status_init_by_id(FLASH_AREA_IMAGE_SCRATCH, bs);
Fabio Utzig2473ac02017-05-02 12:45:02 -0300962 } else {
963 /* Prepare the status area... here it is known that the
964 * last sector is not being used by the image data so it's
965 * safe to erase.
966 */
967 rc = boot_erase_last_sector_by_id(FLASH_AREA_IMAGE_0);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300968 assert(rc == 0);
Fabio Utzig2473ac02017-05-02 12:45:02 -0300969
Fabio Utzig46490722017-09-04 15:34:32 -0300970 boot_status_init_by_id(FLASH_AREA_IMAGE_0, bs);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300971 }
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300972 }
973
Fabio Utzig39000012018-07-30 12:40:20 -0300974 bs->state = BOOT_STATUS_STATE_1;
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
Fabio Utzig39000012018-07-30 12:40:20 -0300979 if (bs->state == BOOT_STATUS_STATE_1) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800980 rc = boot_erase_sector(FLASH_AREA_IMAGE_1, img_off, sz);
Christopher Collins4772ac42017-02-27 20:08:01 -0800981 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800982
Christopher Collins92ea77f2016-12-12 15:59:26 -0800983 rc = boot_copy_sector(FLASH_AREA_IMAGE_0, FLASH_AREA_IMAGE_1,
984 img_off, img_off, copy_sz);
Christopher Collins4772ac42017-02-27 20:08:01 -0800985 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800986
Fabio Utzig39000012018-07-30 12:40:20 -0300987 if (bs->idx == BOOT_STATUS_IDX_0 && !bs->use_scratch) {
Fabio Utzig2473ac02017-05-02 12:45:02 -0300988 /* If not all sectors of the slot are being swapped,
989 * guarantee here that only slot0 will have the state.
990 */
991 rc = boot_erase_last_sector_by_id(FLASH_AREA_IMAGE_1);
992 assert(rc == 0);
993 }
994
Fabio Utzig39000012018-07-30 12:40:20 -0300995 bs->state = BOOT_STATUS_STATE_2;
Christopher Collins4772ac42017-02-27 20:08:01 -0800996 rc = boot_write_status(bs);
Fabio Utziga0e1cce2017-11-23 20:04:01 -0200997 BOOT_STATUS_ASSERT(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800998 }
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300999
Fabio Utzig39000012018-07-30 12:40:20 -03001000 if (bs->state == BOOT_STATUS_STATE_2) {
Christopher Collins92ea77f2016-12-12 15:59:26 -08001001 rc = boot_erase_sector(FLASH_AREA_IMAGE_0, img_off, sz);
Christopher Collins4772ac42017-02-27 20:08:01 -08001002 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001003
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001004 /* NOTE: also copy trailer from scratch (has status info) */
Christopher Collins92ea77f2016-12-12 15:59:26 -08001005 rc = boot_copy_sector(FLASH_AREA_IMAGE_SCRATCH, FLASH_AREA_IMAGE_0,
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001006 0, img_off, copy_sz);
Christopher Collins4772ac42017-02-27 20:08:01 -08001007 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001008
Fabio Utzig94d998c2017-05-22 11:02:41 -04001009 if (bs->use_scratch) {
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001010 rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH, &fap);
1011 assert(rc == 0);
1012
1013 scratch_trailer_off = boot_status_off(fap);
1014
1015 flash_area_close(fap);
1016
1017 rc = flash_area_open(FLASH_AREA_IMAGE_0, &fap);
1018 assert(rc == 0);
1019
1020 /* copy current status that is being maintained in scratch */
1021 rc = boot_copy_sector(FLASH_AREA_IMAGE_SCRATCH, FLASH_AREA_IMAGE_0,
Marti Bolivare10a7392017-06-14 16:20:07 -04001022 scratch_trailer_off,
Fabio Utziga0bc9b52017-06-28 09:19:55 -03001023 img_off + copy_sz,
Marti Bolivare10a7392017-06-14 16:20:07 -04001024 BOOT_STATUS_STATE_COUNT * BOOT_WRITE_SZ(&boot_data));
Fabio Utziga0e1cce2017-11-23 20:04:01 -02001025 BOOT_STATUS_ASSERT(rc == 0);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001026
Fabio Utzig2473ac02017-05-02 12:45:02 -03001027 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SCRATCH,
1028 &swap_state);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001029 assert(rc == 0);
1030
Fabio Utzigde8a38a2017-05-23 11:15:01 -04001031 if (swap_state.image_ok == BOOT_FLAG_SET) {
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001032 rc = boot_write_image_ok(fap);
1033 assert(rc == 0);
1034 }
1035
Fabio Utzig46490722017-09-04 15:34:32 -03001036 rc = boot_write_swap_size(fap, bs->swap_size);
1037 assert(rc == 0);
1038
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001039 rc = boot_write_magic(fap);
1040 assert(rc == 0);
1041
1042 flash_area_close(fap);
1043 }
1044
Christopher Collins92ea77f2016-12-12 15:59:26 -08001045 bs->idx++;
Fabio Utzig39000012018-07-30 12:40:20 -03001046 bs->state = BOOT_STATUS_STATE_0;
Fabio Utzig2473ac02017-05-02 12:45:02 -03001047 bs->use_scratch = 0;
Christopher Collins4772ac42017-02-27 20:08:01 -08001048 rc = boot_write_status(bs);
Fabio Utziga0e1cce2017-11-23 20:04:01 -02001049 BOOT_STATUS_ASSERT(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001050 }
Christopher Collins92ea77f2016-12-12 15:59:26 -08001051}
Fabio Utzig3488eef2017-06-12 10:25:43 -03001052#endif /* !MCUBOOT_OVERWRITE_ONLY */
Christopher Collins92ea77f2016-12-12 15:59:26 -08001053
1054/**
1055 * Swaps the two images in flash. If a prior copy operation was interrupted
1056 * by a system reset, this function completes that operation.
1057 *
1058 * @param bs The current boot status. This function reads
1059 * this struct to determine if it is resuming
1060 * an interrupted swap operation. This
1061 * function writes the updated status to this
1062 * function on return.
1063 *
1064 * @return 0 on success; nonzero on failure.
1065 */
Fabio Utzig3488eef2017-06-12 10:25:43 -03001066#ifdef MCUBOOT_OVERWRITE_ONLY
David Brown17609d82017-05-05 09:41:34 -06001067static int
1068boot_copy_image(struct boot_status *bs)
1069{
Marti Bolivard3269fd2017-06-12 16:31:12 -04001070 size_t sect_count;
1071 size_t sect;
David Brown17609d82017-05-05 09:41:34 -06001072 int rc;
Fabio Utzig13d9e352017-10-05 20:32:31 -03001073 size_t size;
Marti Bolivard3269fd2017-06-12 16:31:12 -04001074 size_t this_size;
Fabio Utzig13d9e352017-10-05 20:32:31 -03001075 size_t last_sector;
1076
Fabio Utzigaaf767c2017-12-05 10:22:46 -02001077 (void)bs;
1078
Fabio Utzig13d9e352017-10-05 20:32:31 -03001079#if defined(MCUBOOT_OVERWRITE_ONLY_FAST)
1080 uint32_t src_size = 0;
1081 rc = boot_read_image_size(1, boot_img_hdr(&boot_data, 1), &src_size);
1082 assert(rc == 0);
1083#endif
David Brown17609d82017-05-05 09:41:34 -06001084
1085 BOOT_LOG_INF("Image upgrade slot1 -> slot0");
1086 BOOT_LOG_INF("Erasing slot0");
1087
Marti Bolivard3269fd2017-06-12 16:31:12 -04001088 sect_count = boot_img_num_sectors(&boot_data, 0);
Fabio Utzig13d9e352017-10-05 20:32:31 -03001089 for (sect = 0, size = 0; sect < sect_count; sect++) {
Marti Bolivard3269fd2017-06-12 16:31:12 -04001090 this_size = boot_img_sector_size(&boot_data, 0, sect);
David Brown17609d82017-05-05 09:41:34 -06001091 rc = boot_erase_sector(FLASH_AREA_IMAGE_0,
1092 size,
1093 this_size);
1094 assert(rc == 0);
1095
1096 size += this_size;
Fabio Utzig13d9e352017-10-05 20:32:31 -03001097
1098#if defined(MCUBOOT_OVERWRITE_ONLY_FAST)
1099 if (size >= src_size) {
1100 break;
1101 }
1102#endif
David Brown17609d82017-05-05 09:41:34 -06001103 }
1104
Fabio Utzig6a537ee2017-09-13 17:31:44 -03001105 BOOT_LOG_INF("Copying slot 1 to slot 0: 0x%lx bytes", size);
David Brown17609d82017-05-05 09:41:34 -06001106 rc = boot_copy_sector(FLASH_AREA_IMAGE_1, FLASH_AREA_IMAGE_0,
1107 0, 0, size);
1108
Fabio Utzig13d9e352017-10-05 20:32:31 -03001109 /*
1110 * Erases header and trailer. The trailer is erased because when a new
1111 * image is written without a trailer as is the case when using newt, the
1112 * trailer that was left might trigger a new upgrade.
1113 */
David Brown17609d82017-05-05 09:41:34 -06001114 rc = boot_erase_sector(FLASH_AREA_IMAGE_1,
Fabio Utzig13d9e352017-10-05 20:32:31 -03001115 boot_img_sector_off(&boot_data, 1, 0),
1116 boot_img_sector_size(&boot_data, 1, 0));
David Brown17609d82017-05-05 09:41:34 -06001117 assert(rc == 0);
Fabio Utzig13d9e352017-10-05 20:32:31 -03001118 last_sector = boot_img_num_sectors(&boot_data, 1) - 1;
1119 rc = boot_erase_sector(FLASH_AREA_IMAGE_1,
1120 boot_img_sector_off(&boot_data, 1, last_sector),
1121 boot_img_sector_size(&boot_data, 1, last_sector));
1122 assert(rc == 0);
1123
1124 /* TODO: Perhaps verify slot 0's signature again? */
David Brown17609d82017-05-05 09:41:34 -06001125
1126 return 0;
1127}
1128#else
Christopher Collins92ea77f2016-12-12 15:59:26 -08001129static int
1130boot_copy_image(struct boot_status *bs)
1131{
1132 uint32_t sz;
1133 int first_sector_idx;
1134 int last_sector_idx;
Fabio Utzigcd5774b2017-11-29 10:18:26 -02001135 uint32_t swap_idx;
Fabio Utzig2473ac02017-05-02 12:45:02 -03001136 struct image_header *hdr;
1137 uint32_t size;
1138 uint32_t copy_size;
Fabio Utzig2473ac02017-05-02 12:45:02 -03001139 int rc;
1140
1141 /* FIXME: just do this if asked by user? */
1142
1143 size = copy_size = 0;
1144
Fabio Utzig39000012018-07-30 12:40:20 -03001145 if (bs->idx == BOOT_STATUS_IDX_0 && bs->state == BOOT_STATUS_STATE_0) {
Fabio Utzig46490722017-09-04 15:34:32 -03001146 /*
1147 * No swap ever happened, so need to find the largest image which
1148 * will be used to determine the amount of sectors to swap.
1149 */
1150 hdr = boot_img_hdr(&boot_data, 0);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001151 if (hdr->ih_magic == IMAGE_MAGIC) {
Fabio Utzig46490722017-09-04 15:34:32 -03001152 rc = boot_read_image_size(0, hdr, &copy_size);
David Brownf5b33d82017-09-01 10:58:27 -06001153 assert(rc == 0);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001154 }
Fabio Utzig2473ac02017-05-02 12:45:02 -03001155
Fabio Utzig46490722017-09-04 15:34:32 -03001156 hdr = boot_img_hdr(&boot_data, 1);
1157 if (hdr->ih_magic == IMAGE_MAGIC) {
1158 rc = boot_read_image_size(1, hdr, &size);
1159 assert(rc == 0);
1160 }
1161
1162 if (size > copy_size) {
1163 copy_size = size;
1164 }
1165
1166 bs->swap_size = copy_size;
1167 } else {
1168 /*
1169 * If a swap was under way, the swap_size should already be present
1170 * in the trailer...
1171 */
1172 rc = boot_read_swap_size(&bs->swap_size);
1173 assert(rc == 0);
1174
1175 copy_size = bs->swap_size;
Fabio Utzig2473ac02017-05-02 12:45:02 -03001176 }
1177
1178 size = 0;
1179 last_sector_idx = 0;
1180 while (1) {
Marti Bolivard3269fd2017-06-12 16:31:12 -04001181 size += boot_img_sector_size(&boot_data, 0, last_sector_idx);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001182 if (size >= copy_size) {
1183 break;
1184 }
1185 last_sector_idx++;
1186 }
Christopher Collins92ea77f2016-12-12 15:59:26 -08001187
1188 swap_idx = 0;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001189 while (last_sector_idx >= 0) {
1190 sz = boot_copy_sz(last_sector_idx, &first_sector_idx);
Fabio Utzig39000012018-07-30 12:40:20 -03001191 if (swap_idx >= (bs->idx - BOOT_STATUS_IDX_0)) {
Christopher Collins92ea77f2016-12-12 15:59:26 -08001192 boot_swap_sectors(first_sector_idx, sz, bs);
1193 }
1194
1195 last_sector_idx = first_sector_idx - 1;
1196 swap_idx++;
1197 }
1198
Fabio Utziga0e1cce2017-11-23 20:04:01 -02001199#ifdef MCUBOOT_VALIDATE_SLOT0
1200 if (boot_status_fails > 0) {
1201 BOOT_LOG_WRN("%d status write fails performing the swap", boot_status_fails);
1202 }
1203#endif
1204
Christopher Collins92ea77f2016-12-12 15:59:26 -08001205 return 0;
1206}
David Brown17609d82017-05-05 09:41:34 -06001207#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -08001208
1209/**
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03001210 * Marks the image in slot 0 as fully copied.
Christopher Collins92ea77f2016-12-12 15:59:26 -08001211 */
Fabio Utzig8d0e5882017-09-13 17:32:44 -03001212#ifndef MCUBOOT_OVERWRITE_ONLY
Christopher Collins92ea77f2016-12-12 15:59:26 -08001213static int
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03001214boot_set_copy_done(void)
Christopher Collins92ea77f2016-12-12 15:59:26 -08001215{
1216 const struct flash_area *fap;
1217 int rc;
1218
1219 rc = flash_area_open(FLASH_AREA_IMAGE_0, &fap);
1220 if (rc != 0) {
1221 return BOOT_EFLASH;
1222 }
1223
1224 rc = boot_write_copy_done(fap);
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03001225 flash_area_close(fap);
1226 return rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001227}
Fabio Utzig8d0e5882017-09-13 17:32:44 -03001228#endif /* !MCUBOOT_OVERWRITE_ONLY */
Christopher Collins92ea77f2016-12-12 15:59:26 -08001229
1230/**
1231 * Marks a reverted image in slot 0 as confirmed. This is necessary to ensure
1232 * the status bytes from the image revert operation don't get processed on a
1233 * subsequent boot.
Fabio Utzig1e56fcc2017-07-17 15:39:14 -03001234 *
1235 * NOTE: image_ok is tested before writing because if there's a valid permanent
1236 * image installed on slot0 and the new image to be upgrade to has a bad sig,
1237 * image_ok would be overwritten.
Christopher Collins92ea77f2016-12-12 15:59:26 -08001238 */
Fabio Utzig8d0e5882017-09-13 17:32:44 -03001239#ifndef MCUBOOT_OVERWRITE_ONLY
Christopher Collins92ea77f2016-12-12 15:59:26 -08001240static int
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03001241boot_set_image_ok(void)
Christopher Collins92ea77f2016-12-12 15:59:26 -08001242{
1243 const struct flash_area *fap;
Fabio Utzig1e56fcc2017-07-17 15:39:14 -03001244 struct boot_swap_state state;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001245 int rc;
1246
1247 rc = flash_area_open(FLASH_AREA_IMAGE_0, &fap);
1248 if (rc != 0) {
1249 return BOOT_EFLASH;
1250 }
1251
Fabio Utzig1e56fcc2017-07-17 15:39:14 -03001252 rc = boot_read_swap_state(fap, &state);
1253 if (rc != 0) {
1254 rc = BOOT_EFLASH;
1255 goto out;
1256 }
1257
1258 if (state.image_ok == BOOT_FLAG_UNSET) {
1259 rc = boot_write_image_ok(fap);
1260 }
1261
1262out:
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03001263 flash_area_close(fap);
1264 return rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001265}
Fabio Utzig8d0e5882017-09-13 17:32:44 -03001266#endif /* !MCUBOOT_OVERWRITE_ONLY */
Christopher Collins92ea77f2016-12-12 15:59:26 -08001267
1268/**
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001269 * Performs an image swap if one is required.
1270 *
1271 * @param out_swap_type On success, the type of swap performed gets
1272 * written here.
1273 *
1274 * @return 0 on success; nonzero on failure.
1275 */
1276static int
1277boot_swap_if_needed(int *out_swap_type)
1278{
1279 struct boot_status bs;
1280 int swap_type;
1281 int rc;
1282
1283 /* Determine if we rebooted in the middle of an image swap
1284 * operation.
1285 */
1286 rc = boot_read_status(&bs);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001287 assert(rc == 0);
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001288 if (rc != 0) {
1289 return rc;
1290 }
1291
1292 /* If a partial swap was detected, complete it. */
Fabio Utzig39000012018-07-30 12:40:20 -03001293 if (bs.idx != BOOT_STATUS_IDX_0 || bs.state != BOOT_STATUS_STATE_0) {
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001294 rc = boot_copy_image(&bs);
1295 assert(rc == 0);
1296
Fabio Utzigb5b2f552017-06-30 10:03:47 -03001297 /* NOTE: here we have finished a swap resume. The initial request
1298 * was either a TEST or PERM swap, which now after the completed
1299 * swap will be determined to be respectively REVERT (was TEST)
1300 * or NONE (was PERM).
1301 */
1302
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001303 /* Extrapolate the type of the partial swap. We need this
1304 * information to know how to mark the swap complete in flash.
1305 */
1306 swap_type = boot_previous_swap_type();
1307 } else {
1308 swap_type = boot_validated_swap_type();
1309 switch (swap_type) {
1310 case BOOT_SWAP_TYPE_TEST:
Christopher Collinsfd7eb5c2016-12-21 13:46:08 -08001311 case BOOT_SWAP_TYPE_PERM:
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001312 case BOOT_SWAP_TYPE_REVERT:
1313 rc = boot_copy_image(&bs);
1314 assert(rc == 0);
1315 break;
1316 }
1317 }
1318
1319 *out_swap_type = swap_type;
1320 return 0;
1321}
1322
1323/**
Christopher Collins92ea77f2016-12-12 15:59:26 -08001324 * Prepares the booting process. This function moves images around in flash as
1325 * appropriate, and tells you what address to boot from.
1326 *
1327 * @param rsp On success, indicates how booting should occur.
1328 *
1329 * @return 0 on success; nonzero on failure.
1330 */
1331int
1332boot_go(struct boot_rsp *rsp)
1333{
Christopher Collins92ea77f2016-12-12 15:59:26 -08001334 int swap_type;
Marti Bolivar84898652017-06-13 17:20:22 -04001335 size_t slot;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001336 int rc;
Marti Bolivarc0b47912017-06-13 17:18:09 -04001337 int fa_id;
David Brown52eee562017-07-05 11:25:09 -06001338 bool reload_headers = false;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001339
1340 /* The array of slot sectors are defined here (as opposed to file scope) so
1341 * that they don't get allocated for non-boot-loader apps. This is
1342 * necessary because the gcc option "-fdata-sections" doesn't seem to have
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001343 * any effect in older gcc versions (e.g., 4.8.4).
Christopher Collins92ea77f2016-12-12 15:59:26 -08001344 */
Marti Bolivarc50926f2017-06-14 09:35:40 -04001345 static boot_sector_t slot0_sectors[BOOT_MAX_IMG_SECTORS];
1346 static boot_sector_t slot1_sectors[BOOT_MAX_IMG_SECTORS];
Christopher Collins92ea77f2016-12-12 15:59:26 -08001347 boot_data.imgs[0].sectors = slot0_sectors;
1348 boot_data.imgs[1].sectors = slot1_sectors;
1349
Marti Bolivarc0b47912017-06-13 17:18:09 -04001350 /* Open boot_data image areas for the duration of this call. */
1351 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
1352 fa_id = flash_area_id_from_image_slot(slot);
1353 rc = flash_area_open(fa_id, &BOOT_IMG_AREA(&boot_data, slot));
1354 assert(rc == 0);
1355 }
1356 rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH,
1357 &BOOT_SCRATCH_AREA(&boot_data));
1358 assert(rc == 0);
1359
Christopher Collins92ea77f2016-12-12 15:59:26 -08001360 /* Determine the sector layout of the image slots and scratch area. */
1361 rc = boot_read_sectors();
1362 if (rc != 0) {
Fabio Utziga1fae672018-03-30 10:52:38 -03001363 BOOT_LOG_WRN("Failed reading sectors; BOOT_MAX_IMG_SECTORS=%d - too small?",
1364 BOOT_MAX_IMG_SECTORS);
Marti Bolivarc0b47912017-06-13 17:18:09 -04001365 goto out;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001366 }
1367
1368 /* Attempt to read an image header from each slot. */
Fabio Utzig9c25fa72017-12-12 14:57:20 -02001369 rc = boot_read_image_headers(false);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001370 if (rc != 0) {
Marti Bolivarc0b47912017-06-13 17:18:09 -04001371 goto out;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001372 }
1373
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001374 /* If the image slots aren't compatible, no swap is possible. Just boot
1375 * into slot 0.
1376 */
1377 if (boot_slots_compatible()) {
1378 rc = boot_swap_if_needed(&swap_type);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001379 assert(rc == 0);
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001380 if (rc != 0) {
Marti Bolivarc0b47912017-06-13 17:18:09 -04001381 goto out;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001382 }
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03001383
1384 /*
1385 * The following states need image_ok be explicitly set after the
1386 * swap was finished to avoid a new revert.
1387 */
1388 if (swap_type == BOOT_SWAP_TYPE_REVERT || swap_type == BOOT_SWAP_TYPE_FAIL) {
Fabio Utzig8d0e5882017-09-13 17:32:44 -03001389#ifndef MCUBOOT_OVERWRITE_ONLY
Fabio Utzig695d5642017-07-20 09:47:16 -03001390 rc = boot_set_image_ok();
1391 if (rc != 0) {
1392 swap_type = BOOT_SWAP_TYPE_PANIC;
1393 }
Fabio Utzig8d0e5882017-09-13 17:32:44 -03001394#endif /* !MCUBOOT_OVERWRITE_ONLY */
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03001395 }
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001396 } else {
1397 swap_type = BOOT_SWAP_TYPE_NONE;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001398 }
1399
1400 switch (swap_type) {
1401 case BOOT_SWAP_TYPE_NONE:
1402 slot = 0;
1403 break;
1404
Fabio Utzig695d5642017-07-20 09:47:16 -03001405 case BOOT_SWAP_TYPE_TEST: /* fallthrough */
1406 case BOOT_SWAP_TYPE_PERM: /* fallthrough */
Christopher Collins92ea77f2016-12-12 15:59:26 -08001407 case BOOT_SWAP_TYPE_REVERT:
1408 slot = 1;
David Brown52eee562017-07-05 11:25:09 -06001409 reload_headers = true;
Fabio Utzig8d0e5882017-09-13 17:32:44 -03001410#ifndef MCUBOOT_OVERWRITE_ONLY
Fabio Utzig695d5642017-07-20 09:47:16 -03001411 rc = boot_set_copy_done();
1412 if (rc != 0) {
1413 swap_type = BOOT_SWAP_TYPE_PANIC;
1414 }
Fabio Utzig8d0e5882017-09-13 17:32:44 -03001415#endif /* !MCUBOOT_OVERWRITE_ONLY */
Christopher Collins92ea77f2016-12-12 15:59:26 -08001416 break;
1417
1418 case BOOT_SWAP_TYPE_FAIL:
1419 /* The image in slot 1 was invalid and is now erased. Ensure we don't
1420 * try to boot into it again on the next reboot. Do this by pretending
1421 * we just reverted back to slot 0.
1422 */
1423 slot = 0;
David Brown52eee562017-07-05 11:25:09 -06001424 reload_headers = true;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001425 break;
1426
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03001427 default:
Fabio Utzig695d5642017-07-20 09:47:16 -03001428 swap_type = BOOT_SWAP_TYPE_PANIC;
1429 }
1430
1431 if (swap_type == BOOT_SWAP_TYPE_PANIC) {
1432 BOOT_LOG_ERR("panic!");
Fabio Utzigb5b2f552017-06-30 10:03:47 -03001433 assert(0);
Fabio Utzig695d5642017-07-20 09:47:16 -03001434
1435 /* Loop forever... */
1436 while (1) {}
Christopher Collins92ea77f2016-12-12 15:59:26 -08001437 }
1438
David Brown52eee562017-07-05 11:25:09 -06001439 if (reload_headers) {
Fabio Utzig9c25fa72017-12-12 14:57:20 -02001440 rc = boot_read_image_headers(false);
Fabio Utzigc6a7b0c2017-09-13 19:01:15 -03001441 if (rc != 0) {
1442 goto out;
1443 }
1444 /* Since headers were reloaded, it can be assumed we just performed a
1445 * swap or overwrite. Now the header info that should be used to
1446 * provide the data for the bootstrap, which previously was at Slot 1,
1447 * was updated to Slot 0.
1448 */
1449 slot = 0;
David Brown52eee562017-07-05 11:25:09 -06001450 }
1451
Marti Bolivarc1f939d2017-11-14 20:04:51 -05001452#ifdef MCUBOOT_VALIDATE_SLOT0
David Brown554c52e2017-06-30 16:01:07 -06001453 rc = boot_validate_slot(0);
Fabio Utzig57c40f72017-12-12 21:48:30 -02001454 ASSERT(rc == 0);
David Brown554c52e2017-06-30 16:01:07 -06001455 if (rc != 0) {
1456 rc = BOOT_EBADIMAGE;
1457 goto out;
1458 }
Fabio Utzig1e56fcc2017-07-17 15:39:14 -03001459#else
Marti Bolivarc1f939d2017-11-14 20:04:51 -05001460 /* Even if we're not re-validating slot 0, we could be booting
1461 * onto an empty flash chip. At least do a basic sanity check that
1462 * the magic number on the image is OK.
1463 */
1464 if (boot_data.imgs[0].hdr.ih_magic != IMAGE_MAGIC) {
Fabio Utzig67716012018-02-26 10:36:15 -03001465 BOOT_LOG_ERR("bad image magic 0x%lx", (unsigned long)boot_data.imgs[0].hdr.ih_magic);
Marti Bolivarc1f939d2017-11-14 20:04:51 -05001466 rc = BOOT_EBADIMAGE;
1467 goto out;
1468 }
David Brown554c52e2017-06-30 16:01:07 -06001469#endif
1470
Christopher Collins92ea77f2016-12-12 15:59:26 -08001471 /* Always boot from the primary slot. */
Andrzej Puzdrowskib788c712018-04-12 12:42:49 +02001472 rsp->br_flash_dev_id = boot_data.imgs[0].area->fa_device_id;
Marti Bolivar88f48d92017-05-01 22:30:02 -04001473 rsp->br_image_off = boot_img_slot_off(&boot_data, 0);
Marti Bolivarf804f622017-06-12 15:41:48 -04001474 rsp->br_hdr = boot_img_hdr(&boot_data, slot);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001475
Marti Bolivarc0b47912017-06-13 17:18:09 -04001476 out:
1477 flash_area_close(BOOT_SCRATCH_AREA(&boot_data));
1478 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
1479 flash_area_close(BOOT_IMG_AREA(&boot_data, BOOT_NUM_SLOTS - 1 - slot));
1480 }
1481 return rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001482}
1483
1484int
1485split_go(int loader_slot, int split_slot, void **entry)
1486{
Marti Bolivarc50926f2017-06-14 09:35:40 -04001487 boot_sector_t *sectors;
Christopher Collins034a6202017-01-11 12:19:37 -08001488 uintptr_t entry_val;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001489 int loader_flash_id;
Marti Bolivarc0b47912017-06-13 17:18:09 -04001490 int split_flash_id;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001491 int rc;
1492
Christopher Collins92ea77f2016-12-12 15:59:26 -08001493 sectors = malloc(BOOT_MAX_IMG_SECTORS * 2 * sizeof *sectors);
1494 if (sectors == NULL) {
Marti Bolivarc0b47912017-06-13 17:18:09 -04001495 return SPLIT_GO_ERR;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001496 }
Marti Bolivarc0b47912017-06-13 17:18:09 -04001497 boot_data.imgs[loader_slot].sectors = sectors + 0;
1498 boot_data.imgs[split_slot].sectors = sectors + BOOT_MAX_IMG_SECTORS;
1499
1500 loader_flash_id = flash_area_id_from_image_slot(loader_slot);
1501 rc = flash_area_open(loader_flash_id,
1502 &BOOT_IMG_AREA(&boot_data, split_slot));
1503 assert(rc == 0);
1504 split_flash_id = flash_area_id_from_image_slot(split_slot);
1505 rc = flash_area_open(split_flash_id,
1506 &BOOT_IMG_AREA(&boot_data, split_slot));
1507 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001508
1509 /* Determine the sector layout of the image slots and scratch area. */
1510 rc = boot_read_sectors();
1511 if (rc != 0) {
1512 rc = SPLIT_GO_ERR;
1513 goto done;
1514 }
1515
Fabio Utzig9c25fa72017-12-12 14:57:20 -02001516 rc = boot_read_image_headers(true);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001517 if (rc != 0) {
1518 goto done;
1519 }
1520
Christopher Collins92ea77f2016-12-12 15:59:26 -08001521 /* Don't check the bootable image flag because we could really call a
1522 * bootable or non-bootable image. Just validate that the image check
1523 * passes which is distinct from the normal check.
1524 */
Marti Bolivarf804f622017-06-12 15:41:48 -04001525 rc = split_image_check(boot_img_hdr(&boot_data, split_slot),
Marti Bolivarc0b47912017-06-13 17:18:09 -04001526 BOOT_IMG_AREA(&boot_data, split_slot),
Marti Bolivarf804f622017-06-12 15:41:48 -04001527 boot_img_hdr(&boot_data, loader_slot),
Marti Bolivarc0b47912017-06-13 17:18:09 -04001528 BOOT_IMG_AREA(&boot_data, loader_slot));
Christopher Collins92ea77f2016-12-12 15:59:26 -08001529 if (rc != 0) {
1530 rc = SPLIT_GO_NON_MATCHING;
1531 goto done;
1532 }
1533
Marti Bolivarea088872017-06-12 17:10:49 -04001534 entry_val = boot_img_slot_off(&boot_data, split_slot) +
Marti Bolivarf804f622017-06-12 15:41:48 -04001535 boot_img_hdr(&boot_data, split_slot)->ih_hdr_size;
Christopher Collins034a6202017-01-11 12:19:37 -08001536 *entry = (void *) entry_val;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001537 rc = SPLIT_GO_OK;
1538
1539done:
Marti Bolivarc0b47912017-06-13 17:18:09 -04001540 flash_area_close(BOOT_IMG_AREA(&boot_data, split_slot));
1541 flash_area_close(BOOT_IMG_AREA(&boot_data, loader_slot));
Christopher Collins92ea77f2016-12-12 15:59:26 -08001542 free(sectors);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001543 return rc;
1544}