Skip to content

Commit 8554eb5

Browse files
committed
tests: bootloader: NSIB MCUBoot locks
complete set of tests for region 3 and 4 lockouts. Signed-off-by: Mateusz Michalek <[email protected]>
1 parent 5d6e34d commit 8554eb5

File tree

10 files changed

+288
-114
lines changed

10 files changed

+288
-114
lines changed

subsys/bootloader/Kconfig

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,13 +105,27 @@ config SB_CLEANUP_RAM
105105
help
106106
Sets contents of memory to 0 before jumping to application.
107107

108+
config SB_INFINITE_LOOP_AFTER_RAM_CLEANUP
109+
bool "Infinite loop after RAM cleanup"
110+
depends on SB_CLEANUP_RAM
111+
help
112+
Verification option that keeps execution in infinite loop after
113+
RAM cleanup has been performed.
114+
108115
config SB_DISABLE_SELF_RWX
109116
bool "Disable read and execution on self NVM"
110117
depends on (SOC_NRF54L15_CPUAPP || SOC_NRF54L05_CPUAPP || SOC_NRF54L10_CPUAPP) && !FPROTECT_ALLOW_COMBINED_REGIONS
111118
help
112119
Sets RRAMC's BOOTCONF region protection before jumping to application.
113120
It disables reads writes and execution memory area which holds NSIB.
114121

122+
config SB_DISABLE_NEXT_W
123+
bool "Disable writes for next stage"
124+
depends on (SOC_NRF54L15_CPUAPP || SOC_NRF54L05_CPUAPP || SOC_NRF54L10_CPUAPP) && !FPROTECT
125+
help
126+
NSIB disables writes on next stage in bootloading chain.
127+
It uses RRAMC's region 4 and is limited to 31KB.
128+
115129
endif # IS_SECURE_BOOTLOADER
116130

117131
config IS_BOOTLOADER_IMG

subsys/bootloader/bl_boot/bl_boot.c

Lines changed: 133 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -19,25 +19,144 @@
1919
#include <hal/nrf_gpio.h>
2020
#endif
2121

22+
#include <zephyr/linker/linker-defs.h>
23+
#define CLEANUP_RAM_GAP_START ((int)__ramfunc_region_start)
24+
#define CLEANUP_RAM_GAP_SIZE ((int) (__ramfunc_end - __ramfunc_region_start))
25+
26+
#if defined(CONFIG_SB_DISABLE_NEXT_W)
27+
#include <hal/nrf_rramc.h>
28+
#define RRAMC_REGION_FOR_NEXT_W 4
29+
#define NRF_RRAM_REGION_SIZE_UNIT 0x400
30+
#define NRF_RRAM_REGION_ADDRESS_RESOLUTION 0x400
31+
#define NEXT_W_SIZE_KB (PM_MCUBOOT_SIZE / NRF_RRAM_REGION_SIZE_UNIT)
32+
33+
BUILD_ASSERT((PM_MCUBOOT_ADDRESS % NRF_RRAM_REGION_ADDRESS_RESOLUTION) == 0,
34+
"Start of protected region is not aligned");
35+
36+
BUILD_ASSERT((PM_MCUBOOT_SIZE % NRF_RRAM_REGION_SIZE_UNIT) == 0,
37+
"Size of protected region is not aligned");
38+
39+
BUILD_ASSERT(NEXT_W_SIZE_KB < 31,
40+
"Size of requested protection is too big");
41+
42+
static int disable_next_w(void)
43+
{
44+
nrf_rramc_region_config_t config = {
45+
.address = PM_MCUBOOT_ADDRESS,
46+
.permissions = NRF_RRAMC_REGION_PERM_READ_MASK |
47+
NRF_RRAMC_REGION_PERM_EXECUTE_MASK,
48+
.writeonce = false,
49+
.lock = false,
50+
.size_kb = NEXT_W_SIZE_KB,
51+
};
52+
53+
nrf_rramc_region_config_set(NRF_RRAMC, RRAMC_REGION_FOR_NEXT_W, &config);
54+
nrf_rramc_region_config_get(NRF_RRAMC, RRAMC_REGION_FOR_NEXT_W, &config);
55+
if (config.permissions & (NRF_RRAMC_REGION_PERM_WRITE_MASK)) {
56+
return -ENOSPC;
57+
}
58+
if (config.size_kb != NEXT_W_SIZE_KB) {
59+
return -ENOSPC;
60+
}
61+
62+
return 0;
63+
}
64+
65+
#endif
66+
2267
#if defined(CONFIG_SB_DISABLE_SELF_RWX)
2368
/* Disabling R_X has to be done while running from RAM for obvious reasons.
2469
* Moreover as a last step before jumping to application it must work even after
25-
* RAM has been cleared, therefore we are using custom RAM function relocator.
26-
* This relocator runs after RAM cleanup.
27-
* Size of the relocated 'locking' function isn't known but it doesn't matter
28-
* as long as at least entire aforementioned function is copied to RAM.
70+
* RAM has been cleared, therefore these operations are performed while executing from RAM.
71+
* RAM cleanup ommits portion of the memory where code lives.
2972
*/
3073
#include <hal/nrf_rramc.h>
3174

32-
#define FUNCTION_BUFFER_LEN 64
3375
#define RRAMC_REGION_RWX_LSB 0
3476
#define RRAMC_REGION_RWX_WIDTH 3
3577
#define RRAMC_REGION_TO_LOCK_ADDR NRF_RRAMC->REGION[3].CONFIG
3678
#define RRAMC_REGION_TO_LOCK_ADDR_H (((uint32_t)(&(RRAMC_REGION_TO_LOCK_ADDR))) >> 16)
3779
#define RRAMC_REGION_TO_LOCK_ADDR_L (((uint32_t)(&(RRAMC_REGION_TO_LOCK_ADDR))) & 0x0000fffful)
38-
static uint8_t ram_exec_buf[FUNCTION_BUFFER_LEN];
3980
#endif /* CONFIG_SB_DISABLE_SELF_RWX */
4081

82+
static void __ramfunc jump_in(uint32_t reset)
83+
{
84+
__asm__ volatile (
85+
/* reset -> r0 */
86+
" mov r0, %0\n"
87+
#ifdef CONFIG_SB_CLEANUP_RAM
88+
/* Base to write -> r1 */
89+
" mov r1, %1\n"
90+
/* Size to write -> r2 */
91+
" mov r2, %2\n"
92+
/* Value to write -> r3 */
93+
" movw r3, %5\n"
94+
/* gap start */
95+
" mov r4, %3\n"
96+
/* gap size */
97+
" mov r5, %4\n"
98+
"clear:\n"
99+
" subs r6, r4, r1\n"
100+
" cbnz r6, skip_gap\n"
101+
" add r1, r5\n"
102+
"skip_gap:\n"
103+
" str r3, [r1]\n"
104+
" add r1, r1, #1\n"
105+
" sub r2, r2, #1\n"
106+
" cbz r2, clear_end\n"
107+
" b clear\n"
108+
"clear_end:\n"
109+
" dsb\n"
110+
#ifdef CONFIG_SB_INFINITE_LOOP_AFTER_RAM_CLEANUP
111+
" b clear_end\n"
112+
#endif /* CONFIG_SB_INFINITE_LOOP_AFTER_RAM_CLEANUP */
113+
#endif /* CONFIG_SB_CLEANUP_RAM */
114+
115+
#ifdef CONFIG_SB_DISABLE_SELF_RWX
116+
".thumb_func\n"
117+
"bootconf_disable_rwx:\n"
118+
" movw r1, %6\n"
119+
" movt r1, %7\n"
120+
" ldr r2, [r1]\n"
121+
/* Size of the region should be set at this point
122+
* by provisioning through BOOTCONF.
123+
* If not, set it according partition size.
124+
*/
125+
" ands r4, r2, %12\n"
126+
" cbnz r4, clear_rwx\n"
127+
" movt r2, %8\n"
128+
"clear_rwx:\n"
129+
" bfc r2, %9, %10\n"
130+
/* Disallow further modifications */
131+
" orr r2, %11\n"
132+
" str r2, [r1]\n"
133+
" dsb\n"
134+
/* Next assembly line is important for current function */
135+
136+
#endif /* CONFIG_SB_DISABLE_SELF_RWX */
137+
138+
/* Jump to reset vector of an app */
139+
" bx r0\n"
140+
:
141+
: "r" (reset),
142+
"i" (CONFIG_SRAM_BASE_ADDRESS),
143+
"i" (CONFIG_SRAM_SIZE * 1024),
144+
"r" (CLEANUP_RAM_GAP_START),
145+
"r" (CLEANUP_RAM_GAP_SIZE),
146+
"i" (0)
147+
#ifdef CONFIG_SB_DISABLE_SELF_RWX
148+
, "i" (RRAMC_REGION_TO_LOCK_ADDR_L),
149+
"i" (RRAMC_REGION_TO_LOCK_ADDR_H),
150+
"i" (CONFIG_PM_PARTITION_SIZE_B0_IMAGE / 1024),
151+
"i" (RRAMC_REGION_RWX_LSB),
152+
"i" (RRAMC_REGION_RWX_WIDTH),
153+
"i" (RRAMC_REGION_CONFIG_LOCK_Msk),
154+
"i" (RRAMC_REGION_CONFIG_SIZE_Msk)
155+
#endif /* CONFIG_SB_DISABLE_SELF_RWX */
156+
: "r0", "r1", "r2", "r3", "r4", "r5", "r6", "memory"
157+
);
158+
}
159+
41160
#ifdef CONFIG_UART_NRFX_UARTE
42161
static void uninit_used_uarte(NRF_UARTE_Type *p_reg)
43162
{
@@ -163,6 +282,13 @@ void bl_boot(const struct fw_info *fw_info)
163282
VTOR = fw_info->address;
164283
uint32_t *vector_table = (uint32_t *)fw_info->address;
165284

285+
#if defined(CONFIG_SB_DISABLE_NEXT_W)
286+
if (disable_next_w()) {
287+
printk("Unable to disable writes on next stage.");
288+
return;
289+
}
290+
#endif
291+
166292
#if defined(CONFIG_BUILTIN_STACK_GUARD) && \
167293
defined(CONFIG_CPU_CORTEX_M_HAS_SPLIM)
168294
/* Reset limit registers to avoid inflicting stack overflow on image
@@ -175,96 +301,7 @@ void bl_boot(const struct fw_info *fw_info)
175301
__set_MSP(vector_table[0]);
176302
__set_PSP(0);
177303

178-
__asm__ volatile (
179-
/* vector_table[1] -> r0 */
180-
" mov r0, %0\n"
181-
#ifdef CONFIG_SB_CLEANUP_RAM
182-
/* Base to write -> r1 */
183-
" mov r1, %1\n"
184-
/* Size to write -> r2 */
185-
" mov r2, %2\n"
186-
/* Value to write -> r3 */
187-
" movw r3, %3\n"
188-
"clear:\n"
189-
" str r3, [r1]\n"
190-
" add r1, r1, #4\n"
191-
" sub r2, r2, #4\n"
192-
" cbz r2, out\n"
193-
" b clear\n"
194-
"out:\n"
195-
" dsb\n"
196-
#endif /* CONFIG_SB_CLEANUP_RAM */
197-
198-
#ifdef CONFIG_SB_DISABLE_SELF_RWX
199-
/* FUNCTION_BUFFER_LEN */
200-
" movw r4, %4\n"
201-
/* Address of ram_exec_buf goes to r2 */
202-
" mov r2, %5\n"
203-
" movw r3, :lower16:bootconf_disable_rwx\n"
204-
" movt r3, :upper16:bootconf_disable_rwx\n"
205-
/* Adjust address for thumb */
206-
" and r3, #0xfffffffe\n"
207-
/* Address of ram_exec_buf also goes to r5 */
208-
" mov r5, %5\n"
209-
/* Adjust buffer address for thumb */
210-
" orr r5, #0x1\n"
211-
/* End of the copy address in r4 */
212-
" add r4, r2\n"
213-
"ram_cpy:\n"
214-
/* Read and increment */
215-
" ldrb r1, [r3], #1\n"
216-
/* Write and increment */
217-
" strb r1, [r2], #1\n"
218-
/* Check if end address is reached */
219-
" cmp r2, r4\n"
220-
" bne ram_cpy\n"
221-
" dsb\n"
222-
/* Jump to ram */
223-
" bx r5\n"
224-
/* CODE_UNREACHABLE */
225-
226-
".thumb_func\n"
227-
"bootconf_disable_rwx:\n"
228-
" movw r1, %6\n"
229-
" movt r1, %7\n"
230-
" ldr r2, [r1]\n"
231-
/* Size of the region should be set at this point
232-
* by provisioning through BOOTCONF.
233-
* If not, set it according partition size.
234-
*/
235-
" ands r4, r2, %12\n"
236-
" cbnz r4, clear_rwx\n"
237-
" movt r2, %8\n"
238-
"clear_rwx:\n"
239-
" bfc r2, %9, %10\n"
240-
/* Disallow further modifications */
241-
" orr r2, %11\n"
242-
" str r2, [r1]\n"
243-
" dsb\n"
244-
/* Next assembly line is important for current function */
245-
246-
#endif /* CONFIG_SB_DISABLE_SELF_RWX */
247-
248-
/* Jump to reset vector of an app */
249-
" bx r0\n"
250-
:
251-
: "r" (vector_table[1]),
252-
"i" (CONFIG_SRAM_BASE_ADDRESS),
253-
"i" (CONFIG_SRAM_SIZE * 1024),
254-
"i" (0)
255-
#ifdef CONFIG_SB_DISABLE_SELF_RWX
256-
, "i" (FUNCTION_BUFFER_LEN),
257-
"r" (ram_exec_buf),
258-
"i" (RRAMC_REGION_TO_LOCK_ADDR_L),
259-
"i" (RRAMC_REGION_TO_LOCK_ADDR_H),
260-
"i" (CONFIG_PM_PARTITION_SIZE_B0_IMAGE / 1024),
261-
"i" (RRAMC_REGION_RWX_LSB),
262-
"i" (RRAMC_REGION_RWX_WIDTH),
263-
"i" (RRAMC_REGION_CONFIG_LOCK_Msk),
264-
"i" (RRAMC_REGION_CONFIG_SIZE_Msk)
265-
#endif /* CONFIG_SB_DISABLE_SELF_RWX */
266-
: "r0", "r1", "r2", "r3", "r4", "r5", "memory"
267-
);
304+
jump_in((vector_table[1]));
268305

269306
CODE_UNREACHABLE;
270307
}

tests/subsys/bootloader/b0_lock/testcase.yaml

Lines changed: 0 additions & 11 deletions
This file was deleted.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#
2+
# Copyright (c) 2022 Nordic Semiconductor
3+
#
4+
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
#
6+
7+
config TEST_B0_LOCK_READS
8+
bool "Test read prevention"
9+
help
10+
Reads are disabled after writes has been disabled, therefore testing against reads
11+
implies portion of the memory cannot be accessed at all.
12+
In case this symbol isn't selected, tests against writes are performed.
13+
14+
config TEST_B0_LOCK_REGION
15+
int "Region number"
16+
range 3 4
17+
default 3
18+
help
19+
Region 3 is used for NSIB protection. Other one for MCUBoot.
20+
21+
menu "Zephyr"
22+
source "Kconfig.zephyr"
23+
endmenu

0 commit comments

Comments
 (0)