1 /*
2 * Copyright (c) 2021-2023, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8 /* NOTE: For the security of the protected storage system, the bootloader
9 * rollback protection, and the protection of cryptographic material it is
10 * CRITICAL to use a internal (in-die) persistent memory for the implementation
11 * of the OTP_NV_COUNTERS flash area (see flash_otp_nv_layout.c).
12 */
13
14 #include "tfm_plat_otp.h"
15
16 #include "flash_layout.h"
17 #include "flash_otp_nv_counters_backend.h"
18 #include <string.h>
19 #include <stddef.h>
20
tfm_plat_otp_init(void)21 enum tfm_plat_err_t tfm_plat_otp_init(void)
22 {
23 return init_otp_nv_counters_flash();
24 }
25
write_to_output(enum tfm_otp_element_id_t id,uint32_t offset,size_t out_len,uint8_t * out)26 static enum tfm_plat_err_t write_to_output(enum tfm_otp_element_id_t id,
27 uint32_t offset, size_t out_len,
28 uint8_t *out)
29 {
30 enum tfm_plat_err_t err = TFM_PLAT_ERR_SUCCESS;
31 size_t value_size;
32 size_t copy_size;
33
34 err = tfm_plat_otp_get_size(id, &value_size);
35 if (err != TFM_PLAT_ERR_SUCCESS) {
36 return err;
37 }
38
39 copy_size = out_len < value_size ? out_len : value_size;
40
41 err = read_otp_nv_counters_flash(offset, out, copy_size);
42 if (err != TFM_PLAT_ERR_SUCCESS) {
43 return err;
44 }
45
46 return TFM_PLAT_ERR_SUCCESS;
47 }
48
tfm_plat_otp_read(enum tfm_otp_element_id_t id,size_t out_len,uint8_t * out)49 enum tfm_plat_err_t tfm_plat_otp_read(enum tfm_otp_element_id_t id,
50 size_t out_len, uint8_t *out)
51 {
52 switch (id) {
53 case PLAT_OTP_ID_HUK:
54 return write_to_output(id, offsetof(struct flash_otp_nv_counters_region_t, huk), out_len, out);
55 case PLAT_OTP_ID_IAK:
56 return write_to_output(id, offsetof(struct flash_otp_nv_counters_region_t, iak), out_len, out);
57 case PLAT_OTP_ID_IAK_LEN:
58 return write_to_output(id, offsetof(struct flash_otp_nv_counters_region_t, iak_len), out_len, out);
59 case PLAT_OTP_ID_IAK_TYPE:
60 return write_to_output(id, offsetof(struct flash_otp_nv_counters_region_t, iak_type), out_len, out);
61 case PLAT_OTP_ID_IAK_ID:
62 return write_to_output(id, offsetof(struct flash_otp_nv_counters_region_t, iak_id), out_len, out);
63
64 case PLAT_OTP_ID_BOOT_SEED:
65 return write_to_output(id, offsetof(struct flash_otp_nv_counters_region_t, boot_seed), out_len, out);
66 case PLAT_OTP_ID_LCS:
67 return write_to_output(id, offsetof(struct flash_otp_nv_counters_region_t, lcs), out_len, out);
68 case PLAT_OTP_ID_IMPLEMENTATION_ID:
69 return write_to_output(id, offsetof(struct flash_otp_nv_counters_region_t, implementation_id), out_len, out);
70 case PLAT_OTP_ID_CERT_REF:
71 return write_to_output(id, offsetof(struct flash_otp_nv_counters_region_t, cert_ref), out_len, out);
72 case PLAT_OTP_ID_VERIFICATION_SERVICE_URL:
73 return write_to_output(id, offsetof(struct flash_otp_nv_counters_region_t, verification_service_url), out_len, out);
74 case PLAT_OTP_ID_PROFILE_DEFINITION:
75 return write_to_output(id, offsetof(struct flash_otp_nv_counters_region_t, profile_definition), out_len, out);
76
77 #ifdef BL2
78 case PLAT_OTP_ID_BL2_ROTPK_0:
79 return write_to_output(id, offsetof(struct flash_otp_nv_counters_region_t, bl2_rotpk_0), out_len, out);
80 case PLAT_OTP_ID_BL2_ROTPK_1:
81 return write_to_output(id, offsetof(struct flash_otp_nv_counters_region_t, bl2_rotpk_1), out_len, out);
82 case PLAT_OTP_ID_BL2_ROTPK_2:
83 return write_to_output(id, offsetof(struct flash_otp_nv_counters_region_t, bl2_rotpk_2), out_len, out);
84 case PLAT_OTP_ID_BL2_ROTPK_3:
85 return write_to_output(id, offsetof(struct flash_otp_nv_counters_region_t, bl2_rotpk_3), out_len, out);
86
87 case PLAT_OTP_ID_NV_COUNTER_BL2_0:
88 return write_to_output(id, offsetof(struct flash_otp_nv_counters_region_t, bl2_nv_counter_0), out_len, out);
89 case PLAT_OTP_ID_NV_COUNTER_BL2_1:
90 return write_to_output(id, offsetof(struct flash_otp_nv_counters_region_t, bl2_nv_counter_1), out_len, out);
91 case PLAT_OTP_ID_NV_COUNTER_BL2_2:
92 return write_to_output(id, offsetof(struct flash_otp_nv_counters_region_t, bl2_nv_counter_2), out_len, out);
93 case PLAT_OTP_ID_NV_COUNTER_BL2_3:
94 return write_to_output(id, offsetof(struct flash_otp_nv_counters_region_t, bl2_nv_counter_3), out_len, out);
95
96 #endif /* BL2 */
97
98 #ifdef BL1
99 case PLAT_OTP_ID_BL1_ROTPK_0:
100 return write_to_output(id, offsetof(struct flash_otp_nv_counters_region_t, bl1_rotpk_0), out_len, out);
101
102 case PLAT_OTP_ID_NV_COUNTER_BL1_0:
103 return write_to_output(id, offsetof(struct flash_otp_nv_counters_region_t, bl1_nv_counter_0), out_len, out);
104 #endif /* BL1 */
105
106 #if (PLATFORM_NS_NV_COUNTERS > 0)
107 case PLAT_OTP_ID_NV_COUNTER_NS_0:
108 return write_to_output(id, offsetof(struct flash_otp_nv_counters_region_t, ns_nv_counter_0), out_len, out);
109 #endif
110 #if (PLATFORM_NS_NV_COUNTERS > 1)
111 case PLAT_OTP_ID_NV_COUNTER_NS_1:
112 return write_to_output(id, offsetof(struct flash_otp_nv_counters_region_t, ns_nv_counter_1), out_len, out);
113 #endif
114 #if (PLATFORM_NS_NV_COUNTERS > 2)
115 case PLAT_OTP_ID_NV_COUNTER_NS_2:
116 return write_to_output(id, offsetof(struct flash_otp_nv_counters_region_t, ns_nv_counter_2), out_len, out);
117 #endif
118
119 case PLAT_OTP_ID_ENTROPY_SEED:
120 return write_to_output(id, offsetof(struct flash_otp_nv_counters_region_t, entropy_seed), out_len, out);
121
122 case PLAT_OTP_ID_SECURE_DEBUG_PK:
123 return write_to_output(id, offsetof(struct flash_otp_nv_counters_region_t, secure_debug_pk), out_len, out);
124
125 default:
126 return TFM_PLAT_ERR_UNSUPPORTED;
127 }
128 }
129
130 #if defined(OTP_WRITEABLE)
read_from_input(enum tfm_otp_element_id_t id,uint32_t offset,size_t in_len,const uint8_t * in)131 static enum tfm_plat_err_t read_from_input(enum tfm_otp_element_id_t id,
132 uint32_t offset, size_t in_len,
133 const uint8_t *in)
134 {
135 enum tfm_plat_err_t err = TFM_PLAT_ERR_SUCCESS;
136 size_t value_size;
137 uint8_t buffer[64];
138 size_t idx;
139
140 err = tfm_plat_otp_get_size(id, &value_size);
141 if (err != TFM_PLAT_ERR_SUCCESS) {
142 return err;
143 }
144
145 if (in_len > value_size) {
146 return TFM_PLAT_ERR_INVALID_INPUT;
147 }
148
149 if (sizeof(buffer) < value_size) {
150 return TFM_PLAT_ERR_INVALID_INPUT;
151 }
152
153 /* Check that we are not attempting to write any bits from 1 to 0 */
154 err = read_otp_nv_counters_flash(offset, buffer, in_len);
155 if (err != TFM_PLAT_ERR_SUCCESS) {
156 return err;
157 }
158 for (idx = 0; idx < in_len; idx++) {
159 if ((buffer[idx] | in[idx]) != in[idx]) {
160 return TFM_PLAT_ERR_INVALID_INPUT;
161 }
162 }
163
164 err = write_otp_nv_counters_flash(offset, in, in_len);
165 if (err != TFM_PLAT_ERR_SUCCESS) {
166 return err;
167 }
168
169 return TFM_PLAT_ERR_SUCCESS;
170 }
171
tfm_plat_otp_write(enum tfm_otp_element_id_t id,size_t in_len,const uint8_t * in)172 enum tfm_plat_err_t tfm_plat_otp_write(enum tfm_otp_element_id_t id,
173 size_t in_len, const uint8_t *in)
174 {
175 switch (id) {
176 case PLAT_OTP_ID_HUK:
177 return read_from_input(id, offsetof(struct flash_otp_nv_counters_region_t, huk), in_len, in);
178 case PLAT_OTP_ID_IAK:
179 return read_from_input(id, offsetof(struct flash_otp_nv_counters_region_t, iak), in_len, in);
180 case PLAT_OTP_ID_IAK_LEN:
181 return read_from_input(id, offsetof(struct flash_otp_nv_counters_region_t, iak_len), in_len, in);
182 case PLAT_OTP_ID_IAK_TYPE:
183 return read_from_input(id, offsetof(struct flash_otp_nv_counters_region_t, iak_type), in_len, in);
184 case PLAT_OTP_ID_IAK_ID:
185 return read_from_input(id, offsetof(struct flash_otp_nv_counters_region_t, iak_id), in_len, in);
186
187 case PLAT_OTP_ID_BOOT_SEED:
188 return read_from_input(id, offsetof(struct flash_otp_nv_counters_region_t, boot_seed), in_len, in);
189 case PLAT_OTP_ID_LCS:
190 return read_from_input(id, offsetof(struct flash_otp_nv_counters_region_t, lcs), in_len, in);
191 case PLAT_OTP_ID_IMPLEMENTATION_ID:
192 return read_from_input(id, offsetof(struct flash_otp_nv_counters_region_t, implementation_id), in_len, in);
193 case PLAT_OTP_ID_CERT_REF:
194 return read_from_input(id, offsetof(struct flash_otp_nv_counters_region_t, cert_ref), in_len, in);
195 case PLAT_OTP_ID_VERIFICATION_SERVICE_URL:
196 return read_from_input(id, offsetof(struct flash_otp_nv_counters_region_t, verification_service_url), in_len, in);
197 case PLAT_OTP_ID_PROFILE_DEFINITION:
198 return read_from_input(id, offsetof(struct flash_otp_nv_counters_region_t, profile_definition), in_len, in);
199
200 #ifdef BL2
201 case PLAT_OTP_ID_BL2_ROTPK_0:
202 return read_from_input(id, offsetof(struct flash_otp_nv_counters_region_t, bl2_rotpk_0), in_len, in);
203 case PLAT_OTP_ID_BL2_ROTPK_1:
204 return read_from_input(id, offsetof(struct flash_otp_nv_counters_region_t, bl2_rotpk_1), in_len, in);
205 case PLAT_OTP_ID_BL2_ROTPK_2:
206 return read_from_input(id, offsetof(struct flash_otp_nv_counters_region_t, bl2_rotpk_2), in_len, in);
207 case PLAT_OTP_ID_BL2_ROTPK_3:
208 return read_from_input(id, offsetof(struct flash_otp_nv_counters_region_t, bl2_rotpk_3), in_len, in);
209
210 case PLAT_OTP_ID_NV_COUNTER_BL2_0:
211 return read_from_input(id, offsetof(struct flash_otp_nv_counters_region_t, bl2_nv_counter_0), in_len, in);
212 case PLAT_OTP_ID_NV_COUNTER_BL2_1:
213 return read_from_input(id, offsetof(struct flash_otp_nv_counters_region_t, bl2_nv_counter_1), in_len, in);
214 case PLAT_OTP_ID_NV_COUNTER_BL2_2:
215 return read_from_input(id, offsetof(struct flash_otp_nv_counters_region_t, bl2_nv_counter_2), in_len, in);
216 case PLAT_OTP_ID_NV_COUNTER_BL2_3:
217 return read_from_input(id, offsetof(struct flash_otp_nv_counters_region_t, bl2_nv_counter_3), in_len, in);
218 #endif /* Bl2 */
219
220 #ifdef BL1
221 case PLAT_OTP_ID_BL1_ROTPK_0:
222 return read_from_input(id, offsetof(struct flash_otp_nv_counters_region_t, bl1_rotpk_0), in_len, in);
223
224 case PLAT_OTP_ID_NV_COUNTER_BL1_0:
225 return read_from_input(id, offsetof(struct flash_otp_nv_counters_region_t, bl1_nv_counter_0), in_len, in);
226 #endif /* BL1 */
227
228 #if (PLATFORM_NS_NV_COUNTERS > 0)
229 case PLAT_OTP_ID_NV_COUNTER_NS_0:
230 return read_from_input(id, offsetof(struct flash_otp_nv_counters_region_t, ns_nv_counter_0), in_len, in);
231 #endif
232 #if (PLATFORM_NS_NV_COUNTERS > 1)
233 case PLAT_OTP_ID_NV_COUNTER_NS_1:
234 return read_from_input(id, offsetof(struct flash_otp_nv_counters_region_t, ns_nv_counter_1), in_len, in);
235 #endif
236 #if (PLATFORM_NS_NV_COUNTERS > 2)
237 case PLAT_OTP_ID_NV_COUNTER_NS_2:
238 return read_from_input(id, offsetof(struct flash_otp_nv_counters_region_t, ns_nv_counter_2), in_len, in);
239 #endif
240
241 case PLAT_OTP_ID_ENTROPY_SEED:
242 return read_from_input(id, offsetof(struct flash_otp_nv_counters_region_t, entropy_seed), in_len, in);
243
244 case PLAT_OTP_ID_SECURE_DEBUG_PK:
245 return read_from_input(id, offsetof(struct flash_otp_nv_counters_region_t, secure_debug_pk), in_len, in);
246
247 default:
248 return TFM_PLAT_ERR_UNSUPPORTED;
249 }
250 }
251 #else
tfm_plat_otp_write(enum tfm_otp_element_id_t id,size_t in_len,const uint8_t * in)252 enum tfm_plat_err_t tfm_plat_otp_write(enum tfm_otp_element_id_t id,
253 size_t in_len, const uint8_t *in)
254 {
255 (void)id;
256 (void)in_len;
257 (void)in;
258 return TFM_PLAT_ERR_UNSUPPORTED;
259 }
260 #endif
261
tfm_plat_otp_get_size(enum tfm_otp_element_id_t id,size_t * size)262 enum tfm_plat_err_t tfm_plat_otp_get_size(enum tfm_otp_element_id_t id,
263 size_t *size)
264 {
265 switch (id) {
266 case PLAT_OTP_ID_HUK:
267 *size = sizeof(((struct flash_otp_nv_counters_region_t*)0)->huk);
268 break;
269 case PLAT_OTP_ID_IAK:
270 *size = sizeof(((struct flash_otp_nv_counters_region_t*)0)->iak);
271 break;
272 case PLAT_OTP_ID_IAK_LEN:
273 *size = sizeof(((struct flash_otp_nv_counters_region_t*)0)->iak_len);
274 break;
275 case PLAT_OTP_ID_IAK_TYPE:
276 *size = sizeof(((struct flash_otp_nv_counters_region_t*)0)->iak_type);
277 break;
278 case PLAT_OTP_ID_IAK_ID:
279 *size = sizeof(((struct flash_otp_nv_counters_region_t*)0)->iak_id);
280 break;
281
282 case PLAT_OTP_ID_BOOT_SEED:
283 *size = sizeof(((struct flash_otp_nv_counters_region_t*)0)->boot_seed);
284 break;
285 case PLAT_OTP_ID_LCS:
286 *size = sizeof(((struct flash_otp_nv_counters_region_t*)0)->lcs);
287 break;
288 case PLAT_OTP_ID_IMPLEMENTATION_ID:
289 *size = sizeof(((struct flash_otp_nv_counters_region_t*)0)->implementation_id);
290 break;
291 case PLAT_OTP_ID_CERT_REF:
292 *size = sizeof(((struct flash_otp_nv_counters_region_t*)0)->cert_ref);
293 break;
294 case PLAT_OTP_ID_VERIFICATION_SERVICE_URL:
295 *size = sizeof(((struct flash_otp_nv_counters_region_t*)0)->verification_service_url);
296 break;
297 case PLAT_OTP_ID_PROFILE_DEFINITION:
298 *size = sizeof(((struct flash_otp_nv_counters_region_t*)0)->profile_definition);
299 break;
300
301 #ifdef BL2
302 case PLAT_OTP_ID_BL2_ROTPK_0:
303 *size = sizeof(((struct flash_otp_nv_counters_region_t*)0)->bl2_rotpk_0);
304 break;
305 case PLAT_OTP_ID_BL2_ROTPK_1:
306 *size = sizeof(((struct flash_otp_nv_counters_region_t*)0)->bl2_rotpk_1);
307 break;
308 case PLAT_OTP_ID_BL2_ROTPK_2:
309 *size = sizeof(((struct flash_otp_nv_counters_region_t*)0)->bl2_rotpk_2);
310 break;
311 case PLAT_OTP_ID_BL2_ROTPK_3:
312 *size = sizeof(((struct flash_otp_nv_counters_region_t*)0)->bl2_rotpk_3);
313 break;
314
315 case PLAT_OTP_ID_NV_COUNTER_BL2_0:
316 *size = sizeof(((struct flash_otp_nv_counters_region_t*)0)->bl2_nv_counter_0);
317 break;
318 case PLAT_OTP_ID_NV_COUNTER_BL2_1:
319 *size = sizeof(((struct flash_otp_nv_counters_region_t*)0)->bl2_nv_counter_1);
320 break;
321 case PLAT_OTP_ID_NV_COUNTER_BL2_2:
322 *size = sizeof(((struct flash_otp_nv_counters_region_t*)0)->bl2_nv_counter_2);
323 break;
324 case PLAT_OTP_ID_NV_COUNTER_BL2_3:
325 *size = sizeof(((struct flash_otp_nv_counters_region_t*)0)->bl2_nv_counter_3);
326 break;
327 #endif /* BL2 */
328
329 #ifdef BL1
330 case PLAT_OTP_ID_BL1_ROTPK_0:
331 *size = sizeof(((struct flash_otp_nv_counters_region_t*)0)->bl1_rotpk_0);
332 break;
333
334 case PLAT_OTP_ID_NV_COUNTER_BL1_0:
335 *size = sizeof(((struct flash_otp_nv_counters_region_t*)0)->bl1_nv_counter_0);
336 break;
337 #endif /* BL1 */
338
339 #if (PLATFORM_NS_NV_COUNTERS > 0)
340 case PLAT_OTP_ID_NV_COUNTER_NS_0:
341 *size = sizeof(((struct flash_otp_nv_counters_region_t*)0)->ns_nv_counter_0);
342 break;
343 #endif
344 #if (PLATFORM_NS_NV_COUNTERS > 1)
345 case PLAT_OTP_ID_NV_COUNTER_NS_1:
346 *size = sizeof(((struct flash_otp_nv_counters_region_t*)0)->ns_nv_counter_1);
347 break;
348 #endif
349 #if (PLATFORM_NS_NV_COUNTERS > 2)
350 case PLAT_OTP_ID_NV_COUNTER_NS_2:
351 *size = sizeof(((struct flash_otp_nv_counters_region_t*)0)->ns_nv_counter_2);
352 break;
353 #endif
354
355 case PLAT_OTP_ID_ENTROPY_SEED:
356 *size = sizeof(((struct flash_otp_nv_counters_region_t*)0)->entropy_seed);
357 break;
358
359 case PLAT_OTP_ID_SECURE_DEBUG_PK:
360 *size = sizeof(((struct flash_otp_nv_counters_region_t*)0)->secure_debug_pk);
361 break;
362
363 default:
364 return TFM_PLAT_ERR_UNSUPPORTED;
365 }
366
367 return TFM_PLAT_ERR_SUCCESS;
368 }
369