1414#include <sdfw/sdfw_update.h>
1515#include <suit_plat_mem_util.h>
1616
17- #include <suit_digest_sink.h>
18-
1917#define SUIT_MAX_SDFW_RECOVERY_COMPONENTS 1
2018
21- #define SDFW_RECOVERY_SINK_ERR_AGAIN \
22- 1 /* Reboot is needed before proceeding. Call the API again. \
23- */
24-
2519LOG_MODULE_REGISTER (suit_sdfw_recovery_sink , CONFIG_SUIT_LOG_LEVEL );
2620
27- typedef int sdf_sink_err_t ;
28-
2921struct sdfw_recovery_sink_context {
3022 bool in_use ;
3123 bool write_called ;
@@ -44,55 +36,18 @@ static struct sdfw_recovery_sink_context *get_new_context(void)
4436 return NULL ;
4537}
4638
47- static digest_sink_err_t verify_digest (uint8_t * buf , size_t buf_size , psa_algorithm_t algorithm ,
48- uint8_t * expected_digest )
39+ static suit_plat_err_t schedule_update (const uint8_t * buf , size_t size )
4940{
50- struct stream_sink digest_sink ;
51- suit_plat_err_t err = suit_digest_sink_get (& digest_sink , algorithm , expected_digest );
52-
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 ;
63- }
64-
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 );
41+ int err = 0 ;
7942
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 ;
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 ;
9050 }
91- }
92-
93- static suit_plat_err_t schedule_sdfw_recovery_update (const uint8_t * buf , size_t size )
94- {
95- int err = 0 ;
9651
9752 const struct sdfw_update_blob update_blob = {
9853 .manifest_addr =
@@ -122,66 +77,18 @@ static suit_plat_err_t schedule_sdfw_recovery_update(const uint8_t *buf, size_t
12277
12378 if (err ) {
12479 LOG_ERR ("Failed to schedule SDFW Recovery update: %d" , err );
125- return SUIT_PLAT_ERR_CRASH ;
126- }
127-
128- LOG_INF ("SDFW Recovery update scheduled" );
129-
130- return SUIT_PLAT_SUCCESS ;
131- }
132-
133- static sdf_sink_err_t check_update_candidate (const uint8_t * buf , size_t size )
134- {
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 );
141-
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- }
154-
155- return SUIT_PLAT_ERR_CRASH ;
156- }
157-
158- LOG_DBG ("Candidate consistent" );
159-
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 );
164- if (err == SUIT_PLAT_SUCCESS ) {
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 ;
173- }
174- return err ;
80+ err = SUIT_PLAT_ERR_CRASH ;
81+ } else {
82+ err = SUIT_PLAT_SUCCESS ;
17583 }
17684
177- LOG_ERR ("Failed to calculate digest: %d" , err );
178- return SUIT_PLAT_ERR_CRASH ;
85+ return err ;
17986}
18087
18188static void reboot_to_continue (void )
18289{
18390 if (IS_ENABLED (CONFIG_SUIT_UPDATE_REBOOT_ENABLED )) {
184- LOG_INF ("Reboot the system to continue SDFW Recovery update" );
91+ LOG_INF ("Reboot the system to continue update" );
18592
18693 LOG_PANIC ();
18794
@@ -191,26 +98,15 @@ static void reboot_to_continue(void)
19198 }
19299}
193100
194- static suit_plat_err_t check_urot_none (const uint8_t * buf , size_t size )
101+ static suit_plat_err_t schedule_update_and_reboot (const uint8_t * buf , size_t size )
195102{
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- }
203-
204- LOG_INF ("Update candidate found" );
103+ suit_plat_err_t err = schedule_update (buf , size );
205104
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 */
105+ if (err == SUIT_PLAT_SUCCESS ) {
210106 reboot_to_continue ();
211107 if (IS_ENABLED (CONFIG_SUIT_UPDATE_REBOOT_ENABLED )) {
212108 /* If this code is reached, it means that reboot did not work. */
213- /* In such case report an error and convert the error code . */
109+ /* In such case report an error. */
214110 LOG_ERR ("Expected reboot did not happen" );
215111 err = SUIT_PLAT_ERR_UNREACHABLE_PATH ;
216112 }
@@ -219,29 +115,77 @@ static suit_plat_err_t check_urot_none(const uint8_t *buf, size_t size)
219115 return err ;
220116}
221117
222- static suit_plat_err_t check_recovery_activated (const uint8_t * buf , size_t size )
118+ static suit_plat_err_t update_already_ongoing (const uint8_t * buf , size_t size )
223119{
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- }
120+ suit_plat_err_t err = SUIT_PLAT_SUCCESS ;
121+
122+ enum sdfw_update_status update_status = sdfw_update_initial_status_get ();
238123
239- LOG_ERR ("Failed to calculate digest: %d" , err );
240- return SUIT_PLAT_ERR_CRASH ;
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+ }
241143 }
242144
243- LOG_DBG ("Digest match - update success" );
244- return SUIT_PLAT_SUCCESS ;
145+ return err ;
146+ }
147+
148+ static suit_plat_err_t update_needed_action (const uint8_t * buf , size_t size )
149+ {
150+ suit_plat_err_t err = SUIT_PLAT_SUCCESS ;
151+
152+ enum sdfw_update_operation initial_operation = sdfw_update_initial_operation_get ();
153+
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+ }
172+ }
173+
174+ return err ;
175+ }
176+
177+ static bool is_update_needed (const uint8_t * buf , size_t size )
178+ {
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 );
183+
184+ bool digests_match = memcmp (candidate_digest_in_manifest , current_sdfw_recovery_digest ,
185+ PSA_HASH_LENGTH (PSA_ALG_SHA_512 )) == 0 ;
186+
187+ /* Update is needed when candidate's digest doesn't match current FW digest */
188+ return !digests_match ;
245189}
246190
247191/* NOTE: Size means size of the SDFW binary to be updated,
@@ -267,57 +211,12 @@ static suit_plat_err_t write(void *ctx, const uint8_t *buf, size_t size)
267211 context -> write_called = true;
268212
269213 suit_plat_err_t err = SUIT_PLAT_SUCCESS ;
270- bool clear_registers = true;
271-
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- }
285214
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- }
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" );
321220 }
322221
323222 return err ;
0 commit comments