xref: /optee_os/core/drivers/versal_ocp.c (revision abca35a69f9bea0496cf05e025c3c36e6d5ea68b)
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
228 uint32_t versal_ocp_status_get(void)
229 {
230 	return versal_ocp_plm_status_get() & VERSAL_OCP_STATUS_MASK;
231 }
232 
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 
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 
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 
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, &params, 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 
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 
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, &param, 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
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, &param, 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 
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 
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, &param, 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 
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, &param, 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 
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 
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