Skip to content

Commit 4eba780

Browse files
SebastianBoembolivar-nordic
authored andcommitted
[nrf noup] treewide: add NCS partition manager support
Partition Manager is an nRF Connect SDK component which uses yaml files to resolve flash partition placement with a holistic view of the device. This component's MCUboot portions began life as upstream mcuboot PR#430. This added support for being built as a sub image from the downstream Nordic patch set for a zephyr multi image build system (mcuboot 430 was combined with effor submitted to upstream zephyr as PR#13672, which was ultimately reworked after being rejected for mainline at the ELCE 2019 conference in Lyon). It has since evolved over time. This is the version that will go into NCS v1.3. It features: - page size aligned partitions for all partitions used by mcuboot. - image swaps without scratch partitions Add support for configurations where there exists two primary slots but only one secondary slot, which is shared. These two primary slots are the regular application and B1. B1 can be either S0 or S1 depending on the state of the device. Decide where an upgrade should be stored by looking at the vector table. Provide update candidates for both s0 and s1. These candidates must be signed with mcuboot after being signed by b0. Additional notes: - we make update.hex without trailer data This is needed for serial recovery to work using hex files. Prior to this the update.hex got TLV data at the end of the partition, which caused many blank pages to be included, which made it hard to use in a serial recovery scheme. Instead, make update.hex without TLV data at the end, and provide a new file test_update.hex which contains the TLV data, and can be directly flashed to test the upgrade procedure. - we use a function for signing the application as future-proofing for when other components must be signed as well - this includes an update to single image applications that enables support for partition manager; when single image DFU is used, a scratch partition is not needed. - In NCS, image 1 primary slot is the upgrade bank for mcuboot (IE S0 or S1 depending on the active slot). It is not required that this slot contains any valid data. - The nRF boards all have a single flash page size, and partition manager deals with the size of the update partitions and so on, so we must skip a boot_slots_compatible() check to avoid getting an error. - There is no need to verify the target when using partition manager. - We lock mcuboot using fprotect before jumping, to enable the secure boot property of the system. Signed-off-by: Håkon Øye Amundsen <haakon.amundsen@nordicsemi.no> Signed-off-by: Øyvind Rønningstad <oyvind.ronningstad@nordicsemi.no> Signed-off-by: Sebastian Bøe <sebastian.boe@nordicsemi.no> Signed-off-by: Sigvart Hovland <sigvart.m@gmail.com> Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no> Signed-off-by: Torsten Rasmussen <Torsten.Rasmussen@nordicsemi.no> Signed-off-by: Andrzej Głąbek <andrzej.glabek@nordicsemi.no> Signed-off-by: Robert Lubos <robert.lubos@nordicsemi.no> Signed-off-by: Andrzej Puzdrowski <andrzej.puzdrowski@nordicsemi.no> Signed-off-by: Dominik Ermel <dominik.ermel@nordicsemi.no> Signed-off-by: Emil Obalski <emil.obalski@nordicsemi.no> Signed-off-by: Torsten Rasmussen <Torsten.Rasmussen@nordicsemi.no> Signed-off-by: Pawel Dunaj <pawel.dunaj@nordicsemi.no> Signed-off-by: Ioannis Glaropoulos <Ioannis.Glaropoulos@nordicsemi.no> Signed-off-by: Johann Fischer <johann.fischer@nordicsemi.no> Signed-off-by: Vidar Berg <vidar.berg@nordicsemi.no> Signed-off-by: Draus, Sebastian <sebastian.draus@nordicsemi.no> Signed-off-by: Trond Einar Snekvik <Trond.Einar.Snekvik@nordicsemi.no> (cherry picked from commit 60e1d4b) (cherry picked from commit d84e34f) (cherry picked from commit 669b951) (cherry picked from commit 280bc15) (cherry picked from commit 262ef98) (cherry picked from commit 28db522) (cherry picked from commit 9efa2fd)
1 parent 3eff777 commit 4eba780

File tree

11 files changed

+240
-6
lines changed

11 files changed

+240
-6
lines changed

boot/bootutil/src/loader.c

+62-4
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,15 @@ boot_read_image_headers(struct boot_loader_state *state, bool require_all,
108108
*
109109
* Failure to read any headers is a fatal error.
110110
*/
111+
#ifdef PM_S1_ADDRESS
112+
/* Patch needed for NCS. The primary slot of the second image
113+
* (image 1) will not contain a valid image header until an upgrade
114+
* of mcuboot has happened (filling S1 with the new version).
115+
*/
116+
if (BOOT_CURR_IMG(state) == 1 && i == 0) {
117+
continue;
118+
}
119+
#endif /* PM_S1_ADDRESS */
111120
if (i > 0 && !require_all) {
112121
return 0;
113122
} else {
@@ -839,6 +848,42 @@ boot_validated_swap_type(struct boot_loader_state *state,
839848
{
840849
int swap_type;
841850
fih_int fih_rc = FIH_FAILURE;
851+
#ifdef PM_S1_ADDRESS
852+
/* Patch needed for NCS. Since image 0 (the app) and image 1 (the other
853+
* B1 slot S0 or S1) share the same secondary slot, we need to check
854+
* whether the update candidate in the secondary slot is intended for
855+
* image 0 or image 1 primary by looking at the address of the reset
856+
* vector. Note that there are good reasons for not using img_num from
857+
* the swap info.
858+
*/
859+
const struct flash_area *secondary_fa =
860+
BOOT_IMG_AREA(state, BOOT_SECONDARY_SLOT);
861+
struct image_header *hdr =
862+
(struct image_header *)secondary_fa->fa_off;
863+
864+
if (hdr->ih_magic == IMAGE_MAGIC) {
865+
const struct flash_area *primary_fa;
866+
uint32_t vtable_addr = (uint32_t)hdr + hdr->ih_hdr_size;
867+
uint32_t *vtable = (uint32_t *)(vtable_addr);
868+
uint32_t reset_addr = vtable[1];
869+
int rc = flash_area_open(
870+
flash_area_id_from_multi_image_slot(
871+
BOOT_CURR_IMG(state),
872+
BOOT_PRIMARY_SLOT),
873+
&primary_fa);
874+
875+
if (rc != 0) {
876+
return BOOT_SWAP_TYPE_FAIL;
877+
}
878+
/* Get start and end of primary slot for current image */
879+
if (reset_addr < primary_fa->fa_off ||
880+
reset_addr > (primary_fa->fa_off + primary_fa->fa_size)) {
881+
/* The image in the secondary slot is not intended for this image
882+
*/
883+
return BOOT_SWAP_TYPE_NONE;
884+
}
885+
}
886+
#endif
842887

843888
swap_type = boot_swap_type_multi(BOOT_CURR_IMG(state));
844889
if (BOOT_IS_UPGRADE(swap_type)) {
@@ -2007,10 +2052,23 @@ context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp)
20072052
}
20082053

20092054
#ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT
2010-
FIH_CALL(boot_validate_slot, fih_rc, state, BOOT_PRIMARY_SLOT, NULL);
2011-
if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
2012-
goto out;
2013-
}
2055+
#ifdef PM_S1_ADDRESS
2056+
/* Patch needed for NCS. If secure boot is enabled, then mcuboot
2057+
* will be stored in either partition S0 or S1. Image 1 primary
2058+
* will point to the 'other' Sx partition. Hence, image 1 primary
2059+
* does not contain a valid image until mcuboot has been upgraded.
2060+
* Note that B0 will perform validation of the active mcuboot image,
2061+
* so there is no security lost by skipping this check for image 1
2062+
* primary.
2063+
*/
2064+
if (BOOT_CURR_IMG(state) == 0)
2065+
#endif
2066+
{
2067+
FIH_CALL(boot_validate_slot, fih_rc, state, BOOT_PRIMARY_SLOT, NULL);
2068+
if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
2069+
goto out;
2070+
}
2071+
}
20142072
#else
20152073
/* Even if we're not re-validating the primary slot, we could be booting
20162074
* onto an empty flash chip. At least do a basic sanity check that

boot/bootutil/src/swap_move.c

+13
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,18 @@ boot_status_internal_off(const struct boot_status *bs, int elem_sz)
211211
int
212212
boot_slots_compatible(struct boot_loader_state *state)
213213
{
214+
#ifdef PM_S1_ADDRESS
215+
/* Patch needed for NCS. In this case, image 1 primary points to the other
216+
* B1 slot (ie S0 or S1), and image 0 primary points to the app.
217+
* With this configuration, image 0 and image 1 share the secondary slot.
218+
* Hence, the primary slot of image 1 will be *smaller* than image 1's
219+
* secondary slot. This is not allowed in upstream mcuboot, so we need
220+
* this patch to allow it. Also, all of these checks are redundant when
221+
* partition manager is in use, and since we have the same sector size
222+
* in all of our flash.
223+
*/
224+
return 1;
225+
#else
214226
size_t num_sectors_pri;
215227
size_t num_sectors_sec;
216228
size_t sector_sz_pri = 0;
@@ -247,6 +259,7 @@ boot_slots_compatible(struct boot_loader_state *state)
247259
}
248260

249261
return 1;
262+
#endif /* PM_S1_ADDRESS */
250263
}
251264

252265
#define BOOT_LOG_SWAP_STATE(area, state) \

boot/bootutil/src/swap_scratch.c

+13
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,18 @@ boot_status_internal_off(const struct boot_status *bs, int elem_sz)
175175
int
176176
boot_slots_compatible(struct boot_loader_state *state)
177177
{
178+
#ifdef PM_S1_ADDRESS
179+
/* Patch needed for NCS. In this case, image 1 primary points to the other
180+
* B1 slot (ie S0 or S1), and image 0 primary points to the app.
181+
* With this configuration, image 0 and image 1 share the secondary slot.
182+
* Hence, the primary slot of image 1 will be *smaller* than image 1's
183+
* secondary slot. This is not allowed in upstream mcuboot, so we need
184+
* this patch to allow it. Also, all of these checks are redundant when
185+
* partition manager is in use, and since we have the same sector size
186+
* in all of our flash.
187+
*/
188+
return 1;
189+
#else
178190
size_t num_sectors_primary;
179191
size_t num_sectors_secondary;
180192
size_t sz0, sz1;
@@ -260,6 +272,7 @@ boot_slots_compatible(struct boot_loader_state *state)
260272
}
261273

262274
return 1;
275+
#endif /* PM_S1_ADDRESS */
263276
}
264277

265278
#define BOOT_LOG_SWAP_STATE(area, state) \

boot/zephyr/CMakeLists.txt

+7
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,13 @@ if(NOT CONFIG_BOOT_SIGNATURE_KEY_FILE STREQUAL "")
276276
endif()
277277
message("MCUBoot bootloader key file: ${KEY_FILE}")
278278

279+
set_property(
280+
GLOBAL
281+
PROPERTY
282+
KEY_FILE
283+
${KEY_FILE}
284+
)
285+
279286
set(GENERATED_PUBKEY ${ZEPHYR_BINARY_DIR}/autogen-pubkey.c)
280287
add_custom_command(
281288
OUTPUT ${GENERATED_PUBKEY}

boot/zephyr/Kconfig

+12-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,18 @@ config MCUBOOT
1616
select USE_DT_CODE_PARTITION if HAS_FLASH_LOAD_OFFSET
1717
select MCUBOOT_BOOTUTIL_LIB
1818

19+
partition=MCUBOOT
20+
partition-size=0xc000
21+
source "${ZEPHYR_BASE}/../nrf/subsys/partition_manager/Kconfig.template.partition_size"
22+
23+
partition=MCUBOOT_SCRATCH
24+
partition-size=0x1e000
25+
source "${ZEPHYR_BASE}/../nrf/subsys/partition_manager/Kconfig.template.partition_size"
26+
27+
partition=MCUBOOT_PAD
28+
partition-size=0x200
29+
source "${ZEPHYR_BASE}/../nrf/subsys/partition_manager/Kconfig.template.partition_size"
30+
1931
config BOOT_USE_MBEDTLS
2032
bool
2133
# Hidden option
@@ -134,7 +146,6 @@ config BOOT_SIGNATURE_KEY_FILE
134146
default "root-ed25519.pem" if BOOT_SIGNATURE_TYPE_ED25519
135147
default "root-rsa-3072.pem" if BOOT_SIGNATURE_TYPE_RSA && BOOT_SIGNATURE_TYPE_RSA_LEN=3072
136148
default "root-rsa-2048.pem" if BOOT_SIGNATURE_TYPE_RSA && BOOT_SIGNATURE_TYPE_RSA_LEN=2048
137-
default ""
138149
help
139150
You can use either absolute or relative path.
140151
In case relative path is used, the build system assumes that it starts

boot/zephyr/include/sysflash/sysflash.h

+47
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,51 @@
33
#ifndef __SYSFLASH_H__
44
#define __SYSFLASH_H__
55

6+
#if USE_PARTITION_MANAGER
7+
#include <pm_config.h>
8+
#include <mcuboot_config/mcuboot_config.h>
9+
10+
#ifndef CONFIG_SINGLE_APPLICATION_SLOT
11+
12+
#if (MCUBOOT_IMAGE_NUMBER == 1)
13+
14+
#define FLASH_AREA_IMAGE_PRIMARY(x) PM_MCUBOOT_PRIMARY_ID
15+
#define FLASH_AREA_IMAGE_SECONDARY(x) PM_MCUBOOT_SECONDARY_ID
16+
17+
#elif (MCUBOOT_IMAGE_NUMBER == 2)
18+
19+
extern uint32_t _image_1_primary_slot_id[];
20+
21+
#define FLASH_AREA_IMAGE_PRIMARY(x) \
22+
((x == 0) ? \
23+
PM_MCUBOOT_PRIMARY_ID : \
24+
(x == 1) ? \
25+
(uint32_t)_image_1_primary_slot_id : \
26+
255 )
27+
28+
#define FLASH_AREA_IMAGE_SECONDARY(x) \
29+
((x == 0) ? \
30+
PM_MCUBOOT_SECONDARY_ID: \
31+
(x == 1) ? \
32+
PM_MCUBOOT_SECONDARY_ID: \
33+
255 )
34+
#endif
35+
#define FLASH_AREA_IMAGE_SCRATCH PM_MCUBOOT_SCRATCH_ID
36+
37+
#else /* CONFIG_SINGLE_APPLICATION_SLOT */
38+
39+
#define FLASH_AREA_IMAGE_PRIMARY(x) PM_MCUBOOT_PRIMARY_ID
40+
#define FLASH_AREA_IMAGE_SECONDARY(x) PM_MCUBOOT_PRIMARY_ID
41+
/* NOTE: Scratch parition is not used by single image DFU but some of
42+
* functions in common files reference it, so the definitions has been
43+
* provided to allow compilation of common units.
44+
*/
45+
#define FLASH_AREA_IMAGE_SCRATCH 0
46+
47+
#endif /* CONFIG_SINGLE_APPLICATION_SLOT */
48+
49+
#else
50+
651
#include <devicetree.h>
752
#include <mcuboot_config/mcuboot_config.h>
853

@@ -55,4 +100,6 @@
55100

56101
#endif /* CONFIG_SINGLE_APPLICATION_SLOT */
57102

103+
#endif /* USE_PARTITION_MANAGER */
104+
58105
#endif /* __SYSFLASH_H__ */

boot/zephyr/include/target.h

+4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
#ifndef H_TARGETS_TARGET_
99
#define H_TARGETS_TARGET_
1010

11+
#ifndef USE_PARTITION_MANAGER
12+
1113
#if defined(MCUBOOT_TARGET_CONFIG)
1214
/*
1315
* Target-specific definitions are permitted in legacy cases that
@@ -47,4 +49,6 @@
4749
#error "Target support is incomplete; cannot build mcuboot."
4850
#endif
4951

52+
#endif /* ifndef USE_PARTITION_MANAGER */
53+
5054
#endif /* H_TARGETS_TARGET_ */

boot/zephyr/main.c

+28
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,11 @@ K_SEM_DEFINE(boot_log_sem, 1, 1);
8585
#define ZEPHYR_BOOT_LOG_STOP() do { } while (false)
8686
#endif /* defined(CONFIG_LOG) && !defined(CONFIG_LOG_IMMEDIATE) */
8787

88+
#if USE_PARTITION_MANAGER && CONFIG_FPROTECT
89+
#include <fprotect.h>
90+
#include <pm_config.h>
91+
#endif
92+
8893
#ifdef CONFIG_SOC_FAMILY_NRF
8994
#include <hal/nrf_power.h>
9095

@@ -526,7 +531,30 @@ void main(void)
526531
#else
527532
BOOT_LOG_INF("Jumping to the first image slot");
528533
#endif
534+
535+
#if USE_PARTITION_MANAGER && CONFIG_FPROTECT
536+
537+
#ifdef PM_S1_ADDRESS
538+
/* MCUBoot is stored in either S0 or S1, protect both */
539+
#define PROTECT_SIZE (PM_MCUBOOT_PRIMARY_ADDRESS - PM_S0_ADDRESS)
540+
#define PROTECT_ADDR PM_S0_ADDRESS
541+
#else
542+
/* There is only one instance of MCUBoot */
543+
#define PROTECT_SIZE (PM_MCUBOOT_PRIMARY_ADDRESS - PM_MCUBOOT_ADDRESS)
544+
#define PROTECT_ADDR PM_MCUBOOT_ADDRESS
545+
#endif
546+
547+
rc = fprotect_area(PROTECT_ADDR, PROTECT_SIZE);
548+
549+
if (rc != 0) {
550+
BOOT_LOG_ERR("Protect mcuboot flash failed, cancel startup.");
551+
while (1)
552+
;
553+
}
554+
#endif /* USE_PARTITION_MANAGER && CONFIG_FPROTECT */
555+
529556
ZEPHYR_BOOT_LOG_STOP();
557+
530558
do_boot(&rsp);
531559

532560
BOOT_LOG_ERR("Never should get here");

boot/zephyr/pm.yml

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#include <autoconf.h>
2+
3+
mcuboot:
4+
size: CONFIG_PM_PARTITION_SIZE_MCUBOOT
5+
placement:
6+
before: [mcuboot_primary]
7+
8+
mcuboot_primary_app:
9+
# All images to be placed in MCUboot's slot 0 should be placed in this
10+
# partition
11+
span: [app]
12+
13+
mcuboot_primary:
14+
span: [mcuboot_pad, mcuboot_primary_app]
15+
16+
# Partition for secondary slot is not created if building in single application
17+
# slot configuration.
18+
#if !defined(CONFIG_SINGLE_APPLICATION_SLOT)
19+
mcuboot_secondary:
20+
#if defined(CONFIG_PM_EXTERNAL_FLASH_MCUBOOT_SECONDARY)
21+
region: external_flash
22+
size: CONFIG_PM_PARTITION_SIZE_MCUBOOT_SECONDARY
23+
placement:
24+
align: {start: 4}
25+
#else
26+
share_size: [mcuboot_primary]
27+
placement:
28+
align: {start: CONFIG_FPROTECT_BLOCK_SIZE}
29+
after: mcuboot_primary
30+
#endif /* CONFIG_PM_EXTERNAL_FLASH_MCUBOOT_SECONDARY */
31+
#endif /* !defined(CONFIG_SINGLE_APPLICATION_SLOT) */
32+
33+
#if !defined(CONFIG_BOOT_SWAP_USING_MOVE) && !defined(CONFIG_SINGLE_APPLICATION_SLOT) && !defined(CONFIG_BOOT_UPGRADE_ONLY)
34+
mcuboot_scratch:
35+
size: CONFIG_PM_PARTITION_SIZE_MCUBOOT_SCRATCH
36+
placement:
37+
after: app
38+
align: {start: CONFIG_FPROTECT_BLOCK_SIZE}
39+
#endif
40+
41+
# Padding placed before image to boot. This reserves space for the MCUboot image header
42+
# and it ensures that the boot image gets linked with the correct address offset in flash.
43+
mcuboot_pad:
44+
# MCUboot pad must be placed before the 'spm' partition if that is present.
45+
# If 'spm' partition is not present, it must be placed before the 'app'.
46+
size: CONFIG_PM_PARTITION_SIZE_MCUBOOT_PAD
47+
placement:
48+
before: [mcuboot_primary_app]
49+
#ifdef CONFIG_FPROTECT
50+
align: {start: CONFIG_FPROTECT_BLOCK_SIZE}
51+
#endif

boot/zephyr/prj.conf

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ CONFIG_BOOT_BOOTSTRAP=n
2424
# CONFIG_TINYCRYPT_SHA256 is not set
2525

2626
CONFIG_FLASH=y
27+
CONFIG_FPROTECT=y
2728

2829
### Various Zephyr boards enable features that we don't want.
2930
# CONFIG_BT is not set

zephyr/module.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
samples:
22
- boot/zephyr
33
build:
4-
cmake: ./boot/bootutil/zephyr
4+
cmake-ext: True
5+
kconfig-ext: True

0 commit comments

Comments
 (0)