blob: 5204a1e1e0d06b330919695df68efaee81fa3d12 [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 Vinczecea8b592019-10-29 16:09:51 +010023 * Git SHA of the original version: 4f0ea747c314547daa6b6299ccbd77ae4dee6758
Tamas Ban5b647472019-01-05 08:59:30 +000024 * Modifications are Copyright (c) 2018-2019 Arm Limited.
Tamas Ban581034a2017-12-19 19:54:37 +000025 */
26
Tamas Banf70ef8c2017-12-19 15:35:09 +000027/**
28 * This file provides an interface to the boot loader. Functions defined in
29 * this file should only be called while the boot loader is running.
30 */
31
32#include <assert.h>
33#include <stddef.h>
34#include <stdbool.h>
35#include <inttypes.h>
36#include <stdlib.h>
37#include <string.h>
Tamas Banc3828852018-02-01 12:24:16 +000038#include "flash_map/flash_map.h"
Tamas Banf70ef8c2017-12-19 15:35:09 +000039#include "bootutil/bootutil.h"
40#include "bootutil/image.h"
41#include "bootutil_priv.h"
David Vincze73dfbc52019-10-11 13:54:58 +020042#include "bootutil/bootutil_log.h"
Tamas Bana9de4a62018-09-18 08:09:45 +010043#include "bl2/include/tfm_boot_status.h"
44#include "bl2/include/boot_record.h"
David Vincze060968d2019-05-23 01:13:14 +020045#include "security_cnt.h"
Tamas Banf70ef8c2017-12-19 15:35:09 +000046
Tamas Banf70ef8c2017-12-19 15:35:09 +000047static struct boot_loader_state boot_data;
David Vinczecea8b592019-10-29 16:09:51 +010048
49#if (BOOT_IMAGE_NUMBER > 1)
50#define IMAGES_ITER(x) for ((x) = 0; (x) < BOOT_IMAGE_NUMBER; ++(x))
51#else
52#define IMAGES_ITER(x)
53#endif
Tamas Banf70ef8c2017-12-19 15:35:09 +000054
Oliver Swedef9982442018-08-24 18:37:44 +010055#if !defined(MCUBOOT_NO_SWAP) && !defined(MCUBOOT_RAM_LOADING)
David Vincze39e78552018-10-10 17:10:01 +020056
David Vincze8bdfc2d2019-03-18 15:49:23 +010057#if defined(MCUBOOT_VALIDATE_PRIMARY_SLOT) && !defined(MCUBOOT_OVERWRITE_ONLY)
David Vincze39e78552018-10-10 17:10:01 +020058static int boot_status_fails = 0;
59#define BOOT_STATUS_ASSERT(x) \
60 do { \
61 if (!(x)) { \
62 boot_status_fails++; \
63 } \
64 } while (0)
65#else
David Vincze401c7422019-06-21 20:44:05 +020066#define BOOT_STATUS_ASSERT(x) ASSERT(x)
David Vincze39e78552018-10-10 17:10:01 +020067#endif
68
Tamas Banf70ef8c2017-12-19 15:35:09 +000069struct boot_status_table {
David Vincze8bdfc2d2019-03-18 15:49:23 +010070 uint8_t bst_magic_primary_slot;
Tamas Banf70ef8c2017-12-19 15:35:09 +000071 uint8_t bst_magic_scratch;
David Vincze8bdfc2d2019-03-18 15:49:23 +010072 uint8_t bst_copy_done_primary_slot;
Tamas Banf70ef8c2017-12-19 15:35:09 +000073 uint8_t bst_status_source;
74};
75
76/**
77 * This set of tables maps swap state contents to boot status location.
78 * When searching for a match, these tables must be iterated in order.
79 */
80static const struct boot_status_table boot_status_tables[] = {
81 {
David Vincze8bdfc2d2019-03-18 15:49:23 +010082 /* | primary slot | scratch |
83 * ----------+--------------+--------------|
84 * magic | Good | Any |
85 * copy-done | Set | N/A |
86 * ----------+--------------+--------------'
87 * source: none |
88 * ----------------------------------------'
Tamas Banf70ef8c2017-12-19 15:35:09 +000089 */
David Vincze8bdfc2d2019-03-18 15:49:23 +010090 .bst_magic_primary_slot = BOOT_MAGIC_GOOD,
David Vincze401c7422019-06-21 20:44:05 +020091 .bst_magic_scratch = BOOT_MAGIC_NOTGOOD,
David Vincze8bdfc2d2019-03-18 15:49:23 +010092 .bst_copy_done_primary_slot = BOOT_FLAG_SET,
93 .bst_status_source = BOOT_STATUS_SOURCE_NONE,
Tamas Banf70ef8c2017-12-19 15:35:09 +000094 },
95
96 {
David Vincze8bdfc2d2019-03-18 15:49:23 +010097 /* | primary slot | scratch |
98 * ----------+--------------+--------------|
99 * magic | Good | Any |
100 * copy-done | Unset | N/A |
101 * ----------+--------------+--------------'
102 * source: primary slot |
103 * ----------------------------------------'
Tamas Banf70ef8c2017-12-19 15:35:09 +0000104 */
David Vincze8bdfc2d2019-03-18 15:49:23 +0100105 .bst_magic_primary_slot = BOOT_MAGIC_GOOD,
David Vincze401c7422019-06-21 20:44:05 +0200106 .bst_magic_scratch = BOOT_MAGIC_NOTGOOD,
David Vincze8bdfc2d2019-03-18 15:49:23 +0100107 .bst_copy_done_primary_slot = BOOT_FLAG_UNSET,
108 .bst_status_source = BOOT_STATUS_SOURCE_PRIMARY_SLOT,
Tamas Banf70ef8c2017-12-19 15:35:09 +0000109 },
110
111 {
David Vincze8bdfc2d2019-03-18 15:49:23 +0100112 /* | primary slot | scratch |
113 * ----------+--------------+--------------|
114 * magic | Any | Good |
115 * copy-done | Any | N/A |
116 * ----------+--------------+--------------'
117 * source: scratch |
118 * ----------------------------------------'
Tamas Banf70ef8c2017-12-19 15:35:09 +0000119 */
David Vincze8bdfc2d2019-03-18 15:49:23 +0100120 .bst_magic_primary_slot = BOOT_MAGIC_ANY,
121 .bst_magic_scratch = BOOT_MAGIC_GOOD,
122 .bst_copy_done_primary_slot = BOOT_FLAG_ANY,
123 .bst_status_source = BOOT_STATUS_SOURCE_SCRATCH,
Tamas Banf70ef8c2017-12-19 15:35:09 +0000124 },
125
126 {
David Vincze8bdfc2d2019-03-18 15:49:23 +0100127 /* | primary slot | scratch |
128 * ----------+--------------+--------------|
129 * magic | Unset | Any |
130 * copy-done | Unset | N/A |
131 * ----------+--------------+--------------|
132 * source: varies |
133 * ----------------------------------------+--------------------------+
Tamas Banf70ef8c2017-12-19 15:35:09 +0000134 * This represents one of two cases: |
135 * o No swaps ever (no status to read, so no harm in checking). |
David Vincze8bdfc2d2019-03-18 15:49:23 +0100136 * o Mid-revert; status in the primary slot. |
Tamas Banf70ef8c2017-12-19 15:35:09 +0000137 * -------------------------------------------------------------------'
138 */
David Vincze8bdfc2d2019-03-18 15:49:23 +0100139 .bst_magic_primary_slot = BOOT_MAGIC_UNSET,
140 .bst_magic_scratch = BOOT_MAGIC_ANY,
141 .bst_copy_done_primary_slot = BOOT_FLAG_UNSET,
142 .bst_status_source = BOOT_STATUS_SOURCE_PRIMARY_SLOT,
Tamas Banf70ef8c2017-12-19 15:35:09 +0000143 },
144};
145
146#define BOOT_STATUS_TABLES_COUNT \
Tamas Ban581034a2017-12-19 19:54:37 +0000147 (sizeof(boot_status_tables) / sizeof(boot_status_tables[0]))
Tamas Banf70ef8c2017-12-19 15:35:09 +0000148
149#define BOOT_LOG_SWAP_STATE(area, state) \
David Vincze401c7422019-06-21 20:44:05 +0200150 BOOT_LOG_INF("%s: magic=%5s, swap_type=0x%x, copy_done=0x%x, " \
151 "image_ok=0x%x", \
Tamas Banf70ef8c2017-12-19 15:35:09 +0000152 (area), \
153 ((state)->magic == BOOT_MAGIC_GOOD ? "good" : \
154 (state)->magic == BOOT_MAGIC_UNSET ? "unset" : \
155 "bad"), \
David Vincze401c7422019-06-21 20:44:05 +0200156 (state)->swap_type, \
Tamas Banf70ef8c2017-12-19 15:35:09 +0000157 (state)->copy_done, \
158 (state)->image_ok)
Oliver Swedef9982442018-08-24 18:37:44 +0100159#endif /* !MCUBOOT_NO_SWAP && !MCUBOOT_RAM_LOADING */
Tamas Banf70ef8c2017-12-19 15:35:09 +0000160
Tamas Ban056ed0b2019-09-16 12:48:32 +0100161/*
David Vinczecea8b592019-10-29 16:09:51 +0100162 * Locate the TLVs in an image.
163 *
164 * @param hdr The image_header struct of the image being checked
165 * @param fap flash_area struct of the slot storing the image being checked
166 * @param off Address of the first TLV (after TLV info)
167 * @param end Address where TLV area ends
168 *
169 * Returns 0 on success.
170 */
171int
172boot_find_tlv_offs(const struct image_header *hdr, const struct flash_area *fap,
173 uint32_t *off, uint32_t *end)
174{
175 struct image_tlv_info info;
176 uint32_t off_;
177
178 off_ = BOOT_TLV_OFF(hdr);
179
180 if (LOAD_IMAGE_DATA(fap, off_, &info, sizeof(info))) {
181 return BOOT_EFLASH;
182 }
183
184 if (info.it_magic != IMAGE_TLV_INFO_MAGIC) {
185 return BOOT_EBADIMAGE;
186 }
187
188 *end = off_ + info.it_tlv_tot;
189 *off = off_ + sizeof(info);
190 return 0;
191}
192
193/*
Tamas Ban056ed0b2019-09-16 12:48:32 +0100194 * \brief Verifies the image header: magic value, flags, integer overflow.
195 *
196 * \retval 0
197 * \retval BOOT_EBADIMAGE
198 */
199static int
200boot_verify_image_header(struct image_header *hdr)
201{
202 uint32_t image_end;
203
204 if (hdr->ih_magic != IMAGE_MAGIC) {
205 return BOOT_EBADIMAGE;
206 }
207
208 /* Check input parameters against integer overflow */
209 if (boot_add_uint32_overflow_check(hdr->ih_hdr_size, hdr->ih_img_size)) {
210 return BOOT_EBADIMAGE;
211 }
212
213 image_end = hdr->ih_hdr_size + hdr->ih_img_size;
214 if (boot_add_uint32_overflow_check(image_end, hdr->ih_protect_tlv_size)) {
215 return BOOT_EBADIMAGE;
216 }
217
218
219#if MCUBOOT_RAM_LOADING
220 if (!(hdr->ih_flags & IMAGE_F_RAM_LOAD)) {
221 return BOOT_EBADIMAGE;
222 }
223
224 /* Check input parameters against integer overflow */
225 if (boot_add_uint32_overflow_check(image_end, hdr->ih_load_addr)) {
226 return BOOT_EBADIMAGE;
227 }
228#endif
229
230 return 0;
231}
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000232
233static int
David Vinczecea8b592019-10-29 16:09:51 +0100234boot_read_image_header(struct boot_loader_state *state, int slot,
235 struct image_header *out_hdr)
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000236{
237 const struct flash_area *fap = NULL;
238 int area_id;
239 int rc;
240
David Vinczecea8b592019-10-29 16:09:51 +0100241#if (BOOT_IMAGE_NUMBER == 1)
242 (void)state;
243#endif
244
245 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000246 rc = flash_area_open(area_id, &fap);
247 if (rc != 0) {
248 rc = BOOT_EFLASH;
249 goto done;
250 }
251
252 rc = flash_area_read(fap, 0, out_hdr, sizeof(*out_hdr));
253 if (rc != 0) {
254 rc = BOOT_EFLASH;
255 goto done;
256 }
257
Tamas Ban056ed0b2019-09-16 12:48:32 +0100258 rc = boot_verify_image_header(out_hdr);
David Vinczecea8b592019-10-29 16:09:51 +0100259 BOOT_IMG_HDR_IS_VALID(state, slot) = (rc == 0);
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000260
261done:
262 flash_area_close(fap);
263 return rc;
264}
265
266static int
David Vinczecea8b592019-10-29 16:09:51 +0100267boot_read_image_headers(struct boot_loader_state *state, bool require_all)
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000268{
269 int rc;
270 int i;
271
272 for (i = 0; i < BOOT_NUM_SLOTS; i++) {
David Vinczecea8b592019-10-29 16:09:51 +0100273 rc = boot_read_image_header(state, i, boot_img_hdr(state, i));
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000274 if (rc != 0) {
David Vincze39e78552018-10-10 17:10:01 +0200275 /* If `require_all` is set, fail on any single fail, otherwise
276 * if at least the first slot's header was read successfully,
277 * then the boot loader can attempt a boot.
278 *
279 * Failure to read any headers is a fatal error.
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000280 */
David Vincze39e78552018-10-10 17:10:01 +0200281 if (i > 0 && !require_all) {
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000282 return 0;
283 } else {
284 return rc;
285 }
286 }
287 }
288
289 return 0;
290}
291
Raef Coles204c5b42019-09-05 09:18:47 +0100292static uint32_t
David Vinczecea8b592019-10-29 16:09:51 +0100293boot_write_sz(struct boot_loader_state *state)
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000294{
Raef Coles204c5b42019-09-05 09:18:47 +0100295 uint32_t elem_sz;
296 uint32_t align;
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000297
298 /* Figure out what size to write update status update as. The size depends
299 * on what the minimum write size is for scratch area, active image slot.
300 * We need to use the bigger of those 2 values.
301 */
David Vinczecea8b592019-10-29 16:09:51 +0100302 elem_sz = flash_area_align(BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT));
303 align = flash_area_align(BOOT_SCRATCH_AREA(state));
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000304 if (align > elem_sz) {
305 elem_sz = align;
306 }
307
308 return elem_sz;
309}
310
David Vinczecea8b592019-10-29 16:09:51 +0100311#ifndef MCUBOOT_USE_FLASH_AREA_GET_SECTORS
312static int
313boot_initialize_area(struct boot_loader_state *state, int flash_area)
314{
315 int num_sectors = BOOT_MAX_IMG_SECTORS;
316 int rc;
317
318 if (flash_area == FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state))) {
319 rc = flash_area_to_sectors(flash_area, &num_sectors,
320 BOOT_IMG(state, BOOT_PRIMARY_SLOT).sectors);
321 BOOT_IMG(state, BOOT_PRIMARY_SLOT).num_sectors = (size_t)num_sectors;
322
323 } else if (flash_area == FLASH_AREA_IMAGE_SECONDARY(BOOT_CURR_IMG(state))) {
324 rc = flash_area_to_sectors(flash_area, &num_sectors,
325 BOOT_IMG(state, BOOT_SECONDARY_SLOT).sectors);
326 BOOT_IMG(state, BOOT_SECONDARY_SLOT).num_sectors = (size_t)num_sectors;
327
328 } else if (flash_area == FLASH_AREA_IMAGE_SCRATCH) {
329 rc = flash_area_to_sectors(flash_area, &num_sectors,
330 state->scratch.sectors);
331 state->scratch.num_sectors = (size_t)num_sectors;
332 } else {
333 return BOOT_EFLASH;
334 }
335
336 return rc;
337}
338#else /* defined(MCUBOOT_USE_FLASH_AREA_GET_SECTORS) */
339static int
340boot_initialize_area(struct boot_loader_state *state, int flash_area)
341{
342 uint32_t num_sectors;
343 struct flash_sector *out_sectors;
344 size_t *out_num_sectors;
345 int rc;
346
347 num_sectors = BOOT_MAX_IMG_SECTORS;
348
349 if (flash_area == FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state))) {
350 out_sectors = BOOT_IMG(state, BOOT_PRIMARY_SLOT).sectors;
351 out_num_sectors = &BOOT_IMG(state, BOOT_PRIMARY_SLOT).num_sectors;
352 } else if (flash_area == FLASH_AREA_IMAGE_SECONDARY(BOOT_CURR_IMG(state))) {
353 out_sectors = BOOT_IMG(state, BOOT_SECONDARY_SLOT).sectors;
354 out_num_sectors = &BOOT_IMG(state, BOOT_SECONDARY_SLOT).num_sectors;
355 } else if (flash_area == FLASH_AREA_IMAGE_SCRATCH) {
356 out_sectors = state->scratch.sectors;
357 out_num_sectors = &state->scratch.num_sectors;
358 } else {
359 return BOOT_EFLASH;
360 }
361
362 rc = flash_area_get_sectors(flash_area, &num_sectors, out_sectors);
363 if (rc != 0) {
364 return rc;
365 }
366 *out_num_sectors = num_sectors;
367 return 0;
368}
369#endif /* !defined(MCUBOOT_USE_FLASH_AREA_GET_SECTORS) */
370
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000371/**
372 * Determines the sector layout of both image slots and the scratch area.
373 * This information is necessary for calculating the number of bytes to erase
374 * and copy during an image swap. The information collected during this
David Vinczecea8b592019-10-29 16:09:51 +0100375 * function is used to populate the state.
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000376 */
377static int
David Vinczecea8b592019-10-29 16:09:51 +0100378boot_read_sectors(struct boot_loader_state *state)
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000379{
David Vinczecea8b592019-10-29 16:09:51 +0100380 uint8_t image_index;
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000381 int rc;
382
David Vinczecea8b592019-10-29 16:09:51 +0100383 image_index = BOOT_CURR_IMG(state);
384
385 rc = boot_initialize_area(state, FLASH_AREA_IMAGE_PRIMARY(image_index));
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000386 if (rc != 0) {
387 return BOOT_EFLASH;
388 }
389
David Vinczecea8b592019-10-29 16:09:51 +0100390 rc = boot_initialize_area(state, FLASH_AREA_IMAGE_SECONDARY(image_index));
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000391 if (rc != 0) {
392 return BOOT_EFLASH;
393 }
394
David Vinczecea8b592019-10-29 16:09:51 +0100395 rc = boot_initialize_area(state, FLASH_AREA_IMAGE_SCRATCH);
David Vincze401c7422019-06-21 20:44:05 +0200396 if (rc != 0) {
397 return BOOT_EFLASH;
398 }
399
David Vinczecea8b592019-10-29 16:09:51 +0100400 BOOT_WRITE_SZ(state) = boot_write_sz(state);
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000401
402 return 0;
403}
404
David Vincze060968d2019-05-23 01:13:14 +0200405/**
406 * Validate image hash/signature and security counter in a slot.
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000407 */
408static int
David Vinczecea8b592019-10-29 16:09:51 +0100409boot_image_check(struct boot_loader_state *state, struct image_header *hdr,
410 const struct flash_area *fap, struct boot_status *bs)
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000411{
412 static uint8_t tmpbuf[BOOT_TMPBUF_SZ];
David Vinczecea8b592019-10-29 16:09:51 +0100413 uint8_t image_index;
414
415#if (BOOT_IMAGE_NUMBER == 1)
416 (void)state;
417#endif
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000418
David Vincze401c7422019-06-21 20:44:05 +0200419 (void)bs;
420
David Vinczecea8b592019-10-29 16:09:51 +0100421 image_index = BOOT_CURR_IMG(state);
422
423 if (bootutil_img_validate(image_index, hdr, fap, tmpbuf,
424 BOOT_TMPBUF_SZ, NULL, 0, NULL)) {
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000425 return BOOT_EBADIMAGE;
426 }
David Vinczecea8b592019-10-29 16:09:51 +0100427
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000428 return 0;
429}
430
David Vincze401c7422019-06-21 20:44:05 +0200431/*
432 * Check that a memory area consists of a given value.
433 */
434static inline bool
435boot_data_is_set_to(uint8_t val, void *data, size_t len)
David Vincze39e78552018-10-10 17:10:01 +0200436{
437 uint8_t i;
David Vincze401c7422019-06-21 20:44:05 +0200438 uint8_t *p = (uint8_t *)data;
439 for (i = 0; i < len; i++) {
440 if (val != p[i]) {
441 return false;
David Vincze39e78552018-10-10 17:10:01 +0200442 }
443 }
David Vincze401c7422019-06-21 20:44:05 +0200444 return true;
David Vincze39e78552018-10-10 17:10:01 +0200445}
446
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000447static int
David Vinczecea8b592019-10-29 16:09:51 +0100448boot_check_header_erased(struct boot_loader_state *state, int slot)
David Vincze401c7422019-06-21 20:44:05 +0200449{
450 const struct flash_area *fap;
451 struct image_header *hdr;
452 uint8_t erased_val;
David Vinczecea8b592019-10-29 16:09:51 +0100453 int area_id;
David Vincze401c7422019-06-21 20:44:05 +0200454 int rc;
455
David Vinczecea8b592019-10-29 16:09:51 +0100456 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
457 rc = flash_area_open(area_id, &fap);
David Vincze401c7422019-06-21 20:44:05 +0200458 if (rc != 0) {
459 return -1;
460 }
461
462 erased_val = flash_area_erased_val(fap);
463 flash_area_close(fap);
464
David Vinczecea8b592019-10-29 16:09:51 +0100465 hdr = boot_img_hdr(state, slot);
David Vincze401c7422019-06-21 20:44:05 +0200466 if (!boot_data_is_set_to(erased_val, &hdr->ih_magic,
467 sizeof(hdr->ih_magic))) {
468 return -1;
469 }
470
471 return 0;
472}
473
David Vinczecea8b592019-10-29 16:09:51 +0100474/*
475 * Check that there is a valid image in a slot
476 *
477 * @returns
478 * 0 if image was succesfully validated
479 * 1 if no bootloable image was found
480 * -1 on any errors
481 */
David Vincze401c7422019-06-21 20:44:05 +0200482static int
David Vinczecea8b592019-10-29 16:09:51 +0100483boot_validate_slot(struct boot_loader_state *state, int slot,
484 struct boot_status *bs)
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000485{
486 const struct flash_area *fap;
487 struct image_header *hdr;
David Vinczecea8b592019-10-29 16:09:51 +0100488 int area_id;
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000489 int rc;
490
David Vinczecea8b592019-10-29 16:09:51 +0100491 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
492 rc = flash_area_open(area_id, &fap);
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000493 if (rc != 0) {
David Vinczecea8b592019-10-29 16:09:51 +0100494 return -1;
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000495 }
496
David Vinczecea8b592019-10-29 16:09:51 +0100497 hdr = boot_img_hdr(state, slot);
498 if ((boot_check_header_erased(state, slot) == 0) ||
David Vincze401c7422019-06-21 20:44:05 +0200499 (hdr->ih_flags & IMAGE_F_NON_BOOTABLE)) {
David Vincze8bdfc2d2019-03-18 15:49:23 +0100500 /* No bootable image in slot; continue booting from the primary slot. */
David Vinczecea8b592019-10-29 16:09:51 +0100501 rc = 1;
David Vincze401c7422019-06-21 20:44:05 +0200502 goto out;
David Vincze39e78552018-10-10 17:10:01 +0200503 }
504
David Vinczecea8b592019-10-29 16:09:51 +0100505 if ((!BOOT_IMG_HDR_IS_VALID(state, slot)) ||
506 (boot_image_check(state, hdr, fap, bs) != 0)) {
David Vincze401c7422019-06-21 20:44:05 +0200507 if (slot != BOOT_PRIMARY_SLOT) {
David Vinczecea8b592019-10-29 16:09:51 +0100508 flash_area_erase(fap, 0, fap->fa_size);
David Vincze8bdfc2d2019-03-18 15:49:23 +0100509 /* Image in the secondary slot is invalid. Erase the image and
510 * continue booting from the primary slot.
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000511 */
512 }
David Vinczecea8b592019-10-29 16:09:51 +0100513 BOOT_LOG_ERR("Image in the %s slot is not valid!",
514 (slot == BOOT_PRIMARY_SLOT) ? "primary" : "secondary");
David Vincze401c7422019-06-21 20:44:05 +0200515 rc = -1;
516 goto out;
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000517 }
518
David Vincze8bdfc2d2019-03-18 15:49:23 +0100519 /* Image in the secondary slot is valid. */
David Vincze401c7422019-06-21 20:44:05 +0200520 rc = 0;
521
522out:
523 flash_area_close(fap);
524 return rc;
Tamas Ban4fb8e9d2018-02-23 14:22:03 +0000525}
526
David Vincze060968d2019-05-23 01:13:14 +0200527/**
528 * Updates the stored security counter value with the image's security counter
529 * value which resides in the given slot if it's greater than the stored value.
530 *
David Vinczecea8b592019-10-29 16:09:51 +0100531 * @param image_index Index of the image to determine which security
532 * counter to update.
533 * @param slot Slot number of the image.
534 * @param hdr Pointer to the image header structure of the image
535 * that is currently stored in the given slot.
David Vincze060968d2019-05-23 01:13:14 +0200536 *
David Vinczecea8b592019-10-29 16:09:51 +0100537 * @return 0 on success; nonzero on failure.
David Vincze060968d2019-05-23 01:13:14 +0200538 */
539static int
David Vinczecea8b592019-10-29 16:09:51 +0100540boot_update_security_counter(uint8_t image_index, int slot,
541 struct image_header *hdr)
David Vincze060968d2019-05-23 01:13:14 +0200542{
543 const struct flash_area *fap = NULL;
544 uint32_t img_security_cnt;
545 int rc;
546
David Vinczecea8b592019-10-29 16:09:51 +0100547 rc = flash_area_open(flash_area_id_from_multi_image_slot(image_index, slot),
548 &fap);
David Vincze060968d2019-05-23 01:13:14 +0200549 if (rc != 0) {
550 rc = BOOT_EFLASH;
551 goto done;
552 }
553
554 rc = bootutil_get_img_security_cnt(hdr, fap, &img_security_cnt);
555 if (rc != 0) {
556 goto done;
557 }
558
David Vinczecea8b592019-10-29 16:09:51 +0100559 rc = boot_nv_security_counter_update(image_index, img_security_cnt);
David Vincze060968d2019-05-23 01:13:14 +0200560 if (rc != 0) {
561 goto done;
562 }
563
564done:
565 flash_area_close(fap);
566 return rc;
567}
568
Oliver Swedef9982442018-08-24 18:37:44 +0100569#if !defined(MCUBOOT_NO_SWAP) && !defined(MCUBOOT_OVERWRITE_ONLY)
570/*
571 * Compute the total size of the given image. Includes the size of
572 * the TLVs.
573 */
574static int
David Vinczecea8b592019-10-29 16:09:51 +0100575boot_read_image_size(struct boot_loader_state *state, int slot, uint32_t *size)
Oliver Swedef9982442018-08-24 18:37:44 +0100576{
577 const struct flash_area *fap = NULL;
David Vinczecea8b592019-10-29 16:09:51 +0100578 uint32_t off;
Oliver Swedef9982442018-08-24 18:37:44 +0100579 int area_id;
580 int rc;
581
David Vinczecea8b592019-10-29 16:09:51 +0100582#if (BOOT_IMAGE_NUMBER == 1)
583 (void)state;
584#endif
585
586 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
Oliver Swedef9982442018-08-24 18:37:44 +0100587 rc = flash_area_open(area_id, &fap);
588 if (rc != 0) {
589 rc = BOOT_EFLASH;
590 goto done;
591 }
592
David Vinczecea8b592019-10-29 16:09:51 +0100593 rc = boot_find_tlv_offs(boot_img_hdr(state, slot), fap, &off, size);
Oliver Swedef9982442018-08-24 18:37:44 +0100594 if (rc != 0) {
Oliver Swedef9982442018-08-24 18:37:44 +0100595 goto done;
596 }
Oliver Swedef9982442018-08-24 18:37:44 +0100597 rc = 0;
598
599done:
600 flash_area_close(fap);
601 return rc;
602}
603#endif /* !MCUBOOT_NO_SWAP && !MCUBOOT_OVERWRITE_ONLY */
604
605#if !defined(MCUBOOT_NO_SWAP) && !defined(MCUBOOT_RAM_LOADING)
Tamas Banf70ef8c2017-12-19 15:35:09 +0000606/**
Tamas Ban581034a2017-12-19 19:54:37 +0000607 * Determines where in flash the most recent boot status is stored. The boot
Tamas Banf70ef8c2017-12-19 15:35:09 +0000608 * status is necessary for completing a swap that was interrupted by a boot
609 * loader reset.
610 *
David Vincze401c7422019-06-21 20:44:05 +0200611 * @return A BOOT_STATUS_SOURCE_[...] code indicating where status should
612 * be read from.
Tamas Banf70ef8c2017-12-19 15:35:09 +0000613 */
614static int
David Vinczecea8b592019-10-29 16:09:51 +0100615boot_status_source(struct boot_loader_state *state)
Tamas Banf70ef8c2017-12-19 15:35:09 +0000616{
617 const struct boot_status_table *table;
618 struct boot_swap_state state_scratch;
David Vincze8bdfc2d2019-03-18 15:49:23 +0100619 struct boot_swap_state state_primary_slot;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000620 int rc;
David Vincze39e78552018-10-10 17:10:01 +0200621 size_t i;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000622 uint8_t source;
David Vinczecea8b592019-10-29 16:09:51 +0100623 uint8_t image_index;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000624
David Vinczecea8b592019-10-29 16:09:51 +0100625#if (BOOT_IMAGE_NUMBER == 1)
626 (void)state;
627#endif
628
629 image_index = BOOT_CURR_IMG(state);
630 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_PRIMARY(image_index),
631 &state_primary_slot);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000632 assert(rc == 0);
633
634 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SCRATCH, &state_scratch);
635 assert(rc == 0);
636
David Vincze401c7422019-06-21 20:44:05 +0200637 BOOT_LOG_SWAP_STATE("Primary image", &state_primary_slot);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000638 BOOT_LOG_SWAP_STATE("Scratch", &state_scratch);
639
640 for (i = 0; i < BOOT_STATUS_TABLES_COUNT; i++) {
641 table = &boot_status_tables[i];
642
David Vincze401c7422019-06-21 20:44:05 +0200643 if (boot_magic_compatible_check(table->bst_magic_primary_slot,
644 state_primary_slot.magic) &&
645 boot_magic_compatible_check(table->bst_magic_scratch,
646 state_scratch.magic) &&
David Vincze8bdfc2d2019-03-18 15:49:23 +0100647 (table->bst_copy_done_primary_slot == BOOT_FLAG_ANY ||
648 table->bst_copy_done_primary_slot == state_primary_slot.copy_done))
649 {
Tamas Banf70ef8c2017-12-19 15:35:09 +0000650 source = table->bst_status_source;
David Vincze7384ee72019-07-23 17:00:42 +0200651
652#if (BOOT_IMAGE_NUMBER > 1)
653 /* In case of multi-image boot it can happen that if boot status
654 * info is found on scratch area then it does not belong to the
655 * currently examined image.
656 */
657 if (source == BOOT_STATUS_SOURCE_SCRATCH &&
David Vinczecea8b592019-10-29 16:09:51 +0100658 state_scratch.image_num != BOOT_CURR_IMG(state)) {
David Vincze7384ee72019-07-23 17:00:42 +0200659 source = BOOT_STATUS_SOURCE_NONE;
660 }
661#endif
662
Tamas Banf70ef8c2017-12-19 15:35:09 +0000663 BOOT_LOG_INF("Boot source: %s",
664 source == BOOT_STATUS_SOURCE_NONE ? "none" :
665 source == BOOT_STATUS_SOURCE_SCRATCH ? "scratch" :
David Vincze8bdfc2d2019-03-18 15:49:23 +0100666 source == BOOT_STATUS_SOURCE_PRIMARY_SLOT ?
667 "primary slot" : "BUG; can't happen");
Tamas Banf70ef8c2017-12-19 15:35:09 +0000668 return source;
669 }
670 }
671
672 BOOT_LOG_INF("Boot source: none");
673 return BOOT_STATUS_SOURCE_NONE;
674}
675
David Vincze401c7422019-06-21 20:44:05 +0200676/*
677 * Slots are compatible when all sectors that store upto to size of the image
678 * round up to sector size, in both slot's are able to fit in the scratch
679 * area, and have sizes that are a multiple of each other (powers of two
680 * presumably!).
Tamas Banf70ef8c2017-12-19 15:35:09 +0000681 */
682static int
David Vinczecea8b592019-10-29 16:09:51 +0100683boot_slots_compatible(struct boot_loader_state *state)
Tamas Banf70ef8c2017-12-19 15:35:09 +0000684{
David Vincze401c7422019-06-21 20:44:05 +0200685 size_t num_sectors_primary;
686 size_t num_sectors_secondary;
687 size_t sz0, sz1;
688 size_t primary_slot_sz, secondary_slot_sz;
689 size_t scratch_sz;
690 size_t i, j;
691 int8_t smaller;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000692
David Vinczecea8b592019-10-29 16:09:51 +0100693 num_sectors_primary = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT);
694 num_sectors_secondary = boot_img_num_sectors(state, BOOT_SECONDARY_SLOT);
David Vincze401c7422019-06-21 20:44:05 +0200695 if ((num_sectors_primary > BOOT_MAX_IMG_SECTORS) ||
696 (num_sectors_secondary > BOOT_MAX_IMG_SECTORS)) {
David Vincze39e78552018-10-10 17:10:01 +0200697 BOOT_LOG_WRN("Cannot upgrade: more sectors than allowed");
Tamas Banf70ef8c2017-12-19 15:35:09 +0000698 return 0;
699 }
David Vincze39e78552018-10-10 17:10:01 +0200700
David Vinczecea8b592019-10-29 16:09:51 +0100701 scratch_sz = boot_scratch_area_size(state);
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 }
744 if (sz0 == sz1) {
745 primary_slot_sz += sz0;
746 secondary_slot_sz += sz1;
747 /* Scratch has to fit each swap operation to the size of the larger
748 * sector among the primary slot and the secondary slot.
749 */
750 if (sz0 > scratch_sz || sz1 > scratch_sz) {
751 BOOT_LOG_WRN("Cannot upgrade: not all sectors fit inside"
752 " scratch");
753 return 0;
754 }
755 smaller = sz0 = sz1 = 0;
756 }
David Vincze39e78552018-10-10 17:10:01 +0200757 }
758
David Vincze401c7422019-06-21 20:44:05 +0200759 if ((i != num_sectors_primary) ||
760 (j != num_sectors_secondary) ||
761 (primary_slot_sz != secondary_slot_sz)) {
762 BOOT_LOG_WRN("Cannot upgrade: slots are not compatible");
763 return 0;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000764 }
765
766 return 1;
767}
768
Tamas Banf70ef8c2017-12-19 15:35:09 +0000769static uint32_t
770boot_status_internal_off(int idx, int state, int elem_sz)
771{
772 int idx_sz;
773
774 idx_sz = elem_sz * BOOT_STATUS_STATE_COUNT;
775
David Vincze39e78552018-10-10 17:10:01 +0200776 return (idx - BOOT_STATUS_IDX_0) * idx_sz +
777 (state - BOOT_STATUS_STATE_0) * elem_sz;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000778}
779
780/**
781 * Reads the status of a partially-completed swap, if any. This is necessary
782 * to recover in case the boot lodaer was reset in the middle of a swap
783 * operation.
784 */
785static int
David Vinczecea8b592019-10-29 16:09:51 +0100786boot_read_status_bytes(const struct flash_area *fap,
787 struct boot_loader_state *state, struct boot_status *bs)
Tamas Banf70ef8c2017-12-19 15:35:09 +0000788{
789 uint32_t off;
790 uint8_t status;
791 int max_entries;
792 int found;
David Vincze39e78552018-10-10 17:10:01 +0200793 int found_idx;
794 int invalid;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000795 int rc;
796 int i;
797
798 off = boot_status_off(fap);
David Vinczecea8b592019-10-29 16:09:51 +0100799 max_entries = boot_status_entries(BOOT_CURR_IMG(state), fap);
800 if (max_entries < 0) {
801 return BOOT_EBADARGS;
802 }
Tamas Banf70ef8c2017-12-19 15:35:09 +0000803
804 found = 0;
David Vincze39e78552018-10-10 17:10:01 +0200805 found_idx = 0;
806 invalid = 0;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000807 for (i = 0; i < max_entries; i++) {
David Vinczecea8b592019-10-29 16:09:51 +0100808 rc = flash_area_read_is_empty(fap, off + i * BOOT_WRITE_SZ(state),
David Vincze39e78552018-10-10 17:10:01 +0200809 &status, 1);
810 if (rc < 0) {
Tamas Banf70ef8c2017-12-19 15:35:09 +0000811 return BOOT_EFLASH;
812 }
813
David Vincze39e78552018-10-10 17:10:01 +0200814 if (rc == 1) {
815 if (found && !found_idx) {
816 found_idx = i;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000817 }
818 } else if (!found) {
819 found = 1;
David Vincze39e78552018-10-10 17:10:01 +0200820 } else if (found_idx) {
821 invalid = 1;
822 break;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000823 }
824 }
825
David Vincze39e78552018-10-10 17:10:01 +0200826 if (invalid) {
827 /* This means there was an error writing status on the last
828 * swap. Tell user and move on to validation!
829 */
830 BOOT_LOG_ERR("Detected inconsistent status!");
831
David Vincze8bdfc2d2019-03-18 15:49:23 +0100832#if !defined(MCUBOOT_VALIDATE_PRIMARY_SLOT)
833 /* With validation of the primary slot disabled, there is no way
834 * to be sure the swapped primary slot is OK, so abort!
David Vincze39e78552018-10-10 17:10:01 +0200835 */
836 assert(0);
837#endif
838 }
839
Tamas Banf70ef8c2017-12-19 15:35:09 +0000840 if (found) {
David Vincze39e78552018-10-10 17:10:01 +0200841 if (!found_idx) {
842 found_idx = i;
843 }
David Vincze39e78552018-10-10 17:10:01 +0200844 bs->idx = (found_idx / BOOT_STATUS_STATE_COUNT) + 1;
845 bs->state = (found_idx % BOOT_STATUS_STATE_COUNT) + 1;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000846 }
847
848 return 0;
849}
850
851/**
852 * Reads the boot status from the flash. The boot status contains
853 * the current state of an interrupted image copy operation. If the boot
854 * status is not present, or it indicates that previous copy finished,
855 * there is no operation in progress.
856 */
857static int
David Vinczecea8b592019-10-29 16:09:51 +0100858boot_read_status(struct boot_loader_state *state, struct boot_status *bs)
Tamas Banf70ef8c2017-12-19 15:35:09 +0000859{
860 const struct flash_area *fap;
David Vincze401c7422019-06-21 20:44:05 +0200861 uint32_t off;
David Vincze91b71ef2019-06-24 13:06:47 +0200862 uint8_t swap_info;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000863 int status_loc;
864 int area_id;
865 int rc;
866
David Vincze39e78552018-10-10 17:10:01 +0200867 memset(bs, 0, sizeof *bs);
868 bs->idx = BOOT_STATUS_IDX_0;
869 bs->state = BOOT_STATUS_STATE_0;
David Vincze401c7422019-06-21 20:44:05 +0200870 bs->swap_type = BOOT_SWAP_TYPE_NONE;
David Vincze39e78552018-10-10 17:10:01 +0200871
872#ifdef MCUBOOT_OVERWRITE_ONLY
873 /* Overwrite-only doesn't make use of the swap status area. */
874 return 0;
875#endif
Tamas Banf70ef8c2017-12-19 15:35:09 +0000876
David Vinczecea8b592019-10-29 16:09:51 +0100877 status_loc = boot_status_source(state);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000878 switch (status_loc) {
879 case BOOT_STATUS_SOURCE_NONE:
880 return 0;
881
882 case BOOT_STATUS_SOURCE_SCRATCH:
883 area_id = FLASH_AREA_IMAGE_SCRATCH;
884 break;
885
David Vincze8bdfc2d2019-03-18 15:49:23 +0100886 case BOOT_STATUS_SOURCE_PRIMARY_SLOT:
David Vinczecea8b592019-10-29 16:09:51 +0100887 area_id = FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state));
Tamas Banf70ef8c2017-12-19 15:35:09 +0000888 break;
889
890 default:
891 assert(0);
892 return BOOT_EBADARGS;
893 }
894
895 rc = flash_area_open(area_id, &fap);
896 if (rc != 0) {
897 return BOOT_EFLASH;
898 }
899
David Vinczecea8b592019-10-29 16:09:51 +0100900 rc = boot_read_status_bytes(fap, state, bs);
David Vincze401c7422019-06-21 20:44:05 +0200901 if (rc == 0) {
David Vincze91b71ef2019-06-24 13:06:47 +0200902 off = boot_swap_info_off(fap);
903 rc = flash_area_read_is_empty(fap, off, &swap_info, sizeof swap_info);
David Vincze401c7422019-06-21 20:44:05 +0200904 if (rc == 1) {
David Vincze91b71ef2019-06-24 13:06:47 +0200905 BOOT_SET_SWAP_INFO(swap_info, 0, BOOT_SWAP_TYPE_NONE);
David Vincze401c7422019-06-21 20:44:05 +0200906 rc = 0;
907 }
David Vincze91b71ef2019-06-24 13:06:47 +0200908
909 /* Extract the swap type info */
910 bs->swap_type = BOOT_GET_SWAP_TYPE(swap_info);
David Vincze401c7422019-06-21 20:44:05 +0200911 }
Tamas Banf70ef8c2017-12-19 15:35:09 +0000912
913 flash_area_close(fap);
David Vincze39e78552018-10-10 17:10:01 +0200914
Tamas Banf70ef8c2017-12-19 15:35:09 +0000915 return rc;
916}
917
918/**
919 * Writes the supplied boot status to the flash file system. The boot status
920 * contains the current state of an in-progress image copy operation.
921 *
922 * @param bs The boot status to write.
923 *
924 * @return 0 on success; nonzero on failure.
925 */
926int
David Vinczecea8b592019-10-29 16:09:51 +0100927boot_write_status(struct boot_loader_state *state, struct boot_status *bs)
Tamas Banf70ef8c2017-12-19 15:35:09 +0000928{
Tamas Ban581034a2017-12-19 19:54:37 +0000929 const struct flash_area *fap = NULL;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000930 uint32_t off;
931 int area_id;
932 int rc;
933 uint8_t buf[BOOT_MAX_ALIGN];
Raef Coles204c5b42019-09-05 09:18:47 +0100934 uint32_t align;
David Vincze39e78552018-10-10 17:10:01 +0200935 uint8_t erased_val;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000936
937 /* NOTE: The first sector copied (that is the last sector on slot) contains
David Vincze8bdfc2d2019-03-18 15:49:23 +0100938 * the trailer. Since in the last step the primary slot is erased, the
939 * first two status writes go to the scratch which will be copied to
940 * the primary slot!
Tamas Banf70ef8c2017-12-19 15:35:09 +0000941 */
942
943 if (bs->use_scratch) {
944 /* Write to scratch. */
945 area_id = FLASH_AREA_IMAGE_SCRATCH;
946 } else {
David Vincze8bdfc2d2019-03-18 15:49:23 +0100947 /* Write to the primary slot. */
David Vinczecea8b592019-10-29 16:09:51 +0100948 area_id = FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state));
Tamas Banf70ef8c2017-12-19 15:35:09 +0000949 }
950
951 rc = flash_area_open(area_id, &fap);
952 if (rc != 0) {
953 rc = BOOT_EFLASH;
954 goto done;
955 }
956
957 off = boot_status_off(fap) +
David Vinczecea8b592019-10-29 16:09:51 +0100958 boot_status_internal_off(bs->idx, bs->state, BOOT_WRITE_SZ(state));
Tamas Banc3828852018-02-01 12:24:16 +0000959 align = flash_area_align(fap);
David Vincze39e78552018-10-10 17:10:01 +0200960 erased_val = flash_area_erased_val(fap);
961 memset(buf, erased_val, BOOT_MAX_ALIGN);
Tamas Banf70ef8c2017-12-19 15:35:09 +0000962 buf[0] = bs->state;
963
964 rc = flash_area_write(fap, off, buf, align);
965 if (rc != 0) {
966 rc = BOOT_EFLASH;
967 goto done;
968 }
969
970 rc = 0;
971
972done:
973 flash_area_close(fap);
974 return rc;
975}
976
Tamas Banf70ef8c2017-12-19 15:35:09 +0000977/**
978 * Determines which swap operation to perform, if any. If it is determined
David Vincze8bdfc2d2019-03-18 15:49:23 +0100979 * that a swap operation is required, the image in the secondary slot is checked
980 * for validity. If the image in the secondary slot is invalid, it is erased,
981 * and a swap type of "none" is indicated.
Tamas Banf70ef8c2017-12-19 15:35:09 +0000982 *
983 * @return The type of swap to perform (BOOT_SWAP_TYPE...)
984 */
985static int
David Vinczecea8b592019-10-29 16:09:51 +0100986boot_validated_swap_type(struct boot_loader_state *state,
987 struct boot_status *bs)
Tamas Banf70ef8c2017-12-19 15:35:09 +0000988{
989 int swap_type;
David Vinczecea8b592019-10-29 16:09:51 +0100990 int rc;
Tamas Banf70ef8c2017-12-19 15:35:09 +0000991
David Vinczecea8b592019-10-29 16:09:51 +0100992 swap_type = boot_swap_type_multi(BOOT_CURR_IMG(state));
993 if (BOOT_IS_UPGRADE(swap_type)) {
David Vincze8bdfc2d2019-03-18 15:49:23 +0100994 /* Boot loader wants to switch to the secondary slot.
995 * Ensure image is valid.
996 */
David Vinczecea8b592019-10-29 16:09:51 +0100997 rc = boot_validate_slot(state, BOOT_SECONDARY_SLOT, bs);
998 if (rc == 1) {
999 swap_type = BOOT_SWAP_TYPE_NONE;
1000 } else if (rc != 0) {
Tamas Banf70ef8c2017-12-19 15:35:09 +00001001 swap_type = BOOT_SWAP_TYPE_FAIL;
1002 }
1003 }
1004
1005 return swap_type;
1006}
1007
1008/**
1009 * Calculates the number of sectors the scratch area can contain. A "last"
1010 * source sector is specified because images are copied backwards in flash
1011 * (final index to index number 0).
1012 *
1013 * @param last_sector_idx The index of the last source sector
1014 * (inclusive).
1015 * @param out_first_sector_idx The index of the first source sector
1016 * (inclusive) gets written here.
1017 *
1018 * @return The number of bytes comprised by the
1019 * [first-sector, last-sector] range.
1020 */
1021#ifndef MCUBOOT_OVERWRITE_ONLY
1022static uint32_t
David Vinczecea8b592019-10-29 16:09:51 +01001023boot_copy_sz(struct boot_loader_state *state, int last_sector_idx,
1024 int *out_first_sector_idx)
Tamas Banf70ef8c2017-12-19 15:35:09 +00001025{
1026 size_t scratch_sz;
1027 uint32_t new_sz;
1028 uint32_t sz;
1029 int i;
1030
1031 sz = 0;
1032
David Vinczecea8b592019-10-29 16:09:51 +01001033 scratch_sz = boot_scratch_area_size(state);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001034 for (i = last_sector_idx; i >= 0; i--) {
David Vinczecea8b592019-10-29 16:09:51 +01001035 new_sz = sz + boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i);
David Vincze401c7422019-06-21 20:44:05 +02001036 /*
1037 * The secondary slot is not being checked here, because
1038 * `boot_slots_compatible` already provides assurance that the copy size
1039 * will be compatible with the primary slot and scratch.
1040 */
Tamas Banf70ef8c2017-12-19 15:35:09 +00001041 if (new_sz > scratch_sz) {
1042 break;
1043 }
1044 sz = new_sz;
1045 }
1046
1047 /* i currently refers to a sector that doesn't fit or it is -1 because all
1048 * sectors have been processed. In both cases, exclude sector i.
1049 */
1050 *out_first_sector_idx = i + 1;
1051 return sz;
1052}
1053#endif /* !MCUBOOT_OVERWRITE_ONLY */
1054
1055/**
David Vinczef7641fa2018-09-04 18:29:46 +02001056 * Erases a region of flash.
1057 *
David Vincze401c7422019-06-21 20:44:05 +02001058 * @param flash_area The flash_area containing the region to erase.
David Vinczef7641fa2018-09-04 18:29:46 +02001059 * @param off The offset within the flash area to start the
1060 * erase.
1061 * @param sz The number of bytes to erase.
1062 *
1063 * @return 0 on success; nonzero on failure.
1064 */
David Vincze401c7422019-06-21 20:44:05 +02001065static inline int
David Vinczecea8b592019-10-29 16:09:51 +01001066boot_erase_region(const struct flash_area *fap, uint32_t off, uint32_t sz)
David Vinczef7641fa2018-09-04 18:29:46 +02001067{
David Vincze401c7422019-06-21 20:44:05 +02001068 return flash_area_erase(fap, off, sz);
David Vinczef7641fa2018-09-04 18:29:46 +02001069}
1070
1071/**
Tamas Banf70ef8c2017-12-19 15:35:09 +00001072 * Copies the contents of one flash region to another. You must erase the
1073 * destination region prior to calling this function.
1074 *
1075 * @param flash_area_id_src The ID of the source flash area.
1076 * @param flash_area_id_dst The ID of the destination flash area.
1077 * @param off_src The offset within the source flash area to
1078 * copy from.
1079 * @param off_dst The offset within the destination flash area to
1080 * copy to.
1081 * @param sz The number of bytes to copy.
1082 *
1083 * @return 0 on success; nonzero on failure.
1084 */
1085static int
David Vinczecea8b592019-10-29 16:09:51 +01001086boot_copy_region(struct boot_loader_state *state,
1087 const struct flash_area *fap_src,
David Vincze401c7422019-06-21 20:44:05 +02001088 const struct flash_area *fap_dst,
Tamas Banf70ef8c2017-12-19 15:35:09 +00001089 uint32_t off_src, uint32_t off_dst, uint32_t sz)
1090{
Tamas Banf70ef8c2017-12-19 15:35:09 +00001091 uint32_t bytes_copied;
1092 int chunk_sz;
1093 int rc;
1094
1095 static uint8_t buf[1024];
1096
David Vinczecea8b592019-10-29 16:09:51 +01001097 (void)state;
1098
Tamas Banf70ef8c2017-12-19 15:35:09 +00001099 bytes_copied = 0;
1100 while (bytes_copied < sz) {
Tamas Ban581034a2017-12-19 19:54:37 +00001101 if (sz - bytes_copied > sizeof(buf)) {
1102 chunk_sz = sizeof(buf);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001103 } else {
1104 chunk_sz = sz - bytes_copied;
1105 }
1106
1107 rc = flash_area_read(fap_src, off_src + bytes_copied, buf, chunk_sz);
1108 if (rc != 0) {
David Vincze401c7422019-06-21 20:44:05 +02001109 return BOOT_EFLASH;
Tamas Banf70ef8c2017-12-19 15:35:09 +00001110 }
1111
1112 rc = flash_area_write(fap_dst, off_dst + bytes_copied, buf, chunk_sz);
1113 if (rc != 0) {
David Vincze401c7422019-06-21 20:44:05 +02001114 return BOOT_EFLASH;
Tamas Banf70ef8c2017-12-19 15:35:09 +00001115 }
1116
1117 bytes_copied += chunk_sz;
1118 }
1119
David Vincze401c7422019-06-21 20:44:05 +02001120 return 0;
Tamas Banf70ef8c2017-12-19 15:35:09 +00001121}
1122
1123#ifndef MCUBOOT_OVERWRITE_ONLY
1124static inline int
David Vinczecea8b592019-10-29 16:09:51 +01001125boot_status_init(const struct boot_loader_state *state,
1126 const struct flash_area *fap,
1127 const struct boot_status *bs)
Tamas Banf70ef8c2017-12-19 15:35:09 +00001128{
Tamas Banf70ef8c2017-12-19 15:35:09 +00001129 struct boot_swap_state swap_state;
David Vinczecea8b592019-10-29 16:09:51 +01001130 uint8_t image_index;
Tamas Banf70ef8c2017-12-19 15:35:09 +00001131 int rc;
1132
David Vinczecea8b592019-10-29 16:09:51 +01001133#if (BOOT_IMAGE_NUMBER == 1)
1134 (void)state;
1135#endif
1136
1137 image_index = BOOT_CURR_IMG(state);
1138
David Vincze401c7422019-06-21 20:44:05 +02001139 BOOT_LOG_DBG("initializing status; fa_id=%d", fap->fa_id);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001140
David Vinczecea8b592019-10-29 16:09:51 +01001141 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SECONDARY(image_index),
1142 &swap_state);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001143 assert(rc == 0);
1144
David Vincze401c7422019-06-21 20:44:05 +02001145 if (bs->swap_type != BOOT_SWAP_TYPE_NONE) {
David Vinczecea8b592019-10-29 16:09:51 +01001146 rc = boot_write_swap_info(fap, bs->swap_type, image_index);
David Vincze401c7422019-06-21 20:44:05 +02001147 assert(rc == 0);
1148 }
1149
Tamas Banf70ef8c2017-12-19 15:35:09 +00001150 if (swap_state.image_ok == BOOT_FLAG_SET) {
1151 rc = boot_write_image_ok(fap);
1152 assert(rc == 0);
1153 }
1154
1155 rc = boot_write_swap_size(fap, bs->swap_size);
1156 assert(rc == 0);
1157
1158 rc = boot_write_magic(fap);
1159 assert(rc == 0);
1160
Tamas Banf70ef8c2017-12-19 15:35:09 +00001161 return 0;
1162}
David Vinczef7641fa2018-09-04 18:29:46 +02001163
1164static int
David Vinczecea8b592019-10-29 16:09:51 +01001165boot_erase_trailer_sectors(const struct boot_loader_state *state,
1166 const struct flash_area *fap)
David Vinczef7641fa2018-09-04 18:29:46 +02001167{
1168 uint8_t slot;
David Vincze401c7422019-06-21 20:44:05 +02001169 uint32_t sector;
1170 uint32_t trailer_sz;
1171 uint32_t total_sz;
1172 uint32_t off;
1173 uint32_t sz;
David Vinczebb207982019-08-21 15:13:04 +02001174 int fa_id_primary;
1175 int fa_id_secondary;
David Vinczecea8b592019-10-29 16:09:51 +01001176 uint8_t image_index;
David Vinczef7641fa2018-09-04 18:29:46 +02001177 int rc;
1178
David Vincze401c7422019-06-21 20:44:05 +02001179 BOOT_LOG_DBG("erasing trailer; fa_id=%d", fap->fa_id);
1180
David Vinczecea8b592019-10-29 16:09:51 +01001181 image_index = BOOT_CURR_IMG(state);
1182 fa_id_primary = flash_area_id_from_multi_image_slot(image_index,
1183 BOOT_PRIMARY_SLOT);
1184 fa_id_secondary = flash_area_id_from_multi_image_slot(image_index,
1185 BOOT_SECONDARY_SLOT);
David Vinczebb207982019-08-21 15:13:04 +02001186
1187 if (fap->fa_id == fa_id_primary) {
David Vincze8bdfc2d2019-03-18 15:49:23 +01001188 slot = BOOT_PRIMARY_SLOT;
David Vinczebb207982019-08-21 15:13:04 +02001189 } else if (fap->fa_id == fa_id_secondary) {
David Vincze8bdfc2d2019-03-18 15:49:23 +01001190 slot = BOOT_SECONDARY_SLOT;
David Vinczebb207982019-08-21 15:13:04 +02001191 } else {
David Vinczef7641fa2018-09-04 18:29:46 +02001192 return BOOT_EFLASH;
1193 }
1194
David Vincze401c7422019-06-21 20:44:05 +02001195 /* delete starting from last sector and moving to beginning */
David Vinczecea8b592019-10-29 16:09:51 +01001196 sector = boot_img_num_sectors(state, slot) - 1;
1197 trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(state));
David Vincze401c7422019-06-21 20:44:05 +02001198 total_sz = 0;
1199 do {
David Vinczecea8b592019-10-29 16:09:51 +01001200 sz = boot_img_sector_size(state, slot, sector);
1201 off = boot_img_sector_off(state, slot, sector);
1202 rc = boot_erase_region(fap, off, sz);
David Vincze401c7422019-06-21 20:44:05 +02001203 assert(rc == 0);
1204
1205 sector--;
1206 total_sz += sz;
1207 } while (total_sz < trailer_sz);
David Vinczef7641fa2018-09-04 18:29:46 +02001208
1209 return rc;
1210}
1211#endif /* !MCUBOOT_OVERWRITE_ONLY */
Tamas Banf70ef8c2017-12-19 15:35:09 +00001212
Tamas Banf70ef8c2017-12-19 15:35:09 +00001213/**
1214 * Swaps the contents of two flash regions within the two image slots.
1215 *
1216 * @param idx The index of the first sector in the range of
1217 * sectors being swapped.
1218 * @param sz The number of bytes to swap.
1219 * @param bs The current boot status. This struct gets
1220 * updated according to the outcome.
1221 *
1222 * @return 0 on success; nonzero on failure.
1223 */
1224#ifndef MCUBOOT_OVERWRITE_ONLY
1225static 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
1622/**
David Vincze8bdfc2d2019-03-18 15:49:23 +01001623 * Marks the image in the primary slot as fully copied.
Tamas Banf70ef8c2017-12-19 15:35:09 +00001624 */
1625#ifndef MCUBOOT_OVERWRITE_ONLY
1626static 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}
1642#endif /* !MCUBOOT_OVERWRITE_ONLY */
1643
1644/**
David Vincze8bdfc2d2019-03-18 15:49:23 +01001645 * Marks a reverted image in the primary slot as confirmed. This is necessary to
1646 * ensure the status bytes from the image revert operation don't get processed
1647 * on a subsequent boot.
Tamas Banf70ef8c2017-12-19 15:35:09 +00001648 *
1649 * NOTE: image_ok is tested before writing because if there's a valid permanent
David Vincze8bdfc2d2019-03-18 15:49:23 +01001650 * image installed on the primary slot and the new image to be upgrade to has a
1651 * bad sig, image_ok would be overwritten.
Tamas Banf70ef8c2017-12-19 15:35:09 +00001652 */
1653#ifndef MCUBOOT_OVERWRITE_ONLY
1654static int
David Vinczecea8b592019-10-29 16:09:51 +01001655boot_set_image_ok(uint8_t image_index)
Tamas Banf70ef8c2017-12-19 15:35:09 +00001656{
1657 const struct flash_area *fap;
1658 struct boot_swap_state state;
1659 int rc;
1660
David Vinczecea8b592019-10-29 16:09:51 +01001661 rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index),
1662 &fap);
Tamas Banf70ef8c2017-12-19 15:35:09 +00001663 if (rc != 0) {
1664 return BOOT_EFLASH;
1665 }
1666
1667 rc = boot_read_swap_state(fap, &state);
1668 if (rc != 0) {
1669 rc = BOOT_EFLASH;
1670 goto out;
1671 }
1672
1673 if (state.image_ok == BOOT_FLAG_UNSET) {
1674 rc = boot_write_image_ok(fap);
1675 }
1676
1677out:
1678 flash_area_close(fap);
1679 return rc;
1680}
1681#endif /* !MCUBOOT_OVERWRITE_ONLY */
1682
David Vinczebb6e3b62019-07-31 14:24:05 +02001683#if (BOOT_IMAGE_NUMBER > 1)
1684/**
David Vinczecea8b592019-10-29 16:09:51 +01001685 * Check if the version of the image is not older than required.
1686 *
1687 * @param req Required minimal image version.
1688 * @param ver Version of the image to be checked.
1689 *
1690 * @return 0 if the version is sufficient, nonzero otherwise.
1691 */
1692static int
1693boot_is_version_sufficient(struct image_version *req,
1694 struct image_version *ver)
1695{
1696 if (ver->iv_major > req->iv_major) {
1697 return 0;
1698 }
1699 if (ver->iv_major < req->iv_major) {
1700 return BOOT_EBADVERSION;
1701 }
1702 /* The major version numbers are equal. */
1703 if (ver->iv_minor > req->iv_minor) {
1704 return 0;
1705 }
1706 if (ver->iv_minor < req->iv_minor) {
1707 return BOOT_EBADVERSION;
1708 }
1709 /* The minor version numbers are equal. */
1710 if (ver->iv_revision < req->iv_revision) {
1711 return BOOT_EBADVERSION;
1712 }
1713
1714 return 0;
1715}
1716
1717/**
David Vinczebb6e3b62019-07-31 14:24:05 +02001718 * Check the image dependency whether it is satisfied and modify
1719 * the swap type if necessary.
1720 *
1721 * @param dep Image dependency which has to be verified.
1722 *
1723 * @return 0 on success; nonzero on failure.
1724 */
1725static int
David Vinczecea8b592019-10-29 16:09:51 +01001726boot_verify_slot_dependency(struct boot_loader_state *state,
1727 struct image_dependency *dep)
David Vinczebb6e3b62019-07-31 14:24:05 +02001728{
1729 struct image_version *dep_version;
1730 size_t dep_slot;
1731 int rc;
David Vinczecea8b592019-10-29 16:09:51 +01001732 uint8_t swap_type;
David Vinczebb6e3b62019-07-31 14:24:05 +02001733
1734 /* Determine the source of the image which is the subject of
1735 * the dependency and get it's version. */
David Vinczecea8b592019-10-29 16:09:51 +01001736 swap_type = state->swap_type[dep->image_id];
1737 dep_slot = (swap_type != BOOT_SWAP_TYPE_NONE) ?
David Vinczebb6e3b62019-07-31 14:24:05 +02001738 BOOT_SECONDARY_SLOT : BOOT_PRIMARY_SLOT;
David Vinczecea8b592019-10-29 16:09:51 +01001739 dep_version = &state->imgs[dep->image_id][dep_slot].hdr.ih_ver;
David Vinczebb6e3b62019-07-31 14:24:05 +02001740
1741 rc = boot_is_version_sufficient(&dep->image_min_version, dep_version);
1742 if (rc != 0) {
1743 /* Dependency not satisfied.
1744 * Modify the swap type to decrease the version number of the image
1745 * (which will be located in the primary slot after the boot process),
1746 * consequently the number of unsatisfied dependencies will be
1747 * decreased or remain the same.
1748 */
David Vinczecea8b592019-10-29 16:09:51 +01001749 switch (BOOT_SWAP_TYPE(state)) {
David Vinczebb6e3b62019-07-31 14:24:05 +02001750 case BOOT_SWAP_TYPE_TEST:
1751 case BOOT_SWAP_TYPE_PERM:
David Vinczecea8b592019-10-29 16:09:51 +01001752 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
David Vinczebb6e3b62019-07-31 14:24:05 +02001753 break;
1754 case BOOT_SWAP_TYPE_NONE:
David Vinczecea8b592019-10-29 16:09:51 +01001755 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_REVERT;
David Vinczebb6e3b62019-07-31 14:24:05 +02001756 break;
1757 default:
1758 break;
1759 }
1760 }
1761
1762 return rc;
1763}
1764
1765/**
1766 * Read all dependency TLVs of an image from the flash and verify
1767 * one after another to see if they are all satisfied.
1768 *
1769 * @param slot Image slot number.
1770 *
1771 * @return 0 on success; nonzero on failure.
1772 */
1773static int
David Vinczecea8b592019-10-29 16:09:51 +01001774boot_verify_slot_dependencies(struct boot_loader_state *state, uint32_t slot)
David Vinczebb6e3b62019-07-31 14:24:05 +02001775{
1776 const struct flash_area *fap;
David Vinczebb6e3b62019-07-31 14:24:05 +02001777 struct image_tlv tlv;
1778 struct image_dependency dep;
1779 uint32_t off;
1780 uint32_t end;
1781 bool dep_tlvs_found = false;
David Vinczecea8b592019-10-29 16:09:51 +01001782 int area_id;
David Vinczebb6e3b62019-07-31 14:24:05 +02001783 int rc;
1784
David Vinczecea8b592019-10-29 16:09:51 +01001785 area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
1786 rc = flash_area_open(area_id, &fap);
David Vinczebb6e3b62019-07-31 14:24:05 +02001787 if (rc != 0) {
1788 rc = BOOT_EFLASH;
1789 goto done;
1790 }
1791
David Vinczecea8b592019-10-29 16:09:51 +01001792 rc = boot_find_tlv_offs(boot_img_hdr(state, slot), fap, &off, &end);
David Vinczebb6e3b62019-07-31 14:24:05 +02001793 if (rc != 0) {
David Vinczebb6e3b62019-07-31 14:24:05 +02001794 goto done;
1795 }
1796
David Vinczebb6e3b62019-07-31 14:24:05 +02001797 /* Traverse through all of the TLVs to find the dependency TLVs. */
Tamas Ban056ed0b2019-09-16 12:48:32 +01001798 while(off < end) {
David Vinczebb6e3b62019-07-31 14:24:05 +02001799 rc = flash_area_read(fap, off, &tlv, sizeof(tlv));
1800 if (rc != 0) {
1801 rc = BOOT_EFLASH;
1802 goto done;
1803 }
1804
1805 if (tlv.it_type == IMAGE_TLV_DEPENDENCY) {
David Vinczecea8b592019-10-29 16:09:51 +01001806 dep_tlvs_found = true;
David Vinczebb6e3b62019-07-31 14:24:05 +02001807
1808 if (tlv.it_len != sizeof(dep)) {
1809 rc = BOOT_EBADIMAGE;
1810 goto done;
1811 }
1812
1813 rc = flash_area_read(fap, off + sizeof(tlv), &dep, tlv.it_len);
1814 if (rc != 0) {
1815 rc = BOOT_EFLASH;
1816 goto done;
1817 }
1818
David Vinczecea8b592019-10-29 16:09:51 +01001819 if (dep.image_id >= BOOT_IMAGE_NUMBER) {
1820 rc = BOOT_EBADARGS;
1821 goto done;
1822 }
1823
David Vinczebb6e3b62019-07-31 14:24:05 +02001824 /* Verify dependency and modify the swap type if not satisfied. */
David Vinczecea8b592019-10-29 16:09:51 +01001825 rc = boot_verify_slot_dependency(state, &dep);
David Vinczebb6e3b62019-07-31 14:24:05 +02001826 if (rc != 0) {
1827 /* Dependency not satisfied. */
1828 goto done;
1829 }
1830
1831 /* Dependency satisfied, no action needed.
1832 * Continue with the next TLV entry.
1833 */
1834 } else if (dep_tlvs_found) {
1835 /* The dependency TLVs are contiguous in the TLV area. If a
1836 * dependency had already been found and the last read TLV
1837 * has a different type then there are no more dependency TLVs.
1838 * The search can be finished.
1839 */
1840 break;
1841 }
Tamas Ban056ed0b2019-09-16 12:48:32 +01001842 /* Avoid integer overflow. */
1843 if (boot_add_uint32_overflow_check(off, (sizeof(tlv) + tlv.it_len))) {
1844 /* Potential overflow. */
1845 return BOOT_EBADIMAGE;
1846 } else {
1847 off += sizeof(tlv) + tlv.it_len;
1848 }
David Vinczebb6e3b62019-07-31 14:24:05 +02001849 }
1850
1851done:
1852 flash_area_close(fap);
1853 return rc;
1854}
1855
1856/**
David Vinczebb6e3b62019-07-31 14:24:05 +02001857 * Iterate over all the images and verify whether the image dependencies in the
1858 * TLV area are all satisfied and update the related swap type if necessary.
1859 */
David Vinczecea8b592019-10-29 16:09:51 +01001860static int
1861boot_verify_dependencies(struct boot_loader_state *state)
David Vinczebb6e3b62019-07-31 14:24:05 +02001862{
David Vinczebb6e3b62019-07-31 14:24:05 +02001863 int rc;
David Vinczecea8b592019-10-29 16:09:51 +01001864 uint8_t slot;
David Vinczebb6e3b62019-07-31 14:24:05 +02001865
David Vinczecea8b592019-10-29 16:09:51 +01001866 BOOT_CURR_IMG(state) = 0;
1867 while (BOOT_CURR_IMG(state) < BOOT_IMAGE_NUMBER) {
1868 if (BOOT_SWAP_TYPE(state) != BOOT_SWAP_TYPE_NONE &&
1869 BOOT_SWAP_TYPE(state) != BOOT_SWAP_TYPE_FAIL) {
1870 slot = BOOT_SECONDARY_SLOT;
1871 } else {
1872 slot = BOOT_PRIMARY_SLOT;
1873 }
1874
1875 rc = boot_verify_slot_dependencies(state, slot);
David Vinczebb6e3b62019-07-31 14:24:05 +02001876 if (rc == 0) {
1877 /* All dependencies've been satisfied, continue with next image. */
David Vinczecea8b592019-10-29 16:09:51 +01001878 BOOT_CURR_IMG(state)++;
David Vinczebb6e3b62019-07-31 14:24:05 +02001879 } else if (rc == BOOT_EBADVERSION) {
David Vinczecea8b592019-10-29 16:09:51 +01001880 /* Cannot upgrade due to non-met dependencies, so disable all
1881 * image upgrades.
1882 */
1883 for (int idx = 0; idx < BOOT_IMAGE_NUMBER; idx++) {
1884 BOOT_CURR_IMG(state) = idx;
1885 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
1886 }
1887 break;
David Vinczebb6e3b62019-07-31 14:24:05 +02001888 } else {
1889 /* Other error happened, images are inconsistent */
David Vinczecea8b592019-10-29 16:09:51 +01001890 return rc;
David Vinczebb6e3b62019-07-31 14:24:05 +02001891 }
1892 }
David Vinczecea8b592019-10-29 16:09:51 +01001893 return rc;
David Vinczebb6e3b62019-07-31 14:24:05 +02001894}
1895#endif /* (BOOT_IMAGE_NUMBER > 1) */
1896
Tamas Banf70ef8c2017-12-19 15:35:09 +00001897/**
David Vincze7384ee72019-07-23 17:00:42 +02001898 * Performs a clean (not aborted) image update.
Tamas Banf70ef8c2017-12-19 15:35:09 +00001899 *
David Vincze7384ee72019-07-23 17:00:42 +02001900 * @param bs The current boot status.
Tamas Banf70ef8c2017-12-19 15:35:09 +00001901 *
1902 * @return 0 on success; nonzero on failure.
1903 */
1904static int
David Vinczecea8b592019-10-29 16:09:51 +01001905boot_perform_update(struct boot_loader_state *state, struct boot_status *bs)
Tamas Banf70ef8c2017-12-19 15:35:09 +00001906{
Tamas Banf70ef8c2017-12-19 15:35:09 +00001907 int rc;
David Vinczecea8b592019-10-29 16:09:51 +01001908#ifndef MCUBOOT_OVERWRITE_ONLY
1909 uint8_t swap_type;
1910#endif
Tamas Banf70ef8c2017-12-19 15:35:09 +00001911
David Vincze7384ee72019-07-23 17:00:42 +02001912 /* At this point there are no aborted swaps. */
1913#if defined(MCUBOOT_OVERWRITE_ONLY)
David Vinczecea8b592019-10-29 16:09:51 +01001914 rc = boot_copy_image(state, bs);
David Vincze7384ee72019-07-23 17:00:42 +02001915#else
David Vinczecea8b592019-10-29 16:09:51 +01001916 rc = boot_swap_image(state, bs);
David Vincze7384ee72019-07-23 17:00:42 +02001917#endif
Tamas Banf70ef8c2017-12-19 15:35:09 +00001918 assert(rc == 0);
David Vincze7384ee72019-07-23 17:00:42 +02001919
1920#ifndef MCUBOOT_OVERWRITE_ONLY
1921 /* The following state needs image_ok be explicitly set after the
1922 * swap was finished to avoid a new revert.
1923 */
David Vinczecea8b592019-10-29 16:09:51 +01001924 swap_type = BOOT_SWAP_TYPE(state);
1925 if (swap_type == BOOT_SWAP_TYPE_REVERT ||
1926 swap_type == BOOT_SWAP_TYPE_PERM) {
1927 rc = boot_set_image_ok(BOOT_CURR_IMG(state));
David Vincze7384ee72019-07-23 17:00:42 +02001928 if (rc != 0) {
David Vinczecea8b592019-10-29 16:09:51 +01001929 BOOT_SWAP_TYPE(state) = swap_type = BOOT_SWAP_TYPE_PANIC;
David Vincze7384ee72019-07-23 17:00:42 +02001930 }
Tamas Banf70ef8c2017-12-19 15:35:09 +00001931 }
1932
David Vinczecea8b592019-10-29 16:09:51 +01001933 if (swap_type == BOOT_SWAP_TYPE_PERM) {
David Vincze7384ee72019-07-23 17:00:42 +02001934 /* Update the stored security counter with the new image's security
1935 * counter value. The primary slot holds the new image at this
1936 * point, but the secondary slot's image header must be passed
1937 * because the read image headers in the boot_data structure have
1938 * not been updated yet.
1939 *
1940 * In case of a permanent image swap mcuboot will never attempt to
1941 * revert the images on the next reboot. Therefore, the security
1942 * counter must be increased right after the image upgrade.
David Vincze401c7422019-06-21 20:44:05 +02001943 */
David Vinczecea8b592019-10-29 16:09:51 +01001944 rc = boot_update_security_counter(
1945 BOOT_CURR_IMG(state),
1946 BOOT_PRIMARY_SLOT,
1947 boot_img_hdr(state, BOOT_SECONDARY_SLOT));
David Vincze7384ee72019-07-23 17:00:42 +02001948 if (rc != 0) {
1949 BOOT_LOG_ERR("Security counter update failed after "
1950 "image upgrade.");
David Vinczecea8b592019-10-29 16:09:51 +01001951 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
Tamas Banf70ef8c2017-12-19 15:35:09 +00001952 }
1953 }
1954
David Vinczecea8b592019-10-29 16:09:51 +01001955 if (BOOT_IS_UPGRADE(swap_type)) {
1956 rc = boot_set_copy_done(BOOT_CURR_IMG(state));
David Vincze7384ee72019-07-23 17:00:42 +02001957 if (rc != 0) {
David Vinczecea8b592019-10-29 16:09:51 +01001958 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
David Vincze7384ee72019-07-23 17:00:42 +02001959 }
1960 }
1961#endif /* !MCUBOOT_OVERWRITE_ONLY */
1962
1963 return rc;
1964}
1965
1966/**
1967 * Completes a previously aborted image swap.
1968 *
1969 * @param bs The current boot status.
1970 *
1971 * @return 0 on success; nonzero on failure.
1972 */
1973#if !defined(MCUBOOT_OVERWRITE_ONLY)
1974static int
David Vinczecea8b592019-10-29 16:09:51 +01001975boot_complete_partial_swap(struct boot_loader_state *state,
1976 struct boot_status *bs)
David Vincze7384ee72019-07-23 17:00:42 +02001977{
1978 int rc;
1979
1980 /* Determine the type of swap operation being resumed from the
1981 * `swap-type` trailer field.
1982 */
David Vinczecea8b592019-10-29 16:09:51 +01001983 rc = boot_swap_image(state, bs);
David Vincze7384ee72019-07-23 17:00:42 +02001984 assert(rc == 0);
1985
David Vinczecea8b592019-10-29 16:09:51 +01001986 BOOT_SWAP_TYPE(state) = bs->swap_type;
David Vincze7384ee72019-07-23 17:00:42 +02001987
1988 /* The following states need image_ok be explicitly set after the
1989 * swap was finished to avoid a new revert.
1990 */
1991 if (bs->swap_type == BOOT_SWAP_TYPE_REVERT ||
1992 bs->swap_type == BOOT_SWAP_TYPE_PERM) {
David Vinczecea8b592019-10-29 16:09:51 +01001993 rc = boot_set_image_ok(BOOT_CURR_IMG(state));
David Vincze7384ee72019-07-23 17:00:42 +02001994 if (rc != 0) {
David Vinczecea8b592019-10-29 16:09:51 +01001995 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
David Vincze7384ee72019-07-23 17:00:42 +02001996 }
1997 }
1998
David Vinczecea8b592019-10-29 16:09:51 +01001999 if (BOOT_IS_UPGRADE(bs->swap_type)) {
2000 rc = boot_set_copy_done(BOOT_CURR_IMG(state));
David Vincze7384ee72019-07-23 17:00:42 +02002001 if (rc != 0) {
David Vinczecea8b592019-10-29 16:09:51 +01002002 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
David Vincze7384ee72019-07-23 17:00:42 +02002003 }
2004 }
2005
David Vinczecea8b592019-10-29 16:09:51 +01002006 if (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_PANIC) {
David Vincze7384ee72019-07-23 17:00:42 +02002007 BOOT_LOG_ERR("panic!");
2008 assert(0);
2009
2010 /* Loop forever... */
2011 while (1) {}
2012 }
2013
2014 return rc;
2015}
2016#endif /* !MCUBOOT_OVERWRITE_ONLY */
2017
2018#if (BOOT_IMAGE_NUMBER > 1)
2019/**
2020 * Review the validity of previously determined swap types of other images.
2021 *
2022 * @param aborted_swap The current image upgrade is a
2023 * partial/aborted swap.
2024 */
2025static void
David Vinczecea8b592019-10-29 16:09:51 +01002026boot_review_image_swap_types(struct boot_loader_state *state,
2027 bool aborted_swap)
David Vincze7384ee72019-07-23 17:00:42 +02002028{
2029 /* In that case if we rebooted in the middle of an image upgrade process, we
2030 * must review the validity of swap types, that were previously determined
2031 * for other images. The image_ok flag had not been set before the reboot
2032 * for any of the updated images (only the copy_done flag) and thus falsely
2033 * the REVERT swap type has been determined for the previous images that had
2034 * been updated before the reboot.
2035 *
2036 * There are two separate scenarios that we have to deal with:
2037 *
2038 * 1. The reboot has happened during swapping an image:
2039 * The current image upgrade has been determined as a
2040 * partial/aborted swap.
2041 * 2. The reboot has happened between two separate image upgrades:
2042 * In this scenario we must check the swap type of the current image.
2043 * In those cases if it is NONE or REVERT we cannot certainly determine
2044 * the fact of a reboot. In a consistent state images must move in the
2045 * same direction or stay in place, e.g. in practice REVERT and TEST
2046 * swap types cannot be present at the same time. If the swap type of
2047 * the current image is either TEST, PERM or FAIL we must review the
2048 * already determined swap types of other images and set each false
2049 * REVERT swap types to NONE (these images had been successfully
2050 * updated before the system rebooted between two separate image
2051 * upgrades).
2052 */
2053
David Vinczecea8b592019-10-29 16:09:51 +01002054 if (BOOT_CURR_IMG(state) == 0) {
David Vincze7384ee72019-07-23 17:00:42 +02002055 /* Nothing to do */
2056 return;
2057 }
2058
2059 if (!aborted_swap) {
David Vinczecea8b592019-10-29 16:09:51 +01002060 if ((BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_NONE) ||
2061 (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_REVERT)) {
David Vincze7384ee72019-07-23 17:00:42 +02002062 /* Nothing to do */
2063 return;
2064 }
2065 }
2066
David Vinczecea8b592019-10-29 16:09:51 +01002067 for (uint8_t i = 0; i < BOOT_CURR_IMG(state); i++) {
2068 if (state->swap_type[i] == BOOT_SWAP_TYPE_REVERT) {
2069 state->swap_type[i] = BOOT_SWAP_TYPE_NONE;
David Vincze7384ee72019-07-23 17:00:42 +02002070 }
2071 }
2072}
2073#endif
2074
2075/**
2076 * Prepare image to be updated if required.
2077 *
2078 * Prepare image to be updated if required with completing an image swap
2079 * operation if one was aborted and/or determining the type of the
2080 * swap operation. In case of any error set the swap type to NONE.
2081 *
David Vinczecea8b592019-10-29 16:09:51 +01002082 * @param state Boot loader status information.
David Vincze7384ee72019-07-23 17:00:42 +02002083 * @param bs Pointer where the read and possibly updated
2084 * boot status can be written to.
2085 */
2086static void
David Vinczecea8b592019-10-29 16:09:51 +01002087boot_prepare_image_for_update(struct boot_loader_state *state,
2088 struct boot_status *bs)
David Vincze7384ee72019-07-23 17:00:42 +02002089{
2090 int rc;
2091
2092 /* Determine the sector layout of the image slots and scratch area. */
David Vinczecea8b592019-10-29 16:09:51 +01002093 rc = boot_read_sectors(state);
David Vincze7384ee72019-07-23 17:00:42 +02002094 if (rc != 0) {
2095 BOOT_LOG_WRN("Failed reading sectors; BOOT_MAX_IMG_SECTORS=%d"
2096 " - too small?", BOOT_MAX_IMG_SECTORS);
2097 /* Unable to determine sector layout, continue with next image
2098 * if there is one.
2099 */
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 /* Attempt to read an image header from each slot. */
David Vinczecea8b592019-10-29 16:09:51 +01002105 rc = boot_read_image_headers(state, false);
David Vincze7384ee72019-07-23 17:00:42 +02002106 if (rc != 0) {
2107 /* Continue with next image if there is one. */
David Vinczecea8b592019-10-29 16:09:51 +01002108 BOOT_LOG_WRN("Failed reading image headers; Image=%u",
2109 BOOT_CURR_IMG(state));
2110 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
David Vincze7384ee72019-07-23 17:00:42 +02002111 return;
2112 }
2113
2114 /* If the current image's slots aren't compatible, no swap is possible.
2115 * Just boot into primary slot.
2116 */
David Vinczecea8b592019-10-29 16:09:51 +01002117 if (boot_slots_compatible(state)) {
2118 rc = boot_read_status(state, bs);
David Vincze7384ee72019-07-23 17:00:42 +02002119 if (rc != 0) {
2120 BOOT_LOG_WRN("Failed reading boot status; Image=%u",
David Vinczecea8b592019-10-29 16:09:51 +01002121 BOOT_CURR_IMG(state));
David Vincze7384ee72019-07-23 17:00:42 +02002122 /* Continue with next image if there is one. */
David Vinczecea8b592019-10-29 16:09:51 +01002123 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
David Vincze7384ee72019-07-23 17:00:42 +02002124 return;
2125 }
2126
2127 /* Determine if we rebooted in the middle of an image swap
2128 * operation. If a partial swap was detected, complete it.
2129 */
2130 if (bs->idx != BOOT_STATUS_IDX_0 || bs->state != BOOT_STATUS_STATE_0) {
2131
2132#if (BOOT_IMAGE_NUMBER > 1)
David Vinczecea8b592019-10-29 16:09:51 +01002133 boot_review_image_swap_types(state, true);
David Vincze7384ee72019-07-23 17:00:42 +02002134#endif
2135
2136#ifdef MCUBOOT_OVERWRITE_ONLY
2137 /* Should never arrive here, overwrite-only mode has
2138 * no swap state.
2139 */
2140 assert(0);
2141#else
2142 /* Determine the type of swap operation being resumed from the
2143 * `swap-type` trailer field.
2144 */
David Vinczecea8b592019-10-29 16:09:51 +01002145 rc = boot_complete_partial_swap(state, bs);
David Vincze7384ee72019-07-23 17:00:42 +02002146 assert(rc == 0);
2147#endif
2148 /* Attempt to read an image header from each slot. Ensure that
2149 * image headers in slots are aligned with headers in boot_data.
2150 */
David Vinczecea8b592019-10-29 16:09:51 +01002151 rc = boot_read_image_headers(state, false);
David Vincze7384ee72019-07-23 17:00:42 +02002152 assert(rc == 0);
2153
2154 /* Swap has finished set to NONE */
David Vinczecea8b592019-10-29 16:09:51 +01002155 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
David Vincze7384ee72019-07-23 17:00:42 +02002156 } else {
2157 /* There was no partial swap, determine swap type. */
2158 if (bs->swap_type == BOOT_SWAP_TYPE_NONE) {
David Vinczecea8b592019-10-29 16:09:51 +01002159 BOOT_SWAP_TYPE(state) = boot_validated_swap_type(state, bs);
2160 } else if (boot_validate_slot(state,
2161 BOOT_SECONDARY_SLOT, bs) != 0) {
2162 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_FAIL;
David Vincze7384ee72019-07-23 17:00:42 +02002163 } else {
David Vinczecea8b592019-10-29 16:09:51 +01002164 BOOT_SWAP_TYPE(state) = bs->swap_type;
David Vincze7384ee72019-07-23 17:00:42 +02002165 }
2166
2167#if (BOOT_IMAGE_NUMBER > 1)
David Vinczecea8b592019-10-29 16:09:51 +01002168 boot_review_image_swap_types(state, false);
David Vincze7384ee72019-07-23 17:00:42 +02002169#endif
2170 }
2171 } else {
2172 /* In that case if slots are not compatible. */
David Vinczecea8b592019-10-29 16:09:51 +01002173 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
David Vincze7384ee72019-07-23 17:00:42 +02002174 }
Tamas Banf70ef8c2017-12-19 15:35:09 +00002175}
2176
2177/**
2178 * Prepares the booting process. This function moves images around in flash as
2179 * appropriate, and tells you what address to boot from.
2180 *
David Vinczecea8b592019-10-29 16:09:51 +01002181 * @param state Boot loader status information.
Tamas Banf70ef8c2017-12-19 15:35:09 +00002182 * @param rsp On success, indicates how booting should occur.
2183 *
2184 * @return 0 on success; nonzero on failure.
2185 */
2186int
David Vinczecea8b592019-10-29 16:09:51 +01002187context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp)
Tamas Banf70ef8c2017-12-19 15:35:09 +00002188{
Tamas Banf70ef8c2017-12-19 15:35:09 +00002189 size_t slot;
David Vincze7384ee72019-07-23 17:00:42 +02002190 struct boot_status bs;
Tamas Ban4e5ed8d2019-09-17 09:31:11 +01002191 int rc = 0;
Tamas Banf70ef8c2017-12-19 15:35:09 +00002192 int fa_id;
David Vinczecea8b592019-10-29 16:09:51 +01002193 int image_index;
2194 bool has_upgrade;
Tamas Banf70ef8c2017-12-19 15:35:09 +00002195
2196 /* The array of slot sectors are defined here (as opposed to file scope) so
2197 * that they don't get allocated for non-boot-loader apps. This is
2198 * necessary because the gcc option "-fdata-sections" doesn't seem to have
2199 * any effect in older gcc versions (e.g., 4.8.4).
2200 */
David Vincze7384ee72019-07-23 17:00:42 +02002201 static boot_sector_t
2202 primary_slot_sectors[BOOT_IMAGE_NUMBER][BOOT_MAX_IMG_SECTORS];
2203 static boot_sector_t
2204 secondary_slot_sectors[BOOT_IMAGE_NUMBER][BOOT_MAX_IMG_SECTORS];
David Vincze401c7422019-06-21 20:44:05 +02002205 static boot_sector_t scratch_sectors[BOOT_MAX_IMG_SECTORS];
Tamas Banf70ef8c2017-12-19 15:35:09 +00002206
David Vincze7384ee72019-07-23 17:00:42 +02002207 /* Iterate over all the images. By the end of the loop the swap type has
2208 * to be determined for each image and all aborted swaps have to be
2209 * completed.
Tamas Banf70ef8c2017-12-19 15:35:09 +00002210 */
David Vinczecea8b592019-10-29 16:09:51 +01002211 IMAGES_ITER(BOOT_CURR_IMG(state)) {
2212
2213 image_index = BOOT_CURR_IMG(state);
2214
2215 BOOT_IMG(state, BOOT_PRIMARY_SLOT).sectors =
2216 primary_slot_sectors[image_index];
2217 BOOT_IMG(state, BOOT_SECONDARY_SLOT).sectors =
2218 secondary_slot_sectors[image_index];
2219 state->scratch.sectors = scratch_sectors;
Tamas Banf70ef8c2017-12-19 15:35:09 +00002220
David Vincze7384ee72019-07-23 17:00:42 +02002221 /* Open primary and secondary image areas for the duration
2222 * of this call.
Tamas Banf70ef8c2017-12-19 15:35:09 +00002223 */
David Vincze7384ee72019-07-23 17:00:42 +02002224 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
David Vinczecea8b592019-10-29 16:09:51 +01002225 fa_id = flash_area_id_from_multi_image_slot(image_index, slot);
2226 rc = flash_area_open(fa_id, &BOOT_IMG_AREA(state, slot));
David Vincze7384ee72019-07-23 17:00:42 +02002227 assert(rc == 0);
2228 }
2229 rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH,
David Vinczecea8b592019-10-29 16:09:51 +01002230 &BOOT_SCRATCH_AREA(state));
David Vincze7384ee72019-07-23 17:00:42 +02002231 assert(rc == 0);
2232
2233 /* Determine swap type and complete swap if it has been aborted. */
David Vinczecea8b592019-10-29 16:09:51 +01002234 boot_prepare_image_for_update(state, &bs);
2235
2236 if (BOOT_IS_UPGRADE(BOOT_SWAP_TYPE(state))) {
2237 has_upgrade = true;
2238 }
David Vincze7384ee72019-07-23 17:00:42 +02002239 }
2240
David Vinczebb6e3b62019-07-31 14:24:05 +02002241#if (BOOT_IMAGE_NUMBER > 1)
David Vinczecea8b592019-10-29 16:09:51 +01002242 if (has_upgrade) {
2243 /* Iterate over all the images and verify whether the image dependencies
2244 * are all satisfied and update swap type if necessary.
2245 */
2246 rc = boot_verify_dependencies(state);
2247 if (rc == BOOT_EBADVERSION) {
2248 /*
2249 * It was impossible to upgrade because the expected dependency
2250 * version was not available. Here we already changed the swap_type
2251 * so that instead of asserting the bootloader, we continue and no
2252 * upgrade is performed.
2253 */
2254 rc = 0;
2255 }
2256 }
David Vinczebb6e3b62019-07-31 14:24:05 +02002257#endif
2258
David Vincze7384ee72019-07-23 17:00:42 +02002259 /* Iterate over all the images. At this point there are no aborted swaps
2260 * and the swap types are determined for each image. By the end of the loop
2261 * all required update operations will have been finished.
2262 */
David Vinczecea8b592019-10-29 16:09:51 +01002263 IMAGES_ITER(BOOT_CURR_IMG(state)) {
David Vincze7384ee72019-07-23 17:00:42 +02002264
2265#if (BOOT_IMAGE_NUMBER > 1)
2266 /* Indicate that swap is not aborted */
2267 memset(&bs, 0, sizeof bs);
2268 bs.idx = BOOT_STATUS_IDX_0;
2269 bs.state = BOOT_STATUS_STATE_0;
2270#endif /* (BOOT_IMAGE_NUMBER > 1) */
2271
2272 /* Set the previously determined swap type */
David Vinczecea8b592019-10-29 16:09:51 +01002273 bs.swap_type = BOOT_SWAP_TYPE(state);
David Vincze7384ee72019-07-23 17:00:42 +02002274
David Vinczecea8b592019-10-29 16:09:51 +01002275 switch (BOOT_SWAP_TYPE(state)) {
David Vincze7384ee72019-07-23 17:00:42 +02002276 case BOOT_SWAP_TYPE_NONE:
2277 break;
2278
2279 case BOOT_SWAP_TYPE_TEST: /* fallthrough */
2280 case BOOT_SWAP_TYPE_PERM: /* fallthrough */
2281 case BOOT_SWAP_TYPE_REVERT:
David Vinczecea8b592019-10-29 16:09:51 +01002282 rc = boot_perform_update(state, &bs);
David Vincze7384ee72019-07-23 17:00:42 +02002283 assert(rc == 0);
2284 break;
2285
2286 case BOOT_SWAP_TYPE_FAIL:
2287 /* The image in secondary slot was invalid and is now erased. Ensure
2288 * we don't try to boot into it again on the next reboot. Do this by
2289 * pretending we just reverted back to primary slot.
2290 */
Tamas Banf70ef8c2017-12-19 15:35:09 +00002291#ifndef MCUBOOT_OVERWRITE_ONLY
David Vincze7384ee72019-07-23 17:00:42 +02002292 /* image_ok needs to be explicitly set to avoid a new revert. */
David Vinczecea8b592019-10-29 16:09:51 +01002293 rc = boot_set_image_ok(BOOT_CURR_IMG(state));
Tamas Banf70ef8c2017-12-19 15:35:09 +00002294 if (rc != 0) {
David Vinczecea8b592019-10-29 16:09:51 +01002295 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
Tamas Banf70ef8c2017-12-19 15:35:09 +00002296 }
2297#endif /* !MCUBOOT_OVERWRITE_ONLY */
David Vincze7384ee72019-07-23 17:00:42 +02002298 break;
2299
2300 default:
David Vinczecea8b592019-10-29 16:09:51 +01002301 BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
Tamas Banf70ef8c2017-12-19 15:35:09 +00002302 }
David Vincze7384ee72019-07-23 17:00:42 +02002303
David Vinczecea8b592019-10-29 16:09:51 +01002304 if (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_PANIC) {
David Vincze7384ee72019-07-23 17:00:42 +02002305 BOOT_LOG_ERR("panic!");
2306 assert(0);
2307
2308 /* Loop forever... */
2309 while (1) {}
2310 }
Tamas Banf70ef8c2017-12-19 15:35:09 +00002311 }
2312
David Vincze7384ee72019-07-23 17:00:42 +02002313 /* Iterate over all the images. At this point all required update operations
2314 * have finished. By the end of the loop each image in the primary slot will
2315 * have been re-validated.
2316 */
David Vinczecea8b592019-10-29 16:09:51 +01002317 IMAGES_ITER(BOOT_CURR_IMG(state)) {
2318 if (BOOT_SWAP_TYPE(state) != BOOT_SWAP_TYPE_NONE) {
David Vincze7384ee72019-07-23 17:00:42 +02002319 /* Attempt to read an image header from each slot. Ensure that image
2320 * headers in slots are aligned with headers in boot_data.
David Vincze060968d2019-05-23 01:13:14 +02002321 */
David Vinczecea8b592019-10-29 16:09:51 +01002322 rc = boot_read_image_headers(state, false);
David Vincze060968d2019-05-23 01:13:14 +02002323 if (rc != 0) {
David Vincze7384ee72019-07-23 17:00:42 +02002324 goto out;
2325 }
2326 /* Since headers were reloaded, it can be assumed we just performed
2327 * a swap or overwrite. Now the header info that should be used to
2328 * provide the data for the bootstrap, which previously was at
2329 * secondary slot, was updated to primary slot.
2330 */
2331 }
2332
2333#ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT
David Vinczecea8b592019-10-29 16:09:51 +01002334 rc = boot_validate_slot(state, BOOT_PRIMARY_SLOT, NULL);
David Vincze7384ee72019-07-23 17:00:42 +02002335 if (rc != 0) {
2336 rc = BOOT_EBADIMAGE;
2337 goto out;
2338 }
2339#else
2340 /* Even if we're not re-validating the primary slot, we could be booting
2341 * onto an empty flash chip. At least do a basic sanity check that
2342 * the magic number on the image is OK.
2343 */
David Vinczecea8b592019-10-29 16:09:51 +01002344 if (!BOOT_IMG_HDR_IS_VALID(state, BOOT_PRIMARY_SLOT)) {
2345 BOOT_LOG_ERR("bad image magic 0x%lx; Image=%u", (unsigned long)
2346 &boot_img_hdr(state, BOOT_PRIMARY_SLOT)->ih_magic,
2347 BOOT_CURR_IMG(state));
David Vincze7384ee72019-07-23 17:00:42 +02002348 rc = BOOT_EBADIMAGE;
2349 goto out;
2350 }
2351#endif /* MCUBOOT_VALIDATE_PRIMARY_SLOT */
2352
2353 /* Update the stored security counter with the active image's security
2354 * counter value. It will be updated only if the new security counter is
2355 * greater than the stored value.
2356 *
2357 * In case of a successful image swapping when the swap type is TEST the
2358 * security counter can be increased only after a reset, when the swap
2359 * type is NONE and the image has marked itself "OK" (the image_ok flag
2360 * has been set). This way a "revert" swap can be performed if it's
2361 * necessary.
2362 */
David Vinczecea8b592019-10-29 16:09:51 +01002363 if (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_NONE) {
2364 rc = boot_update_security_counter(
2365 BOOT_CURR_IMG(state),
2366 BOOT_PRIMARY_SLOT,
2367 boot_img_hdr(state, BOOT_PRIMARY_SLOT));
David Vincze7384ee72019-07-23 17:00:42 +02002368 if (rc != 0) {
2369 BOOT_LOG_ERR("Security counter update failed after image "
2370 "validation.");
David Vincze060968d2019-05-23 01:13:14 +02002371 goto out;
2372 }
2373 }
2374
David Vincze7384ee72019-07-23 17:00:42 +02002375 /* Save boot status to shared memory area */
2376#if (BOOT_IMAGE_NUMBER > 1)
David Vinczecea8b592019-10-29 16:09:51 +01002377 rc = boot_save_boot_status((BOOT_CURR_IMG(state) == 0) ?
2378 SW_SPE : SW_NSPE,
2379 boot_img_hdr(state, BOOT_PRIMARY_SLOT),
2380 BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT)
David Vincze7384ee72019-07-23 17:00:42 +02002381 );
David Vincze8bdfc2d2019-03-18 15:49:23 +01002382#else
David Vincze7384ee72019-07-23 17:00:42 +02002383 rc = boot_save_boot_status(SW_S_NS,
David Vinczecea8b592019-10-29 16:09:51 +01002384 boot_img_hdr(state, BOOT_PRIMARY_SLOT),
2385 BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT)
David Vincze7384ee72019-07-23 17:00:42 +02002386 );
2387#endif
2388 if (rc) {
2389 BOOT_LOG_ERR("Failed to add Image %u data to shared area",
David Vinczecea8b592019-10-29 16:09:51 +01002390 BOOT_CURR_IMG(state));
David Vincze060968d2019-05-23 01:13:14 +02002391 }
2392 }
2393
David Vinczecea8b592019-10-29 16:09:51 +01002394#if (BOOT_IMAGE_NUMBER > 1)
David Vincze7384ee72019-07-23 17:00:42 +02002395 /* Always boot from the primary slot of Image 0. */
David Vinczecea8b592019-10-29 16:09:51 +01002396 BOOT_CURR_IMG(state) = 0;
2397#endif
Tamas Ban0e8ab302019-01-17 11:45:31 +00002398
David Vinczecea8b592019-10-29 16:09:51 +01002399 rsp->br_flash_dev_id =
2400 BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT)->fa_device_id;
2401 rsp->br_image_off =
2402 boot_img_slot_off(state, BOOT_PRIMARY_SLOT);
2403 rsp->br_hdr =
2404 boot_img_hdr(state, BOOT_PRIMARY_SLOT);
2405
2406out:
2407 IMAGES_ITER(BOOT_CURR_IMG(state)) {
2408 flash_area_close(BOOT_SCRATCH_AREA(state));
David Vincze7384ee72019-07-23 17:00:42 +02002409 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
David Vinczecea8b592019-10-29 16:09:51 +01002410 flash_area_close(BOOT_IMG_AREA(state,
David Vincze7384ee72019-07-23 17:00:42 +02002411 BOOT_NUM_SLOTS - 1 - slot));
2412 }
Tamas Banf70ef8c2017-12-19 15:35:09 +00002413 }
2414 return rc;
2415}
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002416
Oliver Swedef9982442018-08-24 18:37:44 +01002417#else /* MCUBOOT_NO_SWAP || MCUBOOT_RAM_LOADING */
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002418
David Vinczedcba70b2019-05-28 12:02:52 +02002419#define BOOT_LOG_IMAGE_INFO(area, hdr, state) \
2420 BOOT_LOG_INF("Image %u: version=%u.%u.%u+%u, magic=%5s, image_ok=0x%x", \
2421 (area), \
2422 (hdr)->ih_ver.iv_major, \
2423 (hdr)->ih_ver.iv_minor, \
2424 (hdr)->ih_ver.iv_revision, \
2425 (hdr)->ih_ver.iv_build_num, \
2426 ((state)->magic == BOOT_MAGIC_GOOD ? "good" : \
2427 (state)->magic == BOOT_MAGIC_UNSET ? "unset" : \
2428 "bad"), \
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002429 (state)->image_ok)
2430
2431struct image_slot_version {
2432 uint64_t version;
2433 uint32_t slot_number;
2434};
2435
2436/**
2437 * Extract the version number from the image header. This function must be
2438 * ported if version number format has changed in the image header.
2439 *
2440 * @param hdr Pointer to an image header structure
2441 *
Oliver Swedef9982442018-08-24 18:37:44 +01002442 * @return Version number casted to uint64_t
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002443 */
2444static uint64_t
2445boot_get_version_number(struct image_header *hdr)
2446{
Oliver Swedef9982442018-08-24 18:37:44 +01002447 uint64_t version = 0;
2448 version |= (uint64_t)hdr->ih_ver.iv_major << (IMAGE_VER_MINOR_LENGTH
2449 + IMAGE_VER_REVISION_LENGTH
2450 + IMAGE_VER_BUILD_NUM_LENGTH);
2451 version |= (uint64_t)hdr->ih_ver.iv_minor << (IMAGE_VER_REVISION_LENGTH
2452 + IMAGE_VER_BUILD_NUM_LENGTH);
2453 version |= (uint64_t)hdr->ih_ver.iv_revision << IMAGE_VER_BUILD_NUM_LENGTH;
2454 version |= hdr->ih_ver.iv_build_num;
2455 return version;
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002456}
2457
2458/**
2459 * Comparator function for `qsort` to compare version numbers. This function
2460 * must be ported if version number format has changed in the image header.
2461 *
2462 * @param ver1 Pointer to an array element which holds the version number
2463 * @param ver2 Pointer to another array element which holds the version
2464 * number
2465 *
2466 * @return if version1 > version2 -1
2467 * if version1 == version2 0
2468 * if version1 < version2 1
2469 */
2470static int
2471boot_compare_version_numbers(const void *ver1, const void *ver2)
2472{
2473 if (((struct image_slot_version *)ver1)->version <
2474 ((struct image_slot_version *)ver2)->version) {
2475 return 1;
2476 }
2477
2478 if (((struct image_slot_version *)ver1)->version ==
2479 ((struct image_slot_version *)ver2)->version) {
2480 return 0;
2481 }
2482
2483 return -1;
2484}
2485
2486/**
2487 * Sort the available images based on the version number and puts them in
2488 * a list.
2489 *
David Vinczecea8b592019-10-29 16:09:51 +01002490 * @param state Boot loader status information.
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002491 * @param boot_sequence A pointer to an array, whose aim is to carry
2492 * the boot order of candidate images.
2493 * @param slot_cnt The number of flash areas, which can contains firmware
2494 * images.
2495 *
2496 * @return The number of valid images.
2497 */
2498uint32_t
David Vinczecea8b592019-10-29 16:09:51 +01002499boot_get_boot_sequence(struct boot_loader_state *state,
2500 uint32_t *boot_sequence, uint32_t slot_cnt)
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002501{
2502 struct boot_swap_state slot_state;
2503 struct image_header *hdr;
2504 struct image_slot_version image_versions[BOOT_NUM_SLOTS] = {{0}};
2505 uint32_t image_cnt = 0;
2506 uint32_t slot;
2507 int32_t rc;
2508 int32_t fa_id;
2509
2510 for (slot = 0; slot < slot_cnt; slot++) {
David Vinczecea8b592019-10-29 16:09:51 +01002511 hdr = boot_img_hdr(state, slot);
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002512 fa_id = flash_area_id_from_image_slot(slot);
2513 rc = boot_read_swap_state_by_id(fa_id, &slot_state);
2514 if (rc != 0) {
David Vinczedcba70b2019-05-28 12:02:52 +02002515 BOOT_LOG_ERR("Error during reading image trailer from slot: %u",
2516 slot);
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002517 continue;
2518 }
2519
David Vinczecea8b592019-10-29 16:09:51 +01002520 if (BOOT_IMG_HDR_IS_VALID(state, slot)) {
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002521 if (slot_state.magic == BOOT_MAGIC_GOOD ||
David Vincze39e78552018-10-10 17:10:01 +02002522 slot_state.image_ok == BOOT_FLAG_SET) {
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002523 /* Valid cases:
2524 * - Test mode: magic is OK in image trailer
2525 * - Permanent mode: image_ok flag has previously set
2526 */
2527 image_versions[slot].slot_number = slot;
2528 image_versions[slot].version = boot_get_version_number(hdr);
2529 image_cnt++;
2530 }
2531
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002532 BOOT_LOG_IMAGE_INFO(slot, hdr, &slot_state);
2533 } else {
David Vinczedcba70b2019-05-28 12:02:52 +02002534 BOOT_LOG_INF("Image %u: No valid image", slot);
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002535 }
2536 }
2537
2538 /* Sort the images based on version number */
2539 qsort(&image_versions[0],
2540 slot_cnt,
2541 sizeof(struct image_slot_version),
2542 boot_compare_version_numbers);
2543
2544 /* Copy the calculated boot sequence to boot_sequence array */
2545 for (slot = 0; slot < slot_cnt; slot++) {
2546 boot_sequence[slot] = image_versions[slot].slot_number;
2547 }
2548
2549 return image_cnt;
2550}
2551
Oliver Swedef9982442018-08-24 18:37:44 +01002552#ifdef MCUBOOT_RAM_LOADING
Raef Colesaf082382019-10-01 11:10:33 +01002553
2554/**
2555 * Verifies that the image in a slot lies within the predefined bounds that are
2556 * allowed to be used by executable images.
2557 *
2558 * @param img_dst The address to which the image is going to be copied.
2559 *
2560 * @param img_sz The size of the image.
2561 *
2562 * @return 0 on success; nonzero on failure.
2563 */
2564static int
2565boot_verify_ram_loading_address(uint32_t img_dst, uint32_t img_sz)
2566{
2567 if (img_dst < IMAGE_EXECUTABLE_RAM_START) {
2568 return BOOT_EBADIMAGE;
2569 }
2570
2571 if (boot_add_uint32_overflow_check(img_dst, img_sz)) {
2572 return BOOT_EBADIMAGE;
2573 }
2574
2575 if (img_dst + img_sz > IMAGE_EXECUTABLE_RAM_START +
2576 IMAGE_EXECUTABLE_RAM_SIZE) {
2577 return BOOT_EBADIMAGE;
2578 }
2579
2580 return 0;
2581}
2582
Oliver Swedef9982442018-08-24 18:37:44 +01002583/**
2584 * Copies an image from a slot in the flash to an SRAM address, where the load
2585 * address has already been inserted into the image header by this point and is
2586 * extracted from it within this method. The copying is done sector-by-sector.
2587 *
David Vinczecea8b592019-10-29 16:09:51 +01002588 * @param state Boot loader status information.
Oliver Swedef9982442018-08-24 18:37:44 +01002589 * @param slot The flash slot of the image to be copied to SRAM.
2590 *
2591 * @param hdr Pointer to the image header structure of the image
Raef Colesaf082382019-10-01 11:10:33 +01002592 *
2593 * @param img_dst The address at which the image needs to be copied to
2594 * SRAM.
2595 *
2596 * @param img_sz The size of the image that needs to be copied to SRAM.
Oliver Swedef9982442018-08-24 18:37:44 +01002597 *
2598 * @return 0 on success; nonzero on failure.
2599 */
2600static int
David Vinczecea8b592019-10-29 16:09:51 +01002601boot_copy_image_to_sram(struct boot_loader_state *state, int slot,
2602 struct image_header *hdr,
Raef Colesaf082382019-10-01 11:10:33 +01002603 uint32_t img_dst, uint32_t img_sz)
Oliver Swedef9982442018-08-24 18:37:44 +01002604{
2605 int rc;
2606 uint32_t sect_sz;
2607 uint32_t sect = 0;
2608 uint32_t bytes_copied = 0;
2609 const struct flash_area *fap_src = NULL;
Oliver Swedef9982442018-08-24 18:37:44 +01002610
Raef Colesaf082382019-10-01 11:10:33 +01002611 if (img_dst % 4 != 0) {
Tamas Banc27b5c32019-05-28 16:30:19 +01002612 BOOT_LOG_INF("Cannot copy the image to the SRAM address 0x%x "
Oliver Swedef9982442018-08-24 18:37:44 +01002613 "- the load address must be aligned with 4 bytes due to SRAM "
Raef Colesaf082382019-10-01 11:10:33 +01002614 "restrictions", img_dst);
Oliver Swedef9982442018-08-24 18:37:44 +01002615 return BOOT_EBADARGS;
2616 }
2617
2618 rc = flash_area_open(flash_area_id_from_image_slot(slot), &fap_src);
2619 if (rc != 0) {
2620 return BOOT_EFLASH;
2621 }
2622
Oliver Swedef9982442018-08-24 18:37:44 +01002623 while (bytes_copied < img_sz) {
David Vinczecea8b592019-10-29 16:09:51 +01002624 sect_sz = boot_img_sector_size(state, slot, sect);
Oliver Swedef9982442018-08-24 18:37:44 +01002625 /*
2626 * Direct copy from where the image sector resides in flash to its new
2627 * location in SRAM
2628 */
2629 rc = flash_area_read(fap_src,
2630 bytes_copied,
Raef Colesaf082382019-10-01 11:10:33 +01002631 (void *)(img_dst + bytes_copied),
Oliver Swedef9982442018-08-24 18:37:44 +01002632 sect_sz);
2633 if (rc != 0) {
2634 BOOT_LOG_INF("Error whilst copying image from Flash to SRAM");
2635 break;
2636 } else {
2637 bytes_copied += sect_sz;
2638 }
2639 sect++;
2640 }
2641
2642 if (fap_src) {
2643 flash_area_close(fap_src);
2644 }
2645 return rc;
2646}
Raef Coles27a61452019-09-25 15:32:25 +01002647
2648/**
2649 * Removes an image from SRAM, by overwriting it with zeros.
2650 *
Raef Colesaf082382019-10-01 11:10:33 +01002651 * @param img_dst The address of the image that needs to be removed from
2652 * SRAM.
Raef Coles27a61452019-09-25 15:32:25 +01002653 *
Raef Colesaf082382019-10-01 11:10:33 +01002654 * @param img_sz The size of the image that needs to be removed from
2655 * SRAM.
Raef Coles27a61452019-09-25 15:32:25 +01002656 *
2657 * @return 0 on success; nonzero on failure.
2658 */
2659static int
Raef Colesaf082382019-10-01 11:10:33 +01002660boot_remove_image_from_sram(uint32_t img_dst, uint32_t img_sz)
Raef Coles27a61452019-09-25 15:32:25 +01002661{
Raef Colesaf082382019-10-01 11:10:33 +01002662 BOOT_LOG_INF("Removing image from SRAM at address 0x%x", img_dst);
2663 memset((void*)img_dst, 0, img_sz);
Raef Coles27a61452019-09-25 15:32:25 +01002664
2665 return 0;
2666}
Oliver Swedef9982442018-08-24 18:37:44 +01002667#endif /* MCUBOOT_RAM_LOADING */
2668
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002669/**
2670 * Prepares the booting process. This function choose the newer image in flash
David Vinczecea8b592019-10-29 16:09:51 +01002671 * as appropriate, and tells you what address to boot from.
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002672 *
David Vinczecea8b592019-10-29 16:09:51 +01002673 * @param state Boot loader status information.
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002674 * @param rsp On success, indicates how booting should occur.
2675 *
2676 * @return 0 on success; nonzero on failure.
2677 */
2678int
David Vinczecea8b592019-10-29 16:09:51 +01002679context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp)
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002680{
2681 size_t slot = 0;
2682 int32_t i;
2683 int rc;
2684 int fa_id;
2685 uint32_t boot_sequence[BOOT_NUM_SLOTS];
2686 uint32_t img_cnt;
Raef Coles27a61452019-09-25 15:32:25 +01002687 struct image_header *selected_image_header;
2688#ifdef MCUBOOT_RAM_LOADING
2689 int image_copied = 0;
Raef Colesaf082382019-10-01 11:10:33 +01002690 uint32_t img_dst = 0;
2691 uint32_t img_sz = 0;
Raef Coles27a61452019-09-25 15:32:25 +01002692#endif /* MCUBOOT_RAM_LOADING */
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002693
David Vincze8bdfc2d2019-03-18 15:49:23 +01002694 static boot_sector_t primary_slot_sectors[BOOT_MAX_IMG_SECTORS];
2695 static boot_sector_t secondary_slot_sectors[BOOT_MAX_IMG_SECTORS];
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002696
David Vinczecea8b592019-10-29 16:09:51 +01002697 BOOT_IMG(state, BOOT_PRIMARY_SLOT).sectors = &primary_slot_sectors[0];
2698 BOOT_IMG(state, BOOT_SECONDARY_SLOT).sectors = &secondary_slot_sectors[0];
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002699
2700 /* Open boot_data image areas for the duration of this call. */
2701 for (i = 0; i < BOOT_NUM_SLOTS; i++) {
2702 fa_id = flash_area_id_from_image_slot(i);
David Vinczecea8b592019-10-29 16:09:51 +01002703 rc = flash_area_open(fa_id, &BOOT_IMG_AREA(state, i));
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002704 assert(rc == 0);
2705 }
2706
2707 /* Determine the sector layout of the image slots. */
David Vinczecea8b592019-10-29 16:09:51 +01002708 rc = boot_read_sectors(state);
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002709 if (rc != 0) {
David Vinczecea8b592019-10-29 16:09:51 +01002710 BOOT_LOG_WRN("Failed reading sectors; BOOT_MAX_IMG_SECTORS=%d - "
2711 "too small?", BOOT_MAX_IMG_SECTORS);
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002712 goto out;
2713 }
2714
2715 /* Attempt to read an image header from each slot. */
David Vinczecea8b592019-10-29 16:09:51 +01002716 rc = boot_read_image_headers(state, false);
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002717 if (rc != 0) {
2718 goto out;
2719 }
2720
David Vinczecea8b592019-10-29 16:09:51 +01002721 img_cnt = boot_get_boot_sequence(state, boot_sequence, BOOT_NUM_SLOTS);
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002722 if (img_cnt) {
2723 /* Authenticate images */
2724 for (i = 0; i < img_cnt; i++) {
Raef Coles27a61452019-09-25 15:32:25 +01002725
2726 slot = boot_sequence[i];
David Vinczecea8b592019-10-29 16:09:51 +01002727 selected_image_header = boot_img_hdr(state, slot);
Raef Coles27a61452019-09-25 15:32:25 +01002728
2729#ifdef MCUBOOT_RAM_LOADING
2730 if (selected_image_header->ih_flags & IMAGE_F_RAM_LOAD) {
Raef Colesaf082382019-10-01 11:10:33 +01002731
2732 img_dst = selected_image_header->ih_load_addr;
2733
David Vinczecea8b592019-10-29 16:09:51 +01002734 rc = boot_read_image_size(state, slot, &img_sz);
Raef Colesaf082382019-10-01 11:10:33 +01002735 if (rc != 0) {
2736 rc = BOOT_EFLASH;
2737 BOOT_LOG_INF("Could not load image headers from the image"
2738 "in the %s slot.",
2739 (slot == BOOT_PRIMARY_SLOT) ?
2740 "primary" : "secondary");
2741 continue;
2742 }
2743
2744 rc = boot_verify_ram_loading_address(img_dst, img_sz);
2745 if (rc != 0) {
2746 BOOT_LOG_INF("Could not copy image from the %s slot in "
2747 "the Flash to load address 0x%x in SRAM as"
2748 " the image would overlap memory outside"
2749 " the defined executable region.",
2750 (slot == BOOT_PRIMARY_SLOT) ?
2751 "primary" : "secondary",
2752 selected_image_header->ih_load_addr);
2753 continue;
2754 }
2755
Raef Coles27a61452019-09-25 15:32:25 +01002756 /* Copy image to the load address from where it
2757 * currently resides in flash
2758 */
David Vinczecea8b592019-10-29 16:09:51 +01002759 rc = boot_copy_image_to_sram(state, slot, selected_image_header,
Raef Colesaf082382019-10-01 11:10:33 +01002760 img_dst, img_sz);
Raef Coles27a61452019-09-25 15:32:25 +01002761 if (rc != 0) {
2762 rc = BOOT_EBADIMAGE;
2763 BOOT_LOG_INF("Could not copy image from the %s slot in "
2764 "the Flash to load address 0x%x in SRAM, "
2765 "aborting..", (slot == BOOT_PRIMARY_SLOT) ?
2766 "primary" : "secondary",
2767 selected_image_header->ih_load_addr);
2768 continue;
2769 } else {
2770 BOOT_LOG_INF("Image has been copied from the %s slot in "
2771 "the flash to SRAM address 0x%x",
2772 (slot == BOOT_PRIMARY_SLOT) ?
2773 "primary" : "secondary",
2774 selected_image_header->ih_load_addr);
2775 image_copied = 1;
2776 }
2777 } else {
2778 /* Only images that support IMAGE_F_RAM_LOAD are allowed if
2779 * MCUBOOT_RAM_LOADING is set.
2780 */
2781 rc = BOOT_EBADIMAGE;
2782 continue;
2783 }
2784#endif /* MCUBOOT_RAM_LOADING */
David Vinczecea8b592019-10-29 16:09:51 +01002785 rc = boot_validate_slot(state, slot, NULL);
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002786 if (rc == 0) {
Raef Coles27a61452019-09-25 15:32:25 +01002787 /* If a valid image is found then there is no reason to check
2788 * the rest of the images, as they were already ordered by
2789 * preference.
2790 */
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002791 break;
2792 }
Raef Coles27a61452019-09-25 15:32:25 +01002793#ifdef MCUBOOT_RAM_LOADING
2794 else if (image_copied) {
2795 /* If an image is found to be invalid then it is removed from
2796 * RAM to prevent it being a shellcode vector.
2797 */
Raef Colesaf082382019-10-01 11:10:33 +01002798 boot_remove_image_from_sram(img_dst, img_sz);
Raef Coles27a61452019-09-25 15:32:25 +01002799 image_copied = 0;
2800 }
2801#endif /* MCUBOOT_RAM_LOADING */
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002802 }
2803 if (rc) {
2804 /* If there was no valid image at all */
2805 rc = BOOT_EBADIMAGE;
2806 goto out;
2807 }
2808
David Vincze060968d2019-05-23 01:13:14 +02002809 /* Update the security counter with the newest image's security
2810 * counter value.
2811 */
David Vinczecea8b592019-10-29 16:09:51 +01002812 rc = boot_update_security_counter(BOOT_CURR_IMG(state), slot,
2813 selected_image_header);
David Vincze060968d2019-05-23 01:13:14 +02002814 if (rc != 0) {
2815 BOOT_LOG_ERR("Security counter update failed after image "
2816 "validation.");
2817 goto out;
2818 }
2819
Oliver Swedef9982442018-08-24 18:37:44 +01002820
David Vincze8a2a4e22019-05-24 10:14:23 +02002821#ifdef MCUBOOT_RAM_LOADING
Raef Coles27a61452019-09-25 15:32:25 +01002822 BOOT_LOG_INF("Booting image from SRAM at address 0x%x",
2823 selected_image_header->ih_load_addr);
2824#else
2825 BOOT_LOG_INF("Booting image from the %s slot",
2826 (slot == BOOT_PRIMARY_SLOT) ? "primary" : "secondary");
2827#endif /* MCUBOOT_RAM_LOADING */
Oliver Swedef9982442018-08-24 18:37:44 +01002828
Raef Coles27a61452019-09-25 15:32:25 +01002829 rsp->br_hdr = selected_image_header;
David Vinczecea8b592019-10-29 16:09:51 +01002830 rsp->br_image_off = boot_img_slot_off(state, slot);
2831 rsp->br_flash_dev_id = BOOT_IMG_AREA(state, slot)->fa_device_id;
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002832 } else {
2833 /* No candidate image available */
2834 rc = BOOT_EBADIMAGE;
David Vincze060968d2019-05-23 01:13:14 +02002835 goto out;
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002836 }
2837
Tamas Ban0e8ab302019-01-17 11:45:31 +00002838 /* Save boot status to shared memory area */
2839 rc = boot_save_boot_status(SW_S_NS,
2840 rsp->br_hdr,
David Vinczecea8b592019-10-29 16:09:51 +01002841 BOOT_IMG_AREA(state, slot));
Tamas Ban0e8ab302019-01-17 11:45:31 +00002842 if (rc) {
2843 BOOT_LOG_ERR("Failed to add data to shared area");
2844 }
2845
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002846out:
2847 for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
David Vinczecea8b592019-10-29 16:09:51 +01002848 flash_area_close(BOOT_IMG_AREA(state, BOOT_NUM_SLOTS - 1 - slot));
Tamas Ban4fb8e9d2018-02-23 14:22:03 +00002849 }
2850 return rc;
2851}
Oliver Swedef9982442018-08-24 18:37:44 +01002852#endif /* MCUBOOT_NO_SWAP || MCUBOOT_RAM_LOADING */
David Vinczecea8b592019-10-29 16:09:51 +01002853
2854int
2855boot_go(struct boot_rsp *rsp)
2856{
2857 return context_boot_go(&boot_data, rsp);
2858}