/** @file
AmiTcgPlatformDxe - AMI TCG Platform DXE Driver
This is the AMI TCG (Trusted Computing Group) Platform DXE driver for the
HR650X BIOS. It provides TPM/TCG platform initialization during the DXE
phase, including:
- TPM 1.2 and TPM 2.0 protocol detection and dispatch
- Physical Presence Interface (PPI) request processing
- TPM PER BIOS flag management
- Measurement of boot variables (SecureBoot, PK, KEK, db, dbx)
- Option ROM measurement
- Ready-to-Boot notification callback
- TPM state synchronization with UEFI setup variables
Build source path: e:\hs\AmiModulePkg\TCG2\Common\AmiTcgPlatformDxe\
Source file: AmiTcgPlatformDxe.c
Copyright (C) 2025 American Megatrends Inc. (AMI)
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <Uefi.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Library/UefiHiiServicesLib.h>
#include <Library/DxeHobLib.h>
#include <Library/HiiLib.h>
#include <Library/PrintLib.h>
#include <Library/DebugLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Protocol/TcgService.h>
#include <Protocol/Tcg2Protocol.h>
#include <Protocol/TrEEProtocol.h>
#include <Protocol/HiiFont.h>
#include <Protocol/HiiDatabase.h>
#include <Protocol/HiiConfigRouting.h>
#include <Protocol/HiiConfigAccess.h>
#include <Protocol/HiiPackageList.h>
#include <Guid/EventGroup.h>
#include "AmiTcgPlatformDxe.h"
// ===========================================================================
// Global Variable Definitions
// ===========================================================================
//
// Standard UEFI global variables from library constructors
//
EFI_HANDLE ImageHandle = NULL;
EFI_SYSTEM_TABLE *SystemTable = NULL;
EFI_BOOT_SERVICES *BootServices = NULL;
EFI_RUNTIME_SERVICES *RuntimeServices = NULL;
//
// Module-specific globals
//
UINT8 byte_8D18; // SecureBoot status shadow
UINT8 byte_8D19; // TPM platform type shadow
UINT64 qword_8D08; // Saved protocol handle
UINT64 qword_8D10; // Ready-to-boot invocation counter
UINT64 qword_8D60; // Cached HOB list pointer
UINT64 qword_8D68; // Image handle cache
UINT64 qword_8D70; // HII Database Protocol
UINT64 qword_8D78; // Protocol instance slots
UINT64 qword_8D80;
UINT64 qword_8D88;
UINT64 qword_8D90;
UINT64 qword_9420; // HII Handle
UINT64 qword_9428; // Registered ready-to-boot event
UINT32 dword_8DDC; // Reset type parameter
UINT8 byte_8DA8; // TPM presence flag (non-zero = 2.0)
// ===========================================================================
// GUID Definitions
// ===========================================================================
EFI_GUID unk_8A20;
EFI_GUID unk_8A30;
EFI_GUID unk_8A50;
EFI_GUID unk_8A80;
EFI_GUID unk_8AB0;
EFI_GUID unk_8AD0;
EFI_GUID unk_8AE0;
EFI_GUID unk_8B00;
EFI_GUID unk_8B20;
EFI_GUID unk_8B30;
EFI_GUID unk_8B40;
EFI_GUID unk_8B50;
EFI_GUID unk_8B60;
EFI_GUID unk_8B80;
EFI_GUID unk_8B90;
EFI_GUID unk_8BC0;
EFI_GUID unk_8BD0;
EFI_GUID unk_8BE0;
EFI_GUID unk_8C10;
EFI_GUID unk_8C40;
EFI_GUID unk_8C50;
EFI_GUID unk_8C60;
EFI_GUID unk_8C70;
//
// Protocol notify registrations
//
VOID *off_8CB0;
VOID *unk_8DC0;
VOID *unk_8DE0;
VOID *unk_8DE8;
UINT8 unk_8DF0[512];
UINT8 unk_8DFE;
//
// GUID constants for known algorithm identifiers
//
CONST UINT64 xmmword_6B40[2] = { 0, 0 }; // SHA-1 algorithm GUID
CONST UINT64 xmmword_8A50[2] = { 0, 0 }; // Default algorithm GUID
// ===========================================================================
// Local Helper Functions
// ===========================================================================
/**
Debug print wrapper. Formats and prints a debug message at the given
error level.
@param[in] ErrorLevel Debug error severity level.
@param[in] Format Format string.
@param[in] ... Variable arguments.
**/
VOID
DebugPrint (
IN UINTN ErrorLevel,
IN CHAR8 *Format,
...
)
{
VA_LIST Marker;
VA_START (Marker, Format);
DEBUG ((ErrorLevel, Format, Marker));
VA_END (Marker);
}
/**
Assertion failure handler. Called when an ASSERT condition evaluates
to FALSE.
@param[in] FileName Source file name.
@param[in] LineNumber Line number.
@param[in] Description Assertion text.
**/
VOID
AssertFailure (
IN CHAR8 *FileName,
IN UINTN LineNumber,
IN CHAR8 *Description
)
{
DEBUG ((EFI_D_ERROR, "ASSERT [%a](%lu): %a\n", FileName, LineNumber, Description));
CpuDeadLoop ();
}
/**
Returns the length of a UCS-2 string (number of characters).
@param[in] String Null-terminated UCS-2 string.
@return Number of characters excluding the null terminator.
**/
UINTN
StrLen (
IN UINT16 *String
)
{
UINTN Length;
ASSERT (String != NULL);
ASSERT (((UINTN)String & 1) == 0);
for (Length = 0; String[Length] != 0; Length++) {
;
}
return Length;
}
/**
Returns the byte-size of a UCS-2 string including the null terminator.
@param[in] String Null-terminated UCS-2 string.
@return Size in bytes, or 0 if String is NULL or empty.
**/
UINTN
StrSize (
IN UINT16 *String
)
{
return (StrLen (String) + 1) * sizeof (UINT16);
}
/**
Copies a UCS-2 string with overlap-safe handling. Equivalent to
StrCpyS with overlap checking.
@param[out] Destination Destination buffer.
@param[in] Source Source string.
@return Destination.
**/
UINT16 *
StrCatOverlap (
OUT UINT16 *Destination,
IN UINT16 *Source
)
{
UINT16 *Ptr;
INTN Offset;
UINT16 Char;
Ptr = Destination + StrLen (Destination);
ASSERT (Ptr != NULL);
ASSERT (((UINTN)Ptr & 1) == 0);
ASSERT ((Ptr - Source) >> 1 <= StrLen (Source));
ASSERT ((Source - Ptr) >> 1 <= StrLen (Source));
Char = *Source;
if (Char != 0) {
Offset = Source - Ptr;
do {
*Ptr = Char;
Ptr++;
Char = *(UINT16 *)((UINT8 *)Ptr + Offset);
} while (Char != 0);
}
*Ptr = 0;
ASSERT (StrSize (Destination) != 0);
return Destination;
}
// ===========================================================================
// EFI Module Entry Point
// ===========================================================================
/**
The UEFI module entry point.
Initializes the driver by saving UEFI table pointers, locating HII
services, installing the TCG platform protocol, measuring secure boot
variables, and registering the ready-to-boot notification.
@param[in] ImageHandle The firmware allocated handle for the EFI image.
@param[in] SystemTable A pointer to the EFI System Table.
@retval EFI_SUCCESS The entry point executed successfully.
@retval EFI_INVALID_PARAMETER ImageHandle or SystemTable is NULL.
@retval EFI_UNSUPPORTED A required protocol could not be located.
**/
EFI_STATUS
EFIAPI
ModuleEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
//
// Save UEFI table pointers and locate HII protocols.
//
DriverInit (ImageHandle, SystemTable);
//
// Register HII package list, measure secure variables, and register
// the reset notification callback.
//
return RegisterAndMeasure (ImageHandle);
}
// ===========================================================================
// Driver Initialization
// ===========================================================================
/**
Save UEFI boot/runtime service table pointers and locate HII protocols.
Initializes the module's global table pointers (BootServices,
RuntimeServices), then locates the HII Font, Database, ConfigRouting,
and ConfigAccess protocols.
@param[in] ImageHandle The module's image handle.
@param[in] SystemTable The UEFI system table.
**/
EFI_STATUS
DriverInit (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
//
// Save the image handle and system table.
//
::ImageHandle = ImageHandle;
ASSERT (::ImageHandle != NULL);
::SystemTable = SystemTable;
ASSERT (::SystemTable != NULL);
//
// Save the boot services and runtime services pointers.
//
BootServices = SystemTable->BootServices;
ASSERT (BootServices != NULL);
RuntimeServices = SystemTable->RuntimeServices;
ASSERT (RuntimeServices != NULL);
//
// Initialize the HOB list pointer.
//
InternalGetHobList ();
//
// Save the image handle for protocol lookups.
//
qword_8D68 = sub_4BC4 ();
//
// Detect TPM type (enable TPM 2.0 path if applicable).
//
if (*(CHAR8 *)sub_6000 (1024068) >= 0) {
sub_6740 (sub_6000 (1024064));
*(UINT8 *)sub_6000 (1024068) |= 0x80;
}
//
// Wait for TPM interface to become ready.
//
{
UINT16 TpmStatus;
UINT64 Ticks;
BOOLEAN TpmPresent;
TpmStatus = sub_410 ();
sub_400 ();
TpmPresent = (TpmStatus & 0x200) != 0;
Ticks = sub_6774 (1288) & 0xFFFFFF;
sub_3E0 ();
while (((Ticks + 357 - (UINT32)sub_6774 (1288)) & 0x800000) == 0) {
sub_3D0 ();
}
sub_3E0 ();
if (TpmPresent) {
sub_3F0 ();
} else {
sub_400 ();
}
}
//
// Locate HII protocols.
//
Status = BootServices->LocateProtocol (&unk_8BE0, NULL, &qword_8D70);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "ASSERT_EFI_ERROR (Status = %r)\n", Status));
ASSERT_EFI_ERROR (Status);
}
Status = BootServices->LocateProtocol (&unk_8BD0, NULL, &unk_8D90);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "ASSERT_EFI_ERROR (Status = %r)\n", Status));
ASSERT_EFI_ERROR (Status);
}
Status = BootServices->LocateProtocol (&unk_8B80, NULL, &unk_8D80);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "ASSERT_EFI_ERROR (Status = %r)\n", Status));
ASSERT_EFI_ERROR (Status);
}
BootServices->LocateProtocol (&unk_8CA0, NULL, &unk_8D78);
BootServices->LocateProtocol (&unk_8BC0, NULL, &unk_8D88);
return EFI_SUCCESS;
}
// ===========================================================================
// HII Package List and Measurement Registration
// ===========================================================================
/**
Opens the HII Package List protocol, registers the HII package list,
measures secure boot variables, and registers the DoResetNow callback.
@param[in] ImageHandle The module's image handle.
@retval EFI_SUCCESS All operations succeeded.
@retval EFI_OUT_OF_RESOURCES Memory allocation failed.
**/
EFI_STATUS
RegisterAndMeasure (
IN EFI_HANDLE ImageHandle
)
{
EFI_STATUS Status;
EFI_HANDLE Handle;
EFI_HII_DATABASE_PROTOCOL *HiiDatabase;
EFI_HII_HANDLE HiiHandle;
Handle = ImageHandle;
//
// Install the HII Package List protocol on our image handle.
//
BootServices->InstallMultipleProtocolInterfaces (
&Handle,
&unk_8A20,
off_8CB0,
NULL
);
//
// Locate the HII Database protocol and register the package list.
//
Status = sub_5E18 ();
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "ASSERT_EFI_ERROR (Status = %r)\n", Status));
ASSERT_EFI_ERROR (Status);
}
Status = BootServices->OpenProtocol (
Handle,
&unk_8AE0,
&HiiHandle,
Handle,
0,
EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL
);
if (!EFI_ERROR (Status)) {
//
// Locate HII Database protocol and register the new package list.
//
Status = BootServices->LocateProtocol (&unk_8BD0, NULL, &HiiDatabase);
if (!EFI_ERROR (Status)) {
Status = HiiDatabase->NewPackageList (
HiiDatabase,
HiiHandle,
NULL,
&qword_9420
);
DEBUG ((EFI_D_INFO, "NewPackageList status: %r\n", Status));
} else {
DEBUG ((EFI_D_INFO,
"gEfiHiiDatabaseProtocolGuid protocol is not found\n"));
}
} else {
DEBUG ((EFI_D_INFO,
"gEfiHiiPackageListProtocolGuid protocol is not found\n"));
}
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "ASSERT_EFI_ERROR (Status = %r)\n", Status));
ASSERT_EFI_ERROR (Status);
}
//
// Measure secure boot variables (PK, KEK, db, dbx).
//
if (EFI_ERROR (MeasureSecureBootVariables ())) {
DEBUG ((EFI_D_ERROR, "Error Measuring Secure Vars\n"));
}
//
// Write a TCG reset-short event and return.
//
TcgWriteResetShortEvent (7);
return EFI_SUCCESS;
}
// ===========================================================================
// TCG Hash/Extend Event Functions
// ===========================================================================
/**
TPM 1.2 hash-and-extend event.
Locates the TCG protocol (EFI_TCG_PROTOCOL) and performs a
HashLogExtendEvent with the provided buffer and metadata.
@param[in] a1 Event type (TPM_PCR_EVENT event type).
@param[in] a2 PCR index (event metadata).
@param[in] a3 Buffer to hash.
@param[in] a4 Algorithm GUID.
@param[in] a5 Additional metadata buffer.
@param[in] a6 Size of additional data.
@return Status from TcgHashLogExtendEvent.
**/
EFI_STATUS
Tpm12HashLogExtendEvent (
IN INT32 a1,
IN INT32 a2,
IN VOID *a3,
IN VOID *a4,
IN VOID *a5,
IN UINT64 a6
)
{
EFI_STATUS Status;
EFI_TCG_PROTOCOL *TcgProtocol;
UINT32 EventSize;
EFI_PHYSICAL_ADDRESS TcgEventData;
TPML_DIGEST_VALUES DigestList;
TCG_PCR_EVENT *TcgEvent;
TcgProtocol = NULL;
TcgEvent = NULL;
TcgEventData = 0;
//
// Locate the TCG protocol.
//
Status = BootServices->LocateProtocol (
&unk_8C50,
NULL,
(VOID **)&TcgProtocol
);
if (EFI_ERROR (Status)) {
ASSERT (!EFI_ERROR (Status));
}
EventSize = a6 + 32 + 2 * StrLen (a3);
//
// Allocate the TCG event descriptor buffer.
//
Status = BootServices->AllocatePages (
AllocateAnyPages,
EfiBootServicesData,
EFI_SIZE_TO_PAGES (EventSize + 32),
&TcgEventData
);
if (!EFI_ERROR (Status) && (VOID *)TcgEventData != NULL) {
TcgEvent = (TCG_PCR_EVENT *)(UINTN)TcgEventData;
TcgEvent->PCRIndex = a1;
TcgEvent->EventType = a2;
TcgEvent->EventSize = EventSize;
//
// Allocate the event log data buffer.
//
Status = BootServices->AllocatePages (
AllocateAnyPages,
EfiBootServicesData,
EFI_SIZE_TO_PAGES (EventSize),
&TcgEventData
);
if (!EFI_ERROR (Status) && (VOID *)TcgEventData != NULL) {
TPML_DIGEST_VALUES *Digest;
UINT8 *EventLog;
Digest = (TPML_DIGEST_VALUES *)(UINTN)TcgEventData;
EventLog = (UINT8 *)(UINTN)TcgEventData;
CopyMem (Digest, a4, sizeof (TPML_DIGEST_VALUES));
Digest->count = StrLen (a3);
*(UINT64 *)&Digest->digests[0] = a6;
CopyMem (EventLog + 32, a3, 2 * StrLen (a3));
CopyMem (EventLog + 32 + 2 * StrLen (a3), a5, a6);
CopyMem (TcgEvent + 1, EventLog, (UINTN)TcgEvent->EventSize);
//
// Call TcgHashLogExtendEvent.
//
Status = TcgProtocol->HashLogExtendEvent (
TcgProtocol,
EventLog,
(UINT32)TcgEvent->EventSize,
TPM_ALG_SHA,
TcgEvent,
Digest,
(TCG_PCR_EVENT **)&Digest
);
if ((VOID *)TcgEvent != NULL) {
BootServices->FreePages ((EFI_PHYSICAL_ADDRESS)(UINTN)TcgEvent, 1);
}
if (EFI_ERROR (Status)) {
ASSERT (!EFI_ERROR (Status));
}
if ((VOID *)TcgEventData != NULL) {
BootServices->FreePages (TcgEventData, 1);
}
return Status;
} else {
BootServices->FreePages ((EFI_PHYSICAL_ADDRESS)(UINTN)TcgEvent, 1);
return EFI_OUT_OF_RESOURCES;
}
}
return Status;
}
/**
TPM 2.0 hash-and-extend event.
Locates the TCG2 protocol (EFI_TCG2_PROTOCOL) and performs a
HashLogExtendEvent with larger event descriptor (44 byte header
vs 32 for TPM 1.2). Used when sub_60B0() returns TRUE.
@param[in] a1 Event type.
@param[in] a2 PCR index / event metadata.
@param[in] a3 Buffer to hash.
@param[in] a4 Algorithm GUID / TCG_PCR_EVENT2 header.
@param[in] a5 Additional metadata.
@param[in] a6 Size of additional data.
@return Status from Tcg2HashLogExtendEvent.
**/
EFI_STATUS
Tcg2HashLogExtendEvent (
IN INT32 a1,
IN INT32 a2,
IN VOID *a3,
IN VOID *a4,
IN VOID *a5,
IN UINT64 a6
)
{
EFI_STATUS Status;
EFI_TCG2_PROTOCOL *Tcg2Protocol;
UINT32 EventSize;
EFI_PHYSICAL_ADDRESS TcgEventData;
TPML_DIGEST_VALUES DigestList;
TCG_PCR_EVENT2 *TcgEvent;
UINTN DigestListCount;
Tcg2Protocol = NULL;
TcgEvent = NULL;
TcgEventData = 0;
//
// Locate the TCG2 protocol.
//
Status = BootServices->LocateProtocol (
&unk_8C50,
NULL,
(VOID **)&Tcg2Protocol
);
if (EFI_ERROR (Status)) {
ASSERT (!EFI_ERROR (Status));
}
DigestListCount = StrLen (a3);
EventSize = a6 + 32 + 2 * (UINT32)DigestListCount;
//
// Allocate the TCG2 event descriptor (44 extra bytes).
//
Status = BootServices->AllocatePages (
AllocateAnyPages,
EfiBootServicesData,
EFI_SIZE_TO_PAGES (EventSize + 44),
&TcgEventData
);
if (!EFI_ERROR (Status) && (VOID *)TcgEventData != NULL) {
TcgEvent = (TCG_PCR_EVENT2 *)(UINTN)TcgEventData;
TcgEvent->PCRIndex = a1;
TcgEvent->EventType = a2;
TcgEvent->EventSize = EventSize;
//
// Allocate the event log data buffer.
//
Status = BootServices->AllocatePages (
AllocateAnyPages,
EfiBootServicesData,
EFI_SIZE_TO_PAGES (EventSize),
&TcgEventData
);
if (!EFI_ERROR (Status) && (VOID *)TcgEventData != NULL) {
TPML_DIGEST_VALUES *Digest;
UINT8 *EventLog;
Digest = (TPML_DIGEST_VALUES *)(UINTN)TcgEventData;
EventLog = (UINT8 *)(UINTN)TcgEventData;
CopyMem (Digest, a4, sizeof (TPML_DIGEST_VALUES));
Digest->count = DigestListCount;
*(UINT64 *)&Digest->digests[0] = a6;
CopyMem (EventLog + 32, a3, 2 * DigestListCount);
CopyMem (EventLog + 32 + 2 * DigestListCount, a5, a6);
CopyMem (TcgEvent + 11, EventLog, (UINTN)TcgEvent->EventSize);
//
// Call Tcg2HashLogExtendEvent.
//
Status = Tcg2Protocol->HashLogExtendEvent (
Tcg2Protocol,
EventLog,
(UINT32)TcgEvent->EventSize,
TPM_ALG_SHA256,
TcgEvent,
Digest,
(TCG_PCR_EVENT2 **)&Digest
);
if ((VOID *)TcgEvent != NULL) {
BootServices->FreePages ((EFI_PHYSICAL_ADDRESS)(UINTN)TcgEvent, 1);
}
if (EFI_ERROR (Status)) {
ASSERT (!EFI_ERROR (Status));
}
if ((VOID *)TcgEventData != NULL) {
BootServices->FreePages (TcgEventData, 1);
}
return Status;
} else {
BootServices->FreePages ((EFI_PHYSICAL_ADDRESS)(UINTN)TcgEvent, 1);
return EFI_OUT_OF_RESOURCES;
}
}
return Status;
}
// ===========================================================================
// Ready-to-Boot Notification
// ===========================================================================
/**
Ready-to-Boot notification callback.
Invoked when the UEFI Boot Manager signals the ReadyToBoot event.
Measures boot option variables, calls the OpRom Start/End protocol,
processes PER BIOS flags, and handles PPI state transitions.
This function is a major integration point for the TCG platform
initialization sequence.
**/
VOID
TcgReadyToBoot (
VOID
)
{
EFI_STATUS Status;
EFI_TCG2_PROTOCOL *Tcg2Protocol;
BOOLEAN IsTpm20;
VOID *TcgProtocol;
EFI_EVENT ResetEvent;
UINT16 ResetData;
VOID *PpiProtocol;
UINT64 TpmStatus;
INT32 Result;
DEBUG ((EFI_D_INFO, "TcgReady to boot entry\n"));
//
// Locate TCG2 protocol.
//
BootServices->LocateProtocol (&unk_8C50, NULL, &TcgProtocol);
IsTpm20 = sub_60B0 ();
//
// Locate TCG1.2 protocol for measuring during boot.
//
Status = BootServices->LocateProtocol (
&unk_8C40,
NULL,
(VOID **)&Tcg2Protocol
);
if (EFI_ERROR (Status)) {
return;
}
//
// Check if we have already entered this callback.
//
if (qword_8D10 != 0) {
if (IsTpm20) {
Status = Tcg2MeasureStringEvent ("Returning from EFI Application from Boot Option");
} else {
Status = Tpm12MeasureStringEvent ("Returning from EFI Application from Boot Option");
}
if (EFI_ERROR (Status)) {
return;
}
goto Done;
}
//
// First invocation: measure boot variables and call OpRomStartEnd.
//
sub_1E74 ();
if (!EFI_ERROR (BootServices->LocateProtocol (
&unk_8AB0,
NULL,
&PpiProtocol
))) {
((VOID (*)(VOID))PpiProtocol) ();
}
//
// Measure "Calling EFI Application from Boot Option" event.
//
if (IsTpm20) {
Status = Tcg2MeasureStringEvent ("Calling EFI Application from Boot Option");
} else {
Status = Tpm12MeasureStringEvent ("Calling EFI Application from Boot Option");
}
if (!EFI_ERROR (Status)) {
//
// Measure boot variables.
//
if (EFI_ERROR (sub_1BCC ())) {
DEBUG ((EFI_D_INFO, "Boot Variables not Measured. Error!\n"));
}
sub_1F20 ();
//
// Signal that we are done with boot measurements.
//
BootServices->SignalEvent (qword_9428);
Done:
//
// Check for TPM physical presence request.
//
if (qword_8D10 == 0) {
//
// Try to locate the physical presence protocol first.
//
if (EFI_ERROR (BootServices->LocateProtocol (
&unk_8B90,
NULL,
&PpiProtocol
))) {
TpmStatus = sub_60B0 ();
if (!TpmStatus) {
//
// No PPI protocol: issue TPM reset command directly.
//
ResetData = 1024;
TpmStatus = TpmSubmitCommand (
(UINT64)TcgProtocol,
1073741834,
2,
&ResetData
);
if (byte_8DA8) {
sub_6A4C (1, 50694662);
}
if (TpmStatus) {
if (byte_8DA8) {
sub_6A4C (2147483650LL, 50694659);
}
}
}
} else {
((VOID (*)(VOID))PpiProtocol) ();
}
}
qword_8D10++;
}
}
// ===========================================================================
// Physical Presence Interface (PPI) Functions
// ===========================================================================
/**
TCG2 PPI handler.
Reads the AMITCGPPIVAR and TcgINTPPI variables, processes PPI
operations (TPM enable/disable/clear), dispatches TPM commands,
and manages TPM PER BIOS flag and TPM state transitions.
Handles PPI request codes:
- 168 (0xA8): TPM Enable + Activate
- 341 (0x155): TPM Disable + Deactivate
- 358 (0x166): TPM Clear
**/
EFI_STATUS
PpiHandler (
VOID
)
{
EFI_STATUS Status;
EFI_TCG2_PROTOCOL *Tcg2Protocol;
UINT64 TcgProtocol;
VOID *TcgPpProtocol;
VOID *TcgProtocolInterface;
EFI_GUID *PpiProtocolGuid;
VOID *PpiEventData;
VOID *PpiNotifyRegistration;
UINTN DataSize;
UINT64 AmiTcgPpiVar[2];
INT32 PpiFlags;
UINTN PpiFlagsSize;
INT32 TcgFlags;
INT32 TcgFlagsSize;
UINT16 PerBiosFlags;
UINT8 PerBiosFlagsByte;
UINT16 Tpm20Response;
UINT8 SetupValue;
UINT32 PpiRequestNewValue;
UINT32 CommandResult;
UINT64 TpmStatus;
INT32 PpiRequest;
UINT8 EnableFlag;
UINT32 StatusCode;
BOOLEAN IsTpm20;
PpiRequest = 0;
SetupValue = 1;
DataSize = 4;
//
// Try to locate an existing PPI protocol handler.
//
if (!EFI_ERROR (BootServices->LocateProtocol (
&unk_8C70, NULL, &PpiProtocolGuid
))) {
return ((EFI_STATUS (*)(VOID))PpiProtocolGuid) ();
}
//
// Locate the TPM Platform Protocol.
//
Status = BootServices->LocateProtocol (
&unk_8C10,
NULL,
&TcgProtocolInterface
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Read TPM PER BIOS flags via TCG Platform Protocol.
//
PerBiosFlags = 0;
Status = BootServices->LocateProtocol (
&unk_8B50,
NULL,
&TcgPpProtocol
);
if (!EFI_ERROR (Status)) {
Status = ((EFI_STATUS (*)(UINT16 *))TcgPpProtocol) (&PerBiosFlags);
if (EFI_ERROR (Status)) {
PerBiosFlags = 0;
}
}
if (!EFI_ERROR (Status)) {
PerBiosFlags = 0;
}
//
// Read TPMPERBIOSFLAGS variable.
//
sub_60EC (
L"TPMPERBIOSFLAGS",
&unk_8B30,
7,
6,
&PerBiosFlags
);
DataSize = 24;
//
// Read or initialize the AMITCGPPIVAR variable.
//
Status = RuntimeServices->GetVariable (
L"AMITCGPPIVAR",
&unk_8B20,
NULL,
&DataSize,
AmiTcgPpiVar
);
if (Status == EFI_NOT_FOUND) {
AmiTcgPpiVar[0] = 0;
AmiTcgPpiVar[1] = 0;
*((UINT32 *)&AmiTcgPpiVar[2]) = 0;
sub_60EC (
L"AMITCGPPIVAR",
&unk_8B20,
7,
DataSize,
AmiTcgPpiVar
);
}
PpiRequestNewValue = (UINT32)AmiTcgPpiVar[0];
//
// Read the TcgINTPPI variable (PPI request code from OS).
//
TcgFlagsSize = 7;
PpiFlagsSize = 4;
PpiFlags = 0;
Status = RuntimeServices->GetVariable (
L"TcgINTPPI",
&unk_8C60,
&TcgFlagsSize,
&PpiFlagsSize,
&PpiFlags
);
if (EFI_ERROR (Status)) {
PpiFlags = 0;
}
DEBUG ((EFI_D_INFO, "\n PPI_request is: %x \n", PpiRequestNewValue));
//
// Process PPI request if one is pending.
//
if (PpiFlags != 0) {
EFI_TCG_PROTOCOL *TcgProtocolInstance;
EFI_EVENT *TcgEvent;
BOOLEAN IsTpm20Local;
//
// Initialize TPM platform type context.
//
CopyMem (
TpmPlatformContext,
TcgProtocolInterface + 1,
27
);
TpmPlatformContext[14] = 1;
((VOID (*)(VOID *, UINT8))(
*(VOID **)((UINT8 *)TcgProtocolInterface + 32)
)) (TpmPlatformContext, 1);
//
// Locate the TCG protocol.
//
Status = BootServices->LocateProtocol (
&unk_8C40,
NULL,
&TcgProtocolInstance
);
if (EFI_ERROR (Status)) {
return Status;
}
Status = BootServices->LocateProtocol (
&unk_8C50,
NULL,
&TcgProtocol
);
if (EFI_ERROR (Status)) {
return Status;
}
IsTpm20Local = sub_60B0 ();
if (IsTpm20Local) {
//
// TPM 2.0 path
//
if (PpiFlags == 168) {
//
// TPM Enable + Activate
//
CommandResult = TpmSubmitCommand (TcgProtocol, 113, 1, &SetupValue);
Tpm20Response = (UINT16)((CommandResult >> 8) |
HIWORD (CommandResult) & 0xFF00);
sub_61C0 (TcgProtocol, Tpm20Response);
if (!sub_60B0 ()) {
TcgProtocolInstance->ExitBootServices (TcgProtocolInstance);
}
PpiFlags = 0;
sub_60EC (L"TcgINTPPI", &unk_8C60, 3, 4, &PpiFlags);
TpmResetSystem ();
}
if (PpiFlags == 341) {
//
// TPM Disable + Deactivate
//
TpmSubmitCommand (TcgProtocol, 93, 0, NULL);
if (!sub_60B0 ()) {
TcgProtocolInstance->ExitBootServices (TcgProtocolInstance);
}
PpiFlags = 0;
sub_60EC (L"TcgINTPPI", &unk_8C60, 3, 4, &PpiFlags);
TpmResetSystem ();
}
if (PpiFlags == 358) {
//
// TPM Clear (owner clear + clear control)
//
CommandResult = TpmSubmitCommand (TcgProtocol, 32879, 0, NULL);
if (!CommandResult) {
CommandResult = TpmSubmitCommand (TcgProtocol, 32882, 1, &SetupValue);
if (!byte_8DA8) {
goto PpiUpdateDone;
}
sub_6A4C (1, 50694667);
} else {
if (!byte_8DA8) {
goto PpiUpdateDone;
}
sub_6A4C (2147483650LL, 50694676);
}
PpiUpdateDone:
Tpm20Response = (UINT16)((CommandResult >> 8) |
HIWORD (CommandResult) & 0xFF00);
sub_61C0 (TcgProtocol, Tpm20Response);
if (!sub_60B0 ()) {
TcgProtocolInstance->ExitBootServices (TcgProtocolInstance);
}
PpiFlags = 0;
sub_60EC (L"TcgINTPPI", &unk_8C60, 3, 4, &PpiFlags);
TpmResetSystem ();
}
} else {
//
// TPM 1.2 path
//
TcgProtocolInstance->ExitBootServices (TcgProtocolInstance);
if (PpiFlags == 168) {
//
// TPM Enable + Activate
//
CommandResult = TpmSubmitCommand (TcgProtocol, 113, 1, &SetupValue);
Tpm20Response = (UINT16)((CommandResult >> 8) |
HIWORD (CommandResult) & 0xFF00);
sub_61C0 (TcgProtocol, Tpm20Response);
if (!sub_60B0 ()) {
TcgProtocolInstance->ExitBootServices (TcgProtocolInstance);
}
PpiFlags = 0;
sub_60EC (L"TcgINTPPI", &unk_8C60, 3, 4, &PpiFlags);
TpmResetSystem ();
}
if (PpiFlags == 341) {
//
// TPM Disable + Deactivate
//
TpmSubmitCommand (TcgProtocol, 93, 0, NULL);
if (!sub_60B0 ()) {
TcgProtocolInstance->ExitBootServices (TcgProtocolInstance);
}
PpiFlags = 0;
sub_60EC (L"TcgINTPPI", &unk_8C60, 3, 4, &PpiFlags);
TpmResetSystem ();
}
if (PpiFlags == 358) {
//
// TPM Clear
//
CommandResult = TpmSubmitCommand (TcgProtocol, 111, 0, NULL);
if (byte_8DA8) {
sub_6A4C (1, 50694666);
}
if (!CommandResult) {
CommandResult = TpmSubmitCommand (TcgProtocol, 114, 1, &SetupValue);
goto UpdateResponse;
}
if (!byte_8DA8) {
goto PpiUpdateDone;
}
sub_6A4C (2147483650LL, 50694676);
goto UpdateResponse;
}
}
}
//
// After PPI processing, check for pending AMI PPI VAR and install
// the appropriate protocol notify handler.
//
if (PpiRequestNewValue == 13) {
//
// PPI setup value "PPI request sync" - install the PPI member protocol.
//
if (!EFI_ERROR (BootServices->AllocatePool (
EfiBootServicesData,
512,
(VOID **)&PpiNotifyRegistration
))) {
BootServices->InstallProtocolInterface (
&unk_8B00,
&unk_8C70,
EFI_NATIVE_INTERFACE,
unk_8DC0
);
}
return EFI_SUCCESS;
}
if ((PpiRequestNewValue - 1) <= 0x15) {
//
// PPI request in range 1-22: install PPI protocol with the
// appropriate handler (PpiSetupFlowStub for user confirmation flows).
//
return BootServices->InstallProtocolInterface (
&unk_8B60,
&unk_8C70,
EFI_NATIVE_INTERFACE,
unk_8DE8
);
}
//
// Default: install PPI protocol with PpiDispatchStub handler.
//
return BootServices->InstallProtocolInterface (
&unk_8B00,
&unk_8C70,
EFI_NATIVE_INTERFACE,
unk_8DC0
);
}
/**
TPM state machine and PER BIOS flag synchronization.
Reads the current TPM state from the TCG GetCapability, then
synchronizes with the "TpmOldvar" runtime variable and setup
values. If the TPM state differs from setup, triggers a TPM
enable/disable transition.
@return EFI_STATUS from the TCG protocol operations.
**/
EFI_STATUS
TpmStateSync (
VOID
)
{
EFI_STATUS Status;
EFI_TCG2_PROTOCOL *Tcg2Protocol;
UINT64 TcgProtocol;
VOID *TcgPpProtocol;
VOID *TcgPlatformProtocol;
UINTN DataSize;
UINT32 PpiFlags;
UINT64 PpiFlagsBuffer;
UINT16 PerBiosStatus;
UINT8 TpmEnabled;
UINT8 TpmOldVar;
UINT8 TpmOldVarNew;
UINT8 PlatformTypeContext[27];
UINT8 TpmCapData[512];
UINT8 TpmCapResult;
UINT64 VarSize;
UINT8 TpmActive;
UINT8 TpmEnable;
UINT8 SyncRequired;
UINT32 ResetValue;
UINT8 EnablePending;
INT32 SetupValue;
UINT8 OldVarMatch;
UINT16 CapTag;
UINT32 CapRetCode;
UINT32 CapSize;
PpiFlagsBuffer = 0;
ResetValue = 3;
DataSize = 64;
SyncRequired = 0;
EnablePending = 0;
OldVarMatch = 1;
//
// Try PPI protocol first (already installed).
//
if (!EFI_ERROR (BootServices->LocateProtocol (
&unk_8A80, NULL, &TcgPpProtocol
))) {
return ((EFI_STATUS (*)(VOID))TcgPpProtocol) ();
}
//
// Locate TCG1.2 protocol and TCG2 protocol.
//
Status = BootServices->LocateProtocol (
&unk_8C40, NULL, (VOID **)&Tcg2Protocol
);
if (EFI_ERROR (Status)) {
return Status;
}
Status = BootServices->LocateProtocol (
&unk_8C50, NULL, &TcgProtocol
);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR,
"Error: failed to locate TCG protocol: %r\n", Status));
return Status;
}
//
// Locate the TPM Platform Protocol.
//
Status = BootServices->LocateProtocol (
&unk_8C10, NULL, &TcgPlatformProtocol
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Get TPM capability information.
//
TcgGetCapability (TcgProtocol, TpmCapData);
//
// Read "TpmOldvar" UEFI variable (tracks previous TPM state).
//
VarSize = 3;
TpmOldVar = 0;
Status = RuntimeServices->GetVariable (
L"TpmOldvar",
&unk_8C60,
&VarSize,
&PpiFlagsBuffer,
&TpmOldVar
);
if (Status == EFI_NOT_FOUND) {
//
// Variable does not exist yet - create it.
//
TpmOldVar = TpmPlatformInfo.Enable;
Status = RuntimeServices->SetVariable (
L"TpmOldvar",
&unk_8C60,
VarSize,
PpiFlagsBuffer,
&TpmOldVar
);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_INFO,
"\n Set Old TpmOldvar Status = %r \n", Status));
}
} else {
TpmOldVarNew = TpmOldVar;
}
//
// Compare old TPM state with current state from setup.
//
if (Status == EFI_SUCCESS) {
TpmActive = ((TpmCapData[0] | TpmCapData[1]) & 1) == 0;
if (TpmOldVar != TpmActive) {
//
// TPM state changed: sync required.
//
TpmOldVarNew = TpmActive;
SyncRequired = 1;
TpmOldVar = TpmActive;
EnablePending = 0;
Status = RuntimeServices->SetVariable (
L"TpmOldvar",
&unk_8C60,
VarSize,
PpiFlagsBuffer,
&TpmOldVar
);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_INFO,
"\n Set Old TpmOldvar Status = %r \n", Status));
}
}
}
//
// Save the platform type context.
//
byte_8D19 = PlatformTypeContext[0];
//
// Process TPM PER BIOS flags and setup synchronisation.
//
Status = sub_647C (&SyncRequired);
if (EFI_ERROR (Status)) {
//
// Register a periodic timer callback to retry PER BIOS processing.
//
Status = BootServices->SetTimer (
&ResetValue,
TimerPeriodic,
EFI_TIMER_PERIOD_SECONDS (1)
);
if (EFI_ERROR (Status)) {
return Status;
}
Status = BootServices->RegisterProtocolNotify (
&unk_8B00,
ResetValue,
(VOID **)&PpiFlagsBuffer
);
if (EFI_ERROR (Status)) {
return Status;
}
}
//
// Update the TPM platform type.
//
((VOID (*)(VOID *, UINT64))(
*(VOID **)((UINT8 *)TcgPlatformProtocol + 32)
)) (PlatformTypeContext, 0);
//
// Check if TPM state needs to change.
//
if (TpmOldVarNew == TpmActive) {
if (EnablePending) {
//
// Enable was requested.
//
DEBUG ((EFI_D_INFO, "\n ENABLE == Setup in setup \n"));
sub_24D8 (EnablePending);
EnablePending = 0;
}
return Status;
}
//
// TPM state mismatch: trigger a TPM enable/disable request.
//
DEBUG ((EFI_D_INFO, "\n TMP_ENABLE != Setup in setup \n"));
sub_24D8 (7 - (TpmOldVarNew != 0));
//
// Refresh the platform type context.
//
((VOID (*)(VOID *, UINT8))(
*(VOID **)((UINT8 *)TcgPlatformProtocol + 32)
)) (PlatformTypeContext, 0);
//
// Apply the new TPM state.
//
((VOID (*)(VOID *, UINT8))(
*(VOID **)((UINT8 *)TcgPlatformProtocol + 32)
)) (PlatformTypeContext, 1);
TpmResetSystem ();
return Status;
}
// ===========================================================================
// TPM Reset Functions
// ===========================================================================
/**
Perform a TPM / system reset.
Issues ResetSystem via the UEFI Runtime Services. If the reset call
returns (which it should not normally), logs the failure and registers
a callback to retry once the Reset Architectural Protocol is available.
**/
VOID
TpmResetSystem (
VOID
)
{
EFI_STATUS Status;
dword_8DDC = 0;
DEBUG ((EFI_D_INFO, "TCG: Resets the system: type(%d)\n", 0));
DEBUG ((EFI_D_INFO, "TCG: Resets the system: typeaddress(%x)\n",
(UINTN)&dword_8DDC));
//
// Attempt to clear the "LastBootFailed" flag.
//
{
UINTN VarSize;
UINT8 BootFailedFlag;
VarSize = 4;
if (!EFI_ERROR (RuntimeServices->GetVariable (
L"LastBootFailed",
&unk_8B40,
NULL,
&VarSize,
&BootFailedFlag
))) {
Status = RuntimeServices->SetVariable (
L"LastBootFailed",
&unk_8B40,
1,
0,
&BootFailedFlag
);
DEBUG ((EFI_D_INFO, "Status : = %r\n", Status));
}
}
//
// Issue the system reset.
//
RuntimeServices->ResetSystem (
dword_8DDC,
EFI_SUCCESS,
0,
NULL
);
DEBUG ((EFI_D_ERROR, "\tError: Reset failed???\n"));
//
// Register a DoResetNow callback in case ResetSystem failed.
//
Status = BootServices->CreateEvent (
EVT_TIMER | EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
DoResetNow,
&dword_8DDC,
&qword_8DC8
);
if (!EFI_ERROR (Status)) {
BootServices->SetTimer (
qword_8DC8,
TimerPeriodic,
EFI_TIMER_PERIOD_SECONDS (1)
);
DEBUG ((EFI_D_INFO,
"\tRegister DoResetNow after Reset Architecture driver\n"));
}
}
/**
DoResetNow callback.
Called (via timer or event) to retry the system reset after the
Reset Architectural Protocol becomes available.
@param[in] a1 Context / reset type value.
@param[in] a2 Reset data (unused).
**/
VOID
DoResetNow (
IN UINT32 *a1,
IN UINT32 *a2
)
{
DEBUG ((EFI_D_INFO, "TCG: DoResetNow resets the system: type(%d)\n",
*a1));
DEBUG ((EFI_D_INFO, "TCG: DoResetNow resets the system: type(%x)\n",
(UINTN)a1));
RuntimeServices->ResetSystem (*a1, EFI_SUCCESS, 0, NULL);
DEBUG ((EFI_D_ERROR, "\tError: Reset failed???\n"));
}
// ===========================================================================
// TCG GetCapability
// ===========================================================================
/**
TCG GetCapability wrapper with debug logging.
Sends a TPM2_GetCapability command via the TCG2 protocol and logs
the response (capability data, return code, tag, and data bytes)
for diagnostic purposes.
@param[in] a1 TCG2/TCG protocol instance.
@param[in] a2 Output buffer (minimum 36 bytes for capability response).
@return EFI_STATUS from GetCapability.
**/
EFI_STATUS
TcgGetCapability (
IN VOID *a1,
OUT VOID *a2
)
{
EFI_STATUS Status;
UINT32 CapSize;
UINT32 CapRetCode;
UINT16 CapTag;
UINT32 CapDataBytes;
UINT16 TcgCapCmd;
UINT32 ResponseSize;
UINT8 ResponseBuffer[256];
//
// Build the TPM GetCapability command buffer.
//
TcgCapCmd = TPM_ST_NO_SESSIONS;
*(UINT32 *)((UINT8 *)&TcgCapCmd + 2) = 369098752; // TPM_CC_GetCapability
*(UINT32 *)((UINT8 *)&TcgCapCmd + 6) = 0x4000000;
*(UINT32 *)((UINT8 *)&TcgCapCmd + 10) = 134283264;
*(UINT32 *)((UINT8 *)&TcgCapCmd + 14) = 1702887424;
if (!sub_60B0 ()) {
*(UINT32 *)((UINT8 *)&TcgCapCmd + 14) = 1694498816;
}
*(UINT32 *)((UINT8 *)&TcgCapCmd + 18) = 0x4000000;
//
// TPM2_GetCapability via the TCG2 protocol.
//
Status = ((EFI_STATUS (*)(VOID *, UINT32, VOID *, UINT32, VOID *))(
*(VOID **)((UINT8 *)a1 + 24)
)) (a1, 22, &TcgCapCmd, 256, ResponseBuffer);
if (!EFI_ERROR (Status)) {
//
// Copy capability response to the caller's buffer.
//
CopyMem (a2, ResponseBuffer, 36);
//
// Decode and log capability response fields (byte-order swap).
//
CapDataBytes = ((*(UINT32 *)((UINT8 *)a2 + 16) & 0xFF00 |
(*(UINT32 *)((UINT8 *)a2 + 16) << 16)) << 8) |
((HIWORD(*(UINT32 *)((UINT8 *)a2 + 16)) |
*(UINT32 *)((UINT8 *)a2 + 16) & 0xFF0000u) >> 8);
CapTag = HIBYTE(*(UINT16 *)((UINT8 *)a2 + 14)) |
(*(UINT16 *)((UINT8 *)a2 + 14) << 8);
CapRetCode = ((*(UINT32 *)((UINT8 *)a2 + 6) & 0xFF00 |
(*(UINT32 *)((UINT8 *)a2 + 6) << 16)) << 8) |
((HIWORD(*(UINT32 *)((UINT8 *)a2 + 6)) |
*(UINT32 *)((UINT8 *)a2 + 6) & 0xFF0000u) >> 8);
CapSize = ((*(UINT32 *)((UINT8 *)a2 + 2) & 0xFF00 |
(*(UINT32 *)((UINT8 *)a2 + 2) << 16)) << 8) |
((HIWORD(*(UINT32 *)((UINT8 *)a2 + 2)) |
*(UINT32 *)((UINT8 *)a2 + 2) & 0xFF0000u) >> 8);
DEBUG ((EFI_D_INFO,
"GetCapability: %r; size: %x; retCode:%x; tag:%x; bytes %08x\n",
Status, CapSize, CapRetCode, CapTag, CapDataBytes));
}
return Status;
}
// ===========================================================================
// TCG Measurement Event Helpers
// ===========================================================================
/**
TPM 1.2 measurement of an event with a string description.
Allocates a TCG_PCR_EVENT buffer, populates it with the string,
and calls TcgHashLogExtendEvent to measure the data.
@param[in] String Null-terminated ASCII string describing the event.
@return EFI_STATUS from the TCG protocol HashLogExtendEvent.
**/
EFI_STATUS
Tpm12MeasureStringEvent (
IN CHAR8 *String
)
{
EFI_STATUS Status;
EFI_TCG_PROTOCOL *TcgProtocol;
UINT32 EventSize;
TCG_PCR_EVENT *TcgEvent;
UINT32 ReturnSize;
UINT8 Digest[16];
TcgEvent = NULL;
//
// Locate TCG protocol.
//
Status = BootServices->LocateProtocol (
&unk_8C50,
NULL,
(VOID **)&TcgProtocol
);
if (EFI_ERROR (Status)) {
ASSERT (!EFI_ERROR (Status));
}
//
// Calculate event size and allocate buffer.
//
EventSize = StrSize (String);
Status = BootServices->AllocatePool (
EfiBootServicesData,
EventSize + 32,
(VOID **)&TcgEvent
);
if (!EFI_ERROR (Status) && TcgEvent != NULL) {
TcgEvent->PCRIndex = 5;
TcgEvent->EventType = (UINT32)(INT32)0x80010007;
TcgEvent->EventSize = EventSize;
//
// Copy event data into the buffer.
//
CopyMem (TcgEvent + 1, String, EventSize);
//
// Submit the measurement.
//
Status = TcgProtocol->HashLogExtendEvent (
TcgProtocol,
String,
EventSize,
TPM_ALG_SHA,
TcgEvent,
Digest,
&ReturnSize
);
if (TcgEvent != NULL) {
BootServices->FreePool (TcgEvent);
}
return Status;
}
return Status;
}
/**
TPM 2.0 measurement of an event with a string description.
Uses the larger TCG2_PCR_EVENT2 structure with 44-byte header
(vs 32 for TPM 1.2). Supports multiple algorithm digests.
@param[in] String Null-terminated ASCII string describing the event.
@return EFI_STATUS from the TCG2 protocol HashLogExtendEvent.
**/
EFI_STATUS
Tcg2MeasureStringEvent (
IN CHAR8 *String
)
{
EFI_STATUS Status;
EFI_TCG2_PROTOCOL *Tcg2Protocol;
UINT32 EventSize;
TCG_PCR_EVENT2 *TcgEvent;
UINT32 ReturnSize;
UINT8 Digest[16];
TcgEvent = NULL;
//
// Locate TCG2 protocol.
//
Status = BootServices->LocateProtocol (
&unk_8C50,
NULL,
(VOID **)&Tcg2Protocol
);
if (EFI_ERROR (Status)) {
ASSERT (!EFI_ERROR (Status));
}
//
// Calculate event size and allocate buffer (44 extra bytes for TCG2 header).
//
EventSize = StrSize (String);
Status = BootServices->AllocatePool (
EfiBootServicesData,
EventSize + 44,
(VOID **)&TcgEvent
);
if (!EFI_ERROR (Status) && TcgEvent != NULL) {
TcgEvent->PCRIndex = 5;
TcgEvent->EventType = (UINT32)(INT32)0x80010007;
TcgEvent->EventSize = EventSize;
//
// Copy event data after the header (offset 44 for TCG2).
//
CopyMem ((UINT8 *)TcgEvent + 44, String, EventSize);
//
// Submit the measurement.
//
Status = Tcg2Protocol->HashLogExtendEvent (
Tcg2Protocol,
String,
EventSize,
TPM_ALG_SHA256,
TcgEvent,
Digest,
&ReturnSize
);
if (TcgEvent != NULL) {
BootServices->FreePool (TcgEvent);
}
return Status;
}
return Status;
}
// ===========================================================================
// Secure Boot Variable Measurement
// ===========================================================================
/**
Measures Secure Boot related UEFI variables into PCR[7].
Iterates over SecureBoot, PK, KEK, db, dbx (and ImageExecTable)
UEFI variables and measures each via the TCG/TCG2 protocol.
@return EFI_STATUS from the last measurement operation.
**/
EFI_STATUS
MeasureSecureBootVariables (
VOID
)
{
EFI_STATUS Status;
UINT64 TcgProtocol;
UINTN Index;
EFI_GUID *AlgoGuid;
UINT16 *VariableNames[6];
INT32 EventTypes[6];
//
// Initialize variable name and event type tables.
//
VariableNames[0] = L"SecureBoot";
VariableNames[1] = L"PK";
VariableNames[2] = L"KEK";
VariableNames[3] = L"db";
VariableNames[4] = L"dbx";
VariableNames[5] = L"ImageExecTable";
EventTypes[0] = (INT32)0x80010007;
EventTypes[1] = (INT32)0x80010007;
EventTypes[2] = (INT32)0x80010007;
EventTypes[3] = (INT32)0x80010007;
EventTypes[4] = (INT32)0x80010007;
//
// Locate TCG2 protocol.
//
Status = BootServices->LocateProtocol (
&unk_8C50,
NULL,
&TcgProtocol
);
if (EFI_ERROR (Status)) {
ASSERT (!EFI_ERROR (Status));
}
for (Index = 0; Index < 5; Index++) {
EFI_GUID Guid;
VOID *VariableData;
UINTN VariableSize;
//
// Select the algorithm GUID.
//
if ((Index >= 3) && (Index <= 4)) {
Guid = *(EFI_GUID *)xmmword_6B40;
} else {
Guid = *(EFI_GUID *)xmmword_8A50;
}
//
// Read the UEFI variable.
//
Status = sub_18E8 (VariableNames[Index], &Guid, &VariableSize);
if (Status == EFI_SUCCESS && VariableSize > 0) {
//
// Check if this is the SecureBoot variable.
//
if (Index == 0) {
byte_8D18 = (*(UINT8 *)VariableData != 0) ? 1 : byte_8D18;
}
if (byte_8D18 != 1) {
BOOLEAN IsTpm20;
IsTpm20 = sub_60B0 ();
if (IsTpm20) {
Status = Tcg2HashLogExtendEvent (
7,
EventTypes[Index],
VariableNames[Index],
&Guid,
VariableData,
VariableSize
);
} else {
Status = Tpm12HashLogExtendEvent (
7,
EventTypes[Index],
VariableNames[Index],
&Guid,
VariableData,
VariableSize
);
}
if (byte_8DA8) {
sub_6A4C (1, 50694677);
}
BootServices->FreePool (VariableData);
}
}
}
return Status;
}
// ===========================================================================
// Option ROM Measurement
// ===========================================================================
/**
Measures an option ROM or legacy image into the TPM.
Locates the TCG/TCG2 protocol and builds a TCG_PCR_EVENT or
TCG_PCR_EVENT2 structure to measure the image.
@param[in] ImageBase Pointer to the image to measure.
@param[in] ImageSize Size of the image in bytes.
@param[in] Pfa PFA (Processor Family Architecture) identifier.
@return EFI_STATUS from TcgHashLogExtendEvent.
**/
EFI_STATUS
MeasureOptionRom (
IN VOID *ImageBase,
IN UINT64 ImageSize,
IN UINT16 Pfa
)
{
EFI_STATUS Status;
UINT64 TcgProtocol;
UINT32 HashLen;
UINT8 *HashPtr;
UINT32 EventStruct[2];
UINT32 EventHeader[2];
UINT32 PcrIndex;
UINT32 StructSize;
BOOLEAN IsTpm20;
UINT8 *DigestBuf;
DEBUG ((EFI_D_INFO,
"Measuring image @ %x, image len = %x, pfa = %x \n",
ImageBase, ImageSize, Pfa));
IsTpm20 = sub_60B0 ();
if (IsTpm20) {
//
// TPM 2.0 measurement path.
//
Status = BootServices->LocateProtocol (
&unk_8C50,
NULL,
&TcgProtocol
);
if (EFI_ERROR (Status)) {
return EFI_SUCCESS;
}
EventHeader[1] = Pfa;
HashPtr = &DigestBuf;
EventStruct[0] = 2;
EventStruct[1] = 6;
PcrIndex = 7;
StructSize = 44;
HashLen = 32;
Status = ((EFI_STATUS (*)(VOID *, VOID *, UINT64, UINT32,
UINT32 *, UINT8 **))(
*(VOID **)((UINT8 *)TcgProtocol + 8)
)) (TcgProtocol, ImageBase, ImageSize, 4, &HashLen, &HashPtr);
if (!EFI_ERROR (Status)) {
Status = ((EFI_STATUS (*)(VOID *, UINT32 *, UINT32, UINT32,
UINT32 *, UINT8 *, UINT8 *))(
*(VOID **)((UINT8 *)TcgProtocol + 32)
)) (TcgProtocol, PcrIndex, StructSize, 4, EventStruct,
HashPtr, DigestBuf);
}
} else {
//
// TPM 1.2 measurement path.
//
Status = BootServices->LocateProtocol (
&unk_8C50,
NULL,
&TcgProtocol
);
if (EFI_ERROR (Status)) {
return EFI_SUCCESS;
}
EventHeader[1] = Pfa;
HashPtr = &DigestBuf;
EventStruct[0] = 2;
EventStruct[1] = 6;
StructSize = 32;
HashLen = 20;
Status = ((EFI_STATUS (*)(VOID *, VOID *, UINT64, UINT32,
UINT32 *, UINT8 **))(
*(VOID **)((UINT8 *)TcgProtocol + 8)
)) (TcgProtocol, ImageBase, ImageSize, 4, &HashLen, &HashPtr);
if (!EFI_ERROR (Status)) {
Status = ((EFI_STATUS (*)(VOID *, UINT32 *, UINT32, UINT32,
UINT32 *, UINT8 *, UINT8 *))(
*(VOID **)((UINT8 *)TcgProtocol + 32)
)) (TcgProtocol, PcrIndex, StructSize, 4, EventStruct,
HashPtr, DigestBuf);
}
}
return Status;
}
// ===========================================================================
// PCI I/O Protocol Notify and OpROM Measurement
// ===========================================================================
/**
OnPciIOInstalled protocol callback.
Triggered when a PCI I/O protocol is installed. Locates the
OpRomStartEnd protocol to obtain the PCI I/O instance, then
retrieves and measures the option ROM image associated with
the device.
The function reads RomImage and RomSize from the PCI I/O protocol,
determines the PFA (Processor Family Architecture) from the device,
and calls MeasureOptionRom to measure the ROM content.
**/
VOID
OnPciIOInstalled (
VOID
)
{
EFI_STATUS Status;
EFI_HANDLE *HandleBuffer;
UINTN HandleCount;
UINTN Index;
OPROM_START_END_PROTOCOL *OpRomStartEnd;
EFI_PCI_IO_PROTOCOL *PciIo;
UINT64 RomSize;
VOID *RomImage;
UINT16 Pfa;
UINTN DataSize;
HandleBuffer = NULL;
DataSize = 8;
DEBUG ((EFI_D_INFO, "OnPciIOInstalled\n"));
//
// Locate all handles that support the OpRomStartEnd protocol.
//
Status = BootServices->LocateHandle (
ByProtocol,
&unk_8AD0,
NULL,
&DataSize,
&HandleBuffer
);
if (Status == EFI_BUFFER_TOO_SMALL) {
HandleBuffer = AllocatePool (DataSize);
if (HandleBuffer != NULL) {
Status = BootServices->LocateHandle (
ByProtocol,
&unk_8AD0,
NULL,
&DataSize,
HandleBuffer
);
}
}
DEBUG ((EFI_D_INFO,
"OnPciIOInstalled LocateHandle = %r \n", Status));
//
// Open the OpRomStartEnd protocol on each handle.
//
if (!EFI_ERROR (Status)) {
HandleCount = DataSize / sizeof (EFI_HANDLE);
} else {
HandleCount = 0;
}
for (Index = 0; Index < HandleCount; Index++) {
Status = BootServices->HandleProtocol (
HandleBuffer[Index],
&unk_8AD0,
(VOID **)&OpRomStartEnd
);
DEBUG ((EFI_D_INFO,
"OnPciIOInstalled HandleProtocol = %r \n", Status));
if (!EFI_ERROR (Status)) {
DEBUG ((EFI_D_INFO,
"OpRomStartEndProtocol located \n"));
if (OpRomStartEnd != NULL && OpRomStartEnd->PciIo != NULL) {
RomImage = OpRomStartEnd->PciIo->RomImage;
RomSize = OpRomStartEnd->PciIo->RomSize;
DEBUG ((EFI_D_INFO,
"OpRomStartEndProtocol->PciIo->RomImage = %x \n",
RomImage));
DEBUG ((EFI_D_INFO,
"OpRomStartEndProtocol->PciIo->RomSize = %x \n",
RomSize));
DEBUG ((EFI_D_INFO, "Measuring legacy image \n"));
//
// Determine PFA from the PCI I/O protocol.
//
Pfa = sub_1234 (OpRomStartEnd);
//
// Measure the option ROM image.
//
MeasureOptionRom (RomImage, (UINT32)RomSize, Pfa);
}
}
}
if (HandleBuffer != NULL) {
FreePool (HandleBuffer);
}
}
// ===========================================================================
// TPM PER BIOS Flag Processing
// ===========================================================================
/**
Writes a value into a TPM-peripheral BIOS-storage format block.
Parses a TPM-formatted data buffer, finds the field matching the
magic tag "TPM_" (0x5F504D54), and updates the value at the field's
offset based on the type byte.
Supported types:
0x01 (UINT8), 0x0A (UINT8 at offset+5), 0x0B (UINT16 at offset+5),
0x0C (UINT32 at offset+5), 0x0E (UINT64 at offset+5)
@param[in] Buffer TPM-formatted data buffer (type-length-value).
@param[in] Size Size of the data buffer.
@param[in] Data Input string (used for initial tag calculation).
@param[in] NewValue The new value to write at the matched field.
@retval EFI_SUCCESS Value updated successfully.
@retval EFI_NOT_FOUND "TPM_" tag not found in buffer.
@retval EFI_UNSUPPORTED Unrecognized field type.
**/
UINT64
PerBiosWriteValue (
IN VOID *Buffer,
IN UINT64 Size,
IN VOID *Data,
IN UINT64 NewValue
)
{
UINT32 TpmTag;
UINT32 TagValue;
INT32 FieldOffset;
UINT32 Index;
UINT8 *BytePtr;
//
// Compute the TPM tag ("TPM_" = 0x5F504D54 as an integer
// written into the buffer).
//
TpmTag = 1600085855; // Magic constant for tag search
CopyMem (&TagValue, Data, StrSize (Data));
//
// Search for the tag in the buffer.
//
FieldOffset = -1;
for (Index = 0; Index < (UINT32)Size; Index++) {
if (*(UINT32 *)((UINT8 *)Buffer + Index) == TpmTag) {
FieldOffset = (INT32)Index;
break;
}
}
if (FieldOffset < 0) {
return EFI_NOT_FOUND;
}
BytePtr = (UINT8 *)Buffer + FieldOffset;
//
// Check if the preceding byte is a valid continuation indicator.
//
if (((*(BytePtr - 1) - 92) & 0xFD) == 0) {
BytePtr--;
}
//
// Determine the value type and update accordingly.
//
if (*(BytePtr - 1) == 8) {
//
// Found a valid field - examine its type.
//
switch (*(BytePtr + 4)) {
case 0x01:
case 0x02:
//
// UINT8 - only update if the new value fits.
//
if (NewValue >= 2) {
return EFI_UNSUPPORTED;
}
*(BytePtr + 4) = (UINT8)NewValue;
break;
case 0x0A:
*(BytePtr + 5) = (UINT8)NewValue;
break;
case 0x0B:
*(UINT16 *)(BytePtr + 5) = (UINT16)NewValue;
break;
case 0x0C:
*(UINT32 *)(BytePtr + 5) = (UINT32)NewValue;
break;
case 0x0E:
*(UINT64 *)(BytePtr + 5) = NewValue;
return EFI_SUCCESS;
default:
return EFI_UNSUPPORTED;
}
}
return EFI_SUCCESS;
}
// ===========================================================================
// HOB List Initialization
// ===========================================================================
/**
Initializes the HOB list pointer by scanning the system table.
Walks the configuration table entries looking for a HOB list,
caches the pointer in qword_8D60, and uses ASSERT on failure.
@param[in] a1 ImageHandle (unused in this implementation).
**/
UINT64
InternalGetHobList (
IN VOID *a1
)
{
UINTN Index;
if (qword_8D60 == 0) {
qword_8D60 = 0;
if (SystemTable->NumberOfTableEntries > 0) {
for (Index = 0; Index < SystemTable->NumberOfTableEntries; Index++) {
if (sub_6814 (a1,
SystemTable->ConfigurationTable[Index].VendorTable)) {
qword_8D60 =
(UINT64)SystemTable->ConfigurationTable[Index].VendorTable;
break;
}
}
if (qword_8D60 == 0) {
DEBUG ((EFI_D_ERROR,
"ASSERT_EFI_ERROR (Status = %r)\n",
EFI_NOT_FOUND));
ASSERT_EFI_ERROR (EFI_NOT_FOUND);
}
} else {
DEBUG ((EFI_D_ERROR,
"ASSERT_EFI_ERROR (Status = %r)\n",
EFI_NOT_FOUND));
ASSERT_EFI_ERROR (EFI_NOT_FOUND);
}
if (qword_8D60 == 0) {
ASSERT (qword_8D60 != 0);
}
}
return qword_8D60;
}
// ===========================================================================
// HII String Retrieval
// ===========================================================================
/**
Retrieves a string from the HII database by String ID.
@param[in] HiiHandle HII handle of the package list.
@param[in] StringId ID of the string to retrieve.
@param[in] Language Language code string.
@return Pointer to the retrieved UCS-2 string, or NULL on failure.
**/
UINT16 *
HiiGetString (
IN EFI_HII_HANDLE HiiHandle,
IN UINT16 StringId,
IN CHAR8 *Language
)
{
EFI_HII_DATABASE_PROTOCOL *HiiDatabase;
EFI_HII_STRING_PROTOCOL *StringProtocol;
UINT16 *StringBuffer;
UINT16 *StringPtr;
UINTN StringSize;
VOID *PackageList;
VOID *PackageListCopy;
HiiDatabase = NULL;
StringBuffer = NULL;
StringPtr = NULL;
StringSize = 0;
PackageList = NULL;
//
// Validate HII handle.
//
ASSERT (qword_9420 != NULL);
ASSERT (StringId != 0);
//
// Get the HII package list for the given handle.
//
PackageList = sub_63D8 (qword_9420);
if (PackageList != NULL) {
sub_5BDC (PackageList, &PackageListCopy);
if (PackageListCopy != NULL) {
StringPtr = PackageListCopy;
} else {
StringPtr = &unk_84FA;
}
StringBuffer = sub_5CD4 (
(UINT64)PackageList,
0,
&unk_84FA,
StringPtr,
(UINT64)PackageList,
0
);
if (StringBuffer != NULL) {
//
// Try to get the string via HII String Protocol.
//
if (((EFI_STATUS (*)(VOID *, UINT16 *, UINT64, UINT16,
UINT16 **, UINTN *, UINT32))(
*(VOID **)((UINT8 *)qword_8D70 + 8)
)) (qword_8D70, StringBuffer, qword_9420, StringId,
&StringSize, &StringBuffer, 0) == EFI_BUFFER_TOO_SMALL) {
//
// Allocate a temporary buffer for the string.
//
StringPtr = sub_69E0 (StringSize);
if (StringPtr != NULL) {
if (((EFI_STATUS (*)(VOID *, UINT16 *, UINT64, UINT16,
UINT16 *, UINTN *, UINT32))(
*(VOID **)((UINT8 *)qword_8D70 + 8)
)) (qword_8D70, StringBuffer, qword_9420, StringId,
StringPtr, &StringSize, 0) < 0) {
sub_6A08 (StringPtr);
StringPtr = NULL;
}
}
}
}
sub_6A08 (PackageList);
if (PackageListCopy != NULL) {
sub_6A08 (PackageListCopy);
}
if (StringBuffer != NULL) {
sub_6A08 (StringBuffer);
}
}
return StringPtr;
}
// ===========================================================================
// Write TCG Reset-Short Event
// ===========================================================================
/**
Writes a short-form TCG event indicating a TPM reset cycle.
@param[in] ResetType Reset type code (typically 7 for TPM reset).
@return EFI_STATUS from TcgHashLogExtendEvent.
**/
EFI_STATUS
TcgWriteResetShortEvent (
IN INT32 ResetType
)
{
EFI_STATUS Status;
UINT64 TcgProtocol;
UINT32 EventData[8];
UINT8 DigestBuffer[24];
INT32 ResetEvent;
UINT8 EventOut;
UINT8 EventOut2;
TcgProtocol = 0;
ResetEvent = 0;
//
// Locate TCG protocol.
//
BootServices->LocateProtocol (
&unk_8C50,
NULL,
&TcgProtocol
);
//
// Build the TCG_PCR_EVENT structure.
//
EventData[0] = ResetType;
EventData[1] = 4;
EventData[7] = 4;
CopyMem (DigestBuffer, &ResetEvent, 4);
//
// Call HashLogExtendEvent.
//
return ((EFI_STATUS (*)(VOID *, INT32 *, UINT32, UINT32,
UINT32 *, UINT8 *, UINT8 *))(
*(VOID **)((UINT8 *)TcgProtocol + 32)
)) (TcgProtocol, &ResetEvent, 4, 4, EventData, &EventOut, &EventOut2);
}
// ===========================================================================
// TCG Command Submission
// ===========================================================================
/**
Submits a TPM command via the TCG/TCG2 protocol and returns the response.
Wraps the TcgSubmitCommand / Tcg2SubmitCommand protocol call with
a command code and parameters.
@param[in] TcgProtocol Pointer to the TCG or TCG2 protocol instance.
@param[in] CommandCode TPM command ordinal (e.g. TPM_CC_GetCapability).
@param[in] Param1 First parameter (varies by command).
@param[in] Param2 Second parameter (varies by command).
@return Command response data (platform-specific encoding).
**/
UINT32
TpmSubmitCommand (
IN VOID *TcgProtocol,
IN UINT32 CommandCode,
IN UINT32 Param1,
IN UINT32 Param2
)
{
//
// Build the TPM command buffer and call SubmitCommand via
// the protocol interface (offset +24 from protocol base).
//
// The exact buffer format depends on the TPM command type
// and the TCG/TCG2 protocol version.
//
return ((UINT32 (*)(VOID *, UINT32, UINT32, UINT32, UINT32))(
*(VOID **)((UINT8 *)TcgProtocol + 24)
)) (TcgProtocol, CommandCode, Param1, Param2, 0);
}
/**
Debug wrapper: writes 1 to output and returns 0.
@param[out] a1 Set to 1.
@return 0 (EFI_SUCCESS).
**/
EFI_STATUS
PpiWriteAndReturnSuccess (
OUT UINT32 *a1
)
{
*a1 = 1;
return 0;
}
/**
Stub function for PPI member protocol dispatch.
@return EFI_SUCCESS.
**/
VOID
PpiDispatchStub (
VOID
)
{
return;
}
/**
Stub function for PPI protocol dispatch (setup flow).
@return EFI_SUCCESS.
**/
VOID
PpiSetupFlowStub (
VOID
)
{
return;
}
/**
Timer notification callback for PER BIOS retry processing.
@param[in] a1 Event context (unused).
@param[in] a2 Event context (unused).
**/
VOID
PerBiosRetryTimerNotify (
UINT64 a1,
UINT64 a2
)
{
return;
}