Skip to content

Commit d504c2f

Browse files
ahasztagrlubos
authored andcommitted
samples: suit: Added first version of the recovery application
The recovery application can be built as a standalone application and flashed with nrfutil. Signed-off-by: Artur Hadasz <artur.hadasz@nordicsemi.no>
1 parent 643c3f4 commit d504c2f

19 files changed

+649
-24
lines changed

cmake/sysbuild/suit.cmake

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -174,14 +174,23 @@ function(suit_create_package)
174174
)
175175

176176
foreach(image ${IMAGES})
177+
unset(target)
177178
sysbuild_get(BINARY_DIR IMAGE ${image} VAR APPLICATION_BINARY_DIR CACHE)
178179
sysbuild_get(BINARY_FILE IMAGE ${image} VAR CONFIG_KERNEL_BIN_NAME KCONFIG)
180+
sysbuild_get(target IMAGE ${image} VAR CONFIG_SUIT_ENVELOPE_TARGET KCONFIG)
179181

180182
set(BINARY_FILE "${BINARY_FILE}.bin")
181183

182184
list(APPEND CORE_ARGS
183185
--core ${image},${SUIT_ROOT_DIRECTORY}${image}.bin,${BINARY_DIR}/zephyr/edt.pickle,${BINARY_DIR}/zephyr/.config
184186
)
187+
188+
if(DEFINED target AND NOT target STREQUAL "")
189+
list(APPEND CORE_ARGS
190+
--core ${target},${SUIT_ROOT_DIRECTORY}${target}.bin,${BINARY_DIR}/zephyr/edt.pickle,${BINARY_DIR}/zephyr/.config
191+
)
192+
suit_copy_artifact_to_output_directory(${target} ${BINARY_DIR}/zephyr/${BINARY_FILE})
193+
endif()
185194
suit_copy_artifact_to_output_directory(${image} ${BINARY_DIR}/zephyr/${BINARY_FILE})
186195
endforeach()
187196

@@ -194,24 +203,18 @@ function(suit_create_package)
194203

195204
sysbuild_get(INPUT_ENVELOPE_JINJA_FILE IMAGE ${image} VAR CONFIG_SUIT_ENVELOPE_TEMPLATE KCONFIG)
196205
sysbuild_get(target IMAGE ${image} VAR CONFIG_SUIT_ENVELOPE_TARGET KCONFIG)
197-
sysbuild_get(BINARY_DIR IMAGE ${image} VAR APPLICATION_BINARY_DIR CACHE)
198-
sysbuild_get(BINARY_FILE IMAGE ${image} VAR CONFIG_KERNEL_BIN_NAME KCONFIG)
206+
suit_set_absolute_or_relative_path(${INPUT_ENVELOPE_JINJA_FILE} ${PROJECT_BINARY_DIR} INPUT_ENVELOPE_JINJA_FILE)
207+
199208
suit_copy_input_template(${INPUT_TEMPLATES_DIRECTORY} "${INPUT_ENVELOPE_JINJA_FILE}" ENVELOPE_JINJA_FILE)
200209
if(NOT DEFINED ENVELOPE_JINJA_FILE)
201210
message(SEND_ERROR "DFU: Creation of SUIT artifacts failed.")
202211
return()
203212
endif()
204213
suit_check_template_digest(${INPUT_TEMPLATES_DIRECTORY} "${INPUT_ENVELOPE_JINJA_FILE}")
205-
set(BINARY_FILE "${BINARY_FILE}.bin")
206-
207-
list(APPEND CORE_ARGS
208-
--core ${target},${SUIT_ROOT_DIRECTORY}${target}.bin,${BINARY_DIR}/zephyr/edt.pickle,${BINARY_DIR}/zephyr/.config
209-
)
210214

211215
set(ENVELOPE_YAML_FILE ${SUIT_ROOT_DIRECTORY}${target}.yaml)
212216
set(ENVELOPE_SUIT_FILE ${SUIT_ROOT_DIRECTORY}${target}.suit)
213217

214-
suit_copy_artifact_to_output_directory(${target} ${BINARY_DIR}/zephyr/${BINARY_FILE})
215218
suit_render_template(${ENVELOPE_JINJA_FILE} ${ENVELOPE_YAML_FILE} "${CORE_ARGS}")
216219
suit_create_envelope(${ENVELOPE_YAML_FILE} ${ENVELOPE_SUIT_FILE} ${ENVELOPE_SHALL_BE_SIGNED})
217220
list(APPEND STORAGE_BOOT_ARGS
@@ -224,6 +227,7 @@ function(suit_create_package)
224227
# create root envelope if defined
225228
if(DEFINED INPUT_ROOT_ENVELOPE_JINJA_FILE AND NOT INPUT_ROOT_ENVELOPE_JINJA_FILE STREQUAL "")
226229
set(ROOT_NAME ${SB_CONFIG_SUIT_ENVELOPE_ROOT_ARTIFACT_NAME})
230+
suit_set_absolute_or_relative_path(${INPUT_ROOT_ENVELOPE_JINJA_FILE} ${PROJECT_BINARY_DIR} INPUT_ROOT_ENVELOPE_JINJA_FILE)
227231
suit_copy_input_template(${INPUT_TEMPLATES_DIRECTORY} "${INPUT_ROOT_ENVELOPE_JINJA_FILE}" ROOT_ENVELOPE_JINJA_FILE)
228232
suit_check_template_digest(${INPUT_TEMPLATES_DIRECTORY} "${INPUT_ROOT_ENVELOPE_JINJA_FILE}")
229233
set(ROOT_ENVELOPE_YAML_FILE ${SUIT_ROOT_DIRECTORY}${ROOT_NAME}.yaml)

samples/suit/flash_companion/prj.conf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ CONFIG_SSF_EXTMEM_SERVICE_ENABLED=y
5454
CONFIG_USE_DT_CODE_PARTITION=y
5555

5656
CONFIG_SUIT_LOCAL_ENVELOPE_GENERATE=n
57+
CONFIG_SUIT_ENVELOPE_TARGET=""
5758
CONFIG_NRF_REGTOOL_GENERATE_UICR=n
5859

5960
# Enable canonical zcbor encoding

samples/suit/recovery/CMakeLists.txt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#
2+
# Copyright (c) 2024 Nordic Semiconductor ASA
3+
#
4+
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
#
6+
7+
cmake_minimum_required(VERSION 3.20.0)
8+
9+
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
10+
11+
project(suit_recovery)
12+
13+
target_sources(app PRIVATE src/main.c)
14+
15+
# This project uses orginal sdk-zephyr C source code
16+
target_include_directories(app PRIVATE $ENV{ZEPHYR_BASE}/samples/subsys/mgmt/mcumgr/smp_svr/src)
17+
target_sources_ifdef(CONFIG_MCUMGR_TRANSPORT_BT app PRIVATE $ENV{ZEPHYR_BASE}/samples/subsys/mgmt/mcumgr/smp_svr/src/bluetooth.c)

samples/suit/recovery/README.rst

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
:orphan:
2+
3+
.. _suit_recovery:
4+
5+
SUIT recovery application
6+
#########################
7+
8+
.. contents::
9+
:local:
10+
:depth: 2
11+
12+
The SUIT recovery application is a minimal application that allows recovering the device firmware if the original firmware is damaged.
13+
It is to be used as a additional companion firmware to the main application using SUIT rather than a standalone application.
14+
15+
The application uses the SMP protocol via BLE and SUIT to perform the recovery.
16+
17+
Building
18+
********
19+
20+
The recovery application needs to be compatible with the main application in terms of hardware configuration.
21+
To achieve this, appropriate devicetree overlay files from the main application must be passed when building the recovery application as ``EXTRA_DTC_OVERLAY_FILE``
22+
.
23+
These devicetree also need to specify a partition for the recovery application.
24+
See the overlay files for the smp_transfer sample as an example.
25+
26+
For example, to build the recovery application as a recovery image for the smp transfer sample, run:
27+
28+
``west build -p --sysbuild -b nrf54h20dk/nrf54h20/cpuapp -- -DEXTRA_DTC_OVERLAY_FILE='../smp_transfer/sysbuild/recovery.overlay' -Dhci_ipc_EXTRA_DTC_OVERLAY_FILE='<absolute_path_to_smp_transfer_sample>/sysbuild/recovery_hci_ipc.overlay'``
29+
30+
Flashing
31+
********
32+
33+
Currently it is not possible to flash the application using ``west flash`` .
34+
Instead, ``nrfutil`` should be used to flash the hex files for the application core image, radio core image and SUIT storage:
35+
36+
``nrfutil device program --options chip_erase_mode=ERASE_NONE --firmware build/recovery/zephyr/suit_installed_envelopes_application_merged.hex``
37+
38+
``nrfutil device program --options chip_erase_mode=ERASE_NONE --firmware build/recovery/zephyr/suit_installed_envelopes_radio_merged.hex``
39+
40+
``nrfutil device program --options chip_erase_mode=ERASE_NONE --firmware build/recovery/zephyr/zephyr.hex``
41+
42+
``nrfutil device program --options chip_erase_mode=ERASE_NONE --firmware build/hci_ipc/zephyr/zephyr.hex``
43+
44+
It is also possible to install recovery application by performing an update using the recovery application envelope found in ``DFU/application.suit``
45+
46+
Updating
47+
********
48+
49+
Note that in order to update the recovery application the ``DFU/application.suit`` file found in the recovery application build directory should be used.
50+
This is different than in case of the main application, where usually ``DFU/root.suit`` should be used.
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
{%- set component_index = 0 %}
2+
{%- set component_list = [] %}
3+
{%- set dependencies_list = [] %}
4+
{%- set mpi_app_recovery_vendor_name = application['config']['CONFIG_SUIT_MPI_APP_RECOVERY_VENDOR_NAME']|default('nordicsemi.com') %}
5+
{%- set mpi_app_recovery_class_name = application['config']['CONFIG_SUIT_MPI_APP_RECOVERY_CLASS_NAME']|default('nRF54H20_sample_app_recovery') %}
6+
{%- set mpi_rad_recovery_vendor_name = application['config']['CONFIG_SUIT_MPI_RAD_RECOVERY_VENDOR_NAME']|default('nordicsemi.com') %}
7+
{%- set mpi_rad_recovery_class_name = application['config']['CONFIG_SUIT_MPI_RAD_RECOVERY_CLASS_NAME']|default('nRF54H20_sample_rad_recovery') %}
8+
{%- set sequence_number = sysbuild['config']['SB_CONFIG_SUIT_ENVELOPE_SEQUENCE_NUM'] %}
9+
SUIT_Envelope_Tagged:
10+
suit-authentication-wrapper:
11+
SuitDigest:
12+
suit-digest-algorithm-id: cose-alg-sha-256
13+
suit-manifest:
14+
suit-manifest-version: 1
15+
suit-manifest-sequence-number: {{ sequence_number }}
16+
suit-common:
17+
suit-components:
18+
- - CAND_IMG
19+
- 0
20+
- - CAND_MFST
21+
- 0
22+
{%- set component_index = 2 %}
23+
{%- if application is defined %}
24+
{%- set app_img_component_index = component_index %}
25+
{{- component_list.append( app_img_component_index ) or ""}}
26+
- - MEM
27+
- {{ application['dt'].label2node['cpu'].unit_addr }}
28+
- {{ get_absolute_address(application['dt'].chosen_nodes['zephyr,code-partition']) }}
29+
- {{ application['dt'].chosen_nodes['zephyr,code-partition'].regs[0].size }}
30+
{%- set component_index = component_index + 1 %}
31+
{%- endif %}
32+
{%- if radio is defined %}
33+
{%- set rad_instld_mfst_component_index = component_index %}
34+
{{- component_list.append( rad_instld_mfst_component_index ) or ""}}
35+
{{- dependencies_list.append( rad_instld_mfst_component_index ) or ""}}
36+
- - INSTLD_MFST
37+
- RFC4122_UUID:
38+
namespace: {{ mpi_rad_recovery_vendor_name }}
39+
name: {{ mpi_rad_recovery_class_name }}
40+
{%- set component_index = component_index + 1 %}
41+
{%- endif %}
42+
43+
suit-shared-sequence:
44+
{%- if radio is defined %}
45+
- suit-directive-set-component-index: {{ rad_instld_mfst_component_index }}
46+
- suit-directive-override-parameters:
47+
suit-parameter-vendor-identifier:
48+
RFC4122_UUID: {{ mpi_app_recovery_vendor_name }}
49+
suit-parameter-class-identifier:
50+
RFC4122_UUID:
51+
namespace: {{ mpi_app_recovery_vendor_name }}
52+
name: {{ mpi_app_recovery_class_name }}
53+
{%- endif %}
54+
{%- if application is defined %}
55+
- suit-directive-set-component-index: {{ app_img_component_index }}
56+
- suit-directive-override-parameters:
57+
suit-parameter-vendor-identifier:
58+
RFC4122_UUID: {{ mpi_app_recovery_vendor_name }}
59+
suit-parameter-class-identifier:
60+
RFC4122_UUID:
61+
namespace: {{ mpi_app_recovery_vendor_name }}
62+
name: {{ mpi_app_recovery_class_name }}
63+
suit-parameter-image-digest:
64+
suit-digest-algorithm-id: cose-alg-sha-256
65+
suit-digest-bytes:
66+
file: {{ application['binary'] }}
67+
suit-parameter-image-size:
68+
file: {{ application['binary'] }}
69+
{%- endif %}
70+
- suit-directive-set-component-index: [{{ component_list|join(',') }}]
71+
- suit-condition-vendor-identifier:
72+
- suit-send-record-success
73+
- suit-send-record-failure
74+
- suit-send-sysinfo-success
75+
- suit-send-sysinfo-failure
76+
- suit-condition-class-identifier:
77+
- suit-send-record-success
78+
- suit-send-record-failure
79+
- suit-send-sysinfo-success
80+
- suit-send-sysinfo-failure
81+
suit-dependencies:
82+
# Key is the index of suit-components that describe the dependency manifest
83+
"1": {}
84+
{%- for component_element in dependencies_list %}
85+
"{{ component_element }}": {}
86+
{%- endfor %}
87+
88+
suit-validate:
89+
{% if dependencies_list|length > 0 %}
90+
- suit-directive-set-component-index: [{{ dependencies_list|join(',') }}]
91+
- suit-condition-dependency-integrity:
92+
- suit-send-record-success
93+
- suit-send-record-failure
94+
- suit-send-sysinfo-success
95+
- suit-send-sysinfo-failure
96+
- suit-directive-process-dependency:
97+
- suit-send-record-success
98+
- suit-send-record-failure
99+
- suit-send-sysinfo-success
100+
- suit-send-sysinfo-failure
101+
{% endif %}
102+
{%- if application is defined %}
103+
- suit-directive-set-component-index: {{ app_img_component_index }}
104+
- suit-condition-image-match:
105+
- suit-send-record-success
106+
- suit-send-record-failure
107+
- suit-send-sysinfo-success
108+
- suit-send-sysinfo-failure
109+
{%- endif %}
110+
111+
suit-invoke:
112+
{% if dependencies_list|length > 0 %}
113+
- suit-directive-set-component-index: [{{ dependencies_list|join(',') }}]
114+
- suit-condition-dependency-integrity:
115+
- suit-send-record-success
116+
- suit-send-record-failure
117+
- suit-send-sysinfo-success
118+
- suit-send-sysinfo-failure
119+
- suit-directive-process-dependency:
120+
- suit-send-record-success
121+
- suit-send-record-failure
122+
- suit-send-sysinfo-success
123+
- suit-send-sysinfo-failure
124+
{% endif %}
125+
{%- if application is defined %}
126+
- suit-directive-set-component-index: {{ app_img_component_index }}
127+
- suit-directive-invoke:
128+
- suit-send-record-failure
129+
{%- endif %}
130+
131+
suit-install:
132+
{%- if radio is defined %}
133+
- suit-directive-set-component-index: 1
134+
- suit-directive-override-parameters:
135+
suit-parameter-uri: '#{{ radio['name'] }}'
136+
suit-parameter-image-digest:
137+
suit-digest-algorithm-id: cose-alg-sha-256
138+
suit-digest-bytes:
139+
envelope: {{ artifacts_folder ~ radio['name'] }}.suit
140+
- suit-directive-fetch:
141+
- suit-send-record-failure
142+
- suit-condition-image-match:
143+
- suit-send-record-success
144+
- suit-send-record-failure
145+
- suit-send-sysinfo-success
146+
- suit-send-sysinfo-failure
147+
- suit-condition-dependency-integrity:
148+
- suit-send-record-success
149+
- suit-send-record-failure
150+
- suit-send-sysinfo-success
151+
- suit-send-sysinfo-failure
152+
- suit-directive-process-dependency:
153+
- suit-send-record-success
154+
- suit-send-record-failure
155+
- suit-send-sysinfo-success
156+
- suit-send-sysinfo-failure
157+
{%- endif %}
158+
{%- if application is defined %}
159+
- suit-directive-set-component-index: 0
160+
- suit-directive-override-parameters:
161+
suit-parameter-uri: '#{{ application['name'] }}'
162+
suit-parameter-image-digest:
163+
suit-digest-algorithm-id: cose-alg-sha-256
164+
suit-digest-bytes:
165+
file: {{ application['binary'] }}
166+
- suit-directive-fetch:
167+
- suit-send-record-failure
168+
- suit-condition-image-match:
169+
- suit-send-record-success
170+
- suit-send-record-failure
171+
- suit-send-sysinfo-success
172+
- suit-send-sysinfo-failure
173+
- suit-directive-set-component-index: {{ app_img_component_index }}
174+
- suit-directive-override-parameters:
175+
suit-parameter-source-component: 0
176+
- suit-directive-copy:
177+
- suit-send-record-failure
178+
- suit-condition-image-match:
179+
- suit-send-record-success
180+
- suit-send-record-failure
181+
- suit-send-sysinfo-success
182+
- suit-send-sysinfo-failure
183+
{%- endif %}
184+
suit-manifest-component-id:
185+
- INSTLD_MFST
186+
- RFC4122_UUID:
187+
namespace: {{ mpi_app_recovery_vendor_name }}
188+
name: {{ mpi_app_recovery_class_name }}
189+
suit-integrated-dependencies:
190+
{%- if radio is defined %}
191+
'#{{ radio['name'] }}': {{ artifacts_folder ~ radio['name'] }}.suit
192+
{%- endif %}
193+
{%- if application is defined %}
194+
'#{{ application['name'] }}': {{ application['binary'] }}
195+
{%- endif %}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/*
2+
* Copyright (c) 2024 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
*/
6+
7+
/ {
8+
chosen {
9+
zephyr,code-partition = &cpuapp_recovery_partition;
10+
nrf,tz-secure-image = &cpuapp_recovery_partition;
11+
};
12+
};

0 commit comments

Comments
 (0)