Skip to content

Commit 8f554cc

Browse files
committed
[nrf fromtree] soc: nordic: ironside: Add counter service
Add counter service. Signed-off-by: Sebastian Bøe <[email protected]> (cherry-picked from commit f324a15)
1 parent 716d6a7 commit 8f554cc

File tree

4 files changed

+230
-0
lines changed

4 files changed

+230
-0
lines changed

soc/nordic/ironside/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ zephyr_library_sources_ifdef(CONFIG_NRF_IRONSIDE_BOOTMODE_SERVICE bootmode.c)
1010
zephyr_library_sources_ifdef(CONFIG_NRF_IRONSIDE_TDD_SERVICE tdd.c)
1111
zephyr_library_sources_ifdef(CONFIG_NRF_IRONSIDE_UPDATE_SERVICE update.c)
1212
zephyr_library_sources_ifdef(CONFIG_NRF_IRONSIDE_DVFS_SERVICE dvfs.c)
13+
zephyr_library_sources_ifdef(CONFIG_NRF_IRONSIDE_COUNTER_SERVICE counter.c)

soc/nordic/ironside/Kconfig

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,12 @@ config NRF_IRONSIDE_DVFS_SERVICE
6969
help
7070
Service used to handle DVFS operating point requests.
7171

72+
config NRF_IRONSIDE_COUNTER_SERVICE
73+
bool "IronSide counter service"
74+
select NRF_IRONSIDE_CALL
75+
help
76+
Service used to manage secure monotonic counters.
77+
7278
if NRF_IRONSIDE_DVFS_SERVICE
7379

7480
config NRF_IRONSIDE_ABB_STATUSANA_CHECK_MAX_ATTEMPTS

soc/nordic/ironside/counter.c

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* Copyright (c) 2025 Nordic Semiconductor ASA
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
#include <nrf_ironside/counter.h>
7+
#include <nrf_ironside/call.h>
8+
9+
int ironside_counter_set(enum ironside_counter counter_id, uint32_t value)
10+
{
11+
int err;
12+
struct ironside_call_buf *const buf = ironside_call_alloc();
13+
14+
buf->id = IRONSIDE_CALL_ID_COUNTER_SET_V1;
15+
buf->args[IRONSIDE_COUNTER_SET_SERVICE_COUNTER_ID_IDX] = (uint32_t)counter_id;
16+
buf->args[IRONSIDE_COUNTER_SET_SERVICE_VALUE_IDX] = value;
17+
18+
ironside_call_dispatch(buf);
19+
20+
if (buf->status == IRONSIDE_CALL_STATUS_RSP_SUCCESS) {
21+
err = buf->args[IRONSIDE_COUNTER_SET_SERVICE_RETCODE_IDX];
22+
} else {
23+
err = buf->status;
24+
}
25+
26+
ironside_call_release(buf);
27+
28+
return err;
29+
}
30+
31+
int ironside_counter_get(enum ironside_counter counter_id, uint32_t *value)
32+
{
33+
int err;
34+
struct ironside_call_buf *buf;
35+
36+
if (value == NULL) {
37+
return -IRONSIDE_COUNTER_ERROR_INVALID_PARAM;
38+
}
39+
40+
buf = ironside_call_alloc();
41+
42+
buf->id = IRONSIDE_CALL_ID_COUNTER_GET_V1;
43+
buf->args[IRONSIDE_COUNTER_GET_SERVICE_COUNTER_ID_IDX] = (uint32_t)counter_id;
44+
45+
ironside_call_dispatch(buf);
46+
47+
if (buf->status == IRONSIDE_CALL_STATUS_RSP_SUCCESS) {
48+
err = buf->args[IRONSIDE_COUNTER_GET_SERVICE_RETCODE_IDX];
49+
if (err == 0) {
50+
*value = buf->args[IRONSIDE_COUNTER_GET_SERVICE_VALUE_IDX];
51+
}
52+
} else {
53+
err = buf->status;
54+
}
55+
56+
ironside_call_release(buf);
57+
58+
return err;
59+
}
60+
61+
int ironside_counter_lock(enum ironside_counter counter_id)
62+
{
63+
int err;
64+
struct ironside_call_buf *const buf = ironside_call_alloc();
65+
66+
buf->id = IRONSIDE_CALL_ID_COUNTER_LOCK_V1;
67+
buf->args[IRONSIDE_COUNTER_LOCK_SERVICE_COUNTER_ID_IDX] = (uint32_t)counter_id;
68+
69+
ironside_call_dispatch(buf);
70+
71+
if (buf->status == IRONSIDE_CALL_STATUS_RSP_SUCCESS) {
72+
err = buf->args[IRONSIDE_COUNTER_LOCK_SERVICE_RETCODE_IDX];
73+
} else {
74+
err = buf->status;
75+
}
76+
77+
ironside_call_release(buf);
78+
79+
return err;
80+
}
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
/*
2+
* Copyright (c) 2025 Nordic Semiconductor ASA
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
#ifndef ZEPHYR_SOC_NORDIC_IRONSIDE_INCLUDE_NRF_IRONSIDE_COUNTER_H_
7+
#define ZEPHYR_SOC_NORDIC_IRONSIDE_INCLUDE_NRF_IRONSIDE_COUNTER_H_
8+
9+
#include <stdint.h>
10+
#include <zephyr/toolchain/common.h>
11+
#include <nrf_ironside/call.h>
12+
13+
/**
14+
* @name Counter service error codes.
15+
* @{
16+
*/
17+
18+
/** Counter value is lower than current value (monotonic violation). */
19+
#define IRONSIDE_COUNTER_ERROR_TOO_LOW (1)
20+
/** Invalid counter ID. */
21+
#define IRONSIDE_COUNTER_ERROR_INVALID_ID (2)
22+
/** Counter is locked and cannot be modified. */
23+
#define IRONSIDE_COUNTER_ERROR_LOCKED (3)
24+
/** Invalid parameter. */
25+
#define IRONSIDE_COUNTER_ERROR_INVALID_PARAM (4)
26+
/** Storage operation failed. */
27+
#define IRONSIDE_COUNTER_ERROR_STORAGE_FAILURE (5)
28+
29+
/**
30+
* @}
31+
*/
32+
33+
/** Maximum value for a counter */
34+
#define IRONSIDE_COUNTER_MAX_VALUE UINT32_MAX
35+
36+
/** Number of counters */
37+
#define IRONSIDE_COUNTER_NUM 4
38+
39+
/**
40+
* @brief Counter identifiers.
41+
*/
42+
enum ironside_counter {
43+
IRONSIDE_COUNTER_0 = 0,
44+
IRONSIDE_COUNTER_1,
45+
IRONSIDE_COUNTER_2,
46+
IRONSIDE_COUNTER_3
47+
};
48+
49+
/* IronSide call identifiers with implicit versions. */
50+
#define IRONSIDE_CALL_ID_COUNTER_SET_V1 6
51+
#define IRONSIDE_CALL_ID_COUNTER_GET_V1 7
52+
#define IRONSIDE_CALL_ID_COUNTER_LOCK_V1 8
53+
54+
enum {
55+
IRONSIDE_COUNTER_SET_SERVICE_COUNTER_ID_IDX,
56+
IRONSIDE_COUNTER_SET_SERVICE_VALUE_IDX,
57+
/* The last enum value is reserved for the number of arguments */
58+
IRONSIDE_COUNTER_SET_NUM_ARGS
59+
};
60+
61+
enum {
62+
IRONSIDE_COUNTER_GET_SERVICE_COUNTER_ID_IDX,
63+
/* The last enum value is reserved for the number of arguments */
64+
IRONSIDE_COUNTER_GET_NUM_ARGS
65+
};
66+
67+
enum {
68+
IRONSIDE_COUNTER_LOCK_SERVICE_COUNTER_ID_IDX,
69+
/* The last enum value is reserved for the number of arguments */
70+
IRONSIDE_COUNTER_LOCK_NUM_ARGS
71+
};
72+
73+
/* Index of the return code within the service buffer. */
74+
#define IRONSIDE_COUNTER_SET_SERVICE_RETCODE_IDX (0)
75+
#define IRONSIDE_COUNTER_GET_SERVICE_RETCODE_IDX (0)
76+
#define IRONSIDE_COUNTER_LOCK_SERVICE_RETCODE_IDX (0)
77+
78+
/* Index of the value within the GET response buffer. */
79+
#define IRONSIDE_COUNTER_GET_SERVICE_VALUE_IDX (1)
80+
81+
BUILD_ASSERT(IRONSIDE_COUNTER_SET_NUM_ARGS <= NRF_IRONSIDE_CALL_NUM_ARGS);
82+
BUILD_ASSERT(IRONSIDE_COUNTER_GET_NUM_ARGS <= NRF_IRONSIDE_CALL_NUM_ARGS);
83+
BUILD_ASSERT(IRONSIDE_COUNTER_LOCK_NUM_ARGS <= NRF_IRONSIDE_CALL_NUM_ARGS);
84+
85+
/**
86+
* @brief Set a counter value.
87+
*
88+
* This sets the specified counter to the given value. The counter is monotonic,
89+
* so the new value must be greater than or equal to the current value.
90+
* If the counter is locked, the operation will fail.
91+
*
92+
* @note Counters are automatically initialized to 0 during the first boot in LCS ROT.
93+
* The monotonic constraint applies to all subsequent writes.
94+
*
95+
* @param counter_id Counter identifier.
96+
* @param value New counter value.
97+
*
98+
* @retval 0 on success.
99+
* @retval -IRONSIDE_COUNTER_ERROR_INVALID_ID if counter_id is invalid.
100+
* @retval -IRONSIDE_COUNTER_ERROR_TOO_LOW if value is lower than current value.
101+
* @retval -IRONSIDE_COUNTER_ERROR_LOCKED if counter is locked.
102+
* @retval -IRONSIDE_COUNTER_ERROR_STORAGE_FAILURE if storage operation failed.
103+
* @retval Positive error status if reported by IronSide call (see error codes in @ref call.h).
104+
*/
105+
int ironside_counter_set(enum ironside_counter counter_id, uint32_t value);
106+
107+
/**
108+
* @brief Get a counter value.
109+
*
110+
* This retrieves the current value of the specified counter.
111+
*
112+
* @note Counters are automatically initialized to 0 during the first boot in LCS ROT,
113+
* so this function will always succeed for valid counter IDs.
114+
*
115+
* @param counter_id Counter identifier.
116+
* @param value Pointer to store the counter value.
117+
*
118+
* @retval 0 on success.
119+
* @retval -IRONSIDE_COUNTER_ERROR_INVALID_ID if counter_id is invalid.
120+
* @retval -IRONSIDE_COUNTER_ERROR_INVALID_PARAM if value is NULL.
121+
* @retval -IRONSIDE_COUNTER_ERROR_STORAGE_FAILURE if storage operation failed.
122+
* @retval Positive error status if reported by IronSide call (see error codes in @ref call.h).
123+
*/
124+
int ironside_counter_get(enum ironside_counter counter_id, uint32_t *value);
125+
126+
/**
127+
* @brief Lock a counter for the current boot.
128+
*
129+
* This locks the specified counter, preventing any further modifications until the next reboot.
130+
* The lock state is not persistent and will be cleared on reboot.
131+
*
132+
* @note The intended use case is for a bootloader to lock a counter before transferring control
133+
* to the next boot stage, preventing that image from modifying the counter value.
134+
*
135+
* @param counter_id Counter identifier.
136+
*
137+
* @retval 0 on success.
138+
* @retval -IRONSIDE_COUNTER_ERROR_INVALID_ID if counter_id is invalid.
139+
* @retval Positive error status if reported by IronSide call (see error codes in @ref call.h).
140+
*/
141+
int ironside_counter_lock(enum ironside_counter counter_id);
142+
143+
#endif /* ZEPHYR_SOC_NORDIC_IRONSIDE_INCLUDE_NRF_IRONSIDE_COUNTER_H_ */

0 commit comments

Comments
 (0)