Skip to content

Commit 4af7316

Browse files
committed
boot: bootutil: Add swap using offset algorithm
Adds a new variation of the swap using move mode, named swap using offset, whereby instead of moving all the sectors in the primary image, the sectors in the secondary image are offset instead. This fastens image swapping time both for updates and reverts as each sector in both slots is erased only once, which also reduces flash wear, and uses less swap status bits to represent Signed-off-by: Jamie McCrae <jamie.mccrae@nordicsemi.no>
1 parent 2fe9cd4 commit 4af7316

18 files changed

+975
-17
lines changed

boot/bootutil/include/bootutil/boot_status.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ enum mcuboot_mode {
130130
MCUBOOT_MODE_RAM_LOAD,
131131
MCUBOOT_MODE_FIRMWARE_LOADER,
132132
MCUBOOT_MODE_SINGLE_SLOT_RAM_LOAD,
133+
MCUBOOT_MODE_SWAP_USING_OFFSET,
133134
};
134135

135136
enum mcuboot_signature_type {

boot/bootutil/include/bootutil/bootutil.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ struct boot_loader_state;
9090
void boot_state_clear(struct boot_loader_state *state);
9191
fih_ret context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp);
9292
const struct image_max_size *boot_get_max_app_size(void);
93+
uint32_t boot_get_state_secondary_offset(struct boot_loader_state *state,
94+
const struct flash_area *fap);
9395

9496
#define SPLIT_GO_OK (0)
9597
#define SPLIT_GO_NON_MATCHING (-1)

boot/bootutil/include/bootutil/bootutil_public.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ extern "C" {
8585

8686
#ifdef MCUBOOT_BOOT_MAX_ALIGN
8787

88-
#if defined(MCUBOOT_SWAP_USING_MOVE) || defined(MCUBOOT_SWAP_USING_SCRATCH)
88+
#if defined(MCUBOOT_SWAP_USING_MOVE) || defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SWAP_USING_OFFSET)
8989
_Static_assert(MCUBOOT_BOOT_MAX_ALIGN >= 8 && MCUBOOT_BOOT_MAX_ALIGN <= 32,
9090
"Unsupported value for MCUBOOT_BOOT_MAX_ALIGN for SWAP upgrade modes");
9191
#endif

boot/bootutil/include/bootutil/caps.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ uint32_t bootutil_get_caps(void);
5353
#define BOOTUTIL_CAP_DIRECT_XIP (1<<17)
5454
#define BOOTUTIL_CAP_HW_ROLLBACK_PROT (1<<18)
5555
#define BOOTUTIL_CAP_ECDSA_P384 (1<<19)
56+
#define BOOTUTIL_CAP_SWAP_USING_OFFSET (1<<20)
5657

5758
/*
5859
* Query the number of images this bootloader is configured for. This

boot/bootutil/include/bootutil/image.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,9 @@ struct image_tlv_iter {
211211
uint32_t prot_end;
212212
uint32_t tlv_off;
213213
uint32_t tlv_end;
214+
#if defined(MCUBOOT_SWAP_USING_OFFSET)
215+
uint32_t start_off;
216+
#endif
214217
};
215218

216219
int bootutil_tlv_iter_begin(struct image_tlv_iter *it,

boot/bootutil/src/boot_record.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,9 @@ boot_save_boot_status(uint8_t sw_module,
143143
/* Manifest data is concatenated to the end of the image.
144144
* It is encoded in TLV format.
145145
*/
146+
#if defined(MCUBOOT_SWAP_USING_OFFSET)
147+
it.start_off = 0;
148+
#endif
146149

147150
rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_ANY, false);
148151
if (rc) {
@@ -249,6 +252,8 @@ int boot_save_shared_data(const struct image_header *hdr, const struct flash_are
249252
uint8_t mode = MCUBOOT_MODE_UPGRADE_ONLY;
250253
#elif defined(MCUBOOT_SWAP_USING_MOVE)
251254
uint8_t mode = MCUBOOT_MODE_SWAP_USING_MOVE;
255+
#elif defined(MCUBOOT_SWAP_USING_OFFSET)
256+
uint8_t mode = MCUBOOT_MODE_SWAP_USING_OFFSET;
252257
#elif defined(MCUBOOT_DIRECT_XIP)
253258
#if defined(MCUBOOT_DIRECT_XIP_REVERT)
254259
uint8_t mode = MCUBOOT_MODE_DIRECT_XIP_WITH_REVERT;

boot/bootutil/src/bootutil_misc.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ uint32_t bootutil_max_image_size(const struct flash_area *fap)
336336
#if defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SINGLE_APPLICATION_SLOT) || \
337337
defined(MCUBOOT_FIRMWARE_LOADER) || defined(MCUBOOT_SINGLE_APPLICATION_SLOT_RAM_LOAD)
338338
return boot_status_off(fap);
339-
#elif defined(MCUBOOT_SWAP_USING_MOVE)
339+
#elif defined(MCUBOOT_SWAP_USING_MOVE) || defined(MCUBOOT_SWAP_USING_OFFSET)
340340
struct flash_sector sector;
341341
/* get the last sector offset */
342342
int rc = flash_area_get_sector(fap, boot_status_off(fap), &sector);
@@ -361,6 +361,7 @@ uint32_t bootutil_max_image_size(const struct flash_area *fap)
361361
* the TLVs.
362362
*/
363363
#if !defined(MCUBOOT_DIRECT_XIP) && \
364+
!defined(MCUBOOT_SWAP_USING_OFFSET) && \
364365
(!defined(MCUBOOT_OVERWRITE_ONLY) || \
365366
defined(MCUBOOT_OVERWRITE_ONLY_FAST))
366367
int

boot/bootutil/src/bootutil_priv.h

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,12 @@ struct flash_area;
5858

5959
#if (defined(MCUBOOT_OVERWRITE_ONLY) + \
6060
defined(MCUBOOT_SWAP_USING_MOVE) + \
61+
defined(MCUBOOT_SWAP_USING_OFFSET) + \
6162
defined(MCUBOOT_DIRECT_XIP) + \
6263
defined(MCUBOOT_RAM_LOAD) + \
6364
defined(MCUBOOT_FIRMWARE_LOADER) + \
6465
defined(MCUBOOT_SWAP_USING_SCRATCH)) > 1
65-
#error "Please enable only one of MCUBOOT_OVERWRITE_ONLY, MCUBOOT_SWAP_USING_MOVE, MCUBOOT_DIRECT_XIP, MCUBOOT_RAM_LOAD or MCUBOOT_FIRMWARE_LOADER"
66+
#error "Please enable only one of MCUBOOT_OVERWRITE_ONLY, MCUBOOT_SWAP_USING_MOVE, MCUBOOT_SWAP_USING_OFFSET, MCUBOOT_DIRECT_XIP, MCUBOOT_RAM_LOAD or MCUBOOT_FIRMWARE_LOADER"
6667
#endif
6768

6869
#if !defined(MCUBOOT_DIRECT_XIP) && \
@@ -72,15 +73,20 @@ struct flash_area;
7273

7374
#if !defined(MCUBOOT_OVERWRITE_ONLY) && \
7475
!defined(MCUBOOT_SWAP_USING_MOVE) && \
76+
!defined(MCUBOOT_SWAP_USING_OFFSET) && \
7577
!defined(MCUBOOT_DIRECT_XIP) && \
7678
!defined(MCUBOOT_RAM_LOAD) && \
7779
!defined(MCUBOOT_SINGLE_APPLICATION_SLOT) && \
7880
!defined(MCUBOOT_FIRMWARE_LOADER)
7981
#define MCUBOOT_SWAP_USING_SCRATCH 1
8082
#endif
8183

84+
#if defined(MCUBOOT_SWAP_USING_OFFSET)
85+
#define BOOT_STATUS_OP_SWAP 1
86+
#else
8287
#define BOOT_STATUS_OP_MOVE 1
8388
#define BOOT_STATUS_OP_SWAP 2
89+
#endif
8490

8591
/*
8692
* Maintain state of copy progress.
@@ -196,6 +202,9 @@ _Static_assert(sizeof(boot_img_magic) == BOOT_MAGIC_SZ, "Invalid size for image
196202
#define BOOT_STATUS_MOVE_STATE_COUNT 1
197203
#define BOOT_STATUS_SWAP_STATE_COUNT 2
198204
#define BOOT_STATUS_STATE_COUNT (BOOT_STATUS_MOVE_STATE_COUNT + BOOT_STATUS_SWAP_STATE_COUNT)
205+
#elif MCUBOOT_SWAP_USING_OFFSET
206+
#define BOOT_STATUS_SWAP_STATE_COUNT 2
207+
#define BOOT_STATUS_STATE_COUNT BOOT_STATUS_SWAP_STATE_COUNT
199208
#else
200209
#define BOOT_STATUS_STATE_COUNT 3
201210
#endif
@@ -241,6 +250,13 @@ struct boot_loader_state {
241250
uint8_t swap_type[BOOT_IMAGE_NUMBER];
242251
uint32_t write_sz;
243252

253+
#if defined(MCUBOOT_SWAP_USING_OFFSET)
254+
uint32_t secondary_offset[BOOT_IMAGE_NUMBER];
255+
#if defined(MCUBOOT_BOOTSTRAP)
256+
bool bootstrap_secondary_offset_set[BOOT_IMAGE_NUMBER];
257+
#endif
258+
#endif
259+
244260
#if defined(MCUBOOT_ENC_IMAGES)
245261
struct enc_key_data enc[BOOT_IMAGE_NUMBER][BOOT_NUM_SLOTS];
246262
#endif
@@ -307,10 +323,17 @@ int boot_slots_compatible(struct boot_loader_state *state);
307323
uint32_t boot_status_internal_off(const struct boot_status *bs, int elem_sz);
308324
int boot_read_image_header(struct boot_loader_state *state, int slot,
309325
struct image_header *out_hdr, struct boot_status *bs);
326+
#if defined(MCUBOOT_SWAP_USING_OFFSET) && defined(MCUBOOT_ENC_IMAGES)
327+
int boot_copy_region(struct boot_loader_state *state,
328+
const struct flash_area *fap_src,
329+
const struct flash_area *fap_dst,
330+
uint32_t off_src, uint32_t off_dst, uint32_t sz, uint32_t sector_off);
331+
#else
310332
int boot_copy_region(struct boot_loader_state *state,
311333
const struct flash_area *fap_src,
312334
const struct flash_area *fap_dst,
313335
uint32_t off_src, uint32_t off_dst, uint32_t sz);
336+
#endif
314337
int boot_erase_region(const struct flash_area *fap, uint32_t off, uint32_t sz);
315338
bool boot_status_is_reset(const struct boot_status *bs);
316339

boot/bootutil/src/bootutil_public.c

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* Copyright (c) 2017-2019 Linaro LTD
55
* Copyright (c) 2016-2019 JUUL Labs
66
* Copyright (c) 2019-2023 Arm Limited
7-
* Copyright (c) 2020-2023 Nordic Semiconductor ASA
7+
* Copyright (c) 2020-2025 Nordic Semiconductor ASA
88
*
99
* Original license:
1010
*
@@ -84,6 +84,9 @@ struct boot_swap_table {
8484
uint8_t image_ok_primary_slot;
8585
uint8_t image_ok_secondary_slot;
8686
uint8_t copy_done_primary_slot;
87+
#if defined(MCUBOOT_SWAP_USING_OFFSET)
88+
uint8_t copy_done_secondary_slot;
89+
#endif
8790

8891
uint8_t swap_type;
8992
};
@@ -100,12 +103,26 @@ struct boot_swap_table {
100103
* the bootloader, as in starting/finishing a swap operation.
101104
*/
102105
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
103117
{
104118
.magic_primary_slot = BOOT_MAGIC_ANY,
105119
.magic_secondary_slot = BOOT_MAGIC_GOOD,
106120
.image_ok_primary_slot = BOOT_FLAG_ANY,
107121
.image_ok_secondary_slot = BOOT_FLAG_UNSET,
108122
.copy_done_primary_slot = BOOT_FLAG_ANY,
123+
#if defined(MCUBOOT_SWAP_USING_OFFSET)
124+
.copy_done_secondary_slot = BOOT_FLAG_ANY,
125+
#endif
109126
.swap_type = BOOT_SWAP_TYPE_TEST,
110127
},
111128
{
@@ -114,6 +131,9 @@ static const struct boot_swap_table boot_swap_tables[] = {
114131
.image_ok_primary_slot = BOOT_FLAG_ANY,
115132
.image_ok_secondary_slot = BOOT_FLAG_SET,
116133
.copy_done_primary_slot = BOOT_FLAG_ANY,
134+
#if defined(MCUBOOT_SWAP_USING_OFFSET)
135+
.copy_done_secondary_slot = BOOT_FLAG_ANY,
136+
#endif
117137
.swap_type = BOOT_SWAP_TYPE_PERM,
118138
},
119139
{
@@ -122,6 +142,9 @@ static const struct boot_swap_table boot_swap_tables[] = {
122142
.image_ok_primary_slot = BOOT_FLAG_UNSET,
123143
.image_ok_secondary_slot = BOOT_FLAG_ANY,
124144
.copy_done_primary_slot = BOOT_FLAG_SET,
145+
#if defined(MCUBOOT_SWAP_USING_OFFSET)
146+
.copy_done_secondary_slot = BOOT_FLAG_ANY,
147+
#endif
125148
.swap_type = BOOT_SWAP_TYPE_REVERT,
126149
},
127150
};
@@ -439,7 +462,12 @@ boot_swap_type_multi(int image_index)
439462
(table->image_ok_secondary_slot == BOOT_FLAG_ANY ||
440463
table->image_ok_secondary_slot == secondary_slot.image_ok) &&
441464
(table->copy_done_primary_slot == BOOT_FLAG_ANY ||
442-
table->copy_done_primary_slot == primary_slot.copy_done)) {
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+
) {
443471
BOOT_LOG_INF("Image index: %d, Swap type: %s", image_index,
444472
table->swap_type == BOOT_SWAP_TYPE_TEST ? "test" :
445473
table->swap_type == BOOT_SWAP_TYPE_PERM ? "perm" :

boot/bootutil/src/caps.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ uint32_t bootutil_get_caps(void)
4545
res |= BOOTUTIL_CAP_OVERWRITE_UPGRADE;
4646
#elif defined(MCUBOOT_SWAP_USING_MOVE)
4747
res |= BOOTUTIL_CAP_SWAP_USING_MOVE;
48+
#elif defined(MCUBOOT_SWAP_USING_OFFSET)
49+
res |= BOOTUTIL_CAP_SWAP_USING_OFFSET;
4850
#else
4951
res |= BOOTUTIL_CAP_SWAP_USING_SCRATCH;
5052
#endif

0 commit comments

Comments
 (0)