/** @file
Tpm20Acpi - TPM 2.0 ACPI Table Driver for HR650X platform
This module provides TPM 2.0 ACPI table initialization and management
functionality. It communicates with the TPM hardware via memory-mapped
I/O at 0xFED40000 and publishes ACPI tables (TPM2, SSDT) describing
the TPM device to the OS.
Key features:
- Detects TPM 2.0 hardware via memory-mapped registers
- Locates DSDT table from RSDT/XSDT
- Programs ACPI SSDT tables with TPM configuration information
- Supports TPM Physical Presence (TPP) interface
- Supports TPM command/response buffer interface
Copyright (c) 2025, Dell Inc. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "Tpm20Acpi.h"
//
// Global variables - UEFI boot/runtime services
//
EFI_HANDLE gImageHandle = NULL;
EFI_SYSTEM_TABLE *gST = NULL;
EFI_BOOT_SERVICES *gBS = NULL;
EFI_RUNTIME_SERVICES *gRT = NULL;
//
// Module global variables
//
UINT64 mHobList = 0; ///< HOB list pointer (cached)
UINT64 mPcdDb = 0; ///< PCD database protocol pointer
UINT64 mPciExpressBase = 0; ///< PCI Express MMIO base address
UINT64 mTpmStolenAddr = 0; ///< TPM stolen memory address (cached)
UINT32 mTpmMode = 0; ///< TPM operating mode
UINT64 mDsdtAddr = 0; ///< DSDT address from RSDT
UINT64 mXsdtDsdtAddr = 0; ///< DSDT address from XSDT
VOID *mAcpiSupport = 0; ///< ACPI Support protocol interface
UINT32 mAcpiGpeSignature = 0x1E941A97; ///< ACPI GPE block GUID-like constant
UINT32 mAcpiGpeVal = 0;
UINT32 m541674817 = 0; ///< Cached signature
//
// Static (internal) function prototypes
//
/**
Copy memory from source to destination.
@param[out] Destination Pointer to the destination buffer.
@param[in] Source Pointer to the source buffer.
@param[in] Length Number of bytes to copy.
@return Destination pointer.
**/
STATIC
VOID *
EFIAPI
InternalCopyMem (
OUT VOID *Destination,
IN CONST VOID *Source,
IN UINTN Length
);
/**
Compare two memory buffers.
@param[in] DestinationBuffer Pointer to the first buffer.
@param[in] SourceBuffer Pointer to the second buffer.
@param[in] Length Number of bytes to compare.
@return 0 if the buffers are equal; nonzero if they differ.
**/
STATIC
INTN
EFIAPI
InternalCompareMem (
IN CONST VOID *DestinationBuffer,
IN CONST VOID *SourceBuffer,
IN UINTN Length
);
/**
Read a 64-bit value from an unaligned pointer.
@param[in] Buffer Pointer to read from.
@return The 64-bit value at the pointer.
**/
STATIC
UINT64
EFIAPI
ReadUnaligned64 (
IN CONST VOID *Buffer
);
/**
Read the GUID portion of a HOB entry for comparison.
@param[in] HobGuid Pointer to the GUID in a HOB.
@param[in] Guid2 Pointer to the GUID to compare against.
@retval TRUE The GUIDs match.
@retval FALSE The GUIDs do not match.
**/
STATIC
BOOLEAN
EFIAPI
IsHobGuidEqual (
IN CONST EFI_GUID *HobGuid,
IN CONST EFI_GUID *Guid2
);
/**
Write a 16-bit value to an I/O port.
@param[in] Port The I/O port address to write to.
**/
STATIC
VOID
EFIAPI
IoWrite16 (
IN UINT16 Port
);
/**
Read a 32-bit value from an I/O port.
@param[in] Port The I/O port address to read from.
@return The 32-bit value read from the port.
**/
STATIC
UINT32
EFIAPI
IoRead32 (
IN UINT16 Port
);
/**
Read the CPU's timestamp counter.
@return The current TSC value.
**/
STATIC
UINT64
EFIAPI
ReadTimestampCounter (
VOID
);
/**
Read the caller's EFLAGS register.
@return The EFLAGS value at the call site.
**/
STATIC
UINT64
EFIAPI
ReadCallerEflags (
VOID
);
/**
Halt the CPU (PAUSE instruction).
**/
STATIC
VOID
EFIAPI
CpuPause (
VOID
);
/**
Enable interrupts.
**/
STATIC
VOID
EFIAPI
EnableInterrupts (
VOID
);
/**
Disable interrupts.
**/
STATIC
VOID
EFIAPI
DisableInterrupts (
VOID
);
/**
Locate the ACPI Support protocol.
@return Pointer to the ACPI Support protocol interface, or NULL if not found.
**/
STATIC
VOID *
EFIAPI
GetAcpiSupportProtocol (
VOID
);
/**
Initialize the ACPI Support protocol and cache the interface pointer.
**/
STATIC
VOID
EFIAPI
InitializeAcpiSupport (
VOID
);
/**
Retrieve the HOB list pointer.
@return Pointer to the HOB list, or 0 if not found.
**/
STATIC
UINT64
EFIAPI
GetHobList (
VOID
);
/**
Find the next HOB of type EFI_HOB_TYPE_RESOURCE_DESCRIPTOR
in the HOB list.
@param[in] HobStart Pointer to the current HOB.
@return Pointer to the resource descriptor HOB, or 0 if not found.
**/
STATIC
VOID *
EFIAPI
GetNextResourceHob (
IN VOID *HobStart
);
/**
Assertion handler used by UEFI library code. Prints the file/line/expression
and enters deadloop.
@param[in] FileName File name where the assertion occurred.
@param[in] LineNumber Line number of the assertion.
@param[in] Description The assertion expression string.
**/
STATIC
VOID
EFIAPI
AssertHandler (
IN CONST CHAR8 *FileName,
IN UINTN LineNumber,
IN CONST CHAR8 *Description
);
/**
Debug print implementation using CMOS port 0x70/0x71 serial redirection.
@param[in] ErrorLevel Debug error level mask.
@param[in] Format Format string.
@param[in] ... Variable arguments.
@return The character printed (or a status indicator).
**/
STATIC
CHAR8
EFIAPI
DebugPrint (
IN UINT64 ErrorLevel,
IN CONST CHAR8 *Format,
...
);
//
// UEFI Boot Services Table Library initialization
//
/**
Constructor for UefiBootServicesTableLib.
Saves ImageHandle, SystemTable, BootServices, and RuntimeServices
into global variables.
@param[in] ImageHandle The firmware allocated handle for the UEFI image.
@param[in] SystemTable A pointer to the EFI System Table.
**/
STATIC
VOID
EFIAPI
InitializeUefiBootServicesTable (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
gImageHandle = ImageHandle;
ASSERT (gImageHandle != NULL);
gST = SystemTable;
ASSERT (gST != NULL);
gBS = SystemTable->BootServices;
ASSERT (gBS != NULL);
gRT = SystemTable->RuntimeServices;
ASSERT (gRT != NULL);
}
/**
PCD Get interface wrapper.
Retrieves a token from the PCD database.
@param[in] TokenNumber The PCD token number to retrieve.
@return The value of the PCD token.
**/
STATIC
UINT64
EFIAPI
PcdGet32 (
IN UINTN TokenNumber
)
{
ASSERT (mPcdDb != NULL);
return ((UINT64 (*)(UINTN))(*((UINT64 *)mPcdDb + 4)))(TokenNumber);
}
/**
PCD Set interface wrapper.
Sets a token in the PCD database.
@param[in] TokenNumber The PCD token number to set.
@param[in] Value The value to write.
**/
STATIC
VOID
EFIAPI
PcdSet32 (
IN UINTN TokenNumber,
IN UINT64 Value
)
{
ASSERT (mPcdDb != NULL);
((VOID (*)(UINTN, UINT64))(*((UINT64 *)mPcdDb + 5)))(TokenNumber, Value);
}
//
// Memory Operations
//
/**
Copy memory from source to destination.
Implements a memcpy with overlapping support for forward/backward copies.
@param[out] Destination Pointer to the destination buffer.
@param[in] Source Pointer to the source buffer.
@param[in] Length Number of bytes to copy.
@return Destination pointer.
**/
STATIC
VOID *
EFIAPI
InternalCopyMem (
OUT VOID *Destination,
IN CONST VOID *Source,
IN UINTN Length
)
{
VOID *Dst;
UINTN LengthRemaining;
Dst = Destination;
if (Source < Destination && (UINT8 *)Source + Length - 1 >= (UINT8 *)Destination) {
//
// Overlapping with Source before Destination: copy backwards
//
CopyMemBackwards (Dst, Source, Length);
} else {
//
// Non-overlapping or Destination before Source: copy forwards
//
LengthRemaining = Length;
Length &= 7;
LengthRemaining >>= 3;
if (LengthRemaining > 0) {
CopyMem (Dst, Source, LengthRemaining * 8);
}
CopyMem ((UINT8 *)Dst + (LengthRemaining * 8),
(UINT8 *)Source + (LengthRemaining * 8),
Length);
}
return Dst;
}
/**
Compare two memory buffers.
@param[in] DestinationBuffer Pointer to the first buffer.
@param[in] SourceBuffer Pointer to the second buffer.
@param[in] Length Number of bytes to compare.
@return 0 if the buffers are equal; nonzero if they differ.
**/
STATIC
INTN
EFIAPI
InternalCompareMem (
IN CONST VOID *DestinationBuffer,
IN CONST VOID *SourceBuffer,
IN UINTN Length
)
{
CONST UINT8 *Dst;
CONST UINT8 *Src;
BOOLEAN IsEqual;
Dst = (CONST UINT8 *)DestinationBuffer;
Src = (CONST UINT8 *)SourceBuffer;
do {
if (Length == 0) {
break;
}
IsEqual = (*Dst++ == *Src++);
Length--;
} while (IsEqual);
return (INTN)(*(Dst - 1) - *(Src - 1));
}
//
// Unaligned and string operations
//
/**
Calculate the length of an ASCII string.
@param[in] String Pointer to the null-terminated ASCII string.
@return The number of characters in the string, excluding the terminator.
**/
STATIC
UINTN
EFIAPI
AsciiStrLen (
IN CONST CHAR8 *String
)
{
UINTN Length;
ASSERT (String != NULL);
Length = 0;
while (*String != '\0') {
if (Length >= MAX_UINT32) {
ASSERT (FALSE);
}
String++;
Length++;
}
return Length;
}
/**
Read a 64-bit value from an unaligned pointer.
@param[in] Buffer Pointer to read from.
@return The 64-bit value at the pointer.
**/
STATIC
UINT64
EFIAPI
ReadUnaligned64 (
IN CONST VOID *Buffer
)
{
ASSERT (Buffer != NULL);
return *(UINT64 *)Buffer;
}
/**
Read the GUID portion of a HOB entry for comparison.
@param[in] HobGuid Pointer to the GUID in a HOB.
@param[in] Guid2 Pointer to the GUID to compare against.
@retval TRUE The GUIDs match.
@retval FALSE The GUIDs do not match.
**/
STATIC
BOOLEAN
EFIAPI
IsHobGuidEqual (
IN CONST EFI_GUID *HobGuid,
IN CONST EFI_GUID *Guid2
)
{
return ReadUnaligned64 (HobGuid) == ReadUnaligned64 (Guid2) &&
ReadUnaligned64 ((UINT8 *)HobGuid + 8) == ReadUnaligned64 ((UINT8 *)Guid2 + 8);
}
//
// I/O and CPU helpers
//
/**
Write a 16-bit value to an I/O port.
@param[in] Port The I/O port address to write to.
**/
STATIC
VOID
EFIAPI
IoWrite16 (
IN UINT16 Port
)
{
ASSERT ((Port & 1) == 0);
*(volatile UINT16 *)(UINTN)Port = 0x500; // ACPI PM1a_CNT.SLP_TYPx + SLP_EN
}
/**
Read a 32-bit value from an I/O port.
@param[in] Port The I/O port address to read from.
@return The 32-bit value read from the port.
**/
STATIC
UINT32
EFIAPI
IoRead32 (
IN UINT16 Port
)
{
ASSERT ((Port & 3) == 0);
return __indword (Port);
}
/**
Read the CPU's timestamp counter.
@return The current TSC value.
**/
STATIC
UINT64
EFIAPI
ReadTimestampCounter (
VOID
)
{
return __rdtsc ();
}
/**
Read the caller's EFLAGS register via __getcallerseflags().
@return The EFLAGS value at the call site.
**/
STATIC
UINT64
EFIAPI
ReadCallerEflags (
VOID
)
{
return __getcallerseflags ();
}
/**
Halt the CPU (PAUSE instruction).
**/
STATIC
VOID
EFIAPI
CpuPause (
VOID
)
{
_mm_pause ();
}
/**
Enable interrupts.
**/
STATIC
VOID
EFIAPI
EnableInterrupts (
VOID
)
{
_enable ();
}
/**
Disable interrupts.
**/
STATIC
VOID
EFIAPI
DisableInterrupts (
VOID
)
{
_disable ();
}
//
// Protocol locator helpers
//
/**
Locate the ACPI Support protocol.
@return Pointer to the ACPI Support protocol interface, or NULL if not found.
**/
STATIC
VOID *
EFIAPI
GetAcpiSupportProtocol (
VOID
)
{
UINT64 Status;
VOID *Interface;
if (mAcpiSupport != NULL) {
return mAcpiSupport;
}
Status = gBS->LocateProtocol (&gEfiAcpiSupportProtocolGuid, NULL, &Interface);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "AcpiResLib: LibGetDsdt(): LocateProtocol(ACPISupport) returned %r \n", Status));
return NULL;
}
mAcpiSupport = Interface;
return Interface;
}
/**
Initialize ACPI Support protocol.
Allocates and enables the ACPI table storage.
**/
STATIC
VOID
EFIAPI
InitializeAcpiSupport (
VOID
)
{
VOID *AcpiSupport;
UINT64 Status;
AcpiSupport = GetAcpiSupportProtocol ();
Status = AcpiSupport->OpenTable (5, &mPciExpressBase); // Allocate 5 pages for ACPI tables
ASSERT_EFI_ERROR (Status);
AcpiSupport->SetAcpiTable (&mPciExpressBase, 0, 0);
}
//
// HOB list management
//
/**
Retrieve the HOB list pointer from the HOB list GUID in the System Table
ConfigurationTable array.
@return Pointer to the HOB list, or 0 if not found.
**/
STATIC
UINT64
EFIAPI
GetHobList (
VOID
)
{
UINTN Index;
UINT64 HobListAddr;
UINTN NumberOfTableEntries;
if (mHobList != 0) {
return mHobList;
}
mHobList = 0;
NumberOfTableEntries = gST->NumberOfTableEntries;
for (Index = 0; Index < NumberOfTableEntries; Index++) {
if (IsHobGuidEqual (&gEfiHobListGuid,
(EFI_GUID *)(gST->ConfigurationTable + (Index * sizeof (EFI_CONFIGURATION_TABLE))))) {
HobListAddr = *(UINT64 *)(gST->ConfigurationTable + (Index * sizeof (EFI_CONFIGURATION_TABLE) + sizeof (EFI_GUID)));
mHobList = HobListAddr;
return HobListAddr;
}
}
DEBUG ((DEBUG_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", EFI_NOT_FOUND));
ASSERT (!EFI_ERROR (EFI_NOT_FOUND));
ASSERT (mHobList != NULL);
return mHobList;
}
/**
Find the next HOB of type EFI_HOB_TYPE_RESOURCE_DESCRIPTOR
in the HOB list.
@param[in] HobStart Pointer to the current HOB.
@return Pointer to the resource descriptor HOB, or 0 if not found.
**/
STATIC
VOID *
EFIAPI
GetNextResourceHob (
IN VOID *HobStart
)
{
UINT16 *Hob;
Hob = (UINT16 *)HobStart;
if (Hob == NULL) {
ASSERT (HobStart != NULL);
}
while (TRUE) {
if (*Hob == 0xFFFF) {
//
// End of HOB list
//
return NULL;
}
if (*Hob == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
break;
}
Hob = (UINT16 *)((UINT8 *)Hob + Hob[1]);
}
return Hob;
}
//
// Assert and Debug
//
/**
Assertion handler used by UEFI library code. Prints the file/line/expression
and enters deadloop if debug is enabled.
@param[in] FileName File name where the assertion occurred.
@param[in] LineNumber Line number of the assertion.
@param[in] Description The assertion expression string.
**/
STATIC
VOID
EFIAPI
AssertHandler (
IN CONST CHAR8 *FileName,
IN UINTN LineNumber,
IN CONST CHAR8 *Description
)
{
VOID *DebugProtocol;
DebugProtocol = GetAcpiSupportProtocol ();
if (DebugProtocol != NULL) {
DebugProtocol->DebugAssert (FileName, LineNumber, Description);
}
}
/**
Debug print implementation using internal debug protocol.
@param[in] ErrorLevel Debug error level mask.
@param[in] Format Format string.
@param[in] ... Variable arguments.
@return The character printed (or a status indicator).
**/
STATIC
CHAR8
EFIAPI
DebugPrint (
IN UINT64 ErrorLevel,
IN CONST CHAR8 *Format,
...
)
{
VOID *DebugProtocol;
UINT8 CmosIndex;
UINT8 CmosData;
UINT8 DebugLevel;
UINT8 DebugLevel2;
UINT64 OutputType;
VA_LIST Args;
VA_START (Args, Format);
DebugProtocol = GetAcpiSupportProtocol ();
if (DebugProtocol == NULL) {
VA_END (Args);
return 0;
}
//
// Read CMOS index 0x4B to determine debug routing
//
CmosIndex = __inbyte (0x70);
__outbyte (0x70, CmosIndex & 0x80 | 0x4B);
CmosData = __inbyte (0x71);
DebugLevel = CmosData;
if (DebugLevel > 3) {
DebugLevel2 = CmosData;
if (DebugLevel2 == 0) {
DebugLevel2 = (MEMORY[0xFDAF0490] & 2) | 1;
}
}
DebugLevel = DebugLevel - 1;
if (DebugLevel <= 0xFD) {
DebugLevel = 4;
OutputType = DEBUG_INFO;
if (CmosData == 1) {
OutputType = DEBUG_WARN;
}
}
if ((OutputType & ErrorLevel) != 0) {
return DebugProtocol->DebugPrint (ErrorLevel, Format, Args);
}
VA_END (Args);
return 0;
}
// ---------------------------------------------------------------------------
// DSDT Locator
// ---------------------------------------------------------------------------
/**
Locate the DSDT address by searching RSDT/XSDT tables from the
ACPI Support protocol.
Walks the RSDT (v1.0b) and XSDT (v2.0+) entries to find the
DSDT signature and caches the address in mDsdtAddr/mXsdtDsdtAddr.
@param[out] DsdtAddr Pointer to receive the DSDT address.
@retval EFI_SUCCESS DSDT was found and cached.
@retval EFI_NOT_FOUND DSDT could not be located.
@retval EFI_INVALID_PARAMETER DsdtAddr is NULL.
@retval EFI_UNSUPPORTED ACPI Support protocol not available.
**/
EFI_STATUS
EFIAPI
LibGetDsdt (
OUT UINT64 *DsdtAddr
)
{
EFI_STATUS Status;
VOID *AcpiSupport;
UINTN TableIndex;
EFI_ACPI_TABLE_VERSION TableVersion;
VOID *Table;
UINTN TableKey;
UINT64 DsdtAddress;
UINT32 *RsdtEntry;
UINT64 *XsdtEntry;
UINTN NumberOfTableEntries;
UINTN EntryIndex;
if (DsdtAddr == NULL) {
return EFI_INVALID_PARAMETER;
}
//
// Check cache first
//
if (mDsdtAddr != 0 && mXsdtDsdtAddr != 0) {
*DsdtAddr = (mXsdtDsdtAddr != 0) ? mXsdtDsdtAddr : mDsdtAddr;
return EFI_SUCCESS;
}
//
// Locate ACPI Support protocol
//
AcpiSupport = GetAcpiSupportProtocol ();
if (AcpiSupport == NULL) {
return EFI_UNSUPPORTED;
}
//
// Get the RSDT/XSDT table
//
TableIndex = 0;
while (TRUE) {
Status = AcpiSupport->GetAcpiTable (TableIndex, &Table, &TableVersion, &TableKey);
if (EFI_ERROR (Status)) {
break;
}
//
// Check for RSDT (1.0b) or XSDT (2.0+)
//
if (*(UINT32 *)Table == EFI_ACPI_RSDT_SIGNATURE) {
//
// RSDT found - search for DSDT pointer
//
NumberOfTableEntries = (*(UINT32 *)((UINT8 *)Table + 4) - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof (UINT32);
RsdtEntry = (UINT32 *)((UINT8 *)Table + sizeof (EFI_ACPI_DESCRIPTION_HEADER));
for (EntryIndex = 0; EntryIndex < NumberOfTableEntries; EntryIndex++) {
if (*(UINT32 *)(UINTN)RsdtEntry[EntryIndex] == EFI_ACPI_DSDT_SIGNATURE) {
mDsdtAddr = RsdtEntry[EntryIndex];
DEBUG ((DEBUG_INFO, "AcpiResLib: LibGetDsdt(): Found v1.0b RSDT->DSDT @ 0x%lX\n", mDsdtAddr));
break;
}
}
}
if (*(UINT32 *)Table == EFI_ACPI_XSDT_SIGNATURE) {
//
// XSDT found - search for DSDT pointer
//
NumberOfTableEntries = (*(UINT32 *)((UINT8 *)Table + 4) - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof (UINT64);
XsdtEntry = (UINT64 *)((UINT8 *)Table + sizeof (EFI_ACPI_DESCRIPTION_HEADER));
for (EntryIndex = 0; EntryIndex < NumberOfTableEntries; EntryIndex++) {
if (*(UINT32 *)(UINTN)XsdtEntry[EntryIndex] == EFI_ACPI_DSDT_SIGNATURE) {
mXsdtDsdtAddr = XsdtEntry[EntryIndex];
DEBUG ((DEBUG_INFO, "AcpiResLib: LibGetDsdt(): Found v2.0&UP XSDT->DSDT @ 0x%lX\n", mXsdtDsdtAddr));
break;
}
}
}
TableIndex++;
}
//
// Report if we couldn't find DSDT
//
if (mDsdtAddr == 0 && mXsdtDsdtAddr == 0) {
DEBUG ((DEBUG_ERROR, "Can't find Dsdt table -> %r search %d Tables\n", EFI_NOT_FOUND, TableIndex));
return EFI_NOT_FOUND;
}
*DsdtAddr = (mXsdtDsdtAddr != 0) ? mXsdtDsdtAddr : mDsdtAddr;
return EFI_SUCCESS;
}
// ---------------------------------------------------------------------------
// ACPI AML Write Helper
// ---------------------------------------------------------------------------
/**
Write an integer value into an ACPI AML buffer at a location
identified by a signature search.
Searches the DSDT for the specified signature bytes, then writes
the given value into the AML encoding at that location based on the
opcode (BYTE, WORD, DWORD, QWORD).
@param[in] DsdtBase Base address of the DSDT.
@param[in] DsdtSize Size of the DSDT in bytes.
@param[in] Signature 4-byte signature to search for in the DSDT.
@param[in] Value The value to write.
@retval EFI_SUCCESS The value was written successfully.
@retval EFI_NOT_FOUND The signature was not found in the DSDT.
@retval EFI_INVALID_PARAMETER The AML opcode at the location is unrecognized.
@retval EFI_BUFFER_TOO_SMALL The DSDT region is too small for the value.
**/
EFI_STATUS
EFIAPI
AcpiAmlWriteInteger (
IN UINT64 DsdtBase,
IN UINT64 DsdtSize,
IN UINT32 Signature,
IN UINT64 Value
)
{
UINT8 *BytePtr;
UINTN Offset;
UINTN FoundOffset;
BOOLEAN Found;
Found = FALSE;
FoundOffset = 0;
while (TRUE) {
//
// Search for the signature in the DSDT
//
for (Offset = FoundOffset; Offset < DsdtSize; Offset += 4) {
if (*(UINT32 *)(DsdtBase + Offset) == Signature) {
FoundOffset = Offset;
Found = TRUE;
break;
}
}
if (!Found) {
return EFI_NOT_FOUND;
}
//
// Check the AML NameString prefix before the signature
//
BytePtr = (UINT8 *)(DsdtBase + FoundOffset - 1);
if (((*BytePtr - 0x5C) & 0xFD) == 0) {
BytePtr--;
}
if (*(BytePtr - 1) == AML_DUAL_NAME_PREFIX) {
break;
}
//
// Skip past this match and search again
//
DsdtSize -= FoundOffset + 4;
DsdtBase += FoundOffset + 4;
FoundOffset = 0;
}
//
// Write the value based on the AML opcode after the signature
//
switch (*(BytePtr + 4)) {
case AML_ZERO_OP:
case AML_ONE_OP:
//
// Replace ZeroOp/OneOp with the value
//
if (Value > 1) {
return EFI_INVALID_PARAMETER;
}
*(BytePtr + 4) = (UINT8)Value;
return EFI_SUCCESS;
case AML_BYTE_PREFIX:
*(BytePtr + 5) = (UINT8)Value;
return EFI_SUCCESS;
case AML_WORD_PREFIX:
*(UINT16 *)(BytePtr + 5) = (UINT16)Value;
return EFI_SUCCESS;
case AML_DWORD_PREFIX:
*(UINT32 *)(BytePtr + 5) = (UINT32)Value;
return EFI_SUCCESS;
case AML_QWORD_PREFIX:
*(UINT64 *)(BytePtr + 5) = Value;
return EFI_SUCCESS;
default:
return EFI_INVALID_PARAMETER;
}
}
// ---------------------------------------------------------------------------
// TPM Hardware Detection
// ---------------------------------------------------------------------------
/**
Check if TPM 2.0 hardware is present and active.
Reads the TPM interface ID register at 0xFED40030.
If the value is not 0xFFFFFFFF (no device) and is nonzero,
TPM hardware is considered present.
@retval TRUE TPM hardware is present.
@retval FALSE TPM hardware is not present.
**/
STATIC
BOOLEAN
EFIAPI
IsTpmHwPresent (
VOID
)
{
return (MEMORY[TPM_REG_BASE + 0x30] != 0xFFFFFFFF) &&
(MEMORY[TPM_REG_BASE + 0x30] != 0);
}
/**
Get the TPM interface type.
Reads the lower nibble of the TPM interface ID register.
@return The TPM interface type (0-15), or the result of sub_1534()
if hardware is not present.
**/
STATIC
UINT8
EFIAPI
GetTpmInterfaceType (
VOID
)
{
UINT8 InterfaceType;
InterfaceType = MEMORY[TPM_REG_BASE + 0x30] & 0x0F;
if (IsTpmHwPresent ()) {
return InterfaceType;
} else {
return (UINT8)sub_1534 ();
}
}
/**
Determine if TPM is available.
Checks via the firmware TPM detection flag, and falls back
to hardware detection (FIFO/TIS interface type == 1).
@retval TRUE TPM is available.
@retval FALSE TPM is not available.
**/
STATIC
BOOLEAN
EFIAPI
IsTpmAvailable (
VOID
)
{
if (sub_1534 () != 0) {
return TRUE;
}
return IsTpmHwPresent () && (GetTpmInterfaceType () == 1);
}
//
// PCI Express MMIO access
//
/**
Read from PCI Express configuration space via MMIO.
@param[in] Address The PCI Express extended configuration space address.
@return The value at the address plus the PCI Express base.
**/
STATIC
UINT64
EFIAPI
PciExpressRead (
IN UINT64 Address
)
{
ASSERT ((Address & ~0xFFFFFFF) == 0);
return Address + mPciExpressBase;
}
// ---------------------------------------------------------------------------
// Main TPM ACPI Initialization
// ---------------------------------------------------------------------------
/**
TPM 2.0 ACPI initialization entry function.
This is the main initialization routine called as a callback. It:
1. Initializes the ACPI support protocol and PCD database
2. Locates the DSDT table
3. Detects TPM hardware (FIFO/TIS vs TPP vs no TPM)
4. Determines the TPM stolen memory address
5. Programs the ACPI SSDT tables with TPM configuration
6. Installs the TPM2 ACPI table
@param[in] a1 The event context (ImageHandle-like).
@retval EFI_SUCCESS The TPM ACPI tables were published successfully.
@retval Others An error occurred.
**/
EFI_STATUS
EFIAPI
Tpm20AcpiInitEntry (
IN UINT64 a1
)
{
EFI_STATUS Status;
UINT64 DsdtAddr;
UINT64 StolenAddr;
UINT64 HobPtr;
VOID *ResourceHob;
UINT64 StolenAddressLoc;
UINT64 *CtrlAreaMap;
UINT64 TpmModeN2;
UINT64 PcdPtr;
UINT64 Tpm24Data;
UINT64 Status2;
VOID *DsdtInterface;
UINT64 Result;
UINT64 Buffer;
UINT64 DsdtSignature;
VOID *BufferPtr;
//
// Locate DSDT
//
Status = LibGetDsdt (&DsdtAddr);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Initialize ACPI tables
//
InitializeAcpiSupport ();
//
// Detect TPM hardware availability
//
if (!IsTpmAvailable ()) {
//
// No TPM: set defaults
//
mTpmStolenAddr = 0;
mTpmMode = 6; // No TPM
//
// Write no-TPM configuration to DSDT
//
Status = AcpiAmlWriteInteger (DsdtAddr, MAX_UINT32, SIGNATURE_AMDT, 0);
if (EFI_ERROR (Status)) return Status;
Status = AcpiAmlWriteInteger (DsdtAddr, MAX_UINT32, SIGNATURE_DTPT, 0);
if (EFI_ERROR (Status)) return Status;
//
// Write "TPMM" with default stolen address (no TPM)
//
Status = AcpiAmlWriteInteger (DsdtAddr, MAX_UINT32, SIGNATURE_TPMM, 0xFED00000);
if (EFI_ERROR (Status)) return Status;
return EFI_SUCCESS;
}
//
// TPM is available - write TPMF=1
//
Status = AcpiAmlWriteInteger (DsdtAddr, MAX_UINT32, SIGNATURE_TPMF, 1);
if (EFI_ERROR (Status)) return Status;
//
// Check if TPM has active interface
//
if (MEMORY[TPM_REG_BASE + TPM_CTRL_AREA_OFFSET] == 0xFFFFFFFF) {
//
// TPM with no active interface (TPP mode)
//
mTpmMode = 7;
mTpmStolenAddr = 0xFED00080;
//
// Dump CtrlAreaMap registers
//
DEBUG ((DEBUG_INFO, "CtrlAreaMap->Error = %x \n", MEMORY[TPM_REG_BASE + TPM_CTRL_ERROR]));
DEBUG ((DEBUG_INFO, "CtrlAreaMap->Cancel = %x \n", MEMORY[TPM_REG_BASE + TPM_CTRL_CANCEL]));
DEBUG ((DEBUG_INFO, "CtrlAreaMap->Start = %x \n", MEMORY[TPM_REG_BASE + TPM_CTRL_START]));
DEBUG ((DEBUG_INFO, "CtrlAreaMap->Reserved = %x \n", MEMORY[TPM_REG_BASE + TPM_CTRL_RESERVED]));
DEBUG ((DEBUG_INFO, "CtrlAreaMap->CommandSize = %x \n", MEMORY[TPM_REG_BASE + TPM_CTRL_COMMAND_SIZE]));
DEBUG ((DEBUG_INFO, "CtrlAreaMap->Command = %x \n", MEMORY[TPM_REG_BASE + TPM_CTRL_COMMAND]));
DEBUG ((DEBUG_INFO, "CtrlAreaMap->ResponseSize = %x \n", MEMORY[TPM_REG_BASE + TPM_CTRL_RESPONSE_SIZE]));
DEBUG ((DEBUG_INFO, "CtrlAreaMap->Response = %x \n", MEMORY[TPM_REG_BASE + TPM_CTRL_RESPONSE]));
Status = AcpiAmlWriteInteger (DsdtAddr, MAX_UINT32, SIGNATURE_TPMM, (UINT32)(mTpmStolenAddr - 64));
if (EFI_ERROR (Status)) return Status;
Status = AcpiAmlWriteInteger (DsdtAddr, MAX_UINT32, SIGNATURE_FTPM, (UINT32)mTpmStolenAddr);
if (EFI_ERROR (Status)) return Status;
Status = AcpiAmlWriteInteger (DsdtAddr, MAX_UINT32, SIGNATURE_AMDT, 0);
if (EFI_ERROR (Status)) return Status;
//
// Program "DTPT" with 1
//
Status = AcpiAmlWriteInteger (DsdtAddr, MAX_UINT32, SIGNATURE_DTPT, 1);
if (EFI_ERROR (Status)) return Status;
} else {
//
// TPM with active interface - find stolen address from HOB
//
HobPtr = GetHobList ();
StolenAddressLoc = 0;
for (HobPtr = GetHobList (); ; HobPtr = (UINT64)((UINT8 *)HobPtr + *(UINT16 *)(HobPtr + 2))) {
ResourceHob = GetNextResourceHob ((VOID *)HobPtr);
if (ResourceHob == NULL) {
break;
}
if (IsHobGuidEqual ((EFI_GUID *)((UINT8 *)ResourceHob + 8), (EFI_GUID *)mGuid)) {
break;
}
}
DEBUG ((DEBUG_INFO, "Tpm20Acpi StolenAddress = %x \n", *(UINT64 *)((UINT8 *)ResourceHob + 24)));
DEBUG ((DEBUG_INFO, "Tpm20Acpi StolenAddress Loc = %x \n", ResourceHob));
//
// Determine stolen address
//
StolenAddr = STOLEN_ADDR_DEFAULT;
if (*(UINT64 *)((UINT8 *)ResourceHob + 24) != 0) {
StolenAddr = *(UINT64 *)((UINT8 *)ResourceHob + 24);
}
mTpmStolenAddr = StolenAddr;
mTpmMode = 2; // TPM2 with DMA
//
// Zero the stolen memory region if it's not the default location
//
if (StolenAddr != STOLEN_ADDR_DEFAULT) {
gBS->SetMem ((VOID *)StolenAddr, 48, 0);
}
//
// Set up TPM control area in stolen memory
//
*(UINT32 *)(StolenAddr + 24) = 0; // Response
*(UINT32 *)(StolenAddr + 36) = 0; // ResponseSize
*(UINT64 *)(StolenAddr + 28) = (UINT64)(StolenAddr + 128); // Command buffer
*(UINT64 *)(StolenAddr + 40) = (UINT64)(StolenAddr + 128); // Response buffer
Status = AcpiAmlWriteInteger (DsdtAddr, MAX_UINT32, SIGNATURE_TPMM, STOLEN_ADDR_DEFAULT);
if (EFI_ERROR (Status)) return Status;
Status = AcpiAmlWriteInteger (DsdtAddr, MAX_UINT32, SIGNATURE_FTPM, (UINT32)mTpmStolenAddr);
if (EFI_ERROR (Status)) return Status;
Status = AcpiAmlWriteInteger (DsdtAddr, MAX_UINT32, SIGNATURE_AMDT, 0);
if (EFI_ERROR (Status)) return Status;
//
// Program "DTPT" with 0
//
Status = AcpiAmlWriteInteger (DsdtAddr, MAX_UINT32, SIGNATURE_DTPT, 0);
if (EFI_ERROR (Status)) return Status;
}
//
// Install TPM2 ACPI table
//
if (mTpmMode == 2) {
//
// Allocate and populate TPM2 table
//
Status = gBS->AllocatePool (EfiBootServicesData, 56, &BufferPtr);
if (EFI_ERROR (Status)) return Status;
gBS->SetMem (BufferPtr, 56, 0);
//
// Copy "TPM24" signature header (52 bytes)
//
CopyMem (BufferPtr, "TPM24", 52);
*(UINT32 *)((UINT8 *)BufferPtr + 4) = *(UINT32 *)&"TPM24"[4] + 4;
//
// Install via ACPI table protocol
//
Status = ((EFI_ACPI_TABLE_PROTOCOL *)DsdtInterface)->InstallAcpiTable (
(EFI_ACPI_TABLE_PROTOCOL *)DsdtInterface,
BufferPtr,
56,
(UINTN *)&Buffer
);
gBS->FreePool (BufferPtr);
} else {
//
// Direct install of TPM24 signature
//
Status = ((EFI_ACPI_TABLE_PROTOCOL *)DsdtInterface)->InstallAcpiTable (
(EFI_ACPI_TABLE_PROTOCOL *)DsdtInterface,
"TPM24",
52,
(UINTN *)&Buffer
);
}
if (EFI_ERROR (Status)) {
return Status;
}
//
// Signal that initialization is complete
//
Status = gBS->SignalEvent ((EFI_EVENT)a1);
return Status;
}
// ---------------------------------------------------------------------------
// Module Entry Point
// ---------------------------------------------------------------------------
/**
Entry point to the Tpm20Acpi UEFI driver.
Saves the UEFI boot/runtime service pointers, initializes the
PCD database, sets up the HOB list, registers the initialization
event, and returns.
@param[in] ImageHandle The firmware allocated handle for the UEFI image.
@param[in] SystemTable A pointer to the EFI System Table.
@retval EFI_SUCCESS The driver entry point executed successfully.
**/
EFI_STATUS
EFIAPI
ModuleEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
//
// Initialize UEFI Boot/Runtime Services Table
//
InitializeUefiBootServicesTable (ImageHandle, SystemTable);
//
// Initialize PCD database via LocateProtocol
//
mPcdDb = (UINT64)PcdGet32 (5);
if (*(CHAR8 *)PciExpressRead (PCD_TOKEN_SOMETHING) >= 0) {
PcdSet32 (PCD_TOKEN_SOMETHING, PcdGet32 (PCD_TOKEN_SOMETHING_ELSE));
*(UINT8 *)PciExpressRead (PCD_TOKEN_FLAGS) |= 0x80;
}
//
// Detect TPM hardware via EFLAGS.IF check
//
if (ReadCallerEflags () & 0x200) {
EnableInterrupts ();
DisableInterrupts ();
}
//
// Initialize ACPI tables
//
InitializeAcpiSupport ();
//
// Timeout loop using TSC
//
while (((IoRead32 (1288) + 357 - IoRead32 (1288)) & 0x800000) == 0) {
CpuPause ();
}
//
// Enable/disable interrupts based on original state
//
EnableInterrupts ();
if (ReadCallerEflags () & 0x200) {
EnableInterrupts ();
} else {
DisableInterrupts ();
}
//
// Register the initialization event via CreateEvent
//
return gBS->CreateEvent (
EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
(EFI_EVENT_NOTIFY)Tpm20AcpiInitEntry,
NULL,
&ImageHandle
);
}