1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright (C) 2025 Missing Link Electronics, Inc.
4 */
5
6 #include <drivers/versal_mbox.h>
7 #include <drivers/versal_pmc.h>
8 #include <drivers/versal_ocp.h>
9 #include <kernel/panic.h>
10 #include <mm/core_memprot.h>
11 #include <stdint.h>
12 #include <string.h>
13 #include <tee_api_types.h>
14 #include <util.h>
15
16 /* Protocol API with Versal PLM Firmware on PMC */
17 #define OCP_MODULE_SHIFT 8
18 #define OCP_MODULE 13
19 #define OCP_API_ID(_id) (SHIFT_U32(OCP_MODULE, OCP_MODULE_SHIFT) | (_id))
20
21 /*
22 * The following symbols/types/definitions are taken from AMD/Xilinx
23 * embeddedsw::lib/sw_services/xilocp/src/common/xocp_def.h
24 * v2024.2
25 */
26
27 enum versal_ocp_api_id {
28 API_FEATURES = 0,
29 EXTEND_HWPCR = 1,
30 GET_HWPCR = 2,
31 GET_HWPCRLOG = 3,
32 GENDMERESP = 4,
33 DEVAKINPUT = 5,
34 GETCERTUSERCFG = 6,
35 GETX509CERT = 7,
36 ATTESTWITHDEVAK = 8,
37 SET_SWPCRCONFIG = 9,
38 EXTEND_SWPCR = 10,
39 GET_SWPCR = 11,
40 GET_SWPCRLOG = 12,
41 GET_SWPCRDATA = 13,
42 GEN_SHARED_SECRET = 14,
43 ATTEST_WITH_KEYWRAP_DEVAK = 15,
44 API_MAX = 16
45 };
46
47 #define VERSAL_OCP_EXTENDED_HASH_SIZE_IN_BYTES 48
48
49 /*
50 * The following symbols/types/definitions are taken from AMD/Xilinx
51 * embeddedsw::lib/sw_services/xilocp/src/common/xocp_common.h
52 * v2024.2
53 */
54
55 struct versal_ocp_swpcr_extend_params {
56 uint32_t pcr_num;
57 uint32_t measurement_idx;
58 uint32_t data_size;
59 uint32_t overwrite;
60 uint64_t data_addr;
61 };
62
63 struct versal_ocp_swpcr_log_read_data {
64 uint32_t pcr_num;
65 uint32_t log_size;
66 uint64_t pcr_log_addr;
67 uint32_t digest_count;
68 };
69
70 struct versal_ocp_swpcr_read_data {
71 uint32_t pcr_num;
72 uint32_t measurement_idx;
73 uint32_t data_start_idx;
74 uint32_t buf_size;
75 uint64_t buf_addr;
76 uint32_t returned_bytes;
77 };
78
79 struct versal_ocp_x509_cert {
80 uint64_t cert_addr;
81 uint64_t actual_len_addr;
82 uint32_t cert_size;
83 enum versal_ocp_dev_key dev_key_sel;
84 uint32_t is_csr;
85 };
86
87 struct versal_ocp_attest {
88 uint64_t hash_addr;
89 uint64_t signature_addr;
90 uint32_t reserved;
91 uint32_t hash_len;
92 };
93
94 /*
95 * The following helper functions shall be regarded as a possible general API
96 * towards constructing "struct versal_ipi_cmd" instances. After extracting them
97 * into a separate drivers/ file, like drivers/versal_ipi_cmd.c, they may be
98 * used by other existing drivers in the future, too. For now, they shall live
99 * here, since versal_ocp.c is the only user [1].
100 *
101 * [1] https://github.com/OP-TEE/optee_os/pull/7726#issuecomment-4237954478
102 */
103
versal_ipi_cmd_ibuf_alloc(struct versal_ipi_cmd * cmd,void * buf,size_t len,size_t * idx)104 static TEE_Result versal_ipi_cmd_ibuf_alloc(struct versal_ipi_cmd *cmd,
105 void *buf, size_t len, size_t *idx)
106 {
107 TEE_Result ret = TEE_SUCCESS;
108 struct versal_mbox_mem mem = {};
109
110 if (cmd->ibuf_count >= VERSAL_MAX_IPI_BUF)
111 panic();
112
113 ret = versal_mbox_alloc(len, buf, &mem);
114 if (ret)
115 return ret;
116
117 cmd->ibuf[cmd->ibuf_count].mem = mem;
118 if (idx)
119 *idx = cmd->ibuf_count;
120 cmd->ibuf_count++;
121 return ret;
122 }
123
versal_ipi_cmd_free(struct versal_ipi_cmd * cmd)124 static void versal_ipi_cmd_free(struct versal_ipi_cmd *cmd)
125 {
126 memset(cmd->data, 0, sizeof(cmd->data));
127 cmd->data_count = 0;
128
129 for (size_t idx = 0; idx < cmd->ibuf_count; idx++)
130 versal_mbox_free(&cmd->ibuf[idx].mem);
131 cmd->ibuf_count = 0;
132 }
133
versal_ipi_cmd_data_push_val(struct versal_ipi_cmd * cmd,uint32_t val)134 static void versal_ipi_cmd_data_push_val(struct versal_ipi_cmd *cmd,
135 uint32_t val)
136 {
137 if (cmd->data_count >= VERSAL_MAX_IPI_DATA)
138 panic();
139
140 cmd->data[cmd->data_count++] = val;
141 }
142
versal_ipi_cmd_data_push_ptr(struct versal_ipi_cmd * cmd,void * ptr)143 static void versal_ipi_cmd_data_push_ptr(struct versal_ipi_cmd *cmd, void *ptr)
144 {
145 uint32_t low = 0;
146 uint32_t hi = 0;
147
148 if (cmd->data_count >= (VERSAL_MAX_IPI_DATA - 1))
149 panic();
150
151 reg_pair_from_64(virt_to_phys(ptr), &hi, &low);
152 cmd->data[cmd->data_count++] = low;
153 cmd->data[cmd->data_count++] = hi;
154 }
155
versal_ipi_cmd_data_push_ibuf(struct versal_ipi_cmd * cmd,void * buf,size_t len,size_t * idx)156 static TEE_Result versal_ipi_cmd_data_push_ibuf(struct versal_ipi_cmd *cmd,
157 void *buf, size_t len,
158 size_t *idx)
159 {
160 TEE_Result ret = TEE_SUCCESS;
161 size_t target_idx = 0;
162
163 if (cmd->ibuf_count >= VERSAL_MAX_IPI_BUF)
164 panic();
165 if (cmd->data_count >= (VERSAL_MAX_IPI_DATA - 1))
166 panic();
167
168 ret = versal_ipi_cmd_ibuf_alloc(cmd, buf, len, &target_idx);
169 if (ret)
170 return ret;
171
172 if (idx)
173 *idx = target_idx;
174
175 versal_ipi_cmd_data_push_ptr(cmd, cmd->ibuf[target_idx].mem.buf);
176 return ret;
177 }
178
versal_ipi_cmd_ibuf_get(struct versal_ipi_cmd * cmd,size_t idx)179 static void *versal_ipi_cmd_ibuf_get(struct versal_ipi_cmd *cmd, size_t idx)
180 {
181 if (idx >= cmd->ibuf_count)
182 panic();
183
184 return cmd->ibuf[idx].mem.buf;
185 }
186
versal_ipi_cmd_ibuf_get_paddr(struct versal_ipi_cmd * cmd,size_t idx)187 static paddr_t versal_ipi_cmd_ibuf_get_paddr(struct versal_ipi_cmd *cmd,
188 size_t idx)
189 {
190 if (idx >= cmd->ibuf_count)
191 panic();
192
193 return virt_to_phys(cmd->ibuf[idx].mem.buf);
194 }
195
versal_ipi_cmd_ibuf_fetch(struct versal_ipi_cmd * cmd,void * dst,size_t len,size_t idx)196 static void versal_ipi_cmd_ibuf_fetch(struct versal_ipi_cmd *cmd,
197 void *dst, size_t len, size_t idx)
198 {
199 if (idx >= cmd->ibuf_count)
200 panic();
201 if (len > cmd->ibuf[idx].mem.len)
202 panic();
203
204 memcpy(dst, cmd->ibuf[idx].mem.buf, len);
205 }
206
207 /*
208 * The following functions shall mimic the XilOCP client side interface from
209 * AMD/Xilinx embeddedsw::lib/sw_services/xilocp/src/client/xocp_client.h
210 * v2024.2
211 */
212
213 /* capture PLM status/error code */
214 static uint32_t plm_status;
215 struct mutex plm_status_lock = MUTEX_INITIALIZER;
216
versal_ocp_plm_status_get(void)217 uint32_t versal_ocp_plm_status_get(void)
218 {
219 uint32_t status = 0;
220
221 mutex_lock(&plm_status_lock);
222 status = plm_status;
223 mutex_unlock(&plm_status_lock);
224
225 return status;
226 }
227
versal_ocp_status_get(void)228 uint32_t versal_ocp_status_get(void)
229 {
230 return versal_ocp_plm_status_get() & VERSAL_OCP_STATUS_MASK;
231 }
232
versal_ocp_extend_hwpcr(enum versal_ocp_hwpcr pcr_num,void * data,uint32_t data_size)233 TEE_Result versal_ocp_extend_hwpcr(enum versal_ocp_hwpcr pcr_num,
234 void *data, uint32_t data_size)
235 {
236 TEE_Result ret = TEE_SUCCESS;
237 struct versal_ipi_cmd cmd = {};
238
239 if (!data || !data_size)
240 return TEE_ERROR_BAD_PARAMETERS;
241
242 versal_ipi_cmd_data_push_val(&cmd, OCP_API_ID(EXTEND_HWPCR));
243
244 versal_ipi_cmd_data_push_val(&cmd, pcr_num);
245
246 ret = versal_ipi_cmd_data_push_ibuf(&cmd, data, data_size, NULL);
247 if (ret)
248 goto out;
249
250 versal_ipi_cmd_data_push_val(&cmd, data_size);
251
252 mutex_lock(&plm_status_lock);
253 plm_status = 0;
254 if (versal_pmc_notify(&cmd, NULL, &plm_status)) {
255 EMSG("Versal PLM API ID EXTEND_HWPCR failed: 0x%" PRIx32,
256 plm_status);
257 ret = TEE_ERROR_GENERIC;
258 }
259 mutex_unlock(&plm_status_lock);
260
261 out:
262 versal_ipi_cmd_free(&cmd);
263 return ret;
264 }
265
versal_ocp_get_hwpcr(uint32_t pcr_mask,void * pcr,uint32_t pcr_size)266 TEE_Result versal_ocp_get_hwpcr(uint32_t pcr_mask,
267 void *pcr, uint32_t pcr_size)
268 {
269 TEE_Result ret = TEE_SUCCESS;
270 struct versal_ipi_cmd cmd = {};
271 size_t idx = 0;
272
273 if (!pcr || !pcr_size)
274 return TEE_ERROR_BAD_PARAMETERS;
275
276 versal_ipi_cmd_data_push_val(&cmd, OCP_API_ID(GET_HWPCR));
277
278 versal_ipi_cmd_data_push_val(&cmd, pcr_mask);
279
280 ret = versal_ipi_cmd_data_push_ibuf(&cmd, NULL, pcr_size, &idx);
281 if (ret)
282 goto out;
283
284 versal_ipi_cmd_data_push_val(&cmd, pcr_size);
285
286 mutex_lock(&plm_status_lock);
287 plm_status = 0;
288 if (versal_pmc_notify(&cmd, NULL, &plm_status)) {
289 EMSG("Versal PLM API ID GET_HWPCR failed: 0x%" PRIx32,
290 plm_status);
291 ret = TEE_ERROR_GENERIC;
292 mutex_unlock(&plm_status_lock);
293 goto out;
294 }
295 mutex_unlock(&plm_status_lock);
296
297 versal_ipi_cmd_ibuf_fetch(&cmd, pcr, pcr_size, idx);
298
299 out:
300 versal_ipi_cmd_free(&cmd);
301 return ret;
302 }
303
versal_ocp_get_hwpcr_log(struct versal_ocp_hwpcr_event * events,uint32_t events_size,struct versal_ocp_hwpcr_log_info * loginfo)304 TEE_Result versal_ocp_get_hwpcr_log(struct versal_ocp_hwpcr_event *events,
305 uint32_t events_size,
306 struct versal_ocp_hwpcr_log_info *loginfo)
307 {
308 TEE_Result ret = TEE_SUCCESS;
309 struct versal_ipi_cmd cmd = {};
310 size_t idx_events = 0;
311 size_t idx_loginfo = 0;
312
313 if (!events || !events_size || (events_size % sizeof(*events)))
314 return TEE_ERROR_BAD_PARAMETERS;
315 if (!loginfo)
316 return TEE_ERROR_BAD_PARAMETERS;
317
318 versal_ipi_cmd_data_push_val(&cmd, OCP_API_ID(GET_HWPCRLOG));
319
320 ret = versal_ipi_cmd_data_push_ibuf(&cmd, NULL, events_size,
321 &idx_events);
322 if (ret)
323 goto out;
324 ret = versal_ipi_cmd_data_push_ibuf(&cmd, NULL, sizeof(*loginfo),
325 &idx_loginfo);
326 if (ret)
327 goto out;
328
329 versal_ipi_cmd_data_push_val(&cmd, events_size / sizeof(*events));
330
331 mutex_lock(&plm_status_lock);
332 plm_status = 0;
333 if (versal_pmc_notify(&cmd, NULL, &plm_status)) {
334 EMSG("Versal PLM API ID GET_HWPCRLOG failed: 0x%" PRIx32,
335 plm_status);
336 ret = TEE_ERROR_GENERIC;
337 mutex_unlock(&plm_status_lock);
338 goto out;
339 }
340 mutex_unlock(&plm_status_lock);
341
342 versal_ipi_cmd_ibuf_fetch(&cmd, loginfo, sizeof(*loginfo), idx_loginfo);
343
344 versal_ipi_cmd_ibuf_fetch(&cmd, events, events_size, idx_events);
345
346 out:
347 versal_ipi_cmd_free(&cmd);
348 return ret;
349 }
350
versal_ocp_extend_swpcr(uint32_t pcr_num,void * data,uint32_t data_size,uint32_t measurement_idx,bool overwrite)351 TEE_Result versal_ocp_extend_swpcr(uint32_t pcr_num,
352 void *data, uint32_t data_size,
353 uint32_t measurement_idx, bool overwrite)
354 {
355 TEE_Result ret = TEE_SUCCESS;
356 struct versal_ipi_cmd cmd = {};
357 struct versal_ocp_swpcr_extend_params params = {
358 .pcr_num = pcr_num,
359 .measurement_idx = measurement_idx,
360 .data_size = data_size,
361 .overwrite = overwrite,
362 .data_addr = 0,
363 };
364 size_t idx = 0;
365
366 if (!data || !data_size)
367 return TEE_ERROR_BAD_PARAMETERS;
368
369 /*
370 * NOTE: AMD/Xilinx XilOCP client side code does this check explicitly
371 * before calling into PLM Firmware. Despite checking it again in
372 * PLM Firmware. It looks like hardware can handle data buffers
373 * beyond 48 Bytes, only, if within the first 4GiB of
374 * RAM. Probably some kind of DMA engine issue ...?
375 */
376 if (data_size > VERSAL_OCP_EXTENDED_HASH_SIZE_IN_BYTES)
377 if ((vaddr_t)data >> 32)
378 return TEE_ERROR_BAD_PARAMETERS;
379
380 versal_ipi_cmd_data_push_val(&cmd, OCP_API_ID(EXTEND_SWPCR));
381
382 ret = versal_ipi_cmd_ibuf_alloc(&cmd, data, data_size, &idx);
383 if (ret)
384 goto out;
385
386 params.data_addr = (uint64_t)versal_ipi_cmd_ibuf_get_paddr(&cmd, idx);
387
388 ret = versal_ipi_cmd_data_push_ibuf(&cmd, ¶ms, sizeof(params),
389 NULL);
390 if (ret)
391 goto out;
392
393 mutex_lock(&plm_status_lock);
394 plm_status = 0;
395 if (versal_pmc_notify(&cmd, NULL, &plm_status)) {
396 EMSG("Versal PLM API ID EXTEND_SWPCR failed: 0x%" PRIx32,
397 plm_status);
398 ret = TEE_ERROR_GENERIC;
399 }
400 mutex_unlock(&plm_status_lock);
401
402 out:
403 versal_ipi_cmd_free(&cmd);
404 return ret;
405 }
406
versal_ocp_get_swpcr(uint32_t pcr_mask,void * pcr,uint32_t pcr_size)407 TEE_Result versal_ocp_get_swpcr(uint32_t pcr_mask,
408 void *pcr, uint32_t pcr_size)
409 {
410 TEE_Result ret = TEE_SUCCESS;
411 struct versal_ipi_cmd cmd = {};
412 size_t idx = 0;
413
414 if (!pcr || !pcr_size)
415 return TEE_ERROR_BAD_PARAMETERS;
416
417 versal_ipi_cmd_data_push_val(&cmd, OCP_API_ID(GET_SWPCR));
418
419 versal_ipi_cmd_data_push_val(&cmd, pcr_mask);
420
421 ret = versal_ipi_cmd_data_push_ibuf(&cmd, NULL, pcr_size, &idx);
422 if (ret)
423 goto out;
424
425 versal_ipi_cmd_data_push_val(&cmd, pcr_size);
426
427 mutex_lock(&plm_status_lock);
428 plm_status = 0;
429 if (versal_pmc_notify(&cmd, NULL, &plm_status)) {
430 EMSG("Versal PLM API ID GET_SWPCR failed: 0x%" PRIx32,
431 plm_status);
432 ret = TEE_ERROR_GENERIC;
433 mutex_unlock(&plm_status_lock);
434 goto out;
435 }
436 mutex_unlock(&plm_status_lock);
437
438 versal_ipi_cmd_ibuf_fetch(&cmd, pcr, pcr_size, idx);
439
440 out:
441 versal_ipi_cmd_free(&cmd);
442 return ret;
443 }
444
versal_ocp_get_swpcr_data(uint32_t pcr_num,uint32_t measurement_idx,uint32_t data_start_idx,void * data,uint32_t data_size,uint32_t * data_returned)445 TEE_Result versal_ocp_get_swpcr_data(uint32_t pcr_num, uint32_t measurement_idx,
446 uint32_t data_start_idx,
447 void *data, uint32_t data_size,
448 uint32_t *data_returned)
449 {
450 TEE_Result ret = TEE_SUCCESS;
451 struct versal_ipi_cmd cmd = {};
452 struct versal_ocp_swpcr_read_data param = {
453 .pcr_num = pcr_num,
454 .measurement_idx = measurement_idx,
455 .data_start_idx = data_start_idx,
456 .buf_size = data_size,
457 .buf_addr = 0,
458 .returned_bytes = 0,
459 };
460 size_t idx_buf = 0;
461 size_t idx_param = 0;
462 struct versal_ocp_swpcr_read_data *_param = NULL;
463
464 if (!data || !data_size || !data_returned)
465 return TEE_ERROR_BAD_PARAMETERS;
466
467 versal_ipi_cmd_data_push_val(&cmd, OCP_API_ID(GET_SWPCRDATA));
468
469 ret = versal_ipi_cmd_ibuf_alloc(&cmd, NULL, data_size, &idx_buf);
470 if (ret)
471 goto out;
472
473 param.buf_addr = versal_ipi_cmd_ibuf_get_paddr(&cmd, idx_buf);
474
475 ret = versal_ipi_cmd_data_push_ibuf(&cmd, ¶m, sizeof(param),
476 &idx_param);
477 if (ret)
478 goto out;
479
480 mutex_lock(&plm_status_lock);
481 plm_status = 0;
482 if (versal_pmc_notify(&cmd, NULL, &plm_status)) {
483 EMSG("Versal PLM API ID GET_SWPCRDATA failed: 0x%" PRIx32,
484 plm_status);
485 ret = TEE_ERROR_GENERIC;
486 mutex_unlock(&plm_status_lock);
487 goto out;
488 }
489 mutex_unlock(&plm_status_lock);
490
491 _param = versal_ipi_cmd_ibuf_get(&cmd, idx_param);
492 *data_returned = _param->returned_bytes;
493
494 versal_ipi_cmd_ibuf_fetch(&cmd, data, *data_returned, idx_buf);
495
496 out:
497 versal_ipi_cmd_free(&cmd);
498 return ret;
499 }
500
501 TEE_Result
versal_ocp_get_swpcr_log(uint32_t pcr_num,struct versal_ocp_pcr_measurement * measurements,uint32_t measurements_size,uint32_t * measurements_count)502 versal_ocp_get_swpcr_log(uint32_t pcr_num,
503 struct versal_ocp_pcr_measurement *measurements,
504 uint32_t measurements_size,
505 uint32_t *measurements_count)
506 {
507 TEE_Result ret = TEE_SUCCESS;
508 struct versal_ipi_cmd cmd = {};
509 struct versal_ocp_swpcr_log_read_data param = {
510 .pcr_num = pcr_num,
511 .log_size = measurements_size,
512 .pcr_log_addr = 0,
513 .digest_count = 0,
514 };
515 size_t idx_buf = 0;
516 size_t idx_param = 0;
517 struct versal_ocp_swpcr_log_read_data *_param = NULL;
518
519 if (!measurements || !measurements_size ||
520 (measurements_size % sizeof(struct versal_ocp_pcr_measurement)))
521 return TEE_ERROR_BAD_PARAMETERS;
522
523 versal_ipi_cmd_data_push_val(&cmd, OCP_API_ID(GET_SWPCRLOG));
524
525 ret = versal_ipi_cmd_ibuf_alloc(&cmd, NULL, measurements_size,
526 &idx_buf);
527 if (ret)
528 goto out;
529
530 param.pcr_log_addr = versal_ipi_cmd_ibuf_get_paddr(&cmd, idx_buf);
531
532 ret = versal_ipi_cmd_data_push_ibuf(&cmd, ¶m, sizeof(param),
533 &idx_param);
534 if (ret)
535 goto out;
536
537 mutex_lock(&plm_status_lock);
538 plm_status = 0;
539 if (versal_pmc_notify(&cmd, NULL, &plm_status)) {
540 EMSG("Versal PLM API ID GET_SWPCRLOG failed: 0x%" PRIx32,
541 plm_status);
542 ret = TEE_ERROR_GENERIC;
543 mutex_unlock(&plm_status_lock);
544 goto out;
545 }
546 mutex_unlock(&plm_status_lock);
547
548 _param = versal_ipi_cmd_ibuf_get(&cmd, idx_param);
549 *measurements_count = _param->digest_count;
550
551 versal_ipi_cmd_ibuf_fetch(&cmd, measurements,
552 sizeof(*measurements) * *measurements_count,
553 idx_buf);
554
555 out:
556 versal_ipi_cmd_free(&cmd);
557 return ret;
558 }
559
versal_ocp_gen_dme_resp(void * nonce,uint32_t nonce_size,struct versal_ocp_dme_response * response)560 TEE_Result versal_ocp_gen_dme_resp(void *nonce, uint32_t nonce_size,
561 struct versal_ocp_dme_response *response)
562 {
563 TEE_Result ret = TEE_SUCCESS;
564 struct versal_ipi_cmd cmd = {};
565 size_t idx = 0;
566
567 if (!nonce || nonce_size != VERSAL_OCP_DME_NONCE_SIZE_BYTES)
568 return TEE_ERROR_BAD_PARAMETERS;
569
570 if (!response)
571 return TEE_ERROR_BAD_PARAMETERS;
572
573 versal_ipi_cmd_data_push_val(&cmd, OCP_API_ID(GENDMERESP));
574
575 ret = versal_ipi_cmd_data_push_ibuf(&cmd, nonce, nonce_size, NULL);
576 if (ret)
577 goto out;
578
579 ret = versal_ipi_cmd_data_push_ibuf(&cmd, NULL, sizeof(*response),
580 &idx);
581 if (ret)
582 goto out;
583
584 mutex_lock(&plm_status_lock);
585 plm_status = 0;
586 if (versal_pmc_notify(&cmd, NULL, &plm_status)) {
587 EMSG("Versal PLM API ID GENDMERESP failed: 0x%" PRIx32,
588 plm_status);
589 ret = TEE_ERROR_GENERIC;
590 mutex_unlock(&plm_status_lock);
591 goto out;
592 }
593 mutex_unlock(&plm_status_lock);
594
595 versal_ipi_cmd_ibuf_fetch(&cmd, response, sizeof(*response), idx);
596
597 out:
598 versal_ipi_cmd_free(&cmd);
599 return ret;
600 }
601
versal_ocp_get_x509_cert(void * cert,uint32_t cert_size,uint32_t * actual_cert_size,enum versal_ocp_dev_key dev_key_sel,bool is_csr)602 TEE_Result versal_ocp_get_x509_cert(void *cert, uint32_t cert_size,
603 uint32_t *actual_cert_size,
604 enum versal_ocp_dev_key dev_key_sel,
605 bool is_csr)
606 {
607 TEE_Result ret = TEE_SUCCESS;
608 struct versal_ipi_cmd cmd = {};
609 /*
610 * NOTE: PLM Firmware (function XCert_GenerateX509Cert()) actually
611 * ignores member "cert_size" (called "MaxCertSize" there) and
612 * has a hard-coded internal buffer of 2000 Bytes, which is used
613 * to construct the certificate. The result is then copied to our
614 * ibuf:
615 */
616 struct versal_ocp_x509_cert param = {
617 .cert_addr = 0,
618 .actual_len_addr = 0,
619 .cert_size = 2000,
620 .dev_key_sel = dev_key_sel,
621 .is_csr = is_csr ? 1 : 0,
622 };
623 size_t idx_cert = 0;
624 size_t idx_size = 0;
625
626 if (!cert)
627 return TEE_ERROR_BAD_PARAMETERS;
628
629 versal_ipi_cmd_data_push_val(&cmd, OCP_API_ID(GETX509CERT));
630
631 if (cert_size > param.cert_size)
632 param.cert_size = cert_size;
633 ret = versal_ipi_cmd_ibuf_alloc(&cmd, NULL, param.cert_size,
634 &idx_cert);
635 if (ret)
636 goto out;
637
638 ret = versal_ipi_cmd_ibuf_alloc(&cmd, NULL, sizeof(*actual_cert_size),
639 &idx_size);
640 if (ret)
641 goto out;
642
643 param.cert_addr = versal_ipi_cmd_ibuf_get_paddr(&cmd, idx_cert);
644 param.actual_len_addr = versal_ipi_cmd_ibuf_get_paddr(&cmd, idx_size);
645
646 ret = versal_ipi_cmd_data_push_ibuf(&cmd, ¶m, sizeof(param), NULL);
647 if (ret)
648 goto out;
649
650 mutex_lock(&plm_status_lock);
651 plm_status = 0;
652 if (versal_pmc_notify(&cmd, NULL, &plm_status)) {
653 EMSG("Versal PLM API ID GETX509CERT failed: 0x%" PRIx32,
654 plm_status);
655 ret = TEE_ERROR_GENERIC;
656 mutex_unlock(&plm_status_lock);
657 goto out;
658 }
659 mutex_unlock(&plm_status_lock);
660
661 versal_ipi_cmd_ibuf_fetch(&cmd, actual_cert_size,
662 sizeof(*actual_cert_size), idx_size);
663 if (param.cert_size < *actual_cert_size) {
664 EMSG("Versal PLM API ID GETX509CERT failed: wrote beyond X.509 certificate buffer, provided %u bytes, needed %u bytes",
665 param.cert_size, *actual_cert_size);
666 panic();
667 }
668 if (cert_size < *actual_cert_size) {
669 EMSG("Versal PLM API ID GETX509CERT failed: X.509 certificate buffer too small, need %u bytes",
670 *actual_cert_size);
671 return TEE_ERROR_GENERIC;
672 }
673
674 versal_ipi_cmd_ibuf_fetch(&cmd, cert, *actual_cert_size, idx_cert);
675
676 out:
677 versal_ipi_cmd_free(&cmd);
678 return ret;
679 }
680
versal_ocp_attest_with_devak(void * hash,uint32_t hash_size,void * signature,uint32_t signature_size)681 TEE_Result versal_ocp_attest_with_devak(void *hash, uint32_t hash_size,
682 void *signature,
683 uint32_t signature_size)
684 {
685 TEE_Result ret = TEE_SUCCESS;
686 struct versal_ipi_cmd cmd = {};
687 struct versal_ocp_attest param = {
688 .hash_addr = 0,
689 .signature_addr = 0,
690 .reserved = 0,
691 .hash_len = hash_size,
692 };
693 size_t idx_hash = 0;
694 size_t idx_sign = 0;
695
696 if (!hash || !hash_size)
697 return TEE_ERROR_BAD_PARAMETERS;
698
699 if (!signature ||
700 signature_size != VERSAL_OCP_ECC_P384_SIZE_BYTES)
701 return TEE_ERROR_BAD_PARAMETERS;
702
703 versal_ipi_cmd_data_push_val(&cmd, OCP_API_ID(ATTESTWITHDEVAK));
704
705 ret = versal_ipi_cmd_ibuf_alloc(&cmd, hash, hash_size, &idx_hash);
706 if (ret)
707 goto out;
708
709 ret = versal_ipi_cmd_ibuf_alloc(&cmd, NULL, signature_size, &idx_sign);
710 if (ret)
711 goto out;
712
713 param.hash_addr = versal_ipi_cmd_ibuf_get_paddr(&cmd, idx_hash);
714 param.signature_addr = versal_ipi_cmd_ibuf_get_paddr(&cmd, idx_sign);
715
716 ret = versal_ipi_cmd_data_push_ibuf(&cmd, ¶m, sizeof(param), NULL);
717 if (ret)
718 goto out;
719
720 mutex_lock(&plm_status_lock);
721 plm_status = 0;
722 if (versal_pmc_notify(&cmd, NULL, &plm_status)) {
723 EMSG("Versal PLM API ID ATTESTWITHDEVAK failed: 0x%" PRIx32,
724 plm_status);
725 ret = TEE_ERROR_GENERIC;
726 mutex_unlock(&plm_status_lock);
727 goto out;
728 }
729 mutex_unlock(&plm_status_lock);
730
731 versal_ipi_cmd_ibuf_fetch(&cmd, signature,
732 VERSAL_OCP_ECC_P384_SIZE_BYTES, idx_sign);
733
734 out:
735 versal_ipi_cmd_free(&cmd);
736 return ret;
737 }
738
versal_ocp_attest_with_key_wrap_devak(void * attest_buf,uint32_t attest_buf_size,uint32_t pub_key_offset,void * signature,uint32_t signature_size)739 TEE_Result versal_ocp_attest_with_key_wrap_devak(void *attest_buf,
740 uint32_t attest_buf_size,
741 uint32_t pub_key_offset,
742 void *signature,
743 uint32_t signature_size)
744 {
745 TEE_Result ret = TEE_SUCCESS;
746 struct versal_ipi_cmd cmd = {};
747 size_t idx_buf = 0;
748 size_t idx_sign = 0;
749 void *_attest_buf = NULL;
750
751 /*
752 * NOTE: The buffer with data to be attested has 2 "components":
753 * - the actual input data to be attested
754 * - the output RSA 3072 public key (768 Bytes, included in
755 * attestation)
756 *
757 * The space for the RSA public key is supposed to be located at
758 * the end of the buffer at the offset specified by argument
759 * "pub_key_offset".
760 *
761 * For an unknown reason PLM Firmware
762 * (XOcp_AttestWithKeyWrapDevAkIpi()) checks parameter
763 * "attest_buf_size" (called "AttnPloadSize" there) for being
764 * strictly _greater_ than:
765 * public key offset +
766 * half of struct versal_secure_rsapubkey() +
767 * 4 Bytes
768 *
769 * At the same time the code does copy the complete struct
770 * versal_secure_rsapubkey at the public key offset. Thus the size
771 * check is wrong! And why "greater than"? Why not "greater or
772 * equal"?
773 */
774 if (!attest_buf ||
775 (attest_buf_size <
776 (pub_key_offset + sizeof(struct versal_secure_rsapubkey))))
777 return TEE_ERROR_BAD_PARAMETERS;
778
779 if (!signature ||
780 signature_size != VERSAL_OCP_ECC_P384_SIZE_BYTES)
781 return TEE_ERROR_BAD_PARAMETERS;
782
783 versal_ipi_cmd_data_push_val(&cmd,
784 OCP_API_ID(ATTEST_WITH_KEYWRAP_DEVAK));
785
786 ret = versal_ipi_cmd_data_push_ibuf(&cmd, attest_buf, attest_buf_size,
787 &idx_buf);
788 if (ret)
789 goto out;
790
791 versal_ipi_cmd_data_push_val(&cmd, attest_buf_size);
792 versal_ipi_cmd_data_push_val(&cmd, pub_key_offset);
793
794 ret = versal_ipi_cmd_data_push_ibuf(&cmd, NULL, signature_size,
795 &idx_sign);
796 if (ret)
797 goto out;
798
799 mutex_lock(&plm_status_lock);
800 plm_status = 0;
801 if (versal_pmc_notify(&cmd, NULL, &plm_status)) {
802 EMSG("Versal PLM API ID ATTEST_WITH_KEYWRAP_DEVAK failed: 0x%" PRIx32,
803 plm_status);
804 ret = TEE_ERROR_GENERIC;
805 mutex_unlock(&plm_status_lock);
806 goto out;
807 }
808 mutex_unlock(&plm_status_lock);
809
810 _attest_buf = versal_ipi_cmd_ibuf_get(&cmd, idx_buf);
811 memcpy((uint8_t *)attest_buf + pub_key_offset,
812 (uint8_t *)_attest_buf + pub_key_offset,
813 sizeof(struct versal_secure_rsapubkey));
814
815 versal_ipi_cmd_ibuf_fetch(&cmd, signature,
816 VERSAL_OCP_ECC_P384_SIZE_BYTES, idx_sign);
817
818 out:
819 versal_ipi_cmd_free(&cmd);
820 return ret;
821 }
822
versal_ocp_gen_shared_secret_with_devak(void * pub_key,uint32_t pub_key_size,void * shared_secret,uint32_t shared_secret_size)823 TEE_Result versal_ocp_gen_shared_secret_with_devak(void *pub_key,
824 uint32_t pub_key_size,
825 void *shared_secret,
826 uint32_t shared_secret_size)
827 {
828 TEE_Result ret = TEE_SUCCESS;
829 struct versal_ipi_cmd cmd = {};
830 size_t idx = 0;
831
832 if (!pub_key ||
833 (pub_key_size != (VERSAL_OCP_ECC_P384_SIZE_BYTES * 2)))
834 return TEE_ERROR_BAD_PARAMETERS;
835
836 if (!shared_secret ||
837 (shared_secret_size != (VERSAL_OCP_ECC_P384_SIZE_BYTES * 2)))
838 return TEE_ERROR_BAD_PARAMETERS;
839
840 versal_ipi_cmd_data_push_val(&cmd, OCP_API_ID(GEN_SHARED_SECRET));
841
842 ret = versal_ipi_cmd_data_push_ibuf(&cmd, pub_key, pub_key_size, NULL);
843 if (ret)
844 goto out;
845
846 ret = versal_ipi_cmd_data_push_ibuf(&cmd, NULL, shared_secret_size,
847 &idx);
848 if (ret)
849 goto out;
850
851 mutex_lock(&plm_status_lock);
852 plm_status = 0;
853 if (versal_pmc_notify(&cmd, NULL, &plm_status)) {
854 EMSG("Versal PLM API ID GEN_SHARED_SECRET failed: 0x%" PRIx32,
855 plm_status);
856 ret = TEE_ERROR_GENERIC;
857 mutex_unlock(&plm_status_lock);
858 goto out;
859 }
860 mutex_unlock(&plm_status_lock);
861
862 versal_ipi_cmd_ibuf_fetch(&cmd, shared_secret, shared_secret_size, idx);
863
864 out:
865 versal_ipi_cmd_free(&cmd);
866 return ret;
867 }
868