9
9
10
10
#include <string.h>
11
11
#include <zephyr/types.h>
12
+ #include <zephyr/autoconf.h>
12
13
#include <drivers/nrfx_common.h>
14
+ #if defined(CONFIG_NRFX_NVMC )
13
15
#include <nrfx_nvmc.h>
16
+ #elif defined(CONFIG_NRFX_RRAMC )
17
+ #include <nrfx_rramc.h>
18
+ #else
19
+ #error "No NRFX storage technology supported backend selected"
20
+ #endif
14
21
#include <errno.h>
15
22
#include <pm_config.h>
16
23
19
26
extern "C" {
20
27
#endif
21
28
29
+ #if defined(CONFIG_NRFX_NVMC )
30
+ typedef uint16_t counter_t ;
31
+ typedef uint16_t lcs_data_t ;
32
+ typedef uint16_t lcs_reserved_t ;
33
+ #elif defined(CONFIG_NRFX_RRAMC )
34
+ /* nRF54L15 only supports word writes */
35
+ typedef uint32_t counter_t ;
36
+ typedef uint32_t lcs_data_t ;
37
+ typedef uint32_t lcs_reserved_t ;
38
+ #endif
39
+
22
40
#define EHASHFF 113 /* A hash contains too many 0xFs. */
23
41
#define EREADLCS 114 /* LCS field of OTP is in an invalid state */
24
42
#define EINVALIDLCS 115 /* Invalid LCS*/
@@ -46,17 +64,52 @@ extern "C" {
46
64
* This works as ASSEMBLY implies the OTP to be erased.
47
65
*/
48
66
struct life_cycle_state_data {
49
- uint16_t provisioning ;
50
- uint16_t secure ;
51
- /* Pad to end the alignment at a 4-byte boundary as the UICR->OTP
52
- * only supports 4-byte reads. We place the reserved padding in
53
- * the middle of the struct in case we ever need to support
67
+ lcs_data_t provisioning ;
68
+ lcs_data_t secure ;
69
+ /* Pad to end the alignment at a 4-byte boundary as some devices
70
+ * are only supporting 4-byte UICR->OTP reads. We place the reserved
71
+ * padding in the middle of the struct in case we ever need to support
54
72
* another state.
55
73
*/
56
- uint16_t reserved_for_padding ;
57
- uint16_t decommissioned ;
74
+ lcs_reserved_t reserved_for_padding ;
75
+ lcs_data_t decommissioned ;
76
+ };
77
+
78
+ /** This library implements monotonic counters where each time the counter
79
+ * is increased, a new slot is written.
80
+ * This way, the counter can be updated without erase. This is, among other things,
81
+ * necessary so the counter can be used in the OTP section of the UICR
82
+ * (available on e.g. nRF91 and nRF53).
83
+ */
84
+ struct monotonic_counter {
85
+ /* Counter description. What the counter is used for. See
86
+ * BL_MONOTONIC_COUNTERS_DESC_x.
87
+ */
88
+ uint16_t description ;
89
+ /* Number of entries in 'counter_slots' list. */
90
+ uint16_t num_counter_slots ;
91
+ counter_t counter_slots [1 ];
58
92
};
59
93
94
+ /** The second data structure in the provision page. It has unknown length since
95
+ * 'counters' is repeated. Note that each entry in counters also has unknown
96
+ * length, and each entry can have different length from the others, so the
97
+ * entries beyond the first cannot be accessed via array indices.
98
+ */
99
+ struct counter_collection {
100
+ uint16_t type ; /* Must be "monotonic counter". */
101
+ uint16_t num_counters ; /* Number of entries in 'counters' list. */
102
+ struct monotonic_counter counters [1 ];
103
+ };
104
+
105
+ NRFX_STATIC_INLINE uint32_t bl_storage_word_read (uint32_t address );
106
+ NRFX_STATIC_INLINE uint32_t bl_storage_word_write (uint32_t address , uint32_t value );
107
+ NRFX_STATIC_INLINE counter_t bl_storage_counter_get (uint32_t address );
108
+ NRFX_STATIC_INLINE void bl_storage_counter_set (uint32_t address , counter_t value );
109
+
110
+ const struct monotonic_counter * get_counter_struct (uint16_t description );
111
+ int get_counter (uint16_t counter_desc , counter_t * counter_value , const counter_t * * free_slot );
112
+
60
113
/** The first data structure in the bootloader storage. It has unknown length
61
114
* since 'key_data' is repeated. This data structure is immediately followed by
62
115
* struct counter_collection.
@@ -155,7 +208,7 @@ int num_monotonic_counter_slots(uint16_t counter_desc, uint16_t *counter_slots);
155
208
* @retval -EINVAL Cannot find counters with description @p counter_desc or the pointer to
156
209
* @p counter_value is NULL.
157
210
*/
158
- int get_monotonic_counter (uint16_t counter_desc , uint16_t * counter_value );
211
+ int get_monotonic_counter (uint16_t counter_desc , counter_t * counter_value );
159
212
160
213
/**
161
214
* @brief Set the current HW monotonic counter.
@@ -174,7 +227,7 @@ int get_monotonic_counter(uint16_t counter_desc, uint16_t *counter_value);
174
227
* @retval -ENOMEM There are no more free counter slots (see
175
228
* @kconfig{CONFIG_SB_NUM_VER_COUNTER_SLOTS}).
176
229
*/
177
- int set_monotonic_counter (uint16_t counter_desc , uint16_t new_counter );
230
+ int set_monotonic_counter (uint16_t counter_desc , counter_t new_counter );
178
231
179
232
/**
180
233
* @brief The PSA life cycle states a device can be in.
@@ -202,7 +255,7 @@ NRFX_STATIC_INLINE void otp_copy32(uint8_t *restrict dst, uint32_t volatile * re
202
255
{
203
256
for (int i = 0 ; i < size / 4 ; i ++ ) {
204
257
/* OTP is in UICR */
205
- uint32_t val = nrfx_nvmc_uicr_word_read ( src + i );
258
+ uint32_t val = bl_storage_word_read (( uint32_t )( src + i ) );
206
259
207
260
for (int j = 0 ; j < 4 ; j ++ ) {
208
261
dst [i * 4 + j ] = (val >> 8 * j ) & 0xFF ;
@@ -238,6 +291,87 @@ NRFX_STATIC_INLINE void read_implementation_id_from_otp(uint8_t *buf)
238
291
* This is a temporary solution until TF-M has access to NSIB functions.
239
292
*/
240
293
294
+ #if defined(CONFIG_NRFX_RRAMC )
295
+ NRFX_STATIC_INLINE uint32_t index_from_address (uint32_t address )
296
+ {
297
+ return ((address - (uint32_t )BL_STORAGE )/sizeof (uint32_t ));
298
+ }
299
+ #endif
300
+
301
+ NRFX_STATIC_INLINE counter_t bl_storage_counter_get (uint32_t address )
302
+ {
303
+ #if defined(CONFIG_NRFX_NVMC )
304
+ return ~nrfx_nvmc_otp_halfword_read (address );
305
+ #elif defined(CONFIG_NRFX_RRAMC )
306
+ return ~nrfx_rramc_otp_word_read (index_from_address (address ));
307
+ #endif
308
+ }
309
+
310
+ NRFX_STATIC_INLINE void bl_storage_counter_set (uint32_t address , counter_t value )
311
+ {
312
+ #if defined(CONFIG_NRFX_NVMC )
313
+ nrfx_nvmc_halfword_write ((uint32_t )address , ~value );
314
+ #elif defined(CONFIG_NRFX_RRAMC )
315
+ nrfx_rramc_otp_word_write (index_from_address ((uint32_t )address ), ~value );
316
+ #endif
317
+ }
318
+
319
+ NRFX_STATIC_INLINE uint32_t bl_storage_word_read (uint32_t address )
320
+ {
321
+ #if defined(CONFIG_NRFX_NVMC )
322
+ return nrfx_nvmc_uicr_word_read ((uint32_t * )address );
323
+ #elif defined(CONFIG_NRFX_RRAMC )
324
+ return nrfx_rramc_word_read (address );
325
+ #endif
326
+ }
327
+
328
+ NRFX_STATIC_INLINE uint32_t bl_storage_word_write (uint32_t address , uint32_t value )
329
+ {
330
+ #if defined(CONFIG_NRFX_NVMC )
331
+ nrfx_nvmc_word_write (address , value );
332
+ return 0 ;
333
+ #elif defined(CONFIG_NRFX_RRAMC )
334
+ nrfx_rramc_word_write (address , value );
335
+ return 0 ;
336
+ #endif
337
+ }
338
+
339
+ NRFX_STATIC_INLINE uint16_t bl_storage_otp_halfword_read (uint32_t address )
340
+ {
341
+ uint16_t halfword ;
342
+ #if defined(CONFIG_NRFX_NVMC )
343
+ halfword = nrfx_nvmc_otp_halfword_read (address );
344
+ #elif defined(CONFIG_NRFX_RRAMC )
345
+ uint32_t word = nrfx_rramc_otp_word_read (index_from_address (address ));
346
+
347
+ if (!(address & 0x3 )) {
348
+ halfword = (uint16_t )(word & 0x0000FFFF ); /* C truncates the upper bits */
349
+ } else {
350
+ halfword = (uint16_t )(word >> 16 ); /* Shift the upper half down */
351
+ }
352
+ #endif
353
+ return halfword ;
354
+ }
355
+
356
+ NRFX_STATIC_INLINE lcs_data_t bl_storage_lcs_get (uint32_t address )
357
+ {
358
+ #if defined(CONFIG_NRFX_NVMC )
359
+ return nrfx_nvmc_otp_halfword_read (address );
360
+ #elif defined(CONFIG_NRFX_RRAMC )
361
+ return nrfx_rramc_otp_word_read (index_from_address (address ));
362
+ #endif
363
+ }
364
+
365
+ NRFX_STATIC_INLINE int bl_storage_lcs_set (uint32_t address , lcs_data_t state )
366
+ {
367
+ #if defined(CONFIG_NRFX_NVMC )
368
+ nrfx_nvmc_halfword_write (address , state );
369
+ #elif defined(CONFIG_NRFX_RRAMC )
370
+ bl_storage_word_write (address , state );
371
+ #endif
372
+ return 0 ;
373
+ }
374
+
241
375
/**
242
376
* @brief Read the current life cycle state the device is in from OTP,
243
377
*
@@ -252,10 +386,10 @@ NRFX_STATIC_INLINE int read_life_cycle_state(enum lcs *lcs)
252
386
return - EINVAL ;
253
387
}
254
388
255
- uint16_t provisioning = nrfx_nvmc_otp_halfword_read (
389
+ lcs_data_t provisioning = bl_storage_lcs_get (
256
390
(uint32_t ) & BL_STORAGE -> lcs .provisioning );
257
- uint16_t secure = nrfx_nvmc_otp_halfword_read ((uint32_t ) & BL_STORAGE -> lcs .secure );
258
- uint16_t decommissioned = nrfx_nvmc_otp_halfword_read (
391
+ lcs_data_t secure = bl_storage_lcs_get ((uint32_t ) & BL_STORAGE -> lcs .secure );
392
+ lcs_data_t decommissioned = bl_storage_lcs_get (
259
393
(uint32_t ) & BL_STORAGE -> lcs .decommissioned );
260
394
261
395
if (provisioning == STATE_NOT_ENTERED
@@ -318,18 +452,15 @@ NRFX_STATIC_INLINE int update_life_cycle_state(enum lcs next_lcs)
318
452
319
453
/* As the device starts in ASSEMBLY, it is not possible to write it */
320
454
if (current_lcs == BL_STORAGE_LCS_ASSEMBLY && next_lcs == BL_STORAGE_LCS_PROVISIONING ) {
321
- nrfx_nvmc_halfword_write ((uint32_t )& BL_STORAGE -> lcs .provisioning , STATE_ENTERED );
322
- return 0 ;
455
+ return bl_storage_lcs_set ((uint32_t )& BL_STORAGE -> lcs .provisioning , STATE_ENTERED );
323
456
}
324
457
325
458
if (current_lcs == BL_STORAGE_LCS_PROVISIONING && next_lcs == BL_STORAGE_LCS_SECURED ) {
326
- nrfx_nvmc_halfword_write ((uint32_t )& BL_STORAGE -> lcs .secure , STATE_ENTERED );
327
- return 0 ;
459
+ return bl_storage_lcs_set ((uint32_t )& BL_STORAGE -> lcs .secure , STATE_ENTERED );
328
460
}
329
461
330
462
if (current_lcs == BL_STORAGE_LCS_SECURED && next_lcs == BL_STORAGE_LCS_DECOMMISSIONED ) {
331
- nrfx_nvmc_halfword_write ((uint32_t )& BL_STORAGE -> lcs .decommissioned , STATE_ENTERED );
332
- return 0 ;
463
+ return bl_storage_lcs_set ((uint32_t )& BL_STORAGE -> lcs .decommissioned , STATE_ENTERED );
333
464
}
334
465
335
466
/* This will be the case if any invalid transition is tried */
0 commit comments