blob: 2b6f655c29f44639538c13f25e18551567b618d9 [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 Vincze2ddc1372019-10-25 11:10:08 +020023 * Git SHA of the original version: ac55554059147fff718015be9f4bd3108123f50a
David Vincze225c58f2019-12-09 17:32:48 +010024 * Modifications are Copyright (c) 2018-2020 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>
David Vincze225c58f2019-12-09 17:32:48 +010038#include "sysflash/sysflash.h"
Tamas Banc3828852018-02-01 12:24:16 +000039#include "flash_map/flash_map.h"
David Vincze225c58f2019-12-09 17:32:48 +010040#include "flash_map_backend/flash_map_backend.h"
Tamas Banf70ef8c2017-12-19 15:35:09 +000041#include "bootutil/bootutil.h"
42#include "bootutil/image.h"
43#include "bootutil_priv.h"
David Vincze73dfbc52019-10-11 13:54:58 +020044#include "bootutil/bootutil_log.h"
Tamas Bana9de4a62018-09-18 08:09:45 +010045#include "bl2/include/tfm_boot_status.h"
46#include "bl2/include/boot_record.h"
David Vincze060968d2019-05-23 01:13:14 +020047#include "security_cnt.h"
Balint Matyi2fe04922020-02-18 12:27:38 +000048#include "mcuboot_config/mcuboot_config.h"
Tamas Banf70ef8c2017-12-19 15:35:09 +000049
Tamas Banf70ef8c2017-12-19 15:35:09 +000050static struct boot_loader_state boot_data;
David Vinczecea8b592019-10-29 16:09:51 +010051
52#if (BOOT_IMAGE_NUMBER > 1)
53#define IMAGES_ITER(x) for ((x) = 0; (x) < BOOT_IMAGE_NUMBER; ++(x))
54#else
55#define IMAGES_ITER(x)
56#endif
Tamas Banf70ef8c2017-12-19 15:35:09 +000057
Oliver Swedef9982442018-08-24 18:37:44 +010058#if !defined(MCUBOOT_NO_SWAP) && !defined(MCUBOOT_RAM_LOADING)
David Vincze39e78552018-10-10 17:10:01 +020059
David Vincze8bdfc2d2019-03-18 15:49:23 +010060#if defined(MCUBOOT_VALIDATE_PRIMARY_SLOT) && !defined(MCUBOOT_OVERWRITE_ONLY)
David Vincze39e78552018-10-10 17:10:01 +020061static int boot_status_fails = 0;
62#define BOOT_STATUS_ASSERT(x) \
63 do { \
64 if (!(x)) { \
65 boot_status_fails++; \
66 } \
67 } while (0)
68#else
David Vincze401c7422019-06-21 20:44:05 +020069#define BOOT_STATUS_ASSERT(x) ASSERT(x)
David Vincze39e78552018-10-10 17:10:01 +020070#endif
71
Tamas Banf70ef8c2017-12-19 15:35:09 +000072struct boot_status_table {
David Vincze8bdfc2d2019-03-18 15:49:23 +010073 uint8_t bst_magic_primary_slot;
Tamas Banf70ef8c2017-12-19 15:35:09 +000074 uint8_t bst_magic_scratch;
David Vincze8bdfc2d2019-03-18 15:49:23 +010075 uint8_t bst_copy_done_primary_slot;
Tamas Banf70ef8c2017-12-19 15:35:09 +000076 uint8_t bst_status_source;
77};
78
79/**
80 * This set of tables maps swap state contents to boot status location.
81 * When searching for a match, these tables must be iterated in order.
82 */
83static const struct boot_status_table boot_status_tables[] = {
84 {
David Vincze8bdfc2d2019-03-18 15:49:23 +010085 /* | primary slot | scratch |
86 * ----------+--------------+--------------|
87 * magic | Good | Any |
88 * copy-done | Set | N/A |
89 * ----------+--------------+--------------'
90 * source: none |
91 * ----------------------------------------'
Tamas Banf70ef8c2017-12-19 15:35:09 +000092 */
David Vincze8bdfc2d2019-03-18 15:49:23 +010093 .bst_magic_primary_slot = BOOT_MAGIC_GOOD,
David Vincze401c7422019-06-21 20:44:05 +020094 .bst_magic_scratch = BOOT_MAGIC_NOTGOOD,
David Vincze8bdfc2d2019-03-18 15:49:23 +010095 .bst_copy_done_primary_slot = BOOT_FLAG_SET,
96 .bst_status_source = BOOT_STATUS_SOURCE_NONE,
Tamas Banf70ef8c2017-12-19 15:35:09 +000097 },
98
99 {
David Vincze8bdfc2d2019-03-18 15:49:23 +0100100 /* | primary slot | scratch |
101 * ----------+--------------+--------------|
102 * magic | Good | Any |
103 * copy-done | Unset | N/A |
104 * ----------+--------------+--------------'
105 * source: primary slot |
106 * ----------------------------------------'
Tamas Banf70ef8c2017-12-19 15:35:09 +0000107 */
David Vincze8bdfc2d2019-03-18 15:49:23 +0100108 .bst_magic_primary_slot = BOOT_MAGIC_GOOD,
David Vincze401c7422019-06-21 20:44:05 +0200109 .bst_magic_scratch = BOOT_MAGIC_NOTGOOD,
David Vincze8bdfc2d2019-03-18 15:49:23 +0100110 .bst_copy_done_primary_slot = BOOT_FLAG_UNSET,
111 .bst_status_source = BOOT_STATUS_SOURCE_PRIMARY_SLOT,
Tamas Banf70ef8c2017-12-19 15:35:09 +0000112 },
113
114 {
David Vincze8bdfc2d2019-03-18 15:49:23 +0100115 /* | primary slot | scratch |
116 * ----------+--------------+--------------|
117 * magic | Any | Good |
118 * copy-done | Any | N/A |
119 * ----------+--------------+--------------'
120 * source: scratch |
121 * ----------------------------------------'
Tamas Banf70ef8c2017-12-19 15:35:09 +0000122 */
David Vincze8bdfc2d2019-03-18 15:49:23 +0100123 .bst_magic_primary_slot = BOOT_MAGIC_ANY,
124 .bst_magic_scratch = BOOT_MAGIC_GOOD,
125 .bst_copy_done_primary_slot = BOOT_FLAG_ANY,
126 .bst_status_source = BOOT_STATUS_SOURCE_SCRATCH,
Tamas Banf70ef8c2017-12-19 15:35:09 +0000127 },
128
129 {
David Vincze8bdfc2d2019-03-18 15:49:23 +0100130 /* | primary slot | scratch |
131 * ----------+--------------+--------------|
132 * magic | Unset | Any |
133 * copy-done | Unset | N/A |
134 * ----------+--------------+--------------|
135 * source: varies |
136 * ----------------------------------------+--------------------------+
Tamas Banf70ef8c2017-12-19 15:35:09 +0000137 * This represents one of two cases: |
138 * o No swaps ever (no status to read, so no harm in checking). |
David Vincze8bdfc2d2019-03-18 15:49:23 +0100139 * o Mid-revert; status in the primary slot. |
Tamas Banf70ef8c2017-12-19 15:35:09 +0000140 * -------------------------------------------------------------------'
141 */
David Vincze8bdfc2d2019-03-18 15:49:23 +0100142 .bst_magic_primary_slot = BOOT_MAGIC_UNSET,
143 .bst_magic_scratch = BOOT_MAGIC_ANY,
144 .bst_copy_done_primary_slot = BOOT_FLAG_UNSET,
145 .bst_status_source = BOOT_STATUS_SOURCE_PRIMARY_SLOT,
Tamas Banf70ef8c2017-12-19 15:35:09 +0000146 },
147};
148
149#define BOOT_STATUS_TABLES_COUNT \
Tamas Ban581034a2017-12-19 19:54:37 +0000150 (sizeof(boot_status_tables) / sizeof(boot_status_tables[0]))
Tamas Banf70ef8c2017-12-19 15:35:09 +0000151
152#define BOOT_LOG_SWAP_STATE(area, state) \
David Vincze401c7422019-06-21 20:44:05 +0200153 BOOT_LOG_INF("%s: magic=%5s, swap_type=0x%x, copy_done=0x%x, " \
154 "image_ok=0x%x", \
Tamas Banf70ef8c2017-12-19 15:35:09 +0000155 (area), \
156 ((state)->magic == BOOT_MAGIC_GOOD ? "good" : \
157 (state)->magic == BOOT_MAGIC_UNSET ? "unset" : \
158 "bad"), \
David Vincze401c7422019-06-21 20:44:05 +0200159 (state)->swap_type, \
Tamas Banf70ef8c2017-12-19 15:35:09 +0000160 (state)->copy_done, \
161 (state)->image_ok)
Oliver Swedef9982442018-08-24 18:37:44 +0100162#endif /* !MCUBOOT_NO_SWAP && !MCUBOOT_RAM_LOADING */
Tamas Banf70ef8c2017-12-19 15:35:09 +0000163
Tamas Ban056ed0b2019-09-16 12:48:32 +0100164/*
165 * \brief Verifies the image header: magic value, flags, integer overflow.
166 *
167 * \retval 0
168 * \retval BOOT_EBADIMAGE
169 */
170static int
171boot_verify_image_header(struct image_header *hdr)
172{
173 uint32_t image_end;
David Vincze0dc41d22019-10-28 14:56:29 +0100174 uint32_t x;
Tamas Ban056ed0b2019-09-16 12:48:32 +0100175
176 if (hdr->ih_magic != IMAGE_MAGIC) {
177 return BOOT_EBADIMAGE;
178 }
179
180 /* Check input parameters against integer overflow */
David Vincze0dc41d22019-10-28 14:56:29 +0100181 if (!boot_u32_safe_add(&image_end, hdr->ih_hdr_size, hdr->ih_img_size)) {
Tamas Ban056ed0b2019-09-16 12:48:32 +0100182 return BOOT_EBADIMAGE;
183 }
184
David Vincze0dc41d22019-10-28 14:56:29 +0100185 if (!boot_u32_safe_add(&x, image_end, hdr->ih_protect_tlv_size)) {
Tamas Ban056ed0b2019-09-16 12:48:32 +0100186 return BOOT_EBADIMAGE;
187 }
188
Tamas Ban056ed0b2019-09-16 12:48:32 +0100189#if MCUBOOT_RAM_LOADING
190 if (!(hdr->ih_flags & IMAGE_F_RAM_LOAD)) {
191 return BOOT_EBADIMAGE;
192 }
193
194 /* Check input parameters against integer overflow */
David Vincze0dc41d22019-10-28 14:56:29 +0100195 if (!boot_u32_safe_add(&x, image_end, hdr->ih_load_addr)) {
Tamas Ban056ed0b2019-09-16 12:48:32 +0100196 return BOOT_EBADIMAGE;
197 }
198#endif
199
200 return 0;
201}
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000202
203static int
David Vinczecea8b592019-10-29 16:09:51 +0100204boot_read_image_header(struct boot_loader_state *state, int slot,
205 struct image_header *out_hdr)
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000206{
207 const struct flash_area *fap = NULL;
208 int area_id;
209 int rc;
210
David Vinczecea8b592019-10-29 16:09:51 +0100211#if (BOOT_IMAGE_NUMBER == 1)
212 (void)state;
213#endif
214
215 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000216 rc = flash_area_open(area_id, &fap);
217 if (rc != 0) {
218 rc = BOOT_EFLASH;
219 goto done;
220 }
221
222 rc = flash_area_read(fap, 0, out_hdr, sizeof(*out_hdr));
223 if (rc != 0) {
224 rc = BOOT_EFLASH;
225 goto done;
226 }
227
Tamas Ban056ed0b2019-09-16 12:48:32 +0100228 rc = boot_verify_image_header(out_hdr);
David Vinczecea8b592019-10-29 16:09:51 +0100229 BOOT_IMG_HDR_IS_VALID(state, slot) = (rc == 0);
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000230
231done:
232 flash_area_close(fap);
233 return rc;
234}
235
236static int
David Vinczecea8b592019-10-29 16:09:51 +0100237boot_read_image_headers(struct boot_loader_state *state, bool require_all)
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000238{
239 int rc;
240 int i;
241
242 for (i = 0; i < BOOT_NUM_SLOTS; i++) {
David Vinczecea8b592019-10-29 16:09:51 +0100243 rc = boot_read_image_header(state, i, boot_img_hdr(state, i));
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000244 if (rc != 0) {
David Vincze39e78552018-10-10 17:10:01 +0200245 /* If `require_all` is set, fail on any single fail, otherwise
246 * if at least the first slot's header was read successfully,
247 * then the boot loader can attempt a boot.
248 *
249 * Failure to read any headers is a fatal error.
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000250 */
David Vincze39e78552018-10-10 17:10:01 +0200251 if (i > 0 && !require_all) {
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000252 return 0;
253 } else {
254 return rc;
255 }
256 }
257 }
258
259 return 0;
260}
261
Raef Coles204c5b42019-09-05 09:18:47 +0100262static uint32_t
David Vinczecea8b592019-10-29 16:09:51 +0100263boot_write_sz(struct boot_loader_state *state)
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000264{
Raef Coles204c5b42019-09-05 09:18:47 +0100265 uint32_t elem_sz;
266 uint32_t align;
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000267
268 /* Figure out what size to write update status update as. The size depends
269 * on what the minimum write size is for scratch area, active image slot.
270 * We need to use the bigger of those 2 values.
271 */
David Vinczecea8b592019-10-29 16:09:51 +0100272 elem_sz = flash_area_align(BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT));
273 align = flash_area_align(BOOT_SCRATCH_AREA(state));
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000274 if (align > elem_sz) {
275 elem_sz = align;
276 }
277
278 return elem_sz;
279}
280
David Vinczecea8b592019-10-29 16:09:51 +0100281#ifndef MCUBOOT_USE_FLASH_AREA_GET_SECTORS
282static int
283boot_initialize_area(struct boot_loader_state *state, int flash_area)
284{
285 int num_sectors = BOOT_MAX_IMG_SECTORS;
286 int rc;
287
288 if (flash_area == FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state))) {
289 rc = flash_area_to_sectors(flash_area, &num_sectors,
290 BOOT_IMG(state, BOOT_PRIMARY_SLOT).sectors);
291 BOOT_IMG(state, BOOT_PRIMARY_SLOT).num_sectors = (size_t)num_sectors;
292
293 } else if (flash_area == FLASH_AREA_IMAGE_SECONDARY(BOOT_CURR_IMG(state))) {
294 rc = flash_area_to_sectors(flash_area, &num_sectors,
295 BOOT_IMG(state, BOOT_SECONDARY_SLOT).sectors);
296 BOOT_IMG(state, BOOT_SECONDARY_SLOT).num_sectors = (size_t)num_sectors;
297
298 } else if (flash_area == FLASH_AREA_IMAGE_SCRATCH) {
299 rc = flash_area_to_sectors(flash_area, &num_sectors,
300 state->scratch.sectors);
301 state->scratch.num_sectors = (size_t)num_sectors;
302 } else {
303 return BOOT_EFLASH;
304 }
305
306 return rc;
307}
308#else /* defined(MCUBOOT_USE_FLASH_AREA_GET_SECTORS) */
309static int
310boot_initialize_area(struct boot_loader_state *state, int flash_area)
311{
312 uint32_t num_sectors;
313 struct flash_sector *out_sectors;
314 size_t *out_num_sectors;
315 int rc;
316
317 num_sectors = BOOT_MAX_IMG_SECTORS;
318
319 if (flash_area == FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state))) {
320 out_sectors = BOOT_IMG(state, BOOT_PRIMARY_SLOT).sectors;
321 out_num_sectors = &BOOT_IMG(state, BOOT_PRIMARY_SLOT).num_sectors;
322 } else if (flash_area == FLASH_AREA_IMAGE_SECONDARY(BOOT_CURR_IMG(state))) {
323 out_sectors = BOOT_IMG(state, BOOT_SECONDARY_SLOT).sectors;
324 out_num_sectors = &BOOT_IMG(state, BOOT_SECONDARY_SLOT).num_sectors;
325 } else if (flash_area == FLASH_AREA_IMAGE_SCRATCH) {
326 out_sectors = state->scratch.sectors;
327 out_num_sectors = &state->scratch.num_sectors;
328 } else {
329 return BOOT_EFLASH;
330 }
331
332 rc = flash_area_get_sectors(flash_area, &num_sectors, out_sectors);
333 if (rc != 0) {
334 return rc;
335 }
336 *out_num_sectors = num_sectors;
337 return 0;
338}
339#endif /* !defined(MCUBOOT_USE_FLASH_AREA_GET_SECTORS) */
340
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000341/**
342 * Determines the sector layout of both image slots and the scratch area.
343 * This information is necessary for calculating the number of bytes to erase
344 * and copy during an image swap. The information collected during this
David Vinczecea8b592019-10-29 16:09:51 +0100345 * function is used to populate the state.
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000346 */
347static int
David Vinczecea8b592019-10-29 16:09:51 +0100348boot_read_sectors(struct boot_loader_state *state)
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000349{
David Vinczecea8b592019-10-29 16:09:51 +0100350 uint8_t image_index;
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000351 int rc;
352
David Vinczecea8b592019-10-29 16:09:51 +0100353 image_index = BOOT_CURR_IMG(state);
354
355 rc = boot_initialize_area(state, FLASH_AREA_IMAGE_PRIMARY(image_index));
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000356 if (rc != 0) {
357 return BOOT_EFLASH;
358 }
359
David Vinczecea8b592019-10-29 16:09:51 +0100360 rc = boot_initialize_area(state, FLASH_AREA_IMAGE_SECONDARY(image_index));
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000361 if (rc != 0) {
362 return BOOT_EFLASH;
363 }
364
David Vinczecea8b592019-10-29 16:09:51 +0100365 rc = boot_initialize_area(state, FLASH_AREA_IMAGE_SCRATCH);
David Vincze401c7422019-06-21 20:44:05 +0200366 if (rc != 0) {
367 return BOOT_EFLASH;
368 }
369
David Vinczecea8b592019-10-29 16:09:51 +0100370 BOOT_WRITE_SZ(state) = boot_write_sz(state);
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000371
372 return 0;
373}
374
David Vincze060968d2019-05-23 01:13:14 +0200375/**
376 * Validate image hash/signature and security counter in a slot.
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000377 */
378static int
David Vinczecea8b592019-10-29 16:09:51 +0100379boot_image_check(struct boot_loader_state *state, struct image_header *hdr,
380 const struct flash_area *fap, struct boot_status *bs)
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000381{
382 static uint8_t tmpbuf[BOOT_TMPBUF_SZ];
David Vinczecea8b592019-10-29 16:09:51 +0100383 uint8_t image_index;
384
385#if (BOOT_IMAGE_NUMBER == 1)
386 (void)state;
387#endif
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000388
David Vincze401c7422019-06-21 20:44:05 +0200389 (void)bs;
390
David Vinczecea8b592019-10-29 16:09:51 +0100391 image_index = BOOT_CURR_IMG(state);
392
393 if (bootutil_img_validate(image_index, hdr, fap, tmpbuf,
394 BOOT_TMPBUF_SZ, NULL, 0, NULL)) {
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000395 return BOOT_EBADIMAGE;
396 }
David Vinczecea8b592019-10-29 16:09:51 +0100397
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000398 return 0;
399}
400
David Vincze401c7422019-06-21 20:44:05 +0200401/*
402 * Check that a memory area consists of a given value.
403 */
404static inline bool
405boot_data_is_set_to(uint8_t val, void *data, size_t len)
David Vincze39e78552018-10-10 17:10:01 +0200406{
407 uint8_t i;
David Vincze401c7422019-06-21 20:44:05 +0200408 uint8_t *p = (uint8_t *)data;
409 for (i = 0; i < len; i++) {
410 if (val != p[i]) {
411 return false;
David Vincze39e78552018-10-10 17:10:01 +0200412 }
413 }
David Vincze401c7422019-06-21 20:44:05 +0200414 return true;
David Vincze39e78552018-10-10 17:10:01 +0200415}
416
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000417static int
David Vinczecea8b592019-10-29 16:09:51 +0100418boot_check_header_erased(struct boot_loader_state *state, int slot)
David Vincze401c7422019-06-21 20:44:05 +0200419{
420 const struct flash_area *fap;
421 struct image_header *hdr;
422 uint8_t erased_val;
David Vinczecea8b592019-10-29 16:09:51 +0100423 int area_id;
David Vincze401c7422019-06-21 20:44:05 +0200424 int rc;
425
David Vinczecea8b592019-10-29 16:09:51 +0100426 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
427 rc = flash_area_open(area_id, &fap);
David Vincze401c7422019-06-21 20:44:05 +0200428 if (rc != 0) {
429 return -1;
430 }
431
432 erased_val = flash_area_erased_val(fap);
433 flash_area_close(fap);
434
David Vinczecea8b592019-10-29 16:09:51 +0100435 hdr = boot_img_hdr(state, slot);
David Vincze401c7422019-06-21 20:44:05 +0200436 if (!boot_data_is_set_to(erased_val, &hdr->ih_magic,
437 sizeof(hdr->ih_magic))) {
438 return -1;
439 }
440
441 return 0;
442}
443
David Vinczecea8b592019-10-29 16:09:51 +0100444/*
445 * Check that there is a valid image in a slot
446 *
447 * @returns
448 * 0 if image was succesfully validated
449 * 1 if no bootloable image was found
450 * -1 on any errors
451 */
David Vincze401c7422019-06-21 20:44:05 +0200452static int
David Vinczecea8b592019-10-29 16:09:51 +0100453boot_validate_slot(struct boot_loader_state *state, int slot,
454 struct boot_status *bs)
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000455{
456 const struct flash_area *fap;
457 struct image_header *hdr;
David Vinczecea8b592019-10-29 16:09:51 +0100458 int area_id;
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000459 int rc;
460
David Vinczecea8b592019-10-29 16:09:51 +0100461 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
462 rc = flash_area_open(area_id, &fap);
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000463 if (rc != 0) {
David Vinczecea8b592019-10-29 16:09:51 +0100464 return -1;
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000465 }
466
David Vinczecea8b592019-10-29 16:09:51 +0100467 hdr = boot_img_hdr(state, slot);
468 if ((boot_check_header_erased(state, slot) == 0) ||
David Vincze401c7422019-06-21 20:44:05 +0200469 (hdr->ih_flags & IMAGE_F_NON_BOOTABLE)) {
David Vincze8bdfc2d2019-03-18 15:49:23 +0100470 /* No bootable image in slot; continue booting from the primary slot. */
David Vinczecea8b592019-10-29 16:09:51 +0100471 rc = 1;
David Vincze401c7422019-06-21 20:44:05 +0200472 goto out;
David Vincze39e78552018-10-10 17:10:01 +0200473 }
474
David Vinczecea8b592019-10-29 16:09:51 +0100475 if ((!BOOT_IMG_HDR_IS_VALID(state, slot)) ||
476 (boot_image_check(state, hdr, fap, bs) != 0)) {
David Vincze401c7422019-06-21 20:44:05 +0200477 if (slot != BOOT_PRIMARY_SLOT) {
David Vinczecea8b592019-10-29 16:09:51 +0100478 flash_area_erase(fap, 0, fap->fa_size);
David Vincze8bdfc2d2019-03-18 15:49:23 +0100479 /* Image in the secondary slot is invalid. Erase the image and
480 * continue booting from the primary slot.
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000481 */
482 }
David Vinczecea8b592019-10-29 16:09:51 +0100483 BOOT_LOG_ERR("Image in the %s slot is not valid!",
484 (slot == BOOT_PRIMARY_SLOT) ? "primary" : "secondary");
David Vincze401c7422019-06-21 20:44:05 +0200485 rc = -1;
486 goto out;
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000487 }
488
David Vincze8bdfc2d2019-03-18 15:49:23 +0100489 /* Image in the secondary slot is valid. */
David Vincze401c7422019-06-21 20:44:05 +0200490 rc = 0;
491
492out:
493 flash_area_close(fap);
494 return rc;
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000495}
496
David Vincze060968d2019-05-23 01:13:14 +0200497/**
498 * Updates the stored security counter value with the image's security counter
499 * value which resides in the given slot if it's greater than the stored value.
500 *
David Vinczecea8b592019-10-29 16:09:51 +0100501 * @param image_index Index of the image to determine which security
502 * counter to update.
503 * @param slot Slot number of the image.
504 * @param hdr Pointer to the image header structure of the image
505 * that is currently stored in the given slot.
David Vincze060968d2019-05-23 01:13:14 +0200506 *
David Vinczecea8b592019-10-29 16:09:51 +0100507 * @return 0 on success; nonzero on failure.
David Vincze060968d2019-05-23 01:13:14 +0200508 */
509static int
David Vinczecea8b592019-10-29 16:09:51 +0100510boot_update_security_counter(uint8_t image_index, int slot,
511 struct image_header *hdr)
David Vincze060968d2019-05-23 01:13:14 +0200512{
513 const struct flash_area *fap = NULL;
514 uint32_t img_security_cnt;
515 int rc;
516
David Vinczecea8b592019-10-29 16:09:51 +0100517 rc = flash_area_open(flash_area_id_from_multi_image_slot(image_index, slot),
518 &fap);
David Vincze060968d2019-05-23 01:13:14 +0200519 if (rc != 0) {
520 rc = BOOT_EFLASH;
521 goto done;
522 }
523
524 rc = bootutil_get_img_security_cnt(hdr, fap, &img_security_cnt);
525 if (rc != 0) {
526 goto done;
527 }
528
David Vinczecea8b592019-10-29 16:09:51 +0100529 rc = boot_nv_security_counter_update(image_index, img_security_cnt);
David Vincze060968d2019-05-23 01:13:14 +0200530 if (rc != 0) {
531 goto done;
532 }
533
534done:
535 flash_area_close(fap);
536 return rc;
537}
538
Oliver Swedef9982442018-08-24 18:37:44 +0100539#if !defined(MCUBOOT_NO_SWAP) && !defined(MCUBOOT_OVERWRITE_ONLY)
540/*
541 * Compute the total size of the given image. Includes the size of
542 * the TLVs.
543 */
544static int
David Vinczecea8b592019-10-29 16:09:51 +0100545boot_read_image_size(struct boot_loader_state *state, int slot, uint32_t *size)
Oliver Swedef9982442018-08-24 18:37:44 +0100546{
547 const struct flash_area *fap = NULL;
David Vincze07706a42019-12-12 18:20:12 +0100548 struct image_tlv_info info;
David Vinczecea8b592019-10-29 16:09:51 +0100549 uint32_t off;
David Vincze61bd1e52019-10-24 16:47:31 +0200550 uint32_t protect_tlv_size;
Oliver Swedef9982442018-08-24 18:37:44 +0100551 int area_id;
552 int rc;
553
David Vinczecea8b592019-10-29 16:09:51 +0100554#if (BOOT_IMAGE_NUMBER == 1)
555 (void)state;
556#endif
557
558 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
Oliver Swedef9982442018-08-24 18:37:44 +0100559 rc = flash_area_open(area_id, &fap);
560 if (rc != 0) {
561 rc = BOOT_EFLASH;
562 goto done;
563 }
564
David Vincze07706a42019-12-12 18:20:12 +0100565 off = BOOT_TLV_OFF(boot_img_hdr(state, slot));
566
567 if (flash_area_read(fap, off, &info, sizeof(info))) {
568 rc = BOOT_EFLASH;
Oliver Swedef9982442018-08-24 18:37:44 +0100569 goto done;
570 }
David Vincze07706a42019-12-12 18:20:12 +0100571
David Vincze61bd1e52019-10-24 16:47:31 +0200572 protect_tlv_size = boot_img_hdr(state, slot)->ih_protect_tlv_size;
573 if (info.it_magic == IMAGE_TLV_PROT_INFO_MAGIC) {
574 if (protect_tlv_size != info.it_tlv_tot) {
575 rc = BOOT_EBADIMAGE;
576 goto done;
577 }
578
579 if (flash_area_read(fap, off + info.it_tlv_tot, &info, sizeof(info))) {
580 rc = BOOT_EFLASH;
581 goto done;
582 }
583 } else if (protect_tlv_size != 0) {
584 rc = BOOT_EBADIMAGE;
585 goto done;
586 }
587
David Vincze07706a42019-12-12 18:20:12 +0100588 if (info.it_magic != IMAGE_TLV_INFO_MAGIC) {
589 rc = BOOT_EBADIMAGE;
590 goto done;
591 }
592
David Vincze61bd1e52019-10-24 16:47:31 +0200593 *size = off + protect_tlv_size + info.it_tlv_tot;
Oliver Swedef9982442018-08-24 18:37:44 +0100594 rc = 0;
595
596done:
597 flash_area_close(fap);
598 return rc;
599}
600#endif /* !MCUBOOT_NO_SWAP && !MCUBOOT_OVERWRITE_ONLY */
601
602#if !defined(MCUBOOT_NO_SWAP) && !defined(MCUBOOT_RAM_LOADING)
Tamas Banf70ef8c2017-12-19 15:35:09 +0000603/**
Tamas Ban581034a2017-12-19 19:54:37 +0000604 * Determines where in flash the most recent boot status is stored. The boot
Tamas Banf70ef8c2017-12-19 15:35:09 +0000605 * status is necessary for completing a swap that was interrupted by a boot
606 * loader reset.
607 *
David Vincze401c7422019-06-21 20:44:05 +0200608 * @return A BOOT_STATUS_SOURCE_[...] code indicating where status should
609 * be read from.
Tamas Banf70ef8c2017-12-19 15:35:09 +0000610 */
611static int
David Vinczecea8b592019-10-29 16:09:51 +0100612boot_status_source(struct boot_loader_state *state)
Tamas Banf70ef8c2017-12-19 15:35:09 +0000613{
614 const struct boot_status_table *table;
615 struct boot_swap_state state_scratch;
David Vincze8bdfc2d2019-03-18 15:49:23 +0100616 struct boot_swap_state state_primary_slot;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000617 int rc;
David Vincze39e78552018-10-10 17:10:01 +0200618 size_t i;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000619 uint8_t source;
David Vinczecea8b592019-10-29 16:09:51 +0100620 uint8_t image_index;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000621
David Vinczecea8b592019-10-29 16:09:51 +0100622#if (BOOT_IMAGE_NUMBER == 1)
623 (void)state;
624#endif
625
626 image_index = BOOT_CURR_IMG(state);
627 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_PRIMARY(image_index),
628 &state_primary_slot);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000629 assert(rc == 0);
630
631 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SCRATCH, &state_scratch);
632 assert(rc == 0);
633
David Vincze401c7422019-06-21 20:44:05 +0200634 BOOT_LOG_SWAP_STATE("Primary image", &state_primary_slot);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000635 BOOT_LOG_SWAP_STATE("Scratch", &state_scratch);
636
637 for (i = 0; i < BOOT_STATUS_TABLES_COUNT; i++) {
638 table = &boot_status_tables[i];
639
David Vincze401c7422019-06-21 20:44:05 +0200640 if (boot_magic_compatible_check(table->bst_magic_primary_slot,
641 state_primary_slot.magic) &&
642 boot_magic_compatible_check(table->bst_magic_scratch,
643 state_scratch.magic) &&
David Vincze8bdfc2d2019-03-18 15:49:23 +0100644 (table->bst_copy_done_primary_slot == BOOT_FLAG_ANY ||
645 table->bst_copy_done_primary_slot == state_primary_slot.copy_done))
646 {
Tamas Banf70ef8c2017-12-19 15:35:09 +0000647 source = table->bst_status_source;
David Vincze7384ee72019-07-23 17:00:42 +0200648
649#if (BOOT_IMAGE_NUMBER > 1)
650 /* In case of multi-image boot it can happen that if boot status
651 * info is found on scratch area then it does not belong to the
652 * currently examined image.
653 */
654 if (source == BOOT_STATUS_SOURCE_SCRATCH &&
David Vinczecea8b592019-10-29 16:09:51 +0100655 state_scratch.image_num != BOOT_CURR_IMG(state)) {
David Vincze7384ee72019-07-23 17:00:42 +0200656 source = BOOT_STATUS_SOURCE_NONE;
657 }
658#endif
659
Tamas Banf70ef8c2017-12-19 15:35:09 +0000660 BOOT_LOG_INF("Boot source: %s",
661 source == BOOT_STATUS_SOURCE_NONE ? "none" :
662 source == BOOT_STATUS_SOURCE_SCRATCH ? "scratch" :
David Vincze8bdfc2d2019-03-18 15:49:23 +0100663 source == BOOT_STATUS_SOURCE_PRIMARY_SLOT ?
664 "primary slot" : "BUG; can't happen");
Tamas Banf70ef8c2017-12-19 15:35:09 +0000665 return source;
666 }
667 }
668
669 BOOT_LOG_INF("Boot source: none");
670 return BOOT_STATUS_SOURCE_NONE;
671}
672
David Vincze401c7422019-06-21 20:44:05 +0200673/*
David Vincze4af67832019-12-11 18:31:34 +0100674 * Slots are compatible when all sectors that store up to to size of the image
David Vincze401c7422019-06-21 20:44:05 +0200675 * round up to sector size, in both slot's are able to fit in the scratch
676 * area, and have sizes that are a multiple of each other (powers of two
677 * presumably!).
Tamas Banf70ef8c2017-12-19 15:35:09 +0000678 */
679static int
David Vinczecea8b592019-10-29 16:09:51 +0100680boot_slots_compatible(struct boot_loader_state *state)
Tamas Banf70ef8c2017-12-19 15:35:09 +0000681{
David Vincze401c7422019-06-21 20:44:05 +0200682 size_t num_sectors_primary;
683 size_t num_sectors_secondary;
684 size_t sz0, sz1;
685 size_t primary_slot_sz, secondary_slot_sz;
David Vincze4af67832019-12-11 18:31:34 +0100686#ifndef MCUBOOT_OVERWRITE_ONLY
David Vincze401c7422019-06-21 20:44:05 +0200687 size_t scratch_sz;
David Vincze4af67832019-12-11 18:31:34 +0100688#endif
David Vincze401c7422019-06-21 20:44:05 +0200689 size_t i, j;
690 int8_t smaller;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000691
David Vinczecea8b592019-10-29 16:09:51 +0100692 num_sectors_primary = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT);
693 num_sectors_secondary = boot_img_num_sectors(state, BOOT_SECONDARY_SLOT);
David Vincze401c7422019-06-21 20:44:05 +0200694 if ((num_sectors_primary > BOOT_MAX_IMG_SECTORS) ||
695 (num_sectors_secondary > BOOT_MAX_IMG_SECTORS)) {
David Vincze39e78552018-10-10 17:10:01 +0200696 BOOT_LOG_WRN("Cannot upgrade: more sectors than allowed");
Tamas Banf70ef8c2017-12-19 15:35:09 +0000697 return 0;
698 }
David Vincze39e78552018-10-10 17:10:01 +0200699
David Vincze4af67832019-12-11 18:31:34 +0100700#ifndef MCUBOOT_OVERWRITE_ONLY
David Vinczecea8b592019-10-29 16:09:51 +0100701 scratch_sz = boot_scratch_area_size(state);
David Vincze4af67832019-12-11 18:31:34 +0100702#endif
David Vincze401c7422019-06-21 20:44:05 +0200703
704 /*
705 * The following loop scans all sectors in a linear fashion, assuring that
706 * for each possible sector in each slot, it is able to fit in the other
707 * slot's sector or sectors. Slot's should be compatible as long as any
708 * number of a slot's sectors are able to fit into another, which only
709 * excludes cases where sector sizes are not a multiple of each other.
710 */
711 i = sz0 = primary_slot_sz = 0;
712 j = sz1 = secondary_slot_sz = 0;
713 smaller = 0;
714 while (i < num_sectors_primary || j < num_sectors_secondary) {
715 if (sz0 == sz1) {
David Vinczecea8b592019-10-29 16:09:51 +0100716 sz0 += boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i);
717 sz1 += boot_img_sector_size(state, BOOT_SECONDARY_SLOT, j);
David Vincze401c7422019-06-21 20:44:05 +0200718 i++;
719 j++;
720 } else if (sz0 < sz1) {
David Vinczecea8b592019-10-29 16:09:51 +0100721 sz0 += boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i);
David Vincze401c7422019-06-21 20:44:05 +0200722 /* Guarantee that multiple sectors of the secondary slot
723 * fit into the primary slot.
724 */
725 if (smaller == 2) {
726 BOOT_LOG_WRN("Cannot upgrade: slots have non-compatible"
727 " sectors");
728 return 0;
729 }
730 smaller = 1;
731 i++;
732 } else {
David Vinczecea8b592019-10-29 16:09:51 +0100733 sz1 += boot_img_sector_size(state, BOOT_SECONDARY_SLOT, j);
David Vincze401c7422019-06-21 20:44:05 +0200734 /* Guarantee that multiple sectors of the primary slot
735 * fit into the secondary slot.
736 */
737 if (smaller == 1) {
738 BOOT_LOG_WRN("Cannot upgrade: slots have non-compatible"
739 " sectors");
740 return 0;
741 }
742 smaller = 2;
743 j++;
744 }
David Vincze4af67832019-12-11 18:31:34 +0100745#ifndef MCUBOOT_OVERWRITE_ONLY
David Vincze401c7422019-06-21 20:44:05 +0200746 if (sz0 == sz1) {
747 primary_slot_sz += sz0;
748 secondary_slot_sz += sz1;
749 /* Scratch has to fit each swap operation to the size of the larger
750 * sector among the primary slot and the secondary slot.
751 */
752 if (sz0 > scratch_sz || sz1 > scratch_sz) {
753 BOOT_LOG_WRN("Cannot upgrade: not all sectors fit inside"
754 " scratch");
755 return 0;
756 }
757 smaller = sz0 = sz1 = 0;
758 }
David Vincze4af67832019-12-11 18:31:34 +0100759#endif
David Vincze39e78552018-10-10 17:10:01 +0200760 }
761
David Vincze401c7422019-06-21 20:44:05 +0200762 if ((i != num_sectors_primary) ||
763 (j != num_sectors_secondary) ||
764 (primary_slot_sz != secondary_slot_sz)) {
765 BOOT_LOG_WRN("Cannot upgrade: slots are not compatible");
766 return 0;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000767 }
768
769 return 1;
770}
771
Tamas Banf70ef8c2017-12-19 15:35:09 +0000772static uint32_t
773boot_status_internal_off(int idx, int state, int elem_sz)
774{
775 int idx_sz;
776
777 idx_sz = elem_sz * BOOT_STATUS_STATE_COUNT;
778
David Vincze39e78552018-10-10 17:10:01 +0200779 return (idx - BOOT_STATUS_IDX_0) * idx_sz +
780 (state - BOOT_STATUS_STATE_0) * elem_sz;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000781}
782
783/**
784 * Reads the status of a partially-completed swap, if any. This is necessary
785 * to recover in case the boot lodaer was reset in the middle of a swap
786 * operation.
787 */
788static int
David Vinczecea8b592019-10-29 16:09:51 +0100789boot_read_status_bytes(const struct flash_area *fap,
790 struct boot_loader_state *state, struct boot_status *bs)
Tamas Banf70ef8c2017-12-19 15:35:09 +0000791{
792 uint32_t off;
793 uint8_t status;
794 int max_entries;
795 int found;
David Vincze39e78552018-10-10 17:10:01 +0200796 int found_idx;
797 int invalid;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000798 int rc;
799 int i;
800
801 off = boot_status_off(fap);
David Vinczecea8b592019-10-29 16:09:51 +0100802 max_entries = boot_status_entries(BOOT_CURR_IMG(state), fap);
803 if (max_entries < 0) {
804 return BOOT_EBADARGS;
805 }
Tamas Banf70ef8c2017-12-19 15:35:09 +0000806
807 found = 0;
David Vincze39e78552018-10-10 17:10:01 +0200808 found_idx = 0;
809 invalid = 0;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000810 for (i = 0; i < max_entries; i++) {
David Vinczecea8b592019-10-29 16:09:51 +0100811 rc = flash_area_read_is_empty(fap, off + i * BOOT_WRITE_SZ(state),
David Vincze39e78552018-10-10 17:10:01 +0200812 &status, 1);
813 if (rc < 0) {
Tamas Banf70ef8c2017-12-19 15:35:09 +0000814 return BOOT_EFLASH;
815 }
816
David Vincze39e78552018-10-10 17:10:01 +0200817 if (rc == 1) {
818 if (found && !found_idx) {
819 found_idx = i;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000820 }
821 } else if (!found) {
822 found = 1;
David Vincze39e78552018-10-10 17:10:01 +0200823 } else if (found_idx) {
824 invalid = 1;
825 break;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000826 }
827 }
828
David Vincze39e78552018-10-10 17:10:01 +0200829 if (invalid) {
830 /* This means there was an error writing status on the last
831 * swap. Tell user and move on to validation!
832 */
833 BOOT_LOG_ERR("Detected inconsistent status!");
834
David Vincze8bdfc2d2019-03-18 15:49:23 +0100835#if !defined(MCUBOOT_VALIDATE_PRIMARY_SLOT)
836 /* With validation of the primary slot disabled, there is no way
837 * to be sure the swapped primary slot is OK, so abort!
David Vincze39e78552018-10-10 17:10:01 +0200838 */
839 assert(0);
840#endif
841 }
842
Tamas Banf70ef8c2017-12-19 15:35:09 +0000843 if (found) {
David Vincze39e78552018-10-10 17:10:01 +0200844 if (!found_idx) {
845 found_idx = i;
846 }
David Vincze39e78552018-10-10 17:10:01 +0200847 bs->idx = (found_idx / BOOT_STATUS_STATE_COUNT) + 1;
848 bs->state = (found_idx % BOOT_STATUS_STATE_COUNT) + 1;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000849 }
850
851 return 0;
852}
853
854/**
855 * Reads the boot status from the flash. The boot status contains
856 * the current state of an interrupted image copy operation. If the boot
857 * status is not present, or it indicates that previous copy finished,
858 * there is no operation in progress.
859 */
860static int
David Vinczecea8b592019-10-29 16:09:51 +0100861boot_read_status(struct boot_loader_state *state, struct boot_status *bs)
Tamas Banf70ef8c2017-12-19 15:35:09 +0000862{
863 const struct flash_area *fap;
David Vincze401c7422019-06-21 20:44:05 +0200864 uint32_t off;
David Vincze91b71ef2019-06-24 13:06:47 +0200865 uint8_t swap_info;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000866 int status_loc;
867 int area_id;
868 int rc;
869
David Vincze39e78552018-10-10 17:10:01 +0200870 memset(bs, 0, sizeof *bs);
871 bs->idx = BOOT_STATUS_IDX_0;
872 bs->state = BOOT_STATUS_STATE_0;
David Vincze401c7422019-06-21 20:44:05 +0200873 bs->swap_type = BOOT_SWAP_TYPE_NONE;
David Vincze39e78552018-10-10 17:10:01 +0200874
875#ifdef MCUBOOT_OVERWRITE_ONLY
876 /* Overwrite-only doesn't make use of the swap status area. */
877 return 0;
878#endif
Tamas Banf70ef8c2017-12-19 15:35:09 +0000879
David Vinczecea8b592019-10-29 16:09:51 +0100880 status_loc = boot_status_source(state);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000881 switch (status_loc) {
882 case BOOT_STATUS_SOURCE_NONE:
883 return 0;
884
885 case BOOT_STATUS_SOURCE_SCRATCH:
886 area_id = FLASH_AREA_IMAGE_SCRATCH;
887 break;
888
David Vincze8bdfc2d2019-03-18 15:49:23 +0100889 case BOOT_STATUS_SOURCE_PRIMARY_SLOT:
David Vinczecea8b592019-10-29 16:09:51 +0100890 area_id = FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state));
Tamas Banf70ef8c2017-12-19 15:35:09 +0000891 break;
892
893 default:
894 assert(0);
895 return BOOT_EBADARGS;
896 }
897
898 rc = flash_area_open(area_id, &fap);
899 if (rc != 0) {
900 return BOOT_EFLASH;
901 }
902
David Vinczecea8b592019-10-29 16:09:51 +0100903 rc = boot_read_status_bytes(fap, state, bs);
David Vincze401c7422019-06-21 20:44:05 +0200904 if (rc == 0) {
David Vincze91b71ef2019-06-24 13:06:47 +0200905 off = boot_swap_info_off(fap);
906 rc = flash_area_read_is_empty(fap, off, &swap_info, sizeof swap_info);
David Vincze401c7422019-06-21 20:44:05 +0200907 if (rc == 1) {
David Vincze91b71ef2019-06-24 13:06:47 +0200908 BOOT_SET_SWAP_INFO(swap_info, 0, BOOT_SWAP_TYPE_NONE);
David Vincze401c7422019-06-21 20:44:05 +0200909 rc = 0;
910 }
David Vincze91b71ef2019-06-24 13:06:47 +0200911
912 /* Extract the swap type info */
913 bs->swap_type = BOOT_GET_SWAP_TYPE(swap_info);
David Vincze401c7422019-06-21 20:44:05 +0200914 }
Tamas Banf70ef8c2017-12-19 15:35:09 +0000915
916 flash_area_close(fap);
David Vincze39e78552018-10-10 17:10:01 +0200917
Tamas Banf70ef8c2017-12-19 15:35:09 +0000918 return rc;
919}
920
921/**
922 * Writes the supplied boot status to the flash file system. The boot status
923 * contains the current state of an in-progress image copy operation.
924 *
925 * @param bs The boot status to write.
926 *
927 * @return 0 on success; nonzero on failure.
928 */
929int
David Vinczecea8b592019-10-29 16:09:51 +0100930boot_write_status(struct boot_loader_state *state, struct boot_status *bs)
Tamas Banf70ef8c2017-12-19 15:35:09 +0000931{
Tamas Ban581034a2017-12-19 19:54:37 +0000932 const struct flash_area *fap = NULL;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000933 uint32_t off;
934 int area_id;
935 int rc;
936 uint8_t buf[BOOT_MAX_ALIGN];
Raef Coles204c5b42019-09-05 09:18:47 +0100937 uint32_t align;
David Vincze39e78552018-10-10 17:10:01 +0200938 uint8_t erased_val;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000939
940 /* NOTE: The first sector copied (that is the last sector on slot) contains
David Vincze8bdfc2d2019-03-18 15:49:23 +0100941 * the trailer. Since in the last step the primary slot is erased, the
942 * first two status writes go to the scratch which will be copied to
943 * the primary slot!
Tamas Banf70ef8c2017-12-19 15:35:09 +0000944 */
945
946 if (bs->use_scratch) {
947 /* Write to scratch. */
948 area_id = FLASH_AREA_IMAGE_SCRATCH;
949 } else {
David Vincze8bdfc2d2019-03-18 15:49:23 +0100950 /* Write to the primary slot. */
David Vinczecea8b592019-10-29 16:09:51 +0100951 area_id = FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state));
Tamas Banf70ef8c2017-12-19 15:35:09 +0000952 }
953
954 rc = flash_area_open(area_id, &fap);
955 if (rc != 0) {
956 rc = BOOT_EFLASH;
957 goto done;
958 }
959
960 off = boot_status_off(fap) +
David Vinczecea8b592019-10-29 16:09:51 +0100961 boot_status_internal_off(bs->idx, bs->state, BOOT_WRITE_SZ(state));
Tamas Banc3828852018-02-01 12:24:16 +0000962 align = flash_area_align(fap);
David Vincze39e78552018-10-10 17:10:01 +0200963 erased_val = flash_area_erased_val(fap);
964 memset(buf, erased_val, BOOT_MAX_ALIGN);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000965 buf[0] = bs->state;
966
967 rc = flash_area_write(fap, off, buf, align);
968 if (rc != 0) {
969 rc = BOOT_EFLASH;
970 goto done;
971 }
972
973 rc = 0;
974
975done:
976 flash_area_close(fap);
977 return rc;
978}
979
Tamas Banf70ef8c2017-12-19 15:35:09 +0000980/**
981 * Determines which swap operation to perform, if any. If it is determined
David Vincze8bdfc2d2019-03-18 15:49:23 +0100982 * that a swap operation is required, the image in the secondary slot is checked
983 * for validity. If the image in the secondary slot is invalid, it is erased,
984 * and a swap type of "none" is indicated.
Tamas Banf70ef8c2017-12-19 15:35:09 +0000985 *
986 * @return The type of swap to perform (BOOT_SWAP_TYPE...)
987 */
988static int
David Vinczecea8b592019-10-29 16:09:51 +0100989boot_validated_swap_type(struct boot_loader_state *state,
990 struct boot_status *bs)
Tamas Banf70ef8c2017-12-19 15:35:09 +0000991{
992 int swap_type;
David Vinczecea8b592019-10-29 16:09:51 +0100993 int rc;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000994
David Vinczecea8b592019-10-29 16:09:51 +0100995 swap_type = boot_swap_type_multi(BOOT_CURR_IMG(state));
996 if (BOOT_IS_UPGRADE(swap_type)) {
David Vincze8bdfc2d2019-03-18 15:49:23 +0100997 /* Boot loader wants to switch to the secondary slot.
998 * Ensure image is valid.
999 */
David Vinczecea8b592019-10-29 16:09:51 +01001000 rc = boot_validate_slot(state, BOOT_SECONDARY_SLOT, bs);
1001 if (rc == 1) {
1002 swap_type = BOOT_SWAP_TYPE_NONE;
1003 } else if (rc != 0) {
Tamas Banf70ef8c2017-12-19 15:35:09 +00001004 swap_type = BOOT_SWAP_TYPE_FAIL;
1005 }
1006 }
1007
1008 return swap_type;
1009}
1010
1011/**
1012 * Calculates the number of sectors the scratch area can contain. A "last"
1013 * source sector is specified because images are copied backwards in flash
1014 * (final index to index number 0).
1015 *
1016 * @param last_sector_idx The index of the last source sector
1017 * (inclusive).
1018 * @param out_first_sector_idx The index of the first source sector
1019 * (inclusive) gets written here.
1020 *
1021 * @return The number of bytes comprised by the
1022 * [first-sector, last-sector] range.
1023 */
1024#ifndef MCUBOOT_OVERWRITE_ONLY
1025static uint32_t
David Vinczecea8b592019-10-29 16:09:51 +01001026boot_copy_sz(struct boot_loader_state *state, int last_sector_idx,
1027 int *out_first_sector_idx)
Tamas Banf70ef8c2017-12-19 15:35:09 +00001028{
1029 size_t scratch_sz;
1030 uint32_t new_sz;
1031 uint32_t sz;
1032 int i;
1033
1034 sz = 0;
1035
David Vinczecea8b592019-10-29 16:09:51 +01001036 scratch_sz = boot_scratch_area_size(state);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001037 for (i = last_sector_idx; i >= 0; i--) {
David Vinczecea8b592019-10-29 16:09:51 +01001038 new_sz = sz + boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i);
David Vincze401c7422019-06-21 20:44:05 +02001039 /*
1040 * The secondary slot is not being checked here, because
1041 * `boot_slots_compatible` already provides assurance that the copy size
1042 * will be compatible with the primary slot and scratch.
1043 */
Tamas Banf70ef8c2017-12-19 15:35:09 +00001044 if (new_sz > scratch_sz) {
1045 break;
1046 }
1047 sz = new_sz;
1048 }
1049
1050 /* i currently refers to a sector that doesn't fit or it is -1 because all
1051 * sectors have been processed. In both cases, exclude sector i.
1052 */
1053 *out_first_sector_idx = i + 1;
1054 return sz;
1055}
1056#endif /* !MCUBOOT_OVERWRITE_ONLY */
1057
1058/**
David Vinczef7641fa2018-09-04 18:29:46 +02001059 * Erases a region of flash.
1060 *
David Vincze401c7422019-06-21 20:44:05 +02001061 * @param flash_area The flash_area containing the region to erase.
David Vinczef7641fa2018-09-04 18:29:46 +02001062 * @param off The offset within the flash area to start the
1063 * erase.
1064 * @param sz The number of bytes to erase.
1065 *
1066 * @return 0 on success; nonzero on failure.
1067 */
David Vincze401c7422019-06-21 20:44:05 +02001068static inline int
David Vinczecea8b592019-10-29 16:09:51 +01001069boot_erase_region(const struct flash_area *fap, uint32_t off, uint32_t sz)
David Vinczef7641fa2018-09-04 18:29:46 +02001070{
David Vincze401c7422019-06-21 20:44:05 +02001071 return flash_area_erase(fap, off, sz);
David Vinczef7641fa2018-09-04 18:29:46 +02001072}
1073
1074/**
Tamas Banf70ef8c2017-12-19 15:35:09 +00001075 * Copies the contents of one flash region to another. You must erase the
1076 * destination region prior to calling this function.
1077 *
1078 * @param flash_area_id_src The ID of the source flash area.
1079 * @param flash_area_id_dst The ID of the destination flash area.
1080 * @param off_src The offset within the source flash area to
1081 * copy from.
1082 * @param off_dst The offset within the destination flash area to
1083 * copy to.
1084 * @param sz The number of bytes to copy.
1085 *
1086 * @return 0 on success; nonzero on failure.
1087 */
1088static int
David Vinczecea8b592019-10-29 16:09:51 +01001089boot_copy_region(struct boot_loader_state *state,
1090 const struct flash_area *fap_src,
David Vincze401c7422019-06-21 20:44:05 +02001091 const struct flash_area *fap_dst,
Tamas Banf70ef8c2017-12-19 15:35:09 +00001092 uint32_t off_src, uint32_t off_dst, uint32_t sz)
1093{
Tamas Banf70ef8c2017-12-19 15:35:09 +00001094 uint32_t bytes_copied;
1095 int chunk_sz;
1096 int rc;
1097
1098 static uint8_t buf[1024];
1099
David Vinczecea8b592019-10-29 16:09:51 +01001100 (void)state;
1101
Tamas Banf70ef8c2017-12-19 15:35:09 +00001102 bytes_copied = 0;
1103 while (bytes_copied < sz) {
Tamas Ban581034a2017-12-19 19:54:37 +00001104 if (sz - bytes_copied > sizeof(buf)) {
1105 chunk_sz = sizeof(buf);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001106 } else {
1107 chunk_sz = sz - bytes_copied;
1108 }
1109
1110 rc = flash_area_read(fap_src, off_src + bytes_copied, buf, chunk_sz);
1111 if (rc != 0) {
David Vincze401c7422019-06-21 20:44:05 +02001112 return BOOT_EFLASH;
Tamas Banf70ef8c2017-12-19 15:35:09 +00001113 }
1114
1115 rc = flash_area_write(fap_dst, off_dst + bytes_copied, buf, chunk_sz);
1116 if (rc != 0) {
David Vincze401c7422019-06-21 20:44:05 +02001117 return BOOT_EFLASH;
Tamas Banf70ef8c2017-12-19 15:35:09 +00001118 }
1119
1120 bytes_copied += chunk_sz;
1121 }
1122
David Vincze401c7422019-06-21 20:44:05 +02001123 return 0;
Tamas Banf70ef8c2017-12-19 15:35:09 +00001124}
1125
1126#ifndef MCUBOOT_OVERWRITE_ONLY
1127static inline int
David Vinczecea8b592019-10-29 16:09:51 +01001128boot_status_init(const struct boot_loader_state *state,
1129 const struct flash_area *fap,
1130 const struct boot_status *bs)
Tamas Banf70ef8c2017-12-19 15:35:09 +00001131{
Tamas Banf70ef8c2017-12-19 15:35:09 +00001132 struct boot_swap_state swap_state;
David Vinczecea8b592019-10-29 16:09:51 +01001133 uint8_t image_index;
Tamas Banf70ef8c2017-12-19 15:35:09 +00001134 int rc;
1135
David Vinczecea8b592019-10-29 16:09:51 +01001136#if (BOOT_IMAGE_NUMBER == 1)
1137 (void)state;
1138#endif
1139
1140 image_index = BOOT_CURR_IMG(state);
1141
David Vincze401c7422019-06-21 20:44:05 +02001142 BOOT_LOG_DBG("initializing status; fa_id=%d", fap->fa_id);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001143
David Vinczecea8b592019-10-29 16:09:51 +01001144 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SECONDARY(image_index),
1145 &swap_state);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001146 assert(rc == 0);
1147
David Vincze401c7422019-06-21 20:44:05 +02001148 if (bs->swap_type != BOOT_SWAP_TYPE_NONE) {
David Vinczecea8b592019-10-29 16:09:51 +01001149 rc = boot_write_swap_info(fap, bs->swap_type, image_index);
David Vincze401c7422019-06-21 20:44:05 +02001150 assert(rc == 0);
1151 }
1152
Tamas Banf70ef8c2017-12-19 15:35:09 +00001153 if (swap_state.image_ok == BOOT_FLAG_SET) {
1154 rc = boot_write_image_ok(fap);
1155 assert(rc == 0);
1156 }
1157
1158 rc = boot_write_swap_size(fap, bs->swap_size);
1159 assert(rc == 0);
1160
1161 rc = boot_write_magic(fap);
1162 assert(rc == 0);
1163
Tamas Banf70ef8c2017-12-19 15:35:09 +00001164 return 0;
1165}
David Vinczef7641fa2018-09-04 18:29:46 +02001166
1167static int
David Vinczecea8b592019-10-29 16:09:51 +01001168boot_erase_trailer_sectors(const struct boot_loader_state *state,
1169 const struct flash_area *fap)
David Vinczef7641fa2018-09-04 18:29:46 +02001170{
1171 uint8_t slot;
David Vincze401c7422019-06-21 20:44:05 +02001172 uint32_t sector;
1173 uint32_t trailer_sz;
1174 uint32_t total_sz;
1175 uint32_t off;
1176 uint32_t sz;
David Vinczebb207982019-08-21 15:13:04 +02001177 int fa_id_primary;
1178 int fa_id_secondary;
David Vinczecea8b592019-10-29 16:09:51 +01001179 uint8_t image_index;
David Vinczef7641fa2018-09-04 18:29:46 +02001180 int rc;
1181
David Vincze401c7422019-06-21 20:44:05 +02001182 BOOT_LOG_DBG("erasing trailer; fa_id=%d", fap->fa_id);
1183
David Vinczecea8b592019-10-29 16:09:51 +01001184 image_index = BOOT_CURR_IMG(state);
1185 fa_id_primary = flash_area_id_from_multi_image_slot(image_index,
1186 BOOT_PRIMARY_SLOT);
1187 fa_id_secondary = flash_area_id_from_multi_image_slot(image_index,
1188 BOOT_SECONDARY_SLOT);
David Vinczebb207982019-08-21 15:13:04 +02001189
1190 if (fap->fa_id == fa_id_primary) {
David Vincze8bdfc2d2019-03-18 15:49:23 +01001191 slot = BOOT_PRIMARY_SLOT;
David Vinczebb207982019-08-21 15:13:04 +02001192 } else if (fap->fa_id == fa_id_secondary) {
David Vincze8bdfc2d2019-03-18 15:49:23 +01001193 slot = BOOT_SECONDARY_SLOT;
David Vinczebb207982019-08-21 15:13:04 +02001194 } else {
David Vinczef7641fa2018-09-04 18:29:46 +02001195 return BOOT_EFLASH;
1196 }
1197
David Vincze401c7422019-06-21 20:44:05 +02001198 /* delete starting from last sector and moving to beginning */
David Vinczecea8b592019-10-29 16:09:51 +01001199 sector = boot_img_num_sectors(state, slot) - 1;
1200 trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(state));
David Vincze401c7422019-06-21 20:44:05 +02001201 total_sz = 0;
1202 do {
David Vinczecea8b592019-10-29 16:09:51 +01001203 sz = boot_img_sector_size(state, slot, sector);
1204 off = boot_img_sector_off(state, slot, sector);
1205 rc = boot_erase_region(fap, off, sz);
David Vincze401c7422019-06-21 20:44:05 +02001206 assert(rc == 0);
1207
1208 sector--;
1209 total_sz += sz;
1210 } while (total_sz < trailer_sz);
David Vinczef7641fa2018-09-04 18:29:46 +02001211
1212 return rc;
1213}
Tamas Banf70ef8c2017-12-19 15:35:09 +00001214
Tamas Banf70ef8c2017-12-19 15:35:09 +00001215/**
1216 * Swaps the contents of two flash regions within the two image slots.
1217 *
1218 * @param idx The index of the first sector in the range of
1219 * sectors being swapped.
1220 * @param sz The number of bytes to swap.
1221 * @param bs The current boot status. This struct gets
1222 * updated according to the outcome.
1223 *
1224 * @return 0 on success; nonzero on failure.
1225 */
Tamas Banf70ef8c2017-12-19 15:35:09 +00001226static void
David Vinczecea8b592019-10-29 16:09:51 +01001227boot_swap_sectors(int idx, uint32_t sz, struct boot_loader_state *state,
1228 struct boot_status *bs)
Tamas Banf70ef8c2017-12-19 15:35:09 +00001229{
David Vincze401c7422019-06-21 20:44:05 +02001230 const struct flash_area *fap_primary_slot;
1231 const struct flash_area *fap_secondary_slot;
1232 const struct flash_area *fap_scratch;
Tamas Banf70ef8c2017-12-19 15:35:09 +00001233 uint32_t copy_sz;
1234 uint32_t trailer_sz;
1235 uint32_t img_off;
1236 uint32_t scratch_trailer_off;
1237 struct boot_swap_state swap_state;
1238 size_t last_sector;
David Vincze401c7422019-06-21 20:44:05 +02001239 bool erase_scratch;
David Vinczecea8b592019-10-29 16:09:51 +01001240 uint8_t image_index;
Tamas Banf70ef8c2017-12-19 15:35:09 +00001241 int rc;
1242
1243 /* Calculate offset from start of image area. */
David Vinczecea8b592019-10-29 16:09:51 +01001244 img_off = boot_img_sector_off(state, BOOT_PRIMARY_SLOT, idx);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001245
1246 copy_sz = sz;
David Vinczecea8b592019-10-29 16:09:51 +01001247 trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(state));
Tamas Banf70ef8c2017-12-19 15:35:09 +00001248
David Vincze401c7422019-06-21 20:44:05 +02001249 /* sz in this function is always sized on a multiple of the sector size.
1250 * The check against the start offset of the last sector
Tamas Banf70ef8c2017-12-19 15:35:09 +00001251 * is to determine if we're swapping the last sector. The last sector
1252 * needs special handling because it's where the trailer lives. If we're
1253 * copying it, we need to use scratch to write the trailer temporarily.
1254 *
1255 * NOTE: `use_scratch` is a temporary flag (never written to flash) which
1256 * controls if special handling is needed (swapping last sector).
1257 */
David Vinczecea8b592019-10-29 16:09:51 +01001258 last_sector = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT) - 1;
David Vincze7384ee72019-07-23 17:00:42 +02001259 if ((img_off + sz) >
David Vinczecea8b592019-10-29 16:09:51 +01001260 boot_img_sector_off(state, BOOT_PRIMARY_SLOT, last_sector)) {
Tamas Banf70ef8c2017-12-19 15:35:09 +00001261 copy_sz -= trailer_sz;
1262 }
1263
David Vincze39e78552018-10-10 17:10:01 +02001264 bs->use_scratch = (bs->idx == BOOT_STATUS_IDX_0 && copy_sz != sz);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001265
David Vinczecea8b592019-10-29 16:09:51 +01001266 image_index = BOOT_CURR_IMG(state);
1267
1268 rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index),
1269 &fap_primary_slot);
David Vincze401c7422019-06-21 20:44:05 +02001270 assert (rc == 0);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001271
David Vinczecea8b592019-10-29 16:09:51 +01001272 rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY(image_index),
1273 &fap_secondary_slot);
David Vincze401c7422019-06-21 20:44:05 +02001274 assert (rc == 0);
1275
1276 rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH, &fap_scratch);
1277 assert (rc == 0);
1278
1279 if (bs->state == BOOT_STATUS_STATE_0) {
1280 BOOT_LOG_DBG("erasing scratch area");
David Vinczecea8b592019-10-29 16:09:51 +01001281 rc = boot_erase_region(fap_scratch, 0, fap_scratch->fa_size);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001282 assert(rc == 0);
1283
David Vincze39e78552018-10-10 17:10:01 +02001284 if (bs->idx == BOOT_STATUS_IDX_0) {
David Vincze401c7422019-06-21 20:44:05 +02001285 /* Write a trailer to the scratch area, even if we don't need the
1286 * scratch area for status. We need a temporary place to store the
1287 * `swap-type` while we erase the primary trailer.
1288 */
David Vinczecea8b592019-10-29 16:09:51 +01001289 rc = boot_status_init(state, fap_scratch, bs);
David Vincze401c7422019-06-21 20:44:05 +02001290 assert(rc == 0);
1291
1292 if (!bs->use_scratch) {
1293 /* Prepare the primary status area... here it is known that the
1294 * last sector is not being used by the image data so it's safe
1295 * to erase.
Tamas Banf70ef8c2017-12-19 15:35:09 +00001296 */
David Vinczecea8b592019-10-29 16:09:51 +01001297 rc = boot_erase_trailer_sectors(state, fap_primary_slot);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001298 assert(rc == 0);
1299
David Vinczecea8b592019-10-29 16:09:51 +01001300 rc = boot_status_init(state, fap_primary_slot, bs);
David Vincze401c7422019-06-21 20:44:05 +02001301 assert(rc == 0);
1302
1303 /* Erase the temporary trailer from the scratch area. */
David Vinczecea8b592019-10-29 16:09:51 +01001304 rc = boot_erase_region(fap_scratch, 0, fap_scratch->fa_size);
David Vincze401c7422019-06-21 20:44:05 +02001305 assert(rc == 0);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001306 }
1307 }
1308
David Vinczecea8b592019-10-29 16:09:51 +01001309 rc = boot_copy_region(state, fap_secondary_slot, fap_scratch,
David Vincze401c7422019-06-21 20:44:05 +02001310 img_off, 0, copy_sz);
1311 assert(rc == 0);
1312
David Vinczecea8b592019-10-29 16:09:51 +01001313 rc = boot_write_status(state, bs);
David Vincze39e78552018-10-10 17:10:01 +02001314 bs->state = BOOT_STATUS_STATE_1;
David Vincze39e78552018-10-10 17:10:01 +02001315 BOOT_STATUS_ASSERT(rc == 0);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001316 }
1317
David Vincze39e78552018-10-10 17:10:01 +02001318 if (bs->state == BOOT_STATUS_STATE_1) {
David Vinczecea8b592019-10-29 16:09:51 +01001319 rc = boot_erase_region(fap_secondary_slot, img_off, sz);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001320 assert(rc == 0);
1321
David Vinczecea8b592019-10-29 16:09:51 +01001322 rc = boot_copy_region(state, fap_primary_slot, fap_secondary_slot,
Tamas Banf70ef8c2017-12-19 15:35:09 +00001323 img_off, img_off, copy_sz);
1324 assert(rc == 0);
1325
David Vincze39e78552018-10-10 17:10:01 +02001326 if (bs->idx == BOOT_STATUS_IDX_0 && !bs->use_scratch) {
Tamas Banf70ef8c2017-12-19 15:35:09 +00001327 /* If not all sectors of the slot are being swapped,
David Vincze8bdfc2d2019-03-18 15:49:23 +01001328 * guarantee here that only the primary slot will have the state.
Tamas Banf70ef8c2017-12-19 15:35:09 +00001329 */
David Vinczecea8b592019-10-29 16:09:51 +01001330 rc = boot_erase_trailer_sectors(state, fap_secondary_slot);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001331 assert(rc == 0);
1332 }
1333
David Vinczecea8b592019-10-29 16:09:51 +01001334 rc = boot_write_status(state, bs);
David Vincze39e78552018-10-10 17:10:01 +02001335 bs->state = BOOT_STATUS_STATE_2;
David Vincze39e78552018-10-10 17:10:01 +02001336 BOOT_STATUS_ASSERT(rc == 0);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001337 }
1338
David Vincze39e78552018-10-10 17:10:01 +02001339 if (bs->state == BOOT_STATUS_STATE_2) {
David Vinczecea8b592019-10-29 16:09:51 +01001340 rc = boot_erase_region(fap_primary_slot, img_off, sz);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001341 assert(rc == 0);
1342
David Vincze401c7422019-06-21 20:44:05 +02001343 /* NOTE: If this is the final sector, we exclude the image trailer from
1344 * this copy (copy_sz was truncated earlier).
1345 */
David Vinczecea8b592019-10-29 16:09:51 +01001346 rc = boot_copy_region(state, fap_scratch, fap_primary_slot,
Tamas Banf70ef8c2017-12-19 15:35:09 +00001347 0, img_off, copy_sz);
1348 assert(rc == 0);
1349
1350 if (bs->use_scratch) {
David Vincze401c7422019-06-21 20:44:05 +02001351 scratch_trailer_off = boot_status_off(fap_scratch);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001352
1353 /* copy current status that is being maintained in scratch */
David Vinczecea8b592019-10-29 16:09:51 +01001354 rc = boot_copy_region(state, fap_scratch, fap_primary_slot,
David Vincze401c7422019-06-21 20:44:05 +02001355 scratch_trailer_off, img_off + copy_sz,
David Vinczecea8b592019-10-29 16:09:51 +01001356 (BOOT_STATUS_STATE_COUNT - 1) * BOOT_WRITE_SZ(state));
David Vincze39e78552018-10-10 17:10:01 +02001357 BOOT_STATUS_ASSERT(rc == 0);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001358
1359 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SCRATCH,
1360 &swap_state);
1361 assert(rc == 0);
1362
1363 if (swap_state.image_ok == BOOT_FLAG_SET) {
David Vincze401c7422019-06-21 20:44:05 +02001364 rc = boot_write_image_ok(fap_primary_slot);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001365 assert(rc == 0);
1366 }
1367
David Vincze401c7422019-06-21 20:44:05 +02001368 if (swap_state.swap_type != BOOT_SWAP_TYPE_NONE) {
David Vincze91b71ef2019-06-24 13:06:47 +02001369 rc = boot_write_swap_info(fap_primary_slot,
1370 swap_state.swap_type,
David Vinczecea8b592019-10-29 16:09:51 +01001371 image_index);
David Vincze401c7422019-06-21 20:44:05 +02001372 assert(rc == 0);
1373 }
1374
1375 rc = boot_write_swap_size(fap_primary_slot, bs->swap_size);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001376 assert(rc == 0);
1377
David Vincze401c7422019-06-21 20:44:05 +02001378 rc = boot_write_magic(fap_primary_slot);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001379 assert(rc == 0);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001380 }
1381
David Vincze401c7422019-06-21 20:44:05 +02001382 /* If we wrote a trailer to the scratch area, erase it after we persist
1383 * a trailer to the primary slot. We do this to prevent mcuboot from
1384 * reading a stale status from the scratch area in case of immediate
1385 * reset.
1386 */
1387 erase_scratch = bs->use_scratch;
1388 bs->use_scratch = 0;
1389
David Vinczecea8b592019-10-29 16:09:51 +01001390 rc = boot_write_status(state, bs);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001391 bs->idx++;
David Vincze39e78552018-10-10 17:10:01 +02001392 bs->state = BOOT_STATUS_STATE_0;
David Vincze39e78552018-10-10 17:10:01 +02001393 BOOT_STATUS_ASSERT(rc == 0);
David Vincze401c7422019-06-21 20:44:05 +02001394
1395 if (erase_scratch) {
David Vinczecea8b592019-10-29 16:09:51 +01001396 rc = boot_erase_region(fap_scratch, 0, sz);
David Vincze401c7422019-06-21 20:44:05 +02001397 assert(rc == 0);
1398 }
Tamas Banf70ef8c2017-12-19 15:35:09 +00001399 }
David Vincze401c7422019-06-21 20:44:05 +02001400
1401 flash_area_close(fap_primary_slot);
1402 flash_area_close(fap_secondary_slot);
1403 flash_area_close(fap_scratch);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001404}
1405#endif /* !MCUBOOT_OVERWRITE_ONLY */
1406
1407/**
David Vincze401c7422019-06-21 20:44:05 +02001408 * Overwrite primary slot with the image contained in the secondary slot.
1409 * If a prior copy operation was interrupted by a system reset, this function
1410 * redos the copy.
Tamas Banf70ef8c2017-12-19 15:35:09 +00001411 *
1412 * @param bs The current boot status. This function reads
1413 * this struct to determine if it is resuming
1414 * an interrupted swap operation. This
1415 * function writes the updated status to this
1416 * function on return.
1417 *
1418 * @return 0 on success; nonzero on failure.
1419 */
1420#ifdef MCUBOOT_OVERWRITE_ONLY
1421static int
David Vinczecea8b592019-10-29 16:09:51 +01001422boot_copy_image(struct boot_loader_state *state, struct boot_status *bs)
Tamas Banf70ef8c2017-12-19 15:35:09 +00001423{
1424 size_t sect_count;
1425 size_t sect;
1426 int rc;
David Vinczecea8b592019-10-29 16:09:51 +01001427 size_t size;
Tamas Banf70ef8c2017-12-19 15:35:09 +00001428 size_t this_size;
David Vincze39e78552018-10-10 17:10:01 +02001429 size_t last_sector;
David Vincze401c7422019-06-21 20:44:05 +02001430 const struct flash_area *fap_primary_slot;
1431 const struct flash_area *fap_secondary_slot;
David Vinczecea8b592019-10-29 16:09:51 +01001432 uint8_t image_index;
David Vincze39e78552018-10-10 17:10:01 +02001433
1434 (void)bs;
Tamas Banf70ef8c2017-12-19 15:35:09 +00001435
David Vincze8bdfc2d2019-03-18 15:49:23 +01001436 BOOT_LOG_INF("Image upgrade secondary slot -> primary slot");
1437 BOOT_LOG_INF("Erasing the primary slot");
Tamas Banf70ef8c2017-12-19 15:35:09 +00001438
David Vinczecea8b592019-10-29 16:09:51 +01001439 image_index = BOOT_CURR_IMG(state);
1440
1441 rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index),
1442 &fap_primary_slot);
David Vincze401c7422019-06-21 20:44:05 +02001443 assert (rc == 0);
1444
David Vinczecea8b592019-10-29 16:09:51 +01001445 rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY(image_index),
1446 &fap_secondary_slot);
David Vincze401c7422019-06-21 20:44:05 +02001447 assert (rc == 0);
1448
David Vinczecea8b592019-10-29 16:09:51 +01001449 sect_count = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT);
1450 for (sect = 0, size = 0; sect < sect_count; sect++) {
1451 this_size = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, sect);
1452 rc = boot_erase_region(fap_primary_slot, size, this_size);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001453 assert(rc == 0);
1454
1455 size += this_size;
1456 }
1457
David Vincze8bdfc2d2019-03-18 15:49:23 +01001458 BOOT_LOG_INF("Copying the secondary slot to the primary slot: 0x%zx bytes",
1459 size);
David Vinczecea8b592019-10-29 16:09:51 +01001460 rc = boot_copy_region(state, fap_secondary_slot, fap_primary_slot,
1461 0, 0, size);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001462
David Vincze060968d2019-05-23 01:13:14 +02001463 /* Update the stored security counter with the new image's security counter
David Vincze8bdfc2d2019-03-18 15:49:23 +01001464 * value. Both slots hold the new image at this point, but the secondary
1465 * slot's image header must be passed because the read image headers in the
1466 * boot_data structure have not been updated yet.
David Vincze060968d2019-05-23 01:13:14 +02001467 */
David Vinczecea8b592019-10-29 16:09:51 +01001468 rc = boot_update_security_counter(BOOT_CURR_IMG(state), BOOT_PRIMARY_SLOT,
1469 boot_img_hdr(state, BOOT_SECONDARY_SLOT));
David Vincze060968d2019-05-23 01:13:14 +02001470 if (rc != 0) {
1471 BOOT_LOG_ERR("Security counter update failed after image upgrade.");
1472 return rc;
1473 }
1474
David Vincze39e78552018-10-10 17:10:01 +02001475 /*
1476 * Erases header and trailer. The trailer is erased because when a new
1477 * image is written without a trailer as is the case when using newt, the
1478 * trailer that was left might trigger a new upgrade.
1479 */
David Vincze401c7422019-06-21 20:44:05 +02001480 BOOT_LOG_DBG("erasing secondary header");
David Vinczecea8b592019-10-29 16:09:51 +01001481 rc = boot_erase_region(fap_secondary_slot,
1482 boot_img_sector_off(state, BOOT_SECONDARY_SLOT, 0),
1483 boot_img_sector_size(state, BOOT_SECONDARY_SLOT, 0));
Tamas Banf70ef8c2017-12-19 15:35:09 +00001484 assert(rc == 0);
David Vinczecea8b592019-10-29 16:09:51 +01001485 last_sector = boot_img_num_sectors(state, BOOT_SECONDARY_SLOT) - 1;
David Vincze401c7422019-06-21 20:44:05 +02001486 BOOT_LOG_DBG("erasing secondary trailer");
David Vinczecea8b592019-10-29 16:09:51 +01001487 rc = boot_erase_region(fap_secondary_slot,
1488 boot_img_sector_off(state, BOOT_SECONDARY_SLOT,
1489 last_sector),
1490 boot_img_sector_size(state, BOOT_SECONDARY_SLOT,
1491 last_sector));
David Vincze39e78552018-10-10 17:10:01 +02001492 assert(rc == 0);
1493
David Vincze401c7422019-06-21 20:44:05 +02001494 flash_area_close(fap_primary_slot);
1495 flash_area_close(fap_secondary_slot);
1496
David Vincze8bdfc2d2019-03-18 15:49:23 +01001497 /* TODO: Perhaps verify the primary slot's signature again? */
Tamas Banf70ef8c2017-12-19 15:35:09 +00001498
1499 return 0;
1500}
1501#else
David Vincze401c7422019-06-21 20:44:05 +02001502/**
1503 * Swaps the two images in flash. If a prior copy operation was interrupted
1504 * by a system reset, this function completes that operation.
1505 *
1506 * @param bs The current boot status. This function reads
1507 * this struct to determine if it is resuming
1508 * an interrupted swap operation. This
1509 * function writes the updated status to this
1510 * function on return.
1511 *
1512 * @return 0 on success; nonzero on failure.
1513 */
Tamas Banf70ef8c2017-12-19 15:35:09 +00001514static int
David Vinczecea8b592019-10-29 16:09:51 +01001515boot_swap_image(struct boot_loader_state *state, struct boot_status *bs)
Tamas Banf70ef8c2017-12-19 15:35:09 +00001516{
1517 uint32_t sz;
1518 int first_sector_idx;
1519 int last_sector_idx;
David Vincze401c7422019-06-21 20:44:05 +02001520 int last_idx_secondary_slot;
David Vincze39e78552018-10-10 17:10:01 +02001521 uint32_t swap_idx;
Tamas Banf70ef8c2017-12-19 15:35:09 +00001522 struct image_header *hdr;
1523 uint32_t size;
1524 uint32_t copy_size;
David Vincze401c7422019-06-21 20:44:05 +02001525 uint32_t primary_slot_size;
1526 uint32_t secondary_slot_size;
David Vinczecea8b592019-10-29 16:09:51 +01001527 uint8_t image_index;
Tamas Banf70ef8c2017-12-19 15:35:09 +00001528 int rc;
1529
1530 /* FIXME: just do this if asked by user? */
1531
1532 size = copy_size = 0;
David Vinczecea8b592019-10-29 16:09:51 +01001533 image_index = BOOT_CURR_IMG(state);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001534
David Vincze39e78552018-10-10 17:10:01 +02001535 if (bs->idx == BOOT_STATUS_IDX_0 && bs->state == BOOT_STATUS_STATE_0) {
Tamas Banf70ef8c2017-12-19 15:35:09 +00001536 /*
1537 * No swap ever happened, so need to find the largest image which
1538 * will be used to determine the amount of sectors to swap.
1539 */
David Vinczecea8b592019-10-29 16:09:51 +01001540 hdr = boot_img_hdr(state, BOOT_PRIMARY_SLOT);
1541 if (hdr->ih_magic == IMAGE_MAGIC) {
1542 rc = boot_read_image_size(state, BOOT_PRIMARY_SLOT, &copy_size);
1543 assert(rc == 0);
1544 }
Tamas Banf70ef8c2017-12-19 15:35:09 +00001545
David Vinczecea8b592019-10-29 16:09:51 +01001546 hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT);
1547 if (hdr->ih_magic == IMAGE_MAGIC) {
1548 rc = boot_read_image_size(state, BOOT_SECONDARY_SLOT, &size);
1549 assert(rc == 0);
1550 }
Tamas Banf70ef8c2017-12-19 15:35:09 +00001551
1552 if (size > copy_size) {
1553 copy_size = size;
1554 }
1555
1556 bs->swap_size = copy_size;
1557 } else {
1558 /*
1559 * If a swap was under way, the swap_size should already be present
1560 * in the trailer...
1561 */
David Vinczecea8b592019-10-29 16:09:51 +01001562 rc = boot_read_swap_size(image_index, &bs->swap_size);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001563 assert(rc == 0);
1564
1565 copy_size = bs->swap_size;
1566 }
1567
David Vincze401c7422019-06-21 20:44:05 +02001568 primary_slot_size = 0;
1569 secondary_slot_size = 0;
Tamas Banf70ef8c2017-12-19 15:35:09 +00001570 last_sector_idx = 0;
David Vincze401c7422019-06-21 20:44:05 +02001571 last_idx_secondary_slot = 0;
1572
1573 /*
1574 * Knowing the size of the largest image between both slots, here we
1575 * find what is the last sector in the primary slot that needs swapping.
1576 * Since we already know that both slots are compatible, the secondary
1577 * slot's last sector is not really required after this check is finished.
1578 */
Tamas Banf70ef8c2017-12-19 15:35:09 +00001579 while (1) {
David Vincze401c7422019-06-21 20:44:05 +02001580 if ((primary_slot_size < copy_size) ||
1581 (primary_slot_size < secondary_slot_size)) {
David Vinczecea8b592019-10-29 16:09:51 +01001582 primary_slot_size += boot_img_sector_size(state,
David Vincze401c7422019-06-21 20:44:05 +02001583 BOOT_PRIMARY_SLOT,
1584 last_sector_idx);
1585 }
1586 if ((secondary_slot_size < copy_size) ||
1587 (secondary_slot_size < primary_slot_size)) {
David Vinczecea8b592019-10-29 16:09:51 +01001588 secondary_slot_size += boot_img_sector_size(state,
David Vincze401c7422019-06-21 20:44:05 +02001589 BOOT_SECONDARY_SLOT,
1590 last_idx_secondary_slot);
1591 }
1592 if (primary_slot_size >= copy_size &&
1593 secondary_slot_size >= copy_size &&
1594 primary_slot_size == secondary_slot_size) {
Tamas Banf70ef8c2017-12-19 15:35:09 +00001595 break;
1596 }
1597 last_sector_idx++;
David Vincze401c7422019-06-21 20:44:05 +02001598 last_idx_secondary_slot++;
Tamas Banf70ef8c2017-12-19 15:35:09 +00001599 }
1600
1601 swap_idx = 0;
1602 while (last_sector_idx >= 0) {
David Vinczecea8b592019-10-29 16:09:51 +01001603 sz = boot_copy_sz(state, last_sector_idx, &first_sector_idx);
David Vincze39e78552018-10-10 17:10:01 +02001604 if (swap_idx >= (bs->idx - BOOT_STATUS_IDX_0)) {
David Vinczecea8b592019-10-29 16:09:51 +01001605 boot_swap_sectors(first_sector_idx, sz, state, bs);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001606 }
1607
1608 last_sector_idx = first_sector_idx - 1;
1609 swap_idx++;
1610 }
1611
David Vincze8bdfc2d2019-03-18 15:49:23 +01001612#ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT
David Vincze39e78552018-10-10 17:10:01 +02001613 if (boot_status_fails > 0) {
David Vincze401c7422019-06-21 20:44:05 +02001614 BOOT_LOG_WRN("%d status write fails performing the swap",
1615 boot_status_fails);
David Vincze39e78552018-10-10 17:10:01 +02001616 }
1617#endif
1618
Tamas Banf70ef8c2017-12-19 15:35:09 +00001619 return 0;
1620}
1621#endif
1622
David Vincze44b79f42019-10-25 15:39:59 +02001623#ifndef MCUBOOT_OVERWRITE_ONLY
Tamas Banf70ef8c2017-12-19 15:35:09 +00001624/**
David Vincze8bdfc2d2019-03-18 15:49:23 +01001625 * Marks the image in the primary slot as fully copied.
Tamas Banf70ef8c2017-12-19 15:35:09 +00001626 */
Tamas Banf70ef8c2017-12-19 15:35:09 +00001627static int
David Vinczecea8b592019-10-29 16:09:51 +01001628boot_set_copy_done(uint8_t image_index)
Tamas Banf70ef8c2017-12-19 15:35:09 +00001629{
1630 const struct flash_area *fap;
1631 int rc;
1632
David Vinczecea8b592019-10-29 16:09:51 +01001633 rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index),
1634 &fap);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001635 if (rc != 0) {
1636 return BOOT_EFLASH;
1637 }
1638
1639 rc = boot_write_copy_done(fap);
1640 flash_area_close(fap);
1641 return rc;
1642}
Tamas Banf70ef8c2017-12-19 15:35:09 +00001643
1644/**
David Vincze8bdfc2d2019-03-18 15:49:23 +01001645 * Marks a reverted image in the primary slot as confirmed. This is necessary to
1646 * ensure the status bytes from the image revert operation don't get processed
1647 * on a subsequent boot.
Tamas Banf70ef8c2017-12-19 15:35:09 +00001648 *
1649 * NOTE: image_ok is tested before writing because if there's a valid permanent
David Vincze8bdfc2d2019-03-18 15:49:23 +01001650 * image installed on the primary slot and the new image to be upgrade to has a
1651 * bad sig, image_ok would be overwritten.
Tamas Banf70ef8c2017-12-19 15:35:09 +00001652 */
Tamas Banf70ef8c2017-12-19 15:35:09 +00001653static int
David Vinczecea8b592019-10-29 16:09:51 +01001654boot_set_image_ok(uint8_t image_index)
Tamas Banf70ef8c2017-12-19 15:35:09 +00001655{
1656 const struct flash_area *fap;
1657 struct boot_swap_state state;
1658 int rc;
1659
David Vinczecea8b592019-10-29 16:09:51 +01001660 rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index),
1661 &fap);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001662 if (rc != 0) {
1663 return BOOT_EFLASH;
1664 }
1665
1666 rc = boot_read_swap_state(fap, &state);
1667 if (rc != 0) {
1668 rc = BOOT_EFLASH;
1669 goto out;
1670 }
1671
1672 if (state.image_ok == BOOT_FLAG_UNSET) {
1673 rc = boot_write_image_ok(fap);
1674 }
1675
1676out:
1677 flash_area_close(fap);
1678 return rc;
1679}
1680#endif /* !MCUBOOT_OVERWRITE_ONLY */
1681
David Vinczebb6e3b62019-07-31 14:24:05 +02001682#if (BOOT_IMAGE_NUMBER > 1)
1683/**
David Vinczecea8b592019-10-29 16:09:51 +01001684 * Check if the version of the image is not older than required.
1685 *
1686 * @param req Required minimal image version.
1687 * @param ver Version of the image to be checked.
1688 *
1689 * @return 0 if the version is sufficient, nonzero otherwise.
1690 */
1691static int
1692boot_is_version_sufficient(struct image_version *req,
1693 struct image_version *ver)
1694{
1695 if (ver->iv_major > req->iv_major) {
1696 return 0;
1697 }
1698 if (ver->iv_major < req->iv_major) {
1699 return BOOT_EBADVERSION;
1700 }
1701 /* The major version numbers are equal. */
1702 if (ver->iv_minor > req->iv_minor) {
1703 return 0;
1704 }
1705 if (ver->iv_minor < req->iv_minor) {
1706 return BOOT_EBADVERSION;
1707 }
1708 /* The minor version numbers are equal. */
1709 if (ver->iv_revision < req->iv_revision) {
1710 return BOOT_EBADVERSION;
1711 }
1712
1713 return 0;
1714}
1715
1716/**
David Vinczebb6e3b62019-07-31 14:24:05 +02001717 * Check the image dependency whether it is satisfied and modify
1718 * the swap type if necessary.
1719 *
1720 * @param dep Image dependency which has to be verified.
1721 *
1722 * @return 0 on success; nonzero on failure.
1723 */
1724static int
David Vinczecea8b592019-10-29 16:09:51 +01001725boot_verify_slot_dependency(struct boot_loader_state *state,
1726 struct image_dependency *dep)
David Vinczebb6e3b62019-07-31 14:24:05 +02001727{
1728 struct image_version *dep_version;
1729 size_t dep_slot;
1730 int rc;
David Vinczecea8b592019-10-29 16:09:51 +01001731 uint8_t swap_type;
David Vinczebb6e3b62019-07-31 14:24:05 +02001732
1733 /* Determine the source of the image which is the subject of
1734 * the dependency and get it's version. */
David Vinczecea8b592019-10-29 16:09:51 +01001735 swap_type = state->swap_type[dep->image_id];
1736 dep_slot = (swap_type != BOOT_SWAP_TYPE_NONE) ?
David Vinczebb6e3b62019-07-31 14:24:05 +02001737 BOOT_SECONDARY_SLOT : BOOT_PRIMARY_SLOT;
David Vinczecea8b592019-10-29 16:09:51 +01001738 dep_version = &state->imgs[dep->image_id][dep_slot].hdr.ih_ver;
David Vinczebb6e3b62019-07-31 14:24:05 +02001739
1740 rc = boot_is_version_sufficient(&dep->image_min_version, dep_version);
1741 if (rc != 0) {
1742 /* Dependency not satisfied.
1743 * Modify the swap type to decrease the version number of the image
1744 * (which will be located in the primary slot after the boot process),
1745 * consequently the number of unsatisfied dependencies will be
1746 * decreased or remain the same.
1747 */
David Vinczecea8b592019-10-29 16:09:51 +01001748 switch (BOOT_SWAP_TYPE(state)) {
David Vinczebb6e3b62019-07-31 14:24:05 +02001749 case BOOT_SWAP_TYPE_TEST:
1750 case BOOT_SWAP_TYPE_PERM:
David Vinczecea8b592019-10-29 16:09:51 +01001751 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
David Vinczebb6e3b62019-07-31 14:24:05 +02001752 break;
1753 case BOOT_SWAP_TYPE_NONE:
David Vinczecea8b592019-10-29 16:09:51 +01001754 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_REVERT;
David Vinczebb6e3b62019-07-31 14:24:05 +02001755 break;
1756 default:
1757 break;
1758 }
1759 }
1760
1761 return rc;
1762}
1763
1764/**
1765 * Read all dependency TLVs of an image from the flash and verify
1766 * one after another to see if they are all satisfied.
1767 *
1768 * @param slot Image slot number.
1769 *
1770 * @return 0 on success; nonzero on failure.
1771 */
1772static int
David Vinczecea8b592019-10-29 16:09:51 +01001773boot_verify_slot_dependencies(struct boot_loader_state *state, uint32_t slot)
David Vinczebb6e3b62019-07-31 14:24:05 +02001774{
1775 const struct flash_area *fap;
David Vincze07706a42019-12-12 18:20:12 +01001776 struct image_tlv_iter it;
David Vinczebb6e3b62019-07-31 14:24:05 +02001777 struct image_dependency dep;
1778 uint32_t off;
David Vincze07706a42019-12-12 18:20:12 +01001779 uint16_t len;
David Vinczecea8b592019-10-29 16:09:51 +01001780 int area_id;
David Vinczebb6e3b62019-07-31 14:24:05 +02001781 int rc;
1782
David Vinczecea8b592019-10-29 16:09:51 +01001783 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
1784 rc = flash_area_open(area_id, &fap);
David Vinczebb6e3b62019-07-31 14:24:05 +02001785 if (rc != 0) {
1786 rc = BOOT_EFLASH;
1787 goto done;
1788 }
1789
David Vincze07706a42019-12-12 18:20:12 +01001790 rc = bootutil_tlv_iter_begin(&it, boot_img_hdr(state, slot), fap,
1791 IMAGE_TLV_DEPENDENCY, true);
David Vinczebb6e3b62019-07-31 14:24:05 +02001792 if (rc != 0) {
David Vinczebb6e3b62019-07-31 14:24:05 +02001793 goto done;
1794 }
1795
David Vincze07706a42019-12-12 18:20:12 +01001796 while (true) {
1797 rc = bootutil_tlv_iter_next(&it, &off, &len, NULL);
1798 if (rc < 0) {
1799 return -1;
1800 } else if (rc > 0) {
1801 rc = 0;
David Vinczebb6e3b62019-07-31 14:24:05 +02001802 break;
1803 }
David Vincze07706a42019-12-12 18:20:12 +01001804
1805 if (len != sizeof(dep)) {
1806 rc = BOOT_EBADIMAGE;
1807 goto done;
1808 }
1809
1810 rc = flash_area_read(fap, off, &dep, len);
1811 if (rc != 0) {
1812 rc = BOOT_EFLASH;
1813 goto done;
1814 }
1815
1816 if (dep.image_id >= BOOT_IMAGE_NUMBER) {
1817 rc = BOOT_EBADARGS;
1818 goto done;
1819 }
1820
1821 /* Verify dependency and modify the swap type if not satisfied. */
1822 rc = boot_verify_slot_dependency(state, &dep);
1823 if (rc != 0) {
1824 /* Dependency not satisfied. */
1825 goto done;
Tamas Ban056ed0b2019-09-16 12:48:32 +01001826 }
David Vinczebb6e3b62019-07-31 14:24:05 +02001827 }
1828
1829done:
1830 flash_area_close(fap);
1831 return rc;
1832}
1833
1834/**
David Vinczebb6e3b62019-07-31 14:24:05 +02001835 * Iterate over all the images and verify whether the image dependencies in the
1836 * TLV area are all satisfied and update the related swap type if necessary.
1837 */
David Vinczecea8b592019-10-29 16:09:51 +01001838static int
1839boot_verify_dependencies(struct boot_loader_state *state)
David Vinczebb6e3b62019-07-31 14:24:05 +02001840{
David Vinczebb6e3b62019-07-31 14:24:05 +02001841 int rc;
David Vinczecea8b592019-10-29 16:09:51 +01001842 uint8_t slot;
David Vinczebb6e3b62019-07-31 14:24:05 +02001843
David Vinczecea8b592019-10-29 16:09:51 +01001844 BOOT_CURR_IMG(state) = 0;
1845 while (BOOT_CURR_IMG(state) < BOOT_IMAGE_NUMBER) {
1846 if (BOOT_SWAP_TYPE(state) != BOOT_SWAP_TYPE_NONE &&
1847 BOOT_SWAP_TYPE(state) != BOOT_SWAP_TYPE_FAIL) {
1848 slot = BOOT_SECONDARY_SLOT;
1849 } else {
1850 slot = BOOT_PRIMARY_SLOT;
1851 }
1852
1853 rc = boot_verify_slot_dependencies(state, slot);
David Vinczebb6e3b62019-07-31 14:24:05 +02001854 if (rc == 0) {
1855 /* All dependencies've been satisfied, continue with next image. */
David Vinczecea8b592019-10-29 16:09:51 +01001856 BOOT_CURR_IMG(state)++;
David Vinczebb6e3b62019-07-31 14:24:05 +02001857 } else if (rc == BOOT_EBADVERSION) {
David Vinczecea8b592019-10-29 16:09:51 +01001858 /* Cannot upgrade due to non-met dependencies, so disable all
1859 * image upgrades.
1860 */
1861 for (int idx = 0; idx < BOOT_IMAGE_NUMBER; idx++) {
1862 BOOT_CURR_IMG(state) = idx;
1863 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
1864 }
1865 break;
David Vinczebb6e3b62019-07-31 14:24:05 +02001866 } else {
1867 /* Other error happened, images are inconsistent */
David Vinczecea8b592019-10-29 16:09:51 +01001868 return rc;
David Vinczebb6e3b62019-07-31 14:24:05 +02001869 }
1870 }
David Vinczecea8b592019-10-29 16:09:51 +01001871 return rc;
David Vinczebb6e3b62019-07-31 14:24:05 +02001872}
1873#endif /* (BOOT_IMAGE_NUMBER > 1) */
1874
Tamas Banf70ef8c2017-12-19 15:35:09 +00001875/**
David Vincze7384ee72019-07-23 17:00:42 +02001876 * Performs a clean (not aborted) image update.
Tamas Banf70ef8c2017-12-19 15:35:09 +00001877 *
David Vincze7384ee72019-07-23 17:00:42 +02001878 * @param bs The current boot status.
Tamas Banf70ef8c2017-12-19 15:35:09 +00001879 *
1880 * @return 0 on success; nonzero on failure.
1881 */
1882static int
David Vinczecea8b592019-10-29 16:09:51 +01001883boot_perform_update(struct boot_loader_state *state, struct boot_status *bs)
Tamas Banf70ef8c2017-12-19 15:35:09 +00001884{
Tamas Banf70ef8c2017-12-19 15:35:09 +00001885 int rc;
David Vinczecea8b592019-10-29 16:09:51 +01001886#ifndef MCUBOOT_OVERWRITE_ONLY
1887 uint8_t swap_type;
1888#endif
Tamas Banf70ef8c2017-12-19 15:35:09 +00001889
David Vincze7384ee72019-07-23 17:00:42 +02001890 /* At this point there are no aborted swaps. */
1891#if defined(MCUBOOT_OVERWRITE_ONLY)
David Vinczecea8b592019-10-29 16:09:51 +01001892 rc = boot_copy_image(state, bs);
David Vincze7384ee72019-07-23 17:00:42 +02001893#else
David Vinczecea8b592019-10-29 16:09:51 +01001894 rc = boot_swap_image(state, bs);
David Vincze7384ee72019-07-23 17:00:42 +02001895#endif
Tamas Banf70ef8c2017-12-19 15:35:09 +00001896 assert(rc == 0);
David Vincze7384ee72019-07-23 17:00:42 +02001897
1898#ifndef MCUBOOT_OVERWRITE_ONLY
1899 /* The following state needs image_ok be explicitly set after the
1900 * swap was finished to avoid a new revert.
1901 */
David Vinczecea8b592019-10-29 16:09:51 +01001902 swap_type = BOOT_SWAP_TYPE(state);
1903 if (swap_type == BOOT_SWAP_TYPE_REVERT ||
1904 swap_type == BOOT_SWAP_TYPE_PERM) {
1905 rc = boot_set_image_ok(BOOT_CURR_IMG(state));
David Vincze7384ee72019-07-23 17:00:42 +02001906 if (rc != 0) {
David Vinczecea8b592019-10-29 16:09:51 +01001907 BOOT_SWAP_TYPE(state) = swap_type = BOOT_SWAP_TYPE_PANIC;
David Vincze7384ee72019-07-23 17:00:42 +02001908 }
Tamas Banf70ef8c2017-12-19 15:35:09 +00001909 }
1910
David Vinczecea8b592019-10-29 16:09:51 +01001911 if (swap_type == BOOT_SWAP_TYPE_PERM) {
David Vincze7384ee72019-07-23 17:00:42 +02001912 /* Update the stored security counter with the new image's security
1913 * counter value. The primary slot holds the new image at this
1914 * point, but the secondary slot's image header must be passed
1915 * because the read image headers in the boot_data structure have
1916 * not been updated yet.
1917 *
1918 * In case of a permanent image swap mcuboot will never attempt to
1919 * revert the images on the next reboot. Therefore, the security
1920 * counter must be increased right after the image upgrade.
David Vincze401c7422019-06-21 20:44:05 +02001921 */
David Vinczecea8b592019-10-29 16:09:51 +01001922 rc = boot_update_security_counter(
1923 BOOT_CURR_IMG(state),
1924 BOOT_PRIMARY_SLOT,
1925 boot_img_hdr(state, BOOT_SECONDARY_SLOT));
David Vincze7384ee72019-07-23 17:00:42 +02001926 if (rc != 0) {
1927 BOOT_LOG_ERR("Security counter update failed after "
1928 "image upgrade.");
David Vinczecea8b592019-10-29 16:09:51 +01001929 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
Tamas Banf70ef8c2017-12-19 15:35:09 +00001930 }
1931 }
1932
David Vinczecea8b592019-10-29 16:09:51 +01001933 if (BOOT_IS_UPGRADE(swap_type)) {
1934 rc = boot_set_copy_done(BOOT_CURR_IMG(state));
David Vincze7384ee72019-07-23 17:00:42 +02001935 if (rc != 0) {
David Vinczecea8b592019-10-29 16:09:51 +01001936 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
David Vincze7384ee72019-07-23 17:00:42 +02001937 }
1938 }
1939#endif /* !MCUBOOT_OVERWRITE_ONLY */
1940
1941 return rc;
1942}
1943
1944/**
1945 * Completes a previously aborted image swap.
1946 *
1947 * @param bs The current boot status.
1948 *
1949 * @return 0 on success; nonzero on failure.
1950 */
1951#if !defined(MCUBOOT_OVERWRITE_ONLY)
1952static int
David Vinczecea8b592019-10-29 16:09:51 +01001953boot_complete_partial_swap(struct boot_loader_state *state,
1954 struct boot_status *bs)
David Vincze7384ee72019-07-23 17:00:42 +02001955{
1956 int rc;
1957
1958 /* Determine the type of swap operation being resumed from the
1959 * `swap-type` trailer field.
1960 */
David Vinczecea8b592019-10-29 16:09:51 +01001961 rc = boot_swap_image(state, bs);
David Vincze7384ee72019-07-23 17:00:42 +02001962 assert(rc == 0);
1963
David Vinczecea8b592019-10-29 16:09:51 +01001964 BOOT_SWAP_TYPE(state) = bs->swap_type;
David Vincze7384ee72019-07-23 17:00:42 +02001965
1966 /* The following states need image_ok be explicitly set after the
1967 * swap was finished to avoid a new revert.
1968 */
1969 if (bs->swap_type == BOOT_SWAP_TYPE_REVERT ||
1970 bs->swap_type == BOOT_SWAP_TYPE_PERM) {
David Vinczecea8b592019-10-29 16:09:51 +01001971 rc = boot_set_image_ok(BOOT_CURR_IMG(state));
David Vincze7384ee72019-07-23 17:00:42 +02001972 if (rc != 0) {
David Vinczecea8b592019-10-29 16:09:51 +01001973 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
David Vincze7384ee72019-07-23 17:00:42 +02001974 }
1975 }
1976
David Vinczecea8b592019-10-29 16:09:51 +01001977 if (BOOT_IS_UPGRADE(bs->swap_type)) {
1978 rc = boot_set_copy_done(BOOT_CURR_IMG(state));
David Vincze7384ee72019-07-23 17:00:42 +02001979 if (rc != 0) {
David Vinczecea8b592019-10-29 16:09:51 +01001980 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
David Vincze7384ee72019-07-23 17:00:42 +02001981 }
1982 }
1983
David Vinczecea8b592019-10-29 16:09:51 +01001984 if (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_PANIC) {
David Vincze7384ee72019-07-23 17:00:42 +02001985 BOOT_LOG_ERR("panic!");
1986 assert(0);
1987
1988 /* Loop forever... */
1989 while (1) {}
1990 }
1991
1992 return rc;
1993}
1994#endif /* !MCUBOOT_OVERWRITE_ONLY */
1995
1996#if (BOOT_IMAGE_NUMBER > 1)
1997/**
1998 * Review the validity of previously determined swap types of other images.
1999 *
2000 * @param aborted_swap The current image upgrade is a
2001 * partial/aborted swap.
2002 */
2003static void
David Vinczecea8b592019-10-29 16:09:51 +01002004boot_review_image_swap_types(struct boot_loader_state *state,
2005 bool aborted_swap)
David Vincze7384ee72019-07-23 17:00:42 +02002006{
2007 /* In that case if we rebooted in the middle of an image upgrade process, we
2008 * must review the validity of swap types, that were previously determined
2009 * for other images. The image_ok flag had not been set before the reboot
2010 * for any of the updated images (only the copy_done flag) and thus falsely
2011 * the REVERT swap type has been determined for the previous images that had
2012 * been updated before the reboot.
2013 *
2014 * There are two separate scenarios that we have to deal with:
2015 *
2016 * 1. The reboot has happened during swapping an image:
2017 * The current image upgrade has been determined as a
2018 * partial/aborted swap.
2019 * 2. The reboot has happened between two separate image upgrades:
2020 * In this scenario we must check the swap type of the current image.
2021 * In those cases if it is NONE or REVERT we cannot certainly determine
2022 * the fact of a reboot. In a consistent state images must move in the
2023 * same direction or stay in place, e.g. in practice REVERT and TEST
2024 * swap types cannot be present at the same time. If the swap type of
2025 * the current image is either TEST, PERM or FAIL we must review the
2026 * already determined swap types of other images and set each false
2027 * REVERT swap types to NONE (these images had been successfully
2028 * updated before the system rebooted between two separate image
2029 * upgrades).
2030 */
2031
David Vinczecea8b592019-10-29 16:09:51 +01002032 if (BOOT_CURR_IMG(state) == 0) {
David Vincze7384ee72019-07-23 17:00:42 +02002033 /* Nothing to do */
2034 return;
2035 }
2036
2037 if (!aborted_swap) {
David Vinczecea8b592019-10-29 16:09:51 +01002038 if ((BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_NONE) ||
2039 (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_REVERT)) {
David Vincze7384ee72019-07-23 17:00:42 +02002040 /* Nothing to do */
2041 return;
2042 }
2043 }
2044
David Vinczecea8b592019-10-29 16:09:51 +01002045 for (uint8_t i = 0; i < BOOT_CURR_IMG(state); i++) {
2046 if (state->swap_type[i] == BOOT_SWAP_TYPE_REVERT) {
2047 state->swap_type[i] = BOOT_SWAP_TYPE_NONE;
David Vincze7384ee72019-07-23 17:00:42 +02002048 }
2049 }
2050}
2051#endif
2052
2053/**
2054 * Prepare image to be updated if required.
2055 *
2056 * Prepare image to be updated if required with completing an image swap
2057 * operation if one was aborted and/or determining the type of the
2058 * swap operation. In case of any error set the swap type to NONE.
2059 *
David Vinczecea8b592019-10-29 16:09:51 +01002060 * @param state Boot loader status information.
David Vincze7384ee72019-07-23 17:00:42 +02002061 * @param bs Pointer where the read and possibly updated
2062 * boot status can be written to.
2063 */
2064static void
David Vinczecea8b592019-10-29 16:09:51 +01002065boot_prepare_image_for_update(struct boot_loader_state *state,
2066 struct boot_status *bs)
David Vincze7384ee72019-07-23 17:00:42 +02002067{
2068 int rc;
2069
2070 /* Determine the sector layout of the image slots and scratch area. */
David Vinczecea8b592019-10-29 16:09:51 +01002071 rc = boot_read_sectors(state);
David Vincze7384ee72019-07-23 17:00:42 +02002072 if (rc != 0) {
2073 BOOT_LOG_WRN("Failed reading sectors; BOOT_MAX_IMG_SECTORS=%d"
2074 " - too small?", BOOT_MAX_IMG_SECTORS);
2075 /* Unable to determine sector layout, continue with next image
2076 * if there is one.
2077 */
David Vinczecea8b592019-10-29 16:09:51 +01002078 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
David Vincze7384ee72019-07-23 17:00:42 +02002079 return;
2080 }
2081
2082 /* Attempt to read an image header from each slot. */
David Vinczecea8b592019-10-29 16:09:51 +01002083 rc = boot_read_image_headers(state, false);
David Vincze7384ee72019-07-23 17:00:42 +02002084 if (rc != 0) {
2085 /* Continue with next image if there is one. */
David Vinczecea8b592019-10-29 16:09:51 +01002086 BOOT_LOG_WRN("Failed reading image headers; Image=%u",
2087 BOOT_CURR_IMG(state));
2088 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
David Vincze7384ee72019-07-23 17:00:42 +02002089 return;
2090 }
2091
2092 /* If the current image's slots aren't compatible, no swap is possible.
2093 * Just boot into primary slot.
2094 */
David Vinczecea8b592019-10-29 16:09:51 +01002095 if (boot_slots_compatible(state)) {
2096 rc = boot_read_status(state, bs);
David Vincze7384ee72019-07-23 17:00:42 +02002097 if (rc != 0) {
2098 BOOT_LOG_WRN("Failed reading boot status; Image=%u",
David Vinczecea8b592019-10-29 16:09:51 +01002099 BOOT_CURR_IMG(state));
David Vincze7384ee72019-07-23 17:00:42 +02002100 /* Continue with next image if there is one. */
David Vinczecea8b592019-10-29 16:09:51 +01002101 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
David Vincze7384ee72019-07-23 17:00:42 +02002102 return;
2103 }
2104
2105 /* Determine if we rebooted in the middle of an image swap
2106 * operation. If a partial swap was detected, complete it.
2107 */
2108 if (bs->idx != BOOT_STATUS_IDX_0 || bs->state != BOOT_STATUS_STATE_0) {
2109
2110#if (BOOT_IMAGE_NUMBER > 1)
David Vinczecea8b592019-10-29 16:09:51 +01002111 boot_review_image_swap_types(state, true);
David Vincze7384ee72019-07-23 17:00:42 +02002112#endif
2113
2114#ifdef MCUBOOT_OVERWRITE_ONLY
2115 /* Should never arrive here, overwrite-only mode has
2116 * no swap state.
2117 */
2118 assert(0);
2119#else
2120 /* Determine the type of swap operation being resumed from the
2121 * `swap-type` trailer field.
2122 */
David Vinczecea8b592019-10-29 16:09:51 +01002123 rc = boot_complete_partial_swap(state, bs);
David Vincze7384ee72019-07-23 17:00:42 +02002124 assert(rc == 0);
2125#endif
2126 /* Attempt to read an image header from each slot. Ensure that
2127 * image headers in slots are aligned with headers in boot_data.
2128 */
David Vinczecea8b592019-10-29 16:09:51 +01002129 rc = boot_read_image_headers(state, false);
David Vincze7384ee72019-07-23 17:00:42 +02002130 assert(rc == 0);
2131
2132 /* Swap has finished set to NONE */
David Vinczecea8b592019-10-29 16:09:51 +01002133 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
David Vincze7384ee72019-07-23 17:00:42 +02002134 } else {
2135 /* There was no partial swap, determine swap type. */
2136 if (bs->swap_type == BOOT_SWAP_TYPE_NONE) {
David Vinczecea8b592019-10-29 16:09:51 +01002137 BOOT_SWAP_TYPE(state) = boot_validated_swap_type(state, bs);
2138 } else if (boot_validate_slot(state,
2139 BOOT_SECONDARY_SLOT, bs) != 0) {
2140 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_FAIL;
David Vincze7384ee72019-07-23 17:00:42 +02002141 } else {
David Vinczecea8b592019-10-29 16:09:51 +01002142 BOOT_SWAP_TYPE(state) = bs->swap_type;
David Vincze7384ee72019-07-23 17:00:42 +02002143 }
2144
2145#if (BOOT_IMAGE_NUMBER > 1)
David Vinczecea8b592019-10-29 16:09:51 +01002146 boot_review_image_swap_types(state, false);
David Vincze7384ee72019-07-23 17:00:42 +02002147#endif
2148 }
2149 } else {
2150 /* In that case if slots are not compatible. */
David Vinczecea8b592019-10-29 16:09:51 +01002151 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
David Vincze7384ee72019-07-23 17:00:42 +02002152 }
Tamas Banf70ef8c2017-12-19 15:35:09 +00002153}
2154
2155/**
2156 * Prepares the booting process. This function moves images around in flash as
2157 * appropriate, and tells you what address to boot from.
2158 *
David Vinczecea8b592019-10-29 16:09:51 +01002159 * @param state Boot loader status information.
Tamas Banf70ef8c2017-12-19 15:35:09 +00002160 * @param rsp On success, indicates how booting should occur.
2161 *
2162 * @return 0 on success; nonzero on failure.
2163 */
2164int
David Vinczecea8b592019-10-29 16:09:51 +01002165context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp)
Tamas Banf70ef8c2017-12-19 15:35:09 +00002166{
Tamas Banf70ef8c2017-12-19 15:35:09 +00002167 size_t slot;
David Vincze7384ee72019-07-23 17:00:42 +02002168 struct boot_status bs;
Tamas Ban4e5ed8d2019-09-17 09:31:11 +01002169 int rc = 0;
Tamas Banf70ef8c2017-12-19 15:35:09 +00002170 int fa_id;
David Vinczecea8b592019-10-29 16:09:51 +01002171 int image_index;
2172 bool has_upgrade;
Tamas Banf70ef8c2017-12-19 15:35:09 +00002173
2174 /* The array of slot sectors are defined here (as opposed to file scope) so
2175 * that they don't get allocated for non-boot-loader apps. This is
2176 * necessary because the gcc option "-fdata-sections" doesn't seem to have
2177 * any effect in older gcc versions (e.g., 4.8.4).
2178 */
David Vincze7384ee72019-07-23 17:00:42 +02002179 static boot_sector_t
2180 primary_slot_sectors[BOOT_IMAGE_NUMBER][BOOT_MAX_IMG_SECTORS];
2181 static boot_sector_t
2182 secondary_slot_sectors[BOOT_IMAGE_NUMBER][BOOT_MAX_IMG_SECTORS];
David Vincze401c7422019-06-21 20:44:05 +02002183 static boot_sector_t scratch_sectors[BOOT_MAX_IMG_SECTORS];
Tamas Banf70ef8c2017-12-19 15:35:09 +00002184
David Vincze7384ee72019-07-23 17:00:42 +02002185 /* Iterate over all the images. By the end of the loop the swap type has
2186 * to be determined for each image and all aborted swaps have to be
2187 * completed.
Tamas Banf70ef8c2017-12-19 15:35:09 +00002188 */
David Vinczecea8b592019-10-29 16:09:51 +01002189 IMAGES_ITER(BOOT_CURR_IMG(state)) {
2190
2191 image_index = BOOT_CURR_IMG(state);
2192
2193 BOOT_IMG(state, BOOT_PRIMARY_SLOT).sectors =
2194 primary_slot_sectors[image_index];
2195 BOOT_IMG(state, BOOT_SECONDARY_SLOT).sectors =
2196 secondary_slot_sectors[image_index];
2197 state->scratch.sectors = scratch_sectors;
Tamas Banf70ef8c2017-12-19 15:35:09 +00002198
David Vincze7384ee72019-07-23 17:00:42 +02002199 /* Open primary and secondary image areas for the duration
2200 * of this call.
Tamas Banf70ef8c2017-12-19 15:35:09 +00002201 */
David Vincze7384ee72019-07-23 17:00:42 +02002202 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
David Vinczecea8b592019-10-29 16:09:51 +01002203 fa_id = flash_area_id_from_multi_image_slot(image_index, slot);
2204 rc = flash_area_open(fa_id, &BOOT_IMG_AREA(state, slot));
David Vincze7384ee72019-07-23 17:00:42 +02002205 assert(rc == 0);
2206 }
2207 rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH,
David Vinczecea8b592019-10-29 16:09:51 +01002208 &BOOT_SCRATCH_AREA(state));
David Vincze7384ee72019-07-23 17:00:42 +02002209 assert(rc == 0);
2210
2211 /* Determine swap type and complete swap if it has been aborted. */
David Vinczecea8b592019-10-29 16:09:51 +01002212 boot_prepare_image_for_update(state, &bs);
2213
2214 if (BOOT_IS_UPGRADE(BOOT_SWAP_TYPE(state))) {
2215 has_upgrade = true;
2216 }
David Vincze7384ee72019-07-23 17:00:42 +02002217 }
2218
David Vinczebb6e3b62019-07-31 14:24:05 +02002219#if (BOOT_IMAGE_NUMBER > 1)
David Vinczecea8b592019-10-29 16:09:51 +01002220 if (has_upgrade) {
2221 /* Iterate over all the images and verify whether the image dependencies
2222 * are all satisfied and update swap type if necessary.
2223 */
2224 rc = boot_verify_dependencies(state);
2225 if (rc == BOOT_EBADVERSION) {
2226 /*
2227 * It was impossible to upgrade because the expected dependency
2228 * version was not available. Here we already changed the swap_type
2229 * so that instead of asserting the bootloader, we continue and no
2230 * upgrade is performed.
2231 */
2232 rc = 0;
2233 }
2234 }
David Vinczebb6e3b62019-07-31 14:24:05 +02002235#endif
2236
David Vincze7384ee72019-07-23 17:00:42 +02002237 /* Iterate over all the images. At this point there are no aborted swaps
2238 * and the swap types are determined for each image. By the end of the loop
2239 * all required update operations will have been finished.
2240 */
David Vinczecea8b592019-10-29 16:09:51 +01002241 IMAGES_ITER(BOOT_CURR_IMG(state)) {
David Vincze7384ee72019-07-23 17:00:42 +02002242
2243#if (BOOT_IMAGE_NUMBER > 1)
2244 /* Indicate that swap is not aborted */
2245 memset(&bs, 0, sizeof bs);
2246 bs.idx = BOOT_STATUS_IDX_0;
2247 bs.state = BOOT_STATUS_STATE_0;
2248#endif /* (BOOT_IMAGE_NUMBER > 1) */
2249
2250 /* Set the previously determined swap type */
David Vinczecea8b592019-10-29 16:09:51 +01002251 bs.swap_type = BOOT_SWAP_TYPE(state);
David Vincze7384ee72019-07-23 17:00:42 +02002252
David Vinczecea8b592019-10-29 16:09:51 +01002253 switch (BOOT_SWAP_TYPE(state)) {
David Vincze7384ee72019-07-23 17:00:42 +02002254 case BOOT_SWAP_TYPE_NONE:
2255 break;
2256
2257 case BOOT_SWAP_TYPE_TEST: /* fallthrough */
2258 case BOOT_SWAP_TYPE_PERM: /* fallthrough */
2259 case BOOT_SWAP_TYPE_REVERT:
David Vinczecea8b592019-10-29 16:09:51 +01002260 rc = boot_perform_update(state, &bs);
David Vincze7384ee72019-07-23 17:00:42 +02002261 assert(rc == 0);
2262 break;
2263
2264 case BOOT_SWAP_TYPE_FAIL:
2265 /* The image in secondary slot was invalid and is now erased. Ensure
2266 * we don't try to boot into it again on the next reboot. Do this by
2267 * pretending we just reverted back to primary slot.
2268 */
Tamas Banf70ef8c2017-12-19 15:35:09 +00002269#ifndef MCUBOOT_OVERWRITE_ONLY
David Vincze7384ee72019-07-23 17:00:42 +02002270 /* image_ok needs to be explicitly set to avoid a new revert. */
David Vinczecea8b592019-10-29 16:09:51 +01002271 rc = boot_set_image_ok(BOOT_CURR_IMG(state));
Tamas Banf70ef8c2017-12-19 15:35:09 +00002272 if (rc != 0) {
David Vinczecea8b592019-10-29 16:09:51 +01002273 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
Tamas Banf70ef8c2017-12-19 15:35:09 +00002274 }
2275#endif /* !MCUBOOT_OVERWRITE_ONLY */
David Vincze7384ee72019-07-23 17:00:42 +02002276 break;
2277
2278 default:
David Vinczecea8b592019-10-29 16:09:51 +01002279 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
Tamas Banf70ef8c2017-12-19 15:35:09 +00002280 }
David Vincze7384ee72019-07-23 17:00:42 +02002281
David Vinczecea8b592019-10-29 16:09:51 +01002282 if (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_PANIC) {
David Vincze7384ee72019-07-23 17:00:42 +02002283 BOOT_LOG_ERR("panic!");
2284 assert(0);
2285
2286 /* Loop forever... */
2287 while (1) {}
2288 }
Tamas Banf70ef8c2017-12-19 15:35:09 +00002289 }
2290
David Vincze7384ee72019-07-23 17:00:42 +02002291 /* Iterate over all the images. At this point all required update operations
2292 * have finished. By the end of the loop each image in the primary slot will
2293 * have been re-validated.
2294 */
David Vinczecea8b592019-10-29 16:09:51 +01002295 IMAGES_ITER(BOOT_CURR_IMG(state)) {
2296 if (BOOT_SWAP_TYPE(state) != BOOT_SWAP_TYPE_NONE) {
David Vincze7384ee72019-07-23 17:00:42 +02002297 /* Attempt to read an image header from each slot. Ensure that image
2298 * headers in slots are aligned with headers in boot_data.
David Vincze060968d2019-05-23 01:13:14 +02002299 */
David Vinczecea8b592019-10-29 16:09:51 +01002300 rc = boot_read_image_headers(state, false);
David Vincze060968d2019-05-23 01:13:14 +02002301 if (rc != 0) {
David Vincze7384ee72019-07-23 17:00:42 +02002302 goto out;
2303 }
2304 /* Since headers were reloaded, it can be assumed we just performed
2305 * a swap or overwrite. Now the header info that should be used to
2306 * provide the data for the bootstrap, which previously was at
2307 * secondary slot, was updated to primary slot.
2308 */
2309 }
2310
2311#ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT
David Vinczecea8b592019-10-29 16:09:51 +01002312 rc = boot_validate_slot(state, BOOT_PRIMARY_SLOT, NULL);
David Vincze7384ee72019-07-23 17:00:42 +02002313 if (rc != 0) {
2314 rc = BOOT_EBADIMAGE;
2315 goto out;
2316 }
2317#else
2318 /* Even if we're not re-validating the primary slot, we could be booting
2319 * onto an empty flash chip. At least do a basic sanity check that
2320 * the magic number on the image is OK.
2321 */
David Vinczecea8b592019-10-29 16:09:51 +01002322 if (!BOOT_IMG_HDR_IS_VALID(state, BOOT_PRIMARY_SLOT)) {
2323 BOOT_LOG_ERR("bad image magic 0x%lx; Image=%u", (unsigned long)
2324 &boot_img_hdr(state, BOOT_PRIMARY_SLOT)->ih_magic,
2325 BOOT_CURR_IMG(state));
David Vincze7384ee72019-07-23 17:00:42 +02002326 rc = BOOT_EBADIMAGE;
2327 goto out;
2328 }
2329#endif /* MCUBOOT_VALIDATE_PRIMARY_SLOT */
2330
2331 /* Update the stored security counter with the active image's security
2332 * counter value. It will be updated only if the new security counter is
2333 * greater than the stored value.
2334 *
2335 * In case of a successful image swapping when the swap type is TEST the
2336 * security counter can be increased only after a reset, when the swap
2337 * type is NONE and the image has marked itself "OK" (the image_ok flag
2338 * has been set). This way a "revert" swap can be performed if it's
2339 * necessary.
2340 */
David Vinczecea8b592019-10-29 16:09:51 +01002341 if (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_NONE) {
2342 rc = boot_update_security_counter(
2343 BOOT_CURR_IMG(state),
2344 BOOT_PRIMARY_SLOT,
2345 boot_img_hdr(state, BOOT_PRIMARY_SLOT));
David Vincze7384ee72019-07-23 17:00:42 +02002346 if (rc != 0) {
2347 BOOT_LOG_ERR("Security counter update failed after image "
2348 "validation.");
David Vincze060968d2019-05-23 01:13:14 +02002349 goto out;
2350 }
2351 }
2352
David Vincze7384ee72019-07-23 17:00:42 +02002353 /* Save boot status to shared memory area */
2354#if (BOOT_IMAGE_NUMBER > 1)
David Vinczecea8b592019-10-29 16:09:51 +01002355 rc = boot_save_boot_status((BOOT_CURR_IMG(state) == 0) ?
2356 SW_SPE : SW_NSPE,
2357 boot_img_hdr(state, BOOT_PRIMARY_SLOT),
2358 BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT)
David Vincze7384ee72019-07-23 17:00:42 +02002359 );
David Vincze8bdfc2d2019-03-18 15:49:23 +01002360#else
David Vincze7384ee72019-07-23 17:00:42 +02002361 rc = boot_save_boot_status(SW_S_NS,
David Vinczecea8b592019-10-29 16:09:51 +01002362 boot_img_hdr(state, BOOT_PRIMARY_SLOT),
2363 BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT)
David Vincze7384ee72019-07-23 17:00:42 +02002364 );
2365#endif
2366 if (rc) {
2367 BOOT_LOG_ERR("Failed to add Image %u data to shared area",
David Vinczecea8b592019-10-29 16:09:51 +01002368 BOOT_CURR_IMG(state));
David Vincze060968d2019-05-23 01:13:14 +02002369 }
2370 }
2371
David Vinczecea8b592019-10-29 16:09:51 +01002372#if (BOOT_IMAGE_NUMBER > 1)
David Vincze7384ee72019-07-23 17:00:42 +02002373 /* Always boot from the primary slot of Image 0. */
David Vinczecea8b592019-10-29 16:09:51 +01002374 BOOT_CURR_IMG(state) = 0;
2375#endif
Tamas Ban0e8ab302019-01-17 11:45:31 +00002376
David Vinczecea8b592019-10-29 16:09:51 +01002377 rsp->br_flash_dev_id =
2378 BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT)->fa_device_id;
2379 rsp->br_image_off =
2380 boot_img_slot_off(state, BOOT_PRIMARY_SLOT);
2381 rsp->br_hdr =
2382 boot_img_hdr(state, BOOT_PRIMARY_SLOT);
2383
2384out:
2385 IMAGES_ITER(BOOT_CURR_IMG(state)) {
2386 flash_area_close(BOOT_SCRATCH_AREA(state));
David Vincze7384ee72019-07-23 17:00:42 +02002387 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
David Vinczecea8b592019-10-29 16:09:51 +01002388 flash_area_close(BOOT_IMG_AREA(state,
David Vincze7384ee72019-07-23 17:00:42 +02002389 BOOT_NUM_SLOTS - 1 - slot));
2390 }
Tamas Banf70ef8c2017-12-19 15:35:09 +00002391 }
2392 return rc;
2393}
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002394
Oliver Swedef9982442018-08-24 18:37:44 +01002395#else /* MCUBOOT_NO_SWAP || MCUBOOT_RAM_LOADING */
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002396
David Vinczedcba70b2019-05-28 12:02:52 +02002397#define BOOT_LOG_IMAGE_INFO(area, hdr, state) \
2398 BOOT_LOG_INF("Image %u: version=%u.%u.%u+%u, magic=%5s, image_ok=0x%x", \
2399 (area), \
2400 (hdr)->ih_ver.iv_major, \
2401 (hdr)->ih_ver.iv_minor, \
2402 (hdr)->ih_ver.iv_revision, \
2403 (hdr)->ih_ver.iv_build_num, \
2404 ((state)->magic == BOOT_MAGIC_GOOD ? "good" : \
2405 (state)->magic == BOOT_MAGIC_UNSET ? "unset" : \
2406 "bad"), \
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002407 (state)->image_ok)
2408
2409struct image_slot_version {
2410 uint64_t version;
2411 uint32_t slot_number;
2412};
2413
2414/**
2415 * Extract the version number from the image header. This function must be
2416 * ported if version number format has changed in the image header.
2417 *
2418 * @param hdr Pointer to an image header structure
2419 *
Oliver Swedef9982442018-08-24 18:37:44 +01002420 * @return Version number casted to uint64_t
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002421 */
2422static uint64_t
2423boot_get_version_number(struct image_header *hdr)
2424{
Oliver Swedef9982442018-08-24 18:37:44 +01002425 uint64_t version = 0;
2426 version |= (uint64_t)hdr->ih_ver.iv_major << (IMAGE_VER_MINOR_LENGTH
2427 + IMAGE_VER_REVISION_LENGTH
2428 + IMAGE_VER_BUILD_NUM_LENGTH);
2429 version |= (uint64_t)hdr->ih_ver.iv_minor << (IMAGE_VER_REVISION_LENGTH
2430 + IMAGE_VER_BUILD_NUM_LENGTH);
2431 version |= (uint64_t)hdr->ih_ver.iv_revision << IMAGE_VER_BUILD_NUM_LENGTH;
2432 version |= hdr->ih_ver.iv_build_num;
2433 return version;
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002434}
2435
2436/**
2437 * Comparator function for `qsort` to compare version numbers. This function
2438 * must be ported if version number format has changed in the image header.
2439 *
2440 * @param ver1 Pointer to an array element which holds the version number
2441 * @param ver2 Pointer to another array element which holds the version
2442 * number
2443 *
2444 * @return if version1 > version2 -1
2445 * if version1 == version2 0
2446 * if version1 < version2 1
2447 */
2448static int
2449boot_compare_version_numbers(const void *ver1, const void *ver2)
2450{
2451 if (((struct image_slot_version *)ver1)->version <
2452 ((struct image_slot_version *)ver2)->version) {
2453 return 1;
2454 }
2455
2456 if (((struct image_slot_version *)ver1)->version ==
2457 ((struct image_slot_version *)ver2)->version) {
2458 return 0;
2459 }
2460
2461 return -1;
2462}
2463
2464/**
2465 * Sort the available images based on the version number and puts them in
2466 * a list.
2467 *
David Vinczecea8b592019-10-29 16:09:51 +01002468 * @param state Boot loader status information.
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002469 * @param boot_sequence A pointer to an array, whose aim is to carry
2470 * the boot order of candidate images.
2471 * @param slot_cnt The number of flash areas, which can contains firmware
2472 * images.
2473 *
2474 * @return The number of valid images.
2475 */
2476uint32_t
David Vinczecea8b592019-10-29 16:09:51 +01002477boot_get_boot_sequence(struct boot_loader_state *state,
2478 uint32_t *boot_sequence, uint32_t slot_cnt)
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002479{
2480 struct boot_swap_state slot_state;
2481 struct image_header *hdr;
2482 struct image_slot_version image_versions[BOOT_NUM_SLOTS] = {{0}};
2483 uint32_t image_cnt = 0;
2484 uint32_t slot;
2485 int32_t rc;
2486 int32_t fa_id;
2487
2488 for (slot = 0; slot < slot_cnt; slot++) {
David Vinczecea8b592019-10-29 16:09:51 +01002489 hdr = boot_img_hdr(state, slot);
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002490 fa_id = flash_area_id_from_image_slot(slot);
2491 rc = boot_read_swap_state_by_id(fa_id, &slot_state);
2492 if (rc != 0) {
David Vinczedcba70b2019-05-28 12:02:52 +02002493 BOOT_LOG_ERR("Error during reading image trailer from slot: %u",
2494 slot);
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002495 continue;
2496 }
2497
David Vinczecea8b592019-10-29 16:09:51 +01002498 if (BOOT_IMG_HDR_IS_VALID(state, slot)) {
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002499 if (slot_state.magic == BOOT_MAGIC_GOOD ||
David Vincze39e78552018-10-10 17:10:01 +02002500 slot_state.image_ok == BOOT_FLAG_SET) {
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002501 /* Valid cases:
2502 * - Test mode: magic is OK in image trailer
2503 * - Permanent mode: image_ok flag has previously set
2504 */
2505 image_versions[slot].slot_number = slot;
2506 image_versions[slot].version = boot_get_version_number(hdr);
2507 image_cnt++;
2508 }
2509
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002510 BOOT_LOG_IMAGE_INFO(slot, hdr, &slot_state);
2511 } else {
David Vinczedcba70b2019-05-28 12:02:52 +02002512 BOOT_LOG_INF("Image %u: No valid image", slot);
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002513 }
2514 }
2515
2516 /* Sort the images based on version number */
2517 qsort(&image_versions[0],
2518 slot_cnt,
2519 sizeof(struct image_slot_version),
2520 boot_compare_version_numbers);
2521
2522 /* Copy the calculated boot sequence to boot_sequence array */
2523 for (slot = 0; slot < slot_cnt; slot++) {
2524 boot_sequence[slot] = image_versions[slot].slot_number;
2525 }
2526
2527 return image_cnt;
2528}
2529
Oliver Swedef9982442018-08-24 18:37:44 +01002530#ifdef MCUBOOT_RAM_LOADING
Raef Colesaf082382019-10-01 11:10:33 +01002531
2532/**
2533 * Verifies that the image in a slot lies within the predefined bounds that are
2534 * allowed to be used by executable images.
2535 *
2536 * @param img_dst The address to which the image is going to be copied.
2537 *
2538 * @param img_sz The size of the image.
2539 *
2540 * @return 0 on success; nonzero on failure.
2541 */
2542static int
2543boot_verify_ram_loading_address(uint32_t img_dst, uint32_t img_sz)
2544{
David Vincze0dc41d22019-10-28 14:56:29 +01002545 uint32_t img_end_addr;
2546
Raef Colesaf082382019-10-01 11:10:33 +01002547 if (img_dst < IMAGE_EXECUTABLE_RAM_START) {
2548 return BOOT_EBADIMAGE;
2549 }
2550
David Vincze0dc41d22019-10-28 14:56:29 +01002551 if (!boot_u32_safe_add(&img_end_addr, img_dst, img_sz)) {
Raef Colesaf082382019-10-01 11:10:33 +01002552 return BOOT_EBADIMAGE;
2553 }
2554
David Vincze0dc41d22019-10-28 14:56:29 +01002555 if (img_end_addr > (IMAGE_EXECUTABLE_RAM_START +
2556 IMAGE_EXECUTABLE_RAM_SIZE)) {
Raef Colesaf082382019-10-01 11:10:33 +01002557 return BOOT_EBADIMAGE;
2558 }
2559
2560 return 0;
2561}
2562
Oliver Swedef9982442018-08-24 18:37:44 +01002563/**
2564 * Copies an image from a slot in the flash to an SRAM address, where the load
2565 * address has already been inserted into the image header by this point and is
2566 * extracted from it within this method. The copying is done sector-by-sector.
2567 *
David Vinczecea8b592019-10-29 16:09:51 +01002568 * @param state Boot loader status information.
Oliver Swedef9982442018-08-24 18:37:44 +01002569 * @param slot The flash slot of the image to be copied to SRAM.
2570 *
2571 * @param hdr Pointer to the image header structure of the image
Raef Colesaf082382019-10-01 11:10:33 +01002572 *
2573 * @param img_dst The address at which the image needs to be copied to
2574 * SRAM.
2575 *
2576 * @param img_sz The size of the image that needs to be copied to SRAM.
Oliver Swedef9982442018-08-24 18:37:44 +01002577 *
2578 * @return 0 on success; nonzero on failure.
2579 */
2580static int
David Vinczecea8b592019-10-29 16:09:51 +01002581boot_copy_image_to_sram(struct boot_loader_state *state, int slot,
2582 struct image_header *hdr,
Raef Colesaf082382019-10-01 11:10:33 +01002583 uint32_t img_dst, uint32_t img_sz)
Oliver Swedef9982442018-08-24 18:37:44 +01002584{
2585 int rc;
2586 uint32_t sect_sz;
2587 uint32_t sect = 0;
2588 uint32_t bytes_copied = 0;
2589 const struct flash_area *fap_src = NULL;
Oliver Swedef9982442018-08-24 18:37:44 +01002590
Raef Colesaf082382019-10-01 11:10:33 +01002591 if (img_dst % 4 != 0) {
Tamas Banc27b5c32019-05-28 16:30:19 +01002592 BOOT_LOG_INF("Cannot copy the image to the SRAM address 0x%x "
Oliver Swedef9982442018-08-24 18:37:44 +01002593 "- the load address must be aligned with 4 bytes due to SRAM "
Raef Colesaf082382019-10-01 11:10:33 +01002594 "restrictions", img_dst);
Oliver Swedef9982442018-08-24 18:37:44 +01002595 return BOOT_EBADARGS;
2596 }
2597
2598 rc = flash_area_open(flash_area_id_from_image_slot(slot), &fap_src);
2599 if (rc != 0) {
2600 return BOOT_EFLASH;
2601 }
2602
Oliver Swedef9982442018-08-24 18:37:44 +01002603 while (bytes_copied < img_sz) {
David Vinczecea8b592019-10-29 16:09:51 +01002604 sect_sz = boot_img_sector_size(state, slot, sect);
Oliver Swedef9982442018-08-24 18:37:44 +01002605 /*
2606 * Direct copy from where the image sector resides in flash to its new
2607 * location in SRAM
2608 */
2609 rc = flash_area_read(fap_src,
2610 bytes_copied,
Raef Colesaf082382019-10-01 11:10:33 +01002611 (void *)(img_dst + bytes_copied),
Oliver Swedef9982442018-08-24 18:37:44 +01002612 sect_sz);
2613 if (rc != 0) {
2614 BOOT_LOG_INF("Error whilst copying image from Flash to SRAM");
2615 break;
2616 } else {
2617 bytes_copied += sect_sz;
2618 }
2619 sect++;
2620 }
2621
2622 if (fap_src) {
2623 flash_area_close(fap_src);
2624 }
2625 return rc;
2626}
Raef Coles27a61452019-09-25 15:32:25 +01002627
2628/**
2629 * Removes an image from SRAM, by overwriting it with zeros.
2630 *
Raef Colesaf082382019-10-01 11:10:33 +01002631 * @param img_dst The address of the image that needs to be removed from
2632 * SRAM.
Raef Coles27a61452019-09-25 15:32:25 +01002633 *
Raef Colesaf082382019-10-01 11:10:33 +01002634 * @param img_sz The size of the image that needs to be removed from
2635 * SRAM.
Raef Coles27a61452019-09-25 15:32:25 +01002636 *
2637 * @return 0 on success; nonzero on failure.
2638 */
2639static int
Raef Colesaf082382019-10-01 11:10:33 +01002640boot_remove_image_from_sram(uint32_t img_dst, uint32_t img_sz)
Raef Coles27a61452019-09-25 15:32:25 +01002641{
Raef Colesaf082382019-10-01 11:10:33 +01002642 BOOT_LOG_INF("Removing image from SRAM at address 0x%x", img_dst);
2643 memset((void*)img_dst, 0, img_sz);
Raef Coles27a61452019-09-25 15:32:25 +01002644
2645 return 0;
2646}
Oliver Swedef9982442018-08-24 18:37:44 +01002647#endif /* MCUBOOT_RAM_LOADING */
2648
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002649/**
2650 * Prepares the booting process. This function choose the newer image in flash
David Vinczecea8b592019-10-29 16:09:51 +01002651 * as appropriate, and tells you what address to boot from.
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002652 *
David Vinczecea8b592019-10-29 16:09:51 +01002653 * @param state Boot loader status information.
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002654 * @param rsp On success, indicates how booting should occur.
2655 *
2656 * @return 0 on success; nonzero on failure.
2657 */
2658int
David Vinczecea8b592019-10-29 16:09:51 +01002659context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp)
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002660{
2661 size_t slot = 0;
2662 int32_t i;
2663 int rc;
2664 int fa_id;
2665 uint32_t boot_sequence[BOOT_NUM_SLOTS];
2666 uint32_t img_cnt;
Raef Coles27a61452019-09-25 15:32:25 +01002667 struct image_header *selected_image_header;
2668#ifdef MCUBOOT_RAM_LOADING
2669 int image_copied = 0;
Raef Colesaf082382019-10-01 11:10:33 +01002670 uint32_t img_dst = 0;
2671 uint32_t img_sz = 0;
Raef Coles27a61452019-09-25 15:32:25 +01002672#endif /* MCUBOOT_RAM_LOADING */
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002673
David Vincze8bdfc2d2019-03-18 15:49:23 +01002674 static boot_sector_t primary_slot_sectors[BOOT_MAX_IMG_SECTORS];
2675 static boot_sector_t secondary_slot_sectors[BOOT_MAX_IMG_SECTORS];
Raef Coles35ff8162019-12-12 13:43:15 +00002676 static boot_sector_t scratch_sectors[BOOT_MAX_IMG_SECTORS];
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002677
Raef Coles35ff8162019-12-12 13:43:15 +00002678 BOOT_IMG(state, BOOT_PRIMARY_SLOT).sectors = primary_slot_sectors;
2679 BOOT_IMG(state, BOOT_SECONDARY_SLOT).sectors = secondary_slot_sectors;
2680 state->scratch.sectors = scratch_sectors;
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002681
2682 /* Open boot_data image areas for the duration of this call. */
2683 for (i = 0; i < BOOT_NUM_SLOTS; i++) {
2684 fa_id = flash_area_id_from_image_slot(i);
David Vinczecea8b592019-10-29 16:09:51 +01002685 rc = flash_area_open(fa_id, &BOOT_IMG_AREA(state, i));
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002686 assert(rc == 0);
2687 }
2688
2689 /* Determine the sector layout of the image slots. */
David Vinczecea8b592019-10-29 16:09:51 +01002690 rc = boot_read_sectors(state);
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002691 if (rc != 0) {
David Vinczecea8b592019-10-29 16:09:51 +01002692 BOOT_LOG_WRN("Failed reading sectors; BOOT_MAX_IMG_SECTORS=%d - "
2693 "too small?", BOOT_MAX_IMG_SECTORS);
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002694 goto out;
2695 }
2696
2697 /* Attempt to read an image header from each slot. */
David Vinczecea8b592019-10-29 16:09:51 +01002698 rc = boot_read_image_headers(state, false);
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002699 if (rc != 0) {
2700 goto out;
2701 }
2702
David Vinczecea8b592019-10-29 16:09:51 +01002703 img_cnt = boot_get_boot_sequence(state, boot_sequence, BOOT_NUM_SLOTS);
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002704 if (img_cnt) {
2705 /* Authenticate images */
2706 for (i = 0; i < img_cnt; i++) {
Raef Coles27a61452019-09-25 15:32:25 +01002707
2708 slot = boot_sequence[i];
David Vinczecea8b592019-10-29 16:09:51 +01002709 selected_image_header = boot_img_hdr(state, slot);
Raef Coles27a61452019-09-25 15:32:25 +01002710
2711#ifdef MCUBOOT_RAM_LOADING
2712 if (selected_image_header->ih_flags & IMAGE_F_RAM_LOAD) {
Raef Colesaf082382019-10-01 11:10:33 +01002713
2714 img_dst = selected_image_header->ih_load_addr;
2715
David Vinczecea8b592019-10-29 16:09:51 +01002716 rc = boot_read_image_size(state, slot, &img_sz);
Raef Colesaf082382019-10-01 11:10:33 +01002717 if (rc != 0) {
2718 rc = BOOT_EFLASH;
2719 BOOT_LOG_INF("Could not load image headers from the image"
2720 "in the %s slot.",
2721 (slot == BOOT_PRIMARY_SLOT) ?
2722 "primary" : "secondary");
2723 continue;
2724 }
2725
2726 rc = boot_verify_ram_loading_address(img_dst, img_sz);
2727 if (rc != 0) {
2728 BOOT_LOG_INF("Could not copy image from the %s slot in "
2729 "the Flash to load address 0x%x in SRAM as"
2730 " the image would overlap memory outside"
2731 " the defined executable region.",
2732 (slot == BOOT_PRIMARY_SLOT) ?
2733 "primary" : "secondary",
2734 selected_image_header->ih_load_addr);
2735 continue;
2736 }
2737
Raef Coles27a61452019-09-25 15:32:25 +01002738 /* Copy image to the load address from where it
2739 * currently resides in flash
2740 */
David Vinczecea8b592019-10-29 16:09:51 +01002741 rc = boot_copy_image_to_sram(state, slot, selected_image_header,
Raef Colesaf082382019-10-01 11:10:33 +01002742 img_dst, img_sz);
Raef Coles27a61452019-09-25 15:32:25 +01002743 if (rc != 0) {
2744 rc = BOOT_EBADIMAGE;
2745 BOOT_LOG_INF("Could not copy image from the %s slot in "
2746 "the Flash to load address 0x%x in SRAM, "
2747 "aborting..", (slot == BOOT_PRIMARY_SLOT) ?
2748 "primary" : "secondary",
2749 selected_image_header->ih_load_addr);
2750 continue;
2751 } else {
2752 BOOT_LOG_INF("Image has been copied from the %s slot in "
2753 "the flash to SRAM address 0x%x",
2754 (slot == BOOT_PRIMARY_SLOT) ?
2755 "primary" : "secondary",
2756 selected_image_header->ih_load_addr);
2757 image_copied = 1;
2758 }
2759 } else {
2760 /* Only images that support IMAGE_F_RAM_LOAD are allowed if
2761 * MCUBOOT_RAM_LOADING is set.
2762 */
2763 rc = BOOT_EBADIMAGE;
2764 continue;
2765 }
2766#endif /* MCUBOOT_RAM_LOADING */
David Vinczecea8b592019-10-29 16:09:51 +01002767 rc = boot_validate_slot(state, slot, NULL);
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002768 if (rc == 0) {
Raef Coles27a61452019-09-25 15:32:25 +01002769 /* If a valid image is found then there is no reason to check
2770 * the rest of the images, as they were already ordered by
2771 * preference.
2772 */
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002773 break;
2774 }
Raef Coles27a61452019-09-25 15:32:25 +01002775#ifdef MCUBOOT_RAM_LOADING
2776 else if (image_copied) {
2777 /* If an image is found to be invalid then it is removed from
2778 * RAM to prevent it being a shellcode vector.
2779 */
Raef Colesaf082382019-10-01 11:10:33 +01002780 boot_remove_image_from_sram(img_dst, img_sz);
Raef Coles27a61452019-09-25 15:32:25 +01002781 image_copied = 0;
2782 }
2783#endif /* MCUBOOT_RAM_LOADING */
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002784 }
2785 if (rc) {
2786 /* If there was no valid image at all */
2787 rc = BOOT_EBADIMAGE;
2788 goto out;
2789 }
2790
David Vincze060968d2019-05-23 01:13:14 +02002791 /* Update the security counter with the newest image's security
2792 * counter value.
2793 */
David Vinczecea8b592019-10-29 16:09:51 +01002794 rc = boot_update_security_counter(BOOT_CURR_IMG(state), slot,
2795 selected_image_header);
David Vincze060968d2019-05-23 01:13:14 +02002796 if (rc != 0) {
2797 BOOT_LOG_ERR("Security counter update failed after image "
2798 "validation.");
2799 goto out;
2800 }
2801
Oliver Swedef9982442018-08-24 18:37:44 +01002802
David Vincze8a2a4e22019-05-24 10:14:23 +02002803#ifdef MCUBOOT_RAM_LOADING
Raef Coles27a61452019-09-25 15:32:25 +01002804 BOOT_LOG_INF("Booting image from SRAM at address 0x%x",
2805 selected_image_header->ih_load_addr);
2806#else
2807 BOOT_LOG_INF("Booting image from the %s slot",
2808 (slot == BOOT_PRIMARY_SLOT) ? "primary" : "secondary");
2809#endif /* MCUBOOT_RAM_LOADING */
Oliver Swedef9982442018-08-24 18:37:44 +01002810
Raef Coles27a61452019-09-25 15:32:25 +01002811 rsp->br_hdr = selected_image_header;
David Vinczecea8b592019-10-29 16:09:51 +01002812 rsp->br_image_off = boot_img_slot_off(state, slot);
2813 rsp->br_flash_dev_id = BOOT_IMG_AREA(state, slot)->fa_device_id;
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002814 } else {
2815 /* No candidate image available */
2816 rc = BOOT_EBADIMAGE;
David Vincze060968d2019-05-23 01:13:14 +02002817 goto out;
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002818 }
2819
Tamas Ban0e8ab302019-01-17 11:45:31 +00002820 /* Save boot status to shared memory area */
2821 rc = boot_save_boot_status(SW_S_NS,
2822 rsp->br_hdr,
David Vinczecea8b592019-10-29 16:09:51 +01002823 BOOT_IMG_AREA(state, slot));
Tamas Ban0e8ab302019-01-17 11:45:31 +00002824 if (rc) {
2825 BOOT_LOG_ERR("Failed to add data to shared area");
2826 }
2827
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002828out:
2829 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
David Vinczecea8b592019-10-29 16:09:51 +01002830 flash_area_close(BOOT_IMG_AREA(state, BOOT_NUM_SLOTS - 1 - slot));
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002831 }
2832 return rc;
2833}
Oliver Swedef9982442018-08-24 18:37:44 +01002834#endif /* MCUBOOT_NO_SWAP || MCUBOOT_RAM_LOADING */
David Vinczecea8b592019-10-29 16:09:51 +01002835
2836int
2837boot_go(struct boot_rsp *rsp)
2838{
2839 return context_boot_go(&boot_data, rsp);
Robert Rostohar4b630372019-12-23 13:24:50 +01002840}