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, ¶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 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, ¶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 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 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, ¶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 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 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