audk/OvmfPkg/Library/PlatformInitLib/IntelTdx.c

952 lines
30 KiB
C
Raw Normal View History

OvmfPkg: Update PlatformInitLib to process Tdx hoblist RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429 When host VMM create the Td guest, the system memory informations are stored in TdHob, which is a memory region described in Tdx metadata. The system memory region in TdHob should be accepted before it can be accessed. So the newly added function (ProcessTdxHobList) is to process the TdHobList to accept the memory. Because TdHobList is provided by host VMM which is not trusted, so its content should be checked before it is consumed by TDVF. Because ProcessTdxHobList is to be called in SEC phase, so PlatformInitLib.inf is updated to support SEC. Note: In this patch it is BSP which accepts the pages. So there maybe boot performance issue. There are some mitigations to this issue, such as lazy accept, 2M accept page size, etc. We will re-visit here in the future. EFI_RESOURCE_MEMORY_UNACCEPTED is a new ResourceType in EFI_HOB_RESOURCE_DESCRIPTOR. It is defined for the unaccepted memory passed from Host VMM. This is proposed in microsoft/mu_basecore#66 files#diff-b20a11152d1ce9249c691be5690b4baf52069efadf2e2546cdd2eb663d80c9 e4R237 according to UEFI-Code-First. The proposal was approved in 2021 in UEFI Mantis, and will be added to the new PI.next specification. Per the MdePkg reviewer's comments, before this new ResourceType is added in the PI spec, it should not be in MdePkg. So it is now defined as an internal implementation and will be moved to MdePkg/Include/Pi/PiHob.h after it is added in PI spec. See https://edk2.groups.io/g/devel/message/87641 PcdTdxAcceptPageSize is added for page accepting. Currently TDX supports 4K and 2M accept page size. The default value is 2M. Tdx guest is only supported in X64. So for IA32 ProcessTdxHobList just returns EFI_UNSUPPORTED. Cc: Ard Biesheuvel <ardb+tianocore@kernel.org> Cc: Jordan Justen <jordan.l.justen@intel.com> Cc: Brijesh Singh <brijesh.singh@amd.com> Cc: Erdem Aktas <erdemaktas@google.com> Cc: James Bottomley <jejb@linux.ibm.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Tom Lendacky <thomas.lendacky@amd.com> Cc: Gerd Hoffmann <kraxel@redhat.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>
2022-02-16 06:32:13 +01:00
/** @file
Initialize Intel TDX support.
Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <Base.h>
OvmfPkg: Update PlatformInitLib to process Tdx hoblist RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429 When host VMM create the Td guest, the system memory informations are stored in TdHob, which is a memory region described in Tdx metadata. The system memory region in TdHob should be accepted before it can be accessed. So the newly added function (ProcessTdxHobList) is to process the TdHobList to accept the memory. Because TdHobList is provided by host VMM which is not trusted, so its content should be checked before it is consumed by TDVF. Because ProcessTdxHobList is to be called in SEC phase, so PlatformInitLib.inf is updated to support SEC. Note: In this patch it is BSP which accepts the pages. So there maybe boot performance issue. There are some mitigations to this issue, such as lazy accept, 2M accept page size, etc. We will re-visit here in the future. EFI_RESOURCE_MEMORY_UNACCEPTED is a new ResourceType in EFI_HOB_RESOURCE_DESCRIPTOR. It is defined for the unaccepted memory passed from Host VMM. This is proposed in microsoft/mu_basecore#66 files#diff-b20a11152d1ce9249c691be5690b4baf52069efadf2e2546cdd2eb663d80c9 e4R237 according to UEFI-Code-First. The proposal was approved in 2021 in UEFI Mantis, and will be added to the new PI.next specification. Per the MdePkg reviewer's comments, before this new ResourceType is added in the PI spec, it should not be in MdePkg. So it is now defined as an internal implementation and will be moved to MdePkg/Include/Pi/PiHob.h after it is added in PI spec. See https://edk2.groups.io/g/devel/message/87641 PcdTdxAcceptPageSize is added for page accepting. Currently TDX supports 4K and 2M accept page size. The default value is 2M. Tdx guest is only supported in X64. So for IA32 ProcessTdxHobList just returns EFI_UNSUPPORTED. Cc: Ard Biesheuvel <ardb+tianocore@kernel.org> Cc: Jordan Justen <jordan.l.justen@intel.com> Cc: Brijesh Singh <brijesh.singh@amd.com> Cc: Erdem Aktas <erdemaktas@google.com> Cc: James Bottomley <jejb@linux.ibm.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Tom Lendacky <thomas.lendacky@amd.com> Cc: Gerd Hoffmann <kraxel@redhat.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>
2022-02-16 06:32:13 +01:00
#include <PiPei.h>
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include <Library/HobLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>
#include <IndustryStandard/Tdx.h>
#include <IndustryStandard/IntelTdx.h>
#include <IndustryStandard/QemuFwCfg.h>
#include <Library/QemuFwCfgLib.h>
#include <Library/PeiServicesLib.h>
#include <Library/TdxLib.h>
OvmfPkg/PlatformInitLib: Implement multi-core accept memory for TDVF BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4172 TDVF once accepts memory only by BSP. To improve the boot performance this patch introduce the multi-core accpet memory. Multi-core means BSP and APs work together to accept memory. TDVF leverages mailbox to wake up APs. It is not enabled in MpInitLib (Which requires SIPI). So multi-core accept memory cannot leverages MpInitLib to coordinate BSP and APs to work together. So TDVF split the accept memory into 2 phases. - AcceptMemoryForAPsStack: BSP accepts a small piece of memory which is then used by APs to setup stack. We assign a 16KB stack for each AP. So a td-guest with 256 vCPU requires 255*16KB = 4080KB. - AcceptMemory: After above small piece of memory is accepted, BSP commands APs to accept memory by sending AcceptPages command in td-mailbox. Together with the command and accpet-function, the APsStack address is send as well. APs then set the stack and jump to accept-function to accept memory. AcceptMemoryForAPsStack accepts as small memory as possible and then jump to AcceptMemory. It fully takes advantage of BSP/APs to work together. After accept memory is done, the memory region for APsStack is not used anymore. It can be used as other private memory. Because accept-memory is in the very beginning of boot process and it will not impact other phases. Cc: Erdem Aktas <erdemaktas@google.com> Cc: Gerd Hoffmann <kraxel@redhat.com> Cc: James Bottomley <jejb@linux.ibm.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Tom Lendacky <thomas.lendacky@amd.com> Signed-off-by: Min Xu <min.m.xu@intel.com> Reviewed-by: Jiewen Yao <jiewen.yao@intel.com>
2022-12-20 09:42:40 +01:00
#include <Library/TdxMailboxLib.h>
OvmfPkg: Update PlatformInitLib to process Tdx hoblist RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429 When host VMM create the Td guest, the system memory informations are stored in TdHob, which is a memory region described in Tdx metadata. The system memory region in TdHob should be accepted before it can be accessed. So the newly added function (ProcessTdxHobList) is to process the TdHobList to accept the memory. Because TdHobList is provided by host VMM which is not trusted, so its content should be checked before it is consumed by TDVF. Because ProcessTdxHobList is to be called in SEC phase, so PlatformInitLib.inf is updated to support SEC. Note: In this patch it is BSP which accepts the pages. So there maybe boot performance issue. There are some mitigations to this issue, such as lazy accept, 2M accept page size, etc. We will re-visit here in the future. EFI_RESOURCE_MEMORY_UNACCEPTED is a new ResourceType in EFI_HOB_RESOURCE_DESCRIPTOR. It is defined for the unaccepted memory passed from Host VMM. This is proposed in microsoft/mu_basecore#66 files#diff-b20a11152d1ce9249c691be5690b4baf52069efadf2e2546cdd2eb663d80c9 e4R237 according to UEFI-Code-First. The proposal was approved in 2021 in UEFI Mantis, and will be added to the new PI.next specification. Per the MdePkg reviewer's comments, before this new ResourceType is added in the PI spec, it should not be in MdePkg. So it is now defined as an internal implementation and will be moved to MdePkg/Include/Pi/PiHob.h after it is added in PI spec. See https://edk2.groups.io/g/devel/message/87641 PcdTdxAcceptPageSize is added for page accepting. Currently TDX supports 4K and 2M accept page size. The default value is 2M. Tdx guest is only supported in X64. So for IA32 ProcessTdxHobList just returns EFI_UNSUPPORTED. Cc: Ard Biesheuvel <ardb+tianocore@kernel.org> Cc: Jordan Justen <jordan.l.justen@intel.com> Cc: Brijesh Singh <brijesh.singh@amd.com> Cc: Erdem Aktas <erdemaktas@google.com> Cc: James Bottomley <jejb@linux.ibm.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Tom Lendacky <thomas.lendacky@amd.com> Cc: Gerd Hoffmann <kraxel@redhat.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>
2022-02-16 06:32:13 +01:00
#include <Library/SynchronizationLib.h>
#include <Pi/PrePiHob.h>
OvmfPkg: Update PlatformInitLib to process Tdx hoblist RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429 When host VMM create the Td guest, the system memory informations are stored in TdHob, which is a memory region described in Tdx metadata. The system memory region in TdHob should be accepted before it can be accessed. So the newly added function (ProcessTdxHobList) is to process the TdHobList to accept the memory. Because TdHobList is provided by host VMM which is not trusted, so its content should be checked before it is consumed by TDVF. Because ProcessTdxHobList is to be called in SEC phase, so PlatformInitLib.inf is updated to support SEC. Note: In this patch it is BSP which accepts the pages. So there maybe boot performance issue. There are some mitigations to this issue, such as lazy accept, 2M accept page size, etc. We will re-visit here in the future. EFI_RESOURCE_MEMORY_UNACCEPTED is a new ResourceType in EFI_HOB_RESOURCE_DESCRIPTOR. It is defined for the unaccepted memory passed from Host VMM. This is proposed in microsoft/mu_basecore#66 files#diff-b20a11152d1ce9249c691be5690b4baf52069efadf2e2546cdd2eb663d80c9 e4R237 according to UEFI-Code-First. The proposal was approved in 2021 in UEFI Mantis, and will be added to the new PI.next specification. Per the MdePkg reviewer's comments, before this new ResourceType is added in the PI spec, it should not be in MdePkg. So it is now defined as an internal implementation and will be moved to MdePkg/Include/Pi/PiHob.h after it is added in PI spec. See https://edk2.groups.io/g/devel/message/87641 PcdTdxAcceptPageSize is added for page accepting. Currently TDX supports 4K and 2M accept page size. The default value is 2M. Tdx guest is only supported in X64. So for IA32 ProcessTdxHobList just returns EFI_UNSUPPORTED. Cc: Ard Biesheuvel <ardb+tianocore@kernel.org> Cc: Jordan Justen <jordan.l.justen@intel.com> Cc: Brijesh Singh <brijesh.singh@amd.com> Cc: Erdem Aktas <erdemaktas@google.com> Cc: James Bottomley <jejb@linux.ibm.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Tom Lendacky <thomas.lendacky@amd.com> Cc: Gerd Hoffmann <kraxel@redhat.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>
2022-02-16 06:32:13 +01:00
#include <WorkArea.h>
#include <ConfidentialComputingGuestAttr.h>
#define ALIGNED_2MB_MASK 0x1fffff
#define MEGABYTE_SHIFT 20
OvmfPkg: Update PlatformInitLib to process Tdx hoblist RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429 When host VMM create the Td guest, the system memory informations are stored in TdHob, which is a memory region described in Tdx metadata. The system memory region in TdHob should be accepted before it can be accessed. So the newly added function (ProcessTdxHobList) is to process the TdHobList to accept the memory. Because TdHobList is provided by host VMM which is not trusted, so its content should be checked before it is consumed by TDVF. Because ProcessTdxHobList is to be called in SEC phase, so PlatformInitLib.inf is updated to support SEC. Note: In this patch it is BSP which accepts the pages. So there maybe boot performance issue. There are some mitigations to this issue, such as lazy accept, 2M accept page size, etc. We will re-visit here in the future. EFI_RESOURCE_MEMORY_UNACCEPTED is a new ResourceType in EFI_HOB_RESOURCE_DESCRIPTOR. It is defined for the unaccepted memory passed from Host VMM. This is proposed in microsoft/mu_basecore#66 files#diff-b20a11152d1ce9249c691be5690b4baf52069efadf2e2546cdd2eb663d80c9 e4R237 according to UEFI-Code-First. The proposal was approved in 2021 in UEFI Mantis, and will be added to the new PI.next specification. Per the MdePkg reviewer's comments, before this new ResourceType is added in the PI spec, it should not be in MdePkg. So it is now defined as an internal implementation and will be moved to MdePkg/Include/Pi/PiHob.h after it is added in PI spec. See https://edk2.groups.io/g/devel/message/87641 PcdTdxAcceptPageSize is added for page accepting. Currently TDX supports 4K and 2M accept page size. The default value is 2M. Tdx guest is only supported in X64. So for IA32 ProcessTdxHobList just returns EFI_UNSUPPORTED. Cc: Ard Biesheuvel <ardb+tianocore@kernel.org> Cc: Jordan Justen <jordan.l.justen@intel.com> Cc: Brijesh Singh <brijesh.singh@amd.com> Cc: Erdem Aktas <erdemaktas@google.com> Cc: James Bottomley <jejb@linux.ibm.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Tom Lendacky <thomas.lendacky@amd.com> Cc: Gerd Hoffmann <kraxel@redhat.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>
2022-02-16 06:32:13 +01:00
OvmfPkg/PlatformInitLib: Implement multi-core accept memory for TDVF BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4172 TDVF once accepts memory only by BSP. To improve the boot performance this patch introduce the multi-core accpet memory. Multi-core means BSP and APs work together to accept memory. TDVF leverages mailbox to wake up APs. It is not enabled in MpInitLib (Which requires SIPI). So multi-core accept memory cannot leverages MpInitLib to coordinate BSP and APs to work together. So TDVF split the accept memory into 2 phases. - AcceptMemoryForAPsStack: BSP accepts a small piece of memory which is then used by APs to setup stack. We assign a 16KB stack for each AP. So a td-guest with 256 vCPU requires 255*16KB = 4080KB. - AcceptMemory: After above small piece of memory is accepted, BSP commands APs to accept memory by sending AcceptPages command in td-mailbox. Together with the command and accpet-function, the APsStack address is send as well. APs then set the stack and jump to accept-function to accept memory. AcceptMemoryForAPsStack accepts as small memory as possible and then jump to AcceptMemory. It fully takes advantage of BSP/APs to work together. After accept memory is done, the memory region for APsStack is not used anymore. It can be used as other private memory. Because accept-memory is in the very beginning of boot process and it will not impact other phases. Cc: Erdem Aktas <erdemaktas@google.com> Cc: Gerd Hoffmann <kraxel@redhat.com> Cc: James Bottomley <jejb@linux.ibm.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Tom Lendacky <thomas.lendacky@amd.com> Signed-off-by: Min Xu <min.m.xu@intel.com> Reviewed-by: Jiewen Yao <jiewen.yao@intel.com>
2022-12-20 09:42:40 +01:00
#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))
OvmfPkg: Update PlatformInitLib to process Tdx hoblist RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429 When host VMM create the Td guest, the system memory informations are stored in TdHob, which is a memory region described in Tdx metadata. The system memory region in TdHob should be accepted before it can be accessed. So the newly added function (ProcessTdxHobList) is to process the TdHobList to accept the memory. Because TdHobList is provided by host VMM which is not trusted, so its content should be checked before it is consumed by TDVF. Because ProcessTdxHobList is to be called in SEC phase, so PlatformInitLib.inf is updated to support SEC. Note: In this patch it is BSP which accepts the pages. So there maybe boot performance issue. There are some mitigations to this issue, such as lazy accept, 2M accept page size, etc. We will re-visit here in the future. EFI_RESOURCE_MEMORY_UNACCEPTED is a new ResourceType in EFI_HOB_RESOURCE_DESCRIPTOR. It is defined for the unaccepted memory passed from Host VMM. This is proposed in microsoft/mu_basecore#66 files#diff-b20a11152d1ce9249c691be5690b4baf52069efadf2e2546cdd2eb663d80c9 e4R237 according to UEFI-Code-First. The proposal was approved in 2021 in UEFI Mantis, and will be added to the new PI.next specification. Per the MdePkg reviewer's comments, before this new ResourceType is added in the PI spec, it should not be in MdePkg. So it is now defined as an internal implementation and will be moved to MdePkg/Include/Pi/PiHob.h after it is added in PI spec. See https://edk2.groups.io/g/devel/message/87641 PcdTdxAcceptPageSize is added for page accepting. Currently TDX supports 4K and 2M accept page size. The default value is 2M. Tdx guest is only supported in X64. So for IA32 ProcessTdxHobList just returns EFI_UNSUPPORTED. Cc: Ard Biesheuvel <ardb+tianocore@kernel.org> Cc: Jordan Justen <jordan.l.justen@intel.com> Cc: Brijesh Singh <brijesh.singh@amd.com> Cc: Erdem Aktas <erdemaktas@google.com> Cc: James Bottomley <jejb@linux.ibm.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Tom Lendacky <thomas.lendacky@amd.com> Cc: Gerd Hoffmann <kraxel@redhat.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>
2022-02-16 06:32:13 +01:00
/**
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;
}
OvmfPkg/PlatformInitLib: Implement multi-core accept memory for TDVF BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4172 TDVF once accepts memory only by BSP. To improve the boot performance this patch introduce the multi-core accpet memory. Multi-core means BSP and APs work together to accept memory. TDVF leverages mailbox to wake up APs. It is not enabled in MpInitLib (Which requires SIPI). So multi-core accept memory cannot leverages MpInitLib to coordinate BSP and APs to work together. So TDVF split the accept memory into 2 phases. - AcceptMemoryForAPsStack: BSP accepts a small piece of memory which is then used by APs to setup stack. We assign a 16KB stack for each AP. So a td-guest with 256 vCPU requires 255*16KB = 4080KB. - AcceptMemory: After above small piece of memory is accepted, BSP commands APs to accept memory by sending AcceptPages command in td-mailbox. Together with the command and accpet-function, the APsStack address is send as well. APs then set the stack and jump to accept-function to accept memory. AcceptMemoryForAPsStack accepts as small memory as possible and then jump to AcceptMemory. It fully takes advantage of BSP/APs to work together. After accept memory is done, the memory region for APsStack is not used anymore. It can be used as other private memory. Because accept-memory is in the very beginning of boot process and it will not impact other phases. Cc: Erdem Aktas <erdemaktas@google.com> Cc: Gerd Hoffmann <kraxel@redhat.com> Cc: James Bottomley <jejb@linux.ibm.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Tom Lendacky <thomas.lendacky@amd.com> Signed-off-by: Min Xu <min.m.xu@intel.com> Reviewed-by: Jiewen Yao <jiewen.yao@intel.com>
2022-12-20 09:42:40 +01:00
/**
* 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;
}
OvmfPkg: Update PlatformInitLib to process Tdx hoblist RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429 When host VMM create the Td guest, the system memory informations are stored in TdHob, which is a memory region described in Tdx metadata. The system memory region in TdHob should be accepted before it can be accessed. So the newly added function (ProcessTdxHobList) is to process the TdHobList to accept the memory. Because TdHobList is provided by host VMM which is not trusted, so its content should be checked before it is consumed by TDVF. Because ProcessTdxHobList is to be called in SEC phase, so PlatformInitLib.inf is updated to support SEC. Note: In this patch it is BSP which accepts the pages. So there maybe boot performance issue. There are some mitigations to this issue, such as lazy accept, 2M accept page size, etc. We will re-visit here in the future. EFI_RESOURCE_MEMORY_UNACCEPTED is a new ResourceType in EFI_HOB_RESOURCE_DESCRIPTOR. It is defined for the unaccepted memory passed from Host VMM. This is proposed in microsoft/mu_basecore#66 files#diff-b20a11152d1ce9249c691be5690b4baf52069efadf2e2546cdd2eb663d80c9 e4R237 according to UEFI-Code-First. The proposal was approved in 2021 in UEFI Mantis, and will be added to the new PI.next specification. Per the MdePkg reviewer's comments, before this new ResourceType is added in the PI spec, it should not be in MdePkg. So it is now defined as an internal implementation and will be moved to MdePkg/Include/Pi/PiHob.h after it is added in PI spec. See https://edk2.groups.io/g/devel/message/87641 PcdTdxAcceptPageSize is added for page accepting. Currently TDX supports 4K and 2M accept page size. The default value is 2M. Tdx guest is only supported in X64. So for IA32 ProcessTdxHobList just returns EFI_UNSUPPORTED. Cc: Ard Biesheuvel <ardb+tianocore@kernel.org> Cc: Jordan Justen <jordan.l.justen@intel.com> Cc: Brijesh Singh <brijesh.singh@amd.com> Cc: Erdem Aktas <erdemaktas@google.com> Cc: James Bottomley <jejb@linux.ibm.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Tom Lendacky <thomas.lendacky@amd.com> Cc: Gerd Hoffmann <kraxel@redhat.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>
2022-02-16 06:32:13 +01:00
/**
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
OvmfPkg: Update PlatformInitLib to process Tdx hoblist RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429 When host VMM create the Td guest, the system memory informations are stored in TdHob, which is a memory region described in Tdx metadata. The system memory region in TdHob should be accepted before it can be accessed. So the newly added function (ProcessTdxHobList) is to process the TdHobList to accept the memory. Because TdHobList is provided by host VMM which is not trusted, so its content should be checked before it is consumed by TDVF. Because ProcessTdxHobList is to be called in SEC phase, so PlatformInitLib.inf is updated to support SEC. Note: In this patch it is BSP which accepts the pages. So there maybe boot performance issue. There are some mitigations to this issue, such as lazy accept, 2M accept page size, etc. We will re-visit here in the future. EFI_RESOURCE_MEMORY_UNACCEPTED is a new ResourceType in EFI_HOB_RESOURCE_DESCRIPTOR. It is defined for the unaccepted memory passed from Host VMM. This is proposed in microsoft/mu_basecore#66 files#diff-b20a11152d1ce9249c691be5690b4baf52069efadf2e2546cdd2eb663d80c9 e4R237 according to UEFI-Code-First. The proposal was approved in 2021 in UEFI Mantis, and will be added to the new PI.next specification. Per the MdePkg reviewer's comments, before this new ResourceType is added in the PI spec, it should not be in MdePkg. So it is now defined as an internal implementation and will be moved to MdePkg/Include/Pi/PiHob.h after it is added in PI spec. See https://edk2.groups.io/g/devel/message/87641 PcdTdxAcceptPageSize is added for page accepting. Currently TDX supports 4K and 2M accept page size. The default value is 2M. Tdx guest is only supported in X64. So for IA32 ProcessTdxHobList just returns EFI_UNSUPPORTED. Cc: Ard Biesheuvel <ardb+tianocore@kernel.org> Cc: Jordan Justen <jordan.l.justen@intel.com> Cc: Brijesh Singh <brijesh.singh@amd.com> Cc: Erdem Aktas <erdemaktas@google.com> Cc: James Bottomley <jejb@linux.ibm.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Tom Lendacky <thomas.lendacky@amd.com> Cc: Gerd Hoffmann <kraxel@redhat.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>
2022-02-16 06:32:13 +01:00
};
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;
OvmfPkg/PlatformInitLib: Implement multi-core accept memory for TDVF BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4172 TDVF once accepts memory only by BSP. To improve the boot performance this patch introduce the multi-core accpet memory. Multi-core means BSP and APs work together to accept memory. TDVF leverages mailbox to wake up APs. It is not enabled in MpInitLib (Which requires SIPI). So multi-core accept memory cannot leverages MpInitLib to coordinate BSP and APs to work together. So TDVF split the accept memory into 2 phases. - AcceptMemoryForAPsStack: BSP accepts a small piece of memory which is then used by APs to setup stack. We assign a 16KB stack for each AP. So a td-guest with 256 vCPU requires 255*16KB = 4080KB. - AcceptMemory: After above small piece of memory is accepted, BSP commands APs to accept memory by sending AcceptPages command in td-mailbox. Together with the command and accpet-function, the APsStack address is send as well. APs then set the stack and jump to accept-function to accept memory. AcceptMemoryForAPsStack accepts as small memory as possible and then jump to AcceptMemory. It fully takes advantage of BSP/APs to work together. After accept memory is done, the memory region for APsStack is not used anymore. It can be used as other private memory. Because accept-memory is in the very beginning of boot process and it will not impact other phases. Cc: Erdem Aktas <erdemaktas@google.com> Cc: Gerd Hoffmann <kraxel@redhat.com> Cc: James Bottomley <jejb@linux.ibm.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Tom Lendacky <thomas.lendacky@amd.com> Signed-off-by: Min Xu <min.m.xu@intel.com> Reviewed-by: Jiewen Yao <jiewen.yao@intel.com>
2022-12-20 09:42:40 +01:00
UINT32 CpusNum;
OvmfPkg: Update PlatformInitLib to process Tdx hoblist RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429 When host VMM create the Td guest, the system memory informations are stored in TdHob, which is a memory region described in Tdx metadata. The system memory region in TdHob should be accepted before it can be accessed. So the newly added function (ProcessTdxHobList) is to process the TdHobList to accept the memory. Because TdHobList is provided by host VMM which is not trusted, so its content should be checked before it is consumed by TDVF. Because ProcessTdxHobList is to be called in SEC phase, so PlatformInitLib.inf is updated to support SEC. Note: In this patch it is BSP which accepts the pages. So there maybe boot performance issue. There are some mitigations to this issue, such as lazy accept, 2M accept page size, etc. We will re-visit here in the future. EFI_RESOURCE_MEMORY_UNACCEPTED is a new ResourceType in EFI_HOB_RESOURCE_DESCRIPTOR. It is defined for the unaccepted memory passed from Host VMM. This is proposed in microsoft/mu_basecore#66 files#diff-b20a11152d1ce9249c691be5690b4baf52069efadf2e2546cdd2eb663d80c9 e4R237 according to UEFI-Code-First. The proposal was approved in 2021 in UEFI Mantis, and will be added to the new PI.next specification. Per the MdePkg reviewer's comments, before this new ResourceType is added in the PI spec, it should not be in MdePkg. So it is now defined as an internal implementation and will be moved to MdePkg/Include/Pi/PiHob.h after it is added in PI spec. See https://edk2.groups.io/g/devel/message/87641 PcdTdxAcceptPageSize is added for page accepting. Currently TDX supports 4K and 2M accept page size. The default value is 2M. Tdx guest is only supported in X64. So for IA32 ProcessTdxHobList just returns EFI_UNSUPPORTED. Cc: Ard Biesheuvel <ardb+tianocore@kernel.org> Cc: Jordan Justen <jordan.l.justen@intel.com> Cc: Brijesh Singh <brijesh.singh@amd.com> Cc: Erdem Aktas <erdemaktas@google.com> Cc: James Bottomley <jejb@linux.ibm.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Tom Lendacky <thomas.lendacky@amd.com> Cc: Gerd Hoffmann <kraxel@redhat.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>
2022-02-16 06:32:13 +01:00
EFI_PHYSICAL_ADDRESS PhysicalEnd;
OvmfPkg/PlatformInitLib: Implement multi-core accept memory for TDVF BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4172 TDVF once accepts memory only by BSP. To improve the boot performance this patch introduce the multi-core accpet memory. Multi-core means BSP and APs work together to accept memory. TDVF leverages mailbox to wake up APs. It is not enabled in MpInitLib (Which requires SIPI). So multi-core accept memory cannot leverages MpInitLib to coordinate BSP and APs to work together. So TDVF split the accept memory into 2 phases. - AcceptMemoryForAPsStack: BSP accepts a small piece of memory which is then used by APs to setup stack. We assign a 16KB stack for each AP. So a td-guest with 256 vCPU requires 255*16KB = 4080KB. - AcceptMemory: After above small piece of memory is accepted, BSP commands APs to accept memory by sending AcceptPages command in td-mailbox. Together with the command and accpet-function, the APsStack address is send as well. APs then set the stack and jump to accept-function to accept memory. AcceptMemoryForAPsStack accepts as small memory as possible and then jump to AcceptMemory. It fully takes advantage of BSP/APs to work together. After accept memory is done, the memory region for APsStack is not used anymore. It can be used as other private memory. Because accept-memory is in the very beginning of boot process and it will not impact other phases. Cc: Erdem Aktas <erdemaktas@google.com> Cc: Gerd Hoffmann <kraxel@redhat.com> Cc: James Bottomley <jejb@linux.ibm.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Tom Lendacky <thomas.lendacky@amd.com> Signed-off-by: Min Xu <min.m.xu@intel.com> Reviewed-by: Jiewen Yao <jiewen.yao@intel.com>
2022-12-20 09:42:40 +01:00
EFI_PHYSICAL_ADDRESS APsStackStartAddress;
OvmfPkg: Update PlatformInitLib to process Tdx hoblist RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429 When host VMM create the Td guest, the system memory informations are stored in TdHob, which is a memory region described in Tdx metadata. The system memory region in TdHob should be accepted before it can be accessed. So the newly added function (ProcessTdxHobList) is to process the TdHobList to accept the memory. Because TdHobList is provided by host VMM which is not trusted, so its content should be checked before it is consumed by TDVF. Because ProcessTdxHobList is to be called in SEC phase, so PlatformInitLib.inf is updated to support SEC. Note: In this patch it is BSP which accepts the pages. So there maybe boot performance issue. There are some mitigations to this issue, such as lazy accept, 2M accept page size, etc. We will re-visit here in the future. EFI_RESOURCE_MEMORY_UNACCEPTED is a new ResourceType in EFI_HOB_RESOURCE_DESCRIPTOR. It is defined for the unaccepted memory passed from Host VMM. This is proposed in microsoft/mu_basecore#66 files#diff-b20a11152d1ce9249c691be5690b4baf52069efadf2e2546cdd2eb663d80c9 e4R237 according to UEFI-Code-First. The proposal was approved in 2021 in UEFI Mantis, and will be added to the new PI.next specification. Per the MdePkg reviewer's comments, before this new ResourceType is added in the PI spec, it should not be in MdePkg. So it is now defined as an internal implementation and will be moved to MdePkg/Include/Pi/PiHob.h after it is added in PI spec. See https://edk2.groups.io/g/devel/message/87641 PcdTdxAcceptPageSize is added for page accepting. Currently TDX supports 4K and 2M accept page size. The default value is 2M. Tdx guest is only supported in X64. So for IA32 ProcessTdxHobList just returns EFI_UNSUPPORTED. Cc: Ard Biesheuvel <ardb+tianocore@kernel.org> Cc: Jordan Justen <jordan.l.justen@intel.com> Cc: Brijesh Singh <brijesh.singh@amd.com> Cc: Erdem Aktas <erdemaktas@google.com> Cc: James Bottomley <jejb@linux.ibm.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Tom Lendacky <thomas.lendacky@amd.com> Cc: Gerd Hoffmann <kraxel@redhat.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>
2022-02-16 06:32:13 +01:00
OvmfPkg/PlatformInitLib: Implement multi-core accept memory for TDVF BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4172 TDVF once accepts memory only by BSP. To improve the boot performance this patch introduce the multi-core accpet memory. Multi-core means BSP and APs work together to accept memory. TDVF leverages mailbox to wake up APs. It is not enabled in MpInitLib (Which requires SIPI). So multi-core accept memory cannot leverages MpInitLib to coordinate BSP and APs to work together. So TDVF split the accept memory into 2 phases. - AcceptMemoryForAPsStack: BSP accepts a small piece of memory which is then used by APs to setup stack. We assign a 16KB stack for each AP. So a td-guest with 256 vCPU requires 255*16KB = 4080KB. - AcceptMemory: After above small piece of memory is accepted, BSP commands APs to accept memory by sending AcceptPages command in td-mailbox. Together with the command and accpet-function, the APsStack address is send as well. APs then set the stack and jump to accept-function to accept memory. AcceptMemoryForAPsStack accepts as small memory as possible and then jump to AcceptMemory. It fully takes advantage of BSP/APs to work together. After accept memory is done, the memory region for APsStack is not used anymore. It can be used as other private memory. Because accept-memory is in the very beginning of boot process and it will not impact other phases. Cc: Erdem Aktas <erdemaktas@google.com> Cc: Gerd Hoffmann <kraxel@redhat.com> Cc: James Bottomley <jejb@linux.ibm.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Tom Lendacky <thomas.lendacky@amd.com> Signed-off-by: Min Xu <min.m.xu@intel.com> Reviewed-by: Jiewen Yao <jiewen.yao@intel.com>
2022-12-20 09:42:40 +01:00
CpusNum = GetCpusNum ();
OvmfPkg: Update PlatformInitLib to process Tdx hoblist RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429 When host VMM create the Td guest, the system memory informations are stored in TdHob, which is a memory region described in Tdx metadata. The system memory region in TdHob should be accepted before it can be accessed. So the newly added function (ProcessTdxHobList) is to process the TdHobList to accept the memory. Because TdHobList is provided by host VMM which is not trusted, so its content should be checked before it is consumed by TDVF. Because ProcessTdxHobList is to be called in SEC phase, so PlatformInitLib.inf is updated to support SEC. Note: In this patch it is BSP which accepts the pages. So there maybe boot performance issue. There are some mitigations to this issue, such as lazy accept, 2M accept page size, etc. We will re-visit here in the future. EFI_RESOURCE_MEMORY_UNACCEPTED is a new ResourceType in EFI_HOB_RESOURCE_DESCRIPTOR. It is defined for the unaccepted memory passed from Host VMM. This is proposed in microsoft/mu_basecore#66 files#diff-b20a11152d1ce9249c691be5690b4baf52069efadf2e2546cdd2eb663d80c9 e4R237 according to UEFI-Code-First. The proposal was approved in 2021 in UEFI Mantis, and will be added to the new PI.next specification. Per the MdePkg reviewer's comments, before this new ResourceType is added in the PI spec, it should not be in MdePkg. So it is now defined as an internal implementation and will be moved to MdePkg/Include/Pi/PiHob.h after it is added in PI spec. See https://edk2.groups.io/g/devel/message/87641 PcdTdxAcceptPageSize is added for page accepting. Currently TDX supports 4K and 2M accept page size. The default value is 2M. Tdx guest is only supported in X64. So for IA32 ProcessTdxHobList just returns EFI_UNSUPPORTED. Cc: Ard Biesheuvel <ardb+tianocore@kernel.org> Cc: Jordan Justen <jordan.l.justen@intel.com> Cc: Brijesh Singh <brijesh.singh@amd.com> Cc: Erdem Aktas <erdemaktas@google.com> Cc: James Bottomley <jejb@linux.ibm.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Tom Lendacky <thomas.lendacky@amd.com> Cc: Gerd Hoffmann <kraxel@redhat.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>
2022-02-16 06:32:13 +01:00
//
OvmfPkg/PlatformInitLib: Implement multi-core accept memory for TDVF BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4172 TDVF once accepts memory only by BSP. To improve the boot performance this patch introduce the multi-core accpet memory. Multi-core means BSP and APs work together to accept memory. TDVF leverages mailbox to wake up APs. It is not enabled in MpInitLib (Which requires SIPI). So multi-core accept memory cannot leverages MpInitLib to coordinate BSP and APs to work together. So TDVF split the accept memory into 2 phases. - AcceptMemoryForAPsStack: BSP accepts a small piece of memory which is then used by APs to setup stack. We assign a 16KB stack for each AP. So a td-guest with 256 vCPU requires 255*16KB = 4080KB. - AcceptMemory: After above small piece of memory is accepted, BSP commands APs to accept memory by sending AcceptPages command in td-mailbox. Together with the command and accpet-function, the APsStack address is send as well. APs then set the stack and jump to accept-function to accept memory. AcceptMemoryForAPsStack accepts as small memory as possible and then jump to AcceptMemory. It fully takes advantage of BSP/APs to work together. After accept memory is done, the memory region for APsStack is not used anymore. It can be used as other private memory. Because accept-memory is in the very beginning of boot process and it will not impact other phases. Cc: Erdem Aktas <erdemaktas@google.com> Cc: Gerd Hoffmann <kraxel@redhat.com> Cc: James Bottomley <jejb@linux.ibm.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Tom Lendacky <thomas.lendacky@amd.com> Signed-off-by: Min Xu <min.m.xu@intel.com> Reviewed-by: Jiewen Yao <jiewen.yao@intel.com>
2022-12-20 09:42:40 +01:00
// 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.
OvmfPkg: Update PlatformInitLib to process Tdx hoblist RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429 When host VMM create the Td guest, the system memory informations are stored in TdHob, which is a memory region described in Tdx metadata. The system memory region in TdHob should be accepted before it can be accessed. So the newly added function (ProcessTdxHobList) is to process the TdHobList to accept the memory. Because TdHobList is provided by host VMM which is not trusted, so its content should be checked before it is consumed by TDVF. Because ProcessTdxHobList is to be called in SEC phase, so PlatformInitLib.inf is updated to support SEC. Note: In this patch it is BSP which accepts the pages. So there maybe boot performance issue. There are some mitigations to this issue, such as lazy accept, 2M accept page size, etc. We will re-visit here in the future. EFI_RESOURCE_MEMORY_UNACCEPTED is a new ResourceType in EFI_HOB_RESOURCE_DESCRIPTOR. It is defined for the unaccepted memory passed from Host VMM. This is proposed in microsoft/mu_basecore#66 files#diff-b20a11152d1ce9249c691be5690b4baf52069efadf2e2546cdd2eb663d80c9 e4R237 according to UEFI-Code-First. The proposal was approved in 2021 in UEFI Mantis, and will be added to the new PI.next specification. Per the MdePkg reviewer's comments, before this new ResourceType is added in the PI spec, it should not be in MdePkg. So it is now defined as an internal implementation and will be moved to MdePkg/Include/Pi/PiHob.h after it is added in PI spec. See https://edk2.groups.io/g/devel/message/87641 PcdTdxAcceptPageSize is added for page accepting. Currently TDX supports 4K and 2M accept page size. The default value is 2M. Tdx guest is only supported in X64. So for IA32 ProcessTdxHobList just returns EFI_UNSUPPORTED. Cc: Ard Biesheuvel <ardb+tianocore@kernel.org> Cc: Jordan Justen <jordan.l.justen@intel.com> Cc: Brijesh Singh <brijesh.singh@amd.com> Cc: Erdem Aktas <erdemaktas@google.com> Cc: James Bottomley <jejb@linux.ibm.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Tom Lendacky <thomas.lendacky@amd.com> Cc: Gerd Hoffmann <kraxel@redhat.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>
2022-02-16 06:32:13 +01:00
//
OvmfPkg/PlatformInitLib: Implement multi-core accept memory for TDVF BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4172 TDVF once accepts memory only by BSP. To improve the boot performance this patch introduce the multi-core accpet memory. Multi-core means BSP and APs work together to accept memory. TDVF leverages mailbox to wake up APs. It is not enabled in MpInitLib (Which requires SIPI). So multi-core accept memory cannot leverages MpInitLib to coordinate BSP and APs to work together. So TDVF split the accept memory into 2 phases. - AcceptMemoryForAPsStack: BSP accepts a small piece of memory which is then used by APs to setup stack. We assign a 16KB stack for each AP. So a td-guest with 256 vCPU requires 255*16KB = 4080KB. - AcceptMemory: After above small piece of memory is accepted, BSP commands APs to accept memory by sending AcceptPages command in td-mailbox. Together with the command and accpet-function, the APsStack address is send as well. APs then set the stack and jump to accept-function to accept memory. AcceptMemoryForAPsStack accepts as small memory as possible and then jump to AcceptMemory. It fully takes advantage of BSP/APs to work together. After accept memory is done, the memory region for APsStack is not used anymore. It can be used as other private memory. Because accept-memory is in the very beginning of boot process and it will not impact other phases. Cc: Erdem Aktas <erdemaktas@google.com> Cc: Gerd Hoffmann <kraxel@redhat.com> Cc: James Bottomley <jejb@linux.ibm.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Tom Lendacky <thomas.lendacky@amd.com> Signed-off-by: Min Xu <min.m.xu@intel.com> Reviewed-by: Jiewen Yao <jiewen.yao@intel.com>
2022-12-20 09:42:40 +01:00
// 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;
OvmfPkg: Update PlatformInitLib to process Tdx hoblist RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429 When host VMM create the Td guest, the system memory informations are stored in TdHob, which is a memory region described in Tdx metadata. The system memory region in TdHob should be accepted before it can be accessed. So the newly added function (ProcessTdxHobList) is to process the TdHobList to accept the memory. Because TdHobList is provided by host VMM which is not trusted, so its content should be checked before it is consumed by TDVF. Because ProcessTdxHobList is to be called in SEC phase, so PlatformInitLib.inf is updated to support SEC. Note: In this patch it is BSP which accepts the pages. So there maybe boot performance issue. There are some mitigations to this issue, such as lazy accept, 2M accept page size, etc. We will re-visit here in the future. EFI_RESOURCE_MEMORY_UNACCEPTED is a new ResourceType in EFI_HOB_RESOURCE_DESCRIPTOR. It is defined for the unaccepted memory passed from Host VMM. This is proposed in microsoft/mu_basecore#66 files#diff-b20a11152d1ce9249c691be5690b4baf52069efadf2e2546cdd2eb663d80c9 e4R237 according to UEFI-Code-First. The proposal was approved in 2021 in UEFI Mantis, and will be added to the new PI.next specification. Per the MdePkg reviewer's comments, before this new ResourceType is added in the PI spec, it should not be in MdePkg. So it is now defined as an internal implementation and will be moved to MdePkg/Include/Pi/PiHob.h after it is added in PI spec. See https://edk2.groups.io/g/devel/message/87641 PcdTdxAcceptPageSize is added for page accepting. Currently TDX supports 4K and 2M accept page size. The default value is 2M. Tdx guest is only supported in X64. So for IA32 ProcessTdxHobList just returns EFI_UNSUPPORTED. Cc: Ard Biesheuvel <ardb+tianocore@kernel.org> Cc: Jordan Justen <jordan.l.justen@intel.com> Cc: Brijesh Singh <brijesh.singh@amd.com> Cc: Erdem Aktas <erdemaktas@google.com> Cc: James Bottomley <jejb@linux.ibm.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Tom Lendacky <thomas.lendacky@amd.com> Cc: Gerd Hoffmann <kraxel@redhat.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>
2022-02-16 06:32:13 +01:00
}
OvmfPkg/PlatformInitLib: Implement multi-core accept memory for TDVF BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=4172 TDVF once accepts memory only by BSP. To improve the boot performance this patch introduce the multi-core accpet memory. Multi-core means BSP and APs work together to accept memory. TDVF leverages mailbox to wake up APs. It is not enabled in MpInitLib (Which requires SIPI). So multi-core accept memory cannot leverages MpInitLib to coordinate BSP and APs to work together. So TDVF split the accept memory into 2 phases. - AcceptMemoryForAPsStack: BSP accepts a small piece of memory which is then used by APs to setup stack. We assign a 16KB stack for each AP. So a td-guest with 256 vCPU requires 255*16KB = 4080KB. - AcceptMemory: After above small piece of memory is accepted, BSP commands APs to accept memory by sending AcceptPages command in td-mailbox. Together with the command and accpet-function, the APsStack address is send as well. APs then set the stack and jump to accept-function to accept memory. AcceptMemoryForAPsStack accepts as small memory as possible and then jump to AcceptMemory. It fully takes advantage of BSP/APs to work together. After accept memory is done, the memory region for APsStack is not used anymore. It can be used as other private memory. Because accept-memory is in the very beginning of boot process and it will not impact other phases. Cc: Erdem Aktas <erdemaktas@google.com> Cc: Gerd Hoffmann <kraxel@redhat.com> Cc: James Bottomley <jejb@linux.ibm.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Tom Lendacky <thomas.lendacky@amd.com> Signed-off-by: Min Xu <min.m.xu@intel.com> Reviewed-by: Jiewen Yao <jiewen.yao@intel.com>
2022-12-20 09:42:40 +01:00
Status = AcceptMemory (VmmHobList, CpusNum, APsStackStartAddress, PhysicalEnd);
ASSERT (Status == EFI_SUCCESS);
OvmfPkg: Update PlatformInitLib to process Tdx hoblist RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429 When host VMM create the Td guest, the system memory informations are stored in TdHob, which is a memory region described in Tdx metadata. The system memory region in TdHob should be accepted before it can be accessed. So the newly added function (ProcessTdxHobList) is to process the TdHobList to accept the memory. Because TdHobList is provided by host VMM which is not trusted, so its content should be checked before it is consumed by TDVF. Because ProcessTdxHobList is to be called in SEC phase, so PlatformInitLib.inf is updated to support SEC. Note: In this patch it is BSP which accepts the pages. So there maybe boot performance issue. There are some mitigations to this issue, such as lazy accept, 2M accept page size, etc. We will re-visit here in the future. EFI_RESOURCE_MEMORY_UNACCEPTED is a new ResourceType in EFI_HOB_RESOURCE_DESCRIPTOR. It is defined for the unaccepted memory passed from Host VMM. This is proposed in microsoft/mu_basecore#66 files#diff-b20a11152d1ce9249c691be5690b4baf52069efadf2e2546cdd2eb663d80c9 e4R237 according to UEFI-Code-First. The proposal was approved in 2021 in UEFI Mantis, and will be added to the new PI.next specification. Per the MdePkg reviewer's comments, before this new ResourceType is added in the PI spec, it should not be in MdePkg. So it is now defined as an internal implementation and will be moved to MdePkg/Include/Pi/PiHob.h after it is added in PI spec. See https://edk2.groups.io/g/devel/message/87641 PcdTdxAcceptPageSize is added for page accepting. Currently TDX supports 4K and 2M accept page size. The default value is 2M. Tdx guest is only supported in X64. So for IA32 ProcessTdxHobList just returns EFI_UNSUPPORTED. Cc: Ard Biesheuvel <ardb+tianocore@kernel.org> Cc: Jordan Justen <jordan.l.justen@intel.com> Cc: Brijesh Singh <brijesh.singh@amd.com> Cc: Erdem Aktas <erdemaktas@google.com> Cc: James Bottomley <jejb@linux.ibm.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Tom Lendacky <thomas.lendacky@amd.com> Cc: Gerd Hoffmann <kraxel@redhat.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>
2022-02-16 06:32:13 +01:00
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.
* This memory region may be splitted into 2 parts because of lazy accept.
*
* @param Hob Point to the EFI_HOB_RESOURCE_DESCRIPTOR
* @return VOID
*/
VOID
BuildResourceDescriptorHobForUnacceptedMemory (
IN EFI_HOB_RESOURCE_DESCRIPTOR *Hob
)
{
EFI_PHYSICAL_ADDRESS PhysicalStart;
EFI_PHYSICAL_ADDRESS PhysicalEnd;
UINT64 ResourceLength;
EFI_RESOURCE_TYPE ResourceType;
EFI_RESOURCE_ATTRIBUTE_TYPE ResourceAttribute;
UINT64 MaxAcceptedMemoryAddress;
ASSERT (Hob->ResourceType == BZ3937_EFI_RESOURCE_MEMORY_UNACCEPTED);
ResourceType = BZ3937_EFI_RESOURCE_MEMORY_UNACCEPTED;
ResourceAttribute = Hob->ResourceAttribute;
PhysicalStart = Hob->PhysicalStart;
ResourceLength = Hob->ResourceLength;
PhysicalEnd = PhysicalStart + ResourceLength;
//
// In the first stage of lazy-accept, all the memory under 4G will be accepted.
// The memory above 4G will not be accepted.
//
MaxAcceptedMemoryAddress = BASE_4GB;
if (PhysicalEnd <= MaxAcceptedMemoryAddress) {
//
// This memory region has been accepted.
//
ResourceType = EFI_RESOURCE_SYSTEM_MEMORY;
ResourceAttribute |= (EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED | EFI_RESOURCE_ATTRIBUTE_TESTED);
} else if (PhysicalStart >= MaxAcceptedMemoryAddress) {
//
// This memory region hasn't been accepted.
// So keep the ResourceType and ResourceAttribute unchange.
//
}
BuildResourceDescriptorHob (
ResourceType,
ResourceAttribute,
PhysicalStart,
ResourceLength
);
}
OvmfPkg: Update PlatformInitLib to process Tdx hoblist RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429 When host VMM create the Td guest, the system memory informations are stored in TdHob, which is a memory region described in Tdx metadata. The system memory region in TdHob should be accepted before it can be accessed. So the newly added function (ProcessTdxHobList) is to process the TdHobList to accept the memory. Because TdHobList is provided by host VMM which is not trusted, so its content should be checked before it is consumed by TDVF. Because ProcessTdxHobList is to be called in SEC phase, so PlatformInitLib.inf is updated to support SEC. Note: In this patch it is BSP which accepts the pages. So there maybe boot performance issue. There are some mitigations to this issue, such as lazy accept, 2M accept page size, etc. We will re-visit here in the future. EFI_RESOURCE_MEMORY_UNACCEPTED is a new ResourceType in EFI_HOB_RESOURCE_DESCRIPTOR. It is defined for the unaccepted memory passed from Host VMM. This is proposed in microsoft/mu_basecore#66 files#diff-b20a11152d1ce9249c691be5690b4baf52069efadf2e2546cdd2eb663d80c9 e4R237 according to UEFI-Code-First. The proposal was approved in 2021 in UEFI Mantis, and will be added to the new PI.next specification. Per the MdePkg reviewer's comments, before this new ResourceType is added in the PI spec, it should not be in MdePkg. So it is now defined as an internal implementation and will be moved to MdePkg/Include/Pi/PiHob.h after it is added in PI spec. See https://edk2.groups.io/g/devel/message/87641 PcdTdxAcceptPageSize is added for page accepting. Currently TDX supports 4K and 2M accept page size. The default value is 2M. Tdx guest is only supported in X64. So for IA32 ProcessTdxHobList just returns EFI_UNSUPPORTED. Cc: Ard Biesheuvel <ardb+tianocore@kernel.org> Cc: Jordan Justen <jordan.l.justen@intel.com> Cc: Brijesh Singh <brijesh.singh@amd.com> Cc: Erdem Aktas <erdemaktas@google.com> Cc: James Bottomley <jejb@linux.ibm.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Tom Lendacky <thomas.lendacky@amd.com> Cc: Gerd Hoffmann <kraxel@redhat.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>
2022-02-16 06:32:13 +01:00
/**
Transfer the incoming HobList for the TD to the final HobList for Dxe.
The Hobs transferred in this function are ResourceDescriptor hob and
MemoryAllocation hob.
@param[in] VmmHobList The Hoblist pass the firmware
**/
VOID
EFIAPI
TransferTdxHobList (
VOID
)
{
EFI_PEI_HOB_POINTERS Hob;
EFI_RESOURCE_TYPE ResourceType;
EFI_RESOURCE_ATTRIBUTE_TYPE ResourceAttribute;
VOID *GuidedData;
OvmfPkg: Update PlatformInitLib to process Tdx hoblist RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429 When host VMM create the Td guest, the system memory informations are stored in TdHob, which is a memory region described in Tdx metadata. The system memory region in TdHob should be accepted before it can be accessed. So the newly added function (ProcessTdxHobList) is to process the TdHobList to accept the memory. Because TdHobList is provided by host VMM which is not trusted, so its content should be checked before it is consumed by TDVF. Because ProcessTdxHobList is to be called in SEC phase, so PlatformInitLib.inf is updated to support SEC. Note: In this patch it is BSP which accepts the pages. So there maybe boot performance issue. There are some mitigations to this issue, such as lazy accept, 2M accept page size, etc. We will re-visit here in the future. EFI_RESOURCE_MEMORY_UNACCEPTED is a new ResourceType in EFI_HOB_RESOURCE_DESCRIPTOR. It is defined for the unaccepted memory passed from Host VMM. This is proposed in microsoft/mu_basecore#66 files#diff-b20a11152d1ce9249c691be5690b4baf52069efadf2e2546cdd2eb663d80c9 e4R237 according to UEFI-Code-First. The proposal was approved in 2021 in UEFI Mantis, and will be added to the new PI.next specification. Per the MdePkg reviewer's comments, before this new ResourceType is added in the PI spec, it should not be in MdePkg. So it is now defined as an internal implementation and will be moved to MdePkg/Include/Pi/PiHob.h after it is added in PI spec. See https://edk2.groups.io/g/devel/message/87641 PcdTdxAcceptPageSize is added for page accepting. Currently TDX supports 4K and 2M accept page size. The default value is 2M. Tdx guest is only supported in X64. So for IA32 ProcessTdxHobList just returns EFI_UNSUPPORTED. Cc: Ard Biesheuvel <ardb+tianocore@kernel.org> Cc: Jordan Justen <jordan.l.justen@intel.com> Cc: Brijesh Singh <brijesh.singh@amd.com> Cc: Erdem Aktas <erdemaktas@google.com> Cc: James Bottomley <jejb@linux.ibm.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Tom Lendacky <thomas.lendacky@amd.com> Cc: Gerd Hoffmann <kraxel@redhat.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>
2022-02-16 06:32:13 +01:00
//
// PcdOvmfSecGhcbBase is used as the TD_HOB in Tdx guest.
//
Hob.Raw = (UINT8 *)(UINTN)FixedPcdGet32 (PcdOvmfSecGhcbBase);
while (!END_OF_HOB_LIST (Hob)) {
switch (Hob.Header->HobType) {
case EFI_HOB_TYPE_RESOURCE_DESCRIPTOR:
ResourceType = Hob.ResourceDescriptor->ResourceType;
ResourceAttribute = Hob.ResourceDescriptor->ResourceAttribute;
if (ResourceType == BZ3937_EFI_RESOURCE_MEMORY_UNACCEPTED) {
BuildResourceDescriptorHobForUnacceptedMemory (Hob.ResourceDescriptor);
} else {
BuildResourceDescriptorHob (
ResourceType,
ResourceAttribute,
Hob.ResourceDescriptor->PhysicalStart,
Hob.ResourceDescriptor->ResourceLength
);
OvmfPkg: Update PlatformInitLib to process Tdx hoblist RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429 When host VMM create the Td guest, the system memory informations are stored in TdHob, which is a memory region described in Tdx metadata. The system memory region in TdHob should be accepted before it can be accessed. So the newly added function (ProcessTdxHobList) is to process the TdHobList to accept the memory. Because TdHobList is provided by host VMM which is not trusted, so its content should be checked before it is consumed by TDVF. Because ProcessTdxHobList is to be called in SEC phase, so PlatformInitLib.inf is updated to support SEC. Note: In this patch it is BSP which accepts the pages. So there maybe boot performance issue. There are some mitigations to this issue, such as lazy accept, 2M accept page size, etc. We will re-visit here in the future. EFI_RESOURCE_MEMORY_UNACCEPTED is a new ResourceType in EFI_HOB_RESOURCE_DESCRIPTOR. It is defined for the unaccepted memory passed from Host VMM. This is proposed in microsoft/mu_basecore#66 files#diff-b20a11152d1ce9249c691be5690b4baf52069efadf2e2546cdd2eb663d80c9 e4R237 according to UEFI-Code-First. The proposal was approved in 2021 in UEFI Mantis, and will be added to the new PI.next specification. Per the MdePkg reviewer's comments, before this new ResourceType is added in the PI spec, it should not be in MdePkg. So it is now defined as an internal implementation and will be moved to MdePkg/Include/Pi/PiHob.h after it is added in PI spec. See https://edk2.groups.io/g/devel/message/87641 PcdTdxAcceptPageSize is added for page accepting. Currently TDX supports 4K and 2M accept page size. The default value is 2M. Tdx guest is only supported in X64. So for IA32 ProcessTdxHobList just returns EFI_UNSUPPORTED. Cc: Ard Biesheuvel <ardb+tianocore@kernel.org> Cc: Jordan Justen <jordan.l.justen@intel.com> Cc: Brijesh Singh <brijesh.singh@amd.com> Cc: Erdem Aktas <erdemaktas@google.com> Cc: James Bottomley <jejb@linux.ibm.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Tom Lendacky <thomas.lendacky@amd.com> Cc: Gerd Hoffmann <kraxel@redhat.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>
2022-02-16 06:32:13 +01:00
}
break;
case EFI_HOB_TYPE_MEMORY_ALLOCATION:
BuildMemoryAllocationHob (
Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress,
Hob.MemoryAllocation->AllocDescriptor.MemoryLength,
Hob.MemoryAllocation->AllocDescriptor.MemoryType
);
break;
case EFI_HOB_TYPE_GUID_EXTENSION:
GuidedData = (VOID *)(&Hob.Guid->Name + 1);
BuildGuidDataHob (&Hob.Guid->Name, GuidedData, Hob.Guid->Header.HobLength - sizeof (EFI_HOB_GUID_TYPE));
break;
OvmfPkg: Update PlatformInitLib to process Tdx hoblist RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429 When host VMM create the Td guest, the system memory informations are stored in TdHob, which is a memory region described in Tdx metadata. The system memory region in TdHob should be accepted before it can be accessed. So the newly added function (ProcessTdxHobList) is to process the TdHobList to accept the memory. Because TdHobList is provided by host VMM which is not trusted, so its content should be checked before it is consumed by TDVF. Because ProcessTdxHobList is to be called in SEC phase, so PlatformInitLib.inf is updated to support SEC. Note: In this patch it is BSP which accepts the pages. So there maybe boot performance issue. There are some mitigations to this issue, such as lazy accept, 2M accept page size, etc. We will re-visit here in the future. EFI_RESOURCE_MEMORY_UNACCEPTED is a new ResourceType in EFI_HOB_RESOURCE_DESCRIPTOR. It is defined for the unaccepted memory passed from Host VMM. This is proposed in microsoft/mu_basecore#66 files#diff-b20a11152d1ce9249c691be5690b4baf52069efadf2e2546cdd2eb663d80c9 e4R237 according to UEFI-Code-First. The proposal was approved in 2021 in UEFI Mantis, and will be added to the new PI.next specification. Per the MdePkg reviewer's comments, before this new ResourceType is added in the PI spec, it should not be in MdePkg. So it is now defined as an internal implementation and will be moved to MdePkg/Include/Pi/PiHob.h after it is added in PI spec. See https://edk2.groups.io/g/devel/message/87641 PcdTdxAcceptPageSize is added for page accepting. Currently TDX supports 4K and 2M accept page size. The default value is 2M. Tdx guest is only supported in X64. So for IA32 ProcessTdxHobList just returns EFI_UNSUPPORTED. Cc: Ard Biesheuvel <ardb+tianocore@kernel.org> Cc: Jordan Justen <jordan.l.justen@intel.com> Cc: Brijesh Singh <brijesh.singh@amd.com> Cc: Erdem Aktas <erdemaktas@google.com> Cc: James Bottomley <jejb@linux.ibm.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Tom Lendacky <thomas.lendacky@amd.com> Cc: Gerd Hoffmann <kraxel@redhat.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>
2022-02-16 06:32:13 +01:00
}
Hob.Raw = GET_NEXT_HOB (Hob);
}
}
OvmfPkg: Update PlatformInitLib for Tdx guest RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429 There are below changes in PlatformInitLib for Tdx guest: 1. Publish ram regions In Tdx guest, the system memory is passed in TdHob by host VMM. So the major task of PlatformTdxPublishRamRegions is to walk thru the TdHob list and transfer the ResourceDescriptorHob and MemoryAllocationHob to the hobs in DXE phase. 2. Build MemoryAllocationHob for Tdx Mailbox and Ovmf work area. 3. Update of PlatformAddressWidthInitialization. The physical address width that Tdx guest supports is either 48 or 52. 4. Update of PlatformMemMapInitialization. 0xA0000 - 0xFFFFF is VGA bios region. Platform initialization marks the region as MMIO region. Dxe code maps MMIO region as IO region. As TDX guest, MMIO region is maps as shared. However VGA BIOS doesn't need to be shared. Guest TDX Linux maps VGA BIOS as private and accesses for BIOS and stuck on repeating EPT violation. VGA BIOS (more generally ROM region) should be private. Skip marking VGA BIOA region [0xa000, 0xfffff] as MMIO in HOB. Cc: Ard Biesheuvel <ardb+tianocore@kernel.org> Cc: Jordan Justen <jordan.l.justen@intel.com> Cc: Brijesh Singh <brijesh.singh@amd.com> Cc: Erdem Aktas <erdemaktas@google.com> Cc: James Bottomley <jejb@linux.ibm.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Tom Lendacky <thomas.lendacky@amd.com> Cc: Gerd Hoffmann <kraxel@redhat.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>
2022-02-16 06:42:55 +01:00
/**
In Tdx guest, the system memory is passed in TdHob by host VMM. So
the major task of PlatformTdxPublishRamRegions is to walk thru the
TdHob list and transfer the ResourceDescriptorHob and MemoryAllocationHob
to the hobs in DXE phase.
MemoryAllocationHob should also be created for Mailbox and Ovmf work area.
**/
VOID
EFIAPI
PlatformTdxPublishRamRegions (
VOID
)
{
if (!TdIsEnabled ()) {
return;
}
TransferTdxHobList ();
//
// The memory region defined by PcdOvmfSecGhcbBackupBase is pre-allocated by
// host VMM and used as the td mailbox at the beginning of system boot.
//
BuildMemoryAllocationHob (
FixedPcdGet32 (PcdOvmfSecGhcbBackupBase),
FixedPcdGet32 (PcdOvmfSecGhcbBackupSize),
EfiACPIMemoryNVS
);
if (FixedPcdGet32 (PcdOvmfWorkAreaSize) != 0) {
//
// Reserve the work area.
//
// Since this memory range will be used by the Reset Vector on S3
// resume, it must be reserved as ACPI NVS.
//
// If S3 is unsupported, then various drivers might still write to the
// work area. We ought to prevent DXE from serving allocation requests
// such that they would overlap the work area.
//
BuildMemoryAllocationHob (
(EFI_PHYSICAL_ADDRESS)(UINTN)FixedPcdGet32 (PcdOvmfWorkAreaBase),
(UINT64)(UINTN)FixedPcdGet32 (PcdOvmfWorkAreaSize),
EfiBootServicesData
);
}
}