IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob\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
- prepared by host VMM and put in HobList which is described in TdxMetadata.\r
-\r
- Information in HobList is treated as external input. From the security\r
- perspective before it is consumed, it should be validated.\r
-\r
- @retval EFI_SUCCESS Successfully process the hoblist\r
- @retval Others Other error as indicated\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-ProcessTdxHobList (\r
- VOID\r
- );\r
-\r
/**\r
In Tdx guest, the system memory is passed in TdHob by host VMM. So\r
the major task of PlatformTdxPublishRamRegions is to walk thru the\r
#include <Library/LocalApicLib.h>\r
#include <Library/CpuExceptionHandlerLib.h>\r
#include <IndustryStandard/Tdx.h>\r
-#include <Library/PlatformInitLib.h>\r
+#include <Library/TdxHelperLib.h>\r
#include <Library/CcProbeLib.h>\r
#include <Library/PeilessStartupLib.h>\r
\r
// first so that the memory is accepted. Otherwise access to the unaccepted\r
// memory will trigger tripple fault.\r
//\r
- if (ProcessTdxHobList () != EFI_SUCCESS) {\r
+ if (TdxHelperProcessTdHob () != EFI_SUCCESS) {\r
CpuDeadLoop ();\r
}\r
}\r
#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
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
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
#include <Library/MemoryAllocationLib.h>\r
#include <IndustryStandard/Tdx.h>\r
#include <IndustryStandard/IntelTdx.h>\r
-#include <IndustryStandard/QemuFwCfg.h>\r
-#include <Library/QemuFwCfgLib.h>\r
#include <Library/PeiServicesLib.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
\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
- 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
-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
-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
-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
-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
-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
-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
-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
- prepared by host VMM and put in HobList which is described in TdxMetadata.\r
-\r
- Information in HobList is treated as external input. From the security\r
- perspective before it is consumed, it should be validated.\r
-\r
- @retval EFI_SUCCESS Successfully process the hoblist\r
- @retval Others Other error as indicated\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-ProcessTdxHobList (\r
- VOID\r
- )\r
-{\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
* Build ResourceDescriptorHob for the unaccepted memory region.\r
* This memory region may be splitted into 2 parts because of lazy accept.\r
\r
#include <PiPei.h>\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
- prepared by host VMM and put in HobList which is described in TdxMetadata.\r
-\r
- Information in HobList is treated as external input. From the security\r
- perspective before it is consumed, it should be validated.\r
-\r
- @retval EFI_SUCCESS Successfully process the hoblist\r
- @retval Others Other error as indicated\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-ProcessTdxHobList (\r
- VOID\r
- )\r
-{\r
- return EFI_UNSUPPORTED;\r
-}\r
-\r
/**\r
In Tdx guest, the system memory is passed in TdHob by host VMM. So\r
the major task of PlatformTdxPublishRamRegions is to walk thru the\r
PcdLib\r
PciLib\r
PeiHardwareInfoLib\r
- TdxMailboxLib\r
\r
[LibraryClasses.X64]\r
TdxLib\r
OvmfPkg/Sec/SecMain.inf {\r
<LibraryClasses>\r
NULL|MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaCustomDecompressLib.inf\r
- NULL|OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf\r
+ NULL|OvmfPkg/IntelTdx/TdxHelperLib/SecTdxHelperLib.inf\r
+ BaseCryptLib|CryptoPkg/Library/BaseCryptLib/SecCryptLib.inf\r
}\r
\r
#\r
#include <Library/CpuExceptionHandlerLib.h>\r
#include <Ppi/TemporaryRamSupport.h>\r
#include <Ppi/MpInitLibDep.h>\r
-#include <Library/PlatformInitLib.h>\r
+#include <Library/TdxHelperLib.h>\r
#include <Library/CcProbeLib.h>\r
#include "AmdSev.h"\r
\r
// first so that the memory is accepted. Otherwise access to the unaccepted\r
// memory will trigger tripple fault.\r
//\r
- if (ProcessTdxHobList () != EFI_SUCCESS) {\r
+ if (TdxHelperProcessTdHob () != EFI_SUCCESS) {\r
CpuDeadLoop ();\r
}\r
}\r