blob: e60467744ad50e1c12ec1dba69d8f3deba8a09b3 [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"
Tamas Banf70ef8c2017-12-19 15:35:09 +000048
Tamas Banf70ef8c2017-12-19 15:35:09 +000049static struct boot_loader_state boot_data;
David Vinczecea8b592019-10-29 16:09:51 +010050
51#if (BOOT_IMAGE_NUMBER > 1)
52#define IMAGES_ITER(x) for ((x) = 0; (x) < BOOT_IMAGE_NUMBER; ++(x))
53#else
54#define IMAGES_ITER(x)
55#endif
Tamas Banf70ef8c2017-12-19 15:35:09 +000056
Oliver Swedef9982442018-08-24 18:37:44 +010057#if !defined(MCUBOOT_NO_SWAP) && !defined(MCUBOOT_RAM_LOADING)
David Vincze39e78552018-10-10 17:10:01 +020058
David Vincze8bdfc2d2019-03-18 15:49:23 +010059#if defined(MCUBOOT_VALIDATE_PRIMARY_SLOT) && !defined(MCUBOOT_OVERWRITE_ONLY)
David Vincze39e78552018-10-10 17:10:01 +020060static int boot_status_fails = 0;
61#define BOOT_STATUS_ASSERT(x) \
62 do { \
63 if (!(x)) { \
64 boot_status_fails++; \
65 } \
66 } while (0)
67#else
David Vincze401c7422019-06-21 20:44:05 +020068#define BOOT_STATUS_ASSERT(x) ASSERT(x)
David Vincze39e78552018-10-10 17:10:01 +020069#endif
70
Tamas Banf70ef8c2017-12-19 15:35:09 +000071struct boot_status_table {
David Vincze8bdfc2d2019-03-18 15:49:23 +010072 uint8_t bst_magic_primary_slot;
Tamas Banf70ef8c2017-12-19 15:35:09 +000073 uint8_t bst_magic_scratch;
David Vincze8bdfc2d2019-03-18 15:49:23 +010074 uint8_t bst_copy_done_primary_slot;
Tamas Banf70ef8c2017-12-19 15:35:09 +000075 uint8_t bst_status_source;
76};
77
78/**
79 * This set of tables maps swap state contents to boot status location.
80 * When searching for a match, these tables must be iterated in order.
81 */
82static const struct boot_status_table boot_status_tables[] = {
83 {
David Vincze8bdfc2d2019-03-18 15:49:23 +010084 /* | primary slot | scratch |
85 * ----------+--------------+--------------|
86 * magic | Good | Any |
87 * copy-done | Set | N/A |
88 * ----------+--------------+--------------'
89 * source: none |
90 * ----------------------------------------'
Tamas Banf70ef8c2017-12-19 15:35:09 +000091 */
David Vincze8bdfc2d2019-03-18 15:49:23 +010092 .bst_magic_primary_slot = BOOT_MAGIC_GOOD,
David Vincze401c7422019-06-21 20:44:05 +020093 .bst_magic_scratch = BOOT_MAGIC_NOTGOOD,
David Vincze8bdfc2d2019-03-18 15:49:23 +010094 .bst_copy_done_primary_slot = BOOT_FLAG_SET,
95 .bst_status_source = BOOT_STATUS_SOURCE_NONE,
Tamas Banf70ef8c2017-12-19 15:35:09 +000096 },
97
98 {
David Vincze8bdfc2d2019-03-18 15:49:23 +010099 /* | primary slot | scratch |
100 * ----------+--------------+--------------|
101 * magic | Good | Any |
102 * copy-done | Unset | N/A |
103 * ----------+--------------+--------------'
104 * source: primary slot |
105 * ----------------------------------------'
Tamas Banf70ef8c2017-12-19 15:35:09 +0000106 */
David Vincze8bdfc2d2019-03-18 15:49:23 +0100107 .bst_magic_primary_slot = BOOT_MAGIC_GOOD,
David Vincze401c7422019-06-21 20:44:05 +0200108 .bst_magic_scratch = BOOT_MAGIC_NOTGOOD,
David Vincze8bdfc2d2019-03-18 15:49:23 +0100109 .bst_copy_done_primary_slot = BOOT_FLAG_UNSET,
110 .bst_status_source = BOOT_STATUS_SOURCE_PRIMARY_SLOT,
Tamas Banf70ef8c2017-12-19 15:35:09 +0000111 },
112
113 {
David Vincze8bdfc2d2019-03-18 15:49:23 +0100114 /* | primary slot | scratch |
115 * ----------+--------------+--------------|
116 * magic | Any | Good |
117 * copy-done | Any | N/A |
118 * ----------+--------------+--------------'
119 * source: scratch |
120 * ----------------------------------------'
Tamas Banf70ef8c2017-12-19 15:35:09 +0000121 */
David Vincze8bdfc2d2019-03-18 15:49:23 +0100122 .bst_magic_primary_slot = BOOT_MAGIC_ANY,
123 .bst_magic_scratch = BOOT_MAGIC_GOOD,
124 .bst_copy_done_primary_slot = BOOT_FLAG_ANY,
125 .bst_status_source = BOOT_STATUS_SOURCE_SCRATCH,
Tamas Banf70ef8c2017-12-19 15:35:09 +0000126 },
127
128 {
David Vincze8bdfc2d2019-03-18 15:49:23 +0100129 /* | primary slot | scratch |
130 * ----------+--------------+--------------|
131 * magic | Unset | Any |
132 * copy-done | Unset | N/A |
133 * ----------+--------------+--------------|
134 * source: varies |
135 * ----------------------------------------+--------------------------+
Tamas Banf70ef8c2017-12-19 15:35:09 +0000136 * This represents one of two cases: |
137 * o No swaps ever (no status to read, so no harm in checking). |
David Vincze8bdfc2d2019-03-18 15:49:23 +0100138 * o Mid-revert; status in the primary slot. |
Tamas Banf70ef8c2017-12-19 15:35:09 +0000139 * -------------------------------------------------------------------'
140 */
David Vincze8bdfc2d2019-03-18 15:49:23 +0100141 .bst_magic_primary_slot = BOOT_MAGIC_UNSET,
142 .bst_magic_scratch = BOOT_MAGIC_ANY,
143 .bst_copy_done_primary_slot = BOOT_FLAG_UNSET,
144 .bst_status_source = BOOT_STATUS_SOURCE_PRIMARY_SLOT,
Tamas Banf70ef8c2017-12-19 15:35:09 +0000145 },
146};
147
148#define BOOT_STATUS_TABLES_COUNT \
Tamas Ban581034a2017-12-19 19:54:37 +0000149 (sizeof(boot_status_tables) / sizeof(boot_status_tables[0]))
Tamas Banf70ef8c2017-12-19 15:35:09 +0000150
151#define BOOT_LOG_SWAP_STATE(area, state) \
David Vincze401c7422019-06-21 20:44:05 +0200152 BOOT_LOG_INF("%s: magic=%5s, swap_type=0x%x, copy_done=0x%x, " \
153 "image_ok=0x%x", \
Tamas Banf70ef8c2017-12-19 15:35:09 +0000154 (area), \
155 ((state)->magic == BOOT_MAGIC_GOOD ? "good" : \
156 (state)->magic == BOOT_MAGIC_UNSET ? "unset" : \
157 "bad"), \
David Vincze401c7422019-06-21 20:44:05 +0200158 (state)->swap_type, \
Tamas Banf70ef8c2017-12-19 15:35:09 +0000159 (state)->copy_done, \
160 (state)->image_ok)
Oliver Swedef9982442018-08-24 18:37:44 +0100161#endif /* !MCUBOOT_NO_SWAP && !MCUBOOT_RAM_LOADING */
Tamas Banf70ef8c2017-12-19 15:35:09 +0000162
Tamas Ban056ed0b2019-09-16 12:48:32 +0100163/*
164 * \brief Verifies the image header: magic value, flags, integer overflow.
165 *
166 * \retval 0
167 * \retval BOOT_EBADIMAGE
168 */
169static int
170boot_verify_image_header(struct image_header *hdr)
171{
172 uint32_t image_end;
David Vincze0dc41d22019-10-28 14:56:29 +0100173 uint32_t x;
Tamas Ban056ed0b2019-09-16 12:48:32 +0100174
175 if (hdr->ih_magic != IMAGE_MAGIC) {
176 return BOOT_EBADIMAGE;
177 }
178
179 /* Check input parameters against integer overflow */
David Vincze0dc41d22019-10-28 14:56:29 +0100180 if (!boot_u32_safe_add(&image_end, hdr->ih_hdr_size, hdr->ih_img_size)) {
Tamas Ban056ed0b2019-09-16 12:48:32 +0100181 return BOOT_EBADIMAGE;
182 }
183
David Vincze0dc41d22019-10-28 14:56:29 +0100184 if (!boot_u32_safe_add(&x, image_end, hdr->ih_protect_tlv_size)) {
Tamas Ban056ed0b2019-09-16 12:48:32 +0100185 return BOOT_EBADIMAGE;
186 }
187
Tamas Ban056ed0b2019-09-16 12:48:32 +0100188#if MCUBOOT_RAM_LOADING
189 if (!(hdr->ih_flags & IMAGE_F_RAM_LOAD)) {
190 return BOOT_EBADIMAGE;
191 }
192
193 /* Check input parameters against integer overflow */
David Vincze0dc41d22019-10-28 14:56:29 +0100194 if (!boot_u32_safe_add(&x, image_end, hdr->ih_load_addr)) {
Tamas Ban056ed0b2019-09-16 12:48:32 +0100195 return BOOT_EBADIMAGE;
196 }
197#endif
198
199 return 0;
200}
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000201
202static int
David Vinczecea8b592019-10-29 16:09:51 +0100203boot_read_image_header(struct boot_loader_state *state, int slot,
204 struct image_header *out_hdr)
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000205{
206 const struct flash_area *fap = NULL;
207 int area_id;
208 int rc;
209
David Vinczecea8b592019-10-29 16:09:51 +0100210#if (BOOT_IMAGE_NUMBER == 1)
211 (void)state;
212#endif
213
214 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000215 rc = flash_area_open(area_id, &fap);
216 if (rc != 0) {
217 rc = BOOT_EFLASH;
218 goto done;
219 }
220
221 rc = flash_area_read(fap, 0, out_hdr, sizeof(*out_hdr));
222 if (rc != 0) {
223 rc = BOOT_EFLASH;
224 goto done;
225 }
226
Tamas Ban056ed0b2019-09-16 12:48:32 +0100227 rc = boot_verify_image_header(out_hdr);
David Vinczecea8b592019-10-29 16:09:51 +0100228 BOOT_IMG_HDR_IS_VALID(state, slot) = (rc == 0);
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000229
230done:
231 flash_area_close(fap);
232 return rc;
233}
234
235static int
David Vinczecea8b592019-10-29 16:09:51 +0100236boot_read_image_headers(struct boot_loader_state *state, bool require_all)
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000237{
238 int rc;
239 int i;
240
241 for (i = 0; i < BOOT_NUM_SLOTS; i++) {
David Vinczecea8b592019-10-29 16:09:51 +0100242 rc = boot_read_image_header(state, i, boot_img_hdr(state, i));
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000243 if (rc != 0) {
David Vincze39e78552018-10-10 17:10:01 +0200244 /* If `require_all` is set, fail on any single fail, otherwise
245 * if at least the first slot's header was read successfully,
246 * then the boot loader can attempt a boot.
247 *
248 * Failure to read any headers is a fatal error.
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000249 */
David Vincze39e78552018-10-10 17:10:01 +0200250 if (i > 0 && !require_all) {
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000251 return 0;
252 } else {
253 return rc;
254 }
255 }
256 }
257
258 return 0;
259}
260
Raef Coles204c5b42019-09-05 09:18:47 +0100261static uint32_t
David Vinczecea8b592019-10-29 16:09:51 +0100262boot_write_sz(struct boot_loader_state *state)
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000263{
Raef Coles204c5b42019-09-05 09:18:47 +0100264 uint32_t elem_sz;
265 uint32_t align;
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000266
267 /* Figure out what size to write update status update as. The size depends
268 * on what the minimum write size is for scratch area, active image slot.
269 * We need to use the bigger of those 2 values.
270 */
David Vinczecea8b592019-10-29 16:09:51 +0100271 elem_sz = flash_area_align(BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT));
272 align = flash_area_align(BOOT_SCRATCH_AREA(state));
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000273 if (align > elem_sz) {
274 elem_sz = align;
275 }
276
277 return elem_sz;
278}
279
David Vinczecea8b592019-10-29 16:09:51 +0100280#ifndef MCUBOOT_USE_FLASH_AREA_GET_SECTORS
281static int
282boot_initialize_area(struct boot_loader_state *state, int flash_area)
283{
284 int num_sectors = BOOT_MAX_IMG_SECTORS;
285 int rc;
286
287 if (flash_area == FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state))) {
288 rc = flash_area_to_sectors(flash_area, &num_sectors,
289 BOOT_IMG(state, BOOT_PRIMARY_SLOT).sectors);
290 BOOT_IMG(state, BOOT_PRIMARY_SLOT).num_sectors = (size_t)num_sectors;
291
292 } else if (flash_area == FLASH_AREA_IMAGE_SECONDARY(BOOT_CURR_IMG(state))) {
293 rc = flash_area_to_sectors(flash_area, &num_sectors,
294 BOOT_IMG(state, BOOT_SECONDARY_SLOT).sectors);
295 BOOT_IMG(state, BOOT_SECONDARY_SLOT).num_sectors = (size_t)num_sectors;
296
297 } else if (flash_area == FLASH_AREA_IMAGE_SCRATCH) {
298 rc = flash_area_to_sectors(flash_area, &num_sectors,
299 state->scratch.sectors);
300 state->scratch.num_sectors = (size_t)num_sectors;
301 } else {
302 return BOOT_EFLASH;
303 }
304
305 return rc;
306}
307#else /* defined(MCUBOOT_USE_FLASH_AREA_GET_SECTORS) */
308static int
309boot_initialize_area(struct boot_loader_state *state, int flash_area)
310{
311 uint32_t num_sectors;
312 struct flash_sector *out_sectors;
313 size_t *out_num_sectors;
314 int rc;
315
316 num_sectors = BOOT_MAX_IMG_SECTORS;
317
318 if (flash_area == FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state))) {
319 out_sectors = BOOT_IMG(state, BOOT_PRIMARY_SLOT).sectors;
320 out_num_sectors = &BOOT_IMG(state, BOOT_PRIMARY_SLOT).num_sectors;
321 } else if (flash_area == FLASH_AREA_IMAGE_SECONDARY(BOOT_CURR_IMG(state))) {
322 out_sectors = BOOT_IMG(state, BOOT_SECONDARY_SLOT).sectors;
323 out_num_sectors = &BOOT_IMG(state, BOOT_SECONDARY_SLOT).num_sectors;
324 } else if (flash_area == FLASH_AREA_IMAGE_SCRATCH) {
325 out_sectors = state->scratch.sectors;
326 out_num_sectors = &state->scratch.num_sectors;
327 } else {
328 return BOOT_EFLASH;
329 }
330
331 rc = flash_area_get_sectors(flash_area, &num_sectors, out_sectors);
332 if (rc != 0) {
333 return rc;
334 }
335 *out_num_sectors = num_sectors;
336 return 0;
337}
338#endif /* !defined(MCUBOOT_USE_FLASH_AREA_GET_SECTORS) */
339
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000340/**
341 * Determines the sector layout of both image slots and the scratch area.
342 * This information is necessary for calculating the number of bytes to erase
343 * and copy during an image swap. The information collected during this
David Vinczecea8b592019-10-29 16:09:51 +0100344 * function is used to populate the state.
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000345 */
346static int
David Vinczecea8b592019-10-29 16:09:51 +0100347boot_read_sectors(struct boot_loader_state *state)
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000348{
David Vinczecea8b592019-10-29 16:09:51 +0100349 uint8_t image_index;
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000350 int rc;
351
David Vinczecea8b592019-10-29 16:09:51 +0100352 image_index = BOOT_CURR_IMG(state);
353
354 rc = boot_initialize_area(state, FLASH_AREA_IMAGE_PRIMARY(image_index));
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000355 if (rc != 0) {
356 return BOOT_EFLASH;
357 }
358
David Vinczecea8b592019-10-29 16:09:51 +0100359 rc = boot_initialize_area(state, FLASH_AREA_IMAGE_SECONDARY(image_index));
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000360 if (rc != 0) {
361 return BOOT_EFLASH;
362 }
363
David Vinczecea8b592019-10-29 16:09:51 +0100364 rc = boot_initialize_area(state, FLASH_AREA_IMAGE_SCRATCH);
David Vincze401c7422019-06-21 20:44:05 +0200365 if (rc != 0) {
366 return BOOT_EFLASH;
367 }
368
David Vinczecea8b592019-10-29 16:09:51 +0100369 BOOT_WRITE_SZ(state) = boot_write_sz(state);
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000370
371 return 0;
372}
373
David Vincze060968d2019-05-23 01:13:14 +0200374/**
375 * Validate image hash/signature and security counter in a slot.
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000376 */
377static int
David Vinczecea8b592019-10-29 16:09:51 +0100378boot_image_check(struct boot_loader_state *state, struct image_header *hdr,
379 const struct flash_area *fap, struct boot_status *bs)
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000380{
381 static uint8_t tmpbuf[BOOT_TMPBUF_SZ];
David Vinczecea8b592019-10-29 16:09:51 +0100382 uint8_t image_index;
383
384#if (BOOT_IMAGE_NUMBER == 1)
385 (void)state;
386#endif
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000387
David Vincze401c7422019-06-21 20:44:05 +0200388 (void)bs;
389
David Vinczecea8b592019-10-29 16:09:51 +0100390 image_index = BOOT_CURR_IMG(state);
391
392 if (bootutil_img_validate(image_index, hdr, fap, tmpbuf,
393 BOOT_TMPBUF_SZ, NULL, 0, NULL)) {
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000394 return BOOT_EBADIMAGE;
395 }
David Vinczecea8b592019-10-29 16:09:51 +0100396
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000397 return 0;
398}
399
David Vincze401c7422019-06-21 20:44:05 +0200400/*
401 * Check that a memory area consists of a given value.
402 */
403static inline bool
404boot_data_is_set_to(uint8_t val, void *data, size_t len)
David Vincze39e78552018-10-10 17:10:01 +0200405{
406 uint8_t i;
David Vincze401c7422019-06-21 20:44:05 +0200407 uint8_t *p = (uint8_t *)data;
408 for (i = 0; i < len; i++) {
409 if (val != p[i]) {
410 return false;
David Vincze39e78552018-10-10 17:10:01 +0200411 }
412 }
David Vincze401c7422019-06-21 20:44:05 +0200413 return true;
David Vincze39e78552018-10-10 17:10:01 +0200414}
415
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000416static int
David Vinczecea8b592019-10-29 16:09:51 +0100417boot_check_header_erased(struct boot_loader_state *state, int slot)
David Vincze401c7422019-06-21 20:44:05 +0200418{
419 const struct flash_area *fap;
420 struct image_header *hdr;
421 uint8_t erased_val;
David Vinczecea8b592019-10-29 16:09:51 +0100422 int area_id;
David Vincze401c7422019-06-21 20:44:05 +0200423 int rc;
424
David Vinczecea8b592019-10-29 16:09:51 +0100425 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
426 rc = flash_area_open(area_id, &fap);
David Vincze401c7422019-06-21 20:44:05 +0200427 if (rc != 0) {
428 return -1;
429 }
430
431 erased_val = flash_area_erased_val(fap);
432 flash_area_close(fap);
433
David Vinczecea8b592019-10-29 16:09:51 +0100434 hdr = boot_img_hdr(state, slot);
David Vincze401c7422019-06-21 20:44:05 +0200435 if (!boot_data_is_set_to(erased_val, &hdr->ih_magic,
436 sizeof(hdr->ih_magic))) {
437 return -1;
438 }
439
440 return 0;
441}
442
David Vinczecea8b592019-10-29 16:09:51 +0100443/*
444 * Check that there is a valid image in a slot
445 *
446 * @returns
447 * 0 if image was succesfully validated
448 * 1 if no bootloable image was found
449 * -1 on any errors
450 */
David Vincze401c7422019-06-21 20:44:05 +0200451static int
David Vinczecea8b592019-10-29 16:09:51 +0100452boot_validate_slot(struct boot_loader_state *state, int slot,
453 struct boot_status *bs)
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000454{
455 const struct flash_area *fap;
456 struct image_header *hdr;
David Vinczecea8b592019-10-29 16:09:51 +0100457 int area_id;
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000458 int rc;
459
David Vinczecea8b592019-10-29 16:09:51 +0100460 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
461 rc = flash_area_open(area_id, &fap);
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000462 if (rc != 0) {
David Vinczecea8b592019-10-29 16:09:51 +0100463 return -1;
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000464 }
465
David Vinczecea8b592019-10-29 16:09:51 +0100466 hdr = boot_img_hdr(state, slot);
467 if ((boot_check_header_erased(state, slot) == 0) ||
David Vincze401c7422019-06-21 20:44:05 +0200468 (hdr->ih_flags & IMAGE_F_NON_BOOTABLE)) {
David Vincze8bdfc2d2019-03-18 15:49:23 +0100469 /* No bootable image in slot; continue booting from the primary slot. */
David Vinczecea8b592019-10-29 16:09:51 +0100470 rc = 1;
David Vincze401c7422019-06-21 20:44:05 +0200471 goto out;
David Vincze39e78552018-10-10 17:10:01 +0200472 }
473
David Vinczecea8b592019-10-29 16:09:51 +0100474 if ((!BOOT_IMG_HDR_IS_VALID(state, slot)) ||
475 (boot_image_check(state, hdr, fap, bs) != 0)) {
David Vincze401c7422019-06-21 20:44:05 +0200476 if (slot != BOOT_PRIMARY_SLOT) {
David Vinczecea8b592019-10-29 16:09:51 +0100477 flash_area_erase(fap, 0, fap->fa_size);
David Vincze8bdfc2d2019-03-18 15:49:23 +0100478 /* Image in the secondary slot is invalid. Erase the image and
479 * continue booting from the primary slot.
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000480 */
481 }
David Vinczecea8b592019-10-29 16:09:51 +0100482 BOOT_LOG_ERR("Image in the %s slot is not valid!",
483 (slot == BOOT_PRIMARY_SLOT) ? "primary" : "secondary");
David Vincze401c7422019-06-21 20:44:05 +0200484 rc = -1;
485 goto out;
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000486 }
487
David Vincze8bdfc2d2019-03-18 15:49:23 +0100488 /* Image in the secondary slot is valid. */
David Vincze401c7422019-06-21 20:44:05 +0200489 rc = 0;
490
491out:
492 flash_area_close(fap);
493 return rc;
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000494}
495
David Vincze060968d2019-05-23 01:13:14 +0200496/**
497 * Updates the stored security counter value with the image's security counter
498 * value which resides in the given slot if it's greater than the stored value.
499 *
David Vinczecea8b592019-10-29 16:09:51 +0100500 * @param image_index Index of the image to determine which security
501 * counter to update.
502 * @param slot Slot number of the image.
503 * @param hdr Pointer to the image header structure of the image
504 * that is currently stored in the given slot.
David Vincze060968d2019-05-23 01:13:14 +0200505 *
David Vinczecea8b592019-10-29 16:09:51 +0100506 * @return 0 on success; nonzero on failure.
David Vincze060968d2019-05-23 01:13:14 +0200507 */
508static int
David Vinczecea8b592019-10-29 16:09:51 +0100509boot_update_security_counter(uint8_t image_index, int slot,
510 struct image_header *hdr)
David Vincze060968d2019-05-23 01:13:14 +0200511{
512 const struct flash_area *fap = NULL;
513 uint32_t img_security_cnt;
514 int rc;
515
David Vinczecea8b592019-10-29 16:09:51 +0100516 rc = flash_area_open(flash_area_id_from_multi_image_slot(image_index, slot),
517 &fap);
David Vincze060968d2019-05-23 01:13:14 +0200518 if (rc != 0) {
519 rc = BOOT_EFLASH;
520 goto done;
521 }
522
523 rc = bootutil_get_img_security_cnt(hdr, fap, &img_security_cnt);
524 if (rc != 0) {
525 goto done;
526 }
527
David Vinczecea8b592019-10-29 16:09:51 +0100528 rc = boot_nv_security_counter_update(image_index, img_security_cnt);
David Vincze060968d2019-05-23 01:13:14 +0200529 if (rc != 0) {
530 goto done;
531 }
532
533done:
534 flash_area_close(fap);
535 return rc;
536}
537
Oliver Swedef9982442018-08-24 18:37:44 +0100538#if !defined(MCUBOOT_NO_SWAP) && !defined(MCUBOOT_OVERWRITE_ONLY)
539/*
540 * Compute the total size of the given image. Includes the size of
541 * the TLVs.
542 */
543static int
David Vinczecea8b592019-10-29 16:09:51 +0100544boot_read_image_size(struct boot_loader_state *state, int slot, uint32_t *size)
Oliver Swedef9982442018-08-24 18:37:44 +0100545{
546 const struct flash_area *fap = NULL;
David Vincze07706a42019-12-12 18:20:12 +0100547 struct image_tlv_info info;
David Vinczecea8b592019-10-29 16:09:51 +0100548 uint32_t off;
David Vincze61bd1e52019-10-24 16:47:31 +0200549 uint32_t protect_tlv_size;
Oliver Swedef9982442018-08-24 18:37:44 +0100550 int area_id;
551 int rc;
552
David Vinczecea8b592019-10-29 16:09:51 +0100553#if (BOOT_IMAGE_NUMBER == 1)
554 (void)state;
555#endif
556
557 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
Oliver Swedef9982442018-08-24 18:37:44 +0100558 rc = flash_area_open(area_id, &fap);
559 if (rc != 0) {
560 rc = BOOT_EFLASH;
561 goto done;
562 }
563
David Vincze07706a42019-12-12 18:20:12 +0100564 off = BOOT_TLV_OFF(boot_img_hdr(state, slot));
565
566 if (flash_area_read(fap, off, &info, sizeof(info))) {
567 rc = BOOT_EFLASH;
Oliver Swedef9982442018-08-24 18:37:44 +0100568 goto done;
569 }
David Vincze07706a42019-12-12 18:20:12 +0100570
David Vincze61bd1e52019-10-24 16:47:31 +0200571 protect_tlv_size = boot_img_hdr(state, slot)->ih_protect_tlv_size;
572 if (info.it_magic == IMAGE_TLV_PROT_INFO_MAGIC) {
573 if (protect_tlv_size != info.it_tlv_tot) {
574 rc = BOOT_EBADIMAGE;
575 goto done;
576 }
577
578 if (flash_area_read(fap, off + info.it_tlv_tot, &info, sizeof(info))) {
579 rc = BOOT_EFLASH;
580 goto done;
581 }
582 } else if (protect_tlv_size != 0) {
583 rc = BOOT_EBADIMAGE;
584 goto done;
585 }
586
David Vincze07706a42019-12-12 18:20:12 +0100587 if (info.it_magic != IMAGE_TLV_INFO_MAGIC) {
588 rc = BOOT_EBADIMAGE;
589 goto done;
590 }
591
David Vincze61bd1e52019-10-24 16:47:31 +0200592 *size = off + protect_tlv_size + info.it_tlv_tot;
Oliver Swedef9982442018-08-24 18:37:44 +0100593 rc = 0;
594
595done:
596 flash_area_close(fap);
597 return rc;
598}
599#endif /* !MCUBOOT_NO_SWAP && !MCUBOOT_OVERWRITE_ONLY */
600
601#if !defined(MCUBOOT_NO_SWAP) && !defined(MCUBOOT_RAM_LOADING)
Tamas Banf70ef8c2017-12-19 15:35:09 +0000602/**
Tamas Ban581034a2017-12-19 19:54:37 +0000603 * Determines where in flash the most recent boot status is stored. The boot
Tamas Banf70ef8c2017-12-19 15:35:09 +0000604 * status is necessary for completing a swap that was interrupted by a boot
605 * loader reset.
606 *
David Vincze401c7422019-06-21 20:44:05 +0200607 * @return A BOOT_STATUS_SOURCE_[...] code indicating where status should
608 * be read from.
Tamas Banf70ef8c2017-12-19 15:35:09 +0000609 */
610static int
David Vinczecea8b592019-10-29 16:09:51 +0100611boot_status_source(struct boot_loader_state *state)
Tamas Banf70ef8c2017-12-19 15:35:09 +0000612{
613 const struct boot_status_table *table;
614 struct boot_swap_state state_scratch;
David Vincze8bdfc2d2019-03-18 15:49:23 +0100615 struct boot_swap_state state_primary_slot;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000616 int rc;
David Vincze39e78552018-10-10 17:10:01 +0200617 size_t i;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000618 uint8_t source;
David Vinczecea8b592019-10-29 16:09:51 +0100619 uint8_t image_index;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000620
David Vinczecea8b592019-10-29 16:09:51 +0100621#if (BOOT_IMAGE_NUMBER == 1)
622 (void)state;
623#endif
624
625 image_index = BOOT_CURR_IMG(state);
626 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_PRIMARY(image_index),
627 &state_primary_slot);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000628 assert(rc == 0);
629
630 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SCRATCH, &state_scratch);
631 assert(rc == 0);
632
David Vincze401c7422019-06-21 20:44:05 +0200633 BOOT_LOG_SWAP_STATE("Primary image", &state_primary_slot);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000634 BOOT_LOG_SWAP_STATE("Scratch", &state_scratch);
635
636 for (i = 0; i < BOOT_STATUS_TABLES_COUNT; i++) {
637 table = &boot_status_tables[i];
638
David Vincze401c7422019-06-21 20:44:05 +0200639 if (boot_magic_compatible_check(table->bst_magic_primary_slot,
640 state_primary_slot.magic) &&
641 boot_magic_compatible_check(table->bst_magic_scratch,
642 state_scratch.magic) &&
David Vincze8bdfc2d2019-03-18 15:49:23 +0100643 (table->bst_copy_done_primary_slot == BOOT_FLAG_ANY ||
644 table->bst_copy_done_primary_slot == state_primary_slot.copy_done))
645 {
Tamas Banf70ef8c2017-12-19 15:35:09 +0000646 source = table->bst_status_source;
David Vincze7384ee72019-07-23 17:00:42 +0200647
648#if (BOOT_IMAGE_NUMBER > 1)
649 /* In case of multi-image boot it can happen that if boot status
650 * info is found on scratch area then it does not belong to the
651 * currently examined image.
652 */
653 if (source == BOOT_STATUS_SOURCE_SCRATCH &&
David Vinczecea8b592019-10-29 16:09:51 +0100654 state_scratch.image_num != BOOT_CURR_IMG(state)) {
David Vincze7384ee72019-07-23 17:00:42 +0200655 source = BOOT_STATUS_SOURCE_NONE;
656 }
657#endif
658
Tamas Banf70ef8c2017-12-19 15:35:09 +0000659 BOOT_LOG_INF("Boot source: %s",
660 source == BOOT_STATUS_SOURCE_NONE ? "none" :
661 source == BOOT_STATUS_SOURCE_SCRATCH ? "scratch" :
David Vincze8bdfc2d2019-03-18 15:49:23 +0100662 source == BOOT_STATUS_SOURCE_PRIMARY_SLOT ?
663 "primary slot" : "BUG; can't happen");
Tamas Banf70ef8c2017-12-19 15:35:09 +0000664 return source;
665 }
666 }
667
668 BOOT_LOG_INF("Boot source: none");
669 return BOOT_STATUS_SOURCE_NONE;
670}
671
David Vincze401c7422019-06-21 20:44:05 +0200672/*
David Vincze4af67832019-12-11 18:31:34 +0100673 * Slots are compatible when all sectors that store up to to size of the image
David Vincze401c7422019-06-21 20:44:05 +0200674 * round up to sector size, in both slot's are able to fit in the scratch
675 * area, and have sizes that are a multiple of each other (powers of two
676 * presumably!).
Tamas Banf70ef8c2017-12-19 15:35:09 +0000677 */
678static int
David Vinczecea8b592019-10-29 16:09:51 +0100679boot_slots_compatible(struct boot_loader_state *state)
Tamas Banf70ef8c2017-12-19 15:35:09 +0000680{
David Vincze401c7422019-06-21 20:44:05 +0200681 size_t num_sectors_primary;
682 size_t num_sectors_secondary;
683 size_t sz0, sz1;
684 size_t primary_slot_sz, secondary_slot_sz;
David Vincze4af67832019-12-11 18:31:34 +0100685#ifndef MCUBOOT_OVERWRITE_ONLY
David Vincze401c7422019-06-21 20:44:05 +0200686 size_t scratch_sz;
David Vincze4af67832019-12-11 18:31:34 +0100687#endif
David Vincze401c7422019-06-21 20:44:05 +0200688 size_t i, j;
689 int8_t smaller;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000690
David Vinczecea8b592019-10-29 16:09:51 +0100691 num_sectors_primary = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT);
692 num_sectors_secondary = boot_img_num_sectors(state, BOOT_SECONDARY_SLOT);
David Vincze401c7422019-06-21 20:44:05 +0200693 if ((num_sectors_primary > BOOT_MAX_IMG_SECTORS) ||
694 (num_sectors_secondary > BOOT_MAX_IMG_SECTORS)) {
David Vincze39e78552018-10-10 17:10:01 +0200695 BOOT_LOG_WRN("Cannot upgrade: more sectors than allowed");
Tamas Banf70ef8c2017-12-19 15:35:09 +0000696 return 0;
697 }
David Vincze39e78552018-10-10 17:10:01 +0200698
David Vincze4af67832019-12-11 18:31:34 +0100699#ifndef MCUBOOT_OVERWRITE_ONLY
David Vinczecea8b592019-10-29 16:09:51 +0100700 scratch_sz = boot_scratch_area_size(state);
David Vincze4af67832019-12-11 18:31:34 +0100701#endif
David Vincze401c7422019-06-21 20:44:05 +0200702
703 /*
704 * The following loop scans all sectors in a linear fashion, assuring that
705 * for each possible sector in each slot, it is able to fit in the other
706 * slot's sector or sectors. Slot's should be compatible as long as any
707 * number of a slot's sectors are able to fit into another, which only
708 * excludes cases where sector sizes are not a multiple of each other.
709 */
710 i = sz0 = primary_slot_sz = 0;
711 j = sz1 = secondary_slot_sz = 0;
712 smaller = 0;
713 while (i < num_sectors_primary || j < num_sectors_secondary) {
714 if (sz0 == sz1) {
David Vinczecea8b592019-10-29 16:09:51 +0100715 sz0 += boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i);
716 sz1 += boot_img_sector_size(state, BOOT_SECONDARY_SLOT, j);
David Vincze401c7422019-06-21 20:44:05 +0200717 i++;
718 j++;
719 } else if (sz0 < sz1) {
David Vinczecea8b592019-10-29 16:09:51 +0100720 sz0 += boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i);
David Vincze401c7422019-06-21 20:44:05 +0200721 /* Guarantee that multiple sectors of the secondary slot
722 * fit into the primary slot.
723 */
724 if (smaller == 2) {
725 BOOT_LOG_WRN("Cannot upgrade: slots have non-compatible"
726 " sectors");
727 return 0;
728 }
729 smaller = 1;
730 i++;
731 } else {
David Vinczecea8b592019-10-29 16:09:51 +0100732 sz1 += boot_img_sector_size(state, BOOT_SECONDARY_SLOT, j);
David Vincze401c7422019-06-21 20:44:05 +0200733 /* Guarantee that multiple sectors of the primary slot
734 * fit into the secondary slot.
735 */
736 if (smaller == 1) {
737 BOOT_LOG_WRN("Cannot upgrade: slots have non-compatible"
738 " sectors");
739 return 0;
740 }
741 smaller = 2;
742 j++;
743 }
David Vincze4af67832019-12-11 18:31:34 +0100744#ifndef MCUBOOT_OVERWRITE_ONLY
David Vincze401c7422019-06-21 20:44:05 +0200745 if (sz0 == sz1) {
746 primary_slot_sz += sz0;
747 secondary_slot_sz += sz1;
748 /* Scratch has to fit each swap operation to the size of the larger
749 * sector among the primary slot and the secondary slot.
750 */
751 if (sz0 > scratch_sz || sz1 > scratch_sz) {
752 BOOT_LOG_WRN("Cannot upgrade: not all sectors fit inside"
753 " scratch");
754 return 0;
755 }
756 smaller = sz0 = sz1 = 0;
757 }
David Vincze4af67832019-12-11 18:31:34 +0100758#endif
David Vincze39e78552018-10-10 17:10:01 +0200759 }
760
David Vincze401c7422019-06-21 20:44:05 +0200761 if ((i != num_sectors_primary) ||
762 (j != num_sectors_secondary) ||
763 (primary_slot_sz != secondary_slot_sz)) {
764 BOOT_LOG_WRN("Cannot upgrade: slots are not compatible");
765 return 0;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000766 }
767
768 return 1;
769}
770
Tamas Banf70ef8c2017-12-19 15:35:09 +0000771static uint32_t
772boot_status_internal_off(int idx, int state, int elem_sz)
773{
774 int idx_sz;
775
776 idx_sz = elem_sz * BOOT_STATUS_STATE_COUNT;
777
David Vincze39e78552018-10-10 17:10:01 +0200778 return (idx - BOOT_STATUS_IDX_0) * idx_sz +
779 (state - BOOT_STATUS_STATE_0) * elem_sz;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000780}
781
782/**
783 * Reads the status of a partially-completed swap, if any. This is necessary
784 * to recover in case the boot lodaer was reset in the middle of a swap
785 * operation.
786 */
787static int
David Vinczecea8b592019-10-29 16:09:51 +0100788boot_read_status_bytes(const struct flash_area *fap,
789 struct boot_loader_state *state, struct boot_status *bs)
Tamas Banf70ef8c2017-12-19 15:35:09 +0000790{
791 uint32_t off;
792 uint8_t status;
793 int max_entries;
794 int found;
David Vincze39e78552018-10-10 17:10:01 +0200795 int found_idx;
796 int invalid;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000797 int rc;
798 int i;
799
800 off = boot_status_off(fap);
David Vinczecea8b592019-10-29 16:09:51 +0100801 max_entries = boot_status_entries(BOOT_CURR_IMG(state), fap);
802 if (max_entries < 0) {
803 return BOOT_EBADARGS;
804 }
Tamas Banf70ef8c2017-12-19 15:35:09 +0000805
806 found = 0;
David Vincze39e78552018-10-10 17:10:01 +0200807 found_idx = 0;
808 invalid = 0;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000809 for (i = 0; i < max_entries; i++) {
David Vinczecea8b592019-10-29 16:09:51 +0100810 rc = flash_area_read_is_empty(fap, off + i * BOOT_WRITE_SZ(state),
David Vincze39e78552018-10-10 17:10:01 +0200811 &status, 1);
812 if (rc < 0) {
Tamas Banf70ef8c2017-12-19 15:35:09 +0000813 return BOOT_EFLASH;
814 }
815
David Vincze39e78552018-10-10 17:10:01 +0200816 if (rc == 1) {
817 if (found && !found_idx) {
818 found_idx = i;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000819 }
820 } else if (!found) {
821 found = 1;
David Vincze39e78552018-10-10 17:10:01 +0200822 } else if (found_idx) {
823 invalid = 1;
824 break;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000825 }
826 }
827
David Vincze39e78552018-10-10 17:10:01 +0200828 if (invalid) {
829 /* This means there was an error writing status on the last
830 * swap. Tell user and move on to validation!
831 */
832 BOOT_LOG_ERR("Detected inconsistent status!");
833
David Vincze8bdfc2d2019-03-18 15:49:23 +0100834#if !defined(MCUBOOT_VALIDATE_PRIMARY_SLOT)
835 /* With validation of the primary slot disabled, there is no way
836 * to be sure the swapped primary slot is OK, so abort!
David Vincze39e78552018-10-10 17:10:01 +0200837 */
838 assert(0);
839#endif
840 }
841
Tamas Banf70ef8c2017-12-19 15:35:09 +0000842 if (found) {
David Vincze39e78552018-10-10 17:10:01 +0200843 if (!found_idx) {
844 found_idx = i;
845 }
David Vincze39e78552018-10-10 17:10:01 +0200846 bs->idx = (found_idx / BOOT_STATUS_STATE_COUNT) + 1;
847 bs->state = (found_idx % BOOT_STATUS_STATE_COUNT) + 1;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000848 }
849
850 return 0;
851}
852
853/**
854 * Reads the boot status from the flash. The boot status contains
855 * the current state of an interrupted image copy operation. If the boot
856 * status is not present, or it indicates that previous copy finished,
857 * there is no operation in progress.
858 */
859static int
David Vinczecea8b592019-10-29 16:09:51 +0100860boot_read_status(struct boot_loader_state *state, struct boot_status *bs)
Tamas Banf70ef8c2017-12-19 15:35:09 +0000861{
862 const struct flash_area *fap;
David Vincze401c7422019-06-21 20:44:05 +0200863 uint32_t off;
David Vincze91b71ef2019-06-24 13:06:47 +0200864 uint8_t swap_info;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000865 int status_loc;
866 int area_id;
867 int rc;
868
David Vincze39e78552018-10-10 17:10:01 +0200869 memset(bs, 0, sizeof *bs);
870 bs->idx = BOOT_STATUS_IDX_0;
871 bs->state = BOOT_STATUS_STATE_0;
David Vincze401c7422019-06-21 20:44:05 +0200872 bs->swap_type = BOOT_SWAP_TYPE_NONE;
David Vincze39e78552018-10-10 17:10:01 +0200873
874#ifdef MCUBOOT_OVERWRITE_ONLY
875 /* Overwrite-only doesn't make use of the swap status area. */
876 return 0;
877#endif
Tamas Banf70ef8c2017-12-19 15:35:09 +0000878
David Vinczecea8b592019-10-29 16:09:51 +0100879 status_loc = boot_status_source(state);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000880 switch (status_loc) {
881 case BOOT_STATUS_SOURCE_NONE:
882 return 0;
883
884 case BOOT_STATUS_SOURCE_SCRATCH:
885 area_id = FLASH_AREA_IMAGE_SCRATCH;
886 break;
887
David Vincze8bdfc2d2019-03-18 15:49:23 +0100888 case BOOT_STATUS_SOURCE_PRIMARY_SLOT:
David Vinczecea8b592019-10-29 16:09:51 +0100889 area_id = FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state));
Tamas Banf70ef8c2017-12-19 15:35:09 +0000890 break;
891
892 default:
893 assert(0);
894 return BOOT_EBADARGS;
895 }
896
897 rc = flash_area_open(area_id, &fap);
898 if (rc != 0) {
899 return BOOT_EFLASH;
900 }
901
David Vinczecea8b592019-10-29 16:09:51 +0100902 rc = boot_read_status_bytes(fap, state, bs);
David Vincze401c7422019-06-21 20:44:05 +0200903 if (rc == 0) {
David Vincze91b71ef2019-06-24 13:06:47 +0200904 off = boot_swap_info_off(fap);
905 rc = flash_area_read_is_empty(fap, off, &swap_info, sizeof swap_info);
David Vincze401c7422019-06-21 20:44:05 +0200906 if (rc == 1) {
David Vincze91b71ef2019-06-24 13:06:47 +0200907 BOOT_SET_SWAP_INFO(swap_info, 0, BOOT_SWAP_TYPE_NONE);
David Vincze401c7422019-06-21 20:44:05 +0200908 rc = 0;
909 }
David Vincze91b71ef2019-06-24 13:06:47 +0200910
911 /* Extract the swap type info */
912 bs->swap_type = BOOT_GET_SWAP_TYPE(swap_info);
David Vincze401c7422019-06-21 20:44:05 +0200913 }
Tamas Banf70ef8c2017-12-19 15:35:09 +0000914
915 flash_area_close(fap);
David Vincze39e78552018-10-10 17:10:01 +0200916
Tamas Banf70ef8c2017-12-19 15:35:09 +0000917 return rc;
918}
919
920/**
921 * Writes the supplied boot status to the flash file system. The boot status
922 * contains the current state of an in-progress image copy operation.
923 *
924 * @param bs The boot status to write.
925 *
926 * @return 0 on success; nonzero on failure.
927 */
928int
David Vinczecea8b592019-10-29 16:09:51 +0100929boot_write_status(struct boot_loader_state *state, struct boot_status *bs)
Tamas Banf70ef8c2017-12-19 15:35:09 +0000930{
Tamas Ban581034a2017-12-19 19:54:37 +0000931 const struct flash_area *fap = NULL;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000932 uint32_t off;
933 int area_id;
934 int rc;
935 uint8_t buf[BOOT_MAX_ALIGN];
Raef Coles204c5b42019-09-05 09:18:47 +0100936 uint32_t align;
David Vincze39e78552018-10-10 17:10:01 +0200937 uint8_t erased_val;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000938
939 /* NOTE: The first sector copied (that is the last sector on slot) contains
David Vincze8bdfc2d2019-03-18 15:49:23 +0100940 * the trailer. Since in the last step the primary slot is erased, the
941 * first two status writes go to the scratch which will be copied to
942 * the primary slot!
Tamas Banf70ef8c2017-12-19 15:35:09 +0000943 */
944
945 if (bs->use_scratch) {
946 /* Write to scratch. */
947 area_id = FLASH_AREA_IMAGE_SCRATCH;
948 } else {
David Vincze8bdfc2d2019-03-18 15:49:23 +0100949 /* Write to the primary slot. */
David Vinczecea8b592019-10-29 16:09:51 +0100950 area_id = FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state));
Tamas Banf70ef8c2017-12-19 15:35:09 +0000951 }
952
953 rc = flash_area_open(area_id, &fap);
954 if (rc != 0) {
955 rc = BOOT_EFLASH;
956 goto done;
957 }
958
959 off = boot_status_off(fap) +
David Vinczecea8b592019-10-29 16:09:51 +0100960 boot_status_internal_off(bs->idx, bs->state, BOOT_WRITE_SZ(state));
Tamas Banc3828852018-02-01 12:24:16 +0000961 align = flash_area_align(fap);
David Vincze39e78552018-10-10 17:10:01 +0200962 erased_val = flash_area_erased_val(fap);
963 memset(buf, erased_val, BOOT_MAX_ALIGN);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000964 buf[0] = bs->state;
965
966 rc = flash_area_write(fap, off, buf, align);
967 if (rc != 0) {
968 rc = BOOT_EFLASH;
969 goto done;
970 }
971
972 rc = 0;
973
974done:
975 flash_area_close(fap);
976 return rc;
977}
978
Tamas Banf70ef8c2017-12-19 15:35:09 +0000979/**
980 * Determines which swap operation to perform, if any. If it is determined
David Vincze8bdfc2d2019-03-18 15:49:23 +0100981 * that a swap operation is required, the image in the secondary slot is checked
982 * for validity. If the image in the secondary slot is invalid, it is erased,
983 * and a swap type of "none" is indicated.
Tamas Banf70ef8c2017-12-19 15:35:09 +0000984 *
985 * @return The type of swap to perform (BOOT_SWAP_TYPE...)
986 */
987static int
David Vinczecea8b592019-10-29 16:09:51 +0100988boot_validated_swap_type(struct boot_loader_state *state,
989 struct boot_status *bs)
Tamas Banf70ef8c2017-12-19 15:35:09 +0000990{
991 int swap_type;
David Vinczecea8b592019-10-29 16:09:51 +0100992 int rc;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000993
David Vinczecea8b592019-10-29 16:09:51 +0100994 swap_type = boot_swap_type_multi(BOOT_CURR_IMG(state));
995 if (BOOT_IS_UPGRADE(swap_type)) {
David Vincze8bdfc2d2019-03-18 15:49:23 +0100996 /* Boot loader wants to switch to the secondary slot.
997 * Ensure image is valid.
998 */
David Vinczecea8b592019-10-29 16:09:51 +0100999 rc = boot_validate_slot(state, BOOT_SECONDARY_SLOT, bs);
1000 if (rc == 1) {
1001 swap_type = BOOT_SWAP_TYPE_NONE;
1002 } else if (rc != 0) {
Tamas Banf70ef8c2017-12-19 15:35:09 +00001003 swap_type = BOOT_SWAP_TYPE_FAIL;
1004 }
1005 }
1006
1007 return swap_type;
1008}
1009
1010/**
1011 * Calculates the number of sectors the scratch area can contain. A "last"
1012 * source sector is specified because images are copied backwards in flash
1013 * (final index to index number 0).
1014 *
1015 * @param last_sector_idx The index of the last source sector
1016 * (inclusive).
1017 * @param out_first_sector_idx The index of the first source sector
1018 * (inclusive) gets written here.
1019 *
1020 * @return The number of bytes comprised by the
1021 * [first-sector, last-sector] range.
1022 */
1023#ifndef MCUBOOT_OVERWRITE_ONLY
1024static uint32_t
David Vinczecea8b592019-10-29 16:09:51 +01001025boot_copy_sz(struct boot_loader_state *state, int last_sector_idx,
1026 int *out_first_sector_idx)
Tamas Banf70ef8c2017-12-19 15:35:09 +00001027{
1028 size_t scratch_sz;
1029 uint32_t new_sz;
1030 uint32_t sz;
1031 int i;
1032
1033 sz = 0;
1034
David Vinczecea8b592019-10-29 16:09:51 +01001035 scratch_sz = boot_scratch_area_size(state);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001036 for (i = last_sector_idx; i >= 0; i--) {
David Vinczecea8b592019-10-29 16:09:51 +01001037 new_sz = sz + boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i);
David Vincze401c7422019-06-21 20:44:05 +02001038 /*
1039 * The secondary slot is not being checked here, because
1040 * `boot_slots_compatible` already provides assurance that the copy size
1041 * will be compatible with the primary slot and scratch.
1042 */
Tamas Banf70ef8c2017-12-19 15:35:09 +00001043 if (new_sz > scratch_sz) {
1044 break;
1045 }
1046 sz = new_sz;
1047 }
1048
1049 /* i currently refers to a sector that doesn't fit or it is -1 because all
1050 * sectors have been processed. In both cases, exclude sector i.
1051 */
1052 *out_first_sector_idx = i + 1;
1053 return sz;
1054}
1055#endif /* !MCUBOOT_OVERWRITE_ONLY */
1056
1057/**
David Vinczef7641fa2018-09-04 18:29:46 +02001058 * Erases a region of flash.
1059 *
David Vincze401c7422019-06-21 20:44:05 +02001060 * @param flash_area The flash_area containing the region to erase.
David Vinczef7641fa2018-09-04 18:29:46 +02001061 * @param off The offset within the flash area to start the
1062 * erase.
1063 * @param sz The number of bytes to erase.
1064 *
1065 * @return 0 on success; nonzero on failure.
1066 */
David Vincze401c7422019-06-21 20:44:05 +02001067static inline int
David Vinczecea8b592019-10-29 16:09:51 +01001068boot_erase_region(const struct flash_area *fap, uint32_t off, uint32_t sz)
David Vinczef7641fa2018-09-04 18:29:46 +02001069{
David Vincze401c7422019-06-21 20:44:05 +02001070 return flash_area_erase(fap, off, sz);
David Vinczef7641fa2018-09-04 18:29:46 +02001071}
1072
1073/**
Tamas Banf70ef8c2017-12-19 15:35:09 +00001074 * Copies the contents of one flash region to another. You must erase the
1075 * destination region prior to calling this function.
1076 *
1077 * @param flash_area_id_src The ID of the source flash area.
1078 * @param flash_area_id_dst The ID of the destination flash area.
1079 * @param off_src The offset within the source flash area to
1080 * copy from.
1081 * @param off_dst The offset within the destination flash area to
1082 * copy to.
1083 * @param sz The number of bytes to copy.
1084 *
1085 * @return 0 on success; nonzero on failure.
1086 */
1087static int
David Vinczecea8b592019-10-29 16:09:51 +01001088boot_copy_region(struct boot_loader_state *state,
1089 const struct flash_area *fap_src,
David Vincze401c7422019-06-21 20:44:05 +02001090 const struct flash_area *fap_dst,
Tamas Banf70ef8c2017-12-19 15:35:09 +00001091 uint32_t off_src, uint32_t off_dst, uint32_t sz)
1092{
Tamas Banf70ef8c2017-12-19 15:35:09 +00001093 uint32_t bytes_copied;
1094 int chunk_sz;
1095 int rc;
1096
1097 static uint8_t buf[1024];
1098
David Vinczecea8b592019-10-29 16:09:51 +01001099 (void)state;
1100
Tamas Banf70ef8c2017-12-19 15:35:09 +00001101 bytes_copied = 0;
1102 while (bytes_copied < sz) {
Tamas Ban581034a2017-12-19 19:54:37 +00001103 if (sz - bytes_copied > sizeof(buf)) {
1104 chunk_sz = sizeof(buf);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001105 } else {
1106 chunk_sz = sz - bytes_copied;
1107 }
1108
1109 rc = flash_area_read(fap_src, off_src + bytes_copied, buf, chunk_sz);
1110 if (rc != 0) {
David Vincze401c7422019-06-21 20:44:05 +02001111 return BOOT_EFLASH;
Tamas Banf70ef8c2017-12-19 15:35:09 +00001112 }
1113
1114 rc = flash_area_write(fap_dst, off_dst + bytes_copied, buf, chunk_sz);
1115 if (rc != 0) {
David Vincze401c7422019-06-21 20:44:05 +02001116 return BOOT_EFLASH;
Tamas Banf70ef8c2017-12-19 15:35:09 +00001117 }
1118
1119 bytes_copied += chunk_sz;
1120 }
1121
David Vincze401c7422019-06-21 20:44:05 +02001122 return 0;
Tamas Banf70ef8c2017-12-19 15:35:09 +00001123}
1124
1125#ifndef MCUBOOT_OVERWRITE_ONLY
1126static inline int
David Vinczecea8b592019-10-29 16:09:51 +01001127boot_status_init(const struct boot_loader_state *state,
1128 const struct flash_area *fap,
1129 const struct boot_status *bs)
Tamas Banf70ef8c2017-12-19 15:35:09 +00001130{
Tamas Banf70ef8c2017-12-19 15:35:09 +00001131 struct boot_swap_state swap_state;
David Vinczecea8b592019-10-29 16:09:51 +01001132 uint8_t image_index;
Tamas Banf70ef8c2017-12-19 15:35:09 +00001133 int rc;
1134
David Vinczecea8b592019-10-29 16:09:51 +01001135#if (BOOT_IMAGE_NUMBER == 1)
1136 (void)state;
1137#endif
1138
1139 image_index = BOOT_CURR_IMG(state);
1140
David Vincze401c7422019-06-21 20:44:05 +02001141 BOOT_LOG_DBG("initializing status; fa_id=%d", fap->fa_id);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001142
David Vinczecea8b592019-10-29 16:09:51 +01001143 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SECONDARY(image_index),
1144 &swap_state);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001145 assert(rc == 0);
1146
David Vincze401c7422019-06-21 20:44:05 +02001147 if (bs->swap_type != BOOT_SWAP_TYPE_NONE) {
David Vinczecea8b592019-10-29 16:09:51 +01001148 rc = boot_write_swap_info(fap, bs->swap_type, image_index);
David Vincze401c7422019-06-21 20:44:05 +02001149 assert(rc == 0);
1150 }
1151
Tamas Banf70ef8c2017-12-19 15:35:09 +00001152 if (swap_state.image_ok == BOOT_FLAG_SET) {
1153 rc = boot_write_image_ok(fap);
1154 assert(rc == 0);
1155 }
1156
1157 rc = boot_write_swap_size(fap, bs->swap_size);
1158 assert(rc == 0);
1159
1160 rc = boot_write_magic(fap);
1161 assert(rc == 0);
1162
Tamas Banf70ef8c2017-12-19 15:35:09 +00001163 return 0;
1164}
David Vinczef7641fa2018-09-04 18:29:46 +02001165
1166static int
David Vinczecea8b592019-10-29 16:09:51 +01001167boot_erase_trailer_sectors(const struct boot_loader_state *state,
1168 const struct flash_area *fap)
David Vinczef7641fa2018-09-04 18:29:46 +02001169{
1170 uint8_t slot;
David Vincze401c7422019-06-21 20:44:05 +02001171 uint32_t sector;
1172 uint32_t trailer_sz;
1173 uint32_t total_sz;
1174 uint32_t off;
1175 uint32_t sz;
David Vinczebb207982019-08-21 15:13:04 +02001176 int fa_id_primary;
1177 int fa_id_secondary;
David Vinczecea8b592019-10-29 16:09:51 +01001178 uint8_t image_index;
David Vinczef7641fa2018-09-04 18:29:46 +02001179 int rc;
1180
David Vincze401c7422019-06-21 20:44:05 +02001181 BOOT_LOG_DBG("erasing trailer; fa_id=%d", fap->fa_id);
1182
David Vinczecea8b592019-10-29 16:09:51 +01001183 image_index = BOOT_CURR_IMG(state);
1184 fa_id_primary = flash_area_id_from_multi_image_slot(image_index,
1185 BOOT_PRIMARY_SLOT);
1186 fa_id_secondary = flash_area_id_from_multi_image_slot(image_index,
1187 BOOT_SECONDARY_SLOT);
David Vinczebb207982019-08-21 15:13:04 +02001188
1189 if (fap->fa_id == fa_id_primary) {
David Vincze8bdfc2d2019-03-18 15:49:23 +01001190 slot = BOOT_PRIMARY_SLOT;
David Vinczebb207982019-08-21 15:13:04 +02001191 } else if (fap->fa_id == fa_id_secondary) {
David Vincze8bdfc2d2019-03-18 15:49:23 +01001192 slot = BOOT_SECONDARY_SLOT;
David Vinczebb207982019-08-21 15:13:04 +02001193 } else {
David Vinczef7641fa2018-09-04 18:29:46 +02001194 return BOOT_EFLASH;
1195 }
1196
David Vincze401c7422019-06-21 20:44:05 +02001197 /* delete starting from last sector and moving to beginning */
David Vinczecea8b592019-10-29 16:09:51 +01001198 sector = boot_img_num_sectors(state, slot) - 1;
1199 trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(state));
David Vincze401c7422019-06-21 20:44:05 +02001200 total_sz = 0;
1201 do {
David Vinczecea8b592019-10-29 16:09:51 +01001202 sz = boot_img_sector_size(state, slot, sector);
1203 off = boot_img_sector_off(state, slot, sector);
1204 rc = boot_erase_region(fap, off, sz);
David Vincze401c7422019-06-21 20:44:05 +02001205 assert(rc == 0);
1206
1207 sector--;
1208 total_sz += sz;
1209 } while (total_sz < trailer_sz);
David Vinczef7641fa2018-09-04 18:29:46 +02001210
1211 return rc;
1212}
Tamas Banf70ef8c2017-12-19 15:35:09 +00001213
Tamas Banf70ef8c2017-12-19 15:35:09 +00001214/**
1215 * Swaps the contents of two flash regions within the two image slots.
1216 *
1217 * @param idx The index of the first sector in the range of
1218 * sectors being swapped.
1219 * @param sz The number of bytes to swap.
1220 * @param bs The current boot status. This struct gets
1221 * updated according to the outcome.
1222 *
1223 * @return 0 on success; nonzero on failure.
1224 */
Tamas Banf70ef8c2017-12-19 15:35:09 +00001225static void
David Vinczecea8b592019-10-29 16:09:51 +01001226boot_swap_sectors(int idx, uint32_t sz, struct boot_loader_state *state,
1227 struct boot_status *bs)
Tamas Banf70ef8c2017-12-19 15:35:09 +00001228{
David Vincze401c7422019-06-21 20:44:05 +02001229 const struct flash_area *fap_primary_slot;
1230 const struct flash_area *fap_secondary_slot;
1231 const struct flash_area *fap_scratch;
Tamas Banf70ef8c2017-12-19 15:35:09 +00001232 uint32_t copy_sz;
1233 uint32_t trailer_sz;
1234 uint32_t img_off;
1235 uint32_t scratch_trailer_off;
1236 struct boot_swap_state swap_state;
1237 size_t last_sector;
David Vincze401c7422019-06-21 20:44:05 +02001238 bool erase_scratch;
David Vinczecea8b592019-10-29 16:09:51 +01001239 uint8_t image_index;
Tamas Banf70ef8c2017-12-19 15:35:09 +00001240 int rc;
1241
1242 /* Calculate offset from start of image area. */
David Vinczecea8b592019-10-29 16:09:51 +01001243 img_off = boot_img_sector_off(state, BOOT_PRIMARY_SLOT, idx);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001244
1245 copy_sz = sz;
David Vinczecea8b592019-10-29 16:09:51 +01001246 trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(state));
Tamas Banf70ef8c2017-12-19 15:35:09 +00001247
David Vincze401c7422019-06-21 20:44:05 +02001248 /* sz in this function is always sized on a multiple of the sector size.
1249 * The check against the start offset of the last sector
Tamas Banf70ef8c2017-12-19 15:35:09 +00001250 * is to determine if we're swapping the last sector. The last sector
1251 * needs special handling because it's where the trailer lives. If we're
1252 * copying it, we need to use scratch to write the trailer temporarily.
1253 *
1254 * NOTE: `use_scratch` is a temporary flag (never written to flash) which
1255 * controls if special handling is needed (swapping last sector).
1256 */
David Vinczecea8b592019-10-29 16:09:51 +01001257 last_sector = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT) - 1;
David Vincze7384ee72019-07-23 17:00:42 +02001258 if ((img_off + sz) >
David Vinczecea8b592019-10-29 16:09:51 +01001259 boot_img_sector_off(state, BOOT_PRIMARY_SLOT, last_sector)) {
Tamas Banf70ef8c2017-12-19 15:35:09 +00001260 copy_sz -= trailer_sz;
1261 }
1262
David Vincze39e78552018-10-10 17:10:01 +02001263 bs->use_scratch = (bs->idx == BOOT_STATUS_IDX_0 && copy_sz != sz);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001264
David Vinczecea8b592019-10-29 16:09:51 +01001265 image_index = BOOT_CURR_IMG(state);
1266
1267 rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index),
1268 &fap_primary_slot);
David Vincze401c7422019-06-21 20:44:05 +02001269 assert (rc == 0);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001270
David Vinczecea8b592019-10-29 16:09:51 +01001271 rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY(image_index),
1272 &fap_secondary_slot);
David Vincze401c7422019-06-21 20:44:05 +02001273 assert (rc == 0);
1274
1275 rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH, &fap_scratch);
1276 assert (rc == 0);
1277
1278 if (bs->state == BOOT_STATUS_STATE_0) {
1279 BOOT_LOG_DBG("erasing scratch area");
David Vinczecea8b592019-10-29 16:09:51 +01001280 rc = boot_erase_region(fap_scratch, 0, fap_scratch->fa_size);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001281 assert(rc == 0);
1282
David Vincze39e78552018-10-10 17:10:01 +02001283 if (bs->idx == BOOT_STATUS_IDX_0) {
David Vincze401c7422019-06-21 20:44:05 +02001284 /* Write a trailer to the scratch area, even if we don't need the
1285 * scratch area for status. We need a temporary place to store the
1286 * `swap-type` while we erase the primary trailer.
1287 */
David Vinczecea8b592019-10-29 16:09:51 +01001288 rc = boot_status_init(state, fap_scratch, bs);
David Vincze401c7422019-06-21 20:44:05 +02001289 assert(rc == 0);
1290
1291 if (!bs->use_scratch) {
1292 /* Prepare the primary status area... here it is known that the
1293 * last sector is not being used by the image data so it's safe
1294 * to erase.
Tamas Banf70ef8c2017-12-19 15:35:09 +00001295 */
David Vinczecea8b592019-10-29 16:09:51 +01001296 rc = boot_erase_trailer_sectors(state, fap_primary_slot);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001297 assert(rc == 0);
1298
David Vinczecea8b592019-10-29 16:09:51 +01001299 rc = boot_status_init(state, fap_primary_slot, bs);
David Vincze401c7422019-06-21 20:44:05 +02001300 assert(rc == 0);
1301
1302 /* Erase the temporary trailer from the scratch area. */
David Vinczecea8b592019-10-29 16:09:51 +01001303 rc = boot_erase_region(fap_scratch, 0, fap_scratch->fa_size);
David Vincze401c7422019-06-21 20:44:05 +02001304 assert(rc == 0);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001305 }
1306 }
1307
David Vinczecea8b592019-10-29 16:09:51 +01001308 rc = boot_copy_region(state, fap_secondary_slot, fap_scratch,
David Vincze401c7422019-06-21 20:44:05 +02001309 img_off, 0, copy_sz);
1310 assert(rc == 0);
1311
David Vinczecea8b592019-10-29 16:09:51 +01001312 rc = boot_write_status(state, bs);
David Vincze39e78552018-10-10 17:10:01 +02001313 bs->state = BOOT_STATUS_STATE_1;
David Vincze39e78552018-10-10 17:10:01 +02001314 BOOT_STATUS_ASSERT(rc == 0);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001315 }
1316
David Vincze39e78552018-10-10 17:10:01 +02001317 if (bs->state == BOOT_STATUS_STATE_1) {
David Vinczecea8b592019-10-29 16:09:51 +01001318 rc = boot_erase_region(fap_secondary_slot, img_off, sz);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001319 assert(rc == 0);
1320
David Vinczecea8b592019-10-29 16:09:51 +01001321 rc = boot_copy_region(state, fap_primary_slot, fap_secondary_slot,
Tamas Banf70ef8c2017-12-19 15:35:09 +00001322 img_off, img_off, copy_sz);
1323 assert(rc == 0);
1324
David Vincze39e78552018-10-10 17:10:01 +02001325 if (bs->idx == BOOT_STATUS_IDX_0 && !bs->use_scratch) {
Tamas Banf70ef8c2017-12-19 15:35:09 +00001326 /* If not all sectors of the slot are being swapped,
David Vincze8bdfc2d2019-03-18 15:49:23 +01001327 * guarantee here that only the primary slot will have the state.
Tamas Banf70ef8c2017-12-19 15:35:09 +00001328 */
David Vinczecea8b592019-10-29 16:09:51 +01001329 rc = boot_erase_trailer_sectors(state, fap_secondary_slot);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001330 assert(rc == 0);
1331 }
1332
David Vinczecea8b592019-10-29 16:09:51 +01001333 rc = boot_write_status(state, bs);
David Vincze39e78552018-10-10 17:10:01 +02001334 bs->state = BOOT_STATUS_STATE_2;
David Vincze39e78552018-10-10 17:10:01 +02001335 BOOT_STATUS_ASSERT(rc == 0);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001336 }
1337
David Vincze39e78552018-10-10 17:10:01 +02001338 if (bs->state == BOOT_STATUS_STATE_2) {
David Vinczecea8b592019-10-29 16:09:51 +01001339 rc = boot_erase_region(fap_primary_slot, img_off, sz);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001340 assert(rc == 0);
1341
David Vincze401c7422019-06-21 20:44:05 +02001342 /* NOTE: If this is the final sector, we exclude the image trailer from
1343 * this copy (copy_sz was truncated earlier).
1344 */
David Vinczecea8b592019-10-29 16:09:51 +01001345 rc = boot_copy_region(state, fap_scratch, fap_primary_slot,
Tamas Banf70ef8c2017-12-19 15:35:09 +00001346 0, img_off, copy_sz);
1347 assert(rc == 0);
1348
1349 if (bs->use_scratch) {
David Vincze401c7422019-06-21 20:44:05 +02001350 scratch_trailer_off = boot_status_off(fap_scratch);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001351
1352 /* copy current status that is being maintained in scratch */
David Vinczecea8b592019-10-29 16:09:51 +01001353 rc = boot_copy_region(state, fap_scratch, fap_primary_slot,
David Vincze401c7422019-06-21 20:44:05 +02001354 scratch_trailer_off, img_off + copy_sz,
David Vinczecea8b592019-10-29 16:09:51 +01001355 (BOOT_STATUS_STATE_COUNT - 1) * BOOT_WRITE_SZ(state));
David Vincze39e78552018-10-10 17:10:01 +02001356 BOOT_STATUS_ASSERT(rc == 0);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001357
1358 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SCRATCH,
1359 &swap_state);
1360 assert(rc == 0);
1361
1362 if (swap_state.image_ok == BOOT_FLAG_SET) {
David Vincze401c7422019-06-21 20:44:05 +02001363 rc = boot_write_image_ok(fap_primary_slot);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001364 assert(rc == 0);
1365 }
1366
David Vincze401c7422019-06-21 20:44:05 +02001367 if (swap_state.swap_type != BOOT_SWAP_TYPE_NONE) {
David Vincze91b71ef2019-06-24 13:06:47 +02001368 rc = boot_write_swap_info(fap_primary_slot,
1369 swap_state.swap_type,
David Vinczecea8b592019-10-29 16:09:51 +01001370 image_index);
David Vincze401c7422019-06-21 20:44:05 +02001371 assert(rc == 0);
1372 }
1373
1374 rc = boot_write_swap_size(fap_primary_slot, bs->swap_size);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001375 assert(rc == 0);
1376
David Vincze401c7422019-06-21 20:44:05 +02001377 rc = boot_write_magic(fap_primary_slot);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001378 assert(rc == 0);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001379 }
1380
David Vincze401c7422019-06-21 20:44:05 +02001381 /* If we wrote a trailer to the scratch area, erase it after we persist
1382 * a trailer to the primary slot. We do this to prevent mcuboot from
1383 * reading a stale status from the scratch area in case of immediate
1384 * reset.
1385 */
1386 erase_scratch = bs->use_scratch;
1387 bs->use_scratch = 0;
1388
David Vinczecea8b592019-10-29 16:09:51 +01001389 rc = boot_write_status(state, bs);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001390 bs->idx++;
David Vincze39e78552018-10-10 17:10:01 +02001391 bs->state = BOOT_STATUS_STATE_0;
David Vincze39e78552018-10-10 17:10:01 +02001392 BOOT_STATUS_ASSERT(rc == 0);
David Vincze401c7422019-06-21 20:44:05 +02001393
1394 if (erase_scratch) {
David Vinczecea8b592019-10-29 16:09:51 +01001395 rc = boot_erase_region(fap_scratch, 0, sz);
David Vincze401c7422019-06-21 20:44:05 +02001396 assert(rc == 0);
1397 }
Tamas Banf70ef8c2017-12-19 15:35:09 +00001398 }
David Vincze401c7422019-06-21 20:44:05 +02001399
1400 flash_area_close(fap_primary_slot);
1401 flash_area_close(fap_secondary_slot);
1402 flash_area_close(fap_scratch);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001403}
1404#endif /* !MCUBOOT_OVERWRITE_ONLY */
1405
1406/**
David Vincze401c7422019-06-21 20:44:05 +02001407 * Overwrite primary slot with the image contained in the secondary slot.
1408 * If a prior copy operation was interrupted by a system reset, this function
1409 * redos the copy.
Tamas Banf70ef8c2017-12-19 15:35:09 +00001410 *
1411 * @param bs The current boot status. This function reads
1412 * this struct to determine if it is resuming
1413 * an interrupted swap operation. This
1414 * function writes the updated status to this
1415 * function on return.
1416 *
1417 * @return 0 on success; nonzero on failure.
1418 */
1419#ifdef MCUBOOT_OVERWRITE_ONLY
1420static int
David Vinczecea8b592019-10-29 16:09:51 +01001421boot_copy_image(struct boot_loader_state *state, struct boot_status *bs)
Tamas Banf70ef8c2017-12-19 15:35:09 +00001422{
1423 size_t sect_count;
1424 size_t sect;
1425 int rc;
David Vinczecea8b592019-10-29 16:09:51 +01001426 size_t size;
Tamas Banf70ef8c2017-12-19 15:35:09 +00001427 size_t this_size;
David Vincze39e78552018-10-10 17:10:01 +02001428 size_t last_sector;
David Vincze401c7422019-06-21 20:44:05 +02001429 const struct flash_area *fap_primary_slot;
1430 const struct flash_area *fap_secondary_slot;
David Vinczecea8b592019-10-29 16:09:51 +01001431 uint8_t image_index;
David Vincze39e78552018-10-10 17:10:01 +02001432
1433 (void)bs;
Tamas Banf70ef8c2017-12-19 15:35:09 +00001434
David Vincze8bdfc2d2019-03-18 15:49:23 +01001435 BOOT_LOG_INF("Image upgrade secondary slot -> primary slot");
1436 BOOT_LOG_INF("Erasing the primary slot");
Tamas Banf70ef8c2017-12-19 15:35:09 +00001437
David Vinczecea8b592019-10-29 16:09:51 +01001438 image_index = BOOT_CURR_IMG(state);
1439
1440 rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index),
1441 &fap_primary_slot);
David Vincze401c7422019-06-21 20:44:05 +02001442 assert (rc == 0);
1443
David Vinczecea8b592019-10-29 16:09:51 +01001444 rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY(image_index),
1445 &fap_secondary_slot);
David Vincze401c7422019-06-21 20:44:05 +02001446 assert (rc == 0);
1447
David Vinczecea8b592019-10-29 16:09:51 +01001448 sect_count = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT);
1449 for (sect = 0, size = 0; sect < sect_count; sect++) {
1450 this_size = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, sect);
1451 rc = boot_erase_region(fap_primary_slot, size, this_size);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001452 assert(rc == 0);
1453
1454 size += this_size;
1455 }
1456
David Vincze8bdfc2d2019-03-18 15:49:23 +01001457 BOOT_LOG_INF("Copying the secondary slot to the primary slot: 0x%zx bytes",
1458 size);
David Vinczecea8b592019-10-29 16:09:51 +01001459 rc = boot_copy_region(state, fap_secondary_slot, fap_primary_slot,
1460 0, 0, size);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001461
David Vincze060968d2019-05-23 01:13:14 +02001462 /* Update the stored security counter with the new image's security counter
David Vincze8bdfc2d2019-03-18 15:49:23 +01001463 * value. Both slots hold the new image at this point, but the secondary
1464 * slot's image header must be passed because the read image headers in the
1465 * boot_data structure have not been updated yet.
David Vincze060968d2019-05-23 01:13:14 +02001466 */
David Vinczecea8b592019-10-29 16:09:51 +01001467 rc = boot_update_security_counter(BOOT_CURR_IMG(state), BOOT_PRIMARY_SLOT,
1468 boot_img_hdr(state, BOOT_SECONDARY_SLOT));
David Vincze060968d2019-05-23 01:13:14 +02001469 if (rc != 0) {
1470 BOOT_LOG_ERR("Security counter update failed after image upgrade.");
1471 return rc;
1472 }
1473
David Vincze39e78552018-10-10 17:10:01 +02001474 /*
1475 * Erases header and trailer. The trailer is erased because when a new
1476 * image is written without a trailer as is the case when using newt, the
1477 * trailer that was left might trigger a new upgrade.
1478 */
David Vincze401c7422019-06-21 20:44:05 +02001479 BOOT_LOG_DBG("erasing secondary header");
David Vinczecea8b592019-10-29 16:09:51 +01001480 rc = boot_erase_region(fap_secondary_slot,
1481 boot_img_sector_off(state, BOOT_SECONDARY_SLOT, 0),
1482 boot_img_sector_size(state, BOOT_SECONDARY_SLOT, 0));
Tamas Banf70ef8c2017-12-19 15:35:09 +00001483 assert(rc == 0);
David Vinczecea8b592019-10-29 16:09:51 +01001484 last_sector = boot_img_num_sectors(state, BOOT_SECONDARY_SLOT) - 1;
David Vincze401c7422019-06-21 20:44:05 +02001485 BOOT_LOG_DBG("erasing secondary trailer");
David Vinczecea8b592019-10-29 16:09:51 +01001486 rc = boot_erase_region(fap_secondary_slot,
1487 boot_img_sector_off(state, BOOT_SECONDARY_SLOT,
1488 last_sector),
1489 boot_img_sector_size(state, BOOT_SECONDARY_SLOT,
1490 last_sector));
David Vincze39e78552018-10-10 17:10:01 +02001491 assert(rc == 0);
1492
David Vincze401c7422019-06-21 20:44:05 +02001493 flash_area_close(fap_primary_slot);
1494 flash_area_close(fap_secondary_slot);
1495
David Vincze8bdfc2d2019-03-18 15:49:23 +01001496 /* TODO: Perhaps verify the primary slot's signature again? */
Tamas Banf70ef8c2017-12-19 15:35:09 +00001497
1498 return 0;
1499}
1500#else
David Vincze401c7422019-06-21 20:44:05 +02001501/**
1502 * Swaps the two images in flash. If a prior copy operation was interrupted
1503 * by a system reset, this function completes that operation.
1504 *
1505 * @param bs The current boot status. This function reads
1506 * this struct to determine if it is resuming
1507 * an interrupted swap operation. This
1508 * function writes the updated status to this
1509 * function on return.
1510 *
1511 * @return 0 on success; nonzero on failure.
1512 */
Tamas Banf70ef8c2017-12-19 15:35:09 +00001513static int
David Vinczecea8b592019-10-29 16:09:51 +01001514boot_swap_image(struct boot_loader_state *state, struct boot_status *bs)
Tamas Banf70ef8c2017-12-19 15:35:09 +00001515{
1516 uint32_t sz;
1517 int first_sector_idx;
1518 int last_sector_idx;
David Vincze401c7422019-06-21 20:44:05 +02001519 int last_idx_secondary_slot;
David Vincze39e78552018-10-10 17:10:01 +02001520 uint32_t swap_idx;
Tamas Banf70ef8c2017-12-19 15:35:09 +00001521 struct image_header *hdr;
1522 uint32_t size;
1523 uint32_t copy_size;
David Vincze401c7422019-06-21 20:44:05 +02001524 uint32_t primary_slot_size;
1525 uint32_t secondary_slot_size;
David Vinczecea8b592019-10-29 16:09:51 +01001526 uint8_t image_index;
Tamas Banf70ef8c2017-12-19 15:35:09 +00001527 int rc;
1528
1529 /* FIXME: just do this if asked by user? */
1530
1531 size = copy_size = 0;
David Vinczecea8b592019-10-29 16:09:51 +01001532 image_index = BOOT_CURR_IMG(state);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001533
David Vincze39e78552018-10-10 17:10:01 +02001534 if (bs->idx == BOOT_STATUS_IDX_0 && bs->state == BOOT_STATUS_STATE_0) {
Tamas Banf70ef8c2017-12-19 15:35:09 +00001535 /*
1536 * No swap ever happened, so need to find the largest image which
1537 * will be used to determine the amount of sectors to swap.
1538 */
David Vinczecea8b592019-10-29 16:09:51 +01001539 hdr = boot_img_hdr(state, BOOT_PRIMARY_SLOT);
1540 if (hdr->ih_magic == IMAGE_MAGIC) {
1541 rc = boot_read_image_size(state, BOOT_PRIMARY_SLOT, &copy_size);
1542 assert(rc == 0);
1543 }
Tamas Banf70ef8c2017-12-19 15:35:09 +00001544
David Vinczecea8b592019-10-29 16:09:51 +01001545 hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT);
1546 if (hdr->ih_magic == IMAGE_MAGIC) {
1547 rc = boot_read_image_size(state, BOOT_SECONDARY_SLOT, &size);
1548 assert(rc == 0);
1549 }
Tamas Banf70ef8c2017-12-19 15:35:09 +00001550
1551 if (size > copy_size) {
1552 copy_size = size;
1553 }
1554
1555 bs->swap_size = copy_size;
1556 } else {
1557 /*
1558 * If a swap was under way, the swap_size should already be present
1559 * in the trailer...
1560 */
David Vinczecea8b592019-10-29 16:09:51 +01001561 rc = boot_read_swap_size(image_index, &bs->swap_size);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001562 assert(rc == 0);
1563
1564 copy_size = bs->swap_size;
1565 }
1566
David Vincze401c7422019-06-21 20:44:05 +02001567 primary_slot_size = 0;
1568 secondary_slot_size = 0;
Tamas Banf70ef8c2017-12-19 15:35:09 +00001569 last_sector_idx = 0;
David Vincze401c7422019-06-21 20:44:05 +02001570 last_idx_secondary_slot = 0;
1571
1572 /*
1573 * Knowing the size of the largest image between both slots, here we
1574 * find what is the last sector in the primary slot that needs swapping.
1575 * Since we already know that both slots are compatible, the secondary
1576 * slot's last sector is not really required after this check is finished.
1577 */
Tamas Banf70ef8c2017-12-19 15:35:09 +00001578 while (1) {
David Vincze401c7422019-06-21 20:44:05 +02001579 if ((primary_slot_size < copy_size) ||
1580 (primary_slot_size < secondary_slot_size)) {
David Vinczecea8b592019-10-29 16:09:51 +01001581 primary_slot_size += boot_img_sector_size(state,
David Vincze401c7422019-06-21 20:44:05 +02001582 BOOT_PRIMARY_SLOT,
1583 last_sector_idx);
1584 }
1585 if ((secondary_slot_size < copy_size) ||
1586 (secondary_slot_size < primary_slot_size)) {
David Vinczecea8b592019-10-29 16:09:51 +01001587 secondary_slot_size += boot_img_sector_size(state,
David Vincze401c7422019-06-21 20:44:05 +02001588 BOOT_SECONDARY_SLOT,
1589 last_idx_secondary_slot);
1590 }
1591 if (primary_slot_size >= copy_size &&
1592 secondary_slot_size >= copy_size &&
1593 primary_slot_size == secondary_slot_size) {
Tamas Banf70ef8c2017-12-19 15:35:09 +00001594 break;
1595 }
1596 last_sector_idx++;
David Vincze401c7422019-06-21 20:44:05 +02001597 last_idx_secondary_slot++;
Tamas Banf70ef8c2017-12-19 15:35:09 +00001598 }
1599
1600 swap_idx = 0;
1601 while (last_sector_idx >= 0) {
David Vinczecea8b592019-10-29 16:09:51 +01001602 sz = boot_copy_sz(state, last_sector_idx, &first_sector_idx);
David Vincze39e78552018-10-10 17:10:01 +02001603 if (swap_idx >= (bs->idx - BOOT_STATUS_IDX_0)) {
David Vinczecea8b592019-10-29 16:09:51 +01001604 boot_swap_sectors(first_sector_idx, sz, state, bs);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001605 }
1606
1607 last_sector_idx = first_sector_idx - 1;
1608 swap_idx++;
1609 }
1610
David Vincze8bdfc2d2019-03-18 15:49:23 +01001611#ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT
David Vincze39e78552018-10-10 17:10:01 +02001612 if (boot_status_fails > 0) {
David Vincze401c7422019-06-21 20:44:05 +02001613 BOOT_LOG_WRN("%d status write fails performing the swap",
1614 boot_status_fails);
David Vincze39e78552018-10-10 17:10:01 +02001615 }
1616#endif
1617
Tamas Banf70ef8c2017-12-19 15:35:09 +00001618 return 0;
1619}
1620#endif
1621
David Vincze44b79f42019-10-25 15:39:59 +02001622#ifndef MCUBOOT_OVERWRITE_ONLY
Tamas Banf70ef8c2017-12-19 15:35:09 +00001623/**
David Vincze8bdfc2d2019-03-18 15:49:23 +01001624 * Marks the image in the primary slot as fully copied.
Tamas Banf70ef8c2017-12-19 15:35:09 +00001625 */
Tamas Banf70ef8c2017-12-19 15:35:09 +00001626static int
David Vinczecea8b592019-10-29 16:09:51 +01001627boot_set_copy_done(uint8_t image_index)
Tamas Banf70ef8c2017-12-19 15:35:09 +00001628{
1629 const struct flash_area *fap;
1630 int rc;
1631
David Vinczecea8b592019-10-29 16:09:51 +01001632 rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index),
1633 &fap);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001634 if (rc != 0) {
1635 return BOOT_EFLASH;
1636 }
1637
1638 rc = boot_write_copy_done(fap);
1639 flash_area_close(fap);
1640 return rc;
1641}
Tamas Banf70ef8c2017-12-19 15:35:09 +00001642
1643/**
David Vincze8bdfc2d2019-03-18 15:49:23 +01001644 * Marks a reverted image in the primary slot as confirmed. This is necessary to
1645 * ensure the status bytes from the image revert operation don't get processed
1646 * on a subsequent boot.
Tamas Banf70ef8c2017-12-19 15:35:09 +00001647 *
1648 * NOTE: image_ok is tested before writing because if there's a valid permanent
David Vincze8bdfc2d2019-03-18 15:49:23 +01001649 * image installed on the primary slot and the new image to be upgrade to has a
1650 * bad sig, image_ok would be overwritten.
Tamas Banf70ef8c2017-12-19 15:35:09 +00001651 */
Tamas Banf70ef8c2017-12-19 15:35:09 +00001652static int
David Vinczecea8b592019-10-29 16:09:51 +01001653boot_set_image_ok(uint8_t image_index)
Tamas Banf70ef8c2017-12-19 15:35:09 +00001654{
1655 const struct flash_area *fap;
1656 struct boot_swap_state state;
1657 int rc;
1658
David Vinczecea8b592019-10-29 16:09:51 +01001659 rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index),
1660 &fap);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001661 if (rc != 0) {
1662 return BOOT_EFLASH;
1663 }
1664
1665 rc = boot_read_swap_state(fap, &state);
1666 if (rc != 0) {
1667 rc = BOOT_EFLASH;
1668 goto out;
1669 }
1670
1671 if (state.image_ok == BOOT_FLAG_UNSET) {
1672 rc = boot_write_image_ok(fap);
1673 }
1674
1675out:
1676 flash_area_close(fap);
1677 return rc;
1678}
1679#endif /* !MCUBOOT_OVERWRITE_ONLY */
1680
David Vinczebb6e3b62019-07-31 14:24:05 +02001681#if (BOOT_IMAGE_NUMBER > 1)
1682/**
David Vinczecea8b592019-10-29 16:09:51 +01001683 * Check if the version of the image is not older than required.
1684 *
1685 * @param req Required minimal image version.
1686 * @param ver Version of the image to be checked.
1687 *
1688 * @return 0 if the version is sufficient, nonzero otherwise.
1689 */
1690static int
1691boot_is_version_sufficient(struct image_version *req,
1692 struct image_version *ver)
1693{
1694 if (ver->iv_major > req->iv_major) {
1695 return 0;
1696 }
1697 if (ver->iv_major < req->iv_major) {
1698 return BOOT_EBADVERSION;
1699 }
1700 /* The major version numbers are equal. */
1701 if (ver->iv_minor > req->iv_minor) {
1702 return 0;
1703 }
1704 if (ver->iv_minor < req->iv_minor) {
1705 return BOOT_EBADVERSION;
1706 }
1707 /* The minor version numbers are equal. */
1708 if (ver->iv_revision < req->iv_revision) {
1709 return BOOT_EBADVERSION;
1710 }
1711
1712 return 0;
1713}
1714
1715/**
David Vinczebb6e3b62019-07-31 14:24:05 +02001716 * Check the image dependency whether it is satisfied and modify
1717 * the swap type if necessary.
1718 *
1719 * @param dep Image dependency which has to be verified.
1720 *
1721 * @return 0 on success; nonzero on failure.
1722 */
1723static int
David Vinczecea8b592019-10-29 16:09:51 +01001724boot_verify_slot_dependency(struct boot_loader_state *state,
1725 struct image_dependency *dep)
David Vinczebb6e3b62019-07-31 14:24:05 +02001726{
1727 struct image_version *dep_version;
1728 size_t dep_slot;
1729 int rc;
David Vinczecea8b592019-10-29 16:09:51 +01001730 uint8_t swap_type;
David Vinczebb6e3b62019-07-31 14:24:05 +02001731
1732 /* Determine the source of the image which is the subject of
1733 * the dependency and get it's version. */
David Vinczecea8b592019-10-29 16:09:51 +01001734 swap_type = state->swap_type[dep->image_id];
1735 dep_slot = (swap_type != BOOT_SWAP_TYPE_NONE) ?
David Vinczebb6e3b62019-07-31 14:24:05 +02001736 BOOT_SECONDARY_SLOT : BOOT_PRIMARY_SLOT;
David Vinczecea8b592019-10-29 16:09:51 +01001737 dep_version = &state->imgs[dep->image_id][dep_slot].hdr.ih_ver;
David Vinczebb6e3b62019-07-31 14:24:05 +02001738
1739 rc = boot_is_version_sufficient(&dep->image_min_version, dep_version);
1740 if (rc != 0) {
1741 /* Dependency not satisfied.
1742 * Modify the swap type to decrease the version number of the image
1743 * (which will be located in the primary slot after the boot process),
1744 * consequently the number of unsatisfied dependencies will be
1745 * decreased or remain the same.
1746 */
David Vinczecea8b592019-10-29 16:09:51 +01001747 switch (BOOT_SWAP_TYPE(state)) {
David Vinczebb6e3b62019-07-31 14:24:05 +02001748 case BOOT_SWAP_TYPE_TEST:
1749 case BOOT_SWAP_TYPE_PERM:
David Vinczecea8b592019-10-29 16:09:51 +01001750 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
David Vinczebb6e3b62019-07-31 14:24:05 +02001751 break;
1752 case BOOT_SWAP_TYPE_NONE:
David Vinczecea8b592019-10-29 16:09:51 +01001753 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_REVERT;
David Vinczebb6e3b62019-07-31 14:24:05 +02001754 break;
1755 default:
1756 break;
1757 }
1758 }
1759
1760 return rc;
1761}
1762
1763/**
1764 * Read all dependency TLVs of an image from the flash and verify
1765 * one after another to see if they are all satisfied.
1766 *
1767 * @param slot Image slot number.
1768 *
1769 * @return 0 on success; nonzero on failure.
1770 */
1771static int
David Vinczecea8b592019-10-29 16:09:51 +01001772boot_verify_slot_dependencies(struct boot_loader_state *state, uint32_t slot)
David Vinczebb6e3b62019-07-31 14:24:05 +02001773{
1774 const struct flash_area *fap;
David Vincze07706a42019-12-12 18:20:12 +01001775 struct image_tlv_iter it;
David Vinczebb6e3b62019-07-31 14:24:05 +02001776 struct image_dependency dep;
1777 uint32_t off;
David Vincze07706a42019-12-12 18:20:12 +01001778 uint16_t len;
David Vinczecea8b592019-10-29 16:09:51 +01001779 int area_id;
David Vinczebb6e3b62019-07-31 14:24:05 +02001780 int rc;
1781
David Vinczecea8b592019-10-29 16:09:51 +01001782 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
1783 rc = flash_area_open(area_id, &fap);
David Vinczebb6e3b62019-07-31 14:24:05 +02001784 if (rc != 0) {
1785 rc = BOOT_EFLASH;
1786 goto done;
1787 }
1788
David Vincze07706a42019-12-12 18:20:12 +01001789 rc = bootutil_tlv_iter_begin(&it, boot_img_hdr(state, slot), fap,
1790 IMAGE_TLV_DEPENDENCY, true);
David Vinczebb6e3b62019-07-31 14:24:05 +02001791 if (rc != 0) {
David Vinczebb6e3b62019-07-31 14:24:05 +02001792 goto done;
1793 }
1794
David Vincze07706a42019-12-12 18:20:12 +01001795 while (true) {
1796 rc = bootutil_tlv_iter_next(&it, &off, &len, NULL);
1797 if (rc < 0) {
1798 return -1;
1799 } else if (rc > 0) {
1800 rc = 0;
David Vinczebb6e3b62019-07-31 14:24:05 +02001801 break;
1802 }
David Vincze07706a42019-12-12 18:20:12 +01001803
1804 if (len != sizeof(dep)) {
1805 rc = BOOT_EBADIMAGE;
1806 goto done;
1807 }
1808
1809 rc = flash_area_read(fap, off, &dep, len);
1810 if (rc != 0) {
1811 rc = BOOT_EFLASH;
1812 goto done;
1813 }
1814
1815 if (dep.image_id >= BOOT_IMAGE_NUMBER) {
1816 rc = BOOT_EBADARGS;
1817 goto done;
1818 }
1819
1820 /* Verify dependency and modify the swap type if not satisfied. */
1821 rc = boot_verify_slot_dependency(state, &dep);
1822 if (rc != 0) {
1823 /* Dependency not satisfied. */
1824 goto done;
Tamas Ban056ed0b2019-09-16 12:48:32 +01001825 }
David Vinczebb6e3b62019-07-31 14:24:05 +02001826 }
1827
1828done:
1829 flash_area_close(fap);
1830 return rc;
1831}
1832
1833/**
David Vinczebb6e3b62019-07-31 14:24:05 +02001834 * Iterate over all the images and verify whether the image dependencies in the
1835 * TLV area are all satisfied and update the related swap type if necessary.
1836 */
David Vinczecea8b592019-10-29 16:09:51 +01001837static int
1838boot_verify_dependencies(struct boot_loader_state *state)
David Vinczebb6e3b62019-07-31 14:24:05 +02001839{
David Vinczebb6e3b62019-07-31 14:24:05 +02001840 int rc;
David Vinczecea8b592019-10-29 16:09:51 +01001841 uint8_t slot;
David Vinczebb6e3b62019-07-31 14:24:05 +02001842
David Vinczecea8b592019-10-29 16:09:51 +01001843 BOOT_CURR_IMG(state) = 0;
1844 while (BOOT_CURR_IMG(state) < BOOT_IMAGE_NUMBER) {
1845 if (BOOT_SWAP_TYPE(state) != BOOT_SWAP_TYPE_NONE &&
1846 BOOT_SWAP_TYPE(state) != BOOT_SWAP_TYPE_FAIL) {
1847 slot = BOOT_SECONDARY_SLOT;
1848 } else {
1849 slot = BOOT_PRIMARY_SLOT;
1850 }
1851
1852 rc = boot_verify_slot_dependencies(state, slot);
David Vinczebb6e3b62019-07-31 14:24:05 +02001853 if (rc == 0) {
1854 /* All dependencies've been satisfied, continue with next image. */
David Vinczecea8b592019-10-29 16:09:51 +01001855 BOOT_CURR_IMG(state)++;
David Vinczebb6e3b62019-07-31 14:24:05 +02001856 } else if (rc == BOOT_EBADVERSION) {
David Vinczecea8b592019-10-29 16:09:51 +01001857 /* Cannot upgrade due to non-met dependencies, so disable all
1858 * image upgrades.
1859 */
1860 for (int idx = 0; idx < BOOT_IMAGE_NUMBER; idx++) {
1861 BOOT_CURR_IMG(state) = idx;
1862 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
1863 }
1864 break;
David Vinczebb6e3b62019-07-31 14:24:05 +02001865 } else {
1866 /* Other error happened, images are inconsistent */
David Vinczecea8b592019-10-29 16:09:51 +01001867 return rc;
David Vinczebb6e3b62019-07-31 14:24:05 +02001868 }
1869 }
David Vinczecea8b592019-10-29 16:09:51 +01001870 return rc;
David Vinczebb6e3b62019-07-31 14:24:05 +02001871}
1872#endif /* (BOOT_IMAGE_NUMBER > 1) */
1873
Tamas Banf70ef8c2017-12-19 15:35:09 +00001874/**
David Vincze7384ee72019-07-23 17:00:42 +02001875 * Performs a clean (not aborted) image update.
Tamas Banf70ef8c2017-12-19 15:35:09 +00001876 *
David Vincze7384ee72019-07-23 17:00:42 +02001877 * @param bs The current boot status.
Tamas Banf70ef8c2017-12-19 15:35:09 +00001878 *
1879 * @return 0 on success; nonzero on failure.
1880 */
1881static int
David Vinczecea8b592019-10-29 16:09:51 +01001882boot_perform_update(struct boot_loader_state *state, struct boot_status *bs)
Tamas Banf70ef8c2017-12-19 15:35:09 +00001883{
Tamas Banf70ef8c2017-12-19 15:35:09 +00001884 int rc;
David Vinczecea8b592019-10-29 16:09:51 +01001885#ifndef MCUBOOT_OVERWRITE_ONLY
1886 uint8_t swap_type;
1887#endif
Tamas Banf70ef8c2017-12-19 15:35:09 +00001888
David Vincze7384ee72019-07-23 17:00:42 +02001889 /* At this point there are no aborted swaps. */
1890#if defined(MCUBOOT_OVERWRITE_ONLY)
David Vinczecea8b592019-10-29 16:09:51 +01001891 rc = boot_copy_image(state, bs);
David Vincze7384ee72019-07-23 17:00:42 +02001892#else
David Vinczecea8b592019-10-29 16:09:51 +01001893 rc = boot_swap_image(state, bs);
David Vincze7384ee72019-07-23 17:00:42 +02001894#endif
Tamas Banf70ef8c2017-12-19 15:35:09 +00001895 assert(rc == 0);
David Vincze7384ee72019-07-23 17:00:42 +02001896
1897#ifndef MCUBOOT_OVERWRITE_ONLY
1898 /* The following state needs image_ok be explicitly set after the
1899 * swap was finished to avoid a new revert.
1900 */
David Vinczecea8b592019-10-29 16:09:51 +01001901 swap_type = BOOT_SWAP_TYPE(state);
1902 if (swap_type == BOOT_SWAP_TYPE_REVERT ||
1903 swap_type == BOOT_SWAP_TYPE_PERM) {
1904 rc = boot_set_image_ok(BOOT_CURR_IMG(state));
David Vincze7384ee72019-07-23 17:00:42 +02001905 if (rc != 0) {
David Vinczecea8b592019-10-29 16:09:51 +01001906 BOOT_SWAP_TYPE(state) = swap_type = BOOT_SWAP_TYPE_PANIC;
David Vincze7384ee72019-07-23 17:00:42 +02001907 }
Tamas Banf70ef8c2017-12-19 15:35:09 +00001908 }
1909
David Vinczecea8b592019-10-29 16:09:51 +01001910 if (swap_type == BOOT_SWAP_TYPE_PERM) {
David Vincze7384ee72019-07-23 17:00:42 +02001911 /* Update the stored security counter with the new image's security
1912 * counter value. The primary slot holds the new image at this
1913 * point, but the secondary slot's image header must be passed
1914 * because the read image headers in the boot_data structure have
1915 * not been updated yet.
1916 *
1917 * In case of a permanent image swap mcuboot will never attempt to
1918 * revert the images on the next reboot. Therefore, the security
1919 * counter must be increased right after the image upgrade.
David Vincze401c7422019-06-21 20:44:05 +02001920 */
David Vinczecea8b592019-10-29 16:09:51 +01001921 rc = boot_update_security_counter(
1922 BOOT_CURR_IMG(state),
1923 BOOT_PRIMARY_SLOT,
1924 boot_img_hdr(state, BOOT_SECONDARY_SLOT));
David Vincze7384ee72019-07-23 17:00:42 +02001925 if (rc != 0) {
1926 BOOT_LOG_ERR("Security counter update failed after "
1927 "image upgrade.");
David Vinczecea8b592019-10-29 16:09:51 +01001928 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
Tamas Banf70ef8c2017-12-19 15:35:09 +00001929 }
1930 }
1931
David Vinczecea8b592019-10-29 16:09:51 +01001932 if (BOOT_IS_UPGRADE(swap_type)) {
1933 rc = boot_set_copy_done(BOOT_CURR_IMG(state));
David Vincze7384ee72019-07-23 17:00:42 +02001934 if (rc != 0) {
David Vinczecea8b592019-10-29 16:09:51 +01001935 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
David Vincze7384ee72019-07-23 17:00:42 +02001936 }
1937 }
1938#endif /* !MCUBOOT_OVERWRITE_ONLY */
1939
1940 return rc;
1941}
1942
1943/**
1944 * Completes a previously aborted image swap.
1945 *
1946 * @param bs The current boot status.
1947 *
1948 * @return 0 on success; nonzero on failure.
1949 */
1950#if !defined(MCUBOOT_OVERWRITE_ONLY)
1951static int
David Vinczecea8b592019-10-29 16:09:51 +01001952boot_complete_partial_swap(struct boot_loader_state *state,
1953 struct boot_status *bs)
David Vincze7384ee72019-07-23 17:00:42 +02001954{
1955 int rc;
1956
1957 /* Determine the type of swap operation being resumed from the
1958 * `swap-type` trailer field.
1959 */
David Vinczecea8b592019-10-29 16:09:51 +01001960 rc = boot_swap_image(state, bs);
David Vincze7384ee72019-07-23 17:00:42 +02001961 assert(rc == 0);
1962
David Vinczecea8b592019-10-29 16:09:51 +01001963 BOOT_SWAP_TYPE(state) = bs->swap_type;
David Vincze7384ee72019-07-23 17:00:42 +02001964
1965 /* The following states need image_ok be explicitly set after the
1966 * swap was finished to avoid a new revert.
1967 */
1968 if (bs->swap_type == BOOT_SWAP_TYPE_REVERT ||
1969 bs->swap_type == BOOT_SWAP_TYPE_PERM) {
David Vinczecea8b592019-10-29 16:09:51 +01001970 rc = boot_set_image_ok(BOOT_CURR_IMG(state));
David Vincze7384ee72019-07-23 17:00:42 +02001971 if (rc != 0) {
David Vinczecea8b592019-10-29 16:09:51 +01001972 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
David Vincze7384ee72019-07-23 17:00:42 +02001973 }
1974 }
1975
David Vinczecea8b592019-10-29 16:09:51 +01001976 if (BOOT_IS_UPGRADE(bs->swap_type)) {
1977 rc = boot_set_copy_done(BOOT_CURR_IMG(state));
David Vincze7384ee72019-07-23 17:00:42 +02001978 if (rc != 0) {
David Vinczecea8b592019-10-29 16:09:51 +01001979 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
David Vincze7384ee72019-07-23 17:00:42 +02001980 }
1981 }
1982
David Vinczecea8b592019-10-29 16:09:51 +01001983 if (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_PANIC) {
David Vincze7384ee72019-07-23 17:00:42 +02001984 BOOT_LOG_ERR("panic!");
1985 assert(0);
1986
1987 /* Loop forever... */
1988 while (1) {}
1989 }
1990
1991 return rc;
1992}
1993#endif /* !MCUBOOT_OVERWRITE_ONLY */
1994
1995#if (BOOT_IMAGE_NUMBER > 1)
1996/**
1997 * Review the validity of previously determined swap types of other images.
1998 *
1999 * @param aborted_swap The current image upgrade is a
2000 * partial/aborted swap.
2001 */
2002static void
David Vinczecea8b592019-10-29 16:09:51 +01002003boot_review_image_swap_types(struct boot_loader_state *state,
2004 bool aborted_swap)
David Vincze7384ee72019-07-23 17:00:42 +02002005{
2006 /* In that case if we rebooted in the middle of an image upgrade process, we
2007 * must review the validity of swap types, that were previously determined
2008 * for other images. The image_ok flag had not been set before the reboot
2009 * for any of the updated images (only the copy_done flag) and thus falsely
2010 * the REVERT swap type has been determined for the previous images that had
2011 * been updated before the reboot.
2012 *
2013 * There are two separate scenarios that we have to deal with:
2014 *
2015 * 1. The reboot has happened during swapping an image:
2016 * The current image upgrade has been determined as a
2017 * partial/aborted swap.
2018 * 2. The reboot has happened between two separate image upgrades:
2019 * In this scenario we must check the swap type of the current image.
2020 * In those cases if it is NONE or REVERT we cannot certainly determine
2021 * the fact of a reboot. In a consistent state images must move in the
2022 * same direction or stay in place, e.g. in practice REVERT and TEST
2023 * swap types cannot be present at the same time. If the swap type of
2024 * the current image is either TEST, PERM or FAIL we must review the
2025 * already determined swap types of other images and set each false
2026 * REVERT swap types to NONE (these images had been successfully
2027 * updated before the system rebooted between two separate image
2028 * upgrades).
2029 */
2030
David Vinczecea8b592019-10-29 16:09:51 +01002031 if (BOOT_CURR_IMG(state) == 0) {
David Vincze7384ee72019-07-23 17:00:42 +02002032 /* Nothing to do */
2033 return;
2034 }
2035
2036 if (!aborted_swap) {
David Vinczecea8b592019-10-29 16:09:51 +01002037 if ((BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_NONE) ||
2038 (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_REVERT)) {
David Vincze7384ee72019-07-23 17:00:42 +02002039 /* Nothing to do */
2040 return;
2041 }
2042 }
2043
David Vinczecea8b592019-10-29 16:09:51 +01002044 for (uint8_t i = 0; i < BOOT_CURR_IMG(state); i++) {
2045 if (state->swap_type[i] == BOOT_SWAP_TYPE_REVERT) {
2046 state->swap_type[i] = BOOT_SWAP_TYPE_NONE;
David Vincze7384ee72019-07-23 17:00:42 +02002047 }
2048 }
2049}
2050#endif
2051
2052/**
2053 * Prepare image to be updated if required.
2054 *
2055 * Prepare image to be updated if required with completing an image swap
2056 * operation if one was aborted and/or determining the type of the
2057 * swap operation. In case of any error set the swap type to NONE.
2058 *
David Vinczecea8b592019-10-29 16:09:51 +01002059 * @param state Boot loader status information.
David Vincze7384ee72019-07-23 17:00:42 +02002060 * @param bs Pointer where the read and possibly updated
2061 * boot status can be written to.
2062 */
2063static void
David Vinczecea8b592019-10-29 16:09:51 +01002064boot_prepare_image_for_update(struct boot_loader_state *state,
2065 struct boot_status *bs)
David Vincze7384ee72019-07-23 17:00:42 +02002066{
2067 int rc;
2068
2069 /* Determine the sector layout of the image slots and scratch area. */
David Vinczecea8b592019-10-29 16:09:51 +01002070 rc = boot_read_sectors(state);
David Vincze7384ee72019-07-23 17:00:42 +02002071 if (rc != 0) {
2072 BOOT_LOG_WRN("Failed reading sectors; BOOT_MAX_IMG_SECTORS=%d"
2073 " - too small?", BOOT_MAX_IMG_SECTORS);
2074 /* Unable to determine sector layout, continue with next image
2075 * if there is one.
2076 */
David Vinczecea8b592019-10-29 16:09:51 +01002077 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
David Vincze7384ee72019-07-23 17:00:42 +02002078 return;
2079 }
2080
2081 /* Attempt to read an image header from each slot. */
David Vinczecea8b592019-10-29 16:09:51 +01002082 rc = boot_read_image_headers(state, false);
David Vincze7384ee72019-07-23 17:00:42 +02002083 if (rc != 0) {
2084 /* Continue with next image if there is one. */
David Vinczecea8b592019-10-29 16:09:51 +01002085 BOOT_LOG_WRN("Failed reading image headers; Image=%u",
2086 BOOT_CURR_IMG(state));
2087 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
David Vincze7384ee72019-07-23 17:00:42 +02002088 return;
2089 }
2090
2091 /* If the current image's slots aren't compatible, no swap is possible.
2092 * Just boot into primary slot.
2093 */
David Vinczecea8b592019-10-29 16:09:51 +01002094 if (boot_slots_compatible(state)) {
2095 rc = boot_read_status(state, bs);
David Vincze7384ee72019-07-23 17:00:42 +02002096 if (rc != 0) {
2097 BOOT_LOG_WRN("Failed reading boot status; Image=%u",
David Vinczecea8b592019-10-29 16:09:51 +01002098 BOOT_CURR_IMG(state));
David Vincze7384ee72019-07-23 17:00:42 +02002099 /* Continue with next image if there is one. */
David Vinczecea8b592019-10-29 16:09:51 +01002100 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
David Vincze7384ee72019-07-23 17:00:42 +02002101 return;
2102 }
2103
2104 /* Determine if we rebooted in the middle of an image swap
2105 * operation. If a partial swap was detected, complete it.
2106 */
2107 if (bs->idx != BOOT_STATUS_IDX_0 || bs->state != BOOT_STATUS_STATE_0) {
2108
2109#if (BOOT_IMAGE_NUMBER > 1)
David Vinczecea8b592019-10-29 16:09:51 +01002110 boot_review_image_swap_types(state, true);
David Vincze7384ee72019-07-23 17:00:42 +02002111#endif
2112
2113#ifdef MCUBOOT_OVERWRITE_ONLY
2114 /* Should never arrive here, overwrite-only mode has
2115 * no swap state.
2116 */
2117 assert(0);
2118#else
2119 /* Determine the type of swap operation being resumed from the
2120 * `swap-type` trailer field.
2121 */
David Vinczecea8b592019-10-29 16:09:51 +01002122 rc = boot_complete_partial_swap(state, bs);
David Vincze7384ee72019-07-23 17:00:42 +02002123 assert(rc == 0);
2124#endif
2125 /* Attempt to read an image header from each slot. Ensure that
2126 * image headers in slots are aligned with headers in boot_data.
2127 */
David Vinczecea8b592019-10-29 16:09:51 +01002128 rc = boot_read_image_headers(state, false);
David Vincze7384ee72019-07-23 17:00:42 +02002129 assert(rc == 0);
2130
2131 /* Swap has finished set to NONE */
David Vinczecea8b592019-10-29 16:09:51 +01002132 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
David Vincze7384ee72019-07-23 17:00:42 +02002133 } else {
2134 /* There was no partial swap, determine swap type. */
2135 if (bs->swap_type == BOOT_SWAP_TYPE_NONE) {
David Vinczecea8b592019-10-29 16:09:51 +01002136 BOOT_SWAP_TYPE(state) = boot_validated_swap_type(state, bs);
2137 } else if (boot_validate_slot(state,
2138 BOOT_SECONDARY_SLOT, bs) != 0) {
2139 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_FAIL;
David Vincze7384ee72019-07-23 17:00:42 +02002140 } else {
David Vinczecea8b592019-10-29 16:09:51 +01002141 BOOT_SWAP_TYPE(state) = bs->swap_type;
David Vincze7384ee72019-07-23 17:00:42 +02002142 }
2143
2144#if (BOOT_IMAGE_NUMBER > 1)
David Vinczecea8b592019-10-29 16:09:51 +01002145 boot_review_image_swap_types(state, false);
David Vincze7384ee72019-07-23 17:00:42 +02002146#endif
2147 }
2148 } else {
2149 /* In that case if slots are not compatible. */
David Vinczecea8b592019-10-29 16:09:51 +01002150 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
David Vincze7384ee72019-07-23 17:00:42 +02002151 }
Tamas Banf70ef8c2017-12-19 15:35:09 +00002152}
2153
2154/**
2155 * Prepares the booting process. This function moves images around in flash as
2156 * appropriate, and tells you what address to boot from.
2157 *
David Vinczecea8b592019-10-29 16:09:51 +01002158 * @param state Boot loader status information.
Tamas Banf70ef8c2017-12-19 15:35:09 +00002159 * @param rsp On success, indicates how booting should occur.
2160 *
2161 * @return 0 on success; nonzero on failure.
2162 */
2163int
David Vinczecea8b592019-10-29 16:09:51 +01002164context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp)
Tamas Banf70ef8c2017-12-19 15:35:09 +00002165{
Tamas Banf70ef8c2017-12-19 15:35:09 +00002166 size_t slot;
David Vincze7384ee72019-07-23 17:00:42 +02002167 struct boot_status bs;
Tamas Ban4e5ed8d2019-09-17 09:31:11 +01002168 int rc = 0;
Tamas Banf70ef8c2017-12-19 15:35:09 +00002169 int fa_id;
David Vinczecea8b592019-10-29 16:09:51 +01002170 int image_index;
2171 bool has_upgrade;
Tamas Banf70ef8c2017-12-19 15:35:09 +00002172
2173 /* The array of slot sectors are defined here (as opposed to file scope) so
2174 * that they don't get allocated for non-boot-loader apps. This is
2175 * necessary because the gcc option "-fdata-sections" doesn't seem to have
2176 * any effect in older gcc versions (e.g., 4.8.4).
2177 */
David Vincze7384ee72019-07-23 17:00:42 +02002178 static boot_sector_t
2179 primary_slot_sectors[BOOT_IMAGE_NUMBER][BOOT_MAX_IMG_SECTORS];
2180 static boot_sector_t
2181 secondary_slot_sectors[BOOT_IMAGE_NUMBER][BOOT_MAX_IMG_SECTORS];
David Vincze401c7422019-06-21 20:44:05 +02002182 static boot_sector_t scratch_sectors[BOOT_MAX_IMG_SECTORS];
Tamas Banf70ef8c2017-12-19 15:35:09 +00002183
David Vincze7384ee72019-07-23 17:00:42 +02002184 /* Iterate over all the images. By the end of the loop the swap type has
2185 * to be determined for each image and all aborted swaps have to be
2186 * completed.
Tamas Banf70ef8c2017-12-19 15:35:09 +00002187 */
David Vinczecea8b592019-10-29 16:09:51 +01002188 IMAGES_ITER(BOOT_CURR_IMG(state)) {
2189
2190 image_index = BOOT_CURR_IMG(state);
2191
2192 BOOT_IMG(state, BOOT_PRIMARY_SLOT).sectors =
2193 primary_slot_sectors[image_index];
2194 BOOT_IMG(state, BOOT_SECONDARY_SLOT).sectors =
2195 secondary_slot_sectors[image_index];
2196 state->scratch.sectors = scratch_sectors;
Tamas Banf70ef8c2017-12-19 15:35:09 +00002197
David Vincze7384ee72019-07-23 17:00:42 +02002198 /* Open primary and secondary image areas for the duration
2199 * of this call.
Tamas Banf70ef8c2017-12-19 15:35:09 +00002200 */
David Vincze7384ee72019-07-23 17:00:42 +02002201 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
David Vinczecea8b592019-10-29 16:09:51 +01002202 fa_id = flash_area_id_from_multi_image_slot(image_index, slot);
2203 rc = flash_area_open(fa_id, &BOOT_IMG_AREA(state, slot));
David Vincze7384ee72019-07-23 17:00:42 +02002204 assert(rc == 0);
2205 }
2206 rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH,
David Vinczecea8b592019-10-29 16:09:51 +01002207 &BOOT_SCRATCH_AREA(state));
David Vincze7384ee72019-07-23 17:00:42 +02002208 assert(rc == 0);
2209
2210 /* Determine swap type and complete swap if it has been aborted. */
David Vinczecea8b592019-10-29 16:09:51 +01002211 boot_prepare_image_for_update(state, &bs);
2212
2213 if (BOOT_IS_UPGRADE(BOOT_SWAP_TYPE(state))) {
2214 has_upgrade = true;
2215 }
David Vincze7384ee72019-07-23 17:00:42 +02002216 }
2217
David Vinczebb6e3b62019-07-31 14:24:05 +02002218#if (BOOT_IMAGE_NUMBER > 1)
David Vinczecea8b592019-10-29 16:09:51 +01002219 if (has_upgrade) {
2220 /* Iterate over all the images and verify whether the image dependencies
2221 * are all satisfied and update swap type if necessary.
2222 */
2223 rc = boot_verify_dependencies(state);
2224 if (rc == BOOT_EBADVERSION) {
2225 /*
2226 * It was impossible to upgrade because the expected dependency
2227 * version was not available. Here we already changed the swap_type
2228 * so that instead of asserting the bootloader, we continue and no
2229 * upgrade is performed.
2230 */
2231 rc = 0;
2232 }
2233 }
David Vinczebb6e3b62019-07-31 14:24:05 +02002234#endif
2235
David Vincze7384ee72019-07-23 17:00:42 +02002236 /* Iterate over all the images. At this point there are no aborted swaps
2237 * and the swap types are determined for each image. By the end of the loop
2238 * all required update operations will have been finished.
2239 */
David Vinczecea8b592019-10-29 16:09:51 +01002240 IMAGES_ITER(BOOT_CURR_IMG(state)) {
David Vincze7384ee72019-07-23 17:00:42 +02002241
2242#if (BOOT_IMAGE_NUMBER > 1)
2243 /* Indicate that swap is not aborted */
2244 memset(&bs, 0, sizeof bs);
2245 bs.idx = BOOT_STATUS_IDX_0;
2246 bs.state = BOOT_STATUS_STATE_0;
2247#endif /* (BOOT_IMAGE_NUMBER > 1) */
2248
2249 /* Set the previously determined swap type */
David Vinczecea8b592019-10-29 16:09:51 +01002250 bs.swap_type = BOOT_SWAP_TYPE(state);
David Vincze7384ee72019-07-23 17:00:42 +02002251
David Vinczecea8b592019-10-29 16:09:51 +01002252 switch (BOOT_SWAP_TYPE(state)) {
David Vincze7384ee72019-07-23 17:00:42 +02002253 case BOOT_SWAP_TYPE_NONE:
2254 break;
2255
2256 case BOOT_SWAP_TYPE_TEST: /* fallthrough */
2257 case BOOT_SWAP_TYPE_PERM: /* fallthrough */
2258 case BOOT_SWAP_TYPE_REVERT:
David Vinczecea8b592019-10-29 16:09:51 +01002259 rc = boot_perform_update(state, &bs);
David Vincze7384ee72019-07-23 17:00:42 +02002260 assert(rc == 0);
2261 break;
2262
2263 case BOOT_SWAP_TYPE_FAIL:
2264 /* The image in secondary slot was invalid and is now erased. Ensure
2265 * we don't try to boot into it again on the next reboot. Do this by
2266 * pretending we just reverted back to primary slot.
2267 */
Tamas Banf70ef8c2017-12-19 15:35:09 +00002268#ifndef MCUBOOT_OVERWRITE_ONLY
David Vincze7384ee72019-07-23 17:00:42 +02002269 /* image_ok needs to be explicitly set to avoid a new revert. */
David Vinczecea8b592019-10-29 16:09:51 +01002270 rc = boot_set_image_ok(BOOT_CURR_IMG(state));
Tamas Banf70ef8c2017-12-19 15:35:09 +00002271 if (rc != 0) {
David Vinczecea8b592019-10-29 16:09:51 +01002272 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
Tamas Banf70ef8c2017-12-19 15:35:09 +00002273 }
2274#endif /* !MCUBOOT_OVERWRITE_ONLY */
David Vincze7384ee72019-07-23 17:00:42 +02002275 break;
2276
2277 default:
David Vinczecea8b592019-10-29 16:09:51 +01002278 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
Tamas Banf70ef8c2017-12-19 15:35:09 +00002279 }
David Vincze7384ee72019-07-23 17:00:42 +02002280
David Vinczecea8b592019-10-29 16:09:51 +01002281 if (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_PANIC) {
David Vincze7384ee72019-07-23 17:00:42 +02002282 BOOT_LOG_ERR("panic!");
2283 assert(0);
2284
2285 /* Loop forever... */
2286 while (1) {}
2287 }
Tamas Banf70ef8c2017-12-19 15:35:09 +00002288 }
2289
David Vincze7384ee72019-07-23 17:00:42 +02002290 /* Iterate over all the images. At this point all required update operations
2291 * have finished. By the end of the loop each image in the primary slot will
2292 * have been re-validated.
2293 */
David Vinczecea8b592019-10-29 16:09:51 +01002294 IMAGES_ITER(BOOT_CURR_IMG(state)) {
2295 if (BOOT_SWAP_TYPE(state) != BOOT_SWAP_TYPE_NONE) {
David Vincze7384ee72019-07-23 17:00:42 +02002296 /* Attempt to read an image header from each slot. Ensure that image
2297 * headers in slots are aligned with headers in boot_data.
David Vincze060968d2019-05-23 01:13:14 +02002298 */
David Vinczecea8b592019-10-29 16:09:51 +01002299 rc = boot_read_image_headers(state, false);
David Vincze060968d2019-05-23 01:13:14 +02002300 if (rc != 0) {
David Vincze7384ee72019-07-23 17:00:42 +02002301 goto out;
2302 }
2303 /* Since headers were reloaded, it can be assumed we just performed
2304 * a swap or overwrite. Now the header info that should be used to
2305 * provide the data for the bootstrap, which previously was at
2306 * secondary slot, was updated to primary slot.
2307 */
2308 }
2309
2310#ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT
David Vinczecea8b592019-10-29 16:09:51 +01002311 rc = boot_validate_slot(state, BOOT_PRIMARY_SLOT, NULL);
David Vincze7384ee72019-07-23 17:00:42 +02002312 if (rc != 0) {
2313 rc = BOOT_EBADIMAGE;
2314 goto out;
2315 }
2316#else
2317 /* Even if we're not re-validating the primary slot, we could be booting
2318 * onto an empty flash chip. At least do a basic sanity check that
2319 * the magic number on the image is OK.
2320 */
David Vinczecea8b592019-10-29 16:09:51 +01002321 if (!BOOT_IMG_HDR_IS_VALID(state, BOOT_PRIMARY_SLOT)) {
2322 BOOT_LOG_ERR("bad image magic 0x%lx; Image=%u", (unsigned long)
2323 &boot_img_hdr(state, BOOT_PRIMARY_SLOT)->ih_magic,
2324 BOOT_CURR_IMG(state));
David Vincze7384ee72019-07-23 17:00:42 +02002325 rc = BOOT_EBADIMAGE;
2326 goto out;
2327 }
2328#endif /* MCUBOOT_VALIDATE_PRIMARY_SLOT */
2329
2330 /* Update the stored security counter with the active image's security
2331 * counter value. It will be updated only if the new security counter is
2332 * greater than the stored value.
2333 *
2334 * In case of a successful image swapping when the swap type is TEST the
2335 * security counter can be increased only after a reset, when the swap
2336 * type is NONE and the image has marked itself "OK" (the image_ok flag
2337 * has been set). This way a "revert" swap can be performed if it's
2338 * necessary.
2339 */
David Vinczecea8b592019-10-29 16:09:51 +01002340 if (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_NONE) {
2341 rc = boot_update_security_counter(
2342 BOOT_CURR_IMG(state),
2343 BOOT_PRIMARY_SLOT,
2344 boot_img_hdr(state, BOOT_PRIMARY_SLOT));
David Vincze7384ee72019-07-23 17:00:42 +02002345 if (rc != 0) {
2346 BOOT_LOG_ERR("Security counter update failed after image "
2347 "validation.");
David Vincze060968d2019-05-23 01:13:14 +02002348 goto out;
2349 }
2350 }
2351
David Vincze7384ee72019-07-23 17:00:42 +02002352 /* Save boot status to shared memory area */
2353#if (BOOT_IMAGE_NUMBER > 1)
David Vinczecea8b592019-10-29 16:09:51 +01002354 rc = boot_save_boot_status((BOOT_CURR_IMG(state) == 0) ?
2355 SW_SPE : SW_NSPE,
2356 boot_img_hdr(state, BOOT_PRIMARY_SLOT),
2357 BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT)
David Vincze7384ee72019-07-23 17:00:42 +02002358 );
David Vincze8bdfc2d2019-03-18 15:49:23 +01002359#else
David Vincze7384ee72019-07-23 17:00:42 +02002360 rc = boot_save_boot_status(SW_S_NS,
David Vinczecea8b592019-10-29 16:09:51 +01002361 boot_img_hdr(state, BOOT_PRIMARY_SLOT),
2362 BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT)
David Vincze7384ee72019-07-23 17:00:42 +02002363 );
2364#endif
2365 if (rc) {
2366 BOOT_LOG_ERR("Failed to add Image %u data to shared area",
David Vinczecea8b592019-10-29 16:09:51 +01002367 BOOT_CURR_IMG(state));
David Vincze060968d2019-05-23 01:13:14 +02002368 }
2369 }
2370
David Vinczecea8b592019-10-29 16:09:51 +01002371#if (BOOT_IMAGE_NUMBER > 1)
David Vincze7384ee72019-07-23 17:00:42 +02002372 /* Always boot from the primary slot of Image 0. */
David Vinczecea8b592019-10-29 16:09:51 +01002373 BOOT_CURR_IMG(state) = 0;
2374#endif
Tamas Ban0e8ab302019-01-17 11:45:31 +00002375
David Vinczecea8b592019-10-29 16:09:51 +01002376 rsp->br_flash_dev_id =
2377 BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT)->fa_device_id;
2378 rsp->br_image_off =
2379 boot_img_slot_off(state, BOOT_PRIMARY_SLOT);
2380 rsp->br_hdr =
2381 boot_img_hdr(state, BOOT_PRIMARY_SLOT);
2382
2383out:
2384 IMAGES_ITER(BOOT_CURR_IMG(state)) {
2385 flash_area_close(BOOT_SCRATCH_AREA(state));
David Vincze7384ee72019-07-23 17:00:42 +02002386 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
David Vinczecea8b592019-10-29 16:09:51 +01002387 flash_area_close(BOOT_IMG_AREA(state,
David Vincze7384ee72019-07-23 17:00:42 +02002388 BOOT_NUM_SLOTS - 1 - slot));
2389 }
Tamas Banf70ef8c2017-12-19 15:35:09 +00002390 }
2391 return rc;
2392}
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002393
Oliver Swedef9982442018-08-24 18:37:44 +01002394#else /* MCUBOOT_NO_SWAP || MCUBOOT_RAM_LOADING */
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002395
David Vinczedcba70b2019-05-28 12:02:52 +02002396#define BOOT_LOG_IMAGE_INFO(area, hdr, state) \
2397 BOOT_LOG_INF("Image %u: version=%u.%u.%u+%u, magic=%5s, image_ok=0x%x", \
2398 (area), \
2399 (hdr)->ih_ver.iv_major, \
2400 (hdr)->ih_ver.iv_minor, \
2401 (hdr)->ih_ver.iv_revision, \
2402 (hdr)->ih_ver.iv_build_num, \
2403 ((state)->magic == BOOT_MAGIC_GOOD ? "good" : \
2404 (state)->magic == BOOT_MAGIC_UNSET ? "unset" : \
2405 "bad"), \
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002406 (state)->image_ok)
2407
2408struct image_slot_version {
2409 uint64_t version;
2410 uint32_t slot_number;
2411};
2412
2413/**
2414 * Extract the version number from the image header. This function must be
2415 * ported if version number format has changed in the image header.
2416 *
2417 * @param hdr Pointer to an image header structure
2418 *
Oliver Swedef9982442018-08-24 18:37:44 +01002419 * @return Version number casted to uint64_t
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002420 */
2421static uint64_t
2422boot_get_version_number(struct image_header *hdr)
2423{
Oliver Swedef9982442018-08-24 18:37:44 +01002424 uint64_t version = 0;
2425 version |= (uint64_t)hdr->ih_ver.iv_major << (IMAGE_VER_MINOR_LENGTH
2426 + IMAGE_VER_REVISION_LENGTH
2427 + IMAGE_VER_BUILD_NUM_LENGTH);
2428 version |= (uint64_t)hdr->ih_ver.iv_minor << (IMAGE_VER_REVISION_LENGTH
2429 + IMAGE_VER_BUILD_NUM_LENGTH);
2430 version |= (uint64_t)hdr->ih_ver.iv_revision << IMAGE_VER_BUILD_NUM_LENGTH;
2431 version |= hdr->ih_ver.iv_build_num;
2432 return version;
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002433}
2434
2435/**
2436 * Comparator function for `qsort` to compare version numbers. This function
2437 * must be ported if version number format has changed in the image header.
2438 *
2439 * @param ver1 Pointer to an array element which holds the version number
2440 * @param ver2 Pointer to another array element which holds the version
2441 * number
2442 *
2443 * @return if version1 > version2 -1
2444 * if version1 == version2 0
2445 * if version1 < version2 1
2446 */
2447static int
2448boot_compare_version_numbers(const void *ver1, const void *ver2)
2449{
2450 if (((struct image_slot_version *)ver1)->version <
2451 ((struct image_slot_version *)ver2)->version) {
2452 return 1;
2453 }
2454
2455 if (((struct image_slot_version *)ver1)->version ==
2456 ((struct image_slot_version *)ver2)->version) {
2457 return 0;
2458 }
2459
2460 return -1;
2461}
2462
2463/**
2464 * Sort the available images based on the version number and puts them in
2465 * a list.
2466 *
David Vinczecea8b592019-10-29 16:09:51 +01002467 * @param state Boot loader status information.
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002468 * @param boot_sequence A pointer to an array, whose aim is to carry
2469 * the boot order of candidate images.
2470 * @param slot_cnt The number of flash areas, which can contains firmware
2471 * images.
2472 *
2473 * @return The number of valid images.
2474 */
2475uint32_t
David Vinczecea8b592019-10-29 16:09:51 +01002476boot_get_boot_sequence(struct boot_loader_state *state,
2477 uint32_t *boot_sequence, uint32_t slot_cnt)
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002478{
2479 struct boot_swap_state slot_state;
2480 struct image_header *hdr;
2481 struct image_slot_version image_versions[BOOT_NUM_SLOTS] = {{0}};
2482 uint32_t image_cnt = 0;
2483 uint32_t slot;
2484 int32_t rc;
2485 int32_t fa_id;
2486
2487 for (slot = 0; slot < slot_cnt; slot++) {
David Vinczecea8b592019-10-29 16:09:51 +01002488 hdr = boot_img_hdr(state, slot);
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002489 fa_id = flash_area_id_from_image_slot(slot);
2490 rc = boot_read_swap_state_by_id(fa_id, &slot_state);
2491 if (rc != 0) {
David Vinczedcba70b2019-05-28 12:02:52 +02002492 BOOT_LOG_ERR("Error during reading image trailer from slot: %u",
2493 slot);
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002494 continue;
2495 }
2496
David Vinczecea8b592019-10-29 16:09:51 +01002497 if (BOOT_IMG_HDR_IS_VALID(state, slot)) {
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002498 if (slot_state.magic == BOOT_MAGIC_GOOD ||
David Vincze39e78552018-10-10 17:10:01 +02002499 slot_state.image_ok == BOOT_FLAG_SET) {
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002500 /* Valid cases:
2501 * - Test mode: magic is OK in image trailer
2502 * - Permanent mode: image_ok flag has previously set
2503 */
2504 image_versions[slot].slot_number = slot;
2505 image_versions[slot].version = boot_get_version_number(hdr);
2506 image_cnt++;
2507 }
2508
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002509 BOOT_LOG_IMAGE_INFO(slot, hdr, &slot_state);
2510 } else {
David Vinczedcba70b2019-05-28 12:02:52 +02002511 BOOT_LOG_INF("Image %u: No valid image", slot);
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002512 }
2513 }
2514
2515 /* Sort the images based on version number */
2516 qsort(&image_versions[0],
2517 slot_cnt,
2518 sizeof(struct image_slot_version),
2519 boot_compare_version_numbers);
2520
2521 /* Copy the calculated boot sequence to boot_sequence array */
2522 for (slot = 0; slot < slot_cnt; slot++) {
2523 boot_sequence[slot] = image_versions[slot].slot_number;
2524 }
2525
2526 return image_cnt;
2527}
2528
Oliver Swedef9982442018-08-24 18:37:44 +01002529#ifdef MCUBOOT_RAM_LOADING
Raef Colesaf082382019-10-01 11:10:33 +01002530
2531/**
2532 * Verifies that the image in a slot lies within the predefined bounds that are
2533 * allowed to be used by executable images.
2534 *
2535 * @param img_dst The address to which the image is going to be copied.
2536 *
2537 * @param img_sz The size of the image.
2538 *
2539 * @return 0 on success; nonzero on failure.
2540 */
2541static int
2542boot_verify_ram_loading_address(uint32_t img_dst, uint32_t img_sz)
2543{
David Vincze0dc41d22019-10-28 14:56:29 +01002544 uint32_t img_end_addr;
2545
Raef Colesaf082382019-10-01 11:10:33 +01002546 if (img_dst < IMAGE_EXECUTABLE_RAM_START) {
2547 return BOOT_EBADIMAGE;
2548 }
2549
David Vincze0dc41d22019-10-28 14:56:29 +01002550 if (!boot_u32_safe_add(&img_end_addr, img_dst, img_sz)) {
Raef Colesaf082382019-10-01 11:10:33 +01002551 return BOOT_EBADIMAGE;
2552 }
2553
David Vincze0dc41d22019-10-28 14:56:29 +01002554 if (img_end_addr > (IMAGE_EXECUTABLE_RAM_START +
2555 IMAGE_EXECUTABLE_RAM_SIZE)) {
Raef Colesaf082382019-10-01 11:10:33 +01002556 return BOOT_EBADIMAGE;
2557 }
2558
2559 return 0;
2560}
2561
Oliver Swedef9982442018-08-24 18:37:44 +01002562/**
2563 * Copies an image from a slot in the flash to an SRAM address, where the load
2564 * address has already been inserted into the image header by this point and is
2565 * extracted from it within this method. The copying is done sector-by-sector.
2566 *
David Vinczecea8b592019-10-29 16:09:51 +01002567 * @param state Boot loader status information.
Oliver Swedef9982442018-08-24 18:37:44 +01002568 * @param slot The flash slot of the image to be copied to SRAM.
2569 *
2570 * @param hdr Pointer to the image header structure of the image
Raef Colesaf082382019-10-01 11:10:33 +01002571 *
2572 * @param img_dst The address at which the image needs to be copied to
2573 * SRAM.
2574 *
2575 * @param img_sz The size of the image that needs to be copied to SRAM.
Oliver Swedef9982442018-08-24 18:37:44 +01002576 *
2577 * @return 0 on success; nonzero on failure.
2578 */
2579static int
David Vinczecea8b592019-10-29 16:09:51 +01002580boot_copy_image_to_sram(struct boot_loader_state *state, int slot,
2581 struct image_header *hdr,
Raef Colesaf082382019-10-01 11:10:33 +01002582 uint32_t img_dst, uint32_t img_sz)
Oliver Swedef9982442018-08-24 18:37:44 +01002583{
2584 int rc;
2585 uint32_t sect_sz;
2586 uint32_t sect = 0;
2587 uint32_t bytes_copied = 0;
2588 const struct flash_area *fap_src = NULL;
Oliver Swedef9982442018-08-24 18:37:44 +01002589
Raef Colesaf082382019-10-01 11:10:33 +01002590 if (img_dst % 4 != 0) {
Tamas Banc27b5c32019-05-28 16:30:19 +01002591 BOOT_LOG_INF("Cannot copy the image to the SRAM address 0x%x "
Oliver Swedef9982442018-08-24 18:37:44 +01002592 "- the load address must be aligned with 4 bytes due to SRAM "
Raef Colesaf082382019-10-01 11:10:33 +01002593 "restrictions", img_dst);
Oliver Swedef9982442018-08-24 18:37:44 +01002594 return BOOT_EBADARGS;
2595 }
2596
2597 rc = flash_area_open(flash_area_id_from_image_slot(slot), &fap_src);
2598 if (rc != 0) {
2599 return BOOT_EFLASH;
2600 }
2601
Oliver Swedef9982442018-08-24 18:37:44 +01002602 while (bytes_copied < img_sz) {
David Vinczecea8b592019-10-29 16:09:51 +01002603 sect_sz = boot_img_sector_size(state, slot, sect);
Oliver Swedef9982442018-08-24 18:37:44 +01002604 /*
2605 * Direct copy from where the image sector resides in flash to its new
2606 * location in SRAM
2607 */
2608 rc = flash_area_read(fap_src,
2609 bytes_copied,
Raef Colesaf082382019-10-01 11:10:33 +01002610 (void *)(img_dst + bytes_copied),
Oliver Swedef9982442018-08-24 18:37:44 +01002611 sect_sz);
2612 if (rc != 0) {
2613 BOOT_LOG_INF("Error whilst copying image from Flash to SRAM");
2614 break;
2615 } else {
2616 bytes_copied += sect_sz;
2617 }
2618 sect++;
2619 }
2620
2621 if (fap_src) {
2622 flash_area_close(fap_src);
2623 }
2624 return rc;
2625}
Raef Coles27a61452019-09-25 15:32:25 +01002626
2627/**
2628 * Removes an image from SRAM, by overwriting it with zeros.
2629 *
Raef Colesaf082382019-10-01 11:10:33 +01002630 * @param img_dst The address of the image that needs to be removed from
2631 * SRAM.
Raef Coles27a61452019-09-25 15:32:25 +01002632 *
Raef Colesaf082382019-10-01 11:10:33 +01002633 * @param img_sz The size of the image that needs to be removed from
2634 * SRAM.
Raef Coles27a61452019-09-25 15:32:25 +01002635 *
2636 * @return 0 on success; nonzero on failure.
2637 */
2638static int
Raef Colesaf082382019-10-01 11:10:33 +01002639boot_remove_image_from_sram(uint32_t img_dst, uint32_t img_sz)
Raef Coles27a61452019-09-25 15:32:25 +01002640{
Raef Colesaf082382019-10-01 11:10:33 +01002641 BOOT_LOG_INF("Removing image from SRAM at address 0x%x", img_dst);
2642 memset((void*)img_dst, 0, img_sz);
Raef Coles27a61452019-09-25 15:32:25 +01002643
2644 return 0;
2645}
Oliver Swedef9982442018-08-24 18:37:44 +01002646#endif /* MCUBOOT_RAM_LOADING */
2647
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002648/**
2649 * Prepares the booting process. This function choose the newer image in flash
David Vinczecea8b592019-10-29 16:09:51 +01002650 * as appropriate, and tells you what address to boot from.
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002651 *
David Vinczecea8b592019-10-29 16:09:51 +01002652 * @param state Boot loader status information.
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002653 * @param rsp On success, indicates how booting should occur.
2654 *
2655 * @return 0 on success; nonzero on failure.
2656 */
2657int
David Vinczecea8b592019-10-29 16:09:51 +01002658context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp)
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002659{
2660 size_t slot = 0;
2661 int32_t i;
2662 int rc;
2663 int fa_id;
2664 uint32_t boot_sequence[BOOT_NUM_SLOTS];
2665 uint32_t img_cnt;
Raef Coles27a61452019-09-25 15:32:25 +01002666 struct image_header *selected_image_header;
2667#ifdef MCUBOOT_RAM_LOADING
2668 int image_copied = 0;
Raef Colesaf082382019-10-01 11:10:33 +01002669 uint32_t img_dst = 0;
2670 uint32_t img_sz = 0;
Raef Coles27a61452019-09-25 15:32:25 +01002671#endif /* MCUBOOT_RAM_LOADING */
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002672
David Vincze8bdfc2d2019-03-18 15:49:23 +01002673 static boot_sector_t primary_slot_sectors[BOOT_MAX_IMG_SECTORS];
2674 static boot_sector_t secondary_slot_sectors[BOOT_MAX_IMG_SECTORS];
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002675
David Vinczecea8b592019-10-29 16:09:51 +01002676 BOOT_IMG(state, BOOT_PRIMARY_SLOT).sectors = &primary_slot_sectors[0];
2677 BOOT_IMG(state, BOOT_SECONDARY_SLOT).sectors = &secondary_slot_sectors[0];
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002678
2679 /* Open boot_data image areas for the duration of this call. */
2680 for (i = 0; i < BOOT_NUM_SLOTS; i++) {
2681 fa_id = flash_area_id_from_image_slot(i);
David Vinczecea8b592019-10-29 16:09:51 +01002682 rc = flash_area_open(fa_id, &BOOT_IMG_AREA(state, i));
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002683 assert(rc == 0);
2684 }
2685
2686 /* Determine the sector layout of the image slots. */
David Vinczecea8b592019-10-29 16:09:51 +01002687 rc = boot_read_sectors(state);
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002688 if (rc != 0) {
David Vinczecea8b592019-10-29 16:09:51 +01002689 BOOT_LOG_WRN("Failed reading sectors; BOOT_MAX_IMG_SECTORS=%d - "
2690 "too small?", BOOT_MAX_IMG_SECTORS);
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002691 goto out;
2692 }
2693
2694 /* Attempt to read an image header from each slot. */
David Vinczecea8b592019-10-29 16:09:51 +01002695 rc = boot_read_image_headers(state, false);
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002696 if (rc != 0) {
2697 goto out;
2698 }
2699
David Vinczecea8b592019-10-29 16:09:51 +01002700 img_cnt = boot_get_boot_sequence(state, boot_sequence, BOOT_NUM_SLOTS);
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002701 if (img_cnt) {
2702 /* Authenticate images */
2703 for (i = 0; i < img_cnt; i++) {
Raef Coles27a61452019-09-25 15:32:25 +01002704
2705 slot = boot_sequence[i];
David Vinczecea8b592019-10-29 16:09:51 +01002706 selected_image_header = boot_img_hdr(state, slot);
Raef Coles27a61452019-09-25 15:32:25 +01002707
2708#ifdef MCUBOOT_RAM_LOADING
2709 if (selected_image_header->ih_flags & IMAGE_F_RAM_LOAD) {
Raef Colesaf082382019-10-01 11:10:33 +01002710
2711 img_dst = selected_image_header->ih_load_addr;
2712
David Vinczecea8b592019-10-29 16:09:51 +01002713 rc = boot_read_image_size(state, slot, &img_sz);
Raef Colesaf082382019-10-01 11:10:33 +01002714 if (rc != 0) {
2715 rc = BOOT_EFLASH;
2716 BOOT_LOG_INF("Could not load image headers from the image"
2717 "in the %s slot.",
2718 (slot == BOOT_PRIMARY_SLOT) ?
2719 "primary" : "secondary");
2720 continue;
2721 }
2722
2723 rc = boot_verify_ram_loading_address(img_dst, img_sz);
2724 if (rc != 0) {
2725 BOOT_LOG_INF("Could not copy image from the %s slot in "
2726 "the Flash to load address 0x%x in SRAM as"
2727 " the image would overlap memory outside"
2728 " the defined executable region.",
2729 (slot == BOOT_PRIMARY_SLOT) ?
2730 "primary" : "secondary",
2731 selected_image_header->ih_load_addr);
2732 continue;
2733 }
2734
Raef Coles27a61452019-09-25 15:32:25 +01002735 /* Copy image to the load address from where it
2736 * currently resides in flash
2737 */
David Vinczecea8b592019-10-29 16:09:51 +01002738 rc = boot_copy_image_to_sram(state, slot, selected_image_header,
Raef Colesaf082382019-10-01 11:10:33 +01002739 img_dst, img_sz);
Raef Coles27a61452019-09-25 15:32:25 +01002740 if (rc != 0) {
2741 rc = BOOT_EBADIMAGE;
2742 BOOT_LOG_INF("Could not copy image from the %s slot in "
2743 "the Flash to load address 0x%x in SRAM, "
2744 "aborting..", (slot == BOOT_PRIMARY_SLOT) ?
2745 "primary" : "secondary",
2746 selected_image_header->ih_load_addr);
2747 continue;
2748 } else {
2749 BOOT_LOG_INF("Image has been copied from the %s slot in "
2750 "the flash to SRAM address 0x%x",
2751 (slot == BOOT_PRIMARY_SLOT) ?
2752 "primary" : "secondary",
2753 selected_image_header->ih_load_addr);
2754 image_copied = 1;
2755 }
2756 } else {
2757 /* Only images that support IMAGE_F_RAM_LOAD are allowed if
2758 * MCUBOOT_RAM_LOADING is set.
2759 */
2760 rc = BOOT_EBADIMAGE;
2761 continue;
2762 }
2763#endif /* MCUBOOT_RAM_LOADING */
David Vinczecea8b592019-10-29 16:09:51 +01002764 rc = boot_validate_slot(state, slot, NULL);
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002765 if (rc == 0) {
Raef Coles27a61452019-09-25 15:32:25 +01002766 /* If a valid image is found then there is no reason to check
2767 * the rest of the images, as they were already ordered by
2768 * preference.
2769 */
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002770 break;
2771 }
Raef Coles27a61452019-09-25 15:32:25 +01002772#ifdef MCUBOOT_RAM_LOADING
2773 else if (image_copied) {
2774 /* If an image is found to be invalid then it is removed from
2775 * RAM to prevent it being a shellcode vector.
2776 */
Raef Colesaf082382019-10-01 11:10:33 +01002777 boot_remove_image_from_sram(img_dst, img_sz);
Raef Coles27a61452019-09-25 15:32:25 +01002778 image_copied = 0;
2779 }
2780#endif /* MCUBOOT_RAM_LOADING */
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002781 }
2782 if (rc) {
2783 /* If there was no valid image at all */
2784 rc = BOOT_EBADIMAGE;
2785 goto out;
2786 }
2787
David Vincze060968d2019-05-23 01:13:14 +02002788 /* Update the security counter with the newest image's security
2789 * counter value.
2790 */
David Vinczecea8b592019-10-29 16:09:51 +01002791 rc = boot_update_security_counter(BOOT_CURR_IMG(state), slot,
2792 selected_image_header);
David Vincze060968d2019-05-23 01:13:14 +02002793 if (rc != 0) {
2794 BOOT_LOG_ERR("Security counter update failed after image "
2795 "validation.");
2796 goto out;
2797 }
2798
Oliver Swedef9982442018-08-24 18:37:44 +01002799
David Vincze8a2a4e22019-05-24 10:14:23 +02002800#ifdef MCUBOOT_RAM_LOADING
Raef Coles27a61452019-09-25 15:32:25 +01002801 BOOT_LOG_INF("Booting image from SRAM at address 0x%x",
2802 selected_image_header->ih_load_addr);
2803#else
2804 BOOT_LOG_INF("Booting image from the %s slot",
2805 (slot == BOOT_PRIMARY_SLOT) ? "primary" : "secondary");
2806#endif /* MCUBOOT_RAM_LOADING */
Oliver Swedef9982442018-08-24 18:37:44 +01002807
Raef Coles27a61452019-09-25 15:32:25 +01002808 rsp->br_hdr = selected_image_header;
David Vinczecea8b592019-10-29 16:09:51 +01002809 rsp->br_image_off = boot_img_slot_off(state, slot);
2810 rsp->br_flash_dev_id = BOOT_IMG_AREA(state, slot)->fa_device_id;
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002811 } else {
2812 /* No candidate image available */
2813 rc = BOOT_EBADIMAGE;
David Vincze060968d2019-05-23 01:13:14 +02002814 goto out;
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002815 }
2816
Tamas Ban0e8ab302019-01-17 11:45:31 +00002817 /* Save boot status to shared memory area */
2818 rc = boot_save_boot_status(SW_S_NS,
2819 rsp->br_hdr,
David Vinczecea8b592019-10-29 16:09:51 +01002820 BOOT_IMG_AREA(state, slot));
Tamas Ban0e8ab302019-01-17 11:45:31 +00002821 if (rc) {
2822 BOOT_LOG_ERR("Failed to add data to shared area");
2823 }
2824
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002825out:
2826 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
David Vinczecea8b592019-10-29 16:09:51 +01002827 flash_area_close(BOOT_IMG_AREA(state, BOOT_NUM_SLOTS - 1 - slot));
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002828 }
2829 return rc;
2830}
Oliver Swedef9982442018-08-24 18:37:44 +01002831#endif /* MCUBOOT_NO_SWAP || MCUBOOT_RAM_LOADING */
David Vinczecea8b592019-10-29 16:09:51 +01002832
2833int
2834boot_go(struct boot_rsp *rsp)
2835{
2836 return context_boot_go(&boot_data, rsp);
Robert Rostohar4b630372019-12-23 13:24:50 +01002837}