blob: bb623e5b4706ceee395f2e76c9c370169fb09678 [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
David Brownaac71112020-02-03 16:13:42 -07007 *
8 * Original license:
9 *
Christopher Collins92ea77f2016-12-12 15:59:26 -080010 * Licensed to the Apache Software Foundation (ASF) under one
11 * or more contributor license agreements. See the NOTICE file
12 * distributed with this work for additional information
13 * regarding copyright ownership. The ASF licenses this file
14 * to you under the Apache License, Version 2.0 (the
15 * "License"); you may not use this file except in compliance
16 * with the License. You may obtain a copy of the License at
17 *
18 * http://www.apache.org/licenses/LICENSE-2.0
19 *
20 * Unless required by applicable law or agreed to in writing,
21 * software distributed under the License is distributed on an
22 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
23 * KIND, either express or implied. See the License for the
24 * specific language governing permissions and limitations
25 * under the License.
26 */
27
28/**
29 * This file provides an interface to the boot loader. Functions defined in
30 * this file should only be called while the boot loader is running.
31 */
32
Christopher Collins92ea77f2016-12-12 15:59:26 -080033#include <stddef.h>
David Brown52eee562017-07-05 11:25:09 -060034#include <stdbool.h>
Christopher Collins92ea77f2016-12-12 15:59:26 -080035#include <inttypes.h>
36#include <stdlib.h>
37#include <string.h>
Christopher Collins92ea77f2016-12-12 15:59:26 -080038#include "bootutil/bootutil.h"
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +030039#include "bootutil/bootutil_public.h"
Christopher Collins92ea77f2016-12-12 15:59:26 -080040#include "bootutil/image.h"
41#include "bootutil_priv.h"
Fabio Utzig12d59162019-11-28 10:01:59 -030042#include "swap_priv.h"
Marti Bolivarfd20c762017-02-07 16:52:50 -050043#include "bootutil/bootutil_log.h"
David Vinczec3084132020-02-18 14:50:47 +010044#include "bootutil/security_cnt.h"
David Vincze1cf11b52020-03-24 07:51:09 +010045#include "bootutil/boot_record.h"
Raef Colese8fe6cf2020-05-26 13:07:40 +010046#include "bootutil/fault_injection_hardening.h"
Roman Okhrimenko977b3752022-03-31 14:40:48 +030047#include "bootutil/ramload.h"
48#include "bootutil/boot_hooks.h"
Marti Bolivarfd20c762017-02-07 16:52:50 -050049
Fabio Utzigba829042018-09-18 08:29:34 -030050#ifdef MCUBOOT_ENC_IMAGES
51#include "bootutil/enc_key.h"
52#endif
53
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +030054#if (!defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)) || defined(MCUBOOT_MULTI_MEMORY_LOAD)
Roman Okhrimenko977b3752022-03-31 14:40:48 +030055#include <os/os_malloc.h>
56#endif
57
Fabio Utzigba1fbe62017-07-21 14:01:20 -030058#include "mcuboot_config/mcuboot_config.h"
Fabio Utzigeed80b62017-06-10 08:03:05 -030059
Roman Okhrimenko977b3752022-03-31 14:40:48 +030060BOOT_LOG_MODULE_DECLARE(mcuboot);
Emanuele Di Santo9f1933d2018-11-20 10:59:59 +010061
Marti Bolivar9b1f8bb2017-06-12 15:24:13 -040062static struct boot_loader_state boot_data;
Christopher Collins92ea77f2016-12-12 15:59:26 -080063
Fabio Utzigabec0732019-07-31 08:40:22 -030064#if (BOOT_IMAGE_NUMBER > 1)
65#define IMAGES_ITER(x) for ((x) = 0; (x) < BOOT_IMAGE_NUMBER; ++(x))
66#else
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +030067#define IMAGES_ITER(x) for (int iter = 0; iter < 1; ++iter)
Fabio Utzigabec0732019-07-31 08:40:22 -030068#endif
69
Fabio Utzig10ee6482019-08-01 12:04:52 -030070/*
71 * This macro allows some control on the allocation of local variables.
72 * When running natively on a target, we don't want to allocated huge
73 * variables on the stack, so make them global instead. For the simulator
74 * we want to run as many threads as there are tests, and it's safer
75 * to just make those variables stack allocated.
76 */
77#if !defined(__BOOTSIM__)
78#define TARGET_STATIC static
79#else
80#define TARGET_STATIC
81#endif
82
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +030083#if BOOT_MAX_ALIGN > 1024
84#define BUF_SZ BOOT_MAX_ALIGN
85#else
86#define BUF_SZ 1024U
87#endif
88
89static fih_int FIH_SWAP_TYPE_NONE = FIH_INT_INIT(0x3A5C742E);
90
David Vinczee574f2d2020-07-10 11:42:03 +020091static int
92boot_read_image_headers(struct boot_loader_state *state, bool require_all,
93 struct boot_status *bs)
94{
95 int rc;
96 int i;
97
98 for (i = 0; i < BOOT_NUM_SLOTS; i++) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +030099 rc = BOOT_HOOK_CALL(boot_read_image_header_hook, BOOT_HOOK_REGULAR,
100 BOOT_CURR_IMG(state), i, boot_img_hdr(state, i));
101 if (rc == BOOT_HOOK_REGULAR)
102 {
103 rc = boot_read_image_header(state, i, boot_img_hdr(state, i), bs);
104 }
David Vinczee574f2d2020-07-10 11:42:03 +0200105 if (rc != 0) {
106 /* If `require_all` is set, fail on any single fail, otherwise
107 * if at least the first slot's header was read successfully,
108 * then the boot loader can attempt a boot.
109 *
110 * Failure to read any headers is a fatal error.
111 */
112 if (i > 0 && !require_all) {
113 return 0;
114 } else {
115 return rc;
116 }
117 }
118 }
119
120 return 0;
121}
122
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300123/**
124 * Saves boot status and shared data for current image.
125 *
126 * @param state Boot loader status information.
127 * @param active_slot Index of the slot will be loaded for current image.
128 *
129 * @return 0 on success; nonzero on failure.
130 */
131static int
132boot_add_shared_data(struct boot_loader_state *state,
133 uint32_t active_slot)
134{
135#if defined(MCUBOOT_MEASURED_BOOT) || defined(MCUBOOT_DATA_SHARING)
136 int rc;
137
138#ifdef MCUBOOT_MEASURED_BOOT
139 rc = boot_save_boot_status(BOOT_CURR_IMG(state),
140 boot_img_hdr(state, active_slot),
141 BOOT_IMG_AREA(state, active_slot));
142 if (rc != 0) {
143 BOOT_LOG_ERR("Failed to add image data to shared area");
144 return rc;
145 }
146#endif /* MCUBOOT_MEASURED_BOOT */
147
148#ifdef MCUBOOT_DATA_SHARING
149 rc = boot_save_shared_data(boot_img_hdr(state, active_slot),
150 BOOT_IMG_AREA(state, active_slot));
151 if (rc != 0) {
152 BOOT_LOG_ERR("Failed to add data to shared memory area.");
153 return rc;
154 }
155#endif /* MCUBOOT_DATA_SHARING */
156
157 return 0;
158
159#else /* MCUBOOT_MEASURED_BOOT || MCUBOOT_DATA_SHARING */
160 (void) (state);
161 (void) (active_slot);
162
163 return 0;
164#endif
165}
166
167/**
168 * Fills rsp to indicate how booting should occur.
169 *
170 * @param state Boot loader status information.
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300171 * @param rsp boot_rsp struct to fill.
172 */
173static void
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300174fill_rsp(struct boot_loader_state *state, struct boot_rsp *rsp)
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300175{
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300176 uint32_t active_slot = BOOT_PRIMARY_SLOT;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300177
178#if (BOOT_IMAGE_NUMBER > 1)
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300179 /* Always boot from the first enabled image. */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300180 BOOT_CURR_IMG(state) = 0;
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300181 IMAGES_ITER(BOOT_CURR_IMG(state)) {
182 if (!state->img_mask[BOOT_CURR_IMG(state)]) {
183 break;
184 }
185 }
186 /* At least one image must be active, otherwise skip the execution */
187 if(BOOT_CURR_IMG(state) >= BOOT_IMAGE_NUMBER)
188 {
189 return;
190 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300191#endif
192
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300193#if defined(MCUBOOT_MULTI_MEMORY_LOAD)
194 if ((state->slot_usage[BOOT_CURR_IMG(state)].active_slot != BOOT_PRIMARY_SLOT) &&
195 (state->slot_usage[BOOT_CURR_IMG(state)].active_slot != NO_ACTIVE_SLOT))
196#endif
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300197#if defined(MCUBOOT_DIRECT_XIP) || defined(MCUBOOT_RAM_LOAD)
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300198 {
199 active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot;
200 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300201#endif
202
203 rsp->br_flash_dev_id = flash_area_get_device_id(BOOT_IMG_AREA(state, active_slot));
204 rsp->br_image_off = boot_img_slot_off(state, active_slot);
205 rsp->br_hdr = boot_img_hdr(state, active_slot);
206}
207
208/**
209 * Closes all flash areas.
210 *
211 * @param state Boot loader status information.
212 */
213static void
214close_all_flash_areas(struct boot_loader_state *state)
215{
216 uint32_t slot;
217
218 IMAGES_ITER(BOOT_CURR_IMG(state)) {
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300219#if BOOT_IMAGE_NUMBER > 1
220 if (state->img_mask[BOOT_CURR_IMG(state)]) {
221 continue;
222 }
223#endif
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300224#if MCUBOOT_SWAP_USING_SCRATCH
225 flash_area_close(BOOT_SCRATCH_AREA(state));
226#endif
227 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
228 flash_area_close(BOOT_IMG_AREA(state, BOOT_NUM_SLOTS - 1 - slot));
229 }
230 }
231}
232
Tamas Banfe031092020-09-10 17:32:39 +0200233#if !defined(MCUBOOT_DIRECT_XIP)
David Brownf5b33d82017-09-01 10:58:27 -0600234/*
235 * Compute the total size of the given image. Includes the size of
236 * the TLVs.
237 */
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300238#if !defined(MCUBOOT_OVERWRITE_ONLY) || defined(MCUBOOT_OVERWRITE_ONLY_FAST) || defined(MCUBOOT_RAM_LOAD)
David Brownf5b33d82017-09-01 10:58:27 -0600239static int
Fabio Utzigd638b172019-08-09 10:38:05 -0300240boot_read_image_size(struct boot_loader_state *state, int slot, uint32_t *size)
David Brownf5b33d82017-09-01 10:58:27 -0600241{
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300242 const struct flash_area *fap = NULL;
Fabio Utzig61fd8882019-09-14 20:00:20 -0300243 struct image_tlv_info info;
Fabio Utzig233af7d2019-08-26 12:06:16 -0300244 uint32_t off;
Fabio Utzige52c08e2019-09-11 19:32:00 -0300245 uint32_t protect_tlv_size;
David Brownf5b33d82017-09-01 10:58:27 -0600246 int area_id;
247 int rc;
248
Fabio Utzig10ee6482019-08-01 12:04:52 -0300249#if (BOOT_IMAGE_NUMBER == 1)
250 (void)state;
251#endif
252
253 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
David Brownf5b33d82017-09-01 10:58:27 -0600254 rc = flash_area_open(area_id, &fap);
255 if (rc != 0) {
256 rc = BOOT_EFLASH;
257 goto done;
258 }
259
Fabio Utzig61fd8882019-09-14 20:00:20 -0300260 off = BOOT_TLV_OFF(boot_img_hdr(state, slot));
261
262 if (flash_area_read(fap, off, &info, sizeof(info))) {
263 rc = BOOT_EFLASH;
David Brownf5b33d82017-09-01 10:58:27 -0600264 goto done;
265 }
Fabio Utzig61fd8882019-09-14 20:00:20 -0300266
Fabio Utzige52c08e2019-09-11 19:32:00 -0300267 protect_tlv_size = boot_img_hdr(state, slot)->ih_protect_tlv_size;
268 if (info.it_magic == IMAGE_TLV_PROT_INFO_MAGIC) {
269 if (protect_tlv_size != info.it_tlv_tot) {
270 rc = BOOT_EBADIMAGE;
271 goto done;
272 }
273
274 if (flash_area_read(fap, off + info.it_tlv_tot, &info, sizeof(info))) {
275 rc = BOOT_EFLASH;
276 goto done;
277 }
278 } else if (protect_tlv_size != 0) {
279 rc = BOOT_EBADIMAGE;
280 goto done;
281 }
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300282 else
283 {
284 /* acc. to MISRA R.15.7 */
285 }
Fabio Utzige52c08e2019-09-11 19:32:00 -0300286
Fabio Utzig61fd8882019-09-14 20:00:20 -0300287 if (info.it_magic != IMAGE_TLV_INFO_MAGIC) {
288 rc = BOOT_EBADIMAGE;
289 goto done;
290 }
291
Fabio Utzige52c08e2019-09-11 19:32:00 -0300292 *size = off + protect_tlv_size + info.it_tlv_tot;
David Brownf5b33d82017-09-01 10:58:27 -0600293 rc = 0;
294
295done:
296 flash_area_close(fap);
Fabio Utzig2eebf112017-09-04 15:25:08 -0300297 return rc;
David Brownf5b33d82017-09-01 10:58:27 -0600298}
299
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300300#endif
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200301
David Brownab449182019-11-15 09:32:52 -0700302static uint32_t
Fabio Utzig10ee6482019-08-01 12:04:52 -0300303boot_write_sz(struct boot_loader_state *state)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800304{
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300305 size_t elem_sz;
Fabio Utzig12d59162019-11-28 10:01:59 -0300306#if MCUBOOT_SWAP_USING_SCRATCH
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300307 size_t align;
Fabio Utzig12d59162019-11-28 10:01:59 -0300308#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800309
310 /* Figure out what size to write update status update as. The size depends
311 * on what the minimum write size is for scratch area, active image slot.
312 * We need to use the bigger of those 2 values.
313 */
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300314
Fabio Utzig10ee6482019-08-01 12:04:52 -0300315 elem_sz = flash_area_align(BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT));
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300316 assert(elem_sz != 0u);
317
Fabio Utzig12d59162019-11-28 10:01:59 -0300318#if MCUBOOT_SWAP_USING_SCRATCH
Fabio Utzig10ee6482019-08-01 12:04:52 -0300319 align = flash_area_align(BOOT_SCRATCH_AREA(state));
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300320 assert(align != 0u);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800321 if (align > elem_sz) {
322 elem_sz = align;
323 }
Fabio Utzig12d59162019-11-28 10:01:59 -0300324#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800325
326 return elem_sz;
327}
328
Fabio Utzig10ee6482019-08-01 12:04:52 -0300329static int
330boot_initialize_area(struct boot_loader_state *state, int flash_area)
331{
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300332 uint32_t num_sectors = BOOT_MAX_IMG_SECTORS;
333 boot_sector_t *out_sectors;
Fabio Utzig10ee6482019-08-01 12:04:52 -0300334 size_t *out_num_sectors;
335 int rc;
336
337 num_sectors = BOOT_MAX_IMG_SECTORS;
338
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300339 if (flash_area == (int) FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state))) {
Fabio Utzig10ee6482019-08-01 12:04:52 -0300340 out_sectors = BOOT_IMG(state, BOOT_PRIMARY_SLOT).sectors;
341 out_num_sectors = &BOOT_IMG(state, BOOT_PRIMARY_SLOT).num_sectors;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300342 } else if (flash_area == (int) FLASH_AREA_IMAGE_SECONDARY(BOOT_CURR_IMG(state))) {
Fabio Utzig10ee6482019-08-01 12:04:52 -0300343 out_sectors = BOOT_IMG(state, BOOT_SECONDARY_SLOT).sectors;
344 out_num_sectors = &BOOT_IMG(state, BOOT_SECONDARY_SLOT).num_sectors;
Fabio Utzig12d59162019-11-28 10:01:59 -0300345#if MCUBOOT_SWAP_USING_SCRATCH
Fabio Utzig10ee6482019-08-01 12:04:52 -0300346 } else if (flash_area == FLASH_AREA_IMAGE_SCRATCH) {
347 out_sectors = state->scratch.sectors;
348 out_num_sectors = &state->scratch.num_sectors;
Fabio Utzig12d59162019-11-28 10:01:59 -0300349#endif
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200350#if MCUBOOT_SWAP_USING_STATUS
351 } else if (flash_area == FLASH_AREA_IMAGE_SWAP_STATUS) {
352 out_sectors = state->status.sectors;
353 out_num_sectors = &state->status.num_sectors;
354#endif
Fabio Utzig10ee6482019-08-01 12:04:52 -0300355 } else {
356 return BOOT_EFLASH;
357 }
358
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300359#ifdef MCUBOOT_USE_FLASH_AREA_GET_SECTORS
Fabio Utzig10ee6482019-08-01 12:04:52 -0300360 rc = flash_area_get_sectors(flash_area, &num_sectors, out_sectors);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300361#else
362 _Static_assert(sizeof(int) <= sizeof(uint32_t), "Fix needed");
363 rc = flash_area_to_sectors(flash_area, (int *)&num_sectors, out_sectors);
364#endif /* defined(MCUBOOT_USE_FLASH_AREA_GET_SECTORS) */
Fabio Utzig10ee6482019-08-01 12:04:52 -0300365 if (rc != 0) {
366 return rc;
367 }
368 *out_num_sectors = num_sectors;
369 return 0;
370}
Fabio Utzig10ee6482019-08-01 12:04:52 -0300371
Christopher Collins92ea77f2016-12-12 15:59:26 -0800372/**
373 * Determines the sector layout of both image slots and the scratch area.
374 * This information is necessary for calculating the number of bytes to erase
375 * and copy during an image swap. The information collected during this
Fabio Utzig10ee6482019-08-01 12:04:52 -0300376 * function is used to populate the state.
Christopher Collins92ea77f2016-12-12 15:59:26 -0800377 */
378static int
Fabio Utzig10ee6482019-08-01 12:04:52 -0300379boot_read_sectors(struct boot_loader_state *state)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800380{
Fabio Utzigb0f04732019-07-31 09:49:19 -0300381 uint8_t image_index;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800382 int rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800383
Fabio Utzig10ee6482019-08-01 12:04:52 -0300384 image_index = BOOT_CURR_IMG(state);
Fabio Utzigb0f04732019-07-31 09:49:19 -0300385
386 rc = boot_initialize_area(state, FLASH_AREA_IMAGE_PRIMARY(image_index));
Christopher Collins92ea77f2016-12-12 15:59:26 -0800387 if (rc != 0) {
388 return BOOT_EFLASH;
389 }
390
Fabio Utzig10ee6482019-08-01 12:04:52 -0300391 rc = boot_initialize_area(state, FLASH_AREA_IMAGE_SECONDARY(image_index));
Christopher Collins92ea77f2016-12-12 15:59:26 -0800392 if (rc != 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300393 /* We need to differentiate from the primary image issue */
394 return BOOT_EFLASH_SEC;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800395 }
396
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200397#if MCUBOOT_SWAP_USING_STATUS
398 rc = boot_initialize_area(state, FLASH_AREA_IMAGE_SWAP_STATUS);
399 if (rc != 0) {
400 return BOOT_EFLASH;
401 }
402#endif
403
Fabio Utzig12d59162019-11-28 10:01:59 -0300404#if MCUBOOT_SWAP_USING_SCRATCH
Fabio Utzig10ee6482019-08-01 12:04:52 -0300405 rc = boot_initialize_area(state, FLASH_AREA_IMAGE_SCRATCH);
Fabio Utzig2bd980a2018-11-26 10:38:17 -0200406 if (rc != 0) {
407 return BOOT_EFLASH;
408 }
Fabio Utzig12d59162019-11-28 10:01:59 -0300409#endif
Fabio Utzig2bd980a2018-11-26 10:38:17 -0200410
Fabio Utzig10ee6482019-08-01 12:04:52 -0300411 BOOT_WRITE_SZ(state) = boot_write_sz(state);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800412
413 return 0;
414}
415
Fabio Utzig12d59162019-11-28 10:01:59 -0300416void
417boot_status_reset(struct boot_status *bs)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800418{
Fabio Utzig4741c452019-12-19 15:32:41 -0300419#ifdef MCUBOOT_ENC_IMAGES
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300420 (void)memset(&bs->enckey, BOOT_UNINITIALIZED_KEY_FILL,
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300421 BOOT_NUM_SLOTS * BOOT_ENC_KEY_ALIGN_SIZE);
422#ifdef MCUBOOT_SWAP_SAVE_ENCTLV
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300423 (void)memset(&bs->enctlv, BOOT_UNINITIALIZED_TLV_FILL,
424 BOOT_NUM_SLOTS * BOOT_ENC_TLV_ALIGN_SIZE);
Fabio Utzig4741c452019-12-19 15:32:41 -0300425#endif
426#endif /* MCUBOOT_ENC_IMAGES */
427
428 bs->use_scratch = 0;
429 bs->swap_size = 0;
430 bs->source = 0;
431
Fabio Utzig74aef312019-11-28 11:05:34 -0300432 bs->op = BOOT_STATUS_OP_MOVE;
Fabio Utzig39000012018-07-30 12:40:20 -0300433 bs->idx = BOOT_STATUS_IDX_0;
434 bs->state = BOOT_STATUS_STATE_0;
Christopher Collinsa1c12042019-05-23 14:00:28 -0700435 bs->swap_type = BOOT_SWAP_TYPE_NONE;
Fabio Utzig12d59162019-11-28 10:01:59 -0300436}
Christopher Collins92ea77f2016-12-12 15:59:26 -0800437
Fabio Utzig12d59162019-11-28 10:01:59 -0300438bool
439boot_status_is_reset(const struct boot_status *bs)
440{
Fabio Utzig74aef312019-11-28 11:05:34 -0300441 return (bs->op == BOOT_STATUS_OP_MOVE &&
442 bs->idx == BOOT_STATUS_IDX_0 &&
443 bs->state == BOOT_STATUS_STATE_0);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800444}
445
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200446#ifndef MCUBOOT_SWAP_USING_STATUS
Christopher Collins92ea77f2016-12-12 15:59:26 -0800447/**
448 * Writes the supplied boot status to the flash file system. The boot status
449 * contains the current state of an in-progress image copy operation.
450 *
451 * @param bs The boot status to write.
452 *
453 * @return 0 on success; nonzero on failure.
454 */
455int
Fabio Utzig12d59162019-11-28 10:01:59 -0300456boot_write_status(const struct boot_loader_state *state, struct boot_status *bs)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800457{
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300458 const struct flash_area *fap = NULL;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800459 uint32_t off;
460 int area_id;
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300461 int rc = 0;
Fabio Utziga0bc9b52017-06-28 09:19:55 -0300462 uint8_t buf[BOOT_MAX_ALIGN];
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300463 uint32_t align;
Fabio Utzig39000012018-07-30 12:40:20 -0300464 uint8_t erased_val;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800465
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300466 /* NOTE: The first sector copied (that is the last sector on slot) contains
David Vincze2d736ad2019-02-18 11:50:22 +0100467 * the trailer. Since in the last step the primary slot is erased, the
468 * first two status writes go to the scratch which will be copied to
469 * the primary slot!
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300470 */
471
Fabio Utzig12d59162019-11-28 10:01:59 -0300472#if MCUBOOT_SWAP_USING_SCRATCH
Fabio Utzig2473ac02017-05-02 12:45:02 -0300473 if (bs->use_scratch) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800474 /* Write to scratch. */
475 area_id = FLASH_AREA_IMAGE_SCRATCH;
476 } else {
Fabio Utzig12d59162019-11-28 10:01:59 -0300477#endif
David Vincze2d736ad2019-02-18 11:50:22 +0100478 /* Write to the primary slot. */
Fabio Utzig10ee6482019-08-01 12:04:52 -0300479 area_id = FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state));
Fabio Utzig12d59162019-11-28 10:01:59 -0300480#if MCUBOOT_SWAP_USING_SCRATCH
Christopher Collins92ea77f2016-12-12 15:59:26 -0800481 }
Fabio Utzig12d59162019-11-28 10:01:59 -0300482#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800483
484 rc = flash_area_open(area_id, &fap);
485 if (rc != 0) {
486 rc = BOOT_EFLASH;
487 goto done;
488 }
489
490 off = boot_status_off(fap) +
Fabio Utzig12d59162019-11-28 10:01:59 -0300491 boot_status_internal_off(bs, BOOT_WRITE_SZ(state));
Andrzej Puzdrowskib788c712018-04-12 12:42:49 +0200492 align = flash_area_align(fap);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300493 if (align == 0u) {
494 rc = BOOT_EFLASH;
495 goto done;
496 }
497
Fabio Utzig39000012018-07-30 12:40:20 -0300498 erased_val = flash_area_erased_val(fap);
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300499 (void)memset(buf, erased_val, BOOT_MAX_ALIGN);
David Brown9d725462017-01-23 15:50:58 -0700500 buf[0] = bs->state;
501
502 rc = flash_area_write(fap, off, buf, align);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800503 if (rc != 0) {
504 rc = BOOT_EFLASH;
505 goto done;
506 }
507
508 rc = 0;
509
510done:
511 flash_area_close(fap);
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300512
Christopher Collins92ea77f2016-12-12 15:59:26 -0800513 return rc;
514}
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200515#endif /* MCUBOOT_SWAP_USING_STATUS */
516
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300517
David Vinczee574f2d2020-07-10 11:42:03 +0200518#endif /* !MCUBOOT_DIRECT_XIP */
Christopher Collins92ea77f2016-12-12 15:59:26 -0800519
520/*
David Vinczec3084132020-02-18 14:50:47 +0100521 * Validate image hash/signature and optionally the security counter in a slot.
Christopher Collins92ea77f2016-12-12 15:59:26 -0800522 */
Raef Colese8fe6cf2020-05-26 13:07:40 +0100523static fih_int
Fabio Utzig10ee6482019-08-01 12:04:52 -0300524boot_image_check(struct boot_loader_state *state, struct image_header *hdr,
525 const struct flash_area *fap, struct boot_status *bs)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800526{
Fabio Utzig10ee6482019-08-01 12:04:52 -0300527 TARGET_STATIC uint8_t tmpbuf[BOOT_TMPBUF_SZ];
Fabio Utzigb0f04732019-07-31 09:49:19 -0300528 uint8_t image_index;
Raef Colese8fe6cf2020-05-26 13:07:40 +0100529 fih_int fih_rc = FIH_FAILURE;
Fabio Utzigba829042018-09-18 08:29:34 -0300530
Fabio Utzig10ee6482019-08-01 12:04:52 -0300531#if (BOOT_IMAGE_NUMBER == 1)
532 (void)state;
533#endif
534
Fabio Utzigba829042018-09-18 08:29:34 -0300535 (void)bs;
Fabio Utzigbc077932019-08-26 11:16:34 -0300536
537 image_index = BOOT_CURR_IMG(state);
538
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300539/* In the case of ram loading the image has already been decrypted as it is
540 * decrypted when copied in ram */
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300541#if defined(MCUBOOT_ENC_IMAGES)
542 if (MUST_DECRYPT(fap, image_index, hdr) && !IS_RAM_BOOTABLE(hdr)) {
543 int rc = flash_area_id_to_multi_image_slot(image_index, fap->fa_id);
Fabio Utzigba829042018-09-18 08:29:34 -0300544 if (rc < 0) {
Raef Colese8fe6cf2020-05-26 13:07:40 +0100545 FIH_RET(fih_rc);
Fabio Utzigba829042018-09-18 08:29:34 -0300546 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300547 else {
548 uint8_t slot = (uint8_t)rc;
549
550 rc = boot_enc_load(BOOT_CURR_ENC(state), image_index, hdr, fap, bs);
551 if (rc < 0) {
552 FIH_RET(fih_rc);
553 }
554 if (0 == rc && boot_enc_set_key(BOOT_CURR_ENC(state), slot, bs)) {
555 FIH_RET(fih_rc);
556 }
Fabio Utzigba829042018-09-18 08:29:34 -0300557 }
558 }
Fabio Utzigbc077932019-08-26 11:16:34 -0300559#endif
560
Raef Colese8fe6cf2020-05-26 13:07:40 +0100561 FIH_CALL(bootutil_img_validate, fih_rc, BOOT_CURR_ENC(state), image_index,
562 hdr, fap, tmpbuf, BOOT_TMPBUF_SZ, NULL, 0, NULL);
Fabio Utzig10ee6482019-08-01 12:04:52 -0300563
Raef Colese8fe6cf2020-05-26 13:07:40 +0100564 FIH_RET(fih_rc);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800565}
566
Raef Colese8fe6cf2020-05-26 13:07:40 +0100567static fih_int
Christopher Collins92ea77f2016-12-12 15:59:26 -0800568split_image_check(struct image_header *app_hdr,
569 const struct flash_area *app_fap,
570 struct image_header *loader_hdr,
571 const struct flash_area *loader_fap)
572{
573 static void *tmpbuf;
574 uint8_t loader_hash[32];
Raef Colese8fe6cf2020-05-26 13:07:40 +0100575 fih_int fih_rc = FIH_FAILURE;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800576
577 if (!tmpbuf) {
578 tmpbuf = malloc(BOOT_TMPBUF_SZ);
579 if (!tmpbuf) {
Raef Colese8fe6cf2020-05-26 13:07:40 +0100580 goto out;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800581 }
582 }
583
Raef Colese8fe6cf2020-05-26 13:07:40 +0100584 FIH_CALL(bootutil_img_validate, fih_rc, NULL, 0, loader_hdr, loader_fap,
585 tmpbuf, BOOT_TMPBUF_SZ, NULL, 0, loader_hash);
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300586 if (fih_eq(fih_rc, FIH_SUCCESS) != FIH_TRUE) {
Raef Colese8fe6cf2020-05-26 13:07:40 +0100587 FIH_RET(fih_rc);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800588 }
589
Raef Colese8fe6cf2020-05-26 13:07:40 +0100590 FIH_CALL(bootutil_img_validate, fih_rc, NULL, 0, app_hdr, app_fap,
591 tmpbuf, BOOT_TMPBUF_SZ, loader_hash, 32, NULL);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800592
Raef Colese8fe6cf2020-05-26 13:07:40 +0100593out:
594 FIH_RET(fih_rc);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800595}
596
Fabio Utzig338a19f2018-12-03 08:37:08 -0200597/*
David Brown9bf95af2019-10-10 15:36:36 -0600598 * Check that this is a valid header. Valid means that the magic is
599 * correct, and that the sizes/offsets are "sane". Sane means that
600 * there is no overflow on the arithmetic, and that the result fits
601 * within the flash area we are in.
602 */
603static bool
604boot_is_header_valid(const struct image_header *hdr, const struct flash_area *fap)
605{
606 uint32_t size;
607
608 if (hdr->ih_magic != IMAGE_MAGIC) {
609 return false;
610 }
611
612 if (!boot_u32_safe_add(&size, hdr->ih_img_size, hdr->ih_hdr_size)) {
613 return false;
614 }
615
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300616 if (size >= flash_area_get_size(fap)) {
David Brown9bf95af2019-10-10 15:36:36 -0600617 return false;
618 }
619
620 return true;
621}
622
623/*
Fabio Utzig338a19f2018-12-03 08:37:08 -0200624 * Check that a memory area consists of a given value.
625 */
626static inline bool
627boot_data_is_set_to(uint8_t val, void *data, size_t len)
Fabio Utzig39000012018-07-30 12:40:20 -0300628{
629 uint8_t i;
Fabio Utzig338a19f2018-12-03 08:37:08 -0200630 uint8_t *p = (uint8_t *)data;
631 for (i = 0; i < len; i++) {
632 if (val != p[i]) {
633 return false;
Fabio Utzig39000012018-07-30 12:40:20 -0300634 }
635 }
Fabio Utzig338a19f2018-12-03 08:37:08 -0200636 return true;
637}
638
639static int
Fabio Utzig10ee6482019-08-01 12:04:52 -0300640boot_check_header_erased(struct boot_loader_state *state, int slot)
Fabio Utzig338a19f2018-12-03 08:37:08 -0200641{
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300642 const struct flash_area *fap = NULL;
Fabio Utzig338a19f2018-12-03 08:37:08 -0200643 struct image_header *hdr;
644 uint8_t erased_val;
Fabio Utzigb0f04732019-07-31 09:49:19 -0300645 int area_id;
Fabio Utzig338a19f2018-12-03 08:37:08 -0200646 int rc;
647
Fabio Utzig10ee6482019-08-01 12:04:52 -0300648 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
Fabio Utzigb0f04732019-07-31 09:49:19 -0300649 rc = flash_area_open(area_id, &fap);
Fabio Utzig338a19f2018-12-03 08:37:08 -0200650 if (rc != 0) {
651 return -1;
652 }
653
654 erased_val = flash_area_erased_val(fap);
655 flash_area_close(fap);
656
Fabio Utzig10ee6482019-08-01 12:04:52 -0300657 hdr = boot_img_hdr(state, slot);
Fabio Utzig338a19f2018-12-03 08:37:08 -0200658 if (!boot_data_is_set_to(erased_val, &hdr->ih_magic, sizeof(hdr->ih_magic))) {
659 return -1;
660 }
661
662 return 0;
Fabio Utzig39000012018-07-30 12:40:20 -0300663}
664
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +0000665#if (BOOT_IMAGE_NUMBER > 1) || \
David Vinczee574f2d2020-07-10 11:42:03 +0200666 defined(MCUBOOT_DIRECT_XIP) || \
Tamas Banfe031092020-09-10 17:32:39 +0200667 defined(MCUBOOT_RAM_LOAD) || \
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +0000668 (defined(MCUBOOT_OVERWRITE_ONLY) && defined(MCUBOOT_DOWNGRADE_PREVENTION))
669/**
David Vincze8b0b6372020-05-20 19:54:44 +0200670 * Compare image version numbers not including the build number
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +0000671 *
David Vincze8b0b6372020-05-20 19:54:44 +0200672 * @param ver1 Pointer to the first image version to compare.
673 * @param ver2 Pointer to the second image version to compare.
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +0000674 *
David Vincze8b0b6372020-05-20 19:54:44 +0200675 * @retval -1 If ver1 is strictly less than ver2.
676 * @retval 0 If the image version numbers are equal,
677 * (not including the build number).
678 * @retval 1 If ver1 is strictly greater than ver2.
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +0000679 */
680static int
David Vincze8b0b6372020-05-20 19:54:44 +0200681boot_version_cmp(const struct image_version *ver1,
682 const struct image_version *ver2)
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +0000683{
David Vincze8b0b6372020-05-20 19:54:44 +0200684 if (ver1->iv_major > ver2->iv_major) {
685 return 1;
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +0000686 }
David Vincze8b0b6372020-05-20 19:54:44 +0200687 if (ver1->iv_major < ver2->iv_major) {
688 return -1;
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +0000689 }
David Vincze8b0b6372020-05-20 19:54:44 +0200690 /* The major version numbers are equal, continue comparison. */
691 if (ver1->iv_minor > ver2->iv_minor) {
692 return 1;
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +0000693 }
David Vincze8b0b6372020-05-20 19:54:44 +0200694 if (ver1->iv_minor < ver2->iv_minor) {
695 return -1;
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +0000696 }
David Vincze8b0b6372020-05-20 19:54:44 +0200697 /* The minor version numbers are equal, continue comparison. */
698 if (ver1->iv_revision > ver2->iv_revision) {
699 return 1;
700 }
701 if (ver1->iv_revision < ver2->iv_revision) {
702 return -1;
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +0000703 }
704
705 return 0;
706}
707#endif
708
Dominik Ermel0c8c8d52021-02-17 14:45:02 +0000709#if defined(MCUBOOT_DIRECT_XIP)
710/**
711 * Check if image in slot has been set with specific ROM address to run from
712 * and whether the slot starts at that address.
713 *
714 * @returns 0 if IMAGE_F_ROM_FIXED flag is not set;
715 * 0 if IMAGE_F_ROM_FIXED flag is set and ROM address specified in
716 * header matches the slot address;
717 * 1 if IMF_F_ROM_FIXED flag is set but ROM address specified in header
718 * does not match the slot address.
719 */
720static bool
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300721boot_rom_address_check(struct boot_loader_state *state)
Dominik Ermel0c8c8d52021-02-17 14:45:02 +0000722{
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300723 uint32_t active_slot;
724 const struct image_header *hdr;
725 uint32_t f_off;
726
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300727 active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300728 hdr = boot_img_hdr(state, active_slot);
729 f_off = boot_img_slot_off(state, active_slot);
730
Dominik Ermel0c8c8d52021-02-17 14:45:02 +0000731 if (hdr->ih_flags & IMAGE_F_ROM_FIXED && hdr->ih_load_addr != f_off) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300732 BOOT_LOG_WRN("Image in %s slot at 0x%" PRIx32
733 " has been built for offset 0x%" PRIx32 ", skipping",
734 active_slot == 0 ? "primary" : "secondary", f_off,
Dominik Ermel0c8c8d52021-02-17 14:45:02 +0000735 hdr->ih_load_addr);
736
737 /* If there is address mismatch, the image is not bootable from this
738 * slot.
739 */
740 return 1;
741 }
742 return 0;
743}
744#endif
745
Fabio Utzigb1adb1e2019-09-11 11:42:53 -0300746/*
747 * Check that there is a valid image in a slot
748 *
749 * @returns
Raef Colese8fe6cf2020-05-26 13:07:40 +0100750 * FIH_SUCCESS if image was successfully validated
751 * 1 (or its fih_int encoded form) if no bootloable image was found
752 * FIH_FAILURE on any errors
Fabio Utzigb1adb1e2019-09-11 11:42:53 -0300753 */
Raef Colese8fe6cf2020-05-26 13:07:40 +0100754static fih_int
Fabio Utzig10ee6482019-08-01 12:04:52 -0300755boot_validate_slot(struct boot_loader_state *state, int slot,
756 struct boot_status *bs)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800757{
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300758 const struct flash_area *fap = NULL;
Marti Bolivarf804f622017-06-12 15:41:48 -0400759 struct image_header *hdr;
Fabio Utzigb0f04732019-07-31 09:49:19 -0300760 int area_id;
Raef Colese8fe6cf2020-05-26 13:07:40 +0100761 fih_int fih_rc = FIH_FAILURE;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800762 int rc;
Fabio Utzig7ebb7c22017-04-26 10:59:31 -0300763
Fabio Utzig10ee6482019-08-01 12:04:52 -0300764 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
Fabio Utzigb0f04732019-07-31 09:49:19 -0300765 rc = flash_area_open(area_id, &fap);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800766 if (rc != 0) {
Raef Colese8fe6cf2020-05-26 13:07:40 +0100767 FIH_RET(fih_rc);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800768 }
769
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300770 BOOT_LOG_DBG("> boot_validate_slot: fa_id = %u", (unsigned)fap->fa_id);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200771
Fabio Utzig10ee6482019-08-01 12:04:52 -0300772 hdr = boot_img_hdr(state, slot);
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300773
Fabio Utzig10ee6482019-08-01 12:04:52 -0300774 if (boot_check_header_erased(state, slot) == 0 ||
775 (hdr->ih_flags & IMAGE_F_NON_BOOTABLE)) {
Fabio Utzig260ec452020-07-09 18:40:07 -0300776
777#if defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SWAP_USING_MOVE)
778 /*
779 * This fixes an issue where an image might be erased, but a trailer
780 * be left behind. It can happen if the image is in the secondary slot
781 * and did not pass validation, in which case the whole slot is erased.
782 * If during the erase operation, a reset occurs, parts of the slot
783 * might have been erased while some did not. The concerning part is
784 * the trailer because it might disable a new image from being loaded
785 * through mcumgr; so we just get rid of the trailer here, if the header
786 * is erased.
787 */
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200788 BOOT_LOG_DBG(" * Fix the secondary slot when image is invalid.");
Fabio Utzig260ec452020-07-09 18:40:07 -0300789 if (slot != BOOT_PRIMARY_SLOT) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200790 BOOT_LOG_DBG(" * Erase secondary image trailer.");
Fabio Utzig260ec452020-07-09 18:40:07 -0300791 swap_erase_trailer_sectors(state, fap);
792 }
793#endif
794
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200795 BOOT_LOG_DBG(" * No bootable image in slot(%d); continue booting from the primary slot.", slot);
David Vincze2d736ad2019-02-18 11:50:22 +0100796 /* No bootable image in slot; continue booting from the primary slot. */
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300797 fih_rc = FIH_SWAP_TYPE_NONE;
Fabio Utzig338a19f2018-12-03 08:37:08 -0200798 goto out;
Fabio Utzig39000012018-07-30 12:40:20 -0300799 }
800
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +0000801#if defined(MCUBOOT_OVERWRITE_ONLY) && defined(MCUBOOT_DOWNGRADE_PREVENTION)
802 if (slot != BOOT_PRIMARY_SLOT) {
803 /* Check if version of secondary slot is sufficient */
David Vincze8b0b6372020-05-20 19:54:44 +0200804 rc = boot_version_cmp(
805 &boot_img_hdr(state, BOOT_SECONDARY_SLOT)->ih_ver,
806 &boot_img_hdr(state, BOOT_PRIMARY_SLOT)->ih_ver);
807 if (rc < 0 && boot_check_header_erased(state, BOOT_PRIMARY_SLOT)) {
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +0000808 BOOT_LOG_ERR("insufficient version in secondary slot");
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300809 flash_area_erase(fap, 0, flash_area_get_size(fap));
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +0000810 /* Image in the secondary slot does not satisfy version requirement.
811 * Erase the image and continue booting from the primary slot.
812 */
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300813 fih_rc = FIH_SWAP_TYPE_NONE;
Håkon Øye Amundsen2d1bac12020-01-03 13:08:09 +0000814 goto out;
815 }
816 }
817#endif
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300818 BOOT_HOOK_CALL_FIH(boot_image_check_hook, fih_int_encode(BOOT_HOOK_REGULAR),
819 fih_rc, BOOT_CURR_IMG(state), slot);
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300820 if (FIH_TRUE == fih_eq(fih_rc, fih_int_encode(BOOT_HOOK_REGULAR)))
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300821 {
822 FIH_CALL(boot_image_check, fih_rc, state, hdr, fap, bs);
823 }
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300824 if (!boot_is_header_valid(hdr, fap) || fih_eq(fih_rc, FIH_SUCCESS) != FIH_TRUE) {
Tamas Banfe031092020-09-10 17:32:39 +0200825 if ((slot != BOOT_PRIMARY_SLOT) || ARE_SLOTS_EQUIVALENT()) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200826 BOOT_LOG_DBG(" * Image in the secondary slot is invalid. Erase the image");
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300827 flash_area_erase(fap, 0, flash_area_get_size(fap));
David Vinczee574f2d2020-07-10 11:42:03 +0200828 /* Image is invalid, erase it to prevent further unnecessary
829 * attempts to validate and boot it.
David Brownb38e0442017-02-24 13:57:12 -0700830 */
831 }
David Brown098de832019-12-10 11:58:01 -0700832#if !defined(__BOOTSIM__)
David Vincze2d736ad2019-02-18 11:50:22 +0100833 BOOT_LOG_ERR("Image in the %s slot is not valid!",
834 (slot == BOOT_PRIMARY_SLOT) ? "primary" : "secondary");
David Brown098de832019-12-10 11:58:01 -0700835#endif
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300836 fih_rc = FIH_SWAP_TYPE_NONE;
Fabio Utzig338a19f2018-12-03 08:37:08 -0200837 goto out;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800838 }
839
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300840#if MCUBOOT_IMAGE_NUMBER > 1 && !defined(MCUBOOT_ENC_IMAGES) && defined(MCUBOOT_VERIFY_IMG_ADDRESS)
841 /* Verify that the image in the secondary slot has a reset address
842 * located in the primary slot. This is done to avoid users incorrectly
843 * overwriting an application written to the incorrect slot.
844 * This feature is only supported by ARM platforms.
845 */
846 if (area_id == FLASH_AREA_IMAGE_SECONDARY(BOOT_CURR_IMG(state))) {
847 const struct flash_area *pri_fa = BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT);
848 struct image_header *secondary_hdr = boot_img_hdr(state, slot);
849 uint32_t reset_value = 0;
850 uint32_t reset_addr = secondary_hdr->ih_hdr_size + sizeof(reset_value);
851
852 rc = flash_area_read(fap, reset_addr, &reset_value, sizeof(reset_value));
853 if (rc != 0) {
854 fih_rc = fih_int_encode(1);
855 goto out;
856 }
857
858 if (reset_value < pri_fa->fa_off || reset_value> (pri_fa->fa_off + pri_fa->fa_size)) {
859 BOOT_LOG_ERR("Reset address of image in secondary slot is not in the primary slot");
860 BOOT_LOG_ERR("Erasing image from secondary slot");
861
862 /* The vector table in the image located in the secondary
863 * slot does not target the primary slot. This might
864 * indicate that the image was loaded to the wrong slot.
865 *
866 * Erase the image and continue booting from the primary slot.
867 */
868 flash_area_erase(fap, 0, fap->fa_size);
869 fih_rc = fih_int_encode(1);
870 goto out;
871 }
872 }
873#endif
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +0200874
Fabio Utzig338a19f2018-12-03 08:37:08 -0200875out:
876 flash_area_close(fap);
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300877 BOOT_LOG_DBG("< boot_validate_slot: fa_id = %u", (unsigned)fap->fa_id);
Raef Colese8fe6cf2020-05-26 13:07:40 +0100878 FIH_RET(fih_rc);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800879}
880
David Vinczec3084132020-02-18 14:50:47 +0100881#ifdef MCUBOOT_HW_ROLLBACK_PROT
882/**
883 * Updates the stored security counter value with the image's security counter
884 * value which resides in the given slot, only if it's greater than the stored
885 * value.
886 *
887 * @param image_index Index of the image to determine which security
888 * counter to update.
889 * @param slot Slot number of the image.
890 * @param hdr Pointer to the image header structure of the image
891 * that is currently stored in the given slot.
892 *
893 * @return 0 on success; nonzero on failure.
894 */
895static int
896boot_update_security_counter(uint8_t image_index, int slot,
897 struct image_header *hdr)
898{
899 const struct flash_area *fap = NULL;
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300900 fih_int fih_rc = FIH_FAILURE;
901 fih_uint img_security_cnt = FIH_UINT_ZERO;
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300902 void * custom_data = NULL;
David Vinczec3084132020-02-18 14:50:47 +0100903 int rc;
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300904#if defined CYW20829
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300905 uint8_t buff[REPROV_PACK_SIZE];
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300906#endif /* defined CYW20829 */
David Vinczec3084132020-02-18 14:50:47 +0100907
908 rc = flash_area_open(flash_area_id_from_multi_image_slot(image_index, slot),
909 &fap);
910 if (rc != 0) {
911 rc = BOOT_EFLASH;
912 goto done;
913 }
914
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300915 rc = -1;
916 FIH_CALL(bootutil_get_img_security_cnt, fih_rc, hdr, fap, &img_security_cnt);
917 if (fih_eq(fih_rc, FIH_SUCCESS) != FIH_TRUE) {
David Vinczec3084132020-02-18 14:50:47 +0100918 goto done;
919 }
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300920 else
921 {
922 fih_rc = FIH_FAILURE;
923 }
David Vinczec3084132020-02-18 14:50:47 +0100924
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300925#if defined CYW20829
Roman Okhrimenko977b3752022-03-31 14:40:48 +0300926 rc = bootutil_get_img_reprov_packet(hdr, fap, buff);
927 if (rc == 0) {
928 custom_data = (void *)buff;
David Vinczec3084132020-02-18 14:50:47 +0100929 }
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300930#endif /* defined CYW20829 */
David Vinczec3084132020-02-18 14:50:47 +0100931
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300932 rc = boot_nv_security_counter_update(image_index, img_security_cnt, custom_data);
David Vinczec3084132020-02-18 14:50:47 +0100933done:
934 flash_area_close(fap);
935 return rc;
936}
937#endif /* MCUBOOT_HW_ROLLBACK_PROT */
938
David Vinczee574f2d2020-07-10 11:42:03 +0200939/**
940 * Determines which swap operation to perform, if any. If it is determined
941 * that a swap operation is required, the image in the secondary slot is checked
942 * for validity. If the image in the secondary slot is invalid, it is erased,
943 * and a swap type of "none" is indicated.
944 *
945 * @return The type of swap to perform (BOOT_SWAP_TYPE...)
946 */
947static int
948boot_validated_swap_type(struct boot_loader_state *state,
949 struct boot_status *bs)
950{
951 int swap_type;
Raef Colese8fe6cf2020-05-26 13:07:40 +0100952 fih_int fih_rc = FIH_FAILURE;
David Vinczee574f2d2020-07-10 11:42:03 +0200953
954 swap_type = boot_swap_type_multi(BOOT_CURR_IMG(state));
955 if (BOOT_IS_UPGRADE(swap_type)) {
956 /* Boot loader wants to switch to the secondary slot.
957 * Ensure image is valid.
958 */
Raef Colese8fe6cf2020-05-26 13:07:40 +0100959 FIH_CALL(boot_validate_slot, fih_rc, state, BOOT_SECONDARY_SLOT, bs);
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +0300960 if (fih_eq(fih_rc, FIH_SUCCESS) != FIH_TRUE) {
961 if (FIH_TRUE == fih_eq(fih_rc, FIH_SWAP_TYPE_NONE)) {
Raef Colese8fe6cf2020-05-26 13:07:40 +0100962 swap_type = BOOT_SWAP_TYPE_NONE;
963 } else {
964 swap_type = BOOT_SWAP_TYPE_FAIL;
965 }
David Vinczee574f2d2020-07-10 11:42:03 +0200966 }
967 }
968
969 return swap_type;
970}
971
Christopher Collins92ea77f2016-12-12 15:59:26 -0800972/**
Christopher Collins92ea77f2016-12-12 15:59:26 -0800973 * Erases a region of flash.
974 *
Fabio Utzigba829042018-09-18 08:29:34 -0300975 * @param flash_area The flash_area containing the region to erase.
Christopher Collins92ea77f2016-12-12 15:59:26 -0800976 * @param off The offset within the flash area to start the
977 * erase.
978 * @param sz The number of bytes to erase.
979 *
980 * @return 0 on success; nonzero on failure.
981 */
Fabio Utzig12d59162019-11-28 10:01:59 -0300982int
Fabio Utzigc28005b2019-09-10 12:18:29 -0300983boot_erase_region(const struct flash_area *fap, uint32_t off, uint32_t sz)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800984{
Fabio Utzigba829042018-09-18 08:29:34 -0300985 return flash_area_erase(fap, off, sz);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800986}
987
988/**
989 * Copies the contents of one flash region to another. You must erase the
990 * destination region prior to calling this function.
991 *
992 * @param flash_area_id_src The ID of the source flash area.
993 * @param flash_area_id_dst The ID of the destination flash area.
994 * @param off_src The offset within the source flash area to
995 * copy from.
996 * @param off_dst The offset within the destination flash area to
997 * copy to.
998 * @param sz The number of bytes to copy.
999 *
1000 * @return 0 on success; nonzero on failure.
1001 */
Fabio Utzig12d59162019-11-28 10:01:59 -03001002int
Fabio Utzigc28005b2019-09-10 12:18:29 -03001003boot_copy_region(struct boot_loader_state *state,
Fabio Utzig10ee6482019-08-01 12:04:52 -03001004 const struct flash_area *fap_src,
Fabio Utzigba829042018-09-18 08:29:34 -03001005 const struct flash_area *fap_dst,
Christopher Collins92ea77f2016-12-12 15:59:26 -08001006 uint32_t off_src, uint32_t off_dst, uint32_t sz)
1007{
Christopher Collins92ea77f2016-12-12 15:59:26 -08001008 uint32_t bytes_copied;
1009 int chunk_sz;
1010 int rc;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001011#if defined (MCUBOOT_ENC_IMAGES) && !defined(MCUBOOT_ENC_IMAGES_XIP)
Fabio Utzigba829042018-09-18 08:29:34 -03001012 uint32_t off;
Fabio Utziga87cc7d2019-08-26 11:21:45 -03001013 uint32_t tlv_off;
Fabio Utzigba829042018-09-18 08:29:34 -03001014 size_t blk_off;
1015 struct image_header *hdr;
1016 uint16_t idx;
1017 uint32_t blk_sz;
Fabio Utzigb0f04732019-07-31 09:49:19 -03001018 uint8_t image_index;
Fabio Utzigba829042018-09-18 08:29:34 -03001019#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -08001020
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001021/* NOTE:
1022 * Default value 1024 is not suitable for platforms with larger erase size.
1023 * Give user ability to define platform tolerant chunk size. In most cases
1024 * it would be flash erase alignment.
1025 */
1026#ifdef MCUBOOT_PLATFORM_CHUNK_SIZE
1027 #define MCUBOOT_CHUNK_SIZE MCUBOOT_PLATFORM_CHUNK_SIZE
1028#else
1029 #define MCUBOOT_CHUNK_SIZE 1024
1030#endif
Fabio Utzig10ee6482019-08-01 12:04:52 -03001031
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001032 TARGET_STATIC uint8_t buf[MCUBOOT_CHUNK_SIZE] __attribute__((aligned(4)));
1033
1034#if !defined(MCUBOOT_ENC_IMAGES) || defined(MCUBOOT_ENC_IMAGES_XIP)
Fabio Utzig10ee6482019-08-01 12:04:52 -03001035 (void)state;
1036#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -08001037
Christopher Collins92ea77f2016-12-12 15:59:26 -08001038 bytes_copied = 0;
1039 while (bytes_copied < sz) {
1040 if (sz - bytes_copied > sizeof buf) {
1041 chunk_sz = sizeof buf;
1042 } else {
1043 chunk_sz = sz - bytes_copied;
1044 }
1045
1046 rc = flash_area_read(fap_src, off_src + bytes_copied, buf, chunk_sz);
1047 if (rc != 0) {
Fabio Utzigba829042018-09-18 08:29:34 -03001048 return BOOT_EFLASH;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001049 }
1050
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001051#if defined(MCUBOOT_ENC_IMAGES) && !defined(MCUBOOT_ENC_IMAGES_XIP)
Fabio Utzig10ee6482019-08-01 12:04:52 -03001052 image_index = BOOT_CURR_IMG(state);
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001053 if ((flash_area_get_id(fap_src) == FLASH_AREA_IMAGE_PRIMARY(image_index) ||
1054 flash_area_get_id(fap_dst) == FLASH_AREA_IMAGE_PRIMARY(image_index)) &&
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +02001055
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001056 !(flash_area_get_id(fap_src) == FLASH_AREA_IMAGE_PRIMARY(image_index) &&
1057 flash_area_get_id(fap_dst) == FLASH_AREA_IMAGE_PRIMARY(image_index)) &&
1058 !(flash_area_get_id(fap_src) == FLASH_AREA_IMAGE_SECONDARY(image_index) &&
1059 flash_area_get_id(fap_dst) == FLASH_AREA_IMAGE_SECONDARY(image_index)))
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +02001060 {
1061 /* assume the primary slot as src, needs encryption */
1062 hdr = boot_img_hdr(state, BOOT_PRIMARY_SLOT);
Fabio Utzig74aef312019-11-28 11:05:34 -03001063#if !defined(MCUBOOT_SWAP_USING_MOVE)
Fabio Utzigba829042018-09-18 08:29:34 -03001064 off = off_src;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001065 if (flash_area_get_id(fap_dst) == FLASH_AREA_IMAGE_PRIMARY(image_index)) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +02001066 /* might need decryption (metadata from the secondary slot) */
1067 hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT);
Fabio Utzigba829042018-09-18 08:29:34 -03001068 off = off_dst;
1069 }
Fabio Utzig74aef312019-11-28 11:05:34 -03001070#else
1071 off = off_dst;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001072 if (flash_area_get_id(fap_dst) == FLASH_AREA_IMAGE_PRIMARY(image_index)) {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +02001073 hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT);
Fabio Utzig74aef312019-11-28 11:05:34 -03001074 }
1075#endif
Fabio Utzig2fc80df2018-12-14 06:47:38 -02001076 if (IS_ENCRYPTED(hdr)) {
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001077 uint32_t abs_off = off + bytes_copied;
1078 if (abs_off < hdr->ih_hdr_size) {
Fabio Utzigba829042018-09-18 08:29:34 -03001079 /* do not decrypt header */
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001080 if (abs_off + chunk_sz > hdr->ih_hdr_size) {
1081 /* The lower part of the chunk contains header data */
1082 blk_off = 0;
1083 blk_sz = chunk_sz - (hdr->ih_hdr_size - abs_off);
1084 idx = hdr->ih_hdr_size - abs_off;
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +02001085 } else {
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001086 /* The chunk contains exclusively header data */
1087 blk_sz = 0; /* nothing to decrypt */
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +02001088 }
Fabio Utzigba829042018-09-18 08:29:34 -03001089 } else {
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001090 idx = 0;
1091 blk_sz = chunk_sz;
1092 blk_off = (abs_off - hdr->ih_hdr_size) & 0xf;
Fabio Utzigba829042018-09-18 08:29:34 -03001093 }
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001094
1095 if (blk_sz > 0)
1096 {
1097 tlv_off = BOOT_TLV_OFF(hdr);
1098 if (abs_off + chunk_sz > tlv_off) {
1099 /* do not decrypt TLVs */
1100 if (abs_off >= tlv_off) {
1101 blk_sz = 0;
1102 } else {
1103 blk_sz = tlv_off - abs_off;
1104 }
Fabio Utzigba829042018-09-18 08:29:34 -03001105 }
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001106 rc = boot_encrypt(BOOT_CURR_ENC(state), image_index, fap_src,
1107 (abs_off + idx) - hdr->ih_hdr_size, blk_sz,
1108 blk_off, &buf[idx]);
1109 if (rc != 0) {
1110 return rc;
1111 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +02001112 }
Fabio Utzigba829042018-09-18 08:29:34 -03001113 }
1114 }
1115#endif
1116
Christopher Collins92ea77f2016-12-12 15:59:26 -08001117 rc = flash_area_write(fap_dst, off_dst + bytes_copied, buf, chunk_sz);
1118 if (rc != 0) {
Fabio Utzigba829042018-09-18 08:29:34 -03001119 return BOOT_EFLASH;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001120 }
1121
1122 bytes_copied += chunk_sz;
Fabio Utzig853657c2019-05-07 08:06:07 -03001123
1124 MCUBOOT_WATCHDOG_FEED();
Christopher Collins92ea77f2016-12-12 15:59:26 -08001125 }
1126
Fabio Utzigba829042018-09-18 08:29:34 -03001127 return 0;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001128}
1129
Christopher Collins92ea77f2016-12-12 15:59:26 -08001130/**
David Vincze2d736ad2019-02-18 11:50:22 +01001131 * Overwrite primary slot with the image contained in the secondary slot.
1132 * If a prior copy operation was interrupted by a system reset, this function
1133 * redos the copy.
Christopher Collins92ea77f2016-12-12 15:59:26 -08001134 *
1135 * @param bs The current boot status. This function reads
1136 * this struct to determine if it is resuming
1137 * an interrupted swap operation. This
1138 * function writes the updated status to this
1139 * function on return.
1140 *
1141 * @return 0 on success; nonzero on failure.
1142 */
Fabio Utzig338a19f2018-12-03 08:37:08 -02001143#if defined(MCUBOOT_OVERWRITE_ONLY) || defined(MCUBOOT_BOOTSTRAP)
David Brown17609d82017-05-05 09:41:34 -06001144static int
Fabio Utzig10ee6482019-08-01 12:04:52 -03001145boot_copy_image(struct boot_loader_state *state, struct boot_status *bs)
David Brown17609d82017-05-05 09:41:34 -06001146{
Marti Bolivard3269fd2017-06-12 16:31:12 -04001147 size_t sect_count;
1148 size_t sect;
David Brown17609d82017-05-05 09:41:34 -06001149 int rc;
Fabio Utzig13d9e352017-10-05 20:32:31 -03001150 size_t size;
Marti Bolivard3269fd2017-06-12 16:31:12 -04001151 size_t this_size;
Fabio Utzig13d9e352017-10-05 20:32:31 -03001152 size_t last_sector;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001153 const struct flash_area *fap_primary_slot = NULL;
1154 const struct flash_area *fap_secondary_slot = NULL;
Fabio Utzigb0f04732019-07-31 09:49:19 -03001155 uint8_t image_index;
David Vincze2d736ad2019-02-18 11:50:22 +01001156
Fabio Utzigb4f88102020-10-04 10:16:24 -03001157#if defined(MCUBOOT_OVERWRITE_ONLY_FAST)
1158 uint32_t sector;
1159 uint32_t trailer_sz;
1160 uint32_t off;
1161 uint32_t sz;
1162#endif
1163
Fabio Utzigaaf767c2017-12-05 10:22:46 -02001164 (void)bs;
1165
Fabio Utzig13d9e352017-10-05 20:32:31 -03001166#if defined(MCUBOOT_OVERWRITE_ONLY_FAST)
1167 uint32_t src_size = 0;
Fabio Utzigd638b172019-08-09 10:38:05 -03001168 rc = boot_read_image_size(state, BOOT_SECONDARY_SLOT, &src_size);
Fabio Utzig13d9e352017-10-05 20:32:31 -03001169 assert(rc == 0);
1170#endif
David Brown17609d82017-05-05 09:41:34 -06001171
David Vincze2d736ad2019-02-18 11:50:22 +01001172 BOOT_LOG_INF("Image upgrade secondary slot -> primary slot");
1173 BOOT_LOG_INF("Erasing the primary slot");
David Brown17609d82017-05-05 09:41:34 -06001174
Fabio Utzigb0f04732019-07-31 09:49:19 -03001175 image_index = BOOT_CURR_IMG(state);
1176
1177 rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index),
1178 &fap_primary_slot);
Fabio Utzigba829042018-09-18 08:29:34 -03001179 assert (rc == 0);
1180
Fabio Utzigb0f04732019-07-31 09:49:19 -03001181 rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY(image_index),
1182 &fap_secondary_slot);
Fabio Utzigba829042018-09-18 08:29:34 -03001183 assert (rc == 0);
1184
Fabio Utzig10ee6482019-08-01 12:04:52 -03001185 sect_count = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT);
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001186 BOOT_LOG_DBG(" * primary slot sectors: %lu", (unsigned long)sect_count);
Fabio Utzig13d9e352017-10-05 20:32:31 -03001187 for (sect = 0, size = 0; sect < sect_count; sect++) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001188 this_size = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, sect);
Fabio Utzigc28005b2019-09-10 12:18:29 -03001189 rc = boot_erase_region(fap_primary_slot, size, this_size);
David Brown17609d82017-05-05 09:41:34 -06001190 assert(rc == 0);
1191
Fabio Utzig13d9e352017-10-05 20:32:31 -03001192#if defined(MCUBOOT_OVERWRITE_ONLY_FAST)
Fabio Utzigb4f88102020-10-04 10:16:24 -03001193 if ((size + this_size) >= src_size) {
1194 size += src_size - size;
1195 size += BOOT_WRITE_SZ(state) - (size % BOOT_WRITE_SZ(state));
Fabio Utzig13d9e352017-10-05 20:32:31 -03001196 break;
1197 }
1198#endif
Fabio Utzigb4f88102020-10-04 10:16:24 -03001199
1200 size += this_size;
David Brown17609d82017-05-05 09:41:34 -06001201 }
1202
Fabio Utzigb4f88102020-10-04 10:16:24 -03001203#if defined(MCUBOOT_OVERWRITE_ONLY_FAST)
1204 trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(state));
1205 sector = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT) - 1;
1206 sz = 0;
1207 do {
1208 sz += boot_img_sector_size(state, BOOT_PRIMARY_SLOT, sector);
1209 off = boot_img_sector_off(state, BOOT_PRIMARY_SLOT, sector);
1210 sector--;
1211 } while (sz < trailer_sz);
1212
1213 rc = boot_erase_region(fap_primary_slot, off, sz);
1214 assert(rc == 0);
1215#endif
1216
Fabio Utzigba829042018-09-18 08:29:34 -03001217#ifdef MCUBOOT_ENC_IMAGES
Fabio Utzig10ee6482019-08-01 12:04:52 -03001218 if (IS_ENCRYPTED(boot_img_hdr(state, BOOT_SECONDARY_SLOT))) {
Fabio Utzig1e4284b2019-08-23 11:55:27 -03001219 rc = boot_enc_load(BOOT_CURR_ENC(state), image_index,
Fabio Utzig10ee6482019-08-01 12:04:52 -03001220 boot_img_hdr(state, BOOT_SECONDARY_SLOT),
Fabio Utzig4741c452019-12-19 15:32:41 -03001221 fap_secondary_slot, bs);
David Vincze2d736ad2019-02-18 11:50:22 +01001222
Fabio Utzigba829042018-09-18 08:29:34 -03001223 if (rc < 0) {
1224 return BOOT_EBADIMAGE;
1225 }
Fabio Utzig4741c452019-12-19 15:32:41 -03001226 if (rc == 0 && boot_enc_set_key(BOOT_CURR_ENC(state), 1, bs)) {
Fabio Utzigba829042018-09-18 08:29:34 -03001227 return BOOT_EBADIMAGE;
1228 }
1229 }
1230#endif
1231
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001232 BOOT_LOG_INF("Copying the secondary slot to the primary slot: 0x%lx bytes", (unsigned long)size);
Fabio Utzigc28005b2019-09-10 12:18:29 -03001233 rc = boot_copy_region(state, fap_secondary_slot, fap_primary_slot, 0, 0, size);
Fabio Utzigb4f88102020-10-04 10:16:24 -03001234 if (rc != 0) {
1235 return rc;
1236 }
1237
1238#if defined(MCUBOOT_OVERWRITE_ONLY_FAST)
1239 rc = boot_write_magic(fap_primary_slot);
1240 if (rc != 0) {
1241 return rc;
1242 }
1243#endif
David Brown17609d82017-05-05 09:41:34 -06001244
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001245 rc = BOOT_HOOK_CALL(boot_copy_region_post_hook, 0, BOOT_CURR_IMG(state),
1246 BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT), size);
1247 if (rc != 0) {
1248 return rc;
1249 }
1250
David Vinczec3084132020-02-18 14:50:47 +01001251#ifdef MCUBOOT_HW_ROLLBACK_PROT
1252 /* Update the stored security counter with the new image's security counter
1253 * value. Both slots hold the new image at this point, but the secondary
1254 * slot's image header must be passed since the image headers in the
1255 * boot_data structure have not been updated yet.
1256 */
1257 rc = boot_update_security_counter(BOOT_CURR_IMG(state), BOOT_PRIMARY_SLOT,
1258 boot_img_hdr(state, BOOT_SECONDARY_SLOT));
1259 if (rc != 0) {
1260 BOOT_LOG_ERR("Security counter update failed after image upgrade.");
1261 return rc;
1262 }
1263#endif /* MCUBOOT_HW_ROLLBACK_PROT */
1264
Fabio Utzig13d9e352017-10-05 20:32:31 -03001265 /*
1266 * Erases header and trailer. The trailer is erased because when a new
1267 * image is written without a trailer as is the case when using newt, the
1268 * trailer that was left might trigger a new upgrade.
1269 */
Christopher Collins2c88e692019-05-22 15:10:14 -07001270 BOOT_LOG_DBG("erasing secondary header");
Fabio Utzigc28005b2019-09-10 12:18:29 -03001271 rc = boot_erase_region(fap_secondary_slot,
Fabio Utzig10ee6482019-08-01 12:04:52 -03001272 boot_img_sector_off(state, BOOT_SECONDARY_SLOT, 0),
1273 boot_img_sector_size(state, BOOT_SECONDARY_SLOT, 0));
David Brown17609d82017-05-05 09:41:34 -06001274 assert(rc == 0);
Fabio Utzig10ee6482019-08-01 12:04:52 -03001275 last_sector = boot_img_num_sectors(state, BOOT_SECONDARY_SLOT) - 1;
Christopher Collins2c88e692019-05-22 15:10:14 -07001276 BOOT_LOG_DBG("erasing secondary trailer");
Fabio Utzigc28005b2019-09-10 12:18:29 -03001277 rc = boot_erase_region(fap_secondary_slot,
Fabio Utzig10ee6482019-08-01 12:04:52 -03001278 boot_img_sector_off(state, BOOT_SECONDARY_SLOT,
1279 last_sector),
1280 boot_img_sector_size(state, BOOT_SECONDARY_SLOT,
1281 last_sector));
Fabio Utzig13d9e352017-10-05 20:32:31 -03001282 assert(rc == 0);
1283
David Vincze2d736ad2019-02-18 11:50:22 +01001284 flash_area_close(fap_primary_slot);
1285 flash_area_close(fap_secondary_slot);
Fabio Utzigba829042018-09-18 08:29:34 -03001286
David Vincze2d736ad2019-02-18 11:50:22 +01001287 /* TODO: Perhaps verify the primary slot's signature again? */
David Brown17609d82017-05-05 09:41:34 -06001288
1289 return 0;
1290}
Fabio Utzig338a19f2018-12-03 08:37:08 -02001291#endif
Fabio Utzigba829042018-09-18 08:29:34 -03001292
Christopher Collinsa1c12042019-05-23 14:00:28 -07001293#if !defined(MCUBOOT_OVERWRITE_ONLY)
Fabio Utzigba829042018-09-18 08:29:34 -03001294/**
1295 * Swaps the two images in flash. If a prior copy operation was interrupted
1296 * by a system reset, this function completes that operation.
1297 *
1298 * @param bs The current boot status. This function reads
1299 * this struct to determine if it is resuming
1300 * an interrupted swap operation. This
1301 * function writes the updated status to this
1302 * function on return.
1303 *
1304 * @return 0 on success; nonzero on failure.
1305 */
Christopher Collins92ea77f2016-12-12 15:59:26 -08001306static int
Fabio Utzig10ee6482019-08-01 12:04:52 -03001307boot_swap_image(struct boot_loader_state *state, struct boot_status *bs)
Christopher Collins92ea77f2016-12-12 15:59:26 -08001308{
Fabio Utzig2473ac02017-05-02 12:45:02 -03001309 struct image_header *hdr;
Fabio Utzigba829042018-09-18 08:29:34 -03001310#ifdef MCUBOOT_ENC_IMAGES
1311 const struct flash_area *fap;
1312 uint8_t slot;
Fabio Utzigba829042018-09-18 08:29:34 -03001313#endif
Fabio Utzig2473ac02017-05-02 12:45:02 -03001314 uint32_t size;
1315 uint32_t copy_size;
Fabio Utzigb0f04732019-07-31 09:49:19 -03001316 uint8_t image_index;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001317 int rc = -1;
Fabio Utzig2473ac02017-05-02 12:45:02 -03001318
1319 /* FIXME: just do this if asked by user? */
1320
1321 size = copy_size = 0;
Fabio Utzig10ee6482019-08-01 12:04:52 -03001322 image_index = BOOT_CURR_IMG(state);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001323
Fabio Utzig12d59162019-11-28 10:01:59 -03001324 if (boot_status_is_reset(bs)) {
Fabio Utzig46490722017-09-04 15:34:32 -03001325 /*
1326 * No swap ever happened, so need to find the largest image which
1327 * will be used to determine the amount of sectors to swap.
1328 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001329 hdr = boot_img_hdr(state, BOOT_PRIMARY_SLOT);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001330 if (hdr->ih_magic == IMAGE_MAGIC) {
Fabio Utzigd638b172019-08-09 10:38:05 -03001331 rc = boot_read_image_size(state, BOOT_PRIMARY_SLOT, &copy_size);
David Brownf5b33d82017-09-01 10:58:27 -06001332 assert(rc == 0);
Fabio Utzig2473ac02017-05-02 12:45:02 -03001333 }
Fabio Utzig2473ac02017-05-02 12:45:02 -03001334
Fabio Utzigba829042018-09-18 08:29:34 -03001335#ifdef MCUBOOT_ENC_IMAGES
Fabio Utzig2fc80df2018-12-14 06:47:38 -02001336 if (IS_ENCRYPTED(hdr)) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001337 fap = BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT);
Fabio Utzig4741c452019-12-19 15:32:41 -03001338 rc = boot_enc_load(BOOT_CURR_ENC(state), image_index, hdr, fap, bs);
Fabio Utzigba829042018-09-18 08:29:34 -03001339 assert(rc >= 0);
1340
1341 if (rc == 0) {
Fabio Utzig4741c452019-12-19 15:32:41 -03001342 rc = boot_enc_set_key(BOOT_CURR_ENC(state), 0, bs);
Fabio Utzigba829042018-09-18 08:29:34 -03001343 assert(rc == 0);
1344 } else {
1345 rc = 0;
1346 }
1347 } else {
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001348 (void)memset(bs->enckey[0], BOOT_UNINITIALIZED_KEY_FILL,
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001349 BOOT_ENC_KEY_ALIGN_SIZE);
Fabio Utzigba829042018-09-18 08:29:34 -03001350 }
1351#endif
1352
Fabio Utzig10ee6482019-08-01 12:04:52 -03001353 hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT);
Fabio Utzig46490722017-09-04 15:34:32 -03001354 if (hdr->ih_magic == IMAGE_MAGIC) {
Fabio Utzigd638b172019-08-09 10:38:05 -03001355 rc = boot_read_image_size(state, BOOT_SECONDARY_SLOT, &size);
Fabio Utzig46490722017-09-04 15:34:32 -03001356 assert(rc == 0);
1357 }
1358
Fabio Utzigba829042018-09-18 08:29:34 -03001359#ifdef MCUBOOT_ENC_IMAGES
Fabio Utzig10ee6482019-08-01 12:04:52 -03001360 hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT);
Fabio Utzig2fc80df2018-12-14 06:47:38 -02001361 if (IS_ENCRYPTED(hdr)) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001362 fap = BOOT_IMG_AREA(state, BOOT_SECONDARY_SLOT);
Fabio Utzig4741c452019-12-19 15:32:41 -03001363 rc = boot_enc_load(BOOT_CURR_ENC(state), image_index, hdr, fap, bs);
Fabio Utzigba829042018-09-18 08:29:34 -03001364 assert(rc >= 0);
1365
1366 if (rc == 0) {
Fabio Utzig4741c452019-12-19 15:32:41 -03001367 rc = boot_enc_set_key(BOOT_CURR_ENC(state), 1, bs);
Fabio Utzigba829042018-09-18 08:29:34 -03001368 assert(rc == 0);
1369 } else {
1370 rc = 0;
1371 }
1372 } else {
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001373 (void)memset(bs->enckey[1], BOOT_UNINITIALIZED_KEY_FILL,
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001374 BOOT_ENC_KEY_ALIGN_SIZE);
Fabio Utzigba829042018-09-18 08:29:34 -03001375 }
1376#endif
1377
Fabio Utzig46490722017-09-04 15:34:32 -03001378 if (size > copy_size) {
1379 copy_size = size;
1380 }
1381
1382 bs->swap_size = copy_size;
1383 } else {
1384 /*
1385 * If a swap was under way, the swap_size should already be present
1386 * in the trailer...
1387 */
Fabio Utzigb0f04732019-07-31 09:49:19 -03001388 rc = boot_read_swap_size(image_index, &bs->swap_size);
Fabio Utzig46490722017-09-04 15:34:32 -03001389 assert(rc == 0);
1390
1391 copy_size = bs->swap_size;
Fabio Utzigba829042018-09-18 08:29:34 -03001392
1393#ifdef MCUBOOT_ENC_IMAGES
Fabio Utzig4741c452019-12-19 15:32:41 -03001394 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
1395 rc = boot_read_enc_key(image_index, slot, bs);
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001396 assert(0 == rc);
Fabio Utzigba829042018-09-18 08:29:34 -03001397
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001398 /* Set only an initialized key */
1399 if (!bootutil_buffer_is_filled(bs->enckey[slot],
1400 BOOT_UNINITIALIZED_KEY_FILL,
1401 BOOT_ENC_KEY_SIZE)) {
1402 rc = boot_enc_set_key(BOOT_CURR_ENC(state), slot, bs);
1403 assert(rc == 0);
Fabio Utzigba829042018-09-18 08:29:34 -03001404 }
1405 }
1406#endif
Fabio Utzig2473ac02017-05-02 12:45:02 -03001407 }
1408
Fabio Utzig12d59162019-11-28 10:01:59 -03001409 swap_run(state, bs, copy_size);
Christopher Collins92ea77f2016-12-12 15:59:26 -08001410
David Vincze2d736ad2019-02-18 11:50:22 +01001411#ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT
Fabio Utzig12d59162019-11-28 10:01:59 -03001412 extern int boot_status_fails;
Fabio Utziga0e1cce2017-11-23 20:04:01 -02001413 if (boot_status_fails > 0) {
Christopher Collins2c88e692019-05-22 15:10:14 -07001414 BOOT_LOG_WRN("%d status write fails performing the swap",
1415 boot_status_fails);
Fabio Utziga0e1cce2017-11-23 20:04:01 -02001416 }
1417#endif
1418
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001419 return rc;
Christopher Collins92ea77f2016-12-12 15:59:26 -08001420}
David Brown17609d82017-05-05 09:41:34 -06001421#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -08001422
David Vinczee32483f2019-06-13 10:46:24 +02001423#if (BOOT_IMAGE_NUMBER > 1)
1424/**
1425 * Check the image dependency whether it is satisfied and modify
1426 * the swap type if necessary.
1427 *
1428 * @param dep Image dependency which has to be verified.
1429 *
1430 * @return 0 on success; nonzero on failure.
1431 */
1432static int
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001433boot_verify_slot_dependency_flash(struct boot_loader_state *state, struct image_dependency *dep)
David Vinczee32483f2019-06-13 10:46:24 +02001434{
1435 struct image_version *dep_version;
1436 size_t dep_slot;
1437 int rc;
David Browne6ab34c2019-09-03 12:24:21 -06001438 uint8_t swap_type;
David Vinczee32483f2019-06-13 10:46:24 +02001439
1440 /* Determine the source of the image which is the subject of
1441 * the dependency and get it's version. */
David Browne6ab34c2019-09-03 12:24:21 -06001442 swap_type = state->swap_type[dep->image_id];
Barry Solomon04075532020-03-18 09:33:32 -04001443 dep_slot = BOOT_IS_UPGRADE(swap_type) ? BOOT_SECONDARY_SLOT
1444 : BOOT_PRIMARY_SLOT;
Fabio Utzig10ee6482019-08-01 12:04:52 -03001445 dep_version = &state->imgs[dep->image_id][dep_slot].hdr.ih_ver;
David Vinczee32483f2019-06-13 10:46:24 +02001446
David Vincze8b0b6372020-05-20 19:54:44 +02001447 rc = boot_version_cmp(dep_version, &dep->image_min_version);
1448 if (rc < 0) {
David Vinczee32483f2019-06-13 10:46:24 +02001449 /* Dependency not satisfied.
1450 * Modify the swap type to decrease the version number of the image
1451 * (which will be located in the primary slot after the boot process),
1452 * consequently the number of unsatisfied dependencies will be
1453 * decreased or remain the same.
1454 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001455 switch (BOOT_SWAP_TYPE(state)) {
David Vinczee32483f2019-06-13 10:46:24 +02001456 case BOOT_SWAP_TYPE_TEST:
1457 case BOOT_SWAP_TYPE_PERM:
Fabio Utzig10ee6482019-08-01 12:04:52 -03001458 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
David Vinczee32483f2019-06-13 10:46:24 +02001459 break;
1460 case BOOT_SWAP_TYPE_NONE:
Fabio Utzig10ee6482019-08-01 12:04:52 -03001461 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_REVERT;
David Vinczee32483f2019-06-13 10:46:24 +02001462 break;
1463 default:
1464 break;
1465 }
David Vincze8b0b6372020-05-20 19:54:44 +02001466 } else {
1467 /* Dependency satisfied. */
1468 rc = 0;
David Vinczee32483f2019-06-13 10:46:24 +02001469 }
1470
1471 return rc;
1472}
1473
1474/**
1475 * Read all dependency TLVs of an image from the flash and verify
1476 * one after another to see if they are all satisfied.
1477 *
1478 * @param slot Image slot number.
1479 *
1480 * @return 0 on success; nonzero on failure.
1481 */
1482static int
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001483boot_verify_slot_dependencies_flash(struct boot_loader_state *state, uint32_t slot)
David Vinczee32483f2019-06-13 10:46:24 +02001484{
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001485 const struct flash_area *fap = NULL;
Fabio Utzig61fd8882019-09-14 20:00:20 -03001486 struct image_tlv_iter it;
David Vinczee32483f2019-06-13 10:46:24 +02001487 struct image_dependency dep;
1488 uint32_t off;
Fabio Utzig61fd8882019-09-14 20:00:20 -03001489 uint16_t len;
Fabio Utzigb0f04732019-07-31 09:49:19 -03001490 int area_id;
David Vinczee32483f2019-06-13 10:46:24 +02001491 int rc;
1492
Fabio Utzig10ee6482019-08-01 12:04:52 -03001493 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
Fabio Utzigb0f04732019-07-31 09:49:19 -03001494 rc = flash_area_open(area_id, &fap);
David Vinczee32483f2019-06-13 10:46:24 +02001495 if (rc != 0) {
1496 rc = BOOT_EFLASH;
1497 goto done;
1498 }
1499
Fabio Utzig61fd8882019-09-14 20:00:20 -03001500 rc = bootutil_tlv_iter_begin(&it, boot_img_hdr(state, slot), fap,
1501 IMAGE_TLV_DEPENDENCY, true);
David Vinczee32483f2019-06-13 10:46:24 +02001502 if (rc != 0) {
David Vinczee32483f2019-06-13 10:46:24 +02001503 goto done;
1504 }
1505
Fabio Utzig61fd8882019-09-14 20:00:20 -03001506 while (true) {
1507 rc = bootutil_tlv_iter_next(&it, &off, &len, NULL);
1508 if (rc < 0) {
1509 return -1;
1510 } else if (rc > 0) {
1511 rc = 0;
David Vinczee32483f2019-06-13 10:46:24 +02001512 break;
1513 }
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001514 else
1515 {
1516 /* acc. to MISRA R.15.7 */
1517 }
Fabio Utzig61fd8882019-09-14 20:00:20 -03001518
1519 if (len != sizeof(dep)) {
1520 rc = BOOT_EBADIMAGE;
1521 goto done;
1522 }
1523
1524 rc = flash_area_read(fap, off, &dep, len);
1525 if (rc != 0) {
1526 rc = BOOT_EFLASH;
1527 goto done;
1528 }
1529
1530 if (dep.image_id >= BOOT_IMAGE_NUMBER) {
1531 rc = BOOT_EBADARGS;
1532 goto done;
1533 }
1534
1535 /* Verify dependency and modify the swap type if not satisfied. */
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001536 rc = boot_verify_slot_dependency_flash(state, &dep);
Fabio Utzig61fd8882019-09-14 20:00:20 -03001537 if (rc != 0) {
1538 /* Dependency not satisfied. */
1539 goto done;
1540 }
David Vinczee32483f2019-06-13 10:46:24 +02001541 }
1542
1543done:
1544 flash_area_close(fap);
1545 return rc;
1546}
1547
1548/**
David Vinczee32483f2019-06-13 10:46:24 +02001549 * Iterate over all the images and verify whether the image dependencies in the
1550 * TLV area are all satisfied and update the related swap type if necessary.
1551 */
Fabio Utzig298913b2019-08-28 11:22:45 -03001552static int
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001553boot_verify_dependencies_flash(struct boot_loader_state *state)
David Vinczee32483f2019-06-13 10:46:24 +02001554{
Erik Johnson49063752020-02-06 09:59:31 -06001555 int rc = -1;
Fabio Utzig298913b2019-08-28 11:22:45 -03001556 uint8_t slot;
David Vinczee32483f2019-06-13 10:46:24 +02001557
Fabio Utzig10ee6482019-08-01 12:04:52 -03001558 BOOT_CURR_IMG(state) = 0;
1559 while (BOOT_CURR_IMG(state) < BOOT_IMAGE_NUMBER) {
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001560 if (state->img_mask[BOOT_CURR_IMG(state)]) {
1561 BOOT_CURR_IMG(state)++;
1562 continue;
1563 }
Fabio Utzig298913b2019-08-28 11:22:45 -03001564 if (BOOT_SWAP_TYPE(state) != BOOT_SWAP_TYPE_NONE &&
1565 BOOT_SWAP_TYPE(state) != BOOT_SWAP_TYPE_FAIL) {
1566 slot = BOOT_SECONDARY_SLOT;
1567 } else {
1568 slot = BOOT_PRIMARY_SLOT;
1569 }
1570
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001571 rc = boot_verify_slot_dependencies_flash(state, slot);
Fabio Utzigabec0732019-07-31 08:40:22 -03001572 if (rc == 0) {
David Vinczee32483f2019-06-13 10:46:24 +02001573 /* All dependencies've been satisfied, continue with next image. */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001574 BOOT_CURR_IMG(state)++;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001575 } else {
1576#if (USE_SHARED_SLOT == 1)
1577 /* Disable an upgrading of this image.*/
1578 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
1579 BOOT_CURR_IMG(state)++;
1580#else
Fabio Utzig298913b2019-08-28 11:22:45 -03001581 /* Cannot upgrade due to non-met dependencies, so disable all
1582 * image upgrades.
1583 */
1584 for (int idx = 0; idx < BOOT_IMAGE_NUMBER; idx++) {
1585 BOOT_CURR_IMG(state) = idx;
1586 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
1587 }
1588 break;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001589#endif /* (USE_SHARED_SLOT == 1) */
David Vinczee32483f2019-06-13 10:46:24 +02001590 }
1591 }
Fabio Utzig298913b2019-08-28 11:22:45 -03001592 return rc;
David Vinczee32483f2019-06-13 10:46:24 +02001593}
1594#endif /* (BOOT_IMAGE_NUMBER > 1) */
1595
Christopher Collins92ea77f2016-12-12 15:59:26 -08001596/**
David Vinczeba3bd602019-06-17 16:01:43 +02001597 * Performs a clean (not aborted) image update.
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001598 *
David Vinczeba3bd602019-06-17 16:01:43 +02001599 * @param bs The current boot status.
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001600 *
1601 * @return 0 on success; nonzero on failure.
1602 */
1603static int
Fabio Utzig10ee6482019-08-01 12:04:52 -03001604boot_perform_update(struct boot_loader_state *state, struct boot_status *bs)
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001605{
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001606 int rc;
Fabio Utzig10ee6482019-08-01 12:04:52 -03001607#ifndef MCUBOOT_OVERWRITE_ONLY
1608 uint8_t swap_type;
1609#endif
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001610
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001611 BOOT_LOG_DBG("> boot_perform_update: bs->idx = %" PRIu32, bs->idx);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +02001612
David Vinczeba3bd602019-06-17 16:01:43 +02001613 /* At this point there are no aborted swaps. */
1614#if defined(MCUBOOT_OVERWRITE_ONLY)
Fabio Utzig10ee6482019-08-01 12:04:52 -03001615 rc = boot_copy_image(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02001616#elif defined(MCUBOOT_BOOTSTRAP)
1617 /* Check if the image update was triggered by a bad image in the
1618 * primary slot (the validity of the image in the secondary slot had
1619 * already been checked).
1620 */
Raef Colese8fe6cf2020-05-26 13:07:40 +01001621 fih_int fih_rc = FIH_FAILURE;
1622 rc = boot_check_header_erased(state, BOOT_PRIMARY_SLOT);
1623 FIH_CALL(boot_validate_slot, fih_rc, state, BOOT_PRIMARY_SLOT, bs);
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001624 if (rc == 0 || fih_eq(fih_rc, FIH_SUCCESS) != FIH_TRUE) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001625 /* Initialize swap status partition for primary slot, because
1626 * in swap mode it is needed to properly complete copying the image
1627 * to the primary slot.
1628 */
1629 const struct flash_area *fap_primary_slot = NULL;
1630
1631 rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state)),
1632 &fap_primary_slot);
1633 assert(rc == 0);
1634
1635 rc = swap_status_init(state, fap_primary_slot, bs);
1636 assert(rc == 0);
1637
1638 flash_area_close(fap_primary_slot);
1639
Fabio Utzig10ee6482019-08-01 12:04:52 -03001640 rc = boot_copy_image(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02001641 } else {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001642 rc = boot_swap_image(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02001643 }
1644#else
Fabio Utzig10ee6482019-08-01 12:04:52 -03001645 rc = boot_swap_image(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02001646#endif
Fabio Utzig7ebb7c22017-04-26 10:59:31 -03001647 assert(rc == 0);
David Vinczeba3bd602019-06-17 16:01:43 +02001648
1649#ifndef MCUBOOT_OVERWRITE_ONLY
1650 /* The following state needs image_ok be explicitly set after the
1651 * swap was finished to avoid a new revert.
1652 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001653 swap_type = BOOT_SWAP_TYPE(state);
1654 if (swap_type == BOOT_SWAP_TYPE_REVERT ||
1655 swap_type == BOOT_SWAP_TYPE_PERM) {
Fabio Utzig12d59162019-11-28 10:01:59 -03001656 rc = swap_set_image_ok(BOOT_CURR_IMG(state));
David Vinczeba3bd602019-06-17 16:01:43 +02001657 if (rc != 0) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001658 BOOT_SWAP_TYPE(state) = swap_type = BOOT_SWAP_TYPE_PANIC;
David Vinczeba3bd602019-06-17 16:01:43 +02001659 }
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08001660 }
1661
David Vinczec3084132020-02-18 14:50:47 +01001662#ifdef MCUBOOT_HW_ROLLBACK_PROT
1663 if (swap_type == BOOT_SWAP_TYPE_PERM) {
1664 /* Update the stored security counter with the new image's security
1665 * counter value. The primary slot holds the new image at this point,
1666 * but the secondary slot's image header must be passed since image
1667 * headers in the boot_data structure have not been updated yet.
1668 *
1669 * In case of a permanent image swap mcuboot will never attempt to
1670 * revert the images on the next reboot. Therefore, the security
1671 * counter must be increased right after the image upgrade.
1672 */
1673 rc = boot_update_security_counter(
1674 BOOT_CURR_IMG(state),
1675 BOOT_PRIMARY_SLOT,
1676 boot_img_hdr(state, BOOT_SECONDARY_SLOT));
1677 if (rc != 0) {
1678 BOOT_LOG_ERR("Security counter update failed after "
1679 "image upgrade.");
1680 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
1681 }
1682 }
1683#endif /* MCUBOOT_HW_ROLLBACK_PROT */
1684
Fabio Utzige575b0b2019-09-11 12:34:23 -03001685 if (BOOT_IS_UPGRADE(swap_type)) {
Fabio Utzig12d59162019-11-28 10:01:59 -03001686 rc = swap_set_copy_done(BOOT_CURR_IMG(state));
David Vinczeba3bd602019-06-17 16:01:43 +02001687 if (rc != 0) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001688 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
Christopher Collinsa1c12042019-05-23 14:00:28 -07001689 }
David Vinczeba3bd602019-06-17 16:01:43 +02001690 }
1691#endif /* !MCUBOOT_OVERWRITE_ONLY */
Fabio Utzig338a19f2018-12-03 08:37:08 -02001692
David Vinczeba3bd602019-06-17 16:01:43 +02001693 return rc;
1694}
1695
1696/**
1697 * Completes a previously aborted image swap.
1698 *
1699 * @param bs The current boot status.
1700 *
1701 * @return 0 on success; nonzero on failure.
1702 */
1703#if !defined(MCUBOOT_OVERWRITE_ONLY)
1704static int
Fabio Utzig10ee6482019-08-01 12:04:52 -03001705boot_complete_partial_swap(struct boot_loader_state *state,
1706 struct boot_status *bs)
David Vinczeba3bd602019-06-17 16:01:43 +02001707{
1708 int rc;
1709
1710 /* Determine the type of swap operation being resumed from the
1711 * `swap-type` trailer field.
1712 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001713 rc = boot_swap_image(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02001714 assert(rc == 0);
1715
Fabio Utzig10ee6482019-08-01 12:04:52 -03001716 BOOT_SWAP_TYPE(state) = bs->swap_type;
David Vinczeba3bd602019-06-17 16:01:43 +02001717
1718 /* The following states need image_ok be explicitly set after the
1719 * swap was finished to avoid a new revert.
1720 */
1721 if (bs->swap_type == BOOT_SWAP_TYPE_REVERT ||
1722 bs->swap_type == BOOT_SWAP_TYPE_PERM) {
Fabio Utzig12d59162019-11-28 10:01:59 -03001723 rc = swap_set_image_ok(BOOT_CURR_IMG(state));
David Vinczeba3bd602019-06-17 16:01:43 +02001724 if (rc != 0) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001725 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
David Vinczeba3bd602019-06-17 16:01:43 +02001726 }
1727 }
1728
Fabio Utzige575b0b2019-09-11 12:34:23 -03001729 if (BOOT_IS_UPGRADE(bs->swap_type)) {
Fabio Utzig12d59162019-11-28 10:01:59 -03001730 rc = swap_set_copy_done(BOOT_CURR_IMG(state));
David Vinczeba3bd602019-06-17 16:01:43 +02001731 if (rc != 0) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001732 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
David Vinczeba3bd602019-06-17 16:01:43 +02001733 }
1734 }
1735
Fabio Utzig10ee6482019-08-01 12:04:52 -03001736 if (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_PANIC) {
David Vinczeba3bd602019-06-17 16:01:43 +02001737 BOOT_LOG_ERR("panic!");
1738 assert(0);
1739
1740 /* Loop forever... */
1741 while (1) {}
1742 }
1743
1744 return rc;
1745}
1746#endif /* !MCUBOOT_OVERWRITE_ONLY */
1747
1748#if (BOOT_IMAGE_NUMBER > 1)
1749/**
1750 * Review the validity of previously determined swap types of other images.
1751 *
1752 * @param aborted_swap The current image upgrade is a
1753 * partial/aborted swap.
1754 */
1755static void
Fabio Utzig10ee6482019-08-01 12:04:52 -03001756boot_review_image_swap_types(struct boot_loader_state *state,
1757 bool aborted_swap)
David Vinczeba3bd602019-06-17 16:01:43 +02001758{
1759 /* In that case if we rebooted in the middle of an image upgrade process, we
1760 * must review the validity of swap types, that were previously determined
1761 * for other images. The image_ok flag had not been set before the reboot
1762 * for any of the updated images (only the copy_done flag) and thus falsely
1763 * the REVERT swap type has been determined for the previous images that had
1764 * been updated before the reboot.
1765 *
1766 * There are two separate scenarios that we have to deal with:
1767 *
1768 * 1. The reboot has happened during swapping an image:
1769 * The current image upgrade has been determined as a
1770 * partial/aborted swap.
1771 * 2. The reboot has happened between two separate image upgrades:
1772 * In this scenario we must check the swap type of the current image.
1773 * In those cases if it is NONE or REVERT we cannot certainly determine
1774 * the fact of a reboot. In a consistent state images must move in the
1775 * same direction or stay in place, e.g. in practice REVERT and TEST
1776 * swap types cannot be present at the same time. If the swap type of
1777 * the current image is either TEST, PERM or FAIL we must review the
1778 * already determined swap types of other images and set each false
1779 * REVERT swap types to NONE (these images had been successfully
1780 * updated before the system rebooted between two separate image
1781 * upgrades).
1782 */
1783
Fabio Utzig10ee6482019-08-01 12:04:52 -03001784 if (BOOT_CURR_IMG(state) == 0) {
David Vinczeba3bd602019-06-17 16:01:43 +02001785 /* Nothing to do */
1786 return;
1787 }
1788
1789 if (!aborted_swap) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001790 if ((BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_NONE) ||
1791 (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_REVERT)) {
David Vinczeba3bd602019-06-17 16:01:43 +02001792 /* Nothing to do */
1793 return;
1794 }
1795 }
1796
Fabio Utzig10ee6482019-08-01 12:04:52 -03001797 for (uint8_t i = 0; i < BOOT_CURR_IMG(state); i++) {
1798 if (state->swap_type[i] == BOOT_SWAP_TYPE_REVERT) {
1799 state->swap_type[i] = BOOT_SWAP_TYPE_NONE;
David Vinczeba3bd602019-06-17 16:01:43 +02001800 }
1801 }
1802}
1803#endif
1804
1805/**
1806 * Prepare image to be updated if required.
1807 *
1808 * Prepare image to be updated if required with completing an image swap
1809 * operation if one was aborted and/or determining the type of the
1810 * swap operation. In case of any error set the swap type to NONE.
1811 *
Fabio Utzig10ee6482019-08-01 12:04:52 -03001812 * @param state TODO
David Vinczeba3bd602019-06-17 16:01:43 +02001813 * @param bs Pointer where the read and possibly updated
1814 * boot status can be written to.
1815 */
1816static void
Fabio Utzig10ee6482019-08-01 12:04:52 -03001817boot_prepare_image_for_update(struct boot_loader_state *state,
1818 struct boot_status *bs)
David Vinczeba3bd602019-06-17 16:01:43 +02001819{
1820 int rc;
Raef Colese8fe6cf2020-05-26 13:07:40 +01001821 fih_int fih_rc = FIH_FAILURE;
David Vinczeba3bd602019-06-17 16:01:43 +02001822
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001823 BOOT_LOG_DBG("> boot_prepare_image_for_update: image = %u",
1824 (unsigned)BOOT_CURR_IMG(state));
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +02001825
David Vinczeba3bd602019-06-17 16:01:43 +02001826 /* Determine the sector layout of the image slots and scratch area. */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001827 rc = boot_read_sectors(state);
David Vinczeba3bd602019-06-17 16:01:43 +02001828 if (rc != 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001829 BOOT_LOG_WRN("Failed reading sectors; BOOT_MAX_IMG_SECTORS=%u"
1830 " - too small?", (unsigned int) BOOT_MAX_IMG_SECTORS);
David Vinczeba3bd602019-06-17 16:01:43 +02001831 /* Unable to determine sector layout, continue with next image
1832 * if there is one.
1833 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001834 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001835 if (rc == BOOT_EFLASH)
1836 {
1837 /* Only return on error from the primary image flash */
1838 return;
1839 }
David Vinczeba3bd602019-06-17 16:01:43 +02001840 }
1841
1842 /* Attempt to read an image header from each slot. */
Fabio Utzig12d59162019-11-28 10:01:59 -03001843 rc = boot_read_image_headers(state, false, NULL);
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001844 BOOT_LOG_DBG(" * Read an image (%u) header from each slot: rc = %d",
1845 (unsigned)BOOT_CURR_IMG(state), rc);
David Vinczeba3bd602019-06-17 16:01:43 +02001846 if (rc != 0) {
1847 /* Continue with next image if there is one. */
Fabio Utzigb0f04732019-07-31 09:49:19 -03001848 BOOT_LOG_WRN("Failed reading image headers; Image=%u",
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001849 (unsigned)BOOT_CURR_IMG(state));
Fabio Utzig10ee6482019-08-01 12:04:52 -03001850 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
David Vinczeba3bd602019-06-17 16:01:43 +02001851 return;
1852 }
1853
1854 /* If the current image's slots aren't compatible, no swap is possible.
1855 * Just boot into primary slot.
1856 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001857 if (boot_slots_compatible(state)) {
Fabio Utzig12d59162019-11-28 10:01:59 -03001858 boot_status_reset(bs);
1859
1860#ifndef MCUBOOT_OVERWRITE_ONLY
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001861#ifdef MCUBOOT_SWAP_USING_STATUS
1862
1863 const struct flash_area *fap;
1864 uint32_t img_size = 0;
1865
1866 /* Check here if image firmware + tlvs in slot do not
1867 * overlap with last sector of slot. Last sector of slot
1868 * contains trailer of the image which needs to be
1869 * manupulated independently of other image parts.
1870 * If firmware overlaps with trailer sector it does not
1871 * make sense to move further since any attemps to perform
1872 * swap upgrade would lead to failure or unexpected behaviour
1873 */
1874
1875 for (uint32_t i = 0; i < BOOT_NUM_SLOTS; i++) {
1876
1877 rc = boot_read_image_size(state, i, &img_size);
1878
1879 if (rc == 0) {
1880 fap = BOOT_IMG(state, i).area;
1881 if (fap != NULL) {
1882
1883 uint32_t trailer_sector_off = (BOOT_WRITE_SZ(state)) * boot_img_num_sectors(state, i) - BOOT_WRITE_SZ(state);
1884
1885 BOOT_LOG_DBG("Slot %u firmware + tlvs size = %u, slot size = %u, write_size = %u, write_size * sect_num - write_size = %u",
1886 i , img_size, fap->fa_size, BOOT_WRITE_SZ(state), trailer_sector_off);
1887
1888 if (img_size > trailer_sector_off) {
1889 BOOT_LOG_ERR("Firmware + tlvs in slot %u overlaps with last sector, which contains trailer, erasing this image", i);
1890 rc = flash_area_erase(fap, 0, flash_area_get_size(fap));
1891 }
1892 else {
1893 /* image firmware + tlvs do not overlap with last sector of slot, continue */
1894 }
1895 }
1896 }
1897 }
1898#endif /* MCUBOOT_SWAP_USING_STATUS */
1899
Fabio Utzig12d59162019-11-28 10:01:59 -03001900 rc = swap_read_status(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02001901 if (rc != 0) {
1902 BOOT_LOG_WRN("Failed reading boot status; Image=%u",
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001903 (unsigned)BOOT_CURR_IMG(state));
David Vinczeba3bd602019-06-17 16:01:43 +02001904 /* Continue with next image if there is one. */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001905 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
David Vinczeba3bd602019-06-17 16:01:43 +02001906 return;
1907 }
Fabio Utzig12d59162019-11-28 10:01:59 -03001908#endif
David Vinczeba3bd602019-06-17 16:01:43 +02001909
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +02001910#if defined (MCUBOOT_SWAP_USING_MOVE) || defined(MCUBOOT_SWAP_USING_SCRATCH)
Fabio Utzig74aef312019-11-28 11:05:34 -03001911 /*
1912 * Must re-read image headers because the boot status might
1913 * have been updated in the previous function call.
1914 */
1915 rc = boot_read_image_headers(state, !boot_status_is_reset(bs), bs);
Roman Okhrimenko977b3752022-03-31 14:40:48 +03001916 BOOT_LOG_DBG(" * re-read image(%u) headers: rc = %d.",
1917 (unsigned)BOOT_CURR_IMG(state), rc);
Fabio Utzig32afe852020-10-04 10:36:02 -03001918#ifdef MCUBOOT_BOOTSTRAP
1919 /* When bootstrapping it's OK to not have image magic in the primary slot */
1920 if (rc != 0 && (BOOT_CURR_IMG(state) != BOOT_PRIMARY_SLOT ||
1921 boot_check_header_erased(state, BOOT_PRIMARY_SLOT) != 0)) {
1922#else
Fabio Utzig74aef312019-11-28 11:05:34 -03001923 if (rc != 0) {
Fabio Utzig32afe852020-10-04 10:36:02 -03001924#endif
Fabio Utzig74aef312019-11-28 11:05:34 -03001925 /* Continue with next image if there is one. */
1926 BOOT_LOG_WRN("Failed reading image headers; Image=%u",
1927 BOOT_CURR_IMG(state));
1928 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
1929 return;
1930 }
1931#endif
1932
David Vinczeba3bd602019-06-17 16:01:43 +02001933 /* Determine if we rebooted in the middle of an image swap
1934 * operation. If a partial swap was detected, complete it.
1935 */
Fabio Utzig12d59162019-11-28 10:01:59 -03001936 if (!boot_status_is_reset(bs)) {
David Vinczeba3bd602019-06-17 16:01:43 +02001937
1938#if (BOOT_IMAGE_NUMBER > 1)
Fabio Utzig10ee6482019-08-01 12:04:52 -03001939 boot_review_image_swap_types(state, true);
David Vinczeba3bd602019-06-17 16:01:43 +02001940#endif
1941
1942#ifdef MCUBOOT_OVERWRITE_ONLY
1943 /* Should never arrive here, overwrite-only mode has
1944 * no swap state.
1945 */
1946 assert(0);
1947#else
1948 /* Determine the type of swap operation being resumed from the
1949 * `swap-type` trailer field.
1950 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001951 rc = boot_complete_partial_swap(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02001952 assert(rc == 0);
1953#endif
1954 /* Attempt to read an image header from each slot. Ensure that
1955 * image headers in slots are aligned with headers in boot_data.
1956 */
Fabio Utzig12d59162019-11-28 10:01:59 -03001957 rc = boot_read_image_headers(state, false, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02001958 assert(rc == 0);
1959
1960 /* Swap has finished set to NONE */
Fabio Utzig10ee6482019-08-01 12:04:52 -03001961 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
David Vinczeba3bd602019-06-17 16:01:43 +02001962 } else {
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +02001963 BOOT_LOG_DBG(" * There was no partial swap, determine swap type.");
1964
David Vinczeba3bd602019-06-17 16:01:43 +02001965 /* There was no partial swap, determine swap type. */
1966 if (bs->swap_type == BOOT_SWAP_TYPE_NONE) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03001967 BOOT_SWAP_TYPE(state) = boot_validated_swap_type(state, bs);
David Vinczeba3bd602019-06-17 16:01:43 +02001968 } else {
Raef Colese8fe6cf2020-05-26 13:07:40 +01001969 FIH_CALL(boot_validate_slot, fih_rc,
1970 state, BOOT_SECONDARY_SLOT, bs);
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001971 if (fih_eq(fih_rc, FIH_SUCCESS) != FIH_TRUE) {
Raef Colese8fe6cf2020-05-26 13:07:40 +01001972 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_FAIL;
1973 } else {
1974 BOOT_SWAP_TYPE(state) = bs->swap_type;
1975 }
David Vinczeba3bd602019-06-17 16:01:43 +02001976 }
1977
1978#if (BOOT_IMAGE_NUMBER > 1)
Fabio Utzig10ee6482019-08-01 12:04:52 -03001979 boot_review_image_swap_types(state, false);
David Vinczeba3bd602019-06-17 16:01:43 +02001980#endif
1981
1982#ifdef MCUBOOT_BOOTSTRAP
Fabio Utzig10ee6482019-08-01 12:04:52 -03001983 if (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_NONE) {
David Vinczeba3bd602019-06-17 16:01:43 +02001984 /* Header checks are done first because they are
1985 * inexpensive. Since overwrite-only copies starting from
1986 * offset 0, if interrupted, it might leave a valid header
1987 * magic, so also run validation on the primary slot to be
1988 * sure it's not OK.
1989 */
Raef Colese8fe6cf2020-05-26 13:07:40 +01001990 rc = boot_check_header_erased(state, BOOT_PRIMARY_SLOT);
1991 FIH_CALL(boot_validate_slot, fih_rc,
1992 state, BOOT_PRIMARY_SLOT, bs);
1993
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03001994 if (rc == 0 || fih_eq(fih_rc, FIH_SUCCESS) != FIH_TRUE) {
Raef Colese8fe6cf2020-05-26 13:07:40 +01001995
Fabio Utzig3d77c952020-10-04 10:23:17 -03001996 rc = (boot_img_hdr(state, BOOT_SECONDARY_SLOT)->ih_magic == IMAGE_MAGIC) ? 1: 0;
Raef Colese8fe6cf2020-05-26 13:07:40 +01001997 FIH_CALL(boot_validate_slot, fih_rc,
1998 state, BOOT_SECONDARY_SLOT, bs);
1999
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002000 if (rc == 1 && FIH_TRUE == fih_eq(fih_rc, FIH_SUCCESS)) {
David Vinczeba3bd602019-06-17 16:01:43 +02002001 /* Set swap type to REVERT to overwrite the primary
2002 * slot with the image contained in secondary slot
2003 * and to trigger the explicit setting of the
2004 * image_ok flag.
2005 */
Fabio Utzig59b63e52019-09-10 12:22:35 -03002006 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_REVERT;
David Vinczeba3bd602019-06-17 16:01:43 +02002007 }
Fabio Utzig338a19f2018-12-03 08:37:08 -02002008 }
2009 }
Fabio Utzig338a19f2018-12-03 08:37:08 -02002010#endif
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08002011 }
David Vinczeba3bd602019-06-17 16:01:43 +02002012 } else {
2013 /* In that case if slots are not compatible. */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002014 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08002015 }
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +02002016 BOOT_LOG_DBG("< boot_prepare_image_for_update");
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08002017}
2018
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002019/**
2020 * Updates the security counter for the current image.
2021 *
2022 * @param state Boot loader status information.
2023 *
2024 * @return 0 on success; nonzero on failure.
2025 */
2026static int
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002027boot_update_hw_rollback_protection_flash(struct boot_loader_state *state)
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002028{
2029#ifdef MCUBOOT_HW_ROLLBACK_PROT
2030 int rc;
2031
2032 /* Update the stored security counter with the active image's security
2033 * counter value. It will only be updated if the new security counter is
2034 * greater than the stored value.
2035 *
2036 * In case of a successful image swapping when the swap type is TEST the
2037 * security counter can be increased only after a reset, when the swap
2038 * type is NONE and the image has marked itself "OK" (the image_ok flag
2039 * has been set). This way a "revert" can be performed when it's
2040 * necessary.
2041 */
2042 if (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_NONE) {
2043 rc = boot_update_security_counter(
2044 BOOT_CURR_IMG(state),
2045 BOOT_PRIMARY_SLOT,
2046 boot_img_hdr(state, BOOT_PRIMARY_SLOT));
2047 if (rc != 0) {
2048 BOOT_LOG_ERR("Security counter update failed after image "
2049 "validation.");
2050 return rc;
2051 }
2052 }
2053
2054 return 0;
2055
2056#else /* MCUBOOT_HW_ROLLBACK_PROT */
2057 (void) (state);
2058
2059 return 0;
2060#endif
2061}
2062
Raef Colese8fe6cf2020-05-26 13:07:40 +01002063fih_int
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002064context_boot_go_flash(struct boot_loader_state *state, struct boot_rsp *rsp)
Christopher Collins92ea77f2016-12-12 15:59:26 -08002065{
Marti Bolivar84898652017-06-13 17:20:22 -04002066 size_t slot;
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002067 struct boot_status bs = {0};
David Vincze9015a5d2020-05-18 14:43:11 +02002068 int rc = -1;
Raef Colese8fe6cf2020-05-26 13:07:40 +01002069 fih_int fih_rc = FIH_FAILURE;
Marti Bolivarc0b47912017-06-13 17:18:09 -04002070 int fa_id;
Fabio Utzigb0f04732019-07-31 09:49:19 -03002071 int image_index;
Fabio Utzig298913b2019-08-28 11:22:45 -03002072 bool has_upgrade;
Christopher Collins92ea77f2016-12-12 15:59:26 -08002073
2074 /* The array of slot sectors are defined here (as opposed to file scope) so
2075 * that they don't get allocated for non-boot-loader apps. This is
2076 * necessary because the gcc option "-fdata-sections" doesn't seem to have
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08002077 * any effect in older gcc versions (e.g., 4.8.4).
Christopher Collins92ea77f2016-12-12 15:59:26 -08002078 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002079 TARGET_STATIC boot_sector_t primary_slot_sectors[BOOT_IMAGE_NUMBER][BOOT_MAX_IMG_SECTORS];
2080 TARGET_STATIC boot_sector_t secondary_slot_sectors[BOOT_IMAGE_NUMBER][BOOT_MAX_IMG_SECTORS];
Fabio Utzig12d59162019-11-28 10:01:59 -03002081#if MCUBOOT_SWAP_USING_SCRATCH
Fabio Utzig10ee6482019-08-01 12:04:52 -03002082 TARGET_STATIC boot_sector_t scratch_sectors[BOOT_MAX_IMG_SECTORS];
Fabio Utzig12d59162019-11-28 10:01:59 -03002083#endif
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +02002084#if MCUBOOT_SWAP_USING_STATUS
2085 TARGET_STATIC boot_sector_t status_sectors[BOOT_MAX_SWAP_STATUS_SECTORS];
2086#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -08002087
Fabio Utzig298913b2019-08-28 11:22:45 -03002088 has_upgrade = false;
2089
2090#if (BOOT_IMAGE_NUMBER == 1)
2091 (void)has_upgrade;
2092#endif
Fabio Utzigba829042018-09-18 08:29:34 -03002093
David Vinczeba3bd602019-06-17 16:01:43 +02002094 /* Iterate over all the images. By the end of the loop the swap type has
2095 * to be determined for each image and all aborted swaps have to be
2096 * completed.
Christopher Collins0ff3c6c2016-12-21 12:04:17 -08002097 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002098 IMAGES_ITER(BOOT_CURR_IMG(state)) {
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002099#if BOOT_IMAGE_NUMBER > 1
2100 if (state->img_mask[BOOT_CURR_IMG(state)]) {
2101 continue;
2102 }
2103#endif
David Vinczeba3bd602019-06-17 16:01:43 +02002104#if defined(MCUBOOT_ENC_IMAGES) && (BOOT_IMAGE_NUMBER > 1)
2105 /* The keys used for encryption may no longer be valid (could belong to
2106 * another images). Therefore, mark them as invalid to force their reload
2107 * by boot_enc_load().
Fabio Utzigdb5bd3c2017-07-13 22:20:22 -03002108 */
Fabio Utzig1e4284b2019-08-23 11:55:27 -03002109 boot_enc_zeroize(BOOT_CURR_ENC(state));
David Brown554c52e2017-06-30 16:01:07 -06002110#endif
2111
Fabio Utzig10ee6482019-08-01 12:04:52 -03002112 image_index = BOOT_CURR_IMG(state);
Fabio Utzigb0f04732019-07-31 09:49:19 -03002113
Fabio Utzig10ee6482019-08-01 12:04:52 -03002114 BOOT_IMG(state, BOOT_PRIMARY_SLOT).sectors =
Fabio Utzigb0f04732019-07-31 09:49:19 -03002115 primary_slot_sectors[image_index];
Fabio Utzig10ee6482019-08-01 12:04:52 -03002116 BOOT_IMG(state, BOOT_SECONDARY_SLOT).sectors =
Fabio Utzigb0f04732019-07-31 09:49:19 -03002117 secondary_slot_sectors[image_index];
Fabio Utzig12d59162019-11-28 10:01:59 -03002118#if MCUBOOT_SWAP_USING_SCRATCH
Fabio Utzig10ee6482019-08-01 12:04:52 -03002119 state->scratch.sectors = scratch_sectors;
Fabio Utzig12d59162019-11-28 10:01:59 -03002120#endif
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +02002121#if MCUBOOT_SWAP_USING_STATUS
2122 state->status.sectors = status_sectors;
2123#endif
David Vinczeba3bd602019-06-17 16:01:43 +02002124
2125 /* Open primary and secondary image areas for the duration
2126 * of this call.
2127 */
2128 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
Fabio Utzigb0f04732019-07-31 09:49:19 -03002129 fa_id = flash_area_id_from_multi_image_slot(image_index, slot);
Fabio Utzig10ee6482019-08-01 12:04:52 -03002130 rc = flash_area_open(fa_id, &BOOT_IMG_AREA(state, slot));
David Vinczeba3bd602019-06-17 16:01:43 +02002131 assert(rc == 0);
2132 }
Fabio Utzig12d59162019-11-28 10:01:59 -03002133#if MCUBOOT_SWAP_USING_SCRATCH
David Vinczeba3bd602019-06-17 16:01:43 +02002134 rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH,
Fabio Utzig10ee6482019-08-01 12:04:52 -03002135 &BOOT_SCRATCH_AREA(state));
David Vinczeba3bd602019-06-17 16:01:43 +02002136 assert(rc == 0);
Fabio Utzig12d59162019-11-28 10:01:59 -03002137#endif
David Vinczeba3bd602019-06-17 16:01:43 +02002138
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +02002139 BOOT_LOG_DBG(" * boot_prepare_image_for_update...");
David Vinczeba3bd602019-06-17 16:01:43 +02002140 /* Determine swap type and complete swap if it has been aborted. */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002141 boot_prepare_image_for_update(state, &bs);
Fabio Utzig298913b2019-08-28 11:22:45 -03002142
Fabio Utzige575b0b2019-09-11 12:34:23 -03002143 if (BOOT_IS_UPGRADE(BOOT_SWAP_TYPE(state))) {
Fabio Utzig298913b2019-08-28 11:22:45 -03002144 has_upgrade = true;
2145 }
David Vinczeba3bd602019-06-17 16:01:43 +02002146 }
2147
David Vinczee32483f2019-06-13 10:46:24 +02002148#if (BOOT_IMAGE_NUMBER > 1)
Fabio Utzig298913b2019-08-28 11:22:45 -03002149 if (has_upgrade) {
2150 /* Iterate over all the images and verify whether the image dependencies
2151 * are all satisfied and update swap type if necessary.
2152 */
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002153 rc = boot_verify_dependencies_flash(state);
David Vincze8b0b6372020-05-20 19:54:44 +02002154 if (rc != 0) {
Fabio Utzig298913b2019-08-28 11:22:45 -03002155 /*
2156 * It was impossible to upgrade because the expected dependency version
2157 * was not available. Here we already changed the swap_type so that
2158 * instead of asserting the bootloader, we continue and no upgrade is
2159 * performed.
2160 */
2161 rc = 0;
2162 }
2163 }
David Vinczee32483f2019-06-13 10:46:24 +02002164#endif
2165
David Vinczeba3bd602019-06-17 16:01:43 +02002166 /* Iterate over all the images. At this point there are no aborted swaps
2167 * and the swap types are determined for each image. By the end of the loop
2168 * all required update operations will have been finished.
2169 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002170 IMAGES_ITER(BOOT_CURR_IMG(state)) {
David Vinczeba3bd602019-06-17 16:01:43 +02002171#if (BOOT_IMAGE_NUMBER > 1)
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002172 if (state->img_mask[BOOT_CURR_IMG(state)]) {
2173 continue;
2174 }
2175
David Vinczeba3bd602019-06-17 16:01:43 +02002176#ifdef MCUBOOT_ENC_IMAGES
2177 /* The keys used for encryption may no longer be valid (could belong to
2178 * another images). Therefore, mark them as invalid to force their reload
2179 * by boot_enc_load().
2180 */
Fabio Utzig1e4284b2019-08-23 11:55:27 -03002181 boot_enc_zeroize(BOOT_CURR_ENC(state));
David Vinczeba3bd602019-06-17 16:01:43 +02002182#endif /* MCUBOOT_ENC_IMAGES */
2183
2184 /* Indicate that swap is not aborted */
Fabio Utzig12d59162019-11-28 10:01:59 -03002185 boot_status_reset(&bs);
David Vinczeba3bd602019-06-17 16:01:43 +02002186#endif /* (BOOT_IMAGE_NUMBER > 1) */
2187
2188 /* Set the previously determined swap type */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002189 bs.swap_type = BOOT_SWAP_TYPE(state);
David Vinczeba3bd602019-06-17 16:01:43 +02002190
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002191 BOOT_LOG_DBG(" * process swap_type = %u", (unsigned)bs.swap_type);
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +02002192
Fabio Utzig10ee6482019-08-01 12:04:52 -03002193 switch (BOOT_SWAP_TYPE(state)) {
David Vinczeba3bd602019-06-17 16:01:43 +02002194 case BOOT_SWAP_TYPE_NONE:
2195 break;
2196
2197 case BOOT_SWAP_TYPE_TEST: /* fallthrough */
2198 case BOOT_SWAP_TYPE_PERM: /* fallthrough */
2199 case BOOT_SWAP_TYPE_REVERT:
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002200 BOOT_LOG_DBG(" * perform update, mode %u...", (unsigned)bs.swap_type);
2201 rc = BOOT_HOOK_CALL(boot_perform_update_hook, BOOT_HOOK_REGULAR,
2202 BOOT_CURR_IMG(state), &(BOOT_IMG(state, 1).hdr),
2203 BOOT_IMG_AREA(state, BOOT_SECONDARY_SLOT));
2204 if (rc == BOOT_HOOK_REGULAR)
2205 {
2206 rc = boot_perform_update(state, &bs);
2207 }
David Vinczeba3bd602019-06-17 16:01:43 +02002208 assert(rc == 0);
2209 break;
2210
2211 case BOOT_SWAP_TYPE_FAIL:
2212 /* The image in secondary slot was invalid and is now erased. Ensure
2213 * we don't try to boot into it again on the next reboot. Do this by
2214 * pretending we just reverted back to primary slot.
2215 */
2216#ifndef MCUBOOT_OVERWRITE_ONLY
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002217 BOOT_LOG_DBG(" * update failed! Set image_ok manually for image(%u)",
2218 (unsigned)BOOT_CURR_IMG(state));
David Vinczeba3bd602019-06-17 16:01:43 +02002219 /* image_ok needs to be explicitly set to avoid a new revert. */
Fabio Utzig12d59162019-11-28 10:01:59 -03002220 rc = swap_set_image_ok(BOOT_CURR_IMG(state));
David Vinczeba3bd602019-06-17 16:01:43 +02002221 if (rc != 0) {
Fabio Utzig10ee6482019-08-01 12:04:52 -03002222 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
David Vinczeba3bd602019-06-17 16:01:43 +02002223 }
2224#endif /* !MCUBOOT_OVERWRITE_ONLY */
2225 break;
2226
2227 default:
Fabio Utzig10ee6482019-08-01 12:04:52 -03002228 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
David Vinczeba3bd602019-06-17 16:01:43 +02002229 }
2230
Fabio Utzig10ee6482019-08-01 12:04:52 -03002231 if (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_PANIC) {
David Vinczeba3bd602019-06-17 16:01:43 +02002232 BOOT_LOG_ERR("panic!");
2233 assert(0);
2234
2235 /* Loop forever... */
Raef Colese8fe6cf2020-05-26 13:07:40 +01002236 FIH_PANIC;
David Vinczeba3bd602019-06-17 16:01:43 +02002237 }
2238 }
2239
2240 /* Iterate over all the images. At this point all required update operations
2241 * have finished. By the end of the loop each image in the primary slot will
2242 * have been re-validated.
2243 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002244 IMAGES_ITER(BOOT_CURR_IMG(state)) {
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002245#if BOOT_IMAGE_NUMBER > 1
2246 if (state->img_mask[BOOT_CURR_IMG(state)]) {
2247 continue;
2248 }
2249#endif
Fabio Utzig10ee6482019-08-01 12:04:52 -03002250 if (BOOT_SWAP_TYPE(state) != BOOT_SWAP_TYPE_NONE) {
David Vinczeba3bd602019-06-17 16:01:43 +02002251 /* Attempt to read an image header from each slot. Ensure that image
2252 * headers in slots are aligned with headers in boot_data.
2253 */
Fabio Utzig12d59162019-11-28 10:01:59 -03002254 rc = boot_read_image_headers(state, false, &bs);
David Vinczeba3bd602019-06-17 16:01:43 +02002255 if (rc != 0) {
2256 goto out;
2257 }
2258 /* Since headers were reloaded, it can be assumed we just performed
2259 * a swap or overwrite. Now the header info that should be used to
2260 * provide the data for the bootstrap, which previously was at
2261 * secondary slot, was updated to primary slot.
2262 */
2263 }
2264
2265#ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002266 FIH_CALL(boot_validate_slot, fih_rc, state, BOOT_PRIMARY_SLOT, &bs);
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002267 if (fih_eq(fih_rc, FIH_SUCCESS) != FIH_TRUE) {
David Vinczeba3bd602019-06-17 16:01:43 +02002268 goto out;
2269 }
2270#else
2271 /* Even if we're not re-validating the primary slot, we could be booting
2272 * onto an empty flash chip. At least do a basic sanity check that
2273 * the magic number on the image is OK.
2274 */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002275 if (BOOT_IMG(state, BOOT_PRIMARY_SLOT).hdr.ih_magic != IMAGE_MAGIC) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002276 BOOT_LOG_ERR("bad image magic 0x%" PRIx32 "; Image=%u",
2277 BOOT_IMG(state, BOOT_PRIMARY_SLOT).hdr.ih_magic,
2278 (unsigned)BOOT_CURR_IMG(state));
David Vinczeba3bd602019-06-17 16:01:43 +02002279 rc = BOOT_EBADIMAGE;
2280 goto out;
2281 }
David Vinczec3084132020-02-18 14:50:47 +01002282#endif /* MCUBOOT_VALIDATE_PRIMARY_SLOT */
2283
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002284#ifdef MCUBOOT_ENC_IMAGES_XIP
2285 if (0 == BOOT_CURR_IMG(state)) {
2286 if (IS_ENCRYPTED(boot_img_hdr(state, BOOT_PRIMARY_SLOT)))
2287 {
2288 (void)memcpy((uint8_t*)rsp->xip_iv, BOOT_CURR_ENC(state)->aes_iv, BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE);
2289 (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 +01002290 }
2291 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002292#endif /* MCUBOOT_ENC_IMAGES_XIP */
David Vincze1cf11b52020-03-24 07:51:09 +01002293
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002294 rc = boot_update_hw_rollback_protection_flash(state);
David Vincze1cf11b52020-03-24 07:51:09 +01002295 if (rc != 0) {
Raef Colese8fe6cf2020-05-26 13:07:40 +01002296 goto out;
David Vincze1cf11b52020-03-24 07:51:09 +01002297 }
David Vincze1cf11b52020-03-24 07:51:09 +01002298
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002299 rc = boot_add_shared_data(state, BOOT_PRIMARY_SLOT);
David Vincze1cf11b52020-03-24 07:51:09 +01002300 if (rc != 0) {
Raef Colese8fe6cf2020-05-26 13:07:40 +01002301 goto out;
David Vincze1cf11b52020-03-24 07:51:09 +01002302 }
David Vinczeba3bd602019-06-17 16:01:43 +02002303 }
2304
Fabio Utzigb0f04732019-07-31 09:49:19 -03002305#if (BOOT_IMAGE_NUMBER > 1)
David Vinczeba3bd602019-06-17 16:01:43 +02002306 /* Always boot from the primary slot of Image 0. */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002307 BOOT_CURR_IMG(state) = 0;
Fabio Utzigb0f04732019-07-31 09:49:19 -03002308#endif
Fabio Utzig298913b2019-08-28 11:22:45 -03002309
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002310 rsp->br_flash_dev_id = BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT)->fa_device_id;
2311 rsp->br_image_off = boot_img_slot_off(state, BOOT_PRIMARY_SLOT);
2312 rsp->br_hdr = boot_img_hdr(state, BOOT_PRIMARY_SLOT);
Fabio Utzigf616c542019-12-19 15:23:32 -03002313 /*
2314 * Since the boot_status struct stores plaintext encryption keys, reset
2315 * them here to avoid the possibility of jumping into an image that could
2316 * easily recover them.
2317 */
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002318 (void)memset(&bs, 0, sizeof(struct boot_status));
Fabio Utzigf616c542019-12-19 15:23:32 -03002319
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002320 fill_rsp(state, rsp);
Christopher Collins92ea77f2016-12-12 15:59:26 -08002321
Raef Colese8fe6cf2020-05-26 13:07:40 +01002322 fih_rc = FIH_SUCCESS;
Fabio Utzig298913b2019-08-28 11:22:45 -03002323out:
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002324 close_all_flash_areas(state);
Raef Colese8fe6cf2020-05-26 13:07:40 +01002325
2326 if (rc) {
2327 fih_rc = fih_int_encode(rc);
2328 }
2329
2330 FIH_RET(fih_rc);
Christopher Collins92ea77f2016-12-12 15:59:26 -08002331}
2332
Raef Colese8fe6cf2020-05-26 13:07:40 +01002333fih_int
Christopher Collins92ea77f2016-12-12 15:59:26 -08002334split_go(int loader_slot, int split_slot, void **entry)
2335{
Marti Bolivarc50926f2017-06-14 09:35:40 -04002336 boot_sector_t *sectors;
Christopher Collins034a6202017-01-11 12:19:37 -08002337 uintptr_t entry_val;
Christopher Collins92ea77f2016-12-12 15:59:26 -08002338 int loader_flash_id;
Marti Bolivarc0b47912017-06-13 17:18:09 -04002339 int split_flash_id;
Christopher Collins92ea77f2016-12-12 15:59:26 -08002340 int rc;
Raef Colese8fe6cf2020-05-26 13:07:40 +01002341 fih_int fih_rc = FIH_FAILURE;
Christopher Collins92ea77f2016-12-12 15:59:26 -08002342
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002343 if ((loader_slot < 0) || (split_slot < 0)) {
2344 FIH_RET(FIH_FAILURE);
2345 }
2346
Christopher Collins92ea77f2016-12-12 15:59:26 -08002347 sectors = malloc(BOOT_MAX_IMG_SECTORS * 2 * sizeof *sectors);
2348 if (sectors == NULL) {
Raef Colese8fe6cf2020-05-26 13:07:40 +01002349 FIH_RET(FIH_FAILURE);
Christopher Collins92ea77f2016-12-12 15:59:26 -08002350 }
David Vinczeba3bd602019-06-17 16:01:43 +02002351 BOOT_IMG(&boot_data, loader_slot).sectors = sectors + 0;
2352 BOOT_IMG(&boot_data, split_slot).sectors = sectors + BOOT_MAX_IMG_SECTORS;
Marti Bolivarc0b47912017-06-13 17:18:09 -04002353
2354 loader_flash_id = flash_area_id_from_image_slot(loader_slot);
2355 rc = flash_area_open(loader_flash_id,
Alvaro Prieto63a2bdb2019-07-04 12:18:49 -07002356 &BOOT_IMG_AREA(&boot_data, loader_slot));
Marti Bolivarc0b47912017-06-13 17:18:09 -04002357 assert(rc == 0);
2358 split_flash_id = flash_area_id_from_image_slot(split_slot);
2359 rc = flash_area_open(split_flash_id,
2360 &BOOT_IMG_AREA(&boot_data, split_slot));
2361 assert(rc == 0);
Christopher Collins92ea77f2016-12-12 15:59:26 -08002362
2363 /* Determine the sector layout of the image slots and scratch area. */
Fabio Utzig10ee6482019-08-01 12:04:52 -03002364 rc = boot_read_sectors(&boot_data);
Christopher Collins92ea77f2016-12-12 15:59:26 -08002365 if (rc != 0) {
2366 rc = SPLIT_GO_ERR;
2367 goto done;
2368 }
2369
Fabio Utzig12d59162019-11-28 10:01:59 -03002370 rc = boot_read_image_headers(&boot_data, true, NULL);
Christopher Collins92ea77f2016-12-12 15:59:26 -08002371 if (rc != 0) {
2372 goto done;
2373 }
2374
Christopher Collins92ea77f2016-12-12 15:59:26 -08002375 /* Don't check the bootable image flag because we could really call a
2376 * bootable or non-bootable image. Just validate that the image check
2377 * passes which is distinct from the normal check.
2378 */
Raef Colese8fe6cf2020-05-26 13:07:40 +01002379 FIH_CALL(split_image_check, fih_rc,
2380 boot_img_hdr(&boot_data, split_slot),
2381 BOOT_IMG_AREA(&boot_data, split_slot),
2382 boot_img_hdr(&boot_data, loader_slot),
2383 BOOT_IMG_AREA(&boot_data, loader_slot));
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002384 if (fih_eq(fih_rc, FIH_SUCCESS) != FIH_TRUE) {
Christopher Collins92ea77f2016-12-12 15:59:26 -08002385 goto done;
2386 }
2387
Marti Bolivarea088872017-06-12 17:10:49 -04002388 entry_val = boot_img_slot_off(&boot_data, split_slot) +
Marti Bolivarf804f622017-06-12 15:41:48 -04002389 boot_img_hdr(&boot_data, split_slot)->ih_hdr_size;
Christopher Collins034a6202017-01-11 12:19:37 -08002390 *entry = (void *) entry_val;
Christopher Collins92ea77f2016-12-12 15:59:26 -08002391 rc = SPLIT_GO_OK;
2392
2393done:
Marti Bolivarc0b47912017-06-13 17:18:09 -04002394 flash_area_close(BOOT_IMG_AREA(&boot_data, split_slot));
2395 flash_area_close(BOOT_IMG_AREA(&boot_data, loader_slot));
Christopher Collins92ea77f2016-12-12 15:59:26 -08002396 free(sectors);
Raef Colese8fe6cf2020-05-26 13:07:40 +01002397
2398 if (rc) {
2399 fih_rc = fih_int_encode(rc);
2400 }
2401
2402 FIH_RET(fih_rc);
Christopher Collins92ea77f2016-12-12 15:59:26 -08002403}
David Vinczee574f2d2020-07-10 11:42:03 +02002404
David Vinczee574f2d2020-07-10 11:42:03 +02002405
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002406#if defined(MCUBOOT_DIRECT_XIP) || defined(MCUBOOT_RAM_LOAD)
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002407
David Vinczee574f2d2020-07-10 11:42:03 +02002408/**
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002409 * Opens all flash areas and checks which contain an image with a valid header.
David Vinczee574f2d2020-07-10 11:42:03 +02002410 *
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002411 * @param state Boot loader status information.
David Vinczee574f2d2020-07-10 11:42:03 +02002412 *
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002413 * @return 0 on success; nonzero on failure.
2414 */
2415static int
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002416boot_get_slot_usage(struct boot_loader_state *state)
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002417{
2418 uint32_t slot;
2419 int fa_id;
2420 int rc;
2421 struct image_header *hdr = NULL;
2422
2423 IMAGES_ITER(BOOT_CURR_IMG(state)) {
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002424#if BOOT_IMAGE_NUMBER > 1
2425 if (state->img_mask[BOOT_CURR_IMG(state)]) {
2426 continue;
2427 }
2428#endif
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002429 /* Open all the slots */
2430 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
2431 fa_id = flash_area_id_from_multi_image_slot(
2432 BOOT_CURR_IMG(state), slot);
2433 rc = flash_area_open(fa_id, &BOOT_IMG_AREA(state, slot));
2434 assert(rc == 0);
2435 }
2436
2437 /* Attempt to read an image header from each slot. */
2438 rc = boot_read_image_headers(state, false, NULL);
2439 if (rc != 0) {
2440 BOOT_LOG_WRN("Failed reading image headers.");
2441 return rc;
2442 }
2443
2444 /* Check headers in all slots */
2445 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
2446 hdr = boot_img_hdr(state, slot);
2447
2448 if (boot_is_header_valid(hdr, BOOT_IMG_AREA(state, slot))) {
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002449 state->slot_usage[BOOT_CURR_IMG(state)].slot_available[slot] = true;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002450 BOOT_LOG_IMAGE_INFO(slot, hdr);
2451 } else {
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002452 state->slot_usage[BOOT_CURR_IMG(state)].slot_available[slot] = false;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002453 BOOT_LOG_INF("Image %u %s slot: Image not found",
2454 (unsigned)BOOT_CURR_IMG(state),
2455 (slot == BOOT_PRIMARY_SLOT)
2456 ? "Primary" : "Secondary");
2457 }
2458 }
2459
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002460 state->slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002461 }
2462
2463 return 0;
2464}
2465
2466/**
2467 * Finds the slot containing the image with the highest version number for the
2468 * current image.
2469 *
2470 * @param state Boot loader status information.
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002471 *
2472 * @return NO_ACTIVE_SLOT if no available slot found, number of
2473 * the found slot otherwise.
David Vinczee574f2d2020-07-10 11:42:03 +02002474 */
2475static uint32_t
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002476find_slot_with_highest_version(struct boot_loader_state *state)
David Vinczee574f2d2020-07-10 11:42:03 +02002477{
David Vinczee574f2d2020-07-10 11:42:03 +02002478 uint32_t slot;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002479 uint32_t candidate_slot = NO_ACTIVE_SLOT;
2480 int rc;
David Vinczee574f2d2020-07-10 11:42:03 +02002481
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002482 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002483 if (state->slot_usage[BOOT_CURR_IMG(state)].slot_available[slot]) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002484 if (candidate_slot == NO_ACTIVE_SLOT) {
2485 candidate_slot = slot;
2486 } else {
2487 rc = boot_version_cmp(
2488 &boot_img_hdr(state, slot)->ih_ver,
2489 &boot_img_hdr(state, candidate_slot)->ih_ver);
2490 if (rc == 1) {
2491 /* The version of the image being examined is greater than
2492 * the version of the current candidate.
2493 */
2494 candidate_slot = slot;
2495 }
2496 }
David Vinczee574f2d2020-07-10 11:42:03 +02002497 }
2498 }
2499
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002500 return candidate_slot;
David Vinczee574f2d2020-07-10 11:42:03 +02002501}
2502
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002503#ifdef MCUBOOT_HAVE_LOGGING
David Vincze505fba22020-10-22 13:53:29 +02002504/**
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002505 * Prints the state of the loaded images.
David Vincze505fba22020-10-22 13:53:29 +02002506 *
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002507 * @param state Boot loader status information.
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002508 */
2509static void
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002510print_loaded_images(struct boot_loader_state *state)
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002511{
2512 uint32_t active_slot;
2513
2514 (void)state;
2515
2516 IMAGES_ITER(BOOT_CURR_IMG(state)) {
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002517#if BOOT_IMAGE_NUMBER > 1
2518 if (state->img_mask[BOOT_CURR_IMG(state)]) {
2519 continue;
2520 }
2521#endif
2522 active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002523
2524 BOOT_LOG_INF("Image %u loaded from the %s slot",
2525 (unsigned)BOOT_CURR_IMG(state),
2526 (active_slot == BOOT_PRIMARY_SLOT) ?
2527 "primary" : "secondary");
2528 }
2529}
2530#endif
2531
2532#if defined(MCUBOOT_DIRECT_XIP) && defined(MCUBOOT_DIRECT_XIP_REVERT)
2533/**
2534 * Checks whether the active slot of the current image was previously selected
2535 * to run. Erases the image if it was selected but its execution failed,
2536 * otherwise marks it as selected if it has not been before.
David Vincze505fba22020-10-22 13:53:29 +02002537 *
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002538 * @param state Boot loader status information.
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002539 *
2540 * @return 0 on success; nonzero on failure.
David Vincze505fba22020-10-22 13:53:29 +02002541 */
2542static int
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002543boot_select_or_erase(struct boot_loader_state *state)
David Vincze505fba22020-10-22 13:53:29 +02002544{
2545 const struct flash_area *fap;
2546 int fa_id;
2547 int rc;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002548 uint32_t active_slot;
2549 struct boot_swap_state* active_swap_state;
David Vincze505fba22020-10-22 13:53:29 +02002550
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002551 active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002552
2553 fa_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), active_slot);
David Vincze505fba22020-10-22 13:53:29 +02002554 rc = flash_area_open(fa_id, &fap);
2555 assert(rc == 0);
2556
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002557 active_swap_state = &(state->slot_usage[BOOT_CURR_IMG(state)].swap_state);
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002558
2559 (void)memset(active_swap_state, 0, sizeof(struct boot_swap_state));
2560 rc = boot_read_swap_state(fap, active_swap_state);
David Vincze505fba22020-10-22 13:53:29 +02002561 assert(rc == 0);
2562
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002563 if (active_swap_state->magic != BOOT_MAGIC_GOOD ||
2564 (active_swap_state->copy_done == BOOT_FLAG_SET &&
2565 active_swap_state->image_ok != BOOT_FLAG_SET)) {
David Vincze505fba22020-10-22 13:53:29 +02002566 /*
2567 * A reboot happened without the image being confirmed at
2568 * runtime or its trailer is corrupted/invalid. Erase the image
2569 * to prevent it from being selected again on the next reboot.
2570 */
2571 BOOT_LOG_DBG("Erasing faulty image in the %s slot.",
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002572 (active_slot == BOOT_PRIMARY_SLOT) ? "primary" : "secondary");
2573 rc = flash_area_erase(fap, 0, flash_area_get_size(fap));
David Vincze505fba22020-10-22 13:53:29 +02002574 assert(rc == 0);
2575
2576 flash_area_close(fap);
2577 rc = -1;
2578 } else {
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002579 if (active_swap_state->copy_done != BOOT_FLAG_SET) {
2580 if (active_swap_state->copy_done == BOOT_FLAG_BAD) {
David Vincze505fba22020-10-22 13:53:29 +02002581 BOOT_LOG_DBG("The copy_done flag had an unexpected value. Its "
2582 "value was neither 'set' nor 'unset', but 'bad'.");
2583 }
2584 /*
2585 * Set the copy_done flag, indicating that the image has been
2586 * selected to boot. It can be set in advance, before even
2587 * validating the image, because in case the validation fails, the
2588 * entire image slot will be erased (including the trailer).
2589 */
2590 rc = boot_write_copy_done(fap);
2591 if (rc != 0) {
2592 BOOT_LOG_WRN("Failed to set copy_done flag of the image in "
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002593 "the %s slot.", (active_slot == BOOT_PRIMARY_SLOT) ?
David Vincze505fba22020-10-22 13:53:29 +02002594 "primary" : "secondary");
2595 rc = 0;
2596 }
2597 }
2598 flash_area_close(fap);
2599 }
2600
2601 return rc;
2602}
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002603#endif /* MCUBOOT_DIRECT_XIP && MCUBOOT_DIRECT_XIP_REVERT */
David Vincze505fba22020-10-22 13:53:29 +02002604
Tamas Banfe031092020-09-10 17:32:39 +02002605#ifdef MCUBOOT_RAM_LOAD
2606
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002607#ifndef MULTIPLE_EXECUTABLE_RAM_REGIONS
Tamas Banfe031092020-09-10 17:32:39 +02002608#if !defined(IMAGE_EXECUTABLE_RAM_START) || !defined(IMAGE_EXECUTABLE_RAM_SIZE)
2609#error "Platform MUST define executable RAM bounds in case of RAM_LOAD"
2610#endif
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002611#endif
Tamas Banfe031092020-09-10 17:32:39 +02002612
2613/**
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002614 * Verifies that the active slot of the current image can be loaded within the
2615 * predefined bounds that are allowed to be used by executable images.
Tamas Banfe031092020-09-10 17:32:39 +02002616 *
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002617 * @param state Boot loader status information.
Tamas Banfe031092020-09-10 17:32:39 +02002618 *
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002619 * @return 0 on success; nonzero on failure.
Tamas Banfe031092020-09-10 17:32:39 +02002620 */
2621static int
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002622boot_verify_ram_load_address(struct boot_loader_state *state)
Tamas Banfe031092020-09-10 17:32:39 +02002623{
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002624 uint32_t img_dst;
2625 uint32_t img_sz;
Tamas Banfe031092020-09-10 17:32:39 +02002626 uint32_t img_end_addr;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002627 uint32_t exec_ram_start;
2628 uint32_t exec_ram_size;
Tamas Banfe031092020-09-10 17:32:39 +02002629
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002630 (void)state;
2631
2632#ifdef MULTIPLE_EXECUTABLE_RAM_REGIONS
2633 int rc;
2634
2635 rc = boot_get_image_exec_ram_info(BOOT_CURR_IMG(state), &exec_ram_start,
2636 &exec_ram_size);
2637 if (rc != 0) {
2638 return BOOT_EBADSTATUS;
2639 }
2640#else
2641 exec_ram_start = IMAGE_EXECUTABLE_RAM_START;
2642 exec_ram_size = IMAGE_EXECUTABLE_RAM_SIZE;
2643#endif
2644
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002645 img_dst = state->slot_usage[BOOT_CURR_IMG(state)].img_dst;
2646 img_sz = state->slot_usage[BOOT_CURR_IMG(state)].img_sz;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002647
2648 if (img_dst < exec_ram_start) {
Tamas Banfe031092020-09-10 17:32:39 +02002649 return BOOT_EBADIMAGE;
2650 }
2651
2652 if (!boot_u32_safe_add(&img_end_addr, img_dst, img_sz)) {
2653 return BOOT_EBADIMAGE;
2654 }
2655
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002656 if (img_end_addr > (exec_ram_start + exec_ram_size)) {
Tamas Banfe031092020-09-10 17:32:39 +02002657 return BOOT_EBADIMAGE;
2658 }
2659
2660 return 0;
2661}
2662
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002663#ifdef MCUBOOT_ENC_IMAGES
2664
Tamas Banfe031092020-09-10 17:32:39 +02002665/**
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002666 * Copies and decrypts an image from a slot in the flash to an SRAM address.
Tamas Banfe031092020-09-10 17:32:39 +02002667 *
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002668 * @param state Boot loader status information.
2669 * @param slot The flash slot of the image to be copied to SRAM.
2670 * @param hdr The image header.
2671 * @param src_sz Size of the image.
2672 * @param img_dst Pointer to the address at which the image needs to be
2673 * copied to SRAM.
2674 *
2675 * @return 0 on success; nonzero on failure.
2676 */
2677static int
2678boot_decrypt_and_copy_image_to_sram(struct boot_loader_state *state,
2679 uint32_t slot, struct image_header *hdr,
2680 uint32_t src_sz, uint32_t img_dst)
2681{
2682 /* The flow for the decryption and copy of the image is as follows :
2683 * 1. The whole image is copied to the RAM (header + payload + TLV).
2684 * 2. The encryption key is loaded from the TLV in flash.
2685 * 3. The image is then decrypted chunk by chunk in RAM (1 chunk
2686 * is 1024 bytes). Only the payload section is decrypted.
2687 * 4. The image is authenticated in RAM.
2688 */
2689 const struct flash_area *fap_src = NULL;
2690 struct boot_status bs;
2691 uint32_t blk_off;
2692 uint32_t tlv_off;
2693 uint32_t blk_sz;
2694 uint32_t bytes_copied = hdr->ih_hdr_size;
2695 uint32_t chunk_sz;
2696 uint32_t max_sz = 1024;
2697 uint16_t idx;
2698 uint8_t image_index;
2699 uint8_t * cur_dst;
2700 int area_id;
2701 int rc;
2702 uint8_t * ram_dst = (void *)(IMAGE_RAM_BASE + img_dst);
2703
2704 image_index = BOOT_CURR_IMG(state);
2705 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
2706 rc = flash_area_open(area_id, &fap_src);
2707 if (rc != 0){
2708 return BOOT_EFLASH;
2709 }
2710
2711 tlv_off = BOOT_TLV_OFF(hdr);
2712
2713 /* Copying the whole image in RAM */
2714 rc = flash_area_read(fap_src, 0, ram_dst, src_sz);
2715 if (rc != 0) {
2716 goto done;
2717 }
2718
2719 rc = boot_enc_load(BOOT_CURR_ENC(state), image_index, hdr, fap_src, &bs);
2720 if (rc < 0) {
2721 goto done;
2722 }
2723
2724 /* if rc > 0 then the key has already been loaded */
2725 if (rc == 0 && boot_enc_set_key(BOOT_CURR_ENC(state), slot, &bs)) {
2726 goto done;
2727 }
2728
2729 /* Starting at the end of the header as the header section is not encrypted */
2730 while (bytes_copied < tlv_off) { /* TLV section copied previously */
2731 if (src_sz - bytes_copied > max_sz) {
2732 chunk_sz = max_sz;
2733 } else {
2734 chunk_sz = src_sz - bytes_copied;
2735 }
2736
2737 cur_dst = ram_dst + bytes_copied;
2738 blk_sz = chunk_sz;
2739 idx = 0;
2740 if (bytes_copied + chunk_sz > tlv_off) {
2741 /* Going over TLV section
2742 * Part of the chunk is encrypted payload */
2743 blk_off = ((bytes_copied) - hdr->ih_hdr_size) & 0xf;
2744 blk_sz = tlv_off - (bytes_copied);
2745 boot_encrypt(BOOT_CURR_ENC(state), image_index, fap_src,
2746 (bytes_copied + idx) - hdr->ih_hdr_size, blk_sz,
2747 blk_off, cur_dst);
2748 } else {
2749 /* Image encrypted payload section */
2750 blk_off = ((bytes_copied) - hdr->ih_hdr_size) & 0xf;
2751 boot_encrypt(BOOT_CURR_ENC(state), image_index, fap_src,
2752 (bytes_copied + idx) - hdr->ih_hdr_size, blk_sz,
2753 blk_off, cur_dst);
2754 }
2755
2756 bytes_copied += chunk_sz;
2757 }
2758 rc = 0;
2759
2760done:
2761 flash_area_close(fap_src);
2762
2763 return rc;
2764}
2765
2766#endif /* MCUBOOT_ENC_IMAGES */
2767/**
2768 * Copies a slot of the current image into SRAM.
2769 *
2770 * @param state Boot loader status information.
Tamas Banfe031092020-09-10 17:32:39 +02002771 * @param slot The flash slot of the image to be copied to SRAM.
2772 * @param img_dst The address at which the image needs to be copied to
2773 * SRAM.
2774 * @param img_sz The size of the image that needs to be copied to SRAM.
2775 *
2776 * @return 0 on success; nonzero on failure.
2777 */
2778static int
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002779boot_copy_image_to_sram(struct boot_loader_state *state, int slot,
2780 uint32_t img_dst, uint32_t img_sz)
Tamas Banfe031092020-09-10 17:32:39 +02002781{
2782 int rc;
2783 const struct flash_area *fap_src = NULL;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002784 int area_id;
Tamas Banfe031092020-09-10 17:32:39 +02002785
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002786#if (BOOT_IMAGE_NUMBER == 1)
2787 (void)state;
2788#endif
2789
2790 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
2791
2792 rc = flash_area_open(area_id, &fap_src);
Tamas Banfe031092020-09-10 17:32:39 +02002793 if (rc != 0) {
2794 return BOOT_EFLASH;
2795 }
2796
2797 /* Direct copy from flash to its new location in SRAM. */
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002798 rc = flash_area_read(fap_src, 0, (void *)(IMAGE_RAM_BASE + img_dst), img_sz);
Tamas Banfe031092020-09-10 17:32:39 +02002799 if (rc != 0) {
2800 BOOT_LOG_INF("Error whilst copying image from Flash to SRAM: %d", rc);
2801 }
2802
2803 flash_area_close(fap_src);
2804
2805 return rc;
2806}
2807
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002808#if (BOOT_IMAGE_NUMBER > 1)
Tamas Banfe031092020-09-10 17:32:39 +02002809/**
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002810 * Checks if two memory regions (A and B) are overlap or not.
Tamas Banfe031092020-09-10 17:32:39 +02002811 *
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002812 * @param start_a Start of the A region.
2813 * @param end_a End of the A region.
2814 * @param start_b Start of the B region.
2815 * @param end_b End of the B region.
Tamas Banfe031092020-09-10 17:32:39 +02002816 *
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002817 * @return true if there is overlap; false otherwise.
2818 */
2819static bool
2820do_regions_overlap(uint32_t start_a, uint32_t end_a,
2821 uint32_t start_b, uint32_t end_b)
2822{
2823 if (start_b > end_a) {
2824 return false;
2825 } else if (start_b >= start_a) {
2826 return true;
2827 } else if (end_b > start_a) {
2828 return true;
2829 }
2830
2831 return false;
2832}
2833
2834/**
2835 * Checks if the image we want to load to memory overlap with an already
2836 * ramloaded image.
2837 *
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002838 * @param state Boot loader status information.
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002839 *
2840 * @return 0 if there is no overlap; nonzero otherwise.
Tamas Banfe031092020-09-10 17:32:39 +02002841 */
2842static int
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002843boot_check_ram_load_overlapping(struct boot_loader_state *state)
Tamas Banfe031092020-09-10 17:32:39 +02002844{
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002845 uint32_t i;
2846
2847 uint32_t start_a;
2848 uint32_t end_a;
2849 uint32_t start_b;
2850 uint32_t end_b;
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002851 uint32_t image_id_to_check = BOOT_CURR_IMG(state);
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002852
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002853 start_a = state->slot_usage[image_id_to_check].img_dst;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002854 /* Safe to add here, values are already verified in
2855 * boot_verify_ram_load_address() */
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002856 end_a = start_a + state->slot_usage[image_id_to_check].img_sz;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002857
2858 for (i = 0; i < BOOT_IMAGE_NUMBER; i++) {
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002859 if (state->slot_usage[i].active_slot == NO_ACTIVE_SLOT
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002860 || i == image_id_to_check) {
2861 continue;
2862 }
2863
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002864 start_b = state->slot_usage[i].img_dst;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002865 /* Safe to add here, values are already verified in
2866 * boot_verify_ram_load_address() */
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002867 end_b = start_b + state->slot_usage[i].img_sz;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002868
2869 if (do_regions_overlap(start_a, end_a, start_b, end_b)) {
2870 return -1;
2871 }
2872 }
2873
2874 return 0;
2875}
2876#endif
2877
2878/**
2879 * Loads the active slot of the current image into SRAM. The load address and
2880 * image size is extracted from the image header.
2881 *
2882 * @param state Boot loader status information.
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002883 *
2884 * @return 0 on success; nonzero on failure.
2885 */
2886static int
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002887boot_load_image_to_sram(struct boot_loader_state *state)
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002888{
2889 uint32_t active_slot;
2890 struct image_header *hdr = NULL;
2891 uint32_t img_dst;
2892 uint32_t img_sz;
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002893 int rc = 0;
Tamas Banfe031092020-09-10 17:32:39 +02002894
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002895 active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002896 hdr = boot_img_hdr(state, active_slot);
2897
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002898 if (IS_RAM_BOOTABLE(hdr)) {
Tamas Banfe031092020-09-10 17:32:39 +02002899
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002900 img_dst = hdr->ih_load_addr;
Tamas Banfe031092020-09-10 17:32:39 +02002901
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002902 rc = boot_read_image_size(state, active_slot, &img_sz);
Tamas Banfe031092020-09-10 17:32:39 +02002903 if (rc != 0) {
2904 return rc;
2905 }
2906
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002907 state->slot_usage[BOOT_CURR_IMG(state)].img_dst = img_dst;
2908 state->slot_usage[BOOT_CURR_IMG(state)].img_sz = img_sz;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002909
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002910 rc = boot_verify_ram_load_address(state);
Tamas Banfe031092020-09-10 17:32:39 +02002911 if (rc != 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002912 BOOT_LOG_INF("Image RAM load address 0x%" PRIx32 " is invalid.", img_dst);
Tamas Banfe031092020-09-10 17:32:39 +02002913 return rc;
2914 }
2915
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002916#if (BOOT_IMAGE_NUMBER > 1)
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002917 rc = boot_check_ram_load_overlapping(state);
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002918 if (rc != 0) {
2919 BOOT_LOG_INF("Image RAM loading to address 0x%" PRIx32
2920 " would overlap with another image.", img_dst);
2921 return rc;
2922 }
2923#endif
2924#ifdef MCUBOOT_ENC_IMAGES
2925 /* decrypt image if encrypted and copy it to RAM */
2926 if (IS_ENCRYPTED(hdr)) {
2927 rc = boot_decrypt_and_copy_image_to_sram(state, active_slot, hdr, img_sz, img_dst);
2928 } else {
2929 rc = boot_copy_image_to_sram(state, active_slot, img_dst, img_sz);
2930 }
2931#else
Tamas Banfe031092020-09-10 17:32:39 +02002932 /* Copy image to the load address from where it currently resides in
2933 * flash.
2934 */
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002935 rc = boot_copy_image_to_sram(state, active_slot, img_dst, img_sz);
2936#endif
Tamas Banfe031092020-09-10 17:32:39 +02002937 if (rc != 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002938 BOOT_LOG_INF("RAM loading to 0x%" PRIx32 " is failed.", img_dst);
Tamas Banfe031092020-09-10 17:32:39 +02002939 } else {
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002940 BOOT_LOG_INF("RAM loading to 0x%" PRIx32 " is succeeded.", img_dst);
Tamas Banfe031092020-09-10 17:32:39 +02002941 }
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002942 }
2943 else {
Tamas Banfe031092020-09-10 17:32:39 +02002944 /* Only images that support IMAGE_F_RAM_LOAD are allowed if
2945 * MCUBOOT_RAM_LOAD is set.
2946 */
2947 rc = BOOT_EBADIMAGE;
2948 }
2949
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002950 if (rc != 0) {
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002951 state->slot_usage[BOOT_CURR_IMG(state)].img_dst = 0;
2952 state->slot_usage[BOOT_CURR_IMG(state)].img_sz = 0;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002953 }
2954
Tamas Banfe031092020-09-10 17:32:39 +02002955 return rc;
2956}
2957
2958/**
2959 * Removes an image from SRAM, by overwriting it with zeros.
2960 *
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002961 * @param state Boot loader status information.
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002962 *
2963 * @return 0 on success; nonzero on failure.
2964 */
2965static inline int
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002966boot_remove_image_from_sram(struct boot_loader_state *state)
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002967{
2968 (void)state;
2969
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002970 BOOT_LOG_INF("Removing image from SRAM at address 0x%x",
2971 state->slot_usage[BOOT_CURR_IMG(state)].img_dst);
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002972
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002973 (void)memset((void*)(IMAGE_RAM_BASE + state->slot_usage[BOOT_CURR_IMG(state)].img_dst),
2974 0, state->slot_usage[BOOT_CURR_IMG(state)].img_sz);
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002975
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03002976 state->slot_usage[BOOT_CURR_IMG(state)].img_dst = 0;
2977 state->slot_usage[BOOT_CURR_IMG(state)].img_sz = 0;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002978
2979 return 0;
2980}
2981
2982/**
2983 * Removes an image from flash by erasing the corresponding flash area
2984 *
2985 * @param state Boot loader status information.
2986 * @param slot The flash slot of the image to be erased.
Tamas Banfe031092020-09-10 17:32:39 +02002987 *
2988 * @return 0 on success; nonzero on failure.
2989 */
2990static inline int
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002991boot_remove_image_from_flash(struct boot_loader_state *state, uint32_t slot)
Tamas Banfe031092020-09-10 17:32:39 +02002992{
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002993 int area_id;
2994 int rc;
2995 const struct flash_area *fap;
Tamas Banfe031092020-09-10 17:32:39 +02002996
Roman Okhrimenko977b3752022-03-31 14:40:48 +03002997 (void)state;
2998
2999 BOOT_LOG_INF("Removing image %u slot %" PRIu32 " from flash",
3000 (unsigned)BOOT_CURR_IMG(state), slot);
3001 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
3002 rc = flash_area_open(area_id, &fap);
3003 if (rc == 0) {
3004 flash_area_erase(fap, 0, flash_area_get_size(fap));
3005 }
3006
3007 return rc;
Tamas Banfe031092020-09-10 17:32:39 +02003008}
3009#endif /* MCUBOOT_RAM_LOAD */
3010
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003011#if (BOOT_IMAGE_NUMBER > 1)
3012/**
3013 * Checks the image dependency whether it is satisfied.
3014 *
3015 * @param state Boot loader status information.
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003016 * @param dep Image dependency which has to be verified.
3017 *
3018 * @return 0 if dependencies are met; nonzero otherwise.
3019 */
3020static int
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003021boot_verify_slot_dependency_ram(struct boot_loader_state *state,
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003022 struct image_dependency *dep)
David Vinczee574f2d2020-07-10 11:42:03 +02003023{
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003024 struct image_version *dep_version;
3025 uint32_t dep_slot;
David Vinczee574f2d2020-07-10 11:42:03 +02003026 int rc;
3027
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003028 /* Determine the source of the image which is the subject of
3029 * the dependency and get it's version.
David Vinczee574f2d2020-07-10 11:42:03 +02003030 */
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003031 dep_slot = state->slot_usage[dep->image_id].active_slot;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003032 dep_version = &state->imgs[dep->image_id][dep_slot].hdr.ih_ver;
3033
3034 rc = boot_version_cmp(dep_version, &dep->image_min_version);
3035 if (rc >= 0) {
3036 /* Dependency satisfied. */
3037 rc = 0;
David Vinczee574f2d2020-07-10 11:42:03 +02003038 }
3039
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003040 return rc;
3041}
3042
3043/**
3044 * Reads all dependency TLVs of an image and verifies one after another to see
3045 * if they are all satisfied.
3046 *
3047 * @param state Boot loader status information.
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003048 *
3049 * @return 0 if dependencies are met; nonzero otherwise.
3050 */
3051static int
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003052boot_verify_slot_dependencies_ram(struct boot_loader_state *state)
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003053{
3054 uint32_t active_slot;
3055 const struct flash_area *fap;
3056 struct image_tlv_iter it;
3057 struct image_dependency dep;
3058 uint32_t off;
3059 uint16_t len;
3060 int area_id;
3061 int rc;
3062
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003063 active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003064
3065 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state),
3066 active_slot);
3067 rc = flash_area_open(area_id, &fap);
David Vinczee574f2d2020-07-10 11:42:03 +02003068 if (rc != 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003069 rc = BOOT_EFLASH;
3070 goto done;
David Vinczee574f2d2020-07-10 11:42:03 +02003071 }
3072
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003073 rc = bootutil_tlv_iter_begin(&it, boot_img_hdr(state, active_slot), fap,
3074 IMAGE_TLV_DEPENDENCY, true);
3075 if (rc != 0) {
3076 goto done;
3077 }
David Vinczee574f2d2020-07-10 11:42:03 +02003078
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003079 while (true) {
3080 rc = bootutil_tlv_iter_next(&it, &off, &len, NULL);
3081 if (rc < 0) {
3082 return -1;
3083 } else if (rc > 0) {
3084 rc = 0;
3085 break;
3086 }
David Vinczee574f2d2020-07-10 11:42:03 +02003087
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003088 if (len != sizeof(dep)) {
3089 rc = BOOT_EBADIMAGE;
3090 goto done;
3091 }
3092
3093 rc = LOAD_IMAGE_DATA(boot_img_hdr(state, active_slot),
3094 fap, off, &dep, len);
3095 if (rc != 0) {
3096 rc = BOOT_EFLASH;
3097 goto done;
3098 }
3099
3100 if (dep.image_id >= BOOT_IMAGE_NUMBER) {
3101 rc = BOOT_EBADARGS;
3102 goto done;
3103 }
3104
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003105 rc = boot_verify_slot_dependency_ram(state, &dep);
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003106 if (rc != 0) {
3107 /* Dependency not satisfied. */
3108 goto done;
3109 }
3110 }
3111
3112done:
3113 flash_area_close(fap);
3114 return rc;
3115}
3116
3117/**
3118 * Checks the dependency of all the active slots. If an image found with
3119 * invalid or not satisfied dependencies the image is removed from SRAM (in
3120 * case of MCUBOOT_RAM_LOAD strategy) and its slot is set to unavailable.
3121 *
3122 * @param state Boot loader status information.
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003123 *
3124 * @return 0 if dependencies are met; nonzero otherwise.
3125 */
3126static int
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003127boot_verify_dependencies_ram(struct boot_loader_state *state)
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003128{
3129 int rc = -1;
3130 uint32_t active_slot;
3131
3132 IMAGES_ITER(BOOT_CURR_IMG(state)) {
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003133 if (state->img_mask[BOOT_CURR_IMG(state)]) {
3134 continue;
3135 }
3136 rc = boot_verify_slot_dependencies_ram(state);
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003137 if (rc != 0) {
3138 /* Dependencies not met or invalid dependencies. */
3139
3140#ifdef MCUBOOT_RAM_LOAD
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003141 boot_remove_image_from_sram(state);
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003142#endif /* MCUBOOT_RAM_LOAD */
3143
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003144 active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot;
3145 state->slot_usage[BOOT_CURR_IMG(state)].slot_available[active_slot] = false;
3146 state->slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003147
3148 return rc;
3149 }
3150 }
3151
3152 return rc;
3153}
3154#endif /* (BOOT_IMAGE_NUMBER > 1) */
3155
3156/**
3157 * Tries to load a slot for all the images with validation.
3158 *
3159 * @param state Boot loader status information.
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003160 *
3161 * @return 0 on success; nonzero on failure.
3162 */
3163fih_int
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003164boot_load_and_validate_images(struct boot_loader_state *state)
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003165{
3166 uint32_t active_slot;
3167 int rc;
3168 fih_int fih_rc;
3169
3170 /* Go over all the images and try to load one */
3171 IMAGES_ITER(BOOT_CURR_IMG(state)) {
3172 /* All slots tried until a valid image found. Breaking from this loop
3173 * means that a valid image found or already loaded. If no slot is
3174 * found the function returns with error code. */
3175 while (true) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003176 /* Go over all the slots and try to load one */
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003177 active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003178 if (active_slot != NO_ACTIVE_SLOT){
3179 /* A slot is already active, go to next image. */
3180 break;
3181 }
3182
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003183 active_slot = find_slot_with_highest_version(state);
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003184 if (active_slot == NO_ACTIVE_SLOT) {
3185 BOOT_LOG_INF("No slot to load for image %u",
3186 (unsigned)BOOT_CURR_IMG(state));
3187 FIH_RET(FIH_FAILURE);
3188 }
3189
3190 /* Save the number of the active slot. */
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003191 state->slot_usage[BOOT_CURR_IMG(state)].active_slot = active_slot;
3192
3193#if BOOT_IMAGE_NUMBER > 1
3194 if (state->img_mask[BOOT_CURR_IMG(state)]) {
3195 continue;
3196 }
3197#endif
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003198
3199#ifdef MCUBOOT_DIRECT_XIP
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003200 rc = boot_rom_address_check(state);
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003201 if (rc != 0) {
3202 /* The image is placed in an unsuitable slot. */
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003203 state->slot_usage[BOOT_CURR_IMG(state)].slot_available[active_slot] = false;
3204 state->slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003205 continue;
David Vinczee574f2d2020-07-10 11:42:03 +02003206 }
David Vincze505fba22020-10-22 13:53:29 +02003207
3208#ifdef MCUBOOT_DIRECT_XIP_REVERT
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003209 rc = boot_select_or_erase(state);
David Vincze505fba22020-10-22 13:53:29 +02003210 if (rc != 0) {
3211 /* The selected image slot has been erased. */
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003212 state->slot_usage[BOOT_CURR_IMG(state)].slot_available[active_slot] = false;
3213 state->slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT;
David Vincze505fba22020-10-22 13:53:29 +02003214 continue;
3215 }
3216#endif /* MCUBOOT_DIRECT_XIP_REVERT */
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003217#endif /* MCUBOOT_DIRECT_XIP */
David Vincze505fba22020-10-22 13:53:29 +02003218
Tamas Banfe031092020-09-10 17:32:39 +02003219#ifdef MCUBOOT_RAM_LOAD
3220 /* Image is first loaded to RAM and authenticated there in order to
3221 * prevent TOCTOU attack during image copy. This could be applied
3222 * when loading images from external (untrusted) flash to internal
3223 * (trusted) RAM and image is authenticated before copying.
3224 */
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003225 rc = boot_load_image_to_sram(state);
Tamas Banfe031092020-09-10 17:32:39 +02003226 if (rc != 0 ) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003227 /* Image cannot be ramloaded. */
3228 boot_remove_image_from_flash(state, active_slot);
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003229 state->slot_usage[BOOT_CURR_IMG(state)].slot_available[active_slot] = false;
3230 state->slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT;
Tamas Banfe031092020-09-10 17:32:39 +02003231 continue;
Tamas Banfe031092020-09-10 17:32:39 +02003232 }
3233#endif /* MCUBOOT_RAM_LOAD */
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003234
3235 FIH_CALL(boot_validate_slot, fih_rc, state, active_slot, NULL);
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003236 if (fih_eq(fih_rc, FIH_SUCCESS) != FIH_TRUE) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003237 /* Image is invalid. */
Tamas Banfe031092020-09-10 17:32:39 +02003238#ifdef MCUBOOT_RAM_LOAD
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003239 boot_remove_image_from_sram(state);
Tamas Banfe031092020-09-10 17:32:39 +02003240#endif /* MCUBOOT_RAM_LOAD */
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003241 state->slot_usage[BOOT_CURR_IMG(state)].slot_available[active_slot] = false;
3242 state->slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003243 continue;
David Vincze505fba22020-10-22 13:53:29 +02003244 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003245
3246 /* Valid image loaded from a slot, go to next image. */
3247 break;
David Vinczee574f2d2020-07-10 11:42:03 +02003248 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003249 }
3250
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003251 (void) rc;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003252 FIH_RET(FIH_SUCCESS);
3253}
3254
3255/**
3256 * Updates the security counter for the current image.
3257 *
3258 * @param state Boot loader status information.
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003259 *
3260 * @return 0 on success; nonzero on failure.
3261 */
3262static int
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003263boot_update_hw_rollback_protection_ram(struct boot_loader_state *state)
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003264{
3265#ifdef MCUBOOT_HW_ROLLBACK_PROT
3266 int rc;
3267
3268 /* Update the stored security counter with the newer (active) image's
3269 * security counter value.
3270 */
3271#if defined(MCUBOOT_DIRECT_XIP) && defined(MCUBOOT_DIRECT_XIP_REVERT)
3272 /* When the 'revert' mechanism is enabled in direct-xip mode, the
3273 * security counter can be increased only after reboot, if the image
3274 * has been confirmed at runtime (the image_ok flag has been set).
3275 * This way a 'revert' can be performed when it's necessary.
3276 */
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003277 if (state->slot_usage[BOOT_CURR_IMG(state)].swap_state.image_ok == BOOT_FLAG_SET) {
David Vincze505fba22020-10-22 13:53:29 +02003278#endif
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003279 rc = boot_update_security_counter(BOOT_CURR_IMG(state),
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003280 state->slot_usage[BOOT_CURR_IMG(state)].active_slot,
3281 boot_img_hdr(state, state->slot_usage[BOOT_CURR_IMG(state)].active_slot));
David Vinczee574f2d2020-07-10 11:42:03 +02003282 if (rc != 0) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003283 BOOT_LOG_ERR("Security counter update failed after image "
3284 "validation.");
3285 return rc;
David Vinczee574f2d2020-07-10 11:42:03 +02003286 }
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003287#if defined(MCUBOOT_DIRECT_XIP) && defined(MCUBOOT_DIRECT_XIP_REVERT)
3288 }
3289#endif
David Vinczee574f2d2020-07-10 11:42:03 +02003290
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003291 return 0;
David Vinczee574f2d2020-07-10 11:42:03 +02003292
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003293#else /* MCUBOOT_HW_ROLLBACK_PROT */
3294 (void) (state);
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003295 return 0;
3296#endif
3297}
David Vinczee574f2d2020-07-10 11:42:03 +02003298
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003299fih_int
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003300context_boot_go_ram(struct boot_loader_state *state, struct boot_rsp *rsp)
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003301{
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003302 int rc;
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003303 fih_int fih_rc = FIH_FAILURE;
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003304
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003305 rc = boot_get_slot_usage(state);
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003306 if (rc != 0) {
David Vinczee574f2d2020-07-10 11:42:03 +02003307 goto out;
3308 }
3309
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003310#if (BOOT_IMAGE_NUMBER > 1)
3311 while (true) {
3312#endif
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003313 FIH_CALL(boot_load_and_validate_images, fih_rc, state);
3314 if (fih_eq(fih_rc, FIH_SUCCESS) != FIH_TRUE) {
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003315 goto out;
3316 }
3317
3318#if (BOOT_IMAGE_NUMBER > 1)
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003319 rc = boot_verify_dependencies_ram(state);
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003320 if (rc != 0) {
3321 /* Dependency check failed for an image, it has been removed from
3322 * SRAM in case of MCUBOOT_RAM_LOAD strategy, and set to
3323 * unavailable. Try to load an image from another slot.
3324 */
3325 continue;
3326 }
3327 /* Dependency check was successful. */
3328 break;
3329 }
3330#endif
3331
3332 IMAGES_ITER(BOOT_CURR_IMG(state)) {
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003333#if BOOT_IMAGE_NUMBER > 1
3334 if (state->img_mask[BOOT_CURR_IMG(state)]) {
3335 continue;
3336 }
3337#endif
3338 rc = boot_update_hw_rollback_protection_ram(state);
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003339 if (rc != 0) {
3340 goto out;
3341 }
3342
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003343 rc = boot_add_shared_data(state, state->slot_usage[BOOT_CURR_IMG(state)].active_slot);
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003344 if (rc != 0) {
3345 goto out;
3346 }
3347 }
3348
3349 /* All image loaded successfully. */
3350#ifdef MCUBOOT_HAVE_LOGGING
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003351 print_loaded_images(state);
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003352#endif
3353
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003354 fill_rsp(state, rsp);
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003355
David Vinczee574f2d2020-07-10 11:42:03 +02003356out:
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003357 close_all_flash_areas(state);
Raef Colese8fe6cf2020-05-26 13:07:40 +01003358
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003359 if (FIH_TRUE == fih_eq(fih_rc, FIH_SUCCESS)) {
3360 fih_rc = fih_int_encode_zero_equality(rc);
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003361 }
Raef Colese8fe6cf2020-05-26 13:07:40 +01003362
Roman Okhrimenko977b3752022-03-31 14:40:48 +03003363 FIH_RET(fih_rc);
David Vinczee574f2d2020-07-10 11:42:03 +02003364}
Tamas Banfe031092020-09-10 17:32:39 +02003365#endif /* MCUBOOT_DIRECT_XIP || MCUBOOT_RAM_LOAD */
David Vinczee574f2d2020-07-10 11:42:03 +02003366
3367/**
Raef Colese8fe6cf2020-05-26 13:07:40 +01003368 * Prepares the booting process. This function moves images around in flash as
David Vinczee574f2d2020-07-10 11:42:03 +02003369 * appropriate, and tells you what address to boot from.
3370 *
3371 * @param rsp On success, indicates how booting should occur.
3372 *
Raef Colese8fe6cf2020-05-26 13:07:40 +01003373 * @return FIH_SUCCESS on success; nonzero on failure.
David Vinczee574f2d2020-07-10 11:42:03 +02003374 */
Raef Colese8fe6cf2020-05-26 13:07:40 +01003375fih_int
David Vinczee574f2d2020-07-10 11:42:03 +02003376boot_go(struct boot_rsp *rsp)
3377{
Raef Colese8fe6cf2020-05-26 13:07:40 +01003378 fih_int fih_rc = FIH_FAILURE;
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003379
3380 boot_state_clear(NULL);
3381
3382 FIH_CALL(context_boot_go_flash, fih_rc, &boot_data, rsp);
Raef Colese8fe6cf2020-05-26 13:07:40 +01003383 FIH_RET(fih_rc);
David Vinczee574f2d2020-07-10 11:42:03 +02003384}
Roman Okhrimenkodc0ca082023-06-21 20:49:51 +03003385
3386/**
3387 * Prepares the booting process, considering only a single image. This function
3388 * moves images around in flash as appropriate, and tells you what address to
3389 * boot from.
3390 *
3391 * @param rsp On success, indicates how booting should occur.
3392 *
3393 * @param image_id The image ID to prepare the boot process for.
3394 *
3395 * @return FIH_SUCCESS on success; nonzero on failure.
3396 */
3397fih_int
3398boot_go_for_image_id(struct boot_rsp *rsp, uint32_t image_id)
3399{
3400 fih_int fih_rc = FIH_FAILURE;
3401
3402 if (image_id >= BOOT_IMAGE_NUMBER) {
3403 FIH_RET(FIH_FAILURE);
3404 }
3405
3406#if BOOT_IMAGE_NUMBER > 1
3407 (void)memset(&boot_data.img_mask, 1, BOOT_IMAGE_NUMBER);
3408 boot_data.img_mask[image_id] = 0;
3409#endif
3410
3411 FIH_CALL(context_boot_go_flash, fih_rc, &boot_data, rsp);
3412 FIH_RET(fih_rc);
3413}
3414
3415#if defined(MCUBOOT_RAM_LOAD)
3416/**
3417 * Prepares the booting process, considering only a single image. This function
3418 * moves images around in flash as appropriate, and tells you what address to
3419 * boot from.
3420 *
3421 * @param rsp On success, indicates how booting should occur.
3422 *
3423 * @param image_id The image ID to prepare the boot process for.
3424 *
3425 * @return FIH_SUCCESS on success; nonzero on failure.
3426 */
3427fih_int
3428boot_go_for_image_id_ram(struct boot_rsp *rsp, uint32_t image_id)
3429{
3430 fih_int fih_rc = FIH_FAILURE;
3431
3432 if (image_id >= BOOT_IMAGE_NUMBER) {
3433 FIH_RET(FIH_FAILURE);
3434 }
3435
3436#if BOOT_IMAGE_NUMBER > 1
3437 (void)memset(&boot_data.img_mask, 1, BOOT_IMAGE_NUMBER);
3438 boot_data.img_mask[image_id] = 0;
3439#endif
3440
3441 FIH_CALL(context_boot_go_ram, fih_rc, &boot_data, rsp);
3442 FIH_RET(fih_rc);
3443}
3444
3445#endif /* MCUBOOT_RAM_LOAD */
3446
3447/**
3448 * Clears the boot state, so that previous operations have no effect on new
3449 * ones.
3450 *
3451 * @param state The state that should be cleared. If the value
3452 * is NULL, the default bootloader state will be
3453 * cleared.
3454 */
3455void boot_state_clear(struct boot_loader_state *state)
3456{
3457 if (state != NULL) {
3458 (void)memset(state, 0, sizeof(struct boot_loader_state));
3459 } else {
3460 (void)memset(&boot_data, 0, sizeof(struct boot_loader_state));
3461 }
3462}