]> git.proxmox.com Git - mirror_edk2.git/blobdiff - SecurityPkg/Tcg/TdTcg2Dxe/TdTcg2Dxe.c
SecurityPkg: Move TdTcg2Dxe from OvmfPkg to SecurityPkg
[mirror_edk2.git] / SecurityPkg / Tcg / TdTcg2Dxe / TdTcg2Dxe.c
diff --git a/SecurityPkg/Tcg/TdTcg2Dxe/TdTcg2Dxe.c b/SecurityPkg/Tcg/TdTcg2Dxe/TdTcg2Dxe.c
new file mode 100644 (file)
index 0000000..d19923b
--- /dev/null
@@ -0,0 +1,2520 @@
+/** @file\r
+  This module implements EFI TD Protocol.\r
+\r
+  Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include <PiDxe.h>\r
+#include <IndustryStandard/Acpi.h>\r
+#include <IndustryStandard/PeImage.h>\r
+#include <IndustryStandard/TcpaAcpi.h>\r
+\r
+#include <Guid/GlobalVariable.h>\r
+#include <Guid/HobList.h>\r
+#include <Guid/EventGroup.h>\r
+#include <Guid/EventExitBootServiceFailed.h>\r
+#include <Guid/ImageAuthentication.h>\r
+#include <Guid/TpmInstance.h>\r
+\r
+#include <Protocol/DevicePath.h>\r
+#include <Protocol/MpService.h>\r
+#include <Protocol/VariableWrite.h>\r
+#include <Protocol/Tcg2Protocol.h>\r
+#include <Protocol/TrEEProtocol.h>\r
+#include <Protocol/ResetNotification.h>\r
+#include <Protocol/AcpiTable.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/HobLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/PrintLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/HashLib.h>\r
+#include <Library/PerformanceLib.h>\r
+#include <Library/ReportStatusCodeLib.h>\r
+#include <Library/TpmMeasurementLib.h>\r
+\r
+#include <Protocol/CcMeasurement.h>\r
+#include <Guid/CcEventHob.h>\r
+#include <Library/TdxLib.h>\r
+\r
+#define PERF_ID_CC_TCG2_DXE  0x3130\r
+\r
+#define   CC_EVENT_LOG_AREA_COUNT_MAX  1\r
+#define   CC_MR_INDEX_0_MRTD           0\r
+#define   CC_MR_INDEX_1_RTMR0          1\r
+#define   CC_MR_INDEX_2_RTMR1          2\r
+#define   CC_MR_INDEX_3_RTMR2          3\r
+#define   CC_MR_INDEX_INVALID          4\r
+\r
+typedef struct {\r
+  CHAR16      *VariableName;\r
+  EFI_GUID    *VendorGuid;\r
+} VARIABLE_TYPE;\r
+\r
+typedef struct {\r
+  EFI_GUID                   *EventGuid;\r
+  EFI_CC_EVENT_LOG_FORMAT    LogFormat;\r
+} CC_EVENT_INFO_STRUCT;\r
+\r
+typedef struct {\r
+  EFI_CC_EVENT_LOG_FORMAT    EventLogFormat;\r
+  EFI_PHYSICAL_ADDRESS       Lasa;\r
+  UINT64                     Laml;\r
+  UINTN                      EventLogSize;\r
+  UINT8                      *LastEvent;\r
+  BOOLEAN                    EventLogStarted;\r
+  BOOLEAN                    EventLogTruncated;\r
+  UINTN                      Next800155EventOffset;\r
+} CC_EVENT_LOG_AREA_STRUCT;\r
+\r
+typedef struct _TDX_DXE_DATA {\r
+  EFI_CC_BOOT_SERVICE_CAPABILITY    BsCap;\r
+  CC_EVENT_LOG_AREA_STRUCT          EventLogAreaStruct[CC_EVENT_LOG_AREA_COUNT_MAX];\r
+  BOOLEAN                           GetEventLogCalled[CC_EVENT_LOG_AREA_COUNT_MAX];\r
+  CC_EVENT_LOG_AREA_STRUCT          FinalEventLogAreaStruct[CC_EVENT_LOG_AREA_COUNT_MAX];\r
+  EFI_CC_FINAL_EVENTS_TABLE         *FinalEventsTable[CC_EVENT_LOG_AREA_COUNT_MAX];\r
+} TDX_DXE_DATA;\r
+\r
+typedef struct {\r
+  TPMI_ALG_HASH    HashAlgo;\r
+  UINT16           HashSize;\r
+  UINT32           HashMask;\r
+} TDX_HASH_INFO;\r
+\r
+//\r
+//\r
+CC_EVENT_INFO_STRUCT  mCcEventInfo[] = {\r
+  { &gCcEventEntryHobGuid, EFI_CC_EVENT_LOG_FORMAT_TCG_2 },\r
+};\r
+\r
+TDX_DXE_DATA  mTdxDxeData = {\r
+  {\r
+    sizeof (EFI_CC_BOOT_SERVICE_CAPABILITY), // Size\r
+    { 1, 1 },                                // StructureVersion\r
+    { 1, 1 },                                // ProtocolVersion\r
+    EFI_CC_BOOT_HASH_ALG_SHA384,             // HashAlgorithmBitmap\r
+    EFI_CC_EVENT_LOG_FORMAT_TCG_2,           // SupportedEventLogs\r
+    { 2, 0 }                                 // {CC_TYPE, CC_SUBTYPE}\r
+  },\r
+};\r
+\r
+UINTN   mBootAttempts  = 0;\r
+CHAR16  mBootVarName[] = L"BootOrder";\r
+\r
+VARIABLE_TYPE  mVariableType[] = {\r
+  { EFI_SECURE_BOOT_MODE_NAME,    &gEfiGlobalVariableGuid        },\r
+  { EFI_PLATFORM_KEY_NAME,        &gEfiGlobalVariableGuid        },\r
+  { EFI_KEY_EXCHANGE_KEY_NAME,    &gEfiGlobalVariableGuid        },\r
+  { EFI_IMAGE_SECURITY_DATABASE,  &gEfiImageSecurityDatabaseGuid },\r
+  { EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid },\r
+};\r
+\r
+EFI_CC_EVENTLOG_ACPI_TABLE  mTdxEventlogAcpiTemplate = {\r
+  {\r
+    EFI_CC_EVENTLOG_ACPI_TABLE_SIGNATURE,\r
+    sizeof (mTdxEventlogAcpiTemplate),\r
+    EFI_CC_EVENTLOG_ACPI_TABLE_REVISION,\r
+    //\r
+    // Compiler initializes the remaining bytes to 0\r
+    // These fields should be filled in production\r
+    //\r
+  },\r
+  { EFI_CC_TYPE_TDX, 0 }, // CcType\r
+  0,                      // rsvd\r
+  0,                      // laml\r
+  0,                      // lasa\r
+};\r
+\r
+//\r
+// Supported Hash list in Td guest.\r
+// Currently SHA384 is supported.\r
+//\r
+TDX_HASH_INFO  mHashInfo[] = {\r
+  { TPM_ALG_SHA384, SHA384_DIGEST_SIZE, HASH_ALG_SHA384 }\r
+};\r
+\r
+/**\r
+  Get hash size based on Algo\r
+\r
+  @param[in]     HashAlgo           Hash Algorithm Id.\r
+\r
+  @return Size of the hash.\r
+**/\r
+UINT16\r
+GetHashSizeFromAlgo (\r
+  IN TPMI_ALG_HASH  HashAlgo\r
+  )\r
+{\r
+  UINTN  Index;\r
+\r
+  for (Index = 0; Index < sizeof (mHashInfo)/sizeof (mHashInfo[0]); Index++) {\r
+    if (mHashInfo[Index].HashAlgo == HashAlgo) {\r
+      return mHashInfo[Index].HashSize;\r
+    }\r
+  }\r
+\r
+  return 0;\r
+}\r
+\r
+/**\r
+  Get hash mask based on Algo\r
+\r
+  @param[in]     HashAlgo           Hash Algorithm Id.\r
+\r
+  @return Hash mask.\r
+**/\r
+UINT32\r
+GetHashMaskFromAlgo (\r
+  IN TPMI_ALG_HASH  HashAlgo\r
+  )\r
+{\r
+  UINTN  Index;\r
+\r
+  for (Index = 0; Index < ARRAY_SIZE (mHashInfo); Index++) {\r
+    if (mHashInfo[Index].HashAlgo == HashAlgo) {\r
+      return mHashInfo[Index].HashMask;\r
+    }\r
+  }\r
+\r
+  ASSERT (FALSE);\r
+  return 0;\r
+}\r
+\r
+/**\r
+  Copy TPML_DIGEST_VALUES into a buffer\r
+\r
+  @param[in,out] Buffer             Buffer to hold copied TPML_DIGEST_VALUES compact binary.\r
+  @param[in]     DigestList         TPML_DIGEST_VALUES to be copied.\r
+  @param[in]     HashAlgorithmMask  HASH bits corresponding to the desired digests to copy.\r
+\r
+  @return The end of buffer to hold TPML_DIGEST_VALUES.\r
+**/\r
+VOID *\r
+CopyDigestListToBuffer (\r
+  IN OUT VOID            *Buffer,\r
+  IN TPML_DIGEST_VALUES  *DigestList,\r
+  IN UINT32              HashAlgorithmMask\r
+  )\r
+{\r
+  UINTN   Index;\r
+  UINT16  DigestSize;\r
+  UINT32  DigestListCount;\r
+  UINT32  *DigestListCountPtr;\r
+\r
+  DigestListCountPtr = (UINT32 *)Buffer;\r
+  DigestListCount    = 0;\r
+  Buffer             = (UINT8 *)Buffer + sizeof (DigestList->count);\r
+  for (Index = 0; Index < DigestList->count; Index++) {\r
+    if ((DigestList->digests[Index].hashAlg & HashAlgorithmMask) == 0) {\r
+      DEBUG ((DEBUG_ERROR, "WARNING: TD Event log has HashAlg unsupported (0x%x)\n", DigestList->digests[Index].hashAlg));\r
+      continue;\r
+    }\r
+\r
+    CopyMem (Buffer, &DigestList->digests[Index].hashAlg, sizeof (DigestList->digests[Index].hashAlg));\r
+    Buffer     = (UINT8 *)Buffer + sizeof (DigestList->digests[Index].hashAlg);\r
+    DigestSize = GetHashSizeFromAlgo (DigestList->digests[Index].hashAlg);\r
+    CopyMem (Buffer, &DigestList->digests[Index].digest, DigestSize);\r
+    Buffer = (UINT8 *)Buffer + DigestSize;\r
+    DigestListCount++;\r
+  }\r
+\r
+  WriteUnaligned32 (DigestListCountPtr, DigestListCount);\r
+\r
+  return Buffer;\r
+}\r
+\r
+EFI_HANDLE  mImageHandle;\r
+\r
+/**\r
+  Measure PE image into TPM log based on the authenticode image hashing in\r
+  PE/COFF Specification 8.0 Appendix A.\r
+\r
+  Caution: This function may receive untrusted input.\r
+  PE/COFF image is external input, so this function will validate its data structure\r
+  within this image buffer before use.\r
+\r
+  Notes: PE/COFF image is checked by BasePeCoffLib PeCoffLoaderGetImageInfo().\r
+\r
+  @param[in]  RtmrIndex        RTMR index\r
+  @param[in]  ImageAddress   Start address of image buffer.\r
+  @param[in]  ImageSize      Image size\r
+  @param[out] DigestList     Digest list of this image.\r
+\r
+  @retval EFI_SUCCESS            Successfully measure image.\r
+  @retval EFI_OUT_OF_RESOURCES   No enough resource to measure image.\r
+  @retval other error value\r
+**/\r
+EFI_STATUS\r
+MeasurePeImageAndExtend (\r
+  IN  UINT32                RtmrIndex,\r
+  IN  EFI_PHYSICAL_ADDRESS  ImageAddress,\r
+  IN  UINTN                 ImageSize,\r
+  OUT TPML_DIGEST_VALUES    *DigestList\r
+  );\r
+\r
+#define COLUME_SIZE  (16 * 2)\r
+\r
+/**\r
+\r
+  This function dump raw data.\r
+\r
+  @param  Data  raw data\r
+  @param  Size  raw data size\r
+\r
+**/\r
+VOID\r
+InternalDumpData (\r
+  IN UINT8  *Data,\r
+  IN UINTN  Size\r
+  )\r
+{\r
+  UINTN  Index;\r
+\r
+  for (Index = 0; Index < Size; Index++) {\r
+    DEBUG ((DEBUG_INFO, Index == COLUME_SIZE/2 ? " | %02x" : " %02x", (UINTN)Data[Index]));\r
+  }\r
+}\r
+\r
+/**\r
+\r
+  This function dump raw data with colume format.\r
+\r
+  @param  Data  raw data\r
+  @param  Size  raw data size\r
+\r
+**/\r
+VOID\r
+InternalDumpHex (\r
+  IN UINT8  *Data,\r
+  IN UINTN  Size\r
+  )\r
+{\r
+  UINTN  Index;\r
+  UINTN  Count;\r
+  UINTN  Left;\r
+\r
+  Count = Size / COLUME_SIZE;\r
+  Left  = Size % COLUME_SIZE;\r
+  for (Index = 0; Index < Count; Index++) {\r
+    DEBUG ((DEBUG_INFO, "%04x: ", Index * COLUME_SIZE));\r
+    InternalDumpData (Data + Index * COLUME_SIZE, COLUME_SIZE);\r
+    DEBUG ((DEBUG_INFO, "\n"));\r
+  }\r
+\r
+  if (Left != 0) {\r
+    DEBUG ((DEBUG_INFO, "%04x: ", Index * COLUME_SIZE));\r
+    InternalDumpData (Data + Index * COLUME_SIZE, Left);\r
+    DEBUG ((DEBUG_INFO, "\n"));\r
+  }\r
+}\r
+\r
+/**\r
+\r
+  This function initialize TD_EVENT_HDR for EV_NO_ACTION\r
+  Event Type other than EFI Specification ID event. The behavior is defined\r
+  by TCG PC Client PFP Spec. Section 9.3.4 EV_NO_ACTION Event Types\r
+\r
+  @param[in, out]   NoActionEvent  Event Header of EV_NO_ACTION Event\r
+  @param[in]        EventSize      Event Size of the EV_NO_ACTION Event\r
+\r
+**/\r
+VOID\r
+InitNoActionEvent (\r
+  IN OUT CC_EVENT_HDR  *NoActionEvent,\r
+  IN UINT32            EventSize\r
+  )\r
+{\r
+  UINT32         DigestListCount;\r
+  TPMI_ALG_HASH  HashAlgId;\r
+  UINT8          *DigestBuffer;\r
+\r
+  DigestBuffer    = (UINT8 *)NoActionEvent->Digests.digests;\r
+  DigestListCount = 0;\r
+\r
+  NoActionEvent->MrIndex   = 0;\r
+  NoActionEvent->EventType = EV_NO_ACTION;\r
+\r
+  //\r
+  // Set Hash count & hashAlg accordingly, while Digest.digests[n].digest to all 0\r
+  //\r
+  ZeroMem (&NoActionEvent->Digests, sizeof (NoActionEvent->Digests));\r
+\r
+  if ((mTdxDxeData.BsCap.HashAlgorithmBitmap & EFI_CC_BOOT_HASH_ALG_SHA384) != 0) {\r
+    HashAlgId = TPM_ALG_SHA384;\r
+    CopyMem (DigestBuffer, &HashAlgId, sizeof (TPMI_ALG_HASH));\r
+    DigestBuffer += sizeof (TPMI_ALG_HASH) + GetHashSizeFromAlgo (HashAlgId);\r
+    DigestListCount++;\r
+  }\r
+\r
+  //\r
+  // Set Digests Count\r
+  //\r
+  WriteUnaligned32 ((UINT32 *)&NoActionEvent->Digests.count, DigestListCount);\r
+\r
+  //\r
+  // Set Event Size\r
+  //\r
+  WriteUnaligned32 ((UINT32 *)DigestBuffer, EventSize);\r
+}\r
+\r
+/**\r
+  Get All processors EFI_CPU_LOCATION in system. LocationBuf is allocated inside the function\r
+  Caller is responsible to free LocationBuf.\r
+\r
+  @param[out] LocationBuf          Returns Processor Location Buffer.\r
+  @param[out] Num                  Returns processor number.\r
+\r
+  @retval EFI_SUCCESS              Operation completed successfully.\r
+  @retval EFI_UNSUPPORTED       MpService protocol not found.\r
+\r
+**/\r
+EFI_STATUS\r
+GetProcessorsCpuLocation (\r
+  OUT  EFI_CPU_PHYSICAL_LOCATION  **LocationBuf,\r
+  OUT  UINTN                      *Num\r
+  )\r
+{\r
+  EFI_STATUS                 Status;\r
+  EFI_MP_SERVICES_PROTOCOL   *MpProtocol;\r
+  UINTN                      ProcessorNum;\r
+  UINTN                      EnabledProcessorNum;\r
+  EFI_PROCESSOR_INFORMATION  ProcessorInfo;\r
+  EFI_CPU_PHYSICAL_LOCATION  *ProcessorLocBuf;\r
+  UINTN                      Index;\r
+\r
+  Status = gBS->LocateProtocol (&gEfiMpServiceProtocolGuid, NULL, (VOID **)&MpProtocol);\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // MP protocol is not installed\r
+    //\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  Status = MpProtocol->GetNumberOfProcessors (\r
+                         MpProtocol,\r
+                         &ProcessorNum,\r
+                         &EnabledProcessorNum\r
+                         );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = gBS->AllocatePool (\r
+                  EfiBootServicesData,\r
+                  sizeof (EFI_CPU_PHYSICAL_LOCATION) * ProcessorNum,\r
+                  (VOID **)&ProcessorLocBuf\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Get each processor Location info\r
+  //\r
+  for (Index = 0; Index < ProcessorNum; Index++) {\r
+    Status = MpProtocol->GetProcessorInfo (\r
+                           MpProtocol,\r
+                           Index,\r
+                           &ProcessorInfo\r
+                           );\r
+    if (EFI_ERROR (Status)) {\r
+      FreePool (ProcessorLocBuf);\r
+      return Status;\r
+    }\r
+\r
+    //\r
+    // Get all Processor Location info & measure\r
+    //\r
+    CopyMem (\r
+      &ProcessorLocBuf[Index],\r
+      &ProcessorInfo.Location,\r
+      sizeof (EFI_CPU_PHYSICAL_LOCATION)\r
+      );\r
+  }\r
+\r
+  *LocationBuf = ProcessorLocBuf;\r
+  *Num         = ProcessorNum;\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  The EFI_CC_MEASUREMENT_PROTOCOL GetCapability function call provides protocol\r
+  capability information and state information.\r
+\r
+  @param[in]      This               Indicates the calling context\r
+  @param[in, out] ProtocolCapability The caller allocates memory for a EFI_CC_BOOT_SERVICE_CAPABILITY\r
+                                     structure and sets the size field to the size of the structure allocated.\r
+                                     The callee fills in the fields with the EFI protocol capability information\r
+                                     and the current EFI TCG2 state information up to the number of fields which\r
+                                     fit within the size of the structure passed in.\r
+\r
+  @retval EFI_SUCCESS            Operation completed successfully.\r
+  @retval EFI_DEVICE_ERROR       The command was unsuccessful.\r
+                                 The ProtocolCapability variable will not be populated.\r
+  @retval EFI_INVALID_PARAMETER  One or more of the parameters are incorrect.\r
+                                 The ProtocolCapability variable will not be populated.\r
+  @retval EFI_BUFFER_TOO_SMALL   The ProtocolCapability variable is too small to hold the full response.\r
+                                 It will be partially populated (required Size field will be set).\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TdGetCapability (\r
+  IN EFI_CC_MEASUREMENT_PROTOCOL         *This,\r
+  IN OUT EFI_CC_BOOT_SERVICE_CAPABILITY  *ProtocolCapability\r
+  )\r
+{\r
+  DEBUG ((DEBUG_VERBOSE, "TdGetCapability\n"));\r
+\r
+  if ((This == NULL) || (ProtocolCapability == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  CopyMem (ProtocolCapability, &mTdxDxeData.BsCap, sizeof (EFI_CC_BOOT_SERVICE_CAPABILITY));\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  This function dump PCR event.\r
+  TD Event log reuse the TCG PCR Event spec.\r
+  The first event in the event log is the SHA1 log format.\r
+  There is only ONE TCG_PCR_EVENT in TD Event log.\r
+\r
+  @param[in]  EventHdr     TCG PCR event structure.\r
+**/\r
+VOID\r
+DumpPcrEvent (\r
+  IN TCG_PCR_EVENT_HDR  *EventHdr\r
+  )\r
+{\r
+  UINTN  Index;\r
+\r
+  DEBUG ((DEBUG_INFO, "  Event:\n"));\r
+  DEBUG ((DEBUG_INFO, "    MrIndex  - %d\n", EventHdr->PCRIndex));\r
+  DEBUG ((DEBUG_INFO, "    EventType - 0x%08x\n", EventHdr->EventType));\r
+  DEBUG ((DEBUG_INFO, "    Digest    - "));\r
+  for (Index = 0; Index < sizeof (TCG_DIGEST); Index++) {\r
+    DEBUG ((DEBUG_INFO, "%02x ", EventHdr->Digest.digest[Index]));\r
+  }\r
+\r
+  DEBUG ((DEBUG_INFO, "\n"));\r
+  DEBUG ((DEBUG_INFO, "    EventSize - 0x%08x\n", EventHdr->EventSize));\r
+  InternalDumpHex ((UINT8 *)(EventHdr + 1), EventHdr->EventSize);\r
+}\r
+\r
+/**\r
+  This function dump TCG_EfiSpecIDEventStruct.\r
+\r
+  @param[in]  TcgEfiSpecIdEventStruct     A pointer to TCG_EfiSpecIDEventStruct.\r
+**/\r
+VOID\r
+DumpTcgEfiSpecIdEventStruct (\r
+  IN TCG_EfiSpecIDEventStruct  *TcgEfiSpecIdEventStruct\r
+  )\r
+{\r
+  TCG_EfiSpecIdEventAlgorithmSize  *DigestSize;\r
+  UINTN                            Index;\r
+  UINT8                            *VendorInfoSize;\r
+  UINT8                            *VendorInfo;\r
+  UINT32                           NumberOfAlgorithms;\r
+\r
+  DEBUG ((DEBUG_INFO, "  TCG_EfiSpecIDEventStruct:\n"));\r
+  DEBUG ((DEBUG_INFO, "    signature          - '"));\r
+  for (Index = 0; Index < sizeof (TcgEfiSpecIdEventStruct->signature); Index++) {\r
+    DEBUG ((DEBUG_INFO, "%c", TcgEfiSpecIdEventStruct->signature[Index]));\r
+  }\r
+\r
+  DEBUG ((DEBUG_INFO, "'\n"));\r
+  DEBUG ((DEBUG_INFO, "    platformClass      - 0x%08x\n", TcgEfiSpecIdEventStruct->platformClass));\r
+  DEBUG ((DEBUG_INFO, "    specVersion        - %d.%d%d\n", TcgEfiSpecIdEventStruct->specVersionMajor, TcgEfiSpecIdEventStruct->specVersionMinor, TcgEfiSpecIdEventStruct->specErrata));\r
+  DEBUG ((DEBUG_INFO, "    uintnSize          - 0x%02x\n", TcgEfiSpecIdEventStruct->uintnSize));\r
+\r
+  CopyMem (&NumberOfAlgorithms, TcgEfiSpecIdEventStruct + 1, sizeof (NumberOfAlgorithms));\r
+  DEBUG ((DEBUG_INFO, "    NumberOfAlgorithms - 0x%08x\n", NumberOfAlgorithms));\r
+\r
+  DigestSize = (TCG_EfiSpecIdEventAlgorithmSize *)((UINT8 *)TcgEfiSpecIdEventStruct + sizeof (*TcgEfiSpecIdEventStruct) + sizeof (NumberOfAlgorithms));\r
+  for (Index = 0; Index < NumberOfAlgorithms; Index++) {\r
+    DEBUG ((DEBUG_INFO, "    digest(%d)\n", Index));\r
+    DEBUG ((DEBUG_INFO, "      algorithmId      - 0x%04x\n", DigestSize[Index].algorithmId));\r
+    DEBUG ((DEBUG_INFO, "      digestSize       - 0x%04x\n", DigestSize[Index].digestSize));\r
+  }\r
+\r
+  VendorInfoSize = (UINT8 *)&DigestSize[NumberOfAlgorithms];\r
+  DEBUG ((DEBUG_INFO, "    VendorInfoSize     - 0x%02x\n", *VendorInfoSize));\r
+  VendorInfo = VendorInfoSize + 1;\r
+  DEBUG ((DEBUG_INFO, "    VendorInfo         - "));\r
+  for (Index = 0; Index < *VendorInfoSize; Index++) {\r
+    DEBUG ((DEBUG_INFO, "%02x ", VendorInfo[Index]));\r
+  }\r
+\r
+  DEBUG ((DEBUG_INFO, "\n"));\r
+}\r
+\r
+/**\r
+  This function get size of TCG_EfiSpecIDEventStruct.\r
+\r
+  @param[in]  TcgEfiSpecIdEventStruct     A pointer to TCG_EfiSpecIDEventStruct.\r
+**/\r
+UINTN\r
+GetTcgEfiSpecIdEventStructSize (\r
+  IN TCG_EfiSpecIDEventStruct  *TcgEfiSpecIdEventStruct\r
+  )\r
+{\r
+  TCG_EfiSpecIdEventAlgorithmSize  *DigestSize;\r
+  UINT8                            *VendorInfoSize;\r
+  UINT32                           NumberOfAlgorithms;\r
+\r
+  CopyMem (&NumberOfAlgorithms, TcgEfiSpecIdEventStruct + 1, sizeof (NumberOfAlgorithms));\r
+\r
+  DigestSize     = (TCG_EfiSpecIdEventAlgorithmSize *)((UINT8 *)TcgEfiSpecIdEventStruct + sizeof (*TcgEfiSpecIdEventStruct) + sizeof (NumberOfAlgorithms));\r
+  VendorInfoSize = (UINT8 *)&DigestSize[NumberOfAlgorithms];\r
+  return sizeof (TCG_EfiSpecIDEventStruct) + sizeof (UINT32) + (NumberOfAlgorithms * sizeof (TCG_EfiSpecIdEventAlgorithmSize)) + sizeof (UINT8) + (*VendorInfoSize);\r
+}\r
+\r
+/**\r
+  This function dump TD Event (including the Digests).\r
+\r
+  @param[in]  CcEvent     TD Event structure.\r
+**/\r
+VOID\r
+DumpCcEvent (\r
+  IN CC_EVENT  *CcEvent\r
+  )\r
+{\r
+  UINT32         DigestIndex;\r
+  UINT32         DigestCount;\r
+  TPMI_ALG_HASH  HashAlgo;\r
+  UINT32         DigestSize;\r
+  UINT8          *DigestBuffer;\r
+  UINT32         EventSize;\r
+  UINT8          *EventBuffer;\r
+\r
+  DEBUG ((DEBUG_INFO, "Cc Event:\n"));\r
+  DEBUG ((DEBUG_INFO, "    MrIndex  - %d\n", CcEvent->MrIndex));\r
+  DEBUG ((DEBUG_INFO, "    EventType - 0x%08x\n", CcEvent->EventType));\r
+  DEBUG ((DEBUG_INFO, "    DigestCount: 0x%08x\n", CcEvent->Digests.count));\r
+\r
+  DigestCount  = CcEvent->Digests.count;\r
+  HashAlgo     = CcEvent->Digests.digests[0].hashAlg;\r
+  DigestBuffer = (UINT8 *)&CcEvent->Digests.digests[0].digest;\r
+  for (DigestIndex = 0; DigestIndex < DigestCount; DigestIndex++) {\r
+    DEBUG ((DEBUG_INFO, "      HashAlgo : 0x%04x\n", HashAlgo));\r
+    DEBUG ((DEBUG_INFO, "      Digest(%d): \n", DigestIndex));\r
+    DigestSize = GetHashSizeFromAlgo (HashAlgo);\r
+    InternalDumpHex (DigestBuffer, DigestSize);\r
+    //\r
+    // Prepare next\r
+    //\r
+    CopyMem (&HashAlgo, DigestBuffer + DigestSize, sizeof (TPMI_ALG_HASH));\r
+    DigestBuffer = DigestBuffer + DigestSize + sizeof (TPMI_ALG_HASH);\r
+  }\r
+\r
+  DigestBuffer = DigestBuffer - sizeof (TPMI_ALG_HASH);\r
+\r
+  CopyMem (&EventSize, DigestBuffer, sizeof (CcEvent->EventSize));\r
+  DEBUG ((DEBUG_INFO, "    EventSize - 0x%08x\n", EventSize));\r
+  EventBuffer = DigestBuffer + sizeof (CcEvent->EventSize);\r
+  InternalDumpHex (EventBuffer, EventSize);\r
+  DEBUG ((DEBUG_INFO, "\n"));\r
+}\r
+\r
+/**\r
+  This function returns size of Td Table event.\r
+\r
+  @param[in]  CcEvent     Td Table event structure.\r
+\r
+  @return size of Td event.\r
+**/\r
+UINTN\r
+GetCcEventSize (\r
+  IN CC_EVENT  *CcEvent\r
+  )\r
+{\r
+  UINT32         DigestIndex;\r
+  UINT32         DigestCount;\r
+  TPMI_ALG_HASH  HashAlgo;\r
+  UINT32         DigestSize;\r
+  UINT8          *DigestBuffer;\r
+  UINT32         EventSize;\r
+  UINT8          *EventBuffer;\r
+\r
+  DigestCount  = CcEvent->Digests.count;\r
+  HashAlgo     = CcEvent->Digests.digests[0].hashAlg;\r
+  DigestBuffer = (UINT8 *)&CcEvent->Digests.digests[0].digest;\r
+  for (DigestIndex = 0; DigestIndex < DigestCount; DigestIndex++) {\r
+    DigestSize = GetHashSizeFromAlgo (HashAlgo);\r
+    //\r
+    // Prepare next\r
+    //\r
+    CopyMem (&HashAlgo, DigestBuffer + DigestSize, sizeof (TPMI_ALG_HASH));\r
+    DigestBuffer = DigestBuffer + DigestSize + sizeof (TPMI_ALG_HASH);\r
+  }\r
+\r
+  DigestBuffer = DigestBuffer - sizeof (TPMI_ALG_HASH);\r
+\r
+  CopyMem (&EventSize, DigestBuffer, sizeof (CcEvent->EventSize));\r
+  EventBuffer = DigestBuffer + sizeof (CcEvent->EventSize);\r
+\r
+  return (UINTN)EventBuffer + EventSize - (UINTN)CcEvent;\r
+}\r
+\r
+/**\r
+  This function dump CC event log.\r
+  TDVF only supports EFI_CC_EVENT_LOG_FORMAT_TCG_2\r
+\r
+  @param[in]  EventLogFormat     The type of the event log for which the information is requested.\r
+  @param[in]  EventLogLocation   A pointer to the memory address of the event log.\r
+  @param[in]  EventLogLastEntry  If the Event Log contains more than one entry, this is a pointer to the\r
+                                 address of the start of the last entry in the event log in memory.\r
+  @param[in]  FinalEventsTable   A pointer to the memory address of the final event table.\r
+**/\r
+VOID\r
+DumpCcEventLog (\r
+  IN EFI_CC_EVENT_LOG_FORMAT    EventLogFormat,\r
+  IN EFI_PHYSICAL_ADDRESS       EventLogLocation,\r
+  IN EFI_PHYSICAL_ADDRESS       EventLogLastEntry,\r
+  IN EFI_CC_FINAL_EVENTS_TABLE  *FinalEventsTable\r
+  )\r
+{\r
+  TCG_PCR_EVENT_HDR         *EventHdr;\r
+  CC_EVENT                  *CcEvent;\r
+  TCG_EfiSpecIDEventStruct  *TcgEfiSpecIdEventStruct;\r
+  UINTN                     NumberOfEvents;\r
+\r
+  DEBUG ((DEBUG_INFO, "EventLogFormat: (0x%x)\n", EventLogFormat));\r
+  ASSERT (EventLogFormat == EFI_CC_EVENT_LOG_FORMAT_TCG_2);\r
+\r
+  //\r
+  // Dump first event.\r
+  // The first event is always the TCG_PCR_EVENT_HDR\r
+  // After this event is a TCG_EfiSpecIDEventStruct\r
+  //\r
+  EventHdr = (TCG_PCR_EVENT_HDR *)(UINTN)EventLogLocation;\r
+  DumpPcrEvent (EventHdr);\r
+\r
+  TcgEfiSpecIdEventStruct = (TCG_EfiSpecIDEventStruct *)(EventHdr + 1);\r
+  DumpTcgEfiSpecIdEventStruct (TcgEfiSpecIdEventStruct);\r
+\r
+  //\r
+  // Then the CcEvent (Its structure is similar to TCG_PCR_EVENT2)\r
+  //\r
+  CcEvent = (CC_EVENT *)((UINTN)TcgEfiSpecIdEventStruct + GetTcgEfiSpecIdEventStructSize (TcgEfiSpecIdEventStruct));\r
+  while ((UINTN)CcEvent <= EventLogLastEntry) {\r
+    DumpCcEvent (CcEvent);\r
+    CcEvent = (CC_EVENT *)((UINTN)CcEvent + GetCcEventSize (CcEvent));\r
+  }\r
+\r
+  if (FinalEventsTable == NULL) {\r
+    DEBUG ((DEBUG_INFO, "FinalEventsTable: NOT FOUND\n"));\r
+  } else {\r
+    DEBUG ((DEBUG_INFO, "FinalEventsTable:    (0x%x)\n", FinalEventsTable));\r
+    DEBUG ((DEBUG_INFO, "  Version:           (0x%x)\n", FinalEventsTable->Version));\r
+    DEBUG ((DEBUG_INFO, "  NumberOfEvents:    (0x%x)\n", FinalEventsTable->NumberOfEvents));\r
+\r
+    CcEvent = (CC_EVENT *)(UINTN)(FinalEventsTable + 1);\r
+    for (NumberOfEvents = 0; NumberOfEvents < FinalEventsTable->NumberOfEvents; NumberOfEvents++) {\r
+      DumpCcEvent (CcEvent);\r
+      CcEvent = (CC_EVENT *)((UINTN)CcEvent + GetCcEventSize (CcEvent));\r
+    }\r
+  }\r
+\r
+  return;\r
+}\r
+\r
+/**\r
+  The EFI_CC_MEASUREMENT_PROTOCOL Get Event Log function call allows a caller to\r
+  retrieve the address of a given event log and its last entry.\r
+\r
+  @param[in]  This               Indicates the calling context\r
+  @param[in]  EventLogFormat     The type of the event log for which the information is requested.\r
+  @param[out] EventLogLocation   A pointer to the memory address of the event log.\r
+  @param[out] EventLogLastEntry  If the Event Log contains more than one entry, this is a pointer to the\r
+                                 address of the start of the last entry in the event log in memory.\r
+  @param[out] EventLogTruncated  If the Event Log is missing at least one entry because an event would\r
+                                 have exceeded the area allocated for events, this value is set to TRUE.\r
+                                 Otherwise, the value will be FALSE and the Event Log will be complete.\r
+\r
+  @retval EFI_SUCCESS            Operation completed successfully.\r
+  @retval EFI_INVALID_PARAMETER  One or more of the parameters are incorrect\r
+                                 (e.g. asking for an event log whose format is not supported).\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TdGetEventLog (\r
+  IN EFI_CC_MEASUREMENT_PROTOCOL  *This,\r
+  IN EFI_CC_EVENT_LOG_FORMAT      EventLogFormat,\r
+  OUT EFI_PHYSICAL_ADDRESS        *EventLogLocation,\r
+  OUT EFI_PHYSICAL_ADDRESS        *EventLogLastEntry,\r
+  OUT BOOLEAN                     *EventLogTruncated\r
+  )\r
+{\r
+  UINTN  Index = 0;\r
+\r
+  DEBUG ((DEBUG_INFO, "TdGetEventLog ... (0x%x)\n", EventLogFormat));\r
+  ASSERT (EventLogFormat == EFI_CC_EVENT_LOG_FORMAT_TCG_2);\r
+\r
+  if (EventLogLocation != NULL) {\r
+    *EventLogLocation = mTdxDxeData.EventLogAreaStruct[Index].Lasa;\r
+    DEBUG ((DEBUG_INFO, "TdGetEventLog (EventLogLocation - %x)\n", *EventLogLocation));\r
+  }\r
+\r
+  if (EventLogLastEntry != NULL) {\r
+    if (!mTdxDxeData.EventLogAreaStruct[Index].EventLogStarted) {\r
+      *EventLogLastEntry = (EFI_PHYSICAL_ADDRESS)(UINTN)0;\r
+    } else {\r
+      *EventLogLastEntry = (EFI_PHYSICAL_ADDRESS)(UINTN)mTdxDxeData.EventLogAreaStruct[Index].LastEvent;\r
+    }\r
+\r
+    DEBUG ((DEBUG_INFO, "TdGetEventLog (EventLogLastEntry - %x)\n", *EventLogLastEntry));\r
+  }\r
+\r
+  if (EventLogTruncated != NULL) {\r
+    *EventLogTruncated = mTdxDxeData.EventLogAreaStruct[Index].EventLogTruncated;\r
+    DEBUG ((DEBUG_INFO, "TdGetEventLog (EventLogTruncated - %x)\n", *EventLogTruncated));\r
+  }\r
+\r
+  DEBUG ((DEBUG_INFO, "TdGetEventLog - %r\n", EFI_SUCCESS));\r
+\r
+  // Dump Event Log for debug purpose\r
+  if ((EventLogLocation != NULL) && (EventLogLastEntry != NULL)) {\r
+    DumpCcEventLog (EventLogFormat, *EventLogLocation, *EventLogLastEntry, mTdxDxeData.FinalEventsTable[Index]);\r
+  }\r
+\r
+  //\r
+  // All events generated after the invocation of EFI_TCG2_GET_EVENT_LOG SHALL be stored\r
+  // in an instance of an EFI_CONFIGURATION_TABLE named by the VendorGuid of EFI_TCG2_FINAL_EVENTS_TABLE_GUID.\r
+  //\r
+  mTdxDxeData.GetEventLogCalled[Index] = TRUE;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Return if this is a Tcg800155PlatformIdEvent.\r
+\r
+  @param[in]      NewEventHdr         Pointer to a TCG_PCR_EVENT_HDR/TCG_PCR_EVENT_EX data structure.\r
+  @param[in]      NewEventHdrSize     New event header size.\r
+  @param[in]      NewEventData        Pointer to the new event data.\r
+  @param[in]      NewEventSize        New event data size.\r
+\r
+  @retval TRUE   This is a Tcg800155PlatformIdEvent.\r
+  @retval FALSE  This is NOT a Tcg800155PlatformIdEvent.\r
+\r
+**/\r
+BOOLEAN\r
+Is800155Event (\r
+  IN      VOID    *NewEventHdr,\r
+  IN      UINT32  NewEventHdrSize,\r
+  IN      UINT8   *NewEventData,\r
+  IN      UINT32  NewEventSize\r
+  )\r
+{\r
+  if ((((TCG_PCR_EVENT2_HDR *)NewEventHdr)->EventType == EV_NO_ACTION) &&\r
+      (NewEventSize >= sizeof (TCG_Sp800_155_PlatformId_Event2)) &&\r
+      (CompareMem (\r
+         NewEventData,\r
+         TCG_Sp800_155_PlatformId_Event2_SIGNATURE,\r
+         sizeof (TCG_Sp800_155_PlatformId_Event2_SIGNATURE) - 1\r
+         ) == 0))\r
+  {\r
+    return TRUE;\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Add a new entry to the Event Log.\r
+\r
+  @param[in, out] EventLogAreaStruct  The event log area data structure\r
+  @param[in]      NewEventHdr         Pointer to a TCG_PCR_EVENT_HDR/TCG_PCR_EVENT_EX data structure.\r
+  @param[in]      NewEventHdrSize     New event header size.\r
+  @param[in]      NewEventData        Pointer to the new event data.\r
+  @param[in]      NewEventSize        New event data size.\r
+\r
+  @retval EFI_SUCCESS           The new event log entry was added.\r
+  @retval EFI_OUT_OF_RESOURCES  No enough memory to log the new event.\r
+\r
+**/\r
+EFI_STATUS\r
+TcgCommLogEvent (\r
+  IN OUT  CC_EVENT_LOG_AREA_STRUCT  *EventLogAreaStruct,\r
+  IN      VOID                      *NewEventHdr,\r
+  IN      UINT32                    NewEventHdrSize,\r
+  IN      UINT8                     *NewEventData,\r
+  IN      UINT32                    NewEventSize\r
+  )\r
+{\r
+  UINTN         NewLogSize;\r
+  BOOLEAN       Record800155Event;\r
+  CC_EVENT_HDR  *CcEventHdr;\r
+\r
+  CcEventHdr = (CC_EVENT_HDR *)NewEventHdr;\r
+  DEBUG ((DEBUG_VERBOSE, "Td: Try to log event. Index = %d, EventType = 0x%x\n", CcEventHdr->MrIndex, CcEventHdr->EventType));\r
+\r
+  if (NewEventSize > MAX_ADDRESS -  NewEventHdrSize) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  NewLogSize = NewEventHdrSize + NewEventSize;\r
+\r
+  if (NewLogSize > MAX_ADDRESS -  EventLogAreaStruct->EventLogSize) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  if (NewLogSize + EventLogAreaStruct->EventLogSize > EventLogAreaStruct->Laml) {\r
+    DEBUG ((DEBUG_INFO, "  Laml       - 0x%x\n", EventLogAreaStruct->Laml));\r
+    DEBUG ((DEBUG_INFO, "  NewLogSize - 0x%x\n", NewLogSize));\r
+    DEBUG ((DEBUG_INFO, "  LogSize    - 0x%x\n", EventLogAreaStruct->EventLogSize));\r
+    DEBUG ((DEBUG_INFO, "TcgCommLogEvent - %r\n", EFI_OUT_OF_RESOURCES));\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  //\r
+  // Check 800-155 event\r
+  // Record to 800-155 event offset only.\r
+  // If the offset is 0, no need to record.\r
+  //\r
+  Record800155Event = Is800155Event (NewEventHdr, NewEventHdrSize, NewEventData, NewEventSize);\r
+  if (Record800155Event) {\r
+    DEBUG ((DEBUG_INFO, "It is 800155Event.\n"));\r
+\r
+    if (EventLogAreaStruct->Next800155EventOffset != 0) {\r
+      CopyMem (\r
+        (UINT8 *)(UINTN)EventLogAreaStruct->Lasa + EventLogAreaStruct->Next800155EventOffset + NewLogSize,\r
+        (UINT8 *)(UINTN)EventLogAreaStruct->Lasa + EventLogAreaStruct->Next800155EventOffset,\r
+        EventLogAreaStruct->EventLogSize - EventLogAreaStruct->Next800155EventOffset\r
+        );\r
+\r
+      CopyMem (\r
+        (UINT8 *)(UINTN)EventLogAreaStruct->Lasa + EventLogAreaStruct->Next800155EventOffset,\r
+        NewEventHdr,\r
+        NewEventHdrSize\r
+        );\r
+      CopyMem (\r
+        (UINT8 *)(UINTN)EventLogAreaStruct->Lasa + EventLogAreaStruct->Next800155EventOffset + NewEventHdrSize,\r
+        NewEventData,\r
+        NewEventSize\r
+        );\r
+\r
+      EventLogAreaStruct->Next800155EventOffset += NewLogSize;\r
+      EventLogAreaStruct->LastEvent             += NewLogSize;\r
+      EventLogAreaStruct->EventLogSize          += NewLogSize;\r
+    }\r
+\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  EventLogAreaStruct->LastEvent     = (UINT8 *)(UINTN)EventLogAreaStruct->Lasa + EventLogAreaStruct->EventLogSize;\r
+  EventLogAreaStruct->EventLogSize += NewLogSize;\r
+\r
+  CopyMem (EventLogAreaStruct->LastEvent, NewEventHdr, NewEventHdrSize);\r
+  CopyMem (\r
+    EventLogAreaStruct->LastEvent + NewEventHdrSize,\r
+    NewEventData,\r
+    NewEventSize\r
+    );\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  According to UEFI Spec 2.10 Section 38.4.1:\r
+    The following table shows the TPM PCR index mapping and CC event log measurement\r
+  register index interpretation for Intel TDX, where MRTD means Trust Domain Measurement\r
+   Register and RTMR means Runtime Measurement Register\r
+\r
+    // TPM PCR Index | CC Measurement Register Index | TDX-measurement register\r
+    //  ------------------------------------------------------------------------\r
+    // 0             |   0                           |   MRTD\r
+    // 1, 7          |   1                           |   RTMR[0]\r
+    // 2~6           |   2                           |   RTMR[1]\r
+    // 8~15          |   3                           |   RTMR[2]\r
+\r
+  @param[in] PCRIndex Index of the TPM PCR\r
+\r
+  @retval    UINT32               Index of the CC Event Log Measurement Register Index\r
+  @retval    CC_MR_INDEX_INVALID  Invalid MR Index\r
+**/\r
+UINT32\r
+EFIAPI\r
+MapPcrToMrIndex (\r
+  IN  UINT32  PCRIndex\r
+  )\r
+{\r
+  UINT32  MrIndex;\r
+\r
+  if (PCRIndex > 15) {\r
+    ASSERT (FALSE);\r
+    return CC_MR_INDEX_INVALID;\r
+  }\r
+\r
+  MrIndex = 0;\r
+  if (PCRIndex == 0) {\r
+    MrIndex = CC_MR_INDEX_0_MRTD;\r
+  } else if ((PCRIndex == 1) || (PCRIndex == 7)) {\r
+    MrIndex = CC_MR_INDEX_1_RTMR0;\r
+  } else if ((PCRIndex >= 2) && (PCRIndex <= 6)) {\r
+    MrIndex = CC_MR_INDEX_2_RTMR1;\r
+  } else if ((PCRIndex >= 8) && (PCRIndex <= 15)) {\r
+    MrIndex = CC_MR_INDEX_3_RTMR2;\r
+  }\r
+\r
+  return MrIndex;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+TdMapPcrToMrIndex (\r
+  IN  EFI_CC_MEASUREMENT_PROTOCOL  *This,\r
+  IN  UINT32                       PCRIndex,\r
+  OUT UINT32                       *MrIndex\r
+  )\r
+{\r
+  if (MrIndex == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  *MrIndex = MapPcrToMrIndex (PCRIndex);\r
+\r
+  return *MrIndex == CC_MR_INDEX_INVALID ? EFI_INVALID_PARAMETER : EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Add a new entry to the Event Log.\r
+\r
+  @param[in] EventLogFormat  The type of the event log for which the information is requested.\r
+  @param[in] NewEventHdr     Pointer to a TCG_PCR_EVENT_HDR/TCG_PCR_EVENT_EX data structure.\r
+  @param[in] NewEventHdrSize New event header size.\r
+  @param[in] NewEventData    Pointer to the new event data.\r
+  @param[in] NewEventSize    New event data size.\r
+\r
+  @retval EFI_SUCCESS           The new event log entry was added.\r
+  @retval EFI_OUT_OF_RESOURCES  No enough memory to log the new event.\r
+\r
+**/\r
+EFI_STATUS\r
+TdxDxeLogEvent (\r
+  IN      EFI_CC_EVENT_LOG_FORMAT  EventLogFormat,\r
+  IN      VOID                     *NewEventHdr,\r
+  IN      UINT32                   NewEventHdrSize,\r
+  IN      UINT8                    *NewEventData,\r
+  IN      UINT32                   NewEventSize\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINTN                     Index;\r
+  CC_EVENT_LOG_AREA_STRUCT  *EventLogAreaStruct;\r
+\r
+  if (EventLogFormat != EFI_CC_EVENT_LOG_FORMAT_TCG_2) {\r
+    ASSERT (FALSE);\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Index = 0;\r
+\r
+  //\r
+  // Record to normal event log\r
+  //\r
+  EventLogAreaStruct = &mTdxDxeData.EventLogAreaStruct[Index];\r
+\r
+  if (EventLogAreaStruct->EventLogTruncated) {\r
+    return EFI_VOLUME_FULL;\r
+  }\r
+\r
+  Status = TcgCommLogEvent (\r
+             EventLogAreaStruct,\r
+             NewEventHdr,\r
+             NewEventHdrSize,\r
+             NewEventData,\r
+             NewEventSize\r
+             );\r
+\r
+  if (Status == EFI_OUT_OF_RESOURCES) {\r
+    EventLogAreaStruct->EventLogTruncated = TRUE;\r
+    return EFI_VOLUME_FULL;\r
+  } else if (Status == EFI_SUCCESS) {\r
+    EventLogAreaStruct->EventLogStarted = TRUE;\r
+  }\r
+\r
+  //\r
+  // If GetEventLog is called, record to FinalEventsTable, too.\r
+  //\r
+  if (mTdxDxeData.GetEventLogCalled[Index]) {\r
+    if (mTdxDxeData.FinalEventsTable[Index] == NULL) {\r
+      //\r
+      // no need for FinalEventsTable\r
+      //\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    EventLogAreaStruct = &mTdxDxeData.FinalEventLogAreaStruct[Index];\r
+\r
+    if (EventLogAreaStruct->EventLogTruncated) {\r
+      return EFI_VOLUME_FULL;\r
+    }\r
+\r
+    Status = TcgCommLogEvent (\r
+               EventLogAreaStruct,\r
+               NewEventHdr,\r
+               NewEventHdrSize,\r
+               NewEventData,\r
+               NewEventSize\r
+               );\r
+    if (Status == EFI_OUT_OF_RESOURCES) {\r
+      EventLogAreaStruct->EventLogTruncated = TRUE;\r
+      return EFI_VOLUME_FULL;\r
+    } else if (Status == EFI_SUCCESS) {\r
+      EventLogAreaStruct->EventLogStarted = TRUE;\r
+      //\r
+      // Increase the NumberOfEvents in FinalEventsTable\r
+      //\r
+      (mTdxDxeData.FinalEventsTable[Index])->NumberOfEvents++;\r
+      DEBUG ((DEBUG_INFO, "FinalEventsTable->NumberOfEvents - 0x%x\n", (mTdxDxeData.FinalEventsTable[Index])->NumberOfEvents));\r
+      DEBUG ((DEBUG_INFO, "  Size - 0x%x\n", (UINTN)EventLogAreaStruct->EventLogSize));\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Get TPML_DIGEST_VALUES compact binary buffer size.\r
+\r
+  @param[in]     DigestListBin    TPML_DIGEST_VALUES compact binary buffer.\r
+\r
+  @return TPML_DIGEST_VALUES compact binary buffer size.\r
+**/\r
+UINT32\r
+GetDigestListBinSize (\r
+  IN VOID  *DigestListBin\r
+  )\r
+{\r
+  UINTN          Index;\r
+  UINT16         DigestSize;\r
+  UINT32         TotalSize;\r
+  UINT32         Count;\r
+  TPMI_ALG_HASH  HashAlg;\r
+\r
+  Count         = ReadUnaligned32 (DigestListBin);\r
+  TotalSize     = sizeof (Count);\r
+  DigestListBin = (UINT8 *)DigestListBin + sizeof (Count);\r
+  for (Index = 0; Index < Count; Index++) {\r
+    HashAlg       = ReadUnaligned16 (DigestListBin);\r
+    TotalSize    += sizeof (HashAlg);\r
+    DigestListBin = (UINT8 *)DigestListBin + sizeof (HashAlg);\r
+\r
+    DigestSize    = GetHashSizeFromAlgo (HashAlg);\r
+    TotalSize    += DigestSize;\r
+    DigestListBin = (UINT8 *)DigestListBin + DigestSize;\r
+  }\r
+\r
+  return TotalSize;\r
+}\r
+\r
+/**\r
+  Copy TPML_DIGEST_VALUES compact binary into a buffer\r
+\r
+  @param[in,out]    Buffer                  Buffer to hold copied TPML_DIGEST_VALUES compact binary.\r
+  @param[in]        DigestListBin           TPML_DIGEST_VALUES compact binary buffer.\r
+  @param[in]        HashAlgorithmMask       HASH bits corresponding to the desired digests to copy.\r
+  @param[out]       HashAlgorithmMaskCopied Pointer to HASH bits corresponding to the digests copied.\r
+\r
+  @return The end of buffer to hold TPML_DIGEST_VALUES compact binary.\r
+**/\r
+VOID *\r
+CopyDigestListBinToBuffer (\r
+  IN OUT VOID  *Buffer,\r
+  IN VOID      *DigestListBin,\r
+  IN UINT32    HashAlgorithmMask,\r
+  OUT UINT32   *HashAlgorithmMaskCopied\r
+  )\r
+{\r
+  UINTN          Index;\r
+  UINT16         DigestSize;\r
+  UINT32         Count;\r
+  TPMI_ALG_HASH  HashAlg;\r
+  UINT32         DigestListCount;\r
+  UINT32         *DigestListCountPtr;\r
+\r
+  DigestListCountPtr       = (UINT32 *)Buffer;\r
+  DigestListCount          = 0;\r
+  *HashAlgorithmMaskCopied = 0;\r
+\r
+  Count         = ReadUnaligned32 (DigestListBin);\r
+  Buffer        = (UINT8 *)Buffer + sizeof (Count);\r
+  DigestListBin = (UINT8 *)DigestListBin + sizeof (Count);\r
+  for (Index = 0; Index < Count; Index++) {\r
+    HashAlg       = ReadUnaligned16 (DigestListBin);\r
+    DigestListBin = (UINT8 *)DigestListBin + sizeof (HashAlg);\r
+    DigestSize    = GetHashSizeFromAlgo (HashAlg);\r
+\r
+    if ((HashAlg & HashAlgorithmMask) != 0) {\r
+      CopyMem (Buffer, &HashAlg, sizeof (HashAlg));\r
+      Buffer = (UINT8 *)Buffer + sizeof (HashAlg);\r
+      CopyMem (Buffer, DigestListBin, DigestSize);\r
+      Buffer = (UINT8 *)Buffer + DigestSize;\r
+      DigestListCount++;\r
+      (*HashAlgorithmMaskCopied) |= GetHashMaskFromAlgo (HashAlg);\r
+    } else {\r
+      DEBUG ((DEBUG_ERROR, "WARNING: CopyDigestListBinToBuffer Event log has HashAlg unsupported by PCR bank (0x%x)\n", HashAlg));\r
+    }\r
+\r
+    DigestListBin = (UINT8 *)DigestListBin + DigestSize;\r
+  }\r
+\r
+  WriteUnaligned32 (DigestListCountPtr, DigestListCount);\r
+\r
+  return Buffer;\r
+}\r
+\r
+/**\r
+  Add a new entry to the Event Log. The call chain is like below:\r
+  TdxDxeLogHashEvent -> TdxDxeLogEvent -> TcgCommonLogEvent\r
+\r
+  Before this function is called, the event information (including the digest)\r
+  is ready.\r
+\r
+  @param[in]     DigestList    A list of digest.\r
+  @param[in,out] NewEventHdr   Pointer to a TD_EVENT_HDR data structure.\r
+  @param[in]     NewEventData  Pointer to the new event data.\r
+\r
+  @retval EFI_SUCCESS           The new event log entry was added.\r
+  @retval EFI_OUT_OF_RESOURCES  No enough memory to log the new event.\r
+**/\r
+EFI_STATUS\r
+TdxDxeLogHashEvent (\r
+  IN      TPML_DIGEST_VALUES  *DigestList,\r
+  IN OUT  CC_EVENT_HDR        *NewEventHdr,\r
+  IN      UINT8               *NewEventData\r
+  )\r
+{\r
+  EFI_STATUS               Status;\r
+  EFI_TPL                  OldTpl;\r
+  EFI_STATUS               RetStatus;\r
+  CC_EVENT                 CcEvent;\r
+  UINT8                    *DigestBuffer;\r
+  UINT32                   *EventSizePtr;\r
+  EFI_CC_EVENT_LOG_FORMAT  LogFormat;\r
+\r
+  RetStatus = EFI_SUCCESS;\r
+  LogFormat = EFI_CC_EVENT_LOG_FORMAT_TCG_2;\r
+\r
+  ZeroMem (&CcEvent, sizeof (CcEvent));\r
+  CcEvent.MrIndex   = NewEventHdr->MrIndex;\r
+  CcEvent.EventType = NewEventHdr->EventType;\r
+  DigestBuffer      = (UINT8 *)&CcEvent.Digests;\r
+  EventSizePtr      = CopyDigestListToBuffer (DigestBuffer, DigestList, HASH_ALG_SHA384);\r
+  CopyMem (EventSizePtr, &NewEventHdr->EventSize, sizeof (NewEventHdr->EventSize));\r
+\r
+  //\r
+  // Enter critical region\r
+  //\r
+  OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
+  Status = TdxDxeLogEvent (\r
+             LogFormat,\r
+             &CcEvent,\r
+             sizeof (CcEvent.MrIndex) + sizeof (CcEvent.EventType) + GetDigestListBinSize (DigestBuffer) + sizeof (CcEvent.EventSize),\r
+             NewEventData,\r
+             NewEventHdr->EventSize\r
+             );\r
+  if (Status != EFI_SUCCESS) {\r
+    RetStatus = Status;\r
+  }\r
+\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  return RetStatus;\r
+}\r
+\r
+/**\r
+  Do a hash operation on a data buffer, extend a specific RTMR with the hash result,\r
+  and add an entry to the Event Log.\r
+\r
+  @param[in]      Flags         Bitmap providing additional information.\r
+  @param[in]      HashData      Physical address of the start of the data buffer\r
+                                to be hashed, extended, and logged.\r
+  @param[in]      HashDataLen   The length, in bytes, of the buffer referenced by HashData\r
+  @param[in, out] NewEventHdr   Pointer to a TD_EVENT_HDR data structure.\r
+  @param[in]      NewEventData  Pointer to the new event data.\r
+\r
+  @retval EFI_SUCCESS           Operation completed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  No enough memory to log the new event.\r
+  @retval EFI_DEVICE_ERROR      The command was unsuccessful.\r
+\r
+**/\r
+EFI_STATUS\r
+TdxDxeHashLogExtendEvent (\r
+  IN      UINT64        Flags,\r
+  IN      UINT8         *HashData,\r
+  IN      UINT64        HashDataLen,\r
+  IN OUT  CC_EVENT_HDR  *NewEventHdr,\r
+  IN      UINT8         *NewEventData\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  TPML_DIGEST_VALUES  DigestList;\r
+  CC_EVENT_HDR        NoActionEvent;\r
+\r
+  if (NewEventHdr->EventType == EV_NO_ACTION) {\r
+    //\r
+    // Do not do RTMR extend for EV_NO_ACTION\r
+    //\r
+    Status = EFI_SUCCESS;\r
+    InitNoActionEvent (&NoActionEvent, NewEventHdr->EventSize);\r
+    if ((Flags & EFI_CC_FLAG_EXTEND_ONLY) == 0) {\r
+      Status = TdxDxeLogHashEvent (&(NoActionEvent.Digests), NewEventHdr, NewEventData);\r
+    }\r
+\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // According to UEFI Spec 2.10 Section 38.4.1 the mapping between MrIndex and Intel\r
+  // TDX Measurement Register is:\r
+  //    MrIndex 0   <--> MRTD\r
+  //    MrIndex 1-3 <--> RTMR[0-2]\r
+  // Only the RMTR registers can be extended in TDVF by HashAndExtend. So MrIndex will\r
+  // decreased by 1 before it is sent to HashAndExtend.\r
+  //\r
+  Status = HashAndExtend (\r
+             NewEventHdr->MrIndex - 1,\r
+             HashData,\r
+             (UINTN)HashDataLen,\r
+             &DigestList\r
+             );\r
+  if (!EFI_ERROR (Status)) {\r
+    if ((Flags & EFI_CC_FLAG_EXTEND_ONLY) == 0) {\r
+      Status = TdxDxeLogHashEvent (&DigestList, NewEventHdr, NewEventData);\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  The EFI_CC_MEASUREMENT_PROTOCOL HashLogExtendEvent function call provides callers with\r
+  an opportunity to extend and optionally log events without requiring\r
+  knowledge of actual TPM commands.\r
+  The extend operation will occur even if this function cannot create an event\r
+  log entry (e.g. due to the event log being full).\r
+\r
+  @param[in]  This               Indicates the calling context\r
+  @param[in]  Flags              Bitmap providing additional information.\r
+  @param[in]  DataToHash         Physical address of the start of the data buffer to be hashed.\r
+  @param[in]  DataToHashLen      The length in bytes of the buffer referenced by DataToHash.\r
+  @param[in]  Event              Pointer to data buffer containing information about the event.\r
+\r
+  @retval EFI_SUCCESS            Operation completed successfully.\r
+  @retval EFI_DEVICE_ERROR       The command was unsuccessful.\r
+  @retval EFI_VOLUME_FULL        The extend operation occurred, but the event could not be written to one or more event logs.\r
+  @retval EFI_INVALID_PARAMETER  One or more of the parameters are incorrect.\r
+  @retval EFI_UNSUPPORTED        The PE/COFF image type is not supported.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TdHashLogExtendEvent (\r
+  IN EFI_CC_MEASUREMENT_PROTOCOL  *This,\r
+  IN UINT64                       Flags,\r
+  IN EFI_PHYSICAL_ADDRESS         DataToHash,\r
+  IN UINT64                       DataToHashLen,\r
+  IN EFI_CC_EVENT                 *CcEvent\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  CC_EVENT_HDR        NewEventHdr;\r
+  TPML_DIGEST_VALUES  DigestList;\r
+\r
+  DEBUG ((DEBUG_VERBOSE, "TdHashLogExtendEvent ...\n"));\r
+\r
+  if ((This == NULL) || (CcEvent == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Do not check hash data size for EV_NO_ACTION event.\r
+  //\r
+  if ((CcEvent->Header.EventType != EV_NO_ACTION) && (DataToHash == 0)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (CcEvent->Size < CcEvent->Header.HeaderSize + sizeof (UINT32)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (CcEvent->Header.MrIndex == CC_MR_INDEX_0_MRTD) {\r
+    DEBUG ((DEBUG_ERROR, "%a: MRTD cannot be extended in TDVF.\n", __FUNCTION__));\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (CcEvent->Header.MrIndex >= CC_MR_INDEX_INVALID) {\r
+    DEBUG ((DEBUG_ERROR, "%a: MrIndex is invalid. (%d)\n", __FUNCTION__, CcEvent->Header.MrIndex));\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  NewEventHdr.MrIndex   = CcEvent->Header.MrIndex;\r
+  NewEventHdr.EventType = CcEvent->Header.EventType;\r
+  NewEventHdr.EventSize = CcEvent->Size - sizeof (UINT32) - CcEvent->Header.HeaderSize;\r
+  if ((Flags & EFI_CC_FLAG_PE_COFF_IMAGE) != 0) {\r
+    //\r
+    // According to UEFI Spec 2.10 Section 38.4.1 the mapping between MrIndex and Intel\r
+    // TDX Measurement Register is:\r
+    //    MrIndex 0   <--> MRTD\r
+    //    MrIndex 1-3 <--> RTMR[0-2]\r
+    // Only the RMTR registers can be extended in TDVF by HashAndExtend. So MrIndex will\r
+    // decreased by 1 before it is sent to MeasurePeImageAndExtend.\r
+    //\r
+    Status = MeasurePeImageAndExtend (\r
+               NewEventHdr.MrIndex - 1,\r
+               DataToHash,\r
+               (UINTN)DataToHashLen,\r
+               &DigestList\r
+               );\r
+    if (!EFI_ERROR (Status)) {\r
+      if ((Flags & EFI_CC_FLAG_EXTEND_ONLY) == 0) {\r
+        Status = TdxDxeLogHashEvent (&DigestList, &NewEventHdr, CcEvent->Event);\r
+      }\r
+    }\r
+  } else {\r
+    Status = TdxDxeHashLogExtendEvent (\r
+               Flags,\r
+               (UINT8 *)(UINTN)DataToHash,\r
+               DataToHashLen,\r
+               &NewEventHdr,\r
+               CcEvent->Event\r
+               );\r
+  }\r
+\r
+  DEBUG ((DEBUG_VERBOSE, "TdHashLogExtendEvent - %r\n", Status));\r
+  return Status;\r
+}\r
+\r
+EFI_CC_MEASUREMENT_PROTOCOL  mTdProtocol = {\r
+  TdGetCapability,\r
+  TdGetEventLog,\r
+  TdHashLogExtendEvent,\r
+  TdMapPcrToMrIndex,\r
+};\r
+\r
+#define TD_HASH_COUNT  1\r
+#define TEMP_BUF_LEN   (sizeof(TCG_EfiSpecIDEventStruct) +  sizeof(UINT32) \\r
+                     + (TD_HASH_COUNT * sizeof(TCG_EfiSpecIdEventAlgorithmSize)) + sizeof(UINT8))\r
+\r
+/**\r
+  Initialize the TD Event Log and log events passed from the PEI phase.\r
+\r
+  @retval EFI_SUCCESS           Operation completed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  Out of memory.\r
+\r
+**/\r
+EFI_STATUS\r
+SetupCcEventLog (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                       Status;\r
+  EFI_PHYSICAL_ADDRESS             Lasa;\r
+  UINTN                            Index;\r
+  TCG_EfiSpecIDEventStruct         *TcgEfiSpecIdEventStruct;\r
+  UINT8                            TempBuf[TEMP_BUF_LEN];\r
+  TCG_PCR_EVENT_HDR                SpecIdEvent;\r
+  TCG_EfiSpecIdEventAlgorithmSize  *DigestSize;\r
+  TCG_EfiSpecIdEventAlgorithmSize  *TempDigestSize;\r
+  UINT8                            *VendorInfoSize;\r
+  UINT32                           NumberOfAlgorithms;\r
+  EFI_CC_EVENT_LOG_FORMAT          LogFormat;\r
+  EFI_PEI_HOB_POINTERS             GuidHob;\r
+  CC_EVENT_HDR                     NoActionEvent;\r
+\r
+  Status = EFI_SUCCESS;\r
+  DEBUG ((DEBUG_INFO, "SetupCcEventLog\n"));\r
+\r
+  Index     = 0;\r
+  LogFormat = EFI_CC_EVENT_LOG_FORMAT_TCG_2;\r
+\r
+  //\r
+  // 1. Create Log Area\r
+  //\r
+  mTdxDxeData.EventLogAreaStruct[Index].EventLogFormat = LogFormat;\r
+\r
+  // allocate pages for TD Event log\r
+  Status = gBS->AllocatePages (\r
+                  AllocateAnyPages,\r
+                  EfiACPIMemoryNVS,\r
+                  EFI_SIZE_TO_PAGES (PcdGet32 (PcdTcgLogAreaMinLen)),\r
+                  &Lasa\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  mTdxDxeData.EventLogAreaStruct[Index].Lasa                  = Lasa;\r
+  mTdxDxeData.EventLogAreaStruct[Index].Laml                  = PcdGet32 (PcdTcgLogAreaMinLen);\r
+  mTdxDxeData.EventLogAreaStruct[Index].Next800155EventOffset = 0;\r
+\r
+  //\r
+  // Report TD event log address and length, so that they can be reported in\r
+  // TD ACPI table. Ignore the return status, because those fields are optional.\r
+  //\r
+  PcdSet32S (PcdCcEventlogAcpiTableLaml, (UINT32)mTdxDxeData.EventLogAreaStruct[Index].Laml);\r
+  PcdSet64S (PcdCcEventlogAcpiTableLasa, mTdxDxeData.EventLogAreaStruct[Index].Lasa);\r
+\r
+  //\r
+  // To initialize them as 0xFF is recommended\r
+  // because the OS can know the last entry for that.\r
+  //\r
+  SetMem ((VOID *)(UINTN)Lasa, PcdGet32 (PcdTcgLogAreaMinLen), 0xFF);\r
+\r
+  //\r
+  // Create first entry for Log Header Entry Data\r
+  //\r
+\r
+  //\r
+  // TcgEfiSpecIdEventStruct\r
+  //\r
+  TcgEfiSpecIdEventStruct = (TCG_EfiSpecIDEventStruct *)TempBuf;\r
+  CopyMem (TcgEfiSpecIdEventStruct->signature, TCG_EfiSpecIDEventStruct_SIGNATURE_03, sizeof (TcgEfiSpecIdEventStruct->signature));\r
+\r
+  TcgEfiSpecIdEventStruct->platformClass = PcdGet8 (PcdTpmPlatformClass);\r
+\r
+  TcgEfiSpecIdEventStruct->specVersionMajor = TCG_EfiSpecIDEventStruct_SPEC_VERSION_MAJOR_TPM2;\r
+  TcgEfiSpecIdEventStruct->specVersionMinor = TCG_EfiSpecIDEventStruct_SPEC_VERSION_MINOR_TPM2;\r
+  TcgEfiSpecIdEventStruct->specErrata       = TCG_EfiSpecIDEventStruct_SPEC_ERRATA_TPM2;\r
+  TcgEfiSpecIdEventStruct->uintnSize        = sizeof (UINTN)/sizeof (UINT32);\r
+  NumberOfAlgorithms                        = 0;\r
+  DigestSize                                = (TCG_EfiSpecIdEventAlgorithmSize *)((UINT8 *)TcgEfiSpecIdEventStruct\r
+                                                                                  + sizeof (*TcgEfiSpecIdEventStruct)\r
+                                                                                  + sizeof (NumberOfAlgorithms));\r
+\r
+  TempDigestSize              = DigestSize;\r
+  TempDigestSize             += NumberOfAlgorithms;\r
+  TempDigestSize->algorithmId = TPM_ALG_SHA384;\r
+  TempDigestSize->digestSize  = SHA384_DIGEST_SIZE;\r
+  NumberOfAlgorithms++;\r
+\r
+  CopyMem (TcgEfiSpecIdEventStruct + 1, &NumberOfAlgorithms, sizeof (NumberOfAlgorithms));\r
+  TempDigestSize  = DigestSize;\r
+  TempDigestSize += NumberOfAlgorithms;\r
+  VendorInfoSize  = (UINT8 *)TempDigestSize;\r
+  *VendorInfoSize = 0;\r
+\r
+  SpecIdEvent.PCRIndex  = 1; // PCRIndex 0 maps to MrIndex 1\r
+  SpecIdEvent.EventType = EV_NO_ACTION;\r
+  ZeroMem (&SpecIdEvent.Digest, sizeof (SpecIdEvent.Digest));\r
+  SpecIdEvent.EventSize = (UINT32)GetTcgEfiSpecIdEventStructSize (TcgEfiSpecIdEventStruct);\r
+\r
+  //\r
+  // TD Event log re-use the spec of TCG2 Event log.\r
+  // Log TcgEfiSpecIdEventStruct as the first Event. Event format is TCG_PCR_EVENT.\r
+  //   TCG EFI Protocol Spec. Section 5.3 Event Log Header\r
+  //   TCG PC Client PFP spec. Section 9.2 Measurement Event Entries and Log\r
+  //\r
+  Status = TdxDxeLogEvent (\r
+             LogFormat,\r
+             &SpecIdEvent,\r
+             sizeof (SpecIdEvent),\r
+             (UINT8 *)TcgEfiSpecIdEventStruct,\r
+             SpecIdEvent.EventSize\r
+             );\r
+  //\r
+  // record the offset at the end of 800-155 event.\r
+  // the future 800-155 event can be inserted here.\r
+  //\r
+  mTdxDxeData.EventLogAreaStruct[Index].Next800155EventOffset = mTdxDxeData.EventLogAreaStruct[Index].EventLogSize;\r
+\r
+  //\r
+  // Tcg800155PlatformIdEvent. Event format is TCG_PCR_EVENT2\r
+  //\r
+  GuidHob.Guid = GetFirstGuidHob (&gTcg800155PlatformIdEventHobGuid);\r
+  while (GuidHob.Guid != NULL) {\r
+    InitNoActionEvent (&NoActionEvent, GET_GUID_HOB_DATA_SIZE (GuidHob.Guid));\r
+\r
+    Status = TdxDxeLogEvent (\r
+               LogFormat,\r
+               &NoActionEvent,\r
+               sizeof (NoActionEvent.MrIndex) + sizeof (NoActionEvent.EventType) + GetDigestListBinSize (&NoActionEvent.Digests) + sizeof (NoActionEvent.EventSize),\r
+               GET_GUID_HOB_DATA (GuidHob.Guid),\r
+               GET_GUID_HOB_DATA_SIZE (GuidHob.Guid)\r
+               );\r
+\r
+    GuidHob.Guid = GET_NEXT_HOB (GuidHob);\r
+    GuidHob.Guid = GetNextGuidHob (&gTcg800155PlatformIdEventHobGuid, GuidHob.Guid);\r
+  }\r
+\r
+  //\r
+  // 2. Create Final Log Area\r
+  //\r
+  Status = gBS->AllocatePages (\r
+                  AllocateAnyPages,\r
+                  EfiACPIMemoryNVS,\r
+                  EFI_SIZE_TO_PAGES (PcdGet32 (PcdTcg2FinalLogAreaLen)),\r
+                  &Lasa\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  SetMem ((VOID *)(UINTN)Lasa, PcdGet32 (PcdTcg2FinalLogAreaLen), 0xFF);\r
+\r
+  //\r
+  // Initialize\r
+  //\r
+  mTdxDxeData.FinalEventsTable[Index]                   = (VOID *)(UINTN)Lasa;\r
+  (mTdxDxeData.FinalEventsTable[Index])->Version        = EFI_TCG2_FINAL_EVENTS_TABLE_VERSION;\r
+  (mTdxDxeData.FinalEventsTable[Index])->NumberOfEvents = 0;\r
+\r
+  mTdxDxeData.FinalEventLogAreaStruct[Index].EventLogFormat        = LogFormat;\r
+  mTdxDxeData.FinalEventLogAreaStruct[Index].Lasa                  = Lasa + sizeof (EFI_CC_FINAL_EVENTS_TABLE);\r
+  mTdxDxeData.FinalEventLogAreaStruct[Index].Laml                  = PcdGet32 (PcdTcg2FinalLogAreaLen) - sizeof (EFI_CC_FINAL_EVENTS_TABLE);\r
+  mTdxDxeData.FinalEventLogAreaStruct[Index].EventLogSize          = 0;\r
+  mTdxDxeData.FinalEventLogAreaStruct[Index].LastEvent             = (VOID *)(UINTN)mTdxDxeData.FinalEventLogAreaStruct[Index].Lasa;\r
+  mTdxDxeData.FinalEventLogAreaStruct[Index].EventLogStarted       = FALSE;\r
+  mTdxDxeData.FinalEventLogAreaStruct[Index].EventLogTruncated     = FALSE;\r
+  mTdxDxeData.FinalEventLogAreaStruct[Index].Next800155EventOffset = 0;\r
+\r
+  //\r
+  // Install to configuration table for EFI_CC_EVENT_LOG_FORMAT_TCG_2\r
+  //\r
+  Status = gBS->InstallConfigurationTable (&gEfiCcFinalEventsTableGuid, (VOID *)mTdxDxeData.FinalEventsTable[Index]);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Measure and log an action string, and extend the measurement result into RTMR.\r
+\r
+  @param[in] MrIndex        MrIndex to extend\r
+  @param[in] String           A specific string that indicates an Action event.\r
+\r
+  @retval EFI_SUCCESS         Operation completed successfully.\r
+  @retval EFI_DEVICE_ERROR    The operation was unsuccessful.\r
+\r
+**/\r
+EFI_STATUS\r
+TdMeasureAction (\r
+  IN      UINT32  MrIndex,\r
+  IN      CHAR8   *String\r
+  )\r
+{\r
+  CC_EVENT_HDR  CcEvent;\r
+\r
+  CcEvent.MrIndex   = MrIndex;\r
+  CcEvent.EventType = EV_EFI_ACTION;\r
+  CcEvent.EventSize = (UINT32)AsciiStrLen (String);\r
+  return TdxDxeHashLogExtendEvent (\r
+           0,\r
+           (UINT8 *)String,\r
+           CcEvent.EventSize,\r
+           &CcEvent,\r
+           (UINT8 *)String\r
+           );\r
+}\r
+\r
+/**\r
+  Measure and log EFI handoff tables, and extend the measurement result into PCR[1].\r
+\r
+  @retval EFI_SUCCESS         Operation completed successfully.\r
+  @retval EFI_DEVICE_ERROR    The operation was unsuccessful.\r
+\r
+**/\r
+EFI_STATUS\r
+MeasureHandoffTables (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  CC_EVENT_HDR                CcEvent;\r
+  EFI_HANDOFF_TABLE_POINTERS  HandoffTables;\r
+  UINTN                       ProcessorNum;\r
+  EFI_CPU_PHYSICAL_LOCATION   *ProcessorLocBuf;\r
+\r
+  ProcessorLocBuf = NULL;\r
+  Status          = EFI_SUCCESS;\r
+\r
+  if (PcdGet8 (PcdTpmPlatformClass) == TCG_PLATFORM_TYPE_SERVER) {\r
+    //\r
+    // Tcg Server spec.\r
+    // Measure each processor EFI_CPU_PHYSICAL_LOCATION with EV_TABLE_OF_DEVICES to PCR[1]\r
+    //\r
+    Status = GetProcessorsCpuLocation (&ProcessorLocBuf, &ProcessorNum);\r
+\r
+    if (!EFI_ERROR (Status)) {\r
+      CcEvent.MrIndex   = MapPcrToMrIndex (1);\r
+      CcEvent.EventType = EV_TABLE_OF_DEVICES;\r
+      CcEvent.EventSize = sizeof (HandoffTables);\r
+\r
+      HandoffTables.NumberOfTables            = 1;\r
+      HandoffTables.TableEntry[0].VendorGuid  = gEfiMpServiceProtocolGuid;\r
+      HandoffTables.TableEntry[0].VendorTable = ProcessorLocBuf;\r
+\r
+      Status = TdxDxeHashLogExtendEvent (\r
+                 0,\r
+                 (UINT8 *)(UINTN)ProcessorLocBuf,\r
+                 sizeof (EFI_CPU_PHYSICAL_LOCATION) * ProcessorNum,\r
+                 &CcEvent,\r
+                 (UINT8 *)&HandoffTables\r
+                 );\r
+\r
+      FreePool (ProcessorLocBuf);\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Measure and log Separator event, and extend the measurement result into a specific PCR.\r
+\r
+  @param[in] PCRIndex         PCR index.\r
+\r
+  @retval EFI_SUCCESS         Operation completed successfully.\r
+  @retval EFI_DEVICE_ERROR    The operation was unsuccessful.\r
+\r
+**/\r
+EFI_STATUS\r
+MeasureSeparatorEvent (\r
+  IN      UINT32  MrIndex\r
+  )\r
+{\r
+  CC_EVENT_HDR  CcEvent;\r
+  UINT32        EventData;\r
+\r
+  DEBUG ((DEBUG_INFO, "MeasureSeparatorEvent to Rtmr - %d\n", MrIndex));\r
+\r
+  EventData         = 0;\r
+  CcEvent.MrIndex   = MrIndex;\r
+  CcEvent.EventType = EV_SEPARATOR;\r
+  CcEvent.EventSize = (UINT32)sizeof (EventData);\r
+\r
+  return TdxDxeHashLogExtendEvent (\r
+           0,\r
+           (UINT8 *)&EventData,\r
+           sizeof (EventData),\r
+           &CcEvent,\r
+           (UINT8 *)&EventData\r
+           );\r
+}\r
+\r
+/**\r
+  Measure and log an EFI variable, and extend the measurement result into a specific RTMR.\r
+\r
+  @param[in]  MrIndex         RTMR Index.\r
+  @param[in]  EventType         Event type.\r
+  @param[in]  VarName           A Null-terminated string that is the name of the vendor's variable.\r
+  @param[in]  VendorGuid        A unique identifier for the vendor.\r
+  @param[in]  VarData           The content of the variable data.\r
+  @param[in]  VarSize           The size of the variable data.\r
+\r
+  @retval EFI_SUCCESS           Operation completed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  Out of memory.\r
+  @retval EFI_DEVICE_ERROR      The operation was unsuccessful.\r
+\r
+**/\r
+EFI_STATUS\r
+MeasureVariable (\r
+  IN      UINT32         MrIndex,\r
+  IN      TCG_EVENTTYPE  EventType,\r
+  IN      CHAR16         *VarName,\r
+  IN      EFI_GUID       *VendorGuid,\r
+  IN      VOID           *VarData,\r
+  IN      UINTN          VarSize\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  CC_EVENT_HDR        CcEvent;\r
+  UINTN               VarNameLength;\r
+  UEFI_VARIABLE_DATA  *VarLog;\r
+\r
+  DEBUG ((DEBUG_INFO, "TdTcg2Dxe: MeasureVariable (Rtmr - %x, EventType - %x, ", (UINTN)MrIndex, (UINTN)EventType));\r
+  DEBUG ((DEBUG_INFO, "VariableName - %s, VendorGuid - %g)\n", VarName, VendorGuid));\r
+\r
+  VarNameLength     = StrLen (VarName);\r
+  CcEvent.MrIndex   = MrIndex;\r
+  CcEvent.EventType = EventType;\r
+\r
+  CcEvent.EventSize = (UINT32)(sizeof (*VarLog) + VarNameLength * sizeof (*VarName) + VarSize\r
+                               - sizeof (VarLog->UnicodeName) - sizeof (VarLog->VariableData));\r
+\r
+  VarLog = (UEFI_VARIABLE_DATA *)AllocatePool (CcEvent.EventSize);\r
+  if (VarLog == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  VarLog->VariableName       = *VendorGuid;\r
+  VarLog->UnicodeNameLength  = VarNameLength;\r
+  VarLog->VariableDataLength = VarSize;\r
+  CopyMem (\r
+    VarLog->UnicodeName,\r
+    VarName,\r
+    VarNameLength * sizeof (*VarName)\r
+    );\r
+  if ((VarSize != 0) && (VarData != NULL)) {\r
+    CopyMem (\r
+      (CHAR16 *)VarLog->UnicodeName + VarNameLength,\r
+      VarData,\r
+      VarSize\r
+      );\r
+  }\r
+\r
+  if (EventType == EV_EFI_VARIABLE_DRIVER_CONFIG) {\r
+    //\r
+    // Digest is the event data (UEFI_VARIABLE_DATA)\r
+    //\r
+    Status = TdxDxeHashLogExtendEvent (\r
+               0,\r
+               (UINT8 *)VarLog,\r
+               CcEvent.EventSize,\r
+               &CcEvent,\r
+               (UINT8 *)VarLog\r
+               );\r
+  } else {\r
+    ASSERT (VarData != NULL);\r
+    Status = TdxDxeHashLogExtendEvent (\r
+               0,\r
+               (UINT8 *)VarData,\r
+               VarSize,\r
+               &CcEvent,\r
+               (UINT8 *)VarLog\r
+               );\r
+  }\r
+\r
+  FreePool (VarLog);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Read then Measure and log an EFI variable, and extend the measurement result into a specific RTMR.\r
+\r
+  @param[in]  MrIndex           RTMR Index.\r
+  @param[in]  EventType         Event type.\r
+  @param[in]   VarName          A Null-terminated string that is the name of the vendor's variable.\r
+  @param[in]   VendorGuid       A unique identifier for the vendor.\r
+  @param[out]  VarSize          The size of the variable data.\r
+  @param[out]  VarData          Pointer to the content of the variable.\r
+\r
+  @retval EFI_SUCCESS           Operation completed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  Out of memory.\r
+  @retval EFI_DEVICE_ERROR      The operation was unsuccessful.\r
+\r
+**/\r
+EFI_STATUS\r
+ReadAndMeasureVariable (\r
+  IN      UINT32         MrIndex,\r
+  IN      TCG_EVENTTYPE  EventType,\r
+  IN      CHAR16         *VarName,\r
+  IN      EFI_GUID       *VendorGuid,\r
+  OUT     UINTN          *VarSize,\r
+  OUT     VOID           **VarData\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  Status = GetVariable2 (VarName, VendorGuid, VarData, VarSize);\r
+  if (EventType == EV_EFI_VARIABLE_DRIVER_CONFIG) {\r
+    if (EFI_ERROR (Status)) {\r
+      //\r
+      // It is valid case, so we need handle it.\r
+      //\r
+      *VarData = NULL;\r
+      *VarSize = 0;\r
+    }\r
+  } else {\r
+    //\r
+    // if status error, VarData is freed and set NULL by GetVariable2\r
+    //\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_NOT_FOUND;\r
+    }\r
+  }\r
+\r
+  Status = MeasureVariable (\r
+             MrIndex,\r
+             EventType,\r
+             VarName,\r
+             VendorGuid,\r
+             *VarData,\r
+             *VarSize\r
+             );\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Read then Measure and log an EFI boot variable, and extend the measurement result into PCR[1].\r
+according to TCG PC Client PFP spec 0021 Section 2.4.4.2\r
+\r
+  @param[in]   VarName          A Null-terminated string that is the name of the vendor's variable.\r
+  @param[in]   VendorGuid       A unique identifier for the vendor.\r
+  @param[out]  VarSize          The size of the variable data.\r
+  @param[out]  VarData          Pointer to the content of the variable.\r
+\r
+  @retval EFI_SUCCESS           Operation completed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  Out of memory.\r
+  @retval EFI_DEVICE_ERROR      The operation was unsuccessful.\r
+\r
+**/\r
+EFI_STATUS\r
+ReadAndMeasureBootVariable (\r
+  IN      CHAR16    *VarName,\r
+  IN      EFI_GUID  *VendorGuid,\r
+  OUT     UINTN     *VarSize,\r
+  OUT     VOID      **VarData\r
+  )\r
+{\r
+  //\r
+  // Boot variables are measured into (PCR[5]) RTMR[1],\r
+  // details in section 8.1 of TDVF design guide.\r
+  //\r
+  return ReadAndMeasureVariable (\r
+           MapPcrToMrIndex (5),\r
+           EV_EFI_VARIABLE_BOOT,\r
+           VarName,\r
+           VendorGuid,\r
+           VarSize,\r
+           VarData\r
+           );\r
+}\r
+\r
+/**\r
+  Read then Measure and log an EFI Secure variable, and extend the measurement result into PCR[7].\r
+\r
+  @param[in]   VarName          A Null-terminated string that is the name of the vendor's variable.\r
+  @param[in]   VendorGuid       A unique identifier for the vendor.\r
+  @param[out]  VarSize          The size of the variable data.\r
+  @param[out]  VarData          Pointer to the content of the variable.\r
+\r
+  @retval EFI_SUCCESS           Operation completed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  Out of memory.\r
+  @retval EFI_DEVICE_ERROR      The operation was unsuccessful.\r
+\r
+**/\r
+EFI_STATUS\r
+ReadAndMeasureSecureVariable (\r
+  IN      CHAR16    *VarName,\r
+  IN      EFI_GUID  *VendorGuid,\r
+  OUT     UINTN     *VarSize,\r
+  OUT     VOID      **VarData\r
+  )\r
+{\r
+  return ReadAndMeasureVariable (\r
+           MapPcrToMrIndex (7),\r
+           EV_EFI_VARIABLE_DRIVER_CONFIG,\r
+           VarName,\r
+           VendorGuid,\r
+           VarSize,\r
+           VarData\r
+           );\r
+}\r
+\r
+/**\r
+  Measure and log all EFI boot variables, and extend the measurement result into a specific PCR.\r
+\r
+  The EFI boot variables are BootOrder and Boot#### variables.\r
+\r
+  @retval EFI_SUCCESS           Operation completed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  Out of memory.\r
+  @retval EFI_DEVICE_ERROR      The operation was unsuccessful.\r
+\r
+**/\r
+EFI_STATUS\r
+MeasureAllBootVariables (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINT16      *BootOrder;\r
+  UINTN       BootCount;\r
+  UINTN       Index;\r
+  VOID        *BootVarData;\r
+  UINTN       Size;\r
+\r
+  Status = ReadAndMeasureBootVariable (\r
+             mBootVarName,\r
+             &gEfiGlobalVariableGuid,\r
+             &BootCount,\r
+             (VOID **)&BootOrder\r
+             );\r
+  if ((Status == EFI_NOT_FOUND) || (BootOrder == NULL)) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // BootOrder can't be NULL if status is not EFI_NOT_FOUND\r
+    //\r
+    FreePool (BootOrder);\r
+    return Status;\r
+  }\r
+\r
+  BootCount /= sizeof (*BootOrder);\r
+  for (Index = 0; Index < BootCount; Index++) {\r
+    UnicodeSPrint (mBootVarName, sizeof (mBootVarName), L"Boot%04x", BootOrder[Index]);\r
+    Status = ReadAndMeasureBootVariable (\r
+               mBootVarName,\r
+               &gEfiGlobalVariableGuid,\r
+               &Size,\r
+               &BootVarData\r
+               );\r
+    if (!EFI_ERROR (Status)) {\r
+      FreePool (BootVarData);\r
+    }\r
+  }\r
+\r
+  FreePool (BootOrder);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Measure and log all EFI Secure variables, and extend the measurement result into a specific PCR.\r
+\r
+  The EFI boot variables are BootOrder and Boot#### variables.\r
+\r
+  @retval EFI_SUCCESS           Operation completed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  Out of memory.\r
+  @retval EFI_DEVICE_ERROR      The operation was unsuccessful.\r
+\r
+**/\r
+EFI_STATUS\r
+MeasureAllSecureVariables (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  VOID        *Data;\r
+  UINTN       DataSize;\r
+  UINTN       Index;\r
+\r
+  Status = EFI_NOT_FOUND;\r
+  for (Index = 0; Index < sizeof (mVariableType)/sizeof (mVariableType[0]); Index++) {\r
+    Status = ReadAndMeasureSecureVariable (\r
+               mVariableType[Index].VariableName,\r
+               mVariableType[Index].VendorGuid,\r
+               &DataSize,\r
+               &Data\r
+               );\r
+    if (!EFI_ERROR (Status)) {\r
+      if (Data != NULL) {\r
+        FreePool (Data);\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // Measure DBT if present and not empty\r
+  //\r
+  Status = GetVariable2 (EFI_IMAGE_SECURITY_DATABASE2, &gEfiImageSecurityDatabaseGuid, &Data, &DataSize);\r
+  if (!EFI_ERROR (Status)) {\r
+    Status = MeasureVariable (\r
+               MapPcrToMrIndex (7),\r
+               EV_EFI_VARIABLE_DRIVER_CONFIG,\r
+               EFI_IMAGE_SECURITY_DATABASE2,\r
+               &gEfiImageSecurityDatabaseGuid,\r
+               Data,\r
+               DataSize\r
+               );\r
+    FreePool (Data);\r
+  } else {\r
+    DEBUG ((DEBUG_INFO, "Skip measuring variable %s since it's deleted\n", EFI_IMAGE_SECURITY_DATABASE2));\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Measure and log launch of FirmwareDebugger, and extend the measurement result into a specific PCR.\r
+\r
+  @retval EFI_SUCCESS           Operation completed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  Out of memory.\r
+  @retval EFI_DEVICE_ERROR      The operation was unsuccessful.\r
+\r
+**/\r
+EFI_STATUS\r
+MeasureLaunchOfFirmwareDebugger (\r
+  VOID\r
+  )\r
+{\r
+  CC_EVENT_HDR  CcEvent;\r
+\r
+  CcEvent.MrIndex   = MapPcrToMrIndex (7);\r
+  CcEvent.EventType = EV_EFI_ACTION;\r
+  CcEvent.EventSize = sizeof (FIRMWARE_DEBUGGER_EVENT_STRING) - 1;\r
+  return TdxDxeHashLogExtendEvent (\r
+           0,\r
+           (UINT8 *)FIRMWARE_DEBUGGER_EVENT_STRING,\r
+           sizeof (FIRMWARE_DEBUGGER_EVENT_STRING) - 1,\r
+           &CcEvent,\r
+           (UINT8 *)FIRMWARE_DEBUGGER_EVENT_STRING\r
+           );\r
+}\r
+\r
+/**\r
+  Measure and log all Secure Boot Policy, and extend the measurement result into a specific PCR.\r
+\r
+  Platform firmware adhering to the policy must therefore measure the following values into PCR[7]: (in order listed)\r
+   - The contents of the SecureBoot variable\r
+   - The contents of the PK variable\r
+   - The contents of the KEK variable\r
+   - The contents of the EFI_IMAGE_SECURITY_DATABASE variable\r
+   - The contents of the EFI_IMAGE_SECURITY_DATABASE1 variable\r
+   - Separator\r
+   - Entries in the EFI_IMAGE_SECURITY_DATABASE that are used to validate EFI Drivers or EFI Boot Applications in the boot path\r
+\r
+  NOTE: Because of the above, UEFI variables PK, KEK, EFI_IMAGE_SECURITY_DATABASE,\r
+  EFI_IMAGE_SECURITY_DATABASE1 and SecureBoot SHALL NOT be measured into PCR[3].\r
+\r
+  @param[in]  Event     Event whose notification function is being invoked\r
+  @param[in]  Context   Pointer to the notification function's context\r
+**/\r
+VOID\r
+EFIAPI\r
+MeasureSecureBootPolicy (\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *Context\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  VOID        *Protocol;\r
+\r
+  Status = gBS->LocateProtocol (&gEfiVariableWriteArchProtocolGuid, NULL, (VOID **)&Protocol);\r
+  if (EFI_ERROR (Status)) {\r
+    return;\r
+  }\r
+\r
+  if (PcdGetBool (PcdFirmwareDebuggerInitialized)) {\r
+    Status = MeasureLaunchOfFirmwareDebugger ();\r
+    DEBUG ((DEBUG_INFO, "MeasureLaunchOfFirmwareDebugger - %r\n", Status));\r
+  }\r
+\r
+  Status = MeasureAllSecureVariables ();\r
+  DEBUG ((DEBUG_INFO, "MeasureAllSecureVariables - %r\n", Status));\r
+\r
+  //\r
+  // We need measure Separator(7) here, because this event must be between SecureBootPolicy (Configure)\r
+  // and ImageVerification (Authority)\r
+  // There might be a case that we need measure UEFI image from DriverOrder, besides BootOrder. So\r
+  // the Authority measurement happen before ReadToBoot event.\r
+  //\r
+  Status = MeasureSeparatorEvent (MapPcrToMrIndex (7));\r
+  DEBUG ((DEBUG_INFO, "MeasureSeparatorEvent - %r\n", Status));\r
+  return;\r
+}\r
+\r
+/**\r
+  Ready to Boot Event notification handler.\r
+\r
+  Sequence of OS boot events is measured in this event notification handler.\r
+\r
+  @param[in]  Event     Event whose notification function is being invoked\r
+  @param[in]  Context   Pointer to the notification function's context\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+OnReadyToBoot (\r
+  IN      EFI_EVENT  Event,\r
+  IN      VOID       *Context\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  PERF_START_EX (mImageHandle, "EventRec", "TdTcg2Dxe", 0, PERF_ID_CC_TCG2_DXE);\r
+  if (mBootAttempts == 0) {\r
+    //\r
+    // Measure handoff tables.\r
+    //\r
+    Status = MeasureHandoffTables ();\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((DEBUG_ERROR, "HOBs not Measured. Error!\n"));\r
+    }\r
+\r
+    //\r
+    // Measure BootOrder & Boot#### variables.\r
+    //\r
+    Status = MeasureAllBootVariables ();\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((DEBUG_ERROR, "Boot Variables not Measured. Error!\n"));\r
+    }\r
+\r
+    //\r
+    // 1. This is the first boot attempt.\r
+    //\r
+    Status = TdMeasureAction (\r
+               MapPcrToMrIndex (4),\r
+               EFI_CALLING_EFI_APPLICATION\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((DEBUG_ERROR, "%a not Measured. Error!\n", EFI_CALLING_EFI_APPLICATION));\r
+    }\r
+\r
+    //\r
+    // 2. Draw a line between pre-boot env and entering post-boot env.\r
+    // PCR[7] (is RTMR[0]) is already done.\r
+    //\r
+    Status = MeasureSeparatorEvent (1);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((DEBUG_ERROR, "Separator Event not Measured. Error!\n"));\r
+    }\r
+\r
+    //\r
+    // 3. Measure GPT. It would be done in SAP driver.\r
+    //\r
+\r
+    //\r
+    // 4. Measure PE/COFF OS loader. It would be done in SAP driver.\r
+    //\r
+\r
+    //\r
+    // 5. Read & Measure variable. BootOrder already measured.\r
+    //\r
+  } else {\r
+    //\r
+    // 6. Not first attempt, meaning a return from last attempt\r
+    //\r
+    Status = TdMeasureAction (\r
+               MapPcrToMrIndex (4),\r
+               EFI_RETURNING_FROM_EFI_APPLICATION\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((DEBUG_ERROR, "%a not Measured. Error!\n", EFI_RETURNING_FROM_EFI_APPLICATION));\r
+    }\r
+\r
+    //\r
+    // 7. Next boot attempt, measure "Calling EFI Application from Boot Option" again\r
+    // TCG PC Client PFP spec Section 2.4.4.5 Step 4\r
+    //\r
+    Status = TdMeasureAction (\r
+               MapPcrToMrIndex (4),\r
+               EFI_CALLING_EFI_APPLICATION\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((DEBUG_ERROR, "%a not Measured. Error!\n", EFI_CALLING_EFI_APPLICATION));\r
+    }\r
+  }\r
+\r
+  DEBUG ((DEBUG_INFO, "TdTcg2Dxe Measure Data when ReadyToBoot\n"));\r
+  //\r
+  // Increase boot attempt counter.\r
+  //\r
+  mBootAttempts++;\r
+  PERF_END_EX (mImageHandle, "EventRec", "Tcg2Dxe", 0, PERF_ID_CC_TCG2_DXE + 1);\r
+}\r
+\r
+/**\r
+  Exit Boot Services Event notification handler.\r
+\r
+  Measure invocation and success of ExitBootServices.\r
+\r
+  @param[in]  Event     Event whose notification function is being invoked\r
+  @param[in]  Context   Pointer to the notification function's context\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+OnExitBootServices (\r
+  IN      EFI_EVENT  Event,\r
+  IN      VOID       *Context\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  //\r
+  // Measure invocation of ExitBootServices,\r
+  //\r
+  Status = TdMeasureAction (\r
+             MapPcrToMrIndex (5),\r
+             EFI_EXIT_BOOT_SERVICES_INVOCATION\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "%a not Measured. Error!\n", EFI_EXIT_BOOT_SERVICES_INVOCATION));\r
+  }\r
+\r
+  //\r
+  // Measure success of ExitBootServices\r
+  //\r
+  Status = TdMeasureAction (\r
+             MapPcrToMrIndex (5),\r
+             EFI_EXIT_BOOT_SERVICES_SUCCEEDED\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "%a not Measured. Error!\n", EFI_EXIT_BOOT_SERVICES_SUCCEEDED));\r
+  }\r
+}\r
+\r
+/**\r
+  Exit Boot Services Failed Event notification handler.\r
+\r
+  Measure Failure of ExitBootServices.\r
+\r
+  @param[in]  Event     Event whose notification function is being invoked\r
+  @param[in]  Context   Pointer to the notification function's context\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+OnExitBootServicesFailed (\r
+  IN      EFI_EVENT  Event,\r
+  IN      VOID       *Context\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  //\r
+  // Measure Failure of ExitBootServices,\r
+  //\r
+  Status = TdMeasureAction (\r
+             MapPcrToMrIndex (5),\r
+             EFI_EXIT_BOOT_SERVICES_FAILED\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "%a not Measured. Error!\n", EFI_EXIT_BOOT_SERVICES_FAILED));\r
+  }\r
+}\r
+\r
+EFI_STATUS\r
+SyncCcEvent (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS               Status;\r
+  EFI_PEI_HOB_POINTERS     GuidHob;\r
+  VOID                     *CcEvent;\r
+  VOID                     *DigestListBin;\r
+  UINT32                   DigestListBinSize;\r
+  UINT8                    *Event;\r
+  UINT32                   EventSize;\r
+  EFI_CC_EVENT_LOG_FORMAT  LogFormat;\r
+\r
+  DEBUG ((DEBUG_INFO, "Sync Cc event from SEC\n"));\r
+\r
+  Status       = EFI_SUCCESS;\r
+  LogFormat    = EFI_CC_EVENT_LOG_FORMAT_TCG_2;\r
+  GuidHob.Guid = GetFirstGuidHob (&gCcEventEntryHobGuid);\r
+\r
+  while (!EFI_ERROR (Status) && GuidHob.Guid != NULL) {\r
+    CcEvent = AllocateCopyPool (GET_GUID_HOB_DATA_SIZE (GuidHob.Guid), GET_GUID_HOB_DATA (GuidHob.Guid));\r
+    if (CcEvent == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    GuidHob.Guid = GET_NEXT_HOB (GuidHob);\r
+    GuidHob.Guid = GetNextGuidHob (&gCcEventEntryHobGuid, GuidHob.Guid);\r
+\r
+    DigestListBin     = (UINT8 *)CcEvent + sizeof (UINT32) + sizeof (TCG_EVENTTYPE);\r
+    DigestListBinSize = GetDigestListBinSize (DigestListBin);\r
+\r
+    //\r
+    // Event size.\r
+    //\r
+    EventSize = *(UINT32 *)((UINT8 *)DigestListBin + DigestListBinSize);\r
+    Event     = (UINT8 *)DigestListBin + DigestListBinSize + sizeof (UINT32);\r
+\r
+    //\r
+    // Log the event\r
+    //\r
+    Status = TdxDxeLogEvent (\r
+               LogFormat,\r
+               CcEvent,\r
+               sizeof (UINT32) + sizeof (TCG_EVENTTYPE) + DigestListBinSize + sizeof (UINT32),\r
+               Event,\r
+               EventSize\r
+               );\r
+\r
+    DumpCcEvent ((CC_EVENT *)CcEvent);\r
+    FreePool (CcEvent);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Install TDVF ACPI Table when ACPI Table Protocol is available.\r
+\r
+  @param[in]  Event     Event whose notification function is being invoked\r
+  @param[in]  Context   Pointer to the notification function's context\r
+**/\r
+VOID\r
+EFIAPI\r
+InstallAcpiTable (\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *Context\r
+  )\r
+{\r
+  UINTN                    TableKey;\r
+  EFI_STATUS               Status;\r
+  EFI_ACPI_TABLE_PROTOCOL  *AcpiTable;\r
+  UINT64                   OemTableId;\r
+\r
+  Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **)&AcpiTable);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "TD: AcpiTableProtocol is not installed. %r\n", Status));\r
+    return;\r
+  }\r
+\r
+  mTdxEventlogAcpiTemplate.Laml = (UINT64)PcdGet32 (PcdCcEventlogAcpiTableLaml);\r
+  mTdxEventlogAcpiTemplate.Lasa = PcdGet64 (PcdCcEventlogAcpiTableLasa);\r
+  CopyMem (mTdxEventlogAcpiTemplate.Header.OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (mTdxEventlogAcpiTemplate.Header.OemId));\r
+  OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId);\r
+  CopyMem (&mTdxEventlogAcpiTemplate.Header.OemTableId, &OemTableId, sizeof (UINT64));\r
+  mTdxEventlogAcpiTemplate.Header.OemRevision     = PcdGet32 (PcdAcpiDefaultOemRevision);\r
+  mTdxEventlogAcpiTemplate.Header.CreatorId       = PcdGet32 (PcdAcpiDefaultCreatorId);\r
+  mTdxEventlogAcpiTemplate.Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);\r
+\r
+  //\r
+  // Construct ACPI Table\r
+  Status = AcpiTable->InstallAcpiTable (\r
+                        AcpiTable,\r
+                        &mTdxEventlogAcpiTemplate,\r
+                        mTdxEventlogAcpiTemplate.Header.Length,\r
+                        &TableKey\r
+                        );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  DEBUG ((DEBUG_INFO, "TDVF Eventlog ACPI Table is installed.\n"));\r
+}\r
+\r
+/**\r
+  The function install TdTcg2 protocol.\r
+\r
+  @retval EFI_SUCCESS     TdTcg2 protocol is installed.\r
+  @retval other           Some error occurs.\r
+**/\r
+EFI_STATUS\r
+InstallCcMeasurementProtocol (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  EFI_HANDLE  Handle;\r
+\r
+  Handle = NULL;\r
+  Status = gBS->InstallMultipleProtocolInterfaces (\r
+                  &Handle,\r
+                  &gEfiCcMeasurementProtocolGuid,\r
+                  &mTdProtocol,\r
+                  NULL\r
+                  );\r
+  DEBUG ((DEBUG_INFO, "CcProtocol: Install %r\n", Status));\r
+  return Status;\r
+}\r
+\r
+/**\r
+  The driver's entry point. It publishes EFI Tcg2 Protocol.\r
+\r
+  @param[in] ImageHandle  The firmware allocated handle for the EFI image.\r
+  @param[in] SystemTable  A pointer to the EFI System Table.\r
+\r
+  @retval EFI_SUCCESS     The entry point is executed successfully.\r
+  @retval other           Some error occurs when executing this entry point.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DriverEntry (\r
+  IN    EFI_HANDLE        ImageHandle,\r
+  IN    EFI_SYSTEM_TABLE  *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  EFI_EVENT   Event;\r
+  VOID        *Registration;\r
+\r
+  if (!TdIsEnabled ()) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  mImageHandle = ImageHandle;\r
+\r
+  //\r
+  // Fill information\r
+  //\r
+  //  ASSERT (TD_EVENT_LOG_AREA_COUNT_MAX == sizeof(mTEventInfo)/sizeof(mTcg2EventInfo[0]));\r
+\r
+  mTdxDxeData.BsCap.Size                   = sizeof (EFI_CC_BOOT_SERVICE_CAPABILITY);\r
+  mTdxDxeData.BsCap.ProtocolVersion.Major  = 1;\r
+  mTdxDxeData.BsCap.ProtocolVersion.Minor  = 0;\r
+  mTdxDxeData.BsCap.StructureVersion.Major = 1;\r
+  mTdxDxeData.BsCap.StructureVersion.Minor = 0;\r
+\r
+  //\r
+  // Get supported PCR and current Active PCRs\r
+  // For TD gueset HA384 is supported.\r
+  //\r
+  mTdxDxeData.BsCap.HashAlgorithmBitmap = HASH_ALG_SHA384;\r
+\r
+  // TD guest only supports EFI_TCG2_EVENT_LOG_FORMAT_TCG_2\r
+  mTdxDxeData.BsCap.SupportedEventLogs = EFI_CC_EVENT_LOG_FORMAT_TCG_2;\r
+\r
+  //\r
+  // Setup the log area and copy event log from hob list to it\r
+  //\r
+  Status = SetupCcEventLog ();\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    Status = SyncCcEvent ();\r
+    ASSERT_EFI_ERROR (Status);\r
+  }\r
+\r
+  //\r
+  // Measure handoff tables, Boot#### variables etc.\r
+  //\r
+  Status = EfiCreateEventReadyToBootEx (\r
+             TPL_CALLBACK,\r
+             OnReadyToBoot,\r
+             NULL,\r
+             &Event\r
+             );\r
+\r
+  Status = gBS->CreateEventEx (\r
+                  EVT_NOTIFY_SIGNAL,\r
+                  TPL_NOTIFY,\r
+                  OnExitBootServices,\r
+                  NULL,\r
+                  &gEfiEventExitBootServicesGuid,\r
+                  &Event\r
+                  );\r
+\r
+  //\r
+  // Measure Exit Boot Service failed\r
+  //\r
+  Status = gBS->CreateEventEx (\r
+                  EVT_NOTIFY_SIGNAL,\r
+                  TPL_NOTIFY,\r
+                  OnExitBootServicesFailed,\r
+                  NULL,\r
+                  &gEventExitBootServicesFailedGuid,\r
+                  &Event\r
+                  );\r
+\r
+  //\r
+  // Create event callback, because we need access variable on SecureBootPolicyVariable\r
+  // We should use VariableWriteArch instead of VariableArch, because Variable driver\r
+  // may update SecureBoot value based on last setting.\r
+  //\r
+  EfiCreateProtocolNotifyEvent (&gEfiVariableWriteArchProtocolGuid, TPL_CALLBACK, MeasureSecureBootPolicy, NULL, &Registration);\r
+\r
+  //\r
+  // Install CcMeasurementProtocol\r
+  //\r
+  Status = InstallCcMeasurementProtocol ();\r
+  DEBUG ((DEBUG_INFO, "InstallCcMeasurementProtocol - %r\n", Status));\r
+\r
+  if (Status == EFI_SUCCESS) {\r
+    //\r
+    // Create event callback to install CC EventLog ACPI Table\r
+    EfiCreateProtocolNotifyEvent (&gEfiAcpiTableProtocolGuid, TPL_CALLBACK, InstallAcpiTable, NULL, &Registration);\r
+  }\r
+\r
+  return Status;\r
+}\r