blob: e441b56999f3f26c639fdd1dcbb2a1eb1fd2a9ca [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
Roman Okhrimenko977b3752022-03-31 14:40:48 +03006 * Copyright (c) 2019-2021 Arm Limited
INFINEON\DovhalA21babb72025-07-18 10:36:03 +03007 * Copyright (c) 2021-2025 Cypress Semiconductor Corporation (an Infineon company)
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"
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +030040#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"
Roman Okhrimenko977b3752022-03-31 14:40:48 +030048#include "bootutil/ramload.h"
49#include "bootutil/boot_hooks.h"
Marti Bolivarfd20c762017-02-07 16:52:50 -050050
Fabio Utzigba829042018-09-18 08:29:34 -030051#ifdef MCUBOOT_ENC_IMAGES
52#include "bootutil/enc_key.h"
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +020053#ifdef MCUBOOT_ENC_IMAGES_XIP_MULTI
54#include "xip_encryption.h"
55#endif /* MCUBOOT_ENC_IMAGES_XIP_MULTI */
56#endif /* MCUBOOT_ENC_IMAGES */
Fabio Utzigba829042018-09-18 08:29:34 -030057
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +030058#if (!defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)) || defined(MCUBOOT_MULTI_MEMORY_LOAD)
Roman Okhrimenko977b3752022-03-31 14:40:48 +030059#include <os/os_malloc.h>
60#endif
61
Fabio Utzigba1fbe62017-07-21 14:01:20 -030062#include "mcuboot_config/mcuboot_config.h"
Fabio Utzigeed80b62017-06-10 08:03:05 -030063
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +020064#ifdef USE_IFX_SE_CRYPTO
65#include "ifx_se_utils.h"
66#endif /* USE_IFX_SE_CRYPTO */
67
Roman Okhrimenko977b3752022-03-31 14:40:48 +030068BOOT_LOG_MODULE_DECLARE(mcuboot);
Emanuele Di Santo9f1933d2018-11-20 10:59:59 +010069
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +020070bool boot_ram = false;
Marti Bolivar9b1f8bb2017-06-12 15:24:13 -040071static struct boot_loader_state boot_data;
Christopher Collins92ea77f2016-12-12 15:59:26 -080072
Fabio Utzigabec0732019-07-31 08:40:22 -030073#if (BOOT_IMAGE_NUMBER > 1)
74#define IMAGES_ITER(x) for ((x) = 0; (x) < BOOT_IMAGE_NUMBER; ++(x))
75#else
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +030076#define IMAGES_ITER(x) for (int iter = 0; iter < 1; ++iter)
Fabio Utzigabec0732019-07-31 08:40:22 -030077#endif
78
Fabio Utzig10ee6482019-08-01 12:04:52 -030079/*
80 * This macro allows some control on the allocation of local variables.
81 * When running natively on a target, we don't want to allocated huge
82 * variables on the stack, so make them global instead. For the simulator
83 * we want to run as many threads as there are tests, and it's safer
84 * to just make those variables stack allocated.
85 */
86#if !defined(__BOOTSIM__)
87#define TARGET_STATIC static
88#else
89#define TARGET_STATIC
90#endif
91
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +030092#if BOOT_MAX_ALIGN > 1024
93#define BUF_SZ BOOT_MAX_ALIGN
94#else
95#define BUF_SZ 1024U
96#endif
97
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +020098static fih_int FIH_SWAP_TYPE_NONE = FIH_INT_INIT_GLOBAL(0x3A5C742E);
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +030099
David Vinczee574f2d2020-07-10 11:42:03 +0200100static int
101boot_read_image_headers(struct boot_loader_state *state, bool require_all,
102 struct boot_status *bs)
103{
104 int rc;
105 int i;
106
107 for (i = 0; i < BOOT_NUM_SLOTS; i++) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300108 rc = BOOT_HOOK_CALL(boot_read_image_header_hook, BOOT_HOOK_REGULAR,
109 BOOT_CURR_IMG(state), i, boot_img_hdr(state, i));
110 if (rc == BOOT_HOOK_REGULAR)
111 {
112 rc = boot_read_image_header(state, i, boot_img_hdr(state, i), bs);
113 }
David Vinczee574f2d2020-07-10 11:42:03 +0200114 if (rc != 0) {
115 /* If `require_all` is set, fail on any single fail, otherwise
116 * if at least the first slot's header was read successfully,
117 * then the boot loader can attempt a boot.
118 *
119 * Failure to read any headers is a fatal error.
120 */
121 if (i > 0 && !require_all) {
122 return 0;
123 } else {
124 return rc;
125 }
126 }
127 }
128
129 return 0;
130}
131
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300132/**
133 * Saves boot status and shared data for current image.
134 *
135 * @param state Boot loader status information.
136 * @param active_slot Index of the slot will be loaded for current image.
137 *
138 * @return 0 on success; nonzero on failure.
139 */
140static int
141boot_add_shared_data(struct boot_loader_state *state,
142 uint32_t active_slot)
143{
144#if defined(MCUBOOT_MEASURED_BOOT) || defined(MCUBOOT_DATA_SHARING)
145 int rc;
146
147#ifdef MCUBOOT_MEASURED_BOOT
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +0200148 rc = boot_save_boot_status(GET_SW_MODULE_ID(BOOT_CURR_IMG(state)),
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300149 boot_img_hdr(state, active_slot),
150 BOOT_IMG_AREA(state, active_slot));
151 if (rc != 0) {
152 BOOT_LOG_ERR("Failed to add image data to shared area");
153 return rc;
154 }
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +0200155 else {
156 BOOT_LOG_INF("Successfully added image data to shared area");
157 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300158#endif /* MCUBOOT_MEASURED_BOOT */
159
160#ifdef MCUBOOT_DATA_SHARING
161 rc = boot_save_shared_data(boot_img_hdr(state, active_slot),
162 BOOT_IMG_AREA(state, active_slot));
163 if (rc != 0) {
164 BOOT_LOG_ERR("Failed to add data to shared memory area.");
165 return rc;
166 }
167#endif /* MCUBOOT_DATA_SHARING */
168
169 return 0;
170
171#else /* MCUBOOT_MEASURED_BOOT || MCUBOOT_DATA_SHARING */
172 (void) (state);
173 (void) (active_slot);
174
175 return 0;
176#endif
177}
178
179/**
180 * Fills rsp to indicate how booting should occur.
181 *
182 * @param state Boot loader status information.
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300183 * @param rsp boot_rsp struct to fill.
184 */
185static void
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300186fill_rsp(struct boot_loader_state *state, struct boot_rsp *rsp)
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300187{
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300188 uint32_t active_slot = BOOT_PRIMARY_SLOT;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300189
190#if (BOOT_IMAGE_NUMBER > 1)
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300191 /* Always boot from the first enabled image. */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300192 BOOT_CURR_IMG(state) = 0;
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300193 IMAGES_ITER(BOOT_CURR_IMG(state)) {
194 if (!state->img_mask[BOOT_CURR_IMG(state)]) {
195 break;
196 }
197 }
198 /* At least one image must be active, otherwise skip the execution */
199 if(BOOT_CURR_IMG(state) >= BOOT_IMAGE_NUMBER)
200 {
201 return;
202 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300203#endif
204
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300205#if defined(MCUBOOT_MULTI_MEMORY_LOAD)
206 if ((state->slot_usage[BOOT_CURR_IMG(state)].active_slot != BOOT_PRIMARY_SLOT) &&
207 (state->slot_usage[BOOT_CURR_IMG(state)].active_slot != NO_ACTIVE_SLOT))
208#endif
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300209#if defined(MCUBOOT_DIRECT_XIP) || defined(MCUBOOT_RAM_LOAD)
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300210 {
211 active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot;
212 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300213#endif
214
215 rsp->br_flash_dev_id = flash_area_get_device_id(BOOT_IMG_AREA(state, active_slot));
216 rsp->br_image_off = boot_img_slot_off(state, active_slot);
217 rsp->br_hdr = boot_img_hdr(state, active_slot);
218}
219
220/**
221 * Closes all flash areas.
222 *
223 * @param state Boot loader status information.
224 */
225static void
226close_all_flash_areas(struct boot_loader_state *state)
227{
228 uint32_t slot;
229
230 IMAGES_ITER(BOOT_CURR_IMG(state)) {
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300231#if BOOT_IMAGE_NUMBER > 1
232 if (state->img_mask[BOOT_CURR_IMG(state)]) {
233 continue;
234 }
235#endif
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300236#if MCUBOOT_SWAP_USING_SCRATCH
237 flash_area_close(BOOT_SCRATCH_AREA(state));
238#endif
239 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
240 flash_area_close(BOOT_IMG_AREA(state, BOOT_NUM_SLOTS - 1 - slot));
241 }
242 }
243}
244
David Brownf5b33d82017-09-01 10:58:27 -0600245/*
246 * Compute the total size of the given image. Includes the size of
247 * the TLVs.
248 */
INFINEON\DovhalA21babb72025-07-18 10:36:03 +0300249#if defined(MCUBOOT_DIRECT_XIP) || !defined(MCUBOOT_OVERWRITE_ONLY) || defined(MCUBOOT_OVERWRITE_ONLY_FAST) || defined(MCUBOOT_RAM_LOAD)
David Brownf5b33d82017-09-01 10:58:27 -0600250static int
Fabio Utzigd638b172019-08-09 10:38:05 -0300251boot_read_image_size(struct boot_loader_state *state, int slot, uint32_t *size)
David Brownf5b33d82017-09-01 10:58:27 -0600252{
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300253 const struct flash_area *fap = NULL;
Fabio Utzig61fd8882019-09-14 20:00:20 -0300254 struct image_tlv_info info;
Fabio Utzig233af7d2019-08-26 12:06:16 -0300255 uint32_t off;
Fabio Utzige52c08e2019-09-11 19:32:00 -0300256 uint32_t protect_tlv_size;
David Brownf5b33d82017-09-01 10:58:27 -0600257 int area_id;
258 int rc;
259
Fabio Utzig10ee6482019-08-01 12:04:52 -0300260#if (BOOT_IMAGE_NUMBER == 1)
261 (void)state;
262#endif
263
264 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
David Brownf5b33d82017-09-01 10:58:27 -0600265 rc = flash_area_open(area_id, &fap);
266 if (rc != 0) {
267 rc = BOOT_EFLASH;
268 goto done;
269 }
270
Fabio Utzig61fd8882019-09-14 20:00:20 -0300271 off = BOOT_TLV_OFF(boot_img_hdr(state, slot));
272
273 if (flash_area_read(fap, off, &info, sizeof(info))) {
274 rc = BOOT_EFLASH;
David Brownf5b33d82017-09-01 10:58:27 -0600275 goto done;
276 }
Fabio Utzig61fd8882019-09-14 20:00:20 -0300277
Fabio Utzige52c08e2019-09-11 19:32:00 -0300278 protect_tlv_size = boot_img_hdr(state, slot)->ih_protect_tlv_size;
279 if (info.it_magic == IMAGE_TLV_PROT_INFO_MAGIC) {
280 if (protect_tlv_size != info.it_tlv_tot) {
281 rc = BOOT_EBADIMAGE;
282 goto done;
283 }
284
285 if (flash_area_read(fap, off + info.it_tlv_tot, &info, sizeof(info))) {
286 rc = BOOT_EFLASH;
287 goto done;
288 }
289 } else if (protect_tlv_size != 0) {
290 rc = BOOT_EBADIMAGE;
291 goto done;
292 }
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300293 else
294 {
295 /* acc. to MISRA R.15.7 */
296 }
Fabio Utzige52c08e2019-09-11 19:32:00 -0300297
Fabio Utzig61fd8882019-09-14 20:00:20 -0300298 if (info.it_magic != IMAGE_TLV_INFO_MAGIC) {
299 rc = BOOT_EBADIMAGE;
300 goto done;
301 }
302
Fabio Utzige52c08e2019-09-11 19:32:00 -0300303 *size = off + protect_tlv_size + info.it_tlv_tot;
David Brownf5b33d82017-09-01 10:58:27 -0600304 rc = 0;
305
306done:
307 flash_area_close(fap);
Fabio Utzig2eebf112017-09-04 15:25:08 -0300308 return rc;
David Brownf5b33d82017-09-01 10:58:27 -0600309}
310
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300311#endif
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200312
David Brownab449182019-11-15 09:32:52 -0700313static uint32_t
Fabio Utzig10ee6482019-08-01 12:04:52 -0300314boot_write_sz(struct boot_loader_state *state)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800315{
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300316 size_t elem_sz;
Fabio Utzig12d59162019-11-28 10:01:59 -0300317#if MCUBOOT_SWAP_USING_SCRATCH
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300318 size_t align;
Fabio Utzig12d59162019-11-28 10:01:59 -0300319#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800320
321 /* Figure out what size to write update status update as. The size depends
322 * on what the minimum write size is for scratch area, active image slot.
323 * We need to use the bigger of those 2 values.
324 */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300325
Fabio Utzig10ee6482019-08-01 12:04:52 -0300326 elem_sz = flash_area_align(BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT));
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300327 assert(elem_sz != 0u);
328
Fabio Utzig12d59162019-11-28 10:01:59 -0300329#if MCUBOOT_SWAP_USING_SCRATCH
Fabio Utzig10ee6482019-08-01 12:04:52 -0300330 align = flash_area_align(BOOT_SCRATCH_AREA(state));
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300331 assert(align != 0u);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800332 if (align > elem_sz) {
333 elem_sz = align;
334 }
Fabio Utzig12d59162019-11-28 10:01:59 -0300335#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800336
337 return elem_sz;
338}
339
Fabio Utzig10ee6482019-08-01 12:04:52 -0300340static int
341boot_initialize_area(struct boot_loader_state *state, int flash_area)
342{
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300343 uint32_t num_sectors = BOOT_MAX_IMG_SECTORS;
344 boot_sector_t *out_sectors;
Fabio Utzig10ee6482019-08-01 12:04:52 -0300345 size_t *out_num_sectors;
346 int rc;
347
348 num_sectors = BOOT_MAX_IMG_SECTORS;
349
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300350 if (flash_area == (int) FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state))) {
Fabio Utzig10ee6482019-08-01 12:04:52 -0300351 out_sectors = BOOT_IMG(state, BOOT_PRIMARY_SLOT).sectors;
352 out_num_sectors = &BOOT_IMG(state, BOOT_PRIMARY_SLOT).num_sectors;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300353 } else if (flash_area == (int) FLASH_AREA_IMAGE_SECONDARY(BOOT_CURR_IMG(state))) {
Fabio Utzig10ee6482019-08-01 12:04:52 -0300354 out_sectors = BOOT_IMG(state, BOOT_SECONDARY_SLOT).sectors;
355 out_num_sectors = &BOOT_IMG(state, BOOT_SECONDARY_SLOT).num_sectors;
Fabio Utzig12d59162019-11-28 10:01:59 -0300356#if MCUBOOT_SWAP_USING_SCRATCH
Fabio Utzig10ee6482019-08-01 12:04:52 -0300357 } else if (flash_area == FLASH_AREA_IMAGE_SCRATCH) {
358 out_sectors = state->scratch.sectors;
359 out_num_sectors = &state->scratch.num_sectors;
Fabio Utzig12d59162019-11-28 10:01:59 -0300360#endif
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200361#if MCUBOOT_SWAP_USING_STATUS
362 } else if (flash_area == FLASH_AREA_IMAGE_SWAP_STATUS) {
363 out_sectors = state->status.sectors;
364 out_num_sectors = &state->status.num_sectors;
365#endif
Fabio Utzig10ee6482019-08-01 12:04:52 -0300366 } else {
367 return BOOT_EFLASH;
368 }
369
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300370#ifdef MCUBOOT_USE_FLASH_AREA_GET_SECTORS
Fabio Utzig10ee6482019-08-01 12:04:52 -0300371 rc = flash_area_get_sectors(flash_area, &num_sectors, out_sectors);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300372#else
373 _Static_assert(sizeof(int) <= sizeof(uint32_t), "Fix needed");
374 rc = flash_area_to_sectors(flash_area, (int *)&num_sectors, out_sectors);
375#endif /* defined(MCUBOOT_USE_FLASH_AREA_GET_SECTORS) */
Fabio Utzig10ee6482019-08-01 12:04:52 -0300376 if (rc != 0) {
377 return rc;
378 }
379 *out_num_sectors = num_sectors;
380 return 0;
381}
Fabio Utzig10ee6482019-08-01 12:04:52 -0300382
Christopher Collins92ea77f2016-12-12 15:59:26 -0800383/**
384 * Determines the sector layout of both image slots and the scratch area.
385 * This information is necessary for calculating the number of bytes to erase
386 * and copy during an image swap. The information collected during this
Fabio Utzig10ee6482019-08-01 12:04:52 -0300387 * function is used to populate the state.
Christopher Collins92ea77f2016-12-12 15:59:26 -0800388 */
389static int
Fabio Utzig10ee6482019-08-01 12:04:52 -0300390boot_read_sectors(struct boot_loader_state *state)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800391{
Fabio Utzigb0f04732019-07-31 09:49:19 -0300392 uint8_t image_index;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800393 int rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800394
Fabio Utzig10ee6482019-08-01 12:04:52 -0300395 image_index = BOOT_CURR_IMG(state);
Fabio Utzigb0f04732019-07-31 09:49:19 -0300396
397 rc = boot_initialize_area(state, FLASH_AREA_IMAGE_PRIMARY(image_index));
Christopher Collins92ea77f2016-12-12 15:59:26 -0800398 if (rc != 0) {
399 return BOOT_EFLASH;
400 }
401
Fabio Utzig10ee6482019-08-01 12:04:52 -0300402 rc = boot_initialize_area(state, FLASH_AREA_IMAGE_SECONDARY(image_index));
Christopher Collins92ea77f2016-12-12 15:59:26 -0800403 if (rc != 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300404 /* We need to differentiate from the primary image issue */
405 return BOOT_EFLASH_SEC;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800406 }
407
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200408#if MCUBOOT_SWAP_USING_STATUS
409 rc = boot_initialize_area(state, FLASH_AREA_IMAGE_SWAP_STATUS);
410 if (rc != 0) {
411 return BOOT_EFLASH;
412 }
413#endif
414
Fabio Utzig12d59162019-11-28 10:01:59 -0300415#if MCUBOOT_SWAP_USING_SCRATCH
Fabio Utzig10ee6482019-08-01 12:04:52 -0300416 rc = boot_initialize_area(state, FLASH_AREA_IMAGE_SCRATCH);
Fabio Utzig2bd980a2018-11-26 10:38:17 -0200417 if (rc != 0) {
418 return BOOT_EFLASH;
419 }
Fabio Utzig12d59162019-11-28 10:01:59 -0300420#endif
Fabio Utzig2bd980a2018-11-26 10:38:17 -0200421
Fabio Utzig10ee6482019-08-01 12:04:52 -0300422 BOOT_WRITE_SZ(state) = boot_write_sz(state);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800423
424 return 0;
425}
426
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +0200427static void
Fabio Utzig12d59162019-11-28 10:01:59 -0300428boot_status_reset(struct boot_status *bs)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800429{
Fabio Utzig4741c452019-12-19 15:32:41 -0300430#ifdef MCUBOOT_ENC_IMAGES
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300431 (void)memset(&bs->enckey, BOOT_UNINITIALIZED_KEY_FILL,
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300432 BOOT_NUM_SLOTS * BOOT_ENC_KEY_ALIGN_SIZE);
433#ifdef MCUBOOT_SWAP_SAVE_ENCTLV
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300434 (void)memset(&bs->enctlv, BOOT_UNINITIALIZED_TLV_FILL,
435 BOOT_NUM_SLOTS * BOOT_ENC_TLV_ALIGN_SIZE);
Fabio Utzig4741c452019-12-19 15:32:41 -0300436#endif
437#endif /* MCUBOOT_ENC_IMAGES */
438
439 bs->use_scratch = 0;
440 bs->swap_size = 0;
441 bs->source = 0;
442
Fabio Utzig74aef312019-11-28 11:05:34 -0300443 bs->op = BOOT_STATUS_OP_MOVE;
Fabio Utzig39000012018-07-30 12:40:20 -0300444 bs->idx = BOOT_STATUS_IDX_0;
445 bs->state = BOOT_STATUS_STATE_0;
Christopher Collinsa1c12042019-05-23 14:00:28 -0700446 bs->swap_type = BOOT_SWAP_TYPE_NONE;
Fabio Utzig12d59162019-11-28 10:01:59 -0300447}
Christopher Collins92ea77f2016-12-12 15:59:26 -0800448
Fabio Utzig12d59162019-11-28 10:01:59 -0300449bool
450boot_status_is_reset(const struct boot_status *bs)
451{
Fabio Utzig74aef312019-11-28 11:05:34 -0300452 return (bs->op == BOOT_STATUS_OP_MOVE &&
453 bs->idx == BOOT_STATUS_IDX_0 &&
454 bs->state == BOOT_STATUS_STATE_0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800455}
456
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200457#ifndef MCUBOOT_SWAP_USING_STATUS
Christopher Collins92ea77f2016-12-12 15:59:26 -0800458/**
459 * Writes the supplied boot status to the flash file system. The boot status
460 * contains the current state of an in-progress image copy operation.
461 *
462 * @param bs The boot status to write.
463 *
464 * @return 0 on success; nonzero on failure.
465 */
466int
Fabio Utzig12d59162019-11-28 10:01:59 -0300467boot_write_status(const struct boot_loader_state *state, struct boot_status *bs)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800468{
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300469 const struct flash_area *fap = NULL;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800470 uint32_t off;
471 int area_id;
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300472 int rc = 0;
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300473 uint8_t buf[BOOT_MAX_ALIGN];
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300474 uint32_t align;
Fabio Utzig39000012018-07-30 12:40:20 -0300475 uint8_t erased_val;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800476
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300477 /* NOTE: The first sector copied (that is the last sector on slot) contains
David Vincze2d736ad2019-02-18 11:50:22 +0100478 * the trailer. Since in the last step the primary slot is erased, the
479 * first two status writes go to the scratch which will be copied to
480 * the primary slot!
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300481 */
482
Fabio Utzig12d59162019-11-28 10:01:59 -0300483#if MCUBOOT_SWAP_USING_SCRATCH
Fabio Utzig2473ac02017-05-02 12:45:02 -0300484 if (bs->use_scratch) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800485 /* Write to scratch. */
486 area_id = FLASH_AREA_IMAGE_SCRATCH;
487 } else {
Fabio Utzig12d59162019-11-28 10:01:59 -0300488#endif
David Vincze2d736ad2019-02-18 11:50:22 +0100489 /* Write to the primary slot. */
Fabio Utzig10ee6482019-08-01 12:04:52 -0300490 area_id = FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state));
Fabio Utzig12d59162019-11-28 10:01:59 -0300491#if MCUBOOT_SWAP_USING_SCRATCH
Christopher Collins92ea77f2016-12-12 15:59:26 -0800492 }
Fabio Utzig12d59162019-11-28 10:01:59 -0300493#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800494
495 rc = flash_area_open(area_id, &fap);
496 if (rc != 0) {
497 rc = BOOT_EFLASH;
498 goto done;
499 }
500
501 off = boot_status_off(fap) +
Fabio Utzig12d59162019-11-28 10:01:59 -0300502 boot_status_internal_off(bs, BOOT_WRITE_SZ(state));
Andrzej Puzdrowskib788c712018-04-12 12:42:49 +0200503 align = flash_area_align(fap);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300504 if (align == 0u) {
505 rc = BOOT_EFLASH;
506 goto done;
507 }
508
Fabio Utzig39000012018-07-30 12:40:20 -0300509 erased_val = flash_area_erased_val(fap);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300510 (void)memset(buf, erased_val, BOOT_MAX_ALIGN);
David Brown9d725462017-01-23 15:50:58 -0700511 buf[0] = bs->state;
512
513 rc = flash_area_write(fap, off, buf, align);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800514 if (rc != 0) {
515 rc = BOOT_EFLASH;
516 goto done;
517 }
518
519 rc = 0;
520
521done:
522 flash_area_close(fap);
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300523
Christopher Collins92ea77f2016-12-12 15:59:26 -0800524 return rc;
525}
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200526#endif /* MCUBOOT_SWAP_USING_STATUS */
527
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300528
INFINEON\DovhalA21babb72025-07-18 10:36:03 +0300529
Christopher Collins92ea77f2016-12-12 15:59:26 -0800530
531/*
David Vinczec3084132020-02-18 14:50:47 +0100532 * Validate image hash/signature and optionally the security counter in a slot.
Christopher Collins92ea77f2016-12-12 15:59:26 -0800533 */
Raef Colese8fe6cf2020-05-26 13:07:40 +0100534static fih_int
Fabio Utzig10ee6482019-08-01 12:04:52 -0300535boot_image_check(struct boot_loader_state *state, struct image_header *hdr,
536 const struct flash_area *fap, struct boot_status *bs)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800537{
Fabio Utzig10ee6482019-08-01 12:04:52 -0300538 TARGET_STATIC uint8_t tmpbuf[BOOT_TMPBUF_SZ];
Fabio Utzigb0f04732019-07-31 09:49:19 -0300539 uint8_t image_index;
Raef Colese8fe6cf2020-05-26 13:07:40 +0100540 fih_int fih_rc = FIH_FAILURE;
Fabio Utzigba829042018-09-18 08:29:34 -0300541
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +0200542#ifdef USE_IFX_SE_CRYPTO
543 fih_uint fih_complex_result = FIH_UINT_ZERO;
544 extern fih_uint IFX_FIH_IMG_VALIDATE_COMPLEX_OK;
545#else
546 fih_int fih_complex_result = FIH_FAILURE;
547 extern fih_int FIH_IMG_VALIDATE_COMPLEX_OK;
548#endif /* USE_IFX_SE_CRYPTO */
549
Fabio Utzig10ee6482019-08-01 12:04:52 -0300550#if (BOOT_IMAGE_NUMBER == 1)
551 (void)state;
552#endif
553
Fabio Utzigba829042018-09-18 08:29:34 -0300554 (void)bs;
Fabio Utzigbc077932019-08-26 11:16:34 -0300555
556 image_index = BOOT_CURR_IMG(state);
557
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300558/* In the case of ram loading the image has already been decrypted as it is
559 * decrypted when copied in ram */
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300560#if defined(MCUBOOT_ENC_IMAGES)
INFINEON\DovhalA21babb72025-07-18 10:36:03 +0300561#if defined(MCUBOOT_ENC_IMAGES_XIP_MULTI)
562 if (MUST_DECRYPT(fap, image_index, hdr)) {
563#else
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300564 if (MUST_DECRYPT(fap, image_index, hdr) && !IS_RAM_BOOTABLE(hdr)) {
INFINEON\DovhalA21babb72025-07-18 10:36:03 +0300565#endif /* MCUBOOT_ENC_IMAGES_XIP_MULTI */
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300566 int rc = flash_area_id_to_multi_image_slot(image_index, fap->fa_id);
Fabio Utzigba829042018-09-18 08:29:34 -0300567 if (rc < 0) {
Raef Colese8fe6cf2020-05-26 13:07:40 +0100568 FIH_RET(fih_rc);
Fabio Utzigba829042018-09-18 08:29:34 -0300569 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300570 else {
571 uint8_t slot = (uint8_t)rc;
572
573 rc = boot_enc_load(BOOT_CURR_ENC(state), image_index, hdr, fap, bs);
574 if (rc < 0) {
575 FIH_RET(fih_rc);
576 }
577 if (0 == rc && boot_enc_set_key(BOOT_CURR_ENC(state), slot, bs)) {
578 FIH_RET(fih_rc);
579 }
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +0200580#ifdef MCUBOOT_ENC_IMAGES_XIP_MULTI
581 ifx_epb_set_xip_crypto_params((uint32_t *)bs->enckey[slot],
582 (uint32_t *)BOOT_CURR_ENC(state)[slot].aes_iv);
583#endif /* MCUBOOT_ENC_IMAGES_XIP_MULTI */
Fabio Utzigba829042018-09-18 08:29:34 -0300584 }
585 }
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +0200586#endif /* MCUBOOT_ENC_IMAGES */
Fabio Utzigbc077932019-08-26 11:16:34 -0300587
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +0200588#ifdef USE_IFX_SE_CRYPTO
589 FIH_UCALL(bootutil_psa_img_validate, fih_complex_result, \
590 BOOT_CURR_ENC(state), image_index, hdr, fap, \
591 tmpbuf, BOOT_TMPBUF_SZ, NULL, 0);
592
593 BOOT_LOG_DBG(" * bootutil_psa_img_validate expected = 0x%x, " \
594 "returned = 0x%x", \
595 fih_uint_decode(IFX_FIH_IMG_VALIDATE_COMPLEX_OK), \
596 fih_uint_decode(fih_complex_result));
597
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +0200598 if (fih_uint_eq(fih_complex_result, IFX_FIH_IMG_VALIDATE_COMPLEX_OK)) {
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +0200599 fih_rc = fih_int_encode_zero_equality(
600 fih_uint_decode(IFX_FIH_IMG_VALIDATE_COMPLEX_OK) &
601 ~fih_uint_decode(fih_complex_result));
602 }
603 else {
604 fih_rc = FIH_FAILURE;
605 }
606#else
607 FIH_CALL(bootutil_img_validate, fih_complex_result, BOOT_CURR_ENC(state), image_index,
Raef Colese8fe6cf2020-05-26 13:07:40 +0100608 hdr, fap, tmpbuf, BOOT_TMPBUF_SZ, NULL, 0, NULL);
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +0200609 BOOT_LOG_DBG(" * bootutil_img_validate expected = 0x%x, " \
610 "returned = 0x%x", \
611 fih_int_decode(FIH_IMG_VALIDATE_COMPLEX_OK), \
612 fih_int_decode(fih_complex_result));
613
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +0200614 if (fih_eq(fih_complex_result, FIH_IMG_VALIDATE_COMPLEX_OK)) {
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +0200615 fih_rc = fih_int_encode_zero_equality(
616 fih_int_decode(FIH_IMG_VALIDATE_COMPLEX_OK) &
617 ~fih_int_decode(fih_complex_result));
618 }
619 else {
620 fih_rc = FIH_FAILURE;
621 }
622
623#endif /* USE_IFX_SE_CRYPTO */
Fabio Utzig10ee6482019-08-01 12:04:52 -0300624
Raef Colese8fe6cf2020-05-26 13:07:40 +0100625 FIH_RET(fih_rc);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800626}
627
Raef Colese8fe6cf2020-05-26 13:07:40 +0100628static fih_int
Christopher Collins92ea77f2016-12-12 15:59:26 -0800629split_image_check(struct image_header *app_hdr,
630 const struct flash_area *app_fap,
631 struct image_header *loader_hdr,
632 const struct flash_area *loader_fap)
633{
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +0200634 fih_int fih_rc = FIH_FAILURE;
635#if !defined USE_IFX_SE_CRYPTO
Christopher Collins92ea77f2016-12-12 15:59:26 -0800636 static void *tmpbuf;
637 uint8_t loader_hash[32];
638
639 if (!tmpbuf) {
640 tmpbuf = malloc(BOOT_TMPBUF_SZ);
641 if (!tmpbuf) {
Raef Colese8fe6cf2020-05-26 13:07:40 +0100642 goto out;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800643 }
644 }
645
Raef Colese8fe6cf2020-05-26 13:07:40 +0100646 FIH_CALL(bootutil_img_validate, fih_rc, NULL, 0, loader_hdr, loader_fap,
647 tmpbuf, BOOT_TMPBUF_SZ, NULL, 0, loader_hash);
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +0200648 if (!fih_eq(fih_rc, FIH_SUCCESS)) {
Raef Colese8fe6cf2020-05-26 13:07:40 +0100649 FIH_RET(fih_rc);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800650 }
651
Raef Colese8fe6cf2020-05-26 13:07:40 +0100652 FIH_CALL(bootutil_img_validate, fih_rc, NULL, 0, app_hdr, app_fap,
653 tmpbuf, BOOT_TMPBUF_SZ, loader_hash, 32, NULL);
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +0200654#else
655 /* Not implemented for USE_IFX_SE_CRYPTO
656 The code below is just to avoid warnings
657 */
658 (void)app_hdr;
659 (void)app_fap;
660 (void)loader_hdr;
661 (void)loader_fap;
662 goto out;
663#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800664
Raef Colese8fe6cf2020-05-26 13:07:40 +0100665out:
666 FIH_RET(fih_rc);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800667}
668
Fabio Utzig338a19f2018-12-03 08:37:08 -0200669/*
David Brown9bf95af2019-10-10 15:36:36 -0600670 * Check that this is a valid header. Valid means that the magic is
671 * correct, and that the sizes/offsets are "sane". Sane means that
672 * there is no overflow on the arithmetic, and that the result fits
673 * within the flash area we are in.
674 */
675static bool
676boot_is_header_valid(const struct image_header *hdr, const struct flash_area *fap)
677{
678 uint32_t size;
679
680 if (hdr->ih_magic != IMAGE_MAGIC) {
681 return false;
682 }
683
684 if (!boot_u32_safe_add(&size, hdr->ih_img_size, hdr->ih_hdr_size)) {
685 return false;
686 }
687
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300688 if (size >= flash_area_get_size(fap)) {
David Brown9bf95af2019-10-10 15:36:36 -0600689 return false;
690 }
691
692 return true;
693}
694
695/*
Fabio Utzig338a19f2018-12-03 08:37:08 -0200696 * Check that a memory area consists of a given value.
697 */
698static inline bool
699boot_data_is_set_to(uint8_t val, void *data, size_t len)
Fabio Utzig39000012018-07-30 12:40:20 -0300700{
701 uint8_t i;
Fabio Utzig338a19f2018-12-03 08:37:08 -0200702 uint8_t *p = (uint8_t *)data;
703 for (i = 0; i < len; i++) {
704 if (val != p[i]) {
705 return false;
Fabio Utzig39000012018-07-30 12:40:20 -0300706 }
707 }
Fabio Utzig338a19f2018-12-03 08:37:08 -0200708 return true;
709}
710
711static int
Fabio Utzig10ee6482019-08-01 12:04:52 -0300712boot_check_header_erased(struct boot_loader_state *state, int slot)
Fabio Utzig338a19f2018-12-03 08:37:08 -0200713{
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300714 const struct flash_area *fap = NULL;
Fabio Utzig338a19f2018-12-03 08:37:08 -0200715 struct image_header *hdr;
716 uint8_t erased_val;
Fabio Utzigb0f04732019-07-31 09:49:19 -0300717 int area_id;
Fabio Utzig338a19f2018-12-03 08:37:08 -0200718 int rc;
719
Fabio Utzig10ee6482019-08-01 12:04:52 -0300720 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
Fabio Utzigb0f04732019-07-31 09:49:19 -0300721 rc = flash_area_open(area_id, &fap);
Fabio Utzig338a19f2018-12-03 08:37:08 -0200722 if (rc != 0) {
723 return -1;
724 }
725
726 erased_val = flash_area_erased_val(fap);
727 flash_area_close(fap);
728
Fabio Utzig10ee6482019-08-01 12:04:52 -0300729 hdr = boot_img_hdr(state, slot);
Fabio Utzig338a19f2018-12-03 08:37:08 -0200730 if (!boot_data_is_set_to(erased_val, &hdr->ih_magic, sizeof(hdr->ih_magic))) {
731 return -1;
732 }
733
734 return 0;
Fabio Utzig39000012018-07-30 12:40:20 -0300735}
736
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +0200737#if (BOOT_IMAGE_NUMBER > 1 && defined(MCUBOOT_DEPENDENCY_CHECK)) || \
David Vinczee574f2d2020-07-10 11:42:03 +0200738 defined(MCUBOOT_DIRECT_XIP) || \
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +0000739 (defined(MCUBOOT_OVERWRITE_ONLY) && defined(MCUBOOT_DOWNGRADE_PREVENTION))
740/**
David Vincze8b0b6372020-05-20 19:54:44 +0200741 * Compare image version numbers not including the build number
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +0000742 *
David Vincze8b0b6372020-05-20 19:54:44 +0200743 * @param ver1 Pointer to the first image version to compare.
744 * @param ver2 Pointer to the second image version to compare.
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +0000745 *
David Vincze8b0b6372020-05-20 19:54:44 +0200746 * @retval -1 If ver1 is strictly less than ver2.
747 * @retval 0 If the image version numbers are equal,
748 * (not including the build number).
749 * @retval 1 If ver1 is strictly greater than ver2.
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +0000750 */
751static int
David Vincze8b0b6372020-05-20 19:54:44 +0200752boot_version_cmp(const struct image_version *ver1,
753 const struct image_version *ver2)
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +0000754{
David Vincze8b0b6372020-05-20 19:54:44 +0200755 if (ver1->iv_major > ver2->iv_major) {
756 return 1;
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +0000757 }
David Vincze8b0b6372020-05-20 19:54:44 +0200758 if (ver1->iv_major < ver2->iv_major) {
759 return -1;
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +0000760 }
David Vincze8b0b6372020-05-20 19:54:44 +0200761 /* The major version numbers are equal, continue comparison. */
762 if (ver1->iv_minor > ver2->iv_minor) {
763 return 1;
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +0000764 }
David Vincze8b0b6372020-05-20 19:54:44 +0200765 if (ver1->iv_minor < ver2->iv_minor) {
766 return -1;
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +0000767 }
David Vincze8b0b6372020-05-20 19:54:44 +0200768 /* The minor version numbers are equal, continue comparison. */
769 if (ver1->iv_revision > ver2->iv_revision) {
770 return 1;
771 }
772 if (ver1->iv_revision < ver2->iv_revision) {
773 return -1;
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +0000774 }
775
776 return 0;
777}
778#endif
779
Dominik Ermel0c8c8d52021-02-17 14:45:02 +0000780#if defined(MCUBOOT_DIRECT_XIP)
781/**
782 * Check if image in slot has been set with specific ROM address to run from
783 * and whether the slot starts at that address.
784 *
785 * @returns 0 if IMAGE_F_ROM_FIXED flag is not set;
786 * 0 if IMAGE_F_ROM_FIXED flag is set and ROM address specified in
787 * header matches the slot address;
788 * 1 if IMF_F_ROM_FIXED flag is set but ROM address specified in header
789 * does not match the slot address.
790 */
791static bool
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300792boot_rom_address_check(struct boot_loader_state *state)
Dominik Ermel0c8c8d52021-02-17 14:45:02 +0000793{
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300794 uint32_t active_slot;
795 const struct image_header *hdr;
796 uint32_t f_off;
797
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300798 active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300799 hdr = boot_img_hdr(state, active_slot);
800 f_off = boot_img_slot_off(state, active_slot);
801
Dominik Ermel0c8c8d52021-02-17 14:45:02 +0000802 if (hdr->ih_flags & IMAGE_F_ROM_FIXED && hdr->ih_load_addr != f_off) {
INFINEON\DovhalA21babb72025-07-18 10:36:03 +0300803 BOOT_LOG_DBG("Image in %s slot at 0x%" PRIx32
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300804 " has been built for offset 0x%" PRIx32 ", skipping",
805 active_slot == 0 ? "primary" : "secondary", f_off,
Dominik Ermel0c8c8d52021-02-17 14:45:02 +0000806 hdr->ih_load_addr);
807
808 /* If there is address mismatch, the image is not bootable from this
809 * slot.
810 */
811 return 1;
812 }
813 return 0;
814}
815#endif
816
Fabio Utzigb1adb1e2019-09-11 11:42:53 -0300817/*
818 * Check that there is a valid image in a slot
819 *
820 * @returns
Raef Colese8fe6cf2020-05-26 13:07:40 +0100821 * FIH_SUCCESS if image was successfully validated
822 * 1 (or its fih_int encoded form) if no bootloable image was found
823 * FIH_FAILURE on any errors
Fabio Utzigb1adb1e2019-09-11 11:42:53 -0300824 */
Raef Colese8fe6cf2020-05-26 13:07:40 +0100825static fih_int
Fabio Utzig10ee6482019-08-01 12:04:52 -0300826boot_validate_slot(struct boot_loader_state *state, int slot,
827 struct boot_status *bs)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800828{
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300829 const struct flash_area *fap = NULL;
Marti Bolivarf804f622017-06-12 15:41:48 -0400830 struct image_header *hdr;
Fabio Utzigb0f04732019-07-31 09:49:19 -0300831 int area_id;
Raef Colese8fe6cf2020-05-26 13:07:40 +0100832 fih_int fih_rc = FIH_FAILURE;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800833 int rc;
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300834
Fabio Utzig10ee6482019-08-01 12:04:52 -0300835 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
Fabio Utzigb0f04732019-07-31 09:49:19 -0300836 rc = flash_area_open(area_id, &fap);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800837 if (rc != 0) {
Raef Colese8fe6cf2020-05-26 13:07:40 +0100838 FIH_RET(fih_rc);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800839 }
840
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300841 BOOT_LOG_DBG("> boot_validate_slot: fa_id = %u", (unsigned)fap->fa_id);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200842
Fabio Utzig10ee6482019-08-01 12:04:52 -0300843 hdr = boot_img_hdr(state, slot);
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300844
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +0200845#ifdef MCUBOOT_ENC_IMAGES_XIP_MULTI
INFINEON\DovhalA21babb72025-07-18 10:36:03 +0300846/* In the XIP encryption multi image case if XIP encryption is turned on then
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +0200847 * the boot_check_header_erased() can't detect erased header correctly for the second and next images
848 * because erased value is not read as 0xFF.
849 * So, the bootloader has one option only to detect correctness of image header: it is
850 * to check header magic */
851 if (hdr->ih_magic != IMAGE_MAGIC) {
852 FIH_RET(fih_rc);
853 }
854#endif /* MCUBOOT_ENC_IMAGES_XIP_MULTI */
855
Fabio Utzig10ee6482019-08-01 12:04:52 -0300856 if (boot_check_header_erased(state, slot) == 0 ||
857 (hdr->ih_flags & IMAGE_F_NON_BOOTABLE)) {
Fabio Utzig260ec452020-07-09 18:40:07 -0300858
859#if defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SWAP_USING_MOVE)
860 /*
861 * This fixes an issue where an image might be erased, but a trailer
862 * be left behind. It can happen if the image is in the secondary slot
863 * and did not pass validation, in which case the whole slot is erased.
864 * If during the erase operation, a reset occurs, parts of the slot
865 * might have been erased while some did not. The concerning part is
866 * the trailer because it might disable a new image from being loaded
867 * through mcumgr; so we just get rid of the trailer here, if the header
868 * is erased.
869 */
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200870 BOOT_LOG_DBG(" * Fix the secondary slot when image is invalid.");
Fabio Utzig260ec452020-07-09 18:40:07 -0300871 if (slot != BOOT_PRIMARY_SLOT) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200872 BOOT_LOG_DBG(" * Erase secondary image trailer.");
Fabio Utzig260ec452020-07-09 18:40:07 -0300873 swap_erase_trailer_sectors(state, fap);
874 }
875#endif
876
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200877 BOOT_LOG_DBG(" * No bootable image in slot(%d); continue booting from the primary slot.", slot);
David Vincze2d736ad2019-02-18 11:50:22 +0100878 /* No bootable image in slot; continue booting from the primary slot. */
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300879 fih_rc = FIH_SWAP_TYPE_NONE;
Fabio Utzig338a19f2018-12-03 08:37:08 -0200880 goto out;
Fabio Utzig39000012018-07-30 12:40:20 -0300881 }
882
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +0000883#if defined(MCUBOOT_OVERWRITE_ONLY) && defined(MCUBOOT_DOWNGRADE_PREVENTION)
884 if (slot != BOOT_PRIMARY_SLOT) {
885 /* Check if version of secondary slot is sufficient */
David Vincze8b0b6372020-05-20 19:54:44 +0200886 rc = boot_version_cmp(
887 &boot_img_hdr(state, BOOT_SECONDARY_SLOT)->ih_ver,
888 &boot_img_hdr(state, BOOT_PRIMARY_SLOT)->ih_ver);
889 if (rc < 0 && boot_check_header_erased(state, BOOT_PRIMARY_SLOT)) {
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +0000890 BOOT_LOG_ERR("insufficient version in secondary slot");
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300891 flash_area_erase(fap, 0, flash_area_get_size(fap));
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +0000892 /* Image in the secondary slot does not satisfy version requirement.
893 * Erase the image and continue booting from the primary slot.
894 */
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300895 fih_rc = FIH_SWAP_TYPE_NONE;
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +0000896 goto out;
897 }
898 }
899#endif
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +0200900 BOOT_HOOK_CALL_FIH(boot_image_check_hook, FIH_INT_INIT(BOOT_HOOK_REGULAR),
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300901 fih_rc, BOOT_CURR_IMG(state), slot);
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +0200902 if (fih_eq(fih_rc, FIH_INT_INIT(BOOT_HOOK_REGULAR)))
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300903 {
904 FIH_CALL(boot_image_check, fih_rc, state, hdr, fap, bs);
905 }
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +0200906 if (!boot_is_header_valid(hdr, fap) || !fih_eq(fih_rc, FIH_SUCCESS)) {
Tamas Banfe031092020-09-10 17:32:39 +0200907 if ((slot != BOOT_PRIMARY_SLOT) || ARE_SLOTS_EQUIVALENT()) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200908 BOOT_LOG_DBG(" * Image in the secondary slot is invalid. Erase the image");
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300909 flash_area_erase(fap, 0, flash_area_get_size(fap));
David Vinczee574f2d2020-07-10 11:42:03 +0200910 /* Image is invalid, erase it to prevent further unnecessary
911 * attempts to validate and boot it.
David Brownb38e0442017-02-24 13:57:12 -0700912 */
913 }
David Brown098de832019-12-10 11:58:01 -0700914#if !defined(__BOOTSIM__)
David Vincze2d736ad2019-02-18 11:50:22 +0100915 BOOT_LOG_ERR("Image in the %s slot is not valid!",
916 (slot == BOOT_PRIMARY_SLOT) ? "primary" : "secondary");
David Brown098de832019-12-10 11:58:01 -0700917#endif
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300918 fih_rc = FIH_SWAP_TYPE_NONE;
Fabio Utzig338a19f2018-12-03 08:37:08 -0200919 goto out;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800920 }
921
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300922#if MCUBOOT_IMAGE_NUMBER > 1 && !defined(MCUBOOT_ENC_IMAGES) && defined(MCUBOOT_VERIFY_IMG_ADDRESS)
923 /* Verify that the image in the secondary slot has a reset address
924 * located in the primary slot. This is done to avoid users incorrectly
925 * overwriting an application written to the incorrect slot.
926 * This feature is only supported by ARM platforms.
927 */
928 if (area_id == FLASH_AREA_IMAGE_SECONDARY(BOOT_CURR_IMG(state))) {
929 const struct flash_area *pri_fa = BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT);
930 struct image_header *secondary_hdr = boot_img_hdr(state, slot);
931 uint32_t reset_value = 0;
932 uint32_t reset_addr = secondary_hdr->ih_hdr_size + sizeof(reset_value);
933
934 rc = flash_area_read(fap, reset_addr, &reset_value, sizeof(reset_value));
935 if (rc != 0) {
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +0200936 fih_rc = FIH_INT_INIT(1);
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300937 goto out;
938 }
939
940 if (reset_value < pri_fa->fa_off || reset_value> (pri_fa->fa_off + pri_fa->fa_size)) {
941 BOOT_LOG_ERR("Reset address of image in secondary slot is not in the primary slot");
942 BOOT_LOG_ERR("Erasing image from secondary slot");
943
944 /* The vector table in the image located in the secondary
945 * slot does not target the primary slot. This might
946 * indicate that the image was loaded to the wrong slot.
947 *
948 * Erase the image and continue booting from the primary slot.
949 */
950 flash_area_erase(fap, 0, fap->fa_size);
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +0200951 fih_rc = FIH_INT_INIT(1);
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300952 goto out;
953 }
954 }
955#endif
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200956
Fabio Utzig338a19f2018-12-03 08:37:08 -0200957out:
958 flash_area_close(fap);
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300959 BOOT_LOG_DBG("< boot_validate_slot: fa_id = %u", (unsigned)fap->fa_id);
Raef Colese8fe6cf2020-05-26 13:07:40 +0100960 FIH_RET(fih_rc);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800961}
962
INFINEON\DovhalA21babb72025-07-18 10:36:03 +0300963/*
964 * Check that there is a valid image in a slot
965 *
966 * @returns
967 * FIH_SUCCESS if image was successfully validated
968 * 1 (or its fih_int encoded form) if no bootloable image was found
969 * FIH_FAILURE on any errors
970 */
971static fih_int
972boot_soft_validate_slot(struct boot_loader_state *state, int slot,
973 struct boot_status *bs)
974{
975 const struct flash_area *fap = NULL;
976 struct image_header *hdr;
977 int area_id;
978 fih_int fih_rc = FIH_FAILURE;
979 int rc;
980
981 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
982 rc = flash_area_open(area_id, &fap);
983 if (rc != 0) {
984 FIH_RET(fih_rc);
985 }
986
987 BOOT_LOG_DBG("> boot_validate_slot: fa_id = %u", (unsigned)fap->fa_id);
988
989 hdr = boot_img_hdr(state, slot);
990
991 if (hdr->ih_magic != IMAGE_MAGIC) {
992 FIH_RET(fih_rc);
993 }
994
995#if defined(MCUBOOT_OVERWRITE_ONLY) && defined(MCUBOOT_DOWNGRADE_PREVENTION)
996 if (slot != BOOT_PRIMARY_SLOT) {
997 /* Check if version of secondary slot is sufficient */
998 rc = boot_version_cmp(
999 &boot_img_hdr(state, BOOT_SECONDARY_SLOT)->ih_ver,
1000 &boot_img_hdr(state, BOOT_PRIMARY_SLOT)->ih_ver);
1001 if (rc < 0 && boot_check_header_erased(state, BOOT_PRIMARY_SLOT)) {
1002 BOOT_LOG_ERR("insufficient version in secondary slot");
1003 fih_rc = FIH_SWAP_TYPE_NONE;
1004 goto out;
1005 }
1006 }
1007#endif
1008 BOOT_HOOK_CALL_FIH(boot_image_check_hook, FIH_INT_INIT(BOOT_HOOK_REGULAR),
1009 fih_rc, BOOT_CURR_IMG(state), slot);
1010 if (fih_eq(fih_rc, FIH_INT_INIT(BOOT_HOOK_REGULAR)))
1011 {
1012 FIH_CALL(boot_image_check, fih_rc, state, hdr, fap, bs);
1013 }
1014 if (!boot_is_header_valid(hdr, fap) || !fih_eq(fih_rc, FIH_SUCCESS)) {
1015 if ((slot != BOOT_PRIMARY_SLOT) || ARE_SLOTS_EQUIVALENT()) {
1016 BOOT_LOG_DBG(" * Image in the secondary slot is invalid.");
1017 }
1018#if !defined(__BOOTSIM__)
1019 BOOT_LOG_DBG("Image in the %s slot is not valid!",
1020 (slot == BOOT_PRIMARY_SLOT) ? "primary" : "secondary");
1021#endif
1022 fih_rc = FIH_SWAP_TYPE_NONE;
1023 goto out;
1024 }
1025
1026#if MCUBOOT_IMAGE_NUMBER > 1 && !defined(MCUBOOT_ENC_IMAGES) && defined(MCUBOOT_VERIFY_IMG_ADDRESS)
1027 /* Verify that the image in the secondary slot has a reset address
1028 * located in the primary slot. This is done to avoid users incorrectly
1029 * overwriting an application written to the incorrect slot.
1030 * This feature is only supported by ARM platforms.
1031 */
1032 if (area_id == FLASH_AREA_IMAGE_SECONDARY(BOOT_CURR_IMG(state))) {
1033 const struct flash_area *pri_fa = BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT);
1034 struct image_header *secondary_hdr = boot_img_hdr(state, slot);
1035 uint32_t reset_value = 0;
1036 uint32_t reset_addr = secondary_hdr->ih_hdr_size + sizeof(reset_value);
1037
1038 rc = flash_area_read(fap, reset_addr, &reset_value, sizeof(reset_value));
1039 if (rc != 0) {
1040 fih_rc = FIH_INT_INIT(1);
1041 goto out;
1042 }
1043
1044 if (reset_value < pri_fa->fa_off || reset_value> (pri_fa->fa_off + pri_fa->fa_size)) {
1045 BOOT_LOG_ERR("Reset address of image in secondary slot is not in the primary slot");
1046
1047 fih_rc = FIH_INT_INIT(1);
1048 goto out;
1049 }
1050 }
1051#endif
1052
1053out:
1054 flash_area_close(fap);
1055 BOOT_LOG_DBG("< boot_validate_slot: fa_id = %u", (unsigned)fap->fa_id);
1056 FIH_RET(fih_rc);
1057}
1058
David Vinczec3084132020-02-18 14:50:47 +01001059#ifdef MCUBOOT_HW_ROLLBACK_PROT
1060/**
1061 * Updates the stored security counter value with the image's security counter
1062 * value which resides in the given slot, only if it's greater than the stored
1063 * value.
1064 *
1065 * @param image_index Index of the image to determine which security
1066 * counter to update.
1067 * @param slot Slot number of the image.
1068 * @param hdr Pointer to the image header structure of the image
1069 * that is currently stored in the given slot.
1070 *
1071 * @return 0 on success; nonzero on failure.
1072 */
1073static int
1074boot_update_security_counter(uint8_t image_index, int slot,
1075 struct image_header *hdr)
1076{
1077 const struct flash_area *fap = NULL;
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001078 fih_int fih_rc = FIH_FAILURE;
1079 fih_uint img_security_cnt = FIH_UINT_ZERO;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001080 void * custom_data = NULL;
David Vinczec3084132020-02-18 14:50:47 +01001081 int rc;
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001082#if defined CYW20829
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001083 uint8_t buff[REPROV_PACK_SIZE];
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001084#endif /* defined CYW20829 */
David Vinczec3084132020-02-18 14:50:47 +01001085
1086 rc = flash_area_open(flash_area_id_from_multi_image_slot(image_index, slot),
1087 &fap);
1088 if (rc != 0) {
1089 rc = BOOT_EFLASH;
1090 goto done;
1091 }
1092
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001093 rc = -1;
1094 FIH_CALL(bootutil_get_img_security_cnt, fih_rc, hdr, fap, &img_security_cnt);
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02001095 if (!fih_eq(fih_rc, FIH_SUCCESS)) {
David Vinczec3084132020-02-18 14:50:47 +01001096 goto done;
1097 }
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001098 else
1099 {
1100 fih_rc = FIH_FAILURE;
1101 }
David Vinczec3084132020-02-18 14:50:47 +01001102
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001103#if defined CYW20829
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001104 rc = bootutil_get_img_reprov_packet(hdr, fap, buff);
1105 if (rc == 0) {
1106 custom_data = (void *)buff;
David Vinczec3084132020-02-18 14:50:47 +01001107 }
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001108#endif /* defined CYW20829 */
David Vinczec3084132020-02-18 14:50:47 +01001109
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001110 rc = boot_nv_security_counter_update(image_index, img_security_cnt, custom_data);
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +02001111#ifdef USE_IFX_SE_CRYPTO
1112 fih_uint img_security_check = FIH_UINT_ZERO;
1113 FIH_CALL(boot_nv_security_counter_get, fih_rc, image_index, &img_security_check);
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02001114 if (!fih_eq(fih_rc, FIH_SUCCESS)) {
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +02001115 goto done;
1116 }
1117 else
1118 {
1119 fih_rc = FIH_FAILURE;
1120 BOOT_LOG_INF("[SUCCESS] security_counter_get called right after security_counter_update" \
1121 "to check if update is successful upd_cnt = %u, read_cnt = %u",
1122 fih_uint_decode(img_security_check), img_security_cnt);
1123 }
1124#endif /* IFX_SE_RT_CRYPTO */
David Vinczec3084132020-02-18 14:50:47 +01001125done:
1126 flash_area_close(fap);
1127 return rc;
1128}
1129#endif /* MCUBOOT_HW_ROLLBACK_PROT */
1130
David Vinczee574f2d2020-07-10 11:42:03 +02001131/**
1132 * Determines which swap operation to perform, if any. If it is determined
1133 * that a swap operation is required, the image in the secondary slot is checked
1134 * for validity. If the image in the secondary slot is invalid, it is erased,
1135 * and a swap type of "none" is indicated.
1136 *
1137 * @return The type of swap to perform (BOOT_SWAP_TYPE...)
1138 */
1139static int
1140boot_validated_swap_type(struct boot_loader_state *state,
1141 struct boot_status *bs)
1142{
1143 int swap_type;
Raef Colese8fe6cf2020-05-26 13:07:40 +01001144 fih_int fih_rc = FIH_FAILURE;
David Vinczee574f2d2020-07-10 11:42:03 +02001145
1146 swap_type = boot_swap_type_multi(BOOT_CURR_IMG(state));
1147 if (BOOT_IS_UPGRADE(swap_type)) {
1148 /* Boot loader wants to switch to the secondary slot.
1149 * Ensure image is valid.
1150 */
Raef Colese8fe6cf2020-05-26 13:07:40 +01001151 FIH_CALL(boot_validate_slot, fih_rc, state, BOOT_SECONDARY_SLOT, bs);
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02001152 if (!fih_eq(fih_rc, FIH_SUCCESS)) {
1153 if (fih_eq(fih_rc, FIH_SWAP_TYPE_NONE)) {
Raef Colese8fe6cf2020-05-26 13:07:40 +01001154 swap_type = BOOT_SWAP_TYPE_NONE;
1155 } else {
1156 swap_type = BOOT_SWAP_TYPE_FAIL;
1157 }
David Vinczee574f2d2020-07-10 11:42:03 +02001158 }
1159 }
1160
1161 return swap_type;
1162}
1163
Christopher Collins92ea77f2016-12-12 15:59:26 -08001164/**
Christopher Collins92ea77f2016-12-12 15:59:26 -08001165 * Erases a region of flash.
1166 *
Fabio Utzigba829042018-09-18 08:29:34 -03001167 * @param flash_area The flash_area containing the region to erase.
Christopher Collins92ea77f2016-12-12 15:59:26 -08001168 * @param off The offset within the flash area to start the
1169 * erase.
1170 * @param sz The number of bytes to erase.
1171 *
1172 * @return 0 on success; nonzero on failure.
1173 */
Fabio Utzig12d59162019-11-28 10:01:59 -03001174int
Fabio Utzigc28005b2019-09-10 12:18:29 -03001175boot_erase_region(const struct flash_area *fap, uint32_t off, uint32_t sz)
Christopher Collins92ea77f2016-12-12 15:59:26 -08001176{
Fabio Utzigba829042018-09-18 08:29:34 -03001177 return flash_area_erase(fap, off, sz);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001178}
1179
1180/**
1181 * Copies the contents of one flash region to another. You must erase the
1182 * destination region prior to calling this function.
1183 *
1184 * @param flash_area_id_src The ID of the source flash area.
1185 * @param flash_area_id_dst The ID of the destination flash area.
1186 * @param off_src The offset within the source flash area to
1187 * copy from.
1188 * @param off_dst The offset within the destination flash area to
1189 * copy to.
1190 * @param sz The number of bytes to copy.
1191 *
1192 * @return 0 on success; nonzero on failure.
1193 */
Fabio Utzig12d59162019-11-28 10:01:59 -03001194int
Fabio Utzigc28005b2019-09-10 12:18:29 -03001195boot_copy_region(struct boot_loader_state *state,
Fabio Utzig10ee6482019-08-01 12:04:52 -03001196 const struct flash_area *fap_src,
Fabio Utzigba829042018-09-18 08:29:34 -03001197 const struct flash_area *fap_dst,
Christopher Collins92ea77f2016-12-12 15:59:26 -08001198 uint32_t off_src, uint32_t off_dst, uint32_t sz)
1199{
Christopher Collins92ea77f2016-12-12 15:59:26 -08001200 uint32_t bytes_copied;
1201 int chunk_sz;
1202 int rc;
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02001203#if (defined (MCUBOOT_ENC_IMAGES) && !defined(MCUBOOT_ENC_IMAGES_XIP)) || \
1204 (defined (MCUBOOT_ENC_IMAGES) && defined(MCUBOOT_ENC_IMAGES_XIP) && defined(MCUBOOT_ENC_IMAGES_XIP_MULTI))
Fabio Utzigba829042018-09-18 08:29:34 -03001205 uint32_t off;
Fabio Utziga87cc7d2019-08-26 11:21:45 -03001206 uint32_t tlv_off;
Fabio Utzigba829042018-09-18 08:29:34 -03001207 size_t blk_off;
1208 struct image_header *hdr;
1209 uint16_t idx;
1210 uint32_t blk_sz;
Fabio Utzigb0f04732019-07-31 09:49:19 -03001211 uint8_t image_index;
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02001212#endif /* (defined (MCUBOOT_ENC_IMAGES) && !defined(MCUBOOT_ENC_IMAGES_XIP)) || \
1213 (defined (MCUBOOT_ENC_IMAGES) && defined(MCUBOOT_ENC_IMAGES_XIP) && defined(MCUBOOT_ENC_IMAGES_XIP_MULTI)) */
Christopher Collins92ea77f2016-12-12 15:59:26 -08001214
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001215/* NOTE:
1216 * Default value 1024 is not suitable for platforms with larger erase size.
1217 * Give user ability to define platform tolerant chunk size. In most cases
1218 * it would be flash erase alignment.
1219 */
1220#ifdef MCUBOOT_PLATFORM_CHUNK_SIZE
1221 #define MCUBOOT_CHUNK_SIZE MCUBOOT_PLATFORM_CHUNK_SIZE
1222#else
1223 #define MCUBOOT_CHUNK_SIZE 1024
1224#endif
Fabio Utzig10ee6482019-08-01 12:04:52 -03001225
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001226 TARGET_STATIC uint8_t buf[MCUBOOT_CHUNK_SIZE] __attribute__((aligned(4)));
1227
1228#if !defined(MCUBOOT_ENC_IMAGES) || defined(MCUBOOT_ENC_IMAGES_XIP)
Fabio Utzig10ee6482019-08-01 12:04:52 -03001229 (void)state;
1230#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -08001231
Christopher Collins92ea77f2016-12-12 15:59:26 -08001232 bytes_copied = 0;
1233 while (bytes_copied < sz) {
1234 if (sz - bytes_copied > sizeof buf) {
1235 chunk_sz = sizeof buf;
1236 } else {
1237 chunk_sz = sz - bytes_copied;
1238 }
1239
1240 rc = flash_area_read(fap_src, off_src + bytes_copied, buf, chunk_sz);
1241 if (rc != 0) {
Fabio Utzigba829042018-09-18 08:29:34 -03001242 return BOOT_EFLASH;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001243 }
1244
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02001245#if (defined (MCUBOOT_ENC_IMAGES) && !defined(MCUBOOT_ENC_IMAGES_XIP)) || \
1246 (defined (MCUBOOT_ENC_IMAGES) && defined(MCUBOOT_ENC_IMAGES_XIP) && defined(MCUBOOT_ENC_IMAGES_XIP_MULTI))
Fabio Utzig10ee6482019-08-01 12:04:52 -03001247 image_index = BOOT_CURR_IMG(state);
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001248 if ((flash_area_get_id(fap_src) == FLASH_AREA_IMAGE_PRIMARY(image_index) ||
1249 flash_area_get_id(fap_dst) == FLASH_AREA_IMAGE_PRIMARY(image_index)) &&
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +02001250
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001251 !(flash_area_get_id(fap_src) == FLASH_AREA_IMAGE_PRIMARY(image_index) &&
1252 flash_area_get_id(fap_dst) == FLASH_AREA_IMAGE_PRIMARY(image_index)) &&
1253 !(flash_area_get_id(fap_src) == FLASH_AREA_IMAGE_SECONDARY(image_index) &&
1254 flash_area_get_id(fap_dst) == FLASH_AREA_IMAGE_SECONDARY(image_index)))
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +02001255 {
1256 /* assume the primary slot as src, needs encryption */
1257 hdr = boot_img_hdr(state, BOOT_PRIMARY_SLOT);
Fabio Utzig74aef312019-11-28 11:05:34 -03001258#if !defined(MCUBOOT_SWAP_USING_MOVE)
Fabio Utzigba829042018-09-18 08:29:34 -03001259 off = off_src;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001260 if (flash_area_get_id(fap_dst) == FLASH_AREA_IMAGE_PRIMARY(image_index)) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +02001261 /* might need decryption (metadata from the secondary slot) */
1262 hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT);
Fabio Utzigba829042018-09-18 08:29:34 -03001263 off = off_dst;
1264 }
Fabio Utzig74aef312019-11-28 11:05:34 -03001265#else
1266 off = off_dst;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001267 if (flash_area_get_id(fap_dst) == FLASH_AREA_IMAGE_PRIMARY(image_index)) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +02001268 hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT);
Fabio Utzig74aef312019-11-28 11:05:34 -03001269 }
1270#endif
Fabio Utzig2fc80df2018-12-14 06:47:38 -02001271 if (IS_ENCRYPTED(hdr)) {
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001272 uint32_t abs_off = off + bytes_copied;
1273 if (abs_off < hdr->ih_hdr_size) {
Fabio Utzigba829042018-09-18 08:29:34 -03001274 /* do not decrypt header */
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001275 if (abs_off + chunk_sz > hdr->ih_hdr_size) {
1276 /* The lower part of the chunk contains header data */
1277 blk_off = 0;
1278 blk_sz = chunk_sz - (hdr->ih_hdr_size - abs_off);
1279 idx = hdr->ih_hdr_size - abs_off;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +02001280 } else {
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001281 /* The chunk contains exclusively header data */
1282 blk_sz = 0; /* nothing to decrypt */
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +02001283 }
Fabio Utzigba829042018-09-18 08:29:34 -03001284 } else {
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001285 idx = 0;
1286 blk_sz = chunk_sz;
1287 blk_off = (abs_off - hdr->ih_hdr_size) & 0xf;
Fabio Utzigba829042018-09-18 08:29:34 -03001288 }
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001289
1290 if (blk_sz > 0)
1291 {
1292 tlv_off = BOOT_TLV_OFF(hdr);
1293 if (abs_off + chunk_sz > tlv_off) {
1294 /* do not decrypt TLVs */
1295 if (abs_off >= tlv_off) {
1296 blk_sz = 0;
1297 } else {
1298 blk_sz = tlv_off - abs_off;
1299 }
Fabio Utzigba829042018-09-18 08:29:34 -03001300 }
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02001301#ifndef MCUBOOT_ENC_IMAGES_XIP_MULTI
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001302 rc = boot_encrypt(BOOT_CURR_ENC(state), image_index, fap_src,
1303 (abs_off + idx) - hdr->ih_hdr_size, blk_sz,
1304 blk_off, &buf[idx]);
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02001305#else /* MCUBOOT_ENC_IMAGES_XIP_MULTI */
1306 rc = boot_encrypt_xip(fap_src, fap_dst,
1307 (abs_off + idx), blk_sz, &buf[idx]);
1308#endif
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001309 if (rc != 0) {
1310 return rc;
1311 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +02001312 }
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02001313#ifdef MCUBOOT_ENC_IMAGES_XIP_MULTI
1314 rc = flash_area_write(fap_dst, off_dst + bytes_copied, buf, chunk_sz);
1315 }
1316 else {
1317 (void)blk_off;
1318 rc = boot_encrypt_xip(fap_src, fap_dst,
1319 off_dst + bytes_copied,
1320 chunk_sz, buf);
1321
1322 rc = flash_area_write(fap_dst, off_dst + bytes_copied, buf, chunk_sz);
1323 SMIF_SET_CRYPTO_MODE(Enable);
Fabio Utzigba829042018-09-18 08:29:34 -03001324 }
1325 }
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02001326#else
1327 }
1328 }
Christopher Collins92ea77f2016-12-12 15:59:26 -08001329 rc = flash_area_write(fap_dst, off_dst + bytes_copied, buf, chunk_sz);
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02001330#endif /* MCUBOOT_ENC_IMAGES_XIP_MULTI */
1331#else
1332 rc = flash_area_write(fap_dst, off_dst + bytes_copied, buf, chunk_sz);
1333#endif /* (defined (MCUBOOT_ENC_IMAGES) && !defined(MCUBOOT_ENC_IMAGES_XIP)) || \
1334 (defined (MCUBOOT_ENC_IMAGES) && defined(MCUBOOT_ENC_IMAGES_XIP) && defined(MCUBOOT_ENC_IMAGES_XIP_MULTI)) */
1335
Christopher Collins92ea77f2016-12-12 15:59:26 -08001336 if (rc != 0) {
Fabio Utzigba829042018-09-18 08:29:34 -03001337 return BOOT_EFLASH;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001338 }
1339
1340 bytes_copied += chunk_sz;
Fabio Utzig853657c2019-05-07 08:06:07 -03001341
1342 MCUBOOT_WATCHDOG_FEED();
Christopher Collins92ea77f2016-12-12 15:59:26 -08001343 }
1344
Fabio Utzigba829042018-09-18 08:29:34 -03001345 return 0;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001346}
1347
Christopher Collins92ea77f2016-12-12 15:59:26 -08001348/**
David Vincze2d736ad2019-02-18 11:50:22 +01001349 * Overwrite primary slot with the image contained in the secondary slot.
1350 * If a prior copy operation was interrupted by a system reset, this function
1351 * redos the copy.
Christopher Collins92ea77f2016-12-12 15:59:26 -08001352 *
1353 * @param bs The current boot status. This function reads
1354 * this struct to determine if it is resuming
1355 * an interrupted swap operation. This
1356 * function writes the updated status to this
1357 * function on return.
1358 *
1359 * @return 0 on success; nonzero on failure.
1360 */
Fabio Utzig338a19f2018-12-03 08:37:08 -02001361#if defined(MCUBOOT_OVERWRITE_ONLY) || defined(MCUBOOT_BOOTSTRAP)
David Brown17609d82017-05-05 09:41:34 -06001362static int
Fabio Utzig10ee6482019-08-01 12:04:52 -03001363boot_copy_image(struct boot_loader_state *state, struct boot_status *bs)
David Brown17609d82017-05-05 09:41:34 -06001364{
Marti Bolivard3269fd2017-06-12 16:31:12 -04001365 size_t sect_count;
1366 size_t sect;
David Brown17609d82017-05-05 09:41:34 -06001367 int rc;
Fabio Utzig13d9e352017-10-05 20:32:31 -03001368 size_t size;
Marti Bolivard3269fd2017-06-12 16:31:12 -04001369 size_t this_size;
Fabio Utzig13d9e352017-10-05 20:32:31 -03001370 size_t last_sector;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001371 const struct flash_area *fap_primary_slot = NULL;
1372 const struct flash_area *fap_secondary_slot = NULL;
Fabio Utzigb0f04732019-07-31 09:49:19 -03001373 uint8_t image_index;
David Vincze2d736ad2019-02-18 11:50:22 +01001374
Fabio Utzigb4f88102020-10-04 10:16:24 -03001375#if defined(MCUBOOT_OVERWRITE_ONLY_FAST)
1376 uint32_t sector;
1377 uint32_t trailer_sz;
1378 uint32_t off;
1379 uint32_t sz;
1380#endif
1381
Fabio Utzigaaf767c2017-12-05 10:22:46 -02001382 (void)bs;
1383
Fabio Utzig13d9e352017-10-05 20:32:31 -03001384#if defined(MCUBOOT_OVERWRITE_ONLY_FAST)
1385 uint32_t src_size = 0;
Fabio Utzigd638b172019-08-09 10:38:05 -03001386 rc = boot_read_image_size(state, BOOT_SECONDARY_SLOT, &src_size);
Fabio Utzig13d9e352017-10-05 20:32:31 -03001387 assert(rc == 0);
1388#endif
David Brown17609d82017-05-05 09:41:34 -06001389
David Vincze2d736ad2019-02-18 11:50:22 +01001390 BOOT_LOG_INF("Image upgrade secondary slot -> primary slot");
1391 BOOT_LOG_INF("Erasing the primary slot");
David Brown17609d82017-05-05 09:41:34 -06001392
Fabio Utzigb0f04732019-07-31 09:49:19 -03001393 image_index = BOOT_CURR_IMG(state);
1394
1395 rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index),
1396 &fap_primary_slot);
Fabio Utzigba829042018-09-18 08:29:34 -03001397 assert (rc == 0);
1398
Fabio Utzigb0f04732019-07-31 09:49:19 -03001399 rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY(image_index),
1400 &fap_secondary_slot);
Fabio Utzigba829042018-09-18 08:29:34 -03001401 assert (rc == 0);
1402
Fabio Utzig10ee6482019-08-01 12:04:52 -03001403 sect_count = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT);
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001404 BOOT_LOG_DBG(" * primary slot sectors: %lu", (unsigned long)sect_count);
Fabio Utzig13d9e352017-10-05 20:32:31 -03001405 for (sect = 0, size = 0; sect < sect_count; sect++) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001406 this_size = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, sect);
Fabio Utzigc28005b2019-09-10 12:18:29 -03001407 rc = boot_erase_region(fap_primary_slot, size, this_size);
David Brown17609d82017-05-05 09:41:34 -06001408 assert(rc == 0);
1409
Fabio Utzig13d9e352017-10-05 20:32:31 -03001410#if defined(MCUBOOT_OVERWRITE_ONLY_FAST)
Fabio Utzigb4f88102020-10-04 10:16:24 -03001411 if ((size + this_size) >= src_size) {
1412 size += src_size - size;
1413 size += BOOT_WRITE_SZ(state) - (size % BOOT_WRITE_SZ(state));
Fabio Utzig13d9e352017-10-05 20:32:31 -03001414 break;
1415 }
1416#endif
Fabio Utzigb4f88102020-10-04 10:16:24 -03001417
1418 size += this_size;
David Brown17609d82017-05-05 09:41:34 -06001419 }
1420
Fabio Utzigb4f88102020-10-04 10:16:24 -03001421#if defined(MCUBOOT_OVERWRITE_ONLY_FAST)
1422 trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(state));
1423 sector = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT) - 1;
1424 sz = 0;
1425 do {
1426 sz += boot_img_sector_size(state, BOOT_PRIMARY_SLOT, sector);
1427 off = boot_img_sector_off(state, BOOT_PRIMARY_SLOT, sector);
1428 sector--;
1429 } while (sz < trailer_sz);
1430
1431 rc = boot_erase_region(fap_primary_slot, off, sz);
1432 assert(rc == 0);
1433#endif
1434
Fabio Utzigba829042018-09-18 08:29:34 -03001435#ifdef MCUBOOT_ENC_IMAGES
Fabio Utzig10ee6482019-08-01 12:04:52 -03001436 if (IS_ENCRYPTED(boot_img_hdr(state, BOOT_SECONDARY_SLOT))) {
Fabio Utzig1e4284b2019-08-23 11:55:27 -03001437 rc = boot_enc_load(BOOT_CURR_ENC(state), image_index,
Fabio Utzig10ee6482019-08-01 12:04:52 -03001438 boot_img_hdr(state, BOOT_SECONDARY_SLOT),
Fabio Utzig4741c452019-12-19 15:32:41 -03001439 fap_secondary_slot, bs);
David Vincze2d736ad2019-02-18 11:50:22 +01001440
Fabio Utzigba829042018-09-18 08:29:34 -03001441 if (rc < 0) {
1442 return BOOT_EBADIMAGE;
1443 }
Fabio Utzig4741c452019-12-19 15:32:41 -03001444 if (rc == 0 && boot_enc_set_key(BOOT_CURR_ENC(state), 1, bs)) {
Fabio Utzigba829042018-09-18 08:29:34 -03001445 return BOOT_EBADIMAGE;
1446 }
1447 }
1448#endif
1449
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001450 BOOT_LOG_INF("Copying the secondary slot to the primary slot: 0x%lx bytes", (unsigned long)size);
Fabio Utzigc28005b2019-09-10 12:18:29 -03001451 rc = boot_copy_region(state, fap_secondary_slot, fap_primary_slot, 0, 0, size);
Fabio Utzigb4f88102020-10-04 10:16:24 -03001452 if (rc != 0) {
1453 return rc;
1454 }
1455
1456#if defined(MCUBOOT_OVERWRITE_ONLY_FAST)
1457 rc = boot_write_magic(fap_primary_slot);
1458 if (rc != 0) {
1459 return rc;
1460 }
1461#endif
David Brown17609d82017-05-05 09:41:34 -06001462
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001463 rc = BOOT_HOOK_CALL(boot_copy_region_post_hook, 0, BOOT_CURR_IMG(state),
1464 BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT), size);
1465 if (rc != 0) {
1466 return rc;
1467 }
1468
David Vinczec3084132020-02-18 14:50:47 +01001469#ifdef MCUBOOT_HW_ROLLBACK_PROT
1470 /* Update the stored security counter with the new image's security counter
1471 * value. Both slots hold the new image at this point, but the secondary
1472 * slot's image header must be passed since the image headers in the
1473 * boot_data structure have not been updated yet.
1474 */
1475 rc = boot_update_security_counter(BOOT_CURR_IMG(state), BOOT_PRIMARY_SLOT,
1476 boot_img_hdr(state, BOOT_SECONDARY_SLOT));
1477 if (rc != 0) {
1478 BOOT_LOG_ERR("Security counter update failed after image upgrade.");
1479 return rc;
1480 }
1481#endif /* MCUBOOT_HW_ROLLBACK_PROT */
1482
Fabio Utzig13d9e352017-10-05 20:32:31 -03001483 /*
1484 * Erases header and trailer. The trailer is erased because when a new
1485 * image is written without a trailer as is the case when using newt, the
1486 * trailer that was left might trigger a new upgrade.
1487 */
Christopher Collins2c88e692019-05-22 15:10:14 -07001488 BOOT_LOG_DBG("erasing secondary header");
Fabio Utzigc28005b2019-09-10 12:18:29 -03001489 rc = boot_erase_region(fap_secondary_slot,
Fabio Utzig10ee6482019-08-01 12:04:52 -03001490 boot_img_sector_off(state, BOOT_SECONDARY_SLOT, 0),
1491 boot_img_sector_size(state, BOOT_SECONDARY_SLOT, 0));
David Brown17609d82017-05-05 09:41:34 -06001492 assert(rc == 0);
Fabio Utzig10ee6482019-08-01 12:04:52 -03001493 last_sector = boot_img_num_sectors(state, BOOT_SECONDARY_SLOT) - 1;
Christopher Collins2c88e692019-05-22 15:10:14 -07001494 BOOT_LOG_DBG("erasing secondary trailer");
Fabio Utzigc28005b2019-09-10 12:18:29 -03001495 rc = boot_erase_region(fap_secondary_slot,
Fabio Utzig10ee6482019-08-01 12:04:52 -03001496 boot_img_sector_off(state, BOOT_SECONDARY_SLOT,
1497 last_sector),
1498 boot_img_sector_size(state, BOOT_SECONDARY_SLOT,
1499 last_sector));
Fabio Utzig13d9e352017-10-05 20:32:31 -03001500 assert(rc == 0);
1501
David Vincze2d736ad2019-02-18 11:50:22 +01001502 flash_area_close(fap_primary_slot);
1503 flash_area_close(fap_secondary_slot);
Fabio Utzigba829042018-09-18 08:29:34 -03001504
David Vincze2d736ad2019-02-18 11:50:22 +01001505 /* TODO: Perhaps verify the primary slot's signature again? */
David Brown17609d82017-05-05 09:41:34 -06001506
1507 return 0;
1508}
Fabio Utzig338a19f2018-12-03 08:37:08 -02001509#endif
Fabio Utzigba829042018-09-18 08:29:34 -03001510
Christopher Collinsa1c12042019-05-23 14:00:28 -07001511#if !defined(MCUBOOT_OVERWRITE_ONLY)
Fabio Utzigba829042018-09-18 08:29:34 -03001512/**
1513 * Swaps the two images in flash. If a prior copy operation was interrupted
1514 * by a system reset, this function completes that operation.
1515 *
1516 * @param bs The current boot status. This function reads
1517 * this struct to determine if it is resuming
1518 * an interrupted swap operation. This
1519 * function writes the updated status to this
1520 * function on return.
1521 *
1522 * @return 0 on success; nonzero on failure.
1523 */
Christopher Collins92ea77f2016-12-12 15:59:26 -08001524static int
Fabio Utzig10ee6482019-08-01 12:04:52 -03001525boot_swap_image(struct boot_loader_state *state, struct boot_status *bs)
Christopher Collins92ea77f2016-12-12 15:59:26 -08001526{
Fabio Utzig2473ac02017-05-02 12:45:02 -03001527 struct image_header *hdr;
Fabio Utzigba829042018-09-18 08:29:34 -03001528#ifdef MCUBOOT_ENC_IMAGES
1529 const struct flash_area *fap;
1530 uint8_t slot;
Fabio Utzigba829042018-09-18 08:29:34 -03001531#endif
Fabio Utzig2473ac02017-05-02 12:45:02 -03001532 uint32_t size;
1533 uint32_t copy_size;
Fabio Utzigb0f04732019-07-31 09:49:19 -03001534 uint8_t image_index;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001535 int rc = -1;
Fabio Utzig2473ac02017-05-02 12:45:02 -03001536
1537 /* FIXME: just do this if asked by user? */
1538
1539 size = copy_size = 0;
Fabio Utzig10ee6482019-08-01 12:04:52 -03001540 image_index = BOOT_CURR_IMG(state);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001541
Fabio Utzig12d59162019-11-28 10:01:59 -03001542 if (boot_status_is_reset(bs)) {
Fabio Utzig46490722017-09-04 15:34:32 -03001543 /*
1544 * No swap ever happened, so need to find the largest image which
1545 * will be used to determine the amount of sectors to swap.
1546 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001547 hdr = boot_img_hdr(state, BOOT_PRIMARY_SLOT);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001548 if (hdr->ih_magic == IMAGE_MAGIC) {
Fabio Utzigd638b172019-08-09 10:38:05 -03001549 rc = boot_read_image_size(state, BOOT_PRIMARY_SLOT, &copy_size);
David Brownf5b33d82017-09-01 10:58:27 -06001550 assert(rc == 0);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001551 }
Fabio Utzig2473ac02017-05-02 12:45:02 -03001552
Fabio Utzigba829042018-09-18 08:29:34 -03001553#ifdef MCUBOOT_ENC_IMAGES
Fabio Utzig2fc80df2018-12-14 06:47:38 -02001554 if (IS_ENCRYPTED(hdr)) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001555 fap = BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT);
Fabio Utzig4741c452019-12-19 15:32:41 -03001556 rc = boot_enc_load(BOOT_CURR_ENC(state), image_index, hdr, fap, bs);
Fabio Utzigba829042018-09-18 08:29:34 -03001557 assert(rc >= 0);
1558
1559 if (rc == 0) {
Fabio Utzig4741c452019-12-19 15:32:41 -03001560 rc = boot_enc_set_key(BOOT_CURR_ENC(state), 0, bs);
Fabio Utzigba829042018-09-18 08:29:34 -03001561 assert(rc == 0);
1562 } else {
1563 rc = 0;
1564 }
1565 } else {
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001566 (void)memset(bs->enckey[0], BOOT_UNINITIALIZED_KEY_FILL,
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001567 BOOT_ENC_KEY_ALIGN_SIZE);
Fabio Utzigba829042018-09-18 08:29:34 -03001568 }
1569#endif
1570
Fabio Utzig10ee6482019-08-01 12:04:52 -03001571 hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT);
Fabio Utzig46490722017-09-04 15:34:32 -03001572 if (hdr->ih_magic == IMAGE_MAGIC) {
Fabio Utzigd638b172019-08-09 10:38:05 -03001573 rc = boot_read_image_size(state, BOOT_SECONDARY_SLOT, &size);
Fabio Utzig46490722017-09-04 15:34:32 -03001574 assert(rc == 0);
1575 }
1576
Fabio Utzigba829042018-09-18 08:29:34 -03001577#ifdef MCUBOOT_ENC_IMAGES
Fabio Utzig10ee6482019-08-01 12:04:52 -03001578 hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT);
Fabio Utzig2fc80df2018-12-14 06:47:38 -02001579 if (IS_ENCRYPTED(hdr)) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001580 fap = BOOT_IMG_AREA(state, BOOT_SECONDARY_SLOT);
Fabio Utzig4741c452019-12-19 15:32:41 -03001581 rc = boot_enc_load(BOOT_CURR_ENC(state), image_index, hdr, fap, bs);
Fabio Utzigba829042018-09-18 08:29:34 -03001582 assert(rc >= 0);
1583
1584 if (rc == 0) {
Fabio Utzig4741c452019-12-19 15:32:41 -03001585 rc = boot_enc_set_key(BOOT_CURR_ENC(state), 1, bs);
Fabio Utzigba829042018-09-18 08:29:34 -03001586 assert(rc == 0);
1587 } else {
1588 rc = 0;
1589 }
1590 } else {
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001591 (void)memset(bs->enckey[1], BOOT_UNINITIALIZED_KEY_FILL,
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001592 BOOT_ENC_KEY_ALIGN_SIZE);
Fabio Utzigba829042018-09-18 08:29:34 -03001593 }
1594#endif
1595
Fabio Utzig46490722017-09-04 15:34:32 -03001596 if (size > copy_size) {
1597 copy_size = size;
1598 }
1599
1600 bs->swap_size = copy_size;
1601 } else {
1602 /*
1603 * If a swap was under way, the swap_size should already be present
1604 * in the trailer...
1605 */
Fabio Utzigb0f04732019-07-31 09:49:19 -03001606 rc = boot_read_swap_size(image_index, &bs->swap_size);
Fabio Utzig46490722017-09-04 15:34:32 -03001607 assert(rc == 0);
1608
1609 copy_size = bs->swap_size;
Fabio Utzigba829042018-09-18 08:29:34 -03001610
1611#ifdef MCUBOOT_ENC_IMAGES
Fabio Utzig4741c452019-12-19 15:32:41 -03001612 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
1613 rc = boot_read_enc_key(image_index, slot, bs);
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001614 assert(0 == rc);
Fabio Utzigba829042018-09-18 08:29:34 -03001615
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001616 /* Set only an initialized key */
1617 if (!bootutil_buffer_is_filled(bs->enckey[slot],
1618 BOOT_UNINITIALIZED_KEY_FILL,
1619 BOOT_ENC_KEY_SIZE)) {
1620 rc = boot_enc_set_key(BOOT_CURR_ENC(state), slot, bs);
1621 assert(rc == 0);
Fabio Utzigba829042018-09-18 08:29:34 -03001622 }
1623 }
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02001624#if defined(MCUBOOT_SAVE_ENC_IV)
1625 rc = boot_read_iv(image_index, 1, state->enc[image_index][1].aes_iv);
1626 assert(rc == 0);
1627#endif
Fabio Utzigba829042018-09-18 08:29:34 -03001628#endif
Fabio Utzig2473ac02017-05-02 12:45:02 -03001629 }
1630
Fabio Utzig12d59162019-11-28 10:01:59 -03001631 swap_run(state, bs, copy_size);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001632
David Vincze2d736ad2019-02-18 11:50:22 +01001633#ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT
Fabio Utzig12d59162019-11-28 10:01:59 -03001634 extern int boot_status_fails;
Fabio Utziga0e1cce2017-11-23 20:04:01 -02001635 if (boot_status_fails > 0) {
Christopher Collins2c88e692019-05-22 15:10:14 -07001636 BOOT_LOG_WRN("%d status write fails performing the swap",
1637 boot_status_fails);
Fabio Utziga0e1cce2017-11-23 20:04:01 -02001638 }
1639#endif
1640
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001641 return rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001642}
David Brown17609d82017-05-05 09:41:34 -06001643#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -08001644
David Vinczee32483f2019-06-13 10:46:24 +02001645#if (BOOT_IMAGE_NUMBER > 1)
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02001646#if defined(MCUBOOT_DEPENDENCY_CHECK)
David Vinczee32483f2019-06-13 10:46:24 +02001647/**
1648 * Check the image dependency whether it is satisfied and modify
1649 * the swap type if necessary.
1650 *
1651 * @param dep Image dependency which has to be verified.
1652 *
1653 * @return 0 on success; nonzero on failure.
1654 */
1655static int
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001656boot_verify_slot_dependency_flash(struct boot_loader_state *state, struct image_dependency *dep)
David Vinczee32483f2019-06-13 10:46:24 +02001657{
1658 struct image_version *dep_version;
1659 size_t dep_slot;
1660 int rc;
David Browne6ab34c2019-09-03 12:24:21 -06001661 uint8_t swap_type;
David Vinczee32483f2019-06-13 10:46:24 +02001662
1663 /* Determine the source of the image which is the subject of
1664 * the dependency and get it's version. */
David Browne6ab34c2019-09-03 12:24:21 -06001665 swap_type = state->swap_type[dep->image_id];
Barry Solomon04075532020-03-18 09:33:32 -04001666 dep_slot = BOOT_IS_UPGRADE(swap_type) ? BOOT_SECONDARY_SLOT
1667 : BOOT_PRIMARY_SLOT;
Fabio Utzig10ee6482019-08-01 12:04:52 -03001668 dep_version = &state->imgs[dep->image_id][dep_slot].hdr.ih_ver;
David Vinczee32483f2019-06-13 10:46:24 +02001669
David Vincze8b0b6372020-05-20 19:54:44 +02001670 rc = boot_version_cmp(dep_version, &dep->image_min_version);
1671 if (rc < 0) {
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02001672#ifndef MCUBOOT_OVERWRITE_ONLY
David Vinczee32483f2019-06-13 10:46:24 +02001673 /* Dependency not satisfied.
1674 * Modify the swap type to decrease the version number of the image
1675 * (which will be located in the primary slot after the boot process),
1676 * consequently the number of unsatisfied dependencies will be
1677 * decreased or remain the same.
1678 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001679 switch (BOOT_SWAP_TYPE(state)) {
David Vinczee32483f2019-06-13 10:46:24 +02001680 case BOOT_SWAP_TYPE_TEST:
1681 case BOOT_SWAP_TYPE_PERM:
INFINEON\DovhalA21babb72025-07-18 10:36:03 +03001682 /* BOOT_SWAP_TYPE_NONE has been changed to BOOT_SWAP_TYPE_FAIL to avoid
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02001683 * reversion again after device reset */
1684 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_FAIL;
David Vinczee32483f2019-06-13 10:46:24 +02001685 break;
1686 case BOOT_SWAP_TYPE_NONE:
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02001687 BOOT_LOG_DBG("Dependency is unsatisfied. Slot will be reverted.");
Fabio Utzig10ee6482019-08-01 12:04:52 -03001688 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_REVERT;
David Vinczee32483f2019-06-13 10:46:24 +02001689 break;
1690 default:
1691 break;
1692 }
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02001693#else
1694 BOOT_LOG_DBG("Dependency is unsatisfied.");
1695#endif
David Vincze8b0b6372020-05-20 19:54:44 +02001696 } else {
1697 /* Dependency satisfied. */
1698 rc = 0;
David Vinczee32483f2019-06-13 10:46:24 +02001699 }
1700
1701 return rc;
1702}
1703
1704/**
1705 * Read all dependency TLVs of an image from the flash and verify
1706 * one after another to see if they are all satisfied.
1707 *
1708 * @param slot Image slot number.
1709 *
1710 * @return 0 on success; nonzero on failure.
1711 */
1712static int
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001713boot_verify_slot_dependencies_flash(struct boot_loader_state *state, uint32_t slot)
David Vinczee32483f2019-06-13 10:46:24 +02001714{
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001715 const struct flash_area *fap = NULL;
Fabio Utzig61fd8882019-09-14 20:00:20 -03001716 struct image_tlv_iter it;
David Vinczee32483f2019-06-13 10:46:24 +02001717 struct image_dependency dep;
1718 uint32_t off;
Fabio Utzig61fd8882019-09-14 20:00:20 -03001719 uint16_t len;
Fabio Utzigb0f04732019-07-31 09:49:19 -03001720 int area_id;
David Vinczee32483f2019-06-13 10:46:24 +02001721 int rc;
1722
Fabio Utzig10ee6482019-08-01 12:04:52 -03001723 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
Fabio Utzigb0f04732019-07-31 09:49:19 -03001724 rc = flash_area_open(area_id, &fap);
David Vinczee32483f2019-06-13 10:46:24 +02001725 if (rc != 0) {
1726 rc = BOOT_EFLASH;
1727 goto done;
1728 }
1729
Fabio Utzig61fd8882019-09-14 20:00:20 -03001730 rc = bootutil_tlv_iter_begin(&it, boot_img_hdr(state, slot), fap,
1731 IMAGE_TLV_DEPENDENCY, true);
David Vinczee32483f2019-06-13 10:46:24 +02001732 if (rc != 0) {
David Vinczee32483f2019-06-13 10:46:24 +02001733 goto done;
1734 }
1735
Fabio Utzig61fd8882019-09-14 20:00:20 -03001736 while (true) {
1737 rc = bootutil_tlv_iter_next(&it, &off, &len, NULL);
1738 if (rc < 0) {
1739 return -1;
1740 } else if (rc > 0) {
1741 rc = 0;
David Vinczee32483f2019-06-13 10:46:24 +02001742 break;
1743 }
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001744 else
1745 {
1746 /* acc. to MISRA R.15.7 */
1747 }
Fabio Utzig61fd8882019-09-14 20:00:20 -03001748
1749 if (len != sizeof(dep)) {
1750 rc = BOOT_EBADIMAGE;
1751 goto done;
1752 }
1753
1754 rc = flash_area_read(fap, off, &dep, len);
1755 if (rc != 0) {
1756 rc = BOOT_EFLASH;
1757 goto done;
1758 }
1759
1760 if (dep.image_id >= BOOT_IMAGE_NUMBER) {
1761 rc = BOOT_EBADARGS;
1762 goto done;
1763 }
1764
1765 /* Verify dependency and modify the swap type if not satisfied. */
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001766 rc = boot_verify_slot_dependency_flash(state, &dep);
Fabio Utzig61fd8882019-09-14 20:00:20 -03001767 if (rc != 0) {
1768 /* Dependency not satisfied. */
1769 goto done;
1770 }
David Vinczee32483f2019-06-13 10:46:24 +02001771 }
1772
1773done:
1774 flash_area_close(fap);
1775 return rc;
1776}
1777
1778/**
David Vinczee32483f2019-06-13 10:46:24 +02001779 * Iterate over all the images and verify whether the image dependencies in the
1780 * TLV area are all satisfied and update the related swap type if necessary.
1781 */
Fabio Utzig298913b2019-08-28 11:22:45 -03001782static int
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001783boot_verify_dependencies_flash(struct boot_loader_state *state)
David Vinczee32483f2019-06-13 10:46:24 +02001784{
Erik Johnson49063752020-02-06 09:59:31 -06001785 int rc = -1;
Fabio Utzig298913b2019-08-28 11:22:45 -03001786 uint8_t slot;
David Vinczee32483f2019-06-13 10:46:24 +02001787
Fabio Utzig10ee6482019-08-01 12:04:52 -03001788 BOOT_CURR_IMG(state) = 0;
1789 while (BOOT_CURR_IMG(state) < BOOT_IMAGE_NUMBER) {
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001790 if (state->img_mask[BOOT_CURR_IMG(state)]) {
1791 BOOT_CURR_IMG(state)++;
1792 continue;
1793 }
Fabio Utzig298913b2019-08-28 11:22:45 -03001794 if (BOOT_SWAP_TYPE(state) != BOOT_SWAP_TYPE_NONE &&
1795 BOOT_SWAP_TYPE(state) != BOOT_SWAP_TYPE_FAIL) {
1796 slot = BOOT_SECONDARY_SLOT;
1797 } else {
1798 slot = BOOT_PRIMARY_SLOT;
1799 }
1800
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001801 rc = boot_verify_slot_dependencies_flash(state, slot);
Fabio Utzigabec0732019-07-31 08:40:22 -03001802 if (rc == 0) {
David Vinczee32483f2019-06-13 10:46:24 +02001803 /* All dependencies've been satisfied, continue with next image. */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001804 BOOT_CURR_IMG(state)++;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001805 } else {
1806#if (USE_SHARED_SLOT == 1)
1807 /* Disable an upgrading of this image.*/
1808 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
1809 BOOT_CURR_IMG(state)++;
1810#else
Fabio Utzig298913b2019-08-28 11:22:45 -03001811 /* Cannot upgrade due to non-met dependencies, so disable all
1812 * image upgrades.
1813 */
1814 for (int idx = 0; idx < BOOT_IMAGE_NUMBER; idx++) {
1815 BOOT_CURR_IMG(state) = idx;
INFINEON\DovhalA21babb72025-07-18 10:36:03 +03001816 /*When dependency is not satisfied, the boot_verify_slot_dependencies_flash
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02001817 changes swap type to BOOT_SWAP_TYPE_REVERT to have ability of reversion of a
INFINEON\DovhalA21babb72025-07-18 10:36:03 +03001818 dependent image. That's why BOOT_SWAP_TYPE_REVERT must not be changed to
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02001819 BOOT_SWAP_TYPE_NONE */
1820 if (BOOT_SWAP_TYPE(state) != BOOT_SWAP_TYPE_REVERT) {
1821 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
1822 }
Fabio Utzig298913b2019-08-28 11:22:45 -03001823 }
1824 break;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001825#endif /* (USE_SHARED_SLOT == 1) */
David Vinczee32483f2019-06-13 10:46:24 +02001826 }
1827 }
Fabio Utzig298913b2019-08-28 11:22:45 -03001828 return rc;
David Vinczee32483f2019-06-13 10:46:24 +02001829}
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02001830#endif /* (MCUBOOT_DEPENDENCY_CHECK) */
David Vinczee32483f2019-06-13 10:46:24 +02001831#endif /* (BOOT_IMAGE_NUMBER > 1) */
1832
Christopher Collins92ea77f2016-12-12 15:59:26 -08001833/**
David Vinczeba3bd602019-06-17 16:01:43 +02001834 * Performs a clean (not aborted) image update.
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001835 *
David Vinczeba3bd602019-06-17 16:01:43 +02001836 * @param bs The current boot status.
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001837 *
1838 * @return 0 on success; nonzero on failure.
1839 */
1840static int
Fabio Utzig10ee6482019-08-01 12:04:52 -03001841boot_perform_update(struct boot_loader_state *state, struct boot_status *bs)
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001842{
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001843 int rc;
Fabio Utzig10ee6482019-08-01 12:04:52 -03001844#ifndef MCUBOOT_OVERWRITE_ONLY
1845 uint8_t swap_type;
1846#endif
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001847
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001848 BOOT_LOG_DBG("> boot_perform_update: bs->idx = %" PRIu32, bs->idx);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +02001849
David Vinczeba3bd602019-06-17 16:01:43 +02001850 /* At this point there are no aborted swaps. */
1851#if defined(MCUBOOT_OVERWRITE_ONLY)
Fabio Utzig10ee6482019-08-01 12:04:52 -03001852 rc = boot_copy_image(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02001853#elif defined(MCUBOOT_BOOTSTRAP)
1854 /* Check if the image update was triggered by a bad image in the
1855 * primary slot (the validity of the image in the secondary slot had
1856 * already been checked).
1857 */
Raef Colese8fe6cf2020-05-26 13:07:40 +01001858 fih_int fih_rc = FIH_FAILURE;
1859 rc = boot_check_header_erased(state, BOOT_PRIMARY_SLOT);
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +02001860
1861#ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT
Raef Colese8fe6cf2020-05-26 13:07:40 +01001862 FIH_CALL(boot_validate_slot, fih_rc, state, BOOT_PRIMARY_SLOT, bs);
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +02001863#else
1864 fih_rc = FIH_SUCCESS;
1865#endif
1866
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02001867 if (rc == 0 || !fih_eq(fih_rc, FIH_SUCCESS)) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001868 /* Initialize swap status partition for primary slot, because
1869 * in swap mode it is needed to properly complete copying the image
1870 * to the primary slot.
1871 */
1872 const struct flash_area *fap_primary_slot = NULL;
1873
1874 rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state)),
1875 &fap_primary_slot);
1876 assert(rc == 0);
1877
1878 rc = swap_status_init(state, fap_primary_slot, bs);
1879 assert(rc == 0);
1880
1881 flash_area_close(fap_primary_slot);
1882
Fabio Utzig10ee6482019-08-01 12:04:52 -03001883 rc = boot_copy_image(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02001884 } else {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001885 rc = boot_swap_image(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02001886 }
1887#else
Fabio Utzig10ee6482019-08-01 12:04:52 -03001888 rc = boot_swap_image(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02001889#endif
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001890 assert(rc == 0);
David Vinczeba3bd602019-06-17 16:01:43 +02001891
1892#ifndef MCUBOOT_OVERWRITE_ONLY
1893 /* The following state needs image_ok be explicitly set after the
1894 * swap was finished to avoid a new revert.
1895 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001896 swap_type = BOOT_SWAP_TYPE(state);
1897 if (swap_type == BOOT_SWAP_TYPE_REVERT ||
1898 swap_type == BOOT_SWAP_TYPE_PERM) {
Fabio Utzig12d59162019-11-28 10:01:59 -03001899 rc = swap_set_image_ok(BOOT_CURR_IMG(state));
David Vinczeba3bd602019-06-17 16:01:43 +02001900 if (rc != 0) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001901 BOOT_SWAP_TYPE(state) = swap_type = BOOT_SWAP_TYPE_PANIC;
David Vinczeba3bd602019-06-17 16:01:43 +02001902 }
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001903 }
1904
David Vinczec3084132020-02-18 14:50:47 +01001905#ifdef MCUBOOT_HW_ROLLBACK_PROT
1906 if (swap_type == BOOT_SWAP_TYPE_PERM) {
1907 /* Update the stored security counter with the new image's security
1908 * counter value. The primary slot holds the new image at this point,
1909 * but the secondary slot's image header must be passed since image
1910 * headers in the boot_data structure have not been updated yet.
1911 *
1912 * In case of a permanent image swap mcuboot will never attempt to
1913 * revert the images on the next reboot. Therefore, the security
1914 * counter must be increased right after the image upgrade.
1915 */
1916 rc = boot_update_security_counter(
1917 BOOT_CURR_IMG(state),
1918 BOOT_PRIMARY_SLOT,
1919 boot_img_hdr(state, BOOT_SECONDARY_SLOT));
1920 if (rc != 0) {
1921 BOOT_LOG_ERR("Security counter update failed after "
1922 "image upgrade.");
1923 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
1924 }
1925 }
1926#endif /* MCUBOOT_HW_ROLLBACK_PROT */
1927
Fabio Utzige575b0b2019-09-11 12:34:23 -03001928 if (BOOT_IS_UPGRADE(swap_type)) {
Fabio Utzig12d59162019-11-28 10:01:59 -03001929 rc = swap_set_copy_done(BOOT_CURR_IMG(state));
INFINEON\DovhalAe54c0a32024-07-31 22:45:38 +03001930#if defined(MCUBOOT_ENC_IMAGES_SMIF)
1931 rc |= swap_clear_magic_upgrade(BOOT_CURR_IMG(state));
1932#endif
David Vinczeba3bd602019-06-17 16:01:43 +02001933 if (rc != 0) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001934 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
Christopher Collinsa1c12042019-05-23 14:00:28 -07001935 }
David Vinczeba3bd602019-06-17 16:01:43 +02001936 }
1937#endif /* !MCUBOOT_OVERWRITE_ONLY */
Fabio Utzig338a19f2018-12-03 08:37:08 -02001938
David Vinczeba3bd602019-06-17 16:01:43 +02001939 return rc;
1940}
1941
1942/**
1943 * Completes a previously aborted image swap.
1944 *
1945 * @param bs The current boot status.
1946 *
1947 * @return 0 on success; nonzero on failure.
1948 */
1949#if !defined(MCUBOOT_OVERWRITE_ONLY)
1950static int
Fabio Utzig10ee6482019-08-01 12:04:52 -03001951boot_complete_partial_swap(struct boot_loader_state *state,
1952 struct boot_status *bs)
David Vinczeba3bd602019-06-17 16:01:43 +02001953{
1954 int rc;
1955
1956 /* Determine the type of swap operation being resumed from the
1957 * `swap-type` trailer field.
1958 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001959 rc = boot_swap_image(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02001960 assert(rc == 0);
1961
Fabio Utzig10ee6482019-08-01 12:04:52 -03001962 BOOT_SWAP_TYPE(state) = bs->swap_type;
David Vinczeba3bd602019-06-17 16:01:43 +02001963
1964 /* The following states need image_ok be explicitly set after the
1965 * swap was finished to avoid a new revert.
1966 */
1967 if (bs->swap_type == BOOT_SWAP_TYPE_REVERT ||
1968 bs->swap_type == BOOT_SWAP_TYPE_PERM) {
Fabio Utzig12d59162019-11-28 10:01:59 -03001969 rc = swap_set_image_ok(BOOT_CURR_IMG(state));
David Vinczeba3bd602019-06-17 16:01:43 +02001970 if (rc != 0) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001971 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
David Vinczeba3bd602019-06-17 16:01:43 +02001972 }
1973 }
1974
Fabio Utzige575b0b2019-09-11 12:34:23 -03001975 if (BOOT_IS_UPGRADE(bs->swap_type)) {
Fabio Utzig12d59162019-11-28 10:01:59 -03001976 rc = swap_set_copy_done(BOOT_CURR_IMG(state));
David Vinczeba3bd602019-06-17 16:01:43 +02001977 if (rc != 0) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001978 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
David Vinczeba3bd602019-06-17 16:01:43 +02001979 }
1980 }
1981
Fabio Utzig10ee6482019-08-01 12:04:52 -03001982 if (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_PANIC) {
David Vinczeba3bd602019-06-17 16:01:43 +02001983 BOOT_LOG_ERR("panic!");
1984 assert(0);
1985
1986 /* Loop forever... */
1987 while (1) {}
1988 }
1989
1990 return rc;
1991}
1992#endif /* !MCUBOOT_OVERWRITE_ONLY */
1993
1994#if (BOOT_IMAGE_NUMBER > 1)
1995/**
1996 * Review the validity of previously determined swap types of other images.
1997 *
1998 * @param aborted_swap The current image upgrade is a
1999 * partial/aborted swap.
2000 */
2001static void
Fabio Utzig10ee6482019-08-01 12:04:52 -03002002boot_review_image_swap_types(struct boot_loader_state *state,
2003 bool aborted_swap)
David Vinczeba3bd602019-06-17 16:01:43 +02002004{
2005 /* In that case if we rebooted in the middle of an image upgrade process, we
2006 * must review the validity of swap types, that were previously determined
2007 * for other images. The image_ok flag had not been set before the reboot
2008 * for any of the updated images (only the copy_done flag) and thus falsely
2009 * the REVERT swap type has been determined for the previous images that had
2010 * been updated before the reboot.
2011 *
2012 * There are two separate scenarios that we have to deal with:
2013 *
2014 * 1. The reboot has happened during swapping an image:
2015 * The current image upgrade has been determined as a
2016 * partial/aborted swap.
2017 * 2. The reboot has happened between two separate image upgrades:
2018 * In this scenario we must check the swap type of the current image.
2019 * In those cases if it is NONE or REVERT we cannot certainly determine
2020 * the fact of a reboot. In a consistent state images must move in the
2021 * same direction or stay in place, e.g. in practice REVERT and TEST
2022 * swap types cannot be present at the same time. If the swap type of
2023 * the current image is either TEST, PERM or FAIL we must review the
2024 * already determined swap types of other images and set each false
2025 * REVERT swap types to NONE (these images had been successfully
2026 * updated before the system rebooted between two separate image
2027 * upgrades).
2028 */
2029
Fabio Utzig10ee6482019-08-01 12:04:52 -03002030 if (BOOT_CURR_IMG(state) == 0) {
David Vinczeba3bd602019-06-17 16:01:43 +02002031 /* Nothing to do */
2032 return;
2033 }
2034
2035 if (!aborted_swap) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03002036 if ((BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_NONE) ||
2037 (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_REVERT)) {
David Vinczeba3bd602019-06-17 16:01:43 +02002038 /* Nothing to do */
2039 return;
2040 }
2041 }
2042
Fabio Utzig10ee6482019-08-01 12:04:52 -03002043 for (uint8_t i = 0; i < BOOT_CURR_IMG(state); i++) {
2044 if (state->swap_type[i] == BOOT_SWAP_TYPE_REVERT) {
2045 state->swap_type[i] = BOOT_SWAP_TYPE_NONE;
David Vinczeba3bd602019-06-17 16:01:43 +02002046 }
2047 }
2048}
2049#endif
2050
2051/**
2052 * Prepare image to be updated if required.
2053 *
2054 * Prepare image to be updated if required with completing an image swap
2055 * operation if one was aborted and/or determining the type of the
2056 * swap operation. In case of any error set the swap type to NONE.
2057 *
Fabio Utzig10ee6482019-08-01 12:04:52 -03002058 * @param state TODO
David Vinczeba3bd602019-06-17 16:01:43 +02002059 * @param bs Pointer where the read and possibly updated
2060 * boot status can be written to.
2061 */
2062static void
Fabio Utzig10ee6482019-08-01 12:04:52 -03002063boot_prepare_image_for_update(struct boot_loader_state *state,
2064 struct boot_status *bs)
David Vinczeba3bd602019-06-17 16:01:43 +02002065{
2066 int rc;
Raef Colese8fe6cf2020-05-26 13:07:40 +01002067 fih_int fih_rc = FIH_FAILURE;
David Vinczeba3bd602019-06-17 16:01:43 +02002068
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002069 BOOT_LOG_DBG("> boot_prepare_image_for_update: image = %u",
2070 (unsigned)BOOT_CURR_IMG(state));
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +02002071
David Vinczeba3bd602019-06-17 16:01:43 +02002072 /* Determine the sector layout of the image slots and scratch area. */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002073 rc = boot_read_sectors(state);
David Vinczeba3bd602019-06-17 16:01:43 +02002074 if (rc != 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002075 BOOT_LOG_WRN("Failed reading sectors; BOOT_MAX_IMG_SECTORS=%u"
2076 " - too small?", (unsigned int) BOOT_MAX_IMG_SECTORS);
David Vinczeba3bd602019-06-17 16:01:43 +02002077 /* Unable to determine sector layout, continue with next image
2078 * if there is one.
2079 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002080 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002081 if (rc == BOOT_EFLASH)
2082 {
2083 /* Only return on error from the primary image flash */
2084 return;
2085 }
David Vinczeba3bd602019-06-17 16:01:43 +02002086 }
2087
2088 /* Attempt to read an image header from each slot. */
Fabio Utzig12d59162019-11-28 10:01:59 -03002089 rc = boot_read_image_headers(state, false, NULL);
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002090 BOOT_LOG_DBG(" * Read an image (%u) header from each slot: rc = %d",
2091 (unsigned)BOOT_CURR_IMG(state), rc);
David Vinczeba3bd602019-06-17 16:01:43 +02002092 if (rc != 0) {
2093 /* Continue with next image if there is one. */
Fabio Utzigb0f04732019-07-31 09:49:19 -03002094 BOOT_LOG_WRN("Failed reading image headers; Image=%u",
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002095 (unsigned)BOOT_CURR_IMG(state));
Fabio Utzig10ee6482019-08-01 12:04:52 -03002096 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
David Vinczeba3bd602019-06-17 16:01:43 +02002097 return;
2098 }
2099
2100 /* If the current image's slots aren't compatible, no swap is possible.
2101 * Just boot into primary slot.
2102 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002103 if (boot_slots_compatible(state)) {
Fabio Utzig12d59162019-11-28 10:01:59 -03002104 boot_status_reset(bs);
2105
2106#ifndef MCUBOOT_OVERWRITE_ONLY
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002107#ifdef MCUBOOT_SWAP_USING_STATUS
2108
2109 const struct flash_area *fap;
2110 uint32_t img_size = 0;
2111
2112 /* Check here if image firmware + tlvs in slot do not
2113 * overlap with last sector of slot. Last sector of slot
2114 * contains trailer of the image which needs to be
2115 * manupulated independently of other image parts.
2116 * If firmware overlaps with trailer sector it does not
2117 * make sense to move further since any attemps to perform
2118 * swap upgrade would lead to failure or unexpected behaviour
2119 */
2120
2121 for (uint32_t i = 0; i < BOOT_NUM_SLOTS; i++) {
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +02002122 if ((&state->imgs[BOOT_CURR_IMG(state)][i].hdr)->ih_magic == IMAGE_MAGIC) {
2123 rc = boot_read_image_size(state, i, &img_size);
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002124
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +02002125 if (rc == 0) {
2126 fap = BOOT_IMG(state, i).area;
2127 if (fap != NULL) {
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002128
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +02002129 uint32_t trailer_sector_off = (BOOT_WRITE_SZ(state)) * boot_img_num_sectors(state, i) - BOOT_WRITE_SZ(state);
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002130
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +02002131 BOOT_LOG_DBG("Slot %u firmware + tlvs size = %u, "
2132 "slot size = %u, write_size = %u, "
2133 "img sectors num = %u, "
2134 "write_size * sect_num - write_size = %u",
2135 i , img_size, fap->fa_size, BOOT_WRITE_SZ(state),
2136 (uint32_t)boot_img_num_sectors(state, i), trailer_sector_off);
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002137
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +02002138 if (img_size > trailer_sector_off) {
2139 BOOT_LOG_ERR("Firmware + tlvs in slot %u overlaps with last sector, which contains trailer, erasing this image", i);
2140 rc = flash_area_erase(fap, 0, flash_area_get_size(fap));
2141 }
2142 else {
2143 /* image firmware + tlvs do not overlap with last sector of slot, continue */
2144 }
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002145 }
2146 }
2147 }
2148 }
2149#endif /* MCUBOOT_SWAP_USING_STATUS */
2150
Fabio Utzig12d59162019-11-28 10:01:59 -03002151 rc = swap_read_status(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02002152 if (rc != 0) {
2153 BOOT_LOG_WRN("Failed reading boot status; Image=%u",
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002154 (unsigned)BOOT_CURR_IMG(state));
David Vinczeba3bd602019-06-17 16:01:43 +02002155 /* Continue with next image if there is one. */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002156 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
David Vinczeba3bd602019-06-17 16:01:43 +02002157 return;
2158 }
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +02002159#endif /* ifndef MCUBOOT_OVERWRITE_ONLY */
David Vinczeba3bd602019-06-17 16:01:43 +02002160
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +02002161#if defined (MCUBOOT_SWAP_USING_MOVE) || defined(MCUBOOT_SWAP_USING_SCRATCH)
Fabio Utzig74aef312019-11-28 11:05:34 -03002162 /*
2163 * Must re-read image headers because the boot status might
2164 * have been updated in the previous function call.
2165 */
2166 rc = boot_read_image_headers(state, !boot_status_is_reset(bs), bs);
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002167 BOOT_LOG_DBG(" * re-read image(%u) headers: rc = %d.",
2168 (unsigned)BOOT_CURR_IMG(state), rc);
Fabio Utzig32afe852020-10-04 10:36:02 -03002169#ifdef MCUBOOT_BOOTSTRAP
2170 /* When bootstrapping it's OK to not have image magic in the primary slot */
2171 if (rc != 0 && (BOOT_CURR_IMG(state) != BOOT_PRIMARY_SLOT ||
2172 boot_check_header_erased(state, BOOT_PRIMARY_SLOT) != 0)) {
2173#else
Fabio Utzig74aef312019-11-28 11:05:34 -03002174 if (rc != 0) {
Fabio Utzig32afe852020-10-04 10:36:02 -03002175#endif
Fabio Utzig74aef312019-11-28 11:05:34 -03002176 /* Continue with next image if there is one. */
2177 BOOT_LOG_WRN("Failed reading image headers; Image=%u",
2178 BOOT_CURR_IMG(state));
2179 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
2180 return;
2181 }
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +02002182#endif /* (MCUBOOT_SWAP_USING_MOVE) || defined(MCUBOOT_SWAP_USING_SCRATCH) */
Fabio Utzig74aef312019-11-28 11:05:34 -03002183
David Vinczeba3bd602019-06-17 16:01:43 +02002184 /* Determine if we rebooted in the middle of an image swap
2185 * operation. If a partial swap was detected, complete it.
2186 */
Fabio Utzig12d59162019-11-28 10:01:59 -03002187 if (!boot_status_is_reset(bs)) {
David Vinczeba3bd602019-06-17 16:01:43 +02002188
2189#if (BOOT_IMAGE_NUMBER > 1)
Fabio Utzig10ee6482019-08-01 12:04:52 -03002190 boot_review_image_swap_types(state, true);
David Vinczeba3bd602019-06-17 16:01:43 +02002191#endif
2192
2193#ifdef MCUBOOT_OVERWRITE_ONLY
2194 /* Should never arrive here, overwrite-only mode has
2195 * no swap state.
2196 */
2197 assert(0);
2198#else
2199 /* Determine the type of swap operation being resumed from the
2200 * `swap-type` trailer field.
2201 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002202 rc = boot_complete_partial_swap(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02002203 assert(rc == 0);
2204#endif
2205 /* Attempt to read an image header from each slot. Ensure that
2206 * image headers in slots are aligned with headers in boot_data.
2207 */
Fabio Utzig12d59162019-11-28 10:01:59 -03002208 rc = boot_read_image_headers(state, false, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02002209 assert(rc == 0);
2210
2211 /* Swap has finished set to NONE */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002212 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
David Vinczeba3bd602019-06-17 16:01:43 +02002213 } else {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +02002214 BOOT_LOG_DBG(" * There was no partial swap, determine swap type.");
2215
David Vinczeba3bd602019-06-17 16:01:43 +02002216 /* There was no partial swap, determine swap type. */
2217 if (bs->swap_type == BOOT_SWAP_TYPE_NONE) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03002218 BOOT_SWAP_TYPE(state) = boot_validated_swap_type(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02002219 } else {
Raef Colese8fe6cf2020-05-26 13:07:40 +01002220 FIH_CALL(boot_validate_slot, fih_rc,
2221 state, BOOT_SECONDARY_SLOT, bs);
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02002222 if (!fih_eq(fih_rc, FIH_SUCCESS)) {
Raef Colese8fe6cf2020-05-26 13:07:40 +01002223 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_FAIL;
2224 } else {
2225 BOOT_SWAP_TYPE(state) = bs->swap_type;
2226 }
David Vinczeba3bd602019-06-17 16:01:43 +02002227 }
2228
2229#if (BOOT_IMAGE_NUMBER > 1)
Fabio Utzig10ee6482019-08-01 12:04:52 -03002230 boot_review_image_swap_types(state, false);
David Vinczeba3bd602019-06-17 16:01:43 +02002231#endif
2232
2233#ifdef MCUBOOT_BOOTSTRAP
Fabio Utzig10ee6482019-08-01 12:04:52 -03002234 if (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_NONE) {
David Vinczeba3bd602019-06-17 16:01:43 +02002235 /* Header checks are done first because they are
2236 * inexpensive. Since overwrite-only copies starting from
2237 * offset 0, if interrupted, it might leave a valid header
2238 * magic, so also run validation on the primary slot to be
2239 * sure it's not OK.
2240 */
Raef Colese8fe6cf2020-05-26 13:07:40 +01002241 rc = boot_check_header_erased(state, BOOT_PRIMARY_SLOT);
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +02002242#ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT
Raef Colese8fe6cf2020-05-26 13:07:40 +01002243 FIH_CALL(boot_validate_slot, fih_rc,
2244 state, BOOT_PRIMARY_SLOT, bs);
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +02002245#else
2246 fih_rc = FIH_SUCCESS;
2247#endif
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02002248 if (rc == 0 || !fih_eq(fih_rc, FIH_SUCCESS)) {
Raef Colese8fe6cf2020-05-26 13:07:40 +01002249
Fabio Utzig3d77c952020-10-04 10:23:17 -03002250 rc = (boot_img_hdr(state, BOOT_SECONDARY_SLOT)->ih_magic == IMAGE_MAGIC) ? 1: 0;
Raef Colese8fe6cf2020-05-26 13:07:40 +01002251 FIH_CALL(boot_validate_slot, fih_rc,
2252 state, BOOT_SECONDARY_SLOT, bs);
2253
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02002254 if (rc == 1 && fih_eq(fih_rc, FIH_SUCCESS)) {
David Vinczeba3bd602019-06-17 16:01:43 +02002255 /* Set swap type to REVERT to overwrite the primary
2256 * slot with the image contained in secondary slot
2257 * and to trigger the explicit setting of the
2258 * image_ok flag.
2259 */
Fabio Utzig59b63e52019-09-10 12:22:35 -03002260 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_REVERT;
David Vinczeba3bd602019-06-17 16:01:43 +02002261 }
Fabio Utzig338a19f2018-12-03 08:37:08 -02002262 }
2263 }
Fabio Utzig338a19f2018-12-03 08:37:08 -02002264#endif
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08002265 }
David Vinczeba3bd602019-06-17 16:01:43 +02002266 } else {
2267 /* In that case if slots are not compatible. */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002268 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08002269 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +02002270 BOOT_LOG_DBG("< boot_prepare_image_for_update");
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08002271}
2272
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002273/**
2274 * Updates the security counter for the current image.
2275 *
2276 * @param state Boot loader status information.
2277 *
2278 * @return 0 on success; nonzero on failure.
2279 */
2280static int
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002281boot_update_hw_rollback_protection_flash(struct boot_loader_state *state)
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002282{
2283#ifdef MCUBOOT_HW_ROLLBACK_PROT
2284 int rc;
2285
2286 /* Update the stored security counter with the active image's security
2287 * counter value. It will only be updated if the new security counter is
2288 * greater than the stored value.
2289 *
2290 * In case of a successful image swapping when the swap type is TEST the
2291 * security counter can be increased only after a reset, when the swap
2292 * type is NONE and the image has marked itself "OK" (the image_ok flag
2293 * has been set). This way a "revert" can be performed when it's
2294 * necessary.
2295 */
2296 if (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_NONE) {
2297 rc = boot_update_security_counter(
2298 BOOT_CURR_IMG(state),
2299 BOOT_PRIMARY_SLOT,
2300 boot_img_hdr(state, BOOT_PRIMARY_SLOT));
2301 if (rc != 0) {
2302 BOOT_LOG_ERR("Security counter update failed after image "
2303 "validation.");
2304 return rc;
2305 }
2306 }
2307
2308 return 0;
2309
2310#else /* MCUBOOT_HW_ROLLBACK_PROT */
2311 (void) (state);
2312
2313 return 0;
2314#endif
2315}
2316
Raef Colese8fe6cf2020-05-26 13:07:40 +01002317fih_int
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002318context_boot_go_flash(struct boot_loader_state *state, struct boot_rsp *rsp)
Christopher Collins92ea77f2016-12-12 15:59:26 -08002319{
Marti Bolivar84898652017-06-13 17:20:22 -04002320 size_t slot;
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002321 struct boot_status bs = {0};
David Vincze9015a5d2020-05-18 14:43:11 +02002322 int rc = -1;
Raef Colese8fe6cf2020-05-26 13:07:40 +01002323 fih_int fih_rc = FIH_FAILURE;
Marti Bolivarc0b47912017-06-13 17:18:09 -04002324 int fa_id;
Fabio Utzigb0f04732019-07-31 09:49:19 -03002325 int image_index;
Christopher Collins92ea77f2016-12-12 15:59:26 -08002326
2327 /* The array of slot sectors are defined here (as opposed to file scope) so
2328 * that they don't get allocated for non-boot-loader apps. This is
2329 * necessary because the gcc option "-fdata-sections" doesn't seem to have
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08002330 * any effect in older gcc versions (e.g., 4.8.4).
Christopher Collins92ea77f2016-12-12 15:59:26 -08002331 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002332 TARGET_STATIC boot_sector_t primary_slot_sectors[BOOT_IMAGE_NUMBER][BOOT_MAX_IMG_SECTORS];
2333 TARGET_STATIC boot_sector_t secondary_slot_sectors[BOOT_IMAGE_NUMBER][BOOT_MAX_IMG_SECTORS];
Fabio Utzig12d59162019-11-28 10:01:59 -03002334#if MCUBOOT_SWAP_USING_SCRATCH
Fabio Utzig10ee6482019-08-01 12:04:52 -03002335 TARGET_STATIC boot_sector_t scratch_sectors[BOOT_MAX_IMG_SECTORS];
Fabio Utzig12d59162019-11-28 10:01:59 -03002336#endif
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +02002337#if MCUBOOT_SWAP_USING_STATUS
2338 TARGET_STATIC boot_sector_t status_sectors[BOOT_MAX_SWAP_STATUS_SECTORS];
2339#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -08002340
David Vinczeba3bd602019-06-17 16:01:43 +02002341 /* Iterate over all the images. By the end of the loop the swap type has
2342 * to be determined for each image and all aborted swaps have to be
2343 * completed.
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08002344 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002345 IMAGES_ITER(BOOT_CURR_IMG(state)) {
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02002346#if !defined(MCUBOOT_DEPENDENCY_CHECK)
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002347#if BOOT_IMAGE_NUMBER > 1
2348 if (state->img_mask[BOOT_CURR_IMG(state)]) {
2349 continue;
2350 }
2351#endif
INFINEON\DovhalA21babb72025-07-18 10:36:03 +03002352#else
2353 /* Dependency is set and encryption is enabled. In this case we cannot
2354 * reread the first image header because it is encrypted
2355 */
2356#if defined(MCUBOOT_ENC_IMAGES_XIP_MULTI)
2357#if BOOT_IMAGE_NUMBER > 1
2358 if ((BOOT_CURR_IMG(state) == 0) && (state->img_mask[BOOT_CURR_IMG(state)] == true)) {
2359 continue;
2360 }
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02002361#endif
INFINEON\DovhalA21babb72025-07-18 10:36:03 +03002362#endif /* MCUBOOT_ENC_IMAGES_XIP_MULTI */
2363#endif /* !defined(MCUBOOT_DEPENDENCY_CHECK) */
2364
David Vinczeba3bd602019-06-17 16:01:43 +02002365#if defined(MCUBOOT_ENC_IMAGES) && (BOOT_IMAGE_NUMBER > 1)
2366 /* The keys used for encryption may no longer be valid (could belong to
2367 * another images). Therefore, mark them as invalid to force their reload
2368 * by boot_enc_load().
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03002369 */
Fabio Utzig1e4284b2019-08-23 11:55:27 -03002370 boot_enc_zeroize(BOOT_CURR_ENC(state));
David Brown554c52e2017-06-30 16:01:07 -06002371#endif
2372
Fabio Utzig10ee6482019-08-01 12:04:52 -03002373 image_index = BOOT_CURR_IMG(state);
Fabio Utzigb0f04732019-07-31 09:49:19 -03002374
Fabio Utzig10ee6482019-08-01 12:04:52 -03002375 BOOT_IMG(state, BOOT_PRIMARY_SLOT).sectors =
Fabio Utzigb0f04732019-07-31 09:49:19 -03002376 primary_slot_sectors[image_index];
Fabio Utzig10ee6482019-08-01 12:04:52 -03002377 BOOT_IMG(state, BOOT_SECONDARY_SLOT).sectors =
Fabio Utzigb0f04732019-07-31 09:49:19 -03002378 secondary_slot_sectors[image_index];
Fabio Utzig12d59162019-11-28 10:01:59 -03002379#if MCUBOOT_SWAP_USING_SCRATCH
Fabio Utzig10ee6482019-08-01 12:04:52 -03002380 state->scratch.sectors = scratch_sectors;
Fabio Utzig12d59162019-11-28 10:01:59 -03002381#endif
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +02002382#if MCUBOOT_SWAP_USING_STATUS
2383 state->status.sectors = status_sectors;
2384#endif
David Vinczeba3bd602019-06-17 16:01:43 +02002385
2386 /* Open primary and secondary image areas for the duration
2387 * of this call.
2388 */
2389 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
Fabio Utzigb0f04732019-07-31 09:49:19 -03002390 fa_id = flash_area_id_from_multi_image_slot(image_index, slot);
Fabio Utzig10ee6482019-08-01 12:04:52 -03002391 rc = flash_area_open(fa_id, &BOOT_IMG_AREA(state, slot));
David Vinczeba3bd602019-06-17 16:01:43 +02002392 assert(rc == 0);
2393 }
Fabio Utzig12d59162019-11-28 10:01:59 -03002394#if MCUBOOT_SWAP_USING_SCRATCH
David Vinczeba3bd602019-06-17 16:01:43 +02002395 rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH,
Fabio Utzig10ee6482019-08-01 12:04:52 -03002396 &BOOT_SCRATCH_AREA(state));
David Vinczeba3bd602019-06-17 16:01:43 +02002397 assert(rc == 0);
Fabio Utzig12d59162019-11-28 10:01:59 -03002398#endif
David Vinczeba3bd602019-06-17 16:01:43 +02002399
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +02002400 BOOT_LOG_DBG(" * boot_prepare_image_for_update...");
David Vinczeba3bd602019-06-17 16:01:43 +02002401 /* Determine swap type and complete swap if it has been aborted. */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002402 boot_prepare_image_for_update(state, &bs);
Fabio Utzig298913b2019-08-28 11:22:45 -03002403
David Vinczeba3bd602019-06-17 16:01:43 +02002404 }
2405
David Vinczee32483f2019-06-13 10:46:24 +02002406#if (BOOT_IMAGE_NUMBER > 1)
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02002407#if defined(MCUBOOT_DEPENDENCY_CHECK)
Fabio Utzig298913b2019-08-28 11:22:45 -03002408 /* Iterate over all the images and verify whether the image dependencies
2409 * are all satisfied and update swap type if necessary.
2410 */
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002411 rc = boot_verify_dependencies_flash(state);
David Vincze8b0b6372020-05-20 19:54:44 +02002412 if (rc != 0) {
Fabio Utzig298913b2019-08-28 11:22:45 -03002413 /*
2414 * It was impossible to upgrade because the expected dependency version
2415 * was not available. Here we already changed the swap_type so that
2416 * instead of asserting the bootloader, we continue and no upgrade is
2417 * performed.
2418 */
2419 rc = 0;
2420 }
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02002421#endif /* (MCUBOOT_DEPENDENCY_CHECK) */
2422#endif /* (BOOT_IMAGE_NUMBER > 1) */
David Vinczee32483f2019-06-13 10:46:24 +02002423
David Vinczeba3bd602019-06-17 16:01:43 +02002424 /* Iterate over all the images. At this point there are no aborted swaps
2425 * and the swap types are determined for each image. By the end of the loop
2426 * all required update operations will have been finished.
2427 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002428 IMAGES_ITER(BOOT_CURR_IMG(state)) {
David Vinczeba3bd602019-06-17 16:01:43 +02002429#if (BOOT_IMAGE_NUMBER > 1)
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002430 if (state->img_mask[BOOT_CURR_IMG(state)]) {
2431 continue;
2432 }
2433
David Vinczeba3bd602019-06-17 16:01:43 +02002434#ifdef MCUBOOT_ENC_IMAGES
2435 /* The keys used for encryption may no longer be valid (could belong to
2436 * another images). Therefore, mark them as invalid to force their reload
2437 * by boot_enc_load().
2438 */
Fabio Utzig1e4284b2019-08-23 11:55:27 -03002439 boot_enc_zeroize(BOOT_CURR_ENC(state));
David Vinczeba3bd602019-06-17 16:01:43 +02002440#endif /* MCUBOOT_ENC_IMAGES */
2441
2442 /* Indicate that swap is not aborted */
Fabio Utzig12d59162019-11-28 10:01:59 -03002443 boot_status_reset(&bs);
David Vinczeba3bd602019-06-17 16:01:43 +02002444#endif /* (BOOT_IMAGE_NUMBER > 1) */
2445
2446 /* Set the previously determined swap type */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002447 bs.swap_type = BOOT_SWAP_TYPE(state);
David Vinczeba3bd602019-06-17 16:01:43 +02002448
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002449 BOOT_LOG_DBG(" * process swap_type = %u", (unsigned)bs.swap_type);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +02002450
Fabio Utzig10ee6482019-08-01 12:04:52 -03002451 switch (BOOT_SWAP_TYPE(state)) {
David Vinczeba3bd602019-06-17 16:01:43 +02002452 case BOOT_SWAP_TYPE_NONE:
2453 break;
2454
2455 case BOOT_SWAP_TYPE_TEST: /* fallthrough */
2456 case BOOT_SWAP_TYPE_PERM: /* fallthrough */
2457 case BOOT_SWAP_TYPE_REVERT:
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002458 BOOT_LOG_DBG(" * perform update, mode %u...", (unsigned)bs.swap_type);
2459 rc = BOOT_HOOK_CALL(boot_perform_update_hook, BOOT_HOOK_REGULAR,
2460 BOOT_CURR_IMG(state), &(BOOT_IMG(state, 1).hdr),
2461 BOOT_IMG_AREA(state, BOOT_SECONDARY_SLOT));
2462 if (rc == BOOT_HOOK_REGULAR)
2463 {
2464 rc = boot_perform_update(state, &bs);
2465 }
David Vinczeba3bd602019-06-17 16:01:43 +02002466 assert(rc == 0);
2467 break;
2468
2469 case BOOT_SWAP_TYPE_FAIL:
2470 /* The image in secondary slot was invalid and is now erased. Ensure
2471 * we don't try to boot into it again on the next reboot. Do this by
2472 * pretending we just reverted back to primary slot.
2473 */
2474#ifndef MCUBOOT_OVERWRITE_ONLY
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002475 BOOT_LOG_DBG(" * update failed! Set image_ok manually for image(%u)",
2476 (unsigned)BOOT_CURR_IMG(state));
David Vinczeba3bd602019-06-17 16:01:43 +02002477 /* image_ok needs to be explicitly set to avoid a new revert. */
Fabio Utzig12d59162019-11-28 10:01:59 -03002478 rc = swap_set_image_ok(BOOT_CURR_IMG(state));
David Vinczeba3bd602019-06-17 16:01:43 +02002479 if (rc != 0) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03002480 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
David Vinczeba3bd602019-06-17 16:01:43 +02002481 }
2482#endif /* !MCUBOOT_OVERWRITE_ONLY */
2483 break;
2484
2485 default:
Fabio Utzig10ee6482019-08-01 12:04:52 -03002486 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
David Vinczeba3bd602019-06-17 16:01:43 +02002487 }
2488
Fabio Utzig10ee6482019-08-01 12:04:52 -03002489 if (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_PANIC) {
David Vinczeba3bd602019-06-17 16:01:43 +02002490 BOOT_LOG_ERR("panic!");
2491 assert(0);
2492
2493 /* Loop forever... */
Raef Colese8fe6cf2020-05-26 13:07:40 +01002494 FIH_PANIC;
David Vinczeba3bd602019-06-17 16:01:43 +02002495 }
2496 }
2497
2498 /* Iterate over all the images. At this point all required update operations
2499 * have finished. By the end of the loop each image in the primary slot will
2500 * have been re-validated.
2501 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002502 IMAGES_ITER(BOOT_CURR_IMG(state)) {
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002503#if BOOT_IMAGE_NUMBER > 1
2504 if (state->img_mask[BOOT_CURR_IMG(state)]) {
2505 continue;
2506 }
2507#endif
Fabio Utzig10ee6482019-08-01 12:04:52 -03002508 if (BOOT_SWAP_TYPE(state) != BOOT_SWAP_TYPE_NONE) {
David Vinczeba3bd602019-06-17 16:01:43 +02002509 /* Attempt to read an image header from each slot. Ensure that image
2510 * headers in slots are aligned with headers in boot_data.
2511 */
Fabio Utzig12d59162019-11-28 10:01:59 -03002512 rc = boot_read_image_headers(state, false, &bs);
David Vinczeba3bd602019-06-17 16:01:43 +02002513 if (rc != 0) {
2514 goto out;
2515 }
2516 /* Since headers were reloaded, it can be assumed we just performed
2517 * a swap or overwrite. Now the header info that should be used to
2518 * provide the data for the bootstrap, which previously was at
2519 * secondary slot, was updated to primary slot.
2520 */
2521 }
2522
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +02002523#ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT
2524#if defined(MCUBOOT_RAM_LOAD) /* to fix Rule 14.3 violation */
INFINEON\DovhalA21babb72025-07-18 10:36:03 +03002525#if defined(MCUBOOT_ENC_IMAGES_XIP_MULTI)
2526 if (true) {
2527#else
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +02002528 if(IS_RAM_BOOTABLE(boot_img_hdr(state, BOOT_PRIMARY_SLOT)) == false) {
INFINEON\DovhalA21babb72025-07-18 10:36:03 +03002529#endif /* MCUBOOT_ENC_IMAGES_XIP_MULTI */
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +02002530#endif /* defined(MCUBOOT_RAM_LOAD) */
2531 FIH_CALL(boot_validate_slot, fih_rc, state, BOOT_PRIMARY_SLOT, &bs);
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02002532 if (!fih_eq(fih_rc, FIH_SUCCESS)) {
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +02002533 goto out;
2534 }
2535#if defined(MCUBOOT_RAM_LOAD) /* to fix Rule 14.3 violation */
David Vinczeba3bd602019-06-17 16:01:43 +02002536 }
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +02002537#endif /* defined(MCUBOOT_RAM_LOAD) */
David Vinczeba3bd602019-06-17 16:01:43 +02002538#else
2539 /* Even if we're not re-validating the primary slot, we could be booting
2540 * onto an empty flash chip. At least do a basic sanity check that
2541 * the magic number on the image is OK.
2542 */
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +02002543
2544 BOOT_LOG_INF("Since boot image validation was skipped, "\
2545 "at least IMAGE_MAGIC should be checked");
2546
Fabio Utzig10ee6482019-08-01 12:04:52 -03002547 if (BOOT_IMG(state, BOOT_PRIMARY_SLOT).hdr.ih_magic != IMAGE_MAGIC) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002548 BOOT_LOG_ERR("bad image magic 0x%" PRIx32 "; Image=%u",
2549 BOOT_IMG(state, BOOT_PRIMARY_SLOT).hdr.ih_magic,
2550 (unsigned)BOOT_CURR_IMG(state));
David Vinczeba3bd602019-06-17 16:01:43 +02002551 rc = BOOT_EBADIMAGE;
2552 goto out;
2553 }
David Vinczec3084132020-02-18 14:50:47 +01002554#endif /* MCUBOOT_VALIDATE_PRIMARY_SLOT */
2555
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002556#ifdef MCUBOOT_ENC_IMAGES_XIP
2557 if (0 == BOOT_CURR_IMG(state)) {
2558 if (IS_ENCRYPTED(boot_img_hdr(state, BOOT_PRIMARY_SLOT)))
2559 {
2560 (void)memcpy((uint8_t*)rsp->xip_iv, BOOT_CURR_ENC(state)->aes_iv, BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE);
2561 (void)memcpy((uint8_t*)rsp->xip_key, bs.enckey[BOOT_CURR_IMG(state)], BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE);
David Vinczec3084132020-02-18 14:50:47 +01002562 }
2563 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002564#endif /* MCUBOOT_ENC_IMAGES_XIP */
David Vincze1cf11b52020-03-24 07:51:09 +01002565
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002566 rc = boot_update_hw_rollback_protection_flash(state);
David Vincze1cf11b52020-03-24 07:51:09 +01002567 if (rc != 0) {
Raef Colese8fe6cf2020-05-26 13:07:40 +01002568 goto out;
David Vincze1cf11b52020-03-24 07:51:09 +01002569 }
David Vincze1cf11b52020-03-24 07:51:09 +01002570
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02002571 if(IS_RAM_BOOTABLE(boot_img_hdr(state, BOOT_PRIMARY_SLOT)) == false) {
2572 rc = boot_add_shared_data(state, BOOT_PRIMARY_SLOT);
2573 if (rc != 0) {
2574 goto out;
2575 }
David Vincze1cf11b52020-03-24 07:51:09 +01002576 }
David Vinczeba3bd602019-06-17 16:01:43 +02002577 }
2578
Fabio Utzigb0f04732019-07-31 09:49:19 -03002579#if (BOOT_IMAGE_NUMBER > 1)
David Vinczeba3bd602019-06-17 16:01:43 +02002580 /* Always boot from the primary slot of Image 0. */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002581 BOOT_CURR_IMG(state) = 0;
Fabio Utzigb0f04732019-07-31 09:49:19 -03002582#endif
Fabio Utzig298913b2019-08-28 11:22:45 -03002583
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002584 rsp->br_flash_dev_id = BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT)->fa_device_id;
2585 rsp->br_image_off = boot_img_slot_off(state, BOOT_PRIMARY_SLOT);
2586 rsp->br_hdr = boot_img_hdr(state, BOOT_PRIMARY_SLOT);
Fabio Utzigf616c542019-12-19 15:23:32 -03002587 /*
2588 * Since the boot_status struct stores plaintext encryption keys, reset
2589 * them here to avoid the possibility of jumping into an image that could
2590 * easily recover them.
2591 */
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002592 (void)memset(&bs, 0, sizeof(struct boot_status));
Fabio Utzigf616c542019-12-19 15:23:32 -03002593
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002594 fill_rsp(state, rsp);
Christopher Collins92ea77f2016-12-12 15:59:26 -08002595
Raef Colese8fe6cf2020-05-26 13:07:40 +01002596 fih_rc = FIH_SUCCESS;
Fabio Utzig298913b2019-08-28 11:22:45 -03002597out:
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002598 close_all_flash_areas(state);
Raef Colese8fe6cf2020-05-26 13:07:40 +01002599
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02002600#ifdef MCUBOOT_ENC_IMAGES_XIP_MULTI
2601 SMIF_SET_CRYPTO_MODE(Enable);
2602#endif /* MCUBOOT_ENC_IMAGES_XIP_MULTI */
2603
Raef Colese8fe6cf2020-05-26 13:07:40 +01002604 if (rc) {
2605 fih_rc = fih_int_encode(rc);
2606 }
2607
2608 FIH_RET(fih_rc);
Christopher Collins92ea77f2016-12-12 15:59:26 -08002609}
2610
Raef Colese8fe6cf2020-05-26 13:07:40 +01002611fih_int
Christopher Collins92ea77f2016-12-12 15:59:26 -08002612split_go(int loader_slot, int split_slot, void **entry)
2613{
Marti Bolivarc50926f2017-06-14 09:35:40 -04002614 boot_sector_t *sectors;
Christopher Collins034a6202017-01-11 12:19:37 -08002615 uintptr_t entry_val;
Christopher Collins92ea77f2016-12-12 15:59:26 -08002616 int loader_flash_id;
Marti Bolivarc0b47912017-06-13 17:18:09 -04002617 int split_flash_id;
Christopher Collins92ea77f2016-12-12 15:59:26 -08002618 int rc;
Raef Colese8fe6cf2020-05-26 13:07:40 +01002619 fih_int fih_rc = FIH_FAILURE;
Christopher Collins92ea77f2016-12-12 15:59:26 -08002620
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002621 if ((loader_slot < 0) || (split_slot < 0)) {
2622 FIH_RET(FIH_FAILURE);
2623 }
2624
Christopher Collins92ea77f2016-12-12 15:59:26 -08002625 sectors = malloc(BOOT_MAX_IMG_SECTORS * 2 * sizeof *sectors);
2626 if (sectors == NULL) {
Raef Colese8fe6cf2020-05-26 13:07:40 +01002627 FIH_RET(FIH_FAILURE);
Christopher Collins92ea77f2016-12-12 15:59:26 -08002628 }
David Vinczeba3bd602019-06-17 16:01:43 +02002629 BOOT_IMG(&boot_data, loader_slot).sectors = sectors + 0;
2630 BOOT_IMG(&boot_data, split_slot).sectors = sectors + BOOT_MAX_IMG_SECTORS;
Marti Bolivarc0b47912017-06-13 17:18:09 -04002631
2632 loader_flash_id = flash_area_id_from_image_slot(loader_slot);
2633 rc = flash_area_open(loader_flash_id,
Alvaro Prieto63a2bdb2019-07-04 12:18:49 -07002634 &BOOT_IMG_AREA(&boot_data, loader_slot));
Marti Bolivarc0b47912017-06-13 17:18:09 -04002635 assert(rc == 0);
2636 split_flash_id = flash_area_id_from_image_slot(split_slot);
2637 rc = flash_area_open(split_flash_id,
2638 &BOOT_IMG_AREA(&boot_data, split_slot));
2639 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -08002640
2641 /* Determine the sector layout of the image slots and scratch area. */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002642 rc = boot_read_sectors(&boot_data);
Christopher Collins92ea77f2016-12-12 15:59:26 -08002643 if (rc != 0) {
2644 rc = SPLIT_GO_ERR;
2645 goto done;
2646 }
2647
Fabio Utzig12d59162019-11-28 10:01:59 -03002648 rc = boot_read_image_headers(&boot_data, true, NULL);
Christopher Collins92ea77f2016-12-12 15:59:26 -08002649 if (rc != 0) {
2650 goto done;
2651 }
2652
Christopher Collins92ea77f2016-12-12 15:59:26 -08002653 /* Don't check the bootable image flag because we could really call a
2654 * bootable or non-bootable image. Just validate that the image check
2655 * passes which is distinct from the normal check.
2656 */
Raef Colese8fe6cf2020-05-26 13:07:40 +01002657 FIH_CALL(split_image_check, fih_rc,
2658 boot_img_hdr(&boot_data, split_slot),
2659 BOOT_IMG_AREA(&boot_data, split_slot),
2660 boot_img_hdr(&boot_data, loader_slot),
2661 BOOT_IMG_AREA(&boot_data, loader_slot));
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02002662 if (!fih_eq(fih_rc, FIH_SUCCESS)) {
Christopher Collins92ea77f2016-12-12 15:59:26 -08002663 goto done;
2664 }
2665
Marti Bolivarea088872017-06-12 17:10:49 -04002666 entry_val = boot_img_slot_off(&boot_data, split_slot) +
Marti Bolivarf804f622017-06-12 15:41:48 -04002667 boot_img_hdr(&boot_data, split_slot)->ih_hdr_size;
Christopher Collins034a6202017-01-11 12:19:37 -08002668 *entry = (void *) entry_val;
Christopher Collins92ea77f2016-12-12 15:59:26 -08002669 rc = SPLIT_GO_OK;
2670
2671done:
Marti Bolivarc0b47912017-06-13 17:18:09 -04002672 flash_area_close(BOOT_IMG_AREA(&boot_data, split_slot));
2673 flash_area_close(BOOT_IMG_AREA(&boot_data, loader_slot));
Christopher Collins92ea77f2016-12-12 15:59:26 -08002674 free(sectors);
Raef Colese8fe6cf2020-05-26 13:07:40 +01002675
2676 if (rc) {
2677 fih_rc = fih_int_encode(rc);
2678 }
2679
2680 FIH_RET(fih_rc);
Christopher Collins92ea77f2016-12-12 15:59:26 -08002681}
David Vinczee574f2d2020-07-10 11:42:03 +02002682
David Vinczee574f2d2020-07-10 11:42:03 +02002683
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002684#if defined(MCUBOOT_DIRECT_XIP) || defined(MCUBOOT_RAM_LOAD)
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002685
David Vinczee574f2d2020-07-10 11:42:03 +02002686/**
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002687 * Opens all flash areas and checks which contain an image with a valid header.
David Vinczee574f2d2020-07-10 11:42:03 +02002688 *
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002689 * @param state Boot loader status information.
David Vinczee574f2d2020-07-10 11:42:03 +02002690 *
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002691 * @return 0 on success; nonzero on failure.
2692 */
2693static int
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002694boot_get_slot_usage(struct boot_loader_state *state)
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002695{
2696 uint32_t slot;
2697 int fa_id;
2698 int rc;
2699 struct image_header *hdr = NULL;
2700
2701 IMAGES_ITER(BOOT_CURR_IMG(state)) {
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02002702#if !defined(MCUBOOT_DEPENDENCY_CHECK)
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002703#if BOOT_IMAGE_NUMBER > 1
2704 if (state->img_mask[BOOT_CURR_IMG(state)]) {
2705 continue;
2706 }
2707#endif
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02002708#endif
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002709 /* Open all the slots */
2710 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
2711 fa_id = flash_area_id_from_multi_image_slot(
2712 BOOT_CURR_IMG(state), slot);
2713 rc = flash_area_open(fa_id, &BOOT_IMG_AREA(state, slot));
2714 assert(rc == 0);
2715 }
2716
INFINEON\DovhalA21babb72025-07-18 10:36:03 +03002717#if defined(MCUBOOT_ENC_IMAGES_XIP_MULTI)
2718 if (BOOT_CURR_IMG(state) == 0) {
2719 SMIF_SET_CRYPTO_MODE(Disable);
2720 }
2721#endif /* MCUBOOT_ENC_IMAGES_XIP_MULTI */
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002722 /* Attempt to read an image header from each slot. */
2723 rc = boot_read_image_headers(state, false, NULL);
INFINEON\DovhalA21babb72025-07-18 10:36:03 +03002724#if defined(MCUBOOT_ENC_IMAGES_XIP_MULTI)
2725 if (BOOT_CURR_IMG(state) == 0) {
2726 SMIF_SET_CRYPTO_MODE(Enable);
2727 }
2728#endif /* MCUBOOT_ENC_IMAGES_XIP_MULTI */
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002729 if (rc != 0) {
2730 BOOT_LOG_WRN("Failed reading image headers.");
2731 return rc;
2732 }
2733
2734 /* Check headers in all slots */
2735 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
2736 hdr = boot_img_hdr(state, slot);
2737
2738 if (boot_is_header_valid(hdr, BOOT_IMG_AREA(state, slot))) {
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002739 state->slot_usage[BOOT_CURR_IMG(state)].slot_available[slot] = true;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002740 BOOT_LOG_IMAGE_INFO(slot, hdr);
2741 } else {
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002742 state->slot_usage[BOOT_CURR_IMG(state)].slot_available[slot] = false;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002743 BOOT_LOG_INF("Image %u %s slot: Image not found",
2744 (unsigned)BOOT_CURR_IMG(state),
2745 (slot == BOOT_PRIMARY_SLOT)
2746 ? "Primary" : "Secondary");
2747 }
2748 }
2749
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002750 state->slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002751 }
2752
2753 return 0;
2754}
2755
2756/**
2757 * Finds the slot containing the image with the highest version number for the
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02002758 * current image. Also dependency check feature verifies version of the first
2759 * slot of dependent image and assumes to load from the first slot. In order to
2760 * avoid conflicts dependency ckeck feature is disabled.
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002761 *
2762 * @param state Boot loader status information.
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002763 *
2764 * @return NO_ACTIVE_SLOT if no available slot found, number of
2765 * the found slot otherwise.
David Vinczee574f2d2020-07-10 11:42:03 +02002766 */
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02002767#if !defined(MCUBOOT_DEPENDENCY_CHECK) && !defined(MCUBOOT_RAM_LOAD)
David Vinczee574f2d2020-07-10 11:42:03 +02002768static uint32_t
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002769find_slot_with_highest_version(struct boot_loader_state *state)
David Vinczee574f2d2020-07-10 11:42:03 +02002770{
David Vinczee574f2d2020-07-10 11:42:03 +02002771 uint32_t slot;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002772 uint32_t candidate_slot = NO_ACTIVE_SLOT;
2773 int rc;
David Vinczee574f2d2020-07-10 11:42:03 +02002774
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002775 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002776 if (state->slot_usage[BOOT_CURR_IMG(state)].slot_available[slot]) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002777 if (candidate_slot == NO_ACTIVE_SLOT) {
2778 candidate_slot = slot;
2779 } else {
2780 rc = boot_version_cmp(
2781 &boot_img_hdr(state, slot)->ih_ver,
2782 &boot_img_hdr(state, candidate_slot)->ih_ver);
2783 if (rc == 1) {
2784 /* The version of the image being examined is greater than
2785 * the version of the current candidate.
2786 */
2787 candidate_slot = slot;
2788 }
2789 }
David Vinczee574f2d2020-07-10 11:42:03 +02002790 }
2791 }
2792
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002793 return candidate_slot;
David Vinczee574f2d2020-07-10 11:42:03 +02002794}
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02002795#endif /* !defined(MCUBOOT_DEPENDENCY_CHECK) && !defined(MCUBOOT_RAM_LOAD) */
David Vinczee574f2d2020-07-10 11:42:03 +02002796
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002797#ifdef MCUBOOT_HAVE_LOGGING
David Vincze505fba22020-10-22 13:53:29 +02002798/**
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002799 * Prints the state of the loaded images.
David Vincze505fba22020-10-22 13:53:29 +02002800 *
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002801 * @param state Boot loader status information.
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002802 */
2803static void
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002804print_loaded_images(struct boot_loader_state *state)
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002805{
2806 uint32_t active_slot;
2807
2808 (void)state;
2809
2810 IMAGES_ITER(BOOT_CURR_IMG(state)) {
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002811#if BOOT_IMAGE_NUMBER > 1
2812 if (state->img_mask[BOOT_CURR_IMG(state)]) {
2813 continue;
2814 }
2815#endif
2816 active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002817
2818 BOOT_LOG_INF("Image %u loaded from the %s slot",
2819 (unsigned)BOOT_CURR_IMG(state),
2820 (active_slot == BOOT_PRIMARY_SLOT) ?
2821 "primary" : "secondary");
2822 }
2823}
2824#endif
2825
2826#if defined(MCUBOOT_DIRECT_XIP) && defined(MCUBOOT_DIRECT_XIP_REVERT)
INFINEON\DovhalA21babb72025-07-18 10:36:03 +03002827static int
2828boot_get_swap_state(struct boot_loader_state *state, uint32_t active_slot, struct boot_swap_state* active_swap_state)
2829{
2830 (void)state;
2831 int rc = -1;
2832
2833 const struct flash_area *fap;
2834 int fa_id;
2835
2836 fa_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), active_slot);
2837 rc = flash_area_open(fa_id, &fap);
2838
2839 if (rc == 0)
2840 {
2841 (void)memset(active_swap_state, 0, sizeof(struct boot_swap_state));
2842
2843 rc = boot_read_swap_state(fap, active_swap_state);
2844 }
2845
2846 return rc;
2847}
2848
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002849/**
2850 * Checks whether the active slot of the current image was previously selected
2851 * to run. Erases the image if it was selected but its execution failed,
2852 * otherwise marks it as selected if it has not been before.
David Vincze505fba22020-10-22 13:53:29 +02002853 *
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002854 * @param state Boot loader status information.
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002855 *
2856 * @return 0 on success; nonzero on failure.
David Vincze505fba22020-10-22 13:53:29 +02002857 */
2858static int
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002859boot_select_or_erase(struct boot_loader_state *state)
David Vincze505fba22020-10-22 13:53:29 +02002860{
2861 const struct flash_area *fap;
2862 int fa_id;
2863 int rc;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002864 uint32_t active_slot;
2865 struct boot_swap_state* active_swap_state;
David Vincze505fba22020-10-22 13:53:29 +02002866
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002867 active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002868
2869 fa_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), active_slot);
David Vincze505fba22020-10-22 13:53:29 +02002870 rc = flash_area_open(fa_id, &fap);
David Vincze505fba22020-10-22 13:53:29 +02002871
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002872 active_swap_state = &(state->slot_usage[BOOT_CURR_IMG(state)].swap_state);
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002873
2874 (void)memset(active_swap_state, 0, sizeof(struct boot_swap_state));
2875 rc = boot_read_swap_state(fap, active_swap_state);
David Vincze505fba22020-10-22 13:53:29 +02002876
INFINEON\DovhalA21babb72025-07-18 10:36:03 +03002877 if ((active_swap_state->copy_done == BOOT_FLAG_SET &&
2878 active_swap_state->image_ok != BOOT_FLAG_SET)) {
David Vincze505fba22020-10-22 13:53:29 +02002879 /*
INFINEON\DovhalA21babb72025-07-18 10:36:03 +03002880 * A reboot happened without the image being confirmed at
2881 * runtime or its trailer is corrupted/invalid. Erase the image
2882 * to prevent it from being selected again on the next reboot.
2883 */
David Vincze505fba22020-10-22 13:53:29 +02002884 BOOT_LOG_DBG("Erasing faulty image in the %s slot.",
INFINEON\DovhalA21babb72025-07-18 10:36:03 +03002885 (active_slot == BOOT_PRIMARY_SLOT) ? "primary" : "secondary");
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002886 rc = flash_area_erase(fap, 0, flash_area_get_size(fap));
David Vincze505fba22020-10-22 13:53:29 +02002887 assert(rc == 0);
2888
David Vincze505fba22020-10-22 13:53:29 +02002889 rc = -1;
2890 } else {
INFINEON\DovhalA21babb72025-07-18 10:36:03 +03002891 struct image_header *hdr = boot_img_hdr(state, active_slot);
2892
2893 if (boot_is_header_valid(hdr, fap))
2894 {
2895 if (active_swap_state->copy_done != BOOT_FLAG_SET) {
2896 if (active_swap_state->copy_done == BOOT_FLAG_BAD) {
2897 BOOT_LOG_DBG("The copy_done flag had an unexpected value. Its "
2898 "value was neither 'set' nor 'unset', but 'bad'.");
2899 }
2900
2901 bool img_ok = (active_swap_state->image_ok == BOOT_FLAG_SET);
2902
2903 uint32_t off = flash_area_get_size(fap) - BOOT_MAX_ALIGN;
2904
2905 flash_area_erase(fap, off, BOOT_MAX_ALIGN);
2906
2907 /*
2908 * Set the copy_done flag, indicating that the image has been
2909 * selected to boot. It can be set in advance, before even
2910 * validating the image, because in case the validation fails, the
2911 * entire image slot will be erased (including the trailer).
2912 */
2913 rc = boot_write_copy_done(fap);
2914
2915 rc |= boot_write_magic(fap);
2916
2917 if (img_ok) {
2918 rc |= boot_write_image_ok(fap);
2919 }
2920
2921 if (rc != 0) {
2922 BOOT_LOG_WRN("Failed to set copy_done flag of the image in "
2923 "the %s slot.", (active_slot == BOOT_PRIMARY_SLOT) ?
2924 "primary" : "secondary");
2925 rc = 0;
2926 }
David Vincze505fba22020-10-22 13:53:29 +02002927 }
2928 }
David Vincze505fba22020-10-22 13:53:29 +02002929 }
INFINEON\DovhalA21babb72025-07-18 10:36:03 +03002930
2931 flash_area_close(fap);
David Vincze505fba22020-10-22 13:53:29 +02002932 return rc;
2933}
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002934#endif /* MCUBOOT_DIRECT_XIP && MCUBOOT_DIRECT_XIP_REVERT */
David Vincze505fba22020-10-22 13:53:29 +02002935
Tamas Banfe031092020-09-10 17:32:39 +02002936#ifdef MCUBOOT_RAM_LOAD
2937
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002938#ifndef MULTIPLE_EXECUTABLE_RAM_REGIONS
Tamas Banfe031092020-09-10 17:32:39 +02002939#if !defined(IMAGE_EXECUTABLE_RAM_START) || !defined(IMAGE_EXECUTABLE_RAM_SIZE)
2940#error "Platform MUST define executable RAM bounds in case of RAM_LOAD"
2941#endif
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002942#endif
Tamas Banfe031092020-09-10 17:32:39 +02002943
2944/**
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002945 * Verifies that the active slot of the current image can be loaded within the
2946 * predefined bounds that are allowed to be used by executable images.
Tamas Banfe031092020-09-10 17:32:39 +02002947 *
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002948 * @param state Boot loader status information.
Tamas Banfe031092020-09-10 17:32:39 +02002949 *
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002950 * @return 0 on success; nonzero on failure.
Tamas Banfe031092020-09-10 17:32:39 +02002951 */
2952static int
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002953boot_verify_ram_load_address(struct boot_loader_state *state)
Tamas Banfe031092020-09-10 17:32:39 +02002954{
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002955 uint32_t img_dst;
2956 uint32_t img_sz;
Tamas Banfe031092020-09-10 17:32:39 +02002957 uint32_t img_end_addr;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002958 uint32_t exec_ram_start;
2959 uint32_t exec_ram_size;
Tamas Banfe031092020-09-10 17:32:39 +02002960
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002961 (void)state;
2962
2963#ifdef MULTIPLE_EXECUTABLE_RAM_REGIONS
2964 int rc;
2965
2966 rc = boot_get_image_exec_ram_info(BOOT_CURR_IMG(state), &exec_ram_start,
2967 &exec_ram_size);
2968 if (rc != 0) {
2969 return BOOT_EBADSTATUS;
2970 }
2971#else
2972 exec_ram_start = IMAGE_EXECUTABLE_RAM_START;
2973 exec_ram_size = IMAGE_EXECUTABLE_RAM_SIZE;
2974#endif
2975
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002976 img_dst = state->slot_usage[BOOT_CURR_IMG(state)].img_dst;
2977 img_sz = state->slot_usage[BOOT_CURR_IMG(state)].img_sz;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002978
2979 if (img_dst < exec_ram_start) {
Tamas Banfe031092020-09-10 17:32:39 +02002980 return BOOT_EBADIMAGE;
2981 }
2982
2983 if (!boot_u32_safe_add(&img_end_addr, img_dst, img_sz)) {
2984 return BOOT_EBADIMAGE;
2985 }
2986
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002987 if (img_end_addr > (exec_ram_start + exec_ram_size)) {
Tamas Banfe031092020-09-10 17:32:39 +02002988 return BOOT_EBADIMAGE;
2989 }
2990
2991 return 0;
2992}
2993
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002994#ifdef MCUBOOT_ENC_IMAGES
2995
Tamas Banfe031092020-09-10 17:32:39 +02002996/**
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002997 * Copies and decrypts an image from a slot in the flash to an SRAM address.
Tamas Banfe031092020-09-10 17:32:39 +02002998 *
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002999 * @param state Boot loader status information.
3000 * @param slot The flash slot of the image to be copied to SRAM.
3001 * @param hdr The image header.
3002 * @param src_sz Size of the image.
3003 * @param img_dst Pointer to the address at which the image needs to be
3004 * copied to SRAM.
3005 *
3006 * @return 0 on success; nonzero on failure.
3007 */
3008static int
3009boot_decrypt_and_copy_image_to_sram(struct boot_loader_state *state,
3010 uint32_t slot, struct image_header *hdr,
3011 uint32_t src_sz, uint32_t img_dst)
3012{
3013 /* The flow for the decryption and copy of the image is as follows :
3014 * 1. The whole image is copied to the RAM (header + payload + TLV).
3015 * 2. The encryption key is loaded from the TLV in flash.
3016 * 3. The image is then decrypted chunk by chunk in RAM (1 chunk
3017 * is 1024 bytes). Only the payload section is decrypted.
3018 * 4. The image is authenticated in RAM.
3019 */
3020 const struct flash_area *fap_src = NULL;
INFINEON\DovhalA21babb72025-07-18 10:36:03 +03003021 uint32_t tlv_off;
3022 int area_id;
3023 int rc;
3024 uint8_t image_index;
3025 uint8_t * ram_dst = (void *)(IMAGE_RAM_BASE + img_dst);
3026#if !defined(MCUBOOT_ENC_IMAGES_XIP_MULTI)
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003027 struct boot_status bs;
3028 uint32_t blk_off;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003029 uint32_t blk_sz;
3030 uint32_t bytes_copied = hdr->ih_hdr_size;
3031 uint32_t chunk_sz;
3032 uint32_t max_sz = 1024;
3033 uint16_t idx;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003034 uint8_t * cur_dst;
INFINEON\DovhalA21babb72025-07-18 10:36:03 +03003035#endif /* MCUBOOT_ENC_IMAGES_XIP_MULTI */
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003036
3037 image_index = BOOT_CURR_IMG(state);
3038 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
3039 rc = flash_area_open(area_id, &fap_src);
3040 if (rc != 0){
3041 return BOOT_EFLASH;
3042 }
3043
3044 tlv_off = BOOT_TLV_OFF(hdr);
3045
3046 /* Copying the whole image in RAM */
3047 rc = flash_area_read(fap_src, 0, ram_dst, src_sz);
3048 if (rc != 0) {
3049 goto done;
3050 }
INFINEON\DovhalA21babb72025-07-18 10:36:03 +03003051#if !defined(MCUBOOT_ENC_IMAGES_XIP_MULTI)
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003052 rc = boot_enc_load(BOOT_CURR_ENC(state), image_index, hdr, fap_src, &bs);
3053 if (rc < 0) {
3054 goto done;
3055 }
3056
3057 /* if rc > 0 then the key has already been loaded */
3058 if (rc == 0 && boot_enc_set_key(BOOT_CURR_ENC(state), slot, &bs)) {
3059 goto done;
3060 }
3061
3062 /* Starting at the end of the header as the header section is not encrypted */
3063 while (bytes_copied < tlv_off) { /* TLV section copied previously */
3064 if (src_sz - bytes_copied > max_sz) {
3065 chunk_sz = max_sz;
3066 } else {
3067 chunk_sz = src_sz - bytes_copied;
3068 }
3069
3070 cur_dst = ram_dst + bytes_copied;
3071 blk_sz = chunk_sz;
3072 idx = 0;
3073 if (bytes_copied + chunk_sz > tlv_off) {
3074 /* Going over TLV section
3075 * Part of the chunk is encrypted payload */
3076 blk_off = ((bytes_copied) - hdr->ih_hdr_size) & 0xf;
3077 blk_sz = tlv_off - (bytes_copied);
3078 boot_encrypt(BOOT_CURR_ENC(state), image_index, fap_src,
3079 (bytes_copied + idx) - hdr->ih_hdr_size, blk_sz,
3080 blk_off, cur_dst);
3081 } else {
3082 /* Image encrypted payload section */
3083 blk_off = ((bytes_copied) - hdr->ih_hdr_size) & 0xf;
3084 boot_encrypt(BOOT_CURR_ENC(state), image_index, fap_src,
3085 (bytes_copied + idx) - hdr->ih_hdr_size, blk_sz,
3086 blk_off, cur_dst);
3087 }
3088
3089 bytes_copied += chunk_sz;
3090 }
INFINEON\DovhalA21babb72025-07-18 10:36:03 +03003091#else
3092 (void)image_index;
3093 /* Special case for the first image because header and TLV are not encrypted */
3094 SMIF_CRYPTO_SECTION(Disable) {
3095 /* Copy header to RAM */
3096 rc = flash_area_read(fap_src, 0, ram_dst, hdr->ih_hdr_size);
3097 }
3098 if (0 != rc) {
3099 goto done;
3100 }
3101
3102 SMIF_CRYPTO_SECTION(Disable) {
3103 /* Copy TLV ro RAM */
3104 rc = flash_area_read(fap_src, tlv_off, ram_dst + tlv_off, src_sz - tlv_off);
3105 }
3106 if (0 != rc) {
3107 goto done;
3108 }
3109#endif /* !defined(MCUBOOT_ENC_IMAGES_XIP_MULTI) */
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003110 rc = 0;
3111
3112done:
3113 flash_area_close(fap_src);
3114
3115 return rc;
3116}
3117
3118#endif /* MCUBOOT_ENC_IMAGES */
3119/**
3120 * Copies a slot of the current image into SRAM.
3121 *
3122 * @param state Boot loader status information.
Tamas Banfe031092020-09-10 17:32:39 +02003123 * @param slot The flash slot of the image to be copied to SRAM.
3124 * @param img_dst The address at which the image needs to be copied to
3125 * SRAM.
3126 * @param img_sz The size of the image that needs to be copied to SRAM.
3127 *
3128 * @return 0 on success; nonzero on failure.
3129 */
3130static int
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003131boot_copy_image_to_sram(struct boot_loader_state *state, int slot,
3132 uint32_t img_dst, uint32_t img_sz)
Tamas Banfe031092020-09-10 17:32:39 +02003133{
3134 int rc;
3135 const struct flash_area *fap_src = NULL;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003136 int area_id;
Tamas Banfe031092020-09-10 17:32:39 +02003137
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003138#if (BOOT_IMAGE_NUMBER == 1)
3139 (void)state;
3140#endif
3141
3142 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
3143
3144 rc = flash_area_open(area_id, &fap_src);
Tamas Banfe031092020-09-10 17:32:39 +02003145 if (rc != 0) {
3146 return BOOT_EFLASH;
3147 }
3148
3149 /* Direct copy from flash to its new location in SRAM. */
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003150 rc = flash_area_read(fap_src, 0, (void *)(IMAGE_RAM_BASE + img_dst), img_sz);
Tamas Banfe031092020-09-10 17:32:39 +02003151 if (rc != 0) {
3152 BOOT_LOG_INF("Error whilst copying image from Flash to SRAM: %d", rc);
3153 }
3154
3155 flash_area_close(fap_src);
3156
3157 return rc;
3158}
3159
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003160#if (BOOT_IMAGE_NUMBER > 1)
Tamas Banfe031092020-09-10 17:32:39 +02003161/**
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003162 * Checks if two memory regions (A and B) are overlap or not.
Tamas Banfe031092020-09-10 17:32:39 +02003163 *
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003164 * @param start_a Start of the A region.
3165 * @param end_a End of the A region.
3166 * @param start_b Start of the B region.
3167 * @param end_b End of the B region.
Tamas Banfe031092020-09-10 17:32:39 +02003168 *
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003169 * @return true if there is overlap; false otherwise.
3170 */
3171static bool
3172do_regions_overlap(uint32_t start_a, uint32_t end_a,
3173 uint32_t start_b, uint32_t end_b)
3174{
3175 if (start_b > end_a) {
3176 return false;
3177 } else if (start_b >= start_a) {
3178 return true;
3179 } else if (end_b > start_a) {
3180 return true;
3181 }
3182
3183 return false;
3184}
3185
3186/**
3187 * Checks if the image we want to load to memory overlap with an already
3188 * ramloaded image.
3189 *
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003190 * @param state Boot loader status information.
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003191 *
3192 * @return 0 if there is no overlap; nonzero otherwise.
Tamas Banfe031092020-09-10 17:32:39 +02003193 */
3194static int
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003195boot_check_ram_load_overlapping(struct boot_loader_state *state)
Tamas Banfe031092020-09-10 17:32:39 +02003196{
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003197 uint32_t i;
3198
3199 uint32_t start_a;
3200 uint32_t end_a;
3201 uint32_t start_b;
3202 uint32_t end_b;
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003203 uint32_t image_id_to_check = BOOT_CURR_IMG(state);
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003204
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003205 start_a = state->slot_usage[image_id_to_check].img_dst;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003206 /* Safe to add here, values are already verified in
3207 * boot_verify_ram_load_address() */
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003208 end_a = start_a + state->slot_usage[image_id_to_check].img_sz;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003209
3210 for (i = 0; i < BOOT_IMAGE_NUMBER; i++) {
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003211 if (state->slot_usage[i].active_slot == NO_ACTIVE_SLOT
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003212 || i == image_id_to_check) {
3213 continue;
3214 }
3215
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003216 start_b = state->slot_usage[i].img_dst;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003217 /* Safe to add here, values are already verified in
3218 * boot_verify_ram_load_address() */
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003219 end_b = start_b + state->slot_usage[i].img_sz;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003220
3221 if (do_regions_overlap(start_a, end_a, start_b, end_b)) {
3222 return -1;
3223 }
3224 }
3225
3226 return 0;
3227}
3228#endif
3229
3230/**
3231 * Loads the active slot of the current image into SRAM. The load address and
3232 * image size is extracted from the image header.
3233 *
3234 * @param state Boot loader status information.
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003235 *
3236 * @return 0 on success; nonzero on failure.
3237 */
3238static int
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003239boot_load_image_to_sram(struct boot_loader_state *state)
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003240{
3241 uint32_t active_slot;
3242 struct image_header *hdr = NULL;
3243 uint32_t img_dst;
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02003244 uint32_t img_sz = 0;
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003245 int rc = 0;
Tamas Banfe031092020-09-10 17:32:39 +02003246
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003247 active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003248 hdr = boot_img_hdr(state, active_slot);
3249
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003250 if (IS_RAM_BOOTABLE(hdr)) {
Tamas Banfe031092020-09-10 17:32:39 +02003251
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003252 img_dst = hdr->ih_load_addr;
Tamas Banfe031092020-09-10 17:32:39 +02003253
INFINEON\DovhalA21babb72025-07-18 10:36:03 +03003254#if defined(MCUBOOT_ENC_IMAGES_XIP_MULTI)
3255 if (BOOT_CURR_IMG(state) == 0) {
3256 SMIF_SET_CRYPTO_MODE(Disable);
3257 }
3258#endif /* MCUBOOT_ENC_IMAGES_XIP_MULTI */
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003259 rc = boot_read_image_size(state, active_slot, &img_sz);
INFINEON\DovhalA21babb72025-07-18 10:36:03 +03003260#if defined(MCUBOOT_ENC_IMAGES_XIP_MULTI)
3261 if (BOOT_CURR_IMG(state) == 0) {
3262 SMIF_SET_CRYPTO_MODE(Enable);
3263 }
3264#endif /* MCUBOOT_ENC_IMAGES_XIP_MULTI */
Tamas Banfe031092020-09-10 17:32:39 +02003265 if (rc != 0) {
3266 return rc;
3267 }
3268
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003269 state->slot_usage[BOOT_CURR_IMG(state)].img_dst = img_dst;
3270 state->slot_usage[BOOT_CURR_IMG(state)].img_sz = img_sz;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003271
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003272 rc = boot_verify_ram_load_address(state);
Tamas Banfe031092020-09-10 17:32:39 +02003273 if (rc != 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003274 BOOT_LOG_INF("Image RAM load address 0x%" PRIx32 " is invalid.", img_dst);
Tamas Banfe031092020-09-10 17:32:39 +02003275 return rc;
3276 }
3277
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003278#if (BOOT_IMAGE_NUMBER > 1)
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003279 rc = boot_check_ram_load_overlapping(state);
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003280 if (rc != 0) {
3281 BOOT_LOG_INF("Image RAM loading to address 0x%" PRIx32
3282 " would overlap with another image.", img_dst);
3283 return rc;
3284 }
3285#endif
3286#ifdef MCUBOOT_ENC_IMAGES
3287 /* decrypt image if encrypted and copy it to RAM */
3288 if (IS_ENCRYPTED(hdr)) {
3289 rc = boot_decrypt_and_copy_image_to_sram(state, active_slot, hdr, img_sz, img_dst);
3290 } else {
3291 rc = boot_copy_image_to_sram(state, active_slot, img_dst, img_sz);
3292 }
3293#else
Tamas Banfe031092020-09-10 17:32:39 +02003294 /* Copy image to the load address from where it currently resides in
3295 * flash.
3296 */
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003297 rc = boot_copy_image_to_sram(state, active_slot, img_dst, img_sz);
3298#endif
Tamas Banfe031092020-09-10 17:32:39 +02003299 if (rc != 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003300 BOOT_LOG_INF("RAM loading to 0x%" PRIx32 " is failed.", img_dst);
Tamas Banfe031092020-09-10 17:32:39 +02003301 } else {
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003302 BOOT_LOG_INF("RAM loading to 0x%" PRIx32 " is succeeded.", img_dst);
Tamas Banfe031092020-09-10 17:32:39 +02003303 }
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003304 }
3305 else {
Tamas Banfe031092020-09-10 17:32:39 +02003306 /* Only images that support IMAGE_F_RAM_LOAD are allowed if
3307 * MCUBOOT_RAM_LOAD is set.
3308 */
3309 rc = BOOT_EBADIMAGE;
3310 }
3311
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003312 if (rc != 0) {
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003313 state->slot_usage[BOOT_CURR_IMG(state)].img_dst = 0;
3314 state->slot_usage[BOOT_CURR_IMG(state)].img_sz = 0;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003315 }
3316
Tamas Banfe031092020-09-10 17:32:39 +02003317 return rc;
3318}
3319
3320/**
3321 * Removes an image from SRAM, by overwriting it with zeros.
3322 *
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003323 * @param state Boot loader status information.
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003324 *
3325 * @return 0 on success; nonzero on failure.
3326 */
3327static inline int
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003328boot_remove_image_from_sram(struct boot_loader_state *state)
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003329{
3330 (void)state;
3331
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003332 BOOT_LOG_INF("Removing image from SRAM at address 0x%x",
3333 state->slot_usage[BOOT_CURR_IMG(state)].img_dst);
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003334
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003335 (void)memset((void*)(IMAGE_RAM_BASE + state->slot_usage[BOOT_CURR_IMG(state)].img_dst),
3336 0, state->slot_usage[BOOT_CURR_IMG(state)].img_sz);
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003337
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003338 state->slot_usage[BOOT_CURR_IMG(state)].img_dst = 0;
3339 state->slot_usage[BOOT_CURR_IMG(state)].img_sz = 0;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003340
3341 return 0;
3342}
3343
3344/**
3345 * Removes an image from flash by erasing the corresponding flash area
3346 *
3347 * @param state Boot loader status information.
3348 * @param slot The flash slot of the image to be erased.
Tamas Banfe031092020-09-10 17:32:39 +02003349 *
3350 * @return 0 on success; nonzero on failure.
3351 */
3352static inline int
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003353boot_remove_image_from_flash(struct boot_loader_state *state, uint32_t slot)
Tamas Banfe031092020-09-10 17:32:39 +02003354{
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003355 int area_id;
3356 int rc;
3357 const struct flash_area *fap;
Tamas Banfe031092020-09-10 17:32:39 +02003358
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003359 (void)state;
3360
3361 BOOT_LOG_INF("Removing image %u slot %" PRIu32 " from flash",
3362 (unsigned)BOOT_CURR_IMG(state), slot);
3363 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
3364 rc = flash_area_open(area_id, &fap);
3365 if (rc == 0) {
3366 flash_area_erase(fap, 0, flash_area_get_size(fap));
3367 }
3368
3369 return rc;
Tamas Banfe031092020-09-10 17:32:39 +02003370}
INFINEON\DovhalA21babb72025-07-18 10:36:03 +03003371
3372/**
3373 * Switch to image in SRAM
3374 *
3375 * @param state Boot loader status information.
3376 * @param slot The flash slot of the image to be erased.
3377 *
3378 * @return 0 on success; nonzero on failure.
3379 */
3380static inline int
3381boot_switch_to_sram_image(struct boot_loader_state *state, uint32_t slot)
3382{
3383 int area_id = -1;
3384 int rc = -1;
3385 struct flash_area *fap = NULL;
3386 struct image_header *hdr = NULL;
3387
3388 (void)state;
3389
3390 hdr = boot_img_hdr(state, slot);
3391 BOOT_LOG_INF("Image %u slot %" PRIu32 " switch to SRAM",
3392 (unsigned)BOOT_CURR_IMG(state), slot);
3393 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
3394 rc = flash_area_open(area_id, (const struct flash_area **)&fap);
3395
3396 if (rc == 0) {
3397 /* Switch to image SRAM */
3398
3399 if (IS_RAM_BOOTABLE_SECURE(hdr)) {
3400 fap->fa_device_id = INTERNAL_S_SRAM;
3401 }
3402 else {
3403 fap->fa_device_id = INTERNAL_NS_SRAM;
3404 }
3405
3406 if (hdr->ih_load_addr < flash_devices[fap->fa_device_id].address) {
3407 return -1;
3408 }
3409 fap->fa_off = hdr->ih_load_addr - flash_devices[fap->fa_device_id].address;
3410 /* Image is already decrepted, so clear encrypted flags in the header */
3411 CLEAR_ENCRYPT_FLAGS(hdr);
3412 }
3413
3414 return rc;
3415}
Tamas Banfe031092020-09-10 17:32:39 +02003416#endif /* MCUBOOT_RAM_LOAD */
3417
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003418#if (BOOT_IMAGE_NUMBER > 1)
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02003419#if defined(MCUBOOT_DEPENDENCY_CHECK)
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003420/**
3421 * Checks the image dependency whether it is satisfied.
3422 *
3423 * @param state Boot loader status information.
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003424 * @param dep Image dependency which has to be verified.
3425 *
3426 * @return 0 if dependencies are met; nonzero otherwise.
3427 */
3428static int
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003429boot_verify_slot_dependency_ram(struct boot_loader_state *state,
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003430 struct image_dependency *dep)
David Vinczee574f2d2020-07-10 11:42:03 +02003431{
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003432 struct image_version *dep_version;
3433 uint32_t dep_slot;
David Vinczee574f2d2020-07-10 11:42:03 +02003434 int rc;
3435
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003436 /* Determine the source of the image which is the subject of
3437 * the dependency and get it's version.
David Vinczee574f2d2020-07-10 11:42:03 +02003438 */
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003439 dep_slot = state->slot_usage[dep->image_id].active_slot;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003440 dep_version = &state->imgs[dep->image_id][dep_slot].hdr.ih_ver;
3441
3442 rc = boot_version_cmp(dep_version, &dep->image_min_version);
3443 if (rc >= 0) {
3444 /* Dependency satisfied. */
3445 rc = 0;
David Vinczee574f2d2020-07-10 11:42:03 +02003446 }
3447
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003448 return rc;
3449}
3450
3451/**
3452 * Reads all dependency TLVs of an image and verifies one after another to see
3453 * if they are all satisfied.
3454 *
3455 * @param state Boot loader status information.
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003456 *
3457 * @return 0 if dependencies are met; nonzero otherwise.
3458 */
3459static int
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003460boot_verify_slot_dependencies_ram(struct boot_loader_state *state)
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003461{
3462 uint32_t active_slot;
3463 const struct flash_area *fap;
3464 struct image_tlv_iter it;
3465 struct image_dependency dep;
3466 uint32_t off;
3467 uint16_t len;
3468 int area_id;
3469 int rc;
3470
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003471 active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003472
3473 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state),
3474 active_slot);
3475 rc = flash_area_open(area_id, &fap);
David Vinczee574f2d2020-07-10 11:42:03 +02003476 if (rc != 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003477 rc = BOOT_EFLASH;
3478 goto done;
David Vinczee574f2d2020-07-10 11:42:03 +02003479 }
3480
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003481 rc = bootutil_tlv_iter_begin(&it, boot_img_hdr(state, active_slot), fap,
3482 IMAGE_TLV_DEPENDENCY, true);
3483 if (rc != 0) {
3484 goto done;
3485 }
David Vinczee574f2d2020-07-10 11:42:03 +02003486
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003487 while (true) {
3488 rc = bootutil_tlv_iter_next(&it, &off, &len, NULL);
3489 if (rc < 0) {
3490 return -1;
3491 } else if (rc > 0) {
3492 rc = 0;
3493 break;
3494 }
David Vinczee574f2d2020-07-10 11:42:03 +02003495
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003496 if (len != sizeof(dep)) {
3497 rc = BOOT_EBADIMAGE;
3498 goto done;
3499 }
3500
3501 rc = LOAD_IMAGE_DATA(boot_img_hdr(state, active_slot),
3502 fap, off, &dep, len);
3503 if (rc != 0) {
3504 rc = BOOT_EFLASH;
3505 goto done;
3506 }
3507
3508 if (dep.image_id >= BOOT_IMAGE_NUMBER) {
3509 rc = BOOT_EBADARGS;
3510 goto done;
3511 }
3512
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003513 rc = boot_verify_slot_dependency_ram(state, &dep);
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003514 if (rc != 0) {
3515 /* Dependency not satisfied. */
3516 goto done;
3517 }
3518 }
3519
3520done:
3521 flash_area_close(fap);
3522 return rc;
3523}
3524
3525/**
3526 * Checks the dependency of all the active slots. If an image found with
3527 * invalid or not satisfied dependencies the image is removed from SRAM (in
3528 * case of MCUBOOT_RAM_LOAD strategy) and its slot is set to unavailable.
3529 *
3530 * @param state Boot loader status information.
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003531 *
3532 * @return 0 if dependencies are met; nonzero otherwise.
3533 */
3534static int
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003535boot_verify_dependencies_ram(struct boot_loader_state *state)
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003536{
3537 int rc = -1;
3538 uint32_t active_slot;
3539
3540 IMAGES_ITER(BOOT_CURR_IMG(state)) {
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003541 if (state->img_mask[BOOT_CURR_IMG(state)]) {
3542 continue;
3543 }
3544 rc = boot_verify_slot_dependencies_ram(state);
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003545 if (rc != 0) {
3546 /* Dependencies not met or invalid dependencies. */
3547
3548#ifdef MCUBOOT_RAM_LOAD
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003549 boot_remove_image_from_sram(state);
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003550#endif /* MCUBOOT_RAM_LOAD */
3551
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003552 active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot;
3553 state->slot_usage[BOOT_CURR_IMG(state)].slot_available[active_slot] = false;
3554 state->slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003555
3556 return rc;
3557 }
3558 }
3559
3560 return rc;
3561}
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02003562#endif /* (MCUBOOT_DEPENDENCY_CHECK) */
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003563#endif /* (BOOT_IMAGE_NUMBER > 1) */
3564
INFINEON\DovhalA21babb72025-07-18 10:36:03 +03003565static const uint8_t slot_table[] = {BOOT_PRIMARY_SLOT, BOOT_SECONDARY_SLOT};
3566
3567/**
3568 * Tries to load a slot for all the images with validation.
3569 *
3570 * @param state Boot loader status information.
3571 *
3572 * @return 0 on success; nonzero on failure.
3573 */
3574fih_int
3575boot_load_and_validate_images_xip(struct boot_loader_state *state)
3576{
3577 uint32_t active_slot = NO_ACTIVE_SLOT;
3578 int rc = -1;
3579 fih_int fih_rc = FIH_FAILURE;
3580
3581 struct boot_swap_state swap_state[BOOT_NUM_SLOTS];
3582
3583 /* Go over all the images and try to load one */
3584 IMAGES_ITER(BOOT_CURR_IMG(state))
3585 {
3586#if BOOT_IMAGE_NUMBER > 1
3587 if (state->img_mask[BOOT_CURR_IMG(state)]) {
3588 continue;
3589 }
3590#endif
3591
3592 for (uint32_t i = 0; i < BOOT_NUM_SLOTS; i++) {
3593 active_slot = slot_table[i];
3594
3595 /* Save the number of the active slot. */
3596 state->slot_usage[BOOT_CURR_IMG(state)].active_slot = active_slot;
3597
3598 rc = boot_rom_address_check(state);
3599 if (rc != 0) {
3600 /* The image is placed in an unsuitable slot. */
3601 state->slot_usage[BOOT_CURR_IMG(state)].slot_available[active_slot] = false;
3602 state->slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT;
3603 continue;
3604 }
3605
3606
3607 rc = boot_get_swap_state(state, active_slot, &swap_state[i]);
3608
3609 if (rc == 0) {
3610 /* Proceed with inactive state */
3611 if (swap_state[i].image_inactive == BOOT_FLAG_SET) {
3612 state->slot_usage[BOOT_CURR_IMG(state)].slot_available[active_slot] = false;
3613 state->slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT;
3614
3615
3616 if (swap_state[i].copy_done == BOOT_FLAG_SET && swap_state[i].image_ok == BOOT_FLAG_SET)
3617 {
3618 state->slot_usage[BOOT_CURR_IMG(state)].slot_validated[active_slot] = true;
3619 }
3620 else
3621 {
3622 FIH_CALL(boot_validate_slot, fih_rc, state, active_slot, NULL);
3623 if (fih_eq(fih_rc, FIH_SUCCESS)) {
3624 state->slot_usage[BOOT_CURR_IMG(state)].slot_validated[active_slot] = true;
3625 }
3626 }
3627 continue;
3628
3629 } else {
3630 /* Proceed with revert state */
3631 if (boot_select_or_erase(state) != 0) {
3632 /* The selected image slot has been erased. */
3633 state->slot_usage[BOOT_CURR_IMG(state)].slot_available[active_slot] = false;
3634 state->slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT;
3635 continue;
3636 }
3637 }
3638 }
3639 }
3640
3641 active_slot = NO_ACTIVE_SLOT;
3642
3643 for (int i = 0; i < BOOT_NUM_SLOTS; i++) {
3644 if (state->slot_usage[BOOT_CURR_IMG(state)].slot_available[i] == true) {
3645 if (swap_state[i].copy_done == BOOT_FLAG_UNSET)
3646 {
3647 active_slot = i;
3648 break;
3649 }
3650 }
3651 }
3652
3653 if (active_slot == NO_ACTIVE_SLOT)
3654 {
3655 active_slot = find_slot_with_highest_version(state);
3656 }
3657
3658 if (active_slot != NO_ACTIVE_SLOT)
3659 {
3660 #ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT
3661 FIH_CALL(boot_validate_slot, fih_rc, state, active_slot, NULL);
3662 #else
3663 fih_rc = FIH_SUCCESS;
3664 #endif
3665
3666 if (fih_eq(fih_rc, FIH_SUCCESS)) {
3667 state->slot_usage[BOOT_CURR_IMG(state)].slot_validated[active_slot] = true;
3668 state->slot_usage[BOOT_CURR_IMG(state)].active_slot = active_slot;
3669 }
3670 }
3671 else
3672 {
3673 bool dead_state = true;
3674 for (int i = 0; i < BOOT_NUM_SLOTS; i++) {
3675 if (state->slot_usage[BOOT_CURR_IMG(state)].slot_available[i] == false) {
3676 dead_state = false;
3677 break;
3678 }
3679 }
3680
3681 if (dead_state == false) {
3682 for (int i = 0; i < BOOT_NUM_SLOTS; i++) {
3683 if (state->slot_usage[BOOT_CURR_IMG(state)].slot_validated[i] == true) {
3684 state->slot_usage[BOOT_CURR_IMG(state)].slot_available[i] = true;
3685 state->slot_usage[BOOT_CURR_IMG(state)].active_slot = i;
3686
3687 fih_rc = FIH_SUCCESS;
3688
3689 break;
3690 }
3691 }
3692 }
3693 }
3694 }
3695
3696
3697 FIH_RET(fih_rc);
3698}
3699
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003700/**
3701 * Tries to load a slot for all the images with validation.
3702 *
3703 * @param state Boot loader status information.
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003704 *
3705 * @return 0 on success; nonzero on failure.
3706 */
3707fih_int
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003708boot_load_and_validate_images(struct boot_loader_state *state)
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003709{
3710 uint32_t active_slot;
3711 int rc;
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +02003712 fih_int fih_rc = FIH_FAILURE;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003713
3714 /* Go over all the images and try to load one */
3715 IMAGES_ITER(BOOT_CURR_IMG(state)) {
3716 /* All slots tried until a valid image found. Breaking from this loop
3717 * means that a valid image found or already loaded. If no slot is
3718 * found the function returns with error code. */
3719 while (true) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003720 /* Go over all the slots and try to load one */
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003721 active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003722 if (active_slot != NO_ACTIVE_SLOT){
3723 /* A slot is already active, go to next image. */
3724 break;
3725 }
INFINEON\DovhalA21babb72025-07-18 10:36:03 +03003726
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02003727 /* Ram load assumes to find the highest version of available slots
3728 * and load it. Also dependency check feature verifies version
3729 * of first slot of dependent image and assumes to load from the
3730 * first slot. So logic is separated into two cases to avoid conflicts,
3731 * where the first is when dependency check is disabled,
3732 * and the second is when it is enabled.
3733 * Notation: to avoid situations when reverted image with higher version is
3734 * ram-loaded, the current logic is changed to loading 'BOOT_PRIMARY_SLOT'
3735 * on a constant basis.
3736 * */
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003737
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02003738#if !defined(MCUBOOT_DEPENDENCY_CHECK) && !defined(MCUBOOT_RAM_LOAD)
3739 /* Go over all slots and find the highest version. */
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003740 active_slot = find_slot_with_highest_version(state);
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02003741#else
3742 /* Dependecy check feature assumes to load from the first slot */
3743 active_slot = BOOT_PRIMARY_SLOT;
3744#endif
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003745 if (active_slot == NO_ACTIVE_SLOT) {
3746 BOOT_LOG_INF("No slot to load for image %u",
3747 (unsigned)BOOT_CURR_IMG(state));
3748 FIH_RET(FIH_FAILURE);
3749 }
3750
3751 /* Save the number of the active slot. */
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003752 state->slot_usage[BOOT_CURR_IMG(state)].active_slot = active_slot;
3753
3754#if BOOT_IMAGE_NUMBER > 1
3755 if (state->img_mask[BOOT_CURR_IMG(state)]) {
3756 continue;
3757 }
3758#endif
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003759
3760#ifdef MCUBOOT_DIRECT_XIP
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003761 rc = boot_rom_address_check(state);
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003762 if (rc != 0) {
3763 /* The image is placed in an unsuitable slot. */
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003764 state->slot_usage[BOOT_CURR_IMG(state)].slot_available[active_slot] = false;
3765 state->slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003766 continue;
David Vinczee574f2d2020-07-10 11:42:03 +02003767 }
David Vincze505fba22020-10-22 13:53:29 +02003768
3769#ifdef MCUBOOT_DIRECT_XIP_REVERT
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003770 rc = boot_select_or_erase(state);
David Vincze505fba22020-10-22 13:53:29 +02003771 if (rc != 0) {
3772 /* The selected image slot has been erased. */
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003773 state->slot_usage[BOOT_CURR_IMG(state)].slot_available[active_slot] = false;
3774 state->slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT;
INFINEON\DovhalA21babb72025-07-18 10:36:03 +03003775
3776 FIH_CALL(boot_validate_slot, fih_rc, state, active_slot, NULL);
3777 if (fih_eq(fih_rc, FIH_SUCCESS)) {
3778 state->slot_usage[BOOT_CURR_IMG(state)].slot_validated[active_slot] = true;
3779 }
3780
David Vincze505fba22020-10-22 13:53:29 +02003781 continue;
3782 }
3783#endif /* MCUBOOT_DIRECT_XIP_REVERT */
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003784#endif /* MCUBOOT_DIRECT_XIP */
David Vincze505fba22020-10-22 13:53:29 +02003785
Tamas Banfe031092020-09-10 17:32:39 +02003786#ifdef MCUBOOT_RAM_LOAD
3787 /* Image is first loaded to RAM and authenticated there in order to
3788 * prevent TOCTOU attack during image copy. This could be applied
3789 * when loading images from external (untrusted) flash to internal
3790 * (trusted) RAM and image is authenticated before copying.
3791 */
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003792 rc = boot_load_image_to_sram(state);
Tamas Banfe031092020-09-10 17:32:39 +02003793 if (rc != 0 ) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003794 /* Image cannot be ramloaded. */
3795 boot_remove_image_from_flash(state, active_slot);
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003796 state->slot_usage[BOOT_CURR_IMG(state)].slot_available[active_slot] = false;
3797 state->slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT;
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02003798 /* Since active_slot is set BOOT_PRIMARY_SLOT only, then after its deletion
3799 * no sense to check BOOT_SECONDARY_SLOT. So go outside with an error */
3800 BOOT_LOG_ERR("BOOT slot of image %u has been removed from flash",
3801 (unsigned)BOOT_CURR_IMG(state));
3802 FIH_RET(FIH_FAILURE);
Tamas Banfe031092020-09-10 17:32:39 +02003803 }
INFINEON\DovhalA21babb72025-07-18 10:36:03 +03003804
3805 if (boot_switch_to_sram_image(state, active_slot) != 0) {
3806 FIH_RET(FIH_FAILURE);
3807 }
Tamas Banfe031092020-09-10 17:32:39 +02003808#endif /* MCUBOOT_RAM_LOAD */
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +02003809#ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003810 FIH_CALL(boot_validate_slot, fih_rc, state, active_slot, NULL);
INFINEON\DovhalA21babb72025-07-18 10:36:03 +03003811
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02003812 if (!fih_eq(fih_rc, FIH_SUCCESS)) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003813 /* Image is invalid. */
Tamas Banfe031092020-09-10 17:32:39 +02003814#ifdef MCUBOOT_RAM_LOAD
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003815 boot_remove_image_from_sram(state);
Tamas Banfe031092020-09-10 17:32:39 +02003816#endif /* MCUBOOT_RAM_LOAD */
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003817 state->slot_usage[BOOT_CURR_IMG(state)].slot_available[active_slot] = false;
3818 state->slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT;
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02003819 /* Since active_slot is set BOOT_PRIMARY_SLOT only, then after its deletion
3820 * no sense to check BOOT_SECONDARY_SLOT. So go outside with an error */
3821 BOOT_LOG_ERR("BOOT slot of image %u has been removed from SRAM",
INFINEON\DovhalA21babb72025-07-18 10:36:03 +03003822 (unsigned)BOOT_CURR_IMG(state));
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02003823 FIH_RET(FIH_FAILURE);
David Vincze505fba22020-10-22 13:53:29 +02003824 }
INFINEON\DovhalA21babb72025-07-18 10:36:03 +03003825#endif /* MCUBOOT_VALIDATE_PRIMARY_SLOT */
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003826 /* Valid image loaded from a slot, go to next image. */
3827 break;
David Vinczee574f2d2020-07-10 11:42:03 +02003828 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003829 }
3830
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003831 (void) rc;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003832 FIH_RET(FIH_SUCCESS);
3833}
3834
3835/**
3836 * Updates the security counter for the current image.
3837 *
3838 * @param state Boot loader status information.
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003839 *
3840 * @return 0 on success; nonzero on failure.
3841 */
3842static int
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003843boot_update_hw_rollback_protection_ram(struct boot_loader_state *state)
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003844{
3845#ifdef MCUBOOT_HW_ROLLBACK_PROT
3846 int rc;
3847
3848 /* Update the stored security counter with the newer (active) image's
3849 * security counter value.
3850 */
3851#if defined(MCUBOOT_DIRECT_XIP) && defined(MCUBOOT_DIRECT_XIP_REVERT)
3852 /* When the 'revert' mechanism is enabled in direct-xip mode, the
3853 * security counter can be increased only after reboot, if the image
3854 * has been confirmed at runtime (the image_ok flag has been set).
3855 * This way a 'revert' can be performed when it's necessary.
3856 */
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003857 if (state->slot_usage[BOOT_CURR_IMG(state)].swap_state.image_ok == BOOT_FLAG_SET) {
David Vincze505fba22020-10-22 13:53:29 +02003858#endif
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003859 rc = boot_update_security_counter(BOOT_CURR_IMG(state),
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003860 state->slot_usage[BOOT_CURR_IMG(state)].active_slot,
3861 boot_img_hdr(state, state->slot_usage[BOOT_CURR_IMG(state)].active_slot));
David Vinczee574f2d2020-07-10 11:42:03 +02003862 if (rc != 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003863 BOOT_LOG_ERR("Security counter update failed after image "
3864 "validation.");
3865 return rc;
David Vinczee574f2d2020-07-10 11:42:03 +02003866 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003867#if defined(MCUBOOT_DIRECT_XIP) && defined(MCUBOOT_DIRECT_XIP_REVERT)
3868 }
3869#endif
David Vinczee574f2d2020-07-10 11:42:03 +02003870
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003871 return 0;
David Vinczee574f2d2020-07-10 11:42:03 +02003872
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003873#else /* MCUBOOT_HW_ROLLBACK_PROT */
3874 (void) (state);
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003875 return 0;
3876#endif
3877}
David Vinczee574f2d2020-07-10 11:42:03 +02003878
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003879fih_int
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003880context_boot_go_ram(struct boot_loader_state *state, struct boot_rsp *rsp)
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003881{
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003882 int rc;
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003883 fih_int fih_rc = FIH_FAILURE;
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +02003884 boot_ram = true;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003885
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003886 rc = boot_get_slot_usage(state);
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003887 if (rc != 0) {
David Vinczee574f2d2020-07-10 11:42:03 +02003888 goto out;
3889 }
3890
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003891#if (BOOT_IMAGE_NUMBER > 1)
3892 while (true) {
3893#endif
INFINEON\DovhalA21babb72025-07-18 10:36:03 +03003894
3895#if defined(MCUBOOT_DIRECT_XIP)
3896 FIH_CALL(boot_load_and_validate_images_xip, fih_rc, state);
3897#else
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003898 FIH_CALL(boot_load_and_validate_images, fih_rc, state);
INFINEON\DovhalA21babb72025-07-18 10:36:03 +03003899#endif
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02003900 if (!fih_eq(fih_rc, FIH_SUCCESS)) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003901 goto out;
3902 }
3903
3904#if (BOOT_IMAGE_NUMBER > 1)
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02003905#if defined(MCUBOOT_DEPENDENCY_CHECK)
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003906 rc = boot_verify_dependencies_ram(state);
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003907 if (rc != 0) {
3908 /* Dependency check failed for an image, it has been removed from
3909 * SRAM in case of MCUBOOT_RAM_LOAD strategy, and set to
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02003910 * unavailable. */
3911 goto out;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003912 }
3913 /* Dependency check was successful. */
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02003914#endif /* defined(MCUBOOT_DEPENDENCY_CHECK) */
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003915 break;
3916 }
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02003917#endif /* (BOOT_IMAGE_NUMBER > 1) */
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003918
3919 IMAGES_ITER(BOOT_CURR_IMG(state)) {
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003920#if BOOT_IMAGE_NUMBER > 1
3921 if (state->img_mask[BOOT_CURR_IMG(state)]) {
3922 continue;
3923 }
3924#endif
3925 rc = boot_update_hw_rollback_protection_ram(state);
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003926 if (rc != 0) {
3927 goto out;
3928 }
3929
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003930 rc = boot_add_shared_data(state, state->slot_usage[BOOT_CURR_IMG(state)].active_slot);
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003931 if (rc != 0) {
3932 goto out;
3933 }
3934 }
3935
3936 /* All image loaded successfully. */
3937#ifdef MCUBOOT_HAVE_LOGGING
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003938 print_loaded_images(state);
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003939#endif
3940
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003941 fill_rsp(state, rsp);
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003942
David Vinczee574f2d2020-07-10 11:42:03 +02003943out:
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003944 close_all_flash_areas(state);
Raef Colese8fe6cf2020-05-26 13:07:40 +01003945
INFINEON\DovhalA3b578f32024-11-29 01:06:04 +02003946 if (fih_eq(fih_rc, FIH_SUCCESS)) {
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003947 fih_rc = fih_int_encode_zero_equality(rc);
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003948 }
Raef Colese8fe6cf2020-05-26 13:07:40 +01003949
Roman Okhrimenko883cb5b2024-03-28 17:22:33 +02003950 boot_ram = false;
3951
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003952 FIH_RET(fih_rc);
David Vinczee574f2d2020-07-10 11:42:03 +02003953}
Tamas Banfe031092020-09-10 17:32:39 +02003954#endif /* MCUBOOT_DIRECT_XIP || MCUBOOT_RAM_LOAD */
David Vinczee574f2d2020-07-10 11:42:03 +02003955
3956/**
Raef Colese8fe6cf2020-05-26 13:07:40 +01003957 * Prepares the booting process. This function moves images around in flash as
David Vinczee574f2d2020-07-10 11:42:03 +02003958 * appropriate, and tells you what address to boot from.
3959 *
3960 * @param rsp On success, indicates how booting should occur.
3961 *
Raef Colese8fe6cf2020-05-26 13:07:40 +01003962 * @return FIH_SUCCESS on success; nonzero on failure.
David Vinczee574f2d2020-07-10 11:42:03 +02003963 */
Raef Colese8fe6cf2020-05-26 13:07:40 +01003964fih_int
David Vinczee574f2d2020-07-10 11:42:03 +02003965boot_go(struct boot_rsp *rsp)
3966{
Raef Colese8fe6cf2020-05-26 13:07:40 +01003967 fih_int fih_rc = FIH_FAILURE;
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003968
3969 boot_state_clear(NULL);
3970
INFINEON\DovhalA21babb72025-07-18 10:36:03 +03003971#if defined(MCUBOOT_DIRECT_XIP) || defined(MCUBOOT_RAM_LOAD)
3972 FIH_CALL(context_boot_go_ram, fih_rc, &boot_data, rsp);
3973#else
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003974 FIH_CALL(context_boot_go_flash, fih_rc, &boot_data, rsp);
INFINEON\DovhalA21babb72025-07-18 10:36:03 +03003975#endif
Raef Colese8fe6cf2020-05-26 13:07:40 +01003976 FIH_RET(fih_rc);
David Vinczee574f2d2020-07-10 11:42:03 +02003977}
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003978
3979/**
3980 * Prepares the booting process, considering only a single image. This function
3981 * moves images around in flash as appropriate, and tells you what address to
3982 * boot from.
3983 *
3984 * @param rsp On success, indicates how booting should occur.
3985 *
3986 * @param image_id The image ID to prepare the boot process for.
3987 *
3988 * @return FIH_SUCCESS on success; nonzero on failure.
3989 */
3990fih_int
3991boot_go_for_image_id(struct boot_rsp *rsp, uint32_t image_id)
3992{
3993 fih_int fih_rc = FIH_FAILURE;
3994
3995 if (image_id >= BOOT_IMAGE_NUMBER) {
3996 FIH_RET(FIH_FAILURE);
3997 }
3998
3999#if BOOT_IMAGE_NUMBER > 1
4000 (void)memset(&boot_data.img_mask, 1, BOOT_IMAGE_NUMBER);
4001 boot_data.img_mask[image_id] = 0;
4002#endif
4003
4004 FIH_CALL(context_boot_go_flash, fih_rc, &boot_data, rsp);
4005 FIH_RET(fih_rc);
4006}
4007
INFINEON\DovhalA21babb72025-07-18 10:36:03 +03004008#if defined(MCUBOOT_RAM_LOAD) || defined(MCUBOOT_DIRECT_XIP)
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03004009/**
4010 * Prepares the booting process, considering only a single image. This function
4011 * moves images around in flash as appropriate, and tells you what address to
4012 * boot from.
4013 *
4014 * @param rsp On success, indicates how booting should occur.
4015 *
4016 * @param image_id The image ID to prepare the boot process for.
4017 *
4018 * @return FIH_SUCCESS on success; nonzero on failure.
4019 */
4020fih_int
4021boot_go_for_image_id_ram(struct boot_rsp *rsp, uint32_t image_id)
4022{
4023 fih_int fih_rc = FIH_FAILURE;
4024
4025 if (image_id >= BOOT_IMAGE_NUMBER) {
4026 FIH_RET(FIH_FAILURE);
4027 }
4028
4029#if BOOT_IMAGE_NUMBER > 1
4030 (void)memset(&boot_data.img_mask, 1, BOOT_IMAGE_NUMBER);
4031 boot_data.img_mask[image_id] = 0;
4032#endif
4033
4034 FIH_CALL(context_boot_go_ram, fih_rc, &boot_data, rsp);
4035 FIH_RET(fih_rc);
4036}
4037
4038#endif /* MCUBOOT_RAM_LOAD */
4039
4040/**
4041 * Clears the boot state, so that previous operations have no effect on new
4042 * ones.
4043 *
4044 * @param state The state that should be cleared. If the value
4045 * is NULL, the default bootloader state will be
4046 * cleared.
4047 */
4048void boot_state_clear(struct boot_loader_state *state)
4049{
4050 if (state != NULL) {
4051 (void)memset(state, 0, sizeof(struct boot_loader_state));
4052 } else {
4053 (void)memset(&boot_data, 0, sizeof(struct boot_loader_state));
4054 }
4055}
INFINEON\DovhalA21babb72025-07-18 10:36:03 +03004056
4057fih_int
4058context_validate_slot_flash(struct boot_loader_state *state, int image_slot)
4059{
4060 fih_int fih_rc = FIH_FAILURE;
4061
4062 struct boot_status bs = {0};
4063 int rc = boot_read_image_headers(state, false, &bs);
4064
4065 if (rc == 0) {
4066 FIH_CALL(boot_soft_validate_slot, fih_rc, state, image_slot, &bs);
4067 }
4068
4069 FIH_RET(fih_rc);
4070}
4071
4072/**
4073 * Prepares the booting process, considering only a single image. This function
4074 * moves images around in flash as appropriate, and tells you what address to
4075 * boot from.
4076 *
4077 * @param rsp On success, indicates how booting should occur.
4078 *
4079 * @param image_id The image ID to prepare the boot process for.
4080 *
4081 * @return FIH_SUCCESS on success; nonzero on failure.
4082 */
4083fih_int
4084boot_validate_slot_for_image_id(uint32_t image_id, uint32_t slot_id)
4085{
4086 fih_int fih_rc = FIH_FAILURE;
4087
4088 if (image_id >= BOOT_IMAGE_NUMBER) {
4089 FIH_RET(FIH_FAILURE);
4090 }
4091
4092#if BOOT_IMAGE_NUMBER > 1
4093 (void)memset(&boot_data.img_mask, 1, BOOT_IMAGE_NUMBER);
4094 boot_data.img_mask[image_id] = 0;
4095#endif
4096
4097 FIH_CALL(context_validate_slot_flash, fih_rc, &boot_data, slot_id);
4098 FIH_RET(fih_rc);
4099}
4100
4101int boot_get_image_version(uint32_t image_id, uint32_t slot_id, struct image_version *image_version)
4102{
4103 int rc = -1;
4104 struct boot_status bs = {0};
4105
4106 if (image_id < BOOT_IMAGE_NUMBER) {
4107#if BOOT_IMAGE_NUMBER > 1
4108 (void)memset(&boot_data.img_mask, 1, BOOT_IMAGE_NUMBER);
4109 boot_data.img_mask[image_id] = 0;
4110#endif
4111
4112 if (boot_read_image_headers(&boot_data, false, &bs) == 0) {
4113 struct image_header *hdr = boot_img_hdr(&boot_data, slot_id);
4114
4115 if (hdr->ih_magic == IMAGE_MAGIC) {
4116 *image_version = hdr->ih_ver;
4117 rc = 0;
4118 } else {
4119 /* Image magic is not valid - fill with flash area erase value */
4120 const struct flash_area *fa = BOOT_IMG_AREA(&boot_data, slot_id);
4121 memset(image_version, flash_area_erased_val(fa), sizeof(struct image_version));
4122 }
4123 }
4124 }
4125 return rc;
4126}
4127
4128#if defined(MCUBOOT_DIRECT_XIP)
4129
4130int boot_read_image_header(struct boot_loader_state *state, int slot,
4131 struct image_header *out_hdr, struct boot_status *bs)
4132{
4133 (void) bs;
4134 (void) state;
4135 const struct flash_area *fap = NULL;
4136 int rc = -1;
4137 int area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
4138
4139 do {
4140 rc = flash_area_open(area_id, &fap);
4141 if (rc != 0) {
4142 rc = BOOT_EFLASH;
4143 break;
4144 }
4145
4146 rc = flash_area_read(fap, 0, out_hdr, sizeof *out_hdr);
4147 if (rc < 0) {
4148 rc = BOOT_EFLASH;
4149 break;
4150 }
4151
4152 flash_area_close(fap);
4153 } while (false);
4154
4155 return rc;
4156}
4157
4158int
4159boot_set_inactive_slot(uint32_t image_id, uint32_t slot_id)
4160{
4161 const struct flash_area *fap = NULL;
4162 int fa_id = flash_area_id_from_multi_image_slot(image_id, slot_id);
4163 int rc = flash_area_open(fa_id, &fap);
4164
4165 if (rc == 0)
4166 {
4167 rc = boot_write_image_inv(fap);
4168 }
4169 flash_area_close(fap);
4170
4171 return rc;
4172}
4173
4174static
4175int boot_read_slot_flag(uint32_t image_id, uint32_t slot_id, int (* fn)(const struct flash_area *, uint8_t *))
4176{
4177 uint8_t flag = 0U;
4178 const struct flash_area *fap = NULL;
4179 int fa_id = flash_area_id_from_multi_image_slot(image_id, slot_id);
4180 int rc = flash_area_open(fa_id, &fap);
4181
4182 if (rc == 0)
4183 {
4184 rc = fn(fap, &flag);
4185 }
4186
4187 if (rc == 0)
4188 {
4189 rc = -1;
4190
4191 if (flag == BOOT_FLAG_SET)
4192 {
4193 rc = 1;
4194 }
4195 else
4196 {
4197 rc = 0;
4198 }
4199 }
4200
4201 flash_area_close(fap);
4202
4203 return rc;
4204}
4205
4206int
4207boot_is_slot_inactive(uint32_t image_id, uint32_t slot_id)
4208{
4209 int rc = boot_read_slot_flag(image_id, slot_id, &boot_read_image_inactive);
4210
4211 return rc;
4212}
4213
4214int
4215boot_is_slot_booted(uint32_t image_id, uint32_t slot_id)
4216{
4217 int rc = boot_read_slot_flag(image_id, slot_id, &boot_read_copy_done);
4218
4219 return rc;
4220}
4221
4222int
4223boot_is_slot_confirmed(uint32_t image_id, uint32_t slot_id)
4224{
4225 int rc = boot_read_slot_flag(image_id, slot_id, &boot_read_image_ok);
4226
4227 return rc;
4228}
4229
4230int
4231boot_set_pending_slot(uint32_t image_id, uint32_t slot_id)
4232{
4233 const struct flash_area *fap = NULL;
4234 int fa_id = flash_area_id_from_multi_image_slot(image_id, slot_id);
4235 int rc = flash_area_open(fa_id, &fap);
4236
4237 uint32_t off;
4238
4239 off = boot_image_inactive_off(fap);
4240
4241 if (rc == 0)
4242 {
4243 rc = flash_area_erase(fap, off, BOOT_MAX_ALIGN);
4244 }
4245 flash_area_close(fap);
4246
4247 return rc;
4248}
4249
4250int
4251boot_set_revert_slot(uint32_t image_id, uint32_t slot_id)
4252{
4253 int rc = boot_set_pending_slot(image_id, slot_id);
4254
4255 if (rc == 0)
4256 {
4257 const struct flash_area *fap = NULL;
4258 int fa_id = flash_area_id_from_multi_image_slot(image_id, slot_id);
4259
4260 rc = flash_area_open(fa_id, &fap);
4261
4262 if (rc == 0)
4263 {
4264 rc = boot_write_copy_done(fap);
4265 }
4266
4267 flash_area_close(fap);
4268 }
4269
4270 return rc;
4271}
4272
4273int
4274boot_find_image_tlv_info(uint32_t image_id, uint32_t slot_id, uint16_t type, uint16_t* len, uint32_t* off)
4275{
4276 struct boot_loader_state *state = &boot_data;
4277 struct boot_status bs = {0};
4278 struct image_tlv_iter it = {0};
4279 int rc = -1;
4280
4281 if (image_id < BOOT_IMAGE_NUMBER) {
4282#if BOOT_IMAGE_NUMBER > 1
4283 (void)memset(state->img_mask, 1, BOOT_IMAGE_NUMBER);
4284 state->img_mask[image_id] = 0;
4285#endif
4286 if (boot_read_image_headers(state, false, &bs) == 0) {
4287 int area_id = flash_area_id_from_multi_image_slot(image_id, slot_id);
4288 struct image_header* hdr = boot_img_hdr(state, slot_id);
4289 const struct flash_area *fap = NULL;
4290
4291 rc = flash_area_open(area_id, &fap);
4292
4293 if (rc == 0)
4294 {
4295 rc = bootutil_tlv_iter_begin(&it, hdr, fap, type, false);
4296 }
4297
4298 if (rc == 0)
4299 {
4300 rc = bootutil_tlv_iter_next(&it, off, len, NULL);
4301 }
4302
4303 flash_area_close(fap);
4304 }
4305 }
4306
4307 return rc;
4308}
4309
4310int boot_read_image_tlv_value(uint32_t image_id, uint32_t slot_id, uint16_t type, uint8_t *buf, uint32_t buf_len, uint32_t *read_len)
4311{
4312 int rc = -1;
4313
4314 uint16_t tlv_len = 0;
4315 uint32_t tlv_off = 0;
4316 uint32_t tmp_len = 0;
4317
4318 if (buf != NULL && buf_len > 0U) {
4319 rc = boot_find_image_tlv_info(image_id, slot_id, type, &tlv_len, &tlv_off);
4320
4321 if (rc == 0) {
4322 int area_id = flash_area_id_from_multi_image_slot(image_id, slot_id);
4323 const struct flash_area *fap = NULL;
4324
4325 tmp_len = tlv_len;
4326
4327 if (tlv_len > buf_len) {
4328 tmp_len = buf_len;
4329 }
4330
4331 rc = flash_area_open(area_id, &fap);
4332
4333 if (rc == 0) {
4334 rc = flash_area_read(fap, tlv_off, buf, tmp_len);
4335 }
4336
4337 if (rc == 0) {
4338 if (read_len != NULL) {
4339 *read_len = tmp_len;
4340 }
4341 }
4342
4343 flash_area_close(fap);
4344 }
4345 }
4346
4347 return rc;
4348}
4349
4350int
4351boot_get_slot_state(uint32_t image_id, uint32_t slot_id, boot_slot_state_t* state)
4352{
4353 int rc = 0;
4354
4355 if (boot_is_slot_inactive(image_id, slot_id) == 1)
4356 {
4357 *state = MCUBOOT_SLOT_STATE_INACTIVE;
4358 }
4359 else if ((boot_is_slot_booted(image_id, slot_id) == 1) && (boot_is_slot_confirmed(image_id, slot_id) == 0))
4360 {
4361 *state = MCUBOOT_SLOT_STATE_VERIFYING;
4362 }
4363 else if (boot_is_slot_booted(image_id, slot_id) == 0)
4364 {
4365 *state = MCUBOOT_SLOT_STATE_PENDING;
4366 }
4367 else if ((boot_is_slot_booted(image_id, slot_id) == 1) && (boot_is_slot_confirmed(image_id, slot_id) == 1))
4368 {
4369 *state = MCUBOOT_SLOT_STATE_ACTIVE;
4370 }
4371
4372 return rc;
4373}
4374
4375int
4376boot_get_image_state(uint32_t image_id, uint32_t slot_id, boot_slot_state_t* state)
4377{
4378 int rc = -1;
4379 fih_int fih_rc;
4380
4381 FIH_CALL(boot_validate_slot_for_image_id, fih_rc, image_id, slot_id);
4382
4383 if (fih_eq(fih_rc, FIH_SUCCESS)) {
4384 rc = boot_get_slot_state(image_id, slot_id, state);
4385 }
4386 else
4387 {
4388 rc = 0;
4389 *state = MCUBOOT_SLOT_STATE_NO_IMAGE;
4390 }
4391
4392 return rc;
4393}
4394
4395#endif