Skip to content

Commit 17a1154

Browse files
committed
samples: ironside_se: Add sample that protects periphconf
Add a sample that demonstrates how to protect periphconf using PROTECTEDMEM. Signed-off-by: Sebastian Bøe <sebastian.boe@nordicsemi.no>
1 parent 40aaea4 commit 17a1154

File tree

12 files changed

+440
-0
lines changed

12 files changed

+440
-0
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#
2+
# Copyright (c) 2025 Nordic Semiconductor ASA
3+
#
4+
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
#
6+
7+
cmake_minimum_required(VERSION 3.13.1)
8+
9+
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
10+
11+
project(protectedmem_periphconf)
12+
13+
target_sources(app PRIVATE
14+
src/main.c
15+
)
16+
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
.. _protectedmem_periphconf_sample:
2+
3+
Protected Memory with PERIPHCONF Partition
4+
##########################################
5+
6+
.. contents::
7+
:local:
8+
:depth: 2
9+
10+
This sample demonstrates how to protect the ``periphconf_partition`` using UICR.PROTECTEDMEM. The sample shows that when protected memory is modified, the integrity check fails on the next boot, causing IronSide SE to boot a secondary firmware instead of the main application.
11+
12+
Requirements
13+
************
14+
15+
The sample supports the following development kit:
16+
17+
.. table-from-sample-yaml::
18+
19+
Overview
20+
********
21+
22+
This sample demonstrates:
23+
24+
* How to configure UICR.PROTECTEDMEM to protect a memory region
25+
* How to relocate the ``periphconf_partition`` using a device tree overlay to be placed right after ``cpuapp_boot_partition``
26+
* How to configure the PROTECTEDMEM size in Kconfig to cover both ``cpuapp_boot_partition`` and ``periphconf_partition``
27+
* How to configure a secondary firmware that boots when PROTECTEDMEM integrity check fails
28+
* How the protected memory region prevents unauthorized modifications by causing the secondary firmware to boot when integrity is violated
29+
30+
The sample works as follows:
31+
32+
1. The application writes a test pattern to the protected memory region
33+
2. The application then reboots
34+
3. On the next boot, the IronSide SE performs an integrity check of the protected memory region
35+
4. If the integrity check fails (because the memory was modified), IronSide SE automatically boots the secondary firmware instead of the main application
36+
5. The secondary firmware prints a message indicating that the PROTECTEDMEM integrity check failed, demonstrating that unauthorized modifications are detected and prevented
37+
38+
Building and running
39+
*********************
40+
41+
.. |sample path| replace:: :file:`samples/ironside_se/protectedmem_periphconf`
42+
43+
.. include:: /includes/build_and_run_ns.txt
44+
45+
To build the sample, run the following command:
46+
47+
.. code-block:: console
48+
49+
west build -b <board> samples/ironside_se/protectedmem_periphconf
50+
51+
To program the sample on the device, run the following command:
52+
53+
.. code-block:: console
54+
55+
west flash
56+
57+
Testing
58+
*******
59+
60+
After programming the sample to your development kit, complete the following steps to test it:
61+
62+
1. |connect_terminal|
63+
#. Reset the kit.
64+
#. Observe the console output:
65+
66+
When you run the sample, you should see:
67+
68+
.. code-block:: console
69+
70+
[00:00:00.123,456] === Protected Memory Demo ===
71+
[00:00:00.123,457] periphconf_partition address: 0x0e040000
72+
[00:00:00.123,458] periphconf_partition size: 0x2000 bytes
73+
[00:00:00.123,459] Last 16-byte aligned area start: 0x0e041ff0
74+
[00:00:00.123,460] Test write address (last 4 bytes): 0x0e041ffc
75+
[00:00:00.123,461] Current value at protected address: 0xffffffff
76+
[00:00:00.123,462]
77+
[00:00:00.123,463] This sample demonstrates UICR.PROTECTEDMEM protection.
78+
[00:00:00.123,464] When protected memory is modified, the integrity check will fail
79+
[00:00:00.123,465] on the next boot, preventing the device from booting.
80+
[00:00:00.123,466]
81+
[00:00:00.123,467] Attempting to write test pattern 0xdeadbeef to protected memory...
82+
[00:00:00.123,468] Readback value: 0xdeadbeef
83+
[00:00:00.123,469] Write successful (in current boot).
84+
[00:00:00.123,470]
85+
[00:00:00.123,471] Rebooting...
86+
[00:00:00.123,472] After reboot, if protection is working correctly:
87+
[00:00:00.123,473] - The integrity check will detect the modification
88+
[00:00:00.123,474] - The device will fail to boot with an integrity error
89+
[00:00:00.123,475] - You should see a boot error status indicating PROTECTEDMEM integrity failure
90+
[00:00:00.123,476]
91+
[00:00:00.123,477] If protection is NOT working, the device will boot normally
92+
[00:00:00.123,478] and you will see this message again.
93+
94+
After the reboot, if protection is working correctly, the secondary firmware will boot instead of the main application.
95+
You should see the following output from the secondary firmware:
96+
97+
.. code-block:: console
98+
99+
[00:00:01.234,567] *** Booting nRF Connect SDK v3.1.99-1baadd786027 ***
100+
[00:00:01.234,568] *** Using Zephyr OS v4.2.99-d7669eff2b94 ***
101+
[00:00:01.234,569] === Secondary Firmware Booted ===
102+
[00:00:01.234,570] PROTECTEDMEM integrity check FAILED - device booted secondary firmware
103+
[00:00:01.234,571] This indicates that protected memory was modified and integrity check failed.
104+
105+
This demonstrates that the integrity check detected the modification and prevented the main application from booting.
106+
107+
Configuration
108+
*************
109+
110+
The sample uses the following key configurations:
111+
112+
Device Tree Overlay
113+
===================
114+
115+
The ``app.overlay`` file relocates the ``periphconf_partition`` to be placed right after ``cpuapp_boot_partition``.
116+
The ``sysbuild.cmake`` file applies this same overlay to the UICR image so both images see the same partition layout:
117+
118+
.. code-block:: dts
119+
120+
&mram1x {
121+
partitions {
122+
periphconf_partition: partition@40000 {
123+
reg = <0x40000 DT_SIZE_K(8)>;
124+
};
125+
cpuapp_slot0_partition: partition@42000 {
126+
reg = <0x42000 DT_SIZE_K(328)>;
127+
};
128+
};
129+
};
130+
131+
This places the partition at offset 0x40000 (right after ``cpuapp_boot_partition`` at 0x30000 with size 64KB).
132+
133+
Kconfig Configuration
134+
=====================
135+
136+
The ``sysbuild/uicr.conf`` file configures the PROTECTEDMEM size for the UICR image to cover both partitions:
137+
138+
.. code-block:: cfg
139+
140+
CONFIG_GEN_UICR_PROTECTEDMEM_SIZE_BYTES=73728
141+
142+
This covers:
143+
* ``cpuapp_boot_partition``: 64KB (0x10000)
144+
* ``periphconf_partition``: 8KB (0x2000)
145+
* Total: 72KB (0x12000) = 18 * 4KB blocks
146+
147+
Note that the UICR image configuration is in ``sysbuild/uicr.conf``, not in the main application's Kconfig, as the UICR generation is handled by a separate sysbuild image.
148+
149+
Secondary Firmware
150+
==================
151+
152+
The sample includes a secondary firmware (in the ``secondary/`` directory) that boots automatically when the PROTECTEDMEM integrity check fails. The secondary firmware is configured in ``sysbuild/uicr.conf``:
153+
154+
.. code-block:: cfg
155+
156+
CONFIG_GEN_UICR_SECONDARY=y
157+
158+
The secondary firmware is built as part of the sysbuild process (configured in ``sysbuild.cmake``) and is placed in the ``secondary_partition``. When IronSide SE detects that the PROTECTEDMEM integrity check has failed, it automatically boots the secondary firmware instead of the main application, allowing you to detect and handle the integrity violation.
159+
160+
Dependencies
161+
************
162+
163+
This sample uses the following |NCS| subsystems:
164+
165+
* UICR generation - Configures UICR.PROTECTEDMEM to protect the memory region and UICR.SECONDARY to enable secondary firmware boot
166+
* Sysbuild - Enables building the UICR image and secondary firmware with the protected memory configuration
167+
168+
In addition, it uses the following Zephyr subsystems:
169+
170+
* :ref:`Kernel <kernel>` - Provides basic system functionality and threading
171+
* :ref:`Console <console>` - Enables UART console output for debugging and user interaction
172+
* Device Tree - Defines the partition layout
173+
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* Copyright (c) 2025 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
*/
6+
7+
/* Delete the original partitions before redefining them */
8+
/delete-node/ &cpuapp_slot0_partition;
9+
/delete-node/ &periphconf_partition;
10+
11+
/ {
12+
/* Move periphconf_partition to be right after cpuapp_boot_partition */
13+
};
14+
15+
&mram1x {
16+
partitions {
17+
18+
/* cpuapp_boot_partition is at 0x30000 with size 64KB (0x10000) */
19+
/* Move periphconf_partition to 0x40000 (right after cpuapp_boot_partition) */
20+
periphconf_partition: partition@40000 {
21+
reg = <0x40000 DT_SIZE_K(8)>;
22+
};
23+
24+
/* Move cpuapp_slot0_partition to start after periphconf_partition */
25+
/* periphconf_partition ends at 0x42000, so slot0 starts there */
26+
cpuapp_slot0_partition: partition@42000 {
27+
reg = <0x42000 DT_SIZE_K(328)>;
28+
};
29+
};
30+
};
31+
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#
2+
# Copyright (c) 2025 Nordic Semiconductor ASA
3+
#
4+
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
#
6+
7+
# Disable MPU to allow writing to protected memory region for demonstration
8+
CONFIG_ARM_MPU=n
9+
10+
# Note: UICR configuration (GEN_UICR_PROTECTEDMEM, etc.) is done in sysbuild/uicr.conf
11+
# for the UICR image, not in the main application's prj.conf
12+
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
sample:
2+
name: Protected Memory PERIPHCONF Sample
3+
description: |
4+
Sample demonstrating UICR.PROTECTEDMEM protection of the periphconf_partition.
5+
The sample relocates periphconf_partition to be right after
6+
cpuapp_boot_partition and configures PROTECTEDMEM to protect both partitions.
7+
The sample writes to the protected area, reboots, and demonstrates that the
8+
integrity check fails on boot, preventing the device from booting when the
9+
protected memory is modified.
10+
11+
common:
12+
sysbuild: true
13+
harness: console
14+
harness_config:
15+
type: multi_line
16+
ordered: true
17+
regex:
18+
- "=== Protected Memory Demo ==="
19+
- "Attempting to write test pattern"
20+
- "Write successful \\(in current boot\\)\\."
21+
- "Rebooting\\.\\.\\."
22+
# When PROTECTEDMEM integrity check fails, secondary firmware boots
23+
- "=== Secondary Firmware Booted ==="
24+
- "PROTECTEDMEM integrity check FAILED"
25+
26+
tests:
27+
samples.protectedmem_periphconf.nrf54h20dk:
28+
tags:
29+
- sysbuild
30+
- ci_samples_sdfw
31+
platform_allow:
32+
- nrf54h20dk/nrf54h20/cpuapp
33+
integration_platforms:
34+
- nrf54h20dk/nrf54h20/cpuapp
35+
timeout: 7
36+
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Copyright (c) 2025 Nordic Semiconductor ASA
2+
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
3+
4+
cmake_minimum_required(VERSION 3.20.0)
5+
6+
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
7+
project(secondary)
8+
9+
target_sources(app PRIVATE src/main.c)
10+
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/*
2+
* Copyright (c) 2025 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
*/
6+
7+
/ {
8+
chosen {
9+
zephyr,code-partition = &secondary_partition;
10+
};
11+
};
12+
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#
2+
# Copyright (c) 2025 Nordic Semiconductor ASA
3+
#
4+
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
#
6+
7+
CONFIG_IS_IRONSIDE_SE_SECONDARY_IMAGE=y
8+
9+
# Use the devicetree chosen code-partition to determine flash load offset
10+
CONFIG_USE_DT_CODE_PARTITION=y
11+
12+
# NB: app.overlay sets zephyr,code-partition to secondary_partition
13+
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Copyright (c) 2025 Nordic Semiconductor ASA.
3+
*
4+
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
*/
6+
7+
#include <zephyr/kernel.h>
8+
#include <zephyr/sys/printk.h>
9+
10+
int main(void)
11+
{
12+
printk("=== Secondary Firmware Booted ===\n");
13+
printk("PROTECTEDMEM integrity check FAILED - device booted secondary firmware\n");
14+
printk("This indicates that protected memory was modified and integrity check failed.\n");
15+
16+
/* Keep the secondary image running */
17+
while (1) {
18+
k_msleep(1000);
19+
}
20+
21+
return 0;
22+
}
23+

0 commit comments

Comments
 (0)