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