blob: 3e0ba902648edcad95b43fdb64ab8fbeb9783979 [file] [log] [blame]
Tamas Banf70ef8c2017-12-19 15:35:09 +00001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
Tamas Ban581034a2017-12-19 19:54:37 +000020/*
Tamas Ban4fb8e9d2018-02-23 14:22:03 +000021 * Original code taken from mcuboot project at:
David Vincze39e78552018-10-10 17:10:01 +020022 * https://github.com/JuulLabs-OSS/mcuboot
David Vincze401c7422019-06-21 20:44:05 +020023 * Git SHA of the original version: 3c469bc698a9767859ed73cd0201c44161204d5c
Tamas Ban5b647472019-01-05 08:59:30 +000024 * Modifications are Copyright (c) 2018-2019 Arm Limited.
Tamas Ban581034a2017-12-19 19:54:37 +000025 */
26
Tamas Banf70ef8c2017-12-19 15:35:09 +000027/**
28 * This file provides an interface to the boot loader. Functions defined in
29 * this file should only be called while the boot loader is running.
30 */
31
32#include <assert.h>
33#include <stddef.h>
34#include <stdbool.h>
35#include <inttypes.h>
36#include <stdlib.h>
37#include <string.h>
Tamas Banc3828852018-02-01 12:24:16 +000038#include "flash_map/flash_map.h"
Tamas Banf70ef8c2017-12-19 15:35:09 +000039#include "bootutil/bootutil.h"
40#include "bootutil/image.h"
41#include "bootutil_priv.h"
David Vincze73dfbc52019-10-11 13:54:58 +020042#include "bootutil/bootutil_log.h"
Tamas Bana9de4a62018-09-18 08:09:45 +010043#include "bl2/include/tfm_boot_status.h"
44#include "bl2/include/boot_record.h"
David Vincze060968d2019-05-23 01:13:14 +020045#include "security_cnt.h"
Tamas Banf70ef8c2017-12-19 15:35:09 +000046
Tamas Banf70ef8c2017-12-19 15:35:09 +000047static struct boot_loader_state boot_data;
David Vinczebb207982019-08-21 15:13:04 +020048uint8_t current_image = 0;
Tamas Banf70ef8c2017-12-19 15:35:09 +000049
Oliver Swedef9982442018-08-24 18:37:44 +010050#if !defined(MCUBOOT_NO_SWAP) && !defined(MCUBOOT_RAM_LOADING)
David Vincze39e78552018-10-10 17:10:01 +020051
David Vincze8bdfc2d2019-03-18 15:49:23 +010052#if defined(MCUBOOT_VALIDATE_PRIMARY_SLOT) && !defined(MCUBOOT_OVERWRITE_ONLY)
David Vincze39e78552018-10-10 17:10:01 +020053static int boot_status_fails = 0;
54#define BOOT_STATUS_ASSERT(x) \
55 do { \
56 if (!(x)) { \
57 boot_status_fails++; \
58 } \
59 } while (0)
60#else
David Vincze401c7422019-06-21 20:44:05 +020061#define BOOT_STATUS_ASSERT(x) ASSERT(x)
David Vincze39e78552018-10-10 17:10:01 +020062#endif
63
Tamas Banf70ef8c2017-12-19 15:35:09 +000064struct boot_status_table {
David Vincze8bdfc2d2019-03-18 15:49:23 +010065 uint8_t bst_magic_primary_slot;
Tamas Banf70ef8c2017-12-19 15:35:09 +000066 uint8_t bst_magic_scratch;
David Vincze8bdfc2d2019-03-18 15:49:23 +010067 uint8_t bst_copy_done_primary_slot;
Tamas Banf70ef8c2017-12-19 15:35:09 +000068 uint8_t bst_status_source;
69};
70
71/**
72 * This set of tables maps swap state contents to boot status location.
73 * When searching for a match, these tables must be iterated in order.
74 */
75static const struct boot_status_table boot_status_tables[] = {
76 {
David Vincze8bdfc2d2019-03-18 15:49:23 +010077 /* | primary slot | scratch |
78 * ----------+--------------+--------------|
79 * magic | Good | Any |
80 * copy-done | Set | N/A |
81 * ----------+--------------+--------------'
82 * source: none |
83 * ----------------------------------------'
Tamas Banf70ef8c2017-12-19 15:35:09 +000084 */
David Vincze8bdfc2d2019-03-18 15:49:23 +010085 .bst_magic_primary_slot = BOOT_MAGIC_GOOD,
David Vincze401c7422019-06-21 20:44:05 +020086 .bst_magic_scratch = BOOT_MAGIC_NOTGOOD,
David Vincze8bdfc2d2019-03-18 15:49:23 +010087 .bst_copy_done_primary_slot = BOOT_FLAG_SET,
88 .bst_status_source = BOOT_STATUS_SOURCE_NONE,
Tamas Banf70ef8c2017-12-19 15:35:09 +000089 },
90
91 {
David Vincze8bdfc2d2019-03-18 15:49:23 +010092 /* | primary slot | scratch |
93 * ----------+--------------+--------------|
94 * magic | Good | Any |
95 * copy-done | Unset | N/A |
96 * ----------+--------------+--------------'
97 * source: primary slot |
98 * ----------------------------------------'
Tamas Banf70ef8c2017-12-19 15:35:09 +000099 */
David Vincze8bdfc2d2019-03-18 15:49:23 +0100100 .bst_magic_primary_slot = BOOT_MAGIC_GOOD,
David Vincze401c7422019-06-21 20:44:05 +0200101 .bst_magic_scratch = BOOT_MAGIC_NOTGOOD,
David Vincze8bdfc2d2019-03-18 15:49:23 +0100102 .bst_copy_done_primary_slot = BOOT_FLAG_UNSET,
103 .bst_status_source = BOOT_STATUS_SOURCE_PRIMARY_SLOT,
Tamas Banf70ef8c2017-12-19 15:35:09 +0000104 },
105
106 {
David Vincze8bdfc2d2019-03-18 15:49:23 +0100107 /* | primary slot | scratch |
108 * ----------+--------------+--------------|
109 * magic | Any | Good |
110 * copy-done | Any | N/A |
111 * ----------+--------------+--------------'
112 * source: scratch |
113 * ----------------------------------------'
Tamas Banf70ef8c2017-12-19 15:35:09 +0000114 */
David Vincze8bdfc2d2019-03-18 15:49:23 +0100115 .bst_magic_primary_slot = BOOT_MAGIC_ANY,
116 .bst_magic_scratch = BOOT_MAGIC_GOOD,
117 .bst_copy_done_primary_slot = BOOT_FLAG_ANY,
118 .bst_status_source = BOOT_STATUS_SOURCE_SCRATCH,
Tamas Banf70ef8c2017-12-19 15:35:09 +0000119 },
120
121 {
David Vincze8bdfc2d2019-03-18 15:49:23 +0100122 /* | primary slot | scratch |
123 * ----------+--------------+--------------|
124 * magic | Unset | Any |
125 * copy-done | Unset | N/A |
126 * ----------+--------------+--------------|
127 * source: varies |
128 * ----------------------------------------+--------------------------+
Tamas Banf70ef8c2017-12-19 15:35:09 +0000129 * This represents one of two cases: |
130 * o No swaps ever (no status to read, so no harm in checking). |
David Vincze8bdfc2d2019-03-18 15:49:23 +0100131 * o Mid-revert; status in the primary slot. |
Tamas Banf70ef8c2017-12-19 15:35:09 +0000132 * -------------------------------------------------------------------'
133 */
David Vincze8bdfc2d2019-03-18 15:49:23 +0100134 .bst_magic_primary_slot = BOOT_MAGIC_UNSET,
135 .bst_magic_scratch = BOOT_MAGIC_ANY,
136 .bst_copy_done_primary_slot = BOOT_FLAG_UNSET,
137 .bst_status_source = BOOT_STATUS_SOURCE_PRIMARY_SLOT,
Tamas Banf70ef8c2017-12-19 15:35:09 +0000138 },
139};
140
141#define BOOT_STATUS_TABLES_COUNT \
Tamas Ban581034a2017-12-19 19:54:37 +0000142 (sizeof(boot_status_tables) / sizeof(boot_status_tables[0]))
Tamas Banf70ef8c2017-12-19 15:35:09 +0000143
144#define BOOT_LOG_SWAP_STATE(area, state) \
David Vincze401c7422019-06-21 20:44:05 +0200145 BOOT_LOG_INF("%s: magic=%5s, swap_type=0x%x, copy_done=0x%x, " \
146 "image_ok=0x%x", \
Tamas Banf70ef8c2017-12-19 15:35:09 +0000147 (area), \
148 ((state)->magic == BOOT_MAGIC_GOOD ? "good" : \
149 (state)->magic == BOOT_MAGIC_UNSET ? "unset" : \
150 "bad"), \
David Vincze401c7422019-06-21 20:44:05 +0200151 (state)->swap_type, \
Tamas Banf70ef8c2017-12-19 15:35:09 +0000152 (state)->copy_done, \
153 (state)->image_ok)
Oliver Swedef9982442018-08-24 18:37:44 +0100154#endif /* !MCUBOOT_NO_SWAP && !MCUBOOT_RAM_LOADING */
Tamas Banf70ef8c2017-12-19 15:35:09 +0000155
Tamas Ban056ed0b2019-09-16 12:48:32 +0100156/*
157 * \brief Verifies the image header: magic value, flags, integer overflow.
158 *
159 * \retval 0
160 * \retval BOOT_EBADIMAGE
161 */
162static int
163boot_verify_image_header(struct image_header *hdr)
164{
165 uint32_t image_end;
166
167 if (hdr->ih_magic != IMAGE_MAGIC) {
168 return BOOT_EBADIMAGE;
169 }
170
171 /* Check input parameters against integer overflow */
172 if (boot_add_uint32_overflow_check(hdr->ih_hdr_size, hdr->ih_img_size)) {
173 return BOOT_EBADIMAGE;
174 }
175
176 image_end = hdr->ih_hdr_size + hdr->ih_img_size;
177 if (boot_add_uint32_overflow_check(image_end, hdr->ih_protect_tlv_size)) {
178 return BOOT_EBADIMAGE;
179 }
180
181
182#if MCUBOOT_RAM_LOADING
183 if (!(hdr->ih_flags & IMAGE_F_RAM_LOAD)) {
184 return BOOT_EBADIMAGE;
185 }
186
187 /* Check input parameters against integer overflow */
188 if (boot_add_uint32_overflow_check(image_end, hdr->ih_load_addr)) {
189 return BOOT_EBADIMAGE;
190 }
191#endif
192
193 return 0;
194}
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000195
196static int
197boot_read_image_header(int slot, struct image_header *out_hdr)
198{
199 const struct flash_area *fap = NULL;
200 int area_id;
201 int rc;
202
203 area_id = flash_area_id_from_image_slot(slot);
204 rc = flash_area_open(area_id, &fap);
205 if (rc != 0) {
206 rc = BOOT_EFLASH;
207 goto done;
208 }
209
210 rc = flash_area_read(fap, 0, out_hdr, sizeof(*out_hdr));
211 if (rc != 0) {
212 rc = BOOT_EFLASH;
213 goto done;
214 }
215
Tamas Ban056ed0b2019-09-16 12:48:32 +0100216 rc = boot_verify_image_header(out_hdr);
217 BOOT_IMG_HDR_IS_VALID(&boot_data, slot) = (rc == 0);
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000218
219done:
220 flash_area_close(fap);
221 return rc;
222}
223
224static int
David Vincze39e78552018-10-10 17:10:01 +0200225boot_read_image_headers(bool require_all)
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000226{
227 int rc;
228 int i;
229
230 for (i = 0; i < BOOT_NUM_SLOTS; i++) {
231 rc = boot_read_image_header(i, boot_img_hdr(&boot_data, i));
232 if (rc != 0) {
David Vincze39e78552018-10-10 17:10:01 +0200233 /* If `require_all` is set, fail on any single fail, otherwise
234 * if at least the first slot's header was read successfully,
235 * then the boot loader can attempt a boot.
236 *
237 * Failure to read any headers is a fatal error.
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000238 */
David Vincze39e78552018-10-10 17:10:01 +0200239 if (i > 0 && !require_all) {
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000240 return 0;
241 } else {
242 return rc;
243 }
244 }
245 }
246
247 return 0;
248}
249
Raef Coles204c5b42019-09-05 09:18:47 +0100250static uint32_t
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000251boot_write_sz(void)
252{
Raef Coles204c5b42019-09-05 09:18:47 +0100253 uint32_t elem_sz;
254 uint32_t align;
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000255
256 /* Figure out what size to write update status update as. The size depends
257 * on what the minimum write size is for scratch area, active image slot.
258 * We need to use the bigger of those 2 values.
259 */
David Vincze7384ee72019-07-23 17:00:42 +0200260 elem_sz = flash_area_align(BOOT_IMG_AREA(&boot_data, BOOT_PRIMARY_SLOT));
261 align = flash_area_align(BOOT_SCRATCH_AREA(&boot_data));
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000262 if (align > elem_sz) {
263 elem_sz = align;
264 }
265
266 return elem_sz;
267}
268
269/**
270 * Determines the sector layout of both image slots and the scratch area.
271 * This information is necessary for calculating the number of bytes to erase
272 * and copy during an image swap. The information collected during this
273 * function is used to populate the boot_data global.
274 */
275static int
276boot_read_sectors(void)
277{
278 int rc;
279
David Vincze8bdfc2d2019-03-18 15:49:23 +0100280 rc = boot_initialize_area(&boot_data, FLASH_AREA_IMAGE_PRIMARY);
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000281 if (rc != 0) {
282 return BOOT_EFLASH;
283 }
284
David Vincze8bdfc2d2019-03-18 15:49:23 +0100285 rc = boot_initialize_area(&boot_data, FLASH_AREA_IMAGE_SECONDARY);
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000286 if (rc != 0) {
287 return BOOT_EFLASH;
288 }
289
David Vincze401c7422019-06-21 20:44:05 +0200290 rc = boot_initialize_area(&boot_data, FLASH_AREA_IMAGE_SCRATCH);
291 if (rc != 0) {
292 return BOOT_EFLASH;
293 }
294
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000295 BOOT_WRITE_SZ(&boot_data) = boot_write_sz();
296
297 return 0;
298}
299
David Vincze060968d2019-05-23 01:13:14 +0200300/**
301 * Validate image hash/signature and security counter in a slot.
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000302 */
303static int
David Vincze401c7422019-06-21 20:44:05 +0200304boot_image_check(struct image_header *hdr, const struct flash_area *fap,
305 struct boot_status *bs)
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000306{
307 static uint8_t tmpbuf[BOOT_TMPBUF_SZ];
308
David Vincze401c7422019-06-21 20:44:05 +0200309 (void)bs;
310
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000311 if (bootutil_img_validate(hdr, fap, tmpbuf, BOOT_TMPBUF_SZ,
Tamas Ban0e8ab302019-01-17 11:45:31 +0000312 NULL, 0, NULL)) {
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000313 return BOOT_EBADIMAGE;
314 }
315 return 0;
316}
317
David Vincze401c7422019-06-21 20:44:05 +0200318/*
319 * Check that a memory area consists of a given value.
320 */
321static inline bool
322boot_data_is_set_to(uint8_t val, void *data, size_t len)
David Vincze39e78552018-10-10 17:10:01 +0200323{
324 uint8_t i;
David Vincze401c7422019-06-21 20:44:05 +0200325 uint8_t *p = (uint8_t *)data;
326 for (i = 0; i < len; i++) {
327 if (val != p[i]) {
328 return false;
David Vincze39e78552018-10-10 17:10:01 +0200329 }
330 }
David Vincze401c7422019-06-21 20:44:05 +0200331 return true;
David Vincze39e78552018-10-10 17:10:01 +0200332}
333
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000334static int
David Vincze401c7422019-06-21 20:44:05 +0200335boot_check_header_erased(int slot)
336{
337 const struct flash_area *fap;
338 struct image_header *hdr;
339 uint8_t erased_val;
340 int rc;
341
342 rc = flash_area_open(flash_area_id_from_image_slot(slot), &fap);
343 if (rc != 0) {
344 return -1;
345 }
346
347 erased_val = flash_area_erased_val(fap);
348 flash_area_close(fap);
349
350 hdr = boot_img_hdr(&boot_data, slot);
351 if (!boot_data_is_set_to(erased_val, &hdr->ih_magic,
352 sizeof(hdr->ih_magic))) {
353 return -1;
354 }
355
356 return 0;
357}
358
359static int
360boot_validate_slot(int slot, struct boot_status *bs)
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000361{
362 const struct flash_area *fap;
363 struct image_header *hdr;
364 int rc;
365
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000366 rc = flash_area_open(flash_area_id_from_image_slot(slot), &fap);
367 if (rc != 0) {
368 return BOOT_EFLASH;
369 }
370
David Vincze39e78552018-10-10 17:10:01 +0200371 hdr = boot_img_hdr(&boot_data, slot);
David Vincze401c7422019-06-21 20:44:05 +0200372 if ((boot_check_header_erased(slot) == 0) ||
373 (hdr->ih_flags & IMAGE_F_NON_BOOTABLE)) {
David Vincze8bdfc2d2019-03-18 15:49:23 +0100374 /* No bootable image in slot; continue booting from the primary slot. */
David Vincze401c7422019-06-21 20:44:05 +0200375 rc = -1;
376 goto out;
David Vincze39e78552018-10-10 17:10:01 +0200377 }
378
Tamas Ban056ed0b2019-09-16 12:48:32 +0100379 if ((!BOOT_IMG_HDR_IS_VALID(&boot_data, slot)) ||
380 (boot_image_check(hdr, fap, bs) != 0)) {
David Vincze401c7422019-06-21 20:44:05 +0200381 if (slot != BOOT_PRIMARY_SLOT) {
David Vincze26e8c8a2018-08-28 16:59:41 +0200382 rc = flash_area_erase(fap, 0, fap->fa_size);
383 if(rc != 0) {
David Vincze401c7422019-06-21 20:44:05 +0200384 rc = BOOT_EFLASH;
385 goto out;
David Vincze26e8c8a2018-08-28 16:59:41 +0200386 }
David Vincze8bdfc2d2019-03-18 15:49:23 +0100387 /* Image in the secondary slot is invalid. Erase the image and
388 * continue booting from the primary slot.
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000389 */
390 }
David Vincze8bdfc2d2019-03-18 15:49:23 +0100391 BOOT_LOG_ERR("Authentication failed! Image in the %s slot is not valid."
392 , (slot == BOOT_PRIMARY_SLOT) ? "primary" : "secondary");
David Vincze401c7422019-06-21 20:44:05 +0200393 rc = -1;
394 goto out;
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000395 }
396
David Vincze8bdfc2d2019-03-18 15:49:23 +0100397 /* Image in the secondary slot is valid. */
David Vincze401c7422019-06-21 20:44:05 +0200398 rc = 0;
399
400out:
401 flash_area_close(fap);
402 return rc;
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000403}
404
David Vincze060968d2019-05-23 01:13:14 +0200405/**
406 * Updates the stored security counter value with the image's security counter
407 * value which resides in the given slot if it's greater than the stored value.
408 *
409 * @param slot Slot number of the image.
410 * @param hdr Pointer to the image header structure of the image that is
411 * currently stored in the given slot.
412 *
413 * @return 0 on success; nonzero on failure.
414 */
415static int
416boot_update_security_counter(int slot, struct image_header *hdr)
417{
418 const struct flash_area *fap = NULL;
419 uint32_t img_security_cnt;
420 int rc;
421
422 rc = flash_area_open(flash_area_id_from_image_slot(slot), &fap);
423 if (rc != 0) {
424 rc = BOOT_EFLASH;
425 goto done;
426 }
427
428 rc = bootutil_get_img_security_cnt(hdr, fap, &img_security_cnt);
429 if (rc != 0) {
430 goto done;
431 }
432
David Vincze0b41ee22019-06-28 14:28:20 +0200433 rc = boot_nv_security_counter_update(current_image, img_security_cnt);
David Vincze060968d2019-05-23 01:13:14 +0200434 if (rc != 0) {
435 goto done;
436 }
437
438done:
439 flash_area_close(fap);
440 return rc;
441}
442
Oliver Swedef9982442018-08-24 18:37:44 +0100443#if !defined(MCUBOOT_NO_SWAP) && !defined(MCUBOOT_OVERWRITE_ONLY)
444/*
445 * Compute the total size of the given image. Includes the size of
446 * the TLVs.
447 */
448static int
449boot_read_image_size(int slot, struct image_header *hdr, uint32_t *size)
450{
451 const struct flash_area *fap = NULL;
452 struct image_tlv_info info;
453 int area_id;
454 int rc;
455
456 area_id = flash_area_id_from_image_slot(slot);
457 rc = flash_area_open(area_id, &fap);
458 if (rc != 0) {
459 rc = BOOT_EFLASH;
460 goto done;
461 }
462
463 rc = flash_area_read(fap, hdr->ih_hdr_size + hdr->ih_img_size,
464 &info, sizeof(info));
465 if (rc != 0) {
466 rc = BOOT_EFLASH;
467 goto done;
468 }
469 if (info.it_magic != IMAGE_TLV_INFO_MAGIC) {
470 rc = BOOT_EBADIMAGE;
471 goto done;
472 }
473 *size = hdr->ih_hdr_size + hdr->ih_img_size + info.it_tlv_tot;
474 rc = 0;
475
476done:
477 flash_area_close(fap);
478 return rc;
479}
480#endif /* !MCUBOOT_NO_SWAP && !MCUBOOT_OVERWRITE_ONLY */
481
482#if !defined(MCUBOOT_NO_SWAP) && !defined(MCUBOOT_RAM_LOADING)
Tamas Banf70ef8c2017-12-19 15:35:09 +0000483/**
Tamas Ban581034a2017-12-19 19:54:37 +0000484 * Determines where in flash the most recent boot status is stored. The boot
Tamas Banf70ef8c2017-12-19 15:35:09 +0000485 * status is necessary for completing a swap that was interrupted by a boot
486 * loader reset.
487 *
David Vincze401c7422019-06-21 20:44:05 +0200488 * @return A BOOT_STATUS_SOURCE_[...] code indicating where status should
489 * be read from.
Tamas Banf70ef8c2017-12-19 15:35:09 +0000490 */
491static int
492boot_status_source(void)
493{
494 const struct boot_status_table *table;
495 struct boot_swap_state state_scratch;
David Vincze8bdfc2d2019-03-18 15:49:23 +0100496 struct boot_swap_state state_primary_slot;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000497 int rc;
David Vincze39e78552018-10-10 17:10:01 +0200498 size_t i;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000499 uint8_t source;
500
David Vincze8bdfc2d2019-03-18 15:49:23 +0100501 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_PRIMARY,
502 &state_primary_slot);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000503 assert(rc == 0);
504
505 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SCRATCH, &state_scratch);
506 assert(rc == 0);
507
David Vincze401c7422019-06-21 20:44:05 +0200508 BOOT_LOG_SWAP_STATE("Primary image", &state_primary_slot);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000509 BOOT_LOG_SWAP_STATE("Scratch", &state_scratch);
510
511 for (i = 0; i < BOOT_STATUS_TABLES_COUNT; i++) {
512 table = &boot_status_tables[i];
513
David Vincze401c7422019-06-21 20:44:05 +0200514 if (boot_magic_compatible_check(table->bst_magic_primary_slot,
515 state_primary_slot.magic) &&
516 boot_magic_compatible_check(table->bst_magic_scratch,
517 state_scratch.magic) &&
David Vincze8bdfc2d2019-03-18 15:49:23 +0100518 (table->bst_copy_done_primary_slot == BOOT_FLAG_ANY ||
519 table->bst_copy_done_primary_slot == state_primary_slot.copy_done))
520 {
Tamas Banf70ef8c2017-12-19 15:35:09 +0000521 source = table->bst_status_source;
David Vincze7384ee72019-07-23 17:00:42 +0200522
523#if (BOOT_IMAGE_NUMBER > 1)
524 /* In case of multi-image boot it can happen that if boot status
525 * info is found on scratch area then it does not belong to the
526 * currently examined image.
527 */
528 if (source == BOOT_STATUS_SOURCE_SCRATCH &&
529 state_scratch.image_num != current_image) {
530 source = BOOT_STATUS_SOURCE_NONE;
531 }
532#endif
533
Tamas Banf70ef8c2017-12-19 15:35:09 +0000534 BOOT_LOG_INF("Boot source: %s",
535 source == BOOT_STATUS_SOURCE_NONE ? "none" :
536 source == BOOT_STATUS_SOURCE_SCRATCH ? "scratch" :
David Vincze8bdfc2d2019-03-18 15:49:23 +0100537 source == BOOT_STATUS_SOURCE_PRIMARY_SLOT ?
538 "primary slot" : "BUG; can't happen");
Tamas Banf70ef8c2017-12-19 15:35:09 +0000539 return source;
540 }
541 }
542
543 BOOT_LOG_INF("Boot source: none");
544 return BOOT_STATUS_SOURCE_NONE;
545}
546
David Vincze401c7422019-06-21 20:44:05 +0200547/*
548 * Slots are compatible when all sectors that store upto to size of the image
549 * round up to sector size, in both slot's are able to fit in the scratch
550 * area, and have sizes that are a multiple of each other (powers of two
551 * presumably!).
Tamas Banf70ef8c2017-12-19 15:35:09 +0000552 */
553static int
Tamas Banf70ef8c2017-12-19 15:35:09 +0000554boot_slots_compatible(void)
555{
David Vincze401c7422019-06-21 20:44:05 +0200556 size_t num_sectors_primary;
557 size_t num_sectors_secondary;
558 size_t sz0, sz1;
559 size_t primary_slot_sz, secondary_slot_sz;
560 size_t scratch_sz;
561 size_t i, j;
562 int8_t smaller;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000563
David Vincze401c7422019-06-21 20:44:05 +0200564 num_sectors_primary =
565 boot_img_num_sectors(&boot_data, BOOT_PRIMARY_SLOT);
566 num_sectors_secondary =
567 boot_img_num_sectors(&boot_data, BOOT_SECONDARY_SLOT);
568 if ((num_sectors_primary > BOOT_MAX_IMG_SECTORS) ||
569 (num_sectors_secondary > BOOT_MAX_IMG_SECTORS)) {
David Vincze39e78552018-10-10 17:10:01 +0200570 BOOT_LOG_WRN("Cannot upgrade: more sectors than allowed");
Tamas Banf70ef8c2017-12-19 15:35:09 +0000571 return 0;
572 }
David Vincze39e78552018-10-10 17:10:01 +0200573
David Vincze401c7422019-06-21 20:44:05 +0200574 scratch_sz = boot_scratch_area_size(&boot_data);
575
576 /*
577 * The following loop scans all sectors in a linear fashion, assuring that
578 * for each possible sector in each slot, it is able to fit in the other
579 * slot's sector or sectors. Slot's should be compatible as long as any
580 * number of a slot's sectors are able to fit into another, which only
581 * excludes cases where sector sizes are not a multiple of each other.
582 */
583 i = sz0 = primary_slot_sz = 0;
584 j = sz1 = secondary_slot_sz = 0;
585 smaller = 0;
586 while (i < num_sectors_primary || j < num_sectors_secondary) {
587 if (sz0 == sz1) {
588 sz0 += boot_img_sector_size(&boot_data, BOOT_PRIMARY_SLOT, i);
589 sz1 += boot_img_sector_size(&boot_data, BOOT_SECONDARY_SLOT, j);
590 i++;
591 j++;
592 } else if (sz0 < sz1) {
593 sz0 += boot_img_sector_size(&boot_data, BOOT_PRIMARY_SLOT, i);
594 /* Guarantee that multiple sectors of the secondary slot
595 * fit into the primary slot.
596 */
597 if (smaller == 2) {
598 BOOT_LOG_WRN("Cannot upgrade: slots have non-compatible"
599 " sectors");
600 return 0;
601 }
602 smaller = 1;
603 i++;
604 } else {
605 sz1 += boot_img_sector_size(&boot_data, BOOT_SECONDARY_SLOT, j);
606 /* Guarantee that multiple sectors of the primary slot
607 * fit into the secondary slot.
608 */
609 if (smaller == 1) {
610 BOOT_LOG_WRN("Cannot upgrade: slots have non-compatible"
611 " sectors");
612 return 0;
613 }
614 smaller = 2;
615 j++;
616 }
617 if (sz0 == sz1) {
618 primary_slot_sz += sz0;
619 secondary_slot_sz += sz1;
620 /* Scratch has to fit each swap operation to the size of the larger
621 * sector among the primary slot and the secondary slot.
622 */
623 if (sz0 > scratch_sz || sz1 > scratch_sz) {
624 BOOT_LOG_WRN("Cannot upgrade: not all sectors fit inside"
625 " scratch");
626 return 0;
627 }
628 smaller = sz0 = sz1 = 0;
629 }
David Vincze39e78552018-10-10 17:10:01 +0200630 }
631
David Vincze401c7422019-06-21 20:44:05 +0200632 if ((i != num_sectors_primary) ||
633 (j != num_sectors_secondary) ||
634 (primary_slot_sz != secondary_slot_sz)) {
635 BOOT_LOG_WRN("Cannot upgrade: slots are not compatible");
636 return 0;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000637 }
638
639 return 1;
640}
641
Tamas Banf70ef8c2017-12-19 15:35:09 +0000642static uint32_t
643boot_status_internal_off(int idx, int state, int elem_sz)
644{
645 int idx_sz;
646
647 idx_sz = elem_sz * BOOT_STATUS_STATE_COUNT;
648
David Vincze39e78552018-10-10 17:10:01 +0200649 return (idx - BOOT_STATUS_IDX_0) * idx_sz +
650 (state - BOOT_STATUS_STATE_0) * elem_sz;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000651}
652
653/**
654 * Reads the status of a partially-completed swap, if any. This is necessary
655 * to recover in case the boot lodaer was reset in the middle of a swap
656 * operation.
657 */
658static int
659boot_read_status_bytes(const struct flash_area *fap, struct boot_status *bs)
660{
661 uint32_t off;
662 uint8_t status;
663 int max_entries;
664 int found;
David Vincze39e78552018-10-10 17:10:01 +0200665 int found_idx;
666 int invalid;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000667 int rc;
668 int i;
669
670 off = boot_status_off(fap);
671 max_entries = boot_status_entries(fap);
672
673 found = 0;
David Vincze39e78552018-10-10 17:10:01 +0200674 found_idx = 0;
675 invalid = 0;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000676 for (i = 0; i < max_entries; i++) {
David Vincze39e78552018-10-10 17:10:01 +0200677 rc = flash_area_read_is_empty(fap, off + i * BOOT_WRITE_SZ(&boot_data),
678 &status, 1);
679 if (rc < 0) {
Tamas Banf70ef8c2017-12-19 15:35:09 +0000680 return BOOT_EFLASH;
681 }
682
David Vincze39e78552018-10-10 17:10:01 +0200683 if (rc == 1) {
684 if (found && !found_idx) {
685 found_idx = i;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000686 }
687 } else if (!found) {
688 found = 1;
David Vincze39e78552018-10-10 17:10:01 +0200689 } else if (found_idx) {
690 invalid = 1;
691 break;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000692 }
693 }
694
David Vincze39e78552018-10-10 17:10:01 +0200695 if (invalid) {
696 /* This means there was an error writing status on the last
697 * swap. Tell user and move on to validation!
698 */
699 BOOT_LOG_ERR("Detected inconsistent status!");
700
David Vincze8bdfc2d2019-03-18 15:49:23 +0100701#if !defined(MCUBOOT_VALIDATE_PRIMARY_SLOT)
702 /* With validation of the primary slot disabled, there is no way
703 * to be sure the swapped primary slot is OK, so abort!
David Vincze39e78552018-10-10 17:10:01 +0200704 */
705 assert(0);
706#endif
707 }
708
Tamas Banf70ef8c2017-12-19 15:35:09 +0000709 if (found) {
David Vincze39e78552018-10-10 17:10:01 +0200710 if (!found_idx) {
711 found_idx = i;
712 }
713 found_idx--;
714 bs->idx = (found_idx / BOOT_STATUS_STATE_COUNT) + 1;
715 bs->state = (found_idx % BOOT_STATUS_STATE_COUNT) + 1;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000716 }
717
718 return 0;
719}
720
721/**
722 * Reads the boot status from the flash. The boot status contains
723 * the current state of an interrupted image copy operation. If the boot
724 * status is not present, or it indicates that previous copy finished,
725 * there is no operation in progress.
726 */
727static int
728boot_read_status(struct boot_status *bs)
729{
730 const struct flash_area *fap;
David Vincze401c7422019-06-21 20:44:05 +0200731 uint32_t off;
David Vincze91b71ef2019-06-24 13:06:47 +0200732 uint8_t swap_info;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000733 int status_loc;
734 int area_id;
735 int rc;
736
David Vincze39e78552018-10-10 17:10:01 +0200737 memset(bs, 0, sizeof *bs);
738 bs->idx = BOOT_STATUS_IDX_0;
739 bs->state = BOOT_STATUS_STATE_0;
David Vincze401c7422019-06-21 20:44:05 +0200740 bs->swap_type = BOOT_SWAP_TYPE_NONE;
David Vincze39e78552018-10-10 17:10:01 +0200741
742#ifdef MCUBOOT_OVERWRITE_ONLY
743 /* Overwrite-only doesn't make use of the swap status area. */
744 return 0;
745#endif
Tamas Banf70ef8c2017-12-19 15:35:09 +0000746
747 status_loc = boot_status_source();
748 switch (status_loc) {
749 case BOOT_STATUS_SOURCE_NONE:
750 return 0;
751
752 case BOOT_STATUS_SOURCE_SCRATCH:
753 area_id = FLASH_AREA_IMAGE_SCRATCH;
754 break;
755
David Vincze8bdfc2d2019-03-18 15:49:23 +0100756 case BOOT_STATUS_SOURCE_PRIMARY_SLOT:
757 area_id = FLASH_AREA_IMAGE_PRIMARY;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000758 break;
759
760 default:
761 assert(0);
762 return BOOT_EBADARGS;
763 }
764
765 rc = flash_area_open(area_id, &fap);
766 if (rc != 0) {
767 return BOOT_EFLASH;
768 }
769
770 rc = boot_read_status_bytes(fap, bs);
David Vincze401c7422019-06-21 20:44:05 +0200771 if (rc == 0) {
David Vincze91b71ef2019-06-24 13:06:47 +0200772 off = boot_swap_info_off(fap);
773 rc = flash_area_read_is_empty(fap, off, &swap_info, sizeof swap_info);
David Vincze401c7422019-06-21 20:44:05 +0200774 if (rc == 1) {
David Vincze91b71ef2019-06-24 13:06:47 +0200775 BOOT_SET_SWAP_INFO(swap_info, 0, BOOT_SWAP_TYPE_NONE);
David Vincze401c7422019-06-21 20:44:05 +0200776 rc = 0;
777 }
David Vincze91b71ef2019-06-24 13:06:47 +0200778
779 /* Extract the swap type info */
780 bs->swap_type = BOOT_GET_SWAP_TYPE(swap_info);
David Vincze401c7422019-06-21 20:44:05 +0200781 }
Tamas Banf70ef8c2017-12-19 15:35:09 +0000782
783 flash_area_close(fap);
David Vincze39e78552018-10-10 17:10:01 +0200784
Tamas Banf70ef8c2017-12-19 15:35:09 +0000785 return rc;
786}
787
788/**
789 * Writes the supplied boot status to the flash file system. The boot status
790 * contains the current state of an in-progress image copy operation.
791 *
792 * @param bs The boot status to write.
793 *
794 * @return 0 on success; nonzero on failure.
795 */
796int
797boot_write_status(struct boot_status *bs)
798{
Tamas Ban581034a2017-12-19 19:54:37 +0000799 const struct flash_area *fap = NULL;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000800 uint32_t off;
801 int area_id;
802 int rc;
803 uint8_t buf[BOOT_MAX_ALIGN];
Raef Coles204c5b42019-09-05 09:18:47 +0100804 uint32_t align;
David Vincze39e78552018-10-10 17:10:01 +0200805 uint8_t erased_val;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000806
807 /* NOTE: The first sector copied (that is the last sector on slot) contains
David Vincze8bdfc2d2019-03-18 15:49:23 +0100808 * the trailer. Since in the last step the primary slot is erased, the
809 * first two status writes go to the scratch which will be copied to
810 * the primary slot!
Tamas Banf70ef8c2017-12-19 15:35:09 +0000811 */
812
813 if (bs->use_scratch) {
814 /* Write to scratch. */
815 area_id = FLASH_AREA_IMAGE_SCRATCH;
816 } else {
David Vincze8bdfc2d2019-03-18 15:49:23 +0100817 /* Write to the primary slot. */
818 area_id = FLASH_AREA_IMAGE_PRIMARY;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000819 }
820
821 rc = flash_area_open(area_id, &fap);
822 if (rc != 0) {
823 rc = BOOT_EFLASH;
824 goto done;
825 }
826
827 off = boot_status_off(fap) +
828 boot_status_internal_off(bs->idx, bs->state,
829 BOOT_WRITE_SZ(&boot_data));
830
Tamas Banc3828852018-02-01 12:24:16 +0000831 align = flash_area_align(fap);
David Vincze39e78552018-10-10 17:10:01 +0200832 erased_val = flash_area_erased_val(fap);
833 memset(buf, erased_val, BOOT_MAX_ALIGN);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000834 buf[0] = bs->state;
835
836 rc = flash_area_write(fap, off, buf, align);
837 if (rc != 0) {
838 rc = BOOT_EFLASH;
839 goto done;
840 }
841
842 rc = 0;
843
844done:
845 flash_area_close(fap);
846 return rc;
847}
848
Tamas Banf70ef8c2017-12-19 15:35:09 +0000849/**
850 * Determines which swap operation to perform, if any. If it is determined
David Vincze8bdfc2d2019-03-18 15:49:23 +0100851 * that a swap operation is required, the image in the secondary slot is checked
852 * for validity. If the image in the secondary slot is invalid, it is erased,
853 * and a swap type of "none" is indicated.
Tamas Banf70ef8c2017-12-19 15:35:09 +0000854 *
855 * @return The type of swap to perform (BOOT_SWAP_TYPE...)
856 */
857static int
David Vincze401c7422019-06-21 20:44:05 +0200858boot_validated_swap_type(struct boot_status *bs)
Tamas Banf70ef8c2017-12-19 15:35:09 +0000859{
860 int swap_type;
861
862 swap_type = boot_swap_type();
863 switch (swap_type) {
864 case BOOT_SWAP_TYPE_TEST:
865 case BOOT_SWAP_TYPE_PERM:
866 case BOOT_SWAP_TYPE_REVERT:
David Vincze8bdfc2d2019-03-18 15:49:23 +0100867 /* Boot loader wants to switch to the secondary slot.
868 * Ensure image is valid.
869 */
David Vincze401c7422019-06-21 20:44:05 +0200870 if (boot_validate_slot(BOOT_SECONDARY_SLOT, bs) != 0) {
Tamas Banf70ef8c2017-12-19 15:35:09 +0000871 swap_type = BOOT_SWAP_TYPE_FAIL;
872 }
873 }
874
875 return swap_type;
876}
877
878/**
879 * Calculates the number of sectors the scratch area can contain. A "last"
880 * source sector is specified because images are copied backwards in flash
881 * (final index to index number 0).
882 *
883 * @param last_sector_idx The index of the last source sector
884 * (inclusive).
885 * @param out_first_sector_idx The index of the first source sector
886 * (inclusive) gets written here.
887 *
888 * @return The number of bytes comprised by the
889 * [first-sector, last-sector] range.
890 */
891#ifndef MCUBOOT_OVERWRITE_ONLY
892static uint32_t
893boot_copy_sz(int last_sector_idx, int *out_first_sector_idx)
894{
895 size_t scratch_sz;
896 uint32_t new_sz;
897 uint32_t sz;
898 int i;
899
900 sz = 0;
901
902 scratch_sz = boot_scratch_area_size(&boot_data);
903 for (i = last_sector_idx; i >= 0; i--) {
David Vincze8bdfc2d2019-03-18 15:49:23 +0100904 new_sz = sz + boot_img_sector_size(&boot_data, BOOT_PRIMARY_SLOT, i);
David Vincze401c7422019-06-21 20:44:05 +0200905 /*
906 * The secondary slot is not being checked here, because
907 * `boot_slots_compatible` already provides assurance that the copy size
908 * will be compatible with the primary slot and scratch.
909 */
Tamas Banf70ef8c2017-12-19 15:35:09 +0000910 if (new_sz > scratch_sz) {
911 break;
912 }
913 sz = new_sz;
914 }
915
916 /* i currently refers to a sector that doesn't fit or it is -1 because all
917 * sectors have been processed. In both cases, exclude sector i.
918 */
919 *out_first_sector_idx = i + 1;
920 return sz;
921}
922#endif /* !MCUBOOT_OVERWRITE_ONLY */
923
924/**
David Vinczef7641fa2018-09-04 18:29:46 +0200925 * Erases a region of flash.
926 *
David Vincze401c7422019-06-21 20:44:05 +0200927 * @param flash_area The flash_area containing the region to erase.
David Vinczef7641fa2018-09-04 18:29:46 +0200928 * @param off The offset within the flash area to start the
929 * erase.
930 * @param sz The number of bytes to erase.
931 *
932 * @return 0 on success; nonzero on failure.
933 */
David Vincze401c7422019-06-21 20:44:05 +0200934static inline int
935boot_erase_sector(const struct flash_area *fap, uint32_t off, uint32_t sz)
David Vinczef7641fa2018-09-04 18:29:46 +0200936{
David Vincze401c7422019-06-21 20:44:05 +0200937 return flash_area_erase(fap, off, sz);
David Vinczef7641fa2018-09-04 18:29:46 +0200938}
939
940/**
Tamas Banf70ef8c2017-12-19 15:35:09 +0000941 * Copies the contents of one flash region to another. You must erase the
942 * destination region prior to calling this function.
943 *
944 * @param flash_area_id_src The ID of the source flash area.
945 * @param flash_area_id_dst The ID of the destination flash area.
946 * @param off_src The offset within the source flash area to
947 * copy from.
948 * @param off_dst The offset within the destination flash area to
949 * copy to.
950 * @param sz The number of bytes to copy.
951 *
952 * @return 0 on success; nonzero on failure.
953 */
954static int
David Vincze401c7422019-06-21 20:44:05 +0200955boot_copy_sector(const struct flash_area *fap_src,
956 const struct flash_area *fap_dst,
Tamas Banf70ef8c2017-12-19 15:35:09 +0000957 uint32_t off_src, uint32_t off_dst, uint32_t sz)
958{
Tamas Banf70ef8c2017-12-19 15:35:09 +0000959 uint32_t bytes_copied;
960 int chunk_sz;
961 int rc;
962
963 static uint8_t buf[1024];
964
Tamas Banf70ef8c2017-12-19 15:35:09 +0000965 bytes_copied = 0;
966 while (bytes_copied < sz) {
Tamas Ban581034a2017-12-19 19:54:37 +0000967 if (sz - bytes_copied > sizeof(buf)) {
968 chunk_sz = sizeof(buf);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000969 } else {
970 chunk_sz = sz - bytes_copied;
971 }
972
973 rc = flash_area_read(fap_src, off_src + bytes_copied, buf, chunk_sz);
974 if (rc != 0) {
David Vincze401c7422019-06-21 20:44:05 +0200975 return BOOT_EFLASH;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000976 }
977
978 rc = flash_area_write(fap_dst, off_dst + bytes_copied, buf, chunk_sz);
979 if (rc != 0) {
David Vincze401c7422019-06-21 20:44:05 +0200980 return BOOT_EFLASH;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000981 }
982
983 bytes_copied += chunk_sz;
984 }
985
David Vincze401c7422019-06-21 20:44:05 +0200986 return 0;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000987}
988
989#ifndef MCUBOOT_OVERWRITE_ONLY
990static inline int
David Vincze401c7422019-06-21 20:44:05 +0200991boot_status_init(const struct flash_area *fap, const struct boot_status *bs)
Tamas Banf70ef8c2017-12-19 15:35:09 +0000992{
Tamas Banf70ef8c2017-12-19 15:35:09 +0000993 struct boot_swap_state swap_state;
994 int rc;
995
David Vincze401c7422019-06-21 20:44:05 +0200996 BOOT_LOG_DBG("initializing status; fa_id=%d", fap->fa_id);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000997
David Vincze8bdfc2d2019-03-18 15:49:23 +0100998 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SECONDARY, &swap_state);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000999 assert(rc == 0);
1000
David Vincze401c7422019-06-21 20:44:05 +02001001 if (bs->swap_type != BOOT_SWAP_TYPE_NONE) {
David Vincze91b71ef2019-06-24 13:06:47 +02001002 rc = boot_write_swap_info(fap,
1003 bs->swap_type,
David Vincze7384ee72019-07-23 17:00:42 +02001004 current_image);
David Vincze401c7422019-06-21 20:44:05 +02001005 assert(rc == 0);
1006 }
1007
Tamas Banf70ef8c2017-12-19 15:35:09 +00001008 if (swap_state.image_ok == BOOT_FLAG_SET) {
1009 rc = boot_write_image_ok(fap);
1010 assert(rc == 0);
1011 }
1012
1013 rc = boot_write_swap_size(fap, bs->swap_size);
1014 assert(rc == 0);
1015
1016 rc = boot_write_magic(fap);
1017 assert(rc == 0);
1018
Tamas Banf70ef8c2017-12-19 15:35:09 +00001019 return 0;
1020}
David Vinczef7641fa2018-09-04 18:29:46 +02001021
1022static int
David Vincze401c7422019-06-21 20:44:05 +02001023boot_erase_trailer_sectors(const struct flash_area *fap)
David Vinczef7641fa2018-09-04 18:29:46 +02001024{
1025 uint8_t slot;
David Vincze401c7422019-06-21 20:44:05 +02001026 uint32_t sector;
1027 uint32_t trailer_sz;
1028 uint32_t total_sz;
1029 uint32_t off;
1030 uint32_t sz;
David Vinczebb207982019-08-21 15:13:04 +02001031 int fa_id_primary;
1032 int fa_id_secondary;
David Vinczef7641fa2018-09-04 18:29:46 +02001033 int rc;
1034
David Vincze401c7422019-06-21 20:44:05 +02001035 BOOT_LOG_DBG("erasing trailer; fa_id=%d", fap->fa_id);
1036
David Vinczebb207982019-08-21 15:13:04 +02001037 fa_id_primary = flash_area_id_from_image_slot(BOOT_PRIMARY_SLOT);
1038 fa_id_secondary = flash_area_id_from_image_slot(BOOT_SECONDARY_SLOT);
1039
1040 if (fap->fa_id == fa_id_primary) {
David Vincze8bdfc2d2019-03-18 15:49:23 +01001041 slot = BOOT_PRIMARY_SLOT;
David Vinczebb207982019-08-21 15:13:04 +02001042 } else if (fap->fa_id == fa_id_secondary) {
David Vincze8bdfc2d2019-03-18 15:49:23 +01001043 slot = BOOT_SECONDARY_SLOT;
David Vinczebb207982019-08-21 15:13:04 +02001044 } else {
David Vinczef7641fa2018-09-04 18:29:46 +02001045 return BOOT_EFLASH;
1046 }
1047
David Vincze401c7422019-06-21 20:44:05 +02001048 /* delete starting from last sector and moving to beginning */
1049 sector = boot_img_num_sectors(&boot_data, slot) - 1;
1050 trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(&boot_data));
1051 total_sz = 0;
1052 do {
1053 sz = boot_img_sector_size(&boot_data, slot, sector);
1054 off = boot_img_sector_off(&boot_data, slot, sector);
1055 rc = boot_erase_sector(fap, off, sz);
1056 assert(rc == 0);
1057
1058 sector--;
1059 total_sz += sz;
1060 } while (total_sz < trailer_sz);
David Vinczef7641fa2018-09-04 18:29:46 +02001061
1062 return rc;
1063}
1064#endif /* !MCUBOOT_OVERWRITE_ONLY */
Tamas Banf70ef8c2017-12-19 15:35:09 +00001065
Tamas Banf70ef8c2017-12-19 15:35:09 +00001066/**
1067 * Swaps the contents of two flash regions within the two image slots.
1068 *
1069 * @param idx The index of the first sector in the range of
1070 * sectors being swapped.
1071 * @param sz The number of bytes to swap.
1072 * @param bs The current boot status. This struct gets
1073 * updated according to the outcome.
1074 *
1075 * @return 0 on success; nonzero on failure.
1076 */
1077#ifndef MCUBOOT_OVERWRITE_ONLY
1078static void
1079boot_swap_sectors(int idx, uint32_t sz, struct boot_status *bs)
1080{
David Vincze401c7422019-06-21 20:44:05 +02001081 const struct flash_area *fap_primary_slot;
1082 const struct flash_area *fap_secondary_slot;
1083 const struct flash_area *fap_scratch;
Tamas Banf70ef8c2017-12-19 15:35:09 +00001084 uint32_t copy_sz;
1085 uint32_t trailer_sz;
1086 uint32_t img_off;
1087 uint32_t scratch_trailer_off;
1088 struct boot_swap_state swap_state;
1089 size_t last_sector;
David Vincze401c7422019-06-21 20:44:05 +02001090 bool erase_scratch;
Tamas Banf70ef8c2017-12-19 15:35:09 +00001091 int rc;
1092
1093 /* Calculate offset from start of image area. */
David Vincze8bdfc2d2019-03-18 15:49:23 +01001094 img_off = boot_img_sector_off(&boot_data, BOOT_PRIMARY_SLOT, idx);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001095
1096 copy_sz = sz;
David Vincze401c7422019-06-21 20:44:05 +02001097 trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(&boot_data));
Tamas Banf70ef8c2017-12-19 15:35:09 +00001098
David Vincze401c7422019-06-21 20:44:05 +02001099 /* sz in this function is always sized on a multiple of the sector size.
1100 * The check against the start offset of the last sector
Tamas Banf70ef8c2017-12-19 15:35:09 +00001101 * is to determine if we're swapping the last sector. The last sector
1102 * needs special handling because it's where the trailer lives. If we're
1103 * copying it, we need to use scratch to write the trailer temporarily.
1104 *
1105 * NOTE: `use_scratch` is a temporary flag (never written to flash) which
1106 * controls if special handling is needed (swapping last sector).
1107 */
David Vincze8bdfc2d2019-03-18 15:49:23 +01001108 last_sector = boot_img_num_sectors(&boot_data, BOOT_PRIMARY_SLOT) - 1;
David Vincze7384ee72019-07-23 17:00:42 +02001109 if ((img_off + sz) >
1110 boot_img_sector_off(&boot_data, BOOT_PRIMARY_SLOT, last_sector)) {
Tamas Banf70ef8c2017-12-19 15:35:09 +00001111 copy_sz -= trailer_sz;
1112 }
1113
David Vincze39e78552018-10-10 17:10:01 +02001114 bs->use_scratch = (bs->idx == BOOT_STATUS_IDX_0 && copy_sz != sz);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001115
David Vincze401c7422019-06-21 20:44:05 +02001116 rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY, &fap_primary_slot);
1117 assert (rc == 0);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001118
David Vincze401c7422019-06-21 20:44:05 +02001119 rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY, &fap_secondary_slot);
1120 assert (rc == 0);
1121
1122 rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH, &fap_scratch);
1123 assert (rc == 0);
1124
1125 if (bs->state == BOOT_STATUS_STATE_0) {
1126 BOOT_LOG_DBG("erasing scratch area");
1127 rc = boot_erase_sector(fap_scratch, 0, fap_scratch->fa_size);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001128 assert(rc == 0);
1129
David Vincze39e78552018-10-10 17:10:01 +02001130 if (bs->idx == BOOT_STATUS_IDX_0) {
David Vincze401c7422019-06-21 20:44:05 +02001131 /* Write a trailer to the scratch area, even if we don't need the
1132 * scratch area for status. We need a temporary place to store the
1133 * `swap-type` while we erase the primary trailer.
1134 */
1135 rc = boot_status_init(fap_scratch, bs);
1136 assert(rc == 0);
1137
1138 if (!bs->use_scratch) {
1139 /* Prepare the primary status area... here it is known that the
1140 * last sector is not being used by the image data so it's safe
1141 * to erase.
Tamas Banf70ef8c2017-12-19 15:35:09 +00001142 */
David Vincze401c7422019-06-21 20:44:05 +02001143 rc = boot_erase_trailer_sectors(fap_primary_slot);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001144 assert(rc == 0);
1145
David Vincze401c7422019-06-21 20:44:05 +02001146 rc = boot_status_init(fap_primary_slot, bs);
1147 assert(rc == 0);
1148
1149 /* Erase the temporary trailer from the scratch area. */
1150 rc = boot_erase_sector(fap_scratch, 0, fap_scratch->fa_size);
1151 assert(rc == 0);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001152 }
1153 }
1154
David Vincze401c7422019-06-21 20:44:05 +02001155 rc = boot_copy_sector(fap_secondary_slot, fap_scratch,
1156 img_off, 0, copy_sz);
1157 assert(rc == 0);
1158
David Vincze39e78552018-10-10 17:10:01 +02001159 bs->state = BOOT_STATUS_STATE_1;
Tamas Banf70ef8c2017-12-19 15:35:09 +00001160 rc = boot_write_status(bs);
David Vincze39e78552018-10-10 17:10:01 +02001161 BOOT_STATUS_ASSERT(rc == 0);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001162 }
1163
David Vincze39e78552018-10-10 17:10:01 +02001164 if (bs->state == BOOT_STATUS_STATE_1) {
David Vincze401c7422019-06-21 20:44:05 +02001165 rc = boot_erase_sector(fap_secondary_slot, img_off, sz);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001166 assert(rc == 0);
1167
David Vincze401c7422019-06-21 20:44:05 +02001168 rc = boot_copy_sector(fap_primary_slot, fap_secondary_slot,
Tamas Banf70ef8c2017-12-19 15:35:09 +00001169 img_off, img_off, copy_sz);
1170 assert(rc == 0);
1171
David Vincze39e78552018-10-10 17:10:01 +02001172 if (bs->idx == BOOT_STATUS_IDX_0 && !bs->use_scratch) {
Tamas Banf70ef8c2017-12-19 15:35:09 +00001173 /* If not all sectors of the slot are being swapped,
David Vincze8bdfc2d2019-03-18 15:49:23 +01001174 * guarantee here that only the primary slot will have the state.
Tamas Banf70ef8c2017-12-19 15:35:09 +00001175 */
David Vincze401c7422019-06-21 20:44:05 +02001176 rc = boot_erase_trailer_sectors(fap_secondary_slot);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001177 assert(rc == 0);
1178 }
1179
David Vincze39e78552018-10-10 17:10:01 +02001180 bs->state = BOOT_STATUS_STATE_2;
Tamas Banf70ef8c2017-12-19 15:35:09 +00001181 rc = boot_write_status(bs);
David Vincze39e78552018-10-10 17:10:01 +02001182 BOOT_STATUS_ASSERT(rc == 0);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001183 }
1184
David Vincze39e78552018-10-10 17:10:01 +02001185 if (bs->state == BOOT_STATUS_STATE_2) {
David Vincze401c7422019-06-21 20:44:05 +02001186 rc = boot_erase_sector(fap_primary_slot, img_off, sz);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001187 assert(rc == 0);
1188
David Vincze401c7422019-06-21 20:44:05 +02001189 /* NOTE: If this is the final sector, we exclude the image trailer from
1190 * this copy (copy_sz was truncated earlier).
1191 */
1192 rc = boot_copy_sector(fap_scratch, fap_primary_slot,
Tamas Banf70ef8c2017-12-19 15:35:09 +00001193 0, img_off, copy_sz);
1194 assert(rc == 0);
1195
1196 if (bs->use_scratch) {
David Vincze401c7422019-06-21 20:44:05 +02001197 scratch_trailer_off = boot_status_off(fap_scratch);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001198
1199 /* copy current status that is being maintained in scratch */
David Vincze401c7422019-06-21 20:44:05 +02001200 rc = boot_copy_sector(fap_scratch, fap_primary_slot,
1201 scratch_trailer_off, img_off + copy_sz,
Tamas Banf70ef8c2017-12-19 15:35:09 +00001202 BOOT_STATUS_STATE_COUNT * BOOT_WRITE_SZ(&boot_data));
David Vincze39e78552018-10-10 17:10:01 +02001203 BOOT_STATUS_ASSERT(rc == 0);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001204
1205 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SCRATCH,
1206 &swap_state);
1207 assert(rc == 0);
1208
1209 if (swap_state.image_ok == BOOT_FLAG_SET) {
David Vincze401c7422019-06-21 20:44:05 +02001210 rc = boot_write_image_ok(fap_primary_slot);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001211 assert(rc == 0);
1212 }
1213
David Vincze401c7422019-06-21 20:44:05 +02001214 if (swap_state.swap_type != BOOT_SWAP_TYPE_NONE) {
David Vincze91b71ef2019-06-24 13:06:47 +02001215 rc = boot_write_swap_info(fap_primary_slot,
1216 swap_state.swap_type,
David Vincze7384ee72019-07-23 17:00:42 +02001217 current_image);
David Vincze401c7422019-06-21 20:44:05 +02001218 assert(rc == 0);
1219 }
1220
1221 rc = boot_write_swap_size(fap_primary_slot, bs->swap_size);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001222 assert(rc == 0);
1223
David Vincze401c7422019-06-21 20:44:05 +02001224 rc = boot_write_magic(fap_primary_slot);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001225 assert(rc == 0);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001226 }
1227
David Vincze401c7422019-06-21 20:44:05 +02001228 /* If we wrote a trailer to the scratch area, erase it after we persist
1229 * a trailer to the primary slot. We do this to prevent mcuboot from
1230 * reading a stale status from the scratch area in case of immediate
1231 * reset.
1232 */
1233 erase_scratch = bs->use_scratch;
1234 bs->use_scratch = 0;
1235
Tamas Banf70ef8c2017-12-19 15:35:09 +00001236 bs->idx++;
David Vincze39e78552018-10-10 17:10:01 +02001237 bs->state = BOOT_STATUS_STATE_0;
Tamas Banf70ef8c2017-12-19 15:35:09 +00001238 rc = boot_write_status(bs);
David Vincze39e78552018-10-10 17:10:01 +02001239 BOOT_STATUS_ASSERT(rc == 0);
David Vincze401c7422019-06-21 20:44:05 +02001240
1241 if (erase_scratch) {
1242 rc = boot_erase_sector(fap_scratch, 0, sz);
1243 assert(rc == 0);
1244 }
Tamas Banf70ef8c2017-12-19 15:35:09 +00001245 }
David Vincze401c7422019-06-21 20:44:05 +02001246
1247 flash_area_close(fap_primary_slot);
1248 flash_area_close(fap_secondary_slot);
1249 flash_area_close(fap_scratch);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001250}
1251#endif /* !MCUBOOT_OVERWRITE_ONLY */
1252
1253/**
David Vincze401c7422019-06-21 20:44:05 +02001254 * Overwrite primary slot with the image contained in the secondary slot.
1255 * If a prior copy operation was interrupted by a system reset, this function
1256 * redos the copy.
Tamas Banf70ef8c2017-12-19 15:35:09 +00001257 *
1258 * @param bs The current boot status. This function reads
1259 * this struct to determine if it is resuming
1260 * an interrupted swap operation. This
1261 * function writes the updated status to this
1262 * function on return.
1263 *
1264 * @return 0 on success; nonzero on failure.
1265 */
1266#ifdef MCUBOOT_OVERWRITE_ONLY
1267static int
1268boot_copy_image(struct boot_status *bs)
1269{
1270 size_t sect_count;
1271 size_t sect;
1272 int rc;
1273 size_t size = 0;
1274 size_t this_size;
David Vincze39e78552018-10-10 17:10:01 +02001275 size_t last_sector;
David Vincze401c7422019-06-21 20:44:05 +02001276 const struct flash_area *fap_primary_slot;
1277 const struct flash_area *fap_secondary_slot;
David Vincze39e78552018-10-10 17:10:01 +02001278
1279 (void)bs;
Tamas Banf70ef8c2017-12-19 15:35:09 +00001280
David Vincze8bdfc2d2019-03-18 15:49:23 +01001281 BOOT_LOG_INF("Image upgrade secondary slot -> primary slot");
1282 BOOT_LOG_INF("Erasing the primary slot");
Tamas Banf70ef8c2017-12-19 15:35:09 +00001283
David Vincze401c7422019-06-21 20:44:05 +02001284 rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY, &fap_primary_slot);
1285 assert (rc == 0);
1286
1287 rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY, &fap_secondary_slot);
1288 assert (rc == 0);
1289
David Vincze8bdfc2d2019-03-18 15:49:23 +01001290 sect_count = boot_img_num_sectors(&boot_data, BOOT_PRIMARY_SLOT);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001291 for (sect = 0; sect < sect_count; sect++) {
David Vincze8bdfc2d2019-03-18 15:49:23 +01001292 this_size = boot_img_sector_size(&boot_data, BOOT_PRIMARY_SLOT, sect);
David Vincze401c7422019-06-21 20:44:05 +02001293 rc = boot_erase_sector(fap_primary_slot, size, this_size);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001294 assert(rc == 0);
1295
1296 size += this_size;
1297 }
1298
David Vincze8bdfc2d2019-03-18 15:49:23 +01001299 BOOT_LOG_INF("Copying the secondary slot to the primary slot: 0x%zx bytes",
1300 size);
David Vincze401c7422019-06-21 20:44:05 +02001301 rc = boot_copy_sector(fap_secondary_slot, fap_primary_slot, 0, 0, size);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001302
David Vincze060968d2019-05-23 01:13:14 +02001303 /* Update the stored security counter with the new image's security counter
David Vincze8bdfc2d2019-03-18 15:49:23 +01001304 * value. Both slots hold the new image at this point, but the secondary
1305 * slot's image header must be passed because the read image headers in the
1306 * boot_data structure have not been updated yet.
David Vincze060968d2019-05-23 01:13:14 +02001307 */
David Vincze8bdfc2d2019-03-18 15:49:23 +01001308 rc = boot_update_security_counter(BOOT_PRIMARY_SLOT,
1309 boot_img_hdr(&boot_data, BOOT_SECONDARY_SLOT));
David Vincze060968d2019-05-23 01:13:14 +02001310 if (rc != 0) {
1311 BOOT_LOG_ERR("Security counter update failed after image upgrade.");
1312 return rc;
1313 }
1314
David Vincze39e78552018-10-10 17:10:01 +02001315 /*
1316 * Erases header and trailer. The trailer is erased because when a new
1317 * image is written without a trailer as is the case when using newt, the
1318 * trailer that was left might trigger a new upgrade.
1319 */
David Vincze401c7422019-06-21 20:44:05 +02001320 BOOT_LOG_DBG("erasing secondary header");
1321 rc = boot_erase_sector(fap_secondary_slot,
David Vincze8bdfc2d2019-03-18 15:49:23 +01001322 boot_img_sector_off(&boot_data,
1323 BOOT_SECONDARY_SLOT, 0),
1324 boot_img_sector_size(&boot_data,
1325 BOOT_SECONDARY_SLOT, 0));
Tamas Banf70ef8c2017-12-19 15:35:09 +00001326 assert(rc == 0);
David Vincze8bdfc2d2019-03-18 15:49:23 +01001327 last_sector = boot_img_num_sectors(&boot_data, BOOT_SECONDARY_SLOT) - 1;
David Vincze401c7422019-06-21 20:44:05 +02001328 BOOT_LOG_DBG("erasing secondary trailer");
1329 rc = boot_erase_sector(fap_secondary_slot,
David Vincze8bdfc2d2019-03-18 15:49:23 +01001330 boot_img_sector_off(&boot_data, BOOT_SECONDARY_SLOT,
1331 last_sector),
1332 boot_img_sector_size(&boot_data, BOOT_SECONDARY_SLOT,
1333 last_sector));
David Vincze39e78552018-10-10 17:10:01 +02001334 assert(rc == 0);
1335
David Vincze401c7422019-06-21 20:44:05 +02001336 flash_area_close(fap_primary_slot);
1337 flash_area_close(fap_secondary_slot);
1338
David Vincze8bdfc2d2019-03-18 15:49:23 +01001339 /* TODO: Perhaps verify the primary slot's signature again? */
Tamas Banf70ef8c2017-12-19 15:35:09 +00001340
1341 return 0;
1342}
1343#else
David Vincze401c7422019-06-21 20:44:05 +02001344/**
1345 * Swaps the two images in flash. If a prior copy operation was interrupted
1346 * by a system reset, this function completes that operation.
1347 *
1348 * @param bs The current boot status. This function reads
1349 * this struct to determine if it is resuming
1350 * an interrupted swap operation. This
1351 * function writes the updated status to this
1352 * function on return.
1353 *
1354 * @return 0 on success; nonzero on failure.
1355 */
Tamas Banf70ef8c2017-12-19 15:35:09 +00001356static int
David Vincze401c7422019-06-21 20:44:05 +02001357boot_swap_image(struct boot_status *bs)
Tamas Banf70ef8c2017-12-19 15:35:09 +00001358{
1359 uint32_t sz;
1360 int first_sector_idx;
1361 int last_sector_idx;
David Vincze401c7422019-06-21 20:44:05 +02001362 int last_idx_secondary_slot;
David Vincze39e78552018-10-10 17:10:01 +02001363 uint32_t swap_idx;
Tamas Banf70ef8c2017-12-19 15:35:09 +00001364 struct image_header *hdr;
1365 uint32_t size;
1366 uint32_t copy_size;
David Vincze401c7422019-06-21 20:44:05 +02001367 uint32_t primary_slot_size;
1368 uint32_t secondary_slot_size;
Tamas Banf70ef8c2017-12-19 15:35:09 +00001369 int rc;
1370
1371 /* FIXME: just do this if asked by user? */
1372
1373 size = copy_size = 0;
1374
David Vincze39e78552018-10-10 17:10:01 +02001375 if (bs->idx == BOOT_STATUS_IDX_0 && bs->state == BOOT_STATUS_STATE_0) {
Tamas Banf70ef8c2017-12-19 15:35:09 +00001376 /*
1377 * No swap ever happened, so need to find the largest image which
1378 * will be used to determine the amount of sectors to swap.
1379 */
David Vincze8bdfc2d2019-03-18 15:49:23 +01001380 hdr = boot_img_hdr(&boot_data, BOOT_PRIMARY_SLOT);
Tamas Ban056ed0b2019-09-16 12:48:32 +01001381 rc = boot_read_image_size(BOOT_PRIMARY_SLOT, hdr, &copy_size);
1382 assert(rc == 0);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001383
David Vincze8bdfc2d2019-03-18 15:49:23 +01001384 hdr = boot_img_hdr(&boot_data, BOOT_SECONDARY_SLOT);
Tamas Ban056ed0b2019-09-16 12:48:32 +01001385 rc = boot_read_image_size(BOOT_SECONDARY_SLOT, hdr, &size);
1386 assert(rc == 0);
1387
Tamas Banf70ef8c2017-12-19 15:35:09 +00001388
1389 if (size > copy_size) {
1390 copy_size = size;
1391 }
1392
1393 bs->swap_size = copy_size;
1394 } else {
1395 /*
1396 * If a swap was under way, the swap_size should already be present
1397 * in the trailer...
1398 */
1399 rc = boot_read_swap_size(&bs->swap_size);
1400 assert(rc == 0);
1401
1402 copy_size = bs->swap_size;
1403 }
1404
David Vincze401c7422019-06-21 20:44:05 +02001405 primary_slot_size = 0;
1406 secondary_slot_size = 0;
Tamas Banf70ef8c2017-12-19 15:35:09 +00001407 last_sector_idx = 0;
David Vincze401c7422019-06-21 20:44:05 +02001408 last_idx_secondary_slot = 0;
1409
1410 /*
1411 * Knowing the size of the largest image between both slots, here we
1412 * find what is the last sector in the primary slot that needs swapping.
1413 * Since we already know that both slots are compatible, the secondary
1414 * slot's last sector is not really required after this check is finished.
1415 */
Tamas Banf70ef8c2017-12-19 15:35:09 +00001416 while (1) {
David Vincze401c7422019-06-21 20:44:05 +02001417 if ((primary_slot_size < copy_size) ||
1418 (primary_slot_size < secondary_slot_size)) {
1419 primary_slot_size += boot_img_sector_size(&boot_data,
1420 BOOT_PRIMARY_SLOT,
1421 last_sector_idx);
1422 }
1423 if ((secondary_slot_size < copy_size) ||
1424 (secondary_slot_size < primary_slot_size)) {
1425 secondary_slot_size += boot_img_sector_size(&boot_data,
1426 BOOT_SECONDARY_SLOT,
1427 last_idx_secondary_slot);
1428 }
1429 if (primary_slot_size >= copy_size &&
1430 secondary_slot_size >= copy_size &&
1431 primary_slot_size == secondary_slot_size) {
Tamas Banf70ef8c2017-12-19 15:35:09 +00001432 break;
1433 }
1434 last_sector_idx++;
David Vincze401c7422019-06-21 20:44:05 +02001435 last_idx_secondary_slot++;
Tamas Banf70ef8c2017-12-19 15:35:09 +00001436 }
1437
1438 swap_idx = 0;
1439 while (last_sector_idx >= 0) {
1440 sz = boot_copy_sz(last_sector_idx, &first_sector_idx);
David Vincze39e78552018-10-10 17:10:01 +02001441 if (swap_idx >= (bs->idx - BOOT_STATUS_IDX_0)) {
Tamas Banf70ef8c2017-12-19 15:35:09 +00001442 boot_swap_sectors(first_sector_idx, sz, bs);
1443 }
1444
1445 last_sector_idx = first_sector_idx - 1;
1446 swap_idx++;
1447 }
1448
David Vincze8bdfc2d2019-03-18 15:49:23 +01001449#ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT
David Vincze39e78552018-10-10 17:10:01 +02001450 if (boot_status_fails > 0) {
David Vincze401c7422019-06-21 20:44:05 +02001451 BOOT_LOG_WRN("%d status write fails performing the swap",
1452 boot_status_fails);
David Vincze39e78552018-10-10 17:10:01 +02001453 }
1454#endif
1455
Tamas Banf70ef8c2017-12-19 15:35:09 +00001456 return 0;
1457}
1458#endif
1459
1460/**
David Vincze8bdfc2d2019-03-18 15:49:23 +01001461 * Marks the image in the primary slot as fully copied.
Tamas Banf70ef8c2017-12-19 15:35:09 +00001462 */
1463#ifndef MCUBOOT_OVERWRITE_ONLY
1464static int
1465boot_set_copy_done(void)
1466{
1467 const struct flash_area *fap;
1468 int rc;
1469
David Vincze8bdfc2d2019-03-18 15:49:23 +01001470 rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY, &fap);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001471 if (rc != 0) {
1472 return BOOT_EFLASH;
1473 }
1474
1475 rc = boot_write_copy_done(fap);
1476 flash_area_close(fap);
1477 return rc;
1478}
1479#endif /* !MCUBOOT_OVERWRITE_ONLY */
1480
1481/**
David Vincze8bdfc2d2019-03-18 15:49:23 +01001482 * Marks a reverted image in the primary slot as confirmed. This is necessary to
1483 * ensure the status bytes from the image revert operation don't get processed
1484 * on a subsequent boot.
Tamas Banf70ef8c2017-12-19 15:35:09 +00001485 *
1486 * NOTE: image_ok is tested before writing because if there's a valid permanent
David Vincze8bdfc2d2019-03-18 15:49:23 +01001487 * image installed on the primary slot and the new image to be upgrade to has a
1488 * bad sig, image_ok would be overwritten.
Tamas Banf70ef8c2017-12-19 15:35:09 +00001489 */
1490#ifndef MCUBOOT_OVERWRITE_ONLY
1491static int
1492boot_set_image_ok(void)
1493{
1494 const struct flash_area *fap;
1495 struct boot_swap_state state;
1496 int rc;
1497
David Vincze8bdfc2d2019-03-18 15:49:23 +01001498 rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY, &fap);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001499 if (rc != 0) {
1500 return BOOT_EFLASH;
1501 }
1502
1503 rc = boot_read_swap_state(fap, &state);
1504 if (rc != 0) {
1505 rc = BOOT_EFLASH;
1506 goto out;
1507 }
1508
1509 if (state.image_ok == BOOT_FLAG_UNSET) {
1510 rc = boot_write_image_ok(fap);
1511 }
1512
1513out:
1514 flash_area_close(fap);
1515 return rc;
1516}
1517#endif /* !MCUBOOT_OVERWRITE_ONLY */
1518
David Vinczebb6e3b62019-07-31 14:24:05 +02001519#if (BOOT_IMAGE_NUMBER > 1)
1520/**
1521 * Check the image dependency whether it is satisfied and modify
1522 * the swap type if necessary.
1523 *
1524 * @param dep Image dependency which has to be verified.
1525 *
1526 * @return 0 on success; nonzero on failure.
1527 */
1528static int
1529boot_verify_single_dependency(struct image_dependency *dep)
1530{
1531 struct image_version *dep_version;
1532 size_t dep_slot;
1533 int rc;
1534
1535 /* Determine the source of the image which is the subject of
1536 * the dependency and get it's version. */
1537 dep_slot = (boot_data.swap_type[dep->image_id] != BOOT_SWAP_TYPE_NONE) ?
1538 BOOT_SECONDARY_SLOT : BOOT_PRIMARY_SLOT;
1539 dep_version = &boot_data.imgs[dep->image_id][dep_slot].hdr.ih_ver;
1540
1541 rc = boot_is_version_sufficient(&dep->image_min_version, dep_version);
1542 if (rc != 0) {
1543 /* Dependency not satisfied.
1544 * Modify the swap type to decrease the version number of the image
1545 * (which will be located in the primary slot after the boot process),
1546 * consequently the number of unsatisfied dependencies will be
1547 * decreased or remain the same.
1548 */
1549 switch (BOOT_SWAP_TYPE(&boot_data)) {
1550 case BOOT_SWAP_TYPE_TEST:
1551 case BOOT_SWAP_TYPE_PERM:
1552 BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_NONE;
1553 break;
1554 case BOOT_SWAP_TYPE_NONE:
1555 BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_REVERT;
1556 break;
1557 default:
1558 break;
1559 }
1560 }
1561
1562 return rc;
1563}
1564
1565/**
1566 * Read all dependency TLVs of an image from the flash and verify
1567 * one after another to see if they are all satisfied.
1568 *
1569 * @param slot Image slot number.
1570 *
1571 * @return 0 on success; nonzero on failure.
1572 */
1573static int
1574boot_verify_all_dependency(uint32_t slot)
1575{
1576 const struct flash_area *fap;
1577 struct image_header *hdr;
1578 struct image_tlv_info info;
1579 struct image_tlv tlv;
1580 struct image_dependency dep;
1581 uint32_t off;
1582 uint32_t end;
1583 bool dep_tlvs_found = false;
1584 int rc;
1585
1586 rc = flash_area_open(flash_area_id_from_image_slot(slot), &fap);
1587 if (rc != 0) {
1588 rc = BOOT_EFLASH;
1589 goto done;
1590 }
1591
1592 hdr = boot_img_hdr(&boot_data, slot);
1593 /* The TLVs come after the image. */
1594 off = hdr->ih_hdr_size + hdr->ih_img_size;
1595
1596 /* The TLV area always starts with an image_tlv_info structure. */
1597 rc = flash_area_read(fap, off, &info, sizeof(info));
1598 if (rc != 0) {
1599 rc = BOOT_EFLASH;
1600 goto done;
1601 }
1602
1603 if (info.it_magic != IMAGE_TLV_INFO_MAGIC) {
1604 rc = BOOT_EBADIMAGE;
1605 goto done;
1606 }
Tamas Ban056ed0b2019-09-16 12:48:32 +01001607 if (boot_add_uint32_overflow_check(off, (info.it_tlv_tot + sizeof(info)))) {
1608 return -1;
1609 }
David Vinczebb6e3b62019-07-31 14:24:05 +02001610 end = off + info.it_tlv_tot;
1611 off += sizeof(info);
1612
1613 /* Traverse through all of the TLVs to find the dependency TLVs. */
Tamas Ban056ed0b2019-09-16 12:48:32 +01001614 while(off < end) {
David Vinczebb6e3b62019-07-31 14:24:05 +02001615 rc = flash_area_read(fap, off, &tlv, sizeof(tlv));
1616 if (rc != 0) {
1617 rc = BOOT_EFLASH;
1618 goto done;
1619 }
1620
1621 if (tlv.it_type == IMAGE_TLV_DEPENDENCY) {
1622 if (!dep_tlvs_found) {
1623 dep_tlvs_found = true;
1624 }
1625
1626 if (tlv.it_len != sizeof(dep)) {
1627 rc = BOOT_EBADIMAGE;
1628 goto done;
1629 }
1630
1631 rc = flash_area_read(fap, off + sizeof(tlv), &dep, tlv.it_len);
1632 if (rc != 0) {
1633 rc = BOOT_EFLASH;
1634 goto done;
1635 }
1636
1637 /* Verify dependency and modify the swap type if not satisfied. */
1638 rc = boot_verify_single_dependency(&dep);
1639 if (rc != 0) {
1640 /* Dependency not satisfied. */
1641 goto done;
1642 }
1643
1644 /* Dependency satisfied, no action needed.
1645 * Continue with the next TLV entry.
1646 */
1647 } else if (dep_tlvs_found) {
1648 /* The dependency TLVs are contiguous in the TLV area. If a
1649 * dependency had already been found and the last read TLV
1650 * has a different type then there are no more dependency TLVs.
1651 * The search can be finished.
1652 */
1653 break;
1654 }
Tamas Ban056ed0b2019-09-16 12:48:32 +01001655 /* Avoid integer overflow. */
1656 if (boot_add_uint32_overflow_check(off, (sizeof(tlv) + tlv.it_len))) {
1657 /* Potential overflow. */
1658 return BOOT_EBADIMAGE;
1659 } else {
1660 off += sizeof(tlv) + tlv.it_len;
1661 }
David Vinczebb6e3b62019-07-31 14:24:05 +02001662 }
1663
1664done:
1665 flash_area_close(fap);
1666 return rc;
1667}
1668
1669/**
1670 * Verify whether the image dependencies in the TLV area are
1671 * all satisfied and modify the swap type if necessary.
1672 *
1673 * @return 0 if all dependencies are satisfied,
1674 * nonzero otherwise.
1675 */
1676static int
1677boot_verify_single_image_dependency(void)
1678{
1679 size_t slot;
1680
1681 /* Determine the source of the dependency TLVs. Those dependencies have to
1682 * be checked which belong to the image that will be located in the primary
1683 * slot after the firmware update process.
1684 */
1685 if (BOOT_SWAP_TYPE(&boot_data) != BOOT_SWAP_TYPE_NONE &&
1686 BOOT_SWAP_TYPE(&boot_data) != BOOT_SWAP_TYPE_FAIL) {
1687 slot = BOOT_SECONDARY_SLOT;
1688 } else {
1689 slot = BOOT_PRIMARY_SLOT;
1690 }
1691
1692 return boot_verify_all_dependency(slot);
1693}
1694
1695/**
1696 * Iterate over all the images and verify whether the image dependencies in the
1697 * TLV area are all satisfied and update the related swap type if necessary.
1698 */
1699static void
1700boot_verify_all_image_dependency(void)
1701{
1702 current_image = 0;
1703 int rc;
1704
1705 while (current_image < BOOT_IMAGE_NUMBER) {
1706 rc = boot_verify_single_image_dependency();
1707 if (rc == 0) {
1708 /* All dependencies've been satisfied, continue with next image. */
1709 current_image++;
1710 } else if (rc == BOOT_EBADVERSION) {
1711 /* Dependency check needs to be restarted. */
1712 current_image = 0;
1713 } else {
1714 /* Other error happened, images are inconsistent */
1715 return;
1716 }
1717 }
1718}
1719#endif /* (BOOT_IMAGE_NUMBER > 1) */
1720
Tamas Banf70ef8c2017-12-19 15:35:09 +00001721/**
David Vincze7384ee72019-07-23 17:00:42 +02001722 * Performs a clean (not aborted) image update.
Tamas Banf70ef8c2017-12-19 15:35:09 +00001723 *
David Vincze7384ee72019-07-23 17:00:42 +02001724 * @param bs The current boot status.
Tamas Banf70ef8c2017-12-19 15:35:09 +00001725 *
1726 * @return 0 on success; nonzero on failure.
1727 */
1728static int
David Vincze7384ee72019-07-23 17:00:42 +02001729boot_perform_update(struct boot_status *bs)
Tamas Banf70ef8c2017-12-19 15:35:09 +00001730{
Tamas Banf70ef8c2017-12-19 15:35:09 +00001731 int rc;
1732
David Vincze7384ee72019-07-23 17:00:42 +02001733 /* At this point there are no aborted swaps. */
1734#if defined(MCUBOOT_OVERWRITE_ONLY)
1735 rc = boot_copy_image(bs);
1736#else
1737 rc = boot_swap_image(bs);
1738#endif
Tamas Banf70ef8c2017-12-19 15:35:09 +00001739 assert(rc == 0);
David Vincze7384ee72019-07-23 17:00:42 +02001740
1741#ifndef MCUBOOT_OVERWRITE_ONLY
1742 /* The following state needs image_ok be explicitly set after the
1743 * swap was finished to avoid a new revert.
1744 */
1745 if (BOOT_SWAP_TYPE(&boot_data) == BOOT_SWAP_TYPE_REVERT ||
1746 BOOT_SWAP_TYPE(&boot_data) == BOOT_SWAP_TYPE_PERM) {
1747 rc = boot_set_image_ok();
1748 if (rc != 0) {
1749 BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_PANIC;
1750 }
Tamas Banf70ef8c2017-12-19 15:35:09 +00001751 }
1752
David Vincze7384ee72019-07-23 17:00:42 +02001753 if (BOOT_SWAP_TYPE(&boot_data) == BOOT_SWAP_TYPE_PERM) {
1754 /* Update the stored security counter with the new image's security
1755 * counter value. The primary slot holds the new image at this
1756 * point, but the secondary slot's image header must be passed
1757 * because the read image headers in the boot_data structure have
1758 * not been updated yet.
1759 *
1760 * In case of a permanent image swap mcuboot will never attempt to
1761 * revert the images on the next reboot. Therefore, the security
1762 * counter must be increased right after the image upgrade.
David Vincze401c7422019-06-21 20:44:05 +02001763 */
David Vincze7384ee72019-07-23 17:00:42 +02001764 rc = boot_update_security_counter(BOOT_PRIMARY_SLOT,
1765 boot_img_hdr(&boot_data, BOOT_SECONDARY_SLOT));
1766 if (rc != 0) {
1767 BOOT_LOG_ERR("Security counter update failed after "
1768 "image upgrade.");
1769 BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_PANIC;
Tamas Banf70ef8c2017-12-19 15:35:09 +00001770 }
1771 }
1772
David Vincze7384ee72019-07-23 17:00:42 +02001773 if (BOOT_SWAP_TYPE(&boot_data) == BOOT_SWAP_TYPE_TEST ||
1774 BOOT_SWAP_TYPE(&boot_data) == BOOT_SWAP_TYPE_PERM ||
1775 BOOT_SWAP_TYPE(&boot_data) == BOOT_SWAP_TYPE_REVERT) {
1776 rc = boot_set_copy_done();
1777 if (rc != 0) {
1778 BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_PANIC;
1779 }
1780 }
1781#endif /* !MCUBOOT_OVERWRITE_ONLY */
1782
1783 return rc;
1784}
1785
1786/**
1787 * Completes a previously aborted image swap.
1788 *
1789 * @param bs The current boot status.
1790 *
1791 * @return 0 on success; nonzero on failure.
1792 */
1793#if !defined(MCUBOOT_OVERWRITE_ONLY)
1794static int
1795boot_complete_partial_swap(struct boot_status *bs)
1796{
1797 int rc;
1798
1799 /* Determine the type of swap operation being resumed from the
1800 * `swap-type` trailer field.
1801 */
1802 rc = boot_swap_image(bs);
1803 assert(rc == 0);
1804
1805 BOOT_SWAP_TYPE(&boot_data) = bs->swap_type;
1806
1807 /* The following states need image_ok be explicitly set after the
1808 * swap was finished to avoid a new revert.
1809 */
1810 if (bs->swap_type == BOOT_SWAP_TYPE_REVERT ||
1811 bs->swap_type == BOOT_SWAP_TYPE_PERM) {
1812 rc = boot_set_image_ok();
1813 if (rc != 0) {
1814 BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_PANIC;
1815 }
1816 }
1817
1818 if (bs->swap_type == BOOT_SWAP_TYPE_TEST ||
1819 bs->swap_type == BOOT_SWAP_TYPE_PERM ||
1820 bs->swap_type == BOOT_SWAP_TYPE_REVERT) {
1821 rc = boot_set_copy_done();
1822 if (rc != 0) {
1823 BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_PANIC;
1824 }
1825 }
1826
1827 if (BOOT_SWAP_TYPE(&boot_data) == BOOT_SWAP_TYPE_PANIC) {
1828 BOOT_LOG_ERR("panic!");
1829 assert(0);
1830
1831 /* Loop forever... */
1832 while (1) {}
1833 }
1834
1835 return rc;
1836}
1837#endif /* !MCUBOOT_OVERWRITE_ONLY */
1838
1839#if (BOOT_IMAGE_NUMBER > 1)
1840/**
1841 * Review the validity of previously determined swap types of other images.
1842 *
1843 * @param aborted_swap The current image upgrade is a
1844 * partial/aborted swap.
1845 */
1846static void
1847boot_review_image_swap_types(bool aborted_swap)
1848{
1849 /* In that case if we rebooted in the middle of an image upgrade process, we
1850 * must review the validity of swap types, that were previously determined
1851 * for other images. The image_ok flag had not been set before the reboot
1852 * for any of the updated images (only the copy_done flag) and thus falsely
1853 * the REVERT swap type has been determined for the previous images that had
1854 * been updated before the reboot.
1855 *
1856 * There are two separate scenarios that we have to deal with:
1857 *
1858 * 1. The reboot has happened during swapping an image:
1859 * The current image upgrade has been determined as a
1860 * partial/aborted swap.
1861 * 2. The reboot has happened between two separate image upgrades:
1862 * In this scenario we must check the swap type of the current image.
1863 * In those cases if it is NONE or REVERT we cannot certainly determine
1864 * the fact of a reboot. In a consistent state images must move in the
1865 * same direction or stay in place, e.g. in practice REVERT and TEST
1866 * swap types cannot be present at the same time. If the swap type of
1867 * the current image is either TEST, PERM or FAIL we must review the
1868 * already determined swap types of other images and set each false
1869 * REVERT swap types to NONE (these images had been successfully
1870 * updated before the system rebooted between two separate image
1871 * upgrades).
1872 */
1873
1874 if (current_image == 0) {
1875 /* Nothing to do */
1876 return;
1877 }
1878
1879 if (!aborted_swap) {
1880 if ((BOOT_SWAP_TYPE(&boot_data) == BOOT_SWAP_TYPE_NONE) ||
1881 (BOOT_SWAP_TYPE(&boot_data) == BOOT_SWAP_TYPE_REVERT)) {
1882 /* Nothing to do */
1883 return;
1884 }
1885 }
1886
1887 for (uint8_t i = 0; i < current_image; i++) {
1888 if (boot_data.swap_type[i] == BOOT_SWAP_TYPE_REVERT) {
1889 boot_data.swap_type[i] = BOOT_SWAP_TYPE_NONE;
1890 }
1891 }
1892}
1893#endif
1894
1895/**
1896 * Prepare image to be updated if required.
1897 *
1898 * Prepare image to be updated if required with completing an image swap
1899 * operation if one was aborted and/or determining the type of the
1900 * swap operation. In case of any error set the swap type to NONE.
1901 *
1902 * @param bs Pointer where the read and possibly updated
1903 * boot status can be written to.
1904 */
1905static void
1906boot_prepare_image_for_update(struct boot_status *bs)
1907{
1908 int rc;
1909
1910 /* Determine the sector layout of the image slots and scratch area. */
1911 rc = boot_read_sectors();
1912 if (rc != 0) {
1913 BOOT_LOG_WRN("Failed reading sectors; BOOT_MAX_IMG_SECTORS=%d"
1914 " - too small?", BOOT_MAX_IMG_SECTORS);
1915 /* Unable to determine sector layout, continue with next image
1916 * if there is one.
1917 */
1918 BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_NONE;
1919 return;
1920 }
1921
1922 /* Attempt to read an image header from each slot. */
1923 rc = boot_read_image_headers(false);
1924 if (rc != 0) {
1925 /* Continue with next image if there is one. */
1926 BOOT_LOG_WRN("Failed reading image headers; Image=%u", current_image);
1927 BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_NONE;
1928 return;
1929 }
1930
1931 /* If the current image's slots aren't compatible, no swap is possible.
1932 * Just boot into primary slot.
1933 */
1934 if (boot_slots_compatible()) {
1935
1936 rc = boot_read_status(bs);
1937 if (rc != 0) {
1938 BOOT_LOG_WRN("Failed reading boot status; Image=%u",
1939 current_image);
1940 /* Continue with next image if there is one. */
1941 BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_NONE;
1942 return;
1943 }
1944
1945 /* Determine if we rebooted in the middle of an image swap
1946 * operation. If a partial swap was detected, complete it.
1947 */
1948 if (bs->idx != BOOT_STATUS_IDX_0 || bs->state != BOOT_STATUS_STATE_0) {
1949
1950#if (BOOT_IMAGE_NUMBER > 1)
1951 boot_review_image_swap_types(true);
1952#endif
1953
1954#ifdef MCUBOOT_OVERWRITE_ONLY
1955 /* Should never arrive here, overwrite-only mode has
1956 * no swap state.
1957 */
1958 assert(0);
1959#else
1960 /* Determine the type of swap operation being resumed from the
1961 * `swap-type` trailer field.
1962 */
1963 rc = boot_complete_partial_swap(bs);
1964 assert(rc == 0);
1965#endif
1966 /* Attempt to read an image header from each slot. Ensure that
1967 * image headers in slots are aligned with headers in boot_data.
1968 */
1969 rc = boot_read_image_headers(false);
1970 assert(rc == 0);
1971
1972 /* Swap has finished set to NONE */
1973 BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_NONE;
1974 } else {
1975 /* There was no partial swap, determine swap type. */
1976 if (bs->swap_type == BOOT_SWAP_TYPE_NONE) {
1977 BOOT_SWAP_TYPE(&boot_data) = boot_validated_swap_type(bs);
1978 } else if (boot_validate_slot(BOOT_SECONDARY_SLOT, bs) != 0) {
1979 BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_FAIL;
1980 } else {
1981 BOOT_SWAP_TYPE(&boot_data) = bs->swap_type;
1982 }
1983
1984#if (BOOT_IMAGE_NUMBER > 1)
1985 boot_review_image_swap_types(false);
1986#endif
1987 }
1988 } else {
1989 /* In that case if slots are not compatible. */
1990 BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_NONE;
1991 }
Tamas Banf70ef8c2017-12-19 15:35:09 +00001992}
1993
1994/**
1995 * Prepares the booting process. This function moves images around in flash as
1996 * appropriate, and tells you what address to boot from.
1997 *
1998 * @param rsp On success, indicates how booting should occur.
1999 *
2000 * @return 0 on success; nonzero on failure.
2001 */
2002int
2003boot_go(struct boot_rsp *rsp)
2004{
Tamas Banf70ef8c2017-12-19 15:35:09 +00002005 size_t slot;
David Vincze7384ee72019-07-23 17:00:42 +02002006 struct boot_status bs;
Tamas Ban4e5ed8d2019-09-17 09:31:11 +01002007 int rc = 0;
Tamas Banf70ef8c2017-12-19 15:35:09 +00002008 int fa_id;
Tamas Banf70ef8c2017-12-19 15:35:09 +00002009
2010 /* The array of slot sectors are defined here (as opposed to file scope) so
2011 * that they don't get allocated for non-boot-loader apps. This is
2012 * necessary because the gcc option "-fdata-sections" doesn't seem to have
2013 * any effect in older gcc versions (e.g., 4.8.4).
2014 */
David Vincze7384ee72019-07-23 17:00:42 +02002015 static boot_sector_t
2016 primary_slot_sectors[BOOT_IMAGE_NUMBER][BOOT_MAX_IMG_SECTORS];
2017 static boot_sector_t
2018 secondary_slot_sectors[BOOT_IMAGE_NUMBER][BOOT_MAX_IMG_SECTORS];
David Vincze401c7422019-06-21 20:44:05 +02002019 static boot_sector_t scratch_sectors[BOOT_MAX_IMG_SECTORS];
Tamas Banf70ef8c2017-12-19 15:35:09 +00002020
David Vincze7384ee72019-07-23 17:00:42 +02002021 /* Iterate over all the images. By the end of the loop the swap type has
2022 * to be determined for each image and all aborted swaps have to be
2023 * completed.
Tamas Banf70ef8c2017-12-19 15:35:09 +00002024 */
David Vincze7384ee72019-07-23 17:00:42 +02002025 for (current_image = 0; current_image < BOOT_IMAGE_NUMBER; ++current_image)
2026 {
2027 BOOT_IMG(&boot_data, BOOT_PRIMARY_SLOT).sectors =
2028 primary_slot_sectors[current_image];
2029 BOOT_IMG(&boot_data, BOOT_SECONDARY_SLOT).sectors =
2030 secondary_slot_sectors[current_image];
2031 boot_data.scratch.sectors = scratch_sectors;
Tamas Banf70ef8c2017-12-19 15:35:09 +00002032
David Vincze7384ee72019-07-23 17:00:42 +02002033 /* Open primary and secondary image areas for the duration
2034 * of this call.
Tamas Banf70ef8c2017-12-19 15:35:09 +00002035 */
David Vincze7384ee72019-07-23 17:00:42 +02002036 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
2037 fa_id = flash_area_id_from_image_slot(slot);
2038 rc = flash_area_open(fa_id, &BOOT_IMG_AREA(&boot_data, slot));
2039 assert(rc == 0);
2040 }
2041 rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH,
2042 &BOOT_SCRATCH_AREA(&boot_data));
2043 assert(rc == 0);
2044
2045 /* Determine swap type and complete swap if it has been aborted. */
2046 boot_prepare_image_for_update(&bs);
2047 }
2048
David Vinczebb6e3b62019-07-31 14:24:05 +02002049#if (BOOT_IMAGE_NUMBER > 1)
2050 /* Iterate over all the images and verify whether the image dependencies
2051 * are all satisfied and update swap type if necessary.
2052 */
2053 boot_verify_all_image_dependency();
2054#endif
2055
David Vincze7384ee72019-07-23 17:00:42 +02002056 /* Iterate over all the images. At this point there are no aborted swaps
2057 * and the swap types are determined for each image. By the end of the loop
2058 * all required update operations will have been finished.
2059 */
2060 for (current_image = 0; current_image < BOOT_IMAGE_NUMBER; ++current_image)
2061 {
2062
2063#if (BOOT_IMAGE_NUMBER > 1)
2064 /* Indicate that swap is not aborted */
2065 memset(&bs, 0, sizeof bs);
2066 bs.idx = BOOT_STATUS_IDX_0;
2067 bs.state = BOOT_STATUS_STATE_0;
2068#endif /* (BOOT_IMAGE_NUMBER > 1) */
2069
2070 /* Set the previously determined swap type */
2071 bs.swap_type = BOOT_SWAP_TYPE(&boot_data);
2072
2073 switch (BOOT_SWAP_TYPE(&boot_data)) {
2074 case BOOT_SWAP_TYPE_NONE:
2075 break;
2076
2077 case BOOT_SWAP_TYPE_TEST: /* fallthrough */
2078 case BOOT_SWAP_TYPE_PERM: /* fallthrough */
2079 case BOOT_SWAP_TYPE_REVERT:
2080 rc = boot_perform_update(&bs);
2081 assert(rc == 0);
2082 break;
2083
2084 case BOOT_SWAP_TYPE_FAIL:
2085 /* The image in secondary slot was invalid and is now erased. Ensure
2086 * we don't try to boot into it again on the next reboot. Do this by
2087 * pretending we just reverted back to primary slot.
2088 */
Tamas Banf70ef8c2017-12-19 15:35:09 +00002089#ifndef MCUBOOT_OVERWRITE_ONLY
David Vincze7384ee72019-07-23 17:00:42 +02002090 /* image_ok needs to be explicitly set to avoid a new revert. */
Tamas Banf70ef8c2017-12-19 15:35:09 +00002091 rc = boot_set_image_ok();
2092 if (rc != 0) {
David Vincze7384ee72019-07-23 17:00:42 +02002093 BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_PANIC;
Tamas Banf70ef8c2017-12-19 15:35:09 +00002094 }
2095#endif /* !MCUBOOT_OVERWRITE_ONLY */
David Vincze7384ee72019-07-23 17:00:42 +02002096 break;
2097
2098 default:
2099 BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_PANIC;
Tamas Banf70ef8c2017-12-19 15:35:09 +00002100 }
David Vincze7384ee72019-07-23 17:00:42 +02002101
2102 if (BOOT_SWAP_TYPE(&boot_data) == BOOT_SWAP_TYPE_PANIC) {
2103 BOOT_LOG_ERR("panic!");
2104 assert(0);
2105
2106 /* Loop forever... */
2107 while (1) {}
2108 }
Tamas Banf70ef8c2017-12-19 15:35:09 +00002109 }
2110
David Vincze7384ee72019-07-23 17:00:42 +02002111 /* Iterate over all the images. At this point all required update operations
2112 * have finished. By the end of the loop each image in the primary slot will
2113 * have been re-validated.
2114 */
2115 for (current_image = 0; current_image < BOOT_IMAGE_NUMBER; ++current_image)
2116 {
2117 if (BOOT_SWAP_TYPE(&boot_data) != BOOT_SWAP_TYPE_NONE) {
2118 /* Attempt to read an image header from each slot. Ensure that image
2119 * headers in slots are aligned with headers in boot_data.
David Vincze060968d2019-05-23 01:13:14 +02002120 */
David Vincze7384ee72019-07-23 17:00:42 +02002121 rc = boot_read_image_headers(false);
David Vincze060968d2019-05-23 01:13:14 +02002122 if (rc != 0) {
David Vincze7384ee72019-07-23 17:00:42 +02002123 goto out;
2124 }
2125 /* Since headers were reloaded, it can be assumed we just performed
2126 * a swap or overwrite. Now the header info that should be used to
2127 * provide the data for the bootstrap, which previously was at
2128 * secondary slot, was updated to primary slot.
2129 */
2130 }
2131
2132#ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT
2133 rc = boot_validate_slot(BOOT_PRIMARY_SLOT, NULL);
2134 if (rc != 0) {
2135 rc = BOOT_EBADIMAGE;
2136 goto out;
2137 }
2138#else
2139 /* Even if we're not re-validating the primary slot, we could be booting
2140 * onto an empty flash chip. At least do a basic sanity check that
2141 * the magic number on the image is OK.
2142 */
Tamas Ban056ed0b2019-09-16 12:48:32 +01002143 if (!BOOT_IMG_HDR_IS_VALID(&boot_data, slot)) {
2144 BOOT_LOG_ERR("Invalid image header Image=%u", current_image);
David Vincze7384ee72019-07-23 17:00:42 +02002145 rc = BOOT_EBADIMAGE;
2146 goto out;
2147 }
2148#endif /* MCUBOOT_VALIDATE_PRIMARY_SLOT */
2149
2150 /* Update the stored security counter with the active image's security
2151 * counter value. It will be updated only if the new security counter is
2152 * greater than the stored value.
2153 *
2154 * In case of a successful image swapping when the swap type is TEST the
2155 * security counter can be increased only after a reset, when the swap
2156 * type is NONE and the image has marked itself "OK" (the image_ok flag
2157 * has been set). This way a "revert" swap can be performed if it's
2158 * necessary.
2159 */
2160 if (BOOT_SWAP_TYPE(&boot_data) == BOOT_SWAP_TYPE_NONE) {
2161 rc = boot_update_security_counter(BOOT_PRIMARY_SLOT,
2162 boot_img_hdr(&boot_data, BOOT_PRIMARY_SLOT));
2163 if (rc != 0) {
2164 BOOT_LOG_ERR("Security counter update failed after image "
2165 "validation.");
David Vincze060968d2019-05-23 01:13:14 +02002166 goto out;
2167 }
2168 }
2169
David Vincze7384ee72019-07-23 17:00:42 +02002170 /* Save boot status to shared memory area */
2171#if (BOOT_IMAGE_NUMBER > 1)
2172 rc = boot_save_boot_status((current_image == 0) ? SW_SPE : SW_NSPE,
2173 boot_img_hdr(&boot_data, BOOT_PRIMARY_SLOT),
2174 BOOT_IMG_AREA(&boot_data, BOOT_PRIMARY_SLOT)
2175 );
David Vincze8bdfc2d2019-03-18 15:49:23 +01002176#else
David Vincze7384ee72019-07-23 17:00:42 +02002177 rc = boot_save_boot_status(SW_S_NS,
2178 boot_img_hdr(&boot_data, BOOT_PRIMARY_SLOT),
2179 BOOT_IMG_AREA(&boot_data, BOOT_PRIMARY_SLOT)
2180 );
2181#endif
2182 if (rc) {
2183 BOOT_LOG_ERR("Failed to add Image %u data to shared area",
2184 current_image);
David Vincze060968d2019-05-23 01:13:14 +02002185 }
2186 }
2187
David Vincze7384ee72019-07-23 17:00:42 +02002188 /* Always boot from the primary slot of Image 0. */
2189 current_image = 0;
2190 rsp->br_flash_dev_id =
2191 BOOT_IMG_AREA(&boot_data, BOOT_PRIMARY_SLOT)->fa_device_id;
2192 rsp->br_image_off =
2193 boot_img_slot_off(&boot_data, BOOT_PRIMARY_SLOT);
2194 rsp->br_hdr =
2195 boot_img_hdr(&boot_data, BOOT_PRIMARY_SLOT);
Tamas Ban0e8ab302019-01-17 11:45:31 +00002196
Tamas Banf70ef8c2017-12-19 15:35:09 +00002197 out:
David Vincze7384ee72019-07-23 17:00:42 +02002198 for (current_image = 0; current_image < BOOT_IMAGE_NUMBER; ++current_image)
2199 {
2200 flash_area_close(BOOT_SCRATCH_AREA(&boot_data));
2201 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
2202 flash_area_close(BOOT_IMG_AREA(&boot_data,
2203 BOOT_NUM_SLOTS - 1 - slot));
2204 }
Tamas Banf70ef8c2017-12-19 15:35:09 +00002205 }
2206 return rc;
2207}
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002208
Oliver Swedef9982442018-08-24 18:37:44 +01002209#else /* MCUBOOT_NO_SWAP || MCUBOOT_RAM_LOADING */
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002210
David Vinczedcba70b2019-05-28 12:02:52 +02002211#define BOOT_LOG_IMAGE_INFO(area, hdr, state) \
2212 BOOT_LOG_INF("Image %u: version=%u.%u.%u+%u, magic=%5s, image_ok=0x%x", \
2213 (area), \
2214 (hdr)->ih_ver.iv_major, \
2215 (hdr)->ih_ver.iv_minor, \
2216 (hdr)->ih_ver.iv_revision, \
2217 (hdr)->ih_ver.iv_build_num, \
2218 ((state)->magic == BOOT_MAGIC_GOOD ? "good" : \
2219 (state)->magic == BOOT_MAGIC_UNSET ? "unset" : \
2220 "bad"), \
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002221 (state)->image_ok)
2222
2223struct image_slot_version {
2224 uint64_t version;
2225 uint32_t slot_number;
2226};
2227
2228/**
2229 * Extract the version number from the image header. This function must be
2230 * ported if version number format has changed in the image header.
2231 *
2232 * @param hdr Pointer to an image header structure
2233 *
Oliver Swedef9982442018-08-24 18:37:44 +01002234 * @return Version number casted to uint64_t
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002235 */
2236static uint64_t
2237boot_get_version_number(struct image_header *hdr)
2238{
Oliver Swedef9982442018-08-24 18:37:44 +01002239 uint64_t version = 0;
2240 version |= (uint64_t)hdr->ih_ver.iv_major << (IMAGE_VER_MINOR_LENGTH
2241 + IMAGE_VER_REVISION_LENGTH
2242 + IMAGE_VER_BUILD_NUM_LENGTH);
2243 version |= (uint64_t)hdr->ih_ver.iv_minor << (IMAGE_VER_REVISION_LENGTH
2244 + IMAGE_VER_BUILD_NUM_LENGTH);
2245 version |= (uint64_t)hdr->ih_ver.iv_revision << IMAGE_VER_BUILD_NUM_LENGTH;
2246 version |= hdr->ih_ver.iv_build_num;
2247 return version;
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002248}
2249
2250/**
2251 * Comparator function for `qsort` to compare version numbers. This function
2252 * must be ported if version number format has changed in the image header.
2253 *
2254 * @param ver1 Pointer to an array element which holds the version number
2255 * @param ver2 Pointer to another array element which holds the version
2256 * number
2257 *
2258 * @return if version1 > version2 -1
2259 * if version1 == version2 0
2260 * if version1 < version2 1
2261 */
2262static int
2263boot_compare_version_numbers(const void *ver1, const void *ver2)
2264{
2265 if (((struct image_slot_version *)ver1)->version <
2266 ((struct image_slot_version *)ver2)->version) {
2267 return 1;
2268 }
2269
2270 if (((struct image_slot_version *)ver1)->version ==
2271 ((struct image_slot_version *)ver2)->version) {
2272 return 0;
2273 }
2274
2275 return -1;
2276}
2277
2278/**
2279 * Sort the available images based on the version number and puts them in
2280 * a list.
2281 *
2282 * @param boot_sequence A pointer to an array, whose aim is to carry
2283 * the boot order of candidate images.
2284 * @param slot_cnt The number of flash areas, which can contains firmware
2285 * images.
2286 *
2287 * @return The number of valid images.
2288 */
2289uint32_t
2290boot_get_boot_sequence(uint32_t *boot_sequence, uint32_t slot_cnt)
2291{
2292 struct boot_swap_state slot_state;
2293 struct image_header *hdr;
2294 struct image_slot_version image_versions[BOOT_NUM_SLOTS] = {{0}};
2295 uint32_t image_cnt = 0;
2296 uint32_t slot;
2297 int32_t rc;
2298 int32_t fa_id;
2299
2300 for (slot = 0; slot < slot_cnt; slot++) {
2301 hdr = boot_img_hdr(&boot_data, slot);
2302 fa_id = flash_area_id_from_image_slot(slot);
2303 rc = boot_read_swap_state_by_id(fa_id, &slot_state);
2304 if (rc != 0) {
David Vinczedcba70b2019-05-28 12:02:52 +02002305 BOOT_LOG_ERR("Error during reading image trailer from slot: %u",
2306 slot);
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002307 continue;
2308 }
2309
Tamas Ban056ed0b2019-09-16 12:48:32 +01002310 if (BOOT_IMG_HDR_IS_VALID(&boot_data, slot)) {
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002311 if (slot_state.magic == BOOT_MAGIC_GOOD ||
David Vincze39e78552018-10-10 17:10:01 +02002312 slot_state.image_ok == BOOT_FLAG_SET) {
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002313 /* Valid cases:
2314 * - Test mode: magic is OK in image trailer
2315 * - Permanent mode: image_ok flag has previously set
2316 */
2317 image_versions[slot].slot_number = slot;
2318 image_versions[slot].version = boot_get_version_number(hdr);
2319 image_cnt++;
2320 }
2321
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002322 BOOT_LOG_IMAGE_INFO(slot, hdr, &slot_state);
2323 } else {
David Vinczedcba70b2019-05-28 12:02:52 +02002324 BOOT_LOG_INF("Image %u: No valid image", slot);
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002325 }
2326 }
2327
2328 /* Sort the images based on version number */
2329 qsort(&image_versions[0],
2330 slot_cnt,
2331 sizeof(struct image_slot_version),
2332 boot_compare_version_numbers);
2333
2334 /* Copy the calculated boot sequence to boot_sequence array */
2335 for (slot = 0; slot < slot_cnt; slot++) {
2336 boot_sequence[slot] = image_versions[slot].slot_number;
2337 }
2338
2339 return image_cnt;
2340}
2341
Oliver Swedef9982442018-08-24 18:37:44 +01002342#ifdef MCUBOOT_RAM_LOADING
Raef Colesaf082382019-10-01 11:10:33 +01002343
2344/**
2345 * Verifies that the image in a slot lies within the predefined bounds that are
2346 * allowed to be used by executable images.
2347 *
2348 * @param img_dst The address to which the image is going to be copied.
2349 *
2350 * @param img_sz The size of the image.
2351 *
2352 * @return 0 on success; nonzero on failure.
2353 */
2354static int
2355boot_verify_ram_loading_address(uint32_t img_dst, uint32_t img_sz)
2356{
2357 if (img_dst < IMAGE_EXECUTABLE_RAM_START) {
2358 return BOOT_EBADIMAGE;
2359 }
2360
2361 if (boot_add_uint32_overflow_check(img_dst, img_sz)) {
2362 return BOOT_EBADIMAGE;
2363 }
2364
2365 if (img_dst + img_sz > IMAGE_EXECUTABLE_RAM_START +
2366 IMAGE_EXECUTABLE_RAM_SIZE) {
2367 return BOOT_EBADIMAGE;
2368 }
2369
2370 return 0;
2371}
2372
Oliver Swedef9982442018-08-24 18:37:44 +01002373/**
2374 * Copies an image from a slot in the flash to an SRAM address, where the load
2375 * address has already been inserted into the image header by this point and is
2376 * extracted from it within this method. The copying is done sector-by-sector.
2377 *
2378 * @param slot The flash slot of the image to be copied to SRAM.
2379 *
2380 * @param hdr Pointer to the image header structure of the image
Raef Colesaf082382019-10-01 11:10:33 +01002381 *
2382 * @param img_dst The address at which the image needs to be copied to
2383 * SRAM.
2384 *
2385 * @param img_sz The size of the image that needs to be copied to SRAM.
Oliver Swedef9982442018-08-24 18:37:44 +01002386 *
2387 * @return 0 on success; nonzero on failure.
2388 */
2389static int
Raef Colesaf082382019-10-01 11:10:33 +01002390boot_copy_image_to_sram(int slot, struct image_header *hdr,
2391 uint32_t img_dst, uint32_t img_sz)
Oliver Swedef9982442018-08-24 18:37:44 +01002392{
2393 int rc;
2394 uint32_t sect_sz;
2395 uint32_t sect = 0;
2396 uint32_t bytes_copied = 0;
2397 const struct flash_area *fap_src = NULL;
Oliver Swedef9982442018-08-24 18:37:44 +01002398
Raef Colesaf082382019-10-01 11:10:33 +01002399 if (img_dst % 4 != 0) {
Tamas Banc27b5c32019-05-28 16:30:19 +01002400 BOOT_LOG_INF("Cannot copy the image to the SRAM address 0x%x "
Oliver Swedef9982442018-08-24 18:37:44 +01002401 "- the load address must be aligned with 4 bytes due to SRAM "
Raef Colesaf082382019-10-01 11:10:33 +01002402 "restrictions", img_dst);
Oliver Swedef9982442018-08-24 18:37:44 +01002403 return BOOT_EBADARGS;
2404 }
2405
2406 rc = flash_area_open(flash_area_id_from_image_slot(slot), &fap_src);
2407 if (rc != 0) {
2408 return BOOT_EFLASH;
2409 }
2410
Oliver Swedef9982442018-08-24 18:37:44 +01002411 while (bytes_copied < img_sz) {
2412 sect_sz = boot_img_sector_size(&boot_data, slot, sect);
2413 /*
2414 * Direct copy from where the image sector resides in flash to its new
2415 * location in SRAM
2416 */
2417 rc = flash_area_read(fap_src,
2418 bytes_copied,
Raef Colesaf082382019-10-01 11:10:33 +01002419 (void *)(img_dst + bytes_copied),
Oliver Swedef9982442018-08-24 18:37:44 +01002420 sect_sz);
2421 if (rc != 0) {
2422 BOOT_LOG_INF("Error whilst copying image from Flash to SRAM");
2423 break;
2424 } else {
2425 bytes_copied += sect_sz;
2426 }
2427 sect++;
2428 }
2429
2430 if (fap_src) {
2431 flash_area_close(fap_src);
2432 }
2433 return rc;
2434}
Raef Coles27a61452019-09-25 15:32:25 +01002435
2436/**
2437 * Removes an image from SRAM, by overwriting it with zeros.
2438 *
Raef Colesaf082382019-10-01 11:10:33 +01002439 * @param img_dst The address of the image that needs to be removed from
2440 * SRAM.
Raef Coles27a61452019-09-25 15:32:25 +01002441 *
Raef Colesaf082382019-10-01 11:10:33 +01002442 * @param img_sz The size of the image that needs to be removed from
2443 * SRAM.
Raef Coles27a61452019-09-25 15:32:25 +01002444 *
2445 * @return 0 on success; nonzero on failure.
2446 */
2447static int
Raef Colesaf082382019-10-01 11:10:33 +01002448boot_remove_image_from_sram(uint32_t img_dst, uint32_t img_sz)
Raef Coles27a61452019-09-25 15:32:25 +01002449{
Raef Colesaf082382019-10-01 11:10:33 +01002450 BOOT_LOG_INF("Removing image from SRAM at address 0x%x", img_dst);
2451 memset((void*)img_dst, 0, img_sz);
Raef Coles27a61452019-09-25 15:32:25 +01002452
2453 return 0;
2454}
Oliver Swedef9982442018-08-24 18:37:44 +01002455#endif /* MCUBOOT_RAM_LOADING */
2456
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002457/**
2458 * Prepares the booting process. This function choose the newer image in flash
2459 * as appropriate, and returns the address to boot from.
2460 *
2461 * @param rsp On success, indicates how booting should occur.
2462 *
2463 * @return 0 on success; nonzero on failure.
2464 */
2465int
2466boot_go(struct boot_rsp *rsp)
2467{
2468 size_t slot = 0;
2469 int32_t i;
2470 int rc;
2471 int fa_id;
2472 uint32_t boot_sequence[BOOT_NUM_SLOTS];
2473 uint32_t img_cnt;
Raef Coles27a61452019-09-25 15:32:25 +01002474 struct image_header *selected_image_header;
2475#ifdef MCUBOOT_RAM_LOADING
2476 int image_copied = 0;
Raef Colesaf082382019-10-01 11:10:33 +01002477 uint32_t img_dst = 0;
2478 uint32_t img_sz = 0;
Raef Coles27a61452019-09-25 15:32:25 +01002479#endif /* MCUBOOT_RAM_LOADING */
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002480
David Vincze8bdfc2d2019-03-18 15:49:23 +01002481 static boot_sector_t primary_slot_sectors[BOOT_MAX_IMG_SECTORS];
2482 static boot_sector_t secondary_slot_sectors[BOOT_MAX_IMG_SECTORS];
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002483
David Vincze7384ee72019-07-23 17:00:42 +02002484 BOOT_IMG(&boot_data, BOOT_PRIMARY_SLOT).sectors =
2485 &primary_slot_sectors[0];
2486 BOOT_IMG(&boot_data, BOOT_SECONDARY_SLOT).sectors =
2487 &secondary_slot_sectors[0];
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002488
2489 /* Open boot_data image areas for the duration of this call. */
2490 for (i = 0; i < BOOT_NUM_SLOTS; i++) {
2491 fa_id = flash_area_id_from_image_slot(i);
2492 rc = flash_area_open(fa_id, &BOOT_IMG_AREA(&boot_data, i));
2493 assert(rc == 0);
2494 }
2495
2496 /* Determine the sector layout of the image slots. */
2497 rc = boot_read_sectors();
2498 if (rc != 0) {
David Vincze39e78552018-10-10 17:10:01 +02002499 BOOT_LOG_WRN("Failed reading sectors; BOOT_MAX_IMG_SECTORS=%d - too small?",
2500 BOOT_MAX_IMG_SECTORS);
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002501 goto out;
2502 }
2503
2504 /* Attempt to read an image header from each slot. */
David Vincze39e78552018-10-10 17:10:01 +02002505 rc = boot_read_image_headers(false);
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002506 if (rc != 0) {
2507 goto out;
2508 }
2509
2510 img_cnt = boot_get_boot_sequence(boot_sequence, BOOT_NUM_SLOTS);
2511 if (img_cnt) {
2512 /* Authenticate images */
2513 for (i = 0; i < img_cnt; i++) {
Raef Coles27a61452019-09-25 15:32:25 +01002514
2515 slot = boot_sequence[i];
2516 selected_image_header = boot_img_hdr(&boot_data, slot);
2517
2518#ifdef MCUBOOT_RAM_LOADING
2519 if (selected_image_header->ih_flags & IMAGE_F_RAM_LOAD) {
Raef Colesaf082382019-10-01 11:10:33 +01002520
2521 img_dst = selected_image_header->ih_load_addr;
2522
2523 rc = boot_read_image_size(slot, selected_image_header, &img_sz);
2524 if (rc != 0) {
2525 rc = BOOT_EFLASH;
2526 BOOT_LOG_INF("Could not load image headers from the image"
2527 "in the %s slot.",
2528 (slot == BOOT_PRIMARY_SLOT) ?
2529 "primary" : "secondary");
2530 continue;
2531 }
2532
2533 rc = boot_verify_ram_loading_address(img_dst, img_sz);
2534 if (rc != 0) {
2535 BOOT_LOG_INF("Could not copy image from the %s slot in "
2536 "the Flash to load address 0x%x in SRAM as"
2537 " the image would overlap memory outside"
2538 " the defined executable region.",
2539 (slot == BOOT_PRIMARY_SLOT) ?
2540 "primary" : "secondary",
2541 selected_image_header->ih_load_addr);
2542 continue;
2543 }
2544
Raef Coles27a61452019-09-25 15:32:25 +01002545 /* Copy image to the load address from where it
2546 * currently resides in flash
2547 */
Raef Colesaf082382019-10-01 11:10:33 +01002548 rc = boot_copy_image_to_sram(slot, selected_image_header,
2549 img_dst, img_sz);
Raef Coles27a61452019-09-25 15:32:25 +01002550 if (rc != 0) {
2551 rc = BOOT_EBADIMAGE;
2552 BOOT_LOG_INF("Could not copy image from the %s slot in "
2553 "the Flash to load address 0x%x in SRAM, "
2554 "aborting..", (slot == BOOT_PRIMARY_SLOT) ?
2555 "primary" : "secondary",
2556 selected_image_header->ih_load_addr);
2557 continue;
2558 } else {
2559 BOOT_LOG_INF("Image has been copied from the %s slot in "
2560 "the flash to SRAM address 0x%x",
2561 (slot == BOOT_PRIMARY_SLOT) ?
2562 "primary" : "secondary",
2563 selected_image_header->ih_load_addr);
2564 image_copied = 1;
2565 }
2566 } else {
2567 /* Only images that support IMAGE_F_RAM_LOAD are allowed if
2568 * MCUBOOT_RAM_LOADING is set.
2569 */
2570 rc = BOOT_EBADIMAGE;
2571 continue;
2572 }
2573#endif /* MCUBOOT_RAM_LOADING */
2574 rc = boot_validate_slot(slot, NULL);
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002575 if (rc == 0) {
Raef Coles27a61452019-09-25 15:32:25 +01002576 /* If a valid image is found then there is no reason to check
2577 * the rest of the images, as they were already ordered by
2578 * preference.
2579 */
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002580 break;
2581 }
Raef Coles27a61452019-09-25 15:32:25 +01002582#ifdef MCUBOOT_RAM_LOADING
2583 else if (image_copied) {
2584 /* If an image is found to be invalid then it is removed from
2585 * RAM to prevent it being a shellcode vector.
2586 */
Raef Colesaf082382019-10-01 11:10:33 +01002587 boot_remove_image_from_sram(img_dst, img_sz);
Raef Coles27a61452019-09-25 15:32:25 +01002588 image_copied = 0;
2589 }
2590#endif /* MCUBOOT_RAM_LOADING */
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002591 }
2592 if (rc) {
2593 /* If there was no valid image at all */
2594 rc = BOOT_EBADIMAGE;
2595 goto out;
2596 }
2597
David Vincze060968d2019-05-23 01:13:14 +02002598 /* Update the security counter with the newest image's security
2599 * counter value.
2600 */
Raef Coles27a61452019-09-25 15:32:25 +01002601 rc = boot_update_security_counter(slot, selected_image_header);
David Vincze060968d2019-05-23 01:13:14 +02002602 if (rc != 0) {
2603 BOOT_LOG_ERR("Security counter update failed after image "
2604 "validation.");
2605 goto out;
2606 }
2607
Oliver Swedef9982442018-08-24 18:37:44 +01002608
David Vincze8a2a4e22019-05-24 10:14:23 +02002609#ifdef MCUBOOT_RAM_LOADING
Raef Coles27a61452019-09-25 15:32:25 +01002610 BOOT_LOG_INF("Booting image from SRAM at address 0x%x",
2611 selected_image_header->ih_load_addr);
2612#else
2613 BOOT_LOG_INF("Booting image from the %s slot",
2614 (slot == BOOT_PRIMARY_SLOT) ? "primary" : "secondary");
2615#endif /* MCUBOOT_RAM_LOADING */
Oliver Swedef9982442018-08-24 18:37:44 +01002616
Raef Coles27a61452019-09-25 15:32:25 +01002617 rsp->br_hdr = selected_image_header;
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002618 rsp->br_image_off = boot_img_slot_off(&boot_data, slot);
David Vincze7384ee72019-07-23 17:00:42 +02002619 rsp->br_flash_dev_id = BOOT_IMG_AREA(&boot_data, slot)->fa_device_id;
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002620 } else {
2621 /* No candidate image available */
2622 rc = BOOT_EBADIMAGE;
David Vincze060968d2019-05-23 01:13:14 +02002623 goto out;
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002624 }
2625
Tamas Ban0e8ab302019-01-17 11:45:31 +00002626 /* Save boot status to shared memory area */
2627 rc = boot_save_boot_status(SW_S_NS,
2628 rsp->br_hdr,
2629 BOOT_IMG_AREA(&boot_data, slot));
2630 if (rc) {
2631 BOOT_LOG_ERR("Failed to add data to shared area");
2632 }
2633
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002634out:
2635 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
2636 flash_area_close(BOOT_IMG_AREA(&boot_data, BOOT_NUM_SLOTS - 1 - slot));
2637 }
2638 return rc;
2639}
Oliver Swedef9982442018-08-24 18:37:44 +01002640#endif /* MCUBOOT_NO_SWAP || MCUBOOT_RAM_LOADING */