OvmfPkg: Refactor ProcessHobList
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4243 ProcessHobList once was implemented in PlatformInitLib and it walks thru TdHob list and accept un-accepted memories. This patch moves the codes to SecTdxHelperLib and rename ProcessHobList as TdxHelperProcessTdHob After TdxHelperProcessTdHob is introduced, below changes are applied: - Call TdxHelperProcessTdHob instead of ProcessHobList in SecMain.c (in both OvmfPkgX64/Sec and IntelTdx/Sec). - Delete the duplicated codes in PlatformInitLib Cc: Erdem Aktas <erdemaktas@google.com> Cc: James Bottomley <jejb@linux.ibm.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Gerd Hoffmann <kraxel@redhat.com> Cc: Tom Lendacky <thomas.lendacky@amd.com> Cc: Michael Roth <michael.roth@amd.com> Acked-by: Gerd Hoffmann <kraxel@redhat.com> Reviewed-by: Jiewen Yao <jiewen.yao@intel.com> Signed-off-by: Min Xu <min.m.xu@intel.com>
This commit is contained in:
@ -210,23 +210,6 @@ PlatformMaxCpuCountInitialization (
|
|||||||
IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob
|
IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
|
||||||
In Tdx guest, some information need to be passed from host VMM to guest
|
|
||||||
firmware. For example, the memory resource, etc. These information are
|
|
||||||
prepared by host VMM and put in HobList which is described in TdxMetadata.
|
|
||||||
|
|
||||||
Information in HobList is treated as external input. From the security
|
|
||||||
perspective before it is consumed, it should be validated.
|
|
||||||
|
|
||||||
@retval EFI_SUCCESS Successfully process the hoblist
|
|
||||||
@retval Others Other error as indicated
|
|
||||||
**/
|
|
||||||
EFI_STATUS
|
|
||||||
EFIAPI
|
|
||||||
ProcessTdxHobList (
|
|
||||||
VOID
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
In Tdx guest, the system memory is passed in TdHob by host VMM. So
|
In Tdx guest, the system memory is passed in TdHob by host VMM. So
|
||||||
the major task of PlatformTdxPublishRamRegions is to walk thru the
|
the major task of PlatformTdxPublishRamRegions is to walk thru the
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
#include <Library/LocalApicLib.h>
|
#include <Library/LocalApicLib.h>
|
||||||
#include <Library/CpuExceptionHandlerLib.h>
|
#include <Library/CpuExceptionHandlerLib.h>
|
||||||
#include <IndustryStandard/Tdx.h>
|
#include <IndustryStandard/Tdx.h>
|
||||||
#include <Library/PlatformInitLib.h>
|
#include <Library/TdxHelperLib.h>
|
||||||
#include <Library/CcProbeLib.h>
|
#include <Library/CcProbeLib.h>
|
||||||
#include <Library/PeilessStartupLib.h>
|
#include <Library/PeilessStartupLib.h>
|
||||||
|
|
||||||
@ -67,7 +67,7 @@ SecCoreStartupWithStack (
|
|||||||
// first so that the memory is accepted. Otherwise access to the unaccepted
|
// first so that the memory is accepted. Otherwise access to the unaccepted
|
||||||
// memory will trigger tripple fault.
|
// memory will trigger tripple fault.
|
||||||
//
|
//
|
||||||
if (ProcessTdxHobList () != EFI_SUCCESS) {
|
if (TdxHelperProcessTdHob () != EFI_SUCCESS) {
|
||||||
CpuDeadLoop ();
|
CpuDeadLoop ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,11 +17,20 @@
|
|||||||
#include <IndustryStandard/IntelTdx.h>
|
#include <IndustryStandard/IntelTdx.h>
|
||||||
#include <IndustryStandard/Tpm20.h>
|
#include <IndustryStandard/Tpm20.h>
|
||||||
#include <Library/TdxLib.h>
|
#include <Library/TdxLib.h>
|
||||||
|
#include <Library/TdxMailboxLib.h>
|
||||||
|
#include <Library/SynchronizationLib.h>
|
||||||
#include <Pi/PrePiHob.h>
|
#include <Pi/PrePiHob.h>
|
||||||
#include <WorkArea.h>
|
#include <WorkArea.h>
|
||||||
#include <ConfidentialComputingGuestAttr.h>
|
#include <ConfidentialComputingGuestAttr.h>
|
||||||
#include <Library/TdxHelperLib.h>
|
#include <Library/TdxHelperLib.h>
|
||||||
|
|
||||||
|
#define ALIGNED_2MB_MASK 0x1fffff
|
||||||
|
#define MEGABYTE_SHIFT 20
|
||||||
|
|
||||||
|
#define ACCEPT_CHUNK_SIZE SIZE_32MB
|
||||||
|
#define AP_STACK_SIZE SIZE_16KB
|
||||||
|
#define APS_STACK_SIZE(CpusNum) (ALIGN_VALUE(CpusNum*AP_STACK_SIZE, SIZE_2MB))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Build the GuidHob for tdx measurements which were done in SEC phase.
|
Build the GuidHob for tdx measurements which were done in SEC phase.
|
||||||
The measurement values are stored in WorkArea.
|
The measurement values are stored in WorkArea.
|
||||||
@ -34,6 +43,720 @@ InternalBuildGuidHobForTdxMeasurement (
|
|||||||
VOID
|
VOID
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
This function will be called to accept pages. Only BSP accepts pages.
|
||||||
|
|
||||||
|
TDCALL(ACCEPT_PAGE) supports the accept page size of 4k and 2M. To
|
||||||
|
simplify the implementation, the Memory to be accpeted is splitted
|
||||||
|
into 3 parts:
|
||||||
|
----------------- <-- StartAddress1 (not 2M aligned)
|
||||||
|
| part 1 | Length1 < 2M
|
||||||
|
|---------------| <-- StartAddress2 (2M aligned)
|
||||||
|
| | Length2 = Integer multiples of 2M
|
||||||
|
| part 2 |
|
||||||
|
| |
|
||||||
|
|---------------| <-- StartAddress3
|
||||||
|
| part 3 | Length3 < 2M
|
||||||
|
|---------------|
|
||||||
|
|
||||||
|
@param[in] PhysicalAddress Start physical adress
|
||||||
|
@param[in] PhysicalEnd End physical address
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Accept memory successfully
|
||||||
|
@retval Others Other errors as indicated
|
||||||
|
**/
|
||||||
|
STATIC
|
||||||
|
EFI_STATUS
|
||||||
|
EFIAPI
|
||||||
|
BspAcceptMemoryResourceRange (
|
||||||
|
IN EFI_PHYSICAL_ADDRESS PhysicalAddress,
|
||||||
|
IN EFI_PHYSICAL_ADDRESS PhysicalEnd
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EFI_STATUS Status;
|
||||||
|
UINT32 AcceptPageSize;
|
||||||
|
UINT64 StartAddress1;
|
||||||
|
UINT64 StartAddress2;
|
||||||
|
UINT64 StartAddress3;
|
||||||
|
UINT64 TotalLength;
|
||||||
|
UINT64 Length1;
|
||||||
|
UINT64 Length2;
|
||||||
|
UINT64 Length3;
|
||||||
|
UINT64 Pages;
|
||||||
|
|
||||||
|
AcceptPageSize = FixedPcdGet32 (PcdTdxAcceptPageSize);
|
||||||
|
TotalLength = PhysicalEnd - PhysicalAddress;
|
||||||
|
StartAddress1 = 0;
|
||||||
|
StartAddress2 = 0;
|
||||||
|
StartAddress3 = 0;
|
||||||
|
Length1 = 0;
|
||||||
|
Length2 = 0;
|
||||||
|
Length3 = 0;
|
||||||
|
|
||||||
|
if (TotalLength == 0) {
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ALIGN_VALUE (PhysicalAddress, SIZE_2MB) != PhysicalAddress) {
|
||||||
|
StartAddress1 = PhysicalAddress;
|
||||||
|
Length1 = ALIGN_VALUE (PhysicalAddress, SIZE_2MB) - PhysicalAddress;
|
||||||
|
if (Length1 >= TotalLength) {
|
||||||
|
Length1 = TotalLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
PhysicalAddress += Length1;
|
||||||
|
TotalLength -= Length1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TotalLength > SIZE_2MB) {
|
||||||
|
StartAddress2 = PhysicalAddress;
|
||||||
|
Length2 = TotalLength & ~(UINT64)ALIGNED_2MB_MASK;
|
||||||
|
PhysicalAddress += Length2;
|
||||||
|
TotalLength -= Length2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TotalLength) {
|
||||||
|
StartAddress3 = PhysicalAddress;
|
||||||
|
Length3 = TotalLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
Status = EFI_SUCCESS;
|
||||||
|
if (Length1 > 0) {
|
||||||
|
Pages = Length1 / SIZE_4KB;
|
||||||
|
Status = TdAcceptPages (StartAddress1, Pages, SIZE_4KB);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Length2 > 0) {
|
||||||
|
Pages = Length2 / AcceptPageSize;
|
||||||
|
Status = TdAcceptPages (StartAddress2, Pages, AcceptPageSize);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Length3 > 0) {
|
||||||
|
Pages = Length3 / SIZE_4KB;
|
||||||
|
Status = TdAcceptPages (StartAddress3, Pages, SIZE_4KB);
|
||||||
|
ASSERT (!EFI_ERROR (Status));
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is called by BSP and APs to accept memory.
|
||||||
|
* Note:
|
||||||
|
* The input PhysicalStart/PhysicalEnd indicates the whole memory region
|
||||||
|
* to be accepted. BSP or AP only accepts one piece in the whole memory region.
|
||||||
|
*
|
||||||
|
* @param CpuIndex vCPU index
|
||||||
|
* @param CpusNum Total vCPU number of a Tdx guest
|
||||||
|
* @param PhysicalStart Start address of a memory region which is to be accepted
|
||||||
|
* @param PhysicalEnd End address of a memory region which is to be accepted
|
||||||
|
*
|
||||||
|
* @retval EFI_SUCCESS Successfully accept the memory
|
||||||
|
* @retval Other Other errors as indicated
|
||||||
|
*/
|
||||||
|
STATIC
|
||||||
|
EFI_STATUS
|
||||||
|
EFIAPI
|
||||||
|
BspApAcceptMemoryResourceRange (
|
||||||
|
UINT32 CpuIndex,
|
||||||
|
UINT32 CpusNum,
|
||||||
|
EFI_PHYSICAL_ADDRESS PhysicalStart,
|
||||||
|
EFI_PHYSICAL_ADDRESS PhysicalEnd
|
||||||
|
)
|
||||||
|
{
|
||||||
|
UINT64 Status;
|
||||||
|
UINT64 Pages;
|
||||||
|
UINT64 Stride;
|
||||||
|
UINT64 AcceptPageSize;
|
||||||
|
EFI_PHYSICAL_ADDRESS PhysicalAddress;
|
||||||
|
|
||||||
|
AcceptPageSize = (UINT64)(UINTN)FixedPcdGet32 (PcdTdxAcceptPageSize);
|
||||||
|
|
||||||
|
Status = EFI_SUCCESS;
|
||||||
|
Stride = (UINTN)CpusNum * ACCEPT_CHUNK_SIZE;
|
||||||
|
PhysicalAddress = PhysicalStart + ACCEPT_CHUNK_SIZE * (UINTN)CpuIndex;
|
||||||
|
|
||||||
|
while (!EFI_ERROR (Status) && PhysicalAddress < PhysicalEnd) {
|
||||||
|
Pages = MIN (ACCEPT_CHUNK_SIZE, PhysicalEnd - PhysicalAddress) / AcceptPageSize;
|
||||||
|
Status = TdAcceptPages (PhysicalAddress, Pages, (UINT32)(UINTN)AcceptPageSize);
|
||||||
|
ASSERT (!EFI_ERROR (Status));
|
||||||
|
PhysicalAddress += Stride;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is called by APs to accept memory.
|
||||||
|
*
|
||||||
|
* @param CpuIndex vCPU index of an AP
|
||||||
|
* @param PhysicalStart Start address of a memory region which is to be accepted
|
||||||
|
* @param PhysicalEnd End address of a memory region which is to be accepted
|
||||||
|
*
|
||||||
|
* @retval EFI_SUCCESS Successfully accept the memory
|
||||||
|
* @retval Others Other errors as indicated
|
||||||
|
*/
|
||||||
|
STATIC
|
||||||
|
EFI_STATUS
|
||||||
|
EFIAPI
|
||||||
|
ApAcceptMemoryResourceRange (
|
||||||
|
UINT32 CpuIndex,
|
||||||
|
EFI_PHYSICAL_ADDRESS PhysicalStart,
|
||||||
|
EFI_PHYSICAL_ADDRESS PhysicalEnd
|
||||||
|
)
|
||||||
|
{
|
||||||
|
UINT64 Status;
|
||||||
|
TD_RETURN_DATA TdReturnData;
|
||||||
|
|
||||||
|
Status = TdCall (TDCALL_TDINFO, 0, 0, 0, &TdReturnData);
|
||||||
|
if (Status != TDX_EXIT_REASON_SUCCESS) {
|
||||||
|
ASSERT (FALSE);
|
||||||
|
return EFI_ABORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((CpuIndex == 0) || (CpuIndex >= TdReturnData.TdInfo.NumVcpus)) {
|
||||||
|
ASSERT (FALSE);
|
||||||
|
return EFI_ABORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return BspApAcceptMemoryResourceRange (CpuIndex, TdReturnData.TdInfo.NumVcpus, PhysicalStart, PhysicalEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is called by BSP. It coordinates BSP/APs to accept memory together.
|
||||||
|
*
|
||||||
|
* @param PhysicalStart Start address of a memory region which is to be accepted
|
||||||
|
* @param PhysicalEnd End address of a memory region which is to be accepted
|
||||||
|
* @param APsStackAddress APs stack address
|
||||||
|
* @param CpusNum Total vCPU number of the Tdx guest
|
||||||
|
*
|
||||||
|
* @retval EFI_SUCCESS Successfully accept the memory
|
||||||
|
* @retval Others Other errors as indicated
|
||||||
|
*/
|
||||||
|
STATIC
|
||||||
|
EFI_STATUS
|
||||||
|
EFIAPI
|
||||||
|
MpAcceptMemoryResourceRange (
|
||||||
|
IN EFI_PHYSICAL_ADDRESS PhysicalStart,
|
||||||
|
IN EFI_PHYSICAL_ADDRESS PhysicalEnd,
|
||||||
|
IN OUT EFI_PHYSICAL_ADDRESS APsStackAddress,
|
||||||
|
IN UINT32 CpusNum
|
||||||
|
)
|
||||||
|
{
|
||||||
|
UINT64 Length;
|
||||||
|
EFI_STATUS Status;
|
||||||
|
|
||||||
|
Length = PhysicalEnd - PhysicalStart;
|
||||||
|
|
||||||
|
DEBUG ((DEBUG_INFO, "MpAccept : 0x%llx - 0x%llx (0x%llx)\n", PhysicalStart, PhysicalEnd, Length));
|
||||||
|
|
||||||
|
if (Length == 0) {
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// The start address is not 2M aligned. BSP first accept the part which is not 2M aligned.
|
||||||
|
//
|
||||||
|
if (ALIGN_VALUE (PhysicalStart, SIZE_2MB) != PhysicalStart) {
|
||||||
|
Length = MIN (ALIGN_VALUE (PhysicalStart, SIZE_2MB) - PhysicalStart, Length);
|
||||||
|
Status = BspAcceptMemoryResourceRange (PhysicalStart, PhysicalStart + Length);
|
||||||
|
ASSERT (Status == EFI_SUCCESS);
|
||||||
|
|
||||||
|
PhysicalStart += Length;
|
||||||
|
Length = PhysicalEnd - PhysicalStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Length == 0) {
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// BSP will accept the memory by itself if the memory is not big enough compared with a chunk.
|
||||||
|
//
|
||||||
|
if (Length <= ACCEPT_CHUNK_SIZE) {
|
||||||
|
return BspAcceptMemoryResourceRange (PhysicalStart, PhysicalEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Now APs are asked to accept the memory together.
|
||||||
|
//
|
||||||
|
MpSerializeStart ();
|
||||||
|
|
||||||
|
MpSendWakeupCommand (
|
||||||
|
MpProtectedModeWakeupCommandAcceptPages,
|
||||||
|
(UINT64)(UINTN)ApAcceptMemoryResourceRange,
|
||||||
|
PhysicalStart,
|
||||||
|
PhysicalEnd,
|
||||||
|
APsStackAddress,
|
||||||
|
AP_STACK_SIZE
|
||||||
|
);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Now BSP does its job.
|
||||||
|
//
|
||||||
|
BspApAcceptMemoryResourceRange (0, CpusNum, PhysicalStart, PhysicalEnd);
|
||||||
|
|
||||||
|
MpSerializeEnd ();
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
BSP accept a small piece of memory which will be used as APs stack.
|
||||||
|
|
||||||
|
@param[in] VmmHobList The Hoblist pass the firmware
|
||||||
|
@param[in] APsStackSize APs stack size
|
||||||
|
@param[out] PhysicalAddressEnd The physical end address of accepted memory in phase-1
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Process the HobList successfully
|
||||||
|
@retval Others Other errors as indicated
|
||||||
|
**/
|
||||||
|
STATIC
|
||||||
|
EFI_STATUS
|
||||||
|
EFIAPI
|
||||||
|
AcceptMemoryForAPsStack (
|
||||||
|
IN CONST VOID *VmmHobList,
|
||||||
|
IN UINT32 APsStackSize,
|
||||||
|
OUT EFI_PHYSICAL_ADDRESS *PhysicalAddressEnd
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EFI_STATUS Status;
|
||||||
|
EFI_PEI_HOB_POINTERS Hob;
|
||||||
|
EFI_PHYSICAL_ADDRESS PhysicalEnd;
|
||||||
|
EFI_PHYSICAL_ADDRESS PhysicalStart;
|
||||||
|
UINT64 ResourceLength;
|
||||||
|
BOOLEAN MemoryRegionFound;
|
||||||
|
|
||||||
|
ASSERT (VmmHobList != NULL);
|
||||||
|
|
||||||
|
Status = EFI_SUCCESS;
|
||||||
|
Hob.Raw = (UINT8 *)VmmHobList;
|
||||||
|
MemoryRegionFound = FALSE;
|
||||||
|
|
||||||
|
DEBUG ((DEBUG_INFO, "AcceptMemoryForAPsStack with APsStackSize=0x%x\n", APsStackSize));
|
||||||
|
|
||||||
|
//
|
||||||
|
// Parse the HOB list until end of list or matching type is found.
|
||||||
|
//
|
||||||
|
while (!END_OF_HOB_LIST (Hob) && !MemoryRegionFound) {
|
||||||
|
if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
|
||||||
|
DEBUG ((DEBUG_INFO, "\nResourceType: 0x%x\n", Hob.ResourceDescriptor->ResourceType));
|
||||||
|
|
||||||
|
if (Hob.ResourceDescriptor->ResourceType == BZ3937_EFI_RESOURCE_MEMORY_UNACCEPTED) {
|
||||||
|
ResourceLength = Hob.ResourceDescriptor->ResourceLength;
|
||||||
|
PhysicalStart = Hob.ResourceDescriptor->PhysicalStart;
|
||||||
|
PhysicalEnd = PhysicalStart + ResourceLength;
|
||||||
|
|
||||||
|
DEBUG ((DEBUG_INFO, "ResourceAttribute: 0x%x\n", Hob.ResourceDescriptor->ResourceAttribute));
|
||||||
|
DEBUG ((DEBUG_INFO, "PhysicalStart: 0x%llx\n", PhysicalStart));
|
||||||
|
DEBUG ((DEBUG_INFO, "ResourceLength: 0x%llx\n", ResourceLength));
|
||||||
|
DEBUG ((DEBUG_INFO, "Owner: %g\n\n", &Hob.ResourceDescriptor->Owner));
|
||||||
|
|
||||||
|
if (ResourceLength >= APsStackSize) {
|
||||||
|
MemoryRegionFound = TRUE;
|
||||||
|
if (ResourceLength > ACCEPT_CHUNK_SIZE) {
|
||||||
|
PhysicalEnd = Hob.ResourceDescriptor->PhysicalStart + APsStackSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Status = BspAcceptMemoryResourceRange (
|
||||||
|
Hob.ResourceDescriptor->PhysicalStart,
|
||||||
|
PhysicalEnd
|
||||||
|
);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Hob.Raw = GET_NEXT_HOB (Hob);
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT (MemoryRegionFound);
|
||||||
|
*PhysicalAddressEnd = PhysicalEnd;
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
BSP and APs work togeter to accept memory which is under the address of 4G.
|
||||||
|
|
||||||
|
@param[in] VmmHobList The Hoblist pass the firmware
|
||||||
|
@param[in] CpusNum Number of vCPUs
|
||||||
|
@param[in] APsStackStartAddres Start address of APs stack
|
||||||
|
@param[in] PhysicalAddressStart Start physical address which to be accepted
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Process the HobList successfully
|
||||||
|
@retval Others Other errors as indicated
|
||||||
|
**/
|
||||||
|
STATIC
|
||||||
|
EFI_STATUS
|
||||||
|
EFIAPI
|
||||||
|
AcceptMemory (
|
||||||
|
IN CONST VOID *VmmHobList,
|
||||||
|
IN UINT32 CpusNum,
|
||||||
|
IN EFI_PHYSICAL_ADDRESS APsStackStartAddress,
|
||||||
|
IN EFI_PHYSICAL_ADDRESS PhysicalAddressStart
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EFI_STATUS Status;
|
||||||
|
EFI_PEI_HOB_POINTERS Hob;
|
||||||
|
EFI_PHYSICAL_ADDRESS PhysicalStart;
|
||||||
|
EFI_PHYSICAL_ADDRESS PhysicalEnd;
|
||||||
|
EFI_PHYSICAL_ADDRESS AcceptMemoryEndAddress;
|
||||||
|
|
||||||
|
Status = EFI_SUCCESS;
|
||||||
|
AcceptMemoryEndAddress = BASE_4GB;
|
||||||
|
|
||||||
|
ASSERT (VmmHobList != NULL);
|
||||||
|
Hob.Raw = (UINT8 *)VmmHobList;
|
||||||
|
|
||||||
|
DEBUG ((DEBUG_INFO, "AcceptMemory under address of 4G\n"));
|
||||||
|
|
||||||
|
//
|
||||||
|
// Parse the HOB list until end of list or matching type is found.
|
||||||
|
//
|
||||||
|
while (!END_OF_HOB_LIST (Hob)) {
|
||||||
|
if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
|
||||||
|
if (Hob.ResourceDescriptor->ResourceType == BZ3937_EFI_RESOURCE_MEMORY_UNACCEPTED) {
|
||||||
|
PhysicalStart = Hob.ResourceDescriptor->PhysicalStart;
|
||||||
|
PhysicalEnd = PhysicalStart + Hob.ResourceDescriptor->ResourceLength;
|
||||||
|
|
||||||
|
if (PhysicalEnd <= PhysicalAddressStart) {
|
||||||
|
// this memory region has been accepted. Skipped it.
|
||||||
|
Hob.Raw = GET_NEXT_HOB (Hob);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PhysicalStart >= AcceptMemoryEndAddress) {
|
||||||
|
// this memory region is not to be accepted. And we're done.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PhysicalStart >= PhysicalAddressStart) {
|
||||||
|
// this memory region has not been acceted.
|
||||||
|
} else if ((PhysicalStart < PhysicalAddressStart) && (PhysicalEnd > PhysicalAddressStart)) {
|
||||||
|
// part of the memory region has been accepted.
|
||||||
|
PhysicalStart = PhysicalAddressStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
// then compare the PhysicalEnd with AcceptMemoryEndAddress
|
||||||
|
if (PhysicalEnd >= AcceptMemoryEndAddress) {
|
||||||
|
PhysicalEnd = AcceptMemoryEndAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG ((DEBUG_INFO, "ResourceAttribute: 0x%x\n", Hob.ResourceDescriptor->ResourceAttribute));
|
||||||
|
DEBUG ((DEBUG_INFO, "PhysicalStart: 0x%llx\n", Hob.ResourceDescriptor->PhysicalStart));
|
||||||
|
DEBUG ((DEBUG_INFO, "ResourceLength: 0x%llx\n", Hob.ResourceDescriptor->ResourceLength));
|
||||||
|
DEBUG ((DEBUG_INFO, "Owner: %g\n\n", &Hob.ResourceDescriptor->Owner));
|
||||||
|
|
||||||
|
// Now we're ready to accept memory [PhysicalStart, PhysicalEnd)
|
||||||
|
if (CpusNum == 1) {
|
||||||
|
Status = BspAcceptMemoryResourceRange (PhysicalStart, PhysicalEnd);
|
||||||
|
} else {
|
||||||
|
Status = MpAcceptMemoryResourceRange (
|
||||||
|
PhysicalStart,
|
||||||
|
PhysicalEnd,
|
||||||
|
APsStackStartAddress,
|
||||||
|
CpusNum
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
ASSERT (FALSE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PhysicalEnd == AcceptMemoryEndAddress) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Hob.Raw = GET_NEXT_HOB (Hob);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Check the value whether in the valid list.
|
||||||
|
|
||||||
|
@param[in] Value A value
|
||||||
|
@param[in] ValidList A pointer to valid list
|
||||||
|
@param[in] ValidListLength Length of valid list
|
||||||
|
|
||||||
|
@retval TRUE The value is in valid list.
|
||||||
|
@retval FALSE The value is not in valid list.
|
||||||
|
|
||||||
|
**/
|
||||||
|
STATIC
|
||||||
|
BOOLEAN
|
||||||
|
EFIAPI
|
||||||
|
IsInValidList (
|
||||||
|
IN UINT32 Value,
|
||||||
|
IN UINT32 *ValidList,
|
||||||
|
IN UINT32 ValidListLength
|
||||||
|
)
|
||||||
|
{
|
||||||
|
UINT32 index;
|
||||||
|
|
||||||
|
if (ValidList == NULL) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (index = 0; index < ValidListLength; index++) {
|
||||||
|
if (ValidList[index] == Value) {
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Check the integrity of VMM Hob List.
|
||||||
|
|
||||||
|
@param[in] VmmHobList A pointer to Hob List
|
||||||
|
|
||||||
|
@retval TRUE The Hob List is valid.
|
||||||
|
@retval FALSE The Hob List is invalid.
|
||||||
|
|
||||||
|
**/
|
||||||
|
STATIC
|
||||||
|
BOOLEAN
|
||||||
|
EFIAPI
|
||||||
|
ValidateHobList (
|
||||||
|
IN CONST VOID *VmmHobList
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EFI_PEI_HOB_POINTERS Hob;
|
||||||
|
UINT32 EFI_BOOT_MODE_LIST[] = {
|
||||||
|
BOOT_WITH_FULL_CONFIGURATION,
|
||||||
|
BOOT_WITH_MINIMAL_CONFIGURATION,
|
||||||
|
BOOT_ASSUMING_NO_CONFIGURATION_CHANGES,
|
||||||
|
BOOT_WITH_FULL_CONFIGURATION_PLUS_DIAGNOSTICS,
|
||||||
|
BOOT_WITH_DEFAULT_SETTINGS,
|
||||||
|
BOOT_ON_S4_RESUME,
|
||||||
|
BOOT_ON_S5_RESUME,
|
||||||
|
BOOT_WITH_MFG_MODE_SETTINGS,
|
||||||
|
BOOT_ON_S2_RESUME,
|
||||||
|
BOOT_ON_S3_RESUME,
|
||||||
|
BOOT_ON_FLASH_UPDATE,
|
||||||
|
BOOT_IN_RECOVERY_MODE
|
||||||
|
};
|
||||||
|
|
||||||
|
UINT32 EFI_RESOURCE_TYPE_LIST[] = {
|
||||||
|
EFI_RESOURCE_SYSTEM_MEMORY,
|
||||||
|
EFI_RESOURCE_MEMORY_MAPPED_IO,
|
||||||
|
EFI_RESOURCE_IO,
|
||||||
|
EFI_RESOURCE_FIRMWARE_DEVICE,
|
||||||
|
EFI_RESOURCE_MEMORY_MAPPED_IO_PORT,
|
||||||
|
EFI_RESOURCE_MEMORY_RESERVED,
|
||||||
|
EFI_RESOURCE_IO_RESERVED,
|
||||||
|
BZ3937_EFI_RESOURCE_MEMORY_UNACCEPTED
|
||||||
|
};
|
||||||
|
|
||||||
|
if (VmmHobList == NULL) {
|
||||||
|
DEBUG ((DEBUG_ERROR, "HOB: HOB data pointer is NULL\n"));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
Hob.Raw = (UINT8 *)VmmHobList;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Parse the HOB list until end of list or matching type is found.
|
||||||
|
//
|
||||||
|
while (!END_OF_HOB_LIST (Hob)) {
|
||||||
|
if (Hob.Header->Reserved != (UINT32)0) {
|
||||||
|
DEBUG ((DEBUG_ERROR, "HOB: Hob header Reserved filed should be zero\n"));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Hob.Header->HobLength == 0) {
|
||||||
|
DEBUG ((DEBUG_ERROR, "HOB: Hob header LEANGTH should not be zero\n"));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (Hob.Header->HobType) {
|
||||||
|
case EFI_HOB_TYPE_HANDOFF:
|
||||||
|
if (Hob.Header->HobLength != sizeof (EFI_HOB_HANDOFF_INFO_TABLE)) {
|
||||||
|
DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_HANDOFF));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsInValidList (Hob.HandoffInformationTable->BootMode, EFI_BOOT_MODE_LIST, ARRAY_SIZE (EFI_BOOT_MODE_LIST)) == FALSE) {
|
||||||
|
DEBUG ((DEBUG_ERROR, "HOB: Unknow HandoffInformationTable BootMode type. Type: 0x%08x\n", Hob.HandoffInformationTable->BootMode));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((Hob.HandoffInformationTable->EfiFreeMemoryTop % 4096) != 0) {
|
||||||
|
DEBUG ((DEBUG_ERROR, "HOB: HandoffInformationTable EfiFreeMemoryTop address must be 4-KB aligned to meet page restrictions of UEFI.\
|
||||||
|
Address: 0x%016lx\n", Hob.HandoffInformationTable->EfiFreeMemoryTop));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EFI_HOB_TYPE_RESOURCE_DESCRIPTOR:
|
||||||
|
if (Hob.Header->HobLength != sizeof (EFI_HOB_RESOURCE_DESCRIPTOR)) {
|
||||||
|
DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_RESOURCE_DESCRIPTOR));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsInValidList (Hob.ResourceDescriptor->ResourceType, EFI_RESOURCE_TYPE_LIST, ARRAY_SIZE (EFI_RESOURCE_TYPE_LIST)) == FALSE) {
|
||||||
|
DEBUG ((DEBUG_ERROR, "HOB: Unknow ResourceDescriptor ResourceType type. Type: 0x%08x\n", Hob.ResourceDescriptor->ResourceType));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((Hob.ResourceDescriptor->ResourceAttribute & (~(EFI_RESOURCE_ATTRIBUTE_PRESENT |
|
||||||
|
EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
|
||||||
|
EFI_RESOURCE_ATTRIBUTE_TESTED |
|
||||||
|
EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED |
|
||||||
|
EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED |
|
||||||
|
EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED |
|
||||||
|
EFI_RESOURCE_ATTRIBUTE_PERSISTENT |
|
||||||
|
EFI_RESOURCE_ATTRIBUTE_SINGLE_BIT_ECC |
|
||||||
|
EFI_RESOURCE_ATTRIBUTE_MULTIPLE_BIT_ECC |
|
||||||
|
EFI_RESOURCE_ATTRIBUTE_ECC_RESERVED_1 |
|
||||||
|
EFI_RESOURCE_ATTRIBUTE_ECC_RESERVED_2 |
|
||||||
|
EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
|
||||||
|
EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
|
||||||
|
EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
|
||||||
|
EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE |
|
||||||
|
EFI_RESOURCE_ATTRIBUTE_16_BIT_IO |
|
||||||
|
EFI_RESOURCE_ATTRIBUTE_32_BIT_IO |
|
||||||
|
EFI_RESOURCE_ATTRIBUTE_64_BIT_IO |
|
||||||
|
EFI_RESOURCE_ATTRIBUTE_UNCACHED_EXPORTED |
|
||||||
|
EFI_RESOURCE_ATTRIBUTE_READ_PROTECTABLE |
|
||||||
|
EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTABLE |
|
||||||
|
EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTABLE |
|
||||||
|
EFI_RESOURCE_ATTRIBUTE_PERSISTABLE |
|
||||||
|
EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTED |
|
||||||
|
EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTABLE |
|
||||||
|
EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE))) != 0)
|
||||||
|
{
|
||||||
|
DEBUG ((DEBUG_ERROR, "HOB: Unknow ResourceDescriptor ResourceAttribute type. Type: 0x%08x\n", Hob.ResourceDescriptor->ResourceAttribute));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
// EFI_HOB_GUID_TYPE is variable length data, so skip check
|
||||||
|
case EFI_HOB_TYPE_GUID_EXTENSION:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EFI_HOB_TYPE_FV:
|
||||||
|
if (Hob.Header->HobLength != sizeof (EFI_HOB_FIRMWARE_VOLUME)) {
|
||||||
|
DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_FV));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EFI_HOB_TYPE_FV2:
|
||||||
|
if (Hob.Header->HobLength != sizeof (EFI_HOB_FIRMWARE_VOLUME2)) {
|
||||||
|
DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_FV2));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EFI_HOB_TYPE_FV3:
|
||||||
|
if (Hob.Header->HobLength != sizeof (EFI_HOB_FIRMWARE_VOLUME3)) {
|
||||||
|
DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_FV3));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EFI_HOB_TYPE_CPU:
|
||||||
|
if (Hob.Header->HobLength != sizeof (EFI_HOB_CPU)) {
|
||||||
|
DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_CPU));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (UINT32 index = 0; index < 6; index++) {
|
||||||
|
if (Hob.Cpu->Reserved[index] != 0) {
|
||||||
|
DEBUG ((DEBUG_ERROR, "HOB: Cpu Reserved field will always be set to zero.\n"));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
DEBUG ((DEBUG_ERROR, "HOB: Hob type is not know. Type: 0x%04x\n", Hob.Header->HobType));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get next HOB
|
||||||
|
Hob.Raw = (UINT8 *)(Hob.Raw + Hob.Header->HobLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Processing the incoming HobList for the TDX
|
||||||
|
|
||||||
|
Firmware must parse list, and accept the pages of memory before their can be
|
||||||
|
use by the guest.
|
||||||
|
|
||||||
|
@param[in] VmmHobList The Hoblist pass the firmware
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Process the HobList successfully
|
||||||
|
@retval Others Other errors as indicated
|
||||||
|
|
||||||
|
**/
|
||||||
|
STATIC
|
||||||
|
EFI_STATUS
|
||||||
|
EFIAPI
|
||||||
|
ProcessHobList (
|
||||||
|
IN CONST VOID *VmmHobList
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EFI_STATUS Status;
|
||||||
|
UINT32 CpusNum;
|
||||||
|
EFI_PHYSICAL_ADDRESS PhysicalEnd;
|
||||||
|
EFI_PHYSICAL_ADDRESS APsStackStartAddress;
|
||||||
|
|
||||||
|
CpusNum = GetCpusNum ();
|
||||||
|
|
||||||
|
//
|
||||||
|
// If there are mutli-vCPU in a TDX guest, accept memory is split into 2 phases.
|
||||||
|
// Phase-1 accepts a small piece of memory by BSP. This piece of memory
|
||||||
|
// is used to setup AP's stack.
|
||||||
|
// After that phase-2 accepts a big piece of memory by BSP/APs.
|
||||||
|
//
|
||||||
|
// TDVF supports 4K and 2M accept-page-size. The memory which can be accpeted
|
||||||
|
// in 2M accept-page-size must be 2M aligned and multiple 2M. So we align
|
||||||
|
// APsStackSize to 2M size aligned.
|
||||||
|
//
|
||||||
|
if (CpusNum > 1) {
|
||||||
|
Status = AcceptMemoryForAPsStack (VmmHobList, APS_STACK_SIZE (CpusNum), &PhysicalEnd);
|
||||||
|
ASSERT (Status == EFI_SUCCESS);
|
||||||
|
APsStackStartAddress = PhysicalEnd - APS_STACK_SIZE (CpusNum);
|
||||||
|
} else {
|
||||||
|
PhysicalEnd = 0;
|
||||||
|
APsStackStartAddress = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Status = AcceptMemory (VmmHobList, CpusNum, APsStackStartAddress, PhysicalEnd);
|
||||||
|
ASSERT (Status == EFI_SUCCESS);
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
In Tdx guest, some information need to be passed from host VMM to guest
|
In Tdx guest, some information need to be passed from host VMM to guest
|
||||||
firmware. For example, the memory resource, etc. These information are
|
firmware. For example, the memory resource, etc. These information are
|
||||||
@ -49,7 +772,36 @@ TdxHelperProcessTdHob (
|
|||||||
VOID
|
VOID
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return EFI_UNSUPPORTED;
|
EFI_STATUS Status;
|
||||||
|
VOID *TdHob;
|
||||||
|
TD_RETURN_DATA TdReturnData;
|
||||||
|
|
||||||
|
TdHob = (VOID *)(UINTN)FixedPcdGet32 (PcdOvmfSecGhcbBase);
|
||||||
|
Status = TdCall (TDCALL_TDINFO, 0, 0, 0, &TdReturnData);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG ((
|
||||||
|
DEBUG_INFO,
|
||||||
|
"Intel Tdx Started with (GPAW: %d, Cpus: %d)\n",
|
||||||
|
TdReturnData.TdInfo.Gpaw,
|
||||||
|
TdReturnData.TdInfo.NumVcpus
|
||||||
|
));
|
||||||
|
|
||||||
|
//
|
||||||
|
// Validate HobList
|
||||||
|
//
|
||||||
|
if (ValidateHobList (TdHob) == FALSE) {
|
||||||
|
return EFI_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Process Hoblist to accept memory
|
||||||
|
//
|
||||||
|
Status = ProcessHobList (TdHob);
|
||||||
|
|
||||||
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -16,779 +16,11 @@
|
|||||||
#include <Library/MemoryAllocationLib.h>
|
#include <Library/MemoryAllocationLib.h>
|
||||||
#include <IndustryStandard/Tdx.h>
|
#include <IndustryStandard/Tdx.h>
|
||||||
#include <IndustryStandard/IntelTdx.h>
|
#include <IndustryStandard/IntelTdx.h>
|
||||||
#include <IndustryStandard/QemuFwCfg.h>
|
|
||||||
#include <Library/QemuFwCfgLib.h>
|
|
||||||
#include <Library/PeiServicesLib.h>
|
#include <Library/PeiServicesLib.h>
|
||||||
#include <Library/TdxLib.h>
|
|
||||||
#include <Library/TdxMailboxLib.h>
|
|
||||||
#include <Library/SynchronizationLib.h>
|
|
||||||
#include <Pi/PrePiHob.h>
|
#include <Pi/PrePiHob.h>
|
||||||
#include <WorkArea.h>
|
#include <WorkArea.h>
|
||||||
#include <ConfidentialComputingGuestAttr.h>
|
#include <ConfidentialComputingGuestAttr.h>
|
||||||
|
|
||||||
#define ALIGNED_2MB_MASK 0x1fffff
|
|
||||||
#define MEGABYTE_SHIFT 20
|
|
||||||
|
|
||||||
#define ACCEPT_CHUNK_SIZE SIZE_32MB
|
|
||||||
#define AP_STACK_SIZE SIZE_16KB
|
|
||||||
#define APS_STACK_SIZE(CpusNum) (ALIGN_VALUE(CpusNum*AP_STACK_SIZE, SIZE_2MB))
|
|
||||||
|
|
||||||
/**
|
|
||||||
This function will be called to accept pages. Only BSP accepts pages.
|
|
||||||
|
|
||||||
TDCALL(ACCEPT_PAGE) supports the accept page size of 4k and 2M. To
|
|
||||||
simplify the implementation, the Memory to be accpeted is splitted
|
|
||||||
into 3 parts:
|
|
||||||
----------------- <-- StartAddress1 (not 2M aligned)
|
|
||||||
| part 1 | Length1 < 2M
|
|
||||||
|---------------| <-- StartAddress2 (2M aligned)
|
|
||||||
| | Length2 = Integer multiples of 2M
|
|
||||||
| part 2 |
|
|
||||||
| |
|
|
||||||
|---------------| <-- StartAddress3
|
|
||||||
| part 3 | Length3 < 2M
|
|
||||||
|---------------|
|
|
||||||
|
|
||||||
@param[in] PhysicalAddress Start physical adress
|
|
||||||
@param[in] PhysicalEnd End physical address
|
|
||||||
|
|
||||||
@retval EFI_SUCCESS Accept memory successfully
|
|
||||||
@retval Others Other errors as indicated
|
|
||||||
**/
|
|
||||||
EFI_STATUS
|
|
||||||
EFIAPI
|
|
||||||
BspAcceptMemoryResourceRange (
|
|
||||||
IN EFI_PHYSICAL_ADDRESS PhysicalAddress,
|
|
||||||
IN EFI_PHYSICAL_ADDRESS PhysicalEnd
|
|
||||||
)
|
|
||||||
{
|
|
||||||
EFI_STATUS Status;
|
|
||||||
UINT32 AcceptPageSize;
|
|
||||||
UINT64 StartAddress1;
|
|
||||||
UINT64 StartAddress2;
|
|
||||||
UINT64 StartAddress3;
|
|
||||||
UINT64 TotalLength;
|
|
||||||
UINT64 Length1;
|
|
||||||
UINT64 Length2;
|
|
||||||
UINT64 Length3;
|
|
||||||
UINT64 Pages;
|
|
||||||
|
|
||||||
AcceptPageSize = FixedPcdGet32 (PcdTdxAcceptPageSize);
|
|
||||||
TotalLength = PhysicalEnd - PhysicalAddress;
|
|
||||||
StartAddress1 = 0;
|
|
||||||
StartAddress2 = 0;
|
|
||||||
StartAddress3 = 0;
|
|
||||||
Length1 = 0;
|
|
||||||
Length2 = 0;
|
|
||||||
Length3 = 0;
|
|
||||||
|
|
||||||
if (TotalLength == 0) {
|
|
||||||
return EFI_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ALIGN_VALUE (PhysicalAddress, SIZE_2MB) != PhysicalAddress) {
|
|
||||||
StartAddress1 = PhysicalAddress;
|
|
||||||
Length1 = ALIGN_VALUE (PhysicalAddress, SIZE_2MB) - PhysicalAddress;
|
|
||||||
if (Length1 >= TotalLength) {
|
|
||||||
Length1 = TotalLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
PhysicalAddress += Length1;
|
|
||||||
TotalLength -= Length1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TotalLength > SIZE_2MB) {
|
|
||||||
StartAddress2 = PhysicalAddress;
|
|
||||||
Length2 = TotalLength & ~(UINT64)ALIGNED_2MB_MASK;
|
|
||||||
PhysicalAddress += Length2;
|
|
||||||
TotalLength -= Length2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TotalLength) {
|
|
||||||
StartAddress3 = PhysicalAddress;
|
|
||||||
Length3 = TotalLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
Status = EFI_SUCCESS;
|
|
||||||
if (Length1 > 0) {
|
|
||||||
Pages = Length1 / SIZE_4KB;
|
|
||||||
Status = TdAcceptPages (StartAddress1, Pages, SIZE_4KB);
|
|
||||||
if (EFI_ERROR (Status)) {
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Length2 > 0) {
|
|
||||||
Pages = Length2 / AcceptPageSize;
|
|
||||||
Status = TdAcceptPages (StartAddress2, Pages, AcceptPageSize);
|
|
||||||
if (EFI_ERROR (Status)) {
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Length3 > 0) {
|
|
||||||
Pages = Length3 / SIZE_4KB;
|
|
||||||
Status = TdAcceptPages (StartAddress3, Pages, SIZE_4KB);
|
|
||||||
ASSERT (!EFI_ERROR (Status));
|
|
||||||
if (EFI_ERROR (Status)) {
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This function is called by BSP and APs to accept memory.
|
|
||||||
* Note:
|
|
||||||
* The input PhysicalStart/PhysicalEnd indicates the whole memory region
|
|
||||||
* to be accepted. BSP or AP only accepts one piece in the whole memory region.
|
|
||||||
*
|
|
||||||
* @param CpuIndex vCPU index
|
|
||||||
* @param CpusNum Total vCPU number of a Tdx guest
|
|
||||||
* @param PhysicalStart Start address of a memory region which is to be accepted
|
|
||||||
* @param PhysicalEnd End address of a memory region which is to be accepted
|
|
||||||
*
|
|
||||||
* @retval EFI_SUCCESS Successfully accept the memory
|
|
||||||
* @retval Other Other errors as indicated
|
|
||||||
*/
|
|
||||||
STATIC
|
|
||||||
EFI_STATUS
|
|
||||||
EFIAPI
|
|
||||||
BspApAcceptMemoryResourceRange (
|
|
||||||
UINT32 CpuIndex,
|
|
||||||
UINT32 CpusNum,
|
|
||||||
EFI_PHYSICAL_ADDRESS PhysicalStart,
|
|
||||||
EFI_PHYSICAL_ADDRESS PhysicalEnd
|
|
||||||
)
|
|
||||||
{
|
|
||||||
UINT64 Status;
|
|
||||||
UINT64 Pages;
|
|
||||||
UINT64 Stride;
|
|
||||||
UINT64 AcceptPageSize;
|
|
||||||
EFI_PHYSICAL_ADDRESS PhysicalAddress;
|
|
||||||
|
|
||||||
AcceptPageSize = (UINT64)(UINTN)FixedPcdGet32 (PcdTdxAcceptPageSize);
|
|
||||||
|
|
||||||
Status = EFI_SUCCESS;
|
|
||||||
Stride = (UINTN)CpusNum * ACCEPT_CHUNK_SIZE;
|
|
||||||
PhysicalAddress = PhysicalStart + ACCEPT_CHUNK_SIZE * (UINTN)CpuIndex;
|
|
||||||
|
|
||||||
while (!EFI_ERROR (Status) && PhysicalAddress < PhysicalEnd) {
|
|
||||||
Pages = MIN (ACCEPT_CHUNK_SIZE, PhysicalEnd - PhysicalAddress) / AcceptPageSize;
|
|
||||||
Status = TdAcceptPages (PhysicalAddress, Pages, (UINT32)(UINTN)AcceptPageSize);
|
|
||||||
ASSERT (!EFI_ERROR (Status));
|
|
||||||
PhysicalAddress += Stride;
|
|
||||||
}
|
|
||||||
|
|
||||||
return EFI_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This function is called by APs to accept memory.
|
|
||||||
*
|
|
||||||
* @param CpuIndex vCPU index of an AP
|
|
||||||
* @param PhysicalStart Start address of a memory region which is to be accepted
|
|
||||||
* @param PhysicalEnd End address of a memory region which is to be accepted
|
|
||||||
*
|
|
||||||
* @retval EFI_SUCCESS Successfully accept the memory
|
|
||||||
* @retval Others Other errors as indicated
|
|
||||||
*/
|
|
||||||
STATIC
|
|
||||||
EFI_STATUS
|
|
||||||
EFIAPI
|
|
||||||
ApAcceptMemoryResourceRange (
|
|
||||||
UINT32 CpuIndex,
|
|
||||||
EFI_PHYSICAL_ADDRESS PhysicalStart,
|
|
||||||
EFI_PHYSICAL_ADDRESS PhysicalEnd
|
|
||||||
)
|
|
||||||
{
|
|
||||||
UINT64 Status;
|
|
||||||
TD_RETURN_DATA TdReturnData;
|
|
||||||
|
|
||||||
Status = TdCall (TDCALL_TDINFO, 0, 0, 0, &TdReturnData);
|
|
||||||
if (Status != TDX_EXIT_REASON_SUCCESS) {
|
|
||||||
ASSERT (FALSE);
|
|
||||||
return EFI_ABORTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((CpuIndex == 0) || (CpuIndex >= TdReturnData.TdInfo.NumVcpus)) {
|
|
||||||
ASSERT (FALSE);
|
|
||||||
return EFI_ABORTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
return BspApAcceptMemoryResourceRange (CpuIndex, TdReturnData.TdInfo.NumVcpus, PhysicalStart, PhysicalEnd);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This function is called by BSP. It coordinates BSP/APs to accept memory together.
|
|
||||||
*
|
|
||||||
* @param PhysicalStart Start address of a memory region which is to be accepted
|
|
||||||
* @param PhysicalEnd End address of a memory region which is to be accepted
|
|
||||||
* @param APsStackAddress APs stack address
|
|
||||||
* @param CpusNum Total vCPU number of the Tdx guest
|
|
||||||
*
|
|
||||||
* @retval EFI_SUCCESS Successfully accept the memory
|
|
||||||
* @retval Others Other errors as indicated
|
|
||||||
*/
|
|
||||||
EFI_STATUS
|
|
||||||
EFIAPI
|
|
||||||
MpAcceptMemoryResourceRange (
|
|
||||||
IN EFI_PHYSICAL_ADDRESS PhysicalStart,
|
|
||||||
IN EFI_PHYSICAL_ADDRESS PhysicalEnd,
|
|
||||||
IN OUT EFI_PHYSICAL_ADDRESS APsStackAddress,
|
|
||||||
IN UINT32 CpusNum
|
|
||||||
)
|
|
||||||
{
|
|
||||||
UINT64 Length;
|
|
||||||
EFI_STATUS Status;
|
|
||||||
|
|
||||||
Length = PhysicalEnd - PhysicalStart;
|
|
||||||
|
|
||||||
DEBUG ((DEBUG_INFO, "MpAccept : 0x%llx - 0x%llx (0x%llx)\n", PhysicalStart, PhysicalEnd, Length));
|
|
||||||
|
|
||||||
if (Length == 0) {
|
|
||||||
return EFI_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// The start address is not 2M aligned. BSP first accept the part which is not 2M aligned.
|
|
||||||
//
|
|
||||||
if (ALIGN_VALUE (PhysicalStart, SIZE_2MB) != PhysicalStart) {
|
|
||||||
Length = MIN (ALIGN_VALUE (PhysicalStart, SIZE_2MB) - PhysicalStart, Length);
|
|
||||||
Status = BspAcceptMemoryResourceRange (PhysicalStart, PhysicalStart + Length);
|
|
||||||
ASSERT (Status == EFI_SUCCESS);
|
|
||||||
|
|
||||||
PhysicalStart += Length;
|
|
||||||
Length = PhysicalEnd - PhysicalStart;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Length == 0) {
|
|
||||||
return EFI_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// BSP will accept the memory by itself if the memory is not big enough compared with a chunk.
|
|
||||||
//
|
|
||||||
if (Length <= ACCEPT_CHUNK_SIZE) {
|
|
||||||
return BspAcceptMemoryResourceRange (PhysicalStart, PhysicalEnd);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Now APs are asked to accept the memory together.
|
|
||||||
//
|
|
||||||
MpSerializeStart ();
|
|
||||||
|
|
||||||
MpSendWakeupCommand (
|
|
||||||
MpProtectedModeWakeupCommandAcceptPages,
|
|
||||||
(UINT64)(UINTN)ApAcceptMemoryResourceRange,
|
|
||||||
PhysicalStart,
|
|
||||||
PhysicalEnd,
|
|
||||||
APsStackAddress,
|
|
||||||
AP_STACK_SIZE
|
|
||||||
);
|
|
||||||
|
|
||||||
//
|
|
||||||
// Now BSP does its job.
|
|
||||||
//
|
|
||||||
BspApAcceptMemoryResourceRange (0, CpusNum, PhysicalStart, PhysicalEnd);
|
|
||||||
|
|
||||||
MpSerializeEnd ();
|
|
||||||
|
|
||||||
return EFI_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
BSP accept a small piece of memory which will be used as APs stack.
|
|
||||||
|
|
||||||
@param[in] VmmHobList The Hoblist pass the firmware
|
|
||||||
@param[in] APsStackSize APs stack size
|
|
||||||
@param[out] PhysicalAddressEnd The physical end address of accepted memory in phase-1
|
|
||||||
|
|
||||||
@retval EFI_SUCCESS Process the HobList successfully
|
|
||||||
@retval Others Other errors as indicated
|
|
||||||
**/
|
|
||||||
EFI_STATUS
|
|
||||||
EFIAPI
|
|
||||||
AcceptMemoryForAPsStack (
|
|
||||||
IN CONST VOID *VmmHobList,
|
|
||||||
IN UINT32 APsStackSize,
|
|
||||||
OUT EFI_PHYSICAL_ADDRESS *PhysicalAddressEnd
|
|
||||||
)
|
|
||||||
{
|
|
||||||
EFI_STATUS Status;
|
|
||||||
EFI_PEI_HOB_POINTERS Hob;
|
|
||||||
EFI_PHYSICAL_ADDRESS PhysicalEnd;
|
|
||||||
EFI_PHYSICAL_ADDRESS PhysicalStart;
|
|
||||||
UINT64 ResourceLength;
|
|
||||||
BOOLEAN MemoryRegionFound;
|
|
||||||
|
|
||||||
ASSERT (VmmHobList != NULL);
|
|
||||||
|
|
||||||
Status = EFI_SUCCESS;
|
|
||||||
Hob.Raw = (UINT8 *)VmmHobList;
|
|
||||||
MemoryRegionFound = FALSE;
|
|
||||||
|
|
||||||
DEBUG ((DEBUG_INFO, "AcceptMemoryForAPsStack with APsStackSize=0x%x\n", APsStackSize));
|
|
||||||
|
|
||||||
//
|
|
||||||
// Parse the HOB list until end of list or matching type is found.
|
|
||||||
//
|
|
||||||
while (!END_OF_HOB_LIST (Hob) && !MemoryRegionFound) {
|
|
||||||
if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
|
|
||||||
DEBUG ((DEBUG_INFO, "\nResourceType: 0x%x\n", Hob.ResourceDescriptor->ResourceType));
|
|
||||||
|
|
||||||
if (Hob.ResourceDescriptor->ResourceType == BZ3937_EFI_RESOURCE_MEMORY_UNACCEPTED) {
|
|
||||||
ResourceLength = Hob.ResourceDescriptor->ResourceLength;
|
|
||||||
PhysicalStart = Hob.ResourceDescriptor->PhysicalStart;
|
|
||||||
PhysicalEnd = PhysicalStart + ResourceLength;
|
|
||||||
|
|
||||||
DEBUG ((DEBUG_INFO, "ResourceAttribute: 0x%x\n", Hob.ResourceDescriptor->ResourceAttribute));
|
|
||||||
DEBUG ((DEBUG_INFO, "PhysicalStart: 0x%llx\n", PhysicalStart));
|
|
||||||
DEBUG ((DEBUG_INFO, "ResourceLength: 0x%llx\n", ResourceLength));
|
|
||||||
DEBUG ((DEBUG_INFO, "Owner: %g\n\n", &Hob.ResourceDescriptor->Owner));
|
|
||||||
|
|
||||||
if (ResourceLength >= APsStackSize) {
|
|
||||||
MemoryRegionFound = TRUE;
|
|
||||||
if (ResourceLength > ACCEPT_CHUNK_SIZE) {
|
|
||||||
PhysicalEnd = Hob.ResourceDescriptor->PhysicalStart + APsStackSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Status = BspAcceptMemoryResourceRange (
|
|
||||||
Hob.ResourceDescriptor->PhysicalStart,
|
|
||||||
PhysicalEnd
|
|
||||||
);
|
|
||||||
if (EFI_ERROR (Status)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Hob.Raw = GET_NEXT_HOB (Hob);
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT (MemoryRegionFound);
|
|
||||||
*PhysicalAddressEnd = PhysicalEnd;
|
|
||||||
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
BSP and APs work togeter to accept memory which is under the address of 4G.
|
|
||||||
|
|
||||||
@param[in] VmmHobList The Hoblist pass the firmware
|
|
||||||
@param[in] CpusNum Number of vCPUs
|
|
||||||
@param[in] APsStackStartAddres Start address of APs stack
|
|
||||||
@param[in] PhysicalAddressStart Start physical address which to be accepted
|
|
||||||
|
|
||||||
@retval EFI_SUCCESS Process the HobList successfully
|
|
||||||
@retval Others Other errors as indicated
|
|
||||||
**/
|
|
||||||
EFI_STATUS
|
|
||||||
EFIAPI
|
|
||||||
AcceptMemory (
|
|
||||||
IN CONST VOID *VmmHobList,
|
|
||||||
IN UINT32 CpusNum,
|
|
||||||
IN EFI_PHYSICAL_ADDRESS APsStackStartAddress,
|
|
||||||
IN EFI_PHYSICAL_ADDRESS PhysicalAddressStart
|
|
||||||
)
|
|
||||||
{
|
|
||||||
EFI_STATUS Status;
|
|
||||||
EFI_PEI_HOB_POINTERS Hob;
|
|
||||||
EFI_PHYSICAL_ADDRESS PhysicalStart;
|
|
||||||
EFI_PHYSICAL_ADDRESS PhysicalEnd;
|
|
||||||
EFI_PHYSICAL_ADDRESS AcceptMemoryEndAddress;
|
|
||||||
|
|
||||||
Status = EFI_SUCCESS;
|
|
||||||
AcceptMemoryEndAddress = BASE_4GB;
|
|
||||||
|
|
||||||
ASSERT (VmmHobList != NULL);
|
|
||||||
Hob.Raw = (UINT8 *)VmmHobList;
|
|
||||||
|
|
||||||
DEBUG ((DEBUG_INFO, "AcceptMemory under address of 4G\n"));
|
|
||||||
|
|
||||||
//
|
|
||||||
// Parse the HOB list until end of list or matching type is found.
|
|
||||||
//
|
|
||||||
while (!END_OF_HOB_LIST (Hob)) {
|
|
||||||
if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
|
|
||||||
if (Hob.ResourceDescriptor->ResourceType == BZ3937_EFI_RESOURCE_MEMORY_UNACCEPTED) {
|
|
||||||
PhysicalStart = Hob.ResourceDescriptor->PhysicalStart;
|
|
||||||
PhysicalEnd = PhysicalStart + Hob.ResourceDescriptor->ResourceLength;
|
|
||||||
|
|
||||||
if (PhysicalEnd <= PhysicalAddressStart) {
|
|
||||||
// this memory region has been accepted. Skipped it.
|
|
||||||
Hob.Raw = GET_NEXT_HOB (Hob);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PhysicalStart >= AcceptMemoryEndAddress) {
|
|
||||||
// this memory region is not to be accepted. And we're done.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PhysicalStart >= PhysicalAddressStart) {
|
|
||||||
// this memory region has not been acceted.
|
|
||||||
} else if ((PhysicalStart < PhysicalAddressStart) && (PhysicalEnd > PhysicalAddressStart)) {
|
|
||||||
// part of the memory region has been accepted.
|
|
||||||
PhysicalStart = PhysicalAddressStart;
|
|
||||||
}
|
|
||||||
|
|
||||||
// then compare the PhysicalEnd with AcceptMemoryEndAddress
|
|
||||||
if (PhysicalEnd >= AcceptMemoryEndAddress) {
|
|
||||||
PhysicalEnd = AcceptMemoryEndAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG ((DEBUG_INFO, "ResourceAttribute: 0x%x\n", Hob.ResourceDescriptor->ResourceAttribute));
|
|
||||||
DEBUG ((DEBUG_INFO, "PhysicalStart: 0x%llx\n", Hob.ResourceDescriptor->PhysicalStart));
|
|
||||||
DEBUG ((DEBUG_INFO, "ResourceLength: 0x%llx\n", Hob.ResourceDescriptor->ResourceLength));
|
|
||||||
DEBUG ((DEBUG_INFO, "Owner: %g\n\n", &Hob.ResourceDescriptor->Owner));
|
|
||||||
|
|
||||||
// Now we're ready to accept memory [PhysicalStart, PhysicalEnd)
|
|
||||||
if (CpusNum == 1) {
|
|
||||||
Status = BspAcceptMemoryResourceRange (PhysicalStart, PhysicalEnd);
|
|
||||||
} else {
|
|
||||||
Status = MpAcceptMemoryResourceRange (
|
|
||||||
PhysicalStart,
|
|
||||||
PhysicalEnd,
|
|
||||||
APsStackStartAddress,
|
|
||||||
CpusNum
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (EFI_ERROR (Status)) {
|
|
||||||
ASSERT (FALSE);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PhysicalEnd == AcceptMemoryEndAddress) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Hob.Raw = GET_NEXT_HOB (Hob);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Check the value whether in the valid list.
|
|
||||||
|
|
||||||
@param[in] Value A value
|
|
||||||
@param[in] ValidList A pointer to valid list
|
|
||||||
@param[in] ValidListLength Length of valid list
|
|
||||||
|
|
||||||
@retval TRUE The value is in valid list.
|
|
||||||
@retval FALSE The value is not in valid list.
|
|
||||||
|
|
||||||
**/
|
|
||||||
BOOLEAN
|
|
||||||
EFIAPI
|
|
||||||
IsInValidList (
|
|
||||||
IN UINT32 Value,
|
|
||||||
IN UINT32 *ValidList,
|
|
||||||
IN UINT32 ValidListLength
|
|
||||||
)
|
|
||||||
{
|
|
||||||
UINT32 index;
|
|
||||||
|
|
||||||
if (ValidList == NULL) {
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (index = 0; index < ValidListLength; index++) {
|
|
||||||
if (ValidList[index] == Value) {
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Check the integrity of VMM Hob List.
|
|
||||||
|
|
||||||
@param[in] VmmHobList A pointer to Hob List
|
|
||||||
|
|
||||||
@retval TRUE The Hob List is valid.
|
|
||||||
@retval FALSE The Hob List is invalid.
|
|
||||||
|
|
||||||
**/
|
|
||||||
BOOLEAN
|
|
||||||
EFIAPI
|
|
||||||
ValidateHobList (
|
|
||||||
IN CONST VOID *VmmHobList
|
|
||||||
)
|
|
||||||
{
|
|
||||||
EFI_PEI_HOB_POINTERS Hob;
|
|
||||||
UINT32 EFI_BOOT_MODE_LIST[] = {
|
|
||||||
BOOT_WITH_FULL_CONFIGURATION,
|
|
||||||
BOOT_WITH_MINIMAL_CONFIGURATION,
|
|
||||||
BOOT_ASSUMING_NO_CONFIGURATION_CHANGES,
|
|
||||||
BOOT_WITH_FULL_CONFIGURATION_PLUS_DIAGNOSTICS,
|
|
||||||
BOOT_WITH_DEFAULT_SETTINGS,
|
|
||||||
BOOT_ON_S4_RESUME,
|
|
||||||
BOOT_ON_S5_RESUME,
|
|
||||||
BOOT_WITH_MFG_MODE_SETTINGS,
|
|
||||||
BOOT_ON_S2_RESUME,
|
|
||||||
BOOT_ON_S3_RESUME,
|
|
||||||
BOOT_ON_FLASH_UPDATE,
|
|
||||||
BOOT_IN_RECOVERY_MODE
|
|
||||||
};
|
|
||||||
|
|
||||||
UINT32 EFI_RESOURCE_TYPE_LIST[] = {
|
|
||||||
EFI_RESOURCE_SYSTEM_MEMORY,
|
|
||||||
EFI_RESOURCE_MEMORY_MAPPED_IO,
|
|
||||||
EFI_RESOURCE_IO,
|
|
||||||
EFI_RESOURCE_FIRMWARE_DEVICE,
|
|
||||||
EFI_RESOURCE_MEMORY_MAPPED_IO_PORT,
|
|
||||||
EFI_RESOURCE_MEMORY_RESERVED,
|
|
||||||
EFI_RESOURCE_IO_RESERVED,
|
|
||||||
BZ3937_EFI_RESOURCE_MEMORY_UNACCEPTED
|
|
||||||
};
|
|
||||||
|
|
||||||
if (VmmHobList == NULL) {
|
|
||||||
DEBUG ((DEBUG_ERROR, "HOB: HOB data pointer is NULL\n"));
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
Hob.Raw = (UINT8 *)VmmHobList;
|
|
||||||
|
|
||||||
//
|
|
||||||
// Parse the HOB list until end of list or matching type is found.
|
|
||||||
//
|
|
||||||
while (!END_OF_HOB_LIST (Hob)) {
|
|
||||||
if (Hob.Header->Reserved != (UINT32)0) {
|
|
||||||
DEBUG ((DEBUG_ERROR, "HOB: Hob header Reserved filed should be zero\n"));
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Hob.Header->HobLength == 0) {
|
|
||||||
DEBUG ((DEBUG_ERROR, "HOB: Hob header LEANGTH should not be zero\n"));
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (Hob.Header->HobType) {
|
|
||||||
case EFI_HOB_TYPE_HANDOFF:
|
|
||||||
if (Hob.Header->HobLength != sizeof (EFI_HOB_HANDOFF_INFO_TABLE)) {
|
|
||||||
DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_HANDOFF));
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsInValidList (Hob.HandoffInformationTable->BootMode, EFI_BOOT_MODE_LIST, ARRAY_SIZE (EFI_BOOT_MODE_LIST)) == FALSE) {
|
|
||||||
DEBUG ((DEBUG_ERROR, "HOB: Unknow HandoffInformationTable BootMode type. Type: 0x%08x\n", Hob.HandoffInformationTable->BootMode));
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((Hob.HandoffInformationTable->EfiFreeMemoryTop % 4096) != 0) {
|
|
||||||
DEBUG ((DEBUG_ERROR, "HOB: HandoffInformationTable EfiFreeMemoryTop address must be 4-KB aligned to meet page restrictions of UEFI.\
|
|
||||||
Address: 0x%016lx\n", Hob.HandoffInformationTable->EfiFreeMemoryTop));
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case EFI_HOB_TYPE_RESOURCE_DESCRIPTOR:
|
|
||||||
if (Hob.Header->HobLength != sizeof (EFI_HOB_RESOURCE_DESCRIPTOR)) {
|
|
||||||
DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_RESOURCE_DESCRIPTOR));
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsInValidList (Hob.ResourceDescriptor->ResourceType, EFI_RESOURCE_TYPE_LIST, ARRAY_SIZE (EFI_RESOURCE_TYPE_LIST)) == FALSE) {
|
|
||||||
DEBUG ((DEBUG_ERROR, "HOB: Unknow ResourceDescriptor ResourceType type. Type: 0x%08x\n", Hob.ResourceDescriptor->ResourceType));
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((Hob.ResourceDescriptor->ResourceAttribute & (~(EFI_RESOURCE_ATTRIBUTE_PRESENT |
|
|
||||||
EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
|
|
||||||
EFI_RESOURCE_ATTRIBUTE_TESTED |
|
|
||||||
EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED |
|
|
||||||
EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED |
|
|
||||||
EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED |
|
|
||||||
EFI_RESOURCE_ATTRIBUTE_PERSISTENT |
|
|
||||||
EFI_RESOURCE_ATTRIBUTE_SINGLE_BIT_ECC |
|
|
||||||
EFI_RESOURCE_ATTRIBUTE_MULTIPLE_BIT_ECC |
|
|
||||||
EFI_RESOURCE_ATTRIBUTE_ECC_RESERVED_1 |
|
|
||||||
EFI_RESOURCE_ATTRIBUTE_ECC_RESERVED_2 |
|
|
||||||
EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
|
|
||||||
EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
|
|
||||||
EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
|
|
||||||
EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE |
|
|
||||||
EFI_RESOURCE_ATTRIBUTE_16_BIT_IO |
|
|
||||||
EFI_RESOURCE_ATTRIBUTE_32_BIT_IO |
|
|
||||||
EFI_RESOURCE_ATTRIBUTE_64_BIT_IO |
|
|
||||||
EFI_RESOURCE_ATTRIBUTE_UNCACHED_EXPORTED |
|
|
||||||
EFI_RESOURCE_ATTRIBUTE_READ_PROTECTABLE |
|
|
||||||
EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTABLE |
|
|
||||||
EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTABLE |
|
|
||||||
EFI_RESOURCE_ATTRIBUTE_PERSISTABLE |
|
|
||||||
EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTED |
|
|
||||||
EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTABLE |
|
|
||||||
EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE))) != 0)
|
|
||||||
{
|
|
||||||
DEBUG ((DEBUG_ERROR, "HOB: Unknow ResourceDescriptor ResourceAttribute type. Type: 0x%08x\n", Hob.ResourceDescriptor->ResourceAttribute));
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
// EFI_HOB_GUID_TYPE is variable length data, so skip check
|
|
||||||
case EFI_HOB_TYPE_GUID_EXTENSION:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case EFI_HOB_TYPE_FV:
|
|
||||||
if (Hob.Header->HobLength != sizeof (EFI_HOB_FIRMWARE_VOLUME)) {
|
|
||||||
DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_FV));
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case EFI_HOB_TYPE_FV2:
|
|
||||||
if (Hob.Header->HobLength != sizeof (EFI_HOB_FIRMWARE_VOLUME2)) {
|
|
||||||
DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_FV2));
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case EFI_HOB_TYPE_FV3:
|
|
||||||
if (Hob.Header->HobLength != sizeof (EFI_HOB_FIRMWARE_VOLUME3)) {
|
|
||||||
DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_FV3));
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case EFI_HOB_TYPE_CPU:
|
|
||||||
if (Hob.Header->HobLength != sizeof (EFI_HOB_CPU)) {
|
|
||||||
DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_CPU));
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (UINT32 index = 0; index < 6; index++) {
|
|
||||||
if (Hob.Cpu->Reserved[index] != 0) {
|
|
||||||
DEBUG ((DEBUG_ERROR, "HOB: Cpu Reserved field will always be set to zero.\n"));
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
DEBUG ((DEBUG_ERROR, "HOB: Hob type is not know. Type: 0x%04x\n", Hob.Header->HobType));
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get next HOB
|
|
||||||
Hob.Raw = (UINT8 *)(Hob.Raw + Hob.Header->HobLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Processing the incoming HobList for the TDX
|
|
||||||
|
|
||||||
Firmware must parse list, and accept the pages of memory before their can be
|
|
||||||
use by the guest.
|
|
||||||
|
|
||||||
@param[in] VmmHobList The Hoblist pass the firmware
|
|
||||||
|
|
||||||
@retval EFI_SUCCESS Process the HobList successfully
|
|
||||||
@retval Others Other errors as indicated
|
|
||||||
|
|
||||||
**/
|
|
||||||
EFI_STATUS
|
|
||||||
EFIAPI
|
|
||||||
ProcessHobList (
|
|
||||||
IN CONST VOID *VmmHobList
|
|
||||||
)
|
|
||||||
{
|
|
||||||
EFI_STATUS Status;
|
|
||||||
UINT32 CpusNum;
|
|
||||||
EFI_PHYSICAL_ADDRESS PhysicalEnd;
|
|
||||||
EFI_PHYSICAL_ADDRESS APsStackStartAddress;
|
|
||||||
|
|
||||||
CpusNum = GetCpusNum ();
|
|
||||||
|
|
||||||
//
|
|
||||||
// If there are mutli-vCPU in a TDX guest, accept memory is split into 2 phases.
|
|
||||||
// Phase-1 accepts a small piece of memory by BSP. This piece of memory
|
|
||||||
// is used to setup AP's stack.
|
|
||||||
// After that phase-2 accepts a big piece of memory by BSP/APs.
|
|
||||||
//
|
|
||||||
// TDVF supports 4K and 2M accept-page-size. The memory which can be accpeted
|
|
||||||
// in 2M accept-page-size must be 2M aligned and multiple 2M. So we align
|
|
||||||
// APsStackSize to 2M size aligned.
|
|
||||||
//
|
|
||||||
if (CpusNum > 1) {
|
|
||||||
Status = AcceptMemoryForAPsStack (VmmHobList, APS_STACK_SIZE (CpusNum), &PhysicalEnd);
|
|
||||||
ASSERT (Status == EFI_SUCCESS);
|
|
||||||
APsStackStartAddress = PhysicalEnd - APS_STACK_SIZE (CpusNum);
|
|
||||||
} else {
|
|
||||||
PhysicalEnd = 0;
|
|
||||||
APsStackStartAddress = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Status = AcceptMemory (VmmHobList, CpusNum, APsStackStartAddress, PhysicalEnd);
|
|
||||||
ASSERT (Status == EFI_SUCCESS);
|
|
||||||
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
In Tdx guest, some information need to be passed from host VMM to guest
|
|
||||||
firmware. For example, the memory resource, etc. These information are
|
|
||||||
prepared by host VMM and put in HobList which is described in TdxMetadata.
|
|
||||||
|
|
||||||
Information in HobList is treated as external input. From the security
|
|
||||||
perspective before it is consumed, it should be validated.
|
|
||||||
|
|
||||||
@retval EFI_SUCCESS Successfully process the hoblist
|
|
||||||
@retval Others Other error as indicated
|
|
||||||
**/
|
|
||||||
EFI_STATUS
|
|
||||||
EFIAPI
|
|
||||||
ProcessTdxHobList (
|
|
||||||
VOID
|
|
||||||
)
|
|
||||||
{
|
|
||||||
EFI_STATUS Status;
|
|
||||||
VOID *TdHob;
|
|
||||||
TD_RETURN_DATA TdReturnData;
|
|
||||||
|
|
||||||
TdHob = (VOID *)(UINTN)FixedPcdGet32 (PcdOvmfSecGhcbBase);
|
|
||||||
Status = TdCall (TDCALL_TDINFO, 0, 0, 0, &TdReturnData);
|
|
||||||
if (EFI_ERROR (Status)) {
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG ((
|
|
||||||
DEBUG_INFO,
|
|
||||||
"Intel Tdx Started with (GPAW: %d, Cpus: %d)\n",
|
|
||||||
TdReturnData.TdInfo.Gpaw,
|
|
||||||
TdReturnData.TdInfo.NumVcpus
|
|
||||||
));
|
|
||||||
|
|
||||||
//
|
|
||||||
// Validate HobList
|
|
||||||
//
|
|
||||||
if (ValidateHobList (TdHob) == FALSE) {
|
|
||||||
return EFI_INVALID_PARAMETER;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Process Hoblist to accept memory
|
|
||||||
//
|
|
||||||
Status = ProcessHobList (TdHob);
|
|
||||||
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build ResourceDescriptorHob for the unaccepted memory region.
|
* Build ResourceDescriptorHob for the unaccepted memory region.
|
||||||
* This memory region may be splitted into 2 parts because of lazy accept.
|
* This memory region may be splitted into 2 parts because of lazy accept.
|
||||||
|
@ -9,26 +9,6 @@
|
|||||||
|
|
||||||
#include <PiPei.h>
|
#include <PiPei.h>
|
||||||
|
|
||||||
/**
|
|
||||||
In Tdx guest, some information need to be passed from host VMM to guest
|
|
||||||
firmware. For example, the memory resource, etc. These information are
|
|
||||||
prepared by host VMM and put in HobList which is described in TdxMetadata.
|
|
||||||
|
|
||||||
Information in HobList is treated as external input. From the security
|
|
||||||
perspective before it is consumed, it should be validated.
|
|
||||||
|
|
||||||
@retval EFI_SUCCESS Successfully process the hoblist
|
|
||||||
@retval Others Other error as indicated
|
|
||||||
**/
|
|
||||||
EFI_STATUS
|
|
||||||
EFIAPI
|
|
||||||
ProcessTdxHobList (
|
|
||||||
VOID
|
|
||||||
)
|
|
||||||
{
|
|
||||||
return EFI_UNSUPPORTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
In Tdx guest, the system memory is passed in TdHob by host VMM. So
|
In Tdx guest, the system memory is passed in TdHob by host VMM. So
|
||||||
the major task of PlatformTdxPublishRamRegions is to walk thru the
|
the major task of PlatformTdxPublishRamRegions is to walk thru the
|
||||||
|
@ -52,7 +52,6 @@
|
|||||||
PcdLib
|
PcdLib
|
||||||
PciLib
|
PciLib
|
||||||
PeiHardwareInfoLib
|
PeiHardwareInfoLib
|
||||||
TdxMailboxLib
|
|
||||||
|
|
||||||
[LibraryClasses.X64]
|
[LibraryClasses.X64]
|
||||||
TdxLib
|
TdxLib
|
||||||
|
@ -724,7 +724,8 @@
|
|||||||
OvmfPkg/Sec/SecMain.inf {
|
OvmfPkg/Sec/SecMain.inf {
|
||||||
<LibraryClasses>
|
<LibraryClasses>
|
||||||
NULL|MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaCustomDecompressLib.inf
|
NULL|MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaCustomDecompressLib.inf
|
||||||
NULL|OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
|
NULL|OvmfPkg/IntelTdx/TdxHelperLib/SecTdxHelperLib.inf
|
||||||
|
BaseCryptLib|CryptoPkg/Library/BaseCryptLib/SecCryptLib.inf
|
||||||
}
|
}
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
#include <Library/CpuExceptionHandlerLib.h>
|
#include <Library/CpuExceptionHandlerLib.h>
|
||||||
#include <Ppi/TemporaryRamSupport.h>
|
#include <Ppi/TemporaryRamSupport.h>
|
||||||
#include <Ppi/MpInitLibDep.h>
|
#include <Ppi/MpInitLibDep.h>
|
||||||
#include <Library/PlatformInitLib.h>
|
#include <Library/TdxHelperLib.h>
|
||||||
#include <Library/CcProbeLib.h>
|
#include <Library/CcProbeLib.h>
|
||||||
#include "AmdSev.h"
|
#include "AmdSev.h"
|
||||||
|
|
||||||
@ -765,7 +765,7 @@ SecCoreStartupWithStack (
|
|||||||
// first so that the memory is accepted. Otherwise access to the unaccepted
|
// first so that the memory is accepted. Otherwise access to the unaccepted
|
||||||
// memory will trigger tripple fault.
|
// memory will trigger tripple fault.
|
||||||
//
|
//
|
||||||
if (ProcessTdxHobList () != EFI_SUCCESS) {
|
if (TdxHelperProcessTdHob () != EFI_SUCCESS) {
|
||||||
CpuDeadLoop ();
|
CpuDeadLoop ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user