aboutsummaryrefslogtreecommitdiffstats
path: root/roms/edk2/SecurityPkg/Library/Tpm2DeviceLibDTpm
diff options
context:
space:
mode:
Diffstat (limited to 'roms/edk2/SecurityPkg/Library/Tpm2DeviceLibDTpm')
-rw-r--r--roms/edk2/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.c165
-rw-r--r--roms/edk2/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.inf53
-rw-r--r--roms/edk2/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.uni19
-rw-r--r--roms/edk2/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.c132
-rw-r--r--roms/edk2/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.inf49
-rw-r--r--roms/edk2/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.uni18
-rw-r--r--roms/edk2/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2Ptp.c616
-rw-r--r--roms/edk2/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2Tis.c434
8 files changed, 1486 insertions, 0 deletions
diff --git a/roms/edk2/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.c b/roms/edk2/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.c
new file mode 100644
index 000000000..42e1ecbce
--- /dev/null
+++ b/roms/edk2/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.c
@@ -0,0 +1,165 @@
+/** @file
+ This library is TPM2 DTPM device lib.
+ Choosing this library means platform uses and only uses DTPM device as TPM2 engine.
+
+Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved. <BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/Tpm2DeviceLib.h>
+#include <Library/PcdLib.h>
+
+/**
+ Return PTP interface type.
+
+ @param[in] Register Pointer to PTP register.
+
+ @return PTP interface type.
+**/
+TPM2_PTP_INTERFACE_TYPE
+Tpm2GetPtpInterface (
+ IN VOID *Register
+ );
+
+/**
+ Return PTP CRB interface IdleByPass state.
+
+ @param[in] Register Pointer to PTP register.
+
+ @return PTP CRB interface IdleByPass state.
+**/
+UINT8
+Tpm2GetIdleByPass (
+ IN VOID *Register
+ );
+
+/**
+ This service enables the sending of commands to the TPM2.
+
+ @param[in] InputParameterBlockSize Size of the TPM2 input parameter block.
+ @param[in] InputParameterBlock Pointer to the TPM2 input parameter block.
+ @param[in,out] OutputParameterBlockSize Size of the TPM2 output parameter block.
+ @param[in] OutputParameterBlock Pointer to the TPM2 output parameter block.
+
+ @retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received.
+ @retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device.
+ @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small.
+**/
+EFI_STATUS
+EFIAPI
+DTpm2SubmitCommand (
+ IN UINT32 InputParameterBlockSize,
+ IN UINT8 *InputParameterBlock,
+ IN OUT UINT32 *OutputParameterBlockSize,
+ IN UINT8 *OutputParameterBlock
+ );
+
+/**
+ This service requests use TPM2.
+
+ @retval EFI_SUCCESS Get the control of TPM2 chip.
+ @retval EFI_NOT_FOUND TPM2 not found.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+DTpm2RequestUseTpm (
+ VOID
+ );
+
+/**
+ This service enables the sending of commands to the TPM2.
+
+ @param[in] InputParameterBlockSize Size of the TPM2 input parameter block.
+ @param[in] InputParameterBlock Pointer to the TPM2 input parameter block.
+ @param[in,out] OutputParameterBlockSize Size of the TPM2 output parameter block.
+ @param[in] OutputParameterBlock Pointer to the TPM2 output parameter block.
+
+ @retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received.
+ @retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device.
+ @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2SubmitCommand (
+ IN UINT32 InputParameterBlockSize,
+ IN UINT8 *InputParameterBlock,
+ IN OUT UINT32 *OutputParameterBlockSize,
+ IN UINT8 *OutputParameterBlock
+ )
+{
+ return DTpm2SubmitCommand (
+ InputParameterBlockSize,
+ InputParameterBlock,
+ OutputParameterBlockSize,
+ OutputParameterBlock
+ );
+}
+
+/**
+ This service requests use TPM2.
+
+ @retval EFI_SUCCESS Get the control of TPM2 chip.
+ @retval EFI_NOT_FOUND TPM2 not found.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2RequestUseTpm (
+ VOID
+ )
+{
+ return DTpm2RequestUseTpm ();
+}
+
+/**
+ This service register TPM2 device.
+
+ @param Tpm2Device TPM2 device
+
+ @retval EFI_SUCCESS This TPM2 device is registered successfully.
+ @retval EFI_UNSUPPORTED System does not support register this TPM2 device.
+ @retval EFI_ALREADY_STARTED System already register this TPM2 device.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2RegisterTpm2DeviceLib (
+ IN TPM2_DEVICE_INTERFACE *Tpm2Device
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ The function caches current active TPM interface type.
+
+ @retval EFI_SUCCESS DTPM2.0 instance is registered, or system does not support register DTPM2.0 instance
+**/
+EFI_STATUS
+EFIAPI
+Tpm2DeviceLibConstructor (
+ VOID
+ )
+{
+ TPM2_PTP_INTERFACE_TYPE PtpInterface;
+ UINT8 IdleByPass;
+
+ //
+ // Cache current active TpmInterfaceType only when needed
+ //
+ if (PcdGet8(PcdActiveTpmInterfaceType) == 0xFF) {
+ PtpInterface = Tpm2GetPtpInterface ((VOID *) (UINTN) PcdGet64 (PcdTpmBaseAddress));
+ PcdSet8S(PcdActiveTpmInterfaceType, PtpInterface);
+ }
+
+ if (PcdGet8(PcdActiveTpmInterfaceType) == Tpm2PtpInterfaceCrb && PcdGet8(PcdCRBIdleByPass) == 0xFF) {
+ IdleByPass = Tpm2GetIdleByPass((VOID *) (UINTN) PcdGet64 (PcdTpmBaseAddress));
+ PcdSet8S(PcdCRBIdleByPass, IdleByPass);
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.inf b/roms/edk2/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.inf
new file mode 100644
index 000000000..2b6275046
--- /dev/null
+++ b/roms/edk2/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.inf
@@ -0,0 +1,53 @@
+## @file
+# Provides TPM 2.0 TIS/PTP functions for DTPM
+#
+# Spec Compliance Info:
+# "TCG PC Client Platform TPM Profile(PTP) Specification Family 2.0 Level 00 Revision 00.43"
+# "TCG PC Client Specific TPM Interface Specification(TIS) Version 1.3"
+#
+# This library implements TIS (TPM Interface Specification) and
+# PTP (Platform TPM Profile) functions which is
+# used for every TPM 2.0 command. Choosing this library means platform uses and
+# only uses TPM 2.0 DTPM device.
+#
+# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = Tpm2DeviceLibDTpm
+ MODULE_UNI_FILE = Tpm2DeviceLibDTpm.uni
+ FILE_GUID = E54A3327-A345-4068-8842-70AC0D519855
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = Tpm2DeviceLib|PEIM DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER
+ CONSTRUCTOR = Tpm2DeviceLibConstructor
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ Tpm2Tis.c
+ Tpm2Ptp.c
+ Tpm2DeviceLibDTpm.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ IoLib
+ TimerLib
+ DebugLib
+ PcdLib
+
+[Pcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmBaseAddress ## CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdActiveTpmInterfaceType ## PRODUCES
+ gEfiSecurityPkgTokenSpaceGuid.PcdCRBIdleByPass ## PRODUCES
diff --git a/roms/edk2/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.uni b/roms/edk2/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.uni
new file mode 100644
index 000000000..a92e2be9e
--- /dev/null
+++ b/roms/edk2/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.uni
@@ -0,0 +1,19 @@
+// /** @file
+// Provides TPM 2.0 TIS/PTP functions for DTPM
+//
+// This library implements TIS (TPM Interface Specification) and
+// PTP (Platform TPM Profile) functions which is
+// used for every TPM 2.0 command. Choosing this library means platform uses and
+// only uses TPM 2.0 DTPM device.
+//
+// Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides TPM 2.0 TIS/PTP functions for DTPM"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library implements TIS (TPM Interface Specification) and PTP (Platform TPM Profile) functions which is used for every TPM 2.0 command. Choosing this library means platform uses and only uses TPM 2.0 DTPM device."
+
diff --git a/roms/edk2/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.c b/roms/edk2/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.c
new file mode 100644
index 000000000..691eaa40c
--- /dev/null
+++ b/roms/edk2/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.c
@@ -0,0 +1,132 @@
+/** @file
+ This library is TPM2 DTPM instance.
+ It can be registered to Tpm2 Device router, to be active TPM2 engine,
+ based on platform setting.
+
+Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved. <BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/Tpm2DeviceLib.h>
+#include <Library/PcdLib.h>
+
+#include <Guid/TpmInstance.h>
+
+/**
+ Return PTP interface type.
+
+ @param[in] Register Pointer to PTP register.
+
+ @return PTP interface type.
+**/
+TPM2_PTP_INTERFACE_TYPE
+Tpm2GetPtpInterface (
+ IN VOID *Register
+ );
+
+/**
+ Return PTP CRB interface IdleByPass state.
+
+ @param[in] Register Pointer to PTP register.
+
+ @return PTP CRB interface IdleByPass state.
+**/
+UINT8
+Tpm2GetIdleByPass (
+ IN VOID *Register
+ );
+
+/**
+ Dump PTP register information.
+
+ @param[in] Register Pointer to PTP register.
+**/
+VOID
+DumpPtpInfo (
+ IN VOID *Register
+ );
+
+/**
+ This service enables the sending of commands to the TPM2.
+
+ @param[in] InputParameterBlockSize Size of the TPM2 input parameter block.
+ @param[in] InputParameterBlock Pointer to the TPM2 input parameter block.
+ @param[in,out] OutputParameterBlockSize Size of the TPM2 output parameter block.
+ @param[in] OutputParameterBlock Pointer to the TPM2 output parameter block.
+
+ @retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received.
+ @retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device.
+ @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small.
+**/
+EFI_STATUS
+EFIAPI
+DTpm2SubmitCommand (
+ IN UINT32 InputParameterBlockSize,
+ IN UINT8 *InputParameterBlock,
+ IN OUT UINT32 *OutputParameterBlockSize,
+ IN UINT8 *OutputParameterBlock
+ );
+
+/**
+ This service requests use TPM2.
+
+ @retval EFI_SUCCESS Get the control of TPM2 chip.
+ @retval EFI_NOT_FOUND TPM2 not found.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+DTpm2RequestUseTpm (
+ VOID
+ );
+
+TPM2_DEVICE_INTERFACE mDTpm2InternalTpm2Device = {
+ TPM_DEVICE_INTERFACE_TPM20_DTPM,
+ DTpm2SubmitCommand,
+ DTpm2RequestUseTpm,
+};
+
+/**
+ The function register DTPM2.0 instance and caches current active TPM interface type.
+
+ @retval EFI_SUCCESS DTPM2.0 instance is registered, or system does not support register DTPM2.0 instance
+**/
+EFI_STATUS
+EFIAPI
+Tpm2InstanceLibDTpmConstructor (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ TPM2_PTP_INTERFACE_TYPE PtpInterface;
+ UINT8 IdleByPass;
+
+ Status = Tpm2RegisterTpm2DeviceLib (&mDTpm2InternalTpm2Device);
+ if ((Status == EFI_SUCCESS) || (Status == EFI_UNSUPPORTED)) {
+ //
+ // Unsupported means platform policy does not need this instance enabled.
+ //
+ if (Status == EFI_SUCCESS) {
+ //
+ // Cache current active TpmInterfaceType only when needed
+ //
+ if (PcdGet8(PcdActiveTpmInterfaceType) == 0xFF) {
+ PtpInterface = Tpm2GetPtpInterface ((VOID *) (UINTN) PcdGet64 (PcdTpmBaseAddress));
+ PcdSet8S(PcdActiveTpmInterfaceType, PtpInterface);
+ }
+
+ if (PcdGet8(PcdActiveTpmInterfaceType) == Tpm2PtpInterfaceCrb && PcdGet8(PcdCRBIdleByPass) == 0xFF) {
+ IdleByPass = Tpm2GetIdleByPass((VOID *) (UINTN) PcdGet64 (PcdTpmBaseAddress));
+ PcdSet8S(PcdCRBIdleByPass, IdleByPass);
+ }
+
+ DumpPtpInfo ((VOID *) (UINTN) PcdGet64 (PcdTpmBaseAddress));
+ }
+ return EFI_SUCCESS;
+ }
+ return Status;
+}
diff --git a/roms/edk2/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.inf b/roms/edk2/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.inf
new file mode 100644
index 000000000..5f267f552
--- /dev/null
+++ b/roms/edk2/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.inf
@@ -0,0 +1,49 @@
+## @file
+# Provides a DTPM instance for TPM 2.0 TIS/PTP.
+#
+# This library can be registered to Tpm 2.0 device router, to be active TPM 2.0
+# engine, based on platform setting. It supports both TIS (TPM Interface Specification)
+# and PTP (Platform TPM Profile) functions.
+#
+# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = Tpm2InstanceLibDTpm
+ MODULE_UNI_FILE = Tpm2InstanceLibDTpm.uni
+ FILE_GUID = 286BF25A-C2C3-408c-B3B4-25E6758B7317
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = NULL
+ CONSTRUCTOR = Tpm2InstanceLibDTpmConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ Tpm2Tis.c
+ Tpm2Ptp.c
+ Tpm2InstanceLibDTpm.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ IoLib
+ TimerLib
+ DebugLib
+ PcdLib
+
+[Pcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmBaseAddress ## CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdActiveTpmInterfaceType ## PRODUCES
+ gEfiSecurityPkgTokenSpaceGuid.PcdCRBIdleByPass ## PRODUCES
diff --git a/roms/edk2/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.uni b/roms/edk2/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.uni
new file mode 100644
index 000000000..795b44318
--- /dev/null
+++ b/roms/edk2/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.uni
@@ -0,0 +1,18 @@
+// /** @file
+// Provides a DTPM instance for TPM 2.0 TIS/PTP
+//
+// This library can be registered to Tpm 2.0 device router, to be active TPM 2.0
+// engine, based on platform setting. It supports both TIS (TPM Interface Specification)
+// and PTP (Platform TPM Profile) functions.
+//
+// Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides a DTPM instance for TPM 2.0 TIS/PTP"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library can be registered to Tpm 2.0 device router, to be active TPM 2.0 engine, based on platform setting. It supports both TIS (TPM Interface Specification) and PTP (Platform TPM Profile) functions."
+
diff --git a/roms/edk2/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2Ptp.c b/roms/edk2/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2Ptp.c
new file mode 100644
index 000000000..2c73385b6
--- /dev/null
+++ b/roms/edk2/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2Ptp.c
@@ -0,0 +1,616 @@
+/** @file
+ PTP (Platform TPM Profile) CRB (Command Response Buffer) interface used by dTPM2.0 library.
+
+Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <IndustryStandard/Tpm20.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/IoLib.h>
+#include <Library/TimerLib.h>
+#include <Library/DebugLib.h>
+#include <Library/Tpm2DeviceLib.h>
+#include <Library/PcdLib.h>
+
+#include <IndustryStandard/TpmPtp.h>
+#include <IndustryStandard/TpmTis.h>
+
+//
+// Execution of the command may take from several seconds to minutes for certain
+// commands, such as key generation.
+//
+#define PTP_TIMEOUT_MAX (90000 * 1000) // 90s
+
+//
+// Max TPM command/response length
+//
+#define TPMCMDBUFLENGTH 0x500
+
+/**
+ Check whether TPM PTP register exist.
+
+ @param[in] Reg Pointer to PTP register.
+
+ @retval TRUE TPM PTP exists.
+ @retval FALSE TPM PTP is not found.
+**/
+BOOLEAN
+Tpm2IsPtpPresence (
+ IN VOID *Reg
+ )
+{
+ UINT8 RegRead;
+
+ RegRead = MmioRead8 ((UINTN)Reg);
+ if (RegRead == 0xFF) {
+ //
+ // No TPM chip
+ //
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ Check whether the value of a TPM chip register satisfies the input BIT setting.
+
+ @param[in] Register Address port of register to be checked.
+ @param[in] BitSet Check these data bits are set.
+ @param[in] BitClear Check these data bits are clear.
+ @param[in] TimeOut The max wait time (unit MicroSecond) when checking register.
+
+ @retval EFI_SUCCESS The register satisfies the check bit.
+ @retval EFI_TIMEOUT The register can't run into the expected status in time.
+**/
+EFI_STATUS
+PtpCrbWaitRegisterBits (
+ IN UINT32 *Register,
+ IN UINT32 BitSet,
+ IN UINT32 BitClear,
+ IN UINT32 TimeOut
+ )
+{
+ UINT32 RegRead;
+ UINT32 WaitTime;
+
+ for (WaitTime = 0; WaitTime < TimeOut; WaitTime += 30){
+ RegRead = MmioRead32 ((UINTN)Register);
+ if ((RegRead & BitSet) == BitSet && (RegRead & BitClear) == 0) {
+ return EFI_SUCCESS;
+ }
+ MicroSecondDelay (30);
+ }
+ return EFI_TIMEOUT;
+}
+
+/**
+ Get the control of TPM chip.
+
+ @param[in] CrbReg Pointer to CRB register.
+
+ @retval EFI_SUCCESS Get the control of TPM chip.
+ @retval EFI_INVALID_PARAMETER CrbReg is NULL.
+ @retval EFI_NOT_FOUND TPM chip doesn't exit.
+ @retval EFI_TIMEOUT Can't get the TPM control in time.
+**/
+EFI_STATUS
+PtpCrbRequestUseTpm (
+ IN PTP_CRB_REGISTERS_PTR CrbReg
+ )
+{
+ EFI_STATUS Status;
+
+ if (!Tpm2IsPtpPresence (CrbReg)) {
+ return EFI_NOT_FOUND;
+ }
+
+ MmioWrite32((UINTN)&CrbReg->LocalityControl, PTP_CRB_LOCALITY_CONTROL_REQUEST_ACCESS);
+ Status = PtpCrbWaitRegisterBits (
+ &CrbReg->LocalityStatus,
+ PTP_CRB_LOCALITY_STATUS_GRANTED,
+ 0,
+ PTP_TIMEOUT_A
+ );
+ return Status;
+}
+
+/**
+ Send a command to TPM for execution and return response data.
+
+ @param[in] CrbReg TPM register space base address.
+ @param[in] BufferIn Buffer for command data.
+ @param[in] SizeIn Size of command data.
+ @param[in, out] BufferOut Buffer for response data.
+ @param[in, out] SizeOut Size of response data.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+ @retval EFI_UNSUPPORTED Unsupported TPM version
+
+**/
+EFI_STATUS
+PtpCrbTpmCommand (
+ IN PTP_CRB_REGISTERS_PTR CrbReg,
+ IN UINT8 *BufferIn,
+ IN UINT32 SizeIn,
+ IN OUT UINT8 *BufferOut,
+ IN OUT UINT32 *SizeOut
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Index;
+ UINT32 TpmOutSize;
+ UINT16 Data16;
+ UINT32 Data32;
+
+ DEBUG_CODE (
+ UINTN DebugSize;
+
+ DEBUG ((EFI_D_VERBOSE, "PtpCrbTpmCommand Send - "));
+ if (SizeIn > 0x100) {
+ DebugSize = 0x40;
+ } else {
+ DebugSize = SizeIn;
+ }
+ for (Index = 0; Index < DebugSize; Index++) {
+ DEBUG ((EFI_D_VERBOSE, "%02x ", BufferIn[Index]));
+ }
+ if (DebugSize != SizeIn) {
+ DEBUG ((EFI_D_VERBOSE, "...... "));
+ for (Index = SizeIn - 0x20; Index < SizeIn; Index++) {
+ DEBUG ((EFI_D_VERBOSE, "%02x ", BufferIn[Index]));
+ }
+ }
+ DEBUG ((EFI_D_VERBOSE, "\n"));
+ );
+ TpmOutSize = 0;
+
+ //
+ // STEP 0:
+ // if CapCRbIdelByPass == 0, enforce Idle state before sending command
+ //
+ if (PcdGet8(PcdCRBIdleByPass) == 0 && (MmioRead32((UINTN)&CrbReg->CrbControlStatus) & PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE) == 0){
+ Status = PtpCrbWaitRegisterBits (
+ &CrbReg->CrbControlStatus,
+ PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE,
+ 0,
+ PTP_TIMEOUT_C
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Try to goIdle to recover TPM
+ //
+ Status = EFI_DEVICE_ERROR;
+ goto GoIdle_Exit;
+ }
+ }
+
+ //
+ // STEP 1:
+ // Ready is any time the TPM is ready to receive a command, following a write
+ // of 1 by software to Request.cmdReady, as indicated by the Status field
+ // being cleared to 0.
+ //
+ MmioWrite32((UINTN)&CrbReg->CrbControlRequest, PTP_CRB_CONTROL_AREA_REQUEST_COMMAND_READY);
+ Status = PtpCrbWaitRegisterBits (
+ &CrbReg->CrbControlRequest,
+ 0,
+ PTP_CRB_CONTROL_AREA_REQUEST_COMMAND_READY,
+ PTP_TIMEOUT_C
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto GoIdle_Exit;
+ }
+ Status = PtpCrbWaitRegisterBits (
+ &CrbReg->CrbControlStatus,
+ 0,
+ PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE,
+ PTP_TIMEOUT_C
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto GoIdle_Exit;
+ }
+
+ //
+ // STEP 2:
+ // Command Reception occurs following a Ready state between the write of the
+ // first byte of a command to the Command Buffer and the receipt of a write
+ // of 1 to Start.
+ //
+ for (Index = 0; Index < SizeIn; Index++) {
+ MmioWrite8 ((UINTN)&CrbReg->CrbDataBuffer[Index], BufferIn[Index]);
+ }
+ MmioWrite32 ((UINTN)&CrbReg->CrbControlCommandAddressHigh, (UINT32)RShiftU64 ((UINTN)CrbReg->CrbDataBuffer, 32));
+ MmioWrite32 ((UINTN)&CrbReg->CrbControlCommandAddressLow, (UINT32)(UINTN)CrbReg->CrbDataBuffer);
+ MmioWrite32 ((UINTN)&CrbReg->CrbControlCommandSize, sizeof(CrbReg->CrbDataBuffer));
+
+ MmioWrite64 ((UINTN)&CrbReg->CrbControlResponseAddrss, (UINT32)(UINTN)CrbReg->CrbDataBuffer);
+ MmioWrite32 ((UINTN)&CrbReg->CrbControlResponseSize, sizeof(CrbReg->CrbDataBuffer));
+
+ //
+ // STEP 3:
+ // Command Execution occurs after receipt of a 1 to Start and the TPM
+ // clearing Start to 0.
+ //
+ MmioWrite32((UINTN)&CrbReg->CrbControlStart, PTP_CRB_CONTROL_START);
+ Status = PtpCrbWaitRegisterBits (
+ &CrbReg->CrbControlStart,
+ 0,
+ PTP_CRB_CONTROL_START,
+ PTP_TIMEOUT_MAX
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Command Completion check timeout. Cancel the currently executing command by writing TPM_CRB_CTRL_CANCEL,
+ // Expect TPM_RC_CANCELLED or successfully completed response.
+ //
+ MmioWrite32((UINTN)&CrbReg->CrbControlCancel, PTP_CRB_CONTROL_CANCEL);
+ Status = PtpCrbWaitRegisterBits (
+ &CrbReg->CrbControlStart,
+ 0,
+ PTP_CRB_CONTROL_START,
+ PTP_TIMEOUT_B
+ );
+ MmioWrite32((UINTN)&CrbReg->CrbControlCancel, 0);
+
+ if (EFI_ERROR(Status)) {
+ //
+ // Still in Command Execution state. Try to goIdle, the behavior is agnostic.
+ //
+ Status = EFI_DEVICE_ERROR;
+ goto GoIdle_Exit;
+ }
+ }
+
+ //
+ // STEP 4:
+ // Command Completion occurs after completion of a command (indicated by the
+ // TPM clearing TPM_CRB_CTRL_Start_x to 0) and before a write of a 1 by the
+ // software to Request.goIdle.
+ //
+
+ //
+ // Get response data header
+ //
+ for (Index = 0; Index < sizeof (TPM2_RESPONSE_HEADER); Index++) {
+ BufferOut[Index] = MmioRead8 ((UINTN)&CrbReg->CrbDataBuffer[Index]);
+ }
+ DEBUG_CODE (
+ DEBUG ((EFI_D_VERBOSE, "PtpCrbTpmCommand ReceiveHeader - "));
+ for (Index = 0; Index < sizeof (TPM2_RESPONSE_HEADER); Index++) {
+ DEBUG ((EFI_D_VERBOSE, "%02x ", BufferOut[Index]));
+ }
+ DEBUG ((EFI_D_VERBOSE, "\n"));
+ );
+ //
+ // Check the response data header (tag, parasize and returncode)
+ //
+ CopyMem (&Data16, BufferOut, sizeof (UINT16));
+ // TPM2 should not use this RSP_COMMAND
+ if (SwapBytes16 (Data16) == TPM_ST_RSP_COMMAND) {
+ DEBUG ((EFI_D_ERROR, "TPM2: TPM_ST_RSP error - %x\n", TPM_ST_RSP_COMMAND));
+ Status = EFI_UNSUPPORTED;
+ goto GoIdle_Exit;
+ }
+
+ CopyMem (&Data32, (BufferOut + 2), sizeof (UINT32));
+ TpmOutSize = SwapBytes32 (Data32);
+ if (*SizeOut < TpmOutSize) {
+ //
+ // Command completed, but buffer is not enough
+ //
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto GoReady_Exit;
+ }
+ *SizeOut = TpmOutSize;
+ //
+ // Continue reading the remaining data
+ //
+ for (Index = sizeof (TPM2_RESPONSE_HEADER); Index < TpmOutSize; Index++) {
+ BufferOut[Index] = MmioRead8 ((UINTN)&CrbReg->CrbDataBuffer[Index]);
+ }
+
+ DEBUG_CODE (
+ DEBUG ((EFI_D_VERBOSE, "PtpCrbTpmCommand Receive - "));
+ for (Index = 0; Index < TpmOutSize; Index++) {
+ DEBUG ((EFI_D_VERBOSE, "%02x ", BufferOut[Index]));
+ }
+ DEBUG ((EFI_D_VERBOSE, "\n"));
+ );
+
+GoReady_Exit:
+ //
+ // Goto Ready State if command is completed successfully and TPM support IdleBypass
+ // If not supported. flow down to GoIdle
+ //
+ if (PcdGet8(PcdCRBIdleByPass) == 1) {
+ MmioWrite32((UINTN)&CrbReg->CrbControlRequest, PTP_CRB_CONTROL_AREA_REQUEST_COMMAND_READY);
+ return Status;
+ }
+
+ //
+ // Do not wait for state transition for TIMEOUT_C
+ // This function will try to wait 2 TIMEOUT_C at the beginning in next call.
+ //
+GoIdle_Exit:
+
+ //
+ // Return to Idle state by setting TPM_CRB_CTRL_STS_x.Status.goIdle to 1.
+ //
+ MmioWrite32((UINTN)&CrbReg->CrbControlRequest, PTP_CRB_CONTROL_AREA_REQUEST_GO_IDLE);
+
+ //
+ // Only enforce Idle state transition if execution fails when CRBIdleBypass==1
+ // Leave regular Idle delay at the beginning of next command execution
+ //
+ if (PcdGet8(PcdCRBIdleByPass) == 1){
+ Status = PtpCrbWaitRegisterBits (
+ &CrbReg->CrbControlStatus,
+ PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE,
+ 0,
+ PTP_TIMEOUT_C
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Send a command to TPM for execution and return response data.
+
+ @param[in] TisReg TPM register space base address.
+ @param[in] BufferIn Buffer for command data.
+ @param[in] SizeIn Size of command data.
+ @param[in, out] BufferOut Buffer for response data.
+ @param[in, out] SizeOut Size of response data.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+ @retval EFI_UNSUPPORTED Unsupported TPM version
+
+**/
+EFI_STATUS
+Tpm2TisTpmCommand (
+ IN TIS_PC_REGISTERS_PTR TisReg,
+ IN UINT8 *BufferIn,
+ IN UINT32 SizeIn,
+ IN OUT UINT8 *BufferOut,
+ IN OUT UINT32 *SizeOut
+ );
+
+/**
+ Get the control of TPM chip by sending requestUse command TIS_PC_ACC_RQUUSE
+ to ACCESS Register in the time of default TIS_TIMEOUT_A.
+
+ @param[in] TisReg Pointer to TIS register.
+
+ @retval EFI_SUCCESS Get the control of TPM chip.
+ @retval EFI_INVALID_PARAMETER TisReg is NULL.
+ @retval EFI_NOT_FOUND TPM chip doesn't exit.
+ @retval EFI_TIMEOUT Can't get the TPM control in time.
+**/
+EFI_STATUS
+TisPcRequestUseTpm (
+ IN TIS_PC_REGISTERS_PTR TisReg
+ );
+
+/**
+ Return PTP interface type.
+
+ @param[in] Register Pointer to PTP register.
+
+ @return PTP interface type.
+**/
+TPM2_PTP_INTERFACE_TYPE
+Tpm2GetPtpInterface (
+ IN VOID *Register
+ )
+{
+ PTP_CRB_INTERFACE_IDENTIFIER InterfaceId;
+ PTP_FIFO_INTERFACE_CAPABILITY InterfaceCapability;
+
+ if (!Tpm2IsPtpPresence (Register)) {
+ return Tpm2PtpInterfaceMax;
+ }
+ //
+ // Check interface id
+ //
+ InterfaceId.Uint32 = MmioRead32 ((UINTN)&((PTP_CRB_REGISTERS *)Register)->InterfaceId);
+ InterfaceCapability.Uint32 = MmioRead32 ((UINTN)&((PTP_FIFO_REGISTERS *)Register)->InterfaceCapability);
+
+ if ((InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_CRB) &&
+ (InterfaceId.Bits.InterfaceVersion == PTP_INTERFACE_IDENTIFIER_INTERFACE_VERSION_CRB) &&
+ (InterfaceId.Bits.CapCRB != 0)) {
+ return Tpm2PtpInterfaceCrb;
+ }
+ if ((InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_FIFO) &&
+ (InterfaceId.Bits.InterfaceVersion == PTP_INTERFACE_IDENTIFIER_INTERFACE_VERSION_FIFO) &&
+ (InterfaceId.Bits.CapFIFO != 0) &&
+ (InterfaceCapability.Bits.InterfaceVersion == INTERFACE_CAPABILITY_INTERFACE_VERSION_PTP)) {
+ return Tpm2PtpInterfaceFifo;
+ }
+ return Tpm2PtpInterfaceTis;
+}
+
+/**
+ Return PTP CRB interface IdleByPass state.
+
+ @param[in] Register Pointer to PTP register.
+
+ @return PTP CRB interface IdleByPass state.
+**/
+UINT8
+Tpm2GetIdleByPass (
+ IN VOID *Register
+ )
+{
+ PTP_CRB_INTERFACE_IDENTIFIER InterfaceId;
+
+ //
+ // Check interface id
+ //
+ InterfaceId.Uint32 = MmioRead32 ((UINTN)&((PTP_CRB_REGISTERS *)Register)->InterfaceId);
+
+ return (UINT8)(InterfaceId.Bits.CapCRBIdleBypass);
+}
+
+/**
+ Dump PTP register information.
+
+ @param[in] Register Pointer to PTP register.
+**/
+VOID
+DumpPtpInfo (
+ IN VOID *Register
+ )
+{
+ PTP_CRB_INTERFACE_IDENTIFIER InterfaceId;
+ PTP_FIFO_INTERFACE_CAPABILITY InterfaceCapability;
+ UINT8 StatusEx;
+ UINT16 Vid;
+ UINT16 Did;
+ UINT8 Rid;
+ TPM2_PTP_INTERFACE_TYPE PtpInterface;
+
+ if (!Tpm2IsPtpPresence (Register)) {
+ return ;
+ }
+
+ InterfaceId.Uint32 = MmioRead32 ((UINTN)&((PTP_CRB_REGISTERS *)Register)->InterfaceId);
+ InterfaceCapability.Uint32 = MmioRead32 ((UINTN)&((PTP_FIFO_REGISTERS *)Register)->InterfaceCapability);
+ StatusEx = MmioRead8 ((UINTN)&((PTP_FIFO_REGISTERS *)Register)->StatusEx);
+
+ //
+ // Dump InterfaceId Register for PTP
+ //
+ DEBUG ((EFI_D_INFO, "InterfaceId - 0x%08x\n", InterfaceId.Uint32));
+ DEBUG ((EFI_D_INFO, " InterfaceType - 0x%02x\n", InterfaceId.Bits.InterfaceType));
+ if (InterfaceId.Bits.InterfaceType != PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_TIS) {
+ DEBUG ((EFI_D_INFO, " InterfaceVersion - 0x%02x\n", InterfaceId.Bits.InterfaceVersion));
+ DEBUG ((EFI_D_INFO, " CapFIFO - 0x%x\n", InterfaceId.Bits.CapFIFO));
+ DEBUG ((EFI_D_INFO, " CapCRB - 0x%x\n", InterfaceId.Bits.CapCRB));
+ }
+
+ //
+ // Dump Capability Register for TIS and FIFO
+ //
+ DEBUG ((EFI_D_INFO, "InterfaceCapability - 0x%08x\n", InterfaceCapability.Uint32));
+ if ((InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_TIS) ||
+ (InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_FIFO)) {
+ DEBUG ((EFI_D_INFO, " InterfaceVersion - 0x%x\n", InterfaceCapability.Bits.InterfaceVersion));
+ }
+
+ //
+ // Dump StatusEx Register for PTP FIFO
+ //
+ DEBUG ((EFI_D_INFO, "StatusEx - 0x%02x\n", StatusEx));
+ if (InterfaceCapability.Bits.InterfaceVersion == INTERFACE_CAPABILITY_INTERFACE_VERSION_PTP) {
+ DEBUG ((EFI_D_INFO, " TpmFamily - 0x%x\n", (StatusEx & PTP_FIFO_STS_EX_TPM_FAMILY) >> PTP_FIFO_STS_EX_TPM_FAMILY_OFFSET));
+ }
+
+ Vid = 0xFFFF;
+ Did = 0xFFFF;
+ Rid = 0xFF;
+ PtpInterface = PcdGet8(PcdActiveTpmInterfaceType);
+ DEBUG ((EFI_D_INFO, "PtpInterface - %x\n", PtpInterface));
+ switch (PtpInterface) {
+ case Tpm2PtpInterfaceCrb:
+ Vid = MmioRead16 ((UINTN)&((PTP_CRB_REGISTERS *)Register)->Vid);
+ Did = MmioRead16 ((UINTN)&((PTP_CRB_REGISTERS *)Register)->Did);
+ Rid = (UINT8)InterfaceId.Bits.Rid;
+ break;
+ case Tpm2PtpInterfaceFifo:
+ case Tpm2PtpInterfaceTis:
+ Vid = MmioRead16 ((UINTN)&((PTP_FIFO_REGISTERS *)Register)->Vid);
+ Did = MmioRead16 ((UINTN)&((PTP_FIFO_REGISTERS *)Register)->Did);
+ Rid = MmioRead8 ((UINTN)&((PTP_FIFO_REGISTERS *)Register)->Rid);
+ break;
+ default:
+ break;
+ }
+ DEBUG ((EFI_D_INFO, "VID - 0x%04x\n", Vid));
+ DEBUG ((EFI_D_INFO, "DID - 0x%04x\n", Did));
+ DEBUG ((EFI_D_INFO, "RID - 0x%02x\n", Rid));
+}
+
+/**
+ This service enables the sending of commands to the TPM2.
+
+ @param[in] InputParameterBlockSize Size of the TPM2 input parameter block.
+ @param[in] InputParameterBlock Pointer to the TPM2 input parameter block.
+ @param[in,out] OutputParameterBlockSize Size of the TPM2 output parameter block.
+ @param[in] OutputParameterBlock Pointer to the TPM2 output parameter block.
+
+ @retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received.
+ @retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device.
+ @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small.
+**/
+EFI_STATUS
+EFIAPI
+DTpm2SubmitCommand (
+ IN UINT32 InputParameterBlockSize,
+ IN UINT8 *InputParameterBlock,
+ IN OUT UINT32 *OutputParameterBlockSize,
+ IN UINT8 *OutputParameterBlock
+ )
+{
+ TPM2_PTP_INTERFACE_TYPE PtpInterface;
+
+ PtpInterface = PcdGet8(PcdActiveTpmInterfaceType);
+ switch (PtpInterface) {
+ case Tpm2PtpInterfaceCrb:
+ return PtpCrbTpmCommand (
+ (PTP_CRB_REGISTERS_PTR) (UINTN) PcdGet64 (PcdTpmBaseAddress),
+ InputParameterBlock,
+ InputParameterBlockSize,
+ OutputParameterBlock,
+ OutputParameterBlockSize
+ );
+ case Tpm2PtpInterfaceFifo:
+ case Tpm2PtpInterfaceTis:
+ return Tpm2TisTpmCommand (
+ (TIS_PC_REGISTERS_PTR) (UINTN) PcdGet64 (PcdTpmBaseAddress),
+ InputParameterBlock,
+ InputParameterBlockSize,
+ OutputParameterBlock,
+ OutputParameterBlockSize
+ );
+ default:
+ return EFI_NOT_FOUND;
+ }
+}
+
+/**
+ This service requests use TPM2.
+
+ @retval EFI_SUCCESS Get the control of TPM2 chip.
+ @retval EFI_NOT_FOUND TPM2 not found.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+DTpm2RequestUseTpm (
+ VOID
+ )
+{
+ TPM2_PTP_INTERFACE_TYPE PtpInterface;
+
+ PtpInterface = PcdGet8(PcdActiveTpmInterfaceType);
+ switch (PtpInterface) {
+ case Tpm2PtpInterfaceCrb:
+ return PtpCrbRequestUseTpm ((PTP_CRB_REGISTERS_PTR) (UINTN) PcdGet64 (PcdTpmBaseAddress));
+ case Tpm2PtpInterfaceFifo:
+ case Tpm2PtpInterfaceTis:
+ return TisPcRequestUseTpm ((TIS_PC_REGISTERS_PTR) (UINTN) PcdGet64 (PcdTpmBaseAddress));
+ default:
+ return EFI_NOT_FOUND;
+ }
+}
diff --git a/roms/edk2/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2Tis.c b/roms/edk2/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2Tis.c
new file mode 100644
index 000000000..9a809612b
--- /dev/null
+++ b/roms/edk2/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2Tis.c
@@ -0,0 +1,434 @@
+/** @file
+ TIS (TPM Interface Specification) functions used by dTPM2.0 library.
+
+Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <IndustryStandard/Tpm20.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/IoLib.h>
+#include <Library/TimerLib.h>
+#include <Library/DebugLib.h>
+#include <Library/Tpm2DeviceLib.h>
+#include <Library/PcdLib.h>
+
+#include <IndustryStandard/TpmTis.h>
+
+#define TIS_TIMEOUT_MAX (90000 * 1000) // 90s
+
+//
+// Max TPM command/response length
+//
+#define TPMCMDBUFLENGTH 0x500
+
+/**
+ Check whether TPM chip exist.
+
+ @param[in] TisReg Pointer to TIS register.
+
+ @retval TRUE TPM chip exists.
+ @retval FALSE TPM chip is not found.
+**/
+BOOLEAN
+TisPcPresenceCheck (
+ IN TIS_PC_REGISTERS_PTR TisReg
+ )
+{
+ UINT8 RegRead;
+
+ RegRead = MmioRead8 ((UINTN)&TisReg->Access);
+ return (BOOLEAN)(RegRead != (UINT8)-1);
+}
+
+/**
+ Check whether the value of a TPM chip register satisfies the input BIT setting.
+
+ @param[in] Register Address port of register to be checked.
+ @param[in] BitSet Check these data bits are set.
+ @param[in] BitClear Check these data bits are clear.
+ @param[in] TimeOut The max wait time (unit MicroSecond) when checking register.
+
+ @retval EFI_SUCCESS The register satisfies the check bit.
+ @retval EFI_TIMEOUT The register can't run into the expected status in time.
+**/
+EFI_STATUS
+TisPcWaitRegisterBits (
+ IN UINT8 *Register,
+ IN UINT8 BitSet,
+ IN UINT8 BitClear,
+ IN UINT32 TimeOut
+ )
+{
+ UINT8 RegRead;
+ UINT32 WaitTime;
+
+ for (WaitTime = 0; WaitTime < TimeOut; WaitTime += 30){
+ RegRead = MmioRead8 ((UINTN)Register);
+ if ((RegRead & BitSet) == BitSet && (RegRead & BitClear) == 0)
+ return EFI_SUCCESS;
+ MicroSecondDelay (30);
+ }
+ return EFI_TIMEOUT;
+}
+
+/**
+ Get BurstCount by reading the burstCount field of a TIS register
+ in the time of default TIS_TIMEOUT_D.
+
+ @param[in] TisReg Pointer to TIS register.
+ @param[out] BurstCount Pointer to a buffer to store the got BurstCount.
+
+ @retval EFI_SUCCESS Get BurstCount.
+ @retval EFI_INVALID_PARAMETER TisReg is NULL or BurstCount is NULL.
+ @retval EFI_TIMEOUT BurstCount can't be got in time.
+**/
+EFI_STATUS
+TisPcReadBurstCount (
+ IN TIS_PC_REGISTERS_PTR TisReg,
+ OUT UINT16 *BurstCount
+ )
+{
+ UINT32 WaitTime;
+ UINT8 DataByte0;
+ UINT8 DataByte1;
+
+ if (BurstCount == NULL || TisReg == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ WaitTime = 0;
+ do {
+ //
+ // TIS_PC_REGISTERS_PTR->burstCount is UINT16, but it is not 2bytes aligned,
+ // so it needs to use MmioRead8 to read two times
+ //
+ DataByte0 = MmioRead8 ((UINTN)&TisReg->BurstCount);
+ DataByte1 = MmioRead8 ((UINTN)&TisReg->BurstCount + 1);
+ *BurstCount = (UINT16)((DataByte1 << 8) + DataByte0);
+ if (*BurstCount != 0) {
+ return EFI_SUCCESS;
+ }
+ MicroSecondDelay (30);
+ WaitTime += 30;
+ } while (WaitTime < TIS_TIMEOUT_D);
+
+ return EFI_TIMEOUT;
+}
+
+/**
+ Set TPM chip to ready state by sending ready command TIS_PC_STS_READY
+ to Status Register in time.
+
+ @param[in] TisReg Pointer to TIS register.
+
+ @retval EFI_SUCCESS TPM chip enters into ready state.
+ @retval EFI_INVALID_PARAMETER TisReg is NULL.
+ @retval EFI_TIMEOUT TPM chip can't be set to ready state in time.
+**/
+EFI_STATUS
+TisPcPrepareCommand (
+ IN TIS_PC_REGISTERS_PTR TisReg
+ )
+{
+ EFI_STATUS Status;
+
+ if (TisReg == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ MmioWrite8((UINTN)&TisReg->Status, TIS_PC_STS_READY);
+ Status = TisPcWaitRegisterBits (
+ &TisReg->Status,
+ TIS_PC_STS_READY,
+ 0,
+ TIS_TIMEOUT_B
+ );
+ return Status;
+}
+
+/**
+ Get the control of TPM chip by sending requestUse command TIS_PC_ACC_RQUUSE
+ to ACCESS Register in the time of default TIS_TIMEOUT_A.
+
+ @param[in] TisReg Pointer to TIS register.
+
+ @retval EFI_SUCCESS Get the control of TPM chip.
+ @retval EFI_INVALID_PARAMETER TisReg is NULL.
+ @retval EFI_NOT_FOUND TPM chip doesn't exit.
+ @retval EFI_TIMEOUT Can't get the TPM control in time.
+**/
+EFI_STATUS
+TisPcRequestUseTpm (
+ IN TIS_PC_REGISTERS_PTR TisReg
+ )
+{
+ EFI_STATUS Status;
+
+ if (TisReg == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!TisPcPresenceCheck (TisReg)) {
+ return EFI_NOT_FOUND;
+ }
+
+ MmioWrite8((UINTN)&TisReg->Access, TIS_PC_ACC_RQUUSE);
+ Status = TisPcWaitRegisterBits (
+ &TisReg->Access,
+ (UINT8)(TIS_PC_ACC_ACTIVE |TIS_PC_VALID),
+ 0,
+ TIS_TIMEOUT_A
+ );
+ return Status;
+}
+
+/**
+ Send a command to TPM for execution and return response data.
+
+ @param[in] TisReg TPM register space base address.
+ @param[in] BufferIn Buffer for command data.
+ @param[in] SizeIn Size of command data.
+ @param[in, out] BufferOut Buffer for response data.
+ @param[in, out] SizeOut Size of response data.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+ @retval EFI_UNSUPPORTED Unsupported TPM version
+
+**/
+EFI_STATUS
+Tpm2TisTpmCommand (
+ IN TIS_PC_REGISTERS_PTR TisReg,
+ IN UINT8 *BufferIn,
+ IN UINT32 SizeIn,
+ IN OUT UINT8 *BufferOut,
+ IN OUT UINT32 *SizeOut
+ )
+{
+ EFI_STATUS Status;
+ UINT16 BurstCount;
+ UINT32 Index;
+ UINT32 TpmOutSize;
+ UINT16 Data16;
+ UINT32 Data32;
+
+ DEBUG_CODE (
+ UINTN DebugSize;
+
+ DEBUG ((EFI_D_VERBOSE, "Tpm2TisTpmCommand Send - "));
+ if (SizeIn > 0x100) {
+ DebugSize = 0x40;
+ } else {
+ DebugSize = SizeIn;
+ }
+ for (Index = 0; Index < DebugSize; Index++) {
+ DEBUG ((EFI_D_VERBOSE, "%02x ", BufferIn[Index]));
+ }
+ if (DebugSize != SizeIn) {
+ DEBUG ((EFI_D_VERBOSE, "...... "));
+ for (Index = SizeIn - 0x20; Index < SizeIn; Index++) {
+ DEBUG ((EFI_D_VERBOSE, "%02x ", BufferIn[Index]));
+ }
+ }
+ DEBUG ((EFI_D_VERBOSE, "\n"));
+ );
+ TpmOutSize = 0;
+
+ Status = TisPcPrepareCommand (TisReg);
+ if (EFI_ERROR (Status)){
+ DEBUG ((DEBUG_ERROR, "Tpm2 is not ready for command!\n"));
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Send the command data to Tpm
+ //
+ Index = 0;
+ while (Index < SizeIn) {
+ Status = TisPcReadBurstCount (TisReg, &BurstCount);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ for (; BurstCount > 0 && Index < SizeIn; BurstCount--) {
+ MmioWrite8((UINTN)&TisReg->DataFifo, *(BufferIn + Index));
+ Index++;
+ }
+ }
+ //
+ // Check the Tpm status STS_EXPECT change from 1 to 0
+ //
+ Status = TisPcWaitRegisterBits (
+ &TisReg->Status,
+ (UINT8) TIS_PC_VALID,
+ TIS_PC_STS_EXPECT,
+ TIS_TIMEOUT_C
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Tpm2 The send buffer too small!\n"));
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto Exit;
+ }
+ //
+ // Executed the TPM command and waiting for the response data ready
+ //
+ MmioWrite8((UINTN)&TisReg->Status, TIS_PC_STS_GO);
+
+ //
+ // NOTE: That may take many seconds to minutes for certain commands, such as key generation.
+ //
+ Status = TisPcWaitRegisterBits (
+ &TisReg->Status,
+ (UINT8) (TIS_PC_VALID | TIS_PC_STS_DATA),
+ 0,
+ TIS_TIMEOUT_MAX
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // dataAvail check timeout. Cancel the currently executing command by writing commandCancel,
+ // Expect TPM_RC_CANCELLED or successfully completed response.
+ //
+ DEBUG ((DEBUG_ERROR, "Wait for Tpm2 response data time out. Trying to cancel the command!!\n"));
+
+ MmioWrite32((UINTN)&TisReg->Status, TIS_PC_STS_CANCEL);
+ Status = TisPcWaitRegisterBits (
+ &TisReg->Status,
+ (UINT8) (TIS_PC_VALID | TIS_PC_STS_DATA),
+ 0,
+ TIS_TIMEOUT_B
+ );
+ //
+ // Do not clear CANCEL bit here because Writes of 0 to this bit are ignored
+ //
+ if (EFI_ERROR (Status)) {
+ //
+ // Cancel executing command fail to get any response
+ // Try to abort the command with write of a 1 to commandReady in Command Execution state
+ //
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ }
+
+ //
+ // Get response data header
+ //
+ Index = 0;
+ BurstCount = 0;
+ while (Index < sizeof (TPM2_RESPONSE_HEADER)) {
+ Status = TisPcReadBurstCount (TisReg, &BurstCount);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ for (; BurstCount > 0; BurstCount--) {
+ *(BufferOut + Index) = MmioRead8 ((UINTN)&TisReg->DataFifo);
+ Index++;
+ if (Index == sizeof (TPM2_RESPONSE_HEADER)) break;
+ }
+ }
+ DEBUG_CODE (
+ DEBUG ((EFI_D_VERBOSE, "Tpm2TisTpmCommand ReceiveHeader - "));
+ for (Index = 0; Index < sizeof (TPM2_RESPONSE_HEADER); Index++) {
+ DEBUG ((EFI_D_VERBOSE, "%02x ", BufferOut[Index]));
+ }
+ DEBUG ((EFI_D_VERBOSE, "\n"));
+ );
+ //
+ // Check the response data header (tag,parasize and returncode )
+ //
+ CopyMem (&Data16, BufferOut, sizeof (UINT16));
+ // TPM2 should not use this RSP_COMMAND
+ if (SwapBytes16 (Data16) == TPM_ST_RSP_COMMAND) {
+ DEBUG ((EFI_D_ERROR, "TPM2: TPM_ST_RSP error - %x\n", TPM_ST_RSP_COMMAND));
+ Status = EFI_UNSUPPORTED;
+ goto Exit;
+ }
+
+ CopyMem (&Data32, (BufferOut + 2), sizeof (UINT32));
+ TpmOutSize = SwapBytes32 (Data32);
+ if (*SizeOut < TpmOutSize) {
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto Exit;
+ }
+ *SizeOut = TpmOutSize;
+ //
+ // Continue reading the remaining data
+ //
+ while ( Index < TpmOutSize ) {
+ for (; BurstCount > 0; BurstCount--) {
+ *(BufferOut + Index) = MmioRead8 ((UINTN)&TisReg->DataFifo);
+ Index++;
+ if (Index == TpmOutSize) {
+ Status = EFI_SUCCESS;
+ goto Exit;
+ }
+ }
+ Status = TisPcReadBurstCount (TisReg, &BurstCount);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ }
+Exit:
+ DEBUG_CODE (
+ DEBUG ((EFI_D_VERBOSE, "Tpm2TisTpmCommand Receive - "));
+ for (Index = 0; Index < TpmOutSize; Index++) {
+ DEBUG ((EFI_D_VERBOSE, "%02x ", BufferOut[Index]));
+ }
+ DEBUG ((EFI_D_VERBOSE, "\n"));
+ );
+ MmioWrite8((UINTN)&TisReg->Status, TIS_PC_STS_READY);
+ return Status;
+}
+
+/**
+ This service enables the sending of commands to the TPM2.
+
+ @param[in] InputParameterBlockSize Size of the TPM2 input parameter block.
+ @param[in] InputParameterBlock Pointer to the TPM2 input parameter block.
+ @param[in,out] OutputParameterBlockSize Size of the TPM2 output parameter block.
+ @param[in] OutputParameterBlock Pointer to the TPM2 output parameter block.
+
+ @retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received.
+ @retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device.
+ @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small.
+**/
+EFI_STATUS
+EFIAPI
+DTpm2TisSubmitCommand (
+ IN UINT32 InputParameterBlockSize,
+ IN UINT8 *InputParameterBlock,
+ IN OUT UINT32 *OutputParameterBlockSize,
+ IN UINT8 *OutputParameterBlock
+ )
+{
+ return Tpm2TisTpmCommand (
+ (TIS_PC_REGISTERS_PTR) (UINTN) PcdGet64 (PcdTpmBaseAddress),
+ InputParameterBlock,
+ InputParameterBlockSize,
+ OutputParameterBlock,
+ OutputParameterBlockSize
+ );
+}
+
+/**
+ This service requests use TPM2.
+
+ @retval EFI_SUCCESS Get the control of TPM2 chip.
+ @retval EFI_NOT_FOUND TPM2 not found.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+DTpm2TisRequestUseTpm (
+ VOID
+ )
+{
+ return TisPcRequestUseTpm ((TIS_PC_REGISTERS_PTR) (UINTN) PcdGet64 (PcdTpmBaseAddress));
+}