blob: a01492fa3c5a647a0a77c74b6fcfa256089ca4f0 [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
David Vinczee2453472019-06-17 12:31:59 +020020/*
21 * Modifications are Copyright (c) 2019 Arm Limited.
22 */
23
Christopher Collins92ea77f2016-12-12 15:59:26 -080024/**
25 * This file provides an interface to the boot loader. Functions defined in
26 * this file should only be called while the boot loader is running.
27 */
28
29#include <assert.h>
30#include <stddef.h>
David Brown52eee562017-07-05 11:25:09 -060031#include <stdbool.h>
Christopher Collins92ea77f2016-12-12 15:59:26 -080032#include <inttypes.h>
33#include <stdlib.h>
34#include <string.h>
Christopher Collins92ea77f2016-12-12 15:59:26 -080035#include <os/os_malloc.h>
36#include "bootutil/bootutil.h"
37#include "bootutil/image.h"
38#include "bootutil_priv.h"
Marti Bolivarfd20c762017-02-07 16:52:50 -050039#include "bootutil/bootutil_log.h"
40
Fabio Utzigba829042018-09-18 08:29:34 -030041#ifdef MCUBOOT_ENC_IMAGES
42#include "bootutil/enc_key.h"
43#endif
44
Fabio Utzigba1fbe62017-07-21 14:01:20 -030045#include "mcuboot_config/mcuboot_config.h"
Fabio Utzigeed80b62017-06-10 08:03:05 -030046
Emanuele Di Santo9f1933d2018-11-20 10:59:59 +010047MCUBOOT_LOG_MODULE_DECLARE(mcuboot);
48
Marti Bolivar9b1f8bb2017-06-12 15:24:13 -040049static struct boot_loader_state boot_data;
Christopher Collins92ea77f2016-12-12 15:59:26 -080050
Fabio Utzigabec0732019-07-31 08:40:22 -030051#if (BOOT_IMAGE_NUMBER > 1)
52#define IMAGES_ITER(x) for ((x) = 0; (x) < BOOT_IMAGE_NUMBER; ++(x))
53#else
54#define IMAGES_ITER(x)
55#endif
56
David Vincze2d736ad2019-02-18 11:50:22 +010057#if defined(MCUBOOT_VALIDATE_PRIMARY_SLOT) && !defined(MCUBOOT_OVERWRITE_ONLY)
Fabio Utziga0e1cce2017-11-23 20:04:01 -020058static int boot_status_fails = 0;
59#define BOOT_STATUS_ASSERT(x) \
60 do { \
Johann Fischered8461b2018-02-15 16:50:31 +010061 if (!(x)) { \
Fabio Utziga0e1cce2017-11-23 20:04:01 -020062 boot_status_fails++; \
63 } \
64 } while (0)
65#else
Fabio Utzig57c40f72017-12-12 21:48:30 -020066#define BOOT_STATUS_ASSERT(x) ASSERT(x)
Fabio Utziga0e1cce2017-11-23 20:04:01 -020067#endif
68
Christopher Collins92ea77f2016-12-12 15:59:26 -080069struct boot_status_table {
David Vincze2d736ad2019-02-18 11:50:22 +010070 uint8_t bst_magic_primary_slot;
Christopher Collins92ea77f2016-12-12 15:59:26 -080071 uint8_t bst_magic_scratch;
David Vincze2d736ad2019-02-18 11:50:22 +010072 uint8_t bst_copy_done_primary_slot;
Christopher Collins92ea77f2016-12-12 15:59:26 -080073 uint8_t bst_status_source;
74};
75
76/**
77 * This set of tables maps swap state contents to boot status location.
78 * When searching for a match, these tables must be iterated in order.
79 */
80static const struct boot_status_table boot_status_tables[] = {
81 {
David Vincze2d736ad2019-02-18 11:50:22 +010082 /* | primary slot | scratch |
83 * ----------+--------------+--------------|
84 * magic | Good | Any |
85 * copy-done | Set | N/A |
86 * ----------+--------------+--------------'
87 * source: none |
88 * ----------------------------------------'
Christopher Collins92ea77f2016-12-12 15:59:26 -080089 */
David Vincze2d736ad2019-02-18 11:50:22 +010090 .bst_magic_primary_slot = BOOT_MAGIC_GOOD,
Christopher Collinsa1c12042019-05-23 14:00:28 -070091 .bst_magic_scratch = BOOT_MAGIC_NOTGOOD,
David Vincze2d736ad2019-02-18 11:50:22 +010092 .bst_copy_done_primary_slot = BOOT_FLAG_SET,
93 .bst_status_source = BOOT_STATUS_SOURCE_NONE,
Christopher Collins92ea77f2016-12-12 15:59:26 -080094 },
95
96 {
David Vincze2d736ad2019-02-18 11:50:22 +010097 /* | primary slot | scratch |
98 * ----------+--------------+--------------|
99 * magic | Good | Any |
100 * copy-done | Unset | N/A |
101 * ----------+--------------+--------------'
102 * source: primary slot |
103 * ----------------------------------------'
Christopher Collins92ea77f2016-12-12 15:59:26 -0800104 */
David Vincze2d736ad2019-02-18 11:50:22 +0100105 .bst_magic_primary_slot = BOOT_MAGIC_GOOD,
Christopher Collinsa1c12042019-05-23 14:00:28 -0700106 .bst_magic_scratch = BOOT_MAGIC_NOTGOOD,
David Vincze2d736ad2019-02-18 11:50:22 +0100107 .bst_copy_done_primary_slot = BOOT_FLAG_UNSET,
108 .bst_status_source = BOOT_STATUS_SOURCE_PRIMARY_SLOT,
Christopher Collins92ea77f2016-12-12 15:59:26 -0800109 },
110
111 {
David Vincze2d736ad2019-02-18 11:50:22 +0100112 /* | primary slot | scratch |
113 * ----------+--------------+--------------|
114 * magic | Any | Good |
115 * copy-done | Any | N/A |
116 * ----------+--------------+--------------'
117 * source: scratch |
118 * ----------------------------------------'
Christopher Collins92ea77f2016-12-12 15:59:26 -0800119 */
David Vincze2d736ad2019-02-18 11:50:22 +0100120 .bst_magic_primary_slot = BOOT_MAGIC_ANY,
121 .bst_magic_scratch = BOOT_MAGIC_GOOD,
122 .bst_copy_done_primary_slot = BOOT_FLAG_ANY,
123 .bst_status_source = BOOT_STATUS_SOURCE_SCRATCH,
Christopher Collins92ea77f2016-12-12 15:59:26 -0800124 },
Christopher Collins92ea77f2016-12-12 15:59:26 -0800125 {
David Vincze2d736ad2019-02-18 11:50:22 +0100126 /* | primary slot | scratch |
127 * ----------+--------------+--------------|
128 * magic | Unset | Any |
129 * copy-done | Unset | N/A |
130 * ----------+--------------+--------------|
131 * source: varies |
132 * ----------------------------------------+--------------------------+
Christopher Collins92ea77f2016-12-12 15:59:26 -0800133 * This represents one of two cases: |
134 * o No swaps ever (no status to read, so no harm in checking). |
David Vincze2d736ad2019-02-18 11:50:22 +0100135 * o Mid-revert; status in primary slot. |
Christopher Collins92ea77f2016-12-12 15:59:26 -0800136 * -------------------------------------------------------------------'
137 */
David Vincze2d736ad2019-02-18 11:50:22 +0100138 .bst_magic_primary_slot = BOOT_MAGIC_UNSET,
139 .bst_magic_scratch = BOOT_MAGIC_ANY,
140 .bst_copy_done_primary_slot = BOOT_FLAG_UNSET,
141 .bst_status_source = BOOT_STATUS_SOURCE_PRIMARY_SLOT,
Christopher Collins92ea77f2016-12-12 15:59:26 -0800142 },
143};
144
145#define BOOT_STATUS_TABLES_COUNT \
146 (sizeof boot_status_tables / sizeof boot_status_tables[0])
147
Marti Bolivarfd20c762017-02-07 16:52:50 -0500148#define BOOT_LOG_SWAP_STATE(area, state) \
Christopher Collinsa1c12042019-05-23 14:00:28 -0700149 BOOT_LOG_INF("%s: magic=%s, swap_type=0x%x, copy_done=0x%x, " \
150 "image_ok=0x%x", \
Marti Bolivarfd20c762017-02-07 16:52:50 -0500151 (area), \
152 ((state)->magic == BOOT_MAGIC_GOOD ? "good" : \
153 (state)->magic == BOOT_MAGIC_UNSET ? "unset" : \
154 "bad"), \
Christopher Collinsa1c12042019-05-23 14:00:28 -0700155 (state)->swap_type, \
Marti Bolivarfd20c762017-02-07 16:52:50 -0500156 (state)->copy_done, \
157 (state)->image_ok)
158
Christopher Collins92ea77f2016-12-12 15:59:26 -0800159/**
David Vincze2d736ad2019-02-18 11:50:22 +0100160 * Determines where in flash the most recent boot status is stored. The boot
Christopher Collins92ea77f2016-12-12 15:59:26 -0800161 * status is necessary for completing a swap that was interrupted by a boot
162 * loader reset.
163 *
David Vincze2d736ad2019-02-18 11:50:22 +0100164 * @return A BOOT_STATUS_SOURCE_[...] code indicating where status should
165 * be read from.
Christopher Collins92ea77f2016-12-12 15:59:26 -0800166 */
167static int
168boot_status_source(void)
169{
170 const struct boot_status_table *table;
171 struct boot_swap_state state_scratch;
David Vincze2d736ad2019-02-18 11:50:22 +0100172 struct boot_swap_state state_primary_slot;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800173 int rc;
Fabio Utzigcd5774b2017-11-29 10:18:26 -0200174 size_t i;
Marti Bolivarfd20c762017-02-07 16:52:50 -0500175 uint8_t source;
Fabio Utzigb0f04732019-07-31 09:49:19 -0300176 uint8_t image_index;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800177
Fabio Utzigb0f04732019-07-31 09:49:19 -0300178#if (BOOT_IMAGE_NUMBER == 1)
179 (void)state;
180#endif
181
182 image_index = BOOT_CURR_IMG(&boot_data);
183 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_PRIMARY(image_index),
184 &state_primary_slot);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800185 assert(rc == 0);
186
Fabio Utzig2473ac02017-05-02 12:45:02 -0300187 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SCRATCH, &state_scratch);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800188 assert(rc == 0);
189
David Vincze2d736ad2019-02-18 11:50:22 +0100190 BOOT_LOG_SWAP_STATE("Primary image", &state_primary_slot);
Marti Bolivarfd20c762017-02-07 16:52:50 -0500191 BOOT_LOG_SWAP_STATE("Scratch", &state_scratch);
192
Christopher Collins92ea77f2016-12-12 15:59:26 -0800193 for (i = 0; i < BOOT_STATUS_TABLES_COUNT; i++) {
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300194 table = &boot_status_tables[i];
Christopher Collins92ea77f2016-12-12 15:59:26 -0800195
Christopher Collinsa1c12042019-05-23 14:00:28 -0700196 if (boot_magic_compatible_check(table->bst_magic_primary_slot,
197 state_primary_slot.magic) &&
198 boot_magic_compatible_check(table->bst_magic_scratch,
199 state_scratch.magic) &&
David Vincze2d736ad2019-02-18 11:50:22 +0100200 (table->bst_copy_done_primary_slot == BOOT_FLAG_ANY ||
201 table->bst_copy_done_primary_slot == state_primary_slot.copy_done))
202 {
Marti Bolivarfd20c762017-02-07 16:52:50 -0500203 source = table->bst_status_source;
David Vinczeba3bd602019-06-17 16:01:43 +0200204
205#if (BOOT_IMAGE_NUMBER > 1)
206 /* In case of multi-image boot it can happen that if boot status
207 * info is found on scratch area then it does not belong to the
208 * currently examined image.
209 */
210 if (source == BOOT_STATUS_SOURCE_SCRATCH &&
Fabio Utzigb0f04732019-07-31 09:49:19 -0300211 state_scratch.image_num != BOOT_CURR_IMG(&boot_data)) {
David Vinczeba3bd602019-06-17 16:01:43 +0200212 source = BOOT_STATUS_SOURCE_NONE;
213 }
214#endif
215
Marti Bolivarfd20c762017-02-07 16:52:50 -0500216 BOOT_LOG_INF("Boot source: %s",
217 source == BOOT_STATUS_SOURCE_NONE ? "none" :
218 source == BOOT_STATUS_SOURCE_SCRATCH ? "scratch" :
David Vincze2d736ad2019-02-18 11:50:22 +0100219 source == BOOT_STATUS_SOURCE_PRIMARY_SLOT ?
220 "primary slot" : "BUG; can't happen");
Marti Bolivarfd20c762017-02-07 16:52:50 -0500221 return source;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800222 }
223 }
224
Marti Bolivarfd20c762017-02-07 16:52:50 -0500225 BOOT_LOG_INF("Boot source: none");
Christopher Collins92ea77f2016-12-12 15:59:26 -0800226 return BOOT_STATUS_SOURCE_NONE;
227}
228
David Brownf5b33d82017-09-01 10:58:27 -0600229/*
230 * Compute the total size of the given image. Includes the size of
231 * the TLVs.
232 */
Fabio Utzig13d9e352017-10-05 20:32:31 -0300233#if !defined(MCUBOOT_OVERWRITE_ONLY) || defined(MCUBOOT_OVERWRITE_ONLY_FAST)
David Brownf5b33d82017-09-01 10:58:27 -0600234static int
235boot_read_image_size(int slot, struct image_header *hdr, uint32_t *size)
236{
237 const struct flash_area *fap;
238 struct image_tlv_info info;
239 int area_id;
240 int rc;
241
Fabio Utzigb0f04732019-07-31 09:49:19 -0300242 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(&boot_data),
243 slot);
David Brownf5b33d82017-09-01 10:58:27 -0600244 rc = flash_area_open(area_id, &fap);
245 if (rc != 0) {
246 rc = BOOT_EFLASH;
247 goto done;
248 }
249
250 rc = flash_area_read(fap, hdr->ih_hdr_size + hdr->ih_img_size,
251 &info, sizeof(info));
252 if (rc != 0) {
253 rc = BOOT_EFLASH;
254 goto done;
255 }
256 if (info.it_magic != IMAGE_TLV_INFO_MAGIC) {
257 rc = BOOT_EBADIMAGE;
258 goto done;
259 }
260 *size = hdr->ih_hdr_size + hdr->ih_img_size + info.it_tlv_tot;
261 rc = 0;
262
263done:
264 flash_area_close(fap);
Fabio Utzig2eebf112017-09-04 15:25:08 -0300265 return rc;
David Brownf5b33d82017-09-01 10:58:27 -0600266}
Fabio Utzig36ec0e72017-09-05 08:10:33 -0300267#endif /* !MCUBOOT_OVERWRITE_ONLY */
David Brownf5b33d82017-09-01 10:58:27 -0600268
Fabio Utzigc08ed212017-06-20 19:28:36 -0300269static int
Christopher Collins92ea77f2016-12-12 15:59:26 -0800270boot_read_image_header(int slot, struct image_header *out_hdr)
271{
272 const struct flash_area *fap;
273 int area_id;
274 int rc;
275
Fabio Utzigb0f04732019-07-31 09:49:19 -0300276 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(&boot_data),
277 slot);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800278 rc = flash_area_open(area_id, &fap);
279 if (rc != 0) {
280 rc = BOOT_EFLASH;
281 goto done;
282 }
283
284 rc = flash_area_read(fap, 0, out_hdr, sizeof *out_hdr);
285 if (rc != 0) {
286 rc = BOOT_EFLASH;
287 goto done;
288 }
289
290 rc = 0;
291
292done:
293 flash_area_close(fap);
294 return rc;
295}
296
297static int
Fabio Utzig9c25fa72017-12-12 14:57:20 -0200298boot_read_image_headers(bool require_all)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800299{
300 int rc;
301 int i;
302
303 for (i = 0; i < BOOT_NUM_SLOTS; i++) {
Marti Bolivarf804f622017-06-12 15:41:48 -0400304 rc = boot_read_image_header(i, boot_img_hdr(&boot_data, i));
Christopher Collins92ea77f2016-12-12 15:59:26 -0800305 if (rc != 0) {
Fabio Utzig9c25fa72017-12-12 14:57:20 -0200306 /* If `require_all` is set, fail on any single fail, otherwise
307 * if at least the first slot's header was read successfully,
308 * then the boot loader can attempt a boot.
309 *
310 * Failure to read any headers is a fatal error.
Christopher Collins0ff3c6c2016-12-21 12:04:17 -0800311 */
Fabio Utzig9c25fa72017-12-12 14:57:20 -0200312 if (i > 0 && !require_all) {
Christopher Collins0ff3c6c2016-12-21 12:04:17 -0800313 return 0;
314 } else {
315 return rc;
316 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800317 }
318 }
319
320 return 0;
321}
322
323static uint8_t
324boot_write_sz(void)
325{
326 uint8_t elem_sz;
327 uint8_t align;
328
329 /* Figure out what size to write update status update as. The size depends
330 * on what the minimum write size is for scratch area, active image slot.
331 * We need to use the bigger of those 2 values.
332 */
David Vinczeba3bd602019-06-17 16:01:43 +0200333 elem_sz = flash_area_align(BOOT_IMG_AREA(&boot_data, BOOT_PRIMARY_SLOT));
334 align = flash_area_align(BOOT_SCRATCH_AREA(&boot_data));
Christopher Collins92ea77f2016-12-12 15:59:26 -0800335 if (align > elem_sz) {
336 elem_sz = align;
337 }
338
339 return elem_sz;
340}
341
Fabio Utzig2bd980a2018-11-26 10:38:17 -0200342/*
343 * Slots are compatible when all sectors that store upto to size of the image
344 * round up to sector size, in both slot's are able to fit in the scratch
345 * area, and have sizes that are a multiple of each other (powers of two
346 * presumably!).
347 */
Christopher Collins0ff3c6c2016-12-21 12:04:17 -0800348static int
349boot_slots_compatible(void)
350{
David Vincze2d736ad2019-02-18 11:50:22 +0100351 size_t num_sectors_primary;
352 size_t num_sectors_secondary;
Fabio Utzig2bd980a2018-11-26 10:38:17 -0200353 size_t sz0, sz1;
David Vincze2d736ad2019-02-18 11:50:22 +0100354 size_t primary_slot_sz, secondary_slot_sz;
Fabio Utzig2bd980a2018-11-26 10:38:17 -0200355 size_t scratch_sz;
356 size_t i, j;
357 int8_t smaller;
Christopher Collins0ff3c6c2016-12-21 12:04:17 -0800358
David Vincze2d736ad2019-02-18 11:50:22 +0100359 num_sectors_primary =
360 boot_img_num_sectors(&boot_data, BOOT_PRIMARY_SLOT);
361 num_sectors_secondary =
362 boot_img_num_sectors(&boot_data, BOOT_SECONDARY_SLOT);
363 if ((num_sectors_primary > BOOT_MAX_IMG_SECTORS) ||
364 (num_sectors_secondary > BOOT_MAX_IMG_SECTORS)) {
Fabio Utziga1fae672018-03-30 10:52:38 -0300365 BOOT_LOG_WRN("Cannot upgrade: more sectors than allowed");
Christopher Collins0ff3c6c2016-12-21 12:04:17 -0800366 return 0;
367 }
Fabio Utziga1fae672018-03-30 10:52:38 -0300368
Fabio Utzig2bd980a2018-11-26 10:38:17 -0200369 scratch_sz = boot_scratch_area_size(&boot_data);
370
371 /*
372 * The following loop scans all sectors in a linear fashion, assuring that
373 * for each possible sector in each slot, it is able to fit in the other
374 * slot's sector or sectors. Slot's should be compatible as long as any
375 * number of a slot's sectors are able to fit into another, which only
376 * excludes cases where sector sizes are not a multiple of each other.
377 */
David Vincze2d736ad2019-02-18 11:50:22 +0100378 i = sz0 = primary_slot_sz = 0;
379 j = sz1 = secondary_slot_sz = 0;
Fabio Utzig2bd980a2018-11-26 10:38:17 -0200380 smaller = 0;
David Vincze2d736ad2019-02-18 11:50:22 +0100381 while (i < num_sectors_primary || j < num_sectors_secondary) {
Fabio Utzig2bd980a2018-11-26 10:38:17 -0200382 if (sz0 == sz1) {
David Vincze2d736ad2019-02-18 11:50:22 +0100383 sz0 += boot_img_sector_size(&boot_data, BOOT_PRIMARY_SLOT, i);
384 sz1 += boot_img_sector_size(&boot_data, BOOT_SECONDARY_SLOT, j);
Fabio Utzig2bd980a2018-11-26 10:38:17 -0200385 i++;
386 j++;
387 } else if (sz0 < sz1) {
David Vincze2d736ad2019-02-18 11:50:22 +0100388 sz0 += boot_img_sector_size(&boot_data, BOOT_PRIMARY_SLOT, i);
389 /* Guarantee that multiple sectors of the secondary slot
390 * fit into the primary slot.
391 */
Fabio Utzig2bd980a2018-11-26 10:38:17 -0200392 if (smaller == 2) {
393 BOOT_LOG_WRN("Cannot upgrade: slots have non-compatible sectors");
394 return 0;
395 }
396 smaller = 1;
397 i++;
398 } else {
David Vincze2d736ad2019-02-18 11:50:22 +0100399 sz1 += boot_img_sector_size(&boot_data, BOOT_SECONDARY_SLOT, j);
400 /* Guarantee that multiple sectors of the primary slot
401 * fit into the secondary slot.
402 */
Fabio Utzig2bd980a2018-11-26 10:38:17 -0200403 if (smaller == 1) {
404 BOOT_LOG_WRN("Cannot upgrade: slots have non-compatible sectors");
405 return 0;
406 }
407 smaller = 2;
408 j++;
409 }
410 if (sz0 == sz1) {
David Vincze2d736ad2019-02-18 11:50:22 +0100411 primary_slot_sz += sz0;
412 secondary_slot_sz += sz1;
413 /* Scratch has to fit each swap operation to the size of the larger
414 * sector among the primary slot and the secondary slot.
Fabio Utzig2bd980a2018-11-26 10:38:17 -0200415 */
416 if (sz0 > scratch_sz || sz1 > scratch_sz) {
417 BOOT_LOG_WRN("Cannot upgrade: not all sectors fit inside scratch");
418 return 0;
419 }
420 smaller = sz0 = sz1 = 0;
421 }
Fabio Utziga1fae672018-03-30 10:52:38 -0300422 }
423
David Vincze2d736ad2019-02-18 11:50:22 +0100424 if ((i != num_sectors_primary) ||
425 (j != num_sectors_secondary) ||
426 (primary_slot_sz != secondary_slot_sz)) {
Fabio Utzig2bd980a2018-11-26 10:38:17 -0200427 BOOT_LOG_WRN("Cannot upgrade: slots are not compatible");
428 return 0;
Christopher Collins0ff3c6c2016-12-21 12:04:17 -0800429 }
430
431 return 1;
432}
433
Christopher Collins92ea77f2016-12-12 15:59:26 -0800434/**
435 * Determines the sector layout of both image slots and the scratch area.
436 * This information is necessary for calculating the number of bytes to erase
437 * and copy during an image swap. The information collected during this
438 * function is used to populate the boot_data global.
439 */
440static int
441boot_read_sectors(void)
442{
Fabio Utzigb0f04732019-07-31 09:49:19 -0300443 uint8_t image_index;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800444 int rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800445
Fabio Utzigb0f04732019-07-31 09:49:19 -0300446 image_index = BOOT_CURR_IMG(&boot_data);
447
448 rc = boot_initialize_area(state, FLASH_AREA_IMAGE_PRIMARY(image_index));
Christopher Collins92ea77f2016-12-12 15:59:26 -0800449 if (rc != 0) {
450 return BOOT_EFLASH;
451 }
452
Fabio Utzigb0f04732019-07-31 09:49:19 -0300453 rc = boot_initialize_area(&boot_data,
454 FLASH_AREA_IMAGE_SECONDARY(image_index));
Christopher Collins92ea77f2016-12-12 15:59:26 -0800455 if (rc != 0) {
456 return BOOT_EFLASH;
457 }
458
Fabio Utzig2bd980a2018-11-26 10:38:17 -0200459 rc = boot_initialize_area(&boot_data, FLASH_AREA_IMAGE_SCRATCH);
460 if (rc != 0) {
461 return BOOT_EFLASH;
462 }
463
Marti Bolivare10a7392017-06-14 16:20:07 -0400464 BOOT_WRITE_SZ(&boot_data) = boot_write_sz();
Christopher Collins92ea77f2016-12-12 15:59:26 -0800465
466 return 0;
467}
468
469static uint32_t
470boot_status_internal_off(int idx, int state, int elem_sz)
471{
472 int idx_sz;
473
474 idx_sz = elem_sz * BOOT_STATUS_STATE_COUNT;
475
Fabio Utzig39000012018-07-30 12:40:20 -0300476 return (idx - BOOT_STATUS_IDX_0) * idx_sz +
477 (state - BOOT_STATUS_STATE_0) * elem_sz;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800478}
479
480/**
481 * Reads the status of a partially-completed swap, if any. This is necessary
482 * to recover in case the boot lodaer was reset in the middle of a swap
483 * operation.
484 */
485static int
486boot_read_status_bytes(const struct flash_area *fap, struct boot_status *bs)
487{
488 uint32_t off;
489 uint8_t status;
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300490 int max_entries;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800491 int found;
Fabio Utziga0e1cce2017-11-23 20:04:01 -0200492 int found_idx;
493 int invalid;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800494 int rc;
495 int i;
496
497 off = boot_status_off(fap);
Fabio Utzigb0f04732019-07-31 09:49:19 -0300498 max_entries = boot_status_entries(BOOT_CURR_IMG(&boot_data), fap);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300499
Christopher Collins92ea77f2016-12-12 15:59:26 -0800500 found = 0;
Fabio Utziga0e1cce2017-11-23 20:04:01 -0200501 found_idx = 0;
502 invalid = 0;
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300503 for (i = 0; i < max_entries; i++) {
Fabio Utzig178be542018-09-19 08:12:56 -0300504 rc = flash_area_read_is_empty(fap, off + i * BOOT_WRITE_SZ(&boot_data),
505 &status, 1);
506 if (rc < 0) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800507 return BOOT_EFLASH;
508 }
509
Fabio Utzig178be542018-09-19 08:12:56 -0300510 if (rc == 1) {
Fabio Utziga0e1cce2017-11-23 20:04:01 -0200511 if (found && !found_idx) {
512 found_idx = i;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800513 }
514 } else if (!found) {
515 found = 1;
Fabio Utziga0e1cce2017-11-23 20:04:01 -0200516 } else if (found_idx) {
517 invalid = 1;
518 break;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800519 }
520 }
521
Fabio Utziga0e1cce2017-11-23 20:04:01 -0200522 if (invalid) {
523 /* This means there was an error writing status on the last
524 * swap. Tell user and move on to validation!
525 */
526 BOOT_LOG_ERR("Detected inconsistent status!");
527
David Vincze2d736ad2019-02-18 11:50:22 +0100528#if !defined(MCUBOOT_VALIDATE_PRIMARY_SLOT)
529 /* With validation of the primary slot disabled, there is no way
530 * to be sure the swapped primary slot is OK, so abort!
Fabio Utziga0e1cce2017-11-23 20:04:01 -0200531 */
532 assert(0);
533#endif
534 }
535
Christopher Collins92ea77f2016-12-12 15:59:26 -0800536 if (found) {
Fabio Utziga0e1cce2017-11-23 20:04:01 -0200537 if (!found_idx) {
538 found_idx = i;
539 }
540 found_idx--;
Fabio Utzig39000012018-07-30 12:40:20 -0300541 bs->idx = (found_idx / BOOT_STATUS_STATE_COUNT) + 1;
542 bs->state = (found_idx % BOOT_STATUS_STATE_COUNT) + 1;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800543 }
544
545 return 0;
546}
547
548/**
549 * Reads the boot status from the flash. The boot status contains
550 * the current state of an interrupted image copy operation. If the boot
551 * status is not present, or it indicates that previous copy finished,
552 * there is no operation in progress.
553 */
554static int
555boot_read_status(struct boot_status *bs)
556{
557 const struct flash_area *fap;
Christopher Collinsa1c12042019-05-23 14:00:28 -0700558 uint32_t off;
David Vinczee2453472019-06-17 12:31:59 +0200559 uint8_t swap_info;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800560 int status_loc;
561 int area_id;
562 int rc;
563
564 memset(bs, 0, sizeof *bs);
Fabio Utzig39000012018-07-30 12:40:20 -0300565 bs->idx = BOOT_STATUS_IDX_0;
566 bs->state = BOOT_STATUS_STATE_0;
Christopher Collinsa1c12042019-05-23 14:00:28 -0700567 bs->swap_type = BOOT_SWAP_TYPE_NONE;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800568
Fabio Utzig03dc9a02018-06-11 12:24:07 -0700569#ifdef MCUBOOT_OVERWRITE_ONLY
570 /* Overwrite-only doesn't make use of the swap status area. */
571 return 0;
572#endif
573
Christopher Collins92ea77f2016-12-12 15:59:26 -0800574 status_loc = boot_status_source();
575 switch (status_loc) {
576 case BOOT_STATUS_SOURCE_NONE:
577 return 0;
578
579 case BOOT_STATUS_SOURCE_SCRATCH:
580 area_id = FLASH_AREA_IMAGE_SCRATCH;
581 break;
582
David Vincze2d736ad2019-02-18 11:50:22 +0100583 case BOOT_STATUS_SOURCE_PRIMARY_SLOT:
Fabio Utzigb0f04732019-07-31 09:49:19 -0300584 area_id = FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(&boot_data));
Christopher Collins92ea77f2016-12-12 15:59:26 -0800585 break;
586
587 default:
588 assert(0);
589 return BOOT_EBADARGS;
590 }
591
592 rc = flash_area_open(area_id, &fap);
593 if (rc != 0) {
594 return BOOT_EFLASH;
595 }
596
Fabio Utzig46490722017-09-04 15:34:32 -0300597 rc = boot_read_status_bytes(fap, bs);
Christopher Collinsa1c12042019-05-23 14:00:28 -0700598 if (rc == 0) {
David Vinczee2453472019-06-17 12:31:59 +0200599 off = boot_swap_info_off(fap);
600 rc = flash_area_read_is_empty(fap, off, &swap_info, sizeof swap_info);
Christopher Collinsa1c12042019-05-23 14:00:28 -0700601 if (rc == 1) {
David Vinczee2453472019-06-17 12:31:59 +0200602 BOOT_SET_SWAP_INFO(swap_info, 0, BOOT_SWAP_TYPE_NONE);
Christopher Collinsa1c12042019-05-23 14:00:28 -0700603 rc = 0;
604 }
David Vinczee2453472019-06-17 12:31:59 +0200605
606 /* Extract the swap type info */
607 bs->swap_type = BOOT_GET_SWAP_TYPE(swap_info);
Christopher Collinsa1c12042019-05-23 14:00:28 -0700608 }
Fabio Utzig46490722017-09-04 15:34:32 -0300609
610 flash_area_close(fap);
Fabio Utzig03dc9a02018-06-11 12:24:07 -0700611
Fabio Utzig46490722017-09-04 15:34:32 -0300612 return rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800613}
614
615/**
616 * Writes the supplied boot status to the flash file system. The boot status
617 * contains the current state of an in-progress image copy operation.
618 *
619 * @param bs The boot status to write.
620 *
621 * @return 0 on success; nonzero on failure.
622 */
623int
624boot_write_status(struct boot_status *bs)
625{
626 const struct flash_area *fap;
627 uint32_t off;
628 int area_id;
629 int rc;
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300630 uint8_t buf[BOOT_MAX_ALIGN];
David Brown9d725462017-01-23 15:50:58 -0700631 uint8_t align;
Fabio Utzig39000012018-07-30 12:40:20 -0300632 uint8_t erased_val;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800633
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300634 /* NOTE: The first sector copied (that is the last sector on slot) contains
David Vincze2d736ad2019-02-18 11:50:22 +0100635 * the trailer. Since in the last step the primary slot is erased, the
636 * first two status writes go to the scratch which will be copied to
637 * the primary slot!
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300638 */
639
Fabio Utzig2473ac02017-05-02 12:45:02 -0300640 if (bs->use_scratch) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800641 /* Write to scratch. */
642 area_id = FLASH_AREA_IMAGE_SCRATCH;
643 } else {
David Vincze2d736ad2019-02-18 11:50:22 +0100644 /* Write to the primary slot. */
Fabio Utzigb0f04732019-07-31 09:49:19 -0300645 area_id = FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(&boot_data));
Christopher Collins92ea77f2016-12-12 15:59:26 -0800646 }
647
648 rc = flash_area_open(area_id, &fap);
649 if (rc != 0) {
650 rc = BOOT_EFLASH;
651 goto done;
652 }
653
654 off = boot_status_off(fap) +
Marti Bolivare10a7392017-06-14 16:20:07 -0400655 boot_status_internal_off(bs->idx, bs->state,
656 BOOT_WRITE_SZ(&boot_data));
Andrzej Puzdrowskib788c712018-04-12 12:42:49 +0200657 align = flash_area_align(fap);
Fabio Utzig39000012018-07-30 12:40:20 -0300658 erased_val = flash_area_erased_val(fap);
659 memset(buf, erased_val, BOOT_MAX_ALIGN);
David Brown9d725462017-01-23 15:50:58 -0700660 buf[0] = bs->state;
661
662 rc = flash_area_write(fap, off, buf, align);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800663 if (rc != 0) {
664 rc = BOOT_EFLASH;
665 goto done;
666 }
667
668 rc = 0;
669
670done:
671 flash_area_close(fap);
672 return rc;
673}
674
675/*
676 * Validate image hash/signature in a slot.
677 */
678static int
Fabio Utzigba829042018-09-18 08:29:34 -0300679boot_image_check(struct image_header *hdr, const struct flash_area *fap,
680 struct boot_status *bs)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800681{
David Browndb1d9d32017-01-06 11:07:54 -0700682 static uint8_t tmpbuf[BOOT_TMPBUF_SZ];
Fabio Utzigb0f04732019-07-31 09:49:19 -0300683 uint8_t image_index;
Fabio Utzigba829042018-09-18 08:29:34 -0300684 int rc;
685
Fabio Utzigb0f04732019-07-31 09:49:19 -0300686 image_index = BOOT_CURR_IMG(&boot_data);
687
Fabio Utzigba829042018-09-18 08:29:34 -0300688#ifndef MCUBOOT_ENC_IMAGES
689 (void)bs;
690 (void)rc;
691#else
Fabio Utzigb0f04732019-07-31 09:49:19 -0300692 if ((fap->fa_id == FLASH_AREA_IMAGE_SECONDARY(image_index))
693 && IS_ENCRYPTED(hdr)) {
694 rc = boot_enc_load(image_index, hdr, fap, bs->enckey[1]);
Fabio Utzigba829042018-09-18 08:29:34 -0300695 if (rc < 0) {
696 return BOOT_EBADIMAGE;
697 }
698 if (rc == 0 && boot_enc_set_key(1, bs->enckey[1])) {
699 return BOOT_EBADIMAGE;
700 }
701 }
702#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800703
Fabio Utzigb0f04732019-07-31 09:49:19 -0300704 if (bootutil_img_validate(image_index, hdr, fap, tmpbuf, BOOT_TMPBUF_SZ,
705 NULL, 0, NULL)) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800706 return BOOT_EBADIMAGE;
707 }
708 return 0;
709}
710
711static int
712split_image_check(struct image_header *app_hdr,
713 const struct flash_area *app_fap,
714 struct image_header *loader_hdr,
715 const struct flash_area *loader_fap)
716{
717 static void *tmpbuf;
718 uint8_t loader_hash[32];
719
720 if (!tmpbuf) {
721 tmpbuf = malloc(BOOT_TMPBUF_SZ);
722 if (!tmpbuf) {
723 return BOOT_ENOMEM;
724 }
725 }
726
Fabio Utzigb0f04732019-07-31 09:49:19 -0300727 if (bootutil_img_validate(0, loader_hdr, loader_fap, tmpbuf, BOOT_TMPBUF_SZ,
Christopher Collins92ea77f2016-12-12 15:59:26 -0800728 NULL, 0, loader_hash)) {
729 return BOOT_EBADIMAGE;
730 }
731
Fabio Utzigb0f04732019-07-31 09:49:19 -0300732 if (bootutil_img_validate(0, app_hdr, app_fap, tmpbuf, BOOT_TMPBUF_SZ,
Christopher Collins92ea77f2016-12-12 15:59:26 -0800733 loader_hash, 32, NULL)) {
734 return BOOT_EBADIMAGE;
735 }
736
737 return 0;
738}
739
Fabio Utzig338a19f2018-12-03 08:37:08 -0200740/*
741 * Check that a memory area consists of a given value.
742 */
743static inline bool
744boot_data_is_set_to(uint8_t val, void *data, size_t len)
Fabio Utzig39000012018-07-30 12:40:20 -0300745{
746 uint8_t i;
Fabio Utzig338a19f2018-12-03 08:37:08 -0200747 uint8_t *p = (uint8_t *)data;
748 for (i = 0; i < len; i++) {
749 if (val != p[i]) {
750 return false;
Fabio Utzig39000012018-07-30 12:40:20 -0300751 }
752 }
Fabio Utzig338a19f2018-12-03 08:37:08 -0200753 return true;
754}
755
756static int
757boot_check_header_erased(int slot)
758{
759 const struct flash_area *fap;
760 struct image_header *hdr;
761 uint8_t erased_val;
Fabio Utzigb0f04732019-07-31 09:49:19 -0300762 int area_id;
Fabio Utzig338a19f2018-12-03 08:37:08 -0200763 int rc;
764
Fabio Utzigb0f04732019-07-31 09:49:19 -0300765 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(&boot_data),
766 slot);
767 rc = flash_area_open(area_id, &fap);
Fabio Utzig338a19f2018-12-03 08:37:08 -0200768 if (rc != 0) {
769 return -1;
770 }
771
772 erased_val = flash_area_erased_val(fap);
773 flash_area_close(fap);
774
775 hdr = boot_img_hdr(&boot_data, slot);
776 if (!boot_data_is_set_to(erased_val, &hdr->ih_magic, sizeof(hdr->ih_magic))) {
777 return -1;
778 }
779
780 return 0;
Fabio Utzig39000012018-07-30 12:40:20 -0300781}
782
Christopher Collins92ea77f2016-12-12 15:59:26 -0800783static int
Fabio Utzigba829042018-09-18 08:29:34 -0300784boot_validate_slot(int slot, struct boot_status *bs)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800785{
786 const struct flash_area *fap;
Marti Bolivarf804f622017-06-12 15:41:48 -0400787 struct image_header *hdr;
Fabio Utzigb0f04732019-07-31 09:49:19 -0300788 int area_id;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800789 int rc;
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300790
Fabio Utzigb0f04732019-07-31 09:49:19 -0300791 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(&boot_data),
792 slot);
793 rc = flash_area_open(area_id, &fap);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800794 if (rc != 0) {
795 return BOOT_EFLASH;
796 }
797
Fabio Utzig39000012018-07-30 12:40:20 -0300798 hdr = boot_img_hdr(&boot_data, slot);
Fabio Utzig338a19f2018-12-03 08:37:08 -0200799 if (boot_check_header_erased(slot) == 0 || (hdr->ih_flags & IMAGE_F_NON_BOOTABLE)) {
David Vincze2d736ad2019-02-18 11:50:22 +0100800 /* No bootable image in slot; continue booting from the primary slot. */
Fabio Utzig338a19f2018-12-03 08:37:08 -0200801 rc = -1;
802 goto out;
Fabio Utzig39000012018-07-30 12:40:20 -0300803 }
804
Fabio Utzigba829042018-09-18 08:29:34 -0300805 if ((hdr->ih_magic != IMAGE_MAGIC || boot_image_check(hdr, fap, bs) != 0)) {
David Vincze2d736ad2019-02-18 11:50:22 +0100806 if (slot != BOOT_PRIMARY_SLOT) {
David Brownb38e0442017-02-24 13:57:12 -0700807 flash_area_erase(fap, 0, fap->fa_size);
David Vincze2d736ad2019-02-18 11:50:22 +0100808 /* Image in the secondary slot is invalid. Erase the image and
809 * continue booting from the primary slot.
David Brownb38e0442017-02-24 13:57:12 -0700810 */
811 }
David Vincze2d736ad2019-02-18 11:50:22 +0100812 BOOT_LOG_ERR("Image in the %s slot is not valid!",
813 (slot == BOOT_PRIMARY_SLOT) ? "primary" : "secondary");
Fabio Utzig338a19f2018-12-03 08:37:08 -0200814 rc = -1;
815 goto out;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800816 }
817
David Vincze2d736ad2019-02-18 11:50:22 +0100818 /* Image in the secondary slot is valid. */
Fabio Utzig338a19f2018-12-03 08:37:08 -0200819 rc = 0;
820
821out:
822 flash_area_close(fap);
823 return rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800824}
825
826/**
827 * Determines which swap operation to perform, if any. If it is determined
David Vincze2d736ad2019-02-18 11:50:22 +0100828 * that a swap operation is required, the image in the secondary slot is checked
829 * for validity. If the image in the secondary slot is invalid, it is erased,
830 * and a swap type of "none" is indicated.
Christopher Collins92ea77f2016-12-12 15:59:26 -0800831 *
832 * @return The type of swap to perform (BOOT_SWAP_TYPE...)
833 */
834static int
Fabio Utzigba829042018-09-18 08:29:34 -0300835boot_validated_swap_type(struct boot_status *bs)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800836{
837 int swap_type;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800838
Fabio Utzigb0f04732019-07-31 09:49:19 -0300839#if (BOOT_IMAGE_NUMBER == 1)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800840 swap_type = boot_swap_type();
Fabio Utzigb0f04732019-07-31 09:49:19 -0300841#else
842 swap_type = boot_swap_type_multi(BOOT_CURR_IMG(state));
843#endif
Fabio Utzigb5b2f552017-06-30 10:03:47 -0300844 switch (swap_type) {
845 case BOOT_SWAP_TYPE_TEST:
846 case BOOT_SWAP_TYPE_PERM:
847 case BOOT_SWAP_TYPE_REVERT:
David Vincze2d736ad2019-02-18 11:50:22 +0100848 /* Boot loader wants to switch to the secondary slot.
849 * Ensure image is valid.
850 */
851 if (boot_validate_slot(BOOT_SECONDARY_SLOT, bs) != 0) {
Fabio Utzigb5b2f552017-06-30 10:03:47 -0300852 swap_type = BOOT_SWAP_TYPE_FAIL;
853 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800854 }
855
856 return swap_type;
857}
858
859/**
860 * Calculates the number of sectors the scratch area can contain. A "last"
861 * source sector is specified because images are copied backwards in flash
862 * (final index to index number 0).
863 *
864 * @param last_sector_idx The index of the last source sector
865 * (inclusive).
866 * @param out_first_sector_idx The index of the first source sector
867 * (inclusive) gets written here.
868 *
869 * @return The number of bytes comprised by the
870 * [first-sector, last-sector] range.
871 */
Fabio Utzig3488eef2017-06-12 10:25:43 -0300872#ifndef MCUBOOT_OVERWRITE_ONLY
Christopher Collins92ea77f2016-12-12 15:59:26 -0800873static uint32_t
874boot_copy_sz(int last_sector_idx, int *out_first_sector_idx)
875{
Marti Bolivard3269fd2017-06-12 16:31:12 -0400876 size_t scratch_sz;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800877 uint32_t new_sz;
878 uint32_t sz;
879 int i;
880
881 sz = 0;
882
Marti Bolivard3269fd2017-06-12 16:31:12 -0400883 scratch_sz = boot_scratch_area_size(&boot_data);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800884 for (i = last_sector_idx; i >= 0; i--) {
David Vincze2d736ad2019-02-18 11:50:22 +0100885 new_sz = sz + boot_img_sector_size(&boot_data, BOOT_PRIMARY_SLOT, i);
Fabio Utzig2bd980a2018-11-26 10:38:17 -0200886 /*
David Vincze2d736ad2019-02-18 11:50:22 +0100887 * The secondary slot is not being checked here, because
888 * `boot_slots_compatible` already provides assurance that the copy size
889 * will be compatible with the primary slot and scratch.
Fabio Utzig2bd980a2018-11-26 10:38:17 -0200890 */
Marti Bolivard3269fd2017-06-12 16:31:12 -0400891 if (new_sz > scratch_sz) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800892 break;
893 }
894 sz = new_sz;
895 }
896
897 /* i currently refers to a sector that doesn't fit or it is -1 because all
898 * sectors have been processed. In both cases, exclude sector i.
899 */
900 *out_first_sector_idx = i + 1;
901 return sz;
902}
Fabio Utzig3488eef2017-06-12 10:25:43 -0300903#endif /* !MCUBOOT_OVERWRITE_ONLY */
Christopher Collins92ea77f2016-12-12 15:59:26 -0800904
905/**
906 * Erases a region of flash.
907 *
Fabio Utzigba829042018-09-18 08:29:34 -0300908 * @param flash_area The flash_area containing the region to erase.
Christopher Collins92ea77f2016-12-12 15:59:26 -0800909 * @param off The offset within the flash area to start the
910 * erase.
911 * @param sz The number of bytes to erase.
912 *
913 * @return 0 on success; nonzero on failure.
914 */
Fabio Utzigba829042018-09-18 08:29:34 -0300915static inline int
916boot_erase_sector(const struct flash_area *fap, uint32_t off, uint32_t sz)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800917{
Fabio Utzigba829042018-09-18 08:29:34 -0300918 return flash_area_erase(fap, off, sz);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800919}
920
921/**
922 * Copies the contents of one flash region to another. You must erase the
923 * destination region prior to calling this function.
924 *
925 * @param flash_area_id_src The ID of the source flash area.
926 * @param flash_area_id_dst The ID of the destination flash area.
927 * @param off_src The offset within the source flash area to
928 * copy from.
929 * @param off_dst The offset within the destination flash area to
930 * copy to.
931 * @param sz The number of bytes to copy.
932 *
933 * @return 0 on success; nonzero on failure.
934 */
935static int
Fabio Utzigba829042018-09-18 08:29:34 -0300936boot_copy_sector(const struct flash_area *fap_src,
937 const struct flash_area *fap_dst,
Christopher Collins92ea77f2016-12-12 15:59:26 -0800938 uint32_t off_src, uint32_t off_dst, uint32_t sz)
939{
Christopher Collins92ea77f2016-12-12 15:59:26 -0800940 uint32_t bytes_copied;
941 int chunk_sz;
942 int rc;
Fabio Utzigba829042018-09-18 08:29:34 -0300943#ifdef MCUBOOT_ENC_IMAGES
944 uint32_t off;
945 size_t blk_off;
946 struct image_header *hdr;
947 uint16_t idx;
948 uint32_t blk_sz;
Fabio Utzigb0f04732019-07-31 09:49:19 -0300949 uint8_t image_index;
Fabio Utzigba829042018-09-18 08:29:34 -0300950#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800951
952 static uint8_t buf[1024];
953
Christopher Collins92ea77f2016-12-12 15:59:26 -0800954 bytes_copied = 0;
955 while (bytes_copied < sz) {
956 if (sz - bytes_copied > sizeof buf) {
957 chunk_sz = sizeof buf;
958 } else {
959 chunk_sz = sz - bytes_copied;
960 }
961
962 rc = flash_area_read(fap_src, off_src + bytes_copied, buf, chunk_sz);
963 if (rc != 0) {
Fabio Utzigba829042018-09-18 08:29:34 -0300964 return BOOT_EFLASH;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800965 }
966
Fabio Utzigba829042018-09-18 08:29:34 -0300967#ifdef MCUBOOT_ENC_IMAGES
Fabio Utzigb0f04732019-07-31 09:49:19 -0300968 image_index = BOOT_CURR_IMG(&boot_data);
969 if (fap_src->fa_id == FLASH_AREA_IMAGE_SECONDARY(image_index) ||
970 fap_dst->fa_id == FLASH_AREA_IMAGE_SECONDARY(image_index)) {
David Vincze2d736ad2019-02-18 11:50:22 +0100971 /* assume the secondary slot as src, needs decryption */
972 hdr = boot_img_hdr(&boot_data, BOOT_SECONDARY_SLOT);
Fabio Utzigba829042018-09-18 08:29:34 -0300973 off = off_src;
Fabio Utzigb0f04732019-07-31 09:49:19 -0300974 if (fap_dst->fa_id == FLASH_AREA_IMAGE_SECONDARY(image_index)) {
David Vincze2d736ad2019-02-18 11:50:22 +0100975 /* might need encryption (metadata from the primary slot) */
976 hdr = boot_img_hdr(&boot_data, BOOT_PRIMARY_SLOT);
Fabio Utzigba829042018-09-18 08:29:34 -0300977 off = off_dst;
978 }
Fabio Utzig2fc80df2018-12-14 06:47:38 -0200979 if (IS_ENCRYPTED(hdr)) {
Fabio Utzigba829042018-09-18 08:29:34 -0300980 blk_sz = chunk_sz;
981 idx = 0;
982 if (off + bytes_copied < hdr->ih_hdr_size) {
983 /* do not decrypt header */
984 blk_off = 0;
985 blk_sz = chunk_sz - hdr->ih_hdr_size;
986 idx = hdr->ih_hdr_size;
987 } else {
988 blk_off = ((off + bytes_copied) - hdr->ih_hdr_size) & 0xf;
989 }
990 if (off + bytes_copied + chunk_sz > hdr->ih_hdr_size + hdr->ih_img_size) {
991 /* do not decrypt TLVs */
992 if (off + bytes_copied >= hdr->ih_hdr_size + hdr->ih_img_size) {
993 blk_sz = 0;
994 } else {
995 blk_sz = (hdr->ih_hdr_size + hdr->ih_img_size) - (off + bytes_copied);
996 }
997 }
Fabio Utzigb0f04732019-07-31 09:49:19 -0300998 boot_encrypt(image_index, fap_src,
999 (off + bytes_copied + idx) - hdr->ih_hdr_size, blk_sz,
1000 blk_off, &buf[idx]);
Fabio Utzigba829042018-09-18 08:29:34 -03001001 }
1002 }
1003#endif
1004
Christopher Collins92ea77f2016-12-12 15:59:26 -08001005 rc = flash_area_write(fap_dst, off_dst + bytes_copied, buf, chunk_sz);
1006 if (rc != 0) {
Fabio Utzigba829042018-09-18 08:29:34 -03001007 return BOOT_EFLASH;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001008 }
1009
1010 bytes_copied += chunk_sz;
Fabio Utzig853657c2019-05-07 08:06:07 -03001011
1012 MCUBOOT_WATCHDOG_FEED();
Christopher Collins92ea77f2016-12-12 15:59:26 -08001013 }
1014
Fabio Utzigba829042018-09-18 08:29:34 -03001015 return 0;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001016}
1017
David Brown6b1b3b92017-09-19 08:59:10 -06001018#ifndef MCUBOOT_OVERWRITE_ONLY
Fabio Utzig2473ac02017-05-02 12:45:02 -03001019static inline int
Fabio Utzigba829042018-09-18 08:29:34 -03001020boot_status_init(const struct flash_area *fap, const struct boot_status *bs)
Fabio Utzig2473ac02017-05-02 12:45:02 -03001021{
Fabio Utzig2473ac02017-05-02 12:45:02 -03001022 struct boot_swap_state swap_state;
Fabio Utzigb0f04732019-07-31 09:49:19 -03001023 uint8_t image_index;
Fabio Utzig2473ac02017-05-02 12:45:02 -03001024 int rc;
1025
Fabio Utzigb0f04732019-07-31 09:49:19 -03001026 image_index = BOOT_CURR_IMG(&boot_data);
1027
Christopher Collins2c88e692019-05-22 15:10:14 -07001028 BOOT_LOG_DBG("initializing status; fa_id=%d", fap->fa_id);
1029
Fabio Utzigb0f04732019-07-31 09:49:19 -03001030 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SECONDARY(image_index),
1031 &swap_state);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001032 assert(rc == 0);
1033
Christopher Collinsa1c12042019-05-23 14:00:28 -07001034 if (bs->swap_type != BOOT_SWAP_TYPE_NONE) {
Fabio Utzigb0f04732019-07-31 09:49:19 -03001035 rc = boot_write_swap_info(fap, bs->swap_type, image_index);
Christopher Collinsa1c12042019-05-23 14:00:28 -07001036 assert(rc == 0);
1037 }
1038
Fabio Utzigde8a38a2017-05-23 11:15:01 -04001039 if (swap_state.image_ok == BOOT_FLAG_SET) {
Fabio Utzig2473ac02017-05-02 12:45:02 -03001040 rc = boot_write_image_ok(fap);
1041 assert(rc == 0);
1042 }
1043
Fabio Utzig46490722017-09-04 15:34:32 -03001044 rc = boot_write_swap_size(fap, bs->swap_size);
1045 assert(rc == 0);
1046
Fabio Utzigba829042018-09-18 08:29:34 -03001047#ifdef MCUBOOT_ENC_IMAGES
1048 rc = boot_write_enc_key(fap, 0, bs->enckey[0]);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001049 assert(rc == 0);
1050
Fabio Utzigba829042018-09-18 08:29:34 -03001051 rc = boot_write_enc_key(fap, 1, bs->enckey[1]);
1052 assert(rc == 0);
1053#endif
1054
1055 rc = boot_write_magic(fap);
1056 assert(rc == 0);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001057
1058 return 0;
1059}
Christopher Collinsa1c12042019-05-23 14:00:28 -07001060
David Brown6b1b3b92017-09-19 08:59:10 -06001061#endif
Fabio Utzig2473ac02017-05-02 12:45:02 -03001062
Fabio Utzig358c9352017-07-25 22:10:45 -03001063#ifndef MCUBOOT_OVERWRITE_ONLY
Fabio Utzig2473ac02017-05-02 12:45:02 -03001064static int
Fabio Utziged0ca432019-01-23 14:50:11 -02001065boot_erase_trailer_sectors(const struct flash_area *fap)
Fabio Utzig2473ac02017-05-02 12:45:02 -03001066{
1067 uint8_t slot;
Fabio Utziged0ca432019-01-23 14:50:11 -02001068 uint32_t sector;
1069 uint32_t trailer_sz;
1070 uint32_t total_sz;
1071 uint32_t off;
1072 uint32_t sz;
David Vinczeb75c12a2019-03-22 14:58:33 +01001073 int fa_id_primary;
1074 int fa_id_secondary;
Fabio Utzigb0f04732019-07-31 09:49:19 -03001075 uint8_t image_index;
Fabio Utzig2473ac02017-05-02 12:45:02 -03001076 int rc;
1077
Christopher Collins2c88e692019-05-22 15:10:14 -07001078 BOOT_LOG_DBG("erasing trailer; fa_id=%d", fap->fa_id);
1079
Fabio Utzigb0f04732019-07-31 09:49:19 -03001080 image_index = BOOT_CURR_IMG(&boot_data);
1081 fa_id_primary = flash_area_id_from_multi_image_slot(image_index,
1082 BOOT_PRIMARY_SLOT);
1083 fa_id_secondary = flash_area_id_from_multi_image_slot(image_index,
1084 BOOT_SECONDARY_SLOT);
David Vinczeb75c12a2019-03-22 14:58:33 +01001085
1086 if (fap->fa_id == fa_id_primary) {
David Vincze2d736ad2019-02-18 11:50:22 +01001087 slot = BOOT_PRIMARY_SLOT;
David Vinczeb75c12a2019-03-22 14:58:33 +01001088 } else if (fap->fa_id == fa_id_secondary) {
David Vincze2d736ad2019-02-18 11:50:22 +01001089 slot = BOOT_SECONDARY_SLOT;
David Vinczeb75c12a2019-03-22 14:58:33 +01001090 } else {
Fabio Utzig2473ac02017-05-02 12:45:02 -03001091 return BOOT_EFLASH;
1092 }
1093
Fabio Utziged0ca432019-01-23 14:50:11 -02001094 /* delete starting from last sector and moving to beginning */
1095 sector = boot_img_num_sectors(&boot_data, slot) - 1;
Christopher Collins2adef702019-05-22 14:37:31 -07001096 trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(&boot_data));
Fabio Utziged0ca432019-01-23 14:50:11 -02001097 total_sz = 0;
1098 do {
1099 sz = boot_img_sector_size(&boot_data, slot, sector);
1100 off = boot_img_sector_off(&boot_data, slot, sector);
1101 rc = boot_erase_sector(fap, off, sz);
1102 assert(rc == 0);
1103
1104 sector--;
1105 total_sz += sz;
1106 } while (total_sz < trailer_sz);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001107
1108 return rc;
1109}
Fabio Utzig358c9352017-07-25 22:10:45 -03001110#endif /* !MCUBOOT_OVERWRITE_ONLY */
Fabio Utzig2473ac02017-05-02 12:45:02 -03001111
Christopher Collins92ea77f2016-12-12 15:59:26 -08001112/**
1113 * Swaps the contents of two flash regions within the two image slots.
1114 *
1115 * @param idx The index of the first sector in the range of
1116 * sectors being swapped.
1117 * @param sz The number of bytes to swap.
1118 * @param bs The current boot status. This struct gets
1119 * updated according to the outcome.
1120 *
1121 * @return 0 on success; nonzero on failure.
1122 */
Fabio Utzig3488eef2017-06-12 10:25:43 -03001123#ifndef MCUBOOT_OVERWRITE_ONLY
Christopher Collins4772ac42017-02-27 20:08:01 -08001124static void
Christopher Collins92ea77f2016-12-12 15:59:26 -08001125boot_swap_sectors(int idx, uint32_t sz, struct boot_status *bs)
1126{
David Vincze2d736ad2019-02-18 11:50:22 +01001127 const struct flash_area *fap_primary_slot;
1128 const struct flash_area *fap_secondary_slot;
Fabio Utzigba829042018-09-18 08:29:34 -03001129 const struct flash_area *fap_scratch;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001130 uint32_t copy_sz;
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001131 uint32_t trailer_sz;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001132 uint32_t img_off;
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001133 uint32_t scratch_trailer_off;
1134 struct boot_swap_state swap_state;
Marti Bolivard3269fd2017-06-12 16:31:12 -04001135 size_t last_sector;
Christopher Collinsa1c12042019-05-23 14:00:28 -07001136 bool erase_scratch;
Fabio Utzigb0f04732019-07-31 09:49:19 -03001137 uint8_t image_index;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001138 int rc;
1139
1140 /* Calculate offset from start of image area. */
David Vincze2d736ad2019-02-18 11:50:22 +01001141 img_off = boot_img_sector_off(&boot_data, BOOT_PRIMARY_SLOT, idx);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001142
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001143 copy_sz = sz;
Christopher Collins2adef702019-05-22 14:37:31 -07001144 trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(&boot_data));
Fabio Utzig9678c972017-05-23 11:28:56 -04001145
Fabio Utzig2bd980a2018-11-26 10:38:17 -02001146 /* sz in this function is always sized on a multiple of the sector size.
1147 * The check against the start offset of the last sector
Fabio Utzig9678c972017-05-23 11:28:56 -04001148 * is to determine if we're swapping the last sector. The last sector
1149 * needs special handling because it's where the trailer lives. If we're
1150 * copying it, we need to use scratch to write the trailer temporarily.
1151 *
1152 * NOTE: `use_scratch` is a temporary flag (never written to flash) which
1153 * controls if special handling is needed (swapping last sector).
1154 */
David Vincze2d736ad2019-02-18 11:50:22 +01001155 last_sector = boot_img_num_sectors(&boot_data, BOOT_PRIMARY_SLOT) - 1;
David Vinczeba3bd602019-06-17 16:01:43 +02001156 if ((img_off + sz) >
1157 boot_img_sector_off(&boot_data, BOOT_PRIMARY_SLOT, last_sector)) {
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001158 copy_sz -= trailer_sz;
1159 }
1160
Fabio Utzig39000012018-07-30 12:40:20 -03001161 bs->use_scratch = (bs->idx == BOOT_STATUS_IDX_0 && copy_sz != sz);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001162
Fabio Utzigb0f04732019-07-31 09:49:19 -03001163 image_index = BOOT_CURR_IMG(&boot_data);
1164
1165 rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index),
1166 &fap_primary_slot);
Fabio Utzigba829042018-09-18 08:29:34 -03001167 assert (rc == 0);
1168
Fabio Utzigb0f04732019-07-31 09:49:19 -03001169 rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY(image_index),
1170 &fap_secondary_slot);
Fabio Utzigba829042018-09-18 08:29:34 -03001171 assert (rc == 0);
1172
1173 rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH, &fap_scratch);
1174 assert (rc == 0);
1175
Fabio Utzig39000012018-07-30 12:40:20 -03001176 if (bs->state == BOOT_STATUS_STATE_0) {
Christopher Collins2c88e692019-05-22 15:10:14 -07001177 BOOT_LOG_DBG("erasing scratch area");
Christopher Collinsa1c12042019-05-23 14:00:28 -07001178 rc = boot_erase_sector(fap_scratch, 0, fap_scratch->fa_size);
Christopher Collins4772ac42017-02-27 20:08:01 -08001179 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001180
Fabio Utzig39000012018-07-30 12:40:20 -03001181 if (bs->idx == BOOT_STATUS_IDX_0) {
Christopher Collinsa1c12042019-05-23 14:00:28 -07001182 /* Write a trailer to the scratch area, even if we don't need the
1183 * scratch area for status. We need a temporary place to store the
1184 * `swap-type` while we erase the primary trailer.
1185 */
1186 rc = boot_status_init(fap_scratch, bs);
1187 assert(rc == 0);
1188
1189 if (!bs->use_scratch) {
1190 /* Prepare the primary status area... here it is known that the
1191 * last sector is not being used by the image data so it's safe
1192 * to erase.
Fabio Utzig2473ac02017-05-02 12:45:02 -03001193 */
David Vincze2d736ad2019-02-18 11:50:22 +01001194 rc = boot_erase_trailer_sectors(fap_primary_slot);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001195 assert(rc == 0);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001196
Christopher Collinsa1c12042019-05-23 14:00:28 -07001197 rc = boot_status_init(fap_primary_slot, bs);
1198 assert(rc == 0);
1199
1200 /* Erase the temporary trailer from the scratch area. */
1201 rc = boot_erase_sector(fap_scratch, 0, fap_scratch->fa_size);
1202 assert(rc == 0);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001203 }
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001204 }
1205
Christopher Collinsa1c12042019-05-23 14:00:28 -07001206 rc = boot_copy_sector(fap_secondary_slot, fap_scratch,
1207 img_off, 0, copy_sz);
1208 assert(rc == 0);
1209
Fabio Utzig39000012018-07-30 12:40:20 -03001210 bs->state = BOOT_STATUS_STATE_1;
Christopher Collins4772ac42017-02-27 20:08:01 -08001211 rc = boot_write_status(bs);
Fabio Utziga0e1cce2017-11-23 20:04:01 -02001212 BOOT_STATUS_ASSERT(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001213 }
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001214
Fabio Utzig39000012018-07-30 12:40:20 -03001215 if (bs->state == BOOT_STATUS_STATE_1) {
David Vincze2d736ad2019-02-18 11:50:22 +01001216 rc = boot_erase_sector(fap_secondary_slot, img_off, sz);
Christopher Collins4772ac42017-02-27 20:08:01 -08001217 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001218
David Vincze2d736ad2019-02-18 11:50:22 +01001219 rc = boot_copy_sector(fap_primary_slot, fap_secondary_slot,
1220 img_off, img_off, copy_sz);
Christopher Collins4772ac42017-02-27 20:08:01 -08001221 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001222
Fabio Utzig39000012018-07-30 12:40:20 -03001223 if (bs->idx == BOOT_STATUS_IDX_0 && !bs->use_scratch) {
Fabio Utzig2473ac02017-05-02 12:45:02 -03001224 /* If not all sectors of the slot are being swapped,
David Vincze2d736ad2019-02-18 11:50:22 +01001225 * guarantee here that only the primary slot will have the state.
Fabio Utzig2473ac02017-05-02 12:45:02 -03001226 */
David Vincze2d736ad2019-02-18 11:50:22 +01001227 rc = boot_erase_trailer_sectors(fap_secondary_slot);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001228 assert(rc == 0);
1229 }
1230
Fabio Utzig39000012018-07-30 12:40:20 -03001231 bs->state = BOOT_STATUS_STATE_2;
Christopher Collins4772ac42017-02-27 20:08:01 -08001232 rc = boot_write_status(bs);
Fabio Utziga0e1cce2017-11-23 20:04:01 -02001233 BOOT_STATUS_ASSERT(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001234 }
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001235
Fabio Utzig39000012018-07-30 12:40:20 -03001236 if (bs->state == BOOT_STATUS_STATE_2) {
David Vincze2d736ad2019-02-18 11:50:22 +01001237 rc = boot_erase_sector(fap_primary_slot, img_off, sz);
Christopher Collins4772ac42017-02-27 20:08:01 -08001238 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001239
Christopher Collinsa1c12042019-05-23 14:00:28 -07001240 /* NOTE: If this is the final sector, we exclude the image trailer from
1241 * this copy (copy_sz was truncated earlier).
1242 */
David Vincze2d736ad2019-02-18 11:50:22 +01001243 rc = boot_copy_sector(fap_scratch, fap_primary_slot,
1244 0, img_off, copy_sz);
Christopher Collins4772ac42017-02-27 20:08:01 -08001245 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001246
Fabio Utzig94d998c2017-05-22 11:02:41 -04001247 if (bs->use_scratch) {
Fabio Utzigba829042018-09-18 08:29:34 -03001248 scratch_trailer_off = boot_status_off(fap_scratch);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001249
1250 /* copy current status that is being maintained in scratch */
David Vincze2d736ad2019-02-18 11:50:22 +01001251 rc = boot_copy_sector(fap_scratch, fap_primary_slot,
1252 scratch_trailer_off, img_off + copy_sz,
Marti Bolivare10a7392017-06-14 16:20:07 -04001253 BOOT_STATUS_STATE_COUNT * BOOT_WRITE_SZ(&boot_data));
Fabio Utziga0e1cce2017-11-23 20:04:01 -02001254 BOOT_STATUS_ASSERT(rc == 0);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001255
Fabio Utzig2473ac02017-05-02 12:45:02 -03001256 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SCRATCH,
1257 &swap_state);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001258 assert(rc == 0);
1259
Fabio Utzigde8a38a2017-05-23 11:15:01 -04001260 if (swap_state.image_ok == BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +01001261 rc = boot_write_image_ok(fap_primary_slot);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001262 assert(rc == 0);
1263 }
1264
Christopher Collinsa1c12042019-05-23 14:00:28 -07001265 if (swap_state.swap_type != BOOT_SWAP_TYPE_NONE) {
David Vinczee2453472019-06-17 12:31:59 +02001266 rc = boot_write_swap_info(fap_primary_slot,
Fabio Utzigb0f04732019-07-31 09:49:19 -03001267 swap_state.swap_type, image_index);
Christopher Collinsa1c12042019-05-23 14:00:28 -07001268 assert(rc == 0);
1269 }
1270
David Vincze2d736ad2019-02-18 11:50:22 +01001271 rc = boot_write_swap_size(fap_primary_slot, bs->swap_size);
Fabio Utzig46490722017-09-04 15:34:32 -03001272 assert(rc == 0);
1273
Fabio Utzigba829042018-09-18 08:29:34 -03001274#ifdef MCUBOOT_ENC_IMAGES
David Vincze2d736ad2019-02-18 11:50:22 +01001275 rc = boot_write_enc_key(fap_primary_slot, 0, bs->enckey[0]);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001276 assert(rc == 0);
1277
David Vincze2d736ad2019-02-18 11:50:22 +01001278 rc = boot_write_enc_key(fap_primary_slot, 1, bs->enckey[1]);
Fabio Utzigba829042018-09-18 08:29:34 -03001279 assert(rc == 0);
1280#endif
David Vincze2d736ad2019-02-18 11:50:22 +01001281 rc = boot_write_magic(fap_primary_slot);
Fabio Utzigba829042018-09-18 08:29:34 -03001282 assert(rc == 0);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001283 }
1284
Christopher Collinsa1c12042019-05-23 14:00:28 -07001285 /* If we wrote a trailer to the scratch area, erase it after we persist
1286 * a trailer to the primary slot. We do this to prevent mcuboot from
1287 * reading a stale status from the scratch area in case of immediate
1288 * reset.
1289 */
1290 erase_scratch = bs->use_scratch;
1291 bs->use_scratch = 0;
1292
Christopher Collins92ea77f2016-12-12 15:59:26 -08001293 bs->idx++;
Fabio Utzig39000012018-07-30 12:40:20 -03001294 bs->state = BOOT_STATUS_STATE_0;
Christopher Collins4772ac42017-02-27 20:08:01 -08001295 rc = boot_write_status(bs);
Fabio Utziga0e1cce2017-11-23 20:04:01 -02001296 BOOT_STATUS_ASSERT(rc == 0);
Christopher Collinsa1c12042019-05-23 14:00:28 -07001297
1298 if (erase_scratch) {
1299 rc = boot_erase_sector(fap_scratch, 0, sz);
1300 assert(rc == 0);
1301 }
Christopher Collins92ea77f2016-12-12 15:59:26 -08001302 }
Fabio Utzigba829042018-09-18 08:29:34 -03001303
David Vincze2d736ad2019-02-18 11:50:22 +01001304 flash_area_close(fap_primary_slot);
1305 flash_area_close(fap_secondary_slot);
Fabio Utzigba829042018-09-18 08:29:34 -03001306 flash_area_close(fap_scratch);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001307}
Fabio Utzig3488eef2017-06-12 10:25:43 -03001308#endif /* !MCUBOOT_OVERWRITE_ONLY */
Christopher Collins92ea77f2016-12-12 15:59:26 -08001309
1310/**
David Vincze2d736ad2019-02-18 11:50:22 +01001311 * Overwrite primary slot with the image contained in the secondary slot.
1312 * If a prior copy operation was interrupted by a system reset, this function
1313 * redos the copy.
Christopher Collins92ea77f2016-12-12 15:59:26 -08001314 *
1315 * @param bs The current boot status. This function reads
1316 * this struct to determine if it is resuming
1317 * an interrupted swap operation. This
1318 * function writes the updated status to this
1319 * function on return.
1320 *
1321 * @return 0 on success; nonzero on failure.
1322 */
Fabio Utzig338a19f2018-12-03 08:37:08 -02001323#if defined(MCUBOOT_OVERWRITE_ONLY) || defined(MCUBOOT_BOOTSTRAP)
David Brown17609d82017-05-05 09:41:34 -06001324static int
1325boot_copy_image(struct boot_status *bs)
1326{
Marti Bolivard3269fd2017-06-12 16:31:12 -04001327 size_t sect_count;
1328 size_t sect;
David Brown17609d82017-05-05 09:41:34 -06001329 int rc;
Fabio Utzig13d9e352017-10-05 20:32:31 -03001330 size_t size;
Marti Bolivard3269fd2017-06-12 16:31:12 -04001331 size_t this_size;
Fabio Utzig13d9e352017-10-05 20:32:31 -03001332 size_t last_sector;
David Vincze2d736ad2019-02-18 11:50:22 +01001333 const struct flash_area *fap_primary_slot;
1334 const struct flash_area *fap_secondary_slot;
Fabio Utzigb0f04732019-07-31 09:49:19 -03001335 uint8_t image_index;
David Vincze2d736ad2019-02-18 11:50:22 +01001336
Fabio Utzigaaf767c2017-12-05 10:22:46 -02001337 (void)bs;
1338
Fabio Utzig13d9e352017-10-05 20:32:31 -03001339#if defined(MCUBOOT_OVERWRITE_ONLY_FAST)
1340 uint32_t src_size = 0;
David Vincze2d736ad2019-02-18 11:50:22 +01001341 rc = boot_read_image_size(BOOT_SECONDARY_SLOT,
1342 boot_img_hdr(&boot_data, BOOT_SECONDARY_SLOT),
1343 &src_size);
Fabio Utzig13d9e352017-10-05 20:32:31 -03001344 assert(rc == 0);
1345#endif
David Brown17609d82017-05-05 09:41:34 -06001346
David Vincze2d736ad2019-02-18 11:50:22 +01001347 BOOT_LOG_INF("Image upgrade secondary slot -> primary slot");
1348 BOOT_LOG_INF("Erasing the primary slot");
David Brown17609d82017-05-05 09:41:34 -06001349
Fabio Utzigb0f04732019-07-31 09:49:19 -03001350 image_index = BOOT_CURR_IMG(state);
1351
1352 rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index),
1353 &fap_primary_slot);
Fabio Utzigba829042018-09-18 08:29:34 -03001354 assert (rc == 0);
1355
Fabio Utzigb0f04732019-07-31 09:49:19 -03001356 rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY(image_index),
1357 &fap_secondary_slot);
Fabio Utzigba829042018-09-18 08:29:34 -03001358 assert (rc == 0);
1359
David Vincze2d736ad2019-02-18 11:50:22 +01001360 sect_count = boot_img_num_sectors(&boot_data, BOOT_PRIMARY_SLOT);
Fabio Utzig13d9e352017-10-05 20:32:31 -03001361 for (sect = 0, size = 0; sect < sect_count; sect++) {
David Vincze2d736ad2019-02-18 11:50:22 +01001362 this_size = boot_img_sector_size(&boot_data, BOOT_PRIMARY_SLOT, sect);
1363 rc = boot_erase_sector(fap_primary_slot, size, this_size);
David Brown17609d82017-05-05 09:41:34 -06001364 assert(rc == 0);
1365
1366 size += this_size;
Fabio Utzig13d9e352017-10-05 20:32:31 -03001367
1368#if defined(MCUBOOT_OVERWRITE_ONLY_FAST)
1369 if (size >= src_size) {
1370 break;
1371 }
1372#endif
David Brown17609d82017-05-05 09:41:34 -06001373 }
1374
Fabio Utzigba829042018-09-18 08:29:34 -03001375#ifdef MCUBOOT_ENC_IMAGES
David Vincze2d736ad2019-02-18 11:50:22 +01001376 if (IS_ENCRYPTED(boot_img_hdr(&boot_data, BOOT_SECONDARY_SLOT))) {
Fabio Utzigb0f04732019-07-31 09:49:19 -03001377 rc = boot_enc_load(image_index,
1378 boot_img_hdr(&boot_data, BOOT_SECONDARY_SLOT),
1379 fap_secondary_slot, bs->enckey[1]);
David Vincze2d736ad2019-02-18 11:50:22 +01001380
Fabio Utzigba829042018-09-18 08:29:34 -03001381 if (rc < 0) {
1382 return BOOT_EBADIMAGE;
1383 }
Fabio Utzige641ea52018-12-03 10:37:53 -02001384 if (rc == 0 && boot_enc_set_key(1, bs->enckey[1])) {
Fabio Utzigba829042018-09-18 08:29:34 -03001385 return BOOT_EBADIMAGE;
1386 }
1387 }
1388#endif
1389
David Vincze2d736ad2019-02-18 11:50:22 +01001390 BOOT_LOG_INF("Copying the secondary slot to the primary slot: 0x%zx bytes",
1391 size);
1392 rc = boot_copy_sector(fap_secondary_slot, fap_primary_slot, 0, 0, size);
David Brown17609d82017-05-05 09:41:34 -06001393
Fabio Utzig13d9e352017-10-05 20:32:31 -03001394 /*
1395 * Erases header and trailer. The trailer is erased because when a new
1396 * image is written without a trailer as is the case when using newt, the
1397 * trailer that was left might trigger a new upgrade.
1398 */
Christopher Collins2c88e692019-05-22 15:10:14 -07001399 BOOT_LOG_DBG("erasing secondary header");
David Vincze2d736ad2019-02-18 11:50:22 +01001400 rc = boot_erase_sector(fap_secondary_slot,
1401 boot_img_sector_off(&boot_data,
1402 BOOT_SECONDARY_SLOT, 0),
1403 boot_img_sector_size(&boot_data,
1404 BOOT_SECONDARY_SLOT, 0));
David Brown17609d82017-05-05 09:41:34 -06001405 assert(rc == 0);
David Vincze2d736ad2019-02-18 11:50:22 +01001406 last_sector = boot_img_num_sectors(&boot_data, BOOT_SECONDARY_SLOT) - 1;
Christopher Collins2c88e692019-05-22 15:10:14 -07001407 BOOT_LOG_DBG("erasing secondary trailer");
David Vincze2d736ad2019-02-18 11:50:22 +01001408 rc = boot_erase_sector(fap_secondary_slot,
1409 boot_img_sector_off(&boot_data,
1410 BOOT_SECONDARY_SLOT, last_sector),
1411 boot_img_sector_size(&boot_data,
1412 BOOT_SECONDARY_SLOT, last_sector));
Fabio Utzig13d9e352017-10-05 20:32:31 -03001413 assert(rc == 0);
1414
David Vincze2d736ad2019-02-18 11:50:22 +01001415 flash_area_close(fap_primary_slot);
1416 flash_area_close(fap_secondary_slot);
Fabio Utzigba829042018-09-18 08:29:34 -03001417
David Vincze2d736ad2019-02-18 11:50:22 +01001418 /* TODO: Perhaps verify the primary slot's signature again? */
David Brown17609d82017-05-05 09:41:34 -06001419
1420 return 0;
1421}
Fabio Utzig338a19f2018-12-03 08:37:08 -02001422#endif
Fabio Utzigba829042018-09-18 08:29:34 -03001423
Christopher Collinsa1c12042019-05-23 14:00:28 -07001424#if !defined(MCUBOOT_OVERWRITE_ONLY)
Fabio Utzigba829042018-09-18 08:29:34 -03001425/**
1426 * Swaps the two images in flash. If a prior copy operation was interrupted
1427 * by a system reset, this function completes that operation.
1428 *
1429 * @param bs The current boot status. This function reads
1430 * this struct to determine if it is resuming
1431 * an interrupted swap operation. This
1432 * function writes the updated status to this
1433 * function on return.
1434 *
1435 * @return 0 on success; nonzero on failure.
1436 */
Christopher Collins92ea77f2016-12-12 15:59:26 -08001437static int
Fabio Utzig338a19f2018-12-03 08:37:08 -02001438boot_swap_image(struct boot_status *bs)
Christopher Collins92ea77f2016-12-12 15:59:26 -08001439{
1440 uint32_t sz;
1441 int first_sector_idx;
1442 int last_sector_idx;
David Vincze2d736ad2019-02-18 11:50:22 +01001443 int last_idx_secondary_slot;
Fabio Utzigcd5774b2017-11-29 10:18:26 -02001444 uint32_t swap_idx;
Fabio Utzig2473ac02017-05-02 12:45:02 -03001445 struct image_header *hdr;
Fabio Utzigba829042018-09-18 08:29:34 -03001446#ifdef MCUBOOT_ENC_IMAGES
1447 const struct flash_area *fap;
1448 uint8_t slot;
1449 uint8_t i;
Fabio Utzigba829042018-09-18 08:29:34 -03001450#endif
Fabio Utzig2473ac02017-05-02 12:45:02 -03001451 uint32_t size;
1452 uint32_t copy_size;
David Vincze2d736ad2019-02-18 11:50:22 +01001453 uint32_t primary_slot_size;
1454 uint32_t secondary_slot_size;
Fabio Utzigb0f04732019-07-31 09:49:19 -03001455 uint8_t image_index;
Fabio Utzig2473ac02017-05-02 12:45:02 -03001456 int rc;
1457
1458 /* FIXME: just do this if asked by user? */
1459
1460 size = copy_size = 0;
Fabio Utzigb0f04732019-07-31 09:49:19 -03001461 image_index = BOOT_CURR_IMG(&boot_data);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001462
Fabio Utzig39000012018-07-30 12:40:20 -03001463 if (bs->idx == BOOT_STATUS_IDX_0 && bs->state == BOOT_STATUS_STATE_0) {
Fabio Utzig46490722017-09-04 15:34:32 -03001464 /*
1465 * No swap ever happened, so need to find the largest image which
1466 * will be used to determine the amount of sectors to swap.
1467 */
David Vincze2d736ad2019-02-18 11:50:22 +01001468 hdr = boot_img_hdr(&boot_data, BOOT_PRIMARY_SLOT);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001469 if (hdr->ih_magic == IMAGE_MAGIC) {
David Vincze2d736ad2019-02-18 11:50:22 +01001470 rc = boot_read_image_size(BOOT_PRIMARY_SLOT, hdr, &copy_size);
David Brownf5b33d82017-09-01 10:58:27 -06001471 assert(rc == 0);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001472 }
Fabio Utzig2473ac02017-05-02 12:45:02 -03001473
Fabio Utzigba829042018-09-18 08:29:34 -03001474#ifdef MCUBOOT_ENC_IMAGES
Fabio Utzig2fc80df2018-12-14 06:47:38 -02001475 if (IS_ENCRYPTED(hdr)) {
David Vincze2d736ad2019-02-18 11:50:22 +01001476 fap = BOOT_IMG_AREA(&boot_data, BOOT_PRIMARY_SLOT);
Fabio Utzigb0f04732019-07-31 09:49:19 -03001477 rc = boot_enc_load(image_index, hdr, fap, bs->enckey[0]);
Fabio Utzigba829042018-09-18 08:29:34 -03001478 assert(rc >= 0);
1479
1480 if (rc == 0) {
1481 rc = boot_enc_set_key(0, bs->enckey[0]);
1482 assert(rc == 0);
1483 } else {
1484 rc = 0;
1485 }
1486 } else {
1487 memset(bs->enckey[0], 0xff, BOOT_ENC_KEY_SIZE);
1488 }
1489#endif
1490
David Vincze2d736ad2019-02-18 11:50:22 +01001491 hdr = boot_img_hdr(&boot_data, BOOT_SECONDARY_SLOT);
Fabio Utzig46490722017-09-04 15:34:32 -03001492 if (hdr->ih_magic == IMAGE_MAGIC) {
David Vincze2d736ad2019-02-18 11:50:22 +01001493 rc = boot_read_image_size(BOOT_SECONDARY_SLOT, hdr, &size);
Fabio Utzig46490722017-09-04 15:34:32 -03001494 assert(rc == 0);
1495 }
1496
Fabio Utzigba829042018-09-18 08:29:34 -03001497#ifdef MCUBOOT_ENC_IMAGES
David Vincze2d736ad2019-02-18 11:50:22 +01001498 hdr = boot_img_hdr(&boot_data, BOOT_SECONDARY_SLOT);
Fabio Utzig2fc80df2018-12-14 06:47:38 -02001499 if (IS_ENCRYPTED(hdr)) {
David Vincze2d736ad2019-02-18 11:50:22 +01001500 fap = BOOT_IMG_AREA(&boot_data, BOOT_SECONDARY_SLOT);
Fabio Utzigb0f04732019-07-31 09:49:19 -03001501 rc = boot_enc_load(image_index, hdr, fap, bs->enckey[1]);
Fabio Utzigba829042018-09-18 08:29:34 -03001502 assert(rc >= 0);
1503
1504 if (rc == 0) {
1505 rc = boot_enc_set_key(1, bs->enckey[1]);
1506 assert(rc == 0);
1507 } else {
1508 rc = 0;
1509 }
1510 } else {
1511 memset(bs->enckey[1], 0xff, BOOT_ENC_KEY_SIZE);
1512 }
1513#endif
1514
Fabio Utzig46490722017-09-04 15:34:32 -03001515 if (size > copy_size) {
1516 copy_size = size;
1517 }
1518
1519 bs->swap_size = copy_size;
1520 } else {
1521 /*
1522 * If a swap was under way, the swap_size should already be present
1523 * in the trailer...
1524 */
Fabio Utzigb0f04732019-07-31 09:49:19 -03001525 rc = boot_read_swap_size(image_index, &bs->swap_size);
Fabio Utzig46490722017-09-04 15:34:32 -03001526 assert(rc == 0);
1527
1528 copy_size = bs->swap_size;
Fabio Utzigba829042018-09-18 08:29:34 -03001529
1530#ifdef MCUBOOT_ENC_IMAGES
1531 for (slot = 0; slot <= 1; slot++) {
Fabio Utzigb0f04732019-07-31 09:49:19 -03001532 rc = boot_read_enc_key(image_index, slot, bs->enckey[slot]);
Fabio Utzigba829042018-09-18 08:29:34 -03001533 assert(rc == 0);
1534
1535 for (i = 0; i < BOOT_ENC_KEY_SIZE; i++) {
Fabio Utzig1c7d9592018-12-03 10:35:56 -02001536 if (bs->enckey[slot][i] != 0xff) {
Fabio Utzigba829042018-09-18 08:29:34 -03001537 break;
1538 }
1539 }
1540
1541 if (i != BOOT_ENC_KEY_SIZE) {
1542 boot_enc_set_key(slot, bs->enckey[slot]);
1543 }
1544 }
1545#endif
Fabio Utzig2473ac02017-05-02 12:45:02 -03001546 }
1547
David Vincze2d736ad2019-02-18 11:50:22 +01001548 primary_slot_size = 0;
1549 secondary_slot_size = 0;
Fabio Utzig2473ac02017-05-02 12:45:02 -03001550 last_sector_idx = 0;
David Vincze2d736ad2019-02-18 11:50:22 +01001551 last_idx_secondary_slot = 0;
Fabio Utzig2bd980a2018-11-26 10:38:17 -02001552
1553 /*
1554 * Knowing the size of the largest image between both slots, here we
David Vincze2d736ad2019-02-18 11:50:22 +01001555 * find what is the last sector in the primary slot that needs swapping.
1556 * Since we already know that both slots are compatible, the secondary
1557 * slot's last sector is not really required after this check is finished.
Fabio Utzig2bd980a2018-11-26 10:38:17 -02001558 */
Fabio Utzig2473ac02017-05-02 12:45:02 -03001559 while (1) {
David Vincze2d736ad2019-02-18 11:50:22 +01001560 if ((primary_slot_size < copy_size) ||
1561 (primary_slot_size < secondary_slot_size)) {
1562 primary_slot_size += boot_img_sector_size(&boot_data,
1563 BOOT_PRIMARY_SLOT,
1564 last_sector_idx);
Fabio Utzig2bd980a2018-11-26 10:38:17 -02001565 }
David Vincze2d736ad2019-02-18 11:50:22 +01001566 if ((secondary_slot_size < copy_size) ||
1567 (secondary_slot_size < primary_slot_size)) {
1568 secondary_slot_size += boot_img_sector_size(&boot_data,
1569 BOOT_SECONDARY_SLOT,
1570 last_idx_secondary_slot);
Fabio Utzig2bd980a2018-11-26 10:38:17 -02001571 }
David Vincze2d736ad2019-02-18 11:50:22 +01001572 if (primary_slot_size >= copy_size &&
1573 secondary_slot_size >= copy_size &&
1574 primary_slot_size == secondary_slot_size) {
Fabio Utzig2473ac02017-05-02 12:45:02 -03001575 break;
1576 }
1577 last_sector_idx++;
David Vincze2d736ad2019-02-18 11:50:22 +01001578 last_idx_secondary_slot++;
Fabio Utzig2473ac02017-05-02 12:45:02 -03001579 }
Christopher Collins92ea77f2016-12-12 15:59:26 -08001580
1581 swap_idx = 0;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001582 while (last_sector_idx >= 0) {
1583 sz = boot_copy_sz(last_sector_idx, &first_sector_idx);
Fabio Utzig39000012018-07-30 12:40:20 -03001584 if (swap_idx >= (bs->idx - BOOT_STATUS_IDX_0)) {
Christopher Collins92ea77f2016-12-12 15:59:26 -08001585 boot_swap_sectors(first_sector_idx, sz, bs);
1586 }
1587
1588 last_sector_idx = first_sector_idx - 1;
1589 swap_idx++;
1590 }
1591
David Vincze2d736ad2019-02-18 11:50:22 +01001592#ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT
Fabio Utziga0e1cce2017-11-23 20:04:01 -02001593 if (boot_status_fails > 0) {
Christopher Collins2c88e692019-05-22 15:10:14 -07001594 BOOT_LOG_WRN("%d status write fails performing the swap",
1595 boot_status_fails);
Fabio Utziga0e1cce2017-11-23 20:04:01 -02001596 }
1597#endif
1598
Christopher Collins92ea77f2016-12-12 15:59:26 -08001599 return 0;
1600}
David Brown17609d82017-05-05 09:41:34 -06001601#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -08001602
1603/**
David Vincze2d736ad2019-02-18 11:50:22 +01001604 * Marks the image in the primary slot as fully copied.
Christopher Collins92ea77f2016-12-12 15:59:26 -08001605 */
Fabio Utzig8d0e5882017-09-13 17:32:44 -03001606#ifndef MCUBOOT_OVERWRITE_ONLY
Christopher Collins92ea77f2016-12-12 15:59:26 -08001607static int
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03001608boot_set_copy_done(void)
Christopher Collins92ea77f2016-12-12 15:59:26 -08001609{
1610 const struct flash_area *fap;
1611 int rc;
1612
Fabio Utzigb0f04732019-07-31 09:49:19 -03001613 rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index),
1614 &fap);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001615 if (rc != 0) {
1616 return BOOT_EFLASH;
1617 }
1618
1619 rc = boot_write_copy_done(fap);
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03001620 flash_area_close(fap);
1621 return rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001622}
Fabio Utzig8d0e5882017-09-13 17:32:44 -03001623#endif /* !MCUBOOT_OVERWRITE_ONLY */
Christopher Collins92ea77f2016-12-12 15:59:26 -08001624
1625/**
David Vincze2d736ad2019-02-18 11:50:22 +01001626 * Marks a reverted image in the primary slot as confirmed. This is necessary to
1627 * ensure the status bytes from the image revert operation don't get processed
1628 * on a subsequent boot.
Fabio Utzig1e56fcc2017-07-17 15:39:14 -03001629 *
1630 * NOTE: image_ok is tested before writing because if there's a valid permanent
David Vincze2d736ad2019-02-18 11:50:22 +01001631 * image installed on the primary slot and the new image to be upgrade to has a
1632 * bad sig, image_ok would be overwritten.
Christopher Collins92ea77f2016-12-12 15:59:26 -08001633 */
Fabio Utzig8d0e5882017-09-13 17:32:44 -03001634#ifndef MCUBOOT_OVERWRITE_ONLY
Christopher Collins92ea77f2016-12-12 15:59:26 -08001635static int
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03001636boot_set_image_ok(void)
Christopher Collins92ea77f2016-12-12 15:59:26 -08001637{
1638 const struct flash_area *fap;
Fabio Utzig1e56fcc2017-07-17 15:39:14 -03001639 struct boot_swap_state state;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001640 int rc;
1641
Fabio Utzigb0f04732019-07-31 09:49:19 -03001642 rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index),
1643 &fap);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001644 if (rc != 0) {
1645 return BOOT_EFLASH;
1646 }
1647
Fabio Utzig1e56fcc2017-07-17 15:39:14 -03001648 rc = boot_read_swap_state(fap, &state);
1649 if (rc != 0) {
1650 rc = BOOT_EFLASH;
1651 goto out;
1652 }
1653
1654 if (state.image_ok == BOOT_FLAG_UNSET) {
1655 rc = boot_write_image_ok(fap);
1656 }
1657
1658out:
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03001659 flash_area_close(fap);
1660 return rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001661}
Fabio Utzig8d0e5882017-09-13 17:32:44 -03001662#endif /* !MCUBOOT_OVERWRITE_ONLY */
Christopher Collins92ea77f2016-12-12 15:59:26 -08001663
David Vinczee32483f2019-06-13 10:46:24 +02001664#if (BOOT_IMAGE_NUMBER > 1)
1665/**
1666 * Check the image dependency whether it is satisfied and modify
1667 * the swap type if necessary.
1668 *
1669 * @param dep Image dependency which has to be verified.
1670 *
1671 * @return 0 on success; nonzero on failure.
1672 */
1673static int
1674boot_verify_single_dependency(struct image_dependency *dep)
1675{
1676 struct image_version *dep_version;
1677 size_t dep_slot;
1678 int rc;
1679
1680 /* Determine the source of the image which is the subject of
1681 * the dependency and get it's version. */
1682 dep_slot = (boot_data.swap_type[dep->image_id] != BOOT_SWAP_TYPE_NONE) ?
1683 BOOT_SECONDARY_SLOT : BOOT_PRIMARY_SLOT;
1684 dep_version = &boot_data.imgs[dep->image_id][dep_slot].hdr.ih_ver;
1685
1686 rc = boot_is_version_sufficient(&dep->image_min_version, dep_version);
1687 if (rc != 0) {
1688 /* Dependency not satisfied.
1689 * Modify the swap type to decrease the version number of the image
1690 * (which will be located in the primary slot after the boot process),
1691 * consequently the number of unsatisfied dependencies will be
1692 * decreased or remain the same.
1693 */
1694 switch (BOOT_SWAP_TYPE(&boot_data)) {
1695 case BOOT_SWAP_TYPE_TEST:
1696 case BOOT_SWAP_TYPE_PERM:
1697 BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_NONE;
1698 break;
1699 case BOOT_SWAP_TYPE_NONE:
1700 BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_REVERT;
1701 break;
1702 default:
1703 break;
1704 }
1705 }
1706
1707 return rc;
1708}
1709
1710/**
1711 * Read all dependency TLVs of an image from the flash and verify
1712 * one after another to see if they are all satisfied.
1713 *
1714 * @param slot Image slot number.
1715 *
1716 * @return 0 on success; nonzero on failure.
1717 */
1718static int
1719boot_verify_all_dependency(uint32_t slot)
1720{
1721 const struct flash_area *fap;
1722 struct image_header *hdr;
1723 struct image_tlv_info info;
1724 struct image_tlv tlv;
1725 struct image_dependency dep;
1726 uint32_t off;
1727 uint32_t end;
1728 bool dep_tlvs_found = false;
Fabio Utzigb0f04732019-07-31 09:49:19 -03001729 int area_id;
David Vinczee32483f2019-06-13 10:46:24 +02001730 int rc;
1731
Fabio Utzigb0f04732019-07-31 09:49:19 -03001732 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(&boot_data),
1733 slot);
1734 rc = flash_area_open(area_id, &fap);
David Vinczee32483f2019-06-13 10:46:24 +02001735 if (rc != 0) {
1736 rc = BOOT_EFLASH;
1737 goto done;
1738 }
1739
1740 hdr = boot_img_hdr(&boot_data, slot);
1741 /* The TLVs come after the image. */
1742 off = hdr->ih_hdr_size + hdr->ih_img_size;
1743
1744 /* The TLV area always starts with an image_tlv_info structure. */
1745 rc = flash_area_read(fap, off, &info, sizeof(info));
1746 if (rc != 0) {
1747 rc = BOOT_EFLASH;
1748 goto done;
1749 }
1750
1751 if (info.it_magic != IMAGE_TLV_INFO_MAGIC) {
1752 rc = BOOT_EBADIMAGE;
1753 goto done;
1754 }
1755 end = off + info.it_tlv_tot;
1756 off += sizeof(info);
1757
1758 /* Traverse through all of the TLVs to find the dependency TLVs. */
1759 for (; off < end; off += sizeof(tlv) + tlv.it_len) {
1760 rc = flash_area_read(fap, off, &tlv, sizeof(tlv));
1761 if (rc != 0) {
1762 rc = BOOT_EFLASH;
1763 goto done;
1764 }
1765
1766 if (tlv.it_type == IMAGE_TLV_DEPENDENCY) {
1767 if (!dep_tlvs_found) {
1768 dep_tlvs_found = true;
1769 }
1770
1771 if (tlv.it_len != sizeof(dep)) {
1772 rc = BOOT_EBADIMAGE;
1773 goto done;
1774 }
1775
1776 rc = flash_area_read(fap, off + sizeof(tlv), &dep, tlv.it_len);
1777 if (rc != 0) {
1778 rc = BOOT_EFLASH;
1779 goto done;
1780 }
1781
1782 /* Verify dependency and modify the swap type if not satisfied. */
1783 rc = boot_verify_single_dependency(&dep);
1784 if (rc != 0) {
1785 /* Dependency not satisfied. */
1786 goto done;
1787 }
1788
1789 /* Dependency satisfied, no action needed.
1790 * Continue with the next TLV entry.
1791 */
1792 } else if (dep_tlvs_found) {
1793 /* The dependency TLVs are contiguous in the TLV area. If a
1794 * dependency had already been found and the last read TLV
1795 * has a different type then there are no more dependency TLVs.
1796 * The search can be finished.
1797 */
1798 break;
1799 }
1800 }
1801
1802done:
1803 flash_area_close(fap);
1804 return rc;
1805}
1806
1807/**
1808 * Verify whether the image dependencies in the TLV area are
1809 * all satisfied and modify the swap type if necessary.
1810 *
1811 * @return 0 if all dependencies are satisfied,
1812 * nonzero otherwise.
1813 */
1814static int
1815boot_verify_single_image_dependency(void)
1816{
1817 size_t slot;
1818
1819 /* Determine the source of the dependency TLVs. Those dependencies have to
1820 * be checked which belong to the image that will be located in the primary
1821 * slot after the firmware update process.
1822 */
1823 if (BOOT_SWAP_TYPE(&boot_data) != BOOT_SWAP_TYPE_NONE &&
1824 BOOT_SWAP_TYPE(&boot_data) != BOOT_SWAP_TYPE_FAIL) {
1825 slot = BOOT_SECONDARY_SLOT;
1826 } else {
1827 slot = BOOT_PRIMARY_SLOT;
1828 }
1829
1830 return boot_verify_all_dependency(slot);
1831}
1832
1833/**
1834 * Iterate over all the images and verify whether the image dependencies in the
1835 * TLV area are all satisfied and update the related swap type if necessary.
1836 */
1837static void
1838boot_verify_all_image_dependency(void)
1839{
David Vinczee32483f2019-06-13 10:46:24 +02001840 int rc;
1841
Fabio Utzigb0f04732019-07-31 09:49:19 -03001842 BOOT_CURR_IMG(&boot_data) = 0;
1843 while (BOOT_CURR_IMG(&boot_data) < BOOT_IMAGE_NUMBER) {
David Vinczee32483f2019-06-13 10:46:24 +02001844 rc = boot_verify_single_image_dependency();
Fabio Utzigabec0732019-07-31 08:40:22 -03001845 if (rc == 0) {
David Vinczee32483f2019-06-13 10:46:24 +02001846 /* All dependencies've been satisfied, continue with next image. */
Fabio Utzigb0f04732019-07-31 09:49:19 -03001847 BOOT_CURR_IMG(&boot_data)++;
David Vinczee32483f2019-06-13 10:46:24 +02001848 } else if (rc == BOOT_EBADVERSION) {
1849 /* Dependency check needs to be restarted. */
Fabio Utzigb0f04732019-07-31 09:49:19 -03001850 BOOT_CURR_IMG(&boot_data) = 0;
David Vinczee32483f2019-06-13 10:46:24 +02001851 } else {
1852 /* Other error happened, images are inconsistent */
1853 return;
1854 }
1855 }
1856}
1857#endif /* (BOOT_IMAGE_NUMBER > 1) */
1858
Christopher Collins92ea77f2016-12-12 15:59:26 -08001859/**
David Vinczeba3bd602019-06-17 16:01:43 +02001860 * Performs a clean (not aborted) image update.
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001861 *
David Vinczeba3bd602019-06-17 16:01:43 +02001862 * @param bs The current boot status.
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001863 *
1864 * @return 0 on success; nonzero on failure.
1865 */
1866static int
David Vinczeba3bd602019-06-17 16:01:43 +02001867boot_perform_update(struct boot_status *bs)
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001868{
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001869 int rc;
1870
David Vinczeba3bd602019-06-17 16:01:43 +02001871 /* At this point there are no aborted swaps. */
1872#if defined(MCUBOOT_OVERWRITE_ONLY)
1873 rc = boot_copy_image(bs);
1874#elif defined(MCUBOOT_BOOTSTRAP)
1875 /* Check if the image update was triggered by a bad image in the
1876 * primary slot (the validity of the image in the secondary slot had
1877 * already been checked).
1878 */
1879 if (boot_check_header_erased(BOOT_PRIMARY_SLOT) == 0 ||
1880 boot_validate_slot(BOOT_PRIMARY_SLOT, bs) != 0) {
1881 rc = boot_copy_image(bs);
1882 } else {
1883 rc = boot_swap_image(bs);
1884 }
1885#else
1886 rc = boot_swap_image(bs);
1887#endif
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001888 assert(rc == 0);
David Vinczeba3bd602019-06-17 16:01:43 +02001889
1890#ifndef MCUBOOT_OVERWRITE_ONLY
1891 /* The following state needs image_ok be explicitly set after the
1892 * swap was finished to avoid a new revert.
1893 */
1894 if (BOOT_SWAP_TYPE(&boot_data) == BOOT_SWAP_TYPE_REVERT ||
1895 BOOT_SWAP_TYPE(&boot_data) == BOOT_SWAP_TYPE_PERM) {
1896 rc = boot_set_image_ok();
1897 if (rc != 0) {
1898 BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_PANIC;
1899 }
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001900 }
1901
David Vinczeba3bd602019-06-17 16:01:43 +02001902 if (BOOT_SWAP_TYPE(&boot_data) == BOOT_SWAP_TYPE_TEST ||
1903 BOOT_SWAP_TYPE(&boot_data) == BOOT_SWAP_TYPE_PERM ||
1904 BOOT_SWAP_TYPE(&boot_data) == BOOT_SWAP_TYPE_REVERT) {
1905 rc = boot_set_copy_done();
1906 if (rc != 0) {
1907 BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_PANIC;
Christopher Collinsa1c12042019-05-23 14:00:28 -07001908 }
David Vinczeba3bd602019-06-17 16:01:43 +02001909 }
1910#endif /* !MCUBOOT_OVERWRITE_ONLY */
Fabio Utzig338a19f2018-12-03 08:37:08 -02001911
David Vinczeba3bd602019-06-17 16:01:43 +02001912 return rc;
1913}
1914
1915/**
1916 * Completes a previously aborted image swap.
1917 *
1918 * @param bs The current boot status.
1919 *
1920 * @return 0 on success; nonzero on failure.
1921 */
1922#if !defined(MCUBOOT_OVERWRITE_ONLY)
1923static int
1924boot_complete_partial_swap(struct boot_status *bs)
1925{
1926 int rc;
1927
1928 /* Determine the type of swap operation being resumed from the
1929 * `swap-type` trailer field.
1930 */
1931 rc = boot_swap_image(bs);
1932 assert(rc == 0);
1933
1934 BOOT_SWAP_TYPE(&boot_data) = bs->swap_type;
1935
1936 /* The following states need image_ok be explicitly set after the
1937 * swap was finished to avoid a new revert.
1938 */
1939 if (bs->swap_type == BOOT_SWAP_TYPE_REVERT ||
1940 bs->swap_type == BOOT_SWAP_TYPE_PERM) {
1941 rc = boot_set_image_ok();
1942 if (rc != 0) {
1943 BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_PANIC;
1944 }
1945 }
1946
1947 if (bs->swap_type == BOOT_SWAP_TYPE_TEST ||
1948 bs->swap_type == BOOT_SWAP_TYPE_PERM ||
1949 bs->swap_type == BOOT_SWAP_TYPE_REVERT) {
1950 rc = boot_set_copy_done();
1951 if (rc != 0) {
1952 BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_PANIC;
1953 }
1954 }
1955
1956 if (BOOT_SWAP_TYPE(&boot_data) == BOOT_SWAP_TYPE_PANIC) {
1957 BOOT_LOG_ERR("panic!");
1958 assert(0);
1959
1960 /* Loop forever... */
1961 while (1) {}
1962 }
1963
1964 return rc;
1965}
1966#endif /* !MCUBOOT_OVERWRITE_ONLY */
1967
1968#if (BOOT_IMAGE_NUMBER > 1)
1969/**
1970 * Review the validity of previously determined swap types of other images.
1971 *
1972 * @param aborted_swap The current image upgrade is a
1973 * partial/aborted swap.
1974 */
1975static void
1976boot_review_image_swap_types(bool aborted_swap)
1977{
1978 /* In that case if we rebooted in the middle of an image upgrade process, we
1979 * must review the validity of swap types, that were previously determined
1980 * for other images. The image_ok flag had not been set before the reboot
1981 * for any of the updated images (only the copy_done flag) and thus falsely
1982 * the REVERT swap type has been determined for the previous images that had
1983 * been updated before the reboot.
1984 *
1985 * There are two separate scenarios that we have to deal with:
1986 *
1987 * 1. The reboot has happened during swapping an image:
1988 * The current image upgrade has been determined as a
1989 * partial/aborted swap.
1990 * 2. The reboot has happened between two separate image upgrades:
1991 * In this scenario we must check the swap type of the current image.
1992 * In those cases if it is NONE or REVERT we cannot certainly determine
1993 * the fact of a reboot. In a consistent state images must move in the
1994 * same direction or stay in place, e.g. in practice REVERT and TEST
1995 * swap types cannot be present at the same time. If the swap type of
1996 * the current image is either TEST, PERM or FAIL we must review the
1997 * already determined swap types of other images and set each false
1998 * REVERT swap types to NONE (these images had been successfully
1999 * updated before the system rebooted between two separate image
2000 * upgrades).
2001 */
2002
Fabio Utzigb0f04732019-07-31 09:49:19 -03002003 if (BOOT_CURR_IMG(&boot_data) == 0) {
David Vinczeba3bd602019-06-17 16:01:43 +02002004 /* Nothing to do */
2005 return;
2006 }
2007
2008 if (!aborted_swap) {
2009 if ((BOOT_SWAP_TYPE(&boot_data) == BOOT_SWAP_TYPE_NONE) ||
2010 (BOOT_SWAP_TYPE(&boot_data) == BOOT_SWAP_TYPE_REVERT)) {
2011 /* Nothing to do */
2012 return;
2013 }
2014 }
2015
Fabio Utzigb0f04732019-07-31 09:49:19 -03002016 for (uint8_t i = 0; i < BOOT_CURR_IMG(&boot_data); i++) {
David Vinczeba3bd602019-06-17 16:01:43 +02002017 if (boot_data.swap_type[i] == BOOT_SWAP_TYPE_REVERT) {
2018 boot_data.swap_type[i] = BOOT_SWAP_TYPE_NONE;
2019 }
2020 }
2021}
2022#endif
2023
2024/**
2025 * Prepare image to be updated if required.
2026 *
2027 * Prepare image to be updated if required with completing an image swap
2028 * operation if one was aborted and/or determining the type of the
2029 * swap operation. In case of any error set the swap type to NONE.
2030 *
2031 * @param bs Pointer where the read and possibly updated
2032 * boot status can be written to.
2033 */
2034static void
2035boot_prepare_image_for_update(struct boot_status *bs)
2036{
2037 int rc;
2038
2039 /* Determine the sector layout of the image slots and scratch area. */
2040 rc = boot_read_sectors();
2041 if (rc != 0) {
2042 BOOT_LOG_WRN("Failed reading sectors; BOOT_MAX_IMG_SECTORS=%d"
2043 " - too small?", BOOT_MAX_IMG_SECTORS);
2044 /* Unable to determine sector layout, continue with next image
2045 * if there is one.
2046 */
2047 BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_NONE;
2048 return;
2049 }
2050
2051 /* Attempt to read an image header from each slot. */
2052 rc = boot_read_image_headers(false);
2053 if (rc != 0) {
2054 /* Continue with next image if there is one. */
Fabio Utzigb0f04732019-07-31 09:49:19 -03002055 BOOT_LOG_WRN("Failed reading image headers; Image=%u",
2056 BOOT_CURR_IMG(&boot_data));
David Vinczeba3bd602019-06-17 16:01:43 +02002057 BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_NONE;
2058 return;
2059 }
2060
2061 /* If the current image's slots aren't compatible, no swap is possible.
2062 * Just boot into primary slot.
2063 */
2064 if (boot_slots_compatible()) {
2065
2066 rc = boot_read_status(bs);
2067 if (rc != 0) {
2068 BOOT_LOG_WRN("Failed reading boot status; Image=%u",
Fabio Utzigb0f04732019-07-31 09:49:19 -03002069 BOOT_CURR_IMG(&boot_data));
David Vinczeba3bd602019-06-17 16:01:43 +02002070 /* Continue with next image if there is one. */
2071 BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_NONE;
2072 return;
2073 }
2074
2075 /* Determine if we rebooted in the middle of an image swap
2076 * operation. If a partial swap was detected, complete it.
2077 */
2078 if (bs->idx != BOOT_STATUS_IDX_0 || bs->state != BOOT_STATUS_STATE_0) {
2079
2080#if (BOOT_IMAGE_NUMBER > 1)
2081 boot_review_image_swap_types(true);
2082#endif
2083
2084#ifdef MCUBOOT_OVERWRITE_ONLY
2085 /* Should never arrive here, overwrite-only mode has
2086 * no swap state.
2087 */
2088 assert(0);
2089#else
2090 /* Determine the type of swap operation being resumed from the
2091 * `swap-type` trailer field.
2092 */
2093 rc = boot_complete_partial_swap(bs);
2094 assert(rc == 0);
2095#endif
2096 /* Attempt to read an image header from each slot. Ensure that
2097 * image headers in slots are aligned with headers in boot_data.
2098 */
2099 rc = boot_read_image_headers(false);
2100 assert(rc == 0);
2101
2102 /* Swap has finished set to NONE */
2103 BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_NONE;
2104 } else {
2105 /* There was no partial swap, determine swap type. */
2106 if (bs->swap_type == BOOT_SWAP_TYPE_NONE) {
2107 BOOT_SWAP_TYPE(&boot_data) = boot_validated_swap_type(bs);
2108 } else if (boot_validate_slot(BOOT_SECONDARY_SLOT, bs) != 0) {
2109 BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_FAIL;
2110 } else {
2111 BOOT_SWAP_TYPE(&boot_data) = bs->swap_type;
2112 }
2113
2114#if (BOOT_IMAGE_NUMBER > 1)
2115 boot_review_image_swap_types(false);
2116#endif
2117
2118#ifdef MCUBOOT_BOOTSTRAP
2119 if (BOOT_SWAP_TYPE(&boot_data) == BOOT_SWAP_TYPE_NONE) {
2120 /* Header checks are done first because they are
2121 * inexpensive. Since overwrite-only copies starting from
2122 * offset 0, if interrupted, it might leave a valid header
2123 * magic, so also run validation on the primary slot to be
2124 * sure it's not OK.
2125 */
2126 if (boot_check_header_erased(BOOT_PRIMARY_SLOT) == 0 ||
2127 boot_validate_slot(BOOT_PRIMARY_SLOT, bs) != 0) {
2128 if (boot_img_hdr(&boot_data,
2129 BOOT_SECONDARY_SLOT)->ih_magic == IMAGE_MAGIC &&
2130 boot_validate_slot(BOOT_SECONDARY_SLOT, bs) == 0)
2131 {
2132 /* Set swap type to REVERT to overwrite the primary
2133 * slot with the image contained in secondary slot
2134 * and to trigger the explicit setting of the
2135 * image_ok flag.
2136 */
2137 BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_REVERT;
2138 }
Fabio Utzig338a19f2018-12-03 08:37:08 -02002139 }
2140 }
Fabio Utzig338a19f2018-12-03 08:37:08 -02002141#endif
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08002142 }
David Vinczeba3bd602019-06-17 16:01:43 +02002143 } else {
2144 /* In that case if slots are not compatible. */
2145 BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_NONE;
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08002146 }
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08002147}
2148
2149/**
Christopher Collins92ea77f2016-12-12 15:59:26 -08002150 * Prepares the booting process. This function moves images around in flash as
2151 * appropriate, and tells you what address to boot from.
2152 *
2153 * @param rsp On success, indicates how booting should occur.
2154 *
2155 * @return 0 on success; nonzero on failure.
2156 */
2157int
2158boot_go(struct boot_rsp *rsp)
2159{
Marti Bolivar84898652017-06-13 17:20:22 -04002160 size_t slot;
David Vinczeba3bd602019-06-17 16:01:43 +02002161 struct boot_status bs;
Christopher Collins92ea77f2016-12-12 15:59:26 -08002162 int rc;
Marti Bolivarc0b47912017-06-13 17:18:09 -04002163 int fa_id;
Fabio Utzigb0f04732019-07-31 09:49:19 -03002164 int image_index;
Christopher Collins92ea77f2016-12-12 15:59:26 -08002165
2166 /* The array of slot sectors are defined here (as opposed to file scope) so
2167 * that they don't get allocated for non-boot-loader apps. This is
2168 * necessary because the gcc option "-fdata-sections" doesn't seem to have
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08002169 * any effect in older gcc versions (e.g., 4.8.4).
Christopher Collins92ea77f2016-12-12 15:59:26 -08002170 */
David Vinczeba3bd602019-06-17 16:01:43 +02002171 static boot_sector_t
2172 primary_slot_sectors[BOOT_IMAGE_NUMBER][BOOT_MAX_IMG_SECTORS];
2173 static boot_sector_t
2174 secondary_slot_sectors[BOOT_IMAGE_NUMBER][BOOT_MAX_IMG_SECTORS];
Fabio Utzig2bd980a2018-11-26 10:38:17 -02002175 static boot_sector_t scratch_sectors[BOOT_MAX_IMG_SECTORS];
Christopher Collins92ea77f2016-12-12 15:59:26 -08002176
Fabio Utzigba829042018-09-18 08:29:34 -03002177#ifdef MCUBOOT_ENC_IMAGES
2178 /* FIXME: remove this after RAM is cleared by sim */
2179 boot_enc_zeroize();
2180#endif
2181
David Vinczeba3bd602019-06-17 16:01:43 +02002182 /* Iterate over all the images. By the end of the loop the swap type has
2183 * to be determined for each image and all aborted swaps have to be
2184 * completed.
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08002185 */
Fabio Utzigb0f04732019-07-31 09:49:19 -03002186 IMAGES_ITER(BOOT_CURR_IMG(&boot_data)) {
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03002187
David Vinczeba3bd602019-06-17 16:01:43 +02002188#if defined(MCUBOOT_ENC_IMAGES) && (BOOT_IMAGE_NUMBER > 1)
2189 /* The keys used for encryption may no longer be valid (could belong to
2190 * another images). Therefore, mark them as invalid to force their reload
2191 * by boot_enc_load().
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03002192 */
David Vinczeba3bd602019-06-17 16:01:43 +02002193 boot_enc_mark_keys_invalid();
David Brown554c52e2017-06-30 16:01:07 -06002194#endif
2195
Fabio Utzigb0f04732019-07-31 09:49:19 -03002196 image_index = BOOT_CURR_IMG(&boot_data);
2197
David Vinczeba3bd602019-06-17 16:01:43 +02002198 BOOT_IMG(&boot_data, BOOT_PRIMARY_SLOT).sectors =
Fabio Utzigb0f04732019-07-31 09:49:19 -03002199 primary_slot_sectors[image_index];
David Vinczeba3bd602019-06-17 16:01:43 +02002200 BOOT_IMG(&boot_data, BOOT_SECONDARY_SLOT).sectors =
Fabio Utzigb0f04732019-07-31 09:49:19 -03002201 secondary_slot_sectors[image_index];
David Vinczeba3bd602019-06-17 16:01:43 +02002202 boot_data.scratch.sectors = scratch_sectors;
2203
2204 /* Open primary and secondary image areas for the duration
2205 * of this call.
2206 */
2207 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
Fabio Utzigb0f04732019-07-31 09:49:19 -03002208 fa_id = flash_area_id_from_multi_image_slot(image_index, slot);
David Vinczeba3bd602019-06-17 16:01:43 +02002209 rc = flash_area_open(fa_id, &BOOT_IMG_AREA(&boot_data, slot));
2210 assert(rc == 0);
2211 }
2212 rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH,
2213 &BOOT_SCRATCH_AREA(&boot_data));
2214 assert(rc == 0);
2215
2216 /* Determine swap type and complete swap if it has been aborted. */
2217 boot_prepare_image_for_update(&bs);
2218 }
2219
David Vinczee32483f2019-06-13 10:46:24 +02002220#if (BOOT_IMAGE_NUMBER > 1)
2221 /* Iterate over all the images and verify whether the image dependencies
2222 * are all satisfied and update swap type if necessary.
2223 */
2224 boot_verify_all_image_dependency();
2225#endif
2226
David Vinczeba3bd602019-06-17 16:01:43 +02002227 /* Iterate over all the images. At this point there are no aborted swaps
2228 * and the swap types are determined for each image. By the end of the loop
2229 * all required update operations will have been finished.
2230 */
Fabio Utzigb0f04732019-07-31 09:49:19 -03002231 IMAGES_ITER(BOOT_CURR_IMG(&boot_data)) {
David Vinczeba3bd602019-06-17 16:01:43 +02002232
2233#if (BOOT_IMAGE_NUMBER > 1)
2234#ifdef MCUBOOT_ENC_IMAGES
2235 /* The keys used for encryption may no longer be valid (could belong to
2236 * another images). Therefore, mark them as invalid to force their reload
2237 * by boot_enc_load().
2238 */
2239 boot_enc_mark_keys_invalid();
2240#endif /* MCUBOOT_ENC_IMAGES */
2241
2242 /* Indicate that swap is not aborted */
2243 memset(&bs, 0, sizeof bs);
2244 bs.idx = BOOT_STATUS_IDX_0;
2245 bs.state = BOOT_STATUS_STATE_0;
2246#endif /* (BOOT_IMAGE_NUMBER > 1) */
2247
2248 /* Set the previously determined swap type */
2249 bs.swap_type = BOOT_SWAP_TYPE(&boot_data);
2250
2251 switch (BOOT_SWAP_TYPE(&boot_data)) {
2252 case BOOT_SWAP_TYPE_NONE:
2253 break;
2254
2255 case BOOT_SWAP_TYPE_TEST: /* fallthrough */
2256 case BOOT_SWAP_TYPE_PERM: /* fallthrough */
2257 case BOOT_SWAP_TYPE_REVERT:
2258 rc = boot_perform_update(&bs);
2259 assert(rc == 0);
2260 break;
2261
2262 case BOOT_SWAP_TYPE_FAIL:
2263 /* The image in secondary slot was invalid and is now erased. Ensure
2264 * we don't try to boot into it again on the next reboot. Do this by
2265 * pretending we just reverted back to primary slot.
2266 */
2267#ifndef MCUBOOT_OVERWRITE_ONLY
2268 /* image_ok needs to be explicitly set to avoid a new revert. */
2269 rc = boot_set_image_ok();
2270 if (rc != 0) {
2271 BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_PANIC;
2272 }
2273#endif /* !MCUBOOT_OVERWRITE_ONLY */
2274 break;
2275
2276 default:
2277 BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_PANIC;
2278 }
2279
2280 if (BOOT_SWAP_TYPE(&boot_data) == BOOT_SWAP_TYPE_PANIC) {
2281 BOOT_LOG_ERR("panic!");
2282 assert(0);
2283
2284 /* Loop forever... */
2285 while (1) {}
2286 }
2287 }
2288
2289 /* Iterate over all the images. At this point all required update operations
2290 * have finished. By the end of the loop each image in the primary slot will
2291 * have been re-validated.
2292 */
Fabio Utzigb0f04732019-07-31 09:49:19 -03002293 IMAGES_ITER(BOOT_CURR_IMG(&boot_data)) {
David Vinczeba3bd602019-06-17 16:01:43 +02002294 if (BOOT_SWAP_TYPE(&boot_data) != BOOT_SWAP_TYPE_NONE) {
2295 /* Attempt to read an image header from each slot. Ensure that image
2296 * headers in slots are aligned with headers in boot_data.
2297 */
2298 rc = boot_read_image_headers(false);
2299 if (rc != 0) {
2300 goto out;
2301 }
2302 /* Since headers were reloaded, it can be assumed we just performed
2303 * a swap or overwrite. Now the header info that should be used to
2304 * provide the data for the bootstrap, which previously was at
2305 * secondary slot, was updated to primary slot.
2306 */
2307 }
2308
2309#ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT
2310 rc = boot_validate_slot(BOOT_PRIMARY_SLOT, NULL);
2311 if (rc != 0) {
2312 rc = BOOT_EBADIMAGE;
2313 goto out;
2314 }
2315#else
2316 /* Even if we're not re-validating the primary slot, we could be booting
2317 * onto an empty flash chip. At least do a basic sanity check that
2318 * the magic number on the image is OK.
2319 */
2320 if (BOOT_IMG(&boot_data, BOOT_PRIMARY_SLOT).hdr.ih_magic !=
2321 IMAGE_MAGIC) {
2322 BOOT_LOG_ERR("bad image magic 0x%lx; Image=%u", (unsigned long)
2323 &boot_img_hdr(&boot_data,BOOT_PRIMARY_SLOT)->ih_magic,
Fabio Utzigb0f04732019-07-31 09:49:19 -03002324 BOOT_CURR_IMG(&boot_data));
David Vinczeba3bd602019-06-17 16:01:43 +02002325 rc = BOOT_EBADIMAGE;
2326 goto out;
2327 }
2328#endif
2329 }
2330
Fabio Utzigb0f04732019-07-31 09:49:19 -03002331#if (BOOT_IMAGE_NUMBER > 1)
David Vinczeba3bd602019-06-17 16:01:43 +02002332 /* Always boot from the primary slot of Image 0. */
Fabio Utzigb0f04732019-07-31 09:49:19 -03002333 BOOT_CURR_IMG(&boot_data) = 0;
2334#endif
David Vinczeba3bd602019-06-17 16:01:43 +02002335 rsp->br_flash_dev_id =
2336 BOOT_IMG_AREA(&boot_data, BOOT_PRIMARY_SLOT)->fa_device_id;
2337 rsp->br_image_off =
2338 boot_img_slot_off(&boot_data, BOOT_PRIMARY_SLOT);
2339 rsp->br_hdr =
2340 boot_img_hdr(&boot_data, BOOT_PRIMARY_SLOT);
Christopher Collins92ea77f2016-12-12 15:59:26 -08002341
Marti Bolivarc0b47912017-06-13 17:18:09 -04002342 out:
Fabio Utzigb0f04732019-07-31 09:49:19 -03002343 IMAGES_ITER(BOOT_CURR_IMG(&boot_data)) {
David Vinczeba3bd602019-06-17 16:01:43 +02002344 flash_area_close(BOOT_SCRATCH_AREA(&boot_data));
2345 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
2346 flash_area_close(BOOT_IMG_AREA(&boot_data,
2347 BOOT_NUM_SLOTS - 1 - slot));
2348 }
Marti Bolivarc0b47912017-06-13 17:18:09 -04002349 }
2350 return rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -08002351}
2352
2353int
2354split_go(int loader_slot, int split_slot, void **entry)
2355{
Marti Bolivarc50926f2017-06-14 09:35:40 -04002356 boot_sector_t *sectors;
Christopher Collins034a6202017-01-11 12:19:37 -08002357 uintptr_t entry_val;
Christopher Collins92ea77f2016-12-12 15:59:26 -08002358 int loader_flash_id;
Marti Bolivarc0b47912017-06-13 17:18:09 -04002359 int split_flash_id;
Christopher Collins92ea77f2016-12-12 15:59:26 -08002360 int rc;
2361
Christopher Collins92ea77f2016-12-12 15:59:26 -08002362 sectors = malloc(BOOT_MAX_IMG_SECTORS * 2 * sizeof *sectors);
2363 if (sectors == NULL) {
Marti Bolivarc0b47912017-06-13 17:18:09 -04002364 return SPLIT_GO_ERR;
Christopher Collins92ea77f2016-12-12 15:59:26 -08002365 }
David Vinczeba3bd602019-06-17 16:01:43 +02002366 BOOT_IMG(&boot_data, loader_slot).sectors = sectors + 0;
2367 BOOT_IMG(&boot_data, split_slot).sectors = sectors + BOOT_MAX_IMG_SECTORS;
Marti Bolivarc0b47912017-06-13 17:18:09 -04002368
2369 loader_flash_id = flash_area_id_from_image_slot(loader_slot);
2370 rc = flash_area_open(loader_flash_id,
Alvaro Prieto63a2bdb2019-07-04 12:18:49 -07002371 &BOOT_IMG_AREA(&boot_data, loader_slot));
Marti Bolivarc0b47912017-06-13 17:18:09 -04002372 assert(rc == 0);
2373 split_flash_id = flash_area_id_from_image_slot(split_slot);
2374 rc = flash_area_open(split_flash_id,
2375 &BOOT_IMG_AREA(&boot_data, split_slot));
2376 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -08002377
2378 /* Determine the sector layout of the image slots and scratch area. */
2379 rc = boot_read_sectors();
2380 if (rc != 0) {
2381 rc = SPLIT_GO_ERR;
2382 goto done;
2383 }
2384
Fabio Utzig9c25fa72017-12-12 14:57:20 -02002385 rc = boot_read_image_headers(true);
Christopher Collins92ea77f2016-12-12 15:59:26 -08002386 if (rc != 0) {
2387 goto done;
2388 }
2389
Christopher Collins92ea77f2016-12-12 15:59:26 -08002390 /* Don't check the bootable image flag because we could really call a
2391 * bootable or non-bootable image. Just validate that the image check
2392 * passes which is distinct from the normal check.
2393 */
Marti Bolivarf804f622017-06-12 15:41:48 -04002394 rc = split_image_check(boot_img_hdr(&boot_data, split_slot),
Marti Bolivarc0b47912017-06-13 17:18:09 -04002395 BOOT_IMG_AREA(&boot_data, split_slot),
Marti Bolivarf804f622017-06-12 15:41:48 -04002396 boot_img_hdr(&boot_data, loader_slot),
Marti Bolivarc0b47912017-06-13 17:18:09 -04002397 BOOT_IMG_AREA(&boot_data, loader_slot));
Christopher Collins92ea77f2016-12-12 15:59:26 -08002398 if (rc != 0) {
2399 rc = SPLIT_GO_NON_MATCHING;
2400 goto done;
2401 }
2402
Marti Bolivarea088872017-06-12 17:10:49 -04002403 entry_val = boot_img_slot_off(&boot_data, split_slot) +
Marti Bolivarf804f622017-06-12 15:41:48 -04002404 boot_img_hdr(&boot_data, split_slot)->ih_hdr_size;
Christopher Collins034a6202017-01-11 12:19:37 -08002405 *entry = (void *) entry_val;
Christopher Collins92ea77f2016-12-12 15:59:26 -08002406 rc = SPLIT_GO_OK;
2407
2408done:
Marti Bolivarc0b47912017-06-13 17:18:09 -04002409 flash_area_close(BOOT_IMG_AREA(&boot_data, split_slot));
2410 flash_area_close(BOOT_IMG_AREA(&boot_data, loader_slot));
Christopher Collins92ea77f2016-12-12 15:59:26 -08002411 free(sectors);
Christopher Collins92ea77f2016-12-12 15:59:26 -08002412 return rc;
2413}