blob: 163431200f616f693b96ef74530d2647911c431e [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
Fabio Utzig10ee6482019-08-01 12:04:52 -030057/*
58 * This macro allows some control on the allocation of local variables.
59 * When running natively on a target, we don't want to allocated huge
60 * variables on the stack, so make them global instead. For the simulator
61 * we want to run as many threads as there are tests, and it's safer
62 * to just make those variables stack allocated.
63 */
64#if !defined(__BOOTSIM__)
65#define TARGET_STATIC static
66#else
67#define TARGET_STATIC
68#endif
69
David Vincze2d736ad2019-02-18 11:50:22 +010070#if defined(MCUBOOT_VALIDATE_PRIMARY_SLOT) && !defined(MCUBOOT_OVERWRITE_ONLY)
Fabio Utzig10ee6482019-08-01 12:04:52 -030071/*
72 * FIXME: this might have to be updated for threaded sim
73 */
Fabio Utziga0e1cce2017-11-23 20:04:01 -020074static int boot_status_fails = 0;
75#define BOOT_STATUS_ASSERT(x) \
76 do { \
Johann Fischered8461b2018-02-15 16:50:31 +010077 if (!(x)) { \
Fabio Utziga0e1cce2017-11-23 20:04:01 -020078 boot_status_fails++; \
79 } \
80 } while (0)
81#else
Fabio Utzig57c40f72017-12-12 21:48:30 -020082#define BOOT_STATUS_ASSERT(x) ASSERT(x)
Fabio Utziga0e1cce2017-11-23 20:04:01 -020083#endif
84
Christopher Collins92ea77f2016-12-12 15:59:26 -080085struct boot_status_table {
David Vincze2d736ad2019-02-18 11:50:22 +010086 uint8_t bst_magic_primary_slot;
Christopher Collins92ea77f2016-12-12 15:59:26 -080087 uint8_t bst_magic_scratch;
David Vincze2d736ad2019-02-18 11:50:22 +010088 uint8_t bst_copy_done_primary_slot;
Christopher Collins92ea77f2016-12-12 15:59:26 -080089 uint8_t bst_status_source;
90};
91
92/**
93 * This set of tables maps swap state contents to boot status location.
94 * When searching for a match, these tables must be iterated in order.
95 */
96static const struct boot_status_table boot_status_tables[] = {
97 {
David Vincze2d736ad2019-02-18 11:50:22 +010098 /* | primary slot | scratch |
99 * ----------+--------------+--------------|
100 * magic | Good | Any |
101 * copy-done | Set | N/A |
102 * ----------+--------------+--------------'
103 * source: none |
104 * ----------------------------------------'
Christopher Collins92ea77f2016-12-12 15:59:26 -0800105 */
David Vincze2d736ad2019-02-18 11:50:22 +0100106 .bst_magic_primary_slot = BOOT_MAGIC_GOOD,
Christopher Collinsa1c12042019-05-23 14:00:28 -0700107 .bst_magic_scratch = BOOT_MAGIC_NOTGOOD,
David Vincze2d736ad2019-02-18 11:50:22 +0100108 .bst_copy_done_primary_slot = BOOT_FLAG_SET,
109 .bst_status_source = BOOT_STATUS_SOURCE_NONE,
Christopher Collins92ea77f2016-12-12 15:59:26 -0800110 },
111
112 {
David Vincze2d736ad2019-02-18 11:50:22 +0100113 /* | primary slot | scratch |
114 * ----------+--------------+--------------|
115 * magic | Good | Any |
116 * copy-done | Unset | N/A |
117 * ----------+--------------+--------------'
118 * source: primary slot |
119 * ----------------------------------------'
Christopher Collins92ea77f2016-12-12 15:59:26 -0800120 */
David Vincze2d736ad2019-02-18 11:50:22 +0100121 .bst_magic_primary_slot = BOOT_MAGIC_GOOD,
Christopher Collinsa1c12042019-05-23 14:00:28 -0700122 .bst_magic_scratch = BOOT_MAGIC_NOTGOOD,
David Vincze2d736ad2019-02-18 11:50:22 +0100123 .bst_copy_done_primary_slot = BOOT_FLAG_UNSET,
124 .bst_status_source = BOOT_STATUS_SOURCE_PRIMARY_SLOT,
Christopher Collins92ea77f2016-12-12 15:59:26 -0800125 },
126
127 {
David Vincze2d736ad2019-02-18 11:50:22 +0100128 /* | primary slot | scratch |
129 * ----------+--------------+--------------|
130 * magic | Any | Good |
131 * copy-done | Any | N/A |
132 * ----------+--------------+--------------'
133 * source: scratch |
134 * ----------------------------------------'
Christopher Collins92ea77f2016-12-12 15:59:26 -0800135 */
David Vincze2d736ad2019-02-18 11:50:22 +0100136 .bst_magic_primary_slot = BOOT_MAGIC_ANY,
137 .bst_magic_scratch = BOOT_MAGIC_GOOD,
138 .bst_copy_done_primary_slot = BOOT_FLAG_ANY,
139 .bst_status_source = BOOT_STATUS_SOURCE_SCRATCH,
Christopher Collins92ea77f2016-12-12 15:59:26 -0800140 },
Christopher Collins92ea77f2016-12-12 15:59:26 -0800141 {
David Vincze2d736ad2019-02-18 11:50:22 +0100142 /* | primary slot | scratch |
143 * ----------+--------------+--------------|
144 * magic | Unset | Any |
145 * copy-done | Unset | N/A |
146 * ----------+--------------+--------------|
147 * source: varies |
148 * ----------------------------------------+--------------------------+
Christopher Collins92ea77f2016-12-12 15:59:26 -0800149 * This represents one of two cases: |
150 * o No swaps ever (no status to read, so no harm in checking). |
David Vincze2d736ad2019-02-18 11:50:22 +0100151 * o Mid-revert; status in primary slot. |
Christopher Collins92ea77f2016-12-12 15:59:26 -0800152 * -------------------------------------------------------------------'
153 */
David Vincze2d736ad2019-02-18 11:50:22 +0100154 .bst_magic_primary_slot = BOOT_MAGIC_UNSET,
155 .bst_magic_scratch = BOOT_MAGIC_ANY,
156 .bst_copy_done_primary_slot = BOOT_FLAG_UNSET,
157 .bst_status_source = BOOT_STATUS_SOURCE_PRIMARY_SLOT,
Christopher Collins92ea77f2016-12-12 15:59:26 -0800158 },
159};
160
161#define BOOT_STATUS_TABLES_COUNT \
162 (sizeof boot_status_tables / sizeof boot_status_tables[0])
163
Marti Bolivarfd20c762017-02-07 16:52:50 -0500164#define BOOT_LOG_SWAP_STATE(area, state) \
Christopher Collinsa1c12042019-05-23 14:00:28 -0700165 BOOT_LOG_INF("%s: magic=%s, swap_type=0x%x, copy_done=0x%x, " \
166 "image_ok=0x%x", \
Marti Bolivarfd20c762017-02-07 16:52:50 -0500167 (area), \
168 ((state)->magic == BOOT_MAGIC_GOOD ? "good" : \
169 (state)->magic == BOOT_MAGIC_UNSET ? "unset" : \
170 "bad"), \
Christopher Collinsa1c12042019-05-23 14:00:28 -0700171 (state)->swap_type, \
Marti Bolivarfd20c762017-02-07 16:52:50 -0500172 (state)->copy_done, \
173 (state)->image_ok)
174
Christopher Collins92ea77f2016-12-12 15:59:26 -0800175/**
David Vincze2d736ad2019-02-18 11:50:22 +0100176 * Determines where in flash the most recent boot status is stored. The boot
Christopher Collins92ea77f2016-12-12 15:59:26 -0800177 * status is necessary for completing a swap that was interrupted by a boot
178 * loader reset.
179 *
David Vincze2d736ad2019-02-18 11:50:22 +0100180 * @return A BOOT_STATUS_SOURCE_[...] code indicating where status should
181 * be read from.
Christopher Collins92ea77f2016-12-12 15:59:26 -0800182 */
183static int
Fabio Utzig10ee6482019-08-01 12:04:52 -0300184boot_status_source(struct boot_loader_state *state)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800185{
186 const struct boot_status_table *table;
187 struct boot_swap_state state_scratch;
David Vincze2d736ad2019-02-18 11:50:22 +0100188 struct boot_swap_state state_primary_slot;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800189 int rc;
Fabio Utzigcd5774b2017-11-29 10:18:26 -0200190 size_t i;
Marti Bolivarfd20c762017-02-07 16:52:50 -0500191 uint8_t source;
Fabio Utzigb0f04732019-07-31 09:49:19 -0300192 uint8_t image_index;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800193
Fabio Utzigb0f04732019-07-31 09:49:19 -0300194#if (BOOT_IMAGE_NUMBER == 1)
195 (void)state;
196#endif
197
Fabio Utzig10ee6482019-08-01 12:04:52 -0300198 image_index = BOOT_CURR_IMG(state);
Fabio Utzigb0f04732019-07-31 09:49:19 -0300199 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_PRIMARY(image_index),
200 &state_primary_slot);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800201 assert(rc == 0);
202
Fabio Utzig2473ac02017-05-02 12:45:02 -0300203 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SCRATCH, &state_scratch);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800204 assert(rc == 0);
205
David Vincze2d736ad2019-02-18 11:50:22 +0100206 BOOT_LOG_SWAP_STATE("Primary image", &state_primary_slot);
Marti Bolivarfd20c762017-02-07 16:52:50 -0500207 BOOT_LOG_SWAP_STATE("Scratch", &state_scratch);
208
Christopher Collins92ea77f2016-12-12 15:59:26 -0800209 for (i = 0; i < BOOT_STATUS_TABLES_COUNT; i++) {
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300210 table = &boot_status_tables[i];
Christopher Collins92ea77f2016-12-12 15:59:26 -0800211
Christopher Collinsa1c12042019-05-23 14:00:28 -0700212 if (boot_magic_compatible_check(table->bst_magic_primary_slot,
213 state_primary_slot.magic) &&
214 boot_magic_compatible_check(table->bst_magic_scratch,
215 state_scratch.magic) &&
David Vincze2d736ad2019-02-18 11:50:22 +0100216 (table->bst_copy_done_primary_slot == BOOT_FLAG_ANY ||
217 table->bst_copy_done_primary_slot == state_primary_slot.copy_done))
218 {
Marti Bolivarfd20c762017-02-07 16:52:50 -0500219 source = table->bst_status_source;
David Vinczeba3bd602019-06-17 16:01:43 +0200220
221#if (BOOT_IMAGE_NUMBER > 1)
222 /* In case of multi-image boot it can happen that if boot status
223 * info is found on scratch area then it does not belong to the
224 * currently examined image.
225 */
226 if (source == BOOT_STATUS_SOURCE_SCRATCH &&
Fabio Utzig10ee6482019-08-01 12:04:52 -0300227 state_scratch.image_num != BOOT_CURR_IMG(state)) {
David Vinczeba3bd602019-06-17 16:01:43 +0200228 source = BOOT_STATUS_SOURCE_NONE;
229 }
230#endif
231
Marti Bolivarfd20c762017-02-07 16:52:50 -0500232 BOOT_LOG_INF("Boot source: %s",
233 source == BOOT_STATUS_SOURCE_NONE ? "none" :
234 source == BOOT_STATUS_SOURCE_SCRATCH ? "scratch" :
David Vincze2d736ad2019-02-18 11:50:22 +0100235 source == BOOT_STATUS_SOURCE_PRIMARY_SLOT ?
236 "primary slot" : "BUG; can't happen");
Marti Bolivarfd20c762017-02-07 16:52:50 -0500237 return source;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800238 }
239 }
240
Marti Bolivarfd20c762017-02-07 16:52:50 -0500241 BOOT_LOG_INF("Boot source: none");
Christopher Collins92ea77f2016-12-12 15:59:26 -0800242 return BOOT_STATUS_SOURCE_NONE;
243}
244
David Brownf5b33d82017-09-01 10:58:27 -0600245/*
Fabio Utzig233af7d2019-08-26 12:06:16 -0300246 * Locate the TLVs in an image.
247 *
248 * @param hdr The image_header struct of the image being checked
249 * @param fap flash_area struct of the slot storing the image being checked
250 * @param off Address of the first TLV (after TLV info)
251 * @param end Address where TLV area ends
252 *
253 * Returns 0 on success.
254 */
255int
256boot_find_tlv_offs(const struct image_header *hdr, const struct flash_area *fap,
257 uint32_t *off, uint32_t *end)
258{
259 struct image_tlv_info info;
260 uint32_t off_;
261
262 off_ = BOOT_TLV_OFF(hdr);
263
264 if (flash_area_read(fap, off_, &info, sizeof(info))) {
265 return BOOT_EFLASH;
266 }
267
268 if (info.it_magic != IMAGE_TLV_INFO_MAGIC) {
269 return BOOT_EBADIMAGE;
270 }
271
272 *end = off_ + info.it_tlv_tot;
273 *off = off_ + sizeof(info);
274 return 0;
275}
276
277/*
David Brownf5b33d82017-09-01 10:58:27 -0600278 * Compute the total size of the given image. Includes the size of
279 * the TLVs.
280 */
Fabio Utzig13d9e352017-10-05 20:32:31 -0300281#if !defined(MCUBOOT_OVERWRITE_ONLY) || defined(MCUBOOT_OVERWRITE_ONLY_FAST)
David Brownf5b33d82017-09-01 10:58:27 -0600282static int
Fabio Utzigd638b172019-08-09 10:38:05 -0300283boot_read_image_size(struct boot_loader_state *state, int slot, uint32_t *size)
David Brownf5b33d82017-09-01 10:58:27 -0600284{
285 const struct flash_area *fap;
Fabio Utzig233af7d2019-08-26 12:06:16 -0300286 uint32_t off;
David Brownf5b33d82017-09-01 10:58:27 -0600287 int area_id;
288 int rc;
289
Fabio Utzig10ee6482019-08-01 12:04:52 -0300290#if (BOOT_IMAGE_NUMBER == 1)
291 (void)state;
292#endif
293
294 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
David Brownf5b33d82017-09-01 10:58:27 -0600295 rc = flash_area_open(area_id, &fap);
296 if (rc != 0) {
297 rc = BOOT_EFLASH;
298 goto done;
299 }
300
Fabio Utzig233af7d2019-08-26 12:06:16 -0300301 rc = boot_find_tlv_offs(boot_img_hdr(state, slot), fap, &off, size);
David Brownf5b33d82017-09-01 10:58:27 -0600302 if (rc != 0) {
David Brownf5b33d82017-09-01 10:58:27 -0600303 goto done;
304 }
David Brownf5b33d82017-09-01 10:58:27 -0600305 rc = 0;
306
307done:
308 flash_area_close(fap);
Fabio Utzig2eebf112017-09-04 15:25:08 -0300309 return rc;
David Brownf5b33d82017-09-01 10:58:27 -0600310}
Fabio Utzig36ec0e72017-09-05 08:10:33 -0300311#endif /* !MCUBOOT_OVERWRITE_ONLY */
David Brownf5b33d82017-09-01 10:58:27 -0600312
Fabio Utzigc08ed212017-06-20 19:28:36 -0300313static int
Fabio Utzig10ee6482019-08-01 12:04:52 -0300314boot_read_image_header(struct boot_loader_state *state, int slot,
315 struct image_header *out_hdr)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800316{
317 const struct flash_area *fap;
318 int area_id;
319 int rc;
320
Fabio Utzig10ee6482019-08-01 12:04:52 -0300321#if (BOOT_IMAGE_NUMBER == 1)
322 (void)state;
323#endif
324
325 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800326 rc = flash_area_open(area_id, &fap);
327 if (rc != 0) {
328 rc = BOOT_EFLASH;
329 goto done;
330 }
331
332 rc = flash_area_read(fap, 0, out_hdr, sizeof *out_hdr);
333 if (rc != 0) {
334 rc = BOOT_EFLASH;
335 goto done;
336 }
337
338 rc = 0;
339
340done:
341 flash_area_close(fap);
342 return rc;
343}
344
345static int
Fabio Utzig10ee6482019-08-01 12:04:52 -0300346boot_read_image_headers(struct boot_loader_state *state, bool require_all)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800347{
348 int rc;
349 int i;
350
351 for (i = 0; i < BOOT_NUM_SLOTS; i++) {
Fabio Utzig10ee6482019-08-01 12:04:52 -0300352 rc = boot_read_image_header(state, i, boot_img_hdr(state, i));
Christopher Collins92ea77f2016-12-12 15:59:26 -0800353 if (rc != 0) {
Fabio Utzig9c25fa72017-12-12 14:57:20 -0200354 /* If `require_all` is set, fail on any single fail, otherwise
355 * if at least the first slot's header was read successfully,
356 * then the boot loader can attempt a boot.
357 *
358 * Failure to read any headers is a fatal error.
Christopher Collins0ff3c6c2016-12-21 12:04:17 -0800359 */
Fabio Utzig9c25fa72017-12-12 14:57:20 -0200360 if (i > 0 && !require_all) {
Christopher Collins0ff3c6c2016-12-21 12:04:17 -0800361 return 0;
362 } else {
363 return rc;
364 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800365 }
366 }
367
368 return 0;
369}
370
371static uint8_t
Fabio Utzig10ee6482019-08-01 12:04:52 -0300372boot_write_sz(struct boot_loader_state *state)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800373{
374 uint8_t elem_sz;
375 uint8_t align;
376
377 /* Figure out what size to write update status update as. The size depends
378 * on what the minimum write size is for scratch area, active image slot.
379 * We need to use the bigger of those 2 values.
380 */
Fabio Utzig10ee6482019-08-01 12:04:52 -0300381 elem_sz = flash_area_align(BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT));
382 align = flash_area_align(BOOT_SCRATCH_AREA(state));
Christopher Collins92ea77f2016-12-12 15:59:26 -0800383 if (align > elem_sz) {
384 elem_sz = align;
385 }
386
387 return elem_sz;
388}
389
Fabio Utzig2bd980a2018-11-26 10:38:17 -0200390/*
391 * Slots are compatible when all sectors that store upto to size of the image
392 * round up to sector size, in both slot's are able to fit in the scratch
393 * area, and have sizes that are a multiple of each other (powers of two
394 * presumably!).
395 */
Christopher Collins0ff3c6c2016-12-21 12:04:17 -0800396static int
Fabio Utzig10ee6482019-08-01 12:04:52 -0300397boot_slots_compatible(struct boot_loader_state *state)
Christopher Collins0ff3c6c2016-12-21 12:04:17 -0800398{
David Vincze2d736ad2019-02-18 11:50:22 +0100399 size_t num_sectors_primary;
400 size_t num_sectors_secondary;
Fabio Utzig2bd980a2018-11-26 10:38:17 -0200401 size_t sz0, sz1;
David Vincze2d736ad2019-02-18 11:50:22 +0100402 size_t primary_slot_sz, secondary_slot_sz;
Fabio Utzig2bd980a2018-11-26 10:38:17 -0200403 size_t scratch_sz;
404 size_t i, j;
405 int8_t smaller;
Christopher Collins0ff3c6c2016-12-21 12:04:17 -0800406
Fabio Utzig10ee6482019-08-01 12:04:52 -0300407 num_sectors_primary = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT);
408 num_sectors_secondary = boot_img_num_sectors(state, BOOT_SECONDARY_SLOT);
David Vincze2d736ad2019-02-18 11:50:22 +0100409 if ((num_sectors_primary > BOOT_MAX_IMG_SECTORS) ||
410 (num_sectors_secondary > BOOT_MAX_IMG_SECTORS)) {
Fabio Utziga1fae672018-03-30 10:52:38 -0300411 BOOT_LOG_WRN("Cannot upgrade: more sectors than allowed");
Christopher Collins0ff3c6c2016-12-21 12:04:17 -0800412 return 0;
413 }
Fabio Utziga1fae672018-03-30 10:52:38 -0300414
Fabio Utzig10ee6482019-08-01 12:04:52 -0300415 scratch_sz = boot_scratch_area_size(state);
Fabio Utzig2bd980a2018-11-26 10:38:17 -0200416
417 /*
418 * The following loop scans all sectors in a linear fashion, assuring that
419 * for each possible sector in each slot, it is able to fit in the other
420 * slot's sector or sectors. Slot's should be compatible as long as any
421 * number of a slot's sectors are able to fit into another, which only
422 * excludes cases where sector sizes are not a multiple of each other.
423 */
David Vincze2d736ad2019-02-18 11:50:22 +0100424 i = sz0 = primary_slot_sz = 0;
425 j = sz1 = secondary_slot_sz = 0;
Fabio Utzig2bd980a2018-11-26 10:38:17 -0200426 smaller = 0;
David Vincze2d736ad2019-02-18 11:50:22 +0100427 while (i < num_sectors_primary || j < num_sectors_secondary) {
Fabio Utzig2bd980a2018-11-26 10:38:17 -0200428 if (sz0 == sz1) {
Fabio Utzig10ee6482019-08-01 12:04:52 -0300429 sz0 += boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i);
430 sz1 += boot_img_sector_size(state, BOOT_SECONDARY_SLOT, j);
Fabio Utzig2bd980a2018-11-26 10:38:17 -0200431 i++;
432 j++;
433 } else if (sz0 < sz1) {
Fabio Utzig10ee6482019-08-01 12:04:52 -0300434 sz0 += boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i);
David Vincze2d736ad2019-02-18 11:50:22 +0100435 /* Guarantee that multiple sectors of the secondary slot
436 * fit into the primary slot.
437 */
Fabio Utzig2bd980a2018-11-26 10:38:17 -0200438 if (smaller == 2) {
439 BOOT_LOG_WRN("Cannot upgrade: slots have non-compatible sectors");
440 return 0;
441 }
442 smaller = 1;
443 i++;
444 } else {
Fabio Utzig10ee6482019-08-01 12:04:52 -0300445 sz1 += boot_img_sector_size(state, BOOT_SECONDARY_SLOT, j);
David Vincze2d736ad2019-02-18 11:50:22 +0100446 /* Guarantee that multiple sectors of the primary slot
447 * fit into the secondary slot.
448 */
Fabio Utzig2bd980a2018-11-26 10:38:17 -0200449 if (smaller == 1) {
450 BOOT_LOG_WRN("Cannot upgrade: slots have non-compatible sectors");
451 return 0;
452 }
453 smaller = 2;
454 j++;
455 }
456 if (sz0 == sz1) {
David Vincze2d736ad2019-02-18 11:50:22 +0100457 primary_slot_sz += sz0;
458 secondary_slot_sz += sz1;
459 /* Scratch has to fit each swap operation to the size of the larger
460 * sector among the primary slot and the secondary slot.
Fabio Utzig2bd980a2018-11-26 10:38:17 -0200461 */
462 if (sz0 > scratch_sz || sz1 > scratch_sz) {
463 BOOT_LOG_WRN("Cannot upgrade: not all sectors fit inside scratch");
464 return 0;
465 }
466 smaller = sz0 = sz1 = 0;
467 }
Fabio Utziga1fae672018-03-30 10:52:38 -0300468 }
469
David Vincze2d736ad2019-02-18 11:50:22 +0100470 if ((i != num_sectors_primary) ||
471 (j != num_sectors_secondary) ||
472 (primary_slot_sz != secondary_slot_sz)) {
Fabio Utzig2bd980a2018-11-26 10:38:17 -0200473 BOOT_LOG_WRN("Cannot upgrade: slots are not compatible");
474 return 0;
Christopher Collins0ff3c6c2016-12-21 12:04:17 -0800475 }
476
477 return 1;
478}
479
Fabio Utzig10ee6482019-08-01 12:04:52 -0300480#ifndef MCUBOOT_USE_FLASH_AREA_GET_SECTORS
481static int
482boot_initialize_area(struct boot_loader_state *state, int flash_area)
483{
484 int num_sectors = BOOT_MAX_IMG_SECTORS;
485 int rc;
486
487 if (flash_area == FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state))) {
488 rc = flash_area_to_sectors(flash_area, &num_sectors,
489 BOOT_IMG(state, BOOT_PRIMARY_SLOT).sectors);
490 BOOT_IMG(state, BOOT_PRIMARY_SLOT).num_sectors = (size_t)num_sectors;
491
492 } else if (flash_area == FLASH_AREA_IMAGE_SECONDARY(BOOT_CURR_IMG(state))) {
493 rc = flash_area_to_sectors(flash_area, &num_sectors,
494 BOOT_IMG(state, BOOT_SECONDARY_SLOT).sectors);
495 BOOT_IMG(state, BOOT_SECONDARY_SLOT).num_sectors = (size_t)num_sectors;
496
497 } else if (flash_area == FLASH_AREA_IMAGE_SCRATCH) {
498 rc = flash_area_to_sectors(flash_area, &num_sectors,
499 state->scratch.sectors);
500 state->scratch.num_sectors = (size_t)num_sectors;
501 } else {
502 return BOOT_EFLASH;
503 }
504
505 return rc;
506}
507#else /* defined(MCUBOOT_USE_FLASH_AREA_GET_SECTORS) */
508static int
509boot_initialize_area(struct boot_loader_state *state, int flash_area)
510{
511 uint32_t num_sectors;
512 struct flash_sector *out_sectors;
513 size_t *out_num_sectors;
514 int rc;
515
516 num_sectors = BOOT_MAX_IMG_SECTORS;
517
518 if (flash_area == FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state))) {
519 out_sectors = BOOT_IMG(state, BOOT_PRIMARY_SLOT).sectors;
520 out_num_sectors = &BOOT_IMG(state, BOOT_PRIMARY_SLOT).num_sectors;
521 } else if (flash_area == FLASH_AREA_IMAGE_SECONDARY(BOOT_CURR_IMG(state))) {
522 out_sectors = BOOT_IMG(state, BOOT_SECONDARY_SLOT).sectors;
523 out_num_sectors = &BOOT_IMG(state, BOOT_SECONDARY_SLOT).num_sectors;
524 } else if (flash_area == FLASH_AREA_IMAGE_SCRATCH) {
525 out_sectors = state->scratch.sectors;
526 out_num_sectors = &state->scratch.num_sectors;
527 } else {
528 return BOOT_EFLASH;
529 }
530
531 rc = flash_area_get_sectors(flash_area, &num_sectors, out_sectors);
532 if (rc != 0) {
533 return rc;
534 }
535 *out_num_sectors = num_sectors;
536 return 0;
537}
538#endif /* !defined(MCUBOOT_USE_FLASH_AREA_GET_SECTORS) */
539
Christopher Collins92ea77f2016-12-12 15:59:26 -0800540/**
541 * Determines the sector layout of both image slots and the scratch area.
542 * This information is necessary for calculating the number of bytes to erase
543 * and copy during an image swap. The information collected during this
Fabio Utzig10ee6482019-08-01 12:04:52 -0300544 * function is used to populate the state.
Christopher Collins92ea77f2016-12-12 15:59:26 -0800545 */
546static int
Fabio Utzig10ee6482019-08-01 12:04:52 -0300547boot_read_sectors(struct boot_loader_state *state)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800548{
Fabio Utzigb0f04732019-07-31 09:49:19 -0300549 uint8_t image_index;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800550 int rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800551
Fabio Utzig10ee6482019-08-01 12:04:52 -0300552 image_index = BOOT_CURR_IMG(state);
Fabio Utzigb0f04732019-07-31 09:49:19 -0300553
554 rc = boot_initialize_area(state, FLASH_AREA_IMAGE_PRIMARY(image_index));
Christopher Collins92ea77f2016-12-12 15:59:26 -0800555 if (rc != 0) {
556 return BOOT_EFLASH;
557 }
558
Fabio Utzig10ee6482019-08-01 12:04:52 -0300559 rc = boot_initialize_area(state, FLASH_AREA_IMAGE_SECONDARY(image_index));
Christopher Collins92ea77f2016-12-12 15:59:26 -0800560 if (rc != 0) {
561 return BOOT_EFLASH;
562 }
563
Fabio Utzig10ee6482019-08-01 12:04:52 -0300564 rc = boot_initialize_area(state, FLASH_AREA_IMAGE_SCRATCH);
Fabio Utzig2bd980a2018-11-26 10:38:17 -0200565 if (rc != 0) {
566 return BOOT_EFLASH;
567 }
568
Fabio Utzig10ee6482019-08-01 12:04:52 -0300569 BOOT_WRITE_SZ(state) = boot_write_sz(state);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800570
571 return 0;
572}
573
574static uint32_t
575boot_status_internal_off(int idx, int state, int elem_sz)
576{
577 int idx_sz;
578
579 idx_sz = elem_sz * BOOT_STATUS_STATE_COUNT;
580
Fabio Utzig39000012018-07-30 12:40:20 -0300581 return (idx - BOOT_STATUS_IDX_0) * idx_sz +
582 (state - BOOT_STATUS_STATE_0) * elem_sz;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800583}
584
585/**
586 * Reads the status of a partially-completed swap, if any. This is necessary
587 * to recover in case the boot lodaer was reset in the middle of a swap
588 * operation.
589 */
590static int
Fabio Utzig10ee6482019-08-01 12:04:52 -0300591boot_read_status_bytes(const struct flash_area *fap,
592 struct boot_loader_state *state, struct boot_status *bs)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800593{
594 uint32_t off;
595 uint8_t status;
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300596 int max_entries;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800597 int found;
Fabio Utziga0e1cce2017-11-23 20:04:01 -0200598 int found_idx;
599 int invalid;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800600 int rc;
601 int i;
602
603 off = boot_status_off(fap);
Fabio Utzig10ee6482019-08-01 12:04:52 -0300604 max_entries = boot_status_entries(BOOT_CURR_IMG(state), fap);
Fabio Utzig9d160092019-08-09 07:46:34 -0300605 if (max_entries < 0) {
606 return BOOT_EBADARGS;
607 }
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300608
Christopher Collins92ea77f2016-12-12 15:59:26 -0800609 found = 0;
Fabio Utziga0e1cce2017-11-23 20:04:01 -0200610 found_idx = 0;
611 invalid = 0;
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300612 for (i = 0; i < max_entries; i++) {
Fabio Utzig10ee6482019-08-01 12:04:52 -0300613 rc = flash_area_read_is_empty(fap, off + i * BOOT_WRITE_SZ(state),
Fabio Utzig178be542018-09-19 08:12:56 -0300614 &status, 1);
615 if (rc < 0) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800616 return BOOT_EFLASH;
617 }
618
Fabio Utzig178be542018-09-19 08:12:56 -0300619 if (rc == 1) {
Fabio Utziga0e1cce2017-11-23 20:04:01 -0200620 if (found && !found_idx) {
621 found_idx = i;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800622 }
623 } else if (!found) {
624 found = 1;
Fabio Utziga0e1cce2017-11-23 20:04:01 -0200625 } else if (found_idx) {
626 invalid = 1;
627 break;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800628 }
629 }
630
Fabio Utziga0e1cce2017-11-23 20:04:01 -0200631 if (invalid) {
632 /* This means there was an error writing status on the last
633 * swap. Tell user and move on to validation!
634 */
635 BOOT_LOG_ERR("Detected inconsistent status!");
636
David Vincze2d736ad2019-02-18 11:50:22 +0100637#if !defined(MCUBOOT_VALIDATE_PRIMARY_SLOT)
638 /* With validation of the primary slot disabled, there is no way
639 * to be sure the swapped primary slot is OK, so abort!
Fabio Utziga0e1cce2017-11-23 20:04:01 -0200640 */
641 assert(0);
642#endif
643 }
644
Christopher Collins92ea77f2016-12-12 15:59:26 -0800645 if (found) {
Fabio Utziga0e1cce2017-11-23 20:04:01 -0200646 if (!found_idx) {
647 found_idx = i;
648 }
Fabio Utzig39000012018-07-30 12:40:20 -0300649 bs->idx = (found_idx / BOOT_STATUS_STATE_COUNT) + 1;
650 bs->state = (found_idx % BOOT_STATUS_STATE_COUNT) + 1;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800651 }
652
653 return 0;
654}
655
656/**
657 * Reads the boot status from the flash. The boot status contains
658 * the current state of an interrupted image copy operation. If the boot
659 * status is not present, or it indicates that previous copy finished,
660 * there is no operation in progress.
661 */
662static int
Fabio Utzig10ee6482019-08-01 12:04:52 -0300663boot_read_status(struct boot_loader_state *state, struct boot_status *bs)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800664{
665 const struct flash_area *fap;
Christopher Collinsa1c12042019-05-23 14:00:28 -0700666 uint32_t off;
David Vinczee2453472019-06-17 12:31:59 +0200667 uint8_t swap_info;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800668 int status_loc;
669 int area_id;
670 int rc;
671
672 memset(bs, 0, sizeof *bs);
Fabio Utzig39000012018-07-30 12:40:20 -0300673 bs->idx = BOOT_STATUS_IDX_0;
674 bs->state = BOOT_STATUS_STATE_0;
Christopher Collinsa1c12042019-05-23 14:00:28 -0700675 bs->swap_type = BOOT_SWAP_TYPE_NONE;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800676
Fabio Utzig03dc9a02018-06-11 12:24:07 -0700677#ifdef MCUBOOT_OVERWRITE_ONLY
678 /* Overwrite-only doesn't make use of the swap status area. */
679 return 0;
680#endif
681
Fabio Utzig10ee6482019-08-01 12:04:52 -0300682 status_loc = boot_status_source(state);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800683 switch (status_loc) {
684 case BOOT_STATUS_SOURCE_NONE:
685 return 0;
686
687 case BOOT_STATUS_SOURCE_SCRATCH:
688 area_id = FLASH_AREA_IMAGE_SCRATCH;
689 break;
690
David Vincze2d736ad2019-02-18 11:50:22 +0100691 case BOOT_STATUS_SOURCE_PRIMARY_SLOT:
Fabio Utzig10ee6482019-08-01 12:04:52 -0300692 area_id = FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state));
Christopher Collins92ea77f2016-12-12 15:59:26 -0800693 break;
694
695 default:
696 assert(0);
697 return BOOT_EBADARGS;
698 }
699
700 rc = flash_area_open(area_id, &fap);
701 if (rc != 0) {
702 return BOOT_EFLASH;
703 }
704
Fabio Utzig10ee6482019-08-01 12:04:52 -0300705 rc = boot_read_status_bytes(fap, state, bs);
Christopher Collinsa1c12042019-05-23 14:00:28 -0700706 if (rc == 0) {
David Vinczee2453472019-06-17 12:31:59 +0200707 off = boot_swap_info_off(fap);
708 rc = flash_area_read_is_empty(fap, off, &swap_info, sizeof swap_info);
Christopher Collinsa1c12042019-05-23 14:00:28 -0700709 if (rc == 1) {
David Vinczee2453472019-06-17 12:31:59 +0200710 BOOT_SET_SWAP_INFO(swap_info, 0, BOOT_SWAP_TYPE_NONE);
Christopher Collinsa1c12042019-05-23 14:00:28 -0700711 rc = 0;
712 }
David Vinczee2453472019-06-17 12:31:59 +0200713
714 /* Extract the swap type info */
715 bs->swap_type = BOOT_GET_SWAP_TYPE(swap_info);
Christopher Collinsa1c12042019-05-23 14:00:28 -0700716 }
Fabio Utzig46490722017-09-04 15:34:32 -0300717
718 flash_area_close(fap);
Fabio Utzig03dc9a02018-06-11 12:24:07 -0700719
Fabio Utzig46490722017-09-04 15:34:32 -0300720 return rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800721}
722
723/**
724 * Writes the supplied boot status to the flash file system. The boot status
725 * contains the current state of an in-progress image copy operation.
726 *
727 * @param bs The boot status to write.
728 *
729 * @return 0 on success; nonzero on failure.
730 */
731int
Fabio Utzig10ee6482019-08-01 12:04:52 -0300732boot_write_status(struct boot_loader_state *state, struct boot_status *bs)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800733{
734 const struct flash_area *fap;
735 uint32_t off;
736 int area_id;
737 int rc;
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300738 uint8_t buf[BOOT_MAX_ALIGN];
David Brown9d725462017-01-23 15:50:58 -0700739 uint8_t align;
Fabio Utzig39000012018-07-30 12:40:20 -0300740 uint8_t erased_val;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800741
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300742 /* NOTE: The first sector copied (that is the last sector on slot) contains
David Vincze2d736ad2019-02-18 11:50:22 +0100743 * the trailer. Since in the last step the primary slot is erased, the
744 * first two status writes go to the scratch which will be copied to
745 * the primary slot!
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300746 */
747
Fabio Utzig2473ac02017-05-02 12:45:02 -0300748 if (bs->use_scratch) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800749 /* Write to scratch. */
750 area_id = FLASH_AREA_IMAGE_SCRATCH;
751 } else {
David Vincze2d736ad2019-02-18 11:50:22 +0100752 /* Write to the primary slot. */
Fabio Utzig10ee6482019-08-01 12:04:52 -0300753 area_id = FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state));
Christopher Collins92ea77f2016-12-12 15:59:26 -0800754 }
755
756 rc = flash_area_open(area_id, &fap);
757 if (rc != 0) {
758 rc = BOOT_EFLASH;
759 goto done;
760 }
761
762 off = boot_status_off(fap) +
Fabio Utzigd638b172019-08-09 10:38:05 -0300763 boot_status_internal_off(bs->idx, bs->state, BOOT_WRITE_SZ(state));
Andrzej Puzdrowskib788c712018-04-12 12:42:49 +0200764 align = flash_area_align(fap);
Fabio Utzig39000012018-07-30 12:40:20 -0300765 erased_val = flash_area_erased_val(fap);
766 memset(buf, erased_val, BOOT_MAX_ALIGN);
David Brown9d725462017-01-23 15:50:58 -0700767 buf[0] = bs->state;
768
769 rc = flash_area_write(fap, off, buf, align);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800770 if (rc != 0) {
771 rc = BOOT_EFLASH;
772 goto done;
773 }
774
775 rc = 0;
776
777done:
778 flash_area_close(fap);
779 return rc;
780}
781
782/*
783 * Validate image hash/signature in a slot.
784 */
785static int
Fabio Utzig10ee6482019-08-01 12:04:52 -0300786boot_image_check(struct boot_loader_state *state, struct image_header *hdr,
787 const struct flash_area *fap, struct boot_status *bs)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800788{
Fabio Utzig10ee6482019-08-01 12:04:52 -0300789 TARGET_STATIC uint8_t tmpbuf[BOOT_TMPBUF_SZ];
Fabio Utzigb0f04732019-07-31 09:49:19 -0300790 uint8_t image_index;
Fabio Utzigba829042018-09-18 08:29:34 -0300791 int rc;
792
Fabio Utzig10ee6482019-08-01 12:04:52 -0300793#if (BOOT_IMAGE_NUMBER == 1)
794 (void)state;
795#endif
796
Fabio Utzigba829042018-09-18 08:29:34 -0300797 (void)bs;
798 (void)rc;
Fabio Utzigbc077932019-08-26 11:16:34 -0300799
800 image_index = BOOT_CURR_IMG(state);
801
802#ifdef MCUBOOT_ENC_IMAGES
803 if (MUST_DECRYPT(fap, image_index, hdr)) {
Fabio Utzig1e4284b2019-08-23 11:55:27 -0300804 rc = boot_enc_load(BOOT_CURR_ENC(state), image_index, hdr, fap, bs->enckey[1]);
Fabio Utzigba829042018-09-18 08:29:34 -0300805 if (rc < 0) {
806 return BOOT_EBADIMAGE;
807 }
Fabio Utzig1e4284b2019-08-23 11:55:27 -0300808 if (rc == 0 && boot_enc_set_key(BOOT_CURR_ENC(state), 1, bs->enckey[1])) {
Fabio Utzigba829042018-09-18 08:29:34 -0300809 return BOOT_EBADIMAGE;
810 }
811 }
Fabio Utzigbc077932019-08-26 11:16:34 -0300812#endif
813
Fabio Utzig1e4284b2019-08-23 11:55:27 -0300814 if (bootutil_img_validate(BOOT_CURR_ENC(state), image_index, hdr, fap, tmpbuf,
Fabio Utzig10ee6482019-08-01 12:04:52 -0300815 BOOT_TMPBUF_SZ, NULL, 0, NULL)) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800816 return BOOT_EBADIMAGE;
817 }
Fabio Utzig10ee6482019-08-01 12:04:52 -0300818
Christopher Collins92ea77f2016-12-12 15:59:26 -0800819 return 0;
820}
821
822static int
823split_image_check(struct image_header *app_hdr,
824 const struct flash_area *app_fap,
825 struct image_header *loader_hdr,
826 const struct flash_area *loader_fap)
827{
828 static void *tmpbuf;
829 uint8_t loader_hash[32];
830
831 if (!tmpbuf) {
832 tmpbuf = malloc(BOOT_TMPBUF_SZ);
833 if (!tmpbuf) {
834 return BOOT_ENOMEM;
835 }
836 }
837
Fabio Utzig10ee6482019-08-01 12:04:52 -0300838 if (bootutil_img_validate(NULL, 0, loader_hdr, loader_fap, tmpbuf,
839 BOOT_TMPBUF_SZ, NULL, 0, loader_hash)) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800840 return BOOT_EBADIMAGE;
841 }
842
Fabio Utzig10ee6482019-08-01 12:04:52 -0300843 if (bootutil_img_validate(NULL, 0, app_hdr, app_fap, tmpbuf,
844 BOOT_TMPBUF_SZ, loader_hash, 32, NULL)) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800845 return BOOT_EBADIMAGE;
846 }
847
848 return 0;
849}
850
Fabio Utzig338a19f2018-12-03 08:37:08 -0200851/*
852 * Check that a memory area consists of a given value.
853 */
854static inline bool
855boot_data_is_set_to(uint8_t val, void *data, size_t len)
Fabio Utzig39000012018-07-30 12:40:20 -0300856{
857 uint8_t i;
Fabio Utzig338a19f2018-12-03 08:37:08 -0200858 uint8_t *p = (uint8_t *)data;
859 for (i = 0; i < len; i++) {
860 if (val != p[i]) {
861 return false;
Fabio Utzig39000012018-07-30 12:40:20 -0300862 }
863 }
Fabio Utzig338a19f2018-12-03 08:37:08 -0200864 return true;
865}
866
867static int
Fabio Utzig10ee6482019-08-01 12:04:52 -0300868boot_check_header_erased(struct boot_loader_state *state, int slot)
Fabio Utzig338a19f2018-12-03 08:37:08 -0200869{
870 const struct flash_area *fap;
871 struct image_header *hdr;
872 uint8_t erased_val;
Fabio Utzigb0f04732019-07-31 09:49:19 -0300873 int area_id;
Fabio Utzig338a19f2018-12-03 08:37:08 -0200874 int rc;
875
Fabio Utzig10ee6482019-08-01 12:04:52 -0300876 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
Fabio Utzigb0f04732019-07-31 09:49:19 -0300877 rc = flash_area_open(area_id, &fap);
Fabio Utzig338a19f2018-12-03 08:37:08 -0200878 if (rc != 0) {
879 return -1;
880 }
881
882 erased_val = flash_area_erased_val(fap);
883 flash_area_close(fap);
884
Fabio Utzig10ee6482019-08-01 12:04:52 -0300885 hdr = boot_img_hdr(state, slot);
Fabio Utzig338a19f2018-12-03 08:37:08 -0200886 if (!boot_data_is_set_to(erased_val, &hdr->ih_magic, sizeof(hdr->ih_magic))) {
887 return -1;
888 }
889
890 return 0;
Fabio Utzig39000012018-07-30 12:40:20 -0300891}
892
Fabio Utzigb1adb1e2019-09-11 11:42:53 -0300893/*
894 * Check that there is a valid image in a slot
895 *
896 * @returns
897 * 0 if image was succesfully validated
898 * 1 if no bootloable image was found
899 * -1 on any errors
900 */
Christopher Collins92ea77f2016-12-12 15:59:26 -0800901static int
Fabio Utzig10ee6482019-08-01 12:04:52 -0300902boot_validate_slot(struct boot_loader_state *state, int slot,
903 struct boot_status *bs)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800904{
905 const struct flash_area *fap;
Marti Bolivarf804f622017-06-12 15:41:48 -0400906 struct image_header *hdr;
Fabio Utzigb0f04732019-07-31 09:49:19 -0300907 int area_id;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800908 int rc;
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300909
Fabio Utzig10ee6482019-08-01 12:04:52 -0300910 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
Fabio Utzigb0f04732019-07-31 09:49:19 -0300911 rc = flash_area_open(area_id, &fap);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800912 if (rc != 0) {
Fabio Utzigb1adb1e2019-09-11 11:42:53 -0300913 return -1;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800914 }
915
Fabio Utzig10ee6482019-08-01 12:04:52 -0300916 hdr = boot_img_hdr(state, slot);
917 if (boot_check_header_erased(state, slot) == 0 ||
918 (hdr->ih_flags & IMAGE_F_NON_BOOTABLE)) {
David Vincze2d736ad2019-02-18 11:50:22 +0100919 /* No bootable image in slot; continue booting from the primary slot. */
Fabio Utzigb1adb1e2019-09-11 11:42:53 -0300920 rc = 1;
Fabio Utzig338a19f2018-12-03 08:37:08 -0200921 goto out;
Fabio Utzig39000012018-07-30 12:40:20 -0300922 }
923
Fabio Utzig10ee6482019-08-01 12:04:52 -0300924 if (hdr->ih_magic != IMAGE_MAGIC || boot_image_check(state, hdr, fap, bs)) {
David Vincze2d736ad2019-02-18 11:50:22 +0100925 if (slot != BOOT_PRIMARY_SLOT) {
David Brownb38e0442017-02-24 13:57:12 -0700926 flash_area_erase(fap, 0, fap->fa_size);
David Vincze2d736ad2019-02-18 11:50:22 +0100927 /* Image in the secondary slot is invalid. Erase the image and
928 * continue booting from the primary slot.
David Brownb38e0442017-02-24 13:57:12 -0700929 */
930 }
David Vincze2d736ad2019-02-18 11:50:22 +0100931 BOOT_LOG_ERR("Image in the %s slot is not valid!",
932 (slot == BOOT_PRIMARY_SLOT) ? "primary" : "secondary");
Fabio Utzig338a19f2018-12-03 08:37:08 -0200933 rc = -1;
934 goto out;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800935 }
936
David Vincze2d736ad2019-02-18 11:50:22 +0100937 /* Image in the secondary slot is valid. */
Fabio Utzig338a19f2018-12-03 08:37:08 -0200938 rc = 0;
939
940out:
941 flash_area_close(fap);
942 return rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800943}
944
945/**
946 * Determines which swap operation to perform, if any. If it is determined
David Vincze2d736ad2019-02-18 11:50:22 +0100947 * that a swap operation is required, the image in the secondary slot is checked
948 * for validity. If the image in the secondary slot is invalid, it is erased,
949 * and a swap type of "none" is indicated.
Christopher Collins92ea77f2016-12-12 15:59:26 -0800950 *
951 * @return The type of swap to perform (BOOT_SWAP_TYPE...)
952 */
953static int
Fabio Utzig10ee6482019-08-01 12:04:52 -0300954boot_validated_swap_type(struct boot_loader_state *state,
955 struct boot_status *bs)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800956{
957 int swap_type;
Fabio Utzigb1adb1e2019-09-11 11:42:53 -0300958 int rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800959
Fabio Utzigb0f04732019-07-31 09:49:19 -0300960 swap_type = boot_swap_type_multi(BOOT_CURR_IMG(state));
Fabio Utzige575b0b2019-09-11 12:34:23 -0300961 if (BOOT_IS_UPGRADE(swap_type)) {
David Vincze2d736ad2019-02-18 11:50:22 +0100962 /* Boot loader wants to switch to the secondary slot.
963 * Ensure image is valid.
964 */
Fabio Utzigb1adb1e2019-09-11 11:42:53 -0300965 rc = boot_validate_slot(state, BOOT_SECONDARY_SLOT, bs);
966 if (rc == 1) {
967 swap_type = BOOT_SWAP_TYPE_NONE;
968 } else if (rc != 0) {
Fabio Utzigb5b2f552017-06-30 10:03:47 -0300969 swap_type = BOOT_SWAP_TYPE_FAIL;
970 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800971 }
972
973 return swap_type;
974}
975
976/**
977 * Calculates the number of sectors the scratch area can contain. A "last"
978 * source sector is specified because images are copied backwards in flash
979 * (final index to index number 0).
980 *
981 * @param last_sector_idx The index of the last source sector
982 * (inclusive).
983 * @param out_first_sector_idx The index of the first source sector
984 * (inclusive) gets written here.
985 *
986 * @return The number of bytes comprised by the
987 * [first-sector, last-sector] range.
988 */
Fabio Utzig3488eef2017-06-12 10:25:43 -0300989#ifndef MCUBOOT_OVERWRITE_ONLY
Christopher Collins92ea77f2016-12-12 15:59:26 -0800990static uint32_t
Fabio Utzig10ee6482019-08-01 12:04:52 -0300991boot_copy_sz(struct boot_loader_state *state, int last_sector_idx,
992 int *out_first_sector_idx)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800993{
Marti Bolivard3269fd2017-06-12 16:31:12 -0400994 size_t scratch_sz;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800995 uint32_t new_sz;
996 uint32_t sz;
997 int i;
998
999 sz = 0;
1000
Fabio Utzig10ee6482019-08-01 12:04:52 -03001001 scratch_sz = boot_scratch_area_size(state);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001002 for (i = last_sector_idx; i >= 0; i--) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001003 new_sz = sz + boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i);
Fabio Utzig2bd980a2018-11-26 10:38:17 -02001004 /*
David Vincze2d736ad2019-02-18 11:50:22 +01001005 * The secondary slot is not being checked here, because
1006 * `boot_slots_compatible` already provides assurance that the copy size
1007 * will be compatible with the primary slot and scratch.
Fabio Utzig2bd980a2018-11-26 10:38:17 -02001008 */
Marti Bolivard3269fd2017-06-12 16:31:12 -04001009 if (new_sz > scratch_sz) {
Christopher Collins92ea77f2016-12-12 15:59:26 -08001010 break;
1011 }
1012 sz = new_sz;
1013 }
1014
1015 /* i currently refers to a sector that doesn't fit or it is -1 because all
1016 * sectors have been processed. In both cases, exclude sector i.
1017 */
1018 *out_first_sector_idx = i + 1;
1019 return sz;
1020}
Fabio Utzig3488eef2017-06-12 10:25:43 -03001021#endif /* !MCUBOOT_OVERWRITE_ONLY */
Christopher Collins92ea77f2016-12-12 15:59:26 -08001022
1023/**
1024 * Erases a region of flash.
1025 *
Fabio Utzigba829042018-09-18 08:29:34 -03001026 * @param flash_area The flash_area containing the region to erase.
Christopher Collins92ea77f2016-12-12 15:59:26 -08001027 * @param off The offset within the flash area to start the
1028 * erase.
1029 * @param sz The number of bytes to erase.
1030 *
1031 * @return 0 on success; nonzero on failure.
1032 */
Fabio Utzigba829042018-09-18 08:29:34 -03001033static inline int
Fabio Utzigc28005b2019-09-10 12:18:29 -03001034boot_erase_region(const struct flash_area *fap, uint32_t off, uint32_t sz)
Christopher Collins92ea77f2016-12-12 15:59:26 -08001035{
Fabio Utzigba829042018-09-18 08:29:34 -03001036 return flash_area_erase(fap, off, sz);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001037}
1038
1039/**
1040 * Copies the contents of one flash region to another. You must erase the
1041 * destination region prior to calling this function.
1042 *
1043 * @param flash_area_id_src The ID of the source flash area.
1044 * @param flash_area_id_dst The ID of the destination flash area.
1045 * @param off_src The offset within the source flash area to
1046 * copy from.
1047 * @param off_dst The offset within the destination flash area to
1048 * copy to.
1049 * @param sz The number of bytes to copy.
1050 *
1051 * @return 0 on success; nonzero on failure.
1052 */
1053static int
Fabio Utzigc28005b2019-09-10 12:18:29 -03001054boot_copy_region(struct boot_loader_state *state,
Fabio Utzig10ee6482019-08-01 12:04:52 -03001055 const struct flash_area *fap_src,
Fabio Utzigba829042018-09-18 08:29:34 -03001056 const struct flash_area *fap_dst,
Christopher Collins92ea77f2016-12-12 15:59:26 -08001057 uint32_t off_src, uint32_t off_dst, uint32_t sz)
1058{
Christopher Collins92ea77f2016-12-12 15:59:26 -08001059 uint32_t bytes_copied;
1060 int chunk_sz;
1061 int rc;
Fabio Utzigba829042018-09-18 08:29:34 -03001062#ifdef MCUBOOT_ENC_IMAGES
1063 uint32_t off;
Fabio Utziga87cc7d2019-08-26 11:21:45 -03001064 uint32_t tlv_off;
Fabio Utzigba829042018-09-18 08:29:34 -03001065 size_t blk_off;
1066 struct image_header *hdr;
1067 uint16_t idx;
1068 uint32_t blk_sz;
Fabio Utzigb0f04732019-07-31 09:49:19 -03001069 uint8_t image_index;
Fabio Utzigba829042018-09-18 08:29:34 -03001070#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -08001071
Fabio Utzig10ee6482019-08-01 12:04:52 -03001072 TARGET_STATIC uint8_t buf[1024];
1073
1074#if !defined(MCUBOOT_ENC_IMAGES)
1075 (void)state;
1076#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -08001077
Christopher Collins92ea77f2016-12-12 15:59:26 -08001078 bytes_copied = 0;
1079 while (bytes_copied < sz) {
1080 if (sz - bytes_copied > sizeof buf) {
1081 chunk_sz = sizeof buf;
1082 } else {
1083 chunk_sz = sz - bytes_copied;
1084 }
1085
1086 rc = flash_area_read(fap_src, off_src + bytes_copied, buf, chunk_sz);
1087 if (rc != 0) {
Fabio Utzigba829042018-09-18 08:29:34 -03001088 return BOOT_EFLASH;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001089 }
1090
Fabio Utzigba829042018-09-18 08:29:34 -03001091#ifdef MCUBOOT_ENC_IMAGES
Fabio Utzig10ee6482019-08-01 12:04:52 -03001092 image_index = BOOT_CURR_IMG(state);
Fabio Utzigb0f04732019-07-31 09:49:19 -03001093 if (fap_src->fa_id == FLASH_AREA_IMAGE_SECONDARY(image_index) ||
1094 fap_dst->fa_id == FLASH_AREA_IMAGE_SECONDARY(image_index)) {
David Vincze2d736ad2019-02-18 11:50:22 +01001095 /* assume the secondary slot as src, needs decryption */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001096 hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT);
Fabio Utzigba829042018-09-18 08:29:34 -03001097 off = off_src;
Fabio Utzigb0f04732019-07-31 09:49:19 -03001098 if (fap_dst->fa_id == FLASH_AREA_IMAGE_SECONDARY(image_index)) {
David Vincze2d736ad2019-02-18 11:50:22 +01001099 /* might need encryption (metadata from the primary slot) */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001100 hdr = boot_img_hdr(state, BOOT_PRIMARY_SLOT);
Fabio Utzigba829042018-09-18 08:29:34 -03001101 off = off_dst;
1102 }
Fabio Utzig2fc80df2018-12-14 06:47:38 -02001103 if (IS_ENCRYPTED(hdr)) {
Fabio Utzigba829042018-09-18 08:29:34 -03001104 blk_sz = chunk_sz;
1105 idx = 0;
1106 if (off + bytes_copied < hdr->ih_hdr_size) {
1107 /* do not decrypt header */
1108 blk_off = 0;
1109 blk_sz = chunk_sz - hdr->ih_hdr_size;
1110 idx = hdr->ih_hdr_size;
1111 } else {
1112 blk_off = ((off + bytes_copied) - hdr->ih_hdr_size) & 0xf;
1113 }
Fabio Utziga87cc7d2019-08-26 11:21:45 -03001114 tlv_off = BOOT_TLV_OFF(hdr);
1115 if (off + bytes_copied + chunk_sz > tlv_off) {
Fabio Utzigba829042018-09-18 08:29:34 -03001116 /* do not decrypt TLVs */
Fabio Utziga87cc7d2019-08-26 11:21:45 -03001117 if (off + bytes_copied >= tlv_off) {
Fabio Utzigba829042018-09-18 08:29:34 -03001118 blk_sz = 0;
1119 } else {
Fabio Utziga87cc7d2019-08-26 11:21:45 -03001120 blk_sz = tlv_off - (off + bytes_copied);
Fabio Utzigba829042018-09-18 08:29:34 -03001121 }
1122 }
Fabio Utzig1e4284b2019-08-23 11:55:27 -03001123 boot_encrypt(BOOT_CURR_ENC(state), image_index, fap_src,
Fabio Utzigb0f04732019-07-31 09:49:19 -03001124 (off + bytes_copied + idx) - hdr->ih_hdr_size, blk_sz,
1125 blk_off, &buf[idx]);
Fabio Utzigba829042018-09-18 08:29:34 -03001126 }
1127 }
1128#endif
1129
Christopher Collins92ea77f2016-12-12 15:59:26 -08001130 rc = flash_area_write(fap_dst, off_dst + bytes_copied, buf, chunk_sz);
1131 if (rc != 0) {
Fabio Utzigba829042018-09-18 08:29:34 -03001132 return BOOT_EFLASH;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001133 }
1134
1135 bytes_copied += chunk_sz;
Fabio Utzig853657c2019-05-07 08:06:07 -03001136
1137 MCUBOOT_WATCHDOG_FEED();
Christopher Collins92ea77f2016-12-12 15:59:26 -08001138 }
1139
Fabio Utzigba829042018-09-18 08:29:34 -03001140 return 0;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001141}
1142
David Brown6b1b3b92017-09-19 08:59:10 -06001143#ifndef MCUBOOT_OVERWRITE_ONLY
Fabio Utzig2473ac02017-05-02 12:45:02 -03001144static inline int
Fabio Utzig10ee6482019-08-01 12:04:52 -03001145boot_status_init(const struct boot_loader_state *state,
1146 const struct flash_area *fap,
1147 const struct boot_status *bs)
Fabio Utzig2473ac02017-05-02 12:45:02 -03001148{
Fabio Utzig2473ac02017-05-02 12:45:02 -03001149 struct boot_swap_state swap_state;
Fabio Utzigb0f04732019-07-31 09:49:19 -03001150 uint8_t image_index;
Fabio Utzig2473ac02017-05-02 12:45:02 -03001151 int rc;
1152
Fabio Utzig10ee6482019-08-01 12:04:52 -03001153#if (BOOT_IMAGE_NUMBER == 1)
1154 (void)state;
1155#endif
1156
1157 image_index = BOOT_CURR_IMG(state);
Fabio Utzigb0f04732019-07-31 09:49:19 -03001158
Christopher Collins2c88e692019-05-22 15:10:14 -07001159 BOOT_LOG_DBG("initializing status; fa_id=%d", fap->fa_id);
1160
Fabio Utzigb0f04732019-07-31 09:49:19 -03001161 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SECONDARY(image_index),
1162 &swap_state);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001163 assert(rc == 0);
1164
Christopher Collinsa1c12042019-05-23 14:00:28 -07001165 if (bs->swap_type != BOOT_SWAP_TYPE_NONE) {
Fabio Utzigb0f04732019-07-31 09:49:19 -03001166 rc = boot_write_swap_info(fap, bs->swap_type, image_index);
Christopher Collinsa1c12042019-05-23 14:00:28 -07001167 assert(rc == 0);
1168 }
1169
Fabio Utzigde8a38a2017-05-23 11:15:01 -04001170 if (swap_state.image_ok == BOOT_FLAG_SET) {
Fabio Utzig2473ac02017-05-02 12:45:02 -03001171 rc = boot_write_image_ok(fap);
1172 assert(rc == 0);
1173 }
1174
Fabio Utzig46490722017-09-04 15:34:32 -03001175 rc = boot_write_swap_size(fap, bs->swap_size);
1176 assert(rc == 0);
1177
Fabio Utzigba829042018-09-18 08:29:34 -03001178#ifdef MCUBOOT_ENC_IMAGES
1179 rc = boot_write_enc_key(fap, 0, bs->enckey[0]);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001180 assert(rc == 0);
1181
Fabio Utzigba829042018-09-18 08:29:34 -03001182 rc = boot_write_enc_key(fap, 1, bs->enckey[1]);
1183 assert(rc == 0);
1184#endif
1185
1186 rc = boot_write_magic(fap);
1187 assert(rc == 0);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001188
1189 return 0;
1190}
Christopher Collinsa1c12042019-05-23 14:00:28 -07001191
David Brown6b1b3b92017-09-19 08:59:10 -06001192#endif
Fabio Utzig2473ac02017-05-02 12:45:02 -03001193
Fabio Utzig358c9352017-07-25 22:10:45 -03001194#ifndef MCUBOOT_OVERWRITE_ONLY
Fabio Utzig2473ac02017-05-02 12:45:02 -03001195static int
Fabio Utzig10ee6482019-08-01 12:04:52 -03001196boot_erase_trailer_sectors(const struct boot_loader_state *state,
1197 const struct flash_area *fap)
Fabio Utzig2473ac02017-05-02 12:45:02 -03001198{
1199 uint8_t slot;
Fabio Utziged0ca432019-01-23 14:50:11 -02001200 uint32_t sector;
1201 uint32_t trailer_sz;
1202 uint32_t total_sz;
1203 uint32_t off;
1204 uint32_t sz;
David Vinczeb75c12a2019-03-22 14:58:33 +01001205 int fa_id_primary;
1206 int fa_id_secondary;
Fabio Utzigb0f04732019-07-31 09:49:19 -03001207 uint8_t image_index;
Fabio Utzig2473ac02017-05-02 12:45:02 -03001208 int rc;
1209
Christopher Collins2c88e692019-05-22 15:10:14 -07001210 BOOT_LOG_DBG("erasing trailer; fa_id=%d", fap->fa_id);
1211
Fabio Utzig10ee6482019-08-01 12:04:52 -03001212 image_index = BOOT_CURR_IMG(state);
Fabio Utzigb0f04732019-07-31 09:49:19 -03001213 fa_id_primary = flash_area_id_from_multi_image_slot(image_index,
1214 BOOT_PRIMARY_SLOT);
1215 fa_id_secondary = flash_area_id_from_multi_image_slot(image_index,
1216 BOOT_SECONDARY_SLOT);
David Vinczeb75c12a2019-03-22 14:58:33 +01001217
1218 if (fap->fa_id == fa_id_primary) {
David Vincze2d736ad2019-02-18 11:50:22 +01001219 slot = BOOT_PRIMARY_SLOT;
David Vinczeb75c12a2019-03-22 14:58:33 +01001220 } else if (fap->fa_id == fa_id_secondary) {
David Vincze2d736ad2019-02-18 11:50:22 +01001221 slot = BOOT_SECONDARY_SLOT;
David Vinczeb75c12a2019-03-22 14:58:33 +01001222 } else {
Fabio Utzig2473ac02017-05-02 12:45:02 -03001223 return BOOT_EFLASH;
1224 }
1225
Fabio Utziged0ca432019-01-23 14:50:11 -02001226 /* delete starting from last sector and moving to beginning */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001227 sector = boot_img_num_sectors(state, slot) - 1;
1228 trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(state));
Fabio Utziged0ca432019-01-23 14:50:11 -02001229 total_sz = 0;
1230 do {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001231 sz = boot_img_sector_size(state, slot, sector);
1232 off = boot_img_sector_off(state, slot, sector);
Fabio Utzigc28005b2019-09-10 12:18:29 -03001233 rc = boot_erase_region(fap, off, sz);
Fabio Utziged0ca432019-01-23 14:50:11 -02001234 assert(rc == 0);
1235
1236 sector--;
1237 total_sz += sz;
1238 } while (total_sz < trailer_sz);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001239
1240 return rc;
1241}
Fabio Utzig358c9352017-07-25 22:10:45 -03001242#endif /* !MCUBOOT_OVERWRITE_ONLY */
Fabio Utzig2473ac02017-05-02 12:45:02 -03001243
Christopher Collins92ea77f2016-12-12 15:59:26 -08001244/**
1245 * Swaps the contents of two flash regions within the two image slots.
1246 *
1247 * @param idx The index of the first sector in the range of
1248 * sectors being swapped.
1249 * @param sz The number of bytes to swap.
1250 * @param bs The current boot status. This struct gets
1251 * updated according to the outcome.
1252 *
1253 * @return 0 on success; nonzero on failure.
1254 */
Fabio Utzig3488eef2017-06-12 10:25:43 -03001255#ifndef MCUBOOT_OVERWRITE_ONLY
Christopher Collins4772ac42017-02-27 20:08:01 -08001256static void
Fabio Utzig10ee6482019-08-01 12:04:52 -03001257boot_swap_sectors(int idx, uint32_t sz, struct boot_loader_state *state,
1258 struct boot_status *bs)
Christopher Collins92ea77f2016-12-12 15:59:26 -08001259{
David Vincze2d736ad2019-02-18 11:50:22 +01001260 const struct flash_area *fap_primary_slot;
1261 const struct flash_area *fap_secondary_slot;
Fabio Utzigba829042018-09-18 08:29:34 -03001262 const struct flash_area *fap_scratch;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001263 uint32_t copy_sz;
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001264 uint32_t trailer_sz;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001265 uint32_t img_off;
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001266 uint32_t scratch_trailer_off;
1267 struct boot_swap_state swap_state;
Marti Bolivard3269fd2017-06-12 16:31:12 -04001268 size_t last_sector;
Christopher Collinsa1c12042019-05-23 14:00:28 -07001269 bool erase_scratch;
Fabio Utzigb0f04732019-07-31 09:49:19 -03001270 uint8_t image_index;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001271 int rc;
1272
1273 /* Calculate offset from start of image area. */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001274 img_off = boot_img_sector_off(state, BOOT_PRIMARY_SLOT, idx);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001275
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001276 copy_sz = sz;
Fabio Utzig10ee6482019-08-01 12:04:52 -03001277 trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(state));
Fabio Utzig9678c972017-05-23 11:28:56 -04001278
Fabio Utzig2bd980a2018-11-26 10:38:17 -02001279 /* sz in this function is always sized on a multiple of the sector size.
1280 * The check against the start offset of the last sector
Fabio Utzig9678c972017-05-23 11:28:56 -04001281 * is to determine if we're swapping the last sector. The last sector
1282 * needs special handling because it's where the trailer lives. If we're
1283 * copying it, we need to use scratch to write the trailer temporarily.
1284 *
1285 * NOTE: `use_scratch` is a temporary flag (never written to flash) which
1286 * controls if special handling is needed (swapping last sector).
1287 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001288 last_sector = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT) - 1;
David Vinczeba3bd602019-06-17 16:01:43 +02001289 if ((img_off + sz) >
Fabio Utzig10ee6482019-08-01 12:04:52 -03001290 boot_img_sector_off(state, BOOT_PRIMARY_SLOT, last_sector)) {
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001291 copy_sz -= trailer_sz;
1292 }
1293
Fabio Utzig39000012018-07-30 12:40:20 -03001294 bs->use_scratch = (bs->idx == BOOT_STATUS_IDX_0 && copy_sz != sz);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001295
Fabio Utzig10ee6482019-08-01 12:04:52 -03001296 image_index = BOOT_CURR_IMG(state);
Fabio Utzigb0f04732019-07-31 09:49:19 -03001297
1298 rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index),
1299 &fap_primary_slot);
Fabio Utzigba829042018-09-18 08:29:34 -03001300 assert (rc == 0);
1301
Fabio Utzigb0f04732019-07-31 09:49:19 -03001302 rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY(image_index),
1303 &fap_secondary_slot);
Fabio Utzigba829042018-09-18 08:29:34 -03001304 assert (rc == 0);
1305
1306 rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH, &fap_scratch);
1307 assert (rc == 0);
1308
Fabio Utzig39000012018-07-30 12:40:20 -03001309 if (bs->state == BOOT_STATUS_STATE_0) {
Christopher Collins2c88e692019-05-22 15:10:14 -07001310 BOOT_LOG_DBG("erasing scratch area");
Fabio Utzigc28005b2019-09-10 12:18:29 -03001311 rc = boot_erase_region(fap_scratch, 0, fap_scratch->fa_size);
Christopher Collins4772ac42017-02-27 20:08:01 -08001312 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001313
Fabio Utzig39000012018-07-30 12:40:20 -03001314 if (bs->idx == BOOT_STATUS_IDX_0) {
Christopher Collinsa1c12042019-05-23 14:00:28 -07001315 /* Write a trailer to the scratch area, even if we don't need the
1316 * scratch area for status. We need a temporary place to store the
1317 * `swap-type` while we erase the primary trailer.
1318 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001319 rc = boot_status_init(state, fap_scratch, bs);
Christopher Collinsa1c12042019-05-23 14:00:28 -07001320 assert(rc == 0);
1321
1322 if (!bs->use_scratch) {
1323 /* Prepare the primary status area... here it is known that the
1324 * last sector is not being used by the image data so it's safe
1325 * to erase.
Fabio Utzig2473ac02017-05-02 12:45:02 -03001326 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001327 rc = boot_erase_trailer_sectors(state, fap_primary_slot);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001328 assert(rc == 0);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001329
Fabio Utzig10ee6482019-08-01 12:04:52 -03001330 rc = boot_status_init(state, fap_primary_slot, bs);
Christopher Collinsa1c12042019-05-23 14:00:28 -07001331 assert(rc == 0);
1332
1333 /* Erase the temporary trailer from the scratch area. */
Fabio Utzigc28005b2019-09-10 12:18:29 -03001334 rc = boot_erase_region(fap_scratch, 0, fap_scratch->fa_size);
Christopher Collinsa1c12042019-05-23 14:00:28 -07001335 assert(rc == 0);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001336 }
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001337 }
1338
Fabio Utzigc28005b2019-09-10 12:18:29 -03001339 rc = boot_copy_region(state, fap_secondary_slot, fap_scratch,
Christopher Collinsa1c12042019-05-23 14:00:28 -07001340 img_off, 0, copy_sz);
1341 assert(rc == 0);
1342
Fabio Utzig10ee6482019-08-01 12:04:52 -03001343 rc = boot_write_status(state, bs);
Fabio Utzig4d7396d2019-09-05 18:38:05 -03001344 bs->state = BOOT_STATUS_STATE_1;
Fabio Utziga0e1cce2017-11-23 20:04:01 -02001345 BOOT_STATUS_ASSERT(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001346 }
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001347
Fabio Utzig39000012018-07-30 12:40:20 -03001348 if (bs->state == BOOT_STATUS_STATE_1) {
Fabio Utzigc28005b2019-09-10 12:18:29 -03001349 rc = boot_erase_region(fap_secondary_slot, img_off, sz);
Christopher Collins4772ac42017-02-27 20:08:01 -08001350 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001351
Fabio Utzigc28005b2019-09-10 12:18:29 -03001352 rc = boot_copy_region(state, fap_primary_slot, fap_secondary_slot,
David Vincze2d736ad2019-02-18 11:50:22 +01001353 img_off, img_off, copy_sz);
Christopher Collins4772ac42017-02-27 20:08:01 -08001354 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001355
Fabio Utzig39000012018-07-30 12:40:20 -03001356 if (bs->idx == BOOT_STATUS_IDX_0 && !bs->use_scratch) {
Fabio Utzig2473ac02017-05-02 12:45:02 -03001357 /* If not all sectors of the slot are being swapped,
David Vincze2d736ad2019-02-18 11:50:22 +01001358 * guarantee here that only the primary slot will have the state.
Fabio Utzig2473ac02017-05-02 12:45:02 -03001359 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001360 rc = boot_erase_trailer_sectors(state, fap_secondary_slot);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001361 assert(rc == 0);
1362 }
1363
Fabio Utzig10ee6482019-08-01 12:04:52 -03001364 rc = boot_write_status(state, bs);
Fabio Utzig4d7396d2019-09-05 18:38:05 -03001365 bs->state = BOOT_STATUS_STATE_2;
Fabio Utziga0e1cce2017-11-23 20:04:01 -02001366 BOOT_STATUS_ASSERT(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001367 }
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001368
Fabio Utzig39000012018-07-30 12:40:20 -03001369 if (bs->state == BOOT_STATUS_STATE_2) {
Fabio Utzigc28005b2019-09-10 12:18:29 -03001370 rc = boot_erase_region(fap_primary_slot, img_off, sz);
Christopher Collins4772ac42017-02-27 20:08:01 -08001371 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001372
Christopher Collinsa1c12042019-05-23 14:00:28 -07001373 /* NOTE: If this is the final sector, we exclude the image trailer from
1374 * this copy (copy_sz was truncated earlier).
1375 */
Fabio Utzigc28005b2019-09-10 12:18:29 -03001376 rc = boot_copy_region(state, fap_scratch, fap_primary_slot,
David Vincze2d736ad2019-02-18 11:50:22 +01001377 0, img_off, copy_sz);
Christopher Collins4772ac42017-02-27 20:08:01 -08001378 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001379
Fabio Utzig94d998c2017-05-22 11:02:41 -04001380 if (bs->use_scratch) {
Fabio Utzigba829042018-09-18 08:29:34 -03001381 scratch_trailer_off = boot_status_off(fap_scratch);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001382
1383 /* copy current status that is being maintained in scratch */
Fabio Utzigc28005b2019-09-10 12:18:29 -03001384 rc = boot_copy_region(state, fap_scratch, fap_primary_slot,
David Vincze2d736ad2019-02-18 11:50:22 +01001385 scratch_trailer_off, img_off + copy_sz,
Fabio Utzig4d7396d2019-09-05 18:38:05 -03001386 (BOOT_STATUS_STATE_COUNT - 1) * BOOT_WRITE_SZ(state));
Fabio Utziga0e1cce2017-11-23 20:04:01 -02001387 BOOT_STATUS_ASSERT(rc == 0);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001388
Fabio Utzig2473ac02017-05-02 12:45:02 -03001389 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SCRATCH,
1390 &swap_state);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001391 assert(rc == 0);
1392
Fabio Utzigde8a38a2017-05-23 11:15:01 -04001393 if (swap_state.image_ok == BOOT_FLAG_SET) {
David Vincze2d736ad2019-02-18 11:50:22 +01001394 rc = boot_write_image_ok(fap_primary_slot);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001395 assert(rc == 0);
1396 }
1397
Christopher Collinsa1c12042019-05-23 14:00:28 -07001398 if (swap_state.swap_type != BOOT_SWAP_TYPE_NONE) {
David Vinczee2453472019-06-17 12:31:59 +02001399 rc = boot_write_swap_info(fap_primary_slot,
Fabio Utzigb0f04732019-07-31 09:49:19 -03001400 swap_state.swap_type, image_index);
Christopher Collinsa1c12042019-05-23 14:00:28 -07001401 assert(rc == 0);
1402 }
1403
David Vincze2d736ad2019-02-18 11:50:22 +01001404 rc = boot_write_swap_size(fap_primary_slot, bs->swap_size);
Fabio Utzig46490722017-09-04 15:34:32 -03001405 assert(rc == 0);
1406
Fabio Utzigba829042018-09-18 08:29:34 -03001407#ifdef MCUBOOT_ENC_IMAGES
David Vincze2d736ad2019-02-18 11:50:22 +01001408 rc = boot_write_enc_key(fap_primary_slot, 0, bs->enckey[0]);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001409 assert(rc == 0);
1410
David Vincze2d736ad2019-02-18 11:50:22 +01001411 rc = boot_write_enc_key(fap_primary_slot, 1, bs->enckey[1]);
Fabio Utzigba829042018-09-18 08:29:34 -03001412 assert(rc == 0);
1413#endif
David Vincze2d736ad2019-02-18 11:50:22 +01001414 rc = boot_write_magic(fap_primary_slot);
Fabio Utzigba829042018-09-18 08:29:34 -03001415 assert(rc == 0);
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001416 }
1417
Christopher Collinsa1c12042019-05-23 14:00:28 -07001418 /* If we wrote a trailer to the scratch area, erase it after we persist
1419 * a trailer to the primary slot. We do this to prevent mcuboot from
1420 * reading a stale status from the scratch area in case of immediate
1421 * reset.
1422 */
1423 erase_scratch = bs->use_scratch;
1424 bs->use_scratch = 0;
1425
Fabio Utzig4d7396d2019-09-05 18:38:05 -03001426 rc = boot_write_status(state, bs);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001427 bs->idx++;
Fabio Utzig39000012018-07-30 12:40:20 -03001428 bs->state = BOOT_STATUS_STATE_0;
Fabio Utziga0e1cce2017-11-23 20:04:01 -02001429 BOOT_STATUS_ASSERT(rc == 0);
Christopher Collinsa1c12042019-05-23 14:00:28 -07001430
1431 if (erase_scratch) {
Fabio Utzigc28005b2019-09-10 12:18:29 -03001432 rc = boot_erase_region(fap_scratch, 0, sz);
Christopher Collinsa1c12042019-05-23 14:00:28 -07001433 assert(rc == 0);
1434 }
Christopher Collins92ea77f2016-12-12 15:59:26 -08001435 }
Fabio Utzigba829042018-09-18 08:29:34 -03001436
David Vincze2d736ad2019-02-18 11:50:22 +01001437 flash_area_close(fap_primary_slot);
1438 flash_area_close(fap_secondary_slot);
Fabio Utzigba829042018-09-18 08:29:34 -03001439 flash_area_close(fap_scratch);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001440}
Fabio Utzig3488eef2017-06-12 10:25:43 -03001441#endif /* !MCUBOOT_OVERWRITE_ONLY */
Christopher Collins92ea77f2016-12-12 15:59:26 -08001442
1443/**
David Vincze2d736ad2019-02-18 11:50:22 +01001444 * Overwrite primary slot with the image contained in the secondary slot.
1445 * If a prior copy operation was interrupted by a system reset, this function
1446 * redos the copy.
Christopher Collins92ea77f2016-12-12 15:59:26 -08001447 *
1448 * @param bs The current boot status. This function reads
1449 * this struct to determine if it is resuming
1450 * an interrupted swap operation. This
1451 * function writes the updated status to this
1452 * function on return.
1453 *
1454 * @return 0 on success; nonzero on failure.
1455 */
Fabio Utzig338a19f2018-12-03 08:37:08 -02001456#if defined(MCUBOOT_OVERWRITE_ONLY) || defined(MCUBOOT_BOOTSTRAP)
David Brown17609d82017-05-05 09:41:34 -06001457static int
Fabio Utzig10ee6482019-08-01 12:04:52 -03001458boot_copy_image(struct boot_loader_state *state, struct boot_status *bs)
David Brown17609d82017-05-05 09:41:34 -06001459{
Marti Bolivard3269fd2017-06-12 16:31:12 -04001460 size_t sect_count;
1461 size_t sect;
David Brown17609d82017-05-05 09:41:34 -06001462 int rc;
Fabio Utzig13d9e352017-10-05 20:32:31 -03001463 size_t size;
Marti Bolivard3269fd2017-06-12 16:31:12 -04001464 size_t this_size;
Fabio Utzig13d9e352017-10-05 20:32:31 -03001465 size_t last_sector;
David Vincze2d736ad2019-02-18 11:50:22 +01001466 const struct flash_area *fap_primary_slot;
1467 const struct flash_area *fap_secondary_slot;
Fabio Utzigb0f04732019-07-31 09:49:19 -03001468 uint8_t image_index;
David Vincze2d736ad2019-02-18 11:50:22 +01001469
Fabio Utzigaaf767c2017-12-05 10:22:46 -02001470 (void)bs;
1471
Fabio Utzig13d9e352017-10-05 20:32:31 -03001472#if defined(MCUBOOT_OVERWRITE_ONLY_FAST)
1473 uint32_t src_size = 0;
Fabio Utzigd638b172019-08-09 10:38:05 -03001474 rc = boot_read_image_size(state, BOOT_SECONDARY_SLOT, &src_size);
Fabio Utzig13d9e352017-10-05 20:32:31 -03001475 assert(rc == 0);
1476#endif
David Brown17609d82017-05-05 09:41:34 -06001477
David Vincze2d736ad2019-02-18 11:50:22 +01001478 BOOT_LOG_INF("Image upgrade secondary slot -> primary slot");
1479 BOOT_LOG_INF("Erasing the primary slot");
David Brown17609d82017-05-05 09:41:34 -06001480
Fabio Utzigb0f04732019-07-31 09:49:19 -03001481 image_index = BOOT_CURR_IMG(state);
1482
1483 rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index),
1484 &fap_primary_slot);
Fabio Utzigba829042018-09-18 08:29:34 -03001485 assert (rc == 0);
1486
Fabio Utzigb0f04732019-07-31 09:49:19 -03001487 rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY(image_index),
1488 &fap_secondary_slot);
Fabio Utzigba829042018-09-18 08:29:34 -03001489 assert (rc == 0);
1490
Fabio Utzig10ee6482019-08-01 12:04:52 -03001491 sect_count = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT);
Fabio Utzig13d9e352017-10-05 20:32:31 -03001492 for (sect = 0, size = 0; sect < sect_count; sect++) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001493 this_size = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, sect);
Fabio Utzigc28005b2019-09-10 12:18:29 -03001494 rc = boot_erase_region(fap_primary_slot, size, this_size);
David Brown17609d82017-05-05 09:41:34 -06001495 assert(rc == 0);
1496
1497 size += this_size;
Fabio Utzig13d9e352017-10-05 20:32:31 -03001498
1499#if defined(MCUBOOT_OVERWRITE_ONLY_FAST)
1500 if (size >= src_size) {
1501 break;
1502 }
1503#endif
David Brown17609d82017-05-05 09:41:34 -06001504 }
1505
Fabio Utzigba829042018-09-18 08:29:34 -03001506#ifdef MCUBOOT_ENC_IMAGES
Fabio Utzig10ee6482019-08-01 12:04:52 -03001507 if (IS_ENCRYPTED(boot_img_hdr(state, BOOT_SECONDARY_SLOT))) {
Fabio Utzig1e4284b2019-08-23 11:55:27 -03001508 rc = boot_enc_load(BOOT_CURR_ENC(state), image_index,
Fabio Utzig10ee6482019-08-01 12:04:52 -03001509 boot_img_hdr(state, BOOT_SECONDARY_SLOT),
Fabio Utzigb0f04732019-07-31 09:49:19 -03001510 fap_secondary_slot, bs->enckey[1]);
David Vincze2d736ad2019-02-18 11:50:22 +01001511
Fabio Utzigba829042018-09-18 08:29:34 -03001512 if (rc < 0) {
1513 return BOOT_EBADIMAGE;
1514 }
Fabio Utzig1e4284b2019-08-23 11:55:27 -03001515 if (rc == 0 && boot_enc_set_key(BOOT_CURR_ENC(state), 1, bs->enckey[1])) {
Fabio Utzigba829042018-09-18 08:29:34 -03001516 return BOOT_EBADIMAGE;
1517 }
1518 }
1519#endif
1520
David Vincze2d736ad2019-02-18 11:50:22 +01001521 BOOT_LOG_INF("Copying the secondary slot to the primary slot: 0x%zx bytes",
1522 size);
Fabio Utzigc28005b2019-09-10 12:18:29 -03001523 rc = boot_copy_region(state, fap_secondary_slot, fap_primary_slot, 0, 0, size);
David Brown17609d82017-05-05 09:41:34 -06001524
Fabio Utzig13d9e352017-10-05 20:32:31 -03001525 /*
1526 * Erases header and trailer. The trailer is erased because when a new
1527 * image is written without a trailer as is the case when using newt, the
1528 * trailer that was left might trigger a new upgrade.
1529 */
Christopher Collins2c88e692019-05-22 15:10:14 -07001530 BOOT_LOG_DBG("erasing secondary header");
Fabio Utzigc28005b2019-09-10 12:18:29 -03001531 rc = boot_erase_region(fap_secondary_slot,
Fabio Utzig10ee6482019-08-01 12:04:52 -03001532 boot_img_sector_off(state, BOOT_SECONDARY_SLOT, 0),
1533 boot_img_sector_size(state, BOOT_SECONDARY_SLOT, 0));
David Brown17609d82017-05-05 09:41:34 -06001534 assert(rc == 0);
Fabio Utzig10ee6482019-08-01 12:04:52 -03001535 last_sector = boot_img_num_sectors(state, BOOT_SECONDARY_SLOT) - 1;
Christopher Collins2c88e692019-05-22 15:10:14 -07001536 BOOT_LOG_DBG("erasing secondary trailer");
Fabio Utzigc28005b2019-09-10 12:18:29 -03001537 rc = boot_erase_region(fap_secondary_slot,
Fabio Utzig10ee6482019-08-01 12:04:52 -03001538 boot_img_sector_off(state, BOOT_SECONDARY_SLOT,
1539 last_sector),
1540 boot_img_sector_size(state, BOOT_SECONDARY_SLOT,
1541 last_sector));
Fabio Utzig13d9e352017-10-05 20:32:31 -03001542 assert(rc == 0);
1543
David Vincze2d736ad2019-02-18 11:50:22 +01001544 flash_area_close(fap_primary_slot);
1545 flash_area_close(fap_secondary_slot);
Fabio Utzigba829042018-09-18 08:29:34 -03001546
David Vincze2d736ad2019-02-18 11:50:22 +01001547 /* TODO: Perhaps verify the primary slot's signature again? */
David Brown17609d82017-05-05 09:41:34 -06001548
1549 return 0;
1550}
Fabio Utzig338a19f2018-12-03 08:37:08 -02001551#endif
Fabio Utzigba829042018-09-18 08:29:34 -03001552
Christopher Collinsa1c12042019-05-23 14:00:28 -07001553#if !defined(MCUBOOT_OVERWRITE_ONLY)
Fabio Utzigba829042018-09-18 08:29:34 -03001554/**
1555 * Swaps the two images in flash. If a prior copy operation was interrupted
1556 * by a system reset, this function completes that operation.
1557 *
1558 * @param bs The current boot status. This function reads
1559 * this struct to determine if it is resuming
1560 * an interrupted swap operation. This
1561 * function writes the updated status to this
1562 * function on return.
1563 *
1564 * @return 0 on success; nonzero on failure.
1565 */
Christopher Collins92ea77f2016-12-12 15:59:26 -08001566static int
Fabio Utzig10ee6482019-08-01 12:04:52 -03001567boot_swap_image(struct boot_loader_state *state, struct boot_status *bs)
Christopher Collins92ea77f2016-12-12 15:59:26 -08001568{
1569 uint32_t sz;
1570 int first_sector_idx;
1571 int last_sector_idx;
David Vincze2d736ad2019-02-18 11:50:22 +01001572 int last_idx_secondary_slot;
Fabio Utzigcd5774b2017-11-29 10:18:26 -02001573 uint32_t swap_idx;
Fabio Utzig2473ac02017-05-02 12:45:02 -03001574 struct image_header *hdr;
Fabio Utzigba829042018-09-18 08:29:34 -03001575#ifdef MCUBOOT_ENC_IMAGES
1576 const struct flash_area *fap;
1577 uint8_t slot;
1578 uint8_t i;
Fabio Utzigba829042018-09-18 08:29:34 -03001579#endif
Fabio Utzig2473ac02017-05-02 12:45:02 -03001580 uint32_t size;
1581 uint32_t copy_size;
David Vincze2d736ad2019-02-18 11:50:22 +01001582 uint32_t primary_slot_size;
1583 uint32_t secondary_slot_size;
Fabio Utzigb0f04732019-07-31 09:49:19 -03001584 uint8_t image_index;
Fabio Utzig2473ac02017-05-02 12:45:02 -03001585 int rc;
1586
1587 /* FIXME: just do this if asked by user? */
1588
1589 size = copy_size = 0;
Fabio Utzig10ee6482019-08-01 12:04:52 -03001590 image_index = BOOT_CURR_IMG(state);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001591
Fabio Utzig39000012018-07-30 12:40:20 -03001592 if (bs->idx == BOOT_STATUS_IDX_0 && bs->state == BOOT_STATUS_STATE_0) {
Fabio Utzig46490722017-09-04 15:34:32 -03001593 /*
1594 * No swap ever happened, so need to find the largest image which
1595 * will be used to determine the amount of sectors to swap.
1596 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001597 hdr = boot_img_hdr(state, BOOT_PRIMARY_SLOT);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001598 if (hdr->ih_magic == IMAGE_MAGIC) {
Fabio Utzigd638b172019-08-09 10:38:05 -03001599 rc = boot_read_image_size(state, BOOT_PRIMARY_SLOT, &copy_size);
David Brownf5b33d82017-09-01 10:58:27 -06001600 assert(rc == 0);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001601 }
Fabio Utzig2473ac02017-05-02 12:45:02 -03001602
Fabio Utzigba829042018-09-18 08:29:34 -03001603#ifdef MCUBOOT_ENC_IMAGES
Fabio Utzig2fc80df2018-12-14 06:47:38 -02001604 if (IS_ENCRYPTED(hdr)) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001605 fap = BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT);
Fabio Utzig1e4284b2019-08-23 11:55:27 -03001606 rc = boot_enc_load(BOOT_CURR_ENC(state), image_index, hdr, fap, bs->enckey[0]);
Fabio Utzigba829042018-09-18 08:29:34 -03001607 assert(rc >= 0);
1608
1609 if (rc == 0) {
Fabio Utzig1e4284b2019-08-23 11:55:27 -03001610 rc = boot_enc_set_key(BOOT_CURR_ENC(state), 0, bs->enckey[0]);
Fabio Utzigba829042018-09-18 08:29:34 -03001611 assert(rc == 0);
1612 } else {
1613 rc = 0;
1614 }
1615 } else {
1616 memset(bs->enckey[0], 0xff, BOOT_ENC_KEY_SIZE);
1617 }
1618#endif
1619
Fabio Utzig10ee6482019-08-01 12:04:52 -03001620 hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT);
Fabio Utzig46490722017-09-04 15:34:32 -03001621 if (hdr->ih_magic == IMAGE_MAGIC) {
Fabio Utzigd638b172019-08-09 10:38:05 -03001622 rc = boot_read_image_size(state, BOOT_SECONDARY_SLOT, &size);
Fabio Utzig46490722017-09-04 15:34:32 -03001623 assert(rc == 0);
1624 }
1625
Fabio Utzigba829042018-09-18 08:29:34 -03001626#ifdef MCUBOOT_ENC_IMAGES
Fabio Utzig10ee6482019-08-01 12:04:52 -03001627 hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT);
Fabio Utzig2fc80df2018-12-14 06:47:38 -02001628 if (IS_ENCRYPTED(hdr)) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001629 fap = BOOT_IMG_AREA(state, BOOT_SECONDARY_SLOT);
Fabio Utzig1e4284b2019-08-23 11:55:27 -03001630 rc = boot_enc_load(BOOT_CURR_ENC(state), image_index, hdr, fap, bs->enckey[1]);
Fabio Utzigba829042018-09-18 08:29:34 -03001631 assert(rc >= 0);
1632
1633 if (rc == 0) {
Fabio Utzig1e4284b2019-08-23 11:55:27 -03001634 rc = boot_enc_set_key(BOOT_CURR_ENC(state), 1, bs->enckey[1]);
Fabio Utzigba829042018-09-18 08:29:34 -03001635 assert(rc == 0);
1636 } else {
1637 rc = 0;
1638 }
1639 } else {
1640 memset(bs->enckey[1], 0xff, BOOT_ENC_KEY_SIZE);
1641 }
1642#endif
1643
Fabio Utzig46490722017-09-04 15:34:32 -03001644 if (size > copy_size) {
1645 copy_size = size;
1646 }
1647
1648 bs->swap_size = copy_size;
1649 } else {
1650 /*
1651 * If a swap was under way, the swap_size should already be present
1652 * in the trailer...
1653 */
Fabio Utzigb0f04732019-07-31 09:49:19 -03001654 rc = boot_read_swap_size(image_index, &bs->swap_size);
Fabio Utzig46490722017-09-04 15:34:32 -03001655 assert(rc == 0);
1656
1657 copy_size = bs->swap_size;
Fabio Utzigba829042018-09-18 08:29:34 -03001658
1659#ifdef MCUBOOT_ENC_IMAGES
1660 for (slot = 0; slot <= 1; slot++) {
Fabio Utzigb0f04732019-07-31 09:49:19 -03001661 rc = boot_read_enc_key(image_index, slot, bs->enckey[slot]);
Fabio Utzigba829042018-09-18 08:29:34 -03001662 assert(rc == 0);
1663
1664 for (i = 0; i < BOOT_ENC_KEY_SIZE; i++) {
Fabio Utzig1c7d9592018-12-03 10:35:56 -02001665 if (bs->enckey[slot][i] != 0xff) {
Fabio Utzigba829042018-09-18 08:29:34 -03001666 break;
1667 }
1668 }
1669
1670 if (i != BOOT_ENC_KEY_SIZE) {
Fabio Utzig1e4284b2019-08-23 11:55:27 -03001671 boot_enc_set_key(BOOT_CURR_ENC(state), slot, bs->enckey[slot]);
Fabio Utzigba829042018-09-18 08:29:34 -03001672 }
1673 }
1674#endif
Fabio Utzig2473ac02017-05-02 12:45:02 -03001675 }
1676
David Vincze2d736ad2019-02-18 11:50:22 +01001677 primary_slot_size = 0;
1678 secondary_slot_size = 0;
Fabio Utzig2473ac02017-05-02 12:45:02 -03001679 last_sector_idx = 0;
David Vincze2d736ad2019-02-18 11:50:22 +01001680 last_idx_secondary_slot = 0;
Fabio Utzig2bd980a2018-11-26 10:38:17 -02001681
1682 /*
1683 * Knowing the size of the largest image between both slots, here we
David Vincze2d736ad2019-02-18 11:50:22 +01001684 * find what is the last sector in the primary slot that needs swapping.
1685 * Since we already know that both slots are compatible, the secondary
1686 * slot's last sector is not really required after this check is finished.
Fabio Utzig2bd980a2018-11-26 10:38:17 -02001687 */
Fabio Utzig2473ac02017-05-02 12:45:02 -03001688 while (1) {
David Vincze2d736ad2019-02-18 11:50:22 +01001689 if ((primary_slot_size < copy_size) ||
1690 (primary_slot_size < secondary_slot_size)) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001691 primary_slot_size += boot_img_sector_size(state,
David Vincze2d736ad2019-02-18 11:50:22 +01001692 BOOT_PRIMARY_SLOT,
1693 last_sector_idx);
Fabio Utzig2bd980a2018-11-26 10:38:17 -02001694 }
David Vincze2d736ad2019-02-18 11:50:22 +01001695 if ((secondary_slot_size < copy_size) ||
1696 (secondary_slot_size < primary_slot_size)) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001697 secondary_slot_size += boot_img_sector_size(state,
David Vincze2d736ad2019-02-18 11:50:22 +01001698 BOOT_SECONDARY_SLOT,
1699 last_idx_secondary_slot);
Fabio Utzig2bd980a2018-11-26 10:38:17 -02001700 }
David Vincze2d736ad2019-02-18 11:50:22 +01001701 if (primary_slot_size >= copy_size &&
1702 secondary_slot_size >= copy_size &&
1703 primary_slot_size == secondary_slot_size) {
Fabio Utzig2473ac02017-05-02 12:45:02 -03001704 break;
1705 }
1706 last_sector_idx++;
David Vincze2d736ad2019-02-18 11:50:22 +01001707 last_idx_secondary_slot++;
Fabio Utzig2473ac02017-05-02 12:45:02 -03001708 }
Christopher Collins92ea77f2016-12-12 15:59:26 -08001709
1710 swap_idx = 0;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001711 while (last_sector_idx >= 0) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001712 sz = boot_copy_sz(state, last_sector_idx, &first_sector_idx);
Fabio Utzig39000012018-07-30 12:40:20 -03001713 if (swap_idx >= (bs->idx - BOOT_STATUS_IDX_0)) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001714 boot_swap_sectors(first_sector_idx, sz, state, bs);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001715 }
1716
1717 last_sector_idx = first_sector_idx - 1;
1718 swap_idx++;
1719 }
1720
David Vincze2d736ad2019-02-18 11:50:22 +01001721#ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT
Fabio Utziga0e1cce2017-11-23 20:04:01 -02001722 if (boot_status_fails > 0) {
Christopher Collins2c88e692019-05-22 15:10:14 -07001723 BOOT_LOG_WRN("%d status write fails performing the swap",
1724 boot_status_fails);
Fabio Utziga0e1cce2017-11-23 20:04:01 -02001725 }
1726#endif
1727
Christopher Collins92ea77f2016-12-12 15:59:26 -08001728 return 0;
1729}
David Brown17609d82017-05-05 09:41:34 -06001730#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -08001731
1732/**
David Vincze2d736ad2019-02-18 11:50:22 +01001733 * Marks the image in the primary slot as fully copied.
Christopher Collins92ea77f2016-12-12 15:59:26 -08001734 */
Fabio Utzig8d0e5882017-09-13 17:32:44 -03001735#ifndef MCUBOOT_OVERWRITE_ONLY
Christopher Collins92ea77f2016-12-12 15:59:26 -08001736static int
Fabio Utzig10ee6482019-08-01 12:04:52 -03001737boot_set_copy_done(uint8_t image_index)
Christopher Collins92ea77f2016-12-12 15:59:26 -08001738{
1739 const struct flash_area *fap;
1740 int rc;
1741
Fabio Utzigb0f04732019-07-31 09:49:19 -03001742 rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index),
1743 &fap);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001744 if (rc != 0) {
1745 return BOOT_EFLASH;
1746 }
1747
1748 rc = boot_write_copy_done(fap);
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03001749 flash_area_close(fap);
1750 return rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001751}
Fabio Utzig8d0e5882017-09-13 17:32:44 -03001752#endif /* !MCUBOOT_OVERWRITE_ONLY */
Christopher Collins92ea77f2016-12-12 15:59:26 -08001753
1754/**
David Vincze2d736ad2019-02-18 11:50:22 +01001755 * Marks a reverted image in the primary slot as confirmed. This is necessary to
1756 * ensure the status bytes from the image revert operation don't get processed
1757 * on a subsequent boot.
Fabio Utzig1e56fcc2017-07-17 15:39:14 -03001758 *
1759 * NOTE: image_ok is tested before writing because if there's a valid permanent
David Vincze2d736ad2019-02-18 11:50:22 +01001760 * image installed on the primary slot and the new image to be upgrade to has a
1761 * bad sig, image_ok would be overwritten.
Christopher Collins92ea77f2016-12-12 15:59:26 -08001762 */
Fabio Utzig8d0e5882017-09-13 17:32:44 -03001763#ifndef MCUBOOT_OVERWRITE_ONLY
Christopher Collins92ea77f2016-12-12 15:59:26 -08001764static int
Fabio Utzig10ee6482019-08-01 12:04:52 -03001765boot_set_image_ok(uint8_t image_index)
Christopher Collins92ea77f2016-12-12 15:59:26 -08001766{
1767 const struct flash_area *fap;
Fabio Utzig1e56fcc2017-07-17 15:39:14 -03001768 struct boot_swap_state state;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001769 int rc;
1770
Fabio Utzigb0f04732019-07-31 09:49:19 -03001771 rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index),
1772 &fap);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001773 if (rc != 0) {
1774 return BOOT_EFLASH;
1775 }
1776
Fabio Utzig1e56fcc2017-07-17 15:39:14 -03001777 rc = boot_read_swap_state(fap, &state);
1778 if (rc != 0) {
1779 rc = BOOT_EFLASH;
1780 goto out;
1781 }
1782
1783 if (state.image_ok == BOOT_FLAG_UNSET) {
1784 rc = boot_write_image_ok(fap);
1785 }
1786
1787out:
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03001788 flash_area_close(fap);
1789 return rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001790}
Fabio Utzig8d0e5882017-09-13 17:32:44 -03001791#endif /* !MCUBOOT_OVERWRITE_ONLY */
Christopher Collins92ea77f2016-12-12 15:59:26 -08001792
David Vinczee32483f2019-06-13 10:46:24 +02001793#if (BOOT_IMAGE_NUMBER > 1)
1794/**
Fabio Utzig019a81a2019-08-27 10:33:39 -03001795 * Check if the version of the image is not older than required.
1796 *
1797 * @param req Required minimal image version.
1798 * @param ver Version of the image to be checked.
1799 *
1800 * @return 0 if the version is sufficient, nonzero otherwise.
1801 */
1802static int
1803boot_is_version_sufficient(struct image_version *req,
1804 struct image_version *ver)
1805{
1806 if (ver->iv_major > req->iv_major) {
1807 return 0;
1808 }
1809 if (ver->iv_major < req->iv_major) {
1810 return BOOT_EBADVERSION;
1811 }
1812 /* The major version numbers are equal. */
1813 if (ver->iv_minor > req->iv_minor) {
1814 return 0;
1815 }
1816 if (ver->iv_minor < req->iv_minor) {
1817 return BOOT_EBADVERSION;
1818 }
1819 /* The minor version numbers are equal. */
1820 if (ver->iv_revision < req->iv_revision) {
1821 return BOOT_EBADVERSION;
1822 }
1823
1824 return 0;
1825}
1826
1827/**
David Vinczee32483f2019-06-13 10:46:24 +02001828 * Check the image dependency whether it is satisfied and modify
1829 * the swap type if necessary.
1830 *
1831 * @param dep Image dependency which has to be verified.
1832 *
1833 * @return 0 on success; nonzero on failure.
1834 */
1835static int
Fabio Utzig298913b2019-08-28 11:22:45 -03001836boot_verify_slot_dependency(struct boot_loader_state *state,
1837 struct image_dependency *dep)
David Vinczee32483f2019-06-13 10:46:24 +02001838{
1839 struct image_version *dep_version;
1840 size_t dep_slot;
1841 int rc;
David Browne6ab34c2019-09-03 12:24:21 -06001842 uint8_t swap_type;
David Vinczee32483f2019-06-13 10:46:24 +02001843
1844 /* Determine the source of the image which is the subject of
1845 * the dependency and get it's version. */
David Browne6ab34c2019-09-03 12:24:21 -06001846 swap_type = state->swap_type[dep->image_id];
Fabio Utzigb1adb1e2019-09-11 11:42:53 -03001847 dep_slot = (swap_type != BOOT_SWAP_TYPE_NONE) ?
David Vinczee32483f2019-06-13 10:46:24 +02001848 BOOT_SECONDARY_SLOT : BOOT_PRIMARY_SLOT;
Fabio Utzig10ee6482019-08-01 12:04:52 -03001849 dep_version = &state->imgs[dep->image_id][dep_slot].hdr.ih_ver;
David Vinczee32483f2019-06-13 10:46:24 +02001850
1851 rc = boot_is_version_sufficient(&dep->image_min_version, dep_version);
1852 if (rc != 0) {
1853 /* Dependency not satisfied.
1854 * Modify the swap type to decrease the version number of the image
1855 * (which will be located in the primary slot after the boot process),
1856 * consequently the number of unsatisfied dependencies will be
1857 * decreased or remain the same.
1858 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001859 switch (BOOT_SWAP_TYPE(state)) {
David Vinczee32483f2019-06-13 10:46:24 +02001860 case BOOT_SWAP_TYPE_TEST:
1861 case BOOT_SWAP_TYPE_PERM:
Fabio Utzig10ee6482019-08-01 12:04:52 -03001862 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
David Vinczee32483f2019-06-13 10:46:24 +02001863 break;
1864 case BOOT_SWAP_TYPE_NONE:
Fabio Utzig10ee6482019-08-01 12:04:52 -03001865 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_REVERT;
David Vinczee32483f2019-06-13 10:46:24 +02001866 break;
1867 default:
1868 break;
1869 }
1870 }
1871
1872 return rc;
1873}
1874
1875/**
1876 * Read all dependency TLVs of an image from the flash and verify
1877 * one after another to see if they are all satisfied.
1878 *
1879 * @param slot Image slot number.
1880 *
1881 * @return 0 on success; nonzero on failure.
1882 */
1883static int
Fabio Utzig298913b2019-08-28 11:22:45 -03001884boot_verify_slot_dependencies(struct boot_loader_state *state, uint32_t slot)
David Vinczee32483f2019-06-13 10:46:24 +02001885{
1886 const struct flash_area *fap;
David Vinczee32483f2019-06-13 10:46:24 +02001887 struct image_tlv tlv;
1888 struct image_dependency dep;
1889 uint32_t off;
1890 uint32_t end;
1891 bool dep_tlvs_found = false;
Fabio Utzigb0f04732019-07-31 09:49:19 -03001892 int area_id;
David Vinczee32483f2019-06-13 10:46:24 +02001893 int rc;
1894
Fabio Utzig10ee6482019-08-01 12:04:52 -03001895 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
Fabio Utzigb0f04732019-07-31 09:49:19 -03001896 rc = flash_area_open(area_id, &fap);
David Vinczee32483f2019-06-13 10:46:24 +02001897 if (rc != 0) {
1898 rc = BOOT_EFLASH;
1899 goto done;
1900 }
1901
Fabio Utzig233af7d2019-08-26 12:06:16 -03001902 rc = boot_find_tlv_offs(boot_img_hdr(state, slot), fap, &off, &end);
David Vinczee32483f2019-06-13 10:46:24 +02001903 if (rc != 0) {
David Vinczee32483f2019-06-13 10:46:24 +02001904 goto done;
1905 }
1906
David Vinczee32483f2019-06-13 10:46:24 +02001907 /* Traverse through all of the TLVs to find the dependency TLVs. */
1908 for (; off < end; off += sizeof(tlv) + tlv.it_len) {
1909 rc = flash_area_read(fap, off, &tlv, sizeof(tlv));
1910 if (rc != 0) {
1911 rc = BOOT_EFLASH;
1912 goto done;
1913 }
1914
1915 if (tlv.it_type == IMAGE_TLV_DEPENDENCY) {
Fabio Utzig298913b2019-08-28 11:22:45 -03001916 dep_tlvs_found = true;
David Vinczee32483f2019-06-13 10:46:24 +02001917
1918 if (tlv.it_len != sizeof(dep)) {
1919 rc = BOOT_EBADIMAGE;
1920 goto done;
1921 }
1922
1923 rc = flash_area_read(fap, off + sizeof(tlv), &dep, tlv.it_len);
1924 if (rc != 0) {
1925 rc = BOOT_EFLASH;
1926 goto done;
1927 }
1928
Fabio Utzig298913b2019-08-28 11:22:45 -03001929 if (dep.image_id >= BOOT_IMAGE_NUMBER) {
1930 rc = BOOT_EBADARGS;
1931 goto done;
1932 }
1933
David Vinczee32483f2019-06-13 10:46:24 +02001934 /* Verify dependency and modify the swap type if not satisfied. */
Fabio Utzig298913b2019-08-28 11:22:45 -03001935 rc = boot_verify_slot_dependency(state, &dep);
David Vinczee32483f2019-06-13 10:46:24 +02001936 if (rc != 0) {
1937 /* Dependency not satisfied. */
1938 goto done;
1939 }
1940
1941 /* Dependency satisfied, no action needed.
1942 * Continue with the next TLV entry.
1943 */
1944 } else if (dep_tlvs_found) {
1945 /* The dependency TLVs are contiguous in the TLV area. If a
1946 * dependency had already been found and the last read TLV
1947 * has a different type then there are no more dependency TLVs.
1948 * The search can be finished.
1949 */
1950 break;
1951 }
1952 }
1953
1954done:
1955 flash_area_close(fap);
1956 return rc;
1957}
1958
1959/**
David Vinczee32483f2019-06-13 10:46:24 +02001960 * Iterate over all the images and verify whether the image dependencies in the
1961 * TLV area are all satisfied and update the related swap type if necessary.
1962 */
Fabio Utzig298913b2019-08-28 11:22:45 -03001963static int
1964boot_verify_dependencies(struct boot_loader_state *state)
David Vinczee32483f2019-06-13 10:46:24 +02001965{
David Vinczee32483f2019-06-13 10:46:24 +02001966 int rc;
Fabio Utzig298913b2019-08-28 11:22:45 -03001967 uint8_t slot;
David Vinczee32483f2019-06-13 10:46:24 +02001968
Fabio Utzig10ee6482019-08-01 12:04:52 -03001969 BOOT_CURR_IMG(state) = 0;
1970 while (BOOT_CURR_IMG(state) < BOOT_IMAGE_NUMBER) {
Fabio Utzig298913b2019-08-28 11:22:45 -03001971 if (BOOT_SWAP_TYPE(state) != BOOT_SWAP_TYPE_NONE &&
1972 BOOT_SWAP_TYPE(state) != BOOT_SWAP_TYPE_FAIL) {
1973 slot = BOOT_SECONDARY_SLOT;
1974 } else {
1975 slot = BOOT_PRIMARY_SLOT;
1976 }
1977
1978 rc = boot_verify_slot_dependencies(state, slot);
Fabio Utzigabec0732019-07-31 08:40:22 -03001979 if (rc == 0) {
David Vinczee32483f2019-06-13 10:46:24 +02001980 /* All dependencies've been satisfied, continue with next image. */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001981 BOOT_CURR_IMG(state)++;
David Vinczee32483f2019-06-13 10:46:24 +02001982 } else if (rc == BOOT_EBADVERSION) {
Fabio Utzig298913b2019-08-28 11:22:45 -03001983 /* Cannot upgrade due to non-met dependencies, so disable all
1984 * image upgrades.
1985 */
1986 for (int idx = 0; idx < BOOT_IMAGE_NUMBER; idx++) {
1987 BOOT_CURR_IMG(state) = idx;
1988 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
1989 }
1990 break;
David Vinczee32483f2019-06-13 10:46:24 +02001991 } else {
1992 /* Other error happened, images are inconsistent */
Fabio Utzig298913b2019-08-28 11:22:45 -03001993 return rc;
David Vinczee32483f2019-06-13 10:46:24 +02001994 }
1995 }
Fabio Utzig298913b2019-08-28 11:22:45 -03001996 return rc;
David Vinczee32483f2019-06-13 10:46:24 +02001997}
1998#endif /* (BOOT_IMAGE_NUMBER > 1) */
1999
Christopher Collins92ea77f2016-12-12 15:59:26 -08002000/**
David Vinczeba3bd602019-06-17 16:01:43 +02002001 * Performs a clean (not aborted) image update.
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08002002 *
David Vinczeba3bd602019-06-17 16:01:43 +02002003 * @param bs The current boot status.
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08002004 *
2005 * @return 0 on success; nonzero on failure.
2006 */
2007static int
Fabio Utzig10ee6482019-08-01 12:04:52 -03002008boot_perform_update(struct boot_loader_state *state, struct boot_status *bs)
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08002009{
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08002010 int rc;
Fabio Utzig10ee6482019-08-01 12:04:52 -03002011#ifndef MCUBOOT_OVERWRITE_ONLY
2012 uint8_t swap_type;
2013#endif
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08002014
David Vinczeba3bd602019-06-17 16:01:43 +02002015 /* At this point there are no aborted swaps. */
2016#if defined(MCUBOOT_OVERWRITE_ONLY)
Fabio Utzig10ee6482019-08-01 12:04:52 -03002017 rc = boot_copy_image(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02002018#elif defined(MCUBOOT_BOOTSTRAP)
2019 /* Check if the image update was triggered by a bad image in the
2020 * primary slot (the validity of the image in the secondary slot had
2021 * already been checked).
2022 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002023 if (boot_check_header_erased(state, BOOT_PRIMARY_SLOT) == 0 ||
2024 boot_validate_slot(state, BOOT_PRIMARY_SLOT, bs) != 0) {
2025 rc = boot_copy_image(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02002026 } else {
Fabio Utzig10ee6482019-08-01 12:04:52 -03002027 rc = boot_swap_image(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02002028 }
2029#else
Fabio Utzig10ee6482019-08-01 12:04:52 -03002030 rc = boot_swap_image(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02002031#endif
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03002032 assert(rc == 0);
David Vinczeba3bd602019-06-17 16:01:43 +02002033
2034#ifndef MCUBOOT_OVERWRITE_ONLY
2035 /* The following state needs image_ok be explicitly set after the
2036 * swap was finished to avoid a new revert.
2037 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002038 swap_type = BOOT_SWAP_TYPE(state);
2039 if (swap_type == BOOT_SWAP_TYPE_REVERT ||
2040 swap_type == BOOT_SWAP_TYPE_PERM) {
2041 rc = boot_set_image_ok(BOOT_CURR_IMG(state));
David Vinczeba3bd602019-06-17 16:01:43 +02002042 if (rc != 0) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03002043 BOOT_SWAP_TYPE(state) = swap_type = BOOT_SWAP_TYPE_PANIC;
David Vinczeba3bd602019-06-17 16:01:43 +02002044 }
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08002045 }
2046
Fabio Utzige575b0b2019-09-11 12:34:23 -03002047 if (BOOT_IS_UPGRADE(swap_type)) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03002048 rc = boot_set_copy_done(BOOT_CURR_IMG(state));
David Vinczeba3bd602019-06-17 16:01:43 +02002049 if (rc != 0) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03002050 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
Christopher Collinsa1c12042019-05-23 14:00:28 -07002051 }
David Vinczeba3bd602019-06-17 16:01:43 +02002052 }
2053#endif /* !MCUBOOT_OVERWRITE_ONLY */
Fabio Utzig338a19f2018-12-03 08:37:08 -02002054
David Vinczeba3bd602019-06-17 16:01:43 +02002055 return rc;
2056}
2057
2058/**
2059 * Completes a previously aborted image swap.
2060 *
2061 * @param bs The current boot status.
2062 *
2063 * @return 0 on success; nonzero on failure.
2064 */
2065#if !defined(MCUBOOT_OVERWRITE_ONLY)
2066static int
Fabio Utzig10ee6482019-08-01 12:04:52 -03002067boot_complete_partial_swap(struct boot_loader_state *state,
2068 struct boot_status *bs)
David Vinczeba3bd602019-06-17 16:01:43 +02002069{
2070 int rc;
2071
2072 /* Determine the type of swap operation being resumed from the
2073 * `swap-type` trailer field.
2074 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002075 rc = boot_swap_image(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02002076 assert(rc == 0);
2077
Fabio Utzig10ee6482019-08-01 12:04:52 -03002078 BOOT_SWAP_TYPE(state) = bs->swap_type;
David Vinczeba3bd602019-06-17 16:01:43 +02002079
2080 /* The following states need image_ok be explicitly set after the
2081 * swap was finished to avoid a new revert.
2082 */
2083 if (bs->swap_type == BOOT_SWAP_TYPE_REVERT ||
2084 bs->swap_type == BOOT_SWAP_TYPE_PERM) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03002085 rc = boot_set_image_ok(BOOT_CURR_IMG(state));
David Vinczeba3bd602019-06-17 16:01:43 +02002086 if (rc != 0) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03002087 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
David Vinczeba3bd602019-06-17 16:01:43 +02002088 }
2089 }
2090
Fabio Utzige575b0b2019-09-11 12:34:23 -03002091 if (BOOT_IS_UPGRADE(bs->swap_type)) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03002092 rc = boot_set_copy_done(BOOT_CURR_IMG(state));
David Vinczeba3bd602019-06-17 16:01:43 +02002093 if (rc != 0) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03002094 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
David Vinczeba3bd602019-06-17 16:01:43 +02002095 }
2096 }
2097
Fabio Utzig10ee6482019-08-01 12:04:52 -03002098 if (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_PANIC) {
David Vinczeba3bd602019-06-17 16:01:43 +02002099 BOOT_LOG_ERR("panic!");
2100 assert(0);
2101
2102 /* Loop forever... */
2103 while (1) {}
2104 }
2105
2106 return rc;
2107}
2108#endif /* !MCUBOOT_OVERWRITE_ONLY */
2109
2110#if (BOOT_IMAGE_NUMBER > 1)
2111/**
2112 * Review the validity of previously determined swap types of other images.
2113 *
2114 * @param aborted_swap The current image upgrade is a
2115 * partial/aborted swap.
2116 */
2117static void
Fabio Utzig10ee6482019-08-01 12:04:52 -03002118boot_review_image_swap_types(struct boot_loader_state *state,
2119 bool aborted_swap)
David Vinczeba3bd602019-06-17 16:01:43 +02002120{
2121 /* In that case if we rebooted in the middle of an image upgrade process, we
2122 * must review the validity of swap types, that were previously determined
2123 * for other images. The image_ok flag had not been set before the reboot
2124 * for any of the updated images (only the copy_done flag) and thus falsely
2125 * the REVERT swap type has been determined for the previous images that had
2126 * been updated before the reboot.
2127 *
2128 * There are two separate scenarios that we have to deal with:
2129 *
2130 * 1. The reboot has happened during swapping an image:
2131 * The current image upgrade has been determined as a
2132 * partial/aborted swap.
2133 * 2. The reboot has happened between two separate image upgrades:
2134 * In this scenario we must check the swap type of the current image.
2135 * In those cases if it is NONE or REVERT we cannot certainly determine
2136 * the fact of a reboot. In a consistent state images must move in the
2137 * same direction or stay in place, e.g. in practice REVERT and TEST
2138 * swap types cannot be present at the same time. If the swap type of
2139 * the current image is either TEST, PERM or FAIL we must review the
2140 * already determined swap types of other images and set each false
2141 * REVERT swap types to NONE (these images had been successfully
2142 * updated before the system rebooted between two separate image
2143 * upgrades).
2144 */
2145
Fabio Utzig10ee6482019-08-01 12:04:52 -03002146 if (BOOT_CURR_IMG(state) == 0) {
David Vinczeba3bd602019-06-17 16:01:43 +02002147 /* Nothing to do */
2148 return;
2149 }
2150
2151 if (!aborted_swap) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03002152 if ((BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_NONE) ||
2153 (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_REVERT)) {
David Vinczeba3bd602019-06-17 16:01:43 +02002154 /* Nothing to do */
2155 return;
2156 }
2157 }
2158
Fabio Utzig10ee6482019-08-01 12:04:52 -03002159 for (uint8_t i = 0; i < BOOT_CURR_IMG(state); i++) {
2160 if (state->swap_type[i] == BOOT_SWAP_TYPE_REVERT) {
2161 state->swap_type[i] = BOOT_SWAP_TYPE_NONE;
David Vinczeba3bd602019-06-17 16:01:43 +02002162 }
2163 }
2164}
2165#endif
2166
2167/**
2168 * Prepare image to be updated if required.
2169 *
2170 * Prepare image to be updated if required with completing an image swap
2171 * operation if one was aborted and/or determining the type of the
2172 * swap operation. In case of any error set the swap type to NONE.
2173 *
Fabio Utzig10ee6482019-08-01 12:04:52 -03002174 * @param state TODO
David Vinczeba3bd602019-06-17 16:01:43 +02002175 * @param bs Pointer where the read and possibly updated
2176 * boot status can be written to.
2177 */
2178static void
Fabio Utzig10ee6482019-08-01 12:04:52 -03002179boot_prepare_image_for_update(struct boot_loader_state *state,
2180 struct boot_status *bs)
David Vinczeba3bd602019-06-17 16:01:43 +02002181{
2182 int rc;
2183
2184 /* Determine the sector layout of the image slots and scratch area. */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002185 rc = boot_read_sectors(state);
David Vinczeba3bd602019-06-17 16:01:43 +02002186 if (rc != 0) {
2187 BOOT_LOG_WRN("Failed reading sectors; BOOT_MAX_IMG_SECTORS=%d"
2188 " - too small?", BOOT_MAX_IMG_SECTORS);
2189 /* Unable to determine sector layout, continue with next image
2190 * if there is one.
2191 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002192 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
David Vinczeba3bd602019-06-17 16:01:43 +02002193 return;
2194 }
2195
2196 /* Attempt to read an image header from each slot. */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002197 rc = boot_read_image_headers(state, false);
David Vinczeba3bd602019-06-17 16:01:43 +02002198 if (rc != 0) {
2199 /* Continue with next image if there is one. */
Fabio Utzigb0f04732019-07-31 09:49:19 -03002200 BOOT_LOG_WRN("Failed reading image headers; Image=%u",
Fabio Utzig10ee6482019-08-01 12:04:52 -03002201 BOOT_CURR_IMG(state));
2202 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
David Vinczeba3bd602019-06-17 16:01:43 +02002203 return;
2204 }
2205
2206 /* If the current image's slots aren't compatible, no swap is possible.
2207 * Just boot into primary slot.
2208 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002209 if (boot_slots_compatible(state)) {
2210 rc = boot_read_status(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02002211 if (rc != 0) {
2212 BOOT_LOG_WRN("Failed reading boot status; Image=%u",
Fabio Utzig10ee6482019-08-01 12:04:52 -03002213 BOOT_CURR_IMG(state));
David Vinczeba3bd602019-06-17 16:01:43 +02002214 /* Continue with next image if there is one. */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002215 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
David Vinczeba3bd602019-06-17 16:01:43 +02002216 return;
2217 }
2218
2219 /* Determine if we rebooted in the middle of an image swap
2220 * operation. If a partial swap was detected, complete it.
2221 */
2222 if (bs->idx != BOOT_STATUS_IDX_0 || bs->state != BOOT_STATUS_STATE_0) {
2223
2224#if (BOOT_IMAGE_NUMBER > 1)
Fabio Utzig10ee6482019-08-01 12:04:52 -03002225 boot_review_image_swap_types(state, true);
David Vinczeba3bd602019-06-17 16:01:43 +02002226#endif
2227
2228#ifdef MCUBOOT_OVERWRITE_ONLY
2229 /* Should never arrive here, overwrite-only mode has
2230 * no swap state.
2231 */
2232 assert(0);
2233#else
2234 /* Determine the type of swap operation being resumed from the
2235 * `swap-type` trailer field.
2236 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002237 rc = boot_complete_partial_swap(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02002238 assert(rc == 0);
2239#endif
2240 /* Attempt to read an image header from each slot. Ensure that
2241 * image headers in slots are aligned with headers in boot_data.
2242 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002243 rc = boot_read_image_headers(state, false);
David Vinczeba3bd602019-06-17 16:01:43 +02002244 assert(rc == 0);
2245
2246 /* Swap has finished set to NONE */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002247 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
David Vinczeba3bd602019-06-17 16:01:43 +02002248 } else {
2249 /* There was no partial swap, determine swap type. */
2250 if (bs->swap_type == BOOT_SWAP_TYPE_NONE) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03002251 BOOT_SWAP_TYPE(state) = boot_validated_swap_type(state, bs);
2252 } else if (boot_validate_slot(state, BOOT_SECONDARY_SLOT, bs) != 0) {
2253 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_FAIL;
David Vinczeba3bd602019-06-17 16:01:43 +02002254 } else {
Fabio Utzig10ee6482019-08-01 12:04:52 -03002255 BOOT_SWAP_TYPE(state) = bs->swap_type;
David Vinczeba3bd602019-06-17 16:01:43 +02002256 }
2257
2258#if (BOOT_IMAGE_NUMBER > 1)
Fabio Utzig10ee6482019-08-01 12:04:52 -03002259 boot_review_image_swap_types(state, false);
David Vinczeba3bd602019-06-17 16:01:43 +02002260#endif
2261
2262#ifdef MCUBOOT_BOOTSTRAP
Fabio Utzig10ee6482019-08-01 12:04:52 -03002263 if (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_NONE) {
David Vinczeba3bd602019-06-17 16:01:43 +02002264 /* Header checks are done first because they are
2265 * inexpensive. Since overwrite-only copies starting from
2266 * offset 0, if interrupted, it might leave a valid header
2267 * magic, so also run validation on the primary slot to be
2268 * sure it's not OK.
2269 */
Fabio Utzig59b63e52019-09-10 12:22:35 -03002270 if (boot_check_header_erased(state, BOOT_PRIMARY_SLOT) == 0 ||
2271 boot_validate_slot(state, BOOT_PRIMARY_SLOT, bs) != 0) {
2272 if (boot_img_hdr(state,
2273 BOOT_SECONDARY_SLOT)->ih_magic == IMAGE_MAGIC &&
2274 boot_validate_slot(state, BOOT_SECONDARY_SLOT, bs) == 0) {
David Vinczeba3bd602019-06-17 16:01:43 +02002275 /* Set swap type to REVERT to overwrite the primary
2276 * slot with the image contained in secondary slot
2277 * and to trigger the explicit setting of the
2278 * image_ok flag.
2279 */
Fabio Utzig59b63e52019-09-10 12:22:35 -03002280 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_REVERT;
David Vinczeba3bd602019-06-17 16:01:43 +02002281 }
Fabio Utzig338a19f2018-12-03 08:37:08 -02002282 }
2283 }
Fabio Utzig338a19f2018-12-03 08:37:08 -02002284#endif
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08002285 }
David Vinczeba3bd602019-06-17 16:01:43 +02002286 } else {
2287 /* In that case if slots are not compatible. */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002288 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08002289 }
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08002290}
2291
Christopher Collins92ea77f2016-12-12 15:59:26 -08002292int
Fabio Utzig10ee6482019-08-01 12:04:52 -03002293context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp)
Christopher Collins92ea77f2016-12-12 15:59:26 -08002294{
Marti Bolivar84898652017-06-13 17:20:22 -04002295 size_t slot;
David Vinczeba3bd602019-06-17 16:01:43 +02002296 struct boot_status bs;
Christopher Collins92ea77f2016-12-12 15:59:26 -08002297 int rc;
Marti Bolivarc0b47912017-06-13 17:18:09 -04002298 int fa_id;
Fabio Utzigb0f04732019-07-31 09:49:19 -03002299 int image_index;
Fabio Utzig298913b2019-08-28 11:22:45 -03002300 bool has_upgrade;
Christopher Collins92ea77f2016-12-12 15:59:26 -08002301
2302 /* The array of slot sectors are defined here (as opposed to file scope) so
2303 * that they don't get allocated for non-boot-loader apps. This is
2304 * necessary because the gcc option "-fdata-sections" doesn't seem to have
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08002305 * any effect in older gcc versions (e.g., 4.8.4).
Christopher Collins92ea77f2016-12-12 15:59:26 -08002306 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002307 TARGET_STATIC boot_sector_t primary_slot_sectors[BOOT_IMAGE_NUMBER][BOOT_MAX_IMG_SECTORS];
2308 TARGET_STATIC boot_sector_t secondary_slot_sectors[BOOT_IMAGE_NUMBER][BOOT_MAX_IMG_SECTORS];
2309 TARGET_STATIC boot_sector_t scratch_sectors[BOOT_MAX_IMG_SECTORS];
Christopher Collins92ea77f2016-12-12 15:59:26 -08002310
Fabio Utzig10ee6482019-08-01 12:04:52 -03002311 memset(state, 0, sizeof(struct boot_loader_state));
Fabio Utzig298913b2019-08-28 11:22:45 -03002312 has_upgrade = false;
2313
2314#if (BOOT_IMAGE_NUMBER == 1)
2315 (void)has_upgrade;
2316#endif
Fabio Utzigba829042018-09-18 08:29:34 -03002317
David Vinczeba3bd602019-06-17 16:01:43 +02002318 /* Iterate over all the images. By the end of the loop the swap type has
2319 * to be determined for each image and all aborted swaps have to be
2320 * completed.
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08002321 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002322 IMAGES_ITER(BOOT_CURR_IMG(state)) {
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03002323
David Vinczeba3bd602019-06-17 16:01:43 +02002324#if defined(MCUBOOT_ENC_IMAGES) && (BOOT_IMAGE_NUMBER > 1)
2325 /* The keys used for encryption may no longer be valid (could belong to
2326 * another images). Therefore, mark them as invalid to force their reload
2327 * by boot_enc_load().
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03002328 */
Fabio Utzig1e4284b2019-08-23 11:55:27 -03002329 boot_enc_zeroize(BOOT_CURR_ENC(state));
David Brown554c52e2017-06-30 16:01:07 -06002330#endif
2331
Fabio Utzig10ee6482019-08-01 12:04:52 -03002332 image_index = BOOT_CURR_IMG(state);
Fabio Utzigb0f04732019-07-31 09:49:19 -03002333
Fabio Utzig10ee6482019-08-01 12:04:52 -03002334 BOOT_IMG(state, BOOT_PRIMARY_SLOT).sectors =
Fabio Utzigb0f04732019-07-31 09:49:19 -03002335 primary_slot_sectors[image_index];
Fabio Utzig10ee6482019-08-01 12:04:52 -03002336 BOOT_IMG(state, BOOT_SECONDARY_SLOT).sectors =
Fabio Utzigb0f04732019-07-31 09:49:19 -03002337 secondary_slot_sectors[image_index];
Fabio Utzig10ee6482019-08-01 12:04:52 -03002338 state->scratch.sectors = scratch_sectors;
David Vinczeba3bd602019-06-17 16:01:43 +02002339
2340 /* Open primary and secondary image areas for the duration
2341 * of this call.
2342 */
2343 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
Fabio Utzigb0f04732019-07-31 09:49:19 -03002344 fa_id = flash_area_id_from_multi_image_slot(image_index, slot);
Fabio Utzig10ee6482019-08-01 12:04:52 -03002345 rc = flash_area_open(fa_id, &BOOT_IMG_AREA(state, slot));
David Vinczeba3bd602019-06-17 16:01:43 +02002346 assert(rc == 0);
2347 }
2348 rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH,
Fabio Utzig10ee6482019-08-01 12:04:52 -03002349 &BOOT_SCRATCH_AREA(state));
David Vinczeba3bd602019-06-17 16:01:43 +02002350 assert(rc == 0);
2351
2352 /* Determine swap type and complete swap if it has been aborted. */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002353 boot_prepare_image_for_update(state, &bs);
Fabio Utzig298913b2019-08-28 11:22:45 -03002354
Fabio Utzige575b0b2019-09-11 12:34:23 -03002355 if (BOOT_IS_UPGRADE(BOOT_SWAP_TYPE(state))) {
Fabio Utzig298913b2019-08-28 11:22:45 -03002356 has_upgrade = true;
2357 }
David Vinczeba3bd602019-06-17 16:01:43 +02002358 }
2359
David Vinczee32483f2019-06-13 10:46:24 +02002360#if (BOOT_IMAGE_NUMBER > 1)
Fabio Utzig298913b2019-08-28 11:22:45 -03002361 if (has_upgrade) {
2362 /* Iterate over all the images and verify whether the image dependencies
2363 * are all satisfied and update swap type if necessary.
2364 */
2365 rc = boot_verify_dependencies(state);
2366 if (rc == BOOT_EBADVERSION) {
2367 /*
2368 * It was impossible to upgrade because the expected dependency version
2369 * was not available. Here we already changed the swap_type so that
2370 * instead of asserting the bootloader, we continue and no upgrade is
2371 * performed.
2372 */
2373 rc = 0;
2374 }
2375 }
David Vinczee32483f2019-06-13 10:46:24 +02002376#endif
2377
David Vinczeba3bd602019-06-17 16:01:43 +02002378 /* Iterate over all the images. At this point there are no aborted swaps
2379 * and the swap types are determined for each image. By the end of the loop
2380 * all required update operations will have been finished.
2381 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002382 IMAGES_ITER(BOOT_CURR_IMG(state)) {
David Vinczeba3bd602019-06-17 16:01:43 +02002383
2384#if (BOOT_IMAGE_NUMBER > 1)
2385#ifdef MCUBOOT_ENC_IMAGES
2386 /* The keys used for encryption may no longer be valid (could belong to
2387 * another images). Therefore, mark them as invalid to force their reload
2388 * by boot_enc_load().
2389 */
Fabio Utzig1e4284b2019-08-23 11:55:27 -03002390 boot_enc_zeroize(BOOT_CURR_ENC(state));
David Vinczeba3bd602019-06-17 16:01:43 +02002391#endif /* MCUBOOT_ENC_IMAGES */
2392
2393 /* Indicate that swap is not aborted */
2394 memset(&bs, 0, sizeof bs);
2395 bs.idx = BOOT_STATUS_IDX_0;
2396 bs.state = BOOT_STATUS_STATE_0;
2397#endif /* (BOOT_IMAGE_NUMBER > 1) */
2398
2399 /* Set the previously determined swap type */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002400 bs.swap_type = BOOT_SWAP_TYPE(state);
David Vinczeba3bd602019-06-17 16:01:43 +02002401
Fabio Utzig10ee6482019-08-01 12:04:52 -03002402 switch (BOOT_SWAP_TYPE(state)) {
David Vinczeba3bd602019-06-17 16:01:43 +02002403 case BOOT_SWAP_TYPE_NONE:
2404 break;
2405
2406 case BOOT_SWAP_TYPE_TEST: /* fallthrough */
2407 case BOOT_SWAP_TYPE_PERM: /* fallthrough */
2408 case BOOT_SWAP_TYPE_REVERT:
Fabio Utzig10ee6482019-08-01 12:04:52 -03002409 rc = boot_perform_update(state, &bs);
David Vinczeba3bd602019-06-17 16:01:43 +02002410 assert(rc == 0);
2411 break;
2412
2413 case BOOT_SWAP_TYPE_FAIL:
2414 /* The image in secondary slot was invalid and is now erased. Ensure
2415 * we don't try to boot into it again on the next reboot. Do this by
2416 * pretending we just reverted back to primary slot.
2417 */
2418#ifndef MCUBOOT_OVERWRITE_ONLY
2419 /* image_ok needs to be explicitly set to avoid a new revert. */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002420 rc = boot_set_image_ok(BOOT_CURR_IMG(state));
David Vinczeba3bd602019-06-17 16:01:43 +02002421 if (rc != 0) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03002422 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
David Vinczeba3bd602019-06-17 16:01:43 +02002423 }
2424#endif /* !MCUBOOT_OVERWRITE_ONLY */
2425 break;
2426
2427 default:
Fabio Utzig10ee6482019-08-01 12:04:52 -03002428 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
David Vinczeba3bd602019-06-17 16:01:43 +02002429 }
2430
Fabio Utzig10ee6482019-08-01 12:04:52 -03002431 if (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_PANIC) {
David Vinczeba3bd602019-06-17 16:01:43 +02002432 BOOT_LOG_ERR("panic!");
2433 assert(0);
2434
2435 /* Loop forever... */
2436 while (1) {}
2437 }
2438 }
2439
2440 /* Iterate over all the images. At this point all required update operations
2441 * have finished. By the end of the loop each image in the primary slot will
2442 * have been re-validated.
2443 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002444 IMAGES_ITER(BOOT_CURR_IMG(state)) {
2445 if (BOOT_SWAP_TYPE(state) != BOOT_SWAP_TYPE_NONE) {
David Vinczeba3bd602019-06-17 16:01:43 +02002446 /* Attempt to read an image header from each slot. Ensure that image
2447 * headers in slots are aligned with headers in boot_data.
2448 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002449 rc = boot_read_image_headers(state, false);
David Vinczeba3bd602019-06-17 16:01:43 +02002450 if (rc != 0) {
2451 goto out;
2452 }
2453 /* Since headers were reloaded, it can be assumed we just performed
2454 * a swap or overwrite. Now the header info that should be used to
2455 * provide the data for the bootstrap, which previously was at
2456 * secondary slot, was updated to primary slot.
2457 */
2458 }
2459
2460#ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT
Fabio Utzig10ee6482019-08-01 12:04:52 -03002461 rc = boot_validate_slot(state, BOOT_PRIMARY_SLOT, NULL);
David Vinczeba3bd602019-06-17 16:01:43 +02002462 if (rc != 0) {
2463 rc = BOOT_EBADIMAGE;
2464 goto out;
2465 }
2466#else
2467 /* Even if we're not re-validating the primary slot, we could be booting
2468 * onto an empty flash chip. At least do a basic sanity check that
2469 * the magic number on the image is OK.
2470 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002471 if (BOOT_IMG(state, BOOT_PRIMARY_SLOT).hdr.ih_magic != IMAGE_MAGIC) {
David Vinczeba3bd602019-06-17 16:01:43 +02002472 BOOT_LOG_ERR("bad image magic 0x%lx; Image=%u", (unsigned long)
Fabio Utzig10ee6482019-08-01 12:04:52 -03002473 &boot_img_hdr(state,BOOT_PRIMARY_SLOT)->ih_magic,
2474 BOOT_CURR_IMG(state));
David Vinczeba3bd602019-06-17 16:01:43 +02002475 rc = BOOT_EBADIMAGE;
2476 goto out;
2477 }
2478#endif
2479 }
2480
Fabio Utzigb0f04732019-07-31 09:49:19 -03002481#if (BOOT_IMAGE_NUMBER > 1)
David Vinczeba3bd602019-06-17 16:01:43 +02002482 /* Always boot from the primary slot of Image 0. */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002483 BOOT_CURR_IMG(state) = 0;
Fabio Utzigb0f04732019-07-31 09:49:19 -03002484#endif
Fabio Utzig298913b2019-08-28 11:22:45 -03002485
Fabio Utzig10ee6482019-08-01 12:04:52 -03002486 rsp->br_flash_dev_id = BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT)->fa_device_id;
2487 rsp->br_image_off = boot_img_slot_off(state, BOOT_PRIMARY_SLOT);
2488 rsp->br_hdr = boot_img_hdr(state, BOOT_PRIMARY_SLOT);
Christopher Collins92ea77f2016-12-12 15:59:26 -08002489
Fabio Utzig298913b2019-08-28 11:22:45 -03002490out:
Fabio Utzig10ee6482019-08-01 12:04:52 -03002491 IMAGES_ITER(BOOT_CURR_IMG(state)) {
2492 flash_area_close(BOOT_SCRATCH_AREA(state));
David Vinczeba3bd602019-06-17 16:01:43 +02002493 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03002494 flash_area_close(BOOT_IMG_AREA(state, BOOT_NUM_SLOTS - 1 - slot));
David Vinczeba3bd602019-06-17 16:01:43 +02002495 }
Marti Bolivarc0b47912017-06-13 17:18:09 -04002496 }
2497 return rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -08002498}
2499
Fabio Utzig10ee6482019-08-01 12:04:52 -03002500/**
2501 * Prepares the booting process. This function moves images around in flash as
2502 * appropriate, and tells you what address to boot from.
2503 *
2504 * @param rsp On success, indicates how booting should occur.
2505 *
2506 * @return 0 on success; nonzero on failure.
2507 */
2508int
2509boot_go(struct boot_rsp *rsp)
2510{
2511 return context_boot_go(&boot_data, rsp);
2512}
2513
Christopher Collins92ea77f2016-12-12 15:59:26 -08002514int
2515split_go(int loader_slot, int split_slot, void **entry)
2516{
Marti Bolivarc50926f2017-06-14 09:35:40 -04002517 boot_sector_t *sectors;
Christopher Collins034a6202017-01-11 12:19:37 -08002518 uintptr_t entry_val;
Christopher Collins92ea77f2016-12-12 15:59:26 -08002519 int loader_flash_id;
Marti Bolivarc0b47912017-06-13 17:18:09 -04002520 int split_flash_id;
Christopher Collins92ea77f2016-12-12 15:59:26 -08002521 int rc;
2522
Christopher Collins92ea77f2016-12-12 15:59:26 -08002523 sectors = malloc(BOOT_MAX_IMG_SECTORS * 2 * sizeof *sectors);
2524 if (sectors == NULL) {
Marti Bolivarc0b47912017-06-13 17:18:09 -04002525 return SPLIT_GO_ERR;
Christopher Collins92ea77f2016-12-12 15:59:26 -08002526 }
David Vinczeba3bd602019-06-17 16:01:43 +02002527 BOOT_IMG(&boot_data, loader_slot).sectors = sectors + 0;
2528 BOOT_IMG(&boot_data, split_slot).sectors = sectors + BOOT_MAX_IMG_SECTORS;
Marti Bolivarc0b47912017-06-13 17:18:09 -04002529
2530 loader_flash_id = flash_area_id_from_image_slot(loader_slot);
2531 rc = flash_area_open(loader_flash_id,
Alvaro Prieto63a2bdb2019-07-04 12:18:49 -07002532 &BOOT_IMG_AREA(&boot_data, loader_slot));
Marti Bolivarc0b47912017-06-13 17:18:09 -04002533 assert(rc == 0);
2534 split_flash_id = flash_area_id_from_image_slot(split_slot);
2535 rc = flash_area_open(split_flash_id,
2536 &BOOT_IMG_AREA(&boot_data, split_slot));
2537 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -08002538
2539 /* Determine the sector layout of the image slots and scratch area. */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002540 rc = boot_read_sectors(&boot_data);
Christopher Collins92ea77f2016-12-12 15:59:26 -08002541 if (rc != 0) {
2542 rc = SPLIT_GO_ERR;
2543 goto done;
2544 }
2545
Fabio Utzig10ee6482019-08-01 12:04:52 -03002546 rc = boot_read_image_headers(&boot_data, true);
Christopher Collins92ea77f2016-12-12 15:59:26 -08002547 if (rc != 0) {
2548 goto done;
2549 }
2550
Christopher Collins92ea77f2016-12-12 15:59:26 -08002551 /* Don't check the bootable image flag because we could really call a
2552 * bootable or non-bootable image. Just validate that the image check
2553 * passes which is distinct from the normal check.
2554 */
Marti Bolivarf804f622017-06-12 15:41:48 -04002555 rc = split_image_check(boot_img_hdr(&boot_data, split_slot),
Marti Bolivarc0b47912017-06-13 17:18:09 -04002556 BOOT_IMG_AREA(&boot_data, split_slot),
Marti Bolivarf804f622017-06-12 15:41:48 -04002557 boot_img_hdr(&boot_data, loader_slot),
Marti Bolivarc0b47912017-06-13 17:18:09 -04002558 BOOT_IMG_AREA(&boot_data, loader_slot));
Christopher Collins92ea77f2016-12-12 15:59:26 -08002559 if (rc != 0) {
2560 rc = SPLIT_GO_NON_MATCHING;
2561 goto done;
2562 }
2563
Marti Bolivarea088872017-06-12 17:10:49 -04002564 entry_val = boot_img_slot_off(&boot_data, split_slot) +
Marti Bolivarf804f622017-06-12 15:41:48 -04002565 boot_img_hdr(&boot_data, split_slot)->ih_hdr_size;
Christopher Collins034a6202017-01-11 12:19:37 -08002566 *entry = (void *) entry_val;
Christopher Collins92ea77f2016-12-12 15:59:26 -08002567 rc = SPLIT_GO_OK;
2568
2569done:
Marti Bolivarc0b47912017-06-13 17:18:09 -04002570 flash_area_close(BOOT_IMG_AREA(&boot_data, split_slot));
2571 flash_area_close(BOOT_IMG_AREA(&boot_data, loader_slot));
Christopher Collins92ea77f2016-12-12 15:59:26 -08002572 free(sectors);
Christopher Collins92ea77f2016-12-12 15:59:26 -08002573 return rc;
2574}