public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [PATCH V2 00/28] Enable Intel TDX in OvmfPkg (Config-A)
@ 2021-10-05  3:39 Min Xu
  2021-10-05  3:39 ` [PATCH V2 01/28] OvmfPkg: Copy Main.asm from UefiCpuPkg to OvmfPkg's ResetVector Min Xu
                   ` (27 more replies)
  0 siblings, 28 replies; 91+ messages in thread
From: Min Xu @ 2021-10-05  3:39 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

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 is still in review.

This patch-set is Wave-2 which is focused on the changes in SEC/PEI/DXE
phases. Wave-2 has little dependencies on Wave-1 except some PCDs
definitions. So reviewers can skip Patch 01-03. Once Wave-1 is done,
Wave-2 will be rebased on the latest code base. Thanks for your
understanding.

Patch 01-03 are the patches of Wave-1 (ResetVector phase). They can be
skipped.

Patch 04 - 18 are changes in SEC phase. Also some libraries in these
patches are workable in both SEC and PEI.

Patch 19 - 21 are changes for PEI phase.

Patch 22 is copied from SEV's patch which defines a new PCD
(PcdConfidentialComputingGuestAttr). Because SEV is also doing the
upstream and some of the code is shared between TDX and SEV.
Reviewer can skip this patch.

Patch 23 - 28 are changes in DXE phase.

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

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>
Signed-off-by: Min Xu <min.m.xu@intel.com>

Min Xu (28):
  OvmfPkg: Copy Main.asm from UefiCpuPkg to OvmfPkg's ResetVector
  OvmfPkg: Enable TDX in ResetVector
  OvmfPkg: Merge TEMP_MEM entries in Tdx metadata
  MdePkg: Add Tdx.h
  MdePkg: Add TdxLib to wrap Tdx operations
  MdePkg: Update BaseIoLibIntrinsicSev to support Tdx
  UefiCpuPkg: Support TDX in BaseXApicX2ApicLib
  UefiCpuPkg: Add VmTdExitLibNull
  UefiPayloadPkg: Prepare UefiPayloadPkg to use the VmTdExitLib library
  OvmfPkg: Prepare OvmfPkg to use the VmTdExitLib library
  OvmfPkg: Implement library support for VmTdExitLib in Ovmf
  UefiCpuPkg/CpuExceptionHandler: Add base support for the #VE exception
  UefiCpuPkg: Enable Tdx support in MpInitLib
  OvmfPkg: Update SecEntry.nasm to support Tdx
  OvmfPkg: Add IntelTdx.h in OvmfPkg/Include/IndustryStandard
  OvmfPkg: Add TdxMailboxLib
  MdePkg: Add EFI_RESOURCE_ATTRIBUTE_ENCRYPTED in PiHob.h
  OvmfPkg: Enable Tdx in SecMain.c
  OvmfPkg: Check Tdx in QemuFwCfgPei to avoid DMA operation
  MdeModulePkg: EFER should not be changed in TDX
  OvmfPkg: Update PlatformPei to support TDX
  UefiCpuPkg: Define ConfidentialComputingGuestAttr (Temp)
  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: Add LocalApicTimerDxe

 MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf       |   1 +
 .../Core/DxeIplPeim/X64/VirtualMemory.c       |   6 +
 MdeModulePkg/MdeModulePkg.dec                 |   5 +
 MdePkg/Include/IndustryStandard/Tdx.h         | 203 ++++
 MdePkg/Include/Library/TdxLib.h               | 167 ++++
 MdePkg/Include/Pi/PiHob.h                     |   8 +
 .../BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf |   2 +
 .../BaseIoLibIntrinsicSev.inf                 |   7 +-
 MdePkg/Library/BaseIoLibIntrinsic/IoLib.c     |  97 +-
 MdePkg/Library/BaseIoLibIntrinsic/IoLibFifo.c | 216 ++++
 MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c  |  49 +-
 .../BaseIoLibIntrinsic/IoLibInternalTdx.c     | 735 ++++++++++++++
 .../BaseIoLibIntrinsic/IoLibInternalTdxNull.c | 499 ++++++++++
 MdePkg/Library/BaseIoLibIntrinsic/IoLibMsc.c  |  73 +-
 MdePkg/Library/BaseIoLibIntrinsic/IoLibSev.h  | 166 ++++
 MdePkg/Library/BaseIoLibIntrinsic/IoLibTdx.h  | 411 ++++++++
 .../BaseIoLibIntrinsic/X64/IoFifoSev.nasm     |  34 +-
 MdePkg/Library/TdxLib/AcceptPages.c           | 136 +++
 MdePkg/Library/TdxLib/Rtmr.c                  | 118 +++
 MdePkg/Library/TdxLib/TdInfo.c                | 103 ++
 MdePkg/Library/TdxLib/TdxLib.inf              |  39 +
 MdePkg/Library/TdxLib/TdxLibNull.c            | 192 ++++
 MdePkg/Library/TdxLib/X64/Tdcall.nasm         |  85 ++
 MdePkg/Library/TdxLib/X64/Tdvmcall.nasm       | 207 ++++
 MdePkg/MdePkg.dec                             |   3 +
 MdePkg/MdePkg.dsc                             |   1 +
 OvmfPkg/8254TimerDxe/8254Timer.inf            |   3 +
 OvmfPkg/8254TimerDxe/Timer.c                  |   5 +
 OvmfPkg/8254TimerDxe/Timer.h                  |   1 +
 OvmfPkg/8259InterruptControllerDxe/8259.c     |   1 +
 OvmfPkg/8259InterruptControllerDxe/8259.inf   |   1 +
 OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c       |  12 +-
 .../QemuFwCfgAcpiPlatformDxe.inf              |   1 +
 OvmfPkg/Include/IndustryStandard/AcpiTdx.h    |  23 +
 OvmfPkg/Include/IndustryStandard/IntelTdx.h   |  76 ++
 OvmfPkg/Include/Library/MemEncryptTdxLib.h    |  81 ++
 OvmfPkg/Include/Library/TdxMailboxLib.h       |  75 ++
 .../Include/Protocol/QemuAcpiTableNotify.h    |  29 +
 OvmfPkg/Include/Protocol/TimerSelector.h      |  16 +
 OvmfPkg/Include/TdxCommondefs.inc             |  51 +
 OvmfPkg/IoMmuDxe/AmdSevIoMmu.c                | 134 ++-
 OvmfPkg/IoMmuDxe/AmdSevIoMmu.h                |  12 +
 OvmfPkg/IoMmuDxe/IoMmuDxe.c                   |   4 +-
 OvmfPkg/IoMmuDxe/IoMmuDxe.inf                 |   1 +
 .../BaseMemEncryptTdxLib.inf                  |  45 +
 .../BaseMemEncryptTdxLibNull.inf              |  35 +
 .../BaseMemoryEncryptionNull.c                |  90 ++
 .../BaseMemEncryptTdxLib/MemoryEncryption.c   | 938 ++++++++++++++++++
 .../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    | 138 +++
 .../Library/TdxMailboxLib/TdxMailboxLib.inf   |  52 +
 .../Library/TdxMailboxLib/TdxMailboxNull.c    |  86 ++
 OvmfPkg/Library/VmTdExitLib/VmTdExitLib.inf   |  39 +
 .../Library/VmTdExitLib/VmTdExitVeHandler.c   | 515 ++++++++++
 OvmfPkg/LocalApicTimerDxe/LocalApicTimer.c    | 488 +++++++++
 .../LocalApicTimerDxe/LocalApicTimerDxe.inf   |  52 +
 .../LocalApicTimerDxe/LocalApicTimerDxe.uni   |  13 +
 OvmfPkg/OvmfPkg.dec                           |  45 +
 OvmfPkg/OvmfPkgDefines.fdf.inc                |   9 +
 OvmfPkg/OvmfPkgIa32.dsc                       |   4 +
 OvmfPkg/OvmfPkgIa32X64.dsc                    |   4 +
 OvmfPkg/OvmfPkgX64.dsc                        |  15 +
 OvmfPkg/OvmfPkgX64.fdf                        |   4 +
 OvmfPkg/OvmfXen.dsc                           |   1 +
 OvmfPkg/PlatformPei/FeatureControl.c          |   8 +-
 OvmfPkg/PlatformPei/IntelTdx.c                | 286 ++++++
 OvmfPkg/PlatformPei/IntelTdxNull.c            |  49 +
 OvmfPkg/PlatformPei/MemDetect.c               |  57 +-
 OvmfPkg/PlatformPei/Platform.c                |   1 +
 OvmfPkg/PlatformPei/Platform.h                |  28 +
 OvmfPkg/PlatformPei/PlatformPei.inf           |  13 +
 OvmfPkg/PlatformPei/X64/ApRunLoop.nasm        |  83 ++
 OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm  |  39 +
 OvmfPkg/ResetVector/Ia32/Flat32ToFlat64.asm   |  11 +
 OvmfPkg/ResetVector/Ia32/IntelTdx.asm         | 235 +++++
 OvmfPkg/ResetVector/Ia32/PageTables64.asm     |  21 +-
 OvmfPkg/ResetVector/Main.asm                  | 119 +++
 OvmfPkg/ResetVector/ResetVector.inf           |   9 +
 OvmfPkg/ResetVector/ResetVector.nasmb         |  37 +-
 OvmfPkg/ResetVector/X64/IntelTdxMetadata.asm  |  86 ++
 OvmfPkg/Sec/IntelTdx.c                        | 608 ++++++++++++
 OvmfPkg/Sec/IntelTdx.h                        |  33 +
 OvmfPkg/Sec/SecMain.c                         |  60 +-
 OvmfPkg/Sec/SecMain.inf                       |   7 +
 OvmfPkg/Sec/X64/SecEntry.nasm                 | 314 ++++++
 OvmfPkg/TdxDxe/TdxAcpiTable.c                 | 207 ++++
 OvmfPkg/TdxDxe/TdxAcpiTable.h                 |  38 +
 OvmfPkg/TdxDxe/TdxDxe.c                       | 210 ++++
 OvmfPkg/TdxDxe/TdxDxe.inf                     |  63 ++
 .../Include/ConfidentialComputingGuestAttr.h  |  25 +
 UefiCpuPkg/Include/Library/VmTdExitLib.h      |  47 +
 .../BaseXApicX2ApicLib/BaseXApicX2ApicLib.c   | 233 ++++-
 .../BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf |   1 +
 .../DxeCpuExceptionHandlerLib.inf             |   1 +
 .../PeiCpuExceptionHandlerLib.inf             |   1 +
 .../PeiDxeSmmCpuException.c                   |  18 +
 .../SecPeiCpuException.c                      |  19 +
 .../SecPeiCpuExceptionHandlerLib.inf          |   1 +
 .../SmmCpuExceptionHandlerLib.inf             |   1 +
 .../Xcode5SecPeiCpuExceptionHandlerLib.inf    |   1 +
 UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf |   4 +
 UefiCpuPkg/Library/MpInitLib/DxeMpLib.c       |  14 +-
 UefiCpuPkg/Library/MpInitLib/MpIntelTdx.h     | 107 ++
 UefiCpuPkg/Library/MpInitLib/MpLib.c          |  26 +
 UefiCpuPkg/Library/MpInitLib/MpLibTdx.c       | 186 ++++
 UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c   | 117 +++
 UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf |   4 +
 .../Library/MpInitLib/X64/IntelTdcall.nasm    | 120 +++
 .../Library/VmTdExitLibNull/VmTdExitLibNull.c |  37 +
 .../VmTdExitLibNull/VmTdExitLibNull.inf       |  34 +
 UefiCpuPkg/UefiCpuPkg.dec                     |   7 +
 UefiCpuPkg/UefiCpuPkg.dsc                     |   3 +
 UefiPayloadPkg/UefiPayloadPkg.dsc             |   3 +
 118 files changed, 10387 insertions(+), 143 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/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 MdePkg/Library/TdxLib/X64/Tdcall.nasm
 create mode 100644 MdePkg/Library/TdxLib/X64/Tdvmcall.nasm
 create mode 100644 OvmfPkg/Include/IndustryStandard/AcpiTdx.h
 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/Protocol/TimerSelector.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/VmTdExitLib/VmTdExitLib.inf
 create mode 100644 OvmfPkg/Library/VmTdExitLib/VmTdExitVeHandler.c
 create mode 100644 OvmfPkg/LocalApicTimerDxe/LocalApicTimer.c
 create mode 100644 OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
 create mode 100644 OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.uni
 create mode 100644 OvmfPkg/PlatformPei/IntelTdx.c
 create mode 100644 OvmfPkg/PlatformPei/IntelTdxNull.c
 create mode 100644 OvmfPkg/PlatformPei/X64/ApRunLoop.nasm
 create mode 100644 OvmfPkg/ResetVector/Ia32/IntelTdx.asm
 create mode 100644 OvmfPkg/ResetVector/Main.asm
 create mode 100644 OvmfPkg/ResetVector/X64/IntelTdxMetadata.asm
 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 UefiCpuPkg/Include/ConfidentialComputingGuestAttr.h
 create mode 100644 UefiCpuPkg/Include/Library/VmTdExitLib.h
 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/MpInitLib/X64/IntelTdcall.nasm
 create mode 100644 UefiCpuPkg/Library/VmTdExitLibNull/VmTdExitLibNull.c
 create mode 100644 UefiCpuPkg/Library/VmTdExitLibNull/VmTdExitLibNull.inf

-- 
2.29.2.windows.2


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

* [PATCH V2 01/28] OvmfPkg: Copy Main.asm from UefiCpuPkg to OvmfPkg's ResetVector
  2021-10-05  3:39 [PATCH V2 00/28] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
@ 2021-10-05  3:39 ` Min Xu
  2021-10-05  3:39 ` [PATCH V2 02/28] OvmfPkg: Enable TDX in ResetVector Min Xu
                   ` (26 subsequent siblings)
  27 siblings, 0 replies; 91+ messages in thread
From: Min Xu @ 2021-10-05  3:39 UTC (permalink / raw)
  To: devel; +Cc: Min Xu

Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/ResetVector/Main.asm | 103 +++++++++++++++++++++++++++++++++++
 1 file changed, 103 insertions(+)
 create mode 100644 OvmfPkg/ResetVector/Main.asm

diff --git a/OvmfPkg/ResetVector/Main.asm b/OvmfPkg/ResetVector/Main.asm
new file mode 100644
index 000000000000..ae90a148fce7
--- /dev/null
+++ b/OvmfPkg/ResetVector/Main.asm
@@ -0,0 +1,103 @@
+;------------------------------------------------------------------------------
+; @file
+; Main routine of the pre-SEC code up through the jump into SEC
+;
+; Copyright (c) 2008 - 2009, Intel Corporation. All rights reserved.<BR>
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+;------------------------------------------------------------------------------
+
+
+BITS    16
+
+;
+; Modified:  EBX, ECX, EDX, EBP
+;
+; @param[in,out]  RAX/EAX  Initial value of the EAX register
+;                          (BIST: Built-in Self Test)
+; @param[in,out]  DI       'BP': boot-strap processor, or
+;                          'AP': application processor
+; @param[out]     RBP/EBP  Address of Boot Firmware Volume (BFV)
+; @param[out]     DS       Selector allowing flat access to all addresses
+; @param[out]     ES       Selector allowing flat access to all addresses
+; @param[out]     FS       Selector allowing flat access to all addresses
+; @param[out]     GS       Selector allowing flat access to all addresses
+; @param[out]     SS       Selector allowing flat access to all addresses
+;
+; @return         None  This routine jumps to SEC and does not return
+;
+Main16:
+    OneTimeCall EarlyInit16
+
+    ;
+    ; Transition the processor from 16-bit real mode to 32-bit flat mode
+    ;
+    OneTimeCall TransitionFromReal16To32BitFlat
+
+BITS    32
+
+    ;
+    ; Search for the Boot Firmware Volume (BFV)
+    ;
+    OneTimeCall Flat32SearchForBfvBase
+
+    ;
+    ; EBP - Start of BFV
+    ;
+
+    ;
+    ; Search for the SEC entry point
+    ;
+    OneTimeCall Flat32SearchForSecEntryPoint
+
+    ;
+    ; ESI - SEC Core entry point
+    ; EBP - Start of BFV
+    ;
+
+%ifdef ARCH_IA32
+
+    ;
+    ; Restore initial EAX value into the EAX register
+    ;
+    mov     eax, esp
+
+    ;
+    ; Jump to the 32-bit SEC entry point
+    ;
+    jmp     esi
+
+%else
+
+    ;
+    ; Transition the processor from 32-bit flat mode to 64-bit flat mode
+    ;
+    OneTimeCall Transition32FlatTo64Flat
+
+BITS    64
+
+    ;
+    ; Some values were calculated in 32-bit mode.  Make sure the upper
+    ; 32-bits of 64-bit registers are zero for these values.
+    ;
+    mov     rax, 0x00000000ffffffff
+    and     rsi, rax
+    and     rbp, rax
+    and     rsp, rax
+
+    ;
+    ; RSI - SEC Core entry point
+    ; RBP - Start of BFV
+    ;
+
+    ;
+    ; Restore initial EAX value into the RAX register
+    ;
+    mov     rax, rsp
+
+    ;
+    ; Jump to the 64-bit SEC entry point
+    ;
+    jmp     rsi
+
+%endif
-- 
2.29.2.windows.2


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

* [PATCH V2 02/28] OvmfPkg: Enable TDX in ResetVector
  2021-10-05  3:39 [PATCH V2 00/28] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
  2021-10-05  3:39 ` [PATCH V2 01/28] OvmfPkg: Copy Main.asm from UefiCpuPkg to OvmfPkg's ResetVector Min Xu
@ 2021-10-05  3:39 ` Min Xu
  2021-10-05  3:39 ` [PATCH V2 03/28] OvmfPkg: Merge TEMP_MEM entries in Tdx metadata Min Xu
                   ` (25 subsequent siblings)
  27 siblings, 0 replies; 91+ messages in thread
From: Min Xu @ 2021-10-05  3:39 UTC (permalink / raw)
  To: devel; +Cc: Min Xu

Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/OvmfPkg.dec                          |   9 +
 OvmfPkg/OvmfPkgDefines.fdf.inc               |   9 +
 OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm |  39 +++
 OvmfPkg/ResetVector/Ia32/Flat32ToFlat64.asm  |  11 +
 OvmfPkg/ResetVector/Ia32/IntelTdx.asm        | 235 +++++++++++++++++++
 OvmfPkg/ResetVector/Ia32/PageTables64.asm    |  21 +-
 OvmfPkg/ResetVector/Main.asm                 |  16 ++
 OvmfPkg/ResetVector/ResetVector.inf          |   9 +
 OvmfPkg/ResetVector/ResetVector.nasmb        |  40 +++-
 OvmfPkg/ResetVector/X64/IntelTdxMetadata.asm | 102 ++++++++
 10 files changed, 484 insertions(+), 7 deletions(-)
 create mode 100644 OvmfPkg/ResetVector/Ia32/IntelTdx.asm
 create mode 100644 OvmfPkg/ResetVector/X64/IntelTdxMetadata.asm

diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index 1be8d5dccbc7..340d83f794d0 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -340,6 +340,15 @@
   # header definition.
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfConfidentialComputingWorkAreaHeader|4|UINT32|0x51
 
+  ## The base address and size of the TDX Cfv base and size.
+  gUefiOvmfPkgTokenSpaceGuid.PcdCfvBase|0|UINT32|0x52
+  gUefiOvmfPkgTokenSpaceGuid.PcdCfvRawDataOffset|0|UINT32|0x53
+  gUefiOvmfPkgTokenSpaceGuid.PcdCfvRawDataSize|0|UINT32|0x54
+
+  ## The base address and size of the TDX Bfv base and size.
+  gUefiOvmfPkgTokenSpaceGuid.PcdBfvBase|0|UINT32|0x55
+  gUefiOvmfPkgTokenSpaceGuid.PcdBfvRawDataOffset|0|UINT32|0x56
+  gUefiOvmfPkgTokenSpaceGuid.PcdBfvRawDataSize|0|UINT32|0x57
 
 [PcdsDynamic, PcdsDynamicEx]
   gUefiOvmfPkgTokenSpaceGuid.PcdEmuVariableEvent|0|UINT64|2
diff --git a/OvmfPkg/OvmfPkgDefines.fdf.inc b/OvmfPkg/OvmfPkgDefines.fdf.inc
index 3b5e45253916..6170c5993ce5 100644
--- a/OvmfPkg/OvmfPkgDefines.fdf.inc
+++ b/OvmfPkg/OvmfPkgDefines.fdf.inc
@@ -9,6 +9,7 @@
 ##
 
 DEFINE BLOCK_SIZE        = 0x1000
+DEFINE VARS_OFFSET       = 0
 
 #
 # A firmware binary built with FD_SIZE_IN_KB=1024, and a firmware binary built
@@ -88,6 +89,14 @@ SET gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize = $(VARS_SPARE_
 # Computing Work Area header defined in the Include/WorkArea.h
 SET gUefiOvmfPkgTokenSpaceGuid.PcdOvmfConfidentialComputingWorkAreaHeader  = 4
 
+SET gUefiOvmfPkgTokenSpaceGuid.PcdCfvBase           = $(FW_BASE_ADDRESS)
+SET gUefiOvmfPkgTokenSpaceGuid.PcdCfvRawDataOffset  = $(VARS_OFFSET)
+SET gUefiOvmfPkgTokenSpaceGuid.PcdCfvRawDataSize    = $(VARS_SIZE)
+
+SET gUefiOvmfPkgTokenSpaceGuid.PcdBfvBase           = $(CODE_BASE_ADDRESS)
+SET gUefiOvmfPkgTokenSpaceGuid.PcdBfvRawDataOffset  = $(VARS_SIZE)
+SET gUefiOvmfPkgTokenSpaceGuid.PcdBfvRawDataSize    = $(CODE_SIZE)
+
 !if $(SMM_REQUIRE) == TRUE
 SET gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64 = gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashNvStorageVariableBase
 SET gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase = gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashNvStorageFtwWorkingBase
diff --git a/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm b/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
index 7ec3c6e980c3..76bc3aa00735 100644
--- a/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
+++ b/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
@@ -47,6 +47,25 @@ TIMES (15 - ((guidedStructureEnd - guidedStructureStart + 15) % 16)) DB 0
 ;
 guidedStructureStart:
 
+%ifdef ARCH_X64
+;
+; TDX Metadata offset block
+;
+; TdxMetadata.asm is included in ARCH_X64 because Inte TDX is only
+; available in ARCH_X64. Below block describes the offset of
+; TdxMetadata block in Ovmf image
+;
+; GUID : e47a6535-984a-4798-865e-4685a7bf8ec2
+;
+tdxMetadataOffsetStart:
+    DD      tdxMetadataOffsetStart - TdxMetadataGuid - 16
+    DW      tdxMetadataOffsetEnd - tdxMetadataOffsetStart
+    DB      0x35, 0x65, 0x7a, 0xe4, 0x4a, 0x98, 0x98, 0x47
+    DB      0x86, 0x5e, 0x46, 0x85, 0xa7, 0xbf, 0x8e, 0xc2
+tdxMetadataOffsetEnd:
+
+%endif
+
 ; SEV Hash Table Block
 ;
 ; This describes the guest ram area where the hypervisor should
@@ -158,10 +177,30 @@ resetVector:
 ;
 ; This is where the processor will begin execution
 ;
+; In IA32 we follow the standard reset vector flow. While in X64, Td guest
+; may be supported. Td guest requires the startup mode to be 32-bit
+; protected mode but the legacy VM startup mode is 16-bit real mode.
+; To make NASM generate such shared entry code that behaves correctly in
+; both 16-bit and 32-bit mode, more BITS directives are added.
+;
+%ifdef ARCH_IA32
     nop
     nop
     jmp     EarlyBspInitReal16
 
+%else
+
+    mov     eax, cr0
+    test    al, 1
+    jz      .Real
+BITS 32
+    jmp     Main32
+BITS 16
+.Real:
+    jmp     EarlyBspInitReal16
+
+%endif
+
 ALIGN   16
 
 fourGigabytes:
diff --git a/OvmfPkg/ResetVector/Ia32/Flat32ToFlat64.asm b/OvmfPkg/ResetVector/Ia32/Flat32ToFlat64.asm
index c6d0d898bcd1..eb3546668ef8 100644
--- a/OvmfPkg/ResetVector/Ia32/Flat32ToFlat64.asm
+++ b/OvmfPkg/ResetVector/Ia32/Flat32ToFlat64.asm
@@ -21,6 +21,17 @@ Transition32FlatTo64Flat:
     bts     eax, 5                      ; enable PAE
     mov     cr4, eax
 
+    ;
+    ; In TDX LME has already been set. So we're done and jump to enable
+    ; paging directly if Tdx is enabled.
+    ; EBX is cleared because in the later it will be used to check if
+    ; the second step of the SEV-ES mitigation is to be performed.
+    ;
+    xor     ebx, ebx
+    OneTimeCall IsTdxEnabled
+    test    eax, eax
+    jnz     EnablePaging
+
     mov     ecx, 0xc0000080
     rdmsr
     bts     eax, 8                      ; set LME
diff --git a/OvmfPkg/ResetVector/Ia32/IntelTdx.asm b/OvmfPkg/ResetVector/Ia32/IntelTdx.asm
new file mode 100644
index 000000000000..f67b1bcf0b2e
--- /dev/null
+++ b/OvmfPkg/ResetVector/Ia32/IntelTdx.asm
@@ -0,0 +1,235 @@
+;------------------------------------------------------------------------------
+; @file
+;   Intel TDX routines
+;
+; Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+;------------------------------------------------------------------------------
+
+%define SEC_DEFAULT_CR0  0x00000023
+%define SEC_DEFAULT_CR4  0x640
+%define VM_GUEST_TDX     2
+
+BITS 32
+
+;
+; Check if it is Intel Tdx
+;
+; Modified: EAX, EBX, ECX, EDX
+;
+; If it is Intel Tdx, EAX is 1
+; If it is not Intel Tdx, EAX is 0
+;
+IsTdx:
+    ;
+    ; CPUID (0)
+    ;
+    mov     eax, 0
+    cpuid
+    cmp     ebx, 0x756e6547  ; "Genu"
+    jne     IsNotTdx
+    cmp     edx, 0x49656e69  ; "ineI"
+    jne     IsNotTdx
+    cmp     ecx, 0x6c65746e  ; "ntel"
+    jne     IsNotTdx
+
+    ;
+    ; CPUID (1)
+    ;
+    mov     eax, 1
+    cpuid
+    test    ecx, 0x80000000
+    jz      IsNotTdx
+
+    ;
+    ; CPUID[0].EAX >= 0x21?
+    ;
+    mov     eax, 0
+    cpuid
+    cmp     eax, 0x21
+    jl      IsNotTdx
+
+    ;
+    ; CPUID (0x21,0)
+    ;
+    mov     eax, 0x21
+    mov     ecx, 0
+    cpuid
+
+    cmp     ebx, 0x65746E49   ; "Inte"
+    jne     IsNotTdx
+    cmp     edx, 0x5844546C   ; "lTDX"
+    jne     IsNotTdx
+    cmp     ecx, 0x20202020   ; "    "
+    jne     IsNotTdx
+
+    mov     eax, 1
+    jmp     ExitIsTdx
+
+IsNotTdx:
+    xor     eax, eax
+
+ExitIsTdx:
+
+  OneTimeCallRet IsTdx
+
+;
+; Initialize work area if it is Tdx guest. Detailed definition is in
+; OvmfPkg/Include/WorkArea.h.
+; BSP and APs all go here. Only BSP initialize this work area.
+;
+; Param[in] EBP[5:0]    CPU Supported GPAW (48 or 52)
+; Param[in] ESI[31:0]   vCPU ID (BSP is 0, others are AP)
+;
+; Modified:  EBP
+;
+InitTdxWorkarea:
+
+    ;
+    ; First check if it is Tdx
+    ;
+    OneTimeCall IsTdx
+
+    test    eax, eax
+    jz      ExitInitTdxWorkarea
+
+    cmp     esi, 0
+    je      TdxBspEntry
+
+    ;
+    ; In Td guest, BSP/AP shares the same entry point
+    ; BSP builds up the page table, while APs shouldn't do the same task.
+    ; Instead, APs just leverage the page table which is built by BSP.
+    ; APs will wait until the page table is ready.
+    ;
+TdxApWait:
+    cmp     byte[TDX_WORK_AREA_PGTBL_READY], 0
+    je      TdxApWait
+    jmp     ExitInitTdxWorkarea
+
+TdxBspEntry:
+    ;
+    ; Set Type of WORK_AREA_GUEST_TYPE so that the following code can use
+    ; these information.
+    ;
+    mov     byte[WORK_AREA_GUEST_TYPE], VM_GUEST_TDX
+
+    ;
+    ; EBP[5:0] CPU supported GPA width
+    ;
+    and     ebp, 0x3f
+    mov     DWORD[TDX_WORK_AREA_GPAW], ebp
+
+ExitInitTdxWorkarea:
+    OneTimeCallRet InitTdxWorkarea
+
+;
+; Load the GDT and set the CR0.
+;
+; Modified:  EAX, EBX, CR0, CR4, DS, ES, FS, GS, SS, CS
+;
+ReloadFlat32:
+
+    cli
+    mov     ebx, ADDR_OF(gdtr)
+    lgdt    [ebx]
+
+    mov     eax, SEC_DEFAULT_CR0
+    mov     cr0, eax
+
+    jmp     LINEAR_CODE_SEL:dword ADDR_OF(jumpToFlat32BitAndLandHere)
+
+jumpToFlat32BitAndLandHere:
+
+    mov     eax, SEC_DEFAULT_CR4
+    mov     cr4, eax
+
+    debugShowPostCode POSTCODE_32BIT_MODE
+
+    mov     ax, LINEAR_SEL
+    mov     ds, ax
+    mov     es, ax
+    mov     fs, ax
+    mov     gs, ax
+    mov     ss, ax
+
+    OneTimeCallRet ReloadFlat32
+
+;
+; Tdx initialization after entering into ResetVector
+;
+; Modified:  EAX, EBX, ECX, EDX, EBP, EDI, ESP
+;
+InitTdx:
+    ;
+    ; Save EBX in EBP because EBX will be changed in ReloadFlat32
+    ;
+    mov     ebp, ebx
+
+    ;
+    ; First load the GDT and jump to Flat32 mode
+    ;
+    OneTimeCall ReloadFlat32
+
+    ;
+    ; Initialization of Tdx work area
+    ;
+    OneTimeCall  InitTdxWorkarea
+
+    OneTimeCallRet InitTdx
+
+;
+; Check TDX features, TDX or TDX-BSP or TDX-APs?
+;
+; By design TDX BSP is reponsible for initializing the PageTables.
+; After PageTables are ready, byte[TDX_WORK_AREA_PGTBL_READY] is set to 1.
+; APs will spin when byte[TDX_WORK_AREA_PGTBL_READY] is 0 until it is set to 1.
+;
+; When this routine is run on TDX BSP, byte[TDX_WORK_AREA_PGTBL_READY] should be 0.
+; When this routine is run on TDX APs, byte[TDX_WORK_AREA_PGTBL_READY] should be 1.
+;
+;
+; Modified:  EAX, EDX
+;
+; 0-NonTdx, 1-TdxBsp, 2-TdxAps
+;
+CheckTdxFeaturesBeforeBuildPagetables:
+    xor     eax, eax
+    cmp     byte[WORK_AREA_GUEST_TYPE], VM_GUEST_TDX
+    jne     NotTdx
+
+    xor     edx, edx
+    mov     al, byte[TDX_WORK_AREA_PGTBL_READY]
+    inc     eax
+
+NotTdx:
+    OneTimeCallRet CheckTdxFeaturesBeforeBuildPagetables
+
+;
+; Set byte[TDX_WORK_AREA_PGTBL_READY] to 1
+;
+TdxPostBuildPageTables:
+    cmp     byte[WORK_AREA_GUEST_TYPE], VM_GUEST_TDX
+    jne     ExitTdxPostBuildPageTables
+    mov     byte[TDX_WORK_AREA_PGTBL_READY], 1
+
+ExitTdxPostBuildPageTables:
+    OneTimeCallRet TdxPostBuildPageTables
+
+;
+; Check if TDX is enabled
+;
+; Modified:  EAX
+;
+; If TDX is enabled then EAX will be 1
+; If TDX is disabled then EAX will be 0.
+;
+IsTdxEnabled:
+    xor     eax, eax
+    cmp     byte[WORK_AREA_GUEST_TYPE], VM_GUEST_TDX
+    jne     TdxNotEnabled
+    mov     eax, 1
+
+TdxNotEnabled:
+    OneTimeCallRet IsTdxEnabled
diff --git a/OvmfPkg/ResetVector/Ia32/PageTables64.asm b/OvmfPkg/ResetVector/Ia32/PageTables64.asm
index 07b6ca070909..dc640dd2bf58 100644
--- a/OvmfPkg/ResetVector/Ia32/PageTables64.asm
+++ b/OvmfPkg/ResetVector/Ia32/PageTables64.asm
@@ -37,14 +37,23 @@ BITS    32
                        PAGE_READ_WRITE + \
                        PAGE_PRESENT)
 
+%define TDX_BSP         1
+%define TDX_AP          2
+
 ;
 ; Modified:  EAX, EBX, ECX, EDX
 ;
 SetCr3ForPageTables64:
-
-    ; Clear the WorkArea header. The SEV probe routines will populate the
-    ; work area when detected.
-    mov     byte[WORK_AREA_GUEST_TYPE], 0
+    ; Check the TDX features.
+    ; If it is TDX APs, then jump to SetCr3 directly.
+    ; In TD guest the initialization is done by BSP, including building
+    ; the page tables. APs will spin on until byte[TDX_WORK_AREA_PGTBL_READY]
+    ; is set.
+    OneTimeCall   CheckTdxFeaturesBeforeBuildPagetables
+    cmp       eax, TDX_BSP
+    je        ClearOvmfPageTables
+    cmp       eax, TDX_AP
+    je        SetCr3
 
     ; Check whether the SEV is active and populate the SevEsWorkArea
     OneTimeCall   CheckSevFeatures
@@ -54,6 +63,7 @@ SetCr3ForPageTables64:
     ; the page table build below.
     OneTimeCall   GetSevCBitMaskAbove31
 
+ClearOvmfPageTables:
     ;
     ; For OVMF, build some initial page tables at
     ; PcdOvmfSecPageTablesBase - (PcdOvmfSecPageTablesBase + 0x6000).
@@ -105,6 +115,9 @@ pageTableEntriesLoop:
     ; Clear the C-bit from the GHCB page if the SEV-ES is enabled.
     OneTimeCall   SevClearPageEncMaskForGhcbPage
 
+    ; Set byte[TDX_WORK_AREA_PGTBL_READY] if TDX is enabled.
+    OneTimeCall   TdxPostBuildPageTables
+
 SetCr3:
     ;
     ; Set CR3 now that the paging structures are available
diff --git a/OvmfPkg/ResetVector/Main.asm b/OvmfPkg/ResetVector/Main.asm
index ae90a148fce7..2a7efbc48a2a 100644
--- a/OvmfPkg/ResetVector/Main.asm
+++ b/OvmfPkg/ResetVector/Main.asm
@@ -35,7 +35,23 @@ Main16:
     OneTimeCall TransitionFromReal16To32BitFlat
 
 BITS    32
+%ifdef ARCH_X64
 
+    ; Clear the WorkArea header. The SEV probe routines will populate the
+    ; work area when detected.
+    mov     byte[WORK_AREA_GUEST_TYPE], 0
+
+    jmp SearchBfv
+
+;
+; Entry point of Main32
+;
+Main32:
+    OneTimeCall InitTdx
+
+SearchBfv:
+
+%endif
     ;
     ; Search for the Boot Firmware Volume (BFV)
     ;
diff --git a/OvmfPkg/ResetVector/ResetVector.inf b/OvmfPkg/ResetVector/ResetVector.inf
index a2520dde5508..320e5f2c6527 100644
--- a/OvmfPkg/ResetVector/ResetVector.inf
+++ b/OvmfPkg/ResetVector/ResetVector.inf
@@ -44,6 +44,15 @@
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfWorkAreaBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfWorkAreaSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdCfvBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdCfvRawDataOffset
+  gUefiOvmfPkgTokenSpaceGuid.PcdCfvRawDataSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdBfvBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdBfvRawDataOffset
+  gUefiOvmfPkgTokenSpaceGuid.PcdBfvRawDataSize
 
 [FixedPcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdSevLaunchSecretBase
diff --git a/OvmfPkg/ResetVector/ResetVector.nasmb b/OvmfPkg/ResetVector/ResetVector.nasmb
index d1d800c56745..5f30d099a7f1 100644
--- a/OvmfPkg/ResetVector/ResetVector.nasmb
+++ b/OvmfPkg/ResetVector/ResetVector.nasmb
@@ -67,8 +67,39 @@
     %error "This implementation inherently depends on PcdOvmfSecGhcbBase not straddling a 2MB boundary"
   %endif
 
+  %define TDX_BFV_RAW_DATA_OFFSET   FixedPcdGet32 (PcdBfvRawDataOffset)
+  %define TDX_BFV_RAW_DATA_SIZE     FixedPcdGet32 (PcdBfvRawDataSize)
+  %define TDX_BFV_MEMORY_BASE       FixedPcdGet32 (PcdBfvBase)
+  %define TDX_BFV_MEMORY_SIZE       FixedPcdGet32 (PcdBfvRawDataSize)
+
+  %define TDX_CFV_RAW_DATA_OFFSET   FixedPcdGet32 (PcdCfvRawDataOffset)
+  %define TDX_CFV_RAW_DATA_SIZE     FixedPcdGet32 (PcdCfvRawDataSize)
+  %define TDX_CFV_MEMORY_BASE       FixedPcdGet32 (PcdCfvBase),
+  %define TDX_CFV_MEMORY_SIZE       FixedPcdGet32 (PcdCfvRawDataSize),
+
+  %define TDX_HEAP_MEMORY_BASE      FixedPcdGet32 (PcdOvmfSecPeiTempRamBase)
+  %define TDX_HEAP_MEMORY_SIZE      FixedPcdGet32 (PcdOvmfSecPeiTempRamSize) / 2
+
+  %define TDX_STACK_MEMORY_BASE     (TDX_HEAP_MEMORY_BASE + TDX_HEAP_MEMORY_SIZE)
+  %define TDX_STACK_MEMORY_SIZE     FixedPcdGet32 (PcdOvmfSecPeiTempRamSize) / 2
+
+  %define TDX_HOB_MEMORY_BASE       FixedPcdGet32 (PcdOvmfSecGhcbBase)
+  %define TDX_HOB_MEMORY_SIZE       FixedPcdGet32 (PcdOvmfSecGhcbSize)
+
+  %define TDX_MAILBOX_MEMORY_BASE   FixedPcdGet32 (PcdOvmfSecGhcbBackupBase)
+  %define TDX_MAILBOX_MEMORY_SIZE   FixedPcdGet32 (PcdOvmfSecGhcbBackupSize)
+
+  %define OVMF_PAGE_TABLE_BASE      FixedPcdGet32 (PcdOvmfSecPageTablesBase)
+  %define OVMF_PAGE_TABLE_SIZE      FixedPcdGet32 (PcdOvmfSecPageTablesSize)
+
+  %define TDX_WORK_AREA_PGTBL_READY (FixedPcdGet32 (PcdOvmfWorkAreaBase) + 4)
+  %define TDX_WORK_AREA_GPAW        (FixedPcdGet32 (PcdOvmfWorkAreaBase) + 8)
+
   %define PT_ADDR(Offset) (FixedPcdGet32 (PcdOvmfSecPageTablesBase) + (Offset))
 
+  %define OVMF_WORK_AREA_BASE (FixedPcdGet32 (PcdOvmfWorkAreaBase))
+  %define OVMF_WORK_AREA_SIZE (FixedPcdGet32 (PcdOvmfWorkAreaSize))
+
   %define GHCB_PT_ADDR (FixedPcdGet32 (PcdOvmfSecGhcbPageTableBase))
   %define GHCB_BASE (FixedPcdGet32 (PcdOvmfSecGhcbBase))
   %define GHCB_SIZE (FixedPcdGet32 (PcdOvmfSecGhcbSize))
@@ -77,9 +108,12 @@
   %define SEV_ES_WORK_AREA_RDRAND (FixedPcdGet32 (PcdSevEsWorkAreaBase) + 8)
   %define SEV_ES_WORK_AREA_ENC_MASK (FixedPcdGet32 (PcdSevEsWorkAreaBase) + 16)
   %define SEV_ES_VC_TOP_OF_STACK (FixedPcdGet32 (PcdOvmfSecPeiTempRamBase) + FixedPcdGet32 (PcdOvmfSecPeiTempRamSize))
-%include "Ia32/Flat32ToFlat64.asm"
-%include "Ia32/AmdSev.asm"
-%include "Ia32/PageTables64.asm"
+
+  %include "X64/IntelTdxMetadata.asm"
+  %include "Ia32/Flat32ToFlat64.asm"
+  %include "Ia32/AmdSev.asm"
+  %include "Ia32/PageTables64.asm"
+  %include "Ia32/IntelTdx.asm"
 %endif
 
 %include "Ia16/Real16ToFlat32.asm"
diff --git a/OvmfPkg/ResetVector/X64/IntelTdxMetadata.asm b/OvmfPkg/ResetVector/X64/IntelTdxMetadata.asm
new file mode 100644
index 000000000000..18e10931bbc2
--- /dev/null
+++ b/OvmfPkg/ResetVector/X64/IntelTdxMetadata.asm
@@ -0,0 +1,102 @@
+;------------------------------------------------------------------------------
+; @file
+; Tdx Virtual Firmware metadata
+;
+; Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+;------------------------------------------------------------------------------
+
+BITS    64
+
+%define TDX_METADATA_SECTION_TYPE_BFV       0
+%define TDX_METADATA_SECTION_TYPE_CFV       1
+%define TDX_METADATA_SECTION_TYPE_TD_HOB    2
+%define TDX_METADATA_SECTION_TYPE_TEMP_MEM  3
+%define TDX_METADATA_VERSION                1
+%define TDX_METADATA_ATTRIBUTES_EXTENDMR    0x00000001
+
+ALIGN   16
+TIMES (15 - ((TdxGuidedStructureEnd - TdxGuidedStructureStart + 15) % 16)) DB 0
+
+TdxGuidedStructureStart:
+
+;
+; TDVF meta data
+;
+TdxMetadataGuid:
+  DB  0xf3, 0xf9, 0xea, 0xe9, 0x8e, 0x16, 0xd5, 0x44
+  DB  0xa8, 0xeb, 0x7f, 0x4d, 0x87, 0x38, 0xf6, 0xae
+
+_Descriptor:
+  DB 'T','D','V','F'                                  ; Signature
+  DD TdxGuidedStructureEnd - _Descriptor              ; Length
+  DD TDX_METADATA_VERSION                             ; Version
+  DD (TdxGuidedStructureEnd - _Descriptor - 16)/32    ; Number of sections
+
+_Bfv:
+  DD TDX_BFV_RAW_DATA_OFFSET
+  DD TDX_BFV_RAW_DATA_SIZE
+  DQ TDX_BFV_MEMORY_BASE
+  DQ TDX_BFV_MEMORY_SIZE
+  DD TDX_METADATA_SECTION_TYPE_BFV
+  DD TDX_METADATA_ATTRIBUTES_EXTENDMR
+
+_Cfv:
+  DD TDX_CFV_RAW_DATA_OFFSET
+  DD TDX_CFV_RAW_DATA_SIZE
+  DQ TDX_CFV_MEMORY_BASE
+  DQ TDX_CFV_MEMORY_SIZE
+  DD TDX_METADATA_SECTION_TYPE_CFV
+  DD 0
+
+_Stack:
+  DD 0
+  DD 0
+  DQ TDX_STACK_MEMORY_BASE
+  DQ TDX_STACK_MEMORY_SIZE
+  DD TDX_METADATA_SECTION_TYPE_TEMP_MEM
+  DD 0
+
+_Heap:
+  DD 0
+  DD 0
+  DQ TDX_HEAP_MEMORY_BASE
+  DQ TDX_HEAP_MEMORY_SIZE
+  DD TDX_METADATA_SECTION_TYPE_TEMP_MEM
+  DD 0
+
+_MailBox:
+  DD 0
+  DD 0
+  DQ TDX_MAILBOX_MEMORY_BASE
+  DQ TDX_MAILBOX_MEMORY_SIZE
+  DD TDX_METADATA_SECTION_TYPE_TEMP_MEM
+  DD 0
+
+_OvmfWorkarea:
+  DD 0
+  DD 0
+  DQ OVMF_WORK_AREA_BASE
+  DQ OVMF_WORK_AREA_SIZE
+  DD TDX_METADATA_SECTION_TYPE_TEMP_MEM
+  DD 0
+
+_TdHob:
+  DD 0
+  DD 0
+  DQ TDX_HOB_MEMORY_BASE
+  DQ TDX_HOB_MEMORY_SIZE
+  DD TDX_METADATA_SECTION_TYPE_TD_HOB
+  DD 0
+
+_OvmfPageTable:
+  DD 0
+  DD 0
+  DQ OVMF_PAGE_TABLE_BASE
+  DQ OVMF_PAGE_TABLE_SIZE
+  DD TDX_METADATA_SECTION_TYPE_TEMP_MEM
+  DD 0
+
+TdxGuidedStructureEnd:
+ALIGN   16
-- 
2.29.2.windows.2


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

* [PATCH V2 03/28] OvmfPkg: Merge TEMP_MEM entries in Tdx metadata
  2021-10-05  3:39 [PATCH V2 00/28] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
  2021-10-05  3:39 ` [PATCH V2 01/28] OvmfPkg: Copy Main.asm from UefiCpuPkg to OvmfPkg's ResetVector Min Xu
  2021-10-05  3:39 ` [PATCH V2 02/28] OvmfPkg: Enable TDX in ResetVector Min Xu
@ 2021-10-05  3:39 ` Min Xu
  2021-10-05  3:39 ` [PATCH V2 04/28] MdePkg: Add Tdx.h Min Xu
                   ` (24 subsequent siblings)
  27 siblings, 0 replies; 91+ messages in thread
From: Min Xu @ 2021-10-05  3:39 UTC (permalink / raw)
  To: devel; +Cc: Min Xu

Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/ResetVector/ResetVector.nasmb        | 13 ++++-----
 OvmfPkg/ResetVector/X64/IntelTdxMetadata.asm | 28 +++++---------------
 2 files changed, 11 insertions(+), 30 deletions(-)

diff --git a/OvmfPkg/ResetVector/ResetVector.nasmb b/OvmfPkg/ResetVector/ResetVector.nasmb
index 5f30d099a7f1..bf1ed8228133 100644
--- a/OvmfPkg/ResetVector/ResetVector.nasmb
+++ b/OvmfPkg/ResetVector/ResetVector.nasmb
@@ -77,21 +77,18 @@
   %define TDX_CFV_MEMORY_BASE       FixedPcdGet32 (PcdCfvBase),
   %define TDX_CFV_MEMORY_SIZE       FixedPcdGet32 (PcdCfvRawDataSize),
 
-  %define TDX_HEAP_MEMORY_BASE      FixedPcdGet32 (PcdOvmfSecPeiTempRamBase)
-  %define TDX_HEAP_MEMORY_SIZE      FixedPcdGet32 (PcdOvmfSecPeiTempRamSize) / 2
-
-  %define TDX_STACK_MEMORY_BASE     (TDX_HEAP_MEMORY_BASE + TDX_HEAP_MEMORY_SIZE)
-  %define TDX_STACK_MEMORY_SIZE     FixedPcdGet32 (PcdOvmfSecPeiTempRamSize) / 2
+  %define TDX_HEAP_STACK_BASE       FixedPcdGet32 (PcdOvmfSecPeiTempRamBase)
+  %define TDX_HEAP_STACK_SIZE       FixedPcdGet32 (PcdOvmfSecPeiTempRamSize)
 
   %define TDX_HOB_MEMORY_BASE       FixedPcdGet32 (PcdOvmfSecGhcbBase)
   %define TDX_HOB_MEMORY_SIZE       FixedPcdGet32 (PcdOvmfSecGhcbSize)
 
-  %define TDX_MAILBOX_MEMORY_BASE   FixedPcdGet32 (PcdOvmfSecGhcbBackupBase)
-  %define TDX_MAILBOX_MEMORY_SIZE   FixedPcdGet32 (PcdOvmfSecGhcbBackupSize)
-
   %define OVMF_PAGE_TABLE_BASE      FixedPcdGet32 (PcdOvmfSecPageTablesBase)
   %define OVMF_PAGE_TABLE_SIZE      FixedPcdGet32 (PcdOvmfSecPageTablesSize)
 
+  %define TDX_INIT_MEMORY_BASE      FixedPcdGet32 (PcdOvmfWorkAreaBase)
+  %define TDX_INIT_MEMORY_SIZE      (FixedPcdGet32 (PcdOvmfWorkAreaSize) + FixedPcdGet32 (PcdOvmfSecGhcbBackupSize))
+
   %define TDX_WORK_AREA_PGTBL_READY (FixedPcdGet32 (PcdOvmfWorkAreaBase) + 4)
   %define TDX_WORK_AREA_GPAW        (FixedPcdGet32 (PcdOvmfWorkAreaBase) + 8)
 
diff --git a/OvmfPkg/ResetVector/X64/IntelTdxMetadata.asm b/OvmfPkg/ResetVector/X64/IntelTdxMetadata.asm
index 18e10931bbc2..dd66b468c5c6 100644
--- a/OvmfPkg/ResetVector/X64/IntelTdxMetadata.asm
+++ b/OvmfPkg/ResetVector/X64/IntelTdxMetadata.asm
@@ -50,35 +50,19 @@ _Cfv:
   DD TDX_METADATA_SECTION_TYPE_CFV
   DD 0
 
-_Stack:
+_TdxHeapStack:
   DD 0
   DD 0
-  DQ TDX_STACK_MEMORY_BASE
-  DQ TDX_STACK_MEMORY_SIZE
+  DQ TDX_HEAP_STACK_BASE
+  DQ TDX_HEAP_STACK_SIZE
   DD TDX_METADATA_SECTION_TYPE_TEMP_MEM
   DD 0
 
-_Heap:
+_TdxInitMem:
   DD 0
   DD 0
-  DQ TDX_HEAP_MEMORY_BASE
-  DQ TDX_HEAP_MEMORY_SIZE
-  DD TDX_METADATA_SECTION_TYPE_TEMP_MEM
-  DD 0
-
-_MailBox:
-  DD 0
-  DD 0
-  DQ TDX_MAILBOX_MEMORY_BASE
-  DQ TDX_MAILBOX_MEMORY_SIZE
-  DD TDX_METADATA_SECTION_TYPE_TEMP_MEM
-  DD 0
-
-_OvmfWorkarea:
-  DD 0
-  DD 0
-  DQ OVMF_WORK_AREA_BASE
-  DQ OVMF_WORK_AREA_SIZE
+  DQ TDX_INIT_MEMORY_BASE
+  DQ TDX_INIT_MEMORY_SIZE
   DD TDX_METADATA_SECTION_TYPE_TEMP_MEM
   DD 0
 
-- 
2.29.2.windows.2


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

* [PATCH V2 04/28] MdePkg: Add Tdx.h
  2021-10-05  3:39 [PATCH V2 00/28] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (2 preceding siblings ...)
  2021-10-05  3:39 ` [PATCH V2 03/28] OvmfPkg: Merge TEMP_MEM entries in Tdx metadata Min Xu
@ 2021-10-05  3:39 ` Min Xu
  2021-10-12  7:48   ` [edk2-devel] " Gerd Hoffmann
  2021-10-05  3:39 ` [PATCH V2 05/28] MdePkg: Add TdxLib to wrap Tdx operations Min Xu
                   ` (23 subsequent siblings)
  27 siblings, 1 reply; 91+ messages in thread
From: Min Xu @ 2021-10-05  3:39 UTC (permalink / raw)
  To: devel; +Cc: Min Xu, Michael D Kinney, Liming Gao, Zhiguang Liu, 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: Jiewen Yao <jiewen.yao@intel.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..11b3d3345de3
--- /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] 91+ messages in thread

* [PATCH V2 05/28] MdePkg: Add TdxLib to wrap Tdx operations
  2021-10-05  3:39 [PATCH V2 00/28] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (3 preceding siblings ...)
  2021-10-05  3:39 ` [PATCH V2 04/28] MdePkg: Add Tdx.h Min Xu
@ 2021-10-05  3:39 ` Min Xu
  2021-10-12  8:22   ` [edk2-devel] " Gerd Hoffmann
  2021-10-05  3:39 ` [PATCH V2 06/28] MdePkg: Update BaseIoLibIntrinsicSev to support Tdx Min Xu
                   ` (22 subsequent siblings)
  27 siblings, 1 reply; 91+ messages in thread
From: Min Xu @ 2021-10-05  3:39 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

TdxLib is created with functions to perform the related Tdx operation.
This includes functions for:
 - TdCall          : Cause a VM exit to the Intel TDX module.
 - TdVmCall        : It helps invoke services from the host VMM to pass/
                     receive information.
 - TdVmCallCpuid   : Enable the TD guest to request VMM to emulate CPUID
 - 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>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 MdePkg/Include/Library/TdxLib.h         | 167 +++++++++++++++++++
 MdePkg/Library/TdxLib/AcceptPages.c     | 136 ++++++++++++++++
 MdePkg/Library/TdxLib/Rtmr.c            | 118 ++++++++++++++
 MdePkg/Library/TdxLib/TdInfo.c          | 103 ++++++++++++
 MdePkg/Library/TdxLib/TdxLib.inf        |  39 +++++
 MdePkg/Library/TdxLib/TdxLibNull.c      | 192 ++++++++++++++++++++++
 MdePkg/Library/TdxLib/X64/Tdcall.nasm   |  85 ++++++++++
 MdePkg/Library/TdxLib/X64/Tdvmcall.nasm | 207 ++++++++++++++++++++++++
 MdePkg/MdePkg.dec                       |   3 +
 MdePkg/MdePkg.dsc                       |   1 +
 10 files changed, 1051 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
 create mode 100644 MdePkg/Library/TdxLib/X64/Tdcall.nasm
 create mode 100644 MdePkg/Library/TdxLib/X64/Tdvmcall.nasm

diff --git a/MdePkg/Include/Library/TdxLib.h b/MdePkg/Include/Library/TdxLib.h
new file mode 100644
index 000000000000..43a7d709657e
--- /dev/null
+++ b/MdePkg/Include/Library/TdxLib.h
@@ -0,0 +1,167 @@
+/** @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.
+  @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 UINT64  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
+  );
+
+
+/**
+  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
+**/
+EFI_STATUS
+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
+
+**/
+EFI_STATUS
+EFIAPI
+TdVmCall (
+  IN UINT64          Leaf,
+  IN UINT64          Arg1,
+  IN UINT64          Arg2,
+  IN UINT64          Arg3,
+  IN UINT64          Arg4,
+  IN OUT VOID        *Results
+  );
+
+/**
+  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/MdePkg/Library/TdxLib/AcceptPages.c b/MdePkg/Library/TdxLib/AcceptPages.c
new file mode 100644
index 000000000000..8941dc05b114
--- /dev/null
+++ b/MdePkg/Library/TdxLib/AcceptPages.c
@@ -0,0 +1,136 @@
+/** @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;
+
+// PageSize is mapped to PageLevel like below:
+// 4KB - 0, 2MB - 1
+UINT64  mTdxAcceptPageLevelMap[2] = {
+  SIZE_4KB,
+  SIZE_2MB
+};
+
+/**
+  This function gets the PageLevel according to the input page size.
+
+  @param[in]  PageSize    Page size
+
+  @return UINTN           The mapped page level
+**/
+UINTN
+GetGpaPageLevel (
+  UINT64 PageSize
+  )
+{
+  UINTN Index;
+
+  for (Index = 0; Index < sizeof (mTdxAcceptPageLevelMap) / sizeof (mTdxAcceptPageLevelMap[0]); 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.
+  @param[in]  NumberOfPages     Number of the pages to be accepted.
+  @param[in]  PageSize          GPA page size. Only accept 1G/2M/4K size.
+
+  @return EFI_SUCCESS           Accept successfully
+  @return others                Indicate other errors
+**/
+EFI_STATUS
+EFIAPI
+TdAcceptPages (
+  IN UINT64  StartAddress,
+  IN UINT64  NumberOfPages,
+  IN UINT64  PageSize
+  )
+{
+  EFI_STATUS  Status;
+  UINT64      Address;
+  UINT64      TdxStatus;
+  UINT64      Index;
+  UINT64      GpaPageLevel;
+  UINT64      PageSize2;
+
+  Address = StartAddress;
+
+  GpaPageLevel = (UINT64) GetGpaPageLevel (PageSize);
+  if (GpaPageLevel > sizeof (mTdxAcceptPageLevelMap) / sizeof (mTdxAcceptPageLevelMap[0])) {
+    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++) {
+    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++;
+        } 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 {
+
+          //
+          // 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..c86902ae21bc
--- /dev/null
+++ b/MdePkg/Library/TdxLib/Rtmr.c
@@ -0,0 +1,118 @@
+/** @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 + 64)
+#define EXTEND_BUFFER_ADDRESS_MASK  0x3f
+
+
+#pragma pack(16)
+typedef struct {
+  UINT8   Buffer[TD_EXTEND_BUFFER_LEN];
+} TDX_EXTEND_BUFFER;
+#pragma pack()
+
+UINT8               *mExtendBufferAddress = NULL;
+TDX_EXTEND_BUFFER   mExtendBuffer;
+
+/**
+  TD.RTMR.EXTEND requires 64B-aligned guest physical address of
+  48B-extension data. In runtime we walk thru the Buffer to find
+  out a 64B-aligned start address.
+
+  @return Start address of the extend buffer
+
+**/
+UINT8 *
+EFIAPI
+GetExtendBuffer (
+  VOID
+  )
+{
+  UINT8     *ExtendBufferAddress;
+  UINT64    Gap;
+
+  if (mExtendBufferAddress != NULL) {
+    return mExtendBufferAddress;
+  }
+
+  ExtendBufferAddress = mExtendBuffer.Buffer;
+
+  Gap = 0x40 - ((UINT64)(UINTN)ExtendBufferAddress & EXTEND_BUFFER_ADDRESS_MASK);
+  mExtendBufferAddress = (UINT8*)((UINT64)(UINTN)ExtendBufferAddress + Gap);
+
+  DEBUG ((DEBUG_VERBOSE, "ExtendBufferAddress: 0x%p, Gap: 0x%x\n", ExtendBufferAddress, Gap));
+  DEBUG ((DEBUG_VERBOSE, "mExtendBufferAddress: 0x%p\n", mExtendBufferAddress));
+
+  ASSERT (mExtendBufferAddress + 64 <= ExtendBufferAddress + TD_EXTEND_BUFFER_LEN);
+
+  return mExtendBufferAddress;
+}
+
+
+/**
+  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 (Index >= 0 && Index < RTMR_COUNT);
+  ASSERT (DataLen == SHA384_DIGEST_SIZE);
+
+  ExtendBuffer = GetExtendBuffer();
+  ASSERT (ExtendBuffer != NULL);
+  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..56c268e70c8d
--- /dev/null
+++ b/MdePkg/Library/TdxLib/TdInfo.c
@@ -0,0 +1,103 @@
+/** @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;
+
+/**
+  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
+  )
+{
+  UINT64                      Status;
+  UINT8                       Gpaw;
+  TD_RETURN_DATA              TdReturnData;
+
+  if (mTdSharedPageMask != 0) {
+    return mTdSharedPageMask;
+  }
+
+  Status = TdCall (TDCALL_TDINFO, 0, 0, 0, &TdReturnData);
+  ASSERT (Status == TDX_EXIT_REASON_SUCCESS);
+
+  Gpaw = (UINT8)(TdReturnData.TdInfo.Gpaw & 0x3f);
+  ASSERT(Gpaw == 48 || Gpaw == 52);
+  mTdSharedPageMask = 1ULL << (Gpaw - 1);
+  return mTdSharedPageMask;
+}
+
+/**
+  This function gets the maximum number of Virtual CPUs that are usable for
+  Td Guest.
+
+  @return maximum Virtual CPUs number
+**/
+UINT32
+EFIAPI
+TdMaxVCpuNum (
+  VOID
+  )
+{
+  UINT64                      Status;
+  TD_RETURN_DATA              TdReturnData;
+
+  if (mTdMaxVCpuNum != 0) {
+    return mTdMaxVCpuNum;
+  }
+
+  Status = TdCall (TDCALL_TDINFO, 0, 0, 0, &TdReturnData);
+  ASSERT (Status == TDX_EXIT_REASON_SUCCESS);
+
+  mTdMaxVCpuNum = TdReturnData.TdInfo.MaxVcpus;
+
+  return mTdMaxVCpuNum;
+}
+
+/**
+  This function gets the number of Virtual CPUs that are usable for Td
+  Guest.
+
+  @return Virtual CPUs number
+**/
+UINT32
+EFIAPI
+TdVCpuNum (
+  VOID
+  )
+{
+  UINT64                      Status;
+  TD_RETURN_DATA              TdReturnData;
+
+  if (mTdVCpuNum != 0) {
+    return mTdVCpuNum;
+  }
+
+  Status = TdCall (TDCALL_TDINFO, 0, 0, 0, &TdReturnData);
+  ASSERT (Status == TDX_EXIT_REASON_SUCCESS);
+
+  mTdVCpuNum = TdReturnData.TdInfo.NumVcpus;
+  return mTdVCpuNum;
+}
diff --git a/MdePkg/Library/TdxLib/TdxLib.inf b/MdePkg/Library/TdxLib/TdxLib.inf
new file mode 100644
index 000000000000..772abcc49d8b
--- /dev/null
+++ b/MdePkg/Library/TdxLib/TdxLib.inf
@@ -0,0 +1,39 @@
+## @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
+  X64/Tdcall.nasm
+  X64/Tdvmcall.nasm
+
+[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..5a8f19c6d8d2
--- /dev/null
+++ b/MdePkg/Library/TdxLib/TdxLibNull.c
@@ -0,0 +1,192 @@
+/** @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 UINT64  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;
+}
+
+
+/**
+  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
+**/
+EFI_STATUS
+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
+
+**/
+EFI_STATUS
+EFIAPI
+TdVmCall (
+  IN UINT64          Leaf,
+  IN UINT64          Arg1,
+  IN UINT64          Arg2,
+  IN UINT64          Arg3,
+  IN UINT64          Arg4,
+  IN OUT VOID        *Results
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+
+/**
+  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
+  )
+{
+  return EFI_UNSUPPORTED;
+}
diff --git a/MdePkg/Library/TdxLib/X64/Tdcall.nasm b/MdePkg/Library/TdxLib/X64/Tdcall.nasm
new file mode 100644
index 000000000000..e8a094b0eb3f
--- /dev/null
+++ b/MdePkg/Library/TdxLib/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/TdxLib/X64/Tdvmcall.nasm b/MdePkg/Library/TdxLib/X64/Tdvmcall.nasm
new file mode 100644
index 000000000000..eb1cb967dc29
--- /dev/null
+++ b/MdePkg/Library/TdxLib/X64/Tdvmcall.nasm
@@ -0,0 +1,207 @@
+;------------------------------------------------------------------------------
+;*
+;* 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
+%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
+
+;------------------------------------------------------------------------------
+; 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
+;  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
+
+       ; Panic 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
+
+.panic:
+       ud2
diff --git a/MdePkg/MdePkg.dec b/MdePkg/MdePkg.dec
index 9cdc915ebae9..8b85f59e6dfb 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] 91+ messages in thread

* [PATCH V2 06/28] MdePkg: Update BaseIoLibIntrinsicSev to support Tdx
  2021-10-05  3:39 [PATCH V2 00/28] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (4 preceding siblings ...)
  2021-10-05  3:39 ` [PATCH V2 05/28] MdePkg: Add TdxLib to wrap Tdx operations Min Xu
@ 2021-10-05  3:39 ` Min Xu
  2021-10-12 10:05   ` [edk2-devel] " Gerd Hoffmann
  2021-10-05  3:39 ` [PATCH V2 07/28] UefiCpuPkg: Support TDX in BaseXApicX2ApicLib Min Xu
                   ` (21 subsequent siblings)
  27 siblings, 1 reply; 91+ messages in thread
From: Min Xu @ 2021-10-05  3:39 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.

BaseIoLibIntrinsicSev.inf is the IoLib used by OvmfPkg. TDVF updates
BaseIoLibIntrinsicSev to support I/O in Td guest. Below files are updated
to support I/O in Td guest.
 - IoLib.c
 - IoLibGcc.c
 - IoLibMsc.c
 - X64/IoFifoSev.nasm

In the I/O functions of above files, if IsTdxGuest() returns TRUE, then
Td I/O routine is called, otherwise the legacy I/O routine is called.
Td I/O routines are declared in IoLibTdx.h and implemented in
IoLibInternalTdx.c.

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 is created which holds the null stub of the Td I/O
routines. IoLibInternalTdxNull.c is included in BaseIoLibIntrinsic.inf.
BaseIoLibIntrinsic.inf doesn't import TdxLib so that the Pkgs which
include BaseIoLibIntrinsic.inf need not include TdxLib.

BaseIoLibIntrinsicArmVirt.inf is not touched because it shares no files
with BaseIoLibIntrinsicSev.

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>
---
 .../BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf |   2 +
 .../BaseIoLibIntrinsicSev.inf                 |   7 +-
 MdePkg/Library/BaseIoLibIntrinsic/IoLib.c     |  97 ++-
 MdePkg/Library/BaseIoLibIntrinsic/IoLibFifo.c | 216 +++++
 MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c  |  49 +-
 .../BaseIoLibIntrinsic/IoLibInternalTdx.c     | 735 ++++++++++++++++++
 .../BaseIoLibIntrinsic/IoLibInternalTdxNull.c | 499 ++++++++++++
 MdePkg/Library/BaseIoLibIntrinsic/IoLibMsc.c  |  73 +-
 MdePkg/Library/BaseIoLibIntrinsic/IoLibSev.h  | 166 ++++
 MdePkg/Library/BaseIoLibIntrinsic/IoLibTdx.h  | 411 ++++++++++
 .../BaseIoLibIntrinsic/X64/IoFifoSev.nasm     |  34 +-
 11 files changed, 2223 insertions(+), 66 deletions(-)
 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

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 34f9d1d1062f..7e94be5a794f 100644
--- a/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicSev.inf
+++ b/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicSev.inf
@@ -30,17 +30,22 @@
   IoLibMmioBuffer.c
   BaseIoLibIntrinsicInternal.h
   IoHighLevel.c
+  IoLibSev.h
+  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
+  IoLibFifo.c
+  IoLibInternalTdx.c
   X64/IoFifoSev.nasm
 
 [Packages]
@@ -50,4 +55,4 @@
   DebugLib
   BaseLib
   RegisterFilterLib
-
+  TdxLib
diff --git a/MdePkg/Library/BaseIoLibIntrinsic/IoLib.c b/MdePkg/Library/BaseIoLibIntrinsic/IoLib.c
index d0d7044f0901..68298749ee56 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.
@@ -70,6 +71,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,9 +89,13 @@ MmioRead8 (
 
   Flag = FilterBeforeMmIoRead (FilterWidth8, Address, &Value);
   if (Flag) {
-    MemoryFence ();
-    Value = *(volatile UINT8*)Address;
-    MemoryFence ();
+    if (IsTdxGuest ()) {
+      Value = TdMmioRead8 (Address);
+    } else {
+      MemoryFence ();
+      Value = *(volatile UINT8*)Address;
+      MemoryFence ();
+    }
   }
   FilterAfterMmIoRead (FilterWidth8, Address, &Value);
 
@@ -104,6 +111,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.
 
@@ -121,9 +130,13 @@ MmioWrite8 (
 
   Flag = FilterBeforeMmIoWrite (FilterWidth8, Address, &Value);
   if (Flag) {
-    MemoryFence ();
-    *(volatile UINT8*)Address = Value;
-    MemoryFence ();
+    if (IsTdxGuest ()) {
+      TdMmioWrite8 (Address, Value);
+    } else {
+      MemoryFence ();
+      *(volatile UINT8*)Address = Value;
+      MemoryFence ();
+    }
   }
   FilterAfterMmIoWrite (FilterWidth8, Address, &Value);
 
@@ -140,6 +153,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.
@@ -157,9 +172,13 @@ MmioRead16 (
   ASSERT ((Address & 1) == 0);
   Flag = FilterBeforeMmIoRead (FilterWidth16, Address, &Value);
   if (Flag) {
-    MemoryFence ();
-    Value = *(volatile UINT16*)Address;
-    MemoryFence ();
+    if (IsTdxGuest ()) {
+      Value = TdMmioRead16 (Address);
+    } else {
+      MemoryFence ();
+      Value = *(volatile UINT16*)Address;
+      MemoryFence ();
+    }
   }
   FilterAfterMmIoRead (FilterWidth16, Address, &Value);
 
@@ -176,6 +195,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.
 
@@ -195,9 +216,13 @@ MmioWrite16 (
 
   Flag = FilterBeforeMmIoWrite (FilterWidth16, Address, &Value);
   if (Flag) {
-    MemoryFence ();
-    *(volatile UINT16*)Address = Value;
-    MemoryFence ();
+    if (IsTdxGuest ()) {
+      TdMmioWrite16 (Address, Value);
+    } else {
+      MemoryFence ();
+      *(volatile UINT16*)Address = Value;
+      MemoryFence ();
+    }
   }
   FilterAfterMmIoWrite (FilterWidth16, Address, &Value);
 
@@ -214,6 +239,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.
@@ -232,9 +259,13 @@ MmioRead32 (
 
   Flag = FilterBeforeMmIoRead (FilterWidth32, Address, &Value);
   if (Flag) {
-    MemoryFence ();
-    Value = *(volatile UINT32*)Address;
-    MemoryFence ();
+    if (IsTdxGuest ()) {
+      Value = TdMmioRead32 (Address);
+    } else {
+      MemoryFence ();
+      Value = *(volatile UINT32*)Address;
+      MemoryFence ();
+    }
   }
   FilterAfterMmIoRead (FilterWidth32, Address, &Value);
 
@@ -251,6 +282,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.
 
@@ -270,9 +303,13 @@ MmioWrite32 (
 
   Flag = FilterBeforeMmIoWrite (FilterWidth32, Address, &Value);
   if (Flag) {
-    MemoryFence ();
-    *(volatile UINT32*)Address = Value;
-    MemoryFence ();
+    if (IsTdxGuest ()) {
+      TdMmioWrite32 (Address, Value);
+    } else {
+      MemoryFence ();
+      *(volatile UINT32*)Address = Value;
+      MemoryFence ();
+    }
   }
   FilterAfterMmIoWrite (FilterWidth32, Address, &Value);
 
@@ -289,6 +326,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.
@@ -307,9 +346,13 @@ MmioRead64 (
 
   Flag = FilterBeforeMmIoRead (FilterWidth64, Address, &Value);
   if (Flag) {
-    MemoryFence ();
-    Value = *(volatile UINT64*)Address;
-    MemoryFence ();
+    if (IsTdxGuest ()) {
+      Value = TdMmioRead64 (Address);
+    } else {
+      MemoryFence ();
+      Value = *(volatile UINT64*)Address;
+      MemoryFence ();
+    }
   }
   FilterAfterMmIoRead (FilterWidth64, Address, &Value);
 
@@ -326,6 +369,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.
 
@@ -343,9 +388,13 @@ MmioWrite64 (
 
   Flag = FilterBeforeMmIoWrite (FilterWidth64, Address, &Value);
   if (Flag) {
-    MemoryFence ();
-    *(volatile UINT64*)Address = Value;
-    MemoryFence ();
+    if (IsTdxGuest ()) {
+      TdMmioWrite64 (Address, Value);
+    } else {
+      MemoryFence ();
+      *(volatile UINT64*)Address = Value;
+      MemoryFence ();
+    }
   }
   FilterAfterMmIoWrite (FilterWidth64, Address, &Value);
 
diff --git a/MdePkg/Library/BaseIoLibIntrinsic/IoLibFifo.c b/MdePkg/Library/BaseIoLibIntrinsic/IoLibFifo.c
new file mode 100644
index 000000000000..9e243543cfe2
--- /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/IoLibGcc.c b/MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c
index ecf9ed61911f..42b5d5743a4f 100644
--- a/MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c
+++ b/MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c
@@ -17,6 +17,7 @@
 
 
 #include "BaseIoLibIntrinsicInternal.h"
+#include "IoLibTdx.h"
 
 /**
   Reads an 8-bit I/O port.
@@ -25,7 +26,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.
 
@@ -43,7 +46,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);
 
@@ -93,6 +106,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.
@@ -111,7 +126,11 @@ IoRead16 (
 
   Flag = FilterBeforeIoRead (FilterWidth16, Port, &Data);
   if (Flag) {
+    if (IsTdxGuest ()) {
+      Data = TdIoRead16 (Port);
+    } else {
      __asm__ __volatile__ ("inw %w1,%w0" : "=a" (Data) : "d" ((UINT16)Port));
+    }
   }
   FilterAfterIoRead (FilterWidth16, Port, &Data);
 
@@ -128,6 +147,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.
 
@@ -148,7 +169,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);
 
@@ -165,6 +190,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.
@@ -183,7 +210,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);
 
@@ -200,6 +231,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.
 
@@ -219,7 +252,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/IoLibInternalTdx.c b/MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdx.c
new file mode 100644
index 000000000000..d321cc9f00be
--- /dev/null
+++ b/MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdx.c
@@ -0,0 +1,735 @@
+/** @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 <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
+  )
+{
+  UINT32    Eax;
+  UINT32    Ebx;
+  UINT32    Ecx;
+  UINT32    Edx;
+  UINT32    LargestEax;
+
+  if (mTdxProbed) {
+    return mTdxEnabled;
+  }
+
+  mTdxEnabled = FALSE;
+
+  do {
+    AsmCpuid (0, &LargestEax, &Ebx, &Ecx, &Edx);
+
+    if (Ebx != SIGNATURE_32 ('G', 'e', 'n', 'u')
+      || Edx != SIGNATURE_32 ('i', 'n', 'e', 'I')
+      || Ecx != SIGNATURE_32 ('n', 't', 'e', 'l')) {
+      break;
+    }
+
+    AsmCpuid (1, 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;
+    }
+
+    mTdxEnabled = TRUE;
+  }while (FALSE);
+
+  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;
+
+  Address |= TdSharedPageMask ();
+
+  MemoryFence ();
+  Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_1, TDVMCALL_ACCESS_READ, Address, 0, &Value);
+  if (Status != 0) {
+    Value = *(volatile UINT64*) Address;
+  }
+  MemoryFence ();
+
+  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;
+
+  Address |= TdSharedPageMask ();
+
+  MemoryFence ();
+  Val = Value;
+  Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_1, TDVMCALL_ACCESS_WRITE, Address, Val, 0);
+  if (Status != 0) {
+    *(volatile UINT8*) Address = Value;
+  }
+  MemoryFence ();
+
+  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;
+
+  Address |= TdSharedPageMask ();
+
+  MemoryFence ();
+  Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_2, TDVMCALL_ACCESS_READ, Address, 0, &Value);
+  if (Status != 0) {
+    Value = *(volatile UINT64*) Address;
+  }
+  MemoryFence ();
+
+  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);
+
+  Address |= TdSharedPageMask ();
+
+  MemoryFence ();
+  Val = Value;
+  Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_2, TDVMCALL_ACCESS_WRITE, Address, Val, 0);
+  if (Status != 0) {
+    *(volatile UINT16*) Address = Value;
+  }
+  MemoryFence ();
+
+  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;
+
+  Address |= TdSharedPageMask ();
+
+  MemoryFence ();
+  Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_4, TDVMCALL_ACCESS_READ, Address, 0, &Value);
+  if (Status != 0) {
+    Value = *(volatile UINT64*)Address;
+  }
+  MemoryFence ();
+
+  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);
+
+  Address |= TdSharedPageMask ();
+
+  MemoryFence ();
+  Val = Value;
+  Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_4, TDVMCALL_ACCESS_WRITE, Address, Val, 0);
+  if (Status != 0) {
+    *(volatile UINT32*)Address = Value;
+  }
+  MemoryFence ();
+
+  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;
+
+  Address |= TdSharedPageMask ();
+
+  MemoryFence ();
+  Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_8, TDVMCALL_ACCESS_READ, Address, 0, &Value);
+  if (Status != 0) {
+    Value = *(volatile UINT64*)Address;
+  }
+  MemoryFence ();
+
+  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);
+
+  Address |= TdSharedPageMask ();
+
+  MemoryFence ();
+  Val = Value;
+  Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_8, TDVMCALL_ACCESS_WRITE, Address, Val, 0);
+  if (Status != 0) {
+    *(volatile UINT64*)Address = Value;
+  }
+  MemoryFence ();
+  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..f518d8ffd825
--- /dev/null
+++ b/MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdxNull.c
@@ -0,0 +1,499 @@
+/** @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/IoLibMsc.c b/MdePkg/Library/BaseIoLibIntrinsic/IoLibMsc.c
index d2bc5f527cf6..4d7945ae496f 100644
--- a/MdePkg/Library/BaseIoLibIntrinsic/IoLibMsc.c
+++ b/MdePkg/Library/BaseIoLibIntrinsic/IoLibMsc.c
@@ -16,6 +16,7 @@
 
 
 #include "BaseIoLibIntrinsicInternal.h"
+#include "IoLibTdx.h"
 
 //
 // Microsoft Visual Studio 7.1 Function Prototypes for I/O Intrinsics.
@@ -54,6 +55,8 @@ void          _ReadWriteBarrier (void);
 
   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.
@@ -70,9 +73,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);
 
@@ -88,6 +95,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.
 
@@ -105,9 +114,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);
 
@@ -124,6 +137,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.
@@ -142,9 +157,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);
 
@@ -161,6 +180,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.
 
@@ -180,9 +201,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);
 
@@ -199,6 +224,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.
@@ -217,9 +244,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);
 
@@ -236,6 +267,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.
 
@@ -255,9 +288,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);
 
diff --git a/MdePkg/Library/BaseIoLibIntrinsic/IoLibSev.h b/MdePkg/Library/BaseIoLibIntrinsic/IoLibSev.h
new file mode 100644
index 000000000000..e219f8a36a47
--- /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/IoLibTdx.h b/MdePkg/Library/BaseIoLibIntrinsic/IoLibTdx.h
new file mode 100644
index 000000000000..3aad197d3b39
--- /dev/null
+++ b/MdePkg/Library/BaseIoLibIntrinsic/IoLibTdx.h
@@ -0,0 +1,411 @@
+/** @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
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] 91+ messages in thread

* [PATCH V2 07/28] UefiCpuPkg: Support TDX in BaseXApicX2ApicLib
  2021-10-05  3:39 [PATCH V2 00/28] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (5 preceding siblings ...)
  2021-10-05  3:39 ` [PATCH V2 06/28] MdePkg: Update BaseIoLibIntrinsicSev to support Tdx Min Xu
@ 2021-10-05  3:39 ` Min Xu
  2021-10-12 10:15   ` [edk2-devel] " Gerd Hoffmann
  2021-10-13  5:30   ` Ni, Ray
  2021-10-05  3:39 ` [PATCH V2 08/28] UefiCpuPkg: Add VmTdExitLibNull Min Xu
                   ` (20 subsequent siblings)
  27 siblings, 2 replies; 91+ messages in thread
From: Min Xu @ 2021-10-05  3:39 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Eric Dong, Ray Ni, Rahul Kumar, Brijesh Singh,
	Erdem Aktas, James Bottomley, Jiewen Yao, Tom Lendacky

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.

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>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 .../BaseXApicX2ApicLib/BaseXApicX2ApicLib.c   | 233 +++++++++++++++++-
 .../BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf |   1 +
 UefiCpuPkg/UefiCpuPkg.dsc                     |   1 +
 3 files changed, 227 insertions(+), 8 deletions(-)

diff --git a/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c b/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c
index cdcbca046191..eaa132ea30f4 100644
--- a/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c
+++ b/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c
@@ -23,11 +23,227 @@
 #include <Library/TimerLib.h>
 #include <Library/PcdLib.h>
 #include <Library/UefiCpuLib.h>
+#include <IndustryStandard/Tdx.h>
+#include <Library/TdxLib.h>
 
 //
 // Library internal functions
 //
 
+BOOLEAN mBaseXApicIsTdxEnabled = FALSE;
+BOOLEAN mBaseXApicTdxProbed = FALSE;
+
+/**
+  Check if it is Tdx guest.
+
+  @return TRUE    It is Tdx guest
+  @return FALSE   It is not Tdx guest
+
+**/
+BOOLEAN
+EFIAPI
+BaseXApicIsTdxGuest (
+  VOID
+  )
+{
+  UINT32    Eax;
+  UINT32    Ebx;
+  UINT32    Ecx;
+  UINT32    Edx;
+  UINT32    LargestEax;
+
+  if (mBaseXApicTdxProbed) {
+    return mBaseXApicIsTdxEnabled;
+  }
+
+  mBaseXApicIsTdxEnabled = FALSE;
+
+  do {
+    AsmCpuid (0, &LargestEax, &Ebx, &Ecx, &Edx);
+
+    if (Ebx != SIGNATURE_32 ('G', 'e', 'n', 'u')
+      || Edx != SIGNATURE_32 ('i', 'n', 'e', 'I')
+      || Ecx != SIGNATURE_32 ('n', 't', 'e', 'l')) {
+      break;
+    }
+
+    AsmCpuid (1, 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;
+    }
+
+    mBaseXApicIsTdxEnabled = TRUE;
+  }while (FALSE);
+
+  mBaseXApicTdxProbed = TRUE;
+
+  return mBaseXApicIsTdxEnabled;
+}
+
+
+/**
+  Some MSRs in TDX are directly read/write from/to CPU.
+
+  @param  MsrIndex  Index of the MSR
+  @retval TRUE      MSR direct read/write from/to CPU.
+  @retval FALSE     MSR not direct read/write from/to CPU.
+
+**/
+BOOLEAN
+EFIAPI
+AccessMsrNative (
+  IN UINT32 MsrIndex
+  )
+{
+  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 TRUE;
+  default:
+    break;
+  }
+  return FALSE;
+}
+
+/**
+  Read MSR value.
+
+  @param  MsrIndex  Index of the MSR to read
+  @retval 64-bit    Value of MSR.
+
+**/
+UINT64
+EFIAPI
+ReadMsrReg64 (
+  IN UINT32 MsrIndex
+  )
+{
+  UINT64    Val;
+  UINT64    Status;
+  if (!AccessMsrNative (MsrIndex) && BaseXApicIsTdxGuest ()) {
+    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  Val       Value to be written to the MSR
+
+**/
+VOID
+EFIAPI
+WriteMsrReg64 (
+  IN UINT32 MsrIndex,
+  IN UINT64 Val
+  )
+{
+  UINT64 Status;
+  if (!AccessMsrNative (MsrIndex) && BaseXApicIsTdxGuest ()) {
+    Status = TdVmCall (TDVMCALL_WRMSR, (UINT64) MsrIndex, Val, 0, 0, 0);
+    if (Status != 0) {
+      TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
+    }
+  } else {
+    AsmWriteMsr64 (MsrIndex, Val);
+  }
+}
+
+/**
+  Read MSR value.
+
+  @param  MsrIndex  Index of the MSR to read
+  @retval 32-bit    Value of MSR.
+
+**/
+UINT32
+EFIAPI
+ReadMsrReg32 (
+  IN UINT32 MsrIndex
+  )
+{
+  UINT64    Val;
+  UINT64    Status;
+  if (!AccessMsrNative (MsrIndex) && BaseXApicIsTdxGuest ()) {
+    Status = TdVmCall (TDVMCALL_RDMSR, (UINT64) MsrIndex, 0, 0, 0, &Val);
+    if (Status != 0) {
+      TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
+    }
+  } else {
+    Val = AsmReadMsr32 (MsrIndex);
+  }
+  return (UINT32)(UINTN) Val;
+}
+
+/**
+  Write to MSR.
+
+  @param  MsrIndex  Index of the MSR to write to
+  @param  Val       Value to be written to the MSR
+
+**/
+VOID
+EFIAPI
+WriteMsrReg32 (
+  IN UINT32 MsrIndex,
+  IN UINT32 Val
+  )
+{
+  UINT64    Status;
+  if (!AccessMsrNative (MsrIndex) && BaseXApicIsTdxGuest ()) {
+    Status = TdVmCall (TDVMCALL_WRMSR, (UINT64) MsrIndex, (UINT64) Val, 0, 0, 0);
+    if (Status != 0) {
+      DEBUG((DEBUG_ERROR, "WriteMsrReg32 returned failure. Status=0x%llx\n", Status));
+      TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
+    }
+  } else {
+    AsmWriteMsr32 (MsrIndex, Val);
+  }
+}
+
 /**
   Determine if the CPU supports the Local APIC Base Address MSR.
 
@@ -77,7 +293,7 @@ GetLocalApicBaseAddress (
     return PcdGet32 (PcdCpuLocalApicBaseAddress);
   }
 
-  ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+  ApicBaseMsr.Uint64 = ReadMsrReg64 (MSR_IA32_APIC_BASE);
 
   return (UINTN)(LShiftU64 ((UINT64) ApicBaseMsr.Bits.ApicBaseHi, 32)) +
            (((UINTN)ApicBaseMsr.Bits.ApicBase) << 12);
@@ -108,12 +324,12 @@ SetLocalApicBaseAddress (
     return;
   }
 
-  ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+  ApicBaseMsr.Uint64 = ReadMsrReg64 (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);
+  WriteMsrReg64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
 }
 
 /**
@@ -153,7 +369,7 @@ ReadLocalApicReg (
     ASSERT (MmioOffset != XAPIC_ICR_HIGH_OFFSET);
 
     MsrIndex = (UINT32)(MmioOffset >> 4) + X2APIC_MSR_BASE_ADDRESS;
-    return AsmReadMsr32 (MsrIndex);
+    return ReadMsrReg32 (MsrIndex);
   }
 }
 
@@ -202,7 +418,7 @@ WriteLocalApicReg (
     // Use memory fence here to force the serializing semantics to be consisent with xAPIC mode.
     //
     MemoryFence ();
-    AsmWriteMsr32 (MsrIndex, Value);
+    WriteMsrReg32 (MsrIndex, Value);
   }
 }
 
@@ -309,7 +525,7 @@ GetApicMode (
     return LOCAL_APIC_MODE_XAPIC;
   }
 
-  ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+  ApicBaseMsr.Uint64 = ReadMsrReg64 (MSR_IA32_APIC_BASE);
   //
   // Local APIC should have been enabled
   //
@@ -350,13 +566,14 @@ SetApicMode (
 
   CurrentMode = GetApicMode ();
   if (CurrentMode == LOCAL_APIC_MODE_XAPIC) {
+
     switch (ApicMode) {
       case LOCAL_APIC_MODE_XAPIC:
         break;
       case LOCAL_APIC_MODE_X2APIC:
-        ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+        ApicBaseMsr.Uint64 = ReadMsrReg64 (MSR_IA32_APIC_BASE);
         ApicBaseMsr.Bits.EXTD = 1;
-        AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
+        WriteMsrReg64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
         break;
       default:
         ASSERT (FALSE);
diff --git a/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf b/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf
index 1e2a4f8b790f..1276f6ec06d6 100644
--- a/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf
+++ b/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf
@@ -39,6 +39,7 @@
   IoLib
   PcdLib
   UefiCpuLib
+  TdxLib
 
 [Pcd]
   gUefiCpuPkgTokenSpaceGuid.PcdCpuInitIpiDelayInMicroSeconds  ## SOMETIMES_CONSUMES
diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc
index 870b45284087..e5e6bf77c8e2 100644
--- a/UefiCpuPkg/UefiCpuPkg.dsc
+++ b/UefiCpuPkg/UefiCpuPkg.dsc
@@ -61,6 +61,7 @@
   TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf
   VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf
   MicrocodeLib|UefiCpuPkg/Library/MicrocodeLib/MicrocodeLib.inf
+  TdxLib|MdePkg/Library/TdxLib/TdxLib.inf
 
 [LibraryClasses.common.SEC]
   PlatformSecLib|UefiCpuPkg/Library/PlatformSecLibNull/PlatformSecLibNull.inf
-- 
2.29.2.windows.2


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

* [PATCH V2 08/28] UefiCpuPkg: Add VmTdExitLibNull
  2021-10-05  3:39 [PATCH V2 00/28] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (6 preceding siblings ...)
  2021-10-05  3:39 ` [PATCH V2 07/28] UefiCpuPkg: Support TDX in BaseXApicX2ApicLib Min Xu
@ 2021-10-05  3:39 ` Min Xu
  2021-10-05  3:39 ` [PATCH V2 09/28] UefiPayloadPkg: Prepare UefiPayloadPkg to use the VmTdExitLib library Min Xu
                   ` (19 subsequent siblings)
  27 siblings, 0 replies; 91+ messages in thread
From: Min Xu @ 2021-10-05  3:39 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Brijesh Singh, Erdem Aktas, James Bottomley, Jiewen Yao,
	Tom Lendacky, Eric Dong, Ray Ni, Rahul Kumar

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

VmTdExitLib performs the necessary processing to handle a #VE exception.
VmTdExitLibNull is a NULL instance of VmTdExitLib which provides a default
limited interface. A full feature version of VmTdExitLib should be created
later (for example in OvmfPkg).

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>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 UefiCpuPkg/Include/Library/VmTdExitLib.h      | 47 +++++++++++++++++++
 .../Library/VmTdExitLibNull/VmTdExitLibNull.c | 37 +++++++++++++++
 .../VmTdExitLibNull/VmTdExitLibNull.inf       | 34 ++++++++++++++
 UefiCpuPkg/UefiCpuPkg.dec                     |  3 ++
 UefiCpuPkg/UefiCpuPkg.dsc                     |  2 +
 5 files changed, 123 insertions(+)
 create mode 100644 UefiCpuPkg/Include/Library/VmTdExitLib.h
 create mode 100644 UefiCpuPkg/Library/VmTdExitLibNull/VmTdExitLibNull.c
 create mode 100644 UefiCpuPkg/Library/VmTdExitLibNull/VmTdExitLibNull.inf

diff --git a/UefiCpuPkg/Include/Library/VmTdExitLib.h b/UefiCpuPkg/Include/Library/VmTdExitLib.h
new file mode 100644
index 000000000000..a55a76dc7a30
--- /dev/null
+++ b/UefiCpuPkg/Include/Library/VmTdExitLib.h
@@ -0,0 +1,47 @@
+/** @file
+  Public header file for the VMTDEXIT Support library class.
+
+  This library class defines some routines used when invoking the VMEXIT
+  instruction in support of VMX and TDX to handle #VE exceptions.
+
+  Copyright (c) 2020 - 2021, Intel Inc. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef VMTD_EXIT_LIB_H_
+#define VMTD_EXIT_LIB_H_
+
+#include <Library/BaseLib.h>
+#include <Uefi/UefiBaseType.h>
+#include <Protocol/DebugSupport.h>
+
+#define VE_EXCEPTION    20
+
+/**
+  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/VmTdExitLibNull/VmTdExitLibNull.c b/UefiCpuPkg/Library/VmTdExitLibNull/VmTdExitLibNull.c
new file mode 100644
index 000000000000..a632abfab498
--- /dev/null
+++ b/UefiCpuPkg/Library/VmTdExitLibNull/VmTdExitLibNull.c
@@ -0,0 +1,37 @@
+/** @file
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include <Library/BaseLib.h>
+#include <Library/VmTdExitLib.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/VmTdExitLibNull/VmTdExitLibNull.inf b/UefiCpuPkg/Library/VmTdExitLibNull/VmTdExitLibNull.inf
new file mode 100644
index 000000000000..ae9af1b7f56b
--- /dev/null
+++ b/UefiCpuPkg/Library/VmTdExitLibNull/VmTdExitLibNull.inf
@@ -0,0 +1,34 @@
+## @file
+#  VMTDEXIT Support Library.
+#
+#  Copyright (c) 2020, Intel Inc. All rights reserved.<BR>
+#  Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = VmTdExitLibNull
+  FILE_GUID                      = 79BD5323-6CF4-4ECF-A132-F7D31EEADC1E
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = VmTdExitLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = X64 IA32
+#
+
+[Sources.common]
+  VmTdExitLibNull.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  DebugLib
diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
index 62acb291f309..439bfc86a112 100644
--- a/UefiCpuPkg/UefiCpuPkg.dec
+++ b/UefiCpuPkg/UefiCpuPkg.dec
@@ -62,6 +62,9 @@
   ##  @libraryclass  Provides function for loading microcode.
   MicrocodeLib|Include/Library/MicrocodeLib.h
 
+  ##  @libraryclass  Provides function to support VMTDEXIT processing.
+  VmgExitLib|Include/Library/VmTdExitLib.h
+
 [Guids]
   gUefiCpuPkgTokenSpaceGuid      = { 0xac05bf33, 0x995a, 0x4ed4, { 0xaa, 0xb8, 0xef, 0x7a, 0xe8, 0xf, 0x5c, 0xb0 }}
   gMsegSmramGuid                 = { 0x5802bce4, 0xeeee, 0x4e33, { 0xa1, 0x30, 0xeb, 0xad, 0x27, 0xf0, 0xe4, 0x39 }}
diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc
index e5e6bf77c8e2..50bb49f95b17 100644
--- a/UefiCpuPkg/UefiCpuPkg.dsc
+++ b/UefiCpuPkg/UefiCpuPkg.dsc
@@ -60,6 +60,7 @@
   PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf
   TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf
   VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf
+  VmTdExitLib|UefiCpuPkg/Library/VmTdExitLibNull/VmTdExitLibNull.inf
   MicrocodeLib|UefiCpuPkg/Library/MicrocodeLib/MicrocodeLib.inf
   TdxLib|MdePkg/Library/TdxLib/TdxLib.inf
 
@@ -159,6 +160,7 @@
   UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLibStm.inf
   UefiCpuPkg/Library/SmmCpuFeaturesLib/StandaloneMmCpuFeaturesLib.inf
   UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf
+  UefiCpuPkg/Library/VmTdExitLibNull/VmTdExitLibNull.inf
   UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationPei.inf
   UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationSmm.inf
   UefiCpuPkg/SecCore/SecCore.inf
-- 
2.29.2.windows.2


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

* [PATCH V2 09/28] UefiPayloadPkg: Prepare UefiPayloadPkg to use the VmTdExitLib library
  2021-10-05  3:39 [PATCH V2 00/28] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (7 preceding siblings ...)
  2021-10-05  3:39 ` [PATCH V2 08/28] UefiCpuPkg: Add VmTdExitLibNull Min Xu
@ 2021-10-05  3:39 ` Min Xu
  2021-10-05  3:39 ` [PATCH V2 10/28] OvmfPkg: Prepare OvmfPkg " Min Xu
                   ` (18 subsequent siblings)
  27 siblings, 0 replies; 91+ messages in thread
From: Min Xu @ 2021-10-05  3:39 UTC (permalink / raw)
  To: devel; +Cc: Min Xu

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

Various CpuExceptionHandlerLib libraries will updated to use the new
VmTdExitLib library. To prevent any build breakage, update the
UefiPayloadPkg.dsc that use a form of the CpuExceptionHandlerLib
library to include the VmTdExitLib library.

Guo Dong <guo.dong@intel.com>
Ray Ni <ray.ni@intel.com>
Maurice Ma <maurice.ma@intel.com>
Benjamin You <benjamin.you@intel.com>
Jiewen Yao <jiewen.yao@intel.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 UefiPayloadPkg/UefiPayloadPkg.dsc | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/UefiPayloadPkg/UefiPayloadPkg.dsc b/UefiPayloadPkg/UefiPayloadPkg.dsc
index 9319422efe4b..0522bbc52742 100644
--- a/UefiPayloadPkg/UefiPayloadPkg.dsc
+++ b/UefiPayloadPkg/UefiPayloadPkg.dsc
@@ -245,6 +245,7 @@
   VarCheckLib|MdeModulePkg/Library/VarCheckLib/VarCheckLib.inf
   VariablePolicyLib|MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf
   VariablePolicyHelperLib|MdeModulePkg/Library/VariablePolicyHelperLib/VariablePolicyHelperLib.inf
+  TdxLib|MdePkg/Library/TdxLib/TdxLib.inf
 
 [LibraryClasses.common.SEC]
   HobLib|UefiPayloadPkg/Library/PayloadEntryHobLib/HobLib.inf
@@ -263,6 +264,7 @@
 !endif
   CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
   VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf
+  VmTdExitLib|UefiCpuPkg/Library/VmTdExitLibNull/VmTdExitLibNull.inf
 
 [LibraryClasses.common.DXE_DRIVER]
   PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf
@@ -275,6 +277,7 @@
   CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
   MpInitLib|UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
   VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf
+  VmTdExitLib|UefiCpuPkg/Library/VmTdExitLibNull/VmTdExitLibNull.inf
 
 [LibraryClasses.common.DXE_RUNTIME_DRIVER]
   PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf
-- 
2.29.2.windows.2


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

* [PATCH V2 10/28] OvmfPkg: Prepare OvmfPkg to use the VmTdExitLib library
  2021-10-05  3:39 [PATCH V2 00/28] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (8 preceding siblings ...)
  2021-10-05  3:39 ` [PATCH V2 09/28] UefiPayloadPkg: Prepare UefiPayloadPkg to use the VmTdExitLib library Min Xu
@ 2021-10-05  3:39 ` Min Xu
  2021-10-05  3:39 ` [PATCH V2 11/28] OvmfPkg: Implement library support for VmTdExitLib in Ovmf Min Xu
                   ` (17 subsequent siblings)
  27 siblings, 0 replies; 91+ messages in thread
From: Min Xu @ 2021-10-05  3:39 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

Various CpuExceptionHandlerLib libraries will updated to use the new
VmTdExitLib library. To prevent any build breakage, update the OvmfPkg
DSC files that use a form of the CpuExceptionHandlerLib library to
include the VmTdExitLib library.

Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/OvmfPkgIa32.dsc    | 1 +
 OvmfPkg/OvmfPkgIa32X64.dsc | 1 +
 OvmfPkg/OvmfPkgX64.dsc     | 1 +
 OvmfPkg/OvmfXen.dsc        | 1 +
 4 files changed, 4 insertions(+)

diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
index 6a5be97c059d..1f75075152a6 100644
--- a/OvmfPkg/OvmfPkgIa32.dsc
+++ b/OvmfPkg/OvmfPkgIa32.dsc
@@ -243,6 +243,7 @@
 [LibraryClasses.common]
   BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf
   VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf
+  VmTdExitLib|UefiCpuPkg/Library/VmTdExitLibNull/VmTdExitLibNull.inf
 
 [LibraryClasses.common.SEC]
   TimerLib|OvmfPkg/Library/AcpiTimerLib/BaseRomAcpiTimerLib.inf
diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index 71227d1b709a..771b08088b96 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -247,6 +247,7 @@
 [LibraryClasses.common]
   BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf
   VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf
+  VmTdExitLib|UefiCpuPkg/Library/VmTdExitLibNull/VmTdExitLibNull.inf
 
 [LibraryClasses.common.SEC]
   TimerLib|OvmfPkg/Library/AcpiTimerLib/BaseRomAcpiTimerLib.inf
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index 52f7598cf1c7..162858e2659b 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -247,6 +247,7 @@
 [LibraryClasses.common]
   BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf
   VmgExitLib|OvmfPkg/Library/VmgExitLib/VmgExitLib.inf
+  VmTdExitLib|UefiCpuPkg/Library/VmTdExitLibNull/VmTdExitLibNull.inf
 
 [LibraryClasses.common.SEC]
   TimerLib|OvmfPkg/Library/AcpiTimerLib/BaseRomAcpiTimerLib.inf
diff --git a/OvmfPkg/OvmfXen.dsc b/OvmfPkg/OvmfXen.dsc
index a31519e356b7..5fce410523f8 100644
--- a/OvmfPkg/OvmfXen.dsc
+++ b/OvmfPkg/OvmfXen.dsc
@@ -227,6 +227,7 @@
 [LibraryClasses.common]
   BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf
   VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf
+  VmTdExitLib|UefiCpuPkg/Library/VmTdExitLibNull/VmTdExitLibNull.inf
 
 [LibraryClasses.common.SEC]
   QemuFwCfgLib|OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgSecLib.inf
-- 
2.29.2.windows.2


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

* [PATCH V2 11/28] OvmfPkg: Implement library support for VmTdExitLib in Ovmf
  2021-10-05  3:39 [PATCH V2 00/28] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (9 preceding siblings ...)
  2021-10-05  3:39 ` [PATCH V2 10/28] OvmfPkg: Prepare OvmfPkg " Min Xu
@ 2021-10-05  3:39 ` Min Xu
  2021-10-05  3:39 ` [PATCH V2 12/28] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VE exception Min Xu
                   ` (16 subsequent siblings)
  27 siblings, 0 replies; 91+ messages in thread
From: Min Xu @ 2021-10-05  3:39 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ard Biesheuvel, Jiewen Yao, Jordan Justen, Brijesh Singh,
	Erdem Aktas, James Bottomley, Tom Lendacky

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

The base VmTdExitLib library provides a default limited interface. As
it does not provide full support, create an OVMF version of this library
to begin the process of providing full support of TDX within OVMF.

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

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>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/Library/VmTdExitLib/VmTdExitLib.inf   |  39 ++
 .../Library/VmTdExitLib/VmTdExitVeHandler.c   | 515 ++++++++++++++++++
 OvmfPkg/OvmfPkg.dec                           |   3 +
 3 files changed, 557 insertions(+)
 create mode 100644 OvmfPkg/Library/VmTdExitLib/VmTdExitLib.inf
 create mode 100644 OvmfPkg/Library/VmTdExitLib/VmTdExitVeHandler.c

diff --git a/OvmfPkg/Library/VmTdExitLib/VmTdExitLib.inf b/OvmfPkg/Library/VmTdExitLib/VmTdExitLib.inf
new file mode 100644
index 000000000000..84e308621f7f
--- /dev/null
+++ b/OvmfPkg/Library/VmTdExitLib/VmTdExitLib.inf
@@ -0,0 +1,39 @@
+## @file
+#  VMTDEXIT Support Library.
+#
+#  Copyright (c) 2020, Intel Inc. All rights reserved.<BR>
+#  Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = VmTdExitLib
+  FILE_GUID                      = b29eabb0-f9a3-11ea-8b6e-0800200c9a66
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = VmTdExitLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = X64
+#
+
+[Sources.common]
+  VmTdExitVeHandler.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  OvmfPkg/OvmfPkg.dec
+  UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  DebugLib
+  TdxLib
+
+[Pcd]
+  gUefiOvmfPkgTokenSpaceGuid.PcdIgnoreVeHalt
diff --git a/OvmfPkg/Library/VmTdExitLib/VmTdExitVeHandler.c b/OvmfPkg/Library/VmTdExitLib/VmTdExitVeHandler.c
new file mode 100644
index 000000000000..6e41261cd108
--- /dev/null
+++ b/OvmfPkg/Library/VmTdExitLib/VmTdExitVeHandler.c
@@ -0,0 +1,515 @@
+/** @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 <Library/TdxLib.h>
+#include <Library/VmTdExitLib.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/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index 340d83f794d0..2124bd639399 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -350,6 +350,9 @@
   gUefiOvmfPkgTokenSpaceGuid.PcdBfvRawDataOffset|0|UINT32|0x56
   gUefiOvmfPkgTokenSpaceGuid.PcdBfvRawDataSize|0|UINT32|0x57
 
+  ## Ignore the VE halt in Tdx
+  gUefiOvmfPkgTokenSpaceGuid.PcdIgnoreVeHalt|FALSE|BOOLEAN|0x58
+
 [PcdsDynamic, PcdsDynamicEx]
   gUefiOvmfPkgTokenSpaceGuid.PcdEmuVariableEvent|0|UINT64|2
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashVariablesEnable|FALSE|BOOLEAN|0x10
-- 
2.29.2.windows.2


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

* [PATCH V2 12/28] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VE exception
  2021-10-05  3:39 [PATCH V2 00/28] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (10 preceding siblings ...)
  2021-10-05  3:39 ` [PATCH V2 11/28] OvmfPkg: Implement library support for VmTdExitLib in Ovmf Min Xu
@ 2021-10-05  3:39 ` Min Xu
  2021-10-12 10:27   ` [edk2-devel] " Gerd Hoffmann
  2021-10-05  3:39 ` [PATCH V2 13/28] UefiCpuPkg: Enable Tdx support in MpInitLib Min Xu
                   ` (15 subsequent siblings)
  27 siblings, 1 reply; 91+ messages in thread
From: Min Xu @ 2021-10-05  3:39 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Brijesh Singh, Erdem Aktas, James Bottomley, Jiewen Yao,
	Tom Lendacky, Eric Dong, Ray Ni, Rahul Kumar

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 VmTdExitLib
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>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 .../DxeCpuExceptionHandlerLib.inf             |  1 +
 .../PeiCpuExceptionHandlerLib.inf             |  1 +
 .../PeiDxeSmmCpuException.c                   | 18 ++++++++++++++++++
 .../SecPeiCpuException.c                      | 19 +++++++++++++++++++
 .../SecPeiCpuExceptionHandlerLib.inf          |  1 +
 .../SmmCpuExceptionHandlerLib.inf             |  1 +
 .../Xcode5SecPeiCpuExceptionHandlerLib.inf    |  1 +
 7 files changed, 42 insertions(+)

diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
index e7a81bebdb13..630a83bf003b 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
@@ -61,3 +61,4 @@
   MemoryAllocationLib
   DebugLib
   VmgExitLib
+  VmTdExitLib
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf
index cf5bfe40832b..63a7abfb6242 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf
@@ -53,6 +53,7 @@
   MemoryAllocationLib
   SynchronizationLib
   VmgExitLib
+  VmTdExitLib
 
 [Pcd]
   gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard    # CONSUMES
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeSmmCpuException.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeSmmCpuException.c
index 892d349d4b37..0976a880825b 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeSmmCpuException.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeSmmCpuException.c
@@ -8,6 +8,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
 
 #include <Library/DebugLib.h>
 #include <Library/VmgExitLib.h>
+#include <Library/VmTdExitLib.h>
 #include "CpuExceptionCommon.h"
 
 /**
@@ -45,6 +46,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 01b5a2f1f4fc..173047a6b494 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c
@@ -8,6 +8,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
 
 #include <PiPei.h>
 #include <Library/VmgExitLib.h>
+#include <Library/VmTdExitLib.h>
 #include "CpuExceptionCommon.h"
 
 CONST UINTN    mDoFarReturnFlag  = 0;
@@ -43,6 +44,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.
   //
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
index 8ae4feae6238..4aeab2057b08 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
@@ -49,6 +49,7 @@
   LocalApicLib
   PeCoffGetEntryPointLib
   VmgExitLib
+  VmTdExitLib
 
 [FeaturePcd]
   gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStackGuard                    ## CONSUMES
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf
index c9f20da05860..2622e48103f3 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf
@@ -52,6 +52,7 @@
   PeCoffGetEntryPointLib
   DebugLib
   VmgExitLib
+  VmTdExitLib
 
 [FeaturePcd]
   gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStackGuard                    ## CONSUMES
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/Xcode5SecPeiCpuExceptionHandlerLib.inf b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Xcode5SecPeiCpuExceptionHandlerLib.inf
index a15f125d5b5e..36ccb7ef97ec 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/Xcode5SecPeiCpuExceptionHandlerLib.inf
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Xcode5SecPeiCpuExceptionHandlerLib.inf
@@ -54,6 +54,7 @@
   LocalApicLib
   PeCoffGetEntryPointLib
   VmgExitLib
+  VmTdExitLib
 
 [FeaturePcd]
   gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStackGuard                    ## CONSUMES
-- 
2.29.2.windows.2


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

* [PATCH V2 13/28] UefiCpuPkg: Enable Tdx support in MpInitLib
  2021-10-05  3:39 [PATCH V2 00/28] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (11 preceding siblings ...)
  2021-10-05  3:39 ` [PATCH V2 12/28] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VE exception Min Xu
@ 2021-10-05  3:39 ` Min Xu
  2021-10-12 10:31   ` [edk2-devel] " Gerd Hoffmann
  2021-10-13  6:01   ` Ni, Ray
  2021-10-05  3:39 ` [PATCH V2 14/28] OvmfPkg: Update SecEntry.nasm to support Tdx Min Xu
                   ` (14 subsequent siblings)
  27 siblings, 2 replies; 91+ messages in thread
From: Min Xu @ 2021-10-05  3:39 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Brijesh Singh, Erdem Aktas, James Bottomley, Jiewen Yao,
	Tom Lendacky, Eric Dong, Ray Ni, Rahul Kumar

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>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf |   4 +
 UefiCpuPkg/Library/MpInitLib/DxeMpLib.c       |  14 +-
 UefiCpuPkg/Library/MpInitLib/MpIntelTdx.h     | 107 ++++++++++
 UefiCpuPkg/Library/MpInitLib/MpLib.c          |  26 +++
 UefiCpuPkg/Library/MpInitLib/MpLibTdx.c       | 186 ++++++++++++++++++
 UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c   | 117 +++++++++++
 UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf |   4 +
 .../Library/MpInitLib/X64/IntelTdcall.nasm    | 120 +++++++++++
 8 files changed, 577 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
 create mode 100644 UefiCpuPkg/Library/MpInitLib/X64/IntelTdcall.nasm

diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
index d34419c2a524..084e025564ef 100644
--- a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
@@ -22,10 +22,13 @@
 #
 
 [Sources.IA32]
+  MpLibTdxNull.c
   Ia32/MpFuncs.nasm
 
 [Sources.X64]
+  MpLibTdx.c
   X64/MpFuncs.nasm
+  X64/IntelTdcall.nasm
 
 [Sources.common]
   MpEqu.inc
@@ -33,6 +36,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 93fc63bf93e3..b7275db3d564 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,7 +16,6 @@
 #include <Library/VmgExitLib.h>
 #include <Register/Amd/Fam17Msr.h>
 #include <Register/Amd/Ghcb.h>
-
 #include <Protocol/Timer.h>
 
 #define  AP_SAFE_STACK_SIZE    128
@@ -801,6 +801,10 @@ MpInitLibStartupThisAP (
 {
   EFI_STATUS              Status;
 
+  if (MpTdxIsEnabled ()) {
+    return EFI_UNSUPPORTED;
+  }
+
   //
   // temporarily stop checkAllApsStatus for avoid resource dead-lock.
   //
@@ -857,6 +861,10 @@ MpInitLibSwitchBSP (
   EFI_TIMER_ARCH_PROTOCOL      *Timer;
   UINT64                       TimerPeriod;
 
+  if (MpTdxIsEnabled ()) {
+    return EFI_UNSUPPORTED;
+  }
+
   TimerPeriod = 0;
   //
   // Locate Timer Arch Protocol
@@ -930,6 +938,10 @@ MpInitLibEnableDisableAP (
   EFI_STATUS     Status;
   BOOLEAN        TempStopCheckState;
 
+  if (MpTdxIsEnabled ()) {
+    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..59bd739eed22
--- /dev/null
+++ b/UefiCpuPkg/Library/MpInitLib/MpIntelTdx.h
@@ -0,0 +1,107 @@
+/** @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
+  );
+
+/**
+  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
+**/
+EFI_STATUS
+EFIAPI
+MpTdCall (
+  IN UINT64           Leaf,
+  IN UINT64           Arg1,
+  IN UINT64           Arg2,
+  IN UINT64           Arg3,
+  IN OUT VOID         *Results
+  );
+
+/**
+  Whether Intel TDX is enabled.
+
+  @return TRUE    TDX enabled
+  @return FALSE   TDX not enabled
+**/
+BOOLEAN
+EFIAPI
+MpTdxIsEnabled (
+  VOID
+  );
+
+#endif
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index b9a06747edbf..d03ad8ff483e 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -9,6 +9,7 @@
 **/
 
 #include "MpLib.h"
+#include "MpIntelTdx.h"
 #include <Library/VmgExitLib.h>
 #include <Register/Amd/Fam17Msr.h>
 #include <Register/Amd/Ghcb.h>
@@ -1965,6 +1966,10 @@ MpInitLibInitialize (
   UINTN                    BackupBufferAddr;
   UINTN                    ApIdtBase;
 
+  if (MpTdxIsEnabled ()) {
+    return EFI_SUCCESS;
+  }
+
   OldCpuMpData = GetCpuMpDataFromGuidedHob ();
   if (OldCpuMpData == NULL) {
     MaxLogicalProcessorNumber = PcdGet32(PcdCpuMaxLogicalProcessorNumber);
@@ -2215,6 +2220,10 @@ MpInitLibGetProcessorInfo (
   CPU_INFO_IN_HOB        *CpuInfoInHob;
   UINTN                  OriginalProcessorNumber;
 
+  if (MpTdxIsEnabled ()) {
+    return TdxMpInitLibGetProcessorInfo (ProcessorNumber, ProcessorInfoBuffer, HealthData);
+  }
+
   CpuMpData = GetCpuMpData ();
   CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;
 
@@ -2446,6 +2455,10 @@ EnableDisableApWorker (
   CPU_MP_DATA               *CpuMpData;
   UINTN                     CallerNumber;
 
+  if (MpTdxIsEnabled ()) {
+    return EFI_UNSUPPORTED;
+  }
+
   CpuMpData = GetCpuMpData ();
 
   //
@@ -2506,6 +2519,11 @@ MpInitLibWhoAmI (
     return EFI_INVALID_PARAMETER;
   }
 
+  if (MpTdxIsEnabled ()) {
+    *ProcessorNumber = 0;
+    return EFI_SUCCESS;
+  }
+
   CpuMpData = GetCpuMpData ();
 
   return GetProcessorNumber (CpuMpData, ProcessorNumber);
@@ -2544,6 +2562,10 @@ MpInitLibGetNumberOfProcessors (
   UINTN                   EnabledProcessorNumber;
   UINTN                   Index;
 
+  if (MpTdxIsEnabled ()) {
+    return TdxMpInitLibGetNumberOfProcessors(NumberOfProcessors, NumberOfEnabledProcessors);
+  }
+
   CpuMpData = GetCpuMpData ();
 
   if ((NumberOfProcessors == NULL) && (NumberOfEnabledProcessors == NULL)) {
@@ -2629,6 +2651,10 @@ StartupAllCPUsWorker (
   BOOLEAN                 HasEnabledAp;
   CPU_STATE               ApState;
 
+  if (MpTdxIsEnabled ()) {
+    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..d8bd4eb65d25
--- /dev/null
+++ b/UefiCpuPkg/Library/MpInitLib/MpLibTdx.c
@@ -0,0 +1,186 @@
+/** @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>
+
+BOOLEAN mMpTdxEnabled = FALSE;
+BOOLEAN mMpTdxProbed = FALSE;
+
+/**
+  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 = MpTdCall(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 = MpTdCall(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;
+}
+
+/**
+  Whether Intel TDX is enabled.
+
+  @return TRUE    TDX enabled
+  @return FALSE   TDX not enabled
+**/
+BOOLEAN
+EFIAPI
+MpTdxIsEnabled (
+  VOID
+  )
+{
+  UINT32    Eax;
+  UINT32    Ebx;
+  UINT32    Ecx;
+  UINT32    Edx;
+  UINT32    LargestEax;
+
+  if (mMpTdxProbed) {
+    return mMpTdxEnabled;
+  }
+
+  mMpTdxEnabled = FALSE;
+
+  do {
+    AsmCpuid (0, &LargestEax, &Ebx, &Ecx, &Edx);
+
+    if (Ebx != SIGNATURE_32 ('G', 'e', 'n', 'u')
+      || Edx != SIGNATURE_32 ('i', 'n', 'e', 'I')
+      || Ecx != SIGNATURE_32 ('n', 't', 'e', 'l')) {
+      break;
+    }
+
+    AsmCpuid (1, 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;
+    }
+
+    mMpTdxEnabled = TRUE;
+  }while (FALSE);
+
+  mMpTdxProbed = TRUE;
+
+  return mMpTdxEnabled;
+}
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c b/UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c
new file mode 100644
index 000000000000..f9cfedf01240
--- /dev/null
+++ b/UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c
@@ -0,0 +1,117 @@
+/** @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;
+}
+
+/**
+  Whether Intel TDX is enabled.
+
+  @return TRUE    TDX enabled
+  @return FALSE   TDX not enabled
+**/
+BOOLEAN
+EFIAPI
+MpTdxIsEnabled (
+  VOID
+  )
+{
+  return FALSE;
+}
+
+/**
+  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
+**/
+EFI_STATUS
+EFIAPI
+MpTdCall (
+  IN UINT64           Leaf,
+  IN UINT64           Arg1,
+  IN UINT64           Arg2,
+  IN UINT64           Arg3,
+  IN OUT VOID         *Results
+  )
+{
+  return EFI_UNSUPPORTED;
+}
diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
index 36fcb96b5852..b48dab2b1537 100644
--- a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
@@ -22,10 +22,13 @@
 #
 
 [Sources.IA32]
+  MpLibTdxNull.c
   Ia32/MpFuncs.nasm
 
 [Sources.X64]
+  MpLibTdx.c
   X64/MpFuncs.nasm
+  X64/IntelTdcall.nasm
 
 [Sources.common]
   MpEqu.inc
@@ -33,6 +36,7 @@
   MpLib.c
   MpLib.h
   Microcode.c
+  MpIntelTdx.h
 
 [Packages]
   MdePkg/MdePkg.dec
diff --git a/UefiCpuPkg/Library/MpInitLib/X64/IntelTdcall.nasm b/UefiCpuPkg/Library/MpInitLib/X64/IntelTdcall.nasm
new file mode 100644
index 000000000000..5e98557d5590
--- /dev/null
+++ b/UefiCpuPkg/Library/MpInitLib/X64/IntelTdcall.nasm
@@ -0,0 +1,120 @@
+;------------------------------------------------------------------------------
+;*
+;* 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)
+
+%macro tdcall_regs_preamble 2
+    mov rax, %1
+
+    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
+
+;  MpTdCall (
+;    UINT64  Leaf,    // Rcx
+;    UINT64  P1,      // Rdx
+;    UINT64  P2,      // R8
+;    UINT64  P3,      // R9
+;    UINT64  Results, // rsp + 0x28
+;    )
+global ASM_PFX(MpTdCall)
+ASM_PFX(MpTdCall):
+       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
-- 
2.29.2.windows.2


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

* [PATCH V2 14/28] OvmfPkg: Update SecEntry.nasm to support Tdx
  2021-10-05  3:39 [PATCH V2 00/28] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (12 preceding siblings ...)
  2021-10-05  3:39 ` [PATCH V2 13/28] UefiCpuPkg: Enable Tdx support in MpInitLib Min Xu
@ 2021-10-05  3:39 ` Min Xu
  2021-10-12 10:38   ` [edk2-devel] " Gerd Hoffmann
  2021-10-05  3:39 ` [PATCH V2 15/28] OvmfPkg: Add IntelTdx.h in OvmfPkg/Include/IndustryStandard Min Xu
                   ` (13 subsequent siblings)
  27 siblings, 1 reply; 91+ messages in thread
From: Min Xu @ 2021-10-05  3:39 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

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.

There are 2 commands are supported:
 - WakeUp:
   BSP issues this command to move APs to final OS spinloop and Mailbox
   in reserved memory.
 - AcceptPages:
   To mitigate the performance impact of accepting pages in SEC phase on
   BSP, BSP will parse memory resources and assign each AP the task of
   accepting a subset of pages. This command may be called several times
   until all memory resources are processed. In accepting pages, PageLevel
   may fall back to smaller one if SIZE_MISMATCH error is returned.

TdxCommondefs.inc is added which includes the common definitions used by
the APs in SecEntry.nasm.

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>
---
 OvmfPkg/Include/TdxCommondefs.inc |  51 +++++
 OvmfPkg/Sec/SecMain.inf           |   1 +
 OvmfPkg/Sec/X64/SecEntry.nasm     | 314 ++++++++++++++++++++++++++++++
 3 files changed, 366 insertions(+)
 create mode 100644 OvmfPkg/Include/TdxCommondefs.inc

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/Sec/SecMain.inf b/OvmfPkg/Sec/SecMain.inf
index ea4b9611f52d..6083fa21a433 100644
--- a/OvmfPkg/Sec/SecMain.inf
+++ b/OvmfPkg/Sec/SecMain.inf
@@ -72,6 +72,7 @@
   gEfiMdeModulePkgTokenSpaceGuid.PcdInitValueInTempStack
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfConfidentialComputingWorkAreaHeader
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfWorkAreaBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupBase
 
 [FeaturePcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire
diff --git a/OvmfPkg/Sec/X64/SecEntry.nasm b/OvmfPkg/Sec/X64/SecEntry.nasm
index 1cc680a70716..d0833db68410 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,286 @@ 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
+
+    cmp     eax, MpProtectedModeWakeupCommandAcceptPages
+    jne     .check_command
+
+    ;
+    ; AP Accept Pages
+    ;
+    ; Accept Pages in TDX is time-consuming, especially for big memory.
+    ; One of the mitigation is to accept pages by BSP and APs parallely.
+    ;
+    ; For example, there are 4 CPUs (1 BSP and 3 APs). Totally there are
+    ; 1G memory to be accepted.
+    ;
+    ; BSP is responsible for the memory regions of:
+    ;    Start : StartAddress + ChunkSize * (4) * Index
+    ;    Length: ChunkSize
+    ; APs is reponsible for the memory regions of:
+    ;    Start : StartAddress + ChunkSize * (4) * Index + ChunkSize * CpuId
+    ;    Length: ChunkSize
+    ;
+    ; TDCALL_TDACCEPTPAGE supports the PageSize of 4K and 2M. Sometimes when
+    ; the PageSize is 2M, TDX_PAGE_SIZE_MISMATCH is returned as the error code.
+    ; In this case, TDVF need fall back to 4k PageSize to accept again.
+    ;
+    ; If any errors happened in accept pages, an error code is recorded in
+    ; Mailbox [ErrorsOffset + CpuIndex]
+    ;
+.ap_accept_page:
+
+    ;
+    ; Clear the errors and fallback flag
+    ;
+    mov     al, ERROR_NON
+    mov     byte[rsp + ErrorsOffset + rbp], al
+    xor     r12, r12
+
+    ;
+    ; Get PhysicalAddress/ChunkSize/PageSize
+    ;
+    mov     rcx, [rsp + AcceptPageArgsPhysicalStart]
+    mov     rbx, [rsp + AcceptPageArgsChunkSize]
+
+    ;
+    ; Set AcceptPageLevel based on the AcceptPagesize
+    ; Currently only 2M/4K page size is acceptable
+    ;
+    mov     r15, [rsp + AcceptPageArgsPageSize]
+    cmp     r15, SIZE_4KB
+    je      .set_4kb
+    cmp     r15, SIZE_2MB
+    je      .set_2mb
+
+    mov     al, ERROR_INVALID_ACCEPT_PAGE_SIZE
+    mov     byte[rsp + ErrorsOffset + rbp], al
+    jmp     .do_finish_command
+
+.set_4kb:
+    mov     r15, PAGE_ACCEPT_LEVEL_4K
+    jmp     .physical_address
+
+.set_2mb:
+    mov     r15, PAGE_ACCEPT_LEVEL_2M
+
+.physical_address:
+    ;
+    ; PhysicalAddress += (CpuId * ChunkSize)
+    ;
+    xor     rdx, rdx
+    mov     eax, ebp
+    mul     ebx
+    add     rcx, rax
+    shl     rdx, 32
+    add     rcx, rdx
+
+.do_accept_next_range:
+    ;
+    ; Make sure we don't accept page beyond ending page
+    ; This could happen is ChunkSize crosses the end of region
+    ;
+    cmp     rcx, [rsp + AcceptPageArgsPhysicalEnd ]
+    jge     .do_finish_command
+
+    ;
+    ; Save starting address for this region
+    ;
+    mov     r11, rcx
+
+    ;
+    ; Size = MIN(ChunkSize, PhysicalEnd - PhysicalAddress);
+    ;
+    mov     rax, [rsp + AcceptPageArgsPhysicalEnd]
+    sub     rax, rcx
+    cmp     rax, rbx
+    jge     .do_accept_loop
+    mov     rbx, rax
+
+.do_accept_loop:
+    ;
+    ; RCX: Accept address
+    ; R15: Accept Page Level
+    ; R12: Flag of fall back accept
+    ;
+    mov     rax, TDCALL_TDACCEPTPAGE
+    xor     rdx, rdx
+    or      rcx, r15
+
+    tdcall
+
+    ;
+    ; Check status code in RAX
+    ;
+    test    rax, rax
+    jz      .accept_success
+
+    shr     rax, 32
+    cmp     eax, TDX_PAGE_ALREADY_ACCEPTED
+    jz      .already_accepted
+
+    cmp     eax, TDX_PAGE_SIZE_MISMATCH
+    jz      .accept_size_mismatch
+
+    ;
+    ; other error
+    ;
+    mov     al, ERROR_ACCEPT_PAGE_ERROR
+    mov     byte[rsp + ErrorsOffset + rbp], al
+    jmp     .do_finish_command
+
+.accept_size_mismatch:
+    ;
+    ; Check the current PageLevel.
+    ; ACCEPT_LEVEL_4K is the least level and cannot fall back any more.
+    ; If in this case, just record the error and return
+    ;
+    cmp     r15, PAGE_ACCEPT_LEVEL_4K
+    jne     .do_fallback_accept
+    mov     al, ERROR_INVALID_FALLBACK_PAGE_LEVEL
+    mov     byte[rsp + ErrorsOffset + rbp], al
+    jmp     .do_finish_command
+
+.do_fallback_accept:
+    ;
+    ; In fall back accept, just loop 512 times (2M = 512 * 4K)
+    ; Save the rcx in r13.
+    ; Decrease the PageLevel in R15.
+    ; R12 indicates it is in a fall back accept loop.
+    ;
+    mov     r14, 512
+    and     rcx, ~0x3ULL
+    mov     r13, rcx
+    xor     rdx, rdx
+    dec     r15
+    mov     r12, 1
+
+    jmp     .do_accept_loop
+
+.accept_success:
+    ;
+    ; Keep track of how many accepts per cpu
+    ;
+    inc dword[rsp + TalliesOffset + rbp * 4]
+
+    ;
+    ; R12 indicate whether it is a fall back accept
+    ; If it is a success of fall back accept
+    ; Just loop 512 times to .do_accept_loop
+    ;
+    test    r12, r12
+    jz      .normal_accept_success
+
+    ;
+    ; This is fallback accept success
+    ;
+    add     rcx, SIZE_4KB
+    dec     r14
+    test    r14, r14
+    jz      .fallback_accept_done
+    jmp     .do_accept_loop
+
+.fallback_accept_done:
+    ;
+    ; Fall back accept done.
+    ; Restore the start address to RCX from R13
+    ; Clear the fall back accept flag
+    ;
+    mov     rcx, r13
+    inc     r15
+    xor     r12, r12
+
+.already_accepted:
+    ;
+    ; Handle the sitution of fall back accpet
+    ;
+    test    r12, r12
+    jnz     .accept_success
+
+.normal_accept_success:
+    ;
+    ; Reduce accept size by a PageSize, and increment address
+    ;
+    mov     r12, [rsp + AcceptPageArgsPageSize]
+    sub     rbx, r12
+    add     rcx, r12
+    xor     r12, r12
+
+    ;
+    ; We may be given multiple pages to accept, make sure we
+    ; aren't done
+    ;
+    test    rbx, rbx
+    jne     .do_accept_loop
+
+    ;
+    ; Restore address before, and then increment by stride (num-cpus * ChunkSize)
+    ;
+    xor     rdx, rdx
+    mov     rcx, r11
+    mov     eax, r8d
+    mov     ebx, [rsp + AcceptPageArgsChunkSize]
+    mul     ebx
+    add     rcx, rax
+    shl     rdx, 32
+    add     rcx, rdx
+    jmp     .do_accept_next_range
+
+.do_finish_command:
+    mov       eax, 0FFFFFFFFh
+    lock xadd dword [rsp + CpusExitingOffset], eax
+    dec       eax
+
+.check_exiting_cnt:
+    cmp       eax, 0
+    je        .do_wait_loop
+    mov       eax, dword[rsp + CpusExitingOffset]
+    jmp       .check_exiting_cnt
+
+.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] 91+ messages in thread

* [PATCH V2 15/28] OvmfPkg: Add IntelTdx.h in OvmfPkg/Include/IndustryStandard
  2021-10-05  3:39 [PATCH V2 00/28] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (13 preceding siblings ...)
  2021-10-05  3:39 ` [PATCH V2 14/28] OvmfPkg: Update SecEntry.nasm to support Tdx Min Xu
@ 2021-10-05  3:39 ` Min Xu
  2021-10-05  3:39 ` [PATCH V2 16/28] OvmfPkg: Add TdxMailboxLib Min Xu
                   ` (12 subsequent siblings)
  27 siblings, 0 replies; 91+ messages in thread
From: Min Xu @ 2021-10-05  3:39 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

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>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/Include/IndustryStandard/IntelTdx.h | 77 +++++++++++++++++++++
 1 file changed, 77 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..2370f18289a1
--- /dev/null
+++ b/OvmfPkg/Include/IndustryStandard/IntelTdx.h
@@ -0,0 +1,77 @@
+/** @file
+  TBD
+
+  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] 91+ messages in thread

* [PATCH V2 16/28] OvmfPkg: Add TdxMailboxLib
  2021-10-05  3:39 [PATCH V2 00/28] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (14 preceding siblings ...)
  2021-10-05  3:39 ` [PATCH V2 15/28] OvmfPkg: Add IntelTdx.h in OvmfPkg/Include/IndustryStandard Min Xu
@ 2021-10-05  3:39 ` Min Xu
  2021-10-05  3:39 ` [PATCH V2 17/28] MdePkg: Add EFI_RESOURCE_ATTRIBUTE_ENCRYPTED in PiHob.h Min Xu
                   ` (11 subsequent siblings)
  27 siblings, 0 replies; 91+ messages in thread
From: Min Xu @ 2021-10-05  3:39 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

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>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/Include/Library/TdxMailboxLib.h       |  75 ++++++++++
 OvmfPkg/Library/TdxMailboxLib/TdxMailbox.c    | 138 ++++++++++++++++++
 .../Library/TdxMailboxLib/TdxMailboxLib.inf   |  52 +++++++
 .../Library/TdxMailboxLib/TdxMailboxNull.c    |  86 +++++++++++
 OvmfPkg/OvmfPkg.dec                           |   4 +
 5 files changed, 355 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..a410a9618495
--- /dev/null
+++ b/OvmfPkg/Include/Library/TdxMailboxLib.h
@@ -0,0 +1,75 @@
+/** @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..688ac6ca8262
--- /dev/null
+++ b/OvmfPkg/Library/TdxMailboxLib/TdxMailbox.c
@@ -0,0 +1,138 @@
+/** @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..f15222d51f45
--- /dev/null
+++ b/OvmfPkg/Library/TdxMailboxLib/TdxMailboxNull.c
@@ -0,0 +1,86 @@
+/** @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 2124bd639399..145943532a74 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] 91+ messages in thread

* [PATCH V2 17/28] MdePkg: Add EFI_RESOURCE_ATTRIBUTE_ENCRYPTED in PiHob.h
  2021-10-05  3:39 [PATCH V2 00/28] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (15 preceding siblings ...)
  2021-10-05  3:39 ` [PATCH V2 16/28] OvmfPkg: Add TdxMailboxLib Min Xu
@ 2021-10-05  3:39 ` Min Xu
  2021-10-05  3:39 ` [PATCH V2 18/28] OvmfPkg: Enable Tdx in SecMain.c Min Xu
                   ` (10 subsequent siblings)
  27 siblings, 0 replies; 91+ messages in thread
From: Min Xu @ 2021-10-05  3:39 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 62c07742a688..600ec2d4919e 100644
--- a/MdePkg/Include/Pi/PiHob.h
+++ b/MdePkg/Include/Pi/PiHob.h
@@ -298,6 +298,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] 91+ messages in thread

* [PATCH V2 18/28] OvmfPkg: Enable Tdx in SecMain.c
  2021-10-05  3:39 [PATCH V2 00/28] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (16 preceding siblings ...)
  2021-10-05  3:39 ` [PATCH V2 17/28] MdePkg: Add EFI_RESOURCE_ATTRIBUTE_ENCRYPTED in PiHob.h Min Xu
@ 2021-10-05  3:39 ` Min Xu
  2021-10-05  3:39 ` [PATCH V2 19/28] OvmfPkg: Check Tdx in QemuFwCfgPei to avoid DMA operation Min Xu
                   ` (9 subsequent siblings)
  27 siblings, 0 replies; 91+ messages in thread
From: Min Xu @ 2021-10-05  3:39 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

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 set is to process the TdHobList
to accept the memory. After that TDVF follow the standard OVMF flow
and jump to PEI phase.

PcdTdxAcceptChunkSize & PcdTdxAcceptPageSize are added for page accepting.
They're the default settings of the chunk size and the Accept page size.

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.

3 Tdx specific libs are used by OvmfPkgX64:
 - VmTdExitLib
 - TdxLib
 - TdxMailboxLib

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>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/OvmfPkg.dec        |   6 +
 OvmfPkg/OvmfPkgIa32.dsc    |   2 +
 OvmfPkg/OvmfPkgIa32X64.dsc |   2 +
 OvmfPkg/OvmfPkgX64.dsc     |   8 +-
 OvmfPkg/Sec/IntelTdx.c     | 608 +++++++++++++++++++++++++++++++++++++
 OvmfPkg/Sec/IntelTdx.h     |  33 ++
 OvmfPkg/Sec/SecMain.c      |  60 +++-
 OvmfPkg/Sec/SecMain.inf    |   6 +
 8 files changed, 718 insertions(+), 7 deletions(-)
 create mode 100644 OvmfPkg/Sec/IntelTdx.c
 create mode 100644 OvmfPkg/Sec/IntelTdx.h

diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index 145943532a74..6f535d718203 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -357,6 +357,12 @@
   ## Ignore the VE halt in Tdx
   gUefiOvmfPkgTokenSpaceGuid.PcdIgnoreVeHalt|FALSE|BOOLEAN|0x58
 
+  ## The chunk size of Tdx accept page
+  gUefiOvmfPkgTokenSpaceGuid.PcdTdxAcceptChunkSize|0x2000000|UINT64|0x59
+
+  ## The Tdx accept page size. 0x1000(4k),0x200000(2M)
+  gUefiOvmfPkgTokenSpaceGuid.PcdTdxAcceptPageSize|0x1000|UINT64|0x5a
+
 [PcdsDynamic, PcdsDynamicEx]
   gUefiOvmfPkgTokenSpaceGuid.PcdEmuVariableEvent|0|UINT64|2
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashVariablesEnable|FALSE|BOOLEAN|0x10
diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
index 1f75075152a6..46040357da83 100644
--- a/OvmfPkg/OvmfPkgIa32.dsc
+++ b/OvmfPkg/OvmfPkgIa32.dsc
@@ -244,6 +244,8 @@
   BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf
   VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf
   VmTdExitLib|UefiCpuPkg/Library/VmTdExitLibNull/VmTdExitLibNull.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/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index 771b08088b96..acdcdeee9969 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -248,6 +248,8 @@
   BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf
   VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf
   VmTdExitLib|UefiCpuPkg/Library/VmTdExitLibNull/VmTdExitLibNull.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 162858e2659b..12ebde74433d 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -247,7 +247,9 @@
 [LibraryClasses.common]
   BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf
   VmgExitLib|OvmfPkg/Library/VmgExitLib/VmgExitLib.inf
-  VmTdExitLib|UefiCpuPkg/Library/VmTdExitLibNull/VmTdExitLibNull.inf
+  VmTdExitLib|OvmfPkg/Library/VmTdExitLib/VmTdExitLib.inf
+  TdxLib|MdePkg/Library/TdxLib/TdxLib.inf
+  TdxMailboxLib|OvmfPkg/Library/TdxMailboxLib/TdxMailboxLib.inf
 
 [LibraryClasses.common.SEC]
   TimerLib|OvmfPkg/Library/AcpiTimerLib/BaseRomAcpiTimerLib.inf
@@ -573,6 +575,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..e4bbd0fdea4e
--- /dev/null
+++ b/OvmfPkg/Sec/IntelTdx.c
@@ -0,0 +1,608 @@
+/** @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 <Library/TdxMailboxLib.h>
+#include <IndustryStandard/Tdx.h>
+#include <IndustryStandard/IntelTdx.h>
+#include "IntelTdx.h"
+
+#define ALIGNED_2MB_MASK 0x1fffff
+
+/**
+  BSP call this function to accept memory in a range.
+
+  @param[in]  StartAddress      Start address of the memory region
+  @param[in]  Length            Length of the memory region
+  @param[in]  AcceptChunkSize   Accept chunk size
+  @param[in]  AcceptPageSize    Accept page size
+  @retval     EFI_SUCCESS       Successfully accept the memory region
+  @retval     Others            Indicate the other errors
+**/
+EFI_STATUS
+EFIAPI
+BspAcceptMemoryResourceRange (
+  IN EFI_PHYSICAL_ADDRESS   StartAddress,
+  IN UINT64                 Length,
+  IN UINT64                 AcceptChunkSize,
+  IN UINT64                 AcceptPageSize
+  )
+{
+  EFI_STATUS                  Status;
+  UINT64                      Pages;
+  UINT64                      Stride;
+  EFI_PHYSICAL_ADDRESS        PhysicalAddress;
+  volatile MP_WAKEUP_MAILBOX  *MailBox;
+
+  Status = EFI_SUCCESS;
+  PhysicalAddress = StartAddress;
+  Stride = GetCpusNum () * AcceptChunkSize;
+  MailBox = (volatile MP_WAKEUP_MAILBOX *) GetTdxMailBox ();
+
+  while (!EFI_ERROR(Status) && PhysicalAddress < StartAddress + Length) {
+    //
+    // Decrease size of near end of resource if needed.
+    //
+    Pages = MIN (AcceptChunkSize, StartAddress + Length - PhysicalAddress) / AcceptPageSize;
+
+    MailBox->Tallies[0] += (UINT32)Pages;
+
+    Status = TdAcceptPages (PhysicalAddress, Pages, AcceptPageSize);
+    //
+    // Bump address to next chunk this cpu is responisble for
+    //
+    PhysicalAddress += Stride;
+  }
+
+  return Status;
+}
+
+/**
+  This function will be called to accept pages. BSP and APs are invokded
+  to do the task together.
+
+  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
+  |---------------|
+
+  part 1) will be accepted in 4k and by BSP.
+  Part 2) will be accepted in 2M and by BSP/AP.
+  Part 3) will be accepted in 4k and by BSP.
+
+  @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
+MpAcceptMemoryResourceRange (
+  IN EFI_PHYSICAL_ADDRESS        PhysicalAddress,
+  IN EFI_PHYSICAL_ADDRESS        PhysicalEnd
+  )
+{
+  EFI_STATUS                  Status;
+  UINT64                      AcceptChunkSize;
+  UINT64                      AcceptPageSize;
+  UINT64                      StartAddress1;
+  UINT64                      StartAddress2;
+  UINT64                      StartAddress3;
+  UINT64                      TotalLength;
+  UINT64                      Length1;
+  UINT64                      Length2;
+  UINT64                      Length3;
+  UINT32                      Index;
+  UINT32                      CpusNum;
+  volatile MP_WAKEUP_MAILBOX  *MailBox;
+
+  AcceptChunkSize = FixedPcdGet64 (PcdTdxAcceptChunkSize);
+  AcceptPageSize = FixedPcdGet64 (PcdTdxAcceptPageSize);
+  TotalLength = PhysicalEnd - PhysicalAddress;
+  StartAddress1 = 0;
+  StartAddress2 = 0;
+  StartAddress3 = 0;
+  Length1 = 0;
+  Length2 = 0;
+  Length3 = 0;
+
+  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, "   Chunk: 0x%llx, Page : 0x%llx\n", AcceptChunkSize, AcceptPageSize));
+
+  MpSerializeStart ();
+
+  if (Length2 > 0) {
+    MpSendWakeupCommand (
+      MpProtectedModeWakeupCommandAcceptPages,
+      0,
+      StartAddress2,
+      StartAddress2 + Length2,
+      AcceptChunkSize,
+      AcceptPageSize);
+
+    Status = BspAcceptMemoryResourceRange (
+                StartAddress2,
+                Length2,
+                AcceptChunkSize,
+                AcceptPageSize);
+    ASSERT (!EFI_ERROR (Status));
+  }
+
+  if (Length1 > 0) {
+    Status = BspAcceptMemoryResourceRange (
+                StartAddress1,
+                Length1,
+                AcceptChunkSize,
+                SIZE_4KB);
+    ASSERT (!EFI_ERROR (Status));
+  }
+
+  if (Length3 > 0) {
+    Status = BspAcceptMemoryResourceRange (
+                StartAddress3,
+                Length3,
+                AcceptChunkSize,
+                SIZE_4KB);
+    ASSERT (!EFI_ERROR (Status));
+  }
+
+  MpSerializeEnd ();
+
+  CpusNum = GetCpusNum ();
+  MailBox = (volatile MP_WAKEUP_MAILBOX *) GetTdxMailBox ();
+
+  DEBUG ((DEBUG_INFO, "AcceptPage Tallies:\n"));
+  DEBUG ((DEBUG_INFO, "  "));
+  for (Index = 0; Index < CpusNum; Index++) {
+    DEBUG ((DEBUG_INFO, "%8d", MailBox->Tallies[Index]));
+    if (Index % 8 == 7) {
+      DEBUG ((DEBUG_INFO, "\n"));
+      DEBUG ((DEBUG_INFO, "  "));
+    }
+  }
+  DEBUG ((DEBUG_INFO, "\n"));
+
+  for (Index = 0; Index < CpusNum; Index++) {
+    if (MailBox->Errors[Index] > 0) {
+      Status = EFI_DEVICE_ERROR;
+      DEBUG ((DEBUG_ERROR, "Error(%d) of CPU-%d when accepting memory\n",
+        MailBox->Errors[Index], Index));
+    }
+  }
+
+  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 = MpAcceptMemoryResourceRange (
+            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..9420f586b176
--- /dev/null
+++ b/OvmfPkg/Sec/IntelTdx.h
@@ -0,0 +1,33 @@
+/** @file
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#ifndef __INTEL_TDX_H__
+#define __INTEL_TDX_H__
+
+#include <PiPei.h>
+#include <Library/BaseLib.h>
+#include <Uefi/UefiSpec.h>
+#include <Uefi/UefiBaseType.h>
+#include <IndustryStandard/UefiTcgPlatform.h>
+
+/**
+  In Tdx guest, some information need to be passed from host VMM to guest
+  firmware. For example, the memory resource, etc. These information are
+  prepared by host VMM and put in HobList which is described in TdxMetadata.
+
+  Information in HobList is treated as external input. From the security
+  perspective before it is consumed, it should be validated.
+
+  @retval   EFI_SUCCESS   Successfully process the hoblist
+  @retval   Others        Other error as indicated
+**/
+EFI_STATUS
+EFIAPI
+ProcessTdxHobList (
+  VOID
+  );
+#endif
diff --git a/OvmfPkg/Sec/SecMain.c b/OvmfPkg/Sec/SecMain.c
index 707b0d4bbff4..56ee8c4a230c 100644
--- a/OvmfPkg/Sec/SecMain.c
+++ b/OvmfPkg/Sec/SecMain.c
@@ -29,8 +29,10 @@
 #include <Library/MemEncryptSevLib.h>
 #include <Register/Amd/Ghcb.h>
 #include <Register/Amd/Msr.h>
-
+#include <IndustryStandard/Tdx.h>
+#include <Library/TdxLib.h>
 #include <Ppi/TemporaryRamSupport.h>
+#include "IntelTdx.h"
 
 #define SEC_IDT_ENTRY_COUNT  34
 
@@ -865,6 +867,24 @@ SevEsIsEnabled (
   return (SevEsWorkArea->SevEsEnabled != 0);
 }
 
+/**
+  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);
+}
+
+
 VOID
 EFIAPI
 SecCoreStartupWithStack (
@@ -878,6 +898,19 @@ 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
@@ -895,13 +928,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];
     }
@@ -947,6 +987,14 @@ SecCoreStartupWithStack (
     AsmEnableCache ();
   }
 
+  if (SecTdxIsEnabled ()) {
+    //
+    // InitializeCpuExceptionHandlers () should be called in Td guests so that
+    // #VE exceptions can be handled correctly.
+    //
+    InitializeCpuExceptionHandlers (NULL);
+  }
+
   DEBUG ((DEBUG_INFO,
     "SecCoreStartupWithStack(0x%x, 0x%x)\n",
     (UINT32)(UINTN)BootFv,
diff --git a/OvmfPkg/Sec/SecMain.inf b/OvmfPkg/Sec/SecMain.inf
index 6083fa21a433..4f16ff5d8330 100644
--- a/OvmfPkg/Sec/SecMain.inf
+++ b/OvmfPkg/Sec/SecMain.inf
@@ -28,6 +28,7 @@
   Ia32/SecEntry.nasm
 
 [Sources.X64]
+  IntelTdx.c
   X64/SecEntry.nasm
 
 [Packages]
@@ -51,6 +52,8 @@
   ExtractGuidedSectionLib
   LocalApicLib
   CpuExceptionHandlerLib
+  TdxLib
+  TdxMailboxLib
 
 [Ppis]
   gEfiTemporaryRamSupportPpiGuid                # PPI ALWAYS_PRODUCED
@@ -73,6 +76,9 @@
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfConfidentialComputingWorkAreaHeader
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfWorkAreaBase
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdTdxAcceptChunkSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdTdxAcceptPageSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfWorkAreaBase
 
 [FeaturePcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire
-- 
2.29.2.windows.2


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

* [PATCH V2 19/28] OvmfPkg: Check Tdx in QemuFwCfgPei to avoid DMA operation
  2021-10-05  3:39 [PATCH V2 00/28] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (17 preceding siblings ...)
  2021-10-05  3:39 ` [PATCH V2 18/28] OvmfPkg: Enable Tdx in SecMain.c Min Xu
@ 2021-10-05  3:39 ` Min Xu
  2021-10-05  3:39 ` [PATCH V2 20/28] MdeModulePkg: EFER should not be changed in TDX Min Xu
                   ` (8 subsequent siblings)
  27 siblings, 0 replies; 91+ messages in thread
From: Min Xu @ 2021-10-05  3:39 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

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>
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 1fa80686e0bd..1130552bc60a 100644
--- a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibInternal.h
+++ b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibInternal.h
@@ -60,4 +60,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 ecabd88fab66..bd2e51363bc6 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
@@ -82,6 +100,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"));
@@ -162,6 +188,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] 91+ messages in thread

* [PATCH V2 20/28] MdeModulePkg: EFER should not be changed in TDX
  2021-10-05  3:39 [PATCH V2 00/28] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (18 preceding siblings ...)
  2021-10-05  3:39 ` [PATCH V2 19/28] OvmfPkg: Check Tdx in QemuFwCfgPei to avoid DMA operation Min Xu
@ 2021-10-05  3:39 ` Min Xu
  2021-10-05  3:39 ` [PATCH V2 21/28] OvmfPkg: Update PlatformPei to support TDX Min Xu
                   ` (7 subsequent siblings)
  27 siblings, 0 replies; 91+ messages in thread
From: Min Xu @ 2021-10-05  3:39 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Jian J Wang, Hao A Wu, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky

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>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf          | 1 +
 MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c | 6 ++++++
 MdeModulePkg/MdeModulePkg.dec                    | 5 +++++
 3 files changed, 12 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 6831946c54d3..8a3b72509310 100644
--- a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
+++ b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
@@ -148,6 +148,12 @@ 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 133e04ee86ca..007044a311c2 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] 91+ messages in thread

* [PATCH V2 21/28] OvmfPkg: Update PlatformPei to support TDX
  2021-10-05  3:39 [PATCH V2 00/28] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (19 preceding siblings ...)
  2021-10-05  3:39 ` [PATCH V2 20/28] MdeModulePkg: EFER should not be changed in TDX Min Xu
@ 2021-10-05  3:39 ` Min Xu
  2021-10-13  4:49   ` [edk2-devel] " Gerd Hoffmann
  2021-10-05  3:39 ` [PATCH V2 22/28] UefiCpuPkg: Define ConfidentialComputingGuestAttr (Temp) Min Xu
                   ` (6 subsequent siblings)
  27 siblings, 1 reply; 91+ messages in thread
From: Min Xu @ 2021-10-05  3:39 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

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. Relocate mailbox
  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 waiting for
  further command.
3. 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>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/OvmfPkg.dec                    |   1 +
 OvmfPkg/PlatformPei/FeatureControl.c   |   8 +-
 OvmfPkg/PlatformPei/IntelTdx.c         | 290 +++++++++++++++++++++++++
 OvmfPkg/PlatformPei/IntelTdxNull.c     |  49 +++++
 OvmfPkg/PlatformPei/MemDetect.c        |  57 +++--
 OvmfPkg/PlatformPei/Platform.c         |   1 +
 OvmfPkg/PlatformPei/Platform.h         |  28 +++
 OvmfPkg/PlatformPei/PlatformPei.inf    |  13 ++
 OvmfPkg/PlatformPei/X64/ApRunLoop.nasm |  83 +++++++
 9 files changed, 516 insertions(+), 14 deletions(-)
 create mode 100644 OvmfPkg/PlatformPei/IntelTdx.c
 create mode 100644 OvmfPkg/PlatformPei/IntelTdxNull.c
 create mode 100644 OvmfPkg/PlatformPei/X64/ApRunLoop.nasm

diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index 6f535d718203..b489c69a736e 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -128,6 +128,7 @@
   gQemuKernelLoaderFsMediaGuid          = {0x1428f772, 0xb64a, 0x441e, {0xb8, 0xc3, 0x9e, 0xbd, 0xd7, 0xf8, 0x93, 0xc7}}
   gGrubFileGuid                         = {0xb5ae312c, 0xbc8a, 0x43b1, {0x9c, 0x62, 0xeb, 0xb8, 0x26, 0xdd, 0x5d, 0x07}}
   gConfidentialComputingSecretGuid      = {0xadf956ad, 0xe98c, 0x484c, {0xae, 0x11, 0xb5, 0x1c, 0x7d, 0x33, 0x64, 0x47}}
+  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 dccf9505dd7b..cf1a25722704 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..684907179c10
--- /dev/null
+++ b/OvmfPkg/PlatformPei/IntelTdx.c
@@ -0,0 +1,290 @@
+/** @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 <Library/TdxMailboxLib.h>
+#include <IndustryStandard/Tdx.h>
+#include <IndustryStandard/IntelTdx.h>
+#include <IndustryStandard/QemuFwCfg.h>
+#include <Library/QemuFwCfgLib.h>
+#include <Library/PeiServicesLib.h>
+#include <WorkArea.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);
+}
+
+/**
+  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   UINT64    Address of the relocated mailbox
+**/
+UINT64
+EFIAPI
+TdxRelocateMailbox (
+  VOID
+  )
+{
+  EFI_STATUS                  Status;
+  EFI_PHYSICAL_ADDRESS        Address;
+  VOID                        *ApLoopFunc = NULL;
+  UINT32                      RelocationPages;
+  MP_RELOCATION_MAP           RelocationMap;
+  MP_WAKEUP_MAILBOX           *RelocatedMailBox;
+
+  //
+  // Get information needed to setup aps running in their
+  // run loop in allocated acpi reserved memory
+  // Add another page for mailbox
+  //
+  AsmGetRelocationMap (&RelocationMap);
+  RelocationPages  = EFI_SIZE_TO_PAGES ((UINT32)RelocationMap.RelocateApLoopFuncSize) + 1;
+
+  Status = PeiServicesAllocatePages (EfiACPIMemoryNVS, RelocationPages, &Address);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Failed to allocate pages to relocate Td mailbox. %r\n", Status));
+    ASSERT (FALSE);
+    return 0;
+  }
+
+  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 (UINT64)RelocatedMailBox;
+}
+
+/**
+
+  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;
+  UINT32                      ConfidentialComputingCategory;
+  CONFIDENTIAL_COMPUTING_WORK_AREA_HEADER   *CcWorkAreaHeader;
+
+  if (!PlatformPeiIsTdxGuest ()) {
+    return;
+  }
+
+  CcWorkAreaHeader = (CONFIDENTIAL_COMPUTING_WORK_AREA_HEADER *) FixedPcdGet32 (PcdOvmfWorkAreaBase);
+  ConfidentialComputingCategory = *((UINT32 *)CcWorkAreaHeader);
+
+  PcdStatus = PcdSet32S (PcdConfidentialComputingCategory, ConfidentialComputingCategory);
+  ASSERT_RETURN_ERROR (PcdStatus);
+
+  PcdStatus = PcdSetBoolS (PcdIa32EferChangeAllowed, FALSE);
+  ASSERT_RETURN_ERROR (PcdStatus);
+
+  ZeroMem (&PlatformInfoHob, sizeof (PlatformInfoHob));
+  PlatformInfoHob.HostBridgePciDevId = mHostBridgeDevId;
+
+  PlatformInfoHob.RelocatedMailBox = TdxRelocateMailbox ();
+
+  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..35a079d82f66
--- /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 2c2c4641ec8a..43febcb3bf57 100644
--- a/OvmfPkg/PlatformPei/MemDetect.c
+++ b/OvmfPkg/PlatformPei/MemDetect.c
@@ -35,6 +35,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"
@@ -484,6 +485,7 @@ AddressWidthInitialization (
   )
 {
   UINT64 FirstNonAddress;
+  UINT64 TdxSharedPageMask;
 
   //
   // As guest-physical memory size grows, the permanent PEI RAM requirements
@@ -511,7 +513,17 @@ AddressWidthInitialization (
   if (mPhysMemAddressWidth <= 36) {
     mPhysMemAddressWidth = 36;
   }
-  ASSERT (mPhysMemAddressWidth <= 48);
+
+  if (PlatformPeiIsTdxGuest ()) {
+    TdxSharedPageMask = TdSharedPageMask ();
+    if (TdxSharedPageMask == (1ULL << 47)) {
+      mPhysMemAddressWidth = 48;
+    } else {
+      mPhysMemAddressWidth = 52;
+    }
+  }
+
+  ASSERT (mPhysMemAddressWidth <= 52);
 }
 
 
@@ -528,8 +540,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.
@@ -557,20 +571,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
@@ -815,7 +842,11 @@ InitializeRamRegions (
   VOID
   )
 {
-  QemuInitializeRam ();
+  if (PlatformPeiIsTdxGuest ()) {
+    TdxPublishRamRegions ();
+  } else {
+    QemuInitializeRam ();
+  }
 
   if (mS3Supported && mBootMode != BOOT_ON_S3_RESUME) {
     //
diff --git a/OvmfPkg/PlatformPei/Platform.c b/OvmfPkg/PlatformPei/Platform.c
index d3a20122a2ea..2c099376dad0 100644
--- a/OvmfPkg/PlatformPei/Platform.c
+++ b/OvmfPkg/PlatformPei/Platform.c
@@ -742,6 +742,7 @@ InitializePlatform (
 
   InstallClearCacheCallback ();
   AmdSevInitialize ();
+  IntelTdxInitialize ();
   MiscInitialization ();
   InstallFeatureControlCallback ();
 
diff --git a/OvmfPkg/PlatformPei/Platform.h b/OvmfPkg/PlatformPei/Platform.h
index 8b1d270c2b0b..bf12b52d153e 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,33 @@ AmdSevInitialize (
   VOID
   );
 
+VOID
+TdxPublishRamRegions (
+  VOID
+  );
+
+VOID
+AsmGetRelocationMap (
+  OUT MP_RELOCATION_MAP    *AddressMap
+  );
+
+
+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;
 
 extern BOOLEAN mS3Supported;
diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf
index 67eb7aa7166b..eec1bb3d9c38 100644
--- a/OvmfPkg/PlatformPei/PlatformPei.inf
+++ b/OvmfPkg/PlatformPei/PlatformPei.inf
@@ -34,6 +34,13 @@
   Platform.c
   Platform.h
 
+[Sources.IA32, Sources.EBC]
+  IntelTdxNull.c
+
+[Sources.X64]
+  IntelTdx.c
+  X64/ApRunLoop.nasm
+
 [Packages]
   EmbeddedPkg/EmbeddedPkg.dec
   MdePkg/MdePkg.dec
@@ -44,6 +51,7 @@
 
 [Guids]
   gEfiMemoryTypeInformationGuid
+  gUefiOvmfPkgTdxPlatformGuid
 
 [LibraryClasses]
   BaseLib
@@ -62,6 +70,9 @@
   MtrrLib
   MemEncryptSevLib
   PcdLib
+  TdxMailboxLib
+  TdxLib
+  MemoryAllocationLib
 
 [Pcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfPeiMemFvBase
@@ -106,6 +117,8 @@
   gUefiCpuPkgTokenSpaceGuid.PcdCpuBootLogicalProcessorNumber
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize
   gUefiCpuPkgTokenSpaceGuid.PcdSevEsIsEnabled
+  gEfiMdeModulePkgTokenSpaceGuid.PcdIa32EferChangeAllowed
+  gUefiCpuPkgTokenSpaceGuid.PcdConfidentialComputingCategory
 
 [FixedPcd]
   gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
diff --git a/OvmfPkg/PlatformPei/X64/ApRunLoop.nasm b/OvmfPkg/PlatformPei/X64/ApRunLoop.nasm
new file mode 100644
index 000000000000..adf4f03c3a9e
--- /dev/null
+++ b/OvmfPkg/PlatformPei/X64/ApRunLoop.nasm
@@ -0,0 +1,83 @@
+;------------------------------------------------------------------------------ ;
+; Copyright (c) 2015, 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
+
+%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:
+
+    ;
+    ; TdCall[TDINFO] to get the vCpuId
+    ;
+    ;mov     rax, 1
+    ;tdcall
+    ;
+    ; R8  [31:0]  NUM_VCPUS
+    ;     [63:32] MAX_VCPUS
+    ; R9  [31:0]  VCPU_INDEX
+    ;
+
+    mov       r8, rbp
+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       $
+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] 91+ messages in thread

* [PATCH V2 22/28] UefiCpuPkg: Define ConfidentialComputingGuestAttr (Temp)
  2021-10-05  3:39 [PATCH V2 00/28] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (20 preceding siblings ...)
  2021-10-05  3:39 ` [PATCH V2 21/28] OvmfPkg: Update PlatformPei to support TDX Min Xu
@ 2021-10-05  3:39 ` Min Xu
  2021-10-05  3:39 ` [PATCH V2 23/28] OvmfPkg: Update AcpiPlatformDxe to alter MADT table Min Xu
                   ` (5 subsequent siblings)
  27 siblings, 0 replies; 91+ messages in thread
From: Min Xu @ 2021-10-05  3:39 UTC (permalink / raw)
  To: devel; +Cc: Min Xu, Brijesh Singh

Add a new ConfidentialComputingGuestAttr PCD that can be used to query
the memory encryption attribute. (This is AMD's patch)

Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 OvmfPkg/PlatformPei/IntelTdx.c                |  8 ++----
 OvmfPkg/PlatformPei/PlatformPei.inf           |  2 +-
 .../Include/ConfidentialComputingGuestAttr.h  | 25 +++++++++++++++++++
 UefiCpuPkg/UefiCpuPkg.dec                     |  4 +++
 4 files changed, 32 insertions(+), 7 deletions(-)
 create mode 100644 UefiCpuPkg/Include/ConfidentialComputingGuestAttr.h

diff --git a/OvmfPkg/PlatformPei/IntelTdx.c b/OvmfPkg/PlatformPei/IntelTdx.c
index 684907179c10..5256740376b8 100644
--- a/OvmfPkg/PlatformPei/IntelTdx.c
+++ b/OvmfPkg/PlatformPei/IntelTdx.c
@@ -20,6 +20,7 @@
 #include <Library/QemuFwCfgLib.h>
 #include <Library/PeiServicesLib.h>
 #include <WorkArea.h>
+#include <ConfidentialComputingGuestAttr.h>
 #include "Platform.h"
 
 /**
@@ -263,17 +264,12 @@ IntelTdxInitialize (
 {
   EFI_HOB_PLATFORM_INFO       PlatformInfoHob;
   RETURN_STATUS               PcdStatus;
-  UINT32                      ConfidentialComputingCategory;
-  CONFIDENTIAL_COMPUTING_WORK_AREA_HEADER   *CcWorkAreaHeader;
 
   if (!PlatformPeiIsTdxGuest ()) {
     return;
   }
 
-  CcWorkAreaHeader = (CONFIDENTIAL_COMPUTING_WORK_AREA_HEADER *) FixedPcdGet32 (PcdOvmfWorkAreaBase);
-  ConfidentialComputingCategory = *((UINT32 *)CcWorkAreaHeader);
-
-  PcdStatus = PcdSet32S (PcdConfidentialComputingCategory, ConfidentialComputingCategory);
+  PcdStatus = PcdSet64S (PcdConfidentialComputingGuestAttr, CCAttrIntelTdx);
   ASSERT_RETURN_ERROR (PcdStatus);
 
   PcdStatus = PcdSetBoolS (PcdIa32EferChangeAllowed, FALSE);
diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf
index eec1bb3d9c38..91a35f77a81f 100644
--- a/OvmfPkg/PlatformPei/PlatformPei.inf
+++ b/OvmfPkg/PlatformPei/PlatformPei.inf
@@ -118,7 +118,7 @@
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize
   gUefiCpuPkgTokenSpaceGuid.PcdSevEsIsEnabled
   gEfiMdeModulePkgTokenSpaceGuid.PcdIa32EferChangeAllowed
-  gUefiCpuPkgTokenSpaceGuid.PcdConfidentialComputingCategory
+  gUefiCpuPkgTokenSpaceGuid.PcdConfidentialComputingGuestAttr
 
 [FixedPcd]
   gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
diff --git a/UefiCpuPkg/Include/ConfidentialComputingGuestAttr.h b/UefiCpuPkg/Include/ConfidentialComputingGuestAttr.h
new file mode 100644
index 000000000000..495b0df0ac33
--- /dev/null
+++ b/UefiCpuPkg/Include/ConfidentialComputingGuestAttr.h
@@ -0,0 +1,25 @@
+/** @file
+Definitions for Confidential Computing Attribute
+
+Copyright (c) 2021 AMD Inc. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef CONFIDENTIAL_COMPUTING_GUEST_ATTR_H_
+#define CONFIDENTIAL_COMPUTING_GUEST_ATTR_H_
+
+typedef enum {
+  /* The guest is running with memory encryption disabled. */
+  CCAttrNotEncrypted = 0,
+
+  /* The guest is running with AMD SEV memory encryption enabled. */
+  CCAttrAmdSev      = 0x100,
+  CCAttrAmdSevEs    = 0x101,
+  CCAttrAmdSevSnp   = 0x102,
+
+  /* The guest is running with Intel TDX memory encryption enabled. */
+  CCAttrIntelTdx    = 0x200,
+} CONFIDENTIAL_COMPUTING_GUEST_ATTR;
+
+#endif
diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
index 439bfc86a112..f270bbb990f6 100644
--- a/UefiCpuPkg/UefiCpuPkg.dec
+++ b/UefiCpuPkg/UefiCpuPkg.dec
@@ -399,5 +399,9 @@
   # @Prompt SEV-ES Status
   gUefiCpuPkgTokenSpaceGuid.PcdSevEsIsEnabled|FALSE|BOOLEAN|0x60000016
 
+  ## This dynamic PCD indicates the memory encryption attribute of the guest.
+  # @Prompt Memory encryption attribute
+  gUefiCpuPkgTokenSpaceGuid.PcdConfidentialComputingGuestAttr|0|UINT64|0x60000017
+
 [UserExtensions.TianoCore."ExtraFiles"]
   UefiCpuPkgExtra.uni
-- 
2.29.2.windows.2


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

* [PATCH V2 23/28] OvmfPkg: Update AcpiPlatformDxe to alter MADT table
  2021-10-05  3:39 [PATCH V2 00/28] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (21 preceding siblings ...)
  2021-10-05  3:39 ` [PATCH V2 22/28] UefiCpuPkg: Define ConfidentialComputingGuestAttr (Temp) Min Xu
@ 2021-10-05  3:39 ` Min Xu
  2021-10-05  3:39 ` [PATCH V2 24/28] OvmfPkg: Add TdxDxe driver Min Xu
                   ` (4 subsequent siblings)
  27 siblings, 0 replies; 91+ messages in thread
From: Min Xu @ 2021-10-05  3:39 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

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

diff --git a/OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c b/OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpi.c
index df800b149275..e8a9aff089e8 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
@@ -1129,7 +1132,14 @@ 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/AcpiPlatformDxe/QemuFwCfgAcpiPlatformDxe.inf b/OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpiPlatformDxe.inf
index dac25d1505be..6ffce2db5f99 100644
--- a/OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpiPlatformDxe.inf
+++ b/OvmfPkg/AcpiPlatformDxe/QemuFwCfgAcpiPlatformDxe.inf
@@ -48,6 +48,7 @@
 [Protocols]
   gEfiAcpiTableProtocolGuid                     # PROTOCOL ALWAYS_CONSUMED
   gEfiPciIoProtocolGuid                         # PROTOCOL SOMETIMES_CONSUMED
+  gQemuAcpiTableNotifyProtocolGuid              # PROTOCOL PRODUCES
 
 [Guids]
   gRootBridgesConnectedEventGroupGuid
diff --git a/OvmfPkg/Include/Protocol/QemuAcpiTableNotify.h b/OvmfPkg/Include/Protocol/QemuAcpiTableNotify.h
new file mode 100644
index 000000000000..8549ea9ec374
--- /dev/null
+++ b/OvmfPkg/Include/Protocol/QemuAcpiTableNotify.h
@@ -0,0 +1,29 @@
+/** @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] 91+ messages in thread

* [PATCH V2 24/28] OvmfPkg: Add TdxDxe driver
  2021-10-05  3:39 [PATCH V2 00/28] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (22 preceding siblings ...)
  2021-10-05  3:39 ` [PATCH V2 23/28] OvmfPkg: Update AcpiPlatformDxe to alter MADT table Min Xu
@ 2021-10-05  3:39 ` Min Xu
  2021-10-12 11:50   ` [edk2-devel] " Gerd Hoffmann
  2021-10-05  3:39 ` [PATCH V2 25/28] OvmfPkg/BaseMemEncryptTdxLib: Add TDX helper library Min Xu
                   ` (3 subsequent siblings)
  27 siblings, 1 reply; 91+ messages in thread
From: Min Xu @ 2021-10-05  3:39 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

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

Besides above features, TdxDxe driver will update the ACPI 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>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/Include/IndustryStandard/AcpiTdx.h  |  23 +++
 OvmfPkg/Include/IndustryStandard/IntelTdx.h |   5 +-
 OvmfPkg/OvmfPkg.dec                         |   4 +
 OvmfPkg/OvmfPkgX64.dsc                      |   2 +
 OvmfPkg/OvmfPkgX64.fdf                      |   3 +
 OvmfPkg/TdxDxe/TdxAcpiTable.c               | 207 ++++++++++++++++++++
 OvmfPkg/TdxDxe/TdxAcpiTable.h               |  38 ++++
 OvmfPkg/TdxDxe/TdxDxe.c                     | 207 ++++++++++++++++++++
 OvmfPkg/TdxDxe/TdxDxe.inf                   |  62 ++++++
 9 files changed, 548 insertions(+), 3 deletions(-)
 create mode 100644 OvmfPkg/Include/IndustryStandard/AcpiTdx.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

diff --git a/OvmfPkg/Include/IndustryStandard/AcpiTdx.h b/OvmfPkg/Include/IndustryStandard/AcpiTdx.h
new file mode 100644
index 000000000000..9e2753bbe52a
--- /dev/null
+++ b/OvmfPkg/Include/IndustryStandard/AcpiTdx.h
@@ -0,0 +1,23 @@
+/** @file
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef ACPI_TDX_H_
+#define ACPI_TDX_H_
+
+#define ACPI_MADT_MPWK_STRUCT_TYPE  0x10
+
+#pragma pack(1)
+
+typedef struct {
+  UINT8                       Type;
+  UINT8                       Length;
+  UINT16                      MailBoxVersion;
+  UINT32                      Reserved2;
+  UINT64                      MailBoxAddress;
+} ACPI_MADT_MPWK_STRUCT;
+
+#pragma pack()
+#endif
diff --git a/OvmfPkg/Include/IndustryStandard/IntelTdx.h b/OvmfPkg/Include/IndustryStandard/IntelTdx.h
index 2370f18289a1..bb02970394d7 100644
--- a/OvmfPkg/Include/IndustryStandard/IntelTdx.h
+++ b/OvmfPkg/Include/IndustryStandard/IntelTdx.h
@@ -6,8 +6,8 @@
 
 **/
 
-#ifndef _OVMF_INTEL_TDX__H_
-#define _OVMF_INTEL_TDX__H_
+#ifndef OVMF_INTEL_TDX_H_
+#define OVMF_INTEL_TDX_H_
 
 #include <PiPei.h>
 #include <Library/BaseLib.h>
@@ -52,7 +52,6 @@ typedef enum {
     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.
diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index b489c69a736e..cc5087da6aa2 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -153,6 +153,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
@@ -403,6 +404,9 @@
   #  instance in PiSmmCpuDxeSmm, and CpuHotplugSmm.
   gUefiOvmfPkgTokenSpaceGuid.PcdCpuHotEjectDataAddress|0|UINT64|0x46
 
+  ## TDX relocated Mailbox base address
+  gUefiOvmfPkgTokenSpaceGuid.PcdTdRelocatedMailboxBase|0|UINT64|0x60
+
 [PcdsFeatureFlag]
   gUefiOvmfPkgTokenSpaceGuid.PcdQemuBootOrderPciTranslation|TRUE|BOOLEAN|0x1c
   gUefiOvmfPkgTokenSpaceGuid.PcdQemuBootOrderMmioTranslation|FALSE|BOOLEAN|0x1d
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index 12ebde74433d..2c4a6613b1ea 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -977,6 +977,8 @@
   OvmfPkg/AmdSevDxe/AmdSevDxe.inf
   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 b6cc3cabdd69..bbd9303ab14f 100644
--- a/OvmfPkg/OvmfPkgX64.fdf
+++ b/OvmfPkg/OvmfPkgX64.fdf
@@ -214,6 +214,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
@@ -319,6 +320,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..249dbbb9128f
--- /dev/null
+++ b/OvmfPkg/TdxDxe/TdxAcpiTable.c
@@ -0,0 +1,207 @@
+/** @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 <IndustryStandard/AcpiTdx.h>
+#include <Protocol/AcpiSystemDescriptionTable.h>
+#include <Protocol/AcpiTable.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Protocol/Cpu.h>
+#include <Uefi.h>
+#include <TdxAcpiTable.h>
+
+STATIC
+EFI_STATUS
+EFIAPI
+QemuInstallAcpiMadtTable (
+  IN   EFI_ACPI_TABLE_PROTOCOL       *AcpiProtocol,
+  IN   VOID                          *AcpiTableBuffer,
+  IN   UINTN                         AcpiTableBufferSize,
+  OUT  UINTN                         *TableKey
+  )
+{
+  UINTN                                               CpuCount;
+  UINTN                                               NewBufferSize;
+  EFI_ACPI_1_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *Madt;
+  EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC_STRUCTURE         *LocalApic;
+  EFI_ACPI_1_0_IO_APIC_STRUCTURE                      *IoApic;
+  EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE    *Iso;
+  EFI_ACPI_1_0_LOCAL_APIC_NMI_STRUCTURE               *LocalApicNmi;
+  VOID                                                *Ptr;
+  UINTN                                               Loop;
+  EFI_STATUS                                          Status;
+  ACPI_MADT_MPWK_STRUCT                               *MadtMpWk;
+
+  ASSERT (AcpiTableBufferSize >= sizeof (EFI_ACPI_DESCRIPTION_HEADER));
+
+  CpuCount = TdVCpuNum();
+
+  ASSERT (CpuCount >= 1);
+
+#define NUM_8259_IRQS                   16
+  NewBufferSize = 1                     * sizeof (*Madt) +
+                  CpuCount              * sizeof (*LocalApic) +
+                  1                     * sizeof (*IoApic) +
+                  NUM_8259_IRQS         * sizeof (*Iso) +
+                  1                     * sizeof (*LocalApicNmi);
+
+  NewBufferSize += sizeof(ACPI_MADT_MPWK_STRUCT);
+
+  Madt = AllocatePool (NewBufferSize);
+  if (Madt == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  CopyMem (&(Madt->Header), AcpiTableBuffer, sizeof (EFI_ACPI_DESCRIPTION_HEADER));
+  Madt->Header.Length    = (UINT32) NewBufferSize;
+  Madt->LocalApicAddress = PcdGet32 (PcdCpuLocalApicBaseAddress);
+  Madt->Flags            = EFI_ACPI_1_0_PCAT_COMPAT;
+  Ptr = Madt + 1;
+
+  LocalApic = Ptr;
+  for (Loop = 0; Loop < CpuCount; ++Loop) {
+    LocalApic->Type            = EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC;
+    LocalApic->Length          = sizeof (*LocalApic);
+    LocalApic->AcpiProcessorId = (UINT8) Loop;
+    LocalApic->ApicId          = (UINT8) Loop;
+    LocalApic->Flags           = 1; // enabled
+    ++LocalApic;
+  }
+  Ptr = LocalApic;
+
+  IoApic = Ptr;
+  IoApic->Type             = EFI_ACPI_1_0_IO_APIC;
+  IoApic->Length           = sizeof (*IoApic);
+  IoApic->IoApicId         = (UINT8) CpuCount;
+  IoApic->Reserved         = EFI_ACPI_RESERVED_BYTE;
+  IoApic->IoApicAddress    = 0xFEC00000;
+  IoApic->SystemVectorBase = 0x00000000;
+  Ptr = IoApic + 1;
+
+  //
+  // IRQ0 (8254 Timer) => IRQ2 (PIC) Interrupt Source Override Structure
+  //
+  Iso = Ptr;
+  Iso->Type                        = EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE;
+  Iso->Length                      = sizeof (*Iso);
+  Iso->Bus                         = 0x00;    // ISA
+  Iso->Source                      = 0x00;    // IRQ0
+  Iso->GlobalSystemInterruptVector = 0x00000002;
+  Iso->Flags                       = 0x0005;  // Edge-triggered, Active High
+  ++Iso;
+
+  for (Loop = 1; Loop < NUM_8259_IRQS; ++Loop) {
+    Iso->Type                        = EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE;
+    Iso->Length                      = sizeof (*Iso);
+    Iso->Bus                         = 0x00; // ISA
+    Iso->Source                      = (UINT8) Loop;
+    Iso->GlobalSystemInterruptVector = (UINT32) Loop;
+    Iso->Flags                       = 0x0005; // Edge-triggered, Active High
+    ++Iso;
+  }
+  Ptr = Iso;
+
+  LocalApicNmi = Ptr;
+  LocalApicNmi->Type            = EFI_ACPI_1_0_LOCAL_APIC_NMI;
+  LocalApicNmi->Length          = sizeof (*LocalApicNmi);
+  LocalApicNmi->AcpiProcessorId = 0xFF; // applies to all processors
+  //
+  // polarity and trigger mode of the APIC I/O input signals conform to the
+  // specifications of the bus
+  //
+  LocalApicNmi->Flags           = 0x0000;
+  //
+  // Local APIC interrupt input LINTn to which NMI is connected.
+  //
+  LocalApicNmi->LocalApicInti   = 0x01;
+  Ptr = LocalApicNmi + 1;
+
+  MadtMpWk = Ptr;
+  MadtMpWk->Type = ACPI_MADT_MPWK_STRUCT_TYPE;
+  MadtMpWk->Length = sizeof(ACPI_MADT_MPWK_STRUCT);
+  MadtMpWk->MailBoxVersion = 1;
+  MadtMpWk->Reserved2 = 0;
+  MadtMpWk->MailBoxAddress = PcdGet64 (PcdTdRelocatedMailboxBase);
+  Ptr = MadtMpWk + 1;
+
+  ASSERT ((UINTN) ((UINT8 *)Ptr - (UINT8 *)Madt) == NewBufferSize);
+  Status = AcpiProtocol->InstallAcpiTable (AcpiProtocol, Madt, NewBufferSize, TableKey);
+
+  FreePool (Madt);
+
+  return Status;
+}
+
+/**
+  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          *AcpiSdtTable;
+  EFI_ACPI_TABLE_PROTOCOL        *AcpiTable;
+  EFI_STATUS                     Status;
+  UINTN                          Index;
+  EFI_ACPI_SDT_HEADER            *Table;
+  EFI_ACPI_TABLE_VERSION         Version;
+  UINTN                          OriginalTableKey;
+  UINTN                          UpdatedTableKey;
+
+  Index = 0;
+
+  Status = gBS->LocateProtocol (&gEfiAcpiSdtProtocolGuid, NULL, (void **) &AcpiSdtTable);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Unable to locate ACPI SDT protocol.\n"));
+    return;
+  }
+
+  do {
+    Status = AcpiSdtTable->GetAcpiTable (Index, &Table, &Version, &OriginalTableKey);
+
+    if (!EFI_ERROR (Status) && Table->Signature == EFI_ACPI_1_0_APIC_SIGNATURE) {
+      Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (void **) &AcpiTable);
+      if (EFI_ERROR (Status)) {
+        DEBUG ((DEBUG_ERROR, "Unable to locate ACPI Table protocol.\n"));
+        return;
+      }
+
+      //
+      // The altered MADT should be rebuilt and installed before uninstall the
+      // original one, because unintall table will free the memory which will be
+      // copied in QemuInstallAcpiMadtTable().
+      //
+      QemuInstallAcpiMadtTable (AcpiTable, Table, Table->Length, &UpdatedTableKey);
+      Status = AcpiTable->UninstallAcpiTable (AcpiTable, OriginalTableKey);
+      if (EFI_ERROR (Status)) {
+        DEBUG ((DEBUG_ERROR, "Uninstall MADT table error.\n"));
+      }
+      break;
+    }
+    Index ++;
+  } while (!EFI_ERROR (Status));
+}
diff --git a/OvmfPkg/TdxDxe/TdxAcpiTable.h b/OvmfPkg/TdxDxe/TdxAcpiTable.h
new file mode 100644
index 000000000000..36aaab9d1f41
--- /dev/null
+++ b/OvmfPkg/TdxDxe/TdxAcpiTable.h
@@ -0,0 +1,38 @@
+/** @file
+  Sample ACPI Platform Driver
+
+  Copyright (c) 2008 - 2012, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _TDX_QEMU_ACPI_H_INCLUDED_
+#define _TDX_QEMU_ACPI_H_INCLUDED_
+
+#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/Acpi.h>
+
+/**
+  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..eecad8f6e050
--- /dev/null
+++ b/OvmfPkg/TdxDxe/TdxDxe.c
@@ -0,0 +1,207 @@
+/** @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>
+
+/**
+  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;
+}
+
+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;
+  }
+
+  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);
+      }
+    }
+    //
+    // Set initial protected mode reset address to our initial mailbox
+    // After DXE, will update address before exiting
+    //
+    PcdStatus = PcdSet64S (PcdTdRelocatedMailboxBase, PlatformInfo->RelocatedMailBox);
+    ASSERT_RETURN_ERROR(PcdStatus);
+  }
+
+  return EFI_SUCCESS;
+}
diff --git a/OvmfPkg/TdxDxe/TdxDxe.inf b/OvmfPkg/TdxDxe/TdxDxe.inf
new file mode 100644
index 000000000000..b77c6e5e9252
--- /dev/null
+++ b/OvmfPkg/TdxDxe/TdxDxe.inf
@@ -0,0 +1,62 @@
+#/** @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
+
+[Packages]
+  MdeModulePkg/MdeModulePkg.dec
+  MdePkg/MdePkg.dec
+  UefiCpuPkg/UefiCpuPkg.dec
+  OvmfPkg/OvmfPkg.dec
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  DebugLib
+  DxeServicesTableLib
+  MemoryAllocationLib
+  PcdLib
+  UefiDriverEntryPoint
+  TdxLib
+  HobLib
+
+[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
+  gUefiOvmfPkgTokenSpaceGuid.PcdTdRelocatedMailboxBase
+  gUefiCpuPkgTokenSpaceGuid.PcdCpuLocalApicBaseAddress
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFdBaseAddress
-- 
2.29.2.windows.2


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

* [PATCH V2 25/28] OvmfPkg/BaseMemEncryptTdxLib: Add TDX helper library
  2021-10-05  3:39 [PATCH V2 00/28] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (23 preceding siblings ...)
  2021-10-05  3:39 ` [PATCH V2 24/28] OvmfPkg: Add TdxDxe driver Min Xu
@ 2021-10-05  3:39 ` Min Xu
  2021-10-12 12:13   ` [edk2-devel] " Gerd Hoffmann
  2021-10-05  3:39 ` [PATCH V2 26/28] OvmfPkg/QemuFwCfgLib: Support Tdx in QemuFwCfgDxe Min Xu
                   ` (2 subsequent siblings)
  27 siblings, 1 reply; 91+ messages in thread
From: Min Xu @ 2021-10-05  3:39 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

Add Intel TDXhelper 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>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/Include/Library/MemEncryptTdxLib.h    |  81 ++
 .../BaseMemEncryptTdxLib.inf                  |  45 +
 .../BaseMemEncryptTdxLibNull.inf              |  35 +
 .../BaseMemoryEncryptionNull.c                |  90 ++
 .../BaseMemEncryptTdxLib/MemoryEncryption.c   | 938 ++++++++++++++++++
 .../BaseMemEncryptTdxLib/VirtualMemory.h      | 181 ++++
 OvmfPkg/OvmfPkg.dec                           |   4 +
 OvmfPkg/OvmfPkgIa32.dsc                       |   1 +
 OvmfPkg/OvmfPkgIa32X64.dsc                    |   1 +
 9 files changed, 1376 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..6a482422f5ed
--- /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..c74581c447bf
--- /dev/null
+++ b/OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLib.inf
@@ -0,0 +1,45 @@
+## @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
+  UefiCpuPkg/UefiCpuPkg.dec
+
+[Sources]
+  VirtualMemory.h
+  MemoryEncryption.c
+
+[LibraryClasses]
+  BaseLib
+  CacheMaintenanceLib
+  CpuLib
+  DebugLib
+  MemoryAllocationLib
+  PcdLib
+  TdxLib
+
+[Pcd]
+  gUefiCpuPkgTokenSpaceGuid.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..3deb6ffeae3d
--- /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..29155c525401
--- /dev/null
+++ b/OvmfPkg/Library/BaseMemEncryptTdxLib/MemoryEncryption.c
@@ -0,0 +1,938 @@
+/** @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 PcdGet64 (PcdConfidentialComputingGuestAttr) == CCAttrIntelTdx;
+}
+
+/**
+  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..c23472f71909
--- /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 __VIRTUAL_MEMORY__
+#define __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 cc5087da6aa2..dda83d81695b 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 46040357da83..b17f654c96cc 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 acdcdeee9969..096d609d0d86 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] 91+ messages in thread

* [PATCH V2 26/28] OvmfPkg/QemuFwCfgLib: Support Tdx in QemuFwCfgDxe
  2021-10-05  3:39 [PATCH V2 00/28] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (24 preceding siblings ...)
  2021-10-05  3:39 ` [PATCH V2 25/28] OvmfPkg/BaseMemEncryptTdxLib: Add TDX helper library Min Xu
@ 2021-10-05  3:39 ` Min Xu
  2021-10-05  3:39 ` [PATCH V2 27/28] OvmfPkg: Update IoMmuDxe to support TDX Min Xu
  2021-10-05  3:39 ` [PATCH V2 28/28] OvmfPkg: Add LocalApicTimerDxe Min Xu
  27 siblings, 0 replies; 91+ messages in thread
From: Min Xu @ 2021-10-05  3:39 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

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>
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 0182c9235cac..7a60b3e82863 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;
 
     //
@@ -96,7 +97,7 @@ QemuFwCfgInitialize (
                     (VOID **)&mIoMmuProtocol);
     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__));
       ASSERT (FALSE);
       CpuDeadLoop ();
@@ -371,10 +372,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] 91+ messages in thread

* [PATCH V2 27/28] OvmfPkg: Update IoMmuDxe to support TDX
  2021-10-05  3:39 [PATCH V2 00/28] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (25 preceding siblings ...)
  2021-10-05  3:39 ` [PATCH V2 26/28] OvmfPkg/QemuFwCfgLib: Support Tdx in QemuFwCfgDxe Min Xu
@ 2021-10-05  3:39 ` Min Xu
  2021-10-12 12:15   ` [edk2-devel] " Gerd Hoffmann
  2021-10-05  3:39 ` [PATCH V2 28/28] OvmfPkg: Add LocalApicTimerDxe Min Xu
  27 siblings, 1 reply; 91+ messages in thread
From: Min Xu @ 2021-10-05  3:39 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

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, mIoMmuType is added to determine
if it is Legac guest, 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 mIoMmuType.

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>
---
 OvmfPkg/IoMmuDxe/AmdSevIoMmu.c | 134 ++++++++++++++++++++++++---------
 OvmfPkg/IoMmuDxe/AmdSevIoMmu.h |  12 +++
 OvmfPkg/IoMmuDxe/IoMmuDxe.c    |   4 +-
 OvmfPkg/IoMmuDxe/IoMmuDxe.inf  |   1 +
 OvmfPkg/OvmfPkgX64.dsc         |   2 +
 5 files changed, 117 insertions(+), 36 deletions(-)

diff --git a/OvmfPkg/IoMmuDxe/AmdSevIoMmu.c b/OvmfPkg/IoMmuDxe/AmdSevIoMmu.c
index b30628078f73..6c9570677cdc 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>
@@ -14,6 +14,12 @@
 
 #include "AmdSevIoMmu.h"
 
+#define IO_MMU_LEGACY  0x0
+#define IO_MMU_SEV     0x01
+#define IO_MMU_TDX     0x02
+
+UINTN mIoMmuType = IO_MMU_LEGACY;
+
 #define MAP_INFO_SIG SIGNATURE_64 ('M', 'A', 'P', '_', 'I', 'N', 'F', 'O')
 
 typedef struct {
@@ -74,7 +80,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.
@@ -246,14 +252,29 @@ IoMmuMap (
     goto FreeMapInfo;
   }
 
-  //
-  // Clear the memory encryption mask on the plaintext buffer.
-  //
-  Status = MemEncryptSevClearPageEncMask (
-             0,
-             MapInfo->PlainTextAddress,
-             MapInfo->NumberOfPages
-             );
+  if (mIoMmuType == IO_MMU_SEV) {
+    //
+    // Clear the memory encryption mask on the plaintext buffer.
+    //
+    Status = MemEncryptSevClearPageEncMask (
+               0,
+               MapInfo->PlainTextAddress,
+               MapInfo->NumberOfPages
+               );
+  } else if (mIoMmuType == IO_MMU_TDX) {
+    //
+    // Set the memory shared bit.
+    //
+    Status = MemEncryptTdxSetPageSharedBit (
+               0,
+               MapInfo->PlainTextAddress,
+               MapInfo->NumberOfPages
+               );
+
+  } else {
+    ASSERT (FALSE);
+  }
+
   ASSERT_EFI_ERROR (Status);
   if (EFI_ERROR (Status)) {
     CpuDeadLoop ();
@@ -399,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 (mIoMmuType == IO_MMU_SEV) {
+    //
+    // Restore the memory encryption mask on the area we used to hold the
+    // plaintext.
+    //
+    Status = MemEncryptSevSetPageEncMask (
+               0,
+               MapInfo->PlainTextAddress,
+               MapInfo->NumberOfPages
+               );
+  } else if (mIoMmuType == IO_MMU_TDX) {
+    //
+    // 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 ();
@@ -731,7 +767,7 @@ IoMmuSetAttribute (
   return EFI_UNSUPPORTED;
 }
 
-EDKII_IOMMU_PROTOCOL  mAmdSev = {
+EDKII_IOMMU_PROTOCOL  mIoMmu = {
   EDKII_IOMMU_PROTOCOL_REVISION,
   IoMmuSetAttribute,
   IoMmuMap,
@@ -763,7 +799,7 @@ EDKII_IOMMU_PROTOCOL  mAmdSev = {
 STATIC
 VOID
 EFIAPI
-AmdSevExitBoot (
+IoMmuExitBoot (
   IN EFI_EVENT Event,
   IN VOID      *EventToSignal
   )
@@ -771,11 +807,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.
@@ -783,13 +819,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*
@@ -815,7 +851,7 @@ AmdSevExitBoot (
 STATIC
 VOID
 EFIAPI
-AmdSevUnmapAllMappings (
+IoMmuUnmapAllMappings (
   IN EFI_EVENT Event,
   IN VOID      *Context
   )
@@ -834,7 +870,7 @@ AmdSevUnmapAllMappings (
     NextNode = GetNextNode (&mMapInfos, Node);
     MapInfo = CR (Node, MAP_INFO, Link, MAP_INFO_SIG);
     IoMmuUnmapWorker (
-      &mAmdSev, // This
+      &mIoMmu,  // This
       MapInfo,  // Mapping
       TRUE      // MemoryMapLocked
       );
@@ -847,7 +883,7 @@ AmdSevUnmapAllMappings (
 **/
 EFI_STATUS
 EFIAPI
-AmdSevInstallIoMmuProtocol (
+InstallIoMmuProtocol (
   VOID
   )
 {
@@ -863,7 +899,7 @@ AmdSevInstallIoMmuProtocol (
   Status = gBS->CreateEvent (
                   EVT_NOTIFY_SIGNAL,      // Type
                   TPL_CALLBACK,           // NotifyTpl
-                  AmdSevUnmapAllMappings, // NotifyFunction
+                  IoMmuUnmapAllMappings,  // NotifyFunction
                   NULL,                   // NotifyContext
                   &UnmapAllMappingsEvent  // Event
                   );
@@ -878,7 +914,7 @@ AmdSevInstallIoMmuProtocol (
   Status = gBS->CreateEvent (
                   EVT_SIGNAL_EXIT_BOOT_SERVICES, // Type
                   TPL_CALLBACK,                  // NotifyTpl
-                  AmdSevExitBoot,                // NotifyFunction
+                  IoMmuExitBoot,                 // NotifyFunction
                   UnmapAllMappingsEvent,         // NotifyContext
                   &ExitBootEvent                 // Event
                   );
@@ -889,7 +925,7 @@ AmdSevInstallIoMmuProtocol (
   Handle = NULL;
   Status = gBS->InstallMultipleProtocolInterfaces (
                   &Handle,
-                  &gEdkiiIoMmuProtocolGuid, &mAmdSev,
+                  &gEdkiiIoMmuProtocolGuid, &mIoMmu,
                   NULL
                   );
   if (EFI_ERROR (Status)) {
@@ -906,3 +942,31 @@ CloseUnmapAllMappingsEvent:
 
   return Status;
 }
+
+/**
+  Initialize Iommu Protocol for Intel TDX.
+
+**/
+EFI_STATUS
+EFIAPI
+IntelTdxInstallIoMmuProtocol (
+  VOID
+  )
+{
+  mIoMmuType = IO_MMU_TDX;
+  return InstallIoMmuProtocol ();
+}
+
+/**
+  Initialize Iommu Protocol for Intel TDX.
+
+**/
+EFI_STATUS
+EFIAPI
+AmdSevInstallIoMmuProtocol (
+  VOID
+  )
+{
+  mIoMmuType = IO_MMU_SEV;
+  return InstallIoMmuProtocol ();
+}
diff --git a/OvmfPkg/IoMmuDxe/AmdSevIoMmu.h b/OvmfPkg/IoMmuDxe/AmdSevIoMmu.h
index 8244f28b57fd..768d18028198 100644
--- a/OvmfPkg/IoMmuDxe/AmdSevIoMmu.h
+++ b/OvmfPkg/IoMmuDxe/AmdSevIoMmu.h
@@ -21,6 +21,7 @@
 #include <Library/BaseMemoryLib.h>
 #include <Library/DebugLib.h>
 #include <Library/MemEncryptSevLib.h>
+#include <Library/MemEncryptTdxLib.h>
 #include <Library/MemoryAllocationLib.h>
 #include <Library/UefiBootServicesTableLib.h>
 
@@ -35,4 +36,15 @@ AmdSevInstallIoMmuProtocol (
   VOID
   );
 
+/**
+  Install IOMMU protocol to provide the DMA support for PciHostBridge and
+  MemEncryptSevLib.
+
+**/
+EFI_STATUS
+EFIAPI
+IntelTdxInstallIoMmuProtocol (
+  VOID
+  );
+
 #endif
diff --git a/OvmfPkg/IoMmuDxe/IoMmuDxe.c b/OvmfPkg/IoMmuDxe/IoMmuDxe.c
index 13df8ba874c5..698229b16bfa 100644
--- a/OvmfPkg/IoMmuDxe/IoMmuDxe.c
+++ b/OvmfPkg/IoMmuDxe/IoMmuDxe.c
@@ -22,11 +22,13 @@ 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 ();
+  } else if (MemEncryptTdxIsEnabled ()) {
+    Status = IntelTdxInstallIoMmuProtocol ();
   } else {
     Handle = NULL;
 
diff --git a/OvmfPkg/IoMmuDxe/IoMmuDxe.inf b/OvmfPkg/IoMmuDxe/IoMmuDxe.inf
index 2ebd74e5558c..52ad6f2efdb7 100644
--- a/OvmfPkg/IoMmuDxe/IoMmuDxe.inf
+++ b/OvmfPkg/IoMmuDxe/IoMmuDxe.inf
@@ -32,6 +32,7 @@
   BaseMemoryLib
   DebugLib
   MemEncryptSevLib
+  MemEncryptTdxLib
   MemoryAllocationLib
   UefiBootServicesTableLib
   UefiDriverEntryPoint
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index 2c4a6613b1ea..455e901c2eb8 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] 91+ messages in thread

* [PATCH V2 28/28] OvmfPkg: Add LocalApicTimerDxe
  2021-10-05  3:39 [PATCH V2 00/28] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
                   ` (26 preceding siblings ...)
  2021-10-05  3:39 ` [PATCH V2 27/28] OvmfPkg: Update IoMmuDxe to support TDX Min Xu
@ 2021-10-05  3:39 ` Min Xu
  2021-10-12 13:02   ` [edk2-devel] " Gerd Hoffmann
  27 siblings, 1 reply; 91+ messages in thread
From: Min Xu @ 2021-10-05  3:39 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

TDX guest supports LocalApicTimer. But in current OvmfPkg the supported
timer is 8254TimerDxe. So gUefiOvmfPkgTokenSpaceGuid.PcdTimerSelector
is introduced to select the running Timer. The Timer driver will check
the TimerSelector in its entry point. The default Timer is 8254.

TimerSelector will be set to LocalApicTimer by TdxDxe driver in Tdx guest.

Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/8254TimerDxe/8254Timer.inf            |   3 +
 OvmfPkg/8254TimerDxe/Timer.c                  |   5 +
 OvmfPkg/8254TimerDxe/Timer.h                  |   1 +
 OvmfPkg/8259InterruptControllerDxe/8259.c     |   1 +
 OvmfPkg/8259InterruptControllerDxe/8259.inf   |   1 +
 OvmfPkg/Include/Protocol/TimerSelector.h      |  16 +
 OvmfPkg/LocalApicTimerDxe/LocalApicTimer.c    | 488 ++++++++++++++++++
 .../LocalApicTimerDxe/LocalApicTimerDxe.inf   |  52 ++
 .../LocalApicTimerDxe/LocalApicTimerDxe.uni   |  13 +
 OvmfPkg/OvmfPkg.dec                           |  14 +
 OvmfPkg/OvmfPkgX64.dsc                        |   4 +
 OvmfPkg/OvmfPkgX64.fdf                        |   1 +
 OvmfPkg/TdxDxe/TdxDxe.c                       |   3 +
 OvmfPkg/TdxDxe/TdxDxe.inf                     |   1 +
 14 files changed, 603 insertions(+)
 create mode 100644 OvmfPkg/Include/Protocol/TimerSelector.h
 create mode 100644 OvmfPkg/LocalApicTimerDxe/LocalApicTimer.c
 create mode 100644 OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
 create mode 100644 OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.uni

diff --git a/OvmfPkg/8254TimerDxe/8254Timer.inf b/OvmfPkg/8254TimerDxe/8254Timer.inf
index 8a07c8247ebe..f15792106944 100644
--- a/OvmfPkg/8254TimerDxe/8254Timer.inf
+++ b/OvmfPkg/8254TimerDxe/8254Timer.inf
@@ -36,6 +36,9 @@
   gEfiLegacy8259ProtocolGuid    ## CONSUMES
   gEfiTimerArchProtocolGuid     ## PRODUCES
 
+[Pcd]
+  gUefiOvmfPkgTokenSpaceGuid.PcdTimerSelector
+
 [Depex]
   gEfiCpuArchProtocolGuid AND gEfiLegacy8259ProtocolGuid
 [UserExtensions.TianoCore."ExtraFiles"]
diff --git a/OvmfPkg/8254TimerDxe/Timer.c b/OvmfPkg/8254TimerDxe/Timer.c
index fd1691beb3c7..b8d29acebf39 100644
--- a/OvmfPkg/8254TimerDxe/Timer.c
+++ b/OvmfPkg/8254TimerDxe/Timer.c
@@ -7,6 +7,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
 **/
 
 #include "Timer.h"
+#include <Library/PcdLib.h>
 
 //
 // The handle onto which the Timer Architectural Protocol will be installed
@@ -340,6 +341,10 @@ TimerDriverInitialize (
   EFI_STATUS  Status;
   UINT32      TimerVector;
 
+  if (PcdGet32 (PcdTimerSelector) != TimerSelector8254) {
+    return EFI_UNSUPPORTED;
+  }
+
   //
   // Initialize the pointer to our notify function.
   //
diff --git a/OvmfPkg/8254TimerDxe/Timer.h b/OvmfPkg/8254TimerDxe/Timer.h
index 4c4b720d50dd..2beb7901fefd 100644
--- a/OvmfPkg/8254TimerDxe/Timer.h
+++ b/OvmfPkg/8254TimerDxe/Timer.h
@@ -13,6 +13,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
 #include <Protocol/Cpu.h>
 #include <Protocol/Legacy8259.h>
 #include <Protocol/Timer.h>
+#include <Protocol/TimerSelector.h>
 
 #include <Library/UefiBootServicesTableLib.h>
 #include <Library/BaseLib.h>
diff --git a/OvmfPkg/8259InterruptControllerDxe/8259.c b/OvmfPkg/8259InterruptControllerDxe/8259.c
index 1c2ac1039d40..eb69302cc12e 100644
--- a/OvmfPkg/8259InterruptControllerDxe/8259.c
+++ b/OvmfPkg/8259InterruptControllerDxe/8259.c
@@ -7,6 +7,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
 **/
 
 #include "8259.h"
+#include <Library/PcdLib.h>
 
 //
 // Global for the Legacy 8259 Protocol that is produced by this driver
diff --git a/OvmfPkg/8259InterruptControllerDxe/8259.inf b/OvmfPkg/8259InterruptControllerDxe/8259.inf
index 7320ff2490a7..fcd245720060 100644
--- a/OvmfPkg/8259InterruptControllerDxe/8259.inf
+++ b/OvmfPkg/8259InterruptControllerDxe/8259.inf
@@ -22,6 +22,7 @@
 [Packages]
   MdePkg/MdePkg.dec
   OvmfPkg/OvmfPkg.dec
+  UefiCpuPkg/UefiCpuPkg.dec
 
 [LibraryClasses]
   UefiBootServicesTableLib
diff --git a/OvmfPkg/Include/Protocol/TimerSelector.h b/OvmfPkg/Include/Protocol/TimerSelector.h
new file mode 100644
index 000000000000..b062ab94706e
--- /dev/null
+++ b/OvmfPkg/Include/Protocol/TimerSelector.h
@@ -0,0 +1,16 @@
+/** @file
+
+Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef TIMER_SELECTOR_H_
+#define TIMER_SELECTOR_H_
+
+typedef enum {
+  TimerSelector8254,
+  TimerSelectorLocalApic,
+} TIMER_SELECTOR;
+
+#endif
diff --git a/OvmfPkg/LocalApicTimerDxe/LocalApicTimer.c b/OvmfPkg/LocalApicTimerDxe/LocalApicTimer.c
new file mode 100644
index 000000000000..fafb01ec841b
--- /dev/null
+++ b/OvmfPkg/LocalApicTimerDxe/LocalApicTimer.c
@@ -0,0 +1,488 @@
+/** @file
+  Timer Architectural Protocol module using Local APIC Timer
+
+  Copyright (c) 2011 - 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+
+#include <Protocol/Cpu.h>
+#include <Protocol/Timer.h>
+#include <Protocol/TimerSelector.h>
+
+#include <Library/PcdLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/LocalApicLib.h>
+#include <Register/LocalApic.h>
+#include <ConfidentialComputingGuestAttr.h>
+
+/**
+  This function registers the handler NotifyFunction so it is called every time
+  the timer interrupt fires.  It also passes the amount of time since the last
+  handler call to the NotifyFunction.  If NotifyFunction is NULL, then the
+  handler is unregistered.  If the handler is registered, then EFI_SUCCESS is
+  returned.  If the CPU does not support registering a timer interrupt handler,
+  then EFI_UNSUPPORTED is returned.  If an attempt is made to register a handler
+  when a handler is already registered, then EFI_ALREADY_STARTED is returned.
+  If an attempt is made to unregister a handler when a handler is not registered,
+  then EFI_INVALID_PARAMETER is returned.  If an error occurs attempting to
+  register the NotifyFunction with the timer interrupt, then EFI_DEVICE_ERROR
+  is returned.
+
+  @param  This            The EFI_TIMER_ARCH_PROTOCOL instance.
+  @param  NotifyFunction  The function to call when a timer interrupt fires.
+                          This function executes at TPL_HIGH_LEVEL.  The DXE
+                          Core will register a handler for the timer interrupt,
+                          so it can know how much time has passed.  This
+                          information is used to signal timer based events.
+                          NULL will unregister the handler.
+
+  @retval  EFI_SUCCESS            The timer handler was registered.
+  @retval  EFI_UNSUPPORTED        The platform does not support timer interrupts.
+  @retval  EFI_ALREADY_STARTED    NotifyFunction is not NULL, and a handler is already
+                                  registered.
+  @retval  EFI_INVALID_PARAMETER  NotifyFunction is NULL, and a handler was not
+                                  previously registered.
+  @retval  EFI_DEVICE_ERROR       The timer handler could not be registered.
+
+**/
+EFI_STATUS
+EFIAPI
+TimerDriverRegisterHandler (
+  IN EFI_TIMER_ARCH_PROTOCOL  *This,
+  IN EFI_TIMER_NOTIFY         NotifyFunction
+  );
+
+/**
+  This function adjusts the period of timer interrupts to the value specified
+  by TimerPeriod.  If the timer period is updated, then the selected timer
+  period is stored in EFI_TIMER.TimerPeriod, and EFI_SUCCESS is returned.  If
+  the timer hardware is not programmable, then EFI_UNSUPPORTED is returned.
+  If an error occurs while attempting to update the timer period, then the
+  timer hardware will be put back in its state prior to this call, and
+  EFI_DEVICE_ERROR is returned.  If TimerPeriod is 0, then the timer interrupt
+  is disabled.  This is not the same as disabling the CPU's interrupts.
+  Instead, it must either turn off the timer hardware, or it must adjust the
+  interrupt controller so that a CPU interrupt is not generated when the timer
+  interrupt fires.
+
+  @param  This         The EFI_TIMER_ARCH_PROTOCOL instance.
+  @param  TimerPeriod  The rate to program the timer interrupt in 100 nS units.
+                       If the timer hardware is not programmable, then
+                       EFI_UNSUPPORTED is returned.  If the timer is programmable,
+                       then the timer period will be rounded up to the nearest
+                       timer period that is supported by the timer hardware.
+                       If TimerPeriod is set to 0, then the timer interrupts
+                       will be disabled.
+
+  @retval  EFI_SUCCESS       The timer period was changed.
+  @retval  EFI_UNSUPPORTED   The platform cannot change the period of the timer interrupt.
+  @retval  EFI_DEVICE_ERROR  The timer period could not be changed due to a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+TimerDriverSetTimerPeriod (
+  IN EFI_TIMER_ARCH_PROTOCOL  *This,
+  IN UINT64                   TimerPeriod
+  );
+
+/**
+  This function retrieves the period of timer interrupts in 100 ns units,
+  returns that value in TimerPeriod, and returns EFI_SUCCESS.  If TimerPeriod
+  is NULL, then EFI_INVALID_PARAMETER is returned.  If a TimerPeriod of 0 is
+  returned, then the timer is currently disabled.
+
+  @param  This         The EFI_TIMER_ARCH_PROTOCOL instance.
+  @param  TimerPeriod  A pointer to the timer period to retrieve in 100 ns units.
+                       If 0 is returned, then the timer is currently disabled.
+
+  @retval  EFI_SUCCESS            The timer period was returned in TimerPeriod.
+  @retval  EFI_INVALID_PARAMETER  TimerPeriod is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+TimerDriverGetTimerPeriod (
+  IN EFI_TIMER_ARCH_PROTOCOL   *This,
+  OUT UINT64                   *TimerPeriod
+  );
+
+/**
+  This function generates a soft timer interrupt. If the platform does not support soft
+  timer interrupts, then EFI_UNSUPPORTED is returned. Otherwise, EFI_SUCCESS is returned.
+  If a handler has been registered through the EFI_TIMER_ARCH_PROTOCOL.RegisterHandler()
+  service, then a soft timer interrupt will be generated. If the timer interrupt is
+  enabled when this service is called, then the registered handler will be invoked. The
+  registered handler should not be able to distinguish a hardware-generated timer
+  interrupt from a software-generated timer interrupt.
+
+  @param  This  The EFI_TIMER_ARCH_PROTOCOL instance.
+
+  @retval  EFI_SUCCESS       The soft timer interrupt was generated.
+  @retval  EFI_UNSUPPORTED   The platform does not support the generation of soft
+                             timer interrupts.
+
+**/
+EFI_STATUS
+EFIAPI
+TimerDriverGenerateSoftInterrupt (
+  IN EFI_TIMER_ARCH_PROTOCOL  *This
+  );
+
+///
+/// The handle onto which the Timer Architectural Protocol will be installed.
+///
+EFI_HANDLE   mTimerHandle = NULL;
+
+///
+/// The Timer Architectural Protocol that this driver produces.
+///
+EFI_TIMER_ARCH_PROTOCOL  mTimer = {
+  TimerDriverRegisterHandler,
+  TimerDriverSetTimerPeriod,
+  TimerDriverGetTimerPeriod,
+  TimerDriverGenerateSoftInterrupt
+};
+
+///
+/// Pointer to the CPU Architectural Protocol instance.
+///
+EFI_CPU_ARCH_PROTOCOL  *mCpu = NULL;
+
+///
+/// The notification function to call on every timer interrupt.
+///
+EFI_TIMER_NOTIFY  mTimerNotifyFunction = NULL;
+
+///
+/// The current period of the Local APIC timer interrupt in 100 ns units.
+///
+UINT64  mTimerPeriod = 0;
+
+///
+/// Counts the number of Local APIC Timer interrupts processed by this driver.
+/// Only required for debug.
+///
+volatile UINTN  mNumTicks;
+
+/**
+  The interrupt handler for the Local APIC timer.  This handler clears the Local
+  APIC interrupt and computes the amount of time that has passed since the last
+  Local APIC timer interrupt.  If a notification function is registered, then
+  the amount of time since the last Local APIC timer interrupt is passed to that
+  notification function in 100 ns units.  The Local APIC timer is updated to
+  generate another interrupt in the required time period.
+
+  @param  InterruptType  The type of interrupt that occurred.
+  @param  SystemContext  A pointer to the system context when the interrupt occurred.
+**/
+VOID
+EFIAPI
+TimerInterruptHandler (
+  IN EFI_EXCEPTION_TYPE   InterruptType,
+  IN EFI_SYSTEM_CONTEXT   SystemContext
+  )
+{
+
+  EFI_TPL OriginalTPL;
+
+  OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+
+  //
+  // Count number of ticks
+  //
+  DEBUG_CODE (mNumTicks++;);
+
+  //
+  // Check to see if there is a registered notification function
+  //
+  if (mTimerNotifyFunction != NULL) {
+    mTimerNotifyFunction (mTimerPeriod);
+  }
+
+  gBS->RestoreTPL (OriginalTPL);
+
+  DisableInterrupts ();
+
+  SendApicEoi();
+}
+
+/**
+  This function registers the handler NotifyFunction so it is called every time
+  the timer interrupt fires.  It also passes the amount of time since the last
+  handler call to the NotifyFunction.  If NotifyFunction is NULL, then the
+  handler is unregistered.  If the handler is registered, then EFI_SUCCESS is
+  returned.  If the CPU does not support registering a timer interrupt handler,
+  then EFI_UNSUPPORTED is returned.  If an attempt is made to register a handler
+  when a handler is already registered, then EFI_ALREADY_STARTED is returned.
+  If an attempt is made to unregister a handler when a handler is not registered,
+  then EFI_INVALID_PARAMETER is returned.  If an error occurs attempting to
+  register the NotifyFunction with the timer interrupt, then EFI_DEVICE_ERROR
+  is returned.
+
+  @param  This            The EFI_TIMER_ARCH_PROTOCOL instance.
+  @param  NotifyFunction  The function to call when a timer interrupt fires.
+                          This function executes at TPL_HIGH_LEVEL.  The DXE
+                          Core will register a handler for the timer interrupt,
+                          so it can know how much time has passed.  This
+                          information is used to signal timer based events.
+                          NULL will unregister the handler.
+
+  @retval  EFI_SUCCESS            The timer handler was registered.
+  @retval  EFI_UNSUPPORTED        The platform does not support timer interrupts.
+  @retval  EFI_ALREADY_STARTED    NotifyFunction is not NULL, and a handler is already
+                                  registered.
+  @retval  EFI_INVALID_PARAMETER  NotifyFunction is NULL, and a handler was not
+                                  previously registered.
+  @retval  EFI_DEVICE_ERROR       The timer handler could not be registered.
+
+**/
+EFI_STATUS
+EFIAPI
+TimerDriverRegisterHandler (
+  IN EFI_TIMER_ARCH_PROTOCOL  *This,
+  IN EFI_TIMER_NOTIFY         NotifyFunction
+  )
+{
+  //
+  // Check for invalid parameters
+  //
+  if (NotifyFunction == NULL && mTimerNotifyFunction == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+  if (NotifyFunction != NULL && mTimerNotifyFunction != NULL) {
+    return EFI_ALREADY_STARTED;
+  }
+
+  //
+  // Cache the registered notification function
+  //
+  mTimerNotifyFunction = NotifyFunction;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function adjusts the period of timer interrupts to the value specified
+  by TimerPeriod.  If the timer period is updated, then the selected timer
+  period is stored in EFI_TIMER.TimerPeriod, and EFI_SUCCESS is returned.  If
+  the timer hardware is not programmable, then EFI_UNSUPPORTED is returned.
+  If an error occurs while attempting to update the timer period, then the
+  timer hardware will be put back in its state prior to this call, and
+  EFI_DEVICE_ERROR is returned.  If TimerPeriod is 0, then the timer interrupt
+  is disabled.  This is not the same as disabling the CPU's interrupts.
+  Instead, it must either turn off the timer hardware, or it must adjust the
+  interrupt controller so that a CPU interrupt is not generated when the timer
+  interrupt fires.
+
+  @param  This         The EFI_TIMER_ARCH_PROTOCOL instance.
+  @param  TimerPeriod  The rate to program the timer interrupt in 100 nS units.
+                       If the timer hardware is not programmable, then
+                       EFI_UNSUPPORTED is returned.  If the timer is programmable,
+                       then the timer period will be rounded up to the nearest
+                       timer period that is supported by the timer hardware.
+                       If TimerPeriod is set to 0, then the timer interrupts
+                       will be disabled.
+
+  @retval  EFI_SUCCESS       The timer period was changed.
+  @retval  EFI_UNSUPPORTED   The platform cannot change the period of the timer interrupt.
+  @retval  EFI_DEVICE_ERROR  The timer period could not be changed due to a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+TimerDriverSetTimerPeriod (
+  IN EFI_TIMER_ARCH_PROTOCOL  *This,
+  IN UINT64                   TimerPeriod
+  )
+{
+  EFI_TPL                        Tpl;
+  UINTN    Divisor;
+  UINT64   TimerCount;
+
+  //
+  // Disable interrupts
+  //
+  Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+
+  if (TimerPeriod == 0) {
+    //
+    // Disable timer interrupt for a TimerPeriod of 0
+    //
+    DisableApicTimerInterrupt ();
+  } else {
+    DisableApicTimerInterrupt ();
+
+    //
+    // Convert TimerPeriod in 100ns units to Local APIC Timer ticks.
+    //
+    GetApicTimerState (&Divisor, NULL, NULL);
+    TimerCount = DivU64x32 (
+                   MultU64x32 (TimerPeriod, PcdGet32(PcdFSBClock)),
+                   (UINT32)Divisor * 10000000
+                   );
+
+    //
+    // Program the local APIC timer
+    //
+    InitializeApicTimer (0, (UINT32)TimerCount, TRUE, PcdGet8 (PcdHpetLocalApicVector));
+
+    EnableApicTimerInterrupt ();
+  }
+
+  //
+  // Save the new timer period
+  //
+  mTimerPeriod = TimerPeriod;
+
+  //
+  // Restore interrupts
+  //
+  gBS->RestoreTPL (Tpl);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function retrieves the period of timer interrupts in 100 ns units,
+  returns that value in TimerPeriod, and returns EFI_SUCCESS.  If TimerPeriod
+  is NULL, then EFI_INVALID_PARAMETER is returned.  If a TimerPeriod of 0 is
+  returned, then the timer is currently disabled.
+
+  @param  This         The EFI_TIMER_ARCH_PROTOCOL instance.
+  @param  TimerPeriod  A pointer to the timer period to retrieve in 100 ns units.
+                       If 0 is returned, then the timer is currently disabled.
+
+  @retval  EFI_SUCCESS            The timer period was returned in TimerPeriod.
+  @retval  EFI_INVALID_PARAMETER  TimerPeriod is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+TimerDriverGetTimerPeriod (
+  IN EFI_TIMER_ARCH_PROTOCOL   *This,
+  OUT UINT64                   *TimerPeriod
+  )
+{
+  if (TimerPeriod == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *TimerPeriod = mTimerPeriod;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function generates a soft timer interrupt. If the platform does not support soft
+  timer interrupts, then EFI_UNSUPPORTED is returned. Otherwise, EFI_SUCCESS is returned.
+  If a handler has been registered through the EFI_TIMER_ARCH_PROTOCOL.RegisterHandler()
+  service, then a soft timer interrupt will be generated. If the timer interrupt is
+  enabled when this service is called, then the registered handler will be invoked. The
+  registered handler should not be able to distinguish a hardware-generated timer
+  interrupt from a software-generated timer interrupt.
+
+  @param  This  The EFI_TIMER_ARCH_PROTOCOL instance.
+
+  @retval  EFI_SUCCESS       The soft timer interrupt was generated.
+  @retval  EFI_UNSUPPORTED   The platform does not support the generation of soft
+                             timer interrupts.
+
+**/
+EFI_STATUS
+EFIAPI
+TimerDriverGenerateSoftInterrupt (
+  IN EFI_TIMER_ARCH_PROTOCOL  *This
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  Initialize the Timer Architectural Protocol driver
+
+  @param  ImageHandle  ImageHandle of the loaded driver
+  @param  SystemTable  Pointer to the System Table
+
+  @retval  EFI_SUCCESS           Timer Architectural Protocol created
+  @retval  EFI_OUT_OF_RESOURCES  Not enough resources available to initialize driver.
+  @retval  EFI_DEVICE_ERROR      A device error occurred attempting to initialize the driver.
+
+**/
+EFI_STATUS
+EFIAPI
+TimerDriverInitialize (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS                             Status;
+
+  if (PcdGet32 (PcdTimerSelector) != TimerSelectorLocalApic) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Make sure the Timer Architectural Protocol is not already installed in the system
+  //
+  ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiTimerArchProtocolGuid);
+
+  //
+  // Find the CPU architectural protocol.
+  //
+  Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **) &mCpu);
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Install interrupt handler for the Local APIC Timer
+  //
+  Status = mCpu->RegisterInterruptHandler (mCpu, PcdGet8 (PcdHpetLocalApicVector), TimerInterruptHandler);
+  ASSERT_EFI_ERROR (Status);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Unable to register Local APIC interrupt with CPU Arch Protocol.  Unload Local APIC timer driver.\n"));
+    return EFI_DEVICE_ERROR;
+  }
+
+  //
+  // Force the Local APIC timer to be disabled while setting everything up
+  //
+  DisableApicTimerInterrupt ();
+  InitializeApicTimer (0, 0, FALSE, PcdGet8 (PcdHpetLocalApicVector));
+
+  //
+  // Force the Local APIC Timer to be enabled at its default period
+  //
+  Status = TimerDriverSetTimerPeriod (&mTimer, PcdGet64 (PcdHpetDefaultTimerPeriod));
+  ASSERT_EFI_ERROR (Status);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Unable to set Local APIC default timer rate.  Unload Local APIC timer driver.\n"));
+    return EFI_DEVICE_ERROR;
+  }
+
+  //
+  // Show state of enabled timer
+  //
+  DEBUG_CODE (
+    //
+    // Wait for a few timer interrupts to fire before continuing
+    //
+    while (mNumTicks < 10);
+  );
+
+  //
+  // Install the Timer Architectural Protocol onto a new handle
+  //
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &mTimerHandle,
+                  &gEfiTimerArchProtocolGuid, &mTimer,
+                  NULL
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  return Status;
+}
diff --git a/OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf b/OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
new file mode 100644
index 000000000000..70bc0ef6b2ea
--- /dev/null
+++ b/OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
@@ -0,0 +1,52 @@
+## @file
+# Timer Architectural Protocol module using Local APIC Timer
+#
+# Copyright (c) 2011 - 2020, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = LocalApicTimerDxe
+  MODULE_UNI_FILE                = LocalApicTimerDxe.uni
+  FILE_GUID                      = 74EB4D00-E63E-11EA-8B6E-0800200C9A66
+  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           = X64
+#
+#
+
+[Sources]
+  LocalApicTimer.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  UefiCpuPkg/UefiCpuPkg.dec
+  OvmfPkg/OvmfPkg.dec
+
+[LibraryClasses]
+  PcdLib
+  DebugLib
+  UefiDriverEntryPoint
+  UefiBootServicesTableLib
+  BaseLib
+  LocalApicLib
+
+[Protocols]
+  gEfiTimerArchProtocolGuid                     ## PRODUCES
+  gEfiCpuArchProtocolGuid                       ## CONSUMES
+
+[Pcd]
+  gUefiOvmfPkgTokenSpaceGuid.PcdHpetLocalApicVector      ## CONSUMES
+  gUefiOvmfPkgTokenSpaceGuid.PcdHpetDefaultTimerPeriod   ## CONSUMES
+  gEfiMdePkgTokenSpaceGuid.PcdFSBClock
+  gUefiOvmfPkgTokenSpaceGuid.PcdTimerSelector
+
+[Depex]
+  gEfiCpuArchProtocolGuid
diff --git a/OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.uni b/OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.uni
new file mode 100644
index 000000000000..7525d9493858
--- /dev/null
+++ b/OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.uni
@@ -0,0 +1,13 @@
+// /** @file
+// Timer Architectural Protocol module using Local APIC Timer
+//
+// Copyright (c) 2011 - 2020, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT             #language en-US "Timer Architectural Protocol module using Local APIC Timer"
+
+#string STR_MODULE_DESCRIPTION          #language en-US "Timer Architectural Protocol module using Local APIC Timer."
diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index dda83d81695b..56714d3311ad 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -369,6 +369,15 @@
   ## The Tdx accept page size. 0x1000(4k),0x200000(2M)
   gUefiOvmfPkgTokenSpaceGuid.PcdTdxAcceptPageSize|0x1000|UINT64|0x5a
 
+  ## This PCD specifies the Local APIC Interrupt Vector for the HPET Timer.
+  # @Prompt HPET local APIC vector.
+  gUefiOvmfPkgTokenSpaceGuid.PcdHpetLocalApicVector|0x40|UINT8|0x5b
+
+  ## This PCD specifies the default period of the HPET Timer in 100 ns units.
+  #  The default value of 100000 100 ns units is the same as 10 ms.
+  # @Prompt Default period of HPET timer.
+  gUefiOvmfPkgTokenSpaceGuid.PcdHpetDefaultTimerPeriod|100000|UINT64|0x5c
+
 [PcdsDynamic, PcdsDynamicEx]
   gUefiOvmfPkgTokenSpaceGuid.PcdEmuVariableEvent|0|UINT64|2
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashVariablesEnable|FALSE|BOOLEAN|0x10
@@ -411,6 +420,11 @@
   ## TDX relocated Mailbox base address
   gUefiOvmfPkgTokenSpaceGuid.PcdTdRelocatedMailboxBase|0|UINT64|0x60
 
+  ## Timer selector
+  #  There are multiple timer in Ovmf. This PCD indicates which Timer is installed.
+  #  The default Timer is 8254 (0x0). See TimerSelector.h for more definition.
+  gUefiOvmfPkgTokenSpaceGuid.PcdTimerSelector|0|UINT32|0x61
+
 [PcdsFeatureFlag]
   gUefiOvmfPkgTokenSpaceGuid.PcdQemuBootOrderPciTranslation|TRUE|BOOLEAN|0x1c
   gUefiOvmfPkgTokenSpaceGuid.PcdQemuBootOrderMmioTranslation|FALSE|BOOLEAN|0x1d
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index 455e901c2eb8..a17d6603af0b 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -777,6 +777,10 @@
   OvmfPkg/8259InterruptControllerDxe/8259.inf
   UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
   UefiCpuPkg/CpuDxe/CpuDxe.inf
+  OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf {
+    <LibraryClasses>
+      LocalApicLib|UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf
+  }
   OvmfPkg/8254TimerDxe/8254Timer.inf
   OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
   OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
index bbd9303ab14f..716297e52aff 100644
--- a/OvmfPkg/OvmfPkgX64.fdf
+++ b/OvmfPkg/OvmfPkgX64.fdf
@@ -236,6 +236,7 @@ INF  MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
 INF  OvmfPkg/8259InterruptControllerDxe/8259.inf
 INF  UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
 INF  UefiCpuPkg/CpuDxe/CpuDxe.inf
+INF  OvmfPkg/LocalApicTimerDxe/LocalApicTimerDxe.inf
 INF  OvmfPkg/8254TimerDxe/8254Timer.inf
 INF  OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
 INF  OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
diff --git a/OvmfPkg/TdxDxe/TdxDxe.c b/OvmfPkg/TdxDxe/TdxDxe.c
index eecad8f6e050..fcfb972cc67c 100644
--- a/OvmfPkg/TdxDxe/TdxDxe.c
+++ b/OvmfPkg/TdxDxe/TdxDxe.c
@@ -23,6 +23,7 @@
 #include <Library/UefiLib.h>
 #include <Library/HobLib.h>
 #include <Protocol/Cpu.h>
+#include <Protocol/TimerSelector.h>
 #include <Library/UefiBootServicesTableLib.h>
 #include <IndustryStandard/Tdx.h>
 #include <IndustryStandard/IntelTdx.h>
@@ -131,6 +132,8 @@ TdxDxeEntryPoint (
     return EFI_UNSUPPORTED;
   }
 
+  PcdSet32S (PcdTimerSelector, TimerSelectorLocalApic);
+
   PlatformInfo = (EFI_HOB_PLATFORM_INFO *) GET_GUID_HOB_DATA (GuidHob);
 
   //
diff --git a/OvmfPkg/TdxDxe/TdxDxe.inf b/OvmfPkg/TdxDxe/TdxDxe.inf
index b77c6e5e9252..045c3c8c2ccc 100644
--- a/OvmfPkg/TdxDxe/TdxDxe.inf
+++ b/OvmfPkg/TdxDxe/TdxDxe.inf
@@ -60,3 +60,4 @@
   gUefiOvmfPkgTokenSpaceGuid.PcdTdRelocatedMailboxBase
   gUefiCpuPkgTokenSpaceGuid.PcdCpuLocalApicBaseAddress
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFdBaseAddress
+  gUefiOvmfPkgTokenSpaceGuid.PcdTimerSelector
-- 
2.29.2.windows.2


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

* Re: [edk2-devel] [PATCH V2 04/28] MdePkg: Add Tdx.h
  2021-10-05  3:39 ` [PATCH V2 04/28] MdePkg: Add Tdx.h Min Xu
@ 2021-10-12  7:48   ` Gerd Hoffmann
  0 siblings, 0 replies; 91+ messages in thread
From: Gerd Hoffmann @ 2021-10-12  7:48 UTC (permalink / raw)
  To: devel, min.m.xu; +Cc: Michael D Kinney, Liming Gao, Zhiguang Liu, Jiewen Yao

On Tue, Oct 05, 2021 at 11:39:15AM +0800, Min Xu wrote:
> 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: Jiewen Yao <jiewen.yao@intel.com>
> Signed-off-by: Min Xu <min.m.xu@intel.com>

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


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

* Re: [edk2-devel] [PATCH V2 05/28] MdePkg: Add TdxLib to wrap Tdx operations
  2021-10-05  3:39 ` [PATCH V2 05/28] MdePkg: Add TdxLib to wrap Tdx operations Min Xu
@ 2021-10-12  8:22   ` Gerd Hoffmann
  2021-10-13 12:13     ` Min Xu
  0 siblings, 1 reply; 91+ messages in thread
From: Gerd Hoffmann @ 2021-10-12  8:22 UTC (permalink / raw)
  To: devel, min.m.xu
  Cc: Michael D Kinney, Liming Gao, Zhiguang Liu, Brijesh Singh,
	Erdem Aktas, James Bottomley, Jiewen Yao, Tom Lendacky

> +// PageSize is mapped to PageLevel like below:
> +// 4KB - 0, 2MB - 1
> +UINT64  mTdxAcceptPageLevelMap[2] = {
> +  SIZE_4KB,
> +  SIZE_2MB

No 1G pages?

> +UINTN
> +GetGpaPageLevel (
> +  UINT64 PageSize

Uh, UINT32 is not enough?  Keep the door open for 512G pages?

> +{
> +  UINTN Index;
> +
> +  for (Index = 0; Index < sizeof (mTdxAcceptPageLevelMap) / sizeof (mTdxAcceptPageLevelMap[0]); Index++) {

There is an ARRAY_SIZE() macro, no need to open code the sizeof() trick.

> +    if (mTdxAcceptPageLevelMap[Index] == PageSize) {
> +      break;
> +    }
> +  }
> +
> +  return Index;
> +}

No error handling (invalid PageSize) here?

> +/**
> +  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.
> +  @param[in]  NumberOfPages     Number of the pages to be accepted.
> +  @param[in]  PageSize          GPA page size. Only accept 1G/2M/4K size.
> +
> +  @return EFI_SUCCESS           Accept successfully
> +  @return others                Indicate other errors
> +**/
> +EFI_STATUS
> +EFIAPI
> +TdAcceptPages (
> +  IN UINT64  StartAddress,
> +  IN UINT64  NumberOfPages,
> +  IN UINT64  PageSize
> +  )
> +{
> +  EFI_STATUS  Status;
> +  UINT64      Address;
> +  UINT64      TdxStatus;
> +  UINT64      Index;
> +  UINT64      GpaPageLevel;
> +  UINT64      PageSize2;
> +
> +  Address = StartAddress;
> +
> +  GpaPageLevel = (UINT64) GetGpaPageLevel (PageSize);

Why cast?

> +  if (GpaPageLevel > sizeof (mTdxAcceptPageLevelMap) / sizeof (mTdxAcceptPageLevelMap[0])) {
> +    DEBUG ((DEBUG_ERROR, "Accept page size must be 4K/2M. Invalid page size - 0x%llx\n", PageSize));

Ah.  Errors are catched here.  Well, no.  The check is wrong,
it should be ">=" not ">".

Better would be GetGpaPageLevel explicitly returning a specific value
(for example -1) on error.

> +  Status = EFI_SUCCESS;
> +  for (Index = 0; Index < NumberOfPages; Index++) {
> +    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++;

Hmm.  When this happens we have a bug somewhere, right?
So should this be an assert()?
Or should we at least log the address?

> +#define RTMR_COUNT                  4
> +#define TD_EXTEND_BUFFER_LEN        (64 + 64)
> +#define EXTEND_BUFFER_ADDRESS_MASK  0x3f
> +
> +
> +#pragma pack(16)
> +typedef struct {
> +  UINT8   Buffer[TD_EXTEND_BUFFER_LEN];
> +} TDX_EXTEND_BUFFER;
> +#pragma pack()
> +
> +UINT8               *mExtendBufferAddress = NULL;
> +TDX_EXTEND_BUFFER   mExtendBuffer;
> +
> +/**
> +  TD.RTMR.EXTEND requires 64B-aligned guest physical address of
> +  48B-extension data. In runtime we walk thru the Buffer to find
> +  out a 64B-aligned start address.

Can't you just use __attribute__((aligned(64))) for that?

take care,
  Gerd


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

* Re: [edk2-devel] [PATCH V2 06/28] MdePkg: Update BaseIoLibIntrinsicSev to support Tdx
  2021-10-05  3:39 ` [PATCH V2 06/28] MdePkg: Update BaseIoLibIntrinsicSev to support Tdx Min Xu
@ 2021-10-12 10:05   ` Gerd Hoffmann
  2021-10-13 13:40     ` Min Xu
  0 siblings, 1 reply; 91+ messages in thread
From: Gerd Hoffmann @ 2021-10-12 10:05 UTC (permalink / raw)
  To: devel, min.m.xu
  Cc: Michael D Kinney, Liming Gao, Zhiguang Liu, Brijesh Singh,
	Erdem Aktas, James Bottomley, Jiewen Yao, Tom Lendacky

On Tue, Oct 05, 2021 at 11:39:17AM +0800, Min Xu wrote:
> 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.

This monster patch needs splitting up.  At least into io + mmio + fifo.
Adding the tdx helper functions can be a separate patch too.

Calling CPUID should not be needed, we have a new fancy
ConfidentialComputing PCD for that now.

The new wrappers in IoLibFifo.c should also check for sev, so we have
something along the lines of ...

  switch (getpcd(cc)) {
  case tdx:
    TdxFifo(...)
    break;
  case sev:
    SevFifo(...)
    break;
  default:
    DefaultFifo(...)
    break;
  }

... instead of hiding the default case in IoFifoSev.nasm.

Maybe that's something to cleanup for amd (Brijesh?) beforehand, so the
structure is there already and the tdx patches just need to add the
"case tdx:" bits.

take care,
  Gerd
 


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

* Re: [edk2-devel] [PATCH V2 07/28] UefiCpuPkg: Support TDX in BaseXApicX2ApicLib
  2021-10-05  3:39 ` [PATCH V2 07/28] UefiCpuPkg: Support TDX in BaseXApicX2ApicLib Min Xu
@ 2021-10-12 10:15   ` Gerd Hoffmann
  2021-10-13 14:06     ` Min Xu
  2021-10-13  5:30   ` Ni, Ray
  1 sibling, 1 reply; 91+ messages in thread
From: Gerd Hoffmann @ 2021-10-12 10:15 UTC (permalink / raw)
  To: devel, min.m.xu
  Cc: Eric Dong, Ray Ni, Rahul Kumar, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky

  Hi,

> +  do {
> +    AsmCpuid (0, &LargestEax, &Ebx, &Ecx, &Edx);

Use ConfidentialComputing PCD ?

> +BOOLEAN
> +EFIAPI
> +AccessMsrNative (

I'd suggest to reverse the logic, i.e. have a AccessMsrTdxCall() which
returns true in case (a) tdx is active and (b) the msr is not on the
white list for native access ...

> +{
> +  UINT64    Val;
> +  UINT64    Status;
> +  if (!AccessMsrNative (MsrIndex) && BaseXApicIsTdxGuest ()) {

... the just use "if (AccessMsrTdxCall(MsrIndex)) { ..." here.

Beside that:  Are the apic msr registers the only ones which can
be accessed directly?

take care,
  Gerd


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

* Re: [edk2-devel] [PATCH V2 12/28] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VE exception
  2021-10-05  3:39 ` [PATCH V2 12/28] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VE exception Min Xu
@ 2021-10-12 10:27   ` Gerd Hoffmann
  2021-10-26  5:06     ` Min Xu
  0 siblings, 1 reply; 91+ messages in thread
From: Gerd Hoffmann @ 2021-10-12 10:27 UTC (permalink / raw)
  To: devel, min.m.xu
  Cc: Brijesh Singh, Erdem Aktas, James Bottomley, Jiewen Yao,
	Tom Lendacky, Eric Dong, Ray Ni, Rahul Kumar

  Hi,

> +  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.

Can please you explain in more detail why this is the case?

thanks,
  Gerd


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

* Re: [edk2-devel] [PATCH V2 13/28] UefiCpuPkg: Enable Tdx support in MpInitLib
  2021-10-05  3:39 ` [PATCH V2 13/28] UefiCpuPkg: Enable Tdx support in MpInitLib Min Xu
@ 2021-10-12 10:31   ` Gerd Hoffmann
  2021-10-14  0:27     ` Min Xu
  2021-10-13  6:01   ` Ni, Ray
  1 sibling, 1 reply; 91+ messages in thread
From: Gerd Hoffmann @ 2021-10-12 10:31 UTC (permalink / raw)
  To: devel, min.m.xu
  Cc: Brijesh Singh, Erdem Aktas, James Bottomley, Jiewen Yao,
	Tom Lendacky, Eric Dong, Ray Ni, Rahul Kumar

  Hi,

> +  do {
> +    AsmCpuid (0, &LargestEax, &Ebx, &Ecx, &Edx);

Again: this should use PCD.

take care,
  Gerd


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

* Re: [edk2-devel] [PATCH V2 14/28] OvmfPkg: Update SecEntry.nasm to support Tdx
  2021-10-05  3:39 ` [PATCH V2 14/28] OvmfPkg: Update SecEntry.nasm to support Tdx Min Xu
@ 2021-10-12 10:38   ` Gerd Hoffmann
  2021-10-14  0:55     ` Min Xu
  0 siblings, 1 reply; 91+ messages in thread
From: Gerd Hoffmann @ 2021-10-12 10:38 UTC (permalink / raw)
  To: devel, min.m.xu
  Cc: Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky

  Hi,

>  - AcceptPages:
>    To mitigate the performance impact of accepting pages in SEC phase on
>    BSP, BSP will parse memory resources and assign each AP the task of
>    accepting a subset of pages. This command may be called several times
>    until all memory resources are processed. In accepting pages, PageLevel
>    may fall back to smaller one if SIZE_MISMATCH error is returned.

Hmm, I'm wondering whenever it is useful to have this in the first place
with the longer-term plan to implement lazy on-demand acceptance.

take care,
  Gerd


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

* Re: [edk2-devel] [PATCH V2 24/28] OvmfPkg: Add TdxDxe driver
  2021-10-05  3:39 ` [PATCH V2 24/28] OvmfPkg: Add TdxDxe driver Min Xu
@ 2021-10-12 11:50   ` Gerd Hoffmann
  2021-10-18  8:38     ` Min Xu
  0 siblings, 1 reply; 91+ messages in thread
From: Gerd Hoffmann @ 2021-10-12 11:50 UTC (permalink / raw)
  To: devel, min.m.xu
  Cc: Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky

  Hi,

> Besides above features, TdxDxe driver will update the ACPI MADT
> Mutiprocessor Wakeup Table.

> +  ACPI_MADT_MPWK_STRUCT                               *MadtMpWk;

> +  NewBufferSize = 1                     * sizeof (*Madt) +
> +                  CpuCount              * sizeof (*LocalApic) +
> +                  1                     * sizeof (*IoApic) +
> +                  NUM_8259_IRQS         * sizeof (*Iso) +
> +                  1                     * sizeof (*LocalApicNmi);

+ sizeof(MadtMpWk)

> +  CopyMem (&(Madt->Header), AcpiTableBuffer, sizeof (EFI_ACPI_DESCRIPTION_HEADER));
> +  Madt->Header.Length    = (UINT32) NewBufferSize;
> +  Madt->LocalApicAddress = PcdGet32 (PcdCpuLocalApicBaseAddress);
> +  Madt->Flags            = EFI_ACPI_1_0_PCAT_COMPAT;
> +  Ptr = Madt + 1;

[ ... ]

You are not updating the MADT.  You create a new one from scratch.  Not
a good plan.  I think you should simply get the installed table, copy it
to a larger buffer and append the ACPI_MADT_MPWK_STRUCT to that.

take care,
  Gerd


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

* Re: [edk2-devel] [PATCH V2 25/28] OvmfPkg/BaseMemEncryptTdxLib: Add TDX helper library
  2021-10-05  3:39 ` [PATCH V2 25/28] OvmfPkg/BaseMemEncryptTdxLib: Add TDX helper library Min Xu
@ 2021-10-12 12:13   ` Gerd Hoffmann
  0 siblings, 0 replies; 91+ messages in thread
From: Gerd Hoffmann @ 2021-10-12 12:13 UTC (permalink / raw)
  To: devel, min.m.xu
  Cc: Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky

> +/**
> +  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.

Hmm, doesn't have tianocore a lib for such allocation pools?

> +  //
> +  // Link all pools into a list for easier track later.
> +  //

Seems to be never used.

> +/**
> + Disable Write Protect on pages marked as read-only.
> +**/
> +STATIC
> +VOID
> +DisableReadOnlyPageWriteProtect (

Why this is needed?

> +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;

No need to add that, there is OvmfPkg/Include/IndustryStandard/PageTable.h

take care,
  Gerd


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

* Re: [edk2-devel] [PATCH V2 27/28] OvmfPkg: Update IoMmuDxe to support TDX
  2021-10-05  3:39 ` [PATCH V2 27/28] OvmfPkg: Update IoMmuDxe to support TDX Min Xu
@ 2021-10-12 12:15   ` Gerd Hoffmann
  2021-10-14  2:11     ` Min Xu
  0 siblings, 1 reply; 91+ messages in thread
From: Gerd Hoffmann @ 2021-10-12 12:15 UTC (permalink / raw)
  To: devel, min.m.xu
  Cc: Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky

  Hi,

> +#define IO_MMU_LEGACY  0x0
> +#define IO_MMU_SEV     0x01
> +#define IO_MMU_TDX     0x02
> +
> +UINTN mIoMmuType = IO_MMU_LEGACY;

Yet another place where you should be able to just use the
ConfidentialComputing PCD.

take care,
  Gerd


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

* Re: [edk2-devel] [PATCH V2 28/28] OvmfPkg: Add LocalApicTimerDxe
  2021-10-05  3:39 ` [PATCH V2 28/28] OvmfPkg: Add LocalApicTimerDxe Min Xu
@ 2021-10-12 13:02   ` Gerd Hoffmann
  2021-10-14  5:20     ` Min Xu
  2021-10-25  7:37     ` Min Xu
  0 siblings, 2 replies; 91+ messages in thread
From: Gerd Hoffmann @ 2021-10-12 13:02 UTC (permalink / raw)
  To: devel, min.m.xu
  Cc: Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky

On Tue, Oct 05, 2021 at 11:39:39AM +0800, Min Xu wrote:
> RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
> 
> TDX guest supports LocalApicTimer. But in current OvmfPkg the supported
> timer is 8254TimerDxe. So gUefiOvmfPkgTokenSpaceGuid.PcdTimerSelector
> is introduced to select the running Timer. The Timer driver will check
> the TimerSelector in its entry point. The default Timer is 8254.

Hmm.

We already have a local apic timer implementation (XenTimerDxe).  Works
fine with kvm, microvm already uses that.  See commit 76602f45dcd9
("OvmfPkg/Microvm: use XenTimerDxe (lapic timer)").

So, first I'd suggest to just use that (maybe rename the thing to avoid
confusion as it isn't really Xen specific).

Next question is whenever there is a need for a runtime switch.  I doubt
it is possible to create a virtual machine without lapic, so switching
ovmf from 8254 (aka pit) to lapic unconditionally should work fine.
Quick smoke test (patch below) shows no obvious problems.

take care,
  Gerd

>From 948aaf555a864da1d6f2ccc8dddc7e22cefb76e1 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 12 Oct 2021 14:58:18 +0200
Subject: [PATCH 1/1] OvmfPkgX64: use lapic timer

---
 OvmfPkg/OvmfPkgX64.dsc | 4 ++--
 OvmfPkg/OvmfPkgX64.fdf | 3 +--
 2 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index 52f7598cf1c7..687aae6e3e68 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -620,6 +620,7 @@ [PcdsDynamicDefault]
   gUefiOvmfPkgTokenSpaceGuid.PcdPciMmio64Size|0x800000000
 !endif
 
+  gEfiMdePkgTokenSpaceGuid.PcdFSBClock|1000000000
   gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut|0
 
   # Set video resolution for text setup.
@@ -765,10 +766,9 @@ [Components]
   }
 
   MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
-  OvmfPkg/8259InterruptControllerDxe/8259.inf
   UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf
   UefiCpuPkg/CpuDxe/CpuDxe.inf
-  OvmfPkg/8254TimerDxe/8254Timer.inf
+  OvmfPkg/XenTimerDxe/XenTimerDxe.inf
   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 b6cc3cabdd69..9ca723dc8604 100644
--- a/OvmfPkg/OvmfPkgX64.fdf
+++ b/OvmfPkg/OvmfPkgX64.fdf
@@ -232,10 +232,9 @@ [FV.DXEFV]
 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/XenTimerDxe/XenTimerDxe.inf
 INF  OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf
 INF  OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf
 INF  MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
-- 
2.31.1


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

* Re: [edk2-devel] [PATCH V2 21/28] OvmfPkg: Update PlatformPei to support TDX
  2021-10-05  3:39 ` [PATCH V2 21/28] OvmfPkg: Update PlatformPei to support TDX Min Xu
@ 2021-10-13  4:49   ` Gerd Hoffmann
  2021-10-15  1:31     ` Yao, Jiewen
  0 siblings, 1 reply; 91+ messages in thread
From: Gerd Hoffmann @ 2021-10-13  4:49 UTC (permalink / raw)
  To: devel, min.m.xu
  Cc: Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky

  Hi,

> 2. Relocate mailbox
>   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 waiting for
>   further command.

Why is the mailbox relocated?  Are there any problems when simply
continuing to use the memfd page?

The memfd page location is known to qemu, so when not relocating the
mailbox the MADT update could be done on the host side.

take care,
  Gerd


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

* Re: [PATCH V2 07/28] UefiCpuPkg: Support TDX in BaseXApicX2ApicLib
  2021-10-05  3:39 ` [PATCH V2 07/28] UefiCpuPkg: Support TDX in BaseXApicX2ApicLib Min Xu
  2021-10-12 10:15   ` [edk2-devel] " Gerd Hoffmann
@ 2021-10-13  5:30   ` Ni, Ray
  2021-10-14  7:58     ` Min Xu
  1 sibling, 1 reply; 91+ messages in thread
From: Ni, Ray @ 2021-10-13  5:30 UTC (permalink / raw)
  To: Xu, Min M, devel@edk2.groups.io
  Cc: Dong, Eric, Kumar, Rahul1, Brijesh Singh, Erdem Aktas,
	James Bottomley, Yao, Jiewen, Tom Lendacky

Min,
Comments below:

-----Original Message-----
From: Xu, Min M <min.m.xu@intel.com> 
Sent: Tuesday, October 5, 2021 11:39 AM
To: devel@edk2.groups.io
Cc: Xu, Min M <min.m.xu@intel.com>; Dong, Eric <eric.dong@intel.com>; Ni, Ray <ray.ni@intel.com>; Kumar, Rahul1 <rahul1.kumar@intel.com>; Brijesh Singh <brijesh.singh@amd.com>; Erdem Aktas <erdemaktas@google.com>; James Bottomley <jejb@linux.ibm.com>; Yao, Jiewen <jiewen.yao@intel.com>; Tom Lendacky <thomas.lendacky@amd.com>
Subject: [PATCH V2 07/28] UefiCpuPkg: Support TDX in BaseXApicX2ApicLib

+**/
+BOOLEAN
+EFIAPI

1. EFIAPI is for public lib API. Is this a public API?

+BaseXApicIsTdxGuest (
+  VOID
+  )
+{
+  UINT32    Eax;
+  UINT32    Ebx;
+  UINT32    Ecx;
+  UINT32    Edx;
+  UINT32    LargestEax;
+
+  if (mBaseXApicTdxProbed) {
+    return mBaseXApicIsTdxEnabled;
+  }
+
+  mBaseXApicIsTdxEnabled = FALSE;

2. ApicLib can be used in pre-mem running directly in flash.
The global variable cannot be modified in that case.


+
+  do {
+    AsmCpuid (0, &LargestEax, &Ebx, &Ecx, &Edx);

+
+    if (Ebx != SIGNATURE_32 ('G', 'e', 'n', 'u')
+      || Edx != SIGNATURE_32 ('i', 'n', 'e', 'I')
+      || Ecx != SIGNATURE_32 ('n', 't', 'e', 'l')) {
+      break;
+    }
+
+    AsmCpuid (1, 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;
+    }


3. Can you use definition from MdePkg\Include\Register\Intel\Cpuid.h instead of hardcode 0, 1, 0x21, "Genu" and etc.?

+
+    mBaseXApicIsTdxEnabled = TRUE;

4. avoid relying on global variable for caching the result.

+
+  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:

5. Can you explain in the comments about  what spec says that above MSR can be accessed directly while others cannot?


+  UINT64    Val;
+  UINT64    Status;
+  if (!AccessMsrNative (MsrIndex) && BaseXApicIsTdxGuest ()) {

6. can we simplify the above check with " if (!AccessMsrNative (MsrIndex))"?
IsTdxGuest() can be called inside AccessMsrNative().

+UINT32
+EFIAPI

7. No EFIAPI please.

+ReadMsrReg32 (
+  IN UINT32 MsrIndex
+  )
+{
+  UINT64    Val;
+  UINT64    Status;
+  if (!AccessMsrNative (MsrIndex) && BaseXApicIsTdxGuest ()) {
+    Status = TdVmCall (TDVMCALL_RDMSR, (UINT64) MsrIndex, 0, 0, 0, &Val);
+    if (Status != 0) {
+      TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
+    }
+  } else {
+    Val = AsmReadMsr32 (MsrIndex);
+  }
+  return (UINT32)(UINTN) Val;

8. Can you directly call ReadMsrReg64()?


+VOID
+EFIAPI
+WriteMsrReg32 (
+  IN UINT32 MsrIndex,
+  IN UINT32 Val
+  )
+{
+  UINT64    Status;
+  if (!AccessMsrNative (MsrIndex) && BaseXApicIsTdxGuest ()) {
+    Status = TdVmCall (TDVMCALL_WRMSR, (UINT64) MsrIndex, (UINT64) Val, 0, 0, 0);
+    if (Status != 0) {
+      DEBUG((DEBUG_ERROR, "WriteMsrReg32 returned failure. Status=0x%llx\n", Status));
+      TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
+    }
+  } else {
+    AsmWriteMsr32 (MsrIndex, Val);

8. Can you directly call WriteMsrReg64()?

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

9. I prefer to use "LocalApicLibReadMsr64()". It indicates two meanings:
    a. it's a local function which can be found within this lib
    b. it's consistent with "AsmReadMsr64".



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

* Re: [PATCH V2 13/28] UefiCpuPkg: Enable Tdx support in MpInitLib
  2021-10-05  3:39 ` [PATCH V2 13/28] UefiCpuPkg: Enable Tdx support in MpInitLib Min Xu
  2021-10-12 10:31   ` [edk2-devel] " Gerd Hoffmann
@ 2021-10-13  6:01   ` Ni, Ray
  2021-10-14  8:22     ` Min Xu
  1 sibling, 1 reply; 91+ messages in thread
From: Ni, Ray @ 2021-10-13  6:01 UTC (permalink / raw)
  To: Xu, Min M, devel@edk2.groups.io
  Cc: Brijesh Singh, Erdem Aktas, James Bottomley, Yao, Jiewen,
	Tom Lendacky, Dong, Eric, Kumar, Rahul1

Min,
The change is to provide a totally different MP service in TDX case.
It makes the MpInitLib more complicated.

How about?
1. Change CpuMpPei/CpuMpDxe to return directly in TDX case.
2. Add new TdxCpuMpPei/TdxCpuMpDxe to provide a new set simple MP service in TDX case.

This makes the whole code easier to understand.

Thanks,
Ray

-----Original Message-----
From: Xu, Min M <min.m.xu@intel.com> 
Sent: Tuesday, October 5, 2021 11:39 AM
To: devel@edk2.groups.io
Cc: Xu, Min M <min.m.xu@intel.com>; Brijesh Singh <brijesh.singh@amd.com>; Erdem Aktas <erdemaktas@google.com>; James Bottomley <jejb@linux.ibm.com>; Yao, Jiewen <jiewen.yao@intel.com>; Tom Lendacky <thomas.lendacky@amd.com>; Dong, Eric <eric.dong@intel.com>; Ni, Ray <ray.ni@intel.com>; Kumar, Rahul1 <rahul1.kumar@intel.com>
Subject: [PATCH V2 13/28] UefiCpuPkg: Enable Tdx support in MpInitLib

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>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf |   4 +
 UefiCpuPkg/Library/MpInitLib/DxeMpLib.c       |  14 +-
 UefiCpuPkg/Library/MpInitLib/MpIntelTdx.h     | 107 ++++++++++
 UefiCpuPkg/Library/MpInitLib/MpLib.c          |  26 +++
 UefiCpuPkg/Library/MpInitLib/MpLibTdx.c       | 186 ++++++++++++++++++
 UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c   | 117 +++++++++++
 UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf |   4 +
 .../Library/MpInitLib/X64/IntelTdcall.nasm    | 120 +++++++++++
 8 files changed, 577 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
 create mode 100644 UefiCpuPkg/Library/MpInitLib/X64/IntelTdcall.nasm

diff --git a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
index d34419c2a524..084e025564ef 100644
--- a/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
@@ -22,10 +22,13 @@
 #
 
 [Sources.IA32]
+  MpLibTdxNull.c
   Ia32/MpFuncs.nasm
 
 [Sources.X64]
+  MpLibTdx.c
   X64/MpFuncs.nasm
+  X64/IntelTdcall.nasm
 
 [Sources.common]
   MpEqu.inc
@@ -33,6 +36,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 93fc63bf93e3..b7275db3d564 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,7 +16,6 @@
 #include <Library/VmgExitLib.h>
 #include <Register/Amd/Fam17Msr.h>
 #include <Register/Amd/Ghcb.h>
-
 #include <Protocol/Timer.h>
 
 #define  AP_SAFE_STACK_SIZE    128
@@ -801,6 +801,10 @@ MpInitLibStartupThisAP (  {
   EFI_STATUS              Status;
 
+  if (MpTdxIsEnabled ()) {
+    return EFI_UNSUPPORTED;
+  }
+
   //
   // temporarily stop checkAllApsStatus for avoid resource dead-lock.
   //
@@ -857,6 +861,10 @@ MpInitLibSwitchBSP (
   EFI_TIMER_ARCH_PROTOCOL      *Timer;
   UINT64                       TimerPeriod;
 
+  if (MpTdxIsEnabled ()) {
+    return EFI_UNSUPPORTED;
+  }
+
   TimerPeriod = 0;
   //
   // Locate Timer Arch Protocol
@@ -930,6 +938,10 @@ MpInitLibEnableDisableAP (
   EFI_STATUS     Status;
   BOOLEAN        TempStopCheckState;
 
+  if (MpTdxIsEnabled ()) {
+    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..59bd739eed22
--- /dev/null
+++ b/UefiCpuPkg/Library/MpInitLib/MpIntelTdx.h
@@ -0,0 +1,107 @@
+/** @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
+  );
+
+/**
+  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
+**/
+EFI_STATUS
+EFIAPI
+MpTdCall (
+  IN UINT64           Leaf,
+  IN UINT64           Arg1,
+  IN UINT64           Arg2,
+  IN UINT64           Arg3,
+  IN OUT VOID         *Results
+  );
+
+/**
+  Whether Intel TDX is enabled.
+
+  @return TRUE    TDX enabled
+  @return FALSE   TDX not enabled
+**/
+BOOLEAN
+EFIAPI
+MpTdxIsEnabled (
+  VOID
+  );
+
+#endif
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c
index b9a06747edbf..d03ad8ff483e 100644
--- a/UefiCpuPkg/Library/MpInitLib/MpLib.c
+++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -9,6 +9,7 @@
 **/
 
 #include "MpLib.h"
+#include "MpIntelTdx.h"
 #include <Library/VmgExitLib.h>
 #include <Register/Amd/Fam17Msr.h>
 #include <Register/Amd/Ghcb.h>
@@ -1965,6 +1966,10 @@ MpInitLibInitialize (
   UINTN                    BackupBufferAddr;
   UINTN                    ApIdtBase;
 
+  if (MpTdxIsEnabled ()) {
+    return EFI_SUCCESS;
+  }
+
   OldCpuMpData = GetCpuMpDataFromGuidedHob ();
   if (OldCpuMpData == NULL) {
     MaxLogicalProcessorNumber = PcdGet32(PcdCpuMaxLogicalProcessorNumber);
@@ -2215,6 +2220,10 @@ MpInitLibGetProcessorInfo (
   CPU_INFO_IN_HOB        *CpuInfoInHob;
   UINTN                  OriginalProcessorNumber;
 
+  if (MpTdxIsEnabled ()) {
+    return TdxMpInitLibGetProcessorInfo (ProcessorNumber, 
+ ProcessorInfoBuffer, HealthData);  }
+
   CpuMpData = GetCpuMpData ();
   CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;
 
@@ -2446,6 +2455,10 @@ EnableDisableApWorker (
   CPU_MP_DATA               *CpuMpData;
   UINTN                     CallerNumber;
 
+  if (MpTdxIsEnabled ()) {
+    return EFI_UNSUPPORTED;
+  }
+
   CpuMpData = GetCpuMpData ();
 
   //
@@ -2506,6 +2519,11 @@ MpInitLibWhoAmI (
     return EFI_INVALID_PARAMETER;
   }
 
+  if (MpTdxIsEnabled ()) {
+    *ProcessorNumber = 0;
+    return EFI_SUCCESS;
+  }
+
   CpuMpData = GetCpuMpData ();
 
   return GetProcessorNumber (CpuMpData, ProcessorNumber); @@ -2544,6 +2562,10 @@ MpInitLibGetNumberOfProcessors (
   UINTN                   EnabledProcessorNumber;
   UINTN                   Index;
 
+  if (MpTdxIsEnabled ()) {
+    return TdxMpInitLibGetNumberOfProcessors(NumberOfProcessors, 
+ NumberOfEnabledProcessors);  }
+
   CpuMpData = GetCpuMpData ();
 
   if ((NumberOfProcessors == NULL) && (NumberOfEnabledProcessors == NULL)) { @@ -2629,6 +2651,10 @@ StartupAllCPUsWorker (
   BOOLEAN                 HasEnabledAp;
   CPU_STATE               ApState;
 
+  if (MpTdxIsEnabled ()) {
+    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..d8bd4eb65d25
--- /dev/null
+++ b/UefiCpuPkg/Library/MpInitLib/MpLibTdx.c
@@ -0,0 +1,186 @@
+/** @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>
+
+BOOLEAN mMpTdxEnabled = FALSE;
+BOOLEAN mMpTdxProbed = FALSE;
+
+/**
+  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 = MpTdCall(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 = MpTdCall(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;
+}
+
+/**
+  Whether Intel TDX is enabled.
+
+  @return TRUE    TDX enabled
+  @return FALSE   TDX not enabled
+**/
+BOOLEAN
+EFIAPI
+MpTdxIsEnabled (
+  VOID
+  )
+{
+  UINT32    Eax;
+  UINT32    Ebx;
+  UINT32    Ecx;
+  UINT32    Edx;
+  UINT32    LargestEax;
+
+  if (mMpTdxProbed) {
+    return mMpTdxEnabled;
+  }
+
+  mMpTdxEnabled = FALSE;
+
+  do {
+    AsmCpuid (0, &LargestEax, &Ebx, &Ecx, &Edx);
+
+    if (Ebx != SIGNATURE_32 ('G', 'e', 'n', 'u')
+      || Edx != SIGNATURE_32 ('i', 'n', 'e', 'I')
+      || Ecx != SIGNATURE_32 ('n', 't', 'e', 'l')) {
+      break;
+    }
+
+    AsmCpuid (1, 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;
+    }
+
+    mMpTdxEnabled = TRUE;
+  }while (FALSE);
+
+  mMpTdxProbed = TRUE;
+
+  return mMpTdxEnabled;
+}
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c b/UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c
new file mode 100644
index 000000000000..f9cfedf01240
--- /dev/null
+++ b/UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c
@@ -0,0 +1,117 @@
+/** @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;
+}
+
+/**
+  Whether Intel TDX is enabled.
+
+  @return TRUE    TDX enabled
+  @return FALSE   TDX not enabled
+**/
+BOOLEAN
+EFIAPI
+MpTdxIsEnabled (
+  VOID
+  )
+{
+  return FALSE;
+}
+
+/**
+  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
+**/
+EFI_STATUS
+EFIAPI
+MpTdCall (
+  IN UINT64           Leaf,
+  IN UINT64           Arg1,
+  IN UINT64           Arg2,
+  IN UINT64           Arg3,
+  IN OUT VOID         *Results
+  )
+{
+  return EFI_UNSUPPORTED;
+}
diff --git a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
index 36fcb96b5852..b48dab2b1537 100644
--- a/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
+++ b/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
@@ -22,10 +22,13 @@
 #
 
 [Sources.IA32]
+  MpLibTdxNull.c
   Ia32/MpFuncs.nasm
 
 [Sources.X64]
+  MpLibTdx.c
   X64/MpFuncs.nasm
+  X64/IntelTdcall.nasm
 
 [Sources.common]
   MpEqu.inc
@@ -33,6 +36,7 @@
   MpLib.c
   MpLib.h
   Microcode.c
+  MpIntelTdx.h
 
 [Packages]
   MdePkg/MdePkg.dec
diff --git a/UefiCpuPkg/Library/MpInitLib/X64/IntelTdcall.nasm b/UefiCpuPkg/Library/MpInitLib/X64/IntelTdcall.nasm
new file mode 100644
index 000000000000..5e98557d5590
--- /dev/null
+++ b/UefiCpuPkg/Library/MpInitLib/X64/IntelTdcall.nasm
@@ -0,0 +1,120 @@
+;----------------------------------------------------------------------
+--------
+;*
+;* 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)
+
+%macro tdcall_regs_preamble 2
+    mov rax, %1
+
+    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
+
+;  MpTdCall (
+;    UINT64  Leaf,    // Rcx
+;    UINT64  P1,      // Rdx
+;    UINT64  P2,      // R8
+;    UINT64  P3,      // R9
+;    UINT64  Results, // rsp + 0x28
+;    )
+global ASM_PFX(MpTdCall)
+ASM_PFX(MpTdCall):
+       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
--
2.29.2.windows.2


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

* Re: [edk2-devel] [PATCH V2 05/28] MdePkg: Add TdxLib to wrap Tdx operations
  2021-10-12  8:22   ` [edk2-devel] " Gerd Hoffmann
@ 2021-10-13 12:13     ` Min Xu
  2021-10-14  5:30       ` Gerd Hoffmann
  0 siblings, 1 reply; 91+ messages in thread
From: Min Xu @ 2021-10-13 12:13 UTC (permalink / raw)
  To: Gerd Hoffmann, devel@edk2.groups.io
  Cc: Kinney, Michael D, Liming Gao, Liu, Zhiguang, Brijesh Singh,
	Erdem Aktas, James Bottomley, Yao, Jiewen, Tom Lendacky

On October 12, 2021 4:22 PM, Gerd Hoffmann wrote:
> > +// PageSize is mapped to PageLevel like below:
> > +// 4KB - 0, 2MB - 1
> > +UINT64  mTdxAcceptPageLevelMap[2] = {
> > +  SIZE_4KB,
> > +  SIZE_2MB
> 
> No 1G pages?
TDX: https://software.intel.com/content/dam/develop/external/us/en/documents/tdx-module-1.0-public-spec-v0.931.pdf 
Theoretically there are 3 AcceptPageSize (4KB/2MB/1GB). But currently only 4KB and 2MB are supported. See section 22.3.2.
> 
> > +UINTN
> > +GetGpaPageLevel (
> > +  UINT64 PageSize
> 
> Uh, UINT32 is not enough?  Keep the door open for 512G pages?
Thanks for reminder. UINT32 is enough. It will be updated in next version.
> 
> > +{
> > +  UINTN Index;
> > +
> > +  for (Index = 0; Index < sizeof (mTdxAcceptPageLevelMap) / sizeof
> > + (mTdxAcceptPageLevelMap[0]); Index++) {
> 
> There is an ARRAY_SIZE() macro, no need to open code the sizeof() trick.
Thanks for reminder. It will be updated in next version.
> 
> > +    if (mTdxAcceptPageLevelMap[Index] == PageSize) {
> > +      break;
> > +    }
> > +  }
> > +
> > +  return Index;
> > +}
> 
> No error handling (invalid PageSize) here?
> 
> > +/**
> > +  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.
> > +  @param[in]  NumberOfPages     Number of the pages to be accepted.
> > +  @param[in]  PageSize          GPA page size. Only accept 1G/2M/4K size.
> > +
> > +  @return EFI_SUCCESS           Accept successfully
> > +  @return others                Indicate other errors
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +TdAcceptPages (
> > +  IN UINT64  StartAddress,
> > +  IN UINT64  NumberOfPages,
> > +  IN UINT64  PageSize
> > +  )
> > +{
> > +  EFI_STATUS  Status;
> > +  UINT64      Address;
> > +  UINT64      TdxStatus;
> > +  UINT64      Index;
> > +  UINT64      GpaPageLevel;
> > +  UINT64      PageSize2;
> > +
> > +  Address = StartAddress;
> > +
> > +  GpaPageLevel = (UINT64) GetGpaPageLevel (PageSize);
> 
> Why cast?
Thanks for reminder. The cast is not needed. It will be updated in next version.
> 
> > +  if (GpaPageLevel > sizeof (mTdxAcceptPageLevelMap) / sizeof
> (mTdxAcceptPageLevelMap[0])) {
> > +    DEBUG ((DEBUG_ERROR, "Accept page size must be 4K/2M. Invalid
> > + page size - 0x%llx\n", PageSize));
> 
> Ah.  Errors are catched here.  Well, no.  The check is wrong, it should be ">=" not
> ">".
> 
> Better would be GetGpaPageLevel explicitly returning a specific value (for
> example -1) on error.
You're right. A dumb error ... It will be fixed in the next version.
> 
> > +  Status = EFI_SUCCESS;
> > +  for (Index = 0; Index < NumberOfPages; Index++) {
> > +    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++;
> 
> Hmm.  When this happens we have a bug somewhere, right?
> So should this be an assert()?
> Or should we at least log the address?
ASSERT() is not necessary because the code can still run. But we should log the address which has been already accepted.
It  will be added in the next version.
> 
> > +#define RTMR_COUNT                  4
> > +#define TD_EXTEND_BUFFER_LEN        (64 + 64)
> > +#define EXTEND_BUFFER_ADDRESS_MASK  0x3f
> > +
> > +
> > +#pragma pack(16)
> > +typedef struct {
> > +  UINT8   Buffer[TD_EXTEND_BUFFER_LEN];
> > +} TDX_EXTEND_BUFFER;
> > +#pragma pack()
> > +
> > +UINT8               *mExtendBufferAddress = NULL;
> > +TDX_EXTEND_BUFFER   mExtendBuffer;
> > +
> > +/**
> > +  TD.RTMR.EXTEND requires 64B-aligned guest physical address of
> > +  48B-extension data. In runtime we walk thru the Buffer to find
> > +  out a 64B-aligned start address.
> 
> Can't you just use __attribute__((aligned(64))) for that?
> 
In the PoC of TDVF I had thought about it. But at last I gave up such solution. The reasons are:
1) OVMF/TDVF supports both GCC and VS2019 tool chain. __attribute__((aligned(64))) is for GCC. Its counterpart of VS2019 Tool chain is __declspec(align(x)).
2) There is the limitation of /ALIGN:32 in the build scripts which means aligned 64 exceeds  the /ALIGN 32, unless /ALIGN is updated to 64.
That's why the current solution is used.

Thanks!
Min


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

* Re: [edk2-devel] [PATCH V2 06/28] MdePkg: Update BaseIoLibIntrinsicSev to support Tdx
  2021-10-12 10:05   ` [edk2-devel] " Gerd Hoffmann
@ 2021-10-13 13:40     ` Min Xu
  2021-10-14  5:37       ` Gerd Hoffmann
  0 siblings, 1 reply; 91+ messages in thread
From: Min Xu @ 2021-10-13 13:40 UTC (permalink / raw)
  To: Gerd Hoffmann, devel@edk2.groups.io
  Cc: Kinney, Michael D, Liming Gao, Liu, Zhiguang, Brijesh Singh,
	Erdem Aktas, James Bottomley, Yao, Jiewen, Tom Lendacky

On October 12, 2021 6:06 PM, Gerd Hoffmann wrote:
> On Tue, Oct 05, 2021 at 11:39:17AM +0800, Min Xu wrote:
> > 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.
> 
> This monster patch needs splitting up.  At least into io + mmio + fifo.
> Adding the tdx helper functions can be a separate patch too.
Ok, this patch will be split up into io+mmio+fifo in the next version.
> 
> Calling CPUID should not be needed, we have a new fancy
> ConfidentialComputing PCD for that now.
The gUefiCpuPkgTokenSpaceGuid.PcdConfidentialComputingGuestAttr is defined in UefiCpuPkg. While BaseIoLibIntrinsicSev is in MdePkg.
If the ConfidentialComputing PCD is used, then UefiCpuPkg has to be included in BaseIoLibIntrinsicSev.inf. 
I check all the *.inf under MdePkg but no one *.inf include UefiCpuPkg. 
I am not sure if UefiCpuPkg can be included in BaseIoLibIntrinsicSev.inf.
> 
> The new wrappers in IoLibFifo.c should also check for sev, so we have
> something along the lines of ...
> 
>   switch (getpcd(cc)) {
>   case tdx:
>     TdxFifo(...)
>     break;
>   case sev:
>     SevFifo(...)
>     break;
>   default:
>     DefaultFifo(...)
>     break;
>   }
> 
> ... instead of hiding the default case in IoFifoSev.nasm.
> 
> Maybe that's something to cleanup for amd (Brijesh?) beforehand, so the
> structure is there already and the tdx patches just need to add the "case tdx:"
> bits.
Tdx patches can first use above structure. AMD can update it later. Either way is ok.

Thanks!
Min

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

* Re: [edk2-devel] [PATCH V2 07/28] UefiCpuPkg: Support TDX in BaseXApicX2ApicLib
  2021-10-12 10:15   ` [edk2-devel] " Gerd Hoffmann
@ 2021-10-13 14:06     ` Min Xu
  0 siblings, 0 replies; 91+ messages in thread
From: Min Xu @ 2021-10-13 14:06 UTC (permalink / raw)
  To: Gerd Hoffmann, devel@edk2.groups.io
  Cc: Dong, Eric, Ni, Ray, Kumar, Rahul1, Brijesh Singh, Erdem Aktas,
	James Bottomley, Yao, Jiewen, Tom Lendacky

On October 12, 2021 6:16 PM, Gerd Hoffman wrote:
>   Hi,
> 
> > +  do {
> > +    AsmCpuid (0, &LargestEax, &Ebx, &Ecx, &Edx);
> 
> Use ConfidentialComputing PCD ?
BaseXApicX2ApicLib (LocalApicLib) is included by the drivers/libs not only in DXE phase, but also in SEC/PEI. For example, SecPeiCpuExceptionHandlerLib is included in SEC/PEI_CORE/PEIM. In SEC phase ConfidentialComputing PCD has not been set. So it cannot be used in SEC phase to determine if it is TDX guest or not.
That's why CPUID is used in BaseXApicX2ApicLib so that it works in SEC/PEI/DXE phases.
> 
> > +BOOLEAN
> > +EFIAPI
> > +AccessMsrNative (
> 
> I'd suggest to reverse the logic, i.e. have a AccessMsrTdxCall() which returns
> true in case (a) tdx is active and (b) the msr is not on the white list for native
> access ...
> 
> > +{
> > +  UINT64    Val;
> > +  UINT64    Status;
> > +  if (!AccessMsrNative (MsrIndex) && BaseXApicIsTdxGuest ()) {
> 
> ... the just use "if (AccessMsrTdxCall(MsrIndex)) { ..." here.
> 
Ok, It will be updated in the next version.
> Beside that:  Are the apic msr registers the only ones which can be accessed
> directly?
TDX: https://software.intel.com/content/dam/develop/external/us/en/documents/tdx-module-1.0-public-spec-v0.931.pdf
Section 10.7 MSR Handling
Section 18.1 Table 18.2 MSR Virtualization 
X2APIC MSR Registers which can be accessed natively is in above table.
> 
Thanks!
Min

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

* Re: [edk2-devel] [PATCH V2 13/28] UefiCpuPkg: Enable Tdx support in MpInitLib
  2021-10-12 10:31   ` [edk2-devel] " Gerd Hoffmann
@ 2021-10-14  0:27     ` Min Xu
  2021-10-14  6:04       ` Gerd Hoffmann
  0 siblings, 1 reply; 91+ messages in thread
From: Min Xu @ 2021-10-14  0:27 UTC (permalink / raw)
  To: devel@edk2.groups.io, kraxel@redhat.com
  Cc: Brijesh Singh, Erdem Aktas, James Bottomley, Yao, Jiewen,
	Tom Lendacky, Dong, Eric, Ni, Ray, Kumar, Rahul1

On October 12, 2021 6:32 PM, Gerd Hoffman wrote:
>   Hi,
> 
> > +  do {
> > +    AsmCpuid (0, &LargestEax, &Ebx, &Ecx, &Edx);
> 
> Again: this should use PCD.
ConfidentialComputing PCD is set in PlatformPei. So any check of this PCD should be after PlatformPei.
MpInitLib will be included in CpuMpPei. So if PCD is checked in MpInitLib, then we must assume CpuMpPei is called after PlatformPei.
In current OVMF, CpuMpPei is called after PlatforPei. But I am not sure if it is always the case. Can we have such assumption?
Based on above consideration, CPUID is used to probe if it is Tdx guest.
> 
> take care,
>   Gerd
> 
> 
> 
> 
> 


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

* Re: [edk2-devel] [PATCH V2 14/28] OvmfPkg: Update SecEntry.nasm to support Tdx
  2021-10-12 10:38   ` [edk2-devel] " Gerd Hoffmann
@ 2021-10-14  0:55     ` Min Xu
  2021-10-14  6:51       ` Gerd Hoffmann
  0 siblings, 1 reply; 91+ messages in thread
From: Min Xu @ 2021-10-14  0:55 UTC (permalink / raw)
  To: Gerd Hoffmann, devel@edk2.groups.io
  Cc: Ard Biesheuvel, Justen, Jordan L, Brijesh Singh, Erdem Aktas,
	James Bottomley, Yao, Jiewen, Tom Lendacky

On October 12, 2021 6:39 PM, Gerd Hoffmann wrote:
>   Hi,
> 
> >  - AcceptPages:
> >    To mitigate the performance impact of accepting pages in SEC phase on
> >    BSP, BSP will parse memory resources and assign each AP the task of
> >    accepting a subset of pages. This command may be called several times
> >    until all memory resources are processed. In accepting pages, PageLevel
> >    may fall back to smaller one if SIZE_MISMATCH error is returned.
> 
> Hmm, I'm wondering whenever it is useful to have this in the first place with
> the longer-term plan to implement lazy on-demand acceptance.
To mitigate the performance impact of accepting pages, there are 3 ways.
1. Big accept page size.
2. Accept the pages by BSP and APs together.
3. Lazy on-demand acceptance.
>From the perspective of implementation complexity, 1 < 2 < 3.
Lazy on-demand acceptance need the update not only in TDVF, but also in Guest kernel. More investigation shows it also impacts the grub and memory management in EDK2.
>From the perspective of performance improvement, 2M accept page size + BSP/AP together, can improve the performance a lot. 
Based on above consideration, in current TDVF upstream, 1 + 2 are the ways to mitigate the performance impact.
Upstream of 3 is in the future plan.

Thanks!
Min

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

* Re: [edk2-devel] [PATCH V2 27/28] OvmfPkg: Update IoMmuDxe to support TDX
  2021-10-12 12:15   ` [edk2-devel] " Gerd Hoffmann
@ 2021-10-14  2:11     ` Min Xu
  0 siblings, 0 replies; 91+ messages in thread
From: Min Xu @ 2021-10-14  2:11 UTC (permalink / raw)
  To: Gerd Hoffmann, devel@edk2.groups.io
  Cc: Ard Biesheuvel, Justen, Jordan L, Brijesh Singh, Erdem Aktas,
	James Bottomley, Yao, Jiewen, Tom Lendacky

On October 12, 2021 8:16 PM, Gerd Hoffmann wrote:
>   Hi,
> 
> > +#define IO_MMU_LEGACY  0x0
> > +#define IO_MMU_SEV     0x01
> > +#define IO_MMU_TDX     0x02
> > +
> > +UINTN mIoMmuType = IO_MMU_LEGACY;
> 
> Yet another place where you should be able to just use the
> ConfidentialComputing PCD.
Thanks for reminder. It will be updated in next version.

Thanks
Min

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

* Re: [edk2-devel] [PATCH V2 28/28] OvmfPkg: Add LocalApicTimerDxe
  2021-10-12 13:02   ` [edk2-devel] " Gerd Hoffmann
@ 2021-10-14  5:20     ` Min Xu
  2021-10-15  1:21       ` Yao, Jiewen
  2021-10-25  7:37     ` Min Xu
  1 sibling, 1 reply; 91+ messages in thread
From: Min Xu @ 2021-10-14  5:20 UTC (permalink / raw)
  To: devel@edk2.groups.io, kraxel@redhat.com
  Cc: Ard Biesheuvel, Justen, Jordan L, Brijesh Singh, Erdem Aktas,
	James Bottomley, Yao, Jiewen, Tom Lendacky

On October 12, 2021 9:02 PM, Gerd Hoffmann wrote:
> On Tue, Oct 05, 2021 at 11:39:39AM +0800, Min Xu wrote:
> > RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
> >
> > TDX guest supports LocalApicTimer. But in current OvmfPkg the
> > supported timer is 8254TimerDxe. So
> > gUefiOvmfPkgTokenSpaceGuid.PcdTimerSelector
> > is introduced to select the running Timer. The Timer driver will check
> > the TimerSelector in its entry point. The default Timer is 8254.
> 
> Hmm.
> 
> We already have a local apic timer implementation (XenTimerDxe).  Works fine
> with kvm, microvm already uses that.  See commit 76602f45dcd9
> ("OvmfPkg/Microvm: use XenTimerDxe (lapic timer)").
> 
> So, first I'd suggest to just use that (maybe rename the thing to avoid confusion
> as it isn't really Xen specific).
Thanks for reminder. Let me first do some more investigation about the XenTimerDxe. It will be better to use an existing lapic timer than introducing a new one.
> 
> Next question is whenever there is a need for a runtime switch.  I doubt it is
> possible to create a virtual machine without lapic, so switching ovmf from 8254
> (aka pit) to lapic unconditionally should work fine.
> Quick smoke test (patch below) shows no obvious problems.
Let me do some more investigation.
> 

Thanks.
Min

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

* Re: [edk2-devel] [PATCH V2 05/28] MdePkg: Add TdxLib to wrap Tdx operations
  2021-10-13 12:13     ` Min Xu
@ 2021-10-14  5:30       ` Gerd Hoffmann
  2021-10-22  2:06         ` Min Xu
  0 siblings, 1 reply; 91+ messages in thread
From: Gerd Hoffmann @ 2021-10-14  5:30 UTC (permalink / raw)
  To: Xu, Min M
  Cc: devel@edk2.groups.io, Kinney, Michael D, Liming Gao,
	Liu, Zhiguang, Brijesh Singh, Erdem Aktas, James Bottomley,
	Yao, Jiewen, Tom Lendacky

  Hi,

> > > +UINT8               *mExtendBufferAddress = NULL;
> > > +TDX_EXTEND_BUFFER   mExtendBuffer;
> > > +
> > > +/**
> > > +  TD.RTMR.EXTEND requires 64B-aligned guest physical address of
> > > +  48B-extension data. In runtime we walk thru the Buffer to find
> > > +  out a 64B-aligned start address.
> > 
> > Can't you just use __attribute__((aligned(64))) for that?
> > 
> In the PoC of TDVF I had thought about it. But at last I gave up such solution. The reasons are:
> 1) OVMF/TDVF supports both GCC and VS2019 tool chain. __attribute__((aligned(64))) is for GCC. Its counterpart of VS2019 Tool chain is __declspec(align(x)).
> 2) There is the limitation of /ALIGN:32 in the build scripts which means aligned 64 exceeds  the /ALIGN 32, unless /ALIGN is updated to 64.
> That's why the current solution is used.

MdePkg/Include/Base.h has a bunch of ALIGN_* macros to do the math for
you, which should simplify this alot.  I'd suggest to also drop the
mExtendBufferAddress and the function calculating it.  Just use the
macro instead when needed.

take care,
  Gerd


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

* Re: [edk2-devel] [PATCH V2 06/28] MdePkg: Update BaseIoLibIntrinsicSev to support Tdx
  2021-10-13 13:40     ` Min Xu
@ 2021-10-14  5:37       ` Gerd Hoffmann
  2021-10-14  6:24         ` Min Xu
  2021-10-22  5:23         ` Min Xu
  0 siblings, 2 replies; 91+ messages in thread
From: Gerd Hoffmann @ 2021-10-14  5:37 UTC (permalink / raw)
  To: Xu, Min M
  Cc: devel@edk2.groups.io, Kinney, Michael D, Liming Gao,
	Liu, Zhiguang, Brijesh Singh, Erdem Aktas, James Bottomley,
	Yao, Jiewen, Tom Lendacky

  Hi,

> > Calling CPUID should not be needed, we have a new fancy
> > ConfidentialComputing PCD for that now.
> The gUefiCpuPkgTokenSpaceGuid.PcdConfidentialComputingGuestAttr is defined in UefiCpuPkg. While BaseIoLibIntrinsicSev is in MdePkg.
> If the ConfidentialComputing PCD is used, then UefiCpuPkg has to be included in BaseIoLibIntrinsicSev.inf. 
> I check all the *.inf under MdePkg but no one *.inf include UefiCpuPkg. 
> I am not sure if UefiCpuPkg can be included in BaseIoLibIntrinsicSev.inf.

Hmm, I guess we should move the pcd then so it cam be used more widely.
Confidential computing has an impact beyond just cpu, it's also memory,
io and more.

> > Maybe that's something to cleanup for amd (Brijesh?) beforehand, so the
> > structure is there already and the tdx patches just need to add the "case tdx:"
> > bits.
> Tdx patches can first use above structure. AMD can update it later. Either way is ok.

That'll work too, I don't care much about the ordering.

take care,
  Gerd


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

* Re: [edk2-devel] [PATCH V2 13/28] UefiCpuPkg: Enable Tdx support in MpInitLib
  2021-10-14  0:27     ` Min Xu
@ 2021-10-14  6:04       ` Gerd Hoffmann
  2021-10-14  6:31         ` Min Xu
  0 siblings, 1 reply; 91+ messages in thread
From: Gerd Hoffmann @ 2021-10-14  6:04 UTC (permalink / raw)
  To: Xu, Min M
  Cc: devel@edk2.groups.io, Brijesh Singh, Erdem Aktas, James Bottomley,
	Yao, Jiewen, Tom Lendacky, Dong, Eric, Ni, Ray, Kumar, Rahul1

On Thu, Oct 14, 2021 at 12:27:13AM +0000, Xu, Min M wrote:
> On October 12, 2021 6:32 PM, Gerd Hoffman wrote:
> >   Hi,
> > 
> > > +  do {
> > > +    AsmCpuid (0, &LargestEax, &Ebx, &Ecx, &Edx);
> > 
> > Again: this should use PCD.
> ConfidentialComputing PCD is set in PlatformPei. So any check of this PCD should be after PlatformPei.

Can we move that to the SEC phase?

> MpInitLib will be included in CpuMpPei. So if PCD is checked in MpInitLib, then we must assume CpuMpPei is called after PlatformPei.
> In current OVMF, CpuMpPei is called after PlatforPei. But I am not sure if it is always the case. Can we have such assumption?
> Based on above consideration, CPUID is used to probe if it is Tdx guest.

Not sure.  There are no explicit depex dependencies, so I suspect the
initialization order could change.

take care,
  Gerd


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

* Re: [edk2-devel] [PATCH V2 06/28] MdePkg: Update BaseIoLibIntrinsicSev to support Tdx
  2021-10-14  5:37       ` Gerd Hoffmann
@ 2021-10-14  6:24         ` Min Xu
  2021-10-14  9:03           ` Gerd Hoffmann
  2021-10-22  5:23         ` Min Xu
  1 sibling, 1 reply; 91+ messages in thread
From: Min Xu @ 2021-10-14  6:24 UTC (permalink / raw)
  To: Gerd Hoffmann
  Cc: devel@edk2.groups.io, Kinney, Michael D, Liming Gao,
	Liu, Zhiguang, Brijesh Singh, Erdem Aktas, James Bottomley,
	Yao, Jiewen, Tom Lendacky

On October 14, 2021 1:38 PM, Gerd Hoffmann wrote:
>   Hi,
> 
> > > Calling CPUID should not be needed, we have a new fancy
> > > ConfidentialComputing PCD for that now.
> > The gUefiCpuPkgTokenSpaceGuid.PcdConfidentialComputingGuestAttr is
> defined in UefiCpuPkg. While BaseIoLibIntrinsicSev is in MdePkg.
> > If the ConfidentialComputing PCD is used, then UefiCpuPkg has to be included
> in BaseIoLibIntrinsicSev.inf.
> > I check all the *.inf under MdePkg but no one *.inf include UefiCpuPkg.
> > I am not sure if UefiCpuPkg can be included in BaseIoLibIntrinsicSev.inf.
> 
> Hmm, I guess we should move the pcd then so it cam be used more widely.
> Confidential computing has an impact beyond just cpu, it's also memory, io and
> more.
How about define ConfidentialComputingAttr PCD in MdePkg.dec?
> 
> > > Maybe that's something to cleanup for amd (Brijesh?) beforehand, so
> > > the structure is there already and the tdx patches just need to add the "case
> tdx:"
> > > bits.
> > Tdx patches can first use above structure. AMD can update it later. Either way
> is ok.
> 
> That'll work too, I don't care much about the ordering.
> 
It will be updated in the next version.

Thanks.
Min

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

* Re: [edk2-devel] [PATCH V2 13/28] UefiCpuPkg: Enable Tdx support in MpInitLib
  2021-10-14  6:04       ` Gerd Hoffmann
@ 2021-10-14  6:31         ` Min Xu
  2021-10-14  6:56           ` Gerd Hoffmann
  0 siblings, 1 reply; 91+ messages in thread
From: Min Xu @ 2021-10-14  6:31 UTC (permalink / raw)
  To: kraxel@redhat.com
  Cc: devel@edk2.groups.io, Brijesh Singh, Erdem Aktas, James Bottomley,
	Yao, Jiewen, Tom Lendacky, Dong, Eric, Ni, Ray, Kumar, Rahul1

On October 14, 2021 2:05 PM, Gerd Hoffmann wrote:
> On Thu, Oct 14, 2021 at 12:27:13AM +0000, Xu, Min M wrote:
> > On October 12, 2021 6:32 PM, Gerd Hoffman wrote:
> > >   Hi,
> > >
> > > > +  do {
> > > > +    AsmCpuid (0, &LargestEax, &Ebx, &Ecx, &Edx);
> > >
> > > Again: this should use PCD.
> > ConfidentialComputing PCD is set in PlatformPei. So any check of this PCD
> should be after PlatformPei.
> 
> Can we move that to the SEC phase?
PCD cannot be set in SEC phase.
> 
> > MpInitLib will be included in CpuMpPei. So if PCD is checked in MpInitLib,
> then we must assume CpuMpPei is called after PlatformPei.
> > In current OVMF, CpuMpPei is called after PlatforPei. But I am not sure if it is
> always the case. Can we have such assumption?
> > Based on above consideration, CPUID is used to probe if it is Tdx guest.
> 
> Not sure.  There are no explicit depex dependencies, so I suspect the
> initialization order could change.
> 
> take care,
>   Gerd


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

* Re: [edk2-devel] [PATCH V2 14/28] OvmfPkg: Update SecEntry.nasm to support Tdx
  2021-10-14  0:55     ` Min Xu
@ 2021-10-14  6:51       ` Gerd Hoffmann
  0 siblings, 0 replies; 91+ messages in thread
From: Gerd Hoffmann @ 2021-10-14  6:51 UTC (permalink / raw)
  To: Xu, Min M
  Cc: devel@edk2.groups.io, Ard Biesheuvel, Justen, Jordan L,
	Brijesh Singh, Erdem Aktas, James Bottomley, Yao, Jiewen,
	Tom Lendacky

On Thu, Oct 14, 2021 at 12:55:22AM +0000, Xu, Min M wrote:
> On October 12, 2021 6:39 PM, Gerd Hoffmann wrote:
> >   Hi,
> > 
> > >  - AcceptPages:
> > >    To mitigate the performance impact of accepting pages in SEC phase on
> > >    BSP, BSP will parse memory resources and assign each AP the task of
> > >    accepting a subset of pages. This command may be called several times
> > >    until all memory resources are processed. In accepting pages, PageLevel
> > >    may fall back to smaller one if SIZE_MISMATCH error is returned.
> > 
> > Hmm, I'm wondering whenever it is useful to have this in the first place with
> > the longer-term plan to implement lazy on-demand acceptance.
> To mitigate the performance impact of accepting pages, there are 3 ways.
> 1. Big accept page size.
> 2. Accept the pages by BSP and APs together.
> 3. Lazy on-demand acceptance.
> From the perspective of implementation complexity, 1 < 2 < 3.

> Lazy on-demand acceptance need the update not only in TDVF, but also
> in Guest kernel. More investigation shows it also impacts the grub and
> memory management in EDK2.

Yes.

> From the perspective of performance improvement, 2M accept page size +
> BSP/AP together, can improve the performance a lot. 

Yes.

The question is whenever that has to happen in the SEC phase though,
especially considering that we want get rid of that longer-term with
the switch to lazy acceptance.

You have patches to setup MpLib for Tdx.  So it should be possible to
use MpLib to distribute the acceptance jobs to the APs in PEI or DXE
phase instead.  Advantages:

  * You don't need large chunks of assembler code for the APs to
    handle acceptance.
  * The AP boot can be simplified, you can just let them spin until
    the BSP initialized MpLib.
  * You can continue to use the MpLib-based parallel acceptance code
    when switching over to lazy on-demand acceptance later on.

The BSP would still need to accept some memory in SEC (enough to reach
PEI or DXE), but that shouldn't be very much.

take care,
  Gerd


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

* Re: [edk2-devel] [PATCH V2 13/28] UefiCpuPkg: Enable Tdx support in MpInitLib
  2021-10-14  6:31         ` Min Xu
@ 2021-10-14  6:56           ` Gerd Hoffmann
  0 siblings, 0 replies; 91+ messages in thread
From: Gerd Hoffmann @ 2021-10-14  6:56 UTC (permalink / raw)
  To: Xu, Min M
  Cc: devel@edk2.groups.io, Brijesh Singh, Erdem Aktas, James Bottomley,
	Yao, Jiewen, Tom Lendacky, Dong, Eric, Ni, Ray, Kumar, Rahul1

On Thu, Oct 14, 2021 at 06:31:30AM +0000, Xu, Min M wrote:
> On October 14, 2021 2:05 PM, Gerd Hoffmann wrote:
> > On Thu, Oct 14, 2021 at 12:27:13AM +0000, Xu, Min M wrote:
> > > On October 12, 2021 6:32 PM, Gerd Hoffman wrote:
> > > >   Hi,
> > > >
> > > > > +  do {
> > > > > +    AsmCpuid (0, &LargestEax, &Ebx, &Ecx, &Edx);
> > > >
> > > > Again: this should use PCD.
> > > ConfidentialComputing PCD is set in PlatformPei. So any check of this PCD
> > should be after PlatformPei.
> > 
> > Can we move that to the SEC phase?
> PCD cannot be set in SEC phase.

Hmm, ok.  Can we have a helper function for that in TdxLib for sec and
pei then, so this check doesn't need to be cut+pasted to various places?

thanks,
  Gerd


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

* Re: [PATCH V2 07/28] UefiCpuPkg: Support TDX in BaseXApicX2ApicLib
  2021-10-13  5:30   ` Ni, Ray
@ 2021-10-14  7:58     ` Min Xu
  0 siblings, 0 replies; 91+ messages in thread
From: Min Xu @ 2021-10-14  7:58 UTC (permalink / raw)
  To: Ni, Ray, devel@edk2.groups.io
  Cc: Dong, Eric, Kumar, Rahul1, Brijesh Singh, Erdem Aktas,
	James Bottomley, Yao, Jiewen, Tom Lendacky

On October 13, 2021 1:31 PM, Ray Ni wrote:
> Min,
> Comments below:
> 
> +**/
> +BOOLEAN
> +EFIAPI
> 
> 1. EFIAPI is for public lib API. Is this a public API?
No, it is not a public API. The EFIAPI will be removed. Thanks for reminder.
> 
> +BaseXApicIsTdxGuest (
> +  VOID
> +  )
> +{
> +  UINT32    Eax;
> +  UINT32    Ebx;
> +  UINT32    Ecx;
> +  UINT32    Edx;
> +  UINT32    LargestEax;
> +
> +  if (mBaseXApicTdxProbed) {
> +    return mBaseXApicIsTdxEnabled;
> +  }
> +
> +  mBaseXApicIsTdxEnabled = FALSE;
> 
> 2. ApicLib can be used in pre-mem running directly in flash.
> The global variable cannot be modified in that case.
What will happen when the global variable is modified in flash?
Will the system hang? Or just a failure of write operation?
> 
> 
> +
> +  do {
> +    AsmCpuid (0, &LargestEax, &Ebx, &Ecx, &Edx);
> 
> +
> +    if (Ebx != SIGNATURE_32 ('G', 'e', 'n', 'u')
> +      || Edx != SIGNATURE_32 ('i', 'n', 'e', 'I')
> +      || Ecx != SIGNATURE_32 ('n', 't', 'e', 'l')) {
> +      break;
> +    }
> +
> +    AsmCpuid (1, 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;
> +    }
> 
> 
> 3. Can you use definition from MdePkg\Include\Register\Intel\Cpuid.h instead
> of hardcode 0, 1, 0x21, "Genu" and etc.?
Thanks for reminder. It will be updated in the next version.
CPUID leaf 0x21 is newly added in [TDX] Section 10.2
TDX: https://software.intel.com/content/dam/develop/external/us/en/documents/tdx-module-1.0-public-spec-v0.931.pdf
Can I add a definition of leaf 0x21 in MdePkg\Include\Register\Intel\Cpuid.h?
> 
> +
> +    mBaseXApicIsTdxEnabled = TRUE;
> 
> 4. avoid relying on global variable for caching the result.
Is it because LocalApicLib will run in flash?
> 
> +
> +  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:
> 
> 5. Can you explain in the comments about  what spec says that above MSR can
> be accessed directly while others cannot?
TDX: https://software.intel.com/content/dam/develop/external/us/en/documents/tdx-module-1.0-public-spec-v0.931.pdf
[TDX] Section 18.1
> 
> 
> +  UINT64    Val;
> +  UINT64    Status;
> +  if (!AccessMsrNative (MsrIndex) && BaseXApicIsTdxGuest ()) {
> 
> 6. can we simplify the above check with " if (!AccessMsrNative (MsrIndex))"?
> IsTdxGuest() can be called inside AccessMsrNative().
Sure. It will be updated in next version.
> 
> +UINT32
> +EFIAPI
> 
> 7. No EFIAPI please.
Sure. It will be fixed in next version.
> 
> +ReadMsrReg32 (
> +  IN UINT32 MsrIndex
> +  )
> +{
> +  UINT64    Val;
> +  UINT64    Status;
> +  if (!AccessMsrNative (MsrIndex) && BaseXApicIsTdxGuest ()) {
> +    Status = TdVmCall (TDVMCALL_RDMSR, (UINT64) MsrIndex, 0, 0, 0, &Val);
> +    if (Status != 0) {
> +      TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
> +    }
> +  } else {
> +    Val = AsmReadMsr32 (MsrIndex);
> +  }
> +  return (UINT32)(UINTN) Val;
> 
> 8. Can you directly call ReadMsrReg64()?
Sure. It will be updated in next version.
> 
> 
> +VOID
> +EFIAPI
> +WriteMsrReg32 (
> +  IN UINT32 MsrIndex,
> +  IN UINT32 Val
> +  )
> +{
> +  UINT64    Status;
> +  if (!AccessMsrNative (MsrIndex) && BaseXApicIsTdxGuest ()) {
> +    Status = TdVmCall (TDVMCALL_WRMSR, (UINT64) MsrIndex, (UINT64) Val, 0,
> 0, 0);
> +    if (Status != 0) {
> +      DEBUG((DEBUG_ERROR, "WriteMsrReg32 returned failure.
> Status=0x%llx\n", Status));
> +      TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
> +    }
> +  } else {
> +    AsmWriteMsr32 (MsrIndex, Val);
> 
> 8. Can you directly call WriteMsrReg64()?
Sure. It will be updated in next version.
> 
> 
> -  ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
> +  ApicBaseMsr.Uint64 = ReadMsrReg64 (MSR_IA32_APIC_BASE);
> 
> 9. I prefer to use "LocalApicLibReadMsr64()". It indicates two meanings:
>     a. it's a local function which can be found within this lib
>     b. it's consistent with "AsmReadMsr64".
Sure. It will be updated in next version.
> 

Thanks.
Min

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

* Re: [PATCH V2 13/28] UefiCpuPkg: Enable Tdx support in MpInitLib
  2021-10-13  6:01   ` Ni, Ray
@ 2021-10-14  8:22     ` Min Xu
  0 siblings, 0 replies; 91+ messages in thread
From: Min Xu @ 2021-10-14  8:22 UTC (permalink / raw)
  To: Ni, Ray, devel@edk2.groups.io
  Cc: Brijesh Singh, Erdem Aktas, James Bottomley, Yao, Jiewen,
	Tom Lendacky, Dong, Eric, Kumar, Rahul1

On October 13, 2021 2:01 PM, Ray Ni wrote:
> Min,
> The change is to provide a totally different MP service in TDX case.
> It makes the MpInitLib more complicated.
> 
> How about?
> 1. Change CpuMpPei/CpuMpDxe to return directly in TDX case.
> 2. Add new TdxCpuMpPei/TdxCpuMpDxe to provide a new set simple MP
> service in TDX case.
> 
> This makes the whole code easier to understand.
Thanks for the suggestion. Let me think it about and will reply to you later. Thanks for your understanding.

Thanks
Min

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

* Re: [edk2-devel] [PATCH V2 06/28] MdePkg: Update BaseIoLibIntrinsicSev to support Tdx
  2021-10-14  6:24         ` Min Xu
@ 2021-10-14  9:03           ` Gerd Hoffmann
  0 siblings, 0 replies; 91+ messages in thread
From: Gerd Hoffmann @ 2021-10-14  9:03 UTC (permalink / raw)
  To: Xu, Min M
  Cc: devel@edk2.groups.io, Kinney, Michael D, Liming Gao,
	Liu, Zhiguang, Brijesh Singh, Erdem Aktas, James Bottomley,
	Yao, Jiewen, Tom Lendacky

  Hi,

> > Hmm, I guess we should move the pcd then so it cam be used more widely.
> > Confidential computing has an impact beyond just cpu, it's also memory, io and
> > more.
> How about define ConfidentialComputingAttr PCD in MdePkg.dec?

Looks sensible to me.

take care,
  Gerd


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

* Re: [edk2-devel] [PATCH V2 28/28] OvmfPkg: Add LocalApicTimerDxe
  2021-10-14  5:20     ` Min Xu
@ 2021-10-15  1:21       ` Yao, Jiewen
  0 siblings, 0 replies; 91+ messages in thread
From: Yao, Jiewen @ 2021-10-15  1:21 UTC (permalink / raw)
  To: Xu, Min M, devel@edk2.groups.io, kraxel@redhat.com
  Cc: Ard Biesheuvel, Justen, Jordan L, Brijesh Singh, Erdem Aktas,
	James Bottomley, Tom Lendacky

Good suggestion, Gerd.

I agree with both suggestion. We should rename XenTimerDxe to LocalApicTimerDxe.


> -----Original Message-----
> From: Xu, Min M <min.m.xu@intel.com>
> Sent: Thursday, October 14, 2021 1:20 PM
> To: devel@edk2.groups.io; kraxel@redhat.com
> Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>; Justen, Jordan L
> <jordan.l.justen@intel.com>; Brijesh Singh <brijesh.singh@amd.com>; Erdem
> Aktas <erdemaktas@google.com>; James Bottomley <jejb@linux.ibm.com>;
> Yao, Jiewen <jiewen.yao@intel.com>; Tom Lendacky
> <thomas.lendacky@amd.com>
> Subject: RE: [edk2-devel] [PATCH V2 28/28] OvmfPkg: Add LocalApicTimerDxe
> 
> On October 12, 2021 9:02 PM, Gerd Hoffmann wrote:
> > On Tue, Oct 05, 2021 at 11:39:39AM +0800, Min Xu wrote:
> > > RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
> > >
> > > TDX guest supports LocalApicTimer. But in current OvmfPkg the
> > > supported timer is 8254TimerDxe. So
> > > gUefiOvmfPkgTokenSpaceGuid.PcdTimerSelector
> > > is introduced to select the running Timer. The Timer driver will check
> > > the TimerSelector in its entry point. The default Timer is 8254.
> >
> > Hmm.
> >
> > We already have a local apic timer implementation (XenTimerDxe).  Works fine
> > with kvm, microvm already uses that.  See commit 76602f45dcd9
> > ("OvmfPkg/Microvm: use XenTimerDxe (lapic timer)").
> >
> > So, first I'd suggest to just use that (maybe rename the thing to avoid
> confusion
> > as it isn't really Xen specific).
> Thanks for reminder. Let me first do some more investigation about the
> XenTimerDxe. It will be better to use an existing lapic timer than introducing a
> new one.
> >
> > Next question is whenever there is a need for a runtime switch.  I doubt it is
> > possible to create a virtual machine without lapic, so switching ovmf from
> 8254
> > (aka pit) to lapic unconditionally should work fine.
> > Quick smoke test (patch below) shows no obvious problems.
> Let me do some more investigation.
> >
> 
> Thanks.
> Min

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

* Re: [edk2-devel] [PATCH V2 21/28] OvmfPkg: Update PlatformPei to support TDX
  2021-10-13  4:49   ` [edk2-devel] " Gerd Hoffmann
@ 2021-10-15  1:31     ` Yao, Jiewen
  2021-10-15  5:45       ` Gerd Hoffmann
  0 siblings, 1 reply; 91+ messages in thread
From: Yao, Jiewen @ 2021-10-15  1:31 UTC (permalink / raw)
  To: devel@edk2.groups.io, kraxel@redhat.com, Xu, Min M
  Cc: Ard Biesheuvel, Justen, Jordan L, Brijesh Singh, Erdem Aktas,
	James Bottomley, Tom Lendacky

We have to relocate based upon best practice.

The mailbox must be in ACPI-NVS. And the ACPI-NVS should be in high memory.

The original mailbox location is in low memory. If we do not relocate to high memory, then the OS will see a hole in low memory.

That is not preferred.

Thank you
Yao Jiewen

> -----Original Message-----
> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Gerd
> Hoffmann
> Sent: Wednesday, October 13, 2021 12:49 PM
> To: devel@edk2.groups.io; Xu, Min M <min.m.xu@intel.com>
> Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>; Justen, Jordan L
> <jordan.l.justen@intel.com>; Brijesh Singh <brijesh.singh@amd.com>; Erdem
> Aktas <erdemaktas@google.com>; James Bottomley <jejb@linux.ibm.com>;
> Yao, Jiewen <jiewen.yao@intel.com>; Tom Lendacky
> <thomas.lendacky@amd.com>
> Subject: Re: [edk2-devel] [PATCH V2 21/28] OvmfPkg: Update PlatformPei to
> support TDX
> 
>   Hi,
> 
> > 2. Relocate mailbox
> >   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 waiting for
> >   further command.
> 
> Why is the mailbox relocated?  Are there any problems when simply
> continuing to use the memfd page?
> 
> The memfd page location is known to qemu, so when not relocating the
> mailbox the MADT update could be done on the host side.
> 
> take care,
>   Gerd
> 
> 
> 
> 
> 


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

* Re: [edk2-devel] [PATCH V2 21/28] OvmfPkg: Update PlatformPei to support TDX
  2021-10-15  1:31     ` Yao, Jiewen
@ 2021-10-15  5:45       ` Gerd Hoffmann
  2021-10-15  6:41         ` Yao, Jiewen
  0 siblings, 1 reply; 91+ messages in thread
From: Gerd Hoffmann @ 2021-10-15  5:45 UTC (permalink / raw)
  To: Yao, Jiewen
  Cc: devel@edk2.groups.io, Xu, Min M, Ard Biesheuvel, Justen, Jordan L,
	Brijesh Singh, Erdem Aktas, James Bottomley, Tom Lendacky

  Hi,

> The original mailbox location is in low memory. If we do not relocate
> to high memory, then the OS will see a hole in low memory.

Well, both low and high memory to be exact.  qemu maps the whole
firmware image below 4G, and mirrors the topmost 128k (including
memfd + reset vector) below 1M.

Given that TDX starts the processor in 32bit mode, so it doesn't need
the 16bit entry @ f000:fff0, I assumed TDX completely ignores the low
memory mapping and uses only the high memory mapping.

So you are telling me this is not the case?

take care,
  Gerd


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

* Re: [edk2-devel] [PATCH V2 21/28] OvmfPkg: Update PlatformPei to support TDX
  2021-10-15  5:45       ` Gerd Hoffmann
@ 2021-10-15  6:41         ` Yao, Jiewen
  0 siblings, 0 replies; 91+ messages in thread
From: Yao, Jiewen @ 2021-10-15  6:41 UTC (permalink / raw)
  To: devel@edk2.groups.io, kraxel@redhat.com
  Cc: Xu, Min M, Ard Biesheuvel, Justen, Jordan L, Brijesh Singh,
	Erdem Aktas, James Bottomley, Tom Lendacky

Ok. Please allow me to clarify my description. 

"high memory" in this context means the memory region just below the less than 4GiB DRAM limit. In a platform BIOS, it means the memory just below TOLUD (Top of Low Usable DRAM).
Usually, the BIOS will reserve a chunk of memory just below TOLUD, including ReservedMemory, ACPI-NVS, ACPI-Reclaim, RuntimeData, RuntimeCode. As such the OS can use the reset memory as a continuous memory region.

"low memory" in this context means the memory region below the "high memory" defined above. From OS perspective, there will be a hole in the continuous memory region. Technically, OS shall handle that. But the best practice told us we should avoid that as much as possible. We have experience that if we put too many holes, some OSes will refuse to boot. From OS perspective, the BIOS should put all BIOS-reserved memory together.

Here, the initial mailbox is in "low memory", because we cannot predict how many virtual-DRAM the VMM will allocate for the OVMF. We cannot predict where is the TOLUD.
And we have to put the final mailbox (reserved) to "high memory" to avoid creating a hole for OS.

If you look at the whole firmware code, relocation is quite usual design pattern in firmware. For example, PEI HOB, SMM init, CPU AP Loop, ACPI table, BootScript, etc.

Thank you
Yao Jiewen

> -----Original Message-----
> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Gerd
> Hoffmann
> Sent: Friday, October 15, 2021 1:46 PM
> To: Yao, Jiewen <jiewen.yao@intel.com>
> Cc: devel@edk2.groups.io; Xu, Min M <min.m.xu@intel.com>; Ard Biesheuvel
> <ardb+tianocore@kernel.org>; Justen, Jordan L <jordan.l.justen@intel.com>;
> Brijesh Singh <brijesh.singh@amd.com>; Erdem Aktas
> <erdemaktas@google.com>; James Bottomley <jejb@linux.ibm.com>; Tom
> Lendacky <thomas.lendacky@amd.com>
> Subject: Re: [edk2-devel] [PATCH V2 21/28] OvmfPkg: Update PlatformPei to
> support TDX
> 
>   Hi,
> 
> > The original mailbox location is in low memory. If we do not relocate
> > to high memory, then the OS will see a hole in low memory.
> 
> Well, both low and high memory to be exact.  qemu maps the whole
> firmware image below 4G, and mirrors the topmost 128k (including
> memfd + reset vector) below 1M.
> 
> Given that TDX starts the processor in 32bit mode, so it doesn't need
> the 16bit entry @ f000:fff0, I assumed TDX completely ignores the low
> memory mapping and uses only the high memory mapping.
> 
> So you are telling me this is not the case?
> 
> take care,
>   Gerd
> 
> 
> 
> 
> 


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

* Re: [edk2-devel] [PATCH V2 24/28] OvmfPkg: Add TdxDxe driver
  2021-10-12 11:50   ` [edk2-devel] " Gerd Hoffmann
@ 2021-10-18  8:38     ` Min Xu
  0 siblings, 0 replies; 91+ messages in thread
From: Min Xu @ 2021-10-18  8:38 UTC (permalink / raw)
  To: Gerd Hoffmann, devel@edk2.groups.io
  Cc: Ard Biesheuvel, Justen, Jordan L, Brijesh Singh, Erdem Aktas,
	James Bottomley, Yao, Jiewen, Tom Lendacky

On October 12, 2021 7:50 PM, Gerd Hoffmann wrote:
>   Hi,
> 
> > Besides above features, TdxDxe driver will update the ACPI MADT
> > Mutiprocessor Wakeup Table.
> 
> > +  ACPI_MADT_MPWK_STRUCT                               *MadtMpWk;
> 
> > +  NewBufferSize = 1                     * sizeof (*Madt) +
> > +                  CpuCount              * sizeof (*LocalApic) +
> > +                  1                     * sizeof (*IoApic) +
> > +                  NUM_8259_IRQS         * sizeof (*Iso) +
> > +                  1                     * sizeof (*LocalApicNmi);
> 
> + sizeof(MadtMpWk)
> 
> > +  CopyMem (&(Madt->Header), AcpiTableBuffer, sizeof
> (EFI_ACPI_DESCRIPTION_HEADER));
> > +  Madt->Header.Length    = (UINT32) NewBufferSize;
> > +  Madt->LocalApicAddress = PcdGet32 (PcdCpuLocalApicBaseAddress);
> > +  Madt->Flags            = EFI_ACPI_1_0_PCAT_COMPAT;
> > +  Ptr = Madt + 1;
> 
> [ ... ]
> 
> You are not updating the MADT.  You create a new one from scratch.  Not a
> good plan.  I think you should simply get the installed table, copy it to a larger
> buffer and append the ACPI_MADT_MPWK_STRUCT to that.
> 
Thanks for reminder. It will be updated in the next version.

Thanks.
Min

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

* Re: [edk2-devel] [PATCH V2 05/28] MdePkg: Add TdxLib to wrap Tdx operations
  2021-10-14  5:30       ` Gerd Hoffmann
@ 2021-10-22  2:06         ` Min Xu
  0 siblings, 0 replies; 91+ messages in thread
From: Min Xu @ 2021-10-22  2:06 UTC (permalink / raw)
  To: Gerd Hoffmann
  Cc: devel@edk2.groups.io, Kinney, Michael D, Liming Gao,
	Liu, Zhiguang, Brijesh Singh, Erdem Aktas, James Bottomley,
	Yao, Jiewen, Tom Lendacky

On October 14, 2021 1:30 PM, Gerd Hoffmann wrote:
> > > > +UINT8               *mExtendBufferAddress = NULL;
> > > > +TDX_EXTEND_BUFFER   mExtendBuffer;
> > > > +
> > > > +/**
> > > > +  TD.RTMR.EXTEND requires 64B-aligned guest physical address of
> > > > +  48B-extension data. In runtime we walk thru the Buffer to find
> > > > +  out a 64B-aligned start address.
> > >
> > > Can't you just use __attribute__((aligned(64))) for that?
> > >
> > In the PoC of TDVF I had thought about it. But at last I gave up such solution.
> The reasons are:
> > 1) OVMF/TDVF supports both GCC and VS2019 tool chain.
> __attribute__((aligned(64))) is for GCC. Its counterpart of VS2019 Tool chain
> is __declspec(align(x)).
> > 2) There is the limitation of /ALIGN:32 in the build scripts which means
> aligned 64 exceeds  the /ALIGN 32, unless /ALIGN is updated to 64.
> > That's why the current solution is used.
> 
> MdePkg/Include/Base.h has a bunch of ALIGN_* macros to do the math for
> you, which should simplify this alot.  I'd suggest to also drop the
> mExtendBufferAddress and the function calculating it.  Just use the macro
> instead when needed.
Thanks for reminder. It will be updated in the next version.

Thanks.
Min

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

* Re: [edk2-devel] [PATCH V2 06/28] MdePkg: Update BaseIoLibIntrinsicSev to support Tdx
  2021-10-14  5:37       ` Gerd Hoffmann
  2021-10-14  6:24         ` Min Xu
@ 2021-10-22  5:23         ` Min Xu
  1 sibling, 0 replies; 91+ messages in thread
From: Min Xu @ 2021-10-22  5:23 UTC (permalink / raw)
  To: Gerd Hoffmann
  Cc: devel@edk2.groups.io, Kinney, Michael D, Liming Gao,
	Liu, Zhiguang, Brijesh Singh, Erdem Aktas, James Bottomley,
	Yao, Jiewen, Tom Lendacky

On October 14, 2021 1:38 PM, Gerd Hoffmann wrote:
> > > Calling CPUID should not be needed, we have a new fancy
> > > ConfidentialComputing PCD for that now.
> > The gUefiCpuPkgTokenSpaceGuid.PcdConfidentialComputingGuestAttr is
> defined in UefiCpuPkg. While BaseIoLibIntrinsicSev is in MdePkg.
> > If the ConfidentialComputing PCD is used, then UefiCpuPkg has to be
> included in BaseIoLibIntrinsicSev.inf.
> > I check all the *.inf under MdePkg but no one *.inf include UefiCpuPkg.
> > I am not sure if UefiCpuPkg can be included in BaseIoLibIntrinsicSev.inf.
> 
> Hmm, I guess we should move the pcd then so it cam be used more widely.
> Confidential computing has an impact beyond just cpu, it's also memory, io
> and more.
> 
> > > Maybe that's something to cleanup for amd (Brijesh?) beforehand, so
> > > the structure is there already and the tdx patches just need to add the
> "case tdx:"
> > > bits.
> > Tdx patches can first use above structure. AMD can update it later. Either
> way is ok.
> 
> That'll work too, I don't care much about the ordering.
> 
Hi, Gerd
I revisit this comments and I think we cannot use the PCD in BaseIoLib to
determine Tdx or SEV or legacy guest. It is because BaseIoLib may be called
in SEC phase in which the PCD (it is set in PlatformPei) is not available then.
That's why CPUID(0x21) is used in used in BaseIoLib to probe tdx guest.

Thanks.
Min

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

* Re: [edk2-devel] [PATCH V2 28/28] OvmfPkg: Add LocalApicTimerDxe
  2021-10-12 13:02   ` [edk2-devel] " Gerd Hoffmann
  2021-10-14  5:20     ` Min Xu
@ 2021-10-25  7:37     ` Min Xu
  2021-10-25 11:27       ` Gerd Hoffmann
  1 sibling, 1 reply; 91+ messages in thread
From: Min Xu @ 2021-10-25  7:37 UTC (permalink / raw)
  To: devel@edk2.groups.io, kraxel@redhat.com
  Cc: Ard Biesheuvel, Justen, Jordan L, Brijesh Singh, Erdem Aktas,
	James Bottomley, Yao, Jiewen, Tom Lendacky

On October 12, 2021 9:02 PM, Gerd Hoffmann wrote:
> On Tue, Oct 05, 2021 at 11:39:39AM +0800, Min Xu wrote:
> > RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
> >
> > TDX guest supports LocalApicTimer. But in current OvmfPkg the
> > supported timer is 8254TimerDxe. So
> > gUefiOvmfPkgTokenSpaceGuid.PcdTimerSelector
> > is introduced to select the running Timer. The Timer driver will check
> > the TimerSelector in its entry point. The default Timer is 8254.
> 
> Hmm.
> 
> We already have a local apic timer implementation (XenTimerDxe).  Works fine
> with kvm, microvm already uses that.  See commit 76602f45dcd9
> ("OvmfPkg/Microvm: use XenTimerDxe (lapic timer)").
> 
> So, first I'd suggest to just use that (maybe rename the thing to avoid confusion
> as it isn't really Xen specific).
Thanks for reminder. We can use XenTimerDxe as the LocalApicTimerDxe in Tdx guest. There will be a separate patch to rename XenTimerDxe to LocalApicTimerDxe in the next version.
> 
> Next question is whenever there is a need for a runtime switch.  I doubt it is
> possible to create a virtual machine without lapic, so switching ovmf from 8254
> (aka pit) to lapic unconditionally should work fine.
> Quick smoke test (patch below) shows no obvious problems.
> 
I am not quite sure if there will be any side effect if we switch ovmf (X64) from 8254 to lapic unconditionally. Quick smoke test does show no obvious problems (EDK2 CI shows no error either). But since 8254 timer has already been used in OvmfPkgX64, then there always a reason why 8254 is used.
I am thinking if it is a more secure way to introduce PcdTimerSelector (to select timer in run-time) this time.
We can revisit this proposal (switch ovmf from 8254 to lapic unconditionally) when we are pretty sure there is no side effect in the future.

Thanks.
Min

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

* Re: [edk2-devel] [PATCH V2 28/28] OvmfPkg: Add LocalApicTimerDxe
  2021-10-25  7:37     ` Min Xu
@ 2021-10-25 11:27       ` Gerd Hoffmann
  2021-10-26  1:29         ` Min Xu
  0 siblings, 1 reply; 91+ messages in thread
From: Gerd Hoffmann @ 2021-10-25 11:27 UTC (permalink / raw)
  To: devel, min.m.xu
  Cc: Ard Biesheuvel, Justen, Jordan L, Brijesh Singh, Erdem Aktas,
	James Bottomley, Yao, Jiewen, Tom Lendacky

On Mon, Oct 25, 2021 at 07:37:33AM +0000, Min Xu wrote:
> On October 12, 2021 9:02 PM, Gerd Hoffmann wrote:
> > On Tue, Oct 05, 2021 at 11:39:39AM +0800, Min Xu wrote:
> > > RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
> > >
> > > TDX guest supports LocalApicTimer. But in current OvmfPkg the
> > > supported timer is 8254TimerDxe. So
> > > gUefiOvmfPkgTokenSpaceGuid.PcdTimerSelector
> > > is introduced to select the running Timer. The Timer driver will check
> > > the TimerSelector in its entry point. The default Timer is 8254.
> > 
> > Hmm.
> > 
> > We already have a local apic timer implementation (XenTimerDxe).  Works fine
> > with kvm, microvm already uses that.  See commit 76602f45dcd9
> > ("OvmfPkg/Microvm: use XenTimerDxe (lapic timer)").
> > 
> > So, first I'd suggest to just use that (maybe rename the thing to avoid confusion
> > as it isn't really Xen specific).
> 
> Thanks for reminder. We can use XenTimerDxe as the LocalApicTimerDxe in Tdx guest. There will be a separate patch to rename XenTimerDxe to LocalApicTimerDxe in the next version.

You can also split this off into a separate patch series as it
shouldn't have any tdx dependency.

> I am not quite sure if there will be any side effect if we switch ovmf
> (X64) from 8254 to lapic unconditionally. Quick smoke test does show
> no obvious problems (EDK2 CI shows no error either). But since 8254
> timer has already been used in OvmfPkgX64, then there always a reason
> why 8254 is used.

Note 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.

Hmm, CSM support was moved in 2019 too, checking ...

Yes, CSM support depends on 8254 (and 8259) drivers.

> I am thinking if it is a more secure way to introduce PcdTimerSelector
> (to select timer in run-time) this time.  We can revisit this proposal
> (switch ovmf from 8254 to lapic unconditionally) when we are pretty
> sure there is no side effect in the future.

I still think we don't need a runtime switch.  Continue using
8254TimerDxe for CSM_ENABLE=TRUE builds should be enough.

take care,
  Gerd


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

* Re: [edk2-devel] [PATCH V2 28/28] OvmfPkg: Add LocalApicTimerDxe
  2021-10-25 11:27       ` Gerd Hoffmann
@ 2021-10-26  1:29         ` Min Xu
  2021-10-26  5:50           ` Gerd Hoffmann
  0 siblings, 1 reply; 91+ messages in thread
From: Min Xu @ 2021-10-26  1:29 UTC (permalink / raw)
  To: kraxel@redhat.com, devel@edk2.groups.io
  Cc: Ard Biesheuvel, Justen, Jordan L, Brijesh Singh, Erdem Aktas,
	James Bottomley, Yao, Jiewen, Tom Lendacky, Xu, Min M

On October 25, 2021 7:28 PM, Gerd Hoffmann wrote:
> On Mon, Oct 25, 2021 at 07:37:33AM +0000, Min Xu wrote:
> > On October 12, 2021 9:02 PM, Gerd Hoffmann wrote:
> > > On Tue, Oct 05, 2021 at 11:39:39AM +0800, Min Xu wrote:
> > > > RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
> > > >
> > > > TDX guest supports LocalApicTimer. But in current OvmfPkg the
> > > > supported timer is 8254TimerDxe. So
> > > > gUefiOvmfPkgTokenSpaceGuid.PcdTimerSelector
> > > > is introduced to select the running Timer. The Timer driver will
> > > > check the TimerSelector in its entry point. The default Timer is 8254.
> > >
> > > Hmm.
> > >
> > > We already have a local apic timer implementation (XenTimerDxe).
> > > Works fine with kvm, microvm already uses that.  See commit
> > > 76602f45dcd9
> > > ("OvmfPkg/Microvm: use XenTimerDxe (lapic timer)").
> > >
> > > So, first I'd suggest to just use that (maybe rename the thing to
> > > avoid confusion as it isn't really Xen specific).
> >
> > Thanks for reminder. We can use XenTimerDxe as the LocalApicTimerDxe in
> Tdx guest. There will be a separate patch to rename XenTimerDxe to
> LocalApicTimerDxe in the next version.
> 
> You can also split this off into a separate patch series as it shouldn't have any tdx
> dependency.
> 
> > I am not quite sure if there will be any side effect if we switch ovmf
> > (X64) from 8254 to lapic unconditionally. Quick smoke test does show
> > no obvious problems (EDK2 CI shows no error either). But since 8254
> > timer has already been used in OvmfPkgX64, then there always a reason
> > why 8254 is used.
> 
> Note 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.
> 
> Hmm, CSM support was moved in 2019 too, checking ...
> 
> Yes, CSM support depends on 8254 (and 8259) drivers.
> 
> > I am thinking if it is a more secure way to introduce PcdTimerSelector
> > (to select timer in run-time) this time.  We can revisit this proposal
> > (switch ovmf from 8254 to lapic unconditionally) when we are pretty
> > sure there is no side effect in the future.
> 
> I still think we don't need a runtime switch.  Continue using 8254TimerDxe for
> CSM_ENABLE=TRUE builds should be enough.
> 
Thanks for your detailed explanation. I agree we don't need a runtime switch. Just use CSM_ENABLE=TRUE in *.dsc/*.fdf to switch 8254 and lapic in build time.
I will submit a separate patch series for this change.

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

Do you think we should apply the changes to all above 4 .dsc?

Thanks
Min

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

* Re: [edk2-devel] [PATCH V2 12/28] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VE exception
  2021-10-12 10:27   ` [edk2-devel] " Gerd Hoffmann
@ 2021-10-26  5:06     ` Min Xu
  2021-10-26  6:11       ` Gerd Hoffmann
  0 siblings, 1 reply; 91+ messages in thread
From: Min Xu @ 2021-10-26  5:06 UTC (permalink / raw)
  To: devel@edk2.groups.io, kraxel@redhat.com
  Cc: Brijesh Singh, Erdem Aktas, James Bottomley, Yao, Jiewen,
	Tom Lendacky, Dong, Eric, Ni, Ray, Kumar, Rahul1, Xu, Min M

On October 12, 2021 6:27 PM, Gerd Hoffmann wrote:
> > +  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.
> 
> Can please you explain in more detail why this is the case?
> 
VE Exception may happen before a component registers exception. So it has to be implemented inside the exception lib.

Thanks.
Min

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

* Re: [edk2-devel] [PATCH V2 28/28] OvmfPkg: Add LocalApicTimerDxe
  2021-10-26  1:29         ` Min Xu
@ 2021-10-26  5:50           ` Gerd Hoffmann
  0 siblings, 0 replies; 91+ messages in thread
From: Gerd Hoffmann @ 2021-10-26  5:50 UTC (permalink / raw)
  To: Xu, Min M
  Cc: devel@edk2.groups.io, Ard Biesheuvel, Justen, Jordan L,
	Brijesh Singh, Erdem Aktas, James Bottomley, Yao, Jiewen,
	Tom Lendacky

> > I still think we don't need a runtime switch.  Continue using 8254TimerDxe for
> > CSM_ENABLE=TRUE builds should be enough.
> > 
> Thanks for your detailed explanation. I agree we don't need a runtime switch. Just use CSM_ENABLE=TRUE in *.dsc/*.fdf to switch 8254 and lapic in build time.
> I will submit a separate patch series for this change.
> 
> There are 4 .dsc which include the 8254Timer. 
>  - OvmfPkg/AmdSev/AmdSevX64.dsc
>  - OvmfPkg/OvmfPkgIa32.dsc
>  - OvmfPkg/OvmfPkgIa32X64.dsc
>  - OvmfPkg/OvmfPkgX64.dsc
> 
> Do you think we should apply the changes to all above 4 .dsc?

For the AmdSev config it doesn't make sense to support a CSM.
So I' suggest to just remove support for CSM_ENABLE=TRUE (separate
patch), then use the lapic timer unconditionally.

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

take care,
  Gerd


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

* Re: [edk2-devel] [PATCH V2 12/28] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VE exception
  2021-10-26  5:06     ` Min Xu
@ 2021-10-26  6:11       ` Gerd Hoffmann
  2021-10-26  8:23         ` Min Xu
  0 siblings, 1 reply; 91+ messages in thread
From: Gerd Hoffmann @ 2021-10-26  6:11 UTC (permalink / raw)
  To: Xu, Min M
  Cc: devel@edk2.groups.io, Brijesh Singh, Erdem Aktas, James Bottomley,
	Yao, Jiewen, Tom Lendacky, Dong, Eric, Ni, Ray, Kumar, Rahul1

On Tue, Oct 26, 2021 at 05:06:21AM +0000, Xu, Min M wrote:
> On October 12, 2021 6:27 PM, Gerd Hoffmann wrote:
> > > +  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.
> > 
> > Can please you explain in more detail why this is the case?
> > 
> VE Exception may happen before a component registers exception.
> 
> So it has to be implemented inside the exception lib.

Well, no, you can also change the code to avoid triggering an exception.

Adding a new lib for the exception means the lib must be added into each
and every *.dsc file (either the tdx impl or the null variant), not only
in the tianocore core itself but also all projects depending on tianocore.

So IMHO it is worth checking out how much effort it would be to avoid
early (before component registration) exceptions.

Which early exception do actually happen?

take care,
  Gerd


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

* Re: [edk2-devel] [PATCH V2 12/28] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VE exception
  2021-10-26  6:11       ` Gerd Hoffmann
@ 2021-10-26  8:23         ` Min Xu
  2021-10-26 10:24           ` Gerd Hoffmann
  0 siblings, 1 reply; 91+ messages in thread
From: Min Xu @ 2021-10-26  8:23 UTC (permalink / raw)
  To: kraxel@redhat.com
  Cc: devel@edk2.groups.io, Brijesh Singh, Erdem Aktas, James Bottomley,
	Yao, Jiewen, Tom Lendacky, Dong, Eric, Ni, Ray, Kumar, Rahul1,
	Xu, Min M

On October 26, 2021 2:12 PM, Gerd Hoffmann wrote:
> On Tue, Oct 26, 2021 at 05:06:21AM +0000, Xu, Min M wrote:
> > On October 12, 2021 6:27 PM, Gerd Hoffmann wrote:
> > > > +  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.
> > >
> > > Can please you explain in more detail why this is the case?
> > >
> > VE Exception may happen before a component registers exception.
> >
> > So it has to be implemented inside the exception lib.
> 
> Well, no, you can also change the code to avoid triggering an exception.
> 
> Adding a new lib for the exception means the lib must be added into each
> and every *.dsc file (either the tdx impl or the null variant), not only in the
> tianocore core itself but also all projects depending on tianocore.
> 
> So IMHO it is worth checking out how much effort it would be to avoid early
> (before component registration) exceptions.
> 
> Which early exception do actually happen?
> 
RegisterCpuInterfaceHandler() is not supported in SEC/PEI phase. But there are still some scenarios in SEC/PEI which will trigger #VE.
 CPUID is the sample. See below call chain in CpuMpPei.
InitializeCpuMpWorker --> CollectBitsDataFromPpi --> MpInitLibGetProcessorInfo --> GetProcessorLocationByApicId()

Actually #VE handler follows the same way as #VC handler (by SEV). See discussions in below link.
https://edk2.groups.io/g/devel/topic/73201885

Thanks
Min


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

* Re: [edk2-devel] [PATCH V2 12/28] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VE exception
  2021-10-26  8:23         ` Min Xu
@ 2021-10-26 10:24           ` Gerd Hoffmann
  2021-10-26 12:09             ` Min Xu
  0 siblings, 1 reply; 91+ messages in thread
From: Gerd Hoffmann @ 2021-10-26 10:24 UTC (permalink / raw)
  To: Xu, Min M
  Cc: devel@edk2.groups.io, Brijesh Singh, Erdem Aktas, James Bottomley,
	Yao, Jiewen, Tom Lendacky, Dong, Eric, Ni, Ray, Kumar, Rahul1

  Hi,

> > > So it has to be implemented inside the exception lib.
> > 
> > Well, no, you can also change the code to avoid triggering an exception.
> > 
> > Adding a new lib for the exception means the lib must be added into each
> > and every *.dsc file (either the tdx impl or the null variant), not only in the
> > tianocore core itself but also all projects depending on tianocore.
> > 
> > So IMHO it is worth checking out how much effort it would be to avoid early
> > (before component registration) exceptions.
> > 
> > Which early exception do actually happen?
> > 
> RegisterCpuInterfaceHandler() is not supported in SEC/PEI phase. But there are still some scenarios in SEC/PEI which will trigger #VE.
>  CPUID is the sample. See below call chain in CpuMpPei.
> InitializeCpuMpWorker --> CollectBitsDataFromPpi --> MpInitLibGetProcessorInfo --> GetProcessorLocationByApicId()

Bad example ;)

TDX needs its own Mp implementations anyway, so that
one specifically should be quite easy to avoid.

> Actually #VE handler follows the same way as #VC handler (by SEV). See discussions in below link.
> https://edk2.groups.io/g/devel/topic/73201885

I guess the list of instructions which trap on tdx is quite simliar
to sev?  cpuid, msr access, io instructions?

I suspect there isn't an easy way around that then (as discussed at
length in the email thread linked, thanks for that).

How about adding the tdx exception handler to the existing library, so
we don't have the churn of adding a new library everywhere *again*?

take care,
  Gerd


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

* Re: [edk2-devel] [PATCH V2 12/28] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VE exception
  2021-10-26 10:24           ` Gerd Hoffmann
@ 2021-10-26 12:09             ` Min Xu
  2021-10-27  7:19               ` Gerd Hoffmann
  0 siblings, 1 reply; 91+ messages in thread
From: Min Xu @ 2021-10-26 12:09 UTC (permalink / raw)
  To: kraxel@redhat.com, Brijesh Singh, Yao, Jiewen
  Cc: devel@edk2.groups.io, Erdem Aktas, James Bottomley, Tom Lendacky,
	Dong, Eric, Ni, Ray, Kumar, Rahul1, Xu, Min M

On October 26, 2021 6:25 PM, Gerd Hoffmann wrote: 
>   Hi,
> 
> > > > So it has to be implemented inside the exception lib.
> > >
> > > Well, no, you can also change the code to avoid triggering an exception.
> > >
> > > Adding a new lib for the exception means the lib must be added into
> > > each and every *.dsc file (either the tdx impl or the null variant),
> > > not only in the tianocore core itself but also all projects depending on
> tianocore.
> > >
> > > So IMHO it is worth checking out how much effort it would be to
> > > avoid early (before component registration) exceptions.
> > >
> > > Which early exception do actually happen?
> > >
> > RegisterCpuInterfaceHandler() is not supported in SEC/PEI phase. But there
> are still some scenarios in SEC/PEI which will trigger #VE.
> >  CPUID is the sample. See below call chain in CpuMpPei.
> > InitializeCpuMpWorker --> CollectBitsDataFromPpi -->
> > MpInitLibGetProcessorInfo --> GetProcessorLocationByApicId()
> 
> Bad example ;)
> 
> TDX needs its own Mp implementations anyway, so that one specifically should
> be quite easy to avoid.
> 
> > Actually #VE handler follows the same way as #VC handler (by SEV). See
> discussions in below link.
> > https://edk2.groups.io/g/devel/topic/73201885
> 
> I guess the list of instructions which trap on tdx is quite simliar to sev?  cpuid,
> msr access, io instructions?
> 
> I suspect there isn't an easy way around that then (as discussed at length in the
> email thread linked, thanks for that).
> 
> How about adding the tdx exception handler to the existing library, so we don't
> have the churn of adding a new library everywhere *again*?
Do you mean add the VmTdExitVeHandler.c/VmTdExitLibNull.c in CpuExceptionHandlerLib, then include the corresponding source file in each *CpuExceptionHandlerLib.inf? 
If this is the case, then the implementation of #VE handler (TDX) will be in-consistent with #VC handler (SEV). 
Shall we keep these 2 implementation consistent? Or will SEV agree to update the #VC handler in the same way?

Thanks
Min

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

* Re: [edk2-devel] [PATCH V2 12/28] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VE exception
  2021-10-26 12:09             ` Min Xu
@ 2021-10-27  7:19               ` Gerd Hoffmann
  2021-10-28  1:59                 ` Yao, Jiewen
       [not found]                 ` <16B20F4407499229.28171@groups.io>
  0 siblings, 2 replies; 91+ messages in thread
From: Gerd Hoffmann @ 2021-10-27  7:19 UTC (permalink / raw)
  To: Xu, Min M
  Cc: Brijesh Singh, Yao, Jiewen, devel@edk2.groups.io, Erdem Aktas,
	James Bottomley, Tom Lendacky, Dong, Eric, Ni, Ray, Kumar, Rahul1

  Hi,

> > How about adding the tdx exception handler to the existing library, so we don't
> > have the churn of adding a new library everywhere *again*?

> Do you mean add the VmTdExitVeHandler.c/VmTdExitLibNull.c in CpuExceptionHandlerLib, then include the corresponding source file in each *CpuExceptionHandlerLib.inf? 

No, I mean extend the existing VmgExitLib instead of adding a new
VmTdExitLib, i.e. place the tdx handler in
OvmfPkg/Library/VmgExitLib/TdxExitHandler.c

take care,
  Gerd


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

* Re: [edk2-devel] [PATCH V2 12/28] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VE exception
  2021-10-27  7:19               ` Gerd Hoffmann
@ 2021-10-28  1:59                 ` Yao, Jiewen
  2021-10-28 15:35                   ` Brijesh Singh
       [not found]                 ` <16B20F4407499229.28171@groups.io>
  1 sibling, 1 reply; 91+ messages in thread
From: Yao, Jiewen @ 2021-10-28  1:59 UTC (permalink / raw)
  To: kraxel@redhat.com, Xu, Min M
  Cc: Brijesh Singh, devel@edk2.groups.io, Erdem Aktas, James Bottomley,
	Tom Lendacky, Dong, Eric, Ni, Ray, Kumar, Rahul1

Hi Gerd
I tend to agree with you on the direction to use one TEE specific Exception lib.

However, I have naming concern.
The VMG is very SEV specific term. I don't believe it is a right name to cover the TEE exception lib.

If Brijesh agree to merge, I think we should rename it to a neutral name, such as TeeExitLib.

What do you think, Brijesh?

Thank you
Yao Jiewen


> -----Original Message-----
> From: kraxel@redhat.com <kraxel@redhat.com>
> Sent: Wednesday, October 27, 2021 3:20 PM
> To: Xu, Min M <min.m.xu@intel.com>
> Cc: Brijesh Singh <brijesh.singh@amd.com>; Yao, Jiewen
> <jiewen.yao@intel.com>; devel@edk2.groups.io; Erdem Aktas
> <erdemaktas@google.com>; James Bottomley <jejb@linux.ibm.com>; Tom
> Lendacky <thomas.lendacky@amd.com>; Dong, Eric <eric.dong@intel.com>; Ni,
> Ray <ray.ni@intel.com>; Kumar, Rahul1 <rahul1.kumar@intel.com>
> Subject: Re: [edk2-devel] [PATCH V2 12/28] UefiCpuPkg/CpuExceptionHandler:
> Add base support for the #VE exception
> 
>   Hi,
> 
> > > How about adding the tdx exception handler to the existing library, so we
> don't
> > > have the churn of adding a new library everywhere *again*?
> 
> > Do you mean add the VmTdExitVeHandler.c/VmTdExitLibNull.c in
> CpuExceptionHandlerLib, then include the corresponding source file in each
> *CpuExceptionHandlerLib.inf?
> 
> No, I mean extend the existing VmgExitLib instead of adding a new
> VmTdExitLib, i.e. place the tdx handler in
> OvmfPkg/Library/VmgExitLib/TdxExitHandler.c
> 
> take care,
>   Gerd


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

* Re: [edk2-devel] [PATCH V2 12/28] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VE exception
       [not found]                 ` <16B20F4407499229.28171@groups.io>
@ 2021-10-28  2:07                   ` Yao, Jiewen
  2021-10-28  8:24                     ` Gerd Hoffmann
  0 siblings, 1 reply; 91+ messages in thread
From: Yao, Jiewen @ 2021-10-28  2:07 UTC (permalink / raw)
  To: devel@edk2.groups.io, Yao, Jiewen, kraxel@redhat.com, Xu, Min M
  Cc: Brijesh Singh, Erdem Aktas, James Bottomley, Tom Lendacky,
	Dong, Eric, Ni, Ray, Kumar, Rahul1

Besides VmgExitLib - 
https://github.com/tianocore/edk2/blob/master/UefiCpuPkg/Include/Library/VmgExitLib.h

We have another potential issue - MemEncryptSevLib -
https://github.com/tianocore/edk2/blob/master/OvmfPkg/Include/Library/MemEncryptSevLib.h
We might need rename it to MemEncryptionTeeLib.

I think we need setup direction on how to hand those cases in a consistent way.

Option 1: Keep using current name: SEV and TDX as two class name. Add two instances.

Option 2: Define a new architecture neutral class name such as TEE. Add one instance to cover both SEV and TDX.

Thought?

Thank you
Yao Jiewen


> -----Original Message-----
> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Yao, Jiewen
> Sent: Thursday, October 28, 2021 10:00 AM
> To: kraxel@redhat.com; Xu, Min M <min.m.xu@intel.com>
> Cc: Brijesh Singh <brijesh.singh@amd.com>; devel@edk2.groups.io; Erdem
> Aktas <erdemaktas@google.com>; James Bottomley <jejb@linux.ibm.com>;
> Tom Lendacky <thomas.lendacky@amd.com>; Dong, Eric
> <eric.dong@intel.com>; Ni, Ray <ray.ni@intel.com>; Kumar, Rahul1
> <rahul1.kumar@intel.com>
> Subject: Re: [edk2-devel] [PATCH V2 12/28] UefiCpuPkg/CpuExceptionHandler:
> Add base support for the #VE exception
> 
> Hi Gerd
> I tend to agree with you on the direction to use one TEE specific Exception lib.
> 
> However, I have naming concern.
> The VMG is very SEV specific term. I don't believe it is a right name to cover the
> TEE exception lib.
> 
> If Brijesh agree to merge, I think we should rename it to a neutral name, such as
> TeeExitLib.
> 
> What do you think, Brijesh?
> 
> Thank you
> Yao Jiewen
> 
> 
> > -----Original Message-----
> > From: kraxel@redhat.com <kraxel@redhat.com>
> > Sent: Wednesday, October 27, 2021 3:20 PM
> > To: Xu, Min M <min.m.xu@intel.com>
> > Cc: Brijesh Singh <brijesh.singh@amd.com>; Yao, Jiewen
> > <jiewen.yao@intel.com>; devel@edk2.groups.io; Erdem Aktas
> > <erdemaktas@google.com>; James Bottomley <jejb@linux.ibm.com>; Tom
> > Lendacky <thomas.lendacky@amd.com>; Dong, Eric <eric.dong@intel.com>;
> Ni,
> > Ray <ray.ni@intel.com>; Kumar, Rahul1 <rahul1.kumar@intel.com>
> > Subject: Re: [edk2-devel] [PATCH V2 12/28] UefiCpuPkg/CpuExceptionHandler:
> > Add base support for the #VE exception
> >
> >   Hi,
> >
> > > > How about adding the tdx exception handler to the existing library, so we
> > don't
> > > > have the churn of adding a new library everywhere *again*?
> >
> > > Do you mean add the VmTdExitVeHandler.c/VmTdExitLibNull.c in
> > CpuExceptionHandlerLib, then include the corresponding source file in each
> > *CpuExceptionHandlerLib.inf?
> >
> > No, I mean extend the existing VmgExitLib instead of adding a new
> > VmTdExitLib, i.e. place the tdx handler in
> > OvmfPkg/Library/VmgExitLib/TdxExitHandler.c
> >
> > take care,
> >   Gerd
> 
> 
> 
> 
> 


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

* Re: [edk2-devel] [PATCH V2 12/28] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VE exception
  2021-10-28  2:07                   ` Yao, Jiewen
@ 2021-10-28  8:24                     ` Gerd Hoffmann
  0 siblings, 0 replies; 91+ messages in thread
From: Gerd Hoffmann @ 2021-10-28  8:24 UTC (permalink / raw)
  To: Yao, Jiewen
  Cc: devel@edk2.groups.io, Xu, Min M, Brijesh Singh, Erdem Aktas,
	James Bottomley, Tom Lendacky, Dong, Eric, Ni, Ray, Kumar, Rahul1

On Thu, Oct 28, 2021 at 02:07:58AM +0000, Yao, Jiewen wrote:
> Besides VmgExitLib - 
> https://github.com/tianocore/edk2/blob/master/UefiCpuPkg/Include/Library/VmgExitLib.h
> 
> We have another potential issue - MemEncryptSevLib -
> https://github.com/tianocore/edk2/blob/master/OvmfPkg/Include/Library/MemEncryptSevLib.h
> We might need rename it to MemEncryptionTeeLib.
> 
> I think we need setup direction on how to hand those cases in a consistent way.
> 
> Option 1: Keep using current name: SEV and TDX as two class name. Add two instances.
> 
> Option 2: Define a new architecture neutral class name such as TEE. Add one instance to cover both SEV and TDX.

(2) looks better to me (for libraries, drivers is a different story).
Would also have the advantage that we can probably move (some of) the
dispatcher code (if sev call this, if tdx call that, else do nothing)
into the library too.

take care,
  Gerd


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

* Re: [edk2-devel] [PATCH V2 12/28] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VE exception
  2021-10-28  1:59                 ` Yao, Jiewen
@ 2021-10-28 15:35                   ` Brijesh Singh
  2021-10-28 15:52                     ` Yao, Jiewen
  0 siblings, 1 reply; 91+ messages in thread
From: Brijesh Singh @ 2021-10-28 15:35 UTC (permalink / raw)
  To: Yao, Jiewen, kraxel@redhat.com, Xu, Min M
  Cc: brijesh.singh, devel@edk2.groups.io, Erdem Aktas, James Bottomley,
	Tom Lendacky, Dong, Eric, Ni, Ray, Kumar, Rahul1



On 10/27/21 8:59 PM, Yao, Jiewen wrote:
> Hi Gerd
> I tend to agree with you on the direction to use one TEE specific Exception lib.
> 
> However, I have naming concern.
> The VMG is very SEV specific term. I don't believe it is a right name to cover the TEE exception lib.
> 
> If Brijesh agree to merge, I think we should rename it to a neutral name, such as TeeExitLib.
> 
> What do you think, Brijesh?

I am good with merging both the TDX and SEV feature into one library but 
I am not sure about the "TEE" name in it. TEE generally is used on the 
ARM. In Linux kernel and everywhere else we have been using the COCO 
(Confidential Computing), so something along that line makes much more 
sense.

We can rename the library after the SNP patches are merged. I would 
prefer to avoid renaming because all of the SNP patches are Ack-ed.

-Brijesh
> 
> Thank you
> Yao Jiewen
> 
> 
>> -----Original Message-----
>> From: kraxel@redhat.com <kraxel@redhat.com>
>> Sent: Wednesday, October 27, 2021 3:20 PM
>> To: Xu, Min M <min.m.xu@intel.com>
>> Cc: Brijesh Singh <brijesh.singh@amd.com>; Yao, Jiewen
>> <jiewen.yao@intel.com>; devel@edk2.groups.io; Erdem Aktas
>> <erdemaktas@google.com>; James Bottomley <jejb@linux.ibm.com>; Tom
>> Lendacky <thomas.lendacky@amd.com>; Dong, Eric <eric.dong@intel.com>; Ni,
>> Ray <ray.ni@intel.com>; Kumar, Rahul1 <rahul1.kumar@intel.com>
>> Subject: Re: [edk2-devel] [PATCH V2 12/28] UefiCpuPkg/CpuExceptionHandler:
>> Add base support for the #VE exception
>>
>>    Hi,
>>
>>>> How about adding the tdx exception handler to the existing library, so we
>> don't
>>>> have the churn of adding a new library everywhere *again*?
>>
>>> Do you mean add the VmTdExitVeHandler.c/VmTdExitLibNull.c in
>> CpuExceptionHandlerLib, then include the corresponding source file in each
>> *CpuExceptionHandlerLib.inf?
>>
>> No, I mean extend the existing VmgExitLib instead of adding a new
>> VmTdExitLib, i.e. place the tdx handler in
>> OvmfPkg/Library/VmgExitLib/TdxExitHandler.c
>>
>> take care,
>>    Gerd
> 

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

* Re: [edk2-devel] [PATCH V2 12/28] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VE exception
  2021-10-28 15:35                   ` Brijesh Singh
@ 2021-10-28 15:52                     ` Yao, Jiewen
  2021-10-28 18:28                       ` Lendacky, Thomas
  0 siblings, 1 reply; 91+ messages in thread
From: Yao, Jiewen @ 2021-10-28 15:52 UTC (permalink / raw)
  To: Brijesh Singh, kraxel@redhat.com, Xu, Min M
  Cc: devel@edk2.groups.io, Erdem Aktas, James Bottomley, Tom Lendacky,
	Dong, Eric, Ni, Ray, Kumar, Rahul1

Thanks Brijesh.

We can merge SNP patches at first, then decide next step. Not a problem.

TEE is just my initial thought. And I am open to change if we have a better name.

We already have EFI_TEE_MEASUREMENT_PROTOCOL. I did not see your feedback on that. So I assume you agree with that.

If you have different idea, please feedback to this patch. I hope we have one name.

COCO seems weird to me, btw. :(

Thank you
Yao Jiewen

> -----Original Message-----
> From: Brijesh Singh <brijesh.singh@amd.com>
> Sent: Thursday, October 28, 2021 11:35 PM
> To: Yao, Jiewen <jiewen.yao@intel.com>; kraxel@redhat.com; Xu, Min M
> <min.m.xu@intel.com>
> Cc: brijesh.singh@amd.com; devel@edk2.groups.io; Erdem Aktas
> <erdemaktas@google.com>; James Bottomley <jejb@linux.ibm.com>; Tom
> Lendacky <thomas.lendacky@amd.com>; Dong, Eric <eric.dong@intel.com>; Ni,
> Ray <ray.ni@intel.com>; Kumar, Rahul1 <rahul1.kumar@intel.com>
> Subject: Re: [edk2-devel] [PATCH V2 12/28] UefiCpuPkg/CpuExceptionHandler:
> Add base support for the #VE exception
> 
> 
> 
> On 10/27/21 8:59 PM, Yao, Jiewen wrote:
> > Hi Gerd
> > I tend to agree with you on the direction to use one TEE specific Exception lib.
> >
> > However, I have naming concern.
> > The VMG is very SEV specific term. I don't believe it is a right name to cover
> the TEE exception lib.
> >
> > If Brijesh agree to merge, I think we should rename it to a neutral name, such
> as TeeExitLib.
> >
> > What do you think, Brijesh?
> 
> I am good with merging both the TDX and SEV feature into one library but
> I am not sure about the "TEE" name in it. TEE generally is used on the
> ARM. In Linux kernel and everywhere else we have been using the COCO
> (Confidential Computing), so something along that line makes much more
> sense.
> 
> We can rename the library after the SNP patches are merged. I would
> prefer to avoid renaming because all of the SNP patches are Ack-ed.
> 
> -Brijesh
> >
> > Thank you
> > Yao Jiewen
> >
> >
> >> -----Original Message-----
> >> From: kraxel@redhat.com <kraxel@redhat.com>
> >> Sent: Wednesday, October 27, 2021 3:20 PM
> >> To: Xu, Min M <min.m.xu@intel.com>
> >> Cc: Brijesh Singh <brijesh.singh@amd.com>; Yao, Jiewen
> >> <jiewen.yao@intel.com>; devel@edk2.groups.io; Erdem Aktas
> >> <erdemaktas@google.com>; James Bottomley <jejb@linux.ibm.com>; Tom
> >> Lendacky <thomas.lendacky@amd.com>; Dong, Eric <eric.dong@intel.com>;
> Ni,
> >> Ray <ray.ni@intel.com>; Kumar, Rahul1 <rahul1.kumar@intel.com>
> >> Subject: Re: [edk2-devel] [PATCH V2 12/28]
> UefiCpuPkg/CpuExceptionHandler:
> >> Add base support for the #VE exception
> >>
> >>    Hi,
> >>
> >>>> How about adding the tdx exception handler to the existing library, so we
> >> don't
> >>>> have the churn of adding a new library everywhere *again*?
> >>
> >>> Do you mean add the VmTdExitVeHandler.c/VmTdExitLibNull.c in
> >> CpuExceptionHandlerLib, then include the corresponding source file in each
> >> *CpuExceptionHandlerLib.inf?
> >>
> >> No, I mean extend the existing VmgExitLib instead of adding a new
> >> VmTdExitLib, i.e. place the tdx handler in
> >> OvmfPkg/Library/VmgExitLib/TdxExitHandler.c
> >>
> >> take care,
> >>    Gerd
> >

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

* Re: [edk2-devel] [PATCH V2 12/28] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VE exception
  2021-10-28 15:52                     ` Yao, Jiewen
@ 2021-10-28 18:28                       ` Lendacky, Thomas
  2021-10-29  0:17                         ` Yao, Jiewen
       [not found]                         ` <16B2583BF2C9DB9C.5572@groups.io>
  0 siblings, 2 replies; 91+ messages in thread
From: Lendacky, Thomas @ 2021-10-28 18:28 UTC (permalink / raw)
  To: Yao, Jiewen, Brijesh Singh, kraxel@redhat.com, Xu, Min M
  Cc: devel@edk2.groups.io, Erdem Aktas, James Bottomley, Dong, Eric,
	Ni, Ray, Kumar, Rahul1

On 10/28/21 10:52 AM, Yao, Jiewen wrote:
> Thanks Brijesh.
> 
> We can merge SNP patches at first, then decide next step. Not a problem.
> 
> TEE is just my initial thought. And I am open to change if we have a better name.
> 
> We already have EFI_TEE_MEASUREMENT_PROTOCOL. I did not see your feedback on that. So I assume you agree with that.
> 
> If you have different idea, please feedback to this patch. I hope we have one name.
> 
> COCO seems weird to me, btw. :(

Like Brijesh, I worry about confusion with the ARM TEE feature. Maybe just 
CC then?

Thanks,
Tom

> 
> Thank you
> Yao Jiewen
> 
>> -----Original Message-----
>> From: Brijesh Singh <brijesh.singh@amd.com>
>> Sent: Thursday, October 28, 2021 11:35 PM
>> To: Yao, Jiewen <jiewen.yao@intel.com>; kraxel@redhat.com; Xu, Min M
>> <min.m.xu@intel.com>
>> Cc: brijesh.singh@amd.com; devel@edk2.groups.io; Erdem Aktas
>> <erdemaktas@google.com>; James Bottomley <jejb@linux.ibm.com>; Tom
>> Lendacky <thomas.lendacky@amd.com>; Dong, Eric <eric.dong@intel.com>; Ni,
>> Ray <ray.ni@intel.com>; Kumar, Rahul1 <rahul1.kumar@intel.com>
>> Subject: Re: [edk2-devel] [PATCH V2 12/28] UefiCpuPkg/CpuExceptionHandler:
>> Add base support for the #VE exception
>>
>>
>>
>> On 10/27/21 8:59 PM, Yao, Jiewen wrote:
>>> Hi Gerd
>>> I tend to agree with you on the direction to use one TEE specific Exception lib.
>>>
>>> However, I have naming concern.
>>> The VMG is very SEV specific term. I don't believe it is a right name to cover
>> the TEE exception lib.
>>>
>>> If Brijesh agree to merge, I think we should rename it to a neutral name, such
>> as TeeExitLib.
>>>
>>> What do you think, Brijesh?
>>
>> I am good with merging both the TDX and SEV feature into one library but
>> I am not sure about the "TEE" name in it. TEE generally is used on the
>> ARM. In Linux kernel and everywhere else we have been using the COCO
>> (Confidential Computing), so something along that line makes much more
>> sense.
>>
>> We can rename the library after the SNP patches are merged. I would
>> prefer to avoid renaming because all of the SNP patches are Ack-ed.
>>
>> -Brijesh
>>>
>>> Thank you
>>> Yao Jiewen
>>>
>>>
>>>> -----Original Message-----
>>>> From: kraxel@redhat.com <kraxel@redhat.com>
>>>> Sent: Wednesday, October 27, 2021 3:20 PM
>>>> To: Xu, Min M <min.m.xu@intel.com>
>>>> Cc: Brijesh Singh <brijesh.singh@amd.com>; Yao, Jiewen
>>>> <jiewen.yao@intel.com>; devel@edk2.groups.io; Erdem Aktas
>>>> <erdemaktas@google.com>; James Bottomley <jejb@linux.ibm.com>; Tom
>>>> Lendacky <thomas.lendacky@amd.com>; Dong, Eric <eric.dong@intel.com>;
>> Ni,
>>>> Ray <ray.ni@intel.com>; Kumar, Rahul1 <rahul1.kumar@intel.com>
>>>> Subject: Re: [edk2-devel] [PATCH V2 12/28]
>> UefiCpuPkg/CpuExceptionHandler:
>>>> Add base support for the #VE exception
>>>>
>>>>     Hi,
>>>>
>>>>>> How about adding the tdx exception handler to the existing library, so we
>>>> don't
>>>>>> have the churn of adding a new library everywhere *again*?
>>>>
>>>>> Do you mean add the VmTdExitVeHandler.c/VmTdExitLibNull.c in
>>>> CpuExceptionHandlerLib, then include the corresponding source file in each
>>>> *CpuExceptionHandlerLib.inf?
>>>>
>>>> No, I mean extend the existing VmgExitLib instead of adding a new
>>>> VmTdExitLib, i.e. place the tdx handler in
>>>> OvmfPkg/Library/VmgExitLib/TdxExitHandler.c
>>>>
>>>> take care,
>>>>     Gerd
>>>

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

* Re: [edk2-devel] [PATCH V2 12/28] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VE exception
  2021-10-28 18:28                       ` Lendacky, Thomas
@ 2021-10-29  0:17                         ` Yao, Jiewen
  2021-10-29  4:52                           ` Gerd Hoffmann
  2021-11-01 13:54                           ` Sami Mujawar
       [not found]                         ` <16B2583BF2C9DB9C.5572@groups.io>
  1 sibling, 2 replies; 91+ messages in thread
From: Yao, Jiewen @ 2021-10-29  0:17 UTC (permalink / raw)
  To: Tom Lendacky, Brijesh Singh, kraxel@redhat.com, Xu, Min M,
	sami.mujawar@arm.com
  Cc: devel@edk2.groups.io, Erdem Aktas, James Bottomley, Dong, Eric,
	Ni, Ray, Kumar, Rahul1

I am OK to use EFI_CC_MEASUREMENT_PROTOCOL to replace EFI_TEE_MEASUREMENT_PROTOCOL. (much better than COCO)

Samy
What do you think?



> -----Original Message-----
> From: Tom Lendacky <thomas.lendacky@amd.com>
> Sent: Friday, October 29, 2021 2:29 AM
> To: Yao, Jiewen <jiewen.yao@intel.com>; Brijesh Singh
> <brijesh.singh@amd.com>; kraxel@redhat.com; Xu, Min M
> <min.m.xu@intel.com>
> Cc: devel@edk2.groups.io; Erdem Aktas <erdemaktas@google.com>; James
> Bottomley <jejb@linux.ibm.com>; Dong, Eric <eric.dong@intel.com>; Ni, Ray
> <ray.ni@intel.com>; Kumar, Rahul1 <rahul1.kumar@intel.com>
> Subject: Re: [edk2-devel] [PATCH V2 12/28] UefiCpuPkg/CpuExceptionHandler:
> Add base support for the #VE exception
> 
> On 10/28/21 10:52 AM, Yao, Jiewen wrote:
> > Thanks Brijesh.
> >
> > We can merge SNP patches at first, then decide next step. Not a problem.
> >
> > TEE is just my initial thought. And I am open to change if we have a better
> name.
> >
> > We already have EFI_TEE_MEASUREMENT_PROTOCOL. I did not see your
> feedback on that. So I assume you agree with that.
> >
> > If you have different idea, please feedback to this patch. I hope we have one
> name.
> >
> > COCO seems weird to me, btw. :(
> 
> Like Brijesh, I worry about confusion with the ARM TEE feature. Maybe just
> CC then?
> 
> Thanks,
> Tom
> 
> >
> > Thank you
> > Yao Jiewen
> >
> >> -----Original Message-----
> >> From: Brijesh Singh <brijesh.singh@amd.com>
> >> Sent: Thursday, October 28, 2021 11:35 PM
> >> To: Yao, Jiewen <jiewen.yao@intel.com>; kraxel@redhat.com; Xu, Min M
> >> <min.m.xu@intel.com>
> >> Cc: brijesh.singh@amd.com; devel@edk2.groups.io; Erdem Aktas
> >> <erdemaktas@google.com>; James Bottomley <jejb@linux.ibm.com>; Tom
> >> Lendacky <thomas.lendacky@amd.com>; Dong, Eric <eric.dong@intel.com>;
> Ni,
> >> Ray <ray.ni@intel.com>; Kumar, Rahul1 <rahul1.kumar@intel.com>
> >> Subject: Re: [edk2-devel] [PATCH V2 12/28]
> UefiCpuPkg/CpuExceptionHandler:
> >> Add base support for the #VE exception
> >>
> >>
> >>
> >> On 10/27/21 8:59 PM, Yao, Jiewen wrote:
> >>> Hi Gerd
> >>> I tend to agree with you on the direction to use one TEE specific Exception
> lib.
> >>>
> >>> However, I have naming concern.
> >>> The VMG is very SEV specific term. I don't believe it is a right name to cover
> >> the TEE exception lib.
> >>>
> >>> If Brijesh agree to merge, I think we should rename it to a neutral name,
> such
> >> as TeeExitLib.
> >>>
> >>> What do you think, Brijesh?
> >>
> >> I am good with merging both the TDX and SEV feature into one library but
> >> I am not sure about the "TEE" name in it. TEE generally is used on the
> >> ARM. In Linux kernel and everywhere else we have been using the COCO
> >> (Confidential Computing), so something along that line makes much more
> >> sense.
> >>
> >> We can rename the library after the SNP patches are merged. I would
> >> prefer to avoid renaming because all of the SNP patches are Ack-ed.
> >>
> >> -Brijesh
> >>>
> >>> Thank you
> >>> Yao Jiewen
> >>>
> >>>
> >>>> -----Original Message-----
> >>>> From: kraxel@redhat.com <kraxel@redhat.com>
> >>>> Sent: Wednesday, October 27, 2021 3:20 PM
> >>>> To: Xu, Min M <min.m.xu@intel.com>
> >>>> Cc: Brijesh Singh <brijesh.singh@amd.com>; Yao, Jiewen
> >>>> <jiewen.yao@intel.com>; devel@edk2.groups.io; Erdem Aktas
> >>>> <erdemaktas@google.com>; James Bottomley <jejb@linux.ibm.com>;
> Tom
> >>>> Lendacky <thomas.lendacky@amd.com>; Dong, Eric
> <eric.dong@intel.com>;
> >> Ni,
> >>>> Ray <ray.ni@intel.com>; Kumar, Rahul1 <rahul1.kumar@intel.com>
> >>>> Subject: Re: [edk2-devel] [PATCH V2 12/28]
> >> UefiCpuPkg/CpuExceptionHandler:
> >>>> Add base support for the #VE exception
> >>>>
> >>>>     Hi,
> >>>>
> >>>>>> How about adding the tdx exception handler to the existing library, so
> we
> >>>> don't
> >>>>>> have the churn of adding a new library everywhere *again*?
> >>>>
> >>>>> Do you mean add the VmTdExitVeHandler.c/VmTdExitLibNull.c in
> >>>> CpuExceptionHandlerLib, then include the corresponding source file in
> each
> >>>> *CpuExceptionHandlerLib.inf?
> >>>>
> >>>> No, I mean extend the existing VmgExitLib instead of adding a new
> >>>> VmTdExitLib, i.e. place the tdx handler in
> >>>> OvmfPkg/Library/VmgExitLib/TdxExitHandler.c
> >>>>
> >>>> take care,
> >>>>     Gerd
> >>>

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

* Re: [edk2-devel] [PATCH V2 12/28] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VE exception
       [not found]                         ` <16B2583BF2C9DB9C.5572@groups.io>
@ 2021-10-29  0:20                           ` Yao, Jiewen
  2021-10-29  0:25                             ` Brijesh Singh
  0 siblings, 1 reply; 91+ messages in thread
From: Yao, Jiewen @ 2021-10-29  0:20 UTC (permalink / raw)
  To: devel@edk2.groups.io, Yao, Jiewen, Tom Lendacky, Brijesh Singh,
	kraxel@redhat.com, Xu, Min M, sami.mujawar@arm.com
  Cc: Erdem Aktas, James Bottomley, Dong, Eric, Ni, Ray, Kumar, Rahul1

Just to clarify the proposal: We will use EFI_CC_MEASUREMENT_PROTOCOL, CcMemoryEncryptionLib, and CcExceptionLib, right?

Thank you
Yao Jiewen

> -----Original Message-----
> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Yao, Jiewen
> Sent: Friday, October 29, 2021 8:17 AM
> To: Tom Lendacky <thomas.lendacky@amd.com>; Brijesh Singh
> <brijesh.singh@amd.com>; kraxel@redhat.com; Xu, Min M
> <min.m.xu@intel.com>; sami.mujawar@arm.com
> Cc: devel@edk2.groups.io; Erdem Aktas <erdemaktas@google.com>; James
> Bottomley <jejb@linux.ibm.com>; Dong, Eric <eric.dong@intel.com>; Ni, Ray
> <ray.ni@intel.com>; Kumar, Rahul1 <rahul1.kumar@intel.com>
> Subject: Re: [edk2-devel] [PATCH V2 12/28] UefiCpuPkg/CpuExceptionHandler:
> Add base support for the #VE exception
> 
> I am OK to use EFI_CC_MEASUREMENT_PROTOCOL to replace
> EFI_TEE_MEASUREMENT_PROTOCOL. (much better than COCO)
> 
> Samy
> What do you think?
> 
> 
> 
> > -----Original Message-----
> > From: Tom Lendacky <thomas.lendacky@amd.com>
> > Sent: Friday, October 29, 2021 2:29 AM
> > To: Yao, Jiewen <jiewen.yao@intel.com>; Brijesh Singh
> > <brijesh.singh@amd.com>; kraxel@redhat.com; Xu, Min M
> > <min.m.xu@intel.com>
> > Cc: devel@edk2.groups.io; Erdem Aktas <erdemaktas@google.com>; James
> > Bottomley <jejb@linux.ibm.com>; Dong, Eric <eric.dong@intel.com>; Ni, Ray
> > <ray.ni@intel.com>; Kumar, Rahul1 <rahul1.kumar@intel.com>
> > Subject: Re: [edk2-devel] [PATCH V2 12/28] UefiCpuPkg/CpuExceptionHandler:
> > Add base support for the #VE exception
> >
> > On 10/28/21 10:52 AM, Yao, Jiewen wrote:
> > > Thanks Brijesh.
> > >
> > > We can merge SNP patches at first, then decide next step. Not a problem.
> > >
> > > TEE is just my initial thought. And I am open to change if we have a better
> > name.
> > >
> > > We already have EFI_TEE_MEASUREMENT_PROTOCOL. I did not see your
> > feedback on that. So I assume you agree with that.
> > >
> > > If you have different idea, please feedback to this patch. I hope we have one
> > name.
> > >
> > > COCO seems weird to me, btw. :(
> >
> > Like Brijesh, I worry about confusion with the ARM TEE feature. Maybe just
> > CC then?
> >
> > Thanks,
> > Tom
> >
> > >
> > > Thank you
> > > Yao Jiewen
> > >
> > >> -----Original Message-----
> > >> From: Brijesh Singh <brijesh.singh@amd.com>
> > >> Sent: Thursday, October 28, 2021 11:35 PM
> > >> To: Yao, Jiewen <jiewen.yao@intel.com>; kraxel@redhat.com; Xu, Min M
> > >> <min.m.xu@intel.com>
> > >> Cc: brijesh.singh@amd.com; devel@edk2.groups.io; Erdem Aktas
> > >> <erdemaktas@google.com>; James Bottomley <jejb@linux.ibm.com>; Tom
> > >> Lendacky <thomas.lendacky@amd.com>; Dong, Eric
> <eric.dong@intel.com>;
> > Ni,
> > >> Ray <ray.ni@intel.com>; Kumar, Rahul1 <rahul1.kumar@intel.com>
> > >> Subject: Re: [edk2-devel] [PATCH V2 12/28]
> > UefiCpuPkg/CpuExceptionHandler:
> > >> Add base support for the #VE exception
> > >>
> > >>
> > >>
> > >> On 10/27/21 8:59 PM, Yao, Jiewen wrote:
> > >>> Hi Gerd
> > >>> I tend to agree with you on the direction to use one TEE specific Exception
> > lib.
> > >>>
> > >>> However, I have naming concern.
> > >>> The VMG is very SEV specific term. I don't believe it is a right name to
> cover
> > >> the TEE exception lib.
> > >>>
> > >>> If Brijesh agree to merge, I think we should rename it to a neutral name,
> > such
> > >> as TeeExitLib.
> > >>>
> > >>> What do you think, Brijesh?
> > >>
> > >> I am good with merging both the TDX and SEV feature into one library but
> > >> I am not sure about the "TEE" name in it. TEE generally is used on the
> > >> ARM. In Linux kernel and everywhere else we have been using the COCO
> > >> (Confidential Computing), so something along that line makes much more
> > >> sense.
> > >>
> > >> We can rename the library after the SNP patches are merged. I would
> > >> prefer to avoid renaming because all of the SNP patches are Ack-ed.
> > >>
> > >> -Brijesh
> > >>>
> > >>> Thank you
> > >>> Yao Jiewen
> > >>>
> > >>>
> > >>>> -----Original Message-----
> > >>>> From: kraxel@redhat.com <kraxel@redhat.com>
> > >>>> Sent: Wednesday, October 27, 2021 3:20 PM
> > >>>> To: Xu, Min M <min.m.xu@intel.com>
> > >>>> Cc: Brijesh Singh <brijesh.singh@amd.com>; Yao, Jiewen
> > >>>> <jiewen.yao@intel.com>; devel@edk2.groups.io; Erdem Aktas
> > >>>> <erdemaktas@google.com>; James Bottomley <jejb@linux.ibm.com>;
> > Tom
> > >>>> Lendacky <thomas.lendacky@amd.com>; Dong, Eric
> > <eric.dong@intel.com>;
> > >> Ni,
> > >>>> Ray <ray.ni@intel.com>; Kumar, Rahul1 <rahul1.kumar@intel.com>
> > >>>> Subject: Re: [edk2-devel] [PATCH V2 12/28]
> > >> UefiCpuPkg/CpuExceptionHandler:
> > >>>> Add base support for the #VE exception
> > >>>>
> > >>>>     Hi,
> > >>>>
> > >>>>>> How about adding the tdx exception handler to the existing library, so
> > we
> > >>>> don't
> > >>>>>> have the churn of adding a new library everywhere *again*?
> > >>>>
> > >>>>> Do you mean add the VmTdExitVeHandler.c/VmTdExitLibNull.c in
> > >>>> CpuExceptionHandlerLib, then include the corresponding source file in
> > each
> > >>>> *CpuExceptionHandlerLib.inf?
> > >>>>
> > >>>> No, I mean extend the existing VmgExitLib instead of adding a new
> > >>>> VmTdExitLib, i.e. place the tdx handler in
> > >>>> OvmfPkg/Library/VmgExitLib/TdxExitHandler.c
> > >>>>
> > >>>> take care,
> > >>>>     Gerd
> > >>>
> 
> 
> 
> 


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

* Re: [edk2-devel] [PATCH V2 12/28] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VE exception
  2021-10-29  0:20                           ` Yao, Jiewen
@ 2021-10-29  0:25                             ` Brijesh Singh
  0 siblings, 0 replies; 91+ messages in thread
From: Brijesh Singh @ 2021-10-29  0:25 UTC (permalink / raw)
  To: Yao, Jiewen, devel@edk2.groups.io, Tom Lendacky,
	kraxel@redhat.com, Xu, Min M, sami.mujawar@arm.com
  Cc: brijesh.singh, Erdem Aktas, James Bottomley, Dong, Eric, Ni, Ray,
	Kumar, Rahul1


On 10/28/21 7:20 PM, Yao, Jiewen wrote:
> Just to clarify the proposal: We will use EFI_CC_MEASUREMENT_PROTOCOL, CcMemoryEncryptionLib, and CcExceptionLib, right?

Ack.


>
> Thank you
> Yao Jiewen
>
>> -----Original Message-----
>> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Yao, Jiewen
>> Sent: Friday, October 29, 2021 8:17 AM
>> To: Tom Lendacky <thomas.lendacky@amd.com>; Brijesh Singh
>> <brijesh.singh@amd.com>; kraxel@redhat.com; Xu, Min M
>> <min.m.xu@intel.com>; sami.mujawar@arm.com
>> Cc: devel@edk2.groups.io; Erdem Aktas <erdemaktas@google.com>; James
>> Bottomley <jejb@linux.ibm.com>; Dong, Eric <eric.dong@intel.com>; Ni, Ray
>> <ray.ni@intel.com>; Kumar, Rahul1 <rahul1.kumar@intel.com>
>> Subject: Re: [edk2-devel] [PATCH V2 12/28] UefiCpuPkg/CpuExceptionHandler:
>> Add base support for the #VE exception
>>
>> I am OK to use EFI_CC_MEASUREMENT_PROTOCOL to replace
>> EFI_TEE_MEASUREMENT_PROTOCOL. (much better than COCO)
>>
>> Samy
>> What do you think?
>>
>>
>>
>>> -----Original Message-----
>>> From: Tom Lendacky <thomas.lendacky@amd.com>
>>> Sent: Friday, October 29, 2021 2:29 AM
>>> To: Yao, Jiewen <jiewen.yao@intel.com>; Brijesh Singh
>>> <brijesh.singh@amd.com>; kraxel@redhat.com; Xu, Min M
>>> <min.m.xu@intel.com>
>>> Cc: devel@edk2.groups.io; Erdem Aktas <erdemaktas@google.com>; James
>>> Bottomley <jejb@linux.ibm.com>; Dong, Eric <eric.dong@intel.com>; Ni, Ray
>>> <ray.ni@intel.com>; Kumar, Rahul1 <rahul1.kumar@intel.com>
>>> Subject: Re: [edk2-devel] [PATCH V2 12/28] UefiCpuPkg/CpuExceptionHandler:
>>> Add base support for the #VE exception
>>>
>>> On 10/28/21 10:52 AM, Yao, Jiewen wrote:
>>>> Thanks Brijesh.
>>>>
>>>> We can merge SNP patches at first, then decide next step. Not a problem.
>>>>
>>>> TEE is just my initial thought. And I am open to change if we have a better
>>> name.
>>>> We already have EFI_TEE_MEASUREMENT_PROTOCOL. I did not see your
>>> feedback on that. So I assume you agree with that.
>>>> If you have different idea, please feedback to this patch. I hope we have one
>>> name.
>>>> COCO seems weird to me, btw. :(
>>> Like Brijesh, I worry about confusion with the ARM TEE feature. Maybe just
>>> CC then?
>>>
>>> Thanks,
>>> Tom
>>>
>>>> Thank you
>>>> Yao Jiewen
>>>>
>>>>> -----Original Message-----
>>>>> From: Brijesh Singh <brijesh.singh@amd.com>
>>>>> Sent: Thursday, October 28, 2021 11:35 PM
>>>>> To: Yao, Jiewen <jiewen.yao@intel.com>; kraxel@redhat.com; Xu, Min M
>>>>> <min.m.xu@intel.com>
>>>>> Cc: brijesh.singh@amd.com; devel@edk2.groups.io; Erdem Aktas
>>>>> <erdemaktas@google.com>; James Bottomley <jejb@linux.ibm.com>; Tom
>>>>> Lendacky <thomas.lendacky@amd.com>; Dong, Eric
>> <eric.dong@intel.com>;
>>> Ni,
>>>>> Ray <ray.ni@intel.com>; Kumar, Rahul1 <rahul1.kumar@intel.com>
>>>>> Subject: Re: [edk2-devel] [PATCH V2 12/28]
>>> UefiCpuPkg/CpuExceptionHandler:
>>>>> Add base support for the #VE exception
>>>>>
>>>>>
>>>>>
>>>>> On 10/27/21 8:59 PM, Yao, Jiewen wrote:
>>>>>> Hi Gerd
>>>>>> I tend to agree with you on the direction to use one TEE specific Exception
>>> lib.
>>>>>> However, I have naming concern.
>>>>>> The VMG is very SEV specific term. I don't believe it is a right name to
>> cover
>>>>> the TEE exception lib.
>>>>>> If Brijesh agree to merge, I think we should rename it to a neutral name,
>>> such
>>>>> as TeeExitLib.
>>>>>> What do you think, Brijesh?
>>>>> I am good with merging both the TDX and SEV feature into one library but
>>>>> I am not sure about the "TEE" name in it. TEE generally is used on the
>>>>> ARM. In Linux kernel and everywhere else we have been using the COCO
>>>>> (Confidential Computing), so something along that line makes much more
>>>>> sense.
>>>>>
>>>>> We can rename the library after the SNP patches are merged. I would
>>>>> prefer to avoid renaming because all of the SNP patches are Ack-ed.
>>>>>
>>>>> -Brijesh
>>>>>> Thank you
>>>>>> Yao Jiewen
>>>>>>
>>>>>>
>>>>>>> -----Original Message-----
>>>>>>> From: kraxel@redhat.com <kraxel@redhat.com>
>>>>>>> Sent: Wednesday, October 27, 2021 3:20 PM
>>>>>>> To: Xu, Min M <min.m.xu@intel.com>
>>>>>>> Cc: Brijesh Singh <brijesh.singh@amd.com>; Yao, Jiewen
>>>>>>> <jiewen.yao@intel.com>; devel@edk2.groups.io; Erdem Aktas
>>>>>>> <erdemaktas@google.com>; James Bottomley <jejb@linux.ibm.com>;
>>> Tom
>>>>>>> Lendacky <thomas.lendacky@amd.com>; Dong, Eric
>>> <eric.dong@intel.com>;
>>>>> Ni,
>>>>>>> Ray <ray.ni@intel.com>; Kumar, Rahul1 <rahul1.kumar@intel.com>
>>>>>>> Subject: Re: [edk2-devel] [PATCH V2 12/28]
>>>>> UefiCpuPkg/CpuExceptionHandler:
>>>>>>> Add base support for the #VE exception
>>>>>>>
>>>>>>>     Hi,
>>>>>>>
>>>>>>>>> How about adding the tdx exception handler to the existing library, so
>>> we
>>>>>>> don't
>>>>>>>>> have the churn of adding a new library everywhere *again*?
>>>>>>>> Do you mean add the VmTdExitVeHandler.c/VmTdExitLibNull.c in
>>>>>>> CpuExceptionHandlerLib, then include the corresponding source file in
>>> each
>>>>>>> *CpuExceptionHandlerLib.inf?
>>>>>>>
>>>>>>> No, I mean extend the existing VmgExitLib instead of adding a new
>>>>>>> VmTdExitLib, i.e. place the tdx handler in
>>>>>>> OvmfPkg/Library/VmgExitLib/TdxExitHandler.c
>>>>>>>
>>>>>>> take care,
>>>>>>>     Gerd
>>
>> 
>>

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

* Re: [edk2-devel] [PATCH V2 12/28] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VE exception
  2021-10-29  0:17                         ` Yao, Jiewen
@ 2021-10-29  4:52                           ` Gerd Hoffmann
  2021-10-29  7:51                             ` Min Xu
  2021-11-01 13:54                           ` Sami Mujawar
  1 sibling, 1 reply; 91+ messages in thread
From: Gerd Hoffmann @ 2021-10-29  4:52 UTC (permalink / raw)
  To: Yao, Jiewen
  Cc: Tom Lendacky, Brijesh Singh, Xu, Min M, sami.mujawar@arm.com,
	devel@edk2.groups.io, Erdem Aktas, James Bottomley, Dong, Eric,
	Ni, Ray, Kumar, Rahul1

On Fri, Oct 29, 2021 at 12:17:05AM +0000, Yao, Jiewen wrote:
> I am OK to use EFI_CC_MEASUREMENT_PROTOCOL to replace EFI_TEE_MEASUREMENT_PROTOCOL. (much better than COCO)

Looks good to me.  The PCD uses the term ConfidentialComputing too,
so using that or 'CC' as shortcut consistently everywhere makes sense.

take care,
  Gerd


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

* Re: [edk2-devel] [PATCH V2 12/28] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VE exception
  2021-10-29  4:52                           ` Gerd Hoffmann
@ 2021-10-29  7:51                             ` Min Xu
  2021-10-29 11:40                               ` Gerd Hoffmann
  0 siblings, 1 reply; 91+ messages in thread
From: Min Xu @ 2021-10-29  7:51 UTC (permalink / raw)
  To: devel@edk2.groups.io, kraxel@redhat.com, Yao, Jiewen
  Cc: Tom Lendacky, Brijesh Singh, sami.mujawar@arm.com, Erdem Aktas,
	James Bottomley, Dong, Eric, Ni, Ray, Kumar, Rahul1

On October 29, 2021 12:53 PM, Gerd Hoffmann wrote:
> On Fri, Oct 29, 2021 at 12:17:05AM +0000, Yao, Jiewen wrote:
> > I am OK to use EFI_CC_MEASUREMENT_PROTOCOL to replace
> > EFI_TEE_MEASUREMENT_PROTOCOL. (much better than COCO)
> 
> Looks good to me.  The PCD uses the term ConfidentialComputing too, so using
> that or 'CC' as shortcut consistently everywhere makes sense.
> 
So do we reach consensus that as the first step, extend the existing VmgExitLib to place the tdx handler (OvmfPkg/Library/VmgExitLib/TdxExitHandler.c). After SNP patch is merged, rename VmgExitLib to CcExitLib. Right?

Thanks.
Min

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

* Re: [edk2-devel] [PATCH V2 12/28] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VE exception
  2021-10-29  7:51                             ` Min Xu
@ 2021-10-29 11:40                               ` Gerd Hoffmann
  0 siblings, 0 replies; 91+ messages in thread
From: Gerd Hoffmann @ 2021-10-29 11:40 UTC (permalink / raw)
  To: Xu, Min M
  Cc: devel@edk2.groups.io, Yao, Jiewen, Tom Lendacky, Brijesh Singh,
	sami.mujawar@arm.com, Erdem Aktas, James Bottomley, Dong, Eric,
	Ni, Ray, Kumar, Rahul1

On Fri, Oct 29, 2021 at 07:51:13AM +0000, Xu, Min M wrote:
> On October 29, 2021 12:53 PM, Gerd Hoffmann wrote:
> > On Fri, Oct 29, 2021 at 12:17:05AM +0000, Yao, Jiewen wrote:
> > > I am OK to use EFI_CC_MEASUREMENT_PROTOCOL to replace
> > > EFI_TEE_MEASUREMENT_PROTOCOL. (much better than COCO)
> > 
> > Looks good to me.  The PCD uses the term ConfidentialComputing too, so using
> > that or 'CC' as shortcut consistently everywhere makes sense.
> > 
> So do we reach consensus that as the first step, extend the existing
> VmgExitLib to place the tdx handler
> (OvmfPkg/Library/VmgExitLib/TdxExitHandler.c). After SNP patch is
> merged, rename VmgExitLib to CcExitLib. Right?

snp series goes first.

Whenever adding TdxExitHandler.c or renaming the library goes next
doesn't matter much, just do whatever is easier for you.

The renaming can be a separate series, so maybe easiest to do that
first and merge quickly so you have less unmerged patches to handle.

take care,
  Gerd


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

* Re: [edk2-devel] [PATCH V2 12/28] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VE exception
  2021-10-29  0:17                         ` Yao, Jiewen
  2021-10-29  4:52                           ` Gerd Hoffmann
@ 2021-11-01 13:54                           ` Sami Mujawar
  2021-11-01 13:57                             ` Yao, Jiewen
  1 sibling, 1 reply; 91+ messages in thread
From: Sami Mujawar @ 2021-11-01 13:54 UTC (permalink / raw)
  To: Yao, Jiewen, Tom Lendacky, Brijesh Singh, kraxel@redhat.com,
	Xu, Min M
  Cc: devel@edk2.groups.io, Erdem Aktas, James Bottomley, Dong, Eric,
	Ni, Ray, Kumar, Rahul1, nd

Hi Jiewen,

I agree using CC as in (EFI_CC_MEASUREMENT_PROTOCOL) would be much clearer.

Regards,

Sami Mujawar

On 29/10/2021, 01:17, "Yao, Jiewen" <jiewen.yao@intel.com> wrote:

    I am OK to use EFI_CC_MEASUREMENT_PROTOCOL to replace EFI_TEE_MEASUREMENT_PROTOCOL. (much better than COCO)

    Samy
    What do you think?



    > -----Original Message-----
    > From: Tom Lendacky <thomas.lendacky@amd.com>
    > Sent: Friday, October 29, 2021 2:29 AM
    > To: Yao, Jiewen <jiewen.yao@intel.com>; Brijesh Singh
    > <brijesh.singh@amd.com>; kraxel@redhat.com; Xu, Min M
    > <min.m.xu@intel.com>
    > Cc: devel@edk2.groups.io; Erdem Aktas <erdemaktas@google.com>; James
    > Bottomley <jejb@linux.ibm.com>; Dong, Eric <eric.dong@intel.com>; Ni, Ray
    > <ray.ni@intel.com>; Kumar, Rahul1 <rahul1.kumar@intel.com>
    > Subject: Re: [edk2-devel] [PATCH V2 12/28] UefiCpuPkg/CpuExceptionHandler:
    > Add base support for the #VE exception
    > 
    > On 10/28/21 10:52 AM, Yao, Jiewen wrote:
    > > Thanks Brijesh.
    > >
    > > We can merge SNP patches at first, then decide next step. Not a problem.
    > >
    > > TEE is just my initial thought. And I am open to change if we have a better
    > name.
    > >
    > > We already have EFI_TEE_MEASUREMENT_PROTOCOL. I did not see your
    > feedback on that. So I assume you agree with that.
    > >
    > > If you have different idea, please feedback to this patch. I hope we have one
    > name.
    > >
    > > COCO seems weird to me, btw. :(
    > 
    > Like Brijesh, I worry about confusion with the ARM TEE feature. Maybe just
    > CC then?
    > 
    > Thanks,
    > Tom
    > 
    > >
    > > Thank you
    > > Yao Jiewen
    > >
    > >> -----Original Message-----
    > >> From: Brijesh Singh <brijesh.singh@amd.com>
    > >> Sent: Thursday, October 28, 2021 11:35 PM
    > >> To: Yao, Jiewen <jiewen.yao@intel.com>; kraxel@redhat.com; Xu, Min M
    > >> <min.m.xu@intel.com>
    > >> Cc: brijesh.singh@amd.com; devel@edk2.groups.io; Erdem Aktas
    > >> <erdemaktas@google.com>; James Bottomley <jejb@linux.ibm.com>; Tom
    > >> Lendacky <thomas.lendacky@amd.com>; Dong, Eric <eric.dong@intel.com>;
    > Ni,
    > >> Ray <ray.ni@intel.com>; Kumar, Rahul1 <rahul1.kumar@intel.com>
    > >> Subject: Re: [edk2-devel] [PATCH V2 12/28]
    > UefiCpuPkg/CpuExceptionHandler:
    > >> Add base support for the #VE exception
    > >>
    > >>
    > >>
    > >> On 10/27/21 8:59 PM, Yao, Jiewen wrote:
    > >>> Hi Gerd
    > >>> I tend to agree with you on the direction to use one TEE specific Exception
    > lib.
    > >>>
    > >>> However, I have naming concern.
    > >>> The VMG is very SEV specific term. I don't believe it is a right name to cover
    > >> the TEE exception lib.
    > >>>
    > >>> If Brijesh agree to merge, I think we should rename it to a neutral name,
    > such
    > >> as TeeExitLib.
    > >>>
    > >>> What do you think, Brijesh?
    > >>
    > >> I am good with merging both the TDX and SEV feature into one library but
    > >> I am not sure about the "TEE" name in it. TEE generally is used on the
    > >> ARM. In Linux kernel and everywhere else we have been using the COCO
    > >> (Confidential Computing), so something along that line makes much more
    > >> sense.
    > >>
    > >> We can rename the library after the SNP patches are merged. I would
    > >> prefer to avoid renaming because all of the SNP patches are Ack-ed.
    > >>
    > >> -Brijesh
    > >>>
    > >>> Thank you
    > >>> Yao Jiewen
    > >>>
    > >>>
    > >>>> -----Original Message-----
    > >>>> From: kraxel@redhat.com <kraxel@redhat.com>
    > >>>> Sent: Wednesday, October 27, 2021 3:20 PM
    > >>>> To: Xu, Min M <min.m.xu@intel.com>
    > >>>> Cc: Brijesh Singh <brijesh.singh@amd.com>; Yao, Jiewen
    > >>>> <jiewen.yao@intel.com>; devel@edk2.groups.io; Erdem Aktas
    > >>>> <erdemaktas@google.com>; James Bottomley <jejb@linux.ibm.com>;
    > Tom
    > >>>> Lendacky <thomas.lendacky@amd.com>; Dong, Eric
    > <eric.dong@intel.com>;
    > >> Ni,
    > >>>> Ray <ray.ni@intel.com>; Kumar, Rahul1 <rahul1.kumar@intel.com>
    > >>>> Subject: Re: [edk2-devel] [PATCH V2 12/28]
    > >> UefiCpuPkg/CpuExceptionHandler:
    > >>>> Add base support for the #VE exception
    > >>>>
    > >>>>     Hi,
    > >>>>
    > >>>>>> How about adding the tdx exception handler to the existing library, so
    > we
    > >>>> don't
    > >>>>>> have the churn of adding a new library everywhere *again*?
    > >>>>
    > >>>>> Do you mean add the VmTdExitVeHandler.c/VmTdExitLibNull.c in
    > >>>> CpuExceptionHandlerLib, then include the corresponding source file in
    > each
    > >>>> *CpuExceptionHandlerLib.inf?
    > >>>>
    > >>>> No, I mean extend the existing VmgExitLib instead of adding a new
    > >>>> VmTdExitLib, i.e. place the tdx handler in
    > >>>> OvmfPkg/Library/VmgExitLib/TdxExitHandler.c
    > >>>>
    > >>>> take care,
    > >>>>     Gerd
    > >>>


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

* Re: [edk2-devel] [PATCH V2 12/28] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VE exception
  2021-11-01 13:54                           ` Sami Mujawar
@ 2021-11-01 13:57                             ` Yao, Jiewen
  0 siblings, 0 replies; 91+ messages in thread
From: Yao, Jiewen @ 2021-11-01 13:57 UTC (permalink / raw)
  To: Sami Mujawar, Tom Lendacky, Brijesh Singh, kraxel@redhat.com,
	Xu, Min M
  Cc: devel@edk2.groups.io, Erdem Aktas, James Bottomley, Dong, Eric,
	Ni, Ray, Kumar, Rahul1, nd

Great. It seems we are all aligned.

> -----Original Message-----
> From: Sami Mujawar <Sami.Mujawar@arm.com>
> Sent: Monday, November 1, 2021 9:55 PM
> To: Yao, Jiewen <jiewen.yao@intel.com>; Tom Lendacky
> <thomas.lendacky@amd.com>; Brijesh Singh <brijesh.singh@amd.com>;
> kraxel@redhat.com; Xu, Min M <min.m.xu@intel.com>
> Cc: devel@edk2.groups.io; Erdem Aktas <erdemaktas@google.com>; James
> Bottomley <jejb@linux.ibm.com>; Dong, Eric <eric.dong@intel.com>; Ni, Ray
> <ray.ni@intel.com>; Kumar, Rahul1 <rahul1.kumar@intel.com>; nd
> <nd@arm.com>
> Subject: Re: [edk2-devel] [PATCH V2 12/28] UefiCpuPkg/CpuExceptionHandler:
> Add base support for the #VE exception
> 
> Hi Jiewen,
> 
> I agree using CC as in (EFI_CC_MEASUREMENT_PROTOCOL) would be much
> clearer.
> 
> Regards,
> 
> Sami Mujawar
> 
> On 29/10/2021, 01:17, "Yao, Jiewen" <jiewen.yao@intel.com> wrote:
> 
>     I am OK to use EFI_CC_MEASUREMENT_PROTOCOL to replace
> EFI_TEE_MEASUREMENT_PROTOCOL. (much better than COCO)
> 
>     Samy
>     What do you think?
> 
> 
> 
>     > -----Original Message-----
>     > From: Tom Lendacky <thomas.lendacky@amd.com>
>     > Sent: Friday, October 29, 2021 2:29 AM
>     > To: Yao, Jiewen <jiewen.yao@intel.com>; Brijesh Singh
>     > <brijesh.singh@amd.com>; kraxel@redhat.com; Xu, Min M
>     > <min.m.xu@intel.com>
>     > Cc: devel@edk2.groups.io; Erdem Aktas <erdemaktas@google.com>; James
>     > Bottomley <jejb@linux.ibm.com>; Dong, Eric <eric.dong@intel.com>; Ni,
> Ray
>     > <ray.ni@intel.com>; Kumar, Rahul1 <rahul1.kumar@intel.com>
>     > Subject: Re: [edk2-devel] [PATCH V2 12/28]
> UefiCpuPkg/CpuExceptionHandler:
>     > Add base support for the #VE exception
>     >
>     > On 10/28/21 10:52 AM, Yao, Jiewen wrote:
>     > > Thanks Brijesh.
>     > >
>     > > We can merge SNP patches at first, then decide next step. Not a problem.
>     > >
>     > > TEE is just my initial thought. And I am open to change if we have a better
>     > name.
>     > >
>     > > We already have EFI_TEE_MEASUREMENT_PROTOCOL. I did not see your
>     > feedback on that. So I assume you agree with that.
>     > >
>     > > If you have different idea, please feedback to this patch. I hope we have
> one
>     > name.
>     > >
>     > > COCO seems weird to me, btw. :(
>     >
>     > Like Brijesh, I worry about confusion with the ARM TEE feature. Maybe just
>     > CC then?
>     >
>     > Thanks,
>     > Tom
>     >
>     > >
>     > > Thank you
>     > > Yao Jiewen
>     > >
>     > >> -----Original Message-----
>     > >> From: Brijesh Singh <brijesh.singh@amd.com>
>     > >> Sent: Thursday, October 28, 2021 11:35 PM
>     > >> To: Yao, Jiewen <jiewen.yao@intel.com>; kraxel@redhat.com; Xu, Min
> M
>     > >> <min.m.xu@intel.com>
>     > >> Cc: brijesh.singh@amd.com; devel@edk2.groups.io; Erdem Aktas
>     > >> <erdemaktas@google.com>; James Bottomley <jejb@linux.ibm.com>;
> Tom
>     > >> Lendacky <thomas.lendacky@amd.com>; Dong, Eric
> <eric.dong@intel.com>;
>     > Ni,
>     > >> Ray <ray.ni@intel.com>; Kumar, Rahul1 <rahul1.kumar@intel.com>
>     > >> Subject: Re: [edk2-devel] [PATCH V2 12/28]
>     > UefiCpuPkg/CpuExceptionHandler:
>     > >> Add base support for the #VE exception
>     > >>
>     > >>
>     > >>
>     > >> On 10/27/21 8:59 PM, Yao, Jiewen wrote:
>     > >>> Hi Gerd
>     > >>> I tend to agree with you on the direction to use one TEE specific
> Exception
>     > lib.
>     > >>>
>     > >>> However, I have naming concern.
>     > >>> The VMG is very SEV specific term. I don't believe it is a right name to
> cover
>     > >> the TEE exception lib.
>     > >>>
>     > >>> If Brijesh agree to merge, I think we should rename it to a neutral name,
>     > such
>     > >> as TeeExitLib.
>     > >>>
>     > >>> What do you think, Brijesh?
>     > >>
>     > >> I am good with merging both the TDX and SEV feature into one library but
>     > >> I am not sure about the "TEE" name in it. TEE generally is used on the
>     > >> ARM. In Linux kernel and everywhere else we have been using the COCO
>     > >> (Confidential Computing), so something along that line makes much more
>     > >> sense.
>     > >>
>     > >> We can rename the library after the SNP patches are merged. I would
>     > >> prefer to avoid renaming because all of the SNP patches are Ack-ed.
>     > >>
>     > >> -Brijesh
>     > >>>
>     > >>> Thank you
>     > >>> Yao Jiewen
>     > >>>
>     > >>>
>     > >>>> -----Original Message-----
>     > >>>> From: kraxel@redhat.com <kraxel@redhat.com>
>     > >>>> Sent: Wednesday, October 27, 2021 3:20 PM
>     > >>>> To: Xu, Min M <min.m.xu@intel.com>
>     > >>>> Cc: Brijesh Singh <brijesh.singh@amd.com>; Yao, Jiewen
>     > >>>> <jiewen.yao@intel.com>; devel@edk2.groups.io; Erdem Aktas
>     > >>>> <erdemaktas@google.com>; James Bottomley <jejb@linux.ibm.com>;
>     > Tom
>     > >>>> Lendacky <thomas.lendacky@amd.com>; Dong, Eric
>     > <eric.dong@intel.com>;
>     > >> Ni,
>     > >>>> Ray <ray.ni@intel.com>; Kumar, Rahul1 <rahul1.kumar@intel.com>
>     > >>>> Subject: Re: [edk2-devel] [PATCH V2 12/28]
>     > >> UefiCpuPkg/CpuExceptionHandler:
>     > >>>> Add base support for the #VE exception
>     > >>>>
>     > >>>>     Hi,
>     > >>>>
>     > >>>>>> How about adding the tdx exception handler to the existing library,
> so
>     > we
>     > >>>> don't
>     > >>>>>> have the churn of adding a new library everywhere *again*?
>     > >>>>
>     > >>>>> Do you mean add the VmTdExitVeHandler.c/VmTdExitLibNull.c in
>     > >>>> CpuExceptionHandlerLib, then include the corresponding source file in
>     > each
>     > >>>> *CpuExceptionHandlerLib.inf?
>     > >>>>
>     > >>>> No, I mean extend the existing VmgExitLib instead of adding a new
>     > >>>> VmTdExitLib, i.e. place the tdx handler in
>     > >>>> OvmfPkg/Library/VmgExitLib/TdxExitHandler.c
>     > >>>>
>     > >>>> take care,
>     > >>>>     Gerd
>     > >>>


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

end of thread, other threads:[~2021-11-01 13:57 UTC | newest]

Thread overview: 91+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2021-10-05  3:39 [PATCH V2 00/28] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
2021-10-05  3:39 ` [PATCH V2 01/28] OvmfPkg: Copy Main.asm from UefiCpuPkg to OvmfPkg's ResetVector Min Xu
2021-10-05  3:39 ` [PATCH V2 02/28] OvmfPkg: Enable TDX in ResetVector Min Xu
2021-10-05  3:39 ` [PATCH V2 03/28] OvmfPkg: Merge TEMP_MEM entries in Tdx metadata Min Xu
2021-10-05  3:39 ` [PATCH V2 04/28] MdePkg: Add Tdx.h Min Xu
2021-10-12  7:48   ` [edk2-devel] " Gerd Hoffmann
2021-10-05  3:39 ` [PATCH V2 05/28] MdePkg: Add TdxLib to wrap Tdx operations Min Xu
2021-10-12  8:22   ` [edk2-devel] " Gerd Hoffmann
2021-10-13 12:13     ` Min Xu
2021-10-14  5:30       ` Gerd Hoffmann
2021-10-22  2:06         ` Min Xu
2021-10-05  3:39 ` [PATCH V2 06/28] MdePkg: Update BaseIoLibIntrinsicSev to support Tdx Min Xu
2021-10-12 10:05   ` [edk2-devel] " Gerd Hoffmann
2021-10-13 13:40     ` Min Xu
2021-10-14  5:37       ` Gerd Hoffmann
2021-10-14  6:24         ` Min Xu
2021-10-14  9:03           ` Gerd Hoffmann
2021-10-22  5:23         ` Min Xu
2021-10-05  3:39 ` [PATCH V2 07/28] UefiCpuPkg: Support TDX in BaseXApicX2ApicLib Min Xu
2021-10-12 10:15   ` [edk2-devel] " Gerd Hoffmann
2021-10-13 14:06     ` Min Xu
2021-10-13  5:30   ` Ni, Ray
2021-10-14  7:58     ` Min Xu
2021-10-05  3:39 ` [PATCH V2 08/28] UefiCpuPkg: Add VmTdExitLibNull Min Xu
2021-10-05  3:39 ` [PATCH V2 09/28] UefiPayloadPkg: Prepare UefiPayloadPkg to use the VmTdExitLib library Min Xu
2021-10-05  3:39 ` [PATCH V2 10/28] OvmfPkg: Prepare OvmfPkg " Min Xu
2021-10-05  3:39 ` [PATCH V2 11/28] OvmfPkg: Implement library support for VmTdExitLib in Ovmf Min Xu
2021-10-05  3:39 ` [PATCH V2 12/28] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VE exception Min Xu
2021-10-12 10:27   ` [edk2-devel] " Gerd Hoffmann
2021-10-26  5:06     ` Min Xu
2021-10-26  6:11       ` Gerd Hoffmann
2021-10-26  8:23         ` Min Xu
2021-10-26 10:24           ` Gerd Hoffmann
2021-10-26 12:09             ` Min Xu
2021-10-27  7:19               ` Gerd Hoffmann
2021-10-28  1:59                 ` Yao, Jiewen
2021-10-28 15:35                   ` Brijesh Singh
2021-10-28 15:52                     ` Yao, Jiewen
2021-10-28 18:28                       ` Lendacky, Thomas
2021-10-29  0:17                         ` Yao, Jiewen
2021-10-29  4:52                           ` Gerd Hoffmann
2021-10-29  7:51                             ` Min Xu
2021-10-29 11:40                               ` Gerd Hoffmann
2021-11-01 13:54                           ` Sami Mujawar
2021-11-01 13:57                             ` Yao, Jiewen
     [not found]                         ` <16B2583BF2C9DB9C.5572@groups.io>
2021-10-29  0:20                           ` Yao, Jiewen
2021-10-29  0:25                             ` Brijesh Singh
     [not found]                 ` <16B20F4407499229.28171@groups.io>
2021-10-28  2:07                   ` Yao, Jiewen
2021-10-28  8:24                     ` Gerd Hoffmann
2021-10-05  3:39 ` [PATCH V2 13/28] UefiCpuPkg: Enable Tdx support in MpInitLib Min Xu
2021-10-12 10:31   ` [edk2-devel] " Gerd Hoffmann
2021-10-14  0:27     ` Min Xu
2021-10-14  6:04       ` Gerd Hoffmann
2021-10-14  6:31         ` Min Xu
2021-10-14  6:56           ` Gerd Hoffmann
2021-10-13  6:01   ` Ni, Ray
2021-10-14  8:22     ` Min Xu
2021-10-05  3:39 ` [PATCH V2 14/28] OvmfPkg: Update SecEntry.nasm to support Tdx Min Xu
2021-10-12 10:38   ` [edk2-devel] " Gerd Hoffmann
2021-10-14  0:55     ` Min Xu
2021-10-14  6:51       ` Gerd Hoffmann
2021-10-05  3:39 ` [PATCH V2 15/28] OvmfPkg: Add IntelTdx.h in OvmfPkg/Include/IndustryStandard Min Xu
2021-10-05  3:39 ` [PATCH V2 16/28] OvmfPkg: Add TdxMailboxLib Min Xu
2021-10-05  3:39 ` [PATCH V2 17/28] MdePkg: Add EFI_RESOURCE_ATTRIBUTE_ENCRYPTED in PiHob.h Min Xu
2021-10-05  3:39 ` [PATCH V2 18/28] OvmfPkg: Enable Tdx in SecMain.c Min Xu
2021-10-05  3:39 ` [PATCH V2 19/28] OvmfPkg: Check Tdx in QemuFwCfgPei to avoid DMA operation Min Xu
2021-10-05  3:39 ` [PATCH V2 20/28] MdeModulePkg: EFER should not be changed in TDX Min Xu
2021-10-05  3:39 ` [PATCH V2 21/28] OvmfPkg: Update PlatformPei to support TDX Min Xu
2021-10-13  4:49   ` [edk2-devel] " Gerd Hoffmann
2021-10-15  1:31     ` Yao, Jiewen
2021-10-15  5:45       ` Gerd Hoffmann
2021-10-15  6:41         ` Yao, Jiewen
2021-10-05  3:39 ` [PATCH V2 22/28] UefiCpuPkg: Define ConfidentialComputingGuestAttr (Temp) Min Xu
2021-10-05  3:39 ` [PATCH V2 23/28] OvmfPkg: Update AcpiPlatformDxe to alter MADT table Min Xu
2021-10-05  3:39 ` [PATCH V2 24/28] OvmfPkg: Add TdxDxe driver Min Xu
2021-10-12 11:50   ` [edk2-devel] " Gerd Hoffmann
2021-10-18  8:38     ` Min Xu
2021-10-05  3:39 ` [PATCH V2 25/28] OvmfPkg/BaseMemEncryptTdxLib: Add TDX helper library Min Xu
2021-10-12 12:13   ` [edk2-devel] " Gerd Hoffmann
2021-10-05  3:39 ` [PATCH V2 26/28] OvmfPkg/QemuFwCfgLib: Support Tdx in QemuFwCfgDxe Min Xu
2021-10-05  3:39 ` [PATCH V2 27/28] OvmfPkg: Update IoMmuDxe to support TDX Min Xu
2021-10-12 12:15   ` [edk2-devel] " Gerd Hoffmann
2021-10-14  2:11     ` Min Xu
2021-10-05  3:39 ` [PATCH V2 28/28] OvmfPkg: Add LocalApicTimerDxe Min Xu
2021-10-12 13:02   ` [edk2-devel] " Gerd Hoffmann
2021-10-14  5:20     ` Min Xu
2021-10-15  1:21       ` Yao, Jiewen
2021-10-25  7:37     ` Min Xu
2021-10-25 11:27       ` Gerd Hoffmann
2021-10-26  1:29         ` Min Xu
2021-10-26  5:50           ` Gerd Hoffmann

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