1 /*
2 * SPDX-License-Identifier: BSD-3-Clause
3 * SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
4 *
5 */
6
7 #include "tfm_plat_nv_counters.h"
8 #include "tfm_plat_otp.h"
9
10 #if (PS_NS_NV_COUNTER_IN_ITS == 1)
11 #include "psa/internal_trusted_storage.h"
12 #endif
13
14 #include <limits.h>
15 #include <string.h>
16
17 #define OTP_COUNTER_MAX_SIZE 64
18 #define NV_COUNTER_SIZE 4
19 #define OTP_COUNTER_MAGIC 0xAEC7
20 #define ITS_NV_COUNTER_UID_BASE 0xFFFFFFFFFFFFA000
21
tfm_plat_init_nv_counter(void)22 enum tfm_plat_err_t tfm_plat_init_nv_counter(void)
23 {
24 return TFM_PLAT_ERR_SUCCESS;
25 }
26
read_otp_counter(enum tfm_otp_element_id_t id,uint8_t * val)27 static enum tfm_plat_err_t read_otp_counter(enum tfm_otp_element_id_t id,
28 uint8_t *val)
29 {
30 size_t counter_size;
31 enum tfm_plat_err_t err;
32 size_t idx;
33 uint16_t counter_value[OTP_COUNTER_MAX_SIZE / sizeof(uint16_t)] = {0};
34 uint32_t count;
35
36 err = tfm_plat_otp_get_size(id, &counter_size);
37 if (err != TFM_PLAT_ERR_SUCCESS) {
38 return err;
39 }
40
41 counter_size = counter_size > OTP_COUNTER_MAX_SIZE ? OTP_COUNTER_MAX_SIZE
42 : counter_size;
43
44 err = tfm_plat_otp_read(id, counter_size, (uint8_t *)counter_value);
45 if (err != TFM_PLAT_ERR_SUCCESS) {
46 return err;
47 }
48
49 count = 0;
50 for (idx = 0; idx < counter_size / sizeof(uint16_t); idx++) {
51 if (counter_value[idx] == OTP_COUNTER_MAGIC) {
52 count += 1;
53 } else if (counter_value[idx] == 0) {
54 break;
55 } else {
56 return TFM_PLAT_ERR_SYSTEM_ERR;
57 }
58 }
59
60 memcpy(val, &count, NV_COUNTER_SIZE);
61
62 return TFM_PLAT_ERR_SUCCESS;
63 }
64
65 #if (PS_NS_NV_COUNTER_IN_ITS == 1)
read_its_nv_counter(enum tfm_otp_element_id_t id,uint8_t * val)66 static enum tfm_plat_err_t read_its_nv_counter(enum tfm_otp_element_id_t id,
67 uint8_t *val)
68 {
69 psa_storage_uid_t uid = (ITS_NV_COUNTER_UID_BASE + id);
70 psa_status_t status;
71 size_t data_length = 0;
72
73 status = psa_its_get(uid, 0, NV_COUNTER_SIZE, val, &data_length);
74
75 if (status == PSA_ERROR_DOES_NOT_EXIST) {
76 memset(val, 0, NV_COUNTER_SIZE);
77 }
78
79 if (((status == PSA_SUCCESS) && (data_length == NV_COUNTER_SIZE)) ||
80 (status == PSA_ERROR_DOES_NOT_EXIST)) {
81 return TFM_PLAT_ERR_SUCCESS;
82 } else {
83 return TFM_PLAT_ERR_SYSTEM_ERR;
84 }
85 }
86 #endif /* (PS_NS_NV_COUNTER_IN_ITS == 1) */
87
tfm_plat_read_nv_counter(enum tfm_nv_counter_t counter_id,uint32_t size,uint8_t * val)88 enum tfm_plat_err_t tfm_plat_read_nv_counter(enum tfm_nv_counter_t counter_id,
89 uint32_t size, uint8_t *val)
90 {
91 if (size != NV_COUNTER_SIZE) {
92 return TFM_PLAT_ERR_INVALID_INPUT;
93 }
94
95 /* Assumes Platform nv counters are contiguous*/
96 if (counter_id >= PLAT_NV_COUNTER_BL2_0 &&
97 counter_id < (PLAT_NV_COUNTER_BL2_0 + MCUBOOT_IMAGE_NUMBER)) {
98 return read_otp_counter(PLAT_OTP_ID_NV_COUNTER_BL2_0 +
99 (counter_id - PLAT_NV_COUNTER_BL2_0),
100 val);
101 }
102
103 switch (counter_id) {
104 #if (PS_NS_NV_COUNTER_IN_ITS == 0)
105 case (PLAT_NV_COUNTER_NS_0):
106 return read_otp_counter(PLAT_OTP_ID_NV_COUNTER_NS_0, val);
107 case (PLAT_NV_COUNTER_NS_1):
108 return read_otp_counter(PLAT_OTP_ID_NV_COUNTER_NS_1, val);
109 case (PLAT_NV_COUNTER_NS_2):
110 return read_otp_counter(PLAT_OTP_ID_NV_COUNTER_NS_2, val);
111 case (PLAT_NV_COUNTER_PS_0):
112 return read_otp_counter(PLAT_OTP_ID_NV_COUNTER_PS_0, val);
113 case (PLAT_NV_COUNTER_PS_1):
114 return read_otp_counter(PLAT_OTP_ID_NV_COUNTER_PS_1, val);
115 case (PLAT_NV_COUNTER_PS_2):
116 return read_otp_counter(PLAT_OTP_ID_NV_COUNTER_PS_2, val);
117 #else
118 case (PLAT_NV_COUNTER_NS_0):
119 return read_its_nv_counter(PLAT_OTP_ID_NV_COUNTER_NS_0, val);
120 case (PLAT_NV_COUNTER_NS_1):
121 return read_its_nv_counter(PLAT_OTP_ID_NV_COUNTER_NS_1, val);
122 case (PLAT_NV_COUNTER_NS_2):
123 return read_its_nv_counter(PLAT_OTP_ID_NV_COUNTER_NS_2, val);
124 case (PLAT_NV_COUNTER_PS_0):
125 return read_its_nv_counter(PLAT_OTP_ID_NV_COUNTER_PS_0, val);
126 case (PLAT_NV_COUNTER_PS_1):
127 return read_its_nv_counter(PLAT_OTP_ID_NV_COUNTER_PS_1, val);
128 case (PLAT_NV_COUNTER_PS_2):
129 return read_its_nv_counter(PLAT_OTP_ID_NV_COUNTER_PS_2, val);
130 #endif /* (PS_NS_NV_COUNTER_IN_ITS == 0) */
131
132 default:
133 return TFM_PLAT_ERR_UNSUPPORTED;
134 }
135 }
136
set_otp_counter(enum tfm_otp_element_id_t id,uint32_t val)137 static enum tfm_plat_err_t set_otp_counter(enum tfm_otp_element_id_t id,
138 uint32_t val)
139 {
140 size_t counter_size;
141 enum tfm_plat_err_t err;
142 size_t idx;
143 uint16_t counter_value[OTP_COUNTER_MAX_SIZE / sizeof(uint16_t)] = {0};
144
145 err = tfm_plat_otp_get_size(id, &counter_size);
146 if (err != TFM_PLAT_ERR_SUCCESS) {
147 return err;
148 }
149
150 counter_size = counter_size > OTP_COUNTER_MAX_SIZE ? OTP_COUNTER_MAX_SIZE
151 : counter_size;
152
153 if (val > (counter_size / sizeof(uint16_t))) {
154 return TFM_PLAT_ERR_INVALID_INPUT;
155 }
156
157 for (idx = 0; idx < val; idx++) {
158 counter_value[idx] = OTP_COUNTER_MAGIC;
159 }
160
161 err = tfm_plat_otp_write(id, counter_size,
162 (uint8_t *)counter_value);
163
164 return err;
165 }
166
167 #if (PS_NS_NV_COUNTER_IN_ITS == 1)
set_its_nv_counter(enum tfm_otp_element_id_t id,uint32_t val)168 static enum tfm_plat_err_t set_its_nv_counter(enum tfm_otp_element_id_t id,
169 uint32_t val)
170 {
171 psa_storage_uid_t uid = (ITS_NV_COUNTER_UID_BASE + id);
172 psa_status_t status;
173
174 status = psa_its_set(uid, NV_COUNTER_SIZE, &val, PSA_STORAGE_FLAG_NONE);
175
176 if (status == PSA_SUCCESS) {
177 return TFM_PLAT_ERR_SUCCESS;
178 } else {
179 return TFM_PLAT_ERR_SYSTEM_ERR;
180 }
181 }
182 #endif /* (PS_NS_NV_COUNTER_IN_ITS == 1) */
183
tfm_plat_set_nv_counter(enum tfm_nv_counter_t counter_id,uint32_t value)184 enum tfm_plat_err_t tfm_plat_set_nv_counter(enum tfm_nv_counter_t counter_id,
185 uint32_t value)
186 {
187 /* Assumes Platform nv counters are contiguous*/
188 if (counter_id >= PLAT_NV_COUNTER_BL2_0 &&
189 counter_id < (PLAT_NV_COUNTER_BL2_0 + MCUBOOT_IMAGE_NUMBER)) {
190 return set_otp_counter(PLAT_OTP_ID_NV_COUNTER_BL2_0 +
191 (counter_id - PLAT_NV_COUNTER_BL2_0),
192 value);
193 }
194
195 switch (counter_id) {
196 #if (PS_NS_NV_COUNTER_IN_ITS == 0)
197 case (PLAT_NV_COUNTER_NS_0):
198 return set_otp_counter(PLAT_OTP_ID_NV_COUNTER_NS_0, value);
199 case (PLAT_NV_COUNTER_NS_1):
200 return set_otp_counter(PLAT_OTP_ID_NV_COUNTER_NS_1, value);
201 case (PLAT_NV_COUNTER_NS_2):
202 return set_otp_counter(PLAT_OTP_ID_NV_COUNTER_NS_2, value);
203 case (PLAT_NV_COUNTER_PS_0):
204 return set_otp_counter(PLAT_OTP_ID_NV_COUNTER_PS_0, value);
205 case (PLAT_NV_COUNTER_PS_1):
206 return set_otp_counter(PLAT_OTP_ID_NV_COUNTER_PS_1, value);
207 case (PLAT_NV_COUNTER_PS_2):
208 return set_otp_counter(PLAT_OTP_ID_NV_COUNTER_PS_2, value);
209 #else
210 case (PLAT_NV_COUNTER_NS_0):
211 return set_its_nv_counter(PLAT_OTP_ID_NV_COUNTER_NS_0, value);
212 case (PLAT_NV_COUNTER_NS_1):
213 return set_its_nv_counter(PLAT_OTP_ID_NV_COUNTER_NS_1, value);
214 case (PLAT_NV_COUNTER_NS_2):
215 return set_its_nv_counter(PLAT_OTP_ID_NV_COUNTER_NS_2, value);
216 case (PLAT_NV_COUNTER_PS_0):
217 return set_its_nv_counter(PLAT_OTP_ID_NV_COUNTER_PS_0, value);
218 case (PLAT_NV_COUNTER_PS_1):
219 return set_its_nv_counter(PLAT_OTP_ID_NV_COUNTER_PS_1, value);
220 case (PLAT_NV_COUNTER_PS_2):
221 return set_its_nv_counter(PLAT_OTP_ID_NV_COUNTER_PS_2, value);
222 #endif /* (PS_NS_NV_COUNTER_IN_ITS == 0) */
223
224 default:
225 return TFM_PLAT_ERR_UNSUPPORTED;
226 }
227 }
228
tfm_plat_increment_nv_counter(enum tfm_nv_counter_t counter_id)229 enum tfm_plat_err_t tfm_plat_increment_nv_counter(
230 enum tfm_nv_counter_t counter_id)
231 {
232 uint32_t security_cnt;
233 enum tfm_plat_err_t err;
234
235 err = tfm_plat_read_nv_counter(counter_id,
236 sizeof(security_cnt),
237 (uint8_t *)&security_cnt);
238 if (err != TFM_PLAT_ERR_SUCCESS) {
239 return err;
240 }
241
242 return tfm_plat_set_nv_counter(counter_id, security_cnt + 1u);
243 }
244