2 PTP (Platform TPM Profile) CRB (Command Response Buffer) interface used by dTPM2.0 library.
4 Copyright (c) 2015 - 2021, 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 // Max retry count according to Spec TCG PC Client Device Driver Design Principles
38 // for TPM2.0, Version 1.1, Revision 0.04, Section 7.2.1
40 #define RETRY_CNT_MAX 3
43 Check whether TPM PTP register exist.
45 @param[in] Reg Pointer to PTP register.
47 @retval TRUE TPM PTP exists.
48 @retval FALSE TPM PTP is not found.
57 RegRead
= MmioRead8 ((UINTN
)Reg
);
58 if (RegRead
== 0xFF) {
69 Check whether the value of a TPM chip register satisfies the input BIT setting.
71 @param[in] Register Address port of register to be checked.
72 @param[in] BitSet Check these data bits are set.
73 @param[in] BitClear Check these data bits are clear.
74 @param[in] TimeOut The max wait time (unit MicroSecond) when checking register.
76 @retval EFI_SUCCESS The register satisfies the check bit.
77 @retval EFI_TIMEOUT The register can't run into the expected status in time.
80 PtpCrbWaitRegisterBits (
90 for (WaitTime
= 0; WaitTime
< TimeOut
; WaitTime
+= 30) {
91 RegRead
= MmioRead32 ((UINTN
)Register
);
92 if (((RegRead
& BitSet
) == BitSet
) && ((RegRead
& BitClear
) == 0)) {
96 MicroSecondDelay (30);
103 Get the control of TPM chip.
105 @param[in] CrbReg Pointer to CRB register.
107 @retval EFI_SUCCESS Get the control of TPM chip.
108 @retval EFI_INVALID_PARAMETER CrbReg is NULL.
109 @retval EFI_NOT_FOUND TPM chip doesn't exit.
110 @retval EFI_TIMEOUT Can't get the TPM control in time.
113 PtpCrbRequestUseTpm (
114 IN PTP_CRB_REGISTERS_PTR CrbReg
119 if (!Tpm2IsPtpPresence (CrbReg
)) {
120 return EFI_NOT_FOUND
;
123 MmioWrite32 ((UINTN
)&CrbReg
->LocalityControl
, PTP_CRB_LOCALITY_CONTROL_REQUEST_ACCESS
);
124 Status
= PtpCrbWaitRegisterBits (
125 &CrbReg
->LocalityStatus
,
126 PTP_CRB_LOCALITY_STATUS_GRANTED
,
134 Send a command to TPM for execution and return response data.
136 @param[in] CrbReg TPM register space base address.
137 @param[in] BufferIn Buffer for command data.
138 @param[in] SizeIn Size of command data.
139 @param[in, out] BufferOut Buffer for response data.
140 @param[in, out] SizeOut Size of response data.
142 @retval EFI_SUCCESS Operation completed successfully.
143 @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small.
144 @retval EFI_DEVICE_ERROR Unexpected device behavior.
145 @retval EFI_UNSUPPORTED Unsupported TPM version
150 IN PTP_CRB_REGISTERS_PTR CrbReg
,
153 IN OUT UINT8
*BufferOut
,
154 IN OUT UINT32
*SizeOut
167 DEBUG ((DEBUG_VERBOSE
, "PtpCrbTpmCommand Send - "));
168 if (SizeIn
> 0x100) {
174 for (Index
= 0; Index
< DebugSize
; Index
++) {
175 DEBUG ((DEBUG_VERBOSE
, "%02x ", BufferIn
[Index
]));
178 if (DebugSize
!= SizeIn
) {
179 DEBUG ((DEBUG_VERBOSE
, "...... "));
180 for (Index
= SizeIn
- 0x20; Index
< SizeIn
; Index
++) {
181 DEBUG ((DEBUG_VERBOSE
, "%02x ", BufferIn
[Index
]));
185 DEBUG ((DEBUG_VERBOSE
, "\n"));
193 // if CapCRbIdelByPass == 0, enforce Idle state before sending command
195 if ((GetCachedIdleByPass () == 0) && ((MmioRead32 ((UINTN
)&CrbReg
->CrbControlStatus
) & PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE
) == 0)) {
196 Status
= PtpCrbWaitRegisterBits (
197 &CrbReg
->CrbControlStatus
,
198 PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE
,
202 if (EFI_ERROR (Status
)) {
204 if (RetryCnt
< RETRY_CNT_MAX
) {
205 MmioWrite32 ((UINTN
)&CrbReg
->CrbControlRequest
, PTP_CRB_CONTROL_AREA_REQUEST_GO_IDLE
);
209 // Try to goIdle to recover TPM
211 Status
= EFI_DEVICE_ERROR
;
219 // Ready is any time the TPM is ready to receive a command, following a write
220 // of 1 by software to Request.cmdReady, as indicated by the Status field
221 // being cleared to 0.
223 MmioWrite32 ((UINTN
)&CrbReg
->CrbControlRequest
, PTP_CRB_CONTROL_AREA_REQUEST_COMMAND_READY
);
224 Status
= PtpCrbWaitRegisterBits (
225 &CrbReg
->CrbControlRequest
,
227 PTP_CRB_CONTROL_AREA_REQUEST_COMMAND_READY
,
230 if (EFI_ERROR (Status
)) {
232 if (RetryCnt
< RETRY_CNT_MAX
) {
233 MmioWrite32 ((UINTN
)&CrbReg
->CrbControlRequest
, PTP_CRB_CONTROL_AREA_REQUEST_GO_IDLE
);
236 Status
= EFI_DEVICE_ERROR
;
241 Status
= PtpCrbWaitRegisterBits (
242 &CrbReg
->CrbControlStatus
,
244 PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE
,
247 if (EFI_ERROR (Status
)) {
249 if (RetryCnt
< RETRY_CNT_MAX
) {
250 MmioWrite32 ((UINTN
)&CrbReg
->CrbControlRequest
, PTP_CRB_CONTROL_AREA_REQUEST_GO_IDLE
);
253 Status
= EFI_DEVICE_ERROR
;
263 // Command Reception occurs following a Ready state between the write of the
264 // first byte of a command to the Command Buffer and the receipt of a write
267 for (Index
= 0; Index
< SizeIn
; Index
++) {
268 MmioWrite8 ((UINTN
)&CrbReg
->CrbDataBuffer
[Index
], BufferIn
[Index
]);
271 MmioWrite32 ((UINTN
)&CrbReg
->CrbControlCommandAddressHigh
, (UINT32
)RShiftU64 ((UINTN
)CrbReg
->CrbDataBuffer
, 32));
272 MmioWrite32 ((UINTN
)&CrbReg
->CrbControlCommandAddressLow
, (UINT32
)(UINTN
)CrbReg
->CrbDataBuffer
);
273 MmioWrite32 ((UINTN
)&CrbReg
->CrbControlCommandSize
, sizeof (CrbReg
->CrbDataBuffer
));
275 MmioWrite64 ((UINTN
)&CrbReg
->CrbControlResponseAddrss
, (UINT32
)(UINTN
)CrbReg
->CrbDataBuffer
);
276 MmioWrite32 ((UINTN
)&CrbReg
->CrbControlResponseSize
, sizeof (CrbReg
->CrbDataBuffer
));
280 // Command Execution occurs after receipt of a 1 to Start and the TPM
281 // clearing Start to 0.
283 MmioWrite32 ((UINTN
)&CrbReg
->CrbControlStart
, PTP_CRB_CONTROL_START
);
284 Status
= PtpCrbWaitRegisterBits (
285 &CrbReg
->CrbControlStart
,
287 PTP_CRB_CONTROL_START
,
290 if (EFI_ERROR (Status
)) {
292 // Command Completion check timeout. Cancel the currently executing command by writing TPM_CRB_CTRL_CANCEL,
293 // Expect TPM_RC_CANCELLED or successfully completed response.
295 MmioWrite32 ((UINTN
)&CrbReg
->CrbControlCancel
, PTP_CRB_CONTROL_CANCEL
);
296 Status
= PtpCrbWaitRegisterBits (
297 &CrbReg
->CrbControlStart
,
299 PTP_CRB_CONTROL_START
,
302 MmioWrite32 ((UINTN
)&CrbReg
->CrbControlCancel
, 0);
304 if (EFI_ERROR (Status
)) {
306 // Still in Command Execution state. Try to goIdle, the behavior is agnostic.
308 Status
= EFI_DEVICE_ERROR
;
315 // Command Completion occurs after completion of a command (indicated by the
316 // TPM clearing TPM_CRB_CTRL_Start_x to 0) and before a write of a 1 by the
317 // software to Request.goIdle.
321 // Get response data header
323 for (Index
= 0; Index
< sizeof (TPM2_RESPONSE_HEADER
); Index
++) {
324 BufferOut
[Index
] = MmioRead8 ((UINTN
)&CrbReg
->CrbDataBuffer
[Index
]);
328 DEBUG ((DEBUG_VERBOSE
, "PtpCrbTpmCommand ReceiveHeader - "));
329 for (Index
= 0; Index
< sizeof (TPM2_RESPONSE_HEADER
); Index
++) {
330 DEBUG ((DEBUG_VERBOSE
, "%02x ", BufferOut
[Index
]));
333 DEBUG ((DEBUG_VERBOSE
, "\n"));
336 // Check the response data header (tag, parasize and returncode)
338 CopyMem (&Data16
, BufferOut
, sizeof (UINT16
));
339 // TPM2 should not use this RSP_COMMAND
340 if (SwapBytes16 (Data16
) == TPM_ST_RSP_COMMAND
) {
341 DEBUG ((DEBUG_ERROR
, "TPM2: TPM_ST_RSP error - %x\n", TPM_ST_RSP_COMMAND
));
342 Status
= EFI_UNSUPPORTED
;
346 CopyMem (&Data32
, (BufferOut
+ 2), sizeof (UINT32
));
347 TpmOutSize
= SwapBytes32 (Data32
);
348 if (*SizeOut
< TpmOutSize
) {
350 // Command completed, but buffer is not enough
352 Status
= EFI_BUFFER_TOO_SMALL
;
356 *SizeOut
= TpmOutSize
;
358 // Continue reading the remaining data
360 for (Index
= sizeof (TPM2_RESPONSE_HEADER
); Index
< TpmOutSize
; Index
++) {
361 BufferOut
[Index
] = MmioRead8 ((UINTN
)&CrbReg
->CrbDataBuffer
[Index
]);
365 DEBUG ((DEBUG_VERBOSE
, "PtpCrbTpmCommand Receive - "));
366 for (Index
= 0; Index
< TpmOutSize
; Index
++) {
367 DEBUG ((DEBUG_VERBOSE
, "%02x ", BufferOut
[Index
]));
370 DEBUG ((DEBUG_VERBOSE
, "\n"));
374 // Do not wait for state transition for TIMEOUT_C
375 // This function will try to wait 2 TIMEOUT_C at the beginning in next call.
380 // Return to Idle state by setting TPM_CRB_CTRL_STS_x.Status.goIdle to 1.
382 MmioWrite32 ((UINTN
)&CrbReg
->CrbControlRequest
, PTP_CRB_CONTROL_AREA_REQUEST_GO_IDLE
);
385 // Only enforce Idle state transition if execution fails when CRBIdleBypass==1
386 // Leave regular Idle delay at the beginning of next command execution
388 if (GetCachedIdleByPass () == 1) {
389 Status
= PtpCrbWaitRegisterBits (
390 &CrbReg
->CrbControlStatus
,
391 PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE
,
401 Send a command to TPM for execution and return response data.
403 @param[in] TisReg TPM register space base address.
404 @param[in] BufferIn Buffer for command data.
405 @param[in] SizeIn Size of command data.
406 @param[in, out] BufferOut Buffer for response data.
407 @param[in, out] SizeOut Size of response data.
409 @retval EFI_SUCCESS Operation completed successfully.
410 @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small.
411 @retval EFI_DEVICE_ERROR Unexpected device behavior.
412 @retval EFI_UNSUPPORTED Unsupported TPM version
417 IN TIS_PC_REGISTERS_PTR TisReg
,
420 IN OUT UINT8
*BufferOut
,
421 IN OUT UINT32
*SizeOut
425 Get the control of TPM chip by sending requestUse command TIS_PC_ACC_RQUUSE
426 to ACCESS Register in the time of default TIS_TIMEOUT_A.
428 @param[in] TisReg Pointer to TIS register.
430 @retval EFI_SUCCESS Get the control of TPM chip.
431 @retval EFI_INVALID_PARAMETER TisReg is NULL.
432 @retval EFI_NOT_FOUND TPM chip doesn't exit.
433 @retval EFI_TIMEOUT Can't get the TPM control in time.
437 IN TIS_PC_REGISTERS_PTR TisReg
441 Return PTP interface type.
443 @param[in] Register Pointer to PTP register.
445 @return PTP interface type.
447 TPM2_PTP_INTERFACE_TYPE
448 Tpm2GetPtpInterface (
452 PTP_CRB_INTERFACE_IDENTIFIER InterfaceId
;
453 PTP_FIFO_INTERFACE_CAPABILITY InterfaceCapability
;
455 if (!Tpm2IsPtpPresence (Register
)) {
456 return Tpm2PtpInterfaceMax
;
460 // Check interface id
462 InterfaceId
.Uint32
= MmioRead32 ((UINTN
)&((PTP_CRB_REGISTERS
*)Register
)->InterfaceId
);
463 InterfaceCapability
.Uint32
= MmioRead32 ((UINTN
)&((PTP_FIFO_REGISTERS
*)Register
)->InterfaceCapability
);
465 if ((InterfaceId
.Bits
.InterfaceType
== PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_CRB
) &&
466 (InterfaceId
.Bits
.InterfaceVersion
== PTP_INTERFACE_IDENTIFIER_INTERFACE_VERSION_CRB
) &&
467 (InterfaceId
.Bits
.CapCRB
!= 0))
469 return Tpm2PtpInterfaceCrb
;
472 if ((InterfaceId
.Bits
.InterfaceType
== PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_FIFO
) &&
473 (InterfaceId
.Bits
.InterfaceVersion
== PTP_INTERFACE_IDENTIFIER_INTERFACE_VERSION_FIFO
) &&
474 (InterfaceId
.Bits
.CapFIFO
!= 0) &&
475 (InterfaceCapability
.Bits
.InterfaceVersion
== INTERFACE_CAPABILITY_INTERFACE_VERSION_PTP
))
477 return Tpm2PtpInterfaceFifo
;
480 return Tpm2PtpInterfaceTis
;
484 Return PTP CRB interface IdleByPass state.
486 @param[in] Register Pointer to PTP register.
488 @return PTP CRB interface IdleByPass state.
495 PTP_CRB_INTERFACE_IDENTIFIER InterfaceId
;
498 // Check interface id
500 InterfaceId
.Uint32
= MmioRead32 ((UINTN
)&((PTP_CRB_REGISTERS
*)Register
)->InterfaceId
);
502 return (UINT8
)(InterfaceId
.Bits
.CapCRBIdleBypass
);
506 Dump PTP register information.
508 @param[in] Register Pointer to PTP register.
515 PTP_CRB_INTERFACE_IDENTIFIER InterfaceId
;
516 PTP_FIFO_INTERFACE_CAPABILITY InterfaceCapability
;
521 TPM2_PTP_INTERFACE_TYPE PtpInterface
;
523 if (!Tpm2IsPtpPresence (Register
)) {
527 InterfaceId
.Uint32
= MmioRead32 ((UINTN
)&((PTP_CRB_REGISTERS
*)Register
)->InterfaceId
);
528 InterfaceCapability
.Uint32
= MmioRead32 ((UINTN
)&((PTP_FIFO_REGISTERS
*)Register
)->InterfaceCapability
);
529 StatusEx
= MmioRead8 ((UINTN
)&((PTP_FIFO_REGISTERS
*)Register
)->StatusEx
);
532 // Dump InterfaceId Register for PTP
534 DEBUG ((DEBUG_INFO
, "InterfaceId - 0x%08x\n", InterfaceId
.Uint32
));
535 DEBUG ((DEBUG_INFO
, " InterfaceType - 0x%02x\n", InterfaceId
.Bits
.InterfaceType
));
536 if (InterfaceId
.Bits
.InterfaceType
!= PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_TIS
) {
537 DEBUG ((DEBUG_INFO
, " InterfaceVersion - 0x%02x\n", InterfaceId
.Bits
.InterfaceVersion
));
538 DEBUG ((DEBUG_INFO
, " CapFIFO - 0x%x\n", InterfaceId
.Bits
.CapFIFO
));
539 DEBUG ((DEBUG_INFO
, " CapCRB - 0x%x\n", InterfaceId
.Bits
.CapCRB
));
543 // Dump Capability Register for TIS and FIFO
545 DEBUG ((DEBUG_INFO
, "InterfaceCapability - 0x%08x\n", InterfaceCapability
.Uint32
));
546 if ((InterfaceId
.Bits
.InterfaceType
== PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_TIS
) ||
547 (InterfaceId
.Bits
.InterfaceType
== PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_FIFO
))
549 DEBUG ((DEBUG_INFO
, " InterfaceVersion - 0x%x\n", InterfaceCapability
.Bits
.InterfaceVersion
));
553 // Dump StatusEx Register for PTP FIFO
555 DEBUG ((DEBUG_INFO
, "StatusEx - 0x%02x\n", StatusEx
));
556 if (InterfaceCapability
.Bits
.InterfaceVersion
== INTERFACE_CAPABILITY_INTERFACE_VERSION_PTP
) {
557 DEBUG ((DEBUG_INFO
, " TpmFamily - 0x%x\n", (StatusEx
& PTP_FIFO_STS_EX_TPM_FAMILY
) >> PTP_FIFO_STS_EX_TPM_FAMILY_OFFSET
));
563 PtpInterface
= GetCachedPtpInterface ();
564 DEBUG ((DEBUG_INFO
, "PtpInterface - %x\n", PtpInterface
));
565 switch (PtpInterface
) {
566 case Tpm2PtpInterfaceCrb
:
567 Vid
= MmioRead16 ((UINTN
)&((PTP_CRB_REGISTERS
*)Register
)->Vid
);
568 Did
= MmioRead16 ((UINTN
)&((PTP_CRB_REGISTERS
*)Register
)->Did
);
569 Rid
= (UINT8
)InterfaceId
.Bits
.Rid
;
571 case Tpm2PtpInterfaceFifo
:
572 case Tpm2PtpInterfaceTis
:
573 Vid
= MmioRead16 ((UINTN
)&((PTP_FIFO_REGISTERS
*)Register
)->Vid
);
574 Did
= MmioRead16 ((UINTN
)&((PTP_FIFO_REGISTERS
*)Register
)->Did
);
575 Rid
= MmioRead8 ((UINTN
)&((PTP_FIFO_REGISTERS
*)Register
)->Rid
);
581 DEBUG ((DEBUG_INFO
, "VID - 0x%04x\n", Vid
));
582 DEBUG ((DEBUG_INFO
, "DID - 0x%04x\n", Did
));
583 DEBUG ((DEBUG_INFO
, "RID - 0x%02x\n", Rid
));
587 This service enables the sending of commands to the TPM2.
589 @param[in] InputParameterBlockSize Size of the TPM2 input parameter block.
590 @param[in] InputParameterBlock Pointer to the TPM2 input parameter block.
591 @param[in,out] OutputParameterBlockSize Size of the TPM2 output parameter block.
592 @param[in] OutputParameterBlock Pointer to the TPM2 output parameter block.
594 @retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received.
595 @retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device.
596 @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small.
601 IN UINT32 InputParameterBlockSize
,
602 IN UINT8
*InputParameterBlock
,
603 IN OUT UINT32
*OutputParameterBlockSize
,
604 IN UINT8
*OutputParameterBlock
607 TPM2_PTP_INTERFACE_TYPE PtpInterface
;
609 PtpInterface
= GetCachedPtpInterface ();
610 switch (PtpInterface
) {
611 case Tpm2PtpInterfaceCrb
:
612 return PtpCrbTpmCommand (
613 (PTP_CRB_REGISTERS_PTR
)(UINTN
)PcdGet64 (PcdTpmBaseAddress
),
615 InputParameterBlockSize
,
616 OutputParameterBlock
,
617 OutputParameterBlockSize
619 case Tpm2PtpInterfaceFifo
:
620 case Tpm2PtpInterfaceTis
:
621 return Tpm2TisTpmCommand (
622 (TIS_PC_REGISTERS_PTR
)(UINTN
)PcdGet64 (PcdTpmBaseAddress
),
624 InputParameterBlockSize
,
625 OutputParameterBlock
,
626 OutputParameterBlockSize
629 return EFI_NOT_FOUND
;
634 This service requests use TPM2.
636 @retval EFI_SUCCESS Get the control of TPM2 chip.
637 @retval EFI_NOT_FOUND TPM2 not found.
638 @retval EFI_DEVICE_ERROR Unexpected device behavior.
646 TPM2_PTP_INTERFACE_TYPE PtpInterface
;
648 PtpInterface
= GetCachedPtpInterface ();
649 switch (PtpInterface
) {
650 case Tpm2PtpInterfaceCrb
:
651 return PtpCrbRequestUseTpm ((PTP_CRB_REGISTERS_PTR
)(UINTN
)PcdGet64 (PcdTpmBaseAddress
));
652 case Tpm2PtpInterfaceFifo
:
653 case Tpm2PtpInterfaceTis
:
654 return TisPcRequestUseTpm ((TIS_PC_REGISTERS_PTR
)(UINTN
)PcdGet64 (PcdTpmBaseAddress
));
656 return EFI_NOT_FOUND
;