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 SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include <IndustryStandard/Tpm20.h>
11 #include <Library/BaseLib.h>
12 #include <Library/BaseMemoryLib.h>
13 #include <Library/IoLib.h>
14 #include <Library/TimerLib.h>
15 #include <Library/DebugLib.h>
16 #include <Library/Tpm2DeviceLib.h>
17 #include <Library/PcdLib.h>
19 #include <IndustryStandard/TpmPtp.h>
20 #include <IndustryStandard/TpmTis.h>
23 // Execution of the command may take from several seconds to minutes for certain
24 // commands, such as key generation.
26 #define PTP_TIMEOUT_MAX (90000 * 1000) // 90s
29 // Max TPM command/reponse length
31 #define TPMCMDBUFLENGTH 0x500
34 Check whether TPM PTP register exist.
36 @param[in] Reg Pointer to PTP register.
38 @retval TRUE TPM PTP exists.
39 @retval FALSE TPM PTP is not found.
48 RegRead
= MmioRead8 ((UINTN
)Reg
);
49 if (RegRead
== 0xFF) {
59 Check whether the value of a TPM chip register satisfies the input BIT setting.
61 @param[in] Register Address port of register to be checked.
62 @param[in] BitSet Check these data bits are set.
63 @param[in] BitClear Check these data bits are clear.
64 @param[in] TimeOut The max wait time (unit MicroSecond) when checking register.
66 @retval EFI_SUCCESS The register satisfies the check bit.
67 @retval EFI_TIMEOUT The register can't run into the expected status in time.
70 PtpCrbWaitRegisterBits (
80 for (WaitTime
= 0; WaitTime
< TimeOut
; WaitTime
+= 30){
81 RegRead
= MmioRead32 ((UINTN
)Register
);
82 if ((RegRead
& BitSet
) == BitSet
&& (RegRead
& BitClear
) == 0) {
85 MicroSecondDelay (30);
91 Get the control of TPM chip.
93 @param[in] CrbReg Pointer to CRB register.
95 @retval EFI_SUCCESS Get the control of TPM chip.
96 @retval EFI_INVALID_PARAMETER CrbReg is NULL.
97 @retval EFI_NOT_FOUND TPM chip doesn't exit.
98 @retval EFI_TIMEOUT Can't get the TPM control in time.
101 PtpCrbRequestUseTpm (
102 IN PTP_CRB_REGISTERS_PTR CrbReg
107 if (!Tpm2IsPtpPresence (CrbReg
)) {
108 return EFI_NOT_FOUND
;
111 MmioWrite32((UINTN
)&CrbReg
->LocalityControl
, PTP_CRB_LOCALITY_CONTROL_REQUEST_ACCESS
);
112 Status
= PtpCrbWaitRegisterBits (
113 &CrbReg
->LocalityStatus
,
114 PTP_CRB_LOCALITY_STATUS_GRANTED
,
122 Send a command to TPM for execution and return response data.
124 @param[in] CrbReg TPM register space base address.
125 @param[in] BufferIn Buffer for command data.
126 @param[in] SizeIn Size of command data.
127 @param[in, out] BufferOut Buffer for response data.
128 @param[in, out] SizeOut Size of response data.
130 @retval EFI_SUCCESS Operation completed successfully.
131 @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small.
132 @retval EFI_DEVICE_ERROR Unexpected device behavior.
133 @retval EFI_UNSUPPORTED Unsupported TPM version
138 IN PTP_CRB_REGISTERS_PTR CrbReg
,
141 IN OUT UINT8
*BufferOut
,
142 IN OUT UINT32
*SizeOut
154 DEBUG ((EFI_D_VERBOSE
, "PtpCrbTpmCommand Send - "));
155 if (SizeIn
> 0x100) {
160 for (Index
= 0; Index
< DebugSize
; Index
++) {
161 DEBUG ((EFI_D_VERBOSE
, "%02x ", BufferIn
[Index
]));
163 if (DebugSize
!= SizeIn
) {
164 DEBUG ((EFI_D_VERBOSE
, "...... "));
165 for (Index
= SizeIn
- 0x20; Index
< SizeIn
; Index
++) {
166 DEBUG ((EFI_D_VERBOSE
, "%02x ", BufferIn
[Index
]));
169 DEBUG ((EFI_D_VERBOSE
, "\n"));
175 // if CapCRbIdelByPass == 0, enforce Idle state before sending command
177 if (PcdGet8(PcdCRBIdleByPass
) == 0 && (MmioRead32((UINTN
)&CrbReg
->CrbControlStatus
) & PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE
) == 0){
178 Status
= PtpCrbWaitRegisterBits (
179 &CrbReg
->CrbControlStatus
,
180 PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE
,
184 if (EFI_ERROR (Status
)) {
186 // Try to goIdle to recover TPM
188 Status
= EFI_DEVICE_ERROR
;
195 // Ready is any time the TPM is ready to receive a command, following a write
196 // of 1 by software to Request.cmdReady, as indicated by the Status field
197 // being cleared to 0.
199 MmioWrite32((UINTN
)&CrbReg
->CrbControlRequest
, PTP_CRB_CONTROL_AREA_REQUEST_COMMAND_READY
);
200 Status
= PtpCrbWaitRegisterBits (
201 &CrbReg
->CrbControlRequest
,
203 PTP_CRB_CONTROL_AREA_REQUEST_COMMAND_READY
,
206 if (EFI_ERROR (Status
)) {
207 Status
= EFI_DEVICE_ERROR
;
210 Status
= PtpCrbWaitRegisterBits (
211 &CrbReg
->CrbControlStatus
,
213 PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE
,
216 if (EFI_ERROR (Status
)) {
217 Status
= EFI_DEVICE_ERROR
;
223 // Command Reception occurs following a Ready state between the write of the
224 // first byte of a command to the Command Buffer and the receipt of a write
227 for (Index
= 0; Index
< SizeIn
; Index
++) {
228 MmioWrite8 ((UINTN
)&CrbReg
->CrbDataBuffer
[Index
], BufferIn
[Index
]);
230 MmioWrite32 ((UINTN
)&CrbReg
->CrbControlCommandAddressHigh
, (UINT32
)RShiftU64 ((UINTN
)CrbReg
->CrbDataBuffer
, 32));
231 MmioWrite32 ((UINTN
)&CrbReg
->CrbControlCommandAddressLow
, (UINT32
)(UINTN
)CrbReg
->CrbDataBuffer
);
232 MmioWrite32 ((UINTN
)&CrbReg
->CrbControlCommandSize
, sizeof(CrbReg
->CrbDataBuffer
));
234 MmioWrite64 ((UINTN
)&CrbReg
->CrbControlResponseAddrss
, (UINT32
)(UINTN
)CrbReg
->CrbDataBuffer
);
235 MmioWrite32 ((UINTN
)&CrbReg
->CrbControlResponseSize
, sizeof(CrbReg
->CrbDataBuffer
));
239 // Command Execution occurs after receipt of a 1 to Start and the TPM
240 // clearing Start to 0.
242 MmioWrite32((UINTN
)&CrbReg
->CrbControlStart
, PTP_CRB_CONTROL_START
);
243 Status
= PtpCrbWaitRegisterBits (
244 &CrbReg
->CrbControlStart
,
246 PTP_CRB_CONTROL_START
,
249 if (EFI_ERROR (Status
)) {
251 // Command Completion check timeout. Cancel the currently executing command by writing TPM_CRB_CTRL_CANCEL,
252 // Expect TPM_RC_CANCELLED or successfully completed response.
254 MmioWrite32((UINTN
)&CrbReg
->CrbControlCancel
, PTP_CRB_CONTROL_CANCEL
);
255 Status
= PtpCrbWaitRegisterBits (
256 &CrbReg
->CrbControlStart
,
258 PTP_CRB_CONTROL_START
,
261 MmioWrite32((UINTN
)&CrbReg
->CrbControlCancel
, 0);
263 if (EFI_ERROR(Status
)) {
265 // Still in Command Execution state. Try to goIdle, the behavior is agnostic.
267 Status
= EFI_DEVICE_ERROR
;
274 // Command Completion occurs after completion of a command (indicated by the
275 // TPM clearing TPM_CRB_CTRL_Start_x to 0) and before a write of a 1 by the
276 // software to Request.goIdle.
280 // Get response data header
282 for (Index
= 0; Index
< sizeof (TPM2_RESPONSE_HEADER
); Index
++) {
283 BufferOut
[Index
] = MmioRead8 ((UINTN
)&CrbReg
->CrbDataBuffer
[Index
]);
286 DEBUG ((EFI_D_VERBOSE
, "PtpCrbTpmCommand ReceiveHeader - "));
287 for (Index
= 0; Index
< sizeof (TPM2_RESPONSE_HEADER
); Index
++) {
288 DEBUG ((EFI_D_VERBOSE
, "%02x ", BufferOut
[Index
]));
290 DEBUG ((EFI_D_VERBOSE
, "\n"));
293 // Check the reponse data header (tag, parasize and returncode)
295 CopyMem (&Data16
, BufferOut
, sizeof (UINT16
));
296 // TPM2 should not use this RSP_COMMAND
297 if (SwapBytes16 (Data16
) == TPM_ST_RSP_COMMAND
) {
298 DEBUG ((EFI_D_ERROR
, "TPM2: TPM_ST_RSP error - %x\n", TPM_ST_RSP_COMMAND
));
299 Status
= EFI_UNSUPPORTED
;
303 CopyMem (&Data32
, (BufferOut
+ 2), sizeof (UINT32
));
304 TpmOutSize
= SwapBytes32 (Data32
);
305 if (*SizeOut
< TpmOutSize
) {
307 // Command completed, but buffer is not enough
309 Status
= EFI_BUFFER_TOO_SMALL
;
312 *SizeOut
= TpmOutSize
;
314 // Continue reading the remaining data
316 for (Index
= sizeof (TPM2_RESPONSE_HEADER
); Index
< TpmOutSize
; Index
++) {
317 BufferOut
[Index
] = MmioRead8 ((UINTN
)&CrbReg
->CrbDataBuffer
[Index
]);
321 DEBUG ((EFI_D_VERBOSE
, "PtpCrbTpmCommand Receive - "));
322 for (Index
= 0; Index
< TpmOutSize
; Index
++) {
323 DEBUG ((EFI_D_VERBOSE
, "%02x ", BufferOut
[Index
]));
325 DEBUG ((EFI_D_VERBOSE
, "\n"));
330 // Goto Ready State if command is completed succesfully and TPM support IdleBypass
331 // If not supported. flow down to GoIdle
333 if (PcdGet8(PcdCRBIdleByPass
) == 1) {
334 MmioWrite32((UINTN
)&CrbReg
->CrbControlRequest
, PTP_CRB_CONTROL_AREA_REQUEST_COMMAND_READY
);
339 // Do not wait for state transition for TIMEOUT_C
340 // This function will try to wait 2 TIMEOUT_C at the beginning in next call.
345 // Return to Idle state by setting TPM_CRB_CTRL_STS_x.Status.goIdle to 1.
347 MmioWrite32((UINTN
)&CrbReg
->CrbControlRequest
, PTP_CRB_CONTROL_AREA_REQUEST_GO_IDLE
);
350 // Only enforce Idle state transition if execution fails when CRBIndleBypass==1
351 // Leave regular Idle delay at the beginning of next command execution
353 if (PcdGet8(PcdCRBIdleByPass
) == 1){
354 Status
= PtpCrbWaitRegisterBits (
355 &CrbReg
->CrbControlStatus
,
356 PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE
,
366 Send a command to TPM for execution and return response data.
368 @param[in] TisReg TPM register space base address.
369 @param[in] BufferIn Buffer for command data.
370 @param[in] SizeIn Size of command data.
371 @param[in, out] BufferOut Buffer for response data.
372 @param[in, out] SizeOut Size of response data.
374 @retval EFI_SUCCESS Operation completed successfully.
375 @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small.
376 @retval EFI_DEVICE_ERROR Unexpected device behavior.
377 @retval EFI_UNSUPPORTED Unsupported TPM version
382 IN TIS_PC_REGISTERS_PTR TisReg
,
385 IN OUT UINT8
*BufferOut
,
386 IN OUT UINT32
*SizeOut
390 Get the control of TPM chip by sending requestUse command TIS_PC_ACC_RQUUSE
391 to ACCESS Register in the time of default TIS_TIMEOUT_A.
393 @param[in] TisReg Pointer to TIS register.
395 @retval EFI_SUCCESS Get the control of TPM chip.
396 @retval EFI_INVALID_PARAMETER TisReg is NULL.
397 @retval EFI_NOT_FOUND TPM chip doesn't exit.
398 @retval EFI_TIMEOUT Can't get the TPM control in time.
402 IN TIS_PC_REGISTERS_PTR TisReg
406 Return PTP interface type.
408 @param[in] Register Pointer to PTP register.
410 @return PTP interface type.
412 TPM2_PTP_INTERFACE_TYPE
413 Tpm2GetPtpInterface (
417 PTP_CRB_INTERFACE_IDENTIFIER InterfaceId
;
418 PTP_FIFO_INTERFACE_CAPABILITY InterfaceCapability
;
420 if (!Tpm2IsPtpPresence (Register
)) {
421 return Tpm2PtpInterfaceMax
;
424 // Check interface id
426 InterfaceId
.Uint32
= MmioRead32 ((UINTN
)&((PTP_CRB_REGISTERS
*)Register
)->InterfaceId
);
427 InterfaceCapability
.Uint32
= MmioRead32 ((UINTN
)&((PTP_FIFO_REGISTERS
*)Register
)->InterfaceCapability
);
429 if ((InterfaceId
.Bits
.InterfaceType
== PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_CRB
) &&
430 (InterfaceId
.Bits
.InterfaceVersion
== PTP_INTERFACE_IDENTIFIER_INTERFACE_VERSION_CRB
) &&
431 (InterfaceId
.Bits
.CapCRB
!= 0)) {
432 return Tpm2PtpInterfaceCrb
;
434 if ((InterfaceId
.Bits
.InterfaceType
== PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_FIFO
) &&
435 (InterfaceId
.Bits
.InterfaceVersion
== PTP_INTERFACE_IDENTIFIER_INTERFACE_VERSION_FIFO
) &&
436 (InterfaceId
.Bits
.CapFIFO
!= 0) &&
437 (InterfaceCapability
.Bits
.InterfaceVersion
== INTERFACE_CAPABILITY_INTERFACE_VERSION_PTP
)) {
438 return Tpm2PtpInterfaceFifo
;
440 return Tpm2PtpInterfaceTis
;
444 Return PTP CRB interface IdleByPass state.
446 @param[in] Register Pointer to PTP register.
448 @return PTP CRB interface IdleByPass state.
455 PTP_CRB_INTERFACE_IDENTIFIER InterfaceId
;
458 // Check interface id
460 InterfaceId
.Uint32
= MmioRead32 ((UINTN
)&((PTP_CRB_REGISTERS
*)Register
)->InterfaceId
);
462 return (UINT8
)(InterfaceId
.Bits
.CapCRBIdleBypass
);
466 Dump PTP register information.
468 @param[in] Register Pointer to PTP register.
475 PTP_CRB_INTERFACE_IDENTIFIER InterfaceId
;
476 PTP_FIFO_INTERFACE_CAPABILITY InterfaceCapability
;
481 TPM2_PTP_INTERFACE_TYPE PtpInterface
;
483 if (!Tpm2IsPtpPresence (Register
)) {
487 InterfaceId
.Uint32
= MmioRead32 ((UINTN
)&((PTP_CRB_REGISTERS
*)Register
)->InterfaceId
);
488 InterfaceCapability
.Uint32
= MmioRead32 ((UINTN
)&((PTP_FIFO_REGISTERS
*)Register
)->InterfaceCapability
);
489 StatusEx
= MmioRead8 ((UINTN
)&((PTP_FIFO_REGISTERS
*)Register
)->StatusEx
);
492 // Dump InterfaceId Register for PTP
494 DEBUG ((EFI_D_INFO
, "InterfaceId - 0x%08x\n", InterfaceId
.Uint32
));
495 DEBUG ((EFI_D_INFO
, " InterfaceType - 0x%02x\n", InterfaceId
.Bits
.InterfaceType
));
496 if (InterfaceId
.Bits
.InterfaceType
!= PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_TIS
) {
497 DEBUG ((EFI_D_INFO
, " InterfaceVersion - 0x%02x\n", InterfaceId
.Bits
.InterfaceVersion
));
498 DEBUG ((EFI_D_INFO
, " CapFIFO - 0x%x\n", InterfaceId
.Bits
.CapFIFO
));
499 DEBUG ((EFI_D_INFO
, " CapCRB - 0x%x\n", InterfaceId
.Bits
.CapCRB
));
503 // Dump Capability Register for TIS and FIFO
505 DEBUG ((EFI_D_INFO
, "InterfaceCapability - 0x%08x\n", InterfaceCapability
.Uint32
));
506 if ((InterfaceId
.Bits
.InterfaceType
== PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_TIS
) ||
507 (InterfaceId
.Bits
.InterfaceType
== PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_FIFO
)) {
508 DEBUG ((EFI_D_INFO
, " InterfaceVersion - 0x%x\n", InterfaceCapability
.Bits
.InterfaceVersion
));
512 // Dump StatusEx Register for PTP FIFO
514 DEBUG ((EFI_D_INFO
, "StatusEx - 0x%02x\n", StatusEx
));
515 if (InterfaceCapability
.Bits
.InterfaceVersion
== INTERFACE_CAPABILITY_INTERFACE_VERSION_PTP
) {
516 DEBUG ((EFI_D_INFO
, " TpmFamily - 0x%x\n", (StatusEx
& PTP_FIFO_STS_EX_TPM_FAMILY
) >> PTP_FIFO_STS_EX_TPM_FAMILY_OFFSET
));
522 PtpInterface
= PcdGet8(PcdActiveTpmInterfaceType
);
523 DEBUG ((EFI_D_INFO
, "PtpInterface - %x\n", PtpInterface
));
524 switch (PtpInterface
) {
525 case Tpm2PtpInterfaceCrb
:
526 Vid
= MmioRead16 ((UINTN
)&((PTP_CRB_REGISTERS
*)Register
)->Vid
);
527 Did
= MmioRead16 ((UINTN
)&((PTP_CRB_REGISTERS
*)Register
)->Did
);
528 Rid
= (UINT8
)InterfaceId
.Bits
.Rid
;
530 case Tpm2PtpInterfaceFifo
:
531 case Tpm2PtpInterfaceTis
:
532 Vid
= MmioRead16 ((UINTN
)&((PTP_FIFO_REGISTERS
*)Register
)->Vid
);
533 Did
= MmioRead16 ((UINTN
)&((PTP_FIFO_REGISTERS
*)Register
)->Did
);
534 Rid
= MmioRead8 ((UINTN
)&((PTP_FIFO_REGISTERS
*)Register
)->Rid
);
539 DEBUG ((EFI_D_INFO
, "VID - 0x%04x\n", Vid
));
540 DEBUG ((EFI_D_INFO
, "DID - 0x%04x\n", Did
));
541 DEBUG ((EFI_D_INFO
, "RID - 0x%02x\n", Rid
));
545 This service enables the sending of commands to the TPM2.
547 @param[in] InputParameterBlockSize Size of the TPM2 input parameter block.
548 @param[in] InputParameterBlock Pointer to the TPM2 input parameter block.
549 @param[in,out] OutputParameterBlockSize Size of the TPM2 output parameter block.
550 @param[in] OutputParameterBlock Pointer to the TPM2 output parameter block.
552 @retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received.
553 @retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device.
554 @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small.
559 IN UINT32 InputParameterBlockSize
,
560 IN UINT8
*InputParameterBlock
,
561 IN OUT UINT32
*OutputParameterBlockSize
,
562 IN UINT8
*OutputParameterBlock
565 TPM2_PTP_INTERFACE_TYPE PtpInterface
;
567 PtpInterface
= PcdGet8(PcdActiveTpmInterfaceType
);
568 switch (PtpInterface
) {
569 case Tpm2PtpInterfaceCrb
:
570 return PtpCrbTpmCommand (
571 (PTP_CRB_REGISTERS_PTR
) (UINTN
) PcdGet64 (PcdTpmBaseAddress
),
573 InputParameterBlockSize
,
574 OutputParameterBlock
,
575 OutputParameterBlockSize
577 case Tpm2PtpInterfaceFifo
:
578 case Tpm2PtpInterfaceTis
:
579 return Tpm2TisTpmCommand (
580 (TIS_PC_REGISTERS_PTR
) (UINTN
) PcdGet64 (PcdTpmBaseAddress
),
582 InputParameterBlockSize
,
583 OutputParameterBlock
,
584 OutputParameterBlockSize
587 return EFI_NOT_FOUND
;
592 This service requests use TPM2.
594 @retval EFI_SUCCESS Get the control of TPM2 chip.
595 @retval EFI_NOT_FOUND TPM2 not found.
596 @retval EFI_DEVICE_ERROR Unexpected device behavior.
604 TPM2_PTP_INTERFACE_TYPE PtpInterface
;
606 PtpInterface
= PcdGet8(PcdActiveTpmInterfaceType
);
607 switch (PtpInterface
) {
608 case Tpm2PtpInterfaceCrb
:
609 return PtpCrbRequestUseTpm ((PTP_CRB_REGISTERS_PTR
) (UINTN
) PcdGet64 (PcdTpmBaseAddress
));
610 case Tpm2PtpInterfaceFifo
:
611 case Tpm2PtpInterfaceTis
:
612 return TisPcRequestUseTpm ((TIS_PC_REGISTERS_PTR
) (UINTN
) PcdGet64 (PcdTpmBaseAddress
));
614 return EFI_NOT_FOUND
;