Date   

[PATCH V6 29/42] OvmfPkg: Check Tdx in QemuFwCfgPei to avoid DMA operation

Min Xu
 

RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429

If TDX is enabled then we do not support DMA operation in PEI phase.
This is mainly because DMA in TDX guest requires using bounce buffer
(which need to allocate dynamic memory and allocating a PAGE size'd
buffer can be challenge in PEI phase).

Cc: Ard Biesheuvel <ardb+tianocore@...>
Cc: Jordan Justen <jordan.l.justen@...>
Cc: Brijesh Singh <brijesh.singh@...>
Cc: Erdem Aktas <erdemaktas@...>
Cc: James Bottomley <jejb@...>
Cc: Jiewen Yao <jiewen.yao@...>
Cc: Tom Lendacky <thomas.lendacky@...>
Cc: Gerd Hoffmann <kraxel@...>
Acked-by: Gerd Hoffmann <kraxel@...>
Signed-off-by: Min Xu <min.m.xu@...>
---
.../QemuFwCfgLib/QemuFwCfgLibInternal.h | 11 +++++++
OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPei.c | 32 +++++++++++++++++++
.../Library/QemuFwCfgLib/QemuFwCfgPeiLib.inf | 2 ++
3 files changed, 45 insertions(+)

diff --git a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibInternal.h b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibInternal.h
index 0b77cad1c030..6f7beb6ac1c7 100644
--- a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibInternal.h
+++ b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibInternal.h
@@ -59,4 +59,15 @@ InternalQemuFwCfgDmaBytes (
IN UINT32 Control
);

+/**
+ Check if it is Tdx guest
+
+ @retval TRUE It is Tdx guest
+ @retval FALSE It is not Tdx guest
+**/
+BOOLEAN
+QemuFwCfgIsTdxGuest (
+ VOID
+ );
+
#endif
diff --git a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPei.c b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPei.c
index f696fb7cacaa..b8230613dcea 100644
--- a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPei.c
+++ b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPei.c
@@ -14,12 +14,30 @@
#include <Library/DebugLib.h>
#include <Library/QemuFwCfgLib.h>
#include <Library/MemEncryptSevLib.h>
+#include <WorkArea.h>

#include "QemuFwCfgLibInternal.h"

STATIC BOOLEAN mQemuFwCfgSupported = FALSE;
STATIC BOOLEAN mQemuFwCfgDmaSupported;

+/**
+ Check if it is Tdx guest
+
+ @retval TRUE It is Tdx guest
+ @retval FALSE It is not Tdx guest
+**/
+BOOLEAN
+QemuFwCfgIsTdxGuest (
+ VOID
+ )
+{
+ CONFIDENTIAL_COMPUTING_WORK_AREA_HEADER *CcWorkAreaHeader;
+
+ CcWorkAreaHeader = (CONFIDENTIAL_COMPUTING_WORK_AREA_HEADER *)FixedPcdGet32 (PcdOvmfWorkAreaBase);
+ return (CcWorkAreaHeader != NULL && CcWorkAreaHeader->GuestType == GUEST_TYPE_INTEL_TDX);
+}
+
/**
Returns a boolean indicating if the firmware configuration interface
is available or not.
@@ -81,6 +99,14 @@ QemuFwCfgInitialize (
//
if (MemEncryptSevIsEnabled ()) {
DEBUG ((DEBUG_INFO, "SEV: QemuFwCfg fallback to IO Port interface.\n"));
+ } else if (QemuFwCfgIsTdxGuest ()) {
+ //
+ // If TDX is enabled then we do not support DMA operations in PEI phase.
+ // This is mainly because DMA in TDX guest requires using bounce buffer
+ // (which need to allocate dynamic memory and allocating a PAGE size'd
+ // buffer can be challenge in PEI phase)
+ //
+ DEBUG ((DEBUG_INFO, "TDX: QemuFwCfg fallback to IO Port interface.\n"));
} else {
mQemuFwCfgDmaSupported = TRUE;
DEBUG ((DEBUG_INFO, "QemuFwCfg interface (DMA) is supported.\n"));
@@ -163,6 +189,12 @@ InternalQemuFwCfgDmaBytes (
//
ASSERT (!MemEncryptSevIsEnabled ());

+ //
+ // TDX does not support DMA operations in PEI stage, we should
+ // not have reached here.
+ //
+ ASSERT (!QemuFwCfgIsTdxGuest ());
+
Access.Control = SwapBytes32 (Control);
Access.Length = SwapBytes32 (Size);
Access.Address = SwapBytes64 ((UINTN)Buffer);
diff --git a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPeiLib.inf b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPeiLib.inf
index 9f9af7d03201..3910511880c9 100644
--- a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPeiLib.inf
+++ b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPeiLib.inf
@@ -43,3 +43,5 @@
MemoryAllocationLib
MemEncryptSevLib

+[Pcd]
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfWorkAreaBase
--
2.29.2.windows.2


[PATCH V6 27/42] OvmfPkg/Sec: Declare local variable as volatile in SecCoreStartupWithStack

Min Xu
 

RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429

Declare the local variables in SecCoreStartupWithStack that actually
move the data elements as volatile to prevent the optimizer from
replacing this function with the intrinsic memcpy().

Cc: Ard Biesheuvel <ardb+tianocore@...>
Cc: Jordan Justen <jordan.l.justen@...>
Cc: Brijesh Singh <brijesh.singh@...>
Cc: Erdem Aktas <erdemaktas@...>
Cc: James Bottomley <jejb@...>
Cc: Jiewen Yao <jiewen.yao@...>
Cc: Tom Lendacky <thomas.lendacky@...>
Cc: Gerd Hoffmann <kraxel@...>
Signed-off-by: Min Xu <min.m.xu@...>
---
OvmfPkg/Sec/SecMain.c | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/OvmfPkg/Sec/SecMain.c b/OvmfPkg/Sec/SecMain.c
index 2c5561661ef3..02520e25ab9a 100644
--- a/OvmfPkg/Sec/SecMain.c
+++ b/OvmfPkg/Sec/SecMain.c
@@ -757,12 +757,17 @@ SecCoreStartupWithStack (
//
IdtTableInStack.PeiService = NULL;
for (Index = 0; Index < SEC_IDT_ENTRY_COUNT; Index++) {
- UINT8 *Src;
- UINT8 *Dst;
- UINTN Byte;
+ //
+ // Declare the local variables that actually move the data elements as
+ // volatile to prevent the optimizer from replacing this function with
+ // the intrinsic memcpy()
+ //
+ CONST UINT8 *Src;
+ volatile UINT8 *Dst;
+ UINTN Byte;

- Src = (UINT8 *)&mIdtEntryTemplate;
- Dst = (UINT8 *)&IdtTableInStack.IdtTable[Index];
+ Src = (CONST UINT8 *)&mIdtEntryTemplate;
+ Dst = (volatile UINT8 *)&IdtTableInStack.IdtTable[Index];
for (Byte = 0; Byte < sizeof (mIdtEntryTemplate); Byte++) {
Dst[Byte] = Src[Byte];
}
--
2.29.2.windows.2


[PATCH V6 26/42] OvmfPkg: Add null instance of PlatformInitLib

Min Xu
 

RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429

Add null instance of PlatformInitLib.

Cc: Ard Biesheuvel <ardb+tianocore@...>
Cc: Jordan Justen <jordan.l.justen@...>
Cc: Brijesh Singh <brijesh.singh@...>
Cc: Erdem Aktas <erdemaktas@...>
Cc: James Bottomley <jejb@...>
Cc: Jiewen Yao <jiewen.yao@...>
Cc: Tom Lendacky <thomas.lendacky@...>
Cc: Gerd Hoffmann <kraxel@...>
Signed-off-by: Min Xu <min.m.xu@...>
---
.../PlatformInitLib/PlatformInitLibNull.c | 310 ++++++++++++++++++
.../PlatformInitLib/PlatformInitLibNull.inf | 34 ++
2 files changed, 344 insertions(+)
create mode 100644 OvmfPkg/Library/PlatformInitLib/PlatformInitLibNull.c
create mode 100644 OvmfPkg/Library/PlatformInitLib/PlatformInitLibNull.inf

diff --git a/OvmfPkg/Library/PlatformInitLib/PlatformInitLibNull.c b/OvmfPkg/Library/PlatformInitLib/PlatformInitLibNull.c
new file mode 100644
index 000000000000..dba4ed33a9dc
--- /dev/null
+++ b/OvmfPkg/Library/PlatformInitLib/PlatformInitLibNull.c
@@ -0,0 +1,310 @@
+/** @file
+ Null instance of Platform Initialization Lib
+
+ This module provides platform specific function to detect boot mode.
+ Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Base.h>
+#include <Uefi.h>
+#include <Library/PlatformInitLib.h>
+
+/**
+ Reads 8-bits of CMOS data.
+
+ Reads the 8-bits of CMOS data at the location specified by Index.
+ The 8-bit read value is returned.
+
+ @param Index The CMOS location to read.
+
+ @return The value read.
+
+**/
+UINT8
+EFIAPI
+PlatformCmosRead8 (
+ IN UINTN Index
+ )
+{
+ return 0;
+}
+
+/**
+ Writes 8-bits of CMOS data.
+
+ Writes 8-bits of CMOS data to the location specified by Index
+ with the value specified by Value and returns Value.
+
+ @param Index The CMOS location to write.
+ @param Value The value to write to CMOS.
+
+ @return The value written to CMOS.
+
+**/
+UINT8
+EFIAPI
+PlatformCmosWrite8 (
+ IN UINTN Index,
+ IN UINT8 Value
+ )
+{
+ return 0;
+}
+
+/**
+ Dump the CMOS content
+ */
+VOID
+EFIAPI
+PlatformDebugDumpCmos (
+ VOID
+ )
+{
+}
+
+/**
+ * Return the highest address that DXE could possibly use, plus one.
+ *
+ * @param Pci64Base The 64-bit PCI host aperture base address.
+ * @param Pci64Size The 64-bit PCI host aperture size.
+ * @param DefaultPciMmio64Size The default 64-bit PCI host aperture size.
+ *
+ * @return The highest address that DXE could possibly use, plus one.
+ */
+UINT64
+EFIAPI
+PlatformGetFirstNonAddress (
+ OUT UINT64 *Pci64Base,
+ OUT UINT64 *Pci64Size,
+ IN UINT64 DefaultPciMmio64Size
+ )
+{
+ return 0;
+}
+
+/**
+ * Initialize the PhysMemAddressWidth variable, based on guest RAM size.
+ *
+ * @param FirstNonAddress The highest address that DXE could possibly use, plus one.
+ *
+ * @return The physical memory address width based on the guest RAM size.
+ */
+UINT8
+EFIAPI
+PlatformAddressWidthInitialization (
+ IN UINT64 FirstNonAddress
+ )
+{
+ return 0;
+}
+
+/**
+ * Get the memory size below 4GB.
+ *
+ * @return UINT32 The lower memory size.
+ */
+UINT32
+EFIAPI
+PlatformGetSystemMemorySizeBelow4gb (
+ VOID
+ )
+{
+ return 0;
+}
+
+/**
+ * Initializatoin of Qemu UC32Base.
+ *
+ * @param HostBridgeDevId The host bridge Dev Id.
+ * @param LowerMemorySize The lower memory size (under 4G).
+ * @return UINT32 The Qemu UC32 base address.
+ */
+UINT32
+EFIAPI
+PlatformQemuUc32BaseInitialization (
+ IN UINT16 HostBridgeDevId,
+ IN UINT32 LowerMemorySize
+ )
+{
+ return 0;
+}
+
+/**
+ * Query Host Bridge Dev Id.
+ *
+ * @return Host Bridge Dev Id.
+ */
+UINT16
+EFIAPI
+PlatformQueryHostBridgeDid (
+ VOID
+ )
+{
+ return 0;
+}
+
+/**
+ Fetch the boot CPU count and the possible CPU count from QEMU.
+
+ @param HostBridgeDevId The Host bridge Dev Id.
+ @param DefaultMaxCpuCount The default max cpu count.
+ @param MaxCpuCount The pointer to the returned max cpu count.
+ @param BootCpuCount The pointer to the returned boot cpu count.
+**/
+VOID
+EFIAPI
+PlatformMaxCpuCountInitialization (
+ IN UINT16 HostBridgeDevId,
+ IN UINT32 DefaultMaxCpuCount,
+ OUT UINT32 *MaxCpuCount,
+ OUT UINT16 *BootCpuCount
+ )
+{
+}
+
+/**
+ * Initialize the Memory Map IO hobs.
+ *
+ * @param HostBridgeDevId The host bridge Dev Id.
+ * @param Uc32Base The Qemu Uc32Base address.
+ * @param PciBase The pointer to the Pci base address.
+ * @param PciSize The pointer to the Pci base size.
+ * @param PciIoBase The pointer to the Pci Io base address.
+ * @param PciIoSize The pointer to the Pci Io size.
+ */
+VOID
+EFIAPI
+PlatformMemMapInitialization (
+ IN UINT16 HostBridgeDevId,
+ IN UINT32 Uc32Base,
+ OUT UINT32 *PciBase,
+ OUT UINT32 *PciSize,
+ OUT UINT64 *PciIoBase,
+ OUT UINT64 *PciIoSize
+ )
+{
+}
+
+/**
+ * Fetch "opt/ovmf/PcdSetNxForStack" from QEMU
+ *
+ * @param Setting The pointer to the setting of "/opt/ovmf/PcdSetNxForStack".
+ * @return EFI_SUCCESS Successfully fetch the settings.
+ */
+EFI_STATUS
+EFIAPI
+PlatformNoexecDxeInitialization (
+ OUT BOOLEAN *Setting
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ * Misc initialization, such as Disable A20 Mask, Build CPU Hob,
+ * PM settings, Set PCI Express Register Range Base Address.
+ *
+ * @param HostBridgeDevId The host bridge Dev id.
+ * @param PhysMemAddressWidth The physical memory address width.
+ */
+VOID
+EFIAPI
+PlatformMiscInitialization (
+ IN UINT16 HostBridgeDevId,
+ IN UINT8 PhysMemAddressWidth
+ )
+{
+}
+
+/**
+ Publish system RAM and reserve memory regions.
+
+ @param Uc32Base
+ @param HostBridgeDevId
+ @param SmmSmramRequire
+ @param BootMode
+ @param S3Supported
+ @param LowerMemorySize
+ @param Q35TsegMbytes
+**/
+VOID
+EFIAPI
+PlatformInitializeRamRegions (
+ IN UINT32 Uc32Base,
+ IN UINT16 HostBridgeDevId,
+ IN BOOLEAN SmmSmramRequire,
+ IN EFI_BOOT_MODE BootMode,
+ IN BOOLEAN S3Supported,
+ IN UINT32 LowerMemorySize,
+ IN UINT16 Q35TsegMbytes
+ )
+{
+}
+
+VOID
+EFIAPI
+PlatformAddIoMemoryBaseSizeHob (
+ IN EFI_PHYSICAL_ADDRESS MemoryBase,
+ IN UINT64 MemorySize
+ )
+{
+}
+
+VOID
+EFIAPI
+PlatformAddIoMemoryRangeHob (
+ IN EFI_PHYSICAL_ADDRESS MemoryBase,
+ IN EFI_PHYSICAL_ADDRESS MemoryLimit
+ )
+{
+}
+
+VOID
+EFIAPI
+PlatformAddMemoryBaseSizeHob (
+ IN EFI_PHYSICAL_ADDRESS MemoryBase,
+ IN UINT64 MemorySize
+ )
+{
+}
+
+VOID
+EFIAPI
+PlatformAddMemoryRangeHob (
+ IN EFI_PHYSICAL_ADDRESS MemoryBase,
+ IN EFI_PHYSICAL_ADDRESS MemoryLimit
+ )
+{
+}
+
+VOID
+EFIAPI
+PlatformAddReservedMemoryBaseSizeHob (
+ IN EFI_PHYSICAL_ADDRESS MemoryBase,
+ IN UINT64 MemorySize,
+ IN BOOLEAN Cacheable
+ )
+{
+}
+
+/**
+ 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;
+}
diff --git a/OvmfPkg/Library/PlatformInitLib/PlatformInitLibNull.inf b/OvmfPkg/Library/PlatformInitLib/PlatformInitLibNull.inf
new file mode 100644
index 000000000000..09d4938889fc
--- /dev/null
+++ b/OvmfPkg/Library/PlatformInitLib/PlatformInitLibNull.inf
@@ -0,0 +1,34 @@
+## @file
+# Null instance of Platform Initialization Lib
+#
+# This module provides platform specific function to detect boot mode.
+# Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PlatformInitLibNull
+ FILE_GUID = 048e3e29-a025-4d87-9e64-d5d8c9dbf757
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PlatformInitLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ PlatformInitLibNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ OvmfPkg/OvmfPkg.dec
+
+[LibraryClasses]
+ BaseLib
--
2.29.2.windows.2


[PATCH V6 25/42] OvmfPkg: Update PlatformInitLib to process Tdx hoblist

Min Xu
 

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.

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@...>
Cc: Jordan Justen <jordan.l.justen@...>
Cc: Brijesh Singh <brijesh.singh@...>
Cc: Erdem Aktas <erdemaktas@...>
Cc: James Bottomley <jejb@...>
Cc: Jiewen Yao <jiewen.yao@...>
Cc: Tom Lendacky <thomas.lendacky@...>
Cc: Gerd Hoffmann <kraxel@...>
Signed-off-by: Min Xu <min.m.xu@...>
---
OvmfPkg/Include/Library/PlatformInitLib.h | 17 +
OvmfPkg/Library/PlatformInitLib/IntelTdx.c | 504 ++++++++++++++++++
.../Library/PlatformInitLib/IntelTdxNull.c | 30 ++
.../PlatformInitLib/PlatformInitLib.inf | 13 +-
OvmfPkg/OvmfPkg.dec | 3 +
5 files changed, 566 insertions(+), 1 deletion(-)
create mode 100644 OvmfPkg/Library/PlatformInitLib/IntelTdx.c
create mode 100644 OvmfPkg/Library/PlatformInitLib/IntelTdxNull.c

diff --git a/OvmfPkg/Include/Library/PlatformInitLib.h b/OvmfPkg/Include/Library/PlatformInitLib.h
index dd108b3a4339..538fd7aee48c 100644
--- a/OvmfPkg/Include/Library/PlatformInitLib.h
+++ b/OvmfPkg/Include/Library/PlatformInitLib.h
@@ -252,4 +252,21 @@ PlatformAddReservedMemoryBaseSizeHob (
IN BOOLEAN Cacheable
);

+/**
+ 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
+ );
+
#endif // PLATFORM_INIT_LIB_H_
diff --git a/OvmfPkg/Library/PlatformInitLib/IntelTdx.c b/OvmfPkg/Library/PlatformInitLib/IntelTdx.c
new file mode 100644
index 000000000000..1ee24dfe754d
--- /dev/null
+++ b/OvmfPkg/Library/PlatformInitLib/IntelTdx.c
@@ -0,0 +1,504 @@
+/** @file
+ Initialize Intel TDX support.
+
+ Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#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>
+#include <Library/SynchronizationLib.h>
+#include <WorkArea.h>
+#include <ConfidentialComputingGuestAttr.h>
+
+#define ALIGNED_2MB_MASK 0x1fffff
+
+/**
+ 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;
+ }
+
+ DEBUG ((DEBUG_INFO, "TdAccept: 0x%llx - 0x%llx\n", PhysicalAddress, TotalLength));
+
+ 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;
+ }
+
+ DEBUG ((DEBUG_INFO, " Part1: 0x%llx - 0x%llx\n", StartAddress1, Length1));
+ DEBUG ((DEBUG_INFO, " Part2: 0x%llx - 0x%llx\n", StartAddress2, Length2));
+ DEBUG ((DEBUG_INFO, " Part3: 0x%llx - 0x%llx\n", StartAddress3, Length3));
+ DEBUG ((DEBUG_INFO, " Page : 0x%x\n", AcceptPageSize));
+
+ 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;
+}
+
+/**
+ 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[12] = {
+ 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[8] = {
+ 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,
+ EFI_RESOURCE_MAX_MEMORY_TYPE
+ };
+
+ 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, 12) == 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, 8) == 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 |
+ EFI_RESOURCE_ATTRIBUTE_ENCRYPTED))) != 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;
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_PHYSICAL_ADDRESS PhysicalEnd;
+
+ Status = EFI_SUCCESS;
+ ASSERT (VmmHobList != NULL);
+ 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->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
+ DEBUG ((DEBUG_INFO, "\nResourceType: 0x%x\n", Hob.ResourceDescriptor->ResourceType));
+
+ if (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) {
+ 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));
+
+ PhysicalEnd = Hob.ResourceDescriptor->PhysicalStart + Hob.ResourceDescriptor->ResourceLength;
+
+ Status = BspAcceptMemoryResourceRange (
+ Hob.ResourceDescriptor->PhysicalStart,
+ PhysicalEnd
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+ }
+
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ }
+
+ 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;
+}
+
+/**
+ 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;
+
+ //
+ // 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:
+ BuildResourceDescriptorHob (
+ Hob.ResourceDescriptor->ResourceType,
+ Hob.ResourceDescriptor->ResourceAttribute,
+ Hob.ResourceDescriptor->PhysicalStart,
+ Hob.ResourceDescriptor->ResourceLength
+ );
+ break;
+ case EFI_HOB_TYPE_MEMORY_ALLOCATION:
+ BuildMemoryAllocationHob (
+ Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress,
+ Hob.MemoryAllocation->AllocDescriptor.MemoryLength,
+ Hob.MemoryAllocation->AllocDescriptor.MemoryType
+ );
+ break;
+ }
+
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ }
+}
diff --git a/OvmfPkg/Library/PlatformInitLib/IntelTdxNull.c b/OvmfPkg/Library/PlatformInitLib/IntelTdxNull.c
new file mode 100644
index 000000000000..af90e0866e89
--- /dev/null
+++ b/OvmfPkg/Library/PlatformInitLib/IntelTdxNull.c
@@ -0,0 +1,30 @@
+/** @file
+ Initialize Intel TDX support.
+
+ Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#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;
+}
diff --git a/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf b/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
index a42b54805ba6..264250e56b5c 100644
--- a/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
+++ b/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
@@ -14,7 +14,7 @@
FILE_GUID = 89f886b0-7109-46e1-9d28-503ad4ab6ee0
MODULE_TYPE = BASE
VERSION_STRING = 1.0
- LIBRARY_CLASS = PlatformInitLib|PEIM
+ LIBRARY_CLASS = PlatformInitLib|SEC PEIM

#
# The following information is for reference only and not required by the build tools.
@@ -27,6 +27,12 @@
MemDetect.c
Platform.c

+[Sources.IA32]
+ IntelTdxNull.c
+
+[Sources.X64]
+ IntelTdx.c
+
[Packages]
EmbeddedPkg/EmbeddedPkg.dec
MdeModulePkg/MdeModulePkg.dec
@@ -45,6 +51,9 @@
PcdLib
PciLib

+[LibraryClasses.X64]
+ TdxLib
+
[FixedPcd]
gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfWorkAreaBase
@@ -79,5 +88,7 @@
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
gUefiCpuPkgTokenSpaceGuid.PcdCpuLocalApicBaseAddress

+ gUefiOvmfPkgTokenSpaceGuid.PcdTdxAcceptPageSize
+
[FeaturePcd]
gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode
diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index 61635c73c761..f3d06411b51b 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -377,6 +377,9 @@
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecValidatedStart|0|UINT32|0x62
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecValidatedEnd|0|UINT32|0x63

+ ## The Tdx accept page size. 0x1000(4k),0x200000(2M)
+ gUefiOvmfPkgTokenSpaceGuid.PcdTdxAcceptPageSize|0x200000|UINT32|0x65
+
[PcdsDynamic, PcdsDynamicEx]
gUefiOvmfPkgTokenSpaceGuid.PcdEmuVariableEvent|0|UINT64|2
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashVariablesEnable|FALSE|BOOLEAN|0x10
--
2.29.2.windows.2


[PATCH V6 23/42] OvmfPkg/PlatformInitLib: Add platform functions

Min Xu
 

RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429

Below platform functions are introducted in PlatformInitLib:
- PlatformMaxCpuCountInitialization
- PlatformMemMapInitialization
- PlatformNoexecDxeInitialization
- PlatformMiscInitialization

They correspond to the below functions in OvmfPkg/PlatformPei:
- MaxCpuCountInitialization
- MemMapInitialization
- MiscInitialization
- NoexecDxeInitialization

QueryHostBridgeDid is a newly added function.

Cc: Ard Biesheuvel <ardb+tianocore@...>
Cc: Jordan Justen <jordan.l.justen@...>
Cc: Brijesh Singh <brijesh.singh@...>
Cc: Erdem Aktas <erdemaktas@...>
Cc: James Bottomley <jejb@...>
Cc: Jiewen Yao <jiewen.yao@...>
Cc: Tom Lendacky <thomas.lendacky@...>
Cc: Gerd Hoffmann <kraxel@...>
Signed-off-by: Min Xu <min.m.xu@...>
---
OvmfPkg/Include/Library/PlatformInitLib.h | 75 +++
OvmfPkg/Library/PlatformInitLib/Platform.c | 491 ++++++++++++++++++
.../PlatformInitLib/PlatformInitLib.inf | 29 ++
3 files changed, 595 insertions(+)

diff --git a/OvmfPkg/Include/Library/PlatformInitLib.h b/OvmfPkg/Include/Library/PlatformInitLib.h
index df2646880909..dd108b3a4339 100644
--- a/OvmfPkg/Include/Library/PlatformInitLib.h
+++ b/OvmfPkg/Include/Library/PlatformInitLib.h
@@ -118,6 +118,81 @@ PlatformQemuUc32BaseInitialization (
IN UINT32 LowerMemorySize
);

+/**
+ * Query Host Bridge Dev Id.
+ *
+ * @return Host Bridge Dev Id.
+ */
+UINT16
+EFIAPI
+PlatformQueryHostBridgeDid (
+ VOID
+ );
+
+/**
+ Fetch the boot CPU count and the possible CPU count from QEMU.
+
+ @param HostBridgeDevId The Host bridge Dev Id.
+ @param DefaultMaxCpuCount The default max cpu count.
+ @param MaxCpuCount The pointer to the returned max cpu count.
+ @param BootCpuCount The pointer to the returned boot cpu count.
+**/
+VOID
+EFIAPI
+PlatformMaxCpuCountInitialization (
+ IN UINT16 HostBridgeDevId,
+ IN UINT32 DefaultMaxCpuCount,
+ OUT UINT32 *MaxCpuCount,
+ OUT UINT16 *BootCpuCount
+ );
+
+/**
+ * Initialize the Memory Map IO hobs.
+ *
+ * @param HostBridgeDevId The host bridge Dev Id.
+ * @param Uc32Base The Qemu Uc32Base address.
+ * @param PciBase The pointer to the Pci base address.
+ * @param PciSize The pointer to the Pci base size.
+ * @param PciIoBase The pointer to the Pci Io base address.
+ * @param PciIoSize The pointer to the Pci Io size.
+ */
+VOID
+EFIAPI
+PlatformMemMapInitialization (
+ IN UINT16 HostBridgeDevId,
+ IN UINT32 Uc32Base,
+ OUT UINT32 *PciBase,
+ OUT UINT32 *PciSize,
+ OUT UINT64 *PciIoBase,
+ OUT UINT64 *PciIoSize
+ );
+
+/**
+ * Fetch "opt/ovmf/PcdSetNxForStack" from QEMU
+ *
+ * @param Setting The pointer to the setting of "/opt/ovmf/PcdSetNxForStack".
+ * @return EFI_SUCCESS Successfully fetch the settings.
+ */
+EFI_STATUS
+EFIAPI
+PlatformNoexecDxeInitialization (
+ OUT BOOLEAN *Setting
+ );
+
+/**
+ * Misc initialization, such as Disable A20 Mask, Build CPU Hob,
+ * PM settings, Set PCI Express Register Range Base Address.
+ *
+ * @param HostBridgeDevId The host bridge Dev id.
+ * @param PhysMemAddressWidth The physical memory address width.
+ */
+VOID
+EFIAPI
+PlatformMiscInitialization (
+ IN UINT16 HostBridgeDevId,
+ IN UINT8 PhysMemAddressWidth
+ );
+
/**
Publish system RAM and reserve memory regions.

diff --git a/OvmfPkg/Library/PlatformInitLib/Platform.c b/OvmfPkg/Library/PlatformInitLib/Platform.c
index e41f230ff563..308a64f6558b 100644
--- a/OvmfPkg/Library/PlatformInitLib/Platform.c
+++ b/OvmfPkg/Library/PlatformInitLib/Platform.c
@@ -19,6 +19,21 @@
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include <Library/HobLib.h>
+#include <Library/IoLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PciLib.h>
+#include <Library/QemuFwCfgLib.h>
+#include <Library/QemuFwCfgS3Lib.h>
+#include <Library/QemuFwCfgSimpleParserLib.h>
+#include <Library/ResourcePublicationLib.h>
+#include <Ppi/MasterBootMode.h>
+#include <IndustryStandard/I440FxPiix4.h>
+#include <IndustryStandard/Microvm.h>
+#include <IndustryStandard/Pci22.h>
+#include <IndustryStandard/Q35MchIch9.h>
+#include <IndustryStandard/QemuCpuHotplug.h>
+#include <OvmfPlatforms.h>
#include <Library/PlatformInitLib.h>

VOID
@@ -104,3 +119,479 @@ PlatformAddMemoryRangeHob (
{
PlatformAddMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase));
}
+
+/**
+ * Initialize the Memory Map IO hobs.
+ *
+ * @param HostBridgeDevId The host bridge Dev Id.
+ * @param Uc32Base The Qemu Uc32Base address.
+ * @param PciBase The pointer to the Pci base address.
+ * @param PciSize The pointer to the Pci base size.
+ * @param PciIoBase The pointer to the Pci Io base address.
+ * @param PciIoSize The pointer to the Pci Io size.
+ */
+VOID
+EFIAPI
+PlatformMemMapInitialization (
+ UINT16 HostBridgeDevId,
+ UINT32 Uc32Base,
+ UINT32 *PciBase,
+ UINT32 *PciSize,
+ UINT64 *PciIoBase,
+ UINT64 *PciIoSize
+ )
+{
+ UINT32 TopOfLowRam;
+ UINT64 PciExBarBase;
+
+ *PciIoBase = 0xC000;
+ *PciIoSize = 0x4000;
+ *PciBase = 0;
+ *PciSize = 0;
+
+ //
+ // Video memory + Legacy BIOS region
+ //
+ PlatformAddIoMemoryRangeHob (0x0A0000, BASE_1MB);
+
+ if (HostBridgeDevId == 0xffff /* microvm */) {
+ PlatformAddIoMemoryBaseSizeHob (MICROVM_GED_MMIO_BASE, SIZE_4KB);
+ PlatformAddIoMemoryBaseSizeHob (0xFEC00000, SIZE_4KB); /* ioapic #1 */
+ PlatformAddIoMemoryBaseSizeHob (0xFEC10000, SIZE_4KB); /* ioapic #2 */
+ return;
+ }
+
+ TopOfLowRam = PlatformGetSystemMemorySizeBelow4gb ();
+ PciExBarBase = 0;
+ if (HostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
+ //
+ // The MMCONFIG area is expected to fall between the top of low RAM and
+ // the base of the 32-bit PCI host aperture.
+ //
+ PciExBarBase = FixedPcdGet64 (PcdPciExpressBaseAddress);
+ ASSERT (TopOfLowRam <= PciExBarBase);
+ ASSERT (PciExBarBase <= MAX_UINT32 - SIZE_256MB);
+ *PciBase = (UINT32)(PciExBarBase + SIZE_256MB);
+ } else {
+ ASSERT (TopOfLowRam <= Uc32Base);
+ *PciBase = Uc32Base;
+ }
+
+ //
+ // address purpose size
+ // ------------ -------- -------------------------
+ // max(top, 2g) PCI MMIO 0xFC000000 - max(top, 2g)
+ // 0xFC000000 gap 44 MB
+ // 0xFEC00000 IO-APIC 4 KB
+ // 0xFEC01000 gap 1020 KB
+ // 0xFED00000 HPET 1 KB
+ // 0xFED00400 gap 111 KB
+ // 0xFED1C000 gap (PIIX4) / RCRB (ICH9) 16 KB
+ // 0xFED20000 gap 896 KB
+ // 0xFEE00000 LAPIC 1 MB
+ //
+ *PciSize = 0xFC000000 - *PciBase;
+ PlatformAddIoMemoryBaseSizeHob (*PciBase, *PciSize);
+
+ PlatformAddIoMemoryBaseSizeHob (0xFEC00000, SIZE_4KB);
+ PlatformAddIoMemoryBaseSizeHob (0xFED00000, SIZE_1KB);
+ if (HostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
+ PlatformAddIoMemoryBaseSizeHob (ICH9_ROOT_COMPLEX_BASE, SIZE_16KB);
+ //
+ // Note: there should be an
+ //
+ // AddIoMemoryBaseSizeHob (PciExBarBase, SIZE_256MB);
+ //
+ // call below, just like the one above for RCBA. However, Linux insists
+ // that the MMCONFIG area be marked in the E820 or UEFI memory map as
+ // "reserved memory" -- Linux does not content itself with a simple gap
+ // in the memory map wherever the MCFG ACPI table points to.
+ //
+ // This appears to be a safety measure. The PCI Firmware Specification
+ // (rev 3.1) says in 4.1.2. "MCFG Table Description": "The resources can
+ // *optionally* be returned in [...] EFIGetMemoryMap as reserved memory
+ // [...]". (Emphasis added here.)
+ //
+ // Normally we add memory resource descriptor HOBs in
+ // QemuInitializeRam(), and pre-allocate from those with memory
+ // allocation HOBs in InitializeRamRegions(). However, the MMCONFIG area
+ // is most definitely not RAM; so, as an exception, cover it with
+ // uncacheable reserved memory right here.
+ //
+ PlatformAddReservedMemoryBaseSizeHob (PciExBarBase, SIZE_256MB, FALSE);
+ BuildMemoryAllocationHob (
+ PciExBarBase,
+ SIZE_256MB,
+ EfiReservedMemoryType
+ );
+ }
+
+ PlatformAddIoMemoryBaseSizeHob (FixedPcdGet32 (PcdCpuLocalApicBaseAddress), SIZE_1MB);
+
+ //
+ // On Q35, the IO Port space is available for PCI resource allocations from
+ // 0x6000 up.
+ //
+ if (HostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
+ *PciIoBase = 0x6000;
+ *PciIoSize = 0xA000;
+ ASSERT ((ICH9_PMBASE_VALUE & 0xF000) < *PciIoBase);
+ }
+
+ //
+ // Add PCI IO Port space available for PCI resource allocations.
+ //
+ BuildResourceDescriptorHob (
+ EFI_RESOURCE_IO,
+ EFI_RESOURCE_ATTRIBUTE_PRESENT |
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED,
+ *PciIoBase,
+ *PciIoSize
+ );
+}
+
+/**
+ * Fetch "opt/ovmf/PcdSetNxForStack" from QEMU
+ *
+ * @param Setting The pointer to the setting of "/opt/ovmf/PcdSetNxForStack".
+ * @return EFI_SUCCESS Successfully fetch the settings.
+ */
+EFI_STATUS
+EFIAPI
+PlatformNoexecDxeInitialization (
+ OUT BOOLEAN *Setting
+ )
+{
+ return QemuFwCfgParseBool ("opt/ovmf/PcdSetNxForStack", Setting);
+}
+
+VOID
+PciExBarInitialization (
+ VOID
+ )
+{
+ union {
+ UINT64 Uint64;
+ UINT32 Uint32[2];
+ } PciExBarBase;
+
+ //
+ // We only support the 256MB size for the MMCONFIG area:
+ // 256 buses * 32 devices * 8 functions * 4096 bytes config space.
+ //
+ // The masks used below enforce the Q35 requirements that the MMCONFIG area
+ // be (a) correctly aligned -- here at 256 MB --, (b) located under 64 GB.
+ //
+ // Note that (b) also ensures that the minimum address width we have
+ // determined in AddressWidthInitialization(), i.e., 36 bits, will suffice
+ // for DXE's page tables to cover the MMCONFIG area.
+ //
+ PciExBarBase.Uint64 = FixedPcdGet64 (PcdPciExpressBaseAddress);
+ ASSERT ((PciExBarBase.Uint32[1] & MCH_PCIEXBAR_HIGHMASK) == 0);
+ ASSERT ((PciExBarBase.Uint32[0] & MCH_PCIEXBAR_LOWMASK) == 0);
+
+ //
+ // Clear the PCIEXBAREN bit first, before programming the high register.
+ //
+ PciWrite32 (DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_LOW), 0);
+
+ //
+ // Program the high register. Then program the low register, setting the
+ // MMCONFIG area size and enabling decoding at once.
+ //
+ PciWrite32 (DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_HIGH), PciExBarBase.Uint32[1]);
+ PciWrite32 (
+ DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_LOW),
+ PciExBarBase.Uint32[0] | MCH_PCIEXBAR_BUS_FF | MCH_PCIEXBAR_EN
+ );
+}
+
+/**
+ * Misc initialization, such as Disable A20 Mask, Build CPU Hob,
+ * PM settings, Set PCI Express Register Range Base Address.
+ *
+ * @param HostBridgeDevId The host bridge Dev id.
+ * @param PhysMemAddressWidth The physical memory address width.
+ */
+VOID
+EFIAPI
+PlatformMiscInitialization (
+ IN UINT16 HostBridgeDevId,
+ IN UINT8 PhysMemAddressWidth
+ )
+{
+ UINTN PmCmd;
+ UINTN Pmba;
+ UINT32 PmbaAndVal;
+ UINT32 PmbaOrVal;
+ UINTN AcpiCtlReg;
+ UINT8 AcpiEnBit;
+
+ //
+ // Disable A20 Mask
+ //
+ IoOr8 (0x92, BIT1);
+
+ //
+ // Build the CPU HOB with guest RAM size dependent address width and 16-bits
+ // of IO space. (Side note: unlike other HOBs, the CPU HOB is needed during
+ // S3 resume as well, so we build it unconditionally.)
+ //
+ BuildCpuHob (PhysMemAddressWidth, 16);
+
+ //
+ // Determine platform type and save Host Bridge DID to PCD
+ //
+ switch (HostBridgeDevId) {
+ case INTEL_82441_DEVICE_ID:
+ PmCmd = POWER_MGMT_REGISTER_PIIX4 (PCI_COMMAND_OFFSET);
+ Pmba = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA);
+ PmbaAndVal = ~(UINT32)PIIX4_PMBA_MASK;
+ PmbaOrVal = PIIX4_PMBA_VALUE;
+ AcpiCtlReg = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMREGMISC);
+ AcpiEnBit = PIIX4_PMREGMISC_PMIOSE;
+ break;
+ case INTEL_Q35_MCH_DEVICE_ID:
+ PmCmd = POWER_MGMT_REGISTER_Q35 (PCI_COMMAND_OFFSET);
+ Pmba = POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE);
+ PmbaAndVal = ~(UINT32)ICH9_PMBASE_MASK;
+ PmbaOrVal = ICH9_PMBASE_VALUE;
+ AcpiCtlReg = POWER_MGMT_REGISTER_Q35 (ICH9_ACPI_CNTL);
+ AcpiEnBit = ICH9_ACPI_CNTL_ACPI_EN;
+ break;
+ default:
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: Unknown Host Bridge Device ID: 0x%04x\n",
+ __FUNCTION__,
+ HostBridgeDevId
+ ));
+ ASSERT (FALSE);
+ return;
+ }
+
+ //
+ // If the appropriate IOspace enable bit is set, assume the ACPI PMBA has
+ // been configured and skip the setup here. This matches the logic in
+ // AcpiTimerLibConstructor ().
+ //
+ if ((PciRead8 (AcpiCtlReg) & AcpiEnBit) == 0) {
+ //
+ // The PEI phase should be exited with fully accessibe ACPI PM IO space:
+ // 1. set PMBA
+ //
+ PciAndThenOr32 (Pmba, PmbaAndVal, PmbaOrVal);
+
+ //
+ // 2. set PCICMD/IOSE
+ //
+ PciOr8 (PmCmd, EFI_PCI_COMMAND_IO_SPACE);
+
+ //
+ // 3. set ACPI PM IO enable bit (PMREGMISC:PMIOSE or ACPI_CNTL:ACPI_EN)
+ //
+ PciOr8 (AcpiCtlReg, AcpiEnBit);
+ }
+
+ if (HostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
+ //
+ // Set Root Complex Register Block BAR
+ //
+ PciWrite32 (
+ POWER_MGMT_REGISTER_Q35 (ICH9_RCBA),
+ ICH9_ROOT_COMPLEX_BASE | ICH9_RCBA_EN
+ );
+
+ //
+ // Set PCI Express Register Range Base Address
+ //
+ PciExBarInitialization ();
+ }
+}
+
+/**
+ Fetch the boot CPU count and the possible CPU count from QEMU.
+
+ @param HostBridgeDevId The Host bridge Dev Id.
+ @param DefaultMaxCpuCount The default max cpu count.
+ @param MaxCpuCount The pointer to the returned max cpu count.
+ @param BootCpuCount The pointer to the returned boot cpu count.
+**/
+VOID
+EFIAPI
+PlatformMaxCpuCountInitialization (
+ IN UINT16 HostBridgeDevId,
+ IN UINT32 DefaultMaxCpuCount,
+ OUT UINT32 *MaxCpuCount,
+ OUT UINT16 *BootCpuCount
+ )
+{
+ //
+ // Try to fetch the boot CPU count.
+ //
+ QemuFwCfgSelectItem (QemuFwCfgItemSmpCpuCount);
+ *BootCpuCount = QemuFwCfgRead16 ();
+ if (*BootCpuCount == 0) {
+ //
+ // QEMU doesn't report the boot CPU count. (BootCpuCount == 0) will let
+ // MpInitLib count APs up to (PcdCpuMaxLogicalProcessorNumber - 1), or
+ // until PcdCpuApInitTimeOutInMicroSeconds elapses (whichever is reached
+ // first).
+ //
+ DEBUG ((DEBUG_WARN, "%a: boot CPU count unavailable\n", __FUNCTION__));
+ *MaxCpuCount = DefaultMaxCpuCount;
+ } else {
+ //
+ // We will expose BootCpuCount to MpInitLib. MpInitLib will count APs up to
+ // (BootCpuCount - 1) precisely, regardless of timeout.
+ //
+ // Now try to fetch the possible CPU count.
+ //
+ UINTN CpuHpBase;
+ UINT32 CmdData2;
+
+ CpuHpBase = ((HostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) ?
+ ICH9_CPU_HOTPLUG_BASE : PIIX4_CPU_HOTPLUG_BASE);
+
+ //
+ // If only legacy mode is available in the CPU hotplug register block, or
+ // the register block is completely missing, then the writes below are
+ // no-ops.
+ //
+ // 1. Switch the hotplug register block to modern mode.
+ //
+ IoWrite32 (CpuHpBase + QEMU_CPUHP_W_CPU_SEL, 0);
+ //
+ // 2. Select a valid CPU for deterministic reading of
+ // QEMU_CPUHP_R_CMD_DATA2.
+ //
+ // CPU#0 is always valid; it is the always present and non-removable
+ // BSP.
+ //
+ IoWrite32 (CpuHpBase + QEMU_CPUHP_W_CPU_SEL, 0);
+ //
+ // 3. Send a command after which QEMU_CPUHP_R_CMD_DATA2 is specified to
+ // read as zero, and which does not invalidate the selector. (The
+ // selector may change, but it must not become invalid.)
+ //
+ // Send QEMU_CPUHP_CMD_GET_PENDING, as it will prove useful later.
+ //
+ IoWrite8 (CpuHpBase + QEMU_CPUHP_W_CMD, QEMU_CPUHP_CMD_GET_PENDING);
+ //
+ // 4. Read QEMU_CPUHP_R_CMD_DATA2.
+ //
+ // If the register block is entirely missing, then this is an unassigned
+ // IO read, returning all-bits-one.
+ //
+ // If only legacy mode is available, then bit#0 stands for CPU#0 in the
+ // "CPU present bitmap". CPU#0 is always present.
+ //
+ // Otherwise, QEMU_CPUHP_R_CMD_DATA2 is either still reserved (returning
+ // all-bits-zero), or it is specified to read as zero after the above
+ // steps. Both cases confirm modern mode.
+ //
+ CmdData2 = IoRead32 (CpuHpBase + QEMU_CPUHP_R_CMD_DATA2);
+ DEBUG ((DEBUG_VERBOSE, "%a: CmdData2=0x%x\n", __FUNCTION__, CmdData2));
+ if (CmdData2 != 0) {
+ //
+ // QEMU doesn't support the modern CPU hotplug interface. Assume that the
+ // possible CPU count equals the boot CPU count (precluding hotplug).
+ //
+ DEBUG ((
+ DEBUG_WARN,
+ "%a: modern CPU hotplug interface unavailable\n",
+ __FUNCTION__
+ ));
+ *MaxCpuCount = *BootCpuCount;
+ } else {
+ //
+ // Grab the possible CPU count from the modern CPU hotplug interface.
+ //
+ UINT32 Present, Possible, Selected;
+
+ Present = 0;
+ Possible = 0;
+
+ //
+ // We've sent QEMU_CPUHP_CMD_GET_PENDING last; this ensures
+ // QEMU_CPUHP_RW_CMD_DATA can now be read usefully. However,
+ // QEMU_CPUHP_CMD_GET_PENDING may have selected a CPU with actual pending
+ // hotplug events; therefore, select CPU#0 forcibly.
+ //
+ IoWrite32 (CpuHpBase + QEMU_CPUHP_W_CPU_SEL, Possible);
+
+ do {
+ UINT8 CpuStatus;
+
+ //
+ // Read the status of the currently selected CPU. This will help with a
+ // sanity check against "BootCpuCount".
+ //
+ CpuStatus = IoRead8 (CpuHpBase + QEMU_CPUHP_R_CPU_STAT);
+ if ((CpuStatus & QEMU_CPUHP_STAT_ENABLED) != 0) {
+ ++Present;
+ }
+
+ //
+ // Attempt to select the next CPU.
+ //
+ ++Possible;
+ IoWrite32 (CpuHpBase + QEMU_CPUHP_W_CPU_SEL, Possible);
+ //
+ // If the selection is successful, then the following read will return
+ // the selector (which we know is positive at this point). Otherwise,
+ // the read will return 0.
+ //
+ Selected = IoRead32 (CpuHpBase + QEMU_CPUHP_RW_CMD_DATA);
+ ASSERT (Selected == Possible || Selected == 0);
+ } while (Selected > 0);
+
+ //
+ // Sanity check: fw_cfg and the modern CPU hotplug interface should
+ // return the same boot CPU count.
+ //
+ if (*BootCpuCount != Present) {
+ DEBUG ((
+ DEBUG_WARN,
+ "%a: QEMU v2.7 reset bug: BootCpuCount=%d "
+ "Present=%u\n",
+ __FUNCTION__,
+ *BootCpuCount,
+ Present
+ ));
+ //
+ // The handling of QemuFwCfgItemSmpCpuCount, across CPU hotplug plus
+ // platform reset (including S3), was corrected in QEMU commit
+ // e3cadac073a9 ("pc: fix FW_CFG_NB_CPUS to account for -device added
+ // CPUs", 2016-11-16), part of release v2.8.0.
+ //
+ *BootCpuCount = (UINT16)Present;
+ }
+
+ *MaxCpuCount = Possible;
+ }
+ }
+
+ DEBUG ((
+ DEBUG_INFO,
+ "%a: BootCpuCount=%d MaxCpuCount=%u\n",
+ __FUNCTION__,
+ *BootCpuCount,
+ *MaxCpuCount
+ ));
+ ASSERT (*BootCpuCount <= *MaxCpuCount);
+}
+
+/**
+ * Query Host Bridge Dev Id.
+ *
+ * @return Host Bridge Dev Id.
+ */
+UINT16
+EFIAPI
+PlatformQueryHostBridgeDid (
+ VOID
+ )
+{
+ return PciRead16 (OVMF_HOSTBRIDGE_DID);
+}
diff --git a/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf b/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
index 6ba1e59246d1..a42b54805ba6 100644
--- a/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
+++ b/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
@@ -28,6 +28,7 @@
Platform.c

[Packages]
+ EmbeddedPkg/EmbeddedPkg.dec
MdeModulePkg/MdeModulePkg.dec
MdePkg/MdePkg.dec
OvmfPkg/OvmfPkg.dec
@@ -42,6 +43,7 @@
QemuFwCfgSimpleParserLib
MtrrLib
PcdLib
+ PciLib

[FixedPcd]
gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
@@ -50,5 +52,32 @@
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageBase
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageSize

+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidBase
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidSize
+ gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiACPIMemoryNVS
+ gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiACPIReclaimMemory
+ gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiReservedMemoryType
+ gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesCode
+ gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesData
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupBase
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupSize
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecretsBase
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSnpSecretsSize
+
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesBase
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesSize
+
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
+
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableBase
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableSize
+
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuLocalApicBaseAddress
+
[FeaturePcd]
gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode
--
2.29.2.windows.2


[PATCH V6 22/42] OvmfPkg/PlatformPei: Update memory functions with PlatformInitLib

Min Xu
 

RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429

Memory functions in OvmfPkg/PlatformPei are updated with the ones in
PlatformInitLib.

Cc: Ard Biesheuvel <ardb+tianocore@...>
Cc: Jordan Justen <jordan.l.justen@...>
Cc: Brijesh Singh <brijesh.singh@...>
Cc: Erdem Aktas <erdemaktas@...>
Cc: James Bottomley <jejb@...>
Cc: Jiewen Yao <jiewen.yao@...>
Cc: Tom Lendacky <thomas.lendacky@...>
Cc: Gerd Hoffmann <kraxel@...>
Signed-off-by: Min Xu <min.m.xu@...>
---
OvmfPkg/PlatformPei/MemDetect.c | 654 ++------------------------------
OvmfPkg/PlatformPei/Platform.c | 9 +-
OvmfPkg/PlatformPei/Platform.h | 5 -
3 files changed, 34 insertions(+), 634 deletions(-)

diff --git a/OvmfPkg/PlatformPei/MemDetect.c b/OvmfPkg/PlatformPei/MemDetect.c
index d19a344d18b8..9b62625f9d91 100644
--- a/OvmfPkg/PlatformPei/MemDetect.c
+++ b/OvmfPkg/PlatformPei/MemDetect.c
@@ -50,6 +50,7 @@ STATIC UINT16 mQ35TsegMbytes;
BOOLEAN mQ35SmramAtDefaultSmbase;

UINT32 mQemuUc32Base;
+UINT32 mLowerMemorySize = 0;

VOID
Q35TsegMbytesInitialization (
@@ -140,406 +141,11 @@ QemuUc32BaseInitialization (
VOID
)
{
- UINT32 LowerMemorySize;
- UINT32 Uc32Size;
-
if (mHostBridgeDevId == 0xffff /* microvm */) {
return;
}

- if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
- //
- // On q35, the 32-bit area that we'll mark as UC, through variable MTRRs,
- // starts at PcdPciExpressBaseAddress. The platform DSC is responsible for
- // setting PcdPciExpressBaseAddress such that describing the
- // [PcdPciExpressBaseAddress, 4GB) range require a very small number of
- // variable MTRRs (preferably 1 or 2).
- //
- ASSERT (FixedPcdGet64 (PcdPciExpressBaseAddress) <= MAX_UINT32);
- mQemuUc32Base = (UINT32)FixedPcdGet64 (PcdPciExpressBaseAddress);
- return;
- }
-
- if (mHostBridgeDevId == CLOUDHV_DEVICE_ID) {
- Uc32Size = CLOUDHV_MMIO_HOLE_SIZE;
- mQemuUc32Base = CLOUDHV_MMIO_HOLE_ADDRESS;
- return;
- }
-
- ASSERT (mHostBridgeDevId == INTEL_82441_DEVICE_ID);
- //
- // On i440fx, start with the [LowerMemorySize, 4GB) range. Make sure one
- // variable MTRR suffices by truncating the size to a whole power of two,
- // while keeping the end affixed to 4GB. This will round the base up.
- //
- LowerMemorySize = GetSystemMemorySizeBelow4gb ();
- Uc32Size = GetPowerOfTwo32 ((UINT32)(SIZE_4GB - LowerMemorySize));
- mQemuUc32Base = (UINT32)(SIZE_4GB - Uc32Size);
- //
- // Assuming that LowerMemorySize is at least 1 byte, Uc32Size is at most 2GB.
- // Therefore mQemuUc32Base is at least 2GB.
- //
- ASSERT (mQemuUc32Base >= BASE_2GB);
-
- if (mQemuUc32Base != LowerMemorySize) {
- DEBUG ((
- DEBUG_VERBOSE,
- "%a: rounded UC32 base from 0x%x up to 0x%x, for "
- "an UC32 size of 0x%x\n",
- __FUNCTION__,
- LowerMemorySize,
- mQemuUc32Base,
- Uc32Size
- ));
- }
-}
-
-/**
- Iterate over the RAM entries in QEMU's fw_cfg E820 RAM map that start outside
- of the 32-bit address range.
-
- Find the highest exclusive >=4GB RAM address, or produce memory resource
- descriptor HOBs for RAM entries that start at or above 4GB.
-
- @param[out] MaxAddress If MaxAddress is NULL, then ScanOrAdd64BitE820Ram()
- produces memory resource descriptor HOBs for RAM
- entries that start at or above 4GB.
-
- Otherwise, MaxAddress holds the highest exclusive
- >=4GB RAM address on output. If QEMU's fw_cfg E820
- RAM map contains no RAM entry that starts outside of
- the 32-bit address range, then MaxAddress is exactly
- 4GB on output.
-
- @retval EFI_SUCCESS The fw_cfg E820 RAM map was found and processed.
-
- @retval EFI_PROTOCOL_ERROR The RAM map was found, but its size wasn't a
- whole multiple of sizeof(EFI_E820_ENTRY64). No
- RAM entry was processed.
-
- @return Error codes from QemuFwCfgFindFile(). No RAM
- entry was processed.
-**/
-STATIC
-EFI_STATUS
-ScanOrAdd64BitE820Ram (
- IN BOOLEAN AddHighHob,
- OUT UINT64 *LowMemory OPTIONAL,
- OUT UINT64 *MaxAddress OPTIONAL
- )
-{
- EFI_STATUS Status;
- FIRMWARE_CONFIG_ITEM FwCfgItem;
- UINTN FwCfgSize;
- EFI_E820_ENTRY64 E820Entry;
- UINTN Processed;
-
- Status = QemuFwCfgFindFile ("etc/e820", &FwCfgItem, &FwCfgSize);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if (FwCfgSize % sizeof E820Entry != 0) {
- return EFI_PROTOCOL_ERROR;
- }
-
- if (LowMemory != NULL) {
- *LowMemory = 0;
- }
-
- if (MaxAddress != NULL) {
- *MaxAddress = BASE_4GB;
- }
-
- QemuFwCfgSelectItem (FwCfgItem);
- for (Processed = 0; Processed < FwCfgSize; Processed += sizeof E820Entry) {
- QemuFwCfgReadBytes (sizeof E820Entry, &E820Entry);
- DEBUG ((
- DEBUG_VERBOSE,
- "%a: Base=0x%Lx Length=0x%Lx Type=%u\n",
- __FUNCTION__,
- E820Entry.BaseAddr,
- E820Entry.Length,
- E820Entry.Type
- ));
- if (E820Entry.Type == EfiAcpiAddressRangeMemory) {
- if (AddHighHob && (E820Entry.BaseAddr >= BASE_4GB)) {
- UINT64 Base;
- UINT64 End;
-
- //
- // Round up the start address, and round down the end address.
- //
- Base = ALIGN_VALUE (E820Entry.BaseAddr, (UINT64)EFI_PAGE_SIZE);
- End = (E820Entry.BaseAddr + E820Entry.Length) &
- ~(UINT64)EFI_PAGE_MASK;
- if (Base < End) {
- PlatformAddMemoryRangeHob (Base, End);
- DEBUG ((
- DEBUG_VERBOSE,
- "%a: PlatformAddMemoryRangeHob [0x%Lx, 0x%Lx)\n",
- __FUNCTION__,
- Base,
- End
- ));
- }
- }
-
- if (MaxAddress || LowMemory) {
- UINT64 Candidate;
-
- Candidate = E820Entry.BaseAddr + E820Entry.Length;
- if (MaxAddress && (Candidate > *MaxAddress)) {
- *MaxAddress = Candidate;
- DEBUG ((
- DEBUG_VERBOSE,
- "%a: MaxAddress=0x%Lx\n",
- __FUNCTION__,
- *MaxAddress
- ));
- }
-
- if (LowMemory && (Candidate > *LowMemory) && (Candidate < BASE_4GB)) {
- *LowMemory = Candidate;
- DEBUG ((
- DEBUG_VERBOSE,
- "%a: LowMemory=0x%Lx\n",
- __FUNCTION__,
- *LowMemory
- ));
- }
- }
- }
- }
-
- return EFI_SUCCESS;
-}
-
-UINT32
-GetSystemMemorySizeBelow4gb (
- VOID
- )
-{
- EFI_STATUS Status;
- UINT64 LowerMemorySize = 0;
- UINT8 Cmos0x34;
- UINT8 Cmos0x35;
-
- Status = ScanOrAdd64BitE820Ram (FALSE, &LowerMemorySize, NULL);
- if ((Status == EFI_SUCCESS) && (LowerMemorySize > 0)) {
- return (UINT32)LowerMemorySize;
- }
-
- //
- // CMOS 0x34/0x35 specifies the system memory above 16 MB.
- // * CMOS(0x35) is the high byte
- // * CMOS(0x34) is the low byte
- // * The size is specified in 64kb chunks
- // * Since this is memory above 16MB, the 16MB must be added
- // into the calculation to get the total memory size.
- //
-
- Cmos0x34 = (UINT8)PlatformCmosRead8 (0x34);
- Cmos0x35 = (UINT8)PlatformCmosRead8 (0x35);
-
- return (UINT32)(((UINTN)((Cmos0x35 << 8) + Cmos0x34) << 16) + SIZE_16MB);
-}
-
-STATIC
-UINT64
-GetSystemMemorySizeAbove4gb (
- )
-{
- UINT32 Size;
- UINTN CmosIndex;
-
- //
- // CMOS 0x5b-0x5d specifies the system memory above 4GB MB.
- // * CMOS(0x5d) is the most significant size byte
- // * CMOS(0x5c) is the middle size byte
- // * CMOS(0x5b) is the least significant size byte
- // * The size is specified in 64kb chunks
- //
-
- Size = 0;
- for (CmosIndex = 0x5d; CmosIndex >= 0x5b; CmosIndex--) {
- Size = (UINT32)(Size << 8) + (UINT32)PlatformCmosRead8 (CmosIndex);
- }
-
- return LShiftU64 (Size, 16);
-}
-
-/**
- Return the highest address that DXE could possibly use, plus one.
-**/
-STATIC
-UINT64
-GetFirstNonAddress (
- VOID
- )
-{
- UINT64 FirstNonAddress;
- UINT64 Pci64Base, Pci64Size;
- UINT32 FwCfgPciMmio64Mb;
- EFI_STATUS Status;
- FIRMWARE_CONFIG_ITEM FwCfgItem;
- UINTN FwCfgSize;
- UINT64 HotPlugMemoryEnd;
- RETURN_STATUS PcdStatus;
-
- //
- // set FirstNonAddress to suppress incorrect compiler/analyzer warnings
- //
- FirstNonAddress = 0;
-
- //
- // If QEMU presents an E820 map, then get the highest exclusive >=4GB RAM
- // address from it. This can express an address >= 4GB+1TB.
- //
- // Otherwise, get the flat size of the memory above 4GB from the CMOS (which
- // can only express a size smaller than 1TB), and add it to 4GB.
- //
- Status = ScanOrAdd64BitE820Ram (FALSE, NULL, &FirstNonAddress);
- if (EFI_ERROR (Status)) {
- FirstNonAddress = BASE_4GB + GetSystemMemorySizeAbove4gb ();
- }
-
- //
- // If DXE is 32-bit, then we're done; PciBusDxe will degrade 64-bit MMIO
- // resources to 32-bit anyway. See DegradeResource() in
- // "PciResourceSupport.c".
- //
- #ifdef MDE_CPU_IA32
- if (!FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
- return FirstNonAddress;
- }
-
- #endif
-
- //
- // Otherwise, in order to calculate the highest address plus one, we must
- // consider the 64-bit PCI host aperture too. Fetch the default size.
- //
- Pci64Size = PcdGet64 (PcdPciMmio64Size);
-
- //
- // See if the user specified the number of megabytes for the 64-bit PCI host
- // aperture. Accept an aperture size up to 16TB.
- //
- // As signaled by the "X-" prefix, this knob is experimental, and might go
- // away at any time.
- //
- Status = QemuFwCfgParseUint32 (
- "opt/ovmf/X-PciMmio64Mb",
- FALSE,
- &FwCfgPciMmio64Mb
- );
- switch (Status) {
- case EFI_UNSUPPORTED:
- case EFI_NOT_FOUND:
- break;
- case EFI_SUCCESS:
- if (FwCfgPciMmio64Mb <= 0x1000000) {
- Pci64Size = LShiftU64 (FwCfgPciMmio64Mb, 20);
- break;
- }
-
- //
- // fall through
- //
- default:
- DEBUG ((
- DEBUG_WARN,
- "%a: ignoring malformed 64-bit PCI host aperture size from fw_cfg\n",
- __FUNCTION__
- ));
- break;
- }
-
- if (Pci64Size == 0) {
- if (mBootMode != BOOT_ON_S3_RESUME) {
- DEBUG ((
- DEBUG_INFO,
- "%a: disabling 64-bit PCI host aperture\n",
- __FUNCTION__
- ));
- PcdStatus = PcdSet64S (PcdPciMmio64Size, 0);
- ASSERT_RETURN_ERROR (PcdStatus);
- }
-
- //
- // There's nothing more to do; the amount of memory above 4GB fully
- // determines the highest address plus one. The memory hotplug area (see
- // below) plays no role for the firmware in this case.
- //
- return FirstNonAddress;
- }
-
- //
- // The "etc/reserved-memory-end" fw_cfg file, when present, contains an
- // absolute, exclusive end address for the memory hotplug area. This area
- // starts right at the end of the memory above 4GB. The 64-bit PCI host
- // aperture must be placed above it.
- //
- Status = QemuFwCfgFindFile (
- "etc/reserved-memory-end",
- &FwCfgItem,
- &FwCfgSize
- );
- if (!EFI_ERROR (Status) && (FwCfgSize == sizeof HotPlugMemoryEnd)) {
- QemuFwCfgSelectItem (FwCfgItem);
- QemuFwCfgReadBytes (FwCfgSize, &HotPlugMemoryEnd);
- DEBUG ((
- DEBUG_VERBOSE,
- "%a: HotPlugMemoryEnd=0x%Lx\n",
- __FUNCTION__,
- HotPlugMemoryEnd
- ));
-
- ASSERT (HotPlugMemoryEnd >= FirstNonAddress);
- FirstNonAddress = HotPlugMemoryEnd;
- }
-
- //
- // SeaBIOS aligns both boundaries of the 64-bit PCI host aperture to 1GB, so
- // that the host can map it with 1GB hugepages. Follow suit.
- //
- Pci64Base = ALIGN_VALUE (FirstNonAddress, (UINT64)SIZE_1GB);
- Pci64Size = ALIGN_VALUE (Pci64Size, (UINT64)SIZE_1GB);
-
- //
- // The 64-bit PCI host aperture should also be "naturally" aligned. The
- // alignment is determined by rounding the size of the aperture down to the
- // next smaller or equal power of two. That is, align the aperture by the
- // largest BAR size that can fit into it.
- //
- Pci64Base = ALIGN_VALUE (Pci64Base, GetPowerOfTwo64 (Pci64Size));
-
- if (mBootMode != BOOT_ON_S3_RESUME) {
- //
- // The core PciHostBridgeDxe driver will automatically add this range to
- // the GCD memory space map through our PciHostBridgeLib instance; here we
- // only need to set the PCDs.
- //
- PcdStatus = PcdSet64S (PcdPciMmio64Base, Pci64Base);
- ASSERT_RETURN_ERROR (PcdStatus);
- PcdStatus = PcdSet64S (PcdPciMmio64Size, Pci64Size);
- ASSERT_RETURN_ERROR (PcdStatus);
-
- DEBUG ((
- DEBUG_INFO,
- "%a: Pci64Base=0x%Lx Pci64Size=0x%Lx\n",
- __FUNCTION__,
- Pci64Base,
- Pci64Size
- ));
- }
-
- //
- // The useful address space ends with the 64-bit PCI host aperture.
- //
- FirstNonAddress = Pci64Base + Pci64Size;
- return FirstNonAddress;
+ mQemuUc32Base = PlatformQemuUc32BaseInitialization (mHostBridgeDevId, mLowerMemorySize);
}

/**
@@ -550,36 +156,19 @@ AddressWidthInitialization (
VOID
)
{
- UINT64 FirstNonAddress;
-
- //
- // As guest-physical memory size grows, the permanent PEI RAM requirements
- // are dominated by the identity-mapping page tables built by the DXE IPL.
- // The DXL IPL keys off of the physical address bits advertized in the CPU
- // HOB. To conserve memory, we calculate the minimum address width here.
- //
- FirstNonAddress = GetFirstNonAddress ();
- mPhysMemAddressWidth = (UINT8)HighBitSet64 (FirstNonAddress);
-
- //
- // If FirstNonAddress is not an integral power of two, then we need an
- // additional bit.
- //
- if ((FirstNonAddress & (FirstNonAddress - 1)) != 0) {
- ++mPhysMemAddressWidth;
- }
-
- //
- // The minimum address width is 36 (covers up to and excluding 64 GB, which
- // is the maximum for Ia32 + PAE). The theoretical architecture maximum for
- // X64 long mode is 52 bits, but the DXE IPL clamps that down to 48 bits. We
- // can simply assert that here, since 48 bits are good enough for 256 TB.
- //
- if (mPhysMemAddressWidth <= 36) {
- mPhysMemAddressWidth = 36;
- }
-
- ASSERT (mPhysMemAddressWidth <= 48);
+ UINT64 Pci64Base;
+ UINT64 Pci64Size;
+ UINT64 FirstNonAddress;
+ RETURN_STATUS PcdStatus;
+
+ Pci64Base = 0;
+ Pci64Size = 0;
+ FirstNonAddress = PlatformGetFirstNonAddress (&Pci64Base, &Pci64Size, PcdGet64 (PcdPciMmio64Size));
+ mPhysMemAddressWidth = PlatformAddressWidthInitialization (FirstNonAddress);
+ PcdStatus = PcdSet64S (PcdPciMmio64Base, Pci64Base);
+ ASSERT_RETURN_ERROR (PcdStatus);
+ PcdStatus = PcdSet64S (PcdPciMmio64Size, Pci64Size);
+ ASSERT_RETURN_ERROR (PcdStatus);
}

/**
@@ -664,7 +253,7 @@ PublishPeiMemory (
UINT32 LowerMemorySize;
UINT32 PeiMemoryCap;

- LowerMemorySize = GetSystemMemorySizeBelow4gb ();
+ LowerMemorySize = PlatformGetSystemMemorySizeBelow4gb ();
if (FeaturePcdGet (PcdSmmSmramRequire)) {
//
// TSEG is chipped from the end of low RAM
@@ -736,162 +325,6 @@ PublishPeiMemory (
return Status;
}

-STATIC
-VOID
-QemuInitializeRamBelow1gb (
- VOID
- )
-{
- if (FeaturePcdGet (PcdSmmSmramRequire) && mQ35SmramAtDefaultSmbase) {
- PlatformAddMemoryRangeHob (0, SMM_DEFAULT_SMBASE);
- PlatformAddReservedMemoryBaseSizeHob (
- SMM_DEFAULT_SMBASE,
- MCH_DEFAULT_SMBASE_SIZE,
- TRUE /* Cacheable */
- );
- STATIC_ASSERT (
- SMM_DEFAULT_SMBASE + MCH_DEFAULT_SMBASE_SIZE < BASE_512KB + BASE_128KB,
- "end of SMRAM at default SMBASE ends at, or exceeds, 640KB"
- );
- PlatformAddMemoryRangeHob (
- SMM_DEFAULT_SMBASE + MCH_DEFAULT_SMBASE_SIZE,
- BASE_512KB + BASE_128KB
- );
- } else {
- PlatformAddMemoryRangeHob (0, BASE_512KB + BASE_128KB);
- }
-}
-
-/**
- Peform Memory Detection for QEMU / KVM
-
-**/
-STATIC
-VOID
-QemuInitializeRam (
- VOID
- )
-{
- UINT64 LowerMemorySize;
- UINT64 UpperMemorySize;
- MTRR_SETTINGS MtrrSettings;
- EFI_STATUS Status;
-
- DEBUG ((DEBUG_INFO, "%a called\n", __FUNCTION__));
-
- //
- // Determine total memory size available
- //
- LowerMemorySize = GetSystemMemorySizeBelow4gb ();
-
- if (mBootMode == BOOT_ON_S3_RESUME) {
- //
- // Create the following memory HOB as an exception on the S3 boot path.
- //
- // Normally we'd create memory HOBs only on the normal boot path. However,
- // CpuMpPei specifically needs such a low-memory HOB on the S3 path as
- // well, for "borrowing" a subset of it temporarily, for the AP startup
- // vector.
- //
- // CpuMpPei saves the original contents of the borrowed area in permanent
- // PEI RAM, in a backup buffer allocated with the normal PEI services.
- // CpuMpPei restores the original contents ("returns" the borrowed area) at
- // End-of-PEI. End-of-PEI in turn is emitted by S3Resume2Pei before
- // transferring control to the OS's wakeup vector in the FACS.
- //
- // We expect any other PEIMs that "borrow" memory similarly to CpuMpPei to
- // restore the original contents. Furthermore, we expect all such PEIMs
- // (CpuMpPei included) to claim the borrowed areas by producing memory
- // allocation HOBs, and to honor preexistent memory allocation HOBs when
- // looking for an area to borrow.
- //
- QemuInitializeRamBelow1gb ();
- } else {
- //
- // Create memory HOBs
- //
- QemuInitializeRamBelow1gb ();
-
- if (FeaturePcdGet (PcdSmmSmramRequire)) {
- UINT32 TsegSize;
-
- TsegSize = mQ35TsegMbytes * SIZE_1MB;
- PlatformAddMemoryRangeHob (BASE_1MB, LowerMemorySize - TsegSize);
- PlatformAddReservedMemoryBaseSizeHob (
- LowerMemorySize - TsegSize,
- TsegSize,
- TRUE
- );
- } else {
- PlatformAddMemoryRangeHob (BASE_1MB, LowerMemorySize);
- }
-
- //
- // If QEMU presents an E820 map, then create memory HOBs for the >=4GB RAM
- // entries. Otherwise, create a single memory HOB with the flat >=4GB
- // memory size read from the CMOS.
- //
- Status = ScanOrAdd64BitE820Ram (TRUE, NULL, NULL);
- if (EFI_ERROR (Status)) {
- UpperMemorySize = GetSystemMemorySizeAbove4gb ();
- if (UpperMemorySize != 0) {
- PlatformAddMemoryBaseSizeHob (BASE_4GB, UpperMemorySize);
- }
- }
- }
-
- //
- // We'd like to keep the following ranges uncached:
- // - [640 KB, 1 MB)
- // - [LowerMemorySize, 4 GB)
- //
- // Everything else should be WB. Unfortunately, programming the inverse (ie.
- // keeping the default UC, and configuring the complement set of the above as
- // WB) is not reliable in general, because the end of the upper RAM can have
- // practically any alignment, and we may not have enough variable MTRRs to
- // cover it exactly.
- //
- if (IsMtrrSupported () && (mHostBridgeDevId != CLOUDHV_DEVICE_ID)) {
- MtrrGetAllMtrrs (&MtrrSettings);
-
- //
- // MTRRs disabled, fixed MTRRs disabled, default type is uncached
- //
- ASSERT ((MtrrSettings.MtrrDefType & BIT11) == 0);
- ASSERT ((MtrrSettings.MtrrDefType & BIT10) == 0);
- ASSERT ((MtrrSettings.MtrrDefType & 0xFF) == 0);
-
- //
- // flip default type to writeback
- //
- SetMem (&MtrrSettings.Fixed, sizeof MtrrSettings.Fixed, 0x06);
- ZeroMem (&MtrrSettings.Variables, sizeof MtrrSettings.Variables);
- MtrrSettings.MtrrDefType |= BIT11 | BIT10 | 6;
- MtrrSetAllMtrrs (&MtrrSettings);
-
- //
- // Set memory range from 640KB to 1MB to uncacheable
- //
- Status = MtrrSetMemoryAttribute (
- BASE_512KB + BASE_128KB,
- BASE_1MB - (BASE_512KB + BASE_128KB),
- CacheUncacheable
- );
- ASSERT_EFI_ERROR (Status);
-
- //
- // Set the memory range from the start of the 32-bit MMIO area (32-bit PCI
- // MMIO aperture on i440fx, PCIEXBAR on q35) to 4GB as uncacheable.
- //
- Status = MtrrSetMemoryAttribute (
- mQemuUc32Base,
- SIZE_4GB - mQemuUc32Base,
- CacheUncacheable
- );
- ASSERT_EFI_ERROR (Status);
- }
-}
-
/**
Publish system RAM and reserve memory regions

@@ -901,7 +334,15 @@ InitializeRamRegions (
VOID
)
{
- QemuInitializeRam ();
+ PlatformInitializeRamRegions (
+ mQemuUc32Base,
+ mHostBridgeDevId,
+ FeaturePcdGet (PcdSmmSmramRequire),
+ mBootMode,
+ mS3Supported,
+ mLowerMemorySize,
+ mQ35TsegMbytes
+ );

SevInitializeRam ();

@@ -979,28 +420,6 @@ InitializeRamRegions (
}

if (mBootMode != BOOT_ON_S3_RESUME) {
- if (!FeaturePcdGet (PcdSmmSmramRequire)) {
- //
- // Reserve the lock box storage area
- //
- // Since this memory range will be used on S3 resume, it must be
- // reserved as ACPI NVS.
- //
- // If S3 is unsupported, then various drivers might still write to the
- // LockBox area. We ought to prevent DXE from serving allocation requests
- // such that they would overlap the LockBox storage.
- //
- ZeroMem (
- (VOID *)(UINTN)PcdGet32 (PcdOvmfLockBoxStorageBase),
- (UINTN)PcdGet32 (PcdOvmfLockBoxStorageSize)
- );
- BuildMemoryAllocationHob (
- (EFI_PHYSICAL_ADDRESS)(UINTN)PcdGet32 (PcdOvmfLockBoxStorageBase),
- (UINT64)(UINTN)PcdGet32 (PcdOvmfLockBoxStorageSize),
- mS3Supported ? EfiACPIMemoryNVS : EfiBootServicesData
- );
- }
-
if (FeaturePcdGet (PcdSmmSmramRequire)) {
UINT32 TsegSize;

@@ -1010,7 +429,7 @@ InitializeRamRegions (
//
TsegSize = mQ35TsegMbytes * SIZE_1MB;
BuildMemoryAllocationHob (
- GetSystemMemorySizeBelow4gb () - TsegSize,
+ PlatformGetSystemMemorySizeBelow4gb () - TsegSize,
TsegSize,
EfiReservedMemoryType
);
@@ -1026,26 +445,5 @@ InitializeRamRegions (
);
}
}
-
- #ifdef MDE_CPU_X64
- 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),
- mS3Supported ? EfiACPIMemoryNVS : EfiBootServicesData
- );
- }
-
- #endif
}
}
diff --git a/OvmfPkg/PlatformPei/Platform.c b/OvmfPkg/PlatformPei/Platform.c
index 62480c3c40e5..7e98f97c8480 100644
--- a/OvmfPkg/PlatformPei/Platform.c
+++ b/OvmfPkg/PlatformPei/Platform.c
@@ -57,6 +57,8 @@ BOOLEAN mS3Supported = FALSE;

UINT32 mMaxCpuCount;

+extern UINT32 mLowerMemorySize;
+
VOID
MemMapInitialization (
VOID
@@ -85,7 +87,7 @@ MemMapInitialization (
return;
}

- TopOfLowRam = GetSystemMemorySizeBelow4gb ();
+ TopOfLowRam = PlatformGetSystemMemorySizeBelow4gb ();
PciExBarBase = 0;
if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
//
@@ -736,6 +738,11 @@ InitializePlatform (
Q35SmramAtDefaultSmbaseInitialization ();
}

+ //
+ // Fetch the lower memory size (Below 4G)
+ //
+ mLowerMemorySize = PlatformGetSystemMemorySizeBelow4gb ();
+
PublishPeiMemory ();

QemuUc32BaseInitialization ();
diff --git a/OvmfPkg/PlatformPei/Platform.h b/OvmfPkg/PlatformPei/Platform.h
index f193ff736549..64af9cde1002 100644
--- a/OvmfPkg/PlatformPei/Platform.h
+++ b/OvmfPkg/PlatformPei/Platform.h
@@ -31,11 +31,6 @@ PublishPeiMemory (
VOID
);

-UINT32
-GetSystemMemorySizeBelow4gb (
- VOID
- );
-
VOID
QemuUc32BaseInitialization (
VOID
--
2.29.2.windows.2


[PATCH V6 21/42] OvmfPkg/PlatformInitLib: Add memory functions

Min Xu
 

Below functions are introduced in PlatformInitLib:
- PlatformGetFirstNonAddress
- PlatformAddressWidthInitialization
- PlatformGetSystemMemorySizeBelow4gb
- PlatformQemuUc32BaseInitialization
- PlatformInitializeRamRegions

They correspond to the below functions in OvmfPkg/PlatformPei:
- GetFirstNonAddress
- AddressWidthInitialization
- GetSystemMemorySizeBelow4gb
- QemuUc32BaseInitialization
- InitializeRamRegions

Note: PlatformInitLib will not determine whether SMM or S3 is supported
or not. Instead the caller of these functions should input SMM / S3
support as the IN parameter by themselves. This is to reduce the
complexity of PlatformInitLib. Another reason is that some PCDs cannot
be declared as FixedAtBuild while PlatformInitLib is designed to be used
in both SEC and PEI phase.

Cc: Ard Biesheuvel <ardb+tianocore@...>
Cc: Jordan Justen <jordan.l.justen@...>
Cc: Brijesh Singh <brijesh.singh@...>
Cc: Erdem Aktas <erdemaktas@...>
Cc: James Bottomley <jejb@...>
Cc: Jiewen Yao <jiewen.yao@...>
Cc: Tom Lendacky <thomas.lendacky@...>
Cc: Gerd Hoffmann <kraxel@...>
Signed-off-by: Min Xu <min.m.xu@...>
---
OvmfPkg/Include/Library/PlatformInitLib.h | 78 ++
OvmfPkg/Library/PlatformInitLib/MemDetect.c | 694 ++++++++++++++++++
.../PlatformInitLib/PlatformInitLib.inf | 16 +
3 files changed, 788 insertions(+)
create mode 100644 OvmfPkg/Library/PlatformInitLib/MemDetect.c

diff --git a/OvmfPkg/Include/Library/PlatformInitLib.h b/OvmfPkg/Include/Library/PlatformInitLib.h
index bc540f549d60..df2646880909 100644
--- a/OvmfPkg/Include/Library/PlatformInitLib.h
+++ b/OvmfPkg/Include/Library/PlatformInitLib.h
@@ -63,6 +63,84 @@ PlatformDebugDumpCmos (
VOID
);

+/**
+ * Return the highest address that DXE could possibly use, plus one.
+ *
+ * @param Pci64Base The 64-bit PCI host aperture base address.
+ * @param Pci64Size The 64-bit PCI host aperture size.
+ * @param DefaultPciMmio64Size The default 64-bit PCI host aperture size.
+ *
+ * @return The highest address that DXE could possibly use, plus one.
+ */
+UINT64
+EFIAPI
+PlatformGetFirstNonAddress (
+ OUT UINT64 *Pci64Base,
+ OUT UINT64 *Pci64Size,
+ IN UINT64 DefaultPciMmio64Size
+ );
+
+/**
+ * Initialize the PhysMemAddressWidth variable, based on guest RAM size.
+ *
+ * @param FirstNonAddress The highest address that DXE could possibly use, plus one.
+ *
+ * @return The physical memory address width based on the guest RAM size.
+ */
+UINT8
+EFIAPI
+PlatformAddressWidthInitialization (
+ IN UINT64 FirstNonAddress
+ );
+
+/**
+ * Get the memory size below 4GB.
+ *
+ * @return UINT32 The lower memory size.
+ */
+UINT32
+EFIAPI
+PlatformGetSystemMemorySizeBelow4gb (
+ VOID
+ );
+
+/**
+ * Initializatoin of Qemu UC32Base.
+ *
+ * @param HostBridgeDevId The host bridge Dev Id.
+ * @param LowerMemorySize The lower memory size (under 4G).
+ * @return UINT32 The Qemu UC32 base address.
+ */
+UINT32
+EFIAPI
+PlatformQemuUc32BaseInitialization (
+ IN UINT16 HostBridgeDevId,
+ IN UINT32 LowerMemorySize
+ );
+
+/**
+ Publish system RAM and reserve memory regions.
+
+ @param Uc32Base
+ @param HostBridgeDevId
+ @param SmmSmramRequire
+ @param BootMode
+ @param S3Supported
+ @param LowerMemorySize
+ @param Q35TsegMbytes
+**/
+VOID
+EFIAPI
+PlatformInitializeRamRegions (
+ IN UINT32 Uc32Base,
+ IN UINT16 HostBridgeDevId,
+ IN BOOLEAN SmmSmramRequire,
+ IN EFI_BOOT_MODE BootMode,
+ IN BOOLEAN S3Supported,
+ IN UINT32 LowerMemorySize,
+ IN UINT16 Q35TsegMbytes
+ );
+
VOID
EFIAPI
PlatformAddIoMemoryBaseSizeHob (
diff --git a/OvmfPkg/Library/PlatformInitLib/MemDetect.c b/OvmfPkg/Library/PlatformInitLib/MemDetect.c
new file mode 100644
index 000000000000..5a9cb6e638ed
--- /dev/null
+++ b/OvmfPkg/Library/PlatformInitLib/MemDetect.c
@@ -0,0 +1,694 @@
+/**@file
+ Memory Detection for Virtual Machines.
+
+ Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+Module Name:
+
+ MemDetect.c
+
+**/
+
+//
+// The package level header files this module uses
+//
+#include <IndustryStandard/E820.h>
+#include <IndustryStandard/I440FxPiix4.h>
+#include <IndustryStandard/Q35MchIch9.h>
+#include <IndustryStandard/CloudHv.h>
+#include <PiPei.h>
+
+//
+// The Library classes this module consumes
+//
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PciLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/ResourcePublicationLib.h>
+#include <Library/MtrrLib.h>
+#include <Library/QemuFwCfgLib.h>
+#include <Library/QemuFwCfgSimpleParserLib.h>
+
+#include <Library/PlatformInitLib.h>
+
+/**
+ * Initializatoin of Qemu UC32Base.
+ *
+ * @param HostBridgeDevId The host bridge Dev Id.
+ * @param LowerMemorySize The lower memory size (under 4G).
+ * @return UINT32 The Qemu UC32 base address.
+ */
+UINT32
+EFIAPI
+PlatformQemuUc32BaseInitialization (
+ IN UINT16 HostBridgeDevId,
+ IN UINT32 LowerMemorySize
+ )
+{
+ UINT32 Uc32Size;
+ UINT32 Uc32Base;
+
+ if (HostBridgeDevId == 0xffff /* microvm */) {
+ return 0;
+ }
+
+ if (HostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
+ //
+ // On q35, the 32-bit area that we'll mark as UC, through variable MTRRs,
+ // starts at PcdPciExpressBaseAddress. The platform DSC is responsible for
+ // setting PcdPciExpressBaseAddress such that describing the
+ // [PcdPciExpressBaseAddress, 4GB) range require a very small number of
+ // variable MTRRs (preferably 1 or 2).
+ //
+
+ ASSERT (FixedPcdGet64 (PcdPciExpressBaseAddress) <= MAX_UINT32);
+ Uc32Base = (UINT32)FixedPcdGet64 (PcdPciExpressBaseAddress);
+ return Uc32Base;
+ }
+
+ if (HostBridgeDevId == CLOUDHV_DEVICE_ID) {
+ Uc32Base = CLOUDHV_MMIO_HOLE_ADDRESS;
+ return Uc32Base;
+ }
+
+ ASSERT (HostBridgeDevId == INTEL_82441_DEVICE_ID);
+ //
+ // On i440fx, start with the [LowerMemorySize, 4GB) range. Make sure one
+ // variable MTRR suffices by truncating the size to a whole power of two,
+ // while keeping the end affixed to 4GB. This will round the base up.
+ //
+ Uc32Size = GetPowerOfTwo32 ((UINT32)(SIZE_4GB - LowerMemorySize));
+ Uc32Base = (UINT32)(SIZE_4GB - Uc32Size);
+ //
+ // Assuming that LowerMemorySize is at least 1 byte, Uc32Size is at most 2GB.
+ // Therefore mQemuUc32Base is at least 2GB.
+ //
+ ASSERT (Uc32Base >= BASE_2GB);
+
+ if (Uc32Base != LowerMemorySize) {
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "%a: rounded UC32 base from 0x%x up to 0x%x, for "
+ "an UC32 size of 0x%x\n",
+ __FUNCTION__,
+ LowerMemorySize,
+ Uc32Base,
+ Uc32Size
+ ));
+ }
+
+ return Uc32Base;
+}
+
+/**
+ Iterate over the RAM entries in QEMU's fw_cfg E820 RAM map that start outside
+ of the 32-bit address range.
+
+ Find the highest exclusive >=4GB RAM address, or produce memory resource
+ descriptor HOBs for RAM entries that start at or above 4GB.
+
+ @param[out] MaxAddress If MaxAddress is NULL, then ScanOrAdd64BitE820Ram()
+ produces memory resource descriptor HOBs for RAM
+ entries that start at or above 4GB.
+
+ Otherwise, MaxAddress holds the highest exclusive
+ >=4GB RAM address on output. If QEMU's fw_cfg E820
+ RAM map contains no RAM entry that starts outside of
+ the 32-bit address range, then MaxAddress is exactly
+ 4GB on output.
+
+ @retval EFI_SUCCESS The fw_cfg E820 RAM map was found and processed.
+
+ @retval EFI_PROTOCOL_ERROR The RAM map was found, but its size wasn't a
+ whole multiple of sizeof(EFI_E820_ENTRY64). No
+ RAM entry was processed.
+
+ @return Error codes from QemuFwCfgFindFile(). No RAM
+ entry was processed.
+**/
+EFI_STATUS
+ScanOrAdd64BitE820Ram (
+ IN BOOLEAN AddHighHob,
+ OUT UINT64 *LowMemory OPTIONAL,
+ OUT UINT64 *MaxAddress OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ FIRMWARE_CONFIG_ITEM FwCfgItem;
+ UINTN FwCfgSize;
+ EFI_E820_ENTRY64 E820Entry;
+ UINTN Processed;
+
+ Status = QemuFwCfgFindFile ("etc/e820", &FwCfgItem, &FwCfgSize);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (FwCfgSize % sizeof E820Entry != 0) {
+ return EFI_PROTOCOL_ERROR;
+ }
+
+ if (LowMemory != NULL) {
+ *LowMemory = 0;
+ }
+
+ if (MaxAddress != NULL) {
+ *MaxAddress = BASE_4GB;
+ }
+
+ QemuFwCfgSelectItem (FwCfgItem);
+ for (Processed = 0; Processed < FwCfgSize; Processed += sizeof E820Entry) {
+ QemuFwCfgReadBytes (sizeof E820Entry, &E820Entry);
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "%a: Base=0x%Lx Length=0x%Lx Type=%u\n",
+ __FUNCTION__,
+ E820Entry.BaseAddr,
+ E820Entry.Length,
+ E820Entry.Type
+ ));
+ if (E820Entry.Type == EfiAcpiAddressRangeMemory) {
+ if (AddHighHob && (E820Entry.BaseAddr >= BASE_4GB)) {
+ UINT64 Base;
+ UINT64 End;
+
+ //
+ // Round up the start address, and round down the end address.
+ //
+ Base = ALIGN_VALUE (E820Entry.BaseAddr, (UINT64)EFI_PAGE_SIZE);
+ End = (E820Entry.BaseAddr + E820Entry.Length) &
+ ~(UINT64)EFI_PAGE_MASK;
+ if (Base < End) {
+ PlatformAddMemoryRangeHob (Base, End);
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "%a: PlatformAddMemoryRangeHob [0x%Lx, 0x%Lx)\n",
+ __FUNCTION__,
+ Base,
+ End
+ ));
+ }
+ }
+
+ if (MaxAddress || LowMemory) {
+ UINT64 Candidate;
+
+ Candidate = E820Entry.BaseAddr + E820Entry.Length;
+ if (MaxAddress && (Candidate > *MaxAddress)) {
+ *MaxAddress = Candidate;
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "%a: MaxAddress=0x%Lx\n",
+ __FUNCTION__,
+ *MaxAddress
+ ));
+ }
+
+ if (LowMemory && (Candidate > *LowMemory) && (Candidate < BASE_4GB)) {
+ *LowMemory = Candidate;
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "%a: LowMemory=0x%Lx\n",
+ __FUNCTION__,
+ *LowMemory
+ ));
+ }
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ * Get the memory size below 4GB.
+ *
+ * @return UINT32 The lower memory size.
+ */
+UINT32
+EFIAPI
+PlatformGetSystemMemorySizeBelow4gb (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT64 LowerMemorySize = 0;
+ UINT8 Cmos0x34;
+ UINT8 Cmos0x35;
+
+ Status = ScanOrAdd64BitE820Ram (FALSE, &LowerMemorySize, NULL);
+ if ((Status == EFI_SUCCESS) && (LowerMemorySize > 0)) {
+ return (UINT32)LowerMemorySize;
+ }
+
+ //
+ // CMOS 0x34/0x35 specifies the system memory above 16 MB.
+ // * CMOS(0x35) is the high byte
+ // * CMOS(0x34) is the low byte
+ // * The size is specified in 64kb chunks
+ // * Since this is memory above 16MB, the 16MB must be added
+ // into the calculation to get the total memory size.
+ //
+
+ Cmos0x34 = (UINT8)PlatformCmosRead8 (0x34);
+ Cmos0x35 = (UINT8)PlatformCmosRead8 (0x35);
+
+ return (UINT32)(((UINTN)((Cmos0x35 << 8) + Cmos0x34) << 16) + SIZE_16MB);
+}
+
+UINT64
+GetSystemMemorySizeAbove4gb (
+ )
+{
+ UINT32 Size;
+ UINTN CmosIndex;
+
+ //
+ // CMOS 0x5b-0x5d specifies the system memory above 4GB MB.
+ // * CMOS(0x5d) is the most significant size byte
+ // * CMOS(0x5c) is the middle size byte
+ // * CMOS(0x5b) is the least significant size byte
+ // * The size is specified in 64kb chunks
+ //
+
+ Size = 0;
+ for (CmosIndex = 0x5d; CmosIndex >= 0x5b; CmosIndex--) {
+ Size = (UINT32)(Size << 8) + (UINT32)PlatformCmosRead8 (CmosIndex);
+ }
+
+ return LShiftU64 (Size, 16);
+}
+
+/**
+ * Return the highest address that DXE could possibly use, plus one.
+ *
+ * @param Pci64Base The 64-bit PCI host aperture base address.
+ * @param Pci64Size The 64-bit PCI host aperture size.
+ * @param DefaultPciMmio64Size The default 64-bit PCI host aperture size.
+ *
+ * @return UINT64 The highest address that DXE could possibly use, plus one.
+ */
+UINT64
+EFIAPI
+PlatformGetFirstNonAddress (
+ OUT UINT64 *Pci64Base,
+ OUT UINT64 *Pci64Size,
+ IN UINT64 DefaultPciMmio64Size
+ )
+{
+ UINT64 FirstNonAddress;
+ UINT32 FwCfgPciMmio64Mb;
+ EFI_STATUS Status;
+ FIRMWARE_CONFIG_ITEM FwCfgItem;
+ UINTN FwCfgSize;
+ UINT64 HotPlugMemoryEnd;
+
+ //
+ // set FirstNonAddress to suppress incorrect compiler/analyzer warnings
+ //
+ FirstNonAddress = 0;
+
+ //
+ // If QEMU presents an E820 map, then get the highest exclusive >=4GB RAM
+ // address from it. This can express an address >= 4GB+1TB.
+ //
+ // Otherwise, get the flat size of the memory above 4GB from the CMOS (which
+ // can only express a size smaller than 1TB), and add it to 4GB.
+ //
+ Status = ScanOrAdd64BitE820Ram (FALSE, NULL, &FirstNonAddress);
+ if (EFI_ERROR (Status)) {
+ FirstNonAddress = BASE_4GB + GetSystemMemorySizeAbove4gb ();
+ }
+
+ //
+ // If DXE is 32-bit, then we're done; PciBusDxe will degrade 64-bit MMIO
+ // resources to 32-bit anyway. See DegradeResource() in
+ // "PciResourceSupport.c".
+ //
+ #ifdef MDE_CPU_IA32
+ if (!FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
+ return FirstNonAddress;
+ }
+
+ #endif
+
+ //
+ // Otherwise, in order to calculate the highest address plus one, we must
+ // consider the 64-bit PCI host aperture too. Fetch the default size.
+ //
+ *Pci64Size = DefaultPciMmio64Size;
+
+ //
+ // See if the user specified the number of megabytes for the 64-bit PCI host
+ // aperture. Accept an aperture size up to 16TB.
+ //
+ // As signaled by the "X-" prefix, this knob is experimental, and might go
+ // away at any time.
+ //
+ Status = QemuFwCfgParseUint32 (
+ "opt/ovmf/X-PciMmio64Mb",
+ FALSE,
+ &FwCfgPciMmio64Mb
+ );
+ switch (Status) {
+ case EFI_UNSUPPORTED:
+ case EFI_NOT_FOUND:
+ break;
+ case EFI_SUCCESS:
+ if (FwCfgPciMmio64Mb <= 0x1000000) {
+ *Pci64Size = LShiftU64 (FwCfgPciMmio64Mb, 20);
+ break;
+ }
+
+ //
+ // fall through
+ //
+ default:
+ DEBUG ((
+ DEBUG_WARN,
+ "%a: ignoring malformed 64-bit PCI host aperture size from fw_cfg\n",
+ __FUNCTION__
+ ));
+ break;
+ }
+
+ if (*Pci64Size == 0) {
+ DEBUG ((
+ DEBUG_INFO,
+ "%a: disabling 64-bit PCI host aperture\n",
+ __FUNCTION__
+ ));
+
+ //
+ // There's nothing more to do; the amount of memory above 4GB fully
+ // determines the highest address plus one. The memory hotplug area (see
+ // below) plays no role for the firmware in this case.
+ //
+ return FirstNonAddress;
+ }
+
+ //
+ // The "etc/reserved-memory-end" fw_cfg file, when present, contains an
+ // absolute, exclusive end address for the memory hotplug area. This area
+ // starts right at the end of the memory above 4GB. The 64-bit PCI host
+ // aperture must be placed above it.
+ //
+ Status = QemuFwCfgFindFile (
+ "etc/reserved-memory-end",
+ &FwCfgItem,
+ &FwCfgSize
+ );
+ if (!EFI_ERROR (Status) && (FwCfgSize == sizeof HotPlugMemoryEnd)) {
+ QemuFwCfgSelectItem (FwCfgItem);
+ QemuFwCfgReadBytes (FwCfgSize, &HotPlugMemoryEnd);
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "%a: HotPlugMemoryEnd=0x%Lx\n",
+ __FUNCTION__,
+ HotPlugMemoryEnd
+ ));
+
+ ASSERT (HotPlugMemoryEnd >= FirstNonAddress);
+ FirstNonAddress = HotPlugMemoryEnd;
+ }
+
+ //
+ // SeaBIOS aligns both boundaries of the 64-bit PCI host aperture to 1GB, so
+ // that the host can map it with 1GB hugepages. Follow suit.
+ //
+ *Pci64Base = ALIGN_VALUE (FirstNonAddress, (UINT64)SIZE_1GB);
+ *Pci64Size = ALIGN_VALUE (*Pci64Size, (UINT64)SIZE_1GB);
+
+ //
+ // The 64-bit PCI host aperture should also be "naturally" aligned. The
+ // alignment is determined by rounding the size of the aperture down to the
+ // next smaller or equal power of two. That is, align the aperture by the
+ // largest BAR size that can fit into it.
+ //
+ *Pci64Base = ALIGN_VALUE (*Pci64Base, GetPowerOfTwo64 (*Pci64Size));
+
+ //
+ // The useful address space ends with the 64-bit PCI host aperture.
+ //
+ FirstNonAddress = *Pci64Base + *Pci64Size;
+ return FirstNonAddress;
+}
+
+/**
+ * Initialize the PhysMemAddressWidth variable, based on guest RAM size.
+ *
+ * @param FirstNonAddress The highest address that DXE could possibly use, plus one.
+ *
+ * @return The physical memory address width based on the guest RAM size.
+ */
+UINT8
+EFIAPI
+PlatformAddressWidthInitialization (
+ IN UINT64 FirstNonAddress
+ )
+{
+ UINT8 PhysMemAddressWidth;
+
+ //
+ // As guest-physical memory size grows, the permanent PEI RAM requirements
+ // are dominated by the identity-mapping page tables built by the DXE IPL.
+ // The DXL IPL keys off of the physical address bits advertized in the CPU
+ // HOB. To conserve memory, we calculate the minimum address width here.
+ //
+ PhysMemAddressWidth = (UINT8)HighBitSet64 (FirstNonAddress);
+
+ //
+ // If FirstNonAddress is not an integral power of two, then we need an
+ // additional bit.
+ //
+ if ((FirstNonAddress & (FirstNonAddress - 1)) != 0) {
+ ++PhysMemAddressWidth;
+ }
+
+ //
+ // The minimum address width is 36 (covers up to and excluding 64 GB, which
+ // is the maximum for Ia32 + PAE). The theoretical architecture maximum for
+ // X64 long mode is 52 bits, but the DXE IPL clamps that down to 48 bits. We
+ // can simply assert that here, since 48 bits are good enough for 256 TB.
+ //
+ if (PhysMemAddressWidth <= 36) {
+ PhysMemAddressWidth = 36;
+ }
+
+ ASSERT (PhysMemAddressWidth <= 48);
+
+ return PhysMemAddressWidth;
+}
+
+VOID
+PlatformQemuInitializeRamBelow1gb (
+ VOID
+ )
+{
+ PlatformAddMemoryRangeHob (0, BASE_512KB + BASE_128KB);
+}
+
+/**
+ Peform Memory Detection for QEMU / KVM
+
+**/
+VOID
+QemuInitializeRam (
+ UINT32 Uc32Base,
+ UINT16 HostBridgeDevId,
+ EFI_BOOT_MODE BootMode,
+ BOOLEAN SmmSmramRequire,
+ UINT32 LowerMemorySize,
+ UINT16 Q35TsegMbytes
+ )
+{
+ UINT64 UpperMemorySize;
+ MTRR_SETTINGS MtrrSettings;
+ EFI_STATUS Status;
+
+ DEBUG ((DEBUG_INFO, "%a called\n", __FUNCTION__));
+
+ if (BootMode == BOOT_ON_S3_RESUME) {
+ //
+ // Create the following memory HOB as an exception on the S3 boot path.
+ //
+ // Normally we'd create memory HOBs only on the normal boot path. However,
+ // CpuMpPei specifically needs such a low-memory HOB on the S3 path as
+ // well, for "borrowing" a subset of it temporarily, for the AP startup
+ // vector.
+ //
+ // CpuMpPei saves the original contents of the borrowed area in permanent
+ // PEI RAM, in a backup buffer allocated with the normal PEI services.
+ // CpuMpPei restores the original contents ("returns" the borrowed area) at
+ // End-of-PEI. End-of-PEI in turn is emitted by S3Resume2Pei before
+ // transferring control to the OS's wakeup vector in the FACS.
+ //
+ // We expect any other PEIMs that "borrow" memory similarly to CpuMpPei to
+ // restore the original contents. Furthermore, we expect all such PEIMs
+ // (CpuMpPei included) to claim the borrowed areas by producing memory
+ // allocation HOBs, and to honor preexistent memory allocation HOBs when
+ // looking for an area to borrow.
+ //
+ PlatformQemuInitializeRamBelow1gb ();
+ } else {
+ //
+ // Create memory HOBs
+ //
+ PlatformQemuInitializeRamBelow1gb ();
+
+ if (SmmSmramRequire) {
+ UINT32 TsegSize;
+
+ TsegSize = Q35TsegMbytes * SIZE_1MB;
+ PlatformAddMemoryRangeHob (BASE_1MB, LowerMemorySize - TsegSize);
+ PlatformAddReservedMemoryBaseSizeHob (
+ LowerMemorySize - TsegSize,
+ TsegSize,
+ TRUE
+ );
+ } else {
+ PlatformAddMemoryRangeHob (BASE_1MB, LowerMemorySize);
+ }
+
+ //
+ // If QEMU presents an E820 map, then create memory HOBs for the >=4GB RAM
+ // entries. Otherwise, create a single memory HOB with the flat >=4GB
+ // memory size read from the CMOS.
+ //
+ Status = ScanOrAdd64BitE820Ram (TRUE, NULL, NULL);
+ if (EFI_ERROR (Status)) {
+ UpperMemorySize = GetSystemMemorySizeAbove4gb ();
+ if (UpperMemorySize != 0) {
+ PlatformAddMemoryBaseSizeHob (BASE_4GB, UpperMemorySize);
+ }
+ }
+ }
+
+ //
+ // We'd like to keep the following ranges uncached:
+ // - [640 KB, 1 MB)
+ // - [LowerMemorySize, 4 GB)
+ //
+ // Everything else should be WB. Unfortunately, programming the inverse (ie.
+ // keeping the default UC, and configuring the complement set of the above as
+ // WB) is not reliable in general, because the end of the upper RAM can have
+ // practically any alignment, and we may not have enough variable MTRRs to
+ // cover it exactly.
+ //
+ if (IsMtrrSupported () && (HostBridgeDevId != CLOUDHV_DEVICE_ID)) {
+ MtrrGetAllMtrrs (&MtrrSettings);
+
+ //
+ // MTRRs disabled, fixed MTRRs disabled, default type is uncached
+ //
+ ASSERT ((MtrrSettings.MtrrDefType & BIT11) == 0);
+ ASSERT ((MtrrSettings.MtrrDefType & BIT10) == 0);
+ ASSERT ((MtrrSettings.MtrrDefType & 0xFF) == 0);
+
+ //
+ // flip default type to writeback
+ //
+ SetMem (&MtrrSettings.Fixed, sizeof MtrrSettings.Fixed, 0x06);
+ ZeroMem (&MtrrSettings.Variables, sizeof MtrrSettings.Variables);
+ MtrrSettings.MtrrDefType |= BIT11 | BIT10 | 6;
+ MtrrSetAllMtrrs (&MtrrSettings);
+
+ //
+ // Set memory range from 640KB to 1MB to uncacheable
+ //
+ Status = MtrrSetMemoryAttribute (
+ BASE_512KB + BASE_128KB,
+ BASE_1MB - (BASE_512KB + BASE_128KB),
+ CacheUncacheable
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Set the memory range from the start of the 32-bit MMIO area (32-bit PCI
+ // MMIO aperture on i440fx, PCIEXBAR on q35) to 4GB as uncacheable.
+ //
+ Status = MtrrSetMemoryAttribute (
+ Uc32Base,
+ SIZE_4GB - Uc32Base,
+ CacheUncacheable
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+}
+
+/**
+ Publish system RAM and reserve memory regions
+
+**/
+VOID
+EFIAPI
+PlatformInitializeRamRegions (
+ IN UINT32 Uc32Base,
+ IN UINT16 HostBridgeDevId,
+ IN BOOLEAN SmmSmramRequire,
+ IN EFI_BOOT_MODE BootMode,
+ IN BOOLEAN S3Supported,
+ IN UINT32 LowerMemorySize,
+ IN UINT16 Q35TsegMbytes
+ )
+{
+ QemuInitializeRam (
+ Uc32Base,
+ HostBridgeDevId,
+ BootMode,
+ SmmSmramRequire,
+ LowerMemorySize,
+ Q35TsegMbytes
+ );
+
+ if (BootMode != BOOT_ON_S3_RESUME) {
+ if (!SmmSmramRequire) {
+ //
+ // Reserve the lock box storage area
+ //
+ // Since this memory range will be used on S3 resume, it must be
+ // reserved as ACPI NVS.
+ //
+ // If S3 is unsupported, then various drivers might still write to the
+ // LockBox area. We ought to prevent DXE from serving allocation requests
+ // such that they would overlap the LockBox storage.
+ //
+ ZeroMem (
+ (VOID *)(UINTN)FixedPcdGet32 (PcdOvmfLockBoxStorageBase),
+ (UINTN)FixedPcdGet32 (PcdOvmfLockBoxStorageSize)
+ );
+ BuildMemoryAllocationHob (
+ (EFI_PHYSICAL_ADDRESS)(UINTN)FixedPcdGet32 (PcdOvmfLockBoxStorageBase),
+ (UINT64)(UINTN)FixedPcdGet32 (PcdOvmfLockBoxStorageSize),
+ S3Supported ? EfiACPIMemoryNVS : EfiBootServicesData
+ );
+ }
+
+ #ifdef MDE_CPU_X64
+ 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
+ );
+ }
+
+ #endif
+ }
+}
diff --git a/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf b/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
index 21813458cb59..6ba1e59246d1 100644
--- a/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
+++ b/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
@@ -24,15 +24,31 @@

[Sources]
Cmos.c
+ MemDetect.c
Platform.c

[Packages]
MdeModulePkg/MdeModulePkg.dec
MdePkg/MdePkg.dec
OvmfPkg/OvmfPkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec

[LibraryClasses]
BaseLib
DebugLib
IoLib
HobLib
+ QemuFwCfgLib
+ QemuFwCfgSimpleParserLib
+ MtrrLib
+ PcdLib
+
+[FixedPcd]
+ gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfWorkAreaBase
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfWorkAreaSize
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageBase
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageSize
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode
--
2.29.2.windows.2


[PATCH V6 20/42] OvmfPkg/PlatformPei: Update hob functions PlatformInitLib

Min Xu
 

RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429

Hob functions in OvmfPkg/PlatformPei are updated with the ones
in PlatformInitLib.

Cc: Ard Biesheuvel <ardb+tianocore@...>
Cc: Jordan Justen <jordan.l.justen@...>
Cc: Brijesh Singh <brijesh.singh@...>
Cc: Erdem Aktas <erdemaktas@...>
Cc: James Bottomley <jejb@...>
Cc: Jiewen Yao <jiewen.yao@...>
Cc: Tom Lendacky <thomas.lendacky@...>
Cc: Gerd Hoffmann <kraxel@...>
Signed-off-by: Min Xu <min.m.xu@...>
---
OvmfPkg/PlatformPei/MemDetect.c | 20 +++----
OvmfPkg/PlatformPei/Platform.c | 101 ++++----------------------------
OvmfPkg/PlatformPei/Platform.h | 31 ----------
3 files changed, 21 insertions(+), 131 deletions(-)

diff --git a/OvmfPkg/PlatformPei/MemDetect.c b/OvmfPkg/PlatformPei/MemDetect.c
index d118dba2f214..d19a344d18b8 100644
--- a/OvmfPkg/PlatformPei/MemDetect.c
+++ b/OvmfPkg/PlatformPei/MemDetect.c
@@ -274,10 +274,10 @@ ScanOrAdd64BitE820Ram (
End = (E820Entry.BaseAddr + E820Entry.Length) &
~(UINT64)EFI_PAGE_MASK;
if (Base < End) {
- AddMemoryRangeHob (Base, End);
+ PlatformAddMemoryRangeHob (Base, End);
DEBUG ((
DEBUG_VERBOSE,
- "%a: AddMemoryRangeHob [0x%Lx, 0x%Lx)\n",
+ "%a: PlatformAddMemoryRangeHob [0x%Lx, 0x%Lx)\n",
__FUNCTION__,
Base,
End
@@ -743,8 +743,8 @@ QemuInitializeRamBelow1gb (
)
{
if (FeaturePcdGet (PcdSmmSmramRequire) && mQ35SmramAtDefaultSmbase) {
- AddMemoryRangeHob (0, SMM_DEFAULT_SMBASE);
- AddReservedMemoryBaseSizeHob (
+ PlatformAddMemoryRangeHob (0, SMM_DEFAULT_SMBASE);
+ PlatformAddReservedMemoryBaseSizeHob (
SMM_DEFAULT_SMBASE,
MCH_DEFAULT_SMBASE_SIZE,
TRUE /* Cacheable */
@@ -753,12 +753,12 @@ QemuInitializeRamBelow1gb (
SMM_DEFAULT_SMBASE + MCH_DEFAULT_SMBASE_SIZE < BASE_512KB + BASE_128KB,
"end of SMRAM at default SMBASE ends at, or exceeds, 640KB"
);
- AddMemoryRangeHob (
+ PlatformAddMemoryRangeHob (
SMM_DEFAULT_SMBASE + MCH_DEFAULT_SMBASE_SIZE,
BASE_512KB + BASE_128KB
);
} else {
- AddMemoryRangeHob (0, BASE_512KB + BASE_128KB);
+ PlatformAddMemoryRangeHob (0, BASE_512KB + BASE_128KB);
}
}

@@ -816,14 +816,14 @@ QemuInitializeRam (
UINT32 TsegSize;

TsegSize = mQ35TsegMbytes * SIZE_1MB;
- AddMemoryRangeHob (BASE_1MB, LowerMemorySize - TsegSize);
- AddReservedMemoryBaseSizeHob (
+ PlatformAddMemoryRangeHob (BASE_1MB, LowerMemorySize - TsegSize);
+ PlatformAddReservedMemoryBaseSizeHob (
LowerMemorySize - TsegSize,
TsegSize,
TRUE
);
} else {
- AddMemoryRangeHob (BASE_1MB, LowerMemorySize);
+ PlatformAddMemoryRangeHob (BASE_1MB, LowerMemorySize);
}

//
@@ -835,7 +835,7 @@ QemuInitializeRam (
if (EFI_ERROR (Status)) {
UpperMemorySize = GetSystemMemorySizeAbove4gb ();
if (UpperMemorySize != 0) {
- AddMemoryBaseSizeHob (BASE_4GB, UpperMemorySize);
+ PlatformAddMemoryBaseSizeHob (BASE_4GB, UpperMemorySize);
}
}
}
diff --git a/OvmfPkg/PlatformPei/Platform.c b/OvmfPkg/PlatformPei/Platform.c
index 594891786440..62480c3c40e5 100644
--- a/OvmfPkg/PlatformPei/Platform.c
+++ b/OvmfPkg/PlatformPei/Platform.c
@@ -57,85 +57,6 @@ BOOLEAN mS3Supported = FALSE;

UINT32 mMaxCpuCount;

-VOID
-AddIoMemoryBaseSizeHob (
- EFI_PHYSICAL_ADDRESS MemoryBase,
- UINT64 MemorySize
- )
-{
- BuildResourceDescriptorHob (
- EFI_RESOURCE_MEMORY_MAPPED_IO,
- EFI_RESOURCE_ATTRIBUTE_PRESENT |
- EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
- EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
- EFI_RESOURCE_ATTRIBUTE_TESTED,
- MemoryBase,
- MemorySize
- );
-}
-
-VOID
-AddReservedMemoryBaseSizeHob (
- EFI_PHYSICAL_ADDRESS MemoryBase,
- UINT64 MemorySize,
- BOOLEAN Cacheable
- )
-{
- BuildResourceDescriptorHob (
- EFI_RESOURCE_MEMORY_RESERVED,
- EFI_RESOURCE_ATTRIBUTE_PRESENT |
- EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
- EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
- (Cacheable ?
- EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
- EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
- EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE :
- 0
- ) |
- EFI_RESOURCE_ATTRIBUTE_TESTED,
- MemoryBase,
- MemorySize
- );
-}
-
-VOID
-AddIoMemoryRangeHob (
- EFI_PHYSICAL_ADDRESS MemoryBase,
- EFI_PHYSICAL_ADDRESS MemoryLimit
- )
-{
- AddIoMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase));
-}
-
-VOID
-AddMemoryBaseSizeHob (
- EFI_PHYSICAL_ADDRESS MemoryBase,
- UINT64 MemorySize
- )
-{
- BuildResourceDescriptorHob (
- EFI_RESOURCE_SYSTEM_MEMORY,
- EFI_RESOURCE_ATTRIBUTE_PRESENT |
- EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
- EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
- EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
- EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
- EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE |
- EFI_RESOURCE_ATTRIBUTE_TESTED,
- MemoryBase,
- MemorySize
- );
-}
-
-VOID
-AddMemoryRangeHob (
- EFI_PHYSICAL_ADDRESS MemoryBase,
- EFI_PHYSICAL_ADDRESS MemoryLimit
- )
-{
- AddMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase));
-}
-
VOID
MemMapInitialization (
VOID
@@ -155,12 +76,12 @@ MemMapInitialization (
//
// Video memory + Legacy BIOS region
//
- AddIoMemoryRangeHob (0x0A0000, BASE_1MB);
+ PlatformAddIoMemoryRangeHob (0x0A0000, BASE_1MB);

if (mHostBridgeDevId == 0xffff /* microvm */) {
- AddIoMemoryBaseSizeHob (MICROVM_GED_MMIO_BASE, SIZE_4KB);
- AddIoMemoryBaseSizeHob (0xFEC00000, SIZE_4KB); /* ioapic #1 */
- AddIoMemoryBaseSizeHob (0xFEC10000, SIZE_4KB); /* ioapic #2 */
+ PlatformAddIoMemoryBaseSizeHob (MICROVM_GED_MMIO_BASE, SIZE_4KB);
+ PlatformAddIoMemoryBaseSizeHob (0xFEC00000, SIZE_4KB); /* ioapic #1 */
+ PlatformAddIoMemoryBaseSizeHob (0xFEC10000, SIZE_4KB); /* ioapic #2 */
return;
}

@@ -194,20 +115,20 @@ MemMapInitialization (
// 0xFEE00000 LAPIC 1 MB
//
PciSize = 0xFC000000 - PciBase;
- AddIoMemoryBaseSizeHob (PciBase, PciSize);
+ PlatformAddIoMemoryBaseSizeHob (PciBase, PciSize);
PcdStatus = PcdSet64S (PcdPciMmio32Base, PciBase);
ASSERT_RETURN_ERROR (PcdStatus);
PcdStatus = PcdSet64S (PcdPciMmio32Size, PciSize);
ASSERT_RETURN_ERROR (PcdStatus);

- AddIoMemoryBaseSizeHob (0xFEC00000, SIZE_4KB);
- AddIoMemoryBaseSizeHob (0xFED00000, SIZE_1KB);
+ PlatformAddIoMemoryBaseSizeHob (0xFEC00000, SIZE_4KB);
+ PlatformAddIoMemoryBaseSizeHob (0xFED00000, SIZE_1KB);
if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
- AddIoMemoryBaseSizeHob (ICH9_ROOT_COMPLEX_BASE, SIZE_16KB);
+ PlatformAddIoMemoryBaseSizeHob (ICH9_ROOT_COMPLEX_BASE, SIZE_16KB);
//
// Note: there should be an
//
- // AddIoMemoryBaseSizeHob (PciExBarBase, SIZE_256MB);
+ // PlatformAddIoMemoryBaseSizeHob (PciExBarBase, SIZE_256MB);
//
// call below, just like the one above for RCBA. However, Linux insists
// that the MMCONFIG area be marked in the E820 or UEFI memory map as
@@ -225,7 +146,7 @@ MemMapInitialization (
// is most definitely not RAM; so, as an exception, cover it with
// uncacheable reserved memory right here.
//
- AddReservedMemoryBaseSizeHob (PciExBarBase, SIZE_256MB, FALSE);
+ PlatformAddReservedMemoryBaseSizeHob (PciExBarBase, SIZE_256MB, FALSE);
BuildMemoryAllocationHob (
PciExBarBase,
SIZE_256MB,
@@ -233,7 +154,7 @@ MemMapInitialization (
);
}

- AddIoMemoryBaseSizeHob (PcdGet32 (PcdCpuLocalApicBaseAddress), SIZE_1MB);
+ PlatformAddIoMemoryBaseSizeHob (PcdGet32 (PcdCpuLocalApicBaseAddress), SIZE_1MB);

//
// On Q35, the IO Port space is available for PCI resource allocations from
diff --git a/OvmfPkg/PlatformPei/Platform.h b/OvmfPkg/PlatformPei/Platform.h
index 24e4da4e1d93..f193ff736549 100644
--- a/OvmfPkg/PlatformPei/Platform.h
+++ b/OvmfPkg/PlatformPei/Platform.h
@@ -11,37 +11,6 @@

#include <IndustryStandard/E820.h>

-VOID
-AddIoMemoryBaseSizeHob (
- EFI_PHYSICAL_ADDRESS MemoryBase,
- UINT64 MemorySize
- );
-
-VOID
-AddIoMemoryRangeHob (
- EFI_PHYSICAL_ADDRESS MemoryBase,
- EFI_PHYSICAL_ADDRESS MemoryLimit
- );
-
-VOID
-AddMemoryBaseSizeHob (
- EFI_PHYSICAL_ADDRESS MemoryBase,
- UINT64 MemorySize
- );
-
-VOID
-AddMemoryRangeHob (
- EFI_PHYSICAL_ADDRESS MemoryBase,
- EFI_PHYSICAL_ADDRESS MemoryLimit
- );
-
-VOID
-AddReservedMemoryBaseSizeHob (
- EFI_PHYSICAL_ADDRESS MemoryBase,
- UINT64 MemorySize,
- BOOLEAN Cacheable
- );
-
VOID
AddressWidthInitialization (
VOID
--
2.29.2.windows.2


[PATCH V6 19/42] OvmfPkg/PlatformInitLib: Add hob functions

Min Xu
 

RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429

In this patch of PlatformInitLib, below hob functions are introduced:
- PlatformAddIoMemoryBaseSizeHob
- PlatformAddIoMemoryRangeHob
- PlatformAddMemoryBaseSizeHob
- PlatformAddMemoryRangeHob
- PlatformAddReservedMemoryBaseSizeHob

They correspond the below functions in OvmfPkg/PlatformPei:
- AddIoMemoryBaseSizeHob
- AddIoMemoryRangeHob
- AddMemoryBaseSizeHob
- AddMemoryRangeHob
- AddReservedMemoryBaseSizeHob

Cc: Ard Biesheuvel <ardb+tianocore@...>
Cc: Jordan Justen <jordan.l.justen@...>
Cc: Brijesh Singh <brijesh.singh@...>
Cc: Erdem Aktas <erdemaktas@...>
Cc: James Bottomley <jejb@...>
Cc: Jiewen Yao <jiewen.yao@...>
Cc: Tom Lendacky <thomas.lendacky@...>
Cc: Gerd Hoffmann <kraxel@...>
Signed-off-by: Min Xu <min.m.xu@...>
---
OvmfPkg/Include/Library/PlatformInitLib.h | 36 ++++++
OvmfPkg/Library/PlatformInitLib/Platform.c | 106 ++++++++++++++++++
.../PlatformInitLib/PlatformInitLib.inf | 2 +
3 files changed, 144 insertions(+)
create mode 100644 OvmfPkg/Library/PlatformInitLib/Platform.c

diff --git a/OvmfPkg/Include/Library/PlatformInitLib.h b/OvmfPkg/Include/Library/PlatformInitLib.h
index af75559e66fa..bc540f549d60 100644
--- a/OvmfPkg/Include/Library/PlatformInitLib.h
+++ b/OvmfPkg/Include/Library/PlatformInitLib.h
@@ -63,4 +63,40 @@ PlatformDebugDumpCmos (
VOID
);

+VOID
+EFIAPI
+PlatformAddIoMemoryBaseSizeHob (
+ IN EFI_PHYSICAL_ADDRESS MemoryBase,
+ IN UINT64 MemorySize
+ );
+
+VOID
+EFIAPI
+PlatformAddIoMemoryRangeHob (
+ IN EFI_PHYSICAL_ADDRESS MemoryBase,
+ IN EFI_PHYSICAL_ADDRESS MemoryLimit
+ );
+
+VOID
+EFIAPI
+PlatformAddMemoryBaseSizeHob (
+ IN EFI_PHYSICAL_ADDRESS MemoryBase,
+ IN UINT64 MemorySize
+ );
+
+VOID
+EFIAPI
+PlatformAddMemoryRangeHob (
+ IN EFI_PHYSICAL_ADDRESS MemoryBase,
+ IN EFI_PHYSICAL_ADDRESS MemoryLimit
+ );
+
+VOID
+EFIAPI
+PlatformAddReservedMemoryBaseSizeHob (
+ IN EFI_PHYSICAL_ADDRESS MemoryBase,
+ IN UINT64 MemorySize,
+ IN BOOLEAN Cacheable
+ );
+
#endif // PLATFORM_INIT_LIB_H_
diff --git a/OvmfPkg/Library/PlatformInitLib/Platform.c b/OvmfPkg/Library/PlatformInitLib/Platform.c
new file mode 100644
index 000000000000..e41f230ff563
--- /dev/null
+++ b/OvmfPkg/Library/PlatformInitLib/Platform.c
@@ -0,0 +1,106 @@
+/**@file
+
+ Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2011, Andrei Warkentin <andreiw@...>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+//
+// The package level header files this module uses
+//
+#include <PiPei.h>
+
+//
+// The Library classes this module consumes
+//
+#include <Library/BaseMemoryLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/PlatformInitLib.h>
+
+VOID
+EFIAPI
+PlatformAddIoMemoryBaseSizeHob (
+ IN EFI_PHYSICAL_ADDRESS MemoryBase,
+ IN UINT64 MemorySize
+ )
+{
+ BuildResourceDescriptorHob (
+ EFI_RESOURCE_MEMORY_MAPPED_IO,
+ EFI_RESOURCE_ATTRIBUTE_PRESENT |
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
+ EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
+ EFI_RESOURCE_ATTRIBUTE_TESTED,
+ MemoryBase,
+ MemorySize
+ );
+}
+
+VOID
+EFIAPI
+PlatformAddReservedMemoryBaseSizeHob (
+ IN EFI_PHYSICAL_ADDRESS MemoryBase,
+ IN UINT64 MemorySize,
+ IN BOOLEAN Cacheable
+ )
+{
+ BuildResourceDescriptorHob (
+ EFI_RESOURCE_MEMORY_RESERVED,
+ EFI_RESOURCE_ATTRIBUTE_PRESENT |
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
+ EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
+ (Cacheable ?
+ EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE :
+ 0
+ ) |
+ EFI_RESOURCE_ATTRIBUTE_TESTED,
+ MemoryBase,
+ MemorySize
+ );
+}
+
+VOID
+EFIAPI
+PlatformAddIoMemoryRangeHob (
+ IN EFI_PHYSICAL_ADDRESS MemoryBase,
+ IN EFI_PHYSICAL_ADDRESS MemoryLimit
+ )
+{
+ PlatformAddIoMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase));
+}
+
+VOID
+EFIAPI
+PlatformAddMemoryBaseSizeHob (
+ IN EFI_PHYSICAL_ADDRESS MemoryBase,
+ IN UINT64 MemorySize
+ )
+{
+ BuildResourceDescriptorHob (
+ EFI_RESOURCE_SYSTEM_MEMORY,
+ EFI_RESOURCE_ATTRIBUTE_PRESENT |
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
+ EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE |
+ EFI_RESOURCE_ATTRIBUTE_TESTED,
+ MemoryBase,
+ MemorySize
+ );
+}
+
+VOID
+EFIAPI
+PlatformAddMemoryRangeHob (
+ IN EFI_PHYSICAL_ADDRESS MemoryBase,
+ IN EFI_PHYSICAL_ADDRESS MemoryLimit
+ )
+{
+ PlatformAddMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase));
+}
diff --git a/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf b/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
index 4ea2da86274f..21813458cb59 100644
--- a/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
+++ b/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
@@ -24,6 +24,7 @@

[Sources]
Cmos.c
+ Platform.c

[Packages]
MdeModulePkg/MdeModulePkg.dec
@@ -34,3 +35,4 @@
BaseLib
DebugLib
IoLib
+ HobLib
--
2.29.2.windows.2


[PATCH V6 18/42] OvmfPkg/PlatformPei: Update Cmos functions with PlatformInitLib

Min Xu
 

RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429

Update the Cmos functions in OvmfPkg/PlatformPei with PlatformInitLib.

Cc: Ard Biesheuvel <ardb+tianocore@...>
Cc: Jordan Justen <jordan.l.justen@...>
Cc: Brijesh Singh <brijesh.singh@...>
Cc: Erdem Aktas <erdemaktas@...>
Cc: James Bottomley <jejb@...>
Cc: Jiewen Yao <jiewen.yao@...>
Cc: Tom Lendacky <thomas.lendacky@...>
Cc: Gerd Hoffmann <kraxel@...>
Signed-off-by: Min Xu <min.m.xu@...>
---
OvmfPkg/AmdSev/AmdSevX64.dsc | 1 +
OvmfPkg/CloudHv/CloudHvX64.dsc | 1 +
OvmfPkg/Microvm/MicrovmX64.dsc | 1 +
OvmfPkg/OvmfPkgIa32.dsc | 1 +
OvmfPkg/OvmfPkgIa32X64.dsc | 1 +
OvmfPkg/OvmfPkgX64.dsc | 1 +
OvmfPkg/PlatformPei/Cmos.c | 55 -----------------------------
OvmfPkg/PlatformPei/Cmos.h | 48 -------------------------
OvmfPkg/PlatformPei/MemDetect.c | 8 ++---
OvmfPkg/PlatformPei/Platform.c | 29 +++------------
OvmfPkg/PlatformPei/PlatformPei.inf | 3 +-
11 files changed, 15 insertions(+), 134 deletions(-)
delete mode 100644 OvmfPkg/PlatformPei/Cmos.c
delete mode 100644 OvmfPkg/PlatformPei/Cmos.h

diff --git a/OvmfPkg/AmdSev/AmdSevX64.dsc b/OvmfPkg/AmdSev/AmdSevX64.dsc
index fd56176796d5..785049c88962 100644
--- a/OvmfPkg/AmdSev/AmdSevX64.dsc
+++ b/OvmfPkg/AmdSev/AmdSevX64.dsc
@@ -280,6 +280,7 @@
!include OvmfPkg/OvmfTpmLibsPeim.dsc.inc

MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf
+ PlatformInitLib|OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf

[LibraryClasses.common.DXE_CORE]
HobLib|MdePkg/Library/DxeCoreHobLib/DxeCoreHobLib.inf
diff --git a/OvmfPkg/CloudHv/CloudHvX64.dsc b/OvmfPkg/CloudHv/CloudHvX64.dsc
index 3172100310b1..e821a72f000c 100644
--- a/OvmfPkg/CloudHv/CloudHvX64.dsc
+++ b/OvmfPkg/CloudHv/CloudHvX64.dsc
@@ -307,6 +307,7 @@
!include OvmfPkg/OvmfTpmLibsPeim.dsc.inc

MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf
+ PlatformInitLib|OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf

[LibraryClasses.common.DXE_CORE]
HobLib|MdePkg/Library/DxeCoreHobLib/DxeCoreHobLib.inf
diff --git a/OvmfPkg/Microvm/MicrovmX64.dsc b/OvmfPkg/Microvm/MicrovmX64.dsc
index 1ea43443ae97..27005eec89f2 100644
--- a/OvmfPkg/Microvm/MicrovmX64.dsc
+++ b/OvmfPkg/Microvm/MicrovmX64.dsc
@@ -300,6 +300,7 @@
QemuFwCfgLib|OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPeiLib.inf

MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf
+ PlatformInitLib|OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf

[LibraryClasses.common.DXE_CORE]
HobLib|MdePkg/Library/DxeCoreHobLib/DxeCoreHobLib.inf
diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
index 85abed24c1a7..8f02dca63869 100644
--- a/OvmfPkg/OvmfPkgIa32.dsc
+++ b/OvmfPkg/OvmfPkgIa32.dsc
@@ -300,6 +300,7 @@
QemuFwCfgS3Lib|OvmfPkg/Library/QemuFwCfgS3Lib/PeiQemuFwCfgS3LibFwCfg.inf
PcdLib|MdePkg/Library/PeiPcdLib/PeiPcdLib.inf
QemuFwCfgLib|OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPeiLib.inf
+ PlatformInitLib|OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf

!include OvmfPkg/OvmfTpmLibsPeim.dsc.inc

diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index a9c1daecc1a8..c58ef8494470 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -304,6 +304,7 @@
QemuFwCfgS3Lib|OvmfPkg/Library/QemuFwCfgS3Lib/PeiQemuFwCfgS3LibFwCfg.inf
PcdLib|MdePkg/Library/PeiPcdLib/PeiPcdLib.inf
QemuFwCfgLib|OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPeiLib.inf
+ PlatformInitLib|OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf

!include OvmfPkg/OvmfTpmLibsPeim.dsc.inc

diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index 718399299f57..227b9845619f 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -305,6 +305,7 @@
QemuFwCfgS3Lib|OvmfPkg/Library/QemuFwCfgS3Lib/PeiQemuFwCfgS3LibFwCfg.inf
PcdLib|MdePkg/Library/PeiPcdLib/PeiPcdLib.inf
QemuFwCfgLib|OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPeiLib.inf
+ PlatformInitLib|OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf

!include OvmfPkg/OvmfTpmLibsPeim.dsc.inc

diff --git a/OvmfPkg/PlatformPei/Cmos.c b/OvmfPkg/PlatformPei/Cmos.c
deleted file mode 100644
index a01b3866bee4..000000000000
--- a/OvmfPkg/PlatformPei/Cmos.c
+++ /dev/null
@@ -1,55 +0,0 @@
-/** @file
- PC/AT CMOS access routines
-
- Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "Cmos.h"
-#include "Library/IoLib.h"
-
-/**
- Reads 8-bits of CMOS data.
-
- Reads the 8-bits of CMOS data at the location specified by Index.
- The 8-bit read value is returned.
-
- @param Index The CMOS location to read.
-
- @return The value read.
-
-**/
-UINT8
-EFIAPI
-CmosRead8 (
- IN UINTN Index
- )
-{
- IoWrite8 (0x70, (UINT8)Index);
- return IoRead8 (0x71);
-}
-
-/**
- Writes 8-bits of CMOS data.
-
- Writes 8-bits of CMOS data to the location specified by Index
- with the value specified by Value and returns Value.
-
- @param Index The CMOS location to write.
- @param Value The value to write to CMOS.
-
- @return The value written to CMOS.
-
-**/
-UINT8
-EFIAPI
-CmosWrite8 (
- IN UINTN Index,
- IN UINT8 Value
- )
-{
- IoWrite8 (0x70, (UINT8)Index);
- IoWrite8 (0x71, Value);
- return Value;
-}
diff --git a/OvmfPkg/PlatformPei/Cmos.h b/OvmfPkg/PlatformPei/Cmos.h
deleted file mode 100644
index 2b3124d7ba36..000000000000
--- a/OvmfPkg/PlatformPei/Cmos.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/** @file
- PC/AT CMOS access routines
-
- Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef __CMOS_H__
-#define __CMOS_H__
-
-/**
- Reads 8-bits of CMOS data.
-
- Reads the 8-bits of CMOS data at the location specified by Index.
- The 8-bit read value is returned.
-
- @param Index The CMOS location to read.
-
- @return The value read.
-
-**/
-UINT8
-EFIAPI
-CmosRead8 (
- IN UINTN Index
- );
-
-/**
- Writes 8-bits of CMOS data.
-
- Writes 8-bits of CMOS data to the location specified by Index
- with the value specified by Value and returns Value.
-
- @param Index The CMOS location to write.
- @param Value The value to write to CMOS.
-
- @return The value written to CMOS.
-
-**/
-UINT8
-EFIAPI
-CmosWrite8 (
- IN UINTN Index,
- IN UINT8 Value
- );
-
-#endif
diff --git a/OvmfPkg/PlatformPei/MemDetect.c b/OvmfPkg/PlatformPei/MemDetect.c
index 1bcb5a08bca6..d118dba2f214 100644
--- a/OvmfPkg/PlatformPei/MemDetect.c
+++ b/OvmfPkg/PlatformPei/MemDetect.c
@@ -36,9 +36,9 @@ Module Name:
#include <Library/MtrrLib.h>
#include <Library/QemuFwCfgLib.h>
#include <Library/QemuFwCfgSimpleParserLib.h>
+#include <Library/PlatformInitLib.h>

#include "Platform.h"
-#include "Cmos.h"

UINT8 mPhysMemAddressWidth;

@@ -339,8 +339,8 @@ GetSystemMemorySizeBelow4gb (
// into the calculation to get the total memory size.
//

- Cmos0x34 = (UINT8)CmosRead8 (0x34);
- Cmos0x35 = (UINT8)CmosRead8 (0x35);
+ Cmos0x34 = (UINT8)PlatformCmosRead8 (0x34);
+ Cmos0x35 = (UINT8)PlatformCmosRead8 (0x35);

return (UINT32)(((UINTN)((Cmos0x35 << 8) + Cmos0x34) << 16) + SIZE_16MB);
}
@@ -363,7 +363,7 @@ GetSystemMemorySizeAbove4gb (

Size = 0;
for (CmosIndex = 0x5d; CmosIndex >= 0x5b; CmosIndex--) {
- Size = (UINT32)(Size << 8) + (UINT32)CmosRead8 (CmosIndex);
+ Size = (UINT32)(Size << 8) + (UINT32)PlatformCmosRead8 (CmosIndex);
}

return LShiftU64 (Size, 16);
diff --git a/OvmfPkg/PlatformPei/Platform.c b/OvmfPkg/PlatformPei/Platform.c
index d0323c645162..594891786440 100644
--- a/OvmfPkg/PlatformPei/Platform.c
+++ b/OvmfPkg/PlatformPei/Platform.c
@@ -36,10 +36,10 @@
#include <IndustryStandard/Pci22.h>
#include <IndustryStandard/Q35MchIch9.h>
#include <IndustryStandard/QemuCpuHotplug.h>
+#include <Library/PlatformInitLib.h>
#include <OvmfPlatforms.h>

#include "Platform.h"
-#include "Cmos.h"

EFI_PEI_PPI_DESCRIPTOR mPpiBootMode[] = {
{
@@ -505,11 +505,11 @@ BootModeInitialization (
{
EFI_STATUS Status;

- if (CmosRead8 (0xF) == 0xFE) {
+ if (PlatformCmosRead8 (0xF) == 0xFE) {
mBootMode = BOOT_ON_S3_RESUME;
}

- CmosWrite8 (0xF, 0x00);
+ PlatformCmosWrite8 (0xF, 0x00);

Status = PeiServicesSetBootMode (mBootMode);
ASSERT_EFI_ERROR (Status);
@@ -546,27 +546,6 @@ ReserveEmuVariableNvStore (
ASSERT_RETURN_ERROR (PcdStatus);
}

-VOID
-DebugDumpCmos (
- VOID
- )
-{
- UINT32 Loop;
-
- DEBUG ((DEBUG_INFO, "CMOS:\n"));
-
- for (Loop = 0; Loop < 0x80; Loop++) {
- if ((Loop % 0x10) == 0) {
- DEBUG ((DEBUG_INFO, "%02x:", Loop));
- }
-
- DEBUG ((DEBUG_INFO, " %02x", CmosRead8 (Loop)));
- if ((Loop % 0x10) == 0xf) {
- DEBUG ((DEBUG_INFO, "\n"));
- }
- }
-}
-
VOID
S3Verification (
VOID
@@ -810,7 +789,7 @@ InitializePlatform (

DEBUG ((DEBUG_INFO, "Platform PEIM Loaded\n"));

- DebugDumpCmos ();
+ PlatformDebugDumpCmos ();

if (QemuFwCfgS3Enabled ()) {
DEBUG ((DEBUG_INFO, "S3 support was detected on QEMU\n"));
diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf
index 8ef404168c45..65e417b2f254 100644
--- a/OvmfPkg/PlatformPei/PlatformPei.inf
+++ b/OvmfPkg/PlatformPei/PlatformPei.inf
@@ -25,8 +25,6 @@
[Sources]
AmdSev.c
ClearCache.c
- Cmos.c
- Cmos.h
FeatureControl.c
Fv.c
MemDetect.c
@@ -64,6 +62,7 @@
MemEncryptSevLib
PcdLib
VmgExitLib
+ PlatformInitLib

[Pcd]
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfPeiMemFvBase
--
2.29.2.windows.2


[PATCH V6 17/42] OvmfPkg: Create initial version of PlatformInitLib

Min Xu
 

RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429

There are 3 variants of PlatformPei in OvmfPkg:
- OvmfPkg/PlatformPei
- OvmfPkg/XenPlatformPei
- OvmfPkg/Bhyve/PlatformPei/PlatformPei.inf
These PlatformPeis can share many common codes, such as
Cmos / Hob / Memory / Platform related functions. This commit
(and its following several patches) are to create a PlatformInitLib
which wraps the common code called in above PlatformPeis.

Considering this PlatformInitLib will be used in SEC phase, global
variables and dynamic PCDs will be avoided. This lib will not handle
the situation of SMM / S3 either.

In this initial version of PlatformInitLib, below Cmos related functions
are introduced:
- PlatformCmosRead8
- PlatformCmosWrite8
- PlatformDebugDumpCmos

They correspond to the functions in OvmfPkg/PlatformPei:
- CmosRead8
- CmosWrite8
- DebugDumpCmos

EFI_HOB_PLATFORM_INFO is also defined in this patch which is used to
pass the platform information in Hob to Dxe phase.

Cc: Ard Biesheuvel <ardb+tianocore@...>
Cc: Jordan Justen <jordan.l.justen@...>
Cc: Brijesh Singh <brijesh.singh@...>
Cc: Erdem Aktas <erdemaktas@...>
Cc: James Bottomley <jejb@...>
Cc: Jiewen Yao <jiewen.yao@...>
Cc: Tom Lendacky <thomas.lendacky@...>
Cc: Gerd Hoffmann <kraxel@...>
Signed-off-by: Min Xu <min.m.xu@...>
---
OvmfPkg/Include/Library/PlatformInitLib.h | 66 +++++++++++++++
OvmfPkg/Library/PlatformInitLib/Cmos.c | 81 +++++++++++++++++++
.../PlatformInitLib/PlatformInitLib.inf | 36 +++++++++
OvmfPkg/OvmfPkg.dec | 4 +
4 files changed, 187 insertions(+)
create mode 100644 OvmfPkg/Include/Library/PlatformInitLib.h
create mode 100644 OvmfPkg/Library/PlatformInitLib/Cmos.c
create mode 100644 OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf

diff --git a/OvmfPkg/Include/Library/PlatformInitLib.h b/OvmfPkg/Include/Library/PlatformInitLib.h
new file mode 100644
index 000000000000..af75559e66fa
--- /dev/null
+++ b/OvmfPkg/Include/Library/PlatformInitLib.h
@@ -0,0 +1,66 @@
+/** @file
+ PlatformInitLib header file.
+
+ Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef PLATFORM_INIT_LIB_H_
+#define PLATFORM_INIT_LIB_H_
+
+#include <PiPei.h>
+
+#pragma pack(1)
+typedef struct {
+ EFI_HOB_GUID_TYPE GuidHeader;
+ UINT16 HostBridgePciDevId;
+} EFI_HOB_PLATFORM_INFO;
+#pragma pack()
+
+/**
+ Reads 8-bits of CMOS data.
+
+ Reads the 8-bits of CMOS data at the location specified by Index.
+ The 8-bit read value is returned.
+
+ @param Index The CMOS location to read.
+
+ @return The value read.
+
+**/
+UINT8
+EFIAPI
+PlatformCmosRead8 (
+ IN UINTN Index
+ );
+
+/**
+ Writes 8-bits of CMOS data.
+
+ Writes 8-bits of CMOS data to the location specified by Index
+ with the value specified by Value and returns Value.
+
+ @param Index The CMOS location to write.
+ @param Value The value to write to CMOS.
+
+ @return The value written to CMOS.
+
+**/
+UINT8
+EFIAPI
+PlatformCmosWrite8 (
+ IN UINTN Index,
+ IN UINT8 Value
+ );
+
+/**
+ Dump the CMOS content
+ */
+VOID
+EFIAPI
+PlatformDebugDumpCmos (
+ VOID
+ );
+
+#endif // PLATFORM_INIT_LIB_H_
diff --git a/OvmfPkg/Library/PlatformInitLib/Cmos.c b/OvmfPkg/Library/PlatformInitLib/Cmos.c
new file mode 100644
index 000000000000..977aa97aea8c
--- /dev/null
+++ b/OvmfPkg/Library/PlatformInitLib/Cmos.c
@@ -0,0 +1,81 @@
+/** @file
+ PC/AT CMOS access routines
+
+ Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/PlatformInitLib.h>
+#include <Library/DebugLib.h>
+#include "Library/IoLib.h"
+
+/**
+ Reads 8-bits of CMOS data.
+
+ Reads the 8-bits of CMOS data at the location specified by Index.
+ The 8-bit read value is returned.
+
+ @param Index The CMOS location to read.
+
+ @return The value read.
+
+**/
+UINT8
+EFIAPI
+PlatformCmosRead8 (
+ IN UINTN Index
+ )
+{
+ IoWrite8 (0x70, (UINT8)Index);
+ return IoRead8 (0x71);
+}
+
+/**
+ Writes 8-bits of CMOS data.
+
+ Writes 8-bits of CMOS data to the location specified by Index
+ with the value specified by Value and returns Value.
+
+ @param Index The CMOS location to write.
+ @param Value The value to write to CMOS.
+
+ @return The value written to CMOS.
+
+**/
+UINT8
+EFIAPI
+PlatformCmosWrite8 (
+ IN UINTN Index,
+ IN UINT8 Value
+ )
+{
+ IoWrite8 (0x70, (UINT8)Index);
+ IoWrite8 (0x71, Value);
+ return Value;
+}
+
+/**
+ Dump the CMOS content
+ */
+VOID
+EFIAPI
+PlatformDebugDumpCmos (
+ VOID
+ )
+{
+ UINT32 Loop;
+
+ DEBUG ((DEBUG_INFO, "CMOS:\n"));
+
+ for (Loop = 0; Loop < 0x80; Loop++) {
+ if ((Loop % 0x10) == 0) {
+ DEBUG ((DEBUG_INFO, "%02x:", Loop));
+ }
+
+ DEBUG ((DEBUG_INFO, " %02x", PlatformCmosRead8 (Loop)));
+ if ((Loop % 0x10) == 0xf) {
+ DEBUG ((DEBUG_INFO, "\n"));
+ }
+ }
+}
diff --git a/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf b/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
new file mode 100644
index 000000000000..4ea2da86274f
--- /dev/null
+++ b/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
@@ -0,0 +1,36 @@
+## @file
+# Platform Initialization Lib
+#
+# This module provides platform specific function to detect boot mode.
+# Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PlatformInitLib
+ FILE_GUID = 89f886b0-7109-46e1-9d28-503ad4ab6ee0
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PlatformInitLib|PEIM
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ Cmos.c
+
+[Packages]
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+ OvmfPkg/OvmfPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ IoLib
diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index d373b5d6042e..61635c73c761 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -113,6 +113,10 @@
#
TdxMailboxLib|Include/Library/TdxMailboxLib.h

+ ## @libraryclass PlatformInitLib
+ #
+ PlatformInitLib|Include/Library/PlatformInitLib.h
+
[Guids]
gUefiOvmfPkgTokenSpaceGuid = {0x93bb96af, 0xb9f2, 0x4eb8, {0x94, 0x62, 0xe0, 0xba, 0x74, 0x56, 0x42, 0x36}}
gEfiXenInfoGuid = {0xd3b46f3b, 0xd441, 0x1244, {0x9a, 0x12, 0x0, 0x12, 0x27, 0x3f, 0xc1, 0x4d}}
--
2.29.2.windows.2


[PATCH V6 16/42] MdePkg: Add EFI_RESOURCE_ATTRIBUTE_ENCRYPTED in PiHob.h

Min Xu
 

RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429

EFI_RESOURCE_ATTRIBUTE_ENCRYPTED is Physical memory encrypted attribute.
It indicates the memory uses platform encrpytion capabilities for
protection. If this bit is clear, the memory does not use platform
encryption protection.

Cc: Ard Biesheuvel <ardb+tianocore@...>
Cc: Jordan Justen <jordan.l.justen@...>
Cc: Brijesh Singh <brijesh.singh@...>
Cc: Erdem Aktas <erdemaktas@...>
Cc: James Bottomley <jejb@...>
Cc: Jiewen Yao <jiewen.yao@...>
Cc: Tom Lendacky <thomas.lendacky@...>
Signed-off-by: Min Xu <min.m.xu@...>
---
MdePkg/Include/Pi/PiHob.h | 8 ++++++++
1 file changed, 8 insertions(+)

diff --git a/MdePkg/Include/Pi/PiHob.h b/MdePkg/Include/Pi/PiHob.h
index e9f0ab4309d1..5bb7fc843112 100644
--- a/MdePkg/Include/Pi/PiHob.h
+++ b/MdePkg/Include/Pi/PiHob.h
@@ -296,6 +296,14 @@ typedef UINT32 EFI_RESOURCE_ATTRIBUTE_TYPE;
//
#define EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE 0x02000000

+//
+// Physical memory encrypted attribute. This
+// memory uses platform encrpytion capabilities for
+// protection. If this bit is clear, the memory does
+// not use platform encryption protection
+//
+#define EFI_RESOURCE_ATTRIBUTE_ENCRYPTED 0x04000000
+
///
/// Describes the resource properties of all fixed,
/// nonrelocatable resource ranges found on the processor
--
2.29.2.windows.2


[PATCH V6 15/42] OvmfPkg: Add TdxMailboxLib

Min Xu
 

RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429

In Tdx BSP may issues commands to APs for some task, for example, to
accept pages paralelly. BSP also need to wait until all the APs have
done the task. TdxMailboxLib wraps these common funtions for BSP.

Cc: Ard Biesheuvel <ardb+tianocore@...>
Cc: Jordan Justen <jordan.l.justen@...>
Cc: Brijesh Singh <brijesh.singh@...>
Cc: Erdem Aktas <erdemaktas@...>
Cc: James Bottomley <jejb@...>
Cc: Jiewen Yao <jiewen.yao@...>
Cc: Tom Lendacky <thomas.lendacky@...>
Cc: Gerd Hoffmann <kraxel@...>
Acked-by: Gerd Hoffmann <kraxel@...>
Signed-off-by: Min Xu <min.m.xu@...>
---
OvmfPkg/Include/Library/TdxMailboxLib.h | 76 ++++++++++
OvmfPkg/Library/TdxMailboxLib/TdxMailbox.c | 140 ++++++++++++++++++
.../Library/TdxMailboxLib/TdxMailboxLib.inf | 52 +++++++
.../Library/TdxMailboxLib/TdxMailboxNull.c | 85 +++++++++++
OvmfPkg/OvmfPkg.dec | 4 +
5 files changed, 357 insertions(+)
create mode 100644 OvmfPkg/Include/Library/TdxMailboxLib.h
create mode 100644 OvmfPkg/Library/TdxMailboxLib/TdxMailbox.c
create mode 100644 OvmfPkg/Library/TdxMailboxLib/TdxMailboxLib.inf
create mode 100644 OvmfPkg/Library/TdxMailboxLib/TdxMailboxNull.c

diff --git a/OvmfPkg/Include/Library/TdxMailboxLib.h b/OvmfPkg/Include/Library/TdxMailboxLib.h
new file mode 100644
index 000000000000..166cab43bc02
--- /dev/null
+++ b/OvmfPkg/Include/Library/TdxMailboxLib.h
@@ -0,0 +1,76 @@
+/** @file
+
+ Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef TDX_MAILBOX_LIB_H_
+#define TDX_MAILBOX_LIB_H_
+
+#include <Library/BaseLib.h>
+#include <Uefi/UefiBaseType.h>
+#include <Uefi/UefiSpec.h>
+#include <Pi/PiPeiCis.h>
+#include <Library/DebugLib.h>
+#include <Protocol/DebugSupport.h>
+
+/**
+ This function will be called by BSP to get the CPU number.
+
+ @retval CPU number
+**/
+UINT32
+EFIAPI
+GetCpusNum (
+ VOID
+ );
+
+/**
+ Get the address of Td mailbox.
+**/
+volatile VOID *
+EFIAPI
+GetTdxMailBox (
+ VOID
+ );
+
+/**
+ This function will be called by BSP to wakeup APs the are spinning on mailbox
+ in protected mode
+
+ @param[in] Command Command to send APs
+ @param[in] WakeupVector If used, address for APs to start executing
+ @param[in] WakeArgsX Args to pass to APs for excuting commands
+**/
+VOID
+EFIAPI
+MpSendWakeupCommand (
+ IN UINT16 Command,
+ IN UINT64 WakeupVector,
+ IN UINT64 WakeupArgs1,
+ IN UINT64 WakeupArgs2,
+ IN UINT64 WakeupArgs3,
+ IN UINT64 WakeupArgs4
+ );
+
+/**
+ BSP wait until all the APs arriving. It means the task triggered by BSP is started.
+**/
+VOID
+EFIAPI
+MpSerializeStart (
+ VOID
+ );
+
+/**
+ BSP wait until all the APs arriving. It means the task triggered by BSP is ended.
+**/
+VOID
+EFIAPI
+MpSerializeEnd (
+ VOID
+ );
+
+#endif
diff --git a/OvmfPkg/Library/TdxMailboxLib/TdxMailbox.c b/OvmfPkg/Library/TdxMailboxLib/TdxMailbox.c
new file mode 100644
index 000000000000..13612dc141e3
--- /dev/null
+++ b/OvmfPkg/Library/TdxMailboxLib/TdxMailbox.c
@@ -0,0 +1,140 @@
+/** @file
+
+ Copyright (c) 2008, Intel Corporation. All rights reserved.<BR>
+ (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiCpuLib.h>
+#include <Library/SynchronizationLib.h>
+#include <Library/TdxLib.h>
+#include <IndustryStandard/IntelTdx.h>
+#include <IndustryStandard/Tdx.h>
+#include <Library/TdxMailboxLib.h>
+
+volatile VOID *mMailBox = NULL;
+UINT32 mNumOfCpus = 0;
+
+/**
+ This function will be called by BSP to get the CPU number.
+
+ @retval CPU number
+**/
+UINT32
+EFIAPI
+GetCpusNum (
+ VOID
+ )
+{
+ if (mNumOfCpus == 0) {
+ mNumOfCpus = TdVCpuNum ();
+ }
+
+ return mNumOfCpus;
+}
+
+/**
+ Get the address of Td mailbox.
+**/
+volatile VOID *
+EFIAPI
+GetTdxMailBox (
+ VOID
+ )
+{
+ if (mMailBox == NULL) {
+ mMailBox = (VOID *)(UINTN)PcdGet32 (PcdOvmfSecGhcbBackupBase);
+ }
+
+ return mMailBox;
+}
+
+/**
+ This function will be called by BSP to wakeup APs the are spinning on mailbox
+ in protected mode
+
+ @param[in] Command Command to send APs
+ @param[in] WakeupVector If used, address for APs to start executing
+ @param[in] WakeArgsX Args to pass to APs for excuting commands
+**/
+VOID
+EFIAPI
+MpSendWakeupCommand (
+ IN UINT16 Command,
+ IN UINT64 WakeupVector,
+ IN UINT64 WakeupArgs1,
+ IN UINT64 WakeupArgs2,
+ IN UINT64 WakeupArgs3,
+ IN UINT64 WakeupArgs4
+ )
+{
+ volatile MP_WAKEUP_MAILBOX *MailBox;
+
+ MailBox = (volatile MP_WAKEUP_MAILBOX *)GetTdxMailBox ();
+ MailBox->ApicId = MP_CPU_PROTECTED_MODE_MAILBOX_APICID_INVALID;
+ MailBox->WakeUpVector = 0;
+ MailBox->Command = MpProtectedModeWakeupCommandNoop;
+ MailBox->ApicId = MP_CPU_PROTECTED_MODE_MAILBOX_APICID_BROADCAST;
+ MailBox->WakeUpVector = WakeupVector;
+ MailBox->WakeUpArgs1 = WakeupArgs1;
+ MailBox->WakeUpArgs2 = WakeupArgs2;
+ MailBox->WakeUpArgs3 = WakeupArgs3;
+ MailBox->WakeUpArgs4 = WakeupArgs4;
+ AsmCpuid (0x01, NULL, NULL, NULL, NULL);
+ MailBox->Command = Command;
+ AsmCpuid (0x01, NULL, NULL, NULL, NULL);
+ return;
+}
+
+/**
+ BSP wait until all the APs arriving. It means the task triggered by BSP is started.
+**/
+VOID
+EFIAPI
+MpSerializeStart (
+ VOID
+ )
+{
+ volatile MP_WAKEUP_MAILBOX *MailBox;
+ UINT32 NumOfCpus;
+
+ NumOfCpus = GetCpusNum ();
+ MailBox = (volatile MP_WAKEUP_MAILBOX *)GetTdxMailBox ();
+
+ DEBUG ((DEBUG_VERBOSE, "Waiting for APs to arriving. NumOfCpus=%d, MailBox=%p\n", NumOfCpus, MailBox));
+ while (MailBox->NumCpusArriving != (NumOfCpus -1)) {
+ CpuPause ();
+ }
+
+ DEBUG ((DEBUG_VERBOSE, "Releasing APs\n"));
+ MailBox->NumCpusExiting = NumOfCpus;
+ InterlockedIncrement ((UINT32 *)&MailBox->NumCpusArriving);
+}
+
+/**
+ BSP wait until all the APs arriving. It means the task triggered by BSP is ended.
+**/
+VOID
+EFIAPI
+MpSerializeEnd (
+ VOID
+ )
+{
+ volatile MP_WAKEUP_MAILBOX *MailBox;
+
+ MailBox = (volatile MP_WAKEUP_MAILBOX *)GetTdxMailBox ();
+ DEBUG ((DEBUG_VERBOSE, "Waiting for APs to finish\n"));
+ while (MailBox->NumCpusExiting != 1 ) {
+ CpuPause ();
+ }
+
+ DEBUG ((DEBUG_VERBOSE, "Restarting APs\n"));
+ MailBox->Command = MpProtectedModeWakeupCommandNoop;
+ MailBox->NumCpusArriving = 0;
+ InterlockedDecrement ((UINT32 *)&MailBox->NumCpusExiting);
+}
diff --git a/OvmfPkg/Library/TdxMailboxLib/TdxMailboxLib.inf b/OvmfPkg/Library/TdxMailboxLib/TdxMailboxLib.inf
new file mode 100644
index 000000000000..3cf3690a16c7
--- /dev/null
+++ b/OvmfPkg/Library/TdxMailboxLib/TdxMailboxLib.inf
@@ -0,0 +1,52 @@
+#/** @file
+#
+# TBD
+#
+# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2008, Apple Inc. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+#**/
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = TdxMailboxLib
+ FILE_GUID = 2F81A9BA-748E-4519-BB11-A63A039D561E
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TdxMailboxLib
+
+#
+# VALID_ARCHITECTURES = X64 IA32
+#
+
+[Sources.IA32]
+ TdxMailboxNull.c
+
+[Sources.X64]
+ TdxMailbox.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+ OvmfPkg/OvmfPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ BaseMemoryLib
+ PcdLib
+ UefiCpuLib
+ DebugAgentLib
+ IoLib
+ SynchronizationLib
+ MemoryAllocationLib
+
+[Guids]
+
+[Pcd]
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupBase
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupSize
diff --git a/OvmfPkg/Library/TdxMailboxLib/TdxMailboxNull.c b/OvmfPkg/Library/TdxMailboxLib/TdxMailboxNull.c
new file mode 100644
index 000000000000..35b070361eb1
--- /dev/null
+++ b/OvmfPkg/Library/TdxMailboxLib/TdxMailboxNull.c
@@ -0,0 +1,85 @@
+/** @file
+
+ Copyright (c) 2008, Intel Corporation. All rights reserved.<BR>
+ (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/DebugLib.h>
+#include <Library/TdxMailboxLib.h>
+
+/**
+ This function will be called by BSP to get the CPU number.
+
+ @retval CPU number
+**/
+UINT32
+EFIAPI
+GetCpusNum (
+ VOID
+ )
+{
+ ASSERT (FALSE);
+ return 0;
+}
+
+/**
+ Get the address of Td mailbox.
+**/
+volatile VOID *
+EFIAPI
+GetTdxMailBox (
+ VOID
+ )
+{
+ ASSERT (FALSE);
+ return (volatile VOID *)NULL;
+}
+
+/**
+ This function will be called by BSP to wakeup APs the are spinning on mailbox
+ in protected mode
+
+ @param[in] Command Command to send APs
+ @param[in] WakeupVector If used, address for APs to start executing
+ @param[in] WakeArgsX Args to pass to APs for excuting commands
+**/
+VOID
+EFIAPI
+MpSendWakeupCommand (
+ IN UINT16 Command,
+ IN UINT64 WakeupVector,
+ IN UINT64 WakeupArgs1,
+ IN UINT64 WakeupArgs2,
+ IN UINT64 WakeupArgs3,
+ IN UINT64 WakeupArgs4
+ )
+{
+ ASSERT (FALSE);
+}
+
+/**
+ BSP wait until all the APs arriving. It means the task triggered by BSP is started.
+**/
+VOID
+EFIAPI
+MpSerializeStart (
+ VOID
+ )
+{
+ ASSERT (FALSE);
+}
+
+/**
+ BSP wait until all the APs arriving. It means the task triggered by BSP is ended.
+**/
+VOID
+EFIAPI
+MpSerializeEnd (
+ VOID
+ )
+{
+ ASSERT (FALSE);
+}
diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index 7aa94ca02863..d373b5d6042e 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -109,6 +109,10 @@
#
XenPlatformLib|Include/Library/XenPlatformLib.h

+ ## @libraryclass TdxMailboxLib
+ #
+ TdxMailboxLib|Include/Library/TdxMailboxLib.h
+
[Guids]
gUefiOvmfPkgTokenSpaceGuid = {0x93bb96af, 0xb9f2, 0x4eb8, {0x94, 0x62, 0xe0, 0xba, 0x74, 0x56, 0x42, 0x36}}
gEfiXenInfoGuid = {0xd3b46f3b, 0xd441, 0x1244, {0x9a, 0x12, 0x0, 0x12, 0x27, 0x3f, 0xc1, 0x4d}}
--
2.29.2.windows.2


[PATCH V6 14/42] OvmfPkg: Add IntelTdx.h in OvmfPkg/Include/IndustryStandard

Min Xu
 

RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429

IntelTdx.h defines the defition used by TDX in OvmfPkg:
- Mailbox related defitions,such as the data structure, command code,
AP relocation defitions.

See Table 5.44 Multiprocessor Wakeup Mailbox Structure in below link.
https://uefi.org/specs/ACPI/6.4/05_ACPI_Software_Programming_Model/
ACPI_Software_Programming_Model.html#multiprocessor-wakeup-structure

Cc: Ard Biesheuvel <ardb+tianocore@...>
Cc: Jordan Justen <jordan.l.justen@...>
Cc: Brijesh Singh <brijesh.singh@...>
Cc: Erdem Aktas <erdemaktas@...>
Cc: James Bottomley <jejb@...>
Cc: Jiewen Yao <jiewen.yao@...>
Cc: Tom Lendacky <thomas.lendacky@...>
Cc: Gerd Hoffmann <kraxel@...>
Acked-by: Gerd Hoffmann <kraxel@...>
Signed-off-by: Min Xu <min.m.xu@...>
---
OvmfPkg/Include/IndustryStandard/IntelTdx.h | 67 +++++++++++++++++++++
1 file changed, 67 insertions(+)
create mode 100644 OvmfPkg/Include/IndustryStandard/IntelTdx.h

diff --git a/OvmfPkg/Include/IndustryStandard/IntelTdx.h b/OvmfPkg/Include/IndustryStandard/IntelTdx.h
new file mode 100644
index 000000000000..cc849be2fb59
--- /dev/null
+++ b/OvmfPkg/Include/IndustryStandard/IntelTdx.h
@@ -0,0 +1,67 @@
+/** @file
+ Defines the defitions used by TDX in OvmfPkg.
+
+ Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef OVMF_INTEL_TDX_H_
+#define OVMF_INTEL_TDX_H_
+
+#include <PiPei.h>
+#include <Library/BaseLib.h>
+#include <Uefi/UefiSpec.h>
+#include <Uefi/UefiBaseType.h>
+
+#define MP_CPU_PROTECTED_MODE_MAILBOX_APICID_INVALID 0xFFFFFFFF
+#define MP_CPU_PROTECTED_MODE_MAILBOX_APICID_BROADCAST 0xFFFFFFFE
+
+typedef enum {
+ MpProtectedModeWakeupCommandNoop = 0,
+ MpProtectedModeWakeupCommandWakeup = 1,
+ MpProtectedModeWakeupCommandSleep = 2,
+ MpProtectedModeWakeupCommandAcceptPages = 3,
+} MP_CPU_PROTECTED_MODE_WAKEUP_CMD;
+
+#pragma pack(1)
+
+//
+// Describes the CPU MAILBOX control structure use to
+// wakeup cpus spinning in long mode
+//
+typedef struct {
+ UINT16 Command;
+ UINT16 Resv;
+ UINT32 ApicId;
+ UINT64 WakeUpVector;
+ UINT8 ResvForOs[2032];
+ //
+ // Arguments available for wakeup code
+ //
+ UINT64 WakeUpArgs1;
+ UINT64 WakeUpArgs2;
+ UINT64 WakeUpArgs3;
+ UINT64 WakeUpArgs4;
+ UINT8 Pad1[0xe0];
+ UINT64 NumCpusArriving;
+ UINT8 Pad2[0xf8];
+ UINT64 NumCpusExiting;
+ UINT32 Tallies[256];
+ UINT8 Errors[256];
+ UINT8 Pad3[0xf8];
+} MP_WAKEUP_MAILBOX;
+
+//
+// AP relocation code information including code address and size,
+// this structure will be shared be C code and assembly code.
+// It is natural aligned by design.
+//
+typedef struct {
+ UINT8 *RelocateApLoopFuncAddress;
+ UINTN RelocateApLoopFuncSize;
+} MP_RELOCATION_MAP;
+
+#pragma pack()
+
+#endif
--
2.29.2.windows.2


[PATCH V6 13/42] UefiCpuPkg: Enable Tdx support in MpInitLib

Min Xu
 

RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429

In TDVF BSP and APs are simplified. BSP is the vCPU-0, while the others
are treated as APs.

So MP intialization is rather simple. The processor info is retrieved by
TDCALL, ApWorker is not supported, BSP is always the working processor,
while the APs are just in a wait-for-precedure state.

Cc: Brijesh Singh <brijesh.singh@...>
Cc: Erdem Aktas <erdemaktas@...>
Cc: James Bottomley <jejb@...>
Cc: Jiewen Yao <jiewen.yao@...>
Cc: Tom Lendacky <thomas.lendacky@...>
Cc: Eric Dong <eric.dong@...>
Cc: Ray Ni <ray.ni@...>
Cc: Rahul Kumar <rahul1.kumar@...>
Cc: Gerd Hoffmann <kraxel@...>
Acked-by: Gerd Hoffmann <kraxel@...>
Signed-off-by: Min Xu <min.m.xu@...>
---
UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf | 3 +
UefiCpuPkg/Library/MpInitLib/DxeMpLib.c | 15 +-
UefiCpuPkg/Library/MpInitLib/MpIntelTdx.h | 71 ++++++++++
UefiCpuPkg/Library/MpInitLib/MpLib.c | 27 ++++
UefiCpuPkg/Library/MpInitLib/MpLibTdx.c | 128 ++++++++++++++++++
UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c | 73 ++++++++++
UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf | 3 +
7 files changed, 319 insertions(+), 1 deletion(-)
create mode 100644 UefiCpuPkg/Library/MpInitLib/MpIntelTdx.h
create mode 100644 UefiCpuPkg/Library/MpInitLib/MpLibTdx.c
create mode 100644 UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c

diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
index e1cd0b350008..159b4d16ed0e 100644
--- a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
@@ -24,10 +24,12 @@
[Sources.IA32]
Ia32/AmdSev.c
Ia32/MpFuncs.nasm
+ MpLibTdxNull.c

[Sources.X64]
X64/AmdSev.c
X64/MpFuncs.nasm
+ MpLibTdx.c

[Sources.common]
AmdSev.c
@@ -36,6 +38,7 @@
MpLib.c
MpLib.h
Microcode.c
+ MpIntelTdx.h

[Packages]
MdePkg/MdePkg.dec
diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
index 60d14a5a0e10..237cad8c5fd6 100644
--- a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
@@ -7,6 +7,7 @@
**/

#include "MpLib.h"
+#include "MpIntelTdx.h"

#include <Library/UefiLib.h>
#include <Library/UefiBootServicesTableLib.h>
@@ -15,8 +16,8 @@
#include <Library/VmgExitLib.h>
#include <Register/Amd/Fam17Msr.h>
#include <Register/Amd/Ghcb.h>
-
#include <Protocol/Timer.h>
+#include <ConfidentialComputingGuestAttr.h>

#define AP_SAFE_STACK_SIZE 128

@@ -824,6 +825,10 @@ MpInitLibStartupThisAP (
{
EFI_STATUS Status;

+ if (CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr))) {
+ return EFI_UNSUPPORTED;
+ }
+
//
// temporarily stop checkAllApsStatus for avoid resource dead-lock.
//
@@ -880,6 +885,10 @@ MpInitLibSwitchBSP (
EFI_TIMER_ARCH_PROTOCOL *Timer;
UINT64 TimerPeriod;

+ if (CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr))) {
+ return EFI_UNSUPPORTED;
+ }
+
TimerPeriod = 0;
//
// Locate Timer Arch Protocol
@@ -953,6 +962,10 @@ MpInitLibEnableDisableAP (
EFI_STATUS Status;
BOOLEAN TempStopCheckState;

+ if (CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr))) {
+ return EFI_UNSUPPORTED;
+ }
+
TempStopCheckState = FALSE;
//
// temporarily stop checkAllAPsStatus for initialize parameters.
diff --git a/UefiCpuPkg/Library/MpInitLib/MpIntelTdx.h b/UefiCpuPkg/Library/MpInitLib/MpIntelTdx.h
new file mode 100644
index 000000000000..b2136f466ce6
--- /dev/null
+++ b/UefiCpuPkg/Library/MpInitLib/MpIntelTdx.h
@@ -0,0 +1,71 @@
+/** @file
+ Intel Tdx header file.
+
+ Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef MP_INTEL_TDX_H_
+#define MP_INTEL_TDX_H_
+
+#include <PiPei.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Uefi/UefiBaseType.h>
+#include <Protocol/MpService.h>
+
+/**
+ Gets detailed MP-related information on the requested processor at the
+ instant this call is made. This service may only be called from the BSP.
+
+ @param[in] ProcessorNumber The handle number of processor.
+ @param[out] ProcessorInfoBuffer A pointer to the buffer where information for
+ the requested processor is deposited.
+ @param[out] HealthData Return processor health data.
+
+ @retval EFI_SUCCESS Processor information was returned.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist in the platform.
+ @retval EFI_NOT_READY MP Initialize Library is not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+TdxMpInitLibGetProcessorInfo (
+ IN UINTN ProcessorNumber,
+ OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer,
+ OUT EFI_HEALTH_FLAGS *HealthData OPTIONAL
+ );
+
+/**
+ Retrieves the number of logical processor in the platform and the number of
+ those logical processors that are enabled on this boot. This service may only
+ be called from the BSP.
+
+ @param[out] NumberOfProcessors Pointer to the total number of logical
+ processors in the system, including the BSP
+ and disabled APs.
+ @param[out] NumberOfEnabledProcessors Pointer to the number of enabled logical
+ processors that exist in system, including
+ the BSP.
+
+ @retval EFI_SUCCESS The number of logical processors and enabled
+ logical processors was retrieved.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL and NumberOfEnabledProcessors
+ is NULL.
+ @retval EFI_NOT_READY MP Initialize Library is not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+TdxMpInitLibGetNumberOfProcessors (
+ OUT UINTN *NumberOfProcessors, OPTIONAL
+ OUT UINTN *NumberOfEnabledProcessors OPTIONAL
+ );
+
+#endif
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index 4a73787ee43a..de2ed8e6c294 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -9,9 +9,11 @@
**/

#include "MpLib.h"
+#include "MpIntelTdx.h"
#include <Library/VmgExitLib.h>
#include <Register/Amd/Fam17Msr.h>
#include <Register/Amd/Ghcb.h>
+#include <ConfidentialComputingGuestAttr.h>

EFI_GUID mCpuInitMpLibHobGuid = CPU_INIT_MP_LIB_HOB_GUID;

@@ -1803,6 +1805,10 @@ MpInitLibInitialize (
UINTN BackupBufferAddr;
UINTN ApIdtBase;

+ if (CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr))) {
+ return EFI_SUCCESS;
+ }
+
OldCpuMpData = GetCpuMpDataFromGuidedHob ();
if (OldCpuMpData == NULL) {
MaxLogicalProcessorNumber = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
@@ -2073,6 +2079,10 @@ MpInitLibGetProcessorInfo (
CPU_INFO_IN_HOB *CpuInfoInHob;
UINTN OriginalProcessorNumber;

+ if (CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr))) {
+ return TdxMpInitLibGetProcessorInfo (ProcessorNumber, ProcessorInfoBuffer, HealthData);
+ }
+
CpuMpData = GetCpuMpData ();
CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;

@@ -2307,6 +2317,10 @@ EnableDisableApWorker (
CPU_MP_DATA *CpuMpData;
UINTN CallerNumber;

+ if (CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr))) {
+ return EFI_UNSUPPORTED;
+ }
+
CpuMpData = GetCpuMpData ();

//
@@ -2367,6 +2381,11 @@ MpInitLibWhoAmI (
return EFI_INVALID_PARAMETER;
}

+ if (CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr))) {
+ *ProcessorNumber = 0;
+ return EFI_SUCCESS;
+ }
+
CpuMpData = GetCpuMpData ();

return GetProcessorNumber (CpuMpData, ProcessorNumber);
@@ -2405,6 +2424,10 @@ MpInitLibGetNumberOfProcessors (
UINTN EnabledProcessorNumber;
UINTN Index;

+ if (CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr))) {
+ return TdxMpInitLibGetNumberOfProcessors (NumberOfProcessors, NumberOfEnabledProcessors);
+ }
+
CpuMpData = GetCpuMpData ();

if ((NumberOfProcessors == NULL) && (NumberOfEnabledProcessors == NULL)) {
@@ -2490,6 +2513,10 @@ StartupAllCPUsWorker (
BOOLEAN HasEnabledAp;
CPU_STATE ApState;

+ if (CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr))) {
+ return EFI_SUCCESS;
+ }
+
CpuMpData = GetCpuMpData ();

if (FailedCpuList != NULL) {
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLibTdx.c b/UefiCpuPkg/Library/MpInitLib/MpLibTdx.c
new file mode 100644
index 000000000000..d31d043b20b7
--- /dev/null
+++ b/UefiCpuPkg/Library/MpInitLib/MpLibTdx.c
@@ -0,0 +1,128 @@
+/** @file
+ CPU MP Initialize Library common functions.
+
+ Copyright (c) 2016 - 2020, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2020, AMD Inc. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MpLib.h"
+#include "MpIntelTdx.h"
+#include <Library/BaseLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DebugLib.h>
+#include <IndustryStandard/Tdx.h>
+
+/**
+ Gets detailed MP-related information on the requested processor at the
+ instant this call is made. This service may only be called from the BSP.
+
+ @param[in] ProcessorNumber The handle number of processor.
+ @param[out] ProcessorInfoBuffer A pointer to the buffer where information for
+ the requested processor is deposited.
+ @param[out] HealthData Return processor health data.
+
+ @retval EFI_SUCCESS Processor information was returned.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist in the platform.
+ @retval EFI_NOT_READY MP Initialize Library is not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+TdxMpInitLibGetProcessorInfo (
+ IN UINTN ProcessorNumber,
+ OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer,
+ OUT EFI_HEALTH_FLAGS *HealthData OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ TD_RETURN_DATA TdReturnData;
+
+ if (ProcessorInfoBuffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = TdCall (TDCALL_TDINFO, 0, 0, 0, &TdReturnData);
+ ASSERT (Status == EFI_SUCCESS);
+
+ if (ProcessorNumber >= TdReturnData.TdInfo.NumVcpus) {
+ return EFI_NOT_FOUND;
+ }
+
+ ProcessorInfoBuffer->ProcessorId = ProcessorNumber;
+ ProcessorInfoBuffer->StatusFlag = 0;
+ if (ProcessorNumber == 0) {
+ ProcessorInfoBuffer->StatusFlag |= PROCESSOR_AS_BSP_BIT;
+ }
+
+ ProcessorInfoBuffer->StatusFlag |= PROCESSOR_ENABLED_BIT;
+
+ //
+ // Get processor location information
+ //
+ GetProcessorLocationByApicId (
+ (UINT32)ProcessorNumber,
+ &ProcessorInfoBuffer->Location.Package,
+ &ProcessorInfoBuffer->Location.Core,
+ &ProcessorInfoBuffer->Location.Thread
+ );
+
+ if (HealthData != NULL) {
+ HealthData->Uint32 = 0;
+ }
+
+ return Status;
+}
+
+/**
+ Retrieves the number of logical processor in the platform and the number of
+ those logical processors that are enabled on this boot. This service may only
+ be called from the BSP.
+
+ @param[out] NumberOfProcessors Pointer to the total number of logical
+ processors in the system, including the BSP
+ and disabled APs.
+ @param[out] NumberOfEnabledProcessors Pointer to the number of enabled logical
+ processors that exist in system, including
+ the BSP.
+
+ @retval EFI_SUCCESS The number of logical processors and enabled
+ logical processors was retrieved.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL and NumberOfEnabledProcessors
+ is NULL.
+ @retval EFI_NOT_READY MP Initialize Library is not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+TdxMpInitLibGetNumberOfProcessors (
+ OUT UINTN *NumberOfProcessors, OPTIONAL
+ OUT UINTN *NumberOfEnabledProcessors OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ TD_RETURN_DATA TdReturnData;
+
+ if ((NumberOfProcessors == NULL) && (NumberOfEnabledProcessors == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = TdCall (TDCALL_TDINFO, 0, 0, 0, &TdReturnData);
+ ASSERT (Status == EFI_SUCCESS);
+
+ if (NumberOfProcessors != NULL) {
+ *NumberOfProcessors = TdReturnData.TdInfo.NumVcpus;
+ }
+
+ if (NumberOfEnabledProcessors != NULL) {
+ *NumberOfEnabledProcessors = TdReturnData.TdInfo.MaxVcpus;
+ }
+
+ return Status;
+}
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c b/UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c
new file mode 100644
index 000000000000..2849e13f2aaa
--- /dev/null
+++ b/UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c
@@ -0,0 +1,73 @@
+/** @file
+ CPU MP Initialize Library common functions.
+
+ Copyright (c) 2016 - 2020, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2020, AMD Inc. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MpLib.h"
+#include "MpIntelTdx.h"
+#include <Library/DebugLib.h>
+
+/**
+ Gets detailed MP-related information on the requested processor at the
+ instant this call is made. This service may only be called from the BSP.
+
+ @param[in] ProcessorNumber The handle number of processor.
+ @param[out] ProcessorInfoBuffer A pointer to the buffer where information for
+ the requested processor is deposited.
+ @param[out] HealthData Return processor health data.
+
+ @retval EFI_SUCCESS Processor information was returned.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist in the platform.
+ @retval EFI_NOT_READY MP Initialize Library is not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+TdxMpInitLibGetProcessorInfo (
+ IN UINTN ProcessorNumber,
+ OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer,
+ OUT EFI_HEALTH_FLAGS *HealthData OPTIONAL
+ )
+{
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Retrieves the number of logical processor in the platform and the number of
+ those logical processors that are enabled on this boot. This service may only
+ be called from the BSP.
+
+ @param[out] NumberOfProcessors Pointer to the total number of logical
+ processors in the system, including the BSP
+ and disabled APs.
+ @param[out] NumberOfEnabledProcessors Pointer to the number of enabled logical
+ processors that exist in system, including
+ the BSP.
+
+ @retval EFI_SUCCESS The number of logical processors and enabled
+ logical processors was retrieved.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL and NumberOfEnabledProcessors
+ is NULL.
+ @retval EFI_NOT_READY MP Initialize Library is not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+TdxMpInitLibGetNumberOfProcessors (
+ OUT UINTN *NumberOfProcessors, OPTIONAL
+ OUT UINTN *NumberOfEnabledProcessors OPTIONAL
+ )
+{
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+}
diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
index 5facf4db9499..894be0f8daab 100644
--- a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
@@ -24,10 +24,12 @@
[Sources.IA32]
Ia32/AmdSev.c
Ia32/MpFuncs.nasm
+ MpLibTdxNull.c

[Sources.X64]
X64/AmdSev.c
X64/MpFuncs.nasm
+ MpLibTdx.c

[Sources.common]
AmdSev.c
@@ -36,6 +38,7 @@
MpLib.c
MpLib.h
Microcode.c
+ MpIntelTdx.h

[Packages]
MdePkg/MdePkg.dec
--
2.29.2.windows.2


[PATCH V6 12/42] MdePkg: Add macro to check SEV / TDX guest

Min Xu
 

RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429

Add macros CC_GUEST_IS_SEV / CC_GUEST_IS_TDX to check SEV / TDX guest.

Cc: Michael Roth <michael.roth@...>
Cc: Ray Ni <ray.ni@...>
Cc: Rahul Kumar <rahul1.kumar@...>
Cc: Eric Dong <eric.dong@...>
Cc: James Bottomley <jejb@...>
Cc: Min Xu <min.m.xu@...>
Cc: Jiewen Yao <jiewen.yao@...>
Cc: Tom Lendacky <thomas.lendacky@...>
Cc: Jordan Justen <jordan.l.justen@...>
Cc: Ard Biesheuvel <ardb+tianocore@...>
Cc: Erdem Aktas <erdemaktas@...>
Cc: Gerd Hoffmann <kraxel@...>
Acked-by: Gerd Hoffmann <kraxel@...>
Signed-off-by: Min Xu <min.m.xu@...>
---
MdePkg/Include/ConfidentialComputingGuestAttr.h | 3 +++
1 file changed, 3 insertions(+)

diff --git a/MdePkg/Include/ConfidentialComputingGuestAttr.h b/MdePkg/Include/ConfidentialComputingGuestAttr.h
index 6a1301801519..dd2541c6dcdf 100644
--- a/MdePkg/Include/ConfidentialComputingGuestAttr.h
+++ b/MdePkg/Include/ConfidentialComputingGuestAttr.h
@@ -22,4 +22,7 @@ typedef enum {
CCAttrIntelTdx = 0x200,
} CONFIDENTIAL_COMPUTING_GUEST_ATTR;

+#define CC_GUEST_IS_TDX(x) ((x) == CCAttrIntelTdx)
+#define CC_GUEST_IS_SEV(x) ((x) == CCAttrAmdSev || (x) == CCAttrAmdSevEs || (x) == CCAttrAmdSevSnp)
+
#endif
--
2.29.2.windows.2


[PATCH V6 11/42] UefiCpuPkg: Support TDX in BaseXApicX2ApicLib

Min Xu
 

RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429

MSR is accessed in BaseXApicX2ApicLib. In TDX some MSRs are accessed
directly from/to CPU. Some should be accessed via explicit requests
from the host VMM using TDCALL(TDG.VP.VMCALL). This is done by the
help of TdxLib.

Please refer to [TDX] Section 18.1
TDX: https://software.intel.com/content/dam/develop/external/us/en/
documents/tdx-module-1.0-public-spec-v0.931.pdf

Cc: Eric Dong <eric.dong@...>
Cc: Ray Ni <ray.ni@...>
Cc: Rahul Kumar <rahul1.kumar@...>
Cc: Brijesh Singh <brijesh.singh@...>
Cc: Erdem Aktas <erdemaktas@...>
Cc: James Bottomley <jejb@...>
Cc: Jiewen Yao <jiewen.yao@...>
Cc: Tom Lendacky <thomas.lendacky@...>
Cc: Gerd Hoffmann <kraxel@...>
Acked-by: Gerd Hoffmann <kraxel@...>
Signed-off-by: Min Xu <min.m.xu@...>
---
.../BaseXApicX2ApicLib/BaseXApicX2ApicLib.c | 160 +++++++++++++++++-
1 file changed, 152 insertions(+), 8 deletions(-)

diff --git a/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c b/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c
index aaa42ff8450b..2d17177df12b 100644
--- a/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c
+++ b/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c
@@ -23,11 +23,155 @@
#include <Library/TimerLib.h>
#include <Library/PcdLib.h>
#include <Library/UefiCpuLib.h>
+#include <IndustryStandard/Tdx.h>

//
// Library internal functions
//

+/**
+ Some MSRs in TDX are accessed via TdCall.
+ Some are directly read/write from/to CPU.
+
+ @param MsrIndex Index of the MSR
+ @retval TRUE MSR accessed via TdCall.
+ @retval FALSE MSR accessed not via TdCall.
+
+**/
+BOOLEAN
+AccessMsrTdxCall (
+ IN UINT32 MsrIndex
+ )
+{
+ if (!TdIsEnabled ()) {
+ return FALSE;
+ }
+
+ switch (MsrIndex) {
+ case MSR_IA32_X2APIC_TPR:
+ case MSR_IA32_X2APIC_PPR:
+ case MSR_IA32_X2APIC_EOI:
+ case MSR_IA32_X2APIC_ISR0:
+ case MSR_IA32_X2APIC_ISR1:
+ case MSR_IA32_X2APIC_ISR2:
+ case MSR_IA32_X2APIC_ISR3:
+ case MSR_IA32_X2APIC_ISR4:
+ case MSR_IA32_X2APIC_ISR5:
+ case MSR_IA32_X2APIC_ISR6:
+ case MSR_IA32_X2APIC_ISR7:
+ case MSR_IA32_X2APIC_TMR0:
+ case MSR_IA32_X2APIC_TMR1:
+ case MSR_IA32_X2APIC_TMR2:
+ case MSR_IA32_X2APIC_TMR3:
+ case MSR_IA32_X2APIC_TMR4:
+ case MSR_IA32_X2APIC_TMR5:
+ case MSR_IA32_X2APIC_TMR6:
+ case MSR_IA32_X2APIC_TMR7:
+ case MSR_IA32_X2APIC_IRR0:
+ case MSR_IA32_X2APIC_IRR1:
+ case MSR_IA32_X2APIC_IRR2:
+ case MSR_IA32_X2APIC_IRR3:
+ case MSR_IA32_X2APIC_IRR4:
+ case MSR_IA32_X2APIC_IRR5:
+ case MSR_IA32_X2APIC_IRR6:
+ case MSR_IA32_X2APIC_IRR7:
+ return FALSE;
+ default:
+ break;
+ }
+
+ return TRUE;
+}
+
+/**
+ Read MSR value.
+
+ @param MsrIndex Index of the MSR to read
+ @retval 64-bit Value of MSR.
+
+**/
+UINT64
+LocalApicReadMsrReg64 (
+ IN UINT32 MsrIndex
+ )
+{
+ UINT64 Val;
+ UINT64 Status;
+
+ if (AccessMsrTdxCall (MsrIndex)) {
+ Status = TdVmCall (TDVMCALL_RDMSR, (UINT64)MsrIndex, 0, 0, 0, &Val);
+ if (Status != 0) {
+ TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
+ }
+ } else {
+ Val = AsmReadMsr64 (MsrIndex);
+ }
+
+ return Val;
+}
+
+/**
+ Write to MSR.
+
+ @param MsrIndex Index of the MSR to write to
+ @param Value Value to be written to the MSR
+
+ @return Value
+
+**/
+UINT64
+LocalApicWriteMsrReg64 (
+ IN UINT32 MsrIndex,
+ IN UINT64 Value
+ )
+{
+ UINT64 Status;
+
+ if (AccessMsrTdxCall (MsrIndex)) {
+ Status = TdVmCall (TDVMCALL_WRMSR, (UINT64)MsrIndex, Value, 0, 0, 0);
+ if (Status != 0) {
+ TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
+ }
+ } else {
+ AsmWriteMsr64 (MsrIndex, Value);
+ }
+
+ return Value;
+}
+
+/**
+ Read MSR value.
+
+ @param MsrIndex Index of the MSR to read
+ @retval 32-bit Value of MSR.
+
+**/
+UINT32
+LocalApicReadMsrReg32 (
+ IN UINT32 MsrIndex
+ )
+{
+ return (UINT32)LocalApicReadMsrReg64 (MsrIndex);
+}
+
+/**
+ Write to MSR.
+
+ @param MsrIndex Index of the MSR to write to
+ @param Value Value to be written to the MSR
+
+ @return Value
+
+**/
+UINT32
+LocalApicWriteMsrReg32 (
+ IN UINT32 MsrIndex,
+ IN UINT32 Value
+ )
+{
+ return (UINT32)LocalApicWriteMsrReg64 (MsrIndex, Value);
+}
+
/**
Determine if the CPU supports the Local APIC Base Address MSR.

@@ -78,7 +222,7 @@ GetLocalApicBaseAddress (
return PcdGet32 (PcdCpuLocalApicBaseAddress);
}

- ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+ ApicBaseMsr.Uint64 = LocalApicReadMsrReg64 (MSR_IA32_APIC_BASE);

return (UINTN)(LShiftU64 ((UINT64)ApicBaseMsr.Bits.ApicBaseHi, 32)) +
(((UINTN)ApicBaseMsr.Bits.ApicBase) << 12);
@@ -109,12 +253,12 @@ SetLocalApicBaseAddress (
return;
}

- ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+ ApicBaseMsr.Uint64 = LocalApicReadMsrReg64 (MSR_IA32_APIC_BASE);

ApicBaseMsr.Bits.ApicBase = (UINT32)(BaseAddress >> 12);
ApicBaseMsr.Bits.ApicBaseHi = (UINT32)(RShiftU64 ((UINT64)BaseAddress, 32));

- AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
+ LocalApicWriteMsrReg64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
}

/**
@@ -154,7 +298,7 @@ ReadLocalApicReg (
ASSERT (MmioOffset != XAPIC_ICR_HIGH_OFFSET);

MsrIndex = (UINT32)(MmioOffset >> 4) + X2APIC_MSR_BASE_ADDRESS;
- return AsmReadMsr32 (MsrIndex);
+ return LocalApicReadMsrReg32 (MsrIndex);
}
}

@@ -203,7 +347,7 @@ WriteLocalApicReg (
// Use memory fence here to force the serializing semantics to be consisent with xAPIC mode.
//
MemoryFence ();
- AsmWriteMsr32 (MsrIndex, Value);
+ LocalApicWriteMsrReg32 (MsrIndex, Value);
}
}

@@ -309,7 +453,7 @@ GetApicMode (
return LOCAL_APIC_MODE_XAPIC;
}

- ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+ ApicBaseMsr.Uint64 = LocalApicReadMsrReg64 (MSR_IA32_APIC_BASE);
//
// Local APIC should have been enabled
//
@@ -354,9 +498,9 @@ SetApicMode (
case LOCAL_APIC_MODE_XAPIC:
break;
case LOCAL_APIC_MODE_X2APIC:
- ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+ ApicBaseMsr.Uint64 = LocalApicReadMsrReg64 (MSR_IA32_APIC_BASE);
ApicBaseMsr.Bits.EXTD = 1;
- AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
+ LocalApicWriteMsrReg64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
break;
default:
ASSERT (FALSE);
--
2.29.2.windows.2


[PATCH V6 10/42] MdePkg: Support IoRead/IoWrite for Tdx guest in BaseIoLibIntrinsic

Min Xu
 

RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429

This commit supports IoRead/IoWrite for SEV/TDX/Legacy guest in one
binary. It checks the guest type in runtime and then call corresponding
functions.

Cc: Michael D Kinney <michael.d.kinney@...>
Cc: Liming Gao <gaoliming@...>
Cc: Zhiguang Liu <zhiguang.liu@...>
Cc: Brijesh Singh <brijesh.singh@...>
Cc: Erdem Aktas <erdemaktas@...>
Cc: James Bottomley <jejb@...>
Cc: Jiewen Yao <jiewen.yao@...>
Cc: Tom Lendacky <thomas.lendacky@...>
Cc: Gerd Hoffmann <kraxel@...>
Acked-by: Gerd Hoffmann <kraxel@...>
Signed-off-by: Min Xu <min.m.xu@...>
---
MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c | 51 ++++++++++++--
MdePkg/Library/BaseIoLibIntrinsic/IoLibMsc.c | 73 +++++++++++++++-----
2 files changed, 99 insertions(+), 25 deletions(-)

diff --git a/MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c b/MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c
index 5c791289c469..05a739085967 100644
--- a/MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c
+++ b/MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c
@@ -16,6 +16,7 @@
**/

#include "BaseIoLibIntrinsicInternal.h"
+#include "IoLibTdx.h"

/**
Reads an 8-bit I/O port.
@@ -24,7 +25,9 @@
This function must guarantee that all I/O read and write operations are
serialized.

- If 8-bit I/O port operations are not supported, then ASSERT().
+ If 8-bit I/O port operations are not supported, then ASSERT()
+
+ For Td guest TDVMCALL_IO is invoked to read I/O port.

@param Port The I/O port to read.

@@ -42,7 +45,11 @@ IoRead8 (

Flag = FilterBeforeIoRead (FilterWidth8, Port, &Data);
if (Flag) {
- __asm__ __volatile__ ("inb %w1,%b0" : "=a" (Data) : "d" ((UINT16)Port));
+ if (IsTdxGuest ()) {
+ Data = TdIoRead8 (Port);
+ } else {
+ __asm__ __volatile__ ("inb %w1,%b0" : "=a" (Data) : "d" ((UINT16)Port));
+ }
}

FilterAfterIoRead (FilterWidth8, Port, &Data);
@@ -59,6 +66,8 @@ IoRead8 (

If 8-bit I/O port operations are not supported, then ASSERT().

+ For Td guest TDVMCALL_IO is invoked to write I/O port.
+
@param Port The I/O port to write.
@param Value The value to write to the I/O port.

@@ -76,7 +85,11 @@ IoWrite8 (

Flag = FilterBeforeIoWrite (FilterWidth8, Port, &Value);
if (Flag) {
- __asm__ __volatile__ ("outb %b0,%w1" : : "a" (Value), "d" ((UINT16)Port));
+ if (IsTdxGuest ()) {
+ TdIoWrite8 (Port, Value);
+ } else {
+ __asm__ __volatile__ ("outb %b0,%w1" : : "a" (Value), "d" ((UINT16)Port));
+ }
}

FilterAfterIoWrite (FilterWidth8, Port, &Value);
@@ -94,6 +107,8 @@ IoWrite8 (
If 16-bit I/O port operations are not supported, then ASSERT().
If Port is not aligned on a 16-bit boundary, then ASSERT().

+ For Td guest TDVMCALL_IO is invoked to read I/O port.
+
@param Port The I/O port to read.

@return The value read.
@@ -112,7 +127,11 @@ IoRead16 (

Flag = FilterBeforeIoRead (FilterWidth16, Port, &Data);
if (Flag) {
- __asm__ __volatile__ ("inw %w1,%w0" : "=a" (Data) : "d" ((UINT16)Port));
+ if (IsTdxGuest ()) {
+ Data = TdIoRead16 (Port);
+ } else {
+ __asm__ __volatile__ ("inw %w1,%w0" : "=a" (Data) : "d" ((UINT16)Port));
+ }
}

FilterAfterIoRead (FilterWidth16, Port, &Data);
@@ -130,6 +149,8 @@ IoRead16 (
If 16-bit I/O port operations are not supported, then ASSERT().
If Port is not aligned on a 16-bit boundary, then ASSERT().

+ For Td guest TDVMCALL_IO is invoked to write I/O port.
+
@param Port The I/O port to write.
@param Value The value to write to the I/O port.

@@ -149,7 +170,11 @@ IoWrite16 (

Flag = FilterBeforeIoWrite (FilterWidth16, Port, &Value);
if (Flag) {
- __asm__ __volatile__ ("outw %w0,%w1" : : "a" (Value), "d" ((UINT16)Port));
+ if (IsTdxGuest ()) {
+ TdIoWrite16 (Port, Value);
+ } else {
+ __asm__ __volatile__ ("outw %w0,%w1" : : "a" (Value), "d" ((UINT16)Port));
+ }
}

FilterAfterIoWrite (FilterWidth16, Port, &Value);
@@ -167,6 +192,8 @@ IoWrite16 (
If 32-bit I/O port operations are not supported, then ASSERT().
If Port is not aligned on a 32-bit boundary, then ASSERT().

+ For Td guest TDVMCALL_IO is invoked to read I/O port.
+
@param Port The I/O port to read.

@return The value read.
@@ -185,7 +212,11 @@ IoRead32 (

Flag = FilterBeforeIoRead (FilterWidth32, Port, &Data);
if (Flag) {
- __asm__ __volatile__ ("inl %w1,%0" : "=a" (Data) : "d" ((UINT16)Port));
+ if (IsTdxGuest ()) {
+ Data = TdIoRead32 (Port);
+ } else {
+ __asm__ __volatile__ ("inl %w1,%0" : "=a" (Data) : "d" ((UINT16)Port));
+ }
}

FilterAfterIoRead (FilterWidth32, Port, &Data);
@@ -203,6 +234,8 @@ IoRead32 (
If 32-bit I/O port operations are not supported, then ASSERT().
If Port is not aligned on a 32-bit boundary, then ASSERT().

+ For Td guest TDVMCALL_IO is invoked to write I/O port.
+
@param Port The I/O port to write.
@param Value The value to write to the I/O port.

@@ -222,7 +255,11 @@ IoWrite32 (

Flag = FilterBeforeIoWrite (FilterWidth32, Port, &Value);
if (Flag) {
- __asm__ __volatile__ ("outl %0,%w1" : : "a" (Value), "d" ((UINT16)Port));
+ if (IsTdxGuest ()) {
+ TdIoWrite32 (Port, Value);
+ } else {
+ __asm__ __volatile__ ("outl %0,%w1" : : "a" (Value), "d" ((UINT16)Port));
+ }
}

FilterAfterIoWrite (FilterWidth32, Port, &Value);
diff --git a/MdePkg/Library/BaseIoLibIntrinsic/IoLibMsc.c b/MdePkg/Library/BaseIoLibIntrinsic/IoLibMsc.c
index 9f225a6b5d39..f1b7d51a7245 100644
--- a/MdePkg/Library/BaseIoLibIntrinsic/IoLibMsc.c
+++ b/MdePkg/Library/BaseIoLibIntrinsic/IoLibMsc.c
@@ -14,6 +14,7 @@
**/

#include "BaseIoLibIntrinsicInternal.h"
+#include "IoLibTdx.h"

//
// Microsoft Visual Studio 7.1 Function Prototypes for I/O Intrinsics.
@@ -82,6 +83,8 @@ _ReadWriteBarrier (

If 8-bit I/O port operations are not supported, then ASSERT().

+ For Td guest TDVMCALL_IO is invoked to read I/O port.
+
@param Port The I/O port to read.

@return The value read.
@@ -98,9 +101,13 @@ IoRead8 (

Flag = FilterBeforeIoRead (FilterWidth8, Port, &Value);
if (Flag) {
- _ReadWriteBarrier ();
- Value = (UINT8)_inp ((UINT16)Port);
- _ReadWriteBarrier ();
+ if (IsTdxGuest ()) {
+ Value = TdIoRead8 (Port);
+ } else {
+ _ReadWriteBarrier ();
+ Value = (UINT8)_inp ((UINT16)Port);
+ _ReadWriteBarrier ();
+ }
}

FilterAfterIoRead (FilterWidth8, Port, &Value);
@@ -117,6 +124,8 @@ IoRead8 (

If 8-bit I/O port operations are not supported, then ASSERT().

+ For Td guest TDVMCALL_IO is invoked to write I/O port.
+
@param Port The I/O port to write.
@param Value The value to write to the I/O port.

@@ -134,9 +143,13 @@ IoWrite8 (

Flag = FilterBeforeIoWrite (FilterWidth8, Port, &Value);
if (Flag) {
- _ReadWriteBarrier ();
- (UINT8)_outp ((UINT16)Port, Value);
- _ReadWriteBarrier ();
+ if (IsTdxGuest ()) {
+ TdIoWrite8 (Port, Value);
+ } else {
+ _ReadWriteBarrier ();
+ (UINT8)_outp ((UINT16)Port, Value);
+ _ReadWriteBarrier ();
+ }
}

FilterAfterIoWrite (FilterWidth8, Port, &Value);
@@ -154,6 +167,8 @@ IoWrite8 (
If 16-bit I/O port operations are not supported, then ASSERT().
If Port is not aligned on a 16-bit boundary, then ASSERT().

+ For Td guest TDVMCALL_IO is invoked to read I/O port.
+
@param Port The I/O port to read.

@return The value read.
@@ -172,9 +187,13 @@ IoRead16 (

Flag = FilterBeforeIoRead (FilterWidth16, Port, &Value);
if (Flag) {
- _ReadWriteBarrier ();
- Value = _inpw ((UINT16)Port);
- _ReadWriteBarrier ();
+ if (IsTdxGuest ()) {
+ Value = TdIoRead16 (Port);
+ } else {
+ _ReadWriteBarrier ();
+ Value = _inpw ((UINT16)Port);
+ _ReadWriteBarrier ();
+ }
}

FilterBeforeIoRead (FilterWidth16, Port, &Value);
@@ -192,6 +211,8 @@ IoRead16 (
If 16-bit I/O port operations are not supported, then ASSERT().
If Port is not aligned on a 16-bit boundary, then ASSERT().

+ For Td guest TDVMCALL_IO is invoked to write I/O port.
+
@param Port The I/O port to write.
@param Value The value to write to the I/O port.

@@ -211,9 +232,13 @@ IoWrite16 (

Flag = FilterBeforeIoWrite (FilterWidth16, Port, &Value);
if (Flag) {
- _ReadWriteBarrier ();
- _outpw ((UINT16)Port, Value);
- _ReadWriteBarrier ();
+ if (IsTdxGuest ()) {
+ TdIoWrite16 (Port, Value);
+ } else {
+ _ReadWriteBarrier ();
+ _outpw ((UINT16)Port, Value);
+ _ReadWriteBarrier ();
+ }
}

FilterAfterIoWrite (FilterWidth16, Port, &Value);
@@ -231,6 +256,8 @@ IoWrite16 (
If 32-bit I/O port operations are not supported, then ASSERT().
If Port is not aligned on a 32-bit boundary, then ASSERT().

+ For Td guest TDVMCALL_IO is invoked to read I/O port.
+
@param Port The I/O port to read.

@return The value read.
@@ -249,9 +276,13 @@ IoRead32 (

Flag = FilterBeforeIoRead (FilterWidth32, Port, &Value);
if (Flag) {
- _ReadWriteBarrier ();
- Value = _inpd ((UINT16)Port);
- _ReadWriteBarrier ();
+ if (IsTdxGuest ()) {
+ Value = TdIoRead32 (Port);
+ } else {
+ _ReadWriteBarrier ();
+ Value = _inpd ((UINT16)Port);
+ _ReadWriteBarrier ();
+ }
}

FilterAfterIoRead (FilterWidth32, Port, &Value);
@@ -269,6 +300,8 @@ IoRead32 (
If 32-bit I/O port operations are not supported, then ASSERT().
If Port is not aligned on a 32-bit boundary, then ASSERT().

+ For Td guest TDVMCALL_IO is invoked to write I/O port.
+
@param Port The I/O port to write.
@param Value The value to write to the I/O port.

@@ -288,9 +321,13 @@ IoWrite32 (

Flag = FilterBeforeIoWrite (FilterWidth32, Port, &Value);
if (Flag) {
- _ReadWriteBarrier ();
- _outpd ((UINT16)Port, Value);
- _ReadWriteBarrier ();
+ if (IsTdxGuest ()) {
+ TdIoWrite32 (Port, Value);
+ } else {
+ _ReadWriteBarrier ();
+ _outpd ((UINT16)Port, Value);
+ _ReadWriteBarrier ();
+ }
}

FilterAfterIoWrite (FilterWidth32, Port, &Value);
--
2.29.2.windows.2


[PATCH V6 09/42] MdePkg: Support IoFifo for Tdx guest in BaseIoLibIntrinsic

Min Xu
 

RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429

Previously IoFifo functions are in X64/IoFifoSev.nasm which supports
both SEV guest and Legacy guest. IoLibFifo.c is introduced to support
SEV/TDX/Legacy guest in one binary. It checks the guest type in runtime
and call corresponding functions then.

Cc: Michael D Kinney <michael.d.kinney@...>
Cc: Liming Gao <gaoliming@...>
Cc: Zhiguang Liu <zhiguang.liu@...>
Cc: Brijesh Singh <brijesh.singh@...>
Cc: Erdem Aktas <erdemaktas@...>
Cc: James Bottomley <jejb@...>
Cc: Jiewen Yao <jiewen.yao@...>
Cc: Tom Lendacky <thomas.lendacky@...>
Cc: Gerd Hoffmann <kraxel@...>
Acked-by: Gerd Hoffmann <kraxel@...>
Signed-off-by: Min Xu <min.m.xu@...>
---
.../BaseIoLibIntrinsicSev.inf | 2 +
MdePkg/Library/BaseIoLibIntrinsic/IoLibFifo.c | 216 ++++++++++++++++++
MdePkg/Library/BaseIoLibIntrinsic/IoLibSev.h | 166 ++++++++++++++
.../BaseIoLibIntrinsic/X64/IoFifoSev.nasm | 34 +--
4 files changed, 401 insertions(+), 17 deletions(-)
create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/IoLibFifo.c
create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/IoLibSev.h

diff --git a/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicSev.inf b/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicSev.inf
index a74e54bee8b5..7fe1c60f046e 100644
--- a/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicSev.inf
+++ b/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicSev.inf
@@ -31,6 +31,7 @@
BaseIoLibIntrinsicInternal.h
IoHighLevel.c
IoLibTdx.h
+ IoLibSev.h

[Sources.IA32]
IoLibGcc.c | GCC
@@ -44,6 +45,7 @@
IoLibMsc.c | MSFT
IoLib.c
IoLibInternalTdx.c
+ IoLibFifo.c
X64/IoFifoSev.nasm

[Packages]
diff --git a/MdePkg/Library/BaseIoLibIntrinsic/IoLibFifo.c b/MdePkg/Library/BaseIoLibIntrinsic/IoLibFifo.c
new file mode 100644
index 000000000000..08761a15a86c
--- /dev/null
+++ b/MdePkg/Library/BaseIoLibIntrinsic/IoLibFifo.c
@@ -0,0 +1,216 @@
+/** @file
+ IoFifo read/write routines.
+
+ Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "BaseIoLibIntrinsicInternal.h"
+#include "IoLibSev.h"
+#include "IoLibTdx.h"
+#include <Library/TdxLib.h>
+
+/**
+ Reads an 8-bit I/O port fifo into a block of memory.
+
+ Reads the 8-bit I/O fifo port specified by Port.
+ The port is read Count times, and the read data is
+ stored in the provided Buffer.
+
+ This function must guarantee that all I/O read and write operations are
+ serialized.
+
+ If 8-bit I/O port operations are not supported, then ASSERT().
+
+ In TDX a serial of TdIoRead8 is invoked to read the I/O port fifo.
+
+ @param Port The I/O port to read.
+ @param Count The number of times to read I/O port.
+ @param Buffer The buffer to store the read data into.
+
+**/
+VOID
+EFIAPI
+IoReadFifo8 (
+ IN UINTN Port,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ )
+{
+ if (IsTdxGuest ()) {
+ TdIoReadFifo8 (Port, Count, Buffer);
+ } else {
+ SevIoReadFifo8 (Port, Count, Buffer);
+ }
+}
+
+/**
+ Writes a block of memory into an 8-bit I/O port fifo.
+
+ Writes the 8-bit I/O fifo port specified by Port.
+ The port is written Count times, and the write data is
+ retrieved from the provided Buffer.
+
+ This function must guarantee that all I/O write and write operations are
+ serialized.
+
+ If 8-bit I/O port operations are not supported, then ASSERT().
+
+ In TDX a serial of TdIoWrite8 is invoked to write data to the I/O port.
+
+ @param Port The I/O port to write.
+ @param Count The number of times to write I/O port.
+ @param Buffer The buffer to retrieve the write data from.
+
+**/
+VOID
+EFIAPI
+IoWriteFifo8 (
+ IN UINTN Port,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+{
+ if (IsTdxGuest ()) {
+ TdIoWriteFifo8 (Port, Count, Buffer);
+ } else {
+ SevIoWriteFifo8 (Port, Count, Buffer);
+ }
+}
+
+/**
+ Reads a 16-bit I/O port fifo into a block of memory.
+
+ Reads the 16-bit I/O fifo port specified by Port.
+ The port is read Count times, and the read data is
+ stored in the provided Buffer.
+
+ This function must guarantee that all I/O read and write operations are
+ serialized.
+
+ If 16-bit I/O port operations are not supported, then ASSERT().
+
+ In TDX a serial of TdIoRead16 is invoked to read data from the I/O port.
+
+ @param Port The I/O port to read.
+ @param Count The number of times to read I/O port.
+ @param Buffer The buffer to store the read data into.
+
+**/
+VOID
+EFIAPI
+IoReadFifo16 (
+ IN UINTN Port,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ )
+{
+ if (IsTdxGuest ()) {
+ TdIoReadFifo16 (Port, Count, Buffer);
+ } else {
+ SevIoReadFifo16 (Port, Count, Buffer);
+ }
+}
+
+/**
+ Writes a block of memory into a 16-bit I/O port fifo.
+
+ Writes the 16-bit I/O fifo port specified by Port.
+ The port is written Count times, and the write data is
+ retrieved from the provided Buffer.
+
+ This function must guarantee that all I/O write and write operations are
+ serialized.
+
+ If 16-bit I/O port operations are not supported, then ASSERT().
+
+ In TDX a serial of TdIoWrite16 is invoked to write data to the I/O port.
+
+ @param Port The I/O port to write.
+ @param Count The number of times to write I/O port.
+ @param Buffer The buffer to retrieve the write data from.
+
+**/
+VOID
+EFIAPI
+IoWriteFifo16 (
+ IN UINTN Port,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+{
+ if (IsTdxGuest ()) {
+ TdIoWriteFifo16 (Port, Count, Buffer);
+ } else {
+ SevIoWriteFifo16 (Port, Count, Buffer);
+ }
+}
+
+/**
+ Reads a 32-bit I/O port fifo into a block of memory.
+
+ Reads the 32-bit I/O fifo port specified by Port.
+ The port is read Count times, and the read data is
+ stored in the provided Buffer.
+
+ This function must guarantee that all I/O read and write operations are
+ serialized.
+
+ If 32-bit I/O port operations are not supported, then ASSERT().
+
+ In TDX a serial of TdIoRead32 is invoked to read data from the I/O port.
+
+ @param Port The I/O port to read.
+ @param Count The number of times to read I/O port.
+ @param Buffer The buffer to store the read data into.
+
+**/
+VOID
+EFIAPI
+IoReadFifo32 (
+ IN UINTN Port,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ )
+{
+ if (IsTdxGuest ()) {
+ TdIoReadFifo32 (Port, Count, Buffer);
+ } else {
+ SevIoReadFifo32 (Port, Count, Buffer);
+ }
+}
+
+/**
+ Writes a block of memory into a 32-bit I/O port fifo.
+
+ Writes the 32-bit I/O fifo port specified by Port.
+ The port is written Count times, and the write data is
+ retrieved from the provided Buffer.
+
+ This function must guarantee that all I/O write and write operations are
+ serialized.
+
+ If 32-bit I/O port operations are not supported, then ASSERT().
+
+ In TDX a serial of TdIoWrite32 is invoked to write data to the I/O port.
+
+ @param Port The I/O port to write.
+ @param Count The number of times to write I/O port.
+ @param Buffer The buffer to retrieve the write data from.
+
+**/
+VOID
+EFIAPI
+IoWriteFifo32 (
+ IN UINTN Port,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+{
+ if (IsTdxGuest ()) {
+ TdIoWriteFifo32 (Port, Count, Buffer);
+ } else {
+ SevIoWriteFifo32 (Port, Count, Buffer);
+ }
+}
diff --git a/MdePkg/Library/BaseIoLibIntrinsic/IoLibSev.h b/MdePkg/Library/BaseIoLibIntrinsic/IoLibSev.h
new file mode 100644
index 000000000000..6d7cafcff27a
--- /dev/null
+++ b/MdePkg/Library/BaseIoLibIntrinsic/IoLibSev.h
@@ -0,0 +1,166 @@
+/** @file
+ Header file for SEV IO library.
+
+ Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef IOLIB_SEV_H_
+#define IOLIB_SEV_H_
+
+#include <Base.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+
+/**
+ Reads an 8-bit I/O port fifo into a block of memory.
+
+ Reads the 8-bit I/O fifo port specified by Port.
+ The port is read Count times, and the read data is
+ stored in the provided Buffer.
+
+ This function must guarantee that all I/O read and write operations are
+ serialized.
+
+ If 8-bit I/O port operations are not supported, then ASSERT().
+
+ @param Port The I/O port to read.
+ @param Count The number of times to read I/O port.
+ @param Buffer The buffer to store the read data into.
+
+**/
+VOID
+EFIAPI
+SevIoReadFifo8 (
+ IN UINTN Port,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ );
+
+/**
+ Writes a block of memory into an 8-bit I/O port fifo.
+
+ Writes the 8-bit I/O fifo port specified by Port.
+ The port is written Count times, and the write data is
+ retrieved from the provided Buffer.
+
+ This function must guarantee that all I/O write and write operations are
+ serialized.
+
+ If 8-bit I/O port operations are not supported, then ASSERT().
+
+ @param Port The I/O port to write.
+ @param Count The number of times to write I/O port.
+ @param Buffer The buffer to retrieve the write data from.
+
+**/
+VOID
+EFIAPI
+SevIoWriteFifo8 (
+ IN UINTN Port,
+ IN UINTN Count,
+ IN VOID *Buffer
+ );
+
+/**
+ Reads an 8-bit I/O port fifo into a block of memory.
+
+ Reads the 8-bit I/O fifo port specified by Port.
+ The port is read Count times, and the read data is
+ stored in the provided Buffer.
+
+ This function must guarantee that all I/O read and write operations are
+ serialized.
+
+ If 8-bit I/O port operations are not supported, then ASSERT().
+
+ @param Port The I/O port to read.
+ @param Count The number of times to read I/O port.
+ @param Buffer The buffer to store the read data into.
+
+**/
+VOID
+EFIAPI
+SevIoReadFifo16 (
+ IN UINTN Port,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ );
+
+/**
+ Writes a block of memory into an 8-bit I/O port fifo.
+
+ Writes the 8-bit I/O fifo port specified by Port.
+ The port is written Count times, and the write data is
+ retrieved from the provided Buffer.
+
+ This function must guarantee that all I/O write and write operations are
+ serialized.
+
+ If 8-bit I/O port operations are not supported, then ASSERT().
+
+ @param Port The I/O port to write.
+ @param Count The number of times to write I/O port.
+ @param Buffer The buffer to retrieve the write data from.
+
+**/
+VOID
+EFIAPI
+SevIoWriteFifo16 (
+ IN UINTN Port,
+ IN UINTN Count,
+ IN VOID *Buffer
+ );
+
+/**
+ Reads an 8-bit I/O port fifo into a block of memory.
+
+ Reads the 8-bit I/O fifo port specified by Port.
+ The port is read Count times, and the read data is
+ stored in the provided Buffer.
+
+ This function must guarantee that all I/O read and write operations are
+ serialized.
+
+ If 8-bit I/O port operations are not supported, then ASSERT().
+
+ @param Port The I/O port to read.
+ @param Count The number of times to read I/O port.
+ @param Buffer The buffer to store the read data into.
+
+**/
+VOID
+EFIAPI
+SevIoReadFifo32 (
+ IN UINTN Port,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ );
+
+/**
+ Writes a block of memory into an 8-bit I/O port fifo.
+
+ Writes the 8-bit I/O fifo port specified by Port.
+ The port is written Count times, and the write data is
+ retrieved from the provided Buffer.
+
+ This function must guarantee that all I/O write and write operations are
+ serialized.
+
+ If 8-bit I/O port operations are not supported, then ASSERT().
+
+ @param Port The I/O port to write.
+ @param Count The number of times to write I/O port.
+ @param Buffer The buffer to retrieve the write data from.
+
+**/
+VOID
+EFIAPI
+SevIoWriteFifo32 (
+ IN UINTN Port,
+ IN UINTN Count,
+ IN VOID *Buffer
+ );
+
+#endif
diff --git a/MdePkg/Library/BaseIoLibIntrinsic/X64/IoFifoSev.nasm b/MdePkg/Library/BaseIoLibIntrinsic/X64/IoFifoSev.nasm
index 106f8881c55c..d02286b4d518 100644
--- a/MdePkg/Library/BaseIoLibIntrinsic/X64/IoFifoSev.nasm
+++ b/MdePkg/Library/BaseIoLibIntrinsic/X64/IoFifoSev.nasm
@@ -67,14 +67,14 @@ ASM_PFX(SevNoRepIo):
;------------------------------------------------------------------------------
; VOID
; EFIAPI
-; IoReadFifo8 (
+; SevIoReadFifo8 (
; IN UINTN Port, // rcx
; IN UINTN Size, // rdx
; OUT VOID *Buffer // r8
; );
;------------------------------------------------------------------------------
-global ASM_PFX(IoReadFifo8)
-ASM_PFX(IoReadFifo8):
+global ASM_PFX(SevIoReadFifo8)
+ASM_PFX(SevIoReadFifo8):
xchg rcx, rdx
xchg rdi, r8 ; rdi: buffer address; r8: save rdi

@@ -103,14 +103,14 @@ ASM_PFX(IoReadFifo8):
;------------------------------------------------------------------------------
; VOID
; EFIAPI
-; IoReadFifo16 (
+; SevIoReadFifo16 (
; IN UINTN Port, // rcx
; IN UINTN Size, // rdx
; OUT VOID *Buffer // r8
; );
;------------------------------------------------------------------------------
-global ASM_PFX(IoReadFifo16)
-ASM_PFX(IoReadFifo16):
+global ASM_PFX(SevIoReadFifo16)
+ASM_PFX(SevIoReadFifo16):
xchg rcx, rdx
xchg rdi, r8 ; rdi: buffer address; r8: save rdi

@@ -139,14 +139,14 @@ ASM_PFX(IoReadFifo16):
;------------------------------------------------------------------------------
; VOID
; EFIAPI
-; IoReadFifo32 (
+; SevIoReadFifo32 (
; IN UINTN Port, // rcx
; IN UINTN Size, // rdx
; OUT VOID *Buffer // r8
; );
;------------------------------------------------------------------------------
-global ASM_PFX(IoReadFifo32)
-ASM_PFX(IoReadFifo32):
+global ASM_PFX(SevIoReadFifo32)
+ASM_PFX(SevIoReadFifo32):
xchg rcx, rdx
xchg rdi, r8 ; rdi: buffer address; r8: save rdi

@@ -181,8 +181,8 @@ ASM_PFX(IoReadFifo32):
; IN VOID *Buffer // r8
; );
;------------------------------------------------------------------------------
-global ASM_PFX(IoWriteFifo8)
-ASM_PFX(IoWriteFifo8):
+global ASM_PFX(SevIoWriteFifo8)
+ASM_PFX(SevIoWriteFifo8):
xchg rcx, rdx
xchg rsi, r8 ; rsi: buffer address; r8: save rsi

@@ -211,14 +211,14 @@ ASM_PFX(IoWriteFifo8):
;------------------------------------------------------------------------------
; VOID
; EFIAPI
-; IoWriteFifo16 (
+; SevIoWriteFifo16 (
; IN UINTN Port, // rcx
; IN UINTN Size, // rdx
; IN VOID *Buffer // r8
; );
;------------------------------------------------------------------------------
-global ASM_PFX(IoWriteFifo16)
-ASM_PFX(IoWriteFifo16):
+global ASM_PFX(SevIoWriteFifo16)
+ASM_PFX(SevIoWriteFifo16):
xchg rcx, rdx
xchg rsi, r8 ; rsi: buffer address; r8: save rsi

@@ -247,14 +247,14 @@ ASM_PFX(IoWriteFifo16):
;------------------------------------------------------------------------------
; VOID
; EFIAPI
-; IoWriteFifo32 (
+; SevIoWriteFifo32 (
; IN UINTN Port, // rcx
; IN UINTN Size, // rdx
; IN VOID *Buffer // r8
; );
;------------------------------------------------------------------------------
-global ASM_PFX(IoWriteFifo32)
-ASM_PFX(IoWriteFifo32):
+global ASM_PFX(SevIoWriteFifo32)
+ASM_PFX(SevIoWriteFifo32):
xchg rcx, rdx
xchg rsi, r8 ; rsi: buffer address; r8: save rsi

--
2.29.2.windows.2


[PATCH V6 08/42] MdePkg: Support mmio for Tdx guest in BaseIoLibIntrinsic

Min Xu
 

RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429

TDVF access MMIO with TDG.VP.VMCALL to invoke VMM provided emulation
functions. If the access to MMIO fails, it fall backs to the direct
access.

BaseIoLibIntrinsic.inf is the IoLib used by other packages. It will
not support I/O in Td guest. But some files are shared between
BaseIoLibIntrinsic and BaseIoLibIntrinsicSev (IoLib.c is the example). So
IoLibInternalTdxNull.c (which holds the null stub of the Td I/O routines)
is included in BaseIoLibIntrinsic.inf. BaseIoLibIntrinsic.inf doesn't
import TdxLib so that the Pkgs which include BaseIoLibIntrinsic.inf
need not include TdxLib.

Cc: Michael D Kinney <michael.d.kinney@...>
Cc: Liming Gao <gaoliming@...>
Cc: Zhiguang Liu <zhiguang.liu@...>
Cc: Brijesh Singh <brijesh.singh@...>
Cc: Erdem Aktas <erdemaktas@...>
Cc: James Bottomley <jejb@...>
Cc: Jiewen Yao <jiewen.yao@...>
Cc: Tom Lendacky <thomas.lendacky@...>
Cc: Gerd Hoffmann <kraxel@...>
Acked-by: Gerd Hoffmann <kraxel@...>
Signed-off-by: Min Xu <min.m.xu@...>
---
.../BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf | 2 +
.../BaseIoLibIntrinsicSev.inf | 3 +
MdePkg/Library/BaseIoLibIntrinsic/IoLib.c | 81 +++++++++++++++++--
3 files changed, 78 insertions(+), 8 deletions(-)

diff --git a/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf b/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf
index 97eeada0656e..27b15d9ae256 100644
--- a/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf
+++ b/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf
@@ -34,6 +34,8 @@
IoLibMmioBuffer.c
BaseIoLibIntrinsicInternal.h
IoHighLevel.c
+ IoLibInternalTdxNull.c
+ IoLibTdx.h

[Sources.IA32]
IoLibGcc.c | GCC
diff --git a/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicSev.inf b/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicSev.inf
index 336d79736d9a..a74e54bee8b5 100644
--- a/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicSev.inf
+++ b/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicSev.inf
@@ -30,17 +30,20 @@
IoLibMmioBuffer.c
BaseIoLibIntrinsicInternal.h
IoHighLevel.c
+ IoLibTdx.h

[Sources.IA32]
IoLibGcc.c | GCC
IoLibMsc.c | MSFT
IoLib.c
+ IoLibInternalTdxNull.c
Ia32/IoFifoSev.nasm

[Sources.X64]
IoLibGcc.c | GCC
IoLibMsc.c | MSFT
IoLib.c
+ IoLibInternalTdx.c
X64/IoFifoSev.nasm

[Packages]
diff --git a/MdePkg/Library/BaseIoLibIntrinsic/IoLib.c b/MdePkg/Library/BaseIoLibIntrinsic/IoLib.c
index 9d42e21a691c..5bd02b56a1fa 100644
--- a/MdePkg/Library/BaseIoLibIntrinsic/IoLib.c
+++ b/MdePkg/Library/BaseIoLibIntrinsic/IoLib.c
@@ -7,6 +7,7 @@
**/

#include "BaseIoLibIntrinsicInternal.h"
+#include "IoLibTdx.h"

/**
Reads a 64-bit I/O port.
@@ -69,6 +70,8 @@ IoWrite64 (

If 8-bit MMIO register operations are not supported, then ASSERT().

+ For Td guest TDVMCALL_MMIO is invoked to read MMIO registers.
+
@param Address The MMIO register to read.

@return The value read.
@@ -86,7 +89,13 @@ MmioRead8 (
Flag = FilterBeforeMmIoRead (FilterWidth8, Address, &Value);
if (Flag) {
MemoryFence ();
- Value = *(volatile UINT8 *)Address;
+
+ if (IsTdxGuest ()) {
+ Value = TdMmioRead8 (Address);
+ } else {
+ Value = *(volatile UINT8 *)Address;
+ }
+
MemoryFence ();
}

@@ -104,6 +113,8 @@ MmioRead8 (

If 8-bit MMIO register operations are not supported, then ASSERT().

+ For Td guest TDVMCALL_MMIO is invoked to write MMIO registers.
+
@param Address The MMIO register to write.
@param Value The value to write to the MMIO register.

@@ -122,7 +133,13 @@ MmioWrite8 (
Flag = FilterBeforeMmIoWrite (FilterWidth8, Address, &Value);
if (Flag) {
MemoryFence ();
- *(volatile UINT8 *)Address = Value;
+
+ if (IsTdxGuest ()) {
+ TdMmioWrite8 (Address, Value);
+ } else {
+ *(volatile UINT8 *)Address = Value;
+ }
+
MemoryFence ();
}

@@ -141,6 +158,8 @@ MmioWrite8 (
If 16-bit MMIO register operations are not supported, then ASSERT().
If Address is not aligned on a 16-bit boundary, then ASSERT().

+ For Td guest TDVMCALL_MMIO is invoked to read MMIO registers.
+
@param Address The MMIO register to read.

@return The value read.
@@ -159,7 +178,13 @@ MmioRead16 (
Flag = FilterBeforeMmIoRead (FilterWidth16, Address, &Value);
if (Flag) {
MemoryFence ();
- Value = *(volatile UINT16 *)Address;
+
+ if (IsTdxGuest ()) {
+ Value = TdMmioRead16 (Address);
+ } else {
+ Value = *(volatile UINT16 *)Address;
+ }
+
MemoryFence ();
}

@@ -178,6 +203,8 @@ MmioRead16 (
If 16-bit MMIO register operations are not supported, then ASSERT().
If Address is not aligned on a 16-bit boundary, then ASSERT().

+ For Td guest TDVMCALL_MMIO is invoked to write MMIO registers.
+
@param Address The MMIO register to write.
@param Value The value to write to the MMIO register.

@@ -198,7 +225,13 @@ MmioWrite16 (
Flag = FilterBeforeMmIoWrite (FilterWidth16, Address, &Value);
if (Flag) {
MemoryFence ();
- *(volatile UINT16 *)Address = Value;
+
+ if (IsTdxGuest ()) {
+ TdMmioWrite16 (Address, Value);
+ } else {
+ *(volatile UINT16 *)Address = Value;
+ }
+
MemoryFence ();
}

@@ -217,6 +250,8 @@ MmioWrite16 (
If 32-bit MMIO register operations are not supported, then ASSERT().
If Address is not aligned on a 32-bit boundary, then ASSERT().

+ For Td guest TDVMCALL_MMIO is invoked to read MMIO registers.
+
@param Address The MMIO register to read.

@return The value read.
@@ -236,7 +271,13 @@ MmioRead32 (
Flag = FilterBeforeMmIoRead (FilterWidth32, Address, &Value);
if (Flag) {
MemoryFence ();
- Value = *(volatile UINT32 *)Address;
+
+ if (IsTdxGuest ()) {
+ Value = TdMmioRead32 (Address);
+ } else {
+ Value = *(volatile UINT32 *)Address;
+ }
+
MemoryFence ();
}

@@ -255,6 +296,8 @@ MmioRead32 (
If 32-bit MMIO register operations are not supported, then ASSERT().
If Address is not aligned on a 32-bit boundary, then ASSERT().

+ For Td guest TDVMCALL_MMIO is invoked to write MMIO registers.
+
@param Address The MMIO register to write.
@param Value The value to write to the MMIO register.

@@ -275,7 +318,13 @@ MmioWrite32 (
Flag = FilterBeforeMmIoWrite (FilterWidth32, Address, &Value);
if (Flag) {
MemoryFence ();
- *(volatile UINT32 *)Address = Value;
+
+ if (IsTdxGuest ()) {
+ TdMmioWrite32 (Address, Value);
+ } else {
+ *(volatile UINT32 *)Address = Value;
+ }
+
MemoryFence ();
}

@@ -294,6 +343,8 @@ MmioWrite32 (
If 64-bit MMIO register operations are not supported, then ASSERT().
If Address is not aligned on a 64-bit boundary, then ASSERT().

+ For Td guest TDVMCALL_MMIO is invoked to read MMIO registers.
+
@param Address The MMIO register to read.

@return The value read.
@@ -313,7 +364,13 @@ MmioRead64 (
Flag = FilterBeforeMmIoRead (FilterWidth64, Address, &Value);
if (Flag) {
MemoryFence ();
- Value = *(volatile UINT64 *)Address;
+
+ if (IsTdxGuest ()) {
+ Value = TdMmioRead64 (Address);
+ } else {
+ Value = *(volatile UINT64 *)Address;
+ }
+
MemoryFence ();
}

@@ -332,6 +389,8 @@ MmioRead64 (
If 64-bit MMIO register operations are not supported, then ASSERT().
If Address is not aligned on a 64-bit boundary, then ASSERT().

+ For Td guest TDVMCALL_MMIO is invoked to write MMIO registers.
+
@param Address The MMIO register to write.
@param Value The value to write to the MMIO register.

@@ -350,7 +409,13 @@ MmioWrite64 (
Flag = FilterBeforeMmIoWrite (FilterWidth64, Address, &Value);
if (Flag) {
MemoryFence ();
- *(volatile UINT64 *)Address = Value;
+
+ if (IsTdxGuest ()) {
+ TdMmioWrite64 (Address, Value);
+ } else {
+ *(volatile UINT64 *)Address = Value;
+ }
+
MemoryFence ();
}

--
2.29.2.windows.2

4221 - 4240 of 90923