blob: 4b0299f54cb9c5f36fc9dfaca9bfb7e7a2a2c586 [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
Antonio de Angelisba5fb1c2022-10-11 10:10:37 +01006 * Copyright (c) 2019-2023 Arm Limited
Dominik Ermel6f7f8732024-02-01 11:59:24 +00007 * Copyright (c) 2024 Nordic Semiconductor ASA
David Brownaac71112020-02-03 16:13:42 -07008 *
9 * Original license:
10 *
Christopher Collins92ea77f2016-12-12 15:59:26 -080011 * Licensed to the Apache Software Foundation (ASF) under one
12 * or more contributor license agreements. See the NOTICE file
13 * distributed with this work for additional information
14 * regarding copyright ownership. The ASF licenses this file
15 * to you under the Apache License, Version 2.0 (the
16 * "License"); you may not use this file except in compliance
17 * with the License. You may obtain a copy of the License at
18 *
19 * http://www.apache.org/licenses/LICENSE-2.0
20 *
21 * Unless required by applicable law or agreed to in writing,
22 * software distributed under the License is distributed on an
23 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
24 * KIND, either express or implied. See the License for the
25 * specific language governing permissions and limitations
26 * under the License.
27 */
28
29/**
30 * This file provides an interface to the boot loader. Functions defined in
31 * this file should only be called while the boot loader is running.
32 */
33
Christopher Collins92ea77f2016-12-12 15:59:26 -080034#include <stddef.h>
David Brown52eee562017-07-05 11:25:09 -060035#include <stdbool.h>
Christopher Collins92ea77f2016-12-12 15:59:26 -080036#include <inttypes.h>
37#include <stdlib.h>
38#include <string.h>
Christopher Collins92ea77f2016-12-12 15:59:26 -080039#include "bootutil/bootutil.h"
Kristine Jassmann73c38c62021-02-03 16:56:14 +000040#include "bootutil/bootutil_public.h"
Christopher Collins92ea77f2016-12-12 15:59:26 -080041#include "bootutil/image.h"
42#include "bootutil_priv.h"
Fabio Utzig12d59162019-11-28 10:01:59 -030043#include "swap_priv.h"
Marti Bolivarfd20c762017-02-07 16:52:50 -050044#include "bootutil/bootutil_log.h"
David Vinczec3084132020-02-18 14:50:47 +010045#include "bootutil/security_cnt.h"
David Vincze1cf11b52020-03-24 07:51:09 +010046#include "bootutil/boot_record.h"
Raef Colese8fe6cf2020-05-26 13:07:40 +010047#include "bootutil/fault_injection_hardening.h"
Mark Horvathccaf7f82021-01-04 18:16:42 +010048#include "bootutil/ramload.h"
Andrzej Puzdrowskib8f39692021-07-02 15:05:37 +020049#include "bootutil/boot_hooks.h"
Jamie McCrae56cb6102022-03-23 11:57:03 +000050#include "bootutil/mcuboot_status.h"
Marti Bolivarfd20c762017-02-07 16:52:50 -050051
Fabio Utzigba829042018-09-18 08:29:34 -030052#ifdef MCUBOOT_ENC_IMAGES
53#include "bootutil/enc_key.h"
54#endif
55
Carlos Falgueras García391b1972021-06-21 16:58:07 +020056#if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)
57#include <os/os_malloc.h>
58#endif
59
Fabio Utzigba1fbe62017-07-21 14:01:20 -030060#include "mcuboot_config/mcuboot_config.h"
Fabio Utzigeed80b62017-06-10 08:03:05 -030061
Carlos Falgueras Garcíaa4b4b0f2021-06-22 10:00:22 +020062BOOT_LOG_MODULE_DECLARE(mcuboot);
Emanuele Di Santo9f1933d2018-11-20 10:59:59 +010063
Marti Bolivar9b1f8bb2017-06-12 15:24:13 -040064static struct boot_loader_state boot_data;
Christopher Collins92ea77f2016-12-12 15:59:26 -080065
Jamie McCrae4f1ab9e2024-07-26 12:29:24 +010066#if defined(MCUBOOT_DATA_SHARING)
67static struct image_max_size image_max_sizes[BOOT_IMAGE_NUMBER] = {0};
68#endif
69
Fabio Utzigabec0732019-07-31 08:40:22 -030070#if (BOOT_IMAGE_NUMBER > 1)
71#define IMAGES_ITER(x) for ((x) = 0; (x) < BOOT_IMAGE_NUMBER; ++(x))
72#else
73#define IMAGES_ITER(x)
74#endif
75
Fabio Utzig10ee6482019-08-01 12:04:52 -030076/*
77 * This macro allows some control on the allocation of local variables.
78 * When running natively on a target, we don't want to allocated huge
79 * variables on the stack, so make them global instead. For the simulator
80 * we want to run as many threads as there are tests, and it's safer
81 * to just make those variables stack allocated.
82 */
83#if !defined(__BOOTSIM__)
84#define TARGET_STATIC static
85#else
86#define TARGET_STATIC
87#endif
88
Kristine Jassmann73c38c62021-02-03 16:56:14 +000089#if BOOT_MAX_ALIGN > 1024
90#define BUF_SZ BOOT_MAX_ALIGN
91#else
92#define BUF_SZ 1024
93#endif
94
Dominik Ermelaafcbad2024-02-29 20:40:20 +000095#define NO_ACTIVE_SLOT UINT32_MAX
96
David Vinczee574f2d2020-07-10 11:42:03 +020097static int
98boot_read_image_headers(struct boot_loader_state *state, bool require_all,
99 struct boot_status *bs)
100{
101 int rc;
102 int i;
103
104 for (i = 0; i < BOOT_NUM_SLOTS; i++) {
Andrzej Puzdrowskib8f39692021-07-02 15:05:37 +0200105 rc = BOOT_HOOK_CALL(boot_read_image_header_hook, BOOT_HOOK_REGULAR,
106 BOOT_CURR_IMG(state), i, boot_img_hdr(state, i));
107 if (rc == BOOT_HOOK_REGULAR)
108 {
109 rc = boot_read_image_header(state, i, boot_img_hdr(state, i), bs);
110 }
David Vinczee574f2d2020-07-10 11:42:03 +0200111 if (rc != 0) {
112 /* If `require_all` is set, fail on any single fail, otherwise
113 * if at least the first slot's header was read successfully,
114 * then the boot loader can attempt a boot.
115 *
116 * Failure to read any headers is a fatal error.
117 */
118 if (i > 0 && !require_all) {
119 return 0;
120 } else {
121 return rc;
122 }
123 }
124 }
125
126 return 0;
127}
128
Mark Horvathccaf7f82021-01-04 18:16:42 +0100129/**
130 * Saves boot status and shared data for current image.
131 *
132 * @param state Boot loader status information.
133 * @param active_slot Index of the slot will be loaded for current image.
134 *
135 * @return 0 on success; nonzero on failure.
136 */
137static int
138boot_add_shared_data(struct boot_loader_state *state,
Jamie McCrae3016d002023-03-14 12:35:51 +0000139 uint8_t active_slot)
Mark Horvathccaf7f82021-01-04 18:16:42 +0100140{
141#if defined(MCUBOOT_MEASURED_BOOT) || defined(MCUBOOT_DATA_SHARING)
142 int rc;
143
144#ifdef MCUBOOT_MEASURED_BOOT
145 rc = boot_save_boot_status(BOOT_CURR_IMG(state),
146 boot_img_hdr(state, active_slot),
147 BOOT_IMG_AREA(state, active_slot));
148 if (rc != 0) {
149 BOOT_LOG_ERR("Failed to add image data to shared area");
150 return rc;
151 }
152#endif /* MCUBOOT_MEASURED_BOOT */
153
154#ifdef MCUBOOT_DATA_SHARING
155 rc = boot_save_shared_data(boot_img_hdr(state, active_slot),
Jamie McCrae3016d002023-03-14 12:35:51 +0000156 BOOT_IMG_AREA(state, active_slot),
Jamie McCrae4f1ab9e2024-07-26 12:29:24 +0100157 active_slot, image_max_sizes);
Mark Horvathccaf7f82021-01-04 18:16:42 +0100158 if (rc != 0) {
159 BOOT_LOG_ERR("Failed to add data to shared memory area.");
160 return rc;
161 }
162#endif /* MCUBOOT_DATA_SHARING */
163
164 return 0;
165
166#else /* MCUBOOT_MEASURED_BOOT || MCUBOOT_DATA_SHARING */
167 (void) (state);
168 (void) (active_slot);
169
170 return 0;
171#endif
172}
173
174/**
175 * Fills rsp to indicate how booting should occur.
176 *
177 * @param state Boot loader status information.
Mark Horvathccaf7f82021-01-04 18:16:42 +0100178 * @param rsp boot_rsp struct to fill.
179 */
180static void
Raef Colesfe57e7d2021-10-15 11:07:09 +0100181fill_rsp(struct boot_loader_state *state, struct boot_rsp *rsp)
Mark Horvathccaf7f82021-01-04 18:16:42 +0100182{
183 uint32_t active_slot;
184
185#if (BOOT_IMAGE_NUMBER > 1)
Raef Colesf11de642021-10-15 11:11:56 +0100186 /* Always boot from the first enabled image. */
Mark Horvathccaf7f82021-01-04 18:16:42 +0100187 BOOT_CURR_IMG(state) = 0;
Raef Colesf11de642021-10-15 11:11:56 +0100188 IMAGES_ITER(BOOT_CURR_IMG(state)) {
189 if (!state->img_mask[BOOT_CURR_IMG(state)]) {
190 break;
191 }
192 }
INFINEON\DovhalA94360d52023-01-18 17:21:56 +0200193 /* At least one image must be active, otherwise skip the execution */
194 if (BOOT_CURR_IMG(state) >= BOOT_IMAGE_NUMBER) {
195 return;
196 }
Mark Horvathccaf7f82021-01-04 18:16:42 +0100197#endif
198
199#if defined(MCUBOOT_DIRECT_XIP) || defined(MCUBOOT_RAM_LOAD)
Raef Colesfe57e7d2021-10-15 11:07:09 +0100200 active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot;
Mark Horvathccaf7f82021-01-04 18:16:42 +0100201#else
Mark Horvathccaf7f82021-01-04 18:16:42 +0100202 active_slot = BOOT_PRIMARY_SLOT;
203#endif
204
Dominik Ermel260ae092021-04-23 05:38:45 +0000205 rsp->br_flash_dev_id = flash_area_get_device_id(BOOT_IMG_AREA(state, active_slot));
Mark Horvathccaf7f82021-01-04 18:16:42 +0100206 rsp->br_image_off = boot_img_slot_off(state, active_slot);
207 rsp->br_hdr = boot_img_hdr(state, active_slot);
208}
209
210/**
211 * Closes all flash areas.
212 *
213 * @param state Boot loader status information.
214 */
215static void
216close_all_flash_areas(struct boot_loader_state *state)
217{
218 uint32_t slot;
219
220 IMAGES_ITER(BOOT_CURR_IMG(state)) {
Raef Colesf11de642021-10-15 11:11:56 +0100221#if BOOT_IMAGE_NUMBER > 1
222 if (state->img_mask[BOOT_CURR_IMG(state)]) {
223 continue;
224 }
225#endif
Mark Horvathccaf7f82021-01-04 18:16:42 +0100226#if MCUBOOT_SWAP_USING_SCRATCH
227 flash_area_close(BOOT_SCRATCH_AREA(state));
228#endif
229 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
230 flash_area_close(BOOT_IMG_AREA(state, BOOT_NUM_SLOTS - 1 - slot));
231 }
232 }
233}
234
Dominik Ermelaafcbad2024-02-29 20:40:20 +0000235#if (BOOT_IMAGE_NUMBER > 1) || \
236 defined(MCUBOOT_DIRECT_XIP) || \
237 defined(MCUBOOT_RAM_LOAD) || \
238 defined(MCUBOOT_DOWNGRADE_PREVENTION)
239/**
240 * Compare image version numbers
241 *
242 * By default, the comparison does not take build number into account.
243 * Enable MCUBOOT_VERSION_CMP_USE_BUILD_NUMBER to take the build number into account.
244 *
245 * @param ver1 Pointer to the first image version to compare.
246 * @param ver2 Pointer to the second image version to compare.
247 *
248 * @retval -1 If ver1 is less than ver2.
249 * @retval 0 If the image version numbers are equal.
250 * @retval 1 If ver1 is greater than ver2.
251 */
252static int
253boot_version_cmp(const struct image_version *ver1,
254 const struct image_version *ver2)
255{
256 if (ver1->iv_major > ver2->iv_major) {
257 return 1;
258 }
259 if (ver1->iv_major < ver2->iv_major) {
260 return -1;
261 }
262 /* The major version numbers are equal, continue comparison. */
263 if (ver1->iv_minor > ver2->iv_minor) {
264 return 1;
265 }
266 if (ver1->iv_minor < ver2->iv_minor) {
267 return -1;
268 }
269 /* The minor version numbers are equal, continue comparison. */
270 if (ver1->iv_revision > ver2->iv_revision) {
271 return 1;
272 }
273 if (ver1->iv_revision < ver2->iv_revision) {
274 return -1;
275 }
276
277#if defined(MCUBOOT_VERSION_CMP_USE_BUILD_NUMBER)
278 /* The revisions are equal, continue comparison. */
279 if (ver1->iv_build_num > ver2->iv_build_num) {
280 return 1;
281 }
282 if (ver1->iv_build_num < ver2->iv_build_num) {
283 return -1;
284 }
285#endif
286
287 return 0;
288}
289#endif
290
291
292#if (BOOT_IMAGE_NUMBER > 1)
293
294static int
295boot_verify_slot_dependencies(struct boot_loader_state *state, uint32_t slot);
296
297/**
298 * Check the image dependency whether it is satisfied and modify
299 * the swap type if necessary.
300 *
301 * @param dep Image dependency which has to be verified.
302 *
303 * @return 0 on success; nonzero on failure.
304 */
305static int
306boot_verify_slot_dependency(struct boot_loader_state *state,
307 struct image_dependency *dep)
308{
309 struct image_version *dep_version;
310 size_t dep_slot;
311 int rc;
312
313 /* Determine the source of the image which is the subject of
314 * the dependency and get it's version. */
315#if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)
316 uint8_t swap_type = state->swap_type[dep->image_id];
317 dep_slot = BOOT_IS_UPGRADE(swap_type) ? BOOT_SECONDARY_SLOT
318 : BOOT_PRIMARY_SLOT;
319#else
320 dep_slot = state->slot_usage[dep->image_id].active_slot;
321#endif
322
323 dep_version = &state->imgs[dep->image_id][dep_slot].hdr.ih_ver;
324
325 rc = boot_version_cmp(dep_version, &dep->image_min_version);
326#if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)
327 if (rc < 0) {
328 /* Dependency not satisfied.
329 * Modify the swap type to decrease the version number of the image
330 * (which will be located in the primary slot after the boot process),
331 * consequently the number of unsatisfied dependencies will be
332 * decreased or remain the same.
333 */
334 switch (BOOT_SWAP_TYPE(state)) {
335 case BOOT_SWAP_TYPE_TEST:
336 case BOOT_SWAP_TYPE_PERM:
337 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
338 break;
339 case BOOT_SWAP_TYPE_NONE:
340 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_REVERT;
341 break;
342 default:
343 break;
344 }
345 } else {
346 /* Dependency satisfied. */
347 rc = 0;
348 }
349#else
350 if (rc >= 0) {
351 /* Dependency satisfied. */
352 rc = 0;
353 }
354#endif
355
356 return rc;
357}
358
359#if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)
360/**
361 * Iterate over all the images and verify whether the image dependencies in the
362 * TLV area are all satisfied and update the related swap type if necessary.
363 */
364static int
365boot_verify_dependencies(struct boot_loader_state *state)
366{
367 int rc = -1;
368 uint8_t slot;
369
370 BOOT_CURR_IMG(state) = 0;
371 while (BOOT_CURR_IMG(state) < BOOT_IMAGE_NUMBER) {
372 if (state->img_mask[BOOT_CURR_IMG(state)]) {
373 BOOT_CURR_IMG(state)++;
374 continue;
375 }
376 if (BOOT_SWAP_TYPE(state) != BOOT_SWAP_TYPE_NONE &&
377 BOOT_SWAP_TYPE(state) != BOOT_SWAP_TYPE_FAIL) {
378 slot = BOOT_SECONDARY_SLOT;
379 } else {
380 slot = BOOT_PRIMARY_SLOT;
381 }
382
383 rc = boot_verify_slot_dependencies(state, slot);
384 if (rc == 0) {
385 /* All dependencies've been satisfied, continue with next image. */
386 BOOT_CURR_IMG(state)++;
387 } else {
388 /* Cannot upgrade due to non-met dependencies, so disable all
389 * image upgrades.
390 */
391 for (int idx = 0; idx < BOOT_IMAGE_NUMBER; idx++) {
392 BOOT_CURR_IMG(state) = idx;
393 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
394 }
395 break;
396 }
397 }
398 return rc;
399}
400#else
401
402#if defined MCUBOOT_RAM_LOAD
403static inline int
404boot_remove_image_from_sram(struct boot_loader_state *state);
405#endif
406
407/**
408 * Checks the dependency of all the active slots. If an image found with
409 * invalid or not satisfied dependencies the image is removed from SRAM (in
410 * case of MCUBOOT_RAM_LOAD strategy) and its slot is set to unavailable.
411 *
412 * @param state Boot loader status information.
413 *
414 * @return 0 if dependencies are met; nonzero otherwise.
415 */
416static int
417boot_verify_dependencies(struct boot_loader_state *state)
418{
419 int rc = -1;
420 uint32_t active_slot;
421
422 IMAGES_ITER(BOOT_CURR_IMG(state)) {
423 if (state->img_mask[BOOT_CURR_IMG(state)]) {
424 continue;
425 }
426 active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot;
427 rc = boot_verify_slot_dependencies(state, active_slot);
428 if (rc != 0) {
429 /* Dependencies not met or invalid dependencies. */
430
431#ifdef MCUBOOT_RAM_LOAD
432 boot_remove_image_from_sram(state);
433#endif /* MCUBOOT_RAM_LOAD */
434
435 state->slot_usage[BOOT_CURR_IMG(state)].slot_available[active_slot] = false;
436 state->slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT;
437
438 return rc;
439 }
440 }
441
442 return rc;
443}
444#endif
445
446/**
447 * Read all dependency TLVs of an image from the flash and verify
448 * one after another to see if they are all satisfied.
449 *
450 * @param slot Image slot number.
451 *
452 * @return 0 on success; nonzero on failure.
453 */
454static int
455boot_verify_slot_dependencies(struct boot_loader_state *state, uint32_t slot)
456{
457 const struct flash_area *fap;
458 struct image_tlv_iter it;
459 struct image_dependency dep;
460 uint32_t off;
461 uint16_t len;
462 int area_id;
463 int rc;
464
465 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
466 rc = flash_area_open(area_id, &fap);
467 if (rc != 0) {
468 rc = BOOT_EFLASH;
469 goto done;
470 }
471
472 rc = bootutil_tlv_iter_begin(&it, boot_img_hdr(state, slot), fap,
473 IMAGE_TLV_DEPENDENCY, true);
474 if (rc != 0) {
475 goto done;
476 }
477
478 while (true) {
479 rc = bootutil_tlv_iter_next(&it, &off, &len, NULL);
480 if (rc < 0) {
481 return -1;
482 } else if (rc > 0) {
483 rc = 0;
484 break;
485 }
486
487 if (len != sizeof(dep)) {
488 rc = BOOT_EBADIMAGE;
489 goto done;
490 }
491
492 rc = LOAD_IMAGE_DATA(boot_img_hdr(state, slot),
493 fap, off, &dep, len);
494 if (rc != 0) {
495 rc = BOOT_EFLASH;
496 goto done;
497 }
498
499 if (dep.image_id >= BOOT_IMAGE_NUMBER) {
500 rc = BOOT_EBADARGS;
501 goto done;
502 }
503
504 /* Verify dependency and modify the swap type if not satisfied. */
505 rc = boot_verify_slot_dependency(state, &dep);
506 if (rc != 0) {
507 /* Dependency not satisfied */
508 goto done;
509 }
510 }
511
512done:
513 flash_area_close(fap);
514 return rc;
515}
516
517#endif /* (BOOT_IMAGE_NUMBER > 1) */
518
Tamas Banfe031092020-09-10 17:32:39 +0200519#if !defined(MCUBOOT_DIRECT_XIP)
David Brownf5b33d82017-09-01 10:58:27 -0600520/*
521 * Compute the total size of the given image. Includes the size of
522 * the TLVs.
523 */
Tamas Banfe031092020-09-10 17:32:39 +0200524#if !defined(MCUBOOT_OVERWRITE_ONLY) || defined(MCUBOOT_OVERWRITE_ONLY_FAST)
David Brownf5b33d82017-09-01 10:58:27 -0600525static int
Fabio Utzigd638b172019-08-09 10:38:05 -0300526boot_read_image_size(struct boot_loader_state *state, int slot, uint32_t *size)
David Brownf5b33d82017-09-01 10:58:27 -0600527{
528 const struct flash_area *fap;
Fabio Utzig61fd8882019-09-14 20:00:20 -0300529 struct image_tlv_info info;
Fabio Utzig233af7d2019-08-26 12:06:16 -0300530 uint32_t off;
Fabio Utzige52c08e2019-09-11 19:32:00 -0300531 uint32_t protect_tlv_size;
David Brownf5b33d82017-09-01 10:58:27 -0600532 int area_id;
533 int rc;
534
Fabio Utzig10ee6482019-08-01 12:04:52 -0300535#if (BOOT_IMAGE_NUMBER == 1)
536 (void)state;
537#endif
538
539 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
David Brownf5b33d82017-09-01 10:58:27 -0600540 rc = flash_area_open(area_id, &fap);
541 if (rc != 0) {
542 rc = BOOT_EFLASH;
543 goto done;
544 }
545
Fabio Utzig61fd8882019-09-14 20:00:20 -0300546 off = BOOT_TLV_OFF(boot_img_hdr(state, slot));
547
548 if (flash_area_read(fap, off, &info, sizeof(info))) {
549 rc = BOOT_EFLASH;
David Brownf5b33d82017-09-01 10:58:27 -0600550 goto done;
551 }
Fabio Utzig61fd8882019-09-14 20:00:20 -0300552
Fabio Utzige52c08e2019-09-11 19:32:00 -0300553 protect_tlv_size = boot_img_hdr(state, slot)->ih_protect_tlv_size;
554 if (info.it_magic == IMAGE_TLV_PROT_INFO_MAGIC) {
555 if (protect_tlv_size != info.it_tlv_tot) {
556 rc = BOOT_EBADIMAGE;
557 goto done;
558 }
559
560 if (flash_area_read(fap, off + info.it_tlv_tot, &info, sizeof(info))) {
561 rc = BOOT_EFLASH;
562 goto done;
563 }
564 } else if (protect_tlv_size != 0) {
565 rc = BOOT_EBADIMAGE;
566 goto done;
567 }
568
Fabio Utzig61fd8882019-09-14 20:00:20 -0300569 if (info.it_magic != IMAGE_TLV_INFO_MAGIC) {
570 rc = BOOT_EBADIMAGE;
571 goto done;
572 }
573
Fabio Utzige52c08e2019-09-11 19:32:00 -0300574 *size = off + protect_tlv_size + info.it_tlv_tot;
David Brownf5b33d82017-09-01 10:58:27 -0600575 rc = 0;
576
577done:
578 flash_area_close(fap);
Fabio Utzig2eebf112017-09-04 15:25:08 -0300579 return rc;
David Brownf5b33d82017-09-01 10:58:27 -0600580}
Fabio Utzig36ec0e72017-09-05 08:10:33 -0300581#endif /* !MCUBOOT_OVERWRITE_ONLY */
David Brownf5b33d82017-09-01 10:58:27 -0600582
Tamas Banfe031092020-09-10 17:32:39 +0200583#if !defined(MCUBOOT_RAM_LOAD)
David Brownab449182019-11-15 09:32:52 -0700584static uint32_t
Fabio Utzig10ee6482019-08-01 12:04:52 -0300585boot_write_sz(struct boot_loader_state *state)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800586{
David Brownab449182019-11-15 09:32:52 -0700587 uint32_t elem_sz;
Fabio Utzig12d59162019-11-28 10:01:59 -0300588#if MCUBOOT_SWAP_USING_SCRATCH
David Brownab449182019-11-15 09:32:52 -0700589 uint32_t align;
Fabio Utzig12d59162019-11-28 10:01:59 -0300590#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800591
592 /* Figure out what size to write update status update as. The size depends
593 * on what the minimum write size is for scratch area, active image slot.
594 * We need to use the bigger of those 2 values.
595 */
Fabio Utzig10ee6482019-08-01 12:04:52 -0300596 elem_sz = flash_area_align(BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT));
Fabio Utzig12d59162019-11-28 10:01:59 -0300597#if MCUBOOT_SWAP_USING_SCRATCH
Fabio Utzig10ee6482019-08-01 12:04:52 -0300598 align = flash_area_align(BOOT_SCRATCH_AREA(state));
Christopher Collins92ea77f2016-12-12 15:59:26 -0800599 if (align > elem_sz) {
600 elem_sz = align;
601 }
Fabio Utzig12d59162019-11-28 10:01:59 -0300602#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800603
604 return elem_sz;
605}
606
Fabio Utzig10ee6482019-08-01 12:04:52 -0300607static int
608boot_initialize_area(struct boot_loader_state *state, int flash_area)
609{
Dominik Ermel51c8d762021-05-24 15:34:01 +0000610 uint32_t num_sectors = BOOT_MAX_IMG_SECTORS;
611 boot_sector_t *out_sectors;
612 uint32_t *out_num_sectors;
Fabio Utzig10ee6482019-08-01 12:04:52 -0300613 int rc;
614
615 num_sectors = BOOT_MAX_IMG_SECTORS;
616
617 if (flash_area == FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state))) {
618 out_sectors = BOOT_IMG(state, BOOT_PRIMARY_SLOT).sectors;
619 out_num_sectors = &BOOT_IMG(state, BOOT_PRIMARY_SLOT).num_sectors;
620 } else if (flash_area == FLASH_AREA_IMAGE_SECONDARY(BOOT_CURR_IMG(state))) {
621 out_sectors = BOOT_IMG(state, BOOT_SECONDARY_SLOT).sectors;
622 out_num_sectors = &BOOT_IMG(state, BOOT_SECONDARY_SLOT).num_sectors;
Fabio Utzig12d59162019-11-28 10:01:59 -0300623#if MCUBOOT_SWAP_USING_SCRATCH
Fabio Utzig10ee6482019-08-01 12:04:52 -0300624 } else if (flash_area == FLASH_AREA_IMAGE_SCRATCH) {
625 out_sectors = state->scratch.sectors;
626 out_num_sectors = &state->scratch.num_sectors;
Fabio Utzig12d59162019-11-28 10:01:59 -0300627#endif
Fabio Utzig10ee6482019-08-01 12:04:52 -0300628 } else {
629 return BOOT_EFLASH;
630 }
631
Dominik Ermel51c8d762021-05-24 15:34:01 +0000632#ifdef MCUBOOT_USE_FLASH_AREA_GET_SECTORS
Fabio Utzig10ee6482019-08-01 12:04:52 -0300633 rc = flash_area_get_sectors(flash_area, &num_sectors, out_sectors);
Dominik Ermel51c8d762021-05-24 15:34:01 +0000634#else
635 _Static_assert(sizeof(int) <= sizeof(uint32_t), "Fix needed");
636 rc = flash_area_to_sectors(flash_area, (int *)&num_sectors, out_sectors);
637#endif /* defined(MCUBOOT_USE_FLASH_AREA_GET_SECTORS) */
Fabio Utzig10ee6482019-08-01 12:04:52 -0300638 if (rc != 0) {
639 return rc;
640 }
641 *out_num_sectors = num_sectors;
642 return 0;
643}
Fabio Utzig10ee6482019-08-01 12:04:52 -0300644
Christopher Collins92ea77f2016-12-12 15:59:26 -0800645/**
646 * Determines the sector layout of both image slots and the scratch area.
647 * This information is necessary for calculating the number of bytes to erase
648 * and copy during an image swap. The information collected during this
Fabio Utzig10ee6482019-08-01 12:04:52 -0300649 * function is used to populate the state.
Christopher Collins92ea77f2016-12-12 15:59:26 -0800650 */
651static int
Fabio Utzig10ee6482019-08-01 12:04:52 -0300652boot_read_sectors(struct boot_loader_state *state)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800653{
Fabio Utzigb0f04732019-07-31 09:49:19 -0300654 uint8_t image_index;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800655 int rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800656
Fabio Utzig10ee6482019-08-01 12:04:52 -0300657 image_index = BOOT_CURR_IMG(state);
Fabio Utzigb0f04732019-07-31 09:49:19 -0300658
659 rc = boot_initialize_area(state, FLASH_AREA_IMAGE_PRIMARY(image_index));
Christopher Collins92ea77f2016-12-12 15:59:26 -0800660 if (rc != 0) {
661 return BOOT_EFLASH;
662 }
663
Fabio Utzig10ee6482019-08-01 12:04:52 -0300664 rc = boot_initialize_area(state, FLASH_AREA_IMAGE_SECONDARY(image_index));
Christopher Collins92ea77f2016-12-12 15:59:26 -0800665 if (rc != 0) {
Andrzej Puzdrowski54b4ad92021-06-22 13:21:22 +0200666 /* We need to differentiate from the primary image issue */
667 return BOOT_EFLASH_SEC;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800668 }
669
Fabio Utzig12d59162019-11-28 10:01:59 -0300670#if MCUBOOT_SWAP_USING_SCRATCH
Fabio Utzig10ee6482019-08-01 12:04:52 -0300671 rc = boot_initialize_area(state, FLASH_AREA_IMAGE_SCRATCH);
Fabio Utzig2bd980a2018-11-26 10:38:17 -0200672 if (rc != 0) {
673 return BOOT_EFLASH;
674 }
Fabio Utzig12d59162019-11-28 10:01:59 -0300675#endif
Fabio Utzig2bd980a2018-11-26 10:38:17 -0200676
Fabio Utzig10ee6482019-08-01 12:04:52 -0300677 BOOT_WRITE_SZ(state) = boot_write_sz(state);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800678
679 return 0;
680}
681
Fabio Utzig12d59162019-11-28 10:01:59 -0300682void
683boot_status_reset(struct boot_status *bs)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800684{
Fabio Utzig4741c452019-12-19 15:32:41 -0300685#ifdef MCUBOOT_ENC_IMAGES
Kristine Jassmann73c38c62021-02-03 16:56:14 +0000686 memset(&bs->enckey, 0xff, BOOT_NUM_SLOTS * BOOT_ENC_KEY_ALIGN_SIZE);
Fabio Utzig4741c452019-12-19 15:32:41 -0300687#if MCUBOOT_SWAP_SAVE_ENCTLV
688 memset(&bs->enctlv, 0xff, BOOT_NUM_SLOTS * BOOT_ENC_TLV_ALIGN_SIZE);
689#endif
690#endif /* MCUBOOT_ENC_IMAGES */
691
692 bs->use_scratch = 0;
693 bs->swap_size = 0;
694 bs->source = 0;
695
Fabio Utzig74aef312019-11-28 11:05:34 -0300696 bs->op = BOOT_STATUS_OP_MOVE;
Fabio Utzig39000012018-07-30 12:40:20 -0300697 bs->idx = BOOT_STATUS_IDX_0;
698 bs->state = BOOT_STATUS_STATE_0;
Christopher Collinsa1c12042019-05-23 14:00:28 -0700699 bs->swap_type = BOOT_SWAP_TYPE_NONE;
Fabio Utzig12d59162019-11-28 10:01:59 -0300700}
Christopher Collins92ea77f2016-12-12 15:59:26 -0800701
Fabio Utzig12d59162019-11-28 10:01:59 -0300702bool
703boot_status_is_reset(const struct boot_status *bs)
704{
Fabio Utzig74aef312019-11-28 11:05:34 -0300705 return (bs->op == BOOT_STATUS_OP_MOVE &&
706 bs->idx == BOOT_STATUS_IDX_0 &&
707 bs->state == BOOT_STATUS_STATE_0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800708}
709
710/**
711 * Writes the supplied boot status to the flash file system. The boot status
712 * contains the current state of an in-progress image copy operation.
713 *
714 * @param bs The boot status to write.
715 *
716 * @return 0 on success; nonzero on failure.
717 */
718int
Fabio Utzig12d59162019-11-28 10:01:59 -0300719boot_write_status(const struct boot_loader_state *state, struct boot_status *bs)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800720{
721 const struct flash_area *fap;
722 uint32_t off;
723 int area_id;
Dominik Ermel9479af02021-10-19 10:06:44 +0000724 int rc = 0;
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300725 uint8_t buf[BOOT_MAX_ALIGN];
Gustavo Henrique Nihei4aa286d2021-11-24 14:54:56 -0300726 uint32_t align;
Fabio Utzig39000012018-07-30 12:40:20 -0300727 uint8_t erased_val;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800728
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300729 /* NOTE: The first sector copied (that is the last sector on slot) contains
David Vincze2d736ad2019-02-18 11:50:22 +0100730 * the trailer. Since in the last step the primary slot is erased, the
731 * first two status writes go to the scratch which will be copied to
732 * the primary slot!
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300733 */
734
Fabio Utzig12d59162019-11-28 10:01:59 -0300735#if MCUBOOT_SWAP_USING_SCRATCH
Fabio Utzig2473ac02017-05-02 12:45:02 -0300736 if (bs->use_scratch) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800737 /* Write to scratch. */
738 area_id = FLASH_AREA_IMAGE_SCRATCH;
739 } else {
Fabio Utzig12d59162019-11-28 10:01:59 -0300740#endif
David Vincze2d736ad2019-02-18 11:50:22 +0100741 /* Write to the primary slot. */
Fabio Utzig10ee6482019-08-01 12:04:52 -0300742 area_id = FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state));
Fabio Utzig12d59162019-11-28 10:01:59 -0300743#if MCUBOOT_SWAP_USING_SCRATCH
Christopher Collins92ea77f2016-12-12 15:59:26 -0800744 }
Fabio Utzig12d59162019-11-28 10:01:59 -0300745#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800746
747 rc = flash_area_open(area_id, &fap);
748 if (rc != 0) {
Dominik Ermel9479af02021-10-19 10:06:44 +0000749 return BOOT_EFLASH;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800750 }
751
752 off = boot_status_off(fap) +
Fabio Utzig12d59162019-11-28 10:01:59 -0300753 boot_status_internal_off(bs, BOOT_WRITE_SZ(state));
Andrzej Puzdrowskib788c712018-04-12 12:42:49 +0200754 align = flash_area_align(fap);
Fabio Utzig39000012018-07-30 12:40:20 -0300755 erased_val = flash_area_erased_val(fap);
756 memset(buf, erased_val, BOOT_MAX_ALIGN);
David Brown9d725462017-01-23 15:50:58 -0700757 buf[0] = bs->state;
758
Jamie McCrae35e99312024-01-03 07:37:55 +0000759 BOOT_LOG_DBG("writing swap status; fa_id=%d off=0x%lx (0x%lx)",
760 flash_area_get_id(fap), (unsigned long)off,
761 (unsigned long)flash_area_get_off(fap) + off);
762
David Brown9d725462017-01-23 15:50:58 -0700763 rc = flash_area_write(fap, off, buf, align);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800764 if (rc != 0) {
765 rc = BOOT_EFLASH;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800766 }
767
Christopher Collins92ea77f2016-12-12 15:59:26 -0800768 flash_area_close(fap);
Dominik Ermel9479af02021-10-19 10:06:44 +0000769
Christopher Collins92ea77f2016-12-12 15:59:26 -0800770 return rc;
771}
Tamas Banfe031092020-09-10 17:32:39 +0200772#endif /* !MCUBOOT_RAM_LOAD */
David Vinczee574f2d2020-07-10 11:42:03 +0200773#endif /* !MCUBOOT_DIRECT_XIP */
Christopher Collins92ea77f2016-12-12 15:59:26 -0800774
775/*
David Vinczec3084132020-02-18 14:50:47 +0100776 * Validate image hash/signature and optionally the security counter in a slot.
Christopher Collins92ea77f2016-12-12 15:59:26 -0800777 */
Michael Grand5047f032022-11-24 16:49:56 +0100778static fih_ret
Fabio Utzig10ee6482019-08-01 12:04:52 -0300779boot_image_check(struct boot_loader_state *state, struct image_header *hdr,
780 const struct flash_area *fap, struct boot_status *bs)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800781{
Fabio Utzig10ee6482019-08-01 12:04:52 -0300782 TARGET_STATIC uint8_t tmpbuf[BOOT_TMPBUF_SZ];
Fabio Utzigba829042018-09-18 08:29:34 -0300783 int rc;
Michael Grand5047f032022-11-24 16:49:56 +0100784 FIH_DECLARE(fih_rc, FIH_FAILURE);
Fabio Utzigba829042018-09-18 08:29:34 -0300785
Fabio Utzig10ee6482019-08-01 12:04:52 -0300786#if (BOOT_IMAGE_NUMBER == 1)
787 (void)state;
788#endif
789
Fabio Utzigba829042018-09-18 08:29:34 -0300790 (void)bs;
791 (void)rc;
Fabio Utzigbc077932019-08-26 11:16:34 -0300792
Hugo L'Hostisdb543e52021-03-09 18:00:31 +0000793/* In the case of ram loading the image has already been decrypted as it is
794 * decrypted when copied in ram */
795#if defined(MCUBOOT_ENC_IMAGES) && !defined(MCUBOOT_RAM_LOAD)
Dominik Ermel7f9ac972024-07-12 19:21:40 +0000796 if (MUST_DECRYPT(fap, BOOT_CURR_IMG(state), hdr)) {
797 rc = boot_enc_load(BOOT_CURR_ENC(state), 1, hdr, fap, bs);
Fabio Utzigba829042018-09-18 08:29:34 -0300798 if (rc < 0) {
Raef Colese8fe6cf2020-05-26 13:07:40 +0100799 FIH_RET(fih_rc);
Fabio Utzigba829042018-09-18 08:29:34 -0300800 }
Fabio Utzig4741c452019-12-19 15:32:41 -0300801 if (rc == 0 && boot_enc_set_key(BOOT_CURR_ENC(state), 1, bs)) {
Raef Colese8fe6cf2020-05-26 13:07:40 +0100802 FIH_RET(fih_rc);
Fabio Utzigba829042018-09-18 08:29:34 -0300803 }
804 }
Fabio Utzigbc077932019-08-26 11:16:34 -0300805#endif
806
Dominik Ermel7f9ac972024-07-12 19:21:40 +0000807 FIH_CALL(bootutil_img_validate, fih_rc, BOOT_CURR_ENC(state),
808 BOOT_CURR_IMG(state), hdr, fap, tmpbuf, BOOT_TMPBUF_SZ,
809 NULL, 0, NULL);
Fabio Utzig10ee6482019-08-01 12:04:52 -0300810
Raef Colese8fe6cf2020-05-26 13:07:40 +0100811 FIH_RET(fih_rc);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800812}
813
Tamas Banfe031092020-09-10 17:32:39 +0200814#if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)
Michael Grand5047f032022-11-24 16:49:56 +0100815static fih_ret
Christopher Collins92ea77f2016-12-12 15:59:26 -0800816split_image_check(struct image_header *app_hdr,
817 const struct flash_area *app_fap,
818 struct image_header *loader_hdr,
819 const struct flash_area *loader_fap)
820{
821 static void *tmpbuf;
822 uint8_t loader_hash[32];
Michael Grand5047f032022-11-24 16:49:56 +0100823 FIH_DECLARE(fih_rc, FIH_FAILURE);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800824
825 if (!tmpbuf) {
826 tmpbuf = malloc(BOOT_TMPBUF_SZ);
827 if (!tmpbuf) {
Raef Colese8fe6cf2020-05-26 13:07:40 +0100828 goto out;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800829 }
830 }
831
Raef Colese8fe6cf2020-05-26 13:07:40 +0100832 FIH_CALL(bootutil_img_validate, fih_rc, NULL, 0, loader_hdr, loader_fap,
833 tmpbuf, BOOT_TMPBUF_SZ, NULL, 0, loader_hash);
Michael Grand5047f032022-11-24 16:49:56 +0100834 if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
Raef Colese8fe6cf2020-05-26 13:07:40 +0100835 FIH_RET(fih_rc);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800836 }
837
Raef Colese8fe6cf2020-05-26 13:07:40 +0100838 FIH_CALL(bootutil_img_validate, fih_rc, NULL, 0, app_hdr, app_fap,
839 tmpbuf, BOOT_TMPBUF_SZ, loader_hash, 32, NULL);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800840
Raef Colese8fe6cf2020-05-26 13:07:40 +0100841out:
842 FIH_RET(fih_rc);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800843}
Tamas Banfe031092020-09-10 17:32:39 +0200844#endif /* !MCUBOOT_DIRECT_XIP && !MCUBOOT_RAM_LOAD */
Christopher Collins92ea77f2016-12-12 15:59:26 -0800845
Fabio Utzig338a19f2018-12-03 08:37:08 -0200846/*
David Brown9bf95af2019-10-10 15:36:36 -0600847 * Check that this is a valid header. Valid means that the magic is
848 * correct, and that the sizes/offsets are "sane". Sane means that
849 * there is no overflow on the arithmetic, and that the result fits
850 * within the flash area we are in.
851 */
852static bool
853boot_is_header_valid(const struct image_header *hdr, const struct flash_area *fap)
854{
855 uint32_t size;
856
857 if (hdr->ih_magic != IMAGE_MAGIC) {
858 return false;
859 }
860
861 if (!boot_u32_safe_add(&size, hdr->ih_img_size, hdr->ih_hdr_size)) {
862 return false;
863 }
864
Dominik Ermel260ae092021-04-23 05:38:45 +0000865 if (size >= flash_area_get_size(fap)) {
David Brown9bf95af2019-10-10 15:36:36 -0600866 return false;
867 }
868
869 return true;
870}
871
872/*
Fabio Utzig338a19f2018-12-03 08:37:08 -0200873 * Check that a memory area consists of a given value.
874 */
875static inline bool
876boot_data_is_set_to(uint8_t val, void *data, size_t len)
Fabio Utzig39000012018-07-30 12:40:20 -0300877{
878 uint8_t i;
Fabio Utzig338a19f2018-12-03 08:37:08 -0200879 uint8_t *p = (uint8_t *)data;
880 for (i = 0; i < len; i++) {
881 if (val != p[i]) {
882 return false;
Fabio Utzig39000012018-07-30 12:40:20 -0300883 }
884 }
Fabio Utzig338a19f2018-12-03 08:37:08 -0200885 return true;
886}
887
888static int
Fabio Utzig10ee6482019-08-01 12:04:52 -0300889boot_check_header_erased(struct boot_loader_state *state, int slot)
Fabio Utzig338a19f2018-12-03 08:37:08 -0200890{
891 const struct flash_area *fap;
892 struct image_header *hdr;
893 uint8_t erased_val;
Fabio Utzigb0f04732019-07-31 09:49:19 -0300894 int area_id;
Fabio Utzig338a19f2018-12-03 08:37:08 -0200895 int rc;
896
Fabio Utzig10ee6482019-08-01 12:04:52 -0300897 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
Fabio Utzigb0f04732019-07-31 09:49:19 -0300898 rc = flash_area_open(area_id, &fap);
Fabio Utzig338a19f2018-12-03 08:37:08 -0200899 if (rc != 0) {
900 return -1;
901 }
902
903 erased_val = flash_area_erased_val(fap);
904 flash_area_close(fap);
905
Fabio Utzig10ee6482019-08-01 12:04:52 -0300906 hdr = boot_img_hdr(state, slot);
Fabio Utzig338a19f2018-12-03 08:37:08 -0200907 if (!boot_data_is_set_to(erased_val, &hdr->ih_magic, sizeof(hdr->ih_magic))) {
908 return -1;
909 }
910
911 return 0;
Fabio Utzig39000012018-07-30 12:40:20 -0300912}
913
Dominik Ermel0c8c8d52021-02-17 14:45:02 +0000914#if defined(MCUBOOT_DIRECT_XIP)
915/**
916 * Check if image in slot has been set with specific ROM address to run from
917 * and whether the slot starts at that address.
918 *
919 * @returns 0 if IMAGE_F_ROM_FIXED flag is not set;
920 * 0 if IMAGE_F_ROM_FIXED flag is set and ROM address specified in
921 * header matches the slot address;
922 * 1 if IMF_F_ROM_FIXED flag is set but ROM address specified in header
923 * does not match the slot address.
924 */
925static bool
Raef Colesfe57e7d2021-10-15 11:07:09 +0100926boot_rom_address_check(struct boot_loader_state *state)
Dominik Ermel0c8c8d52021-02-17 14:45:02 +0000927{
Mark Horvathccaf7f82021-01-04 18:16:42 +0100928 uint32_t active_slot;
929 const struct image_header *hdr;
930 uint32_t f_off;
931
Raef Colesfe57e7d2021-10-15 11:07:09 +0100932 active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot;
Mark Horvathccaf7f82021-01-04 18:16:42 +0100933 hdr = boot_img_hdr(state, active_slot);
934 f_off = boot_img_slot_off(state, active_slot);
935
Dominik Ermel0c8c8d52021-02-17 14:45:02 +0000936 if (hdr->ih_flags & IMAGE_F_ROM_FIXED && hdr->ih_load_addr != f_off) {
937 BOOT_LOG_WRN("Image in %s slot at 0x%x has been built for offset 0x%x"\
Mark Horvathccaf7f82021-01-04 18:16:42 +0100938 ", skipping",
939 active_slot == 0 ? "primary" : "secondary", f_off,
Dominik Ermel0c8c8d52021-02-17 14:45:02 +0000940 hdr->ih_load_addr);
941
942 /* If there is address mismatch, the image is not bootable from this
943 * slot.
944 */
945 return 1;
946 }
947 return 0;
948}
949#endif
950
Fabio Utzigb1adb1e2019-09-11 11:42:53 -0300951/*
952 * Check that there is a valid image in a slot
953 *
954 * @returns
Raef Colese8fe6cf2020-05-26 13:07:40 +0100955 * FIH_SUCCESS if image was successfully validated
Michael Grand5047f032022-11-24 16:49:56 +0100956 * FIH_NO_BOOTABLE_IMAGE if no bootloable image was found
Raef Colese8fe6cf2020-05-26 13:07:40 +0100957 * FIH_FAILURE on any errors
Fabio Utzigb1adb1e2019-09-11 11:42:53 -0300958 */
Michael Grand5047f032022-11-24 16:49:56 +0100959static fih_ret
Fabio Utzig10ee6482019-08-01 12:04:52 -0300960boot_validate_slot(struct boot_loader_state *state, int slot,
961 struct boot_status *bs)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800962{
963 const struct flash_area *fap;
Marti Bolivarf804f622017-06-12 15:41:48 -0400964 struct image_header *hdr;
Fabio Utzigb0f04732019-07-31 09:49:19 -0300965 int area_id;
Michael Grand5047f032022-11-24 16:49:56 +0100966 FIH_DECLARE(fih_rc, FIH_FAILURE);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800967 int rc;
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300968
Fabio Utzig10ee6482019-08-01 12:04:52 -0300969 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
Fabio Utzigb0f04732019-07-31 09:49:19 -0300970 rc = flash_area_open(area_id, &fap);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800971 if (rc != 0) {
Raef Colese8fe6cf2020-05-26 13:07:40 +0100972 FIH_RET(fih_rc);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800973 }
974
Fabio Utzig10ee6482019-08-01 12:04:52 -0300975 hdr = boot_img_hdr(state, slot);
976 if (boot_check_header_erased(state, slot) == 0 ||
977 (hdr->ih_flags & IMAGE_F_NON_BOOTABLE)) {
Fabio Utzig260ec452020-07-09 18:40:07 -0300978
979#if defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SWAP_USING_MOVE)
980 /*
981 * This fixes an issue where an image might be erased, but a trailer
982 * be left behind. It can happen if the image is in the secondary slot
983 * and did not pass validation, in which case the whole slot is erased.
984 * If during the erase operation, a reset occurs, parts of the slot
985 * might have been erased while some did not. The concerning part is
986 * the trailer because it might disable a new image from being loaded
987 * through mcumgr; so we just get rid of the trailer here, if the header
988 * is erased.
989 */
990 if (slot != BOOT_PRIMARY_SLOT) {
991 swap_erase_trailer_sectors(state, fap);
992 }
993#endif
994
David Vincze2d736ad2019-02-18 11:50:22 +0100995 /* No bootable image in slot; continue booting from the primary slot. */
Michael Grand5047f032022-11-24 16:49:56 +0100996 fih_rc = FIH_NO_BOOTABLE_IMAGE;
Fabio Utzig338a19f2018-12-03 08:37:08 -0200997 goto out;
Fabio Utzig39000012018-07-30 12:40:20 -0300998 }
999
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +00001000#if defined(MCUBOOT_OVERWRITE_ONLY) && defined(MCUBOOT_DOWNGRADE_PREVENTION)
1001 if (slot != BOOT_PRIMARY_SLOT) {
1002 /* Check if version of secondary slot is sufficient */
David Vincze8b0b6372020-05-20 19:54:44 +02001003 rc = boot_version_cmp(
1004 &boot_img_hdr(state, BOOT_SECONDARY_SLOT)->ih_ver,
1005 &boot_img_hdr(state, BOOT_PRIMARY_SLOT)->ih_ver);
1006 if (rc < 0 && boot_check_header_erased(state, BOOT_PRIMARY_SLOT)) {
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +00001007 BOOT_LOG_ERR("insufficient version in secondary slot");
Dominik Ermel260ae092021-04-23 05:38:45 +00001008 flash_area_erase(fap, 0, flash_area_get_size(fap));
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +00001009 /* Image in the secondary slot does not satisfy version requirement.
1010 * Erase the image and continue booting from the primary slot.
1011 */
Michael Grand5047f032022-11-24 16:49:56 +01001012 fih_rc = FIH_NO_BOOTABLE_IMAGE;
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +00001013 goto out;
1014 }
1015 }
1016#endif
Michael Grand5047f032022-11-24 16:49:56 +01001017 BOOT_HOOK_CALL_FIH(boot_image_check_hook, FIH_BOOT_HOOK_REGULAR,
Andrzej Puzdrowskib8f39692021-07-02 15:05:37 +02001018 fih_rc, BOOT_CURR_IMG(state), slot);
Michael Grand5047f032022-11-24 16:49:56 +01001019 if (FIH_EQ(fih_rc, FIH_BOOT_HOOK_REGULAR))
Andrzej Puzdrowskib8f39692021-07-02 15:05:37 +02001020 {
1021 FIH_CALL(boot_image_check, fih_rc, state, hdr, fap, bs);
1022 }
Michael Grand5047f032022-11-24 16:49:56 +01001023 if (!boot_is_header_valid(hdr, fap) || FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
Tamas Banfe031092020-09-10 17:32:39 +02001024 if ((slot != BOOT_PRIMARY_SLOT) || ARE_SLOTS_EQUIVALENT()) {
Dominik Ermel260ae092021-04-23 05:38:45 +00001025 flash_area_erase(fap, 0, flash_area_get_size(fap));
David Vinczee574f2d2020-07-10 11:42:03 +02001026 /* Image is invalid, erase it to prevent further unnecessary
1027 * attempts to validate and boot it.
David Brownb38e0442017-02-24 13:57:12 -07001028 */
1029 }
David Brown098de832019-12-10 11:58:01 -07001030#if !defined(__BOOTSIM__)
David Vincze2d736ad2019-02-18 11:50:22 +01001031 BOOT_LOG_ERR("Image in the %s slot is not valid!",
1032 (slot == BOOT_PRIMARY_SLOT) ? "primary" : "secondary");
David Brown098de832019-12-10 11:58:01 -07001033#endif
Michael Grand5047f032022-11-24 16:49:56 +01001034 fih_rc = FIH_NO_BOOTABLE_IMAGE;
Fabio Utzig338a19f2018-12-03 08:37:08 -02001035 goto out;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001036 }
1037
Håkon Øye Amundsene829e9d2021-11-12 14:01:01 +00001038#if MCUBOOT_IMAGE_NUMBER > 1 && !defined(MCUBOOT_ENC_IMAGES) && defined(MCUBOOT_VERIFY_IMG_ADDRESS)
1039 /* Verify that the image in the secondary slot has a reset address
1040 * located in the primary slot. This is done to avoid users incorrectly
1041 * overwriting an application written to the incorrect slot.
1042 * This feature is only supported by ARM platforms.
1043 */
1044 if (area_id == FLASH_AREA_IMAGE_SECONDARY(BOOT_CURR_IMG(state))) {
1045 const struct flash_area *pri_fa = BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT);
1046 struct image_header *secondary_hdr = boot_img_hdr(state, slot);
1047 uint32_t reset_value = 0;
1048 uint32_t reset_addr = secondary_hdr->ih_hdr_size + sizeof(reset_value);
1049
1050 rc = flash_area_read(fap, reset_addr, &reset_value, sizeof(reset_value));
1051 if (rc != 0) {
Michael Grand5047f032022-11-24 16:49:56 +01001052 fih_rc = FIH_NO_BOOTABLE_IMAGE;
Håkon Øye Amundsene829e9d2021-11-12 14:01:01 +00001053 goto out;
1054 }
1055
1056 if (reset_value < pri_fa->fa_off || reset_value> (pri_fa->fa_off + pri_fa->fa_size)) {
1057 BOOT_LOG_ERR("Reset address of image in secondary slot is not in the primary slot");
1058 BOOT_LOG_ERR("Erasing image from secondary slot");
1059
1060 /* The vector table in the image located in the secondary
1061 * slot does not target the primary slot. This might
1062 * indicate that the image was loaded to the wrong slot.
1063 *
1064 * Erase the image and continue booting from the primary slot.
1065 */
1066 flash_area_erase(fap, 0, fap->fa_size);
Michael Grand5047f032022-11-24 16:49:56 +01001067 fih_rc = FIH_NO_BOOTABLE_IMAGE;
Håkon Øye Amundsene829e9d2021-11-12 14:01:01 +00001068 goto out;
1069 }
1070 }
1071#endif
1072
Fabio Utzig338a19f2018-12-03 08:37:08 -02001073out:
1074 flash_area_close(fap);
Raef Colese8fe6cf2020-05-26 13:07:40 +01001075
1076 FIH_RET(fih_rc);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001077}
1078
David Vinczec3084132020-02-18 14:50:47 +01001079#ifdef MCUBOOT_HW_ROLLBACK_PROT
1080/**
1081 * Updates the stored security counter value with the image's security counter
1082 * value which resides in the given slot, only if it's greater than the stored
1083 * value.
1084 *
1085 * @param image_index Index of the image to determine which security
1086 * counter to update.
1087 * @param slot Slot number of the image.
1088 * @param hdr Pointer to the image header structure of the image
1089 * that is currently stored in the given slot.
1090 *
1091 * @return 0 on success; nonzero on failure.
1092 */
1093static int
1094boot_update_security_counter(uint8_t image_index, int slot,
1095 struct image_header *hdr)
1096{
1097 const struct flash_area *fap = NULL;
1098 uint32_t img_security_cnt;
1099 int rc;
1100
1101 rc = flash_area_open(flash_area_id_from_multi_image_slot(image_index, slot),
1102 &fap);
1103 if (rc != 0) {
1104 rc = BOOT_EFLASH;
1105 goto done;
1106 }
1107
1108 rc = bootutil_get_img_security_cnt(hdr, fap, &img_security_cnt);
1109 if (rc != 0) {
1110 goto done;
1111 }
1112
1113 rc = boot_nv_security_counter_update(image_index, img_security_cnt);
1114 if (rc != 0) {
1115 goto done;
1116 }
1117
1118done:
1119 flash_area_close(fap);
1120 return rc;
1121}
1122#endif /* MCUBOOT_HW_ROLLBACK_PROT */
1123
Tamas Banfe031092020-09-10 17:32:39 +02001124#if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)
David Vinczee574f2d2020-07-10 11:42:03 +02001125/**
1126 * Determines which swap operation to perform, if any. If it is determined
1127 * that a swap operation is required, the image in the secondary slot is checked
1128 * for validity. If the image in the secondary slot is invalid, it is erased,
1129 * and a swap type of "none" is indicated.
1130 *
1131 * @return The type of swap to perform (BOOT_SWAP_TYPE...)
1132 */
1133static int
1134boot_validated_swap_type(struct boot_loader_state *state,
1135 struct boot_status *bs)
1136{
1137 int swap_type;
Michael Grand5047f032022-11-24 16:49:56 +01001138 FIH_DECLARE(fih_rc, FIH_FAILURE);
David Vinczee574f2d2020-07-10 11:42:03 +02001139
1140 swap_type = boot_swap_type_multi(BOOT_CURR_IMG(state));
1141 if (BOOT_IS_UPGRADE(swap_type)) {
1142 /* Boot loader wants to switch to the secondary slot.
1143 * Ensure image is valid.
1144 */
Raef Colese8fe6cf2020-05-26 13:07:40 +01001145 FIH_CALL(boot_validate_slot, fih_rc, state, BOOT_SECONDARY_SLOT, bs);
Michael Grand5047f032022-11-24 16:49:56 +01001146 if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
1147 if (FIH_EQ(fih_rc, FIH_NO_BOOTABLE_IMAGE)) {
Raef Colese8fe6cf2020-05-26 13:07:40 +01001148 swap_type = BOOT_SWAP_TYPE_NONE;
1149 } else {
1150 swap_type = BOOT_SWAP_TYPE_FAIL;
1151 }
David Vinczee574f2d2020-07-10 11:42:03 +02001152 }
1153 }
1154
1155 return swap_type;
1156}
David Brown94ed12c2021-05-26 16:28:14 -06001157#endif
David Vinczee574f2d2020-07-10 11:42:03 +02001158
Christopher Collins92ea77f2016-12-12 15:59:26 -08001159/**
Christopher Collins92ea77f2016-12-12 15:59:26 -08001160 * Erases a region of flash.
1161 *
Fabio Utzigba829042018-09-18 08:29:34 -03001162 * @param flash_area The flash_area containing the region to erase.
Christopher Collins92ea77f2016-12-12 15:59:26 -08001163 * @param off The offset within the flash area to start the
1164 * erase.
1165 * @param sz The number of bytes to erase.
1166 *
1167 * @return 0 on success; nonzero on failure.
1168 */
Fabio Utzig12d59162019-11-28 10:01:59 -03001169int
Fabio Utzigc28005b2019-09-10 12:18:29 -03001170boot_erase_region(const struct flash_area *fap, uint32_t off, uint32_t sz)
Christopher Collins92ea77f2016-12-12 15:59:26 -08001171{
Fabio Utzigba829042018-09-18 08:29:34 -03001172 return flash_area_erase(fap, off, sz);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001173}
1174
David Brown94ed12c2021-05-26 16:28:14 -06001175#if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)
Dominik Ermel256bc372022-12-07 15:51:31 +00001176
1177#if defined(MCUBOOT_ENC_IMAGES) || defined(MCUBOOT_SWAP_SAVE_ENCTLV)
1178/* Replacement for memset(p, 0, sizeof(*p) that does not get
1179 * optimized out.
1180 */
1181static void like_mbedtls_zeroize(void *p, size_t n)
1182{
1183 volatile unsigned char *v = (unsigned char *)p;
1184
1185 for (size_t i = 0; i < n; i++) {
1186 v[i] = 0;
1187 }
1188}
1189#endif
1190
Christopher Collins92ea77f2016-12-12 15:59:26 -08001191/**
1192 * Copies the contents of one flash region to another. You must erase the
1193 * destination region prior to calling this function.
1194 *
1195 * @param flash_area_id_src The ID of the source flash area.
1196 * @param flash_area_id_dst The ID of the destination flash area.
1197 * @param off_src The offset within the source flash area to
1198 * copy from.
1199 * @param off_dst The offset within the destination flash area to
1200 * copy to.
1201 * @param sz The number of bytes to copy.
1202 *
1203 * @return 0 on success; nonzero on failure.
1204 */
Fabio Utzig12d59162019-11-28 10:01:59 -03001205int
Fabio Utzigc28005b2019-09-10 12:18:29 -03001206boot_copy_region(struct boot_loader_state *state,
Fabio Utzig10ee6482019-08-01 12:04:52 -03001207 const struct flash_area *fap_src,
Fabio Utzigba829042018-09-18 08:29:34 -03001208 const struct flash_area *fap_dst,
Christopher Collins92ea77f2016-12-12 15:59:26 -08001209 uint32_t off_src, uint32_t off_dst, uint32_t sz)
1210{
Christopher Collins92ea77f2016-12-12 15:59:26 -08001211 uint32_t bytes_copied;
1212 int chunk_sz;
1213 int rc;
Fabio Utzigba829042018-09-18 08:29:34 -03001214#ifdef MCUBOOT_ENC_IMAGES
Dominik Ermel6fe259b2024-07-18 11:40:53 +00001215 uint32_t off = off_dst;
Fabio Utziga87cc7d2019-08-26 11:21:45 -03001216 uint32_t tlv_off;
Fabio Utzigba829042018-09-18 08:29:34 -03001217 size_t blk_off;
1218 struct image_header *hdr;
1219 uint16_t idx;
1220 uint32_t blk_sz;
Dominik Ermel6fe259b2024-07-18 11:40:53 +00001221 uint8_t image_index = BOOT_CURR_IMG(state);
Thomas Altenbach08d2d942024-04-25 15:29:21 +02001222 bool encrypted_src;
1223 bool encrypted_dst;
Dominik Ermel6fe259b2024-07-18 11:40:53 +00001224 /* Assuming the secondary slot is source; note that 0 here not only
1225 * means that primary slot is source, but also that there will be
1226 * encryption happening, if it is 1 then there is decryption from
1227 * secondary slot.
1228 */
Dominik Ermel3f112862024-07-17 14:43:05 +00001229 int source_slot = 1;
Dominik Ermel6fe259b2024-07-18 11:40:53 +00001230 /* In case of encryption enabled, we may have to do more work than
1231 * just copy bytes */
1232 bool only_copy = false;
1233#else
1234 (void)state;
Fabio Utzigba829042018-09-18 08:29:34 -03001235#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -08001236
Kristine Jassmann73c38c62021-02-03 16:56:14 +00001237 TARGET_STATIC uint8_t buf[BUF_SZ] __attribute__((aligned(4)));
Fabio Utzig10ee6482019-08-01 12:04:52 -03001238
Dominik Ermel6fe259b2024-07-18 11:40:53 +00001239#ifdef MCUBOOT_ENC_IMAGES
1240 encrypted_src = (flash_area_get_id(fap_src) != FLASH_AREA_IMAGE_PRIMARY(image_index));
1241 encrypted_dst = (flash_area_get_id(fap_dst) != FLASH_AREA_IMAGE_PRIMARY(image_index));
1242
1243 if (encrypted_src != encrypted_dst) {
1244 if (encrypted_dst) {
1245 /* Need encryption, metadata from the primary slot */
1246 hdr = boot_img_hdr(state, BOOT_PRIMARY_SLOT);
1247 source_slot = 0;
1248 } else {
1249 /* Need decryption, metadata from the secondary slot */
1250 hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT);
1251 source_slot = 1;
1252 }
1253 } else {
1254 /* In case when source and targe is the same area, this means that we
1255 * only have to copy bytes, no encryption or decryption.
1256 */
1257 only_copy = true;
1258 }
Fabio Utzig10ee6482019-08-01 12:04:52 -03001259#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -08001260
Christopher Collins92ea77f2016-12-12 15:59:26 -08001261 bytes_copied = 0;
1262 while (bytes_copied < sz) {
1263 if (sz - bytes_copied > sizeof buf) {
1264 chunk_sz = sizeof buf;
1265 } else {
1266 chunk_sz = sz - bytes_copied;
1267 }
1268
1269 rc = flash_area_read(fap_src, off_src + bytes_copied, buf, chunk_sz);
1270 if (rc != 0) {
Fabio Utzigba829042018-09-18 08:29:34 -03001271 return BOOT_EFLASH;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001272 }
1273
Fabio Utzigba829042018-09-18 08:29:34 -03001274#ifdef MCUBOOT_ENC_IMAGES
Dominik Ermel6fe259b2024-07-18 11:40:53 +00001275 /* If only copy, then does not matter if header indicates need for
1276 * encryptio/decryptio, we just copy data. */
1277 if (!only_copy && IS_ENCRYPTED(hdr)) {
1278 uint32_t abs_off = off + bytes_copied;
1279 if (abs_off < hdr->ih_hdr_size) {
1280 /* do not decrypt header */
1281 if (abs_off + chunk_sz > hdr->ih_hdr_size) {
1282 /* The lower part of the chunk contains header data */
1283 blk_off = 0;
1284 blk_sz = chunk_sz - (hdr->ih_hdr_size - abs_off);
1285 idx = hdr->ih_hdr_size - abs_off;
1286 } else {
1287 /* The chunk contains exclusively header data */
1288 blk_sz = 0; /* nothing to decrypt */
1289 }
Thomas Altenbach08d2d942024-04-25 15:29:21 +02001290 } else {
Dominik Ermel6fe259b2024-07-18 11:40:53 +00001291 idx = 0;
1292 blk_sz = chunk_sz;
1293 blk_off = (abs_off - hdr->ih_hdr_size) & 0xf;
Fabio Utzig74aef312019-11-28 11:05:34 -03001294 }
Thomas Altenbach08d2d942024-04-25 15:29:21 +02001295
Dominik Ermel6fe259b2024-07-18 11:40:53 +00001296 if (blk_sz > 0)
1297 {
1298 tlv_off = BOOT_TLV_OFF(hdr);
1299 if (abs_off + chunk_sz > tlv_off) {
1300 /* do not decrypt TLVs */
1301 if (abs_off >= tlv_off) {
1302 blk_sz = 0;
Andrzej Puzdrowskie38b0af2021-11-04 13:34:11 +01001303 } else {
Dominik Ermel6fe259b2024-07-18 11:40:53 +00001304 blk_sz = tlv_off - abs_off;
Andrzej Puzdrowskie38b0af2021-11-04 13:34:11 +01001305 }
Fabio Utzigba829042018-09-18 08:29:34 -03001306 }
Dominik Ermel6fe259b2024-07-18 11:40:53 +00001307 boot_encrypt(BOOT_CURR_ENC(state), source_slot,
1308 (abs_off + idx) - hdr->ih_hdr_size, blk_sz,
1309 blk_off, &buf[idx]);
Fabio Utzigba829042018-09-18 08:29:34 -03001310 }
1311 }
1312#endif
1313
Christopher Collins92ea77f2016-12-12 15:59:26 -08001314 rc = flash_area_write(fap_dst, off_dst + bytes_copied, buf, chunk_sz);
1315 if (rc != 0) {
Fabio Utzigba829042018-09-18 08:29:34 -03001316 return BOOT_EFLASH;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001317 }
1318
1319 bytes_copied += chunk_sz;
Fabio Utzig853657c2019-05-07 08:06:07 -03001320
1321 MCUBOOT_WATCHDOG_FEED();
Christopher Collins92ea77f2016-12-12 15:59:26 -08001322 }
1323
Fabio Utzigba829042018-09-18 08:29:34 -03001324 return 0;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001325}
1326
Christopher Collins92ea77f2016-12-12 15:59:26 -08001327/**
David Vincze2d736ad2019-02-18 11:50:22 +01001328 * Overwrite primary slot with the image contained in the secondary slot.
1329 * If a prior copy operation was interrupted by a system reset, this function
1330 * redos the copy.
Christopher Collins92ea77f2016-12-12 15:59:26 -08001331 *
1332 * @param bs The current boot status. This function reads
1333 * this struct to determine if it is resuming
1334 * an interrupted swap operation. This
1335 * function writes the updated status to this
1336 * function on return.
1337 *
1338 * @return 0 on success; nonzero on failure.
1339 */
Fabio Utzig338a19f2018-12-03 08:37:08 -02001340#if defined(MCUBOOT_OVERWRITE_ONLY) || defined(MCUBOOT_BOOTSTRAP)
David Brown17609d82017-05-05 09:41:34 -06001341static int
Fabio Utzig10ee6482019-08-01 12:04:52 -03001342boot_copy_image(struct boot_loader_state *state, struct boot_status *bs)
David Brown17609d82017-05-05 09:41:34 -06001343{
Marti Bolivard3269fd2017-06-12 16:31:12 -04001344 size_t sect_count;
1345 size_t sect;
David Brown17609d82017-05-05 09:41:34 -06001346 int rc;
Fabio Utzig13d9e352017-10-05 20:32:31 -03001347 size_t size;
Marti Bolivard3269fd2017-06-12 16:31:12 -04001348 size_t this_size;
Fabio Utzig13d9e352017-10-05 20:32:31 -03001349 size_t last_sector;
David Vincze2d736ad2019-02-18 11:50:22 +01001350 const struct flash_area *fap_primary_slot;
1351 const struct flash_area *fap_secondary_slot;
Fabio Utzigb0f04732019-07-31 09:49:19 -03001352 uint8_t image_index;
David Vincze2d736ad2019-02-18 11:50:22 +01001353
Fabio Utzigb4f88102020-10-04 10:16:24 -03001354#if defined(MCUBOOT_OVERWRITE_ONLY_FAST)
1355 uint32_t sector;
1356 uint32_t trailer_sz;
1357 uint32_t off;
1358 uint32_t sz;
1359#endif
1360
Fabio Utzigaaf767c2017-12-05 10:22:46 -02001361 (void)bs;
1362
Fabio Utzig13d9e352017-10-05 20:32:31 -03001363#if defined(MCUBOOT_OVERWRITE_ONLY_FAST)
1364 uint32_t src_size = 0;
Fabio Utzigd638b172019-08-09 10:38:05 -03001365 rc = boot_read_image_size(state, BOOT_SECONDARY_SLOT, &src_size);
Fabio Utzig13d9e352017-10-05 20:32:31 -03001366 assert(rc == 0);
1367#endif
David Brown17609d82017-05-05 09:41:34 -06001368
Fabio Utzigb0f04732019-07-31 09:49:19 -03001369 image_index = BOOT_CURR_IMG(state);
1370
Antonio de Angelisba5fb1c2022-10-11 10:10:37 +01001371 BOOT_LOG_INF("Image %d upgrade secondary slot -> primary slot", image_index);
1372 BOOT_LOG_INF("Erasing the primary slot");
1373
Fabio Utzigb0f04732019-07-31 09:49:19 -03001374 rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index),
1375 &fap_primary_slot);
Fabio Utzigba829042018-09-18 08:29:34 -03001376 assert (rc == 0);
1377
Fabio Utzigb0f04732019-07-31 09:49:19 -03001378 rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY(image_index),
1379 &fap_secondary_slot);
Fabio Utzigba829042018-09-18 08:29:34 -03001380 assert (rc == 0);
1381
Fabio Utzig10ee6482019-08-01 12:04:52 -03001382 sect_count = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT);
Fabio Utzig13d9e352017-10-05 20:32:31 -03001383 for (sect = 0, size = 0; sect < sect_count; sect++) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001384 this_size = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, sect);
Fabio Utzigc28005b2019-09-10 12:18:29 -03001385 rc = boot_erase_region(fap_primary_slot, size, this_size);
David Brown17609d82017-05-05 09:41:34 -06001386 assert(rc == 0);
1387
Fabio Utzig13d9e352017-10-05 20:32:31 -03001388#if defined(MCUBOOT_OVERWRITE_ONLY_FAST)
Fabio Utzigb4f88102020-10-04 10:16:24 -03001389 if ((size + this_size) >= src_size) {
1390 size += src_size - size;
1391 size += BOOT_WRITE_SZ(state) - (size % BOOT_WRITE_SZ(state));
Fabio Utzig13d9e352017-10-05 20:32:31 -03001392 break;
1393 }
1394#endif
Fabio Utzigb4f88102020-10-04 10:16:24 -03001395
1396 size += this_size;
David Brown17609d82017-05-05 09:41:34 -06001397 }
1398
Fabio Utzigb4f88102020-10-04 10:16:24 -03001399#if defined(MCUBOOT_OVERWRITE_ONLY_FAST)
1400 trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(state));
1401 sector = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT) - 1;
1402 sz = 0;
1403 do {
1404 sz += boot_img_sector_size(state, BOOT_PRIMARY_SLOT, sector);
1405 off = boot_img_sector_off(state, BOOT_PRIMARY_SLOT, sector);
1406 sector--;
1407 } while (sz < trailer_sz);
1408
1409 rc = boot_erase_region(fap_primary_slot, off, sz);
1410 assert(rc == 0);
1411#endif
1412
Fabio Utzigba829042018-09-18 08:29:34 -03001413#ifdef MCUBOOT_ENC_IMAGES
Fabio Utzig10ee6482019-08-01 12:04:52 -03001414 if (IS_ENCRYPTED(boot_img_hdr(state, BOOT_SECONDARY_SLOT))) {
Dominik Ermel7f9ac972024-07-12 19:21:40 +00001415 rc = boot_enc_load(BOOT_CURR_ENC(state), BOOT_SECONDARY_SLOT,
Fabio Utzig10ee6482019-08-01 12:04:52 -03001416 boot_img_hdr(state, BOOT_SECONDARY_SLOT),
Fabio Utzig4741c452019-12-19 15:32:41 -03001417 fap_secondary_slot, bs);
David Vincze2d736ad2019-02-18 11:50:22 +01001418
Fabio Utzigba829042018-09-18 08:29:34 -03001419 if (rc < 0) {
1420 return BOOT_EBADIMAGE;
1421 }
Fabio Utzig4741c452019-12-19 15:32:41 -03001422 if (rc == 0 && boot_enc_set_key(BOOT_CURR_ENC(state), 1, bs)) {
Fabio Utzigba829042018-09-18 08:29:34 -03001423 return BOOT_EBADIMAGE;
1424 }
1425 }
1426#endif
1427
Antonio de Angelis48547002023-04-14 09:47:09 +01001428 BOOT_LOG_INF("Image %d copying the secondary slot to the primary slot: 0x%zx bytes",
1429 image_index, size);
Fabio Utzigc28005b2019-09-10 12:18:29 -03001430 rc = boot_copy_region(state, fap_secondary_slot, fap_primary_slot, 0, 0, size);
Fabio Utzigb4f88102020-10-04 10:16:24 -03001431 if (rc != 0) {
1432 return rc;
1433 }
1434
1435#if defined(MCUBOOT_OVERWRITE_ONLY_FAST)
1436 rc = boot_write_magic(fap_primary_slot);
1437 if (rc != 0) {
1438 return rc;
1439 }
1440#endif
David Brown17609d82017-05-05 09:41:34 -06001441
Andrzej Puzdrowskib8f39692021-07-02 15:05:37 +02001442 rc = BOOT_HOOK_CALL(boot_copy_region_post_hook, 0, BOOT_CURR_IMG(state),
1443 BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT), size);
1444 if (rc != 0) {
1445 return rc;
1446 }
1447
David Vinczec3084132020-02-18 14:50:47 +01001448#ifdef MCUBOOT_HW_ROLLBACK_PROT
1449 /* Update the stored security counter with the new image's security counter
1450 * value. Both slots hold the new image at this point, but the secondary
1451 * slot's image header must be passed since the image headers in the
1452 * boot_data structure have not been updated yet.
1453 */
1454 rc = boot_update_security_counter(BOOT_CURR_IMG(state), BOOT_PRIMARY_SLOT,
1455 boot_img_hdr(state, BOOT_SECONDARY_SLOT));
1456 if (rc != 0) {
1457 BOOT_LOG_ERR("Security counter update failed after image upgrade.");
1458 return rc;
1459 }
1460#endif /* MCUBOOT_HW_ROLLBACK_PROT */
1461
Petr Buchtac5a528b2024-02-24 08:10:38 +01001462#ifndef MCUBOOT_OVERWRITE_ONLY_KEEP_BACKUP
Fabio Utzig13d9e352017-10-05 20:32:31 -03001463 /*
1464 * Erases header and trailer. The trailer is erased because when a new
1465 * image is written without a trailer as is the case when using newt, the
1466 * trailer that was left might trigger a new upgrade.
1467 */
Christopher Collins2c88e692019-05-22 15:10:14 -07001468 BOOT_LOG_DBG("erasing secondary header");
Fabio Utzigc28005b2019-09-10 12:18:29 -03001469 rc = boot_erase_region(fap_secondary_slot,
Fabio Utzig10ee6482019-08-01 12:04:52 -03001470 boot_img_sector_off(state, BOOT_SECONDARY_SLOT, 0),
1471 boot_img_sector_size(state, BOOT_SECONDARY_SLOT, 0));
David Brown17609d82017-05-05 09:41:34 -06001472 assert(rc == 0);
Petr Buchtac5a528b2024-02-24 08:10:38 +01001473#endif
1474
Fabio Utzig10ee6482019-08-01 12:04:52 -03001475 last_sector = boot_img_num_sectors(state, BOOT_SECONDARY_SLOT) - 1;
Christopher Collins2c88e692019-05-22 15:10:14 -07001476 BOOT_LOG_DBG("erasing secondary trailer");
Fabio Utzigc28005b2019-09-10 12:18:29 -03001477 rc = boot_erase_region(fap_secondary_slot,
Fabio Utzig10ee6482019-08-01 12:04:52 -03001478 boot_img_sector_off(state, BOOT_SECONDARY_SLOT,
1479 last_sector),
1480 boot_img_sector_size(state, BOOT_SECONDARY_SLOT,
1481 last_sector));
Fabio Utzig13d9e352017-10-05 20:32:31 -03001482 assert(rc == 0);
1483
David Vincze2d736ad2019-02-18 11:50:22 +01001484 flash_area_close(fap_primary_slot);
1485 flash_area_close(fap_secondary_slot);
Fabio Utzigba829042018-09-18 08:29:34 -03001486
David Vincze2d736ad2019-02-18 11:50:22 +01001487 /* TODO: Perhaps verify the primary slot's signature again? */
David Brown17609d82017-05-05 09:41:34 -06001488
1489 return 0;
1490}
Fabio Utzig338a19f2018-12-03 08:37:08 -02001491#endif
Fabio Utzigba829042018-09-18 08:29:34 -03001492
Christopher Collinsa1c12042019-05-23 14:00:28 -07001493#if !defined(MCUBOOT_OVERWRITE_ONLY)
Fabio Utzigba829042018-09-18 08:29:34 -03001494/**
1495 * Swaps the two images in flash. If a prior copy operation was interrupted
1496 * by a system reset, this function completes that operation.
1497 *
1498 * @param bs The current boot status. This function reads
1499 * this struct to determine if it is resuming
1500 * an interrupted swap operation. This
1501 * function writes the updated status to this
1502 * function on return.
1503 *
1504 * @return 0 on success; nonzero on failure.
1505 */
Christopher Collins92ea77f2016-12-12 15:59:26 -08001506static int
Fabio Utzig10ee6482019-08-01 12:04:52 -03001507boot_swap_image(struct boot_loader_state *state, struct boot_status *bs)
Christopher Collins92ea77f2016-12-12 15:59:26 -08001508{
Fabio Utzig2473ac02017-05-02 12:45:02 -03001509 struct image_header *hdr;
Fabio Utzigba829042018-09-18 08:29:34 -03001510 const struct flash_area *fap;
Dominik Ermel472d4c72023-02-10 13:29:58 +00001511#ifdef MCUBOOT_ENC_IMAGES
Fabio Utzigba829042018-09-18 08:29:34 -03001512 uint8_t slot;
1513 uint8_t i;
Fabio Utzigba829042018-09-18 08:29:34 -03001514#endif
Fabio Utzig2473ac02017-05-02 12:45:02 -03001515 uint32_t size;
1516 uint32_t copy_size;
Fabio Utzigb0f04732019-07-31 09:49:19 -03001517 uint8_t image_index;
Fabio Utzig2473ac02017-05-02 12:45:02 -03001518 int rc;
1519
1520 /* FIXME: just do this if asked by user? */
1521
1522 size = copy_size = 0;
Fabio Utzig10ee6482019-08-01 12:04:52 -03001523 image_index = BOOT_CURR_IMG(state);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001524
Fabio Utzig12d59162019-11-28 10:01:59 -03001525 if (boot_status_is_reset(bs)) {
Fabio Utzig46490722017-09-04 15:34:32 -03001526 /*
1527 * No swap ever happened, so need to find the largest image which
1528 * will be used to determine the amount of sectors to swap.
1529 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001530 hdr = boot_img_hdr(state, BOOT_PRIMARY_SLOT);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001531 if (hdr->ih_magic == IMAGE_MAGIC) {
Fabio Utzigd638b172019-08-09 10:38:05 -03001532 rc = boot_read_image_size(state, BOOT_PRIMARY_SLOT, &copy_size);
David Brownf5b33d82017-09-01 10:58:27 -06001533 assert(rc == 0);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001534 }
Fabio Utzig2473ac02017-05-02 12:45:02 -03001535
Fabio Utzigba829042018-09-18 08:29:34 -03001536#ifdef MCUBOOT_ENC_IMAGES
Fabio Utzig2fc80df2018-12-14 06:47:38 -02001537 if (IS_ENCRYPTED(hdr)) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001538 fap = BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT);
Dominik Ermel7f9ac972024-07-12 19:21:40 +00001539 rc = boot_enc_load(BOOT_CURR_ENC(state), 0, hdr, fap, bs);
Fabio Utzigba829042018-09-18 08:29:34 -03001540 assert(rc >= 0);
1541
1542 if (rc == 0) {
Fabio Utzig4741c452019-12-19 15:32:41 -03001543 rc = boot_enc_set_key(BOOT_CURR_ENC(state), 0, bs);
Fabio Utzigba829042018-09-18 08:29:34 -03001544 assert(rc == 0);
1545 } else {
1546 rc = 0;
1547 }
1548 } else {
Kristine Jassmann73c38c62021-02-03 16:56:14 +00001549 memset(bs->enckey[0], 0xff, BOOT_ENC_KEY_ALIGN_SIZE);
Fabio Utzigba829042018-09-18 08:29:34 -03001550 }
1551#endif
1552
Fabio Utzig10ee6482019-08-01 12:04:52 -03001553 hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT);
Fabio Utzig46490722017-09-04 15:34:32 -03001554 if (hdr->ih_magic == IMAGE_MAGIC) {
Fabio Utzigd638b172019-08-09 10:38:05 -03001555 rc = boot_read_image_size(state, BOOT_SECONDARY_SLOT, &size);
Fabio Utzig46490722017-09-04 15:34:32 -03001556 assert(rc == 0);
1557 }
1558
Fabio Utzigba829042018-09-18 08:29:34 -03001559#ifdef MCUBOOT_ENC_IMAGES
Fabio Utzig10ee6482019-08-01 12:04:52 -03001560 hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT);
Fabio Utzig2fc80df2018-12-14 06:47:38 -02001561 if (IS_ENCRYPTED(hdr)) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001562 fap = BOOT_IMG_AREA(state, BOOT_SECONDARY_SLOT);
Dominik Ermel7f9ac972024-07-12 19:21:40 +00001563 rc = boot_enc_load(BOOT_CURR_ENC(state), 1, hdr, fap, bs);
Fabio Utzigba829042018-09-18 08:29:34 -03001564 assert(rc >= 0);
1565
1566 if (rc == 0) {
Fabio Utzig4741c452019-12-19 15:32:41 -03001567 rc = boot_enc_set_key(BOOT_CURR_ENC(state), 1, bs);
Fabio Utzigba829042018-09-18 08:29:34 -03001568 assert(rc == 0);
1569 } else {
1570 rc = 0;
1571 }
1572 } else {
Kristine Jassmann73c38c62021-02-03 16:56:14 +00001573 memset(bs->enckey[1], 0xff, BOOT_ENC_KEY_ALIGN_SIZE);
Fabio Utzigba829042018-09-18 08:29:34 -03001574 }
1575#endif
1576
Fabio Utzig46490722017-09-04 15:34:32 -03001577 if (size > copy_size) {
1578 copy_size = size;
1579 }
1580
1581 bs->swap_size = copy_size;
1582 } else {
1583 /*
1584 * If a swap was under way, the swap_size should already be present
1585 * in the trailer...
1586 */
Dominik Ermel472d4c72023-02-10 13:29:58 +00001587
1588 rc = boot_find_status(image_index, &fap);
1589 assert(fap != NULL);
1590 rc = boot_read_swap_size(fap, &bs->swap_size);
Fabio Utzig46490722017-09-04 15:34:32 -03001591 assert(rc == 0);
1592
1593 copy_size = bs->swap_size;
Fabio Utzigba829042018-09-18 08:29:34 -03001594
1595#ifdef MCUBOOT_ENC_IMAGES
Fabio Utzig4741c452019-12-19 15:32:41 -03001596 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
Dominik Ermel472d4c72023-02-10 13:29:58 +00001597 rc = boot_read_enc_key(fap, slot, bs);
Fabio Utzigba829042018-09-18 08:29:34 -03001598 assert(rc == 0);
1599
1600 for (i = 0; i < BOOT_ENC_KEY_SIZE; i++) {
Fabio Utzig1c7d9592018-12-03 10:35:56 -02001601 if (bs->enckey[slot][i] != 0xff) {
Fabio Utzigba829042018-09-18 08:29:34 -03001602 break;
1603 }
1604 }
1605
Dominik Ermel7e3a1ce2024-07-12 17:19:17 +00001606 boot_enc_init(BOOT_CURR_ENC(state), slot);
1607
Fabio Utzigba829042018-09-18 08:29:34 -03001608 if (i != BOOT_ENC_KEY_SIZE) {
Fabio Utzig4741c452019-12-19 15:32:41 -03001609 boot_enc_set_key(BOOT_CURR_ENC(state), slot, bs);
Fabio Utzigba829042018-09-18 08:29:34 -03001610 }
1611 }
1612#endif
Dominik Ermel472d4c72023-02-10 13:29:58 +00001613 flash_area_close(fap);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001614 }
1615
Fabio Utzig12d59162019-11-28 10:01:59 -03001616 swap_run(state, bs, copy_size);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001617
David Vincze2d736ad2019-02-18 11:50:22 +01001618#ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT
Fabio Utzig12d59162019-11-28 10:01:59 -03001619 extern int boot_status_fails;
Fabio Utziga0e1cce2017-11-23 20:04:01 -02001620 if (boot_status_fails > 0) {
Christopher Collins2c88e692019-05-22 15:10:14 -07001621 BOOT_LOG_WRN("%d status write fails performing the swap",
1622 boot_status_fails);
Fabio Utziga0e1cce2017-11-23 20:04:01 -02001623 }
1624#endif
Sigvart Hovland3fd4cd42022-09-09 13:21:18 +02001625 rc = BOOT_HOOK_CALL(boot_copy_region_post_hook, 0, BOOT_CURR_IMG(state),
1626 BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT), size);
Fabio Utziga0e1cce2017-11-23 20:04:01 -02001627
Christopher Collins92ea77f2016-12-12 15:59:26 -08001628 return 0;
1629}
David Brown17609d82017-05-05 09:41:34 -06001630#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -08001631
David Vinczee32483f2019-06-13 10:46:24 +02001632
Christopher Collins92ea77f2016-12-12 15:59:26 -08001633/**
David Vinczeba3bd602019-06-17 16:01:43 +02001634 * Performs a clean (not aborted) image update.
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001635 *
David Vinczeba3bd602019-06-17 16:01:43 +02001636 * @param bs The current boot status.
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001637 *
1638 * @return 0 on success; nonzero on failure.
1639 */
1640static int
Fabio Utzig10ee6482019-08-01 12:04:52 -03001641boot_perform_update(struct boot_loader_state *state, struct boot_status *bs)
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001642{
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001643 int rc;
Fabio Utzig10ee6482019-08-01 12:04:52 -03001644#ifndef MCUBOOT_OVERWRITE_ONLY
1645 uint8_t swap_type;
1646#endif
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001647
David Vinczeba3bd602019-06-17 16:01:43 +02001648 /* At this point there are no aborted swaps. */
1649#if defined(MCUBOOT_OVERWRITE_ONLY)
Fabio Utzig10ee6482019-08-01 12:04:52 -03001650 rc = boot_copy_image(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02001651#elif defined(MCUBOOT_BOOTSTRAP)
1652 /* Check if the image update was triggered by a bad image in the
1653 * primary slot (the validity of the image in the secondary slot had
1654 * already been checked).
1655 */
Michael Grand5047f032022-11-24 16:49:56 +01001656 FIH_DECLARE(fih_rc, FIH_FAILURE);
Raef Colese8fe6cf2020-05-26 13:07:40 +01001657 rc = boot_check_header_erased(state, BOOT_PRIMARY_SLOT);
1658 FIH_CALL(boot_validate_slot, fih_rc, state, BOOT_PRIMARY_SLOT, bs);
Michael Grand5047f032022-11-24 16:49:56 +01001659 if (rc == 0 || FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001660 rc = boot_copy_image(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02001661 } else {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001662 rc = boot_swap_image(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02001663 }
1664#else
Fabio Utzig10ee6482019-08-01 12:04:52 -03001665 rc = boot_swap_image(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02001666#endif
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001667 assert(rc == 0);
David Vinczeba3bd602019-06-17 16:01:43 +02001668
1669#ifndef MCUBOOT_OVERWRITE_ONLY
1670 /* The following state needs image_ok be explicitly set after the
1671 * swap was finished to avoid a new revert.
1672 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001673 swap_type = BOOT_SWAP_TYPE(state);
1674 if (swap_type == BOOT_SWAP_TYPE_REVERT ||
1675 swap_type == BOOT_SWAP_TYPE_PERM) {
Fabio Utzig12d59162019-11-28 10:01:59 -03001676 rc = swap_set_image_ok(BOOT_CURR_IMG(state));
David Vinczeba3bd602019-06-17 16:01:43 +02001677 if (rc != 0) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001678 BOOT_SWAP_TYPE(state) = swap_type = BOOT_SWAP_TYPE_PANIC;
David Vinczeba3bd602019-06-17 16:01:43 +02001679 }
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001680 }
1681
David Vinczec3084132020-02-18 14:50:47 +01001682#ifdef MCUBOOT_HW_ROLLBACK_PROT
1683 if (swap_type == BOOT_SWAP_TYPE_PERM) {
1684 /* Update the stored security counter with the new image's security
1685 * counter value. The primary slot holds the new image at this point,
1686 * but the secondary slot's image header must be passed since image
1687 * headers in the boot_data structure have not been updated yet.
1688 *
1689 * In case of a permanent image swap mcuboot will never attempt to
1690 * revert the images on the next reboot. Therefore, the security
1691 * counter must be increased right after the image upgrade.
1692 */
1693 rc = boot_update_security_counter(
1694 BOOT_CURR_IMG(state),
1695 BOOT_PRIMARY_SLOT,
1696 boot_img_hdr(state, BOOT_SECONDARY_SLOT));
1697 if (rc != 0) {
1698 BOOT_LOG_ERR("Security counter update failed after "
1699 "image upgrade.");
1700 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
1701 }
1702 }
1703#endif /* MCUBOOT_HW_ROLLBACK_PROT */
1704
Fabio Utzige575b0b2019-09-11 12:34:23 -03001705 if (BOOT_IS_UPGRADE(swap_type)) {
Fabio Utzig12d59162019-11-28 10:01:59 -03001706 rc = swap_set_copy_done(BOOT_CURR_IMG(state));
David Vinczeba3bd602019-06-17 16:01:43 +02001707 if (rc != 0) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001708 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
Christopher Collinsa1c12042019-05-23 14:00:28 -07001709 }
David Vinczeba3bd602019-06-17 16:01:43 +02001710 }
1711#endif /* !MCUBOOT_OVERWRITE_ONLY */
Fabio Utzig338a19f2018-12-03 08:37:08 -02001712
David Vinczeba3bd602019-06-17 16:01:43 +02001713 return rc;
1714}
1715
1716/**
1717 * Completes a previously aborted image swap.
1718 *
1719 * @param bs The current boot status.
1720 *
1721 * @return 0 on success; nonzero on failure.
1722 */
1723#if !defined(MCUBOOT_OVERWRITE_ONLY)
1724static int
Fabio Utzig10ee6482019-08-01 12:04:52 -03001725boot_complete_partial_swap(struct boot_loader_state *state,
1726 struct boot_status *bs)
David Vinczeba3bd602019-06-17 16:01:43 +02001727{
1728 int rc;
1729
1730 /* Determine the type of swap operation being resumed from the
1731 * `swap-type` trailer field.
1732 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001733 rc = boot_swap_image(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02001734 assert(rc == 0);
1735
Fabio Utzig10ee6482019-08-01 12:04:52 -03001736 BOOT_SWAP_TYPE(state) = bs->swap_type;
David Vinczeba3bd602019-06-17 16:01:43 +02001737
1738 /* The following states need image_ok be explicitly set after the
1739 * swap was finished to avoid a new revert.
1740 */
1741 if (bs->swap_type == BOOT_SWAP_TYPE_REVERT ||
1742 bs->swap_type == BOOT_SWAP_TYPE_PERM) {
Fabio Utzig12d59162019-11-28 10:01:59 -03001743 rc = swap_set_image_ok(BOOT_CURR_IMG(state));
David Vinczeba3bd602019-06-17 16:01:43 +02001744 if (rc != 0) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001745 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
David Vinczeba3bd602019-06-17 16:01:43 +02001746 }
1747 }
1748
Fabio Utzige575b0b2019-09-11 12:34:23 -03001749 if (BOOT_IS_UPGRADE(bs->swap_type)) {
Fabio Utzig12d59162019-11-28 10:01:59 -03001750 rc = swap_set_copy_done(BOOT_CURR_IMG(state));
David Vinczeba3bd602019-06-17 16:01:43 +02001751 if (rc != 0) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001752 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
David Vinczeba3bd602019-06-17 16:01:43 +02001753 }
1754 }
1755
Fabio Utzig10ee6482019-08-01 12:04:52 -03001756 if (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_PANIC) {
David Vinczeba3bd602019-06-17 16:01:43 +02001757 BOOT_LOG_ERR("panic!");
1758 assert(0);
1759
1760 /* Loop forever... */
1761 while (1) {}
1762 }
1763
1764 return rc;
1765}
1766#endif /* !MCUBOOT_OVERWRITE_ONLY */
1767
1768#if (BOOT_IMAGE_NUMBER > 1)
1769/**
1770 * Review the validity of previously determined swap types of other images.
1771 *
1772 * @param aborted_swap The current image upgrade is a
1773 * partial/aborted swap.
1774 */
1775static void
Fabio Utzig10ee6482019-08-01 12:04:52 -03001776boot_review_image_swap_types(struct boot_loader_state *state,
1777 bool aborted_swap)
David Vinczeba3bd602019-06-17 16:01:43 +02001778{
1779 /* In that case if we rebooted in the middle of an image upgrade process, we
1780 * must review the validity of swap types, that were previously determined
1781 * for other images. The image_ok flag had not been set before the reboot
1782 * for any of the updated images (only the copy_done flag) and thus falsely
1783 * the REVERT swap type has been determined for the previous images that had
1784 * been updated before the reboot.
1785 *
1786 * There are two separate scenarios that we have to deal with:
1787 *
1788 * 1. The reboot has happened during swapping an image:
1789 * The current image upgrade has been determined as a
1790 * partial/aborted swap.
1791 * 2. The reboot has happened between two separate image upgrades:
1792 * In this scenario we must check the swap type of the current image.
1793 * In those cases if it is NONE or REVERT we cannot certainly determine
1794 * the fact of a reboot. In a consistent state images must move in the
1795 * same direction or stay in place, e.g. in practice REVERT and TEST
1796 * swap types cannot be present at the same time. If the swap type of
1797 * the current image is either TEST, PERM or FAIL we must review the
1798 * already determined swap types of other images and set each false
1799 * REVERT swap types to NONE (these images had been successfully
1800 * updated before the system rebooted between two separate image
1801 * upgrades).
1802 */
1803
Fabio Utzig10ee6482019-08-01 12:04:52 -03001804 if (BOOT_CURR_IMG(state) == 0) {
David Vinczeba3bd602019-06-17 16:01:43 +02001805 /* Nothing to do */
1806 return;
1807 }
1808
1809 if (!aborted_swap) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001810 if ((BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_NONE) ||
1811 (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_REVERT)) {
David Vinczeba3bd602019-06-17 16:01:43 +02001812 /* Nothing to do */
1813 return;
1814 }
1815 }
1816
Fabio Utzig10ee6482019-08-01 12:04:52 -03001817 for (uint8_t i = 0; i < BOOT_CURR_IMG(state); i++) {
1818 if (state->swap_type[i] == BOOT_SWAP_TYPE_REVERT) {
1819 state->swap_type[i] = BOOT_SWAP_TYPE_NONE;
David Vinczeba3bd602019-06-17 16:01:43 +02001820 }
1821 }
1822}
1823#endif
1824
1825/**
1826 * Prepare image to be updated if required.
1827 *
1828 * Prepare image to be updated if required with completing an image swap
1829 * operation if one was aborted and/or determining the type of the
1830 * swap operation. In case of any error set the swap type to NONE.
1831 *
Fabio Utzig10ee6482019-08-01 12:04:52 -03001832 * @param state TODO
David Vinczeba3bd602019-06-17 16:01:43 +02001833 * @param bs Pointer where the read and possibly updated
1834 * boot status can be written to.
1835 */
1836static void
Fabio Utzig10ee6482019-08-01 12:04:52 -03001837boot_prepare_image_for_update(struct boot_loader_state *state,
1838 struct boot_status *bs)
David Vinczeba3bd602019-06-17 16:01:43 +02001839{
1840 int rc;
Michael Grand5047f032022-11-24 16:49:56 +01001841 FIH_DECLARE(fih_rc, FIH_FAILURE);
David Vinczeba3bd602019-06-17 16:01:43 +02001842
Jamie McCrae4f1ab9e2024-07-26 12:29:24 +01001843#if defined(MCUBOOT_DATA_SHARING)
1844 int max_size;
1845#endif
1846
David Vinczeba3bd602019-06-17 16:01:43 +02001847 /* Determine the sector layout of the image slots and scratch area. */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001848 rc = boot_read_sectors(state);
David Vinczeba3bd602019-06-17 16:01:43 +02001849 if (rc != 0) {
1850 BOOT_LOG_WRN("Failed reading sectors; BOOT_MAX_IMG_SECTORS=%d"
1851 " - too small?", BOOT_MAX_IMG_SECTORS);
1852 /* Unable to determine sector layout, continue with next image
1853 * if there is one.
1854 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001855 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
Andrzej Puzdrowski54b4ad92021-06-22 13:21:22 +02001856 if (rc == BOOT_EFLASH)
1857 {
1858 /* Only return on error from the primary image flash */
1859 return;
1860 }
David Vinczeba3bd602019-06-17 16:01:43 +02001861 }
1862
1863 /* Attempt to read an image header from each slot. */
Fabio Utzig12d59162019-11-28 10:01:59 -03001864 rc = boot_read_image_headers(state, false, NULL);
David Vinczeba3bd602019-06-17 16:01:43 +02001865 if (rc != 0) {
1866 /* Continue with next image if there is one. */
Fabio Utzigb0f04732019-07-31 09:49:19 -03001867 BOOT_LOG_WRN("Failed reading image headers; Image=%u",
Fabio Utzig10ee6482019-08-01 12:04:52 -03001868 BOOT_CURR_IMG(state));
1869 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
David Vinczeba3bd602019-06-17 16:01:43 +02001870 return;
1871 }
1872
Jamie McCrae4f1ab9e2024-07-26 12:29:24 +01001873#if defined(MCUBOOT_DATA_SHARING)
1874 /* Fetch information on maximum sizes for later usage, if needed */
1875 max_size = app_max_size(state);
1876
1877 if (max_size > 0) {
1878 image_max_sizes[BOOT_CURR_IMG(state)].calculated = true;
1879 image_max_sizes[BOOT_CURR_IMG(state)].max_size = max_size;
1880 }
1881#endif
1882
David Vinczeba3bd602019-06-17 16:01:43 +02001883 /* If the current image's slots aren't compatible, no swap is possible.
1884 * Just boot into primary slot.
1885 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001886 if (boot_slots_compatible(state)) {
Fabio Utzig12d59162019-11-28 10:01:59 -03001887 boot_status_reset(bs);
1888
1889#ifndef MCUBOOT_OVERWRITE_ONLY
1890 rc = swap_read_status(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02001891 if (rc != 0) {
1892 BOOT_LOG_WRN("Failed reading boot status; Image=%u",
Fabio Utzig10ee6482019-08-01 12:04:52 -03001893 BOOT_CURR_IMG(state));
David Vinczeba3bd602019-06-17 16:01:43 +02001894 /* Continue with next image if there is one. */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001895 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
David Vinczeba3bd602019-06-17 16:01:43 +02001896 return;
1897 }
Fabio Utzig12d59162019-11-28 10:01:59 -03001898#endif
David Vinczeba3bd602019-06-17 16:01:43 +02001899
Thomas Altenbachf515bb12024-04-26 18:31:57 +02001900#if defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SWAP_USING_MOVE)
Fabio Utzig74aef312019-11-28 11:05:34 -03001901 /*
1902 * Must re-read image headers because the boot status might
1903 * have been updated in the previous function call.
1904 */
1905 rc = boot_read_image_headers(state, !boot_status_is_reset(bs), bs);
Fabio Utzig32afe852020-10-04 10:36:02 -03001906#ifdef MCUBOOT_BOOTSTRAP
1907 /* When bootstrapping it's OK to not have image magic in the primary slot */
1908 if (rc != 0 && (BOOT_CURR_IMG(state) != BOOT_PRIMARY_SLOT ||
1909 boot_check_header_erased(state, BOOT_PRIMARY_SLOT) != 0)) {
1910#else
Fabio Utzig74aef312019-11-28 11:05:34 -03001911 if (rc != 0) {
Fabio Utzig32afe852020-10-04 10:36:02 -03001912#endif
1913
Fabio Utzig74aef312019-11-28 11:05:34 -03001914 /* Continue with next image if there is one. */
1915 BOOT_LOG_WRN("Failed reading image headers; Image=%u",
1916 BOOT_CURR_IMG(state));
1917 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
1918 return;
1919 }
1920#endif
1921
David Vinczeba3bd602019-06-17 16:01:43 +02001922 /* Determine if we rebooted in the middle of an image swap
1923 * operation. If a partial swap was detected, complete it.
1924 */
Fabio Utzig12d59162019-11-28 10:01:59 -03001925 if (!boot_status_is_reset(bs)) {
David Vinczeba3bd602019-06-17 16:01:43 +02001926
1927#if (BOOT_IMAGE_NUMBER > 1)
Fabio Utzig10ee6482019-08-01 12:04:52 -03001928 boot_review_image_swap_types(state, true);
David Vinczeba3bd602019-06-17 16:01:43 +02001929#endif
1930
1931#ifdef MCUBOOT_OVERWRITE_ONLY
1932 /* Should never arrive here, overwrite-only mode has
1933 * no swap state.
1934 */
1935 assert(0);
1936#else
1937 /* Determine the type of swap operation being resumed from the
1938 * `swap-type` trailer field.
1939 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001940 rc = boot_complete_partial_swap(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02001941 assert(rc == 0);
1942#endif
1943 /* Attempt to read an image header from each slot. Ensure that
1944 * image headers in slots are aligned with headers in boot_data.
1945 */
Fabio Utzig12d59162019-11-28 10:01:59 -03001946 rc = boot_read_image_headers(state, false, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02001947 assert(rc == 0);
1948
1949 /* Swap has finished set to NONE */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001950 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
David Vinczeba3bd602019-06-17 16:01:43 +02001951 } else {
1952 /* There was no partial swap, determine swap type. */
1953 if (bs->swap_type == BOOT_SWAP_TYPE_NONE) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001954 BOOT_SWAP_TYPE(state) = boot_validated_swap_type(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02001955 } else {
Raef Colese8fe6cf2020-05-26 13:07:40 +01001956 FIH_CALL(boot_validate_slot, fih_rc,
1957 state, BOOT_SECONDARY_SLOT, bs);
Michael Grand5047f032022-11-24 16:49:56 +01001958 if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
Raef Colese8fe6cf2020-05-26 13:07:40 +01001959 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_FAIL;
1960 } else {
1961 BOOT_SWAP_TYPE(state) = bs->swap_type;
1962 }
David Vinczeba3bd602019-06-17 16:01:43 +02001963 }
1964
1965#if (BOOT_IMAGE_NUMBER > 1)
Fabio Utzig10ee6482019-08-01 12:04:52 -03001966 boot_review_image_swap_types(state, false);
David Vinczeba3bd602019-06-17 16:01:43 +02001967#endif
1968
1969#ifdef MCUBOOT_BOOTSTRAP
Fabio Utzig10ee6482019-08-01 12:04:52 -03001970 if (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_NONE) {
David Vinczeba3bd602019-06-17 16:01:43 +02001971 /* Header checks are done first because they are
1972 * inexpensive. Since overwrite-only copies starting from
1973 * offset 0, if interrupted, it might leave a valid header
1974 * magic, so also run validation on the primary slot to be
1975 * sure it's not OK.
1976 */
Raef Colese8fe6cf2020-05-26 13:07:40 +01001977 rc = boot_check_header_erased(state, BOOT_PRIMARY_SLOT);
1978 FIH_CALL(boot_validate_slot, fih_rc,
1979 state, BOOT_PRIMARY_SLOT, bs);
1980
Michael Grand5047f032022-11-24 16:49:56 +01001981 if (rc == 0 || FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
Raef Colese8fe6cf2020-05-26 13:07:40 +01001982
Fabio Utzig3d77c952020-10-04 10:23:17 -03001983 rc = (boot_img_hdr(state, BOOT_SECONDARY_SLOT)->ih_magic == IMAGE_MAGIC) ? 1: 0;
Raef Colese8fe6cf2020-05-26 13:07:40 +01001984 FIH_CALL(boot_validate_slot, fih_rc,
1985 state, BOOT_SECONDARY_SLOT, bs);
1986
Michael Grand5047f032022-11-24 16:49:56 +01001987 if (rc == 1 && FIH_EQ(fih_rc, FIH_SUCCESS)) {
David Vinczeba3bd602019-06-17 16:01:43 +02001988 /* Set swap type to REVERT to overwrite the primary
1989 * slot with the image contained in secondary slot
1990 * and to trigger the explicit setting of the
1991 * image_ok flag.
1992 */
Fabio Utzig59b63e52019-09-10 12:22:35 -03001993 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_REVERT;
David Vinczeba3bd602019-06-17 16:01:43 +02001994 }
Fabio Utzig338a19f2018-12-03 08:37:08 -02001995 }
1996 }
Fabio Utzig338a19f2018-12-03 08:37:08 -02001997#endif
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001998 }
David Vinczeba3bd602019-06-17 16:01:43 +02001999 } else {
2000 /* In that case if slots are not compatible. */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002001 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08002002 }
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08002003}
2004
Mark Horvathccaf7f82021-01-04 18:16:42 +01002005/**
2006 * Updates the security counter for the current image.
2007 *
2008 * @param state Boot loader status information.
2009 *
2010 * @return 0 on success; nonzero on failure.
2011 */
2012static int
2013boot_update_hw_rollback_protection(struct boot_loader_state *state)
2014{
2015#ifdef MCUBOOT_HW_ROLLBACK_PROT
2016 int rc;
2017
2018 /* Update the stored security counter with the active image's security
2019 * counter value. It will only be updated if the new security counter is
2020 * greater than the stored value.
2021 *
2022 * In case of a successful image swapping when the swap type is TEST the
2023 * security counter can be increased only after a reset, when the swap
2024 * type is NONE and the image has marked itself "OK" (the image_ok flag
2025 * has been set). This way a "revert" can be performed when it's
2026 * necessary.
2027 */
2028 if (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_NONE) {
2029 rc = boot_update_security_counter(
2030 BOOT_CURR_IMG(state),
2031 BOOT_PRIMARY_SLOT,
2032 boot_img_hdr(state, BOOT_PRIMARY_SLOT));
2033 if (rc != 0) {
2034 BOOT_LOG_ERR("Security counter update failed after image "
2035 "validation.");
2036 return rc;
2037 }
2038 }
2039
2040 return 0;
2041
2042#else /* MCUBOOT_HW_ROLLBACK_PROT */
2043 (void) (state);
2044
2045 return 0;
2046#endif
2047}
2048
Jerzy Kasenberge3f895d2022-04-12 15:05:33 +02002049/**
2050 * Checks test swap downgrade prevention conditions.
2051 *
2052 * Function called only for swap upgrades test run. It may prevent
2053 * swap if slot 1 image has <= version number or < security counter
2054 *
2055 * @param state Boot loader status information.
2056 *
2057 * @return 0 - image can be swapped, -1 downgrade prevention
2058 */
2059static int
2060check_downgrade_prevention(struct boot_loader_state *state)
2061{
2062#if defined(MCUBOOT_DOWNGRADE_PREVENTION) && \
2063 (defined(MCUBOOT_SWAP_USING_MOVE) || defined(MCUBOOT_SWAP_USING_SCRATCH))
2064 uint32_t security_counter[2];
2065 int rc;
2066
2067 if (MCUBOOT_DOWNGRADE_PREVENTION_SECURITY_COUNTER) {
2068 /* If there was security no counter in slot 0, allow swap */
2069 rc = bootutil_get_img_security_cnt(&(BOOT_IMG(state, 0).hdr),
2070 BOOT_IMG(state, 0).area,
2071 &security_counter[0]);
2072 if (rc != 0) {
2073 return 0;
2074 }
2075 /* If there is no security counter in slot 1, or it's lower than
2076 * that of slot 0, prevent downgrade */
2077 rc = bootutil_get_img_security_cnt(&(BOOT_IMG(state, 1).hdr),
2078 BOOT_IMG(state, 1).area,
2079 &security_counter[1]);
2080 if (rc != 0 || security_counter[0] > security_counter[1]) {
2081 rc = -1;
2082 }
2083 }
2084 else {
2085 rc = boot_version_cmp(&boot_img_hdr(state, BOOT_SECONDARY_SLOT)->ih_ver,
2086 &boot_img_hdr(state, BOOT_PRIMARY_SLOT)->ih_ver);
2087 }
2088 if (rc < 0) {
2089 /* Image in slot 0 prevents downgrade, delete image in slot 1 */
Antonio de Angelis48547002023-04-14 09:47:09 +01002090 BOOT_LOG_INF("Image %d in slot 1 erased due to downgrade prevention", BOOT_CURR_IMG(state));
Jerzy Kasenberge3f895d2022-04-12 15:05:33 +02002091 flash_area_erase(BOOT_IMG(state, 1).area, 0,
2092 flash_area_get_size(BOOT_IMG(state, 1).area));
2093 } else {
2094 rc = 0;
2095 }
2096 return rc;
2097#else
2098 (void)state;
2099 return 0;
2100#endif
2101}
2102
Michael Grand5047f032022-11-24 16:49:56 +01002103fih_ret
Fabio Utzig10ee6482019-08-01 12:04:52 -03002104context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp)
Christopher Collins92ea77f2016-12-12 15:59:26 -08002105{
Marti Bolivar84898652017-06-13 17:20:22 -04002106 size_t slot;
David Vinczeba3bd602019-06-17 16:01:43 +02002107 struct boot_status bs;
David Vincze9015a5d2020-05-18 14:43:11 +02002108 int rc = -1;
Michael Grand5047f032022-11-24 16:49:56 +01002109 FIH_DECLARE(fih_rc, FIH_FAILURE);
Marti Bolivarc0b47912017-06-13 17:18:09 -04002110 int fa_id;
Fabio Utzigb0f04732019-07-31 09:49:19 -03002111 int image_index;
Fabio Utzig298913b2019-08-28 11:22:45 -03002112 bool has_upgrade;
Michael Grand5047f032022-11-24 16:49:56 +01002113 volatile int fih_cnt;
Christopher Collins92ea77f2016-12-12 15:59:26 -08002114
2115 /* The array of slot sectors are defined here (as opposed to file scope) so
2116 * that they don't get allocated for non-boot-loader apps. This is
2117 * necessary because the gcc option "-fdata-sections" doesn't seem to have
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08002118 * any effect in older gcc versions (e.g., 4.8.4).
Christopher Collins92ea77f2016-12-12 15:59:26 -08002119 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002120 TARGET_STATIC boot_sector_t primary_slot_sectors[BOOT_IMAGE_NUMBER][BOOT_MAX_IMG_SECTORS];
2121 TARGET_STATIC boot_sector_t secondary_slot_sectors[BOOT_IMAGE_NUMBER][BOOT_MAX_IMG_SECTORS];
Fabio Utzig12d59162019-11-28 10:01:59 -03002122#if MCUBOOT_SWAP_USING_SCRATCH
Fabio Utzig10ee6482019-08-01 12:04:52 -03002123 TARGET_STATIC boot_sector_t scratch_sectors[BOOT_MAX_IMG_SECTORS];
Fabio Utzig12d59162019-11-28 10:01:59 -03002124#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -08002125
Fabio Utzig298913b2019-08-28 11:22:45 -03002126 has_upgrade = false;
2127
2128#if (BOOT_IMAGE_NUMBER == 1)
2129 (void)has_upgrade;
2130#endif
Fabio Utzigba829042018-09-18 08:29:34 -03002131
David Vinczeba3bd602019-06-17 16:01:43 +02002132 /* Iterate over all the images. By the end of the loop the swap type has
2133 * to be determined for each image and all aborted swaps have to be
2134 * completed.
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08002135 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002136 IMAGES_ITER(BOOT_CURR_IMG(state)) {
Raef Colesf11de642021-10-15 11:11:56 +01002137#if BOOT_IMAGE_NUMBER > 1
2138 if (state->img_mask[BOOT_CURR_IMG(state)]) {
2139 continue;
2140 }
2141#endif
David Vinczeba3bd602019-06-17 16:01:43 +02002142#if defined(MCUBOOT_ENC_IMAGES) && (BOOT_IMAGE_NUMBER > 1)
2143 /* The keys used for encryption may no longer be valid (could belong to
2144 * another images). Therefore, mark them as invalid to force their reload
2145 * by boot_enc_load().
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03002146 */
Fabio Utzig1e4284b2019-08-23 11:55:27 -03002147 boot_enc_zeroize(BOOT_CURR_ENC(state));
David Brown554c52e2017-06-30 16:01:07 -06002148#endif
2149
Fabio Utzig10ee6482019-08-01 12:04:52 -03002150 image_index = BOOT_CURR_IMG(state);
Fabio Utzigb0f04732019-07-31 09:49:19 -03002151
Fabio Utzig10ee6482019-08-01 12:04:52 -03002152 BOOT_IMG(state, BOOT_PRIMARY_SLOT).sectors =
Fabio Utzigb0f04732019-07-31 09:49:19 -03002153 primary_slot_sectors[image_index];
Fabio Utzig10ee6482019-08-01 12:04:52 -03002154 BOOT_IMG(state, BOOT_SECONDARY_SLOT).sectors =
Fabio Utzigb0f04732019-07-31 09:49:19 -03002155 secondary_slot_sectors[image_index];
Fabio Utzig12d59162019-11-28 10:01:59 -03002156#if MCUBOOT_SWAP_USING_SCRATCH
Fabio Utzig10ee6482019-08-01 12:04:52 -03002157 state->scratch.sectors = scratch_sectors;
Fabio Utzig12d59162019-11-28 10:01:59 -03002158#endif
David Vinczeba3bd602019-06-17 16:01:43 +02002159
2160 /* Open primary and secondary image areas for the duration
2161 * of this call.
2162 */
2163 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
Fabio Utzigb0f04732019-07-31 09:49:19 -03002164 fa_id = flash_area_id_from_multi_image_slot(image_index, slot);
Fabio Utzig10ee6482019-08-01 12:04:52 -03002165 rc = flash_area_open(fa_id, &BOOT_IMG_AREA(state, slot));
David Vinczeba3bd602019-06-17 16:01:43 +02002166 assert(rc == 0);
Jamie McCrae2929a972023-09-25 11:12:20 +01002167
2168 if (rc != 0) {
2169 BOOT_LOG_ERR("Failed to open flash area ID %d (image %d slot %d): %d, "
2170 "cannot continue", fa_id, image_index, (int8_t)slot, rc);
2171 FIH_PANIC;
2172 }
David Vinczeba3bd602019-06-17 16:01:43 +02002173 }
Fabio Utzig12d59162019-11-28 10:01:59 -03002174#if MCUBOOT_SWAP_USING_SCRATCH
David Vinczeba3bd602019-06-17 16:01:43 +02002175 rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH,
Fabio Utzig10ee6482019-08-01 12:04:52 -03002176 &BOOT_SCRATCH_AREA(state));
David Vinczeba3bd602019-06-17 16:01:43 +02002177 assert(rc == 0);
Jamie McCrae2929a972023-09-25 11:12:20 +01002178
2179 if (rc != 0) {
2180 BOOT_LOG_ERR("Failed to open scratch flash area: %d, cannot continue", rc);
2181 FIH_PANIC;
2182 }
Fabio Utzig12d59162019-11-28 10:01:59 -03002183#endif
David Vinczeba3bd602019-06-17 16:01:43 +02002184
2185 /* Determine swap type and complete swap if it has been aborted. */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002186 boot_prepare_image_for_update(state, &bs);
Fabio Utzig298913b2019-08-28 11:22:45 -03002187
Fabio Utzige575b0b2019-09-11 12:34:23 -03002188 if (BOOT_IS_UPGRADE(BOOT_SWAP_TYPE(state))) {
Fabio Utzig298913b2019-08-28 11:22:45 -03002189 has_upgrade = true;
2190 }
David Vinczeba3bd602019-06-17 16:01:43 +02002191 }
2192
David Vinczee32483f2019-06-13 10:46:24 +02002193#if (BOOT_IMAGE_NUMBER > 1)
Fabio Utzig298913b2019-08-28 11:22:45 -03002194 if (has_upgrade) {
2195 /* Iterate over all the images and verify whether the image dependencies
2196 * are all satisfied and update swap type if necessary.
2197 */
2198 rc = boot_verify_dependencies(state);
David Vincze8b0b6372020-05-20 19:54:44 +02002199 if (rc != 0) {
Fabio Utzig298913b2019-08-28 11:22:45 -03002200 /*
2201 * It was impossible to upgrade because the expected dependency version
2202 * was not available. Here we already changed the swap_type so that
2203 * instead of asserting the bootloader, we continue and no upgrade is
2204 * performed.
2205 */
2206 rc = 0;
2207 }
2208 }
David Vinczee32483f2019-06-13 10:46:24 +02002209#endif
2210
Jamie McCrae56cb6102022-03-23 11:57:03 +00002211 /* Trigger status change callback with upgrading status */
2212 mcuboot_status_change(MCUBOOT_STATUS_UPGRADING);
2213
David Vinczeba3bd602019-06-17 16:01:43 +02002214 /* Iterate over all the images. At this point there are no aborted swaps
2215 * and the swap types are determined for each image. By the end of the loop
2216 * all required update operations will have been finished.
2217 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002218 IMAGES_ITER(BOOT_CURR_IMG(state)) {
David Vinczeba3bd602019-06-17 16:01:43 +02002219#if (BOOT_IMAGE_NUMBER > 1)
Raef Colesf11de642021-10-15 11:11:56 +01002220 if (state->img_mask[BOOT_CURR_IMG(state)]) {
2221 continue;
2222 }
2223
David Vinczeba3bd602019-06-17 16:01:43 +02002224#ifdef MCUBOOT_ENC_IMAGES
2225 /* The keys used for encryption may no longer be valid (could belong to
2226 * another images). Therefore, mark them as invalid to force their reload
2227 * by boot_enc_load().
2228 */
Fabio Utzig1e4284b2019-08-23 11:55:27 -03002229 boot_enc_zeroize(BOOT_CURR_ENC(state));
David Vinczeba3bd602019-06-17 16:01:43 +02002230#endif /* MCUBOOT_ENC_IMAGES */
2231
2232 /* Indicate that swap is not aborted */
Fabio Utzig12d59162019-11-28 10:01:59 -03002233 boot_status_reset(&bs);
David Vinczeba3bd602019-06-17 16:01:43 +02002234#endif /* (BOOT_IMAGE_NUMBER > 1) */
2235
2236 /* Set the previously determined swap type */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002237 bs.swap_type = BOOT_SWAP_TYPE(state);
David Vinczeba3bd602019-06-17 16:01:43 +02002238
Fabio Utzig10ee6482019-08-01 12:04:52 -03002239 switch (BOOT_SWAP_TYPE(state)) {
David Vinczeba3bd602019-06-17 16:01:43 +02002240 case BOOT_SWAP_TYPE_NONE:
2241 break;
2242
Jerzy Kasenberge3f895d2022-04-12 15:05:33 +02002243 case BOOT_SWAP_TYPE_TEST:
Michael Grand99613c62023-06-20 15:01:00 +02002244 /* fallthrough */
2245 case BOOT_SWAP_TYPE_PERM:
Jerzy Kasenberge3f895d2022-04-12 15:05:33 +02002246 if (check_downgrade_prevention(state) != 0) {
2247 /* Downgrade prevented */
2248 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
2249 break;
2250 }
2251 /* fallthrough */
David Vinczeba3bd602019-06-17 16:01:43 +02002252 case BOOT_SWAP_TYPE_REVERT:
Andrzej Puzdrowskib8f39692021-07-02 15:05:37 +02002253 rc = BOOT_HOOK_CALL(boot_perform_update_hook, BOOT_HOOK_REGULAR,
2254 BOOT_CURR_IMG(state), &(BOOT_IMG(state, 1).hdr),
2255 BOOT_IMG_AREA(state, BOOT_SECONDARY_SLOT));
2256 if (rc == BOOT_HOOK_REGULAR)
2257 {
2258 rc = boot_perform_update(state, &bs);
2259 }
David Vinczeba3bd602019-06-17 16:01:43 +02002260 assert(rc == 0);
2261 break;
2262
2263 case BOOT_SWAP_TYPE_FAIL:
2264 /* The image in secondary slot was invalid and is now erased. Ensure
2265 * we don't try to boot into it again on the next reboot. Do this by
2266 * pretending we just reverted back to primary slot.
2267 */
2268#ifndef MCUBOOT_OVERWRITE_ONLY
2269 /* image_ok needs to be explicitly set to avoid a new revert. */
Fabio Utzig12d59162019-11-28 10:01:59 -03002270 rc = swap_set_image_ok(BOOT_CURR_IMG(state));
David Vinczeba3bd602019-06-17 16:01:43 +02002271 if (rc != 0) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03002272 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
David Vinczeba3bd602019-06-17 16:01:43 +02002273 }
2274#endif /* !MCUBOOT_OVERWRITE_ONLY */
2275 break;
2276
2277 default:
Fabio Utzig10ee6482019-08-01 12:04:52 -03002278 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
David Vinczeba3bd602019-06-17 16:01:43 +02002279 }
2280
Fabio Utzig10ee6482019-08-01 12:04:52 -03002281 if (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_PANIC) {
David Vinczeba3bd602019-06-17 16:01:43 +02002282 BOOT_LOG_ERR("panic!");
2283 assert(0);
2284
2285 /* Loop forever... */
Raef Colese8fe6cf2020-05-26 13:07:40 +01002286 FIH_PANIC;
David Vinczeba3bd602019-06-17 16:01:43 +02002287 }
2288 }
2289
2290 /* Iterate over all the images. At this point all required update operations
2291 * have finished. By the end of the loop each image in the primary slot will
2292 * have been re-validated.
2293 */
Michael Grand5047f032022-11-24 16:49:56 +01002294 FIH_SET(fih_cnt, 0);
Fabio Utzig10ee6482019-08-01 12:04:52 -03002295 IMAGES_ITER(BOOT_CURR_IMG(state)) {
Raef Colesf11de642021-10-15 11:11:56 +01002296#if BOOT_IMAGE_NUMBER > 1
Michael Grand5047f032022-11-24 16:49:56 +01002297 /* Hardenned to prevent from skipping check of a given image,
2298 * tmp_img_mask is declared volatile
2299 */
2300 volatile bool tmp_img_mask;
2301 FIH_SET(tmp_img_mask, state->img_mask[BOOT_CURR_IMG(state)]);
2302 if (FIH_EQ(tmp_img_mask, true)) {
2303 ++fih_cnt;
Raef Colesf11de642021-10-15 11:11:56 +01002304 continue;
2305 }
2306#endif
Fabio Utzig10ee6482019-08-01 12:04:52 -03002307 if (BOOT_SWAP_TYPE(state) != BOOT_SWAP_TYPE_NONE) {
David Vinczeba3bd602019-06-17 16:01:43 +02002308 /* Attempt to read an image header from each slot. Ensure that image
2309 * headers in slots are aligned with headers in boot_data.
Dominik Ermel6f7f8732024-02-01 11:59:24 +00002310 * Note: Quite complicated internal logic of boot_read_image_headers
2311 * uses boot state, the last parm, to figure out in which slot which
2312 * header is located; when boot state is not provided, then it
2313 * is assumed that headers are at proper slots (we are not in
2314 * the middle of moving images, etc).
David Vinczeba3bd602019-06-17 16:01:43 +02002315 */
Dominik Ermel6f7f8732024-02-01 11:59:24 +00002316 rc = boot_read_image_headers(state, false, NULL);
David Vinczeba3bd602019-06-17 16:01:43 +02002317 if (rc != 0) {
Michael Grand5047f032022-11-24 16:49:56 +01002318 FIH_SET(fih_rc, FIH_FAILURE);
David Vinczeba3bd602019-06-17 16:01:43 +02002319 goto out;
2320 }
2321 /* Since headers were reloaded, it can be assumed we just performed
2322 * a swap or overwrite. Now the header info that should be used to
2323 * provide the data for the bootstrap, which previously was at
2324 * secondary slot, was updated to primary slot.
2325 */
2326 }
2327
2328#ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT
Raef Colese8fe6cf2020-05-26 13:07:40 +01002329 FIH_CALL(boot_validate_slot, fih_rc, state, BOOT_PRIMARY_SLOT, NULL);
Michael Grand5047f032022-11-24 16:49:56 +01002330 /* Check for all possible values is redundant in normal operation it
2331 * is meant to prevent FI attack.
2332 */
2333 if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS) ||
2334 FIH_EQ(fih_rc, FIH_FAILURE) ||
2335 FIH_EQ(fih_rc, FIH_NO_BOOTABLE_IMAGE)) {
2336 FIH_SET(fih_rc, FIH_FAILURE);
David Vinczeba3bd602019-06-17 16:01:43 +02002337 goto out;
2338 }
2339#else
2340 /* Even if we're not re-validating the primary slot, we could be booting
2341 * onto an empty flash chip. At least do a basic sanity check that
2342 * the magic number on the image is OK.
2343 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002344 if (BOOT_IMG(state, BOOT_PRIMARY_SLOT).hdr.ih_magic != IMAGE_MAGIC) {
David Vinczeba3bd602019-06-17 16:01:43 +02002345 BOOT_LOG_ERR("bad image magic 0x%lx; Image=%u", (unsigned long)
Dominik Ermel4a4d1ac2021-08-06 11:23:52 +00002346 BOOT_IMG(state, BOOT_PRIMARY_SLOT).hdr.ih_magic,
Fabio Utzig10ee6482019-08-01 12:04:52 -03002347 BOOT_CURR_IMG(state));
David Vinczeba3bd602019-06-17 16:01:43 +02002348 rc = BOOT_EBADIMAGE;
Michael Grand5047f032022-11-24 16:49:56 +01002349 FIH_SET(fih_rc, FIH_FAILURE);
David Vinczeba3bd602019-06-17 16:01:43 +02002350 goto out;
2351 }
David Vinczec3084132020-02-18 14:50:47 +01002352#endif /* MCUBOOT_VALIDATE_PRIMARY_SLOT */
2353
Mark Horvathccaf7f82021-01-04 18:16:42 +01002354 rc = boot_update_hw_rollback_protection(state);
David Vincze1cf11b52020-03-24 07:51:09 +01002355 if (rc != 0) {
Michael Grand5047f032022-11-24 16:49:56 +01002356 FIH_SET(fih_rc, FIH_FAILURE);
Raef Colese8fe6cf2020-05-26 13:07:40 +01002357 goto out;
David Vincze1cf11b52020-03-24 07:51:09 +01002358 }
David Vincze1cf11b52020-03-24 07:51:09 +01002359
Mark Horvathccaf7f82021-01-04 18:16:42 +01002360 rc = boot_add_shared_data(state, BOOT_PRIMARY_SLOT);
David Vincze1cf11b52020-03-24 07:51:09 +01002361 if (rc != 0) {
Michael Grand5047f032022-11-24 16:49:56 +01002362 FIH_SET(fih_rc, FIH_FAILURE);
Raef Colese8fe6cf2020-05-26 13:07:40 +01002363 goto out;
David Vincze1cf11b52020-03-24 07:51:09 +01002364 }
Michael Grand5047f032022-11-24 16:49:56 +01002365 ++fih_cnt;
David Vinczeba3bd602019-06-17 16:01:43 +02002366 }
Michael Grand5047f032022-11-24 16:49:56 +01002367 /*
2368 * fih_cnt should be equal to BOOT_IMAGE_NUMBER now.
2369 * If this is not the case, at least one iteration of the loop
2370 * has been skipped.
2371 */
2372 if(FIH_NOT_EQ(fih_cnt, BOOT_IMAGE_NUMBER)) {
2373 FIH_PANIC;
2374 }
Fabio Utzigf616c542019-12-19 15:23:32 -03002375
Raef Colesfe57e7d2021-10-15 11:07:09 +01002376 fill_rsp(state, rsp);
Christopher Collins92ea77f2016-12-12 15:59:26 -08002377
Raef Colese8fe6cf2020-05-26 13:07:40 +01002378 fih_rc = FIH_SUCCESS;
Fabio Utzig298913b2019-08-28 11:22:45 -03002379out:
Dominik Ermel256bc372022-12-07 15:51:31 +00002380 /*
2381 * Since the boot_status struct stores plaintext encryption keys, reset
2382 * them here to avoid the possibility of jumping into an image that could
2383 * easily recover them.
2384 */
2385#if defined(MCUBOOT_ENC_IMAGES) || defined(MCUBOOT_SWAP_SAVE_ENCTLV)
2386 like_mbedtls_zeroize(&bs, sizeof(bs));
2387#else
2388 memset(&bs, 0, sizeof(struct boot_status));
2389#endif
2390
Mark Horvathccaf7f82021-01-04 18:16:42 +01002391 close_all_flash_areas(state);
Raef Colese8fe6cf2020-05-26 13:07:40 +01002392 FIH_RET(fih_rc);
Christopher Collins92ea77f2016-12-12 15:59:26 -08002393}
2394
Michael Grand5047f032022-11-24 16:49:56 +01002395fih_ret
Christopher Collins92ea77f2016-12-12 15:59:26 -08002396split_go(int loader_slot, int split_slot, void **entry)
2397{
Marti Bolivarc50926f2017-06-14 09:35:40 -04002398 boot_sector_t *sectors;
Christopher Collins034a6202017-01-11 12:19:37 -08002399 uintptr_t entry_val;
Christopher Collins92ea77f2016-12-12 15:59:26 -08002400 int loader_flash_id;
Marti Bolivarc0b47912017-06-13 17:18:09 -04002401 int split_flash_id;
Christopher Collins92ea77f2016-12-12 15:59:26 -08002402 int rc;
Michael Grand5047f032022-11-24 16:49:56 +01002403 FIH_DECLARE(fih_rc, FIH_FAILURE);
Christopher Collins92ea77f2016-12-12 15:59:26 -08002404
Christopher Collins92ea77f2016-12-12 15:59:26 -08002405 sectors = malloc(BOOT_MAX_IMG_SECTORS * 2 * sizeof *sectors);
2406 if (sectors == NULL) {
Raef Colese8fe6cf2020-05-26 13:07:40 +01002407 FIH_RET(FIH_FAILURE);
Christopher Collins92ea77f2016-12-12 15:59:26 -08002408 }
David Vinczeba3bd602019-06-17 16:01:43 +02002409 BOOT_IMG(&boot_data, loader_slot).sectors = sectors + 0;
2410 BOOT_IMG(&boot_data, split_slot).sectors = sectors + BOOT_MAX_IMG_SECTORS;
Marti Bolivarc0b47912017-06-13 17:18:09 -04002411
2412 loader_flash_id = flash_area_id_from_image_slot(loader_slot);
2413 rc = flash_area_open(loader_flash_id,
Alvaro Prieto63a2bdb2019-07-04 12:18:49 -07002414 &BOOT_IMG_AREA(&boot_data, loader_slot));
Marti Bolivarc0b47912017-06-13 17:18:09 -04002415 assert(rc == 0);
2416 split_flash_id = flash_area_id_from_image_slot(split_slot);
2417 rc = flash_area_open(split_flash_id,
2418 &BOOT_IMG_AREA(&boot_data, split_slot));
2419 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -08002420
2421 /* Determine the sector layout of the image slots and scratch area. */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002422 rc = boot_read_sectors(&boot_data);
Christopher Collins92ea77f2016-12-12 15:59:26 -08002423 if (rc != 0) {
2424 rc = SPLIT_GO_ERR;
2425 goto done;
2426 }
2427
Fabio Utzig12d59162019-11-28 10:01:59 -03002428 rc = boot_read_image_headers(&boot_data, true, NULL);
Christopher Collins92ea77f2016-12-12 15:59:26 -08002429 if (rc != 0) {
2430 goto done;
2431 }
2432
Christopher Collins92ea77f2016-12-12 15:59:26 -08002433 /* Don't check the bootable image flag because we could really call a
2434 * bootable or non-bootable image. Just validate that the image check
2435 * passes which is distinct from the normal check.
2436 */
Raef Colese8fe6cf2020-05-26 13:07:40 +01002437 FIH_CALL(split_image_check, fih_rc,
2438 boot_img_hdr(&boot_data, split_slot),
2439 BOOT_IMG_AREA(&boot_data, split_slot),
2440 boot_img_hdr(&boot_data, loader_slot),
2441 BOOT_IMG_AREA(&boot_data, loader_slot));
Michael Grand5047f032022-11-24 16:49:56 +01002442 if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
Christopher Collins92ea77f2016-12-12 15:59:26 -08002443 goto done;
2444 }
2445
Marti Bolivarea088872017-06-12 17:10:49 -04002446 entry_val = boot_img_slot_off(&boot_data, split_slot) +
Marti Bolivarf804f622017-06-12 15:41:48 -04002447 boot_img_hdr(&boot_data, split_slot)->ih_hdr_size;
Christopher Collins034a6202017-01-11 12:19:37 -08002448 *entry = (void *) entry_val;
Christopher Collins92ea77f2016-12-12 15:59:26 -08002449 rc = SPLIT_GO_OK;
2450
2451done:
Marti Bolivarc0b47912017-06-13 17:18:09 -04002452 flash_area_close(BOOT_IMG_AREA(&boot_data, split_slot));
2453 flash_area_close(BOOT_IMG_AREA(&boot_data, loader_slot));
Christopher Collins92ea77f2016-12-12 15:59:26 -08002454 free(sectors);
Raef Colese8fe6cf2020-05-26 13:07:40 +01002455
2456 if (rc) {
Michael Grand5047f032022-11-24 16:49:56 +01002457 FIH_SET(fih_rc, FIH_FAILURE);
Raef Colese8fe6cf2020-05-26 13:07:40 +01002458 }
2459
2460 FIH_RET(fih_rc);
Christopher Collins92ea77f2016-12-12 15:59:26 -08002461}
David Vinczee574f2d2020-07-10 11:42:03 +02002462
Tamas Banfe031092020-09-10 17:32:39 +02002463#else /* MCUBOOT_DIRECT_XIP || MCUBOOT_RAM_LOAD */
David Vinczee574f2d2020-07-10 11:42:03 +02002464
2465/**
Mark Horvathccaf7f82021-01-04 18:16:42 +01002466 * Opens all flash areas and checks which contain an image with a valid header.
David Vinczee574f2d2020-07-10 11:42:03 +02002467 *
Mark Horvathccaf7f82021-01-04 18:16:42 +01002468 * @param state Boot loader status information.
David Vinczee574f2d2020-07-10 11:42:03 +02002469 *
Mark Horvathccaf7f82021-01-04 18:16:42 +01002470 * @return 0 on success; nonzero on failure.
2471 */
2472static int
Raef Colesfe57e7d2021-10-15 11:07:09 +01002473boot_get_slot_usage(struct boot_loader_state *state)
Mark Horvathccaf7f82021-01-04 18:16:42 +01002474{
2475 uint32_t slot;
2476 int fa_id;
2477 int rc;
2478 struct image_header *hdr = NULL;
2479
2480 IMAGES_ITER(BOOT_CURR_IMG(state)) {
Raef Colesf11de642021-10-15 11:11:56 +01002481#if BOOT_IMAGE_NUMBER > 1
2482 if (state->img_mask[BOOT_CURR_IMG(state)]) {
2483 continue;
2484 }
2485#endif
Mark Horvathccaf7f82021-01-04 18:16:42 +01002486 /* Open all the slots */
2487 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
2488 fa_id = flash_area_id_from_multi_image_slot(
2489 BOOT_CURR_IMG(state), slot);
2490 rc = flash_area_open(fa_id, &BOOT_IMG_AREA(state, slot));
2491 assert(rc == 0);
2492 }
2493
2494 /* Attempt to read an image header from each slot. */
2495 rc = boot_read_image_headers(state, false, NULL);
2496 if (rc != 0) {
2497 BOOT_LOG_WRN("Failed reading image headers.");
2498 return rc;
2499 }
2500
2501 /* Check headers in all slots */
2502 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
2503 hdr = boot_img_hdr(state, slot);
2504
2505 if (boot_is_header_valid(hdr, BOOT_IMG_AREA(state, slot))) {
Raef Colesfe57e7d2021-10-15 11:07:09 +01002506 state->slot_usage[BOOT_CURR_IMG(state)].slot_available[slot] = true;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002507 BOOT_LOG_IMAGE_INFO(slot, hdr);
2508 } else {
Raef Colesfe57e7d2021-10-15 11:07:09 +01002509 state->slot_usage[BOOT_CURR_IMG(state)].slot_available[slot] = false;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002510 BOOT_LOG_INF("Image %d %s slot: Image not found",
2511 BOOT_CURR_IMG(state),
2512 (slot == BOOT_PRIMARY_SLOT)
2513 ? "Primary" : "Secondary");
2514 }
2515 }
2516
Raef Colesfe57e7d2021-10-15 11:07:09 +01002517 state->slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002518 }
2519
2520 return 0;
2521}
2522
2523/**
2524 * Finds the slot containing the image with the highest version number for the
2525 * current image.
2526 *
2527 * @param state Boot loader status information.
Mark Horvathccaf7f82021-01-04 18:16:42 +01002528 *
2529 * @return NO_ACTIVE_SLOT if no available slot found, number of
2530 * the found slot otherwise.
David Vinczee574f2d2020-07-10 11:42:03 +02002531 */
2532static uint32_t
Raef Colesfe57e7d2021-10-15 11:07:09 +01002533find_slot_with_highest_version(struct boot_loader_state *state)
David Vinczee574f2d2020-07-10 11:42:03 +02002534{
David Vinczee574f2d2020-07-10 11:42:03 +02002535 uint32_t slot;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002536 uint32_t candidate_slot = NO_ACTIVE_SLOT;
2537 int rc;
David Vinczee574f2d2020-07-10 11:42:03 +02002538
Mark Horvathccaf7f82021-01-04 18:16:42 +01002539 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
Raef Colesfe57e7d2021-10-15 11:07:09 +01002540 if (state->slot_usage[BOOT_CURR_IMG(state)].slot_available[slot]) {
Mark Horvathccaf7f82021-01-04 18:16:42 +01002541 if (candidate_slot == NO_ACTIVE_SLOT) {
2542 candidate_slot = slot;
2543 } else {
2544 rc = boot_version_cmp(
2545 &boot_img_hdr(state, slot)->ih_ver,
2546 &boot_img_hdr(state, candidate_slot)->ih_ver);
2547 if (rc == 1) {
2548 /* The version of the image being examined is greater than
2549 * the version of the current candidate.
2550 */
2551 candidate_slot = slot;
2552 }
2553 }
David Vinczee574f2d2020-07-10 11:42:03 +02002554 }
2555 }
2556
Mark Horvathccaf7f82021-01-04 18:16:42 +01002557 return candidate_slot;
David Vinczee574f2d2020-07-10 11:42:03 +02002558}
2559
Mark Horvathccaf7f82021-01-04 18:16:42 +01002560#ifdef MCUBOOT_HAVE_LOGGING
2561/**
2562 * Prints the state of the loaded images.
2563 *
2564 * @param state Boot loader status information.
Mark Horvathccaf7f82021-01-04 18:16:42 +01002565 */
2566static void
Raef Colesfe57e7d2021-10-15 11:07:09 +01002567print_loaded_images(struct boot_loader_state *state)
Mark Horvathccaf7f82021-01-04 18:16:42 +01002568{
2569 uint32_t active_slot;
2570
David Brown695e5912021-05-24 16:58:01 -06002571 (void)state;
2572
Mark Horvathccaf7f82021-01-04 18:16:42 +01002573 IMAGES_ITER(BOOT_CURR_IMG(state)) {
Raef Colesf11de642021-10-15 11:11:56 +01002574#if BOOT_IMAGE_NUMBER > 1
2575 if (state->img_mask[BOOT_CURR_IMG(state)]) {
2576 continue;
2577 }
2578#endif
Raef Colesfe57e7d2021-10-15 11:07:09 +01002579 active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002580
2581 BOOT_LOG_INF("Image %d loaded from the %s slot",
2582 BOOT_CURR_IMG(state),
2583 (active_slot == BOOT_PRIMARY_SLOT) ?
2584 "primary" : "secondary");
2585 }
2586}
2587#endif
2588
David Vincze1c456242021-06-29 15:25:24 +02002589#if defined(MCUBOOT_DIRECT_XIP) && defined(MCUBOOT_DIRECT_XIP_REVERT)
David Vincze505fba22020-10-22 13:53:29 +02002590/**
Mark Horvathccaf7f82021-01-04 18:16:42 +01002591 * Checks whether the active slot of the current image was previously selected
2592 * to run. Erases the image if it was selected but its execution failed,
2593 * otherwise marks it as selected if it has not been before.
David Vincze505fba22020-10-22 13:53:29 +02002594 *
Mark Horvathccaf7f82021-01-04 18:16:42 +01002595 * @param state Boot loader status information.
David Vincze505fba22020-10-22 13:53:29 +02002596 *
Mark Horvathccaf7f82021-01-04 18:16:42 +01002597 * @return 0 on success; nonzero on failure.
David Vincze505fba22020-10-22 13:53:29 +02002598 */
2599static int
Raef Colesfe57e7d2021-10-15 11:07:09 +01002600boot_select_or_erase(struct boot_loader_state *state)
David Vincze505fba22020-10-22 13:53:29 +02002601{
2602 const struct flash_area *fap;
2603 int fa_id;
2604 int rc;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002605 uint32_t active_slot;
2606 struct boot_swap_state* active_swap_state;
David Vincze505fba22020-10-22 13:53:29 +02002607
Raef Colesfe57e7d2021-10-15 11:07:09 +01002608 active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002609
2610 fa_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), active_slot);
David Vincze505fba22020-10-22 13:53:29 +02002611 rc = flash_area_open(fa_id, &fap);
2612 assert(rc == 0);
2613
Raef Colesfe57e7d2021-10-15 11:07:09 +01002614 active_swap_state = &(state->slot_usage[BOOT_CURR_IMG(state)].swap_state);
Mark Horvathccaf7f82021-01-04 18:16:42 +01002615
2616 memset(active_swap_state, 0, sizeof(struct boot_swap_state));
2617 rc = boot_read_swap_state(fap, active_swap_state);
David Vincze505fba22020-10-22 13:53:29 +02002618 assert(rc == 0);
2619
Mark Horvathccaf7f82021-01-04 18:16:42 +01002620 if (active_swap_state->magic != BOOT_MAGIC_GOOD ||
2621 (active_swap_state->copy_done == BOOT_FLAG_SET &&
2622 active_swap_state->image_ok != BOOT_FLAG_SET)) {
David Vincze505fba22020-10-22 13:53:29 +02002623 /*
2624 * A reboot happened without the image being confirmed at
2625 * runtime or its trailer is corrupted/invalid. Erase the image
2626 * to prevent it from being selected again on the next reboot.
2627 */
2628 BOOT_LOG_DBG("Erasing faulty image in the %s slot.",
Carlos Falgueras Garcíaae13c3c2021-06-21 17:20:31 +02002629 (active_slot == BOOT_PRIMARY_SLOT) ? "primary" : "secondary");
Dominik Ermel260ae092021-04-23 05:38:45 +00002630 rc = flash_area_erase(fap, 0, flash_area_get_size(fap));
David Vincze505fba22020-10-22 13:53:29 +02002631 assert(rc == 0);
2632
2633 flash_area_close(fap);
2634 rc = -1;
2635 } else {
Mark Horvathccaf7f82021-01-04 18:16:42 +01002636 if (active_swap_state->copy_done != BOOT_FLAG_SET) {
2637 if (active_swap_state->copy_done == BOOT_FLAG_BAD) {
David Vincze505fba22020-10-22 13:53:29 +02002638 BOOT_LOG_DBG("The copy_done flag had an unexpected value. Its "
2639 "value was neither 'set' nor 'unset', but 'bad'.");
2640 }
2641 /*
2642 * Set the copy_done flag, indicating that the image has been
2643 * selected to boot. It can be set in advance, before even
2644 * validating the image, because in case the validation fails, the
2645 * entire image slot will be erased (including the trailer).
2646 */
2647 rc = boot_write_copy_done(fap);
2648 if (rc != 0) {
2649 BOOT_LOG_WRN("Failed to set copy_done flag of the image in "
Carlos Falgueras Garcíaae13c3c2021-06-21 17:20:31 +02002650 "the %s slot.", (active_slot == BOOT_PRIMARY_SLOT) ?
David Vincze505fba22020-10-22 13:53:29 +02002651 "primary" : "secondary");
2652 rc = 0;
2653 }
2654 }
2655 flash_area_close(fap);
2656 }
2657
2658 return rc;
2659}
David Vincze1c456242021-06-29 15:25:24 +02002660#endif /* MCUBOOT_DIRECT_XIP && MCUBOOT_DIRECT_XIP_REVERT */
David Vincze505fba22020-10-22 13:53:29 +02002661
Tamas Banfe031092020-09-10 17:32:39 +02002662#ifdef MCUBOOT_RAM_LOAD
2663
Mark Horvathccaf7f82021-01-04 18:16:42 +01002664#ifndef MULTIPLE_EXECUTABLE_RAM_REGIONS
Tamas Banfe031092020-09-10 17:32:39 +02002665#if !defined(IMAGE_EXECUTABLE_RAM_START) || !defined(IMAGE_EXECUTABLE_RAM_SIZE)
2666#error "Platform MUST define executable RAM bounds in case of RAM_LOAD"
2667#endif
Mark Horvathccaf7f82021-01-04 18:16:42 +01002668#endif
Tamas Banfe031092020-09-10 17:32:39 +02002669
2670/**
Mark Horvathccaf7f82021-01-04 18:16:42 +01002671 * Verifies that the active slot of the current image can be loaded within the
2672 * predefined bounds that are allowed to be used by executable images.
Tamas Banfe031092020-09-10 17:32:39 +02002673 *
Mark Horvathccaf7f82021-01-04 18:16:42 +01002674 * @param state Boot loader status information.
Tamas Banfe031092020-09-10 17:32:39 +02002675 *
Mark Horvathccaf7f82021-01-04 18:16:42 +01002676 * @return 0 on success; nonzero on failure.
Tamas Banfe031092020-09-10 17:32:39 +02002677 */
2678static int
Raef Colesfe57e7d2021-10-15 11:07:09 +01002679boot_verify_ram_load_address(struct boot_loader_state *state)
Tamas Banfe031092020-09-10 17:32:39 +02002680{
Mark Horvathccaf7f82021-01-04 18:16:42 +01002681 uint32_t img_dst;
2682 uint32_t img_sz;
Tamas Banfe031092020-09-10 17:32:39 +02002683 uint32_t img_end_addr;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002684 uint32_t exec_ram_start;
2685 uint32_t exec_ram_size;
David Brown695e5912021-05-24 16:58:01 -06002686
2687 (void)state;
2688
Mark Horvathccaf7f82021-01-04 18:16:42 +01002689#ifdef MULTIPLE_EXECUTABLE_RAM_REGIONS
2690 int rc;
Tamas Banfe031092020-09-10 17:32:39 +02002691
Mark Horvathccaf7f82021-01-04 18:16:42 +01002692 rc = boot_get_image_exec_ram_info(BOOT_CURR_IMG(state), &exec_ram_start,
2693 &exec_ram_size);
2694 if (rc != 0) {
2695 return BOOT_EBADSTATUS;
2696 }
2697#else
2698 exec_ram_start = IMAGE_EXECUTABLE_RAM_START;
2699 exec_ram_size = IMAGE_EXECUTABLE_RAM_SIZE;
2700#endif
2701
Raef Colesfe57e7d2021-10-15 11:07:09 +01002702 img_dst = state->slot_usage[BOOT_CURR_IMG(state)].img_dst;
2703 img_sz = state->slot_usage[BOOT_CURR_IMG(state)].img_sz;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002704
2705 if (img_dst < exec_ram_start) {
Tamas Banfe031092020-09-10 17:32:39 +02002706 return BOOT_EBADIMAGE;
2707 }
2708
2709 if (!boot_u32_safe_add(&img_end_addr, img_dst, img_sz)) {
2710 return BOOT_EBADIMAGE;
2711 }
2712
Mark Horvathccaf7f82021-01-04 18:16:42 +01002713 if (img_end_addr > (exec_ram_start + exec_ram_size)) {
Tamas Banfe031092020-09-10 17:32:39 +02002714 return BOOT_EBADIMAGE;
2715 }
2716
2717 return 0;
2718}
2719
Hugo L'Hostisdb543e52021-03-09 18:00:31 +00002720#ifdef MCUBOOT_ENC_IMAGES
2721
2722/**
2723 * Copies and decrypts an image from a slot in the flash to an SRAM address.
2724 *
2725 * @param state Boot loader status information.
2726 * @param slot The flash slot of the image to be copied to SRAM.
2727 * @param hdr The image header.
2728 * @param src_sz Size of the image.
2729 * @param img_dst Pointer to the address at which the image needs to be
2730 * copied to SRAM.
2731 *
2732 * @return 0 on success; nonzero on failure.
2733 */
2734static int
2735boot_decrypt_and_copy_image_to_sram(struct boot_loader_state *state,
2736 uint32_t slot, struct image_header *hdr,
2737 uint32_t src_sz, uint32_t img_dst)
2738{
2739 /* The flow for the decryption and copy of the image is as follows :
2740 * 1. The whole image is copied to the RAM (header + payload + TLV).
2741 * 2. The encryption key is loaded from the TLV in flash.
2742 * 3. The image is then decrypted chunk by chunk in RAM (1 chunk
2743 * is 1024 bytes). Only the payload section is decrypted.
2744 * 4. The image is authenticated in RAM.
2745 */
2746 const struct flash_area *fap_src = NULL;
2747 struct boot_status bs;
2748 uint32_t blk_off;
2749 uint32_t tlv_off;
2750 uint32_t blk_sz;
2751 uint32_t bytes_copied = hdr->ih_hdr_size;
2752 uint32_t chunk_sz;
2753 uint32_t max_sz = 1024;
2754 uint16_t idx;
Hugo L'Hostisdb543e52021-03-09 18:00:31 +00002755 uint8_t * cur_dst;
2756 int area_id;
2757 int rc;
2758 uint8_t * ram_dst = (void *)(IMAGE_RAM_BASE + img_dst);
2759
Hugo L'Hostisdb543e52021-03-09 18:00:31 +00002760 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
2761 rc = flash_area_open(area_id, &fap_src);
2762 if (rc != 0){
2763 return BOOT_EFLASH;
2764 }
2765
2766 tlv_off = BOOT_TLV_OFF(hdr);
2767
2768 /* Copying the whole image in RAM */
2769 rc = flash_area_read(fap_src, 0, ram_dst, src_sz);
2770 if (rc != 0) {
2771 goto done;
2772 }
2773
Dominik Ermel7f9ac972024-07-12 19:21:40 +00002774 rc = boot_enc_load(BOOT_CURR_ENC(state), slot, hdr, fap_src, &bs);
Hugo L'Hostisdb543e52021-03-09 18:00:31 +00002775 if (rc < 0) {
2776 goto done;
2777 }
2778
2779 /* if rc > 0 then the key has already been loaded */
2780 if (rc == 0 && boot_enc_set_key(BOOT_CURR_ENC(state), slot, &bs)) {
2781 goto done;
2782 }
2783
2784 /* Starting at the end of the header as the header section is not encrypted */
2785 while (bytes_copied < tlv_off) { /* TLV section copied previously */
2786 if (src_sz - bytes_copied > max_sz) {
2787 chunk_sz = max_sz;
2788 } else {
2789 chunk_sz = src_sz - bytes_copied;
2790 }
2791
2792 cur_dst = ram_dst + bytes_copied;
2793 blk_sz = chunk_sz;
2794 idx = 0;
Dominik Ermeld09112a2024-07-18 16:43:57 +00002795 blk_off = ((bytes_copied) - hdr->ih_hdr_size) & 0xf;
Hugo L'Hostisdb543e52021-03-09 18:00:31 +00002796 if (bytes_copied + chunk_sz > tlv_off) {
2797 /* Going over TLV section
2798 * Part of the chunk is encrypted payload */
Hugo L'Hostisdb543e52021-03-09 18:00:31 +00002799 blk_sz = tlv_off - (bytes_copied);
Hugo L'Hostisdb543e52021-03-09 18:00:31 +00002800 }
Dominik Ermel3f112862024-07-17 14:43:05 +00002801 boot_encrypt(BOOT_CURR_ENC(state), slot,
Dominik Ermeld09112a2024-07-18 16:43:57 +00002802 (bytes_copied + idx) - hdr->ih_hdr_size, blk_sz,
2803 blk_off, cur_dst);
Hugo L'Hostisdb543e52021-03-09 18:00:31 +00002804
2805 bytes_copied += chunk_sz;
2806 }
2807 rc = 0;
2808
2809done:
2810 flash_area_close(fap_src);
2811
2812 return rc;
2813}
2814
2815#endif /* MCUBOOT_ENC_IMAGES */
Tamas Banfe031092020-09-10 17:32:39 +02002816/**
Mark Horvathccaf7f82021-01-04 18:16:42 +01002817 * Copies a slot of the current image into SRAM.
Tamas Banfe031092020-09-10 17:32:39 +02002818 *
Mark Horvathccaf7f82021-01-04 18:16:42 +01002819 * @param state Boot loader status information.
Tamas Banfe031092020-09-10 17:32:39 +02002820 * @param slot The flash slot of the image to be copied to SRAM.
2821 * @param img_dst The address at which the image needs to be copied to
2822 * SRAM.
2823 * @param img_sz The size of the image that needs to be copied to SRAM.
2824 *
2825 * @return 0 on success; nonzero on failure.
2826 */
2827static int
Mark Horvathccaf7f82021-01-04 18:16:42 +01002828boot_copy_image_to_sram(struct boot_loader_state *state, int slot,
2829 uint32_t img_dst, uint32_t img_sz)
Tamas Banfe031092020-09-10 17:32:39 +02002830{
2831 int rc;
2832 const struct flash_area *fap_src = NULL;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002833 int area_id;
Tamas Banfe031092020-09-10 17:32:39 +02002834
Mark Horvathccaf7f82021-01-04 18:16:42 +01002835#if (BOOT_IMAGE_NUMBER == 1)
2836 (void)state;
2837#endif
2838
2839 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
2840
2841 rc = flash_area_open(area_id, &fap_src);
Tamas Banfe031092020-09-10 17:32:39 +02002842 if (rc != 0) {
2843 return BOOT_EFLASH;
2844 }
2845
2846 /* Direct copy from flash to its new location in SRAM. */
David Brown9bd7f902021-05-26 16:31:14 -06002847 rc = flash_area_read(fap_src, 0, (void *)(IMAGE_RAM_BASE + img_dst), img_sz);
Tamas Banfe031092020-09-10 17:32:39 +02002848 if (rc != 0) {
Antonio de Angelis48547002023-04-14 09:47:09 +01002849 BOOT_LOG_INF("Error whilst copying image %d from Flash to SRAM: %d",
2850 BOOT_CURR_IMG(state), rc);
Tamas Banfe031092020-09-10 17:32:39 +02002851 }
2852
2853 flash_area_close(fap_src);
2854
2855 return rc;
2856}
2857
Mark Horvathccaf7f82021-01-04 18:16:42 +01002858#if (BOOT_IMAGE_NUMBER > 1)
Tamas Banfe031092020-09-10 17:32:39 +02002859/**
Mark Horvathccaf7f82021-01-04 18:16:42 +01002860 * Checks if two memory regions (A and B) are overlap or not.
Tamas Banfe031092020-09-10 17:32:39 +02002861 *
Mark Horvathccaf7f82021-01-04 18:16:42 +01002862 * @param start_a Start of the A region.
2863 * @param end_a End of the A region.
2864 * @param start_b Start of the B region.
2865 * @param end_b End of the B region.
Tamas Banfe031092020-09-10 17:32:39 +02002866 *
Mark Horvathccaf7f82021-01-04 18:16:42 +01002867 * @return true if there is overlap; false otherwise.
2868 */
2869static bool
2870do_regions_overlap(uint32_t start_a, uint32_t end_a,
2871 uint32_t start_b, uint32_t end_b)
2872{
2873 if (start_b > end_a) {
2874 return false;
2875 } else if (start_b >= start_a) {
2876 return true;
2877 } else if (end_b > start_a) {
2878 return true;
2879 }
2880
2881 return false;
2882}
2883
2884/**
2885 * Checks if the image we want to load to memory overlap with an already
2886 * ramloaded image.
2887 *
Raef Colesfe57e7d2021-10-15 11:07:09 +01002888 * @param state Boot loader status information.
Mark Horvathccaf7f82021-01-04 18:16:42 +01002889 *
2890 * @return 0 if there is no overlap; nonzero otherwise.
Tamas Banfe031092020-09-10 17:32:39 +02002891 */
2892static int
Raef Colesfe57e7d2021-10-15 11:07:09 +01002893boot_check_ram_load_overlapping(struct boot_loader_state *state)
Tamas Banfe031092020-09-10 17:32:39 +02002894{
Mark Horvathccaf7f82021-01-04 18:16:42 +01002895 uint32_t i;
2896
2897 uint32_t start_a;
2898 uint32_t end_a;
2899 uint32_t start_b;
2900 uint32_t end_b;
Raef Colesfe57e7d2021-10-15 11:07:09 +01002901 uint32_t image_id_to_check = BOOT_CURR_IMG(state);
Mark Horvathccaf7f82021-01-04 18:16:42 +01002902
Raef Colesfe57e7d2021-10-15 11:07:09 +01002903 start_a = state->slot_usage[image_id_to_check].img_dst;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002904 /* Safe to add here, values are already verified in
2905 * boot_verify_ram_load_address() */
Raef Colesfe57e7d2021-10-15 11:07:09 +01002906 end_a = start_a + state->slot_usage[image_id_to_check].img_sz;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002907
2908 for (i = 0; i < BOOT_IMAGE_NUMBER; i++) {
Raef Colesfe57e7d2021-10-15 11:07:09 +01002909 if (state->slot_usage[i].active_slot == NO_ACTIVE_SLOT
Mark Horvathccaf7f82021-01-04 18:16:42 +01002910 || i == image_id_to_check) {
2911 continue;
2912 }
2913
Raef Colesfe57e7d2021-10-15 11:07:09 +01002914 start_b = state->slot_usage[i].img_dst;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002915 /* Safe to add here, values are already verified in
2916 * boot_verify_ram_load_address() */
Raef Colesfe57e7d2021-10-15 11:07:09 +01002917 end_b = start_b + state->slot_usage[i].img_sz;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002918
2919 if (do_regions_overlap(start_a, end_a, start_b, end_b)) {
2920 return -1;
2921 }
2922 }
2923
2924 return 0;
2925}
2926#endif
2927
2928/**
2929 * Loads the active slot of the current image into SRAM. The load address and
2930 * image size is extracted from the image header.
2931 *
2932 * @param state Boot loader status information.
Mark Horvathccaf7f82021-01-04 18:16:42 +01002933 *
2934 * @return 0 on success; nonzero on failure.
2935 */
2936static int
Raef Colesfe57e7d2021-10-15 11:07:09 +01002937boot_load_image_to_sram(struct boot_loader_state *state)
Mark Horvathccaf7f82021-01-04 18:16:42 +01002938{
2939 uint32_t active_slot;
2940 struct image_header *hdr = NULL;
2941 uint32_t img_dst;
2942 uint32_t img_sz;
Tamas Banfe031092020-09-10 17:32:39 +02002943 int rc;
2944
Raef Colesfe57e7d2021-10-15 11:07:09 +01002945 active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002946 hdr = boot_img_hdr(state, active_slot);
2947
Tamas Banfe031092020-09-10 17:32:39 +02002948 if (hdr->ih_flags & IMAGE_F_RAM_LOAD) {
2949
Mark Horvathccaf7f82021-01-04 18:16:42 +01002950 img_dst = hdr->ih_load_addr;
Tamas Banfe031092020-09-10 17:32:39 +02002951
Mark Horvathccaf7f82021-01-04 18:16:42 +01002952 rc = boot_read_image_size(state, active_slot, &img_sz);
Tamas Banfe031092020-09-10 17:32:39 +02002953 if (rc != 0) {
2954 return rc;
2955 }
2956
Raef Colesfe57e7d2021-10-15 11:07:09 +01002957 state->slot_usage[BOOT_CURR_IMG(state)].img_dst = img_dst;
2958 state->slot_usage[BOOT_CURR_IMG(state)].img_sz = img_sz;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002959
Raef Colesfe57e7d2021-10-15 11:07:09 +01002960 rc = boot_verify_ram_load_address(state);
Tamas Banfe031092020-09-10 17:32:39 +02002961 if (rc != 0) {
Antonio de Angelisba5fb1c2022-10-11 10:10:37 +01002962 BOOT_LOG_INF("Image %d RAM load address 0x%x is invalid.", BOOT_CURR_IMG(state), img_dst);
Tamas Banfe031092020-09-10 17:32:39 +02002963 return rc;
2964 }
2965
Mark Horvathccaf7f82021-01-04 18:16:42 +01002966#if (BOOT_IMAGE_NUMBER > 1)
Raef Colesfe57e7d2021-10-15 11:07:09 +01002967 rc = boot_check_ram_load_overlapping(state);
Mark Horvathccaf7f82021-01-04 18:16:42 +01002968 if (rc != 0) {
Antonio de Angelisba5fb1c2022-10-11 10:10:37 +01002969 BOOT_LOG_INF("Image %d RAM loading to address 0x%x would overlap with\
2970 another image.", BOOT_CURR_IMG(state), img_dst);
Mark Horvathccaf7f82021-01-04 18:16:42 +01002971 return rc;
2972 }
2973#endif
Hugo L'Hostisdb543e52021-03-09 18:00:31 +00002974#ifdef MCUBOOT_ENC_IMAGES
2975 /* decrypt image if encrypted and copy it to RAM */
2976 if (IS_ENCRYPTED(hdr)) {
2977 rc = boot_decrypt_and_copy_image_to_sram(state, active_slot, hdr, img_sz, img_dst);
2978 } else {
2979 rc = boot_copy_image_to_sram(state, active_slot, img_dst, img_sz);
2980 }
2981#else
Tamas Banfe031092020-09-10 17:32:39 +02002982 /* Copy image to the load address from where it currently resides in
2983 * flash.
2984 */
Mark Horvathccaf7f82021-01-04 18:16:42 +01002985 rc = boot_copy_image_to_sram(state, active_slot, img_dst, img_sz);
Hugo L'Hostisdb543e52021-03-09 18:00:31 +00002986#endif
Tamas Banfe031092020-09-10 17:32:39 +02002987 if (rc != 0) {
Antonio de Angelisba5fb1c2022-10-11 10:10:37 +01002988 BOOT_LOG_INF("Image %d RAM loading to 0x%x is failed.", BOOT_CURR_IMG(state), img_dst);
Tamas Banfe031092020-09-10 17:32:39 +02002989 } else {
Antonio de Angelisba5fb1c2022-10-11 10:10:37 +01002990 BOOT_LOG_INF("Image %d RAM loading to 0x%x is succeeded.", BOOT_CURR_IMG(state), img_dst);
Tamas Banfe031092020-09-10 17:32:39 +02002991 }
2992 } else {
2993 /* Only images that support IMAGE_F_RAM_LOAD are allowed if
2994 * MCUBOOT_RAM_LOAD is set.
2995 */
2996 rc = BOOT_EBADIMAGE;
2997 }
2998
Mark Horvathccaf7f82021-01-04 18:16:42 +01002999 if (rc != 0) {
Raef Colesfe57e7d2021-10-15 11:07:09 +01003000 state->slot_usage[BOOT_CURR_IMG(state)].img_dst = 0;
3001 state->slot_usage[BOOT_CURR_IMG(state)].img_sz = 0;
Mark Horvathccaf7f82021-01-04 18:16:42 +01003002 }
3003
Tamas Banfe031092020-09-10 17:32:39 +02003004 return rc;
3005}
3006
3007/**
3008 * Removes an image from SRAM, by overwriting it with zeros.
3009 *
Mark Horvathccaf7f82021-01-04 18:16:42 +01003010 * @param state Boot loader status information.
Mark Horvathccaf7f82021-01-04 18:16:42 +01003011 *
3012 * @return 0 on success; nonzero on failure.
3013 */
3014static inline int
Raef Colesfe57e7d2021-10-15 11:07:09 +01003015boot_remove_image_from_sram(struct boot_loader_state *state)
Mark Horvathccaf7f82021-01-04 18:16:42 +01003016{
David Brown695e5912021-05-24 16:58:01 -06003017 (void)state;
3018
Antonio de Angelisba5fb1c2022-10-11 10:10:37 +01003019 BOOT_LOG_INF("Removing image %d from SRAM at address 0x%x",
3020 BOOT_CURR_IMG(state),
Raef Colesfe57e7d2021-10-15 11:07:09 +01003021 state->slot_usage[BOOT_CURR_IMG(state)].img_dst);
Mark Horvathccaf7f82021-01-04 18:16:42 +01003022
Raef Colesfe57e7d2021-10-15 11:07:09 +01003023 memset((void*)(IMAGE_RAM_BASE + state->slot_usage[BOOT_CURR_IMG(state)].img_dst),
3024 0, state->slot_usage[BOOT_CURR_IMG(state)].img_sz);
Mark Horvathccaf7f82021-01-04 18:16:42 +01003025
Raef Colesfe57e7d2021-10-15 11:07:09 +01003026 state->slot_usage[BOOT_CURR_IMG(state)].img_dst = 0;
3027 state->slot_usage[BOOT_CURR_IMG(state)].img_sz = 0;
Mark Horvathccaf7f82021-01-04 18:16:42 +01003028
3029 return 0;
3030}
3031
3032/**
3033 * Removes an image from flash by erasing the corresponding flash area
3034 *
3035 * @param state Boot loader status information.
3036 * @param slot The flash slot of the image to be erased.
Tamas Banfe031092020-09-10 17:32:39 +02003037 *
3038 * @return 0 on success; nonzero on failure.
3039 */
3040static inline int
Mark Horvathccaf7f82021-01-04 18:16:42 +01003041boot_remove_image_from_flash(struct boot_loader_state *state, uint32_t slot)
Tamas Banfe031092020-09-10 17:32:39 +02003042{
Mark Horvathccaf7f82021-01-04 18:16:42 +01003043 int area_id;
3044 int rc;
3045 const struct flash_area *fap;
Tamas Banfe031092020-09-10 17:32:39 +02003046
David Brown695e5912021-05-24 16:58:01 -06003047 (void)state;
3048
Mark Horvathccaf7f82021-01-04 18:16:42 +01003049 BOOT_LOG_INF("Removing image %d slot %d from flash", BOOT_CURR_IMG(state),
3050 slot);
3051 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
3052 rc = flash_area_open(area_id, &fap);
3053 if (rc == 0) {
Dominik Ermel260ae092021-04-23 05:38:45 +00003054 flash_area_erase(fap, 0, flash_area_get_size(fap));
Dominik Ermel245de812022-09-02 13:39:23 +00003055 flash_area_close(fap);
Mark Horvathccaf7f82021-01-04 18:16:42 +01003056 }
3057
3058 return rc;
Tamas Banfe031092020-09-10 17:32:39 +02003059}
3060#endif /* MCUBOOT_RAM_LOAD */
3061
Mark Horvathccaf7f82021-01-04 18:16:42 +01003062
3063/**
3064 * Tries to load a slot for all the images with validation.
3065 *
3066 * @param state Boot loader status information.
Mark Horvathccaf7f82021-01-04 18:16:42 +01003067 *
3068 * @return 0 on success; nonzero on failure.
3069 */
Michael Grand5047f032022-11-24 16:49:56 +01003070fih_ret
Raef Colesfe57e7d2021-10-15 11:07:09 +01003071boot_load_and_validate_images(struct boot_loader_state *state)
Mark Horvathccaf7f82021-01-04 18:16:42 +01003072{
3073 uint32_t active_slot;
3074 int rc;
Michael Grand5047f032022-11-24 16:49:56 +01003075 fih_ret fih_rc;
Mark Horvathccaf7f82021-01-04 18:16:42 +01003076
3077 /* Go over all the images and try to load one */
3078 IMAGES_ITER(BOOT_CURR_IMG(state)) {
3079 /* All slots tried until a valid image found. Breaking from this loop
3080 * means that a valid image found or already loaded. If no slot is
3081 * found the function returns with error code. */
3082 while (true) {
Mark Horvathccaf7f82021-01-04 18:16:42 +01003083 /* Go over all the slots and try to load one */
Raef Colesfe57e7d2021-10-15 11:07:09 +01003084 active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot;
Mark Horvathccaf7f82021-01-04 18:16:42 +01003085 if (active_slot != NO_ACTIVE_SLOT){
3086 /* A slot is already active, go to next image. */
3087 break;
David Vinczee574f2d2020-07-10 11:42:03 +02003088 }
David Vincze505fba22020-10-22 13:53:29 +02003089
Raef Colesfe57e7d2021-10-15 11:07:09 +01003090 active_slot = find_slot_with_highest_version(state);
Mark Horvathccaf7f82021-01-04 18:16:42 +01003091 if (active_slot == NO_ACTIVE_SLOT) {
3092 BOOT_LOG_INF("No slot to load for image %d",
3093 BOOT_CURR_IMG(state));
3094 FIH_RET(FIH_FAILURE);
3095 }
3096
3097 /* Save the number of the active slot. */
Raef Colesfe57e7d2021-10-15 11:07:09 +01003098 state->slot_usage[BOOT_CURR_IMG(state)].active_slot = active_slot;
Mark Horvathccaf7f82021-01-04 18:16:42 +01003099
Raef Colesf11de642021-10-15 11:11:56 +01003100#if BOOT_IMAGE_NUMBER > 1
3101 if (state->img_mask[BOOT_CURR_IMG(state)]) {
3102 continue;
3103 }
3104#endif
3105
Mark Horvathccaf7f82021-01-04 18:16:42 +01003106#ifdef MCUBOOT_DIRECT_XIP
Raef Colesfe57e7d2021-10-15 11:07:09 +01003107 rc = boot_rom_address_check(state);
Mark Horvathccaf7f82021-01-04 18:16:42 +01003108 if (rc != 0) {
3109 /* The image is placed in an unsuitable slot. */
Raef Colesfe57e7d2021-10-15 11:07:09 +01003110 state->slot_usage[BOOT_CURR_IMG(state)].slot_available[active_slot] = false;
3111 state->slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT;
Mark Horvathccaf7f82021-01-04 18:16:42 +01003112 continue;
3113 }
George Becksteind4d90f82021-05-11 02:00:00 -04003114
David Vincze505fba22020-10-22 13:53:29 +02003115#ifdef MCUBOOT_DIRECT_XIP_REVERT
Raef Colesfe57e7d2021-10-15 11:07:09 +01003116 rc = boot_select_or_erase(state);
David Vincze505fba22020-10-22 13:53:29 +02003117 if (rc != 0) {
3118 /* The selected image slot has been erased. */
Raef Colesfe57e7d2021-10-15 11:07:09 +01003119 state->slot_usage[BOOT_CURR_IMG(state)].slot_available[active_slot] = false;
3120 state->slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT;
David Vincze505fba22020-10-22 13:53:29 +02003121 continue;
3122 }
3123#endif /* MCUBOOT_DIRECT_XIP_REVERT */
David Vincze1c456242021-06-29 15:25:24 +02003124#endif /* MCUBOOT_DIRECT_XIP */
David Vincze505fba22020-10-22 13:53:29 +02003125
Tamas Banfe031092020-09-10 17:32:39 +02003126#ifdef MCUBOOT_RAM_LOAD
3127 /* Image is first loaded to RAM and authenticated there in order to
3128 * prevent TOCTOU attack during image copy. This could be applied
3129 * when loading images from external (untrusted) flash to internal
3130 * (trusted) RAM and image is authenticated before copying.
3131 */
Raef Colesfe57e7d2021-10-15 11:07:09 +01003132 rc = boot_load_image_to_sram(state);
Tamas Banfe031092020-09-10 17:32:39 +02003133 if (rc != 0 ) {
Mark Horvathccaf7f82021-01-04 18:16:42 +01003134 /* Image cannot be ramloaded. */
3135 boot_remove_image_from_flash(state, active_slot);
Raef Colesfe57e7d2021-10-15 11:07:09 +01003136 state->slot_usage[BOOT_CURR_IMG(state)].slot_available[active_slot] = false;
3137 state->slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT;
Tamas Banfe031092020-09-10 17:32:39 +02003138 continue;
Tamas Banfe031092020-09-10 17:32:39 +02003139 }
3140#endif /* MCUBOOT_RAM_LOAD */
Mark Horvathccaf7f82021-01-04 18:16:42 +01003141
3142 FIH_CALL(boot_validate_slot, fih_rc, state, active_slot, NULL);
Michael Grand5047f032022-11-24 16:49:56 +01003143 if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
Mark Horvathccaf7f82021-01-04 18:16:42 +01003144 /* Image is invalid. */
Tamas Banfe031092020-09-10 17:32:39 +02003145#ifdef MCUBOOT_RAM_LOAD
Raef Colesfe57e7d2021-10-15 11:07:09 +01003146 boot_remove_image_from_sram(state);
Tamas Banfe031092020-09-10 17:32:39 +02003147#endif /* MCUBOOT_RAM_LOAD */
Raef Colesfe57e7d2021-10-15 11:07:09 +01003148 state->slot_usage[BOOT_CURR_IMG(state)].slot_available[active_slot] = false;
3149 state->slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT;
Mark Horvathccaf7f82021-01-04 18:16:42 +01003150 continue;
David Vincze505fba22020-10-22 13:53:29 +02003151 }
Mark Horvathccaf7f82021-01-04 18:16:42 +01003152
3153 /* Valid image loaded from a slot, go to next image. */
3154 break;
3155 }
3156 }
3157
3158 FIH_RET(FIH_SUCCESS);
3159}
3160
3161/**
3162 * Updates the security counter for the current image.
3163 *
3164 * @param state Boot loader status information.
Mark Horvathccaf7f82021-01-04 18:16:42 +01003165 *
3166 * @return 0 on success; nonzero on failure.
3167 */
3168static int
Raef Colesfe57e7d2021-10-15 11:07:09 +01003169boot_update_hw_rollback_protection(struct boot_loader_state *state)
Mark Horvathccaf7f82021-01-04 18:16:42 +01003170{
3171#ifdef MCUBOOT_HW_ROLLBACK_PROT
3172 int rc;
3173
3174 /* Update the stored security counter with the newer (active) image's
3175 * security counter value.
3176 */
David Vincze1c456242021-06-29 15:25:24 +02003177#if defined(MCUBOOT_DIRECT_XIP) && defined(MCUBOOT_DIRECT_XIP_REVERT)
Mark Horvathccaf7f82021-01-04 18:16:42 +01003178 /* When the 'revert' mechanism is enabled in direct-xip mode, the
3179 * security counter can be increased only after reboot, if the image
3180 * has been confirmed at runtime (the image_ok flag has been set).
3181 * This way a 'revert' can be performed when it's necessary.
3182 */
Raef Colesfe57e7d2021-10-15 11:07:09 +01003183 if (state->slot_usage[BOOT_CURR_IMG(state)].swap_state.image_ok == BOOT_FLAG_SET) {
David Vincze505fba22020-10-22 13:53:29 +02003184#endif
Sherry Zhang50b06ae2021-07-09 15:22:51 +08003185 rc = boot_update_security_counter(BOOT_CURR_IMG(state),
Raef Colesfe57e7d2021-10-15 11:07:09 +01003186 state->slot_usage[BOOT_CURR_IMG(state)].active_slot,
3187 boot_img_hdr(state, state->slot_usage[BOOT_CURR_IMG(state)].active_slot));
David Vinczee574f2d2020-07-10 11:42:03 +02003188 if (rc != 0) {
Antonio de Angelisba5fb1c2022-10-11 10:10:37 +01003189 BOOT_LOG_ERR("Security counter update failed after image %d validation.", BOOT_CURR_IMG(state));
Mark Horvathccaf7f82021-01-04 18:16:42 +01003190 return rc;
David Vinczee574f2d2020-07-10 11:42:03 +02003191 }
David Vincze1c456242021-06-29 15:25:24 +02003192#if defined(MCUBOOT_DIRECT_XIP) && defined(MCUBOOT_DIRECT_XIP_REVERT)
Mark Horvathccaf7f82021-01-04 18:16:42 +01003193 }
3194#endif
David Vinczee574f2d2020-07-10 11:42:03 +02003195
Mark Horvathccaf7f82021-01-04 18:16:42 +01003196 return 0;
David Vinczee574f2d2020-07-10 11:42:03 +02003197
Mark Horvathccaf7f82021-01-04 18:16:42 +01003198#else /* MCUBOOT_HW_ROLLBACK_PROT */
3199 (void) (state);
Mark Horvathccaf7f82021-01-04 18:16:42 +01003200 return 0;
3201#endif
3202}
3203
Michael Grand5047f032022-11-24 16:49:56 +01003204fih_ret
Mark Horvathccaf7f82021-01-04 18:16:42 +01003205context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp)
3206{
Mark Horvathccaf7f82021-01-04 18:16:42 +01003207 int rc;
Michael Grand5047f032022-11-24 16:49:56 +01003208 FIH_DECLARE(fih_rc, FIH_FAILURE);
Mark Horvathccaf7f82021-01-04 18:16:42 +01003209
Raef Colesfe57e7d2021-10-15 11:07:09 +01003210 rc = boot_get_slot_usage(state);
Mark Horvathccaf7f82021-01-04 18:16:42 +01003211 if (rc != 0) {
David Vinczee574f2d2020-07-10 11:42:03 +02003212 goto out;
3213 }
3214
Mark Horvathccaf7f82021-01-04 18:16:42 +01003215#if (BOOT_IMAGE_NUMBER > 1)
3216 while (true) {
3217#endif
Raef Colesfe57e7d2021-10-15 11:07:09 +01003218 FIH_CALL(boot_load_and_validate_images, fih_rc, state);
Michael Grand5047f032022-11-24 16:49:56 +01003219 if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
3220 FIH_SET(fih_rc, FIH_FAILURE);
Mark Horvathccaf7f82021-01-04 18:16:42 +01003221 goto out;
3222 }
3223
3224#if (BOOT_IMAGE_NUMBER > 1)
Raef Colesfe57e7d2021-10-15 11:07:09 +01003225 rc = boot_verify_dependencies(state);
Mark Horvathccaf7f82021-01-04 18:16:42 +01003226 if (rc != 0) {
3227 /* Dependency check failed for an image, it has been removed from
3228 * SRAM in case of MCUBOOT_RAM_LOAD strategy, and set to
3229 * unavailable. Try to load an image from another slot.
3230 */
3231 continue;
3232 }
3233 /* Dependency check was successful. */
3234 break;
3235 }
3236#endif
3237
3238 IMAGES_ITER(BOOT_CURR_IMG(state)) {
Raef Colesf11de642021-10-15 11:11:56 +01003239#if BOOT_IMAGE_NUMBER > 1
3240 if (state->img_mask[BOOT_CURR_IMG(state)]) {
3241 continue;
3242 }
3243#endif
Raef Colesfe57e7d2021-10-15 11:07:09 +01003244 rc = boot_update_hw_rollback_protection(state);
Mark Horvathccaf7f82021-01-04 18:16:42 +01003245 if (rc != 0) {
Michael Grand5047f032022-11-24 16:49:56 +01003246 FIH_SET(fih_rc, FIH_FAILURE);
Mark Horvathccaf7f82021-01-04 18:16:42 +01003247 goto out;
3248 }
3249
Jamie McCrae3016d002023-03-14 12:35:51 +00003250 rc = boot_add_shared_data(state, (uint8_t)state->slot_usage[BOOT_CURR_IMG(state)].active_slot);
Mark Horvathccaf7f82021-01-04 18:16:42 +01003251 if (rc != 0) {
Michael Grand5047f032022-11-24 16:49:56 +01003252 FIH_SET(fih_rc, FIH_FAILURE);
Mark Horvathccaf7f82021-01-04 18:16:42 +01003253 goto out;
3254 }
3255 }
3256
3257 /* All image loaded successfully. */
3258#ifdef MCUBOOT_HAVE_LOGGING
Raef Colesfe57e7d2021-10-15 11:07:09 +01003259 print_loaded_images(state);
Mark Horvathccaf7f82021-01-04 18:16:42 +01003260#endif
3261
Raef Colesfe57e7d2021-10-15 11:07:09 +01003262 fill_rsp(state, rsp);
Mark Horvathccaf7f82021-01-04 18:16:42 +01003263
David Vinczee574f2d2020-07-10 11:42:03 +02003264out:
Mark Horvathccaf7f82021-01-04 18:16:42 +01003265 close_all_flash_areas(state);
Raef Colese8fe6cf2020-05-26 13:07:40 +01003266
Michael Grand5047f032022-11-24 16:49:56 +01003267 if (rc != 0) {
3268 FIH_SET(fih_rc, FIH_FAILURE);
Mark Horvathccaf7f82021-01-04 18:16:42 +01003269 }
Raef Colese8fe6cf2020-05-26 13:07:40 +01003270
Mark Horvathccaf7f82021-01-04 18:16:42 +01003271 FIH_RET(fih_rc);
David Vinczee574f2d2020-07-10 11:42:03 +02003272}
Tamas Banfe031092020-09-10 17:32:39 +02003273#endif /* MCUBOOT_DIRECT_XIP || MCUBOOT_RAM_LOAD */
David Vinczee574f2d2020-07-10 11:42:03 +02003274
3275/**
Raef Colese8fe6cf2020-05-26 13:07:40 +01003276 * Prepares the booting process. This function moves images around in flash as
David Vinczee574f2d2020-07-10 11:42:03 +02003277 * appropriate, and tells you what address to boot from.
3278 *
3279 * @param rsp On success, indicates how booting should occur.
3280 *
Raef Colese8fe6cf2020-05-26 13:07:40 +01003281 * @return FIH_SUCCESS on success; nonzero on failure.
David Vinczee574f2d2020-07-10 11:42:03 +02003282 */
Michael Grand5047f032022-11-24 16:49:56 +01003283fih_ret
David Vinczee574f2d2020-07-10 11:42:03 +02003284boot_go(struct boot_rsp *rsp)
3285{
Michael Grand5047f032022-11-24 16:49:56 +01003286 FIH_DECLARE(fih_rc, FIH_FAILURE);
Raef Colesf11de642021-10-15 11:11:56 +01003287
3288 boot_state_clear(NULL);
3289
Raef Colese8fe6cf2020-05-26 13:07:40 +01003290 FIH_CALL(context_boot_go, fih_rc, &boot_data, rsp);
3291 FIH_RET(fih_rc);
David Vinczee574f2d2020-07-10 11:42:03 +02003292}
Raef Colesf11de642021-10-15 11:11:56 +01003293
3294/**
3295 * Prepares the booting process, considering only a single image. This function
3296 * moves images around in flash as appropriate, and tells you what address to
3297 * boot from.
3298 *
3299 * @param rsp On success, indicates how booting should occur.
3300 *
3301 * @param image_id The image ID to prepare the boot process for.
3302 *
3303 * @return FIH_SUCCESS on success; nonzero on failure.
3304 */
Michael Grand5047f032022-11-24 16:49:56 +01003305fih_ret
Raef Colesf11de642021-10-15 11:11:56 +01003306boot_go_for_image_id(struct boot_rsp *rsp, uint32_t image_id)
3307{
Michael Grand5047f032022-11-24 16:49:56 +01003308 FIH_DECLARE(fih_rc, FIH_FAILURE);
Raef Colesf11de642021-10-15 11:11:56 +01003309
3310 if (image_id >= BOOT_IMAGE_NUMBER) {
3311 FIH_RET(FIH_FAILURE);
3312 }
3313
3314#if BOOT_IMAGE_NUMBER > 1
3315 memset(&boot_data.img_mask, 1, BOOT_IMAGE_NUMBER);
3316 boot_data.img_mask[image_id] = 0;
3317#endif
3318
3319 FIH_CALL(context_boot_go, fih_rc, &boot_data, rsp);
3320 FIH_RET(fih_rc);
3321}
3322
3323/**
3324 * Clears the boot state, so that previous operations have no effect on new
3325 * ones.
3326 *
3327 * @param state The state that should be cleared. If the value
3328 * is NULL, the default bootloader state will be
3329 * cleared.
3330 */
3331void boot_state_clear(struct boot_loader_state *state)
3332{
3333 if (state != NULL) {
3334 memset(state, 0, sizeof(struct boot_loader_state));
3335 } else {
3336 memset(&boot_data, 0, sizeof(struct boot_loader_state));
3337 }
3338}
Jamie McCrae4f1ab9e2024-07-26 12:29:24 +01003339
3340#if defined(MCUBOOT_DATA_SHARING)
3341/**
3342* Fetches the maximum allowed size of the image
3343*/
3344const struct image_max_size *boot_get_max_app_size(void)
3345{
3346 return image_max_sizes;
3347}
3348#endif