Skip to content

Commit 4bc1017

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. - Call fw_info_ext_api_provide() before booting if EXT_API_PROVIDE EXT_API is enabled. This is relevant only when the immutable bootloader has booted mcuboot. 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 57cc96f) (cherry picked from commit bc4bb3b) (cherry picked from commit 8e98f3a) (cherry picked from commit e7db825) (cherry picked from commit 17f6d04) (cherry picked from commit 0a20703)
1 parent 56cd972 commit 4bc1017

File tree

11 files changed

+288
-6
lines changed

11 files changed

+288
-6
lines changed

boot/bootutil/src/loader.c

+80-5
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,15 @@ boot_read_image_headers(struct boot_loader_state *state, bool require_all,
107107
*
108108
* Failure to read any headers is a fatal error.
109109
*/
110+
#ifdef PM_S1_ADDRESS
111+
/* Patch needed for NCS. The primary slot of the second image
112+
* (image 1) will not contain a valid image header until an upgrade
113+
* of mcuboot has happened (filling S1 with the new version).
114+
*/
115+
if (BOOT_CURR_IMG(state) == 1 && i == 0) {
116+
continue;
117+
}
118+
#endif /* PM_S1_ADDRESS */
110119
if (i > 0 && !require_all) {
111120
return 0;
112121
} else {
@@ -798,7 +807,24 @@ boot_validate_slot(struct boot_loader_state *state, int slot,
798807
goto out;
799808
}
800809

801-
if (reset_value < pri_fa->fa_off || reset_value> (pri_fa->fa_off + pri_fa->fa_size)) {
810+
uint32_t min_addr, max_addr;
811+
812+
#ifdef PM_CPUNET_APP_ADDRESS
813+
/* The primary slot for the network core is emulated in RAM.
814+
* Its flash_area hasn't got relevant boundaries.
815+
* Therfore need to override its boundaries for the check.
816+
*/
817+
if (BOOT_CURR_IMG(state) == 1) {
818+
min_addr = PM_CPUNET_APP_ADDRESS;
819+
max_addr = PM_CPUNET_APP_ADDRESS + PM_CPUNET_APP_SIZE;
820+
} else
821+
#endif
822+
{
823+
min_addr = pri_fa->fa_off;
824+
max_addr = pri_fa->fa_off + pri_fa->fa_size;
825+
}
826+
827+
if (reset_value < min_addr || reset_value> (max_addr)) {
802828
BOOT_LOG_ERR("Reset address of image in secondary slot is not in the primary slot");
803829
BOOT_LOG_ERR("Erasing image from secondary slot");
804830

@@ -881,6 +907,42 @@ boot_validated_swap_type(struct boot_loader_state *state,
881907
{
882908
int swap_type;
883909
fih_int fih_rc = FIH_FAILURE;
910+
#ifdef PM_S1_ADDRESS
911+
/* Patch needed for NCS. Since image 0 (the app) and image 1 (the other
912+
* B1 slot S0 or S1) share the same secondary slot, we need to check
913+
* whether the update candidate in the secondary slot is intended for
914+
* image 0 or image 1 primary by looking at the address of the reset
915+
* vector. Note that there are good reasons for not using img_num from
916+
* the swap info.
917+
*/
918+
const struct flash_area *secondary_fa =
919+
BOOT_IMG_AREA(state, BOOT_SECONDARY_SLOT);
920+
struct image_header *hdr =
921+
(struct image_header *)secondary_fa->fa_off;
922+
923+
if (hdr->ih_magic == IMAGE_MAGIC) {
924+
const struct flash_area *primary_fa;
925+
uint32_t vtable_addr = (uint32_t)hdr + hdr->ih_hdr_size;
926+
uint32_t *vtable = (uint32_t *)(vtable_addr);
927+
uint32_t reset_addr = vtable[1];
928+
int rc = flash_area_open(
929+
flash_area_id_from_multi_image_slot(
930+
BOOT_CURR_IMG(state),
931+
BOOT_PRIMARY_SLOT),
932+
&primary_fa);
933+
934+
if (rc != 0) {
935+
return BOOT_SWAP_TYPE_FAIL;
936+
}
937+
/* Get start and end of primary slot for current image */
938+
if (reset_addr < primary_fa->fa_off ||
939+
reset_addr > (primary_fa->fa_off + primary_fa->fa_size)) {
940+
/* The image in the secondary slot is not intended for this image
941+
*/
942+
return BOOT_SWAP_TYPE_NONE;
943+
}
944+
}
945+
#endif
884946

885947
swap_type = boot_swap_type_multi(BOOT_CURR_IMG(state));
886948
if (BOOT_IS_UPGRADE(swap_type)) {
@@ -2093,10 +2155,23 @@ context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp)
20932155
}
20942156

20952157
#ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT
2096-
FIH_CALL(boot_validate_slot, fih_rc, state, BOOT_PRIMARY_SLOT, NULL);
2097-
if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
2098-
goto out;
2099-
}
2158+
#ifdef PM_S1_ADDRESS
2159+
/* Patch needed for NCS. If secure boot is enabled, then mcuboot
2160+
* will be stored in either partition S0 or S1. Image 1 primary
2161+
* will point to the 'other' Sx partition. Hence, image 1 primary
2162+
* does not contain a valid image until mcuboot has been upgraded.
2163+
* Note that B0 will perform validation of the active mcuboot image,
2164+
* so there is no security lost by skipping this check for image 1
2165+
* primary.
2166+
*/
2167+
if (BOOT_CURR_IMG(state) == 0)
2168+
#endif
2169+
{
2170+
FIH_CALL(boot_validate_slot, fih_rc, state, BOOT_PRIMARY_SLOT, NULL);
2171+
if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
2172+
goto out;
2173+
}
2174+
}
21002175
#else
21012176
/* Even if we're not re-validating the primary slot, we could be booting
21022177
* 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
@@ -170,6 +170,18 @@ boot_status_internal_off(const struct boot_status *bs, int elem_sz)
170170
int
171171
boot_slots_compatible(struct boot_loader_state *state)
172172
{
173+
#ifdef PM_S1_ADDRESS
174+
/* Patch needed for NCS. In this case, image 1 primary points to the other
175+
* B1 slot (ie S0 or S1), and image 0 primary points to the app.
176+
* With this configuration, image 0 and image 1 share the secondary slot.
177+
* Hence, the primary slot of image 1 will be *smaller* than image 1's
178+
* secondary slot. This is not allowed in upstream mcuboot, so we need
179+
* this patch to allow it. Also, all of these checks are redundant when
180+
* partition manager is in use, and since we have the same sector size
181+
* in all of our flash.
182+
*/
183+
return 1;
184+
#else
173185
size_t num_sectors_primary;
174186
size_t num_sectors_secondary;
175187
size_t sz0, sz1;
@@ -255,6 +267,7 @@ boot_slots_compatible(struct boot_loader_state *state)
255267
}
256268

257269
return 1;
270+
#endif /* PM_S1_ADDRESS */
258271
}
259272

260273
#define BOOT_LOG_SWAP_STATE(area, state) \

boot/zephyr/CMakeLists.txt

+7
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,13 @@ if(NOT CONFIG_BOOT_SIGNATURE_KEY_FILE STREQUAL "")
290290
endif()
291291
message("MCUBoot bootloader key file: ${KEY_FILE}")
292292

293+
set_property(
294+
GLOBAL
295+
PROPERTY
296+
KEY_FILE
297+
${KEY_FILE}
298+
)
299+
293300
set(GENERATED_PUBKEY ${ZEPHYR_BINARY_DIR}/autogen-pubkey.c)
294301
add_custom_command(
295302
OUTPUT ${GENERATED_PUBKEY}

boot/zephyr/Kconfig

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ mainmenu "MCUboot configuration"
88

99
comment "MCUboot-specific configuration options"
1010

11+
source "$(ZEPHYR_NRF_MODULE_DIR)/modules/mcuboot/boot/zephyr/Kconfig"
12+
1113
# Hidden option to mark a project as MCUboot
1214
config MCUBOOT
1315
default y

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
@@ -48,4 +50,6 @@
4850
#error "Target support is incomplete; cannot build mcuboot."
4951
#endif
5052

53+
#endif /* ifndef USE_PARTITION_MANAGER */
54+
5155
#endif /* H_TARGETS_TARGET_ */

boot/zephyr/main.c

+45
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@
3535
#include "bootutil/fault_injection_hardening.h"
3636
#include "flash_map_backend/flash_map_backend.h"
3737

38+
#ifdef CONFIG_FW_INFO
39+
#include <fw_info.h>
40+
#endif
41+
3842
#ifdef CONFIG_MCUBOOT_SERIAL
3943
#include "boot_serial/boot_serial.h"
4044
#include "serial_adapter/serial_adapter.h"
@@ -95,6 +99,11 @@ K_SEM_DEFINE(boot_log_sem, 1, 1);
9599
* !defined(ZEPHYR_LOG_MODE_MINIMAL)
96100
*/
97101

102+
#if USE_PARTITION_MANAGER && CONFIG_FPROTECT
103+
#include <fprotect.h>
104+
#include <pm_config.h>
105+
#endif
106+
98107
#ifdef CONFIG_SOC_FAMILY_NRF
99108
#include <helpers/nrfx_reset_reason.h>
100109

@@ -193,6 +202,19 @@ static void do_boot(struct boot_rsp *rsp)
193202
/* Disable the USB to prevent it from firing interrupts */
194203
usb_disable();
195204
#endif
205+
206+
#if defined(CONFIG_FW_INFO) && !defined(CONFIG_EXT_API_PROVIDE_EXT_API_UNUSED)
207+
bool provided = fw_info_ext_api_provide(fw_info_find((uint32_t)vt), true);
208+
209+
#ifdef PM_S0_ADDRESS
210+
/* Only fail if the immutable bootloader is present. */
211+
if (!provided) {
212+
BOOT_LOG_ERR("Failed to provide EXT_APIs\n");
213+
return;
214+
}
215+
#endif
216+
#endif
217+
196218
#if CONFIG_MCUBOOT_CLEANUP_ARM_CORE
197219
cleanup_arm_nvic(); /* cleanup NVIC registers */
198220

@@ -552,7 +574,30 @@ void main(void)
552574
#else
553575
BOOT_LOG_INF("Jumping to the first image slot");
554576
#endif
577+
578+
#if USE_PARTITION_MANAGER && CONFIG_FPROTECT
579+
580+
#ifdef PM_S1_ADDRESS
581+
/* MCUBoot is stored in either S0 or S1, protect both */
582+
#define PROTECT_SIZE (PM_MCUBOOT_PRIMARY_ADDRESS - PM_S0_ADDRESS)
583+
#define PROTECT_ADDR PM_S0_ADDRESS
584+
#else
585+
/* There is only one instance of MCUBoot */
586+
#define PROTECT_SIZE (PM_MCUBOOT_PRIMARY_ADDRESS - PM_MCUBOOT_ADDRESS)
587+
#define PROTECT_ADDR PM_MCUBOOT_ADDRESS
588+
#endif
589+
590+
rc = fprotect_area(PROTECT_ADDR, PROTECT_SIZE);
591+
592+
if (rc != 0) {
593+
BOOT_LOG_ERR("Protect mcuboot flash failed, cancel startup.");
594+
while (1)
595+
;
596+
}
597+
#endif /* USE_PARTITION_MANAGER && CONFIG_FPROTECT */
598+
555599
ZEPHYR_BOOT_LOG_STOP();
600+
556601
do_boot(&rsp);
557602

558603
BOOT_LOG_ERR("Never should get here");

0 commit comments

Comments
 (0)