1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright (C) 2022 Foundries.io Ltd
4 * Jorge Ramirez-Ortiz <jorge@foundries.io>
5 */
6
7 #include <arm.h>
8 #include <confine_array_index.h>
9 #include <drivers/versal_nvm.h>
10 #include <drivers/versal_pmc.h>
11 #include <drivers/versal_puf.h>
12 #include <initcall.h>
13 #include <mm/core_memprot.h>
14 #include <string.h>
15 #include <tee/cache.h>
16
17 /* Protocol API with the remote processor */
18 #define VERSAL_PUF_MODULE_SHIFT 8
19 #define VERSAL_PUF_MODULE 12
20 #define PUF_API_ID(_id) ((VERSAL_PUF_MODULE << VERSAL_PUF_MODULE_SHIFT) | (_id))
21
22 enum versal_puf_error {
23 /* Registration */
24 ERROR_INVALID_PARAM = 0x02,
25 ERROR_INVALID_SYNDROME_MODE = 0x03,
26 ERROR_SYNDROME_WORD_WAIT_TIMEOUT = 0x04,
27 ERROR_PUF_DONE_WAIT_TIMEOUT = 0x07,
28 ERROR_REGISTRATION_INVALID = 0x08,
29 SHUTTER_GVF_MISMATCH = 0x09,
30 ERROR_SYN_DATA_ERROR = 0x0A,
31 IRO_FREQ_WRITE_MISMATCH = 0x0B,
32 /* Regeneration */
33 ERROR_CHASH_NOT_PROGRAMMED = 0x10,
34 ERROR_PUF_STATUS_DONE_TIMEOUT = 0x11,
35 ERROR_INVALID_REGENERATION_TYPE = 0x12,
36 ERROR_INVALID_PUF_OPERATION = 0x13,
37 ERROR_REGENERATION_INVALID = 0x14,
38 ERROR_REGEN_PUF_HD_INVALID = 0x15,
39 ERROR_INVALID_READ_HD_INPUT = 0x16,
40 ERROR_PUF_DONE_KEY_NT_RDY = 0x17,
41 ERROR_PUF_DONE_ID_NT_RDY = 0x18,
42 ERROR_PUF_ID_ZERO_TIMEOUT = 0x19,
43 };
44
45 #define VERSAL_PUF_ERROR(m) { .error = (m), .name = TO_STR(m) }
46
versal_puf_error(uint8_t err)47 static const char *versal_puf_error(uint8_t err)
48 {
49 struct {
50 enum versal_puf_error error;
51 const char *name;
52 } elist[] = {
53 /* Registration */
54 VERSAL_PUF_ERROR(ERROR_INVALID_PARAM),
55 VERSAL_PUF_ERROR(ERROR_INVALID_SYNDROME_MODE),
56 VERSAL_PUF_ERROR(ERROR_SYNDROME_WORD_WAIT_TIMEOUT),
57 VERSAL_PUF_ERROR(ERROR_PUF_DONE_WAIT_TIMEOUT),
58 VERSAL_PUF_ERROR(ERROR_REGISTRATION_INVALID),
59 VERSAL_PUF_ERROR(SHUTTER_GVF_MISMATCH),
60 VERSAL_PUF_ERROR(ERROR_SYN_DATA_ERROR),
61 VERSAL_PUF_ERROR(IRO_FREQ_WRITE_MISMATCH),
62 /* Regeneration */
63 VERSAL_PUF_ERROR(ERROR_CHASH_NOT_PROGRAMMED),
64 VERSAL_PUF_ERROR(ERROR_PUF_STATUS_DONE_TIMEOUT),
65 VERSAL_PUF_ERROR(ERROR_INVALID_REGENERATION_TYPE),
66 VERSAL_PUF_ERROR(ERROR_INVALID_PUF_OPERATION),
67 VERSAL_PUF_ERROR(ERROR_REGENERATION_INVALID),
68 VERSAL_PUF_ERROR(ERROR_REGEN_PUF_HD_INVALID),
69 VERSAL_PUF_ERROR(ERROR_INVALID_READ_HD_INPUT),
70 VERSAL_PUF_ERROR(ERROR_PUF_DONE_KEY_NT_RDY),
71 VERSAL_PUF_ERROR(ERROR_PUF_DONE_ID_NT_RDY),
72 VERSAL_PUF_ERROR(ERROR_PUF_ID_ZERO_TIMEOUT),
73 };
74 size_t error = 0;
75 size_t index = 0;
76
77 if (err <= ERROR_PUF_ID_ZERO_TIMEOUT && err >= ERROR_INVALID_PARAM) {
78 index = err - ERROR_INVALID_PARAM;
79
80 /* Spectre gadget protection: array index is external event */
81 error = confine_array_index(index, ARRAY_SIZE(elist));
82 if (elist[error].name)
83 return elist[error].name;
84
85 return "Invalid";
86 }
87
88 return "Unknown";
89 }
90
91 /*
92 * Register the Physical Unclonable Function (prior operating with it)
93 *
94 * This must happen during the device provisioning phase and can be done from
95 * the Secure World via this interface or from an earlier firmware.
96 */
versal_puf_register(struct versal_puf_data * buf,struct versal_puf_cfg * cfg)97 TEE_Result versal_puf_register(struct versal_puf_data *buf,
98 struct versal_puf_cfg *cfg)
99 {
100 struct versal_puf_data_req req __aligned_puf = { };
101 struct versal_mbox_mem request = {
102 .alloc_len = sizeof(req),
103 .len = sizeof(req),
104 .buf = &req,
105 };
106 struct versal_mbox_mem efuse_syn_data_addr = { };
107 struct versal_mbox_mem syndrome_data_addr = { };
108 struct versal_mbox_mem puf_id_addr = { };
109 struct versal_mbox_mem hash_addr = { };
110 struct versal_mbox_mem aux_addr = { };
111 struct versal_ipi_cmd arg = { };
112 TEE_Result ret = TEE_SUCCESS;
113 uint32_t err = 0;
114
115 ret = versal_mbox_alloc(sizeof(buf->puf_id), NULL, &puf_id_addr);
116 if (ret)
117 goto out;
118 ret = versal_mbox_alloc(sizeof(buf->chash), NULL, &hash_addr);
119 if (ret)
120 goto out;
121 ret = versal_mbox_alloc(sizeof(buf->aux), NULL, &aux_addr);
122 if (ret)
123 goto out;
124 ret = versal_mbox_alloc(sizeof(buf->efuse_syn_data), NULL,
125 &efuse_syn_data_addr);
126 if (ret)
127 goto out;
128 ret = versal_mbox_alloc(sizeof(buf->syndrome_data), NULL,
129 &syndrome_data_addr);
130 if (ret)
131 goto out;
132
133 arg.ibuf[0].mem = request;
134 arg.ibuf[1].mem = syndrome_data_addr;
135 arg.ibuf[2].mem = hash_addr;
136 arg.ibuf[3].mem = aux_addr;
137 arg.ibuf[4].mem = puf_id_addr;
138 arg.ibuf[5].mem = efuse_syn_data_addr;
139
140 req.efuse_syn_data_addr = virt_to_phys(efuse_syn_data_addr.buf);
141 req.syndrome_data_addr = virt_to_phys(syndrome_data_addr.buf);
142 req.puf_id_addr = virt_to_phys(puf_id_addr.buf);
143 req.hash_addr = virt_to_phys(hash_addr.buf);
144 req.aux_addr = virt_to_phys(aux_addr.buf);
145
146 req.global_var_filter = cfg->global_var_filter;
147 req.shutter_value = cfg->shutter_value;
148 req.puf_operation = cfg->puf_operation;
149 req.read_option = cfg->read_option;
150 #if defined(PLATFORM_FLAVOR_net)
151 req.ro_swap_value = cfg->ro_swap_value;
152 #endif
153
154 arg.data[0] = PUF_API_ID(VERSAL_PUF_REGISTER);
155 reg_pair_from_64(virt_to_phys(arg.ibuf[0].mem.buf),
156 &arg.data[2], &arg.data[1]);
157
158 if (versal_pmc_notify(&arg, NULL, &err)) {
159 EMSG("Versal, failed to register the PUF [%s]",
160 versal_puf_error(err));
161
162 ret = TEE_ERROR_GENERIC;
163 }
164
165 /* Return the generated data */
166 memcpy(buf->puf_id, puf_id_addr.buf, sizeof(buf->puf_id));
167 memcpy(&buf->chash, hash_addr.buf, sizeof(buf->chash));
168 memcpy(&buf->aux, aux_addr.buf, sizeof(buf->aux));
169 memcpy(buf->efuse_syn_data, efuse_syn_data_addr.buf,
170 sizeof(buf->efuse_syn_data));
171 memcpy(buf->syndrome_data, syndrome_data_addr.buf,
172 sizeof(buf->syndrome_data));
173
174 out:
175 versal_mbox_free(&syndrome_data_addr);
176 versal_mbox_free(&efuse_syn_data_addr);
177 versal_mbox_free(&aux_addr);
178 versal_mbox_free(&hash_addr);
179 versal_mbox_free(&puf_id_addr);
180
181 return ret;
182 }
183
184 /*
185 * Re-seed the PUF circuitry so it can re-generate the Key Encryption Key.
186 *
187 * Depending on the configuration options it might use eFused data instead of
188 * the helper data provided via the interface.
189 */
versal_puf_regenerate(struct versal_puf_data * buf,struct versal_puf_cfg * cfg)190 TEE_Result versal_puf_regenerate(struct versal_puf_data *buf,
191 struct versal_puf_cfg *cfg)
192 {
193 struct versal_puf_data_req req __aligned_puf = { };
194 struct versal_mbox_mem request = {
195 .alloc_len = sizeof(req),
196 .len = sizeof(req),
197 .buf = &req,
198 };
199 struct versal_mbox_mem syndrome_data_addr = { };
200 struct versal_mbox_mem puf_id_addr = { };
201 struct versal_mbox_mem hash_addr = { };
202 struct versal_mbox_mem aux_addr = { };
203 struct versal_ipi_cmd arg = { };
204 TEE_Result ret = TEE_SUCCESS;
205 uint32_t err = 0;
206
207 ret = versal_mbox_alloc(sizeof(buf->puf_id), NULL, &puf_id_addr);
208 if (ret)
209 goto out;
210 ret = versal_mbox_alloc(sizeof(buf->chash), &buf->chash, &hash_addr);
211 if (ret)
212 goto out;
213 ret = versal_mbox_alloc(sizeof(buf->aux), &buf->aux, &aux_addr);
214 if (ret)
215 goto out;
216 ret = versal_mbox_alloc(sizeof(buf->syndrome_data), buf->syndrome_data,
217 &syndrome_data_addr);
218 if (ret)
219 goto out;
220
221 arg.ibuf[0].mem = request;
222 arg.ibuf[1].mem = syndrome_data_addr;
223 arg.ibuf[2].mem = hash_addr;
224 arg.ibuf[3].mem = aux_addr;
225 arg.ibuf[4].mem = puf_id_addr;
226
227 req.syndrome_addr = virt_to_phys(syndrome_data_addr.buf);
228 req.puf_id_addr = virt_to_phys(puf_id_addr.buf);
229 req.hash_addr = virt_to_phys(hash_addr.buf);
230 req.aux_addr = virt_to_phys(aux_addr.buf);
231
232 req.global_var_filter = cfg->global_var_filter;
233 req.shutter_value = cfg->shutter_value;
234 req.puf_operation = cfg->puf_operation;
235 req.read_option = cfg->read_option;
236 #if defined(PLATFORM_FLAVOR_net)
237 req.ro_swap_value = cfg->ro_swap_value;
238 #endif
239
240 arg.data[0] = PUF_API_ID(VERSAL_PUF_REGENERATE);
241 reg_pair_from_64(virt_to_phys(arg.ibuf[0].mem.buf),
242 &arg.data[2], &arg.data[1]);
243
244 if (versal_pmc_notify(&arg, NULL, &err)) {
245 EMSG("Versal, failed to regenerate the PUF [%s]",
246 versal_puf_error(err));
247
248 ret = TEE_ERROR_GENERIC;
249 }
250
251 /* Return the updated PUF_ID */
252 memcpy(buf->puf_id, puf_id_addr.buf, sizeof(buf->puf_id));
253
254 out:
255 versal_mbox_free(&syndrome_data_addr);
256 versal_mbox_free(&aux_addr);
257 versal_mbox_free(&hash_addr);
258 versal_mbox_free(&puf_id_addr);
259
260 return ret;
261 }
262
263 /*
264 * Clear/Hide the PUF Unique ID
265 *
266 * The fully accessible (non-secret) Unique ID is generated from the PUF
267 */
versal_puf_clear_id(void)268 TEE_Result versal_puf_clear_id(void)
269 {
270 struct versal_ipi_cmd arg = { };
271
272 arg.data[0] = PUF_API_ID(VERSAL_PUF_CLEAR_ID);
273
274 if (versal_pmc_notify(&arg, NULL, NULL)) {
275 EMSG("Versal, failed to clear the PUF_ID");
276
277 return TEE_ERROR_GENERIC;
278 }
279
280 return TEE_SUCCESS;
281 }
282
283 /* Check that the API id is available to the client */
versal_puf_check_api(enum versal_puf_api id)284 TEE_Result versal_puf_check_api(enum versal_puf_api id)
285 {
286 struct versal_ipi_cmd arg = { };
287
288 arg.data[0] = PUF_API_ID(VERSAL_PUF_API_FEATURES);
289 arg.data[1] = id;
290
291 if (versal_pmc_notify(&arg, NULL, NULL))
292 return TEE_ERROR_GENERIC;
293
294 return TEE_SUCCESS;
295 }
296