1 /* 2 * SPDX-FileCopyrightText: Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 * SPDX-License-Identifier: MIT 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be included in 13 * all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 */ 23 24 /*! 25 * Provides the implementation for all GH100 specific SPDM HALs 26 * interfaces. 27 */ 28 29 /* ------------------------ Includes --------------------------------------- */ 30 #include "nvRmReg.h" 31 #include "gpu/spdm/spdm.h" 32 #include "spdm/rmspdmtransport.h" 33 #include "spdm/rmspdmvendordef.h" 34 #include "objtmr.h" 35 #include "gpu/gsp/kernel_gsp.h" 36 #include "gpu/bus/kern_bus.h" 37 #include "gpu/mem_mgr/mem_mgr.h" 38 #include "gpu/spdm/libspdm_includes.h" 39 #include "rmapi/client_resource.h" 40 #include "ctrl/ctrl2080/ctrl2080spdm.h" 41 #include "flcnretval.h" 42 #include "gpu/conf_compute/conf_compute.h" 43 #include "platform/sli/sli.h" 44 #include "nvspdm_rmconfig.h" 45 #include "published/hopper/gh100/dev_falcon_v4.h" 46 #include "gpu/conf_compute/conf_compute.h" 47 48 /* ------------------------ Macros ----------------------------------------- */ 49 // 50 // List expected capabilties to receive from Responder. 51 // Regardless of whether Requester is configured to support these, 52 // we only expect Responder to provide these capabilities. 53 // 54 #define SPDM_CAPABILITIES_FLAGS_GH100 \ 55 SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CERT_CAP | \ 56 SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MEAS_CAP_SIG | \ 57 SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MEAS_FRESH_CAP | \ 58 SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_ENCRYPT_CAP | \ 59 SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MAC_CAP | \ 60 SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_KEY_EX_CAP | \ 61 SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_KEY_UPD_CAP | \ 62 SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_ENCAP_CAP | \ 63 SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MUT_AUTH_CAP | \ 64 SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HBEAT_CAP; 65 66 /* ------------------------ Static Variables ------------------------------- */ 67 // 68 // For transport functionality, we require access to the GPU and Spdm objects, 69 // as well as additional state (temporary response buffer). 70 // 71 // However, libspdm transport layer is implemented via callbacks which currently 72 // do not support passing any custom parameters, meaning we must use static variables 73 // to access these objects. If we ever require multiple instances of the Spdm object, 74 // this will be an issue. 75 // 76 static OBJGPU *g_pGpu = NULL; 77 static Spdm *g_pSpdm = NULL; 78 static NvU8 *g_pTransportBuffer = NULL; 79 static NvU32 g_transportBufferSize = 0; 80 static NvU32 g_pendingResponseSize = 0; 81 82 static SPDM_ALGO_CHECK_ENTRY g_SpdmAlgoCheckTable_GH100[] = 83 { 84 { LIBSPDM_DATA_MEASUREMENT_SPEC, SPDM_MEASUREMENT_SPECIFICATION_DMTF }, 85 { LIBSPDM_DATA_MEASUREMENT_HASH_ALGO, SPDM_ALGORITHMS_MEASUREMENT_HASH_ALGO_TPM_ALG_SHA_384 }, 86 { LIBSPDM_DATA_BASE_ASYM_ALGO, SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P384 }, 87 { LIBSPDM_DATA_BASE_HASH_ALGO, SPDM_ALGORITHMS_BASE_HASH_ALGO_TPM_ALG_SHA_384 }, 88 { LIBSPDM_DATA_DHE_NAME_GROUP, SPDM_ALGORITHMS_DHE_NAMED_GROUP_SECP_384_R1 }, 89 { LIBSPDM_DATA_AEAD_CIPHER_SUITE, SPDM_ALGORITHMS_AEAD_CIPHER_SUITE_AES_256_GCM }, 90 { LIBSPDM_DATA_KEY_SCHEDULE, SPDM_ALGORITHMS_KEY_SCHEDULE_HMAC_HASH }, 91 { LIBSPDM_DATA_OTHER_PARAMS_SUPPORT, 0 }, 92 #if LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP 93 { LIBSPDM_DATA_REQ_BASE_ASYM_ALG, SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_3072 } 94 #endif 95 }; 96 97 /* ------------------------ Static Function Prototypes --------------------- */ 98 static void _spdmSendHeartbeat(NvU32 gpuInstance, void *pArgs); 99 static NV_STATUS _spdmTriggerHeartbeat(OBJGPU *pGpu, OBJTMR *pTmr, PTMR_EVENT pTmrEvent); 100 101 // 102 // Static transport layer functions which we pass to libspdm as function pointers. 103 // The libspdm library will then use these functions to send and receive SPDM messages. 104 // Function parameters and types must match those expected by libspdm. 105 // 106 static spdm_version_number_t _spdmGetSecuredMessageVersionGsp(spdm_version_number_t secured_message_version); 107 108 static uint8_t _spdmGetSecuredMessageSequenceNumberGsp(uint64_t sequence_number, 109 uint8_t *sequence_number_buffer); 110 111 static uint32_t _spdmGetSecuredMessageMaxRandomNumberCountGsp(void); 112 113 static libspdm_return_t _spdmEncodeMessageGsp(void *spdm_context, const uint32_t *session_id, 114 bool is_app_message, bool is_requester, 115 size_t message_size, void *message, 116 size_t *transport_message_size, 117 void **transport_message); 118 119 static libspdm_return_t _spdmDecodeMessageGsp(void *spdm_context, uint32_t **session_id, 120 bool *is_app_message, bool is_requester, 121 size_t transport_message_size, void *transport_message, 122 size_t *message_size, void **message); 123 124 static libspdm_return_t _spdmSendMessageGsp(void *spdm_context, size_t message_size, 125 const void *message, uint64_t timeout); 126 127 static libspdm_return_t _spdmReceiveMessageGsp(void *spdm_context, size_t *message_size, 128 void **message, uint64_t timeout); 129 130 131 /* ------------------------ Static Functions ------------------------------- */ 132 // 133 // Hardcoding check for libspdm secured message callbacks version. 134 // If libspdm bumps this in a version update, we must update as well. 135 // 136 ct_assert(LIBSPDM_SECURED_MESSAGE_CALLBACKS_VERSION == 2); 137 138 /*! 139 * Callback to convert secured_message_version to DSP0277 version. 140 * In our case, secured_message_version will always be DSP0277 version. 141 */ 142 spdm_version_number_t 143 _spdmGetSecuredMessageVersionGsp 144 ( 145 spdm_version_number_t secured_message_version 146 ) 147 { 148 return secured_message_version; 149 } 150 151 /*! 152 * @brief Work function scheduled by heartbeat callback in order to actually 153 * send the heartbeat to GSP-RM. Checks to ensure whether KEY_UPDATE 154 * is required before sending heartbeat. 155 * 156 * @param[in] gpuInstance : Instance number of the specific GPU 157 * @param[in] pArgs : Opaque pointer to the SPDM object 158 */ 159 static void 160 _spdmSendHeartbeat 161 ( 162 NvU32 gpuInstance, 163 void *pArgs 164 ) 165 { 166 OBJGPU *pGpu = gpumgrGetGpu(gpuInstance); 167 OBJTMR *pTmr = NULL; 168 Spdm *pSpdm = NULL; 169 NV_STATUS status = NV_OK; 170 171 if (pGpu == NULL || pArgs == NULL) 172 { 173 status = NV_ERR_INVALID_ARGUMENT; 174 goto ErrorExit; 175 } 176 177 pTmr = GPU_GET_TIMER(pGpu); 178 pSpdm = (Spdm *)pArgs; 179 if (pSpdm == NULL || pSpdm->pLibspdmContext == NULL || 180 pSpdm->sessionId == INVALID_SESSION_ID) 181 { 182 status = NV_ERR_NOT_READY; 183 goto ErrorExit; 184 } 185 186 // 187 // Check to see if KEY_UPDATE is required before using. As timer resets on 188 // every message sent, sending KEY_UPDATE shouldn't incur any timeout risk. 189 // 190 status = spdmCheckAndExecuteKeyUpdate(pGpu, pSpdm, NV_KEY_UPDATE_TRIGGER_ID_HEARTBEAT); 191 if (status != NV_OK) 192 { 193 goto ErrorExit; 194 } 195 196 CHECK_SPDM_STATUS(libspdm_heartbeat(pSpdm->pLibspdmContext, pSpdm->sessionId)); 197 198 // Reschedule heartbeat only if successful 199 status = tmrEventScheduleRelSec(pTmr, pSpdm->pHeartbeatEvent, pSpdm->heartbeatPeriodSec); 200 201 ErrorExit: 202 if (status != NV_OK && pGpu != NULL) 203 { 204 ConfidentialCompute *pConfCompute = GPU_GET_CONF_COMPUTE(pGpu); 205 // 206 // Set GPU Ready State to false. This will destroy the SPDM session as well. 207 // Ideally we don't have dependency on Confidential Compute object here, 208 // but that's the best we can do without unnecessary code duplication. 209 // 210 confComputeSetErrorState(pGpu, pConfCompute); 211 } 212 } 213 214 /*! 215 * @brief Callback function scheduled when HEARTBEAT is enabled. 216 * Function will queue a work item to actually send the heartbeat, 217 * since we cannot do so in the callback interrupt context. 218 * Upon successful queueing of work item, schedules another heartbeat callback. 219 * 220 * @param[in] pGpu : OBJGPU pointer 221 * @param[in] pTmr : OBJTMR pointer 222 * @param[in] pTmrEvent : Pointer to the specific heartbeat timer event. 223 * 224 * @return NV_STATUS representing success or relevant failure. 225 */ 226 static NV_STATUS 227 _spdmTriggerHeartbeat 228 ( 229 OBJGPU *pGpu, 230 OBJTMR *pTmr, 231 PTMR_EVENT pTmrEvent 232 ) 233 { 234 NV_STATUS status = NV_OK; 235 236 if (pGpu == NULL || pTmr == NULL || pTmrEvent == NULL) 237 { 238 status = NV_ERR_INVALID_ARGUMENT; 239 goto ErrorExit; 240 } 241 242 // Some RM APIs call SPDM, ensure we do not conflict with them 243 status = osQueueWorkItemWithFlags(pGpu, _spdmSendHeartbeat, pTmrEvent->pUserData, 244 OS_QUEUE_WORKITEM_FLAGS_DONT_FREE_PARAMS | 245 OS_QUEUE_WORKITEM_FLAGS_LOCK_API_RW | 246 OS_QUEUE_WORKITEM_FLAGS_LOCK_GPUS_RW); 247 248 ErrorExit: 249 if (status != NV_OK && pGpu != NULL) 250 { 251 ConfidentialCompute *pConfCompute = GPU_GET_CONF_COMPUTE(pGpu); 252 // 253 // Set GPU Ready State to false. This will destroy the SPDM session as well. 254 // Ideally we don't have dependency on Confidential Compute object here, 255 // but that's the best we can do without unnecessary code duplication. 256 // 257 confComputeSetErrorState(pGpu, pConfCompute); 258 } 259 return status; 260 } 261 262 /*! 263 * Callback to fill out sequence number in expected format. 264 * The sequence number is for secured message format only and defined in DMTF DSP0277. 265 * Currently, requester(RM) and responder(GSP-SPDM) doesn't support sequence number. 266 */ 267 uint8_t 268 _spdmGetSecuredMessageSequenceNumberGsp 269 ( 270 uint64_t sequence_number, 271 uint8_t *sequence_number_buffer 272 ) 273 { 274 // No sequence number included as a part of GSP secured message. 275 return 0; 276 } 277 278 /*! 279 * Callback to fill RNG blob in secured message. 280 * The random number size is for secured message format only and defined in DMTF DSP0277. 281 */ 282 uint32_t 283 _spdmGetSecuredMessageMaxRandomNumberCountGsp 284 ( 285 void 286 ) 287 { 288 return NV_SPDM_MAX_RANDOM_MSG_BYTES; 289 } 290 291 /*! 292 * Static function libspdm uses as hook to RM<->GSP transport layer. 293 * If secured, encodes message into SPDM Secured Message format. 294 */ 295 libspdm_return_t 296 _spdmEncodeMessageGsp 297 ( 298 void *spdm_context, 299 const uint32_t *session_id, 300 bool is_app_message, 301 bool is_requester, 302 size_t message_size, 303 void *message, 304 size_t *transport_message_size, 305 void **transport_message 306 ) 307 { 308 libspdm_secured_message_callbacks_t securedMessageInfo; 309 libspdm_return_t status = LIBSPDM_STATUS_SUCCESS; 310 size_t securedMessageSize = 0; 311 void *pSecuredMessageContext = NULL; 312 NV_SPDM_DESC_HEADER *pNvSpdmDescHdr = NULL; 313 NvU32 payloadSize = 0; 314 315 // Check libspdm parameters. 316 if (spdm_context == NULL || message == NULL || message_size == 0 || 317 transport_message == NULL || *transport_message == NULL || 318 transport_message_size == NULL) 319 { 320 return LIBSPDM_STATUS_INVALID_PARAMETER; 321 } 322 323 // Only support sending requester SPDM/Secured messages. 324 if (!is_requester || is_app_message) 325 { 326 return LIBSPDM_STATUS_INVALID_PARAMETER; 327 } 328 329 // The transport buffer must be large enough to fit the transport header and the message. 330 if (*transport_message_size < (sizeof(NV_SPDM_DESC_HEADER) + message_size)) 331 { 332 return LIBSPDM_STATUS_INVALID_MSG_FIELD; 333 } 334 335 // Initialize descriptor header. 336 pNvSpdmDescHdr = (NV_SPDM_DESC_HEADER *)*transport_message; 337 portMemSet(pNvSpdmDescHdr, 0, sizeof(NV_SPDM_DESC_HEADER)); 338 pNvSpdmDescHdr->version = NV_SPDM_DESC_HEADER_VERSION_CURRENT; 339 340 // Determine whether message is secured. 341 if (session_id != NULL) 342 { 343 pNvSpdmDescHdr->msgType = NV_SPDM_MESSAGE_TYPE_SECURED; 344 345 pSecuredMessageContext = 346 libspdm_get_secured_message_context_via_session_id(spdm_context, *session_id); 347 348 if (pSecuredMessageContext == NULL) 349 { 350 return LIBSPDM_STATUS_SESSION_MSG_ERROR; 351 } 352 353 // Calculate max space we have for secured message in transport buffer. 354 securedMessageSize = *transport_message_size; 355 securedMessageSize -= sizeof(NV_SPDM_DESC_HEADER); 356 357 // Initialize secured message attributes. 358 portMemSet(&securedMessageInfo, 0, sizeof(securedMessageInfo)); 359 securedMessageInfo.version = LIBSPDM_SECURED_MESSAGE_CALLBACKS_VERSION; 360 securedMessageInfo.get_sequence_number = _spdmGetSecuredMessageSequenceNumberGsp; 361 securedMessageInfo.get_max_random_number_count = _spdmGetSecuredMessageMaxRandomNumberCountGsp; 362 securedMessageInfo.get_secured_spdm_version = _spdmGetSecuredMessageVersionGsp; 363 364 // Encode secured message into output buffer. 365 status = libspdm_encode_secured_message(pSecuredMessageContext, *session_id, is_requester, 366 message_size, message, &securedMessageSize, 367 (pNvSpdmDescHdr + 1), &securedMessageInfo); 368 if (status != LIBSPDM_STATUS_SUCCESS) 369 { 370 return status; 371 } 372 373 // Transport message buffer must be large enough to store secured message + NV_SPDM_DESC_HEADER. 374 NV_ASSERT_OR_RETURN(*transport_message_size > (securedMessageSize + sizeof(NV_SPDM_DESC_HEADER)), 375 LIBSPDM_STATUS_INVALID_MSG_FIELD); 376 377 pNvSpdmDescHdr->msgSizeByte = (NvU32)securedMessageSize; 378 *transport_message_size = securedMessageSize + sizeof(NV_SPDM_DESC_HEADER); 379 } 380 else 381 { 382 // The normal message is not encrypted, it will be sent as NV_SPDM_DESC_HEADER + Message. 383 payloadSize = sizeof(NV_SPDM_DESC_HEADER) + message_size; 384 385 // 386 // Check for large enough buffer for payload, as well as for overflow in 387 // operation above. If no overflow, we know message_size fits in NvU32. 388 // 389 if (*transport_message_size < payloadSize || payloadSize < message_size) 390 { 391 return LIBSPDM_STATUS_BUFFER_TOO_SMALL; 392 } 393 394 // 395 // Fill in SPDM message header. 396 // The SPDM message is already after the SPDM msg header. 397 // 398 pNvSpdmDescHdr->msgType = NV_SPDM_MESSAGE_TYPE_NORMAL; 399 pNvSpdmDescHdr->msgSizeByte = (NvU32)message_size; 400 *transport_message_size = payloadSize; 401 } 402 403 // Check final encrypted message size. 404 if (*transport_message_size > g_pSpdm->payloadBufferSize) 405 { 406 return LIBSPDM_STATUS_BUFFER_TOO_SMALL; 407 } 408 409 return LIBSPDM_STATUS_SUCCESS; 410 } 411 412 /*! 413 * Static function libspdm uses as hook to RM<->GSP transport layer. 414 * If secured, decodes the message from the SPDM Secured Message format. 415 */ 416 libspdm_return_t 417 _spdmDecodeMessageGsp 418 ( 419 void *spdm_context, 420 uint32_t **session_id, 421 bool *is_app_message, 422 bool is_requester, 423 size_t transport_message_size, 424 void *transport_message, 425 size_t *message_size, 426 void **message 427 ) 428 { 429 libspdm_secured_message_callbacks_t securedMessageInfo; 430 NV_SPDM_DESC_HEADER *pNvSpdmDescHdr = NULL; 431 NvU32 payloadSize = 0; 432 void *pSecuredMessageContext = NULL; 433 libspdm_return_t status = LIBSPDM_STATUS_SUCCESS; 434 spdm_secured_message_a_data_header1_t *pSpdmSecuredMsgHdr = NULL; 435 436 // Check libspdm parameters. 437 if (spdm_context == NULL || session_id == NULL || is_app_message == NULL || 438 transport_message_size == 0 || transport_message == NULL || 439 message_size == NULL || message == NULL || *message == NULL) 440 { 441 return LIBSPDM_STATUS_INVALID_PARAMETER; 442 } 443 444 // Only support receiving Responder SPDM/Secured messages. 445 if (is_requester) 446 { 447 return LIBSPDM_STATUS_INVALID_PARAMETER; 448 } 449 450 // Retrieve NV-header from message, and perform basic validation. 451 pNvSpdmDescHdr = (NV_SPDM_DESC_HEADER *)transport_message; 452 if (transport_message_size < sizeof(NV_SPDM_DESC_HEADER) || 453 transport_message_size > g_pSpdm->payloadBufferSize) 454 { 455 return LIBSPDM_STATUS_INVALID_MSG_FIELD; 456 } 457 458 if (pNvSpdmDescHdr->version != NV_SPDM_DESC_HEADER_VERSION_CURRENT) 459 { 460 NV_PRINTF(LEVEL_ERROR, 461 "SPDM: Version mismatch: [Check] version = 0x%x, [SpdmRet] version = 0x%x\n", 462 NV_SPDM_DESC_HEADER_VERSION_CURRENT, pNvSpdmDescHdr->version); 463 DBG_BREAKPOINT(); 464 return LIBSPDM_STATUS_INVALID_MSG_FIELD; 465 } 466 467 payloadSize = sizeof(NV_SPDM_DESC_HEADER) + pNvSpdmDescHdr->msgSizeByte; 468 469 if (transport_message_size != payloadSize) 470 { 471 return LIBSPDM_STATUS_INVALID_MSG_FIELD; 472 } 473 474 // Decode message, based on type. 475 switch (pNvSpdmDescHdr->msgType) 476 { 477 case NV_SPDM_MESSAGE_TYPE_SECURED: 478 { 479 // 480 // Double-check the payload fits a secured message header. 481 // Our implementation of a secure message header only includes 482 // session ID - no sequence number. 483 // 484 if (pNvSpdmDescHdr->msgSizeByte < sizeof(spdm_secured_message_a_data_header1_t)) 485 { 486 return LIBSPDM_STATUS_INVALID_MSG_FIELD; 487 } 488 489 // Secured message header begins immediately after general NV header. 490 pSpdmSecuredMsgHdr = (spdm_secured_message_a_data_header1_t *)(pNvSpdmDescHdr + 1); 491 *session_id = &pSpdmSecuredMsgHdr->session_id; 492 493 pSecuredMessageContext = 494 libspdm_get_secured_message_context_via_session_id(spdm_context, **session_id); 495 496 if (pSecuredMessageContext == NULL) 497 { 498 return LIBSPDM_STATUS_SESSION_MSG_ERROR; 499 } 500 501 // Initialize secured message attributes. 502 portMemSet(&securedMessageInfo, 0, sizeof(securedMessageInfo)); 503 securedMessageInfo.version = LIBSPDM_SECURED_MESSAGE_CALLBACKS_VERSION; 504 securedMessageInfo.get_sequence_number = _spdmGetSecuredMessageSequenceNumberGsp; 505 securedMessageInfo.get_max_random_number_count = _spdmGetSecuredMessageMaxRandomNumberCountGsp; 506 securedMessageInfo.get_secured_spdm_version = _spdmGetSecuredMessageVersionGsp; 507 508 // Decode and retrieve application payload from secured message. 509 // We must copy the message to the scratch buffer. 510 status = libspdm_decode_secured_message(pSecuredMessageContext, 511 **session_id, is_requester, 512 transport_message_size - sizeof(NV_SPDM_DESC_HEADER), 513 (pNvSpdmDescHdr + 1), message_size, 514 message, &securedMessageInfo); 515 if (status != LIBSPDM_STATUS_SUCCESS) 516 { 517 return status; 518 } 519 } 520 break; 521 522 case NV_SPDM_MESSAGE_TYPE_NORMAL: 523 { 524 // Indicate the message is unsecured. 525 *session_id = NULL; 526 527 // 528 // We both check that the buffer is large enough, and that the 529 // size_t type is large enough to hold the size of the message. 530 // 531 if (*message_size < pNvSpdmDescHdr->msgSizeByte) 532 { 533 return LIBSPDM_STATUS_BUFFER_TOO_SMALL; 534 } 535 536 // The message is already present in the receiver buffer. 537 // Just use that. 538 *message = (uint8_t *)(pNvSpdmDescHdr + 1); 539 *message_size = pNvSpdmDescHdr->msgSizeByte; 540 } 541 break; 542 543 default: 544 { 545 return LIBSPDM_STATUS_INVALID_MSG_FIELD; 546 } 547 } 548 549 // We don't expect app message for any scenario. 550 *is_app_message = NV_FALSE; 551 552 return LIBSPDM_STATUS_SUCCESS; 553 } 554 555 /*! 556 * Static function libspdm uses as hook to RM<->GSP transport layer. 557 * Sends SPDM request message to GSP, and stores received response to buffer. 558 * Response buffer must be freed by corresponding _spdmReceiveMessageGsp(). 559 */ 560 libspdm_return_t 561 _spdmSendMessageGsp 562 ( 563 void *spdm_context, 564 size_t message_size, 565 const void *message, 566 uint64_t timeout 567 ) 568 { 569 NV_STATUS nvStatus = NV_OK; 570 libspdm_return_t spdmStatus = LIBSPDM_STATUS_SUCCESS; 571 572 // Ensure size is cleared to indicate no response pending in buffer yet 573 g_pendingResponseSize = 0; 574 575 // Check libspdm parameters. 576 if (message_size == 0 || message == NULL) 577 { 578 return LIBSPDM_STATUS_INVALID_PARAMETER; 579 } 580 581 if (g_pGpu == NULL || g_pSpdm == NULL) 582 { 583 return LIBSPDM_STATUS_INVALID_STATE_LOCAL; 584 } 585 586 if (g_transportBufferSize < message_size) 587 { 588 return LIBSPDM_STATUS_BUFFER_TOO_SMALL; 589 } 590 591 // Fill transport buffer with message and send 592 g_pendingResponseSize = g_transportBufferSize; 593 portMemCopy(g_pTransportBuffer, g_transportBufferSize, message, message_size); 594 595 nvStatus = spdmMessageProcess_HAL(g_pGpu, g_pSpdm, 596 g_pTransportBuffer, message_size, 597 g_pTransportBuffer, &g_pendingResponseSize); 598 if (nvStatus != NV_OK) 599 { 600 spdmStatus = LIBSPDM_STATUS_SEND_FAIL; 601 } 602 603 if (spdmStatus != LIBSPDM_STATUS_SUCCESS) 604 { 605 // If message failed, size is cleared to indicate no response pending 606 g_pendingResponseSize = 0; 607 } 608 609 return spdmStatus; 610 } 611 612 /*! 613 * Static function libspdm uses as hook to RM<->GSP transport layer. 614 * Copies stored response message back to libspdm buffer. Cannot be retried, 615 * as must free response message regardless of success or failure. 616 */ 617 libspdm_return_t 618 _spdmReceiveMessageGsp 619 ( 620 void *spdm_context, 621 size_t *message_size, 622 void **message, 623 uint64_t timeout 624 ) 625 { 626 libspdm_return_t spdmStatus = LIBSPDM_STATUS_SUCCESS; 627 628 // Check libspdm parameters. 629 if (message_size == NULL || message == NULL || *message == NULL) 630 { 631 return LIBSPDM_STATUS_INVALID_PARAMETER; 632 } 633 634 if (g_pGpu == NULL || g_pSpdm == NULL) 635 { 636 return LIBSPDM_STATUS_INVALID_STATE_LOCAL; 637 } 638 639 // Basic validation to ensure we have a real response. 640 if (g_pendingResponseSize == 0 || g_pendingResponseSize > *message_size) 641 { 642 spdmStatus = LIBSPDM_STATUS_RECEIVE_FAIL; 643 goto ErrorExit; 644 } 645 646 portMemCopy(*message, *message_size, g_pTransportBuffer, g_pendingResponseSize); 647 *message_size = g_pendingResponseSize; 648 649 ErrorExit: 650 651 // Ensure size is cleared to indicate no response pending in buffer 652 g_pendingResponseSize = 0; 653 654 return spdmStatus; 655 } 656 657 658 /* ------------------------ Public Functions ------------------------------- */ 659 /*! 660 * On Hopper, we use GSP as SPDM Responder. To initialize, we must allocate 661 * a surface for SPDM communication, send initialization command to GSP-SPDM 662 * partition, and register all transport-layer functionality with library. 663 */ 664 NV_STATUS 665 spdmDeviceInit_GH100 666 ( 667 OBJGPU *pGpu, 668 Spdm *pSpdm 669 ) 670 { 671 if (pGpu == NULL || pSpdm == NULL || pSpdm->pLibspdmContext == NULL) 672 { 673 return NV_ERR_INVALID_ARGUMENT; 674 } 675 676 g_pGpu = pGpu; 677 g_pSpdm = pSpdm; 678 g_pendingResponseSize = 0; 679 g_pTransportBuffer = portMemAllocNonPaged(pSpdm->payloadBufferSize); 680 681 if (g_pTransportBuffer == NULL) 682 { 683 g_transportBufferSize = 0; 684 return NV_ERR_NO_MEMORY; 685 } 686 687 g_transportBufferSize = pSpdm->payloadBufferSize; 688 689 // Register transport layer functionality with library. 690 libspdm_register_transport_layer_func(pSpdm->pLibspdmContext, 691 NV_SPDM_MAX_SPDM_PAYLOAD_SIZE, 692 sizeof(NV_SPDM_DESC_HEADER), 693 0, 694 _spdmEncodeMessageGsp, 695 _spdmDecodeMessageGsp); 696 697 libspdm_register_device_io_func(pSpdm->pLibspdmContext, 698 _spdmSendMessageGsp, 699 _spdmReceiveMessageGsp); 700 701 pSpdm->bUsePolling = IS_GSP_CLIENT(pGpu); 702 703 return NV_OK; 704 } 705 706 707 /*! 708 * To deinitialize the GSP SPDM Responder, we need to release the surface for 709 * SPDM communication. GSP-RM will handle the rest. 710 */ 711 NV_STATUS 712 spdmDeviceDeinit_GH100 713 ( 714 OBJGPU *pGpu, 715 Spdm *pSpdm, 716 NvBool bForceClear 717 ) 718 { 719 // Just-in-case, portMemFree handles NULL. 720 portMemFree(g_pTransportBuffer); 721 g_pTransportBuffer = NULL; 722 g_transportBufferSize = 0; 723 g_pendingResponseSize = 0; 724 725 return NV_OK; 726 } 727 728 NV_STATUS 729 spdmMessageProcess_GH100 730 ( 731 OBJGPU *pGpu, 732 Spdm *pSpdm, 733 NvU8 *pRequest, 734 NvU32 requestSize, 735 NvU8 *pResponse, 736 NvU32 *pResponseSize 737 ) 738 { 739 NV_STATUS status = NV_OK; 740 NvU8 *pMapMem = NULL; 741 NvU32 messagePending = 0; 742 NvU8 *pPayloadBuffer = NULL; 743 NvU32 transportResponseSize = 0; 744 NV2080_CTRL_INTERNAL_SPDM_PARTITION_PARAMS params; 745 MemoryManager *pMemoryManager = NULL; 746 TRANSFER_SURFACE surf = {0}; 747 NvBool bFreeShadowBuf = NV_FALSE; 748 749 if (pGpu == NULL || pSpdm == NULL ||pRequest == NULL || 750 pResponse == NULL || pResponseSize == NULL) 751 { 752 return NV_ERR_INVALID_ARGUMENT; 753 } 754 755 if (requestSize > pSpdm->payloadBufferSize) 756 { 757 return NV_ERR_INSUFFICIENT_RESOURCES; 758 } 759 760 SLI_LOOP_START(SLI_LOOP_FLAGS_BC_ONLY) 761 762 // Offset is zero for all transfers 763 surf.offset = 0; 764 pMemoryManager = GPU_GET_MEMORY_MANAGER(pGpu); 765 766 if (pSpdm->bUsePolling) 767 { 768 // 769 // If we haven't established the session yet, we need to utilize polling 770 // based communication with GSP-SPDM partition, as GSP-RM RPC is not available. 771 // Note that there is a short window where session is established but GSP-RM RPC is 772 // not active - we don't expect any SPDM messages in this window. 773 // 774 RMTIMEOUT timeout; 775 KernelGsp *pKernelGsp = GPU_GET_KERNEL_GSP(pGpu); 776 KernelFalcon *pKernelFalcon = staticCast(pKernelGsp, KernelFalcon); 777 778 pPayloadBuffer = memmgrMemDescBeginTransfer(pMemoryManager, pSpdm->pPayloadBufferMemDesc, 779 TRANSFER_FLAGS_SHADOW_ALLOC); 780 if (pPayloadBuffer == NULL) 781 { 782 status = NV_ERR_INSUFFICIENT_RESOURCES; 783 goto ErrorExit; 784 } 785 786 // First copy payload to shared buffer 787 portMemCopy(pPayloadBuffer, requestSize, pRequest, requestSize); 788 memdescFlushCpuCaches(pGpu, pSpdm->pPayloadBufferMemDesc); 789 790 // Trigger message pending value, then poll for response from GSP 791 kflcnRegWrite_HAL(pGpu, pKernelFalcon, NV_PFALCON_FALCON_MAILBOX0, NV_SPDM_REQUESTER_MESSAGE_PENDING_TOKEN); 792 793 messagePending = kflcnRegRead_HAL(pGpu, pKernelFalcon, NV_PFALCON_FALCON_MAILBOX0); 794 gpuSetTimeout(pGpu, GPU_TIMEOUT_DEFAULT, &timeout, 0); 795 while (messagePending != NV_SPDM_RESPONDER_MESSAGE_PENDING_TOKEN) 796 { 797 if (gpuCheckTimeout(pGpu, &timeout) == NV_ERR_TIMEOUT) 798 { 799 NV_PRINTF(LEVEL_ERROR, "Timeout waiting for response from SPDM Responder!\n"); 800 DBG_BREAKPOINT(); 801 status = NV_ERR_TIMEOUT; 802 goto ErrorExit; 803 } 804 805 messagePending = kflcnRegRead_HAL(pGpu, pKernelFalcon, NV_PFALCON_FALCON_MAILBOX0); 806 } 807 } 808 else 809 { 810 // 811 // At this point, we have abandoned polling and now rely on GSP-RM RPCs. 812 // 813 814 // Copy entire SPDM message to shared memory. 815 surf.pMemDesc = pSpdm->pPayloadBufferMemDesc; 816 status = memmgrMemWrite(pMemoryManager, &surf, pRequest, requestSize, TRANSFER_FLAGS_NONE); 817 if (status != NV_OK) 818 { 819 goto ErrorExit; 820 } 821 822 // Prepare GSP-CMD and send to GSP-SPDM partition 823 portMemSet(¶ms, 0, sizeof(params)); 824 params.cmd.cmdType = RM_GSP_SPDM_CMD_ID_CC_CTRL; 825 826 status = spdmCtrlSpdmPartition(pGpu, ¶ms); 827 if (params.msg.status != NV_OK) 828 { 829 NV_PRINTF(LEVEL_ERROR, "SPDM: RPC failed! RPC status = 0x%x\n", 830 params.msg.status); 831 status = params.msg.status; 832 DBG_BREAKPOINT(); 833 goto ErrorExit; 834 } 835 } 836 837 if (status != NV_OK) 838 { 839 NV_PRINTF(LEVEL_ERROR, "SPDM: Send/receive failed! status = 0x%x\n", status); 840 DBG_BREAKPOINT(); 841 goto ErrorExit; 842 } 843 844 // Retrieve descriptor header and response message, checking header to ensure valid response. 845 surf.pMemDesc = pSpdm->pPayloadBufferMemDesc; 846 pMapMem = portMemAllocNonPaged(pSpdm->payloadBufferSize); 847 if (pMapMem == NULL) 848 { 849 status = NV_ERR_INSUFFICIENT_RESOURCES; 850 goto ErrorExit; 851 } 852 853 bFreeShadowBuf = NV_TRUE; 854 855 status = memmgrMemRead(pMemoryManager, &surf, pMapMem, 856 pSpdm->payloadBufferSize, 857 TRANSFER_FLAGS_NONE); 858 if (status != NV_OK) 859 { 860 goto ErrorExit; 861 } 862 863 transportResponseSize = (((NV_SPDM_DESC_HEADER *)pMapMem)->msgSizeByte + sizeof(NV_SPDM_DESC_HEADER)); 864 if (transportResponseSize > *pResponseSize) 865 { 866 status = NV_ERR_INSUFFICIENT_RESOURCES; 867 NV_PRINTF(LEVEL_ERROR, "SPDM: Error: transportResponseSize = 0x%x, responseSize = 0x%x\n", 868 transportResponseSize, *pResponseSize); 869 DBG_BREAKPOINT(); 870 goto ErrorExit; 871 } 872 873 portMemCopy(pResponse, *pResponseSize, pMapMem, transportResponseSize); 874 *pResponseSize = transportResponseSize; 875 876 ErrorExit: 877 if (pPayloadBuffer != NULL) 878 { 879 memmgrMemDescEndTransfer(pMemoryManager, pSpdm->pPayloadBufferMemDesc, 880 TRANSFER_FLAGS_SHADOW_ALLOC); 881 } 882 883 SLI_LOOP_END 884 885 if (bFreeShadowBuf) 886 { 887 portMemFree(pMapMem); 888 bFreeShadowBuf = NV_FALSE; 889 } 890 891 return status; 892 } 893 894 NV_STATUS 895 spdmDeviceSecuredSessionSupported_GH100 896 ( 897 OBJGPU *pGpu, 898 Spdm *pSpdm 899 ) 900 { 901 return NV_OK; 902 } 903 904 NV_STATUS 905 spdmCheckConnection_GH100 906 ( 907 OBJGPU *pGpu, 908 Spdm *pSpdm 909 ) 910 { 911 void *pContext = NULL; 912 uint32_t expectedFlags = 0; 913 uint32_t capabilitiesFlags = 0; 914 libspdm_return_t ret = LIBSPDM_STATUS_SUCCESS; 915 libspdm_data_parameter_t dataParam; 916 libspdm_connection_state_t connectionState; 917 uint8_t ctExponent; 918 size_t dataSize; 919 NvU32 i; 920 NvU32 algoCheckCount; 921 NvU32 actualAlgo; 922 PSPDM_ALGO_CHECK_ENTRY pCheckEntry; 923 924 if (pGpu == NULL || pSpdm == NULL) 925 { 926 return NV_ERR_INVALID_ARGUMENT; 927 } 928 929 // Ensure we have at least negotiated the parameters of the SPDM connection. 930 pContext = (void *)pSpdm->pLibspdmContext; 931 932 if (pContext == NULL) 933 { 934 return NV_ERR_NOT_READY; 935 } 936 937 dataParam.location = LIBSPDM_DATA_LOCATION_CONNECTION; 938 dataSize = sizeof(connectionState); 939 ret = libspdm_get_data(pContext, LIBSPDM_DATA_CONNECTION_STATE, 940 &dataParam, &connectionState, &dataSize); 941 942 if (ret != LIBSPDM_STATUS_SUCCESS || connectionState < LIBSPDM_CONNECTION_STATE_NEGOTIATED) 943 { 944 return NV_ERR_NOT_READY; 945 } 946 947 // Check version matches expected. 948 if (libspdm_get_connection_version(pContext) != SPDM_MESSAGE_VERSION_11) 949 { 950 return NV_ERR_INVALID_STATE; 951 } 952 953 dataSize = sizeof(ctExponent); 954 ret = libspdm_get_data(pContext, LIBSPDM_DATA_CAPABILITY_CT_EXPONENT, 955 &dataParam, &ctExponent, &dataSize); 956 957 if (ret != LIBSPDM_STATUS_SUCCESS || ctExponent != LIBSPDM_MAX_CT_EXPONENT) 958 { 959 NV_PRINTF(LEVEL_ERROR, "SPDM: Invalid Responder CT exponent.\n"); 960 return NV_ERR_INVALID_STATE; 961 } 962 963 // Check all capabilities match expected. 964 expectedFlags = SPDM_CAPABILITIES_FLAGS_GH100; 965 966 dataSize = sizeof(capabilitiesFlags); 967 ret = libspdm_get_data(pContext, LIBSPDM_DATA_CAPABILITY_FLAGS, 968 &dataParam, &capabilitiesFlags, &dataSize); 969 970 if (ret != LIBSPDM_STATUS_SUCCESS || capabilitiesFlags != expectedFlags) 971 { 972 NV_PRINTF(LEVEL_ERROR, "SPDM: Invalid Responder capabilities.\n"); 973 return NV_ERR_INVALID_STATE; 974 } 975 976 // Check all crypto algorithms match expected. 977 algoCheckCount = sizeof(g_SpdmAlgoCheckTable_GH100)/sizeof(SPDM_ALGO_CHECK_ENTRY); 978 979 for (i = 0; i < algoCheckCount; i++) 980 { 981 pCheckEntry = &g_SpdmAlgoCheckTable_GH100[i]; 982 983 actualAlgo = 0; 984 dataSize = sizeof(actualAlgo); 985 ret = libspdm_get_data(pContext, pCheckEntry->dataType, 986 &dataParam, &actualAlgo, &dataSize); 987 988 if (ret != LIBSPDM_STATUS_SUCCESS || actualAlgo != pCheckEntry->expectedAlgo) 989 { 990 NV_PRINTF(LEVEL_ERROR, "SPDM: Invalid crypto algorithms selected.\n"); 991 NV_PRINTF(LEVEL_ERROR, "SPDM: AlgoCheckCount 0x%0x, i is 0x%0x, status is 0x%0x.\n", (NvU32)algoCheckCount, (NvU32)i, (NvU32)ret); 992 NV_PRINTF(LEVEL_ERROR, "SPDM: Expected algo 0x%0x, actual algo 0x%0x\n", (NvU32)pCheckEntry->expectedAlgo, (NvU32)actualAlgo); 993 return NV_ERR_INVALID_STATE; 994 } 995 } 996 997 return NV_OK; 998 } 999 1000 NV_STATUS 1001 spdmGetAttestationReport_GH100 1002 ( 1003 OBJGPU *pGpu, 1004 Spdm *pSpdm, 1005 NvU8 *pNonce, 1006 void *pAttestationReport, 1007 NvU32 *pAttestationReportSize, 1008 NvBool *pbIsCecAttestationReportPresent, 1009 void *pCecAttestationReport, 1010 NvU32 *pCecAttestationReportSize 1011 ) 1012 { 1013 NV_STATUS status = NV_OK; 1014 uint8_t numBlocks = 0; 1015 uint32_t measurementSize = 0; 1016 void *pMeasurementBuffer = NULL; 1017 1018 if (pGpu == NULL || pSpdm == NULL) 1019 { 1020 return NV_ERR_INVALID_ARGUMENT; 1021 } 1022 1023 // Ensure we have a valid session, and have retrieved the certificates. 1024 if (pSpdm->pLibspdmContext == NULL || !pSpdm->bSessionEstablished) 1025 { 1026 return NV_ERR_NOT_READY; 1027 } 1028 1029 // Check to see if KEY_UPDATE is required before using. 1030 status = spdmCheckAndExecuteKeyUpdate(pGpu, pSpdm, NV_KEY_UPDATE_TRIGGER_ID_GET_MEASUREMENTS); 1031 if (status != NV_OK) 1032 { 1033 return status; 1034 } 1035 1036 // Retrieve Attestation Report, if requested. 1037 if (pAttestationReport != NULL && pAttestationReportSize != NULL) 1038 { 1039 // Reset the libspdm message log to ensure it only contains the request and response from this call. 1040 libspdm_reset_msg_log(pSpdm->pLibspdmContext); 1041 libspdm_set_msg_log_mode(pSpdm->pLibspdmContext, LIBSPDM_MSG_LOG_MODE_ENABLE); 1042 1043 numBlocks = SPDM_MAX_MEASUREMENT_BLOCK_COUNT; 1044 1045 // 1046 // Use Attestation Report buffer temporarily to store measurements, we will replace 1047 // with the full Attestation Report from message transcripts. If the Attestation Report 1048 // buffer is too small to get the measurements, it won't be large enough for the report. 1049 // 1050 pMeasurementBuffer = pAttestationReport; 1051 measurementSize = *pAttestationReportSize; 1052 1053 // Request the Attestation Report using the provided nonce, signed by the AK cert. 1054 CHECK_SPDM_STATUS(libspdm_get_measurement_ex(pSpdm->pLibspdmContext, &pSpdm->sessionId, 1055 SPDM_GET_MEASUREMENTS_REQUEST_ATTRIBUTES_GENERATE_SIGNATURE, 1056 SPDM_GET_MEASUREMENTS_REQUEST_MEASUREMENT_OPERATION_ALL_MEASUREMENTS, 1057 SPDM_CERT_DEFAULT_SLOT_ID, NULL, &numBlocks, 1058 &measurementSize, pMeasurementBuffer, pNonce, NULL, NULL, NULL, NULL)); 1059 1060 if (!nvspdm_check_and_clear_libspdm_assert()) 1061 { 1062 // libspdm detects assert/error in GET_MEASUREMENT process, need to return error. 1063 NV_PRINTF(LEVEL_ERROR, "SPDM: spdmCheckAndClearLibspdmAssert() failed \n"); 1064 DBG_BREAKPOINT(); 1065 1066 return NV_ERR_INVALID_STATE; 1067 } 1068 1069 // 1070 // Message log buffer will hold Attestation Report, which is comprised of 1071 // the GET_MEASUREMENTS request concatenated with the MEASUREMENTS response. 1072 // 1073 if (*pAttestationReportSize < libspdm_get_msg_log_size(pSpdm->pLibspdmContext)) 1074 { 1075 return NV_ERR_BUFFER_TOO_SMALL; 1076 } 1077 1078 portMemCopy(pAttestationReport, *pAttestationReportSize, 1079 pSpdm->pMsgLog, libspdm_get_msg_log_size(pSpdm->pLibspdmContext)); 1080 *pAttestationReportSize = libspdm_get_msg_log_size(pSpdm->pLibspdmContext); 1081 } 1082 1083 // Retrieve CEC Attestation Report, if requested. 1084 if (pbIsCecAttestationReportPresent != NULL) 1085 { 1086 *pbIsCecAttestationReportPresent = NV_FALSE; 1087 } 1088 1089 ErrorExit: 1090 // Regardless of what happens, reset the message log so we don't track anything past this. 1091 libspdm_reset_msg_log(pSpdm->pLibspdmContext); 1092 1093 return status; 1094 } 1095 1096 /*! 1097 * Function that sends the opaque data from RM to GSP. 1098 */ 1099 NV_STATUS 1100 spdmSendInitRmDataCommand_GH100 1101 ( 1102 OBJGPU *pGpu, 1103 Spdm *pSpdm 1104 ) 1105 { 1106 NV_STATUS status = NV_OK; 1107 RMTIMEOUT timeout; 1108 NV2080_CTRL_INTERNAL_SPDM_PARTITION_PARAMS params; 1109 1110 if (pGpu == NULL || pSpdm == NULL || !pSpdm->bSessionEstablished) 1111 { 1112 return NV_ERR_INVALID_ARGUMENT; 1113 } 1114 1115 portMemSet(¶ms, 0, sizeof(params)); 1116 params.cmd.cmdType = RM_GSP_SPDM_CMD_ID_CC_INIT_RM_DATA; 1117 1118 gpuSetTimeout(pGpu, GPU_TIMEOUT_DEFAULT, &timeout, 0); 1119 1120 status = spdmCtrlSpdmPartition(pGpu, ¶ms); 1121 if (status != NV_OK) 1122 { 1123 NV_PRINTF(LEVEL_ERROR, "SPDM: Send/receive error in INIT_RM_DATA command\n"); 1124 return NV_ERR_FLCN_ERROR; 1125 } 1126 1127 // Perform basic validation of header returned. 1128 status = params.msg.status; 1129 if (status != NV_OK) 1130 { 1131 NV_PRINTF(LEVEL_ERROR, "SPDM: RPC returned failure in INIT_RM_DATA command! status = 0x%0x\n", 1132 status); 1133 DBG_BREAKPOINT(); 1134 return status; 1135 } 1136 1137 return NV_OK; 1138 } 1139 1140 /*! 1141 * @brief spdmCheckAndExecuteKeyUpdate_GH100 1142 * This function is used check scenario and perform key_exchange process if needed. 1143 * 1144 * @param[in] pGpu : OBJGPU Pointer 1145 * @param[in] pSpdm : SPDM pointer 1146 * @param[in] keyUpdateTriggerId : The id to identify the client, which trigger key update. 1147 * 1148 * @return NV_OK : Return NV_OK if no error 1149 * 1150 */ 1151 NV_STATUS 1152 spdmCheckAndExecuteKeyUpdate_GH100 1153 ( 1154 OBJGPU *pGpu, 1155 Spdm *pSpdm, 1156 NvU32 keyUpdateTriggerId 1157 ) 1158 { 1159 libspdm_return_t ret; 1160 bool bSingleDirection = false; 1161 1162 if (pGpu == NULL || pSpdm == NULL) 1163 { 1164 return NV_ERR_INVALID_ARGUMENT; 1165 } 1166 1167 // Ensure we have a valid session, and have retrieved the certificates. 1168 if (pSpdm->pLibspdmContext == NULL || pSpdm->sessionId == INVALID_SESSION_ID) 1169 { 1170 return NV_ERR_NOT_READY; 1171 } 1172 1173 if (keyUpdateTriggerId == NV_KEY_UPDATE_TRIGGER_ID_GET_MEASUREMENTS || 1174 keyUpdateTriggerId == NV_KEY_UPDATE_TRIGGER_ID_HEARTBEAT) 1175 { 1176 pSpdm->sessionMsgCount++; 1177 if (pSpdm->sessionMsgCount >= NV_KEY_UPDATE_TRIGGER_THRESHOLD) 1178 { 1179 ret = libspdm_key_update(pSpdm->pLibspdmContext, pSpdm->sessionId, 1180 bSingleDirection); 1181 1182 if (ret != LIBSPDM_STATUS_SUCCESS) 1183 { 1184 NV_PRINTF(LEVEL_ERROR, "Key Update (single direction(0x%x)) failed, ret(0x%x), triggerId = (0x%x).\n", 1185 bSingleDirection, ret, keyUpdateTriggerId); 1186 return NV_ERR_GENERIC; 1187 } 1188 1189 if (!nvspdm_check_and_clear_libspdm_assert()) 1190 { 1191 // libspdm detects assert/error in key update process, need to return error. 1192 NV_PRINTF(LEVEL_ERROR, "SPDM: spdmCheckAndExecuteKeyUpdate() assert !! \n"); 1193 DBG_BREAKPOINT(); 1194 return NV_ERR_INVALID_STATE; 1195 } 1196 1197 NV_PRINTF(LEVEL_INFO, "SPDM: Key update successfully, triggerId = (0x%x)!\n", keyUpdateTriggerId); 1198 pSpdm->sessionMsgCount = 0; 1199 } 1200 } 1201 else 1202 { 1203 return NV_ERR_INVALID_ARGUMENT; 1204 } 1205 1206 1207 return NV_OK; 1208 } 1209 1210 NV_STATUS 1211 spdmRegisterForHeartbeats_GH100 1212 ( 1213 OBJGPU *pGpu, 1214 Spdm *pSpdm, 1215 NvU32 heartbeatPeriodSec 1216 ) 1217 { 1218 NV_STATUS status = NV_OK; 1219 OBJTMR *pTmr; 1220 RMTIMEOUT timeout; 1221 NV2080_CTRL_INTERNAL_SPDM_PARTITION_PARAMS params; 1222 1223 // Basic parameter validation, make sure we are in a session 1224 if (pGpu == NULL || pSpdm == NULL || pSpdm->sessionId == INVALID_SESSION_ID) 1225 { 1226 return NV_ERR_NOT_READY; 1227 } 1228 // Set minimum value to ensure we don't trigger unexpected behavior with small timer values. 1229 else if (heartbeatPeriodSec < SPDM_DEFAULT_HEARTBEAT_PERIOD_IN_SEC) 1230 { 1231 return NV_ERR_INVALID_ARGUMENT; 1232 } 1233 1234 pTmr = GPU_GET_TIMER(pGpu); 1235 1236 // Create the timer event and schedule the first heartbeat callback 1237 status = tmrEventCreate(pTmr, &pSpdm->pHeartbeatEvent, _spdmTriggerHeartbeat, pSpdm, TMR_FLAGS_NONE); 1238 if (status != NV_OK) 1239 { 1240 return status; 1241 } 1242 1243 pSpdm->heartbeatPeriodSec = heartbeatPeriodSec; 1244 status = tmrEventScheduleRelSec(pTmr, pSpdm->pHeartbeatEvent, pSpdm->heartbeatPeriodSec); 1245 1246 // Tell GSP-RM to start expecting heartbeats. 1247 portMemSet(¶ms, 0, sizeof(params)); 1248 params.cmd.cmdType = RM_GSP_SPDM_CMD_ID_CC_HEARTBEAT_CTRL; 1249 params.cmd.ccHeartbeatCtrl.bEnable = NV_TRUE; 1250 1251 gpuSetTimeout(pGpu, GPU_TIMEOUT_DEFAULT, &timeout, 0); 1252 status = spdmCtrlSpdmPartition(pGpu, ¶ms); 1253 if (status != NV_OK) 1254 { 1255 NV_PRINTF(LEVEL_ERROR, "SPDM: Send/receive error in CC_HEARTBEAT_CTRL command! Status = 0x%0x\n", status); 1256 return status; 1257 } 1258 1259 // Perform basic validation of header returned. 1260 status = params.msg.status; 1261 if (status != NV_OK) 1262 { 1263 NV_PRINTF(LEVEL_ERROR, "SPDM: RPC returned failure in CC_HEARTBEAT_CTRL command! status = 0x%0x\n", 1264 status); 1265 DBG_BREAKPOINT(); 1266 return status; 1267 } 1268 1269 return status; 1270 } 1271 1272 NV_STATUS 1273 spdmUnregisterFromHeartbeats_GH100 1274 ( 1275 OBJGPU *pGpu, 1276 Spdm *pSpdm 1277 ) 1278 { 1279 NV_STATUS status = NV_OK; 1280 1281 OBJTMR *pTmr = GPU_GET_TIMER(pGpu); 1282 RMTIMEOUT timeout; 1283 NV2080_CTRL_INTERNAL_SPDM_PARTITION_PARAMS params; 1284 1285 if (pSpdm->pHeartbeatEvent == NULL) 1286 { 1287 // No timer exists, we never started sending heartbeats. 1288 return NV_OK; 1289 } 1290 1291 // Tell GSP-RM to stop expecting heartbeats. 1292 portMemSet(¶ms, 0, sizeof(params)); 1293 params.cmd.cmdType = RM_GSP_SPDM_CMD_ID_CC_HEARTBEAT_CTRL; 1294 params.cmd.ccHeartbeatCtrl.bEnable = NV_FALSE; 1295 1296 gpuSetTimeout(pGpu, GPU_TIMEOUT_DEFAULT, &timeout, 0); 1297 status = spdmCtrlSpdmPartition(pGpu, ¶ms); 1298 if (status != NV_OK) 1299 { 1300 NV_PRINTF(LEVEL_ERROR, "SPDM: Send/receive error in CC_HEARTBEAT_CTRL command! Status = 0x%0x\n", status); 1301 goto ErrorExit; 1302 } 1303 1304 // Perform basic validation of header returned. 1305 status = params.msg.status; 1306 if (status != NV_OK) 1307 { 1308 NV_PRINTF(LEVEL_ERROR, "SPDM: RPC returned failure in CC_HEARTBEAT_CTRL command! status = 0x%0x\n", 1309 status); 1310 DBG_BREAKPOINT(); 1311 goto ErrorExit; 1312 } 1313 1314 ErrorExit: 1315 // In any case, cancel any further heartbeats that might occur. Handles NULL gracefully. 1316 tmrEventCancel(pTmr, pSpdm->pHeartbeatEvent); 1317 tmrEventDestroy(pTmr, pSpdm->pHeartbeatEvent); 1318 pSpdm->pHeartbeatEvent = NULL; 1319 pSpdm->heartbeatPeriodSec = 0; 1320 1321 return status; 1322 } 1323