Skip to content

Commit 817d645

Browse files
michalek-norlubos
authored andcommitted
bl_storage: fw_info/counters port to RRAMC
Changed the implementation of bl_storage to be compatible with RRAMC and FLASH/NVMC. Due to the limitations in the RRAM controller OTP can only be written to by words not half-words as it can be in NVMC. This means we need to change the way we handle certain cases in `bl_storage.c`, `bl_validation.c` and `fw_info.c`. This commit moves some of the abstractions into two separate files `bl_storage_nvmc.c` and `bl_storage_rramc.c`. However there are multiple other changes needed which are done by using `#ifdef`'s. Ref. NCSDK-25306 Signed-off-by: Mateusz Michalek <mateusz.michalek@nordicsemi.no>
1 parent 4dd6c7a commit 817d645

File tree

6 files changed

+214
-86
lines changed

6 files changed

+214
-86
lines changed

include/bl_storage.h

+150-19
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,15 @@
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

@@ -19,6 +26,17 @@
1926
extern "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
*/
4866
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
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 */

include/bl_validation.h

+4-3
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ extern "C" {
1414
#include <stdbool.h>
1515
#include <fw_info.h>
1616
#include <zephyr/types.h>
17+
#include <bl_storage.h>
1718

1819
/** @defgroup bl_validation Bootloader firmware validation
1920
* @{
@@ -72,7 +73,7 @@ struct bl_validate_fw_ext_api {
7273
*
7374
* @return See @ref set_monotonic_counter.
7475
*/
75-
int set_monotonic_version(uint16_t version, uint16_t slot);
76+
int set_monotonic_version(counter_t version, uint16_t slot);
7677

7778
/** Write the stored 15-bit version to the 16-bit output parameter 'version_out'.
7879
*
@@ -81,7 +82,7 @@ int set_monotonic_version(uint16_t version, uint16_t slot);
8182
* @retval 0 Success
8283
* @retval -EINVAL Error during reading the version or version is NULL.
8384
*/
84-
int get_monotonic_version(uint16_t *version_out);
85+
int get_monotonic_version(counter_t *version_out);
8586

8687
/** Write the stored slot to the output parameter 'slot_out'.
8788
*
@@ -90,7 +91,7 @@ int get_monotonic_version(uint16_t *version_out);
9091
* @retval 0 Success
9192
* @retval -EINVAL Error during reading the version or version is NULL.
9293
*/
93-
int get_monotonic_slot(uint16_t *slot_out);
94+
int get_monotonic_slot(counter_t *slot_out);
9495

9596
/** @} */
9697

samples/bootloader/src/main.c

+10
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,13 @@
1313
#include <bl_storage.h>
1414
#include <bl_boot.h>
1515
#include <bl_validation.h>
16+
#ifdef CONFIG_NRFX_NVMC
1617
#include <nrfx_nvmc.h>
18+
#elif defined(CONFIG_NRFX_RRAMC)
19+
#include <nrfx_rramc.h>
20+
#else
21+
#error "No NRFX memory backend selected"
22+
#endif
1723

1824
#if defined(CONFIG_HW_UNIQUE_KEY_LOAD)
1925
#include <zephyr/init.h>
@@ -28,7 +34,11 @@ int load_huk(void)
2834

2935
if (*(uint32_t *)huk_flag_addr == 0xFFFFFFFF) {
3036
printk("First boot, expecting app to write HUK.\n");
37+
#ifdef CONFIG_NRFX_NVMC
3138
nrfx_nvmc_word_write(huk_flag_addr, 0);
39+
#elif defined(CONFIG_NRFX_RRAMC)
40+
nrfx_rramc_word_write(huk_flag_addr, 0);
41+
#endif
3242
return 0;
3343
}
3444
printk("Error: Hardware Unique Key not present.\n");

0 commit comments

Comments
 (0)