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) {
62 Check whether the value of a TPM chip register satisfies the input BIT setting.
64 @param[in] Register Address port of register to be checked.
65 @param[in] BitSet Check these data bits are set.
66 @param[in] BitClear Check these data bits are clear.
67 @param[in] TimeOut The max wait time (unit MicroSecond) when checking register.
69 @retval EFI_SUCCESS The register satisfies the check bit.
70 @retval EFI_TIMEOUT The register can't run into the expected status in time.
73 PtpCrbWaitRegisterBits (
83 for (WaitTime
= 0; WaitTime
< TimeOut
; WaitTime
+= 30){
84 RegRead
= MmioRead32 ((UINTN
)Register
);
85 if ((RegRead
& BitSet
) == BitSet
&& (RegRead
& BitClear
) == 0) {
88 MicroSecondDelay (30);
94 Get the control of TPM chip.
96 @param[in] CrbReg Pointer to CRB register.
98 @retval EFI_SUCCESS Get the control of TPM chip.
99 @retval EFI_INVALID_PARAMETER CrbReg is NULL.
100 @retval EFI_NOT_FOUND TPM chip doesn't exit.
101 @retval EFI_TIMEOUT Can't get the TPM control in time.
104 PtpCrbRequestUseTpm (
105 IN PTP_CRB_REGISTERS_PTR CrbReg
110 if (!Tpm2IsPtpPresence (CrbReg
)) {
111 return EFI_NOT_FOUND
;
114 MmioWrite32((UINTN
)&CrbReg
->LocalityControl
, PTP_CRB_LOCALITY_CONTROL_REQUEST_ACCESS
);
115 Status
= PtpCrbWaitRegisterBits (
116 &CrbReg
->LocalityStatus
,
117 PTP_CRB_LOCALITY_STATUS_GRANTED
,
125 Send a command to TPM for execution and return response data.
127 @param[in] CrbReg TPM register space base address.
128 @param[in] BufferIn Buffer for command data.
129 @param[in] SizeIn Size of command data.
130 @param[in, out] BufferOut Buffer for response data.
131 @param[in, out] SizeOut Size of response data.
133 @retval EFI_SUCCESS Operation completed successfully.
134 @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small.
135 @retval EFI_DEVICE_ERROR Unexpected device behavior.
136 @retval EFI_UNSUPPORTED Unsupported TPM version
141 IN PTP_CRB_REGISTERS_PTR CrbReg
,
144 IN OUT UINT8
*BufferOut
,
145 IN OUT UINT32
*SizeOut
157 DEBUG ((DEBUG_VERBOSE
, "PtpCrbTpmCommand Send - "));
158 if (SizeIn
> 0x100) {
163 for (Index
= 0; Index
< DebugSize
; Index
++) {
164 DEBUG ((DEBUG_VERBOSE
, "%02x ", BufferIn
[Index
]));
166 if (DebugSize
!= SizeIn
) {
167 DEBUG ((DEBUG_VERBOSE
, "...... "));
168 for (Index
= SizeIn
- 0x20; Index
< SizeIn
; Index
++) {
169 DEBUG ((DEBUG_VERBOSE
, "%02x ", BufferIn
[Index
]));
172 DEBUG ((DEBUG_VERBOSE
, "\n"));
178 // if CapCRbIdelByPass == 0, enforce Idle state before sending command
180 if (GetCachedIdleByPass () == 0 && (MmioRead32((UINTN
)&CrbReg
->CrbControlStatus
) & PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE
) == 0){
181 Status
= PtpCrbWaitRegisterBits (
182 &CrbReg
->CrbControlStatus
,
183 PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE
,
187 if (EFI_ERROR (Status
)) {
189 // Try to goIdle to recover TPM
191 Status
= EFI_DEVICE_ERROR
;
198 // Ready is any time the TPM is ready to receive a command, following a write
199 // of 1 by software to Request.cmdReady, as indicated by the Status field
200 // being cleared to 0.
202 MmioWrite32((UINTN
)&CrbReg
->CrbControlRequest
, PTP_CRB_CONTROL_AREA_REQUEST_COMMAND_READY
);
203 Status
= PtpCrbWaitRegisterBits (
204 &CrbReg
->CrbControlRequest
,
206 PTP_CRB_CONTROL_AREA_REQUEST_COMMAND_READY
,
209 if (EFI_ERROR (Status
)) {
210 Status
= EFI_DEVICE_ERROR
;
213 Status
= PtpCrbWaitRegisterBits (
214 &CrbReg
->CrbControlStatus
,
216 PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE
,
219 if (EFI_ERROR (Status
)) {
220 Status
= EFI_DEVICE_ERROR
;
226 // Command Reception occurs following a Ready state between the write of the
227 // first byte of a command to the Command Buffer and the receipt of a write
230 for (Index
= 0; Index
< SizeIn
; Index
++) {
231 MmioWrite8 ((UINTN
)&CrbReg
->CrbDataBuffer
[Index
], BufferIn
[Index
]);
233 MmioWrite32 ((UINTN
)&CrbReg
->CrbControlCommandAddressHigh
, (UINT32
)RShiftU64 ((UINTN
)CrbReg
->CrbDataBuffer
, 32));
234 MmioWrite32 ((UINTN
)&CrbReg
->CrbControlCommandAddressLow
, (UINT32
)(UINTN
)CrbReg
->CrbDataBuffer
);
235 MmioWrite32 ((UINTN
)&CrbReg
->CrbControlCommandSize
, sizeof(CrbReg
->CrbDataBuffer
));
237 MmioWrite64 ((UINTN
)&CrbReg
->CrbControlResponseAddrss
, (UINT32
)(UINTN
)CrbReg
->CrbDataBuffer
);
238 MmioWrite32 ((UINTN
)&CrbReg
->CrbControlResponseSize
, sizeof(CrbReg
->CrbDataBuffer
));
242 // Command Execution occurs after receipt of a 1 to Start and the TPM
243 // clearing Start to 0.
245 MmioWrite32((UINTN
)&CrbReg
->CrbControlStart
, PTP_CRB_CONTROL_START
);
246 Status
= PtpCrbWaitRegisterBits (
247 &CrbReg
->CrbControlStart
,
249 PTP_CRB_CONTROL_START
,
252 if (EFI_ERROR (Status
)) {
254 // Command Completion check timeout. Cancel the currently executing command by writing TPM_CRB_CTRL_CANCEL,
255 // Expect TPM_RC_CANCELLED or successfully completed response.
257 MmioWrite32((UINTN
)&CrbReg
->CrbControlCancel
, PTP_CRB_CONTROL_CANCEL
);
258 Status
= PtpCrbWaitRegisterBits (
259 &CrbReg
->CrbControlStart
,
261 PTP_CRB_CONTROL_START
,
264 MmioWrite32((UINTN
)&CrbReg
->CrbControlCancel
, 0);
266 if (EFI_ERROR(Status
)) {
268 // Still in Command Execution state. Try to goIdle, the behavior is agnostic.
270 Status
= EFI_DEVICE_ERROR
;
277 // Command Completion occurs after completion of a command (indicated by the
278 // TPM clearing TPM_CRB_CTRL_Start_x to 0) and before a write of a 1 by the
279 // software to Request.goIdle.
283 // Get response data header
285 for (Index
= 0; Index
< sizeof (TPM2_RESPONSE_HEADER
); Index
++) {
286 BufferOut
[Index
] = MmioRead8 ((UINTN
)&CrbReg
->CrbDataBuffer
[Index
]);
289 DEBUG ((DEBUG_VERBOSE
, "PtpCrbTpmCommand ReceiveHeader - "));
290 for (Index
= 0; Index
< sizeof (TPM2_RESPONSE_HEADER
); Index
++) {
291 DEBUG ((DEBUG_VERBOSE
, "%02x ", BufferOut
[Index
]));
293 DEBUG ((DEBUG_VERBOSE
, "\n"));
296 // Check the response data header (tag, parasize and returncode)
298 CopyMem (&Data16
, BufferOut
, sizeof (UINT16
));
299 // TPM2 should not use this RSP_COMMAND
300 if (SwapBytes16 (Data16
) == TPM_ST_RSP_COMMAND
) {
301 DEBUG ((DEBUG_ERROR
, "TPM2: TPM_ST_RSP error - %x\n", TPM_ST_RSP_COMMAND
));
302 Status
= EFI_UNSUPPORTED
;
306 CopyMem (&Data32
, (BufferOut
+ 2), sizeof (UINT32
));
307 TpmOutSize
= SwapBytes32 (Data32
);
308 if (*SizeOut
< TpmOutSize
) {
310 // Command completed, but buffer is not enough
312 Status
= EFI_BUFFER_TOO_SMALL
;
315 *SizeOut
= TpmOutSize
;
317 // Continue reading the remaining data
319 for (Index
= sizeof (TPM2_RESPONSE_HEADER
); Index
< TpmOutSize
; Index
++) {
320 BufferOut
[Index
] = MmioRead8 ((UINTN
)&CrbReg
->CrbDataBuffer
[Index
]);
324 DEBUG ((DEBUG_VERBOSE
, "PtpCrbTpmCommand Receive - "));
325 for (Index
= 0; Index
< TpmOutSize
; Index
++) {
326 DEBUG ((DEBUG_VERBOSE
, "%02x ", BufferOut
[Index
]));
328 DEBUG ((DEBUG_VERBOSE
, "\n"));
333 // Goto Ready State if command is completed successfully and TPM support IdleBypass
334 // If not supported. flow down to GoIdle
336 if (GetCachedIdleByPass () == 1) {
337 MmioWrite32((UINTN
)&CrbReg
->CrbControlRequest
, PTP_CRB_CONTROL_AREA_REQUEST_COMMAND_READY
);
342 // Do not wait for state transition for TIMEOUT_C
343 // This function will try to wait 2 TIMEOUT_C at the beginning in next call.
348 // Return to Idle state by setting TPM_CRB_CTRL_STS_x.Status.goIdle to 1.
350 MmioWrite32((UINTN
)&CrbReg
->CrbControlRequest
, PTP_CRB_CONTROL_AREA_REQUEST_GO_IDLE
);
353 // Only enforce Idle state transition if execution fails when CRBIdleBypass==1
354 // Leave regular Idle delay at the beginning of next command execution
356 if (GetCachedIdleByPass () == 1){
357 Status
= PtpCrbWaitRegisterBits (
358 &CrbReg
->CrbControlStatus
,
359 PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE
,
369 Send a command to TPM for execution and return response data.
371 @param[in] TisReg TPM register space base address.
372 @param[in] BufferIn Buffer for command data.
373 @param[in] SizeIn Size of command data.
374 @param[in, out] BufferOut Buffer for response data.
375 @param[in, out] SizeOut Size of response data.
377 @retval EFI_SUCCESS Operation completed successfully.
378 @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small.
379 @retval EFI_DEVICE_ERROR Unexpected device behavior.
380 @retval EFI_UNSUPPORTED Unsupported TPM version
385 IN TIS_PC_REGISTERS_PTR TisReg
,
388 IN OUT UINT8
*BufferOut
,
389 IN OUT UINT32
*SizeOut
393 Get the control of TPM chip by sending requestUse command TIS_PC_ACC_RQUUSE
394 to ACCESS Register in the time of default TIS_TIMEOUT_A.
396 @param[in] TisReg Pointer to TIS register.
398 @retval EFI_SUCCESS Get the control of TPM chip.
399 @retval EFI_INVALID_PARAMETER TisReg is NULL.
400 @retval EFI_NOT_FOUND TPM chip doesn't exit.
401 @retval EFI_TIMEOUT Can't get the TPM control in time.
405 IN TIS_PC_REGISTERS_PTR TisReg
409 Return PTP interface type.
411 @param[in] Register Pointer to PTP register.
413 @return PTP interface type.
415 TPM2_PTP_INTERFACE_TYPE
416 Tpm2GetPtpInterface (
420 PTP_CRB_INTERFACE_IDENTIFIER InterfaceId
;
421 PTP_FIFO_INTERFACE_CAPABILITY InterfaceCapability
;
423 if (!Tpm2IsPtpPresence (Register
)) {
424 return Tpm2PtpInterfaceMax
;
427 // Check interface id
429 InterfaceId
.Uint32
= MmioRead32 ((UINTN
)&((PTP_CRB_REGISTERS
*)Register
)->InterfaceId
);
430 InterfaceCapability
.Uint32
= MmioRead32 ((UINTN
)&((PTP_FIFO_REGISTERS
*)Register
)->InterfaceCapability
);
432 if ((InterfaceId
.Bits
.InterfaceType
== PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_CRB
) &&
433 (InterfaceId
.Bits
.InterfaceVersion
== PTP_INTERFACE_IDENTIFIER_INTERFACE_VERSION_CRB
) &&
434 (InterfaceId
.Bits
.CapCRB
!= 0)) {
435 return Tpm2PtpInterfaceCrb
;
437 if ((InterfaceId
.Bits
.InterfaceType
== PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_FIFO
) &&
438 (InterfaceId
.Bits
.InterfaceVersion
== PTP_INTERFACE_IDENTIFIER_INTERFACE_VERSION_FIFO
) &&
439 (InterfaceId
.Bits
.CapFIFO
!= 0) &&
440 (InterfaceCapability
.Bits
.InterfaceVersion
== INTERFACE_CAPABILITY_INTERFACE_VERSION_PTP
)) {
441 return Tpm2PtpInterfaceFifo
;
443 return Tpm2PtpInterfaceTis
;
447 Return PTP CRB interface IdleByPass state.
449 @param[in] Register Pointer to PTP register.
451 @return PTP CRB interface IdleByPass state.
458 PTP_CRB_INTERFACE_IDENTIFIER InterfaceId
;
461 // Check interface id
463 InterfaceId
.Uint32
= MmioRead32 ((UINTN
)&((PTP_CRB_REGISTERS
*)Register
)->InterfaceId
);
465 return (UINT8
)(InterfaceId
.Bits
.CapCRBIdleBypass
);
469 Dump PTP register information.
471 @param[in] Register Pointer to PTP register.
478 PTP_CRB_INTERFACE_IDENTIFIER InterfaceId
;
479 PTP_FIFO_INTERFACE_CAPABILITY InterfaceCapability
;
484 TPM2_PTP_INTERFACE_TYPE PtpInterface
;
486 if (!Tpm2IsPtpPresence (Register
)) {
490 InterfaceId
.Uint32
= MmioRead32 ((UINTN
)&((PTP_CRB_REGISTERS
*)Register
)->InterfaceId
);
491 InterfaceCapability
.Uint32
= MmioRead32 ((UINTN
)&((PTP_FIFO_REGISTERS
*)Register
)->InterfaceCapability
);
492 StatusEx
= MmioRead8 ((UINTN
)&((PTP_FIFO_REGISTERS
*)Register
)->StatusEx
);
495 // Dump InterfaceId Register for PTP
497 DEBUG ((DEBUG_INFO
, "InterfaceId - 0x%08x\n", InterfaceId
.Uint32
));
498 DEBUG ((DEBUG_INFO
, " InterfaceType - 0x%02x\n", InterfaceId
.Bits
.InterfaceType
));
499 if (InterfaceId
.Bits
.InterfaceType
!= PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_TIS
) {
500 DEBUG ((DEBUG_INFO
, " InterfaceVersion - 0x%02x\n", InterfaceId
.Bits
.InterfaceVersion
));
501 DEBUG ((DEBUG_INFO
, " CapFIFO - 0x%x\n", InterfaceId
.Bits
.CapFIFO
));
502 DEBUG ((DEBUG_INFO
, " CapCRB - 0x%x\n", InterfaceId
.Bits
.CapCRB
));
506 // Dump Capability Register for TIS and FIFO
508 DEBUG ((DEBUG_INFO
, "InterfaceCapability - 0x%08x\n", InterfaceCapability
.Uint32
));
509 if ((InterfaceId
.Bits
.InterfaceType
== PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_TIS
) ||
510 (InterfaceId
.Bits
.InterfaceType
== PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_FIFO
)) {
511 DEBUG ((DEBUG_INFO
, " InterfaceVersion - 0x%x\n", InterfaceCapability
.Bits
.InterfaceVersion
));
515 // Dump StatusEx Register for PTP FIFO
517 DEBUG ((DEBUG_INFO
, "StatusEx - 0x%02x\n", StatusEx
));
518 if (InterfaceCapability
.Bits
.InterfaceVersion
== INTERFACE_CAPABILITY_INTERFACE_VERSION_PTP
) {
519 DEBUG ((DEBUG_INFO
, " TpmFamily - 0x%x\n", (StatusEx
& PTP_FIFO_STS_EX_TPM_FAMILY
) >> PTP_FIFO_STS_EX_TPM_FAMILY_OFFSET
));
525 PtpInterface
= GetCachedPtpInterface ();
526 DEBUG ((DEBUG_INFO
, "PtpInterface - %x\n", PtpInterface
));
527 switch (PtpInterface
) {
528 case Tpm2PtpInterfaceCrb
:
529 Vid
= MmioRead16 ((UINTN
)&((PTP_CRB_REGISTERS
*)Register
)->Vid
);
530 Did
= MmioRead16 ((UINTN
)&((PTP_CRB_REGISTERS
*)Register
)->Did
);
531 Rid
= (UINT8
)InterfaceId
.Bits
.Rid
;
533 case Tpm2PtpInterfaceFifo
:
534 case Tpm2PtpInterfaceTis
:
535 Vid
= MmioRead16 ((UINTN
)&((PTP_FIFO_REGISTERS
*)Register
)->Vid
);
536 Did
= MmioRead16 ((UINTN
)&((PTP_FIFO_REGISTERS
*)Register
)->Did
);
537 Rid
= MmioRead8 ((UINTN
)&((PTP_FIFO_REGISTERS
*)Register
)->Rid
);
542 DEBUG ((DEBUG_INFO
, "VID - 0x%04x\n", Vid
));
543 DEBUG ((DEBUG_INFO
, "DID - 0x%04x\n", Did
));
544 DEBUG ((DEBUG_INFO
, "RID - 0x%02x\n", Rid
));
548 This service enables the sending of commands to the TPM2.
550 @param[in] InputParameterBlockSize Size of the TPM2 input parameter block.
551 @param[in] InputParameterBlock Pointer to the TPM2 input parameter block.
552 @param[in,out] OutputParameterBlockSize Size of the TPM2 output parameter block.
553 @param[in] OutputParameterBlock Pointer to the TPM2 output parameter block.
555 @retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received.
556 @retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device.
557 @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small.
562 IN UINT32 InputParameterBlockSize
,
563 IN UINT8
*InputParameterBlock
,
564 IN OUT UINT32
*OutputParameterBlockSize
,
565 IN UINT8
*OutputParameterBlock
568 TPM2_PTP_INTERFACE_TYPE PtpInterface
;
570 PtpInterface
= GetCachedPtpInterface ();
571 switch (PtpInterface
) {
572 case Tpm2PtpInterfaceCrb
:
573 return PtpCrbTpmCommand (
574 (PTP_CRB_REGISTERS_PTR
) (UINTN
) PcdGet64 (PcdTpmBaseAddress
),
576 InputParameterBlockSize
,
577 OutputParameterBlock
,
578 OutputParameterBlockSize
580 case Tpm2PtpInterfaceFifo
:
581 case Tpm2PtpInterfaceTis
:
582 return Tpm2TisTpmCommand (
583 (TIS_PC_REGISTERS_PTR
) (UINTN
) PcdGet64 (PcdTpmBaseAddress
),
585 InputParameterBlockSize
,
586 OutputParameterBlock
,
587 OutputParameterBlockSize
590 return EFI_NOT_FOUND
;
595 This service requests use TPM2.
597 @retval EFI_SUCCESS Get the control of TPM2 chip.
598 @retval EFI_NOT_FOUND TPM2 not found.
599 @retval EFI_DEVICE_ERROR Unexpected device behavior.
607 TPM2_PTP_INTERFACE_TYPE PtpInterface
;
609 PtpInterface
= GetCachedPtpInterface ();
610 switch (PtpInterface
) {
611 case Tpm2PtpInterfaceCrb
:
612 return PtpCrbRequestUseTpm ((PTP_CRB_REGISTERS_PTR
) (UINTN
) PcdGet64 (PcdTpmBaseAddress
));
613 case Tpm2PtpInterfaceFifo
:
614 case Tpm2PtpInterfaceTis
:
615 return TisPcRequestUseTpm ((TIS_PC_REGISTERS_PTR
) (UINTN
) PcdGet64 (PcdTpmBaseAddress
));
617 return EFI_NOT_FOUND
;