public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [PATCH V12 00/47] Enable Intel TDX in OvmfPkg (Config-A)
@ 2022-03-29 23:45 Min Xu
  2022-03-29 23:45 ` [PATCH V12 01/47] MdePkg: Add Tdx.h Min Xu
                   ` (40 more replies)
  0 siblings, 41 replies; 53+ messages in thread
From: Min Xu @ 2022-03-29 23:45 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Brijesh Singh, Eric Dong, Erdem Aktas, Hao A Wu,
	Jian J Wang, James Bottomley, Jiewen Yao, Liming Gao,
	Michael D Kinney, Ray Ni, Rahul Kumar, Tom Lendacky, Zhiguang Liu,
	Gerd Hoffmann

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3249

Intel's Trust Domain Extensions (Intel TDX) refers to an Intel technology
that extends Virtual Machines Extensions (VMX) and Multi-Key Total Memory
Encryption (MKTME) with a new kind of virutal machines guest called a 
Trust Domain (TD). A TD is desinged to run in a CPU mode that protects the
confidentiality of TD memory contents and the TD's CPU state from other
software, including the hosting Virtual-Machine Monitor (VMM), unless
explicitly shared by the TD itself.

There are 2 configurations for TDVF to upstream. See below link for
the definitions of the 2 configurations.
https://edk2.groups.io/g/devel/message/76367

This patch-set is to enable Config-A in OvmfPkg.
 - Merge the *basic* TDVF feature to existing OvmfX64Pkg.dsc. (Align
   with existing SEV)
 - Threat model: VMM is NOT out of TCB. (We don’t make things worse.)
 - The OvmfX64Pkg.dsc includes SEV/TDX/normal OVMF basic boot capability.
   The final binary can run on SEV/TDX/normal OVMF
 - No changes to existing OvmfPkgX64 image layout.
 - No need to add additional security features if they do not exist today
 - No need to remove features if they exist today.
 - RTMR is not supported
 - PEI phase is NOT skipped in either Td or Non-Td

Patch 01 - 33 are changes in SEC phase. Also some libraries in these
patches are workable in SEC/PEI/DXE.

Patch 16 - 29 extract the common codes from OvmfPkg/PlatformPei to a new
PlatformInitLib. After that OvmfPkg/PlatformPei is refactored with this
lib. These 14 patches are currently reviewed in another separate
patch-set. https://edk2.groups.io/g/devel/message/87327

Patch 34 - 39 are changes in PEI phase.

Patch 40 - 44 are changes in DXE phase.

Patch 45 - 47 are for local Apic timer DXE driver.

[TDX]: https://software.intel.com/content/dam/develop/external/us/en/
documents/tdx-whitepaper-final9-17.pdf

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

[TDVF]: https://software.intel.com/content/dam/develop/external/us/en/
documents/tdx-virtual-firmware-design-guide-rev-1.pdf

[GCHI]: https://software.intel.com/content/dam/develop/external/us/en/
documents/intel-tdx-guest-hypervisor-communication-interface-1.0-344426-002.pdf

Code is at https://github.com/mxu9/edk2/tree/tdvf_wave2.v12

v12 changes:
 - Update MpInitLib based on the review feedbacks. Please see
   https://edk2.groups.io/g/devel/message/88173.
 - Update the code base to 2b4b8013fe45.

v11 changes:
 - Update MpInitlib based on the review comments. Please see
   https://edk2.groups.io/g/devel/message/88089
 - Update the code base to 3ef2071927fa.

v10 changes:
 - Update MpInitLib based on the review comments. Please see the
   discussion: https://edk2.groups.io/g/devel/message/87902
 - Update the code base to ec0b54849b23.

v9 changes:
 - Move the definition of EFI_RESOURCE_MEMORY_UNACCEPTED from MdePkg
   to OvmfPkg as in internal implementation. Because it has not been
   added in PI spec. After the definition is added in PI spec, it can
   be moved to MdePkg.
 - Add definition of new CPUID leaf 0x21 in
   MdePkg/Include/Register/Intel/Cpuid.h.
 - Use switch-case to hanle VC/VE handling together in
   CpuExceptionHandlerLib.
 - Refactor changes for Tdx guest in MpInitLib.
 - Refine the comments in BaseLib and PlatformInitLib.
 - Other minor updates and changes.

v8 changes:
 - Based on the comments of PlatformInitLib and OvmfPkg/PlatformPei,
   a separte patch-set is created for the changes. It is now under review
   https://edk2.groups.io/g/devel/message/87327
 - Based on the comments, TdCall/TdVmCall/TdIsEnabled is wrapped with
   MDE_CPU_IA32 and MDE_CPU_X64.
 - EFI_RESOURCE_ATTRIBUTE_ENCRYPTED is removed based on the TDVF Spec
   update. Instead EFI_RESOURCE_MEMORY_UNACCEPTED is added to indicate
   the memory which to be accepted in TDVF. The corresponding logic
   of AcceptMemory is updated as well. Please see Patch 31.
 - PcdIa32EferChangeAllowed is deleted. Because for Td guest
   IA32_EFER.NXE is set by default. So we only need check whether it has
   been set before it is to be set again. See Patch 35.
 - Based on comments PcdTdxSharedBitMask is defined in
   [PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
 - Delete un-necessary header files in TdxLib.h.
 - Other minor updates and changes.

v7 changes:
 - Based on the comments from last review, 8 PlatformInitLib patches
   are squashed into 4 patches (#17-#20). These 4 patches are not
   related to Tdx guest. Tdx related codes of PlatformInitLib is
   in #21.
 - gUefiOvmfPkgTdxPlatformGuid is renamed as gUefiOvmfPkgPlatformInfoGuid.
   Because this GUID is used not only by Tdx guest, but also by
   Legacy guest.
 - PlatformInitLibNull is deleted.
 - In PlatformPei Pml4Entries is cap at 512 entries when
   mPhysMemAddressWidth > 48.

v7 not-addressed comments
 - Comments in MpInitLib have not been addressed yet. It will be
   addressed in the following version.
 - Thanks much for your understanding.

v6 changes:
 - PlatformInitLib and OvmfPkg/PlatformPei refactoring are covered in
   patch from 17 - 24. These patches are not related to Tdx guest. Tdx
   related codes of PlatformInitLib is in patch 25.
 - In the previous patch-sets, TdHob is processed in
   OvmfPkg/Sec/IntelTdx.c. Per Gerd's suggestion they are now moved
   to PlatformInitLib/IntelTdx.c. So that they can be reused in Config-B.
 - The default Accept page size is changed from 4K to 2M.
 - The BspAcceptMemoryResourceRange is refactored according to Gerd's
   comment.
 - In ApRunLoop.nasm command field is set to zero as acknowledgement.
   This is a fix based on the ACPI Spec v6.4,Sec titled "Multiprocessor
   Wakeup Structure".

v6 not-addressed comments
 - Comments in MpInitLib have not been addressed yet. It will be
   addressed in the following version.
 - Thanks much for your understanding.

v5 changes:
 - PlatformInitLib is introduced which wraps the common functions in
   OvmfPkg/PlatformPei. It is because there are a lot of duplicated
   codes for Platform initialization in PEI phase and there are at least
   3 variants of PlatformPei. Another reason is that in TDVF Config-B
   PEI-less boot needs the similar initiliazation as PlatformPei. Based
   on the discussion with the community, PlatformInitLib is introduced.
   As the first stage OvmfPkg/PlatformPei is refactored with this lib.
   In the future the other 2 PlatformPei variants will be refactored
   as well.
 - PcdIgnoreVeHalt is deprecated.
 - Add spec link for Mailbox.
 - Other minor changes, such as comments, uncrustify formats, etc.

v5 not-addressed comments
 - Comments in MpInitLib have not been addressed yet. It will be
   addressed in the following version.
 - Some comments may be missed. I will re-visit the review emails.
 - Thanks much for your understanding.

v4 changes:
 - Split the TdxLib into 2 libraries. The TDX basic functions
   (TdCall / TdVmCall / TdIsEnabled) are moved to BaseLib (#2).
   The other functions are in TdxLib. (#3)
 - Based on above changes (TdCall/TdVmCall/TdIsEnabled in BaseLib)
   the TdxLib.inf is not necessary in some Pkgs, such as
   UefiPayloadPkg. The duplicated source code are deleted (BaseIoLib
   is the sample).
 - Drop the Accepting pages with TDX MP service. Instead only BSP
   accepts pages. There maybe boot performance issue. There are some
   mitigations to it, such as 2M accept page size, lazy accept, etc.
   We will re-visit this issue in a separate patch-set.
 - Relocate Mailbox in TdxDxe driver instead of in PlatformPei. This
   is to keep consistence with Config-B (PEI is skipped in Config-B).
 - SetMmioSharedBit in TdxDxe driver instead of in DxeIplPeim after
   CreateIdentityMappingPageTables. This is to keep consistence with
   Config-B (PEI is skipped in Config-B).
 - Some other minor changes, such as switch-case indention.
 - Rebase the code base (commit: 8c06c53b585a) and update the code with
   uncrustify.

v4 not-addressed comments:
 - Comments in MpInitLib have not been addressed yet. It will be
   addressed in the next version.
 - BaseMemEncryptTdxLib is suggested to be merged with
   BaseMemEncryptSevLib. It will be addressed in the next version.
 - Gerd suggests a generic page table walker which is able to set
   and clear bits for a given memory range in both SEV and TDX guest.
   This suggestion will be addressed in the next version.
 - Some comments may be missed. I will re-visit the review emails.
 - Thanks much for your understanding.

v3 changes:
 - LocalApicTimerDxe is split out to be a separate patch-series.
 - VmTdExitLibNull/VmgExitLib are removed. Instead the VmgExitLib
   is extended to handle #VE exception. (Patch 3-5)
 - Split the Tdx support of base IoLib into 4 commits. (Patch 6-9)
 - Alter of MADT table is updated. In previous version it was
   created from scratch. Now it gets the installed table, copy
   it to a larger buffer and append the ACPI_MADT_MPWK to it.
   (Patch 25)
 - Changes in BaseXApicX2ApicLib is refined based on the
   feedbacks. (Add spec link of MSR access definition, rename
   some funtion name, etc.) (Patch 11)
 - Use PcdConfidentialComputingGuestAttr to probe TDX guest instead
   of CPUID. But in some cases PcdConfidentialComputingGuestAttr
   cannot be used because it has not been set yet.
 - Some other minor changes.
 
v3 not-addressed comments:
 - Some of the comments have not been addressed. This is because I
   need more time to consider how to address these comments.
   At the same time I want to submit a new version based on the above
   changes so that community can review in a more efficient way.
   (v2 is the version one month ago).
 - Comments in MpInitLib have not been addressed yet. It will be
   addressed in v4.
 - BaseMemEncryptTdxLib should be merged with BaseMemEncryptSevLib.
   It will be addressed in v4.
 - Some comments may be missed. I will re-visit the review emails.
 - Thanks much for your understanding.

v2 changes:
 - Remove TdxProbeLib. It is to reduce the depencies of the lib.
 - In v1 a new function (AllocatePagesWithMemoryType) is added in
   PeiMemoryAllocationLib. This function is not necessary. It can
   be replaced by PeiServicesAllocatePages.
 - IoLibFifo.c is added in BaseIoLibIntrinsic. This file includes
   the functions of read/write of I/O  port fifo. These functions
   will call TdIoReadFifo or SevIoReadFifo by checking TDX or SEV
   in run-time.
 - DXE related patches are added. (Patch 22-28)
 - Fix typo in commit/comment message, or some minor changes.
 - Rebase the edk2 code base. (4cc1458dbe00)

Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: Hao A Wu <hao.a.wu@intel.com>
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Zhiguang Liu <zhiguang.liu@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>

Min Xu (47):
  MdePkg: Add Tdx.h
  MdePkg: Update Cpuid.h for Tdx
  MdePkg: Introduce basic Tdx functions in BaseLib
  MdePkg: Add TdxLib to wrap Tdx operations
  UefiCpuPkg: Extend VmgExitLibNull to handle #VE exception
  OvmfPkg: Extend VmgExitLib to handle #VE exception
  UefiCpuPkg/CpuExceptionHandler: Add base support for the #VE exception
  MdePkg: Add helper functions for Tdx guest in BaseIoLibIntrinsic
  MdePkg: Support mmio for Tdx guest in BaseIoLibIntrinsic
  MdePkg: Support IoFifo for Tdx guest in BaseIoLibIntrinsic
  MdePkg: Support IoRead/IoWrite for Tdx guest in BaseIoLibIntrinsic
  UefiCpuPkg: Support TDX in BaseXApicX2ApicLib
  MdePkg: Add macro to check SEV / TDX guest
  UefiCpuPkg: Enable Tdx support in MpInitLib
  OvmfPkg: Add IntelTdx.h in OvmfPkg/Include/IndustryStandard
  OvmfPkg: Add TdxMailboxLib
  OvmfPkg: Create initial version of PlatformInitLib
  OvmfPkg/PlatformInitLib: Add hob functions
  OvmfPkg/PlatformPei: Move global variables to PlatformInfoHob
  OvmfPkg/PlatformPei: Refactor MiscInitialization
  OvmfPkg/PlatformPei: Refactor MiscInitialization for CloudHV
  OvmfPkg/PlatformPei: Refactor AddressWidthInitialization
  OvmfPkg/PlatformPei: Refactor MaxCpuCountInitialization
  OvmfPkg/PlatformPei: Refactor QemuUc32BaseInitialization
  OvmfPkg/PlatformPei: Refactor InitializeRamRegions
  OvmfPkg/PlatformPei: Refactor MemMapInitialization
  OvmfPkg/PlatformPei: Refactor NoexecDxeInitialization
  OvmfPkg/PlatformPei: Refactor MiscInitialization
  OvmfPkg/PlatformInitLib: Create MemDetect.c
  OvmfPkg/PlatformInitLib: Move functions to Platform.c
  OvmfPkg: Update PlatformInitLib to process Tdx hoblist
  OvmfPkg/Sec: Declare local variable as volatile in
    SecCoreStartupWithStack
  OvmfPkg: Update Sec to support Tdx
  OvmfPkg: Check Tdx in QemuFwCfgPei to avoid DMA operation
  MdeModulePkg: Skip setting IA32_ERER.NXE if it has already been set
  MdeModulePkg: Add PcdTdxSharedBitMask
  UefiCpuPkg: Update AddressEncMask in CpuPageTable
  OvmfPkg: Update PlatformInitLib for Tdx guest
  OvmfPkg: Update PlatformPei to support Tdx guest
  OvmfPkg: Update AcpiPlatformDxe to alter MADT table
  OvmfPkg/BaseMemEncryptTdxLib: Add TDX helper library
  OvmfPkg: Add TdxDxe driver
  OvmfPkg/QemuFwCfgLib: Support Tdx in QemuFwCfgDxe
  OvmfPkg: Update IoMmuDxe to support TDX
  OvmfPkg: Rename XenTimerDxe to LocalApicTimerDxe
  UefiCpuPkg: Setting initial-count register as the last step
  OvmfPkg: Switch timer in build time for OvmfPkg

 .../Core/DxeIplPeim/X64/VirtualMemory.c       |   8 +-
 MdeModulePkg/MdeModulePkg.dec                 |   4 +
 .../Include/ConfidentialComputingGuestAttr.h  |   3 +
 MdePkg/Include/IndustryStandard/Tdx.h         | 203 ++++
 MdePkg/Include/Library/BaseLib.h              |  66 ++
 MdePkg/Include/Library/TdxLib.h               |  92 ++
 MdePkg/Include/Register/Intel/Cpuid.h         |  35 +-
 .../BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf |   2 +
 .../BaseIoLibIntrinsicSev.inf                 |   7 +
 MdePkg/Library/BaseIoLibIntrinsic/IoLib.c     |  81 +-
 MdePkg/Library/BaseIoLibIntrinsic/IoLibFifo.c | 217 ++++
 MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c  |  51 +-
 .../BaseIoLibIntrinsic/IoLibInternalTdx.c     | 674 +++++++++++++
 .../BaseIoLibIntrinsic/IoLibInternalTdxNull.c | 497 +++++++++
 MdePkg/Library/BaseIoLibIntrinsic/IoLibMsc.c  |  73 +-
 MdePkg/Library/BaseIoLibIntrinsic/IoLibSev.h  | 166 +++
 MdePkg/Library/BaseIoLibIntrinsic/IoLibTdx.h  | 410 ++++++++
 .../BaseIoLibIntrinsic/X64/IoFifoSev.nasm     |  34 +-
 MdePkg/Library/BaseLib/BaseLib.inf            |   4 +
 MdePkg/Library/BaseLib/IntelTdxNull.c         |  83 ++
 MdePkg/Library/BaseLib/X64/TdCall.nasm        |  85 ++
 MdePkg/Library/BaseLib/X64/TdProbe.c          |  63 ++
 MdePkg/Library/BaseLib/X64/TdVmcall.nasm      | 145 +++
 MdePkg/Library/TdxLib/AcceptPages.c           | 181 ++++
 MdePkg/Library/TdxLib/Rtmr.c                  |  84 ++
 MdePkg/Library/TdxLib/TdInfo.c                | 115 +++
 MdePkg/Library/TdxLib/TdxLib.inf              |  37 +
 MdePkg/Library/TdxLib/TdxLibNull.c            | 106 ++
 MdePkg/MdePkg.dec                             |   3 +
 MdePkg/MdePkg.dsc                             |   1 +
 OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf   |   1 +
 OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c       |  14 +-
 OvmfPkg/AmdSev/AmdSevX64.dsc                  |  11 +-
 OvmfPkg/AmdSev/AmdSevX64.fdf                  |   3 +-
 OvmfPkg/Bhyve/BhyveX64.dsc                    |   5 +
 OvmfPkg/CloudHv/CloudHvX64.dsc                |   8 +-
 OvmfPkg/CloudHv/CloudHvX64.fdf                |   2 +-
 OvmfPkg/Include/IndustryStandard/IntelTdx.h   |  67 ++
 OvmfPkg/Include/Library/MemEncryptTdxLib.h    |  81 ++
 OvmfPkg/Include/Library/PlatformInitLib.h     | 237 +++++
 OvmfPkg/Include/Library/TdxMailboxLib.h       |  76 ++
 .../Include/Protocol/QemuAcpiTableNotify.h    |  27 +
 OvmfPkg/Include/TdxCommondefs.inc             |  51 +
 OvmfPkg/IoMmuDxe/AmdSevIoMmu.c                | 103 +-
 OvmfPkg/IoMmuDxe/AmdSevIoMmu.h                |   6 +-
 OvmfPkg/IoMmuDxe/IoMmuDxe.c                   |   6 +-
 OvmfPkg/IoMmuDxe/IoMmuDxe.inf                 |   5 +
 .../BaseMemEncryptTdxLib.inf                  |  44 +
 .../BaseMemEncryptTdxLibNull.inf              |  35 +
 .../BaseMemoryEncryptionNull.c                |  90 ++
 .../BaseMemEncryptTdxLib/MemoryEncryption.c   | 948 ++++++++++++++++++
 .../BaseMemEncryptTdxLib/VirtualMemory.h      | 181 ++++
 .../PlatformInitLib}/Cmos.c                   |  32 +-
 OvmfPkg/Library/PlatformInitLib/IntelTdx.c    | 563 +++++++++++
 .../Library/PlatformInitLib/IntelTdxNull.c    |  46 +
 OvmfPkg/Library/PlatformInitLib/MemDetect.c   | 856 ++++++++++++++++
 OvmfPkg/Library/PlatformInitLib/Platform.c    | 573 +++++++++++
 .../PlatformInitLib/PlatformInitLib.inf       |  98 ++
 OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgDxe.c   |   9 +-
 .../Library/QemuFwCfgLib/QemuFwCfgDxeLib.inf  |   1 +
 .../QemuFwCfgLib/QemuFwCfgLibInternal.h       |  11 +
 OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPei.c   |  32 +
 .../Library/QemuFwCfgLib/QemuFwCfgPeiLib.inf  |   2 +
 OvmfPkg/Library/TdxMailboxLib/TdxMailbox.c    | 141 +++
 .../Library/TdxMailboxLib/TdxMailboxLib.inf   |  52 +
 .../Library/TdxMailboxLib/TdxMailboxNull.c    |  85 ++
 OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf  |   3 +-
 OvmfPkg/Library/VmgExitLib/VmTdExitHandler.h  |  32 +
 .../Library/VmgExitLib/VmTdExitVeHandler.c    | 559 +++++++++++
 OvmfPkg/Library/VmgExitLib/VmgExitLib.inf     |   2 +
 .../Library/VmgExitLib/X64/TdVmcallCpuid.nasm | 146 +++
 .../LocalApicTimerDxe.c}                      |   4 +-
 .../LocalApicTimerDxe.h}                      |   4 +-
 .../LocalApicTimerDxe.inf}                    |   7 +-
 OvmfPkg/Microvm/MicrovmX64.dsc                |   8 +-
 OvmfPkg/Microvm/MicrovmX64.fdf                |   2 +-
 OvmfPkg/OvmfPkg.dec                           |  17 +
 OvmfPkg/OvmfPkgIa32.dsc                       |  15 +-
 OvmfPkg/OvmfPkgIa32.fdf                       |   8 +-
 OvmfPkg/OvmfPkgIa32X64.dsc                    |  15 +-
 OvmfPkg/OvmfPkgIa32X64.fdf                    |   8 +-
 OvmfPkg/OvmfPkgX64.dsc                        |  32 +-
 OvmfPkg/OvmfPkgX64.fdf                        |  11 +-
 OvmfPkg/OvmfXen.dsc                           |   7 +-
 OvmfPkg/OvmfXen.fdf                           |   2 +-
 OvmfPkg/PlatformPei/AmdSev.c                  |   8 +-
 OvmfPkg/PlatformPei/Cmos.h                    |  48 -
 OvmfPkg/PlatformPei/FeatureControl.c          |   7 +-
 OvmfPkg/PlatformPei/Fv.c                      |   4 +-
 OvmfPkg/PlatformPei/IntelTdx.c                |  51 +
 OvmfPkg/PlatformPei/MemDetect.c               | 889 ++--------------
 OvmfPkg/PlatformPei/MemTypeInfo.c             |   2 +-
 OvmfPkg/PlatformPei/Platform.c                | 631 ++----------
 OvmfPkg/PlatformPei/Platform.h                |  97 +-
 OvmfPkg/PlatformPei/PlatformPei.inf           |   6 +-
 OvmfPkg/Sec/SecMain.c                         |  44 +-
 OvmfPkg/Sec/SecMain.inf                       |   3 +
 OvmfPkg/Sec/X64/SecEntry.nasm                 |  82 ++
 OvmfPkg/TdxDxe/TdxAcpiTable.c                 | 213 ++++
 OvmfPkg/TdxDxe/TdxAcpiTable.h                 |  60 ++
 OvmfPkg/TdxDxe/TdxDxe.c                       | 261 +++++
 OvmfPkg/TdxDxe/TdxDxe.inf                     |  64 ++
 OvmfPkg/TdxDxe/X64/ApRunLoop.nasm             |  90 ++
 UefiCpuPkg/CpuDxe/CpuDxe.inf                  |   1 +
 UefiCpuPkg/CpuDxe/CpuPageTable.c              |   3 +
 UefiCpuPkg/Include/Library/VmgExitLib.h       |  28 +
 .../BaseXApicX2ApicLib/BaseXApicX2ApicLib.c   | 170 +++-
 .../PeiDxeSmmCpuException.c                   |  53 +-
 .../SecPeiCpuException.c                      |  57 +-
 UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf |   3 +
 UefiCpuPkg/Library/MpInitLib/MpIntelTdx.h     |  69 ++
 UefiCpuPkg/Library/MpInitLib/MpLib.c          |  63 +-
 UefiCpuPkg/Library/MpInitLib/MpLibTdx.c       | 106 ++
 UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c   |  69 ++
 UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf |   3 +
 .../Library/VmgExitLibNull/VmTdExitNull.c     |  38 +
 .../Library/VmgExitLibNull/VmgExitLibNull.inf |   1 +
 117 files changed, 10472 insertions(+), 1666 deletions(-)
 create mode 100644 MdePkg/Include/IndustryStandard/Tdx.h
 create mode 100644 MdePkg/Include/Library/TdxLib.h
 create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/IoLibFifo.c
 create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdx.c
 create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdxNull.c
 create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/IoLibSev.h
 create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/IoLibTdx.h
 create mode 100644 MdePkg/Library/BaseLib/IntelTdxNull.c
 create mode 100644 MdePkg/Library/BaseLib/X64/TdCall.nasm
 create mode 100644 MdePkg/Library/BaseLib/X64/TdProbe.c
 create mode 100644 MdePkg/Library/BaseLib/X64/TdVmcall.nasm
 create mode 100644 MdePkg/Library/TdxLib/AcceptPages.c
 create mode 100644 MdePkg/Library/TdxLib/Rtmr.c
 create mode 100644 MdePkg/Library/TdxLib/TdInfo.c
 create mode 100644 MdePkg/Library/TdxLib/TdxLib.inf
 create mode 100644 MdePkg/Library/TdxLib/TdxLibNull.c
 create mode 100644 OvmfPkg/Include/IndustryStandard/IntelTdx.h
 create mode 100644 OvmfPkg/Include/Library/MemEncryptTdxLib.h
 create mode 100644 OvmfPkg/Include/Library/PlatformInitLib.h
 create mode 100644 OvmfPkg/Include/Library/TdxMailboxLib.h
 create mode 100644 OvmfPkg/Include/Protocol/QemuAcpiTableNotify.h
 create mode 100644 OvmfPkg/Include/TdxCommondefs.inc
 create mode 100644 OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLib.inf
 create mode 100644 OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLibNull.inf
 create mode 100644 OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemoryEncryptionNull.c
 create mode 100644 OvmfPkg/Library/BaseMemEncryptTdxLib/MemoryEncryption.c
 create mode 100644 OvmfPkg/Library/BaseMemEncryptTdxLib/VirtualMemory.h
 rename OvmfPkg/{PlatformPei => Library/PlatformInitLib}/Cmos.c (61%)
 create mode 100644 OvmfPkg/Library/PlatformInitLib/IntelTdx.c
 create mode 100644 OvmfPkg/Library/PlatformInitLib/IntelTdxNull.c
 create mode 100644 OvmfPkg/Library/PlatformInitLib/MemDetect.c
 create mode 100644 OvmfPkg/Library/PlatformInitLib/Platform.c
 create mode 100644 OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
 create mode 100644 OvmfPkg/Library/TdxMailboxLib/TdxMailbox.c
 create mode 100644 OvmfPkg/Library/TdxMailboxLib/TdxMailboxLib.inf
 create mode 100644 OvmfPkg/Library/TdxMailboxLib/TdxMailboxNull.c
 create mode 100644 OvmfPkg/Library/VmgExitLib/VmTdExitHandler.h
 create mode 100644 OvmfPkg/Library/VmgExitLib/VmTdExitVeHandler.c
 create mode 100644 OvmfPkg/Library/VmgExitLib/X64/TdVmcallCpuid.nasm
 rename OvmfPkg/{XenTimerDxe/XenTimerDxe.c => LocalApicTimerDxe/LocalApicTimerDxe.c} (95%)
 rename OvmfPkg/{XenTimerDxe/XenTimerDxe.h => LocalApicTimerDxe/LocalApicTimerDxe.h} (96%)
 rename OvmfPkg/{XenTimerDxe/XenTimerDxe.inf => LocalApicTimerDxe/LocalApicTimerDxe.inf} (80%)
 delete mode 100644 OvmfPkg/PlatformPei/Cmos.h
 create mode 100644 OvmfPkg/PlatformPei/IntelTdx.c
 create mode 100644 OvmfPkg/TdxDxe/TdxAcpiTable.c
 create mode 100644 OvmfPkg/TdxDxe/TdxAcpiTable.h
 create mode 100644 OvmfPkg/TdxDxe/TdxDxe.c
 create mode 100644 OvmfPkg/TdxDxe/TdxDxe.inf
 create mode 100644 OvmfPkg/TdxDxe/X64/ApRunLoop.nasm
 create mode 100644 UefiCpuPkg/Library/MpInitLib/MpIntelTdx.h
 create mode 100644 UefiCpuPkg/Library/MpInitLib/MpLibTdx.c
 create mode 100644 UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c
 create mode 100644 UefiCpuPkg/Library/VmgExitLibNull/VmTdExitNull.c

-- 
2.29.2.windows.2


^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH V12 01/47] MdePkg: Add Tdx.h
  2022-03-29 23:45 [PATCH V12 00/47] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
@ 2022-03-29 23:45 ` Min Xu
  2022-03-29 23:45 ` [PATCH V12 02/47] MdePkg: Update Cpuid.h for Tdx Min Xu
                   ` (39 subsequent siblings)
  40 siblings, 0 replies; 53+ messages in thread
From: Min Xu @ 2022-03-29 23:45 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Michael D Kinney, Liming Gao, Zhiguang Liu, Gerd Hoffmann,
	Jiewen Yao

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

Tdx.h includes the Intel Trust Domain Extension definitions.

Detailed information can be found in below document:
https://software.intel.com/content/dam/develop/external/us/en/
documents/tdx-module-1eas-v0.85.039.pdf

Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Zhiguang Liu <zhiguang.liu@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Liming Gao <gaoliming@byosoft.com.cn>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 MdePkg/Include/IndustryStandard/Tdx.h | 203 ++++++++++++++++++++++++++
 1 file changed, 203 insertions(+)
 create mode 100644 MdePkg/Include/IndustryStandard/Tdx.h

diff --git a/MdePkg/Include/IndustryStandard/Tdx.h b/MdePkg/Include/IndustryStandard/Tdx.h
new file mode 100644
index 000000000000..81df1361842b
--- /dev/null
+++ b/MdePkg/Include/IndustryStandard/Tdx.h
@@ -0,0 +1,203 @@
+/** @file
+  Intel Trust Domain Extension definitions
+  Detailed information is in below document:
+  https://software.intel.com/content/dam/develop/external/us/en/documents
+  /tdx-module-1eas-v0.85.039.pdf
+
+  Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef MDE_PKG_TDX_H_
+#define MDE_PKG_TDX_H_
+
+#define EXIT_REASON_EXTERNAL_INTERRUPT  1
+#define EXIT_REASON_TRIPLE_FAULT        2
+
+#define EXIT_REASON_PENDING_INTERRUPT    7
+#define EXIT_REASON_NMI_WINDOW           8
+#define EXIT_REASON_TASK_SWITCH          9
+#define EXIT_REASON_CPUID                10
+#define EXIT_REASON_HLT                  12
+#define EXIT_REASON_INVD                 13
+#define EXIT_REASON_INVLPG               14
+#define EXIT_REASON_RDPMC                15
+#define EXIT_REASON_RDTSC                16
+#define EXIT_REASON_VMCALL               18
+#define EXIT_REASON_VMCLEAR              19
+#define EXIT_REASON_VMLAUNCH             20
+#define EXIT_REASON_VMPTRLD              21
+#define EXIT_REASON_VMPTRST              22
+#define EXIT_REASON_VMREAD               23
+#define EXIT_REASON_VMRESUME             24
+#define EXIT_REASON_VMWRITE              25
+#define EXIT_REASON_VMOFF                26
+#define EXIT_REASON_VMON                 27
+#define EXIT_REASON_CR_ACCESS            28
+#define EXIT_REASON_DR_ACCESS            29
+#define EXIT_REASON_IO_INSTRUCTION       30
+#define EXIT_REASON_MSR_READ             31
+#define EXIT_REASON_MSR_WRITE            32
+#define EXIT_REASON_INVALID_STATE        33
+#define EXIT_REASON_MSR_LOAD_FAIL        34
+#define EXIT_REASON_MWAIT_INSTRUCTION    36
+#define EXIT_REASON_MONITOR_TRAP_FLAG    37
+#define EXIT_REASON_MONITOR_INSTRUCTION  39
+#define EXIT_REASON_PAUSE_INSTRUCTION    40
+#define EXIT_REASON_MCE_DURING_VMENTRY   41
+#define EXIT_REASON_TPR_BELOW_THRESHOLD  43
+#define EXIT_REASON_APIC_ACCESS          44
+#define EXIT_REASON_EOI_INDUCED          45
+#define EXIT_REASON_GDTR_IDTR            46
+#define EXIT_REASON_LDTR_TR              47
+#define EXIT_REASON_EPT_VIOLATION        48
+#define EXIT_REASON_EPT_MISCONFIG        49
+#define EXIT_REASON_INVEPT               50
+#define EXIT_REASON_RDTSCP               51
+#define EXIT_REASON_PREEMPTION_TIMER     52
+#define EXIT_REASON_INVVPID              53
+#define EXIT_REASON_WBINVD               54
+#define EXIT_REASON_XSETBV               55
+#define EXIT_REASON_APIC_WRITE           56
+#define EXIT_REASON_RDRAND               57
+#define EXIT_REASON_INVPCID              58
+#define EXIT_REASON_VMFUNC               59
+#define EXIT_REASON_ENCLS                60
+#define EXIT_REASON_RDSEED               61
+#define EXIT_REASON_PML_FULL             62
+#define EXIT_REASON_XSAVES               63
+#define EXIT_REASON_XRSTORS              64
+
+// TDCALL API Function Completion Status Codes
+#define TDX_EXIT_REASON_SUCCESS                0x0000000000000000
+#define TDX_EXIT_REASON_PAGE_ALREADY_ACCEPTED  0x00000B0A00000000
+#define TDX_EXIT_REASON_PAGE_SIZE_MISMATCH     0xC0000B0B00000000
+#define TDX_EXIT_REASON_OPERAND_INVALID        0xC000010000000000
+#define TDX_EXIT_REASON_OPERAND_BUSY           0x8000020000000000
+
+// TDCALL [TDG.MEM.PAGE.ACCEPT] page size
+#define TDCALL_ACCEPT_PAGE_SIZE_4K  0
+#define TDCALL_ACCEPT_PAGE_SIZE_2M  1
+#define TDCALL_ACCEPT_PAGE_SIZE_1G  2
+
+#define TDCALL_TDVMCALL      0
+#define TDCALL_TDINFO        1
+#define TDCALL_TDEXTENDRTMR  2
+#define TDCALL_TDGETVEINFO   3
+#define TDCALL_TDREPORT      4
+#define TDCALL_TDSETCPUIDVE  5
+#define TDCALL_TDACCEPTPAGE  6
+
+#define TDVMCALL_CPUID    0x0000a
+#define TDVMCALL_HALT     0x0000c
+#define TDVMCALL_IO       0x0001e
+#define TDVMCALL_RDMSR    0x0001f
+#define TDVMCALL_WRMSR    0x00020
+#define TDVMCALL_MMIO     0x00030
+#define TDVMCALL_PCONFIG  0x00041
+
+#define TDVMCALL_GET_TDVMCALL_INFO   0x10000
+#define TDVMCALL_MAPGPA              0x10001
+#define TDVMCALL_GET_QUOTE           0x10002
+#define TDVMCALL_REPORT_FATAL_ERR    0x10003
+#define TDVMCALL_SETUP_EVENT_NOTIFY  0x10004
+
+#pragma pack(1)
+typedef struct {
+  UINT64    Data[6];
+} TDCALL_GENERIC_RETURN_DATA;
+
+typedef struct {
+  UINT64    Gpaw;
+  UINT64    Attributes;
+  UINT32    MaxVcpus;
+  UINT32    NumVcpus;
+  UINT64    Resv[3];
+} TDCALL_INFO_RETURN_DATA;
+
+typedef union {
+  UINT64    Val;
+  struct {
+    UINT32    Size      : 3;
+    UINT32    Direction : 1;
+    UINT32    String    : 1;
+    UINT32    Rep       : 1;
+    UINT32    Encoding  : 1;
+    UINT32    Resv      : 9;
+    UINT32    Port      : 16;
+    UINT32    Resv2;
+  } Io;
+} VMX_EXIT_QUALIFICATION;
+
+typedef struct {
+  UINT32                    ExitReason;
+  UINT32                    Resv;
+  VMX_EXIT_QUALIFICATION    ExitQualification;
+  UINT64                    GuestLA;
+  UINT64                    GuestPA;
+  UINT32                    ExitInstructionLength;
+  UINT32                    ExitInstructionInfo;
+  UINT32                    Resv1;
+} TDCALL_VEINFO_RETURN_DATA;
+
+typedef union {
+  TDCALL_GENERIC_RETURN_DATA    Generic;
+  TDCALL_INFO_RETURN_DATA       TdInfo;
+  TDCALL_VEINFO_RETURN_DATA     VeInfo;
+} TD_RETURN_DATA;
+
+/* data structure used in TDREPORT_STRUCT */
+typedef struct {
+  UINT8    Type;
+  UINT8    Subtype;
+  UINT8    Version;
+  UINT8    Rsvd;
+} TD_REPORT_TYPE;
+
+typedef struct {
+  TD_REPORT_TYPE    ReportType;
+  UINT8             Rsvd1[12];
+  UINT8             CpuSvn[16];
+  UINT8             TeeTcbInfoHash[48];
+  UINT8             TeeInfoHash[48];
+  UINT8             ReportData[64];
+  UINT8             Rsvd2[32];
+  UINT8             Mac[32];
+} REPORTMACSTRUCT;
+
+typedef struct {
+  UINT8    Seam[2];
+  UINT8    Rsvd[14];
+} TEE_TCB_SVN;
+
+typedef struct {
+  UINT8          Valid[8];
+  TEE_TCB_SVN    TeeTcbSvn;
+  UINT8          Mrseam[48];
+  UINT8          Mrsignerseam[48];
+  UINT8          Attributes[8];
+  UINT8          Rsvd[111];
+} TEE_TCB_INFO;
+
+typedef struct {
+  UINT8    Attributes[8];
+  UINT8    Xfam[8];
+  UINT8    Mrtd[48];
+  UINT8    Mrconfigid[48];
+  UINT8    Mrowner[48];
+  UINT8    Mrownerconfig[48];
+  UINT8    Rtmrs[4][48];
+  UINT8    Rsvd[112];
+} TDINFO;
+
+typedef struct {
+  REPORTMACSTRUCT    ReportMacStruct;
+  TEE_TCB_INFO       TeeTcbInfo;
+  UINT8              Rsvd[17];
+  TDINFO             Tdinfo;
+} TDREPORT_STRUCT;
+
+#pragma pack()
+
+#endif
-- 
2.29.2.windows.2


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH V12 02/47] MdePkg: Update Cpuid.h for Tdx
  2022-03-29 23:45 [PATCH V12 00/47] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
  2022-03-29 23:45 ` [PATCH V12 01/47] MdePkg: Add Tdx.h Min Xu
@ 2022-03-29 23:45 ` Min Xu
  2022-03-29 23:45 ` [PATCH V12 03/47] MdePkg: Introduce basic Tdx functions in BaseLib Min Xu
                   ` (38 subsequent siblings)
  40 siblings, 0 replies; 53+ messages in thread
From: Min Xu @ 2022-03-29 23:45 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ray Ni, Michael D Kinney, Liming Gao, Zhiguang Liu,
	Brijesh Singh, Erdem Aktas, James Bottomley, Jiewen Yao,
	Tom Lendacky, Gerd Hoffmann

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

Guest software can be designed to run either as a TD, as a legacy virtual
machine, or directly on the CPU, based on enumeration of its run-time
environment. [TDX-Module] Chap 10.2 defines the flow and the new CPUID
leaf 0x21.

[TDX-Module] Architecture Specification: Intel(R) Trust Domain Extensions
Module, Chap 10.2, 344425-003US, August 2021
https://www.intel.com/content/dam/develop/external/us/en/documents/
tdx-module-1.0-public-spec-v0.931.pdf

Cc: Ray Ni <ray.ni@intel.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Zhiguang Liu <zhiguang.liu@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Liming Gao <gaoliming@byosoft.com.cn>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 MdePkg/Include/Register/Intel/Cpuid.h | 35 +++++++++++++++++++++++++--
 1 file changed, 33 insertions(+), 2 deletions(-)

diff --git a/MdePkg/Include/Register/Intel/Cpuid.h b/MdePkg/Include/Register/Intel/Cpuid.h
index bd6349d7940d..350bf60252e1 100644
--- a/MdePkg/Include/Register/Intel/Cpuid.h
+++ b/MdePkg/Include/Register/Intel/Cpuid.h
@@ -12,6 +12,8 @@
   @par Specification Reference:
   Intel(R) 64 and IA-32 Architectures Software Developer's Manual, Volume 2A,
   November 2018, CPUID instruction.
+  Architecture Specification: Intel(R) Trust Domain Extensions Module, Chap 10.2
+  344425-003US, August 2021
 
 **/
 
@@ -321,9 +323,9 @@ typedef union {
     ///
     UINT32    RDRAND              : 1;
     ///
-    /// [Bit 31] Always returns 0.
+    /// [Bit 31] A value of 1 indicates that processor is in Para-Virtualized.
     ///
-    UINT32    NotUsed             : 1;
+    UINT32    ParaVirtualized     : 1;
   } Bits;
   ///
   /// All bit fields as a 32-bit value
@@ -3689,6 +3691,35 @@ typedef union {
 /// @}
 ///
 
+/**
+  CPUID Guest TD Run Time Environment Enumeration Leaf
+
+  @note
+  Guest software can be designed to run either as a TD, as a legacy virtual machine,
+  or directly on the CPU, based on enumeration of its run-time environment.
+  CPUID leaf 21H emulation is done by the Intel TDX module. Sub-leaf 0 returns the values
+  shown below. Other sub-leaves return 0 in EAX/EBX/ECX/EDX.
+    EAX: 0x00000000
+    EBX: 0x65746E49 "Inte"
+    ECX: 0x20202020 "    "
+    EDX: 0x5844546C "lTDX"
+
+  @param   EAX  CPUID_GUESTTD_RUNTIME_ENVIRONMENT                        (0x21)
+  @param   ECX  Level number
+
+**/
+#define CPUID_GUESTTD_RUNTIME_ENVIRONMENT  0x21
+
+///
+/// @{ CPUID Guest TD signature values returned by Intel processors
+///
+#define CPUID_GUESTTD_SIGNATURE_GENUINE_INTEL_EBX  SIGNATURE_32 ('I', 'n', 't', 'e')
+#define CPUID_GUESTTD_SIGNATURE_GENUINE_INTEL_ECX  SIGNATURE_32 (' ', ' ', ' ', ' ')
+#define CPUID_GUESTTD_SIGNATURE_GENUINE_INTEL_EDX  SIGNATURE_32 ('l', 'T', 'D', 'X')
+///
+/// @}
+///
+
 /**
   CPUID Extended Function
 
-- 
2.29.2.windows.2


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH V12 03/47] MdePkg: Introduce basic Tdx functions in BaseLib
  2022-03-29 23:45 [PATCH V12 00/47] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
  2022-03-29 23:45 ` [PATCH V12 01/47] MdePkg: Add Tdx.h Min Xu
  2022-03-29 23:45 ` [PATCH V12 02/47] MdePkg: Update Cpuid.h for Tdx Min Xu
@ 2022-03-29 23:45 ` Min Xu
  2022-03-29 23:45 ` [PATCH V12 04/47] MdePkg: Add TdxLib to wrap Tdx operations Min Xu
                   ` (37 subsequent siblings)
  40 siblings, 0 replies; 53+ messages in thread
From: Min Xu @ 2022-03-29 23:45 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Michael D Kinney, Liming Gao, Zhiguang Liu, Brijesh Singh,
	Erdem Aktas, James Bottomley, Jiewen Yao, Tom Lendacky,
	Gerd Hoffmann

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

Introduce basic Tdx functions in BaseLib:
 - TdCall ()
 - TdVmCall ()
 - TdIsEnabled ()

Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Zhiguang Liu <zhiguang.liu@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Liming Gao <gaoliming@byosoft.com.cn>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 MdePkg/Include/Library/BaseLib.h         |  66 +++++++++++
 MdePkg/Library/BaseLib/BaseLib.inf       |   4 +
 MdePkg/Library/BaseLib/IntelTdxNull.c    |  83 +++++++++++++
 MdePkg/Library/BaseLib/X64/TdCall.nasm   |  85 +++++++++++++
 MdePkg/Library/BaseLib/X64/TdProbe.c     |  63 ++++++++++
 MdePkg/Library/BaseLib/X64/TdVmcall.nasm | 145 +++++++++++++++++++++++
 6 files changed, 446 insertions(+)
 create mode 100644 MdePkg/Library/BaseLib/IntelTdxNull.c
 create mode 100644 MdePkg/Library/BaseLib/X64/TdCall.nasm
 create mode 100644 MdePkg/Library/BaseLib/X64/TdProbe.c
 create mode 100644 MdePkg/Library/BaseLib/X64/TdVmcall.nasm

diff --git a/MdePkg/Include/Library/BaseLib.h b/MdePkg/Include/Library/BaseLib.h
index 6aa0d972186e..9d58a7c4ad13 100644
--- a/MdePkg/Include/Library/BaseLib.h
+++ b/MdePkg/Include/Library/BaseLib.h
@@ -4759,6 +4759,72 @@ SpeculationBarrier (
   VOID
   );
 
+#if defined (MDE_CPU_X64) || defined (MDE_CPU_IA32)
+
+/**
+  The TDCALL instruction causes a VM exit to the Intel TDX module.  It is
+  used to call guest-side Intel TDX functions, either local or a TD exit
+  to the host VMM, as selected by Leaf.
+
+  @param[in]      Leaf        Leaf number of TDCALL instruction
+  @param[in]      Arg1        Arg1
+  @param[in]      Arg2        Arg2
+  @param[in]      Arg3        Arg3
+  @param[in,out]  Results  Returned result of the Leaf function
+
+  @return 0               A successful call
+  @return Other           See individual leaf functions
+**/
+UINTN
+EFIAPI
+TdCall (
+  IN UINT64    Leaf,
+  IN UINT64    Arg1,
+  IN UINT64    Arg2,
+  IN UINT64    Arg3,
+  IN OUT VOID  *Results
+  );
+
+/**
+  TDVMALL is a leaf function 0 for TDCALL. It helps invoke services from the
+  host VMM to pass/receive information.
+
+  @param[in]     Leaf        Number of sub-functions
+  @param[in]     Arg1        Arg1
+  @param[in]     Arg2        Arg2
+  @param[in]     Arg3        Arg3
+  @param[in]     Arg4        Arg4
+  @param[in,out] Results     Returned result of the sub-function
+
+  @return 0               A successful call
+  @return Other           See individual sub-functions
+
+**/
+UINTN
+EFIAPI
+TdVmCall (
+  IN UINT64    Leaf,
+  IN UINT64    Arg1,
+  IN UINT64    Arg2,
+  IN UINT64    Arg3,
+  IN UINT64    Arg4,
+  IN OUT VOID  *Results
+  );
+
+/**
+  Probe if TD is enabled.
+
+  @return TRUE    TD is enabled.
+  @return FALSE   TD is not enabled.
+**/
+BOOLEAN
+EFIAPI
+TdIsEnabled (
+  VOID
+  );
+
+#endif
+
 #if defined (MDE_CPU_X64)
 //
 // The page size for the PVALIDATE instruction
diff --git a/MdePkg/Library/BaseLib/BaseLib.inf b/MdePkg/Library/BaseLib/BaseLib.inf
index cebda3b210c1..16b7ac391705 100644
--- a/MdePkg/Library/BaseLib/BaseLib.inf
+++ b/MdePkg/Library/BaseLib/BaseLib.inf
@@ -210,6 +210,7 @@
   X86RdRand.c
   X86PatchInstruction.c
   X86SpeculationBarrier.c
+  IntelTdxNull.c
 
 [Sources.X64]
   X64/Thunk16.nasm
@@ -293,6 +294,9 @@
   X64/ReadCr0.nasm| MSFT
   X64/ReadEflags.nasm| MSFT
 
+  X64/TdCall.nasm
+  X64/TdVmcall.nasm
+  X64/TdProbe.c
 
   X64/Non-existing.c
   Math64.c
diff --git a/MdePkg/Library/BaseLib/IntelTdxNull.c b/MdePkg/Library/BaseLib/IntelTdxNull.c
new file mode 100644
index 000000000000..ec95470bd43e
--- /dev/null
+++ b/MdePkg/Library/BaseLib/IntelTdxNull.c
@@ -0,0 +1,83 @@
+/** @file
+
+  Null stub of TdxLib
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/BaseLib.h>
+#include <Uefi/UefiBaseType.h>
+
+/**
+  The TDCALL instruction causes a VM exit to the Intel TDX module.  It is
+  used to call guest-side Intel TDX functions, either local or a TD exit
+  to the host VMM, as selected by Leaf.
+  Leaf functions are described at <https://software.intel.com/content/
+  www/us/en/develop/articles/intel-trust-domain-extensions.html>
+
+  @param[in]      Leaf        Leaf number of TDCALL instruction
+  @param[in]      Arg1        Arg1
+  @param[in]      Arg2        Arg2
+  @param[in]      Arg3        Arg3
+  @param[in,out]  Results  Returned result of the Leaf function
+
+  @return EFI_SUCCESS
+  @return Other           See individual leaf functions
+**/
+UINTN
+EFIAPI
+TdCall (
+  IN UINT64    Leaf,
+  IN UINT64    Arg1,
+  IN UINT64    Arg2,
+  IN UINT64    Arg3,
+  IN OUT VOID  *Results
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  TDVMALL is a leaf function 0 for TDCALL. It helps invoke services from the
+  host VMM to pass/receive information.
+
+  @param[in]     Leaf        Number of sub-functions
+  @param[in]     Arg1        Arg1
+  @param[in]     Arg2        Arg2
+  @param[in]     Arg3        Arg3
+  @param[in]     Arg4        Arg4
+  @param[in,out] Results     Returned result of the sub-function
+
+  @return EFI_SUCCESS
+  @return Other           See individual sub-functions
+
+**/
+UINTN
+EFIAPI
+TdVmCall (
+  IN UINT64    Leaf,
+  IN UINT64    Arg1,
+  IN UINT64    Arg2,
+  IN UINT64    Arg3,
+  IN UINT64    Arg4,
+  IN OUT VOID  *Results
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  Probe if TD is enabled.
+
+  @return TRUE    TD is enabled.
+  @return FALSE   TD is not enabled.
+**/
+BOOLEAN
+EFIAPI
+TdIsEnabled (
+  )
+{
+  return FALSE;
+}
diff --git a/MdePkg/Library/BaseLib/X64/TdCall.nasm b/MdePkg/Library/BaseLib/X64/TdCall.nasm
new file mode 100644
index 000000000000..e8a094b0eb3f
--- /dev/null
+++ b/MdePkg/Library/BaseLib/X64/TdCall.nasm
@@ -0,0 +1,85 @@
+;------------------------------------------------------------------------------
+;*
+;* Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
+;* SPDX-License-Identifier: BSD-2-Clause-Patent
+;*
+;*
+;------------------------------------------------------------------------------
+
+DEFAULT REL
+SECTION .text
+
+%macro tdcall 0
+    db 0x66,0x0f,0x01,0xcc
+%endmacro
+
+%macro tdcall_push_regs 0
+    push rbp
+    mov  rbp, rsp
+    push r15
+    push r14
+    push r13
+    push r12
+    push rbx
+    push rsi
+    push rdi
+%endmacro
+
+%macro tdcall_pop_regs 0
+    pop rdi
+    pop rsi
+    pop rbx
+    pop r12
+    pop r13
+    pop r14
+    pop r15
+    pop rbp
+%endmacro
+
+%define number_of_regs_pushed 8
+%define number_of_parameters  4
+
+;
+; Keep these in sync for push_regs/pop_regs, code below
+; uses them to find 5th or greater parameters
+;
+%define first_variable_on_stack_offset \
+  ((number_of_regs_pushed * 8) + (number_of_parameters * 8) + 8)
+%define second_variable_on_stack_offset \
+  ((first_variable_on_stack_offset) + 8)
+
+;  TdCall (
+;    UINT64  Leaf,    // Rcx
+;    UINT64  P1,      // Rdx
+;    UINT64  P2,      // R8
+;    UINT64  P3,      // R9
+;    UINT64  Results, // rsp + 0x28
+;    )
+global ASM_PFX(TdCall)
+ASM_PFX(TdCall):
+       tdcall_push_regs
+
+       mov rax, rcx
+       mov rcx, rdx
+       mov rdx, r8
+       mov r8, r9
+
+       tdcall
+
+       ; exit if tdcall reports failure.
+       test rax, rax
+       jnz .exit
+
+       ; test if caller wanted results
+       mov r12, [rsp + first_variable_on_stack_offset ]
+       test r12, r12
+       jz .exit
+       mov [r12 + 0 ], rcx
+       mov [r12 + 8 ], rdx
+       mov [r12 + 16], r8
+       mov [r12 + 24], r9
+       mov [r12 + 32], r10
+       mov [r12 + 40], r11
+.exit:
+       tdcall_pop_regs
+       ret
diff --git a/MdePkg/Library/BaseLib/X64/TdProbe.c b/MdePkg/Library/BaseLib/X64/TdProbe.c
new file mode 100644
index 000000000000..b893c0a004d5
--- /dev/null
+++ b/MdePkg/Library/BaseLib/X64/TdProbe.c
@@ -0,0 +1,63 @@
+/** @file
+
+  Copyright (c) 2020-2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/BaseLib.h>
+#include <Register/Intel/Cpuid.h>
+
+/**
+  Probe if TD is enabled.
+
+  @return TRUE    TD is enabled.
+  @return FALSE   TD is not enabled.
+**/
+BOOLEAN
+EFIAPI
+TdIsEnabled (
+  )
+{
+  UINT32                  Eax;
+  UINT32                  Ebx;
+  UINT32                  Ecx;
+  UINT32                  Edx;
+  UINT32                  LargestEax;
+  BOOLEAN                 TdEnabled;
+  CPUID_VERSION_INFO_ECX  CpuIdVersionInfoEcx;
+
+  TdEnabled = FALSE;
+
+  do {
+    AsmCpuid (CPUID_SIGNATURE, &LargestEax, &Ebx, &Ecx, &Edx);
+
+    if (  (Ebx != CPUID_SIGNATURE_GENUINE_INTEL_EBX)
+       || (Edx != CPUID_SIGNATURE_GENUINE_INTEL_EDX)
+       || (Ecx != CPUID_SIGNATURE_GENUINE_INTEL_ECX))
+    {
+      break;
+    }
+
+    AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, &CpuIdVersionInfoEcx.Uint32, NULL);
+    if (CpuIdVersionInfoEcx.Bits.ParaVirtualized == 0) {
+      break;
+    }
+
+    if (LargestEax < CPUID_GUESTTD_RUNTIME_ENVIRONMENT) {
+      break;
+    }
+
+    AsmCpuidEx (CPUID_GUESTTD_RUNTIME_ENVIRONMENT, 0, &Eax, &Ebx, &Ecx, &Edx);
+    if (  (Ebx != CPUID_GUESTTD_SIGNATURE_GENUINE_INTEL_EBX)
+       || (Edx != CPUID_GUESTTD_SIGNATURE_GENUINE_INTEL_EDX)
+       || (Ecx != CPUID_GUESTTD_SIGNATURE_GENUINE_INTEL_ECX))
+    {
+      break;
+    }
+
+    TdEnabled = TRUE;
+  } while (FALSE);
+
+  return TdEnabled;
+}
diff --git a/MdePkg/Library/BaseLib/X64/TdVmcall.nasm b/MdePkg/Library/BaseLib/X64/TdVmcall.nasm
new file mode 100644
index 000000000000..5ecc10b17193
--- /dev/null
+++ b/MdePkg/Library/BaseLib/X64/TdVmcall.nasm
@@ -0,0 +1,145 @@
+;------------------------------------------------------------------------------
+;*
+;* Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
+;* SPDX-License-Identifier: BSD-2-Clause-Patent
+;*
+;*
+;------------------------------------------------------------------------------
+
+DEFAULT REL
+SECTION .text
+
+%define TDVMCALL_EXPOSE_REGS_MASK       0xffec
+%define TDVMCALL                        0x0
+
+%macro tdcall 0
+    db 0x66,0x0f,0x01,0xcc
+%endmacro
+
+%macro tdcall_push_regs 0
+    push rbp
+    mov  rbp, rsp
+    push r15
+    push r14
+    push r13
+    push r12
+    push rbx
+    push rsi
+    push rdi
+%endmacro
+
+%macro tdcall_pop_regs 0
+    pop rdi
+    pop rsi
+    pop rbx
+    pop r12
+    pop r13
+    pop r14
+    pop r15
+    pop rbp
+%endmacro
+
+%define number_of_regs_pushed 8
+%define number_of_parameters  4
+
+;
+; Keep these in sync for push_regs/pop_regs, code below
+; uses them to find 5th or greater parameters
+;
+%define first_variable_on_stack_offset \
+  ((number_of_regs_pushed * 8) + (number_of_parameters * 8) + 8)
+%define second_variable_on_stack_offset \
+  ((first_variable_on_stack_offset) + 8)
+
+%macro tdcall_regs_preamble 2
+    mov rax, %1
+
+    xor rcx, rcx
+    mov ecx, %2
+
+    ; R10 = 0 (standard TDVMCALL)
+
+    xor r10d, r10d
+
+    ; Zero out unused (for standard TDVMCALL) registers to avoid leaking
+    ; secrets to the VMM.
+
+    xor ebx, ebx
+    xor esi, esi
+    xor edi, edi
+
+    xor edx, edx
+    xor ebp, ebp
+    xor r8d, r8d
+    xor r9d, r9d
+%endmacro
+
+%macro tdcall_regs_postamble 0
+    xor ebx, ebx
+    xor esi, esi
+    xor edi, edi
+
+    xor ecx, ecx
+    xor edx, edx
+    xor r8d,  r8d
+    xor r9d,  r9d
+    xor r10d, r10d
+    xor r11d, r11d
+%endmacro
+
+;------------------------------------------------------------------------------
+; 0   => RAX = TDCALL leaf
+; M   => RCX = TDVMCALL register behavior
+; 1   => R10 = standard vs. vendor
+; RDI => R11 = TDVMCALL function / nr
+; RSI =  R12 = p1
+; RDX => R13 = p2
+; RCX => R14 = p3
+; R8  => R15 = p4
+
+;  UINT64
+;  EFIAPI
+;  TdVmCall (
+;    UINT64  Leaf,  // Rcx
+;    UINT64  P1,  // Rdx
+;    UINT64  P2,  // R8
+;    UINT64  P3,  // R9
+;    UINT64  P4,  // rsp + 0x28
+;    UINT64  *Val // rsp + 0x30
+;    )
+global ASM_PFX(TdVmCall)
+ASM_PFX(TdVmCall):
+       tdcall_push_regs
+
+       mov r11, rcx
+       mov r12, rdx
+       mov r13, r8
+       mov r14, r9
+       mov r15, [rsp + first_variable_on_stack_offset ]
+
+       tdcall_regs_preamble TDVMCALL, TDVMCALL_EXPOSE_REGS_MASK
+
+       tdcall
+
+       ; ignore return dataif TDCALL reports failure.
+       test rax, rax
+       jnz .no_return_data
+
+       ; Propagate TDVMCALL success/failure to return value.
+       mov rax, r10
+
+       ; Retrieve the Val pointer.
+       mov r9, [rsp + second_variable_on_stack_offset ]
+       test r9, r9
+       jz .no_return_data
+
+       ; On success, propagate TDVMCALL output value to output param
+       test rax, rax
+       jnz .no_return_data
+       mov [r9], r11
+.no_return_data:
+       tdcall_regs_postamble
+
+       tdcall_pop_regs
+
+       ret
-- 
2.29.2.windows.2


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH V12 04/47] MdePkg: Add TdxLib to wrap Tdx operations
  2022-03-29 23:45 [PATCH V12 00/47] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (2 preceding siblings ...)
  2022-03-29 23:45 ` [PATCH V12 03/47] MdePkg: Introduce basic Tdx functions in BaseLib Min Xu
@ 2022-03-29 23:45 ` Min Xu
  2022-03-29 23:45 ` [PATCH V12 05/47] UefiCpuPkg: Extend VmgExitLibNull to handle #VE exception Min Xu
                   ` (36 subsequent siblings)
  40 siblings, 0 replies; 53+ messages in thread
From: Min Xu @ 2022-03-29 23:45 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Michael D Kinney, Liming Gao, Zhiguang Liu, Brijesh Singh,
	Erdem Aktas, James Bottomley, Jiewen Yao, Tom Lendacky,
	Gerd Hoffmann

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

TdxLib is created with functions to perform the related Tdx operation.
This includes functions for:
 - TdAcceptPages   : Accept pending private pages and initialize the pages
                     to all-0 using the TD ephemeral private key.
 - TdExtendRtmr    : Extend measurement to one of the RTMR registers.
 - TdSharedPageMask: Get the Td guest shared page mask which indicates it
                     is a Shared or Private page.
 - TdMaxVCpuNum    : Get the maximum number of virtual CPUs.
 - TdVCpuNum       : Get the number of virtual CPUs.

Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Zhiguang Liu <zhiguang.liu@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Liming Gao <gaoliming@byosoft.com.cn>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 MdePkg/Include/Library/TdxLib.h     |  92 ++++++++++++++
 MdePkg/Library/TdxLib/AcceptPages.c | 181 ++++++++++++++++++++++++++++
 MdePkg/Library/TdxLib/Rtmr.c        |  84 +++++++++++++
 MdePkg/Library/TdxLib/TdInfo.c      | 115 ++++++++++++++++++
 MdePkg/Library/TdxLib/TdxLib.inf    |  37 ++++++
 MdePkg/Library/TdxLib/TdxLibNull.c  | 106 ++++++++++++++++
 MdePkg/MdePkg.dec                   |   3 +
 MdePkg/MdePkg.dsc                   |   1 +
 8 files changed, 619 insertions(+)
 create mode 100644 MdePkg/Include/Library/TdxLib.h
 create mode 100644 MdePkg/Library/TdxLib/AcceptPages.c
 create mode 100644 MdePkg/Library/TdxLib/Rtmr.c
 create mode 100644 MdePkg/Library/TdxLib/TdInfo.c
 create mode 100644 MdePkg/Library/TdxLib/TdxLib.inf
 create mode 100644 MdePkg/Library/TdxLib/TdxLibNull.c

diff --git a/MdePkg/Include/Library/TdxLib.h b/MdePkg/Include/Library/TdxLib.h
new file mode 100644
index 000000000000..55f0436cca1f
--- /dev/null
+++ b/MdePkg/Include/Library/TdxLib.h
@@ -0,0 +1,92 @@
+/** @file
+  TdxLib definitions
+
+  Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef TDX_LIB_H_
+#define TDX_LIB_H_
+
+/**
+  This function accepts a pending private page, and initialize the page to
+  all-0 using the TD ephemeral private key.
+
+  @param[in]  StartAddress     Guest physical address of the private page
+                               to accept. [63:52] and [11:0] must be 0.
+  @param[in]  NumberOfPages    Number of the pages to be accepted.
+  @param[in]  PageSize         GPA page size. Accept 2M/4K page size.
+
+  @return EFI_SUCCESS
+**/
+EFI_STATUS
+EFIAPI
+TdAcceptPages (
+  IN UINT64  StartAddress,
+  IN UINT64  NumberOfPages,
+  IN UINT32  PageSize
+  );
+
+/**
+  This function extends one of the RTMR measurement register
+  in TDCS with the provided extension data in memory.
+  RTMR extending supports SHA384 which length is 48 bytes.
+
+  @param[in]  Data      Point to the data to be extended
+  @param[in]  DataLen   Length of the data. Must be 48
+  @param[in]  Index     RTMR index
+
+  @return EFI_SUCCESS
+  @return EFI_INVALID_PARAMETER
+  @return EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+EFIAPI
+TdExtendRtmr (
+  IN  UINT32  *Data,
+  IN  UINT32  DataLen,
+  IN  UINT8   Index
+  );
+
+/**
+  This function gets the Td guest shared page mask.
+
+  The guest indicates if a page is shared using the Guest Physical Address
+  (GPA) Shared (S) bit. If the GPA Width(GPAW) is 48, the S-bit is bit-47.
+  If the GPAW is 52, the S-bit is bit-51.
+
+  @return Shared page bit mask
+**/
+UINT64
+EFIAPI
+TdSharedPageMask (
+  VOID
+  );
+
+/**
+  This function gets the maximum number of Virtual CPUs that are usable for
+  Td Guest.
+
+  @return maximum Virtual CPUs number
+**/
+UINT32
+EFIAPI
+TdMaxVCpuNum (
+  VOID
+  );
+
+/**
+  This function gets the number of Virtual CPUs that are usable for Td
+  Guest.
+
+  @return Virtual CPUs number
+**/
+UINT32
+EFIAPI
+TdVCpuNum (
+  VOID
+  );
+
+#endif
diff --git a/MdePkg/Library/TdxLib/AcceptPages.c b/MdePkg/Library/TdxLib/AcceptPages.c
new file mode 100644
index 000000000000..3a2182e95f47
--- /dev/null
+++ b/MdePkg/Library/TdxLib/AcceptPages.c
@@ -0,0 +1,181 @@
+/** @file
+
+  Unaccepted memory is a special type of private memory. In Td guest
+  TDCALL [TDG.MEM.PAGE.ACCEPT] is invoked to accept the unaccepted
+  memory before use it.
+
+  Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <IndustryStandard/Tdx.h>
+#include <Uefi/UefiBaseType.h>
+#include <Library/TdxLib.h>
+#include <Library/BaseMemoryLib.h>
+
+UINT64  mNumberOfDuplicatedAcceptedPages;
+
+#define TDX_ACCEPTPAGE_MAX_RETRIED  3
+
+// PageSize is mapped to PageLevel like below:
+// 4KB - 0, 2MB - 1
+UINT32  mTdxAcceptPageLevelMap[2] = {
+  SIZE_4KB,
+  SIZE_2MB
+};
+
+#define INVALID_ACCEPT_PAGELEVEL  ARRAY_SIZE(mTdxAcceptPageLevelMap)
+
+/**
+  This function gets the PageLevel according to the input page size.
+
+  @param[in]  PageSize    Page size
+
+  @return UINT32          The mapped page level
+**/
+UINT32
+GetGpaPageLevel (
+  UINT32  PageSize
+  )
+{
+  UINT32  Index;
+
+  for (Index = 0; Index < ARRAY_SIZE (mTdxAcceptPageLevelMap); Index++) {
+    if (mTdxAcceptPageLevelMap[Index] == PageSize) {
+      break;
+    }
+  }
+
+  return Index;
+}
+
+/**
+  This function accept a pending private page, and initialize the page to
+  all-0 using the TD ephemeral private key.
+
+  Sometimes TDCALL [TDG.MEM.PAGE.ACCEPT] may return
+  TDX_EXIT_REASON_PAGE_SIZE_MISMATCH. It indicates the input PageLevel is
+  not workable. In this case we need to try to fallback to a smaller
+  PageLevel if possible.
+
+  @param[in]  StartAddress      Guest physical address of the private
+                                page to accept. [63:52] and [11:0] must be 0.
+  @param[in]  NumberOfPages     Number of the pages to be accepted.
+  @param[in]  PageSize          GPA page size. Only accept 2M/4K size.
+
+  @return EFI_SUCCESS           Accept successfully
+  @return others                Indicate other errors
+**/
+EFI_STATUS
+EFIAPI
+TdAcceptPages (
+  IN UINT64  StartAddress,
+  IN UINT64  NumberOfPages,
+  IN UINT32  PageSize
+  )
+{
+  EFI_STATUS  Status;
+  UINT64      Address;
+  UINT64      TdxStatus;
+  UINT64      Index;
+  UINT32      GpaPageLevel;
+  UINT32      PageSize2;
+  UINTN       Retried;
+
+  Retried = 0;
+
+  if ((StartAddress & ~0xFFFFFFFFFF000ULL) != 0) {
+    ASSERT (FALSE);
+    DEBUG ((DEBUG_ERROR, "Accept page address(0x%llx) is not valid. [63:52] and [11:0] must be 0\n", StartAddress));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Address = StartAddress;
+
+  GpaPageLevel = GetGpaPageLevel (PageSize);
+  if (GpaPageLevel == INVALID_ACCEPT_PAGELEVEL) {
+    ASSERT (FALSE);
+    DEBUG ((DEBUG_ERROR, "Accept page size must be 4K/2M. Invalid page size - 0x%llx\n", PageSize));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Status = EFI_SUCCESS;
+  for (Index = 0; Index < NumberOfPages; Index++) {
+    Retried = 0;
+
+DoAcceptPage:
+    TdxStatus = TdCall (TDCALL_TDACCEPTPAGE, Address | GpaPageLevel, 0, 0, 0);
+    if (TdxStatus != TDX_EXIT_REASON_SUCCESS) {
+      if ((TdxStatus & ~0xFFFFULL) == TDX_EXIT_REASON_PAGE_ALREADY_ACCEPTED) {
+        //
+        // Already accepted
+        //
+        mNumberOfDuplicatedAcceptedPages++;
+        DEBUG ((DEBUG_WARN, "Page at Address (0x%llx) has already been accepted. - %d\n", Address, mNumberOfDuplicatedAcceptedPages));
+      } else if ((TdxStatus & ~0xFFFFULL) == TDX_EXIT_REASON_PAGE_SIZE_MISMATCH) {
+        //
+        // GpaPageLevel is mismatch, fall back to a smaller GpaPageLevel if possible
+        //
+        DEBUG ((DEBUG_VERBOSE, "Address %llx cannot be accepted in PageLevel of %d\n", Address, GpaPageLevel));
+
+        if (GpaPageLevel == 0) {
+          //
+          // Cannot fall back to smaller page level
+          //
+          DEBUG ((DEBUG_ERROR, "AcceptPage cannot fallback from PageLevel %d\n", GpaPageLevel));
+          Status = EFI_INVALID_PARAMETER;
+          break;
+        } else {
+          //
+          // Fall back to a smaller page size
+          //
+          PageSize2 = mTdxAcceptPageLevelMap[GpaPageLevel - 1];
+          Status    = TdAcceptPages (Address, 512, PageSize2);
+          if (EFI_ERROR (Status)) {
+            break;
+          }
+        }
+      } else if ((TdxStatus & ~0xFFFFULL) == TDX_EXIT_REASON_OPERAND_BUSY) {
+        //
+        // Concurrent TDG.MEM.PAGE.ACCEPT is using the same Secure EPT entry
+        // So try it again. There is a max retried count. If Retried exceeds the max count,
+        // report the error and quit.
+        //
+        Retried += 1;
+        if (Retried > TDX_ACCEPTPAGE_MAX_RETRIED) {
+          DEBUG ((
+            DEBUG_ERROR,
+            "Address %llx (%d) failed to be accepted because of OPERAND_BUSY. Retried %d time.\n",
+            Address,
+            Index,
+            Retried
+            ));
+          Status = EFI_INVALID_PARAMETER;
+          break;
+        } else {
+          goto DoAcceptPage;
+        }
+      } else {
+        //
+        // Other errors
+        //
+        DEBUG ((
+          DEBUG_ERROR,
+          "Address %llx (%d) failed to be accepted. Error = 0x%llx\n",
+          Address,
+          Index,
+          TdxStatus
+          ));
+        Status = EFI_INVALID_PARAMETER;
+        break;
+      }
+    }
+
+    Address += PageSize;
+  }
+
+  return Status;
+}
diff --git a/MdePkg/Library/TdxLib/Rtmr.c b/MdePkg/Library/TdxLib/Rtmr.c
new file mode 100644
index 000000000000..a0283966b353
--- /dev/null
+++ b/MdePkg/Library/TdxLib/Rtmr.c
@@ -0,0 +1,84 @@
+/** @file
+
+  Extends one of the RTMR measurement registers in TDCS with the provided
+  extension data in memory.
+
+  Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Uefi/UefiBaseType.h>
+#include <Library/TdxLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <IndustryStandard/Tpm20.h>
+#include <IndustryStandard/Tdx.h>
+
+#define RTMR_COUNT            4
+#define TD_EXTEND_BUFFER_LEN  (64 + 48)
+
+UINT8  mExtendBuffer[TD_EXTEND_BUFFER_LEN];
+
+/**
+  This function extends one of the RTMR measurement register
+  in TDCS with the provided extension data in memory.
+  RTMR extending supports SHA384 which length is 48 bytes.
+
+  @param[in]  Data      Point to the data to be extended
+  @param[in]  DataLen   Length of the data. Must be 48
+  @param[in]  Index     RTMR index
+
+  @return EFI_SUCCESS
+  @return EFI_INVALID_PARAMETER
+  @return EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+EFIAPI
+TdExtendRtmr (
+  IN  UINT32  *Data,
+  IN  UINT32  DataLen,
+  IN  UINT8   Index
+  )
+{
+  EFI_STATUS  Status;
+  UINT64      TdCallStatus;
+  UINT8       *ExtendBuffer;
+
+  Status = EFI_SUCCESS;
+
+  ASSERT (Data != NULL);
+  ASSERT (DataLen == SHA384_DIGEST_SIZE);
+  ASSERT (Index >= 0 && Index < RTMR_COUNT);
+
+  if ((Data == NULL) || (DataLen != SHA384_DIGEST_SIZE) || (Index >= RTMR_COUNT)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // TD.RTMR.EXTEND requires 64B-aligned guest physical address of
+  // 48B-extension data. We use ALIGN_POINTER(Pointer, 64) to get
+  // the 64B-aligned guest physical address.
+  ExtendBuffer = ALIGN_POINTER (mExtendBuffer, 64);
+  ASSERT (((UINTN)ExtendBuffer & 0x3f) == 0);
+
+  ZeroMem (ExtendBuffer, SHA384_DIGEST_SIZE);
+  CopyMem (ExtendBuffer, Data, SHA384_DIGEST_SIZE);
+
+  TdCallStatus = TdCall (TDCALL_TDEXTENDRTMR, (UINT64)(UINTN)ExtendBuffer, Index, 0, 0);
+
+  if (TdCallStatus == TDX_EXIT_REASON_SUCCESS) {
+    Status = EFI_SUCCESS;
+  } else if (TdCallStatus == TDX_EXIT_REASON_OPERAND_INVALID) {
+    Status = EFI_INVALID_PARAMETER;
+  } else {
+    Status = EFI_DEVICE_ERROR;
+  }
+
+  if (Status != EFI_SUCCESS) {
+    DEBUG ((DEBUG_ERROR, "Error returned from TdExtendRtmr call - 0x%lx\n", TdCallStatus));
+  }
+
+  return Status;
+}
diff --git a/MdePkg/Library/TdxLib/TdInfo.c b/MdePkg/Library/TdxLib/TdInfo.c
new file mode 100644
index 000000000000..3c5689f1d8c6
--- /dev/null
+++ b/MdePkg/Library/TdxLib/TdInfo.c
@@ -0,0 +1,115 @@
+/** @file
+
+  Fetch the Tdx info.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <IndustryStandard/Tdx.h>
+#include <Uefi/UefiBaseType.h>
+#include <Library/TdxLib.h>
+#include <Library/BaseMemoryLib.h>
+
+UINT64   mTdSharedPageMask = 0;
+UINT32   mTdMaxVCpuNum     = 0;
+UINT32   mTdVCpuNum        = 0;
+BOOLEAN  mTdDataReturned   = FALSE;
+
+/**
+  This function call TDCALL_TDINFO to get the TD_RETURN_DATA.
+  If the TDCALL is successful, populate below variables:
+   - mTdSharedPageMask
+   - mTdMaxVCpunum
+   - mTdVCpuNum
+   - mTdDataReturned
+
+  @return TRUE  The TDCALL is successful and above variables are populated.
+  @return FALSE The TDCALL is failed. Above variables are not set.
+**/
+BOOLEAN
+GetTdInfo (
+  VOID
+  )
+{
+  UINT64          Status;
+  TD_RETURN_DATA  TdReturnData;
+  UINT8           Gpaw;
+
+  Status = TdCall (TDCALL_TDINFO, 0, 0, 0, &TdReturnData);
+  if (Status == TDX_EXIT_REASON_SUCCESS) {
+    Gpaw              = (UINT8)(TdReturnData.TdInfo.Gpaw & 0x3f);
+    mTdSharedPageMask = 1ULL << (Gpaw - 1);
+    mTdMaxVCpuNum     = TdReturnData.TdInfo.MaxVcpus;
+    mTdVCpuNum        = TdReturnData.TdInfo.NumVcpus;
+    mTdDataReturned   = TRUE;
+  } else {
+    DEBUG ((DEBUG_ERROR, "Failed call TDCALL_TDINFO. %llx\n", Status));
+    mTdDataReturned = FALSE;
+  }
+
+  return mTdDataReturned;
+}
+
+/**
+  This function gets the Td guest shared page mask.
+
+  The guest indicates if a page is shared using the Guest Physical Address
+  (GPA) Shared (S) bit. If the GPA Width(GPAW) is 48, the S-bit is bit-47.
+  If the GPAW is 52, the S-bit is bit-51.
+
+  @return Shared page bit mask
+**/
+UINT64
+EFIAPI
+TdSharedPageMask (
+  VOID
+  )
+{
+  if (mTdDataReturned) {
+    return mTdSharedPageMask;
+  }
+
+  return GetTdInfo () ? mTdSharedPageMask : 0;
+}
+
+/**
+  This function gets the maximum number of Virtual CPUs that are usable for
+  Td Guest.
+
+  @return maximum Virtual CPUs number
+**/
+UINT32
+EFIAPI
+TdMaxVCpuNum (
+  VOID
+  )
+{
+  if (mTdDataReturned) {
+    return mTdMaxVCpuNum;
+  }
+
+  return GetTdInfo () ? mTdMaxVCpuNum : 0;
+}
+
+/**
+  This function gets the number of Virtual CPUs that are usable for Td
+  Guest.
+
+  @return Virtual CPUs number
+**/
+UINT32
+EFIAPI
+TdVCpuNum (
+  VOID
+  )
+{
+  if (mTdDataReturned) {
+    return mTdVCpuNum;
+  }
+
+  return GetTdInfo () ? mTdVCpuNum : 0;
+}
diff --git a/MdePkg/Library/TdxLib/TdxLib.inf b/MdePkg/Library/TdxLib/TdxLib.inf
new file mode 100644
index 000000000000..442e63d079da
--- /dev/null
+++ b/MdePkg/Library/TdxLib/TdxLib.inf
@@ -0,0 +1,37 @@
+## @file
+# Tdx library
+#
+#  Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = TdxLib
+  FILE_GUID                      = 032A8E0D-0C27-40C0-9CAA-23B731C1B223
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = TdxLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64
+#
+
+[Sources.IA32]
+  TdxLibNull.c
+
+[Sources.X64]
+  AcceptPages.c
+  Rtmr.c
+  TdInfo.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  DebugLib
diff --git a/MdePkg/Library/TdxLib/TdxLibNull.c b/MdePkg/Library/TdxLib/TdxLibNull.c
new file mode 100644
index 000000000000..29b2fe7ae775
--- /dev/null
+++ b/MdePkg/Library/TdxLib/TdxLibNull.c
@@ -0,0 +1,106 @@
+/** @file
+
+  Null stub of TdxLib
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi/UefiBaseType.h>
+#include <Library/TdxLib.h>
+
+/**
+  This function accepts a pending private page, and initialize the page to
+  all-0 using the TD ephemeral private key.
+
+  @param[in]  StartAddress     Guest physical address of the private page
+                               to accept.
+  @param[in]  NumberOfPages    Number of the pages to be accepted.
+  @param[in]  PageSize         GPA page size. Accept 1G/2M/4K page size.
+
+  @return EFI_SUCCESS
+**/
+EFI_STATUS
+EFIAPI
+TdAcceptPages (
+  IN UINT64  StartAddress,
+  IN UINT64  NumberOfPages,
+  IN UINT32  PageSize
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  This function extends one of the RTMR measurement register
+  in TDCS with the provided extension data in memory.
+  RTMR extending supports SHA384 which length is 48 bytes.
+
+  @param[in]  Data      Point to the data to be extended
+  @param[in]  DataLen   Length of the data. Must be 48
+  @param[in]  Index     RTMR index
+
+  @return EFI_SUCCESS
+  @return EFI_INVALID_PARAMETER
+  @return EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+EFIAPI
+TdExtendRtmr (
+  IN  UINT32  *Data,
+  IN  UINT32  DataLen,
+  IN  UINT8   Index
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  This function gets the Td guest shared page mask.
+
+  The guest indicates if a page is shared using the Guest Physical Address
+  (GPA) Shared (S) bit. If the GPA Width(GPAW) is 48, the S-bit is bit-47.
+  If the GPAW is 52, the S-bit is bit-51.
+
+  @return Shared page bit mask
+**/
+UINT64
+EFIAPI
+TdSharedPageMask (
+  VOID
+  )
+{
+  return 0;
+}
+
+/**
+  This function gets the maximum number of Virtual CPUs that are usable for
+  Td Guest.
+
+  @return maximum Virtual CPUs number
+**/
+UINT32
+EFIAPI
+TdMaxVCpuNum (
+  VOID
+  )
+{
+  return 0;
+}
+
+/**
+  This function gets the number of Virtual CPUs that are usable for Td
+  Guest.
+
+  @return Virtual CPUs number
+**/
+UINT32
+EFIAPI
+TdVCpuNum (
+  VOID
+  )
+{
+  return 0;
+}
diff --git a/MdePkg/MdePkg.dec b/MdePkg/MdePkg.dec
index 59b405928bf8..1934c9840423 100644
--- a/MdePkg/MdePkg.dec
+++ b/MdePkg/MdePkg.dec
@@ -296,6 +296,9 @@
   ##  @libraryclass  Provides services to log the SMI handler registration.
   SmiHandlerProfileLib|Include/Library/SmiHandlerProfileLib.h
 
+  ##  @libraryclass  Provides function to support TDX processing.
+  TdxLib|Include/Library/TdxLib.h
+
 [Guids]
   #
   # GUID defined in UEFI2.1/UEFI2.0/EFI1.1
diff --git a/MdePkg/MdePkg.dsc b/MdePkg/MdePkg.dsc
index a94959169b2f..d6a7af412be7 100644
--- a/MdePkg/MdePkg.dsc
+++ b/MdePkg/MdePkg.dsc
@@ -175,6 +175,7 @@
   MdePkg/Library/SmiHandlerProfileLibNull/SmiHandlerProfileLibNull.inf
   MdePkg/Library/MmServicesTableLib/MmServicesTableLib.inf
   MdePkg/Library/MmUnblockMemoryLib/MmUnblockMemoryLibNull.inf
+  MdePkg/Library/TdxLib/TdxLib.inf
 
 [Components.EBC]
   MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf
-- 
2.29.2.windows.2


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH V12 05/47] UefiCpuPkg: Extend VmgExitLibNull to handle #VE exception
  2022-03-29 23:45 [PATCH V12 00/47] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (3 preceding siblings ...)
  2022-03-29 23:45 ` [PATCH V12 04/47] MdePkg: Add TdxLib to wrap Tdx operations Min Xu
@ 2022-03-29 23:45 ` Min Xu
  2022-03-29 23:45 ` [PATCH V12 06/47] OvmfPkg: Extend VmgExitLib " Min Xu
                   ` (35 subsequent siblings)
  40 siblings, 0 replies; 53+ messages in thread
From: Min Xu @ 2022-03-29 23:45 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Brijesh Singh, Erdem Aktas, James Bottomley, Jiewen Yao,
	Tom Lendacky, Eric Dong, Ray Ni, Rahul Kumar, Gerd Hoffmann

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

VmgExitLib performs the necessary processing to handle a #VC exception.
VmgExitLibNull is a NULL instance of VmgExitLib which provides a
default limited interface. In this commit VmgExitLibNull is extended to
handle a #VE exception with a default limited interface. A full feature
version of #VE handler will be created later.

Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Ray Ni <ray.ni@intel.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 UefiCpuPkg/Include/Library/VmgExitLib.h       | 28 ++++++++++++++
 .../Library/VmgExitLibNull/VmTdExitNull.c     | 38 +++++++++++++++++++
 .../Library/VmgExitLibNull/VmgExitLibNull.inf |  1 +
 3 files changed, 67 insertions(+)
 create mode 100644 UefiCpuPkg/Library/VmgExitLibNull/VmTdExitNull.c

diff --git a/UefiCpuPkg/Include/Library/VmgExitLib.h b/UefiCpuPkg/Include/Library/VmgExitLib.h
index ebda1c3d907c..f9f911099a7b 100644
--- a/UefiCpuPkg/Include/Library/VmgExitLib.h
+++ b/UefiCpuPkg/Include/Library/VmgExitLib.h
@@ -15,6 +15,8 @@
 #include <Protocol/DebugSupport.h>
 #include <Register/Amd/Ghcb.h>
 
+#define VE_EXCEPTION  20
+
 /**
   Perform VMGEXIT.
 
@@ -142,4 +144,30 @@ VmgExitHandleVc (
   IN OUT EFI_SYSTEM_CONTEXT  SystemContext
   );
 
+/**
+  Handle a #VE exception.
+
+  Performs the necessary processing to handle a #VE exception.
+
+  The base library function returns an error equal to VE_EXCEPTION,
+  to be propagated to the standard exception handling stack.
+
+  @param[in, out]  ExceptionType  Pointer to an EFI_EXCEPTION_TYPE to be set
+                                  as value to use on error.
+  @param[in, out]  SystemContext  Pointer to EFI_SYSTEM_CONTEXT
+
+  @retval  EFI_SUCCESS            Exception handled
+  @retval  EFI_UNSUPPORTED        #VE not supported, (new) exception value to
+                                  propagate provided
+  @retval  EFI_PROTOCOL_ERROR     #VE handling failed, (new) exception value to
+                                  propagate provided
+
+**/
+EFI_STATUS
+EFIAPI
+VmTdExitHandleVe (
+  IN OUT EFI_EXCEPTION_TYPE  *ExceptionType,
+  IN OUT EFI_SYSTEM_CONTEXT  SystemContext
+  );
+
 #endif
diff --git a/UefiCpuPkg/Library/VmgExitLibNull/VmTdExitNull.c b/UefiCpuPkg/Library/VmgExitLibNull/VmTdExitNull.c
new file mode 100644
index 000000000000..6a4e8087cb89
--- /dev/null
+++ b/UefiCpuPkg/Library/VmgExitLibNull/VmTdExitNull.c
@@ -0,0 +1,38 @@
+/** @file
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include <Base.h>
+#include <Uefi.h>
+#include <Library/VmgExitLib.h>
+
+/**
+  Handle a #VE exception.
+
+  Performs the necessary processing to handle a #VE exception.
+
+  @param[in, out]  ExceptionType  Pointer to an EFI_EXCEPTION_TYPE to be set
+                                  as value to use on error.
+  @param[in, out]  SystemContext  Pointer to EFI_SYSTEM_CONTEXT
+
+  @retval  EFI_SUCCESS            Exception handled
+  @retval  EFI_UNSUPPORTED        #VE not supported, (new) exception value to
+                                  propagate provided
+  @retval  EFI_PROTOCOL_ERROR     #VE handling failed, (new) exception value to
+                                  propagate provided
+
+**/
+EFI_STATUS
+EFIAPI
+VmTdExitHandleVe (
+  IN OUT EFI_EXCEPTION_TYPE  *ExceptionType,
+  IN OUT EFI_SYSTEM_CONTEXT  SystemContext
+  )
+{
+  *ExceptionType = VE_EXCEPTION;
+
+  return EFI_UNSUPPORTED;
+}
diff --git a/UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf b/UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf
index d8770a21c355..4aab601939ff 100644
--- a/UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf
+++ b/UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf
@@ -17,6 +17,7 @@
 
 [Sources.common]
   VmgExitLibNull.c
+  VmTdExitNull.c
 
 [Packages]
   MdePkg/MdePkg.dec
-- 
2.29.2.windows.2


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH V12 06/47] OvmfPkg: Extend VmgExitLib to handle #VE exception
  2022-03-29 23:45 [PATCH V12 00/47] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (4 preceding siblings ...)
  2022-03-29 23:45 ` [PATCH V12 05/47] UefiCpuPkg: Extend VmgExitLibNull to handle #VE exception Min Xu
@ 2022-03-29 23:45 ` Min Xu
  2022-03-29 23:46 ` [PATCH V12 07/47] UefiCpuPkg/CpuExceptionHandler: Add base support for the " Min Xu
                   ` (34 subsequent siblings)
  40 siblings, 0 replies; 53+ messages in thread
From: Min Xu @ 2022-03-29 23:45 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ard Biesheuvel, Jiewen Yao, Jordan Justen, Brijesh Singh,
	Erdem Aktas, James Bottomley, Tom Lendacky, Gerd Hoffmann

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

The base VmgExitLib library provides a default limited interface to
handle #VE exception. To provide full support, the OVMF version of
VmgExitLib is extended to provide full support of #VE handler.

Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf  |   3 +-
 OvmfPkg/Library/VmgExitLib/VmTdExitHandler.h  |  32 +
 .../Library/VmgExitLib/VmTdExitVeHandler.c    | 559 ++++++++++++++++++
 OvmfPkg/Library/VmgExitLib/VmgExitLib.inf     |   2 +
 .../Library/VmgExitLib/X64/TdVmcallCpuid.nasm | 146 +++++
 5 files changed, 741 insertions(+), 1 deletion(-)
 create mode 100644 OvmfPkg/Library/VmgExitLib/VmTdExitHandler.h
 create mode 100644 OvmfPkg/Library/VmgExitLib/VmTdExitVeHandler.c
 create mode 100644 OvmfPkg/Library/VmgExitLib/X64/TdVmcallCpuid.nasm

diff --git a/OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf b/OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf
index 78207fa0f9c9..f9bd4974f6dc 100644
--- a/OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf
+++ b/OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf
@@ -25,6 +25,8 @@
   VmgExitVcHandler.c
   VmgExitVcHandler.h
   SecVmgExitVcHandler.c
+  VmTdExitVeHandler.c
+  X64/TdVmcallCpuid.nasm
 
 [Packages]
   MdePkg/MdePkg.dec
@@ -44,4 +46,3 @@
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupSize
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidBase
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidSize
-
diff --git a/OvmfPkg/Library/VmgExitLib/VmTdExitHandler.h b/OvmfPkg/Library/VmgExitLib/VmTdExitHandler.h
new file mode 100644
index 000000000000..7eacd0872f46
--- /dev/null
+++ b/OvmfPkg/Library/VmgExitLib/VmTdExitHandler.h
@@ -0,0 +1,32 @@
+/** @file
+
+  Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef VMTD_EXIT_HANDLER_H_
+#define VMTD_EXIT_HANDLER_H_
+
+#include <Base.h>
+#include <Uefi.h>
+
+/**
+  This function enable the TD guest to request the VMM to emulate CPUID
+  operation, especially for non-architectural, CPUID leaves.
+
+  @param[in]  Eax        Main leaf of the CPUID
+  @param[in]  Ecx        Sub-leaf of the CPUID
+  @param[out] Results    Returned result of CPUID operation
+
+  @return EFI_SUCCESS
+**/
+EFI_STATUS
+EFIAPI
+TdVmCallCpuid (
+  IN UINT64  Eax,
+  IN UINT64  Ecx,
+  OUT VOID   *Results
+  );
+
+#endif
diff --git a/OvmfPkg/Library/VmgExitLib/VmTdExitVeHandler.c b/OvmfPkg/Library/VmgExitLib/VmTdExitVeHandler.c
new file mode 100644
index 000000000000..b73e877c093b
--- /dev/null
+++ b/OvmfPkg/Library/VmgExitLib/VmTdExitVeHandler.c
@@ -0,0 +1,559 @@
+/** @file
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include "VmTdExitHandler.h"
+#include <Library/VmgExitLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <IndustryStandard/Tdx.h>
+#include <IndustryStandard/InstructionParsing.h>
+
+typedef union {
+  struct {
+    UINT32    Eax;
+    UINT32    Edx;
+  } Regs;
+  UINT64    Val;
+} MSR_DATA;
+
+typedef union {
+  UINT8    Val;
+  struct {
+    UINT8    B : 1;
+    UINT8    X : 1;
+    UINT8    R : 1;
+    UINT8    W : 1;
+  } Bits;
+} REX;
+
+typedef union {
+  UINT8    Val;
+  struct {
+    UINT8    Rm  : 3;
+    UINT8    Reg : 3;
+    UINT8    Mod : 2;
+  } Bits;
+} MODRM;
+
+typedef struct {
+  UINT64    Regs[4];
+} CPUID_DATA;
+
+/**
+  Handle an CPUID event.
+
+  Use the TDVMCALL instruction to handle cpuid #ve
+
+  @param[in, out] Regs             x64 processor context
+  @param[in]      Veinfo           VE Info
+
+  @retval 0                        Event handled successfully
+  @return                          New exception value to propagate
+**/
+STATIC
+UINT64
+EFIAPI
+CpuIdExit (
+  IN EFI_SYSTEM_CONTEXT_X64     *Regs,
+  IN TDCALL_VEINFO_RETURN_DATA  *Veinfo
+  )
+{
+  CPUID_DATA  CpuIdData;
+  UINT64      Status;
+
+  Status = TdVmCallCpuid (Regs->Rax, Regs->Rcx, &CpuIdData);
+
+  if (Status == 0) {
+    Regs->Rax = CpuIdData.Regs[0];
+    Regs->Rbx = CpuIdData.Regs[1];
+    Regs->Rcx = CpuIdData.Regs[2];
+    Regs->Rdx = CpuIdData.Regs[3];
+  }
+
+  return Status;
+}
+
+/**
+  Handle an IO event.
+
+  Use the TDVMCALL instruction to handle either an IO read or an IO write.
+
+  @param[in, out] Regs             x64 processor context
+  @param[in]      Veinfo           VE Info
+
+  @retval 0                        Event handled successfully
+  @return                          New exception value to propagate
+**/
+STATIC
+UINT64
+EFIAPI
+IoExit (
+  IN OUT EFI_SYSTEM_CONTEXT_X64  *Regs,
+  IN TDCALL_VEINFO_RETURN_DATA   *Veinfo
+  )
+{
+  BOOLEAN  Write;
+  UINTN    Size;
+  UINTN    Port;
+  UINT64   Val;
+  UINT64   RepCnt;
+  UINT64   Status;
+
+  Val   = 0;
+  Write = Veinfo->ExitQualification.Io.Direction ? FALSE : TRUE;
+  Size  = Veinfo->ExitQualification.Io.Size + 1;
+  Port  = Veinfo->ExitQualification.Io.Port;
+
+  if (Veinfo->ExitQualification.Io.String) {
+    //
+    // If REP is set, get rep-cnt from Rcx
+    //
+    RepCnt = Veinfo->ExitQualification.Io.Rep ? Regs->Rcx : 1;
+
+    while (RepCnt) {
+      Val = 0;
+      if (Write == TRUE) {
+        CopyMem (&Val, (VOID *)Regs->Rsi, Size);
+        Regs->Rsi += Size;
+      }
+
+      Status = TdVmCall (EXIT_REASON_IO_INSTRUCTION, Size, Write, Port, Val, (Write ? NULL : &Val));
+      if (Status != 0) {
+        break;
+      }
+
+      if (Write == FALSE) {
+        CopyMem ((VOID *)Regs->Rdi, &Val, Size);
+        Regs->Rdi += Size;
+      }
+
+      if (Veinfo->ExitQualification.Io.Rep) {
+        Regs->Rcx -= 1;
+      }
+
+      RepCnt -= 1;
+    }
+  } else {
+    if (Write == TRUE) {
+      CopyMem (&Val, (VOID *)&Regs->Rax, Size);
+    }
+
+    Status = TdVmCall (EXIT_REASON_IO_INSTRUCTION, Size, Write, Port, Val, (Write ? NULL : &Val));
+    if ((Status == 0) && (Write == FALSE)) {
+      CopyMem ((VOID *)&Regs->Rax, &Val, Size);
+    }
+  }
+
+  return Status;
+}
+
+/**
+  Handle an READ MSR event.
+
+  Use the TDVMCALL instruction to handle msr read
+
+  @param[in, out] Regs             x64 processor context
+  @param[in]      Veinfo           VE Info
+
+  @retval 0                        Event handled successfully
+  @return                          New exception value to propagate
+**/
+STATIC
+UINT64
+ReadMsrExit (
+  IN OUT EFI_SYSTEM_CONTEXT_X64  *Regs,
+  IN TDCALL_VEINFO_RETURN_DATA   *Veinfo
+  )
+{
+  MSR_DATA  Data;
+  UINT64    Status;
+
+  Status = TdVmCall (EXIT_REASON_MSR_READ, Regs->Rcx, 0, 0, 0, &Data);
+  if (Status == 0) {
+    Regs->Rax = Data.Regs.Eax;
+    Regs->Rdx = Data.Regs.Edx;
+  }
+
+  return Status;
+}
+
+/**
+  Handle an WRITE MSR event.
+
+  Use the TDVMCALL instruction to handle msr write
+
+  @param[in, out] Regs             x64 processor context
+  @param[in]      Veinfo           VE Info
+
+  @retval 0                        Event handled successfully
+  @return                          New exception value to propagate
+**/
+STATIC
+UINT64
+WriteMsrExit (
+  IN OUT EFI_SYSTEM_CONTEXT_X64  *Regs,
+  IN TDCALL_VEINFO_RETURN_DATA   *Veinfo
+  )
+{
+  UINT64    Status;
+  MSR_DATA  Data;
+
+  Data.Regs.Eax = (UINT32)Regs->Rax;
+  Data.Regs.Edx = (UINT32)Regs->Rdx;
+
+  Status =  TdVmCall (EXIT_REASON_MSR_WRITE, Regs->Rcx, Data.Val, 0, 0, NULL);
+
+  return Status;
+}
+
+STATIC
+VOID
+EFIAPI
+TdxDecodeInstruction (
+  IN UINT8  *Rip
+  )
+{
+  UINTN  i;
+
+  DEBUG ((DEBUG_INFO, "TDX: #TD[EPT] instruction (%p):", Rip));
+  for (i = 0; i < 15; i++) {
+    DEBUG ((DEBUG_INFO, "%02x:", Rip[i]));
+  }
+
+  DEBUG ((DEBUG_INFO, "\n"));
+}
+
+#define TDX_DECODER_BUG_ON(x)               \
+  if ((x)) {                                \
+    TdxDecodeInstruction(Rip);              \
+    TdVmCall(TDVMCALL_HALT, 0, 0, 0, 0, 0); \
+  }
+
+STATIC
+UINT64 *
+EFIAPI
+GetRegFromContext (
+  IN EFI_SYSTEM_CONTEXT_X64  *Regs,
+  IN UINTN                   RegIndex
+  )
+{
+  switch (RegIndex) {
+    case 0: return &Regs->Rax;
+      break;
+    case 1: return &Regs->Rcx;
+      break;
+    case 2: return &Regs->Rdx;
+      break;
+    case 3: return &Regs->Rbx;
+      break;
+    case 4: return &Regs->Rsp;
+      break;
+    case 5: return &Regs->Rbp;
+      break;
+    case 6: return &Regs->Rsi;
+      break;
+    case 7: return &Regs->Rdi;
+      break;
+    case 8: return &Regs->R8;
+      break;
+    case 9: return &Regs->R9;
+      break;
+    case 10: return &Regs->R10;
+      break;
+    case 11: return &Regs->R11;
+      break;
+    case 12: return &Regs->R12;
+      break;
+    case 13: return &Regs->R13;
+      break;
+    case 14: return &Regs->R14;
+      break;
+    case 15: return &Regs->R15;
+      break;
+  }
+
+  return NULL;
+}
+
+/**
+  Handle an MMIO event.
+
+  Use the TDVMCALL instruction to handle either an mmio read or an mmio write.
+
+  @param[in, out] Regs             x64 processor context
+  @param[in]      Veinfo           VE Info
+
+  @retval 0                        Event handled successfully
+  @return                          New exception value to propagate
+**/
+STATIC
+INTN
+EFIAPI
+MmioExit (
+  IN OUT EFI_SYSTEM_CONTEXT_X64  *Regs,
+  IN TDCALL_VEINFO_RETURN_DATA   *Veinfo
+  )
+{
+  UINT64   Status;
+  UINT32   MmioSize;
+  UINT32   RegSize;
+  UINT8    OpCode;
+  BOOLEAN  SeenRex;
+  UINT64   *Reg;
+  UINT8    *Rip;
+  UINT64   Val;
+  UINT32   OpSize;
+  MODRM    ModRm;
+  REX      Rex;
+
+  Rip     = (UINT8 *)Regs->Rip;
+  Val     = 0;
+  Rex.Val = 0;
+  SeenRex = FALSE;
+
+  //
+  // Default to 32bit transfer
+  //
+  OpSize = 4;
+
+  do {
+    OpCode = *Rip++;
+    if (OpCode == 0x66) {
+      OpSize = 2;
+    } else if ((OpCode == 0x64) || (OpCode == 0x65) || (OpCode == 0x67)) {
+      continue;
+    } else if ((OpCode >= 0x40) && (OpCode <= 0x4f)) {
+      SeenRex = TRUE;
+      Rex.Val = OpCode;
+    } else {
+      break;
+    }
+  } while (TRUE);
+
+  //
+  // We need to have at least 2 more bytes for this instruction
+  //
+  TDX_DECODER_BUG_ON (((UINT64)Rip - Regs->Rip) > 13);
+
+  OpCode = *Rip++;
+  //
+  // Two-byte opecode, get next byte
+  //
+  if (OpCode == 0x0F) {
+    OpCode = *Rip++;
+  }
+
+  switch (OpCode) {
+    case 0x88:
+    case 0x8A:
+    case 0xB6:
+      MmioSize = 1;
+      break;
+    case 0xB7:
+      MmioSize = 2;
+      break;
+    default:
+      MmioSize = Rex.Bits.W ? 8 : OpSize;
+      break;
+  }
+
+  /* Punt on AH/BH/CH/DH unless it shows up. */
+  ModRm.Val = *Rip++;
+  TDX_DECODER_BUG_ON (MmioSize == 1 && ModRm.Bits.Reg > 4 && !SeenRex && OpCode != 0xB6);
+  Reg = GetRegFromContext (Regs, ModRm.Bits.Reg | ((int)Rex.Bits.R << 3));
+  TDX_DECODER_BUG_ON (!Reg);
+
+  if (ModRm.Bits.Rm == 4) {
+    ++Rip; /* SIB byte */
+  }
+
+  if ((ModRm.Bits.Mod == 2) || ((ModRm.Bits.Mod == 0) && (ModRm.Bits.Rm == 5))) {
+    Rip += 4; /* DISP32 */
+  } else if (ModRm.Bits.Mod == 1) {
+    ++Rip;  /* DISP8 */
+  }
+
+  switch (OpCode) {
+    case 0x88:
+    case 0x89:
+      CopyMem ((void *)&Val, Reg, MmioSize);
+      Status = TdVmCall (TDVMCALL_MMIO, MmioSize, 1, Veinfo->GuestPA, Val, 0);
+      break;
+    case 0xC7:
+      CopyMem ((void *)&Val, Rip, OpSize);
+      Status = TdVmCall (TDVMCALL_MMIO, MmioSize, 1, Veinfo->GuestPA, Val, 0);
+      Rip   += OpSize;
+    default:
+      //
+      // 32-bit write registers are zero extended to the full register
+      // Hence 'MOVZX r[32/64], r/m16' is
+      // hardcoded to reg size 8, and the straight MOV case has a reg
+      // size of 8 in the 32-bit read case.
+      //
+      switch (OpCode) {
+        case 0xB6:
+          RegSize = Rex.Bits.W ? 8 : OpSize;
+          break;
+        case 0xB7:
+          RegSize =  8;
+          break;
+        default:
+          RegSize = MmioSize == 4 ? 8 : MmioSize;
+          break;
+      }
+
+      Status = TdVmCall (TDVMCALL_MMIO, MmioSize, 0, Veinfo->GuestPA, 0, &Val);
+      if (Status == 0) {
+        ZeroMem (Reg, RegSize);
+        CopyMem (Reg, (void *)&Val, MmioSize);
+      }
+  }
+
+  if (Status == 0) {
+    TDX_DECODER_BUG_ON (((UINT64)Rip - Regs->Rip) > 15);
+
+    //
+    // We change instruction length to reflect true size so handler can
+    // bump rip
+    //
+    Veinfo->ExitInstructionLength =  (UINT32)((UINT64)Rip - Regs->Rip);
+  }
+
+  return Status;
+}
+
+/**
+  Handle a #VE exception.
+
+  Performs the necessary processing to handle a #VE exception.
+
+  @param[in, out]  ExceptionType  Pointer to an EFI_EXCEPTION_TYPE to be set
+                                  as value to use on error.
+  @param[in, out]  SystemContext  Pointer to EFI_SYSTEM_CONTEXT
+
+  @retval  EFI_SUCCESS            Exception handled
+  @retval  EFI_UNSUPPORTED        #VE not supported, (new) exception value to
+                                  propagate provided
+  @retval  EFI_PROTOCOL_ERROR     #VE handling failed, (new) exception value to
+                                  propagate provided
+
+**/
+EFI_STATUS
+EFIAPI
+VmTdExitHandleVe (
+  IN OUT EFI_EXCEPTION_TYPE  *ExceptionType,
+  IN OUT EFI_SYSTEM_CONTEXT  SystemContext
+  )
+{
+  UINT64                  Status;
+  TD_RETURN_DATA          ReturnData;
+  EFI_SYSTEM_CONTEXT_X64  *Regs;
+
+  Regs   = SystemContext.SystemContextX64;
+  Status = TdCall (TDCALL_TDGETVEINFO, 0, 0, 0, &ReturnData);
+  ASSERT (Status == 0);
+  if (Status != 0) {
+    DEBUG ((DEBUG_ERROR, "#VE happened. TDGETVEINFO failed with Status = 0x%llx\n", Status));
+    TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
+  }
+
+  switch (ReturnData.VeInfo.ExitReason) {
+    case EXIT_REASON_CPUID:
+      Status = CpuIdExit (Regs, &ReturnData.VeInfo);
+      DEBUG ((
+        DEBUG_VERBOSE,
+        "CPUID #VE happened, ExitReasion is %d, ExitQualification = 0x%x.\n",
+        ReturnData.VeInfo.ExitReason,
+        ReturnData.VeInfo.ExitQualification.Val
+        ));
+      break;
+
+    case EXIT_REASON_HLT:
+      Status = TdVmCall (EXIT_REASON_HLT, 0, 0, 0, 0, 0);
+      break;
+
+    case EXIT_REASON_IO_INSTRUCTION:
+      Status = IoExit (Regs, &ReturnData.VeInfo);
+      DEBUG ((
+        DEBUG_VERBOSE,
+        "IO_Instruction #VE happened, ExitReasion is %d, ExitQualification = 0x%x.\n",
+        ReturnData.VeInfo.ExitReason,
+        ReturnData.VeInfo.ExitQualification.Val
+        ));
+      break;
+
+    case EXIT_REASON_MSR_READ:
+      Status = ReadMsrExit (Regs, &ReturnData.VeInfo);
+      DEBUG ((
+        DEBUG_VERBOSE,
+        "RDMSR #VE happened, ExitReasion is %d, ExitQualification = 0x%x. Regs->Rcx=0x%llx, Status = 0x%llx\n",
+        ReturnData.VeInfo.ExitReason,
+        ReturnData.VeInfo.ExitQualification.Val,
+        Regs->Rcx,
+        Status
+        ));
+      break;
+
+    case EXIT_REASON_MSR_WRITE:
+      Status = WriteMsrExit (Regs, &ReturnData.VeInfo);
+      DEBUG ((
+        DEBUG_VERBOSE,
+        "WRMSR #VE happened, ExitReasion is %d, ExitQualification = 0x%x. Regs->Rcx=0x%llx, Status = 0x%llx\n",
+        ReturnData.VeInfo.ExitReason,
+        ReturnData.VeInfo.ExitQualification.Val,
+        Regs->Rcx,
+        Status
+        ));
+      break;
+
+    case EXIT_REASON_EPT_VIOLATION:
+      Status = MmioExit (Regs, &ReturnData.VeInfo);
+      DEBUG ((
+        DEBUG_VERBOSE,
+        "MMIO #VE happened, ExitReasion is %d, ExitQualification = 0x%x.\n",
+        ReturnData.VeInfo.ExitReason,
+        ReturnData.VeInfo.ExitQualification.Val
+        ));
+      break;
+
+    case EXIT_REASON_VMCALL:
+    case EXIT_REASON_MWAIT_INSTRUCTION:
+    case EXIT_REASON_MONITOR_INSTRUCTION:
+    case EXIT_REASON_WBINVD:
+    case EXIT_REASON_RDPMC:
+      /* Handle as nops. */
+      break;
+
+    default:
+      DEBUG ((
+        DEBUG_ERROR,
+        "Unsupported #VE happened, ExitReason is %d, ExitQualification = 0x%x.\n",
+        ReturnData.VeInfo.ExitReason,
+        ReturnData.VeInfo.ExitQualification.Val
+        ));
+
+      ASSERT (FALSE);
+      CpuDeadLoop ();
+  }
+
+  if (Status) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "#VE Error (0x%llx) returned from host, ExitReason is %d, ExitQualification = 0x%x.\n",
+      Status,
+      ReturnData.VeInfo.ExitReason,
+      ReturnData.VeInfo.ExitQualification.Val
+      ));
+
+    TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
+  }
+
+  SystemContext.SystemContextX64->Rip += ReturnData.VeInfo.ExitInstructionLength;
+  return EFI_SUCCESS;
+}
diff --git a/OvmfPkg/Library/VmgExitLib/VmgExitLib.inf b/OvmfPkg/Library/VmgExitLib/VmgExitLib.inf
index 7963670e7d30..255b0c1a2f7f 100644
--- a/OvmfPkg/Library/VmgExitLib/VmgExitLib.inf
+++ b/OvmfPkg/Library/VmgExitLib/VmgExitLib.inf
@@ -25,6 +25,8 @@
   VmgExitVcHandler.c
   VmgExitVcHandler.h
   PeiDxeVmgExitVcHandler.c
+  VmTdExitVeHandler.c
+  X64/TdVmcallCpuid.nasm
 
 [Packages]
   MdePkg/MdePkg.dec
diff --git a/OvmfPkg/Library/VmgExitLib/X64/TdVmcallCpuid.nasm b/OvmfPkg/Library/VmgExitLib/X64/TdVmcallCpuid.nasm
new file mode 100644
index 000000000000..fa86440904fe
--- /dev/null
+++ b/OvmfPkg/Library/VmgExitLib/X64/TdVmcallCpuid.nasm
@@ -0,0 +1,146 @@
+;------------------------------------------------------------------------------
+;*
+;* Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
+;* SPDX-License-Identifier: BSD-2-Clause-Patent
+;*
+;*
+;------------------------------------------------------------------------------
+
+DEFAULT REL
+SECTION .text
+
+%define TDVMCALL_EXPOSE_REGS_MASK       0xffec
+%define TDVMCALL                        0x0
+%define EXIT_REASON_CPUID               0xa
+
+%macro tdcall 0
+    db 0x66,0x0f,0x01,0xcc
+%endmacro
+
+%macro tdcall_push_regs 0
+    push rbp
+    mov  rbp, rsp
+    push r15
+    push r14
+    push r13
+    push r12
+    push rbx
+    push rsi
+    push rdi
+%endmacro
+
+%macro tdcall_pop_regs 0
+    pop rdi
+    pop rsi
+    pop rbx
+    pop r12
+    pop r13
+    pop r14
+    pop r15
+    pop rbp
+%endmacro
+
+%define number_of_regs_pushed 8
+%define number_of_parameters  4
+
+;
+; Keep these in sync for push_regs/pop_regs, code below
+; uses them to find 5th or greater parameters
+;
+%define first_variable_on_stack_offset \
+  ((number_of_regs_pushed * 8) + (number_of_parameters * 8) + 8)
+%define second_variable_on_stack_offset \
+  ((first_variable_on_stack_offset) + 8)
+
+%macro tdcall_regs_preamble 2
+    mov rax, %1
+
+    xor rcx, rcx
+    mov ecx, %2
+
+    ; R10 = 0 (standard TDVMCALL)
+
+    xor r10d, r10d
+
+    ; Zero out unused (for standard TDVMCALL) registers to avoid leaking
+    ; secrets to the VMM.
+
+    xor ebx, ebx
+    xor esi, esi
+    xor edi, edi
+
+    xor edx, edx
+    xor ebp, ebp
+    xor r8d, r8d
+    xor r9d, r9d
+    xor r14, r14
+    xor r15, r15
+%endmacro
+
+%macro tdcall_regs_postamble 0
+    xor ebx, ebx
+    xor esi, esi
+    xor edi, edi
+
+    xor ecx, ecx
+    xor edx, edx
+    xor r8d,  r8d
+    xor r9d,  r9d
+    xor r10d, r10d
+    xor r11d, r11d
+%endmacro
+
+;------------------------------------------------------------------------------
+; 0   => RAX = TDCALL leaf / TDVMCALL
+; M   => RCX = TDVMCALL register behavior
+; 0xa => R11 = TDVMCALL function / CPUID
+; RCX => R12 = p1
+; RDX => R13 = p2
+;
+;  UINT64
+;  EFIAPI
+;  TdVmCallCpuid (
+;    UINT64  EaxIn,    // Rcx
+;    UINT64  EcxIn,    // Rdx
+;    UINT64  *Results  // R8
+;    )
+global ASM_PFX(TdVmCallCpuid)
+ASM_PFX(TdVmCallCpuid):
+       tdcall_push_regs
+
+       mov r11, EXIT_REASON_CPUID
+       mov r12, rcx
+       mov r13, rdx
+
+       ; Save *results pointers
+       push r8
+
+       tdcall_regs_preamble TDVMCALL, TDVMCALL_EXPOSE_REGS_MASK
+
+       tdcall
+
+       ; ignore return data if TDCALL reports failure.
+       test rax, rax
+       jnz .no_return_data
+
+       ; Propagate TDVMCALL success/failure to return value.
+       mov rax, r10
+       test rax, rax
+       jnz .no_return_data
+
+       ; Retrieve *Results
+       pop r8
+       test r8, r8
+       jz .no_return_data
+       ; Caller pass in buffer so store results r12-r15 contains eax-edx
+       mov [r8 +  0], r12
+       mov [r8 +  8], r13
+       mov [r8 + 16], r14
+       mov [r8 + 24], r15
+
+.no_return_data:
+       tdcall_regs_postamble
+
+       tdcall_pop_regs
+
+       ret
-- 
2.29.2.windows.2


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH V12 07/47] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VE exception
  2022-03-29 23:45 [PATCH V12 00/47] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (5 preceding siblings ...)
  2022-03-29 23:45 ` [PATCH V12 06/47] OvmfPkg: Extend VmgExitLib " Min Xu
@ 2022-03-29 23:46 ` Min Xu
  2022-03-29 23:46 ` [PATCH V12 08/47] MdePkg: Add helper functions for Tdx guest in BaseIoLibIntrinsic Min Xu
                   ` (33 subsequent siblings)
  40 siblings, 0 replies; 53+ messages in thread
From: Min Xu @ 2022-03-29 23:46 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Brijesh Singh, Erdem Aktas, James Bottomley, Jiewen Yao,
	Tom Lendacky, Eric Dong, Ray Ni, Rahul Kumar, Gerd Hoffmann

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

Add base support to handle #VE exceptions. Update the common exception
handlers to invoke the VmTdExitHandleVe () function of the VmgExitLib
library when a #VE is encountered. A non-zero return code will propagate
to the targeted exception handler.

Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Ray Ni <ray.ni@intel.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 .../PeiDxeSmmCpuException.c                   | 53 ++++++++++++-----
 .../SecPeiCpuException.c                      | 57 +++++++++++++------
 2 files changed, 79 insertions(+), 31 deletions(-)

diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeSmmCpuException.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeSmmCpuException.c
index 762ea2460f91..f47a80dcab8f 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeSmmCpuException.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeSmmCpuException.c
@@ -24,25 +24,48 @@ CommonExceptionHandlerWorker (
   IN EXCEPTION_HANDLER_DATA  *ExceptionHandlerData
   )
 {
+  EFI_STATUS                 Status;
   EXCEPTION_HANDLER_CONTEXT  *ExceptionHandlerContext;
   RESERVED_VECTORS_DATA      *ReservedVectors;
   EFI_CPU_INTERRUPT_HANDLER  *ExternalInterruptHandler;
 
-  if (ExceptionType == VC_EXCEPTION) {
-    EFI_STATUS  Status;
-    //
-    // #VC needs to be handled immediately upon enabling exception handling
-    // and therefore can't use the RegisterCpuInterruptHandler() interface.
-    //
-    // Handle the #VC:
-    //   On EFI_SUCCESS - Exception has been handled, return
-    //   On other       - ExceptionType contains (possibly new) exception
-    //                    value
-    //
-    Status = VmgExitHandleVc (&ExceptionType, SystemContext);
-    if (!EFI_ERROR (Status)) {
-      return;
-    }
+  switch (ExceptionType) {
+    case VC_EXCEPTION:
+      //
+      // #VC needs to be handled immediately upon enabling exception handling
+      // and therefore can't use the RegisterCpuInterruptHandler() interface.
+      //
+      // Handle the #VC:
+      //   On EFI_SUCCESS - Exception has been handled, return
+      //   On other       - ExceptionType contains (possibly new) exception
+      //                    value
+      //
+      Status = VmgExitHandleVc (&ExceptionType, SystemContext);
+      if (!EFI_ERROR (Status)) {
+        return;
+      }
+
+      break;
+
+    case VE_EXCEPTION:
+      //
+      // #VE needs to be handled immediately upon enabling exception handling
+      // and therefore can't use the RegisterCpuInterruptHandler() interface.
+      //
+      // Handle the #VE:
+      //   On EFI_SUCCESS - Exception has been handled, return
+      //   On other       - ExceptionType contains (possibly new) exception
+      //                    value
+      //
+      Status = VmTdExitHandleVe (&ExceptionType, SystemContext);
+      if (!EFI_ERROR (Status)) {
+        return;
+      }
+
+      break;
+
+    default:
+      break;
   }
 
   ExceptionHandlerContext  = (EXCEPTION_HANDLER_CONTEXT *)(UINTN)(SystemContext.SystemContextIa32);
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c
index c614d5b0b6f1..6e5216380da8 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c
@@ -25,22 +25,47 @@ CommonExceptionHandler (
   IN EFI_SYSTEM_CONTEXT  SystemContext
   )
 {
-  if (ExceptionType == VC_EXCEPTION) {
-    EFI_STATUS  Status;
-    //
-    // #VC needs to be handled immediately upon enabling exception handling
-    // and therefore can't use the RegisterCpuInterruptHandler() interface
-    // (which isn't supported under Sec and Pei anyway).
-    //
-    // Handle the #VC:
-    //   On EFI_SUCCESS - Exception has been handled, return
-    //   On other       - ExceptionType contains (possibly new) exception
-    //                    value
-    //
-    Status = VmgExitHandleVc (&ExceptionType, SystemContext);
-    if (!EFI_ERROR (Status)) {
-      return;
-    }
+  EFI_STATUS  Status;
+
+  switch (ExceptionType) {
+    case VC_EXCEPTION:
+      //
+      // #VC needs to be handled immediately upon enabling exception handling
+      // and therefore can't use the RegisterCpuInterruptHandler() interface
+      // (which isn't supported under Sec and Pei anyway).
+      //
+      // Handle the #VC:
+      //   On EFI_SUCCESS - Exception has been handled, return
+      //   On other       - ExceptionType contains (possibly new) exception
+      //                    value
+      //
+      Status = VmgExitHandleVc (&ExceptionType, SystemContext);
+      if (!EFI_ERROR (Status)) {
+        return;
+      }
+
+      break;
+
+    case VE_EXCEPTION:
+      //
+      // #VE needs to be handled immediately upon enabling exception handling
+      // and therefore can't use the RegisterCpuInterruptHandler() interface
+      // (which isn't supported under Sec and Pei anyway).
+      //
+      // Handle the #VE:
+      //   On EFI_SUCCESS - Exception has been handled, return
+      //   On other       - ExceptionType contains (possibly new) exception
+      //                    value
+      //
+      Status = VmTdExitHandleVe (&ExceptionType, SystemContext);
+      if (!EFI_ERROR (Status)) {
+        return;
+      }
+
+      break;
+
+    default:
+      break;
   }
 
   //
-- 
2.29.2.windows.2


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH V12 08/47] MdePkg: Add helper functions for Tdx guest in BaseIoLibIntrinsic
  2022-03-29 23:45 [PATCH V12 00/47] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (6 preceding siblings ...)
  2022-03-29 23:46 ` [PATCH V12 07/47] UefiCpuPkg/CpuExceptionHandler: Add base support for the " Min Xu
@ 2022-03-29 23:46 ` Min Xu
  2022-03-29 23:46 ` [PATCH V12 09/47] MdePkg: Support mmio " Min Xu
                   ` (32 subsequent siblings)
  40 siblings, 0 replies; 53+ messages in thread
From: Min Xu @ 2022-03-29 23:46 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Michael D Kinney, Liming Gao, Zhiguang Liu, Brijesh Singh,
	Erdem Aktas, James Bottomley, Jiewen Yao, Tom Lendacky

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

Intel TDX architecture does not prescribe a specific software convention
to perform I/O from the guest TD. Guest TD providers have many choices to
provide I/O to the guest. The common I/O models are emulated devices,
para-virtualized devices, SRIOV devices and Direct Device assignments.

TDVF chooses para-virtualized I/O (Choice-A) which use the TDG.VP.VMCALL
function to invoke the funtions provided by the host VMM to perform I/O.
Another choice (Choice-B) is the emulation performed by the #VE handler.

There are 2 benefits of para-virtualized I/O:
1. Performance.
   VMEXIT/VMENTRY is skipped so that the performance is better than #VE
   handler.
2. De-couple with #VE handler.
   Choice-B depends on the #VE handler which means I/O is not available
   until #VE handler is installed. For example, in PEI phase #VE handler
   is installed in CpuMpPei, while communication with Qemu (via I/O port)
   happen earlier than it.

IoLibInternalTdx.c provides the helper functions for Tdx guest.
IoLibInternalTdxNull.c provides the null version of the helper functions.
It is included in the Non-X64 IoLib so that the build will not be broken.

Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Zhiguang Liu <zhiguang.liu@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Reviewed-by: Liming Gao <gaoliming@byosoft.com.cn>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 .../BaseIoLibIntrinsicSev.inf                 |   2 +
 .../BaseIoLibIntrinsic/IoLibInternalTdx.c     | 674 ++++++++++++++++++
 .../BaseIoLibIntrinsic/IoLibInternalTdxNull.c | 497 +++++++++++++
 MdePkg/Library/BaseIoLibIntrinsic/IoLibTdx.h  | 410 +++++++++++
 4 files changed, 1583 insertions(+)
 create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdx.c
 create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdxNull.c
 create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/IoLibTdx.h

diff --git a/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicSev.inf b/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicSev.inf
index 34f9d1d1062f..336d79736d9a 100644
--- a/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicSev.inf
+++ b/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicSev.inf
@@ -51,3 +51,5 @@
   BaseLib
   RegisterFilterLib
 
+[LibraryClasses.X64]
+  TdxLib
diff --git a/MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdx.c b/MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdx.c
new file mode 100644
index 000000000000..1e539dbfbbad
--- /dev/null
+++ b/MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdx.c
@@ -0,0 +1,674 @@
+/** @file
+  TDX I/O Library routines.
+
+  Copyright (c) 2020-2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include "BaseIoLibIntrinsicInternal.h"
+#include <Uefi/UefiBaseType.h>
+#include <Include/IndustryStandard/Tdx.h>
+#include <Library/TdxLib.h>
+#include <Register/Intel/Cpuid.h>
+#include "IoLibTdx.h"
+
+// Size of TDVMCALL Access, including IO and MMIO
+#define TDVMCALL_ACCESS_SIZE_1  1
+#define TDVMCALL_ACCESS_SIZE_2  2
+#define TDVMCALL_ACCESS_SIZE_4  4
+#define TDVMCALL_ACCESS_SIZE_8  8
+
+// Direction of TDVMCALL Access, including IO and MMIO
+#define TDVMCALL_ACCESS_READ   0
+#define TDVMCALL_ACCESS_WRITE  1
+
+BOOLEAN  mTdxEnabled = FALSE;
+BOOLEAN  mTdxProbed  = FALSE;
+
+/**
+  Check if it is Tdx guest.
+
+  @return TRUE    It is Tdx guest
+  @return FALSE   It is not Tdx guest
+
+**/
+BOOLEAN
+EFIAPI
+IsTdxGuest (
+  VOID
+  )
+{
+  if (mTdxProbed) {
+    return mTdxEnabled;
+  }
+
+  mTdxEnabled = TdIsEnabled ();
+  mTdxProbed  = TRUE;
+
+  return mTdxEnabled;
+}
+
+/**
+  Reads an 8-bit I/O port.
+
+  TDVMCALL_IO is invoked to read I/O port.
+
+  @param  Port  The I/O port to read.
+
+  @return The value read.
+
+**/
+UINT8
+EFIAPI
+TdIoRead8 (
+  IN      UINTN  Port
+  )
+{
+  UINT64  Status;
+  UINT64  Val;
+
+  Status = TdVmCall (TDVMCALL_IO, TDVMCALL_ACCESS_SIZE_1, TDVMCALL_ACCESS_READ, Port, 0, &Val);
+  if (Status != 0) {
+    TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
+  }
+
+  return (UINT8)Val;
+}
+
+/**
+  Reads a 16-bit I/O port.
+
+  TDVMCALL_IO is invoked to write I/O port.
+
+  @param  Port  The I/O port to read.
+
+  @return The value read.
+
+**/
+UINT16
+EFIAPI
+TdIoRead16 (
+  IN      UINTN  Port
+  )
+{
+  UINT64  Status;
+  UINT64  Val;
+
+  ASSERT ((Port & 1) == 0);
+
+  Status = TdVmCall (TDVMCALL_IO, TDVMCALL_ACCESS_SIZE_2, TDVMCALL_ACCESS_READ, Port, 0, &Val);
+  if (Status != 0) {
+    TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
+  }
+
+  return (UINT16)Val;
+}
+
+/**
+  Reads a 32-bit I/O port.
+
+  TDVMCALL_IO is invoked to read I/O port.
+
+  @param  Port  The I/O port to read.
+
+  @return The value read.
+
+**/
+UINT32
+EFIAPI
+TdIoRead32 (
+  IN      UINTN  Port
+  )
+{
+  UINT64  Status;
+  UINT64  Val;
+
+  ASSERT ((Port & 3) == 0);
+
+  Status = TdVmCall (TDVMCALL_IO, TDVMCALL_ACCESS_SIZE_4, TDVMCALL_ACCESS_READ, Port, 0, &Val);
+  if (Status != 0) {
+    TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
+  }
+
+  return (UINT32)Val;
+}
+
+/**
+  Writes an 8-bit I/O port.
+
+  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.
+
+  @return The value written the I/O port.
+
+**/
+UINT8
+EFIAPI
+TdIoWrite8 (
+  IN      UINTN  Port,
+  IN      UINT8  Value
+  )
+{
+  UINT64  Status;
+  UINT64  Val;
+
+  Val    = Value;
+  Status = TdVmCall (TDVMCALL_IO, TDVMCALL_ACCESS_SIZE_1, TDVMCALL_ACCESS_WRITE, Port, Val, 0);
+  if (Status != 0) {
+    TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
+  }
+
+  return Value;
+}
+
+/**
+  Writes a 16-bit I/O port.
+
+  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.
+
+  @return The value written the I/O port.
+
+**/
+UINT16
+EFIAPI
+TdIoWrite16 (
+  IN      UINTN   Port,
+  IN      UINT16  Value
+  )
+{
+  UINT64  Status;
+  UINT64  Val;
+
+  ASSERT ((Port & 1) == 0);
+  Val    = Value;
+  Status = TdVmCall (TDVMCALL_IO, TDVMCALL_ACCESS_SIZE_2, TDVMCALL_ACCESS_WRITE, Port, Val, 0);
+  if (Status != 0) {
+    TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
+  }
+
+  return Value;
+}
+
+/**
+  Writes a 32-bit I/O port.
+
+  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.
+
+  @return The value written the I/O port.
+
+**/
+UINT32
+EFIAPI
+TdIoWrite32 (
+  IN      UINTN   Port,
+  IN      UINT32  Value
+  )
+{
+  UINT64  Status;
+  UINT64  Val;
+
+  ASSERT ((Port & 3) == 0);
+  Val    = Value;
+  Status = TdVmCall (TDVMCALL_IO, TDVMCALL_ACCESS_SIZE_4, TDVMCALL_ACCESS_WRITE, Port, Val, 0);
+  if (Status != 0) {
+    TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
+  }
+
+  return Value;
+}
+
+/**
+  Reads an 8-bit MMIO register.
+
+  TDVMCALL_MMIO is invoked to read MMIO registers.
+
+  @param  Address The MMIO register to read.
+
+  @return The value read.
+
+**/
+UINT8
+EFIAPI
+TdMmioRead8 (
+  IN      UINTN  Address
+  )
+{
+  UINT64  Value;
+  UINT64  Status;
+
+  Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_1, TDVMCALL_ACCESS_READ, Address | TdSharedPageMask (), 0, &Value);
+  if (Status != 0) {
+    Value = *(volatile UINT64 *)Address;
+  }
+
+  return (UINT8)Value;
+}
+
+/**
+  Writes an 8-bit MMIO register.
+
+  TDVMCALL_MMIO is invoked to read write registers.
+
+  @param  Address The MMIO register to write.
+  @param  Value   The value to write to the MMIO register.
+
+  @return Value.
+
+**/
+UINT8
+EFIAPI
+TdMmioWrite8 (
+  IN      UINTN  Address,
+  IN      UINT8  Value
+  )
+{
+  UINT64  Val;
+  UINT64  Status;
+
+  Val    = Value;
+  Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_1, TDVMCALL_ACCESS_WRITE, Address | TdSharedPageMask (), Val, 0);
+  if (Status != 0) {
+    *(volatile UINT8 *)Address = Value;
+  }
+
+  return Value;
+}
+
+/**
+  Reads a 16-bit MMIO register.
+
+  TDVMCALL_MMIO is invoked to read MMIO registers.
+
+  @param  Address The MMIO register to read.
+
+  @return The value read.
+
+**/
+UINT16
+EFIAPI
+TdMmioRead16 (
+  IN      UINTN  Address
+  )
+{
+  UINT64  Value;
+  UINT64  Status;
+
+  Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_2, TDVMCALL_ACCESS_READ, Address | TdSharedPageMask (), 0, &Value);
+  if (Status != 0) {
+    Value = *(volatile UINT64 *)Address;
+  }
+
+  return (UINT16)Value;
+}
+
+/**
+  Writes a 16-bit MMIO register.
+
+  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.
+
+  @return Value.
+
+**/
+UINT16
+EFIAPI
+TdMmioWrite16 (
+  IN      UINTN   Address,
+  IN      UINT16  Value
+  )
+{
+  UINT64  Val;
+  UINT64  Status;
+
+  ASSERT ((Address & 1) == 0);
+
+  Val    = Value;
+  Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_2, TDVMCALL_ACCESS_WRITE, Address | TdSharedPageMask (), Val, 0);
+  if (Status != 0) {
+    *(volatile UINT16 *)Address = Value;
+  }
+
+  return Value;
+}
+
+/**
+  Reads a 32-bit MMIO register.
+
+  TDVMCALL_MMIO is invoked to read MMIO registers.
+
+  @param  Address The MMIO register to read.
+
+  @return The value read.
+
+**/
+UINT32
+EFIAPI
+TdMmioRead32 (
+  IN      UINTN  Address
+  )
+{
+  UINT64  Value;
+  UINT64  Status;
+
+  Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_4, TDVMCALL_ACCESS_READ, Address | TdSharedPageMask (), 0, &Value);
+  if (Status != 0) {
+    Value = *(volatile UINT64 *)Address;
+  }
+
+  return (UINT32)Value;
+}
+
+/**
+  Writes a 32-bit MMIO register.
+
+  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.
+
+  @return Value.
+
+**/
+UINT32
+EFIAPI
+TdMmioWrite32 (
+  IN      UINTN   Address,
+  IN      UINT32  Value
+  )
+{
+  UINT64  Val;
+  UINT64  Status;
+
+  ASSERT ((Address & 3) == 0);
+
+  Val    = Value;
+  Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_4, TDVMCALL_ACCESS_WRITE, Address | TdSharedPageMask (), Val, 0);
+  if (Status != 0) {
+    *(volatile UINT32 *)Address = Value;
+  }
+
+  return Value;
+}
+
+/**
+  Reads a 64-bit MMIO register.
+
+  TDVMCALL_MMIO is invoked to read MMIO registers.
+
+  @param  Address The MMIO register to read.
+
+  @return The value read.
+
+**/
+UINT64
+EFIAPI
+TdMmioRead64 (
+  IN      UINTN  Address
+  )
+{
+  UINT64  Value;
+  UINT64  Status;
+
+  Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_8, TDVMCALL_ACCESS_READ, Address | TdSharedPageMask (), 0, &Value);
+  if (Status != 0) {
+    Value = *(volatile UINT64 *)Address;
+  }
+
+  return Value;
+}
+
+/**
+  Writes a 64-bit MMIO register.
+
+  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.
+
+**/
+UINT64
+EFIAPI
+TdMmioWrite64 (
+  IN      UINTN   Address,
+  IN      UINT64  Value
+  )
+{
+  UINT64  Status;
+  UINT64  Val;
+
+  ASSERT ((Address & 7) == 0);
+
+  Val    = Value;
+  Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_8, TDVMCALL_ACCESS_WRITE, Address | TdSharedPageMask (), Val, 0);
+  if (Status != 0) {
+    *(volatile UINT64 *)Address = Value;
+  }
+
+  return Value;
+}
+
+/**
+  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
+TdIoReadFifo8 (
+  IN      UINTN  Port,
+  IN      UINTN  Count,
+  OUT     VOID   *Buffer
+  )
+{
+  UINT8  *Buf8;
+  UINTN  Index;
+
+  Buf8 = (UINT8 *)Buffer;
+  for (Index = 0; Index < Count; Index++) {
+    Buf8[Index] = TdIoRead8 (Port);
+  }
+}
+
+/**
+  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
+TdIoWriteFifo8 (
+  IN      UINTN  Port,
+  IN      UINTN  Count,
+  IN      VOID   *Buffer
+  )
+{
+  UINT8  *Buf8;
+  UINTN  Index;
+
+  Buf8 = (UINT8 *)Buffer;
+  for (Index = 0; Index < Count; Index++) {
+    TdIoWrite8 (Port, Buf8[Index]);
+  }
+}
+
+/**
+  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
+TdIoReadFifo16 (
+  IN      UINTN  Port,
+  IN      UINTN  Count,
+  OUT     VOID   *Buffer
+  )
+{
+  UINT16  *Buf16;
+  UINTN   Index;
+
+  Buf16 = (UINT16 *)Buffer;
+  for (Index = 0; Index < Count; Index++) {
+    Buf16[Index] = TdIoRead16 (Port);
+  }
+}
+
+/**
+  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
+TdIoWriteFifo16 (
+  IN      UINTN  Port,
+  IN      UINTN  Count,
+  IN      VOID   *Buffer
+  )
+{
+  UINT16  *Buf16;
+  UINTN   Index;
+
+  Buf16 = (UINT16 *)Buffer;
+  for (Index = 0; Index < Count; Index++) {
+    TdIoWrite16 (Port, Buf16[Index]);
+  }
+}
+
+/**
+  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
+TdIoReadFifo32 (
+  IN      UINTN  Port,
+  IN      UINTN  Count,
+  OUT     VOID   *Buffer
+  )
+{
+  UINT32  *Buf32;
+  UINTN   Index;
+
+  Buf32 = (UINT32 *)Buffer;
+  for (Index = 0; Index < Count; Index++) {
+    Buf32[Index] = TdIoRead32 (Port);
+  }
+}
+
+/**
+  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
+TdIoWriteFifo32 (
+  IN      UINTN  Port,
+  IN      UINTN  Count,
+  IN      VOID   *Buffer
+  )
+{
+  UINT32  *Buf32;
+  UINTN   Index;
+
+  Buf32 = (UINT32 *)Buffer;
+  for (Index = 0; Index < Count; Index++) {
+    TdIoWrite32 (Port, Buf32[Index]);
+  }
+}
diff --git a/MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdxNull.c b/MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdxNull.c
new file mode 100644
index 000000000000..7262704d6b14
--- /dev/null
+++ b/MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdxNull.c
@@ -0,0 +1,497 @@
+/** @file
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/BaseLib.h>
+#include "BaseIoLibIntrinsicInternal.h"
+#include "IoLibTdx.h"
+
+/**
+  Check if it is Tdx guest.
+
+  @return TRUE    It is Tdx guest
+  @return FALSE   It is not Tdx guest
+
+**/
+BOOLEAN
+EFIAPI
+IsTdxGuest (
+  VOID
+  )
+{
+  return FALSE;
+}
+
+/**
+  Reads an 8-bit I/O port.
+
+  TDVMCALL_IO is invoked to read I/O port.
+
+  @param  Port  The I/O port to read.
+
+  @return The value read.
+
+**/
+UINT8
+EFIAPI
+TdIoRead8 (
+  IN      UINTN  Port
+  )
+{
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Reads a 16-bit I/O port.
+
+  TDVMCALL_IO is invoked to write I/O port.
+
+  @param  Port  The I/O port to read.
+
+  @return The value read.
+
+**/
+UINT16
+EFIAPI
+TdIoRead16 (
+  IN      UINTN  Port
+  )
+{
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Reads a 32-bit I/O port.
+
+  TDVMCALL_IO is invoked to read I/O port.
+
+  @param  Port  The I/O port to read.
+
+  @return The value read.
+
+**/
+UINT32
+EFIAPI
+TdIoRead32 (
+  IN      UINTN  Port
+  )
+{
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Writes an 8-bit I/O port.
+
+  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.
+
+  @return The value written the I/O port.
+
+**/
+UINT8
+EFIAPI
+TdIoWrite8 (
+  IN      UINTN  Port,
+  IN      UINT8  Value
+  )
+{
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Writes a 16-bit I/O port.
+
+  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.
+
+  @return The value written the I/O port.
+
+**/
+UINT16
+EFIAPI
+TdIoWrite16 (
+  IN      UINTN   Port,
+  IN      UINT16  Value
+  )
+{
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Writes a 32-bit I/O port.
+
+  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.
+
+  @return The value written the I/O port.
+
+**/
+UINT32
+EFIAPI
+TdIoWrite32 (
+  IN      UINTN   Port,
+  IN      UINT32  Value
+  )
+{
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Reads an 8-bit MMIO register.
+
+  TDVMCALL_MMIO is invoked to read MMIO registers.
+
+  @param  Address The MMIO register to read.
+
+  @return The value read.
+
+**/
+UINT8
+EFIAPI
+TdMmioRead8 (
+  IN      UINTN  Address
+  )
+{
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Writes an 8-bit MMIO register.
+
+  TDVMCALL_MMIO is invoked to read write registers.
+
+  @param  Address The MMIO register to write.
+  @param  Value   The value to write to the MMIO register.
+
+  @return Value.
+
+**/
+UINT8
+EFIAPI
+TdMmioWrite8 (
+  IN      UINTN  Address,
+  IN      UINT8  Val
+  )
+{
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Reads a 16-bit MMIO register.
+
+  TDVMCALL_MMIO is invoked to read MMIO registers.
+
+  @param  Address The MMIO register to read.
+
+  @return The value read.
+
+**/
+UINT16
+EFIAPI
+TdMmioRead16 (
+  IN      UINTN  Address
+  )
+{
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Writes a 16-bit MMIO register.
+
+  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.
+
+  @return Value.
+
+**/
+UINT16
+EFIAPI
+TdMmioWrite16 (
+  IN      UINTN   Address,
+  IN      UINT16  Val
+  )
+{
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Reads a 32-bit MMIO register.
+
+  TDVMCALL_MMIO is invoked to read MMIO registers.
+
+  @param  Address The MMIO register to read.
+
+  @return The value read.
+
+**/
+UINT32
+EFIAPI
+TdMmioRead32 (
+  IN      UINTN  Address
+  )
+{
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Writes a 32-bit MMIO register.
+
+  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.
+
+  @return Value.
+
+**/
+UINT32
+EFIAPI
+TdMmioWrite32 (
+  IN      UINTN   Address,
+  IN      UINT32  Val
+  )
+{
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Reads a 64-bit MMIO register.
+
+  TDVMCALL_MMIO is invoked to read MMIO registers.
+
+  @param  Address The MMIO register to read.
+
+  @return The value read.
+
+**/
+UINT64
+EFIAPI
+TdMmioRead64 (
+  IN      UINTN  Address
+  )
+{
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Writes a 64-bit MMIO register.
+
+  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.
+
+**/
+UINT64
+EFIAPI
+TdMmioWrite64 (
+  IN      UINTN   Address,
+  IN      UINT64  Value
+  )
+{
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  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
+TdIoReadFifo8 (
+  IN      UINTN  Port,
+  IN      UINTN  Count,
+  OUT     VOID   *Buffer
+  )
+{
+  ASSERT (FALSE);
+}
+
+/**
+  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
+TdIoWriteFifo8 (
+  IN      UINTN  Port,
+  IN      UINTN  Count,
+  IN      VOID   *Buffer
+  )
+{
+  ASSERT (FALSE);
+}
+
+/**
+  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
+TdIoReadFifo16 (
+  IN      UINTN  Port,
+  IN      UINTN  Count,
+  OUT     VOID   *Buffer
+  )
+{
+  ASSERT (FALSE);
+}
+
+/**
+  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
+TdIoWriteFifo16 (
+  IN      UINTN  Port,
+  IN      UINTN  Count,
+  IN      VOID   *Buffer
+  )
+{
+  ASSERT (FALSE);
+}
+
+/**
+  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
+TdIoReadFifo32 (
+  IN      UINTN  Port,
+  IN      UINTN  Count,
+  OUT     VOID   *Buffer
+  )
+{
+  ASSERT (FALSE);
+}
+
+/**
+  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
+TdIoWriteFifo32 (
+  IN      UINTN  Port,
+  IN      UINTN  Count,
+  IN      VOID   *Buffer
+  )
+{
+  ASSERT (FALSE);
+}
diff --git a/MdePkg/Library/BaseIoLibIntrinsic/IoLibTdx.h b/MdePkg/Library/BaseIoLibIntrinsic/IoLibTdx.h
new file mode 100644
index 000000000000..ab2fa771f6c8
--- /dev/null
+++ b/MdePkg/Library/BaseIoLibIntrinsic/IoLibTdx.h
@@ -0,0 +1,410 @@
+/** @file
+  Header file for Tdx IO library.
+
+  Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
+   SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef IOLIB_TDX_H_
+#define IOLIB_TDX_H_
+
+/**
+  Check if it is Tdx guest.
+
+  @return TRUE    It is Tdx guest
+  @return FALSE   It is not Tdx guest
+
+**/
+BOOLEAN
+EFIAPI
+IsTdxGuest (
+  VOID
+  );
+
+/**
+  Reads an 8-bit I/O port.
+
+  TDVMCALL_IO is invoked to read I/O port.
+
+  @param  Port  The I/O port to read.
+
+  @return The value read.
+
+**/
+UINT8
+EFIAPI
+TdIoRead8 (
+  IN      UINTN  Port
+  );
+
+/**
+  Reads a 16-bit I/O port.
+
+  TDVMCALL_IO is invoked to write I/O port.
+
+  @param  Port  The I/O port to read.
+
+  @return The value read.
+
+**/
+UINT16
+EFIAPI
+TdIoRead16 (
+  IN      UINTN  Port
+  );
+
+/**
+  Reads a 32-bit I/O port.
+
+  TDVMCALL_IO is invoked to read I/O port.
+
+  @param  Port  The I/O port to read.
+
+  @return The value read.
+
+**/
+UINT32
+EFIAPI
+TdIoRead32 (
+  IN      UINTN  Port
+  );
+
+/**
+  Writes an 8-bit I/O port.
+
+  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.
+
+  @return The value written the I/O port.
+
+**/
+UINT8
+EFIAPI
+TdIoWrite8 (
+  IN      UINTN  Port,
+  IN      UINT8  Value
+  );
+
+/**
+  Writes a 16-bit I/O port.
+
+  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.
+
+  @return The value written the I/O port.
+
+**/
+UINT16
+EFIAPI
+TdIoWrite16 (
+  IN      UINTN   Port,
+  IN      UINT16  Value
+  );
+
+/**
+  Writes a 32-bit I/O port.
+
+  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.
+
+  @return The value written the I/O port.
+
+**/
+UINT32
+EFIAPI
+TdIoWrite32 (
+  IN      UINTN   Port,
+  IN      UINT32  Value
+  );
+
+/**
+  Reads an 8-bit MMIO register.
+
+  TDVMCALL_MMIO is invoked to read MMIO registers.
+
+  @param  Address The MMIO register to read.
+
+  @return The value read.
+
+**/
+UINT8
+EFIAPI
+TdMmioRead8 (
+  IN      UINTN  Address
+  );
+
+/**
+  Writes an 8-bit MMIO register.
+
+  TDVMCALL_MMIO is invoked to read write registers.
+
+  @param  Address The MMIO register to write.
+  @param  Value   The value to write to the MMIO register.
+
+  @return Value.
+
+**/
+UINT8
+EFIAPI
+TdMmioWrite8 (
+  IN      UINTN  Address,
+  IN      UINT8  Val
+  );
+
+/**
+  Reads a 16-bit MMIO register.
+
+  TDVMCALL_MMIO is invoked to read MMIO registers.
+
+  @param  Address The MMIO register to read.
+
+  @return The value read.
+
+**/
+UINT16
+EFIAPI
+TdMmioRead16 (
+  IN      UINTN  Address
+  );
+
+/**
+  Writes a 16-bit MMIO register.
+
+  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.
+
+  @return Value.
+
+**/
+UINT16
+EFIAPI
+TdMmioWrite16 (
+  IN      UINTN   Address,
+  IN      UINT16  Val
+  );
+
+/**
+  Reads a 32-bit MMIO register.
+
+  TDVMCALL_MMIO is invoked to read MMIO registers.
+
+  @param  Address The MMIO register to read.
+
+  @return The value read.
+
+**/
+UINT32
+EFIAPI
+TdMmioRead32 (
+  IN      UINTN  Address
+  );
+
+/**
+  Writes a 32-bit MMIO register.
+
+  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.
+
+  @return Value.
+
+**/
+UINT32
+EFIAPI
+TdMmioWrite32 (
+  IN      UINTN   Address,
+  IN      UINT32  Val
+  );
+
+/**
+  Reads a 64-bit MMIO register.
+
+  TDVMCALL_MMIO is invoked to read MMIO registers.
+
+  @param  Address The MMIO register to read.
+
+  @return The value read.
+
+**/
+UINT64
+EFIAPI
+TdMmioRead64 (
+  IN      UINTN  Address
+  );
+
+/**
+  Writes a 64-bit MMIO register.
+
+  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.
+
+**/
+UINT64
+EFIAPI
+TdMmioWrite64 (
+  IN      UINTN   Address,
+  IN      UINT64  Value
+  );
+
+/**
+  Reads an 8-bit I/O port fifo into a block of memory in Tdx.
+
+  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
+TdIoReadFifo8 (
+  IN      UINTN  Port,
+  IN      UINTN  Count,
+  OUT     VOID   *Buffer
+  );
+
+/**
+  Writes a block of memory into an 8-bit I/O port fifo in Tdx.
+
+  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
+TdIoWriteFifo8 (
+  IN      UINTN  Port,
+  IN      UINTN  Count,
+  IN      VOID   *Buffer
+  );
+
+/**
+  Reads a 16-bit I/O port fifo into a block of memory in Tdx.
+
+  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().
+
+  @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
+TdIoReadFifo16 (
+  IN      UINTN  Port,
+  IN      UINTN  Count,
+  OUT     VOID   *Buffer
+  );
+
+/**
+  Writes a block of memory into a 16-bit I/O port fifo in Tdx.
+
+  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().
+
+  @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
+TdIoWriteFifo16 (
+  IN      UINTN  Port,
+  IN      UINTN  Count,
+  IN      VOID   *Buffer
+  );
+
+/**
+  Reads a 32-bit I/O port fifo into a block of memory in Tdx.
+
+  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().
+
+  @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
+TdIoReadFifo32 (
+  IN      UINTN  Port,
+  IN      UINTN  Count,
+  OUT     VOID   *Buffer
+  );
+
+/**
+  Writes a block of memory into a 32-bit I/O port fifo in Tdx.
+
+  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().
+
+  @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
+TdIoWriteFifo32 (
+  IN      UINTN  Port,
+  IN      UINTN  Count,
+  IN      VOID   *Buffer
+  );
+
+#endif
-- 
2.29.2.windows.2


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH V12 09/47] MdePkg: Support mmio for Tdx guest in BaseIoLibIntrinsic
  2022-03-29 23:45 [PATCH V12 00/47] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (7 preceding siblings ...)
  2022-03-29 23:46 ` [PATCH V12 08/47] MdePkg: Add helper functions for Tdx guest in BaseIoLibIntrinsic Min Xu
@ 2022-03-29 23:46 ` Min Xu
  2022-03-29 23:46 ` [PATCH V12 10/47] MdePkg: Support IoFifo " Min Xu
                   ` (31 subsequent siblings)
  40 siblings, 0 replies; 53+ messages in thread
From: Min Xu @ 2022-03-29 23:46 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Michael D Kinney, Liming Gao, Zhiguang Liu, Brijesh Singh,
	Erdem Aktas, James Bottomley, Jiewen Yao, Tom Lendacky,
	Gerd Hoffmann

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@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Zhiguang Liu <zhiguang.liu@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Liming Gao <gaoliming@byosoft.com.cn>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 .../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


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH V12 10/47] MdePkg: Support IoFifo for Tdx guest in BaseIoLibIntrinsic
  2022-03-29 23:45 [PATCH V12 00/47] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (8 preceding siblings ...)
  2022-03-29 23:46 ` [PATCH V12 09/47] MdePkg: Support mmio " Min Xu
@ 2022-03-29 23:46 ` Min Xu
  2022-03-29 23:46 ` [PATCH V12 11/47] MdePkg: Support IoRead/IoWrite " Min Xu
                   ` (30 subsequent siblings)
  40 siblings, 0 replies; 53+ messages in thread
From: Min Xu @ 2022-03-29 23:46 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Michael D Kinney, Liming Gao, Zhiguang Liu, Brijesh Singh,
	Erdem Aktas, James Bottomley, Jiewen Yao, Tom Lendacky,
	Gerd Hoffmann

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@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Zhiguang Liu <zhiguang.liu@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Liming Gao <gaoliming@byosoft.com.cn>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 .../BaseIoLibIntrinsicSev.inf                 |   2 +
 MdePkg/Library/BaseIoLibIntrinsic/IoLibFifo.c | 217 ++++++++++++++++++
 MdePkg/Library/BaseIoLibIntrinsic/IoLibSev.h  | 166 ++++++++++++++
 .../BaseIoLibIntrinsic/X64/IoFifoSev.nasm     |  34 +--
 4 files changed, 402 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..9a94bc6a054c
--- /dev/null
+++ b/MdePkg/Library/BaseIoLibIntrinsic/IoLibFifo.c
@@ -0,0 +1,217 @@
+/** @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 <Uefi/UefiBaseType.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


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH V12 11/47] MdePkg: Support IoRead/IoWrite for Tdx guest in BaseIoLibIntrinsic
  2022-03-29 23:45 [PATCH V12 00/47] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (9 preceding siblings ...)
  2022-03-29 23:46 ` [PATCH V12 10/47] MdePkg: Support IoFifo " Min Xu
@ 2022-03-29 23:46 ` Min Xu
  2022-03-29 23:46 ` [PATCH V12 12/47] UefiCpuPkg: Support TDX in BaseXApicX2ApicLib Min Xu
                   ` (29 subsequent siblings)
  40 siblings, 0 replies; 53+ messages in thread
From: Min Xu @ 2022-03-29 23:46 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Michael D Kinney, Liming Gao, Zhiguang Liu, Brijesh Singh,
	Erdem Aktas, James Bottomley, Jiewen Yao, Tom Lendacky,
	Gerd Hoffmann

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@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Zhiguang Liu <zhiguang.liu@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Liming Gao <gaoliming@byosoft.com.cn>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 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


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH V12 12/47] UefiCpuPkg: Support TDX in BaseXApicX2ApicLib
  2022-03-29 23:45 [PATCH V12 00/47] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (10 preceding siblings ...)
  2022-03-29 23:46 ` [PATCH V12 11/47] MdePkg: Support IoRead/IoWrite " Min Xu
@ 2022-03-29 23:46 ` Min Xu
  2022-03-29 23:46 ` [PATCH V12 13/47] MdePkg: Add macro to check SEV / TDX guest Min Xu
                   ` (28 subsequent siblings)
  40 siblings, 0 replies; 53+ messages in thread
From: Min Xu @ 2022-03-29 23:46 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Eric Dong, Ray Ni, Rahul Kumar, Brijesh Singh,
	Erdem Aktas, James Bottomley, Jiewen Yao, Tom Lendacky,
	Gerd Hoffmann

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@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Ray Ni <ray.ni@intel.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 .../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


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH V12 13/47] MdePkg: Add macro to check SEV / TDX guest
  2022-03-29 23:45 [PATCH V12 00/47] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (11 preceding siblings ...)
  2022-03-29 23:46 ` [PATCH V12 12/47] UefiCpuPkg: Support TDX in BaseXApicX2ApicLib Min Xu
@ 2022-03-29 23:46 ` Min Xu
  2022-03-29 23:46 ` [PATCH V12 14/47] UefiCpuPkg: Enable Tdx support in MpInitLib Min Xu
                   ` (27 subsequent siblings)
  40 siblings, 0 replies; 53+ messages in thread
From: Min Xu @ 2022-03-29 23:46 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Michael Roth, Ray Ni, Rahul Kumar, Eric Dong,
	James Bottomley, Jiewen Yao, Tom Lendacky, Jordan Justen,
	Ard Biesheuvel, Erdem Aktas, Gerd Hoffmann, Michael D Kinney,
	Liming Gao, Zhiguang Liu

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@amd.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Cc: Eric Dong <eric.dong@intel.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Min Xu <min.m.xu@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Zhiguang Liu <zhiguang.liu@intel.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Liming Gao <gaoliming@byosoft.com.cn>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 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


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH V12 14/47] UefiCpuPkg: Enable Tdx support in MpInitLib
  2022-03-29 23:45 [PATCH V12 00/47] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (12 preceding siblings ...)
  2022-03-29 23:46 ` [PATCH V12 13/47] MdePkg: Add macro to check SEV / TDX guest Min Xu
@ 2022-03-29 23:46 ` Min Xu
  2022-03-30  7:53   ` [edk2-devel] " Ni, Ray
  2022-04-28 13:15   ` Lendacky, Thomas
  2022-03-29 23:46 ` [PATCH V12 15/47] OvmfPkg: Add IntelTdx.h in OvmfPkg/Include/IndustryStandard Min Xu
                   ` (26 subsequent siblings)
  40 siblings, 2 replies; 53+ messages in thread
From: Min Xu @ 2022-03-29 23:46 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Brijesh Singh, Erdem Aktas, James Bottomley, Jiewen Yao,
	Tom Lendacky, Eric Dong, Ray Ni, Rahul Kumar, Gerd Hoffmann

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. 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@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf |   3 +
 UefiCpuPkg/Library/MpInitLib/MpIntelTdx.h     |  69 ++++++++++++
 UefiCpuPkg/Library/MpInitLib/MpLib.c          |  63 ++++++++++-
 UefiCpuPkg/Library/MpInitLib/MpLibTdx.c       | 106 ++++++++++++++++++
 UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c   |  69 ++++++++++++
 UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf |   3 +
 6 files changed, 308 insertions(+), 5 deletions(-)
 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/MpIntelTdx.h b/UefiCpuPkg/Library/MpInitLib/MpIntelTdx.h
new file mode 100644
index 000000000000..8a26f6c19fc4
--- /dev/null
+++ b/UefiCpuPkg/Library/MpInitLib/MpIntelTdx.h
@@ -0,0 +1,69 @@
+/** @file
+  CPU MP Initialize Library header file for Td guest.
+
+  Copyright (c) 2020 - 2022, 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
+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
+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..91c7afaeb2ad 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;
 
@@ -2167,6 +2177,10 @@ SwitchBSPWorker (
   BOOLEAN                      OldInterruptState;
   BOOLEAN                      OldTimerInterruptState;
 
+  if (CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr))) {
+    return EFI_UNSUPPORTED;
+  }
+
   //
   // Save and Disable Local APIC timer interrupt
   //
@@ -2307,6 +2321,10 @@ EnableDisableApWorker (
   CPU_MP_DATA  *CpuMpData;
   UINTN        CallerNumber;
 
+  if (CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr))) {
+    return EFI_UNSUPPORTED;
+  }
+
   CpuMpData = GetCpuMpData ();
 
   //
@@ -2367,6 +2385,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,12 +2428,16 @@ MpInitLibGetNumberOfProcessors (
   UINTN        EnabledProcessorNumber;
   UINTN        Index;
 
-  CpuMpData = GetCpuMpData ();
-
   if ((NumberOfProcessors == NULL) && (NumberOfEnabledProcessors == NULL)) {
     return EFI_INVALID_PARAMETER;
   }
 
+  if (CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr))) {
+    return TdxMpInitLibGetNumberOfProcessors (NumberOfProcessors, NumberOfEnabledProcessors);
+  }
+
+  CpuMpData = GetCpuMpData ();
+
   //
   // Check whether caller processor is BSP
   //
@@ -2490,13 +2517,16 @@ StartupAllCPUsWorker (
   BOOLEAN      HasEnabledAp;
   CPU_STATE    ApState;
 
-  CpuMpData = GetCpuMpData ();
-
   if (FailedCpuList != NULL) {
     *FailedCpuList = NULL;
   }
 
-  if ((CpuMpData->CpuCount == 1) && ExcludeBsp) {
+  Status = MpInitLibGetNumberOfProcessors (&ProcessorCount, NULL);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  if ((ProcessorCount == 1) && ExcludeBsp) {
     return EFI_NOT_STARTED;
   }
 
@@ -2504,6 +2534,22 @@ StartupAllCPUsWorker (
     return EFI_INVALID_PARAMETER;
   }
 
+  if (CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr))) {
+    //
+    // For Td guest ExcludeBsp must be FALSE. Otherwise it will return in above checks.
+    //
+    ASSERT (!ExcludeBsp);
+
+    //
+    // Start BSP.
+    //
+    Procedure (ProcedureArgument);
+
+    return EFI_SUCCESS;
+  }
+
+  CpuMpData = GetCpuMpData ();
+
   //
   // Check whether caller processor is BSP
   //
@@ -2643,6 +2689,13 @@ StartupThisAPWorker (
   CPU_AP_DATA  *CpuData;
   UINTN        CallerNumber;
 
+  //
+  // In Td guest, startup of AP is not supported in current stage.
+  //
+  if (CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr))) {
+    return EFI_UNSUPPORTED;
+  }
+
   CpuMpData = GetCpuMpData ();
 
   if (Finished != NULL) {
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLibTdx.c b/UefiCpuPkg/Library/MpInitLib/MpLibTdx.c
new file mode 100644
index 000000000000..fdb58fba9323
--- /dev/null
+++ b/UefiCpuPkg/Library/MpInitLib/MpLibTdx.c
@@ -0,0 +1,106 @@
+/** @file
+  CPU MP Initialize Library common functions for Td guest.
+
+  Copyright (c) 2020 - 2022, Intel Corporation. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MpLib.h"
+#include "MpIntelTdx.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.
+
+  In current stage only the BSP is workable. So ProcessorNumber should be 0.
+
+  @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 or ProcessorNumber is not 0.
+  @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
+TdxMpInitLibGetProcessorInfo (
+  IN  UINTN                      ProcessorNumber,
+  OUT EFI_PROCESSOR_INFORMATION  *ProcessorInfoBuffer,
+  OUT EFI_HEALTH_FLAGS           *HealthData  OPTIONAL
+  )
+{
+  UINTN  OriginalProcessorNumber;
+
+  //
+  // Lower 24 bits contains the actual processor number.
+  //
+  OriginalProcessorNumber = ProcessorNumber;
+  ProcessorNumber        &= BIT24 - 1;
+
+  if ((ProcessorInfoBuffer == NULL) || (ProcessorNumber != 0)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  ProcessorInfoBuffer->ProcessorId = 0;
+  ProcessorInfoBuffer->StatusFlag  = PROCESSOR_AS_BSP_BIT | PROCESSOR_ENABLED_BIT;
+  ZeroMem (&ProcessorInfoBuffer->Location, sizeof (EFI_CPU_PHYSICAL_LOCATION));
+
+  if ((OriginalProcessorNumber & CPU_V2_EXTENDED_TOPOLOGY) != 0) {
+    ZeroMem (&ProcessorInfoBuffer->ExtendedInformation.Location2, sizeof (EFI_CPU_PHYSICAL_LOCATION2));
+  }
+
+  if (HealthData != NULL) {
+    HealthData->Uint32 = 0;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  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
+TdxMpInitLibGetNumberOfProcessors (
+  OUT UINTN *NumberOfProcessors, OPTIONAL
+  OUT UINTN *NumberOfEnabledProcessors OPTIONAL
+  )
+{
+  ASSERT (NumberOfProcessors != NULL || NumberOfEnabledProcessors != NULL);
+  //
+  // In current stage only the BSP is workable. So NumberOfProcessors
+  // & NumberOfEnableddProcessors are both 1.
+  //
+  if (NumberOfProcessors != NULL) {
+    *NumberOfProcessors = 1;
+  }
+
+  if (NumberOfEnabledProcessors != NULL) {
+    *NumberOfEnabledProcessors = 1;
+  }
+
+  return EFI_SUCCESS;
+}
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c b/UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c
new file mode 100644
index 000000000000..b5aaf6df283f
--- /dev/null
+++ b/UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c
@@ -0,0 +1,69 @@
+/** @file
+  CPU MP Initialize Library common functions (NULL instance) for Td guest.
+
+  Copyright (c) 2020 - 2022, Intel Corporation. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MpLib.h"
+#include "MpIntelTdx.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
+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
+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


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH V12 15/47] OvmfPkg: Add IntelTdx.h in OvmfPkg/Include/IndustryStandard
  2022-03-29 23:45 [PATCH V12 00/47] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (13 preceding siblings ...)
  2022-03-29 23:46 ` [PATCH V12 14/47] UefiCpuPkg: Enable Tdx support in MpInitLib Min Xu
@ 2022-03-29 23:46 ` Min Xu
  2022-03-29 23:46 ` [PATCH V12 16/47] OvmfPkg: Add TdxMailboxLib Min Xu
                   ` (25 subsequent siblings)
  40 siblings, 0 replies; 53+ messages in thread
From: Min Xu @ 2022-03-29 23:46 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky, Gerd Hoffmann

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@kernel.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 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


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH V12 16/47] OvmfPkg: Add TdxMailboxLib
  2022-03-29 23:45 [PATCH V12 00/47] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (14 preceding siblings ...)
  2022-03-29 23:46 ` [PATCH V12 15/47] OvmfPkg: Add IntelTdx.h in OvmfPkg/Include/IndustryStandard Min Xu
@ 2022-03-29 23:46 ` Min Xu
  2022-03-29 23:46 ` [PATCH V12 17/47] OvmfPkg: Create initial version of PlatformInitLib Min Xu
                   ` (24 subsequent siblings)
  40 siblings, 0 replies; 53+ messages in thread
From: Min Xu @ 2022-03-29 23:46 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky, Gerd Hoffmann

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@kernel.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/Include/Library/TdxMailboxLib.h       |  76 ++++++++++
 OvmfPkg/Library/TdxMailboxLib/TdxMailbox.c    | 141 ++++++++++++++++++
 .../Library/TdxMailboxLib/TdxMailboxLib.inf   |  52 +++++++
 .../Library/TdxMailboxLib/TdxMailboxNull.c    |  85 +++++++++++
 OvmfPkg/OvmfPkg.dec                           |   4 +
 5 files changed, 358 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..74cb55611fe3
--- /dev/null
+++ b/OvmfPkg/Library/TdxMailboxLib/TdxMailbox.c
@@ -0,0 +1,141 @@
+/** @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 <Uefi/UefiBaseType.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


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH V12 17/47] OvmfPkg: Create initial version of PlatformInitLib
  2022-03-29 23:45 [PATCH V12 00/47] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (15 preceding siblings ...)
  2022-03-29 23:46 ` [PATCH V12 16/47] OvmfPkg: Add TdxMailboxLib Min Xu
@ 2022-03-29 23:46 ` Min Xu
  2022-03-29 23:46 ` [PATCH V12 18/47] OvmfPkg/PlatformInitLib: Add hob functions Min Xu
                   ` (23 subsequent siblings)
  40 siblings, 0 replies; 53+ messages in thread
From: Min Xu @ 2022-03-29 23:46 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky, Gerd Hoffmann

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3863

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.

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

Considering this PlatformInitLib will be used in SEC phase, global
variables and dynamic PCDs are avoided. We use PlatformInfoHob
to exchange information between functions.

EFI_HOB_PLATFORM_INFO is the data struct which contains the platform
information, such as HostBridgeDevId, BootMode, S3Supported,
SmmSmramRequire, etc.

After PlatformInitLib is created, OvmfPkg/PlatformPei is refactored
with this library.

Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/AmdSev/AmdSevX64.dsc                  |  1 +
 OvmfPkg/CloudHv/CloudHvX64.dsc                |  1 +
 OvmfPkg/Include/Library/PlatformInitLib.h     | 99 +++++++++++++++++++
 .../PlatformInitLib}/Cmos.c                   | 32 +++++-
 .../PlatformInitLib/PlatformInitLib.inf       | 36 +++++++
 OvmfPkg/Microvm/MicrovmX64.dsc                |  1 +
 OvmfPkg/OvmfPkg.dec                           |  4 +
 OvmfPkg/OvmfPkgIa32.dsc                       |  1 +
 OvmfPkg/OvmfPkgIa32X64.dsc                    |  1 +
 OvmfPkg/OvmfPkgX64.dsc                        |  1 +
 OvmfPkg/PlatformPei/Cmos.h                    | 48 ---------
 OvmfPkg/PlatformPei/MemDetect.c               |  8 +-
 OvmfPkg/PlatformPei/Platform.c                | 29 +-----
 OvmfPkg/PlatformPei/PlatformPei.inf           |  3 +-
 14 files changed, 183 insertions(+), 82 deletions(-)
 create mode 100644 OvmfPkg/Include/Library/PlatformInitLib.h
 rename OvmfPkg/{PlatformPei => Library/PlatformInitLib}/Cmos.c (61%)
 create mode 100644 OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
 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 b4d855d80f56..b8a82380202c 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/Include/Library/PlatformInitLib.h b/OvmfPkg/Include/Library/PlatformInitLib.h
new file mode 100644
index 000000000000..2ebac5ccb013
--- /dev/null
+++ b/OvmfPkg/Include/Library/PlatformInitLib.h
@@ -0,0 +1,99 @@
+/** @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               HostBridgeDevId;
+
+  UINT64               PcdConfidentialComputingGuestAttr;
+  BOOLEAN              SevEsIsEnabled;
+
+  UINT32               BootMode;
+  BOOLEAN              S3Supported;
+
+  BOOLEAN              SmmSmramRequire;
+  BOOLEAN              Q35SmramAtDefaultSmbase;
+  UINT16               Q35TsegMbytes;
+
+  UINT64               FirstNonAddress;
+  UINT8                PhysMemAddressWidth;
+  UINT32               Uc32Base;
+  UINT32               Uc32Size;
+
+  BOOLEAN              PcdSetNxForStack;
+  UINT64               PcdTdxSharedBitMask;
+
+  UINT64               PcdPciMmio64Base;
+  UINT64               PcdPciMmio64Size;
+  UINT32               PcdPciMmio32Base;
+  UINT32               PcdPciMmio32Size;
+  UINT64               PcdPciIoBase;
+  UINT64               PcdPciIoSize;
+
+  UINT64               PcdEmuVariableNvStoreReserved;
+  UINT32               PcdCpuBootLogicalProcessorNumber;
+  UINT32               PcdCpuMaxLogicalProcessorNumber;
+  UINT32               DefaultMaxCpuNumber;
+
+  UINT32               S3AcpiReservedMemoryBase;
+  UINT32               S3AcpiReservedMemorySize;
+} 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/PlatformPei/Cmos.c b/OvmfPkg/Library/PlatformInitLib/Cmos.c
similarity index 61%
rename from OvmfPkg/PlatformPei/Cmos.c
rename to OvmfPkg/Library/PlatformInitLib/Cmos.c
index a01b3866bee4..977aa97aea8c 100644
--- a/OvmfPkg/PlatformPei/Cmos.c
+++ b/OvmfPkg/Library/PlatformInitLib/Cmos.c
@@ -6,7 +6,8 @@
 
 **/
 
-#include "Cmos.h"
+#include <Library/PlatformInitLib.h>
+#include <Library/DebugLib.h>
 #include "Library/IoLib.h"
 
 /**
@@ -22,7 +23,7 @@
 **/
 UINT8
 EFIAPI
-CmosRead8 (
+PlatformCmosRead8 (
   IN      UINTN  Index
   )
 {
@@ -44,7 +45,7 @@ CmosRead8 (
 **/
 UINT8
 EFIAPI
-CmosWrite8 (
+PlatformCmosWrite8 (
   IN      UINTN  Index,
   IN      UINT8  Value
   )
@@ -53,3 +54,28 @@ CmosWrite8 (
   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/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/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}}
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.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 8ecc8257f9b9..9c5bf240e3ba 100644
--- a/OvmfPkg/PlatformPei/MemDetect.c
+++ b/OvmfPkg/PlatformPei/MemDetect.c
@@ -37,9 +37,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;
 
@@ -412,8 +412,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);
 }
@@ -436,7 +436,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 212aa7b04751..f6bfc09c2dd5 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


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH V12 18/47] OvmfPkg/PlatformInitLib: Add hob functions
  2022-03-29 23:45 [PATCH V12 00/47] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (16 preceding siblings ...)
  2022-03-29 23:46 ` [PATCH V12 17/47] OvmfPkg: Create initial version of PlatformInitLib Min Xu
@ 2022-03-29 23:46 ` Min Xu
  2022-03-29 23:46 ` [PATCH V12 19/47] OvmfPkg/PlatformPei: Move global variables to PlatformInfoHob Min Xu
                   ` (22 subsequent siblings)
  40 siblings, 0 replies; 53+ messages in thread
From: Min Xu @ 2022-03-29 23:46 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky, Gerd Hoffmann

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3863

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

After above hob functions are introduced in PlatformInitLib,
OvmfPkg/PlatformPei is refactored with this library.

Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/Include/Library/PlatformInitLib.h     |  36 ++++++
 OvmfPkg/Library/PlatformInitLib/Platform.c    | 106 ++++++++++++++++++
 .../PlatformInitLib/PlatformInitLib.inf       |   2 +
 OvmfPkg/PlatformPei/MemDetect.c               |  20 ++--
 OvmfPkg/PlatformPei/Platform.c                | 101 ++---------------
 OvmfPkg/PlatformPei/Platform.h                |  31 -----
 6 files changed, 165 insertions(+), 131 deletions(-)
 create mode 100644 OvmfPkg/Library/PlatformInitLib/Platform.c

diff --git a/OvmfPkg/Include/Library/PlatformInitLib.h b/OvmfPkg/Include/Library/PlatformInitLib.h
index 2ebac5ccb013..9b99d4c1f514 100644
--- a/OvmfPkg/Include/Library/PlatformInitLib.h
+++ b/OvmfPkg/Include/Library/PlatformInitLib.h
@@ -96,4 +96,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@motorola.com>
+
+  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
diff --git a/OvmfPkg/PlatformPei/MemDetect.c b/OvmfPkg/PlatformPei/MemDetect.c
index 9c5bf240e3ba..e5e105f377dd 100644
--- a/OvmfPkg/PlatformPei/MemDetect.c
+++ b/OvmfPkg/PlatformPei/MemDetect.c
@@ -275,10 +275,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
@@ -816,8 +816,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 */
@@ -826,12 +826,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);
   }
 }
 
@@ -889,14 +889,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);
     }
 
     //
@@ -908,7 +908,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


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH V12 19/47] OvmfPkg/PlatformPei: Move global variables to PlatformInfoHob
  2022-03-29 23:45 [PATCH V12 00/47] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (17 preceding siblings ...)
  2022-03-29 23:46 ` [PATCH V12 18/47] OvmfPkg/PlatformInitLib: Add hob functions Min Xu
@ 2022-03-29 23:46 ` Min Xu
  2022-03-29 23:46 ` [PATCH V12 20/47] OvmfPkg/PlatformPei: Refactor MiscInitialization Min Xu
                   ` (21 subsequent siblings)
  40 siblings, 0 replies; 53+ messages in thread
From: Min Xu @ 2022-03-29 23:46 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky, Gerd Hoffmann,
	Sebastien Boeuf

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3863

The intention of PlatformInitLib is to extract the common function used
in OvmfPkg/PlatformPei. This lib will be used not only in PEI phase but
also in SEC phase. SEC phase cannot use global variables between
different functions. So PlatformInfoHob is created to hold the
informations shared between functions. For example, HostBridgeDevId
corespond to mHostBridgeDevId in PlatformPei.

In this patch we will first move below global variables to
PlatformInfoHob.
 - mBootMode
 - mS3Supported
 - mPhysMemAddressWidth
 - mMaxCpuCount
 - mHostBridgeDevId
 - mQ35SmramAtDefaultSmbase
 - mQemuUc32Base
 - mS3AcpiReservedMemorySize
 - mS3AcpiReservedMemoryBase

PlatformInfoHob also holds other information, for example,
PciIoBase / PciIoSize. This is because in SEC phase, PcdSetxxx
doesn't work. So we will restruct the functions which set PCDs
into two, one for PlatformInfoLib, one for PlatformPei.

So in this patch we first move global variables and PCDs to
PlatformInfoHob. All the changes are in OvmfPkg/PlatformPei.

Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Sebastien Boeuf <sebastien.boeuf@intel.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/PlatformPei/AmdSev.c      |   8 +-
 OvmfPkg/PlatformPei/Fv.c          |   4 +-
 OvmfPkg/PlatformPei/MemDetect.c   | 210 +++++++++++++++---------------
 OvmfPkg/PlatformPei/MemTypeInfo.c |   2 +-
 OvmfPkg/PlatformPei/Platform.c    | 109 ++++++++--------
 OvmfPkg/PlatformPei/Platform.h    |  45 ++++---
 6 files changed, 196 insertions(+), 182 deletions(-)

diff --git a/OvmfPkg/PlatformPei/AmdSev.c b/OvmfPkg/PlatformPei/AmdSev.c
index fb7e21ec140f..385562b44c4e 100644
--- a/OvmfPkg/PlatformPei/AmdSev.c
+++ b/OvmfPkg/PlatformPei/AmdSev.c
@@ -228,7 +228,7 @@ AmdSevEsInitialize (
   //   Since the pages must survive across the UEFI to OS transition
   //   make them reserved.
   //
-  GhcbPageCount = mMaxCpuCount * 2;
+  GhcbPageCount = mPlatformInfoHob.PcdCpuMaxLogicalProcessorNumber * 2;
   GhcbBase      = AllocateReservedPages (GhcbPageCount);
   ASSERT (GhcbBase != NULL);
 
@@ -266,7 +266,7 @@ AmdSevEsInitialize (
   // Allocate #VC recursion backup pages. The number of backup pages needed is
   // one less than the maximum VC count.
   //
-  GhcbBackupPageCount = mMaxCpuCount * (VMGEXIT_MAXIMUM_VC_COUNT - 1);
+  GhcbBackupPageCount = mPlatformInfoHob.PcdCpuMaxLogicalProcessorNumber * (VMGEXIT_MAXIMUM_VC_COUNT - 1);
   GhcbBackupBase      = AllocatePages (GhcbBackupPageCount);
   ASSERT (GhcbBackupBase != NULL);
 
@@ -367,7 +367,7 @@ AmdSevInitialize (
   // until after re-encryption, in order to prevent an information leak to the
   // hypervisor.
   //
-  if (FeaturePcdGet (PcdSmmSmramRequire) && (mBootMode != BOOT_ON_S3_RESUME)) {
+  if (mPlatformInfoHob.SmmSmramRequire && (mPlatformInfoHob.BootMode != BOOT_ON_S3_RESUME)) {
     RETURN_STATUS  LocateMapStatus;
     UINTN          MapPagesBase;
     UINTN          MapPagesCount;
@@ -378,7 +378,7 @@ AmdSevInitialize (
                         );
     ASSERT_RETURN_ERROR (LocateMapStatus);
 
-    if (mQ35SmramAtDefaultSmbase) {
+    if (mPlatformInfoHob.Q35SmramAtDefaultSmbase) {
       //
       // The initial SMRAM Save State Map has been covered as part of a larger
       // reserved memory allocation in InitializeRamRegions().
diff --git a/OvmfPkg/PlatformPei/Fv.c b/OvmfPkg/PlatformPei/Fv.c
index 8cd8cacc5913..e40c5922206b 100644
--- a/OvmfPkg/PlatformPei/Fv.c
+++ b/OvmfPkg/PlatformPei/Fv.c
@@ -37,7 +37,7 @@ PeiFvInitialization (
   BuildMemoryAllocationHob (
     PcdGet32 (PcdOvmfPeiMemFvBase),
     PcdGet32 (PcdOvmfPeiMemFvSize),
-    mS3Supported ? EfiACPIMemoryNVS : EfiBootServicesData
+    mPlatformInfoHob.S3Supported ? EfiACPIMemoryNVS : EfiBootServicesData
     );
 
   //
@@ -45,7 +45,7 @@ PeiFvInitialization (
   //
   BuildFvHob (PcdGet32 (PcdOvmfDxeMemFvBase), PcdGet32 (PcdOvmfDxeMemFvSize));
 
-  SecureS3Needed = mS3Supported && FeaturePcdGet (PcdSmmSmramRequire);
+  SecureS3Needed = mPlatformInfoHob.S3Supported && mPlatformInfoHob.SmmSmramRequire;
 
   //
   // Create a memory allocation HOB for the DXE FV.
diff --git a/OvmfPkg/PlatformPei/MemDetect.c b/OvmfPkg/PlatformPei/MemDetect.c
index e5e105f377dd..f3819b997b3b 100644
--- a/OvmfPkg/PlatformPei/MemDetect.c
+++ b/OvmfPkg/PlatformPei/MemDetect.c
@@ -37,21 +37,9 @@ Module Name:
 #include <Library/MtrrLib.h>
 #include <Library/QemuFwCfgLib.h>
 #include <Library/QemuFwCfgSimpleParserLib.h>
-#include <Library/PlatformInitLib.h>
 
 #include "Platform.h"
 
-UINT8  mPhysMemAddressWidth;
-
-STATIC UINT32  mS3AcpiReservedMemoryBase;
-STATIC UINT32  mS3AcpiReservedMemorySize;
-
-STATIC UINT16  mQ35TsegMbytes;
-
-BOOLEAN  mQ35SmramAtDefaultSmbase;
-
-UINT32  mQemuUc32Base;
-
 VOID
 Q35TsegMbytesInitialization (
   VOID
@@ -60,7 +48,7 @@ Q35TsegMbytesInitialization (
   UINT16         ExtendedTsegMbytes;
   RETURN_STATUS  PcdStatus;
 
-  ASSERT (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID);
+  ASSERT (mPlatformInfoHob.HostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID);
 
   //
   // Check if QEMU offers an extended TSEG.
@@ -81,7 +69,7 @@ Q35TsegMbytesInitialization (
   PciWrite16 (DRAMC_REGISTER_Q35 (MCH_EXT_TSEG_MB), MCH_EXT_TSEG_MB_QUERY);
   ExtendedTsegMbytes = PciRead16 (DRAMC_REGISTER_Q35 (MCH_EXT_TSEG_MB));
   if (ExtendedTsegMbytes == MCH_EXT_TSEG_MB_QUERY) {
-    mQ35TsegMbytes = PcdGet16 (PcdQ35TsegMbytes);
+    mPlatformInfoHob.Q35TsegMbytes = PcdGet16 (PcdQ35TsegMbytes);
     return;
   }
 
@@ -93,7 +81,7 @@ Q35TsegMbytesInitialization (
     ));
   PcdStatus = PcdSet16S (PcdQ35TsegMbytes, ExtendedTsegMbytes);
   ASSERT_RETURN_ERROR (PcdStatus);
-  mQ35TsegMbytes = ExtendedTsegMbytes;
+  mPlatformInfoHob.Q35TsegMbytes = ExtendedTsegMbytes;
 }
 
 VOID
@@ -103,9 +91,9 @@ Q35SmramAtDefaultSmbaseInitialization (
 {
   RETURN_STATUS  PcdStatus;
 
-  ASSERT (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID);
+  ASSERT (mPlatformInfoHob.HostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID);
 
-  mQ35SmramAtDefaultSmbase = FALSE;
+  mPlatformInfoHob.Q35SmramAtDefaultSmbase = FALSE;
   if (FeaturePcdGet (PcdCsmEnable)) {
     DEBUG ((
       DEBUG_INFO,
@@ -118,37 +106,36 @@ Q35SmramAtDefaultSmbaseInitialization (
 
     CtlReg = DRAMC_REGISTER_Q35 (MCH_DEFAULT_SMBASE_CTL);
     PciWrite8 (CtlReg, MCH_DEFAULT_SMBASE_QUERY);
-    CtlRegVal                = PciRead8 (CtlReg);
-    mQ35SmramAtDefaultSmbase = (BOOLEAN)(CtlRegVal ==
-                                         MCH_DEFAULT_SMBASE_IN_RAM);
+    CtlRegVal                                = PciRead8 (CtlReg);
+    mPlatformInfoHob.Q35SmramAtDefaultSmbase = (BOOLEAN)(CtlRegVal ==
+                                                         MCH_DEFAULT_SMBASE_IN_RAM);
     DEBUG ((
       DEBUG_INFO,
       "%a: SMRAM at default SMBASE %a\n",
       __FUNCTION__,
-      mQ35SmramAtDefaultSmbase ? "found" : "not found"
+      mPlatformInfoHob.Q35SmramAtDefaultSmbase ? "found" : "not found"
       ));
   }
 
   PcdStatus = PcdSetBoolS (
                 PcdQ35SmramAtDefaultSmbase,
-                mQ35SmramAtDefaultSmbase
+                mPlatformInfoHob.Q35SmramAtDefaultSmbase
                 );
   ASSERT_RETURN_ERROR (PcdStatus);
 }
 
 VOID
 QemuUc32BaseInitialization (
-  VOID
+  IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
   )
 {
   UINT32  LowerMemorySize;
-  UINT32  Uc32Size;
 
-  if (mHostBridgeDevId == 0xffff /* microvm */) {
+  if (PlatformInfoHob->HostBridgeDevId == 0xffff /* microvm */) {
     return;
   }
 
-  if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
+  if (PlatformInfoHob->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
@@ -157,40 +144,40 @@ QemuUc32BaseInitialization (
     // variable MTRRs (preferably 1 or 2).
     //
     ASSERT (FixedPcdGet64 (PcdPciExpressBaseAddress) <= MAX_UINT32);
-    mQemuUc32Base = (UINT32)FixedPcdGet64 (PcdPciExpressBaseAddress);
+    PlatformInfoHob->Uc32Base = (UINT32)FixedPcdGet64 (PcdPciExpressBaseAddress);
     return;
   }
 
-  if (mHostBridgeDevId == CLOUDHV_DEVICE_ID) {
-    Uc32Size      = CLOUDHV_MMIO_HOLE_SIZE;
-    mQemuUc32Base = CLOUDHV_MMIO_HOLE_ADDRESS;
+  if (PlatformInfoHob->HostBridgeDevId == CLOUDHV_DEVICE_ID) {
+    PlatformInfoHob->Uc32Size = CLOUDHV_MMIO_HOLE_SIZE;
+    PlatformInfoHob->Uc32Base = CLOUDHV_MMIO_HOLE_ADDRESS;
     return;
   }
 
-  ASSERT (mHostBridgeDevId == INTEL_82441_DEVICE_ID);
+  ASSERT (PlatformInfoHob->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.
   //
-  LowerMemorySize = GetSystemMemorySizeBelow4gb ();
-  Uc32Size        = GetPowerOfTwo32 ((UINT32)(SIZE_4GB - LowerMemorySize));
-  mQemuUc32Base   = (UINT32)(SIZE_4GB - Uc32Size);
+  LowerMemorySize           = GetSystemMemorySizeBelow4gb (PlatformInfoHob);
+  PlatformInfoHob->Uc32Size = GetPowerOfTwo32 ((UINT32)(SIZE_4GB - LowerMemorySize));
+  PlatformInfoHob->Uc32Base = (UINT32)(SIZE_4GB - PlatformInfoHob->Uc32Size);
   //
   // Assuming that LowerMemorySize is at least 1 byte, Uc32Size is at most 2GB.
   // Therefore mQemuUc32Base is at least 2GB.
   //
-  ASSERT (mQemuUc32Base >= BASE_2GB);
+  ASSERT (PlatformInfoHob->Uc32Base >= BASE_2GB);
 
-  if (mQemuUc32Base != LowerMemorySize) {
+  if (PlatformInfoHob->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,
-      mQemuUc32Base,
-      Uc32Size
+      PlatformInfoHob->Uc32Base,
+      PlatformInfoHob->Uc32Size
       ));
   }
 }
@@ -385,7 +372,7 @@ GetHighestSystemMemoryAddressFromPvhMemmap (
 
 UINT32
 GetSystemMemorySizeBelow4gb (
-  VOID
+  IN EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
   )
 {
   EFI_STATUS  Status;
@@ -393,7 +380,7 @@ GetSystemMemorySizeBelow4gb (
   UINT8       Cmos0x34;
   UINT8       Cmos0x35;
 
-  if (mHostBridgeDevId == CLOUDHV_DEVICE_ID) {
+  if (PlatformInfoHob->HostBridgeDevId == CLOUDHV_DEVICE_ID) {
     // Get the information from PVH memmap
     return (UINT32)GetHighestSystemMemoryAddressFromPvhMemmap (TRUE);
   }
@@ -448,11 +435,10 @@ GetSystemMemorySizeAbove4gb (
 STATIC
 UINT64
 GetFirstNonAddress (
-  VOID
+  IN OUT  EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
   )
 {
   UINT64                FirstNonAddress;
-  UINT64                Pci64Base, Pci64Size;
   UINT32                FwCfgPciMmio64Mb;
   EFI_STATUS            Status;
   FIRMWARE_CONFIG_ITEM  FwCfgItem;
@@ -493,7 +479,7 @@ GetFirstNonAddress (
   // 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);
+  PlatformInfoHob->PcdPciMmio64Size = PcdGet64 (PcdPciMmio64Size);
 
   //
   // See if the user specified the number of megabytes for the 64-bit PCI host
@@ -513,7 +499,7 @@ GetFirstNonAddress (
       break;
     case EFI_SUCCESS:
       if (FwCfgPciMmio64Mb <= 0x1000000) {
-        Pci64Size = LShiftU64 (FwCfgPciMmio64Mb, 20);
+        PlatformInfoHob->PcdPciMmio64Size = LShiftU64 (FwCfgPciMmio64Mb, 20);
         break;
       }
 
@@ -529,8 +515,8 @@ GetFirstNonAddress (
       break;
   }
 
-  if (Pci64Size == 0) {
-    if (mBootMode != BOOT_ON_S3_RESUME) {
+  if (PlatformInfoHob->PcdPciMmio64Size == 0) {
+    if (PlatformInfoHob->BootMode != BOOT_ON_S3_RESUME) {
       DEBUG ((
         DEBUG_INFO,
         "%a: disabling 64-bit PCI host aperture\n",
@@ -577,8 +563,8 @@ GetFirstNonAddress (
   // 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);
+  PlatformInfoHob->PcdPciMmio64Base = ALIGN_VALUE (FirstNonAddress, (UINT64)SIZE_1GB);
+  PlatformInfoHob->PcdPciMmio64Size = ALIGN_VALUE (PlatformInfoHob->PcdPciMmio64Size, (UINT64)SIZE_1GB);
 
   //
   // The 64-bit PCI host aperture should also be "naturally" aligned. The
@@ -586,32 +572,32 @@ GetFirstNonAddress (
   // 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));
+  PlatformInfoHob->PcdPciMmio64Base = ALIGN_VALUE (PlatformInfoHob->PcdPciMmio64Base, GetPowerOfTwo64 (PlatformInfoHob->PcdPciMmio64Size));
 
-  if (mBootMode != BOOT_ON_S3_RESUME) {
+  if (PlatformInfoHob->BootMode != 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);
+    PcdStatus = PcdSet64S (PcdPciMmio64Base, PlatformInfoHob->PcdPciMmio64Base);
     ASSERT_RETURN_ERROR (PcdStatus);
-    PcdStatus = PcdSet64S (PcdPciMmio64Size, Pci64Size);
+    PcdStatus = PcdSet64S (PcdPciMmio64Size, PlatformInfoHob->PcdPciMmio64Size);
     ASSERT_RETURN_ERROR (PcdStatus);
 
     DEBUG ((
       DEBUG_INFO,
       "%a: Pci64Base=0x%Lx Pci64Size=0x%Lx\n",
       __FUNCTION__,
-      Pci64Base,
-      Pci64Size
+      PlatformInfoHob->PcdPciMmio64Base,
+      PlatformInfoHob->PcdPciMmio64Size
       ));
   }
 
   //
   // The useful address space ends with the 64-bit PCI host aperture.
   //
-  FirstNonAddress = Pci64Base + Pci64Size;
+  FirstNonAddress = PlatformInfoHob->PcdPciMmio64Base + PlatformInfoHob->PcdPciMmio64Size;
   return FirstNonAddress;
 }
 
@@ -620,10 +606,11 @@ GetFirstNonAddress (
 **/
 VOID
 AddressWidthInitialization (
-  VOID
+  IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
   )
 {
   UINT64  FirstNonAddress;
+  UINT8   PhysMemAddressWidth;
 
   //
   // As guest-physical memory size grows, the permanent PEI RAM requirements
@@ -631,15 +618,15 @@ AddressWidthInitialization (
   // 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);
+  FirstNonAddress     = GetFirstNonAddress (PlatformInfoHob);
+  PhysMemAddressWidth = (UINT8)HighBitSet64 (FirstNonAddress);
 
   //
   // If FirstNonAddress is not an integral power of two, then we need an
   // additional bit.
   //
   if ((FirstNonAddress & (FirstNonAddress - 1)) != 0) {
-    ++mPhysMemAddressWidth;
+    ++PhysMemAddressWidth;
   }
 
   //
@@ -648,11 +635,14 @@ AddressWidthInitialization (
   // 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;
+  if (PhysMemAddressWidth <= 36) {
+    PhysMemAddressWidth = 36;
   }
 
-  ASSERT (mPhysMemAddressWidth <= 48);
+  ASSERT (PhysMemAddressWidth <= 48);
+
+  PlatformInfoHob->FirstNonAddress     = FirstNonAddress;
+  PlatformInfoHob->PhysMemAddressWidth = PhysMemAddressWidth;
 }
 
 /**
@@ -698,12 +688,12 @@ GetPeiMemoryCap (
     }
   }
 
-  if (mPhysMemAddressWidth <= 39) {
+  if (mPlatformInfoHob.PhysMemAddressWidth <= 39) {
     Pml4Entries = 1;
-    PdpEntries  = 1 << (mPhysMemAddressWidth - 30);
+    PdpEntries  = 1 << (mPlatformInfoHob.PhysMemAddressWidth - 30);
     ASSERT (PdpEntries <= 0x200);
   } else {
-    Pml4Entries = 1 << (mPhysMemAddressWidth - 39);
+    Pml4Entries = 1 << (mPlatformInfoHob.PhysMemAddressWidth - 39);
     ASSERT (Pml4Entries <= 0x200);
     PdpEntries = 512;
   }
@@ -736,38 +726,46 @@ PublishPeiMemory (
   UINT64                MemorySize;
   UINT32                LowerMemorySize;
   UINT32                PeiMemoryCap;
+  UINT32                S3AcpiReservedMemoryBase;
+  UINT32                S3AcpiReservedMemorySize;
 
-  LowerMemorySize = GetSystemMemorySizeBelow4gb ();
-  if (FeaturePcdGet (PcdSmmSmramRequire)) {
+  LowerMemorySize = GetSystemMemorySizeBelow4gb (&mPlatformInfoHob);
+  if (mPlatformInfoHob.SmmSmramRequire) {
     //
     // TSEG is chipped from the end of low RAM
     //
-    LowerMemorySize -= mQ35TsegMbytes * SIZE_1MB;
+    LowerMemorySize -= mPlatformInfoHob.Q35TsegMbytes * SIZE_1MB;
   }
 
+  S3AcpiReservedMemoryBase = 0;
+  S3AcpiReservedMemorySize = 0;
+
   //
   // If S3 is supported, then the S3 permanent PEI memory is placed next,
   // downwards. Its size is primarily dictated by CpuMpPei. The formula below
   // is an approximation.
   //
-  if (mS3Supported) {
-    mS3AcpiReservedMemorySize = SIZE_512KB +
-                                mMaxCpuCount *
-                                PcdGet32 (PcdCpuApStackSize);
-    mS3AcpiReservedMemoryBase = LowerMemorySize - mS3AcpiReservedMemorySize;
-    LowerMemorySize           = mS3AcpiReservedMemoryBase;
+  if (mPlatformInfoHob.S3Supported) {
+    S3AcpiReservedMemorySize = SIZE_512KB +
+                               mPlatformInfoHob.PcdCpuMaxLogicalProcessorNumber *
+                               PcdGet32 (PcdCpuApStackSize);
+    S3AcpiReservedMemoryBase = LowerMemorySize - S3AcpiReservedMemorySize;
+    LowerMemorySize          = S3AcpiReservedMemoryBase;
   }
 
-  if (mBootMode == BOOT_ON_S3_RESUME) {
-    MemoryBase = mS3AcpiReservedMemoryBase;
-    MemorySize = mS3AcpiReservedMemorySize;
+  mPlatformInfoHob.S3AcpiReservedMemoryBase = S3AcpiReservedMemoryBase;
+  mPlatformInfoHob.S3AcpiReservedMemorySize = S3AcpiReservedMemorySize;
+
+  if (mPlatformInfoHob.BootMode == BOOT_ON_S3_RESUME) {
+    MemoryBase = S3AcpiReservedMemoryBase;
+    MemorySize = S3AcpiReservedMemorySize;
   } else {
     PeiMemoryCap = GetPeiMemoryCap ();
     DEBUG ((
       DEBUG_INFO,
       "%a: mPhysMemAddressWidth=%d PeiMemoryCap=%u KB\n",
       __FUNCTION__,
-      mPhysMemAddressWidth,
+      mPlatformInfoHob.PhysMemAddressWidth,
       PeiMemoryCap >> 10
       ));
 
@@ -781,7 +779,7 @@ PublishPeiMemory (
     // allocation HOB, and other allocations served from the permanent PEI RAM
     // shouldn't overlap with that HOB.
     //
-    MemoryBase = mS3Supported && FeaturePcdGet (PcdSmmSmramRequire) ?
+    MemoryBase = mPlatformInfoHob.S3Supported && mPlatformInfoHob.SmmSmramRequire ?
                  PcdGet32 (PcdOvmfDecompressionScratchEnd) :
                  PcdGet32 (PcdOvmfDxeMemFvBase) + PcdGet32 (PcdOvmfDxeMemFvSize);
     MemorySize = LowerMemorySize - MemoryBase;
@@ -796,7 +794,7 @@ PublishPeiMemory (
   // normal boot permanent PEI RAM. Regarding the S3 boot path, the S3
   // permanent PEI RAM is located even higher.
   //
-  if (FeaturePcdGet (PcdSmmSmramRequire) && mQ35SmramAtDefaultSmbase) {
+  if (mPlatformInfoHob.SmmSmramRequire && mPlatformInfoHob.Q35SmramAtDefaultSmbase) {
     ASSERT (SMM_DEFAULT_SMBASE + MCH_DEFAULT_SMBASE_SIZE <= MemoryBase);
   }
 
@@ -812,10 +810,10 @@ PublishPeiMemory (
 STATIC
 VOID
 QemuInitializeRamBelow1gb (
-  VOID
+  IN EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
   )
 {
-  if (FeaturePcdGet (PcdSmmSmramRequire) && mQ35SmramAtDefaultSmbase) {
+  if (PlatformInfoHob->SmmSmramRequire && PlatformInfoHob->Q35SmramAtDefaultSmbase) {
     PlatformAddMemoryRangeHob (0, SMM_DEFAULT_SMBASE);
     PlatformAddReservedMemoryBaseSizeHob (
       SMM_DEFAULT_SMBASE,
@@ -842,7 +840,7 @@ QemuInitializeRamBelow1gb (
 STATIC
 VOID
 QemuInitializeRam (
-  VOID
+  IN EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
   )
 {
   UINT64         LowerMemorySize;
@@ -855,9 +853,9 @@ QemuInitializeRam (
   //
   // Determine total memory size available
   //
-  LowerMemorySize = GetSystemMemorySizeBelow4gb ();
+  LowerMemorySize = GetSystemMemorySizeBelow4gb (PlatformInfoHob);
 
-  if (mBootMode == BOOT_ON_S3_RESUME) {
+  if (PlatformInfoHob->BootMode == BOOT_ON_S3_RESUME) {
     //
     // Create the following memory HOB as an exception on the S3 boot path.
     //
@@ -878,17 +876,17 @@ QemuInitializeRam (
     // allocation HOBs, and to honor preexistent memory allocation HOBs when
     // looking for an area to borrow.
     //
-    QemuInitializeRamBelow1gb ();
+    QemuInitializeRamBelow1gb (PlatformInfoHob);
   } else {
     //
     // Create memory HOBs
     //
-    QemuInitializeRamBelow1gb ();
+    QemuInitializeRamBelow1gb (PlatformInfoHob);
 
-    if (FeaturePcdGet (PcdSmmSmramRequire)) {
+    if (PlatformInfoHob->SmmSmramRequire) {
       UINT32  TsegSize;
 
-      TsegSize = mQ35TsegMbytes * SIZE_1MB;
+      TsegSize = PlatformInfoHob->Q35TsegMbytes * SIZE_1MB;
       PlatformAddMemoryRangeHob (BASE_1MB, LowerMemorySize - TsegSize);
       PlatformAddReservedMemoryBaseSizeHob (
         LowerMemorySize - TsegSize,
@@ -924,7 +922,7 @@ QemuInitializeRam (
   // practically any alignment, and we may not have enough variable MTRRs to
   // cover it exactly.
   //
-  if (IsMtrrSupported () && (mHostBridgeDevId != CLOUDHV_DEVICE_ID)) {
+  if (IsMtrrSupported () && (PlatformInfoHob->HostBridgeDevId != CLOUDHV_DEVICE_ID)) {
     MtrrGetAllMtrrs (&MtrrSettings);
 
     //
@@ -957,8 +955,8 @@ QemuInitializeRam (
     // MMIO aperture on i440fx, PCIEXBAR on q35) to 4GB as uncacheable.
     //
     Status = MtrrSetMemoryAttribute (
-               mQemuUc32Base,
-               SIZE_4GB - mQemuUc32Base,
+               PlatformInfoHob->Uc32Base,
+               SIZE_4GB - PlatformInfoHob->Uc32Base,
                CacheUncacheable
                );
     ASSERT_EFI_ERROR (Status);
@@ -971,20 +969,20 @@ QemuInitializeRam (
 **/
 VOID
 InitializeRamRegions (
-  VOID
+  IN EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
   )
 {
-  QemuInitializeRam ();
+  QemuInitializeRam (PlatformInfoHob);
 
   SevInitializeRam ();
 
-  if (mS3Supported && (mBootMode != BOOT_ON_S3_RESUME)) {
+  if (PlatformInfoHob->S3Supported && (PlatformInfoHob->BootMode != BOOT_ON_S3_RESUME)) {
     //
     // This is the memory range that will be used for PEI on S3 resume
     //
     BuildMemoryAllocationHob (
-      mS3AcpiReservedMemoryBase,
-      mS3AcpiReservedMemorySize,
+      PlatformInfoHob->S3AcpiReservedMemoryBase,
+      PlatformInfoHob->S3AcpiReservedMemorySize,
       EfiACPIMemoryNVS
       );
 
@@ -1021,7 +1019,7 @@ InitializeRamRegions (
       EfiACPIMemoryNVS
       );
 
-    if (MemEncryptSevEsIsEnabled ()) {
+    if (PlatformInfoHob->SevEsIsEnabled) {
       //
       // If SEV-ES is enabled, reserve the GHCB-related memory area. This
       // includes the extra page table used to break down the 2MB page
@@ -1051,8 +1049,8 @@ InitializeRamRegions (
  #endif
   }
 
-  if (mBootMode != BOOT_ON_S3_RESUME) {
-    if (!FeaturePcdGet (PcdSmmSmramRequire)) {
+  if (PlatformInfoHob->BootMode != BOOT_ON_S3_RESUME) {
+    if (!PlatformInfoHob->SmmSmramRequire) {
       //
       // Reserve the lock box storage area
       //
@@ -1070,20 +1068,20 @@ InitializeRamRegions (
       BuildMemoryAllocationHob (
         (EFI_PHYSICAL_ADDRESS)(UINTN)PcdGet32 (PcdOvmfLockBoxStorageBase),
         (UINT64)(UINTN)PcdGet32 (PcdOvmfLockBoxStorageSize),
-        mS3Supported ? EfiACPIMemoryNVS : EfiBootServicesData
+        PlatformInfoHob->S3Supported ? EfiACPIMemoryNVS : EfiBootServicesData
         );
     }
 
-    if (FeaturePcdGet (PcdSmmSmramRequire)) {
+    if (PlatformInfoHob->SmmSmramRequire) {
       UINT32  TsegSize;
 
       //
       // Make sure the TSEG area that we reported as a reserved memory resource
       // cannot be used for reserved memory allocations.
       //
-      TsegSize = mQ35TsegMbytes * SIZE_1MB;
+      TsegSize = PlatformInfoHob->Q35TsegMbytes * SIZE_1MB;
       BuildMemoryAllocationHob (
-        GetSystemMemorySizeBelow4gb () - TsegSize,
+        GetSystemMemorySizeBelow4gb (PlatformInfoHob) - TsegSize,
         TsegSize,
         EfiReservedMemoryType
         );
@@ -1091,7 +1089,7 @@ InitializeRamRegions (
       // Similarly, allocate away the (already reserved) SMRAM at the default
       // SMBASE, if it exists.
       //
-      if (mQ35SmramAtDefaultSmbase) {
+      if (PlatformInfoHob->Q35SmramAtDefaultSmbase) {
         BuildMemoryAllocationHob (
           SMM_DEFAULT_SMBASE,
           MCH_DEFAULT_SMBASE_SIZE,
@@ -1115,7 +1113,7 @@ InitializeRamRegions (
       BuildMemoryAllocationHob (
         (EFI_PHYSICAL_ADDRESS)(UINTN)FixedPcdGet32 (PcdOvmfWorkAreaBase),
         (UINT64)(UINTN)FixedPcdGet32 (PcdOvmfWorkAreaSize),
-        mS3Supported ? EfiACPIMemoryNVS : EfiBootServicesData
+        PlatformInfoHob->S3Supported ? EfiACPIMemoryNVS : EfiBootServicesData
         );
     }
 
diff --git a/OvmfPkg/PlatformPei/MemTypeInfo.c b/OvmfPkg/PlatformPei/MemTypeInfo.c
index fc5ccfaf113d..c8fcf1732687 100644
--- a/OvmfPkg/PlatformPei/MemTypeInfo.c
+++ b/OvmfPkg/PlatformPei/MemTypeInfo.c
@@ -208,7 +208,7 @@ MemTypeInfoInitialization (
 {
   EFI_STATUS  Status;
 
-  if (!FeaturePcdGet (PcdSmmSmramRequire)) {
+  if (!mPlatformInfoHob.SmmSmramRequire) {
     //
     // EFI_PEI_READ_ONLY_VARIABLE2_PPI will never be available; install
     // the default memory type information HOB right away.
diff --git a/OvmfPkg/PlatformPei/Platform.c b/OvmfPkg/PlatformPei/Platform.c
index 62480c3c40e5..80eb4cc9adcd 100644
--- a/OvmfPkg/PlatformPei/Platform.c
+++ b/OvmfPkg/PlatformPei/Platform.c
@@ -36,11 +36,13 @@
 #include <IndustryStandard/Pci22.h>
 #include <IndustryStandard/Q35MchIch9.h>
 #include <IndustryStandard/QemuCpuHotplug.h>
-#include <Library/PlatformInitLib.h>
+#include <Library/MemEncryptSevLib.h>
 #include <OvmfPlatforms.h>
 
 #include "Platform.h"
 
+EFI_HOB_PLATFORM_INFO  mPlatformInfoHob = { 0 };
+
 EFI_PEI_PPI_DESCRIPTOR  mPpiBootMode[] = {
   {
     EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
@@ -49,17 +51,9 @@ EFI_PEI_PPI_DESCRIPTOR  mPpiBootMode[] = {
   }
 };
 
-UINT16  mHostBridgeDevId;
-
-EFI_BOOT_MODE  mBootMode = BOOT_WITH_FULL_CONFIGURATION;
-
-BOOLEAN  mS3Supported = FALSE;
-
-UINT32  mMaxCpuCount;
-
 VOID
 MemMapInitialization (
-  VOID
+  IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
   )
 {
   UINT64         PciIoBase;
@@ -78,16 +72,16 @@ MemMapInitialization (
   //
   PlatformAddIoMemoryRangeHob (0x0A0000, BASE_1MB);
 
-  if (mHostBridgeDevId == 0xffff /* microvm */) {
+  if (PlatformInfoHob->HostBridgeDevId == 0xffff /* microvm */) {
     PlatformAddIoMemoryBaseSizeHob (MICROVM_GED_MMIO_BASE, SIZE_4KB);
     PlatformAddIoMemoryBaseSizeHob (0xFEC00000, SIZE_4KB); /* ioapic #1 */
     PlatformAddIoMemoryBaseSizeHob (0xFEC10000, SIZE_4KB); /* ioapic #2 */
     return;
   }
 
-  TopOfLowRam  = GetSystemMemorySizeBelow4gb ();
+  TopOfLowRam  = GetSystemMemorySizeBelow4gb (PlatformInfoHob);
   PciExBarBase = 0;
-  if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
+  if (PlatformInfoHob->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.
@@ -97,8 +91,8 @@ MemMapInitialization (
     ASSERT (PciExBarBase <= MAX_UINT32 - SIZE_256MB);
     PciBase = (UINT32)(PciExBarBase + SIZE_256MB);
   } else {
-    ASSERT (TopOfLowRam <= mQemuUc32Base);
-    PciBase = mQemuUc32Base;
+    ASSERT (TopOfLowRam <= PlatformInfoHob->Uc32Base);
+    PciBase = PlatformInfoHob->Uc32Base;
   }
 
   //
@@ -121,9 +115,12 @@ MemMapInitialization (
   PcdStatus = PcdSet64S (PcdPciMmio32Size, PciSize);
   ASSERT_RETURN_ERROR (PcdStatus);
 
+  PlatformInfoHob->PcdPciMmio32Base = PciBase;
+  PlatformInfoHob->PcdPciMmio32Size = PciSize;
+
   PlatformAddIoMemoryBaseSizeHob (0xFEC00000, SIZE_4KB);
   PlatformAddIoMemoryBaseSizeHob (0xFED00000, SIZE_1KB);
-  if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
+  if (PlatformInfoHob->HostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
     PlatformAddIoMemoryBaseSizeHob (ICH9_ROOT_COMPLEX_BASE, SIZE_16KB);
     //
     // Note: there should be an
@@ -160,7 +157,7 @@ MemMapInitialization (
   // On Q35, the IO Port space is available for PCI resource allocations from
   // 0x6000 up.
   //
-  if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
+  if (PlatformInfoHob->HostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
     PciIoBase = 0x6000;
     PciIoSize = 0xA000;
     ASSERT ((ICH9_PMBASE_VALUE & 0xF000) < PciIoBase);
@@ -180,6 +177,9 @@ MemMapInitialization (
   ASSERT_RETURN_ERROR (PcdStatus);
   PcdStatus = PcdSet64S (PcdPciIoSize, PciIoSize);
   ASSERT_RETURN_ERROR (PcdStatus);
+
+  PlatformInfoHob->PcdPciIoBase = PciIoBase;
+  PlatformInfoHob->PcdPciIoSize = PciIoSize;
 }
 
 #define UPDATE_BOOLEAN_PCD_FROM_FW_CFG(TokenName)                   \
@@ -306,7 +306,7 @@ MicrovmInitialization (
 
 VOID
 MiscInitialization (
-  VOID
+  IN EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
   )
 {
   UINTN          PmCmd;
@@ -327,12 +327,12 @@ MiscInitialization (
   // of IO space. (Side note: unlike other HOBs, the CPU HOB is needed during
   // S3 resume as well, so we build it unconditionally.)
   //
-  BuildCpuHob (mPhysMemAddressWidth, 16);
+  BuildCpuHob (PlatformInfoHob->PhysMemAddressWidth, 16);
 
   //
   // Determine platform type and save Host Bridge DID to PCD
   //
-  switch (mHostBridgeDevId) {
+  switch (PlatformInfoHob->HostBridgeDevId) {
     case INTEL_82441_DEVICE_ID:
       PmCmd      = POWER_MGMT_REGISTER_PIIX4 (PCI_COMMAND_OFFSET);
       Pmba       = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA);
@@ -371,13 +371,13 @@ MiscInitialization (
         DEBUG_ERROR,
         "%a: Unknown Host Bridge Device ID: 0x%04x\n",
         __FUNCTION__,
-        mHostBridgeDevId
+        PlatformInfoHob->HostBridgeDevId
         ));
       ASSERT (FALSE);
       return;
   }
 
-  PcdStatus = PcdSet16S (PcdOvmfHostBridgePciDevId, mHostBridgeDevId);
+  PcdStatus = PcdSet16S (PcdOvmfHostBridgePciDevId, PlatformInfoHob->HostBridgeDevId);
   ASSERT_RETURN_ERROR (PcdStatus);
 
   //
@@ -403,7 +403,7 @@ MiscInitialization (
     PciOr8 (AcpiCtlReg, AcpiEnBit);
   }
 
-  if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
+  if (PlatformInfoHob->HostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
     //
     // Set Root Complex Register Block BAR
     //
@@ -421,18 +421,18 @@ MiscInitialization (
 
 VOID
 BootModeInitialization (
-  VOID
+  IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
   )
 {
   EFI_STATUS  Status;
 
   if (PlatformCmosRead8 (0xF) == 0xFE) {
-    mBootMode = BOOT_ON_S3_RESUME;
+    PlatformInfoHob->BootMode = BOOT_ON_S3_RESUME;
   }
 
   PlatformCmosWrite8 (0xF, 0x00);
 
-  Status = PeiServicesSetBootMode (mBootMode);
+  Status = PeiServicesSetBootMode (PlatformInfoHob->BootMode);
   ASSERT_EFI_ERROR (Status);
 
   Status = PeiServicesInstallPpi (mPpiBootMode);
@@ -473,7 +473,7 @@ S3Verification (
   )
 {
  #if defined (MDE_CPU_X64)
-  if (FeaturePcdGet (PcdSmmSmramRequire) && mS3Supported) {
+  if (mPlatformInfoHob.SmmSmramRequire && mPlatformInfoHob.S3Supported) {
     DEBUG ((
       DEBUG_ERROR,
       "%a: S3Resume2Pei doesn't support X64 PEI + SMM yet.\n",
@@ -501,7 +501,7 @@ Q35BoardVerification (
   VOID
   )
 {
-  if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
+  if (mPlatformInfoHob.HostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
     return;
   }
 
@@ -510,7 +510,7 @@ Q35BoardVerification (
     "%a: no TSEG (SMRAM) on host bridge DID=0x%04x; "
     "only DID=0x%04x (Q35) is supported\n",
     __FUNCTION__,
-    mHostBridgeDevId,
+    mPlatformInfoHob.HostBridgeDevId,
     INTEL_Q35_MCH_DEVICE_ID
     ));
   ASSERT (FALSE);
@@ -523,10 +523,11 @@ Q35BoardVerification (
 **/
 VOID
 MaxCpuCountInitialization (
-  VOID
+  IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
   )
 {
   UINT16         BootCpuCount;
+  UINT32         MaxCpuCount;
   RETURN_STATUS  PcdStatus;
 
   //
@@ -542,7 +543,7 @@ MaxCpuCountInitialization (
     // first).
     //
     DEBUG ((DEBUG_WARN, "%a: boot CPU count unavailable\n", __FUNCTION__));
-    mMaxCpuCount = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
+    MaxCpuCount = PlatformInfoHob->DefaultMaxCpuNumber;
   } else {
     //
     // We will expose BootCpuCount to MpInitLib. MpInitLib will count APs up to
@@ -553,7 +554,7 @@ MaxCpuCountInitialization (
     UINTN   CpuHpBase;
     UINT32  CmdData2;
 
-    CpuHpBase = ((mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) ?
+    CpuHpBase = ((PlatformInfoHob->HostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) ?
                  ICH9_CPU_HOTPLUG_BASE : PIIX4_CPU_HOTPLUG_BASE);
 
     //
@@ -605,7 +606,7 @@ MaxCpuCountInitialization (
         "%a: modern CPU hotplug interface unavailable\n",
         __FUNCTION__
         ));
-      mMaxCpuCount = BootCpuCount;
+      MaxCpuCount = BootCpuCount;
     } else {
       //
       // Grab the possible CPU count from the modern CPU hotplug interface.
@@ -671,23 +672,26 @@ MaxCpuCountInitialization (
         BootCpuCount = (UINT16)Present;
       }
 
-      mMaxCpuCount = Possible;
+      MaxCpuCount = Possible;
     }
   }
 
   DEBUG ((
     DEBUG_INFO,
-    "%a: BootCpuCount=%d mMaxCpuCount=%u\n",
+    "%a: BootCpuCount=%d MaxCpuCount=%u\n",
     __FUNCTION__,
     BootCpuCount,
-    mMaxCpuCount
+    MaxCpuCount
     ));
-  ASSERT (BootCpuCount <= mMaxCpuCount);
+  ASSERT (BootCpuCount <= MaxCpuCount);
 
   PcdStatus = PcdSet32S (PcdCpuBootLogicalProcessorNumber, BootCpuCount);
   ASSERT_RETURN_ERROR (PcdStatus);
-  PcdStatus = PcdSet32S (PcdCpuMaxLogicalProcessorNumber, mMaxCpuCount);
+  PcdStatus = PcdSet32S (PcdCpuMaxLogicalProcessorNumber, MaxCpuCount);
   ASSERT_RETURN_ERROR (PcdStatus);
+
+  PlatformInfoHob->PcdCpuMaxLogicalProcessorNumber  = MaxCpuCount;
+  PlatformInfoHob->PcdCpuBootLogicalProcessorNumber = BootCpuCount;
 }
 
 /**
@@ -710,27 +714,30 @@ InitializePlatform (
 
   DEBUG ((DEBUG_INFO, "Platform PEIM Loaded\n"));
 
+  mPlatformInfoHob.SmmSmramRequire = FeaturePcdGet (PcdSmmSmramRequire);
+  mPlatformInfoHob.SevEsIsEnabled  = MemEncryptSevEsIsEnabled ();
+
   PlatformDebugDumpCmos ();
 
   if (QemuFwCfgS3Enabled ()) {
     DEBUG ((DEBUG_INFO, "S3 support was detected on QEMU\n"));
-    mS3Supported = TRUE;
-    Status       = PcdSetBoolS (PcdAcpiS3Enable, TRUE);
+    mPlatformInfoHob.S3Supported = TRUE;
+    Status                       = PcdSetBoolS (PcdAcpiS3Enable, TRUE);
     ASSERT_EFI_ERROR (Status);
   }
 
   S3Verification ();
-  BootModeInitialization ();
-  AddressWidthInitialization ();
+  BootModeInitialization (&mPlatformInfoHob);
+  AddressWidthInitialization (&mPlatformInfoHob);
 
   //
   // Query Host Bridge DID
   //
-  mHostBridgeDevId = PciRead16 (OVMF_HOSTBRIDGE_DID);
+  mPlatformInfoHob.HostBridgeDevId = PciRead16 (OVMF_HOSTBRIDGE_DID);
 
-  MaxCpuCountInitialization ();
+  MaxCpuCountInitialization (&mPlatformInfoHob);
 
-  if (FeaturePcdGet (PcdSmmSmramRequire)) {
+  if (mPlatformInfoHob.SmmSmramRequire) {
     Q35BoardVerification ();
     Q35TsegMbytesInitialization ();
     Q35SmramAtDefaultSmbaseInitialization ();
@@ -738,24 +745,24 @@ InitializePlatform (
 
   PublishPeiMemory ();
 
-  QemuUc32BaseInitialization ();
+  QemuUc32BaseInitialization (&mPlatformInfoHob);
 
-  InitializeRamRegions ();
+  InitializeRamRegions (&mPlatformInfoHob);
 
-  if (mBootMode != BOOT_ON_S3_RESUME) {
-    if (!FeaturePcdGet (PcdSmmSmramRequire)) {
+  if (mPlatformInfoHob.BootMode != BOOT_ON_S3_RESUME) {
+    if (!mPlatformInfoHob.SmmSmramRequire) {
       ReserveEmuVariableNvStore ();
     }
 
     PeiFvInitialization ();
     MemTypeInfoInitialization ();
-    MemMapInitialization ();
+    MemMapInitialization (&mPlatformInfoHob);
     NoexecDxeInitialization ();
   }
 
   InstallClearCacheCallback ();
   AmdSevInitialize ();
-  MiscInitialization ();
+  MiscInitialization (&mPlatformInfoHob);
   InstallFeatureControlCallback ();
 
   return EFI_SUCCESS;
diff --git a/OvmfPkg/PlatformPei/Platform.h b/OvmfPkg/PlatformPei/Platform.h
index f193ff736549..ff4459d79fe4 100644
--- a/OvmfPkg/PlatformPei/Platform.h
+++ b/OvmfPkg/PlatformPei/Platform.h
@@ -10,10 +10,13 @@
 #define _PLATFORM_PEI_H_INCLUDED_
 
 #include <IndustryStandard/E820.h>
+#include <Library/PlatformInitLib.h>
+
+extern EFI_HOB_PLATFORM_INFO  mPlatformInfoHob;
 
 VOID
 AddressWidthInitialization (
-  VOID
+  IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
   );
 
 VOID
@@ -33,17 +36,37 @@ PublishPeiMemory (
 
 UINT32
 GetSystemMemorySizeBelow4gb (
-  VOID
+  IN EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
   );
 
 VOID
 QemuUc32BaseInitialization (
-  VOID
+  IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
   );
 
 VOID
 InitializeRamRegions (
-  VOID
+  IN EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
+  );
+
+VOID
+MemMapInitialization (
+  IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
+  );
+
+VOID
+MiscInitialization (
+  IN EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
+  );
+
+VOID
+BootModeInitialization (
+  IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
+  );
+
+VOID
+MaxCpuCountInitialization (
+  IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
   );
 
 EFI_STATUS
@@ -71,23 +94,9 @@ AmdSevInitialize (
   VOID
   );
 
-extern EFI_BOOT_MODE  mBootMode;
-
 VOID
 SevInitializeRam (
   VOID
   );
 
-extern BOOLEAN  mS3Supported;
-
-extern UINT8  mPhysMemAddressWidth;
-
-extern UINT32  mMaxCpuCount;
-
-extern UINT16  mHostBridgeDevId;
-
-extern BOOLEAN  mQ35SmramAtDefaultSmbase;
-
-extern UINT32  mQemuUc32Base;
-
 #endif // _PLATFORM_PEI_H_INCLUDED_
-- 
2.29.2.windows.2


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH V12 20/47] OvmfPkg/PlatformPei: Refactor MiscInitialization
  2022-03-29 23:45 [PATCH V12 00/47] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (18 preceding siblings ...)
  2022-03-29 23:46 ` [PATCH V12 19/47] OvmfPkg/PlatformPei: Move global variables to PlatformInfoHob Min Xu
@ 2022-03-29 23:46 ` Min Xu
  2022-03-29 23:46 ` [PATCH V12 21/47] OvmfPkg/PlatformPei: Refactor MiscInitialization for CloudHV Min Xu
                   ` (20 subsequent siblings)
  40 siblings, 0 replies; 53+ messages in thread
From: Min Xu @ 2022-03-29 23:46 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky, Gerd Hoffmann,
	Sebastien Boeuf

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3863

In MiscInitialization Microvm looks a little weird. Other platforms
call PcdSet16S to set the PcdOvmfHostBridgePciDevId with the value same
as PlatformInfoHob->HostBridgeDevId. But Microvm doesn't follow this
way. In switch-case 0xffff is Microvm, but set with
MICROVM_PSEUDO_DEVICE_ID. So we have to add a new function
( MiscInitializationForMicrovm ) for Microvm and delete the code in
MiscInitialization.

Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Sebastien Boeuf <sebastien.boeuf@intel.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/PlatformPei/Platform.c | 46 ++++++++++++++++++++++++++--------
 1 file changed, 36 insertions(+), 10 deletions(-)

diff --git a/OvmfPkg/PlatformPei/Platform.c b/OvmfPkg/PlatformPei/Platform.c
index 80eb4cc9adcd..af9e72cd7a98 100644
--- a/OvmfPkg/PlatformPei/Platform.c
+++ b/OvmfPkg/PlatformPei/Platform.c
@@ -304,6 +304,36 @@ MicrovmInitialization (
   *FdtHobData = (UINTN)NewBase;
 }
 
+VOID
+MiscInitializationForMicrovm (
+  IN EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
+  )
+{
+  RETURN_STATUS  PcdStatus;
+
+  ASSERT (PlatformInfoHob->HostBridgeDevId == 0xffff);
+
+  DEBUG ((DEBUG_INFO, "%a: microvm\n", __FUNCTION__));
+  //
+  // 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 (PlatformInfoHob->PhysMemAddressWidth, 16);
+
+  MicrovmInitialization ();
+  PcdStatus = PcdSet16S (
+                PcdOvmfHostBridgePciDevId,
+                MICROVM_PSEUDO_DEVICE_ID
+                );
+  ASSERT_RETURN_ERROR (PcdStatus);
+}
+
 VOID
 MiscInitialization (
   IN EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
@@ -349,15 +379,6 @@ MiscInitialization (
       AcpiCtlReg = POWER_MGMT_REGISTER_Q35 (ICH9_ACPI_CNTL);
       AcpiEnBit  = ICH9_ACPI_CNTL_ACPI_EN;
       break;
-    case 0xffff: /* microvm */
-      DEBUG ((DEBUG_INFO, "%a: microvm\n", __FUNCTION__));
-      MicrovmInitialization ();
-      PcdStatus = PcdSet16S (
-                    PcdOvmfHostBridgePciDevId,
-                    MICROVM_PSEUDO_DEVICE_ID
-                    );
-      ASSERT_RETURN_ERROR (PcdStatus);
-      return;
     case CLOUDHV_DEVICE_ID:
       DEBUG ((DEBUG_INFO, "%a: Cloud Hypervisor host bridge\n", __FUNCTION__));
       PcdStatus = PcdSet16S (
@@ -762,7 +783,12 @@ InitializePlatform (
 
   InstallClearCacheCallback ();
   AmdSevInitialize ();
-  MiscInitialization (&mPlatformInfoHob);
+  if (mPlatformInfoHob.HostBridgeDevId == 0xffff) {
+    MiscInitializationForMicrovm (&mPlatformInfoHob);
+  } else {
+    MiscInitialization (&mPlatformInfoHob);
+  }
+
   InstallFeatureControlCallback ();
 
   return EFI_SUCCESS;
-- 
2.29.2.windows.2


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH V12 21/47] OvmfPkg/PlatformPei: Refactor MiscInitialization for CloudHV
  2022-03-29 23:45 [PATCH V12 00/47] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (19 preceding siblings ...)
  2022-03-29 23:46 ` [PATCH V12 20/47] OvmfPkg/PlatformPei: Refactor MiscInitialization Min Xu
@ 2022-03-29 23:46 ` Min Xu
  2022-03-29 23:46 ` [PATCH V12 22/47] OvmfPkg/PlatformPei: Refactor AddressWidthInitialization Min Xu
                   ` (19 subsequent siblings)
  40 siblings, 0 replies; 53+ messages in thread
From: Min Xu @ 2022-03-29 23:46 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky, Gerd Hoffmann,
	Sebastien Boeuf

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3863

Refactor MiscInitialization for CloudHV to set PCD as other platforms
do. Because in the following patch we will split the functions which
set PCDs into two, one for PlatformInitLib, one for PlatformPei.

Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Sebastien Boeuf <sebastien.boeuf@intel.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/PlatformPei/Platform.c | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/OvmfPkg/PlatformPei/Platform.c b/OvmfPkg/PlatformPei/Platform.c
index af9e72cd7a98..3e0c56db57ed 100644
--- a/OvmfPkg/PlatformPei/Platform.c
+++ b/OvmfPkg/PlatformPei/Platform.c
@@ -380,13 +380,7 @@ MiscInitialization (
       AcpiEnBit  = ICH9_ACPI_CNTL_ACPI_EN;
       break;
     case CLOUDHV_DEVICE_ID:
-      DEBUG ((DEBUG_INFO, "%a: Cloud Hypervisor host bridge\n", __FUNCTION__));
-      PcdStatus = PcdSet16S (
-                    PcdOvmfHostBridgePciDevId,
-                    CLOUDHV_DEVICE_ID
-                    );
-      ASSERT_RETURN_ERROR (PcdStatus);
-      return;
+      break;
     default:
       DEBUG ((
         DEBUG_ERROR,
@@ -401,6 +395,11 @@ MiscInitialization (
   PcdStatus = PcdSet16S (PcdOvmfHostBridgePciDevId, PlatformInfoHob->HostBridgeDevId);
   ASSERT_RETURN_ERROR (PcdStatus);
 
+  if (PlatformInfoHob->HostBridgeDevId == CLOUDHV_DEVICE_ID) {
+    DEBUG ((DEBUG_INFO, "%a: Cloud Hypervisor is done.\n", __FUNCTION__));
+    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
-- 
2.29.2.windows.2


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH V12 22/47] OvmfPkg/PlatformPei: Refactor AddressWidthInitialization
  2022-03-29 23:45 [PATCH V12 00/47] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (20 preceding siblings ...)
  2022-03-29 23:46 ` [PATCH V12 21/47] OvmfPkg/PlatformPei: Refactor MiscInitialization for CloudHV Min Xu
@ 2022-03-29 23:46 ` Min Xu
  2022-03-29 23:46 ` [PATCH V12 23/47] OvmfPkg/PlatformPei: Refactor MaxCpuCountInitialization Min Xu
                   ` (18 subsequent siblings)
  40 siblings, 0 replies; 53+ messages in thread
From: Min Xu @ 2022-03-29 23:46 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky, Gerd Hoffmann,
	Sebastien Boeuf

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3863

>From this patch we start to restruct the functions which set PCDs into
two, one for PlatformInitLib, one for PlatformPei.

AddressWidthInitialization is the first one. It is splitted into two:
 - PlatformAddressWidthInitialization is for PlatformInitLib
 - AddressWidthInitialization is for PlatformPei. It calls
   PlatformAddressWidthInitialization then set PCDs.

Below functions are also refined for PlatformInitLib:
 - PlatformScanOrAdd64BitE820Ram
 - PlatformGetSystemMemorySizeAbove4gb
 - PlatformGetFirstNonAddress

All the SetPcd codes are removed from above functions.

Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Sebastien Boeuf <sebastien.boeuf@intel.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/PlatformPei/MemDetect.c | 117 ++++++++++++++++++++------------
 OvmfPkg/PlatformPei/Platform.c  |   6 +-
 2 files changed, 78 insertions(+), 45 deletions(-)

diff --git a/OvmfPkg/PlatformPei/MemDetect.c b/OvmfPkg/PlatformPei/MemDetect.c
index f3819b997b3b..5507d9585bab 100644
--- a/OvmfPkg/PlatformPei/MemDetect.c
+++ b/OvmfPkg/PlatformPei/MemDetect.c
@@ -189,7 +189,7 @@ QemuUc32BaseInitialization (
   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()
+  @param[out] MaxAddress  If MaxAddress is NULL, then PlatformScanOrAdd64BitE820Ram()
                           produces memory resource descriptor HOBs for RAM
                           entries that start at or above 4GB.
 
@@ -210,7 +210,7 @@ QemuUc32BaseInitialization (
 **/
 STATIC
 EFI_STATUS
-ScanOrAdd64BitE820Ram (
+PlatformScanOrAdd64BitE820Ram (
   IN BOOLEAN  AddHighHob,
   OUT UINT64  *LowMemory OPTIONAL,
   OUT UINT64  *MaxAddress OPTIONAL
@@ -385,7 +385,7 @@ GetSystemMemorySizeBelow4gb (
     return (UINT32)GetHighestSystemMemoryAddressFromPvhMemmap (TRUE);
   }
 
-  Status = ScanOrAdd64BitE820Ram (FALSE, &LowerMemorySize, NULL);
+  Status = PlatformScanOrAdd64BitE820Ram (FALSE, &LowerMemorySize, NULL);
   if ((Status == EFI_SUCCESS) && (LowerMemorySize > 0)) {
     return (UINT32)LowerMemorySize;
   }
@@ -407,7 +407,7 @@ GetSystemMemorySizeBelow4gb (
 
 STATIC
 UINT64
-GetSystemMemorySizeAbove4gb (
+PlatformGetSystemMemorySizeAbove4gb (
   )
 {
   UINT32  Size;
@@ -434,7 +434,7 @@ GetSystemMemorySizeAbove4gb (
 **/
 STATIC
 UINT64
-GetFirstNonAddress (
+PlatformGetFirstNonAddress (
   IN OUT  EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
   )
 {
@@ -444,7 +444,6 @@ GetFirstNonAddress (
   FIRMWARE_CONFIG_ITEM  FwCfgItem;
   UINTN                 FwCfgSize;
   UINT64                HotPlugMemoryEnd;
-  RETURN_STATUS         PcdStatus;
 
   //
   // set FirstNonAddress to suppress incorrect compiler/analyzer warnings
@@ -458,9 +457,9 @@ GetFirstNonAddress (
   // 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);
+  Status = PlatformScanOrAdd64BitE820Ram (FALSE, NULL, &FirstNonAddress);
   if (EFI_ERROR (Status)) {
-    FirstNonAddress = BASE_4GB + GetSystemMemorySizeAbove4gb ();
+    FirstNonAddress = BASE_4GB + PlatformGetSystemMemorySizeAbove4gb ();
   }
 
   //
@@ -475,12 +474,6 @@ GetFirstNonAddress (
 
  #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.
-  //
-  PlatformInfoHob->PcdPciMmio64Size = 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.
@@ -522,8 +515,6 @@ GetFirstNonAddress (
         "%a: disabling 64-bit PCI host aperture\n",
         __FUNCTION__
         ));
-      PcdStatus = PcdSet64S (PcdPciMmio64Size, 0);
-      ASSERT_RETURN_ERROR (PcdStatus);
     }
 
     //
@@ -574,26 +565,6 @@ GetFirstNonAddress (
   //
   PlatformInfoHob->PcdPciMmio64Base = ALIGN_VALUE (PlatformInfoHob->PcdPciMmio64Base, GetPowerOfTwo64 (PlatformInfoHob->PcdPciMmio64Size));
 
-  if (PlatformInfoHob->BootMode != 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, PlatformInfoHob->PcdPciMmio64Base);
-    ASSERT_RETURN_ERROR (PcdStatus);
-    PcdStatus = PcdSet64S (PcdPciMmio64Size, PlatformInfoHob->PcdPciMmio64Size);
-    ASSERT_RETURN_ERROR (PcdStatus);
-
-    DEBUG ((
-      DEBUG_INFO,
-      "%a: Pci64Base=0x%Lx Pci64Size=0x%Lx\n",
-      __FUNCTION__,
-      PlatformInfoHob->PcdPciMmio64Base,
-      PlatformInfoHob->PcdPciMmio64Size
-      ));
-  }
-
   //
   // The useful address space ends with the 64-bit PCI host aperture.
   //
@@ -602,10 +573,11 @@ GetFirstNonAddress (
 }
 
 /**
-  Initialize the mPhysMemAddressWidth variable, based on guest RAM size.
+  Initialize the PhysMemAddressWidth field in PlatformInfoHob based on guest RAM size.
 **/
 VOID
-AddressWidthInitialization (
+EFIAPI
+PlatformAddressWidthInitialization (
   IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
   )
 {
@@ -618,7 +590,7 @@ AddressWidthInitialization (
   // 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 (PlatformInfoHob);
+  FirstNonAddress     = PlatformGetFirstNonAddress (PlatformInfoHob);
   PhysMemAddressWidth = (UINT8)HighBitSet64 (FirstNonAddress);
 
   //
@@ -645,6 +617,65 @@ AddressWidthInitialization (
   PlatformInfoHob->PhysMemAddressWidth = PhysMemAddressWidth;
 }
 
+/**
+  Initialize the PhysMemAddressWidth field in PlatformInfoHob based on guest RAM size.
+**/
+VOID
+AddressWidthInitialization (
+  IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
+  )
+{
+  RETURN_STATUS  PcdStatus;
+
+  PlatformAddressWidthInitialization (PlatformInfoHob);
+
+  //
+  // 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;
+  }
+
+ #endif
+
+  if (PlatformInfoHob->PcdPciMmio64Size == 0) {
+    if (PlatformInfoHob->BootMode != BOOT_ON_S3_RESUME) {
+      DEBUG ((
+        DEBUG_INFO,
+        "%a: disabling 64-bit PCI host aperture\n",
+        __FUNCTION__
+        ));
+      PcdStatus = PcdSet64S (PcdPciMmio64Size, 0);
+      ASSERT_RETURN_ERROR (PcdStatus);
+    }
+
+    return;
+  }
+
+  if (PlatformInfoHob->BootMode != 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, PlatformInfoHob->PcdPciMmio64Base);
+    ASSERT_RETURN_ERROR (PcdStatus);
+    PcdStatus = PcdSet64S (PcdPciMmio64Size, PlatformInfoHob->PcdPciMmio64Size);
+    ASSERT_RETURN_ERROR (PcdStatus);
+
+    DEBUG ((
+      DEBUG_INFO,
+      "%a: Pci64Base=0x%Lx Pci64Size=0x%Lx\n",
+      __FUNCTION__,
+      PlatformInfoHob->PcdPciMmio64Base,
+      PlatformInfoHob->PcdPciMmio64Size
+      ));
+  }
+}
+
 /**
   Calculate the cap for the permanent PEI memory.
 **/
@@ -704,7 +735,7 @@ GetPeiMemoryCap (
 
   //
   // Add 64 MB for miscellaneous allocations. Note that for
-  // mPhysMemAddressWidth values close to 36, the cap will actually be
+  // PhysMemAddressWidth values close to 36, the cap will actually be
   // dominated by this increment.
   //
   return (UINT32)(EFI_PAGES_TO_SIZE (TotalPages) + SIZE_64MB);
@@ -763,7 +794,7 @@ PublishPeiMemory (
     PeiMemoryCap = GetPeiMemoryCap ();
     DEBUG ((
       DEBUG_INFO,
-      "%a: mPhysMemAddressWidth=%d PeiMemoryCap=%u KB\n",
+      "%a: PhysMemAddressWidth=%d PeiMemoryCap=%u KB\n",
       __FUNCTION__,
       mPlatformInfoHob.PhysMemAddressWidth,
       PeiMemoryCap >> 10
@@ -902,9 +933,9 @@ QemuInitializeRam (
     // entries. Otherwise, create a single memory HOB with the flat >=4GB
     // memory size read from the CMOS.
     //
-    Status = ScanOrAdd64BitE820Ram (TRUE, NULL, NULL);
+    Status = PlatformScanOrAdd64BitE820Ram (TRUE, NULL, NULL);
     if (EFI_ERROR (Status)) {
-      UpperMemorySize = GetSystemMemorySizeAbove4gb ();
+      UpperMemorySize = PlatformGetSystemMemorySizeAbove4gb ();
       if (UpperMemorySize != 0) {
         PlatformAddMemoryBaseSizeHob (BASE_4GB, UpperMemorySize);
       }
diff --git a/OvmfPkg/PlatformPei/Platform.c b/OvmfPkg/PlatformPei/Platform.c
index 3e0c56db57ed..7d370c9b8fa8 100644
--- a/OvmfPkg/PlatformPei/Platform.c
+++ b/OvmfPkg/PlatformPei/Platform.c
@@ -734,8 +734,10 @@ InitializePlatform (
 
   DEBUG ((DEBUG_INFO, "Platform PEIM Loaded\n"));
 
-  mPlatformInfoHob.SmmSmramRequire = FeaturePcdGet (PcdSmmSmramRequire);
-  mPlatformInfoHob.SevEsIsEnabled  = MemEncryptSevEsIsEnabled ();
+  mPlatformInfoHob.SmmSmramRequire     = FeaturePcdGet (PcdSmmSmramRequire);
+  mPlatformInfoHob.SevEsIsEnabled      = MemEncryptSevEsIsEnabled ();
+  mPlatformInfoHob.PcdPciMmio64Size    = PcdGet64 (PcdPciMmio64Size);
+  mPlatformInfoHob.DefaultMaxCpuNumber = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
 
   PlatformDebugDumpCmos ();
 
-- 
2.29.2.windows.2


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH V12 23/47] OvmfPkg/PlatformPei: Refactor MaxCpuCountInitialization
  2022-03-29 23:45 [PATCH V12 00/47] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (21 preceding siblings ...)
  2022-03-29 23:46 ` [PATCH V12 22/47] OvmfPkg/PlatformPei: Refactor AddressWidthInitialization Min Xu
@ 2022-03-29 23:46 ` Min Xu
  2022-03-29 23:46 ` [PATCH V12 24/47] OvmfPkg/PlatformPei: Refactor QemuUc32BaseInitialization Min Xu
                   ` (17 subsequent siblings)
  40 siblings, 0 replies; 53+ messages in thread
From: Min Xu @ 2022-03-29 23:46 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky, Gerd Hoffmann,
	Sebastien Boeuf

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3863

MaxCpuCountInitialization is splitted into two:
 - PlatformMaxCpuCountInitialization is for PlatformInitLib
 - MaxCpuCountInitialization is for PlatformPei. It calls
   PlatformMaxCpuCountInitialization then sets PCDs.

Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Sebastien Boeuf <sebastien.boeuf@intel.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/PlatformPei/Platform.c | 33 +++++++++++++++++++++++----------
 1 file changed, 23 insertions(+), 10 deletions(-)

diff --git a/OvmfPkg/PlatformPei/Platform.c b/OvmfPkg/PlatformPei/Platform.c
index 7d370c9b8fa8..20e38a098d52 100644
--- a/OvmfPkg/PlatformPei/Platform.c
+++ b/OvmfPkg/PlatformPei/Platform.c
@@ -539,16 +539,15 @@ Q35BoardVerification (
 
 /**
   Fetch the boot CPU count and the possible CPU count from QEMU, and expose
-  them to UefiCpuPkg modules. Set the mMaxCpuCount variable.
+  them to UefiCpuPkg modules. Set the MaxCpuCount field in PlatformInfoHob.
 **/
 VOID
-MaxCpuCountInitialization (
+PlatformMaxCpuCountInitialization (
   IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
   )
 {
-  UINT16         BootCpuCount;
-  UINT32         MaxCpuCount;
-  RETURN_STATUS  PcdStatus;
+  UINT16  BootCpuCount;
+  UINT32  MaxCpuCount;
 
   //
   // Try to fetch the boot CPU count.
@@ -705,15 +704,29 @@ MaxCpuCountInitialization (
     ));
   ASSERT (BootCpuCount <= MaxCpuCount);
 
-  PcdStatus = PcdSet32S (PcdCpuBootLogicalProcessorNumber, BootCpuCount);
-  ASSERT_RETURN_ERROR (PcdStatus);
-  PcdStatus = PcdSet32S (PcdCpuMaxLogicalProcessorNumber, MaxCpuCount);
-  ASSERT_RETURN_ERROR (PcdStatus);
-
   PlatformInfoHob->PcdCpuMaxLogicalProcessorNumber  = MaxCpuCount;
   PlatformInfoHob->PcdCpuBootLogicalProcessorNumber = BootCpuCount;
 }
 
+/**
+  Fetch the boot CPU count and the possible CPU count from QEMU, and expose
+  them to UefiCpuPkg modules. Set the MaxCpuCount field in PlatformInfoHob.
+**/
+VOID
+MaxCpuCountInitialization (
+  IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
+  )
+{
+  RETURN_STATUS  PcdStatus;
+
+  PlatformMaxCpuCountInitialization (PlatformInfoHob);
+
+  PcdStatus = PcdSet32S (PcdCpuBootLogicalProcessorNumber, PlatformInfoHob->PcdCpuBootLogicalProcessorNumber);
+  ASSERT_RETURN_ERROR (PcdStatus);
+  PcdStatus = PcdSet32S (PcdCpuMaxLogicalProcessorNumber, PlatformInfoHob->PcdCpuMaxLogicalProcessorNumber);
+  ASSERT_RETURN_ERROR (PcdStatus);
+}
+
 /**
   Perform Platform PEI initialization.
 
-- 
2.29.2.windows.2


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH V12 24/47] OvmfPkg/PlatformPei: Refactor QemuUc32BaseInitialization
  2022-03-29 23:45 [PATCH V12 00/47] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (22 preceding siblings ...)
  2022-03-29 23:46 ` [PATCH V12 23/47] OvmfPkg/PlatformPei: Refactor MaxCpuCountInitialization Min Xu
@ 2022-03-29 23:46 ` Min Xu
  2022-03-29 23:46 ` [PATCH V12 25/47] OvmfPkg/PlatformPei: Refactor InitializeRamRegions Min Xu
                   ` (16 subsequent siblings)
  40 siblings, 0 replies; 53+ messages in thread
From: Min Xu @ 2022-03-29 23:46 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky, Gerd Hoffmann,
	Sebastien Boeuf

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3863

Rename QemuUc32BaseInitialization to PlatformQemuUc32BaseInitialization.
This function is for PlatformInitLib.

Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Sebastien Boeuf <sebastien.boeuf@intel.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/PlatformPei/MemDetect.c | 3 ++-
 OvmfPkg/PlatformPei/Platform.c  | 2 +-
 OvmfPkg/PlatformPei/Platform.h  | 3 ++-
 3 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/OvmfPkg/PlatformPei/MemDetect.c b/OvmfPkg/PlatformPei/MemDetect.c
index 5507d9585bab..45f7eba65d04 100644
--- a/OvmfPkg/PlatformPei/MemDetect.c
+++ b/OvmfPkg/PlatformPei/MemDetect.c
@@ -125,7 +125,8 @@ Q35SmramAtDefaultSmbaseInitialization (
 }
 
 VOID
-QemuUc32BaseInitialization (
+EFIAPI
+PlatformQemuUc32BaseInitialization (
   IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
   )
 {
diff --git a/OvmfPkg/PlatformPei/Platform.c b/OvmfPkg/PlatformPei/Platform.c
index 20e38a098d52..1275c9187e86 100644
--- a/OvmfPkg/PlatformPei/Platform.c
+++ b/OvmfPkg/PlatformPei/Platform.c
@@ -780,7 +780,7 @@ InitializePlatform (
 
   PublishPeiMemory ();
 
-  QemuUc32BaseInitialization (&mPlatformInfoHob);
+  PlatformQemuUc32BaseInitialization (&mPlatformInfoHob);
 
   InitializeRamRegions (&mPlatformInfoHob);
 
diff --git a/OvmfPkg/PlatformPei/Platform.h b/OvmfPkg/PlatformPei/Platform.h
index ff4459d79fe4..038a806a1e1b 100644
--- a/OvmfPkg/PlatformPei/Platform.h
+++ b/OvmfPkg/PlatformPei/Platform.h
@@ -40,7 +40,8 @@ GetSystemMemorySizeBelow4gb (
   );
 
 VOID
-QemuUc32BaseInitialization (
+EFIAPI
+PlatformQemuUc32BaseInitialization (
   IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
   );
 
-- 
2.29.2.windows.2


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH V12 25/47] OvmfPkg/PlatformPei: Refactor InitializeRamRegions
  2022-03-29 23:45 [PATCH V12 00/47] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (23 preceding siblings ...)
  2022-03-29 23:46 ` [PATCH V12 24/47] OvmfPkg/PlatformPei: Refactor QemuUc32BaseInitialization Min Xu
@ 2022-03-29 23:46 ` Min Xu
  2022-03-29 23:46 ` [PATCH V12 26/47] OvmfPkg/PlatformPei: Refactor MemMapInitialization Min Xu
                   ` (15 subsequent siblings)
  40 siblings, 0 replies; 53+ messages in thread
From: Min Xu @ 2022-03-29 23:46 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky, Gerd Hoffmann,
	Sebastien Boeuf

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3863

InitializeRamRegions is refactored into 3 calls:
 - PlatformQemuInitializeRam
 - SevInitializeRam
 - PlatformQemuInitializeRamForS3

SevInitializeRam is not in PlatformInitLib. Because in the first stage
PlatformInitLib only support the basic platform featues.

PlatformQemuInitializeRamForS3 wraps the code which was previously in
InitializeRamRegions (many code in 2 if-checks).

Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Sebastien Boeuf <sebastien.boeuf@intel.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/PlatformPei/MemDetect.c | 40 ++++++++++++++++++++-------------
 OvmfPkg/PlatformPei/Platform.c  |  2 +-
 OvmfPkg/PlatformPei/Platform.h  |  3 ++-
 3 files changed, 28 insertions(+), 17 deletions(-)

diff --git a/OvmfPkg/PlatformPei/MemDetect.c b/OvmfPkg/PlatformPei/MemDetect.c
index 45f7eba65d04..23a583ed3386 100644
--- a/OvmfPkg/PlatformPei/MemDetect.c
+++ b/OvmfPkg/PlatformPei/MemDetect.c
@@ -161,7 +161,7 @@ PlatformQemuUc32BaseInitialization (
   // 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 (PlatformInfoHob);
+  LowerMemorySize           = PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob);
   PlatformInfoHob->Uc32Size = GetPowerOfTwo32 ((UINT32)(SIZE_4GB - LowerMemorySize));
   PlatformInfoHob->Uc32Base = (UINT32)(SIZE_4GB - PlatformInfoHob->Uc32Size);
   //
@@ -372,7 +372,8 @@ GetHighestSystemMemoryAddressFromPvhMemmap (
 }
 
 UINT32
-GetSystemMemorySizeBelow4gb (
+EFIAPI
+PlatformGetSystemMemorySizeBelow4gb (
   IN EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
   )
 {
@@ -761,7 +762,7 @@ PublishPeiMemory (
   UINT32                S3AcpiReservedMemoryBase;
   UINT32                S3AcpiReservedMemorySize;
 
-  LowerMemorySize = GetSystemMemorySizeBelow4gb (&mPlatformInfoHob);
+  LowerMemorySize = PlatformGetSystemMemorySizeBelow4gb (&mPlatformInfoHob);
   if (mPlatformInfoHob.SmmSmramRequire) {
     //
     // TSEG is chipped from the end of low RAM
@@ -871,7 +872,7 @@ QemuInitializeRamBelow1gb (
 **/
 STATIC
 VOID
-QemuInitializeRam (
+PlatformQemuInitializeRam (
   IN EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
   )
 {
@@ -885,7 +886,7 @@ QemuInitializeRam (
   //
   // Determine total memory size available
   //
-  LowerMemorySize = GetSystemMemorySizeBelow4gb (PlatformInfoHob);
+  LowerMemorySize = PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob);
 
   if (PlatformInfoHob->BootMode == BOOT_ON_S3_RESUME) {
     //
@@ -995,19 +996,12 @@ QemuInitializeRam (
   }
 }
 
-/**
-  Publish system RAM and reserve memory regions
-
-**/
+STATIC
 VOID
-InitializeRamRegions (
+PlatformQemuInitializeRamForS3 (
   IN EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
   )
 {
-  QemuInitializeRam (PlatformInfoHob);
-
-  SevInitializeRam ();
-
   if (PlatformInfoHob->S3Supported && (PlatformInfoHob->BootMode != BOOT_ON_S3_RESUME)) {
     //
     // This is the memory range that will be used for PEI on S3 resume
@@ -1113,7 +1107,7 @@ InitializeRamRegions (
       //
       TsegSize = PlatformInfoHob->Q35TsegMbytes * SIZE_1MB;
       BuildMemoryAllocationHob (
-        GetSystemMemorySizeBelow4gb (PlatformInfoHob) - TsegSize,
+        PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob) - TsegSize,
         TsegSize,
         EfiReservedMemoryType
         );
@@ -1152,3 +1146,19 @@ InitializeRamRegions (
  #endif
   }
 }
+
+/**
+  Publish system RAM and reserve memory regions
+
+**/
+VOID
+InitializeRamRegions (
+  IN EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
+  )
+{
+  PlatformQemuInitializeRam (PlatformInfoHob);
+
+  SevInitializeRam ();
+
+  PlatformQemuInitializeRamForS3 (PlatformInfoHob);
+}
diff --git a/OvmfPkg/PlatformPei/Platform.c b/OvmfPkg/PlatformPei/Platform.c
index 1275c9187e86..f89d14493ecf 100644
--- a/OvmfPkg/PlatformPei/Platform.c
+++ b/OvmfPkg/PlatformPei/Platform.c
@@ -79,7 +79,7 @@ MemMapInitialization (
     return;
   }
 
-  TopOfLowRam  = GetSystemMemorySizeBelow4gb (PlatformInfoHob);
+  TopOfLowRam  = PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob);
   PciExBarBase = 0;
   if (PlatformInfoHob->HostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
     //
diff --git a/OvmfPkg/PlatformPei/Platform.h b/OvmfPkg/PlatformPei/Platform.h
index 038a806a1e1b..635d58379a24 100644
--- a/OvmfPkg/PlatformPei/Platform.h
+++ b/OvmfPkg/PlatformPei/Platform.h
@@ -35,7 +35,8 @@ PublishPeiMemory (
   );
 
 UINT32
-GetSystemMemorySizeBelow4gb (
+EFIAPI
+PlatformGetSystemMemorySizeBelow4gb (
   IN EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
   );
 
-- 
2.29.2.windows.2


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH V12 26/47] OvmfPkg/PlatformPei: Refactor MemMapInitialization
  2022-03-29 23:45 [PATCH V12 00/47] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (24 preceding siblings ...)
  2022-03-29 23:46 ` [PATCH V12 25/47] OvmfPkg/PlatformPei: Refactor InitializeRamRegions Min Xu
@ 2022-03-29 23:46 ` Min Xu
  2022-03-29 23:46 ` [PATCH V12 27/47] OvmfPkg/PlatformPei: Refactor NoexecDxeInitialization Min Xu
                   ` (14 subsequent siblings)
  40 siblings, 0 replies; 53+ messages in thread
From: Min Xu @ 2022-03-29 23:46 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky, Gerd Hoffmann,
	Sebastien Boeuf

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3863

MemMapInitialization is split into 2 functions:
 - PlatformMemMapInitialization is for PlatformInfoLib
 - MemMapInitialization calls PlatformMemMapInitialization and then
   sets PCDs. It is for PlatformPei.

Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Sebastien Boeuf <sebastien.boeuf@intel.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/PlatformPei/Platform.c | 35 +++++++++++++++++++++++++---------
 1 file changed, 26 insertions(+), 9 deletions(-)

diff --git a/OvmfPkg/PlatformPei/Platform.c b/OvmfPkg/PlatformPei/Platform.c
index f89d14493ecf..b83bd7515809 100644
--- a/OvmfPkg/PlatformPei/Platform.c
+++ b/OvmfPkg/PlatformPei/Platform.c
@@ -52,7 +52,8 @@ EFI_PEI_PPI_DESCRIPTOR  mPpiBootMode[] = {
 };
 
 VOID
-MemMapInitialization (
+EFIAPI
+PlatformMemMapInitialization (
   IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
   )
 {
@@ -110,10 +111,6 @@ MemMapInitialization (
   //
   PciSize = 0xFC000000 - PciBase;
   PlatformAddIoMemoryBaseSizeHob (PciBase, PciSize);
-  PcdStatus = PcdSet64S (PcdPciMmio32Base, PciBase);
-  ASSERT_RETURN_ERROR (PcdStatus);
-  PcdStatus = PcdSet64S (PcdPciMmio32Size, PciSize);
-  ASSERT_RETURN_ERROR (PcdStatus);
 
   PlatformInfoHob->PcdPciMmio32Base = PciBase;
   PlatformInfoHob->PcdPciMmio32Size = PciSize;
@@ -173,15 +170,35 @@ MemMapInitialization (
     PciIoBase,
     PciIoSize
     );
-  PcdStatus = PcdSet64S (PcdPciIoBase, PciIoBase);
-  ASSERT_RETURN_ERROR (PcdStatus);
-  PcdStatus = PcdSet64S (PcdPciIoSize, PciIoSize);
-  ASSERT_RETURN_ERROR (PcdStatus);
 
   PlatformInfoHob->PcdPciIoBase = PciIoBase;
   PlatformInfoHob->PcdPciIoSize = PciIoSize;
 }
 
+VOID
+MemMapInitialization (
+  IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
+  )
+{
+  RETURN_STATUS  PcdStatus;
+
+  PlatformMemMapInitialization (PlatformInfoHob);
+
+  if (PlatformInfoHob->HostBridgeDevId == 0xffff /* microvm */) {
+    return;
+  }
+
+  PcdStatus = PcdSet64S (PcdPciMmio32Base, PlatformInfoHob->PcdPciMmio32Base);
+  ASSERT_RETURN_ERROR (PcdStatus);
+  PcdStatus = PcdSet64S (PcdPciMmio32Size, PlatformInfoHob->PcdPciMmio32Size);
+  ASSERT_RETURN_ERROR (PcdStatus);
+
+  PcdStatus = PcdSet64S (PcdPciIoBase, PlatformInfoHob->PcdPciIoBase);
+  ASSERT_RETURN_ERROR (PcdStatus);
+  PcdStatus = PcdSet64S (PcdPciIoSize, PlatformInfoHob->PcdPciIoSize);
+  ASSERT_RETURN_ERROR (PcdStatus);
+}
+
 #define UPDATE_BOOLEAN_PCD_FROM_FW_CFG(TokenName)                   \
           do {                                                      \
             BOOLEAN       Setting;                                  \
-- 
2.29.2.windows.2


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH V12 27/47] OvmfPkg/PlatformPei: Refactor NoexecDxeInitialization
  2022-03-29 23:45 [PATCH V12 00/47] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (25 preceding siblings ...)
  2022-03-29 23:46 ` [PATCH V12 26/47] OvmfPkg/PlatformPei: Refactor MemMapInitialization Min Xu
@ 2022-03-29 23:46 ` Min Xu
  2022-03-29 23:46 ` [PATCH V12 28/47] OvmfPkg/PlatformPei: Refactor MiscInitialization Min Xu
                   ` (13 subsequent siblings)
  40 siblings, 0 replies; 53+ messages in thread
From: Min Xu @ 2022-03-29 23:46 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky, Gerd Hoffmann,
	Sebastien Boeuf

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3863

NoexecDxeInitialization is split into 2 functions:
 - PlatformNoexecDxeInitialization is for PlatformInitLib
 - NoexecDxeInitialization calls PlatformNoexecDxeInitialization and
   then sets PCD.

Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Sebastien Boeuf <sebastien.boeuf@intel.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/PlatformPei/Platform.c | 34 +++++++++++++++++++++-------------
 1 file changed, 21 insertions(+), 13 deletions(-)

diff --git a/OvmfPkg/PlatformPei/Platform.c b/OvmfPkg/PlatformPei/Platform.c
index b83bd7515809..e91acca9f769 100644
--- a/OvmfPkg/PlatformPei/Platform.c
+++ b/OvmfPkg/PlatformPei/Platform.c
@@ -59,7 +59,6 @@ PlatformMemMapInitialization (
 {
   UINT64         PciIoBase;
   UINT64         PciIoSize;
-  RETURN_STATUS  PcdStatus;
   UINT32         TopOfLowRam;
   UINT64         PciExBarBase;
   UINT32         PciBase;
@@ -199,24 +198,33 @@ MemMapInitialization (
   ASSERT_RETURN_ERROR (PcdStatus);
 }
 
-#define UPDATE_BOOLEAN_PCD_FROM_FW_CFG(TokenName)                   \
-          do {                                                      \
-            BOOLEAN       Setting;                                  \
-            RETURN_STATUS PcdStatus;                                \
-                                                                    \
-            if (!RETURN_ERROR (QemuFwCfgParseBool (                 \
-                              "opt/ovmf/" #TokenName, &Setting))) { \
-              PcdStatus = PcdSetBoolS (TokenName, Setting);         \
-              ASSERT_RETURN_ERROR (PcdStatus);                      \
-            }                                                       \
-          } while (0)
+/**
+ * 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 (
+  IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
+  )
+{
+  return QemuFwCfgParseBool ("opt/ovmf/PcdSetNxForStack", &PlatformInfoHob->PcdSetNxForStack);
+}
 
 VOID
 NoexecDxeInitialization (
   VOID
   )
 {
-  UPDATE_BOOLEAN_PCD_FROM_FW_CFG (PcdSetNxForStack);
+  RETURN_STATUS  Status;
+
+  Status = PlatformNoexecDxeInitialization (&mPlatformInfoHob);
+  if (!RETURN_ERROR (Status)) {
+    Status = PcdSetBoolS (PcdSetNxForStack, mPlatformInfoHob.PcdSetNxForStack);
+    ASSERT_RETURN_ERROR (Status);
+  }
 }
 
 VOID
-- 
2.29.2.windows.2


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH V12 28/47] OvmfPkg/PlatformPei: Refactor MiscInitialization
  2022-03-29 23:45 [PATCH V12 00/47] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (26 preceding siblings ...)
  2022-03-29 23:46 ` [PATCH V12 27/47] OvmfPkg/PlatformPei: Refactor NoexecDxeInitialization Min Xu
@ 2022-03-29 23:46 ` Min Xu
  2022-03-29 23:46 ` [PATCH V12 29/47] OvmfPkg/PlatformInitLib: Create MemDetect.c Min Xu
                   ` (12 subsequent siblings)
  40 siblings, 0 replies; 53+ messages in thread
From: Min Xu @ 2022-03-29 23:46 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky, Gerd Hoffmann,
	Sebastien Boeuf

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3863

MiscInitialization is split into 2 functions:
 - PlatformMiscInitialization is for PlatformInitLib.
 - MiscInitialization calls PlatformMiscInitialization and then sets
   PCD. It is for PlatformPei.

Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Sebastien Boeuf <sebastien.boeuf@intel.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/PlatformPei/Platform.c | 43 ++++++++++++++++++++--------------
 1 file changed, 26 insertions(+), 17 deletions(-)

diff --git a/OvmfPkg/PlatformPei/Platform.c b/OvmfPkg/PlatformPei/Platform.c
index e91acca9f769..02697c473d01 100644
--- a/OvmfPkg/PlatformPei/Platform.c
+++ b/OvmfPkg/PlatformPei/Platform.c
@@ -57,12 +57,12 @@ PlatformMemMapInitialization (
   IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
   )
 {
-  UINT64         PciIoBase;
-  UINT64         PciIoSize;
-  UINT32         TopOfLowRam;
-  UINT64         PciExBarBase;
-  UINT32         PciBase;
-  UINT32         PciSize;
+  UINT64  PciIoBase;
+  UINT64  PciIoSize;
+  UINT32  TopOfLowRam;
+  UINT64  PciExBarBase;
+  UINT32  PciBase;
+  UINT32  PciSize;
 
   PciIoBase = 0xC000;
   PciIoSize = 0x4000;
@@ -360,17 +360,16 @@ MiscInitializationForMicrovm (
 }
 
 VOID
-MiscInitialization (
+PlatformMiscInitialization (
   IN EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
   )
 {
-  UINTN          PmCmd;
-  UINTN          Pmba;
-  UINT32         PmbaAndVal;
-  UINT32         PmbaOrVal;
-  UINTN          AcpiCtlReg;
-  UINT8          AcpiEnBit;
-  RETURN_STATUS  PcdStatus;
+  UINTN   PmCmd;
+  UINTN   Pmba;
+  UINT32  PmbaAndVal;
+  UINT32  PmbaOrVal;
+  UINTN   AcpiCtlReg;
+  UINT8   AcpiEnBit;
 
   //
   // Disable A20 Mask
@@ -417,9 +416,6 @@ MiscInitialization (
       return;
   }
 
-  PcdStatus = PcdSet16S (PcdOvmfHostBridgePciDevId, PlatformInfoHob->HostBridgeDevId);
-  ASSERT_RETURN_ERROR (PcdStatus);
-
   if (PlatformInfoHob->HostBridgeDevId == CLOUDHV_DEVICE_ID) {
     DEBUG ((DEBUG_INFO, "%a: Cloud Hypervisor is done.\n", __FUNCTION__));
     return;
@@ -464,6 +460,19 @@ MiscInitialization (
   }
 }
 
+VOID
+MiscInitialization (
+  IN EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
+  )
+{
+  RETURN_STATUS  PcdStatus;
+
+  PlatformMiscInitialization (PlatformInfoHob);
+
+  PcdStatus = PcdSet16S (PcdOvmfHostBridgePciDevId, PlatformInfoHob->HostBridgeDevId);
+  ASSERT_RETURN_ERROR (PcdStatus);
+}
+
 VOID
 BootModeInitialization (
   IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
-- 
2.29.2.windows.2


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH V12 29/47] OvmfPkg/PlatformInitLib: Create MemDetect.c
  2022-03-29 23:45 [PATCH V12 00/47] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (27 preceding siblings ...)
  2022-03-29 23:46 ` [PATCH V12 28/47] OvmfPkg/PlatformPei: Refactor MiscInitialization Min Xu
@ 2022-03-29 23:46 ` Min Xu
  2022-03-29 23:46 ` [PATCH V12 30/47] OvmfPkg/PlatformInitLib: Move functions to Platform.c Min Xu
                   ` (11 subsequent siblings)
  40 siblings, 0 replies; 53+ messages in thread
From: Min Xu @ 2022-03-29 23:46 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky, Gerd Hoffmann,
	Sebastien Boeuf

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3863

Move functions in PlatformPei\MemDetect.c to PlatformInitLib\MemDetect.c.

Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Sebastien Boeuf <sebastien.boeuf@intel.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/Include/Library/PlatformInitLib.h     |  37 +
 OvmfPkg/Library/PlatformInitLib/MemDetect.c   | 842 ++++++++++++++++++
 .../PlatformInitLib/PlatformInitLib.inf       |  49 +
 OvmfPkg/PlatformPei/MemDetect.c               | 804 +----------------
 OvmfPkg/PlatformPei/Platform.h                |  12 -
 5 files changed, 929 insertions(+), 815 deletions(-)
 create mode 100644 OvmfPkg/Library/PlatformInitLib/MemDetect.c

diff --git a/OvmfPkg/Include/Library/PlatformInitLib.h b/OvmfPkg/Include/Library/PlatformInitLib.h
index 9b99d4c1f514..62020efadf37 100644
--- a/OvmfPkg/Include/Library/PlatformInitLib.h
+++ b/OvmfPkg/Include/Library/PlatformInitLib.h
@@ -132,4 +132,41 @@ PlatformAddReservedMemoryBaseSizeHob (
   IN BOOLEAN               Cacheable
   );
 
+VOID
+EFIAPI
+PlatformQemuUc32BaseInitialization (
+  IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
+  );
+
+UINT32
+EFIAPI
+PlatformGetSystemMemorySizeBelow4gb (
+  IN EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
+  );
+
+/**
+  Initialize the PhysMemAddressWidth field in PlatformInfoHob based on guest RAM size.
+**/
+VOID
+EFIAPI
+PlatformAddressWidthInitialization (
+  IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
+  );
+
+/**
+  Peform Memory Detection for QEMU / KVM
+
+**/
+VOID
+EFIAPI
+PlatformQemuInitializeRam (
+  IN EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
+  );
+
+VOID
+EFIAPI
+PlatformQemuInitializeRamForS3 (
+  IN EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
+  );
+
 #endif // PLATFORM_INIT_LIB_H_
diff --git a/OvmfPkg/Library/PlatformInitLib/MemDetect.c b/OvmfPkg/Library/PlatformInitLib/MemDetect.c
new file mode 100644
index 000000000000..911c0906cb3d
--- /dev/null
+++ b/OvmfPkg/Library/PlatformInitLib/MemDetect.c
@@ -0,0 +1,842 @@
+/**@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 <IndustryStandard/Xen/arch-x86/hvm/start_info.h>
+#include <PiPei.h>
+#include <Register/Intel/SmramSaveStateMap.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/MemEncryptSevLib.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>
+
+VOID
+EFIAPI
+PlatformQemuUc32BaseInitialization (
+  IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
+  )
+{
+  UINT32  LowerMemorySize;
+
+  if (PlatformInfoHob->HostBridgeDevId == 0xffff /* microvm */) {
+    return;
+  }
+
+  if (PlatformInfoHob->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);
+    PlatformInfoHob->Uc32Base = (UINT32)FixedPcdGet64 (PcdPciExpressBaseAddress);
+    return;
+  }
+
+  if (PlatformInfoHob->HostBridgeDevId == CLOUDHV_DEVICE_ID) {
+    PlatformInfoHob->Uc32Size = CLOUDHV_MMIO_HOLE_SIZE;
+    PlatformInfoHob->Uc32Base = CLOUDHV_MMIO_HOLE_ADDRESS;
+    return;
+  }
+
+  ASSERT (PlatformInfoHob->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.
+  //
+  LowerMemorySize           = PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob);
+  PlatformInfoHob->Uc32Size = GetPowerOfTwo32 ((UINT32)(SIZE_4GB - LowerMemorySize));
+  PlatformInfoHob->Uc32Base = (UINT32)(SIZE_4GB - PlatformInfoHob->Uc32Size);
+  //
+  // Assuming that LowerMemorySize is at least 1 byte, Uc32Size is at most 2GB.
+  // Therefore Uc32Base is at least 2GB.
+  //
+  ASSERT (PlatformInfoHob->Uc32Base >= BASE_2GB);
+
+  if (PlatformInfoHob->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,
+      PlatformInfoHob->Uc32Base,
+      PlatformInfoHob->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 PlatformScanOrAdd64BitE820Ram()
+                          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
+PlatformScanOrAdd64BitE820Ram (
+  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;
+}
+
+/**
+  Returns PVH memmap
+
+  @param Entries      Pointer to PVH memmap
+  @param Count        Number of entries
+
+  @return EFI_STATUS
+**/
+EFI_STATUS
+GetPvhMemmapEntries (
+  struct hvm_memmap_table_entry  **Entries,
+  UINT32                         *Count
+  )
+{
+  UINT32                 *PVHResetVectorData;
+  struct hvm_start_info  *pvh_start_info;
+
+  PVHResetVectorData = (VOID *)(UINTN)PcdGet32 (PcdXenPvhStartOfDayStructPtr);
+  if (PVHResetVectorData == 0) {
+    return EFI_NOT_FOUND;
+  }
+
+  pvh_start_info = (struct hvm_start_info *)(UINTN)PVHResetVectorData[0];
+
+  *Entries = (struct hvm_memmap_table_entry *)(UINTN)pvh_start_info->memmap_paddr;
+  *Count   = pvh_start_info->memmap_entries;
+
+  return EFI_SUCCESS;
+}
+
+STATIC
+UINT64
+GetHighestSystemMemoryAddressFromPvhMemmap (
+  BOOLEAN  Below4gb
+  )
+{
+  struct hvm_memmap_table_entry  *Memmap;
+  UINT32                         MemmapEntriesCount;
+  struct hvm_memmap_table_entry  *Entry;
+  EFI_STATUS                     Status;
+  UINT32                         Loop;
+  UINT64                         HighestAddress;
+  UINT64                         EntryEnd;
+
+  HighestAddress = 0;
+
+  Status = GetPvhMemmapEntries (&Memmap, &MemmapEntriesCount);
+  ASSERT_EFI_ERROR (Status);
+
+  for (Loop = 0; Loop < MemmapEntriesCount; Loop++) {
+    Entry    = Memmap + Loop;
+    EntryEnd = Entry->addr + Entry->size;
+
+    if ((Entry->type == XEN_HVM_MEMMAP_TYPE_RAM) &&
+        (EntryEnd > HighestAddress))
+    {
+      if (Below4gb && (EntryEnd <= BASE_4GB)) {
+        HighestAddress = EntryEnd;
+      } else if (!Below4gb && (EntryEnd >= BASE_4GB)) {
+        HighestAddress = EntryEnd;
+      }
+    }
+  }
+
+  return HighestAddress;
+}
+
+UINT32
+EFIAPI
+PlatformGetSystemMemorySizeBelow4gb (
+  IN EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
+  )
+{
+  EFI_STATUS  Status;
+  UINT64      LowerMemorySize = 0;
+  UINT8       Cmos0x34;
+  UINT8       Cmos0x35;
+
+  if (PlatformInfoHob->HostBridgeDevId == CLOUDHV_DEVICE_ID) {
+    // Get the information from PVH memmap
+    return (UINT32)GetHighestSystemMemoryAddressFromPvhMemmap (TRUE);
+  }
+
+  Status = PlatformScanOrAdd64BitE820Ram (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
+PlatformGetSystemMemorySizeAbove4gb (
+  )
+{
+  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
+PlatformGetFirstNonAddress (
+  IN OUT  EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
+  )
+{
+  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 = PlatformScanOrAdd64BitE820Ram (FALSE, NULL, &FirstNonAddress);
+  if (EFI_ERROR (Status)) {
+    FirstNonAddress = BASE_4GB + PlatformGetSystemMemorySizeAbove4gb ();
+  }
+
+  //
+  // 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
+
+  //
+  // 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) {
+        PlatformInfoHob->PcdPciMmio64Size = 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 (PlatformInfoHob->PcdPciMmio64Size == 0) {
+    if (PlatformInfoHob->BootMode != BOOT_ON_S3_RESUME) {
+      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.
+  //
+  PlatformInfoHob->PcdPciMmio64Base = ALIGN_VALUE (FirstNonAddress, (UINT64)SIZE_1GB);
+  PlatformInfoHob->PcdPciMmio64Size = ALIGN_VALUE (PlatformInfoHob->PcdPciMmio64Size, (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.
+  //
+  PlatformInfoHob->PcdPciMmio64Base = ALIGN_VALUE (PlatformInfoHob->PcdPciMmio64Base, GetPowerOfTwo64 (PlatformInfoHob->PcdPciMmio64Size));
+
+  //
+  // The useful address space ends with the 64-bit PCI host aperture.
+  //
+  FirstNonAddress = PlatformInfoHob->PcdPciMmio64Base + PlatformInfoHob->PcdPciMmio64Size;
+  return FirstNonAddress;
+}
+
+/**
+  Initialize the PhysMemAddressWidth field in PlatformInfoHob based on guest RAM size.
+**/
+VOID
+EFIAPI
+PlatformAddressWidthInitialization (
+  IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
+  )
+{
+  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.
+  //
+  FirstNonAddress     = PlatformGetFirstNonAddress (PlatformInfoHob);
+  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);
+
+  PlatformInfoHob->FirstNonAddress     = FirstNonAddress;
+  PlatformInfoHob->PhysMemAddressWidth = PhysMemAddressWidth;
+}
+
+STATIC
+VOID
+QemuInitializeRamBelow1gb (
+  IN EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
+  )
+{
+  if (PlatformInfoHob->SmmSmramRequire && PlatformInfoHob->Q35SmramAtDefaultSmbase) {
+    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
+
+**/
+VOID
+EFIAPI
+PlatformQemuInitializeRam (
+  IN EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
+  )
+{
+  UINT64         LowerMemorySize;
+  UINT64         UpperMemorySize;
+  MTRR_SETTINGS  MtrrSettings;
+  EFI_STATUS     Status;
+
+  DEBUG ((DEBUG_INFO, "%a called\n", __FUNCTION__));
+
+  //
+  // Determine total memory size available
+  //
+  LowerMemorySize = PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob);
+
+  if (PlatformInfoHob->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.
+    //
+    QemuInitializeRamBelow1gb (PlatformInfoHob);
+  } else {
+    //
+    // Create memory HOBs
+    //
+    QemuInitializeRamBelow1gb (PlatformInfoHob);
+
+    if (PlatformInfoHob->SmmSmramRequire) {
+      UINT32  TsegSize;
+
+      TsegSize = PlatformInfoHob->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 = PlatformScanOrAdd64BitE820Ram (TRUE, NULL, NULL);
+    if (EFI_ERROR (Status)) {
+      UpperMemorySize = PlatformGetSystemMemorySizeAbove4gb ();
+      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 () && (PlatformInfoHob->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 (
+               PlatformInfoHob->Uc32Base,
+               SIZE_4GB - PlatformInfoHob->Uc32Base,
+               CacheUncacheable
+               );
+    ASSERT_EFI_ERROR (Status);
+  }
+}
+
+VOID
+EFIAPI
+PlatformQemuInitializeRamForS3 (
+  IN EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
+  )
+{
+  if (PlatformInfoHob->S3Supported && (PlatformInfoHob->BootMode != BOOT_ON_S3_RESUME)) {
+    //
+    // This is the memory range that will be used for PEI on S3 resume
+    //
+    BuildMemoryAllocationHob (
+      PlatformInfoHob->S3AcpiReservedMemoryBase,
+      PlatformInfoHob->S3AcpiReservedMemorySize,
+      EfiACPIMemoryNVS
+      );
+
+    //
+    // Cover the initial RAM area used as stack and temporary PEI heap.
+    //
+    // This is reserved as ACPI NVS so it can be used on S3 resume.
+    //
+    BuildMemoryAllocationHob (
+      PcdGet32 (PcdOvmfSecPeiTempRamBase),
+      PcdGet32 (PcdOvmfSecPeiTempRamSize),
+      EfiACPIMemoryNVS
+      );
+
+    //
+    // SEC stores its table of GUIDed section handlers here.
+    //
+    BuildMemoryAllocationHob (
+      PcdGet64 (PcdGuidedExtractHandlerTableAddress),
+      PcdGet32 (PcdGuidedExtractHandlerTableSize),
+      EfiACPIMemoryNVS
+      );
+
+ #ifdef MDE_CPU_X64
+    //
+    // Reserve the initial page tables built by the reset vector code.
+    //
+    // Since this memory range will be used by the Reset Vector on S3
+    // resume, it must be reserved as ACPI NVS.
+    //
+    BuildMemoryAllocationHob (
+      (EFI_PHYSICAL_ADDRESS)(UINTN)PcdGet32 (PcdOvmfSecPageTablesBase),
+      (UINT64)(UINTN)PcdGet32 (PcdOvmfSecPageTablesSize),
+      EfiACPIMemoryNVS
+      );
+
+    if (PlatformInfoHob->SevEsIsEnabled) {
+      //
+      // If SEV-ES is enabled, reserve the GHCB-related memory area. This
+      // includes the extra page table used to break down the 2MB page
+      // mapping into 4KB page entries where the GHCB resides and the
+      // GHCB area itself.
+      //
+      // Since this memory range will be used by the Reset Vector on S3
+      // resume, it must be reserved as ACPI NVS.
+      //
+      BuildMemoryAllocationHob (
+        (EFI_PHYSICAL_ADDRESS)(UINTN)PcdGet32 (PcdOvmfSecGhcbPageTableBase),
+        (UINT64)(UINTN)PcdGet32 (PcdOvmfSecGhcbPageTableSize),
+        EfiACPIMemoryNVS
+        );
+      BuildMemoryAllocationHob (
+        (EFI_PHYSICAL_ADDRESS)(UINTN)PcdGet32 (PcdOvmfSecGhcbBase),
+        (UINT64)(UINTN)PcdGet32 (PcdOvmfSecGhcbSize),
+        EfiACPIMemoryNVS
+        );
+      BuildMemoryAllocationHob (
+        (EFI_PHYSICAL_ADDRESS)(UINTN)PcdGet32 (PcdOvmfSecGhcbBackupBase),
+        (UINT64)(UINTN)PcdGet32 (PcdOvmfSecGhcbBackupSize),
+        EfiACPIMemoryNVS
+        );
+    }
+
+ #endif
+  }
+
+  if (PlatformInfoHob->BootMode != BOOT_ON_S3_RESUME) {
+    if (!PlatformInfoHob->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)PcdGet32 (PcdOvmfLockBoxStorageBase),
+        (UINTN)PcdGet32 (PcdOvmfLockBoxStorageSize)
+        );
+      BuildMemoryAllocationHob (
+        (EFI_PHYSICAL_ADDRESS)(UINTN)PcdGet32 (PcdOvmfLockBoxStorageBase),
+        (UINT64)(UINTN)PcdGet32 (PcdOvmfLockBoxStorageSize),
+        PlatformInfoHob->S3Supported ? EfiACPIMemoryNVS : EfiBootServicesData
+        );
+    }
+
+    if (PlatformInfoHob->SmmSmramRequire) {
+      UINT32  TsegSize;
+
+      //
+      // Make sure the TSEG area that we reported as a reserved memory resource
+      // cannot be used for reserved memory allocations.
+      //
+      TsegSize = PlatformInfoHob->Q35TsegMbytes * SIZE_1MB;
+      BuildMemoryAllocationHob (
+        PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob) - TsegSize,
+        TsegSize,
+        EfiReservedMemoryType
+        );
+      //
+      // Similarly, allocate away the (already reserved) SMRAM at the default
+      // SMBASE, if it exists.
+      //
+      if (PlatformInfoHob->Q35SmramAtDefaultSmbase) {
+        BuildMemoryAllocationHob (
+          SMM_DEFAULT_SMBASE,
+          MCH_DEFAULT_SMBASE_SIZE,
+          EfiReservedMemoryType
+          );
+      }
+    }
+
+ #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),
+        PlatformInfoHob->S3Supported ? EfiACPIMemoryNVS : EfiBootServicesData
+        );
+    }
+
+ #endif
+  }
+}
diff --git a/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf b/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
index 21813458cb59..19a88d363819 100644
--- a/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
+++ b/OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
@@ -24,15 +24,64 @@
 
 [Sources]
   Cmos.c
+  MemDetect.c
   Platform.c
 
 [Packages]
+  EmbeddedPkg/EmbeddedPkg.dec
   MdeModulePkg/MdeModulePkg.dec
   MdePkg/MdePkg.dec
   OvmfPkg/OvmfPkg.dec
+  UefiCpuPkg/UefiCpuPkg.dec
 
 [LibraryClasses]
   BaseLib
   DebugLib
   IoLib
   HobLib
+  QemuFwCfgLib
+  QemuFwCfgSimpleParserLib
+  MtrrLib
+  PcdLib
+  PciLib
+
+[FixedPcd]
+  gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfWorkAreaBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfWorkAreaSize
+  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
+  gUefiOvmfPkgTokenSpaceGuid.PcdXenPvhStartOfDayStructPtr
+  gUefiOvmfPkgTokenSpaceGuid.PcdXenPvhStartOfDayStructPtrSize
+  gEfiMdePkgTokenSpaceGuid.PcdGuidedExtractHandlerTableAddress
+  gUefiOvmfPkgTokenSpaceGuid.PcdGuidedExtractHandlerTableSize
+
+[FeaturePcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode
diff --git a/OvmfPkg/PlatformPei/MemDetect.c b/OvmfPkg/PlatformPei/MemDetect.c
index 23a583ed3386..61d7d3059f7b 100644
--- a/OvmfPkg/PlatformPei/MemDetect.c
+++ b/OvmfPkg/PlatformPei/MemDetect.c
@@ -34,7 +34,7 @@ Module Name:
 #include <Library/PciLib.h>
 #include <Library/PeimEntryPoint.h>
 #include <Library/ResourcePublicationLib.h>
-#include <Library/MtrrLib.h>
+
 #include <Library/QemuFwCfgLib.h>
 #include <Library/QemuFwCfgSimpleParserLib.h>
 
@@ -124,501 +124,6 @@ Q35SmramAtDefaultSmbaseInitialization (
   ASSERT_RETURN_ERROR (PcdStatus);
 }
 
-VOID
-EFIAPI
-PlatformQemuUc32BaseInitialization (
-  IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
-  )
-{
-  UINT32  LowerMemorySize;
-
-  if (PlatformInfoHob->HostBridgeDevId == 0xffff /* microvm */) {
-    return;
-  }
-
-  if (PlatformInfoHob->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);
-    PlatformInfoHob->Uc32Base = (UINT32)FixedPcdGet64 (PcdPciExpressBaseAddress);
-    return;
-  }
-
-  if (PlatformInfoHob->HostBridgeDevId == CLOUDHV_DEVICE_ID) {
-    PlatformInfoHob->Uc32Size = CLOUDHV_MMIO_HOLE_SIZE;
-    PlatformInfoHob->Uc32Base = CLOUDHV_MMIO_HOLE_ADDRESS;
-    return;
-  }
-
-  ASSERT (PlatformInfoHob->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.
-  //
-  LowerMemorySize           = PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob);
-  PlatformInfoHob->Uc32Size = GetPowerOfTwo32 ((UINT32)(SIZE_4GB - LowerMemorySize));
-  PlatformInfoHob->Uc32Base = (UINT32)(SIZE_4GB - PlatformInfoHob->Uc32Size);
-  //
-  // Assuming that LowerMemorySize is at least 1 byte, Uc32Size is at most 2GB.
-  // Therefore mQemuUc32Base is at least 2GB.
-  //
-  ASSERT (PlatformInfoHob->Uc32Base >= BASE_2GB);
-
-  if (PlatformInfoHob->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,
-      PlatformInfoHob->Uc32Base,
-      PlatformInfoHob->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 PlatformScanOrAdd64BitE820Ram()
-                          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
-PlatformScanOrAdd64BitE820Ram (
-  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;
-}
-
-/**
-  Returns PVH memmap
-
-  @param Entries      Pointer to PVH memmap
-  @param Count        Number of entries
-
-  @return EFI_STATUS
-**/
-EFI_STATUS
-GetPvhMemmapEntries (
-  struct hvm_memmap_table_entry  **Entries,
-  UINT32                         *Count
-  )
-{
-  UINT32                 *PVHResetVectorData;
-  struct hvm_start_info  *pvh_start_info;
-
-  PVHResetVectorData = (VOID *)(UINTN)PcdGet32 (PcdXenPvhStartOfDayStructPtr);
-  if (PVHResetVectorData == 0) {
-    return EFI_NOT_FOUND;
-  }
-
-  pvh_start_info = (struct hvm_start_info *)(UINTN)PVHResetVectorData[0];
-
-  *Entries = (struct hvm_memmap_table_entry *)(UINTN)pvh_start_info->memmap_paddr;
-  *Count   = pvh_start_info->memmap_entries;
-
-  return EFI_SUCCESS;
-}
-
-STATIC
-UINT64
-GetHighestSystemMemoryAddressFromPvhMemmap (
-  BOOLEAN  Below4gb
-  )
-{
-  struct hvm_memmap_table_entry  *Memmap;
-  UINT32                         MemmapEntriesCount;
-  struct hvm_memmap_table_entry  *Entry;
-  EFI_STATUS                     Status;
-  UINT32                         Loop;
-  UINT64                         HighestAddress;
-  UINT64                         EntryEnd;
-
-  HighestAddress = 0;
-
-  Status = GetPvhMemmapEntries (&Memmap, &MemmapEntriesCount);
-  ASSERT_EFI_ERROR (Status);
-
-  for (Loop = 0; Loop < MemmapEntriesCount; Loop++) {
-    Entry    = Memmap + Loop;
-    EntryEnd = Entry->addr + Entry->size;
-
-    if ((Entry->type == XEN_HVM_MEMMAP_TYPE_RAM) &&
-        (EntryEnd > HighestAddress))
-    {
-      if (Below4gb && (EntryEnd <= BASE_4GB)) {
-        HighestAddress = EntryEnd;
-      } else if (!Below4gb && (EntryEnd >= BASE_4GB)) {
-        HighestAddress = EntryEnd;
-      }
-    }
-  }
-
-  return HighestAddress;
-}
-
-UINT32
-EFIAPI
-PlatformGetSystemMemorySizeBelow4gb (
-  IN EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
-  )
-{
-  EFI_STATUS  Status;
-  UINT64      LowerMemorySize = 0;
-  UINT8       Cmos0x34;
-  UINT8       Cmos0x35;
-
-  if (PlatformInfoHob->HostBridgeDevId == CLOUDHV_DEVICE_ID) {
-    // Get the information from PVH memmap
-    return (UINT32)GetHighestSystemMemoryAddressFromPvhMemmap (TRUE);
-  }
-
-  Status = PlatformScanOrAdd64BitE820Ram (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
-PlatformGetSystemMemorySizeAbove4gb (
-  )
-{
-  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
-PlatformGetFirstNonAddress (
-  IN OUT  EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
-  )
-{
-  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 = PlatformScanOrAdd64BitE820Ram (FALSE, NULL, &FirstNonAddress);
-  if (EFI_ERROR (Status)) {
-    FirstNonAddress = BASE_4GB + PlatformGetSystemMemorySizeAbove4gb ();
-  }
-
-  //
-  // 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
-
-  //
-  // 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) {
-        PlatformInfoHob->PcdPciMmio64Size = 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 (PlatformInfoHob->PcdPciMmio64Size == 0) {
-    if (PlatformInfoHob->BootMode != BOOT_ON_S3_RESUME) {
-      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.
-  //
-  PlatformInfoHob->PcdPciMmio64Base = ALIGN_VALUE (FirstNonAddress, (UINT64)SIZE_1GB);
-  PlatformInfoHob->PcdPciMmio64Size = ALIGN_VALUE (PlatformInfoHob->PcdPciMmio64Size, (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.
-  //
-  PlatformInfoHob->PcdPciMmio64Base = ALIGN_VALUE (PlatformInfoHob->PcdPciMmio64Base, GetPowerOfTwo64 (PlatformInfoHob->PcdPciMmio64Size));
-
-  //
-  // The useful address space ends with the 64-bit PCI host aperture.
-  //
-  FirstNonAddress = PlatformInfoHob->PcdPciMmio64Base + PlatformInfoHob->PcdPciMmio64Size;
-  return FirstNonAddress;
-}
-
-/**
-  Initialize the PhysMemAddressWidth field in PlatformInfoHob based on guest RAM size.
-**/
-VOID
-EFIAPI
-PlatformAddressWidthInitialization (
-  IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
-  )
-{
-  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.
-  //
-  FirstNonAddress     = PlatformGetFirstNonAddress (PlatformInfoHob);
-  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);
-
-  PlatformInfoHob->FirstNonAddress     = FirstNonAddress;
-  PlatformInfoHob->PhysMemAddressWidth = PhysMemAddressWidth;
-}
-
 /**
   Initialize the PhysMemAddressWidth field in PlatformInfoHob based on guest RAM size.
 **/
@@ -840,313 +345,6 @@ PublishPeiMemory (
   return Status;
 }
 
-STATIC
-VOID
-QemuInitializeRamBelow1gb (
-  IN EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
-  )
-{
-  if (PlatformInfoHob->SmmSmramRequire && PlatformInfoHob->Q35SmramAtDefaultSmbase) {
-    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
-PlatformQemuInitializeRam (
-  IN EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
-  )
-{
-  UINT64         LowerMemorySize;
-  UINT64         UpperMemorySize;
-  MTRR_SETTINGS  MtrrSettings;
-  EFI_STATUS     Status;
-
-  DEBUG ((DEBUG_INFO, "%a called\n", __FUNCTION__));
-
-  //
-  // Determine total memory size available
-  //
-  LowerMemorySize = PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob);
-
-  if (PlatformInfoHob->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.
-    //
-    QemuInitializeRamBelow1gb (PlatformInfoHob);
-  } else {
-    //
-    // Create memory HOBs
-    //
-    QemuInitializeRamBelow1gb (PlatformInfoHob);
-
-    if (PlatformInfoHob->SmmSmramRequire) {
-      UINT32  TsegSize;
-
-      TsegSize = PlatformInfoHob->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 = PlatformScanOrAdd64BitE820Ram (TRUE, NULL, NULL);
-    if (EFI_ERROR (Status)) {
-      UpperMemorySize = PlatformGetSystemMemorySizeAbove4gb ();
-      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 () && (PlatformInfoHob->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 (
-               PlatformInfoHob->Uc32Base,
-               SIZE_4GB - PlatformInfoHob->Uc32Base,
-               CacheUncacheable
-               );
-    ASSERT_EFI_ERROR (Status);
-  }
-}
-
-STATIC
-VOID
-PlatformQemuInitializeRamForS3 (
-  IN EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
-  )
-{
-  if (PlatformInfoHob->S3Supported && (PlatformInfoHob->BootMode != BOOT_ON_S3_RESUME)) {
-    //
-    // This is the memory range that will be used for PEI on S3 resume
-    //
-    BuildMemoryAllocationHob (
-      PlatformInfoHob->S3AcpiReservedMemoryBase,
-      PlatformInfoHob->S3AcpiReservedMemorySize,
-      EfiACPIMemoryNVS
-      );
-
-    //
-    // Cover the initial RAM area used as stack and temporary PEI heap.
-    //
-    // This is reserved as ACPI NVS so it can be used on S3 resume.
-    //
-    BuildMemoryAllocationHob (
-      PcdGet32 (PcdOvmfSecPeiTempRamBase),
-      PcdGet32 (PcdOvmfSecPeiTempRamSize),
-      EfiACPIMemoryNVS
-      );
-
-    //
-    // SEC stores its table of GUIDed section handlers here.
-    //
-    BuildMemoryAllocationHob (
-      PcdGet64 (PcdGuidedExtractHandlerTableAddress),
-      PcdGet32 (PcdGuidedExtractHandlerTableSize),
-      EfiACPIMemoryNVS
-      );
-
- #ifdef MDE_CPU_X64
-    //
-    // Reserve the initial page tables built by the reset vector code.
-    //
-    // Since this memory range will be used by the Reset Vector on S3
-    // resume, it must be reserved as ACPI NVS.
-    //
-    BuildMemoryAllocationHob (
-      (EFI_PHYSICAL_ADDRESS)(UINTN)PcdGet32 (PcdOvmfSecPageTablesBase),
-      (UINT64)(UINTN)PcdGet32 (PcdOvmfSecPageTablesSize),
-      EfiACPIMemoryNVS
-      );
-
-    if (PlatformInfoHob->SevEsIsEnabled) {
-      //
-      // If SEV-ES is enabled, reserve the GHCB-related memory area. This
-      // includes the extra page table used to break down the 2MB page
-      // mapping into 4KB page entries where the GHCB resides and the
-      // GHCB area itself.
-      //
-      // Since this memory range will be used by the Reset Vector on S3
-      // resume, it must be reserved as ACPI NVS.
-      //
-      BuildMemoryAllocationHob (
-        (EFI_PHYSICAL_ADDRESS)(UINTN)PcdGet32 (PcdOvmfSecGhcbPageTableBase),
-        (UINT64)(UINTN)PcdGet32 (PcdOvmfSecGhcbPageTableSize),
-        EfiACPIMemoryNVS
-        );
-      BuildMemoryAllocationHob (
-        (EFI_PHYSICAL_ADDRESS)(UINTN)PcdGet32 (PcdOvmfSecGhcbBase),
-        (UINT64)(UINTN)PcdGet32 (PcdOvmfSecGhcbSize),
-        EfiACPIMemoryNVS
-        );
-      BuildMemoryAllocationHob (
-        (EFI_PHYSICAL_ADDRESS)(UINTN)PcdGet32 (PcdOvmfSecGhcbBackupBase),
-        (UINT64)(UINTN)PcdGet32 (PcdOvmfSecGhcbBackupSize),
-        EfiACPIMemoryNVS
-        );
-    }
-
- #endif
-  }
-
-  if (PlatformInfoHob->BootMode != BOOT_ON_S3_RESUME) {
-    if (!PlatformInfoHob->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)PcdGet32 (PcdOvmfLockBoxStorageBase),
-        (UINTN)PcdGet32 (PcdOvmfLockBoxStorageSize)
-        );
-      BuildMemoryAllocationHob (
-        (EFI_PHYSICAL_ADDRESS)(UINTN)PcdGet32 (PcdOvmfLockBoxStorageBase),
-        (UINT64)(UINTN)PcdGet32 (PcdOvmfLockBoxStorageSize),
-        PlatformInfoHob->S3Supported ? EfiACPIMemoryNVS : EfiBootServicesData
-        );
-    }
-
-    if (PlatformInfoHob->SmmSmramRequire) {
-      UINT32  TsegSize;
-
-      //
-      // Make sure the TSEG area that we reported as a reserved memory resource
-      // cannot be used for reserved memory allocations.
-      //
-      TsegSize = PlatformInfoHob->Q35TsegMbytes * SIZE_1MB;
-      BuildMemoryAllocationHob (
-        PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob) - TsegSize,
-        TsegSize,
-        EfiReservedMemoryType
-        );
-      //
-      // Similarly, allocate away the (already reserved) SMRAM at the default
-      // SMBASE, if it exists.
-      //
-      if (PlatformInfoHob->Q35SmramAtDefaultSmbase) {
-        BuildMemoryAllocationHob (
-          SMM_DEFAULT_SMBASE,
-          MCH_DEFAULT_SMBASE_SIZE,
-          EfiReservedMemoryType
-          );
-      }
-    }
-
- #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),
-        PlatformInfoHob->S3Supported ? EfiACPIMemoryNVS : EfiBootServicesData
-        );
-    }
-
- #endif
-  }
-}
-
 /**
   Publish system RAM and reserve memory regions
 
diff --git a/OvmfPkg/PlatformPei/Platform.h b/OvmfPkg/PlatformPei/Platform.h
index 635d58379a24..3d148893401a 100644
--- a/OvmfPkg/PlatformPei/Platform.h
+++ b/OvmfPkg/PlatformPei/Platform.h
@@ -34,18 +34,6 @@ PublishPeiMemory (
   VOID
   );
 
-UINT32
-EFIAPI
-PlatformGetSystemMemorySizeBelow4gb (
-  IN EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
-  );
-
-VOID
-EFIAPI
-PlatformQemuUc32BaseInitialization (
-  IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
-  );
-
 VOID
 InitializeRamRegions (
   IN EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
-- 
2.29.2.windows.2


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH V12 30/47] OvmfPkg/PlatformInitLib: Move functions to Platform.c
  2022-03-29 23:45 [PATCH V12 00/47] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (28 preceding siblings ...)
  2022-03-29 23:46 ` [PATCH V12 29/47] OvmfPkg/PlatformInitLib: Create MemDetect.c Min Xu
@ 2022-03-29 23:46 ` Min Xu
  2022-03-29 23:46 ` [PATCH V12 31/47] OvmfPkg: Update PlatformInitLib to process Tdx hoblist Min Xu
                   ` (10 subsequent siblings)
  40 siblings, 0 replies; 53+ messages in thread
From: Min Xu @ 2022-03-29 23:46 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky, Gerd Hoffmann,
	Sebastien Boeuf

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3863

Move functions in PlatformPei/Platform.c to PlatformInitLib/Platform.c.

Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Sebastien Boeuf <sebastien.boeuf@intel.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/Include/Library/PlatformInitLib.h  |  34 ++
 OvmfPkg/Library/PlatformInitLib/Platform.c | 465 +++++++++++++++++++++
 OvmfPkg/PlatformPei/Platform.c             | 451 --------------------
 3 files changed, 499 insertions(+), 451 deletions(-)

diff --git a/OvmfPkg/Include/Library/PlatformInitLib.h b/OvmfPkg/Include/Library/PlatformInitLib.h
index 62020efadf37..b31f521578c2 100644
--- a/OvmfPkg/Include/Library/PlatformInitLib.h
+++ b/OvmfPkg/Include/Library/PlatformInitLib.h
@@ -169,4 +169,38 @@ PlatformQemuInitializeRamForS3 (
   IN EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
   );
 
+VOID
+EFIAPI
+PlatformMemMapInitialization (
+  IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
+  );
+
+/**
+ * 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 (
+  IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
+  );
+
+VOID
+EFIAPI
+PlatformMiscInitialization (
+  IN EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
+  );
+
+/**
+  Fetch the boot CPU count and the possible CPU count from QEMU, and expose
+  them to UefiCpuPkg modules.
+**/
+VOID
+EFIAPI
+PlatformMaxCpuCountInitialization (
+  IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
+  );
+
 #endif // PLATFORM_INIT_LIB_H_
diff --git a/OvmfPkg/Library/PlatformInitLib/Platform.c b/OvmfPkg/Library/PlatformInitLib/Platform.c
index e41f230ff563..c4fa7d445394 100644
--- a/OvmfPkg/Library/PlatformInitLib/Platform.c
+++ b/OvmfPkg/Library/PlatformInitLib/Platform.c
@@ -19,6 +19,18 @@
 #include <Library/BaseLib.h>
 #include <Library/DebugLib.h>
 #include <Library/HobLib.h>
+#include <Library/IoLib.h>
+#include <IndustryStandard/I440FxPiix4.h>
+#include <IndustryStandard/Microvm.h>
+#include <IndustryStandard/Pci22.h>
+#include <IndustryStandard/Q35MchIch9.h>
+#include <IndustryStandard/QemuCpuHotplug.h>
+#include <Library/QemuFwCfgLib.h>
+#include <Library/QemuFwCfgS3Lib.h>
+#include <Library/QemuFwCfgSimpleParserLib.h>
+#include <Library/PciLib.h>
+#include <OvmfPlatforms.h>
+
 #include <Library/PlatformInitLib.h>
 
 VOID
@@ -104,3 +116,456 @@ PlatformAddMemoryRangeHob (
 {
   PlatformAddMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase));
 }
+
+VOID
+EFIAPI
+PlatformMemMapInitialization (
+  IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
+  )
+{
+  UINT64  PciIoBase;
+  UINT64  PciIoSize;
+  UINT32  TopOfLowRam;
+  UINT64  PciExBarBase;
+  UINT32  PciBase;
+  UINT32  PciSize;
+
+  PciIoBase = 0xC000;
+  PciIoSize = 0x4000;
+
+  //
+  // Video memory + Legacy BIOS region
+  //
+  PlatformAddIoMemoryRangeHob (0x0A0000, BASE_1MB);
+
+  if (PlatformInfoHob->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 (PlatformInfoHob);
+  PciExBarBase = 0;
+  if (PlatformInfoHob->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 <= PlatformInfoHob->Uc32Base);
+    PciBase = PlatformInfoHob->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);
+
+  PlatformInfoHob->PcdPciMmio32Base = PciBase;
+  PlatformInfoHob->PcdPciMmio32Size = PciSize;
+
+  PlatformAddIoMemoryBaseSizeHob (0xFEC00000, SIZE_4KB);
+  PlatformAddIoMemoryBaseSizeHob (0xFED00000, SIZE_1KB);
+  if (PlatformInfoHob->HostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
+    PlatformAddIoMemoryBaseSizeHob (ICH9_ROOT_COMPLEX_BASE, SIZE_16KB);
+    //
+    // Note: there should be an
+    //
+    //   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
+    // "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 (PcdGet32 (PcdCpuLocalApicBaseAddress), SIZE_1MB);
+
+  //
+  // On Q35, the IO Port space is available for PCI resource allocations from
+  // 0x6000 up.
+  //
+  if (PlatformInfoHob->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
+    );
+
+  PlatformInfoHob->PcdPciIoBase = PciIoBase;
+  PlatformInfoHob->PcdPciIoSize = 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 (
+  IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
+  )
+{
+  return QemuFwCfgParseBool ("opt/ovmf/PcdSetNxForStack", &PlatformInfoHob->PcdSetNxForStack);
+}
+
+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
+    );
+}
+
+VOID
+EFIAPI
+PlatformMiscInitialization (
+  IN EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
+  )
+{
+  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 (PlatformInfoHob->PhysMemAddressWidth, 16);
+
+  //
+  // Determine platform type and save Host Bridge DID to PCD
+  //
+  switch (PlatformInfoHob->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;
+    case CLOUDHV_DEVICE_ID:
+      break;
+    default:
+      DEBUG ((
+        DEBUG_ERROR,
+        "%a: Unknown Host Bridge Device ID: 0x%04x\n",
+        __FUNCTION__,
+        PlatformInfoHob->HostBridgeDevId
+        ));
+      ASSERT (FALSE);
+      return;
+  }
+
+  if (PlatformInfoHob->HostBridgeDevId == CLOUDHV_DEVICE_ID) {
+    DEBUG ((DEBUG_INFO, "%a: Cloud Hypervisor is done.\n", __FUNCTION__));
+    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 (PlatformInfoHob->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, and expose
+  them to UefiCpuPkg modules.
+**/
+VOID
+EFIAPI
+PlatformMaxCpuCountInitialization (
+  IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
+  )
+{
+  UINT16  BootCpuCount;
+  UINT32  MaxCpuCount;
+
+  //
+  // 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 = PlatformInfoHob->DefaultMaxCpuNumber;
+  } 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 = ((PlatformInfoHob->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);
+
+  PlatformInfoHob->PcdCpuMaxLogicalProcessorNumber  = MaxCpuCount;
+  PlatformInfoHob->PcdCpuBootLogicalProcessorNumber = BootCpuCount;
+}
diff --git a/OvmfPkg/PlatformPei/Platform.c b/OvmfPkg/PlatformPei/Platform.c
index 02697c473d01..f05aec599fcb 100644
--- a/OvmfPkg/PlatformPei/Platform.c
+++ b/OvmfPkg/PlatformPei/Platform.c
@@ -51,129 +51,6 @@ EFI_PEI_PPI_DESCRIPTOR  mPpiBootMode[] = {
   }
 };
 
-VOID
-EFIAPI
-PlatformMemMapInitialization (
-  IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
-  )
-{
-  UINT64  PciIoBase;
-  UINT64  PciIoSize;
-  UINT32  TopOfLowRam;
-  UINT64  PciExBarBase;
-  UINT32  PciBase;
-  UINT32  PciSize;
-
-  PciIoBase = 0xC000;
-  PciIoSize = 0x4000;
-
-  //
-  // Video memory + Legacy BIOS region
-  //
-  PlatformAddIoMemoryRangeHob (0x0A0000, BASE_1MB);
-
-  if (PlatformInfoHob->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 (PlatformInfoHob);
-  PciExBarBase = 0;
-  if (PlatformInfoHob->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 <= PlatformInfoHob->Uc32Base);
-    PciBase = PlatformInfoHob->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);
-
-  PlatformInfoHob->PcdPciMmio32Base = PciBase;
-  PlatformInfoHob->PcdPciMmio32Size = PciSize;
-
-  PlatformAddIoMemoryBaseSizeHob (0xFEC00000, SIZE_4KB);
-  PlatformAddIoMemoryBaseSizeHob (0xFED00000, SIZE_1KB);
-  if (PlatformInfoHob->HostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
-    PlatformAddIoMemoryBaseSizeHob (ICH9_ROOT_COMPLEX_BASE, SIZE_16KB);
-    //
-    // Note: there should be an
-    //
-    //   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
-    // "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 (PcdGet32 (PcdCpuLocalApicBaseAddress), SIZE_1MB);
-
-  //
-  // On Q35, the IO Port space is available for PCI resource allocations from
-  // 0x6000 up.
-  //
-  if (PlatformInfoHob->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
-    );
-
-  PlatformInfoHob->PcdPciIoBase = PciIoBase;
-  PlatformInfoHob->PcdPciIoSize = PciIoSize;
-}
-
 VOID
 MemMapInitialization (
   IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
@@ -198,21 +75,6 @@ MemMapInitialization (
   ASSERT_RETURN_ERROR (PcdStatus);
 }
 
-/**
- * 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 (
-  IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
-  )
-{
-  return QemuFwCfgParseBool ("opt/ovmf/PcdSetNxForStack", &PlatformInfoHob->PcdSetNxForStack);
-}
-
 VOID
 NoexecDxeInitialization (
   VOID
@@ -227,47 +89,6 @@ NoexecDxeInitialization (
   }
 }
 
-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
-    );
-}
-
 static const UINT8  EmptyFdt[] = {
   0xd0, 0x0d, 0xfe, 0xed, 0x00, 0x00, 0x00, 0x48,
   0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x48,
@@ -359,107 +180,6 @@ MiscInitializationForMicrovm (
   ASSERT_RETURN_ERROR (PcdStatus);
 }
 
-VOID
-PlatformMiscInitialization (
-  IN EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
-  )
-{
-  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 (PlatformInfoHob->PhysMemAddressWidth, 16);
-
-  //
-  // Determine platform type and save Host Bridge DID to PCD
-  //
-  switch (PlatformInfoHob->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;
-    case CLOUDHV_DEVICE_ID:
-      break;
-    default:
-      DEBUG ((
-        DEBUG_ERROR,
-        "%a: Unknown Host Bridge Device ID: 0x%04x\n",
-        __FUNCTION__,
-        PlatformInfoHob->HostBridgeDevId
-        ));
-      ASSERT (FALSE);
-      return;
-  }
-
-  if (PlatformInfoHob->HostBridgeDevId == CLOUDHV_DEVICE_ID) {
-    DEBUG ((DEBUG_INFO, "%a: Cloud Hypervisor is done.\n", __FUNCTION__));
-    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 (PlatformInfoHob->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 ();
-  }
-}
-
 VOID
 MiscInitialization (
   IN EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
@@ -571,177 +291,6 @@ Q35BoardVerification (
   CpuDeadLoop ();
 }
 
-/**
-  Fetch the boot CPU count and the possible CPU count from QEMU, and expose
-  them to UefiCpuPkg modules. Set the MaxCpuCount field in PlatformInfoHob.
-**/
-VOID
-PlatformMaxCpuCountInitialization (
-  IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
-  )
-{
-  UINT16  BootCpuCount;
-  UINT32  MaxCpuCount;
-
-  //
-  // 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 = PlatformInfoHob->DefaultMaxCpuNumber;
-  } 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 = ((PlatformInfoHob->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);
-
-  PlatformInfoHob->PcdCpuMaxLogicalProcessorNumber  = MaxCpuCount;
-  PlatformInfoHob->PcdCpuBootLogicalProcessorNumber = BootCpuCount;
-}
-
 /**
   Fetch the boot CPU count and the possible CPU count from QEMU, and expose
   them to UefiCpuPkg modules. Set the MaxCpuCount field in PlatformInfoHob.
-- 
2.29.2.windows.2


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH V12 31/47] OvmfPkg: Update PlatformInitLib to process Tdx hoblist
  2022-03-29 23:45 [PATCH V12 00/47] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (29 preceding siblings ...)
  2022-03-29 23:46 ` [PATCH V12 30/47] OvmfPkg/PlatformInitLib: Move functions to Platform.c Min Xu
@ 2022-03-29 23:46 ` Min Xu
  2022-03-29 23:46 ` [PATCH V12 32/47] OvmfPkg/Sec: Declare local variable as volatile in SecCoreStartupWithStack Min Xu
                   ` (9 subsequent siblings)
  40 siblings, 0 replies; 53+ messages in thread
From: Min Xu @ 2022-03-29 23:46 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky, Gerd Hoffmann

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

When host VMM create the Td guest, the system memory informations are
stored in TdHob, which is a memory region described in Tdx metadata.
The system memory region in TdHob should be accepted before it can be
accessed. So the newly added function (ProcessTdxHobList) is to process
the TdHobList to accept the memory. Because TdHobList is provided by
host VMM which is not trusted, so its content should be checked before
it is consumed by TDVF.

Because ProcessTdxHobList is to be called in SEC phase, so
PlatformInitLib.inf is updated to support SEC.

Note: In this patch it is BSP which accepts the pages. So there maybe
boot performance issue. There are some mitigations to this issue, such
as lazy accept, 2M accept page size, etc. We will re-visit here in the
future.

EFI_RESOURCE_MEMORY_UNACCEPTED is a new ResourceType in
EFI_HOB_RESOURCE_DESCRIPTOR. It is defined for the unaccepted memory
passed from Host VMM. This is proposed in microsoft/mu_basecore#66
files#diff-b20a11152d1ce9249c691be5690b4baf52069efadf2e2546cdd2eb663d80c9
e4R237 according to UEFI-Code-First. The proposal was approved in 2021
in UEFI Mantis, and will be added to the new PI.next specification.

Per the MdePkg reviewer's comments, before this new ResourceType is
added in the PI spec, it should not be in MdePkg. So it is now
defined as an internal implementation and will be moved to
MdePkg/Include/Pi/PiHob.h after it is added in PI spec.
See https://edk2.groups.io/g/devel/message/87641

PcdTdxAcceptPageSize is added for page accepting. Currently TDX supports
4K and 2M accept page size. The default value is 2M.

Tdx guest is only supported in X64. So for IA32 ProcessTdxHobList
just returns EFI_UNSUPPORTED.

Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/Include/Library/PlatformInitLib.h     |  17 +
 OvmfPkg/Library/PlatformInitLib/IntelTdx.c    | 514 ++++++++++++++++++
 .../Library/PlatformInitLib/IntelTdxNull.c    |  30 +
 .../PlatformInitLib/PlatformInitLib.inf       |  13 +-
 OvmfPkg/OvmfPkg.dec                           |   3 +
 5 files changed, 576 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 b31f521578c2..6152a43d0da7 100644
--- a/OvmfPkg/Include/Library/PlatformInitLib.h
+++ b/OvmfPkg/Include/Library/PlatformInitLib.h
@@ -203,4 +203,21 @@ PlatformMaxCpuCountInitialization (
   IN OUT EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
   );
 
+/**
+  In Tdx guest, some information need to be passed from host VMM to guest
+  firmware. For example, the memory resource, etc. These information are
+  prepared by host VMM and put in HobList which is described in TdxMetadata.
+
+  Information in HobList is treated as external input. From the security
+  perspective before it is consumed, it should be validated.
+
+  @retval   EFI_SUCCESS   Successfully process the hoblist
+  @retval   Others        Other error as indicated
+**/
+EFI_STATUS
+EFIAPI
+ProcessTdxHobList (
+  VOID
+  );
+
 #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..e9196b7ffaa7
--- /dev/null
+++ b/OvmfPkg/Library/PlatformInitLib/IntelTdx.c
@@ -0,0 +1,514 @@
+/** @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
+#define EFI_RESOURCE_MEMORY_UNACCEPTED  7
+
+/**
+  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[] = {
+    BOOT_WITH_FULL_CONFIGURATION,
+    BOOT_WITH_MINIMAL_CONFIGURATION,
+    BOOT_ASSUMING_NO_CONFIGURATION_CHANGES,
+    BOOT_WITH_FULL_CONFIGURATION_PLUS_DIAGNOSTICS,
+    BOOT_WITH_DEFAULT_SETTINGS,
+    BOOT_ON_S4_RESUME,
+    BOOT_ON_S5_RESUME,
+    BOOT_WITH_MFG_MODE_SETTINGS,
+    BOOT_ON_S2_RESUME,
+    BOOT_ON_S3_RESUME,
+    BOOT_ON_FLASH_UPDATE,
+    BOOT_IN_RECOVERY_MODE
+  };
+
+  UINT32  EFI_RESOURCE_TYPE_LIST[] = {
+    EFI_RESOURCE_SYSTEM_MEMORY,
+    EFI_RESOURCE_MEMORY_MAPPED_IO,
+    EFI_RESOURCE_IO,
+    EFI_RESOURCE_FIRMWARE_DEVICE,
+    EFI_RESOURCE_MEMORY_MAPPED_IO_PORT,
+    EFI_RESOURCE_MEMORY_RESERVED,
+    EFI_RESOURCE_IO_RESERVED,
+    EFI_RESOURCE_MEMORY_UNACCEPTED
+  };
+
+  if (VmmHobList == NULL) {
+    DEBUG ((DEBUG_ERROR, "HOB: HOB data pointer is NULL\n"));
+    return FALSE;
+  }
+
+  Hob.Raw = (UINT8 *)VmmHobList;
+
+  //
+  // Parse the HOB list until end of list or matching type is found.
+  //
+  while (!END_OF_HOB_LIST (Hob)) {
+    if (Hob.Header->Reserved != (UINT32)0) {
+      DEBUG ((DEBUG_ERROR, "HOB: Hob header Reserved filed should be zero\n"));
+      return FALSE;
+    }
+
+    if (Hob.Header->HobLength == 0) {
+      DEBUG ((DEBUG_ERROR, "HOB: Hob header LEANGTH should not be zero\n"));
+      return FALSE;
+    }
+
+    switch (Hob.Header->HobType) {
+      case EFI_HOB_TYPE_HANDOFF:
+        if (Hob.Header->HobLength != sizeof (EFI_HOB_HANDOFF_INFO_TABLE)) {
+          DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_HANDOFF));
+          return FALSE;
+        }
+
+        if (IsInValidList (Hob.HandoffInformationTable->BootMode, EFI_BOOT_MODE_LIST, ARRAY_SIZE (EFI_BOOT_MODE_LIST)) == FALSE) {
+          DEBUG ((DEBUG_ERROR, "HOB: Unknow HandoffInformationTable BootMode type. Type: 0x%08x\n", Hob.HandoffInformationTable->BootMode));
+          return FALSE;
+        }
+
+        if ((Hob.HandoffInformationTable->EfiFreeMemoryTop % 4096) != 0) {
+          DEBUG ((DEBUG_ERROR, "HOB: HandoffInformationTable EfiFreeMemoryTop address must be 4-KB aligned to meet page restrictions of UEFI.\
+                               Address: 0x%016lx\n", Hob.HandoffInformationTable->EfiFreeMemoryTop));
+          return FALSE;
+        }
+
+        break;
+
+      case EFI_HOB_TYPE_RESOURCE_DESCRIPTOR:
+        if (Hob.Header->HobLength != sizeof (EFI_HOB_RESOURCE_DESCRIPTOR)) {
+          DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_RESOURCE_DESCRIPTOR));
+          return FALSE;
+        }
+
+        if (IsInValidList (Hob.ResourceDescriptor->ResourceType, EFI_RESOURCE_TYPE_LIST, ARRAY_SIZE (EFI_RESOURCE_TYPE_LIST)) == FALSE) {
+          DEBUG ((DEBUG_ERROR, "HOB: Unknow ResourceDescriptor ResourceType type. Type: 0x%08x\n", Hob.ResourceDescriptor->ResourceType));
+          return FALSE;
+        }
+
+        if ((Hob.ResourceDescriptor->ResourceAttribute & (~(EFI_RESOURCE_ATTRIBUTE_PRESENT |
+                                                            EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
+                                                            EFI_RESOURCE_ATTRIBUTE_TESTED |
+                                                            EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED |
+                                                            EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED |
+                                                            EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED |
+                                                            EFI_RESOURCE_ATTRIBUTE_PERSISTENT |
+                                                            EFI_RESOURCE_ATTRIBUTE_SINGLE_BIT_ECC |
+                                                            EFI_RESOURCE_ATTRIBUTE_MULTIPLE_BIT_ECC |
+                                                            EFI_RESOURCE_ATTRIBUTE_ECC_RESERVED_1 |
+                                                            EFI_RESOURCE_ATTRIBUTE_ECC_RESERVED_2 |
+                                                            EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
+                                                            EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
+                                                            EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
+                                                            EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE |
+                                                            EFI_RESOURCE_ATTRIBUTE_16_BIT_IO |
+                                                            EFI_RESOURCE_ATTRIBUTE_32_BIT_IO |
+                                                            EFI_RESOURCE_ATTRIBUTE_64_BIT_IO |
+                                                            EFI_RESOURCE_ATTRIBUTE_UNCACHED_EXPORTED |
+                                                            EFI_RESOURCE_ATTRIBUTE_READ_PROTECTABLE |
+                                                            EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTABLE |
+                                                            EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTABLE |
+                                                            EFI_RESOURCE_ATTRIBUTE_PERSISTABLE |
+                                                            EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTED |
+                                                            EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTABLE |
+                                                            EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE))) != 0)
+        {
+          DEBUG ((DEBUG_ERROR, "HOB: Unknow ResourceDescriptor ResourceAttribute type. Type: 0x%08x\n", Hob.ResourceDescriptor->ResourceAttribute));
+          return FALSE;
+        }
+
+        break;
+
+      // EFI_HOB_GUID_TYPE is variable length data, so skip check
+      case EFI_HOB_TYPE_GUID_EXTENSION:
+        break;
+
+      case EFI_HOB_TYPE_FV:
+        if (Hob.Header->HobLength != sizeof (EFI_HOB_FIRMWARE_VOLUME)) {
+          DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_FV));
+          return FALSE;
+        }
+
+        break;
+
+      case EFI_HOB_TYPE_FV2:
+        if (Hob.Header->HobLength != sizeof (EFI_HOB_FIRMWARE_VOLUME2)) {
+          DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_FV2));
+          return FALSE;
+        }
+
+        break;
+
+      case EFI_HOB_TYPE_FV3:
+        if (Hob.Header->HobLength != sizeof (EFI_HOB_FIRMWARE_VOLUME3)) {
+          DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_FV3));
+          return FALSE;
+        }
+
+        break;
+
+      case EFI_HOB_TYPE_CPU:
+        if (Hob.Header->HobLength != sizeof (EFI_HOB_CPU)) {
+          DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_CPU));
+          return FALSE;
+        }
+
+        for (UINT32 index = 0; index < 6; index++) {
+          if (Hob.Cpu->Reserved[index] != 0) {
+            DEBUG ((DEBUG_ERROR, "HOB: Cpu Reserved field will always be set to zero.\n"));
+            return FALSE;
+          }
+        }
+
+        break;
+
+      default:
+        DEBUG ((DEBUG_ERROR, "HOB: Hob type is not know. Type: 0x%04x\n", Hob.Header->HobType));
+        return FALSE;
+    }
+
+    // Get next HOB
+    Hob.Raw = (UINT8 *)(Hob.Raw + Hob.Header->HobLength);
+  }
+
+  return TRUE;
+}
+
+/**
+  Processing the incoming HobList for the TDX
+
+  Firmware must parse list, and accept the pages of memory before their can be
+  use by the guest.
+
+  @param[in] VmmHobList    The Hoblist pass the firmware
+
+  @retval  EFI_SUCCESS     Process the HobList successfully
+  @retval  Others          Other errors as indicated
+
+**/
+EFI_STATUS
+EFIAPI
+ProcessHobList (
+  IN CONST VOID  *VmmHobList
+  )
+{
+  EFI_STATUS            Status;
+  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_MEMORY_UNACCEPTED) {
+        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;
+  EFI_RESOURCE_TYPE            ResourceType;
+  EFI_RESOURCE_ATTRIBUTE_TYPE  ResourceAttribute;
+
+  //
+  // PcdOvmfSecGhcbBase is used as the TD_HOB in Tdx guest.
+  //
+  Hob.Raw = (UINT8 *)(UINTN)FixedPcdGet32 (PcdOvmfSecGhcbBase);
+  while (!END_OF_HOB_LIST (Hob)) {
+    switch (Hob.Header->HobType) {
+      case EFI_HOB_TYPE_RESOURCE_DESCRIPTOR:
+        ResourceType      = Hob.ResourceDescriptor->ResourceType;
+        ResourceAttribute = Hob.ResourceDescriptor->ResourceAttribute;
+
+        if (ResourceType == EFI_RESOURCE_MEMORY_UNACCEPTED) {
+          ResourceType       = EFI_RESOURCE_SYSTEM_MEMORY;
+          ResourceAttribute |= (EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED | EFI_RESOURCE_ATTRIBUTE_TESTED);
+        }
+
+        BuildResourceDescriptorHob (
+          ResourceType,
+          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 19a88d363819..d0fab5cc1f4f 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
@@ -83,5 +92,7 @@
   gEfiMdePkgTokenSpaceGuid.PcdGuidedExtractHandlerTableAddress
   gUefiOvmfPkgTokenSpaceGuid.PcdGuidedExtractHandlerTableSize
 
+  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


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH V12 32/47] OvmfPkg/Sec: Declare local variable as volatile in SecCoreStartupWithStack
  2022-03-29 23:45 [PATCH V12 00/47] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (30 preceding siblings ...)
  2022-03-29 23:46 ` [PATCH V12 31/47] OvmfPkg: Update PlatformInitLib to process Tdx hoblist Min Xu
@ 2022-03-29 23:46 ` Min Xu
  2022-03-29 23:46 ` [PATCH V12 33/47] OvmfPkg: Update Sec to support Tdx Min Xu
                   ` (8 subsequent siblings)
  40 siblings, 0 replies; 53+ messages in thread
From: Min Xu @ 2022-03-29 23:46 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky, Gerd Hoffmann

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@kernel.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 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


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH V12 33/47] OvmfPkg: Update Sec to support Tdx
  2022-03-29 23:45 [PATCH V12 00/47] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (31 preceding siblings ...)
  2022-03-29 23:46 ` [PATCH V12 32/47] OvmfPkg/Sec: Declare local variable as volatile in SecCoreStartupWithStack Min Xu
@ 2022-03-29 23:46 ` Min Xu
  2022-04-15 20:05   ` Lendacky, Thomas
  2022-03-29 23:46 ` [PATCH V12 34/47] OvmfPkg: Check Tdx in QemuFwCfgPei to avoid DMA operation Min Xu
                   ` (7 subsequent siblings)
  40 siblings, 1 reply; 53+ messages in thread
From: Min Xu @ 2022-03-29 23:46 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky, Gerd Hoffmann

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

There are below major changes in this commit.

1. SecEntry.nasm
In TDX BSP and APs goes to the same entry point in SecEntry.nasm.

BSP initialize the temporary stack and then jumps to SecMain, just as
legacy Ovmf does.

APs spin in a modified mailbox loop using initial mailbox structure.
Its structure defition is in OvmfPkg/Include/IndustryStandard/IntelTdx.h.
APs wait for command to see if the command is for me. If so execute the
command.

2. Sec/SecMain.c
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 major task of this patch is to process the TdHobList
to accept the memory. After that TDVF follow the standard OVMF flow
and jump to PEI phase.

PcdUse1GPageTable is set to FALSE by default in OvmfPkgX64.dsc. It gives
no chance for Intel TDX to support 1G page table. To support 1G page
table this PCD is set to TRUE in OvmfPkgX64.dsc.

TDX_GUEST_SUPPORTED is defined in OvmfPkgX64.dsc. This macro wraps the
Tdx specific code.

TDX only works on X64, so the code is only valid in X64 arch.

Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/AmdSev/AmdSevX64.dsc      |  1 +
 OvmfPkg/Bhyve/BhyveX64.dsc        |  1 +
 OvmfPkg/CloudHv/CloudHvX64.dsc    |  1 +
 OvmfPkg/Include/TdxCommondefs.inc | 51 +++++++++++++++++++
 OvmfPkg/Microvm/MicrovmX64.dsc    |  1 +
 OvmfPkg/OvmfPkgIa32X64.dsc        |  2 +
 OvmfPkg/OvmfPkgX64.dsc            | 14 ++++++
 OvmfPkg/OvmfXen.dsc               |  1 +
 OvmfPkg/Sec/SecMain.c             | 29 ++++++++++-
 OvmfPkg/Sec/SecMain.inf           |  3 ++
 OvmfPkg/Sec/X64/SecEntry.nasm     | 82 +++++++++++++++++++++++++++++++
 11 files changed, 184 insertions(+), 2 deletions(-)
 create mode 100644 OvmfPkg/Include/TdxCommondefs.inc

diff --git a/OvmfPkg/AmdSev/AmdSevX64.dsc b/OvmfPkg/AmdSev/AmdSevX64.dsc
index 785049c88962..c173a72134f4 100644
--- a/OvmfPkg/AmdSev/AmdSevX64.dsc
+++ b/OvmfPkg/AmdSev/AmdSevX64.dsc
@@ -208,6 +208,7 @@
 [LibraryClasses.common]
   BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf
   VmgExitLib|OvmfPkg/Library/VmgExitLib/VmgExitLib.inf
+  TdxLib|MdePkg/Library/TdxLib/TdxLib.inf
 
 [LibraryClasses.common.SEC]
   TimerLib|OvmfPkg/Library/AcpiTimerLib/BaseRomAcpiTimerLib.inf
diff --git a/OvmfPkg/Bhyve/BhyveX64.dsc b/OvmfPkg/Bhyve/BhyveX64.dsc
index 5fa08bebd73c..656e407473bb 100644
--- a/OvmfPkg/Bhyve/BhyveX64.dsc
+++ b/OvmfPkg/Bhyve/BhyveX64.dsc
@@ -228,6 +228,7 @@
 [LibraryClasses.common]
   BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf
   VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf
+  TdxLib|MdePkg/Library/TdxLib/TdxLib.inf
 
 [LibraryClasses.common.SEC]
 !ifdef $(DEBUG_ON_SERIAL_PORT)
diff --git a/OvmfPkg/CloudHv/CloudHvX64.dsc b/OvmfPkg/CloudHv/CloudHvX64.dsc
index b8a82380202c..c307f1cc7550 100644
--- a/OvmfPkg/CloudHv/CloudHvX64.dsc
+++ b/OvmfPkg/CloudHv/CloudHvX64.dsc
@@ -237,6 +237,7 @@
 [LibraryClasses.common]
   BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf
   VmgExitLib|OvmfPkg/Library/VmgExitLib/VmgExitLib.inf
+  TdxLib|MdePkg/Library/TdxLib/TdxLib.inf
 
 [LibraryClasses.common.SEC]
   TimerLib|OvmfPkg/Library/AcpiTimerLib/BaseRomAcpiTimerLib.inf
diff --git a/OvmfPkg/Include/TdxCommondefs.inc b/OvmfPkg/Include/TdxCommondefs.inc
new file mode 100644
index 000000000000..970eac96592a
--- /dev/null
+++ b/OvmfPkg/Include/TdxCommondefs.inc
@@ -0,0 +1,51 @@
+;------------------------------------------------------------------------------
+; @file
+; TDX Common defitions used by the APs in mailbox
+;
+; Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+;------------------------------------------------------------------------------
+
+CommandOffset                             equ       00h
+ApicidOffset                              equ       04h
+WakeupVectorOffset                        equ       08h
+OSArgsOffset                              equ       10h
+FirmwareArgsOffset                        equ       800h
+WakeupArgsRelocatedMailBox                equ       800h
+AcceptPageArgsPhysicalStart               equ       800h
+AcceptPageArgsPhysicalEnd                 equ       808h
+AcceptPageArgsChunkSize                   equ       810h
+AcceptPageArgsPageSize                    equ       818h
+CpuArrivalOffset                          equ       900h
+CpusExitingOffset                         equ       0a00h
+TalliesOffset                             equ       0a08h
+ErrorsOffset                              equ       0e08h
+
+SIZE_4KB                                  equ       1000h
+SIZE_2MB                                  equ       200000h
+SIZE_1GB                                  equ       40000000h
+
+PAGE_ACCEPT_LEVEL_4K                      equ       0
+PAGE_ACCEPT_LEVEL_2M                      equ       1
+PAGE_ACCEPT_LEVEL_1G                      equ       2
+
+TDX_PAGE_ALREADY_ACCEPTED                 equ       0x00000b0a
+TDX_PAGE_SIZE_MISMATCH                    equ       0xc0000b0b
+
+; Errors of APs in Mailbox
+ERROR_NON                                 equ       0
+ERROR_INVALID_ACCEPT_PAGE_SIZE            equ       1
+ERROR_ACCEPT_PAGE_ERROR                   equ       2
+ERROR_INVALID_FALLBACK_PAGE_LEVEL         equ       3
+
+MpProtectedModeWakeupCommandNoop          equ       0
+MpProtectedModeWakeupCommandWakeup        equ       1
+MpProtectedModeWakeupCommandSleep         equ       2
+MpProtectedModeWakeupCommandAcceptPages   equ       3
+
+MailboxApicIdInvalid                      equ       0xffffffff
+MailboxApicidBroadcast                    equ       0xfffffffe
+
+%define TDCALL_TDINFO                          0x1
+%define TDCALL_TDACCEPTPAGE                    0x6
diff --git a/OvmfPkg/Microvm/MicrovmX64.dsc b/OvmfPkg/Microvm/MicrovmX64.dsc
index 27005eec89f2..0eac0c02c630 100644
--- a/OvmfPkg/Microvm/MicrovmX64.dsc
+++ b/OvmfPkg/Microvm/MicrovmX64.dsc
@@ -232,6 +232,7 @@
   PlatformHookLib|MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.inf
   FdtLib|EmbeddedPkg/Library/FdtLib/FdtLib.inf
   VirtioMmioDeviceLib|OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDeviceLib.inf
+  TdxLib|MdePkg/Library/TdxLib/TdxLib.inf
 
 [LibraryClasses.common.SEC]
   QemuFwCfgLib|OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgSecLib.inf
diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index c58ef8494470..98a6748c62dd 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -238,6 +238,8 @@
 [LibraryClasses.common]
   BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf
   VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf
+  TdxLib|MdePkg/Library/TdxLib/TdxLib.inf
+  TdxMailboxLib|OvmfPkg/Library/TdxMailboxLib/TdxMailboxLib.inf
 
 [LibraryClasses.common.SEC]
   TimerLib|OvmfPkg/Library/AcpiTimerLib/BaseRomAcpiTimerLib.inf
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index 227b9845619f..2df5b2999610 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -93,6 +93,13 @@
   INTEL:*_*_*_CC_FLAGS = /D DISABLE_NEW_DEPRECATED_INTERFACES
   GCC:*_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES
 
+  #
+  # Add TDX_GUEST_SUPPORTED
+  #
+  MSFT:*_*_*_CC_FLAGS = /D TDX_GUEST_SUPPORTED
+  INTEL:*_*_*_CC_FLAGS = /D TDX_GUEST_SUPPORTED
+  GCC:*_*_*_CC_FLAGS = -D TDX_GUEST_SUPPORTED
+
 !include NetworkPkg/NetworkBuildOptions.dsc.inc
 
 [BuildOptions.common.EDKII.DXE_RUNTIME_DRIVER]
@@ -238,6 +245,8 @@
 [LibraryClasses.common]
   BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf
   VmgExitLib|OvmfPkg/Library/VmgExitLib/VmgExitLib.inf
+  TdxLib|MdePkg/Library/TdxLib/TdxLib.inf
+  TdxMailboxLib|OvmfPkg/Library/TdxMailboxLib/TdxMailboxLib.inf
 
 [LibraryClasses.common.SEC]
   TimerLib|OvmfPkg/Library/AcpiTimerLib/BaseRomAcpiTimerLib.inf
@@ -558,6 +567,10 @@
   gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesCode|0x100
   gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesData|0x100
 
+  #
+  # TDX need 1G PageTable support
+  gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable|TRUE
+
   #
   # Network Pcds
   #
@@ -669,6 +682,7 @@
   OvmfPkg/Sec/SecMain.inf {
     <LibraryClasses>
       NULL|MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaCustomDecompressLib.inf
+      NULL|OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
   }
 
   #
diff --git a/OvmfPkg/OvmfXen.dsc b/OvmfPkg/OvmfXen.dsc
index efa97f09f32b..aa27e2256ae9 100644
--- a/OvmfPkg/OvmfXen.dsc
+++ b/OvmfPkg/OvmfXen.dsc
@@ -227,6 +227,7 @@
 [LibraryClasses.common]
   BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf
   VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf
+  TdxLib|MdePkg/Library/TdxLib/TdxLib.inf
 
 [LibraryClasses.common.SEC]
   QemuFwCfgLib|OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgSecLib.inf
diff --git a/OvmfPkg/Sec/SecMain.c b/OvmfPkg/Sec/SecMain.c
index 02520e25ab9a..ca9717a7b526 100644
--- a/OvmfPkg/Sec/SecMain.c
+++ b/OvmfPkg/Sec/SecMain.c
@@ -26,9 +26,8 @@
 #include <Library/ExtractGuidedSectionLib.h>
 #include <Library/LocalApicLib.h>
 #include <Library/CpuExceptionHandlerLib.h>
-
 #include <Ppi/TemporaryRamSupport.h>
-
+#include <Library/PlatformInitLib.h>
 #include "AmdSev.h"
 
 #define SEC_IDT_ENTRY_COUNT  34
@@ -738,6 +737,20 @@ SecCoreStartupWithStack (
   UINT32                Index;
   volatile UINT8        *Table;
 
+ #if defined (TDX_GUEST_SUPPORTED)
+  if (TdIsEnabled ()) {
+    //
+    // For Td guests, the memory map info is in TdHobLib. It should be processed
+    // first so that the memory is accepted. Otherwise access to the unaccepted
+    // memory will trigger tripple fault.
+    //
+    if (ProcessTdxHobList () != EFI_SUCCESS) {
+      CpuDeadLoop ();
+    }
+  }
+
+ #endif
+
   //
   // To ensure SMM can't be compromised on S3 resume, we must force re-init of
   // the BaseExtractGuidedSectionLib. Since this is before library contructors
@@ -756,6 +769,7 @@ SecCoreStartupWithStack (
   // we use a loop rather than CopyMem.
   //
   IdtTableInStack.PeiService = NULL;
+
   for (Index = 0; Index < SEC_IDT_ENTRY_COUNT; Index++) {
     //
     // Declare the local variables that actually move the data elements as
@@ -813,6 +827,17 @@ SecCoreStartupWithStack (
     AsmEnableCache ();
   }
 
+ #if defined (TDX_GUEST_SUPPORTED)
+  if (TdIsEnabled ()) {
+    //
+    // InitializeCpuExceptionHandlers () should be called in Td guests so that
+    // #VE exceptions can be handled correctly.
+    //
+    InitializeCpuExceptionHandlers (NULL);
+  }
+
+ #endif
+
   DEBUG ((
     DEBUG_INFO,
     "SecCoreStartupWithStack(0x%x, 0x%x)\n",
diff --git a/OvmfPkg/Sec/SecMain.inf b/OvmfPkg/Sec/SecMain.inf
index 95cf0025e100..4b5b089ccd69 100644
--- a/OvmfPkg/Sec/SecMain.inf
+++ b/OvmfPkg/Sec/SecMain.inf
@@ -77,6 +77,9 @@
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfWorkAreaBase
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecValidatedStart
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecValidatedEnd
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdTdxAcceptPageSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfWorkAreaBase
 
 [FeaturePcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire
diff --git a/OvmfPkg/Sec/X64/SecEntry.nasm b/OvmfPkg/Sec/X64/SecEntry.nasm
index 1cc680a70716..4528fec309a0 100644
--- a/OvmfPkg/Sec/X64/SecEntry.nasm
+++ b/OvmfPkg/Sec/X64/SecEntry.nasm
@@ -10,12 +10,17 @@
 ;------------------------------------------------------------------------------
 
 #include <Base.h>
+%include "TdxCommondefs.inc"
 
 DEFAULT REL
 SECTION .text
 
 extern ASM_PFX(SecCoreStartupWithStack)
 
+%macro  tdcall  0
+  db  0x66, 0x0f, 0x01, 0xcc
+%endmacro
+
 ;
 ; SecCore Entry Point
 ;
@@ -35,6 +40,32 @@ extern ASM_PFX(SecCoreStartupWithStack)
 global ASM_PFX(_ModuleEntryPoint)
 ASM_PFX(_ModuleEntryPoint):
 
+    ;
+    ; Guest type is stored in OVMF_WORK_AREA
+    ;
+    %define OVMF_WORK_AREA        FixedPcdGet32 (PcdOvmfWorkAreaBase)
+    %define VM_GUEST_TYPE_TDX     2
+    mov     eax, OVMF_WORK_AREA
+    cmp     byte[eax], VM_GUEST_TYPE_TDX
+    jne     InitStack
+
+    mov     rax, TDCALL_TDINFO
+    tdcall
+
+    ;
+    ; R8  [31:0]  NUM_VCPUS
+    ;     [63:32] MAX_VCPUS
+    ; R9  [31:0]  VCPU_INDEX
+    ; Td Guest set the VCPU0 as the BSP, others are the APs
+    ; APs jump to spinloop and get released by DXE's MpInitLib
+    ;
+    mov     rax, r9
+    and     rax, 0xffff
+    test    rax, rax
+    jne     ParkAp
+
+InitStack:
+
     ;
     ; Fill the temporary RAM with the initial stack value.
     ; The loop below will seed the heap as well, but that's harmless.
@@ -67,3 +98,54 @@ ASM_PFX(_ModuleEntryPoint):
     sub     rsp, 0x20
     call    ASM_PFX(SecCoreStartupWithStack)
 
+    ;
+    ; Note: BSP never gets here. APs will be unblocked by DXE
+    ;
+    ; R8  [31:0]  NUM_VCPUS
+    ;     [63:32] MAX_VCPUS
+    ; R9  [31:0]  VCPU_INDEX
+    ;
+ParkAp:
+
+    mov     rbp,  r9
+
+.do_wait_loop:
+    mov     rsp, FixedPcdGet32 (PcdOvmfSecGhcbBackupBase)
+
+    ;
+    ; register itself in [rsp + CpuArrivalOffset]
+    ;
+    mov       rax, 1
+    lock xadd dword [rsp + CpuArrivalOffset], eax
+    inc       eax
+
+.check_arrival_cnt:
+    cmp       eax, r8d
+    je        .check_command
+    mov       eax, dword[rsp + CpuArrivalOffset]
+    jmp       .check_arrival_cnt
+
+.check_command:
+    mov     eax, dword[rsp + CommandOffset]
+    cmp     eax, MpProtectedModeWakeupCommandNoop
+    je      .check_command
+
+    cmp     eax, MpProtectedModeWakeupCommandWakeup
+    je      .do_wakeup
+
+    ; Don't support this command, so ignore
+    jmp     .check_command
+
+.do_wakeup:
+    ;
+    ; BSP sets these variables before unblocking APs
+    ;   RAX:  WakeupVectorOffset
+    ;   RBX:  Relocated mailbox address
+    ;   RBP:  vCpuId
+    ;
+    mov     rax, 0
+    mov     eax, dword[rsp + WakeupVectorOffset]
+    mov     rbx, [rsp + WakeupArgsRelocatedMailBox]
+    nop
+    jmp     rax
+    jmp     $
-- 
2.29.2.windows.2


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH V12 34/47] OvmfPkg: Check Tdx in QemuFwCfgPei to avoid DMA operation
  2022-03-29 23:45 [PATCH V12 00/47] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (32 preceding siblings ...)
  2022-03-29 23:46 ` [PATCH V12 33/47] OvmfPkg: Update Sec to support Tdx Min Xu
@ 2022-03-29 23:46 ` Min Xu
  2022-03-29 23:46 ` [PATCH V12 35/47] MdeModulePkg: Skip setting IA32_ERER.NXE if it has already been set Min Xu
                   ` (6 subsequent siblings)
  40 siblings, 0 replies; 53+ messages in thread
From: Min Xu @ 2022-03-29 23:46 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky, Gerd Hoffmann

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@kernel.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 .../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


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH V12 35/47] MdeModulePkg: Skip setting IA32_ERER.NXE if it has already been set
  2022-03-29 23:45 [PATCH V12 00/47] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (33 preceding siblings ...)
  2022-03-29 23:46 ` [PATCH V12 34/47] OvmfPkg: Check Tdx in QemuFwCfgPei to avoid DMA operation Min Xu
@ 2022-03-29 23:46 ` Min Xu
  2022-03-29 23:46 ` [PATCH V12 36/47] MdeModulePkg: Add PcdTdxSharedBitMask Min Xu
                   ` (5 subsequent siblings)
  40 siblings, 0 replies; 53+ messages in thread
From: Min Xu @ 2022-03-29 23:46 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Jian J Wang, Hao A Wu, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky, Gerd Hoffmann

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

If IA32_ERER.NXE has already been set, skip setting it again.

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Hao A Wu <hao.a.wu@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
index 1ebab2782010..a451ca160408 100644
--- a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
+++ b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
@@ -179,9 +179,11 @@ EnableExecuteDisableBit (
 {
   UINT64  MsrRegisters;
 
-  MsrRegisters  = AsmReadMsr64 (0xC0000080);
-  MsrRegisters |= BIT11;
-  AsmWriteMsr64 (0xC0000080, MsrRegisters);
+  MsrRegisters = AsmReadMsr64 (0xC0000080);
+  if ((MsrRegisters & BIT11) == 0) {
+    MsrRegisters |= BIT11;
+    AsmWriteMsr64 (0xC0000080, MsrRegisters);
+  }
 }
 
 /**
-- 
2.29.2.windows.2


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH V12 36/47] MdeModulePkg: Add PcdTdxSharedBitMask
  2022-03-29 23:45 [PATCH V12 00/47] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (34 preceding siblings ...)
  2022-03-29 23:46 ` [PATCH V12 35/47] MdeModulePkg: Skip setting IA32_ERER.NXE if it has already been set Min Xu
@ 2022-03-29 23:46 ` Min Xu
  2022-03-29 23:46 ` [PATCH V12 37/47] UefiCpuPkg: Update AddressEncMask in CpuPageTable Min Xu
                   ` (4 subsequent siblings)
  40 siblings, 0 replies; 53+ messages in thread
From: Min Xu @ 2022-03-29 23:46 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Jian J Wang, Hao A Wu, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky, Gerd Hoffmann

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

Guest Physical Address (GPA) space in Td guest is divided into private
and shared sub-spaces, determined by the SHARED bit of GPA. This PCD
holds the shared bit mask. Its default value is 0 and it will be set
in PlatformPei driver if it is of Td guest.

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Hao A Wu <hao.a.wu@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Jian J Wang <jian.j.wang@intel.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 MdeModulePkg/MdeModulePkg.dec  | 4 ++++
 OvmfPkg/AmdSev/AmdSevX64.dsc   | 3 +++
 OvmfPkg/Bhyve/BhyveX64.dsc     | 3 +++
 OvmfPkg/CloudHv/CloudHvX64.dsc | 3 +++
 OvmfPkg/Microvm/MicrovmX64.dsc | 3 +++
 OvmfPkg/OvmfPkgIa32.dsc        | 3 +++
 OvmfPkg/OvmfPkgIa32X64.dsc     | 1 +
 OvmfPkg/OvmfPkgX64.dsc         | 3 +++
 OvmfPkg/OvmfXen.dsc            | 3 +++
 9 files changed, 26 insertions(+)

diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec
index 40601c95832b..cf79292ec877 100644
--- a/MdeModulePkg/MdeModulePkg.dec
+++ b/MdeModulePkg/MdeModulePkg.dec
@@ -2083,6 +2083,10 @@
   # @Prompt Enable PCIe Resizable BAR Capability support.
   gEfiMdeModulePkgTokenSpaceGuid.PcdPcieResizableBarSupport|FALSE|BOOLEAN|0x10000024
 
+  ## This PCD holds the shared bit mask for page table entries when Tdx is enabled.
+  # @Prompt The shared bit mask when Intel Tdx is enabled.
+  gEfiMdeModulePkgTokenSpaceGuid.PcdTdxSharedBitMask|0x0|UINT64|0x10000025
+
 [PcdsPatchableInModule]
   ## Specify memory size with page number for PEI code when
   #  Loading Module at Fixed Address feature is enabled.
diff --git a/OvmfPkg/AmdSev/AmdSevX64.dsc b/OvmfPkg/AmdSev/AmdSevX64.dsc
index c173a72134f4..dda98aa43bdb 100644
--- a/OvmfPkg/AmdSev/AmdSevX64.dsc
+++ b/OvmfPkg/AmdSev/AmdSevX64.dsc
@@ -558,6 +558,9 @@
   # Set memory encryption mask
   gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask|0x0
 
+  # Set Tdx shared bit mask
+  gEfiMdeModulePkgTokenSpaceGuid.PcdTdxSharedBitMask|0x0
+
   # Set SEV-ES defaults
   gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase|0
   gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize|0
diff --git a/OvmfPkg/Bhyve/BhyveX64.dsc b/OvmfPkg/Bhyve/BhyveX64.dsc
index 656e407473bb..0daae82d6705 100644
--- a/OvmfPkg/Bhyve/BhyveX64.dsc
+++ b/OvmfPkg/Bhyve/BhyveX64.dsc
@@ -550,6 +550,9 @@
   # Set memory encryption mask
   gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask|0x0
 
+  # Set Tdx shared bit mask
+  gEfiMdeModulePkgTokenSpaceGuid.PcdTdxSharedBitMask|0x0
+
   gEfiSecurityPkgTokenSpaceGuid.PcdOptionRomImageVerificationPolicy|0x00
 
   # MdeModulePkg resolution sets up the system display resolution
diff --git a/OvmfPkg/CloudHv/CloudHvX64.dsc b/OvmfPkg/CloudHv/CloudHvX64.dsc
index c307f1cc7550..1732f281b435 100644
--- a/OvmfPkg/CloudHv/CloudHvX64.dsc
+++ b/OvmfPkg/CloudHv/CloudHvX64.dsc
@@ -603,6 +603,9 @@
   # Set memory encryption mask
   gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask|0x0
 
+  # Set Tdx shared bit mask
+  gEfiMdeModulePkgTokenSpaceGuid.PcdTdxSharedBitMask|0x0
+
   # Set SEV-ES defaults
   gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase|0
   gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize|0
diff --git a/OvmfPkg/Microvm/MicrovmX64.dsc b/OvmfPkg/Microvm/MicrovmX64.dsc
index 0eac0c02c630..cde90f523520 100644
--- a/OvmfPkg/Microvm/MicrovmX64.dsc
+++ b/OvmfPkg/Microvm/MicrovmX64.dsc
@@ -592,6 +592,9 @@
   # Set memory encryption mask
   gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask|0x0
 
+  # Set Tdx shared bit mask
+  gEfiMdeModulePkgTokenSpaceGuid.PcdTdxSharedBitMask|0x0
+
   # Set SEV-ES defaults
   gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase|0
   gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize|0
diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
index 8f02dca63869..01a26c234a88 100644
--- a/OvmfPkg/OvmfPkgIa32.dsc
+++ b/OvmfPkg/OvmfPkgIa32.dsc
@@ -618,6 +618,9 @@
   # Set memory encryption mask
   gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask|0x0
 
+  # Set Tdx shared bit mask
+  gEfiMdeModulePkgTokenSpaceGuid.PcdTdxSharedBitMask|0x0
+
   # Set SEV-ES defaults
   gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase|0
   gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize|0
diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index 98a6748c62dd..bf08e893e053 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -631,6 +631,7 @@
 
   # Set memory encryption mask
   gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask|0x0
+  gEfiMdeModulePkgTokenSpaceGuid.PcdTdxSharedBitMask|0x0
 
   # Set SEV-ES defaults
   gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase|0
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index 2df5b2999610..3092036bb7f6 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -642,6 +642,9 @@
   # Set memory encryption mask
   gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask|0x0
 
+  # Set Tdx shared bit mask
+  gEfiMdeModulePkgTokenSpaceGuid.PcdTdxSharedBitMask|0x0
+
   # Set SEV-ES defaults
   gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase|0
   gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize|0
diff --git a/OvmfPkg/OvmfXen.dsc b/OvmfPkg/OvmfXen.dsc
index aa27e2256ae9..470c8cfe4d23 100644
--- a/OvmfPkg/OvmfXen.dsc
+++ b/OvmfPkg/OvmfXen.dsc
@@ -495,6 +495,9 @@
   # Set memory encryption mask
   gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask|0x0
 
+  # Set Tdx shared bit mask
+  gEfiMdeModulePkgTokenSpaceGuid.PcdTdxSharedBitMask|0x0
+
   gEfiSecurityPkgTokenSpaceGuid.PcdOptionRomImageVerificationPolicy|0x00
 
 ################################################################################
-- 
2.29.2.windows.2


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH V12 37/47] UefiCpuPkg: Update AddressEncMask in CpuPageTable
  2022-03-29 23:45 [PATCH V12 00/47] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (35 preceding siblings ...)
  2022-03-29 23:46 ` [PATCH V12 36/47] MdeModulePkg: Add PcdTdxSharedBitMask Min Xu
@ 2022-03-29 23:46 ` Min Xu
  2022-03-29 23:46 ` [PATCH V12 38/47] OvmfPkg: Update PlatformInitLib for Tdx guest Min Xu
                   ` (3 subsequent siblings)
  40 siblings, 0 replies; 53+ messages in thread
From: Min Xu @ 2022-03-29 23:46 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Brijesh Singh, Erdem Aktas, James Bottomley, Jiewen Yao,
	Tom Lendacky, Eric Dong, Ray Ni, Rahul Kumar, Gerd Hoffmann

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

MMIO region in Tdx guest is set with PcdTdxSharedBitMask in TdxDxe's
entry point. In SEV guest the page table entries is set with
PcdPteMemoryEncryptionAddressOrMask when creating 1:1 identity table.

So the AddressEncMask in GetPageTableEntry (@CpuPageTable.c) is either
PcdPteMemoryEncryptionAddressOrMask (in SEV guest), or
PcdTdxSharedBitMask (in TDX guest), or all-0 (in Legacy guest).

Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Ray Ni <ray.ni@intel.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 UefiCpuPkg/CpuDxe/CpuDxe.inf     | 1 +
 UefiCpuPkg/CpuDxe/CpuPageTable.c | 3 +++
 2 files changed, 4 insertions(+)

diff --git a/UefiCpuPkg/CpuDxe/CpuDxe.inf b/UefiCpuPkg/CpuDxe/CpuDxe.inf
index d87fe503d152..235241899222 100644
--- a/UefiCpuPkg/CpuDxe/CpuDxe.inf
+++ b/UefiCpuPkg/CpuDxe/CpuDxe.inf
@@ -80,6 +80,7 @@
   gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask    ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdCpuStackSwitchExceptionList              ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdCpuKnownGoodStackSize                    ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdTdxSharedBitMask                    ## CONSUMES
 
 [Depex]
   TRUE
diff --git a/UefiCpuPkg/CpuDxe/CpuPageTable.c b/UefiCpuPkg/CpuDxe/CpuPageTable.c
index d9e65ab4b22a..f7a4d92e921a 100644
--- a/UefiCpuPkg/CpuDxe/CpuPageTable.c
+++ b/UefiCpuPkg/CpuDxe/CpuPageTable.c
@@ -307,6 +307,9 @@ GetPageTableEntry (
   // Make sure AddressEncMask is contained to smallest supported address field.
   //
   AddressEncMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) & PAGING_1G_ADDRESS_MASK_64;
+  if (AddressEncMask == 0) {
+    AddressEncMask = PcdGet64 (PcdTdxSharedBitMask) & PAGING_1G_ADDRESS_MASK_64;
+  }
 
   if (PagingContext->MachineType == IMAGE_FILE_MACHINE_X64) {
     if ((PagingContext->ContextData.X64.Attributes & PAGE_TABLE_LIB_PAGING_CONTEXT_IA32_X64_ATTRIBUTES_5_LEVEL) != 0) {
-- 
2.29.2.windows.2


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH V12 38/47] OvmfPkg: Update PlatformInitLib for Tdx guest
  2022-03-29 23:45 [PATCH V12 00/47] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (36 preceding siblings ...)
  2022-03-29 23:46 ` [PATCH V12 37/47] UefiCpuPkg: Update AddressEncMask in CpuPageTable Min Xu
@ 2022-03-29 23:46 ` Min Xu
  2022-03-29 23:46 ` [PATCH V12 39/47] OvmfPkg: Update PlatformPei to support " Min Xu
                   ` (2 subsequent siblings)
  40 siblings, 0 replies; 53+ messages in thread
From: Min Xu @ 2022-03-29 23:46 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky, Gerd Hoffmann

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

There are below changes in PlatformInitLib for Tdx guest:

1. Publish ram regions
In Tdx guest, the system memory is passed in TdHob by host VMM. So
the major task of PlatformTdxPublishRamRegions is to walk thru the
TdHob list and transfer the ResourceDescriptorHob and MemoryAllocationHob
to the hobs in DXE phase.

2. Build MemoryAllocationHob for Tdx Mailbox and Ovmf work area.

3. Update of PlatformAddressWidthInitialization. The physical
address width that Tdx guest supports is either 48 or 52.

4. Update of PlatformMemMapInitialization.
0xA0000 - 0xFFFFF is VGA bios region.  Platform initialization marks the
region as MMIO region. Dxe code maps MMIO region as IO region.
As TDX guest, MMIO region is maps as shared.  However VGA BIOS doesn't need
to be shared.  Guest TDX Linux maps VGA BIOS as private and accesses for
BIOS and stuck on repeating EPT violation.  VGA BIOS (more generally ROM
region) should be private.  Skip marking VGA BIOA region [0xa000, 0xfffff]
as MMIO in HOB.

Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/Include/Library/PlatformInitLib.h     | 14 ++++++
 OvmfPkg/Library/PlatformInitLib/IntelTdx.c    | 49 +++++++++++++++++++
 .../Library/PlatformInitLib/IntelTdxNull.c    | 16 ++++++
 OvmfPkg/Library/PlatformInitLib/MemDetect.c   | 14 ++++++
 OvmfPkg/Library/PlatformInitLib/Platform.c    |  4 +-
 5 files changed, 96 insertions(+), 1 deletion(-)

diff --git a/OvmfPkg/Include/Library/PlatformInitLib.h b/OvmfPkg/Include/Library/PlatformInitLib.h
index 6152a43d0da7..2987a367cc9c 100644
--- a/OvmfPkg/Include/Library/PlatformInitLib.h
+++ b/OvmfPkg/Include/Library/PlatformInitLib.h
@@ -220,4 +220,18 @@ ProcessTdxHobList (
   VOID
   );
 
+/**
+  In Tdx guest, the system memory is passed in TdHob by host VMM. So
+  the major task of PlatformTdxPublishRamRegions is to walk thru the
+  TdHob list and transfer the ResourceDescriptorHob and MemoryAllocationHob
+  to the hobs in DXE phase.
+
+  MemoryAllocationHob should also be created for Mailbox and Ovmf work area.
+**/
+VOID
+EFIAPI
+PlatformTdxPublishRamRegions (
+  VOID
+  );
+
 #endif // PLATFORM_INIT_LIB_H_
diff --git a/OvmfPkg/Library/PlatformInitLib/IntelTdx.c b/OvmfPkg/Library/PlatformInitLib/IntelTdx.c
index e9196b7ffaa7..c6d7c8bb6e0e 100644
--- a/OvmfPkg/Library/PlatformInitLib/IntelTdx.c
+++ b/OvmfPkg/Library/PlatformInitLib/IntelTdx.c
@@ -512,3 +512,52 @@ TransferTdxHobList (
     Hob.Raw = GET_NEXT_HOB (Hob);
   }
 }
+
+/**
+  In Tdx guest, the system memory is passed in TdHob by host VMM. So
+  the major task of PlatformTdxPublishRamRegions is to walk thru the
+  TdHob list and transfer the ResourceDescriptorHob and MemoryAllocationHob
+  to the hobs in DXE phase.
+
+  MemoryAllocationHob should also be created for Mailbox and Ovmf work area.
+**/
+VOID
+EFIAPI
+PlatformTdxPublishRamRegions (
+  VOID
+  )
+{
+  if (!TdIsEnabled ()) {
+    return;
+  }
+
+  TransferTdxHobList ();
+
+  //
+  // The memory region defined by PcdOvmfSecGhcbBackupBase is pre-allocated by
+  // host VMM and used as the td mailbox at the beginning of system boot.
+  //
+  BuildMemoryAllocationHob (
+    FixedPcdGet32 (PcdOvmfSecGhcbBackupBase),
+    FixedPcdGet32 (PcdOvmfSecGhcbBackupSize),
+    EfiACPIMemoryNVS
+    );
+
+  if (FixedPcdGet32 (PcdOvmfWorkAreaSize) != 0) {
+    //
+    // Reserve the work area.
+    //
+    // Since this memory range will be used by the Reset Vector on S3
+    // resume, it must be reserved as ACPI NVS.
+    //
+    // If S3 is unsupported, then various drivers might still write to the
+    // work area. We ought to prevent DXE from serving allocation requests
+    // such that they would overlap the work area.
+    //
+    BuildMemoryAllocationHob (
+      (EFI_PHYSICAL_ADDRESS)(UINTN)FixedPcdGet32 (PcdOvmfWorkAreaBase),
+      (UINT64)(UINTN)FixedPcdGet32 (PcdOvmfWorkAreaSize),
+      EfiBootServicesData
+      );
+  }
+}
diff --git a/OvmfPkg/Library/PlatformInitLib/IntelTdxNull.c b/OvmfPkg/Library/PlatformInitLib/IntelTdxNull.c
index af90e0866e89..3ebe582af8de 100644
--- a/OvmfPkg/Library/PlatformInitLib/IntelTdxNull.c
+++ b/OvmfPkg/Library/PlatformInitLib/IntelTdxNull.c
@@ -28,3 +28,19 @@ ProcessTdxHobList (
 {
   return EFI_UNSUPPORTED;
 }
+
+/**
+  In Tdx guest, the system memory is passed in TdHob by host VMM. So
+  the major task of PlatformTdxPublishRamRegions is to walk thru the
+  TdHob list and transfer the ResourceDescriptorHob and MemoryAllocationHob
+  to the hobs in DXE phase.
+
+  MemoryAllocationHob should also be created for Mailbox and Ovmf work area.
+**/
+VOID
+EFIAPI
+PlatformTdxPublishRamRegions (
+  VOID
+  )
+{
+}
diff --git a/OvmfPkg/Library/PlatformInitLib/MemDetect.c b/OvmfPkg/Library/PlatformInitLib/MemDetect.c
index 911c0906cb3d..4c1dedf863c3 100644
--- a/OvmfPkg/Library/PlatformInitLib/MemDetect.c
+++ b/OvmfPkg/Library/PlatformInitLib/MemDetect.c
@@ -37,6 +37,8 @@ Module Name:
 #include <Library/MtrrLib.h>
 #include <Library/QemuFwCfgLib.h>
 #include <Library/QemuFwCfgSimpleParserLib.h>
+#include <Library/TdxLib.h>
+
 #include <Library/PlatformInitLib.h>
 
 VOID
@@ -528,7 +530,19 @@ PlatformAddressWidthInitialization (
     PhysMemAddressWidth = 36;
   }
 
+ #if defined (MDE_CPU_X64)
+  if (TdIsEnabled ()) {
+    if (TdSharedPageMask () == (1ULL << 47)) {
+      PhysMemAddressWidth = 48;
+    } else {
+      PhysMemAddressWidth = 52;
+    }
+  }
+
+  ASSERT (PhysMemAddressWidth <= 52);
+ #else
   ASSERT (PhysMemAddressWidth <= 48);
+ #endif
 
   PlatformInfoHob->FirstNonAddress     = FirstNonAddress;
   PlatformInfoHob->PhysMemAddressWidth = PhysMemAddressWidth;
diff --git a/OvmfPkg/Library/PlatformInitLib/Platform.c b/OvmfPkg/Library/PlatformInitLib/Platform.c
index c4fa7d445394..101074f6100d 100644
--- a/OvmfPkg/Library/PlatformInitLib/Platform.c
+++ b/OvmfPkg/Library/PlatformInitLib/Platform.c
@@ -136,7 +136,9 @@ PlatformMemMapInitialization (
   //
   // Video memory + Legacy BIOS region
   //
-  PlatformAddIoMemoryRangeHob (0x0A0000, BASE_1MB);
+  if (!TdIsEnabled ()) {
+    PlatformAddIoMemoryRangeHob (0x0A0000, BASE_1MB);
+  }
 
   if (PlatformInfoHob->HostBridgeDevId == 0xffff /* microvm */) {
     PlatformAddIoMemoryBaseSizeHob (MICROVM_GED_MMIO_BASE, SIZE_4KB);
-- 
2.29.2.windows.2


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* [PATCH V12 39/47] OvmfPkg: Update PlatformPei to support Tdx guest
  2022-03-29 23:45 [PATCH V12 00/47] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (37 preceding siblings ...)
  2022-03-29 23:46 ` [PATCH V12 38/47] OvmfPkg: Update PlatformInitLib for Tdx guest Min Xu
@ 2022-03-29 23:46 ` Min Xu
  2022-03-31  2:47 ` [PATCH V12 00/47] Enable Intel TDX in OvmfPkg (Config-A) Yao, Jiewen
       [not found] ` <4c3aa6915fe7aac06940bea0f9bc5fdd3c539121.1648555175.git.min.m.xu@intel.com>
  40 siblings, 0 replies; 53+ messages in thread
From: Min Xu @ 2022-03-29 23:46 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky, Gerd Hoffmann

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

OvmfPkg/PlatformPei is updated to support Tdx guest. There are below
major changes.
 - Set Tdx related PCDs
 - Publish Tdx RamRegions

In this patch there is another new function BuildPlatformInfoHob ().
This function builds EFI_HOB_PLATFORM_INFO which contains the
HostBridgeDevId. The hob is built in both Td guest and Non-Td guest.

Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/OvmfPkg.dec                  |  1 +
 OvmfPkg/PlatformPei/FeatureControl.c |  7 +++-
 OvmfPkg/PlatformPei/IntelTdx.c       | 51 ++++++++++++++++++++++++++++
 OvmfPkg/PlatformPei/MemDetect.c      | 13 +++++--
 OvmfPkg/PlatformPei/Platform.c       | 13 +++++++
 OvmfPkg/PlatformPei/Platform.h       | 19 +++++++++++
 OvmfPkg/PlatformPei/PlatformPei.inf  |  3 ++
 7 files changed, 104 insertions(+), 3 deletions(-)
 create mode 100644 OvmfPkg/PlatformPei/IntelTdx.c

diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index f3d06411b51b..746050d64ba7 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -133,6 +133,7 @@
   gGrubFileGuid                         = {0xb5ae312c, 0xbc8a, 0x43b1, {0x9c, 0x62, 0xeb, 0xb8, 0x26, 0xdd, 0x5d, 0x07}}
   gConfidentialComputingSecretGuid      = {0xadf956ad, 0xe98c, 0x484c, {0xae, 0x11, 0xb5, 0x1c, 0x7d, 0x33, 0x64, 0x47}}
   gConfidentialComputingSevSnpBlobGuid  = {0x067b1f5f, 0xcf26, 0x44c5, {0x85, 0x54, 0x93, 0xd7, 0x77, 0x91, 0x2d, 0x42}}
+  gUefiOvmfPkgPlatformInfoGuid          = {0xdec9b486, 0x1f16, 0x47c7, {0x8f, 0x68, 0xdf, 0x1a, 0x41, 0x88, 0x8b, 0xa5}}
 
 [Ppis]
   # PPI whose presence in the PPI database signals that the TPM base address
diff --git a/OvmfPkg/PlatformPei/FeatureControl.c b/OvmfPkg/PlatformPei/FeatureControl.c
index 9af58c2655f8..5864ee0c214d 100644
--- a/OvmfPkg/PlatformPei/FeatureControl.c
+++ b/OvmfPkg/PlatformPei/FeatureControl.c
@@ -12,6 +12,7 @@
 #include <Library/QemuFwCfgLib.h>
 #include <Ppi/MpServices.h>
 #include <Register/ArchitecturalMsr.h>
+#include <IndustryStandard/Tdx.h>
 
 #include "Platform.h"
 
@@ -37,7 +38,11 @@ WriteFeatureControl (
   IN OUT VOID  *WorkSpace
   )
 {
-  AsmWriteMsr64 (MSR_IA32_FEATURE_CONTROL, mFeatureControlValue);
+  if (TdIsEnabled ()) {
+    TdVmCall (TDVMCALL_WRMSR, (UINT64)MSR_IA32_FEATURE_CONTROL, mFeatureControlValue, 0, 0, 0);
+  } else {
+    AsmWriteMsr64 (MSR_IA32_FEATURE_CONTROL, mFeatureControlValue);
+  }
 }
 
 /**
diff --git a/OvmfPkg/PlatformPei/IntelTdx.c b/OvmfPkg/PlatformPei/IntelTdx.c
new file mode 100644
index 000000000000..3c1ddbfafd80
--- /dev/null
+++ b/OvmfPkg/PlatformPei/IntelTdx.c
@@ -0,0 +1,51 @@
+/** @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/QemuFwCfg.h>
+#include <Library/QemuFwCfgLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/TdxLib.h>
+#include <Library/PlatformInitLib.h>
+#include <WorkArea.h>
+#include <ConfidentialComputingGuestAttr.h>
+#include "Platform.h"
+
+/**
+  This Function checks if TDX is available, if present then it sets
+  the dynamic PCDs for Tdx guest.
+  **/
+VOID
+IntelTdxInitialize (
+  VOID
+  )
+{
+ #ifdef MDE_CPU_X64
+  RETURN_STATUS  PcdStatus;
+
+  if (!TdIsEnabled ()) {
+    return;
+  }
+
+  PcdStatus = PcdSet64S (PcdConfidentialComputingGuestAttr, CCAttrIntelTdx);
+  ASSERT_RETURN_ERROR (PcdStatus);
+
+  PcdStatus = PcdSet64S (PcdTdxSharedBitMask, TdSharedPageMask ());
+  ASSERT_RETURN_ERROR (PcdStatus);
+
+  PcdStatus = PcdSetBoolS (PcdSetNxForStack, TRUE);
+  ASSERT_RETURN_ERROR (PcdStatus);
+ #endif
+}
diff --git a/OvmfPkg/PlatformPei/MemDetect.c b/OvmfPkg/PlatformPei/MemDetect.c
index 61d7d3059f7b..2e47b1322990 100644
--- a/OvmfPkg/PlatformPei/MemDetect.c
+++ b/OvmfPkg/PlatformPei/MemDetect.c
@@ -37,7 +37,6 @@ Module Name:
 
 #include <Library/QemuFwCfgLib.h>
 #include <Library/QemuFwCfgSimpleParserLib.h>
-
 #include "Platform.h"
 
 VOID
@@ -231,7 +230,12 @@ GetPeiMemoryCap (
     PdpEntries  = 1 << (mPlatformInfoHob.PhysMemAddressWidth - 30);
     ASSERT (PdpEntries <= 0x200);
   } else {
-    Pml4Entries = 1 << (mPlatformInfoHob.PhysMemAddressWidth - 39);
+    if (mPlatformInfoHob.PhysMemAddressWidth > 48) {
+      Pml4Entries = 0x200;
+    } else {
+      Pml4Entries = 1 << (mPlatformInfoHob.PhysMemAddressWidth - 39);
+    }
+
     ASSERT (Pml4Entries <= 0x200);
     PdpEntries = 512;
   }
@@ -354,6 +358,11 @@ InitializeRamRegions (
   IN EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
   )
 {
+  if (TdIsEnabled ()) {
+    PlatformTdxPublishRamRegions ();
+    return;
+  }
+
   PlatformQemuInitializeRam (PlatformInfoHob);
 
   SevInitializeRam ();
diff --git a/OvmfPkg/PlatformPei/Platform.c b/OvmfPkg/PlatformPei/Platform.c
index f05aec599fcb..f006755d5fdb 100644
--- a/OvmfPkg/PlatformPei/Platform.c
+++ b/OvmfPkg/PlatformPei/Platform.c
@@ -310,6 +310,17 @@ MaxCpuCountInitialization (
   ASSERT_RETURN_ERROR (PcdStatus);
 }
 
+/**
+ * @brief Builds PlatformInfo Hob
+ */
+VOID
+BuildPlatformInfoHob (
+  VOID
+  )
+{
+  BuildGuidDataHob (&gUefiOvmfPkgPlatformInfoGuid, &mPlatformInfoHob, sizeof (EFI_HOB_PLATFORM_INFO));
+}
+
 /**
   Perform Platform PEI initialization.
 
@@ -386,7 +397,9 @@ InitializePlatform (
     MiscInitialization (&mPlatformInfoHob);
   }
 
+  IntelTdxInitialize ();
   InstallFeatureControlCallback ();
+  BuildPlatformInfoHob ();
 
   return EFI_SUCCESS;
 }
diff --git a/OvmfPkg/PlatformPei/Platform.h b/OvmfPkg/PlatformPei/Platform.h
index 3d148893401a..29b51b2debd8 100644
--- a/OvmfPkg/PlatformPei/Platform.h
+++ b/OvmfPkg/PlatformPei/Platform.h
@@ -11,6 +11,7 @@
 
 #include <IndustryStandard/E820.h>
 #include <Library/PlatformInitLib.h>
+#include <IndustryStandard/IntelTdx.h>
 
 extern EFI_HOB_PLATFORM_INFO  mPlatformInfoHob;
 
@@ -84,6 +85,24 @@ AmdSevInitialize (
   VOID
   );
 
+/**
+  This Function checks if TDX is available, if present then it sets
+  the dynamic PCDs for Tdx guest. It also builds Guid hob which contains
+  the Host Bridge DevId.
+  **/
+VOID
+IntelTdxInitialize (
+  VOID
+  );
+
+/**
+ * @brief Builds PlatformInfo Hob
+ */
+VOID
+BuildPlatformInfoHob (
+  VOID
+  );
+
 VOID
 SevInitializeRam (
   VOID
diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf
index f6bfc09c2dd5..00372fa0ebb5 100644
--- a/OvmfPkg/PlatformPei/PlatformPei.inf
+++ b/OvmfPkg/PlatformPei/PlatformPei.inf
@@ -31,6 +31,7 @@
   MemTypeInfo.c
   Platform.c
   Platform.h
+  IntelTdx.c
 
 [Packages]
   EmbeddedPkg/EmbeddedPkg.dec
@@ -43,6 +44,7 @@
 [Guids]
   gEfiMemoryTypeInformationGuid
   gFdtHobGuid
+  gUefiOvmfPkgPlatformInfoGuid
 
 [LibraryClasses]
   BaseLib
@@ -111,6 +113,7 @@
   gUefiCpuPkgTokenSpaceGuid.PcdSevEsIsEnabled
   gEfiMdePkgTokenSpaceGuid.PcdConfidentialComputingGuestAttr
   gUefiCpuPkgTokenSpaceGuid.PcdGhcbHypervisorFeatures
+  gEfiMdeModulePkgTokenSpaceGuid.PcdTdxSharedBitMask
 
 [FixedPcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidBase
-- 
2.29.2.windows.2


^ permalink raw reply related	[flat|nested] 53+ messages in thread

* Re: [edk2-devel] [PATCH V12 14/47] UefiCpuPkg: Enable Tdx support in MpInitLib
  2022-03-29 23:46 ` [PATCH V12 14/47] UefiCpuPkg: Enable Tdx support in MpInitLib Min Xu
@ 2022-03-30  7:53   ` Ni, Ray
  2022-04-28 13:15   ` Lendacky, Thomas
  1 sibling, 0 replies; 53+ messages in thread
From: Ni, Ray @ 2022-03-30  7:53 UTC (permalink / raw)
  To: Min Xu, devel

[-- Attachment #1: Type: text/plain, Size: 40 bytes --]

Reviewed-by: Ray Ni <ray.ni@intel.com.

[-- Attachment #2: Type: text/html, Size: 50 bytes --]

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH V12 00/47] Enable Intel TDX in OvmfPkg (Config-A)
  2022-03-29 23:45 [PATCH V12 00/47] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (38 preceding siblings ...)
  2022-03-29 23:46 ` [PATCH V12 39/47] OvmfPkg: Update PlatformPei to support " Min Xu
@ 2022-03-31  2:47 ` Yao, Jiewen
       [not found] ` <4c3aa6915fe7aac06940bea0f9bc5fdd3c539121.1648555175.git.min.m.xu@intel.com>
  40 siblings, 0 replies; 53+ messages in thread
From: Yao, Jiewen @ 2022-03-31  2:47 UTC (permalink / raw)
  To: Xu, Min M, devel@edk2.groups.io
  Cc: Brijesh Singh, Dong, Eric, Aktas, Erdem, Wu, Hao A, Wang, Jian J,
	James Bottomley, Gao, Liming, Kinney, Michael D, Ni, Ray,
	Kumar, Rahul1, Tom Lendacky, Liu, Zhiguang, Gerd Hoffmann

Thanks Min
Series: Reviewed-by: Jiewen Yao <Jiewen.yao@intel.com>

> -----Original Message-----
> From: Xu, Min M <min.m.xu@intel.com>
> Sent: Wednesday, March 30, 2022 7:46 AM
> To: devel@edk2.groups.io
> Cc: Xu, Min M <min.m.xu@intel.com>; Brijesh Singh <brijesh.singh@amd.com>;
> Dong, Eric <eric.dong@intel.com>; Aktas, Erdem <erdemaktas@google.com>;
> Wu, Hao A <hao.a.wu@intel.com>; Wang, Jian J <jian.j.wang@intel.com>;
> James Bottomley <jejb@linux.ibm.com>; Yao, Jiewen <jiewen.yao@intel.com>;
> Gao, Liming <gaoliming@byosoft.com.cn>; Kinney, Michael D
> <michael.d.kinney@intel.com>; Ni, Ray <ray.ni@intel.com>; Kumar, Rahul1
> <rahul1.kumar@intel.com>; Tom Lendacky <thomas.lendacky@amd.com>; Liu,
> Zhiguang <zhiguang.liu@intel.com>; Gerd Hoffmann <kraxel@redhat.com>
> Subject: [PATCH V12 00/47] Enable Intel TDX in OvmfPkg (Config-A)
> 
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3249
> 
> Intel's Trust Domain Extensions (Intel TDX) refers to an Intel technology
> that extends Virtual Machines Extensions (VMX) and Multi-Key Total Memory
> Encryption (MKTME) with a new kind of virutal machines guest called a
> Trust Domain (TD). A TD is desinged to run in a CPU mode that protects the
> confidentiality of TD memory contents and the TD's CPU state from other
> software, including the hosting Virtual-Machine Monitor (VMM), unless
> explicitly shared by the TD itself.
> 
> There are 2 configurations for TDVF to upstream. See below link for
> the definitions of the 2 configurations.
> https://edk2.groups.io/g/devel/message/76367
> 
> This patch-set is to enable Config-A in OvmfPkg.
>  - Merge the *basic* TDVF feature to existing OvmfX64Pkg.dsc. (Align
>    with existing SEV)
>  - Threat model: VMM is NOT out of TCB. (We don’t make things worse.)
>  - The OvmfX64Pkg.dsc includes SEV/TDX/normal OVMF basic boot capability.
>    The final binary can run on SEV/TDX/normal OVMF
>  - No changes to existing OvmfPkgX64 image layout.
>  - No need to add additional security features if they do not exist today
>  - No need to remove features if they exist today.
>  - RTMR is not supported
>  - PEI phase is NOT skipped in either Td or Non-Td
> 
> Patch 01 - 33 are changes in SEC phase. Also some libraries in these
> patches are workable in SEC/PEI/DXE.
> 
> Patch 16 - 29 extract the common codes from OvmfPkg/PlatformPei to a new
> PlatformInitLib. After that OvmfPkg/PlatformPei is refactored with this
> lib. These 14 patches are currently reviewed in another separate
> patch-set. https://edk2.groups.io/g/devel/message/87327
> 
> Patch 34 - 39 are changes in PEI phase.
> 
> Patch 40 - 44 are changes in DXE phase.
> 
> Patch 45 - 47 are for local Apic timer DXE driver.
> 
> [TDX]: https://software.intel.com/content/dam/develop/external/us/en/
> documents/tdx-whitepaper-final9-17.pdf
> 
> [TDX-Module]: https://software.intel.com/content/dam/develop/external/
> us/en/documents/tdx-module-1.0-public-spec-v0.931.pdf
> 
> [TDVF]: https://software.intel.com/content/dam/develop/external/us/en/
> documents/tdx-virtual-firmware-design-guide-rev-1.pdf
> 
> [GCHI]: https://software.intel.com/content/dam/develop/external/us/en/
> documents/intel-tdx-guest-hypervisor-communication-interface-1.0-344426-
> 002.pdf
> 
> Code is at https://github.com/mxu9/edk2/tree/tdvf_wave2.v12
> 
> v12 changes:
>  - Update MpInitLib based on the review feedbacks. Please see
>    https://edk2.groups.io/g/devel/message/88173.
>  - Update the code base to 2b4b8013fe45.
> 
> v11 changes:
>  - Update MpInitlib based on the review comments. Please see
>    https://edk2.groups.io/g/devel/message/88089
>  - Update the code base to 3ef2071927fa.
> 
> v10 changes:
>  - Update MpInitLib based on the review comments. Please see the
>    discussion: https://edk2.groups.io/g/devel/message/87902
>  - Update the code base to ec0b54849b23.
> 
> v9 changes:
>  - Move the definition of EFI_RESOURCE_MEMORY_UNACCEPTED from MdePkg
>    to OvmfPkg as in internal implementation. Because it has not been
>    added in PI spec. After the definition is added in PI spec, it can
>    be moved to MdePkg.
>  - Add definition of new CPUID leaf 0x21 in
>    MdePkg/Include/Register/Intel/Cpuid.h.
>  - Use switch-case to hanle VC/VE handling together in
>    CpuExceptionHandlerLib.
>  - Refactor changes for Tdx guest in MpInitLib.
>  - Refine the comments in BaseLib and PlatformInitLib.
>  - Other minor updates and changes.
> 
> v8 changes:
>  - Based on the comments of PlatformInitLib and OvmfPkg/PlatformPei,
>    a separte patch-set is created for the changes. It is now under review
>    https://edk2.groups.io/g/devel/message/87327
>  - Based on the comments, TdCall/TdVmCall/TdIsEnabled is wrapped with
>    MDE_CPU_IA32 and MDE_CPU_X64.
>  - EFI_RESOURCE_ATTRIBUTE_ENCRYPTED is removed based on the TDVF Spec
>    update. Instead EFI_RESOURCE_MEMORY_UNACCEPTED is added to indicate
>    the memory which to be accepted in TDVF. The corresponding logic
>    of AcceptMemory is updated as well. Please see Patch 31.
>  - PcdIa32EferChangeAllowed is deleted. Because for Td guest
>    IA32_EFER.NXE is set by default. So we only need check whether it has
>    been set before it is to be set again. See Patch 35.
>  - Based on comments PcdTdxSharedBitMask is defined in
>    [PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
>  - Delete un-necessary header files in TdxLib.h.
>  - Other minor updates and changes.
> 
> v7 changes:
>  - Based on the comments from last review, 8 PlatformInitLib patches
>    are squashed into 4 patches (#17-#20). These 4 patches are not
>    related to Tdx guest. Tdx related codes of PlatformInitLib is
>    in #21.
>  - gUefiOvmfPkgTdxPlatformGuid is renamed as gUefiOvmfPkgPlatformInfoGuid.
>    Because this GUID is used not only by Tdx guest, but also by
>    Legacy guest.
>  - PlatformInitLibNull is deleted.
>  - In PlatformPei Pml4Entries is cap at 512 entries when
>    mPhysMemAddressWidth > 48.
> 
> v7 not-addressed comments
>  - Comments in MpInitLib have not been addressed yet. It will be
>    addressed in the following version.
>  - Thanks much for your understanding.
> 
> v6 changes:
>  - PlatformInitLib and OvmfPkg/PlatformPei refactoring are covered in
>    patch from 17 - 24. These patches are not related to Tdx guest. Tdx
>    related codes of PlatformInitLib is in patch 25.
>  - In the previous patch-sets, TdHob is processed in
>    OvmfPkg/Sec/IntelTdx.c. Per Gerd's suggestion they are now moved
>    to PlatformInitLib/IntelTdx.c. So that they can be reused in Config-B.
>  - The default Accept page size is changed from 4K to 2M.
>  - The BspAcceptMemoryResourceRange is refactored according to Gerd's
>    comment.
>  - In ApRunLoop.nasm command field is set to zero as acknowledgement.
>    This is a fix based on the ACPI Spec v6.4,Sec titled "Multiprocessor
>    Wakeup Structure".
> 
> v6 not-addressed comments
>  - Comments in MpInitLib have not been addressed yet. It will be
>    addressed in the following version.
>  - Thanks much for your understanding.
> 
> v5 changes:
>  - PlatformInitLib is introduced which wraps the common functions in
>    OvmfPkg/PlatformPei. It is because there are a lot of duplicated
>    codes for Platform initialization in PEI phase and there are at least
>    3 variants of PlatformPei. Another reason is that in TDVF Config-B
>    PEI-less boot needs the similar initiliazation as PlatformPei. Based
>    on the discussion with the community, PlatformInitLib is introduced.
>    As the first stage OvmfPkg/PlatformPei is refactored with this lib.
>    In the future the other 2 PlatformPei variants will be refactored
>    as well.
>  - PcdIgnoreVeHalt is deprecated.
>  - Add spec link for Mailbox.
>  - Other minor changes, such as comments, uncrustify formats, etc.
> 
> v5 not-addressed comments
>  - Comments in MpInitLib have not been addressed yet. It will be
>    addressed in the following version.
>  - Some comments may be missed. I will re-visit the review emails.
>  - Thanks much for your understanding.
> 
> v4 changes:
>  - Split the TdxLib into 2 libraries. The TDX basic functions
>    (TdCall / TdVmCall / TdIsEnabled) are moved to BaseLib (#2).
>    The other functions are in TdxLib. (#3)
>  - Based on above changes (TdCall/TdVmCall/TdIsEnabled in BaseLib)
>    the TdxLib.inf is not necessary in some Pkgs, such as
>    UefiPayloadPkg. The duplicated source code are deleted (BaseIoLib
>    is the sample).
>  - Drop the Accepting pages with TDX MP service. Instead only BSP
>    accepts pages. There maybe boot performance issue. There are some
>    mitigations to it, such as 2M accept page size, lazy accept, etc.
>    We will re-visit this issue in a separate patch-set.
>  - Relocate Mailbox in TdxDxe driver instead of in PlatformPei. This
>    is to keep consistence with Config-B (PEI is skipped in Config-B).
>  - SetMmioSharedBit in TdxDxe driver instead of in DxeIplPeim after
>    CreateIdentityMappingPageTables. This is to keep consistence with
>    Config-B (PEI is skipped in Config-B).
>  - Some other minor changes, such as switch-case indention.
>  - Rebase the code base (commit: 8c06c53b585a) and update the code with
>    uncrustify.
> 
> v4 not-addressed comments:
>  - Comments in MpInitLib have not been addressed yet. It will be
>    addressed in the next version.
>  - BaseMemEncryptTdxLib is suggested to be merged with
>    BaseMemEncryptSevLib. It will be addressed in the next version.
>  - Gerd suggests a generic page table walker which is able to set
>    and clear bits for a given memory range in both SEV and TDX guest.
>    This suggestion will be addressed in the next version.
>  - Some comments may be missed. I will re-visit the review emails.
>  - Thanks much for your understanding.
> 
> v3 changes:
>  - LocalApicTimerDxe is split out to be a separate patch-series.
>  - VmTdExitLibNull/VmgExitLib are removed. Instead the VmgExitLib
>    is extended to handle #VE exception. (Patch 3-5)
>  - Split the Tdx support of base IoLib into 4 commits. (Patch 6-9)
>  - Alter of MADT table is updated. In previous version it was
>    created from scratch. Now it gets the installed table, copy
>    it to a larger buffer and append the ACPI_MADT_MPWK to it.
>    (Patch 25)
>  - Changes in BaseXApicX2ApicLib is refined based on the
>    feedbacks. (Add spec link of MSR access definition, rename
>    some funtion name, etc.) (Patch 11)
>  - Use PcdConfidentialComputingGuestAttr to probe TDX guest instead
>    of CPUID. But in some cases PcdConfidentialComputingGuestAttr
>    cannot be used because it has not been set yet.
>  - Some other minor changes.
> 
> v3 not-addressed comments:
>  - Some of the comments have not been addressed. This is because I
>    need more time to consider how to address these comments.
>    At the same time I want to submit a new version based on the above
>    changes so that community can review in a more efficient way.
>    (v2 is the version one month ago).
>  - Comments in MpInitLib have not been addressed yet. It will be
>    addressed in v4.
>  - BaseMemEncryptTdxLib should be merged with BaseMemEncryptSevLib.
>    It will be addressed in v4.
>  - Some comments may be missed. I will re-visit the review emails.
>  - Thanks much for your understanding.
> 
> v2 changes:
>  - Remove TdxProbeLib. It is to reduce the depencies of the lib.
>  - In v1 a new function (AllocatePagesWithMemoryType) is added in
>    PeiMemoryAllocationLib. This function is not necessary. It can
>    be replaced by PeiServicesAllocatePages.
>  - IoLibFifo.c is added in BaseIoLibIntrinsic. This file includes
>    the functions of read/write of I/O  port fifo. These functions
>    will call TdIoReadFifo or SevIoReadFifo by checking TDX or SEV
>    in run-time.
>  - DXE related patches are added. (Patch 22-28)
>  - Fix typo in commit/comment message, or some minor changes.
>  - Rebase the edk2 code base. (4cc1458dbe00)
> 
> Cc: Brijesh Singh <brijesh.singh@amd.com>
> Cc: Eric Dong <eric.dong@intel.com>
> Cc: Erdem Aktas <erdemaktas@google.com>
> Cc: Hao A Wu <hao.a.wu@intel.com>
> Cc: Jian J Wang <jian.j.wang@intel.com>
> Cc: James Bottomley <jejb@linux.ibm.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Liming Gao <gaoliming@byosoft.com.cn>
> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> Cc: Ray Ni <ray.ni@intel.com>
> Cc: Rahul Kumar <rahul1.kumar@intel.com>
> Cc: Tom Lendacky <thomas.lendacky@amd.com>
> Cc: Zhiguang Liu <zhiguang.liu@intel.com>
> Cc: Gerd Hoffmann <kraxel@redhat.com>
> Signed-off-by: Min Xu <min.m.xu@intel.com>
> 
> Min Xu (47):
>   MdePkg: Add Tdx.h
>   MdePkg: Update Cpuid.h for Tdx
>   MdePkg: Introduce basic Tdx functions in BaseLib
>   MdePkg: Add TdxLib to wrap Tdx operations
>   UefiCpuPkg: Extend VmgExitLibNull to handle #VE exception
>   OvmfPkg: Extend VmgExitLib to handle #VE exception
>   UefiCpuPkg/CpuExceptionHandler: Add base support for the #VE exception
>   MdePkg: Add helper functions for Tdx guest in BaseIoLibIntrinsic
>   MdePkg: Support mmio for Tdx guest in BaseIoLibIntrinsic
>   MdePkg: Support IoFifo for Tdx guest in BaseIoLibIntrinsic
>   MdePkg: Support IoRead/IoWrite for Tdx guest in BaseIoLibIntrinsic
>   UefiCpuPkg: Support TDX in BaseXApicX2ApicLib
>   MdePkg: Add macro to check SEV / TDX guest
>   UefiCpuPkg: Enable Tdx support in MpInitLib
>   OvmfPkg: Add IntelTdx.h in OvmfPkg/Include/IndustryStandard
>   OvmfPkg: Add TdxMailboxLib
>   OvmfPkg: Create initial version of PlatformInitLib
>   OvmfPkg/PlatformInitLib: Add hob functions
>   OvmfPkg/PlatformPei: Move global variables to PlatformInfoHob
>   OvmfPkg/PlatformPei: Refactor MiscInitialization
>   OvmfPkg/PlatformPei: Refactor MiscInitialization for CloudHV
>   OvmfPkg/PlatformPei: Refactor AddressWidthInitialization
>   OvmfPkg/PlatformPei: Refactor MaxCpuCountInitialization
>   OvmfPkg/PlatformPei: Refactor QemuUc32BaseInitialization
>   OvmfPkg/PlatformPei: Refactor InitializeRamRegions
>   OvmfPkg/PlatformPei: Refactor MemMapInitialization
>   OvmfPkg/PlatformPei: Refactor NoexecDxeInitialization
>   OvmfPkg/PlatformPei: Refactor MiscInitialization
>   OvmfPkg/PlatformInitLib: Create MemDetect.c
>   OvmfPkg/PlatformInitLib: Move functions to Platform.c
>   OvmfPkg: Update PlatformInitLib to process Tdx hoblist
>   OvmfPkg/Sec: Declare local variable as volatile in
>     SecCoreStartupWithStack
>   OvmfPkg: Update Sec to support Tdx
>   OvmfPkg: Check Tdx in QemuFwCfgPei to avoid DMA operation
>   MdeModulePkg: Skip setting IA32_ERER.NXE if it has already been set
>   MdeModulePkg: Add PcdTdxSharedBitMask
>   UefiCpuPkg: Update AddressEncMask in CpuPageTable
>   OvmfPkg: Update PlatformInitLib for Tdx guest
>   OvmfPkg: Update PlatformPei to support Tdx guest
>   OvmfPkg: Update AcpiPlatformDxe to alter MADT table
>   OvmfPkg/BaseMemEncryptTdxLib: Add TDX helper library
>   OvmfPkg: Add TdxDxe driver
>   OvmfPkg/QemuFwCfgLib: Support Tdx in QemuFwCfgDxe
>   OvmfPkg: Update IoMmuDxe to support TDX
>   OvmfPkg: Rename XenTimerDxe to LocalApicTimerDxe
>   UefiCpuPkg: Setting initial-count register as the last step
>   OvmfPkg: Switch timer in build time for OvmfPkg
> 
>  .../Core/DxeIplPeim/X64/VirtualMemory.c       |   8 +-
>  MdeModulePkg/MdeModulePkg.dec                 |   4 +
>  .../Include/ConfidentialComputingGuestAttr.h  |   3 +
>  MdePkg/Include/IndustryStandard/Tdx.h         | 203 ++++
>  MdePkg/Include/Library/BaseLib.h              |  66 ++
>  MdePkg/Include/Library/TdxLib.h               |  92 ++
>  MdePkg/Include/Register/Intel/Cpuid.h         |  35 +-
>  .../BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf |   2 +
>  .../BaseIoLibIntrinsicSev.inf                 |   7 +
>  MdePkg/Library/BaseIoLibIntrinsic/IoLib.c     |  81 +-
>  MdePkg/Library/BaseIoLibIntrinsic/IoLibFifo.c | 217 ++++
>  MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c  |  51 +-
>  .../BaseIoLibIntrinsic/IoLibInternalTdx.c     | 674 +++++++++++++
>  .../BaseIoLibIntrinsic/IoLibInternalTdxNull.c | 497 +++++++++
>  MdePkg/Library/BaseIoLibIntrinsic/IoLibMsc.c  |  73 +-
>  MdePkg/Library/BaseIoLibIntrinsic/IoLibSev.h  | 166 +++
>  MdePkg/Library/BaseIoLibIntrinsic/IoLibTdx.h  | 410 ++++++++
>  .../BaseIoLibIntrinsic/X64/IoFifoSev.nasm     |  34 +-
>  MdePkg/Library/BaseLib/BaseLib.inf            |   4 +
>  MdePkg/Library/BaseLib/IntelTdxNull.c         |  83 ++
>  MdePkg/Library/BaseLib/X64/TdCall.nasm        |  85 ++
>  MdePkg/Library/BaseLib/X64/TdProbe.c          |  63 ++
>  MdePkg/Library/BaseLib/X64/TdVmcall.nasm      | 145 +++
>  MdePkg/Library/TdxLib/AcceptPages.c           | 181 ++++
>  MdePkg/Library/TdxLib/Rtmr.c                  |  84 ++
>  MdePkg/Library/TdxLib/TdInfo.c                | 115 +++
>  MdePkg/Library/TdxLib/TdxLib.inf              |  37 +
>  MdePkg/Library/TdxLib/TdxLibNull.c            | 106 ++
>  MdePkg/MdePkg.dec                             |   3 +
>  MdePkg/MdePkg.dsc                             |   1 +
>  OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf   |   1 +
>  OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c       |  14 +-
>  OvmfPkg/AmdSev/AmdSevX64.dsc                  |  11 +-
>  OvmfPkg/AmdSev/AmdSevX64.fdf                  |   3 +-
>  OvmfPkg/Bhyve/BhyveX64.dsc                    |   5 +
>  OvmfPkg/CloudHv/CloudHvX64.dsc                |   8 +-
>  OvmfPkg/CloudHv/CloudHvX64.fdf                |   2 +-
>  OvmfPkg/Include/IndustryStandard/IntelTdx.h   |  67 ++
>  OvmfPkg/Include/Library/MemEncryptTdxLib.h    |  81 ++
>  OvmfPkg/Include/Library/PlatformInitLib.h     | 237 +++++
>  OvmfPkg/Include/Library/TdxMailboxLib.h       |  76 ++
>  .../Include/Protocol/QemuAcpiTableNotify.h    |  27 +
>  OvmfPkg/Include/TdxCommondefs.inc             |  51 +
>  OvmfPkg/IoMmuDxe/AmdSevIoMmu.c                | 103 +-
>  OvmfPkg/IoMmuDxe/AmdSevIoMmu.h                |   6 +-
>  OvmfPkg/IoMmuDxe/IoMmuDxe.c                   |   6 +-
>  OvmfPkg/IoMmuDxe/IoMmuDxe.inf                 |   5 +
>  .../BaseMemEncryptTdxLib.inf                  |  44 +
>  .../BaseMemEncryptTdxLibNull.inf              |  35 +
>  .../BaseMemoryEncryptionNull.c                |  90 ++
>  .../BaseMemEncryptTdxLib/MemoryEncryption.c   | 948 ++++++++++++++++++
>  .../BaseMemEncryptTdxLib/VirtualMemory.h      | 181 ++++
>  .../PlatformInitLib}/Cmos.c                   |  32 +-
>  OvmfPkg/Library/PlatformInitLib/IntelTdx.c    | 563 +++++++++++
>  .../Library/PlatformInitLib/IntelTdxNull.c    |  46 +
>  OvmfPkg/Library/PlatformInitLib/MemDetect.c   | 856 ++++++++++++++++
>  OvmfPkg/Library/PlatformInitLib/Platform.c    | 573 +++++++++++
>  .../PlatformInitLib/PlatformInitLib.inf       |  98 ++
>  OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgDxe.c   |   9 +-
>  .../Library/QemuFwCfgLib/QemuFwCfgDxeLib.inf  |   1 +
>  .../QemuFwCfgLib/QemuFwCfgLibInternal.h       |  11 +
>  OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPei.c   |  32 +
>  .../Library/QemuFwCfgLib/QemuFwCfgPeiLib.inf  |   2 +
>  OvmfPkg/Library/TdxMailboxLib/TdxMailbox.c    | 141 +++
>  .../Library/TdxMailboxLib/TdxMailboxLib.inf   |  52 +
>  .../Library/TdxMailboxLib/TdxMailboxNull.c    |  85 ++
>  OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf  |   3 +-
>  OvmfPkg/Library/VmgExitLib/VmTdExitHandler.h  |  32 +
>  .../Library/VmgExitLib/VmTdExitVeHandler.c    | 559 +++++++++++
>  OvmfPkg/Library/VmgExitLib/VmgExitLib.inf     |   2 +
>  .../Library/VmgExitLib/X64/TdVmcallCpuid.nasm | 146 +++
>  .../LocalApicTimerDxe.c}                      |   4 +-
>  .../LocalApicTimerDxe.h}                      |   4 +-
>  .../LocalApicTimerDxe.inf}                    |   7 +-
>  OvmfPkg/Microvm/MicrovmX64.dsc                |   8 +-
>  OvmfPkg/Microvm/MicrovmX64.fdf                |   2 +-
>  OvmfPkg/OvmfPkg.dec                           |  17 +
>  OvmfPkg/OvmfPkgIa32.dsc                       |  15 +-
>  OvmfPkg/OvmfPkgIa32.fdf                       |   8 +-
>  OvmfPkg/OvmfPkgIa32X64.dsc                    |  15 +-
>  OvmfPkg/OvmfPkgIa32X64.fdf                    |   8 +-
>  OvmfPkg/OvmfPkgX64.dsc                        |  32 +-
>  OvmfPkg/OvmfPkgX64.fdf                        |  11 +-
>  OvmfPkg/OvmfXen.dsc                           |   7 +-
>  OvmfPkg/OvmfXen.fdf                           |   2 +-
>  OvmfPkg/PlatformPei/AmdSev.c                  |   8 +-
>  OvmfPkg/PlatformPei/Cmos.h                    |  48 -
>  OvmfPkg/PlatformPei/FeatureControl.c          |   7 +-
>  OvmfPkg/PlatformPei/Fv.c                      |   4 +-
>  OvmfPkg/PlatformPei/IntelTdx.c                |  51 +
>  OvmfPkg/PlatformPei/MemDetect.c               | 889 ++--------------
>  OvmfPkg/PlatformPei/MemTypeInfo.c             |   2 +-
>  OvmfPkg/PlatformPei/Platform.c                | 631 ++----------
>  OvmfPkg/PlatformPei/Platform.h                |  97 +-
>  OvmfPkg/PlatformPei/PlatformPei.inf           |   6 +-
>  OvmfPkg/Sec/SecMain.c                         |  44 +-
>  OvmfPkg/Sec/SecMain.inf                       |   3 +
>  OvmfPkg/Sec/X64/SecEntry.nasm                 |  82 ++
>  OvmfPkg/TdxDxe/TdxAcpiTable.c                 | 213 ++++
>  OvmfPkg/TdxDxe/TdxAcpiTable.h                 |  60 ++
>  OvmfPkg/TdxDxe/TdxDxe.c                       | 261 +++++
>  OvmfPkg/TdxDxe/TdxDxe.inf                     |  64 ++
>  OvmfPkg/TdxDxe/X64/ApRunLoop.nasm             |  90 ++
>  UefiCpuPkg/CpuDxe/CpuDxe.inf                  |   1 +
>  UefiCpuPkg/CpuDxe/CpuPageTable.c              |   3 +
>  UefiCpuPkg/Include/Library/VmgExitLib.h       |  28 +
>  .../BaseXApicX2ApicLib/BaseXApicX2ApicLib.c   | 170 +++-
>  .../PeiDxeSmmCpuException.c                   |  53 +-
>  .../SecPeiCpuException.c                      |  57 +-
>  UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf |   3 +
>  UefiCpuPkg/Library/MpInitLib/MpIntelTdx.h     |  69 ++
>  UefiCpuPkg/Library/MpInitLib/MpLib.c          |  63 +-
>  UefiCpuPkg/Library/MpInitLib/MpLibTdx.c       | 106 ++
>  UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c   |  69 ++
>  UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf |   3 +
>  .../Library/VmgExitLibNull/VmTdExitNull.c     |  38 +
>  .../Library/VmgExitLibNull/VmgExitLibNull.inf |   1 +
>  117 files changed, 10472 insertions(+), 1666 deletions(-)
>  create mode 100644 MdePkg/Include/IndustryStandard/Tdx.h
>  create mode 100644 MdePkg/Include/Library/TdxLib.h
>  create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/IoLibFifo.c
>  create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdx.c
>  create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdxNull.c
>  create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/IoLibSev.h
>  create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/IoLibTdx.h
>  create mode 100644 MdePkg/Library/BaseLib/IntelTdxNull.c
>  create mode 100644 MdePkg/Library/BaseLib/X64/TdCall.nasm
>  create mode 100644 MdePkg/Library/BaseLib/X64/TdProbe.c
>  create mode 100644 MdePkg/Library/BaseLib/X64/TdVmcall.nasm
>  create mode 100644 MdePkg/Library/TdxLib/AcceptPages.c
>  create mode 100644 MdePkg/Library/TdxLib/Rtmr.c
>  create mode 100644 MdePkg/Library/TdxLib/TdInfo.c
>  create mode 100644 MdePkg/Library/TdxLib/TdxLib.inf
>  create mode 100644 MdePkg/Library/TdxLib/TdxLibNull.c
>  create mode 100644 OvmfPkg/Include/IndustryStandard/IntelTdx.h
>  create mode 100644 OvmfPkg/Include/Library/MemEncryptTdxLib.h
>  create mode 100644 OvmfPkg/Include/Library/PlatformInitLib.h
>  create mode 100644 OvmfPkg/Include/Library/TdxMailboxLib.h
>  create mode 100644 OvmfPkg/Include/Protocol/QemuAcpiTableNotify.h
>  create mode 100644 OvmfPkg/Include/TdxCommondefs.inc
>  create mode 100644
> OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLib.inf
>  create mode 100644
> OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLibNull.inf
>  create mode 100644
> OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemoryEncryptionNull.c
>  create mode 100644
> OvmfPkg/Library/BaseMemEncryptTdxLib/MemoryEncryption.c
>  create mode 100644
> OvmfPkg/Library/BaseMemEncryptTdxLib/VirtualMemory.h
>  rename OvmfPkg/{PlatformPei => Library/PlatformInitLib}/Cmos.c (61%)
>  create mode 100644 OvmfPkg/Library/PlatformInitLib/IntelTdx.c
>  create mode 100644 OvmfPkg/Library/PlatformInitLib/IntelTdxNull.c
>  create mode 100644 OvmfPkg/Library/PlatformInitLib/MemDetect.c
>  create mode 100644 OvmfPkg/Library/PlatformInitLib/Platform.c
>  create mode 100644 OvmfPkg/Library/PlatformInitLib/PlatformInitLib.inf
>  create mode 100644 OvmfPkg/Library/TdxMailboxLib/TdxMailbox.c
>  create mode 100644 OvmfPkg/Library/TdxMailboxLib/TdxMailboxLib.inf
>  create mode 100644 OvmfPkg/Library/TdxMailboxLib/TdxMailboxNull.c
>  create mode 100644 OvmfPkg/Library/VmgExitLib/VmTdExitHandler.h
>  create mode 100644 OvmfPkg/Library/VmgExitLib/VmTdExitVeHandler.c
>  create mode 100644 OvmfPkg/Library/VmgExitLib/X64/TdVmcallCpuid.nasm
>  rename OvmfPkg/{XenTimerDxe/XenTimerDxe.c =>
> LocalApicTimerDxe/LocalApicTimerDxe.c} (95%)
>  rename OvmfPkg/{XenTimerDxe/XenTimerDxe.h =>
> LocalApicTimerDxe/LocalApicTimerDxe.h} (96%)
>  rename OvmfPkg/{XenTimerDxe/XenTimerDxe.inf =>
> LocalApicTimerDxe/LocalApicTimerDxe.inf} (80%)
>  delete mode 100644 OvmfPkg/PlatformPei/Cmos.h
>  create mode 100644 OvmfPkg/PlatformPei/IntelTdx.c
>  create mode 100644 OvmfPkg/TdxDxe/TdxAcpiTable.c
>  create mode 100644 OvmfPkg/TdxDxe/TdxAcpiTable.h
>  create mode 100644 OvmfPkg/TdxDxe/TdxDxe.c
>  create mode 100644 OvmfPkg/TdxDxe/TdxDxe.inf
>  create mode 100644 OvmfPkg/TdxDxe/X64/ApRunLoop.nasm
>  create mode 100644 UefiCpuPkg/Library/MpInitLib/MpIntelTdx.h
>  create mode 100644 UefiCpuPkg/Library/MpInitLib/MpLibTdx.c
>  create mode 100644 UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c
>  create mode 100644 UefiCpuPkg/Library/VmgExitLibNull/VmTdExitNull.c
> 
> --
> 2.29.2.windows.2


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH V12 33/47] OvmfPkg: Update Sec to support Tdx
  2022-03-29 23:46 ` [PATCH V12 33/47] OvmfPkg: Update Sec to support Tdx Min Xu
@ 2022-04-15 20:05   ` Lendacky, Thomas
  2022-04-16  0:13     ` Min Xu
  0 siblings, 1 reply; 53+ messages in thread
From: Lendacky, Thomas @ 2022-04-15 20:05 UTC (permalink / raw)
  To: Min Xu, devel
  Cc: Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Gerd Hoffmann

On 3/29/22 18:46, Min Xu wrote:
> RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
> 
> There are below major changes in this commit.
> 
> 1. SecEntry.nasm
> In TDX BSP and APs goes to the same entry point in SecEntry.nasm.
> 
> BSP initialize the temporary stack and then jumps to SecMain, just as
> legacy Ovmf does.
> 
> APs spin in a modified mailbox loop using initial mailbox structure.
> Its structure defition is in OvmfPkg/Include/IndustryStandard/IntelTdx.h.
> APs wait for command to see if the command is for me. If so execute the
> command.
> 
> 2. Sec/SecMain.c
> 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 major task of this patch is to process the TdHobList
> to accept the memory. After that TDVF follow the standard OVMF flow
> and jump to PEI phase.
> 
> PcdUse1GPageTable is set to FALSE by default in OvmfPkgX64.dsc. It gives
> no chance for Intel TDX to support 1G page table. To support 1G page
> table this PCD is set to TRUE in OvmfPkgX64.dsc.
> 
> TDX_GUEST_SUPPORTED is defined in OvmfPkgX64.dsc. This macro wraps the
> Tdx specific code.
> 
> TDX only works on X64, so the code is only valid in X64 arch.
> 
> Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Brijesh Singh <brijesh.singh@amd.com>
> Cc: Erdem Aktas <erdemaktas@google.com>
> Cc: James Bottomley <jejb@linux.ibm.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Tom Lendacky <thomas.lendacky@amd.com>
> Cc: Gerd Hoffmann <kraxel@redhat.com>
> Acked-by: Gerd Hoffmann <kraxel@redhat.com>
> Signed-off-by: Min Xu <min.m.xu@intel.com>

> diff --git a/OvmfPkg/Sec/SecMain.c b/OvmfPkg/Sec/SecMain.c
> index 02520e25ab9a..ca9717a7b526 100644
> --- a/OvmfPkg/Sec/SecMain.c
> +++ b/OvmfPkg/Sec/SecMain.c
> @@ -26,9 +26,8 @@
>   #include <Library/ExtractGuidedSectionLib.h>
>   #include <Library/LocalApicLib.h>
>   #include <Library/CpuExceptionHandlerLib.h>
> -
>   #include <Ppi/TemporaryRamSupport.h>
> -
> +#include <Library/PlatformInitLib.h>
>   #include "AmdSev.h"
>   
>   #define SEC_IDT_ENTRY_COUNT  34
> @@ -738,6 +737,20 @@ SecCoreStartupWithStack (
>     UINT32                Index;
>     volatile UINT8        *Table;
>   
> + #if defined (TDX_GUEST_SUPPORTED)
> +  if (TdIsEnabled ()) {

I wish I had caught this earlier, but this patch breaks SEV-ES support. 
TdIsEnabled() uses the CPUID instruction. At this point, exception 
handling is not established and a CPUID instruction will generate a #VC 
and cause the booting guest to crash.

That is why the SevEsIsEnabled() function checks the work area to 
determine if SEV-ES is supported. In the early boot code we established a 
temporary #VC handler to specifically handle CPUID and then set the work 
area indicator that SEV-ES is enabled.

I think you'll need to do something similar for this area. Haven't you 
already set the workarea from calling InitTdx before this point?

Thanks,
Tom

> +    //
> +    // For Td guests, the memory map info is in TdHobLib. It should be processed
> +    // first so that the memory is accepted. Otherwise access to the unaccepted
> +    // memory will trigger tripple fault.
> +    //
> +    if (ProcessTdxHobList () != EFI_SUCCESS) {
> +      CpuDeadLoop ();
> +    }
> +  }
> +
> + #endif
> +

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH V12 42/47] OvmfPkg: Add TdxDxe driver
       [not found] ` <4c3aa6915fe7aac06940bea0f9bc5fdd3c539121.1648555175.git.min.m.xu@intel.com>
@ 2022-04-15 20:51   ` Lendacky, Thomas
  2022-04-16  1:57     ` [edk2-devel] " Min Xu
  0 siblings, 1 reply; 53+ messages in thread
From: Lendacky, Thomas @ 2022-04-15 20:51 UTC (permalink / raw)
  To: Min Xu, devel
  Cc: Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Gerd Hoffmann

On 3/29/22 18:46, Min Xu wrote:
> RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
> 
> TdxDxe driver is dispatched early in DXE, due to being list in APRIORI.
> This module is responsible for below features:
>   - Sets max logical cpus based on TDINFO
>   - Sets PCI PCDs based on resource hobs
>   - Set shared bit in MMIO region
>   - Relocate Td mailbox and set its address in MADT table.
> 
> 1. Set shared bit in MMIO region
> 
> Qemu allows a ROM device to set to ROMD mode (default) or MMIO mode.
> When it is in ROMD mode, the device is mapped to guest memory and
> satisfies read access directly.
> 
> In EDK2 Option ROM is treated as MMIO region. So Tdx guest access
> Option ROM via TDVMCALL(MMIO). But as explained above, since Qemu set
> the Option ROM to ROMD mode, the call of TDVMCALL(MMIO) always return
> INVALID_OPERAND. Tdvf then falls back to direct access. This requires
> to set the shared bit to corresponding PageTable entry. Otherwise it
> triggers GP fault.
> 
> TdxDxe's entry point is the right place to set the shared bit in MMIO
> region because Option ROM has not been discoverd yet.
> 
> 2. Relocate Td mailbox and set the new address in MADT Mutiprocessor
> Wakeup Table.
> 
> In TDX the guest firmware is designed to publish a multiprocessor-wakeup
> structure to let the guest-bootstrap processor wake up guest-application
> processors with a mailbox. The mailbox is memory that the guest firmware
> can reserve so each guest virtual processor can have the guest OS send
> a message to them. The address of the mailbox is recorded in the MADT
> table. See [ACPI].
> 
> TdxDxe registers for protocol notification
> (gQemuAcpiTableNotifyProtocolGuid) to call the AlterAcpiTable(), in
> which MADT table is altered by the above Mailbox address. The protocol
> will be installed in AcpiPlatformDxe when the MADT table provided by
> Qemu is ready. This is to maintain the simplicity of the AcpiPlatformDxe.
> 
> AlterAcpiTable is the registered function which traverses the ACPI
> table list to find the original MADT from Qemu. After the new MADT is
> configured and installed, the original one will be uninstalled.
> 
> [ACPI] 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@kernel.org>
> Cc: Jordan Justen <jordan.l.justen@intel.com>
> Cc: Brijesh Singh <brijesh.singh@amd.com>
> Cc: Erdem Aktas <erdemaktas@google.com>
> Cc: James Bottomley <jejb@linux.ibm.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Tom Lendacky <thomas.lendacky@amd.com>
> Cc: Gerd Hoffmann <kraxel@redhat.com>
> Acked-by: Gerd Hoffmann <kraxel@redhat.com>
> Signed-off-by: Min Xu <min.m.xu@intel.com>

Unfortunately, this driver also breaks SEV-ES. I bypassed the TDX code in
the SEC library, but then hit an issue because this driver is loaded
before the AmdSevDxe driver. The AmdSevDxe driver performs a
MemEncryptSevClearMmioPageEncMask() call against the
PcdPciExpressBaseAddress range to mark it shared/unencrypted. However,
the TdxDxe driver is loaded before the AmdSevDxe driver, and it appears
the dependencies result in an MMIO being performed to an address in the
PcdPciExpressBaseAddress range. Since the range has not been marked
shared/unencrypted, the #VC handler terminates the guest for trying to do
MMIO to an encrypted region.

Here is the error information:

Loading driver at 0x0003F1A5000 EntryPoint=0x0003F1A6BF2 TdxDxe.efi
InstallProtocolInterface: BC62157E-3E33-4FEC-9920-2D3B36D750DF 3F1AFA98
ProtectUefiImageCommon - 0x3F1AFB40
   - 0x000000003F1A5000 - 0x0000000000004300
MMIO using encrypted memory: B00F8040
!!!! X64 Exception Type - 0D(#GP - General Protection)  CPU Apic ID - 00000000 !!!!
ExceptionData - 0000000000000000
RIP  - 000000003F1A6E86, CS  - 0000000000000018, RFLAGS - 0000000000010002
RAX  - 00000000B0000000, RCX - 000000003F4EAD18, RDX - 000000003F4EAD01
RBX  - 0000000000000001, RSP - 000000003FBA5B60, RBP - 0000000000000000
RSI  - 0000000000000000, RDI - 000000003F1AFB18
R8   - 00000000B00F8040, R9  - 00000000000029C0, R10 - 0000000000000000
R11  - 0000000000000000, R12 - 0000000000000000, R13 - 0000000000000000
R14  - 000000003FBCC6D0, R15 - 000000003FBC43E6
DS   - 0000000000000008, ES  - 0000000000000008, FS  - 0000000000000008
GS   - 0000000000000008, SS  - 0000000000000008
CR0  - 0000000080010033, CR2 - 0000000000000000, CR3 - 000000003F801000
CR4  - 0000000000000668, CR8 - 0000000000000000
DR0  - 0000000000000000, DR1 - 0000000000000000, DR2 - 0000000000000000
DR3  - 0000000000000000, DR6 - 0000000000000000, DR7 - 0000000000000000
GDTR - 000000003FBFE000 0000000000000027, LDTR - 0000000000000000
IDTR - 000000003BF95D70 000000000000021F,   TR - 0000000000000000
FXSAVE_STATE - 000000003FBA57C0
!!!! Find image based on IP(0x3F1A6E86) /root/kernels/ovmf-build-X64/Build/OvmfX64/DEBUG_GCC5/X64/OvmfPkg/TdxDxe/TdxDxe/DEBUG/TdxDxe.dll (ImageBase=000000003F1A5000, EntryPoint=000000003F1A6BF2) !!!!

Not sure what the best way forward is on this.

Thanks,
Tom

> ---

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH V12 33/47] OvmfPkg: Update Sec to support Tdx
  2022-04-15 20:05   ` Lendacky, Thomas
@ 2022-04-16  0:13     ` Min Xu
  2022-04-16 14:52       ` Lendacky, Thomas
  0 siblings, 1 reply; 53+ messages in thread
From: Min Xu @ 2022-04-16  0:13 UTC (permalink / raw)
  To: Tom Lendacky, devel@edk2.groups.io
  Cc: Ard Biesheuvel, Justen, Jordan L, Brijesh Singh, Aktas, Erdem,
	James Bottomley, Yao, Jiewen, Gerd Hoffmann

On April 16, 2022 4:05 AM, Tom Lendacky wrote:
> >   #define SEC_IDT_ENTRY_COUNT  34
> > @@ -738,6 +737,20 @@ SecCoreStartupWithStack (
> >     UINT32                Index;
> >     volatile UINT8        *Table;
> >
> > + #if defined (TDX_GUEST_SUPPORTED)
> > +  if (TdIsEnabled ()) {
> 
> I wish I had caught this earlier, but this patch breaks SEV-ES support.
> TdIsEnabled() uses the CPUID instruction. At this point, exception handling is
> not established and a CPUID instruction will generate a #VC and cause the
> booting guest to crash.
>
Sorry for the broken.
> 
> That is why the SevEsIsEnabled() function checks the work area to determine
> if SEV-ES is supported. In the early boot code we established a temporary
> #VC handler to specifically handle CPUID and then set the work area
> indicator that SEV-ES is enabled.
> 
> I think you'll need to do something similar for this area. Haven't you already
> set the workarea from calling InitTdx before this point?
TDX has set the workarea in ResetVector.
I am working on a patch-set (now it is v2) which is to fix the issues caused by TdIsEnabled. Please see https://edk2.groups.io/g/devel/message/88916
This patch-set introduce CcProbe() which checks the Ovmf work area to return the guest type. 
In the next version CcProbe will be called instead of TdIsEnabled in SecMain.c.

Please help to review the above patch-set so that there will not be more broken in the future.

Thanks much
Min

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [edk2-devel] [PATCH V12 42/47] OvmfPkg: Add TdxDxe driver
  2022-04-15 20:51   ` [PATCH V12 42/47] OvmfPkg: Add TdxDxe driver Lendacky, Thomas
@ 2022-04-16  1:57     ` Min Xu
  2022-04-16 15:08       ` Lendacky, Thomas
  0 siblings, 1 reply; 53+ messages in thread
From: Min Xu @ 2022-04-16  1:57 UTC (permalink / raw)
  To: devel@edk2.groups.io, thomas.lendacky@amd.com
  Cc: Ard Biesheuvel, Justen, Jordan L, Brijesh Singh, Aktas, Erdem,
	James Bottomley, Yao, Jiewen, Gerd Hoffmann

On April 16, 2022 4:52 AM, Lendacky, Thomas wrote:
> 
> Unfortunately, this driver also breaks SEV-ES. I bypassed the TDX code in the
> SEC library, but then hit an issue because this driver is loaded before the
> AmdSevDxe driver. The AmdSevDxe driver performs a
> MemEncryptSevClearMmioPageEncMask() call against the
> PcdPciExpressBaseAddress range to mark it shared/unencrypted. However,
> the TdxDxe driver is loaded before the AmdSevDxe driver, and it appears the
> dependencies result in an MMIO being performed to an address in the
> PcdPciExpressBaseAddress range. Since the range has not been marked
> shared/unencrypted, the #VC handler terminates the guest for trying to do
> MMIO to an encrypted region.
> 
I carefully check the code TdxDxeEntryPoint@TdxDxe.c.
If the working guest is NOT td guest, before it returns, it just does below:
1. check if the GuidHob exists
2. Set PcdOvmfHostBridgePciDevId with the information in the GuidHob

SetMmioSharedBit() is called if the working guest is Td guest. So if it is sev guest, SetMmioSharedBit will not be called.

I don't have a SEV-ES in hand. Can you help to add some debug information in TdxDxe to see what the last code before the exception is triggered?

BTW, have you tried to load AmdSev.inf before TdxDxe.inf? I tried it in my TDX guest and it works fine.

Thanks
Min

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH V12 33/47] OvmfPkg: Update Sec to support Tdx
  2022-04-16  0:13     ` Min Xu
@ 2022-04-16 14:52       ` Lendacky, Thomas
  2022-04-17  3:03         ` Min Xu
  0 siblings, 1 reply; 53+ messages in thread
From: Lendacky, Thomas @ 2022-04-16 14:52 UTC (permalink / raw)
  To: Xu, Min M, devel@edk2.groups.io
  Cc: Ard Biesheuvel, Justen, Jordan L, Brijesh Singh, Aktas, Erdem,
	James Bottomley, Yao, Jiewen, Gerd Hoffmann

On 4/15/22 19:13, Xu, Min M wrote:
> On April 16, 2022 4:05 AM, Tom Lendacky wrote:
>>>    #define SEC_IDT_ENTRY_COUNT  34
>>> @@ -738,6 +737,20 @@ SecCoreStartupWithStack (
>>>      UINT32                Index;
>>>      volatile UINT8        *Table;
>>>
>>> + #if defined (TDX_GUEST_SUPPORTED)
>>> +  if (TdIsEnabled ()) {
>>
>> I wish I had caught this earlier, but this patch breaks SEV-ES support.
>> TdIsEnabled() uses the CPUID instruction. At this point, exception handling is
>> not established and a CPUID instruction will generate a #VC and cause the
>> booting guest to crash.
>>
> Sorry for the broken.
>>
>> That is why the SevEsIsEnabled() function checks the work area to determine
>> if SEV-ES is supported. In the early boot code we established a temporary
>> #VC handler to specifically handle CPUID and then set the work area
>> indicator that SEV-ES is enabled.
>>
>> I think you'll need to do something similar for this area. Haven't you already
>> set the workarea from calling InitTdx before this point?
> TDX has set the workarea in ResetVector.
> I am working on a patch-set (now it is v2) which is to fix the issues caused by TdIsEnabled. Please see https://edk2.groups.io/g/devel/message/88916
> This patch-set introduce CcProbe() which checks the Ovmf work area to return the guest type.
> In the next version CcProbe will be called instead of TdIsEnabled in SecMain.c.
> 
> Please help to review the above patch-set so that there will not be more broken in the future.

I'll test out that patchset on Monday. Thanks!

Tom

> 
> Thanks much
> Min

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [edk2-devel] [PATCH V12 42/47] OvmfPkg: Add TdxDxe driver
  2022-04-16  1:57     ` [edk2-devel] " Min Xu
@ 2022-04-16 15:08       ` Lendacky, Thomas
  2022-04-17  0:56         ` Min Xu
  0 siblings, 1 reply; 53+ messages in thread
From: Lendacky, Thomas @ 2022-04-16 15:08 UTC (permalink / raw)
  To: Xu, Min M, devel@edk2.groups.io
  Cc: Ard Biesheuvel, Justen, Jordan L, Brijesh Singh, Aktas, Erdem,
	James Bottomley, Yao, Jiewen, Gerd Hoffmann

On 4/15/22 20:57, Xu, Min M wrote:
> On April 16, 2022 4:52 AM, Lendacky, Thomas wrote:
>>
>> Unfortunately, this driver also breaks SEV-ES. I bypassed the TDX code in the
>> SEC library, but then hit an issue because this driver is loaded before the
>> AmdSevDxe driver. The AmdSevDxe driver performs a
>> MemEncryptSevClearMmioPageEncMask() call against the
>> PcdPciExpressBaseAddress range to mark it shared/unencrypted. However,
>> the TdxDxe driver is loaded before the AmdSevDxe driver, and it appears the
>> dependencies result in an MMIO being performed to an address in the
>> PcdPciExpressBaseAddress range. Since the range has not been marked
>> shared/unencrypted, the #VC handler terminates the guest for trying to do
>> MMIO to an encrypted region.
>>
> I carefully check the code TdxDxeEntryPoint@TdxDxe.c.
> If the working guest is NOT td guest, before it returns, it just does below:
> 1. check if the GuidHob exists
> 2. Set PcdOvmfHostBridgePciDevId with the information in the GuidHob
> 
> SetMmioSharedBit() is called if the working guest is Td guest. So if it is sev guest, SetMmioSharedBit will not be called.
> 
> I don't have a SEV-ES in hand. Can you help to add some debug information in TdxDxe to see what the last code before the exception is triggered?

I don't think it is anything in your code, I think it is another library 
that is being loaded based on dependencies. I put a DEBUG statement at the 
start of TdxDxeEntryPoint() and never see the output before the crash.

> 
> BTW, have you tried to load AmdSev.inf before TdxDxe.inf? I tried it in my TDX guest and it works fine.

Yes, moving AmdSevDxe.inf ahead of TdxDxe.inf does fix this issue. Do you 
want to submit the patch or do you want me to?

Thanks,
Tom

> 
> Thanks
> Min

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [edk2-devel] [PATCH V12 42/47] OvmfPkg: Add TdxDxe driver
  2022-04-16 15:08       ` Lendacky, Thomas
@ 2022-04-17  0:56         ` Min Xu
  2022-04-18 13:36           ` Lendacky, Thomas
  0 siblings, 1 reply; 53+ messages in thread
From: Min Xu @ 2022-04-17  0:56 UTC (permalink / raw)
  To: devel@edk2.groups.io, thomas.lendacky@amd.com
  Cc: Ard Biesheuvel, Justen, Jordan L, Brijesh Singh, Aktas, Erdem,
	James Bottomley, Yao, Jiewen, Gerd Hoffmann

On April 16, 2022 11:09 PM, Lendacky, Thomas wrote:
> On 4/15/22 20:57, Xu, Min M wrote:
> > On April 16, 2022 4:52 AM, Lendacky, Thomas wrote:
> >>
> >> Unfortunately, this driver also breaks SEV-ES. I bypassed the TDX
> >> code in the SEC library, but then hit an issue because this driver is
> >> loaded before the AmdSevDxe driver. The AmdSevDxe driver performs a
> >> MemEncryptSevClearMmioPageEncMask() call against the
> >> PcdPciExpressBaseAddress range to mark it shared/unencrypted.
> >> However, the TdxDxe driver is loaded before the AmdSevDxe driver, and
> >> it appears the dependencies result in an MMIO being performed to an
> >> address in the PcdPciExpressBaseAddress range. Since the range has
> >> not been marked shared/unencrypted, the #VC handler terminates the
> >> guest for trying to do MMIO to an encrypted region.
> >>
> > I carefully check the code TdxDxeEntryPoint@TdxDxe.c.
> > If the working guest is NOT td guest, before it returns, it just does below:
> > 1. check if the GuidHob exists
> > 2. Set PcdOvmfHostBridgePciDevId with the information in the GuidHob
> >
> > SetMmioSharedBit() is called if the working guest is Td guest. So if it is sev
> guest, SetMmioSharedBit will not be called.
> >
> > I don't have a SEV-ES in hand. Can you help to add some debug
> information in TdxDxe to see what the last code before the exception is
> triggered?
> 
> I don't think it is anything in your code, I think it is another library that is
> being loaded based on dependencies. I put a DEBUG statement at the start
> of TdxDxeEntryPoint() and never see the output before the crash.
>
I check the libraries loaded by TdxDxe and AmdSev and find that they load different PciLib.
TdxDxe load PciLib|OvmfPkg/Library/DxePciLibI440FxQ35/DxePciLibI440FxQ35.inf.
AmdSev load PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf.

PciLib is consumed by DxeAcpiTimerLib. In the AcpiTimerLibConstructor@DxeAcpiTimerLib there is below code:
mAcpiTimerIoAddr = (PciRead32 (Pmba) & ~PMBA_RTE) + ACPI_TIMER_OFFSET;

I think this is the root cause of the exception.

There are 2 options to fix this issue.
1. Load AmdSev before TdxDxe
2. Make TdxDxe to import BasePciLibCf8.inf instead of DxePciLibI440FxQ35.inf (just like AmdSev)

I tried above 2 options in my Tdx guest and both work.
Tom, Can you help to try above 2 options in your SEV guest to see whether they work?

> 
> >
> > BTW, have you tried to load AmdSev.inf before TdxDxe.inf? I tried it in my
> TDX guest and it works fine.
> 
> Yes, moving AmdSevDxe.inf ahead of TdxDxe.inf does fix this issue. Do you
> want to submit the patch or do you want me to?
> 
If above option 2 works, I prefer this option to fix the issue. Because there is still potential issues in option 1. I will submit the patch.

Thanks
Min

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH V12 33/47] OvmfPkg: Update Sec to support Tdx
  2022-04-16 14:52       ` Lendacky, Thomas
@ 2022-04-17  3:03         ` Min Xu
  0 siblings, 0 replies; 53+ messages in thread
From: Min Xu @ 2022-04-17  3:03 UTC (permalink / raw)
  To: Tom Lendacky, devel@edk2.groups.io
  Cc: Ard Biesheuvel, Justen, Jordan L, Brijesh Singh, Aktas, Erdem,
	James Bottomley, Yao, Jiewen, Gerd Hoffmann

On April 16, 2022 10:52 PM, Tom Lendacky wrote:
> On 4/15/22 19:13, Xu, Min M wrote:
> > On April 16, 2022 4:05 AM, Tom Lendacky wrote:
> >>>    #define SEC_IDT_ENTRY_COUNT  34
> >>> @@ -738,6 +737,20 @@ SecCoreStartupWithStack (
> >>>      UINT32                Index;
> >>>      volatile UINT8        *Table;
> >>>
> >>> + #if defined (TDX_GUEST_SUPPORTED)
> >>> +  if (TdIsEnabled ()) {
> >>
> >> I wish I had caught this earlier, but this patch breaks SEV-ES support.
> >> TdIsEnabled() uses the CPUID instruction. At this point, exception
> >> handling is not established and a CPUID instruction will generate a
> >> #VC and cause the booting guest to crash.
> >>
> > Sorry for the broken.
> >>
> >> That is why the SevEsIsEnabled() function checks the work area to
> >> determine if SEV-ES is supported. In the early boot code we
> >> established a temporary #VC handler to specifically handle CPUID and
> >> then set the work area indicator that SEV-ES is enabled.
> >>
> >> I think you'll need to do something similar for this area. Haven't
> >> you already set the workarea from calling InitTdx before this point?
> > TDX has set the workarea in ResetVector.
> > I am working on a patch-set (now it is v2) which is to fix the issues
> > caused by TdIsEnabled. Please see
> > https://edk2.groups.io/g/devel/message/88916
> > This patch-set introduce CcProbe() which checks the Ovmf work area to
> return the guest type.
> > In the next version CcProbe will be called instead of TdIsEnabled in
> SecMain.c.
> >
> > Please help to review the above patch-set so that there will not be more
> broken in the future.
> 
> I'll test out that patchset on Monday. Thanks!
> 
The patch-set is sent out. Please help to review.
https://edk2.groups.io/g/devel/message/88969

Thanks
Min

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [edk2-devel] [PATCH V12 42/47] OvmfPkg: Add TdxDxe driver
  2022-04-17  0:56         ` Min Xu
@ 2022-04-18 13:36           ` Lendacky, Thomas
  0 siblings, 0 replies; 53+ messages in thread
From: Lendacky, Thomas @ 2022-04-18 13:36 UTC (permalink / raw)
  To: Xu, Min M, devel@edk2.groups.io
  Cc: Ard Biesheuvel, Justen, Jordan L, Brijesh Singh, Aktas, Erdem,
	James Bottomley, Yao, Jiewen, Gerd Hoffmann

On 4/16/22 19:56, Xu, Min M wrote:
> On April 16, 2022 11:09 PM, Lendacky, Thomas wrote:
>> On 4/15/22 20:57, Xu, Min M wrote:
>>> On April 16, 2022 4:52 AM, Lendacky, Thomas wrote:
>>>>
>>>> Unfortunately, this driver also breaks SEV-ES. I bypassed the TDX
>>>> code in the SEC library, but then hit an issue because this driver is
>>>> loaded before the AmdSevDxe driver. The AmdSevDxe driver performs a
>>>> MemEncryptSevClearMmioPageEncMask() call against the
>>>> PcdPciExpressBaseAddress range to mark it shared/unencrypted.
>>>> However, the TdxDxe driver is loaded before the AmdSevDxe driver, and
>>>> it appears the dependencies result in an MMIO being performed to an
>>>> address in the PcdPciExpressBaseAddress range. Since the range has
>>>> not been marked shared/unencrypted, the #VC handler terminates the
>>>> guest for trying to do MMIO to an encrypted region.
>>>>
>>> I carefully check the code TdxDxeEntryPoint@TdxDxe.c.
>>> If the working guest is NOT td guest, before it returns, it just does below:
>>> 1. check if the GuidHob exists
>>> 2. Set PcdOvmfHostBridgePciDevId with the information in the GuidHob
>>>
>>> SetMmioSharedBit() is called if the working guest is Td guest. So if it is sev
>> guest, SetMmioSharedBit will not be called.
>>>
>>> I don't have a SEV-ES in hand. Can you help to add some debug
>> information in TdxDxe to see what the last code before the exception is
>> triggered?
>>
>> I don't think it is anything in your code, I think it is another library that is
>> being loaded based on dependencies. I put a DEBUG statement at the start
>> of TdxDxeEntryPoint() and never see the output before the crash.
>>
> I check the libraries loaded by TdxDxe and AmdSev and find that they load different PciLib.
> TdxDxe load PciLib|OvmfPkg/Library/DxePciLibI440FxQ35/DxePciLibI440FxQ35.inf.
> AmdSev load PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf.
> 
> PciLib is consumed by DxeAcpiTimerLib. In the AcpiTimerLibConstructor@DxeAcpiTimerLib there is below code:
> mAcpiTimerIoAddr = (PciRead32 (Pmba) & ~PMBA_RTE) + ACPI_TIMER_OFFSET;
> 
> I think this is the root cause of the exception.
> 
> There are 2 options to fix this issue.
> 1. Load AmdSev before TdxDxe
> 2. Make TdxDxe to import BasePciLibCf8.inf instead of DxePciLibI440FxQ35.inf (just like AmdSev)
> 
> I tried above 2 options in my Tdx guest and both work.
> Tom, Can you help to try above 2 options in your SEV guest to see whether they work?
> 
>>
>>>
>>> BTW, have you tried to load AmdSev.inf before TdxDxe.inf? I tried it in my
>> TDX guest and it works fine.
>>
>> Yes, moving AmdSevDxe.inf ahead of TdxDxe.inf does fix this issue. Do you
>> want to submit the patch or do you want me to?
>>
> If above option 2 works, I prefer this option to fix the issue. Because there is still potential issues in option 1. I will submit the patch.

I added the same library class override to TdxDxe and, yes, option 2 worked.

Thanks,
Tom

> 
> Thanks
> Min

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH V12 14/47] UefiCpuPkg: Enable Tdx support in MpInitLib
  2022-03-29 23:46 ` [PATCH V12 14/47] UefiCpuPkg: Enable Tdx support in MpInitLib Min Xu
  2022-03-30  7:53   ` [edk2-devel] " Ni, Ray
@ 2022-04-28 13:15   ` Lendacky, Thomas
  2022-04-29  2:12     ` Min Xu
  1 sibling, 1 reply; 53+ messages in thread
From: Lendacky, Thomas @ 2022-04-28 13:15 UTC (permalink / raw)
  To: Min Xu, devel
  Cc: Erdem Aktas, James Bottomley, Jiewen Yao, Eric Dong, Ray Ni,
	Rahul Kumar, Gerd Hoffmann

On 3/29/22 18:46, Min Xu wrote:
> 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. 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@amd.com>
> Cc: Erdem Aktas <erdemaktas@google.com>
> Cc: James Bottomley <jejb@linux.ibm.com>
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Tom Lendacky <thomas.lendacky@amd.com>
> Cc: Eric Dong <eric.dong@intel.com>
> Cc: Ray Ni <ray.ni@intel.com>
> Cc: Rahul Kumar <rahul1.kumar@intel.com>
> Cc: Gerd Hoffmann <kraxel@redhat.com>
> Acked-by: Gerd Hoffmann <kraxel@redhat.com>
> Signed-off-by: Min Xu <min.m.xu@intel.com>
> ---
>   UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf |   3 +
>   UefiCpuPkg/Library/MpInitLib/MpIntelTdx.h     |  69 ++++++++++++
>   UefiCpuPkg/Library/MpInitLib/MpLib.c          |  63 ++++++++++-
>   UefiCpuPkg/Library/MpInitLib/MpLibTdx.c       | 106 ++++++++++++++++++
>   UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c   |  69 ++++++++++++
>   UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf |   3 +
>   6 files changed, 308 insertions(+), 5 deletions(-)
>   create mode 100644 UefiCpuPkg/Library/MpInitLib/MpIntelTdx.h
>   create mode 100644 UefiCpuPkg/Library/MpInitLib/MpLibTdx.c
>   create mode 100644 UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c
> 

>     //
> @@ -2367,6 +2385,11 @@ MpInitLibWhoAmI (
>       return EFI_INVALID_PARAMETER;
>     }
>   
> +  if (CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr))) {
> +    *ProcessorNumber = 0;
> +    return EFI_SUCCESS;
> +  }
> +

I've narrowed down this change as causing issues when booting multiple 
vCPU guests (regular and SEV). This issues consist of EfiAcquireLock() / 
EfiReleaseLock() ASSERTS and TPL level ASSERTS that occur during 
ExitBootServices when the APs are being parked by RelocateApLoop(). The 
PCD accesses use locking which is not SMP safe. I believe PCD calls are 
not supposed to be issued by APs because of this (or at least not APs 
executing in parallel).

This check is spread throughout the MpLib code and I didn't look to see 
how many of those calls can be done by an AP. I think the PCD usage can be 
reduced to getting the PcdConfidentialComputingGuestAttr value at init and 
caching it in a STATIC variable, but I would feel better if @Min Xu could 
verify that and submit a patch accordingly. Otherwise, maybe this TDX 
guest setting could be added to the CpuMpData (similar to the 
SevEsIsEnabled, etc. fields).

A future cleanup could cache PcdConfidentialComputingGuestAttr in 
CpuMpData and use CC_GUEST_IS_XXX() calls against that.

Thanks,
Tom

>     CpuMpData = GetCpuMpData ();
>   
>     return GetProcessorNumber (CpuMpData, ProcessorNumber);

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH V12 14/47] UefiCpuPkg: Enable Tdx support in MpInitLib
  2022-04-28 13:15   ` Lendacky, Thomas
@ 2022-04-29  2:12     ` Min Xu
  0 siblings, 0 replies; 53+ messages in thread
From: Min Xu @ 2022-04-29  2:12 UTC (permalink / raw)
  To: Tom Lendacky, devel@edk2.groups.io
  Cc: Aktas, Erdem, James Bottomley, Yao, Jiewen, Dong, Eric, Ni, Ray,
	Kumar, Rahul1, Gerd Hoffmann

On April 28, 2022 9:16 PM, Tom Lendacky wrote:
> > +  if (CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr)))
> {
> > +    *ProcessorNumber = 0;
> > +    return EFI_SUCCESS;
> > +  }
> > +
> 
> I've narrowed down this change as causing issues when booting multiple
> vCPU guests (regular and SEV). This issues consist of EfiAcquireLock() /
> EfiReleaseLock() ASSERTS and TPL level ASSERTS that occur during
> ExitBootServices when the APs are being parked by RelocateApLoop(). The
> PCD accesses use locking which is not SMP safe. I believe PCD calls are not
> supposed to be issued by APs because of this (or at least not APs executing in
> parallel).
> 
> This check is spread throughout the MpLib code and I didn't look to see how
> many of those calls can be done by an AP. I think the PCD usage can be
> reduced to getting the PcdConfidentialComputingGuestAttr value at init and
> caching it in a STATIC variable, but I would feel better if @Min Xu could
> verify that and submit a patch accordingly. Otherwise, maybe this TDX guest
> setting could be added to the CpuMpData (similar to the SevEsIsEnabled, etc.
> fields).
>
I verified this fix and it seems working.  I will submit a patch soon.


Thanks
Min

^ permalink raw reply	[flat|nested] 53+ messages in thread

end of thread, other threads:[~2022-04-29  2:12 UTC | newest]

Thread overview: 53+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-03-29 23:45 [PATCH V12 00/47] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
2022-03-29 23:45 ` [PATCH V12 01/47] MdePkg: Add Tdx.h Min Xu
2022-03-29 23:45 ` [PATCH V12 02/47] MdePkg: Update Cpuid.h for Tdx Min Xu
2022-03-29 23:45 ` [PATCH V12 03/47] MdePkg: Introduce basic Tdx functions in BaseLib Min Xu
2022-03-29 23:45 ` [PATCH V12 04/47] MdePkg: Add TdxLib to wrap Tdx operations Min Xu
2022-03-29 23:45 ` [PATCH V12 05/47] UefiCpuPkg: Extend VmgExitLibNull to handle #VE exception Min Xu
2022-03-29 23:45 ` [PATCH V12 06/47] OvmfPkg: Extend VmgExitLib " Min Xu
2022-03-29 23:46 ` [PATCH V12 07/47] UefiCpuPkg/CpuExceptionHandler: Add base support for the " Min Xu
2022-03-29 23:46 ` [PATCH V12 08/47] MdePkg: Add helper functions for Tdx guest in BaseIoLibIntrinsic Min Xu
2022-03-29 23:46 ` [PATCH V12 09/47] MdePkg: Support mmio " Min Xu
2022-03-29 23:46 ` [PATCH V12 10/47] MdePkg: Support IoFifo " Min Xu
2022-03-29 23:46 ` [PATCH V12 11/47] MdePkg: Support IoRead/IoWrite " Min Xu
2022-03-29 23:46 ` [PATCH V12 12/47] UefiCpuPkg: Support TDX in BaseXApicX2ApicLib Min Xu
2022-03-29 23:46 ` [PATCH V12 13/47] MdePkg: Add macro to check SEV / TDX guest Min Xu
2022-03-29 23:46 ` [PATCH V12 14/47] UefiCpuPkg: Enable Tdx support in MpInitLib Min Xu
2022-03-30  7:53   ` [edk2-devel] " Ni, Ray
2022-04-28 13:15   ` Lendacky, Thomas
2022-04-29  2:12     ` Min Xu
2022-03-29 23:46 ` [PATCH V12 15/47] OvmfPkg: Add IntelTdx.h in OvmfPkg/Include/IndustryStandard Min Xu
2022-03-29 23:46 ` [PATCH V12 16/47] OvmfPkg: Add TdxMailboxLib Min Xu
2022-03-29 23:46 ` [PATCH V12 17/47] OvmfPkg: Create initial version of PlatformInitLib Min Xu
2022-03-29 23:46 ` [PATCH V12 18/47] OvmfPkg/PlatformInitLib: Add hob functions Min Xu
2022-03-29 23:46 ` [PATCH V12 19/47] OvmfPkg/PlatformPei: Move global variables to PlatformInfoHob Min Xu
2022-03-29 23:46 ` [PATCH V12 20/47] OvmfPkg/PlatformPei: Refactor MiscInitialization Min Xu
2022-03-29 23:46 ` [PATCH V12 21/47] OvmfPkg/PlatformPei: Refactor MiscInitialization for CloudHV Min Xu
2022-03-29 23:46 ` [PATCH V12 22/47] OvmfPkg/PlatformPei: Refactor AddressWidthInitialization Min Xu
2022-03-29 23:46 ` [PATCH V12 23/47] OvmfPkg/PlatformPei: Refactor MaxCpuCountInitialization Min Xu
2022-03-29 23:46 ` [PATCH V12 24/47] OvmfPkg/PlatformPei: Refactor QemuUc32BaseInitialization Min Xu
2022-03-29 23:46 ` [PATCH V12 25/47] OvmfPkg/PlatformPei: Refactor InitializeRamRegions Min Xu
2022-03-29 23:46 ` [PATCH V12 26/47] OvmfPkg/PlatformPei: Refactor MemMapInitialization Min Xu
2022-03-29 23:46 ` [PATCH V12 27/47] OvmfPkg/PlatformPei: Refactor NoexecDxeInitialization Min Xu
2022-03-29 23:46 ` [PATCH V12 28/47] OvmfPkg/PlatformPei: Refactor MiscInitialization Min Xu
2022-03-29 23:46 ` [PATCH V12 29/47] OvmfPkg/PlatformInitLib: Create MemDetect.c Min Xu
2022-03-29 23:46 ` [PATCH V12 30/47] OvmfPkg/PlatformInitLib: Move functions to Platform.c Min Xu
2022-03-29 23:46 ` [PATCH V12 31/47] OvmfPkg: Update PlatformInitLib to process Tdx hoblist Min Xu
2022-03-29 23:46 ` [PATCH V12 32/47] OvmfPkg/Sec: Declare local variable as volatile in SecCoreStartupWithStack Min Xu
2022-03-29 23:46 ` [PATCH V12 33/47] OvmfPkg: Update Sec to support Tdx Min Xu
2022-04-15 20:05   ` Lendacky, Thomas
2022-04-16  0:13     ` Min Xu
2022-04-16 14:52       ` Lendacky, Thomas
2022-04-17  3:03         ` Min Xu
2022-03-29 23:46 ` [PATCH V12 34/47] OvmfPkg: Check Tdx in QemuFwCfgPei to avoid DMA operation Min Xu
2022-03-29 23:46 ` [PATCH V12 35/47] MdeModulePkg: Skip setting IA32_ERER.NXE if it has already been set Min Xu
2022-03-29 23:46 ` [PATCH V12 36/47] MdeModulePkg: Add PcdTdxSharedBitMask Min Xu
2022-03-29 23:46 ` [PATCH V12 37/47] UefiCpuPkg: Update AddressEncMask in CpuPageTable Min Xu
2022-03-29 23:46 ` [PATCH V12 38/47] OvmfPkg: Update PlatformInitLib for Tdx guest Min Xu
2022-03-29 23:46 ` [PATCH V12 39/47] OvmfPkg: Update PlatformPei to support " Min Xu
2022-03-31  2:47 ` [PATCH V12 00/47] Enable Intel TDX in OvmfPkg (Config-A) Yao, Jiewen
     [not found] ` <4c3aa6915fe7aac06940bea0f9bc5fdd3c539121.1648555175.git.min.m.xu@intel.com>
2022-04-15 20:51   ` [PATCH V12 42/47] OvmfPkg: Add TdxDxe driver Lendacky, Thomas
2022-04-16  1:57     ` [edk2-devel] " Min Xu
2022-04-16 15:08       ` Lendacky, Thomas
2022-04-17  0:56         ` Min Xu
2022-04-18 13:36           ` Lendacky, Thomas

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox