public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [PATCH V4 00/31] Enable Intel TDX in OvmfPkg (Config-A)
@ 2021-12-13 12:56 Min Xu
  2021-12-13 12:56 ` [PATCH V4 01/31] MdePkg: Add Tdx.h Min Xu
                   ` (30 more replies)
  0 siblings, 31 replies; 68+ messages in thread
From: Min Xu @ 2021-12-13 12:56 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

Note:
To improve the review efficiency the whole TDVF upstream to EDK2 is
splitted into several waves. Wave-1 is focused on the changes in
OvmfPkg/ResetVector. It has been merged into master branch.

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

Patch 22 - 22 are changes for PEI phase.

Patch 23 - 27 are changes in DXE phase.

Patch 28 - 31 are for local Apic timer DXE driver. They're under review
in another separate patch-set. But to keep the code complete and
workable, they're included in this patch-set. They can be skipped.

[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.v4

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 (31):
  MdePkg: Add Tdx.h
  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
  MdePkg: Add EFI_RESOURCE_ATTRIBUTE_ENCRYPTED in PiHob.h
  OvmfPkg: Update Sec to support Tdx
  OvmfPkg: Check Tdx in QemuFwCfgPei to avoid DMA operation
  MdeModulePkg: EFER should not be changed in TDX
  MdeModulePkg: Add PcdTdxSharedBitMask
  UefiCpuPkg: Update AddressEncMask in CpuPageTable
  OvmfPkg: Update PlatformPei to support TDX
  OvmfPkg: Update AcpiPlatformDxe to alter MADT table
  OvmfPkg: Add TdxDxe driver
  OvmfPkg/BaseMemEncryptTdxLib: Add TDX helper library
  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
  OvmfPkg: Move LocalApicTimerDxe to UefiCpuPkg

 MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf       |   1 +
 .../Core/DxeIplPeim/X64/VirtualMemory.c       |   7 +
 MdeModulePkg/MdeModulePkg.dec                 |   9 +
 .../Include/ConfidentialComputingGuestAttr.h  |   3 +
 MdePkg/Include/IndustryStandard/Tdx.h         | 203 ++++
 MdePkg/Include/Library/BaseLib.h              |  62 ++
 MdePkg/Include/Library/TdxLib.h               |  97 ++
 MdePkg/Include/Pi/PiHob.h                     |   8 +
 .../BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf |   2 +
 .../BaseIoLibIntrinsicSev.inf                 |   7 +
 MdePkg/Library/BaseIoLibIntrinsic/IoLib.c     |  81 +-
 MdePkg/Library/BaseIoLibIntrinsic/IoLibFifo.c | 216 ++++
 MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c  |  51 +-
 .../BaseIoLibIntrinsic/IoLibInternalTdx.c     | 675 +++++++++++++
 .../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            |  11 +
 MdePkg/Library/BaseLib/IntelTdxNull.c         |  83 ++
 MdePkg/Library/BaseLib/X64/TdCall.nasm        |  85 ++
 MdePkg/Library/BaseLib/X64/TdProbe.c          |  62 ++
 MdePkg/Library/BaseLib/X64/TdVmcall.nasm      | 145 +++
 MdePkg/Library/TdxLib/AcceptPages.c           | 180 ++++
 MdePkg/Library/TdxLib/Rtmr.c                  |  83 ++
 MdePkg/Library/TdxLib/TdInfo.c                | 114 +++
 MdePkg/Library/TdxLib/TdxLib.inf              |  37 +
 MdePkg/Library/TdxLib/TdxLibNull.c            | 107 ++
 MdePkg/MdePkg.dec                             |   3 +
 MdePkg/MdePkg.dsc                             |   1 +
 OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf   |   1 +
 OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c       |  14 +-
 OvmfPkg/AmdSev/AmdSevX64.dsc                  |   5 +-
 OvmfPkg/AmdSev/AmdSevX64.fdf                  |   3 +-
 OvmfPkg/Include/IndustryStandard/IntelTdx.h   |  76 ++
 OvmfPkg/Include/Library/MemEncryptTdxLib.h    |  81 ++
 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   | 941 ++++++++++++++++++
 .../BaseMemEncryptTdxLib/VirtualMemory.h      | 181 ++++
 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    | 140 +++
 .../Library/TdxMailboxLib/TdxMailboxLib.inf   |  52 +
 .../Library/TdxMailboxLib/TdxMailboxNull.c    |  85 ++
 OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf  |   4 +-
 OvmfPkg/Library/VmgExitLib/VmTdExitHandler.h  |  32 +
 .../Library/VmgExitLib/VmTdExitVeHandler.c    | 562 +++++++++++
 OvmfPkg/Library/VmgExitLib/VmgExitLib.inf     |   3 +
 .../Library/VmgExitLib/X64/TdVmcallCpuid.nasm | 146 +++
 OvmfPkg/Microvm/MicrovmX64.dsc                |   2 +-
 OvmfPkg/Microvm/MicrovmX64.fdf                |   2 +-
 OvmfPkg/OvmfPkg.dec                           |  16 +
 OvmfPkg/OvmfPkgIa32.dsc                       |  11 +-
 OvmfPkg/OvmfPkgIa32.fdf                       |   8 +-
 OvmfPkg/OvmfPkgIa32X64.dsc                    |  13 +-
 OvmfPkg/OvmfPkgIa32X64.fdf                    |   8 +-
 OvmfPkg/OvmfPkgX64.dsc                        |  20 +-
 OvmfPkg/OvmfPkgX64.fdf                        |  11 +-
 OvmfPkg/OvmfXen.dsc                           |   2 +-
 OvmfPkg/OvmfXen.fdf                           |   2 +-
 OvmfPkg/PlatformPei/FeatureControl.c          |   8 +-
 OvmfPkg/PlatformPei/IntelTdx.c                | 223 +++++
 OvmfPkg/PlatformPei/IntelTdxNull.c            |  49 +
 OvmfPkg/PlatformPei/MemDetect.c               |  56 +-
 OvmfPkg/PlatformPei/Platform.c                |   1 +
 OvmfPkg/PlatformPei/Platform.h                |  22 +
 OvmfPkg/PlatformPei/PlatformPei.inf           |  12 +
 OvmfPkg/Sec/IntelTdx.c                        | 557 +++++++++++
 OvmfPkg/Sec/IntelTdx.h                        |  46 +
 OvmfPkg/Sec/SecMain.c                         |  46 +-
 OvmfPkg/Sec/SecMain.inf                       |   7 +
 OvmfPkg/Sec/X64/SecEntry.nasm                 |  82 ++
 OvmfPkg/TdxDxe/TdxAcpiTable.c                 | 213 ++++
 OvmfPkg/TdxDxe/TdxAcpiTable.h                 |  60 ++
 OvmfPkg/TdxDxe/TdxDxe.c                       | 251 +++++
 OvmfPkg/TdxDxe/TdxDxe.inf                     |  64 ++
 OvmfPkg/TdxDxe/X64/ApRunLoop.nasm             |  87 ++
 UefiCpuPkg/CpuDxe/CpuDxe.inf                  |   1 +
 UefiCpuPkg/CpuDxe/CpuPageTable.c              |   4 +
 UefiCpuPkg/Include/Library/VmgExitLib.h       |  28 +
 .../BaseXApicX2ApicLib/BaseXApicX2ApicLib.c   | 170 +++-
 .../PeiDxeSmmCpuException.c                   |  17 +
 .../SecPeiCpuException.c                      |  18 +
 UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf |   3 +
 UefiCpuPkg/Library/MpInitLib/DxeMpLib.c       |  15 +-
 UefiCpuPkg/Library/MpInitLib/MpIntelTdx.h     |  71 ++
 UefiCpuPkg/Library/MpInitLib/MpLib.c          |  27 +
 UefiCpuPkg/Library/MpInitLib/MpLibTdx.c       | 128 +++
 UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c   |  73 ++
 UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf |   3 +
 .../Library/VmgExitLibNull/VmTdExitNull.c     |  38 +
 .../Library/VmgExitLibNull/VmgExitLibNull.inf |   1 +
 .../LocalApicTimerDxe/LocalApicTimerDxe.c     |  15 +-
 .../LocalApicTimerDxe/LocalApicTimerDxe.h     |   4 +-
 .../LocalApicTimerDxe/LocalApicTimerDxe.inf   |  22 +-
 UefiCpuPkg/UefiCpuPkg.dsc                     |   1 +
 109 files changed, 8692 insertions(+), 163 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/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
 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
 create mode 100644 OvmfPkg/PlatformPei/IntelTdx.c
 create mode 100644 OvmfPkg/PlatformPei/IntelTdxNull.c
 create mode 100644 OvmfPkg/Sec/IntelTdx.c
 create mode 100644 OvmfPkg/Sec/IntelTdx.h
 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
 rename OvmfPkg/XenTimerDxe/XenTimerDxe.c => UefiCpuPkg/LocalApicTimerDxe/LocalApicTimerDxe.c (94%)
 rename OvmfPkg/XenTimerDxe/XenTimerDxe.h => UefiCpuPkg/LocalApicTimerDxe/LocalApicTimerDxe.h (96%)
 rename OvmfPkg/XenTimerDxe/XenTimerDxe.inf => UefiCpuPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf (56%)

-- 
2.29.2.windows.2


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

* [PATCH V4 01/31] MdePkg: Add Tdx.h
  2021-12-13 12:56 [PATCH V4 00/31] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
@ 2021-12-13 12:56 ` Min Xu
  2021-12-13 12:56 ` [PATCH V4 02/31] MdePkg: Introduce basic Tdx functions in BaseLib Min Xu
                   ` (29 subsequent siblings)
  30 siblings, 0 replies; 68+ messages in thread
From: Min Xu @ 2021-12-13 12:56 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>
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] 68+ messages in thread

* [PATCH V4 02/31] MdePkg: Introduce basic Tdx functions in BaseLib
  2021-12-13 12:56 [PATCH V4 00/31] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
  2021-12-13 12:56 ` [PATCH V4 01/31] MdePkg: Add Tdx.h Min Xu
@ 2021-12-13 12:56 ` Min Xu
  2021-12-15  6:33   ` Gerd Hoffmann
  2021-12-13 12:56 ` [PATCH V4 03/31] MdePkg: Add TdxLib to wrap Tdx operations Min Xu
                   ` (28 subsequent siblings)
  30 siblings, 1 reply; 68+ messages in thread
From: Min Xu @ 2021-12-13 12:56 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>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 MdePkg/Include/Library/BaseLib.h         |  62 ++++++++++
 MdePkg/Library/BaseLib/BaseLib.inf       |  11 ++
 MdePkg/Library/BaseLib/IntelTdxNull.c    |  83 +++++++++++++
 MdePkg/Library/BaseLib/X64/TdCall.nasm   |  85 +++++++++++++
 MdePkg/Library/BaseLib/X64/TdProbe.c     |  62 ++++++++++
 MdePkg/Library/BaseLib/X64/TdVmcall.nasm | 145 +++++++++++++++++++++++
 6 files changed, 448 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..bd762843198f 100644
--- a/MdePkg/Include/Library/BaseLib.h
+++ b/MdePkg/Include/Library/BaseLib.h
@@ -4759,6 +4759,68 @@ SpeculationBarrier (
   VOID
   );
 
+/**
+  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 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
+  );
+
+/**
+  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
+  );
+
+/**
+  Probe if TD is enabled.
+
+  @return TRUE    TD is enabled.
+  @return FALSE   TD is not enabled.
+**/
+BOOLEAN
+EFIAPI
+TdIsEnabled (
+  VOID
+  );
+
 #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..1185f13204df 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
@@ -333,6 +337,7 @@
   Ebc/SpeculationBarrier.c
   Unaligned.c
   Math64.c
+  IntelTdxNull.c
 
 [Sources.ARM]
   Arm/InternalSwitchStack.c
@@ -370,6 +375,8 @@
   Arm/MemoryFence.S             | GCC
   Arm/SpeculationBarrier.S      | GCC
 
+  IntelTdxNull.c
+
 [Sources.AARCH64]
   Arm/InternalSwitchStack.c
   Arm/Unaligned.c
@@ -393,6 +400,8 @@
   AArch64/CpuBreakpoint.asm         | MSFT
   AArch64/SpeculationBarrier.asm    | MSFT
 
+  IntelTdxNull.c
+
 [Sources.RISCV64]
   Math64.c
   Unaligned.c
@@ -409,6 +418,8 @@
   RiscV64/RiscVInterrupt.S          | GCC
   RiscV64/FlushCache.S              | GCC
 
+  IntelTdxNull.c
+
 [Packages]
   MdePkg/MdePkg.dec
 
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..a1cf02717bf2
--- /dev/null
+++ b/MdePkg/Library/BaseLib/X64/TdProbe.c
@@ -0,0 +1,62 @@
+/** @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;
+
+  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, &Ecx, NULL);
+    if ((Ecx & BIT31) == 0) {
+      break;
+    }
+
+    if (LargestEax < 0x21) {
+      break;
+    }
+
+    AsmCpuidEx (0x21, 0, &Eax, &Ebx, &Ecx, &Edx);
+    if (  (Ebx != SIGNATURE_32 ('I', 'n', 't', 'e'))
+       || (Edx != SIGNATURE_32 ('l', 'T', 'D', 'X'))
+       || (Ecx != SIGNATURE_32 (' ', ' ', ' ', ' ')))
+    {
+      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] 68+ messages in thread

* [PATCH V4 03/31] MdePkg: Add TdxLib to wrap Tdx operations
  2021-12-13 12:56 [PATCH V4 00/31] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
  2021-12-13 12:56 ` [PATCH V4 01/31] MdePkg: Add Tdx.h Min Xu
  2021-12-13 12:56 ` [PATCH V4 02/31] MdePkg: Introduce basic Tdx functions in BaseLib Min Xu
@ 2021-12-13 12:56 ` Min Xu
  2021-12-15  6:44   ` Gerd Hoffmann
  2021-12-13 12:56 ` [PATCH V4 04/31] UefiCpuPkg: Extend VmgExitLibNull to handle #VE exception Min Xu
                   ` (27 subsequent siblings)
  30 siblings, 1 reply; 68+ messages in thread
From: Min Xu @ 2021-12-13 12:56 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>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 MdePkg/Include/Library/TdxLib.h     |  97 +++++++++++++++
 MdePkg/Library/TdxLib/AcceptPages.c | 180 ++++++++++++++++++++++++++++
 MdePkg/Library/TdxLib/Rtmr.c        |  83 +++++++++++++
 MdePkg/Library/TdxLib/TdInfo.c      | 114 ++++++++++++++++++
 MdePkg/Library/TdxLib/TdxLib.inf    |  37 ++++++
 MdePkg/Library/TdxLib/TdxLibNull.c  | 107 +++++++++++++++++
 MdePkg/MdePkg.dec                   |   3 +
 MdePkg/MdePkg.dsc                   |   1 +
 8 files changed, 622 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..86539460c9f9
--- /dev/null
+++ b/MdePkg/Include/Library/TdxLib.h
@@ -0,0 +1,97 @@
+/** @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_
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Uefi/UefiBaseType.h>
+#include <Protocol/DebugSupport.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..651d47a8d8a1
--- /dev/null
+++ b/MdePkg/Library/TdxLib/AcceptPages.c
@@ -0,0 +1,180 @@
+/** @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 <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..bdc91b3ebe6a
--- /dev/null
+++ b/MdePkg/Library/TdxLib/Rtmr.c
@@ -0,0 +1,83 @@
+/** @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 <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..a40a15116f30
--- /dev/null
+++ b/MdePkg/Library/TdxLib/TdInfo.c
@@ -0,0 +1,114 @@
+/** @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 <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..83ab929b4a3b
--- /dev/null
+++ b/MdePkg/Library/TdxLib/TdxLibNull.c
@@ -0,0 +1,107 @@
+/** @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 <Library/DebugLib.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] 68+ messages in thread

* [PATCH V4 04/31] UefiCpuPkg: Extend VmgExitLibNull to handle #VE exception
  2021-12-13 12:56 [PATCH V4 00/31] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (2 preceding siblings ...)
  2021-12-13 12:56 ` [PATCH V4 03/31] MdePkg: Add TdxLib to wrap Tdx operations Min Xu
@ 2021-12-13 12:56 ` Min Xu
  2021-12-13 12:56 ` [PATCH V4 05/31] OvmfPkg: Extend VmgExitLib " Min Xu
                   ` (26 subsequent siblings)
  30 siblings, 0 replies; 68+ messages in thread
From: Min Xu @ 2021-12-13 12:56 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>
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] 68+ messages in thread

* [PATCH V4 05/31] OvmfPkg: Extend VmgExitLib to handle #VE exception
  2021-12-13 12:56 [PATCH V4 00/31] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (3 preceding siblings ...)
  2021-12-13 12:56 ` [PATCH V4 04/31] UefiCpuPkg: Extend VmgExitLibNull to handle #VE exception Min Xu
@ 2021-12-13 12:56 ` Min Xu
  2021-12-15  6:56   ` [edk2-devel] " Gerd Hoffmann
  2021-12-13 12:56 ` [PATCH V4 06/31] UefiCpuPkg/CpuExceptionHandler: Add base support for the " Min Xu
                   ` (25 subsequent siblings)
  30 siblings, 1 reply; 68+ messages in thread
From: Min Xu @ 2021-12-13 12:56 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.

PcdIgnoreVeHalt is created in OvmfPkg.dec to ignore the VE halt.

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>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/Library/VmgExitLib/SecVmgExitLib.inf  |   4 +-
 OvmfPkg/Library/VmgExitLib/VmTdExitHandler.h  |  32 +
 .../Library/VmgExitLib/VmTdExitVeHandler.c    | 562 ++++++++++++++++++
 OvmfPkg/Library/VmgExitLib/VmgExitLib.inf     |   3 +
 .../Library/VmgExitLib/X64/TdVmcallCpuid.nasm | 146 +++++
 OvmfPkg/OvmfPkg.dec                           |   3 +
 6 files changed, 749 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..ac4eb0757dfa 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,4 @@
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupSize
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidBase
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidSize
-
+  gUefiOvmfPkgTokenSpaceGuid.PcdIgnoreVeHalt
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..79cb39117891
--- /dev/null
+++ b/OvmfPkg/Library/VmgExitLib/VmTdExitVeHandler.c
@@ -0,0 +1,562 @@
+/** @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:
+      if (FixedPcdGetBool (PcdIgnoreVeHalt) == FALSE) {
+        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..54fd861e8100 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
@@ -41,3 +43,4 @@
 [Pcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidBase
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdIgnoreVeHalt
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
diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index 769bef0ffa12..3b641efa9ee2 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -369,6 +369,9 @@
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecValidatedStart|0|UINT32|0x62
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecValidatedEnd|0|UINT32|0x63
 
+  ## Ignore the VE halt in Tdx
+  gUefiOvmfPkgTokenSpaceGuid.PcdIgnoreVeHalt|FALSE|BOOLEAN|0x64
+
 [PcdsDynamic, PcdsDynamicEx]
   gUefiOvmfPkgTokenSpaceGuid.PcdEmuVariableEvent|0|UINT64|2
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashVariablesEnable|FALSE|BOOLEAN|0x10
-- 
2.29.2.windows.2


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

* [PATCH V4 06/31] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VE exception
  2021-12-13 12:56 [PATCH V4 00/31] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (4 preceding siblings ...)
  2021-12-13 12:56 ` [PATCH V4 05/31] OvmfPkg: Extend VmgExitLib " Min Xu
@ 2021-12-13 12:56 ` Min Xu
  2021-12-13 12:56 ` [PATCH V4 07/31] MdePkg: Add helper functions for Tdx guest in BaseIoLibIntrinsic Min Xu
                   ` (24 subsequent siblings)
  30 siblings, 0 replies; 68+ messages in thread
From: Min Xu @ 2021-12-13 12:56 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>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 .../PeiDxeSmmCpuException.c                    | 17 +++++++++++++++++
 .../SecPeiCpuException.c                       | 18 ++++++++++++++++++
 2 files changed, 35 insertions(+)

diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeSmmCpuException.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeSmmCpuException.c
index 762ea2460f91..4fa3f8202a33 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeSmmCpuException.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeSmmCpuException.c
@@ -45,6 +45,23 @@ CommonExceptionHandlerWorker (
     }
   }
 
+  if (ExceptionType == VE_EXCEPTION) {
+    EFI_STATUS  Status;
+    //
+    // #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;
+    }
+  }
+
   ExceptionHandlerContext  = (EXCEPTION_HANDLER_CONTEXT *)(UINTN)(SystemContext.SystemContextIa32);
   ReservedVectors          = ExceptionHandlerData->ReservedVectors;
   ExternalInterruptHandler = ExceptionHandlerData->ExternalInterruptHandler;
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c
index c614d5b0b6f1..148d89011721 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c
@@ -43,6 +43,24 @@ CommonExceptionHandler (
     }
   }
 
+  if (ExceptionType == VE_EXCEPTION) {
+    EFI_STATUS  Status;
+    //
+    // #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;
+    }
+  }
+
   //
   // Initialize the serial port before dumping.
   //
-- 
2.29.2.windows.2


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

* [PATCH V4 07/31] MdePkg: Add helper functions for Tdx guest in BaseIoLibIntrinsic
  2021-12-13 12:56 [PATCH V4 00/31] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (5 preceding siblings ...)
  2021-12-13 12:56 ` [PATCH V4 06/31] UefiCpuPkg/CpuExceptionHandler: Add base support for the " Min Xu
@ 2021-12-13 12:56 ` Min Xu
  2021-12-13 12:56 ` [PATCH V4 08/31] MdePkg: Support mmio " Min Xu
                   ` (23 subsequent siblings)
  30 siblings, 0 replies; 68+ messages in thread
From: Min Xu @ 2021-12-13 12:56 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>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 .../BaseIoLibIntrinsicSev.inf                 |   2 +
 .../BaseIoLibIntrinsic/IoLibInternalTdx.c     | 675 ++++++++++++++++++
 .../BaseIoLibIntrinsic/IoLibInternalTdxNull.c | 497 +++++++++++++
 MdePkg/Library/BaseIoLibIntrinsic/IoLibTdx.h  | 410 +++++++++++
 4 files changed, 1584 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..368eea49116a
--- /dev/null
+++ b/MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdx.c
@@ -0,0 +1,675 @@
+/** @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 <Include/IndustryStandard/Tdx.h>
+#include <Library/TdxLib.h>
+#include <Library/BaseLib.h>
+#include <Register/Intel/Cpuid.h>
+#include <Base.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] 68+ messages in thread

* [PATCH V4 08/31] MdePkg: Support mmio for Tdx guest in BaseIoLibIntrinsic
  2021-12-13 12:56 [PATCH V4 00/31] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (6 preceding siblings ...)
  2021-12-13 12:56 ` [PATCH V4 07/31] MdePkg: Add helper functions for Tdx guest in BaseIoLibIntrinsic Min Xu
@ 2021-12-13 12:56 ` Min Xu
  2021-12-15  7:02   ` Gerd Hoffmann
  2021-12-13 12:56 ` [PATCH V4 09/31] MdePkg: Support IoFifo " Min Xu
                   ` (22 subsequent siblings)
  30 siblings, 1 reply; 68+ messages in thread
From: Min Xu @ 2021-12-13 12:56 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>
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] 68+ messages in thread

* [PATCH V4 09/31] MdePkg: Support IoFifo for Tdx guest in BaseIoLibIntrinsic
  2021-12-13 12:56 [PATCH V4 00/31] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (7 preceding siblings ...)
  2021-12-13 12:56 ` [PATCH V4 08/31] MdePkg: Support mmio " Min Xu
@ 2021-12-13 12:56 ` Min Xu
  2021-12-15  7:18   ` Gerd Hoffmann
  2021-12-13 12:56 ` [PATCH V4 10/31] MdePkg: Support IoRead/IoWrite " Min Xu
                   ` (21 subsequent siblings)
  30 siblings, 1 reply; 68+ messages in thread
From: Min Xu @ 2021-12-13 12:56 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>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 .../BaseIoLibIntrinsicSev.inf                 |   2 +
 MdePkg/Library/BaseIoLibIntrinsic/IoLibFifo.c | 216 ++++++++++++++++++
 MdePkg/Library/BaseIoLibIntrinsic/IoLibSev.h  | 166 ++++++++++++++
 .../BaseIoLibIntrinsic/X64/IoFifoSev.nasm     |  34 +--
 4 files changed, 401 insertions(+), 17 deletions(-)
 create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/IoLibFifo.c
 create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/IoLibSev.h

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


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

* [PATCH V4 10/31] MdePkg: Support IoRead/IoWrite for Tdx guest in BaseIoLibIntrinsic
  2021-12-13 12:56 [PATCH V4 00/31] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (8 preceding siblings ...)
  2021-12-13 12:56 ` [PATCH V4 09/31] MdePkg: Support IoFifo " Min Xu
@ 2021-12-13 12:56 ` Min Xu
  2021-12-15  7:18   ` Gerd Hoffmann
  2021-12-13 12:56 ` [PATCH V4 11/31] UefiCpuPkg: Support TDX in BaseXApicX2ApicLib Min Xu
                   ` (20 subsequent siblings)
  30 siblings, 1 reply; 68+ messages in thread
From: Min Xu @ 2021-12-13 12:56 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>
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] 68+ messages in thread

* [PATCH V4 11/31] UefiCpuPkg: Support TDX in BaseXApicX2ApicLib
  2021-12-13 12:56 [PATCH V4 00/31] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (9 preceding siblings ...)
  2021-12-13 12:56 ` [PATCH V4 10/31] MdePkg: Support IoRead/IoWrite " Min Xu
@ 2021-12-13 12:56 ` Min Xu
  2021-12-13 12:56 ` [PATCH V4 12/31] MdePkg: Add macro to check SEV / TDX guest Min Xu
                   ` (19 subsequent siblings)
  30 siblings, 0 replies; 68+ messages in thread
From: Min Xu @ 2021-12-13 12:56 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>
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] 68+ messages in thread

* [PATCH V4 12/31] MdePkg: Add macro to check SEV / TDX guest
  2021-12-13 12:56 [PATCH V4 00/31] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (10 preceding siblings ...)
  2021-12-13 12:56 ` [PATCH V4 11/31] UefiCpuPkg: Support TDX in BaseXApicX2ApicLib Min Xu
@ 2021-12-13 12:56 ` Min Xu
  2021-12-13 12:56 ` [PATCH V4 13/31] UefiCpuPkg: Enable Tdx support in MpInitLib Min Xu
                   ` (18 subsequent siblings)
  30 siblings, 0 replies; 68+ messages in thread
From: Min Xu @ 2021-12-13 12:56 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

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>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel>
---
 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] 68+ messages in thread

* [PATCH V4 13/31] UefiCpuPkg: Enable Tdx support in MpInitLib
  2021-12-13 12:56 [PATCH V4 00/31] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (11 preceding siblings ...)
  2021-12-13 12:56 ` [PATCH V4 12/31] MdePkg: Add macro to check SEV / TDX guest Min Xu
@ 2021-12-13 12:56 ` Min Xu
  2021-12-15  7:33   ` Gerd Hoffmann
  2021-12-13 12:56 ` [PATCH V4 14/31] OvmfPkg: Add IntelTdx.h in OvmfPkg/Include/IndustryStandard Min Xu
                   ` (17 subsequent siblings)
  30 siblings, 1 reply; 68+ messages in thread
From: Min Xu @ 2021-12-13 12:56 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. The processor info is retrieved by
TDCALL, ApWorker is not supported, BSP is always the working processor,
while the APs are just in a wait-for-precedure state.

Cc: Brijesh Singh <brijesh.singh@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>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf |   3 +
 UefiCpuPkg/Library/MpInitLib/DxeMpLib.c       |  15 +-
 UefiCpuPkg/Library/MpInitLib/MpIntelTdx.h     |  71 ++++++++++
 UefiCpuPkg/Library/MpInitLib/MpLib.c          |  27 ++++
 UefiCpuPkg/Library/MpInitLib/MpLibTdx.c       | 128 ++++++++++++++++++
 UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c   |  73 ++++++++++
 UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf |   3 +
 7 files changed, 319 insertions(+), 1 deletion(-)
 create mode 100644 UefiCpuPkg/Library/MpInitLib/MpIntelTdx.h
 create mode 100644 UefiCpuPkg/Library/MpInitLib/MpLibTdx.c
 create mode 100644 UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c

diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
index e1cd0b350008..159b4d16ed0e 100644
--- a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
@@ -24,10 +24,12 @@
 [Sources.IA32]
   Ia32/AmdSev.c
   Ia32/MpFuncs.nasm
+  MpLibTdxNull.c
 
 [Sources.X64]
   X64/AmdSev.c
   X64/MpFuncs.nasm
+  MpLibTdx.c
 
 [Sources.common]
   AmdSev.c
@@ -36,6 +38,7 @@
   MpLib.c
   MpLib.h
   Microcode.c
+  MpIntelTdx.h
 
 [Packages]
   MdePkg/MdePkg.dec
diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
index 60d14a5a0e10..237cad8c5fd6 100644
--- a/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
@@ -7,6 +7,7 @@
 **/
 
 #include "MpLib.h"
+#include "MpIntelTdx.h"
 
 #include <Library/UefiLib.h>
 #include <Library/UefiBootServicesTableLib.h>
@@ -15,8 +16,8 @@
 #include <Library/VmgExitLib.h>
 #include <Register/Amd/Fam17Msr.h>
 #include <Register/Amd/Ghcb.h>
-
 #include <Protocol/Timer.h>
+#include <ConfidentialComputingGuestAttr.h>
 
 #define  AP_SAFE_STACK_SIZE  128
 
@@ -824,6 +825,10 @@ MpInitLibStartupThisAP (
 {
   EFI_STATUS  Status;
 
+  if (CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr))) {
+    return EFI_UNSUPPORTED;
+  }
+
   //
   // temporarily stop checkAllApsStatus for avoid resource dead-lock.
   //
@@ -880,6 +885,10 @@ MpInitLibSwitchBSP (
   EFI_TIMER_ARCH_PROTOCOL  *Timer;
   UINT64                   TimerPeriod;
 
+  if (CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr))) {
+    return EFI_UNSUPPORTED;
+  }
+
   TimerPeriod = 0;
   //
   // Locate Timer Arch Protocol
@@ -953,6 +962,10 @@ MpInitLibEnableDisableAP (
   EFI_STATUS  Status;
   BOOLEAN     TempStopCheckState;
 
+  if (CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr))) {
+    return EFI_UNSUPPORTED;
+  }
+
   TempStopCheckState = FALSE;
   //
   // temporarily stop checkAllAPsStatus for initialize parameters.
diff --git a/UefiCpuPkg/Library/MpInitLib/MpIntelTdx.h b/UefiCpuPkg/Library/MpInitLib/MpIntelTdx.h
new file mode 100644
index 000000000000..b2136f466ce6
--- /dev/null
+++ b/UefiCpuPkg/Library/MpInitLib/MpIntelTdx.h
@@ -0,0 +1,71 @@
+/** @file
+  Intel Tdx header file.
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef MP_INTEL_TDX_H_
+#define MP_INTEL_TDX_H_
+
+#include <PiPei.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Uefi/UefiBaseType.h>
+#include <Protocol/MpService.h>
+
+/**
+  Gets detailed MP-related information on the requested processor at the
+  instant this call is made. This service may only be called from the BSP.
+
+  @param[in]  ProcessorNumber       The handle number of processor.
+  @param[out] ProcessorInfoBuffer   A pointer to the buffer where information for
+                                    the requested processor is deposited.
+  @param[out]  HealthData            Return processor health data.
+
+  @retval EFI_SUCCESS             Processor information was returned.
+  @retval EFI_DEVICE_ERROR        The calling processor is an AP.
+  @retval EFI_INVALID_PARAMETER   ProcessorInfoBuffer is NULL.
+  @retval EFI_NOT_FOUND           The processor with the handle specified by
+                                  ProcessorNumber does not exist in the platform.
+  @retval EFI_NOT_READY           MP Initialize Library is not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+TdxMpInitLibGetProcessorInfo (
+  IN  UINTN                      ProcessorNumber,
+  OUT EFI_PROCESSOR_INFORMATION  *ProcessorInfoBuffer,
+  OUT EFI_HEALTH_FLAGS           *HealthData  OPTIONAL
+  );
+
+/**
+  Retrieves the number of logical processor in the platform and the number of
+  those logical processors that are enabled on this boot. This service may only
+  be called from the BSP.
+
+  @param[out] NumberOfProcessors          Pointer to the total number of logical
+                                          processors in the system, including the BSP
+                                          and disabled APs.
+  @param[out] NumberOfEnabledProcessors   Pointer to the number of enabled logical
+                                          processors that exist in system, including
+                                          the BSP.
+
+  @retval EFI_SUCCESS             The number of logical processors and enabled
+                                  logical processors was retrieved.
+  @retval EFI_DEVICE_ERROR        The calling processor is an AP.
+  @retval EFI_INVALID_PARAMETER   NumberOfProcessors is NULL and NumberOfEnabledProcessors
+                                  is NULL.
+  @retval EFI_NOT_READY           MP Initialize Library is not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+TdxMpInitLibGetNumberOfProcessors (
+  OUT UINTN *NumberOfProcessors, OPTIONAL
+  OUT UINTN                     *NumberOfEnabledProcessors OPTIONAL
+  );
+
+#endif
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index 4a73787ee43a..de2ed8e6c294 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -9,9 +9,11 @@
 **/
 
 #include "MpLib.h"
+#include "MpIntelTdx.h"
 #include <Library/VmgExitLib.h>
 #include <Register/Amd/Fam17Msr.h>
 #include <Register/Amd/Ghcb.h>
+#include <ConfidentialComputingGuestAttr.h>
 
 EFI_GUID  mCpuInitMpLibHobGuid = CPU_INIT_MP_LIB_HOB_GUID;
 
@@ -1803,6 +1805,10 @@ MpInitLibInitialize (
   UINTN                    BackupBufferAddr;
   UINTN                    ApIdtBase;
 
+  if (CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr))) {
+    return EFI_SUCCESS;
+  }
+
   OldCpuMpData = GetCpuMpDataFromGuidedHob ();
   if (OldCpuMpData == NULL) {
     MaxLogicalProcessorNumber = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
@@ -2073,6 +2079,10 @@ MpInitLibGetProcessorInfo (
   CPU_INFO_IN_HOB  *CpuInfoInHob;
   UINTN            OriginalProcessorNumber;
 
+  if (CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr))) {
+    return TdxMpInitLibGetProcessorInfo (ProcessorNumber, ProcessorInfoBuffer, HealthData);
+  }
+
   CpuMpData    = GetCpuMpData ();
   CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
 
@@ -2307,6 +2317,10 @@ EnableDisableApWorker (
   CPU_MP_DATA  *CpuMpData;
   UINTN        CallerNumber;
 
+  if (CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr))) {
+    return EFI_UNSUPPORTED;
+  }
+
   CpuMpData = GetCpuMpData ();
 
   //
@@ -2367,6 +2381,11 @@ MpInitLibWhoAmI (
     return EFI_INVALID_PARAMETER;
   }
 
+  if (CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr))) {
+    *ProcessorNumber = 0;
+    return EFI_SUCCESS;
+  }
+
   CpuMpData = GetCpuMpData ();
 
   return GetProcessorNumber (CpuMpData, ProcessorNumber);
@@ -2405,6 +2424,10 @@ MpInitLibGetNumberOfProcessors (
   UINTN        EnabledProcessorNumber;
   UINTN        Index;
 
+  if (CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr))) {
+    return TdxMpInitLibGetNumberOfProcessors (NumberOfProcessors, NumberOfEnabledProcessors);
+  }
+
   CpuMpData = GetCpuMpData ();
 
   if ((NumberOfProcessors == NULL) && (NumberOfEnabledProcessors == NULL)) {
@@ -2490,6 +2513,10 @@ StartupAllCPUsWorker (
   BOOLEAN      HasEnabledAp;
   CPU_STATE    ApState;
 
+  if (CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr))) {
+    return EFI_SUCCESS;
+  }
+
   CpuMpData = GetCpuMpData ();
 
   if (FailedCpuList != NULL) {
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLibTdx.c b/UefiCpuPkg/Library/MpInitLib/MpLibTdx.c
new file mode 100644
index 000000000000..d31d043b20b7
--- /dev/null
+++ b/UefiCpuPkg/Library/MpInitLib/MpLibTdx.c
@@ -0,0 +1,128 @@
+/** @file
+  CPU MP Initialize Library common functions.
+
+  Copyright (c) 2016 - 2020, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2020, AMD Inc. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MpLib.h"
+#include "MpIntelTdx.h"
+#include <Library/BaseLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DebugLib.h>
+#include <IndustryStandard/Tdx.h>
+
+/**
+  Gets detailed MP-related information on the requested processor at the
+  instant this call is made. This service may only be called from the BSP.
+
+  @param[in]  ProcessorNumber       The handle number of processor.
+  @param[out] ProcessorInfoBuffer   A pointer to the buffer where information for
+                                    the requested processor is deposited.
+  @param[out]  HealthData            Return processor health data.
+
+  @retval EFI_SUCCESS             Processor information was returned.
+  @retval EFI_DEVICE_ERROR        The calling processor is an AP.
+  @retval EFI_INVALID_PARAMETER   ProcessorInfoBuffer is NULL.
+  @retval EFI_NOT_FOUND           The processor with the handle specified by
+                                  ProcessorNumber does not exist in the platform.
+  @retval EFI_NOT_READY           MP Initialize Library is not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+TdxMpInitLibGetProcessorInfo (
+  IN  UINTN                      ProcessorNumber,
+  OUT EFI_PROCESSOR_INFORMATION  *ProcessorInfoBuffer,
+  OUT EFI_HEALTH_FLAGS           *HealthData  OPTIONAL
+  )
+{
+  EFI_STATUS      Status;
+  TD_RETURN_DATA  TdReturnData;
+
+  if (ProcessorInfoBuffer == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Status = TdCall (TDCALL_TDINFO, 0, 0, 0, &TdReturnData);
+  ASSERT (Status == EFI_SUCCESS);
+
+  if (ProcessorNumber >= TdReturnData.TdInfo.NumVcpus) {
+    return EFI_NOT_FOUND;
+  }
+
+  ProcessorInfoBuffer->ProcessorId = ProcessorNumber;
+  ProcessorInfoBuffer->StatusFlag  = 0;
+  if (ProcessorNumber == 0) {
+    ProcessorInfoBuffer->StatusFlag |= PROCESSOR_AS_BSP_BIT;
+  }
+
+  ProcessorInfoBuffer->StatusFlag |= PROCESSOR_ENABLED_BIT;
+
+  //
+  // Get processor location information
+  //
+  GetProcessorLocationByApicId (
+    (UINT32)ProcessorNumber,
+    &ProcessorInfoBuffer->Location.Package,
+    &ProcessorInfoBuffer->Location.Core,
+    &ProcessorInfoBuffer->Location.Thread
+    );
+
+  if (HealthData != NULL) {
+    HealthData->Uint32 = 0;
+  }
+
+  return Status;
+}
+
+/**
+  Retrieves the number of logical processor in the platform and the number of
+  those logical processors that are enabled on this boot. This service may only
+  be called from the BSP.
+
+  @param[out] NumberOfProcessors          Pointer to the total number of logical
+                                          processors in the system, including the BSP
+                                          and disabled APs.
+  @param[out] NumberOfEnabledProcessors   Pointer to the number of enabled logical
+                                          processors that exist in system, including
+                                          the BSP.
+
+  @retval EFI_SUCCESS             The number of logical processors and enabled
+                                  logical processors was retrieved.
+  @retval EFI_DEVICE_ERROR        The calling processor is an AP.
+  @retval EFI_INVALID_PARAMETER   NumberOfProcessors is NULL and NumberOfEnabledProcessors
+                                  is NULL.
+  @retval EFI_NOT_READY           MP Initialize Library is not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+TdxMpInitLibGetNumberOfProcessors (
+  OUT UINTN *NumberOfProcessors, OPTIONAL
+  OUT UINTN                     *NumberOfEnabledProcessors OPTIONAL
+  )
+{
+  EFI_STATUS      Status;
+  TD_RETURN_DATA  TdReturnData;
+
+  if ((NumberOfProcessors == NULL) && (NumberOfEnabledProcessors == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Status = TdCall (TDCALL_TDINFO, 0, 0, 0, &TdReturnData);
+  ASSERT (Status == EFI_SUCCESS);
+
+  if (NumberOfProcessors != NULL) {
+    *NumberOfProcessors = TdReturnData.TdInfo.NumVcpus;
+  }
+
+  if (NumberOfEnabledProcessors != NULL) {
+    *NumberOfEnabledProcessors = TdReturnData.TdInfo.MaxVcpus;
+  }
+
+  return Status;
+}
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c b/UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c
new file mode 100644
index 000000000000..2849e13f2aaa
--- /dev/null
+++ b/UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c
@@ -0,0 +1,73 @@
+/** @file
+  CPU MP Initialize Library common functions.
+
+  Copyright (c) 2016 - 2020, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2020, AMD Inc. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MpLib.h"
+#include "MpIntelTdx.h"
+#include <Library/DebugLib.h>
+
+/**
+  Gets detailed MP-related information on the requested processor at the
+  instant this call is made. This service may only be called from the BSP.
+
+  @param[in]  ProcessorNumber       The handle number of processor.
+  @param[out] ProcessorInfoBuffer   A pointer to the buffer where information for
+                                    the requested processor is deposited.
+  @param[out]  HealthData            Return processor health data.
+
+  @retval EFI_SUCCESS             Processor information was returned.
+  @retval EFI_DEVICE_ERROR        The calling processor is an AP.
+  @retval EFI_INVALID_PARAMETER   ProcessorInfoBuffer is NULL.
+  @retval EFI_NOT_FOUND           The processor with the handle specified by
+                                  ProcessorNumber does not exist in the platform.
+  @retval EFI_NOT_READY           MP Initialize Library is not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+TdxMpInitLibGetProcessorInfo (
+  IN  UINTN                      ProcessorNumber,
+  OUT EFI_PROCESSOR_INFORMATION  *ProcessorInfoBuffer,
+  OUT EFI_HEALTH_FLAGS           *HealthData  OPTIONAL
+  )
+{
+  ASSERT (FALSE);
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  Retrieves the number of logical processor in the platform and the number of
+  those logical processors that are enabled on this boot. This service may only
+  be called from the BSP.
+
+  @param[out] NumberOfProcessors          Pointer to the total number of logical
+                                          processors in the system, including the BSP
+                                          and disabled APs.
+  @param[out] NumberOfEnabledProcessors   Pointer to the number of enabled logical
+                                          processors that exist in system, including
+                                          the BSP.
+
+  @retval EFI_SUCCESS             The number of logical processors and enabled
+                                  logical processors was retrieved.
+  @retval EFI_DEVICE_ERROR        The calling processor is an AP.
+  @retval EFI_INVALID_PARAMETER   NumberOfProcessors is NULL and NumberOfEnabledProcessors
+                                  is NULL.
+  @retval EFI_NOT_READY           MP Initialize Library is not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+TdxMpInitLibGetNumberOfProcessors (
+  OUT UINTN *NumberOfProcessors, OPTIONAL
+  OUT UINTN                     *NumberOfEnabledProcessors OPTIONAL
+  )
+{
+  ASSERT (FALSE);
+  return EFI_UNSUPPORTED;
+}
diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
index 5facf4db9499..894be0f8daab 100644
--- a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
@@ -24,10 +24,12 @@
 [Sources.IA32]
   Ia32/AmdSev.c
   Ia32/MpFuncs.nasm
+  MpLibTdxNull.c
 
 [Sources.X64]
   X64/AmdSev.c
   X64/MpFuncs.nasm
+  MpLibTdx.c
 
 [Sources.common]
   AmdSev.c
@@ -36,6 +38,7 @@
   MpLib.c
   MpLib.h
   Microcode.c
+  MpIntelTdx.h
 
 [Packages]
   MdePkg/MdePkg.dec
-- 
2.29.2.windows.2


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

* [PATCH V4 14/31] OvmfPkg: Add IntelTdx.h in OvmfPkg/Include/IndustryStandard
  2021-12-13 12:56 [PATCH V4 00/31] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (12 preceding siblings ...)
  2021-12-13 12:56 ` [PATCH V4 13/31] UefiCpuPkg: Enable Tdx support in MpInitLib Min Xu
@ 2021-12-13 12:56 ` Min Xu
  2021-12-15  7:37   ` Gerd Hoffmann
  2021-12-13 12:56 ` [PATCH V4 15/31] OvmfPkg: Add TdxMailboxLib Min Xu
                   ` (16 subsequent siblings)
  30 siblings, 1 reply; 68+ messages in thread
From: Min Xu @ 2021-12-13 12:56 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 defitions used by TDX in OvmfPkg:
 - Mailbox related defitions,such as the data structure, command code,
   AP relocation defitions.
 - EFI_HOB_PLATFORM_INFO describes the TDX platform information

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>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/Include/IndustryStandard/IntelTdx.h | 76 +++++++++++++++++++++
 1 file changed, 76 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..b021b11601c5
--- /dev/null
+++ b/OvmfPkg/Include/IndustryStandard/IntelTdx.h
@@ -0,0 +1,76 @@
+/** @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;
+
+typedef struct {
+  ///
+  EFI_HOB_GUID_TYPE    GuidHeader;
+  UINT64               RelocatedMailBox;
+  UINT16               HostBridgePciDevId;
+  BOOLEAN              SetNxForStack;
+  UINT8                SystemStates[6];
+} EFI_HOB_PLATFORM_INFO;
+
+#pragma pack()
+
+#endif
-- 
2.29.2.windows.2


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

* [PATCH V4 15/31] OvmfPkg: Add TdxMailboxLib
  2021-12-13 12:56 [PATCH V4 00/31] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (13 preceding siblings ...)
  2021-12-13 12:56 ` [PATCH V4 14/31] OvmfPkg: Add IntelTdx.h in OvmfPkg/Include/IndustryStandard Min Xu
@ 2021-12-13 12:56 ` Min Xu
  2021-12-15  7:47   ` Gerd Hoffmann
  2021-12-13 12:56 ` [PATCH V4 16/31] MdePkg: Add EFI_RESOURCE_ATTRIBUTE_ENCRYPTED in PiHob.h Min Xu
                   ` (15 subsequent siblings)
  30 siblings, 1 reply; 68+ messages in thread
From: Min Xu @ 2021-12-13 12:56 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>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/Include/Library/TdxMailboxLib.h       |  76 ++++++++++
 OvmfPkg/Library/TdxMailboxLib/TdxMailbox.c    | 140 ++++++++++++++++++
 .../Library/TdxMailboxLib/TdxMailboxLib.inf   |  52 +++++++
 .../Library/TdxMailboxLib/TdxMailboxNull.c    |  85 +++++++++++
 OvmfPkg/OvmfPkg.dec                           |   4 +
 5 files changed, 357 insertions(+)
 create mode 100644 OvmfPkg/Include/Library/TdxMailboxLib.h
 create mode 100644 OvmfPkg/Library/TdxMailboxLib/TdxMailbox.c
 create mode 100644 OvmfPkg/Library/TdxMailboxLib/TdxMailboxLib.inf
 create mode 100644 OvmfPkg/Library/TdxMailboxLib/TdxMailboxNull.c

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

* [PATCH V4 16/31] MdePkg: Add EFI_RESOURCE_ATTRIBUTE_ENCRYPTED in PiHob.h
  2021-12-13 12:56 [PATCH V4 00/31] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (14 preceding siblings ...)
  2021-12-13 12:56 ` [PATCH V4 15/31] OvmfPkg: Add TdxMailboxLib Min Xu
@ 2021-12-13 12:56 ` Min Xu
  2021-12-13 12:56 ` [PATCH V4 17/31] OvmfPkg: Update Sec to support Tdx Min Xu
                   ` (14 subsequent siblings)
  30 siblings, 0 replies; 68+ messages in thread
From: Min Xu @ 2021-12-13 12:56 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky

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

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

Cc: Ard Biesheuvel <ardb+tianocore@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>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 MdePkg/Include/Pi/PiHob.h | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/MdePkg/Include/Pi/PiHob.h b/MdePkg/Include/Pi/PiHob.h
index e9f0ab4309d1..5bb7fc843112 100644
--- a/MdePkg/Include/Pi/PiHob.h
+++ b/MdePkg/Include/Pi/PiHob.h
@@ -296,6 +296,14 @@ typedef UINT32 EFI_RESOURCE_ATTRIBUTE_TYPE;
 //
 #define EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE  0x02000000
 
+//
+// Physical memory encrypted attribute. This
+// memory uses platform encrpytion capabilities for
+// protection. If this bit is clear, the memory does
+// not use platform encryption protection
+//
+#define EFI_RESOURCE_ATTRIBUTE_ENCRYPTED  0x04000000
+
 ///
 /// Describes the resource properties of all fixed,
 /// nonrelocatable resource ranges found on the processor
-- 
2.29.2.windows.2


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

* [PATCH V4 17/31] OvmfPkg: Update Sec to support Tdx
  2021-12-13 12:56 [PATCH V4 00/31] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (15 preceding siblings ...)
  2021-12-13 12:56 ` [PATCH V4 16/31] MdePkg: Add EFI_RESOURCE_ATTRIBUTE_ENCRYPTED in PiHob.h Min Xu
@ 2021-12-13 12:56 ` Min Xu
  2021-12-15  8:18   ` Gerd Hoffmann
  2021-12-13 12:56 ` [PATCH V4 18/31] OvmfPkg: Check Tdx in QemuFwCfgPei to avoid DMA operation Min Xu
                   ` (13 subsequent siblings)
  30 siblings, 1 reply; 68+ messages in thread
From: Min Xu @ 2021-12-13 12:56 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.

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

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

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 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>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/Include/TdxCommondefs.inc |  51 +++
 OvmfPkg/OvmfPkg.dec               |   3 +
 OvmfPkg/OvmfPkgIa32X64.dsc        |   2 +
 OvmfPkg/OvmfPkgX64.dsc            |   6 +
 OvmfPkg/Sec/IntelTdx.c            | 557 ++++++++++++++++++++++++++++++
 OvmfPkg/Sec/IntelTdx.h            |  46 +++
 OvmfPkg/Sec/SecMain.c             |  46 ++-
 OvmfPkg/Sec/SecMain.inf           |   7 +
 OvmfPkg/Sec/X64/SecEntry.nasm     |  82 +++++
 9 files changed, 794 insertions(+), 6 deletions(-)
 create mode 100644 OvmfPkg/Include/TdxCommondefs.inc
 create mode 100644 OvmfPkg/Sec/IntelTdx.c
 create mode 100644 OvmfPkg/Sec/IntelTdx.h

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/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index 7f685fd64efc..7a4a58c7a2ce 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -376,6 +376,9 @@
   ## Ignore the VE halt in Tdx
   gUefiOvmfPkgTokenSpaceGuid.PcdIgnoreVeHalt|FALSE|BOOLEAN|0x64
 
+  ## The Tdx accept page size. 0x1000(4k),0x200000(2M)
+  gUefiOvmfPkgTokenSpaceGuid.PcdTdxAcceptPageSize|0x1000|UINT32|0x66
+
 [PcdsDynamic, PcdsDynamicEx]
   gUefiOvmfPkgTokenSpaceGuid.PcdEmuVariableEvent|0|UINT64|2
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashVariablesEnable|FALSE|BOOLEAN|0x10
diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index 9b72575da100..dcec6acb28d7 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -247,6 +247,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 190cb7f09974..fb77a39a0ae5 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -247,6 +247,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
@@ -572,6 +574,10 @@
   gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesCode|0x100
   gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesData|0x100
 
+  #
+  # TDX need 1G PageTable support
+  gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable|TRUE
+
   #
   # Network Pcds
   #
diff --git a/OvmfPkg/Sec/IntelTdx.c b/OvmfPkg/Sec/IntelTdx.c
new file mode 100644
index 000000000000..d1d952e8d433
--- /dev/null
+++ b/OvmfPkg/Sec/IntelTdx.c
@@ -0,0 +1,557 @@
+/** @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 <PiPei.h>
+#include <Uefi/UefiSpec.h>
+#include <Uefi/UefiBaseType.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <IndustryStandard/UefiTcgPlatform.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/SynchronizationLib.h>
+#include <Library/TdxLib.h>
+#include <IndustryStandard/Tdx.h>
+#include <IndustryStandard/IntelTdx.h>
+#include <WorkArea.h>
+#include "IntelTdx.h"
+
+#define ALIGNED_2MB_MASK  0x1fffff
+
+/**
+  Check TDX is enabled.
+
+  @retval    TRUE   TDX is enabled
+  @retval    FALSE  TDX is not enabled
+**/
+BOOLEAN
+SecTdxIsEnabled (
+  VOID
+  )
+{
+  CONFIDENTIAL_COMPUTING_WORK_AREA_HEADER  *CcWorkAreaHeader;
+
+  CcWorkAreaHeader = (CONFIDENTIAL_COMPUTING_WORK_AREA_HEADER *)FixedPcdGet32 (PcdOvmfWorkAreaBase);
+  return (CcWorkAreaHeader != NULL && CcWorkAreaHeader->GuestType == GUEST_TYPE_INTEL_TDX);
+}
+
+/**
+  This function will be called to accept pages. Only BSP accepts pages.
+
+  TDCALL(ACCEPT_PAGE) supports the accept page size of 4k and 2M. To
+  simplify the implementation, the Memory to be accpeted is splitted
+  into 3 parts:
+  -----------------  <-- StartAddress1 (not 2M aligned)
+  |  part 1       |      Length1 < 2M
+  |---------------|  <-- StartAddress2 (2M aligned)
+  |               |      Length2 = Integer multiples of 2M
+  |  part 2       |
+  |               |
+  |---------------|  <-- StartAddress3
+  |  part 3       |      Length3 < 2M
+  |---------------|
+
+  @param[in] PhysicalAddress   Start physical adress
+  @param[in] PhysicalEnd       End physical address
+
+  @retval    EFI_SUCCESS       Accept memory successfully
+  @retval    Others            Other errors as indicated
+**/
+EFI_STATUS
+EFIAPI
+BspAcceptMemoryResourceRange (
+  IN EFI_PHYSICAL_ADDRESS  PhysicalAddress,
+  IN EFI_PHYSICAL_ADDRESS  PhysicalEnd
+  )
+{
+  EFI_STATUS  Status;
+  UINT32      AcceptPageSize;
+  UINT64      StartAddress1;
+  UINT64      StartAddress2;
+  UINT64      StartAddress3;
+  UINT64      TotalLength;
+  UINT64      Length1;
+  UINT64      Length2;
+  UINT64      Length3;
+  UINT64      Pages;
+
+  AcceptPageSize = FixedPcdGet32 (PcdTdxAcceptPageSize);
+  TotalLength    = PhysicalEnd - PhysicalAddress;
+  StartAddress1  = 0;
+  StartAddress2  = 0;
+  StartAddress3  = 0;
+  Length1        = 0;
+  Length2        = 0;
+  Length3        = 0;
+
+  if (TotalLength == 0) {
+    return EFI_SUCCESS;
+  }
+
+  if ((AcceptPageSize == SIZE_4KB) || (TotalLength <= SIZE_2MB)) {
+    //
+    // if total length is less than 2M, then we accept pages in 4k
+    //
+    StartAddress1  = 0;
+    Length1        = 0;
+    StartAddress2  = PhysicalAddress;
+    Length2        = PhysicalEnd - PhysicalAddress;
+    StartAddress3  = 0;
+    Length3        = 0;
+    AcceptPageSize = SIZE_4KB;
+  } else if (AcceptPageSize == SIZE_2MB) {
+    //
+    // Total length is bigger than 2M and Page Accept size 2M is supported.
+    //
+    if ((PhysicalAddress & ALIGNED_2MB_MASK) == 0) {
+      //
+      // Start address is 2M aligned
+      //
+      StartAddress1 = 0;
+      Length1       = 0;
+      StartAddress2 = PhysicalAddress;
+      Length2       = TotalLength & ~(UINT64)ALIGNED_2MB_MASK;
+
+      if (TotalLength > Length2) {
+        //
+        // There is remaining part 3)
+        //
+        StartAddress3 = StartAddress2 + Length2;
+        Length3       = TotalLength - Length2;
+        ASSERT (Length3 < SIZE_2MB);
+      }
+    } else {
+      //
+      // Start address is not 2M aligned and total length is bigger than 2M.
+      //
+      StartAddress1 = PhysicalAddress;
+      ASSERT (TotalLength > SIZE_2MB);
+      Length1 = SIZE_2MB - (PhysicalAddress & ALIGNED_2MB_MASK);
+      if (TotalLength - Length1 < SIZE_2MB) {
+        //
+        // The Part 2) length is less than 2MB, so let's accept all the
+        // memory in 4K
+        //
+        Length1 = TotalLength;
+      } else {
+        StartAddress2 = PhysicalAddress + Length1;
+        Length2       = (TotalLength - Length1) & ~(UINT64)ALIGNED_2MB_MASK;
+        Length3       = TotalLength - Length1 - Length2;
+        StartAddress3 = Length3 > 0 ? StartAddress2 + Length2 : 0;
+        ASSERT (Length3 < SIZE_2MB);
+      }
+    }
+  }
+
+  DEBUG ((DEBUG_INFO, "TdAccept: 0x%llx - 0x%llx\n", PhysicalAddress, 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;
+}
+
+/**
+  Dump out the hob list
+
+  @param[in]  HobStart    Start address of the hob list
+**/
+VOID
+EFIAPI
+DEBUG_HOBLIST (
+  IN CONST VOID  *HobStart
+  )
+{
+  EFI_PEI_HOB_POINTERS  Hob;
+
+  Hob.Raw = (UINT8 *)HobStart;
+  //
+  // Parse the HOB list until end of list or matching type is found.
+  //
+  while (!END_OF_HOB_LIST (Hob)) {
+    DEBUG ((DEBUG_INFO, "HOB(%p) : %x %x\n", Hob, Hob.Header->HobType, Hob.Header->HobLength));
+    switch (Hob.Header->HobType) {
+      case EFI_HOB_TYPE_RESOURCE_DESCRIPTOR:
+        DEBUG ((
+          DEBUG_INFO,
+          "\t: %x %x %llx %llx\n",
+          Hob.ResourceDescriptor->ResourceType,
+          Hob.ResourceDescriptor->ResourceAttribute,
+          Hob.ResourceDescriptor->PhysicalStart,
+          Hob.ResourceDescriptor->ResourceLength
+          ));
+
+        break;
+      case EFI_HOB_TYPE_MEMORY_ALLOCATION:
+        DEBUG ((
+          DEBUG_INFO,
+          "\t: %llx %llx %x\n",
+          Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress,
+          Hob.MemoryAllocation->AllocDescriptor.MemoryLength,
+          Hob.MemoryAllocation->AllocDescriptor.MemoryType
+          ));
+        break;
+      default:
+        break;
+    }
+
+    Hob.Raw = GET_NEXT_HOB (Hob);
+  }
+}
+
+/**
+  Check the value whether in the valid list.
+
+  @param[in] Value             A value
+  @param[in] ValidList         A pointer to valid list
+  @param[in] ValidListLength   Length of valid list
+
+  @retval  TRUE   The value is in valid list.
+  @retval  FALSE  The value is not in valid list.
+
+**/
+BOOLEAN
+EFIAPI
+IsInValidList (
+  IN UINT32  Value,
+  IN UINT32  *ValidList,
+  IN UINT32  ValidListLength
+  )
+{
+  UINT32  index;
+
+  if (ValidList == NULL) {
+    return FALSE;
+  }
+
+  for (index = 0; index < ValidListLength; index++) {
+    if (ValidList[index] == Value) {
+      return TRUE;
+    }
+  }
+
+  return FALSE;
+}
+
+/**
+  Check the integrity of VMM Hob List.
+
+  @param[in] VmmHobList   A pointer to Hob List
+
+  @retval  TRUE     The Hob List is valid.
+  @retval  FALSE    The Hob List is invalid.
+
+**/
+BOOLEAN
+EFIAPI
+ValidateHobList (
+  IN CONST VOID  *VmmHobList
+  )
+{
+  EFI_PEI_HOB_POINTERS  Hob;
+  UINT32                EFI_BOOT_MODE_LIST[12] = {
+    BOOT_WITH_FULL_CONFIGURATION,
+    BOOT_WITH_MINIMAL_CONFIGURATION,
+    BOOT_ASSUMING_NO_CONFIGURATION_CHANGES,
+    BOOT_WITH_FULL_CONFIGURATION_PLUS_DIAGNOSTICS,
+    BOOT_WITH_DEFAULT_SETTINGS,
+    BOOT_ON_S4_RESUME,
+    BOOT_ON_S5_RESUME,
+    BOOT_WITH_MFG_MODE_SETTINGS,
+    BOOT_ON_S2_RESUME,
+    BOOT_ON_S3_RESUME,
+    BOOT_ON_FLASH_UPDATE,
+    BOOT_IN_RECOVERY_MODE
+  };
+
+  UINT32  EFI_RESOURCE_TYPE_LIST[8] = {
+    EFI_RESOURCE_SYSTEM_MEMORY,
+    EFI_RESOURCE_MEMORY_MAPPED_IO,
+    EFI_RESOURCE_IO,
+    EFI_RESOURCE_FIRMWARE_DEVICE,
+    EFI_RESOURCE_MEMORY_MAPPED_IO_PORT,
+    EFI_RESOURCE_MEMORY_RESERVED,
+    EFI_RESOURCE_IO_RESERVED,
+    EFI_RESOURCE_MAX_MEMORY_TYPE
+  };
+
+  if (VmmHobList == NULL) {
+    DEBUG ((DEBUG_ERROR, "HOB: HOB data pointer is NULL\n"));
+    return FALSE;
+  }
+
+  Hob.Raw = (UINT8 *)VmmHobList;
+
+  //
+  // Parse the HOB list until end of list or matching type is found.
+  //
+  while (!END_OF_HOB_LIST (Hob)) {
+    if (Hob.Header->Reserved != (UINT32)0) {
+      DEBUG ((DEBUG_ERROR, "HOB: Hob header Reserved filed should be zero\n"));
+      return FALSE;
+    }
+
+    if (Hob.Header->HobLength == 0) {
+      DEBUG ((DEBUG_ERROR, "HOB: Hob header LEANGTH should not be zero\n"));
+      return FALSE;
+    }
+
+    switch (Hob.Header->HobType) {
+      case EFI_HOB_TYPE_HANDOFF:
+        if (Hob.Header->HobLength != sizeof (EFI_HOB_HANDOFF_INFO_TABLE)) {
+          DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_HANDOFF));
+          return FALSE;
+        }
+
+        if (IsInValidList (Hob.HandoffInformationTable->BootMode, EFI_BOOT_MODE_LIST, 12) == FALSE) {
+          DEBUG ((DEBUG_ERROR, "HOB: Unknow HandoffInformationTable BootMode type. Type: 0x%08x\n", Hob.HandoffInformationTable->BootMode));
+          return FALSE;
+        }
+
+        if ((Hob.HandoffInformationTable->EfiFreeMemoryTop % 4096) != 0) {
+          DEBUG ((DEBUG_ERROR, "HOB: HandoffInformationTable EfiFreeMemoryTop address must be 4-KB aligned to meet page restrictions of UEFI.\
+                               Address: 0x%016lx\n", Hob.HandoffInformationTable->EfiFreeMemoryTop));
+          return FALSE;
+        }
+
+        break;
+
+      case EFI_HOB_TYPE_RESOURCE_DESCRIPTOR:
+        if (Hob.Header->HobLength != sizeof (EFI_HOB_RESOURCE_DESCRIPTOR)) {
+          DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_RESOURCE_DESCRIPTOR));
+          return FALSE;
+        }
+
+        if (IsInValidList (Hob.ResourceDescriptor->ResourceType, EFI_RESOURCE_TYPE_LIST, 8) == FALSE) {
+          DEBUG ((DEBUG_ERROR, "HOB: Unknow ResourceDescriptor ResourceType type. Type: 0x%08x\n", Hob.ResourceDescriptor->ResourceType));
+          return FALSE;
+        }
+
+        if ((Hob.ResourceDescriptor->ResourceAttribute & (~(EFI_RESOURCE_ATTRIBUTE_PRESENT |
+                                                            EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
+                                                            EFI_RESOURCE_ATTRIBUTE_TESTED |
+                                                            EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED |
+                                                            EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED |
+                                                            EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED |
+                                                            EFI_RESOURCE_ATTRIBUTE_PERSISTENT |
+                                                            EFI_RESOURCE_ATTRIBUTE_SINGLE_BIT_ECC |
+                                                            EFI_RESOURCE_ATTRIBUTE_MULTIPLE_BIT_ECC |
+                                                            EFI_RESOURCE_ATTRIBUTE_ECC_RESERVED_1 |
+                                                            EFI_RESOURCE_ATTRIBUTE_ECC_RESERVED_2 |
+                                                            EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
+                                                            EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
+                                                            EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
+                                                            EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE |
+                                                            EFI_RESOURCE_ATTRIBUTE_16_BIT_IO |
+                                                            EFI_RESOURCE_ATTRIBUTE_32_BIT_IO |
+                                                            EFI_RESOURCE_ATTRIBUTE_64_BIT_IO |
+                                                            EFI_RESOURCE_ATTRIBUTE_UNCACHED_EXPORTED |
+                                                            EFI_RESOURCE_ATTRIBUTE_READ_PROTECTABLE |
+                                                            EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTABLE |
+                                                            EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTABLE |
+                                                            EFI_RESOURCE_ATTRIBUTE_PERSISTABLE |
+                                                            EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTED |
+                                                            EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTABLE |
+                                                            EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE |
+                                                            EFI_RESOURCE_ATTRIBUTE_ENCRYPTED))) != 0)
+        {
+          DEBUG ((DEBUG_ERROR, "HOB: Unknow ResourceDescriptor ResourceAttribute type. Type: 0x%08x\n", Hob.ResourceDescriptor->ResourceAttribute));
+          return FALSE;
+        }
+
+        break;
+
+      // EFI_HOB_GUID_TYPE is variable length data, so skip check
+      case EFI_HOB_TYPE_GUID_EXTENSION:
+        break;
+
+      case EFI_HOB_TYPE_FV:
+        if (Hob.Header->HobLength != sizeof (EFI_HOB_FIRMWARE_VOLUME)) {
+          DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_FV));
+          return FALSE;
+        }
+
+        break;
+
+      case EFI_HOB_TYPE_FV2:
+        if (Hob.Header->HobLength != sizeof (EFI_HOB_FIRMWARE_VOLUME2)) {
+          DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_FV2));
+          return FALSE;
+        }
+
+        break;
+
+      case EFI_HOB_TYPE_FV3:
+        if (Hob.Header->HobLength != sizeof (EFI_HOB_FIRMWARE_VOLUME3)) {
+          DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_FV3));
+          return FALSE;
+        }
+
+        break;
+
+      case EFI_HOB_TYPE_CPU:
+        if (Hob.Header->HobLength != sizeof (EFI_HOB_CPU)) {
+          DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_CPU));
+          return FALSE;
+        }
+
+        for (UINT32 index = 0; index < 6; index++) {
+          if (Hob.Cpu->Reserved[index] != 0) {
+            DEBUG ((DEBUG_ERROR, "HOB: Cpu Reserved field will always be set to zero.\n"));
+            return FALSE;
+          }
+        }
+
+        break;
+
+      default:
+        DEBUG ((DEBUG_ERROR, "HOB: Hob type is not know. Type: 0x%04x\n", Hob.Header->HobType));
+        return FALSE;
+    }
+
+    // Get next HOB
+    Hob.Raw = (UINT8 *)(Hob.Raw + Hob.Header->HobLength);
+  }
+
+  return TRUE;
+}
+
+/**
+  Processing the incoming HobList for the TDX
+
+  Firmware must parse list, and accept the pages of memory before their can be
+  use by the guest.
+
+  @param[in] VmmHobList    The Hoblist pass the firmware
+
+  @retval  EFI_SUCCESS     Process the HobList successfully
+  @retval  Others          Other errors as indicated
+
+**/
+EFI_STATUS
+EFIAPI
+ProcessHobList (
+  IN CONST VOID  *VmmHobList
+  )
+{
+  EFI_STATUS            Status;
+  EFI_PEI_HOB_POINTERS  Hob;
+  EFI_PHYSICAL_ADDRESS  PhysicalEnd;
+
+  Status = EFI_SUCCESS;
+  ASSERT (VmmHobList != NULL);
+  Hob.Raw = (UINT8 *)VmmHobList;
+
+  //
+  // Parse the HOB list until end of list or matching type is found.
+  //
+  while (!END_OF_HOB_LIST (Hob)) {
+    if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
+      DEBUG ((DEBUG_INFO, "\nResourceType: 0x%x\n", Hob.ResourceDescriptor->ResourceType));
+
+      if (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) {
+        DEBUG ((DEBUG_INFO, "ResourceAttribute: 0x%x\n", Hob.ResourceDescriptor->ResourceAttribute));
+        DEBUG ((DEBUG_INFO, "PhysicalStart: 0x%llx\n", Hob.ResourceDescriptor->PhysicalStart));
+        DEBUG ((DEBUG_INFO, "ResourceLength: 0x%llx\n", Hob.ResourceDescriptor->ResourceLength));
+        DEBUG ((DEBUG_INFO, "Owner: %g\n\n", &Hob.ResourceDescriptor->Owner));
+
+        PhysicalEnd = Hob.ResourceDescriptor->PhysicalStart + Hob.ResourceDescriptor->ResourceLength;
+
+        Status = BspAcceptMemoryResourceRange (
+                   Hob.ResourceDescriptor->PhysicalStart,
+                   PhysicalEnd
+                   );
+        if (EFI_ERROR (Status)) {
+          break;
+        }
+      }
+    }
+
+    Hob.Raw = GET_NEXT_HOB (Hob);
+  }
+
+  return Status;
+}
+
+/**
+  In Tdx guest, some information need to be passed from host VMM to guest
+  firmware. For example, the memory resource, etc. These information are
+  prepared by host VMM and put in HobList which is described in TdxMetadata.
+
+  Information in HobList is treated as external input. From the security
+  perspective before it is consumed, it should be validated.
+
+  @retval   EFI_SUCCESS   Successfully process the hoblist
+  @retval   Others        Other error as indicated
+**/
+EFI_STATUS
+EFIAPI
+ProcessTdxHobList (
+  VOID
+  )
+{
+  EFI_STATUS      Status;
+  VOID            *TdHob;
+  TD_RETURN_DATA  TdReturnData;
+
+  TdHob  = (VOID *)(UINTN)FixedPcdGet32 (PcdOvmfSecGhcbBase);
+  Status = TdCall (TDCALL_TDINFO, 0, 0, 0, &TdReturnData);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  DEBUG ((
+    DEBUG_INFO,
+    "Intel Tdx Started with (GPAW: %d, Cpus: %d)\n",
+    TdReturnData.TdInfo.Gpaw,
+    TdReturnData.TdInfo.NumVcpus
+    ));
+
+  //
+  // Validate HobList
+  //
+  if (ValidateHobList (TdHob) == FALSE) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Process Hoblist to accept memory
+  //
+  Status = ProcessHobList (TdHob);
+
+  return Status;
+}
diff --git a/OvmfPkg/Sec/IntelTdx.h b/OvmfPkg/Sec/IntelTdx.h
new file mode 100644
index 000000000000..ddd09eff34cd
--- /dev/null
+++ b/OvmfPkg/Sec/IntelTdx.h
@@ -0,0 +1,46 @@
+/** @file
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef SEC_INTEL_TDX_H_
+#define SEC_INTEL_TDX_H_
+
+#include <PiPei.h>
+#include <Library/BaseLib.h>
+#include <Uefi/UefiSpec.h>
+#include <Uefi/UefiBaseType.h>
+#include <IndustryStandard/UefiTcgPlatform.h>
+
+/**
+  Check TDX is enabled.
+
+  @retval    TRUE   TDX is enabled
+  @retval    FALSE  TDX is not enabled
+**/
+BOOLEAN
+SecTdxIsEnabled (
+  VOID
+  );
+
+/**
+  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
diff --git a/OvmfPkg/Sec/SecMain.c b/OvmfPkg/Sec/SecMain.c
index 2c5561661ef3..e2f3ede93901 100644
--- a/OvmfPkg/Sec/SecMain.c
+++ b/OvmfPkg/Sec/SecMain.c
@@ -26,9 +26,11 @@
 #include <Library/ExtractGuidedSectionLib.h>
 #include <Library/LocalApicLib.h>
 #include <Library/CpuExceptionHandlerLib.h>
-
+#include <IndustryStandard/Tdx.h>
+#include <Library/TdxLib.h>
 #include <Ppi/TemporaryRamSupport.h>
 
+#include "IntelTdx.h"
 #include "AmdSev.h"
 
 #define SEC_IDT_ENTRY_COUNT  34
@@ -738,6 +740,20 @@ SecCoreStartupWithStack (
   UINT32                Index;
   volatile UINT8        *Table;
 
+ #if defined (MDE_CPU_X64)
+  if (SecTdxIsEnabled ()) {
+    //
+    // 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,13 +772,20 @@ SecCoreStartupWithStack (
   // we use a loop rather than CopyMem.
   //
   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 = (CONST UINT8 *)&mIdtEntryTemplate;
+    Dst = (volatile UINT8 *)&IdtTableInStack.IdtTable[Index];
 
-    Src = (UINT8 *)&mIdtEntryTemplate;
-    Dst = (UINT8 *)&IdtTableInStack.IdtTable[Index];
     for (Byte = 0; Byte < sizeof (mIdtEntryTemplate); Byte++) {
       Dst[Byte] = Src[Byte];
     }
@@ -808,6 +831,17 @@ SecCoreStartupWithStack (
     AsmEnableCache ();
   }
 
+ #if defined (MDE_CPU_X64)
+  if (SecTdxIsEnabled ()) {
+    //
+    // 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..230ee5e465b9 100644
--- a/OvmfPkg/Sec/SecMain.inf
+++ b/OvmfPkg/Sec/SecMain.inf
@@ -30,6 +30,7 @@
   Ia32/SecEntry.nasm
 
 [Sources.X64]
+  IntelTdx.c
   X64/SecEntry.nasm
 
 [Packages]
@@ -55,6 +56,9 @@
   MemEncryptSevLib
   CpuExceptionHandlerLib
 
+[LibraryClasses.X64]
+  TdxLib
+
 [Ppis]
   gEfiTemporaryRamSupportPpiGuid                # PPI ALWAYS_PRODUCED
 
@@ -77,6 +81,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] 68+ messages in thread

* [PATCH V4 18/31] OvmfPkg: Check Tdx in QemuFwCfgPei to avoid DMA operation
  2021-12-13 12:56 [PATCH V4 00/31] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (16 preceding siblings ...)
  2021-12-13 12:56 ` [PATCH V4 17/31] OvmfPkg: Update Sec to support Tdx Min Xu
@ 2021-12-13 12:56 ` Min Xu
  2021-12-15  8:19   ` Gerd Hoffmann
  2021-12-13 12:56 ` [PATCH V4 19/31] MdeModulePkg: EFER should not be changed in TDX Min Xu
                   ` (12 subsequent siblings)
  30 siblings, 1 reply; 68+ messages in thread
From: Min Xu @ 2021-12-13 12:56 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>
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] 68+ messages in thread

* [PATCH V4 19/31] MdeModulePkg: EFER should not be changed in TDX
  2021-12-13 12:56 [PATCH V4 00/31] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (17 preceding siblings ...)
  2021-12-13 12:56 ` [PATCH V4 18/31] OvmfPkg: Check Tdx in QemuFwCfgPei to avoid DMA operation Min Xu
@ 2021-12-13 12:56 ` Min Xu
  2021-12-13 12:56 ` [PATCH V4 20/31] MdeModulePkg: Add PcdTdxSharedBitMask Min Xu
                   ` (11 subsequent siblings)
  30 siblings, 0 replies; 68+ messages in thread
From: Min Xu @ 2021-12-13 12:56 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

In TDX IA32_ERER is RO to host VMM. It could not be changed.
PcdIa32EferChangeAllowed is added in MdeModulePkg.dec and it is
to be set to FALSE in Tdx 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>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf          | 1 +
 MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c | 7 +++++++
 MdeModulePkg/MdeModulePkg.dec                    | 5 +++++
 3 files changed, 13 insertions(+)

diff --git a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf b/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
index 19b8a4c8aefa..106b679b6bd0 100644
--- a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
+++ b/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
@@ -117,6 +117,7 @@
   gEfiMdeModulePkgTokenSpaceGuid.PcdUse5LevelPageTable                  ## SOMETIMES_CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase                            ## CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize                            ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdIa32EferChangeAllowed               ## CONSUMES
 
 [Pcd.IA32,Pcd.X64,Pcd.ARM,Pcd.AARCH64]
   gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack               ## SOMETIMES_CONSUMES
diff --git a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
index 0700f310b203..5c647c74e773 100644
--- a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
+++ b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
@@ -159,6 +159,13 @@ IsEnableNonExecNeeded (
     return FALSE;
   }
 
+  //
+  // Intel TDX sets this flag to FALSE.
+  //
+  if (!PcdGetBool (PcdIa32EferChangeAllowed)) {
+    return FALSE;
+  }
+
   //
   // XD flag (BIT63) in page table entry is only valid if IA32_EFER.NXE is set.
   // Features controlled by Following PCDs need this feature to be enabled.
diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec
index 463e889e9a68..453f2a74b11d 100644
--- a/MdeModulePkg/MdeModulePkg.dec
+++ b/MdeModulePkg/MdeModulePkg.dec
@@ -2138,6 +2138,11 @@
   # @Prompt GHCB Pool Size
   gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize|0|UINT64|0x00030008
 
+  ## This dynamic PCD indicates if IA32_EFER can be changed. The default value is TRUE but in
+  #  Intel TDX change of IA32_EFER is not allowed.
+  # @Prompt The flag which indicates if IA32_EFER is allowed to be changed.
+  gEfiMdeModulePkgTokenSpaceGuid.PcdIa32EferChangeAllowed|TRUE|BOOLEAN|0x00030009
+
 [PcdsDynamicEx]
   ## This dynamic PCD enables the default variable setting.
   #  Its value is the default store ID value. The default value is zero as Standard default.
-- 
2.29.2.windows.2


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

* [PATCH V4 20/31] MdeModulePkg: Add PcdTdxSharedBitMask
  2021-12-13 12:56 [PATCH V4 00/31] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (18 preceding siblings ...)
  2021-12-13 12:56 ` [PATCH V4 19/31] MdeModulePkg: EFER should not be changed in TDX Min Xu
@ 2021-12-13 12:56 ` Min Xu
  2021-12-15  8:22   ` Gerd Hoffmann
  2021-12-13 12:56 ` [PATCH V4 21/31] UefiCpuPkg: Update AddressEncMask in CpuPageTable Min Xu
                   ` (10 subsequent siblings)
  30 siblings, 1 reply; 68+ messages in thread
From: Min Xu @ 2021-12-13 12:56 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>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 MdeModulePkg/MdeModulePkg.dec | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec
index 453f2a74b11d..e90a7f38708c 100644
--- a/MdeModulePkg/MdeModulePkg.dec
+++ b/MdeModulePkg/MdeModulePkg.dec
@@ -2143,6 +2143,10 @@
   # @Prompt The flag which indicates if IA32_EFER is allowed to be changed.
   gEfiMdeModulePkgTokenSpaceGuid.PcdIa32EferChangeAllowed|TRUE|BOOLEAN|0x00030009
 
+  ## 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|0x0003000a
+
 [PcdsDynamicEx]
   ## This dynamic PCD enables the default variable setting.
   #  Its value is the default store ID value. The default value is zero as Standard default.
-- 
2.29.2.windows.2


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

* [PATCH V4 21/31] UefiCpuPkg: Update AddressEncMask in CpuPageTable
  2021-12-13 12:56 [PATCH V4 00/31] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (19 preceding siblings ...)
  2021-12-13 12:56 ` [PATCH V4 20/31] MdeModulePkg: Add PcdTdxSharedBitMask Min Xu
@ 2021-12-13 12:56 ` Min Xu
  2021-12-15  8:38   ` Gerd Hoffmann
  2021-12-13 12:56 ` [PATCH V4 22/31] OvmfPkg: Update PlatformPei to support TDX Min Xu
                   ` (9 subsequent siblings)
  30 siblings, 1 reply; 68+ messages in thread
From: Min Xu @ 2021-12-13 12:56 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>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 UefiCpuPkg/CpuDxe/CpuDxe.inf     | 1 +
 UefiCpuPkg/CpuDxe/CpuPageTable.c | 4 ++++
 2 files changed, 5 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..28982936fade 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) {
@@ -357,6 +360,7 @@ GetPageTableEntry (
 
   // 4k
   L1PageTable = (UINT64 *)(UINTN)(L2PageTable[Index2] & ~AddressEncMask & PAGING_4K_ADDRESS_MASK_64);
+
   if ((L1PageTable[Index1] == 0) && (Address != 0)) {
     *PageAttribute = PageNone;
     return NULL;
-- 
2.29.2.windows.2


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

* [PATCH V4 22/31] OvmfPkg: Update PlatformPei to support TDX
  2021-12-13 12:56 [PATCH V4 00/31] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (20 preceding siblings ...)
  2021-12-13 12:56 ` [PATCH V4 21/31] UefiCpuPkg: Update AddressEncMask in CpuPageTable Min Xu
@ 2021-12-13 12:56 ` Min Xu
  2021-12-15  8:53   ` Gerd Hoffmann
  2022-01-13 19:18   ` Vishal Annapurve
  2021-12-13 12:56 ` [PATCH V4 23/31] OvmfPkg: Update AcpiPlatformDxe to alter MADT table Min Xu
                   ` (8 subsequent siblings)
  30 siblings, 2 replies; 68+ messages in thread
From: Min Xu @ 2021-12-13 12:56 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

Intel TDX has its own requirement in InitializePlatform (PlatformPei).
1. Publish the ram region
  Host VMM pass the memory region to TDVF in TD Hob. These memory
  are accepted by TDVF before they're available for access. TDVF
  publish these memory information in the final hoblist for DXE.
2. Create PlatformInfoHob
  PlatformInfoHob contains the TDX specific information, for example,
  the relocated Mailbox address. gUefiOvmfPkgTdxPlatformGuid is the new
  GUID added in OvmfPkg.dec for this purpose.

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>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/OvmfPkg.dec                  |   1 +
 OvmfPkg/PlatformPei/FeatureControl.c |   8 +-
 OvmfPkg/PlatformPei/IntelTdx.c       | 223 +++++++++++++++++++++++++++
 OvmfPkg/PlatformPei/IntelTdxNull.c   |  49 ++++++
 OvmfPkg/PlatformPei/MemDetect.c      |  56 +++++--
 OvmfPkg/PlatformPei/Platform.c       |   1 +
 OvmfPkg/PlatformPei/Platform.h       |  22 +++
 OvmfPkg/PlatformPei/PlatformPei.inf  |  12 ++
 8 files changed, 359 insertions(+), 13 deletions(-)
 create mode 100644 OvmfPkg/PlatformPei/IntelTdx.c
 create mode 100644 OvmfPkg/PlatformPei/IntelTdxNull.c

diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index 7a4a58c7a2ce..37427d71a355 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -129,6 +129,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}}
+  gUefiOvmfPkgTdxPlatformGuid           = {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..b351ee1c7288 100644
--- a/OvmfPkg/PlatformPei/FeatureControl.c
+++ b/OvmfPkg/PlatformPei/FeatureControl.c
@@ -12,6 +12,8 @@
 #include <Library/QemuFwCfgLib.h>
 #include <Ppi/MpServices.h>
 #include <Register/ArchitecturalMsr.h>
+#include <Library/TdxLib.h>
+#include <IndustryStandard/Tdx.h>
 
 #include "Platform.h"
 
@@ -37,7 +39,11 @@ WriteFeatureControl (
   IN OUT VOID  *WorkSpace
   )
 {
-  AsmWriteMsr64 (MSR_IA32_FEATURE_CONTROL, mFeatureControlValue);
+  if (PlatformPeiIsTdxGuest ()) {
+    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..e250ecac3ae3
--- /dev/null
+++ b/OvmfPkg/PlatformPei/IntelTdx.c
@@ -0,0 +1,223 @@
+/** @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 <WorkArea.h>
+#include <ConfidentialComputingGuestAttr.h>
+#include "Platform.h"
+
+/**
+  Check if it is Tdx guest
+
+  @retval    TRUE   It is Tdx guest
+  @retval    FALSE  It is not Tdx guest
+**/
+BOOLEAN
+PlatformPeiIsTdxGuest (
+  VOID
+  )
+{
+  CONFIDENTIAL_COMPUTING_WORK_AREA_HEADER  *CcWorkAreaHeader;
+
+  CcWorkAreaHeader = (CONFIDENTIAL_COMPUTING_WORK_AREA_HEADER *)FixedPcdGet32 (PcdOvmfWorkAreaBase);
+  return (CcWorkAreaHeader != NULL && CcWorkAreaHeader->GuestType == GUEST_TYPE_INTEL_TDX);
+}
+
+VOID
+EFIAPI
+DEBUG_HOBLIST (
+  IN CONST VOID  *HobStart
+  )
+{
+  EFI_PEI_HOB_POINTERS  Hob;
+
+  Hob.Raw = (UINT8 *)HobStart;
+  //
+  // Parse the HOB list until end of list or matching type is found.
+  //
+  while (!END_OF_HOB_LIST (Hob)) {
+    DEBUG ((DEBUG_INFO, "HOB(%p) : %x %x\n", Hob, Hob.Header->HobType, Hob.Header->HobLength));
+    switch (Hob.Header->HobType) {
+      case EFI_HOB_TYPE_RESOURCE_DESCRIPTOR:
+        DEBUG ((
+          DEBUG_INFO,
+          "\t: %x %x %llx %llx\n",
+          Hob.ResourceDescriptor->ResourceType,
+          Hob.ResourceDescriptor->ResourceAttribute,
+          Hob.ResourceDescriptor->PhysicalStart,
+          Hob.ResourceDescriptor->ResourceLength
+          ));
+
+        break;
+      case EFI_HOB_TYPE_MEMORY_ALLOCATION:
+        DEBUG ((
+          DEBUG_INFO,
+          "\t: %llx %llx %x\n",
+          Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress,
+          Hob.MemoryAllocation->AllocDescriptor.MemoryLength,
+          Hob.MemoryAllocation->AllocDescriptor.MemoryType
+          ));
+        break;
+      default:
+        break;
+    }
+
+    Hob.Raw = GET_NEXT_HOB (Hob);
+  }
+}
+
+/**
+  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_ATTRIBUTE_TYPE  ResourceAttribute;
+
+  //
+  // PcdOvmfSecGhcbBase is used as the TD_HOB in Tdx guest.
+  //
+  Hob.Raw = (UINT8 *)(UINTN)PcdGet32 (PcdOvmfSecGhcbBase);
+  while (!END_OF_HOB_LIST (Hob)) {
+    switch (Hob.Header->HobType) {
+      case EFI_HOB_TYPE_RESOURCE_DESCRIPTOR:
+        ResourceAttribute = Hob.ResourceDescriptor->ResourceAttribute;
+
+        BuildResourceDescriptorHob (
+          Hob.ResourceDescriptor->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);
+  }
+
+  DEBUG_HOBLIST (GetHobList ());
+}
+
+/**
+
+  Publish memory regions in Intel TDX guest.
+
+**/
+VOID
+TdxPublishRamRegions (
+  VOID
+  )
+{
+  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 (
+    PcdGet32 (PcdOvmfSecGhcbBackupBase),
+    PcdGet32 (PcdOvmfSecGhcbBackupSize),
+    EfiACPIMemoryNVS
+    );
+}
+
+/**
+  This function check the system status from QEMU via fw_cfg.
+  If the system status from QEMU is retrieved, its value is set
+  into PlatformInfoHob.
+
+  @param[in]  PlatformInfoHob   The data structure of PlatformInfo hob
+**/
+VOID
+EFIAPI
+CheckSystemStatsForOverride (
+  IN EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
+  )
+{
+  EFI_STATUS            Status;
+  FIRMWARE_CONFIG_ITEM  FwCfgItem;
+  UINTN                 FwCfgSize;
+
+  //
+  // check for overrides
+  //
+  Status = QemuFwCfgFindFile ("etc/system-states", &FwCfgItem, &FwCfgSize);
+  if ((Status != RETURN_SUCCESS) || (FwCfgSize != sizeof PlatformInfoHob->SystemStates)) {
+    DEBUG ((DEBUG_INFO, "ACPI using S3/S4 defaults\n"));
+    return;
+  }
+
+  QemuFwCfgSelectItem (FwCfgItem);
+  QemuFwCfgReadBytes (sizeof (PlatformInfoHob->SystemStates), PlatformInfoHob->SystemStates);
+}
+
+/**
+
+  This Function checks if TDX is available, if present then it sets
+  the dynamic PcdTdxIsEnabled and PcdIa32EferChangeAllowed.
+
+  It relocates the td mailbox and create the PlatformInfo Hob which includes
+  the TDX specific information which will be consumed in DXE phase.
+
+  **/
+VOID
+IntelTdxInitialize (
+  VOID
+  )
+{
+  EFI_HOB_PLATFORM_INFO  PlatformInfoHob;
+  RETURN_STATUS          PcdStatus;
+
+  if (!PlatformPeiIsTdxGuest ()) {
+    return;
+  }
+
+  PcdStatus = PcdSet64S (PcdConfidentialComputingGuestAttr, CCAttrIntelTdx);
+  ASSERT_RETURN_ERROR (PcdStatus);
+
+  PcdStatus = PcdSetBoolS (PcdIa32EferChangeAllowed, FALSE);
+  ASSERT_RETURN_ERROR (PcdStatus);
+
+  PcdStatus = PcdSet64S (PcdTdxSharedBitMask, TdSharedPageMask ());
+  ASSERT_RETURN_ERROR (PcdStatus);
+
+  ZeroMem (&PlatformInfoHob, sizeof (PlatformInfoHob));
+  PlatformInfoHob.HostBridgePciDevId = mHostBridgeDevId;
+
+  CheckSystemStatsForOverride (&PlatformInfoHob);
+
+  BuildGuidDataHob (&gUefiOvmfPkgTdxPlatformGuid, &PlatformInfoHob, sizeof (EFI_HOB_PLATFORM_INFO));
+}
diff --git a/OvmfPkg/PlatformPei/IntelTdxNull.c b/OvmfPkg/PlatformPei/IntelTdxNull.c
new file mode 100644
index 000000000000..f887afae363a
--- /dev/null
+++ b/OvmfPkg/PlatformPei/IntelTdxNull.c
@@ -0,0 +1,49 @@
+/** @file
+  Main SEC phase code. Handles initial TDX Hob List Processing
+
+  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 <PiPei.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <IndustryStandard/IntelTdx.h>
+
+/**
+  Check if it is Tdx guest
+
+  @retval    TRUE   It is Tdx guest
+  @retval    FALSE  It is not Tdx guest
+**/
+BOOLEAN
+PlatformPeiIsTdxGuest (
+  VOID
+  )
+{
+  return FALSE;
+}
+
+VOID
+TdxPublishRamRegions (
+  VOID
+  )
+{
+}
+
+VOID
+IntelTdxInitialize (
+  VOID
+  )
+{
+}
+
+VOID
+AsmGetRelocationMap (
+  OUT MP_RELOCATION_MAP  *AddressMap
+  )
+{
+}
diff --git a/OvmfPkg/PlatformPei/MemDetect.c b/OvmfPkg/PlatformPei/MemDetect.c
index 934d5c196570..9227fa260ccd 100644
--- a/OvmfPkg/PlatformPei/MemDetect.c
+++ b/OvmfPkg/PlatformPei/MemDetect.c
@@ -36,6 +36,7 @@ Module Name:
 #include <Library/MtrrLib.h>
 #include <Library/QemuFwCfgLib.h>
 #include <Library/QemuFwCfgSimpleParserLib.h>
+#include <Library/TdxLib.h>
 
 #include "Platform.h"
 #include "Cmos.h"
@@ -556,7 +557,19 @@ AddressWidthInitialization (
     mPhysMemAddressWidth = 36;
   }
 
+ #if defined (MDE_CPU_X64)
+  if (PlatformPeiIsTdxGuest ()) {
+    if (TdSharedPageMask () == (1ULL << 47)) {
+      mPhysMemAddressWidth = 48;
+    } else {
+      mPhysMemAddressWidth = 52;
+    }
+  }
+
+  ASSERT (mPhysMemAddressWidth <= 52);
+ #else
   ASSERT (mPhysMemAddressWidth <= 48);
+ #endif
 }
 
 /**
@@ -572,8 +585,10 @@ GetPeiMemoryCap (
   UINT32   RegEax;
   UINT32   RegEdx;
   UINT32   Pml4Entries;
+  UINT32   Pml5Entries;
   UINT32   PdpEntries;
   UINTN    TotalPages;
+  UINT8    PhysicalAddressBits;
 
   //
   // If DXE is 32-bit, then just return the traditional 64 MB cap.
@@ -602,20 +617,33 @@ GetPeiMemoryCap (
     }
   }
 
-  if (mPhysMemAddressWidth <= 39) {
-    Pml4Entries = 1;
-    PdpEntries  = 1 << (mPhysMemAddressWidth - 30);
-    ASSERT (PdpEntries <= 0x200);
+  PhysicalAddressBits = mPhysMemAddressWidth;
+  Pml5Entries         = 1;
+
+  if (PhysicalAddressBits > 48) {
+    Pml5Entries         = (UINT32)LShiftU64 (1, PhysicalAddressBits - 48);
+    PhysicalAddressBits = 48;
+  }
+
+  Pml4Entries = 1;
+  if (PhysicalAddressBits > 39) {
+    Pml4Entries         = (UINT32)LShiftU64 (1, PhysicalAddressBits - 39);
+    PhysicalAddressBits = 39;
+  }
+
+  PdpEntries = 1;
+  ASSERT (PhysicalAddressBits > 30);
+  PdpEntries = (UINT32)LShiftU64 (1, PhysicalAddressBits - 30);
+
+  //
+  // Pre-allocate big pages to avoid later allocations.
+  //
+  if (!Page1GSupport) {
+    TotalPages = ((PdpEntries + 1) * Pml4Entries + 1) * Pml5Entries + 1;
   } else {
-    Pml4Entries = 1 << (mPhysMemAddressWidth - 39);
-    ASSERT (Pml4Entries <= 0x200);
-    PdpEntries = 512;
+    TotalPages = (Pml4Entries + 1) * Pml5Entries + 1;
   }
 
-  TotalPages = Page1GSupport ? Pml4Entries + 1 :
-               (PdpEntries + 1) * Pml4Entries + 1;
-  ASSERT (TotalPages <= 0x40201);
-
   //
   // Add 64 MB for miscellaneous allocations. Note that for
   // mPhysMemAddressWidth values close to 36, the cap will actually be
@@ -876,7 +904,11 @@ InitializeRamRegions (
   VOID
   )
 {
-  QemuInitializeRam ();
+  if (PlatformPeiIsTdxGuest ()) {
+    TdxPublishRamRegions ();
+  } else {
+    QemuInitializeRam ();
+  }
 
   SevInitializeRam ();
 
diff --git a/OvmfPkg/PlatformPei/Platform.c b/OvmfPkg/PlatformPei/Platform.c
index 906f64615de7..70e3eae0f0fb 100644
--- a/OvmfPkg/PlatformPei/Platform.c
+++ b/OvmfPkg/PlatformPei/Platform.c
@@ -792,6 +792,7 @@ InitializePlatform (
 
   InstallClearCacheCallback ();
   AmdSevInitialize ();
+  IntelTdxInitialize ();
   MiscInitialization ();
   InstallFeatureControlCallback ();
 
diff --git a/OvmfPkg/PlatformPei/Platform.h b/OvmfPkg/PlatformPei/Platform.h
index 24e4da4e1d93..add04926f8f0 100644
--- a/OvmfPkg/PlatformPei/Platform.h
+++ b/OvmfPkg/PlatformPei/Platform.h
@@ -10,6 +10,7 @@
 #define _PLATFORM_PEI_H_INCLUDED_
 
 #include <IndustryStandard/E820.h>
+#include <IndustryStandard/IntelTdx.h>
 
 VOID
 AddIoMemoryBaseSizeHob (
@@ -102,6 +103,27 @@ AmdSevInitialize (
   VOID
   );
 
+VOID
+TdxPublishRamRegions (
+  VOID
+  );
+
+VOID
+IntelTdxInitialize (
+  VOID
+  );
+
+/**
+  Check if it is Tdx guest
+
+  @retval    TRUE   It is Tdx guest
+  @retval    FALSE  It is not Tdx guest
+**/
+BOOLEAN
+PlatformPeiIsTdxGuest (
+  VOID
+  );
+
 extern EFI_BOOT_MODE  mBootMode;
 
 VOID
diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf
index 1c56ba275835..696d833bdb6d 100644
--- a/OvmfPkg/PlatformPei/PlatformPei.inf
+++ b/OvmfPkg/PlatformPei/PlatformPei.inf
@@ -34,6 +34,12 @@
   Platform.c
   Platform.h
 
+[Sources.IA32, Sources.EBC]
+  IntelTdxNull.c
+
+[Sources.X64]
+  IntelTdx.c
+
 [Packages]
   EmbeddedPkg/EmbeddedPkg.dec
   MdePkg/MdePkg.dec
@@ -44,6 +50,7 @@
 
 [Guids]
   gEfiMemoryTypeInformationGuid
+  gUefiOvmfPkgTdxPlatformGuid
 
 [LibraryClasses]
   BaseLib
@@ -64,6 +71,9 @@
   PcdLib
   VmgExitLib
 
+[LibraryClasses.X64]
+  TdxLib
+
 [Pcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfPeiMemFvBase
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfPeiMemFvSize
@@ -109,6 +119,8 @@
   gUefiCpuPkgTokenSpaceGuid.PcdSevEsIsEnabled
   gEfiMdePkgTokenSpaceGuid.PcdConfidentialComputingGuestAttr
   gUefiCpuPkgTokenSpaceGuid.PcdGhcbHypervisorFeatures
+  gEfiMdeModulePkgTokenSpaceGuid.PcdIa32EferChangeAllowed
+  gEfiMdeModulePkgTokenSpaceGuid.PcdTdxSharedBitMask
 
 [FixedPcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfCpuidBase
-- 
2.29.2.windows.2


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

* [PATCH V4 23/31] OvmfPkg: Update AcpiPlatformDxe to alter MADT table
  2021-12-13 12:56 [PATCH V4 00/31] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (21 preceding siblings ...)
  2021-12-13 12:56 ` [PATCH V4 22/31] OvmfPkg: Update PlatformPei to support TDX Min Xu
@ 2021-12-13 12:56 ` Min Xu
  2021-12-15  8:54   ` Gerd Hoffmann
  2021-12-13 12:56 ` [PATCH V4 24/31] OvmfPkg: Add TdxDxe driver Min Xu
                   ` (7 subsequent siblings)
  30 siblings, 1 reply; 68+ messages in thread
From: Min Xu @ 2021-12-13 12:56 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 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].

To maintain the simplicity of the AcpiPlatformDxe, the MADT ACPI table
will be altered in another driver (TdxDxe) by installing a protocol
to notify that the ACPI table provided by Qemu is ready. Then in TdxDxe
a notification functioin will be called to alter the MADT table to recorded
the mailbox address.

The protocol is gQemuAcpiTableNotifyProtocolGuid.

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>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf   |  1 +
 OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c       | 14 +++++++++-
 .../Include/Protocol/QemuAcpiTableNotify.h    | 27 +++++++++++++++++++
 3 files changed, 41 insertions(+), 1 deletion(-)
 create mode 100644 OvmfPkg/Include/Protocol/QemuAcpiTableNotify.h

diff --git a/OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf b/OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf
index b36b8413e007..e839e37e935b 100644
--- a/OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf
+++ b/OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf
@@ -49,6 +49,7 @@
 [Protocols]
   gEfiAcpiTableProtocolGuid                     # PROTOCOL ALWAYS_CONSUMED
   gEfiPciIoProtocolGuid                         # PROTOCOL SOMETIMES_CONSUMED
+  gQemuAcpiTableNotifyProtocolGuid              # PROTOCOL PRODUCES
 
 [Guids]
   gRootBridgesConnectedEventGroupGuid
diff --git a/OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c b/OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c
index b885965a601e..c8dee17c13e6 100644
--- a/OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c
+++ b/OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c
@@ -19,7 +19,10 @@
 #include <Library/QemuFwCfgS3Lib.h>           // QemuFwCfgS3Enabled()
 #include <Library/UefiBootServicesTableLib.h> // gBS
 
+#include <Protocol/QemuAcpiTableNotify.h>
 #include "AcpiPlatform.h"
+EFI_HANDLE                       mQemuAcpiHandle = NULL;
+QEMU_ACPI_TABLE_NOTIFY_PROTOCOL  mAcpiNotifyProtocol;
 
 //
 // The user structure for the ordered collection that will track the fw_cfg
@@ -1273,7 +1276,16 @@ UninstallAcpiTables:
       AcpiProtocol->UninstallAcpiTable (AcpiProtocol, InstalledKey[Installed]);
     }
   } else {
-    DEBUG ((DEBUG_INFO, "%a: installed %d tables\n", __FUNCTION__, Installed));
+    //
+    // Install a protocol to notify that the ACPI table provided by Qemu is
+    // ready.
+    //
+    gBS->InstallProtocolInterface (
+           &mQemuAcpiHandle,
+           &gQemuAcpiTableNotifyProtocolGuid,
+           EFI_NATIVE_INTERFACE,
+           &mAcpiNotifyProtocol
+           );
   }
 
   for (SeenPointerEntry = OrderedCollectionMin (SeenPointers);
diff --git a/OvmfPkg/Include/Protocol/QemuAcpiTableNotify.h b/OvmfPkg/Include/Protocol/QemuAcpiTableNotify.h
new file mode 100644
index 000000000000..a3dd2fc1dc91
--- /dev/null
+++ b/OvmfPkg/Include/Protocol/QemuAcpiTableNotify.h
@@ -0,0 +1,27 @@
+/** @file
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef QEMU_ACPI_TABLE_NOTIFY_H_
+#define QEMU_ACPI_TABLE_NOTIFY_H_
+
+#define QEMU_ACPI_TABLE_NOTIFY_GUID \
+  { 0x928939b2, 0x4235, 0x462f, { 0x95, 0x80, 0xf6, 0xa2, 0xb2, 0xc2, 0x1a, 0x4f } };
+
+///
+/// Forward declaration
+///
+typedef struct _QEMU_ACPI_TABLE_NOTIFY_PROTOCOL QEMU_ACPI_TABLE_NOTIFY_PROTOCOL;
+
+///
+/// Protocol structure
+///
+struct _QEMU_ACPI_TABLE_NOTIFY_PROTOCOL {
+  UINT8    Notify;
+};
+
+extern EFI_GUID  gQemuAcpiTableNotifyProtocolGuid;
+
+#endif
-- 
2.29.2.windows.2


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

* [PATCH V4 24/31] OvmfPkg: Add TdxDxe driver
  2021-12-13 12:56 [PATCH V4 00/31] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (22 preceding siblings ...)
  2021-12-13 12:56 ` [PATCH V4 23/31] OvmfPkg: Update AcpiPlatformDxe to alter MADT table Min Xu
@ 2021-12-13 12:56 ` Min Xu
  2021-12-15  9:05   ` Gerd Hoffmann
  2021-12-13 12:56 ` [PATCH V4 25/31] OvmfPkg/BaseMemEncryptTdxLib: Add TDX helper library Min Xu
                   ` (6 subsequent siblings)
  30 siblings, 1 reply; 68+ messages in thread
From: Min Xu @ 2021-12-13 12:56 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

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>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/OvmfPkg.dec               |   1 +
 OvmfPkg/OvmfPkgX64.dsc            |   2 +
 OvmfPkg/OvmfPkgX64.fdf            |   3 +
 OvmfPkg/TdxDxe/TdxAcpiTable.c     | 213 +++++++++++++++++++++++++
 OvmfPkg/TdxDxe/TdxAcpiTable.h     |  60 +++++++
 OvmfPkg/TdxDxe/TdxDxe.c           | 251 ++++++++++++++++++++++++++++++
 OvmfPkg/TdxDxe/TdxDxe.inf         |  64 ++++++++
 OvmfPkg/TdxDxe/X64/ApRunLoop.nasm |  87 +++++++++++
 8 files changed, 681 insertions(+)
 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

diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index 37427d71a355..0456d1cdf47e 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -154,6 +154,7 @@
   gEfiLegacyInterruptProtocolGuid       = {0x31ce593d, 0x108a, 0x485d, {0xad, 0xb2, 0x78, 0xf2, 0x1f, 0x29, 0x66, 0xbe}}
   gEfiVgaMiniPortProtocolGuid           = {0xc7735a2f, 0x88f5, 0x4882, {0xae, 0x63, 0xfa, 0xac, 0x8c, 0x8b, 0x86, 0xb3}}
   gOvmfLoadedX86LinuxKernelProtocolGuid = {0xa3edc05d, 0xb618, 0x4ff6, {0x95, 0x52, 0x76, 0xd7, 0x88, 0x63, 0x43, 0xc8}}
+  gQemuAcpiTableNotifyProtocolGuid      = {0x928939b2, 0x4235, 0x462f, {0x95, 0x80, 0xf6, 0xa2, 0xb2, 0xc2, 0x1a, 0x4f}}
 
 [PcdsFixedAtBuild]
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfPeiMemFvBase|0x0|UINT32|0
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index fb77a39a0ae5..b1ec012e4f83 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -983,6 +983,8 @@
   }
   OvmfPkg/IoMmuDxe/IoMmuDxe.inf
 
+  OvmfPkg/TdxDxe/TdxDxe.inf
+
 !if $(SMM_REQUIRE) == TRUE
   OvmfPkg/SmmAccess/SmmAccess2Dxe.inf
   OvmfPkg/SmmControl2Dxe/SmmControl2Dxe.inf
diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
index 1420ae880221..97c966d16a78 100644
--- a/OvmfPkg/OvmfPkgX64.fdf
+++ b/OvmfPkg/OvmfPkgX64.fdf
@@ -220,6 +220,7 @@ READ_LOCK_STATUS   = TRUE
 APRIORI DXE {
   INF  MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.inf
   INF  MdeModulePkg/Universal/PCD/Dxe/Pcd.inf
+  INF  OvmfPkg/TdxDxe/TdxDxe.inf
   INF  OvmfPkg/AmdSevDxe/AmdSevDxe.inf
 !if $(SMM_REQUIRE) == FALSE
   INF  OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
@@ -324,6 +325,8 @@ INF  ShellPkg/Application/Shell/Shell.inf
 
 INF MdeModulePkg/Logo/LogoDxe.inf
 
+INF OvmfPkg/TdxDxe/TdxDxe.inf
+
 #
 # Network modules
 #
diff --git a/OvmfPkg/TdxDxe/TdxAcpiTable.c b/OvmfPkg/TdxDxe/TdxAcpiTable.c
new file mode 100644
index 000000000000..8a1abe8b1d89
--- /dev/null
+++ b/OvmfPkg/TdxDxe/TdxAcpiTable.c
@@ -0,0 +1,213 @@
+/** @file
+  OVMF ACPI QEMU support
+
+  Copyright (c) 2008 - 2014, Intel Corporation. All rights reserved.<BR>
+
+  Copyright (C) 2012-2014, Red Hat, Inc.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/QemuFwCfgLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/PcdLib.h>
+#include <Library/OrderedCollectionLib.h>
+#include <Library/TdxLib.h>
+#include <IndustryStandard/Acpi.h>
+#include <Protocol/AcpiSystemDescriptionTable.h>
+#include <Protocol/AcpiTable.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/TdxMailboxLib.h>
+#include <Protocol/Cpu.h>
+#include <Uefi.h>
+#include <TdxAcpiTable.h>
+
+/**
+  At the beginning of system boot, a 4K-aligned, 4K-size memory (Td mailbox) is
+  pre-allocated by host VMM. BSP & APs do the page accept together in that memory
+  region.
+
+  After that TDVF is designed to relocate the mailbox to a 4K-aligned, 4K-size
+  memory block which is allocated in the ACPI Nvs memory. APs are waken up and
+  spin around the relocated mailbox for further command.
+
+  @return   EFI_PHYSICAL_ADDRESS    Address of the relocated mailbox
+**/
+EFI_PHYSICAL_ADDRESS
+EFIAPI
+RelocateMailbox (
+  VOID
+  )
+{
+  EFI_PHYSICAL_ADDRESS  Address;
+  VOID                  *ApLoopFunc;
+  UINT32                RelocationPages;
+  MP_RELOCATION_MAP     RelocationMap;
+  MP_WAKEUP_MAILBOX     *RelocatedMailBox;
+  EFI_STATUS            Status;
+
+  Address    = 0;
+  ApLoopFunc = NULL;
+  ZeroMem (&RelocationMap, sizeof (RelocationMap));
+
+  //
+  // Get information needed to setup aps running in their
+  // run loop in allocated acpi reserved memory
+  // Add another page for mailbox
+  //
+  AsmGetRelocationMap (&RelocationMap);
+  if ((RelocationMap.RelocateApLoopFuncAddress == 0) || (RelocationMap.RelocateApLoopFuncSize == 0)) {
+    DEBUG ((DEBUG_ERROR, "Failed to get the RelocationMap.\n"));
+    return 0;
+  }
+
+  RelocationPages = EFI_SIZE_TO_PAGES ((UINT32)RelocationMap.RelocateApLoopFuncSize) + 1;
+
+  Status = gBS->AllocatePages (AllocateAnyPages, EfiACPIMemoryNVS, RelocationPages, &Address);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Failed to allocate pages for MailboxRelocation. %r\n", Status));
+    return 0;
+  }
+
+  ZeroMem ((VOID *)Address, EFI_PAGES_TO_SIZE (RelocationPages));
+
+  ApLoopFunc = (VOID *)((UINTN)Address + EFI_PAGE_SIZE);
+
+  CopyMem (
+    ApLoopFunc,
+    RelocationMap.RelocateApLoopFuncAddress,
+    RelocationMap.RelocateApLoopFuncSize
+    );
+
+  DEBUG ((
+    DEBUG_INFO,
+    "Ap Relocation: mailbox %llx, loop %p\n",
+    Address,
+    ApLoopFunc
+    ));
+
+  //
+  // Initialize mailbox
+  //
+  RelocatedMailBox               = (MP_WAKEUP_MAILBOX *)Address;
+  RelocatedMailBox->Command      = MpProtectedModeWakeupCommandNoop;
+  RelocatedMailBox->ApicId       = MP_CPU_PROTECTED_MODE_MAILBOX_APICID_INVALID;
+  RelocatedMailBox->WakeUpVector = 0;
+
+  //
+  // Wakup APs and have been move to the finalized run loop
+  // They will spin until guest OS wakes them
+  //
+  MpSerializeStart ();
+
+  MpSendWakeupCommand (
+    MpProtectedModeWakeupCommandWakeup,
+    (UINT64)ApLoopFunc,
+    (UINT64)RelocatedMailBox,
+    0,
+    0,
+    0
+    );
+
+  return Address;
+}
+
+/**
+  Alter the MADT when ACPI Table from QEMU is available.
+
+  @param[in]  Event     Event whose notification function is being invoked
+  @param[in]  Context   Pointer to the notification function's context
+**/
+VOID
+EFIAPI
+AlterAcpiTable (
+  IN EFI_EVENT  Event,
+  IN VOID       *Context
+  )
+{
+  EFI_ACPI_SDT_PROTOCOL                                *AcpiSdtProtocol;
+  EFI_ACPI_TABLE_PROTOCOL                              *AcpiTableProtocol;
+  EFI_STATUS                                           Status;
+  UINTN                                                Index;
+  EFI_ACPI_SDT_HEADER                                  *Table;
+  EFI_ACPI_TABLE_VERSION                               Version;
+  UINTN                                                OriginalTableKey;
+  UINTN                                                NewTableKey;
+  UINT8                                                *NewMadtTable;
+  UINTN                                                NewMadtTableLength;
+  EFI_PHYSICAL_ADDRESS                                 RelocateMailboxAddress;
+  EFI_ACPI_6_4_MULTIPROCESSOR_WAKEUP_STRUCTURE         *MadtMpWk;
+  EFI_ACPI_1_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER  *MadtHeader;
+
+  Index        = 0;
+  NewMadtTable = NULL;
+  MadtHeader   = NULL;
+
+  Status = gBS->LocateProtocol (&gEfiAcpiSdtProtocolGuid, NULL, (void **)&AcpiSdtProtocol);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Unable to locate ACPI SDT protocol.\n"));
+    return;
+  }
+
+  RelocateMailboxAddress = RelocateMailbox ();
+  if (RelocateMailboxAddress == 0) {
+    ASSERT (FALSE);
+    DEBUG ((DEBUG_ERROR, "Failed to relocate Td mailbox\n"));
+    return;
+  }
+
+  do {
+    Status = AcpiSdtProtocol->GetAcpiTable (Index, &Table, &Version, &OriginalTableKey);
+
+    if (!EFI_ERROR (Status) && (Table->Signature == EFI_ACPI_1_0_APIC_SIGNATURE)) {
+      Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (void **)&AcpiTableProtocol);
+      if (EFI_ERROR (Status)) {
+        DEBUG ((DEBUG_ERROR, "Unable to locate ACPI Table protocol.\n"));
+        break;
+      }
+
+      NewMadtTableLength = Table->Length + sizeof (EFI_ACPI_6_4_MULTIPROCESSOR_WAKEUP_STRUCTURE);
+      NewMadtTable       = AllocatePool (NewMadtTableLength);
+      if (NewMadtTable == NULL) {
+        DEBUG ((DEBUG_ERROR, "%a: OUT_OF_SOURCES error.\n", __FUNCTION__));
+        break;
+      }
+
+      CopyMem (NewMadtTable, (UINT8 *)Table, Table->Length);
+      MadtHeader                = (EFI_ACPI_1_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *)NewMadtTable;
+      MadtHeader->Header.Length = (UINT32)NewMadtTableLength;
+
+      MadtMpWk                 = (EFI_ACPI_6_4_MULTIPROCESSOR_WAKEUP_STRUCTURE *)(NewMadtTable + Table->Length);
+      MadtMpWk->Type           = EFI_ACPI_6_4_MULTIPROCESSOR_WAKEUP;
+      MadtMpWk->Length         = sizeof (EFI_ACPI_6_4_MULTIPROCESSOR_WAKEUP_STRUCTURE);
+      MadtMpWk->MailBoxVersion = 1;
+      MadtMpWk->Reserved       = 0;
+      MadtMpWk->MailBoxAddress = RelocateMailboxAddress;
+
+      Status = AcpiTableProtocol->InstallAcpiTable (AcpiTableProtocol, NewMadtTable, NewMadtTableLength, &NewTableKey);
+      if (EFI_ERROR (Status)) {
+        DEBUG ((DEBUG_ERROR, "Failed to install new MADT table. %r\n", Status));
+        break;
+      }
+
+      Status = AcpiTableProtocol->UninstallAcpiTable (AcpiTableProtocol, OriginalTableKey);
+      if (EFI_ERROR (Status)) {
+        DEBUG ((DEBUG_ERROR, "Uninstall old MADT table error.\n"));
+      }
+
+      break;
+    }
+
+    Index++;
+  } while (!EFI_ERROR (Status));
+
+  if (NewMadtTable != NULL) {
+    FreePool (NewMadtTable);
+  }
+}
diff --git a/OvmfPkg/TdxDxe/TdxAcpiTable.h b/OvmfPkg/TdxDxe/TdxAcpiTable.h
new file mode 100644
index 000000000000..6b7615dc3687
--- /dev/null
+++ b/OvmfPkg/TdxDxe/TdxAcpiTable.h
@@ -0,0 +1,60 @@
+/** @file
+
+  Copyright (c) 2008 - 2012, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef TDX_ACPI_TABLE_H_
+#define TDX_ACPI_TABLE_H_
+
+#include <PiDxe.h>
+
+#include <Protocol/AcpiTable.h>
+#include <Protocol/FirmwareVolume2.h>
+#include <Protocol/PciIo.h>
+
+#include <Library/BaseLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <IndustryStandard/IntelTdx.h>
+#include <IndustryStandard/Acpi.h>
+
+VOID
+EFIAPI
+AsmGetRelocationMap (
+  OUT MP_RELOCATION_MAP  *AddressMap
+  );
+
+/**
+  At the beginning of system boot, a 4K-aligned, 4K-size memory (Td mailbox) is
+  pre-allocated by host VMM. BSP & APs do the page accept together in that memory
+  region.
+
+  After that TDVF is designed to relocate the mailbox to a 4K-aligned, 4K-size
+  memory block which is allocated in the ACPI Nvs memory. APs are waken up and
+  spin around the relocated mailbox for further command.
+
+  @return   EFI_PHYSICAL_ADDRESS    Address of the relocated mailbox
+**/
+EFI_PHYSICAL_ADDRESS
+EFIAPI
+RelocateMailbox (
+  VOID
+  );
+
+/**
+  Alter the MADT when ACPI Table from QEMU is available.
+
+  @param[in]  Event     Event whose notification function is being invoked
+  @param[in]  Context   Pointer to the notification function's context
+**/
+VOID
+EFIAPI
+AlterAcpiTable (
+  IN EFI_EVENT  Event,
+  IN VOID       *Context
+  );
+
+#endif
diff --git a/OvmfPkg/TdxDxe/TdxDxe.c b/OvmfPkg/TdxDxe/TdxDxe.c
new file mode 100644
index 000000000000..36ef5c510771
--- /dev/null
+++ b/OvmfPkg/TdxDxe/TdxDxe.c
@@ -0,0 +1,251 @@
+/** @file
+
+  TDX Dxe driver. This driver is dispatched early in DXE, due to being list
+  in APRIORI.
+
+  This module is responsible for:
+    - Sets max logical cpus based on TDINFO
+    - Sets PCI PCDs based on resource hobs
+    - Alter MATD table to record address of Mailbox
+
+  Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiLib.h>
+#include <Library/HobLib.h>
+#include <Protocol/Cpu.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <IndustryStandard/Tdx.h>
+#include <IndustryStandard/IntelTdx.h>
+#include <Library/TdxLib.h>
+#include <TdxAcpiTable.h>
+#include <Library/MemEncryptTdxLib.h>
+
+/**
+  Location of resource hob matching type and starting address
+
+  @param[in]  Type             The type of resource hob to locate.
+
+  @param[in]  Start            The resource hob must at least begin at address.
+
+  @retval pointer to resource  Return pointer to a resource hob that matches or NULL.
+**/
+STATIC
+EFI_HOB_RESOURCE_DESCRIPTOR *
+GetResourceDescriptor (
+  EFI_RESOURCE_TYPE     Type,
+  EFI_PHYSICAL_ADDRESS  Start,
+  EFI_PHYSICAL_ADDRESS  End
+  )
+{
+  EFI_PEI_HOB_POINTERS         Hob;
+  EFI_HOB_RESOURCE_DESCRIPTOR  *ResourceDescriptor = NULL;
+
+  Hob.Raw = GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR);
+  while (Hob.Raw != NULL) {
+    DEBUG ((
+      DEBUG_INFO,
+      "%a:%d: resource type 0x%x %llx %llx\n",
+      __func__,
+      __LINE__,
+      Hob.ResourceDescriptor->ResourceType,
+      Hob.ResourceDescriptor->PhysicalStart,
+      Hob.ResourceDescriptor->ResourceLength
+      ));
+
+    if ((Hob.ResourceDescriptor->ResourceType == Type) &&
+        (Hob.ResourceDescriptor->PhysicalStart >= Start) &&
+        ((Hob.ResourceDescriptor->PhysicalStart + Hob.ResourceDescriptor->ResourceLength) < End))
+    {
+      ResourceDescriptor = Hob.ResourceDescriptor;
+      break;
+    }
+
+    Hob.Raw = GET_NEXT_HOB (Hob);
+    Hob.Raw = GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, Hob.Raw);
+  }
+
+  return ResourceDescriptor;
+}
+
+/**
+  Location of resource hob matching type and highest address below end
+
+  @param[in]  Type             The type of resource hob to locate.
+
+  @param[in]  End              The resource hob return is the closest to the End address
+
+  @retval pointer to resource  Return pointer to a resource hob that matches or NULL.
+**/
+STATIC
+EFI_HOB_RESOURCE_DESCRIPTOR *
+GetHighestResourceDescriptor (
+  EFI_RESOURCE_TYPE     Type,
+  EFI_PHYSICAL_ADDRESS  End
+  )
+{
+  EFI_PEI_HOB_POINTERS         Hob;
+  EFI_HOB_RESOURCE_DESCRIPTOR  *ResourceDescriptor = NULL;
+
+  Hob.Raw = GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR);
+  while (Hob.Raw != NULL) {
+    if ((Hob.ResourceDescriptor->ResourceType == Type) &&
+        (Hob.ResourceDescriptor->PhysicalStart < End))
+    {
+      if (!ResourceDescriptor ||
+          (ResourceDescriptor->PhysicalStart < Hob.ResourceDescriptor->PhysicalStart))
+      {
+        ResourceDescriptor = Hob.ResourceDescriptor;
+      }
+    }
+
+    Hob.Raw = GET_NEXT_HOB (Hob);
+    Hob.Raw = GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, Hob.Raw);
+  }
+
+  return ResourceDescriptor;
+}
+
+/**
+  Set the shared bit for mmio region in Tdx guest.
+
+  In Tdx guest there are 2 ways to access mmio, TdVmcall or direct access.
+  For direct access, the shared bit of the PageTableEntry should be set.
+  The mmio region information is retrieved from hob list.
+
+  @retval EFI_SUCCESS                 The shared bit is set successfully.
+  @retval EFI_UNSUPPORTED             Setting the shared bit of memory region
+                                      is not supported
+**/
+EFI_STATUS
+SetMmioSharedBit (
+  VOID
+  )
+{
+  EFI_PEI_HOB_POINTERS  Hob;
+
+  Hob.Raw = (UINT8 *)GetHobList ();
+
+  //
+  // 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)
+       && (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_MEMORY_MAPPED_IO))
+    {
+      MemEncryptTdxSetPageSharedBit (
+        0,
+        Hob.ResourceDescriptor->PhysicalStart,
+        EFI_SIZE_TO_PAGES (Hob.ResourceDescriptor->ResourceLength)
+        );
+    }
+
+    Hob.Raw = GET_NEXT_HOB (Hob);
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+TdxDxeEntryPoint (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS                   Status;
+  RETURN_STATUS                PcdStatus;
+  EFI_HOB_RESOURCE_DESCRIPTOR  *Res          = NULL;
+  EFI_HOB_RESOURCE_DESCRIPTOR  *MemRes       = NULL;
+  EFI_HOB_PLATFORM_INFO        *PlatformInfo = NULL;
+  EFI_HOB_GUID_TYPE            *GuidHob;
+  UINT32                       CpuMaxLogicalProcessorNumber;
+  TD_RETURN_DATA               TdReturnData;
+  EFI_EVENT                    QemuAcpiTableEvent;
+  void                         *Registration;
+
+  GuidHob = GetFirstGuidHob (&gUefiOvmfPkgTdxPlatformGuid);
+
+  if (GuidHob == NULL) {
+    return EFI_UNSUPPORTED;
+  }
+
+  SetMmioSharedBit ();
+
+  PlatformInfo = (EFI_HOB_PLATFORM_INFO *)GET_GUID_HOB_DATA (GuidHob);
+
+  //
+  // Call TDINFO to get actual number of cpus in domain
+  //
+  Status = TdCall (TDCALL_TDINFO, 0, 0, 0, &TdReturnData);
+  ASSERT (Status == EFI_SUCCESS);
+
+  CpuMaxLogicalProcessorNumber = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
+
+  //
+  // Adjust PcdCpuMaxLogicalProcessorNumber, if needed. If firmware is configured for
+  // more than number of reported cpus, update.
+  //
+  if (CpuMaxLogicalProcessorNumber > TdReturnData.TdInfo.NumVcpus) {
+    PcdStatus = PcdSet32S (PcdCpuMaxLogicalProcessorNumber, TdReturnData.TdInfo.NumVcpus);
+    ASSERT_RETURN_ERROR (PcdStatus);
+  }
+
+  //
+  // Register for protocol notifications to call the AlterAcpiTable(),
+  // the protocol will be installed in AcpiPlatformDxe when the ACPI
+  // table provided by Qemu is ready.
+  //
+  Status = gBS->CreateEvent (
+                  EVT_NOTIFY_SIGNAL,
+                  TPL_CALLBACK,
+                  AlterAcpiTable,
+                  NULL,
+                  &QemuAcpiTableEvent
+                  );
+
+  Status = gBS->RegisterProtocolNotify (
+                  &gQemuAcpiTableNotifyProtocolGuid,
+                  QemuAcpiTableEvent,
+                  &Registration
+                  );
+
+  #define INIT_PCDSET(NAME, RES)  do {\
+  PcdStatus = PcdSet64S (NAME##Base, (RES)->PhysicalStart); \
+  ASSERT_RETURN_ERROR (PcdStatus); \
+  PcdStatus = PcdSet64S (NAME##Size, (RES)->ResourceLength); \
+  ASSERT_RETURN_ERROR (PcdStatus); \
+} while(0)
+
+  if (PlatformInfo) {
+    PcdSet16S (PcdOvmfHostBridgePciDevId, PlatformInfo->HostBridgePciDevId);
+
+    if ((Res = GetResourceDescriptor (EFI_RESOURCE_MEMORY_MAPPED_IO, (EFI_PHYSICAL_ADDRESS)0x100000000, (EFI_PHYSICAL_ADDRESS)-1)) != NULL) {
+      INIT_PCDSET (PcdPciMmio64, Res);
+    }
+
+    if ((Res = GetResourceDescriptor (EFI_RESOURCE_IO, 0, 0x10001)) != NULL) {
+      INIT_PCDSET (PcdPciIo, Res);
+    }
+
+    //
+    // To find low mmio, first find top of low memory, and then search for io space.
+    //
+    if ((MemRes = GetHighestResourceDescriptor (EFI_RESOURCE_SYSTEM_MEMORY, 0xffc00000)) != NULL) {
+      if ((Res = GetResourceDescriptor (EFI_RESOURCE_MEMORY_MAPPED_IO, MemRes->PhysicalStart, 0x100000000)) != NULL) {
+        INIT_PCDSET (PcdPciMmio32, Res);
+      }
+    }
+  }
+
+  return EFI_SUCCESS;
+}
diff --git a/OvmfPkg/TdxDxe/TdxDxe.inf b/OvmfPkg/TdxDxe/TdxDxe.inf
new file mode 100644
index 000000000000..077769bcf70c
--- /dev/null
+++ b/OvmfPkg/TdxDxe/TdxDxe.inf
@@ -0,0 +1,64 @@
+#/** @file
+#
+#  Driver clears the encryption attribute from MMIO regions when TDX is enabled
+#
+#  Copyright (c) 2017, AMD Inc. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#**/
+
+[Defines]
+  INF_VERSION                    = 1.25
+  BASE_NAME                      = TdxDxe
+  FILE_GUID                      = E750224E-7BCE-40AF-B5BB-47E3611EB5C2
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = TdxDxeEntryPoint
+
+[Sources]
+  TdxDxe.c
+  TdxAcpiTable.c
+  X64/ApRunLoop.nasm
+
+[Packages]
+  MdeModulePkg/MdeModulePkg.dec
+  MdePkg/MdePkg.dec
+  UefiCpuPkg/UefiCpuPkg.dec
+  OvmfPkg/OvmfPkg.dec
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  DebugLib
+  DxeServicesTableLib
+  MemoryAllocationLib
+  PcdLib
+  UefiDriverEntryPoint
+  TdxLib
+  HobLib
+  TdxMailboxLib
+  MemEncryptTdxLib
+
+[Depex]
+  TRUE
+
+[Guids]
+  gUefiOvmfPkgTdxPlatformGuid                      ## CONSUMES
+
+[Protocols]
+  gQemuAcpiTableNotifyProtocolGuid                 ## CONSUMES
+  gEfiAcpiSdtProtocolGuid                          ## CONSUMES
+  gEfiAcpiTableProtocolGuid                        ## CONSUMES
+
+[Pcd]
+  gUefiOvmfPkgTokenSpaceGuid.PcdPciIoBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdPciIoSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdPciMmio32Base
+  gUefiOvmfPkgTokenSpaceGuid.PcdPciMmio32Size
+  gUefiOvmfPkgTokenSpaceGuid.PcdPciMmio64Base
+  gUefiOvmfPkgTokenSpaceGuid.PcdPciMmio64Size
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfHostBridgePciDevId
+  gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber
+  gUefiCpuPkgTokenSpaceGuid.PcdCpuLocalApicBaseAddress
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFdBaseAddress
diff --git a/OvmfPkg/TdxDxe/X64/ApRunLoop.nasm b/OvmfPkg/TdxDxe/X64/ApRunLoop.nasm
new file mode 100644
index 000000000000..0aad239348b0
--- /dev/null
+++ b/OvmfPkg/TdxDxe/X64/ApRunLoop.nasm
@@ -0,0 +1,87 @@
+;------------------------------------------------------------------------------ ;
+; Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+; Module Name:
+;
+;   ApRunLoop.nasm
+;
+; Abstract:
+;
+;   This is the assembly code for run loop for APs in the guest TD
+;
+;-------------------------------------------------------------------------------
+
+%include "TdxCommondefs.inc"
+
+DEFAULT REL
+
+SECTION .text
+
+BITS 64
+
+%define TDVMCALL_EXPOSE_REGS_MASK       0xffec
+%define TDVMCALL                        0x0
+%define EXIT_REASON_CPUID               0xa
+
+%macro  tdcall  0
+  db  0x66, 0x0f, 0x01, 0xcc
+%endmacro
+
+;
+; Relocated Ap Mailbox loop
+;
+; @param[in]  RBX:  Relocated mailbox address
+; @param[in]  RBP:  vCpuId
+;
+; @return     None  This routine does not return
+;
+global ASM_PFX(AsmRelocateApMailBoxLoop)
+ASM_PFX(AsmRelocateApMailBoxLoop):
+AsmRelocateApMailBoxLoopStart:
+
+    mov         rax, TDVMCALL
+    mov         rcx, TDVMCALL_EXPOSE_REGS_MASK
+    mov         r11, EXIT_REASON_CPUID
+    mov         r12, 0xb
+    tdcall
+    test        rax, rax
+    jnz         Panic
+    mov         r8, r15
+
+MailBoxLoop:
+    ; Spin until command set
+    cmp        dword [rbx + CommandOffset], MpProtectedModeWakeupCommandNoop
+    je         MailBoxLoop
+    ; Determine if this is a broadcast or directly for my apic-id, if not, ignore
+    cmp        dword [rbx + ApicidOffset], MailboxApicidBroadcast
+    je         MailBoxProcessCommand
+    cmp        dword [rbx + ApicidOffset], r8d
+    jne        MailBoxLoop
+MailBoxProcessCommand:
+    cmp        dword [rbx + CommandOffset], MpProtectedModeWakeupCommandWakeup
+    je         MailBoxWakeUp
+    cmp        dword [rbx + CommandOffset], MpProtectedModeWakeupCommandSleep
+    je         MailBoxSleep
+    ; Don't support this command, so ignore
+    jmp        MailBoxLoop
+MailBoxWakeUp:
+    mov       rax, [rbx + WakeupVectorOffset]
+    jmp       rax
+MailBoxSleep:
+    jmp       $
+Panic:
+    ud2
+BITS 64
+AsmRelocateApMailBoxLoopEnd:
+
+;-------------------------------------------------------------------------------------
+;  AsmGetRelocationMap (&RelocationMap);
+;-------------------------------------------------------------------------------------
+global ASM_PFX(AsmGetRelocationMap)
+ASM_PFX(AsmGetRelocationMap):
+    lea        rax, [ASM_PFX(AsmRelocateApMailBoxLoopStart)]
+    mov        qword [rcx], rax
+    mov        qword [rcx +  8h], AsmRelocateApMailBoxLoopEnd - AsmRelocateApMailBoxLoopStart
+    ret
+
-- 
2.29.2.windows.2


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

* [PATCH V4 25/31] OvmfPkg/BaseMemEncryptTdxLib: Add TDX helper library
  2021-12-13 12:56 [PATCH V4 00/31] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (23 preceding siblings ...)
  2021-12-13 12:56 ` [PATCH V4 24/31] OvmfPkg: Add TdxDxe driver Min Xu
@ 2021-12-13 12:56 ` Min Xu
  2021-12-15  9:16   ` Gerd Hoffmann
  2021-12-13 12:56 ` [PATCH V4 26/31] OvmfPkg/QemuFwCfgLib: Support Tdx in QemuFwCfgDxe Min Xu
                   ` (5 subsequent siblings)
  30 siblings, 1 reply; 68+ messages in thread
From: Min Xu @ 2021-12-13 12:56 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

Add Intel Tdx helper library. The library provides the routines to:
-  set or clear Shared bit for a given memory region.
-  query whether TDX is enabled.

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>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/Include/Library/MemEncryptTdxLib.h    |  81 ++
 .../BaseMemEncryptTdxLib.inf                  |  44 +
 .../BaseMemEncryptTdxLibNull.inf              |  35 +
 .../BaseMemoryEncryptionNull.c                |  90 ++
 .../BaseMemEncryptTdxLib/MemoryEncryption.c   | 941 ++++++++++++++++++
 .../BaseMemEncryptTdxLib/VirtualMemory.h      | 181 ++++
 OvmfPkg/OvmfPkg.dec                           |   4 +
 OvmfPkg/OvmfPkgIa32.dsc                       |   1 +
 OvmfPkg/OvmfPkgIa32X64.dsc                    |   1 +
 9 files changed, 1378 insertions(+)
 create mode 100644 OvmfPkg/Include/Library/MemEncryptTdxLib.h
 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

diff --git a/OvmfPkg/Include/Library/MemEncryptTdxLib.h b/OvmfPkg/Include/Library/MemEncryptTdxLib.h
new file mode 100644
index 000000000000..2350dd47bc30
--- /dev/null
+++ b/OvmfPkg/Include/Library/MemEncryptTdxLib.h
@@ -0,0 +1,81 @@
+/** @file
+
+  Define Memory Encrypted Virtualization base library helper function
+
+  Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef MEM_ENCRYPT_TDX_LIB_H_
+#define MEM_ENCRYPT_TDX_LIB_H_
+
+#include <Base.h>
+
+/**
+  Returns boolean to indicate whether to indicate which, if any, memory encryption is enabled
+
+  @param[in]  Type          Bitmask of encryption technologies to check is enabled
+
+  @retval TRUE              The encryption type(s) are enabled
+  @retval FALSE             The encryption type(s) are not enabled
+**/
+BOOLEAN
+EFIAPI
+MemEncryptTdxIsEnabled (
+  VOID
+  );
+
+/**
+  This function clears memory encryption bit for the memory region specified by
+  BaseAddress and NumPages from the current page table context.
+
+  @param[in]  Cr3BaseAddress          Cr3 Base Address (if zero then use
+                                      current CR3)
+  @param[in]  BaseAddress             The physical address that is the start
+                                      address of a memory region.
+  @param[in]  NumPages                The number of pages from start memory
+                                      region.
+
+  @retval RETURN_SUCCESS              The attributes were cleared for the
+                                      memory region.
+  @retval RETURN_INVALID_PARAMETER    Number of pages is zero.
+  @retval RETURN_UNSUPPORTED          Clearing the memory encryption attribute
+                                      is not supported
+**/
+RETURN_STATUS
+EFIAPI
+MemEncryptTdxSetPageSharedBit (
+  IN PHYSICAL_ADDRESS  Cr3BaseAddress,
+  IN PHYSICAL_ADDRESS  BaseAddress,
+  IN UINTN             NumPages
+  );
+
+/**
+  This function sets memory encryption bit for the memory region specified by
+  BaseAddress and NumPages from the current page table context.
+
+  @param[in]  Cr3BaseAddress          Cr3 Base Address (if zero then use
+                                      current CR3)
+  @param[in]  BaseAddress             The physical address that is the start
+                                      address of a memory region.
+  @param[in]  NumPages                The number of pages from start memory
+                                      region.
+
+  @retval RETURN_SUCCESS              The attributes were set for the memory
+                                      region.
+  @retval RETURN_INVALID_PARAMETER    Number of pages is zero.
+  @retval RETURN_UNSUPPORTED          Setting the memory encryption attribute
+                                      is not supported
+**/
+RETURN_STATUS
+EFIAPI
+MemEncryptTdxClearPageSharedBit (
+  IN PHYSICAL_ADDRESS  Cr3BaseAddress,
+  IN PHYSICAL_ADDRESS  BaseAddress,
+  IN UINTN             NumPages
+  );
+
+#endif // _MEM_ENCRYPT_TDX_LIB_H_
diff --git a/OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLib.inf b/OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLib.inf
new file mode 100644
index 000000000000..a8abfec12fa3
--- /dev/null
+++ b/OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLib.inf
@@ -0,0 +1,44 @@
+## @file
+#  Library for TDX Memory Encryption
+#
+#  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+  INF_VERSION                    = 1.25
+  BASE_NAME                      = MemEncryptTdxLib
+  FILE_GUID                      = 7E6651B2-B775-4593-A410-FC05B8C61993
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = MemEncryptTdxLib|PEIM DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_DRIVER
+
+#
+# The following information is for reference only and not required by the build
+# tools.
+#
+# VALID_ARCHITECTURES           = X64
+#
+
+[Packages]
+  MdeModulePkg/MdeModulePkg.dec
+  MdePkg/MdePkg.dec
+  OvmfPkg/OvmfPkg.dec
+
+[Sources]
+  VirtualMemory.h
+  MemoryEncryption.c
+
+[LibraryClasses]
+  BaseLib
+  CacheMaintenanceLib
+  CpuLib
+  DebugLib
+  MemoryAllocationLib
+  PcdLib
+  TdxLib
+
+[Pcd]
+  gEfiMdePkgTokenSpaceGuid.PcdConfidentialComputingGuestAttr
diff --git a/OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLibNull.inf b/OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLibNull.inf
new file mode 100644
index 000000000000..a050edb5b734
--- /dev/null
+++ b/OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLibNull.inf
@@ -0,0 +1,35 @@
+## @file
+#  Library for Memory Encryption
+#
+# Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2017 Advanced Micro Devices. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+  INF_VERSION                    = 1.25
+  BASE_NAME                      = MemEncryptTdxLibNull
+  FILE_GUID                      = 3C69C4CA-DE46-44D7-8AA5-6EE51A4E3EA7
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = MemEncryptTdxLib|PEIM DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_DRIVER
+
+#
+# The following information is for reference only and not required by the build
+# tools.
+#
+# VALID_ARCHITECTURES           = X64 IA32
+#
+
+[Packages]
+  MdePkg/MdePkg.dec
+  OvmfPkg/OvmfPkg.dec
+
+[Sources]
+  BaseMemoryEncryptionNull.c
+
+[LibraryClasses]
+  BaseLib
diff --git a/OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemoryEncryptionNull.c b/OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemoryEncryptionNull.c
new file mode 100644
index 000000000000..137d4674d499
--- /dev/null
+++ b/OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemoryEncryptionNull.c
@@ -0,0 +1,90 @@
+/** @file
+
+  Virtual Memory Management Services to set or clear the memory encryption
+
+  Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  Code is derived from MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
+
+**/
+
+#include <Uefi.h>
+#include <Uefi/UefiBaseType.h>
+#include <Library/BaseLib.h>
+#include <Library/MemEncryptTdxLib.h>
+
+/**
+  Returns boolean to indicate whether to indicate which, if any, memory encryption is enabled
+
+  @param[in]  Type          Bitmask of encryption technologies to check is enabled
+
+  @retval TRUE              The encryption type(s) are enabled
+  @retval FALSE             The encryption type(s) are not enabled
+**/
+BOOLEAN
+EFIAPI
+MemEncryptTdxIsEnabled (
+  VOID
+  )
+{
+  return FALSE;
+}
+
+/**
+  This function clears memory encryption bit for the memory region specified by
+  BaseAddress and NumPages from the current page table context.
+
+  @param[in]  Cr3BaseAddress          Cr3 Base Address (if zero then use
+                                      current CR3)
+  @param[in]  BaseAddress             The physical address that is the start
+                                      address of a memory region.
+  @param[in]  NumPages                The number of pages from start memory
+                                      region.
+
+  @retval RETURN_SUCCESS              The attributes were cleared for the
+                                      memory region.
+  @retval RETURN_INVALID_PARAMETER    Number of pages is zero.
+  @retval RETURN_UNSUPPORTED          Clearing the memory encryption attribute
+                                      is not supported
+**/
+RETURN_STATUS
+EFIAPI
+MemEncryptTdxSetPageSharedBit (
+  IN PHYSICAL_ADDRESS  Cr3BaseAddress,
+  IN PHYSICAL_ADDRESS  BaseAddress,
+  IN UINTN             NumPages
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  This function sets memory encryption bit for the memory region specified by
+  BaseAddress and NumPages from the current page table context.
+
+  @param[in]  Cr3BaseAddress          Cr3 Base Address (if zero then use
+                                      current CR3)
+  @param[in]  BaseAddress             The physical address that is the start
+                                      address of a memory region.
+  @param[in]  NumPages                The number of pages from start memory
+                                      region.
+
+  @retval RETURN_SUCCESS              The attributes were set for the memory
+                                      region.
+  @retval RETURN_INVALID_PARAMETER    Number of pages is zero.
+  @retval RETURN_UNSUPPORTED          Setting the memory encryption attribute
+                                      is not supported
+**/
+RETURN_STATUS
+EFIAPI
+MemEncryptTdxClearPageSharedBit (
+  IN PHYSICAL_ADDRESS  Cr3BaseAddress,
+  IN PHYSICAL_ADDRESS  BaseAddress,
+  IN UINTN             NumPages
+  )
+{
+  return EFI_UNSUPPORTED;
+}
diff --git a/OvmfPkg/Library/BaseMemEncryptTdxLib/MemoryEncryption.c b/OvmfPkg/Library/BaseMemEncryptTdxLib/MemoryEncryption.c
new file mode 100644
index 000000000000..831f5d0814c6
--- /dev/null
+++ b/OvmfPkg/Library/BaseMemEncryptTdxLib/MemoryEncryption.c
@@ -0,0 +1,941 @@
+/** @file
+
+  Virtual Memory Management Services to set or clear the memory encryption
+
+  Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  Code is derived from MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
+
+**/
+
+#include <Uefi.h>
+#include <Uefi/UefiBaseType.h>
+#include <Library/CpuLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemEncryptTdxLib.h>
+#include "VirtualMemory.h"
+#include <IndustryStandard/Tdx.h>
+#include <Library/TdxLib.h>
+#include <ConfidentialComputingGuestAttr.h>
+
+typedef enum {
+  SetSharedBit,
+  ClearSharedBit
+} TDX_PAGETABLE_MODE;
+
+STATIC PAGE_TABLE_POOL  *mPageTablePool = NULL;
+
+/**
+  Returns boolean to indicate whether to indicate which, if any, memory encryption is enabled
+
+  @param[in]  Type          Bitmask of encryption technologies to check is enabled
+
+  @retval TRUE              The encryption type(s) are enabled
+  @retval FALSE             The encryption type(s) are not enabled
+**/
+BOOLEAN
+EFIAPI
+MemEncryptTdxIsEnabled (
+  VOID
+  )
+{
+  return CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr));
+}
+
+/**
+  Get the memory encryption mask
+
+  @param[out]      EncryptionMask        contains the pte mask.
+
+**/
+STATIC
+UINT64
+GetMemEncryptionAddressMask (
+  VOID
+  )
+{
+  return TdSharedPageMask ();
+}
+
+/**
+  Initialize a buffer pool for page table use only.
+
+  To reduce the potential split operation on page table, the pages reserved for
+  page table should be allocated in the times of PAGE_TABLE_POOL_UNIT_PAGES and
+  at the boundary of PAGE_TABLE_POOL_ALIGNMENT. So the page pool is always
+  initialized with number of pages greater than or equal to the given
+  PoolPages.
+
+  Once the pages in the pool are used up, this method should be called again to
+  reserve at least another PAGE_TABLE_POOL_UNIT_PAGES. Usually this won't
+  happen often in practice.
+
+  @param[in] PoolPages      The least page number of the pool to be created.
+
+  @retval TRUE    The pool is initialized successfully.
+  @retval FALSE   The memory is out of resource.
+**/
+STATIC
+BOOLEAN
+InitializePageTablePool (
+  IN  UINTN  PoolPages
+  )
+{
+  VOID  *Buffer;
+
+  //
+  // Always reserve at least PAGE_TABLE_POOL_UNIT_PAGES, including one page for
+  // header.
+  //
+  PoolPages += 1;   // Add one page for header.
+  PoolPages  = ((PoolPages - 1) / PAGE_TABLE_POOL_UNIT_PAGES + 1) *
+               PAGE_TABLE_POOL_UNIT_PAGES;
+  Buffer = AllocateAlignedPages (PoolPages, PAGE_TABLE_POOL_ALIGNMENT);
+  if (Buffer == NULL) {
+    DEBUG ((DEBUG_ERROR, "ERROR: Out of aligned pages\r\n"));
+    return FALSE;
+  }
+
+  //
+  // Link all pools into a list for easier track later.
+  //
+  if (mPageTablePool == NULL) {
+    mPageTablePool           = Buffer;
+    mPageTablePool->NextPool = mPageTablePool;
+  } else {
+    ((PAGE_TABLE_POOL *)Buffer)->NextPool = mPageTablePool->NextPool;
+    mPageTablePool->NextPool              = Buffer;
+    mPageTablePool                        = Buffer;
+  }
+
+  //
+  // Reserve one page for pool header.
+  //
+  mPageTablePool->FreePages = PoolPages - 1;
+  mPageTablePool->Offset    = EFI_PAGES_TO_SIZE (1);
+
+  return TRUE;
+}
+
+/**
+  This API provides a way to allocate memory for page table.
+
+  This API can be called more than once to allocate memory for page tables.
+
+  Allocates the number of 4KB pages and returns a pointer to the allocated
+  buffer. The buffer returned is aligned on a 4KB boundary.
+
+  If Pages is 0, then NULL is returned.
+  If there is not enough memory remaining to satisfy the request, then NULL is
+  returned.
+
+  @param  Pages                 The number of 4 KB pages to allocate.
+
+  @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+STATIC
+VOID *
+EFIAPI
+AllocatePageTableMemory (
+  IN UINTN  Pages
+  )
+{
+  VOID  *Buffer;
+
+  if (Pages == 0) {
+    return NULL;
+  }
+
+  //
+  // Renew the pool if necessary.
+  //
+  if ((mPageTablePool == NULL) ||
+      (Pages > mPageTablePool->FreePages))
+  {
+    if (!InitializePageTablePool (Pages)) {
+      return NULL;
+    }
+  }
+
+  Buffer = (UINT8 *)mPageTablePool + mPageTablePool->Offset;
+
+  mPageTablePool->Offset    += EFI_PAGES_TO_SIZE (Pages);
+  mPageTablePool->FreePages -= Pages;
+
+  DEBUG ((
+    DEBUG_VERBOSE,
+    "%a:%a: Buffer=0x%Lx Pages=%ld\n",
+    gEfiCallerBaseName,
+    __FUNCTION__,
+    Buffer,
+    Pages
+    ));
+
+  return Buffer;
+}
+
+/**
+  Split 2M page to 4K.
+
+  @param[in]      PhysicalAddress       Start physical address the 2M page
+                                        covered.
+  @param[in, out] PageEntry2M           Pointer to 2M page entry.
+  @param[in]      StackBase             Stack base address.
+  @param[in]      StackSize             Stack size.
+
+**/
+STATIC
+VOID
+Split2MPageTo4K (
+  IN        PHYSICAL_ADDRESS  PhysicalAddress,
+  IN  OUT   UINT64            *PageEntry2M,
+  IN        PHYSICAL_ADDRESS  StackBase,
+  IN        UINTN             StackSize,
+  IN        UINT64            AddressEncMask
+  )
+{
+  PHYSICAL_ADDRESS     PhysicalAddress4K;
+  UINTN                IndexOfPageTableEntries;
+  PAGE_TABLE_4K_ENTRY  *PageTableEntry, *PageTableEntry1;
+
+  PageTableEntry = AllocatePageTableMemory (1);
+
+  PageTableEntry1 = PageTableEntry;
+
+  if (PageTableEntry == NULL) {
+    ASSERT (FALSE);
+    return;
+  }
+
+  PhysicalAddress4K = PhysicalAddress;
+  for (IndexOfPageTableEntries = 0;
+       IndexOfPageTableEntries < 512;
+       (IndexOfPageTableEntries++,
+        PageTableEntry++,
+        PhysicalAddress4K += SIZE_4KB))
+  {
+    //
+    // Fill in the Page Table entries
+    //
+    PageTableEntry->Uint64         = (UINT64)PhysicalAddress4K | AddressEncMask;
+    PageTableEntry->Bits.ReadWrite = 1;
+    PageTableEntry->Bits.Present   = 1;
+    if ((PhysicalAddress4K >= StackBase) &&
+        (PhysicalAddress4K < StackBase + StackSize))
+    {
+      //
+      // Set Nx bit for stack.
+      //
+      PageTableEntry->Bits.Nx = 1;
+    }
+  }
+
+  //
+  // Fill in 2M page entry.
+  //
+  *PageEntry2M = ((UINT64)(UINTN)PageTableEntry1 |
+                  IA32_PG_P | IA32_PG_RW | AddressEncMask);
+}
+
+/**
+  Set one page of page table pool memory to be read-only.
+
+  @param[in] PageTableBase    Base address of page table (CR3).
+  @param[in] Address          Start address of a page to be set as read-only.
+  @param[in] Level4Paging     Level 4 paging flag.
+
+**/
+STATIC
+VOID
+SetPageTablePoolReadOnly (
+  IN  UINTN                 PageTableBase,
+  IN  EFI_PHYSICAL_ADDRESS  Address,
+  IN  BOOLEAN               Level4Paging
+  )
+{
+  UINTN                 Index;
+  UINTN                 EntryIndex;
+  UINT64                AddressEncMask;
+  UINT64                ActiveAddressEncMask;
+  EFI_PHYSICAL_ADDRESS  PhysicalAddress;
+  UINT64                *PageTable;
+  UINT64                *NewPageTable;
+  UINT64                PageAttr;
+  UINT64                LevelSize[5];
+  UINT64                LevelMask[5];
+  UINTN                 LevelShift[5];
+  UINTN                 Level;
+  UINT64                PoolUnitSize;
+
+  if (PageTableBase == 0) {
+    ASSERT (FALSE);
+    return;
+  }
+
+  //
+  // Since the page table is always from page table pool, which is always
+  // located at the boundary of PcdPageTablePoolAlignment, we just need to
+  // set the whole pool unit to be read-only.
+  //
+  Address = Address & PAGE_TABLE_POOL_ALIGN_MASK;
+
+  LevelShift[1] = PAGING_L1_ADDRESS_SHIFT;
+  LevelShift[2] = PAGING_L2_ADDRESS_SHIFT;
+  LevelShift[3] = PAGING_L3_ADDRESS_SHIFT;
+  LevelShift[4] = PAGING_L4_ADDRESS_SHIFT;
+
+  LevelMask[1] = PAGING_4K_ADDRESS_MASK_64;
+  LevelMask[2] = PAGING_2M_ADDRESS_MASK_64;
+  LevelMask[3] = PAGING_1G_ADDRESS_MASK_64;
+  LevelMask[4] = PAGING_1G_ADDRESS_MASK_64;
+
+  LevelSize[1] = SIZE_4KB;
+  LevelSize[2] = SIZE_2MB;
+  LevelSize[3] = SIZE_1GB;
+  LevelSize[4] = SIZE_512GB;
+
+  AddressEncMask = GetMemEncryptionAddressMask () &
+                   PAGING_1G_ADDRESS_MASK_64;
+  PageTable    = (UINT64 *)(UINTN)PageTableBase;
+  PoolUnitSize = PAGE_TABLE_POOL_UNIT_SIZE;
+
+  for (Level = (Level4Paging) ? 4 : 3; Level > 0; --Level) {
+    Index  = ((UINTN)RShiftU64 (Address, LevelShift[Level]));
+    Index &= PAGING_PAE_INDEX_MASK;
+
+    PageAttr             = PageTable[Index];
+    ActiveAddressEncMask = GetMemEncryptionAddressMask () & PageAttr;
+
+    if ((PageAttr & IA32_PG_PS) == 0) {
+      //
+      // Go to next level of table.
+      //
+      PageTable = (UINT64 *)(UINTN)(PageAttr & ~AddressEncMask &
+                                    PAGING_4K_ADDRESS_MASK_64);
+      continue;
+    }
+
+    if (PoolUnitSize >= LevelSize[Level]) {
+      //
+      // Clear R/W bit if current page granularity is not larger than pool unit
+      // size.
+      //
+      if ((PageAttr & IA32_PG_RW) != 0) {
+        while (PoolUnitSize > 0) {
+          //
+          // PAGE_TABLE_POOL_UNIT_SIZE and PAGE_TABLE_POOL_ALIGNMENT are fit in
+          // one page (2MB). Then we don't need to update attributes for pages
+          // crossing page directory. ASSERT below is for that purpose.
+          //
+          ASSERT (Index < EFI_PAGE_SIZE/sizeof (UINT64));
+
+          PageTable[Index] &= ~(UINT64)IA32_PG_RW;
+          PoolUnitSize     -= LevelSize[Level];
+
+          ++Index;
+        }
+      }
+
+      break;
+    } else {
+      //
+      // The smaller granularity of page must be needed.
+      //
+      ASSERT (Level > 1);
+
+      NewPageTable = AllocatePageTableMemory (1);
+      if (NewPageTable == NULL) {
+        ASSERT (FALSE);
+        return;
+      }
+
+      PhysicalAddress = PageAttr & LevelMask[Level];
+      for (EntryIndex = 0;
+           EntryIndex < EFI_PAGE_SIZE/sizeof (UINT64);
+           ++EntryIndex)
+      {
+        NewPageTable[EntryIndex] = PhysicalAddress  | ActiveAddressEncMask |
+                                   IA32_PG_P | IA32_PG_RW;
+        if (Level > 2) {
+          NewPageTable[EntryIndex] |= IA32_PG_PS;
+        }
+
+        PhysicalAddress += LevelSize[Level - 1];
+      }
+
+      PageTable[Index] = (UINT64)(UINTN)NewPageTable | ActiveAddressEncMask |
+                         IA32_PG_P | IA32_PG_RW;
+      PageTable = NewPageTable;
+    }
+  }
+}
+
+/**
+  Prevent the memory pages used for page table from been overwritten.
+
+  @param[in] PageTableBase    Base address of page table (CR3).
+  @param[in] Level4Paging     Level 4 paging flag.
+
+**/
+STATIC
+VOID
+EnablePageTableProtection (
+  IN  UINTN    PageTableBase,
+  IN  BOOLEAN  Level4Paging
+  )
+{
+  PAGE_TABLE_POOL       *HeadPool;
+  PAGE_TABLE_POOL       *Pool;
+  UINT64                PoolSize;
+  EFI_PHYSICAL_ADDRESS  Address;
+
+  if (mPageTablePool == NULL) {
+    return;
+  }
+
+  //
+  // SetPageTablePoolReadOnly might update mPageTablePool. It's safer to
+  // remember original one in advance.
+  //
+  HeadPool = mPageTablePool;
+  Pool     = HeadPool;
+  do {
+    Address  = (EFI_PHYSICAL_ADDRESS)(UINTN)Pool;
+    PoolSize = Pool->Offset + EFI_PAGES_TO_SIZE (Pool->FreePages);
+
+    //
+    // The size of one pool must be multiple of PAGE_TABLE_POOL_UNIT_SIZE,
+    // which is one of page size of the processor (2MB by default). Let's apply
+    // the protection to them one by one.
+    //
+    while (PoolSize > 0) {
+      SetPageTablePoolReadOnly (PageTableBase, Address, Level4Paging);
+      Address  += PAGE_TABLE_POOL_UNIT_SIZE;
+      PoolSize -= PAGE_TABLE_POOL_UNIT_SIZE;
+    }
+
+    Pool = Pool->NextPool;
+  } while (Pool != HeadPool);
+}
+
+/**
+  Split 1G page to 2M.
+
+  @param[in]      PhysicalAddress       Start physical address the 1G page
+                                        covered.
+  @param[in, out] PageEntry1G           Pointer to 1G page entry.
+  @param[in]      StackBase             Stack base address.
+  @param[in]      StackSize             Stack size.
+
+**/
+STATIC
+VOID
+Split1GPageTo2M (
+  IN          PHYSICAL_ADDRESS  PhysicalAddress,
+  IN  OUT     UINT64            *PageEntry1G,
+  IN          PHYSICAL_ADDRESS  StackBase,
+  IN          UINTN             StackSize
+  )
+{
+  PHYSICAL_ADDRESS  PhysicalAddress2M;
+  UINTN             IndexOfPageDirectoryEntries;
+  PAGE_TABLE_ENTRY  *PageDirectoryEntry;
+  UINT64            AddressEncMask;
+  UINT64            ActiveAddressEncMask;
+
+  PageDirectoryEntry = AllocatePageTableMemory (1);
+  if (PageDirectoryEntry == NULL) {
+    return;
+  }
+
+  AddressEncMask = GetMemEncryptionAddressMask ();
+  ASSERT (PageDirectoryEntry != NULL);
+
+  ActiveAddressEncMask = *PageEntry1G & AddressEncMask;
+  //
+  // Fill in 1G page entry.
+  //
+  *PageEntry1G = ((UINT64)(UINTN)PageDirectoryEntry |
+                  IA32_PG_P | IA32_PG_RW | ActiveAddressEncMask);
+
+  PhysicalAddress2M = PhysicalAddress;
+  for (IndexOfPageDirectoryEntries = 0;
+       IndexOfPageDirectoryEntries < 512;
+       (IndexOfPageDirectoryEntries++,
+        PageDirectoryEntry++,
+        PhysicalAddress2M += SIZE_2MB))
+  {
+    if ((PhysicalAddress2M < StackBase + StackSize) &&
+        ((PhysicalAddress2M + SIZE_2MB) > StackBase))
+    {
+      //
+      // Need to split this 2M page that covers stack range.
+      //
+      Split2MPageTo4K (
+        PhysicalAddress2M,
+        (UINT64 *)PageDirectoryEntry,
+        StackBase,
+        StackSize,
+        ActiveAddressEncMask
+        );
+    } else {
+      //
+      // Fill in the Page Directory entries
+      //
+      PageDirectoryEntry->Uint64         = (UINT64)PhysicalAddress2M | ActiveAddressEncMask;
+      PageDirectoryEntry->Bits.ReadWrite = 1;
+      PageDirectoryEntry->Bits.Present   = 1;
+      PageDirectoryEntry->Bits.MustBe1   = 1;
+    }
+  }
+}
+
+/**
+  Set or Clear the memory encryption bit
+
+  @param[in]      PagetablePoint        Page table entry pointer (PTE).
+  @param[in]      Mode                  Set or Clear encryption bit
+
+**/
+STATIC VOID
+SetOrClearSharedBit (
+  IN   OUT     UINT64              *PageTablePointer,
+  IN           TDX_PAGETABLE_MODE  Mode,
+  IN           PHYSICAL_ADDRESS    PhysicalAddress,
+  IN           UINT64              Length
+  )
+{
+  UINT64  AddressEncMask;
+  UINT64  Status;
+
+  AddressEncMask = GetMemEncryptionAddressMask ();
+
+  //
+  // Set or clear page table entry. Also, set shared bit in physical address, before calling MapGPA
+  //
+  if (Mode == SetSharedBit) {
+    *PageTablePointer |= AddressEncMask;
+    PhysicalAddress   |= AddressEncMask;
+  } else {
+    *PageTablePointer &= ~AddressEncMask;
+    PhysicalAddress   &= ~AddressEncMask;
+  }
+
+  Status = TdVmCall (TDVMCALL_MAPGPA, PhysicalAddress, Length, 0, 0, NULL);
+
+  //
+  // If changing shared to private, must accept-page again
+  //
+  if (Mode == ClearSharedBit) {
+    TdAcceptPages (PhysicalAddress, Length / EFI_PAGE_SIZE, EFI_PAGE_SIZE);
+  }
+
+  DEBUG ((
+    DEBUG_VERBOSE,
+    "%a:%a: pte=0x%Lx AddressEncMask=0x%Lx Mode=0x%x MapGPA Status=0x%x\n",
+    gEfiCallerBaseName,
+    __FUNCTION__,
+    *PageTablePointer,
+    AddressEncMask,
+    Mode,
+    Status
+    ));
+}
+
+/**
+ Check the WP status in CR0 register. This bit is used to lock or unlock write
+ access to pages marked as read-only.
+
+  @retval TRUE    Write protection is enabled.
+  @retval FALSE   Write protection is disabled.
+**/
+STATIC
+BOOLEAN
+IsReadOnlyPageWriteProtected (
+  VOID
+  )
+{
+  return ((AsmReadCr0 () & BIT16) != 0);
+}
+
+/**
+ Disable Write Protect on pages marked as read-only.
+**/
+STATIC
+VOID
+DisableReadOnlyPageWriteProtect (
+  VOID
+  )
+{
+  AsmWriteCr0 (AsmReadCr0 () & ~BIT16);
+}
+
+/**
+ Enable Write Protect on pages marked as read-only.
+**/
+VOID
+EnableReadOnlyPageWriteProtect (
+  VOID
+  )
+{
+  AsmWriteCr0 (AsmReadCr0 () | BIT16);
+}
+
+/**
+  This function either sets or clears memory encryption for the memory
+  region specified by PhysicalAddress and Length from the current page table
+  context.
+
+  The function iterates through the PhysicalAddress one page at a time, and set
+  or clears the memory encryption in the page table. If it encounters
+  that a given physical address range is part of large page then it attempts to
+  change the attribute at one go (based on size), otherwise it splits the
+  large pages into smaller (e.g 2M page into 4K pages) and then try to set or
+  clear the encryption bit on the smallest page size.
+
+  @param[in]  Cr3BaseAddress          Cr3 Base Address (if zero then use
+                                      current CR3)
+  @param[in]  PhysicalAddress         The physical address that is the start
+                                      address of a memory region.
+  @param[in]  Length                  The length of memory region
+  @param[in]  Mode                    Set or Clear mode
+
+  @retval RETURN_SUCCESS              The attributes were cleared for the
+                                      memory region.
+  @retval RETURN_INVALID_PARAMETER    Number of pages is zero.
+  @retval RETURN_UNSUPPORTED          Setting the memory encyrption attribute
+                                      is not supported
+**/
+STATIC
+RETURN_STATUS
+EFIAPI
+SetMemorySharedOrPrivate (
+  IN    PHYSICAL_ADDRESS    Cr3BaseAddress,
+  IN    PHYSICAL_ADDRESS    PhysicalAddress,
+  IN    UINTN               Length,
+  IN    TDX_PAGETABLE_MODE  Mode
+  )
+{
+  PAGE_MAP_AND_DIRECTORY_POINTER  *PageMapLevel4Entry;
+  PAGE_MAP_AND_DIRECTORY_POINTER  *PageUpperDirectoryPointerEntry;
+  PAGE_MAP_AND_DIRECTORY_POINTER  *PageDirectoryPointerEntry;
+  PAGE_TABLE_1G_ENTRY             *PageDirectory1GEntry;
+  PAGE_TABLE_ENTRY                *PageDirectory2MEntry;
+  PAGE_TABLE_4K_ENTRY             *PageTableEntry;
+  UINT64                          PgTableMask;
+  UINT64                          AddressEncMask;
+  UINT64                          ActiveEncMask;
+  BOOLEAN                         IsWpEnabled;
+  RETURN_STATUS                   Status;
+  IA32_CR4                        Cr4;
+  BOOLEAN                         Page5LevelSupport;
+
+  //
+  // Set PageMapLevel4Entry to suppress incorrect compiler/analyzer warnings.
+  //
+  PageMapLevel4Entry = NULL;
+
+  DEBUG ((
+    DEBUG_VERBOSE,
+    "%a:%a: Cr3Base=0x%Lx Physical=0x%Lx Length=0x%Lx Mode=%a\n",
+    gEfiCallerBaseName,
+    __FUNCTION__,
+    Cr3BaseAddress,
+    PhysicalAddress,
+    (UINT64)Length,
+    (Mode == SetSharedBit) ? "Shared" : "Private"
+    ));
+
+  //
+  // Check if we have a valid memory encryption mask
+  //
+  AddressEncMask = GetMemEncryptionAddressMask ();
+
+  PgTableMask = AddressEncMask | EFI_PAGE_MASK;
+
+  if (Length == 0) {
+    return RETURN_INVALID_PARAMETER;
+  }
+
+  //
+  // Make sure that the page table is changeable.
+  //
+  IsWpEnabled = IsReadOnlyPageWriteProtected ();
+  if (IsWpEnabled) {
+    DisableReadOnlyPageWriteProtect ();
+  }
+
+  //
+  // If Cr3BaseAddress is not specified then read the current CR3
+  //
+  if (Cr3BaseAddress == 0) {
+    Cr3BaseAddress = AsmReadCr3 ();
+  }
+
+  //
+  // CPU will already have LA57 enabled so just check CR4
+  //
+  Cr4.UintN = AsmReadCr4 ();
+
+  Page5LevelSupport = (Cr4.Bits.LA57 ? TRUE : FALSE);
+  //
+  // If 5-level pages, adjust Cr3BaseAddress to point to first 4-level page directory,
+  // we will only have 1
+  //
+  if (Page5LevelSupport) {
+    Cr3BaseAddress = *(UINT64 *)Cr3BaseAddress & ~PgTableMask;
+  }
+
+  Status = EFI_SUCCESS;
+
+  while (Length) {
+    PageMapLevel4Entry  = (VOID *)(Cr3BaseAddress & ~PgTableMask);
+    PageMapLevel4Entry += PML4_OFFSET (PhysicalAddress);
+    if (!PageMapLevel4Entry->Bits.Present) {
+      DEBUG ((
+        DEBUG_ERROR,
+        "%a:%a: bad PML4 for Physical=0x%Lx\n",
+        gEfiCallerBaseName,
+        __FUNCTION__,
+        PhysicalAddress
+        ));
+      Status = RETURN_NO_MAPPING;
+      goto Done;
+    }
+
+    PageDirectory1GEntry = (VOID *)(
+                                    (PageMapLevel4Entry->Bits.PageTableBaseAddress <<
+                                     12) & ~PgTableMask
+                                    );
+    PageDirectory1GEntry += PDP_OFFSET (PhysicalAddress);
+    if (!PageDirectory1GEntry->Bits.Present) {
+      DEBUG ((
+        DEBUG_ERROR,
+        "%a:%a: bad PDPE for Physical=0x%Lx\n",
+        gEfiCallerBaseName,
+        __FUNCTION__,
+        PhysicalAddress
+        ));
+      Status = RETURN_NO_MAPPING;
+      goto Done;
+    }
+
+    //
+    // If the MustBe1 bit is not 1, it's not actually a 1GB entry
+    //
+    if (PageDirectory1GEntry->Bits.MustBe1) {
+      //
+      // Valid 1GB page
+      // If we have at least 1GB to go, we can just update this entry
+      //
+      if (!(PhysicalAddress & (BIT30 - 1)) && (Length >= BIT30)) {
+        SetOrClearSharedBit (&PageDirectory1GEntry->Uint64, Mode, PhysicalAddress, BIT30);
+        DEBUG ((
+          DEBUG_VERBOSE,
+          "%a:%a: updated 1GB entry for Physical=0x%Lx\n",
+          gEfiCallerBaseName,
+          __FUNCTION__,
+          PhysicalAddress
+          ));
+        PhysicalAddress += BIT30;
+        Length          -= BIT30;
+      } else {
+        //
+        // We must split the page
+        //
+        DEBUG ((
+          DEBUG_VERBOSE,
+          "%a:%a: splitting 1GB page for Physical=0x%Lx\n",
+          gEfiCallerBaseName,
+          __FUNCTION__,
+          PhysicalAddress
+          ));
+        Split1GPageTo2M (
+          (UINT64)PageDirectory1GEntry->Bits.PageTableBaseAddress << 30,
+          (UINT64 *)PageDirectory1GEntry,
+          0,
+          0
+          );
+        continue;
+      }
+    } else {
+      //
+      // Actually a PDP
+      //
+      PageUpperDirectoryPointerEntry =
+        (PAGE_MAP_AND_DIRECTORY_POINTER *)PageDirectory1GEntry;
+      PageDirectory2MEntry =
+        (VOID *)(
+                 (PageUpperDirectoryPointerEntry->Bits.PageTableBaseAddress <<
+                  12) & ~PgTableMask
+                 );
+      PageDirectory2MEntry += PDE_OFFSET (PhysicalAddress);
+      if (!PageDirectory2MEntry->Bits.Present) {
+        DEBUG ((
+          DEBUG_ERROR,
+          "%a:%a: bad PDE for Physical=0x%Lx\n",
+          gEfiCallerBaseName,
+          __FUNCTION__,
+          PhysicalAddress
+          ));
+        Status = RETURN_NO_MAPPING;
+        goto Done;
+      }
+
+      //
+      // If the MustBe1 bit is not a 1, it's not a 2MB entry
+      //
+      if (PageDirectory2MEntry->Bits.MustBe1) {
+        //
+        // Valid 2MB page
+        // If we have at least 2MB left to go, we can just update this entry
+        //
+        if (!(PhysicalAddress & (BIT21-1)) && (Length >= BIT21)) {
+          SetOrClearSharedBit (&PageDirectory2MEntry->Uint64, Mode, PhysicalAddress, BIT21);
+          PhysicalAddress += BIT21;
+          Length          -= BIT21;
+        } else {
+          //
+          // We must split up this page into 4K pages
+          //
+          DEBUG ((
+            DEBUG_VERBOSE,
+            "%a:%a: splitting 2MB page for Physical=0x%Lx\n",
+            gEfiCallerBaseName,
+            __FUNCTION__,
+            PhysicalAddress
+            ));
+
+          ActiveEncMask = PageDirectory2MEntry->Uint64 & AddressEncMask;
+
+          Split2MPageTo4K (
+            (UINT64)PageDirectory2MEntry->Bits.PageTableBaseAddress << 21,
+            (UINT64 *)PageDirectory2MEntry,
+            0,
+            0,
+            ActiveEncMask
+            );
+          continue;
+        }
+      } else {
+        PageDirectoryPointerEntry =
+          (PAGE_MAP_AND_DIRECTORY_POINTER *)PageDirectory2MEntry;
+        PageTableEntry =
+          (VOID *)(
+                   (PageDirectoryPointerEntry->Bits.PageTableBaseAddress <<
+                    12) & ~PgTableMask
+                   );
+        PageTableEntry += PTE_OFFSET (PhysicalAddress);
+        if (!PageTableEntry->Bits.Present) {
+          DEBUG ((
+            DEBUG_ERROR,
+            "%a:%a: bad PTE for Physical=0x%Lx\n",
+            gEfiCallerBaseName,
+            __FUNCTION__,
+            PhysicalAddress
+            ));
+          Status = RETURN_NO_MAPPING;
+          goto Done;
+        }
+
+        SetOrClearSharedBit (&PageTableEntry->Uint64, Mode, PhysicalAddress, EFI_PAGE_SIZE);
+        PhysicalAddress += EFI_PAGE_SIZE;
+        Length          -= EFI_PAGE_SIZE;
+      }
+    }
+  }
+
+  //
+  // Protect the page table by marking the memory used for page table to be
+  // read-only.
+  //
+  if (IsWpEnabled) {
+    EnablePageTableProtection ((UINTN)PageMapLevel4Entry, TRUE);
+  }
+
+  //
+  // Flush TLB
+  //
+  CpuFlushTlb ();
+
+Done:
+  //
+  // Restore page table write protection, if any.
+  //
+  if (IsWpEnabled) {
+    EnableReadOnlyPageWriteProtect ();
+  }
+
+  return Status;
+}
+
+/**
+  This function clears memory encryption bit for the memory region specified by
+  BaseAddress and NumPages from the current page table context.
+
+  @param[in]  Cr3BaseAddress          Cr3 Base Address (if zero then use
+                                      current CR3)
+  @param[in]  BaseAddress             The physical address that is the start
+                                      address of a memory region.
+  @param[in]  NumPages                The number of pages from start memory
+                                      region.
+
+  @retval RETURN_SUCCESS              The attributes were cleared for the
+                                      memory region.
+  @retval RETURN_INVALID_PARAMETER    Number of pages is zero.
+  @retval RETURN_UNSUPPORTED          Clearing the memory encryption attribute
+                                      is not supported
+**/
+RETURN_STATUS
+EFIAPI
+MemEncryptTdxSetPageSharedBit (
+  IN PHYSICAL_ADDRESS  Cr3BaseAddress,
+  IN PHYSICAL_ADDRESS  BaseAddress,
+  IN UINTN             NumPages
+  )
+{
+  return SetMemorySharedOrPrivate (
+           Cr3BaseAddress,
+           BaseAddress,
+           EFI_PAGES_TO_SIZE (NumPages),
+           SetSharedBit
+           );
+}
+
+/**
+  This function sets memory encryption bit for the memory region specified by
+  BaseAddress and NumPages from the current page table context.
+
+  @param[in]  Cr3BaseAddress          Cr3 Base Address (if zero then use
+                                      current CR3)
+  @param[in]  BaseAddress             The physical address that is the start
+                                      address of a memory region.
+  @param[in]  NumPages                The number of pages from start memory
+                                      region.
+
+  @retval RETURN_SUCCESS              The attributes were set for the memory
+                                      region.
+  @retval RETURN_INVALID_PARAMETER    Number of pages is zero.
+  @retval RETURN_UNSUPPORTED          Setting the memory encryption attribute
+                                      is not supported
+**/
+RETURN_STATUS
+EFIAPI
+MemEncryptTdxClearPageSharedBit (
+  IN PHYSICAL_ADDRESS  Cr3BaseAddress,
+  IN PHYSICAL_ADDRESS  BaseAddress,
+  IN UINTN             NumPages
+  )
+{
+  return SetMemorySharedOrPrivate (
+           Cr3BaseAddress,
+           BaseAddress,
+           EFI_PAGES_TO_SIZE (NumPages),
+           ClearSharedBit
+           );
+}
diff --git a/OvmfPkg/Library/BaseMemEncryptTdxLib/VirtualMemory.h b/OvmfPkg/Library/BaseMemEncryptTdxLib/VirtualMemory.h
new file mode 100644
index 000000000000..e9403798d98d
--- /dev/null
+++ b/OvmfPkg/Library/BaseMemEncryptTdxLib/VirtualMemory.h
@@ -0,0 +1,181 @@
+/** @file
+
+  Virtual Memory Management Services to set or clear the memory encryption bit
+
+  Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  Code is derived from MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
+
+**/
+
+#ifndef TDX_VIRTUAL_MEMORY_
+#define TDX_VIRTUAL_MEMORY_
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Uefi.h>
+
+#define SYS_CODE64_SEL  0x38
+
+#pragma pack(1)
+
+//
+// Page-Map Level-4 Offset (PML4) and
+// Page-Directory-Pointer Offset (PDPE) entries 4K & 2MB
+//
+
+typedef union {
+  struct {
+    UINT64    Present              : 1;  // 0 = Not present in memory,
+                                         //   1 = Present in memory
+    UINT64    ReadWrite            : 1;  // 0 = Read-Only, 1= Read/Write
+    UINT64    UserSupervisor       : 1;  // 0 = Supervisor, 1=User
+    UINT64    WriteThrough         : 1;  // 0 = Write-Back caching,
+                                         //   1 = Write-Through caching
+    UINT64    CacheDisabled        : 1;  // 0 = Cached, 1=Non-Cached
+    UINT64    Accessed             : 1;  // 0 = Not accessed,
+                                         //   1 = Accessed (set by CPU)
+    UINT64    Reserved             : 1;  // Reserved
+    UINT64    MustBeZero           : 2;  // Must Be Zero
+    UINT64    Available            : 3;  // Available for use by system software
+    UINT64    PageTableBaseAddress : 40; // Page Table Base Address
+    UINT64    AvabilableHigh       : 11; // Available for use by system software
+    UINT64    Nx                   : 1;  // No Execute bit
+  } Bits;
+  UINT64    Uint64;
+} PAGE_MAP_AND_DIRECTORY_POINTER;
+
+//
+// Page Table Entry 4KB
+//
+typedef union {
+  struct {
+    UINT64    Present              : 1;  // 0 = Not present in memory,
+                                         //   1 = Present in memory
+    UINT64    ReadWrite            : 1;  // 0 = Read-Only, 1= Read/Write
+    UINT64    UserSupervisor       : 1;  // 0 = Supervisor, 1=User
+    UINT64    WriteThrough         : 1;  // 0 = Write-Back caching,
+                                         //   1 = Write-Through caching
+    UINT64    CacheDisabled        : 1;  // 0 = Cached, 1=Non-Cached
+    UINT64    Accessed             : 1;  // 0 = Not accessed,
+                                         //   1 = Accessed (set by CPU)
+    UINT64    Dirty                : 1;  // 0 = Not Dirty, 1 = written by
+                                         //   processor on access to page
+    UINT64    PAT                  : 1;  //
+    UINT64    Global               : 1;  // 0 = Not global page, 1 = global page
+                                         //   TLB not cleared on CR3 write
+    UINT64    Available            : 3;  // Available for use by system software
+    UINT64    PageTableBaseAddress : 40; // Page Table Base Address
+    UINT64    AvabilableHigh       : 11; // Available for use by system software
+    UINT64    Nx                   : 1;  // 0 = Execute Code,
+                                         //   1 = No Code Execution
+  } Bits;
+  UINT64    Uint64;
+} PAGE_TABLE_4K_ENTRY;
+
+//
+// Page Table Entry 2MB
+//
+typedef union {
+  struct {
+    UINT64    Present              : 1;  // 0 = Not present in memory,
+                                         //   1 = Present in memory
+    UINT64    ReadWrite            : 1;  // 0 = Read-Only, 1= Read/Write
+    UINT64    UserSupervisor       : 1;  // 0 = Supervisor, 1=User
+    UINT64    WriteThrough         : 1;  // 0 = Write-Back caching,
+                                         //   1=Write-Through caching
+    UINT64    CacheDisabled        : 1;  // 0 = Cached, 1=Non-Cached
+    UINT64    Accessed             : 1;  // 0 = Not accessed,
+                                         //   1 = Accessed (set by CPU)
+    UINT64    Dirty                : 1;  // 0 = Not Dirty, 1 = written by
+                                         //   processor on access to page
+    UINT64    MustBe1              : 1;  // Must be 1
+    UINT64    Global               : 1;  // 0 = Not global page, 1 = global page
+                                         //   TLB not cleared on CR3 write
+    UINT64    Available            : 3;  // Available for use by system software
+    UINT64    PAT                  : 1;  //
+    UINT64    MustBeZero           : 8;  // Must be zero;
+    UINT64    PageTableBaseAddress : 31; // Page Table Base Address
+    UINT64    AvabilableHigh       : 11; // Available for use by system software
+    UINT64    Nx                   : 1;  // 0 = Execute Code,
+                                         //   1 = No Code Execution
+  } Bits;
+  UINT64    Uint64;
+} PAGE_TABLE_ENTRY;
+
+//
+// Page Table Entry 1GB
+//
+typedef union {
+  struct {
+    UINT64    Present              : 1;  // 0 = Not present in memory,
+                                         //   1 = Present in memory
+    UINT64    ReadWrite            : 1;  // 0 = Read-Only, 1= Read/Write
+    UINT64    UserSupervisor       : 1;  // 0 = Supervisor, 1=User
+    UINT64    WriteThrough         : 1;  // 0 = Write-Back caching,
+                                         //   1 = Write-Through caching
+    UINT64    CacheDisabled        : 1;  // 0 = Cached, 1=Non-Cached
+    UINT64    Accessed             : 1;  // 0 = Not accessed,
+                                         //   1 = Accessed (set by CPU)
+    UINT64    Dirty                : 1;  // 0 = Not Dirty, 1 = written by
+                                         //   processor on access to page
+    UINT64    MustBe1              : 1;  // Must be 1
+    UINT64    Global               : 1;  // 0 = Not global page, 1 = global page
+                                         //   TLB not cleared on CR3 write
+    UINT64    Available            : 3;  // Available for use by system software
+    UINT64    PAT                  : 1;  //
+    UINT64    MustBeZero           : 17; // Must be zero;
+    UINT64    PageTableBaseAddress : 22; // Page Table Base Address
+    UINT64    AvabilableHigh       : 11; // Available for use by system software
+    UINT64    Nx                   : 1;  // 0 = Execute Code,
+                                         //   1 = No Code Execution
+  } Bits;
+  UINT64    Uint64;
+} PAGE_TABLE_1G_ENTRY;
+
+#pragma pack()
+
+#define IA32_PG_P   BIT0
+#define IA32_PG_RW  BIT1
+#define IA32_PG_PS  BIT7
+
+#define PAGING_PAE_INDEX_MASK  0x1FF
+
+#define PAGING_4K_ADDRESS_MASK_64  0x000FFFFFFFFFF000ull
+#define PAGING_2M_ADDRESS_MASK_64  0x000FFFFFFFE00000ull
+#define PAGING_1G_ADDRESS_MASK_64  0x000FFFFFC0000000ull
+
+#define PAGING_L1_ADDRESS_SHIFT  12
+#define PAGING_L2_ADDRESS_SHIFT  21
+#define PAGING_L3_ADDRESS_SHIFT  30
+#define PAGING_L4_ADDRESS_SHIFT  39
+
+#define PAGING_PML4E_NUMBER  4
+
+#define PAGETABLE_ENTRY_MASK  ((1UL << 9) - 1)
+#define PML4_OFFSET(x)  ( (x >> 39) & PAGETABLE_ENTRY_MASK)
+#define PDP_OFFSET(x)   ( (x >> 30) & PAGETABLE_ENTRY_MASK)
+#define PDE_OFFSET(x)   ( (x >> 21) & PAGETABLE_ENTRY_MASK)
+#define PTE_OFFSET(x)   ( (x >> 12) & PAGETABLE_ENTRY_MASK)
+#define PAGING_1G_ADDRESS_MASK_64  0x000FFFFFC0000000ull
+
+#define PAGE_TABLE_POOL_ALIGNMENT  BASE_2MB
+#define PAGE_TABLE_POOL_UNIT_SIZE  SIZE_2MB
+#define PAGE_TABLE_POOL_UNIT_PAGES  \
+  EFI_SIZE_TO_PAGES (PAGE_TABLE_POOL_UNIT_SIZE)
+#define PAGE_TABLE_POOL_ALIGN_MASK  \
+  (~(EFI_PHYSICAL_ADDRESS)(PAGE_TABLE_POOL_ALIGNMENT - 1))
+
+typedef struct {
+  VOID     *NextPool;
+  UINTN    Offset;
+  UINTN    FreePages;
+} PAGE_TABLE_POOL;
+
+#endif
diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index 0456d1cdf47e..86138594b83b 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -34,6 +34,10 @@
   #                  Virtualization (SEV) guests.
   MemEncryptSevLib|Include/Library/MemEncryptSevLib.h
 
+  ##  @libraryclass  Declares helper functions for TDX guests.
+  #
+  MemEncryptTdxLib|Include/Library/MemEncryptTdxLib.h
+
   ##  @libraryclass  Save and restore variables using a file
   #
   NvVarsFileLib|Include/Library/NvVarsFileLib.h
diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
index f8873d515592..26c7f536522e 100644
--- a/OvmfPkg/OvmfPkgIa32.dsc
+++ b/OvmfPkg/OvmfPkgIa32.dsc
@@ -176,6 +176,7 @@
   VirtioLib|OvmfPkg/Library/VirtioLib/VirtioLib.inf
   LoadLinuxLib|OvmfPkg/Library/LoadLinuxLib/LoadLinuxLib.inf
   MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf
+  MemEncryptTdxLib|OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLibNull.inf
 !if $(SMM_REQUIRE) == FALSE
   LockBoxLib|OvmfPkg/Library/LockBoxLib/LockBoxBaseLib.inf
 !endif
diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index dcec6acb28d7..6f9509de615e 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -180,6 +180,7 @@
   VirtioLib|OvmfPkg/Library/VirtioLib/VirtioLib.inf
   LoadLinuxLib|OvmfPkg/Library/LoadLinuxLib/LoadLinuxLib.inf
   MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf
+  MemEncryptTdxLib|OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLibNull.inf
 !if $(SMM_REQUIRE) == FALSE
   LockBoxLib|OvmfPkg/Library/LockBoxLib/LockBoxBaseLib.inf
 !endif
-- 
2.29.2.windows.2


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

* [PATCH V4 26/31] OvmfPkg/QemuFwCfgLib: Support Tdx in QemuFwCfgDxe
  2021-12-13 12:56 [PATCH V4 00/31] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (24 preceding siblings ...)
  2021-12-13 12:56 ` [PATCH V4 25/31] OvmfPkg/BaseMemEncryptTdxLib: Add TDX helper library Min Xu
@ 2021-12-13 12:56 ` Min Xu
  2021-12-15  9:16   ` Gerd Hoffmann
  2021-12-13 12:56 ` [PATCH V4 27/31] OvmfPkg: Update IoMmuDxe to support TDX Min Xu
                   ` (4 subsequent siblings)
  30 siblings, 1 reply; 68+ messages in thread
From: Min Xu @ 2021-12-13 12:56 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 the previous QemuFwCfgDxe only SEV is supported. This commit
introduce TDX support in QemuFwCfgDxe.

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>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgDxe.c      | 9 +++++----
 OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgDxeLib.inf | 1 +
 2 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgDxe.c b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgDxe.c
index f5787cd24d38..6a810928a060 100644
--- a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgDxe.c
+++ b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgDxe.c
@@ -19,6 +19,7 @@
 #include <Library/DebugLib.h>
 #include <Library/QemuFwCfgLib.h>
 #include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemEncryptTdxLib.h>
 #include <Library/MemEncryptSevLib.h>
 
 #include "QemuFwCfgLibInternal.h"
@@ -85,7 +86,7 @@ QemuFwCfgInitialize (
     DEBUG ((DEBUG_INFO, "QemuFwCfg interface (DMA) is supported.\n"));
   }
 
-  if (mQemuFwCfgDmaSupported && MemEncryptSevIsEnabled ()) {
+  if (mQemuFwCfgDmaSupported && (MemEncryptSevIsEnabled () || (MemEncryptTdxIsEnabled ()))) {
     EFI_STATUS  Status;
 
     //
@@ -100,7 +101,7 @@ QemuFwCfgInitialize (
     if (EFI_ERROR (Status)) {
       DEBUG ((
         DEBUG_ERROR,
-        "QemuFwCfgSevDma %a:%a Failed to locate IOMMU protocol.\n",
+        "QemuFwCfgDma %a:%a Failed to locate IOMMU protocol.\n",
         gEfiCallerBaseName,
         __FUNCTION__
         ));
@@ -411,10 +412,10 @@ InternalQemuFwCfgDmaBytes (
   DataBuffer    = Buffer;
 
   //
-  // When SEV is enabled, map Buffer to DMA address before issuing the DMA
+  // When SEV or TDX is enabled, map Buffer to DMA address before issuing the DMA
   // request
   //
-  if (MemEncryptSevIsEnabled ()) {
+  if (MemEncryptSevIsEnabled () || MemEncryptTdxIsEnabled ()) {
     VOID                  *AccessBuffer;
     EFI_PHYSICAL_ADDRESS  DataBufferAddress;
 
diff --git a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgDxeLib.inf b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgDxeLib.inf
index 48899ff1236a..ce3eaa5ed8b4 100644
--- a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgDxeLib.inf
+++ b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgDxeLib.inf
@@ -43,6 +43,7 @@
   IoLib
   MemoryAllocationLib
   MemEncryptSevLib
+  MemEncryptTdxLib
 
 [Protocols]
   gEdkiiIoMmuProtocolGuid                         ## SOMETIMES_CONSUMES
-- 
2.29.2.windows.2


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

* [PATCH V4 27/31] OvmfPkg: Update IoMmuDxe to support TDX
  2021-12-13 12:56 [PATCH V4 00/31] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (25 preceding siblings ...)
  2021-12-13 12:56 ` [PATCH V4 26/31] OvmfPkg/QemuFwCfgLib: Support Tdx in QemuFwCfgDxe Min Xu
@ 2021-12-13 12:56 ` Min Xu
  2021-12-15  9:18   ` Gerd Hoffmann
  2021-12-13 12:56 ` [PATCH V4 28/31] OvmfPkg: Rename XenTimerDxe to LocalApicTimerDxe Min Xu
                   ` (3 subsequent siblings)
  30 siblings, 1 reply; 68+ messages in thread
From: Min Xu @ 2021-12-13 12:56 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

The IOMMU protocol driver provides capabilities to set a DMA access
attribute and methods to allocate, free, map and unmap the DMA memory
for the PCI Bus devices.

The current IoMmuDxe driver supports DMA operations inside SEV guest.
To support DMA operation in TDX guest,
CC_GUEST_IS_XXX (PcdConfidentialComputingGuestAttr) is used to determine
if it is SEV guest or TDX guest.

Due to security reasons all DMA operations inside the SEV/TDX guest must
be performed on shared pages. The IOMMU protocol driver for the SEV/TDX
guest uses a bounce buffer to map guest DMA buffer to shared pages in
order to provide the support for DMA operations inside SEV/TDX guest.

The call of SEV or TDX specific function to set/clear EncMask/SharedBit
is determined by CC_GUEST_IS_XXX (PcdConfidentialComputingGuestAttr).

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>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/IoMmuDxe/AmdSevIoMmu.c | 103 +++++++++++++++++++++------------
 OvmfPkg/IoMmuDxe/AmdSevIoMmu.h |   6 +-
 OvmfPkg/IoMmuDxe/IoMmuDxe.c    |   6 +-
 OvmfPkg/IoMmuDxe/IoMmuDxe.inf  |   5 ++
 OvmfPkg/OvmfPkgX64.dsc         |   2 +
 5 files changed, 80 insertions(+), 42 deletions(-)

diff --git a/OvmfPkg/IoMmuDxe/AmdSevIoMmu.c b/OvmfPkg/IoMmuDxe/AmdSevIoMmu.c
index 16b5b4eac8bc..6b65897f032a 100644
--- a/OvmfPkg/IoMmuDxe/AmdSevIoMmu.c
+++ b/OvmfPkg/IoMmuDxe/AmdSevIoMmu.c
@@ -1,9 +1,9 @@
 /** @file
 
   The protocol provides support to allocate, free, map and umap a DMA buffer
-  for bus master (e.g PciHostBridge). When SEV is enabled, the DMA operations
-  must be performed on unencrypted buffer hence we use a bounce buffer to map
-  the guest buffer into an unencrypted DMA buffer.
+  for bus master (e.g PciHostBridge). When SEV or TDX is enabled, the DMA
+  operations must be performed on unencrypted buffer hence we use a bounce
+  buffer to map the guest buffer into an unencrypted DMA buffer.
 
   Copyright (c) 2017, AMD Inc. All rights reserved.<BR>
   Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
@@ -12,6 +12,8 @@
 
 **/
 
+#include <Library/PcdLib.h>
+#include <ConfidentialComputingGuestAttr.h>
 #include "AmdSevIoMmu.h"
 
 #define MAP_INFO_SIG  SIGNATURE_64 ('M', 'A', 'P', '_', 'I', 'N', 'F', 'O')
@@ -74,7 +76,7 @@ typedef struct {
 
 /**
   Provides the controller-specific addresses required to access system memory
-  from a DMA bus master. On SEV guest, the DMA operations must be performed on
+  from a DMA bus master. On SEV/TDX guest, the DMA operations must be performed on
   shared buffer hence we allocate a bounce buffer to map the HostAddress to a
   DeviceAddress. The Encryption attribute is removed from the DeviceAddress
   buffer.
@@ -250,14 +252,28 @@ IoMmuMap (
       goto FreeMapInfo;
   }
 
-  //
-  // Clear the memory encryption mask on the plaintext buffer.
-  //
-  Status = MemEncryptSevClearPageEncMask (
-             0,
-             MapInfo->PlainTextAddress,
-             MapInfo->NumberOfPages
-             );
+  if (CC_GUEST_IS_SEV (PcdGet64 (PcdConfidentialComputingGuestAttr))) {
+    //
+    // Clear the memory encryption mask on the plaintext buffer.
+    //
+    Status = MemEncryptSevClearPageEncMask (
+               0,
+               MapInfo->PlainTextAddress,
+               MapInfo->NumberOfPages
+               );
+  } else if (CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr))) {
+    //
+    // Set the memory shared bit.
+    //
+    Status = MemEncryptTdxSetPageSharedBit (
+               0,
+               MapInfo->PlainTextAddress,
+               MapInfo->NumberOfPages
+               );
+  } else {
+    ASSERT (FALSE);
+  }
+
   ASSERT_EFI_ERROR (Status);
   if (EFI_ERROR (Status)) {
     CpuDeadLoop ();
@@ -358,7 +374,7 @@ IoMmuUnmapWorker (
   }
 
   MapInfo = (MAP_INFO *)Mapping;
-
+  Status  = EFI_SUCCESS;
   //
   // set CommonBufferHeader to suppress incorrect compiler/analyzer warnings
   //
@@ -404,15 +420,30 @@ IoMmuUnmapWorker (
       break;
   }
 
-  //
-  // Restore the memory encryption mask on the area we used to hold the
-  // plaintext.
-  //
-  Status = MemEncryptSevSetPageEncMask (
-             0,
-             MapInfo->PlainTextAddress,
-             MapInfo->NumberOfPages
-             );
+  if (CC_GUEST_IS_SEV (PcdGet64 (PcdConfidentialComputingGuestAttr))) {
+    //
+    // Restore the memory encryption mask on the area we used to hold the
+    // plaintext.
+    //
+    Status = MemEncryptSevSetPageEncMask (
+               0,
+               MapInfo->PlainTextAddress,
+               MapInfo->NumberOfPages
+               );
+  } else if (CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr))) {
+    //
+    // Restore the memory shared bit mask on the area we used to hold the
+    // plaintext.
+    //
+    Status = MemEncryptTdxClearPageSharedBit (
+               0,
+               MapInfo->PlainTextAddress,
+               MapInfo->NumberOfPages
+               );
+  } else {
+    ASSERT (FALSE);
+  }
+
   ASSERT_EFI_ERROR (Status);
   if (EFI_ERROR (Status)) {
     CpuDeadLoop ();
@@ -739,7 +770,7 @@ IoMmuSetAttribute (
   return EFI_UNSUPPORTED;
 }
 
-EDKII_IOMMU_PROTOCOL  mAmdSev = {
+EDKII_IOMMU_PROTOCOL  mIoMmu = {
   EDKII_IOMMU_PROTOCOL_REVISION,
   IoMmuSetAttribute,
   IoMmuMap,
@@ -771,7 +802,7 @@ EDKII_IOMMU_PROTOCOL  mAmdSev = {
 STATIC
 VOID
 EFIAPI
-AmdSevExitBoot (
+IoMmuExitBoot (
   IN EFI_EVENT  Event,
   IN VOID       *EventToSignal
   )
@@ -779,11 +810,11 @@ AmdSevExitBoot (
   //
   // (1) The NotifyFunctions of all the events in
   //     EFI_EVENT_GROUP_EXIT_BOOT_SERVICES will have been queued before
-  //     AmdSevExitBoot() is entered.
+  //     IoMmuExitBoot() is entered.
   //
-  // (2) AmdSevExitBoot() is executing minimally at TPL_CALLBACK.
+  // (2) IoMmuExitBoot() is executing minimally at TPL_CALLBACK.
   //
-  // (3) AmdSevExitBoot() has been queued in unspecified order relative to the
+  // (3) IoMmuExitBoot() has been queued in unspecified order relative to the
   //     NotifyFunctions of all the other events in
   //     EFI_EVENT_GROUP_EXIT_BOOT_SERVICES whose NotifyTpl is the same as
   //     Event's.
@@ -791,13 +822,13 @@ AmdSevExitBoot (
   // Consequences:
   //
   // - If Event's NotifyTpl is TPL_CALLBACK, then some other NotifyFunctions
-  //   queued at TPL_CALLBACK may be invoked after AmdSevExitBoot() returns.
+  //   queued at TPL_CALLBACK may be invoked after IoMmuExitBoot() returns.
   //
   // - If Event's NotifyTpl is TPL_NOTIFY, then some other NotifyFunctions
-  //   queued at TPL_NOTIFY may be invoked after AmdSevExitBoot() returns; plus
+  //   queued at TPL_NOTIFY may be invoked after IoMmuExitBoot() returns; plus
   //   *all* NotifyFunctions queued at TPL_CALLBACK will be invoked strictly
   //   after all NotifyFunctions queued at TPL_NOTIFY, including
-  //   AmdSevExitBoot(), have been invoked.
+  //   IoMmuExitBoot(), have been invoked.
   //
   // - By signaling EventToSignal here, whose NotifyTpl is TPL_CALLBACK, we
   //   queue EventToSignal's NotifyFunction after the NotifyFunctions of *all*
@@ -823,7 +854,7 @@ AmdSevExitBoot (
 STATIC
 VOID
 EFIAPI
-AmdSevUnmapAllMappings (
+IoMmuUnmapAllMappings (
   IN EFI_EVENT  Event,
   IN VOID       *Context
   )
@@ -842,7 +873,7 @@ AmdSevUnmapAllMappings (
     NextNode = GetNextNode (&mMapInfos, Node);
     MapInfo  = CR (Node, MAP_INFO, Link, MAP_INFO_SIG);
     IoMmuUnmapWorker (
-      &mAmdSev, // This
+      &mIoMmu,  // This
       MapInfo,  // Mapping
       TRUE      // MemoryMapLocked
       );
@@ -855,7 +886,7 @@ AmdSevUnmapAllMappings (
 **/
 EFI_STATUS
 EFIAPI
-AmdSevInstallIoMmuProtocol (
+InstallIoMmuProtocol (
   VOID
   )
 {
@@ -871,7 +902,7 @@ AmdSevInstallIoMmuProtocol (
   Status = gBS->CreateEvent (
                   EVT_NOTIFY_SIGNAL,      // Type
                   TPL_CALLBACK,           // NotifyTpl
-                  AmdSevUnmapAllMappings, // NotifyFunction
+                  IoMmuUnmapAllMappings,  // NotifyFunction
                   NULL,                   // NotifyContext
                   &UnmapAllMappingsEvent  // Event
                   );
@@ -886,7 +917,7 @@ AmdSevInstallIoMmuProtocol (
   Status = gBS->CreateEvent (
                   EVT_SIGNAL_EXIT_BOOT_SERVICES, // Type
                   TPL_CALLBACK,                  // NotifyTpl
-                  AmdSevExitBoot,                // NotifyFunction
+                  IoMmuExitBoot,                 // NotifyFunction
                   UnmapAllMappingsEvent,         // NotifyContext
                   &ExitBootEvent                 // Event
                   );
@@ -898,7 +929,7 @@ AmdSevInstallIoMmuProtocol (
   Status = gBS->InstallMultipleProtocolInterfaces (
                   &Handle,
                   &gEdkiiIoMmuProtocolGuid,
-                  &mAmdSev,
+                  &mIoMmu,
                   NULL
                   );
   if (EFI_ERROR (Status)) {
diff --git a/OvmfPkg/IoMmuDxe/AmdSevIoMmu.h b/OvmfPkg/IoMmuDxe/AmdSevIoMmu.h
index 8244f28b57fd..8fdfa9968593 100644
--- a/OvmfPkg/IoMmuDxe/AmdSevIoMmu.h
+++ b/OvmfPkg/IoMmuDxe/AmdSevIoMmu.h
@@ -21,17 +21,17 @@
 #include <Library/BaseMemoryLib.h>
 #include <Library/DebugLib.h>
 #include <Library/MemEncryptSevLib.h>
+#include <Library/MemEncryptTdxLib.h>
 #include <Library/MemoryAllocationLib.h>
 #include <Library/UefiBootServicesTableLib.h>
 
 /**
-  Install IOMMU protocol to provide the DMA support for PciHostBridge and
-  MemEncryptSevLib.
+  Install IOMMU protocol to provide the DMA support for PciHostBridge.
 
 **/
 EFI_STATUS
 EFIAPI
-AmdSevInstallIoMmuProtocol (
+InstallIoMmuProtocol (
   VOID
   );
 
diff --git a/OvmfPkg/IoMmuDxe/IoMmuDxe.c b/OvmfPkg/IoMmuDxe/IoMmuDxe.c
index bca8c14c4076..86777dd05c26 100644
--- a/OvmfPkg/IoMmuDxe/IoMmuDxe.c
+++ b/OvmfPkg/IoMmuDxe/IoMmuDxe.c
@@ -22,11 +22,11 @@ IoMmuDxeEntryPoint (
   EFI_HANDLE  Handle;
 
   //
-  // When SEV is enabled, install IoMmu protocol otherwise install the
+  // When SEV or TDX is enabled, install IoMmu protocol otherwise install the
   // placeholder protocol so that other dependent module can run.
   //
-  if (MemEncryptSevIsEnabled ()) {
-    Status = AmdSevInstallIoMmuProtocol ();
+  if (MemEncryptSevIsEnabled () || MemEncryptTdxIsEnabled ()) {
+    Status = InstallIoMmuProtocol ();
   } else {
     Handle = NULL;
 
diff --git a/OvmfPkg/IoMmuDxe/IoMmuDxe.inf b/OvmfPkg/IoMmuDxe/IoMmuDxe.inf
index 2ebd74e5558c..e10be1dcff49 100644
--- a/OvmfPkg/IoMmuDxe/IoMmuDxe.inf
+++ b/OvmfPkg/IoMmuDxe/IoMmuDxe.inf
@@ -26,16 +26,21 @@
   MdePkg/MdePkg.dec
   MdeModulePkg/MdeModulePkg.dec
   OvmfPkg/OvmfPkg.dec
+#  UefiCpuPkg/UefiCpuPkg.dec
 
 [LibraryClasses]
   BaseLib
   BaseMemoryLib
   DebugLib
   MemEncryptSevLib
+  MemEncryptTdxLib
   MemoryAllocationLib
   UefiBootServicesTableLib
   UefiDriverEntryPoint
 
+[Pcd]
+  gEfiMdePkgTokenSpaceGuid.PcdConfidentialComputingGuestAttr
+
 [Protocols]
   gEdkiiIoMmuProtocolGuid                     ## SOMETIME_PRODUCES
   gIoMmuAbsentProtocolGuid                    ## SOMETIME_PRODUCES
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index b1ec012e4f83..4d23408f1d4c 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -180,6 +180,8 @@
   VirtioLib|OvmfPkg/Library/VirtioLib/VirtioLib.inf
   LoadLinuxLib|OvmfPkg/Library/LoadLinuxLib/LoadLinuxLib.inf
   MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf
+  MemEncryptTdxLib|OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLib.inf
+
 !if $(SMM_REQUIRE) == FALSE
   LockBoxLib|OvmfPkg/Library/LockBoxLib/LockBoxBaseLib.inf
 !endif
-- 
2.29.2.windows.2


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

* [PATCH V4 28/31] OvmfPkg: Rename XenTimerDxe to LocalApicTimerDxe
  2021-12-13 12:56 [PATCH V4 00/31] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (26 preceding siblings ...)
  2021-12-13 12:56 ` [PATCH V4 27/31] OvmfPkg: Update IoMmuDxe to support TDX Min Xu
@ 2021-12-13 12:56 ` Min Xu
  2021-12-15  9:19   ` Gerd Hoffmann
  2021-12-13 12:57 ` [PATCH V4 29/31] UefiCpuPkg: Setting initial-count register as the last step Min Xu
                   ` (2 subsequent siblings)
  30 siblings, 1 reply; 68+ messages in thread
From: Min Xu @ 2021-12-13 12:56 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky, Gerd Hoffmann,
	Anthony Perard, Julien Grall

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

XenTimerDxe is a local Apic timer driver and it has nothing to do
with Xen. So rename it to LocalApicTimerDxe.

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: Anthony Perard <anthony.perard@citrix.com>
Cc: Julien Grall <julien@xen.org>
Acked-by: Anthony PERARD <anthony.perard@citrix.com
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 .../LocalApicTimerDxe.c}                      | 24 +++++++++----------
 .../LocalApicTimerDxe.h}                      | 22 ++++++++---------
 .../LocalApicTimerDxe.inf}                    |  6 ++---
 OvmfPkg/Microvm/MicrovmX64.dsc                |  2 +-
 OvmfPkg/Microvm/MicrovmX64.fdf                |  2 +-
 OvmfPkg/OvmfXen.dsc                           |  2 +-
 OvmfPkg/OvmfXen.fdf                           |  2 +-
 7 files changed, 30 insertions(+), 30 deletions(-)
 rename OvmfPkg/{XenTimerDxe/XenTimerDxe.c => LocalApicTimerDxe/LocalApicTimerDxe.c} (92%)
 rename OvmfPkg/{XenTimerDxe/XenTimerDxe.h => LocalApicTimerDxe/LocalApicTimerDxe.h} (91%)
 rename OvmfPkg/{XenTimerDxe/XenTimerDxe.inf => LocalApicTimerDxe/LocalApicTimerDxe.inf} (86%)

diff --git a/OvmfPkg/XenTimerDxe/XenTimerDxe.c b/OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.c
similarity index 92%
rename from OvmfPkg/XenTimerDxe/XenTimerDxe.c
rename to OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.c
index bbd964eb7ad9..6376b5a49343 100644
--- a/OvmfPkg/XenTimerDxe/XenTimerDxe.c
+++ b/OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.c
@@ -8,7 +8,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
 
 **/
 
-#include "XenTimerDxe.h"
+#include "LocalApicTimerDxe.h"
 
 //
 // The handle onto which the Timer Architectural Protocol will be installed
@@ -54,8 +54,8 @@ volatile UINT64  mTimerPeriod = 0;
 VOID
 EFIAPI
 TimerInterruptHandler (
-  IN EFI_EXCEPTION_TYPE  InterruptType,
-  IN EFI_SYSTEM_CONTEXT  SystemContext
+  IN EFI_EXCEPTION_TYPE InterruptType,
+  IN EFI_SYSTEM_CONTEXT SystemContext
   )
 {
   EFI_TPL  OriginalTPL;
@@ -109,8 +109,8 @@ TimerInterruptHandler (
 EFI_STATUS
 EFIAPI
 TimerDriverRegisterHandler (
-  IN EFI_TIMER_ARCH_PROTOCOL  *This,
-  IN EFI_TIMER_NOTIFY         NotifyFunction
+  IN EFI_TIMER_ARCH_PROTOCOL *This,
+  IN EFI_TIMER_NOTIFY        NotifyFunction
   )
 {
   //
@@ -160,8 +160,8 @@ TimerDriverRegisterHandler (
 EFI_STATUS
 EFIAPI
 TimerDriverSetTimerPeriod (
-  IN EFI_TIMER_ARCH_PROTOCOL  *This,
-  IN UINT64                   TimerPeriod
+  IN EFI_TIMER_ARCH_PROTOCOL *This,
+  IN UINT64                  TimerPeriod
   )
 {
   UINT64  TimerCount;
@@ -231,8 +231,8 @@ TimerDriverSetTimerPeriod (
 EFI_STATUS
 EFIAPI
 TimerDriverGetTimerPeriod (
-  IN EFI_TIMER_ARCH_PROTOCOL  *This,
-  OUT UINT64                  *TimerPeriod
+  IN EFI_TIMER_ARCH_PROTOCOL *This,
+  OUT UINT64                 *TimerPeriod
   )
 {
   if (TimerPeriod == NULL) {
@@ -264,7 +264,7 @@ TimerDriverGetTimerPeriod (
 EFI_STATUS
 EFIAPI
 TimerDriverGenerateSoftInterrupt (
-  IN EFI_TIMER_ARCH_PROTOCOL  *This
+  IN EFI_TIMER_ARCH_PROTOCOL *This
   )
 {
   EFI_TPL  OriginalTPL;
@@ -304,8 +304,8 @@ TimerDriverGenerateSoftInterrupt (
 EFI_STATUS
 EFIAPI
 TimerDriverInitialize (
-  IN EFI_HANDLE        ImageHandle,
-  IN EFI_SYSTEM_TABLE  *SystemTable
+  IN EFI_HANDLE       ImageHandle,
+  IN EFI_SYSTEM_TABLE *SystemTable
   )
 {
   EFI_STATUS  Status;
diff --git a/OvmfPkg/XenTimerDxe/XenTimerDxe.h b/OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.h
similarity index 91%
rename from OvmfPkg/XenTimerDxe/XenTimerDxe.h
rename to OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.h
index b55ece0d941e..a68b7b4c4bc4 100644
--- a/OvmfPkg/XenTimerDxe/XenTimerDxe.h
+++ b/OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.h
@@ -7,8 +7,8 @@ Copyright (c) 2019, Citrix Systems, Inc.
 SPDX-License-Identifier: BSD-2-Clause-Patent
 **/
 
-#ifndef _TIMER_H_
-#define _TIMER_H_
+#ifndef LOCAL_APIC_TIMER_H_
+#define LOCAL_APIC_TIMER_H_
 
 #include <PiDxe.h>
 
@@ -50,8 +50,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
 EFI_STATUS
 EFIAPI
 TimerDriverInitialize (
-  IN EFI_HANDLE        ImageHandle,
-  IN EFI_SYSTEM_TABLE  *SystemTable
+  IN EFI_HANDLE       ImageHandle,
+  IN EFI_SYSTEM_TABLE *SystemTable
   )
 ;
 
@@ -86,8 +86,8 @@ TimerDriverInitialize (
 EFI_STATUS
 EFIAPI
 TimerDriverRegisterHandler (
-  IN EFI_TIMER_ARCH_PROTOCOL  *This,
-  IN EFI_TIMER_NOTIFY         NotifyFunction
+  IN EFI_TIMER_ARCH_PROTOCOL *This,
+  IN EFI_TIMER_NOTIFY        NotifyFunction
   )
 ;
 
@@ -122,8 +122,8 @@ TimerDriverRegisterHandler (
 EFI_STATUS
 EFIAPI
 TimerDriverSetTimerPeriod (
-  IN EFI_TIMER_ARCH_PROTOCOL  *This,
-  IN UINT64                   TimerPeriod
+  IN EFI_TIMER_ARCH_PROTOCOL *This,
+  IN UINT64                  TimerPeriod
   )
 ;
 
@@ -146,8 +146,8 @@ TimerDriverSetTimerPeriod (
 EFI_STATUS
 EFIAPI
 TimerDriverGetTimerPeriod (
-  IN EFI_TIMER_ARCH_PROTOCOL  *This,
-  OUT UINT64                  *TimerPeriod
+  IN EFI_TIMER_ARCH_PROTOCOL *This,
+  OUT UINT64                 *TimerPeriod
   )
 ;
 
@@ -171,7 +171,7 @@ TimerDriverGetTimerPeriod (
 EFI_STATUS
 EFIAPI
 TimerDriverGenerateSoftInterrupt (
-  IN EFI_TIMER_ARCH_PROTOCOL  *This
+  IN EFI_TIMER_ARCH_PROTOCOL *This
   )
 ;
 
diff --git a/OvmfPkg/XenTimerDxe/XenTimerDxe.inf b/OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
similarity index 86%
rename from OvmfPkg/XenTimerDxe/XenTimerDxe.inf
rename to OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
index add1d01bbf9c..63b75b75c921 100644
--- a/OvmfPkg/XenTimerDxe/XenTimerDxe.inf
+++ b/OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
@@ -10,7 +10,7 @@
 
 [Defines]
   INF_VERSION                    = 0x00010005
-  BASE_NAME                      = XenTimerDxe
+  BASE_NAME                      = LocalApicTimerDxe
   FILE_GUID                      = 52fe8196-f9de-4d07-b22f-51f77a0e7c41
   MODULE_TYPE                    = DXE_DRIVER
   VERSION_STRING                 = 1.0
@@ -30,8 +30,8 @@
   LocalApicLib
 
 [Sources]
-  XenTimerDxe.h
-  XenTimerDxe.c
+  LocalApicTimerDxe.h
+  LocalApicTimerDxe.c
 
 [Protocols]
   gEfiCpuArchProtocolGuid       ## CONSUMES
diff --git a/OvmfPkg/Microvm/MicrovmX64.dsc b/OvmfPkg/Microvm/MicrovmX64.dsc
index 5f4d9226791b..8fdb583877dd 100644
--- a/OvmfPkg/Microvm/MicrovmX64.dsc
+++ b/OvmfPkg/Microvm/MicrovmX64.dsc
@@ -658,7 +658,7 @@
 
   MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf
   MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
-  OvmfPkg/XenTimerDxe/XenTimerDxe.inf
+  OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
   UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
   UefiCpuPkg/CpuDxe/CpuDxe.inf
   OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
diff --git a/OvmfPkg/Microvm/MicrovmX64.fdf b/OvmfPkg/Microvm/MicrovmX64.fdf
index 4570bc866c9b..3b8370a15dff 100644
--- a/OvmfPkg/Microvm/MicrovmX64.fdf
+++ b/OvmfPkg/Microvm/MicrovmX64.fdf
@@ -215,7 +215,7 @@ INF  MdeModulePkg/Universal/PCD/Dxe/Pcd.inf
 INF  MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.inf
 INF  MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf
 INF  MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
-INF  OvmfPkg/XenTimerDxe/XenTimerDxe.inf
+INF  OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
 INF  UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
 INF  UefiCpuPkg/CpuDxe/CpuDxe.inf
 INF  OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
diff --git a/OvmfPkg/OvmfXen.dsc b/OvmfPkg/OvmfXen.dsc
index de0d30bfb807..91e011f78404 100644
--- a/OvmfPkg/OvmfXen.dsc
+++ b/OvmfPkg/OvmfXen.dsc
@@ -554,7 +554,7 @@
   MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf
 
   MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
-  OvmfPkg/XenTimerDxe/XenTimerDxe.inf
+  OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
   UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
   UefiCpuPkg/CpuDxe/CpuDxe.inf
   OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
diff --git a/OvmfPkg/OvmfXen.fdf b/OvmfPkg/OvmfXen.fdf
index a6acf3b835aa..8e9c6721f183 100644
--- a/OvmfPkg/OvmfXen.fdf
+++ b/OvmfPkg/OvmfXen.fdf
@@ -298,7 +298,7 @@ INF  MdeModulePkg/Universal/PCD/Dxe/Pcd.inf
 INF  MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.inf
 INF  MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf
 INF  MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
-INF  OvmfPkg/XenTimerDxe/XenTimerDxe.inf
+INF  OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
 INF  UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
 INF  UefiCpuPkg/CpuDxe/CpuDxe.inf
 INF  OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
-- 
2.29.2.windows.2


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

* [PATCH V4 29/31] UefiCpuPkg: Setting initial-count register as the last step
  2021-12-13 12:56 [PATCH V4 00/31] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (27 preceding siblings ...)
  2021-12-13 12:56 ` [PATCH V4 28/31] OvmfPkg: Rename XenTimerDxe to LocalApicTimerDxe Min Xu
@ 2021-12-13 12:57 ` Min Xu
  2021-12-15  9:20   ` Gerd Hoffmann
  2021-12-13 12:57 ` [PATCH V4 30/31] OvmfPkg: Switch timer in build time for OvmfPkg Min Xu
  2021-12-13 12:57 ` [PATCH V4 31/31] OvmfPkg: Move LocalApicTimerDxe to UefiCpuPkg Min Xu
  30 siblings, 1 reply; 68+ messages in thread
From: Min Xu @ 2021-12-13 12:57 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Jiewen Yao, Gerd Hoffmann, Anthony Perard, Julien Grall,
	Eric Dong, Ray Ni

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

Per SDM, changing the mode of APIC timer (from one-shot to periodic or
vice versa) by writing to the timer LVT entry does not start the timer.
To start the timer, it is necessary to write to the initial-count
register.

If initial-count is wrote before mode change, it's possible that timer
expired before the mode change. Thus failing the periodic mode.

Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Anthony Perard <anthony.perard@citrix.com>
Cc: Julien Grall <julien@xen.org>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 .../Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c    | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c b/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c
index 2d17177df12b..f26d9c93894f 100644
--- a/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c
+++ b/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c
@@ -967,11 +967,6 @@ InitializeApicTimer (
   //
   InitializeLocalApicSoftwareEnable (TRUE);
 
-  //
-  // Program init-count register.
-  //
-  WriteLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET, InitCount);
-
   if (DivideValue != 0) {
     ASSERT (DivideValue <= 128);
     ASSERT (DivideValue == GetPowerOfTwo32 ((UINT32)DivideValue));
@@ -996,6 +991,11 @@ InitializeApicTimer (
   LvtTimer.Bits.Mask   = 0;
   LvtTimer.Bits.Vector = Vector;
   WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);
+
+  //
+  // Program init-count register.
+  //
+  WriteLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET, InitCount);
 }
 
 /**
-- 
2.29.2.windows.2


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

* [PATCH V4 30/31] OvmfPkg: Switch timer in build time for OvmfPkg
  2021-12-13 12:56 [PATCH V4 00/31] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (28 preceding siblings ...)
  2021-12-13 12:57 ` [PATCH V4 29/31] UefiCpuPkg: Setting initial-count register as the last step Min Xu
@ 2021-12-13 12:57 ` Min Xu
  2021-12-15  9:21   ` Gerd Hoffmann
  2021-12-13 12:57 ` [PATCH V4 31/31] OvmfPkg: Move LocalApicTimerDxe to UefiCpuPkg Min Xu
  30 siblings, 1 reply; 68+ messages in thread
From: Min Xu @ 2021-12-13 12:57 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=3711

Discussion in https://bugzilla.tianocore.org/show_bug.cgi?id=1496 shows
that 8254TimerDxe was not written for OVMF. It was moved over from
PcAtChipsetPkg to OvmfPkg in 2019.  Probably because OVMF was the only
user left.

Most likely the reason OVMF used 8254TimerDxe initially was that it could
just use the existing driver in PcAtChipsetPkg.  And it simply hasn't
been changed ever.

CSM support was moved in 2019 too. (CSM support depends on 8254/8259
drivers). So 8254TimerDxe will be used when CSM_ENABLE=TRUE.

There are 4 .dsc which include the 8254Timer.
 - OvmfPkg/AmdSev/AmdSevX64.dsc
 - OvmfPkg/OvmfPkgIa32.dsc
 - OvmfPkg/OvmfPkgIa32X64.dsc
 - OvmfPkg/OvmfPkgX64.dsc

For the three OvmfPkg* configs using 8254TimerDxe with CSM_ENABLE=TRUE
and LapicTimerDxe otherwise.

For the AmdSev config it doesn't make sense to support a CSM. So use
the lapic timer unconditionally.

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>
Suggested-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/AmdSev/AmdSevX64.dsc                    |  5 +++--
 OvmfPkg/AmdSev/AmdSevX64.fdf                    |  3 +--
 OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.c   |  2 +-
 OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf |  1 +
 OvmfPkg/OvmfPkgIa32.dsc                         | 10 +++++++++-
 OvmfPkg/OvmfPkgIa32.fdf                         |  8 ++++++--
 OvmfPkg/OvmfPkgIa32X64.dsc                      | 10 +++++++++-
 OvmfPkg/OvmfPkgIa32X64.fdf                      |  8 ++++++--
 OvmfPkg/OvmfPkgX64.dsc                          | 10 +++++++++-
 OvmfPkg/OvmfPkgX64.fdf                          |  8 ++++++--
 10 files changed, 51 insertions(+), 14 deletions(-)

diff --git a/OvmfPkg/AmdSev/AmdSevX64.dsc b/OvmfPkg/AmdSev/AmdSevX64.dsc
index 59bd17f31b28..6c53c805e824 100644
--- a/OvmfPkg/AmdSev/AmdSevX64.dsc
+++ b/OvmfPkg/AmdSev/AmdSevX64.dsc
@@ -584,6 +584,8 @@
   gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid|{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
 !endif
 
+  gEfiMdePkgTokenSpaceGuid.PcdFSBClock|100000000
+
 [PcdsDynamicHii]
 !if $(TPM_ENABLE) == TRUE && $(TPM_CONFIG_ENABLE) == TRUE
   gEfiSecurityPkgTokenSpaceGuid.PcdTcgPhysicalPresenceInterfaceVer|L"TCG2_VERSION"|gTcg2ConfigFormSetGuid|0x0|"1.3"|NV,BS
@@ -675,10 +677,9 @@
   }
 
   MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
-  OvmfPkg/8259InterruptControllerDxe/8259.inf
   UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
   UefiCpuPkg/CpuDxe/CpuDxe.inf
-  OvmfPkg/8254TimerDxe/8254Timer.inf
+  OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
   OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
   OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
   MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf {
diff --git a/OvmfPkg/AmdSev/AmdSevX64.fdf b/OvmfPkg/AmdSev/AmdSevX64.fdf
index b25035c164eb..77e391f2106a 100644
--- a/OvmfPkg/AmdSev/AmdSevX64.fdf
+++ b/OvmfPkg/AmdSev/AmdSevX64.fdf
@@ -206,10 +206,9 @@ INF  MdeModulePkg/Universal/PCD/Dxe/Pcd.inf
 INF  MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.inf
 INF  MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf
 INF  MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
-INF  OvmfPkg/8259InterruptControllerDxe/8259.inf
 INF  UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
 INF  UefiCpuPkg/CpuDxe/CpuDxe.inf
-INF  OvmfPkg/8254TimerDxe/8254Timer.inf
+INF  OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
 INF  OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
 INF  OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
 INF  MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
diff --git a/OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.c b/OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.c
index 6376b5a49343..98610ebd3b06 100644
--- a/OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.c
+++ b/OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.c
@@ -174,7 +174,7 @@ TimerDriverSetTimerPeriod (
     //
     DisableApicTimerInterrupt ();
   } else {
-    TimerFrequency = PcdGet32 (PcdFSBClock) / DivideValue;
+    TimerFrequency = PcdGet32 (PcdFSBClock) / (UINT32)DivideValue;
 
     //
     // Convert TimerPeriod into local APIC counts
diff --git a/OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf b/OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
index 63b75b75c921..3ad28a148c5b 100644
--- a/OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
+++ b/OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
@@ -1,5 +1,6 @@
 ## @file
 # Local APIC timer driver that provides Timer Arch protocol.
+# PcdFSBClock is defined in MdePkg and it should be set by the consumer.
 #
 # Copyright (c) 2005 - 2019, Intel Corporation. All rights reserved.<BR>
 # Copyright (c) 2019, Citrix Systems, Inc.
diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
index 26c7f536522e..ff5b9d707341 100644
--- a/OvmfPkg/OvmfPkgIa32.dsc
+++ b/OvmfPkg/OvmfPkgIa32.dsc
@@ -657,6 +657,10 @@
   # Set ConfidentialComputing defaults
   gEfiMdePkgTokenSpaceGuid.PcdConfidentialComputingGuestAttr|0
 
+!if $(CSM_ENABLE) == FALSE
+  gEfiMdePkgTokenSpaceGuid.PcdFSBClock|100000000
+!endif
+
 [PcdsDynamicHii]
 !if $(TPM_ENABLE) == TRUE && $(TPM_CONFIG_ENABLE) == TRUE
   gEfiSecurityPkgTokenSpaceGuid.PcdTcgPhysicalPresenceInterfaceVer|L"TCG2_VERSION"|gTcg2ConfigFormSetGuid|0x0|"1.3"|NV,BS
@@ -760,10 +764,14 @@
   }
 
   MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
-  OvmfPkg/8259InterruptControllerDxe/8259.inf
   UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
   UefiCpuPkg/CpuDxe/CpuDxe.inf
+!ifdef $(CSM_ENABLE)
+  OvmfPkg/8259InterruptControllerDxe/8259.inf
   OvmfPkg/8254TimerDxe/8254Timer.inf
+!else
+  OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
+!endif
   OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
   OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
   MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf {
diff --git a/OvmfPkg/OvmfPkgIa32.fdf b/OvmfPkg/OvmfPkgIa32.fdf
index cc73180729b6..9e2e90763714 100644
--- a/OvmfPkg/OvmfPkgIa32.fdf
+++ b/OvmfPkg/OvmfPkgIa32.fdf
@@ -212,10 +212,14 @@ INF  MdeModulePkg/Universal/PCD/Dxe/Pcd.inf
 INF  MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.inf
 INF  MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf
 INF  MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
-INF  OvmfPkg/8259InterruptControllerDxe/8259.inf
 INF  UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
 INF  UefiCpuPkg/CpuDxe/CpuDxe.inf
-INF  OvmfPkg/8254TimerDxe/8254Timer.inf
+!ifdef $(CSM_ENABLE)
+  INF OvmfPkg/8259InterruptControllerDxe/8259.inf
+  INF OvmfPkg/8254TimerDxe/8254Timer.inf
+!else
+  INF OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
+!endif
 INF  OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
 INF  OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
 INF  MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index 6f9509de615e..db44a5217f69 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -667,6 +667,10 @@
   # Set ConfidentialComputing defaults
   gEfiMdePkgTokenSpaceGuid.PcdConfidentialComputingGuestAttr|0
 
+!if $(CSM_ENABLE) == FALSE
+  gEfiMdePkgTokenSpaceGuid.PcdFSBClock|100000000
+!endif
+
 [PcdsDynamicDefault.X64]
   # IPv4 and IPv6 PXE Boot support.
   gEfiNetworkPkgTokenSpaceGuid.PcdIPv4PXESupport|0x01
@@ -776,10 +780,14 @@
   }
 
   MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
-  OvmfPkg/8259InterruptControllerDxe/8259.inf
   UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
   UefiCpuPkg/CpuDxe/CpuDxe.inf
+!ifdef $(CSM_ENABLE)
+  OvmfPkg/8259InterruptControllerDxe/8259.inf
   OvmfPkg/8254TimerDxe/8254Timer.inf
+!else
+  OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
+!endif
   OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
   OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
   MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf {
diff --git a/OvmfPkg/OvmfPkgIa32X64.fdf b/OvmfPkg/OvmfPkgIa32X64.fdf
index ad4b1590fa8d..035c439e5237 100644
--- a/OvmfPkg/OvmfPkgIa32X64.fdf
+++ b/OvmfPkg/OvmfPkgIa32X64.fdf
@@ -216,10 +216,14 @@ INF  MdeModulePkg/Universal/PCD/Dxe/Pcd.inf
 INF  MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.inf
 INF  MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf
 INF  MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
-INF  OvmfPkg/8259InterruptControllerDxe/8259.inf
 INF  UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
 INF  UefiCpuPkg/CpuDxe/CpuDxe.inf
-INF  OvmfPkg/8254TimerDxe/8254Timer.inf
+!ifdef $(CSM_ENABLE)
+  INF OvmfPkg/8259InterruptControllerDxe/8259.inf
+  INF OvmfPkg/8254TimerDxe/8254Timer.inf
+!else
+  INF OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
+!endif
 INF  OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
 INF  OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
 INF  MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index 4d23408f1d4c..d1c1dc257797 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -675,6 +675,10 @@
   # Set ConfidentialComputing defaults
   gEfiMdePkgTokenSpaceGuid.PcdConfidentialComputingGuestAttr|0
 
+!if $(CSM_ENABLE) == FALSE
+  gEfiMdePkgTokenSpaceGuid.PcdFSBClock|100000000
+!endif
+
 [PcdsDynamicHii]
 !if $(TPM_ENABLE) == TRUE && $(TPM_CONFIG_ENABLE) == TRUE
   gEfiSecurityPkgTokenSpaceGuid.PcdTcgPhysicalPresenceInterfaceVer|L"TCG2_VERSION"|gTcg2ConfigFormSetGuid|0x0|"1.3"|NV,BS
@@ -778,10 +782,14 @@
   }
 
   MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
-  OvmfPkg/8259InterruptControllerDxe/8259.inf
   UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
   UefiCpuPkg/CpuDxe/CpuDxe.inf
+!ifdef $(CSM_ENABLE)
+  OvmfPkg/8259InterruptControllerDxe/8259.inf
   OvmfPkg/8254TimerDxe/8254Timer.inf
+!else
+  OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
+!endif
   OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
   OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
   MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf {
diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
index 97c966d16a78..c00b61f75c4c 100644
--- a/OvmfPkg/OvmfPkgX64.fdf
+++ b/OvmfPkg/OvmfPkgX64.fdf
@@ -239,10 +239,14 @@ INF  MdeModulePkg/Universal/PCD/Dxe/Pcd.inf
 INF  MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.inf
 INF  MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf
 INF  MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
-INF  OvmfPkg/8259InterruptControllerDxe/8259.inf
 INF  UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
 INF  UefiCpuPkg/CpuDxe/CpuDxe.inf
-INF  OvmfPkg/8254TimerDxe/8254Timer.inf
+!ifdef $(CSM_ENABLE)
+  INF  OvmfPkg/8259InterruptControllerDxe/8259.inf
+  INF  OvmfPkg/8254TimerDxe/8254Timer.inf
+!else
+  INF  OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
+!endif
 INF  OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
 INF  OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
 INF  MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
-- 
2.29.2.windows.2


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

* [PATCH V4 31/31] OvmfPkg: Move LocalApicTimerDxe to UefiCpuPkg
  2021-12-13 12:56 [PATCH V4 00/31] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (29 preceding siblings ...)
  2021-12-13 12:57 ` [PATCH V4 30/31] OvmfPkg: Switch timer in build time for OvmfPkg Min Xu
@ 2021-12-13 12:57 ` Min Xu
  2021-12-15  9:26   ` Gerd Hoffmann
  30 siblings, 1 reply; 68+ messages in thread
From: Min Xu @ 2021-12-13 12:57 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Jiewen Yao, Gerd Hoffmann, Anthony Perard, Julien Grall,
	Eric Dong, Ray Ni

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

OvmfPkg.dec is removed from [Packages] because it doesn't depend
on OvmfPkg. LocalApicTimerDxe is moved to UefiCpuPkg.

Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Anthony Perard <anthony.perard@citrix.com>
Cc: Julien Grall <julien@xen.org>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Acked-by: Anthony Perard <anthony.perard@citrix.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/AmdSev/AmdSevX64.dsc                  |  2 +-
 OvmfPkg/AmdSev/AmdSevX64.fdf                  |  2 +-
 OvmfPkg/Microvm/MicrovmX64.dsc                |  2 +-
 OvmfPkg/Microvm/MicrovmX64.fdf                |  2 +-
 OvmfPkg/OvmfPkgIa32.dsc                       |  2 +-
 OvmfPkg/OvmfPkgIa32.fdf                       |  2 +-
 OvmfPkg/OvmfPkgIa32X64.dsc                    |  2 +-
 OvmfPkg/OvmfPkgIa32X64.fdf                    |  2 +-
 OvmfPkg/OvmfPkgX64.dsc                        |  2 +-
 OvmfPkg/OvmfPkgX64.fdf                        |  2 +-
 OvmfPkg/OvmfXen.dsc                           |  2 +-
 OvmfPkg/OvmfXen.fdf                           |  2 +-
 .../LocalApicTimerDxe/LocalApicTimerDxe.c     | 33 +++++++++----------
 .../LocalApicTimerDxe/LocalApicTimerDxe.h     | 18 +++++-----
 .../LocalApicTimerDxe/LocalApicTimerDxe.inf   | 17 ++++++++--
 UefiCpuPkg/UefiCpuPkg.dsc                     |  1 +
 16 files changed, 52 insertions(+), 41 deletions(-)
 rename {OvmfPkg => UefiCpuPkg}/LocalApicTimerDxe/LocalApicTimerDxe.c (91%)
 rename {OvmfPkg => UefiCpuPkg}/LocalApicTimerDxe/LocalApicTimerDxe.h (92%)
 rename {OvmfPkg => UefiCpuPkg}/LocalApicTimerDxe/LocalApicTimerDxe.inf (62%)

diff --git a/OvmfPkg/AmdSev/AmdSevX64.dsc b/OvmfPkg/AmdSev/AmdSevX64.dsc
index 6c53c805e824..b2636febee3d 100644
--- a/OvmfPkg/AmdSev/AmdSevX64.dsc
+++ b/OvmfPkg/AmdSev/AmdSevX64.dsc
@@ -679,7 +679,7 @@
   MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
   UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
   UefiCpuPkg/CpuDxe/CpuDxe.inf
-  OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
+  UefiCpuPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
   OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
   OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
   MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf {
diff --git a/OvmfPkg/AmdSev/AmdSevX64.fdf b/OvmfPkg/AmdSev/AmdSevX64.fdf
index 77e391f2106a..b3691e79e552 100644
--- a/OvmfPkg/AmdSev/AmdSevX64.fdf
+++ b/OvmfPkg/AmdSev/AmdSevX64.fdf
@@ -208,7 +208,7 @@ INF  MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf
 INF  MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
 INF  UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
 INF  UefiCpuPkg/CpuDxe/CpuDxe.inf
-INF  OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
+INF  UefiCpuPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
 INF  OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
 INF  OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
 INF  MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
diff --git a/OvmfPkg/Microvm/MicrovmX64.dsc b/OvmfPkg/Microvm/MicrovmX64.dsc
index 8fdb583877dd..7e5c131d39b3 100644
--- a/OvmfPkg/Microvm/MicrovmX64.dsc
+++ b/OvmfPkg/Microvm/MicrovmX64.dsc
@@ -658,7 +658,7 @@
 
   MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf
   MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
-  OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
+  UefiCpuPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
   UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
   UefiCpuPkg/CpuDxe/CpuDxe.inf
   OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
diff --git a/OvmfPkg/Microvm/MicrovmX64.fdf b/OvmfPkg/Microvm/MicrovmX64.fdf
index 3b8370a15dff..62827b23e485 100644
--- a/OvmfPkg/Microvm/MicrovmX64.fdf
+++ b/OvmfPkg/Microvm/MicrovmX64.fdf
@@ -215,7 +215,7 @@ INF  MdeModulePkg/Universal/PCD/Dxe/Pcd.inf
 INF  MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.inf
 INF  MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf
 INF  MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
-INF  OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
+INF  UefiCpuPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
 INF  UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
 INF  UefiCpuPkg/CpuDxe/CpuDxe.inf
 INF  OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
index ff5b9d707341..a1192c24f6e0 100644
--- a/OvmfPkg/OvmfPkgIa32.dsc
+++ b/OvmfPkg/OvmfPkgIa32.dsc
@@ -770,7 +770,7 @@
   OvmfPkg/8259InterruptControllerDxe/8259.inf
   OvmfPkg/8254TimerDxe/8254Timer.inf
 !else
-  OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
+  UefiCpuPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
 !endif
   OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
   OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
diff --git a/OvmfPkg/OvmfPkgIa32.fdf b/OvmfPkg/OvmfPkgIa32.fdf
index 9e2e90763714..c90580bc1341 100644
--- a/OvmfPkg/OvmfPkgIa32.fdf
+++ b/OvmfPkg/OvmfPkgIa32.fdf
@@ -218,7 +218,7 @@ INF  UefiCpuPkg/CpuDxe/CpuDxe.inf
   INF OvmfPkg/8259InterruptControllerDxe/8259.inf
   INF OvmfPkg/8254TimerDxe/8254Timer.inf
 !else
-  INF OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
+  INF UefiCpuPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
 !endif
 INF  OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
 INF  OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index db44a5217f69..ee390c064547 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -786,7 +786,7 @@
   OvmfPkg/8259InterruptControllerDxe/8259.inf
   OvmfPkg/8254TimerDxe/8254Timer.inf
 !else
-  OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
+  UefiCpuPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
 !endif
   OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
   OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
diff --git a/OvmfPkg/OvmfPkgIa32X64.fdf b/OvmfPkg/OvmfPkgIa32X64.fdf
index 035c439e5237..7c88850bd7f2 100644
--- a/OvmfPkg/OvmfPkgIa32X64.fdf
+++ b/OvmfPkg/OvmfPkgIa32X64.fdf
@@ -222,7 +222,7 @@ INF  UefiCpuPkg/CpuDxe/CpuDxe.inf
   INF OvmfPkg/8259InterruptControllerDxe/8259.inf
   INF OvmfPkg/8254TimerDxe/8254Timer.inf
 !else
-  INF OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
+  INF UefiCpuPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
 !endif
 INF  OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
 INF  OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index d1c1dc257797..771fa9da13e9 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -788,7 +788,7 @@
   OvmfPkg/8259InterruptControllerDxe/8259.inf
   OvmfPkg/8254TimerDxe/8254Timer.inf
 !else
-  OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
+  UefiCpuPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
 !endif
   OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
   OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
index c00b61f75c4c..72da93586c8f 100644
--- a/OvmfPkg/OvmfPkgX64.fdf
+++ b/OvmfPkg/OvmfPkgX64.fdf
@@ -245,7 +245,7 @@ INF  UefiCpuPkg/CpuDxe/CpuDxe.inf
   INF  OvmfPkg/8259InterruptControllerDxe/8259.inf
   INF  OvmfPkg/8254TimerDxe/8254Timer.inf
 !else
-  INF  OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
+  INF  UefiCpuPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
 !endif
 INF  OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
 INF  OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
diff --git a/OvmfPkg/OvmfXen.dsc b/OvmfPkg/OvmfXen.dsc
index 91e011f78404..f82c3adfe69c 100644
--- a/OvmfPkg/OvmfXen.dsc
+++ b/OvmfPkg/OvmfXen.dsc
@@ -554,7 +554,7 @@
   MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf
 
   MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
-  OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
+  UefiCpuPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
   UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
   UefiCpuPkg/CpuDxe/CpuDxe.inf
   OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
diff --git a/OvmfPkg/OvmfXen.fdf b/OvmfPkg/OvmfXen.fdf
index 8e9c6721f183..ac615f66b84e 100644
--- a/OvmfPkg/OvmfXen.fdf
+++ b/OvmfPkg/OvmfXen.fdf
@@ -298,7 +298,7 @@ INF  MdeModulePkg/Universal/PCD/Dxe/Pcd.inf
 INF  MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.inf
 INF  MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf
 INF  MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
-INF  OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
+INF  UefiCpuPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
 INF  UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
 INF  UefiCpuPkg/CpuDxe/CpuDxe.inf
 INF  OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
diff --git a/OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.c b/UefiCpuPkg/LocalApicTimerDxe/LocalApicTimerDxe.c
similarity index 91%
rename from OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.c
rename to UefiCpuPkg/LocalApicTimerDxe/LocalApicTimerDxe.c
index 98610ebd3b06..5dce7a3223aa 100644
--- a/OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.c
+++ b/UefiCpuPkg/LocalApicTimerDxe/LocalApicTimerDxe.c
@@ -54,8 +54,8 @@ volatile UINT64  mTimerPeriod = 0;
 VOID
 EFIAPI
 TimerInterruptHandler (
-  IN EFI_EXCEPTION_TYPE InterruptType,
-  IN EFI_SYSTEM_CONTEXT SystemContext
+  IN EFI_EXCEPTION_TYPE  InterruptType,
+  IN EFI_SYSTEM_CONTEXT  SystemContext
   )
 {
   EFI_TPL  OriginalTPL;
@@ -63,9 +63,6 @@ TimerInterruptHandler (
   OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL);
 
   if (mTimerNotifyFunction != NULL) {
-    //
-    // @bug : This does not handle missed timer interrupts
-    //
     mTimerNotifyFunction (mTimerPeriod);
   }
 
@@ -109,8 +106,8 @@ TimerInterruptHandler (
 EFI_STATUS
 EFIAPI
 TimerDriverRegisterHandler (
-  IN EFI_TIMER_ARCH_PROTOCOL *This,
-  IN EFI_TIMER_NOTIFY        NotifyFunction
+  IN EFI_TIMER_ARCH_PROTOCOL  *This,
+  IN EFI_TIMER_NOTIFY         NotifyFunction
   )
 {
   //
@@ -160,8 +157,8 @@ TimerDriverRegisterHandler (
 EFI_STATUS
 EFIAPI
 TimerDriverSetTimerPeriod (
-  IN EFI_TIMER_ARCH_PROTOCOL *This,
-  IN UINT64                  TimerPeriod
+  IN EFI_TIMER_ARCH_PROTOCOL  *This,
+  IN UINT64                   TimerPeriod
   )
 {
   UINT64  TimerCount;
@@ -169,6 +166,11 @@ TimerDriverSetTimerPeriod (
   UINT32  DivideValue = 1;
 
   if (TimerPeriod == 0) {
+    //
+    // Stop the timer
+    //
+    InitializeApicTimer (0, 0, FALSE, LOCAL_APIC_TIMER_VECTOR);
+
     //
     // Disable timer interrupt for a TimerPeriod of 0
     //
@@ -231,8 +233,8 @@ TimerDriverSetTimerPeriod (
 EFI_STATUS
 EFIAPI
 TimerDriverGetTimerPeriod (
-  IN EFI_TIMER_ARCH_PROTOCOL *This,
-  OUT UINT64                 *TimerPeriod
+  IN EFI_TIMER_ARCH_PROTOCOL  *This,
+  OUT UINT64                  *TimerPeriod
   )
 {
   if (TimerPeriod == NULL) {
@@ -264,7 +266,7 @@ TimerDriverGetTimerPeriod (
 EFI_STATUS
 EFIAPI
 TimerDriverGenerateSoftInterrupt (
-  IN EFI_TIMER_ARCH_PROTOCOL *This
+  IN EFI_TIMER_ARCH_PROTOCOL  *This
   )
 {
   EFI_TPL  OriginalTPL;
@@ -276,9 +278,6 @@ TimerDriverGenerateSoftInterrupt (
     OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL);
 
     if (mTimerNotifyFunction != NULL) {
-      //
-      // @bug : This does not handle missed timer interrupts
-      //
       mTimerNotifyFunction (mTimerPeriod);
     }
 
@@ -304,8 +303,8 @@ TimerDriverGenerateSoftInterrupt (
 EFI_STATUS
 EFIAPI
 TimerDriverInitialize (
-  IN EFI_HANDLE       ImageHandle,
-  IN EFI_SYSTEM_TABLE *SystemTable
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
   )
 {
   EFI_STATUS  Status;
diff --git a/OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.h b/UefiCpuPkg/LocalApicTimerDxe/LocalApicTimerDxe.h
similarity index 92%
rename from OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.h
rename to UefiCpuPkg/LocalApicTimerDxe/LocalApicTimerDxe.h
index a68b7b4c4bc4..93706995f8ab 100644
--- a/OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.h
+++ b/UefiCpuPkg/LocalApicTimerDxe/LocalApicTimerDxe.h
@@ -50,8 +50,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
 EFI_STATUS
 EFIAPI
 TimerDriverInitialize (
-  IN EFI_HANDLE       ImageHandle,
-  IN EFI_SYSTEM_TABLE *SystemTable
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
   )
 ;
 
@@ -86,8 +86,8 @@ TimerDriverInitialize (
 EFI_STATUS
 EFIAPI
 TimerDriverRegisterHandler (
-  IN EFI_TIMER_ARCH_PROTOCOL *This,
-  IN EFI_TIMER_NOTIFY        NotifyFunction
+  IN EFI_TIMER_ARCH_PROTOCOL  *This,
+  IN EFI_TIMER_NOTIFY         NotifyFunction
   )
 ;
 
@@ -122,8 +122,8 @@ TimerDriverRegisterHandler (
 EFI_STATUS
 EFIAPI
 TimerDriverSetTimerPeriod (
-  IN EFI_TIMER_ARCH_PROTOCOL *This,
-  IN UINT64                  TimerPeriod
+  IN EFI_TIMER_ARCH_PROTOCOL  *This,
+  IN UINT64                   TimerPeriod
   )
 ;
 
@@ -146,8 +146,8 @@ TimerDriverSetTimerPeriod (
 EFI_STATUS
 EFIAPI
 TimerDriverGetTimerPeriod (
-  IN EFI_TIMER_ARCH_PROTOCOL *This,
-  OUT UINT64                 *TimerPeriod
+  IN EFI_TIMER_ARCH_PROTOCOL  *This,
+  OUT UINT64                  *TimerPeriod
   )
 ;
 
@@ -171,7 +171,7 @@ TimerDriverGetTimerPeriod (
 EFI_STATUS
 EFIAPI
 TimerDriverGenerateSoftInterrupt (
-  IN EFI_TIMER_ARCH_PROTOCOL *This
+  IN EFI_TIMER_ARCH_PROTOCOL  *This
   )
 ;
 
diff --git a/OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf b/UefiCpuPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
similarity index 62%
rename from OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
rename to UefiCpuPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
index 3ad28a148c5b..9980085fc776 100644
--- a/OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
+++ b/UefiCpuPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
@@ -1,6 +1,13 @@
 ## @file
 # Local APIC timer driver that provides Timer Arch protocol.
-# PcdFSBClock is defined in MdePkg and it should be set by the consumer.
+#
+# This driver is to support fixed frequency. If a real platform happens
+# to have fixed frequency, then it can be used. In this case the consumer
+# should set PcdFSBClock which is defined in MdePkg.
+#
+# Another restriction is that LocalApicTimerDxe cannot coexist with
+# SourceLevelDebug (which rely on Local Apic Timer). Anyone who choose
+# this driver as the DXE timer dirver should be aware of it.
 #
 # Copyright (c) 2005 - 2019, Intel Corporation. All rights reserved.<BR>
 # Copyright (c) 2019, Citrix Systems, Inc.
@@ -15,13 +22,17 @@
   FILE_GUID                      = 52fe8196-f9de-4d07-b22f-51f77a0e7c41
   MODULE_TYPE                    = DXE_DRIVER
   VERSION_STRING                 = 1.0
-
   ENTRY_POINT                    = TimerDriverInitialize
 
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64
+#
+
 [Packages]
   MdePkg/MdePkg.dec
   UefiCpuPkg/UefiCpuPkg.dec
-  OvmfPkg/OvmfPkg.dec
 
 [LibraryClasses]
   UefiBootServicesTableLib
diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc
index 870b45284087..00cf1286a3ca 100644
--- a/UefiCpuPkg/UefiCpuPkg.dsc
+++ b/UefiCpuPkg/UefiCpuPkg.dsc
@@ -172,6 +172,7 @@
   }
   UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume2Pei.inf
   UefiCpuPkg/ResetVector/Vtf0/Bin/ResetVector.inf
+  UefiCpuPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
 
 [BuildOptions]
   *_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES
-- 
2.29.2.windows.2


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

* Re: [PATCH V4 02/31] MdePkg: Introduce basic Tdx functions in BaseLib
  2021-12-13 12:56 ` [PATCH V4 02/31] MdePkg: Introduce basic Tdx functions in BaseLib Min Xu
@ 2021-12-15  6:33   ` Gerd Hoffmann
  0 siblings, 0 replies; 68+ messages in thread
From: Gerd Hoffmann @ 2021-12-15  6:33 UTC (permalink / raw)
  To: Min Xu
  Cc: devel, Michael D Kinney, Liming Gao, Zhiguang Liu, Brijesh Singh,
	Erdem Aktas, James Bottomley, Jiewen Yao, Tom Lendacky

On Mon, Dec 13, 2021 at 08:56:33PM +0800, Min Xu wrote:
> 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>
> Signed-off-by: Min Xu <min.m.xu@intel.com>

Acked-by: Gerd Hoffmann <kraxel@redhat.com>


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

* Re: [PATCH V4 03/31] MdePkg: Add TdxLib to wrap Tdx operations
  2021-12-13 12:56 ` [PATCH V4 03/31] MdePkg: Add TdxLib to wrap Tdx operations Min Xu
@ 2021-12-15  6:44   ` Gerd Hoffmann
  0 siblings, 0 replies; 68+ messages in thread
From: Gerd Hoffmann @ 2021-12-15  6:44 UTC (permalink / raw)
  To: Min Xu
  Cc: devel, Michael D Kinney, Liming Gao, Zhiguang Liu, Brijesh Singh,
	Erdem Aktas, James Bottomley, Jiewen Yao, Tom Lendacky

On Mon, Dec 13, 2021 at 08:56:34PM +0800, Min Xu wrote:
> 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>
> Signed-off-by: Min Xu <min.m.xu@intel.com>

Acked-by: Gerd Hoffmann <kraxel@redhat.com>


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

* Re: [edk2-devel] [PATCH V4 05/31] OvmfPkg: Extend VmgExitLib to handle #VE exception
  2021-12-13 12:56 ` [PATCH V4 05/31] OvmfPkg: Extend VmgExitLib " Min Xu
@ 2021-12-15  6:56   ` Gerd Hoffmann
  2022-01-20  6:34     ` Min Xu
  0 siblings, 1 reply; 68+ messages in thread
From: Gerd Hoffmann @ 2021-12-15  6:56 UTC (permalink / raw)
  To: devel, min.m.xu
  Cc: Ard Biesheuvel, Jiewen Yao, Jordan Justen, Brijesh Singh,
	Erdem Aktas, James Bottomley, Tom Lendacky

On Mon, Dec 13, 2021 at 08:56:36PM +0800, Min Xu wrote:
> 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.
> 
> PcdIgnoreVeHalt is created in OvmfPkg.dec to ignore the VE halt.

Why this is useful?

> +  X64/TdVmcallCpuid.nasm

Hmm, why not simply call the functions added by patch #2?

take care,
  Gerd


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

* Re: [PATCH V4 08/31] MdePkg: Support mmio for Tdx guest in BaseIoLibIntrinsic
  2021-12-13 12:56 ` [PATCH V4 08/31] MdePkg: Support mmio " Min Xu
@ 2021-12-15  7:02   ` Gerd Hoffmann
  0 siblings, 0 replies; 68+ messages in thread
From: Gerd Hoffmann @ 2021-12-15  7:02 UTC (permalink / raw)
  To: Min Xu
  Cc: devel, Michael D Kinney, Liming Gao, Zhiguang Liu, Brijesh Singh,
	Erdem Aktas, James Bottomley, Jiewen Yao, Tom Lendacky

On Mon, Dec 13, 2021 at 08:56:39PM +0800, Min Xu wrote:
> 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.

Acked-by: Gerd Hoffmann <kraxel@redhat.com>

take care,
  Gerd


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

* Re: [PATCH V4 09/31] MdePkg: Support IoFifo for Tdx guest in BaseIoLibIntrinsic
  2021-12-13 12:56 ` [PATCH V4 09/31] MdePkg: Support IoFifo " Min Xu
@ 2021-12-15  7:18   ` Gerd Hoffmann
  0 siblings, 0 replies; 68+ messages in thread
From: Gerd Hoffmann @ 2021-12-15  7:18 UTC (permalink / raw)
  To: Min Xu
  Cc: devel, Michael D Kinney, Liming Gao, Zhiguang Liu, Brijesh Singh,
	Erdem Aktas, James Bottomley, Jiewen Yao, Tom Lendacky

  Hi,

> +VOID
> +EFIAPI
> +IoReadFifo8 (
> +  IN      UINTN  Port,
> +  IN      UINTN  Count,
> +  OUT     VOID   *Buffer
> +  )
> +{
> +  if (IsTdxGuest ()) {
> +    TdIoReadFifo8 (Port, Count, Buffer);
> +  } else {
> +    SevIoReadFifo8 (Port, Count, Buffer);
> +  }
> +}

Hmm, this is confusing.  IMHO handling the native case should be moved
out of SevIoReadFifo8 and the check done in this function, i.e. have
something like this here:

  switch (GuestType) {
  case TDX: TdIoReadFifo8(); break;
  case SEV: SevIoReadFifo8(); break;
  default:  NativeIoReadFifo8(); break;
  }

Given this is an existing issue in current sev support code:
Acked-by: Gerd Hoffmann <kraxel@redhat.com>

Brijesh?  Can take care please (probably best after this landed)?

thanks & take care,
  Gerd


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

* Re: [PATCH V4 10/31] MdePkg: Support IoRead/IoWrite for Tdx guest in BaseIoLibIntrinsic
  2021-12-13 12:56 ` [PATCH V4 10/31] MdePkg: Support IoRead/IoWrite " Min Xu
@ 2021-12-15  7:18   ` Gerd Hoffmann
  0 siblings, 0 replies; 68+ messages in thread
From: Gerd Hoffmann @ 2021-12-15  7:18 UTC (permalink / raw)
  To: Min Xu
  Cc: devel, Michael D Kinney, Liming Gao, Zhiguang Liu, Brijesh Singh,
	Erdem Aktas, James Bottomley, Jiewen Yao, Tom Lendacky

On Mon, Dec 13, 2021 at 08:56:41PM +0800, Min Xu wrote:
> 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>
> Signed-off-by: Min Xu <min.m.xu@intel.com>

Acked-by: Gerd Hoffmann <kraxel@redhat.com>


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

* Re: [PATCH V4 13/31] UefiCpuPkg: Enable Tdx support in MpInitLib
  2021-12-13 12:56 ` [PATCH V4 13/31] UefiCpuPkg: Enable Tdx support in MpInitLib Min Xu
@ 2021-12-15  7:33   ` Gerd Hoffmann
  0 siblings, 0 replies; 68+ messages in thread
From: Gerd Hoffmann @ 2021-12-15  7:33 UTC (permalink / raw)
  To: Min Xu
  Cc: devel, Brijesh Singh, Erdem Aktas, James Bottomley, Jiewen Yao,
	Tom Lendacky, Eric Dong, Ray Ni, Rahul Kumar

On Mon, Dec 13, 2021 at 08:56:44PM +0800, 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. The processor info is retrieved by
> TDCALL, ApWorker is not supported, BSP is always the working processor,
> while the APs are just in a wait-for-precedure state.

Acked-by: Gerd Hoffmann <kraxel@redhat.com>

take care,
  Gerd


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

* Re: [PATCH V4 14/31] OvmfPkg: Add IntelTdx.h in OvmfPkg/Include/IndustryStandard
  2021-12-13 12:56 ` [PATCH V4 14/31] OvmfPkg: Add IntelTdx.h in OvmfPkg/Include/IndustryStandard Min Xu
@ 2021-12-15  7:37   ` Gerd Hoffmann
  2021-12-16  6:43     ` Min Xu
  0 siblings, 1 reply; 68+ messages in thread
From: Gerd Hoffmann @ 2021-12-15  7:37 UTC (permalink / raw)
  To: Min Xu
  Cc: devel, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky

> +++ b/OvmfPkg/Include/IndustryStandard/IntelTdx.h
> @@ -0,0 +1,76 @@
> +/** @file
> +  Defines the defitions used by TDX in OvmfPkg.

Add pointer to the specs here?

take care,
  Gerd


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

* Re: [PATCH V4 15/31] OvmfPkg: Add TdxMailboxLib
  2021-12-13 12:56 ` [PATCH V4 15/31] OvmfPkg: Add TdxMailboxLib Min Xu
@ 2021-12-15  7:47   ` Gerd Hoffmann
  0 siblings, 0 replies; 68+ messages in thread
From: Gerd Hoffmann @ 2021-12-15  7:47 UTC (permalink / raw)
  To: Min Xu
  Cc: devel, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky

On Mon, Dec 13, 2021 at 08:56:46PM +0800, Min Xu wrote:
> 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>
> Signed-off-by: Min Xu <min.m.xu@intel.com>

Acked-by: Gerd Hoffmann <kraxel@redhat.com>


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

* Re: [PATCH V4 17/31] OvmfPkg: Update Sec to support Tdx
  2021-12-13 12:56 ` [PATCH V4 17/31] OvmfPkg: Update Sec to support Tdx Min Xu
@ 2021-12-15  8:18   ` Gerd Hoffmann
  2021-12-16  8:11     ` [edk2-devel] " Min Xu
  0 siblings, 1 reply; 68+ messages in thread
From: Gerd Hoffmann @ 2021-12-15  8:18 UTC (permalink / raw)
  To: Min Xu
  Cc: devel, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky

> +EFI_STATUS
> +EFIAPI
> +BspAcceptMemoryResourceRange (
> +  IN EFI_PHYSICAL_ADDRESS  PhysicalAddress,
> +  IN EFI_PHYSICAL_ADDRESS  PhysicalEnd
> +  )
> +{
> +  EFI_STATUS  Status;
> +  UINT32      AcceptPageSize;
> +  UINT64      StartAddress1;
> +  UINT64      StartAddress2;
> +  UINT64      StartAddress3;
> +  UINT64      TotalLength;
> +  UINT64      Length1;
> +  UINT64      Length2;
> +  UINT64      Length3;
> +  UINT64      Pages;
> +
> +  AcceptPageSize = FixedPcdGet32 (PcdTdxAcceptPageSize);
> +  TotalLength    = PhysicalEnd - PhysicalAddress;
> +  StartAddress1  = 0;
> +  StartAddress2  = 0;
> +  StartAddress3  = 0;
> +  Length1        = 0;
> +  Length2        = 0;
> +  Length3        = 0;
> +
> +  if (TotalLength == 0) {
> +    return EFI_SUCCESS;
> +  }
> +
> +  if ((AcceptPageSize == SIZE_4KB) || (TotalLength <= SIZE_2MB)) {
> +    //
> +    // if total length is less than 2M, then we accept pages in 4k
> +    //
> +    StartAddress1  = 0;
> +    Length1        = 0;
> +    StartAddress2  = PhysicalAddress;
> +    Length2        = PhysicalEnd - PhysicalAddress;
> +    StartAddress3  = 0;
> +    Length3        = 0;
> +    AcceptPageSize = SIZE_4KB;

You've zero-initialized everything above, no need to do that again.
You also can just use StartAddress1 + Length1 which uses 4k pages
anyway.

> +  } else if (AcceptPageSize == SIZE_2MB) {
> +    //
> +    // Total length is bigger than 2M and Page Accept size 2M is supported.
> +    //
> +    if ((PhysicalAddress & ALIGNED_2MB_MASK) == 0) {

The logic is rather messy.  It should become much simpler if you update
PhysicalAddress and TotalLength.  You can also use the alignment macros.

    if (ALIGN_VALUE(PhysicalAddress, SIZE_2MB) != PhysicalAddress) {
        StartAddress1 = PhysicalAddress;
        Length1 = ALIGN_VALUE(PhysicalAddress, SIZE_2MB) - PhysicalAddress;
        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;
    }

take care,
  Gerd


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

* Re: [PATCH V4 18/31] OvmfPkg: Check Tdx in QemuFwCfgPei to avoid DMA operation
  2021-12-13 12:56 ` [PATCH V4 18/31] OvmfPkg: Check Tdx in QemuFwCfgPei to avoid DMA operation Min Xu
@ 2021-12-15  8:19   ` Gerd Hoffmann
  0 siblings, 0 replies; 68+ messages in thread
From: Gerd Hoffmann @ 2021-12-15  8:19 UTC (permalink / raw)
  To: Min Xu
  Cc: devel, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky

On Mon, Dec 13, 2021 at 08:56:49PM +0800, Min Xu wrote:
> 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>
> Signed-off-by: Min Xu <min.m.xu@intel.com>

Acked-by: Gerd Hoffmann <kraxel@redhat.com>


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

* Re: [PATCH V4 20/31] MdeModulePkg: Add PcdTdxSharedBitMask
  2021-12-13 12:56 ` [PATCH V4 20/31] MdeModulePkg: Add PcdTdxSharedBitMask Min Xu
@ 2021-12-15  8:22   ` Gerd Hoffmann
  0 siblings, 0 replies; 68+ messages in thread
From: Gerd Hoffmann @ 2021-12-15  8:22 UTC (permalink / raw)
  To: Min Xu
  Cc: devel, Jian J Wang, Hao A Wu, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky

On Mon, Dec 13, 2021 at 08:56:51PM +0800, Min Xu wrote:
> 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.

Acked-by: Gerd Hoffmann <kraxel@redhat.com>


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

* Re: [PATCH V4 21/31] UefiCpuPkg: Update AddressEncMask in CpuPageTable
  2021-12-13 12:56 ` [PATCH V4 21/31] UefiCpuPkg: Update AddressEncMask in CpuPageTable Min Xu
@ 2021-12-15  8:38   ` Gerd Hoffmann
  2021-12-16  8:23     ` Min Xu
  0 siblings, 1 reply; 68+ messages in thread
From: Gerd Hoffmann @ 2021-12-15  8:38 UTC (permalink / raw)
  To: Min Xu
  Cc: devel, Brijesh Singh, Erdem Aktas, James Bottomley, Jiewen Yao,
	Tom Lendacky, Eric Dong, Ray Ni, Rahul Kumar

> @@ -357,6 +360,7 @@ GetPageTableEntry (
>  
>    // 4k
>    L1PageTable = (UINT64 *)(UINTN)(L2PageTable[Index2] & ~AddressEncMask & PAGING_4K_ADDRESS_MASK_64);
> +
>    if ((L1PageTable[Index1] == 0) && (Address != 0)) {

Hmm?

With that dropped:
Acked-by: Gerd Hoffmann <kraxel@redhat.com>

take care,
  Gerd


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

* Re: [PATCH V4 22/31] OvmfPkg: Update PlatformPei to support TDX
  2021-12-13 12:56 ` [PATCH V4 22/31] OvmfPkg: Update PlatformPei to support TDX Min Xu
@ 2021-12-15  8:53   ` Gerd Hoffmann
  2022-01-20  9:07     ` [edk2-devel] " Min Xu
  2022-01-13 19:18   ` Vishal Annapurve
  1 sibling, 1 reply; 68+ messages in thread
From: Gerd Hoffmann @ 2021-12-15  8:53 UTC (permalink / raw)
  To: Min Xu
  Cc: devel, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky

> +/**
> +  Check if it is Tdx guest
> +
> +  @retval    TRUE   It is Tdx guest
> +  @retval    FALSE  It is not Tdx guest
> +**/
> +BOOLEAN
> +PlatformPeiIsTdxGuest (
> +  VOID
> +  )
> +{
> +  CONFIDENTIAL_COMPUTING_WORK_AREA_HEADER  *CcWorkAreaHeader;
> +
> +  CcWorkAreaHeader = (CONFIDENTIAL_COMPUTING_WORK_AREA_HEADER *)FixedPcdGet32 (PcdOvmfWorkAreaBase);
> +  return (CcWorkAreaHeader != NULL && CcWorkAreaHeader->GuestType == GUEST_TYPE_INTEL_TDX);
> +}

fwcfg patch adds a similar function.  Can't we have a single function
somewhere, or have a #define for this check, instead of doing this
cut+paste programming?

> +VOID
> +EFIAPI
> +DEBUG_HOBLIST (
> +  IN CONST VOID  *HobStart
> +  )
> +{
> +  EFI_PEI_HOB_POINTERS  Hob;
> +
> +  Hob.Raw = (UINT8 *)HobStart;
> +  //
> +  // Parse the HOB list until end of list or matching type is found.
> +  //
> +  while (!END_OF_HOB_LIST (Hob)) {
> +    DEBUG ((DEBUG_INFO, "HOB(%p) : %x %x\n", Hob, Hob.Header->HobType, Hob.Header->HobLength));
> +    switch (Hob.Header->HobType) {
> +      case EFI_HOB_TYPE_RESOURCE_DESCRIPTOR:
> +        DEBUG ((
> +          DEBUG_INFO,
> +          "\t: %x %x %llx %llx\n",
> +          Hob.ResourceDescriptor->ResourceType,
> +          Hob.ResourceDescriptor->ResourceAttribute,
> +          Hob.ResourceDescriptor->PhysicalStart,
> +          Hob.ResourceDescriptor->ResourceLength
> +          ));
> +
> +        break;
> +      case EFI_HOB_TYPE_MEMORY_ALLOCATION:
> +        DEBUG ((
> +          DEBUG_INFO,
> +          "\t: %llx %llx %x\n",
> +          Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress,
> +          Hob.MemoryAllocation->AllocDescriptor.MemoryLength,
> +          Hob.MemoryAllocation->AllocDescriptor.MemoryType
> +          ));
> +        break;
> +      default:
> +        break;
> +    }
> +
> +    Hob.Raw = GET_NEXT_HOB (Hob);
> +  }
> +}

Likewise, I've seen this before in another patch of this series.

> diff --git a/OvmfPkg/PlatformPei/MemDetect.c b/OvmfPkg/PlatformPei/MemDetect.c
> index 934d5c196570..9227fa260ccd 100644
> --- a/OvmfPkg/PlatformPei/MemDetect.c
> +++ b/OvmfPkg/PlatformPei/MemDetect.c
> @@ -36,6 +36,7 @@ Module Name:
>  #include <Library/MtrrLib.h>
>  #include <Library/QemuFwCfgLib.h>
>  #include <Library/QemuFwCfgSimpleParserLib.h>
> +#include <Library/TdxLib.h>
>  
>  #include "Platform.h"
>  #include "Cmos.h"
> @@ -556,7 +557,19 @@ AddressWidthInitialization (
>      mPhysMemAddressWidth = 36;
>    }
>  
> + #if defined (MDE_CPU_X64)
> +  if (PlatformPeiIsTdxGuest ()) {
> +    if (TdSharedPageMask () == (1ULL << 47)) {
> +      mPhysMemAddressWidth = 48;
> +    } else {
> +      mPhysMemAddressWidth = 52;
> +    }
> +  }
> +
> +  ASSERT (mPhysMemAddressWidth <= 52);
> + #else

Making this TDX-specific looks wrong to me.  5-level paging exists
outside TDX too.

Given we don't support 5-level paging (yet) I think we can just drop
this and revisit in case 5-level paging support is added in the future.

> +  UINT32   Pml5Entries;

Same here.

take care,
  Gerd


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

* Re: [PATCH V4 23/31] OvmfPkg: Update AcpiPlatformDxe to alter MADT table
  2021-12-13 12:56 ` [PATCH V4 23/31] OvmfPkg: Update AcpiPlatformDxe to alter MADT table Min Xu
@ 2021-12-15  8:54   ` Gerd Hoffmann
  0 siblings, 0 replies; 68+ messages in thread
From: Gerd Hoffmann @ 2021-12-15  8:54 UTC (permalink / raw)
  To: Min Xu
  Cc: devel, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky

On Mon, Dec 13, 2021 at 08:56:54PM +0800, Min Xu wrote:
> RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
> 
> 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].
> 
> To maintain the simplicity of the AcpiPlatformDxe, the MADT ACPI table
> will be altered in another driver (TdxDxe) by installing a protocol
> to notify that the ACPI table provided by Qemu is ready. Then in TdxDxe
> a notification functioin will be called to alter the MADT table to recorded
> the mailbox address.
> 
> The protocol is gQemuAcpiTableNotifyProtocolGuid.

Acked-by: Gerd Hoffmann <kraxel@redhat.com>

take care,
  Gerd


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

* Re: [PATCH V4 24/31] OvmfPkg: Add TdxDxe driver
  2021-12-13 12:56 ` [PATCH V4 24/31] OvmfPkg: Add TdxDxe driver Min Xu
@ 2021-12-15  9:05   ` Gerd Hoffmann
  0 siblings, 0 replies; 68+ messages in thread
From: Gerd Hoffmann @ 2021-12-15  9:05 UTC (permalink / raw)
  To: Min Xu
  Cc: devel, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky

On Mon, Dec 13, 2021 at 08:56:55PM +0800, 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>
> Signed-off-by: Min Xu <min.m.xu@intel.com>

Acked-by: Gerd Hoffmann <kraxel@redhat.com>

take care,
  Gerd


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

* Re: [PATCH V4 25/31] OvmfPkg/BaseMemEncryptTdxLib: Add TDX helper library
  2021-12-13 12:56 ` [PATCH V4 25/31] OvmfPkg/BaseMemEncryptTdxLib: Add TDX helper library Min Xu
@ 2021-12-15  9:16   ` Gerd Hoffmann
  2022-01-21  2:54     ` Min Xu
  0 siblings, 1 reply; 68+ messages in thread
From: Gerd Hoffmann @ 2021-12-15  9:16 UTC (permalink / raw)
  To: Min Xu
  Cc: devel, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky

> +++ b/OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemoryEncryptionNull.c
> @@ -0,0 +1,90 @@
> +/** @file
> +
> +  Virtual Memory Management Services to set or clear the memory encryption
> +
> +  Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
> +  Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +  Code is derived from MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c

Can we move most of the code to a (x64) page table library instead of
cut+pasting like this, please?

Brijesh: BaseMemEncryptSevLib is in the same boat.

take care,
  Gerd


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

* Re: [PATCH V4 26/31] OvmfPkg/QemuFwCfgLib: Support Tdx in QemuFwCfgDxe
  2021-12-13 12:56 ` [PATCH V4 26/31] OvmfPkg/QemuFwCfgLib: Support Tdx in QemuFwCfgDxe Min Xu
@ 2021-12-15  9:16   ` Gerd Hoffmann
  0 siblings, 0 replies; 68+ messages in thread
From: Gerd Hoffmann @ 2021-12-15  9:16 UTC (permalink / raw)
  To: Min Xu
  Cc: devel, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky

On Mon, Dec 13, 2021 at 08:56:57PM +0800, Min Xu wrote:
> RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
> 
> In the previous QemuFwCfgDxe only SEV is supported. This commit
> introduce TDX support in QemuFwCfgDxe.
> 
> 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>
> Signed-off-by: Min Xu <min.m.xu@intel.com>

Acked-by: Gerd Hoffmann <kraxel@redhat.com>

take care,
  Gerd


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

* Re: [PATCH V4 27/31] OvmfPkg: Update IoMmuDxe to support TDX
  2021-12-13 12:56 ` [PATCH V4 27/31] OvmfPkg: Update IoMmuDxe to support TDX Min Xu
@ 2021-12-15  9:18   ` Gerd Hoffmann
  0 siblings, 0 replies; 68+ messages in thread
From: Gerd Hoffmann @ 2021-12-15  9:18 UTC (permalink / raw)
  To: Min Xu
  Cc: devel, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky

On Mon, Dec 13, 2021 at 08:56:58PM +0800, Min Xu wrote:
> RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
> 
> The IOMMU protocol driver provides capabilities to set a DMA access
> attribute and methods to allocate, free, map and unmap the DMA memory
> for the PCI Bus devices.
> 
> The current IoMmuDxe driver supports DMA operations inside SEV guest.
> To support DMA operation in TDX guest,
> CC_GUEST_IS_XXX (PcdConfidentialComputingGuestAttr) is used to determine
> if it is SEV guest or TDX guest.
> 
> Due to security reasons all DMA operations inside the SEV/TDX guest must
> be performed on shared pages. The IOMMU protocol driver for the SEV/TDX
> guest uses a bounce buffer to map guest DMA buffer to shared pages in
> order to provide the support for DMA operations inside SEV/TDX guest.
> 
> The call of SEV or TDX specific function to set/clear EncMask/SharedBit
> is determined by CC_GUEST_IS_XXX (PcdConfidentialComputingGuestAttr).
> 
> 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>
> Signed-off-by: Min Xu <min.m.xu@intel.com>

Acked-by: Gerd Hoffmann <kraxel@redhat.com>


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

* Re: [PATCH V4 28/31] OvmfPkg: Rename XenTimerDxe to LocalApicTimerDxe
  2021-12-13 12:56 ` [PATCH V4 28/31] OvmfPkg: Rename XenTimerDxe to LocalApicTimerDxe Min Xu
@ 2021-12-15  9:19   ` Gerd Hoffmann
  0 siblings, 0 replies; 68+ messages in thread
From: Gerd Hoffmann @ 2021-12-15  9:19 UTC (permalink / raw)
  To: Min Xu
  Cc: devel, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky, Anthony Perard,
	Julien Grall

On Mon, Dec 13, 2021 at 08:56:59PM +0800, Min Xu wrote:
> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3711
> 
> XenTimerDxe is a local Apic timer driver and it has nothing to do
> with Xen. So rename it to LocalApicTimerDxe.
> 
> 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: Anthony Perard <anthony.perard@citrix.com>
> Cc: Julien Grall <julien@xen.org>
> Acked-by: Anthony PERARD <anthony.perard@citrix.com
> Signed-off-by: Min Xu <min.m.xu@intel.com>

Acked-by: Gerd Hoffmann <kraxel@redhat.com>


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

* Re: [PATCH V4 29/31] UefiCpuPkg: Setting initial-count register as the last step
  2021-12-13 12:57 ` [PATCH V4 29/31] UefiCpuPkg: Setting initial-count register as the last step Min Xu
@ 2021-12-15  9:20   ` Gerd Hoffmann
  0 siblings, 0 replies; 68+ messages in thread
From: Gerd Hoffmann @ 2021-12-15  9:20 UTC (permalink / raw)
  To: Min Xu; +Cc: devel, Jiewen Yao, Anthony Perard, Julien Grall, Eric Dong,
	Ray Ni

On Mon, Dec 13, 2021 at 08:57:00PM +0800, Min Xu wrote:
> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3711
> 
> Per SDM, changing the mode of APIC timer (from one-shot to periodic or
> vice versa) by writing to the timer LVT entry does not start the timer.
> To start the timer, it is necessary to write to the initial-count
> register.
> 
> If initial-count is wrote before mode change, it's possible that timer
> expired before the mode change. Thus failing the periodic mode.
> 
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Gerd Hoffmann <kraxel@redhat.com>
> Cc: Anthony Perard <anthony.perard@citrix.com>
> Cc: Julien Grall <julien@xen.org>
> Cc: Eric Dong <eric.dong@intel.com>
> Cc: Ray Ni <ray.ni@intel.com>
> Signed-off-by: Min Xu <min.m.xu@intel.com>

Acked-by: Gerd Hoffmann <kraxel@redhat.com>


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

* Re: [PATCH V4 30/31] OvmfPkg: Switch timer in build time for OvmfPkg
  2021-12-13 12:57 ` [PATCH V4 30/31] OvmfPkg: Switch timer in build time for OvmfPkg Min Xu
@ 2021-12-15  9:21   ` Gerd Hoffmann
  0 siblings, 0 replies; 68+ messages in thread
From: Gerd Hoffmann @ 2021-12-15  9:21 UTC (permalink / raw)
  To: Min Xu
  Cc: devel, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky

On Mon, Dec 13, 2021 at 08:57:01PM +0800, Min Xu wrote:
> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3711
> 
> Discussion in https://bugzilla.tianocore.org/show_bug.cgi?id=1496 shows
> that 8254TimerDxe was not written for OVMF. It was moved over from
> PcAtChipsetPkg to OvmfPkg in 2019.  Probably because OVMF was the only
> user left.
> 
> Most likely the reason OVMF used 8254TimerDxe initially was that it could
> just use the existing driver in PcAtChipsetPkg.  And it simply hasn't
> been changed ever.
> 
> CSM support was moved in 2019 too. (CSM support depends on 8254/8259
> drivers). So 8254TimerDxe will be used when CSM_ENABLE=TRUE.
> 
> There are 4 .dsc which include the 8254Timer.
>  - OvmfPkg/AmdSev/AmdSevX64.dsc
>  - OvmfPkg/OvmfPkgIa32.dsc
>  - OvmfPkg/OvmfPkgIa32X64.dsc
>  - OvmfPkg/OvmfPkgX64.dsc
> 
> For the three OvmfPkg* configs using 8254TimerDxe with CSM_ENABLE=TRUE
> and LapicTimerDxe otherwise.
> 
> For the AmdSev config it doesn't make sense to support a CSM. So use
> the lapic timer unconditionally.
> 
> 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>
> Suggested-by: Gerd Hoffmann <kraxel@redhat.com>
> Signed-off-by: Min Xu <min.m.xu@intel.com>

Acked-by: Gerd Hoffmann <kraxel@redhat.com>


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

* Re: [PATCH V4 31/31] OvmfPkg: Move LocalApicTimerDxe to UefiCpuPkg
  2021-12-13 12:57 ` [PATCH V4 31/31] OvmfPkg: Move LocalApicTimerDxe to UefiCpuPkg Min Xu
@ 2021-12-15  9:26   ` Gerd Hoffmann
  2021-12-16  8:29     ` [edk2-devel] " Min Xu
  0 siblings, 1 reply; 68+ messages in thread
From: Gerd Hoffmann @ 2021-12-15  9:26 UTC (permalink / raw)
  To: Min Xu; +Cc: devel, Jiewen Yao, Anthony Perard, Julien Grall, Eric Dong,
	Ray Ni

On Mon, Dec 13, 2021 at 08:57:02PM +0800, Min Xu wrote:
> BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3711
> 
> OvmfPkg.dec is removed from [Packages] because it doesn't depend
> on OvmfPkg. LocalApicTimerDxe is moved to UefiCpuPkg.

>    if (mTimerNotifyFunction != NULL) {
> -    //
> -    // @bug : This does not handle missed timer interrupts
> -    //
>      mTimerNotifyFunction (mTimerPeriod);
>    }

>    if (TimerPeriod == 0) {
> +    //
> +    // Stop the timer
> +    //
> +    InitializeApicTimer (0, 0, FALSE, LOCAL_APIC_TIMER_VECTOR);
> +

This is more than a pure move.
Functional changes should be a separate patch.

>  TimerDriverGetTimerPeriod (
> -  IN EFI_TIMER_ARCH_PROTOCOL *This,
> -  OUT UINT64                 *TimerPeriod
> +  IN EFI_TIMER_ARCH_PROTOCOL  *This,
> +  OUT UINT64                  *TimerPeriod

What's this?  uncrustify?
Reformating should be a separate patch too.

take care,
  Gerd


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

* Re: [PATCH V4 14/31] OvmfPkg: Add IntelTdx.h in OvmfPkg/Include/IndustryStandard
  2021-12-15  7:37   ` Gerd Hoffmann
@ 2021-12-16  6:43     ` Min Xu
  0 siblings, 0 replies; 68+ messages in thread
From: Min Xu @ 2021-12-16  6:43 UTC (permalink / raw)
  To: Gerd Hoffmann
  Cc: devel@edk2.groups.io, Ard Biesheuvel, Justen, Jordan L,
	Brijesh Singh, Aktas, Erdem, James Bottomley, Yao, Jiewen,
	Tom Lendacky

Hi
> 
> Add pointer to the specs here?
> 
Sure, spec links will be added. Thanks for reminder.

Min

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

* Re: [edk2-devel] [PATCH V4 17/31] OvmfPkg: Update Sec to support Tdx
  2021-12-15  8:18   ` Gerd Hoffmann
@ 2021-12-16  8:11     ` Min Xu
  0 siblings, 0 replies; 68+ messages in thread
From: Min Xu @ 2021-12-16  8:11 UTC (permalink / raw)
  To: devel@edk2.groups.io, kraxel@redhat.com
  Cc: Ard Biesheuvel, Justen, Jordan L, Brijesh Singh, Aktas, Erdem,
	James Bottomley, Yao, Jiewen, Tom Lendacky

Hi
> > +EFI_STATUS
> > +EFIAPI
> > +BspAcceptMemoryResourceRange (
> > +  IN EFI_PHYSICAL_ADDRESS  PhysicalAddress,
> > +  IN EFI_PHYSICAL_ADDRESS  PhysicalEnd
> > +  )
> > +{
> > +  EFI_STATUS  Status;
> > +  UINT32      AcceptPageSize;
> > +  UINT64      StartAddress1;
> > +  UINT64      StartAddress2;
> > +  UINT64      StartAddress3;
> > +  UINT64      TotalLength;
> > +  UINT64      Length1;
> > +  UINT64      Length2;
> > +  UINT64      Length3;
> > +  UINT64      Pages;
> > +
> > +  AcceptPageSize = FixedPcdGet32 (PcdTdxAcceptPageSize);
> > +  TotalLength    = PhysicalEnd - PhysicalAddress;
> > +  StartAddress1  = 0;
> > +  StartAddress2  = 0;
> > +  StartAddress3  = 0;
> > +  Length1        = 0;
> > +  Length2        = 0;
> > +  Length3        = 0;
> > +
> > +  if (TotalLength == 0) {
> > +    return EFI_SUCCESS;
> > +  }
> > +
> > +  if ((AcceptPageSize == SIZE_4KB) || (TotalLength <= SIZE_2MB)) {
> > +    //
> > +    // if total length is less than 2M, then we accept pages in 4k
> > +    //
> > +    StartAddress1  = 0;
> > +    Length1        = 0;
> > +    StartAddress2  = PhysicalAddress;
> > +    Length2        = PhysicalEnd - PhysicalAddress;
> > +    StartAddress3  = 0;
> > +    Length3        = 0;
> > +    AcceptPageSize = SIZE_4KB;
> 
> You've zero-initialized everything above, no need to do that again.
Thanks for reminder. It will be updated in the next version.
> You also can just use StartAddress1 + Length1 which uses 4k pages anyway.
In the origin design, StartAddress1+Length1 and StartAddress3+Length3 are for BSP, StartAddress2+Length2 is for BSP/APs. Now only BSP accepts memory. So you're right. We can just use StartAddress1+Length1 which uses 4k pages anyway.
> 
> > +  } else if (AcceptPageSize == SIZE_2MB) {
> > +    //
> > +    // Total length is bigger than 2M and Page Accept size 2M is supported.
> > +    //
> > +    if ((PhysicalAddress & ALIGNED_2MB_MASK) == 0) {
> 
> The logic is rather messy.  It should become much simpler if you update
> PhysicalAddress and TotalLength.  You can also use the alignment macros.
> 
>     if (ALIGN_VALUE(PhysicalAddress, SIZE_2MB) != PhysicalAddress) {
>         StartAddress1 = PhysicalAddress;
>         Length1 = ALIGN_VALUE(PhysicalAddress, SIZE_2MB) - PhysicalAddress;
>         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;
>     }
> 
Thanks for the suggestion. It's better. It will be updated in the next version.

Thanks
Min

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

* Re: [PATCH V4 21/31] UefiCpuPkg: Update AddressEncMask in CpuPageTable
  2021-12-15  8:38   ` Gerd Hoffmann
@ 2021-12-16  8:23     ` Min Xu
  0 siblings, 0 replies; 68+ messages in thread
From: Min Xu @ 2021-12-16  8:23 UTC (permalink / raw)
  To: Gerd Hoffmann
  Cc: devel@edk2.groups.io, Brijesh Singh, Aktas, Erdem,
	James Bottomley, Yao, Jiewen, Tom Lendacky, Dong, Eric, Ni, Ray,
	Kumar, Rahul1

Hi
> > @@ -357,6 +360,7 @@ GetPageTableEntry (
> >
> >    // 4k
> >    L1PageTable = (UINT64 *)(UINTN)(L2PageTable[Index2] & ~AddressEncMask
> & PAGING_4K_ADDRESS_MASK_64);
> > +
> >    if ((L1PageTable[Index1] == 0) && (Address != 0)) {
> 
> Hmm?
The blank line will be dropped.
> 
> With that dropped:
> Acked-by: Gerd Hoffmann <kraxel@redhat.com>
> 
Thanks
Min

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

* Re: [edk2-devel] [PATCH V4 31/31] OvmfPkg: Move LocalApicTimerDxe to UefiCpuPkg
  2021-12-15  9:26   ` Gerd Hoffmann
@ 2021-12-16  8:29     ` Min Xu
  0 siblings, 0 replies; 68+ messages in thread
From: Min Xu @ 2021-12-16  8:29 UTC (permalink / raw)
  To: devel@edk2.groups.io, kraxel@redhat.com
  Cc: Yao, Jiewen, Anthony Perard, Julien Grall, Dong, Eric, Ni, Ray

Hi
> 
> On Mon, Dec 13, 2021 at 08:57:02PM +0800, Min Xu wrote:
> > BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3711
> >
> > OvmfPkg.dec is removed from [Packages] because it doesn't depend on
> > OvmfPkg. LocalApicTimerDxe is moved to UefiCpuPkg.
> 
> >    if (mTimerNotifyFunction != NULL) {
> > -    //
> > -    // @bug : This does not handle missed timer interrupts
> > -    //
> >      mTimerNotifyFunction (mTimerPeriod);
> >    }
> 
> >    if (TimerPeriod == 0) {
> > +    //
> > +    // Stop the timer
> > +    //
> > +    InitializeApicTimer (0, 0, FALSE, LOCAL_APIC_TIMER_VECTOR);
> > +
> 
> This is more than a pure move.
> Functional changes should be a separate patch.
> 
> >  TimerDriverGetTimerPeriod (
> > -  IN EFI_TIMER_ARCH_PROTOCOL *This,
> > -  OUT UINT64                 *TimerPeriod
> > +  IN EFI_TIMER_ARCH_PROTOCOL  *This,
> > +  OUT UINT64                  *TimerPeriod
> 
> What's this?  uncrustify?
> Reformating should be a separate patch too.
> 
Thanks for reminder. It will be in a separate patch.

Min

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

* Re: [edk2-devel] [PATCH V4 22/31] OvmfPkg: Update PlatformPei to support TDX
  2021-12-13 12:56 ` [PATCH V4 22/31] OvmfPkg: Update PlatformPei to support TDX Min Xu
  2021-12-15  8:53   ` Gerd Hoffmann
@ 2022-01-13 19:18   ` Vishal Annapurve
  2022-01-14  2:23     ` Min Xu
  1 sibling, 1 reply; 68+ messages in thread
From: Vishal Annapurve @ 2022-01-13 19:18 UTC (permalink / raw)
  To: Min Xu, devel

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

Hi Min,

> 
> +/**
> + 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_ATTRIBUTE_TYPE ResourceAttribute;
> +
> + //
> + // PcdOvmfSecGhcbBase is used as the TD_HOB in Tdx guest.
> + //
> + Hob.Raw = (UINT8 *)(UINTN)PcdGet32 (PcdOvmfSecGhcbBase);
> + while (!END_OF_HOB_LIST (Hob)) {
> + switch (Hob.Header->HobType) {
> + case EFI_HOB_TYPE_RESOURCE_DESCRIPTOR:
> + ResourceAttribute = Hob.ResourceDescriptor->ResourceAttribute;
> +

I am trying to test TDX functionality with config A patches (Wave1 + Wave2.v4) and with the above function passing the memory attributes of the resources in TD HOB list (Originally populated by VMM) as is to DXE phase,
Function CoreInitializeMemoryServices (from ./MdeModulePkg/Core/Dxe/Gcd/Gcd.c) is not able to find any resources with TESTED_MEMORY_ATTRIBUTES set.

For config A, Is there an expectation from VMM to set TESTED_MEMORY_ATTRIBUTES for each System Memory resource passed via TD HOB list or should this function
be appending TESTED_MEMORY_ATTRIBUTES to existing resource attributes?

Regards,
Vishal

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

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

* Re: [edk2-devel] [PATCH V4 22/31] OvmfPkg: Update PlatformPei to support TDX
  2022-01-13 19:18   ` Vishal Annapurve
@ 2022-01-14  2:23     ` Min Xu
  2022-01-14  2:37       ` Vishal Annapurve
  0 siblings, 1 reply; 68+ messages in thread
From: Min Xu @ 2022-01-14  2:23 UTC (permalink / raw)
  To: devel@edk2.groups.io, vannapurve@google.com

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

Hi, Vishal
TESTED_MEMORY_ATTRIBUTES is expected to be set by host VMM. Please see [TDVF] Table 7-1
[TDVF] https://www.intel.com/content/dam/develop/external/us/en/documents/tdx-virtual-firmware-design-guide-rev-1.01.pdf

Below is the TDVF log (in the very beginning).
   1 Intel Tdx Started with (GPAW: 52, Cpus: 8)
   2
   3 ResourceType: 0x0                       <-- EFI_RESOURCE_SYSTEM_MEMORY
   4 ResourceAttribute: 0x4000007  <-- 7 is TESTED_MEMORY_ATTRIBUTES
   5 PhysicalStart: 0x0
   6 ResourceLength: 0x800000

TransferTdxHobList just copy the ResourceAttribute from host Vmm.

In your mail you mentioned “Function CoreInitializeMemoryServices (from ./MdeModulePkg/Core/Dxe/Gcd/Gcd.c) is not able to find any resources with TESTED_MEMORY_ATTRIBUTES set”.  Can you explain more about it? Have you added some logs?

From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Vishal Annapurve via groups.io
Sent: Friday, January 14, 2022 3:19 AM
To: Xu, Min M <min.m.xu@intel.com>; devel@edk2.groups.io
Subject: Re: [edk2-devel] [PATCH V4 22/31] OvmfPkg: Update PlatformPei to support TDX

Hi Min,
+/**
+ 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_ATTRIBUTE_TYPE ResourceAttribute;
+
+ //
+ // PcdOvmfSecGhcbBase is used as the TD_HOB in Tdx guest.
+ //
+ Hob.Raw = (UINT8 *)(UINTN)PcdGet32 (PcdOvmfSecGhcbBase);
+ while (!END_OF_HOB_LIST (Hob)) {
+ switch (Hob.Header->HobType) {
+ case EFI_HOB_TYPE_RESOURCE_DESCRIPTOR:
+ ResourceAttribute = Hob.ResourceDescriptor->ResourceAttribute;
+
I am trying to test TDX functionality with config A patches (Wave1 + Wave2.v4) and with the above function passing the memory attributes of the resources in TD HOB list (Originally populated by VMM) as is to DXE phase,
Function CoreInitializeMemoryServices (from ./MdeModulePkg/Core/Dxe/Gcd/Gcd.c) is not able to find any resources with TESTED_MEMORY_ATTRIBUTES set.

For config A, Is there an expectation from VMM to set TESTED_MEMORY_ATTRIBUTES for each System Memory resource passed via TD HOB list or should this function
be appending TESTED_MEMORY_ATTRIBUTES to existing resource attributes?

Regards,
Vishal


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

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

* Re: [edk2-devel] [PATCH V4 22/31] OvmfPkg: Update PlatformPei to support TDX
  2022-01-14  2:23     ` Min Xu
@ 2022-01-14  2:37       ` Vishal Annapurve
  2022-01-14  2:40         ` Min Xu
  0 siblings, 1 reply; 68+ messages in thread
From: Vishal Annapurve @ 2022-01-14  2:37 UTC (permalink / raw)
  To: Min Xu, devel

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

Thanks Min for the reference of the firmware design guide.

If VMM is expected to set it then issue I mentioned with CoreInitializeMemoryServices can be ignored.

Though its mentioned in the design guide, I was confused by the current implementation of TDX Qemu as per:
https://github.com/intel/qemu-tdx/blob/tdx/hw/i386/tdvf-hob.c#L169
https://github.com/intel/qemu-tdx/blob/852a069e739a6ffae4f9dec17607a74690b0e4af/hw/i386/tdvf-hob.h#L15

and config B patches:
https://github.com/mxu9/edk2/commit/c5d5786290b2455c5a0a7e3515cf04ec2218d8a4#diff-7cb0d3ac758c9b92166d03049917116ca4a5cb012db99deb491f63c5c5562e0aR124

It's possible that I have incomplete view of Qemu implementation or Config B patches.

Regards,
Vishal

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

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

* Re: [edk2-devel] [PATCH V4 22/31] OvmfPkg: Update PlatformPei to support TDX
  2022-01-14  2:37       ` Vishal Annapurve
@ 2022-01-14  2:40         ` Min Xu
  0 siblings, 0 replies; 68+ messages in thread
From: Min Xu @ 2022-01-14  2:40 UTC (permalink / raw)
  To: devel@edk2.groups.io, vannapurve@google.com

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

Thanks for reminder. It is in-consistent implementation between config-A and config-B. I will fix it in the next version.

From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Vishal Annapurve via groups.io
Sent: Friday, January 14, 2022 10:37 AM
To: Xu, Min M <min.m.xu@intel.com>; devel@edk2.groups.io
Subject: Re: [edk2-devel] [PATCH V4 22/31] OvmfPkg: Update PlatformPei to support TDX

Thanks Min for the reference of the firmware design guide.

If VMM is expected to set it then issue I mentioned with CoreInitializeMemoryServices can be ignored.

Though its mentioned in the design guide, I was confused by the current implementation of TDX Qemu as per:
https://github.com/intel/qemu-tdx/blob/tdx/hw/i386/tdvf-hob.c#L169
https://github.com/intel/qemu-tdx/blob/852a069e739a6ffae4f9dec17607a74690b0e4af/hw/i386/tdvf-hob.h#L15

and config B patches:
https://github.com/mxu9/edk2/commit/c5d5786290b2455c5a0a7e3515cf04ec2218d8a4#diff-7cb0d3ac758c9b92166d03049917116ca4a5cb012db99deb491f63c5c5562e0aR124

It's possible that I have incomplete view of Qemu implementation or Config B patches.

Regards,
Vishal


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

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

* Re: [edk2-devel] [PATCH V4 05/31] OvmfPkg: Extend VmgExitLib to handle #VE exception
  2021-12-15  6:56   ` [edk2-devel] " Gerd Hoffmann
@ 2022-01-20  6:34     ` Min Xu
  0 siblings, 0 replies; 68+ messages in thread
From: Min Xu @ 2022-01-20  6:34 UTC (permalink / raw)
  To: Gerd Hoffmann, devel@edk2.groups.io
  Cc: Ard Biesheuvel, Yao, Jiewen, Justen, Jordan L, Brijesh Singh,
	Aktas, Erdem, James Bottomley, Tom Lendacky

Hi
> > 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.
> >
> > PcdIgnoreVeHalt is created in OvmfPkg.dec to ignore the VE halt.
> 
> Why this is useful?
This Pcd is deprecated. It will be removed in the next version.
> 
> > +  X64/TdVmcallCpuid.nasm
> 
> Hmm, why not simply call the functions added by patch #2?
> 
TdVmcall in patch #2 assumes the returned value is in r11 (if there is returned data). But from [GHCI] spec Table 3-17, TDVMCALL_CPUID returns the values in R12/R13/R14/R15. So there has to be a new TdVmcallCpuid.nasm.
[GHCI] https://www.intel.com/content/dam/develop/external/us/en/documents/intel-tdx-guest-hypervisor-communication-interface-1.0-344426-002.pdf

Thanks
Min

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

* Re: [edk2-devel] [PATCH V4 22/31] OvmfPkg: Update PlatformPei to support TDX
  2021-12-15  8:53   ` Gerd Hoffmann
@ 2022-01-20  9:07     ` Min Xu
  0 siblings, 0 replies; 68+ messages in thread
From: Min Xu @ 2022-01-20  9:07 UTC (permalink / raw)
  To: devel@edk2.groups.io, kraxel@redhat.com
  Cc: Ard Biesheuvel, Justen, Jordan L, Brijesh Singh, Aktas, Erdem,
	James Bottomley, Yao, Jiewen, Tom Lendacky

Hi
> > +/**
> > +  Check if it is Tdx guest
> > +
> > +  @retval    TRUE   It is Tdx guest
> > +  @retval    FALSE  It is not Tdx guest
> > +**/
> > +BOOLEAN
> > +PlatformPeiIsTdxGuest (
> > +  VOID
> > +  )
> > +{
> > +  CONFIDENTIAL_COMPUTING_WORK_AREA_HEADER
> *CcWorkAreaHeader;
> > +
> > +  CcWorkAreaHeader =
> (CONFIDENTIAL_COMPUTING_WORK_AREA_HEADER
> > +*)FixedPcdGet32 (PcdOvmfWorkAreaBase);
> > +  return (CcWorkAreaHeader != NULL && CcWorkAreaHeader->GuestType
> ==
> > +GUEST_TYPE_INTEL_TDX); }
> 
> fwcfg patch adds a similar function.  Can't we have a single function
> somewhere, or have a #define for this check, instead of doing this
> cut+paste programming?
There is TdIsEnabled() in BaseLib. So PlatformPeiIsTdxGuest is deprecated in the next version.
> 
> > +VOID
> > +EFIAPI
> > +DEBUG_HOBLIST (
> > +  IN CONST VOID  *HobStart
> > +  )
> > +{
> > +  EFI_PEI_HOB_POINTERS  Hob;
> > +
> > +  Hob.Raw = (UINT8 *)HobStart;
> > +  //
> > +  // Parse the HOB list until end of list or matching type is found.
> > +  //
> > +  while (!END_OF_HOB_LIST (Hob)) {
> > +    DEBUG ((DEBUG_INFO, "HOB(%p) : %x %x\n", Hob, Hob.Header-
> >HobType, Hob.Header->HobLength));
> > +    switch (Hob.Header->HobType) {
> > +      case EFI_HOB_TYPE_RESOURCE_DESCRIPTOR:
> > +        DEBUG ((
> > +          DEBUG_INFO,
> > +          "\t: %x %x %llx %llx\n",
> > +          Hob.ResourceDescriptor->ResourceType,
> > +          Hob.ResourceDescriptor->ResourceAttribute,
> > +          Hob.ResourceDescriptor->PhysicalStart,
> > +          Hob.ResourceDescriptor->ResourceLength
> > +          ));
> > +
> > +        break;
> > +      case EFI_HOB_TYPE_MEMORY_ALLOCATION:
> > +        DEBUG ((
> > +          DEBUG_INFO,
> > +          "\t: %llx %llx %x\n",
> > +          Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress,
> > +          Hob.MemoryAllocation->AllocDescriptor.MemoryLength,
> > +          Hob.MemoryAllocation->AllocDescriptor.MemoryType
> > +          ));
> > +        break;
> > +      default:
> > +        break;
> > +    }
> > +
> > +    Hob.Raw = GET_NEXT_HOB (Hob);
> > +  }
> > +}
> 
> Likewise, I've seen this before in another patch of this series.
This will be deprecated in the next version.
> 
> > diff --git a/OvmfPkg/PlatformPei/MemDetect.c
> > b/OvmfPkg/PlatformPei/MemDetect.c index 934d5c196570..9227fa260ccd
> > 100644
> > --- a/OvmfPkg/PlatformPei/MemDetect.c
> > +++ b/OvmfPkg/PlatformPei/MemDetect.c
> > @@ -36,6 +36,7 @@ Module Name:
> >  #include <Library/MtrrLib.h>
> >  #include <Library/QemuFwCfgLib.h>
> >  #include <Library/QemuFwCfgSimpleParserLib.h>
> > +#include <Library/TdxLib.h>
> >
> >  #include "Platform.h"
> >  #include "Cmos.h"
> > @@ -556,7 +557,19 @@ AddressWidthInitialization (
> >      mPhysMemAddressWidth = 36;
> >    }
> >
> > + #if defined (MDE_CPU_X64)
> > +  if (PlatformPeiIsTdxGuest ()) {
> > +    if (TdSharedPageMask () == (1ULL << 47)) {
> > +      mPhysMemAddressWidth = 48;
> > +    } else {
> > +      mPhysMemAddressWidth = 52;
> > +    }
> > +  }
> > +
> > +  ASSERT (mPhysMemAddressWidth <= 52); #else
> 
> Making this TDX-specific looks wrong to me.  5-level paging exists outside TDX
> too.
> 
> Given we don't support 5-level paging (yet) I think we can just drop this and
> revisit in case 5-level paging support is added in the future.
> 
> > +  UINT32   Pml5Entries;
> 
> Same here.
mPhysMemAddressWidth indicates the physical memory address width. Tdx guest supports GPAW of 52 or 48. So I think here mPhysMemAddresWidth is correct.
Even mPhysMemAddress is 52, we can still use 4-level paging. So I am going to update GetPeiMemoryCap() like below:

  if (mPhysMemAddressWidth <= 39) {
    Pml4Entries = 1;
    PdpEntries = 1 << (mPhysMemAddressWidth - 30);
    ASSERT (PdpEntries <= 0x200);
  } else {
    if (TdIsEnabled ()) {           <-- If it is td guest, then Pml4Entries is set to 0x200.
      Pml4Entries = 0x200;
    } else {
      Pml4Entries = 1 << (mPhysMemAddressWidth - 39);
    }
    ASSERT (Pml4Entries <= 0x200);
    PdpEntries = 512;
  }

Thanks
Min

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

* Re: [PATCH V4 25/31] OvmfPkg/BaseMemEncryptTdxLib: Add TDX helper library
  2021-12-15  9:16   ` Gerd Hoffmann
@ 2022-01-21  2:54     ` Min Xu
  2022-01-21  8:04       ` Gerd Hoffmann
  0 siblings, 1 reply; 68+ messages in thread
From: Min Xu @ 2022-01-21  2:54 UTC (permalink / raw)
  To: Gerd Hoffmann
  Cc: devel@edk2.groups.io, Ard Biesheuvel, Justen, Jordan L,
	Brijesh Singh, Aktas, Erdem, James Bottomley, Yao, Jiewen,
	Tom Lendacky

Hi
> > +++
> b/OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemoryEncryptionNull.c
> > @@ -0,0 +1,90 @@
> > +/** @file
> > +
> > +  Virtual Memory Management Services to set or clear the memory
> > + encryption
> > +
> > +  Copyright (c) 2006 - 2018, Intel Corporation. All rights
> > + reserved.<BR>  Copyright (c) 2017, AMD Incorporated. All rights
> > + reserved.<BR>
> > +
> > +  SPDX-License-Identifier: BSD-2-Clause-Patent
> > +
> > +  Code is derived from
> > + MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
> 
> Can we move most of the code to a (x64) page table library instead of
> cut+pasting like this, please?
As I explained in https://edk2.groups.io/g/devel/message/85582, there has already been a same feature requirement. https://bugzilla.tianocore.org/show_bug.cgi?id=847 . (Create page table library to abstract all page table manipulations)
I discussed with the feature owner (Ni, Ray).  He said this feature is in his plan of 2022. He suggest I can wait for the library.

Thanks
Min

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

* Re: [PATCH V4 25/31] OvmfPkg/BaseMemEncryptTdxLib: Add TDX helper library
  2022-01-21  2:54     ` Min Xu
@ 2022-01-21  8:04       ` Gerd Hoffmann
  2022-01-21  8:31         ` [edk2-devel] " Min Xu
  0 siblings, 1 reply; 68+ messages in thread
From: Gerd Hoffmann @ 2022-01-21  8:04 UTC (permalink / raw)
  To: Xu, Min M
  Cc: devel@edk2.groups.io, Ard Biesheuvel, Justen, Jordan L,
	Brijesh Singh, Aktas, Erdem, James Bottomley, Yao, Jiewen,
	Tom Lendacky

  Hi,

> > Can we move most of the code to a (x64) page table library instead of
> > cut+pasting like this, please?

> As I explained in https://edk2.groups.io/g/devel/message/85582, there
> has already been a same feature requirement.
> https://bugzilla.tianocore.org/show_bug.cgi?id=847 . (Create page
> table library to abstract all page table manipulations) I discussed
> with the feature owner (Ni, Ray).  He said this feature is in his plan
> of 2022. He suggest I can wait for the library.

Ok.  Can you add a comment to the source code saying this is temporary
until the lib is there, and a link to the bug?

thanks,
  Gerd


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

* Re: [edk2-devel] [PATCH V4 25/31] OvmfPkg/BaseMemEncryptTdxLib: Add TDX helper library
  2022-01-21  8:04       ` Gerd Hoffmann
@ 2022-01-21  8:31         ` Min Xu
  0 siblings, 0 replies; 68+ messages in thread
From: Min Xu @ 2022-01-21  8:31 UTC (permalink / raw)
  To: devel@edk2.groups.io, kraxel@redhat.com
  Cc: Ard Biesheuvel, Justen, Jordan L, Brijesh Singh, Aktas, Erdem,
	James Bottomley, Yao, Jiewen, Tom Lendacky

On January 21, 2022 4:04 PM, Gerd Hoffmann wrote:
> > > Can we move most of the code to a (x64) page table library instead
> > > of
> > > cut+pasting like this, please?
> 
> > As I explained in https://edk2.groups.io/g/devel/message/85582, there
> > has already been a same feature requirement.
> > https://bugzilla.tianocore.org/show_bug.cgi?id=847 . (Create page
> > table library to abstract all page table manipulations) I discussed
> > with the feature owner (Ni, Ray).  He said this feature is in his plan
> > of 2022. He suggest I can wait for the library.
> 
> Ok.  Can you add a comment to the source code saying this is temporary until
> the lib is there, and a link to the bug?
Sure. I will add the comments and thanks for your understanding.

Thanks
Min

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

end of thread, other threads:[~2022-01-21  8:32 UTC | newest]

Thread overview: 68+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2021-12-13 12:56 [PATCH V4 00/31] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
2021-12-13 12:56 ` [PATCH V4 01/31] MdePkg: Add Tdx.h Min Xu
2021-12-13 12:56 ` [PATCH V4 02/31] MdePkg: Introduce basic Tdx functions in BaseLib Min Xu
2021-12-15  6:33   ` Gerd Hoffmann
2021-12-13 12:56 ` [PATCH V4 03/31] MdePkg: Add TdxLib to wrap Tdx operations Min Xu
2021-12-15  6:44   ` Gerd Hoffmann
2021-12-13 12:56 ` [PATCH V4 04/31] UefiCpuPkg: Extend VmgExitLibNull to handle #VE exception Min Xu
2021-12-13 12:56 ` [PATCH V4 05/31] OvmfPkg: Extend VmgExitLib " Min Xu
2021-12-15  6:56   ` [edk2-devel] " Gerd Hoffmann
2022-01-20  6:34     ` Min Xu
2021-12-13 12:56 ` [PATCH V4 06/31] UefiCpuPkg/CpuExceptionHandler: Add base support for the " Min Xu
2021-12-13 12:56 ` [PATCH V4 07/31] MdePkg: Add helper functions for Tdx guest in BaseIoLibIntrinsic Min Xu
2021-12-13 12:56 ` [PATCH V4 08/31] MdePkg: Support mmio " Min Xu
2021-12-15  7:02   ` Gerd Hoffmann
2021-12-13 12:56 ` [PATCH V4 09/31] MdePkg: Support IoFifo " Min Xu
2021-12-15  7:18   ` Gerd Hoffmann
2021-12-13 12:56 ` [PATCH V4 10/31] MdePkg: Support IoRead/IoWrite " Min Xu
2021-12-15  7:18   ` Gerd Hoffmann
2021-12-13 12:56 ` [PATCH V4 11/31] UefiCpuPkg: Support TDX in BaseXApicX2ApicLib Min Xu
2021-12-13 12:56 ` [PATCH V4 12/31] MdePkg: Add macro to check SEV / TDX guest Min Xu
2021-12-13 12:56 ` [PATCH V4 13/31] UefiCpuPkg: Enable Tdx support in MpInitLib Min Xu
2021-12-15  7:33   ` Gerd Hoffmann
2021-12-13 12:56 ` [PATCH V4 14/31] OvmfPkg: Add IntelTdx.h in OvmfPkg/Include/IndustryStandard Min Xu
2021-12-15  7:37   ` Gerd Hoffmann
2021-12-16  6:43     ` Min Xu
2021-12-13 12:56 ` [PATCH V4 15/31] OvmfPkg: Add TdxMailboxLib Min Xu
2021-12-15  7:47   ` Gerd Hoffmann
2021-12-13 12:56 ` [PATCH V4 16/31] MdePkg: Add EFI_RESOURCE_ATTRIBUTE_ENCRYPTED in PiHob.h Min Xu
2021-12-13 12:56 ` [PATCH V4 17/31] OvmfPkg: Update Sec to support Tdx Min Xu
2021-12-15  8:18   ` Gerd Hoffmann
2021-12-16  8:11     ` [edk2-devel] " Min Xu
2021-12-13 12:56 ` [PATCH V4 18/31] OvmfPkg: Check Tdx in QemuFwCfgPei to avoid DMA operation Min Xu
2021-12-15  8:19   ` Gerd Hoffmann
2021-12-13 12:56 ` [PATCH V4 19/31] MdeModulePkg: EFER should not be changed in TDX Min Xu
2021-12-13 12:56 ` [PATCH V4 20/31] MdeModulePkg: Add PcdTdxSharedBitMask Min Xu
2021-12-15  8:22   ` Gerd Hoffmann
2021-12-13 12:56 ` [PATCH V4 21/31] UefiCpuPkg: Update AddressEncMask in CpuPageTable Min Xu
2021-12-15  8:38   ` Gerd Hoffmann
2021-12-16  8:23     ` Min Xu
2021-12-13 12:56 ` [PATCH V4 22/31] OvmfPkg: Update PlatformPei to support TDX Min Xu
2021-12-15  8:53   ` Gerd Hoffmann
2022-01-20  9:07     ` [edk2-devel] " Min Xu
2022-01-13 19:18   ` Vishal Annapurve
2022-01-14  2:23     ` Min Xu
2022-01-14  2:37       ` Vishal Annapurve
2022-01-14  2:40         ` Min Xu
2021-12-13 12:56 ` [PATCH V4 23/31] OvmfPkg: Update AcpiPlatformDxe to alter MADT table Min Xu
2021-12-15  8:54   ` Gerd Hoffmann
2021-12-13 12:56 ` [PATCH V4 24/31] OvmfPkg: Add TdxDxe driver Min Xu
2021-12-15  9:05   ` Gerd Hoffmann
2021-12-13 12:56 ` [PATCH V4 25/31] OvmfPkg/BaseMemEncryptTdxLib: Add TDX helper library Min Xu
2021-12-15  9:16   ` Gerd Hoffmann
2022-01-21  2:54     ` Min Xu
2022-01-21  8:04       ` Gerd Hoffmann
2022-01-21  8:31         ` [edk2-devel] " Min Xu
2021-12-13 12:56 ` [PATCH V4 26/31] OvmfPkg/QemuFwCfgLib: Support Tdx in QemuFwCfgDxe Min Xu
2021-12-15  9:16   ` Gerd Hoffmann
2021-12-13 12:56 ` [PATCH V4 27/31] OvmfPkg: Update IoMmuDxe to support TDX Min Xu
2021-12-15  9:18   ` Gerd Hoffmann
2021-12-13 12:56 ` [PATCH V4 28/31] OvmfPkg: Rename XenTimerDxe to LocalApicTimerDxe Min Xu
2021-12-15  9:19   ` Gerd Hoffmann
2021-12-13 12:57 ` [PATCH V4 29/31] UefiCpuPkg: Setting initial-count register as the last step Min Xu
2021-12-15  9:20   ` Gerd Hoffmann
2021-12-13 12:57 ` [PATCH V4 30/31] OvmfPkg: Switch timer in build time for OvmfPkg Min Xu
2021-12-15  9:21   ` Gerd Hoffmann
2021-12-13 12:57 ` [PATCH V4 31/31] OvmfPkg: Move LocalApicTimerDxe to UefiCpuPkg Min Xu
2021-12-15  9:26   ` Gerd Hoffmann
2021-12-16  8:29     ` [edk2-devel] " Min Xu

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