public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Min Xu" <min.m.xu@intel.com>
To: devel@edk2.groups.io
Cc: Min Xu <min.m.xu@intel.com>,
	Brijesh Singh <brijesh.singh@amd.com>,
	Erdem Aktas <erdemaktas@google.com>,
	James Bottomley <jejb@linux.ibm.com>,
	Jiewen Yao <jiewen.yao@intel.com>,
	Tom Lendacky <thomas.lendacky@amd.com>, Ken Lu <ken.lu@intel.com>,
	Sami Mujawar <sami.mujawar@arm.com>,
	Gerd Hoffmann <kraxel@redhat.com>
Subject: [PATCH V4 8/9] OvmfPkg/IntelTdx: Add TdTcg2Dxe
Date: Mon, 16 May 2022 15:42:22 +0800	[thread overview]
Message-ID: <56ce786fc58cae5110a68734183c0a930bc54fb3.1652686674.git.min.m.xu@intel.com> (raw)
In-Reply-To: <cover.1652686674.git.min.m.xu@intel.com>

RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3853

TdTcg2Dxe mimics the Security/Tcg/Tcg2Dxe. It does below tasks:
 - Set up and install CC_EVENTLOG ACPI table
 - Parse the GUIDed HOB (gCcEventEntryHobGuid) and create CC event log
 - Measure handoff tables, Boot##### variables etc
 - Measure Exit Boot Service failed
 - Install CcMeasurement Protocol

Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Ken Lu <ken.lu@intel.com>
Cc: Sami Mujawar <sami.mujawar@arm.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Jiewen Yao <jiewen.yao@intel.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 .../IntelTdx/TdTcg2Dxe/MeasureBootPeCoff.c    |  407 +++
 OvmfPkg/IntelTdx/TdTcg2Dxe/TdTcg2Dxe.c        | 2489 +++++++++++++++++
 OvmfPkg/IntelTdx/TdTcg2Dxe/TdTcg2Dxe.inf      |  101 +
 3 files changed, 2997 insertions(+)
 create mode 100644 OvmfPkg/IntelTdx/TdTcg2Dxe/MeasureBootPeCoff.c
 create mode 100644 OvmfPkg/IntelTdx/TdTcg2Dxe/TdTcg2Dxe.c
 create mode 100644 OvmfPkg/IntelTdx/TdTcg2Dxe/TdTcg2Dxe.inf

diff --git a/OvmfPkg/IntelTdx/TdTcg2Dxe/MeasureBootPeCoff.c b/OvmfPkg/IntelTdx/TdTcg2Dxe/MeasureBootPeCoff.c
new file mode 100644
index 000000000000..4d542156badd
--- /dev/null
+++ b/OvmfPkg/IntelTdx/TdTcg2Dxe/MeasureBootPeCoff.c
@@ -0,0 +1,407 @@
+/** @file
+  This module implements measuring PeCoff image for Tcg2 Protocol.
+
+  Caution: This file requires additional review when modified.
+  This driver will have external input - PE/COFF image.
+  This external input must be validated carefully to avoid security issue like
+  buffer overflow, integer overflow.
+
+Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/PeCoffLib.h>
+#include <Library/HashLib.h>
+
+UINTN  mTcg2DxeImageSize = 0;
+
+/**
+  Reads contents of a PE/COFF image in memory buffer.
+
+  Caution: This function may receive untrusted input.
+  PE/COFF image is external input, so this function will make sure the PE/COFF image content
+  read is within the image buffer.
+
+  @param  FileHandle      Pointer to the file handle to read the PE/COFF image.
+  @param  FileOffset      Offset into the PE/COFF image to begin the read operation.
+  @param  ReadSize        On input, the size in bytes of the requested read operation.
+                          On output, the number of bytes actually read.
+  @param  Buffer          Output buffer that contains the data read from the PE/COFF image.
+
+  @retval EFI_SUCCESS     The specified portion of the PE/COFF image was read and the size
+**/
+EFI_STATUS
+EFIAPI
+Tcg2DxeImageRead (
+  IN     VOID   *FileHandle,
+  IN     UINTN  FileOffset,
+  IN OUT UINTN  *ReadSize,
+  OUT    VOID   *Buffer
+  )
+{
+  UINTN  EndPosition;
+
+  if ((FileHandle == NULL) || (ReadSize == NULL) || (Buffer == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (MAX_ADDRESS - FileOffset < *ReadSize) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  EndPosition = FileOffset + *ReadSize;
+  if (EndPosition > mTcg2DxeImageSize) {
+    *ReadSize = (UINT32)(mTcg2DxeImageSize - FileOffset);
+  }
+
+  if (FileOffset >= mTcg2DxeImageSize) {
+    *ReadSize = 0;
+  }
+
+  CopyMem (Buffer, (UINT8 *)((UINTN)FileHandle + FileOffset), *ReadSize);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  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]  RtmrIndex      Rtmr 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                RtmrIndex,
+  IN  EFI_PHYSICAL_ADDRESS  ImageAddress,
+  IN  UINTN                 ImageSize,
+  OUT TPML_DIGEST_VALUES    *DigestList
+  )
+{
+  EFI_STATUS                           Status;
+  EFI_IMAGE_DOS_HEADER                 *DosHdr;
+  UINT32                               PeCoffHeaderOffset;
+  EFI_IMAGE_SECTION_HEADER             *Section;
+  UINT8                                *HashBase;
+  UINTN                                HashSize;
+  UINTN                                SumOfBytesHashed;
+  EFI_IMAGE_SECTION_HEADER             *SectionHeader;
+  UINTN                                Index;
+  UINTN                                Pos;
+  EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION  Hdr;
+  UINT32                               NumberOfRvaAndSizes;
+  UINT32                               CertSize;
+  HASH_HANDLE                          HashHandle;
+  PE_COFF_LOADER_IMAGE_CONTEXT         ImageContext;
+
+  HashHandle = 0xFFFFFFFF; // Know bad value
+
+  Status        = EFI_UNSUPPORTED;
+  SectionHeader = NULL;
+
+  //
+  // Check PE/COFF image
+  //
+  ZeroMem (&ImageContext, sizeof (ImageContext));
+  ImageContext.Handle    = (VOID *)(UINTN)ImageAddress;
+  mTcg2DxeImageSize      = ImageSize;
+  ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE)Tcg2DxeImageRead;
+
+  //
+  // Get information about the image being loaded
+  //
+  Status = PeCoffLoaderGetImageInfo (&ImageContext);
+  if (EFI_ERROR (Status)) {
+    //
+    // The information can't be got from the invalid PeImage
+    //
+    DEBUG ((DEBUG_INFO, "Tcg2Dxe: PeImage invalid. Cannot retrieve image information.\n"));
+    goto Finish;
+  }
+
+  DosHdr             = (EFI_IMAGE_DOS_HEADER *)(UINTN)ImageAddress;
+  PeCoffHeaderOffset = 0;
+  if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
+    PeCoffHeaderOffset = DosHdr->e_lfanew;
+  }
+
+  Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *)(UINTN)ImageAddress + PeCoffHeaderOffset);
+  if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
+    Status = EFI_UNSUPPORTED;
+    goto Finish;
+  }
+
+  //
+  // PE/COFF Image Measurement
+  //
+  //    NOTE: The following codes/steps are based upon the authenticode image hashing in
+  //      PE/COFF Specification 8.0 Appendix A.
+  //
+  //
+
+  // 1.  Load the image header into memory.
+
+  // 2.  Initialize a SHA hash context.
+
+  Status = HashStart (&HashHandle);
+  if (EFI_ERROR (Status)) {
+    goto Finish;
+  }
+
+  //
+  // Measuring PE/COFF Image Header;
+  // But CheckSum field and SECURITY data directory (certificate) are excluded
+  //
+
+  //
+  // 3.  Calculate the distance from the base of the image header to the image checksum address.
+  // 4.  Hash the image header from its base to beginning of the image checksum.
+  //
+  HashBase = (UINT8 *)(UINTN)ImageAddress;
+  if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+    //
+    // Use PE32 offset
+    //
+    NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
+    HashSize            = (UINTN)(&Hdr.Pe32->OptionalHeader.CheckSum) - (UINTN)HashBase;
+  } else {
+    //
+    // Use PE32+ offset
+    //
+    NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
+    HashSize            = (UINTN)(&Hdr.Pe32Plus->OptionalHeader.CheckSum) - (UINTN)HashBase;
+  }
+
+  Status = HashUpdate (HashHandle, HashBase, HashSize);
+  if (EFI_ERROR (Status)) {
+    goto Finish;
+  }
+
+  //
+  // 5.  Skip over the image checksum (it occupies a single ULONG).
+  //
+  if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {
+    //
+    // 6.  Since there is no Cert Directory in optional header, hash everything
+    //     from the end of the checksum to the end of image header.
+    //
+    if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+      //
+      // Use PE32 offset.
+      //
+      HashBase = (UINT8 *)&Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);
+      HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN)(HashBase - ImageAddress);
+    } else {
+      //
+      // Use PE32+ offset.
+      //
+      HashBase = (UINT8 *)&Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
+      HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN)(HashBase - ImageAddress);
+    }
+
+    if (HashSize != 0) {
+      Status = HashUpdate (HashHandle, HashBase, HashSize);
+      if (EFI_ERROR (Status)) {
+        goto Finish;
+      }
+    }
+  } else {
+    //
+    // 7.  Hash everything from the end of the checksum to the start of the Cert Directory.
+    //
+    if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+      //
+      // Use PE32 offset
+      //
+      HashBase = (UINT8 *)&Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);
+      HashSize = (UINTN)(&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN)HashBase;
+    } else {
+      //
+      // Use PE32+ offset
+      //
+      HashBase = (UINT8 *)&Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
+      HashSize = (UINTN)(&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN)HashBase;
+    }
+
+    if (HashSize != 0) {
+      Status = HashUpdate (HashHandle, HashBase, HashSize);
+      if (EFI_ERROR (Status)) {
+        goto Finish;
+      }
+    }
+
+    //
+    // 8.  Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.)
+    // 9.  Hash everything from the end of the Cert Directory to the end of image header.
+    //
+    if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+      //
+      // Use PE32 offset
+      //
+      HashBase = (UINT8 *)&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
+      HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN)(HashBase - ImageAddress);
+    } else {
+      //
+      // Use PE32+ offset
+      //
+      HashBase = (UINT8 *)&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
+      HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN)(HashBase - ImageAddress);
+    }
+
+    if (HashSize != 0) {
+      Status = HashUpdate (HashHandle, HashBase, HashSize);
+      if (EFI_ERROR (Status)) {
+        goto Finish;
+      }
+    }
+  }
+
+  //
+  // 10. Set the SUM_OF_BYTES_HASHED to the size of the header
+  //
+  if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+    //
+    // Use PE32 offset
+    //
+    SumOfBytesHashed = Hdr.Pe32->OptionalHeader.SizeOfHeaders;
+  } else {
+    //
+    // Use PE32+ offset
+    //
+    SumOfBytesHashed = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders;
+  }
+
+  //
+  // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER
+  //     structures in the image. The 'NumberOfSections' field of the image
+  //     header indicates how big the table should be. Do not include any
+  //     IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero.
+  //
+  SectionHeader = (EFI_IMAGE_SECTION_HEADER *)AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * Hdr.Pe32->FileHeader.NumberOfSections);
+  if (SectionHeader == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Finish;
+  }
+
+  //
+  // 12.  Using the 'PointerToRawData' in the referenced section headers as
+  //      a key, arrange the elements in the table in ascending order. In other
+  //      words, sort the section headers according to the disk-file offset of
+  //      the section.
+  //
+  Section = (EFI_IMAGE_SECTION_HEADER *)(
+                                         (UINT8 *)(UINTN)ImageAddress +
+                                         PeCoffHeaderOffset +
+                                         sizeof (UINT32) +
+                                         sizeof (EFI_IMAGE_FILE_HEADER) +
+                                         Hdr.Pe32->FileHeader.SizeOfOptionalHeader
+                                         );
+  for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
+    Pos = Index;
+    while ((Pos > 0) && (Section->PointerToRawData < SectionHeader[Pos - 1].PointerToRawData)) {
+      CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof (EFI_IMAGE_SECTION_HEADER));
+      Pos--;
+    }
+
+    CopyMem (&SectionHeader[Pos], Section, sizeof (EFI_IMAGE_SECTION_HEADER));
+    Section += 1;
+  }
+
+  //
+  // 13.  Walk through the sorted table, bring the corresponding section
+  //      into memory, and hash the entire section (using the 'SizeOfRawData'
+  //      field in the section header to determine the amount of data to hash).
+  // 14.  Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED .
+  // 15.  Repeat steps 13 and 14 for all the sections in the sorted table.
+  //
+  for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
+    Section = (EFI_IMAGE_SECTION_HEADER *)&SectionHeader[Index];
+    if (Section->SizeOfRawData == 0) {
+      continue;
+    }
+
+    HashBase = (UINT8 *)(UINTN)ImageAddress + Section->PointerToRawData;
+    HashSize = (UINTN)Section->SizeOfRawData;
+
+    Status = HashUpdate (HashHandle, HashBase, HashSize);
+    if (EFI_ERROR (Status)) {
+      goto Finish;
+    }
+
+    SumOfBytesHashed += HashSize;
+  }
+
+  //
+  // 16.  If the file size is greater than SUM_OF_BYTES_HASHED, there is extra
+  //      data in the file that needs to be added to the hash. This data begins
+  //      at file offset SUM_OF_BYTES_HASHED and its length is:
+  //             FileSize  -  (CertDirectory->Size)
+  //
+  if (ImageSize > SumOfBytesHashed) {
+    HashBase = (UINT8 *)(UINTN)ImageAddress + SumOfBytesHashed;
+
+    if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {
+      CertSize = 0;
+    } else {
+      if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+        //
+        // Use PE32 offset.
+        //
+        CertSize = Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
+      } else {
+        //
+        // Use PE32+ offset.
+        //
+        CertSize = Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
+      }
+    }
+
+    if (ImageSize > CertSize + SumOfBytesHashed) {
+      HashSize = (UINTN)(ImageSize - CertSize - SumOfBytesHashed);
+
+      Status = HashUpdate (HashHandle, HashBase, HashSize);
+      if (EFI_ERROR (Status)) {
+        goto Finish;
+      }
+    } else if (ImageSize < CertSize + SumOfBytesHashed) {
+      Status = EFI_UNSUPPORTED;
+      goto Finish;
+    }
+  }
+
+  //
+  // 17.  Finalize the SHA hash.
+  //
+  Status = HashCompleteAndExtend (HashHandle, RtmrIndex, NULL, 0, DigestList);
+  if (EFI_ERROR (Status)) {
+    goto Finish;
+  }
+
+Finish:
+  if (SectionHeader != NULL) {
+    FreePool (SectionHeader);
+  }
+
+  return Status;
+}
diff --git a/OvmfPkg/IntelTdx/TdTcg2Dxe/TdTcg2Dxe.c b/OvmfPkg/IntelTdx/TdTcg2Dxe/TdTcg2Dxe.c
new file mode 100644
index 000000000000..e9315ecda17b
--- /dev/null
+++ b/OvmfPkg/IntelTdx/TdTcg2Dxe/TdTcg2Dxe.c
@@ -0,0 +1,2489 @@
+/** @file
+  This module implements EFI TD Protocol.
+
+  Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<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/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 <Protocol/AcpiTable.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/PcdLib.h>
+#include <Library/UefiLib.h>
+#include <Library/HashLib.h>
+#include <Library/PerformanceLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/TpmMeasurementLib.h>
+
+#include <Protocol/CcMeasurement.h>
+#include <Guid/CcEventHob.h>
+#include <Library/TdxLib.h>
+
+#define PERF_ID_CC_TCG2_DXE  0x3130
+
+#define   CC_EVENT_LOG_AREA_COUNT_MAX  1
+#define   INVALID_RTMR_INDEX           4
+
+typedef struct {
+  CHAR16      *VariableName;
+  EFI_GUID    *VendorGuid;
+} VARIABLE_TYPE;
+
+typedef struct {
+  EFI_GUID                   *EventGuid;
+  EFI_CC_EVENT_LOG_FORMAT    LogFormat;
+} CC_EVENT_INFO_STRUCT;
+
+typedef struct {
+  EFI_CC_EVENT_LOG_FORMAT    EventLogFormat;
+  EFI_PHYSICAL_ADDRESS       Lasa;
+  UINT64                     Laml;
+  UINTN                      EventLogSize;
+  UINT8                      *LastEvent;
+  BOOLEAN                    EventLogStarted;
+  BOOLEAN                    EventLogTruncated;
+  UINTN                      Next800155EventOffset;
+} CC_EVENT_LOG_AREA_STRUCT;
+
+typedef struct _TDX_DXE_DATA {
+  EFI_CC_BOOT_SERVICE_CAPABILITY    BsCap;
+  CC_EVENT_LOG_AREA_STRUCT          EventLogAreaStruct[CC_EVENT_LOG_AREA_COUNT_MAX];
+  BOOLEAN                           GetEventLogCalled[CC_EVENT_LOG_AREA_COUNT_MAX];
+  CC_EVENT_LOG_AREA_STRUCT          FinalEventLogAreaStruct[CC_EVENT_LOG_AREA_COUNT_MAX];
+  EFI_CC_FINAL_EVENTS_TABLE         *FinalEventsTable[CC_EVENT_LOG_AREA_COUNT_MAX];
+} TDX_DXE_DATA;
+
+typedef struct {
+  TPMI_ALG_HASH    HashAlgo;
+  UINT16           HashSize;
+  UINT32           HashMask;
+} TDX_HASH_INFO;
+
+//
+//
+CC_EVENT_INFO_STRUCT  mCcEventInfo[] = {
+  { &gCcEventEntryHobGuid, EFI_CC_EVENT_LOG_FORMAT_TCG_2 },
+};
+
+TDX_DXE_DATA  mTdxDxeData = {
+  {
+    sizeof (EFI_CC_BOOT_SERVICE_CAPABILITY), // Size
+    { 1, 1 },                                // StructureVersion
+    { 1, 1 },                                // ProtocolVersion
+    EFI_CC_BOOT_HASH_ALG_SHA384,             // HashAlgorithmBitmap
+    EFI_CC_EVENT_LOG_FORMAT_TCG_2,           // SupportedEventLogs
+    { 2, 0 }                                 // {CC_TYPE, CC_SUBTYPE}
+  },
+};
+
+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_CC_EVENTLOG_ACPI_TABLE  mTdxEventlogAcpiTemplate = {
+  {
+    EFI_CC_EVENTLOG_ACPI_TABLE_SIGNATURE,
+    sizeof (mTdxEventlogAcpiTemplate),
+    EFI_CC_EVENTLOG_ACPI_TABLE_REVISION,
+    //
+    // Compiler initializes the remaining bytes to 0
+    // These fields should be filled in production
+    //
+  },
+  { EFI_CC_TYPE_TDX, 0 }, // CcType
+  0,                      // rsvd
+  0,                      // laml
+  0,                      // lasa
+};
+
+//
+// Supported Hash list in Td guest.
+// Currently SHA384 is supported.
+//
+TDX_HASH_INFO  mHashInfo[] = {
+  { TPM_ALG_SHA384, SHA384_DIGEST_SIZE, HASH_ALG_SHA384 }
+};
+
+/**
+  Get hash size based on Algo
+
+  @param[in]     HashAlgo           Hash Algorithm Id.
+
+  @return Size of the hash.
+**/
+UINT16
+GetHashSizeFromAlgo (
+  IN TPMI_ALG_HASH  HashAlgo
+  )
+{
+  UINTN  Index;
+
+  for (Index = 0; Index < sizeof (mHashInfo)/sizeof (mHashInfo[0]); Index++) {
+    if (mHashInfo[Index].HashAlgo == HashAlgo) {
+      return mHashInfo[Index].HashSize;
+    }
+  }
+
+  return 0;
+}
+
+/**
+  Get hash mask based on Algo
+
+  @param[in]     HashAlgo           Hash Algorithm Id.
+
+  @return Hash mask.
+**/
+UINT32
+GetHashMaskFromAlgo (
+  IN TPMI_ALG_HASH  HashAlgo
+  )
+{
+  UINTN  Index;
+
+  for (Index = 0; Index < ARRAY_SIZE (mHashInfo); Index++) {
+    if (mHashInfo[Index].HashAlgo == HashAlgo) {
+      return mHashInfo[Index].HashMask;
+    }
+  }
+
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Copy TPML_DIGEST_VALUES into a buffer
+
+  @param[in,out] Buffer             Buffer to hold copied TPML_DIGEST_VALUES compact binary.
+  @param[in]     DigestList         TPML_DIGEST_VALUES to be copied.
+  @param[in]     HashAlgorithmMask  HASH bits corresponding to the desired digests to copy.
+
+  @return The end of buffer to hold TPML_DIGEST_VALUES.
+**/
+VOID *
+CopyDigestListToBuffer (
+  IN OUT VOID            *Buffer,
+  IN TPML_DIGEST_VALUES  *DigestList,
+  IN UINT32              HashAlgorithmMask
+  )
+{
+  UINTN   Index;
+  UINT16  DigestSize;
+  UINT32  DigestListCount;
+  UINT32  *DigestListCountPtr;
+
+  DigestListCountPtr = (UINT32 *)Buffer;
+  DigestListCount    = 0;
+  Buffer             = (UINT8 *)Buffer + sizeof (DigestList->count);
+  for (Index = 0; Index < DigestList->count; Index++) {
+    if ((DigestList->digests[Index].hashAlg & HashAlgorithmMask) == 0) {
+      DEBUG ((DEBUG_ERROR, "WARNING: TD Event log has HashAlg unsupported (0x%x)\n", DigestList->digests[Index].hashAlg));
+      continue;
+    }
+
+    CopyMem (Buffer, &DigestList->digests[Index].hashAlg, sizeof (DigestList->digests[Index].hashAlg));
+    Buffer     = (UINT8 *)Buffer + sizeof (DigestList->digests[Index].hashAlg);
+    DigestSize = GetHashSizeFromAlgo (DigestList->digests[Index].hashAlg);
+    CopyMem (Buffer, &DigestList->digests[Index].digest, DigestSize);
+    Buffer = (UINT8 *)Buffer + DigestSize;
+    DigestListCount++;
+  }
+
+  WriteUnaligned32 (DigestListCountPtr, DigestListCount);
+
+  return Buffer;
+}
+
+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]  MrIndex      RTMR 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                MrIndex,
+  IN  EFI_PHYSICAL_ADDRESS  ImageAddress,
+  IN  UINTN                 ImageSize,
+  OUT TPML_DIGEST_VALUES    *DigestList
+  );
+
+#define COLUME_SIZE  (16 * 2)
+
+/**
+
+  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, Index == COLUME_SIZE/2 ? " | %02x" : " %02x", (UINTN)Data[Index]));
+  }
+}
+
+/**
+
+  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;
+
+  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"));
+  }
+}
+
+/**
+
+  This function initialize TD_EVENT_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 CC_EVENT_HDR  *NoActionEvent,
+  IN UINT32            EventSize
+  )
+{
+  UINT32         DigestListCount;
+  TPMI_ALG_HASH  HashAlgId;
+  UINT8          *DigestBuffer;
+
+  DigestBuffer    = (UINT8 *)NoActionEvent->Digests.digests;
+  DigestListCount = 0;
+
+  NoActionEvent->MrIndex   = 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 ((mTdxDxeData.BsCap.HashAlgorithmBitmap & EFI_CC_BOOT_HASH_ALG_SHA384) != 0) {
+    HashAlgId = TPM_ALG_SHA384;
+    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);
+}
+
+/**
+  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_CC_MEASUREMENT_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_CC_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
+TdGetCapability (
+  IN EFI_CC_MEASUREMENT_PROTOCOL         *This,
+  IN OUT EFI_CC_BOOT_SERVICE_CAPABILITY  *ProtocolCapability
+  )
+{
+  DEBUG ((DEBUG_VERBOSE, "TdGetCapability\n"));
+
+  if ((This == NULL) || (ProtocolCapability == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  CopyMem (ProtocolCapability, &mTdxDxeData.BsCap, sizeof (EFI_CC_BOOT_SERVICE_CAPABILITY));
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function dump PCR event.
+  TD Event log reuse the TCG PCR Event spec.
+  The first event in the event log is the SHA1 log format.
+  There is only ONE TCG_PCR_EVENT in TD Event log.
+
+  @param[in]  EventHdr     TCG PCR event structure.
+**/
+VOID
+DumpPcrEvent (
+  IN TCG_PCR_EVENT_HDR  *EventHdr
+  )
+{
+  UINTN  Index;
+
+  DEBUG ((DEBUG_INFO, "  Event:\n"));
+  DEBUG ((DEBUG_INFO, "    MrIndex  - %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 TD Event (including the Digests).
+
+  @param[in]  CcEvent     TD Event structure.
+**/
+VOID
+DumpCcEvent (
+  IN CC_EVENT  *CcEvent
+  )
+{
+  UINT32         DigestIndex;
+  UINT32         DigestCount;
+  TPMI_ALG_HASH  HashAlgo;
+  UINT32         DigestSize;
+  UINT8          *DigestBuffer;
+  UINT32         EventSize;
+  UINT8          *EventBuffer;
+
+  DEBUG ((DEBUG_INFO, "Cc Event:\n"));
+  DEBUG ((DEBUG_INFO, "    MrIndex  - %d\n", CcEvent->MrIndex));
+  DEBUG ((DEBUG_INFO, "    EventType - 0x%08x\n", CcEvent->EventType));
+  DEBUG ((DEBUG_INFO, "    DigestCount: 0x%08x\n", CcEvent->Digests.count));
+
+  DigestCount  = CcEvent->Digests.count;
+  HashAlgo     = CcEvent->Digests.digests[0].hashAlg;
+  DigestBuffer = (UINT8 *)&CcEvent->Digests.digests[0].digest;
+  for (DigestIndex = 0; DigestIndex < DigestCount; DigestIndex++) {
+    DEBUG ((DEBUG_INFO, "      HashAlgo : 0x%04x\n", HashAlgo));
+    DEBUG ((DEBUG_INFO, "      Digest(%d): \n", DigestIndex));
+    DigestSize = GetHashSizeFromAlgo (HashAlgo);
+    InternalDumpHex (DigestBuffer, DigestSize);
+    //
+    // 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 (CcEvent->EventSize));
+  DEBUG ((DEBUG_INFO, "    EventSize - 0x%08x\n", EventSize));
+  EventBuffer = DigestBuffer + sizeof (CcEvent->EventSize);
+  InternalDumpHex (EventBuffer, EventSize);
+  DEBUG ((DEBUG_INFO, "\n"));
+}
+
+/**
+  This function returns size of Td Table event.
+
+  @param[in]  CcEvent     Td Table event structure.
+
+  @return size of Td event.
+**/
+UINTN
+GetCcEventSize (
+  IN CC_EVENT  *CcEvent
+  )
+{
+  UINT32         DigestIndex;
+  UINT32         DigestCount;
+  TPMI_ALG_HASH  HashAlgo;
+  UINT32         DigestSize;
+  UINT8          *DigestBuffer;
+  UINT32         EventSize;
+  UINT8          *EventBuffer;
+
+  DigestCount  = CcEvent->Digests.count;
+  HashAlgo     = CcEvent->Digests.digests[0].hashAlg;
+  DigestBuffer = (UINT8 *)&CcEvent->Digests.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 (CcEvent->EventSize));
+  EventBuffer = DigestBuffer + sizeof (CcEvent->EventSize);
+
+  return (UINTN)EventBuffer + EventSize - (UINTN)CcEvent;
+}
+
+/**
+  This function dump CC event log.
+  TDVF only supports EFI_CC_EVENT_LOG_FORMAT_TCG_2
+
+  @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
+DumpCcEventLog (
+  IN EFI_CC_EVENT_LOG_FORMAT    EventLogFormat,
+  IN EFI_PHYSICAL_ADDRESS       EventLogLocation,
+  IN EFI_PHYSICAL_ADDRESS       EventLogLastEntry,
+  IN EFI_CC_FINAL_EVENTS_TABLE  *FinalEventsTable
+  )
+{
+  TCG_PCR_EVENT_HDR         *EventHdr;
+  CC_EVENT                  *CcEvent;
+  TCG_EfiSpecIDEventStruct  *TcgEfiSpecIdEventStruct;
+  UINTN                     NumberOfEvents;
+
+  DEBUG ((DEBUG_INFO, "EventLogFormat: (0x%x)\n", EventLogFormat));
+  ASSERT (EventLogFormat == EFI_CC_EVENT_LOG_FORMAT_TCG_2);
+
+  //
+  // Dump first event.
+  // The first event is always the TCG_PCR_EVENT_HDR
+  // After this event is a TCG_EfiSpecIDEventStruct
+  //
+  EventHdr = (TCG_PCR_EVENT_HDR *)(UINTN)EventLogLocation;
+  DumpPcrEvent (EventHdr);
+
+  TcgEfiSpecIdEventStruct = (TCG_EfiSpecIDEventStruct *)(EventHdr + 1);
+  DumpTcgEfiSpecIdEventStruct (TcgEfiSpecIdEventStruct);
+
+  //
+  // Then the CcEvent (Its structure is similar to TCG_PCR_EVENT2)
+  //
+  CcEvent = (CC_EVENT *)((UINTN)TcgEfiSpecIdEventStruct + GetTcgEfiSpecIdEventStructSize (TcgEfiSpecIdEventStruct));
+  while ((UINTN)CcEvent <= EventLogLastEntry) {
+    DumpCcEvent (CcEvent);
+    CcEvent = (CC_EVENT *)((UINTN)CcEvent + GetCcEventSize (CcEvent));
+  }
+
+  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));
+
+    CcEvent = (CC_EVENT *)(UINTN)(FinalEventsTable + 1);
+    for (NumberOfEvents = 0; NumberOfEvents < FinalEventsTable->NumberOfEvents; NumberOfEvents++) {
+      DumpCcEvent (CcEvent);
+      CcEvent = (CC_EVENT *)((UINTN)CcEvent + GetCcEventSize (CcEvent));
+    }
+  }
+
+  return;
+}
+
+/**
+  The EFI_CC_MEASUREMENT_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
+TdGetEventLog (
+  IN EFI_CC_MEASUREMENT_PROTOCOL  *This,
+  IN EFI_CC_EVENT_LOG_FORMAT      EventLogFormat,
+  OUT EFI_PHYSICAL_ADDRESS        *EventLogLocation,
+  OUT EFI_PHYSICAL_ADDRESS        *EventLogLastEntry,
+  OUT BOOLEAN                     *EventLogTruncated
+  )
+{
+  UINTN  Index = 0;
+
+  DEBUG ((DEBUG_INFO, "TdGetEventLog ... (0x%x)\n", EventLogFormat));
+  ASSERT (EventLogFormat == EFI_CC_EVENT_LOG_FORMAT_TCG_2);
+
+  if (EventLogLocation != NULL) {
+    *EventLogLocation = mTdxDxeData.EventLogAreaStruct[Index].Lasa;
+    DEBUG ((DEBUG_INFO, "TdGetEventLog (EventLogLocation - %x)\n", *EventLogLocation));
+  }
+
+  if (EventLogLastEntry != NULL) {
+    if (!mTdxDxeData.EventLogAreaStruct[Index].EventLogStarted) {
+      *EventLogLastEntry = (EFI_PHYSICAL_ADDRESS)(UINTN)0;
+    } else {
+      *EventLogLastEntry = (EFI_PHYSICAL_ADDRESS)(UINTN)mTdxDxeData.EventLogAreaStruct[Index].LastEvent;
+    }
+
+    DEBUG ((DEBUG_INFO, "TdGetEventLog (EventLogLastEntry - %x)\n", *EventLogLastEntry));
+  }
+
+  if (EventLogTruncated != NULL) {
+    *EventLogTruncated = mTdxDxeData.EventLogAreaStruct[Index].EventLogTruncated;
+    DEBUG ((DEBUG_INFO, "TdGetEventLog (EventLogTruncated - %x)\n", *EventLogTruncated));
+  }
+
+  DEBUG ((DEBUG_INFO, "TdGetEventLog - %r\n", EFI_SUCCESS));
+
+  // Dump Event Log for debug purpose
+  if ((EventLogLocation != NULL) && (EventLogLastEntry != NULL)) {
+    DumpCcEventLog (EventLogFormat, *EventLogLocation, *EventLogLastEntry, mTdxDxeData.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.
+  //
+  mTdxDxeData.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  CC_EVENT_LOG_AREA_STRUCT  *EventLogAreaStruct,
+  IN      VOID                      *NewEventHdr,
+  IN      UINT32                    NewEventHdrSize,
+  IN      UINT8                     *NewEventData,
+  IN      UINT32                    NewEventSize
+  )
+{
+  UINTN         NewLogSize;
+  BOOLEAN       Record800155Event;
+  CC_EVENT_HDR  *CcEventHdr;
+
+  CcEventHdr = (CC_EVENT_HDR *)NewEventHdr;
+  DEBUG ((DEBUG_VERBOSE, "Td: Try to log event. Index = %d, EventType = 0x%x\n", CcEventHdr->MrIndex, CcEventHdr->EventType));
+
+  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) {
+    DEBUG ((DEBUG_INFO, "It is 800155Event.\n"));
+
+    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;
+}
+
+/**
+    RTMR[0]  => PCR[1,7]
+    RTMR[1]  => PCR[2,3,4,5]
+    RTMR[2]  => PCR[8~15]
+    RTMR[3]  => NA
+**/
+UINT32
+EFIAPI
+MapPcrToMrIndex (
+  IN  UINT32  PCRIndex
+  )
+{
+  UINT32  MrIndex;
+
+  if ((PCRIndex > 16) || (PCRIndex == 6) || (PCRIndex == 0)) {
+    ASSERT (FALSE);
+    return INVALID_RTMR_INDEX;
+  }
+
+  MrIndex = 0;
+  if ((PCRIndex == 1) || (PCRIndex == 7)) {
+    MrIndex = 0;
+  } else if ((PCRIndex > 1) && (PCRIndex < 6)) {
+    MrIndex = 1;
+  } else if ((PCRIndex > 7) && (PCRIndex < 16)) {
+    MrIndex = 2;
+  }
+
+  return MrIndex;
+}
+
+EFI_STATUS
+EFIAPI
+TdMapPcrToMrIndex (
+  IN  EFI_CC_MEASUREMENT_PROTOCOL  *This,
+  IN  UINT32                       PCRIndex,
+  OUT UINT32                       *MrIndex
+  )
+{
+  if (MrIndex == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if ((PCRIndex > 16) || (PCRIndex == 0) || (PCRIndex == 6)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *MrIndex = MapPcrToMrIndex (PCRIndex);
+
+  return *MrIndex == INVALID_RTMR_INDEX ? EFI_INVALID_PARAMETER : 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
+TdxDxeLogEvent (
+  IN      EFI_CC_EVENT_LOG_FORMAT  EventLogFormat,
+  IN      VOID                     *NewEventHdr,
+  IN      UINT32                   NewEventHdrSize,
+  IN      UINT8                    *NewEventData,
+  IN      UINT32                   NewEventSize
+  )
+{
+  EFI_STATUS                Status;
+  UINTN                     Index;
+  CC_EVENT_LOG_AREA_STRUCT  *EventLogAreaStruct;
+
+  if (EventLogFormat != EFI_CC_EVENT_LOG_FORMAT_TCG_2) {
+    ASSERT (FALSE);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Index = 0;
+
+  //
+  // Record to normal event log
+  //
+  EventLogAreaStruct = &mTdxDxeData.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 (mTdxDxeData.GetEventLogCalled[Index]) {
+    if (mTdxDxeData.FinalEventsTable[Index] == NULL) {
+      //
+      // no need for FinalEventsTable
+      //
+      return EFI_SUCCESS;
+    }
+
+    EventLogAreaStruct = &mTdxDxeData.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
+      //
+      (mTdxDxeData.FinalEventsTable[Index])->NumberOfEvents++;
+      DEBUG ((DEBUG_INFO, "FinalEventsTable->NumberOfEvents - 0x%x\n", (mTdxDxeData.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 ((HashAlg & HashAlgorithmMask) != 0) {
+      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. The call chain is like below:
+  TdxDxeLogHashEvent -> TdxDxeLogEvent -> TcgCommonLogEvent
+
+  Before this function is called, the event information (including the digest)
+  is ready.
+
+  @param[in]     DigestList    A list of digest.
+  @param[in,out] NewEventHdr   Pointer to a TD_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
+TdxDxeLogHashEvent (
+  IN      TPML_DIGEST_VALUES  *DigestList,
+  IN OUT  CC_EVENT_HDR        *NewEventHdr,
+  IN      UINT8               *NewEventData
+  )
+{
+  EFI_STATUS               Status;
+  EFI_TPL                  OldTpl;
+  EFI_STATUS               RetStatus;
+  CC_EVENT                 CcEvent;
+  UINT8                    *DigestBuffer;
+  UINT32                   *EventSizePtr;
+  EFI_CC_EVENT_LOG_FORMAT  LogFormat;
+
+  RetStatus = EFI_SUCCESS;
+  LogFormat = EFI_CC_EVENT_LOG_FORMAT_TCG_2;
+
+  ZeroMem (&CcEvent, sizeof (CcEvent));
+  //
+  // The index of event log is designed as below:
+  //   0  : MRTD
+  //   1-4: RTMR[0-3]
+  //
+  CcEvent.MrIndex   = NewEventHdr->MrIndex + 1;
+  CcEvent.EventType = NewEventHdr->EventType;
+  DigestBuffer      = (UINT8 *)&CcEvent.Digests;
+  EventSizePtr      = CopyDigestListToBuffer (DigestBuffer, DigestList, HASH_ALG_SHA384);
+  CopyMem (EventSizePtr, &NewEventHdr->EventSize, sizeof (NewEventHdr->EventSize));
+
+  //
+  // Enter critical region
+  //
+  OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+  Status = TdxDxeLogEvent (
+             LogFormat,
+             &CcEvent,
+             sizeof (CcEvent.MrIndex) + sizeof (CcEvent.EventType) + GetDigestListBinSize (DigestBuffer) + sizeof (CcEvent.EventSize),
+             NewEventData,
+             NewEventHdr->EventSize
+             );
+  if (Status != EFI_SUCCESS) {
+    RetStatus = Status;
+  }
+
+  gBS->RestoreTPL (OldTpl);
+
+  return RetStatus;
+}
+
+/**
+  Do a hash operation on a data buffer, extend a specific RTMR 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 TD_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
+TdxDxeHashLogExtendEvent (
+  IN      UINT64        Flags,
+  IN      UINT8         *HashData,
+  IN      UINT64        HashDataLen,
+  IN OUT  CC_EVENT_HDR  *NewEventHdr,
+  IN      UINT8         *NewEventData
+  )
+{
+  EFI_STATUS          Status;
+  TPML_DIGEST_VALUES  DigestList;
+  CC_EVENT_HDR        NoActionEvent;
+
+  if (NewEventHdr->EventType == EV_NO_ACTION) {
+    //
+    // Do not do RTMR extend for EV_NO_ACTION
+    //
+    Status = EFI_SUCCESS;
+    InitNoActionEvent (&NoActionEvent, NewEventHdr->EventSize);
+    if ((Flags & EFI_CC_FLAG_EXTEND_ONLY) == 0) {
+      Status = TdxDxeLogHashEvent (&(NoActionEvent.Digests), NewEventHdr, NewEventData);
+    }
+
+    return Status;
+  }
+
+  Status = HashAndExtend (
+             NewEventHdr->MrIndex,
+             HashData,
+             (UINTN)HashDataLen,
+             &DigestList
+             );
+  if (!EFI_ERROR (Status)) {
+    if ((Flags & EFI_CC_FLAG_EXTEND_ONLY) == 0) {
+      Status = TdxDxeLogHashEvent (&DigestList, NewEventHdr, NewEventData);
+    }
+  }
+
+  return Status;
+}
+
+/**
+  The EFI_CC_MEASUREMENT_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
+TdHashLogExtendEvent (
+  IN EFI_CC_MEASUREMENT_PROTOCOL  *This,
+  IN UINT64                       Flags,
+  IN EFI_PHYSICAL_ADDRESS         DataToHash,
+  IN UINT64                       DataToHashLen,
+  IN EFI_CC_EVENT                 *CcEvent
+  )
+{
+  EFI_STATUS          Status;
+  CC_EVENT_HDR        NewEventHdr;
+  TPML_DIGEST_VALUES  DigestList;
+
+  DEBUG ((DEBUG_VERBOSE, "TdHashLogExtendEvent ...\n"));
+
+  if ((This == NULL) || (CcEvent == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Do not check hash data size for EV_NO_ACTION event.
+  //
+  if ((CcEvent->Header.EventType != EV_NO_ACTION) && (DataToHash == 0)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (CcEvent->Size < CcEvent->Header.HeaderSize + sizeof (UINT32)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (CcEvent->Header.MrIndex > 4) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  NewEventHdr.MrIndex   = CcEvent->Header.MrIndex;
+  NewEventHdr.EventType = CcEvent->Header.EventType;
+  NewEventHdr.EventSize = CcEvent->Size - sizeof (UINT32) - CcEvent->Header.HeaderSize;
+  if ((Flags & EFI_CC_FLAG_PE_COFF_IMAGE) != 0) {
+    Status = MeasurePeImageAndExtend (
+               NewEventHdr.MrIndex,
+               DataToHash,
+               (UINTN)DataToHashLen,
+               &DigestList
+               );
+    if (!EFI_ERROR (Status)) {
+      if ((Flags & EFI_CC_FLAG_EXTEND_ONLY) == 0) {
+        Status = TdxDxeLogHashEvent (&DigestList, &NewEventHdr, CcEvent->Event);
+      }
+    }
+  } else {
+    Status = TdxDxeHashLogExtendEvent (
+               Flags,
+               (UINT8 *)(UINTN)DataToHash,
+               DataToHashLen,
+               &NewEventHdr,
+               CcEvent->Event
+               );
+  }
+
+  DEBUG ((DEBUG_VERBOSE, "TdHashLogExtendEvent - %r\n", Status));
+  return Status;
+}
+
+EFI_CC_MEASUREMENT_PROTOCOL  mTdProtocol = {
+  TdGetCapability,
+  TdGetEventLog,
+  TdHashLogExtendEvent,
+  TdMapPcrToMrIndex,
+};
+
+#define TD_HASH_COUNT  1
+#define TEMP_BUF_LEN   (sizeof(TCG_EfiSpecIDEventStruct) +  sizeof(UINT32) \
+                     + (TD_HASH_COUNT * sizeof(TCG_EfiSpecIdEventAlgorithmSize)) + sizeof(UINT8))
+
+/**
+  Initialize the TD 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
+SetupCcEventLog (
+  VOID
+  )
+{
+  EFI_STATUS                       Status;
+  EFI_PHYSICAL_ADDRESS             Lasa;
+  UINTN                            Index;
+  TCG_EfiSpecIDEventStruct         *TcgEfiSpecIdEventStruct;
+  UINT8                            TempBuf[TEMP_BUF_LEN];
+  TCG_PCR_EVENT_HDR                SpecIdEvent;
+  TCG_EfiSpecIdEventAlgorithmSize  *DigestSize;
+  TCG_EfiSpecIdEventAlgorithmSize  *TempDigestSize;
+  UINT8                            *VendorInfoSize;
+  UINT32                           NumberOfAlgorithms;
+  EFI_CC_EVENT_LOG_FORMAT          LogFormat;
+  EFI_PEI_HOB_POINTERS             GuidHob;
+  CC_EVENT_HDR                     NoActionEvent;
+
+  Status = EFI_SUCCESS;
+  DEBUG ((DEBUG_INFO, "SetupCcEventLog\n"));
+
+  Index     = 0;
+  LogFormat = EFI_CC_EVENT_LOG_FORMAT_TCG_2;
+
+  //
+  // 1. Create Log Area
+  //
+  mTdxDxeData.EventLogAreaStruct[Index].EventLogFormat = LogFormat;
+
+  // allocate pages for TD Event log
+  Status = gBS->AllocatePages (
+                  AllocateAnyPages,
+                  EfiACPIMemoryNVS,
+                  EFI_SIZE_TO_PAGES (PcdGet32 (PcdTcgLogAreaMinLen)),
+                  &Lasa
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  mTdxDxeData.EventLogAreaStruct[Index].Lasa                  = Lasa;
+  mTdxDxeData.EventLogAreaStruct[Index].Laml                  = PcdGet32 (PcdTcgLogAreaMinLen);
+  mTdxDxeData.EventLogAreaStruct[Index].Next800155EventOffset = 0;
+
+  //
+  // Report TD event log address and length, so that they can be reported in
+  // TD ACPI table. Ignore the return status, because those fields are optional.
+  //
+  PcdSet32S (PcdCcEventlogAcpiTableLaml, (UINT32)mTdxDxeData.EventLogAreaStruct[Index].Laml);
+  PcdSet64S (PcdCcEventlogAcpiTableLasa, mTdxDxeData.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
+  //
+
+  //
+  // 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));
+
+  TempDigestSize              = DigestSize;
+  TempDigestSize             += NumberOfAlgorithms;
+  TempDigestSize->algorithmId = TPM_ALG_SHA384;
+  TempDigestSize->digestSize  = SHA384_DIGEST_SIZE;
+  NumberOfAlgorithms++;
+
+  CopyMem (TcgEfiSpecIdEventStruct + 1, &NumberOfAlgorithms, sizeof (NumberOfAlgorithms));
+  TempDigestSize  = DigestSize;
+  TempDigestSize += NumberOfAlgorithms;
+  VendorInfoSize  = (UINT8 *)TempDigestSize;
+  *VendorInfoSize = 0;
+
+  SpecIdEvent.PCRIndex  = 1; // PCRIndex 0 maps to MrIndex 1
+  SpecIdEvent.EventType = EV_NO_ACTION;
+  ZeroMem (&SpecIdEvent.Digest, sizeof (SpecIdEvent.Digest));
+  SpecIdEvent.EventSize = (UINT32)GetTcgEfiSpecIdEventStructSize (TcgEfiSpecIdEventStruct);
+
+  //
+  // TD Event log re-use the spec of TCG2 Event log.
+  // 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 = TdxDxeLogEvent (
+             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.
+  //
+  mTdxDxeData.EventLogAreaStruct[Index].Next800155EventOffset = mTdxDxeData.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 = TdxDxeLogEvent (
+               LogFormat,
+               &NoActionEvent,
+               sizeof (NoActionEvent.MrIndex) + 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);
+  }
+
+  //
+  // 2. Create Final Log Area
+  //
+  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
+  //
+  mTdxDxeData.FinalEventsTable[Index]                   = (VOID *)(UINTN)Lasa;
+  (mTdxDxeData.FinalEventsTable[Index])->Version        = EFI_TCG2_FINAL_EVENTS_TABLE_VERSION;
+  (mTdxDxeData.FinalEventsTable[Index])->NumberOfEvents = 0;
+
+  mTdxDxeData.FinalEventLogAreaStruct[Index].EventLogFormat        = LogFormat;
+  mTdxDxeData.FinalEventLogAreaStruct[Index].Lasa                  = Lasa + sizeof (EFI_CC_FINAL_EVENTS_TABLE);
+  mTdxDxeData.FinalEventLogAreaStruct[Index].Laml                  = PcdGet32 (PcdTcg2FinalLogAreaLen) - sizeof (EFI_CC_FINAL_EVENTS_TABLE);
+  mTdxDxeData.FinalEventLogAreaStruct[Index].EventLogSize          = 0;
+  mTdxDxeData.FinalEventLogAreaStruct[Index].LastEvent             = (VOID *)(UINTN)mTdxDxeData.FinalEventLogAreaStruct[Index].Lasa;
+  mTdxDxeData.FinalEventLogAreaStruct[Index].EventLogStarted       = FALSE;
+  mTdxDxeData.FinalEventLogAreaStruct[Index].EventLogTruncated     = FALSE;
+  mTdxDxeData.FinalEventLogAreaStruct[Index].Next800155EventOffset = 0;
+
+  //
+  // Install to configuration table for EFI_CC_EVENT_LOG_FORMAT_TCG_2
+  //
+  Status = gBS->InstallConfigurationTable (&gEfiCcFinalEventsTableGuid, (VOID *)mTdxDxeData.FinalEventsTable[Index]);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  return Status;
+}
+
+/**
+  Measure and log an action string, and extend the measurement result into RTMR.
+
+  @param[in] MrIndex        MrIndex 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
+TdMeasureAction (
+  IN      UINT32  MrIndex,
+  IN      CHAR8   *String
+  )
+{
+  CC_EVENT_HDR  CcEvent;
+
+  CcEvent.MrIndex   = MrIndex;
+  CcEvent.EventType = EV_EFI_ACTION;
+  CcEvent.EventSize = (UINT32)AsciiStrLen (String);
+  return TdxDxeHashLogExtendEvent (
+           0,
+           (UINT8 *)String,
+           CcEvent.EventSize,
+           &CcEvent,
+           (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;
+  CC_EVENT_HDR                CcEvent;
+  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)) {
+      CcEvent.MrIndex   = MapPcrToMrIndex (1);
+      CcEvent.EventType = EV_TABLE_OF_DEVICES;
+      CcEvent.EventSize = sizeof (HandoffTables);
+
+      HandoffTables.NumberOfTables            = 1;
+      HandoffTables.TableEntry[0].VendorGuid  = gEfiMpServiceProtocolGuid;
+      HandoffTables.TableEntry[0].VendorTable = ProcessorLocBuf;
+
+      Status = TdxDxeHashLogExtendEvent (
+                 0,
+                 (UINT8 *)(UINTN)ProcessorLocBuf,
+                 sizeof (EFI_CPU_PHYSICAL_LOCATION) * ProcessorNum,
+                 &CcEvent,
+                 (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      UINT32  MrIndex
+  )
+{
+  CC_EVENT_HDR  CcEvent;
+  UINT32        EventData;
+
+  DEBUG ((DEBUG_INFO, "MeasureSeparatorEvent to Rtmr - %d\n", MrIndex));
+
+  EventData         = 0;
+  CcEvent.MrIndex   = MrIndex;
+  CcEvent.EventType = EV_SEPARATOR;
+  CcEvent.EventSize = (UINT32)sizeof (EventData);
+
+  return TdxDxeHashLogExtendEvent (
+           0,
+           (UINT8 *)&EventData,
+           sizeof (EventData),
+           &CcEvent,
+           (UINT8 *)&EventData
+           );
+}
+
+/**
+  Measure and log an EFI variable, and extend the measurement result into a specific RTMR.
+
+  @param[in]  MrIndex         RTMR 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      UINT32         MrIndex,
+  IN      TCG_EVENTTYPE  EventType,
+  IN      CHAR16         *VarName,
+  IN      EFI_GUID       *VendorGuid,
+  IN      VOID           *VarData,
+  IN      UINTN          VarSize
+  )
+{
+  EFI_STATUS          Status;
+  CC_EVENT_HDR        CcEvent;
+  UINTN               VarNameLength;
+  UEFI_VARIABLE_DATA  *VarLog;
+
+  DEBUG ((DEBUG_INFO, "TdTcg2Dxe: MeasureVariable (Rtmr - %x, EventType - %x, ", (UINTN)MrIndex, (UINTN)EventType));
+  DEBUG ((DEBUG_INFO, "VariableName - %s, VendorGuid - %g)\n", VarName, VendorGuid));
+
+  VarNameLength     = StrLen (VarName);
+  CcEvent.MrIndex   = MrIndex;
+  CcEvent.EventType = EventType;
+
+  CcEvent.EventSize = (UINT32)(sizeof (*VarLog) + VarNameLength * sizeof (*VarName) + VarSize
+                               - sizeof (VarLog->UnicodeName) - sizeof (VarLog->VariableData));
+
+  VarLog = (UEFI_VARIABLE_DATA *)AllocatePool (CcEvent.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 = TdxDxeHashLogExtendEvent (
+               0,
+               (UINT8 *)VarLog,
+               CcEvent.EventSize,
+               &CcEvent,
+               (UINT8 *)VarLog
+               );
+  } else {
+    ASSERT (VarData != NULL);
+    Status = TdxDxeHashLogExtendEvent (
+               0,
+               (UINT8 *)VarData,
+               VarSize,
+               &CcEvent,
+               (UINT8 *)VarLog
+               );
+  }
+
+  FreePool (VarLog);
+  return Status;
+}
+
+/**
+  Read then Measure and log an EFI variable, and extend the measurement result into a specific RTMR.
+
+  @param[in]  MrIndex           RTMR 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      UINT32         MrIndex,
+  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 (
+             MrIndex,
+             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
+  )
+{
+  //
+  // Boot variables are measured into (PCR[5]) RTMR[1],
+  // details in section 8.1 of TDVF design guide.
+  //
+  return ReadAndMeasureVariable (
+           MapPcrToMrIndex (5),
+           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 (
+           MapPcrToMrIndex (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 (
+               MapPcrToMrIndex (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
+  )
+{
+  CC_EVENT_HDR  CcEvent;
+
+  CcEvent.MrIndex   = MapPcrToMrIndex (7);
+  CcEvent.EventType = EV_EFI_ACTION;
+  CcEvent.EventSize = sizeof (FIRMWARE_DEBUGGER_EVENT_STRING) - 1;
+  return TdxDxeHashLogExtendEvent (
+           0,
+           (UINT8 *)FIRMWARE_DEBUGGER_EVENT_STRING,
+           sizeof (FIRMWARE_DEBUGGER_EVENT_STRING) - 1,
+           &CcEvent,
+           (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 (MapPcrToMrIndex (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;
+
+  PERF_START_EX (mImageHandle, "EventRec", "TdTcg2Dxe", 0, PERF_ID_CC_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 = TdMeasureAction (
+               MapPcrToMrIndex (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 RTMR[0]) is already done.
+    //
+    Status = MeasureSeparatorEvent (1);
+    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 = TdMeasureAction (
+               MapPcrToMrIndex (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 = TdMeasureAction (
+               MapPcrToMrIndex (4),
+               EFI_CALLING_EFI_APPLICATION
+               );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "%a not Measured. Error!\n", EFI_CALLING_EFI_APPLICATION));
+    }
+  }
+
+  DEBUG ((DEBUG_INFO, "TdTcg2Dxe Measure Data when ReadyToBoot\n"));
+  //
+  // Increase boot attempt counter.
+  //
+  mBootAttempts++;
+  PERF_END_EX (mImageHandle, "EventRec", "Tcg2Dxe", 0, PERF_ID_CC_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 = TdMeasureAction (
+             MapPcrToMrIndex (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 = TdMeasureAction (
+             MapPcrToMrIndex (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 = TdMeasureAction (
+             MapPcrToMrIndex (5),
+             EFI_EXIT_BOOT_SERVICES_FAILED
+             );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a not Measured. Error!\n", EFI_EXIT_BOOT_SERVICES_FAILED));
+  }
+}
+
+EFI_STATUS
+SyncCcEvent (
+  VOID
+  )
+{
+  EFI_STATUS               Status;
+  EFI_PEI_HOB_POINTERS     GuidHob;
+  VOID                     *CcEvent;
+  VOID                     *DigestListBin;
+  UINT32                   DigestListBinSize;
+  UINT8                    *Event;
+  UINT32                   EventSize;
+  EFI_CC_EVENT_LOG_FORMAT  LogFormat;
+
+  DEBUG ((DEBUG_INFO, "Sync Cc event from SEC\n"));
+
+  Status       = EFI_SUCCESS;
+  LogFormat    = EFI_CC_EVENT_LOG_FORMAT_TCG_2;
+  GuidHob.Guid = GetFirstGuidHob (&gCcEventEntryHobGuid);
+
+  while (!EFI_ERROR (Status) && GuidHob.Guid != NULL) {
+    CcEvent = AllocateCopyPool (GET_GUID_HOB_DATA_SIZE (GuidHob.Guid), GET_GUID_HOB_DATA (GuidHob.Guid));
+    if (CcEvent == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+
+    GuidHob.Guid = GET_NEXT_HOB (GuidHob);
+    GuidHob.Guid = GetNextGuidHob (&gCcEventEntryHobGuid, GuidHob.Guid);
+
+    DigestListBin     = (UINT8 *)CcEvent + sizeof (UINT32) + sizeof (TCG_EVENTTYPE);
+    DigestListBinSize = GetDigestListBinSize (DigestListBin);
+
+    //
+    // Event size.
+    //
+    EventSize = *(UINT32 *)((UINT8 *)DigestListBin + DigestListBinSize);
+    Event     = (UINT8 *)DigestListBin + DigestListBinSize + sizeof (UINT32);
+
+    //
+    // Log the event
+    //
+    Status = TdxDxeLogEvent (
+               LogFormat,
+               CcEvent,
+               sizeof (UINT32) + sizeof (TCG_EVENTTYPE) + DigestListBinSize + sizeof (UINT32),
+               Event,
+               EventSize
+               );
+
+    DumpCcEvent ((CC_EVENT *)CcEvent);
+    FreePool (CcEvent);
+  }
+
+  return Status;
+}
+
+/**
+  Install TDVF ACPI Table when ACPI Table Protocol is available.
+
+  @param[in]  Event     Event whose notification function is being invoked
+  @param[in]  Context   Pointer to the notification function's context
+**/
+VOID
+EFIAPI
+InstallAcpiTable (
+  IN EFI_EVENT  Event,
+  IN VOID       *Context
+  )
+{
+  UINTN                    TableKey;
+  EFI_STATUS               Status;
+  EFI_ACPI_TABLE_PROTOCOL  *AcpiTable;
+  UINT64                   OemTableId;
+
+  Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **)&AcpiTable);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "TD: AcpiTableProtocol is not installed. %r\n", Status));
+    return;
+  }
+
+  mTdxEventlogAcpiTemplate.Laml = (UINT64)PcdGet32 (PcdCcEventlogAcpiTableLaml);
+  mTdxEventlogAcpiTemplate.Lasa = PcdGet64 (PcdCcEventlogAcpiTableLasa);
+  CopyMem (mTdxEventlogAcpiTemplate.Header.OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (mTdxEventlogAcpiTemplate.Header.OemId));
+  OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId);
+  CopyMem (&mTdxEventlogAcpiTemplate.Header.OemTableId, &OemTableId, sizeof (UINT64));
+  mTdxEventlogAcpiTemplate.Header.OemRevision     = PcdGet32 (PcdAcpiDefaultOemRevision);
+  mTdxEventlogAcpiTemplate.Header.CreatorId       = PcdGet32 (PcdAcpiDefaultCreatorId);
+  mTdxEventlogAcpiTemplate.Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);
+
+  //
+  // Construct ACPI Table
+  Status = AcpiTable->InstallAcpiTable (
+                        AcpiTable,
+                        &mTdxEventlogAcpiTemplate,
+                        mTdxEventlogAcpiTemplate.Header.Length,
+                        &TableKey
+                        );
+  ASSERT_EFI_ERROR (Status);
+
+  DEBUG ((DEBUG_INFO, "TDVF Eventlog ACPI Table is installed.\n"));
+}
+
+/**
+  The function install TdTcg2 protocol.
+
+  @retval EFI_SUCCESS     TdTcg2 protocol is installed.
+  @retval other           Some error occurs.
+**/
+EFI_STATUS
+InstallCcMeasurementProtocol (
+  VOID
+  )
+{
+  EFI_STATUS  Status;
+  EFI_HANDLE  Handle;
+
+  Handle = NULL;
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &Handle,
+                  &gEfiCcMeasurementProtocolGuid,
+                  &mTdProtocol,
+                  NULL
+                  );
+  DEBUG ((DEBUG_INFO, "CcProtocol: Install %r\n", Status));
+  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;
+
+  if (!TdIsEnabled ()) {
+    return EFI_UNSUPPORTED;
+  }
+
+  mImageHandle = ImageHandle;
+
+  //
+  // Fill information
+  //
+  //  ASSERT (TD_EVENT_LOG_AREA_COUNT_MAX == sizeof(mTEventInfo)/sizeof(mTcg2EventInfo[0]));
+
+  mTdxDxeData.BsCap.Size                   = sizeof (EFI_CC_BOOT_SERVICE_CAPABILITY);
+  mTdxDxeData.BsCap.ProtocolVersion.Major  = 1;
+  mTdxDxeData.BsCap.ProtocolVersion.Minor  = 1;
+  mTdxDxeData.BsCap.StructureVersion.Major = 1;
+  mTdxDxeData.BsCap.StructureVersion.Minor = 1;
+
+  //
+  // Get supported PCR and current Active PCRs
+  // For TD gueset HA384 is supported.
+  //
+  mTdxDxeData.BsCap.HashAlgorithmBitmap = HASH_ALG_SHA384;
+
+  // TD guest only supports EFI_TCG2_EVENT_LOG_FORMAT_TCG_2
+  mTdxDxeData.BsCap.SupportedEventLogs = EFI_CC_EVENT_LOG_FORMAT_TCG_2;
+
+  //
+  // Setup the log area and copy event log from hob list to it
+  //
+  Status = SetupCcEventLog ();
+  ASSERT_EFI_ERROR (Status);
+
+  if (!EFI_ERROR (Status)) {
+    Status = SyncCcEvent ();
+    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 CcMeasurementProtocol
+  //
+  Status = InstallCcMeasurementProtocol ();
+  DEBUG ((DEBUG_INFO, "InstallCcMeasurementProtocol - %r\n", Status));
+
+  if (Status == EFI_SUCCESS) {
+    //
+    // Create event callback to install CC EventLog ACPI Table
+    EfiCreateProtocolNotifyEvent (&gEfiAcpiTableProtocolGuid, TPL_CALLBACK, InstallAcpiTable, NULL, &Registration);
+  }
+
+  return Status;
+}
diff --git a/OvmfPkg/IntelTdx/TdTcg2Dxe/TdTcg2Dxe.inf b/OvmfPkg/IntelTdx/TdTcg2Dxe/TdTcg2Dxe.inf
new file mode 100644
index 000000000000..5efe7ef479f1
--- /dev/null
+++ b/OvmfPkg/IntelTdx/TdTcg2Dxe/TdTcg2Dxe.inf
@@ -0,0 +1,101 @@
+## @file
+#
+#  Produces EFI_CC_MEASUREMENT_PROTOCOL and measure boot environment
+#
+#
+# Copyright (c) 2020 - 2022, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = TdTcg2Dxe
+  FILE_GUID                      = F062221E-C607-44C2-B0B4-C3886331D351
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = DriverEntry
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = X64
+#
+
+[Sources]
+  TdTcg2Dxe.c
+  MeasureBootPeCoff.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  SecurityPkg/SecurityPkg.dec
+  CryptoPkg/CryptoPkg.dec
+  OvmfPkg/OvmfPkg.dec
+
+[LibraryClasses]
+  MemoryAllocationLib
+  BaseLib
+  UefiBootServicesTableLib
+  HobLib
+  UefiDriverEntryPoint
+  UefiRuntimeServicesTableLib
+  BaseMemoryLib
+  DebugLib
+  PrintLib
+  UefiLib
+  HashLib
+  PerformanceLib
+  ReportStatusCodeLib
+  PeCoffLib
+  TpmMeasurementLib
+  TdxLib
+
+[Guids]
+  ## SOMETIMES_CONSUMES     ## Variable:L"SecureBoot"
+  ## SOMETIMES_CONSUMES     ## Variable:L"PK"
+  ## SOMETIMES_CONSUMES     ## Variable:L"KEK"
+  ## SOMETIMES_CONSUMES     ## Variable:L"BootXXXX"
+  gEfiGlobalVariableGuid
+
+  ## SOMETIMES_CONSUMES      ## Variable:L"db"
+  ## SOMETIMES_CONSUMES      ## Variable:L"dbx"
+  gEfiImageSecurityDatabaseGuid
+
+  # gTcgEventEntryHobGuid                              ## SOMETIMES_CONSUMES  ## HOB
+  gEfiEventExitBootServicesGuid                      ## CONSUMES            ## Event
+  gEventExitBootServicesFailedGuid                   ## SOMETIMES_CONSUMES  ## Event
+
+  gCcEventEntryHobGuid                               ## SOMETIMES_CONSUMES  ## HOB
+  gTcg800155PlatformIdEventHobGuid                   ## SOMETIMES_CONSUMES  ## HOB
+  gEfiCcFinalEventsTableGuid                         ## PRODUCES
+
+[Protocols]
+  gEfiCcMeasurementProtocolGuid                      ## PRODUCES
+  gEfiMpServiceProtocolGuid                          ## SOMETIMES_CONSUMES
+  gEfiVariableWriteArchProtocolGuid                  ## NOTIFY
+  gEfiResetNotificationProtocolGuid                  ## CONSUMES
+  gEfiAcpiTableProtocolGuid                          ## NOTIFY
+
+[Pcd]
+  gEfiSecurityPkgTokenSpaceGuid.PcdTpmPlatformClass                         ## SOMETIMES_CONSUMES
+  gEfiSecurityPkgTokenSpaceGuid.PcdFirmwareDebuggerInitialized              ## SOMETIMES_CONSUMES
+  gEfiSecurityPkgTokenSpaceGuid.PcdStatusCodeSubClassTpmDevice              ## SOMETIMES_CONSUMES
+  gEfiSecurityPkgTokenSpaceGuid.PcdTcg2HashAlgorithmBitmap                  ## CONSUMES
+  gEfiSecurityPkgTokenSpaceGuid.PcdTcg2NumberOfPCRBanks                     ## CONSUMES
+  gEfiSecurityPkgTokenSpaceGuid.PcdTcgLogAreaMinLen                         ## CONSUMES
+  gEfiSecurityPkgTokenSpaceGuid.PcdTcg2FinalLogAreaLen                      ## CONSUMES
+  gUefiOvmfPkgTokenSpaceGuid.PcdCcEventlogAcpiTableLaml                     ## PRODUCES
+  gUefiOvmfPkgTokenSpaceGuid.PcdCcEventlogAcpiTableLasa                     ## PRODUCES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId                        ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemTableId                   ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemRevision                  ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorId                    ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorRevision              ## CONSUMES
+
+[Depex]
+  # According to PcdTpm2AcpiTableRev definition in SecurityPkg.dec
+  # This PCD should be configured at DynamicHii or DynamicHiiEx.
+  # So, this PCD read operation depends on GetVariable service.
+  # Add VariableArch protocol dependency to make sure PCD read works.
+  gEfiVariableArchProtocolGuid AND gEfiAcpiTableProtocolGuid
-- 
2.29.2.windows.2


  parent reply	other threads:[~2022-05-16  7:43 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-05-16  7:42 [PATCH V4 0/9] Enable RTMR based measurement and measure boot for Td guest Min Xu
2022-05-16  7:42 ` [PATCH V4 1/9] Security: Add HashLibTdx Min Xu
2022-05-16  7:42 ` [PATCH V4 2/9] CryptoPkg: Add SecCryptLib Min Xu
2022-05-16  7:42 ` [PATCH V4 3/9] SecurityPkg: Add definition of EFI_CC_EVENT_HOB_GUID Min Xu
2022-05-16 16:28   ` [edk2-devel] " Sami Mujawar
2022-05-16  7:42 ` [PATCH V4 4/9] OvmfPkg: Introduce SecMeasurementLib Min Xu
2022-05-16  7:42 ` [PATCH V4 5/9] OvmfPkg/IntelTdx: Measure Td HobList and Configuration FV Min Xu
2022-06-10 13:22   ` Gerd Hoffmann
2022-06-12  9:21     ` Min Xu
2022-05-16  7:42 ` [PATCH V4 6/9] OvmfPkg: Add PCDs for LAML/LASA field in CC EVENTLOG ACPI table Min Xu
2022-05-16  7:42 ` [PATCH V4 7/9] MdePkg: Define CC Measure EventLog ACPI Table Min Xu
2022-05-16 16:29   ` [edk2-devel] " Sami Mujawar
2022-05-16  7:42 ` Min Xu [this message]
2022-05-16  7:42 ` [PATCH V4 9/9] OvmfPkg/IntelTdx: Enable RTMR based measurement and measure boot Min Xu
2022-06-03 11:53 ` [edk2-devel] [PATCH V4 0/9] Enable RTMR based measurement and measure boot for Td guest Yao, Jiewen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=56ce786fc58cae5110a68734183c0a930bc54fb3.1652686674.git.min.m.xu@intel.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox