2 PTP (Platform TPM Profile) CRB (Command Response Buffer) interface used by dTPM2.0 library.
4 Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
5 Copyright (c), Microsoft Corporation.
6 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include <IndustryStandard/Tpm20.h>
12 #include <Library/BaseLib.h>
13 #include <Library/BaseMemoryLib.h>
14 #include <Library/IoLib.h>
15 #include <Library/TimerLib.h>
16 #include <Library/DebugLib.h>
17 #include <Library/Tpm2DeviceLib.h>
18 #include <Library/PcdLib.h>
20 #include <IndustryStandard/TpmPtp.h>
21 #include <IndustryStandard/TpmTis.h>
23 #include "Tpm2DeviceLibDTpm.h"
26 // Execution of the command may take from several seconds to minutes for certain
27 // commands, such as key generation.
29 #define PTP_TIMEOUT_MAX (90000 * 1000) // 90s
32 // Max TPM command/response length
34 #define TPMCMDBUFLENGTH 0x500
37 Check whether TPM PTP register exist.
39 @param[in] Reg Pointer to PTP register.
41 @retval TRUE TPM PTP exists.
42 @retval FALSE TPM PTP is not found.
51 RegRead
= MmioRead8 ((UINTN
)Reg
);
52 if (RegRead
== 0xFF) {
63 Check whether the value of a TPM chip register satisfies the input BIT setting.
65 @param[in] Register Address port of register to be checked.
66 @param[in] BitSet Check these data bits are set.
67 @param[in] BitClear Check these data bits are clear.
68 @param[in] TimeOut The max wait time (unit MicroSecond) when checking register.
70 @retval EFI_SUCCESS The register satisfies the check bit.
71 @retval EFI_TIMEOUT The register can't run into the expected status in time.
74 PtpCrbWaitRegisterBits (
84 for (WaitTime
= 0; WaitTime
< TimeOut
; WaitTime
+= 30) {
85 RegRead
= MmioRead32 ((UINTN
)Register
);
86 if (((RegRead
& BitSet
) == BitSet
) && ((RegRead
& BitClear
) == 0)) {
90 MicroSecondDelay (30);
97 Get the control of TPM chip.
99 @param[in] CrbReg Pointer to CRB register.
101 @retval EFI_SUCCESS Get the control of TPM chip.
102 @retval EFI_INVALID_PARAMETER CrbReg is NULL.
103 @retval EFI_NOT_FOUND TPM chip doesn't exit.
104 @retval EFI_TIMEOUT Can't get the TPM control in time.
107 PtpCrbRequestUseTpm (
108 IN PTP_CRB_REGISTERS_PTR CrbReg
113 if (!Tpm2IsPtpPresence (CrbReg
)) {
114 return EFI_NOT_FOUND
;
117 MmioWrite32 ((UINTN
)&CrbReg
->LocalityControl
, PTP_CRB_LOCALITY_CONTROL_REQUEST_ACCESS
);
118 Status
= PtpCrbWaitRegisterBits (
119 &CrbReg
->LocalityStatus
,
120 PTP_CRB_LOCALITY_STATUS_GRANTED
,
128 Send a command to TPM for execution and return response data.
130 @param[in] CrbReg TPM register space base address.
131 @param[in] BufferIn Buffer for command data.
132 @param[in] SizeIn Size of command data.
133 @param[in, out] BufferOut Buffer for response data.
134 @param[in, out] SizeOut Size of response data.
136 @retval EFI_SUCCESS Operation completed successfully.
137 @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small.
138 @retval EFI_DEVICE_ERROR Unexpected device behavior.
139 @retval EFI_UNSUPPORTED Unsupported TPM version
144 IN PTP_CRB_REGISTERS_PTR CrbReg
,
147 IN OUT UINT8
*BufferOut
,
148 IN OUT UINT32
*SizeOut
160 DEBUG ((DEBUG_VERBOSE
, "PtpCrbTpmCommand Send - "));
161 if (SizeIn
> 0x100) {
167 for (Index
= 0; Index
< DebugSize
; Index
++) {
168 DEBUG ((DEBUG_VERBOSE
, "%02x ", BufferIn
[Index
]));
171 if (DebugSize
!= SizeIn
) {
172 DEBUG ((DEBUG_VERBOSE
, "...... "));
173 for (Index
= SizeIn
- 0x20; Index
< SizeIn
; Index
++) {
174 DEBUG ((DEBUG_VERBOSE
, "%02x ", BufferIn
[Index
]));
178 DEBUG ((DEBUG_VERBOSE
, "\n"));
184 // if CapCRbIdelByPass == 0, enforce Idle state before sending command
186 if ((GetCachedIdleByPass () == 0) && ((MmioRead32 ((UINTN
)&CrbReg
->CrbControlStatus
) & PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE
) == 0)) {
187 Status
= PtpCrbWaitRegisterBits (
188 &CrbReg
->CrbControlStatus
,
189 PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE
,
193 if (EFI_ERROR (Status
)) {
195 // Try to goIdle to recover TPM
197 Status
= EFI_DEVICE_ERROR
;
204 // Ready is any time the TPM is ready to receive a command, following a write
205 // of 1 by software to Request.cmdReady, as indicated by the Status field
206 // being cleared to 0.
208 MmioWrite32 ((UINTN
)&CrbReg
->CrbControlRequest
, PTP_CRB_CONTROL_AREA_REQUEST_COMMAND_READY
);
209 Status
= PtpCrbWaitRegisterBits (
210 &CrbReg
->CrbControlRequest
,
212 PTP_CRB_CONTROL_AREA_REQUEST_COMMAND_READY
,
215 if (EFI_ERROR (Status
)) {
216 Status
= EFI_DEVICE_ERROR
;
220 Status
= PtpCrbWaitRegisterBits (
221 &CrbReg
->CrbControlStatus
,
223 PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE
,
226 if (EFI_ERROR (Status
)) {
227 Status
= EFI_DEVICE_ERROR
;
233 // Command Reception occurs following a Ready state between the write of the
234 // first byte of a command to the Command Buffer and the receipt of a write
237 for (Index
= 0; Index
< SizeIn
; Index
++) {
238 MmioWrite8 ((UINTN
)&CrbReg
->CrbDataBuffer
[Index
], BufferIn
[Index
]);
241 MmioWrite32 ((UINTN
)&CrbReg
->CrbControlCommandAddressHigh
, (UINT32
)RShiftU64 ((UINTN
)CrbReg
->CrbDataBuffer
, 32));
242 MmioWrite32 ((UINTN
)&CrbReg
->CrbControlCommandAddressLow
, (UINT32
)(UINTN
)CrbReg
->CrbDataBuffer
);
243 MmioWrite32 ((UINTN
)&CrbReg
->CrbControlCommandSize
, sizeof (CrbReg
->CrbDataBuffer
));
245 MmioWrite64 ((UINTN
)&CrbReg
->CrbControlResponseAddrss
, (UINT32
)(UINTN
)CrbReg
->CrbDataBuffer
);
246 MmioWrite32 ((UINTN
)&CrbReg
->CrbControlResponseSize
, sizeof (CrbReg
->CrbDataBuffer
));
250 // Command Execution occurs after receipt of a 1 to Start and the TPM
251 // clearing Start to 0.
253 MmioWrite32 ((UINTN
)&CrbReg
->CrbControlStart
, PTP_CRB_CONTROL_START
);
254 Status
= PtpCrbWaitRegisterBits (
255 &CrbReg
->CrbControlStart
,
257 PTP_CRB_CONTROL_START
,
260 if (EFI_ERROR (Status
)) {
262 // Command Completion check timeout. Cancel the currently executing command by writing TPM_CRB_CTRL_CANCEL,
263 // Expect TPM_RC_CANCELLED or successfully completed response.
265 MmioWrite32 ((UINTN
)&CrbReg
->CrbControlCancel
, PTP_CRB_CONTROL_CANCEL
);
266 Status
= PtpCrbWaitRegisterBits (
267 &CrbReg
->CrbControlStart
,
269 PTP_CRB_CONTROL_START
,
272 MmioWrite32 ((UINTN
)&CrbReg
->CrbControlCancel
, 0);
274 if (EFI_ERROR (Status
)) {
276 // Still in Command Execution state. Try to goIdle, the behavior is agnostic.
278 Status
= EFI_DEVICE_ERROR
;
285 // Command Completion occurs after completion of a command (indicated by the
286 // TPM clearing TPM_CRB_CTRL_Start_x to 0) and before a write of a 1 by the
287 // software to Request.goIdle.
291 // Get response data header
293 for (Index
= 0; Index
< sizeof (TPM2_RESPONSE_HEADER
); Index
++) {
294 BufferOut
[Index
] = MmioRead8 ((UINTN
)&CrbReg
->CrbDataBuffer
[Index
]);
298 DEBUG ((DEBUG_VERBOSE
, "PtpCrbTpmCommand ReceiveHeader - "));
299 for (Index
= 0; Index
< sizeof (TPM2_RESPONSE_HEADER
); Index
++) {
300 DEBUG ((DEBUG_VERBOSE
, "%02x ", BufferOut
[Index
]));
303 DEBUG ((DEBUG_VERBOSE
, "\n"));
306 // Check the response data header (tag, parasize and returncode)
308 CopyMem (&Data16
, BufferOut
, sizeof (UINT16
));
309 // TPM2 should not use this RSP_COMMAND
310 if (SwapBytes16 (Data16
) == TPM_ST_RSP_COMMAND
) {
311 DEBUG ((DEBUG_ERROR
, "TPM2: TPM_ST_RSP error - %x\n", TPM_ST_RSP_COMMAND
));
312 Status
= EFI_UNSUPPORTED
;
316 CopyMem (&Data32
, (BufferOut
+ 2), sizeof (UINT32
));
317 TpmOutSize
= SwapBytes32 (Data32
);
318 if (*SizeOut
< TpmOutSize
) {
320 // Command completed, but buffer is not enough
322 Status
= EFI_BUFFER_TOO_SMALL
;
326 *SizeOut
= TpmOutSize
;
328 // Continue reading the remaining data
330 for (Index
= sizeof (TPM2_RESPONSE_HEADER
); Index
< TpmOutSize
; Index
++) {
331 BufferOut
[Index
] = MmioRead8 ((UINTN
)&CrbReg
->CrbDataBuffer
[Index
]);
335 DEBUG ((DEBUG_VERBOSE
, "PtpCrbTpmCommand Receive - "));
336 for (Index
= 0; Index
< TpmOutSize
; Index
++) {
337 DEBUG ((DEBUG_VERBOSE
, "%02x ", BufferOut
[Index
]));
340 DEBUG ((DEBUG_VERBOSE
, "\n"));
345 // Goto Ready State if command is completed successfully and TPM support IdleBypass
346 // If not supported. flow down to GoIdle
348 if (GetCachedIdleByPass () == 1) {
349 MmioWrite32 ((UINTN
)&CrbReg
->CrbControlRequest
, PTP_CRB_CONTROL_AREA_REQUEST_COMMAND_READY
);
354 // Do not wait for state transition for TIMEOUT_C
355 // This function will try to wait 2 TIMEOUT_C at the beginning in next call.
360 // Return to Idle state by setting TPM_CRB_CTRL_STS_x.Status.goIdle to 1.
362 MmioWrite32 ((UINTN
)&CrbReg
->CrbControlRequest
, PTP_CRB_CONTROL_AREA_REQUEST_GO_IDLE
);
365 // Only enforce Idle state transition if execution fails when CRBIdleBypass==1
366 // Leave regular Idle delay at the beginning of next command execution
368 if (GetCachedIdleByPass () == 1) {
369 Status
= PtpCrbWaitRegisterBits (
370 &CrbReg
->CrbControlStatus
,
371 PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE
,
381 Send a command to TPM for execution and return response data.
383 @param[in] TisReg TPM register space base address.
384 @param[in] BufferIn Buffer for command data.
385 @param[in] SizeIn Size of command data.
386 @param[in, out] BufferOut Buffer for response data.
387 @param[in, out] SizeOut Size of response data.
389 @retval EFI_SUCCESS Operation completed successfully.
390 @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small.
391 @retval EFI_DEVICE_ERROR Unexpected device behavior.
392 @retval EFI_UNSUPPORTED Unsupported TPM version
397 IN TIS_PC_REGISTERS_PTR TisReg
,
400 IN OUT UINT8
*BufferOut
,
401 IN OUT UINT32
*SizeOut
405 Get the control of TPM chip by sending requestUse command TIS_PC_ACC_RQUUSE
406 to ACCESS Register in the time of default TIS_TIMEOUT_A.
408 @param[in] TisReg Pointer to TIS register.
410 @retval EFI_SUCCESS Get the control of TPM chip.
411 @retval EFI_INVALID_PARAMETER TisReg is NULL.
412 @retval EFI_NOT_FOUND TPM chip doesn't exit.
413 @retval EFI_TIMEOUT Can't get the TPM control in time.
417 IN TIS_PC_REGISTERS_PTR TisReg
421 Return PTP interface type.
423 @param[in] Register Pointer to PTP register.
425 @return PTP interface type.
427 TPM2_PTP_INTERFACE_TYPE
428 Tpm2GetPtpInterface (
432 PTP_CRB_INTERFACE_IDENTIFIER InterfaceId
;
433 PTP_FIFO_INTERFACE_CAPABILITY InterfaceCapability
;
435 if (!Tpm2IsPtpPresence (Register
)) {
436 return Tpm2PtpInterfaceMax
;
440 // Check interface id
442 InterfaceId
.Uint32
= MmioRead32 ((UINTN
)&((PTP_CRB_REGISTERS
*)Register
)->InterfaceId
);
443 InterfaceCapability
.Uint32
= MmioRead32 ((UINTN
)&((PTP_FIFO_REGISTERS
*)Register
)->InterfaceCapability
);
445 if ((InterfaceId
.Bits
.InterfaceType
== PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_CRB
) &&
446 (InterfaceId
.Bits
.InterfaceVersion
== PTP_INTERFACE_IDENTIFIER_INTERFACE_VERSION_CRB
) &&
447 (InterfaceId
.Bits
.CapCRB
!= 0))
449 return Tpm2PtpInterfaceCrb
;
452 if ((InterfaceId
.Bits
.InterfaceType
== PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_FIFO
) &&
453 (InterfaceId
.Bits
.InterfaceVersion
== PTP_INTERFACE_IDENTIFIER_INTERFACE_VERSION_FIFO
) &&
454 (InterfaceId
.Bits
.CapFIFO
!= 0) &&
455 (InterfaceCapability
.Bits
.InterfaceVersion
== INTERFACE_CAPABILITY_INTERFACE_VERSION_PTP
))
457 return Tpm2PtpInterfaceFifo
;
460 return Tpm2PtpInterfaceTis
;
464 Return PTP CRB interface IdleByPass state.
466 @param[in] Register Pointer to PTP register.
468 @return PTP CRB interface IdleByPass state.
475 PTP_CRB_INTERFACE_IDENTIFIER InterfaceId
;
478 // Check interface id
480 InterfaceId
.Uint32
= MmioRead32 ((UINTN
)&((PTP_CRB_REGISTERS
*)Register
)->InterfaceId
);
482 return (UINT8
)(InterfaceId
.Bits
.CapCRBIdleBypass
);
486 Dump PTP register information.
488 @param[in] Register Pointer to PTP register.
495 PTP_CRB_INTERFACE_IDENTIFIER InterfaceId
;
496 PTP_FIFO_INTERFACE_CAPABILITY InterfaceCapability
;
501 TPM2_PTP_INTERFACE_TYPE PtpInterface
;
503 if (!Tpm2IsPtpPresence (Register
)) {
507 InterfaceId
.Uint32
= MmioRead32 ((UINTN
)&((PTP_CRB_REGISTERS
*)Register
)->InterfaceId
);
508 InterfaceCapability
.Uint32
= MmioRead32 ((UINTN
)&((PTP_FIFO_REGISTERS
*)Register
)->InterfaceCapability
);
509 StatusEx
= MmioRead8 ((UINTN
)&((PTP_FIFO_REGISTERS
*)Register
)->StatusEx
);
512 // Dump InterfaceId Register for PTP
514 DEBUG ((DEBUG_INFO
, "InterfaceId - 0x%08x\n", InterfaceId
.Uint32
));
515 DEBUG ((DEBUG_INFO
, " InterfaceType - 0x%02x\n", InterfaceId
.Bits
.InterfaceType
));
516 if (InterfaceId
.Bits
.InterfaceType
!= PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_TIS
) {
517 DEBUG ((DEBUG_INFO
, " InterfaceVersion - 0x%02x\n", InterfaceId
.Bits
.InterfaceVersion
));
518 DEBUG ((DEBUG_INFO
, " CapFIFO - 0x%x\n", InterfaceId
.Bits
.CapFIFO
));
519 DEBUG ((DEBUG_INFO
, " CapCRB - 0x%x\n", InterfaceId
.Bits
.CapCRB
));
523 // Dump Capability Register for TIS and FIFO
525 DEBUG ((DEBUG_INFO
, "InterfaceCapability - 0x%08x\n", InterfaceCapability
.Uint32
));
526 if ((InterfaceId
.Bits
.InterfaceType
== PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_TIS
) ||
527 (InterfaceId
.Bits
.InterfaceType
== PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_FIFO
))
529 DEBUG ((DEBUG_INFO
, " InterfaceVersion - 0x%x\n", InterfaceCapability
.Bits
.InterfaceVersion
));
533 // Dump StatusEx Register for PTP FIFO
535 DEBUG ((DEBUG_INFO
, "StatusEx - 0x%02x\n", StatusEx
));
536 if (InterfaceCapability
.Bits
.InterfaceVersion
== INTERFACE_CAPABILITY_INTERFACE_VERSION_PTP
) {
537 DEBUG ((DEBUG_INFO
, " TpmFamily - 0x%x\n", (StatusEx
& PTP_FIFO_STS_EX_TPM_FAMILY
) >> PTP_FIFO_STS_EX_TPM_FAMILY_OFFSET
));
543 PtpInterface
= GetCachedPtpInterface ();
544 DEBUG ((DEBUG_INFO
, "PtpInterface - %x\n", PtpInterface
));
545 switch (PtpInterface
) {
546 case Tpm2PtpInterfaceCrb
:
547 Vid
= MmioRead16 ((UINTN
)&((PTP_CRB_REGISTERS
*)Register
)->Vid
);
548 Did
= MmioRead16 ((UINTN
)&((PTP_CRB_REGISTERS
*)Register
)->Did
);
549 Rid
= (UINT8
)InterfaceId
.Bits
.Rid
;
551 case Tpm2PtpInterfaceFifo
:
552 case Tpm2PtpInterfaceTis
:
553 Vid
= MmioRead16 ((UINTN
)&((PTP_FIFO_REGISTERS
*)Register
)->Vid
);
554 Did
= MmioRead16 ((UINTN
)&((PTP_FIFO_REGISTERS
*)Register
)->Did
);
555 Rid
= MmioRead8 ((UINTN
)&((PTP_FIFO_REGISTERS
*)Register
)->Rid
);
561 DEBUG ((DEBUG_INFO
, "VID - 0x%04x\n", Vid
));
562 DEBUG ((DEBUG_INFO
, "DID - 0x%04x\n", Did
));
563 DEBUG ((DEBUG_INFO
, "RID - 0x%02x\n", Rid
));
567 This service enables the sending of commands to the TPM2.
569 @param[in] InputParameterBlockSize Size of the TPM2 input parameter block.
570 @param[in] InputParameterBlock Pointer to the TPM2 input parameter block.
571 @param[in,out] OutputParameterBlockSize Size of the TPM2 output parameter block.
572 @param[in] OutputParameterBlock Pointer to the TPM2 output parameter block.
574 @retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received.
575 @retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device.
576 @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small.
581 IN UINT32 InputParameterBlockSize
,
582 IN UINT8
*InputParameterBlock
,
583 IN OUT UINT32
*OutputParameterBlockSize
,
584 IN UINT8
*OutputParameterBlock
587 TPM2_PTP_INTERFACE_TYPE PtpInterface
;
589 PtpInterface
= GetCachedPtpInterface ();
590 switch (PtpInterface
) {
591 case Tpm2PtpInterfaceCrb
:
592 return PtpCrbTpmCommand (
593 (PTP_CRB_REGISTERS_PTR
)(UINTN
)PcdGet64 (PcdTpmBaseAddress
),
595 InputParameterBlockSize
,
596 OutputParameterBlock
,
597 OutputParameterBlockSize
599 case Tpm2PtpInterfaceFifo
:
600 case Tpm2PtpInterfaceTis
:
601 return Tpm2TisTpmCommand (
602 (TIS_PC_REGISTERS_PTR
)(UINTN
)PcdGet64 (PcdTpmBaseAddress
),
604 InputParameterBlockSize
,
605 OutputParameterBlock
,
606 OutputParameterBlockSize
609 return EFI_NOT_FOUND
;
614 This service requests use TPM2.
616 @retval EFI_SUCCESS Get the control of TPM2 chip.
617 @retval EFI_NOT_FOUND TPM2 not found.
618 @retval EFI_DEVICE_ERROR Unexpected device behavior.
626 TPM2_PTP_INTERFACE_TYPE PtpInterface
;
628 PtpInterface
= GetCachedPtpInterface ();
629 switch (PtpInterface
) {
630 case Tpm2PtpInterfaceCrb
:
631 return PtpCrbRequestUseTpm ((PTP_CRB_REGISTERS_PTR
)(UINTN
)PcdGet64 (PcdTpmBaseAddress
));
632 case Tpm2PtpInterfaceFifo
:
633 case Tpm2PtpInterfaceTis
:
634 return TisPcRequestUseTpm ((TIS_PC_REGISTERS_PTR
)(UINTN
)PcdGet64 (PcdTpmBaseAddress
));
636 return EFI_NOT_FOUND
;