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>
36 // Execution of the command may take from several seconds to minutes for certain
37 // commands, such as key generation.
39 #define PTP_TIMEOUT_MAX (90000 * 1000) // 90s
42 // Max TPM command/reponse length
44 #define TPMCMDBUFLENGTH 0x500
47 Check whether TPM PTP register exist.
49 @param[in] Reg Pointer to PTP register.
51 @retval TRUE TPM PTP exists.
52 @retval FALSE TPM PTP is not found.
61 RegRead
= MmioRead8 ((UINTN
)Reg
);
62 if (RegRead
== 0xFF) {
72 Check whether the value of a TPM chip register satisfies the input BIT setting.
74 @param[in] Register Address port of register to be checked.
75 @param[in] BitSet Check these data bits are set.
76 @param[in] BitClear Check these data bits are clear.
77 @param[in] TimeOut The max wait time (unit MicroSecond) when checking register.
79 @retval EFI_SUCCESS The register satisfies the check bit.
80 @retval EFI_TIMEOUT The register can't run into the expected status in time.
83 PtpCrbWaitRegisterBits (
93 for (WaitTime
= 0; WaitTime
< TimeOut
; WaitTime
+= 30){
94 RegRead
= MmioRead32 ((UINTN
)Register
);
95 if ((RegRead
& BitSet
) == BitSet
&& (RegRead
& BitClear
) == 0) {
98 MicroSecondDelay (30);
104 Get the control of TPM chip.
106 @param[in] CrbReg Pointer to CRB register.
108 @retval EFI_SUCCESS Get the control of TPM chip.
109 @retval EFI_INVALID_PARAMETER CrbReg is NULL.
110 @retval EFI_NOT_FOUND TPM chip doesn't exit.
111 @retval EFI_TIMEOUT Can't get the TPM control in time.
114 PtpCrbRequestUseTpm (
115 IN PTP_CRB_REGISTERS_PTR CrbReg
120 if (!Tpm2IsPtpPresence (CrbReg
)) {
121 return EFI_NOT_FOUND
;
124 MmioWrite32((UINTN
)&CrbReg
->LocalityControl
, PTP_CRB_LOCALITY_CONTROL_REQUEST_ACCESS
);
125 Status
= PtpCrbWaitRegisterBits (
126 &CrbReg
->LocalityStatus
,
127 PTP_CRB_LOCALITY_STATUS_GRANTED
,
135 Send a command to TPM for execution and return response data.
137 @param[in] CrbReg TPM register space base address.
138 @param[in] BufferIn Buffer for command data.
139 @param[in] SizeIn Size of command data.
140 @param[in, out] BufferOut Buffer for response data.
141 @param[in, out] SizeOut Size of response data.
143 @retval EFI_SUCCESS Operation completed successfully.
144 @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small.
145 @retval EFI_DEVICE_ERROR Unexpected device behavior.
146 @retval EFI_UNSUPPORTED Unsupported TPM version
151 IN PTP_CRB_REGISTERS_PTR CrbReg
,
154 IN OUT UINT8
*BufferOut
,
155 IN OUT UINT32
*SizeOut
167 DEBUG ((EFI_D_VERBOSE
, "PtpCrbTpmCommand Send - "));
168 if (SizeIn
> 0x100) {
173 for (Index
= 0; Index
< DebugSize
; Index
++) {
174 DEBUG ((EFI_D_VERBOSE
, "%02x ", BufferIn
[Index
]));
176 if (DebugSize
!= SizeIn
) {
177 DEBUG ((EFI_D_VERBOSE
, "...... "));
178 for (Index
= SizeIn
- 0x20; Index
< SizeIn
; Index
++) {
179 DEBUG ((EFI_D_VERBOSE
, "%02x ", BufferIn
[Index
]));
182 DEBUG ((EFI_D_VERBOSE
, "\n"));
188 // Ready is any time the TPM is ready to receive a command, following a write
189 // of 1 by software to Request.cmdReady, as indicated by the Status field
190 // being cleared to 0.
192 MmioWrite32((UINTN
)&CrbReg
->CrbControlRequest
, PTP_CRB_CONTROL_AREA_REQUEST_COMMAND_READY
);
193 Status
= PtpCrbWaitRegisterBits (
194 &CrbReg
->CrbControlRequest
,
196 PTP_CRB_CONTROL_AREA_REQUEST_COMMAND_READY
,
199 if (EFI_ERROR (Status
)) {
200 Status
= EFI_DEVICE_ERROR
;
203 Status
= PtpCrbWaitRegisterBits (
204 &CrbReg
->CrbControlStatus
,
206 PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE
,
209 if (EFI_ERROR (Status
)) {
210 Status
= EFI_DEVICE_ERROR
;
216 // Command Reception occurs following a Ready state between the write of the
217 // first byte of a command to the Command Buffer and the receipt of a write
220 for (Index
= 0; Index
< SizeIn
; Index
++) {
221 MmioWrite8 ((UINTN
)&CrbReg
->CrbDataBuffer
[Index
], BufferIn
[Index
]);
223 MmioWrite32 ((UINTN
)&CrbReg
->CrbControlCommandAddressHigh
, (UINT32
)RShiftU64 ((UINTN
)CrbReg
->CrbDataBuffer
, 32));
224 MmioWrite32 ((UINTN
)&CrbReg
->CrbControlCommandAddressLow
, (UINT32
)(UINTN
)CrbReg
->CrbDataBuffer
);
225 MmioWrite32 ((UINTN
)&CrbReg
->CrbControlCommandSize
, sizeof(CrbReg
->CrbDataBuffer
));
227 MmioWrite64 ((UINTN
)&CrbReg
->CrbControlResponseAddrss
, (UINT32
)(UINTN
)CrbReg
->CrbDataBuffer
);
228 MmioWrite32 ((UINTN
)&CrbReg
->CrbControlResponseSize
, sizeof(CrbReg
->CrbDataBuffer
));
232 // Command Execution occurs after receipt of a 1 to Start and the TPM
233 // clearing Start to 0.
235 MmioWrite32((UINTN
)&CrbReg
->CrbControlStart
, PTP_CRB_CONTROL_START
);
236 Status
= PtpCrbWaitRegisterBits (
237 &CrbReg
->CrbControlStart
,
239 PTP_CRB_CONTROL_START
,
242 if (EFI_ERROR (Status
)) {
244 // Command Completion check timeout. Cancel the currently executing command by writing TPM_CRB_CTRL_CANCEL,
245 // Expect TPM_RC_CANCELLED or successfully completed response.
247 MmioWrite32((UINTN
)&CrbReg
->CrbControlCancel
, PTP_CRB_CONTROL_CANCEL
);
248 Status
= PtpCrbWaitRegisterBits (
249 &CrbReg
->CrbControlStart
,
251 PTP_CRB_CONTROL_START
,
254 MmioWrite32((UINTN
)&CrbReg
->CrbControlCancel
, 0);
256 if (EFI_ERROR(Status
)) {
258 // Still in Command Execution state. Try to goIdle, the behavior is agnostic.
260 Status
= EFI_DEVICE_ERROR
;
267 // Command Completion occurs after completion of a command (indicated by the
268 // TPM clearing TPM_CRB_CTRL_Start_x to 0) and before a write of a 1 by the
269 // software to Request.goIdle.
273 // Get response data header
275 for (Index
= 0; Index
< sizeof (TPM2_RESPONSE_HEADER
); Index
++) {
276 BufferOut
[Index
] = MmioRead8 ((UINTN
)&CrbReg
->CrbDataBuffer
[Index
]);
279 DEBUG ((EFI_D_VERBOSE
, "PtpCrbTpmCommand ReceiveHeader - "));
280 for (Index
= 0; Index
< sizeof (TPM2_RESPONSE_HEADER
); Index
++) {
281 DEBUG ((EFI_D_VERBOSE
, "%02x ", BufferOut
[Index
]));
283 DEBUG ((EFI_D_VERBOSE
, "\n"));
286 // Check the reponse data header (tag, parasize and returncode)
288 CopyMem (&Data16
, BufferOut
, sizeof (UINT16
));
289 // TPM2 should not use this RSP_COMMAND
290 if (SwapBytes16 (Data16
) == TPM_ST_RSP_COMMAND
) {
291 DEBUG ((EFI_D_ERROR
, "TPM2: TPM_ST_RSP error - %x\n", TPM_ST_RSP_COMMAND
));
292 Status
= EFI_UNSUPPORTED
;
296 CopyMem (&Data32
, (BufferOut
+ 2), sizeof (UINT32
));
297 TpmOutSize
= SwapBytes32 (Data32
);
298 if (*SizeOut
< TpmOutSize
) {
299 Status
= EFI_BUFFER_TOO_SMALL
;
302 *SizeOut
= TpmOutSize
;
304 // Continue reading the remaining data
306 for (Index
= sizeof (TPM2_RESPONSE_HEADER
); Index
< TpmOutSize
; Index
++) {
307 BufferOut
[Index
] = MmioRead8 ((UINTN
)&CrbReg
->CrbDataBuffer
[Index
]);
311 DEBUG ((EFI_D_VERBOSE
, "PtpCrbTpmCommand Receive - "));
312 for (Index
= 0; Index
< TpmOutSize
; Index
++) {
313 DEBUG ((EFI_D_VERBOSE
, "%02x ", BufferOut
[Index
]));
315 DEBUG ((EFI_D_VERBOSE
, "\n"));
320 // Idle is any time TPM_CRB_CTRL_STS_x.Status.goIdle is 1.
322 MmioWrite32((UINTN
)&CrbReg
->CrbControlRequest
, PTP_CRB_CONTROL_AREA_REQUEST_GO_IDLE
);
327 Send a command to TPM for execution and return response data.
329 @param[in] TisReg TPM register space base address.
330 @param[in] BufferIn Buffer for command data.
331 @param[in] SizeIn Size of command data.
332 @param[in, out] BufferOut Buffer for response data.
333 @param[in, out] SizeOut Size of response data.
335 @retval EFI_SUCCESS Operation completed successfully.
336 @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small.
337 @retval EFI_DEVICE_ERROR Unexpected device behavior.
338 @retval EFI_UNSUPPORTED Unsupported TPM version
343 IN TIS_PC_REGISTERS_PTR TisReg
,
346 IN OUT UINT8
*BufferOut
,
347 IN OUT UINT32
*SizeOut
351 Get the control of TPM chip by sending requestUse command TIS_PC_ACC_RQUUSE
352 to ACCESS Register in the time of default TIS_TIMEOUT_A.
354 @param[in] TisReg Pointer to TIS register.
356 @retval EFI_SUCCESS Get the control of TPM chip.
357 @retval EFI_INVALID_PARAMETER TisReg is NULL.
358 @retval EFI_NOT_FOUND TPM chip doesn't exit.
359 @retval EFI_TIMEOUT Can't get the TPM control in time.
363 IN TIS_PC_REGISTERS_PTR TisReg
367 Return PTP interface type.
369 @param[in] Register Pointer to PTP register.
371 @return PTP interface type.
374 Tpm2GetPtpInterface (
378 PTP_CRB_INTERFACE_IDENTIFIER InterfaceId
;
379 PTP_FIFO_INTERFACE_CAPABILITY InterfaceCapability
;
381 if (!Tpm2IsPtpPresence (Register
)) {
382 return PtpInterfaceMax
;
385 // Check interface id
387 InterfaceId
.Uint32
= MmioRead32 ((UINTN
)&((PTP_CRB_REGISTERS
*)Register
)->InterfaceId
);
388 InterfaceCapability
.Uint32
= MmioRead32 ((UINTN
)&((PTP_FIFO_REGISTERS
*)Register
)->InterfaceCapability
);
390 if ((InterfaceId
.Bits
.InterfaceType
== PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_CRB
) &&
391 (InterfaceId
.Bits
.InterfaceVersion
== PTP_INTERFACE_IDENTIFIER_INTERFACE_VERSION_CRB
) &&
392 (InterfaceId
.Bits
.CapCRB
!= 0)) {
393 return PtpInterfaceCrb
;
395 if ((InterfaceId
.Bits
.InterfaceType
== PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_FIFO
) &&
396 (InterfaceId
.Bits
.InterfaceVersion
== PTP_INTERFACE_IDENTIFIER_INTERFACE_VERSION_FIFO
) &&
397 (InterfaceId
.Bits
.CapFIFO
!= 0) &&
398 (InterfaceCapability
.Bits
.InterfaceVersion
== INTERFACE_CAPABILITY_INTERFACE_VERSION_PTP
)) {
399 return PtpInterfaceFifo
;
401 return PtpInterfaceTis
;
405 Dump PTP register information.
407 @param[in] Register Pointer to PTP register.
414 PTP_CRB_INTERFACE_IDENTIFIER InterfaceId
;
415 PTP_FIFO_INTERFACE_CAPABILITY InterfaceCapability
;
420 PTP_INTERFACE_TYPE PtpInterface
;
422 if (!Tpm2IsPtpPresence (Register
)) {
426 InterfaceId
.Uint32
= MmioRead32 ((UINTN
)&((PTP_CRB_REGISTERS
*)Register
)->InterfaceId
);
427 InterfaceCapability
.Uint32
= MmioRead32 ((UINTN
)&((PTP_FIFO_REGISTERS
*)Register
)->InterfaceCapability
);
428 StatusEx
= MmioRead8 ((UINTN
)&((PTP_FIFO_REGISTERS
*)Register
)->StatusEx
);
431 // Dump InterfaceId Register for PTP
433 DEBUG ((EFI_D_INFO
, "InterfaceId - 0x%08x\n", InterfaceId
.Uint32
));
434 DEBUG ((EFI_D_INFO
, " InterfaceType - 0x%02x\n", InterfaceId
.Bits
.InterfaceType
));
435 if (InterfaceId
.Bits
.InterfaceType
!= PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_TIS
) {
436 DEBUG ((EFI_D_INFO
, " InterfaceVersion - 0x%02x\n", InterfaceId
.Bits
.InterfaceVersion
));
437 DEBUG ((EFI_D_INFO
, " CapFIFO - 0x%x\n", InterfaceId
.Bits
.CapFIFO
));
438 DEBUG ((EFI_D_INFO
, " CapCRB - 0x%x\n", InterfaceId
.Bits
.CapCRB
));
442 // Dump Capability Register for TIS and FIFO
444 DEBUG ((EFI_D_INFO
, "InterfaceCapability - 0x%08x\n", InterfaceCapability
.Uint32
));
445 if ((InterfaceId
.Bits
.InterfaceType
== PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_TIS
) ||
446 (InterfaceId
.Bits
.InterfaceType
== PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_FIFO
)) {
447 DEBUG ((EFI_D_INFO
, " InterfaceVersion - 0x%x\n", InterfaceCapability
.Bits
.InterfaceVersion
));
451 // Dump StatusEx Register for PTP FIFO
453 DEBUG ((EFI_D_INFO
, "StatusEx - 0x%02x\n", StatusEx
));
454 if (InterfaceCapability
.Bits
.InterfaceVersion
== INTERFACE_CAPABILITY_INTERFACE_VERSION_PTP
) {
455 DEBUG ((EFI_D_INFO
, " TpmFamily - 0x%x\n", (StatusEx
& PTP_FIFO_STS_EX_TPM_FAMILY
) >> PTP_FIFO_STS_EX_TPM_FAMILY_OFFSET
));
461 PtpInterface
= Tpm2GetPtpInterface (Register
);
462 DEBUG ((EFI_D_INFO
, "PtpInterface - %x\n", PtpInterface
));
463 switch (PtpInterface
) {
464 case PtpInterfaceCrb
:
465 Vid
= MmioRead16 ((UINTN
)&((PTP_CRB_REGISTERS
*)Register
)->Vid
);
466 Did
= MmioRead16 ((UINTN
)&((PTP_CRB_REGISTERS
*)Register
)->Did
);
467 Rid
= (UINT8
)InterfaceId
.Bits
.Rid
;
469 case PtpInterfaceFifo
:
470 case PtpInterfaceTis
:
471 Vid
= MmioRead16 ((UINTN
)&((PTP_FIFO_REGISTERS
*)Register
)->Vid
);
472 Did
= MmioRead16 ((UINTN
)&((PTP_FIFO_REGISTERS
*)Register
)->Did
);
473 Rid
= MmioRead8 ((UINTN
)&((PTP_FIFO_REGISTERS
*)Register
)->Rid
);
478 DEBUG ((EFI_D_INFO
, "VID - 0x%04x\n", Vid
));
479 DEBUG ((EFI_D_INFO
, "DID - 0x%04x\n", Did
));
480 DEBUG ((EFI_D_INFO
, "RID - 0x%02x\n", Rid
));
484 This service enables the sending of commands to the TPM2.
486 @param[in] InputParameterBlockSize Size of the TPM2 input parameter block.
487 @param[in] InputParameterBlock Pointer to the TPM2 input parameter block.
488 @param[in,out] OutputParameterBlockSize Size of the TPM2 output parameter block.
489 @param[in] OutputParameterBlock Pointer to the TPM2 output parameter block.
491 @retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received.
492 @retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device.
493 @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small.
498 IN UINT32 InputParameterBlockSize
,
499 IN UINT8
*InputParameterBlock
,
500 IN OUT UINT32
*OutputParameterBlockSize
,
501 IN UINT8
*OutputParameterBlock
504 PTP_INTERFACE_TYPE PtpInterface
;
506 PtpInterface
= Tpm2GetPtpInterface ((VOID
*) (UINTN
) PcdGet64 (PcdTpmBaseAddress
));
507 switch (PtpInterface
) {
508 case PtpInterfaceCrb
:
509 return PtpCrbTpmCommand (
510 (PTP_CRB_REGISTERS_PTR
) (UINTN
) PcdGet64 (PcdTpmBaseAddress
),
512 InputParameterBlockSize
,
513 OutputParameterBlock
,
514 OutputParameterBlockSize
516 case PtpInterfaceFifo
:
517 case PtpInterfaceTis
:
518 return Tpm2TisTpmCommand (
519 (TIS_PC_REGISTERS_PTR
) (UINTN
) PcdGet64 (PcdTpmBaseAddress
),
521 InputParameterBlockSize
,
522 OutputParameterBlock
,
523 OutputParameterBlockSize
526 return EFI_NOT_FOUND
;
531 This service requests use TPM2.
533 @retval EFI_SUCCESS Get the control of TPM2 chip.
534 @retval EFI_NOT_FOUND TPM2 not found.
535 @retval EFI_DEVICE_ERROR Unexpected device behavior.
543 PTP_INTERFACE_TYPE PtpInterface
;
545 PtpInterface
= Tpm2GetPtpInterface ((VOID
*) (UINTN
) PcdGet64 (PcdTpmBaseAddress
));
546 switch (PtpInterface
) {
547 case PtpInterfaceCrb
:
548 return PtpCrbRequestUseTpm ((PTP_CRB_REGISTERS_PTR
) (UINTN
) PcdGet64 (PcdTpmBaseAddress
));
549 case PtpInterfaceFifo
:
550 case PtpInterfaceTis
:
551 return TisPcRequestUseTpm ((TIS_PC_REGISTERS_PTR
) (UINTN
) PcdGet64 (PcdTpmBaseAddress
));
553 return EFI_NOT_FOUND
;