blob: ed46f7977ae1d45b881816dc923e29a29b3ef2d4 [file] [log] [blame]
Christopher Collins92ea77f2016-12-12 15:59:26 -08001/*
David Brownaac71112020-02-03 16:13:42 -07002 * SPDX-License-Identifier: Apache-2.0
3 *
4 * Copyright (c) 2016-2020 Linaro LTD
5 * Copyright (c) 2016-2019 JUUL Labs
Mark Horvathccaf7f82021-01-04 18:16:42 +01006 * Copyright (c) 2019-2021 Arm Limited
David Brownaac71112020-02-03 16:13:42 -07007 *
8 * Original license:
9 *
Christopher Collins92ea77f2016-12-12 15:59:26 -080010 * Licensed to the Apache Software Foundation (ASF) under one
11 * or more contributor license agreements. See the NOTICE file
12 * distributed with this work for additional information
13 * regarding copyright ownership. The ASF licenses this file
14 * to you under the Apache License, Version 2.0 (the
15 * "License"); you may not use this file except in compliance
16 * with the License. You may obtain a copy of the License at
17 *
18 * http://www.apache.org/licenses/LICENSE-2.0
19 *
20 * Unless required by applicable law or agreed to in writing,
21 * software distributed under the License is distributed on an
22 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
23 * KIND, either express or implied. See the License for the
24 * specific language governing permissions and limitations
25 * under the License.
26 */
27
28/**
29 * This file provides an interface to the boot loader. Functions defined in
30 * this file should only be called while the boot loader is running.
31 */
32
Christopher Collins92ea77f2016-12-12 15:59:26 -080033#include <stddef.h>
David Brown52eee562017-07-05 11:25:09 -060034#include <stdbool.h>
Christopher Collins92ea77f2016-12-12 15:59:26 -080035#include <inttypes.h>
36#include <stdlib.h>
37#include <string.h>
Christopher Collins92ea77f2016-12-12 15:59:26 -080038#include "bootutil/bootutil.h"
39#include "bootutil/image.h"
40#include "bootutil_priv.h"
Fabio Utzig12d59162019-11-28 10:01:59 -030041#include "swap_priv.h"
Marti Bolivarfd20c762017-02-07 16:52:50 -050042#include "bootutil/bootutil_log.h"
David Vinczec3084132020-02-18 14:50:47 +010043#include "bootutil/security_cnt.h"
David Vincze1cf11b52020-03-24 07:51:09 +010044#include "bootutil/boot_record.h"
Raef Colese8fe6cf2020-05-26 13:07:40 +010045#include "bootutil/fault_injection_hardening.h"
Mark Horvathccaf7f82021-01-04 18:16:42 +010046#include "bootutil/ramload.h"
Andrzej Puzdrowskib8f39692021-07-02 15:05:37 +020047#include "bootutil/boot_hooks.h"
Marti Bolivarfd20c762017-02-07 16:52:50 -050048
Fabio Utzigba829042018-09-18 08:29:34 -030049#ifdef MCUBOOT_ENC_IMAGES
50#include "bootutil/enc_key.h"
51#endif
52
Carlos Falgueras García391b1972021-06-21 16:58:07 +020053#if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)
54#include <os/os_malloc.h>
55#endif
56
Fabio Utzigba1fbe62017-07-21 14:01:20 -030057#include "mcuboot_config/mcuboot_config.h"
Fabio Utzigeed80b62017-06-10 08:03:05 -030058
Carlos Falgueras Garcíaa4b4b0f2021-06-22 10:00:22 +020059BOOT_LOG_MODULE_DECLARE(mcuboot);
Emanuele Di Santo9f1933d2018-11-20 10:59:59 +010060
Marti Bolivar9b1f8bb2017-06-12 15:24:13 -040061static struct boot_loader_state boot_data;
Christopher Collins92ea77f2016-12-12 15:59:26 -080062
Fabio Utzigabec0732019-07-31 08:40:22 -030063#if (BOOT_IMAGE_NUMBER > 1)
64#define IMAGES_ITER(x) for ((x) = 0; (x) < BOOT_IMAGE_NUMBER; ++(x))
65#else
66#define IMAGES_ITER(x)
67#endif
68
Fabio Utzig10ee6482019-08-01 12:04:52 -030069/*
70 * This macro allows some control on the allocation of local variables.
71 * When running natively on a target, we don't want to allocated huge
72 * variables on the stack, so make them global instead. For the simulator
73 * we want to run as many threads as there are tests, and it's safer
74 * to just make those variables stack allocated.
75 */
76#if !defined(__BOOTSIM__)
77#define TARGET_STATIC static
78#else
79#define TARGET_STATIC
80#endif
81
David Vinczee574f2d2020-07-10 11:42:03 +020082static int
83boot_read_image_headers(struct boot_loader_state *state, bool require_all,
84 struct boot_status *bs)
85{
86 int rc;
87 int i;
88
89 for (i = 0; i < BOOT_NUM_SLOTS; i++) {
Andrzej Puzdrowskib8f39692021-07-02 15:05:37 +020090 rc = BOOT_HOOK_CALL(boot_read_image_header_hook, BOOT_HOOK_REGULAR,
91 BOOT_CURR_IMG(state), i, boot_img_hdr(state, i));
92 if (rc == BOOT_HOOK_REGULAR)
93 {
94 rc = boot_read_image_header(state, i, boot_img_hdr(state, i), bs);
95 }
David Vinczee574f2d2020-07-10 11:42:03 +020096 if (rc != 0) {
97 /* If `require_all` is set, fail on any single fail, otherwise
98 * if at least the first slot's header was read successfully,
99 * then the boot loader can attempt a boot.
100 *
101 * Failure to read any headers is a fatal error.
102 */
103 if (i > 0 && !require_all) {
104 return 0;
105 } else {
106 return rc;
107 }
108 }
109 }
110
111 return 0;
112}
113
Mark Horvathccaf7f82021-01-04 18:16:42 +0100114/**
115 * Saves boot status and shared data for current image.
116 *
117 * @param state Boot loader status information.
118 * @param active_slot Index of the slot will be loaded for current image.
119 *
120 * @return 0 on success; nonzero on failure.
121 */
122static int
123boot_add_shared_data(struct boot_loader_state *state,
124 uint32_t active_slot)
125{
126#if defined(MCUBOOT_MEASURED_BOOT) || defined(MCUBOOT_DATA_SHARING)
127 int rc;
128
129#ifdef MCUBOOT_MEASURED_BOOT
130 rc = boot_save_boot_status(BOOT_CURR_IMG(state),
131 boot_img_hdr(state, active_slot),
132 BOOT_IMG_AREA(state, active_slot));
133 if (rc != 0) {
134 BOOT_LOG_ERR("Failed to add image data to shared area");
135 return rc;
136 }
137#endif /* MCUBOOT_MEASURED_BOOT */
138
139#ifdef MCUBOOT_DATA_SHARING
140 rc = boot_save_shared_data(boot_img_hdr(state, active_slot),
141 BOOT_IMG_AREA(state, active_slot));
142 if (rc != 0) {
143 BOOT_LOG_ERR("Failed to add data to shared memory area.");
144 return rc;
145 }
146#endif /* MCUBOOT_DATA_SHARING */
147
148 return 0;
149
150#else /* MCUBOOT_MEASURED_BOOT || MCUBOOT_DATA_SHARING */
151 (void) (state);
152 (void) (active_slot);
153
154 return 0;
155#endif
156}
157
158/**
159 * Fills rsp to indicate how booting should occur.
160 *
161 * @param state Boot loader status information.
Mark Horvathccaf7f82021-01-04 18:16:42 +0100162 * @param rsp boot_rsp struct to fill.
163 */
164static void
Raef Colesfe57e7d2021-10-15 11:07:09 +0100165fill_rsp(struct boot_loader_state *state, struct boot_rsp *rsp)
Mark Horvathccaf7f82021-01-04 18:16:42 +0100166{
167 uint32_t active_slot;
168
169#if (BOOT_IMAGE_NUMBER > 1)
170 /* Always boot from Image 0. */
171 BOOT_CURR_IMG(state) = 0;
172#endif
173
174#if defined(MCUBOOT_DIRECT_XIP) || defined(MCUBOOT_RAM_LOAD)
Raef Colesfe57e7d2021-10-15 11:07:09 +0100175 active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot;
Mark Horvathccaf7f82021-01-04 18:16:42 +0100176#else
Mark Horvathccaf7f82021-01-04 18:16:42 +0100177 active_slot = BOOT_PRIMARY_SLOT;
178#endif
179
Dominik Ermel260ae092021-04-23 05:38:45 +0000180 rsp->br_flash_dev_id = flash_area_get_device_id(BOOT_IMG_AREA(state, active_slot));
Mark Horvathccaf7f82021-01-04 18:16:42 +0100181 rsp->br_image_off = boot_img_slot_off(state, active_slot);
182 rsp->br_hdr = boot_img_hdr(state, active_slot);
183}
184
185/**
186 * Closes all flash areas.
187 *
188 * @param state Boot loader status information.
189 */
190static void
191close_all_flash_areas(struct boot_loader_state *state)
192{
193 uint32_t slot;
194
195 IMAGES_ITER(BOOT_CURR_IMG(state)) {
196#if MCUBOOT_SWAP_USING_SCRATCH
197 flash_area_close(BOOT_SCRATCH_AREA(state));
198#endif
199 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
200 flash_area_close(BOOT_IMG_AREA(state, BOOT_NUM_SLOTS - 1 - slot));
201 }
202 }
203}
204
Tamas Banfe031092020-09-10 17:32:39 +0200205#if !defined(MCUBOOT_DIRECT_XIP)
David Brownf5b33d82017-09-01 10:58:27 -0600206/*
207 * Compute the total size of the given image. Includes the size of
208 * the TLVs.
209 */
Tamas Banfe031092020-09-10 17:32:39 +0200210#if !defined(MCUBOOT_OVERWRITE_ONLY) || defined(MCUBOOT_OVERWRITE_ONLY_FAST)
David Brownf5b33d82017-09-01 10:58:27 -0600211static int
Fabio Utzigd638b172019-08-09 10:38:05 -0300212boot_read_image_size(struct boot_loader_state *state, int slot, uint32_t *size)
David Brownf5b33d82017-09-01 10:58:27 -0600213{
214 const struct flash_area *fap;
Fabio Utzig61fd8882019-09-14 20:00:20 -0300215 struct image_tlv_info info;
Fabio Utzig233af7d2019-08-26 12:06:16 -0300216 uint32_t off;
Fabio Utzige52c08e2019-09-11 19:32:00 -0300217 uint32_t protect_tlv_size;
David Brownf5b33d82017-09-01 10:58:27 -0600218 int area_id;
219 int rc;
220
Fabio Utzig10ee6482019-08-01 12:04:52 -0300221#if (BOOT_IMAGE_NUMBER == 1)
222 (void)state;
223#endif
224
225 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
David Brownf5b33d82017-09-01 10:58:27 -0600226 rc = flash_area_open(area_id, &fap);
227 if (rc != 0) {
228 rc = BOOT_EFLASH;
229 goto done;
230 }
231
Fabio Utzig61fd8882019-09-14 20:00:20 -0300232 off = BOOT_TLV_OFF(boot_img_hdr(state, slot));
233
234 if (flash_area_read(fap, off, &info, sizeof(info))) {
235 rc = BOOT_EFLASH;
David Brownf5b33d82017-09-01 10:58:27 -0600236 goto done;
237 }
Fabio Utzig61fd8882019-09-14 20:00:20 -0300238
Fabio Utzige52c08e2019-09-11 19:32:00 -0300239 protect_tlv_size = boot_img_hdr(state, slot)->ih_protect_tlv_size;
240 if (info.it_magic == IMAGE_TLV_PROT_INFO_MAGIC) {
241 if (protect_tlv_size != info.it_tlv_tot) {
242 rc = BOOT_EBADIMAGE;
243 goto done;
244 }
245
246 if (flash_area_read(fap, off + info.it_tlv_tot, &info, sizeof(info))) {
247 rc = BOOT_EFLASH;
248 goto done;
249 }
250 } else if (protect_tlv_size != 0) {
251 rc = BOOT_EBADIMAGE;
252 goto done;
253 }
254
Fabio Utzig61fd8882019-09-14 20:00:20 -0300255 if (info.it_magic != IMAGE_TLV_INFO_MAGIC) {
256 rc = BOOT_EBADIMAGE;
257 goto done;
258 }
259
Fabio Utzige52c08e2019-09-11 19:32:00 -0300260 *size = off + protect_tlv_size + info.it_tlv_tot;
David Brownf5b33d82017-09-01 10:58:27 -0600261 rc = 0;
262
263done:
264 flash_area_close(fap);
Fabio Utzig2eebf112017-09-04 15:25:08 -0300265 return rc;
David Brownf5b33d82017-09-01 10:58:27 -0600266}
Fabio Utzig36ec0e72017-09-05 08:10:33 -0300267#endif /* !MCUBOOT_OVERWRITE_ONLY */
David Brownf5b33d82017-09-01 10:58:27 -0600268
Tamas Banfe031092020-09-10 17:32:39 +0200269#if !defined(MCUBOOT_RAM_LOAD)
David Brownab449182019-11-15 09:32:52 -0700270static uint32_t
Fabio Utzig10ee6482019-08-01 12:04:52 -0300271boot_write_sz(struct boot_loader_state *state)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800272{
David Brownab449182019-11-15 09:32:52 -0700273 uint32_t elem_sz;
Fabio Utzig12d59162019-11-28 10:01:59 -0300274#if MCUBOOT_SWAP_USING_SCRATCH
David Brownab449182019-11-15 09:32:52 -0700275 uint32_t align;
Fabio Utzig12d59162019-11-28 10:01:59 -0300276#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800277
278 /* Figure out what size to write update status update as. The size depends
279 * on what the minimum write size is for scratch area, active image slot.
280 * We need to use the bigger of those 2 values.
281 */
Fabio Utzig10ee6482019-08-01 12:04:52 -0300282 elem_sz = flash_area_align(BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT));
Fabio Utzig12d59162019-11-28 10:01:59 -0300283#if MCUBOOT_SWAP_USING_SCRATCH
Fabio Utzig10ee6482019-08-01 12:04:52 -0300284 align = flash_area_align(BOOT_SCRATCH_AREA(state));
Christopher Collins92ea77f2016-12-12 15:59:26 -0800285 if (align > elem_sz) {
286 elem_sz = align;
287 }
Fabio Utzig12d59162019-11-28 10:01:59 -0300288#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800289
290 return elem_sz;
291}
292
Fabio Utzig10ee6482019-08-01 12:04:52 -0300293static int
294boot_initialize_area(struct boot_loader_state *state, int flash_area)
295{
Dominik Ermel51c8d762021-05-24 15:34:01 +0000296 uint32_t num_sectors = BOOT_MAX_IMG_SECTORS;
297 boot_sector_t *out_sectors;
298 uint32_t *out_num_sectors;
Fabio Utzig10ee6482019-08-01 12:04:52 -0300299 int rc;
300
301 num_sectors = BOOT_MAX_IMG_SECTORS;
302
303 if (flash_area == FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state))) {
304 out_sectors = BOOT_IMG(state, BOOT_PRIMARY_SLOT).sectors;
305 out_num_sectors = &BOOT_IMG(state, BOOT_PRIMARY_SLOT).num_sectors;
306 } else if (flash_area == FLASH_AREA_IMAGE_SECONDARY(BOOT_CURR_IMG(state))) {
307 out_sectors = BOOT_IMG(state, BOOT_SECONDARY_SLOT).sectors;
308 out_num_sectors = &BOOT_IMG(state, BOOT_SECONDARY_SLOT).num_sectors;
Fabio Utzig12d59162019-11-28 10:01:59 -0300309#if MCUBOOT_SWAP_USING_SCRATCH
Fabio Utzig10ee6482019-08-01 12:04:52 -0300310 } else if (flash_area == FLASH_AREA_IMAGE_SCRATCH) {
311 out_sectors = state->scratch.sectors;
312 out_num_sectors = &state->scratch.num_sectors;
Fabio Utzig12d59162019-11-28 10:01:59 -0300313#endif
Fabio Utzig10ee6482019-08-01 12:04:52 -0300314 } else {
315 return BOOT_EFLASH;
316 }
317
Dominik Ermel51c8d762021-05-24 15:34:01 +0000318#ifdef MCUBOOT_USE_FLASH_AREA_GET_SECTORS
Fabio Utzig10ee6482019-08-01 12:04:52 -0300319 rc = flash_area_get_sectors(flash_area, &num_sectors, out_sectors);
Dominik Ermel51c8d762021-05-24 15:34:01 +0000320#else
321 _Static_assert(sizeof(int) <= sizeof(uint32_t), "Fix needed");
322 rc = flash_area_to_sectors(flash_area, (int *)&num_sectors, out_sectors);
323#endif /* defined(MCUBOOT_USE_FLASH_AREA_GET_SECTORS) */
Fabio Utzig10ee6482019-08-01 12:04:52 -0300324 if (rc != 0) {
325 return rc;
326 }
327 *out_num_sectors = num_sectors;
328 return 0;
329}
Fabio Utzig10ee6482019-08-01 12:04:52 -0300330
Christopher Collins92ea77f2016-12-12 15:59:26 -0800331/**
332 * Determines the sector layout of both image slots and the scratch area.
333 * This information is necessary for calculating the number of bytes to erase
334 * and copy during an image swap. The information collected during this
Fabio Utzig10ee6482019-08-01 12:04:52 -0300335 * function is used to populate the state.
Christopher Collins92ea77f2016-12-12 15:59:26 -0800336 */
337static int
Fabio Utzig10ee6482019-08-01 12:04:52 -0300338boot_read_sectors(struct boot_loader_state *state)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800339{
Fabio Utzigb0f04732019-07-31 09:49:19 -0300340 uint8_t image_index;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800341 int rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800342
Fabio Utzig10ee6482019-08-01 12:04:52 -0300343 image_index = BOOT_CURR_IMG(state);
Fabio Utzigb0f04732019-07-31 09:49:19 -0300344
345 rc = boot_initialize_area(state, FLASH_AREA_IMAGE_PRIMARY(image_index));
Christopher Collins92ea77f2016-12-12 15:59:26 -0800346 if (rc != 0) {
347 return BOOT_EFLASH;
348 }
349
Fabio Utzig10ee6482019-08-01 12:04:52 -0300350 rc = boot_initialize_area(state, FLASH_AREA_IMAGE_SECONDARY(image_index));
Christopher Collins92ea77f2016-12-12 15:59:26 -0800351 if (rc != 0) {
Andrzej Puzdrowski54b4ad92021-06-22 13:21:22 +0200352 /* We need to differentiate from the primary image issue */
353 return BOOT_EFLASH_SEC;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800354 }
355
Fabio Utzig12d59162019-11-28 10:01:59 -0300356#if MCUBOOT_SWAP_USING_SCRATCH
Fabio Utzig10ee6482019-08-01 12:04:52 -0300357 rc = boot_initialize_area(state, FLASH_AREA_IMAGE_SCRATCH);
Fabio Utzig2bd980a2018-11-26 10:38:17 -0200358 if (rc != 0) {
359 return BOOT_EFLASH;
360 }
Fabio Utzig12d59162019-11-28 10:01:59 -0300361#endif
Fabio Utzig2bd980a2018-11-26 10:38:17 -0200362
Fabio Utzig10ee6482019-08-01 12:04:52 -0300363 BOOT_WRITE_SZ(state) = boot_write_sz(state);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800364
365 return 0;
366}
367
Fabio Utzig12d59162019-11-28 10:01:59 -0300368void
369boot_status_reset(struct boot_status *bs)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800370{
Fabio Utzig4741c452019-12-19 15:32:41 -0300371#ifdef MCUBOOT_ENC_IMAGES
372 memset(&bs->enckey, 0xff, BOOT_NUM_SLOTS * BOOT_ENC_KEY_SIZE);
373#if MCUBOOT_SWAP_SAVE_ENCTLV
374 memset(&bs->enctlv, 0xff, BOOT_NUM_SLOTS * BOOT_ENC_TLV_ALIGN_SIZE);
375#endif
376#endif /* MCUBOOT_ENC_IMAGES */
377
378 bs->use_scratch = 0;
379 bs->swap_size = 0;
380 bs->source = 0;
381
Fabio Utzig74aef312019-11-28 11:05:34 -0300382 bs->op = BOOT_STATUS_OP_MOVE;
Fabio Utzig39000012018-07-30 12:40:20 -0300383 bs->idx = BOOT_STATUS_IDX_0;
384 bs->state = BOOT_STATUS_STATE_0;
Christopher Collinsa1c12042019-05-23 14:00:28 -0700385 bs->swap_type = BOOT_SWAP_TYPE_NONE;
Fabio Utzig12d59162019-11-28 10:01:59 -0300386}
Christopher Collins92ea77f2016-12-12 15:59:26 -0800387
Fabio Utzig12d59162019-11-28 10:01:59 -0300388bool
389boot_status_is_reset(const struct boot_status *bs)
390{
Fabio Utzig74aef312019-11-28 11:05:34 -0300391 return (bs->op == BOOT_STATUS_OP_MOVE &&
392 bs->idx == BOOT_STATUS_IDX_0 &&
393 bs->state == BOOT_STATUS_STATE_0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800394}
395
396/**
397 * Writes the supplied boot status to the flash file system. The boot status
398 * contains the current state of an in-progress image copy operation.
399 *
400 * @param bs The boot status to write.
401 *
402 * @return 0 on success; nonzero on failure.
403 */
404int
Fabio Utzig12d59162019-11-28 10:01:59 -0300405boot_write_status(const struct boot_loader_state *state, struct boot_status *bs)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800406{
407 const struct flash_area *fap;
408 uint32_t off;
409 int area_id;
Dominik Ermel9479af02021-10-19 10:06:44 +0000410 int rc = 0;
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300411 uint8_t buf[BOOT_MAX_ALIGN];
David Brown9d725462017-01-23 15:50:58 -0700412 uint8_t align;
Fabio Utzig39000012018-07-30 12:40:20 -0300413 uint8_t erased_val;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800414
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300415 /* NOTE: The first sector copied (that is the last sector on slot) contains
David Vincze2d736ad2019-02-18 11:50:22 +0100416 * the trailer. Since in the last step the primary slot is erased, the
417 * first two status writes go to the scratch which will be copied to
418 * the primary slot!
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300419 */
420
Fabio Utzig12d59162019-11-28 10:01:59 -0300421#if MCUBOOT_SWAP_USING_SCRATCH
Fabio Utzig2473ac02017-05-02 12:45:02 -0300422 if (bs->use_scratch) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800423 /* Write to scratch. */
424 area_id = FLASH_AREA_IMAGE_SCRATCH;
425 } else {
Fabio Utzig12d59162019-11-28 10:01:59 -0300426#endif
David Vincze2d736ad2019-02-18 11:50:22 +0100427 /* Write to the primary slot. */
Fabio Utzig10ee6482019-08-01 12:04:52 -0300428 area_id = FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state));
Fabio Utzig12d59162019-11-28 10:01:59 -0300429#if MCUBOOT_SWAP_USING_SCRATCH
Christopher Collins92ea77f2016-12-12 15:59:26 -0800430 }
Fabio Utzig12d59162019-11-28 10:01:59 -0300431#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800432
433 rc = flash_area_open(area_id, &fap);
434 if (rc != 0) {
Dominik Ermel9479af02021-10-19 10:06:44 +0000435 return BOOT_EFLASH;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800436 }
437
438 off = boot_status_off(fap) +
Fabio Utzig12d59162019-11-28 10:01:59 -0300439 boot_status_internal_off(bs, BOOT_WRITE_SZ(state));
Andrzej Puzdrowskib788c712018-04-12 12:42:49 +0200440 align = flash_area_align(fap);
Fabio Utzig39000012018-07-30 12:40:20 -0300441 erased_val = flash_area_erased_val(fap);
442 memset(buf, erased_val, BOOT_MAX_ALIGN);
David Brown9d725462017-01-23 15:50:58 -0700443 buf[0] = bs->state;
444
445 rc = flash_area_write(fap, off, buf, align);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800446 if (rc != 0) {
447 rc = BOOT_EFLASH;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800448 }
449
Christopher Collins92ea77f2016-12-12 15:59:26 -0800450 flash_area_close(fap);
Dominik Ermel9479af02021-10-19 10:06:44 +0000451
Christopher Collins92ea77f2016-12-12 15:59:26 -0800452 return rc;
453}
Tamas Banfe031092020-09-10 17:32:39 +0200454#endif /* !MCUBOOT_RAM_LOAD */
David Vinczee574f2d2020-07-10 11:42:03 +0200455#endif /* !MCUBOOT_DIRECT_XIP */
Christopher Collins92ea77f2016-12-12 15:59:26 -0800456
457/*
David Vinczec3084132020-02-18 14:50:47 +0100458 * Validate image hash/signature and optionally the security counter in a slot.
Christopher Collins92ea77f2016-12-12 15:59:26 -0800459 */
Raef Colese8fe6cf2020-05-26 13:07:40 +0100460static fih_int
Fabio Utzig10ee6482019-08-01 12:04:52 -0300461boot_image_check(struct boot_loader_state *state, struct image_header *hdr,
462 const struct flash_area *fap, struct boot_status *bs)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800463{
Fabio Utzig10ee6482019-08-01 12:04:52 -0300464 TARGET_STATIC uint8_t tmpbuf[BOOT_TMPBUF_SZ];
Fabio Utzigb0f04732019-07-31 09:49:19 -0300465 uint8_t image_index;
Fabio Utzigba829042018-09-18 08:29:34 -0300466 int rc;
Raef Colese8fe6cf2020-05-26 13:07:40 +0100467 fih_int fih_rc = FIH_FAILURE;
Fabio Utzigba829042018-09-18 08:29:34 -0300468
Fabio Utzig10ee6482019-08-01 12:04:52 -0300469#if (BOOT_IMAGE_NUMBER == 1)
470 (void)state;
471#endif
472
Fabio Utzigba829042018-09-18 08:29:34 -0300473 (void)bs;
474 (void)rc;
Fabio Utzigbc077932019-08-26 11:16:34 -0300475
476 image_index = BOOT_CURR_IMG(state);
477
Hugo L'Hostisdb543e52021-03-09 18:00:31 +0000478/* In the case of ram loading the image has already been decrypted as it is
479 * decrypted when copied in ram */
480#if defined(MCUBOOT_ENC_IMAGES) && !defined(MCUBOOT_RAM_LOAD)
Fabio Utzigbc077932019-08-26 11:16:34 -0300481 if (MUST_DECRYPT(fap, image_index, hdr)) {
Fabio Utzig4741c452019-12-19 15:32:41 -0300482 rc = boot_enc_load(BOOT_CURR_ENC(state), image_index, hdr, fap, bs);
Fabio Utzigba829042018-09-18 08:29:34 -0300483 if (rc < 0) {
Raef Colese8fe6cf2020-05-26 13:07:40 +0100484 FIH_RET(fih_rc);
Fabio Utzigba829042018-09-18 08:29:34 -0300485 }
Fabio Utzig4741c452019-12-19 15:32:41 -0300486 if (rc == 0 && boot_enc_set_key(BOOT_CURR_ENC(state), 1, bs)) {
Raef Colese8fe6cf2020-05-26 13:07:40 +0100487 FIH_RET(fih_rc);
Fabio Utzigba829042018-09-18 08:29:34 -0300488 }
489 }
Fabio Utzigbc077932019-08-26 11:16:34 -0300490#endif
491
Raef Colese8fe6cf2020-05-26 13:07:40 +0100492 FIH_CALL(bootutil_img_validate, fih_rc, BOOT_CURR_ENC(state), image_index,
493 hdr, fap, tmpbuf, BOOT_TMPBUF_SZ, NULL, 0, NULL);
Fabio Utzig10ee6482019-08-01 12:04:52 -0300494
Raef Colese8fe6cf2020-05-26 13:07:40 +0100495 FIH_RET(fih_rc);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800496}
497
Tamas Banfe031092020-09-10 17:32:39 +0200498#if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)
Raef Colese8fe6cf2020-05-26 13:07:40 +0100499static fih_int
Christopher Collins92ea77f2016-12-12 15:59:26 -0800500split_image_check(struct image_header *app_hdr,
501 const struct flash_area *app_fap,
502 struct image_header *loader_hdr,
503 const struct flash_area *loader_fap)
504{
505 static void *tmpbuf;
506 uint8_t loader_hash[32];
Raef Colese8fe6cf2020-05-26 13:07:40 +0100507 fih_int fih_rc = FIH_FAILURE;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800508
509 if (!tmpbuf) {
510 tmpbuf = malloc(BOOT_TMPBUF_SZ);
511 if (!tmpbuf) {
Raef Colese8fe6cf2020-05-26 13:07:40 +0100512 goto out;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800513 }
514 }
515
Raef Colese8fe6cf2020-05-26 13:07:40 +0100516 FIH_CALL(bootutil_img_validate, fih_rc, NULL, 0, loader_hdr, loader_fap,
517 tmpbuf, BOOT_TMPBUF_SZ, NULL, 0, loader_hash);
518 if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
519 FIH_RET(fih_rc);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800520 }
521
Raef Colese8fe6cf2020-05-26 13:07:40 +0100522 FIH_CALL(bootutil_img_validate, fih_rc, NULL, 0, app_hdr, app_fap,
523 tmpbuf, BOOT_TMPBUF_SZ, loader_hash, 32, NULL);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800524
Raef Colese8fe6cf2020-05-26 13:07:40 +0100525out:
526 FIH_RET(fih_rc);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800527}
Tamas Banfe031092020-09-10 17:32:39 +0200528#endif /* !MCUBOOT_DIRECT_XIP && !MCUBOOT_RAM_LOAD */
Christopher Collins92ea77f2016-12-12 15:59:26 -0800529
Fabio Utzig338a19f2018-12-03 08:37:08 -0200530/*
David Brown9bf95af2019-10-10 15:36:36 -0600531 * Check that this is a valid header. Valid means that the magic is
532 * correct, and that the sizes/offsets are "sane". Sane means that
533 * there is no overflow on the arithmetic, and that the result fits
534 * within the flash area we are in.
535 */
536static bool
537boot_is_header_valid(const struct image_header *hdr, const struct flash_area *fap)
538{
539 uint32_t size;
540
541 if (hdr->ih_magic != IMAGE_MAGIC) {
542 return false;
543 }
544
545 if (!boot_u32_safe_add(&size, hdr->ih_img_size, hdr->ih_hdr_size)) {
546 return false;
547 }
548
Dominik Ermel260ae092021-04-23 05:38:45 +0000549 if (size >= flash_area_get_size(fap)) {
David Brown9bf95af2019-10-10 15:36:36 -0600550 return false;
551 }
552
553 return true;
554}
555
556/*
Fabio Utzig338a19f2018-12-03 08:37:08 -0200557 * Check that a memory area consists of a given value.
558 */
559static inline bool
560boot_data_is_set_to(uint8_t val, void *data, size_t len)
Fabio Utzig39000012018-07-30 12:40:20 -0300561{
562 uint8_t i;
Fabio Utzig338a19f2018-12-03 08:37:08 -0200563 uint8_t *p = (uint8_t *)data;
564 for (i = 0; i < len; i++) {
565 if (val != p[i]) {
566 return false;
Fabio Utzig39000012018-07-30 12:40:20 -0300567 }
568 }
Fabio Utzig338a19f2018-12-03 08:37:08 -0200569 return true;
570}
571
572static int
Fabio Utzig10ee6482019-08-01 12:04:52 -0300573boot_check_header_erased(struct boot_loader_state *state, int slot)
Fabio Utzig338a19f2018-12-03 08:37:08 -0200574{
575 const struct flash_area *fap;
576 struct image_header *hdr;
577 uint8_t erased_val;
Fabio Utzigb0f04732019-07-31 09:49:19 -0300578 int area_id;
Fabio Utzig338a19f2018-12-03 08:37:08 -0200579 int rc;
580
Fabio Utzig10ee6482019-08-01 12:04:52 -0300581 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
Fabio Utzigb0f04732019-07-31 09:49:19 -0300582 rc = flash_area_open(area_id, &fap);
Fabio Utzig338a19f2018-12-03 08:37:08 -0200583 if (rc != 0) {
584 return -1;
585 }
586
587 erased_val = flash_area_erased_val(fap);
588 flash_area_close(fap);
589
Fabio Utzig10ee6482019-08-01 12:04:52 -0300590 hdr = boot_img_hdr(state, slot);
Fabio Utzig338a19f2018-12-03 08:37:08 -0200591 if (!boot_data_is_set_to(erased_val, &hdr->ih_magic, sizeof(hdr->ih_magic))) {
592 return -1;
593 }
594
595 return 0;
Fabio Utzig39000012018-07-30 12:40:20 -0300596}
597
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +0000598#if (BOOT_IMAGE_NUMBER > 1) || \
David Vinczee574f2d2020-07-10 11:42:03 +0200599 defined(MCUBOOT_DIRECT_XIP) || \
Tamas Banfe031092020-09-10 17:32:39 +0200600 defined(MCUBOOT_RAM_LOAD) || \
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +0000601 (defined(MCUBOOT_OVERWRITE_ONLY) && defined(MCUBOOT_DOWNGRADE_PREVENTION))
602/**
David Vincze8b0b6372020-05-20 19:54:44 +0200603 * Compare image version numbers not including the build number
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +0000604 *
David Vincze8b0b6372020-05-20 19:54:44 +0200605 * @param ver1 Pointer to the first image version to compare.
606 * @param ver2 Pointer to the second image version to compare.
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +0000607 *
David Vincze8b0b6372020-05-20 19:54:44 +0200608 * @retval -1 If ver1 is strictly less than ver2.
609 * @retval 0 If the image version numbers are equal,
610 * (not including the build number).
611 * @retval 1 If ver1 is strictly greater than ver2.
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +0000612 */
613static int
David Vincze8b0b6372020-05-20 19:54:44 +0200614boot_version_cmp(const struct image_version *ver1,
615 const struct image_version *ver2)
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +0000616{
David Vincze8b0b6372020-05-20 19:54:44 +0200617 if (ver1->iv_major > ver2->iv_major) {
618 return 1;
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +0000619 }
David Vincze8b0b6372020-05-20 19:54:44 +0200620 if (ver1->iv_major < ver2->iv_major) {
621 return -1;
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +0000622 }
David Vincze8b0b6372020-05-20 19:54:44 +0200623 /* The major version numbers are equal, continue comparison. */
624 if (ver1->iv_minor > ver2->iv_minor) {
625 return 1;
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +0000626 }
David Vincze8b0b6372020-05-20 19:54:44 +0200627 if (ver1->iv_minor < ver2->iv_minor) {
628 return -1;
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +0000629 }
David Vincze8b0b6372020-05-20 19:54:44 +0200630 /* The minor version numbers are equal, continue comparison. */
631 if (ver1->iv_revision > ver2->iv_revision) {
632 return 1;
633 }
634 if (ver1->iv_revision < ver2->iv_revision) {
635 return -1;
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +0000636 }
637
638 return 0;
639}
640#endif
641
Dominik Ermel0c8c8d52021-02-17 14:45:02 +0000642#if defined(MCUBOOT_DIRECT_XIP)
643/**
644 * Check if image in slot has been set with specific ROM address to run from
645 * and whether the slot starts at that address.
646 *
647 * @returns 0 if IMAGE_F_ROM_FIXED flag is not set;
648 * 0 if IMAGE_F_ROM_FIXED flag is set and ROM address specified in
649 * header matches the slot address;
650 * 1 if IMF_F_ROM_FIXED flag is set but ROM address specified in header
651 * does not match the slot address.
652 */
653static bool
Raef Colesfe57e7d2021-10-15 11:07:09 +0100654boot_rom_address_check(struct boot_loader_state *state)
Dominik Ermel0c8c8d52021-02-17 14:45:02 +0000655{
Mark Horvathccaf7f82021-01-04 18:16:42 +0100656 uint32_t active_slot;
657 const struct image_header *hdr;
658 uint32_t f_off;
659
Raef Colesfe57e7d2021-10-15 11:07:09 +0100660 active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot;
Mark Horvathccaf7f82021-01-04 18:16:42 +0100661 hdr = boot_img_hdr(state, active_slot);
662 f_off = boot_img_slot_off(state, active_slot);
663
Dominik Ermel0c8c8d52021-02-17 14:45:02 +0000664 if (hdr->ih_flags & IMAGE_F_ROM_FIXED && hdr->ih_load_addr != f_off) {
665 BOOT_LOG_WRN("Image in %s slot at 0x%x has been built for offset 0x%x"\
Mark Horvathccaf7f82021-01-04 18:16:42 +0100666 ", skipping",
667 active_slot == 0 ? "primary" : "secondary", f_off,
Dominik Ermel0c8c8d52021-02-17 14:45:02 +0000668 hdr->ih_load_addr);
669
670 /* If there is address mismatch, the image is not bootable from this
671 * slot.
672 */
673 return 1;
674 }
675 return 0;
676}
677#endif
678
Fabio Utzigb1adb1e2019-09-11 11:42:53 -0300679/*
680 * Check that there is a valid image in a slot
681 *
682 * @returns
Raef Colese8fe6cf2020-05-26 13:07:40 +0100683 * FIH_SUCCESS if image was successfully validated
684 * 1 (or its fih_int encoded form) if no bootloable image was found
685 * FIH_FAILURE on any errors
Fabio Utzigb1adb1e2019-09-11 11:42:53 -0300686 */
Raef Colese8fe6cf2020-05-26 13:07:40 +0100687static fih_int
Fabio Utzig10ee6482019-08-01 12:04:52 -0300688boot_validate_slot(struct boot_loader_state *state, int slot,
689 struct boot_status *bs)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800690{
691 const struct flash_area *fap;
Marti Bolivarf804f622017-06-12 15:41:48 -0400692 struct image_header *hdr;
Fabio Utzigb0f04732019-07-31 09:49:19 -0300693 int area_id;
Raef Colese8fe6cf2020-05-26 13:07:40 +0100694 fih_int fih_rc = FIH_FAILURE;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800695 int rc;
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300696
Fabio Utzig10ee6482019-08-01 12:04:52 -0300697 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
Fabio Utzigb0f04732019-07-31 09:49:19 -0300698 rc = flash_area_open(area_id, &fap);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800699 if (rc != 0) {
Raef Colese8fe6cf2020-05-26 13:07:40 +0100700 FIH_RET(fih_rc);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800701 }
702
Fabio Utzig10ee6482019-08-01 12:04:52 -0300703 hdr = boot_img_hdr(state, slot);
704 if (boot_check_header_erased(state, slot) == 0 ||
705 (hdr->ih_flags & IMAGE_F_NON_BOOTABLE)) {
Fabio Utzig260ec452020-07-09 18:40:07 -0300706
707#if defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SWAP_USING_MOVE)
708 /*
709 * This fixes an issue where an image might be erased, but a trailer
710 * be left behind. It can happen if the image is in the secondary slot
711 * and did not pass validation, in which case the whole slot is erased.
712 * If during the erase operation, a reset occurs, parts of the slot
713 * might have been erased while some did not. The concerning part is
714 * the trailer because it might disable a new image from being loaded
715 * through mcumgr; so we just get rid of the trailer here, if the header
716 * is erased.
717 */
718 if (slot != BOOT_PRIMARY_SLOT) {
719 swap_erase_trailer_sectors(state, fap);
720 }
721#endif
722
David Vincze2d736ad2019-02-18 11:50:22 +0100723 /* No bootable image in slot; continue booting from the primary slot. */
Raef Colese8fe6cf2020-05-26 13:07:40 +0100724 fih_rc = fih_int_encode(1);
Fabio Utzig338a19f2018-12-03 08:37:08 -0200725 goto out;
Fabio Utzig39000012018-07-30 12:40:20 -0300726 }
727
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +0000728#if defined(MCUBOOT_OVERWRITE_ONLY) && defined(MCUBOOT_DOWNGRADE_PREVENTION)
729 if (slot != BOOT_PRIMARY_SLOT) {
730 /* Check if version of secondary slot is sufficient */
David Vincze8b0b6372020-05-20 19:54:44 +0200731 rc = boot_version_cmp(
732 &boot_img_hdr(state, BOOT_SECONDARY_SLOT)->ih_ver,
733 &boot_img_hdr(state, BOOT_PRIMARY_SLOT)->ih_ver);
734 if (rc < 0 && boot_check_header_erased(state, BOOT_PRIMARY_SLOT)) {
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +0000735 BOOT_LOG_ERR("insufficient version in secondary slot");
Dominik Ermel260ae092021-04-23 05:38:45 +0000736 flash_area_erase(fap, 0, flash_area_get_size(fap));
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +0000737 /* Image in the secondary slot does not satisfy version requirement.
738 * Erase the image and continue booting from the primary slot.
739 */
Raef Colese8fe6cf2020-05-26 13:07:40 +0100740 fih_rc = fih_int_encode(1);
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +0000741 goto out;
742 }
743 }
744#endif
Andrzej Puzdrowskib8f39692021-07-02 15:05:37 +0200745 BOOT_HOOK_CALL_FIH(boot_image_check_hook, fih_int_encode(BOOT_HOOK_REGULAR),
746 fih_rc, BOOT_CURR_IMG(state), slot);
Andrzej Puzdrowski9d4d45c2021-09-14 17:25:58 +0200747 if (fih_eq(fih_rc, fih_int_encode(BOOT_HOOK_REGULAR)))
Andrzej Puzdrowskib8f39692021-07-02 15:05:37 +0200748 {
749 FIH_CALL(boot_image_check, fih_rc, state, hdr, fap, bs);
750 }
Raef Colese8fe6cf2020-05-26 13:07:40 +0100751 if (!boot_is_header_valid(hdr, fap) || fih_not_eq(fih_rc, FIH_SUCCESS)) {
Tamas Banfe031092020-09-10 17:32:39 +0200752 if ((slot != BOOT_PRIMARY_SLOT) || ARE_SLOTS_EQUIVALENT()) {
Dominik Ermel260ae092021-04-23 05:38:45 +0000753 flash_area_erase(fap, 0, flash_area_get_size(fap));
David Vinczee574f2d2020-07-10 11:42:03 +0200754 /* Image is invalid, erase it to prevent further unnecessary
755 * attempts to validate and boot it.
David Brownb38e0442017-02-24 13:57:12 -0700756 */
757 }
David Brown098de832019-12-10 11:58:01 -0700758#if !defined(__BOOTSIM__)
David Vincze2d736ad2019-02-18 11:50:22 +0100759 BOOT_LOG_ERR("Image in the %s slot is not valid!",
760 (slot == BOOT_PRIMARY_SLOT) ? "primary" : "secondary");
David Brown098de832019-12-10 11:58:01 -0700761#endif
Raef Colese8fe6cf2020-05-26 13:07:40 +0100762 fih_rc = fih_int_encode(1);
Fabio Utzig338a19f2018-12-03 08:37:08 -0200763 goto out;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800764 }
765
Fabio Utzig338a19f2018-12-03 08:37:08 -0200766out:
767 flash_area_close(fap);
Raef Colese8fe6cf2020-05-26 13:07:40 +0100768
769 FIH_RET(fih_rc);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800770}
771
David Vinczec3084132020-02-18 14:50:47 +0100772#ifdef MCUBOOT_HW_ROLLBACK_PROT
773/**
774 * Updates the stored security counter value with the image's security counter
775 * value which resides in the given slot, only if it's greater than the stored
776 * value.
777 *
778 * @param image_index Index of the image to determine which security
779 * counter to update.
780 * @param slot Slot number of the image.
781 * @param hdr Pointer to the image header structure of the image
782 * that is currently stored in the given slot.
783 *
784 * @return 0 on success; nonzero on failure.
785 */
786static int
787boot_update_security_counter(uint8_t image_index, int slot,
788 struct image_header *hdr)
789{
790 const struct flash_area *fap = NULL;
791 uint32_t img_security_cnt;
792 int rc;
793
794 rc = flash_area_open(flash_area_id_from_multi_image_slot(image_index, slot),
795 &fap);
796 if (rc != 0) {
797 rc = BOOT_EFLASH;
798 goto done;
799 }
800
801 rc = bootutil_get_img_security_cnt(hdr, fap, &img_security_cnt);
802 if (rc != 0) {
803 goto done;
804 }
805
806 rc = boot_nv_security_counter_update(image_index, img_security_cnt);
807 if (rc != 0) {
808 goto done;
809 }
810
811done:
812 flash_area_close(fap);
813 return rc;
814}
815#endif /* MCUBOOT_HW_ROLLBACK_PROT */
816
Tamas Banfe031092020-09-10 17:32:39 +0200817#if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)
David Vinczee574f2d2020-07-10 11:42:03 +0200818/**
819 * Determines which swap operation to perform, if any. If it is determined
820 * that a swap operation is required, the image in the secondary slot is checked
821 * for validity. If the image in the secondary slot is invalid, it is erased,
822 * and a swap type of "none" is indicated.
823 *
824 * @return The type of swap to perform (BOOT_SWAP_TYPE...)
825 */
826static int
827boot_validated_swap_type(struct boot_loader_state *state,
828 struct boot_status *bs)
829{
830 int swap_type;
Raef Colese8fe6cf2020-05-26 13:07:40 +0100831 fih_int fih_rc = FIH_FAILURE;
David Vinczee574f2d2020-07-10 11:42:03 +0200832
833 swap_type = boot_swap_type_multi(BOOT_CURR_IMG(state));
834 if (BOOT_IS_UPGRADE(swap_type)) {
835 /* Boot loader wants to switch to the secondary slot.
836 * Ensure image is valid.
837 */
Raef Colese8fe6cf2020-05-26 13:07:40 +0100838 FIH_CALL(boot_validate_slot, fih_rc, state, BOOT_SECONDARY_SLOT, bs);
839 if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
840 if (fih_eq(fih_rc, fih_int_encode(1))) {
841 swap_type = BOOT_SWAP_TYPE_NONE;
842 } else {
843 swap_type = BOOT_SWAP_TYPE_FAIL;
844 }
David Vinczee574f2d2020-07-10 11:42:03 +0200845 }
846 }
847
848 return swap_type;
849}
David Brown94ed12c2021-05-26 16:28:14 -0600850#endif
David Vinczee574f2d2020-07-10 11:42:03 +0200851
Christopher Collins92ea77f2016-12-12 15:59:26 -0800852/**
Christopher Collins92ea77f2016-12-12 15:59:26 -0800853 * Erases a region of flash.
854 *
Fabio Utzigba829042018-09-18 08:29:34 -0300855 * @param flash_area The flash_area containing the region to erase.
Christopher Collins92ea77f2016-12-12 15:59:26 -0800856 * @param off The offset within the flash area to start the
857 * erase.
858 * @param sz The number of bytes to erase.
859 *
860 * @return 0 on success; nonzero on failure.
861 */
Fabio Utzig12d59162019-11-28 10:01:59 -0300862int
Fabio Utzigc28005b2019-09-10 12:18:29 -0300863boot_erase_region(const struct flash_area *fap, uint32_t off, uint32_t sz)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800864{
Fabio Utzigba829042018-09-18 08:29:34 -0300865 return flash_area_erase(fap, off, sz);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800866}
867
David Brown94ed12c2021-05-26 16:28:14 -0600868#if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800869/**
870 * Copies the contents of one flash region to another. You must erase the
871 * destination region prior to calling this function.
872 *
873 * @param flash_area_id_src The ID of the source flash area.
874 * @param flash_area_id_dst The ID of the destination flash area.
875 * @param off_src The offset within the source flash area to
876 * copy from.
877 * @param off_dst The offset within the destination flash area to
878 * copy to.
879 * @param sz The number of bytes to copy.
880 *
881 * @return 0 on success; nonzero on failure.
882 */
Fabio Utzig12d59162019-11-28 10:01:59 -0300883int
Fabio Utzigc28005b2019-09-10 12:18:29 -0300884boot_copy_region(struct boot_loader_state *state,
Fabio Utzig10ee6482019-08-01 12:04:52 -0300885 const struct flash_area *fap_src,
Fabio Utzigba829042018-09-18 08:29:34 -0300886 const struct flash_area *fap_dst,
Christopher Collins92ea77f2016-12-12 15:59:26 -0800887 uint32_t off_src, uint32_t off_dst, uint32_t sz)
888{
Christopher Collins92ea77f2016-12-12 15:59:26 -0800889 uint32_t bytes_copied;
890 int chunk_sz;
891 int rc;
Fabio Utzigba829042018-09-18 08:29:34 -0300892#ifdef MCUBOOT_ENC_IMAGES
893 uint32_t off;
Fabio Utziga87cc7d2019-08-26 11:21:45 -0300894 uint32_t tlv_off;
Fabio Utzigba829042018-09-18 08:29:34 -0300895 size_t blk_off;
896 struct image_header *hdr;
897 uint16_t idx;
898 uint32_t blk_sz;
Fabio Utzigb0f04732019-07-31 09:49:19 -0300899 uint8_t image_index;
Fabio Utzigba829042018-09-18 08:29:34 -0300900#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800901
Marek Pietae51ec072021-07-15 14:53:10 +0200902 TARGET_STATIC uint8_t buf[1024] __attribute__((aligned(4)));
Fabio Utzig10ee6482019-08-01 12:04:52 -0300903
904#if !defined(MCUBOOT_ENC_IMAGES)
905 (void)state;
906#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800907
Christopher Collins92ea77f2016-12-12 15:59:26 -0800908 bytes_copied = 0;
909 while (bytes_copied < sz) {
910 if (sz - bytes_copied > sizeof buf) {
911 chunk_sz = sizeof buf;
912 } else {
913 chunk_sz = sz - bytes_copied;
914 }
915
916 rc = flash_area_read(fap_src, off_src + bytes_copied, buf, chunk_sz);
917 if (rc != 0) {
Fabio Utzigba829042018-09-18 08:29:34 -0300918 return BOOT_EFLASH;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800919 }
920
Fabio Utzigba829042018-09-18 08:29:34 -0300921#ifdef MCUBOOT_ENC_IMAGES
Fabio Utzig10ee6482019-08-01 12:04:52 -0300922 image_index = BOOT_CURR_IMG(state);
Dominik Ermel260ae092021-04-23 05:38:45 +0000923 if ((flash_area_get_id(fap_src) == FLASH_AREA_IMAGE_SECONDARY(image_index) ||
924 flash_area_get_id(fap_dst) == FLASH_AREA_IMAGE_SECONDARY(image_index)) &&
925 !(flash_area_get_id(fap_src) == FLASH_AREA_IMAGE_SECONDARY(image_index) &&
926 flash_area_get_id(fap_dst) == FLASH_AREA_IMAGE_SECONDARY(image_index))) {
David Vincze2d736ad2019-02-18 11:50:22 +0100927 /* assume the secondary slot as src, needs decryption */
Fabio Utzig10ee6482019-08-01 12:04:52 -0300928 hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT);
Fabio Utzig74aef312019-11-28 11:05:34 -0300929#if !defined(MCUBOOT_SWAP_USING_MOVE)
Fabio Utzigba829042018-09-18 08:29:34 -0300930 off = off_src;
Dominik Ermel260ae092021-04-23 05:38:45 +0000931 if (flash_area_get_id(fap_dst) == FLASH_AREA_IMAGE_SECONDARY(image_index)) {
David Vincze2d736ad2019-02-18 11:50:22 +0100932 /* might need encryption (metadata from the primary slot) */
Fabio Utzig10ee6482019-08-01 12:04:52 -0300933 hdr = boot_img_hdr(state, BOOT_PRIMARY_SLOT);
Fabio Utzigba829042018-09-18 08:29:34 -0300934 off = off_dst;
935 }
Fabio Utzig74aef312019-11-28 11:05:34 -0300936#else
937 off = off_dst;
Dominik Ermel260ae092021-04-23 05:38:45 +0000938 if (flash_area_get_id(fap_dst) == FLASH_AREA_IMAGE_SECONDARY(image_index)) {
Fabio Utzig74aef312019-11-28 11:05:34 -0300939 hdr = boot_img_hdr(state, BOOT_PRIMARY_SLOT);
940 }
941#endif
Fabio Utzig2fc80df2018-12-14 06:47:38 -0200942 if (IS_ENCRYPTED(hdr)) {
Fabio Utzigba829042018-09-18 08:29:34 -0300943 blk_sz = chunk_sz;
944 idx = 0;
945 if (off + bytes_copied < hdr->ih_hdr_size) {
946 /* do not decrypt header */
947 blk_off = 0;
948 blk_sz = chunk_sz - hdr->ih_hdr_size;
949 idx = hdr->ih_hdr_size;
950 } else {
951 blk_off = ((off + bytes_copied) - hdr->ih_hdr_size) & 0xf;
952 }
Fabio Utziga87cc7d2019-08-26 11:21:45 -0300953 tlv_off = BOOT_TLV_OFF(hdr);
954 if (off + bytes_copied + chunk_sz > tlv_off) {
Fabio Utzigba829042018-09-18 08:29:34 -0300955 /* do not decrypt TLVs */
Fabio Utziga87cc7d2019-08-26 11:21:45 -0300956 if (off + bytes_copied >= tlv_off) {
Fabio Utzigba829042018-09-18 08:29:34 -0300957 blk_sz = 0;
958 } else {
Fabio Utziga87cc7d2019-08-26 11:21:45 -0300959 blk_sz = tlv_off - (off + bytes_copied);
Fabio Utzigba829042018-09-18 08:29:34 -0300960 }
961 }
Fabio Utzig1e4284b2019-08-23 11:55:27 -0300962 boot_encrypt(BOOT_CURR_ENC(state), image_index, fap_src,
Fabio Utzigb0f04732019-07-31 09:49:19 -0300963 (off + bytes_copied + idx) - hdr->ih_hdr_size, blk_sz,
964 blk_off, &buf[idx]);
Fabio Utzigba829042018-09-18 08:29:34 -0300965 }
966 }
967#endif
968
Christopher Collins92ea77f2016-12-12 15:59:26 -0800969 rc = flash_area_write(fap_dst, off_dst + bytes_copied, buf, chunk_sz);
970 if (rc != 0) {
Fabio Utzigba829042018-09-18 08:29:34 -0300971 return BOOT_EFLASH;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800972 }
973
974 bytes_copied += chunk_sz;
Fabio Utzig853657c2019-05-07 08:06:07 -0300975
976 MCUBOOT_WATCHDOG_FEED();
Christopher Collins92ea77f2016-12-12 15:59:26 -0800977 }
978
Fabio Utzigba829042018-09-18 08:29:34 -0300979 return 0;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800980}
981
Christopher Collins92ea77f2016-12-12 15:59:26 -0800982/**
David Vincze2d736ad2019-02-18 11:50:22 +0100983 * Overwrite primary slot with the image contained in the secondary slot.
984 * If a prior copy operation was interrupted by a system reset, this function
985 * redos the copy.
Christopher Collins92ea77f2016-12-12 15:59:26 -0800986 *
987 * @param bs The current boot status. This function reads
988 * this struct to determine if it is resuming
989 * an interrupted swap operation. This
990 * function writes the updated status to this
991 * function on return.
992 *
993 * @return 0 on success; nonzero on failure.
994 */
Fabio Utzig338a19f2018-12-03 08:37:08 -0200995#if defined(MCUBOOT_OVERWRITE_ONLY) || defined(MCUBOOT_BOOTSTRAP)
David Brown17609d82017-05-05 09:41:34 -0600996static int
Fabio Utzig10ee6482019-08-01 12:04:52 -0300997boot_copy_image(struct boot_loader_state *state, struct boot_status *bs)
David Brown17609d82017-05-05 09:41:34 -0600998{
Marti Bolivard3269fd2017-06-12 16:31:12 -0400999 size_t sect_count;
1000 size_t sect;
David Brown17609d82017-05-05 09:41:34 -06001001 int rc;
Fabio Utzig13d9e352017-10-05 20:32:31 -03001002 size_t size;
Marti Bolivard3269fd2017-06-12 16:31:12 -04001003 size_t this_size;
Fabio Utzig13d9e352017-10-05 20:32:31 -03001004 size_t last_sector;
David Vincze2d736ad2019-02-18 11:50:22 +01001005 const struct flash_area *fap_primary_slot;
1006 const struct flash_area *fap_secondary_slot;
Fabio Utzigb0f04732019-07-31 09:49:19 -03001007 uint8_t image_index;
David Vincze2d736ad2019-02-18 11:50:22 +01001008
Fabio Utzigb4f88102020-10-04 10:16:24 -03001009#if defined(MCUBOOT_OVERWRITE_ONLY_FAST)
1010 uint32_t sector;
1011 uint32_t trailer_sz;
1012 uint32_t off;
1013 uint32_t sz;
1014#endif
1015
Fabio Utzigaaf767c2017-12-05 10:22:46 -02001016 (void)bs;
1017
Fabio Utzig13d9e352017-10-05 20:32:31 -03001018#if defined(MCUBOOT_OVERWRITE_ONLY_FAST)
1019 uint32_t src_size = 0;
Fabio Utzigd638b172019-08-09 10:38:05 -03001020 rc = boot_read_image_size(state, BOOT_SECONDARY_SLOT, &src_size);
Fabio Utzig13d9e352017-10-05 20:32:31 -03001021 assert(rc == 0);
1022#endif
David Brown17609d82017-05-05 09:41:34 -06001023
David Vincze2d736ad2019-02-18 11:50:22 +01001024 BOOT_LOG_INF("Image upgrade secondary slot -> primary slot");
1025 BOOT_LOG_INF("Erasing the primary slot");
David Brown17609d82017-05-05 09:41:34 -06001026
Fabio Utzigb0f04732019-07-31 09:49:19 -03001027 image_index = BOOT_CURR_IMG(state);
1028
1029 rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index),
1030 &fap_primary_slot);
Fabio Utzigba829042018-09-18 08:29:34 -03001031 assert (rc == 0);
1032
Fabio Utzigb0f04732019-07-31 09:49:19 -03001033 rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY(image_index),
1034 &fap_secondary_slot);
Fabio Utzigba829042018-09-18 08:29:34 -03001035 assert (rc == 0);
1036
Fabio Utzig10ee6482019-08-01 12:04:52 -03001037 sect_count = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT);
Fabio Utzig13d9e352017-10-05 20:32:31 -03001038 for (sect = 0, size = 0; sect < sect_count; sect++) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001039 this_size = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, sect);
Fabio Utzigc28005b2019-09-10 12:18:29 -03001040 rc = boot_erase_region(fap_primary_slot, size, this_size);
David Brown17609d82017-05-05 09:41:34 -06001041 assert(rc == 0);
1042
Fabio Utzig13d9e352017-10-05 20:32:31 -03001043#if defined(MCUBOOT_OVERWRITE_ONLY_FAST)
Fabio Utzigb4f88102020-10-04 10:16:24 -03001044 if ((size + this_size) >= src_size) {
1045 size += src_size - size;
1046 size += BOOT_WRITE_SZ(state) - (size % BOOT_WRITE_SZ(state));
Fabio Utzig13d9e352017-10-05 20:32:31 -03001047 break;
1048 }
1049#endif
Fabio Utzigb4f88102020-10-04 10:16:24 -03001050
1051 size += this_size;
David Brown17609d82017-05-05 09:41:34 -06001052 }
1053
Fabio Utzigb4f88102020-10-04 10:16:24 -03001054#if defined(MCUBOOT_OVERWRITE_ONLY_FAST)
1055 trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(state));
1056 sector = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT) - 1;
1057 sz = 0;
1058 do {
1059 sz += boot_img_sector_size(state, BOOT_PRIMARY_SLOT, sector);
1060 off = boot_img_sector_off(state, BOOT_PRIMARY_SLOT, sector);
1061 sector--;
1062 } while (sz < trailer_sz);
1063
1064 rc = boot_erase_region(fap_primary_slot, off, sz);
1065 assert(rc == 0);
1066#endif
1067
Fabio Utzigba829042018-09-18 08:29:34 -03001068#ifdef MCUBOOT_ENC_IMAGES
Fabio Utzig10ee6482019-08-01 12:04:52 -03001069 if (IS_ENCRYPTED(boot_img_hdr(state, BOOT_SECONDARY_SLOT))) {
Fabio Utzig1e4284b2019-08-23 11:55:27 -03001070 rc = boot_enc_load(BOOT_CURR_ENC(state), image_index,
Fabio Utzig10ee6482019-08-01 12:04:52 -03001071 boot_img_hdr(state, BOOT_SECONDARY_SLOT),
Fabio Utzig4741c452019-12-19 15:32:41 -03001072 fap_secondary_slot, bs);
David Vincze2d736ad2019-02-18 11:50:22 +01001073
Fabio Utzigba829042018-09-18 08:29:34 -03001074 if (rc < 0) {
1075 return BOOT_EBADIMAGE;
1076 }
Fabio Utzig4741c452019-12-19 15:32:41 -03001077 if (rc == 0 && boot_enc_set_key(BOOT_CURR_ENC(state), 1, bs)) {
Fabio Utzigba829042018-09-18 08:29:34 -03001078 return BOOT_EBADIMAGE;
1079 }
1080 }
1081#endif
1082
David Vincze2d736ad2019-02-18 11:50:22 +01001083 BOOT_LOG_INF("Copying the secondary slot to the primary slot: 0x%zx bytes",
1084 size);
Fabio Utzigc28005b2019-09-10 12:18:29 -03001085 rc = boot_copy_region(state, fap_secondary_slot, fap_primary_slot, 0, 0, size);
Fabio Utzigb4f88102020-10-04 10:16:24 -03001086 if (rc != 0) {
1087 return rc;
1088 }
1089
1090#if defined(MCUBOOT_OVERWRITE_ONLY_FAST)
1091 rc = boot_write_magic(fap_primary_slot);
1092 if (rc != 0) {
1093 return rc;
1094 }
1095#endif
David Brown17609d82017-05-05 09:41:34 -06001096
Andrzej Puzdrowskib8f39692021-07-02 15:05:37 +02001097 rc = BOOT_HOOK_CALL(boot_copy_region_post_hook, 0, BOOT_CURR_IMG(state),
1098 BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT), size);
1099 if (rc != 0) {
1100 return rc;
1101 }
1102
David Vinczec3084132020-02-18 14:50:47 +01001103#ifdef MCUBOOT_HW_ROLLBACK_PROT
1104 /* Update the stored security counter with the new image's security counter
1105 * value. Both slots hold the new image at this point, but the secondary
1106 * slot's image header must be passed since the image headers in the
1107 * boot_data structure have not been updated yet.
1108 */
1109 rc = boot_update_security_counter(BOOT_CURR_IMG(state), BOOT_PRIMARY_SLOT,
1110 boot_img_hdr(state, BOOT_SECONDARY_SLOT));
1111 if (rc != 0) {
1112 BOOT_LOG_ERR("Security counter update failed after image upgrade.");
1113 return rc;
1114 }
1115#endif /* MCUBOOT_HW_ROLLBACK_PROT */
1116
Fabio Utzig13d9e352017-10-05 20:32:31 -03001117 /*
1118 * Erases header and trailer. The trailer is erased because when a new
1119 * image is written without a trailer as is the case when using newt, the
1120 * trailer that was left might trigger a new upgrade.
1121 */
Christopher Collins2c88e692019-05-22 15:10:14 -07001122 BOOT_LOG_DBG("erasing secondary header");
Fabio Utzigc28005b2019-09-10 12:18:29 -03001123 rc = boot_erase_region(fap_secondary_slot,
Fabio Utzig10ee6482019-08-01 12:04:52 -03001124 boot_img_sector_off(state, BOOT_SECONDARY_SLOT, 0),
1125 boot_img_sector_size(state, BOOT_SECONDARY_SLOT, 0));
David Brown17609d82017-05-05 09:41:34 -06001126 assert(rc == 0);
Fabio Utzig10ee6482019-08-01 12:04:52 -03001127 last_sector = boot_img_num_sectors(state, BOOT_SECONDARY_SLOT) - 1;
Christopher Collins2c88e692019-05-22 15:10:14 -07001128 BOOT_LOG_DBG("erasing secondary trailer");
Fabio Utzigc28005b2019-09-10 12:18:29 -03001129 rc = boot_erase_region(fap_secondary_slot,
Fabio Utzig10ee6482019-08-01 12:04:52 -03001130 boot_img_sector_off(state, BOOT_SECONDARY_SLOT,
1131 last_sector),
1132 boot_img_sector_size(state, BOOT_SECONDARY_SLOT,
1133 last_sector));
Fabio Utzig13d9e352017-10-05 20:32:31 -03001134 assert(rc == 0);
1135
David Vincze2d736ad2019-02-18 11:50:22 +01001136 flash_area_close(fap_primary_slot);
1137 flash_area_close(fap_secondary_slot);
Fabio Utzigba829042018-09-18 08:29:34 -03001138
David Vincze2d736ad2019-02-18 11:50:22 +01001139 /* TODO: Perhaps verify the primary slot's signature again? */
David Brown17609d82017-05-05 09:41:34 -06001140
1141 return 0;
1142}
Fabio Utzig338a19f2018-12-03 08:37:08 -02001143#endif
Fabio Utzigba829042018-09-18 08:29:34 -03001144
Christopher Collinsa1c12042019-05-23 14:00:28 -07001145#if !defined(MCUBOOT_OVERWRITE_ONLY)
Fabio Utzigba829042018-09-18 08:29:34 -03001146/**
1147 * Swaps the two images in flash. If a prior copy operation was interrupted
1148 * by a system reset, this function completes that operation.
1149 *
1150 * @param bs The current boot status. This function reads
1151 * this struct to determine if it is resuming
1152 * an interrupted swap operation. This
1153 * function writes the updated status to this
1154 * function on return.
1155 *
1156 * @return 0 on success; nonzero on failure.
1157 */
Christopher Collins92ea77f2016-12-12 15:59:26 -08001158static int
Fabio Utzig10ee6482019-08-01 12:04:52 -03001159boot_swap_image(struct boot_loader_state *state, struct boot_status *bs)
Christopher Collins92ea77f2016-12-12 15:59:26 -08001160{
Fabio Utzig2473ac02017-05-02 12:45:02 -03001161 struct image_header *hdr;
Fabio Utzigba829042018-09-18 08:29:34 -03001162#ifdef MCUBOOT_ENC_IMAGES
1163 const struct flash_area *fap;
1164 uint8_t slot;
1165 uint8_t i;
Fabio Utzigba829042018-09-18 08:29:34 -03001166#endif
Fabio Utzig2473ac02017-05-02 12:45:02 -03001167 uint32_t size;
1168 uint32_t copy_size;
Fabio Utzigb0f04732019-07-31 09:49:19 -03001169 uint8_t image_index;
Fabio Utzig2473ac02017-05-02 12:45:02 -03001170 int rc;
1171
1172 /* FIXME: just do this if asked by user? */
1173
1174 size = copy_size = 0;
Fabio Utzig10ee6482019-08-01 12:04:52 -03001175 image_index = BOOT_CURR_IMG(state);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001176
Fabio Utzig12d59162019-11-28 10:01:59 -03001177 if (boot_status_is_reset(bs)) {
Fabio Utzig46490722017-09-04 15:34:32 -03001178 /*
1179 * No swap ever happened, so need to find the largest image which
1180 * will be used to determine the amount of sectors to swap.
1181 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001182 hdr = boot_img_hdr(state, BOOT_PRIMARY_SLOT);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001183 if (hdr->ih_magic == IMAGE_MAGIC) {
Fabio Utzigd638b172019-08-09 10:38:05 -03001184 rc = boot_read_image_size(state, BOOT_PRIMARY_SLOT, &copy_size);
David Brownf5b33d82017-09-01 10:58:27 -06001185 assert(rc == 0);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001186 }
Fabio Utzig2473ac02017-05-02 12:45:02 -03001187
Fabio Utzigba829042018-09-18 08:29:34 -03001188#ifdef MCUBOOT_ENC_IMAGES
Fabio Utzig2fc80df2018-12-14 06:47:38 -02001189 if (IS_ENCRYPTED(hdr)) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001190 fap = BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT);
Fabio Utzig4741c452019-12-19 15:32:41 -03001191 rc = boot_enc_load(BOOT_CURR_ENC(state), image_index, hdr, fap, bs);
Fabio Utzigba829042018-09-18 08:29:34 -03001192 assert(rc >= 0);
1193
1194 if (rc == 0) {
Fabio Utzig4741c452019-12-19 15:32:41 -03001195 rc = boot_enc_set_key(BOOT_CURR_ENC(state), 0, bs);
Fabio Utzigba829042018-09-18 08:29:34 -03001196 assert(rc == 0);
1197 } else {
1198 rc = 0;
1199 }
1200 } else {
1201 memset(bs->enckey[0], 0xff, BOOT_ENC_KEY_SIZE);
1202 }
1203#endif
1204
Fabio Utzig10ee6482019-08-01 12:04:52 -03001205 hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT);
Fabio Utzig46490722017-09-04 15:34:32 -03001206 if (hdr->ih_magic == IMAGE_MAGIC) {
Fabio Utzigd638b172019-08-09 10:38:05 -03001207 rc = boot_read_image_size(state, BOOT_SECONDARY_SLOT, &size);
Fabio Utzig46490722017-09-04 15:34:32 -03001208 assert(rc == 0);
1209 }
1210
Fabio Utzigba829042018-09-18 08:29:34 -03001211#ifdef MCUBOOT_ENC_IMAGES
Fabio Utzig10ee6482019-08-01 12:04:52 -03001212 hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT);
Fabio Utzig2fc80df2018-12-14 06:47:38 -02001213 if (IS_ENCRYPTED(hdr)) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001214 fap = BOOT_IMG_AREA(state, BOOT_SECONDARY_SLOT);
Fabio Utzig4741c452019-12-19 15:32:41 -03001215 rc = boot_enc_load(BOOT_CURR_ENC(state), image_index, hdr, fap, bs);
Fabio Utzigba829042018-09-18 08:29:34 -03001216 assert(rc >= 0);
1217
1218 if (rc == 0) {
Fabio Utzig4741c452019-12-19 15:32:41 -03001219 rc = boot_enc_set_key(BOOT_CURR_ENC(state), 1, bs);
Fabio Utzigba829042018-09-18 08:29:34 -03001220 assert(rc == 0);
1221 } else {
1222 rc = 0;
1223 }
1224 } else {
1225 memset(bs->enckey[1], 0xff, BOOT_ENC_KEY_SIZE);
1226 }
1227#endif
1228
Fabio Utzig46490722017-09-04 15:34:32 -03001229 if (size > copy_size) {
1230 copy_size = size;
1231 }
1232
1233 bs->swap_size = copy_size;
1234 } else {
1235 /*
1236 * If a swap was under way, the swap_size should already be present
1237 * in the trailer...
1238 */
Fabio Utzigb0f04732019-07-31 09:49:19 -03001239 rc = boot_read_swap_size(image_index, &bs->swap_size);
Fabio Utzig46490722017-09-04 15:34:32 -03001240 assert(rc == 0);
1241
1242 copy_size = bs->swap_size;
Fabio Utzigba829042018-09-18 08:29:34 -03001243
1244#ifdef MCUBOOT_ENC_IMAGES
Fabio Utzig4741c452019-12-19 15:32:41 -03001245 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
1246 rc = boot_read_enc_key(image_index, slot, bs);
Fabio Utzigba829042018-09-18 08:29:34 -03001247 assert(rc == 0);
1248
1249 for (i = 0; i < BOOT_ENC_KEY_SIZE; i++) {
Fabio Utzig1c7d9592018-12-03 10:35:56 -02001250 if (bs->enckey[slot][i] != 0xff) {
Fabio Utzigba829042018-09-18 08:29:34 -03001251 break;
1252 }
1253 }
1254
1255 if (i != BOOT_ENC_KEY_SIZE) {
Fabio Utzig4741c452019-12-19 15:32:41 -03001256 boot_enc_set_key(BOOT_CURR_ENC(state), slot, bs);
Fabio Utzigba829042018-09-18 08:29:34 -03001257 }
1258 }
1259#endif
Fabio Utzig2473ac02017-05-02 12:45:02 -03001260 }
1261
Fabio Utzig12d59162019-11-28 10:01:59 -03001262 swap_run(state, bs, copy_size);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001263
David Vincze2d736ad2019-02-18 11:50:22 +01001264#ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT
Fabio Utzig12d59162019-11-28 10:01:59 -03001265 extern int boot_status_fails;
Fabio Utziga0e1cce2017-11-23 20:04:01 -02001266 if (boot_status_fails > 0) {
Christopher Collins2c88e692019-05-22 15:10:14 -07001267 BOOT_LOG_WRN("%d status write fails performing the swap",
1268 boot_status_fails);
Fabio Utziga0e1cce2017-11-23 20:04:01 -02001269 }
1270#endif
1271
Christopher Collins92ea77f2016-12-12 15:59:26 -08001272 return 0;
1273}
David Brown17609d82017-05-05 09:41:34 -06001274#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -08001275
David Vinczee32483f2019-06-13 10:46:24 +02001276#if (BOOT_IMAGE_NUMBER > 1)
1277/**
1278 * Check the image dependency whether it is satisfied and modify
1279 * the swap type if necessary.
1280 *
1281 * @param dep Image dependency which has to be verified.
1282 *
1283 * @return 0 on success; nonzero on failure.
1284 */
1285static int
Fabio Utzig298913b2019-08-28 11:22:45 -03001286boot_verify_slot_dependency(struct boot_loader_state *state,
1287 struct image_dependency *dep)
David Vinczee32483f2019-06-13 10:46:24 +02001288{
1289 struct image_version *dep_version;
1290 size_t dep_slot;
1291 int rc;
David Browne6ab34c2019-09-03 12:24:21 -06001292 uint8_t swap_type;
David Vinczee32483f2019-06-13 10:46:24 +02001293
1294 /* Determine the source of the image which is the subject of
1295 * the dependency and get it's version. */
David Browne6ab34c2019-09-03 12:24:21 -06001296 swap_type = state->swap_type[dep->image_id];
Barry Solomon04075532020-03-18 09:33:32 -04001297 dep_slot = BOOT_IS_UPGRADE(swap_type) ? BOOT_SECONDARY_SLOT
1298 : BOOT_PRIMARY_SLOT;
Fabio Utzig10ee6482019-08-01 12:04:52 -03001299 dep_version = &state->imgs[dep->image_id][dep_slot].hdr.ih_ver;
David Vinczee32483f2019-06-13 10:46:24 +02001300
David Vincze8b0b6372020-05-20 19:54:44 +02001301 rc = boot_version_cmp(dep_version, &dep->image_min_version);
1302 if (rc < 0) {
David Vinczee32483f2019-06-13 10:46:24 +02001303 /* Dependency not satisfied.
1304 * Modify the swap type to decrease the version number of the image
1305 * (which will be located in the primary slot after the boot process),
1306 * consequently the number of unsatisfied dependencies will be
1307 * decreased or remain the same.
1308 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001309 switch (BOOT_SWAP_TYPE(state)) {
David Vinczee32483f2019-06-13 10:46:24 +02001310 case BOOT_SWAP_TYPE_TEST:
1311 case BOOT_SWAP_TYPE_PERM:
Fabio Utzig10ee6482019-08-01 12:04:52 -03001312 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
David Vinczee32483f2019-06-13 10:46:24 +02001313 break;
1314 case BOOT_SWAP_TYPE_NONE:
Fabio Utzig10ee6482019-08-01 12:04:52 -03001315 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_REVERT;
David Vinczee32483f2019-06-13 10:46:24 +02001316 break;
1317 default:
1318 break;
1319 }
David Vincze8b0b6372020-05-20 19:54:44 +02001320 } else {
1321 /* Dependency satisfied. */
1322 rc = 0;
David Vinczee32483f2019-06-13 10:46:24 +02001323 }
1324
1325 return rc;
1326}
1327
1328/**
1329 * Read all dependency TLVs of an image from the flash and verify
1330 * one after another to see if they are all satisfied.
1331 *
1332 * @param slot Image slot number.
1333 *
1334 * @return 0 on success; nonzero on failure.
1335 */
1336static int
Fabio Utzig298913b2019-08-28 11:22:45 -03001337boot_verify_slot_dependencies(struct boot_loader_state *state, uint32_t slot)
David Vinczee32483f2019-06-13 10:46:24 +02001338{
1339 const struct flash_area *fap;
Fabio Utzig61fd8882019-09-14 20:00:20 -03001340 struct image_tlv_iter it;
David Vinczee32483f2019-06-13 10:46:24 +02001341 struct image_dependency dep;
1342 uint32_t off;
Fabio Utzig61fd8882019-09-14 20:00:20 -03001343 uint16_t len;
Fabio Utzigb0f04732019-07-31 09:49:19 -03001344 int area_id;
David Vinczee32483f2019-06-13 10:46:24 +02001345 int rc;
1346
Fabio Utzig10ee6482019-08-01 12:04:52 -03001347 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
Fabio Utzigb0f04732019-07-31 09:49:19 -03001348 rc = flash_area_open(area_id, &fap);
David Vinczee32483f2019-06-13 10:46:24 +02001349 if (rc != 0) {
1350 rc = BOOT_EFLASH;
1351 goto done;
1352 }
1353
Fabio Utzig61fd8882019-09-14 20:00:20 -03001354 rc = bootutil_tlv_iter_begin(&it, boot_img_hdr(state, slot), fap,
1355 IMAGE_TLV_DEPENDENCY, true);
David Vinczee32483f2019-06-13 10:46:24 +02001356 if (rc != 0) {
David Vinczee32483f2019-06-13 10:46:24 +02001357 goto done;
1358 }
1359
Fabio Utzig61fd8882019-09-14 20:00:20 -03001360 while (true) {
1361 rc = bootutil_tlv_iter_next(&it, &off, &len, NULL);
1362 if (rc < 0) {
1363 return -1;
1364 } else if (rc > 0) {
1365 rc = 0;
David Vinczee32483f2019-06-13 10:46:24 +02001366 break;
1367 }
Fabio Utzig61fd8882019-09-14 20:00:20 -03001368
1369 if (len != sizeof(dep)) {
1370 rc = BOOT_EBADIMAGE;
1371 goto done;
1372 }
1373
1374 rc = flash_area_read(fap, off, &dep, len);
1375 if (rc != 0) {
1376 rc = BOOT_EFLASH;
1377 goto done;
1378 }
1379
1380 if (dep.image_id >= BOOT_IMAGE_NUMBER) {
1381 rc = BOOT_EBADARGS;
1382 goto done;
1383 }
1384
1385 /* Verify dependency and modify the swap type if not satisfied. */
1386 rc = boot_verify_slot_dependency(state, &dep);
1387 if (rc != 0) {
1388 /* Dependency not satisfied. */
1389 goto done;
1390 }
David Vinczee32483f2019-06-13 10:46:24 +02001391 }
1392
1393done:
1394 flash_area_close(fap);
1395 return rc;
1396}
1397
1398/**
David Vinczee32483f2019-06-13 10:46:24 +02001399 * Iterate over all the images and verify whether the image dependencies in the
1400 * TLV area are all satisfied and update the related swap type if necessary.
1401 */
Fabio Utzig298913b2019-08-28 11:22:45 -03001402static int
1403boot_verify_dependencies(struct boot_loader_state *state)
David Vinczee32483f2019-06-13 10:46:24 +02001404{
Erik Johnson49063752020-02-06 09:59:31 -06001405 int rc = -1;
Fabio Utzig298913b2019-08-28 11:22:45 -03001406 uint8_t slot;
David Vinczee32483f2019-06-13 10:46:24 +02001407
Fabio Utzig10ee6482019-08-01 12:04:52 -03001408 BOOT_CURR_IMG(state) = 0;
1409 while (BOOT_CURR_IMG(state) < BOOT_IMAGE_NUMBER) {
Fabio Utzig298913b2019-08-28 11:22:45 -03001410 if (BOOT_SWAP_TYPE(state) != BOOT_SWAP_TYPE_NONE &&
1411 BOOT_SWAP_TYPE(state) != BOOT_SWAP_TYPE_FAIL) {
1412 slot = BOOT_SECONDARY_SLOT;
1413 } else {
1414 slot = BOOT_PRIMARY_SLOT;
1415 }
1416
1417 rc = boot_verify_slot_dependencies(state, slot);
Fabio Utzigabec0732019-07-31 08:40:22 -03001418 if (rc == 0) {
David Vinczee32483f2019-06-13 10:46:24 +02001419 /* All dependencies've been satisfied, continue with next image. */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001420 BOOT_CURR_IMG(state)++;
David Vincze8b0b6372020-05-20 19:54:44 +02001421 } else {
Fabio Utzig298913b2019-08-28 11:22:45 -03001422 /* Cannot upgrade due to non-met dependencies, so disable all
1423 * image upgrades.
1424 */
1425 for (int idx = 0; idx < BOOT_IMAGE_NUMBER; idx++) {
1426 BOOT_CURR_IMG(state) = idx;
1427 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
1428 }
1429 break;
David Vinczee32483f2019-06-13 10:46:24 +02001430 }
1431 }
Fabio Utzig298913b2019-08-28 11:22:45 -03001432 return rc;
David Vinczee32483f2019-06-13 10:46:24 +02001433}
1434#endif /* (BOOT_IMAGE_NUMBER > 1) */
1435
Christopher Collins92ea77f2016-12-12 15:59:26 -08001436/**
David Vinczeba3bd602019-06-17 16:01:43 +02001437 * Performs a clean (not aborted) image update.
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001438 *
David Vinczeba3bd602019-06-17 16:01:43 +02001439 * @param bs The current boot status.
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001440 *
1441 * @return 0 on success; nonzero on failure.
1442 */
1443static int
Fabio Utzig10ee6482019-08-01 12:04:52 -03001444boot_perform_update(struct boot_loader_state *state, struct boot_status *bs)
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001445{
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001446 int rc;
Fabio Utzig10ee6482019-08-01 12:04:52 -03001447#ifndef MCUBOOT_OVERWRITE_ONLY
1448 uint8_t swap_type;
1449#endif
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001450
David Vinczeba3bd602019-06-17 16:01:43 +02001451 /* At this point there are no aborted swaps. */
1452#if defined(MCUBOOT_OVERWRITE_ONLY)
Fabio Utzig10ee6482019-08-01 12:04:52 -03001453 rc = boot_copy_image(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02001454#elif defined(MCUBOOT_BOOTSTRAP)
1455 /* Check if the image update was triggered by a bad image in the
1456 * primary slot (the validity of the image in the secondary slot had
1457 * already been checked).
1458 */
Raef Colese8fe6cf2020-05-26 13:07:40 +01001459 fih_int fih_rc = FIH_FAILURE;
1460 rc = boot_check_header_erased(state, BOOT_PRIMARY_SLOT);
1461 FIH_CALL(boot_validate_slot, fih_rc, state, BOOT_PRIMARY_SLOT, bs);
1462 if (rc == 0 || fih_not_eq(fih_rc, FIH_SUCCESS)) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001463 rc = boot_copy_image(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02001464 } else {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001465 rc = boot_swap_image(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02001466 }
1467#else
Fabio Utzig10ee6482019-08-01 12:04:52 -03001468 rc = boot_swap_image(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02001469#endif
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001470 assert(rc == 0);
David Vinczeba3bd602019-06-17 16:01:43 +02001471
1472#ifndef MCUBOOT_OVERWRITE_ONLY
1473 /* The following state needs image_ok be explicitly set after the
1474 * swap was finished to avoid a new revert.
1475 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001476 swap_type = BOOT_SWAP_TYPE(state);
1477 if (swap_type == BOOT_SWAP_TYPE_REVERT ||
1478 swap_type == BOOT_SWAP_TYPE_PERM) {
Fabio Utzig12d59162019-11-28 10:01:59 -03001479 rc = swap_set_image_ok(BOOT_CURR_IMG(state));
David Vinczeba3bd602019-06-17 16:01:43 +02001480 if (rc != 0) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001481 BOOT_SWAP_TYPE(state) = swap_type = BOOT_SWAP_TYPE_PANIC;
David Vinczeba3bd602019-06-17 16:01:43 +02001482 }
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001483 }
1484
David Vinczec3084132020-02-18 14:50:47 +01001485#ifdef MCUBOOT_HW_ROLLBACK_PROT
1486 if (swap_type == BOOT_SWAP_TYPE_PERM) {
1487 /* Update the stored security counter with the new image's security
1488 * counter value. The primary slot holds the new image at this point,
1489 * but the secondary slot's image header must be passed since image
1490 * headers in the boot_data structure have not been updated yet.
1491 *
1492 * In case of a permanent image swap mcuboot will never attempt to
1493 * revert the images on the next reboot. Therefore, the security
1494 * counter must be increased right after the image upgrade.
1495 */
1496 rc = boot_update_security_counter(
1497 BOOT_CURR_IMG(state),
1498 BOOT_PRIMARY_SLOT,
1499 boot_img_hdr(state, BOOT_SECONDARY_SLOT));
1500 if (rc != 0) {
1501 BOOT_LOG_ERR("Security counter update failed after "
1502 "image upgrade.");
1503 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
1504 }
1505 }
1506#endif /* MCUBOOT_HW_ROLLBACK_PROT */
1507
Fabio Utzige575b0b2019-09-11 12:34:23 -03001508 if (BOOT_IS_UPGRADE(swap_type)) {
Fabio Utzig12d59162019-11-28 10:01:59 -03001509 rc = swap_set_copy_done(BOOT_CURR_IMG(state));
David Vinczeba3bd602019-06-17 16:01:43 +02001510 if (rc != 0) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001511 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
Christopher Collinsa1c12042019-05-23 14:00:28 -07001512 }
David Vinczeba3bd602019-06-17 16:01:43 +02001513 }
1514#endif /* !MCUBOOT_OVERWRITE_ONLY */
Fabio Utzig338a19f2018-12-03 08:37:08 -02001515
David Vinczeba3bd602019-06-17 16:01:43 +02001516 return rc;
1517}
1518
1519/**
1520 * Completes a previously aborted image swap.
1521 *
1522 * @param bs The current boot status.
1523 *
1524 * @return 0 on success; nonzero on failure.
1525 */
1526#if !defined(MCUBOOT_OVERWRITE_ONLY)
1527static int
Fabio Utzig10ee6482019-08-01 12:04:52 -03001528boot_complete_partial_swap(struct boot_loader_state *state,
1529 struct boot_status *bs)
David Vinczeba3bd602019-06-17 16:01:43 +02001530{
1531 int rc;
1532
1533 /* Determine the type of swap operation being resumed from the
1534 * `swap-type` trailer field.
1535 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001536 rc = boot_swap_image(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02001537 assert(rc == 0);
1538
Fabio Utzig10ee6482019-08-01 12:04:52 -03001539 BOOT_SWAP_TYPE(state) = bs->swap_type;
David Vinczeba3bd602019-06-17 16:01:43 +02001540
1541 /* The following states need image_ok be explicitly set after the
1542 * swap was finished to avoid a new revert.
1543 */
1544 if (bs->swap_type == BOOT_SWAP_TYPE_REVERT ||
1545 bs->swap_type == BOOT_SWAP_TYPE_PERM) {
Fabio Utzig12d59162019-11-28 10:01:59 -03001546 rc = swap_set_image_ok(BOOT_CURR_IMG(state));
David Vinczeba3bd602019-06-17 16:01:43 +02001547 if (rc != 0) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001548 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
David Vinczeba3bd602019-06-17 16:01:43 +02001549 }
1550 }
1551
Fabio Utzige575b0b2019-09-11 12:34:23 -03001552 if (BOOT_IS_UPGRADE(bs->swap_type)) {
Fabio Utzig12d59162019-11-28 10:01:59 -03001553 rc = swap_set_copy_done(BOOT_CURR_IMG(state));
David Vinczeba3bd602019-06-17 16:01:43 +02001554 if (rc != 0) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001555 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
David Vinczeba3bd602019-06-17 16:01:43 +02001556 }
1557 }
1558
Fabio Utzig10ee6482019-08-01 12:04:52 -03001559 if (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_PANIC) {
David Vinczeba3bd602019-06-17 16:01:43 +02001560 BOOT_LOG_ERR("panic!");
1561 assert(0);
1562
1563 /* Loop forever... */
1564 while (1) {}
1565 }
1566
1567 return rc;
1568}
1569#endif /* !MCUBOOT_OVERWRITE_ONLY */
1570
1571#if (BOOT_IMAGE_NUMBER > 1)
1572/**
1573 * Review the validity of previously determined swap types of other images.
1574 *
1575 * @param aborted_swap The current image upgrade is a
1576 * partial/aborted swap.
1577 */
1578static void
Fabio Utzig10ee6482019-08-01 12:04:52 -03001579boot_review_image_swap_types(struct boot_loader_state *state,
1580 bool aborted_swap)
David Vinczeba3bd602019-06-17 16:01:43 +02001581{
1582 /* In that case if we rebooted in the middle of an image upgrade process, we
1583 * must review the validity of swap types, that were previously determined
1584 * for other images. The image_ok flag had not been set before the reboot
1585 * for any of the updated images (only the copy_done flag) and thus falsely
1586 * the REVERT swap type has been determined for the previous images that had
1587 * been updated before the reboot.
1588 *
1589 * There are two separate scenarios that we have to deal with:
1590 *
1591 * 1. The reboot has happened during swapping an image:
1592 * The current image upgrade has been determined as a
1593 * partial/aborted swap.
1594 * 2. The reboot has happened between two separate image upgrades:
1595 * In this scenario we must check the swap type of the current image.
1596 * In those cases if it is NONE or REVERT we cannot certainly determine
1597 * the fact of a reboot. In a consistent state images must move in the
1598 * same direction or stay in place, e.g. in practice REVERT and TEST
1599 * swap types cannot be present at the same time. If the swap type of
1600 * the current image is either TEST, PERM or FAIL we must review the
1601 * already determined swap types of other images and set each false
1602 * REVERT swap types to NONE (these images had been successfully
1603 * updated before the system rebooted between two separate image
1604 * upgrades).
1605 */
1606
Fabio Utzig10ee6482019-08-01 12:04:52 -03001607 if (BOOT_CURR_IMG(state) == 0) {
David Vinczeba3bd602019-06-17 16:01:43 +02001608 /* Nothing to do */
1609 return;
1610 }
1611
1612 if (!aborted_swap) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001613 if ((BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_NONE) ||
1614 (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_REVERT)) {
David Vinczeba3bd602019-06-17 16:01:43 +02001615 /* Nothing to do */
1616 return;
1617 }
1618 }
1619
Fabio Utzig10ee6482019-08-01 12:04:52 -03001620 for (uint8_t i = 0; i < BOOT_CURR_IMG(state); i++) {
1621 if (state->swap_type[i] == BOOT_SWAP_TYPE_REVERT) {
1622 state->swap_type[i] = BOOT_SWAP_TYPE_NONE;
David Vinczeba3bd602019-06-17 16:01:43 +02001623 }
1624 }
1625}
1626#endif
1627
1628/**
1629 * Prepare image to be updated if required.
1630 *
1631 * Prepare image to be updated if required with completing an image swap
1632 * operation if one was aborted and/or determining the type of the
1633 * swap operation. In case of any error set the swap type to NONE.
1634 *
Fabio Utzig10ee6482019-08-01 12:04:52 -03001635 * @param state TODO
David Vinczeba3bd602019-06-17 16:01:43 +02001636 * @param bs Pointer where the read and possibly updated
1637 * boot status can be written to.
1638 */
1639static void
Fabio Utzig10ee6482019-08-01 12:04:52 -03001640boot_prepare_image_for_update(struct boot_loader_state *state,
1641 struct boot_status *bs)
David Vinczeba3bd602019-06-17 16:01:43 +02001642{
1643 int rc;
Raef Colese8fe6cf2020-05-26 13:07:40 +01001644 fih_int fih_rc = FIH_FAILURE;
David Vinczeba3bd602019-06-17 16:01:43 +02001645
1646 /* Determine the sector layout of the image slots and scratch area. */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001647 rc = boot_read_sectors(state);
David Vinczeba3bd602019-06-17 16:01:43 +02001648 if (rc != 0) {
1649 BOOT_LOG_WRN("Failed reading sectors; BOOT_MAX_IMG_SECTORS=%d"
1650 " - too small?", BOOT_MAX_IMG_SECTORS);
1651 /* Unable to determine sector layout, continue with next image
1652 * if there is one.
1653 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001654 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
Andrzej Puzdrowski54b4ad92021-06-22 13:21:22 +02001655 if (rc == BOOT_EFLASH)
1656 {
1657 /* Only return on error from the primary image flash */
1658 return;
1659 }
David Vinczeba3bd602019-06-17 16:01:43 +02001660 }
1661
1662 /* Attempt to read an image header from each slot. */
Fabio Utzig12d59162019-11-28 10:01:59 -03001663 rc = boot_read_image_headers(state, false, NULL);
David Vinczeba3bd602019-06-17 16:01:43 +02001664 if (rc != 0) {
1665 /* Continue with next image if there is one. */
Fabio Utzigb0f04732019-07-31 09:49:19 -03001666 BOOT_LOG_WRN("Failed reading image headers; Image=%u",
Fabio Utzig10ee6482019-08-01 12:04:52 -03001667 BOOT_CURR_IMG(state));
1668 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
David Vinczeba3bd602019-06-17 16:01:43 +02001669 return;
1670 }
1671
1672 /* If the current image's slots aren't compatible, no swap is possible.
1673 * Just boot into primary slot.
1674 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001675 if (boot_slots_compatible(state)) {
Fabio Utzig12d59162019-11-28 10:01:59 -03001676 boot_status_reset(bs);
1677
1678#ifndef MCUBOOT_OVERWRITE_ONLY
1679 rc = swap_read_status(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02001680 if (rc != 0) {
1681 BOOT_LOG_WRN("Failed reading boot status; Image=%u",
Fabio Utzig10ee6482019-08-01 12:04:52 -03001682 BOOT_CURR_IMG(state));
David Vinczeba3bd602019-06-17 16:01:43 +02001683 /* Continue with next image if there is one. */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001684 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
David Vinczeba3bd602019-06-17 16:01:43 +02001685 return;
1686 }
Fabio Utzig12d59162019-11-28 10:01:59 -03001687#endif
David Vinczeba3bd602019-06-17 16:01:43 +02001688
Fabio Utzig74aef312019-11-28 11:05:34 -03001689#ifdef MCUBOOT_SWAP_USING_MOVE
1690 /*
1691 * Must re-read image headers because the boot status might
1692 * have been updated in the previous function call.
1693 */
1694 rc = boot_read_image_headers(state, !boot_status_is_reset(bs), bs);
Fabio Utzig32afe852020-10-04 10:36:02 -03001695#ifdef MCUBOOT_BOOTSTRAP
1696 /* When bootstrapping it's OK to not have image magic in the primary slot */
1697 if (rc != 0 && (BOOT_CURR_IMG(state) != BOOT_PRIMARY_SLOT ||
1698 boot_check_header_erased(state, BOOT_PRIMARY_SLOT) != 0)) {
1699#else
Fabio Utzig74aef312019-11-28 11:05:34 -03001700 if (rc != 0) {
Fabio Utzig32afe852020-10-04 10:36:02 -03001701#endif
1702
Fabio Utzig74aef312019-11-28 11:05:34 -03001703 /* Continue with next image if there is one. */
1704 BOOT_LOG_WRN("Failed reading image headers; Image=%u",
1705 BOOT_CURR_IMG(state));
1706 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
1707 return;
1708 }
1709#endif
1710
David Vinczeba3bd602019-06-17 16:01:43 +02001711 /* Determine if we rebooted in the middle of an image swap
1712 * operation. If a partial swap was detected, complete it.
1713 */
Fabio Utzig12d59162019-11-28 10:01:59 -03001714 if (!boot_status_is_reset(bs)) {
David Vinczeba3bd602019-06-17 16:01:43 +02001715
1716#if (BOOT_IMAGE_NUMBER > 1)
Fabio Utzig10ee6482019-08-01 12:04:52 -03001717 boot_review_image_swap_types(state, true);
David Vinczeba3bd602019-06-17 16:01:43 +02001718#endif
1719
1720#ifdef MCUBOOT_OVERWRITE_ONLY
1721 /* Should never arrive here, overwrite-only mode has
1722 * no swap state.
1723 */
1724 assert(0);
1725#else
1726 /* Determine the type of swap operation being resumed from the
1727 * `swap-type` trailer field.
1728 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001729 rc = boot_complete_partial_swap(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02001730 assert(rc == 0);
1731#endif
1732 /* Attempt to read an image header from each slot. Ensure that
1733 * image headers in slots are aligned with headers in boot_data.
1734 */
Fabio Utzig12d59162019-11-28 10:01:59 -03001735 rc = boot_read_image_headers(state, false, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02001736 assert(rc == 0);
1737
1738 /* Swap has finished set to NONE */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001739 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
David Vinczeba3bd602019-06-17 16:01:43 +02001740 } else {
1741 /* There was no partial swap, determine swap type. */
1742 if (bs->swap_type == BOOT_SWAP_TYPE_NONE) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001743 BOOT_SWAP_TYPE(state) = boot_validated_swap_type(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02001744 } else {
Raef Colese8fe6cf2020-05-26 13:07:40 +01001745 FIH_CALL(boot_validate_slot, fih_rc,
1746 state, BOOT_SECONDARY_SLOT, bs);
1747 if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
1748 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_FAIL;
1749 } else {
1750 BOOT_SWAP_TYPE(state) = bs->swap_type;
1751 }
David Vinczeba3bd602019-06-17 16:01:43 +02001752 }
1753
1754#if (BOOT_IMAGE_NUMBER > 1)
Fabio Utzig10ee6482019-08-01 12:04:52 -03001755 boot_review_image_swap_types(state, false);
David Vinczeba3bd602019-06-17 16:01:43 +02001756#endif
1757
1758#ifdef MCUBOOT_BOOTSTRAP
Fabio Utzig10ee6482019-08-01 12:04:52 -03001759 if (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_NONE) {
David Vinczeba3bd602019-06-17 16:01:43 +02001760 /* Header checks are done first because they are
1761 * inexpensive. Since overwrite-only copies starting from
1762 * offset 0, if interrupted, it might leave a valid header
1763 * magic, so also run validation on the primary slot to be
1764 * sure it's not OK.
1765 */
Raef Colese8fe6cf2020-05-26 13:07:40 +01001766 rc = boot_check_header_erased(state, BOOT_PRIMARY_SLOT);
1767 FIH_CALL(boot_validate_slot, fih_rc,
1768 state, BOOT_PRIMARY_SLOT, bs);
1769
1770 if (rc == 0 || fih_not_eq(fih_rc, FIH_SUCCESS)) {
1771
Fabio Utzig3d77c952020-10-04 10:23:17 -03001772 rc = (boot_img_hdr(state, BOOT_SECONDARY_SLOT)->ih_magic == IMAGE_MAGIC) ? 1: 0;
Raef Colese8fe6cf2020-05-26 13:07:40 +01001773 FIH_CALL(boot_validate_slot, fih_rc,
1774 state, BOOT_SECONDARY_SLOT, bs);
1775
Fabio Utzig3d77c952020-10-04 10:23:17 -03001776 if (rc == 1 && fih_eq(fih_rc, FIH_SUCCESS)) {
David Vinczeba3bd602019-06-17 16:01:43 +02001777 /* Set swap type to REVERT to overwrite the primary
1778 * slot with the image contained in secondary slot
1779 * and to trigger the explicit setting of the
1780 * image_ok flag.
1781 */
Fabio Utzig59b63e52019-09-10 12:22:35 -03001782 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_REVERT;
David Vinczeba3bd602019-06-17 16:01:43 +02001783 }
Fabio Utzig338a19f2018-12-03 08:37:08 -02001784 }
1785 }
Fabio Utzig338a19f2018-12-03 08:37:08 -02001786#endif
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001787 }
David Vinczeba3bd602019-06-17 16:01:43 +02001788 } else {
1789 /* In that case if slots are not compatible. */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001790 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001791 }
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001792}
1793
Mark Horvathccaf7f82021-01-04 18:16:42 +01001794/**
1795 * Updates the security counter for the current image.
1796 *
1797 * @param state Boot loader status information.
1798 *
1799 * @return 0 on success; nonzero on failure.
1800 */
1801static int
1802boot_update_hw_rollback_protection(struct boot_loader_state *state)
1803{
1804#ifdef MCUBOOT_HW_ROLLBACK_PROT
1805 int rc;
1806
1807 /* Update the stored security counter with the active image's security
1808 * counter value. It will only be updated if the new security counter is
1809 * greater than the stored value.
1810 *
1811 * In case of a successful image swapping when the swap type is TEST the
1812 * security counter can be increased only after a reset, when the swap
1813 * type is NONE and the image has marked itself "OK" (the image_ok flag
1814 * has been set). This way a "revert" can be performed when it's
1815 * necessary.
1816 */
1817 if (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_NONE) {
1818 rc = boot_update_security_counter(
1819 BOOT_CURR_IMG(state),
1820 BOOT_PRIMARY_SLOT,
1821 boot_img_hdr(state, BOOT_PRIMARY_SLOT));
1822 if (rc != 0) {
1823 BOOT_LOG_ERR("Security counter update failed after image "
1824 "validation.");
1825 return rc;
1826 }
1827 }
1828
1829 return 0;
1830
1831#else /* MCUBOOT_HW_ROLLBACK_PROT */
1832 (void) (state);
1833
1834 return 0;
1835#endif
1836}
1837
Raef Colese8fe6cf2020-05-26 13:07:40 +01001838fih_int
Fabio Utzig10ee6482019-08-01 12:04:52 -03001839context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp)
Christopher Collins92ea77f2016-12-12 15:59:26 -08001840{
Marti Bolivar84898652017-06-13 17:20:22 -04001841 size_t slot;
David Vinczeba3bd602019-06-17 16:01:43 +02001842 struct boot_status bs;
David Vincze9015a5d2020-05-18 14:43:11 +02001843 int rc = -1;
Raef Colese8fe6cf2020-05-26 13:07:40 +01001844 fih_int fih_rc = FIH_FAILURE;
Marti Bolivarc0b47912017-06-13 17:18:09 -04001845 int fa_id;
Fabio Utzigb0f04732019-07-31 09:49:19 -03001846 int image_index;
Fabio Utzig298913b2019-08-28 11:22:45 -03001847 bool has_upgrade;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001848
1849 /* The array of slot sectors are defined here (as opposed to file scope) so
1850 * that they don't get allocated for non-boot-loader apps. This is
1851 * necessary because the gcc option "-fdata-sections" doesn't seem to have
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001852 * any effect in older gcc versions (e.g., 4.8.4).
Christopher Collins92ea77f2016-12-12 15:59:26 -08001853 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001854 TARGET_STATIC boot_sector_t primary_slot_sectors[BOOT_IMAGE_NUMBER][BOOT_MAX_IMG_SECTORS];
1855 TARGET_STATIC boot_sector_t secondary_slot_sectors[BOOT_IMAGE_NUMBER][BOOT_MAX_IMG_SECTORS];
Fabio Utzig12d59162019-11-28 10:01:59 -03001856#if MCUBOOT_SWAP_USING_SCRATCH
Fabio Utzig10ee6482019-08-01 12:04:52 -03001857 TARGET_STATIC boot_sector_t scratch_sectors[BOOT_MAX_IMG_SECTORS];
Fabio Utzig12d59162019-11-28 10:01:59 -03001858#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -08001859
Fabio Utzig10ee6482019-08-01 12:04:52 -03001860 memset(state, 0, sizeof(struct boot_loader_state));
Fabio Utzig298913b2019-08-28 11:22:45 -03001861 has_upgrade = false;
1862
1863#if (BOOT_IMAGE_NUMBER == 1)
1864 (void)has_upgrade;
1865#endif
Fabio Utzigba829042018-09-18 08:29:34 -03001866
David Vinczeba3bd602019-06-17 16:01:43 +02001867 /* Iterate over all the images. By the end of the loop the swap type has
1868 * to be determined for each image and all aborted swaps have to be
1869 * completed.
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001870 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001871 IMAGES_ITER(BOOT_CURR_IMG(state)) {
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03001872
David Vinczeba3bd602019-06-17 16:01:43 +02001873#if defined(MCUBOOT_ENC_IMAGES) && (BOOT_IMAGE_NUMBER > 1)
1874 /* The keys used for encryption may no longer be valid (could belong to
1875 * another images). Therefore, mark them as invalid to force their reload
1876 * by boot_enc_load().
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03001877 */
Fabio Utzig1e4284b2019-08-23 11:55:27 -03001878 boot_enc_zeroize(BOOT_CURR_ENC(state));
David Brown554c52e2017-06-30 16:01:07 -06001879#endif
1880
Fabio Utzig10ee6482019-08-01 12:04:52 -03001881 image_index = BOOT_CURR_IMG(state);
Fabio Utzigb0f04732019-07-31 09:49:19 -03001882
Fabio Utzig10ee6482019-08-01 12:04:52 -03001883 BOOT_IMG(state, BOOT_PRIMARY_SLOT).sectors =
Fabio Utzigb0f04732019-07-31 09:49:19 -03001884 primary_slot_sectors[image_index];
Fabio Utzig10ee6482019-08-01 12:04:52 -03001885 BOOT_IMG(state, BOOT_SECONDARY_SLOT).sectors =
Fabio Utzigb0f04732019-07-31 09:49:19 -03001886 secondary_slot_sectors[image_index];
Fabio Utzig12d59162019-11-28 10:01:59 -03001887#if MCUBOOT_SWAP_USING_SCRATCH
Fabio Utzig10ee6482019-08-01 12:04:52 -03001888 state->scratch.sectors = scratch_sectors;
Fabio Utzig12d59162019-11-28 10:01:59 -03001889#endif
David Vinczeba3bd602019-06-17 16:01:43 +02001890
1891 /* Open primary and secondary image areas for the duration
1892 * of this call.
1893 */
1894 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
Fabio Utzigb0f04732019-07-31 09:49:19 -03001895 fa_id = flash_area_id_from_multi_image_slot(image_index, slot);
Fabio Utzig10ee6482019-08-01 12:04:52 -03001896 rc = flash_area_open(fa_id, &BOOT_IMG_AREA(state, slot));
David Vinczeba3bd602019-06-17 16:01:43 +02001897 assert(rc == 0);
1898 }
Fabio Utzig12d59162019-11-28 10:01:59 -03001899#if MCUBOOT_SWAP_USING_SCRATCH
David Vinczeba3bd602019-06-17 16:01:43 +02001900 rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH,
Fabio Utzig10ee6482019-08-01 12:04:52 -03001901 &BOOT_SCRATCH_AREA(state));
David Vinczeba3bd602019-06-17 16:01:43 +02001902 assert(rc == 0);
Fabio Utzig12d59162019-11-28 10:01:59 -03001903#endif
David Vinczeba3bd602019-06-17 16:01:43 +02001904
1905 /* Determine swap type and complete swap if it has been aborted. */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001906 boot_prepare_image_for_update(state, &bs);
Fabio Utzig298913b2019-08-28 11:22:45 -03001907
Fabio Utzige575b0b2019-09-11 12:34:23 -03001908 if (BOOT_IS_UPGRADE(BOOT_SWAP_TYPE(state))) {
Fabio Utzig298913b2019-08-28 11:22:45 -03001909 has_upgrade = true;
1910 }
David Vinczeba3bd602019-06-17 16:01:43 +02001911 }
1912
David Vinczee32483f2019-06-13 10:46:24 +02001913#if (BOOT_IMAGE_NUMBER > 1)
Fabio Utzig298913b2019-08-28 11:22:45 -03001914 if (has_upgrade) {
1915 /* Iterate over all the images and verify whether the image dependencies
1916 * are all satisfied and update swap type if necessary.
1917 */
1918 rc = boot_verify_dependencies(state);
David Vincze8b0b6372020-05-20 19:54:44 +02001919 if (rc != 0) {
Fabio Utzig298913b2019-08-28 11:22:45 -03001920 /*
1921 * It was impossible to upgrade because the expected dependency version
1922 * was not available. Here we already changed the swap_type so that
1923 * instead of asserting the bootloader, we continue and no upgrade is
1924 * performed.
1925 */
1926 rc = 0;
1927 }
1928 }
David Vinczee32483f2019-06-13 10:46:24 +02001929#endif
1930
David Vinczeba3bd602019-06-17 16:01:43 +02001931 /* Iterate over all the images. At this point there are no aborted swaps
1932 * and the swap types are determined for each image. By the end of the loop
1933 * all required update operations will have been finished.
1934 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001935 IMAGES_ITER(BOOT_CURR_IMG(state)) {
David Vinczeba3bd602019-06-17 16:01:43 +02001936
1937#if (BOOT_IMAGE_NUMBER > 1)
1938#ifdef MCUBOOT_ENC_IMAGES
1939 /* The keys used for encryption may no longer be valid (could belong to
1940 * another images). Therefore, mark them as invalid to force their reload
1941 * by boot_enc_load().
1942 */
Fabio Utzig1e4284b2019-08-23 11:55:27 -03001943 boot_enc_zeroize(BOOT_CURR_ENC(state));
David Vinczeba3bd602019-06-17 16:01:43 +02001944#endif /* MCUBOOT_ENC_IMAGES */
1945
1946 /* Indicate that swap is not aborted */
Fabio Utzig12d59162019-11-28 10:01:59 -03001947 boot_status_reset(&bs);
David Vinczeba3bd602019-06-17 16:01:43 +02001948#endif /* (BOOT_IMAGE_NUMBER > 1) */
1949
1950 /* Set the previously determined swap type */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001951 bs.swap_type = BOOT_SWAP_TYPE(state);
David Vinczeba3bd602019-06-17 16:01:43 +02001952
Fabio Utzig10ee6482019-08-01 12:04:52 -03001953 switch (BOOT_SWAP_TYPE(state)) {
David Vinczeba3bd602019-06-17 16:01:43 +02001954 case BOOT_SWAP_TYPE_NONE:
1955 break;
1956
1957 case BOOT_SWAP_TYPE_TEST: /* fallthrough */
1958 case BOOT_SWAP_TYPE_PERM: /* fallthrough */
1959 case BOOT_SWAP_TYPE_REVERT:
Andrzej Puzdrowskib8f39692021-07-02 15:05:37 +02001960 rc = BOOT_HOOK_CALL(boot_perform_update_hook, BOOT_HOOK_REGULAR,
1961 BOOT_CURR_IMG(state), &(BOOT_IMG(state, 1).hdr),
1962 BOOT_IMG_AREA(state, BOOT_SECONDARY_SLOT));
1963 if (rc == BOOT_HOOK_REGULAR)
1964 {
1965 rc = boot_perform_update(state, &bs);
1966 }
David Vinczeba3bd602019-06-17 16:01:43 +02001967 assert(rc == 0);
1968 break;
1969
1970 case BOOT_SWAP_TYPE_FAIL:
1971 /* The image in secondary slot was invalid and is now erased. Ensure
1972 * we don't try to boot into it again on the next reboot. Do this by
1973 * pretending we just reverted back to primary slot.
1974 */
1975#ifndef MCUBOOT_OVERWRITE_ONLY
1976 /* image_ok needs to be explicitly set to avoid a new revert. */
Fabio Utzig12d59162019-11-28 10:01:59 -03001977 rc = swap_set_image_ok(BOOT_CURR_IMG(state));
David Vinczeba3bd602019-06-17 16:01:43 +02001978 if (rc != 0) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001979 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
David Vinczeba3bd602019-06-17 16:01:43 +02001980 }
1981#endif /* !MCUBOOT_OVERWRITE_ONLY */
1982 break;
1983
1984 default:
Fabio Utzig10ee6482019-08-01 12:04:52 -03001985 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
David Vinczeba3bd602019-06-17 16:01:43 +02001986 }
1987
Fabio Utzig10ee6482019-08-01 12:04:52 -03001988 if (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_PANIC) {
David Vinczeba3bd602019-06-17 16:01:43 +02001989 BOOT_LOG_ERR("panic!");
1990 assert(0);
1991
1992 /* Loop forever... */
Raef Colese8fe6cf2020-05-26 13:07:40 +01001993 FIH_PANIC;
David Vinczeba3bd602019-06-17 16:01:43 +02001994 }
1995 }
1996
1997 /* Iterate over all the images. At this point all required update operations
1998 * have finished. By the end of the loop each image in the primary slot will
1999 * have been re-validated.
2000 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002001 IMAGES_ITER(BOOT_CURR_IMG(state)) {
2002 if (BOOT_SWAP_TYPE(state) != BOOT_SWAP_TYPE_NONE) {
David Vinczeba3bd602019-06-17 16:01:43 +02002003 /* Attempt to read an image header from each slot. Ensure that image
2004 * headers in slots are aligned with headers in boot_data.
2005 */
Fabio Utzig12d59162019-11-28 10:01:59 -03002006 rc = boot_read_image_headers(state, false, &bs);
David Vinczeba3bd602019-06-17 16:01:43 +02002007 if (rc != 0) {
2008 goto out;
2009 }
2010 /* Since headers were reloaded, it can be assumed we just performed
2011 * a swap or overwrite. Now the header info that should be used to
2012 * provide the data for the bootstrap, which previously was at
2013 * secondary slot, was updated to primary slot.
2014 */
2015 }
2016
2017#ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT
Raef Colese8fe6cf2020-05-26 13:07:40 +01002018 FIH_CALL(boot_validate_slot, fih_rc, state, BOOT_PRIMARY_SLOT, NULL);
2019 if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
David Vinczeba3bd602019-06-17 16:01:43 +02002020 goto out;
2021 }
2022#else
2023 /* Even if we're not re-validating the primary slot, we could be booting
2024 * onto an empty flash chip. At least do a basic sanity check that
2025 * the magic number on the image is OK.
2026 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002027 if (BOOT_IMG(state, BOOT_PRIMARY_SLOT).hdr.ih_magic != IMAGE_MAGIC) {
David Vinczeba3bd602019-06-17 16:01:43 +02002028 BOOT_LOG_ERR("bad image magic 0x%lx; Image=%u", (unsigned long)
Dominik Ermel4a4d1ac2021-08-06 11:23:52 +00002029 BOOT_IMG(state, BOOT_PRIMARY_SLOT).hdr.ih_magic,
Fabio Utzig10ee6482019-08-01 12:04:52 -03002030 BOOT_CURR_IMG(state));
David Vinczeba3bd602019-06-17 16:01:43 +02002031 rc = BOOT_EBADIMAGE;
2032 goto out;
2033 }
David Vinczec3084132020-02-18 14:50:47 +01002034#endif /* MCUBOOT_VALIDATE_PRIMARY_SLOT */
2035
Mark Horvathccaf7f82021-01-04 18:16:42 +01002036 rc = boot_update_hw_rollback_protection(state);
David Vincze1cf11b52020-03-24 07:51:09 +01002037 if (rc != 0) {
Raef Colese8fe6cf2020-05-26 13:07:40 +01002038 goto out;
David Vincze1cf11b52020-03-24 07:51:09 +01002039 }
David Vincze1cf11b52020-03-24 07:51:09 +01002040
Mark Horvathccaf7f82021-01-04 18:16:42 +01002041 rc = boot_add_shared_data(state, BOOT_PRIMARY_SLOT);
David Vincze1cf11b52020-03-24 07:51:09 +01002042 if (rc != 0) {
Raef Colese8fe6cf2020-05-26 13:07:40 +01002043 goto out;
David Vincze1cf11b52020-03-24 07:51:09 +01002044 }
David Vinczeba3bd602019-06-17 16:01:43 +02002045 }
2046
Fabio Utzigf616c542019-12-19 15:23:32 -03002047 /*
2048 * Since the boot_status struct stores plaintext encryption keys, reset
2049 * them here to avoid the possibility of jumping into an image that could
2050 * easily recover them.
2051 */
2052 memset(&bs, 0, sizeof(struct boot_status));
2053
Raef Colesfe57e7d2021-10-15 11:07:09 +01002054 fill_rsp(state, rsp);
Christopher Collins92ea77f2016-12-12 15:59:26 -08002055
Raef Colese8fe6cf2020-05-26 13:07:40 +01002056 fih_rc = FIH_SUCCESS;
Fabio Utzig298913b2019-08-28 11:22:45 -03002057out:
Mark Horvathccaf7f82021-01-04 18:16:42 +01002058 close_all_flash_areas(state);
Raef Colese8fe6cf2020-05-26 13:07:40 +01002059
2060 if (rc) {
2061 fih_rc = fih_int_encode(rc);
2062 }
2063
2064 FIH_RET(fih_rc);
Christopher Collins92ea77f2016-12-12 15:59:26 -08002065}
2066
Raef Colese8fe6cf2020-05-26 13:07:40 +01002067fih_int
Christopher Collins92ea77f2016-12-12 15:59:26 -08002068split_go(int loader_slot, int split_slot, void **entry)
2069{
Marti Bolivarc50926f2017-06-14 09:35:40 -04002070 boot_sector_t *sectors;
Christopher Collins034a6202017-01-11 12:19:37 -08002071 uintptr_t entry_val;
Christopher Collins92ea77f2016-12-12 15:59:26 -08002072 int loader_flash_id;
Marti Bolivarc0b47912017-06-13 17:18:09 -04002073 int split_flash_id;
Christopher Collins92ea77f2016-12-12 15:59:26 -08002074 int rc;
Raef Colese8fe6cf2020-05-26 13:07:40 +01002075 fih_int fih_rc = FIH_FAILURE;
Christopher Collins92ea77f2016-12-12 15:59:26 -08002076
Christopher Collins92ea77f2016-12-12 15:59:26 -08002077 sectors = malloc(BOOT_MAX_IMG_SECTORS * 2 * sizeof *sectors);
2078 if (sectors == NULL) {
Raef Colese8fe6cf2020-05-26 13:07:40 +01002079 FIH_RET(FIH_FAILURE);
Christopher Collins92ea77f2016-12-12 15:59:26 -08002080 }
David Vinczeba3bd602019-06-17 16:01:43 +02002081 BOOT_IMG(&boot_data, loader_slot).sectors = sectors + 0;
2082 BOOT_IMG(&boot_data, split_slot).sectors = sectors + BOOT_MAX_IMG_SECTORS;
Marti Bolivarc0b47912017-06-13 17:18:09 -04002083
2084 loader_flash_id = flash_area_id_from_image_slot(loader_slot);
2085 rc = flash_area_open(loader_flash_id,
Alvaro Prieto63a2bdb2019-07-04 12:18:49 -07002086 &BOOT_IMG_AREA(&boot_data, loader_slot));
Marti Bolivarc0b47912017-06-13 17:18:09 -04002087 assert(rc == 0);
2088 split_flash_id = flash_area_id_from_image_slot(split_slot);
2089 rc = flash_area_open(split_flash_id,
2090 &BOOT_IMG_AREA(&boot_data, split_slot));
2091 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -08002092
2093 /* Determine the sector layout of the image slots and scratch area. */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002094 rc = boot_read_sectors(&boot_data);
Christopher Collins92ea77f2016-12-12 15:59:26 -08002095 if (rc != 0) {
2096 rc = SPLIT_GO_ERR;
2097 goto done;
2098 }
2099
Fabio Utzig12d59162019-11-28 10:01:59 -03002100 rc = boot_read_image_headers(&boot_data, true, NULL);
Christopher Collins92ea77f2016-12-12 15:59:26 -08002101 if (rc != 0) {
2102 goto done;
2103 }
2104
Christopher Collins92ea77f2016-12-12 15:59:26 -08002105 /* Don't check the bootable image flag because we could really call a
2106 * bootable or non-bootable image. Just validate that the image check
2107 * passes which is distinct from the normal check.
2108 */
Raef Colese8fe6cf2020-05-26 13:07:40 +01002109 FIH_CALL(split_image_check, fih_rc,
2110 boot_img_hdr(&boot_data, split_slot),
2111 BOOT_IMG_AREA(&boot_data, split_slot),
2112 boot_img_hdr(&boot_data, loader_slot),
2113 BOOT_IMG_AREA(&boot_data, loader_slot));
2114 if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
Christopher Collins92ea77f2016-12-12 15:59:26 -08002115 goto done;
2116 }
2117
Marti Bolivarea088872017-06-12 17:10:49 -04002118 entry_val = boot_img_slot_off(&boot_data, split_slot) +
Marti Bolivarf804f622017-06-12 15:41:48 -04002119 boot_img_hdr(&boot_data, split_slot)->ih_hdr_size;
Christopher Collins034a6202017-01-11 12:19:37 -08002120 *entry = (void *) entry_val;
Christopher Collins92ea77f2016-12-12 15:59:26 -08002121 rc = SPLIT_GO_OK;
2122
2123done:
Marti Bolivarc0b47912017-06-13 17:18:09 -04002124 flash_area_close(BOOT_IMG_AREA(&boot_data, split_slot));
2125 flash_area_close(BOOT_IMG_AREA(&boot_data, loader_slot));
Christopher Collins92ea77f2016-12-12 15:59:26 -08002126 free(sectors);
Raef Colese8fe6cf2020-05-26 13:07:40 +01002127
2128 if (rc) {
2129 fih_rc = fih_int_encode(rc);
2130 }
2131
2132 FIH_RET(fih_rc);
Christopher Collins92ea77f2016-12-12 15:59:26 -08002133}
David Vinczee574f2d2020-07-10 11:42:03 +02002134
Tamas Banfe031092020-09-10 17:32:39 +02002135#else /* MCUBOOT_DIRECT_XIP || MCUBOOT_RAM_LOAD */
David Vinczee574f2d2020-07-10 11:42:03 +02002136
Mark Horvathccaf7f82021-01-04 18:16:42 +01002137#define NO_ACTIVE_SLOT UINT32_MAX
2138
David Vinczee574f2d2020-07-10 11:42:03 +02002139/**
Mark Horvathccaf7f82021-01-04 18:16:42 +01002140 * Opens all flash areas and checks which contain an image with a valid header.
David Vinczee574f2d2020-07-10 11:42:03 +02002141 *
Mark Horvathccaf7f82021-01-04 18:16:42 +01002142 * @param state Boot loader status information.
David Vinczee574f2d2020-07-10 11:42:03 +02002143 *
Mark Horvathccaf7f82021-01-04 18:16:42 +01002144 * @return 0 on success; nonzero on failure.
2145 */
2146static int
Raef Colesfe57e7d2021-10-15 11:07:09 +01002147boot_get_slot_usage(struct boot_loader_state *state)
Mark Horvathccaf7f82021-01-04 18:16:42 +01002148{
2149 uint32_t slot;
2150 int fa_id;
2151 int rc;
2152 struct image_header *hdr = NULL;
2153
2154 IMAGES_ITER(BOOT_CURR_IMG(state)) {
2155 /* Open all the slots */
2156 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
2157 fa_id = flash_area_id_from_multi_image_slot(
2158 BOOT_CURR_IMG(state), slot);
2159 rc = flash_area_open(fa_id, &BOOT_IMG_AREA(state, slot));
2160 assert(rc == 0);
2161 }
2162
2163 /* Attempt to read an image header from each slot. */
2164 rc = boot_read_image_headers(state, false, NULL);
2165 if (rc != 0) {
2166 BOOT_LOG_WRN("Failed reading image headers.");
2167 return rc;
2168 }
2169
2170 /* Check headers in all slots */
2171 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
2172 hdr = boot_img_hdr(state, slot);
2173
2174 if (boot_is_header_valid(hdr, BOOT_IMG_AREA(state, slot))) {
Raef Colesfe57e7d2021-10-15 11:07:09 +01002175 state->slot_usage[BOOT_CURR_IMG(state)].slot_available[slot] = true;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002176 BOOT_LOG_IMAGE_INFO(slot, hdr);
2177 } else {
Raef Colesfe57e7d2021-10-15 11:07:09 +01002178 state->slot_usage[BOOT_CURR_IMG(state)].slot_available[slot] = false;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002179 BOOT_LOG_INF("Image %d %s slot: Image not found",
2180 BOOT_CURR_IMG(state),
2181 (slot == BOOT_PRIMARY_SLOT)
2182 ? "Primary" : "Secondary");
2183 }
2184 }
2185
Raef Colesfe57e7d2021-10-15 11:07:09 +01002186 state->slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002187 }
2188
2189 return 0;
2190}
2191
2192/**
2193 * Finds the slot containing the image with the highest version number for the
2194 * current image.
2195 *
2196 * @param state Boot loader status information.
Mark Horvathccaf7f82021-01-04 18:16:42 +01002197 *
2198 * @return NO_ACTIVE_SLOT if no available slot found, number of
2199 * the found slot otherwise.
David Vinczee574f2d2020-07-10 11:42:03 +02002200 */
2201static uint32_t
Raef Colesfe57e7d2021-10-15 11:07:09 +01002202find_slot_with_highest_version(struct boot_loader_state *state)
David Vinczee574f2d2020-07-10 11:42:03 +02002203{
David Vinczee574f2d2020-07-10 11:42:03 +02002204 uint32_t slot;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002205 uint32_t candidate_slot = NO_ACTIVE_SLOT;
2206 int rc;
David Vinczee574f2d2020-07-10 11:42:03 +02002207
Mark Horvathccaf7f82021-01-04 18:16:42 +01002208 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
Raef Colesfe57e7d2021-10-15 11:07:09 +01002209 if (state->slot_usage[BOOT_CURR_IMG(state)].slot_available[slot]) {
Mark Horvathccaf7f82021-01-04 18:16:42 +01002210 if (candidate_slot == NO_ACTIVE_SLOT) {
2211 candidate_slot = slot;
2212 } else {
2213 rc = boot_version_cmp(
2214 &boot_img_hdr(state, slot)->ih_ver,
2215 &boot_img_hdr(state, candidate_slot)->ih_ver);
2216 if (rc == 1) {
2217 /* The version of the image being examined is greater than
2218 * the version of the current candidate.
2219 */
2220 candidate_slot = slot;
2221 }
2222 }
David Vinczee574f2d2020-07-10 11:42:03 +02002223 }
2224 }
2225
Mark Horvathccaf7f82021-01-04 18:16:42 +01002226 return candidate_slot;
David Vinczee574f2d2020-07-10 11:42:03 +02002227}
2228
Mark Horvathccaf7f82021-01-04 18:16:42 +01002229#ifdef MCUBOOT_HAVE_LOGGING
2230/**
2231 * Prints the state of the loaded images.
2232 *
2233 * @param state Boot loader status information.
Mark Horvathccaf7f82021-01-04 18:16:42 +01002234 */
2235static void
Raef Colesfe57e7d2021-10-15 11:07:09 +01002236print_loaded_images(struct boot_loader_state *state)
Mark Horvathccaf7f82021-01-04 18:16:42 +01002237{
2238 uint32_t active_slot;
2239
David Brown695e5912021-05-24 16:58:01 -06002240 (void)state;
2241
Mark Horvathccaf7f82021-01-04 18:16:42 +01002242 IMAGES_ITER(BOOT_CURR_IMG(state)) {
Raef Colesfe57e7d2021-10-15 11:07:09 +01002243 active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002244
2245 BOOT_LOG_INF("Image %d loaded from the %s slot",
2246 BOOT_CURR_IMG(state),
2247 (active_slot == BOOT_PRIMARY_SLOT) ?
2248 "primary" : "secondary");
2249 }
2250}
2251#endif
2252
David Vincze1c456242021-06-29 15:25:24 +02002253#if defined(MCUBOOT_DIRECT_XIP) && defined(MCUBOOT_DIRECT_XIP_REVERT)
David Vincze505fba22020-10-22 13:53:29 +02002254/**
Mark Horvathccaf7f82021-01-04 18:16:42 +01002255 * Checks whether the active slot of the current image was previously selected
2256 * to run. Erases the image if it was selected but its execution failed,
2257 * otherwise marks it as selected if it has not been before.
David Vincze505fba22020-10-22 13:53:29 +02002258 *
Mark Horvathccaf7f82021-01-04 18:16:42 +01002259 * @param state Boot loader status information.
David Vincze505fba22020-10-22 13:53:29 +02002260 *
Mark Horvathccaf7f82021-01-04 18:16:42 +01002261 * @return 0 on success; nonzero on failure.
David Vincze505fba22020-10-22 13:53:29 +02002262 */
2263static int
Raef Colesfe57e7d2021-10-15 11:07:09 +01002264boot_select_or_erase(struct boot_loader_state *state)
David Vincze505fba22020-10-22 13:53:29 +02002265{
2266 const struct flash_area *fap;
2267 int fa_id;
2268 int rc;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002269 uint32_t active_slot;
2270 struct boot_swap_state* active_swap_state;
David Vincze505fba22020-10-22 13:53:29 +02002271
Raef Colesfe57e7d2021-10-15 11:07:09 +01002272 active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002273
2274 fa_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), active_slot);
David Vincze505fba22020-10-22 13:53:29 +02002275 rc = flash_area_open(fa_id, &fap);
2276 assert(rc == 0);
2277
Raef Colesfe57e7d2021-10-15 11:07:09 +01002278 active_swap_state = &(state->slot_usage[BOOT_CURR_IMG(state)].swap_state);
Mark Horvathccaf7f82021-01-04 18:16:42 +01002279
2280 memset(active_swap_state, 0, sizeof(struct boot_swap_state));
2281 rc = boot_read_swap_state(fap, active_swap_state);
David Vincze505fba22020-10-22 13:53:29 +02002282 assert(rc == 0);
2283
Mark Horvathccaf7f82021-01-04 18:16:42 +01002284 if (active_swap_state->magic != BOOT_MAGIC_GOOD ||
2285 (active_swap_state->copy_done == BOOT_FLAG_SET &&
2286 active_swap_state->image_ok != BOOT_FLAG_SET)) {
David Vincze505fba22020-10-22 13:53:29 +02002287 /*
2288 * A reboot happened without the image being confirmed at
2289 * runtime or its trailer is corrupted/invalid. Erase the image
2290 * to prevent it from being selected again on the next reboot.
2291 */
2292 BOOT_LOG_DBG("Erasing faulty image in the %s slot.",
Carlos Falgueras Garcíaae13c3c2021-06-21 17:20:31 +02002293 (active_slot == BOOT_PRIMARY_SLOT) ? "primary" : "secondary");
Dominik Ermel260ae092021-04-23 05:38:45 +00002294 rc = flash_area_erase(fap, 0, flash_area_get_size(fap));
David Vincze505fba22020-10-22 13:53:29 +02002295 assert(rc == 0);
2296
2297 flash_area_close(fap);
2298 rc = -1;
2299 } else {
Mark Horvathccaf7f82021-01-04 18:16:42 +01002300 if (active_swap_state->copy_done != BOOT_FLAG_SET) {
2301 if (active_swap_state->copy_done == BOOT_FLAG_BAD) {
David Vincze505fba22020-10-22 13:53:29 +02002302 BOOT_LOG_DBG("The copy_done flag had an unexpected value. Its "
2303 "value was neither 'set' nor 'unset', but 'bad'.");
2304 }
2305 /*
2306 * Set the copy_done flag, indicating that the image has been
2307 * selected to boot. It can be set in advance, before even
2308 * validating the image, because in case the validation fails, the
2309 * entire image slot will be erased (including the trailer).
2310 */
2311 rc = boot_write_copy_done(fap);
2312 if (rc != 0) {
2313 BOOT_LOG_WRN("Failed to set copy_done flag of the image in "
Carlos Falgueras Garcíaae13c3c2021-06-21 17:20:31 +02002314 "the %s slot.", (active_slot == BOOT_PRIMARY_SLOT) ?
David Vincze505fba22020-10-22 13:53:29 +02002315 "primary" : "secondary");
2316 rc = 0;
2317 }
2318 }
2319 flash_area_close(fap);
2320 }
2321
2322 return rc;
2323}
David Vincze1c456242021-06-29 15:25:24 +02002324#endif /* MCUBOOT_DIRECT_XIP && MCUBOOT_DIRECT_XIP_REVERT */
David Vincze505fba22020-10-22 13:53:29 +02002325
Tamas Banfe031092020-09-10 17:32:39 +02002326#ifdef MCUBOOT_RAM_LOAD
2327
Mark Horvathccaf7f82021-01-04 18:16:42 +01002328#ifndef MULTIPLE_EXECUTABLE_RAM_REGIONS
Tamas Banfe031092020-09-10 17:32:39 +02002329#if !defined(IMAGE_EXECUTABLE_RAM_START) || !defined(IMAGE_EXECUTABLE_RAM_SIZE)
2330#error "Platform MUST define executable RAM bounds in case of RAM_LOAD"
2331#endif
Mark Horvathccaf7f82021-01-04 18:16:42 +01002332#endif
Tamas Banfe031092020-09-10 17:32:39 +02002333
2334/**
Mark Horvathccaf7f82021-01-04 18:16:42 +01002335 * Verifies that the active slot of the current image can be loaded within the
2336 * predefined bounds that are allowed to be used by executable images.
Tamas Banfe031092020-09-10 17:32:39 +02002337 *
Mark Horvathccaf7f82021-01-04 18:16:42 +01002338 * @param state Boot loader status information.
Tamas Banfe031092020-09-10 17:32:39 +02002339 *
Mark Horvathccaf7f82021-01-04 18:16:42 +01002340 * @return 0 on success; nonzero on failure.
Tamas Banfe031092020-09-10 17:32:39 +02002341 */
2342static int
Raef Colesfe57e7d2021-10-15 11:07:09 +01002343boot_verify_ram_load_address(struct boot_loader_state *state)
Tamas Banfe031092020-09-10 17:32:39 +02002344{
Mark Horvathccaf7f82021-01-04 18:16:42 +01002345 uint32_t img_dst;
2346 uint32_t img_sz;
Tamas Banfe031092020-09-10 17:32:39 +02002347 uint32_t img_end_addr;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002348 uint32_t exec_ram_start;
2349 uint32_t exec_ram_size;
David Brown695e5912021-05-24 16:58:01 -06002350
2351 (void)state;
2352
Mark Horvathccaf7f82021-01-04 18:16:42 +01002353#ifdef MULTIPLE_EXECUTABLE_RAM_REGIONS
2354 int rc;
Tamas Banfe031092020-09-10 17:32:39 +02002355
Mark Horvathccaf7f82021-01-04 18:16:42 +01002356 rc = boot_get_image_exec_ram_info(BOOT_CURR_IMG(state), &exec_ram_start,
2357 &exec_ram_size);
2358 if (rc != 0) {
2359 return BOOT_EBADSTATUS;
2360 }
2361#else
2362 exec_ram_start = IMAGE_EXECUTABLE_RAM_START;
2363 exec_ram_size = IMAGE_EXECUTABLE_RAM_SIZE;
2364#endif
2365
Raef Colesfe57e7d2021-10-15 11:07:09 +01002366 img_dst = state->slot_usage[BOOT_CURR_IMG(state)].img_dst;
2367 img_sz = state->slot_usage[BOOT_CURR_IMG(state)].img_sz;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002368
2369 if (img_dst < exec_ram_start) {
Tamas Banfe031092020-09-10 17:32:39 +02002370 return BOOT_EBADIMAGE;
2371 }
2372
2373 if (!boot_u32_safe_add(&img_end_addr, img_dst, img_sz)) {
2374 return BOOT_EBADIMAGE;
2375 }
2376
Mark Horvathccaf7f82021-01-04 18:16:42 +01002377 if (img_end_addr > (exec_ram_start + exec_ram_size)) {
Tamas Banfe031092020-09-10 17:32:39 +02002378 return BOOT_EBADIMAGE;
2379 }
2380
2381 return 0;
2382}
2383
Hugo L'Hostisdb543e52021-03-09 18:00:31 +00002384#ifdef MCUBOOT_ENC_IMAGES
2385
2386/**
2387 * Copies and decrypts an image from a slot in the flash to an SRAM address.
2388 *
2389 * @param state Boot loader status information.
2390 * @param slot The flash slot of the image to be copied to SRAM.
2391 * @param hdr The image header.
2392 * @param src_sz Size of the image.
2393 * @param img_dst Pointer to the address at which the image needs to be
2394 * copied to SRAM.
2395 *
2396 * @return 0 on success; nonzero on failure.
2397 */
2398static int
2399boot_decrypt_and_copy_image_to_sram(struct boot_loader_state *state,
2400 uint32_t slot, struct image_header *hdr,
2401 uint32_t src_sz, uint32_t img_dst)
2402{
2403 /* The flow for the decryption and copy of the image is as follows :
2404 * 1. The whole image is copied to the RAM (header + payload + TLV).
2405 * 2. The encryption key is loaded from the TLV in flash.
2406 * 3. The image is then decrypted chunk by chunk in RAM (1 chunk
2407 * is 1024 bytes). Only the payload section is decrypted.
2408 * 4. The image is authenticated in RAM.
2409 */
2410 const struct flash_area *fap_src = NULL;
2411 struct boot_status bs;
2412 uint32_t blk_off;
2413 uint32_t tlv_off;
2414 uint32_t blk_sz;
2415 uint32_t bytes_copied = hdr->ih_hdr_size;
2416 uint32_t chunk_sz;
2417 uint32_t max_sz = 1024;
2418 uint16_t idx;
2419 uint8_t image_index;
2420 uint8_t * cur_dst;
2421 int area_id;
2422 int rc;
2423 uint8_t * ram_dst = (void *)(IMAGE_RAM_BASE + img_dst);
2424
2425 image_index = BOOT_CURR_IMG(state);
2426 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
2427 rc = flash_area_open(area_id, &fap_src);
2428 if (rc != 0){
2429 return BOOT_EFLASH;
2430 }
2431
2432 tlv_off = BOOT_TLV_OFF(hdr);
2433
2434 /* Copying the whole image in RAM */
2435 rc = flash_area_read(fap_src, 0, ram_dst, src_sz);
2436 if (rc != 0) {
2437 goto done;
2438 }
2439
2440 rc = boot_enc_load(BOOT_CURR_ENC(state), image_index, hdr, fap_src, &bs);
2441 if (rc < 0) {
2442 goto done;
2443 }
2444
2445 /* if rc > 0 then the key has already been loaded */
2446 if (rc == 0 && boot_enc_set_key(BOOT_CURR_ENC(state), slot, &bs)) {
2447 goto done;
2448 }
2449
2450 /* Starting at the end of the header as the header section is not encrypted */
2451 while (bytes_copied < tlv_off) { /* TLV section copied previously */
2452 if (src_sz - bytes_copied > max_sz) {
2453 chunk_sz = max_sz;
2454 } else {
2455 chunk_sz = src_sz - bytes_copied;
2456 }
2457
2458 cur_dst = ram_dst + bytes_copied;
2459 blk_sz = chunk_sz;
2460 idx = 0;
2461 if (bytes_copied + chunk_sz > tlv_off) {
2462 /* Going over TLV section
2463 * Part of the chunk is encrypted payload */
2464 blk_off = ((bytes_copied) - hdr->ih_hdr_size) & 0xf;
2465 blk_sz = tlv_off - (bytes_copied);
2466 boot_encrypt(BOOT_CURR_ENC(state), image_index, fap_src,
2467 (bytes_copied + idx) - hdr->ih_hdr_size, blk_sz,
2468 blk_off, cur_dst);
2469 } else {
2470 /* Image encrypted payload section */
2471 blk_off = ((bytes_copied) - hdr->ih_hdr_size) & 0xf;
2472 boot_encrypt(BOOT_CURR_ENC(state), image_index, fap_src,
2473 (bytes_copied + idx) - hdr->ih_hdr_size, blk_sz,
2474 blk_off, cur_dst);
2475 }
2476
2477 bytes_copied += chunk_sz;
2478 }
2479 rc = 0;
2480
2481done:
2482 flash_area_close(fap_src);
2483
2484 return rc;
2485}
2486
2487#endif /* MCUBOOT_ENC_IMAGES */
Tamas Banfe031092020-09-10 17:32:39 +02002488/**
Mark Horvathccaf7f82021-01-04 18:16:42 +01002489 * Copies a slot of the current image into SRAM.
Tamas Banfe031092020-09-10 17:32:39 +02002490 *
Mark Horvathccaf7f82021-01-04 18:16:42 +01002491 * @param state Boot loader status information.
Tamas Banfe031092020-09-10 17:32:39 +02002492 * @param slot The flash slot of the image to be copied to SRAM.
2493 * @param img_dst The address at which the image needs to be copied to
2494 * SRAM.
2495 * @param img_sz The size of the image that needs to be copied to SRAM.
2496 *
2497 * @return 0 on success; nonzero on failure.
2498 */
2499static int
Mark Horvathccaf7f82021-01-04 18:16:42 +01002500boot_copy_image_to_sram(struct boot_loader_state *state, int slot,
2501 uint32_t img_dst, uint32_t img_sz)
Tamas Banfe031092020-09-10 17:32:39 +02002502{
2503 int rc;
2504 const struct flash_area *fap_src = NULL;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002505 int area_id;
Tamas Banfe031092020-09-10 17:32:39 +02002506
Mark Horvathccaf7f82021-01-04 18:16:42 +01002507#if (BOOT_IMAGE_NUMBER == 1)
2508 (void)state;
2509#endif
2510
2511 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
2512
2513 rc = flash_area_open(area_id, &fap_src);
Tamas Banfe031092020-09-10 17:32:39 +02002514 if (rc != 0) {
2515 return BOOT_EFLASH;
2516 }
2517
2518 /* Direct copy from flash to its new location in SRAM. */
David Brown9bd7f902021-05-26 16:31:14 -06002519 rc = flash_area_read(fap_src, 0, (void *)(IMAGE_RAM_BASE + img_dst), img_sz);
Tamas Banfe031092020-09-10 17:32:39 +02002520 if (rc != 0) {
2521 BOOT_LOG_INF("Error whilst copying image from Flash to SRAM: %d", rc);
2522 }
2523
2524 flash_area_close(fap_src);
2525
2526 return rc;
2527}
2528
Mark Horvathccaf7f82021-01-04 18:16:42 +01002529#if (BOOT_IMAGE_NUMBER > 1)
Tamas Banfe031092020-09-10 17:32:39 +02002530/**
Mark Horvathccaf7f82021-01-04 18:16:42 +01002531 * Checks if two memory regions (A and B) are overlap or not.
Tamas Banfe031092020-09-10 17:32:39 +02002532 *
Mark Horvathccaf7f82021-01-04 18:16:42 +01002533 * @param start_a Start of the A region.
2534 * @param end_a End of the A region.
2535 * @param start_b Start of the B region.
2536 * @param end_b End of the B region.
Tamas Banfe031092020-09-10 17:32:39 +02002537 *
Mark Horvathccaf7f82021-01-04 18:16:42 +01002538 * @return true if there is overlap; false otherwise.
2539 */
2540static bool
2541do_regions_overlap(uint32_t start_a, uint32_t end_a,
2542 uint32_t start_b, uint32_t end_b)
2543{
2544 if (start_b > end_a) {
2545 return false;
2546 } else if (start_b >= start_a) {
2547 return true;
2548 } else if (end_b > start_a) {
2549 return true;
2550 }
2551
2552 return false;
2553}
2554
2555/**
2556 * Checks if the image we want to load to memory overlap with an already
2557 * ramloaded image.
2558 *
Raef Colesfe57e7d2021-10-15 11:07:09 +01002559 * @param state Boot loader status information.
Mark Horvathccaf7f82021-01-04 18:16:42 +01002560 *
2561 * @return 0 if there is no overlap; nonzero otherwise.
Tamas Banfe031092020-09-10 17:32:39 +02002562 */
2563static int
Raef Colesfe57e7d2021-10-15 11:07:09 +01002564boot_check_ram_load_overlapping(struct boot_loader_state *state)
Tamas Banfe031092020-09-10 17:32:39 +02002565{
Mark Horvathccaf7f82021-01-04 18:16:42 +01002566 uint32_t i;
2567
2568 uint32_t start_a;
2569 uint32_t end_a;
2570 uint32_t start_b;
2571 uint32_t end_b;
Raef Colesfe57e7d2021-10-15 11:07:09 +01002572 uint32_t image_id_to_check = BOOT_CURR_IMG(state);
Mark Horvathccaf7f82021-01-04 18:16:42 +01002573
Raef Colesfe57e7d2021-10-15 11:07:09 +01002574 start_a = state->slot_usage[image_id_to_check].img_dst;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002575 /* Safe to add here, values are already verified in
2576 * boot_verify_ram_load_address() */
Raef Colesfe57e7d2021-10-15 11:07:09 +01002577 end_a = start_a + state->slot_usage[image_id_to_check].img_sz;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002578
2579 for (i = 0; i < BOOT_IMAGE_NUMBER; i++) {
Raef Colesfe57e7d2021-10-15 11:07:09 +01002580 if (state->slot_usage[i].active_slot == NO_ACTIVE_SLOT
Mark Horvathccaf7f82021-01-04 18:16:42 +01002581 || i == image_id_to_check) {
2582 continue;
2583 }
2584
Raef Colesfe57e7d2021-10-15 11:07:09 +01002585 start_b = state->slot_usage[i].img_dst;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002586 /* Safe to add here, values are already verified in
2587 * boot_verify_ram_load_address() */
Raef Colesfe57e7d2021-10-15 11:07:09 +01002588 end_b = start_b + state->slot_usage[i].img_sz;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002589
2590 if (do_regions_overlap(start_a, end_a, start_b, end_b)) {
2591 return -1;
2592 }
2593 }
2594
2595 return 0;
2596}
2597#endif
2598
2599/**
2600 * Loads the active slot of the current image into SRAM. The load address and
2601 * image size is extracted from the image header.
2602 *
2603 * @param state Boot loader status information.
Mark Horvathccaf7f82021-01-04 18:16:42 +01002604 *
2605 * @return 0 on success; nonzero on failure.
2606 */
2607static int
Raef Colesfe57e7d2021-10-15 11:07:09 +01002608boot_load_image_to_sram(struct boot_loader_state *state)
Mark Horvathccaf7f82021-01-04 18:16:42 +01002609{
2610 uint32_t active_slot;
2611 struct image_header *hdr = NULL;
2612 uint32_t img_dst;
2613 uint32_t img_sz;
Tamas Banfe031092020-09-10 17:32:39 +02002614 int rc;
2615
Raef Colesfe57e7d2021-10-15 11:07:09 +01002616 active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002617 hdr = boot_img_hdr(state, active_slot);
2618
Tamas Banfe031092020-09-10 17:32:39 +02002619 if (hdr->ih_flags & IMAGE_F_RAM_LOAD) {
2620
Mark Horvathccaf7f82021-01-04 18:16:42 +01002621 img_dst = hdr->ih_load_addr;
Tamas Banfe031092020-09-10 17:32:39 +02002622
Mark Horvathccaf7f82021-01-04 18:16:42 +01002623 rc = boot_read_image_size(state, active_slot, &img_sz);
Tamas Banfe031092020-09-10 17:32:39 +02002624 if (rc != 0) {
2625 return rc;
2626 }
2627
Raef Colesfe57e7d2021-10-15 11:07:09 +01002628 state->slot_usage[BOOT_CURR_IMG(state)].img_dst = img_dst;
2629 state->slot_usage[BOOT_CURR_IMG(state)].img_sz = img_sz;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002630
Raef Colesfe57e7d2021-10-15 11:07:09 +01002631 rc = boot_verify_ram_load_address(state);
Tamas Banfe031092020-09-10 17:32:39 +02002632 if (rc != 0) {
Mark Horvathccaf7f82021-01-04 18:16:42 +01002633 BOOT_LOG_INF("Image RAM load address 0x%x is invalid.", img_dst);
Tamas Banfe031092020-09-10 17:32:39 +02002634 return rc;
2635 }
2636
Mark Horvathccaf7f82021-01-04 18:16:42 +01002637#if (BOOT_IMAGE_NUMBER > 1)
Raef Colesfe57e7d2021-10-15 11:07:09 +01002638 rc = boot_check_ram_load_overlapping(state);
Mark Horvathccaf7f82021-01-04 18:16:42 +01002639 if (rc != 0) {
2640 BOOT_LOG_INF("Image RAM loading to address 0x%x would overlap with\
2641 another image.", img_dst);
2642 return rc;
2643 }
2644#endif
Hugo L'Hostisdb543e52021-03-09 18:00:31 +00002645#ifdef MCUBOOT_ENC_IMAGES
2646 /* decrypt image if encrypted and copy it to RAM */
2647 if (IS_ENCRYPTED(hdr)) {
2648 rc = boot_decrypt_and_copy_image_to_sram(state, active_slot, hdr, img_sz, img_dst);
2649 } else {
2650 rc = boot_copy_image_to_sram(state, active_slot, img_dst, img_sz);
2651 }
2652#else
Tamas Banfe031092020-09-10 17:32:39 +02002653 /* Copy image to the load address from where it currently resides in
2654 * flash.
2655 */
Mark Horvathccaf7f82021-01-04 18:16:42 +01002656 rc = boot_copy_image_to_sram(state, active_slot, img_dst, img_sz);
Hugo L'Hostisdb543e52021-03-09 18:00:31 +00002657#endif
Tamas Banfe031092020-09-10 17:32:39 +02002658 if (rc != 0) {
Mark Horvathccaf7f82021-01-04 18:16:42 +01002659 BOOT_LOG_INF("RAM loading to 0x%x is failed.", img_dst);
Tamas Banfe031092020-09-10 17:32:39 +02002660 } else {
Mark Horvathccaf7f82021-01-04 18:16:42 +01002661 BOOT_LOG_INF("RAM loading to 0x%x is succeeded.", img_dst);
Tamas Banfe031092020-09-10 17:32:39 +02002662 }
2663 } else {
2664 /* Only images that support IMAGE_F_RAM_LOAD are allowed if
2665 * MCUBOOT_RAM_LOAD is set.
2666 */
2667 rc = BOOT_EBADIMAGE;
2668 }
2669
Mark Horvathccaf7f82021-01-04 18:16:42 +01002670 if (rc != 0) {
Raef Colesfe57e7d2021-10-15 11:07:09 +01002671 state->slot_usage[BOOT_CURR_IMG(state)].img_dst = 0;
2672 state->slot_usage[BOOT_CURR_IMG(state)].img_sz = 0;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002673 }
2674
Tamas Banfe031092020-09-10 17:32:39 +02002675 return rc;
2676}
2677
2678/**
2679 * Removes an image from SRAM, by overwriting it with zeros.
2680 *
Mark Horvathccaf7f82021-01-04 18:16:42 +01002681 * @param state Boot loader status information.
Mark Horvathccaf7f82021-01-04 18:16:42 +01002682 *
2683 * @return 0 on success; nonzero on failure.
2684 */
2685static inline int
Raef Colesfe57e7d2021-10-15 11:07:09 +01002686boot_remove_image_from_sram(struct boot_loader_state *state)
Mark Horvathccaf7f82021-01-04 18:16:42 +01002687{
David Brown695e5912021-05-24 16:58:01 -06002688 (void)state;
2689
Mark Horvathccaf7f82021-01-04 18:16:42 +01002690 BOOT_LOG_INF("Removing image from SRAM at address 0x%x",
Raef Colesfe57e7d2021-10-15 11:07:09 +01002691 state->slot_usage[BOOT_CURR_IMG(state)].img_dst);
Mark Horvathccaf7f82021-01-04 18:16:42 +01002692
Raef Colesfe57e7d2021-10-15 11:07:09 +01002693 memset((void*)(IMAGE_RAM_BASE + state->slot_usage[BOOT_CURR_IMG(state)].img_dst),
2694 0, state->slot_usage[BOOT_CURR_IMG(state)].img_sz);
Mark Horvathccaf7f82021-01-04 18:16:42 +01002695
Raef Colesfe57e7d2021-10-15 11:07:09 +01002696 state->slot_usage[BOOT_CURR_IMG(state)].img_dst = 0;
2697 state->slot_usage[BOOT_CURR_IMG(state)].img_sz = 0;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002698
2699 return 0;
2700}
2701
2702/**
2703 * Removes an image from flash by erasing the corresponding flash area
2704 *
2705 * @param state Boot loader status information.
2706 * @param slot The flash slot of the image to be erased.
Tamas Banfe031092020-09-10 17:32:39 +02002707 *
2708 * @return 0 on success; nonzero on failure.
2709 */
2710static inline int
Mark Horvathccaf7f82021-01-04 18:16:42 +01002711boot_remove_image_from_flash(struct boot_loader_state *state, uint32_t slot)
Tamas Banfe031092020-09-10 17:32:39 +02002712{
Mark Horvathccaf7f82021-01-04 18:16:42 +01002713 int area_id;
2714 int rc;
2715 const struct flash_area *fap;
Tamas Banfe031092020-09-10 17:32:39 +02002716
David Brown695e5912021-05-24 16:58:01 -06002717 (void)state;
2718
Mark Horvathccaf7f82021-01-04 18:16:42 +01002719 BOOT_LOG_INF("Removing image %d slot %d from flash", BOOT_CURR_IMG(state),
2720 slot);
2721 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
2722 rc = flash_area_open(area_id, &fap);
2723 if (rc == 0) {
Dominik Ermel260ae092021-04-23 05:38:45 +00002724 flash_area_erase(fap, 0, flash_area_get_size(fap));
Mark Horvathccaf7f82021-01-04 18:16:42 +01002725 }
2726
2727 return rc;
Tamas Banfe031092020-09-10 17:32:39 +02002728}
2729#endif /* MCUBOOT_RAM_LOAD */
2730
Mark Horvathccaf7f82021-01-04 18:16:42 +01002731#if (BOOT_IMAGE_NUMBER > 1)
2732/**
2733 * Checks the image dependency whether it is satisfied.
2734 *
2735 * @param state Boot loader status information.
Mark Horvathccaf7f82021-01-04 18:16:42 +01002736 * @param dep Image dependency which has to be verified.
2737 *
2738 * @return 0 if dependencies are met; nonzero otherwise.
2739 */
2740static int
2741boot_verify_slot_dependency(struct boot_loader_state *state,
Mark Horvathccaf7f82021-01-04 18:16:42 +01002742 struct image_dependency *dep)
David Vinczee574f2d2020-07-10 11:42:03 +02002743{
Mark Horvathccaf7f82021-01-04 18:16:42 +01002744 struct image_version *dep_version;
2745 uint32_t dep_slot;
David Vinczee574f2d2020-07-10 11:42:03 +02002746 int rc;
2747
Mark Horvathccaf7f82021-01-04 18:16:42 +01002748 /* Determine the source of the image which is the subject of
2749 * the dependency and get it's version.
David Vinczee574f2d2020-07-10 11:42:03 +02002750 */
Raef Colesfe57e7d2021-10-15 11:07:09 +01002751 dep_slot = state->slot_usage[dep->image_id].active_slot;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002752 dep_version = &state->imgs[dep->image_id][dep_slot].hdr.ih_ver;
2753
2754 rc = boot_version_cmp(dep_version, &dep->image_min_version);
2755 if (rc >= 0) {
2756 /* Dependency satisfied. */
2757 rc = 0;
David Vinczee574f2d2020-07-10 11:42:03 +02002758 }
2759
Mark Horvathccaf7f82021-01-04 18:16:42 +01002760 return rc;
2761}
2762
2763/**
2764 * Reads all dependency TLVs of an image and verifies one after another to see
2765 * if they are all satisfied.
2766 *
2767 * @param state Boot loader status information.
Mark Horvathccaf7f82021-01-04 18:16:42 +01002768 *
2769 * @return 0 if dependencies are met; nonzero otherwise.
2770 */
2771static int
Raef Colesfe57e7d2021-10-15 11:07:09 +01002772boot_verify_slot_dependencies(struct boot_loader_state *state)
Mark Horvathccaf7f82021-01-04 18:16:42 +01002773{
2774 uint32_t active_slot;
2775 const struct flash_area *fap;
2776 struct image_tlv_iter it;
2777 struct image_dependency dep;
2778 uint32_t off;
2779 uint16_t len;
2780 int area_id;
2781 int rc;
2782
Raef Colesfe57e7d2021-10-15 11:07:09 +01002783 active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002784
2785 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state),
2786 active_slot);
2787 rc = flash_area_open(area_id, &fap);
David Vinczee574f2d2020-07-10 11:42:03 +02002788 if (rc != 0) {
Mark Horvathccaf7f82021-01-04 18:16:42 +01002789 rc = BOOT_EFLASH;
2790 goto done;
David Vinczee574f2d2020-07-10 11:42:03 +02002791 }
2792
Mark Horvathccaf7f82021-01-04 18:16:42 +01002793 rc = bootutil_tlv_iter_begin(&it, boot_img_hdr(state, active_slot), fap,
2794 IMAGE_TLV_DEPENDENCY, true);
2795 if (rc != 0) {
2796 goto done;
2797 }
David Vinczee574f2d2020-07-10 11:42:03 +02002798
Mark Horvathccaf7f82021-01-04 18:16:42 +01002799 while (true) {
2800 rc = bootutil_tlv_iter_next(&it, &off, &len, NULL);
2801 if (rc < 0) {
2802 return -1;
2803 } else if (rc > 0) {
2804 rc = 0;
2805 break;
2806 }
David Vinczee574f2d2020-07-10 11:42:03 +02002807
Mark Horvathccaf7f82021-01-04 18:16:42 +01002808 if (len != sizeof(dep)) {
2809 rc = BOOT_EBADIMAGE;
2810 goto done;
2811 }
2812
2813 rc = LOAD_IMAGE_DATA(boot_img_hdr(state, active_slot),
2814 fap, off, &dep, len);
2815 if (rc != 0) {
2816 rc = BOOT_EFLASH;
2817 goto done;
2818 }
2819
2820 if (dep.image_id >= BOOT_IMAGE_NUMBER) {
2821 rc = BOOT_EBADARGS;
2822 goto done;
2823 }
2824
Raef Colesfe57e7d2021-10-15 11:07:09 +01002825 rc = boot_verify_slot_dependency(state, &dep);
Mark Horvathccaf7f82021-01-04 18:16:42 +01002826 if (rc != 0) {
2827 /* Dependency not satisfied. */
2828 goto done;
2829 }
2830 }
2831
2832done:
2833 flash_area_close(fap);
2834 return rc;
2835}
2836
2837/**
2838 * Checks the dependency of all the active slots. If an image found with
2839 * invalid or not satisfied dependencies the image is removed from SRAM (in
2840 * case of MCUBOOT_RAM_LOAD strategy) and its slot is set to unavailable.
2841 *
2842 * @param state Boot loader status information.
Mark Horvathccaf7f82021-01-04 18:16:42 +01002843 *
2844 * @return 0 if dependencies are met; nonzero otherwise.
2845 */
2846static int
Raef Colesfe57e7d2021-10-15 11:07:09 +01002847boot_verify_dependencies(struct boot_loader_state *state)
Mark Horvathccaf7f82021-01-04 18:16:42 +01002848{
2849 int rc = -1;
2850 uint32_t active_slot;
2851
2852 IMAGES_ITER(BOOT_CURR_IMG(state)) {
Raef Colesfe57e7d2021-10-15 11:07:09 +01002853 rc = boot_verify_slot_dependencies(state);
Mark Horvathccaf7f82021-01-04 18:16:42 +01002854 if (rc != 0) {
2855 /* Dependencies not met or invalid dependencies. */
2856
2857#ifdef MCUBOOT_RAM_LOAD
Raef Colesfe57e7d2021-10-15 11:07:09 +01002858 boot_remove_image_from_sram(state);
Mark Horvathccaf7f82021-01-04 18:16:42 +01002859#endif /* MCUBOOT_RAM_LOAD */
2860
Raef Colesfe57e7d2021-10-15 11:07:09 +01002861 active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot;
2862 state->slot_usage[BOOT_CURR_IMG(state)].slot_available[active_slot] = false;
2863 state->slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002864
2865 return rc;
2866 }
2867 }
2868
2869 return rc;
2870}
2871#endif /* (BOOT_IMAGE_NUMBER > 1) */
2872
2873/**
2874 * Tries to load a slot for all the images with validation.
2875 *
2876 * @param state Boot loader status information.
Mark Horvathccaf7f82021-01-04 18:16:42 +01002877 *
2878 * @return 0 on success; nonzero on failure.
2879 */
2880fih_int
Raef Colesfe57e7d2021-10-15 11:07:09 +01002881boot_load_and_validate_images(struct boot_loader_state *state)
Mark Horvathccaf7f82021-01-04 18:16:42 +01002882{
2883 uint32_t active_slot;
2884 int rc;
2885 fih_int fih_rc;
2886
2887 /* Go over all the images and try to load one */
2888 IMAGES_ITER(BOOT_CURR_IMG(state)) {
2889 /* All slots tried until a valid image found. Breaking from this loop
2890 * means that a valid image found or already loaded. If no slot is
2891 * found the function returns with error code. */
2892 while (true) {
Mark Horvathccaf7f82021-01-04 18:16:42 +01002893 /* Go over all the slots and try to load one */
Raef Colesfe57e7d2021-10-15 11:07:09 +01002894 active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002895 if (active_slot != NO_ACTIVE_SLOT){
2896 /* A slot is already active, go to next image. */
2897 break;
David Vinczee574f2d2020-07-10 11:42:03 +02002898 }
David Vincze505fba22020-10-22 13:53:29 +02002899
Raef Colesfe57e7d2021-10-15 11:07:09 +01002900 active_slot = find_slot_with_highest_version(state);
Mark Horvathccaf7f82021-01-04 18:16:42 +01002901 if (active_slot == NO_ACTIVE_SLOT) {
2902 BOOT_LOG_INF("No slot to load for image %d",
2903 BOOT_CURR_IMG(state));
2904 FIH_RET(FIH_FAILURE);
2905 }
2906
2907 /* Save the number of the active slot. */
Raef Colesfe57e7d2021-10-15 11:07:09 +01002908 state->slot_usage[BOOT_CURR_IMG(state)].active_slot = active_slot;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002909
2910#ifdef MCUBOOT_DIRECT_XIP
Raef Colesfe57e7d2021-10-15 11:07:09 +01002911 rc = boot_rom_address_check(state);
Mark Horvathccaf7f82021-01-04 18:16:42 +01002912 if (rc != 0) {
2913 /* The image is placed in an unsuitable slot. */
Raef Colesfe57e7d2021-10-15 11:07:09 +01002914 state->slot_usage[BOOT_CURR_IMG(state)].slot_available[active_slot] = false;
2915 state->slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002916 continue;
2917 }
George Becksteind4d90f82021-05-11 02:00:00 -04002918
David Vincze505fba22020-10-22 13:53:29 +02002919#ifdef MCUBOOT_DIRECT_XIP_REVERT
Raef Colesfe57e7d2021-10-15 11:07:09 +01002920 rc = boot_select_or_erase(state);
David Vincze505fba22020-10-22 13:53:29 +02002921 if (rc != 0) {
2922 /* The selected image slot has been erased. */
Raef Colesfe57e7d2021-10-15 11:07:09 +01002923 state->slot_usage[BOOT_CURR_IMG(state)].slot_available[active_slot] = false;
2924 state->slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT;
David Vincze505fba22020-10-22 13:53:29 +02002925 continue;
2926 }
2927#endif /* MCUBOOT_DIRECT_XIP_REVERT */
David Vincze1c456242021-06-29 15:25:24 +02002928#endif /* MCUBOOT_DIRECT_XIP */
David Vincze505fba22020-10-22 13:53:29 +02002929
Tamas Banfe031092020-09-10 17:32:39 +02002930#ifdef MCUBOOT_RAM_LOAD
2931 /* Image is first loaded to RAM and authenticated there in order to
2932 * prevent TOCTOU attack during image copy. This could be applied
2933 * when loading images from external (untrusted) flash to internal
2934 * (trusted) RAM and image is authenticated before copying.
2935 */
Raef Colesfe57e7d2021-10-15 11:07:09 +01002936 rc = boot_load_image_to_sram(state);
Tamas Banfe031092020-09-10 17:32:39 +02002937 if (rc != 0 ) {
Mark Horvathccaf7f82021-01-04 18:16:42 +01002938 /* Image cannot be ramloaded. */
2939 boot_remove_image_from_flash(state, active_slot);
Raef Colesfe57e7d2021-10-15 11:07:09 +01002940 state->slot_usage[BOOT_CURR_IMG(state)].slot_available[active_slot] = false;
2941 state->slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT;
Tamas Banfe031092020-09-10 17:32:39 +02002942 continue;
Tamas Banfe031092020-09-10 17:32:39 +02002943 }
2944#endif /* MCUBOOT_RAM_LOAD */
Mark Horvathccaf7f82021-01-04 18:16:42 +01002945
2946 FIH_CALL(boot_validate_slot, fih_rc, state, active_slot, NULL);
2947 if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
2948 /* Image is invalid. */
Tamas Banfe031092020-09-10 17:32:39 +02002949#ifdef MCUBOOT_RAM_LOAD
Raef Colesfe57e7d2021-10-15 11:07:09 +01002950 boot_remove_image_from_sram(state);
Tamas Banfe031092020-09-10 17:32:39 +02002951#endif /* MCUBOOT_RAM_LOAD */
Raef Colesfe57e7d2021-10-15 11:07:09 +01002952 state->slot_usage[BOOT_CURR_IMG(state)].slot_available[active_slot] = false;
2953 state->slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002954 continue;
David Vincze505fba22020-10-22 13:53:29 +02002955 }
Mark Horvathccaf7f82021-01-04 18:16:42 +01002956
2957 /* Valid image loaded from a slot, go to next image. */
2958 break;
2959 }
2960 }
2961
2962 FIH_RET(FIH_SUCCESS);
2963}
2964
2965/**
2966 * Updates the security counter for the current image.
2967 *
2968 * @param state Boot loader status information.
Mark Horvathccaf7f82021-01-04 18:16:42 +01002969 *
2970 * @return 0 on success; nonzero on failure.
2971 */
2972static int
Raef Colesfe57e7d2021-10-15 11:07:09 +01002973boot_update_hw_rollback_protection(struct boot_loader_state *state)
Mark Horvathccaf7f82021-01-04 18:16:42 +01002974{
2975#ifdef MCUBOOT_HW_ROLLBACK_PROT
2976 int rc;
2977
2978 /* Update the stored security counter with the newer (active) image's
2979 * security counter value.
2980 */
David Vincze1c456242021-06-29 15:25:24 +02002981#if defined(MCUBOOT_DIRECT_XIP) && defined(MCUBOOT_DIRECT_XIP_REVERT)
Mark Horvathccaf7f82021-01-04 18:16:42 +01002982 /* When the 'revert' mechanism is enabled in direct-xip mode, the
2983 * security counter can be increased only after reboot, if the image
2984 * has been confirmed at runtime (the image_ok flag has been set).
2985 * This way a 'revert' can be performed when it's necessary.
2986 */
Raef Colesfe57e7d2021-10-15 11:07:09 +01002987 if (state->slot_usage[BOOT_CURR_IMG(state)].swap_state.image_ok == BOOT_FLAG_SET) {
David Vincze505fba22020-10-22 13:53:29 +02002988#endif
Sherry Zhang50b06ae2021-07-09 15:22:51 +08002989 rc = boot_update_security_counter(BOOT_CURR_IMG(state),
Raef Colesfe57e7d2021-10-15 11:07:09 +01002990 state->slot_usage[BOOT_CURR_IMG(state)].active_slot,
2991 boot_img_hdr(state, state->slot_usage[BOOT_CURR_IMG(state)].active_slot));
David Vinczee574f2d2020-07-10 11:42:03 +02002992 if (rc != 0) {
Mark Horvathccaf7f82021-01-04 18:16:42 +01002993 BOOT_LOG_ERR("Security counter update failed after image "
2994 "validation.");
2995 return rc;
David Vinczee574f2d2020-07-10 11:42:03 +02002996 }
David Vincze1c456242021-06-29 15:25:24 +02002997#if defined(MCUBOOT_DIRECT_XIP) && defined(MCUBOOT_DIRECT_XIP_REVERT)
Mark Horvathccaf7f82021-01-04 18:16:42 +01002998 }
2999#endif
David Vinczee574f2d2020-07-10 11:42:03 +02003000
Mark Horvathccaf7f82021-01-04 18:16:42 +01003001 return 0;
David Vinczee574f2d2020-07-10 11:42:03 +02003002
Mark Horvathccaf7f82021-01-04 18:16:42 +01003003#else /* MCUBOOT_HW_ROLLBACK_PROT */
3004 (void) (state);
Mark Horvathccaf7f82021-01-04 18:16:42 +01003005 return 0;
3006#endif
3007}
3008
3009fih_int
3010context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp)
3011{
Mark Horvathccaf7f82021-01-04 18:16:42 +01003012 int rc;
David Brown695e5912021-05-24 16:58:01 -06003013 fih_int fih_rc = fih_int_encode(0);
Mark Horvathccaf7f82021-01-04 18:16:42 +01003014
3015 memset(state, 0, sizeof(struct boot_loader_state));
Mark Horvathccaf7f82021-01-04 18:16:42 +01003016
Raef Colesfe57e7d2021-10-15 11:07:09 +01003017 rc = boot_get_slot_usage(state);
Mark Horvathccaf7f82021-01-04 18:16:42 +01003018 if (rc != 0) {
David Vinczee574f2d2020-07-10 11:42:03 +02003019 goto out;
3020 }
3021
Mark Horvathccaf7f82021-01-04 18:16:42 +01003022#if (BOOT_IMAGE_NUMBER > 1)
3023 while (true) {
3024#endif
Raef Colesfe57e7d2021-10-15 11:07:09 +01003025 FIH_CALL(boot_load_and_validate_images, fih_rc, state);
Mark Horvathccaf7f82021-01-04 18:16:42 +01003026 if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
3027 goto out;
3028 }
3029
3030#if (BOOT_IMAGE_NUMBER > 1)
Raef Colesfe57e7d2021-10-15 11:07:09 +01003031 rc = boot_verify_dependencies(state);
Mark Horvathccaf7f82021-01-04 18:16:42 +01003032 if (rc != 0) {
3033 /* Dependency check failed for an image, it has been removed from
3034 * SRAM in case of MCUBOOT_RAM_LOAD strategy, and set to
3035 * unavailable. Try to load an image from another slot.
3036 */
3037 continue;
3038 }
3039 /* Dependency check was successful. */
3040 break;
3041 }
3042#endif
3043
3044 IMAGES_ITER(BOOT_CURR_IMG(state)) {
Raef Colesfe57e7d2021-10-15 11:07:09 +01003045 rc = boot_update_hw_rollback_protection(state);
Mark Horvathccaf7f82021-01-04 18:16:42 +01003046 if (rc != 0) {
3047 goto out;
3048 }
3049
Raef Colesfe57e7d2021-10-15 11:07:09 +01003050 rc = boot_add_shared_data(state, state->slot_usage[BOOT_CURR_IMG(state)].active_slot);
Mark Horvathccaf7f82021-01-04 18:16:42 +01003051 if (rc != 0) {
3052 goto out;
3053 }
3054 }
3055
3056 /* All image loaded successfully. */
3057#ifdef MCUBOOT_HAVE_LOGGING
Raef Colesfe57e7d2021-10-15 11:07:09 +01003058 print_loaded_images(state);
Mark Horvathccaf7f82021-01-04 18:16:42 +01003059#endif
3060
Raef Colesfe57e7d2021-10-15 11:07:09 +01003061 fill_rsp(state, rsp);
Mark Horvathccaf7f82021-01-04 18:16:42 +01003062
David Vinczee574f2d2020-07-10 11:42:03 +02003063out:
Mark Horvathccaf7f82021-01-04 18:16:42 +01003064 close_all_flash_areas(state);
Raef Colese8fe6cf2020-05-26 13:07:40 +01003065
Mark Horvathccaf7f82021-01-04 18:16:42 +01003066 if (fih_eq(fih_rc, FIH_SUCCESS)) {
3067 fih_rc = fih_int_encode(rc);
3068 }
Raef Colese8fe6cf2020-05-26 13:07:40 +01003069
Mark Horvathccaf7f82021-01-04 18:16:42 +01003070 FIH_RET(fih_rc);
David Vinczee574f2d2020-07-10 11:42:03 +02003071}
Tamas Banfe031092020-09-10 17:32:39 +02003072#endif /* MCUBOOT_DIRECT_XIP || MCUBOOT_RAM_LOAD */
David Vinczee574f2d2020-07-10 11:42:03 +02003073
3074/**
Raef Colese8fe6cf2020-05-26 13:07:40 +01003075 * Prepares the booting process. This function moves images around in flash as
David Vinczee574f2d2020-07-10 11:42:03 +02003076 * appropriate, and tells you what address to boot from.
3077 *
3078 * @param rsp On success, indicates how booting should occur.
3079 *
Raef Colese8fe6cf2020-05-26 13:07:40 +01003080 * @return FIH_SUCCESS on success; nonzero on failure.
David Vinczee574f2d2020-07-10 11:42:03 +02003081 */
Raef Colese8fe6cf2020-05-26 13:07:40 +01003082fih_int
David Vinczee574f2d2020-07-10 11:42:03 +02003083boot_go(struct boot_rsp *rsp)
3084{
Raef Colese8fe6cf2020-05-26 13:07:40 +01003085 fih_int fih_rc = FIH_FAILURE;
3086 FIH_CALL(context_boot_go, fih_rc, &boot_data, rsp);
3087 FIH_RET(fih_rc);
David Vinczee574f2d2020-07-10 11:42:03 +02003088}