/** @file
TpmSmbiosDxe -- TPM SMBIOS DXE Driver
This DXE driver populates SMBIOS tables with TPM device information.
It supports both TPM 1.2 and TPM 2.0 devices and provides firmware
version, vendor ID, and capability information to the SMBIOS table.
Source: AMI ModulePkg TCG2 TpmSmbios
Original Path: e:\hs\AmiModulePkg\TCG2\Common\TpmSmbios\TpmSmbiosDxe.c
This module:
- Registers protocol notification callbacks for gEfiTrEEProtocolGuid
and gEfiTcgProtocolGuid.
- On TCG protocol availability, collects TPM 1.2 or 2.0 capability data
and populates the TCG protocol structure.
- On TrEE protocol availability, collects TPM 2.0 capability data and
populates the TrEE protocol structure.
- Populates the SMBIOS table (Type 43) with TPM device information
including vendor ID, firmware version, and characteristics.
Copyright (c) 2025, American Megatrends Inc. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "TpmSmbiosDxe.h"
//
// GUID Definitions
//
EFI_GUID gEfiSmbiosProtocolGuid = { 0x0B30D3F9, 0xD8F0, 0x432A, { 0x90, 0x1C, 0x29, 0xC7, 0x41, 0x06, 0xA6, 0xE8 } };
EFI_GUID gEfiTcgProtocolGuid = { 0x41EC7F2C, 0x12F8, 0x4F5E, { 0x97, 0x08, 0xDF, 0x3E, 0x82, 0x80, 0x9B, 0x7B } };
EFI_GUID gEfiTrEEProtocolGuid = { 0x607F766C, 0x7455, 0x42BE, { 0x93, 0x0B, 0xE4, 0xD7, 0x6D, 0xB2, 0x72, 0x0F } };
EFI_GUID gEfiTpmDeviceInstanceGuid = { 0x5C738E09, 0x9E52, 0x4C9B, { 0x90, 0x06, 0x00, 0x0A, 0xB3, 0xF2, 0xE0, 0x8D } };
//
// Globals from UEFI Boot/Runtime Services Table Library
//
EFI_HANDLE gImageHandle = NULL;
EFI_SYSTEM_TABLE *gST = NULL;
EFI_BOOT_SERVICES *gBS = NULL;
EFI_RUNTIME_SERVICES *gRT = NULL;
//
// Module Global Variables (mapped from .data section)
//
// NOTE: These variable names correspond to the decompiler-generated labels
// and should be renamed as understanding of their purpose improves.
//
/// The ImageHandle passed to the driver entry point (saved for later use).
EFI_HANDLE ImageHandle_0 = NULL;
/// The SystemTable pointer (saved for module-internal use).
UINTN SystemTable = 0;
/// The BootServices pointer (extracted from SystemTable).
UINTN BootServices = 0;
/// The RuntimeServices pointer (extracted from SystemTable).
UINTN RuntimeServices = 0;
/// TPM Vendor ID (from TPM capabilities).
UINT32 dword_2C64 = 0;
/// TPM Specification Version: Major (LO byte), Minor (HI byte).
UINT16 word_2C68 = 0;
/// TPM Firmware Version 1.
UINT32 dword_2C6A = 0;
/// TPM Firmware Version 2.
UINT32 dword_2C6E = 0;
/// Characteristics.Unsupported bit flag.
UINT8 byte_2C72 = 0;
/// TPM Characteristics flags (bitfield).
UINT64 qword_2C73 = 0;
/// OemDefined value.
UINT32 dword_2C7B = 0;
/// TPM 2.0 vendor string length.
UINT8 byte_2C61 = 0;
//
// TPM Vendor ID to Name Lookup Table
// Indexed by 12-byte entries: VendorId (UINT32), NamePointer (CHAR8*)
// (17 entries covering 0xCC bytes at address 0x2C80)
//
TPM_VENDOR_ID_MAP VendorIdMap[17] = {
{ 0x484F4E20, "HON HAI" }, // 0x2C80: 0x484F4E20 (HON\0)
{ 0x49424D20, "IBM" }, // 0x2C8C
{ 0x49465820, "Infineon" }, // 0x2C98: 0x49465820 (IFX\0)
{ 0x494E5443, "Intel" }, // 0x2CA4: 0x494E5443 (INTC)
{ 0x4E544300, "NTC" }, // 0x2CB0
{ 0x534C4230, "SLB0" }, // 0x2CBC
{ 0x534D5343, "SMSC" }, // 0x2CC8
{ 0x53545320, "STM" }, // 0x2CD4: 0x53545320 (STS\0)
{ 0x54474E20, "TGN" }, // 0x2CE0
{ 0x57454320, "WEC" }, // 0x2CEC: 0x57454320 (WEC\0)
{ 0x4E544300, "NTC" }, // 0x2CF8 (duplicate)
{ 0x4E544300, "NTC" }, // 0x2D04 (duplicate)
{ 0x4154534D, "ATSM" }, // 0x2D10
{ 0x4D534654, "MSFT" }, // 0x2D1C
{ 0x4E534D20, "NSM" }, // 0x2D28
{ 0x4E544300, "NTC" }, // 0x2D34 (duplicate)
{ 0x4E544300, "NTC" }, // 0x2D40 (duplicate)
};
//
/// TPM Device ID comparison table (address 0x2D50).
/// Used by IsTpm20() to compare device IDs at FED40000.
///
UINT64 qword_2D50[3];
//
/// SMBIOS protocol pointer (queried via gBS->LocateProtocol).
///
UINTN qword_2D60 = 0;
//
/// TrEE protocol pointer.
///
UINTN qword_2D68 = 0;
//
/// TCG protocol pointer.
///
UINTN qword_2D70 = 0;
//
/// TPM support HOB data pointer (retrieved from HOB list).
///
UINTN qword_2D78 = 0;
//
/// Debug library output protocol (for DebugPrint/DebugAssert).
///
UINTN qword_2DA0 = 0;
//
/// PCD protocol pointer.
///
UINTN qword_2DA8 = 0;
//
/// HOB list pointer.
///
UINTN qword_2DB0 = 0;
//
/// PCI Express memory-mapped base address.
///
UINTN qword_2DB8 = 0;
//
/// TPM 2.0 GET_CAPABILITY response buffer at 0x2DD0.
///
UINT64 qword_2DD0[2];
UINT16 word_2DD6;
UINT8 byte_2DD9;
UINT64 qword_2DE0;
UINT16 word_2DE8;
UINT8 byte_2DEA;
//
/// TPM2 GET_CAPABILITY response buffer at 0x2EF0.
///
UINT64 qword_2EF0[2];
UINT16 word_2EFE;
UINT64 qword_2F00[2];
//
/// TCG notification callback context.
///
UINT64 qword_2FF0[2];
//
/// TPM 1.2 GET_CAPABILITY response buffer at 0x3000.
///
UINT8 unk_3000[26];
UINT16 word_3006;
UINT8 byte_3009;
UINT64 qword_3010;
UINT16 word_3018;
UINT8 byte_301A;
//
/// Protocol registration keys (for gBS->RegisterProtocolNotify).
///
UINT64 unk_3100[2]; // TrEE registration
UINT64 unk_3108[2]; // SMBIOS registration
UINT64 unk_3110[2]; // TCG registration
//
// Helper: n25 used as TPM2 capability command size
//
UINT64 n25 = 25;
//
// n513 used as TPM2 firmware version indicator
//
UINT16 n513 = 513;
// Forward declaration of local helpers
static
CHAR8
TpmDxeTcgCallback (
IN EFI_EVENT Event,
IN VOID *Context
);
static
EFI_STATUS
TpmDxeTrEECallback (
IN EFI_EVENT Event,
IN VOID *Context
);
//----------------------------------------------------------------------
// Low-level CPU and I/O helper functions
//----------------------------------------------------------------------
/**
Empty function that executes a CPU pause instruction (hint for
hyper-threading to yield).
**/
VOID
CpuPause (
VOID
)
{
_mm_pause ();
}
/**
Reads the Time-Stamp Counter (TSC).
@return The current 64-bit TSC value.
**/
UINT64
ReadTsc (
VOID
)
{
return __rdtsc ();
}
/**
Enables interrupts (STI).
**/
VOID
EnableInterrupts (
VOID
)
{
_enable ();
}
/**
Disables interrupts (CLI).
**/
VOID
DisableInterrupts (
VOID
)
{
_disable ();
}
/**
Reads the current EFLAGS register.
@return The current EFLAGS value.
**/
UINTN
ReadEflags (
VOID
)
{
return __getcallerseflags ();
}
//----------------------------------------------------------------------
// Memory operation wrappers
//----------------------------------------------------------------------
/**
Copies a block of memory from one location to another, handling
overlapping regions correctly.
@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.
**/
CHAR8 *
InternalCopyMem (
OUT CHAR8 *Destination,
IN CONST CHAR8 *Source,
IN UINTN Length
)
{
CHAR8 *Dst;
CONST CHAR8 *Src;
UINTN Count;
Dst = Destination;
if ((Source < Destination) && (&Source[Length - 1] >= Destination)) {
//
// Overlapping: copy from end to start
//
Src = &Source[Length - 1];
Dst = &Destination[Length - 1];
qmemcpy (Dst, Src, Length & 7);
} else {
//
// Non-overlapping: copy aligned chunks first, then remainder
//
Count = Length;
Length &= 7;
Count >>= 3;
qmemcpy (Destination, Source, 8 * Count);
Src = &Source[8 * Count];
Dst = &Destination[8 * Count];
qmemcpy (Dst, Src, Length);
}
return Destination;
}
/**
Fills a memory buffer with zeros.
@param[in] Buffer Pointer to the buffer to zero.
@param[in] Length Number of bytes to zero.
@return Buffer pointer.
**/
VOID *
InternalZeroMem (
IN VOID *Buffer,
IN UINTN Length
)
{
//
// Zero the buffer in aligned 8-byte chunks, then the remainder
//
memset (Buffer, 0, 8 * (Length >> 3));
memset ((UINT8 *)Buffer + 8 * (Length >> 3), 0, Length & 7);
return Buffer;
}
/**
Compares two memory buffers for equality.
@param[in] DestinationBuffer Pointer to first buffer.
@param[in] SourceBuffer Pointer to second buffer.
@param[in] Length Number of bytes to compare.
@return 0 if all bytes match, nonzero otherwise.
**/
INTN
InternalCompareMem (
IN CONST VOID *DestinationBuffer,
IN CONST VOID *SourceBuffer,
IN UINTN Length
)
{
CONST UINT8 *Dst;
CONST UINT8 *Src;
BOOLEAN Equal;
Dst = (CONST UINT8 *)DestinationBuffer;
Src = (CONST UINT8 *)SourceBuffer;
do {
if (Length == 0) {
break;
}
Equal = (*Dst++ == *Src++);
Length--;
} while (Equal);
return (INTN)(Dst[-1] - Src[-1]);
}
//----------------------------------------------------------------------
// Unaligned read / string length helpers
//----------------------------------------------------------------------
/**
Reads a UINT64 from a potentially unaligned address.
@param[in] Buffer Pointer to the UINT64 value.
@return The UINT64 value read.
**/
UINT64
ReadUnaligned64 (
IN CONST VOID *Buffer
)
{
if (Buffer == NULL) {
DEBUG ((EFI_D_ERROR, "Buffer != ((void *) 0)\n"));
ASSERT (Buffer != NULL);
}
return *(UINT64 *)Buffer;
}
/**
Returns the length of a null-terminated ASCII string.
@param[in] String A pointer to a null-terminated ASCII string.
@return The number of ASCII characters in the string (not including
the null terminator).
**/
UINTN
AsciiStrLen (
IN CONST CHAR8 *String
)
{
CONST CHAR8 *CharPtr;
UINTN Length;
if (String == NULL) {
DEBUG ((EFI_D_ERROR, "String != ((void *) 0)\n"));
ASSERT (String != NULL);
}
Length = 0;
CharPtr = String;
while (*CharPtr != '\0') {
Length++;
CharPtr++;
if (Length >= 0xF4240) {
DEBUG ((EFI_D_ERROR, "Length < _gPcd_FixedAtBuild_PcdMaximumAsciiStringLength\n"));
ASSERT (FALSE);
}
}
return Length;
}
//----------------------------------------------------------------------
// I/O port access wrappers
//----------------------------------------------------------------------
/**
Writes a 16-bit value to an I/O port (2-byte aligned).
@param[in] Address I/O port address (must be 2-byte aligned).
@param[in] Value 16-bit value to write.
**/
VOID
IoWrite16 (
IN UINTN Address,
IN UINT16 Value
)
{
if ((Address & 1) != 0) {
DEBUG ((EFI_D_ERROR, "(Address & 1) == 0\n"));
ASSERT ((Address & 1) == 0);
}
*(volatile UINT16 *)Address = Value;
}
/**
Reads a 32-bit value from an I/O port (4-byte aligned).
@param[in] Port I/O port address (must be 4-byte aligned).
@return The 32-bit value read.
**/
UINT32
IoRead32 (
IN UINTN Port
)
{
if ((Port & 3) != 0) {
DEBUG ((EFI_D_ERROR, "(Port & 3) == 0\n"));
ASSERT ((Port & 3) == 0);
}
return __indword (Port);
}
//----------------------------------------------------------------------
// PciExpressLib wrapper
//----------------------------------------------------------------------
/**
Translates a PCI Express address to a memory-mapped address by adding
the PCI Express base address.
@param[in] Address PCI Express bus/device/function address.
@return Memory-mapped address.
**/
UINTN
PciExpressBaseAddress (
IN UINTN Address
)
{
if ((Address & 0xFFFFFFFFF0000000ULL) != 0) {
DEBUG ((EFI_D_ERROR, "((Address) & ~0xfffffff) == 0\n"));
ASSERT ((Address & ~0xFFFFFFF) == 0);
}
return Address + qword_2DB8;
}
//----------------------------------------------------------------------
// HOB list and TPM support HOB retrieval
//----------------------------------------------------------------------
/**
Retrieves the HOB list pointer. If not yet initialized, walks the HOB
list from the SystemTable.
@return Pointer to the HOB list, or asserts on failure.
**/
VOID *
GetHobList (
VOID
)
{
UINTN HobCount;
UINTN Index;
UINTN HobEntry;
if (qword_2DB0 == 0) {
HobCount = 0;
qword_2DB0 = 0;
if (*(UINTN *)(SystemTable + 104) != 0) {
Index = 0;
while (TRUE) {
HobEntry = *(UINTN *)(SystemTable + 112) + Index;
if (CompareGuid (
(EFI_GUID *)&qword_2D50,
(EFI_GUID *)HobEntry
))
{
qword_2DB0 = *(UINTN *)(HobEntry + 16);
break;
}
HobCount++;
Index += 24;
if (HobCount >= *(UINTN *)(SystemTable + 104)) {
DEBUG ((EFI_D_ERROR, "ASSERT_EFI_ERROR (Status = Not Found)\n"));
ASSERT (FALSE);
break;
}
}
} else {
DEBUG ((EFI_D_ERROR, "ASSERT_EFI_ERROR (Status = Not Found)\n"));
ASSERT (FALSE);
}
if (qword_2DB0 == 0) {
DEBUG ((EFI_D_ERROR, "mHobList != ((void *) 0)\n"));
ASSERT (qword_2DB0 != 0);
}
}
return (VOID *)qword_2DB0;
}
/**
Compares a HOB entry GUID against a target GUID by reading UINT64 halves.
@param[in] Guid1 Pointer to first GUID (as UINT64 pair).
@param[in] Guid2 Pointer to second GUID (as raw address).
@return TRUE if both halves match, FALSE otherwise.
**/
BOOLEAN
CompareGuid (
IN CONST UINT64 *Guid1,
IN UINTN Guid2
)
{
return (ReadUnaligned64 (Guid1) == ReadUnaligned64 ((VOID *)Guid2)) &&
(ReadUnaligned64 ((UINT8 *)Guid1 + 8) == ReadUnaligned64 ((VOID *)(Guid2 + 8)));
}
//----------------------------------------------------------------------
// TPM HOB retrieval (raw HOB walk)
//----------------------------------------------------------------------
/**
Finds a TPM device HOB entry in the HOB list by comparing GUID.
Walks the HOB list backwards (starting from the end) and checks for
a matching GUID. On match, parses the HOB data to find the TPM support
structure.
@param[in] HobStart Pointer to the start of the HOB list.
@param[in] Guid Pointer to the GUID to match.
@return Pointer to the TPM HOB data, or NULL if not found.
**/
TPM_SUPPORT_HOB *
GetTpmSupportHob (
IN VOID *HobStart,
IN EFI_GUID *Guid
)
{
UINTN Count;
UINTN HobPtr;
INT16 *Entry;
INT16 *EntryStart;
INT16 Type;
INT16 *GuidEntry;
UINTN Status;
if (HobStart == NULL) {
return NULL;
}
//
// Walk the HOB list from the end
//
Count = (UINTN)HobStart;
HobPtr = (UINTN)HobStart + 24 * Count;
while (Count > 0) {
HobPtr -= 24;
Count--;
if (InternalCompareMem ((VOID *)HobPtr, (VOID *)Guid, 16) == 0) {
//
// Found matching GUID -- walk the HOB data entries
//
Entry = *(INT16 **)(HobPtr + 16);
while (TRUE) {
if (*Entry == -1) {
break;
}
EntryStart = Entry;
do {
Type = *Entry;
if (Type == 4) {
break;
}
Entry = (INT16 *)((UINT8 *)Entry + (UINT16)Entry[1]);
Type = *Entry;
} while (*Entry != -1);
if (*Entry == -1) {
Entry = EntryStart;
}
if (*Entry == 4) {
if (InternalCompareMem ((VOID *)(Entry + 4), (VOID *)&gEfiTpmDeviceInstanceGuid, 16) == 0) {
return (TPM_SUPPORT_HOB *)(Entry + 12);
}
}
Entry = (INT16 *)((UINT8 *)Entry + (UINT16)Entry[1]);
}
}
}
return NULL;
}
//----------------------------------------------------------------------
// TPM 1.2 / 2.0 detection
//----------------------------------------------------------------------
/**
Determines if the TPM device at FED40000 is a TPM 2.0 device by
comparing vendor/device IDs against the lookup table at qword_2D50.
@return TRUE if the device at FED40000 matches an entry in the TPM 2.0
comparison table, FALSE otherwise.
**/
BOOLEAN
IsTpm20 (
VOID
)
{
UINTN Index;
Index = 0;
while (Index < 12) {
if ((*(UINT16 *)((UINT8 *)&qword_2D50 + Index) == *(UINT16 *)0xFED40F00) &&
(*(UINT16 *)((UINT8 *)&qword_2D50 + Index + 2) == *(UINT16 *)0xFED40F02))
{
return TRUE;
}
Index += 4;
}
return FALSE;
}
//----------------------------------------------------------------------
// TPM capability retrieval
//----------------------------------------------------------------------
/**
Sends a TPM2_GET_CAPABILITY command via the TCG protocol and collects
the response.
@param[in] TpmProtocol Pointer to the TCG protocol interface.
@param[in] Capability The TPM2 capability/command ordinal.
@param[out] ResponseBuffer Pointer to the response data buffer.
@return EFI_STATUS. Returns the status from the TPM submission call.
**/
EFI_STATUS
Tpm2GetCapability (
IN VOID *TpmProtocol,
IN UINT32 Capability,
OUT VOID *ResponseBuffer
)
{
UINT16 CmdBuffer[8];
UINTN ResponseSize;
EFI_STATUS Status;
//
// Build the TPM2_GET_CAPABILITY command buffer
// - tag: 0x8001 (TPM_ST_NO_SESSIONS)
// - commandSize
// - commandCode: TPM2_CC_GetCapability
//
CmdBuffer[0] = 0xC1FF; // tag (big-endian TPM_ST_NO_SESSIONS needs byte swap)
CmdBuffer[1] = 0x1600; // commandSize MSW
CmdBuffer[2] = 0x0000; // commandSize LSW
CmdBuffer[3] = Capability >> 16;
CmdBuffer[4] = Capability & 0xFFFF;
CmdBuffer[5] = 0x0100; // property count = 1
CmdBuffer[6] = 0x0000;
CmdBuffer[7] = 0x0100;
CmdBuffer[8] = 0x0000;
ResponseSize = 256;
//
// Submit the command via the TCG protocol's HashLogExtendEvent
// or similar submit-to-tpm interface
//
Status = ((EFI_TCG_PROTOCOL *)TpmProtocol)->SubmitCommand (
TpmProtocol,
22,
CmdBuffer,
ResponseSize,
ResponseBuffer
);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "(TPM Error) Status: %r; RetCode: %x.\n", Status, *(UINT32 *)ResponseBuffer));
DEBUG ((EFI_D_ERROR, "RetCode %x\n", *(UINT32 *)((UINT8 *)ResponseBuffer + 2)));
}
return Status;
}
/**
Retrieves TPM 1.2 capability information via the TCG protocol.
Builds a TPM_ORD_GetCapability command (capability = 0x40000006,
subCapIndex = 6) and submits it to the TPM. On success, byte-swaps
the version and vendor ID fields from big-endian to host order.
@param[out] TpmInfo Pointer to TPM_DEVICE_INFO structure to receive data.
@return Pointer to TpmInfo.
**/
TPM_DEVICE_INFO *
GetTpm12Capability (
OUT TPM_DEVICE_INFO *TpmInfo
)
{
UINT16 CmdBuffer[8];
UINT32 VendorId;
EFI_STATUS Status;
CmdBuffer[0] = 0xC2FF;
CmdBuffer[1] = 0x1600;
CmdBuffer[2] = 0x0600;
CmdBuffer[3] = 0x0000;
CmdBuffer[4] = 0x0400;
CmdBuffer[5] = 0x0000;
CmdBuffer[6] = 0x0000;
CmdBuffer[7] = 0x0400;
CmdBuffer[8] = 0x0000;
Status = ((EFI_TCG_PROTOCOL *)qword_2D70)->SubmitCommand (
(VOID *)qword_2D70,
22,
CmdBuffer,
256,
&unk_3000
);
if (EFI_ERROR (Status) ||
(byte_3009 | ((*(UINT32 *)&word_3006 >> 8) & 0xFF00) |
(((word_3006 & 0xFF00) | (*(UINT32 *)&word_3006 << 16)) << 8)))
{
DEBUG ((EFI_D_ERROR, "(TPM Error) Status: %r; RetCode: %x.\n",
Status,
byte_3009 |
((*(UINT32 *)&word_3006 >> 8) & 0xFF00) |
(((word_3006 & 0xFF00) | (*(UINT32 *)&word_3006 << 16)) << 8)));
DEBUG ((EFI_D_ERROR, "RetCode %x\n", *(UINT32 *)&word_3006));
} else {
//
// Byte-swap version and vendor ID from big-endian
//
qword_3010 = ((UINT32)((UINT16)__ROL2__((UINT16)(qword_3010 >> 16), 8) |
((UINT16)__ROL2__((UINT16)qword_3010, 8) << 16)) |
((UINT64)((UINT16)__ROL2__((UINT16)((UINT8 *)&qword_3010 + 7)[0], 8) |
((UINT16)__ROL2__(*(UINT16 *)((UINT8 *)&qword_3010 + 7), 8) << 16)) << 32));
DEBUG ((EFI_D_INFO, "Version %x\n", qword_3010));
VendorId = (UINT32)((UINT16)__ROL2__((UINT16)((UINT8 *)&qword_3010 + 7)[0], 8) |
((UINT16)__ROL2__(*(UINT16 *)((UINT8 *)&qword_3010 + 7), 8) << 16));
DEBUG ((EFI_D_INFO, "VendorId %x\n", VendorId));
}
//
// Copy TPM info to output structure
//
CopyMem (TpmInfo, &unk_3000, sizeof (unk_3000));
TpmInfo->VersionInfo = qword_3010;
TpmInfo->VendorId = word_3018;
TpmInfo->SpecInfo = byte_301A;
return TpmInfo;
}
/**
Retrieves TPM 2.0 capability information via the TCG protocol.
Builds a TPM2_GetCapability command and submits it. On success,
parses the response to extract capability data.
@param[out] TpmInfo Pointer to TPM_DEVICE_INFO structure to receive data.
@return Pointer to TpmInfo.
**/
TPM_DEVICE_INFO *
GetTpm20Capability (
OUT TPM_DEVICE_INFO *TpmInfo
)
{
UINT16 CmdBuffer[8];
UINT32 VendorId;
EFI_STATUS Status;
CmdBuffer[0] = 0xC1FF;
CmdBuffer[1] = 0x1600;
CmdBuffer[2] = 0x0000;
CmdBuffer[3] = 0x0000;
CmdBuffer[4] = 0x0400;
CmdBuffer[5] = 0x0000;
CmdBuffer[6] = 0x0100;
CmdBuffer[7] = 0x0000;
CmdBuffer[8] = 0x0100;
CmdBuffer[9] = 0x0000;
Status = ((EFI_TCG_PROTOCOL *)qword_2D70)->SubmitCommand (
(VOID *)qword_2D70,
22,
CmdBuffer,
256,
&qword_2DD0
);
if (EFI_ERROR (Status) ||
(byte_2DD9 | ((*(UINT32 *)&word_2DD6 >> 8) & 0xFF00) |
(((word_2DD6 & 0xFF00) | (*(UINT32 *)&word_2DD6 << 16)) << 8)))
{
DEBUG ((EFI_D_ERROR, "(TPM Error) Status: %r; RetCode: %x.\n",
Status,
byte_2DD9 |
((*(UINT32 *)&word_2DD6 >> 8) & 0xFF00) |
(((word_2DD6 & 0xFF00) | (*(UINT32 *)&word_2DD6 << 16)) << 8)));
DEBUG ((EFI_D_ERROR, "RetCode %x\n", *(UINT32 *)&word_2DD6));
} else {
//
// Byte-swap version and vendor ID from big-endian
//
qword_2DE0 = ((UINT32)((UINT16)__ROL2__((UINT16)(qword_2DE0 >> 16), 8) |
((UINT16)__ROL2__((UINT16)qword_2DE0, 8) << 16)) |
((UINT64)((UINT16)__ROL2__((UINT16)((UINT8 *)&qword_2DE0 + 7)[0], 8) |
((UINT16)__ROL2__(*(UINT16 *)((UINT8 *)&qword_2DE0 + 7), 8) << 16)) << 32));
DEBUG ((EFI_D_INFO, "Version %x\n", qword_2DE0));
VendorId = (UINT32)((UINT16)__ROL2__((UINT16)((UINT8 *)&qword_2DE0 + 7)[0], 8) |
((UINT16)__ROL2__(*(UINT16 *)((UINT8 *)&qword_2DE0 + 7), 8) << 16));
DEBUG ((EFI_D_INFO, "VendorId %x\n", VendorId));
}
//
// Copy TPM info to output structure
//
CopyMem (TpmInfo, &qword_2DD0, sizeof (unk_3000));
TpmInfo->VersionInfo = qword_2DE0;
TpmInfo->VendorId = word_2DE8;
TpmInfo->SpecInfo = byte_2DEA;
return TpmInfo;
}
//----------------------------------------------------------------------
// TCG callback processing
//----------------------------------------------------------------------
/**
TCG protocol notification callback. Called when the TCG protocol is
installed. Retrieves TPM 1.2 or 2.0 capabilities, populates global
TPM data, and installs the TCG protocol.
@param[in] Event Event whose notification function is being invoked.
@param[in] Context Pointer to the notification function's context.
@return 0 on success, returns error code on failure.
**/
CHAR8
TpmDxeTcgCallback (
IN EFI_EVENT Event,
IN VOID *Context
)
{
EFI_STATUS Status;
TPM_DEVICE_INFO TpmInfoBuf;
UINT8 Tpm20Indicator;
UINT8 ConfigVal;
UINT8 ConfigHi;
void *TcgProtocol;
UINT64 VendorId;
if (Context != NULL) {
((EFI_TCG_PROTOCOL *)(*(UINTN *)(qword_2D88 + 112)))();
}
DEBUG ((EFI_D_INFO, "TpmDxeTcgCallback\n"));
//
// Locate the TCG protocol if not already found
//
if (qword_2D70 == 0) {
Status = ((EFI_BOOT_SERVICES *)qword_2D88)->LocateProtocol (
&gEfiTcgProtocolGuid,
NULL,
&qword_2D70
);
if (EFI_ERROR (Status)) {
return (CHAR8)DebugPrint (EFI_D_ERROR,
"Error locating gEfiTcgProtocolGuid. Status = %r\n",
Status);
}
}
//
// Collect TPM capability info (route to TPM 1.2 or 2.0 path)
//
if (IsTpm20 ()) {
GetTpm20Capability (&TpmInfoBuf);
} else {
GetTpm12Capability (&TpmInfoBuf);
}
//
// Extract vendor ID and firmware version from capability response
//
VendorId = *(UINT64 *)&TpmInfoBuf;
dword_2EE2 = *(UINT32 *)((UINT8 *)&TpmInfoBuf + 22);
//
// If vendor ID is nonzero, populate TPM data
//
if (!(VendorId >> 48)) {
n25 = 25;
dword_2EE2 = *(UINT32 *)TpmInfoBuf.Tpm12Data + 22; // Override with raw
Status = Tpm2GetCapability ((VOID *)qword_2D70, 0x4000000A, &qword_2EF0);
if (Status >= 0) {
byte_2EE8 = (TpmInfoBuf.Tpm12Data[16] != 1) ? 1 : 0;
word_2ED8 = (UINT8)(IsTpm20 () ? 3 : 1);
dword_2EDA = (UINT32)TpmInfoBuf.VersionInfo;
dword_2EDE = 0;
//
// Determine configuration type based on PCD settings
//
if (IsTpm20 ()) {
ConfigVal = 1;
} else {
ConfigVal = 1;
}
//
// Check PCD for platform-specific configuration flags
//
TcgProtocol = (void *)GetPcdProtocol ();
if (((EFI_PCD_PROTOCOL *)TcgProtocol)->Get8 (213)) {
HIBYTE(word_2ED8) = 1; // ConfigFirmware
} else if (((EFI_PCD_PROTOCOL *)TcgProtocol)->Get8 (215)) {
HIBYTE(word_2ED8) = 3; // ConfigOem
} else {
ConfigHi = HIBYTE(word_2ED8);
if (((EFI_PCD_PROTOCOL *)TcgProtocol)->Get8 (214)) {
ConfigHi = 2; // ConfigSoftware
}
HIBYTE(word_2ED8) = ConfigHi;
}
//
// Install TCG protocol structure
//
n25 = 25;
((EFI_BOOT_SERVICES *)qword_2D88)->InstallMultipleProtocolInterfaces (
&qword_2FF0,
&gEfiTcgProtocolGuid,
&unk_2C40,
(EFI_GUID *)&unk_2C50,
(VOID *)(UINTN)VendorId,
(VOID *)(UINTN)(VendorId >> 32)
);
if (!IsTpm20 ()) {
dword_2C6E = 0;
n513 = 513;
dword_2C6A = (UINT32)TpmInfoBuf.VersionInfo;
dword_2C64 = *(UINT32 *)(TpmInfoBuf.Tpm12Data + 22);
(VOID)TpmSmbiosPopulate (0);
}
}
}
return (CHAR8)Status;
}
//----------------------------------------------------------------------
// TrEE callback processing
//----------------------------------------------------------------------
/**
TrEE protocol notification callback. Called when the TrEE protocol is
installed. Retrieves TPM 2.0 capability, populates the TrEE protocol
structure, and triggers SMBIOS table population.
@param[in] Event Event whose notification function is being invoked.
@param[in] Context Pointer to the notification function's context.
@return EFI_STATUS.
**/
EFI_STATUS
TpmDxeTrEECallback (
IN EFI_EVENT Event,
IN VOID *Context
)
{
EFI_STATUS Status;
EFI_STATUS HobStatus;
EFI_TCG_PROTOCOL *TreeProtocol;
VOID *PcdProtocol;
TPM_DEVICE_INFO TpmInfoBuf;
UINT8 ConfigHi;
UINT8 ConfigVal;
UINT64 VendorId;
if (Context != NULL) {
((EFI_TCG_PROTOCOL *)(*(UINTN *)(qword_2D88 + 112)))();
}
DEBUG ((EFI_D_INFO, "TpmDxeTrEECallback\n"));
//
// Locate TrEE protocol
//
if (qword_2D68 == 0) {
Status = ((EFI_BOOT_SERVICES *)qword_2D88)->LocateProtocol (
&gEfiTrEEProtocolGuid,
NULL,
&qword_2D68
);
if (EFI_ERROR (Status)) {
return DebugPrint (EFI_D_ERROR,
"Error locating gEfiTrEEProtocolGuid. Status = %r\n",
Status);
}
}
//
// Locate another protocol (SMBIOS?)
//
Status = ((EFI_BOOT_SERVICES *)qword_2D88)->LocateProtocol (
&gEfiSmbiosProtocolGuid,
NULL,
&TpmInfoBuf
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Get TPM support HOB data
//
HobStatus = GetTpmSupportHobData ();
if (EFI_ERROR (HobStatus)) {
return DebugPrint (EFI_D_ERROR, "Error GetTpm20Hob. Status = %r\n", Status);
}
//
// Query TPM capability (capability size = 28 bytes at offset 0)
//
TpmInfoBuf.Tpm12Data[0] = 28;
Status = ((EFI_TCG_PROTOCOL *)qword_2D68)->GetCapability (
qword_2D68,
TpmInfoBuf.Tpm12Data
);
if (EFI_ERROR (Status)) {
return DebugPrint (EFI_D_ERROR, "Error GetCapability. Status = %r\n", Status);
}
DEBUG ((EFI_D_INFO, "Size = %x\n", TpmInfoBuf.Tpm12Data[0]));
DEBUG ((EFI_D_INFO, "StructureVersion.Major = %x\n", TpmInfoBuf.Tpm12Data[1]));
DEBUG ((EFI_D_INFO, "StructureVersion.Minor = %x\n", TpmInfoBuf.Tpm12Data[2]));
DEBUG ((EFI_D_INFO, "ProtocolVersion.Major = %x\n", TpmInfoBuf.Tpm12Data[3]));
DEBUG ((EFI_D_INFO, "ProtocolVersion.Minor = %x\n", TpmInfoBuf.Tpm12Data[4]));
DEBUG ((EFI_D_INFO, "ProtocolCapability.ManufacturerID = %x\n",
*(UINT32 *)(TpmInfoBuf.Tpm12Data + 22)));
//
// Populate global TPM variables
//
dword_2EE2 = *(UINT32 *)(TpmInfoBuf.Tpm12Data + 22);
ConfigVal = 2;
dword_2EDA = *(UINT32 *)(qword_2D78 + 3);
dword_2EDE = *(UINT32 *)(qword_2D78 + 11);
//
// Determine configuration type from PCD
//
PcdProtocol = (VOID *)GetPcdProtocol ();
if (((EFI_PCD_PROTOCOL *)PcdProtocol)->Get8 (213)) {
HIBYTE(ConfigVal) = 1; // ConfigFirmware
} else if (((EFI_PCD_PROTOCOL *)PcdProtocol)->Get8 (215)) {
HIBYTE(ConfigVal) = 3; // ConfigOem
} else {
ConfigHi = HIBYTE(ConfigVal);
if (((EFI_PCD_PROTOCOL *)PcdProtocol)->Get8 (214)) {
ConfigHi = 2; // ConfigSoftware
}
HIBYTE(ConfigVal) = ConfigHi;
}
//
// Set TPM 1.2/2.0 flag
//
n25 = 25;
byte_2EE8 = (TpmInfoBuf.Tpm12Data[21]) ? 0 : 1;
//
// Install TrEE protocol structure
//
((EFI_BOOT_SERVICES *)qword_2D88)->InstallMultipleProtocolInterfaces (
&qword_2FF0,
&gEfiTrEEProtocolGuid,
&unk_2C40,
(EFI_GUID *)&unk_2C50
);
if (!IsTpm20 ()) {
n513 = 2;
dword_2C6A = *(UINT32 *)(qword_2D78 + 3);
dword_2C6E = *(UINT32 *)(qword_2D78 + 11);
dword_2C64 = *(UINT32 *)(TpmInfoBuf.Tpm12Data + 22);
(VOID)TpmSmbiosPopulate (0);
}
return EFI_SUCCESS;
}
//----------------------------------------------------------------------
// TPM SMBIOS table population
//----------------------------------------------------------------------
/**
Populates the SMBIOS table with TPM device information.
This is the core SMBIOS data population routine. It:
1. Locates the SMBIOS protocol.
2. Enumerates SMBIOS records looking for an existing TPM type 43 entry.
3. Reads PCD settings for TPM characteristics flags.
4. Collects TPM vendor and firmware version data.
5. Builds and adds the SMBIOS Type 43 record.
@param[in] SmbiosHandle Unused. Pass 0.
@retval EFI_SUCCESS SMBIOS record added or updated.
**/
EFI_STATUS
TpmSmbiosPopulate (
IN UINTN SmbiosHandle
)
{
EFI_STATUS Status;
EFI_SMBIOS_PROTOCOL *SmbiosProtocol;
EFI_SMBIOS_HANDLE SmbiosHandle2;
UINTN TableSize;
UINT8 *TableBuffer;
UINT8 *TablePtr;
UINTN VendorStringLen;
UINTN VendorIdStrLen;
CONST CHAR8 *TpmVersionStr;
CONST CHAR8 *VendorIdStr;
UINTN FinalSize;
UINT8 *FinalTable;
UINTN Index;
VOID *PcdProtocol;
BOOLEAN TpmIs20;
UINT8 SmbiosHandleIdx;
//
// Notify caller of progress
//
if (SmbiosHandle != 0) {
((EFI_BOOT_SERVICES *)qword_2D88)->RestoreTpl (SmbiosHandle);
}
//
// Locate SMBIOS protocol
//
SmbiosProtocol = (EFI_SMBIOS_PROTOCOL *)qword_2D60;
if (qword_2D60 == 0) {
Status = ((EFI_BOOT_SERVICES *)qword_2D88)->LocateProtocol (
&gEfiSmbiosProtocolGuid,
NULL,
&qword_2D60
);
if (EFI_ERROR (Status)) {
return DebugPrint (EFI_D_ERROR,
"Error locating gEfiSmbiosProtocolGuid. Status = %r\n",
Status);
}
SmbiosProtocol = (EFI_SMBIOS_PROTOCOL *)qword_2D60;
}
DEBUG ((EFI_D_INFO, "Smbios MajorVersion = %x\n",
((EFI_SMBIOS_PROTOCOL *)SmbiosProtocol)->MajorVersion));
DEBUG ((EFI_D_INFO, "Smbios MinorVersion = %x\n",
((EFI_SMBIOS_PROTOCOL *)SmbiosProtocol)->MinorVersion));
//
// Only proceed for SMBIOS 3.x and later
//
if (((EFI_SMBIOS_PROTOCOL *)SmbiosProtocol)->MajorVersion <= 3 &&
((EFI_SMBIOS_PROTOCOL *)SmbiosProtocol)->MinorVersion == 0)
{
return EFI_SUCCESS;
}
//
// Scan existing SMBIOS records for an existing TPM record (type 43)
//
SmbiosHandle2 = (EFI_SMBIOS_HANDLE)(-2);
while (SmbiosProtocol->GetNext (SmbiosProtocol, &SmbiosHandle2, NULL, &TableBuffer, NULL) >= 0) {
if (*TableBuffer == 43) {
//
// Remove existing TPM record
//
Status = SmbiosProtocol->Remove (SmbiosProtocol, SmbiosHandle2);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", Status));
ASSERT_EFI_ERROR (Status);
}
break;
}
}
//
// Read PCD settings for TPM characteristics
//
PcdProtocol = (VOID *)GetPcdProtocol ();
if (((EFI_PCD_PROTOCOL *)PcdProtocol)->Get8 (212)) {
qword_2C73 &= ~(UINT64)4;
}
PcdProtocol = (VOID *)GetPcdProtocol ();
if (((EFI_PCD_PROTOCOL *)PcdProtocol)->Get8 (213)) {
qword_2C73 |= 8;
}
PcdProtocol = (VOID *)GetPcdProtocol ();
if (((EFI_PCD_PROTOCOL *)PcdProtocol)->Get8 (214)) {
qword_2C73 |= 0x10;
}
PcdProtocol = (VOID *)GetPcdProtocol ();
if (((EFI_PCD_PROTOCOL *)PcdProtocol)->Get8 (215)) {
qword_2C73 |= 0x20;
}
dword_2C7B = (UINT32)((EFI_PCD_PROTOCOL *)GetPcdProtocol ())->Get32 (216);
DEBUG ((EFI_D_INFO, "VendorId %x\n", dword_2C64));
DEBUG ((EFI_D_INFO, "MajorSpecVer %x\n", (UINT8)word_2C68));
DEBUG ((EFI_D_INFO, "MinorSpecVer %x\n", HIBYTE(word_2C68)));
DEBUG ((EFI_D_INFO, "FirmwareVer1 %x\n", dword_2C6A));
DEBUG ((EFI_D_INFO, "FirmwareVer2 %x\n", dword_2C6E));
DEBUG ((EFI_D_INFO, "Characteristics.Unsupport %x\n", (UINT32)((qword_2C73 >> 2) & 1)));
DEBUG ((EFI_D_INFO, "Characteristics.ConfigFirmware %x\n", (UINT32)((qword_2C73 >> 3) & 1)));
DEBUG ((EFI_D_INFO, "Characteristics.ConfigSoftware %x\n", (UINT32)((qword_2C73 >> 4) & 1)));
DEBUG ((EFI_D_INFO, "Characteristics.ConfigOem %x\n", (UINT32)((qword_2C73 >> 5) & 1)));
DEBUG ((EFI_D_INFO, "OemDefined %x\n", dword_2C7B));
DEBUG ((EFI_D_INFO, "Description %x\n", (UINT8)byte_2C72));
//
// Determine TPM version string
//
VendorIdStr = "HON HAI";
byte_2C61 = (UINT8)byte_2C61; // vendor string length from capability
if (*(UINT8 *)qword_2D78 != 0) {
TpmVersionStr = "TPM 2.0";
if (*(UINT8 *)qword_2D78 != 1) {
TpmVersionStr = NULL;
}
} else {
TpmVersionStr = "TPM 1.2";
}
//
// Calculate string lengths
//
VendorStringLen = AsciiStrLen (TpmVersionStr);
TableSize = VendorStringLen + byte_2C61 + 1;
//
// Look up vendor name from vendor ID
//
VendorIdStr = VendorIdStr;
for (Index = 0; Index < 17; Index++) {
if (VendorIdMap[Index].VendorId == dword_2C64) {
VendorIdStr = (CONST CHAR8 *)VendorIdMap[Index].VendorName;
}
}
VendorIdStrLen = AsciiStrLen (VendorIdStr);
FinalSize = VendorIdStrLen + TableSize;
DEBUG ((EFI_D_INFO, "Final table Size %x\n", FinalSize));
//
// Allocate and zero the table buffer
//
FinalTable = InternalAllocatePool (EfiBootServicesData, FinalSize + 2);
if (FinalTable != NULL) {
InternalZeroMem (FinalTable, FinalSize + 2);
}
TablePtr = FinalTable;
if (FinalTable != NULL) {
//
// Copy TPM device info into the buffer
//
InternalCopyMem (FinalTable, "TPM 2.0", byte_2C61);
TablePtr = &FinalTable[byte_2C61];
if (VendorStringLen > 0) {
InternalCopyMem (TablePtr, TpmVersionStr, VendorStringLen);
TablePtr += (VendorStringLen + 1);
}
if (VendorIdStrLen > 0) {
InternalCopyMem (TablePtr, VendorIdStr, VendorIdStrLen);
}
//
// Add the SMBIOS record
//
SmbiosHandle2 = (EFI_SMBIOS_HANDLE)(-2);
Status = SmbiosProtocol->Add (
SmbiosProtocol,
(EFI_SMBIOS_HANDLE)0,
&SmbiosHandle2,
FinalTable
);
DEBUG ((EFI_D_INFO, "SmbiosProtocol->Add Status %r\n", Status));
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", Status));
ASSERT_EFI_ERROR (Status);
}
//
// Free the allocated buffer
//
InternalFreePool (FinalTable);
}
return EFI_SUCCESS;
}
//----------------------------------------------------------------------
// TPM support HOB data retrieval
//----------------------------------------------------------------------
/**
Retrieves TPM support HOB data from the HOB list.
Reads the HOB list from the SystemTable and parses it to find TPM
device support information.
@return EFI_SUCCESS if TPM HOB data was found, EFI_NOT_FOUND otherwise.
**/
EFI_STATUS
GetTpmSupportHobData (
VOID
)
{
UINT8 *HobData;
UINTN HobCount;
UINTN HobEntriesEnd;
UINTN HobEntry;
HobData = (UINT8 *)qword_2D78;
if (qword_2D78 == 0) {
//
// Walk GUID HOB entries from SystemTable
//
HobData = (UINT8 *)GetTpmSupportHob (
(VOID *)*(UINTN *)(SystemTable + 104),
&gEfiTpmDeviceInstanceGuid
);
qword_2D78 = (UINTN)HobData;
if (HobData == NULL) {
return EFI_NOT_FOUND;
}
}
DEBUG ((EFI_D_INFO, "TpmSupport->Tpm20DeviceState %X\n", HobData[0]));
DEBUG ((EFI_D_INFO, "TpmSupport->InterfaceType %X\n", HobData[1]));
DEBUG ((EFI_D_INFO, "TpmSupport->Tpm2FWersion1 %X\n", *(UINT32 *)(HobData + 3)));
DEBUG ((EFI_D_INFO, "TpmSupport->Tpm2FWersion2 %X\n", *(UINT32 *)(HobData + 11)));
DEBUG ((EFI_D_INFO, "TpmSupport->Tpm2manufacturer %X\n", *(UINT32 *)(HobData + 7)));
return EFI_SUCCESS;
}
//----------------------------------------------------------------------
// PCD protocol access
//----------------------------------------------------------------------
/**
Retrieves the PCD protocol pointer. Caches the result on first access.
@return Pointer to the EFI_PCD_PROTOCOL interface.
**/
VOID *
GetPcdProtocol (
VOID
)
{
EFI_STATUS Status;
if (qword_2DA8 == 0) {
Status = ((EFI_BOOT_SERVICES *)BootServices)->LocateProtocol (
&gEfiPcdProtocolGuid,
NULL,
&qword_2DA8
);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", Status));
ASSERT_EFI_ERROR (Status);
}
if (qword_2DA8 == 0) {
DEBUG ((EFI_D_ERROR, "mPcd != ((void *) 0)\n"));
ASSERT (qword_2DA8 != 0);
}
}
return (VOID *)qword_2DA8;
}
//----------------------------------------------------------------------
// Memory allocation helpers
//----------------------------------------------------------------------
/**
Allocates a buffer of specified size from the boot services data pool.
@param[in] PoolType Type of pool to allocate from.
@param[in] Size Number of bytes to allocate.
@return Pointer to the allocated buffer, or NULL on failure.
**/
VOID *
InternalAllocatePool (
IN EFI_MEMORY_TYPE PoolType,
IN UINTN Size
)
{
EFI_STATUS Status;
VOID *Buffer;
Status = ((EFI_BOOT_SERVICES *)BootServices)->AllocatePool (
PoolType,
Size,
&Buffer
);
if (EFI_ERROR (Status)) {
return NULL;
}
return Buffer;
}
/**
Frees a buffer previously allocated via InternalAllocatePool.
@param[in] Buffer Pointer to the buffer to free.
@return EFI_STATUS from the FreePool call.
**/
EFI_STATUS
InternalFreePool (
IN VOID *Buffer
)
{
EFI_STATUS Status;
Status = ((EFI_BOOT_SERVICES *)BootServices)->FreePool (Buffer);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", Status));
ASSERT_EFI_ERROR (Status);
}
return Status;
}
//----------------------------------------------------------------------
// Debug output helpers
//----------------------------------------------------------------------
/**
Debug library's output routine. Acquires the debug protocol and uses
it to print formatted messages at the specified error level.
Uses CMOS/RTC access to determine debug level configuration:
- CMOS 0x4B returns the current debug level.
- Level 0-3 are mapped to DP_LOAD (0x80000004), DP_ERROR (0x80000002),
DP_WARN (0x80000006), DP_INFO (0x80000008) respectively.
@param[in] ErrorLevel Debug error level mask.
@param[in] Format Format string.
@param[in] ... Variable arguments.
@return 0 if not printed, otherwise the return value from the
debug protocol's output function.
**/
UINT8
DebugPrint (
IN UINTN ErrorLevel,
IN CONST CHAR8 *Format,
...
)
{
VA_LIST Args;
EFI_DEBUG_PROTOCOL *DebugProtocol;
UINT8 DebugLevel;
UINT8 CmosVal;
UINTN MappedErrorLevel;
UINT8 Result;
VA_START (Args, Format);
DebugProtocol = (EFI_DEBUG_PROTOCOL *)GetDebugProtocol ();
MappedErrorLevel = 0;
Result = 0;
if (DebugProtocol != NULL) {
//
// Read debug level from CMOS
//
__outbyte (0x70, (__inbyte (0x70) & 0x80) | 0x4B);
DebugLevel = __inbyte (0x71);
if (DebugLevel > 3) {
if (DebugLevel == 0) {
DebugLevel = (MEMORY[0xFDAF0490] & 2) | 1;
}
}
Result = DebugLevel - 1;
if (DebugLevel - 1 <= 0xFD) {
//
// Map error level
//
if (DebugLevel == 1) {
MappedErrorLevel = EFI_D_LOAD;
} else {
MappedErrorLevel = EFI_D_ERROR;
}
}
if ((MappedErrorLevel & ErrorLevel) != 0) {
Result = (UINT8)DebugProtocol->Print (ErrorLevel, Format, Args);
}
}
VA_END (Args);
return Result;
}
/**
Debug assertion handler. Prints assertion information through the
debug protocol output interface.
@param[in] FileName Name of the source file.
@param[in] LineNumber Line number of the assertion.
@param[in] Description Description string for the assertion.
**/
VOID
DebugAssert (
IN CONST CHAR8 *FileName,
IN UINTN LineNumber,
IN CONST CHAR8 *Description
)
{
EFI_DEBUG_PROTOCOL *DebugProtocol;
DebugProtocol = (EFI_DEBUG_PROTOCOL *)GetDebugProtocol ();
if (DebugProtocol != NULL) {
DebugProtocol->Assert (FileName, LineNumber, Description);
}
}
/**
Retrieves the debug protocol interface. Caches the result.
@return Pointer to the EFI_DEBUG_PROTOCOL, or NULL if not available.
**/
VOID *
GetDebugProtocol (
VOID
)
{
EFI_STATUS Status;
UINTN Tpl;
if (qword_2DA0 == 0) {
Tpl = ((EFI_BOOT_SERVICES *)BootServices)->RaiseTPL (31);
((EFI_BOOT_SERVICES *)BootServices)->RestoreTPL (Tpl);
if (Tpl <= 16) {
Status = ((EFI_BOOT_SERVICES *)BootServices)->LocateProtocol (
&gEfiDebugProtocolGuid,
NULL,
&qword_2DA0
);
if (EFI_ERROR (Status)) {
qword_2DA0 = 0;
}
}
}
return (VOID *)qword_2DA0;
}
//----------------------------------------------------------------------
// UEFI boot/runtime services initialization
//----------------------------------------------------------------------
/**
Initializes UEFI boot and runtime services tables and checks TPM
hardware state.
Saves ImageHandle, SystemTable, gBS, gRT. Initializes the HOB list.
Reads PCD to get PCI Express base address. Checks CPU EFLAGS for
interrupt state and performs a timed wait using the TSC.
@param[in] ImageHandle The firmware allocated handle for the UEFI image.
@param[in] SystemTable A pointer to the EFI System Table.
**/
VOID
InitializeTpmSmbios (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
UINT32 PciExpressBase;
BOOLEAN InterruptsWereEnabled;
UINT64 StartTsc;
UINT64 CurrentTsc;
UINT64 TimeoutTsc;
//
// Save globals
//
gImageHandle = ImageHandle;
if (gImageHandle == NULL) {
DEBUG ((EFI_D_ERROR, "gImageHandle != ((void *) 0)\n"));
ASSERT (gImageHandle != NULL);
}
gST = SystemTable;
if (gST == NULL) {
DEBUG ((EFI_D_ERROR, "gST != ((void *) 0)\n"));
ASSERT (gST != NULL);
}
gBS = SystemTable->BootServices;
if (gBS == NULL) {
DEBUG ((EFI_D_ERROR, "gBS != ((void *) 0)\n"));
ASSERT (gBS != NULL);
}
gRT = SystemTable->RuntimeServices;
if (gRT == NULL) {
DEBUG ((EFI_D_ERROR, "gRT != ((void *) 0)\n"));
ASSERT (gRT != NULL);
}
//
// Initialize HOB list
//
GetHobList ();
//
// Read PCI Express base address from PCD
//
qword_2DB8 = (UINTN)((EFI_PCD_PROTOCOL *)GetPcdProtocol ())->Get32 (5);
//
// If PCI express is enabled, enable memory-mapped I/O
//
if ((INT8)PciExpressBaseAddress (1024068) >= 0) {
IoWrite16 ((UINTN)PciExpressBaseAddress (1024064), 0x500);
*(UINT8 *)PciExpressBaseAddress (1024068) |= 0x80;
}
//
// Save interrupt state, disable interrupts, and perform TSC delay
//
InterruptsWereEnabled = (ReadEflags () & 0x200) != 0;
DisableInterrupts ();
StartTsc = ReadTsc () & 0xFFFFFF;
EnableInterrupts ();
//
// Wait for approximately 357 TSC ticks (short delay loop)
//
TimeoutTsc = (StartTsc + 357) & 0x800000;
CurrentTsc = (ReadTsc () & 0xFFFFFF);
while ((UINTN)(CurrentTsc + 357 - TimeoutTsc) & 0x800000) {
CpuPause ();
CurrentTsc = (ReadTsc () & 0xFFFFFF);
}
DisableInterrupts ();
//
// Restore interrupt state
//
if (InterruptsWereEnabled) {
EnableInterrupts ();
} else {
DisableInterrupts ();
}
}
//----------------------------------------------------------------------
// Module entry point
//----------------------------------------------------------------------
/**
Module entry point.
Delegates to InitializeTpmSmbios() for boot services setup and then
to TpmSmbiosDxeEntry() for TCG/TrEE callback registration.
@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 function completed successfully.
**/
EFI_STATUS
EFIAPI
ModuleEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
InitializeTpmSmbios (ImageHandle, SystemTable);
return TpmSmbiosDxeEntry (ImageHandle);
}
/**
DXE Driver entry point. Registers TCG and TrEE protocol notification
callbacks, and installs SMBIOS protocol if needed.
This function:
1. Attempts to locate gEfiTrEEProtocolGuid.
- If not found, registers a protocol notification callback
(TpmDxeTrEECallback) and installs the TrEE protocol.
- If found, calls TpmDxeTrEECallback directly.
2. Attempts to locate gEfiTcgProtocolGuid.
- If not found, registers a protocol notification callback
(TpmDxeTcgCallback) and installs the TCG protocol.
- If found, calls TpmDxeTcgCallback directly.
3. Returns the status of the TCG protocol operation.
@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 entry point executed successfully.
**/
EFI_STATUS
EFIAPI
TpmSmbiosDxeEntry (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
EFI_STATUS TcgStatus;
DEBUG ((EFI_D_INFO, "TpmSmbiosDxeEntry\n"));
//
// Save ImageHandle for callback use
//
ImageHandle = (UINTN)ImageHandle;
//
// --- TrEE Protocol ---
//
if (gBS->LocateProtocol (&gEfiTrEEProtocolGuid, NULL, &qword_2D68) != EFI_SUCCESS) {
Status = gBS->RegisterProtocolNotify (
&gEfiTrEEProtocolGuid,
(EFI_NOTIFICATION_FN)TpmDxeTrEECallback,
&ImageHandle_0
);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", Status));
ASSERT_EFI_ERROR (Status);
}
Status = gBS->InstallProtocolInterface (
&gEfiTrEEProtocolGuid,
EFI_NATIVE_INTERFACE,
SystemTable,
&unk_3100
);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", Status));
ASSERT_EFI_ERROR (Status);
}
} else {
TpmDxeTrEECallback (NULL, 0);
}
//
// --- TCG Protocol ---
//
if (gBS->LocateProtocol (&gEfiTcgProtocolGuid, NULL, &qword_2D70) != EFI_SUCCESS) {
Status = gBS->RegisterProtocolNotify (
&gEfiTcgProtocolGuid,
(EFI_NOTIFICATION_FN)TpmDxeTcgCallback,
&ImageHandle_0
);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", Status));
ASSERT_EFI_ERROR (Status);
}
Status = gBS->InstallProtocolInterface (
&gEfiTcgProtocolGuid,
EFI_NATIVE_INTERFACE,
SystemTable,
&unk_3110
);
TcgStatus = Status;
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", Status));
ASSERT_EFI_ERROR (Status);
}
} else {
TpmDxeTcgCallback (NULL, 0);
}
return TcgStatus;
}