blob: 3f07933889be3ca1dc8081ecb6fa2eaefc3cb6f4 [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 McCraee261b282024-07-26 11:48:19 +010066#if defined(MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO) || defined(MCUBOOT_DATA_SHARING)
Jamie McCrae4f1ab9e2024-07-26 12:29:24 +010067static struct image_max_size image_max_sizes[BOOT_IMAGE_NUMBER] = {0};
68#endif
69
Jamie McCraee261b282024-07-26 11:48:19 +010070#if !defined(__BOOTSIM__)
71/* Used for holding static buffers in multiple functions to work around issues
72 * in older versions of gcc (e.g. 4.8.4)
73 */
74struct sector_buffer_t {
75 boot_sector_t *primary;
76 boot_sector_t *secondary;
77#if MCUBOOT_SWAP_USING_SCRATCH
78 boot_sector_t *scratch;
79#endif
80};
81#endif
82
Fabio Utzigabec0732019-07-31 08:40:22 -030083#if (BOOT_IMAGE_NUMBER > 1)
84#define IMAGES_ITER(x) for ((x) = 0; (x) < BOOT_IMAGE_NUMBER; ++(x))
85#else
86#define IMAGES_ITER(x)
87#endif
88
Fabio Utzig10ee6482019-08-01 12:04:52 -030089/*
90 * This macro allows some control on the allocation of local variables.
91 * When running natively on a target, we don't want to allocated huge
92 * variables on the stack, so make them global instead. For the simulator
93 * we want to run as many threads as there are tests, and it's safer
94 * to just make those variables stack allocated.
95 */
96#if !defined(__BOOTSIM__)
97#define TARGET_STATIC static
98#else
99#define TARGET_STATIC
100#endif
101
Kristine Jassmann73c38c62021-02-03 16:56:14 +0000102#if BOOT_MAX_ALIGN > 1024
103#define BUF_SZ BOOT_MAX_ALIGN
104#else
105#define BUF_SZ 1024
106#endif
107
Dominik Ermelaafcbad2024-02-29 20:40:20 +0000108#define NO_ACTIVE_SLOT UINT32_MAX
109
David Vinczee574f2d2020-07-10 11:42:03 +0200110static int
111boot_read_image_headers(struct boot_loader_state *state, bool require_all,
112 struct boot_status *bs)
113{
114 int rc;
115 int i;
116
117 for (i = 0; i < BOOT_NUM_SLOTS; i++) {
Andrzej Puzdrowskib8f39692021-07-02 15:05:37 +0200118 rc = BOOT_HOOK_CALL(boot_read_image_header_hook, BOOT_HOOK_REGULAR,
119 BOOT_CURR_IMG(state), i, boot_img_hdr(state, i));
120 if (rc == BOOT_HOOK_REGULAR)
121 {
122 rc = boot_read_image_header(state, i, boot_img_hdr(state, i), bs);
123 }
David Vinczee574f2d2020-07-10 11:42:03 +0200124 if (rc != 0) {
125 /* If `require_all` is set, fail on any single fail, otherwise
126 * if at least the first slot's header was read successfully,
127 * then the boot loader can attempt a boot.
128 *
129 * Failure to read any headers is a fatal error.
130 */
131 if (i > 0 && !require_all) {
132 return 0;
133 } else {
134 return rc;
135 }
136 }
137 }
138
139 return 0;
140}
141
Mark Horvathccaf7f82021-01-04 18:16:42 +0100142/**
143 * Saves boot status and shared data for current image.
144 *
145 * @param state Boot loader status information.
146 * @param active_slot Index of the slot will be loaded for current image.
147 *
148 * @return 0 on success; nonzero on failure.
149 */
150static int
151boot_add_shared_data(struct boot_loader_state *state,
Jamie McCrae3016d002023-03-14 12:35:51 +0000152 uint8_t active_slot)
Mark Horvathccaf7f82021-01-04 18:16:42 +0100153{
154#if defined(MCUBOOT_MEASURED_BOOT) || defined(MCUBOOT_DATA_SHARING)
155 int rc;
156
157#ifdef MCUBOOT_MEASURED_BOOT
158 rc = boot_save_boot_status(BOOT_CURR_IMG(state),
159 boot_img_hdr(state, active_slot),
160 BOOT_IMG_AREA(state, active_slot));
161 if (rc != 0) {
162 BOOT_LOG_ERR("Failed to add image data to shared area");
163 return rc;
164 }
165#endif /* MCUBOOT_MEASURED_BOOT */
166
167#ifdef MCUBOOT_DATA_SHARING
168 rc = boot_save_shared_data(boot_img_hdr(state, active_slot),
Jamie McCrae3016d002023-03-14 12:35:51 +0000169 BOOT_IMG_AREA(state, active_slot),
Jamie McCrae4f1ab9e2024-07-26 12:29:24 +0100170 active_slot, image_max_sizes);
Mark Horvathccaf7f82021-01-04 18:16:42 +0100171 if (rc != 0) {
172 BOOT_LOG_ERR("Failed to add data to shared memory area.");
173 return rc;
174 }
175#endif /* MCUBOOT_DATA_SHARING */
176
177 return 0;
178
179#else /* MCUBOOT_MEASURED_BOOT || MCUBOOT_DATA_SHARING */
180 (void) (state);
181 (void) (active_slot);
182
183 return 0;
184#endif
185}
186
187/**
188 * Fills rsp to indicate how booting should occur.
189 *
190 * @param state Boot loader status information.
Mark Horvathccaf7f82021-01-04 18:16:42 +0100191 * @param rsp boot_rsp struct to fill.
192 */
193static void
Raef Colesfe57e7d2021-10-15 11:07:09 +0100194fill_rsp(struct boot_loader_state *state, struct boot_rsp *rsp)
Mark Horvathccaf7f82021-01-04 18:16:42 +0100195{
196 uint32_t active_slot;
197
198#if (BOOT_IMAGE_NUMBER > 1)
Raef Colesf11de642021-10-15 11:11:56 +0100199 /* Always boot from the first enabled image. */
Mark Horvathccaf7f82021-01-04 18:16:42 +0100200 BOOT_CURR_IMG(state) = 0;
Raef Colesf11de642021-10-15 11:11:56 +0100201 IMAGES_ITER(BOOT_CURR_IMG(state)) {
202 if (!state->img_mask[BOOT_CURR_IMG(state)]) {
203 break;
204 }
205 }
INFINEON\DovhalA94360d52023-01-18 17:21:56 +0200206 /* At least one image must be active, otherwise skip the execution */
207 if (BOOT_CURR_IMG(state) >= BOOT_IMAGE_NUMBER) {
208 return;
209 }
Mark Horvathccaf7f82021-01-04 18:16:42 +0100210#endif
211
212#if defined(MCUBOOT_DIRECT_XIP) || defined(MCUBOOT_RAM_LOAD)
Raef Colesfe57e7d2021-10-15 11:07:09 +0100213 active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot;
Mark Horvathccaf7f82021-01-04 18:16:42 +0100214#else
Mark Horvathccaf7f82021-01-04 18:16:42 +0100215 active_slot = BOOT_PRIMARY_SLOT;
216#endif
217
Dominik Ermel260ae092021-04-23 05:38:45 +0000218 rsp->br_flash_dev_id = flash_area_get_device_id(BOOT_IMG_AREA(state, active_slot));
Mark Horvathccaf7f82021-01-04 18:16:42 +0100219 rsp->br_image_off = boot_img_slot_off(state, active_slot);
220 rsp->br_hdr = boot_img_hdr(state, active_slot);
221}
222
223/**
224 * Closes all flash areas.
225 *
226 * @param state Boot loader status information.
227 */
228static void
229close_all_flash_areas(struct boot_loader_state *state)
230{
231 uint32_t slot;
232
233 IMAGES_ITER(BOOT_CURR_IMG(state)) {
Raef Colesf11de642021-10-15 11:11:56 +0100234#if BOOT_IMAGE_NUMBER > 1
235 if (state->img_mask[BOOT_CURR_IMG(state)]) {
236 continue;
237 }
238#endif
Mark Horvathccaf7f82021-01-04 18:16:42 +0100239#if MCUBOOT_SWAP_USING_SCRATCH
240 flash_area_close(BOOT_SCRATCH_AREA(state));
241#endif
242 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
243 flash_area_close(BOOT_IMG_AREA(state, BOOT_NUM_SLOTS - 1 - slot));
244 }
245 }
246}
247
Dominik Ermelaafcbad2024-02-29 20:40:20 +0000248#if (BOOT_IMAGE_NUMBER > 1) || \
249 defined(MCUBOOT_DIRECT_XIP) || \
250 defined(MCUBOOT_RAM_LOAD) || \
251 defined(MCUBOOT_DOWNGRADE_PREVENTION)
252/**
253 * Compare image version numbers
254 *
255 * By default, the comparison does not take build number into account.
256 * Enable MCUBOOT_VERSION_CMP_USE_BUILD_NUMBER to take the build number into account.
257 *
258 * @param ver1 Pointer to the first image version to compare.
259 * @param ver2 Pointer to the second image version to compare.
260 *
261 * @retval -1 If ver1 is less than ver2.
262 * @retval 0 If the image version numbers are equal.
263 * @retval 1 If ver1 is greater than ver2.
264 */
265static int
266boot_version_cmp(const struct image_version *ver1,
267 const struct image_version *ver2)
268{
269 if (ver1->iv_major > ver2->iv_major) {
270 return 1;
271 }
272 if (ver1->iv_major < ver2->iv_major) {
273 return -1;
274 }
275 /* The major version numbers are equal, continue comparison. */
276 if (ver1->iv_minor > ver2->iv_minor) {
277 return 1;
278 }
279 if (ver1->iv_minor < ver2->iv_minor) {
280 return -1;
281 }
282 /* The minor version numbers are equal, continue comparison. */
283 if (ver1->iv_revision > ver2->iv_revision) {
284 return 1;
285 }
286 if (ver1->iv_revision < ver2->iv_revision) {
287 return -1;
288 }
289
290#if defined(MCUBOOT_VERSION_CMP_USE_BUILD_NUMBER)
291 /* The revisions are equal, continue comparison. */
292 if (ver1->iv_build_num > ver2->iv_build_num) {
293 return 1;
294 }
295 if (ver1->iv_build_num < ver2->iv_build_num) {
296 return -1;
297 }
298#endif
299
300 return 0;
301}
302#endif
303
304
305#if (BOOT_IMAGE_NUMBER > 1)
306
307static int
308boot_verify_slot_dependencies(struct boot_loader_state *state, uint32_t slot);
309
310/**
311 * Check the image dependency whether it is satisfied and modify
312 * the swap type if necessary.
313 *
314 * @param dep Image dependency which has to be verified.
315 *
316 * @return 0 on success; nonzero on failure.
317 */
318static int
319boot_verify_slot_dependency(struct boot_loader_state *state,
320 struct image_dependency *dep)
321{
322 struct image_version *dep_version;
323 size_t dep_slot;
324 int rc;
325
326 /* Determine the source of the image which is the subject of
327 * the dependency and get it's version. */
328#if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)
329 uint8_t swap_type = state->swap_type[dep->image_id];
330 dep_slot = BOOT_IS_UPGRADE(swap_type) ? BOOT_SECONDARY_SLOT
331 : BOOT_PRIMARY_SLOT;
332#else
333 dep_slot = state->slot_usage[dep->image_id].active_slot;
334#endif
335
336 dep_version = &state->imgs[dep->image_id][dep_slot].hdr.ih_ver;
337
338 rc = boot_version_cmp(dep_version, &dep->image_min_version);
339#if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)
340 if (rc < 0) {
341 /* Dependency not satisfied.
342 * Modify the swap type to decrease the version number of the image
343 * (which will be located in the primary slot after the boot process),
344 * consequently the number of unsatisfied dependencies will be
345 * decreased or remain the same.
346 */
347 switch (BOOT_SWAP_TYPE(state)) {
348 case BOOT_SWAP_TYPE_TEST:
349 case BOOT_SWAP_TYPE_PERM:
350 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
351 break;
352 case BOOT_SWAP_TYPE_NONE:
353 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_REVERT;
354 break;
355 default:
356 break;
357 }
358 } else {
359 /* Dependency satisfied. */
360 rc = 0;
361 }
362#else
363 if (rc >= 0) {
364 /* Dependency satisfied. */
365 rc = 0;
366 }
367#endif
368
369 return rc;
370}
371
372#if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)
373/**
374 * Iterate over all the images and verify whether the image dependencies in the
375 * TLV area are all satisfied and update the related swap type if necessary.
376 */
377static int
378boot_verify_dependencies(struct boot_loader_state *state)
379{
380 int rc = -1;
381 uint8_t slot;
382
383 BOOT_CURR_IMG(state) = 0;
384 while (BOOT_CURR_IMG(state) < BOOT_IMAGE_NUMBER) {
385 if (state->img_mask[BOOT_CURR_IMG(state)]) {
386 BOOT_CURR_IMG(state)++;
387 continue;
388 }
389 if (BOOT_SWAP_TYPE(state) != BOOT_SWAP_TYPE_NONE &&
390 BOOT_SWAP_TYPE(state) != BOOT_SWAP_TYPE_FAIL) {
391 slot = BOOT_SECONDARY_SLOT;
392 } else {
393 slot = BOOT_PRIMARY_SLOT;
394 }
395
396 rc = boot_verify_slot_dependencies(state, slot);
397 if (rc == 0) {
398 /* All dependencies've been satisfied, continue with next image. */
399 BOOT_CURR_IMG(state)++;
400 } else {
401 /* Cannot upgrade due to non-met dependencies, so disable all
402 * image upgrades.
403 */
404 for (int idx = 0; idx < BOOT_IMAGE_NUMBER; idx++) {
405 BOOT_CURR_IMG(state) = idx;
406 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
407 }
408 break;
409 }
410 }
411 return rc;
412}
413#else
414
415#if defined MCUBOOT_RAM_LOAD
416static inline int
417boot_remove_image_from_sram(struct boot_loader_state *state);
418#endif
419
420/**
421 * Checks the dependency of all the active slots. If an image found with
422 * invalid or not satisfied dependencies the image is removed from SRAM (in
423 * case of MCUBOOT_RAM_LOAD strategy) and its slot is set to unavailable.
424 *
425 * @param state Boot loader status information.
426 *
427 * @return 0 if dependencies are met; nonzero otherwise.
428 */
429static int
430boot_verify_dependencies(struct boot_loader_state *state)
431{
432 int rc = -1;
433 uint32_t active_slot;
434
435 IMAGES_ITER(BOOT_CURR_IMG(state)) {
436 if (state->img_mask[BOOT_CURR_IMG(state)]) {
437 continue;
438 }
439 active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot;
440 rc = boot_verify_slot_dependencies(state, active_slot);
441 if (rc != 0) {
442 /* Dependencies not met or invalid dependencies. */
443
444#ifdef MCUBOOT_RAM_LOAD
445 boot_remove_image_from_sram(state);
446#endif /* MCUBOOT_RAM_LOAD */
447
448 state->slot_usage[BOOT_CURR_IMG(state)].slot_available[active_slot] = false;
449 state->slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT;
450
451 return rc;
452 }
453 }
454
455 return rc;
456}
457#endif
458
459/**
460 * Read all dependency TLVs of an image from the flash and verify
461 * one after another to see if they are all satisfied.
462 *
463 * @param slot Image slot number.
464 *
465 * @return 0 on success; nonzero on failure.
466 */
467static int
468boot_verify_slot_dependencies(struct boot_loader_state *state, uint32_t slot)
469{
470 const struct flash_area *fap;
471 struct image_tlv_iter it;
472 struct image_dependency dep;
473 uint32_t off;
474 uint16_t len;
475 int area_id;
476 int rc;
477
478 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
479 rc = flash_area_open(area_id, &fap);
480 if (rc != 0) {
481 rc = BOOT_EFLASH;
482 goto done;
483 }
484
485 rc = bootutil_tlv_iter_begin(&it, boot_img_hdr(state, slot), fap,
486 IMAGE_TLV_DEPENDENCY, true);
487 if (rc != 0) {
488 goto done;
489 }
490
491 while (true) {
492 rc = bootutil_tlv_iter_next(&it, &off, &len, NULL);
493 if (rc < 0) {
494 return -1;
495 } else if (rc > 0) {
496 rc = 0;
497 break;
498 }
499
500 if (len != sizeof(dep)) {
501 rc = BOOT_EBADIMAGE;
502 goto done;
503 }
504
505 rc = LOAD_IMAGE_DATA(boot_img_hdr(state, slot),
506 fap, off, &dep, len);
507 if (rc != 0) {
508 rc = BOOT_EFLASH;
509 goto done;
510 }
511
512 if (dep.image_id >= BOOT_IMAGE_NUMBER) {
513 rc = BOOT_EBADARGS;
514 goto done;
515 }
516
517 /* Verify dependency and modify the swap type if not satisfied. */
518 rc = boot_verify_slot_dependency(state, &dep);
519 if (rc != 0) {
520 /* Dependency not satisfied */
521 goto done;
522 }
523 }
524
525done:
526 flash_area_close(fap);
527 return rc;
528}
529
530#endif /* (BOOT_IMAGE_NUMBER > 1) */
531
Tamas Banfe031092020-09-10 17:32:39 +0200532#if !defined(MCUBOOT_DIRECT_XIP)
David Brownf5b33d82017-09-01 10:58:27 -0600533/*
534 * Compute the total size of the given image. Includes the size of
535 * the TLVs.
536 */
Tamas Banfe031092020-09-10 17:32:39 +0200537#if !defined(MCUBOOT_OVERWRITE_ONLY) || defined(MCUBOOT_OVERWRITE_ONLY_FAST)
David Brownf5b33d82017-09-01 10:58:27 -0600538static int
Fabio Utzigd638b172019-08-09 10:38:05 -0300539boot_read_image_size(struct boot_loader_state *state, int slot, uint32_t *size)
David Brownf5b33d82017-09-01 10:58:27 -0600540{
541 const struct flash_area *fap;
Fabio Utzig61fd8882019-09-14 20:00:20 -0300542 struct image_tlv_info info;
Fabio Utzig233af7d2019-08-26 12:06:16 -0300543 uint32_t off;
Fabio Utzige52c08e2019-09-11 19:32:00 -0300544 uint32_t protect_tlv_size;
David Brownf5b33d82017-09-01 10:58:27 -0600545 int area_id;
546 int rc;
547
Fabio Utzig10ee6482019-08-01 12:04:52 -0300548#if (BOOT_IMAGE_NUMBER == 1)
549 (void)state;
550#endif
551
552 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
David Brownf5b33d82017-09-01 10:58:27 -0600553 rc = flash_area_open(area_id, &fap);
554 if (rc != 0) {
555 rc = BOOT_EFLASH;
556 goto done;
557 }
558
Fabio Utzig61fd8882019-09-14 20:00:20 -0300559 off = BOOT_TLV_OFF(boot_img_hdr(state, slot));
560
561 if (flash_area_read(fap, off, &info, sizeof(info))) {
562 rc = BOOT_EFLASH;
David Brownf5b33d82017-09-01 10:58:27 -0600563 goto done;
564 }
Fabio Utzig61fd8882019-09-14 20:00:20 -0300565
Fabio Utzige52c08e2019-09-11 19:32:00 -0300566 protect_tlv_size = boot_img_hdr(state, slot)->ih_protect_tlv_size;
567 if (info.it_magic == IMAGE_TLV_PROT_INFO_MAGIC) {
568 if (protect_tlv_size != info.it_tlv_tot) {
569 rc = BOOT_EBADIMAGE;
570 goto done;
571 }
572
573 if (flash_area_read(fap, off + info.it_tlv_tot, &info, sizeof(info))) {
574 rc = BOOT_EFLASH;
575 goto done;
576 }
577 } else if (protect_tlv_size != 0) {
578 rc = BOOT_EBADIMAGE;
579 goto done;
580 }
581
Fabio Utzig61fd8882019-09-14 20:00:20 -0300582 if (info.it_magic != IMAGE_TLV_INFO_MAGIC) {
583 rc = BOOT_EBADIMAGE;
584 goto done;
585 }
586
Fabio Utzige52c08e2019-09-11 19:32:00 -0300587 *size = off + protect_tlv_size + info.it_tlv_tot;
David Brownf5b33d82017-09-01 10:58:27 -0600588 rc = 0;
589
590done:
591 flash_area_close(fap);
Fabio Utzig2eebf112017-09-04 15:25:08 -0300592 return rc;
David Brownf5b33d82017-09-01 10:58:27 -0600593}
Fabio Utzig36ec0e72017-09-05 08:10:33 -0300594#endif /* !MCUBOOT_OVERWRITE_ONLY */
David Brownf5b33d82017-09-01 10:58:27 -0600595
Tamas Banfe031092020-09-10 17:32:39 +0200596#if !defined(MCUBOOT_RAM_LOAD)
David Brownab449182019-11-15 09:32:52 -0700597static uint32_t
Fabio Utzig10ee6482019-08-01 12:04:52 -0300598boot_write_sz(struct boot_loader_state *state)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800599{
David Brownab449182019-11-15 09:32:52 -0700600 uint32_t elem_sz;
Fabio Utzig12d59162019-11-28 10:01:59 -0300601#if MCUBOOT_SWAP_USING_SCRATCH
David Brownab449182019-11-15 09:32:52 -0700602 uint32_t align;
Fabio Utzig12d59162019-11-28 10:01:59 -0300603#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800604
605 /* Figure out what size to write update status update as. The size depends
606 * on what the minimum write size is for scratch area, active image slot.
607 * We need to use the bigger of those 2 values.
608 */
Fabio Utzig10ee6482019-08-01 12:04:52 -0300609 elem_sz = flash_area_align(BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT));
Fabio Utzig12d59162019-11-28 10:01:59 -0300610#if MCUBOOT_SWAP_USING_SCRATCH
Fabio Utzig10ee6482019-08-01 12:04:52 -0300611 align = flash_area_align(BOOT_SCRATCH_AREA(state));
Christopher Collins92ea77f2016-12-12 15:59:26 -0800612 if (align > elem_sz) {
613 elem_sz = align;
614 }
Fabio Utzig12d59162019-11-28 10:01:59 -0300615#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800616
617 return elem_sz;
618}
619
Fabio Utzig10ee6482019-08-01 12:04:52 -0300620static int
621boot_initialize_area(struct boot_loader_state *state, int flash_area)
622{
Dominik Ermel51c8d762021-05-24 15:34:01 +0000623 uint32_t num_sectors = BOOT_MAX_IMG_SECTORS;
624 boot_sector_t *out_sectors;
625 uint32_t *out_num_sectors;
Fabio Utzig10ee6482019-08-01 12:04:52 -0300626 int rc;
627
628 num_sectors = BOOT_MAX_IMG_SECTORS;
629
630 if (flash_area == FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state))) {
631 out_sectors = BOOT_IMG(state, BOOT_PRIMARY_SLOT).sectors;
632 out_num_sectors = &BOOT_IMG(state, BOOT_PRIMARY_SLOT).num_sectors;
633 } else if (flash_area == FLASH_AREA_IMAGE_SECONDARY(BOOT_CURR_IMG(state))) {
634 out_sectors = BOOT_IMG(state, BOOT_SECONDARY_SLOT).sectors;
635 out_num_sectors = &BOOT_IMG(state, BOOT_SECONDARY_SLOT).num_sectors;
Fabio Utzig12d59162019-11-28 10:01:59 -0300636#if MCUBOOT_SWAP_USING_SCRATCH
Fabio Utzig10ee6482019-08-01 12:04:52 -0300637 } else if (flash_area == FLASH_AREA_IMAGE_SCRATCH) {
638 out_sectors = state->scratch.sectors;
639 out_num_sectors = &state->scratch.num_sectors;
Fabio Utzig12d59162019-11-28 10:01:59 -0300640#endif
Fabio Utzig10ee6482019-08-01 12:04:52 -0300641 } else {
642 return BOOT_EFLASH;
643 }
644
Dominik Ermel51c8d762021-05-24 15:34:01 +0000645#ifdef MCUBOOT_USE_FLASH_AREA_GET_SECTORS
Fabio Utzig10ee6482019-08-01 12:04:52 -0300646 rc = flash_area_get_sectors(flash_area, &num_sectors, out_sectors);
Dominik Ermel51c8d762021-05-24 15:34:01 +0000647#else
648 _Static_assert(sizeof(int) <= sizeof(uint32_t), "Fix needed");
649 rc = flash_area_to_sectors(flash_area, (int *)&num_sectors, out_sectors);
650#endif /* defined(MCUBOOT_USE_FLASH_AREA_GET_SECTORS) */
Fabio Utzig10ee6482019-08-01 12:04:52 -0300651 if (rc != 0) {
652 return rc;
653 }
654 *out_num_sectors = num_sectors;
655 return 0;
656}
Fabio Utzig10ee6482019-08-01 12:04:52 -0300657
Christopher Collins92ea77f2016-12-12 15:59:26 -0800658/**
659 * Determines the sector layout of both image slots and the scratch area.
660 * This information is necessary for calculating the number of bytes to erase
661 * and copy during an image swap. The information collected during this
Fabio Utzig10ee6482019-08-01 12:04:52 -0300662 * function is used to populate the state.
Christopher Collins92ea77f2016-12-12 15:59:26 -0800663 */
664static int
Fabio Utzig10ee6482019-08-01 12:04:52 -0300665boot_read_sectors(struct boot_loader_state *state)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800666{
Fabio Utzigb0f04732019-07-31 09:49:19 -0300667 uint8_t image_index;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800668 int rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800669
Fabio Utzig10ee6482019-08-01 12:04:52 -0300670 image_index = BOOT_CURR_IMG(state);
Fabio Utzigb0f04732019-07-31 09:49:19 -0300671
672 rc = boot_initialize_area(state, FLASH_AREA_IMAGE_PRIMARY(image_index));
Christopher Collins92ea77f2016-12-12 15:59:26 -0800673 if (rc != 0) {
674 return BOOT_EFLASH;
675 }
676
Fabio Utzig10ee6482019-08-01 12:04:52 -0300677 rc = boot_initialize_area(state, FLASH_AREA_IMAGE_SECONDARY(image_index));
Christopher Collins92ea77f2016-12-12 15:59:26 -0800678 if (rc != 0) {
Andrzej Puzdrowski54b4ad92021-06-22 13:21:22 +0200679 /* We need to differentiate from the primary image issue */
680 return BOOT_EFLASH_SEC;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800681 }
682
Fabio Utzig12d59162019-11-28 10:01:59 -0300683#if MCUBOOT_SWAP_USING_SCRATCH
Fabio Utzig10ee6482019-08-01 12:04:52 -0300684 rc = boot_initialize_area(state, FLASH_AREA_IMAGE_SCRATCH);
Fabio Utzig2bd980a2018-11-26 10:38:17 -0200685 if (rc != 0) {
686 return BOOT_EFLASH;
687 }
Fabio Utzig12d59162019-11-28 10:01:59 -0300688#endif
Fabio Utzig2bd980a2018-11-26 10:38:17 -0200689
Fabio Utzig10ee6482019-08-01 12:04:52 -0300690 BOOT_WRITE_SZ(state) = boot_write_sz(state);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800691
692 return 0;
693}
694
Fabio Utzig12d59162019-11-28 10:01:59 -0300695void
696boot_status_reset(struct boot_status *bs)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800697{
Fabio Utzig4741c452019-12-19 15:32:41 -0300698#ifdef MCUBOOT_ENC_IMAGES
Kristine Jassmann73c38c62021-02-03 16:56:14 +0000699 memset(&bs->enckey, 0xff, BOOT_NUM_SLOTS * BOOT_ENC_KEY_ALIGN_SIZE);
Fabio Utzig4741c452019-12-19 15:32:41 -0300700#if MCUBOOT_SWAP_SAVE_ENCTLV
701 memset(&bs->enctlv, 0xff, BOOT_NUM_SLOTS * BOOT_ENC_TLV_ALIGN_SIZE);
702#endif
703#endif /* MCUBOOT_ENC_IMAGES */
704
705 bs->use_scratch = 0;
706 bs->swap_size = 0;
707 bs->source = 0;
708
Fabio Utzig74aef312019-11-28 11:05:34 -0300709 bs->op = BOOT_STATUS_OP_MOVE;
Fabio Utzig39000012018-07-30 12:40:20 -0300710 bs->idx = BOOT_STATUS_IDX_0;
711 bs->state = BOOT_STATUS_STATE_0;
Christopher Collinsa1c12042019-05-23 14:00:28 -0700712 bs->swap_type = BOOT_SWAP_TYPE_NONE;
Fabio Utzig12d59162019-11-28 10:01:59 -0300713}
Christopher Collins92ea77f2016-12-12 15:59:26 -0800714
Fabio Utzig12d59162019-11-28 10:01:59 -0300715bool
716boot_status_is_reset(const struct boot_status *bs)
717{
Fabio Utzig74aef312019-11-28 11:05:34 -0300718 return (bs->op == BOOT_STATUS_OP_MOVE &&
719 bs->idx == BOOT_STATUS_IDX_0 &&
720 bs->state == BOOT_STATUS_STATE_0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800721}
722
723/**
724 * Writes the supplied boot status to the flash file system. The boot status
725 * contains the current state of an in-progress image copy operation.
726 *
727 * @param bs The boot status to write.
728 *
729 * @return 0 on success; nonzero on failure.
730 */
731int
Fabio Utzig12d59162019-11-28 10:01:59 -0300732boot_write_status(const struct boot_loader_state *state, struct boot_status *bs)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800733{
734 const struct flash_area *fap;
735 uint32_t off;
736 int area_id;
Dominik Ermel9479af02021-10-19 10:06:44 +0000737 int rc = 0;
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300738 uint8_t buf[BOOT_MAX_ALIGN];
Gustavo Henrique Nihei4aa286d2021-11-24 14:54:56 -0300739 uint32_t align;
Fabio Utzig39000012018-07-30 12:40:20 -0300740 uint8_t erased_val;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800741
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300742 /* NOTE: The first sector copied (that is the last sector on slot) contains
David Vincze2d736ad2019-02-18 11:50:22 +0100743 * the trailer. Since in the last step the primary slot is erased, the
744 * first two status writes go to the scratch which will be copied to
745 * the primary slot!
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300746 */
747
Fabio Utzig12d59162019-11-28 10:01:59 -0300748#if MCUBOOT_SWAP_USING_SCRATCH
Fabio Utzig2473ac02017-05-02 12:45:02 -0300749 if (bs->use_scratch) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800750 /* Write to scratch. */
751 area_id = FLASH_AREA_IMAGE_SCRATCH;
752 } else {
Fabio Utzig12d59162019-11-28 10:01:59 -0300753#endif
David Vincze2d736ad2019-02-18 11:50:22 +0100754 /* Write to the primary slot. */
Fabio Utzig10ee6482019-08-01 12:04:52 -0300755 area_id = FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state));
Fabio Utzig12d59162019-11-28 10:01:59 -0300756#if MCUBOOT_SWAP_USING_SCRATCH
Christopher Collins92ea77f2016-12-12 15:59:26 -0800757 }
Fabio Utzig12d59162019-11-28 10:01:59 -0300758#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800759
760 rc = flash_area_open(area_id, &fap);
761 if (rc != 0) {
Dominik Ermel9479af02021-10-19 10:06:44 +0000762 return BOOT_EFLASH;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800763 }
764
765 off = boot_status_off(fap) +
Fabio Utzig12d59162019-11-28 10:01:59 -0300766 boot_status_internal_off(bs, BOOT_WRITE_SZ(state));
Andrzej Puzdrowskib788c712018-04-12 12:42:49 +0200767 align = flash_area_align(fap);
Fabio Utzig39000012018-07-30 12:40:20 -0300768 erased_val = flash_area_erased_val(fap);
769 memset(buf, erased_val, BOOT_MAX_ALIGN);
David Brown9d725462017-01-23 15:50:58 -0700770 buf[0] = bs->state;
771
Jamie McCrae35e99312024-01-03 07:37:55 +0000772 BOOT_LOG_DBG("writing swap status; fa_id=%d off=0x%lx (0x%lx)",
773 flash_area_get_id(fap), (unsigned long)off,
774 (unsigned long)flash_area_get_off(fap) + off);
775
David Brown9d725462017-01-23 15:50:58 -0700776 rc = flash_area_write(fap, off, buf, align);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800777 if (rc != 0) {
778 rc = BOOT_EFLASH;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800779 }
780
Christopher Collins92ea77f2016-12-12 15:59:26 -0800781 flash_area_close(fap);
Dominik Ermel9479af02021-10-19 10:06:44 +0000782
Christopher Collins92ea77f2016-12-12 15:59:26 -0800783 return rc;
784}
Tamas Banfe031092020-09-10 17:32:39 +0200785#endif /* !MCUBOOT_RAM_LOAD */
David Vinczee574f2d2020-07-10 11:42:03 +0200786#endif /* !MCUBOOT_DIRECT_XIP */
Christopher Collins92ea77f2016-12-12 15:59:26 -0800787
788/*
David Vinczec3084132020-02-18 14:50:47 +0100789 * Validate image hash/signature and optionally the security counter in a slot.
Christopher Collins92ea77f2016-12-12 15:59:26 -0800790 */
Michael Grand5047f032022-11-24 16:49:56 +0100791static fih_ret
Fabio Utzig10ee6482019-08-01 12:04:52 -0300792boot_image_check(struct boot_loader_state *state, struct image_header *hdr,
793 const struct flash_area *fap, struct boot_status *bs)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800794{
Fabio Utzig10ee6482019-08-01 12:04:52 -0300795 TARGET_STATIC uint8_t tmpbuf[BOOT_TMPBUF_SZ];
Fabio Utzigba829042018-09-18 08:29:34 -0300796 int rc;
Michael Grand5047f032022-11-24 16:49:56 +0100797 FIH_DECLARE(fih_rc, FIH_FAILURE);
Fabio Utzigba829042018-09-18 08:29:34 -0300798
Fabio Utzig10ee6482019-08-01 12:04:52 -0300799#if (BOOT_IMAGE_NUMBER == 1)
800 (void)state;
801#endif
802
Fabio Utzigba829042018-09-18 08:29:34 -0300803 (void)bs;
804 (void)rc;
Fabio Utzigbc077932019-08-26 11:16:34 -0300805
Hugo L'Hostisdb543e52021-03-09 18:00:31 +0000806/* In the case of ram loading the image has already been decrypted as it is
807 * decrypted when copied in ram */
808#if defined(MCUBOOT_ENC_IMAGES) && !defined(MCUBOOT_RAM_LOAD)
Dominik Ermel7f9ac972024-07-12 19:21:40 +0000809 if (MUST_DECRYPT(fap, BOOT_CURR_IMG(state), hdr)) {
810 rc = boot_enc_load(BOOT_CURR_ENC(state), 1, hdr, fap, bs);
Fabio Utzigba829042018-09-18 08:29:34 -0300811 if (rc < 0) {
Raef Colese8fe6cf2020-05-26 13:07:40 +0100812 FIH_RET(fih_rc);
Fabio Utzigba829042018-09-18 08:29:34 -0300813 }
Fabio Utzig4741c452019-12-19 15:32:41 -0300814 if (rc == 0 && boot_enc_set_key(BOOT_CURR_ENC(state), 1, bs)) {
Raef Colese8fe6cf2020-05-26 13:07:40 +0100815 FIH_RET(fih_rc);
Fabio Utzigba829042018-09-18 08:29:34 -0300816 }
817 }
Fabio Utzigbc077932019-08-26 11:16:34 -0300818#endif
819
Dominik Ermel7f9ac972024-07-12 19:21:40 +0000820 FIH_CALL(bootutil_img_validate, fih_rc, BOOT_CURR_ENC(state),
821 BOOT_CURR_IMG(state), hdr, fap, tmpbuf, BOOT_TMPBUF_SZ,
822 NULL, 0, NULL);
Fabio Utzig10ee6482019-08-01 12:04:52 -0300823
Raef Colese8fe6cf2020-05-26 13:07:40 +0100824 FIH_RET(fih_rc);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800825}
826
Tamas Banfe031092020-09-10 17:32:39 +0200827#if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)
Michael Grand5047f032022-11-24 16:49:56 +0100828static fih_ret
Christopher Collins92ea77f2016-12-12 15:59:26 -0800829split_image_check(struct image_header *app_hdr,
830 const struct flash_area *app_fap,
831 struct image_header *loader_hdr,
832 const struct flash_area *loader_fap)
833{
834 static void *tmpbuf;
835 uint8_t loader_hash[32];
Michael Grand5047f032022-11-24 16:49:56 +0100836 FIH_DECLARE(fih_rc, FIH_FAILURE);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800837
838 if (!tmpbuf) {
839 tmpbuf = malloc(BOOT_TMPBUF_SZ);
840 if (!tmpbuf) {
Raef Colese8fe6cf2020-05-26 13:07:40 +0100841 goto out;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800842 }
843 }
844
Raef Colese8fe6cf2020-05-26 13:07:40 +0100845 FIH_CALL(bootutil_img_validate, fih_rc, NULL, 0, loader_hdr, loader_fap,
846 tmpbuf, BOOT_TMPBUF_SZ, NULL, 0, loader_hash);
Michael Grand5047f032022-11-24 16:49:56 +0100847 if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
Raef Colese8fe6cf2020-05-26 13:07:40 +0100848 FIH_RET(fih_rc);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800849 }
850
Raef Colese8fe6cf2020-05-26 13:07:40 +0100851 FIH_CALL(bootutil_img_validate, fih_rc, NULL, 0, app_hdr, app_fap,
852 tmpbuf, BOOT_TMPBUF_SZ, loader_hash, 32, NULL);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800853
Raef Colese8fe6cf2020-05-26 13:07:40 +0100854out:
855 FIH_RET(fih_rc);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800856}
Tamas Banfe031092020-09-10 17:32:39 +0200857#endif /* !MCUBOOT_DIRECT_XIP && !MCUBOOT_RAM_LOAD */
Christopher Collins92ea77f2016-12-12 15:59:26 -0800858
Fabio Utzig338a19f2018-12-03 08:37:08 -0200859/*
David Brown9bf95af2019-10-10 15:36:36 -0600860 * Check that this is a valid header. Valid means that the magic is
861 * correct, and that the sizes/offsets are "sane". Sane means that
862 * there is no overflow on the arithmetic, and that the result fits
Jamie McCrae206c7e72024-08-23 08:13:26 +0100863 * within the flash area we are in. Also check the flags in the image
864 * and class the image as invalid if flags for encryption/compression
865 * are present but these features are not enabled.
David Brown9bf95af2019-10-10 15:36:36 -0600866 */
867static bool
Jamie McCraedbb5c782024-08-22 10:43:14 +0100868boot_is_header_valid(const struct image_header *hdr, const struct flash_area *fap,
869 struct boot_loader_state *state)
David Brown9bf95af2019-10-10 15:36:36 -0600870{
871 uint32_t size;
872
Jamie McCraedbb5c782024-08-22 10:43:14 +0100873 (void)state;
874
David Brown9bf95af2019-10-10 15:36:36 -0600875 if (hdr->ih_magic != IMAGE_MAGIC) {
876 return false;
877 }
878
879 if (!boot_u32_safe_add(&size, hdr->ih_img_size, hdr->ih_hdr_size)) {
880 return false;
881 }
882
Jamie McCraefeb92652024-08-23 08:16:47 +0100883#ifdef MCUBOOT_DECOMPRESS_IMAGES
884 if (!MUST_DECOMPRESS(fap, BOOT_CURR_IMG(state), hdr)) {
885#else
886 if (1) {
887#endif
888 if (!boot_u32_safe_add(&size, size, hdr->ih_protect_tlv_size)) {
889 return false;
890 }
891 }
892
Dominik Ermel260ae092021-04-23 05:38:45 +0000893 if (size >= flash_area_get_size(fap)) {
David Brown9bf95af2019-10-10 15:36:36 -0600894 return false;
895 }
896
Jamie McCrae206c7e72024-08-23 08:13:26 +0100897#if !defined(MCUBOOT_ENC_IMAGES)
898 if (IS_ENCRYPTED(hdr)) {
899 return false;
900 }
Jamie McCrae4d85e292024-08-23 08:25:24 +0100901#else
902 if ((hdr->ih_flags & IMAGE_F_ENCRYPTED_AES128) &&
903 (hdr->ih_flags & IMAGE_F_ENCRYPTED_AES256))
904 {
905 return false;
906 }
Jamie McCrae206c7e72024-08-23 08:13:26 +0100907#endif
908
909#if !defined(MCUBOOT_DECOMPRESS_IMAGES)
910 if (IS_COMPRESSED(hdr)) {
911 return false;
912 }
Jamie McCrae4d85e292024-08-23 08:25:24 +0100913#else
914 if ((hdr->ih_flags & IMAGE_F_COMPRESSED_LZMA1) &&
915 (hdr->ih_flags & IMAGE_F_COMPRESSED_LZMA2))
916 {
917 return false;
918 }
Jamie McCrae206c7e72024-08-23 08:13:26 +0100919#endif
920
David Brown9bf95af2019-10-10 15:36:36 -0600921 return true;
922}
923
924/*
Fabio Utzig338a19f2018-12-03 08:37:08 -0200925 * Check that a memory area consists of a given value.
926 */
927static inline bool
928boot_data_is_set_to(uint8_t val, void *data, size_t len)
Fabio Utzig39000012018-07-30 12:40:20 -0300929{
930 uint8_t i;
Fabio Utzig338a19f2018-12-03 08:37:08 -0200931 uint8_t *p = (uint8_t *)data;
932 for (i = 0; i < len; i++) {
933 if (val != p[i]) {
934 return false;
Fabio Utzig39000012018-07-30 12:40:20 -0300935 }
936 }
Fabio Utzig338a19f2018-12-03 08:37:08 -0200937 return true;
938}
939
940static int
Fabio Utzig10ee6482019-08-01 12:04:52 -0300941boot_check_header_erased(struct boot_loader_state *state, int slot)
Fabio Utzig338a19f2018-12-03 08:37:08 -0200942{
943 const struct flash_area *fap;
944 struct image_header *hdr;
945 uint8_t erased_val;
Fabio Utzigb0f04732019-07-31 09:49:19 -0300946 int area_id;
Fabio Utzig338a19f2018-12-03 08:37:08 -0200947 int rc;
948
Fabio Utzig10ee6482019-08-01 12:04:52 -0300949 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
Fabio Utzigb0f04732019-07-31 09:49:19 -0300950 rc = flash_area_open(area_id, &fap);
Fabio Utzig338a19f2018-12-03 08:37:08 -0200951 if (rc != 0) {
952 return -1;
953 }
954
955 erased_val = flash_area_erased_val(fap);
956 flash_area_close(fap);
957
Fabio Utzig10ee6482019-08-01 12:04:52 -0300958 hdr = boot_img_hdr(state, slot);
Fabio Utzig338a19f2018-12-03 08:37:08 -0200959 if (!boot_data_is_set_to(erased_val, &hdr->ih_magic, sizeof(hdr->ih_magic))) {
960 return -1;
961 }
962
963 return 0;
Fabio Utzig39000012018-07-30 12:40:20 -0300964}
965
Dominik Ermel0c8c8d52021-02-17 14:45:02 +0000966#if defined(MCUBOOT_DIRECT_XIP)
967/**
968 * Check if image in slot has been set with specific ROM address to run from
969 * and whether the slot starts at that address.
970 *
971 * @returns 0 if IMAGE_F_ROM_FIXED flag is not set;
972 * 0 if IMAGE_F_ROM_FIXED flag is set and ROM address specified in
973 * header matches the slot address;
974 * 1 if IMF_F_ROM_FIXED flag is set but ROM address specified in header
975 * does not match the slot address.
976 */
977static bool
Raef Colesfe57e7d2021-10-15 11:07:09 +0100978boot_rom_address_check(struct boot_loader_state *state)
Dominik Ermel0c8c8d52021-02-17 14:45:02 +0000979{
Mark Horvathccaf7f82021-01-04 18:16:42 +0100980 uint32_t active_slot;
981 const struct image_header *hdr;
982 uint32_t f_off;
983
Raef Colesfe57e7d2021-10-15 11:07:09 +0100984 active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot;
Mark Horvathccaf7f82021-01-04 18:16:42 +0100985 hdr = boot_img_hdr(state, active_slot);
986 f_off = boot_img_slot_off(state, active_slot);
987
Dominik Ermel0c8c8d52021-02-17 14:45:02 +0000988 if (hdr->ih_flags & IMAGE_F_ROM_FIXED && hdr->ih_load_addr != f_off) {
989 BOOT_LOG_WRN("Image in %s slot at 0x%x has been built for offset 0x%x"\
Mark Horvathccaf7f82021-01-04 18:16:42 +0100990 ", skipping",
991 active_slot == 0 ? "primary" : "secondary", f_off,
Dominik Ermel0c8c8d52021-02-17 14:45:02 +0000992 hdr->ih_load_addr);
993
994 /* If there is address mismatch, the image is not bootable from this
995 * slot.
996 */
997 return 1;
998 }
999 return 0;
1000}
1001#endif
1002
Fabio Utzigb1adb1e2019-09-11 11:42:53 -03001003/*
1004 * Check that there is a valid image in a slot
1005 *
1006 * @returns
Raef Colese8fe6cf2020-05-26 13:07:40 +01001007 * FIH_SUCCESS if image was successfully validated
Michael Grand5047f032022-11-24 16:49:56 +01001008 * FIH_NO_BOOTABLE_IMAGE if no bootloable image was found
Raef Colese8fe6cf2020-05-26 13:07:40 +01001009 * FIH_FAILURE on any errors
Fabio Utzigb1adb1e2019-09-11 11:42:53 -03001010 */
Michael Grand5047f032022-11-24 16:49:56 +01001011static fih_ret
Fabio Utzig10ee6482019-08-01 12:04:52 -03001012boot_validate_slot(struct boot_loader_state *state, int slot,
1013 struct boot_status *bs)
Christopher Collins92ea77f2016-12-12 15:59:26 -08001014{
1015 const struct flash_area *fap;
Marti Bolivarf804f622017-06-12 15:41:48 -04001016 struct image_header *hdr;
Fabio Utzigb0f04732019-07-31 09:49:19 -03001017 int area_id;
Michael Grand5047f032022-11-24 16:49:56 +01001018 FIH_DECLARE(fih_rc, FIH_FAILURE);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001019 int rc;
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001020
Fabio Utzig10ee6482019-08-01 12:04:52 -03001021 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
Fabio Utzigb0f04732019-07-31 09:49:19 -03001022 rc = flash_area_open(area_id, &fap);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001023 if (rc != 0) {
Raef Colese8fe6cf2020-05-26 13:07:40 +01001024 FIH_RET(fih_rc);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001025 }
1026
Fabio Utzig10ee6482019-08-01 12:04:52 -03001027 hdr = boot_img_hdr(state, slot);
1028 if (boot_check_header_erased(state, slot) == 0 ||
1029 (hdr->ih_flags & IMAGE_F_NON_BOOTABLE)) {
Fabio Utzig260ec452020-07-09 18:40:07 -03001030
1031#if defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SWAP_USING_MOVE)
1032 /*
1033 * This fixes an issue where an image might be erased, but a trailer
1034 * be left behind. It can happen if the image is in the secondary slot
1035 * and did not pass validation, in which case the whole slot is erased.
1036 * If during the erase operation, a reset occurs, parts of the slot
1037 * might have been erased while some did not. The concerning part is
1038 * the trailer because it might disable a new image from being loaded
1039 * through mcumgr; so we just get rid of the trailer here, if the header
1040 * is erased.
1041 */
1042 if (slot != BOOT_PRIMARY_SLOT) {
1043 swap_erase_trailer_sectors(state, fap);
1044 }
1045#endif
1046
David Vincze2d736ad2019-02-18 11:50:22 +01001047 /* No bootable image in slot; continue booting from the primary slot. */
Michael Grand5047f032022-11-24 16:49:56 +01001048 fih_rc = FIH_NO_BOOTABLE_IMAGE;
Fabio Utzig338a19f2018-12-03 08:37:08 -02001049 goto out;
Fabio Utzig39000012018-07-30 12:40:20 -03001050 }
1051
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +00001052#if defined(MCUBOOT_OVERWRITE_ONLY) && defined(MCUBOOT_DOWNGRADE_PREVENTION)
1053 if (slot != BOOT_PRIMARY_SLOT) {
1054 /* Check if version of secondary slot is sufficient */
David Vincze8b0b6372020-05-20 19:54:44 +02001055 rc = boot_version_cmp(
1056 &boot_img_hdr(state, BOOT_SECONDARY_SLOT)->ih_ver,
1057 &boot_img_hdr(state, BOOT_PRIMARY_SLOT)->ih_ver);
1058 if (rc < 0 && boot_check_header_erased(state, BOOT_PRIMARY_SLOT)) {
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +00001059 BOOT_LOG_ERR("insufficient version in secondary slot");
Dominik Ermel260ae092021-04-23 05:38:45 +00001060 flash_area_erase(fap, 0, flash_area_get_size(fap));
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +00001061 /* Image in the secondary slot does not satisfy version requirement.
1062 * Erase the image and continue booting from the primary slot.
1063 */
Michael Grand5047f032022-11-24 16:49:56 +01001064 fih_rc = FIH_NO_BOOTABLE_IMAGE;
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +00001065 goto out;
1066 }
1067 }
1068#endif
Jamie McCrae2939d302024-08-22 10:44:46 +01001069 if (!boot_is_header_valid(hdr, fap, state)) {
1070 fih_rc = FIH_FAILURE;
1071 } else {
1072 BOOT_HOOK_CALL_FIH(boot_image_check_hook, FIH_BOOT_HOOK_REGULAR,
1073 fih_rc, BOOT_CURR_IMG(state), slot);
1074 if (FIH_EQ(fih_rc, FIH_BOOT_HOOK_REGULAR)) {
1075 FIH_CALL(boot_image_check, fih_rc, state, hdr, fap, bs);
1076 }
Andrzej Puzdrowskib8f39692021-07-02 15:05:37 +02001077 }
Jamie McCrae2939d302024-08-22 10:44:46 +01001078 if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
Tamas Banfe031092020-09-10 17:32:39 +02001079 if ((slot != BOOT_PRIMARY_SLOT) || ARE_SLOTS_EQUIVALENT()) {
Dominik Ermel260ae092021-04-23 05:38:45 +00001080 flash_area_erase(fap, 0, flash_area_get_size(fap));
David Vinczee574f2d2020-07-10 11:42:03 +02001081 /* Image is invalid, erase it to prevent further unnecessary
1082 * attempts to validate and boot it.
David Brownb38e0442017-02-24 13:57:12 -07001083 */
1084 }
David Brown098de832019-12-10 11:58:01 -07001085#if !defined(__BOOTSIM__)
David Vincze2d736ad2019-02-18 11:50:22 +01001086 BOOT_LOG_ERR("Image in the %s slot is not valid!",
1087 (slot == BOOT_PRIMARY_SLOT) ? "primary" : "secondary");
David Brown098de832019-12-10 11:58:01 -07001088#endif
Michael Grand5047f032022-11-24 16:49:56 +01001089 fih_rc = FIH_NO_BOOTABLE_IMAGE;
Fabio Utzig338a19f2018-12-03 08:37:08 -02001090 goto out;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001091 }
1092
Håkon Øye Amundsene829e9d2021-11-12 14:01:01 +00001093#if MCUBOOT_IMAGE_NUMBER > 1 && !defined(MCUBOOT_ENC_IMAGES) && defined(MCUBOOT_VERIFY_IMG_ADDRESS)
1094 /* Verify that the image in the secondary slot has a reset address
1095 * located in the primary slot. This is done to avoid users incorrectly
1096 * overwriting an application written to the incorrect slot.
1097 * This feature is only supported by ARM platforms.
1098 */
1099 if (area_id == FLASH_AREA_IMAGE_SECONDARY(BOOT_CURR_IMG(state))) {
1100 const struct flash_area *pri_fa = BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT);
1101 struct image_header *secondary_hdr = boot_img_hdr(state, slot);
1102 uint32_t reset_value = 0;
1103 uint32_t reset_addr = secondary_hdr->ih_hdr_size + sizeof(reset_value);
1104
1105 rc = flash_area_read(fap, reset_addr, &reset_value, sizeof(reset_value));
1106 if (rc != 0) {
Michael Grand5047f032022-11-24 16:49:56 +01001107 fih_rc = FIH_NO_BOOTABLE_IMAGE;
Håkon Øye Amundsene829e9d2021-11-12 14:01:01 +00001108 goto out;
1109 }
1110
1111 if (reset_value < pri_fa->fa_off || reset_value> (pri_fa->fa_off + pri_fa->fa_size)) {
1112 BOOT_LOG_ERR("Reset address of image in secondary slot is not in the primary slot");
1113 BOOT_LOG_ERR("Erasing image from secondary slot");
1114
1115 /* The vector table in the image located in the secondary
1116 * slot does not target the primary slot. This might
1117 * indicate that the image was loaded to the wrong slot.
1118 *
1119 * Erase the image and continue booting from the primary slot.
1120 */
1121 flash_area_erase(fap, 0, fap->fa_size);
Michael Grand5047f032022-11-24 16:49:56 +01001122 fih_rc = FIH_NO_BOOTABLE_IMAGE;
Håkon Øye Amundsene829e9d2021-11-12 14:01:01 +00001123 goto out;
1124 }
1125 }
1126#endif
1127
Fabio Utzig338a19f2018-12-03 08:37:08 -02001128out:
1129 flash_area_close(fap);
Raef Colese8fe6cf2020-05-26 13:07:40 +01001130
1131 FIH_RET(fih_rc);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001132}
1133
David Vinczec3084132020-02-18 14:50:47 +01001134#ifdef MCUBOOT_HW_ROLLBACK_PROT
1135/**
1136 * Updates the stored security counter value with the image's security counter
1137 * value which resides in the given slot, only if it's greater than the stored
1138 * value.
1139 *
1140 * @param image_index Index of the image to determine which security
1141 * counter to update.
1142 * @param slot Slot number of the image.
1143 * @param hdr Pointer to the image header structure of the image
1144 * that is currently stored in the given slot.
1145 *
1146 * @return 0 on success; nonzero on failure.
1147 */
1148static int
1149boot_update_security_counter(uint8_t image_index, int slot,
1150 struct image_header *hdr)
1151{
1152 const struct flash_area *fap = NULL;
1153 uint32_t img_security_cnt;
1154 int rc;
1155
1156 rc = flash_area_open(flash_area_id_from_multi_image_slot(image_index, slot),
1157 &fap);
1158 if (rc != 0) {
1159 rc = BOOT_EFLASH;
1160 goto done;
1161 }
1162
1163 rc = bootutil_get_img_security_cnt(hdr, fap, &img_security_cnt);
1164 if (rc != 0) {
1165 goto done;
1166 }
1167
1168 rc = boot_nv_security_counter_update(image_index, img_security_cnt);
1169 if (rc != 0) {
1170 goto done;
1171 }
1172
1173done:
1174 flash_area_close(fap);
1175 return rc;
1176}
1177#endif /* MCUBOOT_HW_ROLLBACK_PROT */
1178
Tamas Banfe031092020-09-10 17:32:39 +02001179#if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)
David Vinczee574f2d2020-07-10 11:42:03 +02001180/**
1181 * Determines which swap operation to perform, if any. If it is determined
1182 * that a swap operation is required, the image in the secondary slot is checked
1183 * for validity. If the image in the secondary slot is invalid, it is erased,
1184 * and a swap type of "none" is indicated.
1185 *
1186 * @return The type of swap to perform (BOOT_SWAP_TYPE...)
1187 */
1188static int
1189boot_validated_swap_type(struct boot_loader_state *state,
1190 struct boot_status *bs)
1191{
1192 int swap_type;
Michael Grand5047f032022-11-24 16:49:56 +01001193 FIH_DECLARE(fih_rc, FIH_FAILURE);
David Vinczee574f2d2020-07-10 11:42:03 +02001194
1195 swap_type = boot_swap_type_multi(BOOT_CURR_IMG(state));
1196 if (BOOT_IS_UPGRADE(swap_type)) {
1197 /* Boot loader wants to switch to the secondary slot.
1198 * Ensure image is valid.
1199 */
Raef Colese8fe6cf2020-05-26 13:07:40 +01001200 FIH_CALL(boot_validate_slot, fih_rc, state, BOOT_SECONDARY_SLOT, bs);
Michael Grand5047f032022-11-24 16:49:56 +01001201 if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
1202 if (FIH_EQ(fih_rc, FIH_NO_BOOTABLE_IMAGE)) {
Raef Colese8fe6cf2020-05-26 13:07:40 +01001203 swap_type = BOOT_SWAP_TYPE_NONE;
1204 } else {
1205 swap_type = BOOT_SWAP_TYPE_FAIL;
1206 }
David Vinczee574f2d2020-07-10 11:42:03 +02001207 }
1208 }
1209
1210 return swap_type;
1211}
David Brown94ed12c2021-05-26 16:28:14 -06001212#endif
David Vinczee574f2d2020-07-10 11:42:03 +02001213
Christopher Collins92ea77f2016-12-12 15:59:26 -08001214/**
Christopher Collins92ea77f2016-12-12 15:59:26 -08001215 * Erases a region of flash.
1216 *
Fabio Utzigba829042018-09-18 08:29:34 -03001217 * @param flash_area The flash_area containing the region to erase.
Christopher Collins92ea77f2016-12-12 15:59:26 -08001218 * @param off The offset within the flash area to start the
1219 * erase.
1220 * @param sz The number of bytes to erase.
1221 *
1222 * @return 0 on success; nonzero on failure.
1223 */
Fabio Utzig12d59162019-11-28 10:01:59 -03001224int
Fabio Utzigc28005b2019-09-10 12:18:29 -03001225boot_erase_region(const struct flash_area *fap, uint32_t off, uint32_t sz)
Christopher Collins92ea77f2016-12-12 15:59:26 -08001226{
Fabio Utzigba829042018-09-18 08:29:34 -03001227 return flash_area_erase(fap, off, sz);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001228}
1229
David Brown94ed12c2021-05-26 16:28:14 -06001230#if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)
Dominik Ermel256bc372022-12-07 15:51:31 +00001231
1232#if defined(MCUBOOT_ENC_IMAGES) || defined(MCUBOOT_SWAP_SAVE_ENCTLV)
1233/* Replacement for memset(p, 0, sizeof(*p) that does not get
1234 * optimized out.
1235 */
1236static void like_mbedtls_zeroize(void *p, size_t n)
1237{
1238 volatile unsigned char *v = (unsigned char *)p;
1239
1240 for (size_t i = 0; i < n; i++) {
1241 v[i] = 0;
1242 }
1243}
1244#endif
1245
Christopher Collins92ea77f2016-12-12 15:59:26 -08001246/**
1247 * Copies the contents of one flash region to another. You must erase the
1248 * destination region prior to calling this function.
1249 *
1250 * @param flash_area_id_src The ID of the source flash area.
1251 * @param flash_area_id_dst The ID of the destination flash area.
1252 * @param off_src The offset within the source flash area to
1253 * copy from.
1254 * @param off_dst The offset within the destination flash area to
1255 * copy to.
1256 * @param sz The number of bytes to copy.
1257 *
1258 * @return 0 on success; nonzero on failure.
1259 */
Fabio Utzig12d59162019-11-28 10:01:59 -03001260int
Fabio Utzigc28005b2019-09-10 12:18:29 -03001261boot_copy_region(struct boot_loader_state *state,
Fabio Utzig10ee6482019-08-01 12:04:52 -03001262 const struct flash_area *fap_src,
Fabio Utzigba829042018-09-18 08:29:34 -03001263 const struct flash_area *fap_dst,
Christopher Collins92ea77f2016-12-12 15:59:26 -08001264 uint32_t off_src, uint32_t off_dst, uint32_t sz)
1265{
Christopher Collins92ea77f2016-12-12 15:59:26 -08001266 uint32_t bytes_copied;
1267 int chunk_sz;
1268 int rc;
Fabio Utzigba829042018-09-18 08:29:34 -03001269#ifdef MCUBOOT_ENC_IMAGES
Dominik Ermel6fe259b2024-07-18 11:40:53 +00001270 uint32_t off = off_dst;
Fabio Utziga87cc7d2019-08-26 11:21:45 -03001271 uint32_t tlv_off;
Fabio Utzigba829042018-09-18 08:29:34 -03001272 size_t blk_off;
1273 struct image_header *hdr;
1274 uint16_t idx;
1275 uint32_t blk_sz;
Dominik Ermel6fe259b2024-07-18 11:40:53 +00001276 uint8_t image_index = BOOT_CURR_IMG(state);
Thomas Altenbach08d2d942024-04-25 15:29:21 +02001277 bool encrypted_src;
1278 bool encrypted_dst;
Dominik Ermel6fe259b2024-07-18 11:40:53 +00001279 /* Assuming the secondary slot is source; note that 0 here not only
1280 * means that primary slot is source, but also that there will be
1281 * encryption happening, if it is 1 then there is decryption from
1282 * secondary slot.
1283 */
Dominik Ermel3f112862024-07-17 14:43:05 +00001284 int source_slot = 1;
Dominik Ermel6fe259b2024-07-18 11:40:53 +00001285 /* In case of encryption enabled, we may have to do more work than
1286 * just copy bytes */
1287 bool only_copy = false;
1288#else
1289 (void)state;
Fabio Utzigba829042018-09-18 08:29:34 -03001290#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -08001291
Kristine Jassmann73c38c62021-02-03 16:56:14 +00001292 TARGET_STATIC uint8_t buf[BUF_SZ] __attribute__((aligned(4)));
Fabio Utzig10ee6482019-08-01 12:04:52 -03001293
Dominik Ermel6fe259b2024-07-18 11:40:53 +00001294#ifdef MCUBOOT_ENC_IMAGES
1295 encrypted_src = (flash_area_get_id(fap_src) != FLASH_AREA_IMAGE_PRIMARY(image_index));
1296 encrypted_dst = (flash_area_get_id(fap_dst) != FLASH_AREA_IMAGE_PRIMARY(image_index));
1297
1298 if (encrypted_src != encrypted_dst) {
1299 if (encrypted_dst) {
1300 /* Need encryption, metadata from the primary slot */
1301 hdr = boot_img_hdr(state, BOOT_PRIMARY_SLOT);
1302 source_slot = 0;
1303 } else {
1304 /* Need decryption, metadata from the secondary slot */
1305 hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT);
1306 source_slot = 1;
1307 }
1308 } else {
1309 /* In case when source and targe is the same area, this means that we
1310 * only have to copy bytes, no encryption or decryption.
1311 */
1312 only_copy = true;
1313 }
Fabio Utzig10ee6482019-08-01 12:04:52 -03001314#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -08001315
Christopher Collins92ea77f2016-12-12 15:59:26 -08001316 bytes_copied = 0;
1317 while (bytes_copied < sz) {
1318 if (sz - bytes_copied > sizeof buf) {
1319 chunk_sz = sizeof buf;
1320 } else {
1321 chunk_sz = sz - bytes_copied;
1322 }
1323
1324 rc = flash_area_read(fap_src, off_src + bytes_copied, buf, chunk_sz);
1325 if (rc != 0) {
Fabio Utzigba829042018-09-18 08:29:34 -03001326 return BOOT_EFLASH;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001327 }
1328
Fabio Utzigba829042018-09-18 08:29:34 -03001329#ifdef MCUBOOT_ENC_IMAGES
Dominik Ermel6fe259b2024-07-18 11:40:53 +00001330 /* If only copy, then does not matter if header indicates need for
1331 * encryptio/decryptio, we just copy data. */
1332 if (!only_copy && IS_ENCRYPTED(hdr)) {
1333 uint32_t abs_off = off + bytes_copied;
1334 if (abs_off < hdr->ih_hdr_size) {
1335 /* do not decrypt header */
1336 if (abs_off + chunk_sz > hdr->ih_hdr_size) {
1337 /* The lower part of the chunk contains header data */
1338 blk_off = 0;
1339 blk_sz = chunk_sz - (hdr->ih_hdr_size - abs_off);
1340 idx = hdr->ih_hdr_size - abs_off;
1341 } else {
1342 /* The chunk contains exclusively header data */
1343 blk_sz = 0; /* nothing to decrypt */
1344 }
Thomas Altenbach08d2d942024-04-25 15:29:21 +02001345 } else {
Dominik Ermel6fe259b2024-07-18 11:40:53 +00001346 idx = 0;
1347 blk_sz = chunk_sz;
1348 blk_off = (abs_off - hdr->ih_hdr_size) & 0xf;
Fabio Utzig74aef312019-11-28 11:05:34 -03001349 }
Thomas Altenbach08d2d942024-04-25 15:29:21 +02001350
Dominik Ermel6fe259b2024-07-18 11:40:53 +00001351 if (blk_sz > 0)
1352 {
1353 tlv_off = BOOT_TLV_OFF(hdr);
1354 if (abs_off + chunk_sz > tlv_off) {
1355 /* do not decrypt TLVs */
1356 if (abs_off >= tlv_off) {
1357 blk_sz = 0;
Andrzej Puzdrowskie38b0af2021-11-04 13:34:11 +01001358 } else {
Dominik Ermel6fe259b2024-07-18 11:40:53 +00001359 blk_sz = tlv_off - abs_off;
Andrzej Puzdrowskie38b0af2021-11-04 13:34:11 +01001360 }
Fabio Utzigba829042018-09-18 08:29:34 -03001361 }
Dominik Ermel6fe259b2024-07-18 11:40:53 +00001362 boot_encrypt(BOOT_CURR_ENC(state), source_slot,
1363 (abs_off + idx) - hdr->ih_hdr_size, blk_sz,
1364 blk_off, &buf[idx]);
Fabio Utzigba829042018-09-18 08:29:34 -03001365 }
1366 }
1367#endif
1368
Christopher Collins92ea77f2016-12-12 15:59:26 -08001369 rc = flash_area_write(fap_dst, off_dst + bytes_copied, buf, chunk_sz);
1370 if (rc != 0) {
Fabio Utzigba829042018-09-18 08:29:34 -03001371 return BOOT_EFLASH;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001372 }
1373
1374 bytes_copied += chunk_sz;
Fabio Utzig853657c2019-05-07 08:06:07 -03001375
1376 MCUBOOT_WATCHDOG_FEED();
Christopher Collins92ea77f2016-12-12 15:59:26 -08001377 }
1378
Fabio Utzigba829042018-09-18 08:29:34 -03001379 return 0;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001380}
1381
Christopher Collins92ea77f2016-12-12 15:59:26 -08001382/**
David Vincze2d736ad2019-02-18 11:50:22 +01001383 * Overwrite primary slot with the image contained in the secondary slot.
1384 * If a prior copy operation was interrupted by a system reset, this function
1385 * redos the copy.
Christopher Collins92ea77f2016-12-12 15:59:26 -08001386 *
1387 * @param bs The current boot status. This function reads
1388 * this struct to determine if it is resuming
1389 * an interrupted swap operation. This
1390 * function writes the updated status to this
1391 * function on return.
1392 *
1393 * @return 0 on success; nonzero on failure.
1394 */
Fabio Utzig338a19f2018-12-03 08:37:08 -02001395#if defined(MCUBOOT_OVERWRITE_ONLY) || defined(MCUBOOT_BOOTSTRAP)
David Brown17609d82017-05-05 09:41:34 -06001396static int
Fabio Utzig10ee6482019-08-01 12:04:52 -03001397boot_copy_image(struct boot_loader_state *state, struct boot_status *bs)
David Brown17609d82017-05-05 09:41:34 -06001398{
Marti Bolivard3269fd2017-06-12 16:31:12 -04001399 size_t sect_count;
1400 size_t sect;
David Brown17609d82017-05-05 09:41:34 -06001401 int rc;
Fabio Utzig13d9e352017-10-05 20:32:31 -03001402 size_t size;
Marti Bolivard3269fd2017-06-12 16:31:12 -04001403 size_t this_size;
Fabio Utzig13d9e352017-10-05 20:32:31 -03001404 size_t last_sector;
David Vincze2d736ad2019-02-18 11:50:22 +01001405 const struct flash_area *fap_primary_slot;
1406 const struct flash_area *fap_secondary_slot;
Fabio Utzigb0f04732019-07-31 09:49:19 -03001407 uint8_t image_index;
David Vincze2d736ad2019-02-18 11:50:22 +01001408
Fabio Utzigb4f88102020-10-04 10:16:24 -03001409#if defined(MCUBOOT_OVERWRITE_ONLY_FAST)
1410 uint32_t sector;
1411 uint32_t trailer_sz;
1412 uint32_t off;
1413 uint32_t sz;
1414#endif
1415
Fabio Utzigaaf767c2017-12-05 10:22:46 -02001416 (void)bs;
1417
Fabio Utzig13d9e352017-10-05 20:32:31 -03001418#if defined(MCUBOOT_OVERWRITE_ONLY_FAST)
1419 uint32_t src_size = 0;
Fabio Utzigd638b172019-08-09 10:38:05 -03001420 rc = boot_read_image_size(state, BOOT_SECONDARY_SLOT, &src_size);
Fabio Utzig13d9e352017-10-05 20:32:31 -03001421 assert(rc == 0);
1422#endif
David Brown17609d82017-05-05 09:41:34 -06001423
Fabio Utzigb0f04732019-07-31 09:49:19 -03001424 image_index = BOOT_CURR_IMG(state);
1425
Antonio de Angelisba5fb1c2022-10-11 10:10:37 +01001426 BOOT_LOG_INF("Image %d upgrade secondary slot -> primary slot", image_index);
1427 BOOT_LOG_INF("Erasing the primary slot");
1428
Fabio Utzigb0f04732019-07-31 09:49:19 -03001429 rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index),
1430 &fap_primary_slot);
Fabio Utzigba829042018-09-18 08:29:34 -03001431 assert (rc == 0);
1432
Fabio Utzigb0f04732019-07-31 09:49:19 -03001433 rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY(image_index),
1434 &fap_secondary_slot);
Fabio Utzigba829042018-09-18 08:29:34 -03001435 assert (rc == 0);
1436
Fabio Utzig10ee6482019-08-01 12:04:52 -03001437 sect_count = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT);
Fabio Utzig13d9e352017-10-05 20:32:31 -03001438 for (sect = 0, size = 0; sect < sect_count; sect++) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001439 this_size = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, sect);
Fabio Utzigc28005b2019-09-10 12:18:29 -03001440 rc = boot_erase_region(fap_primary_slot, size, this_size);
David Brown17609d82017-05-05 09:41:34 -06001441 assert(rc == 0);
1442
Fabio Utzig13d9e352017-10-05 20:32:31 -03001443#if defined(MCUBOOT_OVERWRITE_ONLY_FAST)
Fabio Utzigb4f88102020-10-04 10:16:24 -03001444 if ((size + this_size) >= src_size) {
1445 size += src_size - size;
1446 size += BOOT_WRITE_SZ(state) - (size % BOOT_WRITE_SZ(state));
Fabio Utzig13d9e352017-10-05 20:32:31 -03001447 break;
1448 }
1449#endif
Fabio Utzigb4f88102020-10-04 10:16:24 -03001450
1451 size += this_size;
David Brown17609d82017-05-05 09:41:34 -06001452 }
1453
Fabio Utzigb4f88102020-10-04 10:16:24 -03001454#if defined(MCUBOOT_OVERWRITE_ONLY_FAST)
1455 trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(state));
1456 sector = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT) - 1;
1457 sz = 0;
1458 do {
1459 sz += boot_img_sector_size(state, BOOT_PRIMARY_SLOT, sector);
1460 off = boot_img_sector_off(state, BOOT_PRIMARY_SLOT, sector);
1461 sector--;
1462 } while (sz < trailer_sz);
1463
1464 rc = boot_erase_region(fap_primary_slot, off, sz);
1465 assert(rc == 0);
1466#endif
1467
Fabio Utzigba829042018-09-18 08:29:34 -03001468#ifdef MCUBOOT_ENC_IMAGES
Fabio Utzig10ee6482019-08-01 12:04:52 -03001469 if (IS_ENCRYPTED(boot_img_hdr(state, BOOT_SECONDARY_SLOT))) {
Dominik Ermel7f9ac972024-07-12 19:21:40 +00001470 rc = boot_enc_load(BOOT_CURR_ENC(state), BOOT_SECONDARY_SLOT,
Fabio Utzig10ee6482019-08-01 12:04:52 -03001471 boot_img_hdr(state, BOOT_SECONDARY_SLOT),
Fabio Utzig4741c452019-12-19 15:32:41 -03001472 fap_secondary_slot, bs);
David Vincze2d736ad2019-02-18 11:50:22 +01001473
Fabio Utzigba829042018-09-18 08:29:34 -03001474 if (rc < 0) {
1475 return BOOT_EBADIMAGE;
1476 }
Fabio Utzig4741c452019-12-19 15:32:41 -03001477 if (rc == 0 && boot_enc_set_key(BOOT_CURR_ENC(state), 1, bs)) {
Fabio Utzigba829042018-09-18 08:29:34 -03001478 return BOOT_EBADIMAGE;
1479 }
1480 }
1481#endif
1482
Antonio de Angelis48547002023-04-14 09:47:09 +01001483 BOOT_LOG_INF("Image %d copying the secondary slot to the primary slot: 0x%zx bytes",
1484 image_index, size);
Fabio Utzigc28005b2019-09-10 12:18:29 -03001485 rc = boot_copy_region(state, fap_secondary_slot, fap_primary_slot, 0, 0, size);
Fabio Utzigb4f88102020-10-04 10:16:24 -03001486 if (rc != 0) {
1487 return rc;
1488 }
1489
1490#if defined(MCUBOOT_OVERWRITE_ONLY_FAST)
1491 rc = boot_write_magic(fap_primary_slot);
1492 if (rc != 0) {
1493 return rc;
1494 }
1495#endif
David Brown17609d82017-05-05 09:41:34 -06001496
Andrzej Puzdrowskib8f39692021-07-02 15:05:37 +02001497 rc = BOOT_HOOK_CALL(boot_copy_region_post_hook, 0, BOOT_CURR_IMG(state),
1498 BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT), size);
1499 if (rc != 0) {
1500 return rc;
1501 }
1502
David Vinczec3084132020-02-18 14:50:47 +01001503#ifdef MCUBOOT_HW_ROLLBACK_PROT
1504 /* Update the stored security counter with the new image's security counter
1505 * value. Both slots hold the new image at this point, but the secondary
1506 * slot's image header must be passed since the image headers in the
1507 * boot_data structure have not been updated yet.
1508 */
1509 rc = boot_update_security_counter(BOOT_CURR_IMG(state), BOOT_PRIMARY_SLOT,
1510 boot_img_hdr(state, BOOT_SECONDARY_SLOT));
1511 if (rc != 0) {
1512 BOOT_LOG_ERR("Security counter update failed after image upgrade.");
1513 return rc;
1514 }
1515#endif /* MCUBOOT_HW_ROLLBACK_PROT */
1516
Petr Buchtac5a528b2024-02-24 08:10:38 +01001517#ifndef MCUBOOT_OVERWRITE_ONLY_KEEP_BACKUP
Fabio Utzig13d9e352017-10-05 20:32:31 -03001518 /*
1519 * Erases header and trailer. The trailer is erased because when a new
1520 * image is written without a trailer as is the case when using newt, the
1521 * trailer that was left might trigger a new upgrade.
1522 */
Christopher Collins2c88e692019-05-22 15:10:14 -07001523 BOOT_LOG_DBG("erasing secondary header");
Fabio Utzigc28005b2019-09-10 12:18:29 -03001524 rc = boot_erase_region(fap_secondary_slot,
Fabio Utzig10ee6482019-08-01 12:04:52 -03001525 boot_img_sector_off(state, BOOT_SECONDARY_SLOT, 0),
1526 boot_img_sector_size(state, BOOT_SECONDARY_SLOT, 0));
David Brown17609d82017-05-05 09:41:34 -06001527 assert(rc == 0);
Petr Buchtac5a528b2024-02-24 08:10:38 +01001528#endif
1529
Fabio Utzig10ee6482019-08-01 12:04:52 -03001530 last_sector = boot_img_num_sectors(state, BOOT_SECONDARY_SLOT) - 1;
Christopher Collins2c88e692019-05-22 15:10:14 -07001531 BOOT_LOG_DBG("erasing secondary trailer");
Fabio Utzigc28005b2019-09-10 12:18:29 -03001532 rc = boot_erase_region(fap_secondary_slot,
Fabio Utzig10ee6482019-08-01 12:04:52 -03001533 boot_img_sector_off(state, BOOT_SECONDARY_SLOT,
1534 last_sector),
1535 boot_img_sector_size(state, BOOT_SECONDARY_SLOT,
1536 last_sector));
Fabio Utzig13d9e352017-10-05 20:32:31 -03001537 assert(rc == 0);
1538
David Vincze2d736ad2019-02-18 11:50:22 +01001539 flash_area_close(fap_primary_slot);
1540 flash_area_close(fap_secondary_slot);
Fabio Utzigba829042018-09-18 08:29:34 -03001541
David Vincze2d736ad2019-02-18 11:50:22 +01001542 /* TODO: Perhaps verify the primary slot's signature again? */
David Brown17609d82017-05-05 09:41:34 -06001543
1544 return 0;
1545}
Fabio Utzig338a19f2018-12-03 08:37:08 -02001546#endif
Fabio Utzigba829042018-09-18 08:29:34 -03001547
Christopher Collinsa1c12042019-05-23 14:00:28 -07001548#if !defined(MCUBOOT_OVERWRITE_ONLY)
Fabio Utzigba829042018-09-18 08:29:34 -03001549/**
1550 * Swaps the two images in flash. If a prior copy operation was interrupted
1551 * by a system reset, this function completes that operation.
1552 *
1553 * @param bs The current boot status. This function reads
1554 * this struct to determine if it is resuming
1555 * an interrupted swap operation. This
1556 * function writes the updated status to this
1557 * function on return.
1558 *
1559 * @return 0 on success; nonzero on failure.
1560 */
Christopher Collins92ea77f2016-12-12 15:59:26 -08001561static int
Fabio Utzig10ee6482019-08-01 12:04:52 -03001562boot_swap_image(struct boot_loader_state *state, struct boot_status *bs)
Christopher Collins92ea77f2016-12-12 15:59:26 -08001563{
Fabio Utzig2473ac02017-05-02 12:45:02 -03001564 struct image_header *hdr;
Fabio Utzigba829042018-09-18 08:29:34 -03001565 const struct flash_area *fap;
Dominik Ermel472d4c72023-02-10 13:29:58 +00001566#ifdef MCUBOOT_ENC_IMAGES
Fabio Utzigba829042018-09-18 08:29:34 -03001567 uint8_t slot;
1568 uint8_t i;
Fabio Utzigba829042018-09-18 08:29:34 -03001569#endif
Fabio Utzig2473ac02017-05-02 12:45:02 -03001570 uint32_t size;
1571 uint32_t copy_size;
Fabio Utzigb0f04732019-07-31 09:49:19 -03001572 uint8_t image_index;
Fabio Utzig2473ac02017-05-02 12:45:02 -03001573 int rc;
1574
1575 /* FIXME: just do this if asked by user? */
1576
1577 size = copy_size = 0;
Fabio Utzig10ee6482019-08-01 12:04:52 -03001578 image_index = BOOT_CURR_IMG(state);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001579
Fabio Utzig12d59162019-11-28 10:01:59 -03001580 if (boot_status_is_reset(bs)) {
Fabio Utzig46490722017-09-04 15:34:32 -03001581 /*
1582 * No swap ever happened, so need to find the largest image which
1583 * will be used to determine the amount of sectors to swap.
1584 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001585 hdr = boot_img_hdr(state, BOOT_PRIMARY_SLOT);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001586 if (hdr->ih_magic == IMAGE_MAGIC) {
Fabio Utzigd638b172019-08-09 10:38:05 -03001587 rc = boot_read_image_size(state, BOOT_PRIMARY_SLOT, &copy_size);
David Brownf5b33d82017-09-01 10:58:27 -06001588 assert(rc == 0);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001589 }
Fabio Utzig2473ac02017-05-02 12:45:02 -03001590
Fabio Utzigba829042018-09-18 08:29:34 -03001591#ifdef MCUBOOT_ENC_IMAGES
Fabio Utzig2fc80df2018-12-14 06:47:38 -02001592 if (IS_ENCRYPTED(hdr)) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001593 fap = BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT);
Dominik Ermel7f9ac972024-07-12 19:21:40 +00001594 rc = boot_enc_load(BOOT_CURR_ENC(state), 0, hdr, fap, bs);
Fabio Utzigba829042018-09-18 08:29:34 -03001595 assert(rc >= 0);
1596
1597 if (rc == 0) {
Fabio Utzig4741c452019-12-19 15:32:41 -03001598 rc = boot_enc_set_key(BOOT_CURR_ENC(state), 0, bs);
Fabio Utzigba829042018-09-18 08:29:34 -03001599 assert(rc == 0);
1600 } else {
1601 rc = 0;
1602 }
1603 } else {
Kristine Jassmann73c38c62021-02-03 16:56:14 +00001604 memset(bs->enckey[0], 0xff, BOOT_ENC_KEY_ALIGN_SIZE);
Fabio Utzigba829042018-09-18 08:29:34 -03001605 }
1606#endif
1607
Fabio Utzig10ee6482019-08-01 12:04:52 -03001608 hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT);
Fabio Utzig46490722017-09-04 15:34:32 -03001609 if (hdr->ih_magic == IMAGE_MAGIC) {
Fabio Utzigd638b172019-08-09 10:38:05 -03001610 rc = boot_read_image_size(state, BOOT_SECONDARY_SLOT, &size);
Fabio Utzig46490722017-09-04 15:34:32 -03001611 assert(rc == 0);
1612 }
1613
Fabio Utzigba829042018-09-18 08:29:34 -03001614#ifdef MCUBOOT_ENC_IMAGES
Fabio Utzig10ee6482019-08-01 12:04:52 -03001615 hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT);
Fabio Utzig2fc80df2018-12-14 06:47:38 -02001616 if (IS_ENCRYPTED(hdr)) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001617 fap = BOOT_IMG_AREA(state, BOOT_SECONDARY_SLOT);
Dominik Ermel7f9ac972024-07-12 19:21:40 +00001618 rc = boot_enc_load(BOOT_CURR_ENC(state), 1, hdr, fap, bs);
Fabio Utzigba829042018-09-18 08:29:34 -03001619 assert(rc >= 0);
1620
1621 if (rc == 0) {
Fabio Utzig4741c452019-12-19 15:32:41 -03001622 rc = boot_enc_set_key(BOOT_CURR_ENC(state), 1, bs);
Fabio Utzigba829042018-09-18 08:29:34 -03001623 assert(rc == 0);
1624 } else {
1625 rc = 0;
1626 }
1627 } else {
Kristine Jassmann73c38c62021-02-03 16:56:14 +00001628 memset(bs->enckey[1], 0xff, BOOT_ENC_KEY_ALIGN_SIZE);
Fabio Utzigba829042018-09-18 08:29:34 -03001629 }
1630#endif
1631
Fabio Utzig46490722017-09-04 15:34:32 -03001632 if (size > copy_size) {
1633 copy_size = size;
1634 }
1635
1636 bs->swap_size = copy_size;
1637 } else {
1638 /*
1639 * If a swap was under way, the swap_size should already be present
1640 * in the trailer...
1641 */
Dominik Ermel472d4c72023-02-10 13:29:58 +00001642
1643 rc = boot_find_status(image_index, &fap);
1644 assert(fap != NULL);
1645 rc = boot_read_swap_size(fap, &bs->swap_size);
Fabio Utzig46490722017-09-04 15:34:32 -03001646 assert(rc == 0);
1647
1648 copy_size = bs->swap_size;
Fabio Utzigba829042018-09-18 08:29:34 -03001649
1650#ifdef MCUBOOT_ENC_IMAGES
Fabio Utzig4741c452019-12-19 15:32:41 -03001651 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
Dominik Ermel472d4c72023-02-10 13:29:58 +00001652 rc = boot_read_enc_key(fap, slot, bs);
Fabio Utzigba829042018-09-18 08:29:34 -03001653 assert(rc == 0);
1654
1655 for (i = 0; i < BOOT_ENC_KEY_SIZE; i++) {
Fabio Utzig1c7d9592018-12-03 10:35:56 -02001656 if (bs->enckey[slot][i] != 0xff) {
Fabio Utzigba829042018-09-18 08:29:34 -03001657 break;
1658 }
1659 }
1660
Dominik Ermel7e3a1ce2024-07-12 17:19:17 +00001661 boot_enc_init(BOOT_CURR_ENC(state), slot);
1662
Fabio Utzigba829042018-09-18 08:29:34 -03001663 if (i != BOOT_ENC_KEY_SIZE) {
Fabio Utzig4741c452019-12-19 15:32:41 -03001664 boot_enc_set_key(BOOT_CURR_ENC(state), slot, bs);
Fabio Utzigba829042018-09-18 08:29:34 -03001665 }
1666 }
1667#endif
Dominik Ermel472d4c72023-02-10 13:29:58 +00001668 flash_area_close(fap);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001669 }
1670
Fabio Utzig12d59162019-11-28 10:01:59 -03001671 swap_run(state, bs, copy_size);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001672
David Vincze2d736ad2019-02-18 11:50:22 +01001673#ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT
Fabio Utzig12d59162019-11-28 10:01:59 -03001674 extern int boot_status_fails;
Fabio Utziga0e1cce2017-11-23 20:04:01 -02001675 if (boot_status_fails > 0) {
Christopher Collins2c88e692019-05-22 15:10:14 -07001676 BOOT_LOG_WRN("%d status write fails performing the swap",
1677 boot_status_fails);
Fabio Utziga0e1cce2017-11-23 20:04:01 -02001678 }
1679#endif
Sigvart Hovland3fd4cd42022-09-09 13:21:18 +02001680 rc = BOOT_HOOK_CALL(boot_copy_region_post_hook, 0, BOOT_CURR_IMG(state),
1681 BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT), size);
Fabio Utziga0e1cce2017-11-23 20:04:01 -02001682
Christopher Collins92ea77f2016-12-12 15:59:26 -08001683 return 0;
1684}
David Brown17609d82017-05-05 09:41:34 -06001685#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -08001686
David Vinczee32483f2019-06-13 10:46:24 +02001687
Christopher Collins92ea77f2016-12-12 15:59:26 -08001688/**
David Vinczeba3bd602019-06-17 16:01:43 +02001689 * Performs a clean (not aborted) image update.
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001690 *
David Vinczeba3bd602019-06-17 16:01:43 +02001691 * @param bs The current boot status.
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001692 *
1693 * @return 0 on success; nonzero on failure.
1694 */
1695static int
Fabio Utzig10ee6482019-08-01 12:04:52 -03001696boot_perform_update(struct boot_loader_state *state, struct boot_status *bs)
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001697{
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001698 int rc;
Fabio Utzig10ee6482019-08-01 12:04:52 -03001699#ifndef MCUBOOT_OVERWRITE_ONLY
1700 uint8_t swap_type;
1701#endif
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001702
David Vinczeba3bd602019-06-17 16:01:43 +02001703 /* At this point there are no aborted swaps. */
1704#if defined(MCUBOOT_OVERWRITE_ONLY)
Fabio Utzig10ee6482019-08-01 12:04:52 -03001705 rc = boot_copy_image(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02001706#elif defined(MCUBOOT_BOOTSTRAP)
1707 /* Check if the image update was triggered by a bad image in the
1708 * primary slot (the validity of the image in the secondary slot had
1709 * already been checked).
1710 */
Michael Grand5047f032022-11-24 16:49:56 +01001711 FIH_DECLARE(fih_rc, FIH_FAILURE);
Raef Colese8fe6cf2020-05-26 13:07:40 +01001712 rc = boot_check_header_erased(state, BOOT_PRIMARY_SLOT);
1713 FIH_CALL(boot_validate_slot, fih_rc, state, BOOT_PRIMARY_SLOT, bs);
Michael Grand5047f032022-11-24 16:49:56 +01001714 if (rc == 0 || FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001715 rc = boot_copy_image(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02001716 } else {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001717 rc = boot_swap_image(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02001718 }
1719#else
Fabio Utzig10ee6482019-08-01 12:04:52 -03001720 rc = boot_swap_image(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02001721#endif
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001722 assert(rc == 0);
David Vinczeba3bd602019-06-17 16:01:43 +02001723
1724#ifndef MCUBOOT_OVERWRITE_ONLY
1725 /* The following state needs image_ok be explicitly set after the
1726 * swap was finished to avoid a new revert.
1727 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001728 swap_type = BOOT_SWAP_TYPE(state);
1729 if (swap_type == BOOT_SWAP_TYPE_REVERT ||
1730 swap_type == BOOT_SWAP_TYPE_PERM) {
Fabio Utzig12d59162019-11-28 10:01:59 -03001731 rc = swap_set_image_ok(BOOT_CURR_IMG(state));
David Vinczeba3bd602019-06-17 16:01:43 +02001732 if (rc != 0) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001733 BOOT_SWAP_TYPE(state) = swap_type = BOOT_SWAP_TYPE_PANIC;
David Vinczeba3bd602019-06-17 16:01:43 +02001734 }
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001735 }
1736
David Vinczec3084132020-02-18 14:50:47 +01001737#ifdef MCUBOOT_HW_ROLLBACK_PROT
1738 if (swap_type == BOOT_SWAP_TYPE_PERM) {
1739 /* Update the stored security counter with the new image's security
1740 * counter value. The primary slot holds the new image at this point,
1741 * but the secondary slot's image header must be passed since image
1742 * headers in the boot_data structure have not been updated yet.
1743 *
1744 * In case of a permanent image swap mcuboot will never attempt to
1745 * revert the images on the next reboot. Therefore, the security
1746 * counter must be increased right after the image upgrade.
1747 */
1748 rc = boot_update_security_counter(
1749 BOOT_CURR_IMG(state),
1750 BOOT_PRIMARY_SLOT,
1751 boot_img_hdr(state, BOOT_SECONDARY_SLOT));
1752 if (rc != 0) {
1753 BOOT_LOG_ERR("Security counter update failed after "
1754 "image upgrade.");
1755 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
1756 }
1757 }
1758#endif /* MCUBOOT_HW_ROLLBACK_PROT */
1759
Fabio Utzige575b0b2019-09-11 12:34:23 -03001760 if (BOOT_IS_UPGRADE(swap_type)) {
Fabio Utzig12d59162019-11-28 10:01:59 -03001761 rc = swap_set_copy_done(BOOT_CURR_IMG(state));
David Vinczeba3bd602019-06-17 16:01:43 +02001762 if (rc != 0) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001763 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
Christopher Collinsa1c12042019-05-23 14:00:28 -07001764 }
David Vinczeba3bd602019-06-17 16:01:43 +02001765 }
1766#endif /* !MCUBOOT_OVERWRITE_ONLY */
Fabio Utzig338a19f2018-12-03 08:37:08 -02001767
David Vinczeba3bd602019-06-17 16:01:43 +02001768 return rc;
1769}
1770
1771/**
1772 * Completes a previously aborted image swap.
1773 *
1774 * @param bs The current boot status.
1775 *
1776 * @return 0 on success; nonzero on failure.
1777 */
1778#if !defined(MCUBOOT_OVERWRITE_ONLY)
1779static int
Fabio Utzig10ee6482019-08-01 12:04:52 -03001780boot_complete_partial_swap(struct boot_loader_state *state,
1781 struct boot_status *bs)
David Vinczeba3bd602019-06-17 16:01:43 +02001782{
1783 int rc;
1784
1785 /* Determine the type of swap operation being resumed from the
1786 * `swap-type` trailer field.
1787 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001788 rc = boot_swap_image(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02001789 assert(rc == 0);
1790
Fabio Utzig10ee6482019-08-01 12:04:52 -03001791 BOOT_SWAP_TYPE(state) = bs->swap_type;
David Vinczeba3bd602019-06-17 16:01:43 +02001792
1793 /* The following states need image_ok be explicitly set after the
1794 * swap was finished to avoid a new revert.
1795 */
1796 if (bs->swap_type == BOOT_SWAP_TYPE_REVERT ||
1797 bs->swap_type == BOOT_SWAP_TYPE_PERM) {
Fabio Utzig12d59162019-11-28 10:01:59 -03001798 rc = swap_set_image_ok(BOOT_CURR_IMG(state));
David Vinczeba3bd602019-06-17 16:01:43 +02001799 if (rc != 0) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001800 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
David Vinczeba3bd602019-06-17 16:01:43 +02001801 }
1802 }
1803
Fabio Utzige575b0b2019-09-11 12:34:23 -03001804 if (BOOT_IS_UPGRADE(bs->swap_type)) {
Fabio Utzig12d59162019-11-28 10:01:59 -03001805 rc = swap_set_copy_done(BOOT_CURR_IMG(state));
David Vinczeba3bd602019-06-17 16:01:43 +02001806 if (rc != 0) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001807 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
David Vinczeba3bd602019-06-17 16:01:43 +02001808 }
1809 }
1810
Fabio Utzig10ee6482019-08-01 12:04:52 -03001811 if (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_PANIC) {
David Vinczeba3bd602019-06-17 16:01:43 +02001812 BOOT_LOG_ERR("panic!");
1813 assert(0);
1814
1815 /* Loop forever... */
1816 while (1) {}
1817 }
1818
1819 return rc;
1820}
1821#endif /* !MCUBOOT_OVERWRITE_ONLY */
1822
1823#if (BOOT_IMAGE_NUMBER > 1)
1824/**
1825 * Review the validity of previously determined swap types of other images.
1826 *
1827 * @param aborted_swap The current image upgrade is a
1828 * partial/aborted swap.
1829 */
1830static void
Fabio Utzig10ee6482019-08-01 12:04:52 -03001831boot_review_image_swap_types(struct boot_loader_state *state,
1832 bool aborted_swap)
David Vinczeba3bd602019-06-17 16:01:43 +02001833{
1834 /* In that case if we rebooted in the middle of an image upgrade process, we
1835 * must review the validity of swap types, that were previously determined
1836 * for other images. The image_ok flag had not been set before the reboot
1837 * for any of the updated images (only the copy_done flag) and thus falsely
1838 * the REVERT swap type has been determined for the previous images that had
1839 * been updated before the reboot.
1840 *
1841 * There are two separate scenarios that we have to deal with:
1842 *
1843 * 1. The reboot has happened during swapping an image:
1844 * The current image upgrade has been determined as a
1845 * partial/aborted swap.
1846 * 2. The reboot has happened between two separate image upgrades:
1847 * In this scenario we must check the swap type of the current image.
1848 * In those cases if it is NONE or REVERT we cannot certainly determine
1849 * the fact of a reboot. In a consistent state images must move in the
1850 * same direction or stay in place, e.g. in practice REVERT and TEST
1851 * swap types cannot be present at the same time. If the swap type of
1852 * the current image is either TEST, PERM or FAIL we must review the
1853 * already determined swap types of other images and set each false
1854 * REVERT swap types to NONE (these images had been successfully
1855 * updated before the system rebooted between two separate image
1856 * upgrades).
1857 */
1858
Fabio Utzig10ee6482019-08-01 12:04:52 -03001859 if (BOOT_CURR_IMG(state) == 0) {
David Vinczeba3bd602019-06-17 16:01:43 +02001860 /* Nothing to do */
1861 return;
1862 }
1863
1864 if (!aborted_swap) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001865 if ((BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_NONE) ||
1866 (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_REVERT)) {
David Vinczeba3bd602019-06-17 16:01:43 +02001867 /* Nothing to do */
1868 return;
1869 }
1870 }
1871
Fabio Utzig10ee6482019-08-01 12:04:52 -03001872 for (uint8_t i = 0; i < BOOT_CURR_IMG(state); i++) {
1873 if (state->swap_type[i] == BOOT_SWAP_TYPE_REVERT) {
1874 state->swap_type[i] = BOOT_SWAP_TYPE_NONE;
David Vinczeba3bd602019-06-17 16:01:43 +02001875 }
1876 }
1877}
1878#endif
1879
1880/**
1881 * Prepare image to be updated if required.
1882 *
1883 * Prepare image to be updated if required with completing an image swap
1884 * operation if one was aborted and/or determining the type of the
1885 * swap operation. In case of any error set the swap type to NONE.
1886 *
Fabio Utzig10ee6482019-08-01 12:04:52 -03001887 * @param state TODO
David Vinczeba3bd602019-06-17 16:01:43 +02001888 * @param bs Pointer where the read and possibly updated
1889 * boot status can be written to.
1890 */
1891static void
Fabio Utzig10ee6482019-08-01 12:04:52 -03001892boot_prepare_image_for_update(struct boot_loader_state *state,
1893 struct boot_status *bs)
David Vinczeba3bd602019-06-17 16:01:43 +02001894{
1895 int rc;
Michael Grand5047f032022-11-24 16:49:56 +01001896 FIH_DECLARE(fih_rc, FIH_FAILURE);
David Vinczeba3bd602019-06-17 16:01:43 +02001897
Jamie McCraee261b282024-07-26 11:48:19 +01001898#if defined(MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO) || defined(MCUBOOT_DATA_SHARING)
Jamie McCrae4f1ab9e2024-07-26 12:29:24 +01001899 int max_size;
1900#endif
1901
David Vinczeba3bd602019-06-17 16:01:43 +02001902 /* Determine the sector layout of the image slots and scratch area. */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001903 rc = boot_read_sectors(state);
David Vinczeba3bd602019-06-17 16:01:43 +02001904 if (rc != 0) {
1905 BOOT_LOG_WRN("Failed reading sectors; BOOT_MAX_IMG_SECTORS=%d"
1906 " - too small?", BOOT_MAX_IMG_SECTORS);
1907 /* Unable to determine sector layout, continue with next image
1908 * if there is one.
1909 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001910 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
Andrzej Puzdrowski54b4ad92021-06-22 13:21:22 +02001911 if (rc == BOOT_EFLASH)
1912 {
1913 /* Only return on error from the primary image flash */
1914 return;
1915 }
David Vinczeba3bd602019-06-17 16:01:43 +02001916 }
1917
1918 /* Attempt to read an image header from each slot. */
Fabio Utzig12d59162019-11-28 10:01:59 -03001919 rc = boot_read_image_headers(state, false, NULL);
David Vinczeba3bd602019-06-17 16:01:43 +02001920 if (rc != 0) {
1921 /* Continue with next image if there is one. */
Fabio Utzigb0f04732019-07-31 09:49:19 -03001922 BOOT_LOG_WRN("Failed reading image headers; Image=%u",
Fabio Utzig10ee6482019-08-01 12:04:52 -03001923 BOOT_CURR_IMG(state));
1924 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
David Vinczeba3bd602019-06-17 16:01:43 +02001925 return;
1926 }
1927
Jamie McCraee261b282024-07-26 11:48:19 +01001928#if defined(MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO) || defined(MCUBOOT_DATA_SHARING)
Jamie McCrae4f1ab9e2024-07-26 12:29:24 +01001929 /* Fetch information on maximum sizes for later usage, if needed */
1930 max_size = app_max_size(state);
1931
1932 if (max_size > 0) {
1933 image_max_sizes[BOOT_CURR_IMG(state)].calculated = true;
1934 image_max_sizes[BOOT_CURR_IMG(state)].max_size = max_size;
1935 }
1936#endif
1937
David Vinczeba3bd602019-06-17 16:01:43 +02001938 /* If the current image's slots aren't compatible, no swap is possible.
1939 * Just boot into primary slot.
1940 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001941 if (boot_slots_compatible(state)) {
Fabio Utzig12d59162019-11-28 10:01:59 -03001942 boot_status_reset(bs);
1943
1944#ifndef MCUBOOT_OVERWRITE_ONLY
1945 rc = swap_read_status(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02001946 if (rc != 0) {
1947 BOOT_LOG_WRN("Failed reading boot status; Image=%u",
Fabio Utzig10ee6482019-08-01 12:04:52 -03001948 BOOT_CURR_IMG(state));
David Vinczeba3bd602019-06-17 16:01:43 +02001949 /* Continue with next image if there is one. */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001950 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
David Vinczeba3bd602019-06-17 16:01:43 +02001951 return;
1952 }
Fabio Utzig12d59162019-11-28 10:01:59 -03001953#endif
David Vinczeba3bd602019-06-17 16:01:43 +02001954
Thomas Altenbachf515bb12024-04-26 18:31:57 +02001955#if defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SWAP_USING_MOVE)
Fabio Utzig74aef312019-11-28 11:05:34 -03001956 /*
1957 * Must re-read image headers because the boot status might
1958 * have been updated in the previous function call.
1959 */
1960 rc = boot_read_image_headers(state, !boot_status_is_reset(bs), bs);
Fabio Utzig32afe852020-10-04 10:36:02 -03001961#ifdef MCUBOOT_BOOTSTRAP
1962 /* When bootstrapping it's OK to not have image magic in the primary slot */
1963 if (rc != 0 && (BOOT_CURR_IMG(state) != BOOT_PRIMARY_SLOT ||
1964 boot_check_header_erased(state, BOOT_PRIMARY_SLOT) != 0)) {
1965#else
Fabio Utzig74aef312019-11-28 11:05:34 -03001966 if (rc != 0) {
Fabio Utzig32afe852020-10-04 10:36:02 -03001967#endif
1968
Fabio Utzig74aef312019-11-28 11:05:34 -03001969 /* Continue with next image if there is one. */
1970 BOOT_LOG_WRN("Failed reading image headers; Image=%u",
1971 BOOT_CURR_IMG(state));
1972 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
1973 return;
1974 }
1975#endif
1976
David Vinczeba3bd602019-06-17 16:01:43 +02001977 /* Determine if we rebooted in the middle of an image swap
1978 * operation. If a partial swap was detected, complete it.
1979 */
Fabio Utzig12d59162019-11-28 10:01:59 -03001980 if (!boot_status_is_reset(bs)) {
David Vinczeba3bd602019-06-17 16:01:43 +02001981
1982#if (BOOT_IMAGE_NUMBER > 1)
Fabio Utzig10ee6482019-08-01 12:04:52 -03001983 boot_review_image_swap_types(state, true);
David Vinczeba3bd602019-06-17 16:01:43 +02001984#endif
1985
1986#ifdef MCUBOOT_OVERWRITE_ONLY
1987 /* Should never arrive here, overwrite-only mode has
1988 * no swap state.
1989 */
1990 assert(0);
1991#else
1992 /* Determine the type of swap operation being resumed from the
1993 * `swap-type` trailer field.
1994 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001995 rc = boot_complete_partial_swap(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02001996 assert(rc == 0);
1997#endif
1998 /* Attempt to read an image header from each slot. Ensure that
1999 * image headers in slots are aligned with headers in boot_data.
2000 */
Fabio Utzig12d59162019-11-28 10:01:59 -03002001 rc = boot_read_image_headers(state, false, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02002002 assert(rc == 0);
2003
2004 /* Swap has finished set to NONE */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002005 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
David Vinczeba3bd602019-06-17 16:01:43 +02002006 } else {
2007 /* There was no partial swap, determine swap type. */
2008 if (bs->swap_type == BOOT_SWAP_TYPE_NONE) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03002009 BOOT_SWAP_TYPE(state) = boot_validated_swap_type(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02002010 } else {
Raef Colese8fe6cf2020-05-26 13:07:40 +01002011 FIH_CALL(boot_validate_slot, fih_rc,
2012 state, BOOT_SECONDARY_SLOT, bs);
Michael Grand5047f032022-11-24 16:49:56 +01002013 if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
Raef Colese8fe6cf2020-05-26 13:07:40 +01002014 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_FAIL;
2015 } else {
2016 BOOT_SWAP_TYPE(state) = bs->swap_type;
2017 }
David Vinczeba3bd602019-06-17 16:01:43 +02002018 }
2019
2020#if (BOOT_IMAGE_NUMBER > 1)
Fabio Utzig10ee6482019-08-01 12:04:52 -03002021 boot_review_image_swap_types(state, false);
David Vinczeba3bd602019-06-17 16:01:43 +02002022#endif
2023
2024#ifdef MCUBOOT_BOOTSTRAP
Fabio Utzig10ee6482019-08-01 12:04:52 -03002025 if (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_NONE) {
David Vinczeba3bd602019-06-17 16:01:43 +02002026 /* Header checks are done first because they are
2027 * inexpensive. Since overwrite-only copies starting from
2028 * offset 0, if interrupted, it might leave a valid header
2029 * magic, so also run validation on the primary slot to be
2030 * sure it's not OK.
2031 */
Raef Colese8fe6cf2020-05-26 13:07:40 +01002032 rc = boot_check_header_erased(state, BOOT_PRIMARY_SLOT);
2033 FIH_CALL(boot_validate_slot, fih_rc,
2034 state, BOOT_PRIMARY_SLOT, bs);
2035
Michael Grand5047f032022-11-24 16:49:56 +01002036 if (rc == 0 || FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
Raef Colese8fe6cf2020-05-26 13:07:40 +01002037
Fabio Utzig3d77c952020-10-04 10:23:17 -03002038 rc = (boot_img_hdr(state, BOOT_SECONDARY_SLOT)->ih_magic == IMAGE_MAGIC) ? 1: 0;
Raef Colese8fe6cf2020-05-26 13:07:40 +01002039 FIH_CALL(boot_validate_slot, fih_rc,
2040 state, BOOT_SECONDARY_SLOT, bs);
2041
Michael Grand5047f032022-11-24 16:49:56 +01002042 if (rc == 1 && FIH_EQ(fih_rc, FIH_SUCCESS)) {
David Vinczeba3bd602019-06-17 16:01:43 +02002043 /* Set swap type to REVERT to overwrite the primary
2044 * slot with the image contained in secondary slot
2045 * and to trigger the explicit setting of the
2046 * image_ok flag.
2047 */
Fabio Utzig59b63e52019-09-10 12:22:35 -03002048 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_REVERT;
David Vinczeba3bd602019-06-17 16:01:43 +02002049 }
Fabio Utzig338a19f2018-12-03 08:37:08 -02002050 }
2051 }
Fabio Utzig338a19f2018-12-03 08:37:08 -02002052#endif
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08002053 }
David Vinczeba3bd602019-06-17 16:01:43 +02002054 } else {
2055 /* In that case if slots are not compatible. */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002056 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08002057 }
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08002058}
2059
Mark Horvathccaf7f82021-01-04 18:16:42 +01002060/**
2061 * Updates the security counter for the current image.
2062 *
2063 * @param state Boot loader status information.
2064 *
2065 * @return 0 on success; nonzero on failure.
2066 */
2067static int
2068boot_update_hw_rollback_protection(struct boot_loader_state *state)
2069{
2070#ifdef MCUBOOT_HW_ROLLBACK_PROT
2071 int rc;
2072
2073 /* Update the stored security counter with the active image's security
2074 * counter value. It will only be updated if the new security counter is
2075 * greater than the stored value.
2076 *
2077 * In case of a successful image swapping when the swap type is TEST the
2078 * security counter can be increased only after a reset, when the swap
2079 * type is NONE and the image has marked itself "OK" (the image_ok flag
2080 * has been set). This way a "revert" can be performed when it's
2081 * necessary.
2082 */
2083 if (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_NONE) {
2084 rc = boot_update_security_counter(
2085 BOOT_CURR_IMG(state),
2086 BOOT_PRIMARY_SLOT,
2087 boot_img_hdr(state, BOOT_PRIMARY_SLOT));
2088 if (rc != 0) {
2089 BOOT_LOG_ERR("Security counter update failed after image "
2090 "validation.");
2091 return rc;
2092 }
2093 }
2094
2095 return 0;
2096
2097#else /* MCUBOOT_HW_ROLLBACK_PROT */
2098 (void) (state);
2099
2100 return 0;
2101#endif
2102}
2103
Jerzy Kasenberge3f895d2022-04-12 15:05:33 +02002104/**
2105 * Checks test swap downgrade prevention conditions.
2106 *
2107 * Function called only for swap upgrades test run. It may prevent
2108 * swap if slot 1 image has <= version number or < security counter
2109 *
2110 * @param state Boot loader status information.
2111 *
2112 * @return 0 - image can be swapped, -1 downgrade prevention
2113 */
2114static int
2115check_downgrade_prevention(struct boot_loader_state *state)
2116{
2117#if defined(MCUBOOT_DOWNGRADE_PREVENTION) && \
2118 (defined(MCUBOOT_SWAP_USING_MOVE) || defined(MCUBOOT_SWAP_USING_SCRATCH))
2119 uint32_t security_counter[2];
2120 int rc;
2121
2122 if (MCUBOOT_DOWNGRADE_PREVENTION_SECURITY_COUNTER) {
2123 /* If there was security no counter in slot 0, allow swap */
2124 rc = bootutil_get_img_security_cnt(&(BOOT_IMG(state, 0).hdr),
2125 BOOT_IMG(state, 0).area,
2126 &security_counter[0]);
2127 if (rc != 0) {
2128 return 0;
2129 }
2130 /* If there is no security counter in slot 1, or it's lower than
2131 * that of slot 0, prevent downgrade */
2132 rc = bootutil_get_img_security_cnt(&(BOOT_IMG(state, 1).hdr),
2133 BOOT_IMG(state, 1).area,
2134 &security_counter[1]);
2135 if (rc != 0 || security_counter[0] > security_counter[1]) {
2136 rc = -1;
2137 }
2138 }
2139 else {
2140 rc = boot_version_cmp(&boot_img_hdr(state, BOOT_SECONDARY_SLOT)->ih_ver,
2141 &boot_img_hdr(state, BOOT_PRIMARY_SLOT)->ih_ver);
2142 }
2143 if (rc < 0) {
2144 /* Image in slot 0 prevents downgrade, delete image in slot 1 */
Antonio de Angelis48547002023-04-14 09:47:09 +01002145 BOOT_LOG_INF("Image %d in slot 1 erased due to downgrade prevention", BOOT_CURR_IMG(state));
Jerzy Kasenberge3f895d2022-04-12 15:05:33 +02002146 flash_area_erase(BOOT_IMG(state, 1).area, 0,
2147 flash_area_get_size(BOOT_IMG(state, 1).area));
2148 } else {
2149 rc = 0;
2150 }
2151 return rc;
2152#else
2153 (void)state;
2154 return 0;
2155#endif
2156}
2157
Jamie McCraee261b282024-07-26 11:48:19 +01002158#if !defined(__BOOTSIM__)
2159static void boot_get_sector_buffers(struct sector_buffer_t *buffers)
2160{
2161 /* The array of slot sectors are defined here (as opposed to file scope) so
2162 * that they don't get allocated for non-boot-loader apps. This is
2163 * necessary because the gcc option "-fdata-sections" doesn't seem to have
2164 * any effect in older gcc versions (e.g., 4.8.4).
2165 */
2166 static boot_sector_t primary_slot_sectors[BOOT_IMAGE_NUMBER][BOOT_MAX_IMG_SECTORS];
2167 static boot_sector_t secondary_slot_sectors[BOOT_IMAGE_NUMBER][BOOT_MAX_IMG_SECTORS];
2168#if MCUBOOT_SWAP_USING_SCRATCH
2169 static boot_sector_t scratch_sectors[BOOT_MAX_IMG_SECTORS];
2170#endif
2171
2172 buffers->primary = (boot_sector_t *)&primary_slot_sectors;
2173 buffers->secondary = (boot_sector_t *)&secondary_slot_sectors;
2174#if MCUBOOT_SWAP_USING_SCRATCH
2175 buffers->scratch = (boot_sector_t *)&scratch_sectors;
2176#endif
2177}
2178#endif
2179
Michael Grand5047f032022-11-24 16:49:56 +01002180fih_ret
Fabio Utzig10ee6482019-08-01 12:04:52 -03002181context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp)
Christopher Collins92ea77f2016-12-12 15:59:26 -08002182{
Marti Bolivar84898652017-06-13 17:20:22 -04002183 size_t slot;
David Vinczeba3bd602019-06-17 16:01:43 +02002184 struct boot_status bs;
Jamie McCraee261b282024-07-26 11:48:19 +01002185#if !defined(__BOOTSIM__)
2186 struct sector_buffer_t sector_buffers;
2187#endif
David Vincze9015a5d2020-05-18 14:43:11 +02002188 int rc = -1;
Michael Grand5047f032022-11-24 16:49:56 +01002189 FIH_DECLARE(fih_rc, FIH_FAILURE);
Marti Bolivarc0b47912017-06-13 17:18:09 -04002190 int fa_id;
Fabio Utzigb0f04732019-07-31 09:49:19 -03002191 int image_index;
Fabio Utzig298913b2019-08-28 11:22:45 -03002192 bool has_upgrade;
Michael Grand5047f032022-11-24 16:49:56 +01002193 volatile int fih_cnt;
Christopher Collins92ea77f2016-12-12 15:59:26 -08002194
Jamie McCraee261b282024-07-26 11:48:19 +01002195#if defined(__BOOTSIM__)
Christopher Collins92ea77f2016-12-12 15:59:26 -08002196 /* The array of slot sectors are defined here (as opposed to file scope) so
2197 * that they don't get allocated for non-boot-loader apps. This is
2198 * necessary because the gcc option "-fdata-sections" doesn't seem to have
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08002199 * any effect in older gcc versions (e.g., 4.8.4).
Christopher Collins92ea77f2016-12-12 15:59:26 -08002200 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002201 TARGET_STATIC boot_sector_t primary_slot_sectors[BOOT_IMAGE_NUMBER][BOOT_MAX_IMG_SECTORS];
2202 TARGET_STATIC boot_sector_t secondary_slot_sectors[BOOT_IMAGE_NUMBER][BOOT_MAX_IMG_SECTORS];
Fabio Utzig12d59162019-11-28 10:01:59 -03002203#if MCUBOOT_SWAP_USING_SCRATCH
Fabio Utzig10ee6482019-08-01 12:04:52 -03002204 TARGET_STATIC boot_sector_t scratch_sectors[BOOT_MAX_IMG_SECTORS];
Fabio Utzig12d59162019-11-28 10:01:59 -03002205#endif
Jamie McCraee261b282024-07-26 11:48:19 +01002206#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -08002207
Fabio Utzig298913b2019-08-28 11:22:45 -03002208 has_upgrade = false;
2209
2210#if (BOOT_IMAGE_NUMBER == 1)
2211 (void)has_upgrade;
2212#endif
Fabio Utzigba829042018-09-18 08:29:34 -03002213
Jamie McCraee261b282024-07-26 11:48:19 +01002214#if !defined(__BOOTSIM__)
2215 boot_get_sector_buffers(&sector_buffers);
2216#endif
2217
David Vinczeba3bd602019-06-17 16:01:43 +02002218 /* Iterate over all the images. By the end of the loop the swap type has
2219 * to be determined for each image and all aborted swaps have to be
2220 * completed.
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08002221 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002222 IMAGES_ITER(BOOT_CURR_IMG(state)) {
Raef Colesf11de642021-10-15 11:11:56 +01002223#if BOOT_IMAGE_NUMBER > 1
2224 if (state->img_mask[BOOT_CURR_IMG(state)]) {
2225 continue;
2226 }
2227#endif
David Vinczeba3bd602019-06-17 16:01:43 +02002228#if defined(MCUBOOT_ENC_IMAGES) && (BOOT_IMAGE_NUMBER > 1)
2229 /* The keys used for encryption may no longer be valid (could belong to
2230 * another images). Therefore, mark them as invalid to force their reload
2231 * by boot_enc_load().
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03002232 */
Fabio Utzig1e4284b2019-08-23 11:55:27 -03002233 boot_enc_zeroize(BOOT_CURR_ENC(state));
David Brown554c52e2017-06-30 16:01:07 -06002234#endif
2235
Fabio Utzig10ee6482019-08-01 12:04:52 -03002236 image_index = BOOT_CURR_IMG(state);
Fabio Utzigb0f04732019-07-31 09:49:19 -03002237
Jamie McCraee261b282024-07-26 11:48:19 +01002238#if !defined(__BOOTSIM__)
2239 BOOT_IMG(state, BOOT_PRIMARY_SLOT).sectors =
2240 &sector_buffers.primary[image_index];
2241 BOOT_IMG(state, BOOT_SECONDARY_SLOT).sectors =
2242 &sector_buffers.secondary[image_index];
2243#if MCUBOOT_SWAP_USING_SCRATCH
2244 state->scratch.sectors = sector_buffers.scratch;
2245#endif
2246#else
Fabio Utzig10ee6482019-08-01 12:04:52 -03002247 BOOT_IMG(state, BOOT_PRIMARY_SLOT).sectors =
Fabio Utzigb0f04732019-07-31 09:49:19 -03002248 primary_slot_sectors[image_index];
Fabio Utzig10ee6482019-08-01 12:04:52 -03002249 BOOT_IMG(state, BOOT_SECONDARY_SLOT).sectors =
Fabio Utzigb0f04732019-07-31 09:49:19 -03002250 secondary_slot_sectors[image_index];
Fabio Utzig12d59162019-11-28 10:01:59 -03002251#if MCUBOOT_SWAP_USING_SCRATCH
Fabio Utzig10ee6482019-08-01 12:04:52 -03002252 state->scratch.sectors = scratch_sectors;
Fabio Utzig12d59162019-11-28 10:01:59 -03002253#endif
Jamie McCraee261b282024-07-26 11:48:19 +01002254#endif
David Vinczeba3bd602019-06-17 16:01:43 +02002255
2256 /* Open primary and secondary image areas for the duration
2257 * of this call.
2258 */
2259 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
Fabio Utzigb0f04732019-07-31 09:49:19 -03002260 fa_id = flash_area_id_from_multi_image_slot(image_index, slot);
Fabio Utzig10ee6482019-08-01 12:04:52 -03002261 rc = flash_area_open(fa_id, &BOOT_IMG_AREA(state, slot));
David Vinczeba3bd602019-06-17 16:01:43 +02002262 assert(rc == 0);
Jamie McCrae2929a972023-09-25 11:12:20 +01002263
2264 if (rc != 0) {
2265 BOOT_LOG_ERR("Failed to open flash area ID %d (image %d slot %d): %d, "
2266 "cannot continue", fa_id, image_index, (int8_t)slot, rc);
2267 FIH_PANIC;
2268 }
David Vinczeba3bd602019-06-17 16:01:43 +02002269 }
Fabio Utzig12d59162019-11-28 10:01:59 -03002270#if MCUBOOT_SWAP_USING_SCRATCH
David Vinczeba3bd602019-06-17 16:01:43 +02002271 rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH,
Fabio Utzig10ee6482019-08-01 12:04:52 -03002272 &BOOT_SCRATCH_AREA(state));
David Vinczeba3bd602019-06-17 16:01:43 +02002273 assert(rc == 0);
Jamie McCrae2929a972023-09-25 11:12:20 +01002274
2275 if (rc != 0) {
2276 BOOT_LOG_ERR("Failed to open scratch flash area: %d, cannot continue", rc);
2277 FIH_PANIC;
2278 }
Fabio Utzig12d59162019-11-28 10:01:59 -03002279#endif
David Vinczeba3bd602019-06-17 16:01:43 +02002280
2281 /* Determine swap type and complete swap if it has been aborted. */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002282 boot_prepare_image_for_update(state, &bs);
Fabio Utzig298913b2019-08-28 11:22:45 -03002283
Fabio Utzige575b0b2019-09-11 12:34:23 -03002284 if (BOOT_IS_UPGRADE(BOOT_SWAP_TYPE(state))) {
Fabio Utzig298913b2019-08-28 11:22:45 -03002285 has_upgrade = true;
2286 }
David Vinczeba3bd602019-06-17 16:01:43 +02002287 }
2288
David Vinczee32483f2019-06-13 10:46:24 +02002289#if (BOOT_IMAGE_NUMBER > 1)
Fabio Utzig298913b2019-08-28 11:22:45 -03002290 if (has_upgrade) {
2291 /* Iterate over all the images and verify whether the image dependencies
2292 * are all satisfied and update swap type if necessary.
2293 */
2294 rc = boot_verify_dependencies(state);
David Vincze8b0b6372020-05-20 19:54:44 +02002295 if (rc != 0) {
Fabio Utzig298913b2019-08-28 11:22:45 -03002296 /*
2297 * It was impossible to upgrade because the expected dependency version
2298 * was not available. Here we already changed the swap_type so that
2299 * instead of asserting the bootloader, we continue and no upgrade is
2300 * performed.
2301 */
2302 rc = 0;
2303 }
2304 }
David Vinczee32483f2019-06-13 10:46:24 +02002305#endif
2306
Jamie McCrae56cb6102022-03-23 11:57:03 +00002307 /* Trigger status change callback with upgrading status */
2308 mcuboot_status_change(MCUBOOT_STATUS_UPGRADING);
2309
David Vinczeba3bd602019-06-17 16:01:43 +02002310 /* Iterate over all the images. At this point there are no aborted swaps
2311 * and the swap types are determined for each image. By the end of the loop
2312 * all required update operations will have been finished.
2313 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002314 IMAGES_ITER(BOOT_CURR_IMG(state)) {
David Vinczeba3bd602019-06-17 16:01:43 +02002315#if (BOOT_IMAGE_NUMBER > 1)
Raef Colesf11de642021-10-15 11:11:56 +01002316 if (state->img_mask[BOOT_CURR_IMG(state)]) {
2317 continue;
2318 }
2319
David Vinczeba3bd602019-06-17 16:01:43 +02002320#ifdef MCUBOOT_ENC_IMAGES
2321 /* The keys used for encryption may no longer be valid (could belong to
2322 * another images). Therefore, mark them as invalid to force their reload
2323 * by boot_enc_load().
2324 */
Fabio Utzig1e4284b2019-08-23 11:55:27 -03002325 boot_enc_zeroize(BOOT_CURR_ENC(state));
David Vinczeba3bd602019-06-17 16:01:43 +02002326#endif /* MCUBOOT_ENC_IMAGES */
2327
2328 /* Indicate that swap is not aborted */
Fabio Utzig12d59162019-11-28 10:01:59 -03002329 boot_status_reset(&bs);
David Vinczeba3bd602019-06-17 16:01:43 +02002330#endif /* (BOOT_IMAGE_NUMBER > 1) */
2331
2332 /* Set the previously determined swap type */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002333 bs.swap_type = BOOT_SWAP_TYPE(state);
David Vinczeba3bd602019-06-17 16:01:43 +02002334
Fabio Utzig10ee6482019-08-01 12:04:52 -03002335 switch (BOOT_SWAP_TYPE(state)) {
David Vinczeba3bd602019-06-17 16:01:43 +02002336 case BOOT_SWAP_TYPE_NONE:
2337 break;
2338
Jerzy Kasenberge3f895d2022-04-12 15:05:33 +02002339 case BOOT_SWAP_TYPE_TEST:
Michael Grand99613c62023-06-20 15:01:00 +02002340 /* fallthrough */
2341 case BOOT_SWAP_TYPE_PERM:
Jerzy Kasenberge3f895d2022-04-12 15:05:33 +02002342 if (check_downgrade_prevention(state) != 0) {
2343 /* Downgrade prevented */
2344 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
2345 break;
2346 }
2347 /* fallthrough */
David Vinczeba3bd602019-06-17 16:01:43 +02002348 case BOOT_SWAP_TYPE_REVERT:
Andrzej Puzdrowskib8f39692021-07-02 15:05:37 +02002349 rc = BOOT_HOOK_CALL(boot_perform_update_hook, BOOT_HOOK_REGULAR,
2350 BOOT_CURR_IMG(state), &(BOOT_IMG(state, 1).hdr),
2351 BOOT_IMG_AREA(state, BOOT_SECONDARY_SLOT));
2352 if (rc == BOOT_HOOK_REGULAR)
2353 {
2354 rc = boot_perform_update(state, &bs);
2355 }
David Vinczeba3bd602019-06-17 16:01:43 +02002356 assert(rc == 0);
2357 break;
2358
2359 case BOOT_SWAP_TYPE_FAIL:
2360 /* The image in secondary slot was invalid and is now erased. Ensure
2361 * we don't try to boot into it again on the next reboot. Do this by
2362 * pretending we just reverted back to primary slot.
2363 */
2364#ifndef MCUBOOT_OVERWRITE_ONLY
2365 /* image_ok needs to be explicitly set to avoid a new revert. */
Fabio Utzig12d59162019-11-28 10:01:59 -03002366 rc = swap_set_image_ok(BOOT_CURR_IMG(state));
David Vinczeba3bd602019-06-17 16:01:43 +02002367 if (rc != 0) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03002368 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
David Vinczeba3bd602019-06-17 16:01:43 +02002369 }
2370#endif /* !MCUBOOT_OVERWRITE_ONLY */
2371 break;
2372
2373 default:
Fabio Utzig10ee6482019-08-01 12:04:52 -03002374 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
David Vinczeba3bd602019-06-17 16:01:43 +02002375 }
2376
Fabio Utzig10ee6482019-08-01 12:04:52 -03002377 if (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_PANIC) {
David Vinczeba3bd602019-06-17 16:01:43 +02002378 BOOT_LOG_ERR("panic!");
2379 assert(0);
2380
2381 /* Loop forever... */
Raef Colese8fe6cf2020-05-26 13:07:40 +01002382 FIH_PANIC;
David Vinczeba3bd602019-06-17 16:01:43 +02002383 }
2384 }
2385
2386 /* Iterate over all the images. At this point all required update operations
2387 * have finished. By the end of the loop each image in the primary slot will
2388 * have been re-validated.
2389 */
Michael Grand5047f032022-11-24 16:49:56 +01002390 FIH_SET(fih_cnt, 0);
Fabio Utzig10ee6482019-08-01 12:04:52 -03002391 IMAGES_ITER(BOOT_CURR_IMG(state)) {
Raef Colesf11de642021-10-15 11:11:56 +01002392#if BOOT_IMAGE_NUMBER > 1
Michael Grand5047f032022-11-24 16:49:56 +01002393 /* Hardenned to prevent from skipping check of a given image,
2394 * tmp_img_mask is declared volatile
2395 */
2396 volatile bool tmp_img_mask;
2397 FIH_SET(tmp_img_mask, state->img_mask[BOOT_CURR_IMG(state)]);
2398 if (FIH_EQ(tmp_img_mask, true)) {
2399 ++fih_cnt;
Raef Colesf11de642021-10-15 11:11:56 +01002400 continue;
2401 }
2402#endif
Fabio Utzig10ee6482019-08-01 12:04:52 -03002403 if (BOOT_SWAP_TYPE(state) != BOOT_SWAP_TYPE_NONE) {
David Vinczeba3bd602019-06-17 16:01:43 +02002404 /* Attempt to read an image header from each slot. Ensure that image
2405 * headers in slots are aligned with headers in boot_data.
Dominik Ermel6f7f8732024-02-01 11:59:24 +00002406 * Note: Quite complicated internal logic of boot_read_image_headers
2407 * uses boot state, the last parm, to figure out in which slot which
2408 * header is located; when boot state is not provided, then it
2409 * is assumed that headers are at proper slots (we are not in
2410 * the middle of moving images, etc).
David Vinczeba3bd602019-06-17 16:01:43 +02002411 */
Dominik Ermel6f7f8732024-02-01 11:59:24 +00002412 rc = boot_read_image_headers(state, false, NULL);
David Vinczeba3bd602019-06-17 16:01:43 +02002413 if (rc != 0) {
Michael Grand5047f032022-11-24 16:49:56 +01002414 FIH_SET(fih_rc, FIH_FAILURE);
David Vinczeba3bd602019-06-17 16:01:43 +02002415 goto out;
2416 }
2417 /* Since headers were reloaded, it can be assumed we just performed
2418 * a swap or overwrite. Now the header info that should be used to
2419 * provide the data for the bootstrap, which previously was at
2420 * secondary slot, was updated to primary slot.
2421 */
2422 }
2423
2424#ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT
Raef Colese8fe6cf2020-05-26 13:07:40 +01002425 FIH_CALL(boot_validate_slot, fih_rc, state, BOOT_PRIMARY_SLOT, NULL);
Michael Grand5047f032022-11-24 16:49:56 +01002426 /* Check for all possible values is redundant in normal operation it
2427 * is meant to prevent FI attack.
2428 */
2429 if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS) ||
2430 FIH_EQ(fih_rc, FIH_FAILURE) ||
2431 FIH_EQ(fih_rc, FIH_NO_BOOTABLE_IMAGE)) {
2432 FIH_SET(fih_rc, FIH_FAILURE);
David Vinczeba3bd602019-06-17 16:01:43 +02002433 goto out;
2434 }
2435#else
2436 /* Even if we're not re-validating the primary slot, we could be booting
2437 * onto an empty flash chip. At least do a basic sanity check that
2438 * the magic number on the image is OK.
2439 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002440 if (BOOT_IMG(state, BOOT_PRIMARY_SLOT).hdr.ih_magic != IMAGE_MAGIC) {
David Vinczeba3bd602019-06-17 16:01:43 +02002441 BOOT_LOG_ERR("bad image magic 0x%lx; Image=%u", (unsigned long)
Dominik Ermel4a4d1ac2021-08-06 11:23:52 +00002442 BOOT_IMG(state, BOOT_PRIMARY_SLOT).hdr.ih_magic,
Fabio Utzig10ee6482019-08-01 12:04:52 -03002443 BOOT_CURR_IMG(state));
David Vinczeba3bd602019-06-17 16:01:43 +02002444 rc = BOOT_EBADIMAGE;
Michael Grand5047f032022-11-24 16:49:56 +01002445 FIH_SET(fih_rc, FIH_FAILURE);
David Vinczeba3bd602019-06-17 16:01:43 +02002446 goto out;
2447 }
David Vinczec3084132020-02-18 14:50:47 +01002448#endif /* MCUBOOT_VALIDATE_PRIMARY_SLOT */
2449
Mark Horvathccaf7f82021-01-04 18:16:42 +01002450 rc = boot_update_hw_rollback_protection(state);
David Vincze1cf11b52020-03-24 07:51:09 +01002451 if (rc != 0) {
Michael Grand5047f032022-11-24 16:49:56 +01002452 FIH_SET(fih_rc, FIH_FAILURE);
Raef Colese8fe6cf2020-05-26 13:07:40 +01002453 goto out;
David Vincze1cf11b52020-03-24 07:51:09 +01002454 }
David Vincze1cf11b52020-03-24 07:51:09 +01002455
Mark Horvathccaf7f82021-01-04 18:16:42 +01002456 rc = boot_add_shared_data(state, BOOT_PRIMARY_SLOT);
David Vincze1cf11b52020-03-24 07:51:09 +01002457 if (rc != 0) {
Michael Grand5047f032022-11-24 16:49:56 +01002458 FIH_SET(fih_rc, FIH_FAILURE);
Raef Colese8fe6cf2020-05-26 13:07:40 +01002459 goto out;
David Vincze1cf11b52020-03-24 07:51:09 +01002460 }
Michael Grand5047f032022-11-24 16:49:56 +01002461 ++fih_cnt;
David Vinczeba3bd602019-06-17 16:01:43 +02002462 }
Michael Grand5047f032022-11-24 16:49:56 +01002463 /*
2464 * fih_cnt should be equal to BOOT_IMAGE_NUMBER now.
2465 * If this is not the case, at least one iteration of the loop
2466 * has been skipped.
2467 */
2468 if(FIH_NOT_EQ(fih_cnt, BOOT_IMAGE_NUMBER)) {
2469 FIH_PANIC;
2470 }
Fabio Utzigf616c542019-12-19 15:23:32 -03002471
Raef Colesfe57e7d2021-10-15 11:07:09 +01002472 fill_rsp(state, rsp);
Christopher Collins92ea77f2016-12-12 15:59:26 -08002473
Raef Colese8fe6cf2020-05-26 13:07:40 +01002474 fih_rc = FIH_SUCCESS;
Fabio Utzig298913b2019-08-28 11:22:45 -03002475out:
Dominik Ermel256bc372022-12-07 15:51:31 +00002476 /*
2477 * Since the boot_status struct stores plaintext encryption keys, reset
2478 * them here to avoid the possibility of jumping into an image that could
2479 * easily recover them.
2480 */
2481#if defined(MCUBOOT_ENC_IMAGES) || defined(MCUBOOT_SWAP_SAVE_ENCTLV)
2482 like_mbedtls_zeroize(&bs, sizeof(bs));
2483#else
2484 memset(&bs, 0, sizeof(struct boot_status));
2485#endif
2486
Mark Horvathccaf7f82021-01-04 18:16:42 +01002487 close_all_flash_areas(state);
Raef Colese8fe6cf2020-05-26 13:07:40 +01002488 FIH_RET(fih_rc);
Christopher Collins92ea77f2016-12-12 15:59:26 -08002489}
2490
Michael Grand5047f032022-11-24 16:49:56 +01002491fih_ret
Christopher Collins92ea77f2016-12-12 15:59:26 -08002492split_go(int loader_slot, int split_slot, void **entry)
2493{
Marti Bolivarc50926f2017-06-14 09:35:40 -04002494 boot_sector_t *sectors;
Christopher Collins034a6202017-01-11 12:19:37 -08002495 uintptr_t entry_val;
Christopher Collins92ea77f2016-12-12 15:59:26 -08002496 int loader_flash_id;
Marti Bolivarc0b47912017-06-13 17:18:09 -04002497 int split_flash_id;
Christopher Collins92ea77f2016-12-12 15:59:26 -08002498 int rc;
Michael Grand5047f032022-11-24 16:49:56 +01002499 FIH_DECLARE(fih_rc, FIH_FAILURE);
Christopher Collins92ea77f2016-12-12 15:59:26 -08002500
Christopher Collins92ea77f2016-12-12 15:59:26 -08002501 sectors = malloc(BOOT_MAX_IMG_SECTORS * 2 * sizeof *sectors);
2502 if (sectors == NULL) {
Raef Colese8fe6cf2020-05-26 13:07:40 +01002503 FIH_RET(FIH_FAILURE);
Christopher Collins92ea77f2016-12-12 15:59:26 -08002504 }
David Vinczeba3bd602019-06-17 16:01:43 +02002505 BOOT_IMG(&boot_data, loader_slot).sectors = sectors + 0;
2506 BOOT_IMG(&boot_data, split_slot).sectors = sectors + BOOT_MAX_IMG_SECTORS;
Marti Bolivarc0b47912017-06-13 17:18:09 -04002507
2508 loader_flash_id = flash_area_id_from_image_slot(loader_slot);
2509 rc = flash_area_open(loader_flash_id,
Alvaro Prieto63a2bdb2019-07-04 12:18:49 -07002510 &BOOT_IMG_AREA(&boot_data, loader_slot));
Marti Bolivarc0b47912017-06-13 17:18:09 -04002511 assert(rc == 0);
2512 split_flash_id = flash_area_id_from_image_slot(split_slot);
2513 rc = flash_area_open(split_flash_id,
2514 &BOOT_IMG_AREA(&boot_data, split_slot));
2515 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -08002516
2517 /* Determine the sector layout of the image slots and scratch area. */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002518 rc = boot_read_sectors(&boot_data);
Christopher Collins92ea77f2016-12-12 15:59:26 -08002519 if (rc != 0) {
2520 rc = SPLIT_GO_ERR;
2521 goto done;
2522 }
2523
Fabio Utzig12d59162019-11-28 10:01:59 -03002524 rc = boot_read_image_headers(&boot_data, true, NULL);
Christopher Collins92ea77f2016-12-12 15:59:26 -08002525 if (rc != 0) {
2526 goto done;
2527 }
2528
Christopher Collins92ea77f2016-12-12 15:59:26 -08002529 /* Don't check the bootable image flag because we could really call a
2530 * bootable or non-bootable image. Just validate that the image check
2531 * passes which is distinct from the normal check.
2532 */
Raef Colese8fe6cf2020-05-26 13:07:40 +01002533 FIH_CALL(split_image_check, fih_rc,
2534 boot_img_hdr(&boot_data, split_slot),
2535 BOOT_IMG_AREA(&boot_data, split_slot),
2536 boot_img_hdr(&boot_data, loader_slot),
2537 BOOT_IMG_AREA(&boot_data, loader_slot));
Michael Grand5047f032022-11-24 16:49:56 +01002538 if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
Christopher Collins92ea77f2016-12-12 15:59:26 -08002539 goto done;
2540 }
2541
Marti Bolivarea088872017-06-12 17:10:49 -04002542 entry_val = boot_img_slot_off(&boot_data, split_slot) +
Marti Bolivarf804f622017-06-12 15:41:48 -04002543 boot_img_hdr(&boot_data, split_slot)->ih_hdr_size;
Christopher Collins034a6202017-01-11 12:19:37 -08002544 *entry = (void *) entry_val;
Christopher Collins92ea77f2016-12-12 15:59:26 -08002545 rc = SPLIT_GO_OK;
2546
2547done:
Marti Bolivarc0b47912017-06-13 17:18:09 -04002548 flash_area_close(BOOT_IMG_AREA(&boot_data, split_slot));
2549 flash_area_close(BOOT_IMG_AREA(&boot_data, loader_slot));
Christopher Collins92ea77f2016-12-12 15:59:26 -08002550 free(sectors);
Raef Colese8fe6cf2020-05-26 13:07:40 +01002551
2552 if (rc) {
Michael Grand5047f032022-11-24 16:49:56 +01002553 FIH_SET(fih_rc, FIH_FAILURE);
Raef Colese8fe6cf2020-05-26 13:07:40 +01002554 }
2555
2556 FIH_RET(fih_rc);
Christopher Collins92ea77f2016-12-12 15:59:26 -08002557}
David Vinczee574f2d2020-07-10 11:42:03 +02002558
Tamas Banfe031092020-09-10 17:32:39 +02002559#else /* MCUBOOT_DIRECT_XIP || MCUBOOT_RAM_LOAD */
David Vinczee574f2d2020-07-10 11:42:03 +02002560
2561/**
Mark Horvathccaf7f82021-01-04 18:16:42 +01002562 * Opens all flash areas and checks which contain an image with a valid header.
David Vinczee574f2d2020-07-10 11:42:03 +02002563 *
Mark Horvathccaf7f82021-01-04 18:16:42 +01002564 * @param state Boot loader status information.
David Vinczee574f2d2020-07-10 11:42:03 +02002565 *
Mark Horvathccaf7f82021-01-04 18:16:42 +01002566 * @return 0 on success; nonzero on failure.
2567 */
2568static int
Raef Colesfe57e7d2021-10-15 11:07:09 +01002569boot_get_slot_usage(struct boot_loader_state *state)
Mark Horvathccaf7f82021-01-04 18:16:42 +01002570{
2571 uint32_t slot;
2572 int fa_id;
2573 int rc;
2574 struct image_header *hdr = NULL;
2575
2576 IMAGES_ITER(BOOT_CURR_IMG(state)) {
Raef Colesf11de642021-10-15 11:11:56 +01002577#if BOOT_IMAGE_NUMBER > 1
2578 if (state->img_mask[BOOT_CURR_IMG(state)]) {
2579 continue;
2580 }
2581#endif
Mark Horvathccaf7f82021-01-04 18:16:42 +01002582 /* Open all the slots */
2583 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
2584 fa_id = flash_area_id_from_multi_image_slot(
2585 BOOT_CURR_IMG(state), slot);
2586 rc = flash_area_open(fa_id, &BOOT_IMG_AREA(state, slot));
2587 assert(rc == 0);
2588 }
2589
2590 /* Attempt to read an image header from each slot. */
2591 rc = boot_read_image_headers(state, false, NULL);
2592 if (rc != 0) {
2593 BOOT_LOG_WRN("Failed reading image headers.");
2594 return rc;
2595 }
2596
2597 /* Check headers in all slots */
2598 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
2599 hdr = boot_img_hdr(state, slot);
2600
Jamie McCraedbb5c782024-08-22 10:43:14 +01002601 if (boot_is_header_valid(hdr, BOOT_IMG_AREA(state, slot), state)) {
Raef Colesfe57e7d2021-10-15 11:07:09 +01002602 state->slot_usage[BOOT_CURR_IMG(state)].slot_available[slot] = true;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002603 BOOT_LOG_IMAGE_INFO(slot, hdr);
2604 } else {
Raef Colesfe57e7d2021-10-15 11:07:09 +01002605 state->slot_usage[BOOT_CURR_IMG(state)].slot_available[slot] = false;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002606 BOOT_LOG_INF("Image %d %s slot: Image not found",
2607 BOOT_CURR_IMG(state),
2608 (slot == BOOT_PRIMARY_SLOT)
2609 ? "Primary" : "Secondary");
2610 }
2611 }
2612
Raef Colesfe57e7d2021-10-15 11:07:09 +01002613 state->slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002614 }
2615
2616 return 0;
2617}
2618
2619/**
2620 * Finds the slot containing the image with the highest version number for the
2621 * current image.
2622 *
2623 * @param state Boot loader status information.
Mark Horvathccaf7f82021-01-04 18:16:42 +01002624 *
2625 * @return NO_ACTIVE_SLOT if no available slot found, number of
2626 * the found slot otherwise.
David Vinczee574f2d2020-07-10 11:42:03 +02002627 */
2628static uint32_t
Raef Colesfe57e7d2021-10-15 11:07:09 +01002629find_slot_with_highest_version(struct boot_loader_state *state)
David Vinczee574f2d2020-07-10 11:42:03 +02002630{
David Vinczee574f2d2020-07-10 11:42:03 +02002631 uint32_t slot;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002632 uint32_t candidate_slot = NO_ACTIVE_SLOT;
2633 int rc;
David Vinczee574f2d2020-07-10 11:42:03 +02002634
Mark Horvathccaf7f82021-01-04 18:16:42 +01002635 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
Raef Colesfe57e7d2021-10-15 11:07:09 +01002636 if (state->slot_usage[BOOT_CURR_IMG(state)].slot_available[slot]) {
Mark Horvathccaf7f82021-01-04 18:16:42 +01002637 if (candidate_slot == NO_ACTIVE_SLOT) {
2638 candidate_slot = slot;
2639 } else {
2640 rc = boot_version_cmp(
2641 &boot_img_hdr(state, slot)->ih_ver,
2642 &boot_img_hdr(state, candidate_slot)->ih_ver);
2643 if (rc == 1) {
2644 /* The version of the image being examined is greater than
2645 * the version of the current candidate.
2646 */
2647 candidate_slot = slot;
2648 }
2649 }
David Vinczee574f2d2020-07-10 11:42:03 +02002650 }
2651 }
2652
Mark Horvathccaf7f82021-01-04 18:16:42 +01002653 return candidate_slot;
David Vinczee574f2d2020-07-10 11:42:03 +02002654}
2655
Mark Horvathccaf7f82021-01-04 18:16:42 +01002656#ifdef MCUBOOT_HAVE_LOGGING
2657/**
2658 * Prints the state of the loaded images.
2659 *
2660 * @param state Boot loader status information.
Mark Horvathccaf7f82021-01-04 18:16:42 +01002661 */
2662static void
Raef Colesfe57e7d2021-10-15 11:07:09 +01002663print_loaded_images(struct boot_loader_state *state)
Mark Horvathccaf7f82021-01-04 18:16:42 +01002664{
2665 uint32_t active_slot;
2666
David Brown695e5912021-05-24 16:58:01 -06002667 (void)state;
2668
Mark Horvathccaf7f82021-01-04 18:16:42 +01002669 IMAGES_ITER(BOOT_CURR_IMG(state)) {
Raef Colesf11de642021-10-15 11:11:56 +01002670#if BOOT_IMAGE_NUMBER > 1
2671 if (state->img_mask[BOOT_CURR_IMG(state)]) {
2672 continue;
2673 }
2674#endif
Raef Colesfe57e7d2021-10-15 11:07:09 +01002675 active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002676
2677 BOOT_LOG_INF("Image %d loaded from the %s slot",
2678 BOOT_CURR_IMG(state),
2679 (active_slot == BOOT_PRIMARY_SLOT) ?
2680 "primary" : "secondary");
2681 }
2682}
2683#endif
2684
David Vincze1c456242021-06-29 15:25:24 +02002685#if defined(MCUBOOT_DIRECT_XIP) && defined(MCUBOOT_DIRECT_XIP_REVERT)
David Vincze505fba22020-10-22 13:53:29 +02002686/**
Mark Horvathccaf7f82021-01-04 18:16:42 +01002687 * Checks whether the active slot of the current image was previously selected
2688 * to run. Erases the image if it was selected but its execution failed,
2689 * otherwise marks it as selected if it has not been before.
David Vincze505fba22020-10-22 13:53:29 +02002690 *
Mark Horvathccaf7f82021-01-04 18:16:42 +01002691 * @param state Boot loader status information.
David Vincze505fba22020-10-22 13:53:29 +02002692 *
Mark Horvathccaf7f82021-01-04 18:16:42 +01002693 * @return 0 on success; nonzero on failure.
David Vincze505fba22020-10-22 13:53:29 +02002694 */
2695static int
Raef Colesfe57e7d2021-10-15 11:07:09 +01002696boot_select_or_erase(struct boot_loader_state *state)
David Vincze505fba22020-10-22 13:53:29 +02002697{
2698 const struct flash_area *fap;
2699 int fa_id;
2700 int rc;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002701 uint32_t active_slot;
2702 struct boot_swap_state* active_swap_state;
David Vincze505fba22020-10-22 13:53:29 +02002703
Raef Colesfe57e7d2021-10-15 11:07:09 +01002704 active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002705
2706 fa_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), active_slot);
David Vincze505fba22020-10-22 13:53:29 +02002707 rc = flash_area_open(fa_id, &fap);
2708 assert(rc == 0);
2709
Raef Colesfe57e7d2021-10-15 11:07:09 +01002710 active_swap_state = &(state->slot_usage[BOOT_CURR_IMG(state)].swap_state);
Mark Horvathccaf7f82021-01-04 18:16:42 +01002711
2712 memset(active_swap_state, 0, sizeof(struct boot_swap_state));
2713 rc = boot_read_swap_state(fap, active_swap_state);
David Vincze505fba22020-10-22 13:53:29 +02002714 assert(rc == 0);
2715
Mark Horvathccaf7f82021-01-04 18:16:42 +01002716 if (active_swap_state->magic != BOOT_MAGIC_GOOD ||
2717 (active_swap_state->copy_done == BOOT_FLAG_SET &&
2718 active_swap_state->image_ok != BOOT_FLAG_SET)) {
David Vincze505fba22020-10-22 13:53:29 +02002719 /*
2720 * A reboot happened without the image being confirmed at
2721 * runtime or its trailer is corrupted/invalid. Erase the image
2722 * to prevent it from being selected again on the next reboot.
2723 */
2724 BOOT_LOG_DBG("Erasing faulty image in the %s slot.",
Carlos Falgueras Garcíaae13c3c2021-06-21 17:20:31 +02002725 (active_slot == BOOT_PRIMARY_SLOT) ? "primary" : "secondary");
Dominik Ermel260ae092021-04-23 05:38:45 +00002726 rc = flash_area_erase(fap, 0, flash_area_get_size(fap));
David Vincze505fba22020-10-22 13:53:29 +02002727 assert(rc == 0);
2728
2729 flash_area_close(fap);
2730 rc = -1;
2731 } else {
Mark Horvathccaf7f82021-01-04 18:16:42 +01002732 if (active_swap_state->copy_done != BOOT_FLAG_SET) {
2733 if (active_swap_state->copy_done == BOOT_FLAG_BAD) {
David Vincze505fba22020-10-22 13:53:29 +02002734 BOOT_LOG_DBG("The copy_done flag had an unexpected value. Its "
2735 "value was neither 'set' nor 'unset', but 'bad'.");
2736 }
2737 /*
2738 * Set the copy_done flag, indicating that the image has been
2739 * selected to boot. It can be set in advance, before even
2740 * validating the image, because in case the validation fails, the
2741 * entire image slot will be erased (including the trailer).
2742 */
2743 rc = boot_write_copy_done(fap);
2744 if (rc != 0) {
2745 BOOT_LOG_WRN("Failed to set copy_done flag of the image in "
Carlos Falgueras Garcíaae13c3c2021-06-21 17:20:31 +02002746 "the %s slot.", (active_slot == BOOT_PRIMARY_SLOT) ?
David Vincze505fba22020-10-22 13:53:29 +02002747 "primary" : "secondary");
2748 rc = 0;
2749 }
2750 }
2751 flash_area_close(fap);
2752 }
2753
2754 return rc;
2755}
David Vincze1c456242021-06-29 15:25:24 +02002756#endif /* MCUBOOT_DIRECT_XIP && MCUBOOT_DIRECT_XIP_REVERT */
David Vincze505fba22020-10-22 13:53:29 +02002757
Tamas Banfe031092020-09-10 17:32:39 +02002758#ifdef MCUBOOT_RAM_LOAD
2759
Mark Horvathccaf7f82021-01-04 18:16:42 +01002760#ifndef MULTIPLE_EXECUTABLE_RAM_REGIONS
Tamas Banfe031092020-09-10 17:32:39 +02002761#if !defined(IMAGE_EXECUTABLE_RAM_START) || !defined(IMAGE_EXECUTABLE_RAM_SIZE)
2762#error "Platform MUST define executable RAM bounds in case of RAM_LOAD"
2763#endif
Mark Horvathccaf7f82021-01-04 18:16:42 +01002764#endif
Tamas Banfe031092020-09-10 17:32:39 +02002765
2766/**
Mark Horvathccaf7f82021-01-04 18:16:42 +01002767 * Verifies that the active slot of the current image can be loaded within the
2768 * predefined bounds that are allowed to be used by executable images.
Tamas Banfe031092020-09-10 17:32:39 +02002769 *
Mark Horvathccaf7f82021-01-04 18:16:42 +01002770 * @param state Boot loader status information.
Tamas Banfe031092020-09-10 17:32:39 +02002771 *
Mark Horvathccaf7f82021-01-04 18:16:42 +01002772 * @return 0 on success; nonzero on failure.
Tamas Banfe031092020-09-10 17:32:39 +02002773 */
2774static int
Raef Colesfe57e7d2021-10-15 11:07:09 +01002775boot_verify_ram_load_address(struct boot_loader_state *state)
Tamas Banfe031092020-09-10 17:32:39 +02002776{
Mark Horvathccaf7f82021-01-04 18:16:42 +01002777 uint32_t img_dst;
2778 uint32_t img_sz;
Tamas Banfe031092020-09-10 17:32:39 +02002779 uint32_t img_end_addr;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002780 uint32_t exec_ram_start;
2781 uint32_t exec_ram_size;
David Brown695e5912021-05-24 16:58:01 -06002782
2783 (void)state;
2784
Mark Horvathccaf7f82021-01-04 18:16:42 +01002785#ifdef MULTIPLE_EXECUTABLE_RAM_REGIONS
2786 int rc;
Tamas Banfe031092020-09-10 17:32:39 +02002787
Mark Horvathccaf7f82021-01-04 18:16:42 +01002788 rc = boot_get_image_exec_ram_info(BOOT_CURR_IMG(state), &exec_ram_start,
2789 &exec_ram_size);
2790 if (rc != 0) {
2791 return BOOT_EBADSTATUS;
2792 }
2793#else
2794 exec_ram_start = IMAGE_EXECUTABLE_RAM_START;
2795 exec_ram_size = IMAGE_EXECUTABLE_RAM_SIZE;
2796#endif
2797
Raef Colesfe57e7d2021-10-15 11:07:09 +01002798 img_dst = state->slot_usage[BOOT_CURR_IMG(state)].img_dst;
2799 img_sz = state->slot_usage[BOOT_CURR_IMG(state)].img_sz;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002800
2801 if (img_dst < exec_ram_start) {
Tamas Banfe031092020-09-10 17:32:39 +02002802 return BOOT_EBADIMAGE;
2803 }
2804
2805 if (!boot_u32_safe_add(&img_end_addr, img_dst, img_sz)) {
2806 return BOOT_EBADIMAGE;
2807 }
2808
Mark Horvathccaf7f82021-01-04 18:16:42 +01002809 if (img_end_addr > (exec_ram_start + exec_ram_size)) {
Tamas Banfe031092020-09-10 17:32:39 +02002810 return BOOT_EBADIMAGE;
2811 }
2812
2813 return 0;
2814}
2815
Hugo L'Hostisdb543e52021-03-09 18:00:31 +00002816#ifdef MCUBOOT_ENC_IMAGES
2817
2818/**
2819 * Copies and decrypts an image from a slot in the flash to an SRAM address.
2820 *
2821 * @param state Boot loader status information.
2822 * @param slot The flash slot of the image to be copied to SRAM.
2823 * @param hdr The image header.
2824 * @param src_sz Size of the image.
2825 * @param img_dst Pointer to the address at which the image needs to be
2826 * copied to SRAM.
2827 *
2828 * @return 0 on success; nonzero on failure.
2829 */
2830static int
2831boot_decrypt_and_copy_image_to_sram(struct boot_loader_state *state,
2832 uint32_t slot, struct image_header *hdr,
2833 uint32_t src_sz, uint32_t img_dst)
2834{
2835 /* The flow for the decryption and copy of the image is as follows :
2836 * 1. The whole image is copied to the RAM (header + payload + TLV).
2837 * 2. The encryption key is loaded from the TLV in flash.
2838 * 3. The image is then decrypted chunk by chunk in RAM (1 chunk
2839 * is 1024 bytes). Only the payload section is decrypted.
2840 * 4. The image is authenticated in RAM.
2841 */
2842 const struct flash_area *fap_src = NULL;
2843 struct boot_status bs;
2844 uint32_t blk_off;
2845 uint32_t tlv_off;
2846 uint32_t blk_sz;
2847 uint32_t bytes_copied = hdr->ih_hdr_size;
2848 uint32_t chunk_sz;
2849 uint32_t max_sz = 1024;
2850 uint16_t idx;
Hugo L'Hostisdb543e52021-03-09 18:00:31 +00002851 uint8_t * cur_dst;
2852 int area_id;
2853 int rc;
2854 uint8_t * ram_dst = (void *)(IMAGE_RAM_BASE + img_dst);
2855
Hugo L'Hostisdb543e52021-03-09 18:00:31 +00002856 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
2857 rc = flash_area_open(area_id, &fap_src);
2858 if (rc != 0){
2859 return BOOT_EFLASH;
2860 }
2861
2862 tlv_off = BOOT_TLV_OFF(hdr);
2863
2864 /* Copying the whole image in RAM */
2865 rc = flash_area_read(fap_src, 0, ram_dst, src_sz);
2866 if (rc != 0) {
2867 goto done;
2868 }
2869
Dominik Ermel7f9ac972024-07-12 19:21:40 +00002870 rc = boot_enc_load(BOOT_CURR_ENC(state), slot, hdr, fap_src, &bs);
Hugo L'Hostisdb543e52021-03-09 18:00:31 +00002871 if (rc < 0) {
2872 goto done;
2873 }
2874
2875 /* if rc > 0 then the key has already been loaded */
2876 if (rc == 0 && boot_enc_set_key(BOOT_CURR_ENC(state), slot, &bs)) {
2877 goto done;
2878 }
2879
2880 /* Starting at the end of the header as the header section is not encrypted */
2881 while (bytes_copied < tlv_off) { /* TLV section copied previously */
2882 if (src_sz - bytes_copied > max_sz) {
2883 chunk_sz = max_sz;
2884 } else {
2885 chunk_sz = src_sz - bytes_copied;
2886 }
2887
2888 cur_dst = ram_dst + bytes_copied;
2889 blk_sz = chunk_sz;
2890 idx = 0;
Dominik Ermeld09112a2024-07-18 16:43:57 +00002891 blk_off = ((bytes_copied) - hdr->ih_hdr_size) & 0xf;
Hugo L'Hostisdb543e52021-03-09 18:00:31 +00002892 if (bytes_copied + chunk_sz > tlv_off) {
2893 /* Going over TLV section
2894 * Part of the chunk is encrypted payload */
Hugo L'Hostisdb543e52021-03-09 18:00:31 +00002895 blk_sz = tlv_off - (bytes_copied);
Hugo L'Hostisdb543e52021-03-09 18:00:31 +00002896 }
Dominik Ermel3f112862024-07-17 14:43:05 +00002897 boot_encrypt(BOOT_CURR_ENC(state), slot,
Dominik Ermeld09112a2024-07-18 16:43:57 +00002898 (bytes_copied + idx) - hdr->ih_hdr_size, blk_sz,
2899 blk_off, cur_dst);
Hugo L'Hostisdb543e52021-03-09 18:00:31 +00002900
2901 bytes_copied += chunk_sz;
2902 }
2903 rc = 0;
2904
2905done:
2906 flash_area_close(fap_src);
2907
2908 return rc;
2909}
2910
2911#endif /* MCUBOOT_ENC_IMAGES */
Tamas Banfe031092020-09-10 17:32:39 +02002912/**
Mark Horvathccaf7f82021-01-04 18:16:42 +01002913 * Copies a slot of the current image into SRAM.
Tamas Banfe031092020-09-10 17:32:39 +02002914 *
Mark Horvathccaf7f82021-01-04 18:16:42 +01002915 * @param state Boot loader status information.
Tamas Banfe031092020-09-10 17:32:39 +02002916 * @param slot The flash slot of the image to be copied to SRAM.
2917 * @param img_dst The address at which the image needs to be copied to
2918 * SRAM.
2919 * @param img_sz The size of the image that needs to be copied to SRAM.
2920 *
2921 * @return 0 on success; nonzero on failure.
2922 */
2923static int
Mark Horvathccaf7f82021-01-04 18:16:42 +01002924boot_copy_image_to_sram(struct boot_loader_state *state, int slot,
2925 uint32_t img_dst, uint32_t img_sz)
Tamas Banfe031092020-09-10 17:32:39 +02002926{
2927 int rc;
2928 const struct flash_area *fap_src = NULL;
Mark Horvathccaf7f82021-01-04 18:16:42 +01002929 int area_id;
Tamas Banfe031092020-09-10 17:32:39 +02002930
Mark Horvathccaf7f82021-01-04 18:16:42 +01002931#if (BOOT_IMAGE_NUMBER == 1)
2932 (void)state;
2933#endif
2934
2935 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
2936
2937 rc = flash_area_open(area_id, &fap_src);
Tamas Banfe031092020-09-10 17:32:39 +02002938 if (rc != 0) {
2939 return BOOT_EFLASH;
2940 }
2941
2942 /* Direct copy from flash to its new location in SRAM. */
David Brown9bd7f902021-05-26 16:31:14 -06002943 rc = flash_area_read(fap_src, 0, (void *)(IMAGE_RAM_BASE + img_dst), img_sz);
Tamas Banfe031092020-09-10 17:32:39 +02002944 if (rc != 0) {
Antonio de Angelis48547002023-04-14 09:47:09 +01002945 BOOT_LOG_INF("Error whilst copying image %d from Flash to SRAM: %d",
2946 BOOT_CURR_IMG(state), rc);
Tamas Banfe031092020-09-10 17:32:39 +02002947 }
2948
2949 flash_area_close(fap_src);
2950
2951 return rc;
2952}
2953
Mark Horvathccaf7f82021-01-04 18:16:42 +01002954#if (BOOT_IMAGE_NUMBER > 1)
Tamas Banfe031092020-09-10 17:32:39 +02002955/**
Mark Horvathccaf7f82021-01-04 18:16:42 +01002956 * Checks if two memory regions (A and B) are overlap or not.
Tamas Banfe031092020-09-10 17:32:39 +02002957 *
Mark Horvathccaf7f82021-01-04 18:16:42 +01002958 * @param start_a Start of the A region.
2959 * @param end_a End of the A region.
2960 * @param start_b Start of the B region.
2961 * @param end_b End of the B region.
Tamas Banfe031092020-09-10 17:32:39 +02002962 *
Mark Horvathccaf7f82021-01-04 18:16:42 +01002963 * @return true if there is overlap; false otherwise.
2964 */
2965static bool
2966do_regions_overlap(uint32_t start_a, uint32_t end_a,
2967 uint32_t start_b, uint32_t end_b)
2968{
2969 if (start_b > end_a) {
2970 return false;
2971 } else if (start_b >= start_a) {
2972 return true;
2973 } else if (end_b > start_a) {
2974 return true;
2975 }
2976
2977 return false;
2978}
2979
2980/**
2981 * Checks if the image we want to load to memory overlap with an already
2982 * ramloaded image.
2983 *
Raef Colesfe57e7d2021-10-15 11:07:09 +01002984 * @param state Boot loader status information.
Mark Horvathccaf7f82021-01-04 18:16:42 +01002985 *
2986 * @return 0 if there is no overlap; nonzero otherwise.
Tamas Banfe031092020-09-10 17:32:39 +02002987 */
2988static int
Raef Colesfe57e7d2021-10-15 11:07:09 +01002989boot_check_ram_load_overlapping(struct boot_loader_state *state)
Tamas Banfe031092020-09-10 17:32:39 +02002990{
Mark Horvathccaf7f82021-01-04 18:16:42 +01002991 uint32_t i;
2992
2993 uint32_t start_a;
2994 uint32_t end_a;
2995 uint32_t start_b;
2996 uint32_t end_b;
Raef Colesfe57e7d2021-10-15 11:07:09 +01002997 uint32_t image_id_to_check = BOOT_CURR_IMG(state);
Mark Horvathccaf7f82021-01-04 18:16:42 +01002998
Raef Colesfe57e7d2021-10-15 11:07:09 +01002999 start_a = state->slot_usage[image_id_to_check].img_dst;
Mark Horvathccaf7f82021-01-04 18:16:42 +01003000 /* Safe to add here, values are already verified in
3001 * boot_verify_ram_load_address() */
Raef Colesfe57e7d2021-10-15 11:07:09 +01003002 end_a = start_a + state->slot_usage[image_id_to_check].img_sz;
Mark Horvathccaf7f82021-01-04 18:16:42 +01003003
3004 for (i = 0; i < BOOT_IMAGE_NUMBER; i++) {
Raef Colesfe57e7d2021-10-15 11:07:09 +01003005 if (state->slot_usage[i].active_slot == NO_ACTIVE_SLOT
Mark Horvathccaf7f82021-01-04 18:16:42 +01003006 || i == image_id_to_check) {
3007 continue;
3008 }
3009
Raef Colesfe57e7d2021-10-15 11:07:09 +01003010 start_b = state->slot_usage[i].img_dst;
Mark Horvathccaf7f82021-01-04 18:16:42 +01003011 /* Safe to add here, values are already verified in
3012 * boot_verify_ram_load_address() */
Raef Colesfe57e7d2021-10-15 11:07:09 +01003013 end_b = start_b + state->slot_usage[i].img_sz;
Mark Horvathccaf7f82021-01-04 18:16:42 +01003014
3015 if (do_regions_overlap(start_a, end_a, start_b, end_b)) {
3016 return -1;
3017 }
3018 }
3019
3020 return 0;
3021}
3022#endif
3023
3024/**
3025 * Loads the active slot of the current image into SRAM. The load address and
3026 * image size is extracted from the image header.
3027 *
3028 * @param state Boot loader status information.
Mark Horvathccaf7f82021-01-04 18:16:42 +01003029 *
3030 * @return 0 on success; nonzero on failure.
3031 */
3032static int
Raef Colesfe57e7d2021-10-15 11:07:09 +01003033boot_load_image_to_sram(struct boot_loader_state *state)
Mark Horvathccaf7f82021-01-04 18:16:42 +01003034{
3035 uint32_t active_slot;
3036 struct image_header *hdr = NULL;
3037 uint32_t img_dst;
3038 uint32_t img_sz;
Tamas Banfe031092020-09-10 17:32:39 +02003039 int rc;
3040
Raef Colesfe57e7d2021-10-15 11:07:09 +01003041 active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot;
Mark Horvathccaf7f82021-01-04 18:16:42 +01003042 hdr = boot_img_hdr(state, active_slot);
3043
Tamas Banfe031092020-09-10 17:32:39 +02003044 if (hdr->ih_flags & IMAGE_F_RAM_LOAD) {
3045
Mark Horvathccaf7f82021-01-04 18:16:42 +01003046 img_dst = hdr->ih_load_addr;
Tamas Banfe031092020-09-10 17:32:39 +02003047
Mark Horvathccaf7f82021-01-04 18:16:42 +01003048 rc = boot_read_image_size(state, active_slot, &img_sz);
Tamas Banfe031092020-09-10 17:32:39 +02003049 if (rc != 0) {
3050 return rc;
3051 }
3052
Raef Colesfe57e7d2021-10-15 11:07:09 +01003053 state->slot_usage[BOOT_CURR_IMG(state)].img_dst = img_dst;
3054 state->slot_usage[BOOT_CURR_IMG(state)].img_sz = img_sz;
Mark Horvathccaf7f82021-01-04 18:16:42 +01003055
Raef Colesfe57e7d2021-10-15 11:07:09 +01003056 rc = boot_verify_ram_load_address(state);
Tamas Banfe031092020-09-10 17:32:39 +02003057 if (rc != 0) {
Antonio de Angelisba5fb1c2022-10-11 10:10:37 +01003058 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 +02003059 return rc;
3060 }
3061
Mark Horvathccaf7f82021-01-04 18:16:42 +01003062#if (BOOT_IMAGE_NUMBER > 1)
Raef Colesfe57e7d2021-10-15 11:07:09 +01003063 rc = boot_check_ram_load_overlapping(state);
Mark Horvathccaf7f82021-01-04 18:16:42 +01003064 if (rc != 0) {
Antonio de Angelisba5fb1c2022-10-11 10:10:37 +01003065 BOOT_LOG_INF("Image %d RAM loading to address 0x%x would overlap with\
3066 another image.", BOOT_CURR_IMG(state), img_dst);
Mark Horvathccaf7f82021-01-04 18:16:42 +01003067 return rc;
3068 }
3069#endif
Hugo L'Hostisdb543e52021-03-09 18:00:31 +00003070#ifdef MCUBOOT_ENC_IMAGES
3071 /* decrypt image if encrypted and copy it to RAM */
3072 if (IS_ENCRYPTED(hdr)) {
3073 rc = boot_decrypt_and_copy_image_to_sram(state, active_slot, hdr, img_sz, img_dst);
3074 } else {
3075 rc = boot_copy_image_to_sram(state, active_slot, img_dst, img_sz);
3076 }
3077#else
Tamas Banfe031092020-09-10 17:32:39 +02003078 /* Copy image to the load address from where it currently resides in
3079 * flash.
3080 */
Mark Horvathccaf7f82021-01-04 18:16:42 +01003081 rc = boot_copy_image_to_sram(state, active_slot, img_dst, img_sz);
Hugo L'Hostisdb543e52021-03-09 18:00:31 +00003082#endif
Tamas Banfe031092020-09-10 17:32:39 +02003083 if (rc != 0) {
Antonio de Angelisba5fb1c2022-10-11 10:10:37 +01003084 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 +02003085 } else {
Antonio de Angelisba5fb1c2022-10-11 10:10:37 +01003086 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 +02003087 }
3088 } else {
3089 /* Only images that support IMAGE_F_RAM_LOAD are allowed if
3090 * MCUBOOT_RAM_LOAD is set.
3091 */
3092 rc = BOOT_EBADIMAGE;
3093 }
3094
Mark Horvathccaf7f82021-01-04 18:16:42 +01003095 if (rc != 0) {
Raef Colesfe57e7d2021-10-15 11:07:09 +01003096 state->slot_usage[BOOT_CURR_IMG(state)].img_dst = 0;
3097 state->slot_usage[BOOT_CURR_IMG(state)].img_sz = 0;
Mark Horvathccaf7f82021-01-04 18:16:42 +01003098 }
3099
Tamas Banfe031092020-09-10 17:32:39 +02003100 return rc;
3101}
3102
3103/**
3104 * Removes an image from SRAM, by overwriting it with zeros.
3105 *
Mark Horvathccaf7f82021-01-04 18:16:42 +01003106 * @param state Boot loader status information.
Mark Horvathccaf7f82021-01-04 18:16:42 +01003107 *
3108 * @return 0 on success; nonzero on failure.
3109 */
3110static inline int
Raef Colesfe57e7d2021-10-15 11:07:09 +01003111boot_remove_image_from_sram(struct boot_loader_state *state)
Mark Horvathccaf7f82021-01-04 18:16:42 +01003112{
David Brown695e5912021-05-24 16:58:01 -06003113 (void)state;
3114
Antonio de Angelisba5fb1c2022-10-11 10:10:37 +01003115 BOOT_LOG_INF("Removing image %d from SRAM at address 0x%x",
3116 BOOT_CURR_IMG(state),
Raef Colesfe57e7d2021-10-15 11:07:09 +01003117 state->slot_usage[BOOT_CURR_IMG(state)].img_dst);
Mark Horvathccaf7f82021-01-04 18:16:42 +01003118
Raef Colesfe57e7d2021-10-15 11:07:09 +01003119 memset((void*)(IMAGE_RAM_BASE + state->slot_usage[BOOT_CURR_IMG(state)].img_dst),
3120 0, state->slot_usage[BOOT_CURR_IMG(state)].img_sz);
Mark Horvathccaf7f82021-01-04 18:16:42 +01003121
Raef Colesfe57e7d2021-10-15 11:07:09 +01003122 state->slot_usage[BOOT_CURR_IMG(state)].img_dst = 0;
3123 state->slot_usage[BOOT_CURR_IMG(state)].img_sz = 0;
Mark Horvathccaf7f82021-01-04 18:16:42 +01003124
3125 return 0;
3126}
3127
3128/**
3129 * Removes an image from flash by erasing the corresponding flash area
3130 *
3131 * @param state Boot loader status information.
3132 * @param slot The flash slot of the image to be erased.
Tamas Banfe031092020-09-10 17:32:39 +02003133 *
3134 * @return 0 on success; nonzero on failure.
3135 */
3136static inline int
Mark Horvathccaf7f82021-01-04 18:16:42 +01003137boot_remove_image_from_flash(struct boot_loader_state *state, uint32_t slot)
Tamas Banfe031092020-09-10 17:32:39 +02003138{
Mark Horvathccaf7f82021-01-04 18:16:42 +01003139 int area_id;
3140 int rc;
3141 const struct flash_area *fap;
Tamas Banfe031092020-09-10 17:32:39 +02003142
David Brown695e5912021-05-24 16:58:01 -06003143 (void)state;
3144
Mark Horvathccaf7f82021-01-04 18:16:42 +01003145 BOOT_LOG_INF("Removing image %d slot %d from flash", BOOT_CURR_IMG(state),
3146 slot);
3147 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
3148 rc = flash_area_open(area_id, &fap);
3149 if (rc == 0) {
Dominik Ermel260ae092021-04-23 05:38:45 +00003150 flash_area_erase(fap, 0, flash_area_get_size(fap));
Dominik Ermel245de812022-09-02 13:39:23 +00003151 flash_area_close(fap);
Mark Horvathccaf7f82021-01-04 18:16:42 +01003152 }
3153
3154 return rc;
Tamas Banfe031092020-09-10 17:32:39 +02003155}
3156#endif /* MCUBOOT_RAM_LOAD */
3157
Mark Horvathccaf7f82021-01-04 18:16:42 +01003158
3159/**
3160 * Tries to load a slot for all the images with validation.
3161 *
3162 * @param state Boot loader status information.
Mark Horvathccaf7f82021-01-04 18:16:42 +01003163 *
3164 * @return 0 on success; nonzero on failure.
3165 */
Michael Grand5047f032022-11-24 16:49:56 +01003166fih_ret
Raef Colesfe57e7d2021-10-15 11:07:09 +01003167boot_load_and_validate_images(struct boot_loader_state *state)
Mark Horvathccaf7f82021-01-04 18:16:42 +01003168{
3169 uint32_t active_slot;
3170 int rc;
Michael Grand5047f032022-11-24 16:49:56 +01003171 fih_ret fih_rc;
Mark Horvathccaf7f82021-01-04 18:16:42 +01003172
3173 /* Go over all the images and try to load one */
3174 IMAGES_ITER(BOOT_CURR_IMG(state)) {
3175 /* All slots tried until a valid image found. Breaking from this loop
3176 * means that a valid image found or already loaded. If no slot is
3177 * found the function returns with error code. */
3178 while (true) {
Mark Horvathccaf7f82021-01-04 18:16:42 +01003179 /* Go over all the slots and try to load one */
Raef Colesfe57e7d2021-10-15 11:07:09 +01003180 active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot;
Mark Horvathccaf7f82021-01-04 18:16:42 +01003181 if (active_slot != NO_ACTIVE_SLOT){
3182 /* A slot is already active, go to next image. */
3183 break;
David Vinczee574f2d2020-07-10 11:42:03 +02003184 }
David Vincze505fba22020-10-22 13:53:29 +02003185
Raef Colesfe57e7d2021-10-15 11:07:09 +01003186 active_slot = find_slot_with_highest_version(state);
Mark Horvathccaf7f82021-01-04 18:16:42 +01003187 if (active_slot == NO_ACTIVE_SLOT) {
3188 BOOT_LOG_INF("No slot to load for image %d",
3189 BOOT_CURR_IMG(state));
3190 FIH_RET(FIH_FAILURE);
3191 }
3192
3193 /* Save the number of the active slot. */
Raef Colesfe57e7d2021-10-15 11:07:09 +01003194 state->slot_usage[BOOT_CURR_IMG(state)].active_slot = active_slot;
Mark Horvathccaf7f82021-01-04 18:16:42 +01003195
Raef Colesf11de642021-10-15 11:11:56 +01003196#if BOOT_IMAGE_NUMBER > 1
3197 if (state->img_mask[BOOT_CURR_IMG(state)]) {
3198 continue;
3199 }
3200#endif
3201
Mark Horvathccaf7f82021-01-04 18:16:42 +01003202#ifdef MCUBOOT_DIRECT_XIP
Raef Colesfe57e7d2021-10-15 11:07:09 +01003203 rc = boot_rom_address_check(state);
Mark Horvathccaf7f82021-01-04 18:16:42 +01003204 if (rc != 0) {
3205 /* The image is placed in an unsuitable slot. */
Raef Colesfe57e7d2021-10-15 11:07:09 +01003206 state->slot_usage[BOOT_CURR_IMG(state)].slot_available[active_slot] = false;
3207 state->slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT;
Mark Horvathccaf7f82021-01-04 18:16:42 +01003208 continue;
3209 }
George Becksteind4d90f82021-05-11 02:00:00 -04003210
David Vincze505fba22020-10-22 13:53:29 +02003211#ifdef MCUBOOT_DIRECT_XIP_REVERT
Raef Colesfe57e7d2021-10-15 11:07:09 +01003212 rc = boot_select_or_erase(state);
David Vincze505fba22020-10-22 13:53:29 +02003213 if (rc != 0) {
3214 /* The selected image slot has been erased. */
Raef Colesfe57e7d2021-10-15 11:07:09 +01003215 state->slot_usage[BOOT_CURR_IMG(state)].slot_available[active_slot] = false;
3216 state->slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT;
David Vincze505fba22020-10-22 13:53:29 +02003217 continue;
3218 }
3219#endif /* MCUBOOT_DIRECT_XIP_REVERT */
David Vincze1c456242021-06-29 15:25:24 +02003220#endif /* MCUBOOT_DIRECT_XIP */
David Vincze505fba22020-10-22 13:53:29 +02003221
Tamas Banfe031092020-09-10 17:32:39 +02003222#ifdef MCUBOOT_RAM_LOAD
3223 /* Image is first loaded to RAM and authenticated there in order to
3224 * prevent TOCTOU attack during image copy. This could be applied
3225 * when loading images from external (untrusted) flash to internal
3226 * (trusted) RAM and image is authenticated before copying.
3227 */
Raef Colesfe57e7d2021-10-15 11:07:09 +01003228 rc = boot_load_image_to_sram(state);
Tamas Banfe031092020-09-10 17:32:39 +02003229 if (rc != 0 ) {
Mark Horvathccaf7f82021-01-04 18:16:42 +01003230 /* Image cannot be ramloaded. */
3231 boot_remove_image_from_flash(state, active_slot);
Raef Colesfe57e7d2021-10-15 11:07:09 +01003232 state->slot_usage[BOOT_CURR_IMG(state)].slot_available[active_slot] = false;
3233 state->slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT;
Tamas Banfe031092020-09-10 17:32:39 +02003234 continue;
Tamas Banfe031092020-09-10 17:32:39 +02003235 }
3236#endif /* MCUBOOT_RAM_LOAD */
Mark Horvathccaf7f82021-01-04 18:16:42 +01003237
3238 FIH_CALL(boot_validate_slot, fih_rc, state, active_slot, NULL);
Michael Grand5047f032022-11-24 16:49:56 +01003239 if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
Mark Horvathccaf7f82021-01-04 18:16:42 +01003240 /* Image is invalid. */
Tamas Banfe031092020-09-10 17:32:39 +02003241#ifdef MCUBOOT_RAM_LOAD
Raef Colesfe57e7d2021-10-15 11:07:09 +01003242 boot_remove_image_from_sram(state);
Tamas Banfe031092020-09-10 17:32:39 +02003243#endif /* MCUBOOT_RAM_LOAD */
Raef Colesfe57e7d2021-10-15 11:07:09 +01003244 state->slot_usage[BOOT_CURR_IMG(state)].slot_available[active_slot] = false;
3245 state->slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT;
Mark Horvathccaf7f82021-01-04 18:16:42 +01003246 continue;
David Vincze505fba22020-10-22 13:53:29 +02003247 }
Mark Horvathccaf7f82021-01-04 18:16:42 +01003248
3249 /* Valid image loaded from a slot, go to next image. */
3250 break;
3251 }
3252 }
3253
3254 FIH_RET(FIH_SUCCESS);
3255}
3256
3257/**
3258 * Updates the security counter for the current image.
3259 *
3260 * @param state Boot loader status information.
Mark Horvathccaf7f82021-01-04 18:16:42 +01003261 *
3262 * @return 0 on success; nonzero on failure.
3263 */
3264static int
Raef Colesfe57e7d2021-10-15 11:07:09 +01003265boot_update_hw_rollback_protection(struct boot_loader_state *state)
Mark Horvathccaf7f82021-01-04 18:16:42 +01003266{
3267#ifdef MCUBOOT_HW_ROLLBACK_PROT
3268 int rc;
3269
3270 /* Update the stored security counter with the newer (active) image's
3271 * security counter value.
3272 */
David Vincze1c456242021-06-29 15:25:24 +02003273#if defined(MCUBOOT_DIRECT_XIP) && defined(MCUBOOT_DIRECT_XIP_REVERT)
Mark Horvathccaf7f82021-01-04 18:16:42 +01003274 /* When the 'revert' mechanism is enabled in direct-xip mode, the
3275 * security counter can be increased only after reboot, if the image
3276 * has been confirmed at runtime (the image_ok flag has been set).
3277 * This way a 'revert' can be performed when it's necessary.
3278 */
Raef Colesfe57e7d2021-10-15 11:07:09 +01003279 if (state->slot_usage[BOOT_CURR_IMG(state)].swap_state.image_ok == BOOT_FLAG_SET) {
David Vincze505fba22020-10-22 13:53:29 +02003280#endif
Sherry Zhang50b06ae2021-07-09 15:22:51 +08003281 rc = boot_update_security_counter(BOOT_CURR_IMG(state),
Raef Colesfe57e7d2021-10-15 11:07:09 +01003282 state->slot_usage[BOOT_CURR_IMG(state)].active_slot,
3283 boot_img_hdr(state, state->slot_usage[BOOT_CURR_IMG(state)].active_slot));
David Vinczee574f2d2020-07-10 11:42:03 +02003284 if (rc != 0) {
Antonio de Angelisba5fb1c2022-10-11 10:10:37 +01003285 BOOT_LOG_ERR("Security counter update failed after image %d validation.", BOOT_CURR_IMG(state));
Mark Horvathccaf7f82021-01-04 18:16:42 +01003286 return rc;
David Vinczee574f2d2020-07-10 11:42:03 +02003287 }
David Vincze1c456242021-06-29 15:25:24 +02003288#if defined(MCUBOOT_DIRECT_XIP) && defined(MCUBOOT_DIRECT_XIP_REVERT)
Mark Horvathccaf7f82021-01-04 18:16:42 +01003289 }
3290#endif
David Vinczee574f2d2020-07-10 11:42:03 +02003291
Mark Horvathccaf7f82021-01-04 18:16:42 +01003292 return 0;
David Vinczee574f2d2020-07-10 11:42:03 +02003293
Mark Horvathccaf7f82021-01-04 18:16:42 +01003294#else /* MCUBOOT_HW_ROLLBACK_PROT */
3295 (void) (state);
Mark Horvathccaf7f82021-01-04 18:16:42 +01003296 return 0;
3297#endif
3298}
3299
Michael Grand5047f032022-11-24 16:49:56 +01003300fih_ret
Mark Horvathccaf7f82021-01-04 18:16:42 +01003301context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp)
3302{
Mark Horvathccaf7f82021-01-04 18:16:42 +01003303 int rc;
Michael Grand5047f032022-11-24 16:49:56 +01003304 FIH_DECLARE(fih_rc, FIH_FAILURE);
Mark Horvathccaf7f82021-01-04 18:16:42 +01003305
Raef Colesfe57e7d2021-10-15 11:07:09 +01003306 rc = boot_get_slot_usage(state);
Mark Horvathccaf7f82021-01-04 18:16:42 +01003307 if (rc != 0) {
David Vinczee574f2d2020-07-10 11:42:03 +02003308 goto out;
3309 }
3310
Mark Horvathccaf7f82021-01-04 18:16:42 +01003311#if (BOOT_IMAGE_NUMBER > 1)
3312 while (true) {
3313#endif
Raef Colesfe57e7d2021-10-15 11:07:09 +01003314 FIH_CALL(boot_load_and_validate_images, fih_rc, state);
Michael Grand5047f032022-11-24 16:49:56 +01003315 if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
3316 FIH_SET(fih_rc, FIH_FAILURE);
Mark Horvathccaf7f82021-01-04 18:16:42 +01003317 goto out;
3318 }
3319
3320#if (BOOT_IMAGE_NUMBER > 1)
Raef Colesfe57e7d2021-10-15 11:07:09 +01003321 rc = boot_verify_dependencies(state);
Mark Horvathccaf7f82021-01-04 18:16:42 +01003322 if (rc != 0) {
3323 /* Dependency check failed for an image, it has been removed from
3324 * SRAM in case of MCUBOOT_RAM_LOAD strategy, and set to
3325 * unavailable. Try to load an image from another slot.
3326 */
3327 continue;
3328 }
3329 /* Dependency check was successful. */
3330 break;
3331 }
3332#endif
3333
3334 IMAGES_ITER(BOOT_CURR_IMG(state)) {
Raef Colesf11de642021-10-15 11:11:56 +01003335#if BOOT_IMAGE_NUMBER > 1
3336 if (state->img_mask[BOOT_CURR_IMG(state)]) {
3337 continue;
3338 }
3339#endif
Raef Colesfe57e7d2021-10-15 11:07:09 +01003340 rc = boot_update_hw_rollback_protection(state);
Mark Horvathccaf7f82021-01-04 18:16:42 +01003341 if (rc != 0) {
Michael Grand5047f032022-11-24 16:49:56 +01003342 FIH_SET(fih_rc, FIH_FAILURE);
Mark Horvathccaf7f82021-01-04 18:16:42 +01003343 goto out;
3344 }
3345
Jamie McCrae3016d002023-03-14 12:35:51 +00003346 rc = boot_add_shared_data(state, (uint8_t)state->slot_usage[BOOT_CURR_IMG(state)].active_slot);
Mark Horvathccaf7f82021-01-04 18:16:42 +01003347 if (rc != 0) {
Michael Grand5047f032022-11-24 16:49:56 +01003348 FIH_SET(fih_rc, FIH_FAILURE);
Mark Horvathccaf7f82021-01-04 18:16:42 +01003349 goto out;
3350 }
3351 }
3352
3353 /* All image loaded successfully. */
3354#ifdef MCUBOOT_HAVE_LOGGING
Raef Colesfe57e7d2021-10-15 11:07:09 +01003355 print_loaded_images(state);
Mark Horvathccaf7f82021-01-04 18:16:42 +01003356#endif
3357
Raef Colesfe57e7d2021-10-15 11:07:09 +01003358 fill_rsp(state, rsp);
Mark Horvathccaf7f82021-01-04 18:16:42 +01003359
David Vinczee574f2d2020-07-10 11:42:03 +02003360out:
Mark Horvathccaf7f82021-01-04 18:16:42 +01003361 close_all_flash_areas(state);
Raef Colese8fe6cf2020-05-26 13:07:40 +01003362
Michael Grand5047f032022-11-24 16:49:56 +01003363 if (rc != 0) {
3364 FIH_SET(fih_rc, FIH_FAILURE);
Mark Horvathccaf7f82021-01-04 18:16:42 +01003365 }
Raef Colese8fe6cf2020-05-26 13:07:40 +01003366
Mark Horvathccaf7f82021-01-04 18:16:42 +01003367 FIH_RET(fih_rc);
David Vinczee574f2d2020-07-10 11:42:03 +02003368}
Tamas Banfe031092020-09-10 17:32:39 +02003369#endif /* MCUBOOT_DIRECT_XIP || MCUBOOT_RAM_LOAD */
David Vinczee574f2d2020-07-10 11:42:03 +02003370
3371/**
Raef Colese8fe6cf2020-05-26 13:07:40 +01003372 * Prepares the booting process. This function moves images around in flash as
David Vinczee574f2d2020-07-10 11:42:03 +02003373 * appropriate, and tells you what address to boot from.
3374 *
3375 * @param rsp On success, indicates how booting should occur.
3376 *
Raef Colese8fe6cf2020-05-26 13:07:40 +01003377 * @return FIH_SUCCESS on success; nonzero on failure.
David Vinczee574f2d2020-07-10 11:42:03 +02003378 */
Michael Grand5047f032022-11-24 16:49:56 +01003379fih_ret
David Vinczee574f2d2020-07-10 11:42:03 +02003380boot_go(struct boot_rsp *rsp)
3381{
Michael Grand5047f032022-11-24 16:49:56 +01003382 FIH_DECLARE(fih_rc, FIH_FAILURE);
Raef Colesf11de642021-10-15 11:11:56 +01003383
3384 boot_state_clear(NULL);
3385
Raef Colese8fe6cf2020-05-26 13:07:40 +01003386 FIH_CALL(context_boot_go, fih_rc, &boot_data, rsp);
3387 FIH_RET(fih_rc);
David Vinczee574f2d2020-07-10 11:42:03 +02003388}
Raef Colesf11de642021-10-15 11:11:56 +01003389
3390/**
3391 * Prepares the booting process, considering only a single image. This function
3392 * moves images around in flash as appropriate, and tells you what address to
3393 * boot from.
3394 *
3395 * @param rsp On success, indicates how booting should occur.
3396 *
3397 * @param image_id The image ID to prepare the boot process for.
3398 *
3399 * @return FIH_SUCCESS on success; nonzero on failure.
3400 */
Michael Grand5047f032022-11-24 16:49:56 +01003401fih_ret
Raef Colesf11de642021-10-15 11:11:56 +01003402boot_go_for_image_id(struct boot_rsp *rsp, uint32_t image_id)
3403{
Michael Grand5047f032022-11-24 16:49:56 +01003404 FIH_DECLARE(fih_rc, FIH_FAILURE);
Raef Colesf11de642021-10-15 11:11:56 +01003405
3406 if (image_id >= BOOT_IMAGE_NUMBER) {
3407 FIH_RET(FIH_FAILURE);
3408 }
3409
3410#if BOOT_IMAGE_NUMBER > 1
3411 memset(&boot_data.img_mask, 1, BOOT_IMAGE_NUMBER);
3412 boot_data.img_mask[image_id] = 0;
3413#endif
3414
3415 FIH_CALL(context_boot_go, fih_rc, &boot_data, rsp);
3416 FIH_RET(fih_rc);
3417}
3418
3419/**
3420 * Clears the boot state, so that previous operations have no effect on new
3421 * ones.
3422 *
3423 * @param state The state that should be cleared. If the value
3424 * is NULL, the default bootloader state will be
3425 * cleared.
3426 */
3427void boot_state_clear(struct boot_loader_state *state)
3428{
3429 if (state != NULL) {
3430 memset(state, 0, sizeof(struct boot_loader_state));
3431 } else {
3432 memset(&boot_data, 0, sizeof(struct boot_loader_state));
3433 }
3434}
Jamie McCrae4f1ab9e2024-07-26 12:29:24 +01003435
Jamie McCraee261b282024-07-26 11:48:19 +01003436#if defined(MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO)
Jamie McCrae4f1ab9e2024-07-26 12:29:24 +01003437/**
Jamie McCraee261b282024-07-26 11:48:19 +01003438 * Reads image data to find out the maximum application sizes. Only needs to
3439 * be called in serial recovery mode, as the state informatio is unpopulated
3440 * at that time
3441 */
3442static void boot_fetch_slot_state_sizes(void)
3443{
3444 struct sector_buffer_t sector_buffers;
3445 size_t slot;
3446 int rc = -1;
3447 int fa_id;
3448 int image_index;
3449
3450 boot_get_sector_buffers(&sector_buffers);
3451
3452 IMAGES_ITER(BOOT_CURR_IMG(&boot_data)) {
3453 int max_size = 0;
3454
3455 image_index = BOOT_CURR_IMG(&boot_data);
3456
3457 BOOT_IMG(&boot_data, BOOT_PRIMARY_SLOT).sectors =
3458 &sector_buffers.primary[image_index];
3459 BOOT_IMG(&boot_data, BOOT_SECONDARY_SLOT).sectors =
3460 &sector_buffers.secondary[image_index];
3461#if MCUBOOT_SWAP_USING_SCRATCH
3462 boot_data.scratch.sectors = sector_buffers.scratch;;
3463#endif
3464
3465 /* Open primary and secondary image areas for the duration
3466 * of this call.
3467 */
3468 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
3469 fa_id = flash_area_id_from_multi_image_slot(image_index, slot);
3470 rc = flash_area_open(fa_id, &BOOT_IMG_AREA(&boot_data, slot));
3471 assert(rc == 0);
3472
3473 if (rc != 0) {
3474 goto finish;
3475 }
3476 }
3477
3478#if MCUBOOT_SWAP_USING_SCRATCH
3479 rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH,
3480 &BOOT_SCRATCH_AREA(&boot_data));
3481 assert(rc == 0);
3482
3483 if (rc != 0) {
3484 goto finish;
3485 }
3486#endif
3487
3488 /* Determine the sector layout of the image slots and scratch area. */
3489 rc = boot_read_sectors(&boot_data);
3490
3491 if (rc == 0) {
3492 max_size = app_max_size(&boot_data);
3493
3494 if (max_size > 0) {
3495 image_max_sizes[image_index].calculated = true;
3496 image_max_sizes[image_index].max_size = max_size;
3497 }
3498 }
3499 }
3500
3501finish:
3502 close_all_flash_areas(&boot_data);
3503 memset(&boot_data, 0x00, sizeof(boot_data));
3504}
3505#endif
3506
3507#if defined(MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO) || defined(MCUBOOT_DATA_SHARING)
3508/**
3509 * Fetches the maximum allowed size of the image
3510 */
Jamie McCrae4f1ab9e2024-07-26 12:29:24 +01003511const struct image_max_size *boot_get_max_app_size(void)
3512{
Jamie McCraee261b282024-07-26 11:48:19 +01003513#if defined(MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO)
3514 uint8_t i = 0;
3515
3516 while (i < BOOT_IMAGE_NUMBER) {
3517 if (image_max_sizes[i].calculated == true) {
3518 break;
3519 }
3520
3521 ++i;
3522 }
3523
3524 if (i == BOOT_IMAGE_NUMBER) {
3525 /* Information not available, need to fetch it */
3526 boot_fetch_slot_state_sizes();
3527 }
3528#endif
3529
Jamie McCrae4f1ab9e2024-07-26 12:29:24 +01003530 return image_max_sizes;
3531}
3532#endif