99
1010#include <string.h>
1111#include <zephyr/types.h>
12+ #include <zephyr/autoconf.h>
1213#include <drivers/nrfx_common.h>
14+ #if defined(CONFIG_NRFX_NVMC )
1315#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
1421#include <errno.h>
1522#include <pm_config.h>
1623
1926extern "C" {
2027#endif
2128
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+
2240#define EHASHFF 113 /* A hash contains too many 0xFs. */
2341#define EREADLCS 114 /* LCS field of OTP is in an invalid state */
2442#define EINVALIDLCS 115 /* Invalid LCS*/
@@ -46,17 +64,52 @@ extern "C" {
4664 * This works as ASSEMBLY implies the OTP to be erased.
4765 */
4866struct 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
5472 * another state.
5573 */
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 ];
5892};
5993
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+
60113/** The first data structure in the bootloader storage. It has unknown length
61114 * since 'key_data' is repeated. This data structure is immediately followed by
62115 * struct counter_collection.
@@ -155,7 +208,7 @@ int num_monotonic_counter_slots(uint16_t counter_desc, uint16_t *counter_slots);
155208 * @retval -EINVAL Cannot find counters with description @p counter_desc or the pointer to
156209 * @p counter_value is NULL.
157210 */
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 );
159212
160213/**
161214 * @brief Set the current HW monotonic counter.
@@ -174,7 +227,7 @@ int get_monotonic_counter(uint16_t counter_desc, uint16_t *counter_value);
174227 * @retval -ENOMEM There are no more free counter slots (see
175228 * @kconfig{CONFIG_SB_NUM_VER_COUNTER_SLOTS}).
176229 */
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 );
178231
179232/**
180233 * @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
202255{
203256 for (int i = 0 ; i < size / 4 ; i ++ ) {
204257 /* 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 ) );
206259
207260 for (int j = 0 ; j < 4 ; j ++ ) {
208261 dst [i * 4 + j ] = (val >> 8 * j ) & 0xFF ;
@@ -238,6 +291,87 @@ NRFX_STATIC_INLINE void read_implementation_id_from_otp(uint8_t *buf)
238291 * This is a temporary solution until TF-M has access to NSIB functions.
239292 */
240293
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+
241375/**
242376 * @brief Read the current life cycle state the device is in from OTP,
243377 *
@@ -252,10 +386,10 @@ NRFX_STATIC_INLINE int read_life_cycle_state(enum lcs *lcs)
252386 return - EINVAL ;
253387 }
254388
255- uint16_t provisioning = nrfx_nvmc_otp_halfword_read (
389+ lcs_data_t provisioning = bl_storage_lcs_get (
256390 (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 (
259393 (uint32_t ) & BL_STORAGE -> lcs .decommissioned );
260394
261395 if (provisioning == STATE_NOT_ENTERED
@@ -318,18 +452,15 @@ NRFX_STATIC_INLINE int update_life_cycle_state(enum lcs next_lcs)
318452
319453 /* As the device starts in ASSEMBLY, it is not possible to write it */
320454 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 );
323456 }
324457
325458 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 );
328460 }
329461
330462 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 );
333464 }
334465
335466 /* This will be the case if any invalid transition is tried */
0 commit comments