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 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include <IndustryStandard/Tpm20.h>
17 #include <Library/BaseLib.h>
18 #include <Library/BaseMemoryLib.h>
19 #include <Library/IoLib.h>
20 #include <Library/TimerLib.h>
21 #include <Library/DebugLib.h>
22 #include <Library/Tpm2DeviceLib.h>
23 #include <Library/PcdLib.h>
25 #include <IndustryStandard/TpmPtp.h>
26 #include <IndustryStandard/TpmTis.h>
29 // Execution of the command may take from several seconds to minutes for certain
30 // commands, such as key generation.
32 #define PTP_TIMEOUT_MAX (90000 * 1000) // 90s
35 // Max TPM command/reponse length
37 #define TPMCMDBUFLENGTH 0x500
40 Check whether TPM PTP register exist.
42 @param[in] Reg Pointer to PTP register.
44 @retval TRUE TPM PTP exists.
45 @retval FALSE TPM PTP is not found.
54 RegRead
= MmioRead8 ((UINTN
)Reg
);
55 if (RegRead
== 0xFF) {
65 Check whether the value of a TPM chip register satisfies the input BIT setting.
67 @param[in] Register Address port of register to be checked.
68 @param[in] BitSet Check these data bits are set.
69 @param[in] BitClear Check these data bits are clear.
70 @param[in] TimeOut The max wait time (unit MicroSecond) when checking register.
72 @retval EFI_SUCCESS The register satisfies the check bit.
73 @retval EFI_TIMEOUT The register can't run into the expected status in time.
76 PtpCrbWaitRegisterBits (
86 for (WaitTime
= 0; WaitTime
< TimeOut
; WaitTime
+= 30){
87 RegRead
= MmioRead32 ((UINTN
)Register
);
88 if ((RegRead
& BitSet
) == BitSet
&& (RegRead
& BitClear
) == 0) {
91 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 ((EFI_D_VERBOSE
, "PtpCrbTpmCommand Send - "));
161 if (SizeIn
> 0x100) {
166 for (Index
= 0; Index
< DebugSize
; Index
++) {
167 DEBUG ((EFI_D_VERBOSE
, "%02x ", BufferIn
[Index
]));
169 if (DebugSize
!= SizeIn
) {
170 DEBUG ((EFI_D_VERBOSE
, "...... "));
171 for (Index
= SizeIn
- 0x20; Index
< SizeIn
; Index
++) {
172 DEBUG ((EFI_D_VERBOSE
, "%02x ", BufferIn
[Index
]));
175 DEBUG ((EFI_D_VERBOSE
, "\n"));
181 // if CapCRbIdelByPass == 0, enforce Idle state before sending command
183 if (PcdGet8(PcdCRBIdleByPass
) == 0 && (MmioRead32((UINTN
)&CrbReg
->CrbControlStatus
) & PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE
) == 0){
184 Status
= PtpCrbWaitRegisterBits (
185 &CrbReg
->CrbControlStatus
,
186 PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE
,
190 if (EFI_ERROR (Status
)) {
192 // Try to goIdle to recover TPM
194 Status
= EFI_DEVICE_ERROR
;
201 // Ready is any time the TPM is ready to receive a command, following a write
202 // of 1 by software to Request.cmdReady, as indicated by the Status field
203 // being cleared to 0.
205 MmioWrite32((UINTN
)&CrbReg
->CrbControlRequest
, PTP_CRB_CONTROL_AREA_REQUEST_COMMAND_READY
);
206 Status
= PtpCrbWaitRegisterBits (
207 &CrbReg
->CrbControlRequest
,
209 PTP_CRB_CONTROL_AREA_REQUEST_COMMAND_READY
,
212 if (EFI_ERROR (Status
)) {
213 Status
= EFI_DEVICE_ERROR
;
216 Status
= PtpCrbWaitRegisterBits (
217 &CrbReg
->CrbControlStatus
,
219 PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE
,
222 if (EFI_ERROR (Status
)) {
223 Status
= EFI_DEVICE_ERROR
;
229 // Command Reception occurs following a Ready state between the write of the
230 // first byte of a command to the Command Buffer and the receipt of a write
233 for (Index
= 0; Index
< SizeIn
; Index
++) {
234 MmioWrite8 ((UINTN
)&CrbReg
->CrbDataBuffer
[Index
], BufferIn
[Index
]);
236 MmioWrite32 ((UINTN
)&CrbReg
->CrbControlCommandAddressHigh
, (UINT32
)RShiftU64 ((UINTN
)CrbReg
->CrbDataBuffer
, 32));
237 MmioWrite32 ((UINTN
)&CrbReg
->CrbControlCommandAddressLow
, (UINT32
)(UINTN
)CrbReg
->CrbDataBuffer
);
238 MmioWrite32 ((UINTN
)&CrbReg
->CrbControlCommandSize
, sizeof(CrbReg
->CrbDataBuffer
));
240 MmioWrite64 ((UINTN
)&CrbReg
->CrbControlResponseAddrss
, (UINT32
)(UINTN
)CrbReg
->CrbDataBuffer
);
241 MmioWrite32 ((UINTN
)&CrbReg
->CrbControlResponseSize
, sizeof(CrbReg
->CrbDataBuffer
));
245 // Command Execution occurs after receipt of a 1 to Start and the TPM
246 // clearing Start to 0.
248 MmioWrite32((UINTN
)&CrbReg
->CrbControlStart
, PTP_CRB_CONTROL_START
);
249 Status
= PtpCrbWaitRegisterBits (
250 &CrbReg
->CrbControlStart
,
252 PTP_CRB_CONTROL_START
,
255 if (EFI_ERROR (Status
)) {
257 // Command Completion check timeout. Cancel the currently executing command by writing TPM_CRB_CTRL_CANCEL,
258 // Expect TPM_RC_CANCELLED or successfully completed response.
260 MmioWrite32((UINTN
)&CrbReg
->CrbControlCancel
, PTP_CRB_CONTROL_CANCEL
);
261 Status
= PtpCrbWaitRegisterBits (
262 &CrbReg
->CrbControlStart
,
264 PTP_CRB_CONTROL_START
,
267 MmioWrite32((UINTN
)&CrbReg
->CrbControlCancel
, 0);
269 if (EFI_ERROR(Status
)) {
271 // Still in Command Execution state. Try to goIdle, the behavior is agnostic.
273 Status
= EFI_DEVICE_ERROR
;
280 // Command Completion occurs after completion of a command (indicated by the
281 // TPM clearing TPM_CRB_CTRL_Start_x to 0) and before a write of a 1 by the
282 // software to Request.goIdle.
286 // Get response data header
288 for (Index
= 0; Index
< sizeof (TPM2_RESPONSE_HEADER
); Index
++) {
289 BufferOut
[Index
] = MmioRead8 ((UINTN
)&CrbReg
->CrbDataBuffer
[Index
]);
292 DEBUG ((EFI_D_VERBOSE
, "PtpCrbTpmCommand ReceiveHeader - "));
293 for (Index
= 0; Index
< sizeof (TPM2_RESPONSE_HEADER
); Index
++) {
294 DEBUG ((EFI_D_VERBOSE
, "%02x ", BufferOut
[Index
]));
296 DEBUG ((EFI_D_VERBOSE
, "\n"));
299 // Check the reponse data header (tag, parasize and returncode)
301 CopyMem (&Data16
, BufferOut
, sizeof (UINT16
));
302 // TPM2 should not use this RSP_COMMAND
303 if (SwapBytes16 (Data16
) == TPM_ST_RSP_COMMAND
) {
304 DEBUG ((EFI_D_ERROR
, "TPM2: TPM_ST_RSP error - %x\n", TPM_ST_RSP_COMMAND
));
305 Status
= EFI_UNSUPPORTED
;
309 CopyMem (&Data32
, (BufferOut
+ 2), sizeof (UINT32
));
310 TpmOutSize
= SwapBytes32 (Data32
);
311 if (*SizeOut
< TpmOutSize
) {
313 // Command completed, but buffer is not enough
315 Status
= EFI_BUFFER_TOO_SMALL
;
318 *SizeOut
= TpmOutSize
;
320 // Continue reading the remaining data
322 for (Index
= sizeof (TPM2_RESPONSE_HEADER
); Index
< TpmOutSize
; Index
++) {
323 BufferOut
[Index
] = MmioRead8 ((UINTN
)&CrbReg
->CrbDataBuffer
[Index
]);
327 DEBUG ((EFI_D_VERBOSE
, "PtpCrbTpmCommand Receive - "));
328 for (Index
= 0; Index
< TpmOutSize
; Index
++) {
329 DEBUG ((EFI_D_VERBOSE
, "%02x ", BufferOut
[Index
]));
331 DEBUG ((EFI_D_VERBOSE
, "\n"));
336 // Goto Ready State if command is completed succesfully and TPM support IdleBypass
337 // If not supported. flow down to GoIdle
339 if (PcdGet8(PcdCRBIdleByPass
) == 1) {
340 MmioWrite32((UINTN
)&CrbReg
->CrbControlRequest
, PTP_CRB_CONTROL_AREA_REQUEST_COMMAND_READY
);
345 // Do not wait for state transition for TIMEOUT_C
346 // This function will try to wait 2 TIMEOUT_C at the beginning in next call.
351 // Return to Idle state by setting TPM_CRB_CTRL_STS_x.Status.goIdle to 1.
353 MmioWrite32((UINTN
)&CrbReg
->CrbControlRequest
, PTP_CRB_CONTROL_AREA_REQUEST_GO_IDLE
);
356 // Only enforce Idle state transition if execution fails when CRBIndleBypass==1
357 // Leave regular Idle delay at the beginning of next command execution
359 if (PcdGet8(PcdCRBIdleByPass
) == 1){
360 Status
= PtpCrbWaitRegisterBits (
361 &CrbReg
->CrbControlStatus
,
362 PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE
,
372 Send a command to TPM for execution and return response data.
374 @param[in] TisReg TPM register space base address.
375 @param[in] BufferIn Buffer for command data.
376 @param[in] SizeIn Size of command data.
377 @param[in, out] BufferOut Buffer for response data.
378 @param[in, out] SizeOut Size of response data.
380 @retval EFI_SUCCESS Operation completed successfully.
381 @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small.
382 @retval EFI_DEVICE_ERROR Unexpected device behavior.
383 @retval EFI_UNSUPPORTED Unsupported TPM version
388 IN TIS_PC_REGISTERS_PTR TisReg
,
391 IN OUT UINT8
*BufferOut
,
392 IN OUT UINT32
*SizeOut
396 Get the control of TPM chip by sending requestUse command TIS_PC_ACC_RQUUSE
397 to ACCESS Register in the time of default TIS_TIMEOUT_A.
399 @param[in] TisReg Pointer to TIS register.
401 @retval EFI_SUCCESS Get the control of TPM chip.
402 @retval EFI_INVALID_PARAMETER TisReg is NULL.
403 @retval EFI_NOT_FOUND TPM chip doesn't exit.
404 @retval EFI_TIMEOUT Can't get the TPM control in time.
408 IN TIS_PC_REGISTERS_PTR TisReg
412 Return PTP interface type.
414 @param[in] Register Pointer to PTP register.
416 @return PTP interface type.
418 TPM2_PTP_INTERFACE_TYPE
419 Tpm2GetPtpInterface (
423 PTP_CRB_INTERFACE_IDENTIFIER InterfaceId
;
424 PTP_FIFO_INTERFACE_CAPABILITY InterfaceCapability
;
426 if (!Tpm2IsPtpPresence (Register
)) {
427 return Tpm2PtpInterfaceMax
;
430 // Check interface id
432 InterfaceId
.Uint32
= MmioRead32 ((UINTN
)&((PTP_CRB_REGISTERS
*)Register
)->InterfaceId
);
433 InterfaceCapability
.Uint32
= MmioRead32 ((UINTN
)&((PTP_FIFO_REGISTERS
*)Register
)->InterfaceCapability
);
435 if ((InterfaceId
.Bits
.InterfaceType
== PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_CRB
) &&
436 (InterfaceId
.Bits
.InterfaceVersion
== PTP_INTERFACE_IDENTIFIER_INTERFACE_VERSION_CRB
) &&
437 (InterfaceId
.Bits
.CapCRB
!= 0)) {
438 return Tpm2PtpInterfaceCrb
;
440 if ((InterfaceId
.Bits
.InterfaceType
== PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_FIFO
) &&
441 (InterfaceId
.Bits
.InterfaceVersion
== PTP_INTERFACE_IDENTIFIER_INTERFACE_VERSION_FIFO
) &&
442 (InterfaceId
.Bits
.CapFIFO
!= 0) &&
443 (InterfaceCapability
.Bits
.InterfaceVersion
== INTERFACE_CAPABILITY_INTERFACE_VERSION_PTP
)) {
444 return Tpm2PtpInterfaceFifo
;
446 return Tpm2PtpInterfaceTis
;
450 Return PTP CRB interface IdleByPass state.
452 @param[in] Register Pointer to PTP register.
454 @return PTP CRB interface IdleByPass state.
461 PTP_CRB_INTERFACE_IDENTIFIER InterfaceId
;
464 // Check interface id
466 InterfaceId
.Uint32
= MmioRead32 ((UINTN
)&((PTP_CRB_REGISTERS
*)Register
)->InterfaceId
);
468 return (UINT8
)(InterfaceId
.Bits
.CapCRBIdleBypass
);
472 Dump PTP register information.
474 @param[in] Register Pointer to PTP register.
481 PTP_CRB_INTERFACE_IDENTIFIER InterfaceId
;
482 PTP_FIFO_INTERFACE_CAPABILITY InterfaceCapability
;
487 TPM2_PTP_INTERFACE_TYPE PtpInterface
;
489 if (!Tpm2IsPtpPresence (Register
)) {
493 InterfaceId
.Uint32
= MmioRead32 ((UINTN
)&((PTP_CRB_REGISTERS
*)Register
)->InterfaceId
);
494 InterfaceCapability
.Uint32
= MmioRead32 ((UINTN
)&((PTP_FIFO_REGISTERS
*)Register
)->InterfaceCapability
);
495 StatusEx
= MmioRead8 ((UINTN
)&((PTP_FIFO_REGISTERS
*)Register
)->StatusEx
);
498 // Dump InterfaceId Register for PTP
500 DEBUG ((EFI_D_INFO
, "InterfaceId - 0x%08x\n", InterfaceId
.Uint32
));
501 DEBUG ((EFI_D_INFO
, " InterfaceType - 0x%02x\n", InterfaceId
.Bits
.InterfaceType
));
502 if (InterfaceId
.Bits
.InterfaceType
!= PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_TIS
) {
503 DEBUG ((EFI_D_INFO
, " InterfaceVersion - 0x%02x\n", InterfaceId
.Bits
.InterfaceVersion
));
504 DEBUG ((EFI_D_INFO
, " CapFIFO - 0x%x\n", InterfaceId
.Bits
.CapFIFO
));
505 DEBUG ((EFI_D_INFO
, " CapCRB - 0x%x\n", InterfaceId
.Bits
.CapCRB
));
509 // Dump Capability Register for TIS and FIFO
511 DEBUG ((EFI_D_INFO
, "InterfaceCapability - 0x%08x\n", InterfaceCapability
.Uint32
));
512 if ((InterfaceId
.Bits
.InterfaceType
== PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_TIS
) ||
513 (InterfaceId
.Bits
.InterfaceType
== PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_FIFO
)) {
514 DEBUG ((EFI_D_INFO
, " InterfaceVersion - 0x%x\n", InterfaceCapability
.Bits
.InterfaceVersion
));
518 // Dump StatusEx Register for PTP FIFO
520 DEBUG ((EFI_D_INFO
, "StatusEx - 0x%02x\n", StatusEx
));
521 if (InterfaceCapability
.Bits
.InterfaceVersion
== INTERFACE_CAPABILITY_INTERFACE_VERSION_PTP
) {
522 DEBUG ((EFI_D_INFO
, " TpmFamily - 0x%x\n", (StatusEx
& PTP_FIFO_STS_EX_TPM_FAMILY
) >> PTP_FIFO_STS_EX_TPM_FAMILY_OFFSET
));
528 PtpInterface
= PcdGet8(PcdActiveTpmInterfaceType
);
529 DEBUG ((EFI_D_INFO
, "PtpInterface - %x\n", PtpInterface
));
530 switch (PtpInterface
) {
531 case Tpm2PtpInterfaceCrb
:
532 Vid
= MmioRead16 ((UINTN
)&((PTP_CRB_REGISTERS
*)Register
)->Vid
);
533 Did
= MmioRead16 ((UINTN
)&((PTP_CRB_REGISTERS
*)Register
)->Did
);
534 Rid
= (UINT8
)InterfaceId
.Bits
.Rid
;
536 case Tpm2PtpInterfaceFifo
:
537 case Tpm2PtpInterfaceTis
:
538 Vid
= MmioRead16 ((UINTN
)&((PTP_FIFO_REGISTERS
*)Register
)->Vid
);
539 Did
= MmioRead16 ((UINTN
)&((PTP_FIFO_REGISTERS
*)Register
)->Did
);
540 Rid
= MmioRead8 ((UINTN
)&((PTP_FIFO_REGISTERS
*)Register
)->Rid
);
545 DEBUG ((EFI_D_INFO
, "VID - 0x%04x\n", Vid
));
546 DEBUG ((EFI_D_INFO
, "DID - 0x%04x\n", Did
));
547 DEBUG ((EFI_D_INFO
, "RID - 0x%02x\n", Rid
));
551 This service enables the sending of commands to the TPM2.
553 @param[in] InputParameterBlockSize Size of the TPM2 input parameter block.
554 @param[in] InputParameterBlock Pointer to the TPM2 input parameter block.
555 @param[in,out] OutputParameterBlockSize Size of the TPM2 output parameter block.
556 @param[in] OutputParameterBlock Pointer to the TPM2 output parameter block.
558 @retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received.
559 @retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device.
560 @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small.
565 IN UINT32 InputParameterBlockSize
,
566 IN UINT8
*InputParameterBlock
,
567 IN OUT UINT32
*OutputParameterBlockSize
,
568 IN UINT8
*OutputParameterBlock
571 TPM2_PTP_INTERFACE_TYPE PtpInterface
;
573 PtpInterface
= PcdGet8(PcdActiveTpmInterfaceType
);
574 switch (PtpInterface
) {
575 case Tpm2PtpInterfaceCrb
:
576 return PtpCrbTpmCommand (
577 (PTP_CRB_REGISTERS_PTR
) (UINTN
) PcdGet64 (PcdTpmBaseAddress
),
579 InputParameterBlockSize
,
580 OutputParameterBlock
,
581 OutputParameterBlockSize
583 case Tpm2PtpInterfaceFifo
:
584 case Tpm2PtpInterfaceTis
:
585 return Tpm2TisTpmCommand (
586 (TIS_PC_REGISTERS_PTR
) (UINTN
) PcdGet64 (PcdTpmBaseAddress
),
588 InputParameterBlockSize
,
589 OutputParameterBlock
,
590 OutputParameterBlockSize
593 return EFI_NOT_FOUND
;
598 This service requests use TPM2.
600 @retval EFI_SUCCESS Get the control of TPM2 chip.
601 @retval EFI_NOT_FOUND TPM2 not found.
602 @retval EFI_DEVICE_ERROR Unexpected device behavior.
610 TPM2_PTP_INTERFACE_TYPE PtpInterface
;
612 PtpInterface
= PcdGet8(PcdActiveTpmInterfaceType
);
613 switch (PtpInterface
) {
614 case Tpm2PtpInterfaceCrb
:
615 return PtpCrbRequestUseTpm ((PTP_CRB_REGISTERS_PTR
) (UINTN
) PcdGet64 (PcdTpmBaseAddress
));
616 case Tpm2PtpInterfaceFifo
:
617 case Tpm2PtpInterfaceTis
:
618 return TisPcRequestUseTpm ((TIS_PC_REGISTERS_PTR
) (UINTN
) PcdGet64 (PcdTpmBaseAddress
));
620 return EFI_NOT_FOUND
;