Skip to content

Commit b2fbe42

Browse files
hakonfamrlubos
authored andcommitted
Revert "suit: Rework SDFW and SDFW Recovery sinks"
This reverts commit 88380ce. Signed-off-by: Håkon Amundsen <[email protected]>
1 parent 39388a9 commit b2fbe42

File tree

7 files changed

+323
-239
lines changed

7 files changed

+323
-239
lines changed

subsys/suit/plat_err/include/suit_plat_err.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,6 @@ typedef int suit_plat_err_t;
9797
#define SUIT_PLAT_ERR_UNSUPPORTED -2010 /**< Attempt to perform an unsupported operation */
9898
#define SUIT_PLAT_ERR_IPC -2011 /**< IPC error */
9999
#define SUIT_PLAT_ERR_NO_RESOURCES -2012 /**< Not enough resources */
100-
#define SUIT_PLAT_ERR_SDRFW_FAILURE -2013 /**< Failure during SDFW Recovery update */
101100

102101
/**
103102
* If the error code is a common platform error code return it.

subsys/suit/platform/sdfw/src/suit_plat_copy.c

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -251,11 +251,9 @@ int suit_plat_copy(suit_component_t dst_handle, suit_component_t src_handle,
251251
}
252252

253253
if (ret == SUIT_SUCCESS) {
254-
plat_ret =
255-
suit_generic_address_streamer_stream(payload_ptr, payload_size, &dst_sink);
256-
if (plat_ret != SUIT_PLAT_SUCCESS) {
257-
LOG_ERR("memptr_streamer failed - error %i", plat_ret);
258-
ret = suit_plat_err_to_processor_err_convert(plat_ret);
254+
ret = suit_generic_address_streamer_stream(payload_ptr, payload_size, &dst_sink);
255+
if (ret != SUIT_PLAT_SUCCESS) {
256+
LOG_ERR("memptr_streamer failed - error %i", ret);
259257
}
260258
}
261259
#endif /* CONFIG_SUIT_STREAM_SOURCE_MEMPTR */

subsys/suit/platform/src/suit_plat_error_convert.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,6 @@ int suit_plat_err_to_processor_err_convert(suit_plat_err_t plat_err)
2424
case SUIT_PLAT_ERR_CBOR_DECODING:
2525
proc_err = SUIT_ERR_DECODING;
2626
break;
27-
case SUIT_PLAT_ERR_SDRFW_FAILURE:
28-
proc_err = SUIT_FAIL_CONDITION;
29-
break;
3027
/* To be extended */
3128
default:
3229
/* Return SUIT_ERR_CRASH */

subsys/suit/stream/stream_sinks/src/suit_sdfw_recovery_sink.c

Lines changed: 191 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,18 @@
1414
#include <sdfw/sdfw_update.h>
1515
#include <suit_plat_mem_util.h>
1616

17+
#include <suit_digest_sink.h>
18+
1719
#define SUIT_MAX_SDFW_RECOVERY_COMPONENTS 1
1820

21+
#define SDFW_RECOVERY_SINK_ERR_AGAIN \
22+
1 /* Reboot is needed before proceeding. Call the API again. \
23+
*/
24+
1925
LOG_MODULE_REGISTER(suit_sdfw_recovery_sink, CONFIG_SUIT_LOG_LEVEL);
2026

27+
typedef int sdf_sink_err_t;
28+
2129
struct sdfw_recovery_sink_context {
2230
bool in_use;
2331
bool write_called;
@@ -36,19 +44,56 @@ static struct sdfw_recovery_sink_context *get_new_context(void)
3644
return NULL;
3745
}
3846

39-
static suit_plat_err_t schedule_update(const uint8_t *buf, size_t size)
47+
static digest_sink_err_t verify_digest(uint8_t *buf, size_t buf_size, psa_algorithm_t algorithm,
48+
uint8_t *expected_digest)
4049
{
41-
int err = 0;
50+
struct stream_sink digest_sink;
51+
suit_plat_err_t err = suit_digest_sink_get(&digest_sink, algorithm, expected_digest);
4252

43-
if (!suit_plat_mem_clear_sicr_update_registers()) {
44-
LOG_ERR("Failed to clear update registers");
45-
/* By design SDFW Recovery update error should not result in failing whole
46-
* installation.
47-
* Because of that, set specific error code instead of SUIT_PLAT_ERR_CRASH.
48-
*/
49-
return SUIT_PLAT_ERR_SDRFW_FAILURE;
53+
if (err != SUIT_PLAT_SUCCESS) {
54+
LOG_ERR("Failed to get digest sink: %d", err);
55+
return err;
56+
}
57+
58+
err = digest_sink.write(digest_sink.ctx, buf, buf_size);
59+
if (err != SUIT_PLAT_SUCCESS) {
60+
LOG_ERR("Failed to write to stream: %d", err);
61+
(void)digest_sink.release(digest_sink.ctx);
62+
return err;
5063
}
5164

65+
digest_sink_err_t ret = suit_digest_sink_digest_match(digest_sink.ctx);
66+
67+
err = digest_sink.release(digest_sink.ctx);
68+
if (err != SUIT_PLAT_SUCCESS) {
69+
LOG_WRN("Failed to release stream: %d", err);
70+
}
71+
72+
return ret;
73+
}
74+
75+
static suit_plat_err_t clear_urot_update_status(void)
76+
{
77+
mram_erase((uintptr_t)&NRF_SICR->UROT.UPDATE,
78+
sizeof(NRF_SICR->UROT.UPDATE) / CONFIG_SDFW_MRAM_WORD_SIZE);
79+
80+
/* Clearing the registers is crucial for correct handling by SecROM. */
81+
/* Incorrect mram_erase behavior was observed on FPGA. */
82+
/* Since mram_erase returns void, there is a need for extra check and returning error code
83+
* to handle such case.
84+
*/
85+
if (NRF_SICR->UROT.UPDATE.STATUS == SICR_UROT_UPDATE_STATUS_CODE_None &&
86+
NRF_SICR->UROT.UPDATE.OPERATION == SICR_UROT_UPDATE_OPERATION_OPCODE_Nop) {
87+
return SUIT_PLAT_SUCCESS;
88+
} else {
89+
return SUIT_PLAT_ERR_IO;
90+
}
91+
}
92+
93+
static suit_plat_err_t schedule_sdfw_recovery_update(const uint8_t *buf, size_t size)
94+
{
95+
int err = 0;
96+
5297
const struct sdfw_update_blob update_blob = {
5398
.manifest_addr =
5499
(uintptr_t)(buf + CONFIG_SUIT_SDFW_RECOVERY_UPDATE_SIGNED_MANIFEST_OFFSET),
@@ -77,115 +122,126 @@ static suit_plat_err_t schedule_update(const uint8_t *buf, size_t size)
77122

78123
if (err) {
79124
LOG_ERR("Failed to schedule SDFW Recovery update: %d", err);
80-
err = SUIT_PLAT_ERR_CRASH;
81-
} else {
82-
err = SUIT_PLAT_SUCCESS;
125+
return SUIT_PLAT_ERR_CRASH;
83126
}
84127

85-
return err;
128+
LOG_INF("SDFW Recovery update scheduled");
129+
130+
return SUIT_PLAT_SUCCESS;
86131
}
87132

88-
static void reboot_to_continue(void)
133+
static sdf_sink_err_t check_update_candidate(const uint8_t *buf, size_t size)
89134
{
90-
if (IS_ENABLED(CONFIG_SUIT_UPDATE_REBOOT_ENABLED)) {
91-
LOG_INF("Reboot the system to continue update");
135+
uint8_t *candidate_binary_start =
136+
(uint8_t *)(buf + CONFIG_SUIT_SDFW_RECOVERY_UPDATE_FIRMWARE_OFFSET);
137+
uint8_t *candidate_digest_in_manifest =
138+
(uint8_t *)(buf + CONFIG_SUIT_SDFW_RECOVERY_UPDATE_DIGEST_OFFSET);
139+
uint8_t *current_sdfw_recovery_digest =
140+
(uint8_t *)(NRF_SICR->UROT.RECOVERY.SM.TBS.FW.DIGEST);
92141

93-
LOG_PANIC();
142+
/* First check if calculated digest of candidate matches the digest from Signed Manifest */
143+
digest_sink_err_t err =
144+
verify_digest(candidate_binary_start,
145+
size - (size_t)CONFIG_SUIT_SDFW_RECOVERY_UPDATE_FIRMWARE_OFFSET,
146+
PSA_ALG_SHA_512, candidate_digest_in_manifest);
147+
148+
if (err != SUIT_PLAT_SUCCESS) {
149+
if (err == DIGEST_SINK_ERR_DIGEST_MISMATCH) {
150+
LOG_ERR("Candidate inconsistent");
151+
} else {
152+
LOG_ERR("Failed to calculate digest: %d", err);
153+
}
94154

95-
sys_reboot(SYS_REBOOT_COLD);
96-
} else {
97-
LOG_DBG("Reboot disabled - perform manually");
155+
return SUIT_PLAT_ERR_CRASH;
98156
}
99-
}
100157

101-
static suit_plat_err_t schedule_update_and_reboot(const uint8_t *buf, size_t size)
102-
{
103-
suit_plat_err_t err = schedule_update(buf, size);
158+
LOG_DBG("Candidate consistent");
104159

160+
/* Then compare candidate's digest with current SDFW Recovery digest */
161+
err = verify_digest(candidate_binary_start,
162+
size - (size_t)CONFIG_SUIT_SDFW_RECOVERY_UPDATE_FIRMWARE_OFFSET,
163+
PSA_ALG_SHA_512, current_sdfw_recovery_digest);
105164
if (err == SUIT_PLAT_SUCCESS) {
106-
reboot_to_continue();
107-
if (IS_ENABLED(CONFIG_SUIT_UPDATE_REBOOT_ENABLED)) {
108-
/* If this code is reached, it means that reboot did not work. */
109-
/* In such case report an error. */
110-
LOG_ERR("Expected reboot did not happen");
111-
err = SUIT_PLAT_ERR_UNREACHABLE_PATH;
165+
LOG_INF("Same candidate - skip update");
166+
return SUIT_PLAT_SUCCESS;
167+
} else if (err == DIGEST_SINK_ERR_DIGEST_MISMATCH) {
168+
LOG_INF("Different candidate");
169+
err = schedule_sdfw_recovery_update(buf, size);
170+
if (err == SUIT_PLAT_SUCCESS) {
171+
LOG_DBG("Update scheduled");
172+
err = SDFW_RECOVERY_SINK_ERR_AGAIN;
112173
}
174+
return err;
113175
}
114176

115-
return err;
177+
LOG_ERR("Failed to calculate digest: %d", err);
178+
return SUIT_PLAT_ERR_CRASH;
116179
}
117180

118-
static suit_plat_err_t update_already_ongoing(const uint8_t *buf, size_t size)
181+
static void reboot_to_continue(void)
119182
{
120-
suit_plat_err_t err = SUIT_PLAT_SUCCESS;
183+
if (IS_ENABLED(CONFIG_SUIT_UPDATE_REBOOT_ENABLED)) {
184+
LOG_INF("Reboot the system to continue SDFW Recovery update");
121185

122-
enum sdfw_update_status update_status = sdfw_update_initial_status_get();
186+
LOG_PANIC();
123187

124-
/* Candidate is different than current FW but SDFW Recovery update is already ongoing. */
125-
switch (update_status) {
126-
case SDFW_UPDATE_STATUS_NONE: {
127-
/* No pending operation even though operation indicates SDFW Recovery update.
128-
* Yet candidate differs from current FW, so schedule the update.
129-
*/
130-
err = schedule_update_and_reboot(buf, size);
131-
break;
132-
}
133-
default: {
134-
/* SecROM indicates error during update */
135-
LOG_ERR("Update failure: %08x", update_status);
136-
/* By design SDFW Recovery update error should not result in failing whole
137-
* installation.
138-
* Because of that, set specific error code instead of SUIT_PLAT_ERR_CRASH.
139-
*/
140-
err = SUIT_PLAT_ERR_SDRFW_FAILURE;
141-
break;
142-
}
188+
sys_reboot(SYS_REBOOT_COLD);
189+
} else {
190+
LOG_DBG("Reboot disabled - perform manually");
143191
}
144-
145-
return err;
146192
}
147193

148-
static suit_plat_err_t update_needed_action(const uint8_t *buf, size_t size)
194+
static suit_plat_err_t check_urot_none(const uint8_t *buf, size_t size)
149195
{
150-
suit_plat_err_t err = SUIT_PLAT_SUCCESS;
196+
/* Detect update candidate. */
197+
/* It is enough to check Public Key Size field which occupies first 4B of Signed Manifest.
198+
*/
199+
if (*((uint32_t *)buf) == EMPTY_STORAGE_VALUE) {
200+
LOG_INF("Update candidate not found");
201+
return SUIT_PLAT_ERR_NOT_FOUND;
202+
}
151203

152-
enum sdfw_update_operation initial_operation = sdfw_update_initial_operation_get();
204+
LOG_INF("Update candidate found");
153205

154-
switch (initial_operation) {
155-
case SDFW_UPDATE_OPERATION_NOP:
156-
case SDFW_UPDATE_OPERATION_UROT_ACTIVATE: {
157-
/* No previously running update or after the other slot update. */
158-
/* Schedule an update of this slot. */
159-
err = schedule_update_and_reboot(buf, size);
160-
break;
161-
}
162-
case SDFW_UPDATE_OPERATION_RECOVERY_ACTIVATE: {
163-
/* SDFW Recovery update already ongoing */
164-
err = update_already_ongoing(buf, size);
165-
break;
166-
}
167-
default: {
168-
LOG_ERR("Unhandled operation: %08x", initial_operation);
169-
err = SUIT_PLAT_ERR_CRASH;
170-
break;
171-
}
206+
suit_plat_err_t err = check_update_candidate(buf, size);
207+
208+
if (err == SDFW_RECOVERY_SINK_ERR_AGAIN) {
209+
/* Update scheduled, continue after reboot */
210+
reboot_to_continue();
211+
if (IS_ENABLED(CONFIG_SUIT_UPDATE_REBOOT_ENABLED)) {
212+
/* If this code is reached, it means that reboot did not work. */
213+
/* In such case report an error and convert the error code. */
214+
LOG_ERR("Expected reboot did not happen");
215+
err = SUIT_PLAT_ERR_UNREACHABLE_PATH;
216+
}
172217
}
173218

174219
return err;
175220
}
176221

177-
static bool is_update_needed(const uint8_t *buf, size_t size)
222+
static suit_plat_err_t check_recovery_activated(const uint8_t *buf, size_t size)
178223
{
179-
const uint8_t *candidate_digest_in_manifest =
180-
(uint8_t *)(buf + CONFIG_SUIT_SDFW_RECOVERY_UPDATE_DIGEST_OFFSET);
181-
const uint8_t *current_sdfw_recovery_digest =
182-
(uint8_t *)(NRF_SICR->UROT.RECOVERY.SM.TBS.FW.DIGEST);
224+
uint8_t *candidate_binary_start =
225+
(uint8_t *)(buf + CONFIG_SUIT_SDFW_RECOVERY_UPDATE_FIRMWARE_OFFSET);
226+
uint8_t *current_sdfw_digest = (uint8_t *)(NRF_SICR->UROT.RECOVERY.SM.TBS.FW.DIGEST);
227+
228+
/* Compare candidate's digest with current SDFW Recovery digest */
229+
digest_sink_err_t err =
230+
verify_digest(candidate_binary_start,
231+
size - (size_t)CONFIG_SUIT_SDFW_RECOVERY_UPDATE_FIRMWARE_OFFSET,
232+
PSA_ALG_SHA_512, current_sdfw_digest);
233+
if (err != SUIT_PLAT_SUCCESS) {
234+
if (err == DIGEST_SINK_ERR_DIGEST_MISMATCH) {
235+
LOG_ERR("Digest mismatch - update failure");
236+
return SUIT_PLAT_ERR_AUTHENTICATION;
237+
}
183238

184-
bool digests_match = memcmp(candidate_digest_in_manifest, current_sdfw_recovery_digest,
185-
PSA_HASH_LENGTH(PSA_ALG_SHA_512)) == 0;
239+
LOG_ERR("Failed to calculate digest: %d", err);
240+
return SUIT_PLAT_ERR_CRASH;
241+
}
186242

187-
/* Update is needed when candidate's digest doesn't match current FW digest */
188-
return !digests_match;
243+
LOG_DBG("Digest match - update success");
244+
return SUIT_PLAT_SUCCESS;
189245
}
190246

191247
/* NOTE: Size means size of the SDFW binary to be updated,
@@ -211,12 +267,57 @@ static suit_plat_err_t write(void *ctx, const uint8_t *buf, size_t size)
211267
context->write_called = true;
212268

213269
suit_plat_err_t err = SUIT_PLAT_SUCCESS;
270+
bool clear_registers = true;
214271

215-
if (is_update_needed(buf, size)) {
216-
LOG_INF("Update needed");
217-
err = update_needed_action(buf, size);
218-
} else {
219-
LOG_INF("Update not needed");
272+
switch (NRF_SICR->UROT.UPDATE.STATUS) {
273+
case SICR_UROT_UPDATE_STATUS_CODE_None: {
274+
err = check_urot_none(buf, size);
275+
/* Potential start of update process - SecROM needs the registers to be set */
276+
clear_registers = false;
277+
break;
278+
}
279+
280+
case SICR_UROT_UPDATE_STATUS_CODE_RecoveryActivated: {
281+
err = check_recovery_activated(buf, size);
282+
clear_registers = true;
283+
break;
284+
}
285+
286+
/* TODO: Add handling of status RecoveryUnconfirmed and RecoveryConfirmed.
287+
* For now the defines for these states are missing in mdk header files.
288+
* NCSDK-26939
289+
*/
290+
291+
case SICR_UROT_UPDATE_STATUS_CODE_UROTActivated:
292+
case SICR_UROT_UPDATE_STATUS_CODE_VerifyOK:
293+
case SICR_UROT_UPDATE_STATUS_CODE_AROTRecovery: {
294+
LOG_ERR("Unsupported Recovery update status: 0x%08X", NRF_SICR->UROT.UPDATE.STATUS);
295+
err = SUIT_PLAT_ERR_INCORRECT_STATE;
296+
clear_registers = true;
297+
break;
298+
}
299+
300+
default: {
301+
LOG_ERR("SDFW Recovery update failure: 0x%08X", NRF_SICR->UROT.UPDATE.STATUS);
302+
err = NRF_SICR->UROT.UPDATE.STATUS;
303+
clear_registers = true;
304+
break;
305+
}
306+
}
307+
308+
if (clear_registers) {
309+
suit_plat_err_t clear_err = clear_urot_update_status();
310+
311+
if (clear_err) {
312+
LOG_ERR("Failed to clear UROT update status");
313+
/* If the only error was during register clearing - report it. */
314+
/* Otherwise report the original cause of failure. */
315+
if (err == SUIT_PLAT_SUCCESS) {
316+
err = clear_err;
317+
}
318+
} else {
319+
LOG_DBG("UROT update status cleared");
320+
}
220321
}
221322

222323
return err;

0 commit comments

Comments
 (0)