1 /*
2 * SPDX-License-Identifier: Apache-2.0
3 *
4 * Copyright (c) 2017-2019 Linaro LTD
5 * Copyright (c) 2016-2019 JUUL Labs
6 * Copyright (c) 2019-2023 Arm Limited
7 * Copyright (c) 2020-2025 Nordic Semiconductor ASA
8 *
9 * Original license:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one
12 * or more contributor license agreements. See the NOTICE file
13 * distributed with this work for additional information
14 * regarding copyright ownership. The ASF licenses this file
15 * to you under the Apache License, Version 2.0 (the
16 * "License"); you may not use this file except in compliance
17 * with the License. You may obtain a copy of the License at
18 *
19 * http://www.apache.org/licenses/LICENSE-2.0
20 *
21 * Unless required by applicable law or agreed to in writing,
22 * software distributed under the License is distributed on an
23 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
24 * KIND, either express or implied. See the License for the
25 * specific language governing permissions and limitations
26 * under the License.
27 */
28
29 /**
30 * @file
31 * @brief Public MCUBoot interface API implementation
32 *
33 * This file contains API implementation which can be combined with
34 * the application in order to interact with the MCUBoot bootloader.
35 * This file contains shared code-base betwen MCUBoot and the application
36 * which controls DFU process.
37 */
38
39 #include <string.h>
40 #include <inttypes.h>
41 #include <stddef.h>
42
43 #include "sysflash/sysflash.h"
44 #include "flash_map_backend/flash_map_backend.h"
45
46 #include "bootutil/image.h"
47 #include "bootutil/bootutil_public.h"
48 #include "bootutil/bootutil_log.h"
49
50 #include "bootutil/boot_public_hooks.h"
51 #include "bootutil_priv.h"
52 #include "bootutil_misc.h"
53
54 #ifdef CONFIG_MCUBOOT
55 BOOT_LOG_MODULE_DECLARE(mcuboot);
56 #else
57 BOOT_LOG_MODULE_REGISTER(mcuboot_util);
58 #endif
59
60 #if BOOT_MAX_ALIGN == 8
61 const union boot_img_magic_t boot_img_magic = {
62 .val = {
63 0x77, 0xc2, 0x95, 0xf3,
64 0x60, 0xd2, 0xef, 0x7f,
65 0x35, 0x52, 0x50, 0x0f,
66 0x2c, 0xb6, 0x79, 0x80
67 }
68 };
69 #else
70 const union boot_img_magic_t boot_img_magic = {
71 .align = BOOT_MAX_ALIGN,
72 .magic = {
73 0x2d, 0xe1,
74 0x5d, 0x29, 0x41, 0x0b,
75 0x8d, 0x77, 0x67, 0x9c,
76 0x11, 0x0f, 0x1f, 0x8a
77 }
78 };
79 #endif
80
81 struct boot_swap_table {
82 uint8_t magic_primary_slot;
83 uint8_t magic_secondary_slot;
84 uint8_t image_ok_primary_slot;
85 uint8_t image_ok_secondary_slot;
86 uint8_t copy_done_primary_slot;
87 #if defined(MCUBOOT_SWAP_USING_OFFSET)
88 uint8_t copy_done_secondary_slot;
89 #endif
90
91 uint8_t swap_type;
92 };
93
94 /**
95 * This set of tables maps image trailer contents to swap operation type.
96 * When searching for a match, these tables must be iterated sequentially.
97 *
98 * NOTE: the table order is very important. The settings in the secondary
99 * slot always are priority to the primary slot and should be located
100 * earlier in the table.
101 *
102 * The table lists only states where there is action needs to be taken by
103 * the bootloader, as in starting/finishing a swap operation.
104 */
105 static const struct boot_swap_table boot_swap_tables[] = {
106 #if defined(MCUBOOT_SWAP_USING_OFFSET)
107 {
108 .magic_primary_slot = BOOT_MAGIC_ANY,
109 .magic_secondary_slot = BOOT_MAGIC_GOOD,
110 .image_ok_primary_slot = BOOT_FLAG_ANY,
111 .image_ok_secondary_slot = BOOT_FLAG_UNSET,
112 .copy_done_primary_slot = BOOT_FLAG_ANY,
113 .copy_done_secondary_slot = BOOT_FLAG_SET,
114 .swap_type = BOOT_SWAP_TYPE_REVERT,
115 },
116 #endif
117 {
118 .magic_primary_slot = BOOT_MAGIC_ANY,
119 .magic_secondary_slot = BOOT_MAGIC_GOOD,
120 .image_ok_primary_slot = BOOT_FLAG_ANY,
121 .image_ok_secondary_slot = BOOT_FLAG_UNSET,
122 .copy_done_primary_slot = BOOT_FLAG_ANY,
123 #if defined(MCUBOOT_SWAP_USING_OFFSET)
124 .copy_done_secondary_slot = BOOT_FLAG_ANY,
125 #endif
126 .swap_type = BOOT_SWAP_TYPE_TEST,
127 },
128 {
129 .magic_primary_slot = BOOT_MAGIC_ANY,
130 .magic_secondary_slot = BOOT_MAGIC_GOOD,
131 .image_ok_primary_slot = BOOT_FLAG_ANY,
132 .image_ok_secondary_slot = BOOT_FLAG_SET,
133 .copy_done_primary_slot = BOOT_FLAG_ANY,
134 #if defined(MCUBOOT_SWAP_USING_OFFSET)
135 .copy_done_secondary_slot = BOOT_FLAG_ANY,
136 #endif
137 .swap_type = BOOT_SWAP_TYPE_PERM,
138 },
139 {
140 .magic_primary_slot = BOOT_MAGIC_GOOD,
141 .magic_secondary_slot = BOOT_MAGIC_ANY,
142 .image_ok_primary_slot = BOOT_FLAG_UNSET,
143 .image_ok_secondary_slot = BOOT_FLAG_ANY,
144 .copy_done_primary_slot = BOOT_FLAG_SET,
145 #if defined(MCUBOOT_SWAP_USING_OFFSET)
146 .copy_done_secondary_slot = BOOT_FLAG_ANY,
147 #endif
148 .swap_type = BOOT_SWAP_TYPE_REVERT,
149 },
150 };
151
152 #define BOOT_SWAP_TABLES_COUNT \
153 (sizeof boot_swap_tables / sizeof boot_swap_tables[0])
154
155 static int
boot_flag_decode(uint8_t flag)156 boot_flag_decode(uint8_t flag)
157 {
158 if (flag != BOOT_FLAG_SET) {
159 return BOOT_FLAG_BAD;
160 }
161 return BOOT_FLAG_SET;
162 }
163
164 uint32_t
boot_swap_info_off(const struct flash_area * fap)165 boot_swap_info_off(const struct flash_area *fap)
166 {
167 return boot_copy_done_off(fap) - BOOT_MAX_ALIGN;
168 }
169
170 /**
171 * Determines if a status source table is satisfied by the specified magic
172 * code.
173 *
174 * @param tbl_val A magic field from a status source table.
175 * @param val The magic value in a trailer, encoded as a
176 * BOOT_MAGIC_[...].
177 *
178 * @return 1 if the two values are compatible;
179 * 0 otherwise.
180 */
181 int
boot_magic_compatible_check(uint8_t tbl_val,uint8_t val)182 boot_magic_compatible_check(uint8_t tbl_val, uint8_t val)
183 {
184 switch (tbl_val) {
185 case BOOT_MAGIC_ANY:
186 return 1;
187
188 case BOOT_MAGIC_NOTGOOD:
189 return val != BOOT_MAGIC_GOOD;
190
191 default:
192 return tbl_val == val;
193 }
194 }
195
bootutil_buffer_is_erased(const struct flash_area * area,const void * buffer,size_t len)196 bool bootutil_buffer_is_erased(const struct flash_area *area,
197 const void *buffer, size_t len)
198 {
199 size_t i;
200 uint8_t *u8b;
201 uint8_t erased_val;
202
203 if (buffer == NULL || len == 0) {
204 return false;
205 }
206
207 erased_val = flash_area_erased_val(area);
208 for (i = 0, u8b = (uint8_t *)buffer; i < len; i++) {
209 if (u8b[i] != erased_val) {
210 return false;
211 }
212 }
213
214 return true;
215 }
216
217 static int
boot_read_flag(const struct flash_area * fap,uint8_t * flag,uint32_t off)218 boot_read_flag(const struct flash_area *fap, uint8_t *flag, uint32_t off)
219 {
220 int rc;
221
222 rc = flash_area_read(fap, off, flag, sizeof *flag);
223 if (rc < 0) {
224 return BOOT_EFLASH;
225 }
226 if (bootutil_buffer_is_erased(fap, flag, sizeof *flag)) {
227 *flag = BOOT_FLAG_UNSET;
228 } else {
229 *flag = boot_flag_decode(*flag);
230 }
231
232 return 0;
233 }
234
235 static inline int
boot_read_copy_done(const struct flash_area * fap,uint8_t * copy_done)236 boot_read_copy_done(const struct flash_area *fap, uint8_t *copy_done)
237 {
238 return boot_read_flag(fap, copy_done, boot_copy_done_off(fap));
239 }
240
241
242 int
boot_read_swap_state(const struct flash_area * fap,struct boot_swap_state * state)243 boot_read_swap_state(const struct flash_area *fap,
244 struct boot_swap_state *state)
245 {
246 uint8_t magic[BOOT_MAGIC_SZ];
247 uint32_t off;
248 uint8_t swap_info;
249 int rc;
250
251 off = boot_magic_off(fap);
252 rc = flash_area_read(fap, off, magic, BOOT_MAGIC_SZ);
253 if (rc < 0) {
254 return BOOT_EFLASH;
255 }
256 if (bootutil_buffer_is_erased(fap, magic, BOOT_MAGIC_SZ)) {
257 state->magic = BOOT_MAGIC_UNSET;
258 } else {
259 state->magic = boot_magic_decode(magic);
260 }
261
262 off = boot_swap_info_off(fap);
263 rc = flash_area_read(fap, off, &swap_info, sizeof swap_info);
264 if (rc < 0) {
265 return BOOT_EFLASH;
266 }
267
268 /* Extract the swap type and image number */
269 state->swap_type = BOOT_GET_SWAP_TYPE(swap_info);
270 state->image_num = BOOT_GET_IMAGE_NUM(swap_info);
271
272 if (bootutil_buffer_is_erased(fap, &swap_info, sizeof swap_info) ||
273 state->swap_type > BOOT_SWAP_TYPE_REVERT) {
274 state->swap_type = BOOT_SWAP_TYPE_NONE;
275 state->image_num = 0;
276 }
277
278 rc = boot_read_copy_done(fap, &state->copy_done);
279 if (rc) {
280 return BOOT_EFLASH;
281 }
282
283 return boot_read_image_ok(fap, &state->image_ok);
284 }
285
286 int
boot_read_swap_state_by_id(int flash_area_id,struct boot_swap_state * state)287 boot_read_swap_state_by_id(int flash_area_id, struct boot_swap_state *state)
288 {
289 const struct flash_area *fap;
290 int rc;
291
292 rc = flash_area_open(flash_area_id, &fap);
293 if (rc != 0) {
294 return BOOT_EFLASH;
295 }
296
297 rc = boot_read_swap_state(fap, state);
298 flash_area_close(fap);
299 return rc;
300 }
301
302 int
boot_write_magic(const struct flash_area * fap)303 boot_write_magic(const struct flash_area *fap)
304 {
305 uint32_t off;
306 uint32_t pad_off;
307 int rc;
308 uint8_t magic[BOOT_MAGIC_ALIGN_SIZE];
309 uint8_t erased_val;
310
311 off = boot_magic_off(fap);
312
313 /* image_trailer structure was modified with additional padding such that
314 * the pad+magic ends up in a flash minimum write region. The address
315 * returned by boot_magic_off() is the start of magic which is not the
316 * start of the flash write boundary and thus writes to the magic will fail.
317 * To account for this change, write to magic is first padded with 0xFF
318 * before writing to the trailer.
319 */
320 pad_off = ALIGN_DOWN(off, BOOT_MAX_ALIGN);
321
322 erased_val = flash_area_erased_val(fap);
323
324 memset(&magic[0], erased_val, sizeof(magic));
325 memcpy(&magic[BOOT_MAGIC_ALIGN_SIZE - BOOT_MAGIC_SZ], BOOT_IMG_MAGIC, BOOT_MAGIC_SZ);
326
327 BOOT_LOG_DBG("writing magic; fa_id=%d off=0x%lx (0x%lx)",
328 flash_area_get_id(fap), (unsigned long)off,
329 (unsigned long)(flash_area_get_off(fap) + off));
330 rc = flash_area_write(fap, pad_off, &magic[0], BOOT_MAGIC_ALIGN_SIZE);
331
332 if (rc != 0) {
333 return BOOT_EFLASH;
334 }
335
336 return 0;
337 }
338
339 /**
340 * Write trailer data; status bytes, swap_size, etc
341 *
342 * @returns 0 on success, != 0 on error.
343 */
344 int
boot_write_trailer(const struct flash_area * fap,uint32_t off,const uint8_t * inbuf,uint8_t inlen)345 boot_write_trailer(const struct flash_area *fap, uint32_t off,
346 const uint8_t *inbuf, uint8_t inlen)
347 {
348 uint8_t buf[BOOT_MAX_ALIGN];
349 uint8_t erased_val;
350 uint32_t align;
351 int rc;
352
353 align = flash_area_align(fap);
354 align = ALIGN_UP(inlen, align);
355 if (align > BOOT_MAX_ALIGN) {
356 return -1;
357 }
358 erased_val = flash_area_erased_val(fap);
359
360 memcpy(buf, inbuf, inlen);
361 memset(&buf[inlen], erased_val, align - inlen);
362
363 rc = flash_area_write(fap, off, buf, align);
364 if (rc != 0) {
365 return BOOT_EFLASH;
366 }
367
368 return 0;
369 }
370
371 int
boot_write_trailer_flag(const struct flash_area * fap,uint32_t off,uint8_t flag_val)372 boot_write_trailer_flag(const struct flash_area *fap, uint32_t off,
373 uint8_t flag_val)
374 {
375 const uint8_t buf[1] = { flag_val };
376 return boot_write_trailer(fap, off, buf, 1);
377 }
378
379 int
boot_write_image_ok(const struct flash_area * fap)380 boot_write_image_ok(const struct flash_area *fap)
381 {
382 uint32_t off;
383
384 off = boot_image_ok_off(fap);
385 BOOT_LOG_DBG("writing image_ok; fa_id=%d off=0x%lx (0x%lx)",
386 flash_area_get_id(fap), (unsigned long)off,
387 (unsigned long)(flash_area_get_off(fap) + off));
388 return boot_write_trailer_flag(fap, off, BOOT_FLAG_SET);
389 }
390
391 int
boot_read_image_ok(const struct flash_area * fap,uint8_t * image_ok)392 boot_read_image_ok(const struct flash_area *fap, uint8_t *image_ok)
393 {
394 return boot_read_flag(fap, image_ok, boot_image_ok_off(fap));
395 }
396
397 /**
398 * Writes the specified value to the `swap-type` field of an image trailer.
399 * This value is persisted so that the boot loader knows what swap operation to
400 * resume in case of an unexpected reset.
401 */
402 int
boot_write_swap_info(const struct flash_area * fap,uint8_t swap_type,uint8_t image_num)403 boot_write_swap_info(const struct flash_area *fap, uint8_t swap_type,
404 uint8_t image_num)
405 {
406 uint32_t off;
407 uint8_t swap_info;
408
409 BOOT_SET_SWAP_INFO(swap_info, image_num, swap_type);
410 off = boot_swap_info_off(fap);
411 BOOT_LOG_DBG("writing swap_info; fa_id=%d off=0x%lx (0x%lx), swap_type=0x%x"
412 " image_num=0x%x",
413 flash_area_get_id(fap), (unsigned long)off,
414 (unsigned long)(flash_area_get_off(fap) + off),
415 swap_type, image_num);
416 return boot_write_trailer(fap, off, (const uint8_t *) &swap_info, 1);
417 }
418
419 int
boot_swap_type_multi(int image_index)420 boot_swap_type_multi(int image_index)
421 {
422 const struct boot_swap_table *table;
423 struct boot_swap_state primary_slot;
424 struct boot_swap_state secondary_slot;
425 int rc;
426 size_t i;
427
428 rc = BOOT_HOOK_CALL(boot_read_swap_state_primary_slot_hook,
429 BOOT_HOOK_REGULAR, image_index, &primary_slot);
430 if (rc == BOOT_HOOK_REGULAR)
431 {
432 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_PRIMARY(image_index),
433 &primary_slot);
434 }
435 if (rc) {
436 return BOOT_SWAP_TYPE_PANIC;
437 }
438
439 rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SECONDARY(image_index),
440 &secondary_slot);
441 if (rc == BOOT_EFLASH) {
442 BOOT_LOG_INF("Secondary image of image pair (%d.) "
443 "is unreachable. Treat it as empty", image_index);
444 secondary_slot.magic = BOOT_MAGIC_UNSET;
445 secondary_slot.swap_type = BOOT_SWAP_TYPE_NONE;
446 secondary_slot.copy_done = BOOT_FLAG_UNSET;
447 secondary_slot.image_ok = BOOT_FLAG_UNSET;
448 secondary_slot.image_num = 0;
449 } else if (rc) {
450 return BOOT_SWAP_TYPE_PANIC;
451 }
452
453 for (i = 0; i < BOOT_SWAP_TABLES_COUNT; i++) {
454 table = boot_swap_tables + i;
455
456 if (boot_magic_compatible_check(table->magic_primary_slot,
457 primary_slot.magic) &&
458 boot_magic_compatible_check(table->magic_secondary_slot,
459 secondary_slot.magic) &&
460 (table->image_ok_primary_slot == BOOT_FLAG_ANY ||
461 table->image_ok_primary_slot == primary_slot.image_ok) &&
462 (table->image_ok_secondary_slot == BOOT_FLAG_ANY ||
463 table->image_ok_secondary_slot == secondary_slot.image_ok) &&
464 (table->copy_done_primary_slot == BOOT_FLAG_ANY ||
465 table->copy_done_primary_slot == primary_slot.copy_done)
466 #if defined(MCUBOOT_SWAP_USING_OFFSET)
467 && (table->copy_done_secondary_slot == BOOT_FLAG_ANY ||
468 table->copy_done_secondary_slot == secondary_slot.copy_done)
469 #endif
470 ) {
471 BOOT_LOG_INF("Image index: %d, Swap type: %s", image_index,
472 table->swap_type == BOOT_SWAP_TYPE_TEST ? "test" :
473 table->swap_type == BOOT_SWAP_TYPE_PERM ? "perm" :
474 table->swap_type == BOOT_SWAP_TYPE_REVERT ? "revert" :
475 "BUG; can't happen");
476 if (table->swap_type != BOOT_SWAP_TYPE_TEST &&
477 table->swap_type != BOOT_SWAP_TYPE_PERM &&
478 table->swap_type != BOOT_SWAP_TYPE_REVERT) {
479 return BOOT_SWAP_TYPE_PANIC;
480 }
481 return table->swap_type;
482 }
483 }
484
485 BOOT_LOG_INF("Image index: %d, Swap type: none", image_index);
486 return BOOT_SWAP_TYPE_NONE;
487 }
488
489 int
boot_write_copy_done(const struct flash_area * fap)490 boot_write_copy_done(const struct flash_area *fap)
491 {
492 uint32_t off;
493
494 off = boot_copy_done_off(fap);
495 BOOT_LOG_DBG("writing copy_done; fa_id=%d off=0x%lx (0x%lx)",
496 flash_area_get_id(fap), (unsigned long)off,
497 (unsigned long)(flash_area_get_off(fap) + off));
498 return boot_write_trailer_flag(fap, off, BOOT_FLAG_SET);
499 }
500
501 #ifndef MCUBOOT_BOOTUTIL_LIB_FOR_DIRECT_XIP
502
flash_area_to_image(const struct flash_area * fa)503 static int flash_area_to_image(const struct flash_area *fa)
504 {
505 #if BOOT_IMAGE_NUMBER > 1
506 uint8_t i = 0;
507 int id = flash_area_get_id(fa);
508
509 while (i < BOOT_IMAGE_NUMBER) {
510 if (FLASH_AREA_IMAGE_PRIMARY(i) == id || (FLASH_AREA_IMAGE_SECONDARY(i) == id)) {
511 return i;
512 }
513
514 ++i;
515 }
516 #else
517 (void)fa;
518 #endif
519 return 0;
520 }
521
522 int
boot_set_next(const struct flash_area * fa,bool active,bool confirm)523 boot_set_next(const struct flash_area *fa, bool active, bool confirm)
524 {
525 struct boot_swap_state slot_state;
526 int rc;
527
528 if (active) {
529 confirm = true;
530 }
531
532 rc = boot_read_swap_state(fa, &slot_state);
533 if (rc != 0) {
534 return rc;
535 }
536
537 switch (slot_state.magic) {
538 case BOOT_MAGIC_GOOD:
539 /* If non-active then swap already scheduled, else confirm needed.*/
540
541 if (active && slot_state.image_ok == BOOT_FLAG_UNSET) {
542 /* Intentionally do not check copy_done flag to be able to
543 * confirm a padded image which has been programmed using
544 * a programming interface.
545 */
546 rc = boot_write_image_ok(fa);
547 }
548
549 break;
550
551 case BOOT_MAGIC_UNSET:
552 if (!active) {
553 rc = boot_write_magic(fa);
554
555 if (rc == 0 && confirm) {
556 rc = boot_write_image_ok(fa);
557 }
558
559 if (rc == 0) {
560 uint8_t swap_type;
561
562 if (confirm) {
563 swap_type = BOOT_SWAP_TYPE_PERM;
564 } else {
565 swap_type = BOOT_SWAP_TYPE_TEST;
566 }
567 rc = boot_write_swap_info(fa, swap_type, flash_area_to_image(fa));
568 }
569 }
570 break;
571
572 case BOOT_MAGIC_BAD:
573 if (active) {
574 rc = BOOT_EBADVECT;
575 } else {
576 /* The image slot is corrupt. There is no way to recover, so erase the
577 * slot to allow future upgrades.
578 */
579 flash_area_erase(fa, 0, flash_area_get_size(fa));
580 rc = BOOT_EBADIMAGE;
581 }
582 break;
583
584 default:
585 /* Something is not OK, this should never happen */
586 assert(0);
587 rc = BOOT_EBADIMAGE;
588 }
589
590 return rc;
591 }
592 #else
593 int
boot_set_next(const struct flash_area * fa,bool active,bool confirm)594 boot_set_next(const struct flash_area *fa, bool active, bool confirm)
595 {
596 struct boot_swap_state slot_state;
597 int rc;
598
599 if (active) {
600 /* The only way to set active slot for next boot is to confirm it,
601 * as DirectXIP will conclude that, since slot has not been confirmed
602 * last boot, it is bad and will remove it.
603 */
604 confirm = true;
605 }
606
607 rc = boot_read_swap_state(fa, &slot_state);
608 if (rc != 0) {
609 return rc;
610 }
611
612 switch (slot_state.magic) {
613 case BOOT_MAGIC_UNSET:
614 /* Magic is needed for MCUboot to even consider booting an image */
615 rc = boot_write_magic(fa);
616 if (rc != 0) {
617 break;
618 }
619 /* Pass */
620
621 case BOOT_MAGIC_GOOD:
622 if (confirm) {
623 if (slot_state.copy_done == BOOT_FLAG_UNSET) {
624 /* Magic is needed for DirectXIP to even try to boot application.
625 * DirectXIP will set copy-done flag before attempting to boot
626 * application. Next boot, application that has copy-done flag
627 * is expected to already have ok flag, otherwise it will be removed.
628 */
629 rc = boot_write_copy_done(fa);
630 if (rc != 0) {
631 break;
632 }
633 }
634
635 if (slot_state.image_ok == BOOT_FLAG_UNSET) {
636 rc = boot_write_image_ok(fa);
637 if (rc != 0) {
638 break;
639 }
640 }
641 }
642 break;
643
644 case BOOT_MAGIC_BAD:
645 /* This image will not be boot next time anyway */
646 rc = BOOT_EBADIMAGE;
647 break;
648
649 default:
650 /* Something is not OK, this should never happen */
651 assert(0);
652 rc = BOOT_EBADSTATUS;
653 }
654
655 return rc;
656 }
657 #endif
658
659 /*
660 * This function is not used by the bootloader itself, but its required API
661 * by external tooling like mcumgr.
662 */
663 int
boot_swap_type(void)664 boot_swap_type(void)
665 {
666 return boot_swap_type_multi(0);
667 }
668
669 /**
670 * Marks the image with the given index in the secondary slot as pending. On the
671 * next reboot, the system will perform a one-time boot of the the secondary
672 * slot image.
673 *
674 * @param image_index Image pair index.
675 *
676 * @param permanent Whether the image should be used permanently or
677 * only tested once:
678 * 0=run image once, then confirm or revert.
679 * 1=run image forever.
680 *
681 * @return 0 on success; nonzero on failure.
682 */
683 int
boot_set_pending_multi(int image_index,int permanent)684 boot_set_pending_multi(int image_index, int permanent)
685 {
686 const struct flash_area *fap;
687 int rc;
688
689 rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY(image_index), &fap);
690 if (rc != 0) {
691 return BOOT_EFLASH;
692 }
693
694 rc = boot_set_next(fap, false, !(permanent == 0));
695
696 flash_area_close(fap);
697 return rc;
698 }
699
700 /**
701 * Marks the image with index 0 in the secondary slot as pending. On the next
702 * reboot, the system will perform a one-time boot of the the secondary slot
703 * image. Note that this API is kept for compatibility. The
704 * boot_set_pending_multi() API is recommended.
705 *
706 * @param permanent Whether the image should be used permanently or
707 * only tested once:
708 * 0=run image once, then confirm or revert.
709 * 1=run image forever.
710 *
711 * @return 0 on success; nonzero on failure.
712 */
713 int
boot_set_pending(int permanent)714 boot_set_pending(int permanent)
715 {
716 return boot_set_pending_multi(0, permanent);
717 }
718
719 /**
720 * Marks the image with the given index in the primary slot as confirmed. The
721 * system will continue booting into the image in the primary slot until told to
722 * boot from a different slot.
723 *
724 * @param image_index Image pair index.
725 *
726 * @return 0 on success; nonzero on failure.
727 */
728 int
boot_set_confirmed_multi(int image_index)729 boot_set_confirmed_multi(int image_index)
730 {
731 const struct flash_area *fap = NULL;
732 int rc;
733
734 rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index), &fap);
735 if (rc != 0) {
736 return BOOT_EFLASH;
737 }
738
739 rc = boot_set_next(fap, true, true);
740
741 flash_area_close(fap);
742 return rc;
743 }
744
745 /**
746 * Marks the image with index 0 in the primary slot as confirmed. The system
747 * will continue booting into the image in the primary slot until told to boot
748 * from a different slot. Note that this API is kept for compatibility. The
749 * boot_set_confirmed_multi() API is recommended.
750 *
751 * @return 0 on success; nonzero on failure.
752 */
753 int
boot_set_confirmed(void)754 boot_set_confirmed(void)
755 {
756 return boot_set_confirmed_multi(0);
757 }
758
759 int
boot_image_load_header(const struct flash_area * fa_p,struct image_header * hdr)760 boot_image_load_header(const struct flash_area *fa_p,
761 struct image_header *hdr)
762 {
763 uint32_t size;
764 int rc = flash_area_read(fa_p, 0, hdr, sizeof *hdr);
765
766 if (rc != 0) {
767 rc = BOOT_EFLASH;
768 BOOT_LOG_ERR("Failed reading image header");
769 return BOOT_EFLASH;
770 }
771
772 if (hdr->ih_magic != IMAGE_MAGIC) {
773 BOOT_LOG_ERR("Bad image magic 0x%lx", (unsigned long)hdr->ih_magic);
774
775 return BOOT_EBADIMAGE;
776 }
777
778 if (hdr->ih_flags & IMAGE_F_NON_BOOTABLE) {
779 BOOT_LOG_ERR("Image not bootable");
780
781 return BOOT_EBADIMAGE;
782 }
783
784 if (!boot_u32_safe_add(&size, hdr->ih_img_size, hdr->ih_hdr_size) ||
785 size >= flash_area_get_size(fa_p)) {
786 return BOOT_EBADIMAGE;
787 }
788
789 return 0;
790 }
791