Skip to content

Commit b75c12a

Browse files
davidvinczed3zd3z
authored andcommitted
Boot: Extend flash layout for multiple images
This patch introduces the BOOT_IMAGE_NUMBER macro and current_image variable to support multiple updatable images and the associated extended flash layout. The FLASH_AREA_IMAGE_* object-like macros are replaced with function-like ones and therefore some functions have been updated, because the labels of a switch statement and the initialization values of objects with static storage duration have to be constant expressions. Change-Id: Ib7b26ec3c94233e52db4f97825ddb6a3e55bb1d3 Signed-off-by: David Vincze <[email protected]>
1 parent 6c9b416 commit b75c12a

File tree

12 files changed

+144
-74
lines changed

12 files changed

+144
-74
lines changed

NOTICE

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,6 @@ The Apache Software Foundation (http://www.apache.org/).
66

77
Portions of this software were developed at
88
Runtime Inc, copyright 2015.
9+
10+
Portions of this software were developed at
11+
Arm Limited, copyright 2019.

boot/bootutil/src/bootutil_misc.c

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -172,13 +172,12 @@ boot_magic_off(const struct flash_area *fap)
172172
int
173173
boot_status_entries(const struct flash_area *fap)
174174
{
175-
switch (fap->fa_id) {
176-
case FLASH_AREA_IMAGE_PRIMARY:
177-
case FLASH_AREA_IMAGE_SECONDARY:
178-
return BOOT_STATUS_STATE_COUNT * BOOT_STATUS_MAX_ENTRIES;
179-
case FLASH_AREA_IMAGE_SCRATCH:
175+
if (fap->fa_id == FLASH_AREA_IMAGE_SCRATCH) {
180176
return BOOT_STATUS_STATE_COUNT;
181-
default:
177+
} else if ((fap->fa_id == FLASH_AREA_IMAGE_PRIMARY) ||
178+
(fap->fa_id == FLASH_AREA_IMAGE_SECONDARY)) {
179+
return BOOT_STATUS_STATE_COUNT * BOOT_STATUS_MAX_ENTRIES;
180+
} else {
182181
return BOOT_EBADARGS;
183182
}
184183
}
@@ -301,16 +300,14 @@ boot_read_swap_state_by_id(int flash_area_id, struct boot_swap_state *state)
301300
const struct flash_area *fap;
302301
int rc;
303302

304-
switch (flash_area_id) {
305-
case FLASH_AREA_IMAGE_SCRATCH:
306-
case FLASH_AREA_IMAGE_PRIMARY:
307-
case FLASH_AREA_IMAGE_SECONDARY:
303+
if (flash_area_id == FLASH_AREA_IMAGE_SCRATCH ||
304+
flash_area_id == FLASH_AREA_IMAGE_PRIMARY ||
305+
flash_area_id == FLASH_AREA_IMAGE_SECONDARY) {
308306
rc = flash_area_open(flash_area_id, &fap);
309307
if (rc != 0) {
310308
return BOOT_EFLASH;
311309
}
312-
break;
313-
default:
310+
} else {
314311
return BOOT_EBADARGS;
315312
}
316313

boot/bootutil/src/bootutil_priv.h

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,12 @@ struct boot_swap_state {
134134
uint8_t image_num; /* Boot status belongs to this image */
135135
};
136136

137+
#ifdef MCUBOOT_IMAGE_NUMBER
138+
#define BOOT_IMAGE_NUMBER MCUBOOT_IMAGE_NUMBER
139+
#else
140+
#define BOOT_IMAGE_NUMBER 1
141+
#endif
142+
137143
#define BOOT_MAX_IMG_SECTORS MCUBOOT_MAX_IMG_SECTORS
138144

139145
/*
@@ -302,23 +308,21 @@ boot_initialize_area(struct boot_loader_state *state, int flash_area)
302308
int num_sectors = BOOT_MAX_IMG_SECTORS;
303309
int rc;
304310

305-
switch (flash_area) {
306-
case FLASH_AREA_IMAGE_PRIMARY:
311+
if (flash_area == FLASH_AREA_IMAGE_PRIMARY) {
307312
rc = flash_area_to_sectors(flash_area, &num_sectors,
308313
state->imgs[BOOT_PRIMARY_SLOT].sectors);
309314
state->imgs[BOOT_PRIMARY_SLOT].num_sectors = (size_t)num_sectors;
310-
break;
311-
case FLASH_AREA_IMAGE_SECONDARY:
315+
316+
} else if (flash_area == FLASH_AREA_IMAGE_SECONDARY) {
312317
rc = flash_area_to_sectors(flash_area, &num_sectors,
313318
state->imgs[BOOT_SECONDARY_SLOT].sectors);
314319
state->imgs[BOOT_SECONDARY_SLOT].num_sectors = (size_t)num_sectors;
315-
break;
316-
case FLASH_AREA_IMAGE_SCRATCH:
320+
321+
} else if (flash_area == FLASH_AREA_IMAGE_SCRATCH) {
317322
rc = flash_area_to_sectors(flash_area, &num_sectors,
318323
state->scratch.sectors);
319324
state->scratch.num_sectors = (size_t)num_sectors;
320-
break;
321-
default:
325+
} else {
322326
return BOOT_EFLASH;
323327
}
324328

@@ -350,24 +354,19 @@ boot_initialize_area(struct boot_loader_state *state, int flash_area)
350354
size_t *out_num_sectors;
351355
int rc;
352356

353-
switch (flash_area) {
354-
case FLASH_AREA_IMAGE_PRIMARY:
355-
num_sectors = BOOT_MAX_IMG_SECTORS;
357+
num_sectors = BOOT_MAX_IMG_SECTORS;
358+
359+
if (flash_area == FLASH_AREA_IMAGE_PRIMARY) {
356360
out_sectors = state->imgs[BOOT_PRIMARY_SLOT].sectors;
357361
out_num_sectors = &state->imgs[BOOT_PRIMARY_SLOT].num_sectors;
358-
break;
359-
case FLASH_AREA_IMAGE_SECONDARY:
360-
num_sectors = BOOT_MAX_IMG_SECTORS;
362+
} else if (flash_area == FLASH_AREA_IMAGE_SECONDARY) {
361363
out_sectors = state->imgs[BOOT_SECONDARY_SLOT].sectors;
362364
out_num_sectors = &state->imgs[BOOT_SECONDARY_SLOT].num_sectors;
363-
break;
364-
case FLASH_AREA_IMAGE_SCRATCH:
365-
num_sectors = BOOT_MAX_IMG_SECTORS;
365+
} else if (flash_area == FLASH_AREA_IMAGE_SCRATCH) {
366366
out_sectors = state->scratch.sectors;
367367
out_num_sectors = &state->scratch.num_sectors;
368-
break;
369-
default:
370-
return -1;
368+
} else {
369+
return BOOT_EFLASH;
371370
}
372371

373372
rc = flash_area_get_sectors(flash_area, &num_sectors, out_sectors);

boot/bootutil/src/loader.c

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
MCUBOOT_LOG_MODULE_DECLARE(mcuboot);
4848

4949
static struct boot_loader_state boot_data;
50+
uint8_t current_image = 0;
5051

5152
#if defined(MCUBOOT_VALIDATE_PRIMARY_SLOT) && !defined(MCUBOOT_OVERWRITE_ONLY)
5253
static int boot_status_fails = 0;
@@ -1021,18 +1022,20 @@ boot_erase_trailer_sectors(const struct flash_area *fap)
10211022
uint32_t total_sz;
10221023
uint32_t off;
10231024
uint32_t sz;
1025+
int fa_id_primary;
1026+
int fa_id_secondary;
10241027
int rc;
10251028

10261029
BOOT_LOG_DBG("erasing trailer; fa_id=%d", fap->fa_id);
10271030

1028-
switch (fap->fa_id) {
1029-
case FLASH_AREA_IMAGE_PRIMARY:
1031+
fa_id_primary = flash_area_id_from_image_slot(BOOT_PRIMARY_SLOT);
1032+
fa_id_secondary = flash_area_id_from_image_slot(BOOT_SECONDARY_SLOT);
1033+
1034+
if (fap->fa_id == fa_id_primary) {
10301035
slot = BOOT_PRIMARY_SLOT;
1031-
break;
1032-
case FLASH_AREA_IMAGE_SECONDARY:
1036+
} else if (fap->fa_id == fa_id_secondary) {
10331037
slot = BOOT_SECONDARY_SLOT;
1034-
break;
1035-
default:
1038+
} else {
10361039
return BOOT_EFLASH;
10371040
}
10381041

boot/zephyr/flash_map_extended.c

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,12 @@ int flash_device_base(uint8_t fd_id, uintptr_t *ret)
5555
*/
5656
int flash_area_id_from_image_slot(int slot)
5757
{
58-
static const int area_id_tab[] = {FLASH_AREA_IMAGE_PRIMARY,
59-
FLASH_AREA_IMAGE_SECONDARY,
60-
FLASH_AREA_IMAGE_SCRATCH};
58+
#if (MCUBOOT_IMAGE_NUMBER == 1)
59+
static
60+
#endif
61+
const int area_id_tab[] = {FLASH_AREA_IMAGE_PRIMARY,
62+
FLASH_AREA_IMAGE_SECONDARY,
63+
FLASH_AREA_IMAGE_SCRATCH};
6164

6265
if (slot >= 0 && slot < ARRAY_SIZE(area_id_tab)) {
6366
return area_id_tab[slot];
@@ -68,15 +71,15 @@ int flash_area_id_from_image_slot(int slot)
6871

6972
int flash_area_id_to_image_slot(int area_id)
7073
{
71-
switch (area_id) {
72-
case FLASH_AREA_IMAGE_PRIMARY:
74+
if (area_id == FLASH_AREA_IMAGE_PRIMARY) {
7375
return 0;
74-
case FLASH_AREA_IMAGE_SECONDARY:
76+
}
77+
if (area_id == FLASH_AREA_IMAGE_SECONDARY) {
7578
return 1;
76-
default:
77-
BOOT_LOG_ERR("invalid flash area ID");
78-
return -1;
7979
}
80+
81+
BOOT_LOG_ERR("invalid flash area ID");
82+
return -1;
8083
}
8184

8285
int flash_area_sector_from_off(off_t off, struct flash_sector *sector)

boot/zephyr/include/mcuboot_config/mcuboot_config.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
* Copyright (c) 2018 Open Source Foundries Limited
3+
* Copyright (c) 2019 Arm Limited
34
*
45
* SPDX-License-Identifier: Apache-2.0
56
*/
@@ -65,6 +66,12 @@
6566
#define MCUBOOT_BOOTSTRAP 1
6667
#endif
6768

69+
#ifdef CONFIG_UPDATEABLE_IMAGE_NUMBER
70+
#define MCUBOOT_IMAGE_NUMBER CONFIG_UPDATEABLE_IMAGE_NUMBER
71+
#else
72+
#define MCUBOOT_IMAGE_NUMBER 1
73+
#endif
74+
6875
/*
6976
* Enabling this option uses newer flash map APIs. This saves RAM and
7077
* avoids deprecated API usage.

boot/zephyr/include/sysflash/sysflash.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,32 @@
44
#define __SYSFLASH_H__
55

66
#include <generated_dts_board.h>
7+
#include <mcuboot_config/mcuboot_config.h>
78

9+
extern uint8_t current_image;
10+
11+
#if (MCUBOOT_IMAGE_NUMBER == 1)
812
#define FLASH_AREA_IMAGE_PRIMARY DT_FLASH_AREA_IMAGE_0_ID
913
#define FLASH_AREA_IMAGE_SECONDARY DT_FLASH_AREA_IMAGE_1_ID
14+
#elif (MCUBOOT_IMAGE_NUMBER == 2)
15+
/* MCUBoot currently supports only up to 2 updateable firmware images.
16+
* If the number of the current image is greater than MCUBOOT_IMAGE_NUMBER - 1
17+
* then a dummy value will be assigned to the flash area macros.
18+
*/
19+
#define FLASH_AREA_IMAGE_PRIMARY ((current_image == 0) ? \
20+
DT_FLASH_AREA_IMAGE_0_ID : \
21+
(current_image == 1) ? \
22+
DT_FLASH_AREA_IMAGE_2_ID : \
23+
255 )
24+
#define FLASH_AREA_IMAGE_SECONDARY ((current_image == 0) ? \
25+
DT_FLASH_AREA_IMAGE_1_ID : \
26+
(current_image == 1) ? \
27+
DT_FLASH_AREA_IMAGE_3_ID : \
28+
255 )
29+
#else
30+
#error "Image slot and flash area mapping is not defined"
31+
#endif
32+
1033
#define FLASH_AREA_IMAGE_SCRATCH DT_FLASH_AREA_IMAGE_SCRATCH_ID
1134

1235
#endif /* __SYSFLASH_H__ */

boot/zephyr/include/target.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
/*
22
* Copyright (C) 2017, Linaro Ltd
3+
* Copyright (c) 2019, Arm Limited
4+
*
35
* SPDX-License-Identifier: Apache-2.0
46
*/
57

@@ -45,4 +47,11 @@
4547
#error "Target support is incomplete; cannot build mcuboot."
4648
#endif
4749

50+
#if ((MCUBOOT_IMAGE_NUMBER == 2) && (!defined(FLASH_AREA_IMAGE_2_OFFSET) || \
51+
!defined(FLASH_AREA_IMAGE_2_SIZE) || \
52+
!defined(FLASH_AREA_IMAGE_3_OFFSET) || \
53+
!defined(FLASH_AREA_IMAGE_3_SIZE)))
54+
#error "Target support is incomplete; cannot build mcuboot."
4855
#endif
56+
57+
#endif /* H_TARGETS_TARGET_ */

docs/PORTING.md

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,19 @@ struct flash_area {
8686
`fa_id` is can be one of the following options:
8787

8888
```c
89-
#define FLASH_AREA_IMAGE_PRIMARY 1
90-
#define FLASH_AREA_IMAGE_SECONDARY 2
91-
#define FLASH_AREA_IMAGE_SCRATCH 3
89+
/* Independent from multiple image boot */
90+
#define FLASH_AREA_BOOTLOADER 0
91+
#define FLASH_AREA_IMAGE_SCRATCH 3
92+
```
93+
```c
94+
/* Flash area IDs of the first image in case of multiple images */
95+
#define FLASH_AREA_IMAGE_PRIMARY 1
96+
#define FLASH_AREA_IMAGE_SECONDARY 2
97+
```
98+
```c
99+
/* Flash area IDs of the second image in case of multiple images */
100+
#define FLASH_AREA_IMAGE_PRIMARY 5
101+
#define FLASH_AREA_IMAGE_SECONDARY 6
92102
```
93103

94104
The functions that must be defined for working with the `flash_area`s are:

docs/design.md

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -116,33 +116,44 @@ region of disk with the following properties:
116116
2. A write to one area does not restrict writes to other areas.
117117

118118
The boot loader uses the following flash area IDs:
119-
120-
``` c
119+
```c
120+
/* Independent from multiple image boot */
121121
#define FLASH_AREA_BOOTLOADER 0
122+
#define FLASH_AREA_IMAGE_SCRATCH 3
123+
```
124+
```c
125+
/* If the boot loader is working with the first image */
122126
#define FLASH_AREA_IMAGE_PRIMARY 1
123127
#define FLASH_AREA_IMAGE_SECONDARY 2
124-
#define FLASH_AREA_IMAGE_SCRATCH 3
128+
```
129+
```c
130+
/* If the boot loader is working with the second image */
131+
#define FLASH_AREA_IMAGE_PRIMARY 5
132+
#define FLASH_AREA_IMAGE_SECONDARY 6
125133
```
126134

127135
The bootloader area contains the bootloader image itself. The other areas are
128-
described in subsequent sections.
136+
described in subsequent sections. The flash could contain multiple executable
137+
images therefore the flash area IDs of primary and secondary areas are mapped
138+
based on the number of the active image (on which the bootloader is currently
139+
working).
129140

130141
## Image Slots
131142

132-
A portion of the flash memory is partitioned into two image slots: a primary
133-
slot (0) and a secondary slot (1). The boot loader will only run an image from
134-
the primary slot, so images must be built such that they can run from that
135-
fixed location in flash. If the boot loader needs to run the image resident in
136-
the secondary slot, it must copy its contents into the primary slot before doing
137-
so, either by swapping the two images or by overwriting the contents of the
138-
primary slot. The bootloader supports either swap- or overwrite-based image
139-
upgrades, but must be configured at build time to choose one of these two
140-
strategies.
141-
142-
In addition to the two image slots, the boot loader requires a scratch area to
143-
allow for reliable image swapping. The scratch area must have a size that is
144-
enough to store at least the largest sector that is going to be swapped. Many
145-
devices have small equally sized flash sectors, eg 4K, while others have
143+
A portion of the flash memory can be partitioned into multiple image areas, each
144+
contains two image slots: a primary slot and a secondary slot.
145+
The boot loader will only run an image from the primary slot, so images must be
146+
built such that they can run from that fixed location in flash. If the boot
147+
loader needs to run the image resident in the secondary slot, it must copy its
148+
contents into the primary slot before doing so, either by swapping the two
149+
images or by overwriting the contents of the primary slot. The bootloader
150+
supports either swap- or overwrite-based image upgrades, but must be configured
151+
at build time to choose one of these two strategies.
152+
153+
In addition to the slots of image areas, the boot loader requires a scratch
154+
area to allow for reliable image swapping. The scratch area must have a size
155+
that is enough to store at least the largest sector that is going to be swapped.
156+
Many devices have small equally sized flash sectors, eg 4K, while others have
146157
variable sized sectors where the largest sectors might be 128K or 256K, so the
147158
scratch must be big enough to store that. The scratch is only ever used when
148159
swapping firmware, which means only when doing an upgrade. Given that, the main

0 commit comments

Comments
 (0)