Newer
Older
AMI-Aptio-BIOS-Reversed / TpmSmbiosDxe / TpmSmbiosDxe.c
@Ajax Dong Ajax Dong 2 days ago 51 KB Init
/** @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;
}