blob: c8f8f95393c304a2b7bee312b8ed5f008d01247c [file] [log] [blame]
Roman Okhrimenko13f79ed2021-03-11 19:05:41 +02001/*
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-2020 Arm Limited
7 * Copyright (c) 2020 Cypress Semiconductors
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#include <assert.h>
30#include <stddef.h>
31#include <stdbool.h>
32#include <inttypes.h>
33#include <stdlib.h>
34#include <string.h>
35#include "bootutil/bootutil.h"
36#include "bootutil_priv.h"
37#include "swap_priv.h"
38#include "bootutil/bootutil_log.h"
39
40#include "swap_status.h"
41
42#include "mcuboot_config/mcuboot_config.h"
43
44MCUBOOT_LOG_MODULE_DECLARE(mcuboot);
45
46#if defined(MCUBOOT_SWAP_USING_STATUS)
47
48#define BOOT_MAGIC_ARR_SZ \
49 (sizeof boot_img_magic / sizeof boot_img_magic[0])
50
51static int
52boot_find_status(int image_index, const struct flash_area **fap);
53
54static int
55boot_magic_decode(const uint32_t *magic)
56{
57 if (memcmp(magic, boot_img_magic, BOOT_MAGIC_SZ) == 0) {
58 return BOOT_MAGIC_GOOD;
59 }
60 return BOOT_MAGIC_BAD;
61}
62
63static int
64boot_flag_decode(uint8_t flag)
65{
66 if (flag != (uint8_t)BOOT_FLAG_SET) {
67 return BOOT_FLAG_BAD;
68 }
69 return BOOT_FLAG_SET;
70}
71
72static inline size_t
73boot_status_sector_size(const struct boot_loader_state *state, size_t sector)
74{
75 return state->status.sectors[sector].fs_size;
76}
77
78static inline uint32_t
79boot_status_sector_off(const struct boot_loader_state *state,
80 size_t sector)
81{
82 return state->status.sectors[sector].fs_off -
83 state->status.sectors[0].fs_off;
84}
85
86/* Offset Section */
87static inline uint32_t
88boot_magic_off(const struct flash_area *fap)
89{
90 (void)fap;
91 return ((uint32_t)BOOT_SWAP_STATUS_D_SIZE_RAW - (uint32_t)BOOT_MAGIC_SZ);
92}
93
94uint32_t
95boot_image_ok_off(const struct flash_area *fap)
96{
97 return (uint32_t)(boot_magic_off(fap) - 1u);
98}
99
100uint32_t
101boot_copy_done_off(const struct flash_area *fap)
102{
103 return (uint32_t)(boot_image_ok_off(fap) - 1u);
104}
105
106uint32_t
107boot_swap_info_off(const struct flash_area *fap)
108{
109 return (uint32_t)(boot_copy_done_off(fap) - 1u);
110}
111
112uint32_t
113boot_swap_size_off(const struct flash_area *fap)
114{
115 return (uint32_t)(boot_swap_info_off(fap) - 4u);
116}
117
118uint32_t
119boot_status_off(const struct flash_area *fap)
120{
121 (void)fap;
122 /* this offset is equal to 0, because swap status fields
123 in this implementation count from the start of partition */
124 return 0;
125}
126
127#ifdef MCUBOOT_ENC_IMAGES
128static inline uint32_t
129boot_enc_key_off(const struct flash_area *fap, uint8_t slot)
130{
131#ifdef MCUBOOT_SWAP_SAVE_ENCTLV
132 /* suggest encryption key is also stored in status partition */
133 return (uint32_t)(boot_swap_size_off(fap) - (uint32_t)((slot + 1u) * (uint32_t)BOOT_ENC_TLV_SIZE));
134#else
135 return (uint32_t)(boot_swap_size_off(fap) - (uint32_t)((slot + 1u) * (uint32_t)BOOT_ENC_KEY_SIZE));
136#endif
137}
138#endif
139
140/**
141 * Write trailer data; status bytes, swap_size, etc
142 *
143 * @returns 0 on success, != 0 on error.
144 */
145int
146boot_write_trailer(const struct flash_area *fap, uint32_t off,
147 const uint8_t *inbuf, uint8_t inlen)
148{
149 int rc;
150
151 rc = swap_status_update(fap->fa_id, off, (uint8_t *)inbuf, inlen);
152
153 if (rc != 0) {
154 return BOOT_EFLASH;
155 }
156 return rc;
157}
158
159#ifdef MCUBOOT_ENC_IMAGES
160int
161boot_write_enc_key(const struct flash_area *fap, uint8_t slot,
162 const struct boot_status *bs)
163{
164 uint32_t off;
165 int rc;
166
167 off = boot_enc_key_off(fap, slot);
168#ifdef MCUBOOT_SWAP_SAVE_ENCTLV
169 rc = swap_status_update(fap->fa_id, off,
170 (uint8_t *) bs->enctlv[slot], BOOT_ENC_TLV_ALIGN_SIZE);
171#else
172 rc = swap_status_update(fap->fa_id, off,
173 (uint8_t *) bs->enckey[slot], BOOT_ENC_KEY_SIZE);
174#endif
175 if (rc != 0) {
176 return BOOT_EFLASH;
177 }
178
179 return 0;
180}
181
182int
183boot_read_enc_key(int image_index, uint8_t slot, struct boot_status *bs)
184{
185 uint32_t off;
186 const struct flash_area *fap;
187#ifdef MCUBOOT_SWAP_SAVE_ENCTLV
188 int i;
189#endif
190 int rc;
191
192 rc = boot_find_status(image_index, &fap);
193 if (rc == 0) {
194 off = boot_enc_key_off(fap, slot);
195#ifdef MCUBOOT_SWAP_SAVE_ENCTLV
196 rc = swap_status_retrieve(fap->fa_id, off, bs->enctlv[slot], BOOT_ENC_TLV_ALIGN_SIZE);
197 if (rc == 0) {
198 for (i = 0; i < BOOT_ENC_TLV_ALIGN_SIZE; i++) {
199 if (bs->enctlv[slot][i] != 0xff) {
200 break;
201 }
202 }
203 /* Only try to decrypt non-erased TLV metadata */
204 if (i != BOOT_ENC_TLV_ALIGN_SIZE) {
205 rc = boot_enc_decrypt(bs->enctlv[slot], bs->enckey[slot]);
206 }
207 }
208#else
209 rc = swap_status_retrieve(fap->fa_id, off, bs->enckey[slot], BOOT_ENC_KEY_SIZE);
210#endif
211 flash_area_close(fap);
212 }
213
214 return rc;
215}
216#endif /* MCUBOOT_ENC_IMAGES */
217
218/* Write Section */
219int
220boot_write_magic(const struct flash_area *fap)
221{
222 uint32_t off;
223 int rc;
224
225 off = boot_magic_off(fap);
226
227 rc = swap_status_update(fap->fa_id, off,
228 (uint8_t *) boot_img_magic, BOOT_MAGIC_SZ);
229
230 if (rc != 0) {
231 return BOOT_EFLASH;
232 }
233 return 0;
234}
235
236int boot_status_num_sectors(const struct boot_loader_state *state)
237{
238 return (int)(BOOT_SWAP_STATUS_SIZE / boot_status_sector_size(state, 0));
239}
240
241/**
242 * Writes the supplied boot status to the flash file system. The boot status
243 * contains the current state of an in-progress image copy operation.
244 *
245 * @param bs The boot status to write.
246 *
247 * @return 0 on success; nonzero on failure.
248 */
249int
250boot_write_status(const struct boot_loader_state *state, struct boot_status *bs)
251{
252 const struct flash_area *fap = NULL;
253 uint32_t off;
254 int area_id;
255 int rc;
256 (void)state;
257
258 /* NOTE: The first sector copied (that is the last sector on slot) contains
259 * the trailer. Since in the last step the primary slot is erased, the
260 * first two status writes go to the scratch which will be copied to
261 * the primary slot!
262 */
263
264#ifdef MCUBOOT_SWAP_USING_SCRATCH
265 if (bs->use_scratch) {
266 /* Write to scratch status. */
267 area_id = FLASH_AREA_IMAGE_SCRATCH;
268 } else
269#endif
270 {
271 /* Write to the primary slot. */
272 area_id = (int)FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state));
273 }
274
275 rc = flash_area_open((uint8_t)area_id, &fap);
276 if (rc != 0) {
277 rc = BOOT_EFLASH;
278 goto done;
279 }
280 off = boot_status_off(fap) + boot_status_internal_off(bs, 1);
281
282 uint8_t tmp_state = bs->state;
283
284 rc = swap_status_update(fap->fa_id, off, &tmp_state, 1);
285 if (rc != 0) {
286 rc = BOOT_EFLASH;
287 goto done;
288 }
289
290done:
291 flash_area_close(fap);
292
293 return rc;
294}
295
296int
297boot_read_data_empty(const struct flash_area *fap, void *data, uint32_t len)
298{
299 uint8_t *buf;
300
301 buf = (uint8_t *)data;
302 for (uint32_t i = 0; i < len; i++) {
303 if (buf[i] != flash_area_erased_val(fap)) {
304 return 0;
305 }
306 }
307 return 1;
308}
309
310int
311boot_read_swap_state(const struct flash_area *fap,
312 struct boot_swap_state *state)
313{
314 uint32_t magic[BOOT_MAGIC_ARR_SZ];
315 uint32_t off;
316 uint32_t trailer_off = 0U;
317 uint8_t swap_info = 0U;
318 int rc;
319 uint32_t erase_trailer = 0;
320
321 const struct flash_area *fap_stat = NULL;
322
323 rc = flash_area_open(FLASH_AREA_IMAGE_SWAP_STATUS, &fap_stat);
324 if (rc != 0) {
325 return BOOT_EFLASH;
326 }
327
328 off = boot_magic_off(fap);
329 /* retrieve value for magic field from status partition area */
330 rc = swap_status_retrieve(fap->fa_id, off, magic, BOOT_MAGIC_SZ);
331 if (rc < 0) {
332 return BOOT_EFLASH;
333 }
334 rc = boot_read_data_empty(fap_stat, magic, BOOT_MAGIC_SZ);
335 if (rc < 0) {
336 return BOOT_EFLASH;
337 }
338 /* fill magic number value if equal to expected */
339 if (rc == 1) {
340
341 state->magic = BOOT_MAGIC_UNSET;
342
343 /* attempt to find magic in upgrade img slot trailer */
344 if (fap->fa_id == FLASH_AREA_IMAGE_1 ||
345 fap->fa_id == FLASH_AREA_IMAGE_3) {
346
347 trailer_off = fap->fa_size - BOOT_MAGIC_SZ;
348
349 rc = flash_area_read_is_empty(fap, trailer_off, magic, BOOT_MAGIC_SZ);
350 if (rc < 0) {
351 return BOOT_EFLASH;
352 }
353 if (rc == 1) {
354 state->magic = BOOT_MAGIC_UNSET;
355 } else {
356 state->magic = (uint8_t)boot_magic_decode(magic);
357 /* put magic to status partition for upgrade slot*/
358 if (state->magic == (uint32_t)BOOT_MAGIC_GOOD) {
359 rc = swap_status_update(fap->fa_id, off,
360 (uint8_t *) magic, BOOT_MAGIC_SZ);
361 }
362 if (rc < 0) {
363 return BOOT_EFLASH;
364 } else {
365 erase_trailer = 1;
366 }
367 }
368 }
369 } else {
370 state->magic = (uint8_t)boot_magic_decode(magic);
371 }
372
373 off = boot_swap_info_off(fap);
374 rc = swap_status_retrieve(fap->fa_id, off, &swap_info, sizeof swap_info);
375 if (rc < 0) {
376 return BOOT_EFLASH;
377 }
378 rc = boot_read_data_empty(fap_stat, &swap_info, sizeof swap_info);
379 if (rc < 0) {
380 return BOOT_EFLASH;
381 }
382 if (rc == 1 || state->swap_type > (uint8_t)BOOT_SWAP_TYPE_REVERT) {
383 state->swap_type = (uint8_t)BOOT_SWAP_TYPE_NONE;
384 state->image_num = 0;
385 }
386 else {
387 /* Extract the swap type and image number */
388 state->swap_type = (uint8_t)BOOT_GET_SWAP_TYPE_M(swap_info);
389 state->image_num = (uint8_t)BOOT_GET_IMAGE_NUM_M(swap_info);
390 }
391
392 off = boot_copy_done_off(fap);
393 rc = swap_status_retrieve(fap->fa_id, off, &state->copy_done, sizeof state->copy_done);
394 if (rc < 0) {
395 return BOOT_EFLASH;
396 }
397 rc = boot_read_data_empty(fap_stat, &state->copy_done, sizeof state->copy_done);
398 /* need to check swap_info was empty */
399 if (rc < 0) {
400 return BOOT_EFLASH;
401 }
402 if (rc == 1) {
403 state->copy_done = BOOT_FLAG_UNSET;
404 } else {
405 state->copy_done = (uint8_t)boot_flag_decode(state->copy_done);
406 }
407
408 off = boot_image_ok_off(fap);
409 rc = swap_status_retrieve(fap->fa_id, off, &state->image_ok, sizeof state->image_ok);
410 if (rc < 0) {
411 return BOOT_EFLASH;
412 }
413 rc = boot_read_data_empty(fap_stat, &state->image_ok, sizeof state->image_ok);
414 /* need to check swap_info was empty */
415 if (rc < 0) {
416 return BOOT_EFLASH;
417 }
418 if (rc == 1) {
419 /* assign img_ok unset */
420 state->image_ok = BOOT_FLAG_UNSET;
421
422 /* attempt to read img_ok value in upgrade img slots trailer area
423 * it is set when image in slot for upgrade is signed for swap_type permanent
424 */
425 uint32_t process_image_ok = 0;
426 switch (fap->fa_id) {
427 case FLASH_AREA_IMAGE_0:
428 case FLASH_AREA_IMAGE_2:
429 {
430 if (state->copy_done == (uint8_t)BOOT_FLAG_SET)
431 process_image_ok = 1;
432 }
433 break;
434 case FLASH_AREA_IMAGE_1:
435 case FLASH_AREA_IMAGE_3:
436 {
437 process_image_ok = 1;
438 }
439 break;
440 case FLASH_AREA_IMAGE_SCRATCH:
441 {
442 BOOT_LOG_DBG(" * selected SCRATCH area, copy_done = %d", state->copy_done);
443 {
444 if (state->copy_done == (uint8_t)BOOT_FLAG_SET)
445 process_image_ok = 1;
446 }
447 }
448 break;
449 default:
450 {
451 return BOOT_EFLASH;
452 }
453 break;
454 }
455 if (process_image_ok != 0u) {
456 trailer_off = fap->fa_size - (uint8_t)BOOT_MAGIC_SZ - (uint8_t)BOOT_MAX_ALIGN;
457
458 rc = flash_area_read_is_empty(fap, trailer_off, &state->image_ok, sizeof state->image_ok);
459 if (rc < 0) {
460 return BOOT_EFLASH;
461 }
462 if (rc == 1) {
463 state->image_ok = BOOT_FLAG_UNSET;
464 } else {
465 state->image_ok = (uint8_t)boot_flag_decode(state->image_ok);
466
467 /* put img_ok to status partition for upgrade slot */
468 if (state->image_ok != (uint8_t)BOOT_FLAG_BAD) {
469 rc = swap_status_update(fap->fa_id, off,
470 &state->image_ok, sizeof state->image_ok);
471 }
472 if (rc < 0) {
473 return BOOT_EFLASH;
474 }
475
476 /* mark img trailer needs to be erased */
477 erase_trailer = 1;
478 }
479 }
480 } else {
481 state->image_ok = (uint8_t)boot_flag_decode(state->image_ok);
482 }
483
484 if ((erase_trailer != 0u) && (fap->fa_id != FLASH_AREA_IMAGE_SCRATCH)) {
485 /* erase magic from upgrade img trailer */
486 rc = flash_area_erase(fap, trailer_off, BOOT_MAGIC_SZ);
487 if (rc != 0)
488 return rc;
489 }
490 return 0;
491}
492
493/**
494 * This functions tries to locate the status area after an aborted swap,
495 * by looking for the magic in the possible locations.
496 *
497 * If the magic is successfully found, a flash_area * is returned and it
498 * is the responsibility of the called to close it.
499 *
500 * @returns 0 on success, -1 on errors
501 */
502static int
503boot_find_status(int image_index, const struct flash_area **fap)
504{
505 uint32_t magic[BOOT_MAGIC_ARR_SZ] = {0};
506 uint32_t off;
507
508 /* the status is always in status partition */
509 uint8_t area = FLASH_AREA_IMAGE_PRIMARY((uint32_t)image_index);
510 int rc = -1;
511
512 /*
513 * In the middle a swap, tries to locate the area that is currently
514 * storing a valid magic, first on the primary slot, then on scratch.
515 * Both "slots" can end up being temporary storage for a swap and it
516 * is assumed that if magic is valid then other metadata is too,
517 * because magic is always written in the last step.
518 */
519 rc = flash_area_open(area, fap);
520 if (rc != 0) {
521 return rc;
522 }
523 off = boot_magic_off(*fap);
524 rc = swap_status_retrieve(area, off, magic, BOOT_MAGIC_SZ);
525
526 if (rc == 0) {
527 rc = memcmp(magic, boot_img_magic, BOOT_MAGIC_SZ);
528 }
529
530 flash_area_close(*fap);
531 return rc;
532}
533
534int
535boot_read_swap_size(int image_index, uint32_t *swap_size)
536{
537 uint32_t off;
538 const struct flash_area *fap;
539 int rc;
540
541 rc = boot_find_status(image_index, &fap);
542 if (rc == 0) {
543 off = boot_swap_size_off(fap);
544
545 rc = swap_status_retrieve(fap->fa_id, off, swap_size, sizeof *swap_size);
546 }
547 return rc;
548}
549
550int
551swap_erase_trailer_sectors(const struct boot_loader_state *state,
552 const struct flash_area *fap)
553{
554 uint32_t sub_offs, trailer_offs;
555 uint32_t sz;
556 uint8_t fa_id_primary;
557 uint8_t fa_id_secondary;
558 uint8_t image_index;
559 int rc;
560 (void)state;
561
562 BOOT_LOG_INF("Erasing trailer; fa_id=%d", fap->fa_id);
563 /* trailer is located in status-partition */
564 const struct flash_area *fap_stat = NULL;
565
566 rc = flash_area_open(FLASH_AREA_IMAGE_SWAP_STATUS, &fap_stat);
567 if (rc != 0) {
568 return BOOT_EFLASH;
569 }
570
571 if (fap->fa_id != FLASH_AREA_IMAGE_SCRATCH)
572 {
573 image_index = BOOT_CURR_IMG(state);
574 fa_id_primary = (uint8_t)flash_area_id_from_multi_image_slot((int32_t)image_index,
575 BOOT_PRIMARY_SLOT);
576 fa_id_secondary = (uint8_t)flash_area_id_from_multi_image_slot((int32_t)image_index,
577 BOOT_SECONDARY_SLOT);
578
579 /* skip if Flash Area is not recognizable */
580 if ((fap->fa_id != fa_id_primary) && (fap->fa_id != fa_id_secondary)) {
581 return BOOT_EFLASH;
582 }
583 }
584
585 sub_offs = (uint32_t)swap_status_init_offset(fap->fa_id);
586
587 /* delete starting from last sector and moving to beginning */
588 /* calculate last sector of status sub-area */
589 sz = (uint32_t)BOOT_SWAP_STATUS_SIZE;
590
591 rc = flash_area_erase(fap_stat, sub_offs, sz);
592 assert((int)(rc == 0));
593
594 if (fap->fa_id != FLASH_AREA_IMAGE_SCRATCH)
595 {
596 /*
597 * it is also needed to erase trailer area in slots since they may contain
598 * data, which is already cleared in corresponding status partition
599 */
600 trailer_offs = fap->fa_size - BOOT_SWAP_STATUS_TRAILER_SIZE;
601 rc = flash_area_erase(fap, trailer_offs, BOOT_SWAP_STATUS_TRAILER_SIZE);
602 }
603
604 flash_area_close(fap_stat);
605
606 return rc;
607}
608
609int
610swap_status_init(const struct boot_loader_state *state,
611 const struct flash_area *fap,
612 const struct boot_status *bs)
613{
614 struct boot_swap_state swap_state;
615 uint8_t image_index;
616 int rc;
617
618#if (BOOT_IMAGE_NUMBER == 1)
619 (void)state;
620#endif
621
622 image_index = BOOT_CURR_IMG(state);
623
624 BOOT_LOG_DBG("initializing status; fa_id=%d", fap->fa_id);
625
626 rc = boot_read_swap_state_by_id((int32_t)FLASH_AREA_IMAGE_SECONDARY(image_index),
627 &swap_state);
628 assert((int)(rc == 0));
629
630 if (bs->swap_type != (uint8_t)BOOT_SWAP_TYPE_NONE) {
631 rc = boot_write_swap_info(fap, bs->swap_type, image_index);
632 assert((int)(rc == 0));
633 }
634
635 if (swap_state.image_ok == (uint8_t)BOOT_FLAG_SET) {
636 rc = boot_write_image_ok(fap);
637 assert((int)(rc == 0));
638 }
639
640 rc = boot_write_swap_size(fap, bs->swap_size);
641 assert((int)(rc == 0));
642
643#ifdef MCUBOOT_ENC_IMAGES
644 rc = boot_write_enc_key(fap, 0, bs);
645 assert((int)(rc == 0));
646
647 rc = boot_write_enc_key(fap, 1, bs);
648 assert((int)(rc == 0));
649#endif
650
651 rc = boot_write_magic(fap);
652 assert((int)(rc == 0));
653
654 return 0;
655}
656
657int
658swap_read_status(struct boot_loader_state *state, struct boot_status *bs)
659{
660 const struct flash_area *fap = NULL;
661 const struct flash_area *fap_stat = NULL;
662 uint32_t off;
663 uint8_t swap_info = 0;
664 int area_id;
665 int rc = 0;
666
667 bs->source = swap_status_source(state);
668
669 if (bs->source == BOOT_STATUS_SOURCE_NONE) {
670 return 0;
671 }
672
673 if (bs->source == BOOT_STATUS_SOURCE_PRIMARY_SLOT) {
674 area_id = (int32_t)FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state));
675 } else if (bs->source == BOOT_STATUS_SOURCE_SCRATCH) {
676 area_id = FLASH_AREA_IMAGE_SCRATCH;
677 } else {
678 return BOOT_EBADARGS;
679 }
680
681 rc = flash_area_open((uint8_t)area_id, &fap);
682 if (rc != 0) {
683 return BOOT_EFLASH;
684 }
685
686 rc = flash_area_open(FLASH_AREA_IMAGE_SWAP_STATUS, &fap_stat);
687 if (rc != 0) {
688 return BOOT_EFLASH;
689 }
690
691 rc = swap_read_status_bytes(fap, state, bs);
692 if (rc == 0) {
693 off = boot_swap_info_off(fap);
694 rc = swap_status_retrieve((uint8_t)area_id, off, &swap_info, sizeof swap_info);
695 if (rc < 0) {
696 return BOOT_EFLASH;
697 }
698 rc = boot_read_data_empty(fap_stat, &swap_info, sizeof swap_info);
699 if (rc < 0) {
700 return BOOT_EFLASH;
701 }
702
703 if (rc == 1) {
704 BOOT_SET_SWAP_INFO_M(swap_info, 0u, (uint8_t)BOOT_SWAP_TYPE_NONE);
705 rc = 0;
706 }
707
708 /* Extract the swap type info */
709 bs->swap_type = BOOT_GET_SWAP_TYPE_M(swap_info);
710 }
711
712 flash_area_close(fap);
713 flash_area_close(fap_stat);
714
715 return rc;
716}
717
718#endif /* MCUBOOT_SWAP_USING_STATUS */