/** @file | |
This module implements Tcg2 Protocol. | |
Copyright (c) 2015 - 2019, Intel Corporation. All rights reserved.<BR> | |
(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include <PiDxe.h> | |
#include <IndustryStandard/Acpi.h> | |
#include <IndustryStandard/PeImage.h> | |
#include <IndustryStandard/TcpaAcpi.h> | |
#include <Guid/GlobalVariable.h> | |
#include <Guid/HobList.h> | |
#include <Guid/TcgEventHob.h> | |
#include <Guid/EventGroup.h> | |
#include <Guid/EventExitBootServiceFailed.h> | |
#include <Guid/ImageAuthentication.h> | |
#include <Guid/TpmInstance.h> | |
#include <Protocol/DevicePath.h> | |
#include <Protocol/MpService.h> | |
#include <Protocol/VariableWrite.h> | |
#include <Protocol/Tcg2Protocol.h> | |
#include <Protocol/TrEEProtocol.h> | |
#include <Protocol/ResetNotification.h> | |
#include <Library/DebugLib.h> | |
#include <Library/BaseMemoryLib.h> | |
#include <Library/UefiRuntimeServicesTableLib.h> | |
#include <Library/UefiDriverEntryPoint.h> | |
#include <Library/HobLib.h> | |
#include <Library/UefiBootServicesTableLib.h> | |
#include <Library/BaseLib.h> | |
#include <Library/MemoryAllocationLib.h> | |
#include <Library/PrintLib.h> | |
#include <Library/Tpm2CommandLib.h> | |
#include <Library/PcdLib.h> | |
#include <Library/UefiLib.h> | |
#include <Library/Tpm2DeviceLib.h> | |
#include <Library/HashLib.h> | |
#include <Library/PerformanceLib.h> | |
#include <Library/ReportStatusCodeLib.h> | |
#include <Library/Tcg2PhysicalPresenceLib.h> | |
#define PERF_ID_TCG2_DXE 0x3120 | |
typedef struct { | |
CHAR16 *VariableName; | |
EFI_GUID *VendorGuid; | |
} VARIABLE_TYPE; | |
#define TCG2_DEFAULT_MAX_COMMAND_SIZE 0x1000 | |
#define TCG2_DEFAULT_MAX_RESPONSE_SIZE 0x1000 | |
typedef struct { | |
EFI_GUID *EventGuid; | |
EFI_TCG2_EVENT_LOG_FORMAT LogFormat; | |
} TCG2_EVENT_INFO_STRUCT; | |
TCG2_EVENT_INFO_STRUCT mTcg2EventInfo[] = { | |
{ &gTcgEventEntryHobGuid, EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2 }, | |
{ &gTcgEvent2EntryHobGuid, EFI_TCG2_EVENT_LOG_FORMAT_TCG_2 }, | |
}; | |
#define TCG_EVENT_LOG_AREA_COUNT_MAX 2 | |
typedef struct { | |
EFI_TCG2_EVENT_LOG_FORMAT EventLogFormat; | |
EFI_PHYSICAL_ADDRESS Lasa; | |
UINT64 Laml; | |
UINTN EventLogSize; | |
UINT8 *LastEvent; | |
BOOLEAN EventLogStarted; | |
BOOLEAN EventLogTruncated; | |
UINTN Next800155EventOffset; | |
} TCG_EVENT_LOG_AREA_STRUCT; | |
typedef struct _TCG_DXE_DATA { | |
EFI_TCG2_BOOT_SERVICE_CAPABILITY BsCap; | |
TCG_EVENT_LOG_AREA_STRUCT EventLogAreaStruct[TCG_EVENT_LOG_AREA_COUNT_MAX]; | |
BOOLEAN GetEventLogCalled[TCG_EVENT_LOG_AREA_COUNT_MAX]; | |
TCG_EVENT_LOG_AREA_STRUCT FinalEventLogAreaStruct[TCG_EVENT_LOG_AREA_COUNT_MAX]; | |
EFI_TCG2_FINAL_EVENTS_TABLE *FinalEventsTable[TCG_EVENT_LOG_AREA_COUNT_MAX]; | |
} TCG_DXE_DATA; | |
TCG_DXE_DATA mTcgDxeData = { | |
{ | |
sizeof (EFI_TCG2_BOOT_SERVICE_CAPABILITY), // Size | |
{ 1, 1 }, // StructureVersion | |
{ 1, 1 }, // ProtocolVersion | |
EFI_TCG2_BOOT_HASH_ALG_SHA1, // HashAlgorithmBitmap | |
EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2, // SupportedEventLogs | |
TRUE, // TPMPresentFlag | |
TCG2_DEFAULT_MAX_COMMAND_SIZE, // MaxCommandSize | |
TCG2_DEFAULT_MAX_RESPONSE_SIZE, // MaxResponseSize | |
0, // ManufacturerID | |
0, // NumberOfPCRBanks | |
0, // ActivePcrBanks | |
}, | |
}; | |
UINTN mBootAttempts = 0; | |
CHAR16 mBootVarName[] = L"BootOrder"; | |
VARIABLE_TYPE mVariableType[] = { | |
{ EFI_SECURE_BOOT_MODE_NAME, &gEfiGlobalVariableGuid }, | |
{ EFI_PLATFORM_KEY_NAME, &gEfiGlobalVariableGuid }, | |
{ EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid }, | |
{ EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid }, | |
{ EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid }, | |
}; | |
EFI_HANDLE mImageHandle; | |
/** | |
Measure PE image into TPM log based on the authenticode image hashing in | |
PE/COFF Specification 8.0 Appendix A. | |
Caution: This function may receive untrusted input. | |
PE/COFF image is external input, so this function will validate its data structure | |
within this image buffer before use. | |
Notes: PE/COFF image is checked by BasePeCoffLib PeCoffLoaderGetImageInfo(). | |
@param[in] PCRIndex TPM PCR index | |
@param[in] ImageAddress Start address of image buffer. | |
@param[in] ImageSize Image size | |
@param[out] DigestList Digest list of this image. | |
@retval EFI_SUCCESS Successfully measure image. | |
@retval EFI_OUT_OF_RESOURCES No enough resource to measure image. | |
@retval other error value | |
**/ | |
EFI_STATUS | |
MeasurePeImageAndExtend ( | |
IN UINT32 PCRIndex, | |
IN EFI_PHYSICAL_ADDRESS ImageAddress, | |
IN UINTN ImageSize, | |
OUT TPML_DIGEST_VALUES *DigestList | |
); | |
/** | |
This function dump raw data. | |
@param Data raw data | |
@param Size raw data size | |
**/ | |
VOID | |
InternalDumpData ( | |
IN UINT8 *Data, | |
IN UINTN Size | |
) | |
{ | |
UINTN Index; | |
for (Index = 0; Index < Size; Index++) { | |
DEBUG ((DEBUG_INFO, "%02x", (UINTN)Data[Index])); | |
} | |
} | |
/** | |
This function initialize TCG_PCR_EVENT2_HDR for EV_NO_ACTION Event Type other than EFI Specification ID event | |
The behavior is defined by TCG PC Client PFP Spec. Section 9.3.4 EV_NO_ACTION Event Types | |
@param[in, out] NoActionEvent Event Header of EV_NO_ACTION Event | |
@param[in] EventSize Event Size of the EV_NO_ACTION Event | |
**/ | |
VOID | |
InitNoActionEvent ( | |
IN OUT TCG_PCR_EVENT2_HDR *NoActionEvent, | |
IN UINT32 EventSize | |
) | |
{ | |
UINT32 DigestListCount; | |
TPMI_ALG_HASH HashAlgId; | |
UINT8 *DigestBuffer; | |
DigestBuffer = (UINT8 *)NoActionEvent->Digests.digests; | |
DigestListCount = 0; | |
NoActionEvent->PCRIndex = 0; | |
NoActionEvent->EventType = EV_NO_ACTION; | |
// | |
// Set Hash count & hashAlg accordingly, while Digest.digests[n].digest to all 0 | |
// | |
ZeroMem (&NoActionEvent->Digests, sizeof (NoActionEvent->Digests)); | |
if ((mTcgDxeData.BsCap.ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA1) != 0) { | |
HashAlgId = TPM_ALG_SHA1; | |
CopyMem (DigestBuffer, &HashAlgId, sizeof (TPMI_ALG_HASH)); | |
DigestBuffer += sizeof (TPMI_ALG_HASH) + GetHashSizeFromAlgo (HashAlgId); | |
DigestListCount++; | |
} | |
if ((mTcgDxeData.BsCap.ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA256) != 0) { | |
HashAlgId = TPM_ALG_SHA256; | |
CopyMem (DigestBuffer, &HashAlgId, sizeof (TPMI_ALG_HASH)); | |
DigestBuffer += sizeof (TPMI_ALG_HASH) + GetHashSizeFromAlgo (HashAlgId); | |
DigestListCount++; | |
} | |
if ((mTcgDxeData.BsCap.ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA384) != 0) { | |
HashAlgId = TPM_ALG_SHA384; | |
CopyMem (DigestBuffer, &HashAlgId, sizeof (TPMI_ALG_HASH)); | |
DigestBuffer += sizeof (TPMI_ALG_HASH) + GetHashSizeFromAlgo (HashAlgId); | |
DigestListCount++; | |
} | |
if ((mTcgDxeData.BsCap.ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA512) != 0) { | |
HashAlgId = TPM_ALG_SHA512; | |
CopyMem (DigestBuffer, &HashAlgId, sizeof (TPMI_ALG_HASH)); | |
DigestBuffer += sizeof (TPMI_ALG_HASH) + GetHashSizeFromAlgo (HashAlgId); | |
DigestListCount++; | |
} | |
if ((mTcgDxeData.BsCap.ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SM3_256) != 0) { | |
HashAlgId = TPM_ALG_SM3_256; | |
CopyMem (DigestBuffer, &HashAlgId, sizeof (TPMI_ALG_HASH)); | |
DigestBuffer += sizeof (TPMI_ALG_HASH) + GetHashSizeFromAlgo (HashAlgId); | |
DigestListCount++; | |
} | |
// | |
// Set Digests Count | |
// | |
WriteUnaligned32 ((UINT32 *)&NoActionEvent->Digests.count, DigestListCount); | |
// | |
// Set Event Size | |
// | |
WriteUnaligned32 ((UINT32 *)DigestBuffer, EventSize); | |
} | |
/** | |
This function dump raw data with colume format. | |
@param Data raw data | |
@param Size raw data size | |
**/ | |
VOID | |
InternalDumpHex ( | |
IN UINT8 *Data, | |
IN UINTN Size | |
) | |
{ | |
UINTN Index; | |
UINTN Count; | |
UINTN Left; | |
#define COLUME_SIZE (16 * 2) | |
Count = Size / COLUME_SIZE; | |
Left = Size % COLUME_SIZE; | |
for (Index = 0; Index < Count; Index++) { | |
DEBUG ((DEBUG_INFO, "%04x: ", Index * COLUME_SIZE)); | |
InternalDumpData (Data + Index * COLUME_SIZE, COLUME_SIZE); | |
DEBUG ((DEBUG_INFO, "\n")); | |
} | |
if (Left != 0) { | |
DEBUG ((DEBUG_INFO, "%04x: ", Index * COLUME_SIZE)); | |
InternalDumpData (Data + Index * COLUME_SIZE, Left); | |
DEBUG ((DEBUG_INFO, "\n")); | |
} | |
} | |
/** | |
Get All processors EFI_CPU_LOCATION in system. LocationBuf is allocated inside the function | |
Caller is responsible to free LocationBuf. | |
@param[out] LocationBuf Returns Processor Location Buffer. | |
@param[out] Num Returns processor number. | |
@retval EFI_SUCCESS Operation completed successfully. | |
@retval EFI_UNSUPPORTED MpService protocol not found. | |
**/ | |
EFI_STATUS | |
GetProcessorsCpuLocation ( | |
OUT EFI_CPU_PHYSICAL_LOCATION **LocationBuf, | |
OUT UINTN *Num | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_MP_SERVICES_PROTOCOL *MpProtocol; | |
UINTN ProcessorNum; | |
UINTN EnabledProcessorNum; | |
EFI_PROCESSOR_INFORMATION ProcessorInfo; | |
EFI_CPU_PHYSICAL_LOCATION *ProcessorLocBuf; | |
UINTN Index; | |
Status = gBS->LocateProtocol (&gEfiMpServiceProtocolGuid, NULL, (VOID **)&MpProtocol); | |
if (EFI_ERROR (Status)) { | |
// | |
// MP protocol is not installed | |
// | |
return EFI_UNSUPPORTED; | |
} | |
Status = MpProtocol->GetNumberOfProcessors ( | |
MpProtocol, | |
&ProcessorNum, | |
&EnabledProcessorNum | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
Status = gBS->AllocatePool ( | |
EfiBootServicesData, | |
sizeof (EFI_CPU_PHYSICAL_LOCATION) * ProcessorNum, | |
(VOID **)&ProcessorLocBuf | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
// | |
// Get each processor Location info | |
// | |
for (Index = 0; Index < ProcessorNum; Index++) { | |
Status = MpProtocol->GetProcessorInfo ( | |
MpProtocol, | |
Index, | |
&ProcessorInfo | |
); | |
if (EFI_ERROR (Status)) { | |
FreePool (ProcessorLocBuf); | |
return Status; | |
} | |
// | |
// Get all Processor Location info & measure | |
// | |
CopyMem ( | |
&ProcessorLocBuf[Index], | |
&ProcessorInfo.Location, | |
sizeof (EFI_CPU_PHYSICAL_LOCATION) | |
); | |
} | |
*LocationBuf = ProcessorLocBuf; | |
*Num = ProcessorNum; | |
return Status; | |
} | |
/** | |
The EFI_TCG2_PROTOCOL GetCapability function call provides protocol | |
capability information and state information. | |
@param[in] This Indicates the calling context | |
@param[in, out] ProtocolCapability The caller allocates memory for a EFI_TCG2_BOOT_SERVICE_CAPABILITY | |
structure and sets the size field to the size of the structure allocated. | |
The callee fills in the fields with the EFI protocol capability information | |
and the current EFI TCG2 state information up to the number of fields which | |
fit within the size of the structure passed in. | |
@retval EFI_SUCCESS Operation completed successfully. | |
@retval EFI_DEVICE_ERROR The command was unsuccessful. | |
The ProtocolCapability variable will not be populated. | |
@retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect. | |
The ProtocolCapability variable will not be populated. | |
@retval EFI_BUFFER_TOO_SMALL The ProtocolCapability variable is too small to hold the full response. | |
It will be partially populated (required Size field will be set). | |
**/ | |
EFI_STATUS | |
EFIAPI | |
Tcg2GetCapability ( | |
IN EFI_TCG2_PROTOCOL *This, | |
IN OUT EFI_TCG2_BOOT_SERVICE_CAPABILITY *ProtocolCapability | |
) | |
{ | |
DEBUG ((DEBUG_VERBOSE, "Tcg2GetCapability ...\n")); | |
if ((This == NULL) || (ProtocolCapability == NULL)) { | |
return EFI_INVALID_PARAMETER; | |
} | |
DEBUG ((DEBUG_VERBOSE, "Size - 0x%x\n", ProtocolCapability->Size)); | |
DEBUG ((DEBUG_VERBOSE, " 1.1 - 0x%x, 1.0 - 0x%x\n", sizeof (EFI_TCG2_BOOT_SERVICE_CAPABILITY), sizeof (TREE_BOOT_SERVICE_CAPABILITY_1_0))); | |
if (ProtocolCapability->Size < mTcgDxeData.BsCap.Size) { | |
// | |
// Handle the case that firmware support 1.1 but OS only support 1.0. | |
// | |
if ((mTcgDxeData.BsCap.ProtocolVersion.Major > 0x01) || | |
((mTcgDxeData.BsCap.ProtocolVersion.Major == 0x01) && ((mTcgDxeData.BsCap.ProtocolVersion.Minor > 0x00)))) | |
{ | |
if (ProtocolCapability->Size >= sizeof (TREE_BOOT_SERVICE_CAPABILITY_1_0)) { | |
CopyMem (ProtocolCapability, &mTcgDxeData.BsCap, sizeof (TREE_BOOT_SERVICE_CAPABILITY_1_0)); | |
ProtocolCapability->Size = sizeof (TREE_BOOT_SERVICE_CAPABILITY_1_0); | |
ProtocolCapability->StructureVersion.Major = 1; | |
ProtocolCapability->StructureVersion.Minor = 0; | |
ProtocolCapability->ProtocolVersion.Major = 1; | |
ProtocolCapability->ProtocolVersion.Minor = 0; | |
DEBUG ((DEBUG_ERROR, "TreeGetCapability (Compatible) - %r\n", EFI_SUCCESS)); | |
return EFI_SUCCESS; | |
} | |
} | |
ProtocolCapability->Size = mTcgDxeData.BsCap.Size; | |
return EFI_BUFFER_TOO_SMALL; | |
} | |
CopyMem (ProtocolCapability, &mTcgDxeData.BsCap, mTcgDxeData.BsCap.Size); | |
DEBUG ((DEBUG_VERBOSE, "Tcg2GetCapability - %r\n", EFI_SUCCESS)); | |
return EFI_SUCCESS; | |
} | |
/** | |
This function dump PCR event. | |
@param[in] EventHdr TCG PCR event structure. | |
**/ | |
VOID | |
DumpEvent ( | |
IN TCG_PCR_EVENT_HDR *EventHdr | |
) | |
{ | |
UINTN Index; | |
DEBUG ((DEBUG_INFO, " Event:\n")); | |
DEBUG ((DEBUG_INFO, " PCRIndex - %d\n", EventHdr->PCRIndex)); | |
DEBUG ((DEBUG_INFO, " EventType - 0x%08x\n", EventHdr->EventType)); | |
DEBUG ((DEBUG_INFO, " Digest - ")); | |
for (Index = 0; Index < sizeof (TCG_DIGEST); Index++) { | |
DEBUG ((DEBUG_INFO, "%02x ", EventHdr->Digest.digest[Index])); | |
} | |
DEBUG ((DEBUG_INFO, "\n")); | |
DEBUG ((DEBUG_INFO, " EventSize - 0x%08x\n", EventHdr->EventSize)); | |
InternalDumpHex ((UINT8 *)(EventHdr + 1), EventHdr->EventSize); | |
} | |
/** | |
This function dump TCG_EfiSpecIDEventStruct. | |
@param[in] TcgEfiSpecIdEventStruct A pointer to TCG_EfiSpecIDEventStruct. | |
**/ | |
VOID | |
DumpTcgEfiSpecIdEventStruct ( | |
IN TCG_EfiSpecIDEventStruct *TcgEfiSpecIdEventStruct | |
) | |
{ | |
TCG_EfiSpecIdEventAlgorithmSize *DigestSize; | |
UINTN Index; | |
UINT8 *VendorInfoSize; | |
UINT8 *VendorInfo; | |
UINT32 NumberOfAlgorithms; | |
DEBUG ((DEBUG_INFO, " TCG_EfiSpecIDEventStruct:\n")); | |
DEBUG ((DEBUG_INFO, " signature - '")); | |
for (Index = 0; Index < sizeof (TcgEfiSpecIdEventStruct->signature); Index++) { | |
DEBUG ((DEBUG_INFO, "%c", TcgEfiSpecIdEventStruct->signature[Index])); | |
} | |
DEBUG ((DEBUG_INFO, "'\n")); | |
DEBUG ((DEBUG_INFO, " platformClass - 0x%08x\n", TcgEfiSpecIdEventStruct->platformClass)); | |
DEBUG ((DEBUG_INFO, " specVersion - %d.%d%d\n", TcgEfiSpecIdEventStruct->specVersionMajor, TcgEfiSpecIdEventStruct->specVersionMinor, TcgEfiSpecIdEventStruct->specErrata)); | |
DEBUG ((DEBUG_INFO, " uintnSize - 0x%02x\n", TcgEfiSpecIdEventStruct->uintnSize)); | |
CopyMem (&NumberOfAlgorithms, TcgEfiSpecIdEventStruct + 1, sizeof (NumberOfAlgorithms)); | |
DEBUG ((DEBUG_INFO, " NumberOfAlgorithms - 0x%08x\n", NumberOfAlgorithms)); | |
DigestSize = (TCG_EfiSpecIdEventAlgorithmSize *)((UINT8 *)TcgEfiSpecIdEventStruct + sizeof (*TcgEfiSpecIdEventStruct) + sizeof (NumberOfAlgorithms)); | |
for (Index = 0; Index < NumberOfAlgorithms; Index++) { | |
DEBUG ((DEBUG_INFO, " digest(%d)\n", Index)); | |
DEBUG ((DEBUG_INFO, " algorithmId - 0x%04x\n", DigestSize[Index].algorithmId)); | |
DEBUG ((DEBUG_INFO, " digestSize - 0x%04x\n", DigestSize[Index].digestSize)); | |
} | |
VendorInfoSize = (UINT8 *)&DigestSize[NumberOfAlgorithms]; | |
DEBUG ((DEBUG_INFO, " VendorInfoSize - 0x%02x\n", *VendorInfoSize)); | |
VendorInfo = VendorInfoSize + 1; | |
DEBUG ((DEBUG_INFO, " VendorInfo - ")); | |
for (Index = 0; Index < *VendorInfoSize; Index++) { | |
DEBUG ((DEBUG_INFO, "%02x ", VendorInfo[Index])); | |
} | |
DEBUG ((DEBUG_INFO, "\n")); | |
} | |
/** | |
This function get size of TCG_EfiSpecIDEventStruct. | |
@param[in] TcgEfiSpecIdEventStruct A pointer to TCG_EfiSpecIDEventStruct. | |
**/ | |
UINTN | |
GetTcgEfiSpecIdEventStructSize ( | |
IN TCG_EfiSpecIDEventStruct *TcgEfiSpecIdEventStruct | |
) | |
{ | |
TCG_EfiSpecIdEventAlgorithmSize *DigestSize; | |
UINT8 *VendorInfoSize; | |
UINT32 NumberOfAlgorithms; | |
CopyMem (&NumberOfAlgorithms, TcgEfiSpecIdEventStruct + 1, sizeof (NumberOfAlgorithms)); | |
DigestSize = (TCG_EfiSpecIdEventAlgorithmSize *)((UINT8 *)TcgEfiSpecIdEventStruct + sizeof (*TcgEfiSpecIdEventStruct) + sizeof (NumberOfAlgorithms)); | |
VendorInfoSize = (UINT8 *)&DigestSize[NumberOfAlgorithms]; | |
return sizeof (TCG_EfiSpecIDEventStruct) + sizeof (UINT32) + (NumberOfAlgorithms * sizeof (TCG_EfiSpecIdEventAlgorithmSize)) + sizeof (UINT8) + (*VendorInfoSize); | |
} | |
/** | |
This function dump PCR event 2. | |
@param[in] TcgPcrEvent2 TCG PCR event 2 structure. | |
**/ | |
VOID | |
DumpEvent2 ( | |
IN TCG_PCR_EVENT2 *TcgPcrEvent2 | |
) | |
{ | |
UINTN Index; | |
UINT32 DigestIndex; | |
UINT32 DigestCount; | |
TPMI_ALG_HASH HashAlgo; | |
UINT32 DigestSize; | |
UINT8 *DigestBuffer; | |
UINT32 EventSize; | |
UINT8 *EventBuffer; | |
DEBUG ((DEBUG_INFO, " Event:\n")); | |
DEBUG ((DEBUG_INFO, " PCRIndex - %d\n", TcgPcrEvent2->PCRIndex)); | |
DEBUG ((DEBUG_INFO, " EventType - 0x%08x\n", TcgPcrEvent2->EventType)); | |
DEBUG ((DEBUG_INFO, " DigestCount: 0x%08x\n", TcgPcrEvent2->Digest.count)); | |
DigestCount = TcgPcrEvent2->Digest.count; | |
HashAlgo = TcgPcrEvent2->Digest.digests[0].hashAlg; | |
DigestBuffer = (UINT8 *)&TcgPcrEvent2->Digest.digests[0].digest; | |
for (DigestIndex = 0; DigestIndex < DigestCount; DigestIndex++) { | |
DEBUG ((DEBUG_INFO, " HashAlgo : 0x%04x\n", HashAlgo)); | |
DEBUG ((DEBUG_INFO, " Digest(%d): ", DigestIndex)); | |
DigestSize = GetHashSizeFromAlgo (HashAlgo); | |
for (Index = 0; Index < DigestSize; Index++) { | |
DEBUG ((DEBUG_INFO, "%02x ", DigestBuffer[Index])); | |
} | |
DEBUG ((DEBUG_INFO, "\n")); | |
// | |
// Prepare next | |
// | |
CopyMem (&HashAlgo, DigestBuffer + DigestSize, sizeof (TPMI_ALG_HASH)); | |
DigestBuffer = DigestBuffer + DigestSize + sizeof (TPMI_ALG_HASH); | |
} | |
DEBUG ((DEBUG_INFO, "\n")); | |
DigestBuffer = DigestBuffer - sizeof (TPMI_ALG_HASH); | |
CopyMem (&EventSize, DigestBuffer, sizeof (TcgPcrEvent2->EventSize)); | |
DEBUG ((DEBUG_INFO, " EventSize - 0x%08x\n", EventSize)); | |
EventBuffer = DigestBuffer + sizeof (TcgPcrEvent2->EventSize); | |
InternalDumpHex (EventBuffer, EventSize); | |
} | |
/** | |
This function returns size of TCG PCR event 2. | |
@param[in] TcgPcrEvent2 TCG PCR event 2 structure. | |
@return size of TCG PCR event 2. | |
**/ | |
UINTN | |
GetPcrEvent2Size ( | |
IN TCG_PCR_EVENT2 *TcgPcrEvent2 | |
) | |
{ | |
UINT32 DigestIndex; | |
UINT32 DigestCount; | |
TPMI_ALG_HASH HashAlgo; | |
UINT32 DigestSize; | |
UINT8 *DigestBuffer; | |
UINT32 EventSize; | |
UINT8 *EventBuffer; | |
DigestCount = TcgPcrEvent2->Digest.count; | |
HashAlgo = TcgPcrEvent2->Digest.digests[0].hashAlg; | |
DigestBuffer = (UINT8 *)&TcgPcrEvent2->Digest.digests[0].digest; | |
for (DigestIndex = 0; DigestIndex < DigestCount; DigestIndex++) { | |
DigestSize = GetHashSizeFromAlgo (HashAlgo); | |
// | |
// Prepare next | |
// | |
CopyMem (&HashAlgo, DigestBuffer + DigestSize, sizeof (TPMI_ALG_HASH)); | |
DigestBuffer = DigestBuffer + DigestSize + sizeof (TPMI_ALG_HASH); | |
} | |
DigestBuffer = DigestBuffer - sizeof (TPMI_ALG_HASH); | |
CopyMem (&EventSize, DigestBuffer, sizeof (TcgPcrEvent2->EventSize)); | |
EventBuffer = DigestBuffer + sizeof (TcgPcrEvent2->EventSize); | |
return (UINTN)EventBuffer + EventSize - (UINTN)TcgPcrEvent2; | |
} | |
/** | |
This function dump event log. | |
@param[in] EventLogFormat The type of the event log for which the information is requested. | |
@param[in] EventLogLocation A pointer to the memory address of the event log. | |
@param[in] EventLogLastEntry If the Event Log contains more than one entry, this is a pointer to the | |
address of the start of the last entry in the event log in memory. | |
@param[in] FinalEventsTable A pointer to the memory address of the final event table. | |
**/ | |
VOID | |
DumpEventLog ( | |
IN EFI_TCG2_EVENT_LOG_FORMAT EventLogFormat, | |
IN EFI_PHYSICAL_ADDRESS EventLogLocation, | |
IN EFI_PHYSICAL_ADDRESS EventLogLastEntry, | |
IN EFI_TCG2_FINAL_EVENTS_TABLE *FinalEventsTable | |
) | |
{ | |
TCG_PCR_EVENT_HDR *EventHdr; | |
TCG_PCR_EVENT2 *TcgPcrEvent2; | |
TCG_EfiSpecIDEventStruct *TcgEfiSpecIdEventStruct; | |
UINTN NumberOfEvents; | |
DEBUG ((DEBUG_INFO, "EventLogFormat: (0x%x)\n", EventLogFormat)); | |
switch (EventLogFormat) { | |
case EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2: | |
EventHdr = (TCG_PCR_EVENT_HDR *)(UINTN)EventLogLocation; | |
while ((UINTN)EventHdr <= EventLogLastEntry) { | |
DumpEvent (EventHdr); | |
EventHdr = (TCG_PCR_EVENT_HDR *)((UINTN)EventHdr + sizeof (TCG_PCR_EVENT_HDR) + EventHdr->EventSize); | |
} | |
if (FinalEventsTable == NULL) { | |
DEBUG ((DEBUG_INFO, "FinalEventsTable: NOT FOUND\n")); | |
} else { | |
DEBUG ((DEBUG_INFO, "FinalEventsTable: (0x%x)\n", FinalEventsTable)); | |
DEBUG ((DEBUG_INFO, " Version: (0x%x)\n", FinalEventsTable->Version)); | |
DEBUG ((DEBUG_INFO, " NumberOfEvents: (0x%x)\n", FinalEventsTable->NumberOfEvents)); | |
EventHdr = (TCG_PCR_EVENT_HDR *)(UINTN)(FinalEventsTable + 1); | |
for (NumberOfEvents = 0; NumberOfEvents < FinalEventsTable->NumberOfEvents; NumberOfEvents++) { | |
DumpEvent (EventHdr); | |
EventHdr = (TCG_PCR_EVENT_HDR *)((UINTN)EventHdr + sizeof (TCG_PCR_EVENT_HDR) + EventHdr->EventSize); | |
} | |
} | |
break; | |
case EFI_TCG2_EVENT_LOG_FORMAT_TCG_2: | |
// | |
// Dump first event | |
// | |
EventHdr = (TCG_PCR_EVENT_HDR *)(UINTN)EventLogLocation; | |
DumpEvent (EventHdr); | |
TcgEfiSpecIdEventStruct = (TCG_EfiSpecIDEventStruct *)(EventHdr + 1); | |
DumpTcgEfiSpecIdEventStruct (TcgEfiSpecIdEventStruct); | |
TcgPcrEvent2 = (TCG_PCR_EVENT2 *)((UINTN)TcgEfiSpecIdEventStruct + GetTcgEfiSpecIdEventStructSize (TcgEfiSpecIdEventStruct)); | |
while ((UINTN)TcgPcrEvent2 <= EventLogLastEntry) { | |
DumpEvent2 (TcgPcrEvent2); | |
TcgPcrEvent2 = (TCG_PCR_EVENT2 *)((UINTN)TcgPcrEvent2 + GetPcrEvent2Size (TcgPcrEvent2)); | |
} | |
if (FinalEventsTable == NULL) { | |
DEBUG ((DEBUG_INFO, "FinalEventsTable: NOT FOUND\n")); | |
} else { | |
DEBUG ((DEBUG_INFO, "FinalEventsTable: (0x%x)\n", FinalEventsTable)); | |
DEBUG ((DEBUG_INFO, " Version: (0x%x)\n", FinalEventsTable->Version)); | |
DEBUG ((DEBUG_INFO, " NumberOfEvents: (0x%x)\n", FinalEventsTable->NumberOfEvents)); | |
TcgPcrEvent2 = (TCG_PCR_EVENT2 *)(UINTN)(FinalEventsTable + 1); | |
for (NumberOfEvents = 0; NumberOfEvents < FinalEventsTable->NumberOfEvents; NumberOfEvents++) { | |
DumpEvent2 (TcgPcrEvent2); | |
TcgPcrEvent2 = (TCG_PCR_EVENT2 *)((UINTN)TcgPcrEvent2 + GetPcrEvent2Size (TcgPcrEvent2)); | |
} | |
} | |
break; | |
} | |
return; | |
} | |
/** | |
The EFI_TCG2_PROTOCOL Get Event Log function call allows a caller to | |
retrieve the address of a given event log and its last entry. | |
@param[in] This Indicates the calling context | |
@param[in] EventLogFormat The type of the event log for which the information is requested. | |
@param[out] EventLogLocation A pointer to the memory address of the event log. | |
@param[out] EventLogLastEntry If the Event Log contains more than one entry, this is a pointer to the | |
address of the start of the last entry in the event log in memory. | |
@param[out] EventLogTruncated If the Event Log is missing at least one entry because an event would | |
have exceeded the area allocated for events, this value is set to TRUE. | |
Otherwise, the value will be FALSE and the Event Log will be complete. | |
@retval EFI_SUCCESS Operation completed successfully. | |
@retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect | |
(e.g. asking for an event log whose format is not supported). | |
**/ | |
EFI_STATUS | |
EFIAPI | |
Tcg2GetEventLog ( | |
IN EFI_TCG2_PROTOCOL *This, | |
IN EFI_TCG2_EVENT_LOG_FORMAT EventLogFormat, | |
OUT EFI_PHYSICAL_ADDRESS *EventLogLocation, | |
OUT EFI_PHYSICAL_ADDRESS *EventLogLastEntry, | |
OUT BOOLEAN *EventLogTruncated | |
) | |
{ | |
UINTN Index; | |
DEBUG ((DEBUG_INFO, "Tcg2GetEventLog ... (0x%x)\n", EventLogFormat)); | |
if (This == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
for (Index = 0; Index < sizeof (mTcg2EventInfo)/sizeof (mTcg2EventInfo[0]); Index++) { | |
if (EventLogFormat == mTcg2EventInfo[Index].LogFormat) { | |
break; | |
} | |
} | |
if (Index == sizeof (mTcg2EventInfo)/sizeof (mTcg2EventInfo[0])) { | |
return EFI_INVALID_PARAMETER; | |
} | |
if ((mTcg2EventInfo[Index].LogFormat & mTcgDxeData.BsCap.SupportedEventLogs) == 0) { | |
return EFI_INVALID_PARAMETER; | |
} | |
if (!mTcgDxeData.BsCap.TPMPresentFlag) { | |
if (EventLogLocation != NULL) { | |
*EventLogLocation = 0; | |
} | |
if (EventLogLastEntry != NULL) { | |
*EventLogLastEntry = 0; | |
} | |
if (EventLogTruncated != NULL) { | |
*EventLogTruncated = FALSE; | |
} | |
return EFI_SUCCESS; | |
} | |
if (EventLogLocation != NULL) { | |
*EventLogLocation = mTcgDxeData.EventLogAreaStruct[Index].Lasa; | |
DEBUG ((DEBUG_INFO, "Tcg2GetEventLog (EventLogLocation - %x)\n", *EventLogLocation)); | |
} | |
if (EventLogLastEntry != NULL) { | |
if (!mTcgDxeData.EventLogAreaStruct[Index].EventLogStarted) { | |
*EventLogLastEntry = (EFI_PHYSICAL_ADDRESS)(UINTN)0; | |
} else { | |
*EventLogLastEntry = (EFI_PHYSICAL_ADDRESS)(UINTN)mTcgDxeData.EventLogAreaStruct[Index].LastEvent; | |
} | |
DEBUG ((DEBUG_INFO, "Tcg2GetEventLog (EventLogLastEntry - %x)\n", *EventLogLastEntry)); | |
} | |
if (EventLogTruncated != NULL) { | |
*EventLogTruncated = mTcgDxeData.EventLogAreaStruct[Index].EventLogTruncated; | |
DEBUG ((DEBUG_INFO, "Tcg2GetEventLog (EventLogTruncated - %x)\n", *EventLogTruncated)); | |
} | |
DEBUG ((DEBUG_INFO, "Tcg2GetEventLog - %r\n", EFI_SUCCESS)); | |
// Dump Event Log for debug purpose | |
if ((EventLogLocation != NULL) && (EventLogLastEntry != NULL)) { | |
DumpEventLog (EventLogFormat, *EventLogLocation, *EventLogLastEntry, mTcgDxeData.FinalEventsTable[Index]); | |
} | |
// | |
// All events generated after the invocation of EFI_TCG2_GET_EVENT_LOG SHALL be stored | |
// in an instance of an EFI_CONFIGURATION_TABLE named by the VendorGuid of EFI_TCG2_FINAL_EVENTS_TABLE_GUID. | |
// | |
mTcgDxeData.GetEventLogCalled[Index] = TRUE; | |
return EFI_SUCCESS; | |
} | |
/** | |
Return if this is a Tcg800155PlatformIdEvent. | |
@param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR/TCG_PCR_EVENT_EX data structure. | |
@param[in] NewEventHdrSize New event header size. | |
@param[in] NewEventData Pointer to the new event data. | |
@param[in] NewEventSize New event data size. | |
@retval TRUE This is a Tcg800155PlatformIdEvent. | |
@retval FALSE This is NOT a Tcg800155PlatformIdEvent. | |
**/ | |
BOOLEAN | |
Is800155Event ( | |
IN VOID *NewEventHdr, | |
IN UINT32 NewEventHdrSize, | |
IN UINT8 *NewEventData, | |
IN UINT32 NewEventSize | |
) | |
{ | |
if ((((TCG_PCR_EVENT2_HDR *)NewEventHdr)->EventType == EV_NO_ACTION) && | |
(NewEventSize >= sizeof (TCG_Sp800_155_PlatformId_Event2)) && | |
(CompareMem ( | |
NewEventData, | |
TCG_Sp800_155_PlatformId_Event2_SIGNATURE, | |
sizeof (TCG_Sp800_155_PlatformId_Event2_SIGNATURE) - 1 | |
) == 0)) | |
{ | |
return TRUE; | |
} | |
return FALSE; | |
} | |
/** | |
Add a new entry to the Event Log. | |
@param[in, out] EventLogAreaStruct The event log area data structure | |
@param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR/TCG_PCR_EVENT_EX data structure. | |
@param[in] NewEventHdrSize New event header size. | |
@param[in] NewEventData Pointer to the new event data. | |
@param[in] NewEventSize New event data size. | |
@retval EFI_SUCCESS The new event log entry was added. | |
@retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. | |
**/ | |
EFI_STATUS | |
TcgCommLogEvent ( | |
IN OUT TCG_EVENT_LOG_AREA_STRUCT *EventLogAreaStruct, | |
IN VOID *NewEventHdr, | |
IN UINT32 NewEventHdrSize, | |
IN UINT8 *NewEventData, | |
IN UINT32 NewEventSize | |
) | |
{ | |
UINTN NewLogSize; | |
BOOLEAN Record800155Event; | |
if (NewEventSize > MAX_ADDRESS - NewEventHdrSize) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
NewLogSize = NewEventHdrSize + NewEventSize; | |
if (NewLogSize > MAX_ADDRESS - EventLogAreaStruct->EventLogSize) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
if (NewLogSize + EventLogAreaStruct->EventLogSize > EventLogAreaStruct->Laml) { | |
DEBUG ((DEBUG_INFO, " Laml - 0x%x\n", EventLogAreaStruct->Laml)); | |
DEBUG ((DEBUG_INFO, " NewLogSize - 0x%x\n", NewLogSize)); | |
DEBUG ((DEBUG_INFO, " LogSize - 0x%x\n", EventLogAreaStruct->EventLogSize)); | |
DEBUG ((DEBUG_INFO, "TcgCommLogEvent - %r\n", EFI_OUT_OF_RESOURCES)); | |
return EFI_OUT_OF_RESOURCES; | |
} | |
// | |
// Check 800-155 event | |
// Record to 800-155 event offset only. | |
// If the offset is 0, no need to record. | |
// | |
Record800155Event = Is800155Event (NewEventHdr, NewEventHdrSize, NewEventData, NewEventSize); | |
if (Record800155Event) { | |
if (EventLogAreaStruct->Next800155EventOffset != 0) { | |
CopyMem ( | |
(UINT8 *)(UINTN)EventLogAreaStruct->Lasa + EventLogAreaStruct->Next800155EventOffset + NewLogSize, | |
(UINT8 *)(UINTN)EventLogAreaStruct->Lasa + EventLogAreaStruct->Next800155EventOffset, | |
EventLogAreaStruct->EventLogSize - EventLogAreaStruct->Next800155EventOffset | |
); | |
CopyMem ( | |
(UINT8 *)(UINTN)EventLogAreaStruct->Lasa + EventLogAreaStruct->Next800155EventOffset, | |
NewEventHdr, | |
NewEventHdrSize | |
); | |
CopyMem ( | |
(UINT8 *)(UINTN)EventLogAreaStruct->Lasa + EventLogAreaStruct->Next800155EventOffset + NewEventHdrSize, | |
NewEventData, | |
NewEventSize | |
); | |
EventLogAreaStruct->Next800155EventOffset += NewLogSize; | |
EventLogAreaStruct->LastEvent += NewLogSize; | |
EventLogAreaStruct->EventLogSize += NewLogSize; | |
} | |
return EFI_SUCCESS; | |
} | |
EventLogAreaStruct->LastEvent = (UINT8 *)(UINTN)EventLogAreaStruct->Lasa + EventLogAreaStruct->EventLogSize; | |
EventLogAreaStruct->EventLogSize += NewLogSize; | |
CopyMem (EventLogAreaStruct->LastEvent, NewEventHdr, NewEventHdrSize); | |
CopyMem ( | |
EventLogAreaStruct->LastEvent + NewEventHdrSize, | |
NewEventData, | |
NewEventSize | |
); | |
return EFI_SUCCESS; | |
} | |
/** | |
Add a new entry to the Event Log. | |
@param[in] EventLogFormat The type of the event log for which the information is requested. | |
@param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR/TCG_PCR_EVENT_EX data structure. | |
@param[in] NewEventHdrSize New event header size. | |
@param[in] NewEventData Pointer to the new event data. | |
@param[in] NewEventSize New event data size. | |
@retval EFI_SUCCESS The new event log entry was added. | |
@retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. | |
**/ | |
EFI_STATUS | |
TcgDxeLogEvent ( | |
IN EFI_TCG2_EVENT_LOG_FORMAT EventLogFormat, | |
IN VOID *NewEventHdr, | |
IN UINT32 NewEventHdrSize, | |
IN UINT8 *NewEventData, | |
IN UINT32 NewEventSize | |
) | |
{ | |
EFI_STATUS Status; | |
UINTN Index; | |
TCG_EVENT_LOG_AREA_STRUCT *EventLogAreaStruct; | |
for (Index = 0; Index < sizeof (mTcg2EventInfo)/sizeof (mTcg2EventInfo[0]); Index++) { | |
if (EventLogFormat == mTcg2EventInfo[Index].LogFormat) { | |
break; | |
} | |
} | |
if (Index == sizeof (mTcg2EventInfo)/sizeof (mTcg2EventInfo[0])) { | |
return EFI_INVALID_PARAMETER; | |
} | |
// | |
// Record to normal event log | |
// | |
EventLogAreaStruct = &mTcgDxeData.EventLogAreaStruct[Index]; | |
if (EventLogAreaStruct->EventLogTruncated) { | |
return EFI_VOLUME_FULL; | |
} | |
Status = TcgCommLogEvent ( | |
EventLogAreaStruct, | |
NewEventHdr, | |
NewEventHdrSize, | |
NewEventData, | |
NewEventSize | |
); | |
if (Status == EFI_OUT_OF_RESOURCES) { | |
EventLogAreaStruct->EventLogTruncated = TRUE; | |
return EFI_VOLUME_FULL; | |
} else if (Status == EFI_SUCCESS) { | |
EventLogAreaStruct->EventLogStarted = TRUE; | |
} | |
// | |
// If GetEventLog is called, record to FinalEventsTable, too. | |
// | |
if (mTcgDxeData.GetEventLogCalled[Index]) { | |
if (mTcgDxeData.FinalEventsTable[Index] == NULL) { | |
// | |
// no need for FinalEventsTable | |
// | |
return EFI_SUCCESS; | |
} | |
EventLogAreaStruct = &mTcgDxeData.FinalEventLogAreaStruct[Index]; | |
if (EventLogAreaStruct->EventLogTruncated) { | |
return EFI_VOLUME_FULL; | |
} | |
Status = TcgCommLogEvent ( | |
EventLogAreaStruct, | |
NewEventHdr, | |
NewEventHdrSize, | |
NewEventData, | |
NewEventSize | |
); | |
if (Status == EFI_OUT_OF_RESOURCES) { | |
EventLogAreaStruct->EventLogTruncated = TRUE; | |
return EFI_VOLUME_FULL; | |
} else if (Status == EFI_SUCCESS) { | |
EventLogAreaStruct->EventLogStarted = TRUE; | |
// | |
// Increase the NumberOfEvents in FinalEventsTable | |
// | |
(mTcgDxeData.FinalEventsTable[Index])->NumberOfEvents++; | |
DEBUG ((DEBUG_INFO, "FinalEventsTable->NumberOfEvents - 0x%x\n", (mTcgDxeData.FinalEventsTable[Index])->NumberOfEvents)); | |
DEBUG ((DEBUG_INFO, " Size - 0x%x\n", (UINTN)EventLogAreaStruct->EventLogSize)); | |
} | |
} | |
return Status; | |
} | |
/** | |
Get TPML_DIGEST_VALUES compact binary buffer size. | |
@param[in] DigestListBin TPML_DIGEST_VALUES compact binary buffer. | |
@return TPML_DIGEST_VALUES compact binary buffer size. | |
**/ | |
UINT32 | |
GetDigestListBinSize ( | |
IN VOID *DigestListBin | |
) | |
{ | |
UINTN Index; | |
UINT16 DigestSize; | |
UINT32 TotalSize; | |
UINT32 Count; | |
TPMI_ALG_HASH HashAlg; | |
Count = ReadUnaligned32 (DigestListBin); | |
TotalSize = sizeof (Count); | |
DigestListBin = (UINT8 *)DigestListBin + sizeof (Count); | |
for (Index = 0; Index < Count; Index++) { | |
HashAlg = ReadUnaligned16 (DigestListBin); | |
TotalSize += sizeof (HashAlg); | |
DigestListBin = (UINT8 *)DigestListBin + sizeof (HashAlg); | |
DigestSize = GetHashSizeFromAlgo (HashAlg); | |
TotalSize += DigestSize; | |
DigestListBin = (UINT8 *)DigestListBin + DigestSize; | |
} | |
return TotalSize; | |
} | |
/** | |
Copy TPML_DIGEST_VALUES compact binary into a buffer | |
@param[in,out] Buffer Buffer to hold copied TPML_DIGEST_VALUES compact binary. | |
@param[in] DigestListBin TPML_DIGEST_VALUES compact binary buffer. | |
@param[in] HashAlgorithmMask HASH bits corresponding to the desired digests to copy. | |
@param[out] HashAlgorithmMaskCopied Pointer to HASH bits corresponding to the digests copied. | |
@return The end of buffer to hold TPML_DIGEST_VALUES compact binary. | |
**/ | |
VOID * | |
CopyDigestListBinToBuffer ( | |
IN OUT VOID *Buffer, | |
IN VOID *DigestListBin, | |
IN UINT32 HashAlgorithmMask, | |
OUT UINT32 *HashAlgorithmMaskCopied | |
) | |
{ | |
UINTN Index; | |
UINT16 DigestSize; | |
UINT32 Count; | |
TPMI_ALG_HASH HashAlg; | |
UINT32 DigestListCount; | |
UINT32 *DigestListCountPtr; | |
DigestListCountPtr = (UINT32 *)Buffer; | |
DigestListCount = 0; | |
(*HashAlgorithmMaskCopied) = 0; | |
Count = ReadUnaligned32 (DigestListBin); | |
Buffer = (UINT8 *)Buffer + sizeof (Count); | |
DigestListBin = (UINT8 *)DigestListBin + sizeof (Count); | |
for (Index = 0; Index < Count; Index++) { | |
HashAlg = ReadUnaligned16 (DigestListBin); | |
DigestListBin = (UINT8 *)DigestListBin + sizeof (HashAlg); | |
DigestSize = GetHashSizeFromAlgo (HashAlg); | |
if (IsHashAlgSupportedInHashAlgorithmMask (HashAlg, HashAlgorithmMask)) { | |
CopyMem (Buffer, &HashAlg, sizeof (HashAlg)); | |
Buffer = (UINT8 *)Buffer + sizeof (HashAlg); | |
CopyMem (Buffer, DigestListBin, DigestSize); | |
Buffer = (UINT8 *)Buffer + DigestSize; | |
DigestListCount++; | |
(*HashAlgorithmMaskCopied) |= GetHashMaskFromAlgo (HashAlg); | |
} else { | |
DEBUG ((DEBUG_ERROR, "WARNING: CopyDigestListBinToBuffer Event log has HashAlg unsupported by PCR bank (0x%x)\n", HashAlg)); | |
} | |
DigestListBin = (UINT8 *)DigestListBin + DigestSize; | |
} | |
WriteUnaligned32 (DigestListCountPtr, DigestListCount); | |
return Buffer; | |
} | |
/** | |
Add a new entry to the Event Log. | |
@param[in] DigestList A list of digest. | |
@param[in,out] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure. | |
@param[in] NewEventData Pointer to the new event data. | |
@retval EFI_SUCCESS The new event log entry was added. | |
@retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. | |
**/ | |
EFI_STATUS | |
TcgDxeLogHashEvent ( | |
IN TPML_DIGEST_VALUES *DigestList, | |
IN OUT TCG_PCR_EVENT_HDR *NewEventHdr, | |
IN UINT8 *NewEventData | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_TPL OldTpl; | |
UINTN Index; | |
EFI_STATUS RetStatus; | |
TCG_PCR_EVENT2 TcgPcrEvent2; | |
UINT8 *DigestBuffer; | |
UINT32 *EventSizePtr; | |
DEBUG ((DEBUG_INFO, "SupportedEventLogs - 0x%08x\n", mTcgDxeData.BsCap.SupportedEventLogs)); | |
RetStatus = EFI_SUCCESS; | |
for (Index = 0; Index < sizeof (mTcg2EventInfo)/sizeof (mTcg2EventInfo[0]); Index++) { | |
if ((mTcgDxeData.BsCap.SupportedEventLogs & mTcg2EventInfo[Index].LogFormat) != 0) { | |
DEBUG ((DEBUG_INFO, " LogFormat - 0x%08x\n", mTcg2EventInfo[Index].LogFormat)); | |
switch (mTcg2EventInfo[Index].LogFormat) { | |
case EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2: | |
Status = GetDigestFromDigestList (TPM_ALG_SHA1, DigestList, &NewEventHdr->Digest); | |
if (!EFI_ERROR (Status)) { | |
// | |
// Enter critical region | |
// | |
OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); | |
Status = TcgDxeLogEvent ( | |
mTcg2EventInfo[Index].LogFormat, | |
NewEventHdr, | |
sizeof (TCG_PCR_EVENT_HDR), | |
NewEventData, | |
NewEventHdr->EventSize | |
); | |
if (Status != EFI_SUCCESS) { | |
RetStatus = Status; | |
} | |
gBS->RestoreTPL (OldTpl); | |
// | |
// Exit critical region | |
// | |
} | |
break; | |
case EFI_TCG2_EVENT_LOG_FORMAT_TCG_2: | |
ZeroMem (&TcgPcrEvent2, sizeof (TcgPcrEvent2)); | |
TcgPcrEvent2.PCRIndex = NewEventHdr->PCRIndex; | |
TcgPcrEvent2.EventType = NewEventHdr->EventType; | |
DigestBuffer = (UINT8 *)&TcgPcrEvent2.Digest; | |
EventSizePtr = CopyDigestListToBuffer (DigestBuffer, DigestList, mTcgDxeData.BsCap.ActivePcrBanks); | |
CopyMem (EventSizePtr, &NewEventHdr->EventSize, sizeof (NewEventHdr->EventSize)); | |
// | |
// Enter critical region | |
// | |
OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); | |
Status = TcgDxeLogEvent ( | |
mTcg2EventInfo[Index].LogFormat, | |
&TcgPcrEvent2, | |
sizeof (TcgPcrEvent2.PCRIndex) + sizeof (TcgPcrEvent2.EventType) + GetDigestListBinSize (DigestBuffer) + sizeof (TcgPcrEvent2.EventSize), | |
NewEventData, | |
NewEventHdr->EventSize | |
); | |
if (Status != EFI_SUCCESS) { | |
RetStatus = Status; | |
} | |
gBS->RestoreTPL (OldTpl); | |
// | |
// Exit critical region | |
// | |
break; | |
} | |
} | |
} | |
return RetStatus; | |
} | |
/** | |
Do a hash operation on a data buffer, extend a specific TPM PCR with the hash result, | |
and add an entry to the Event Log. | |
@param[in] Flags Bitmap providing additional information. | |
@param[in] HashData Physical address of the start of the data buffer | |
to be hashed, extended, and logged. | |
@param[in] HashDataLen The length, in bytes, of the buffer referenced by HashData | |
@param[in, out] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure. | |
@param[in] NewEventData Pointer to the new event data. | |
@retval EFI_SUCCESS Operation completed successfully. | |
@retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. | |
@retval EFI_DEVICE_ERROR The command was unsuccessful. | |
**/ | |
EFI_STATUS | |
TcgDxeHashLogExtendEvent ( | |
IN UINT64 Flags, | |
IN UINT8 *HashData, | |
IN UINT64 HashDataLen, | |
IN OUT TCG_PCR_EVENT_HDR *NewEventHdr, | |
IN UINT8 *NewEventData | |
) | |
{ | |
EFI_STATUS Status; | |
TPML_DIGEST_VALUES DigestList; | |
TCG_PCR_EVENT2_HDR NoActionEvent; | |
if (!mTcgDxeData.BsCap.TPMPresentFlag) { | |
return EFI_DEVICE_ERROR; | |
} | |
if (NewEventHdr->EventType == EV_NO_ACTION) { | |
// | |
// Do not do TPM extend for EV_NO_ACTION | |
// | |
Status = EFI_SUCCESS; | |
InitNoActionEvent (&NoActionEvent, NewEventHdr->EventSize); | |
if ((Flags & EFI_TCG2_EXTEND_ONLY) == 0) { | |
Status = TcgDxeLogHashEvent (&(NoActionEvent.Digests), NewEventHdr, NewEventData); | |
} | |
return Status; | |
} | |
Status = HashAndExtend ( | |
NewEventHdr->PCRIndex, | |
HashData, | |
(UINTN)HashDataLen, | |
&DigestList | |
); | |
if (!EFI_ERROR (Status)) { | |
if ((Flags & EFI_TCG2_EXTEND_ONLY) == 0) { | |
Status = TcgDxeLogHashEvent (&DigestList, NewEventHdr, NewEventData); | |
} | |
} | |
if (Status == EFI_DEVICE_ERROR) { | |
DEBUG ((DEBUG_ERROR, "TcgDxeHashLogExtendEvent - %r. Disable TPM.\n", Status)); | |
mTcgDxeData.BsCap.TPMPresentFlag = FALSE; | |
REPORT_STATUS_CODE ( | |
EFI_ERROR_CODE | EFI_ERROR_MINOR, | |
(PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR) | |
); | |
} | |
return Status; | |
} | |
/** | |
The EFI_TCG2_PROTOCOL HashLogExtendEvent function call provides callers with | |
an opportunity to extend and optionally log events without requiring | |
knowledge of actual TPM commands. | |
The extend operation will occur even if this function cannot create an event | |
log entry (e.g. due to the event log being full). | |
@param[in] This Indicates the calling context | |
@param[in] Flags Bitmap providing additional information. | |
@param[in] DataToHash Physical address of the start of the data buffer to be hashed. | |
@param[in] DataToHashLen The length in bytes of the buffer referenced by DataToHash. | |
@param[in] Event Pointer to data buffer containing information about the event. | |
@retval EFI_SUCCESS Operation completed successfully. | |
@retval EFI_DEVICE_ERROR The command was unsuccessful. | |
@retval EFI_VOLUME_FULL The extend operation occurred, but the event could not be written to one or more event logs. | |
@retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect. | |
@retval EFI_UNSUPPORTED The PE/COFF image type is not supported. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
Tcg2HashLogExtendEvent ( | |
IN EFI_TCG2_PROTOCOL *This, | |
IN UINT64 Flags, | |
IN EFI_PHYSICAL_ADDRESS DataToHash, | |
IN UINT64 DataToHashLen, | |
IN EFI_TCG2_EVENT *Event | |
) | |
{ | |
EFI_STATUS Status; | |
TCG_PCR_EVENT_HDR NewEventHdr; | |
TPML_DIGEST_VALUES DigestList; | |
DEBUG ((DEBUG_VERBOSE, "Tcg2HashLogExtendEvent ...\n")); | |
if ((This == NULL) || (Event == NULL)) { | |
return EFI_INVALID_PARAMETER; | |
} | |
// | |
// Do not check hash data size for EV_NO_ACTION event. | |
// | |
if ((Event->Header.EventType != EV_NO_ACTION) && (DataToHash == 0)) { | |
return EFI_INVALID_PARAMETER; | |
} | |
if (!mTcgDxeData.BsCap.TPMPresentFlag) { | |
return EFI_DEVICE_ERROR; | |
} | |
if (Event->Size < Event->Header.HeaderSize + sizeof (UINT32)) { | |
return EFI_INVALID_PARAMETER; | |
} | |
if (Event->Header.PCRIndex > MAX_PCR_INDEX) { | |
return EFI_INVALID_PARAMETER; | |
} | |
NewEventHdr.PCRIndex = Event->Header.PCRIndex; | |
NewEventHdr.EventType = Event->Header.EventType; | |
NewEventHdr.EventSize = Event->Size - sizeof (UINT32) - Event->Header.HeaderSize; | |
if ((Flags & PE_COFF_IMAGE) != 0) { | |
Status = MeasurePeImageAndExtend ( | |
NewEventHdr.PCRIndex, | |
DataToHash, | |
(UINTN)DataToHashLen, | |
&DigestList | |
); | |
if (!EFI_ERROR (Status)) { | |
if ((Flags & EFI_TCG2_EXTEND_ONLY) == 0) { | |
Status = TcgDxeLogHashEvent (&DigestList, &NewEventHdr, Event->Event); | |
} | |
} | |
if (Status == EFI_DEVICE_ERROR) { | |
DEBUG ((DEBUG_ERROR, "MeasurePeImageAndExtend - %r. Disable TPM.\n", Status)); | |
mTcgDxeData.BsCap.TPMPresentFlag = FALSE; | |
REPORT_STATUS_CODE ( | |
EFI_ERROR_CODE | EFI_ERROR_MINOR, | |
(PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR) | |
); | |
} | |
} else { | |
Status = TcgDxeHashLogExtendEvent ( | |
Flags, | |
(UINT8 *)(UINTN)DataToHash, | |
DataToHashLen, | |
&NewEventHdr, | |
Event->Event | |
); | |
} | |
DEBUG ((DEBUG_VERBOSE, "Tcg2HashLogExtendEvent - %r\n", Status)); | |
return Status; | |
} | |
/** | |
This service enables the sending of commands to the TPM. | |
@param[in] This Indicates the calling context | |
@param[in] InputParameterBlockSize Size of the TPM input parameter block. | |
@param[in] InputParameterBlock Pointer to the TPM input parameter block. | |
@param[in] OutputParameterBlockSize Size of the TPM output parameter block. | |
@param[in] OutputParameterBlock Pointer to the TPM output parameter block. | |
@retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received. | |
@retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device. | |
@retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect. | |
@retval EFI_BUFFER_TOO_SMALL The output parameter block is too small. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
Tcg2SubmitCommand ( | |
IN EFI_TCG2_PROTOCOL *This, | |
IN UINT32 InputParameterBlockSize, | |
IN UINT8 *InputParameterBlock, | |
IN UINT32 OutputParameterBlockSize, | |
IN UINT8 *OutputParameterBlock | |
) | |
{ | |
EFI_STATUS Status; | |
DEBUG ((DEBUG_INFO, "Tcg2SubmitCommand ...\n")); | |
if ((This == NULL) || | |
(InputParameterBlockSize == 0) || (InputParameterBlock == NULL) || | |
(OutputParameterBlockSize == 0) || (OutputParameterBlock == NULL)) | |
{ | |
return EFI_INVALID_PARAMETER; | |
} | |
if (!mTcgDxeData.BsCap.TPMPresentFlag) { | |
return EFI_DEVICE_ERROR; | |
} | |
if (InputParameterBlockSize > mTcgDxeData.BsCap.MaxCommandSize) { | |
return EFI_INVALID_PARAMETER; | |
} | |
if (OutputParameterBlockSize > mTcgDxeData.BsCap.MaxResponseSize) { | |
return EFI_INVALID_PARAMETER; | |
} | |
Status = Tpm2SubmitCommand ( | |
InputParameterBlockSize, | |
InputParameterBlock, | |
&OutputParameterBlockSize, | |
OutputParameterBlock | |
); | |
DEBUG ((DEBUG_INFO, "Tcg2SubmitCommand - %r\n", Status)); | |
return Status; | |
} | |
/** | |
This service returns the currently active PCR banks. | |
@param[in] This Indicates the calling context | |
@param[out] ActivePcrBanks Pointer to the variable receiving the bitmap of currently active PCR banks. | |
@retval EFI_SUCCESS The bitmap of active PCR banks was stored in the ActivePcrBanks parameter. | |
@retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
Tcg2GetActivePCRBanks ( | |
IN EFI_TCG2_PROTOCOL *This, | |
OUT UINT32 *ActivePcrBanks | |
) | |
{ | |
if (ActivePcrBanks == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
*ActivePcrBanks = mTcgDxeData.BsCap.ActivePcrBanks; | |
return EFI_SUCCESS; | |
} | |
/** | |
This service sets the currently active PCR banks. | |
@param[in] This Indicates the calling context | |
@param[in] ActivePcrBanks Bitmap of the requested active PCR banks. At least one bit SHALL be set. | |
@retval EFI_SUCCESS The bitmap in ActivePcrBank parameter is already active. | |
@retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
Tcg2SetActivePCRBanks ( | |
IN EFI_TCG2_PROTOCOL *This, | |
IN UINT32 ActivePcrBanks | |
) | |
{ | |
EFI_STATUS Status; | |
UINT32 ReturnCode; | |
DEBUG ((DEBUG_INFO, "Tcg2SetActivePCRBanks ... (0x%x)\n", ActivePcrBanks)); | |
if (ActivePcrBanks == 0) { | |
return EFI_INVALID_PARAMETER; | |
} | |
if ((ActivePcrBanks & (~mTcgDxeData.BsCap.HashAlgorithmBitmap)) != 0) { | |
return EFI_INVALID_PARAMETER; | |
} | |
if (ActivePcrBanks == mTcgDxeData.BsCap.ActivePcrBanks) { | |
// | |
// Need clear previous SET_PCR_BANKS setting | |
// | |
ReturnCode = Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunction (TCG2_PHYSICAL_PRESENCE_NO_ACTION, 0); | |
} else { | |
ReturnCode = Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunction (TCG2_PHYSICAL_PRESENCE_SET_PCR_BANKS, ActivePcrBanks); | |
} | |
if (ReturnCode == TCG_PP_SUBMIT_REQUEST_TO_PREOS_SUCCESS) { | |
Status = EFI_SUCCESS; | |
} else if (ReturnCode == TCG_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE) { | |
Status = EFI_OUT_OF_RESOURCES; | |
} else if (ReturnCode == TCG_PP_SUBMIT_REQUEST_TO_PREOS_NOT_IMPLEMENTED) { | |
Status = EFI_UNSUPPORTED; | |
} else { | |
Status = EFI_DEVICE_ERROR; | |
} | |
DEBUG ((DEBUG_INFO, "Tcg2SetActivePCRBanks - %r\n", Status)); | |
return Status; | |
} | |
/** | |
This service retrieves the result of a previous invocation of SetActivePcrBanks. | |
@param[in] This Indicates the calling context | |
@param[out] OperationPresent Non-zero value to indicate a SetActivePcrBank operation was invoked during the last boot. | |
@param[out] Response The response from the SetActivePcrBank request. | |
@retval EFI_SUCCESS The result value could be returned. | |
@retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
Tcg2GetResultOfSetActivePcrBanks ( | |
IN EFI_TCG2_PROTOCOL *This, | |
OUT UINT32 *OperationPresent, | |
OUT UINT32 *Response | |
) | |
{ | |
UINT32 ReturnCode; | |
if ((OperationPresent == NULL) || (Response == NULL)) { | |
return EFI_INVALID_PARAMETER; | |
} | |
ReturnCode = Tcg2PhysicalPresenceLibReturnOperationResponseToOsFunction (OperationPresent, Response); | |
if (ReturnCode == TCG_PP_RETURN_TPM_OPERATION_RESPONSE_SUCCESS) { | |
return EFI_SUCCESS; | |
} else { | |
return EFI_UNSUPPORTED; | |
} | |
} | |
EFI_TCG2_PROTOCOL mTcg2Protocol = { | |
Tcg2GetCapability, | |
Tcg2GetEventLog, | |
Tcg2HashLogExtendEvent, | |
Tcg2SubmitCommand, | |
Tcg2GetActivePCRBanks, | |
Tcg2SetActivePCRBanks, | |
Tcg2GetResultOfSetActivePcrBanks, | |
}; | |
/** | |
Initialize the Event Log and log events passed from the PEI phase. | |
@retval EFI_SUCCESS Operation completed successfully. | |
@retval EFI_OUT_OF_RESOURCES Out of memory. | |
**/ | |
EFI_STATUS | |
SetupEventLog ( | |
VOID | |
) | |
{ | |
EFI_STATUS Status; | |
VOID *TcgEvent; | |
EFI_PEI_HOB_POINTERS GuidHob; | |
EFI_PHYSICAL_ADDRESS Lasa; | |
UINTN Index; | |
VOID *DigestListBin; | |
TPML_DIGEST_VALUES TempDigestListBin; | |
UINT32 DigestListBinSize; | |
UINT8 *Event; | |
UINT32 EventSize; | |
UINT32 *EventSizePtr; | |
UINT32 HashAlgorithmMaskCopied; | |
TCG_EfiSpecIDEventStruct *TcgEfiSpecIdEventStruct; | |
UINT8 TempBuf[sizeof (TCG_EfiSpecIDEventStruct) + sizeof (UINT32) + (HASH_COUNT * sizeof (TCG_EfiSpecIdEventAlgorithmSize)) + sizeof (UINT8)]; | |
TCG_PCR_EVENT_HDR SpecIdEvent; | |
TCG_PCR_EVENT2_HDR NoActionEvent; | |
TCG_EfiSpecIdEventAlgorithmSize *DigestSize; | |
TCG_EfiSpecIdEventAlgorithmSize *TempDigestSize; | |
UINT8 *VendorInfoSize; | |
UINT32 NumberOfAlgorithms; | |
TCG_EfiStartupLocalityEvent StartupLocalityEvent; | |
DEBUG ((DEBUG_INFO, "SetupEventLog\n")); | |
// | |
// 1. Create Log Area | |
// | |
for (Index = 0; Index < sizeof (mTcg2EventInfo)/sizeof (mTcg2EventInfo[0]); Index++) { | |
if ((mTcgDxeData.BsCap.SupportedEventLogs & mTcg2EventInfo[Index].LogFormat) != 0) { | |
mTcgDxeData.EventLogAreaStruct[Index].EventLogFormat = mTcg2EventInfo[Index].LogFormat; | |
if (PcdGet8 (PcdTpm2AcpiTableRev) >= 4) { | |
Status = gBS->AllocatePages ( | |
AllocateAnyPages, | |
EfiACPIMemoryNVS, | |
EFI_SIZE_TO_PAGES (PcdGet32 (PcdTcgLogAreaMinLen)), | |
&Lasa | |
); | |
} else { | |
Status = gBS->AllocatePages ( | |
AllocateAnyPages, | |
EfiBootServicesData, | |
EFI_SIZE_TO_PAGES (PcdGet32 (PcdTcgLogAreaMinLen)), | |
&Lasa | |
); | |
} | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
mTcgDxeData.EventLogAreaStruct[Index].Lasa = Lasa; | |
mTcgDxeData.EventLogAreaStruct[Index].Laml = PcdGet32 (PcdTcgLogAreaMinLen); | |
mTcgDxeData.EventLogAreaStruct[Index].Next800155EventOffset = 0; | |
if ((PcdGet8 (PcdTpm2AcpiTableRev) >= 4) || | |
(mTcg2EventInfo[Index].LogFormat == EFI_TCG2_EVENT_LOG_FORMAT_TCG_2)) | |
{ | |
// | |
// Report TCG2 event log address and length, so that they can be reported in TPM2 ACPI table. | |
// Ignore the return status, because those fields are optional. | |
// | |
PcdSet32S (PcdTpm2AcpiTableLaml, (UINT32)mTcgDxeData.EventLogAreaStruct[Index].Laml); | |
PcdSet64S (PcdTpm2AcpiTableLasa, mTcgDxeData.EventLogAreaStruct[Index].Lasa); | |
} | |
// | |
// To initialize them as 0xFF is recommended | |
// because the OS can know the last entry for that. | |
// | |
SetMem ((VOID *)(UINTN)Lasa, PcdGet32 (PcdTcgLogAreaMinLen), 0xFF); | |
// | |
// Create first entry for Log Header Entry Data | |
// | |
if (mTcg2EventInfo[Index].LogFormat != EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2) { | |
// | |
// TcgEfiSpecIdEventStruct | |
// | |
TcgEfiSpecIdEventStruct = (TCG_EfiSpecIDEventStruct *)TempBuf; | |
CopyMem (TcgEfiSpecIdEventStruct->signature, TCG_EfiSpecIDEventStruct_SIGNATURE_03, sizeof (TcgEfiSpecIdEventStruct->signature)); | |
TcgEfiSpecIdEventStruct->platformClass = PcdGet8 (PcdTpmPlatformClass); | |
TcgEfiSpecIdEventStruct->specVersionMajor = TCG_EfiSpecIDEventStruct_SPEC_VERSION_MAJOR_TPM2; | |
TcgEfiSpecIdEventStruct->specVersionMinor = TCG_EfiSpecIDEventStruct_SPEC_VERSION_MINOR_TPM2; | |
TcgEfiSpecIdEventStruct->specErrata = (UINT8)PcdGet32 (PcdTcgPfpMeasurementRevision); | |
TcgEfiSpecIdEventStruct->uintnSize = sizeof (UINTN)/sizeof (UINT32); | |
NumberOfAlgorithms = 0; | |
DigestSize = (TCG_EfiSpecIdEventAlgorithmSize *)((UINT8 *)TcgEfiSpecIdEventStruct + sizeof (*TcgEfiSpecIdEventStruct) + sizeof (NumberOfAlgorithms)); | |
if ((mTcgDxeData.BsCap.ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA1) != 0) { | |
TempDigestSize = DigestSize; | |
TempDigestSize += NumberOfAlgorithms; | |
TempDigestSize->algorithmId = TPM_ALG_SHA1; | |
TempDigestSize->digestSize = SHA1_DIGEST_SIZE; | |
NumberOfAlgorithms++; | |
} | |
if ((mTcgDxeData.BsCap.ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA256) != 0) { | |
TempDigestSize = DigestSize; | |
TempDigestSize += NumberOfAlgorithms; | |
TempDigestSize->algorithmId = TPM_ALG_SHA256; | |
TempDigestSize->digestSize = SHA256_DIGEST_SIZE; | |
NumberOfAlgorithms++; | |
} | |
if ((mTcgDxeData.BsCap.ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA384) != 0) { | |
TempDigestSize = DigestSize; | |
TempDigestSize += NumberOfAlgorithms; | |
TempDigestSize->algorithmId = TPM_ALG_SHA384; | |
TempDigestSize->digestSize = SHA384_DIGEST_SIZE; | |
NumberOfAlgorithms++; | |
} | |
if ((mTcgDxeData.BsCap.ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA512) != 0) { | |
TempDigestSize = DigestSize; | |
TempDigestSize += NumberOfAlgorithms; | |
TempDigestSize->algorithmId = TPM_ALG_SHA512; | |
TempDigestSize->digestSize = SHA512_DIGEST_SIZE; | |
NumberOfAlgorithms++; | |
} | |
if ((mTcgDxeData.BsCap.ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SM3_256) != 0) { | |
TempDigestSize = DigestSize; | |
TempDigestSize += NumberOfAlgorithms; | |
TempDigestSize->algorithmId = TPM_ALG_SM3_256; | |
TempDigestSize->digestSize = SM3_256_DIGEST_SIZE; | |
NumberOfAlgorithms++; | |
} | |
CopyMem (TcgEfiSpecIdEventStruct + 1, &NumberOfAlgorithms, sizeof (NumberOfAlgorithms)); | |
TempDigestSize = DigestSize; | |
TempDigestSize += NumberOfAlgorithms; | |
VendorInfoSize = (UINT8 *)TempDigestSize; | |
*VendorInfoSize = 0; | |
SpecIdEvent.PCRIndex = 0; | |
SpecIdEvent.EventType = EV_NO_ACTION; | |
ZeroMem (&SpecIdEvent.Digest, sizeof (SpecIdEvent.Digest)); | |
SpecIdEvent.EventSize = (UINT32)GetTcgEfiSpecIdEventStructSize (TcgEfiSpecIdEventStruct); | |
// | |
// Log TcgEfiSpecIdEventStruct as the first Event. Event format is TCG_PCR_EVENT. | |
// TCG EFI Protocol Spec. Section 5.3 Event Log Header | |
// TCG PC Client PFP spec. Section 9.2 Measurement Event Entries and Log | |
// | |
Status = TcgDxeLogEvent ( | |
mTcg2EventInfo[Index].LogFormat, | |
&SpecIdEvent, | |
sizeof (SpecIdEvent), | |
(UINT8 *)TcgEfiSpecIdEventStruct, | |
SpecIdEvent.EventSize | |
); | |
// | |
// record the offset at the end of 800-155 event. | |
// the future 800-155 event can be inserted here. | |
// | |
mTcgDxeData.EventLogAreaStruct[Index].Next800155EventOffset = \ | |
mTcgDxeData.EventLogAreaStruct[Index].EventLogSize; | |
// | |
// Tcg800155PlatformIdEvent. Event format is TCG_PCR_EVENT2 | |
// | |
GuidHob.Guid = GetFirstGuidHob (&gTcg800155PlatformIdEventHobGuid); | |
while (GuidHob.Guid != NULL) { | |
InitNoActionEvent (&NoActionEvent, GET_GUID_HOB_DATA_SIZE (GuidHob.Guid)); | |
Status = TcgDxeLogEvent ( | |
mTcg2EventInfo[Index].LogFormat, | |
&NoActionEvent, | |
sizeof (NoActionEvent.PCRIndex) + sizeof (NoActionEvent.EventType) + GetDigestListBinSize (&NoActionEvent.Digests) + sizeof (NoActionEvent.EventSize), | |
GET_GUID_HOB_DATA (GuidHob.Guid), | |
GET_GUID_HOB_DATA_SIZE (GuidHob.Guid) | |
); | |
GuidHob.Guid = GET_NEXT_HOB (GuidHob); | |
GuidHob.Guid = GetNextGuidHob (&gTcg800155PlatformIdEventHobGuid, GuidHob.Guid); | |
} | |
// | |
// EfiStartupLocalityEvent. Event format is TCG_PCR_EVENT2 | |
// | |
GuidHob.Guid = GetFirstGuidHob (&gTpm2StartupLocalityHobGuid); | |
if (GuidHob.Guid != NULL) { | |
// | |
// Get Locality Indicator from StartupLocality HOB | |
// | |
StartupLocalityEvent.StartupLocality = *(UINT8 *)(GET_GUID_HOB_DATA (GuidHob.Guid)); | |
CopyMem (StartupLocalityEvent.Signature, TCG_EfiStartupLocalityEvent_SIGNATURE, sizeof (StartupLocalityEvent.Signature)); | |
DEBUG ((DEBUG_INFO, "SetupEventLog: Set Locality from HOB into StartupLocalityEvent 0x%02x\n", StartupLocalityEvent.StartupLocality)); | |
// | |
// Initialize StartupLocalityEvent | |
// | |
InitNoActionEvent (&NoActionEvent, sizeof (StartupLocalityEvent)); | |
// | |
// Log EfiStartupLocalityEvent as the second Event | |
// TCG PC Client PFP spec. Section 9.3.4.3 Startup Locality Event | |
// | |
Status = TcgDxeLogEvent ( | |
mTcg2EventInfo[Index].LogFormat, | |
&NoActionEvent, | |
sizeof (NoActionEvent.PCRIndex) + sizeof (NoActionEvent.EventType) + GetDigestListBinSize (&NoActionEvent.Digests) + sizeof (NoActionEvent.EventSize), | |
(UINT8 *)&StartupLocalityEvent, | |
sizeof (StartupLocalityEvent) | |
); | |
} | |
} | |
} | |
} | |
// | |
// 2. Create Final Log Area | |
// | |
for (Index = 0; Index < sizeof (mTcg2EventInfo)/sizeof (mTcg2EventInfo[0]); Index++) { | |
if ((mTcgDxeData.BsCap.SupportedEventLogs & mTcg2EventInfo[Index].LogFormat) != 0) { | |
if (mTcg2EventInfo[Index].LogFormat == EFI_TCG2_EVENT_LOG_FORMAT_TCG_2) { | |
Status = gBS->AllocatePages ( | |
AllocateAnyPages, | |
EfiACPIMemoryNVS, | |
EFI_SIZE_TO_PAGES (PcdGet32 (PcdTcg2FinalLogAreaLen)), | |
&Lasa | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
SetMem ((VOID *)(UINTN)Lasa, PcdGet32 (PcdTcg2FinalLogAreaLen), 0xFF); | |
// | |
// Initialize | |
// | |
mTcgDxeData.FinalEventsTable[Index] = (VOID *)(UINTN)Lasa; | |
(mTcgDxeData.FinalEventsTable[Index])->Version = EFI_TCG2_FINAL_EVENTS_TABLE_VERSION; | |
(mTcgDxeData.FinalEventsTable[Index])->NumberOfEvents = 0; | |
mTcgDxeData.FinalEventLogAreaStruct[Index].EventLogFormat = mTcg2EventInfo[Index].LogFormat; | |
mTcgDxeData.FinalEventLogAreaStruct[Index].Lasa = Lasa + sizeof (EFI_TCG2_FINAL_EVENTS_TABLE); | |
mTcgDxeData.FinalEventLogAreaStruct[Index].Laml = PcdGet32 (PcdTcg2FinalLogAreaLen) - sizeof (EFI_TCG2_FINAL_EVENTS_TABLE); | |
mTcgDxeData.FinalEventLogAreaStruct[Index].EventLogSize = 0; | |
mTcgDxeData.FinalEventLogAreaStruct[Index].LastEvent = (VOID *)(UINTN)mTcgDxeData.FinalEventLogAreaStruct[Index].Lasa; | |
mTcgDxeData.FinalEventLogAreaStruct[Index].EventLogStarted = FALSE; | |
mTcgDxeData.FinalEventLogAreaStruct[Index].EventLogTruncated = FALSE; | |
mTcgDxeData.FinalEventLogAreaStruct[Index].Next800155EventOffset = 0; | |
// | |
// Install to configuration table for EFI_TCG2_EVENT_LOG_FORMAT_TCG_2 | |
// | |
Status = gBS->InstallConfigurationTable (&gEfiTcg2FinalEventsTableGuid, (VOID *)mTcgDxeData.FinalEventsTable[Index]); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
} else { | |
// | |
// No need to handle EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2 | |
// | |
mTcgDxeData.FinalEventsTable[Index] = NULL; | |
mTcgDxeData.FinalEventLogAreaStruct[Index].EventLogFormat = mTcg2EventInfo[Index].LogFormat; | |
mTcgDxeData.FinalEventLogAreaStruct[Index].Lasa = 0; | |
mTcgDxeData.FinalEventLogAreaStruct[Index].Laml = 0; | |
mTcgDxeData.FinalEventLogAreaStruct[Index].EventLogSize = 0; | |
mTcgDxeData.FinalEventLogAreaStruct[Index].LastEvent = 0; | |
mTcgDxeData.FinalEventLogAreaStruct[Index].EventLogStarted = FALSE; | |
mTcgDxeData.FinalEventLogAreaStruct[Index].EventLogTruncated = FALSE; | |
mTcgDxeData.FinalEventLogAreaStruct[Index].Next800155EventOffset = 0; | |
} | |
} | |
} | |
// | |
// 3. Sync data from PEI to DXE | |
// | |
Status = EFI_SUCCESS; | |
for (Index = 0; Index < sizeof (mTcg2EventInfo)/sizeof (mTcg2EventInfo[0]); Index++) { | |
if ((mTcgDxeData.BsCap.SupportedEventLogs & mTcg2EventInfo[Index].LogFormat) != 0) { | |
GuidHob.Raw = GetHobList (); | |
Status = EFI_SUCCESS; | |
while (!EFI_ERROR (Status) && | |
(GuidHob.Raw = GetNextGuidHob (mTcg2EventInfo[Index].EventGuid, GuidHob.Raw)) != NULL) | |
{ | |
TcgEvent = AllocateCopyPool (GET_GUID_HOB_DATA_SIZE (GuidHob.Guid), GET_GUID_HOB_DATA (GuidHob.Guid)); | |
ASSERT (TcgEvent != NULL); | |
GuidHob.Raw = GET_NEXT_HOB (GuidHob); | |
switch (mTcg2EventInfo[Index].LogFormat) { | |
case EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2: | |
Status = TcgDxeLogEvent ( | |
mTcg2EventInfo[Index].LogFormat, | |
TcgEvent, | |
sizeof (TCG_PCR_EVENT_HDR), | |
((TCG_PCR_EVENT *)TcgEvent)->Event, | |
((TCG_PCR_EVENT_HDR *)TcgEvent)->EventSize | |
); | |
break; | |
case EFI_TCG2_EVENT_LOG_FORMAT_TCG_2: | |
DigestListBin = (UINT8 *)TcgEvent + sizeof (TCG_PCRINDEX) + sizeof (TCG_EVENTTYPE); | |
DigestListBinSize = GetDigestListBinSize (DigestListBin); | |
// | |
// Save event size. | |
// | |
CopyMem (&EventSize, (UINT8 *)DigestListBin + DigestListBinSize, sizeof (UINT32)); | |
Event = (UINT8 *)DigestListBin + DigestListBinSize + sizeof (UINT32); | |
// | |
// Filter inactive digest in the event2 log from PEI HOB. | |
// | |
CopyMem (&TempDigestListBin, DigestListBin, GetDigestListBinSize (DigestListBin)); | |
EventSizePtr = CopyDigestListBinToBuffer ( | |
DigestListBin, | |
&TempDigestListBin, | |
mTcgDxeData.BsCap.ActivePcrBanks, | |
&HashAlgorithmMaskCopied | |
); | |
if (HashAlgorithmMaskCopied != mTcgDxeData.BsCap.ActivePcrBanks) { | |
DEBUG (( | |
DEBUG_ERROR, | |
"ERROR: The event2 log includes digest hash mask 0x%x, but required digest hash mask is 0x%x\n", | |
HashAlgorithmMaskCopied, | |
mTcgDxeData.BsCap.ActivePcrBanks | |
)); | |
} | |
// | |
// Restore event size. | |
// | |
CopyMem (EventSizePtr, &EventSize, sizeof (UINT32)); | |
DigestListBinSize = GetDigestListBinSize (DigestListBin); | |
Status = TcgDxeLogEvent ( | |
mTcg2EventInfo[Index].LogFormat, | |
TcgEvent, | |
sizeof (TCG_PCRINDEX) + sizeof (TCG_EVENTTYPE) + DigestListBinSize + sizeof (UINT32), | |
Event, | |
EventSize | |
); | |
break; | |
} | |
FreePool (TcgEvent); | |
} | |
} | |
} | |
return Status; | |
} | |
/** | |
Measure and log an action string, and extend the measurement result into PCR[PCRIndex]. | |
@param[in] PCRIndex PCRIndex to extend | |
@param[in] String A specific string that indicates an Action event. | |
@retval EFI_SUCCESS Operation completed successfully. | |
@retval EFI_DEVICE_ERROR The operation was unsuccessful. | |
**/ | |
EFI_STATUS | |
TcgMeasureAction ( | |
IN TPM_PCRINDEX PCRIndex, | |
IN CHAR8 *String | |
) | |
{ | |
TCG_PCR_EVENT_HDR TcgEvent; | |
TcgEvent.PCRIndex = PCRIndex; | |
TcgEvent.EventType = EV_EFI_ACTION; | |
TcgEvent.EventSize = (UINT32)AsciiStrLen (String); | |
return TcgDxeHashLogExtendEvent ( | |
0, | |
(UINT8 *)String, | |
TcgEvent.EventSize, | |
&TcgEvent, | |
(UINT8 *)String | |
); | |
} | |
/** | |
Measure and log EFI handoff tables, and extend the measurement result into PCR[1]. | |
@retval EFI_SUCCESS Operation completed successfully. | |
@retval EFI_DEVICE_ERROR The operation was unsuccessful. | |
**/ | |
EFI_STATUS | |
MeasureHandoffTables ( | |
VOID | |
) | |
{ | |
EFI_STATUS Status; | |
TCG_PCR_EVENT_HDR TcgEvent; | |
EFI_HANDOFF_TABLE_POINTERS HandoffTables; | |
UINTN ProcessorNum; | |
EFI_CPU_PHYSICAL_LOCATION *ProcessorLocBuf; | |
ProcessorLocBuf = NULL; | |
Status = EFI_SUCCESS; | |
if (PcdGet8 (PcdTpmPlatformClass) == TCG_PLATFORM_TYPE_SERVER) { | |
// | |
// Tcg Server spec. | |
// Measure each processor EFI_CPU_PHYSICAL_LOCATION with EV_TABLE_OF_DEVICES to PCR[1] | |
// | |
Status = GetProcessorsCpuLocation (&ProcessorLocBuf, &ProcessorNum); | |
if (!EFI_ERROR (Status)) { | |
TcgEvent.PCRIndex = 1; | |
TcgEvent.EventType = EV_TABLE_OF_DEVICES; | |
TcgEvent.EventSize = sizeof (HandoffTables); | |
HandoffTables.NumberOfTables = 1; | |
HandoffTables.TableEntry[0].VendorGuid = gEfiMpServiceProtocolGuid; | |
HandoffTables.TableEntry[0].VendorTable = ProcessorLocBuf; | |
Status = TcgDxeHashLogExtendEvent ( | |
0, | |
(UINT8 *)(UINTN)ProcessorLocBuf, | |
sizeof (EFI_CPU_PHYSICAL_LOCATION) * ProcessorNum, | |
&TcgEvent, | |
(UINT8 *)&HandoffTables | |
); | |
FreePool (ProcessorLocBuf); | |
} | |
} | |
return Status; | |
} | |
/** | |
Measure and log Separator event, and extend the measurement result into a specific PCR. | |
@param[in] PCRIndex PCR index. | |
@retval EFI_SUCCESS Operation completed successfully. | |
@retval EFI_DEVICE_ERROR The operation was unsuccessful. | |
**/ | |
EFI_STATUS | |
MeasureSeparatorEvent ( | |
IN TPM_PCRINDEX PCRIndex | |
) | |
{ | |
TCG_PCR_EVENT_HDR TcgEvent; | |
UINT32 EventData; | |
DEBUG ((DEBUG_INFO, "MeasureSeparatorEvent Pcr - %x\n", PCRIndex)); | |
EventData = 0; | |
TcgEvent.PCRIndex = PCRIndex; | |
TcgEvent.EventType = EV_SEPARATOR; | |
TcgEvent.EventSize = (UINT32)sizeof (EventData); | |
return TcgDxeHashLogExtendEvent ( | |
0, | |
(UINT8 *)&EventData, | |
sizeof (EventData), | |
&TcgEvent, | |
(UINT8 *)&EventData | |
); | |
} | |
/** | |
Measure and log an EFI variable, and extend the measurement result into a specific PCR. | |
@param[in] PCRIndex PCR Index. | |
@param[in] EventType Event type. | |
@param[in] VarName A Null-terminated string that is the name of the vendor's variable. | |
@param[in] VendorGuid A unique identifier for the vendor. | |
@param[in] VarData The content of the variable data. | |
@param[in] VarSize The size of the variable data. | |
@retval EFI_SUCCESS Operation completed successfully. | |
@retval EFI_OUT_OF_RESOURCES Out of memory. | |
@retval EFI_DEVICE_ERROR The operation was unsuccessful. | |
**/ | |
EFI_STATUS | |
MeasureVariable ( | |
IN TPM_PCRINDEX PCRIndex, | |
IN TCG_EVENTTYPE EventType, | |
IN CHAR16 *VarName, | |
IN EFI_GUID *VendorGuid, | |
IN VOID *VarData, | |
IN UINTN VarSize | |
) | |
{ | |
EFI_STATUS Status; | |
TCG_PCR_EVENT_HDR TcgEvent; | |
UINTN VarNameLength; | |
UEFI_VARIABLE_DATA *VarLog; | |
DEBUG ((DEBUG_INFO, "Tcg2Dxe: MeasureVariable (Pcr - %x, EventType - %x, ", (UINTN)PCRIndex, (UINTN)EventType)); | |
DEBUG ((DEBUG_INFO, "VariableName - %s, VendorGuid - %g)\n", VarName, VendorGuid)); | |
VarNameLength = StrLen (VarName); | |
TcgEvent.PCRIndex = PCRIndex; | |
TcgEvent.EventType = EventType; | |
TcgEvent.EventSize = (UINT32)(sizeof (*VarLog) + VarNameLength * sizeof (*VarName) + VarSize | |
- sizeof (VarLog->UnicodeName) - sizeof (VarLog->VariableData)); | |
VarLog = (UEFI_VARIABLE_DATA *)AllocatePool (TcgEvent.EventSize); | |
if (VarLog == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
VarLog->VariableName = *VendorGuid; | |
VarLog->UnicodeNameLength = VarNameLength; | |
VarLog->VariableDataLength = VarSize; | |
CopyMem ( | |
VarLog->UnicodeName, | |
VarName, | |
VarNameLength * sizeof (*VarName) | |
); | |
if ((VarSize != 0) && (VarData != NULL)) { | |
CopyMem ( | |
(CHAR16 *)VarLog->UnicodeName + VarNameLength, | |
VarData, | |
VarSize | |
); | |
} | |
if (EventType == EV_EFI_VARIABLE_DRIVER_CONFIG) { | |
// | |
// Digest is the event data (UEFI_VARIABLE_DATA) | |
// | |
Status = TcgDxeHashLogExtendEvent ( | |
0, | |
(UINT8 *)VarLog, | |
TcgEvent.EventSize, | |
&TcgEvent, | |
(UINT8 *)VarLog | |
); | |
} else { | |
ASSERT (VarData != NULL); | |
Status = TcgDxeHashLogExtendEvent ( | |
0, | |
(UINT8 *)VarData, | |
VarSize, | |
&TcgEvent, | |
(UINT8 *)VarLog | |
); | |
} | |
FreePool (VarLog); | |
return Status; | |
} | |
/** | |
Read then Measure and log an EFI variable, and extend the measurement result into a specific PCR. | |
@param[in] PCRIndex PCR Index. | |
@param[in] EventType Event type. | |
@param[in] VarName A Null-terminated string that is the name of the vendor's variable. | |
@param[in] VendorGuid A unique identifier for the vendor. | |
@param[out] VarSize The size of the variable data. | |
@param[out] VarData Pointer to the content of the variable. | |
@retval EFI_SUCCESS Operation completed successfully. | |
@retval EFI_OUT_OF_RESOURCES Out of memory. | |
@retval EFI_DEVICE_ERROR The operation was unsuccessful. | |
**/ | |
EFI_STATUS | |
ReadAndMeasureVariable ( | |
IN TPM_PCRINDEX PCRIndex, | |
IN TCG_EVENTTYPE EventType, | |
IN CHAR16 *VarName, | |
IN EFI_GUID *VendorGuid, | |
OUT UINTN *VarSize, | |
OUT VOID **VarData | |
) | |
{ | |
EFI_STATUS Status; | |
Status = GetVariable2 (VarName, VendorGuid, VarData, VarSize); | |
if (EventType == EV_EFI_VARIABLE_DRIVER_CONFIG) { | |
if (EFI_ERROR (Status)) { | |
// | |
// It is valid case, so we need handle it. | |
// | |
*VarData = NULL; | |
*VarSize = 0; | |
} | |
} else { | |
// | |
// if status error, VarData is freed and set NULL by GetVariable2 | |
// | |
if (EFI_ERROR (Status)) { | |
return EFI_NOT_FOUND; | |
} | |
} | |
Status = MeasureVariable ( | |
PCRIndex, | |
EventType, | |
VarName, | |
VendorGuid, | |
*VarData, | |
*VarSize | |
); | |
return Status; | |
} | |
/** | |
Read then Measure and log an EFI boot variable, and extend the measurement result into PCR[1]. | |
according to TCG PC Client PFP spec 0021 Section 2.4.4.2 | |
@param[in] VarName A Null-terminated string that is the name of the vendor's variable. | |
@param[in] VendorGuid A unique identifier for the vendor. | |
@param[out] VarSize The size of the variable data. | |
@param[out] VarData Pointer to the content of the variable. | |
@retval EFI_SUCCESS Operation completed successfully. | |
@retval EFI_OUT_OF_RESOURCES Out of memory. | |
@retval EFI_DEVICE_ERROR The operation was unsuccessful. | |
**/ | |
EFI_STATUS | |
ReadAndMeasureBootVariable ( | |
IN CHAR16 *VarName, | |
IN EFI_GUID *VendorGuid, | |
OUT UINTN *VarSize, | |
OUT VOID **VarData | |
) | |
{ | |
return ReadAndMeasureVariable ( | |
1, | |
EV_EFI_VARIABLE_BOOT, | |
VarName, | |
VendorGuid, | |
VarSize, | |
VarData | |
); | |
} | |
/** | |
Read then Measure and log an EFI Secure variable, and extend the measurement result into PCR[7]. | |
@param[in] VarName A Null-terminated string that is the name of the vendor's variable. | |
@param[in] VendorGuid A unique identifier for the vendor. | |
@param[out] VarSize The size of the variable data. | |
@param[out] VarData Pointer to the content of the variable. | |
@retval EFI_SUCCESS Operation completed successfully. | |
@retval EFI_OUT_OF_RESOURCES Out of memory. | |
@retval EFI_DEVICE_ERROR The operation was unsuccessful. | |
**/ | |
EFI_STATUS | |
ReadAndMeasureSecureVariable ( | |
IN CHAR16 *VarName, | |
IN EFI_GUID *VendorGuid, | |
OUT UINTN *VarSize, | |
OUT VOID **VarData | |
) | |
{ | |
return ReadAndMeasureVariable ( | |
7, | |
EV_EFI_VARIABLE_DRIVER_CONFIG, | |
VarName, | |
VendorGuid, | |
VarSize, | |
VarData | |
); | |
} | |
/** | |
Measure and log all EFI boot variables, and extend the measurement result into a specific PCR. | |
The EFI boot variables are BootOrder and Boot#### variables. | |
@retval EFI_SUCCESS Operation completed successfully. | |
@retval EFI_OUT_OF_RESOURCES Out of memory. | |
@retval EFI_DEVICE_ERROR The operation was unsuccessful. | |
**/ | |
EFI_STATUS | |
MeasureAllBootVariables ( | |
VOID | |
) | |
{ | |
EFI_STATUS Status; | |
UINT16 *BootOrder; | |
UINTN BootCount; | |
UINTN Index; | |
VOID *BootVarData; | |
UINTN Size; | |
Status = ReadAndMeasureBootVariable ( | |
mBootVarName, | |
&gEfiGlobalVariableGuid, | |
&BootCount, | |
(VOID **)&BootOrder | |
); | |
if ((Status == EFI_NOT_FOUND) || (BootOrder == NULL)) { | |
return EFI_SUCCESS; | |
} | |
if (EFI_ERROR (Status)) { | |
// | |
// BootOrder can't be NULL if status is not EFI_NOT_FOUND | |
// | |
FreePool (BootOrder); | |
return Status; | |
} | |
BootCount /= sizeof (*BootOrder); | |
for (Index = 0; Index < BootCount; Index++) { | |
UnicodeSPrint (mBootVarName, sizeof (mBootVarName), L"Boot%04x", BootOrder[Index]); | |
Status = ReadAndMeasureBootVariable ( | |
mBootVarName, | |
&gEfiGlobalVariableGuid, | |
&Size, | |
&BootVarData | |
); | |
if (!EFI_ERROR (Status)) { | |
FreePool (BootVarData); | |
} | |
} | |
FreePool (BootOrder); | |
return EFI_SUCCESS; | |
} | |
/** | |
Measure and log all EFI Secure variables, and extend the measurement result into a specific PCR. | |
The EFI boot variables are BootOrder and Boot#### variables. | |
@retval EFI_SUCCESS Operation completed successfully. | |
@retval EFI_OUT_OF_RESOURCES Out of memory. | |
@retval EFI_DEVICE_ERROR The operation was unsuccessful. | |
**/ | |
EFI_STATUS | |
MeasureAllSecureVariables ( | |
VOID | |
) | |
{ | |
EFI_STATUS Status; | |
VOID *Data; | |
UINTN DataSize; | |
UINTN Index; | |
Status = EFI_NOT_FOUND; | |
for (Index = 0; Index < sizeof (mVariableType)/sizeof (mVariableType[0]); Index++) { | |
Status = ReadAndMeasureSecureVariable ( | |
mVariableType[Index].VariableName, | |
mVariableType[Index].VendorGuid, | |
&DataSize, | |
&Data | |
); | |
if (!EFI_ERROR (Status)) { | |
if (Data != NULL) { | |
FreePool (Data); | |
} | |
} | |
} | |
// | |
// Measure DBT if present and not empty | |
// | |
Status = GetVariable2 (EFI_IMAGE_SECURITY_DATABASE2, &gEfiImageSecurityDatabaseGuid, &Data, &DataSize); | |
if (!EFI_ERROR (Status)) { | |
Status = MeasureVariable ( | |
7, | |
EV_EFI_VARIABLE_DRIVER_CONFIG, | |
EFI_IMAGE_SECURITY_DATABASE2, | |
&gEfiImageSecurityDatabaseGuid, | |
Data, | |
DataSize | |
); | |
FreePool (Data); | |
} else { | |
DEBUG ((DEBUG_INFO, "Skip measuring variable %s since it's deleted\n", EFI_IMAGE_SECURITY_DATABASE2)); | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
Measure and log launch of FirmwareDebugger, and extend the measurement result into a specific PCR. | |
@retval EFI_SUCCESS Operation completed successfully. | |
@retval EFI_OUT_OF_RESOURCES Out of memory. | |
@retval EFI_DEVICE_ERROR The operation was unsuccessful. | |
**/ | |
EFI_STATUS | |
MeasureLaunchOfFirmwareDebugger ( | |
VOID | |
) | |
{ | |
TCG_PCR_EVENT_HDR TcgEvent; | |
TcgEvent.PCRIndex = 7; | |
TcgEvent.EventType = EV_EFI_ACTION; | |
TcgEvent.EventSize = sizeof (FIRMWARE_DEBUGGER_EVENT_STRING) - 1; | |
return TcgDxeHashLogExtendEvent ( | |
0, | |
(UINT8 *)FIRMWARE_DEBUGGER_EVENT_STRING, | |
sizeof (FIRMWARE_DEBUGGER_EVENT_STRING) - 1, | |
&TcgEvent, | |
(UINT8 *)FIRMWARE_DEBUGGER_EVENT_STRING | |
); | |
} | |
/** | |
Measure and log all Secure Boot Policy, and extend the measurement result into a specific PCR. | |
Platform firmware adhering to the policy must therefore measure the following values into PCR[7]: (in order listed) | |
- The contents of the SecureBoot variable | |
- The contents of the PK variable | |
- The contents of the KEK variable | |
- The contents of the EFI_IMAGE_SECURITY_DATABASE variable | |
- The contents of the EFI_IMAGE_SECURITY_DATABASE1 variable | |
- Separator | |
- Entries in the EFI_IMAGE_SECURITY_DATABASE that are used to validate EFI Drivers or EFI Boot Applications in the boot path | |
NOTE: Because of the above, UEFI variables PK, KEK, EFI_IMAGE_SECURITY_DATABASE, | |
EFI_IMAGE_SECURITY_DATABASE1 and SecureBoot SHALL NOT be measured into PCR[3]. | |
@param[in] Event Event whose notification function is being invoked | |
@param[in] Context Pointer to the notification function's context | |
**/ | |
VOID | |
EFIAPI | |
MeasureSecureBootPolicy ( | |
IN EFI_EVENT Event, | |
IN VOID *Context | |
) | |
{ | |
EFI_STATUS Status; | |
VOID *Protocol; | |
Status = gBS->LocateProtocol (&gEfiVariableWriteArchProtocolGuid, NULL, (VOID **)&Protocol); | |
if (EFI_ERROR (Status)) { | |
return; | |
} | |
if (PcdGetBool (PcdFirmwareDebuggerInitialized)) { | |
Status = MeasureLaunchOfFirmwareDebugger (); | |
DEBUG ((DEBUG_INFO, "MeasureLaunchOfFirmwareDebugger - %r\n", Status)); | |
} | |
Status = MeasureAllSecureVariables (); | |
DEBUG ((DEBUG_INFO, "MeasureAllSecureVariables - %r\n", Status)); | |
// | |
// We need measure Separator(7) here, because this event must be between SecureBootPolicy (Configure) | |
// and ImageVerification (Authority) | |
// There might be a case that we need measure UEFI image from DriverOrder, besides BootOrder. So | |
// the Authority measurement happen before ReadToBoot event. | |
// | |
Status = MeasureSeparatorEvent (7); | |
DEBUG ((DEBUG_INFO, "MeasureSeparatorEvent - %r\n", Status)); | |
return; | |
} | |
/** | |
Ready to Boot Event notification handler. | |
Sequence of OS boot events is measured in this event notification handler. | |
@param[in] Event Event whose notification function is being invoked | |
@param[in] Context Pointer to the notification function's context | |
**/ | |
VOID | |
EFIAPI | |
OnReadyToBoot ( | |
IN EFI_EVENT Event, | |
IN VOID *Context | |
) | |
{ | |
EFI_STATUS Status; | |
TPM_PCRINDEX PcrIndex; | |
PERF_START_EX (mImageHandle, "EventRec", "Tcg2Dxe", 0, PERF_ID_TCG2_DXE); | |
if (mBootAttempts == 0) { | |
// | |
// Measure handoff tables. | |
// | |
Status = MeasureHandoffTables (); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "HOBs not Measured. Error!\n")); | |
} | |
// | |
// Measure BootOrder & Boot#### variables. | |
// | |
Status = MeasureAllBootVariables (); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "Boot Variables not Measured. Error!\n")); | |
} | |
// | |
// 1. This is the first boot attempt. | |
// | |
Status = TcgMeasureAction ( | |
4, | |
EFI_CALLING_EFI_APPLICATION | |
); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "%a not Measured. Error!\n", EFI_CALLING_EFI_APPLICATION)); | |
} | |
// | |
// 2. Draw a line between pre-boot env and entering post-boot env. | |
// PCR[7] is already done. | |
// | |
for (PcrIndex = 0; PcrIndex < 7; PcrIndex++) { | |
Status = MeasureSeparatorEvent (PcrIndex); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "Separator Event not Measured. Error!\n")); | |
} | |
} | |
// | |
// 3. Measure GPT. It would be done in SAP driver. | |
// | |
// | |
// 4. Measure PE/COFF OS loader. It would be done in SAP driver. | |
// | |
// | |
// 5. Read & Measure variable. BootOrder already measured. | |
// | |
} else { | |
// | |
// 6. Not first attempt, meaning a return from last attempt | |
// | |
Status = TcgMeasureAction ( | |
4, | |
EFI_RETURNING_FROM_EFI_APPLICATION | |
); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "%a not Measured. Error!\n", EFI_RETURNING_FROM_EFI_APPLICATION)); | |
} | |
// | |
// 7. Next boot attempt, measure "Calling EFI Application from Boot Option" again | |
// TCG PC Client PFP spec Section 2.4.4.5 Step 4 | |
// | |
Status = TcgMeasureAction ( | |
4, | |
EFI_CALLING_EFI_APPLICATION | |
); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "%a not Measured. Error!\n", EFI_CALLING_EFI_APPLICATION)); | |
} | |
} | |
DEBUG ((DEBUG_INFO, "TPM2 Tcg2Dxe Measure Data when ReadyToBoot\n")); | |
// | |
// Increase boot attempt counter. | |
// | |
mBootAttempts++; | |
PERF_END_EX (mImageHandle, "EventRec", "Tcg2Dxe", 0, PERF_ID_TCG2_DXE + 1); | |
} | |
/** | |
Exit Boot Services Event notification handler. | |
Measure invocation and success of ExitBootServices. | |
@param[in] Event Event whose notification function is being invoked | |
@param[in] Context Pointer to the notification function's context | |
**/ | |
VOID | |
EFIAPI | |
OnExitBootServices ( | |
IN EFI_EVENT Event, | |
IN VOID *Context | |
) | |
{ | |
EFI_STATUS Status; | |
// | |
// Measure invocation of ExitBootServices, | |
// | |
Status = TcgMeasureAction ( | |
5, | |
EFI_EXIT_BOOT_SERVICES_INVOCATION | |
); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "%a not Measured. Error!\n", EFI_EXIT_BOOT_SERVICES_INVOCATION)); | |
} | |
// | |
// Measure success of ExitBootServices | |
// | |
Status = TcgMeasureAction ( | |
5, | |
EFI_EXIT_BOOT_SERVICES_SUCCEEDED | |
); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "%a not Measured. Error!\n", EFI_EXIT_BOOT_SERVICES_SUCCEEDED)); | |
} | |
} | |
/** | |
Exit Boot Services Failed Event notification handler. | |
Measure Failure of ExitBootServices. | |
@param[in] Event Event whose notification function is being invoked | |
@param[in] Context Pointer to the notification function's context | |
**/ | |
VOID | |
EFIAPI | |
OnExitBootServicesFailed ( | |
IN EFI_EVENT Event, | |
IN VOID *Context | |
) | |
{ | |
EFI_STATUS Status; | |
// | |
// Measure Failure of ExitBootServices, | |
// | |
Status = TcgMeasureAction ( | |
5, | |
EFI_EXIT_BOOT_SERVICES_FAILED | |
); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "%a not Measured. Error!\n", EFI_EXIT_BOOT_SERVICES_FAILED)); | |
} | |
} | |
/** | |
This routine is called to properly shutdown the TPM before system reset. | |
It follow chapter "12.2.3 Startup State" in Trusted Platform Module Library | |
Part 1: Architecture, Revision 01.16. | |
@param[in] ResetType The type of reset to perform. | |
@param[in] ResetStatus The status code for the reset. | |
@param[in] DataSize The size, in bytes, of ResetData. | |
@param[in] ResetData For a ResetType of EfiResetCold, EfiResetWarm, or | |
EfiResetShutdown the data buffer starts with a Null-terminated | |
string, optionally followed by additional binary data. | |
The string is a description that the caller may use to further | |
indicate the reason for the system reset. | |
For a ResetType of EfiResetPlatformSpecific the data buffer | |
also starts with a Null-terminated string that is followed | |
by an EFI_GUID that describes the specific type of reset to perform. | |
**/ | |
VOID | |
EFIAPI | |
ShutdownTpmOnReset ( | |
IN EFI_RESET_TYPE ResetType, | |
IN EFI_STATUS ResetStatus, | |
IN UINTN DataSize, | |
IN VOID *ResetData OPTIONAL | |
) | |
{ | |
EFI_STATUS Status; | |
Status = Tpm2Shutdown (TPM_SU_CLEAR); | |
DEBUG ((DEBUG_VERBOSE, "Tpm2Shutdown (SU_CLEAR) - %r\n", Status)); | |
} | |
/** | |
Hook the system reset to properly shutdown TPM. | |
It follow chapter "12.2.3 Startup State" in Trusted Platform Module Library | |
Part 1: Architecture, Revision 01.16. | |
@param[in] Event Event whose notification function is being invoked | |
@param[in] Context Pointer to the notification function's context | |
**/ | |
VOID | |
EFIAPI | |
OnResetNotificationInstall ( | |
IN EFI_EVENT Event, | |
IN VOID *Context | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_RESET_NOTIFICATION_PROTOCOL *ResetNotify; | |
Status = gBS->LocateProtocol (&gEfiResetNotificationProtocolGuid, NULL, (VOID **)&ResetNotify); | |
if (!EFI_ERROR (Status)) { | |
Status = ResetNotify->RegisterResetNotify (ResetNotify, ShutdownTpmOnReset); | |
ASSERT_EFI_ERROR (Status); | |
DEBUG ((DEBUG_VERBOSE, "TCG2: Hook system reset to properly shutdown TPM.\n")); | |
gBS->CloseEvent (Event); | |
} | |
} | |
/** | |
The function install Tcg2 protocol. | |
@retval EFI_SUCCESS Tcg2 protocol is installed. | |
@retval other Some error occurs. | |
**/ | |
EFI_STATUS | |
InstallTcg2 ( | |
VOID | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_HANDLE Handle; | |
Handle = NULL; | |
Status = gBS->InstallMultipleProtocolInterfaces ( | |
&Handle, | |
&gEfiTcg2ProtocolGuid, | |
&mTcg2Protocol, | |
NULL | |
); | |
return Status; | |
} | |
/** | |
The driver's entry point. It publishes EFI Tcg2 Protocol. | |
@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 is executed successfully. | |
@retval other Some error occurs when executing this entry point. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
DriverEntry ( | |
IN EFI_HANDLE ImageHandle, | |
IN EFI_SYSTEM_TABLE *SystemTable | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_EVENT Event; | |
VOID *Registration; | |
UINT32 MaxCommandSize; | |
UINT32 MaxResponseSize; | |
UINTN Index; | |
EFI_TCG2_EVENT_ALGORITHM_BITMAP TpmHashAlgorithmBitmap; | |
UINT32 ActivePCRBanks; | |
UINT32 NumberOfPCRBanks; | |
mImageHandle = ImageHandle; | |
if (CompareGuid (PcdGetPtr (PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceNoneGuid) || | |
CompareGuid (PcdGetPtr (PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm12Guid)) | |
{ | |
DEBUG ((DEBUG_INFO, "No TPM2 instance required!\n")); | |
return EFI_UNSUPPORTED; | |
} | |
if (GetFirstGuidHob (&gTpmErrorHobGuid) != NULL) { | |
DEBUG ((DEBUG_ERROR, "TPM2 error!\n")); | |
return EFI_DEVICE_ERROR; | |
} | |
Status = Tpm2RequestUseTpm (); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "TPM2 not detected!\n")); | |
return Status; | |
} | |
// | |
// Fill information | |
// | |
ASSERT (TCG_EVENT_LOG_AREA_COUNT_MAX == sizeof (mTcg2EventInfo)/sizeof (mTcg2EventInfo[0])); | |
mTcgDxeData.BsCap.Size = sizeof (EFI_TCG2_BOOT_SERVICE_CAPABILITY); | |
mTcgDxeData.BsCap.ProtocolVersion.Major = 1; | |
mTcgDxeData.BsCap.ProtocolVersion.Minor = 1; | |
mTcgDxeData.BsCap.StructureVersion.Major = 1; | |
mTcgDxeData.BsCap.StructureVersion.Minor = 1; | |
DEBUG ((DEBUG_INFO, "Tcg2.ProtocolVersion - %02x.%02x\n", mTcgDxeData.BsCap.ProtocolVersion.Major, mTcgDxeData.BsCap.ProtocolVersion.Minor)); | |
DEBUG ((DEBUG_INFO, "Tcg2.StructureVersion - %02x.%02x\n", mTcgDxeData.BsCap.StructureVersion.Major, mTcgDxeData.BsCap.StructureVersion.Minor)); | |
Status = Tpm2GetCapabilityManufactureID (&mTcgDxeData.BsCap.ManufacturerID); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "Tpm2GetCapabilityManufactureID fail!\n")); | |
} else { | |
DEBUG ((DEBUG_INFO, "Tpm2GetCapabilityManufactureID - %08x\n", mTcgDxeData.BsCap.ManufacturerID)); | |
} | |
DEBUG_CODE_BEGIN (); | |
UINT32 FirmwareVersion1; | |
UINT32 FirmwareVersion2; | |
Status = Tpm2GetCapabilityFirmwareVersion (&FirmwareVersion1, &FirmwareVersion2); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "Tpm2GetCapabilityFirmwareVersion fail!\n")); | |
} else { | |
DEBUG ((DEBUG_INFO, "Tpm2GetCapabilityFirmwareVersion - %08x %08x\n", FirmwareVersion1, FirmwareVersion2)); | |
} | |
DEBUG_CODE_END (); | |
Status = Tpm2GetCapabilityMaxCommandResponseSize (&MaxCommandSize, &MaxResponseSize); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "Tpm2GetCapabilityMaxCommandResponseSize fail!\n")); | |
} else { | |
mTcgDxeData.BsCap.MaxCommandSize = (UINT16)MaxCommandSize; | |
mTcgDxeData.BsCap.MaxResponseSize = (UINT16)MaxResponseSize; | |
DEBUG ((DEBUG_INFO, "Tpm2GetCapabilityMaxCommandResponseSize - %08x, %08x\n", MaxCommandSize, MaxResponseSize)); | |
} | |
// | |
// Get supported PCR and current Active PCRs | |
// | |
Status = Tpm2GetCapabilitySupportedAndActivePcrs (&TpmHashAlgorithmBitmap, &ActivePCRBanks); | |
ASSERT_EFI_ERROR (Status); | |
mTcgDxeData.BsCap.HashAlgorithmBitmap = TpmHashAlgorithmBitmap & PcdGet32 (PcdTcg2HashAlgorithmBitmap); | |
mTcgDxeData.BsCap.ActivePcrBanks = ActivePCRBanks & PcdGet32 (PcdTcg2HashAlgorithmBitmap); | |
// | |
// Need calculate NumberOfPCRBanks here, because HashAlgorithmBitmap might be removed by PCD. | |
// | |
NumberOfPCRBanks = 0; | |
for (Index = 0; Index < 32; Index++) { | |
if ((mTcgDxeData.BsCap.HashAlgorithmBitmap & (1u << Index)) != 0) { | |
NumberOfPCRBanks++; | |
} | |
} | |
if (PcdGet32 (PcdTcg2NumberOfPCRBanks) == 0) { | |
mTcgDxeData.BsCap.NumberOfPCRBanks = NumberOfPCRBanks; | |
} else { | |
mTcgDxeData.BsCap.NumberOfPCRBanks = PcdGet32 (PcdTcg2NumberOfPCRBanks); | |
if (PcdGet32 (PcdTcg2NumberOfPCRBanks) > NumberOfPCRBanks) { | |
DEBUG ((DEBUG_ERROR, "ERROR: PcdTcg2NumberOfPCRBanks(0x%x) > NumberOfPCRBanks(0x%x)\n", PcdGet32 (PcdTcg2NumberOfPCRBanks), NumberOfPCRBanks)); | |
mTcgDxeData.BsCap.NumberOfPCRBanks = NumberOfPCRBanks; | |
} | |
} | |
mTcgDxeData.BsCap.SupportedEventLogs = EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2 | EFI_TCG2_EVENT_LOG_FORMAT_TCG_2; | |
if ((mTcgDxeData.BsCap.ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA1) == 0) { | |
// | |
// No need to expose TCG1.2 event log if SHA1 bank does not exist. | |
// | |
mTcgDxeData.BsCap.SupportedEventLogs &= ~EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2; | |
} | |
DEBUG ((DEBUG_INFO, "Tcg2.SupportedEventLogs - 0x%08x\n", mTcgDxeData.BsCap.SupportedEventLogs)); | |
DEBUG ((DEBUG_INFO, "Tcg2.HashAlgorithmBitmap - 0x%08x\n", mTcgDxeData.BsCap.HashAlgorithmBitmap)); | |
DEBUG ((DEBUG_INFO, "Tcg2.NumberOfPCRBanks - 0x%08x\n", mTcgDxeData.BsCap.NumberOfPCRBanks)); | |
DEBUG ((DEBUG_INFO, "Tcg2.ActivePcrBanks - 0x%08x\n", mTcgDxeData.BsCap.ActivePcrBanks)); | |
if (mTcgDxeData.BsCap.TPMPresentFlag) { | |
// | |
// Setup the log area and copy event log from hob list to it | |
// | |
Status = SetupEventLog (); | |
ASSERT_EFI_ERROR (Status); | |
// | |
// Measure handoff tables, Boot#### variables etc. | |
// | |
Status = EfiCreateEventReadyToBootEx ( | |
TPL_CALLBACK, | |
OnReadyToBoot, | |
NULL, | |
&Event | |
); | |
Status = gBS->CreateEventEx ( | |
EVT_NOTIFY_SIGNAL, | |
TPL_NOTIFY, | |
OnExitBootServices, | |
NULL, | |
&gEfiEventExitBootServicesGuid, | |
&Event | |
); | |
// | |
// Measure Exit Boot Service failed | |
// | |
Status = gBS->CreateEventEx ( | |
EVT_NOTIFY_SIGNAL, | |
TPL_NOTIFY, | |
OnExitBootServicesFailed, | |
NULL, | |
&gEventExitBootServicesFailedGuid, | |
&Event | |
); | |
// | |
// Create event callback, because we need access variable on SecureBootPolicyVariable | |
// We should use VariableWriteArch instead of VariableArch, because Variable driver | |
// may update SecureBoot value based on last setting. | |
// | |
EfiCreateProtocolNotifyEvent (&gEfiVariableWriteArchProtocolGuid, TPL_CALLBACK, MeasureSecureBootPolicy, NULL, &Registration); | |
// | |
// Hook the system reset to properly shutdown TPM. | |
// | |
EfiCreateProtocolNotifyEvent (&gEfiResetNotificationProtocolGuid, TPL_CALLBACK, OnResetNotificationInstall, NULL, &Registration); | |
} | |
// | |
// Install Tcg2Protocol | |
// | |
Status = InstallTcg2 (); | |
DEBUG ((DEBUG_INFO, "InstallTcg2 - %r\n", Status)); | |
return Status; | |
} |