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