Skip to content

Commit fbffaa8

Browse files
michalek-nonordicjm
authored andcommitted
bootloader: self lock at the end of execution
Disables read and execute on memory containing NSIB right before jumping to application. Signed-off-by: Mateusz Michalek <mateusz.michalek@nordicsemi.no>
1 parent 72a34fe commit fbffaa8

File tree

2 files changed

+107
-20
lines changed

2 files changed

+107
-20
lines changed

subsys/bootloader/Kconfig

+7
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,13 @@ config SB_CLEANUP_RAM
104104
help
105105
Sets contents of memory to 0 before jumping to application.
106106

107+
config SB_DISABLE_SELF_RWX
108+
bool "Disable read and execution on self NVM"
109+
depends on SOC_NRF54L15_CPUAPP && !FPROTECT_ALLOW_COMBINED_REGIONS
110+
help
111+
Sets RRAMC's BOOTCONF region protection before jumping to application.
112+
It disables reads writes and execution memory area which holds NSIB.
113+
107114
endif # IS_SECURE_BOOTLOADER
108115

109116
config IS_BOOTLOADER_IMG

subsys/bootloader/bl_boot/bl_boot.c

+100-20
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2020 Nordic Semiconductor ASA
2+
* Copyright (c) 2020-2025 Nordic Semiconductor ASA
33
*
44
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
55
*/
@@ -19,6 +19,25 @@
1919
#include <hal/nrf_gpio.h>
2020
#endif
2121

22+
#if defined(CONFIG_SB_DISABLE_SELF_RWX)
23+
/* Disabling R_X has to be done while running from RAM for obvious reasons.
24+
* 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.
29+
*/
30+
#include <hal/nrf_rramc.h>
31+
32+
#define FUNCTION_BUFFER_LEN 64
33+
#define RRAMC_REGION_RWX_LSB 0
34+
#define RRAMC_REGION_RWX_WIDTH 3
35+
#define RRAMC_REGION_TO_LOCK_ADDR NRF_RRAMC->REGION[3].CONFIG
36+
#define RRAMC_REGION_TO_LOCK_ADDR_H (((uint32_t)(&(RRAMC_REGION_TO_LOCK_ADDR))) >> 16)
37+
#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];
39+
#endif /* CONFIG_SB_DISABLE_SELF_RWX */
40+
2241
#ifdef CONFIG_UART_NRFX_UARTE
2342
static void uninit_used_uarte(NRF_UARTE_Type *p_reg)
2443
{
@@ -151,39 +170,100 @@ void bl_boot(const struct fw_info *fw_info)
151170
__set_PSPLIM(0);
152171
__set_MSPLIM(0);
153172
#endif
154-
155173
/* Set MSP to the new address and clear any information from PSP */
156174
__set_MSP(vector_table[0]);
157175
__set_PSP(0);
158176

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

0 commit comments

Comments
 (0)