summaryrefslogtreecommitdiff
path: root/Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c
diff options
context:
space:
mode:
Diffstat (limited to 'Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c')
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c2621
1 files changed, 2621 insertions, 0 deletions
diff --git a/Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c b/Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c
new file mode 100644
index 0000000000..c2c52e32b8
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c
@@ -0,0 +1,2621 @@
+/** @file
+ This module implements Tcg2 Protocol.
+
+Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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 <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;
+} 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 Digeest 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 ((EFI_D_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 ((EFI_D_INFO, "%04x: ", Index * COLUME_SIZE));
+ InternalDumpData (Data + Index * COLUME_SIZE, COLUME_SIZE);
+ DEBUG ((EFI_D_INFO, "\n"));
+ }
+
+ if (Left != 0) {
+ DEBUG ((EFI_D_INFO, "%04x: ", Index * COLUME_SIZE));
+ InternalDumpData (Data + Index * COLUME_SIZE, Left);
+ DEBUG ((EFI_D_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 ((EFI_D_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 ((EFI_D_INFO, " Event:\n"));
+ DEBUG ((EFI_D_INFO, " PCRIndex - %d\n", EventHdr->PCRIndex));
+ DEBUG ((EFI_D_INFO, " EventType - 0x%08x\n", EventHdr->EventType));
+ DEBUG ((EFI_D_INFO, " Digest - "));
+ for (Index = 0; Index < sizeof(TCG_DIGEST); Index++) {
+ DEBUG ((EFI_D_INFO, "%02x ", EventHdr->Digest.digest[Index]));
+ }
+ DEBUG ((EFI_D_INFO, "\n"));
+ DEBUG ((EFI_D_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 ((EFI_D_INFO, " TCG_EfiSpecIDEventStruct:\n"));
+ DEBUG ((EFI_D_INFO, " signature - '"));
+ for (Index = 0; Index < sizeof(TcgEfiSpecIdEventStruct->signature); Index++) {
+ DEBUG ((EFI_D_INFO, "%c", TcgEfiSpecIdEventStruct->signature[Index]));
+ }
+ DEBUG ((EFI_D_INFO, "'\n"));
+ DEBUG ((EFI_D_INFO, " platformClass - 0x%08x\n", TcgEfiSpecIdEventStruct->platformClass));
+ DEBUG ((EFI_D_INFO, " specVersion - %d.%d%d\n", TcgEfiSpecIdEventStruct->specVersionMajor, TcgEfiSpecIdEventStruct->specVersionMinor, TcgEfiSpecIdEventStruct->specErrata));
+ DEBUG ((EFI_D_INFO, " uintnSize - 0x%02x\n", TcgEfiSpecIdEventStruct->uintnSize));
+
+ CopyMem (&NumberOfAlgorithms, TcgEfiSpecIdEventStruct + 1, sizeof(NumberOfAlgorithms));
+ DEBUG ((EFI_D_INFO, " NumberOfAlgorithms - 0x%08x\n", NumberOfAlgorithms));
+
+ DigestSize = (TCG_EfiSpecIdEventAlgorithmSize *)((UINT8 *)TcgEfiSpecIdEventStruct + sizeof(*TcgEfiSpecIdEventStruct) + sizeof(NumberOfAlgorithms));
+ for (Index = 0; Index < NumberOfAlgorithms; Index++) {
+ DEBUG ((EFI_D_INFO, " digest(%d)\n", Index));
+ DEBUG ((EFI_D_INFO, " algorithmId - 0x%04x\n", DigestSize[Index].algorithmId));
+ DEBUG ((EFI_D_INFO, " digestSize - 0x%04x\n", DigestSize[Index].digestSize));
+ }
+ VendorInfoSize = (UINT8 *)&DigestSize[NumberOfAlgorithms];
+ DEBUG ((EFI_D_INFO, " VendorInfoSize - 0x%02x\n", *VendorInfoSize));
+ VendorInfo = VendorInfoSize + 1;
+ DEBUG ((EFI_D_INFO, " VendorInfo - "));
+ for (Index = 0; Index < *VendorInfoSize; Index++) {
+ DEBUG ((EFI_D_INFO, "%02x ", VendorInfo[Index]));
+ }
+ DEBUG ((EFI_D_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 ((EFI_D_INFO, " Event:\n"));
+ DEBUG ((EFI_D_INFO, " PCRIndex - %d\n", TcgPcrEvent2->PCRIndex));
+ DEBUG ((EFI_D_INFO, " EventType - 0x%08x\n", TcgPcrEvent2->EventType));
+
+ DEBUG ((EFI_D_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 ((EFI_D_INFO, " HashAlgo : 0x%04x\n", HashAlgo));
+ DEBUG ((EFI_D_INFO, " Digest(%d): ", DigestIndex));
+ DigestSize = GetHashSizeFromAlgo (HashAlgo);
+ for (Index = 0; Index < DigestSize; Index++) {
+ DEBUG ((EFI_D_INFO, "%02x ", DigestBuffer[Index]));
+ }
+ DEBUG ((EFI_D_INFO, "\n"));
+ //
+ // Prepare next
+ //
+ CopyMem (&HashAlgo, DigestBuffer + DigestSize, sizeof(TPMI_ALG_HASH));
+ DigestBuffer = DigestBuffer + DigestSize + sizeof(TPMI_ALG_HASH);
+ }
+ DEBUG ((EFI_D_INFO, "\n"));
+ DigestBuffer = DigestBuffer - sizeof(TPMI_ALG_HASH);
+
+ CopyMem (&EventSize, DigestBuffer, sizeof(TcgPcrEvent2->EventSize));
+ DEBUG ((EFI_D_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 ((EFI_D_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 ((EFI_D_INFO, "FinalEventsTable: NOT FOUND\n"));
+ } else {
+ DEBUG ((EFI_D_INFO, "FinalEventsTable: (0x%x)\n", FinalEventsTable));
+ DEBUG ((EFI_D_INFO, " Version: (0x%x)\n", FinalEventsTable->Version));
+ DEBUG ((EFI_D_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 ((EFI_D_INFO, "FinalEventsTable: NOT FOUND\n"));
+ } else {
+ DEBUG ((EFI_D_INFO, "FinalEventsTable: (0x%x)\n", FinalEventsTable));
+ DEBUG ((EFI_D_INFO, " Version: (0x%x)\n", FinalEventsTable->Version));
+ DEBUG ((EFI_D_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 ((EFI_D_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 ((EFI_D_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 ((EFI_D_INFO, "Tcg2GetEventLog (EventLogLastEntry - %x)\n", *EventLogLastEntry));
+ }
+
+ if (EventLogTruncated != NULL) {
+ *EventLogTruncated = mTcgDxeData.EventLogAreaStruct[Index].EventLogTruncated;
+ DEBUG ((EFI_D_INFO, "Tcg2GetEventLog (EventLogTruncated - %x)\n", *EventLogTruncated));
+ }
+
+ DEBUG ((EFI_D_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;
+}
+
+/**
+ Add a new entry to the Event Log.
+
+ @param[in, out] EventLogPtr Pointer to the Event Log data.
+ @param[in, out] LogSize Size of the Event Log.
+ @param[in] MaxSize Maximum size of the Event Log.
+ @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 UINT8 **EventLogPtr,
+ IN OUT UINTN *LogSize,
+ IN UINTN MaxSize,
+ IN VOID *NewEventHdr,
+ IN UINT32 NewEventHdrSize,
+ IN UINT8 *NewEventData,
+ IN UINT32 NewEventSize
+ )
+{
+ UINTN NewLogSize;
+
+ if (NewEventSize > MAX_ADDRESS - NewEventHdrSize) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NewLogSize = NewEventHdrSize + NewEventSize;
+
+ if (NewLogSize > MAX_ADDRESS - *LogSize) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (NewLogSize + *LogSize > MaxSize) {
+ DEBUG ((EFI_D_INFO, " MaxSize - 0x%x\n", MaxSize));
+ DEBUG ((EFI_D_INFO, " NewLogSize - 0x%x\n", NewLogSize));
+ DEBUG ((EFI_D_INFO, " LogSize - 0x%x\n", *LogSize));
+ DEBUG ((EFI_D_INFO, "TcgCommLogEvent - %r\n", EFI_OUT_OF_RESOURCES));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *EventLogPtr += *LogSize;
+ *LogSize += NewLogSize;
+ CopyMem (*EventLogPtr, NewEventHdr, NewEventHdrSize);
+ CopyMem (
+ *EventLogPtr + 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;
+ }
+
+ EventLogAreaStruct->LastEvent = (UINT8*)(UINTN)EventLogAreaStruct->Lasa;
+ Status = TcgCommLogEvent (
+ &EventLogAreaStruct->LastEvent,
+ &EventLogAreaStruct->EventLogSize,
+ (UINTN)EventLogAreaStruct->Laml,
+ 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;
+ }
+
+ EventLogAreaStruct->LastEvent = (UINT8*)(UINTN)EventLogAreaStruct->Lasa;
+ Status = TcgCommLogEvent (
+ &EventLogAreaStruct->LastEvent,
+ &EventLogAreaStruct->EventLogSize,
+ (UINTN)EventLogAreaStruct->Laml,
+ 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 ((EFI_D_INFO, "FinalEventsTable->NumberOfEvents - 0x%x\n", (mTcgDxeData.FinalEventsTable[Index])->NumberOfEvents));
+ DEBUG ((EFI_D_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 ((EFI_D_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 ((EFI_D_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;
+
+ if (!mTcgDxeData.BsCap.TPMPresentFlag) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ 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 ((EFI_D_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) || (DataToHash == 0) || (Event == NULL)) {
+ 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 ((EFI_D_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 ((EFI_D_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 ((EFI_D_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 ((EFI_D_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 ((EFI_D_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 ((EFI_D_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;
+ 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);
+ //
+ // 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 = TCG_EfiSpecIDEventStruct_SPEC_ERRATA_TPM2;
+ 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
+ );
+
+ //
+ // 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;
+
+ //
+ // 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;
+ }
+ }
+ }
+
+ //
+ // 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 ((EFI_D_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 ((EFI_D_INFO, "Tcg2Dxe: MeasureVariable (Pcr - %x, EventType - %x, ", (UINTN)PCRIndex, (UINTN)EventType));
+ DEBUG ((EFI_D_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 ((EFI_D_INFO, "MeasureLaunchOfFirmwareDebugger - %r\n", Status));
+ }
+
+ Status = MeasureAllSecureVariables ();
+ DEBUG ((EFI_D_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 ((EFI_D_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 ((EFI_D_ERROR, "HOBs not Measured. Error!\n"));
+ }
+
+ //
+ // Measure BootOrder & Boot#### variables.
+ //
+ Status = MeasureAllBootVariables ();
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_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 ((EFI_D_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_APPLICATOIN
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "%a not Measured. Error!\n", EFI_RETURNING_FROM_EFI_APPLICATOIN));
+ }
+
+ //
+ // 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 ((EFI_D_ERROR, "%a not Measured. Error!\n", EFI_CALLING_EFI_APPLICATION));
+ }
+ }
+
+ DEBUG ((EFI_D_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 ((EFI_D_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 ((EFI_D_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 ((EFI_D_ERROR, "%a not Measured. Error!\n", EFI_EXIT_BOOT_SERVICES_FAILED));
+ }
+
+}
+
+/**
+ 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 ((EFI_D_ERROR, "TPM2 error!\n"));
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = Tpm2RequestUseTpm ();
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_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 ((EFI_D_INFO, "Tcg2.ProtocolVersion - %02x.%02x\n", mTcgDxeData.BsCap.ProtocolVersion.Major, mTcgDxeData.BsCap.ProtocolVersion.Minor));
+ DEBUG ((EFI_D_INFO, "Tcg2.StructureVersion - %02x.%02x\n", mTcgDxeData.BsCap.StructureVersion.Major, mTcgDxeData.BsCap.StructureVersion.Minor));
+
+ Status = Tpm2GetCapabilityManufactureID (&mTcgDxeData.BsCap.ManufacturerID);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2GetCapabilityManufactureID fail!\n"));
+ } else {
+ DEBUG ((EFI_D_INFO, "Tpm2GetCapabilityManufactureID - %08x\n", mTcgDxeData.BsCap.ManufacturerID));
+ }
+
+ DEBUG_CODE (
+ UINT32 FirmwareVersion1;
+ UINT32 FirmwareVersion2;
+
+ Status = Tpm2GetCapabilityFirmwareVersion (&FirmwareVersion1, &FirmwareVersion2);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2GetCapabilityFirmwareVersion fail!\n"));
+ } else {
+ DEBUG ((EFI_D_INFO, "Tpm2GetCapabilityFirmwareVersion - %08x %08x\n", FirmwareVersion1, FirmwareVersion2));
+ }
+ );
+
+ Status = Tpm2GetCapabilityMaxCommandResponseSize (&MaxCommandSize, &MaxResponseSize);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2GetCapabilityMaxCommandResponseSize fail!\n"));
+ } else {
+ mTcgDxeData.BsCap.MaxCommandSize = (UINT16)MaxCommandSize;
+ mTcgDxeData.BsCap.MaxResponseSize = (UINT16)MaxResponseSize;
+ DEBUG ((EFI_D_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 ((EFI_D_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 ((EFI_D_INFO, "Tcg2.SupportedEventLogs - 0x%08x\n", mTcgDxeData.BsCap.SupportedEventLogs));
+ DEBUG ((EFI_D_INFO, "Tcg2.HashAlgorithmBitmap - 0x%08x\n", mTcgDxeData.BsCap.HashAlgorithmBitmap));
+ DEBUG ((EFI_D_INFO, "Tcg2.NumberOfPCRBanks - 0x%08x\n", mTcgDxeData.BsCap.NumberOfPCRBanks));
+ DEBUG ((EFI_D_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);
+ }
+
+ //
+ // Install Tcg2Protocol
+ //
+ Status = InstallTcg2 ();
+ DEBUG ((EFI_D_INFO, "InstallTcg2 - %r\n", Status));
+
+ return Status;
+}