]> git.proxmox.com Git - mirror_edk2.git/blobdiff - OvmfPkg/IntelTdx/TdxHelperLib/SecTdxHelper.c
OvmfPkg: Refactor ProcessHobList
[mirror_edk2.git] / OvmfPkg / IntelTdx / TdxHelperLib / SecTdxHelper.c
index 1929093f9110d59c362f6f141cf25f2a4775c27d..3372cee2f720a0bfe755a50ad9bf748a2e8cb1ed 100644 (file)
 #include <IndustryStandard/IntelTdx.h>\r
 #include <IndustryStandard/Tpm20.h>\r
 #include <Library/TdxLib.h>\r
+#include <Library/TdxMailboxLib.h>\r
+#include <Library/SynchronizationLib.h>\r
 #include <Pi/PrePiHob.h>\r
 #include <WorkArea.h>\r
 #include <ConfidentialComputingGuestAttr.h>\r
 #include <Library/TdxHelperLib.h>\r
 \r
+#define ALIGNED_2MB_MASK  0x1fffff\r
+#define MEGABYTE_SHIFT    20\r
+\r
+#define ACCEPT_CHUNK_SIZE  SIZE_32MB\r
+#define AP_STACK_SIZE      SIZE_16KB\r
+#define APS_STACK_SIZE(CpusNum)  (ALIGN_VALUE(CpusNum*AP_STACK_SIZE, SIZE_2MB))\r
+\r
 /**\r
   Build the GuidHob for tdx measurements which were done in SEC phase.\r
   The measurement values are stored in WorkArea.\r
@@ -34,6 +43,720 @@ InternalBuildGuidHobForTdxMeasurement (
   VOID\r
   );\r
 \r
+/**\r
+  This function will be called to accept pages. Only BSP accepts pages.\r
+\r
+  TDCALL(ACCEPT_PAGE) supports the accept page size of 4k and 2M. To\r
+  simplify the implementation, the Memory to be accpeted is splitted\r
+  into 3 parts:\r
+  -----------------  <-- StartAddress1 (not 2M aligned)\r
+  |  part 1       |      Length1 < 2M\r
+  |---------------|  <-- StartAddress2 (2M aligned)\r
+  |               |      Length2 = Integer multiples of 2M\r
+  |  part 2       |\r
+  |               |\r
+  |---------------|  <-- StartAddress3\r
+  |  part 3       |      Length3 < 2M\r
+  |---------------|\r
+\r
+  @param[in] PhysicalAddress   Start physical adress\r
+  @param[in] PhysicalEnd       End physical address\r
+\r
+  @retval    EFI_SUCCESS       Accept memory successfully\r
+  @retval    Others            Other errors as indicated\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+BspAcceptMemoryResourceRange (\r
+  IN EFI_PHYSICAL_ADDRESS  PhysicalAddress,\r
+  IN EFI_PHYSICAL_ADDRESS  PhysicalEnd\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINT32      AcceptPageSize;\r
+  UINT64      StartAddress1;\r
+  UINT64      StartAddress2;\r
+  UINT64      StartAddress3;\r
+  UINT64      TotalLength;\r
+  UINT64      Length1;\r
+  UINT64      Length2;\r
+  UINT64      Length3;\r
+  UINT64      Pages;\r
+\r
+  AcceptPageSize = FixedPcdGet32 (PcdTdxAcceptPageSize);\r
+  TotalLength    = PhysicalEnd - PhysicalAddress;\r
+  StartAddress1  = 0;\r
+  StartAddress2  = 0;\r
+  StartAddress3  = 0;\r
+  Length1        = 0;\r
+  Length2        = 0;\r
+  Length3        = 0;\r
+\r
+  if (TotalLength == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if (ALIGN_VALUE (PhysicalAddress, SIZE_2MB) != PhysicalAddress) {\r
+    StartAddress1 = PhysicalAddress;\r
+    Length1       = ALIGN_VALUE (PhysicalAddress, SIZE_2MB) - PhysicalAddress;\r
+    if (Length1 >= TotalLength) {\r
+      Length1 = TotalLength;\r
+    }\r
+\r
+    PhysicalAddress += Length1;\r
+    TotalLength     -= Length1;\r
+  }\r
+\r
+  if (TotalLength > SIZE_2MB) {\r
+    StartAddress2    = PhysicalAddress;\r
+    Length2          = TotalLength & ~(UINT64)ALIGNED_2MB_MASK;\r
+    PhysicalAddress += Length2;\r
+    TotalLength     -= Length2;\r
+  }\r
+\r
+  if (TotalLength) {\r
+    StartAddress3 = PhysicalAddress;\r
+    Length3       = TotalLength;\r
+  }\r
+\r
+  Status = EFI_SUCCESS;\r
+  if (Length1 > 0) {\r
+    Pages  = Length1 / SIZE_4KB;\r
+    Status = TdAcceptPages (StartAddress1, Pages, SIZE_4KB);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  if (Length2 > 0) {\r
+    Pages  = Length2 / AcceptPageSize;\r
+    Status = TdAcceptPages (StartAddress2, Pages, AcceptPageSize);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  if (Length3 > 0) {\r
+    Pages  = Length3 / SIZE_4KB;\r
+    Status = TdAcceptPages (StartAddress3, Pages, SIZE_4KB);\r
+    ASSERT (!EFI_ERROR (Status));\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+ * This function is called by BSP and APs to accept memory.\r
+ * Note:\r
+ * The input PhysicalStart/PhysicalEnd indicates the whole memory region\r
+ * to be accepted. BSP or AP only accepts one piece in the whole memory region.\r
+ *\r
+ * @param CpuIndex        vCPU index\r
+ * @param CpusNum         Total vCPU number of a Tdx guest\r
+ * @param PhysicalStart   Start address of a memory region which is to be accepted\r
+ * @param PhysicalEnd     End address of a memory region which is to be accepted\r
+ *\r
+ * @retval EFI_SUCCESS    Successfully accept the memory\r
+ * @retval Other          Other errors as indicated\r
+ */\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+BspApAcceptMemoryResourceRange (\r
+  UINT32                CpuIndex,\r
+  UINT32                CpusNum,\r
+  EFI_PHYSICAL_ADDRESS  PhysicalStart,\r
+  EFI_PHYSICAL_ADDRESS  PhysicalEnd\r
+  )\r
+{\r
+  UINT64                Status;\r
+  UINT64                Pages;\r
+  UINT64                Stride;\r
+  UINT64                AcceptPageSize;\r
+  EFI_PHYSICAL_ADDRESS  PhysicalAddress;\r
+\r
+  AcceptPageSize = (UINT64)(UINTN)FixedPcdGet32 (PcdTdxAcceptPageSize);\r
+\r
+  Status          = EFI_SUCCESS;\r
+  Stride          = (UINTN)CpusNum * ACCEPT_CHUNK_SIZE;\r
+  PhysicalAddress = PhysicalStart + ACCEPT_CHUNK_SIZE * (UINTN)CpuIndex;\r
+\r
+  while (!EFI_ERROR (Status) && PhysicalAddress < PhysicalEnd) {\r
+    Pages  = MIN (ACCEPT_CHUNK_SIZE, PhysicalEnd - PhysicalAddress) / AcceptPageSize;\r
+    Status = TdAcceptPages (PhysicalAddress, Pages, (UINT32)(UINTN)AcceptPageSize);\r
+    ASSERT (!EFI_ERROR (Status));\r
+    PhysicalAddress += Stride;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ * This function is called by APs to accept memory.\r
+ *\r
+ * @param CpuIndex        vCPU index of an AP\r
+ * @param PhysicalStart   Start address of a memory region which is to be accepted\r
+ * @param PhysicalEnd     End address of a memory region which is to be accepted\r
+ *\r
+ * @retval EFI_SUCCESS    Successfully accept the memory\r
+ * @retval Others         Other errors as indicated\r
+ */\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+ApAcceptMemoryResourceRange (\r
+  UINT32                CpuIndex,\r
+  EFI_PHYSICAL_ADDRESS  PhysicalStart,\r
+  EFI_PHYSICAL_ADDRESS  PhysicalEnd\r
+  )\r
+{\r
+  UINT64          Status;\r
+  TD_RETURN_DATA  TdReturnData;\r
+\r
+  Status = TdCall (TDCALL_TDINFO, 0, 0, 0, &TdReturnData);\r
+  if (Status != TDX_EXIT_REASON_SUCCESS) {\r
+    ASSERT (FALSE);\r
+    return EFI_ABORTED;\r
+  }\r
+\r
+  if ((CpuIndex == 0) || (CpuIndex >= TdReturnData.TdInfo.NumVcpus)) {\r
+    ASSERT (FALSE);\r
+    return EFI_ABORTED;\r
+  }\r
+\r
+  return BspApAcceptMemoryResourceRange (CpuIndex, TdReturnData.TdInfo.NumVcpus, PhysicalStart, PhysicalEnd);\r
+}\r
+\r
+/**\r
+ * This function is called by BSP. It coordinates BSP/APs to accept memory together.\r
+ *\r
+ * @param PhysicalStart     Start address of a memory region which is to be accepted\r
+ * @param PhysicalEnd       End address of a memory region which is to be accepted\r
+ * @param APsStackAddress   APs stack address\r
+ * @param CpusNum           Total vCPU number of the Tdx guest\r
+ *\r
+ * @retval EFI_SUCCESS      Successfully accept the memory\r
+ * @retval Others           Other errors as indicated\r
+ */\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+MpAcceptMemoryResourceRange (\r
+  IN EFI_PHYSICAL_ADDRESS      PhysicalStart,\r
+  IN EFI_PHYSICAL_ADDRESS      PhysicalEnd,\r
+  IN OUT EFI_PHYSICAL_ADDRESS  APsStackAddress,\r
+  IN UINT32                    CpusNum\r
+  )\r
+{\r
+  UINT64      Length;\r
+  EFI_STATUS  Status;\r
+\r
+  Length = PhysicalEnd - PhysicalStart;\r
+\r
+  DEBUG ((DEBUG_INFO, "MpAccept : 0x%llx - 0x%llx (0x%llx)\n", PhysicalStart, PhysicalEnd, Length));\r
+\r
+  if (Length == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // The start address is not 2M aligned. BSP first accept the part which is not 2M aligned.\r
+  //\r
+  if (ALIGN_VALUE (PhysicalStart, SIZE_2MB) != PhysicalStart) {\r
+    Length = MIN (ALIGN_VALUE (PhysicalStart, SIZE_2MB) - PhysicalStart, Length);\r
+    Status = BspAcceptMemoryResourceRange (PhysicalStart, PhysicalStart + Length);\r
+    ASSERT (Status == EFI_SUCCESS);\r
+\r
+    PhysicalStart += Length;\r
+    Length         = PhysicalEnd - PhysicalStart;\r
+  }\r
+\r
+  if (Length == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // BSP will accept the memory by itself if the memory is not big enough compared with a chunk.\r
+  //\r
+  if (Length <= ACCEPT_CHUNK_SIZE) {\r
+    return BspAcceptMemoryResourceRange (PhysicalStart, PhysicalEnd);\r
+  }\r
+\r
+  //\r
+  // Now APs are asked to accept the memory together.\r
+  //\r
+  MpSerializeStart ();\r
+\r
+  MpSendWakeupCommand (\r
+    MpProtectedModeWakeupCommandAcceptPages,\r
+    (UINT64)(UINTN)ApAcceptMemoryResourceRange,\r
+    PhysicalStart,\r
+    PhysicalEnd,\r
+    APsStackAddress,\r
+    AP_STACK_SIZE\r
+    );\r
+\r
+  //\r
+  // Now BSP does its job.\r
+  //\r
+  BspApAcceptMemoryResourceRange (0, CpusNum, PhysicalStart, PhysicalEnd);\r
+\r
+  MpSerializeEnd ();\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  BSP accept a small piece of memory which will be used as APs stack.\r
+\r
+  @param[in] VmmHobList    The Hoblist pass the firmware\r
+  @param[in] APsStackSize  APs stack size\r
+  @param[out] PhysicalAddressEnd    The physical end address of accepted memory in phase-1\r
+\r
+  @retval  EFI_SUCCESS     Process the HobList successfully\r
+  @retval  Others          Other errors as indicated\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+AcceptMemoryForAPsStack (\r
+  IN CONST VOID             *VmmHobList,\r
+  IN UINT32                 APsStackSize,\r
+  OUT EFI_PHYSICAL_ADDRESS  *PhysicalAddressEnd\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  EFI_PEI_HOB_POINTERS  Hob;\r
+  EFI_PHYSICAL_ADDRESS  PhysicalEnd;\r
+  EFI_PHYSICAL_ADDRESS  PhysicalStart;\r
+  UINT64                ResourceLength;\r
+  BOOLEAN               MemoryRegionFound;\r
+\r
+  ASSERT (VmmHobList != NULL);\r
+\r
+  Status            = EFI_SUCCESS;\r
+  Hob.Raw           = (UINT8 *)VmmHobList;\r
+  MemoryRegionFound = FALSE;\r
+\r
+  DEBUG ((DEBUG_INFO, "AcceptMemoryForAPsStack with APsStackSize=0x%x\n", APsStackSize));\r
+\r
+  //\r
+  // Parse the HOB list until end of list or matching type is found.\r
+  //\r
+  while (!END_OF_HOB_LIST (Hob) && !MemoryRegionFound) {\r
+    if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {\r
+      DEBUG ((DEBUG_INFO, "\nResourceType: 0x%x\n", Hob.ResourceDescriptor->ResourceType));\r
+\r
+      if (Hob.ResourceDescriptor->ResourceType == BZ3937_EFI_RESOURCE_MEMORY_UNACCEPTED) {\r
+        ResourceLength = Hob.ResourceDescriptor->ResourceLength;\r
+        PhysicalStart  = Hob.ResourceDescriptor->PhysicalStart;\r
+        PhysicalEnd    = PhysicalStart + ResourceLength;\r
+\r
+        DEBUG ((DEBUG_INFO, "ResourceAttribute: 0x%x\n", Hob.ResourceDescriptor->ResourceAttribute));\r
+        DEBUG ((DEBUG_INFO, "PhysicalStart: 0x%llx\n", PhysicalStart));\r
+        DEBUG ((DEBUG_INFO, "ResourceLength: 0x%llx\n", ResourceLength));\r
+        DEBUG ((DEBUG_INFO, "Owner: %g\n\n", &Hob.ResourceDescriptor->Owner));\r
+\r
+        if (ResourceLength >= APsStackSize) {\r
+          MemoryRegionFound = TRUE;\r
+          if (ResourceLength > ACCEPT_CHUNK_SIZE) {\r
+            PhysicalEnd = Hob.ResourceDescriptor->PhysicalStart + APsStackSize;\r
+          }\r
+        }\r
+\r
+        Status = BspAcceptMemoryResourceRange (\r
+                   Hob.ResourceDescriptor->PhysicalStart,\r
+                   PhysicalEnd\r
+                   );\r
+        if (EFI_ERROR (Status)) {\r
+          break;\r
+        }\r
+      }\r
+    }\r
+\r
+    Hob.Raw = GET_NEXT_HOB (Hob);\r
+  }\r
+\r
+  ASSERT (MemoryRegionFound);\r
+  *PhysicalAddressEnd = PhysicalEnd;\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  BSP and APs work togeter to accept memory which is under the address of 4G.\r
+\r
+  @param[in] VmmHobList           The Hoblist pass the firmware\r
+  @param[in] CpusNum              Number of vCPUs\r
+  @param[in] APsStackStartAddres  Start address of APs stack\r
+  @param[in] PhysicalAddressStart Start physical address which to be accepted\r
+\r
+  @retval  EFI_SUCCESS     Process the HobList successfully\r
+  @retval  Others          Other errors as indicated\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+AcceptMemory (\r
+  IN CONST VOID            *VmmHobList,\r
+  IN UINT32                CpusNum,\r
+  IN EFI_PHYSICAL_ADDRESS  APsStackStartAddress,\r
+  IN EFI_PHYSICAL_ADDRESS  PhysicalAddressStart\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  EFI_PEI_HOB_POINTERS  Hob;\r
+  EFI_PHYSICAL_ADDRESS  PhysicalStart;\r
+  EFI_PHYSICAL_ADDRESS  PhysicalEnd;\r
+  EFI_PHYSICAL_ADDRESS  AcceptMemoryEndAddress;\r
+\r
+  Status                 = EFI_SUCCESS;\r
+  AcceptMemoryEndAddress = BASE_4GB;\r
+\r
+  ASSERT (VmmHobList != NULL);\r
+  Hob.Raw = (UINT8 *)VmmHobList;\r
+\r
+  DEBUG ((DEBUG_INFO, "AcceptMemory under address of 4G\n"));\r
+\r
+  //\r
+  // Parse the HOB list until end of list or matching type is found.\r
+  //\r
+  while (!END_OF_HOB_LIST (Hob)) {\r
+    if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {\r
+      if (Hob.ResourceDescriptor->ResourceType == BZ3937_EFI_RESOURCE_MEMORY_UNACCEPTED) {\r
+        PhysicalStart = Hob.ResourceDescriptor->PhysicalStart;\r
+        PhysicalEnd   = PhysicalStart + Hob.ResourceDescriptor->ResourceLength;\r
+\r
+        if (PhysicalEnd <= PhysicalAddressStart) {\r
+          // this memory region has been accepted. Skipped it.\r
+          Hob.Raw = GET_NEXT_HOB (Hob);\r
+          continue;\r
+        }\r
+\r
+        if (PhysicalStart >= AcceptMemoryEndAddress) {\r
+          // this memory region is not to be accepted. And we're done.\r
+          break;\r
+        }\r
+\r
+        if (PhysicalStart >= PhysicalAddressStart) {\r
+          // this memory region has not been acceted.\r
+        } else if ((PhysicalStart < PhysicalAddressStart) && (PhysicalEnd > PhysicalAddressStart)) {\r
+          // part of the memory region has been accepted.\r
+          PhysicalStart = PhysicalAddressStart;\r
+        }\r
+\r
+        // then compare the PhysicalEnd with AcceptMemoryEndAddress\r
+        if (PhysicalEnd >= AcceptMemoryEndAddress) {\r
+          PhysicalEnd = AcceptMemoryEndAddress;\r
+        }\r
+\r
+        DEBUG ((DEBUG_INFO, "ResourceAttribute: 0x%x\n", Hob.ResourceDescriptor->ResourceAttribute));\r
+        DEBUG ((DEBUG_INFO, "PhysicalStart: 0x%llx\n", Hob.ResourceDescriptor->PhysicalStart));\r
+        DEBUG ((DEBUG_INFO, "ResourceLength: 0x%llx\n", Hob.ResourceDescriptor->ResourceLength));\r
+        DEBUG ((DEBUG_INFO, "Owner: %g\n\n", &Hob.ResourceDescriptor->Owner));\r
+\r
+        // Now we're ready to accept memory [PhysicalStart, PhysicalEnd)\r
+        if (CpusNum == 1) {\r
+          Status = BspAcceptMemoryResourceRange (PhysicalStart, PhysicalEnd);\r
+        } else {\r
+          Status = MpAcceptMemoryResourceRange (\r
+                     PhysicalStart,\r
+                     PhysicalEnd,\r
+                     APsStackStartAddress,\r
+                     CpusNum\r
+                     );\r
+        }\r
+\r
+        if (EFI_ERROR (Status)) {\r
+          ASSERT (FALSE);\r
+          break;\r
+        }\r
+\r
+        if (PhysicalEnd == AcceptMemoryEndAddress) {\r
+          break;\r
+        }\r
+      }\r
+    }\r
+\r
+    Hob.Raw = GET_NEXT_HOB (Hob);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Check the value whether in the valid list.\r
+\r
+  @param[in] Value             A value\r
+  @param[in] ValidList         A pointer to valid list\r
+  @param[in] ValidListLength   Length of valid list\r
+\r
+  @retval  TRUE   The value is in valid list.\r
+  @retval  FALSE  The value is not in valid list.\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+EFIAPI\r
+IsInValidList (\r
+  IN UINT32  Value,\r
+  IN UINT32  *ValidList,\r
+  IN UINT32  ValidListLength\r
+  )\r
+{\r
+  UINT32  index;\r
+\r
+  if (ValidList == NULL) {\r
+    return FALSE;\r
+  }\r
+\r
+  for (index = 0; index < ValidListLength; index++) {\r
+    if (ValidList[index] == Value) {\r
+      return TRUE;\r
+    }\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Check the integrity of VMM Hob List.\r
+\r
+  @param[in] VmmHobList   A pointer to Hob List\r
+\r
+  @retval  TRUE     The Hob List is valid.\r
+  @retval  FALSE    The Hob List is invalid.\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+EFIAPI\r
+ValidateHobList (\r
+  IN CONST VOID  *VmmHobList\r
+  )\r
+{\r
+  EFI_PEI_HOB_POINTERS  Hob;\r
+  UINT32                EFI_BOOT_MODE_LIST[] = {\r
+    BOOT_WITH_FULL_CONFIGURATION,\r
+    BOOT_WITH_MINIMAL_CONFIGURATION,\r
+    BOOT_ASSUMING_NO_CONFIGURATION_CHANGES,\r
+    BOOT_WITH_FULL_CONFIGURATION_PLUS_DIAGNOSTICS,\r
+    BOOT_WITH_DEFAULT_SETTINGS,\r
+    BOOT_ON_S4_RESUME,\r
+    BOOT_ON_S5_RESUME,\r
+    BOOT_WITH_MFG_MODE_SETTINGS,\r
+    BOOT_ON_S2_RESUME,\r
+    BOOT_ON_S3_RESUME,\r
+    BOOT_ON_FLASH_UPDATE,\r
+    BOOT_IN_RECOVERY_MODE\r
+  };\r
+\r
+  UINT32  EFI_RESOURCE_TYPE_LIST[] = {\r
+    EFI_RESOURCE_SYSTEM_MEMORY,\r
+    EFI_RESOURCE_MEMORY_MAPPED_IO,\r
+    EFI_RESOURCE_IO,\r
+    EFI_RESOURCE_FIRMWARE_DEVICE,\r
+    EFI_RESOURCE_MEMORY_MAPPED_IO_PORT,\r
+    EFI_RESOURCE_MEMORY_RESERVED,\r
+    EFI_RESOURCE_IO_RESERVED,\r
+    BZ3937_EFI_RESOURCE_MEMORY_UNACCEPTED\r
+  };\r
+\r
+  if (VmmHobList == NULL) {\r
+    DEBUG ((DEBUG_ERROR, "HOB: HOB data pointer is NULL\n"));\r
+    return FALSE;\r
+  }\r
+\r
+  Hob.Raw = (UINT8 *)VmmHobList;\r
+\r
+  //\r
+  // Parse the HOB list until end of list or matching type is found.\r
+  //\r
+  while (!END_OF_HOB_LIST (Hob)) {\r
+    if (Hob.Header->Reserved != (UINT32)0) {\r
+      DEBUG ((DEBUG_ERROR, "HOB: Hob header Reserved filed should be zero\n"));\r
+      return FALSE;\r
+    }\r
+\r
+    if (Hob.Header->HobLength == 0) {\r
+      DEBUG ((DEBUG_ERROR, "HOB: Hob header LEANGTH should not be zero\n"));\r
+      return FALSE;\r
+    }\r
+\r
+    switch (Hob.Header->HobType) {\r
+      case EFI_HOB_TYPE_HANDOFF:\r
+        if (Hob.Header->HobLength != sizeof (EFI_HOB_HANDOFF_INFO_TABLE)) {\r
+          DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_HANDOFF));\r
+          return FALSE;\r
+        }\r
+\r
+        if (IsInValidList (Hob.HandoffInformationTable->BootMode, EFI_BOOT_MODE_LIST, ARRAY_SIZE (EFI_BOOT_MODE_LIST)) == FALSE) {\r
+          DEBUG ((DEBUG_ERROR, "HOB: Unknow HandoffInformationTable BootMode type. Type: 0x%08x\n", Hob.HandoffInformationTable->BootMode));\r
+          return FALSE;\r
+        }\r
+\r
+        if ((Hob.HandoffInformationTable->EfiFreeMemoryTop % 4096) != 0) {\r
+          DEBUG ((DEBUG_ERROR, "HOB: HandoffInformationTable EfiFreeMemoryTop address must be 4-KB aligned to meet page restrictions of UEFI.\\r
+                               Address: 0x%016lx\n", Hob.HandoffInformationTable->EfiFreeMemoryTop));\r
+          return FALSE;\r
+        }\r
+\r
+        break;\r
+\r
+      case EFI_HOB_TYPE_RESOURCE_DESCRIPTOR:\r
+        if (Hob.Header->HobLength != sizeof (EFI_HOB_RESOURCE_DESCRIPTOR)) {\r
+          DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_RESOURCE_DESCRIPTOR));\r
+          return FALSE;\r
+        }\r
+\r
+        if (IsInValidList (Hob.ResourceDescriptor->ResourceType, EFI_RESOURCE_TYPE_LIST, ARRAY_SIZE (EFI_RESOURCE_TYPE_LIST)) == FALSE) {\r
+          DEBUG ((DEBUG_ERROR, "HOB: Unknow ResourceDescriptor ResourceType type. Type: 0x%08x\n", Hob.ResourceDescriptor->ResourceType));\r
+          return FALSE;\r
+        }\r
+\r
+        if ((Hob.ResourceDescriptor->ResourceAttribute & (~(EFI_RESOURCE_ATTRIBUTE_PRESENT |\r
+                                                            EFI_RESOURCE_ATTRIBUTE_INITIALIZED |\r
+                                                            EFI_RESOURCE_ATTRIBUTE_TESTED |\r
+                                                            EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED |\r
+                                                            EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED |\r
+                                                            EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED |\r
+                                                            EFI_RESOURCE_ATTRIBUTE_PERSISTENT |\r
+                                                            EFI_RESOURCE_ATTRIBUTE_SINGLE_BIT_ECC |\r
+                                                            EFI_RESOURCE_ATTRIBUTE_MULTIPLE_BIT_ECC |\r
+                                                            EFI_RESOURCE_ATTRIBUTE_ECC_RESERVED_1 |\r
+                                                            EFI_RESOURCE_ATTRIBUTE_ECC_RESERVED_2 |\r
+                                                            EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |\r
+                                                            EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |\r
+                                                            EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |\r
+                                                            EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE |\r
+                                                            EFI_RESOURCE_ATTRIBUTE_16_BIT_IO |\r
+                                                            EFI_RESOURCE_ATTRIBUTE_32_BIT_IO |\r
+                                                            EFI_RESOURCE_ATTRIBUTE_64_BIT_IO |\r
+                                                            EFI_RESOURCE_ATTRIBUTE_UNCACHED_EXPORTED |\r
+                                                            EFI_RESOURCE_ATTRIBUTE_READ_PROTECTABLE |\r
+                                                            EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTABLE |\r
+                                                            EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTABLE |\r
+                                                            EFI_RESOURCE_ATTRIBUTE_PERSISTABLE |\r
+                                                            EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTED |\r
+                                                            EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTABLE |\r
+                                                            EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE))) != 0)\r
+        {\r
+          DEBUG ((DEBUG_ERROR, "HOB: Unknow ResourceDescriptor ResourceAttribute type. Type: 0x%08x\n", Hob.ResourceDescriptor->ResourceAttribute));\r
+          return FALSE;\r
+        }\r
+\r
+        break;\r
+\r
+      // EFI_HOB_GUID_TYPE is variable length data, so skip check\r
+      case EFI_HOB_TYPE_GUID_EXTENSION:\r
+        break;\r
+\r
+      case EFI_HOB_TYPE_FV:\r
+        if (Hob.Header->HobLength != sizeof (EFI_HOB_FIRMWARE_VOLUME)) {\r
+          DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_FV));\r
+          return FALSE;\r
+        }\r
+\r
+        break;\r
+\r
+      case EFI_HOB_TYPE_FV2:\r
+        if (Hob.Header->HobLength != sizeof (EFI_HOB_FIRMWARE_VOLUME2)) {\r
+          DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_FV2));\r
+          return FALSE;\r
+        }\r
+\r
+        break;\r
+\r
+      case EFI_HOB_TYPE_FV3:\r
+        if (Hob.Header->HobLength != sizeof (EFI_HOB_FIRMWARE_VOLUME3)) {\r
+          DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_FV3));\r
+          return FALSE;\r
+        }\r
+\r
+        break;\r
+\r
+      case EFI_HOB_TYPE_CPU:\r
+        if (Hob.Header->HobLength != sizeof (EFI_HOB_CPU)) {\r
+          DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_CPU));\r
+          return FALSE;\r
+        }\r
+\r
+        for (UINT32 index = 0; index < 6; index++) {\r
+          if (Hob.Cpu->Reserved[index] != 0) {\r
+            DEBUG ((DEBUG_ERROR, "HOB: Cpu Reserved field will always be set to zero.\n"));\r
+            return FALSE;\r
+          }\r
+        }\r
+\r
+        break;\r
+\r
+      default:\r
+        DEBUG ((DEBUG_ERROR, "HOB: Hob type is not know. Type: 0x%04x\n", Hob.Header->HobType));\r
+        return FALSE;\r
+    }\r
+\r
+    // Get next HOB\r
+    Hob.Raw = (UINT8 *)(Hob.Raw + Hob.Header->HobLength);\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  Processing the incoming HobList for the TDX\r
+\r
+  Firmware must parse list, and accept the pages of memory before their can be\r
+  use by the guest.\r
+\r
+  @param[in] VmmHobList    The Hoblist pass the firmware\r
+\r
+  @retval  EFI_SUCCESS     Process the HobList successfully\r
+  @retval  Others          Other errors as indicated\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+ProcessHobList (\r
+  IN CONST VOID  *VmmHobList\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  UINT32                CpusNum;\r
+  EFI_PHYSICAL_ADDRESS  PhysicalEnd;\r
+  EFI_PHYSICAL_ADDRESS  APsStackStartAddress;\r
+\r
+  CpusNum = GetCpusNum ();\r
+\r
+  //\r
+  // If there are mutli-vCPU in a TDX guest, accept memory is split into 2 phases.\r
+  // Phase-1 accepts a small piece of memory by BSP. This piece of memory\r
+  // is used to setup AP's stack.\r
+  // After that phase-2 accepts a big piece of memory by BSP/APs.\r
+  //\r
+  // TDVF supports 4K and 2M accept-page-size. The memory which can be accpeted\r
+  // in 2M accept-page-size must be 2M aligned and multiple 2M. So we align\r
+  // APsStackSize to 2M size aligned.\r
+  //\r
+  if (CpusNum > 1) {\r
+    Status = AcceptMemoryForAPsStack (VmmHobList, APS_STACK_SIZE (CpusNum), &PhysicalEnd);\r
+    ASSERT (Status == EFI_SUCCESS);\r
+    APsStackStartAddress = PhysicalEnd - APS_STACK_SIZE (CpusNum);\r
+  } else {\r
+    PhysicalEnd          = 0;\r
+    APsStackStartAddress = 0;\r
+  }\r
+\r
+  Status = AcceptMemory (VmmHobList, CpusNum, APsStackStartAddress, PhysicalEnd);\r
+  ASSERT (Status == EFI_SUCCESS);\r
+\r
+  return Status;\r
+}\r
+\r
 /**\r
   In Tdx guest, some information need to be passed from host VMM to guest\r
   firmware. For example, the memory resource, etc. These information are\r
@@ -49,7 +772,36 @@ TdxHelperProcessTdHob (
   VOID\r
   )\r
 {\r
-  return EFI_UNSUPPORTED;\r
+  EFI_STATUS      Status;\r
+  VOID            *TdHob;\r
+  TD_RETURN_DATA  TdReturnData;\r
+\r
+  TdHob  = (VOID *)(UINTN)FixedPcdGet32 (PcdOvmfSecGhcbBase);\r
+  Status = TdCall (TDCALL_TDINFO, 0, 0, 0, &TdReturnData);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  DEBUG ((\r
+    DEBUG_INFO,\r
+    "Intel Tdx Started with (GPAW: %d, Cpus: %d)\n",\r
+    TdReturnData.TdInfo.Gpaw,\r
+    TdReturnData.TdInfo.NumVcpus\r
+    ));\r
+\r
+  //\r
+  // Validate HobList\r
+  //\r
+  if (ValidateHobList (TdHob) == FALSE) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Process Hoblist to accept memory\r
+  //\r
+  Status = ProcessHobList (TdHob);\r
+\r
+  return Status;\r
 }\r
 \r
 /**\r