public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [PATCH 00/23] Enable Intel TDX in OvmfPkg (SEC/PEI)
@ 2021-08-12 11:56 Min Xu
  2021-08-12 11:56 ` [PATCH 01/23] OvmfPkg: Add Tdx BFV/CFV PCDs and PcdOvmfImageSizeInKb Min Xu
                   ` (23 more replies)
  0 siblings, 24 replies; 64+ messages in thread
From: Min Xu @ 2021-08-12 11:56 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Brijesh Singh, Eric Dong, Erdem Aktas, Hao A Wu,
	Jian J Wang, James Bottomley, Jiewen Yao, Liming Gao,
	Michael D Kinney, Ray Ni, Rahul Kumar, Tom Lendacky, Zhiguang Liu

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.

The patch-sets to support Intel TDX in OvmfPkg is split into several
waves. This is Wave-2 which enables Intel TDX in SEC/PEI phases of
OvmfPkgX64. (This is because Intel TDX is only available on X64).

Note:
As mentioned above the whole TDX Virtual Firmware upstream to EDK2 is
splitted into several waves. Wave-1 is focused on the changes in
OvmfPkg/ResetVector. It is still in review. (Hope we can finish it soon).
Wave-2 is focused on the changes in SEC/PEI phases. To make the review
more efficient we send Wave-2 before the review of Wave-1 is finished.
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 - 23 are changes for PEI phase.

Patch 04:
Tdx.h is added in the patch which 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

Patch 05:
It provides *TdxIsEnabled* to determine Td or Non-Td by a new CPUID
leaf(0x21).

Patch 06:
TdxLib is provided in this patch to wrap the functions which perform the
related Tdx operation.

Patch 07:
TDVF chooses para-virtualized I/O which use the TDG.VP.VMCALL function
to invoke the funtions provided by the host VMM to perform I/O.
BaseIoLibIntrinsicSev.inf is updated to support the I/O in Tdx guest.
Some null stub are also added in BaseIoLibIntrinsic.inf to prevent the
broken of build process.

Patch 08:
In this patch BaseXApicX2ApicLib is updated to support Intel TDX. The
major change is access to MSR because some MSR should be accessed via
explicit requests from the host VMM using TDCALL(TDG.VP.VMCALL).

Patch 09 - 12:
These patches add VmTdExitLib library and add base support to handle #VE
exceptions under the help of VmTdExitLib.

Patch 13:
This patch enable Tdx support in MpInitLib.

Patch 14:
In this patch 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.
They wait for command to see if the command is for me. If so execute
the command.

Patch 15:
IntelTdx.h is added to define the defitions used by TDX in OvmfPkg.

Patch 16:
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.

Patch 17:
In this patch EFI_RESOURCE_ATTRIBUTE_ENCRYPTED is added which indicates
the attribute of Physical memory encrypted.

Patch 18:
Now we're ready to update SecMain.c to support Intel TDX. The major
changes of this patch is to accept the private memory described in
Td hoblist. Then TDVF follow the standard OVMF flow and jump to PEI
phase.

Patch 19:
This patch checks Tdx in QemuFwCfgPei to avoid DMA operation. 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).

Patch 20:
A new function - AllocatePagesWithMemoryType - is added in
PeiMemoryAllocationLib. This is because when doing RelocateMailbox,
the memory of ACPI Nvs need be allocated.

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

Patch 22:
In TDX IA32_ERER is RO to host VMM. It could not be changed. A new PCD -
PcdIa32EferChangeAllowed - is added in MdeModulePkg.dec and it will be
set to FALSE in Tdx guest.

Patch 23:
Intel TDX has its own requirement in InitializePlatform (PlatformPei).
 - Publish the ram region
 - Relocate mailbox
 - Create PlatformInfoHob

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

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

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

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 (23):
  OvmfPkg: Add Tdx BFV/CFV PCDs and PcdOvmfImageSizeInKb
  OvmfPkg/Sec: Update the check logic in SevEsIsEnabled
  OvmfPkg/ResetVector: Enable Intel TDX in ResetVector of Ovmf
  MdePkg: Add Tdx.h
  MdePkg: Add TdxProbeLib to probe Intel Tdx
  MdePkg: Add TdxLib to wrap Tdx operations
  MdePkg: Update BaseIoLibIntrinsicSev to support Tdx
  UefiCpuPkg: Support TDX in BaseXApicX2ApicLib
  UefiCpuPkg: Add VmTdExitLibNull
  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
  MdePkg: Add AllocatePagesWithMemoryType support in
    PeiMemoryAllocationLib
  OvmfPkg: Add PcdUse1GPageTable support for TDX
  MdeModulePkg: EFER should not be changed in TDX
  OvmfPkg: Update PlatformPei to support TDX

 MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf       |   1 +
 .../Core/DxeIplPeim/X64/VirtualMemory.c       |   6 +
 MdeModulePkg/MdeModulePkg.dec                 |   5 +
 MdePkg/Include/IndustryStandard/Tdx.h         | 200 +++++
 MdePkg/Include/Library/MemoryAllocationLib.h  |  21 +
 MdePkg/Include/Library/TdxLib.h               | 167 +++++
 MdePkg/Include/Library/TdxProbeLib.h          |  25 +
 MdePkg/Include/Pi/PiHob.h                     |   8 +
 .../BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf |   2 +
 .../BaseIoLibIntrinsicSev.inf                 |   6 +-
 MdePkg/Library/BaseIoLibIntrinsic/IoLib.c     |  97 ++-
 MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c  |  49 +-
 .../BaseIoLibIntrinsic/IoLibInternalTdx.c     | 690 ++++++++++++++++++
 .../BaseIoLibIntrinsic/IoLibInternalTdxNull.c | 499 +++++++++++++
 MdePkg/Library/BaseIoLibIntrinsic/IoLibMsc.c  |  73 +-
 MdePkg/Library/BaseIoLibIntrinsic/IoLibTdx.h  | 411 +++++++++++
 .../BaseIoLibIntrinsic/X64/IoFifoSev.nasm     | 133 ++++
 .../MemoryAllocationLib.c                     |  27 +
 MdePkg/Library/TdxLib/AcceptPages.c           | 136 ++++
 MdePkg/Library/TdxLib/Rtmr.c                  | 118 +++
 MdePkg/Library/TdxLib/TdInfo.c                | 101 +++
 MdePkg/Library/TdxLib/TdxLib.inf              |  39 +
 MdePkg/Library/TdxLib/TdxLibNull.c            | 192 +++++
 MdePkg/Library/TdxLib/X64/Tdcall.nasm         | 120 +++
 MdePkg/Library/TdxLib/X64/Tdvmcall.nasm       | 206 ++++++
 MdePkg/Library/TdxProbeLib/InternalTdxProbe.h |  25 +
 MdePkg/Library/TdxProbeLib/TdProbeNull.c      |  25 +
 MdePkg/Library/TdxProbeLib/TdxProbeLib.c      |  35 +
 MdePkg/Library/TdxProbeLib/TdxProbeLib.inf    |  34 +
 MdePkg/Library/TdxProbeLib/X64/TdProbe.nasm   |  97 +++
 MdePkg/MdePkg.dec                             |   6 +
 MdePkg/MdePkg.dsc                             |   2 +
 OvmfPkg/Include/IndustryStandard/IntelTdx.h   |  77 ++
 OvmfPkg/Include/Library/TdxMailboxLib.h       |  75 ++
 OvmfPkg/Include/TdxCommondefs.inc             |  51 ++
 OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPei.c   |  15 +
 .../Library/QemuFwCfgLib/QemuFwCfgPeiLib.inf  |   1 +
 OvmfPkg/Library/TdxMailboxLib/TdxMailbox.c    | 138 ++++
 .../Library/TdxMailboxLib/TdxMailboxLib.inf   |  52 ++
 .../Library/TdxMailboxLib/TdxMailboxNull.c    |  86 +++
 OvmfPkg/Library/VmTdExitLib/VmTdExitLib.inf   |  41 ++
 .../Library/VmTdExitLib/VmTdExitVeHandler.c   | 515 +++++++++++++
 OvmfPkg/OvmfPkg.dec                           |  27 +
 OvmfPkg/OvmfPkgDefines.fdf.inc                |  10 +
 OvmfPkg/OvmfPkgIa32.dsc                       |   4 +
 OvmfPkg/OvmfPkgIa32X64.dsc                    |   4 +
 OvmfPkg/OvmfPkgX64.dsc                        |   8 +
 OvmfPkg/OvmfXen.dsc                           |   1 +
 OvmfPkg/PlatformPei/FeatureControl.c          |   9 +-
 OvmfPkg/PlatformPei/IntelTdx.c                | 268 +++++++
 OvmfPkg/PlatformPei/IntelTdxNull.c            |  35 +
 OvmfPkg/PlatformPei/MemDetect.c               |  20 +-
 OvmfPkg/PlatformPei/Platform.c                |   2 +
 OvmfPkg/PlatformPei/Platform.h                |  17 +
 OvmfPkg/PlatformPei/PlatformPei.inf           |  14 +
 OvmfPkg/PlatformPei/X64/ApRunLoop.nasm        |  83 +++
 OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm  |  39 +
 OvmfPkg/ResetVector/Ia32/AmdSev.asm           |   7 -
 OvmfPkg/ResetVector/Ia32/Flat32ToFlat64.asm   |   9 +
 OvmfPkg/ResetVector/Ia32/IntelTdx.asm         | 265 +++++++
 OvmfPkg/ResetVector/Ia32/PageTables64.asm     | 113 ++-
 OvmfPkg/ResetVector/Main.asm                  | 121 +++
 OvmfPkg/ResetVector/ResetVector.inf           |  12 +-
 OvmfPkg/ResetVector/ResetVector.nasmb         |  48 +-
 OvmfPkg/ResetVector/X64/IntelTdxMetadata.asm  | 110 +++
 OvmfPkg/Sec/IntelTdx.c                        | 608 +++++++++++++++
 OvmfPkg/Sec/IntelTdx.h                        |  33 +
 OvmfPkg/Sec/SecMain.c                         |  45 +-
 OvmfPkg/Sec/SecMain.inf                       |   7 +
 OvmfPkg/Sec/X64/SecEntry.nasm                 | 313 ++++++++
 UefiCpuPkg/Include/Library/VmTdExitLib.h      |  47 ++
 .../BaseXApicX2ApicLib/BaseXApicX2ApicLib.c   | 172 ++++-
 .../BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf |   2 +
 .../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 |   5 +
 UefiCpuPkg/Library/MpInitLib/DxeMpLib.c       |  14 +-
 UefiCpuPkg/Library/MpInitLib/MpIntelTdx.h     | 107 +++
 UefiCpuPkg/Library/MpInitLib/MpLib.c          |  26 +
 UefiCpuPkg/Library/MpInitLib/MpLibTdx.c       | 142 ++++
 UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c   | 117 +++
 UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf |   5 +
 .../Library/MpInitLib/X64/IntelTdcall.nasm    | 120 +++
 .../Library/VmTdExitLibNull/VmTdExitLibNull.c |  37 +
 .../VmTdExitLibNull/VmTdExitLibNull.inf       |  34 +
 UefiCpuPkg/UefiCpuPkg.dec                     |   9 +
 UefiCpuPkg/UefiCpuPkg.dsc                     |   4 +
 92 files changed, 7610 insertions(+), 112 deletions(-)
 create mode 100644 MdePkg/Include/IndustryStandard/Tdx.h
 create mode 100644 MdePkg/Include/Library/TdxLib.h
 create mode 100644 MdePkg/Include/Library/TdxProbeLib.h
 create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdx.c
 create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdxNull.c
 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 MdePkg/Library/TdxProbeLib/InternalTdxProbe.h
 create mode 100644 MdePkg/Library/TdxProbeLib/TdProbeNull.c
 create mode 100644 MdePkg/Library/TdxProbeLib/TdxProbeLib.c
 create mode 100644 MdePkg/Library/TdxProbeLib/TdxProbeLib.inf
 create mode 100644 MdePkg/Library/TdxProbeLib/X64/TdProbe.nasm
 create mode 100644 OvmfPkg/Include/IndustryStandard/IntelTdx.h
 create mode 100644 OvmfPkg/Include/Library/TdxMailboxLib.h
 create mode 100644 OvmfPkg/Include/TdxCommondefs.inc
 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/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 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] 64+ messages in thread

* [PATCH 01/23] OvmfPkg: Add Tdx BFV/CFV PCDs and PcdOvmfImageSizeInKb
  2021-08-12 11:56 [PATCH 00/23] Enable Intel TDX in OvmfPkg (SEC/PEI) Min Xu
@ 2021-08-12 11:56 ` Min Xu
  2021-08-12 11:56 ` [PATCH 02/23] OvmfPkg/Sec: Update the check logic in SevEsIsEnabled Min Xu
                   ` (22 subsequent siblings)
  23 siblings, 0 replies; 64+ messages in thread
From: Min Xu @ 2021-08-12 11:56 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky

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

Tdx Virtual Firmware (TDVF) includes one Firmware Volume (FV) known
as the Boot Firmware Volume (BFV). The FV format is defined in the
UEFI Platform Initialization (PI) spec. BFV includes all TDVF components
required during boot.

TDVF also include a configuration firmware volume (CFV) that is separated
from the BFV. The reason is because the CFV is measured in RTMR, while
the BFV is measured in MRTD.

In practice BFV is the code part of Ovmf image. CFV is the vars part of
Ovmf image (exclude the SPARE part).

PcdOvmfImageSizeInKb is added which is used to calculate the offset
of TdxMetadata in ResetVectorVtf0.asm.

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            | 13 +++++++++++++
 OvmfPkg/OvmfPkgDefines.fdf.inc | 10 ++++++++++
 2 files changed, 23 insertions(+)

diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index 8fb6f257e8e8..ccda130f0ef6 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -329,6 +329,19 @@
   gUefiOvmfPkgTokenSpaceGuid.PcdQemuHashTableBase|0x0|UINT32|0x47
   gUefiOvmfPkgTokenSpaceGuid.PcdQemuHashTableSize|0x0|UINT32|0x48
 
+  ## The base address and size of the TDX Cfv base and size.
+  gUefiOvmfPkgTokenSpaceGuid.PcdCfvBase|0|UINT32|0x49
+  gUefiOvmfPkgTokenSpaceGuid.PcdCfvRawDataOffset|0|UINT32|0x4a
+  gUefiOvmfPkgTokenSpaceGuid.PcdCfvRawDataSize|0|UINT32|0x4b
+
+  ## The base address and size of the TDX Bfv base and size.
+  gUefiOvmfPkgTokenSpaceGuid.PcdBfvBase|0|UINT32|0x4c
+  gUefiOvmfPkgTokenSpaceGuid.PcdBfvRawDataOffset|0|UINT32|0x4d
+  gUefiOvmfPkgTokenSpaceGuid.PcdBfvRawDataSize|0|UINT32|0x4e
+
+  ## Size of the Ovmf image in KB
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfImageSizeInKb|0|UINT32|0x4f
+
 [PcdsDynamic, PcdsDynamicEx]
   gUefiOvmfPkgTokenSpaceGuid.PcdEmuVariableEvent|0|UINT64|2
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashVariablesEnable|FALSE|BOOLEAN|0x10
diff --git a/OvmfPkg/OvmfPkgDefines.fdf.inc b/OvmfPkg/OvmfPkgDefines.fdf.inc
index 35fd454b97ab..777b7755b198 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
@@ -66,6 +67,7 @@ DEFINE SECFV_OFFSET      = 0x003CC000
 DEFINE SECFV_SIZE        = 0x34000
 !endif
 
+SET gUefiOvmfPkgTokenSpaceGuid.PcdOvmfImageSizeInKb     = $(FD_SIZE_IN_KB)
 SET gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFdBaseAddress     = $(FW_BASE_ADDRESS)
 SET gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFirmwareFdSize    = $(FW_SIZE)
 SET gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFirmwareBlockSize = $(BLOCK_SIZE)
@@ -82,6 +84,14 @@ SET gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize = $(BLOCK_SIZ
 SET gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashNvStorageFtwSpareBase = gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashNvStorageFtwWorkingBase + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
 SET gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize = $(VARS_SPARE_SIZE)
 
+SET gUefiOvmfPkgTokenSpaceGuid.PcdCfvBase           = $(FW_BASE_ADDRESS)
+SET gUefiOvmfPkgTokenSpaceGuid.PcdCfvRawDataOffset  = $(VARS_OFFSET)
+SET gUefiOvmfPkgTokenSpaceGuid.PcdCfvRawDataSize    = $(VARS_LIVE_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
-- 
2.29.2.windows.2


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

* [PATCH 02/23] OvmfPkg/Sec: Update the check logic in SevEsIsEnabled
  2021-08-12 11:56 [PATCH 00/23] Enable Intel TDX in OvmfPkg (SEC/PEI) Min Xu
  2021-08-12 11:56 ` [PATCH 01/23] OvmfPkg: Add Tdx BFV/CFV PCDs and PcdOvmfImageSizeInKb Min Xu
@ 2021-08-12 11:56 ` Min Xu
  2021-09-11  1:13   ` Erdem Aktas
  2021-08-12 11:56 ` [PATCH 03/23] OvmfPkg/ResetVector: Enable Intel TDX in ResetVector of Ovmf Min Xu
                   ` (21 subsequent siblings)
  23 siblings, 1 reply; 64+ messages in thread
From: Min Xu @ 2021-08-12 11:56 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky

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

SevEsIsEnabled return TRUE if SevEsWorkArea->SevEsEnabled is non-zero.
It is correct when SevEsWorkArea is only used by SEV. After Intel TDX
is enabled in Ovmf, the SevEsWorkArea is shared by TDX and SEV. (This
is to avoid the waist of memory region in MEMFD). The value of
SevEsWorkArea->SevEsEnabled now is :
 0 if in Legacy guest
 1 if in SEV
 2 if in Tdx guest
That's why the changes is made.

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/Sec/SecMain.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/OvmfPkg/Sec/SecMain.c b/OvmfPkg/Sec/SecMain.c
index 9db67e17b2aa..e166a9389a1a 100644
--- a/OvmfPkg/Sec/SecMain.c
+++ b/OvmfPkg/Sec/SecMain.c
@@ -828,7 +828,7 @@ SevEsIsEnabled (
 
   SevEsWorkArea = (SEC_SEV_ES_WORK_AREA *) FixedPcdGet32 (PcdSevEsWorkAreaBase);
 
-  return ((SevEsWorkArea != NULL) && (SevEsWorkArea->SevEsEnabled != 0));
+  return ((SevEsWorkArea != NULL) && (SevEsWorkArea->SevEsEnabled == 1));
 }
 
 VOID
-- 
2.29.2.windows.2


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

* [PATCH 03/23] OvmfPkg/ResetVector: Enable Intel TDX in ResetVector of Ovmf
  2021-08-12 11:56 [PATCH 00/23] Enable Intel TDX in OvmfPkg (SEC/PEI) Min Xu
  2021-08-12 11:56 ` [PATCH 01/23] OvmfPkg: Add Tdx BFV/CFV PCDs and PcdOvmfImageSizeInKb Min Xu
  2021-08-12 11:56 ` [PATCH 02/23] OvmfPkg/Sec: Update the check logic in SevEsIsEnabled Min Xu
@ 2021-08-12 11:56 ` Min Xu
  2021-09-11  1:14   ` Erdem Aktas
  2021-08-12 11:56 ` [PATCH 04/23] MdePkg: Add Tdx.h Min Xu
                   ` (20 subsequent siblings)
  23 siblings, 1 reply; 64+ messages in thread
From: Min Xu @ 2021-08-12 11:56 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky

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

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.

Note: Intel TDX only is available on X64, so the Tdx related changes are
in X64 path. In IA32 path, there may be null stub to make the build
success.

This patch includes below major changes.

1. CC_WORK_AREA
Ovmf is able to run on different types of VM guest with ONE image. These
VM guest includes the Legacy guest, SEV guest and TDX guest. In
ResetVector CC_WORK_AREA is such a memory region to record the VM guest
information. Below is the definition of the work area.

 typedef struct {
   UINT8   Type;     // 0 legacy, 1 SEV, 2 TDX
   UINT8   SubType;  // Depends on Type
   UINT8   Rsvd[2];  // Reserved
   union VM_GUEST {
     TDX_WORK_AREA Tdx;
     SEV_WORK_AREA Sev;
   } Guest;
 } CC_WORK_AREA_HEAD;

 typedef struct {
   ... ...
 } TDX_WORK_AREA

 typedef struct {
   ... ...
 } SEV_WORK_AREA

2. X64/IntelTdxMetadata.asm
IntelTdxMetadata describes the information about the image for VMM use.
For example, the base address and length of the TdHob, TdMailbox, etc.
Its offset is put in a GUID-ed structure which is appended in the GUID-ed
chain from a fixed GPA (0xffffffd0). Below are the items in TdxMetadata:
 _Bfv:
    Boot Firmware Volume
 _Cfv:
    Configuration Firmware Volume
 _Stack:
    Initial stack
 _Heap:
    Initial heap
 _MailBox:
    TDVF reserves the memory region so each AP can receive the message
    sent by the guest OS.
 _CcWorkarea:
    Compute Confidential work area which is consumed by CC technologies,
    such as SEV, TDX.
 _TdHob:
    VMM pass the resource information in TdHob to TDVF.
 _TdxPageTable:
    If 5-level page table is supported (GPAW is 52), a top level page
    directory pointers (1 * 256TB entry) is generated in this page.
 _OvmfPageTable:
    Initial page table for standard Ovmf.

TDVF indicate above chunk of temporary initialized memory region (_Stack/
_Heap/_MailBox/_CcWorkarea/_TdHob/_TdxPageTables/OvmfPageTable) to support
TDVF code finishing the memory initialization. Because the other
unaccepted memory cannot be accessed until they're accepted.

Since AMD SEV has already defined some SEV specific memory region in
MEMFD. TDX re-use the memory regions defined by SEV.
 - MailBox      : PcdOvmfSecGhcbBackupBase|PcdOvmfSecGhcbBackupSize
 - TdHob        : PcdOvmfSecGhcbBase|PcdOvmfSecGhcbSize
 - TdxPageTable : PcdOvmfSecGhcbPageTableBase|PcdOvmfSecGhcbPageTableSize
 - CcWorkArea   : PcdSevEsWorkAreaBase|PcdSevEsWorkAreaSize

3. Ia32/IntelTdx.asm
IntelTdx.asm includes below routines used in ResetVector
 - IsTdx
   Check if the running system is Tdx guest.

 - InitTdxWorkarea
   It initialize the CC_WORK_AREA. Because it is called by both BSP and
   APs and to avoid the race condition, only BSP can initialize the
   WORK_AREA. AP will wait until the field of TDX_WORK_AREA_PGTBL_READY
   is set.

 - ReloadFlat32
   After reset all CPUs in TDX are initialized to 32-bit protected mode.
   But GDT register is not set. So this routine loads the GDT and set the
   CR0, then jump to Flat 32 protected mode. After that CR4 and other
   registers are set.

 - InitTdx
   This routine wrap above 3 routines together to do Tdx initialization
   in ResetVector phase.

 - PostSetCr3PageTables64Tdx
   It is called after SetCr3PageTables64 in Tdx guest to set CR0/CR4.
   If GPAW is 52, then CR3 is adjusted as well.

 - IsTdxEnabled
   It is a OneTimeCall to probe if TDX is enabled by checking the
   CC_WORK_AREA.

4. Ia32/AmdSev.asm
AmdSev.asm includes the SEV routines used in ResetVector. This patch
remove the code of clearing SEV_ES_WORK_AREA in CheckSevFeatures. The
clearing of SEV_ES_WORK_AREA is called at Main16 in Main.asm.

5. Main.asm
Previously OvmfPkg/ResetVector use the Main.asm in UefiCpuPkg. There is
only Main16 entry point. Main32 entry point is needed in Main.asm because
of Intel TDX. To reduce the complexity of Main.asm in UefiCpuPkg, OvmfPkg
create its own Main.asm to meet the requirement of Intel TDX. There are
below changes in this Main.asm:
 - A new entry point (Main32) is added. TDX guest will jump to Main32
   from ResetVecotr.
 - In Main16 entry point, after TransitionFromReal16To32BitFlat,
   CC_WORK_AREA is cleared to 0.

6. Ia32/PageTables64.asm
GPAW of TDX can be 48 or 52, which determines the level of page table.
If Level-5(GPAW 52) paging is supported, then an extra page is needed
to hold the top level Page Directory Pointers (1 * 256TB entry).

7. Ia16/ResetVectorVtf0.asm
In Tdx all CPUs "reset" to run on 32-bit protected mode with flat
descriptor (paging disabled). But in Non-Td guest the initial state of
CPUs is 16-bit real mode. To resolve this conflict, BITS 16/32 is used
in the ResetVectorVtf0.asm. It checks the 32-bit protected mode or 16-bit
real mode, then jump to the corresponding entry point.

8. ResetVector.nasmb
TDX related macros and files are added in ResetVecotr.nasmb.

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/ResetVector/Ia16/ResetVectorVtf0.asm |  39 +++
 OvmfPkg/ResetVector/Ia32/AmdSev.asm          |   7 -
 OvmfPkg/ResetVector/Ia32/Flat32ToFlat64.asm  |   9 +
 OvmfPkg/ResetVector/Ia32/IntelTdx.asm        | 265 +++++++++++++++++++
 OvmfPkg/ResetVector/Ia32/PageTables64.asm    | 113 +++++---
 OvmfPkg/ResetVector/Main.asm                 | 121 +++++++++
 OvmfPkg/ResetVector/ResetVector.inf          |  12 +-
 OvmfPkg/ResetVector/ResetVector.nasmb        |  48 +++-
 OvmfPkg/ResetVector/X64/IntelTdxMetadata.asm | 110 ++++++++
 9 files changed, 679 insertions(+), 45 deletions(-)
 create mode 100644 OvmfPkg/ResetVector/Ia32/IntelTdx.asm
 create mode 100644 OvmfPkg/ResetVector/Main.asm
 create mode 100644 OvmfPkg/ResetVector/X64/IntelTdxMetadata.asm

diff --git a/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm b/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
index 7ec3c6e980c3..62feeacbee7b 100644
--- a/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
+++ b/OvmfPkg/ResetVector/Ia16/ResetVectorVtf0.asm
@@ -47,6 +47,24 @@ TIMES (15 - ((guidedStructureEnd - guidedStructureStart + 15) % 16)) DB 0
 ;
 guidedStructureStart:
 
+%ifdef ARCH_X64
+;
+; TDX Metadata offset block
+;
+; If TdxMetadata.asm is included then we need below block which describes
+; the offset of TdxMetadata block in Ovmf image
+;
+; GUID : e47a6535-984a-4798-865e-4685a7bf8ec2
+;
+tdxMetadataOffsetStart:
+    DD      (OVMF_IMAGE_SIZE_IN_KB * 1024 - (fourGigabytes - TdxMetadataGuid - 16))
+    DD      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 +176,31 @@ 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
+
+    smsw    ax
+    test    al, 1
+    jz      .Real
+BITS 32
+    jmp     Main32
+BITS 16
+.Real:
+    jmp     EarlyBspInitReal16
+
+%endif
+
 ALIGN   16
 
 fourGigabytes:
diff --git a/OvmfPkg/ResetVector/Ia32/AmdSev.asm b/OvmfPkg/ResetVector/Ia32/AmdSev.asm
index aa95d06eaddb..d0d9890d5c4b 100644
--- a/OvmfPkg/ResetVector/Ia32/AmdSev.asm
+++ b/OvmfPkg/ResetVector/Ia32/AmdSev.asm
@@ -128,13 +128,6 @@ SevEsUnexpectedRespTerminate:
 ; If SEV is disabled then EAX will be zero.
 ;
 CheckSevFeatures:
-    ; Set the first byte of the workarea to zero to communicate to the SEC
-    ; phase that SEV-ES is not enabled. If SEV-ES is enabled, the CPUID
-    ; instruction will trigger a #VC exception where the first byte of the
-    ; workarea will be set to one or, if CPUID is not being intercepted,
-    ; the MSR check below will set the first byte of the workarea to one.
-    mov     byte[SEV_ES_WORK_AREA], 0
-
     ;
     ; Set up exception handlers to check for SEV-ES
     ;   Load temporary RAM stack based on PCDs (see SevEsIdtVmmComm for
diff --git a/OvmfPkg/ResetVector/Ia32/Flat32ToFlat64.asm b/OvmfPkg/ResetVector/Ia32/Flat32ToFlat64.asm
index c6d0d898bcd1..ea8723efd417 100644
--- a/OvmfPkg/ResetVector/Ia32/Flat32ToFlat64.asm
+++ b/OvmfPkg/ResetVector/Ia32/Flat32ToFlat64.asm
@@ -17,6 +17,14 @@ Transition32FlatTo64Flat:
 
     OneTimeCall SetCr3ForPageTables64
 
+    OneTimeCall PostSetCr3PageTables64Tdx
+
+    ;
+    ; If it is TDX, we're done and jump to enable paging
+    ;
+    cmp     byte[CC_WORK_AREA], VM_GUEST_TDX
+    je      EnablePaging
+
     mov     eax, cr4
     bts     eax, 5                      ; enable PAE
     mov     cr4, eax
@@ -71,6 +79,7 @@ jumpTo64BitAndLandHere:
 
     ;
     ; Check if the second step of the SEV-ES mitigation is to be performed.
+    ; If it is Tdx, ebx is cleared in PostSetCr3PageTables64Tdx.
     ;
     test    ebx, ebx
     jz      InsnCompare
diff --git a/OvmfPkg/ResetVector/Ia32/IntelTdx.asm b/OvmfPkg/ResetVector/Ia32/IntelTdx.asm
new file mode 100644
index 000000000000..f40331a5cbce
--- /dev/null
+++ b/OvmfPkg/ResetVector/Ia32/IntelTdx.asm
@@ -0,0 +1,265 @@
+;------------------------------------------------------------------------------
+; @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 zero
+; If it is not Intel Tdx, EAX is non-zero
+;
+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, 0
+    jmp     ExitIsTdx
+
+IsNotTdx:
+    mov     eax, 1
+
+ExitIsTdx:
+
+  OneTimeCallRet IsTdx
+
+;
+; Initialize Tdx work area (CC_WORK_AREA) if it is Tdx guest.
+; BSP and APs all go here. Only BSP can initialize the WORK_AREA
+;
+; typedef struct {
+;   UINT8   Type;     // 0 legacy, 1 SEV, 2 TDX
+;   UINT8   SubType;  // Depends on Type
+;   UINT8   Rsvd[2];  // Reserved
+;   union VM_GUEST {
+;     TDX_WORK_AREA Tdx;
+;     SEV_WORK_AREA Sev;
+;   } Guest;
+; } CC_WORK_AREA_HEAD;
+;
+; typedef struct {
+;   UINT8    IsPageLevel5;
+;   UINT8    IsPageTableReady;
+;   UINT8    Rsvd[2];
+;   UINT32   Gpaw;
+; } TDX_WORK_AREA
+;
+; Param[in] EBP[6: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
+    jnz     ExitInitTdxWorkarea
+
+    ;
+    ; 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.
+    ;
+    cmp     esi, 0
+    je      TdxBspEntry
+
+TdxApWait:
+    cmp     byte[TDX_WORK_AREA_PGTBL_READY], 0
+    je      TdxApWait
+    jmp     ExitInitTdxWorkarea
+
+TdxBspEntry:
+    ;
+    ; Set Type and SubType of CC_WORK_AREA so that the
+    ; following code can use these information.
+    ;
+    mov     byte[CC_WORK_AREA], VM_GUEST_TDX
+    mov     byte[CC_WORK_AREA_SUBTYPE], 0
+
+    ;
+    ; EBP[6:0] CPU supported GPA width
+    ;
+    and     ebp, 0x3f
+    cmp     ebp, 52
+    jl      NotPageLevel5
+    mov     byte[TDX_WORK_AREA_PAGELEVEL5], 1
+
+NotPageLevel5:
+    mov     DWORD[TDX_WORK_AREA_GPAW], ebp
+
+ExitInitTdxWorkarea:
+    OneTimeCallRet InitTdxWorkarea
+
+;
+; Load the GDT and set the CR0, then jump to Flat 32 protected mode.
+;
+; Modified:  EAX, EBX, CR0, CR4, DS, ES, FS, GS, SS
+;
+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
+
+;
+; Called after SetCr3PageTables64 in Tdx guest to set CR0/CR4.
+; If GPAW is 52, then CR3 is adjusted as well.
+;
+; Modified: EAX, EBX, CR0, CR3, CR4
+;
+PostSetCr3PageTables64Tdx:
+    ;
+    ; TDX_WORK_AREA was set in InitTdx if it is Tdx guest
+    ;
+    cmp     byte[CC_WORK_AREA], VM_GUEST_TDX
+    jne     ExitPostSetCr3PageTables64Tdx
+
+    mov     eax, cr4
+    bts     eax, 5                      ; enable PAE
+
+    ;
+    ; byte[TDX_WORK_AREA_PAGELEVEL5] holds the indicator whether 52bit is
+    ; supported. if it is the case, need to set LA57 and use 5-level paging
+    ;
+    cmp     byte[TDX_WORK_AREA_PAGELEVEL5], 0
+    jz      TdxSetCr4
+    bts     eax, 12
+
+TdxSetCr4:
+    mov     cr4, eax
+    mov     ebx, cr3
+
+    ;
+    ; if la57 is not set, we are ok
+    ; if using 5-level paging, adjust top-level page directory
+    ;
+    bt      eax, 12
+    jnc     TdxSetCr3
+    mov     ebx, TDX_PT_ADDR (0)
+
+TdxSetCr3:
+    mov     cr3, ebx
+
+    xor     ebx, ebx
+
+ExitPostSetCr3PageTables64Tdx:
+    OneTimeCallRet PostSetCr3PageTables64Tdx
+
+;
+; 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[CC_WORK_AREA], VM_GUEST_TDX
+    jne     NotTdx
+    mov     eax, 1
+
+NotTdx:
+    OneTimeCallRet IsTdxEnabled
+
diff --git a/OvmfPkg/ResetVector/Ia32/PageTables64.asm b/OvmfPkg/ResetVector/Ia32/PageTables64.asm
index eacdb69ddb9f..1f4c0c50ac2e 100644
--- a/OvmfPkg/ResetVector/Ia32/PageTables64.asm
+++ b/OvmfPkg/ResetVector/Ia32/PageTables64.asm
@@ -37,11 +37,81 @@ BITS    32
                        PAGE_READ_WRITE + \
                        PAGE_PRESENT)
 
+TdxBuildExtraPageTables:
+    ;
+    ; Extra page tables built by Tdx guests
+    ;
+    xor     eax, eax
+    mov     ecx, 0x400
+tdClearTdxPageTablesMemoryLoop:
+    mov     dword [ecx * 4 + TDX_PT_ADDR(0) - 4], eax
+    loop    tdClearTdxPageTablesMemoryLoop
+
+    ;
+    ; Top level Page Directory Pointers (1 * 256TB entry)
+    ;
+    mov     dword[TDX_PT_ADDR (0)], PT_ADDR(0) + PAGE_PDP_ATTR
+
+    ;
+    ; Set TDX_WORK_AREA_PGTBL_READY to notify APs to go
+    ;
+    mov     byte[TDX_WORK_AREA_PGTBL_READY], 1
+
+    OneTimeCallRet TdxBuildExtraPageTables
+
+SevBuildGhcbPageTables:
+    ;
+    ; The initial GHCB will live at GHCB_BASE and needs to be un-encrypted.
+    ; This requires the 2MB page for this range be broken down into 512 4KB
+    ; pages.  All will be marked encrypted, except for the GHCB.
+    ;
+    mov     ecx, (GHCB_BASE >> 21)
+    mov     eax, GHCB_PT_ADDR + PAGE_PDP_ATTR
+    mov     [ecx * 8 + PT_ADDR (0x2000)], eax
+
+    ;
+    ; Page Table Entries (512 * 4KB entries => 2MB)
+    ;
+    mov     ecx, 512
+pageTableEntries4kLoop:
+    mov     eax, ecx
+    dec     eax
+    shl     eax, 12
+    add     eax, GHCB_BASE & 0xFFE0_0000
+    add     eax, PAGE_4K_PDE_ATTR
+    mov     [ecx * 8 + GHCB_PT_ADDR - 8], eax
+    mov     [(ecx * 8 + GHCB_PT_ADDR - 8) + 4], edx
+    loop    pageTableEntries4kLoop
+
+    ;
+    ; Clear the encryption bit from the GHCB entry
+    ;
+    mov     ecx, (GHCB_BASE & 0x1F_FFFF) >> 12
+    mov     [ecx * 8 + GHCB_PT_ADDR + 4], strict dword 0
+
+    mov     ecx, GHCB_SIZE / 4
+    xor     eax, eax
+clearGhcbMemoryLoop:
+    mov     dword[ecx * 4 + GHCB_BASE - 4], eax
+    loop    clearGhcbMemoryLoop
+
+    OneTimeCallRet  SevBuildGhcbPageTables
+
 ;
 ; Modified:  EAX, EBX, ECX, EDX
 ;
 SetCr3ForPageTables64:
 
+    cmp     byte[CC_WORK_AREA], VM_GUEST_TDX
+    jne     CheckSev
+
+    cmp     byte[TDX_WORK_AREA_PGTBL_READY], 1
+    je      SetCr3
+
+    xor     edx, edx
+    jmp     SevNotActive
+
+CheckSev:
     OneTimeCall   CheckSevFeatures
     xor     edx, edx
     test    eax, eax
@@ -101,44 +171,19 @@ pageTableEntriesLoop:
     mov     [(ecx * 8 + PT_ADDR (0x2000 - 8)) + 4], edx
     loop    pageTableEntriesLoop
 
+    OneTimeCall IsTdxEnabled
+    test    eax, eax
+    jz      IsSevEs
+
+    OneTimeCall TdxBuildExtraPageTables
+    jmp     SetCr3
+
+IsSevEs:
     OneTimeCall   IsSevEsEnabled
     test    eax, eax
     jz      SetCr3
 
-    ;
-    ; The initial GHCB will live at GHCB_BASE and needs to be un-encrypted.
-    ; This requires the 2MB page for this range be broken down into 512 4KB
-    ; pages.  All will be marked encrypted, except for the GHCB.
-    ;
-    mov     ecx, (GHCB_BASE >> 21)
-    mov     eax, GHCB_PT_ADDR + PAGE_PDP_ATTR
-    mov     [ecx * 8 + PT_ADDR (0x2000)], eax
-
-    ;
-    ; Page Table Entries (512 * 4KB entries => 2MB)
-    ;
-    mov     ecx, 512
-pageTableEntries4kLoop:
-    mov     eax, ecx
-    dec     eax
-    shl     eax, 12
-    add     eax, GHCB_BASE & 0xFFE0_0000
-    add     eax, PAGE_4K_PDE_ATTR
-    mov     [ecx * 8 + GHCB_PT_ADDR - 8], eax
-    mov     [(ecx * 8 + GHCB_PT_ADDR - 8) + 4], edx
-    loop    pageTableEntries4kLoop
-
-    ;
-    ; Clear the encryption bit from the GHCB entry
-    ;
-    mov     ecx, (GHCB_BASE & 0x1F_FFFF) >> 12
-    mov     [ecx * 8 + GHCB_PT_ADDR + 4], strict dword 0
-
-    mov     ecx, GHCB_SIZE / 4
-    xor     eax, eax
-clearGhcbMemoryLoop:
-    mov     dword[ecx * 4 + GHCB_BASE - 4], eax
-    loop    clearGhcbMemoryLoop
+    OneTimeCall   SevBuildGhcbPageTables
 
 SetCr3:
     ;
diff --git a/OvmfPkg/ResetVector/Main.asm b/OvmfPkg/ResetVector/Main.asm
new file mode 100644
index 000000000000..fb1731728af5
--- /dev/null
+++ b/OvmfPkg/ResetVector/Main.asm
@@ -0,0 +1,121 @@
+;------------------------------------------------------------------------------
+; @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
+%ifdef ARCH_X64
+    ;
+    ; Clear the first 2 bytes of CC_WORK_AREA.
+    ;
+    mov word[CC_WORK_AREA], 0
+
+    jmp SearchBfv
+
+;
+; Entry point of Main32
+;
+Main32:
+    OneTimeCall InitTdx
+
+SearchBfv:
+
+%endif
+    ;
+    ; 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
+
+
diff --git a/OvmfPkg/ResetVector/ResetVector.inf b/OvmfPkg/ResetVector/ResetVector.inf
index d028c92d8cfa..0cf3a8036b97 100644
--- a/OvmfPkg/ResetVector/ResetVector.inf
+++ b/OvmfPkg/ResetVector/ResetVector.inf
@@ -1,7 +1,7 @@
 ## @file
 #  Reset Vector
 #
-#  Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+#  Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>
 #
 #  SPDX-License-Identifier: BSD-2-Clause-Patent
 #
@@ -35,6 +35,7 @@
 
 [Pcd]
   gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase
+  gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaSize
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableBase
@@ -43,6 +44,15 @@
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesSize
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfImageSizeInKb
+  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 acec46a32450..528a6603a20e 100644
--- a/OvmfPkg/ResetVector/ResetVector.nasmb
+++ b/OvmfPkg/ResetVector/ResetVector.nasmb
@@ -67,6 +67,44 @@
     %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_EXTRA_PAGE_TABLE_BASE FixedPcdGet32 (PcdOvmfSecGhcbPageTableBase)
+  %define TDX_EXTRA_PAGE_TABLE_SIZE FixedPcdGet32 (PcdOvmfSecGhcbPageTableSize)
+
+  %define CC_WORK_AREA_MEMORY_BASE  FixedPcdGet32 (PcdSevEsWorkAreaBase)
+  %define CC_WORK_AREA_MEMORY_SIZE  FixedPcdGet32 (PcdSevEsWorkAreaSize)
+  %define CC_WORK_AREA              (CC_WORK_AREA_MEMORY_BASE)
+  %define CC_WORK_AREA_SUBTYPE      (CC_WORK_AREA + 1)
+  %define TDX_WORK_AREA_PAGELEVEL5  (CC_WORK_AREA + 4)
+  %define TDX_WORK_AREA_PGTBL_READY (CC_WORK_AREA + 5)
+  %define TDX_WORK_AREA_GPAW        (CC_WORK_AREA + 8)
+
+  %define TDX_PT_ADDR(Offset)       (TDX_EXTRA_PAGE_TABLE_BASE + (Offset))
+
   %define PT_ADDR(Offset) (FixedPcdGet32 (PcdOvmfSecPageTablesBase) + (Offset))
 
   %define GHCB_PT_ADDR (FixedPcdGet32 (PcdOvmfSecGhcbPageTableBase))
@@ -76,9 +114,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/IntelTdx.asm"
+  %include "Ia32/Flat32ToFlat64.asm"
+  %include "Ia32/AmdSev.asm"
+  %include "Ia32/PageTables64.asm"
 %endif
 
 %include "Ia16/Real16ToFlat32.asm"
@@ -91,5 +132,6 @@
   %define SEV_LAUNCH_SECRET_SIZE  FixedPcdGet32 (PcdSevLaunchSecretSize)
   %define SEV_FW_HASH_BLOCK_BASE  FixedPcdGet32 (PcdQemuHashTableBase)
   %define SEV_FW_HASH_BLOCK_SIZE  FixedPcdGet32 (PcdQemuHashTableSize)
+  %define OVMF_IMAGE_SIZE_IN_KB   FixedPcdGet32 (PcdOvmfImageSizeInKb)
 %include "Ia16/ResetVectorVtf0.asm"
 
diff --git a/OvmfPkg/ResetVector/X64/IntelTdxMetadata.asm b/OvmfPkg/ResetVector/X64/IntelTdxMetadata.asm
new file mode 100644
index 000000000000..97b1e915d899
--- /dev/null
+++ b/OvmfPkg/ResetVector/X64/IntelTdxMetadata.asm
@@ -0,0 +1,110 @@
+;------------------------------------------------------------------------------
+; @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
+
+_CcWorkarea:
+  DD 0
+  DD 0
+  DQ CC_WORK_AREA_MEMORY_BASE
+  DQ CC_WORK_AREA_MEMORY_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
+
+_TdxPageTable:
+  DD 0
+  DD 0
+  DQ TDX_EXTRA_PAGE_TABLE_BASE
+  DQ TDX_EXTRA_PAGE_TABLE_SIZE
+  DD TDX_METADATA_SECTION_TYPE_TEMP_MEM
+  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] 64+ messages in thread

* [PATCH 04/23] MdePkg: Add Tdx.h
  2021-08-12 11:56 [PATCH 00/23] Enable Intel TDX in OvmfPkg (SEC/PEI) Min Xu
                   ` (2 preceding siblings ...)
  2021-08-12 11:56 ` [PATCH 03/23] OvmfPkg/ResetVector: Enable Intel TDX in ResetVector of Ovmf Min Xu
@ 2021-08-12 11:56 ` Min Xu
  2021-08-12 20:52   ` Michael D Kinney
  2021-08-12 11:56 ` [PATCH 05/23] MdePkg: Add TdxProbeLib to probe Intel Tdx Min Xu
                   ` (19 subsequent siblings)
  23 siblings, 1 reply; 64+ messages in thread
From: Min Xu @ 2021-08-12 11:56 UTC (permalink / raw)
  To: devel; +Cc: Min Xu, Michael D Kinney, Liming Gao, Zhiguang Liu

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>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 MdePkg/Include/IndustryStandard/Tdx.h | 200 ++++++++++++++++++++++++++
 1 file changed, 200 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..c50470708b56
--- /dev/null
+++ b/MdePkg/Include/IndustryStandard/Tdx.h
@@ -0,0 +1,200 @@
+/** @file
+  Intel Trust Domain Extension definitions
+
+  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] 64+ messages in thread

* [PATCH 05/23] MdePkg: Add TdxProbeLib to probe Intel Tdx
  2021-08-12 11:56 [PATCH 00/23] Enable Intel TDX in OvmfPkg (SEC/PEI) Min Xu
                   ` (3 preceding siblings ...)
  2021-08-12 11:56 ` [PATCH 04/23] MdePkg: Add Tdx.h Min Xu
@ 2021-08-12 11:56 ` Min Xu
  2021-08-16  9:43   ` [edk2-devel] " Gerd Hoffmann
  2021-09-11  1:14   ` Erdem Aktas
  2021-08-12 11:56 ` [PATCH 06/23] MdePkg: Add TdxLib to wrap Tdx operations Min Xu
                   ` (18 subsequent siblings)
  23 siblings, 2 replies; 64+ messages in thread
From: Min Xu @ 2021-08-12 11:56 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Michael D Kinney, Liming Gao, Zhiguang Liu, Brijesh Singh,
	Erdem Aktas, James Bottomley, Jiewen Yao, Tom Lendacky

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

Guest software can be designed to run either as a TD, as a legacy virtual
machine, or directly on the CPU, based on enumeration of its run-time
environment. CPUID leaf 0x21 emulation is done by the Intel TDX module.
Sub-leaf 0 returns the values of "IntelTDX    " in EBX/EDX/ECX.

TdxProbeLib provides *TdxIsEnabled* to determine Td or Non-Td.

On IA32 it always return FALSE because Intel TDX only works on X64.

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/TdxProbeLib.h          | 25 +++++
 MdePkg/Library/TdxProbeLib/InternalTdxProbe.h | 25 +++++
 MdePkg/Library/TdxProbeLib/TdProbeNull.c      | 25 +++++
 MdePkg/Library/TdxProbeLib/TdxProbeLib.c      | 35 +++++++
 MdePkg/Library/TdxProbeLib/TdxProbeLib.inf    | 34 +++++++
 MdePkg/Library/TdxProbeLib/X64/TdProbe.nasm   | 97 +++++++++++++++++++
 MdePkg/MdePkg.dec                             |  3 +
 MdePkg/MdePkg.dsc                             |  1 +
 8 files changed, 245 insertions(+)
 create mode 100644 MdePkg/Include/Library/TdxProbeLib.h
 create mode 100644 MdePkg/Library/TdxProbeLib/InternalTdxProbe.h
 create mode 100644 MdePkg/Library/TdxProbeLib/TdProbeNull.c
 create mode 100644 MdePkg/Library/TdxProbeLib/TdxProbeLib.c
 create mode 100644 MdePkg/Library/TdxProbeLib/TdxProbeLib.inf
 create mode 100644 MdePkg/Library/TdxProbeLib/X64/TdProbe.nasm

diff --git a/MdePkg/Include/Library/TdxProbeLib.h b/MdePkg/Include/Library/TdxProbeLib.h
new file mode 100644
index 000000000000..d4fa4ba4cdf8
--- /dev/null
+++ b/MdePkg/Include/Library/TdxProbeLib.h
@@ -0,0 +1,25 @@
+/** @file
+  TdxProbeLib definitions
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef TDX_PROBE_LIB_H_
+#define TDX_PROBE_LIB_H_
+
+#include <Library/BaseLib.h>
+
+/**
+  Whether Intel TDX is enabled.
+
+  @return TRUE    TDX enabled
+  @return FALSE   TDX not enabled
+**/
+BOOLEAN
+EFIAPI
+TdxIsEnabled (
+  VOID);
+
+#endif
diff --git a/MdePkg/Library/TdxProbeLib/InternalTdxProbe.h b/MdePkg/Library/TdxProbeLib/InternalTdxProbe.h
new file mode 100644
index 000000000000..53cbbeda8cd8
--- /dev/null
+++ b/MdePkg/Library/TdxProbeLib/InternalTdxProbe.h
@@ -0,0 +1,25 @@
+/** @file
+  Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef INTERNAL_TDX_PROBE_H_
+#define INTERNAL_TDX_PROBE_H_
+
+#define PROBE_IS_TD_GUEST     0
+#define PROBE_NOT_TD_GUEST    1
+
+/**
+  The internal Td Probe implementation.
+
+  @return 0       TD guest
+  @return others  Non-TD guest
+**/
+UINTN
+EFIAPI
+TdProbe (
+  VOID
+  );
+
+#endif
diff --git a/MdePkg/Library/TdxProbeLib/TdProbeNull.c b/MdePkg/Library/TdxProbeLib/TdProbeNull.c
new file mode 100644
index 000000000000..12e9e1f8a7d4
--- /dev/null
+++ b/MdePkg/Library/TdxProbeLib/TdProbeNull.c
@@ -0,0 +1,25 @@
+/** @file
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include <Library/BaseLib.h>
+#include "InternalTdxProbe.h"
+
+/**
+  TDX only works in X64. So allways return -1 to indicate Non-Td.
+
+  @return 0       TD guest
+  @return others  Non-TD guest
+**/
+UINTN
+EFIAPI
+TdProbe (
+  VOID
+  )
+{
+  return PROBE_NOT_TD_GUEST;
+}
diff --git a/MdePkg/Library/TdxProbeLib/TdxProbeLib.c b/MdePkg/Library/TdxProbeLib/TdxProbeLib.c
new file mode 100644
index 000000000000..3f4524dc16a6
--- /dev/null
+++ b/MdePkg/Library/TdxProbeLib/TdxProbeLib.c
@@ -0,0 +1,35 @@
+/** @file
+  instance of TdxProbeLib
+
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include <Library/BaseLib.h>
+#include <Library/TdxProbeLib.h>
+#include "InternalTdxProbe.h"
+
+BOOLEAN mTdxEnabled = FALSE;
+BOOLEAN mTdxProbed = FALSE;
+
+/**
+  Whether Intel TDX is enabled.
+
+  @return TRUE    TDX enabled
+  @return FALSE   TDX not enabled
+**/
+BOOLEAN
+EFIAPI
+TdxIsEnabled (
+  VOID)
+{
+  if (mTdxProbed) {
+    return mTdxEnabled;
+  }
+
+  mTdxEnabled = TdProbe () == PROBE_IS_TD_GUEST;
+  mTdxProbed = TRUE;
+  return mTdxEnabled;
+}
diff --git a/MdePkg/Library/TdxProbeLib/TdxProbeLib.inf b/MdePkg/Library/TdxProbeLib/TdxProbeLib.inf
new file mode 100644
index 000000000000..59fc12c41569
--- /dev/null
+++ b/MdePkg/Library/TdxProbeLib/TdxProbeLib.inf
@@ -0,0 +1,34 @@
+## @file
+#  Tdx Probe library instance
+#
+#  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = TdxProbeLib
+  FILE_GUID                      = 26BF0B58-6E9D-4375-A363-52FD83FB82CE
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = TdxProbeLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64
+#
+
+[Sources]
+  TdxProbeLib.c
+  InternalTdxProbe.h
+
+[Sources.X64]
+  X64/TdProbe.nasm
+
+[Sources.IA32]
+  TdProbeNull.c
+
+[Packages]
+  MdePkg/MdePkg.dec
diff --git a/MdePkg/Library/TdxProbeLib/X64/TdProbe.nasm b/MdePkg/Library/TdxProbeLib/X64/TdProbe.nasm
new file mode 100644
index 000000000000..ed941830f0ca
--- /dev/null
+++ b/MdePkg/Library/TdxProbeLib/X64/TdProbe.nasm
@@ -0,0 +1,97 @@
+;------------------------------------------------------------------------------
+;*
+;* CPUID leaf 0x21 emulation is done by the Intel TDX module. Sub-leaf 0
+;* returns the values of "IntelTDX    " in EBX/EDX/ECX.
+;*
+;* Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+;* SPDX-License-Identifier: BSD-2-Clause-Patent
+;*
+;*
+;------------------------------------------------------------------------------
+
+DEFAULT REL
+SECTION .text
+
+%define TD_PROBE_TD_GUEST             0
+%define TD_PROBE_NOT_TD_GUEST         1
+
+%macro td_push_regs 0
+    push rbp
+    mov  rbp, rsp
+    push r15
+    push r14
+    push r13
+    push r12
+    push rbx
+    push rsi
+    push rdi
+%endmacro
+
+%macro td_pop_regs 0
+    pop rdi
+    pop rsi
+    pop rbx
+    pop r12
+    pop r13
+    pop r14
+    pop r15
+    pop rbp
+%endmacro
+
+
+global ASM_PFX(TdProbe)
+ASM_PFX(TdProbe):
+
+    td_push_regs
+
+    ;
+    ; CPUID (0)
+    ;
+    mov     eax, 0
+    cpuid
+    cmp     ebx, 0x756e6547  ; "Genu"
+    jne     .not_td
+    cmp     edx, 0x49656e69  ; "ineI"
+    jne     .not_td
+    cmp     ecx, 0x6c65746e  ; "ntel"
+    jne     .not_td
+
+    ;
+    ; CPUID (1)
+    ;
+    mov     eax, 1
+    cpuid
+    test    ecx, 0x80000000
+    jz      .not_td
+
+    ;
+    ; CPUID[0].EAX >= 0x21?
+    ;
+    mov     eax, 0
+    cpuid
+    cmp     eax, 0x21
+    jl      .not_td
+
+    ;
+    ; CPUID (0x21,0)
+    ;
+    mov     eax, 0x21
+    mov     ecx, 0
+    cpuid
+
+    cmp     ebx, 0x65746E49   ; "Inte"
+    jne     .not_td
+    cmp     edx, 0x5844546C   ; "lTDX"
+    jne     .not_td
+    cmp     ecx, 0x20202020   ; "    "
+    jne     .not_td
+
+    mov     rax, TD_PROBE_TD_GUEST
+    jmp     .exit
+
+.not_td:
+    mov     rax, TD_PROBE_NOT_TD_GUEST
+
+.exit:
+    td_pop_regs
+    ret
diff --git a/MdePkg/MdePkg.dec b/MdePkg/MdePkg.dec
index a28a2daaffa8..5702b0596499 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 probe processing.
+  TdxProbeLib|Include/Library/TdxProbeLib.h
+
 [Guids]
   #
   # GUID defined in UEFI2.1/UEFI2.0/EFI1.1
diff --git a/MdePkg/MdePkg.dsc b/MdePkg/MdePkg.dsc
index a94959169b2f..a62a9504bc12 100644
--- a/MdePkg/MdePkg.dsc
+++ b/MdePkg/MdePkg.dsc
@@ -130,6 +130,7 @@
   MdePkg/Library/StandaloneMmServicesTableLib/StandaloneMmServicesTableLib.inf
 
   MdePkg/Library/RegisterFilterLibNull/RegisterFilterLibNull.inf
+  MdePkg/Library/TdxProbeLib/TdxProbeLib.inf
 
 [Components.IA32, Components.X64, Components.ARM, Components.AARCH64]
   #
-- 
2.29.2.windows.2


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

* [PATCH 06/23] MdePkg: Add TdxLib to wrap Tdx operations
  2021-08-12 11:56 [PATCH 00/23] Enable Intel TDX in OvmfPkg (SEC/PEI) Min Xu
                   ` (4 preceding siblings ...)
  2021-08-12 11:56 ` [PATCH 05/23] MdePkg: Add TdxProbeLib to probe Intel Tdx Min Xu
@ 2021-08-12 11:56 ` Min Xu
  2021-09-11  1:15   ` Erdem Aktas
  2021-08-12 11:56 ` [PATCH 07/23] MdePkg: Update BaseIoLibIntrinsicSev to support Tdx Min Xu
                   ` (17 subsequent siblings)
  23 siblings, 1 reply; 64+ messages in thread
From: Min Xu @ 2021-08-12 11:56 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Michael D Kinney, Liming Gao, Zhiguang Liu, Brijesh Singh,
	Erdem Aktas, James Bottomley, Jiewen Yao, Tom Lendacky

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

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 virutal CPUs.
 - TdVCpuNum       : Get the number of virtual CPUs. (In some case VMM may
                     add more vCPU in runtime).

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          | 101 ++++++++++++
 MdePkg/Library/TdxLib/TdxLib.inf        |  39 +++++
 MdePkg/Library/TdxLib/TdxLibNull.c      | 192 ++++++++++++++++++++++
 MdePkg/Library/TdxLib/X64/Tdcall.nasm   | 120 ++++++++++++++
 MdePkg/Library/TdxLib/X64/Tdvmcall.nasm | 206 ++++++++++++++++++++++++
 MdePkg/MdePkg.dec                       |   3 +
 MdePkg/MdePkg.dsc                       |   1 +
 10 files changed, 1083 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..ed07fc522f26
--- /dev/null
+++ b/MdePkg/Library/TdxLib/TdInfo.c
@@ -0,0 +1,101 @@
+/** @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;
+
+/**
+  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;
+
+  //
+  // Due to the possible change of vcpu num in run-time, do the Td call
+  // for every query.
+  //
+  Status = TdCall (TDCALL_TDINFO, 0, 0, 0, &TdReturnData);
+  ASSERT (Status == TDX_EXIT_REASON_SUCCESS);
+
+  return TdReturnData.TdInfo.NumVcpus;
+}
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..eebd4880e2dc
--- /dev/null
+++ b/MdePkg/Library/TdxLib/X64/Tdcall.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
+
+;  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..33bb811a3a25
--- /dev/null
+++ b/MdePkg/Library/TdxLib/X64/Tdvmcall.nasm
@@ -0,0 +1,206 @@
+;------------------------------------------------------------------------------
+;*
+;* 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
+
+    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 5702b0596499..94160588018f 100644
--- a/MdePkg/MdePkg.dec
+++ b/MdePkg/MdePkg.dec
@@ -299,6 +299,9 @@
   ##  @libraryclass  Provides function to support TDX probe processing.
   TdxProbeLib|Include/Library/TdxProbeLib.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 a62a9504bc12..b7f99b2f2772 100644
--- a/MdePkg/MdePkg.dsc
+++ b/MdePkg/MdePkg.dsc
@@ -176,6 +176,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] 64+ messages in thread

* [PATCH 07/23] MdePkg: Update BaseIoLibIntrinsicSev to support Tdx
  2021-08-12 11:56 [PATCH 00/23] Enable Intel TDX in OvmfPkg (SEC/PEI) Min Xu
                   ` (5 preceding siblings ...)
  2021-08-12 11:56 ` [PATCH 06/23] MdePkg: Add TdxLib to wrap Tdx operations Min Xu
@ 2021-08-12 11:56 ` Min Xu
  2021-08-17  8:38   ` [edk2-devel] " Gerd Hoffmann
  2021-09-11  1:15   ` Erdem Aktas
  2021-08-12 11:56 ` [PATCH 08/23] UefiCpuPkg: Support TDX in BaseXApicX2ApicLib Min Xu
                   ` (16 subsequent siblings)
  23 siblings, 2 replies; 64+ messages in thread
From: Min Xu @ 2021-08-12 11:56 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Michael D Kinney, Liming Gao, Zhiguang Liu, Brijesh Singh,
	Erdem Aktas, James Bottomley, Jiewen Yao, Tom Lendacky

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

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

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

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

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 TdxProbeLib/TdxLib so that the Pkgs
which include BaseIoLibIntrinsic.inf need not include TdxProbeLib/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                 |   6 +-
 MdePkg/Library/BaseIoLibIntrinsic/IoLib.c     |  97 ++-
 MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c  |  49 +-
 .../BaseIoLibIntrinsic/IoLibInternalTdx.c     | 690 ++++++++++++++++++
 .../BaseIoLibIntrinsic/IoLibInternalTdxNull.c | 499 +++++++++++++
 MdePkg/Library/BaseIoLibIntrinsic/IoLibMsc.c  |  73 +-
 MdePkg/Library/BaseIoLibIntrinsic/IoLibTdx.h  | 411 +++++++++++
 .../BaseIoLibIntrinsic/X64/IoFifoSev.nasm     | 133 ++++
 9 files changed, 1911 insertions(+), 49 deletions(-)
 create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdx.c
 create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdxNull.c
 create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/IoLibTdx.h

diff --git a/MdePkg/Library/BaseIoLibIntrinsic/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..53ff8d6fd37d 100644
--- a/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicSev.inf
+++ b/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicSev.inf
@@ -30,17 +30,20 @@
   IoLibMmioBuffer.c
   BaseIoLibIntrinsicInternal.h
   IoHighLevel.c
+  IoLibTdx.h
 
 [Sources.IA32]
   IoLibGcc.c    | GCC
   IoLibMsc.c    | MSFT
   IoLib.c
+  IoLibInternalTdxNull.c
   Ia32/IoFifoSev.nasm
 
 [Sources.X64]
   IoLibGcc.c    | GCC
   IoLibMsc.c    | MSFT
   IoLib.c
+  IoLibInternalTdx.c
   X64/IoFifoSev.nasm
 
 [Packages]
@@ -50,4 +53,5 @@
   DebugLib
   BaseLib
   RegisterFilterLib
-
+  TdxLib
+  TdxProbeLib
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/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..4c342f6d3873
--- /dev/null
+++ b/MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdx.c
@@ -0,0 +1,690 @@
+/** @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/TdxProbeLib.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
+
+/**
+  Check if it is Tdx guest.
+
+  @return TRUE    It is Tdx guest
+  @return FALSE   It is not Tdx guest
+
+**/
+BOOLEAN
+EFIAPI
+IsTdxGuest (
+  VOID
+  )
+{
+  return TdxIsEnabled ();
+}
+
+
+/**
+  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/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..7f426495bbe3 100644
--- a/MdePkg/Library/BaseIoLibIntrinsic/X64/IoFifoSev.nasm
+++ b/MdePkg/Library/BaseIoLibIntrinsic/X64/IoFifoSev.nasm
@@ -10,6 +10,79 @@
     DEFAULT REL
     SECTION .text
 
+extern ASM_PFX(TdIoReadFifo8)
+extern ASM_PFX(TdIoReadFifo16)
+extern ASM_PFX(TdIoReadFifo32)
+extern ASM_PFX(TdIoWriteFifo8)
+extern ASM_PFX(TdIoWriteFifo16)
+extern ASM_PFX(TdIoWriteFifo32)
+
+;------------------------------------------------------------------------------
+; Check whether we need to unroll the String I/O in Tdx guest
+;
+; Return // eax   (1 - unroll, 0 - no unroll)
+;------------------------------------------------------------------------------
+global ASM_PFX(TdxNoRepIo)
+ASM_PFX(TdxNoRepIo):
+  ; CPUID clobbers ebx, ecx and edx
+  push      rbx
+  push      rcx
+  push      rdx
+
+  ;
+  ; CPUID (0)
+  ;
+  mov     eax, 0
+  cpuid
+  cmp     ebx, 0x756e6547  ; "Genu"
+  jne     @NoTdx
+  cmp     edx, 0x49656e69  ; "ineI"
+  jne     @NoTdx
+  cmp     ecx, 0x6c65746e  ; "ntel"
+  jne     @NoTdx
+
+  ;
+  ; CPUID (1)
+  ;
+  mov     eax, 1
+  cpuid
+  test    ecx, 0x80000000
+  jz      @NoTdx
+
+  ;
+  ; CPUID[0].EAX >= 0x21?
+  ;
+  mov     eax, 0
+  cpuid
+  cmp     eax, 0x21
+  jl      @NoTdx
+
+  ;
+  ; CPUID (0x21,0)
+  ;
+  mov     eax, 0x21
+  mov     ecx, 0
+  cpuid
+
+  cmp     ebx, 0x65746E49   ; "Inte"
+  jne     @NoTdx
+  cmp     edx, 0x5844546C   ; "lTDX"
+  jne     @NoTdx
+  cmp     ecx, 0x20202020   ; "    "
+  jne     @NoTdx
+
+  mov     rax, 1
+  jmp     @ExitTdxNoRepIo
+
+@NoTdx:
+  mov     rax, 0
+
+@ExitTdxNoRepIo:
+  pop     rdx
+  pop     rcx
+  pop     rbx
+  ret
+
 ;------------------------------------------------------------------------------
 ; Check whether we need to unroll the String I/O in SEV guest
 ;
@@ -75,6 +148,16 @@ ASM_PFX(SevNoRepIo):
 ;------------------------------------------------------------------------------
 global ASM_PFX(IoReadFifo8)
 ASM_PFX(IoReadFifo8):
+    call    ASM_PFX(TdxNoRepIo)
+    test    rax, rax
+    jz      @NonTd_IoReadFifo8
+
+    sub     rsp, 020h
+    call    TdIoReadFifo8
+    add     rsp, 020h
+    ret
+
+@NonTd_IoReadFifo8:
     xchg    rcx, rdx
     xchg    rdi, r8             ; rdi: buffer address; r8: save rdi
 
@@ -111,6 +194,16 @@ ASM_PFX(IoReadFifo8):
 ;------------------------------------------------------------------------------
 global ASM_PFX(IoReadFifo16)
 ASM_PFX(IoReadFifo16):
+    call    ASM_PFX(TdxNoRepIo)
+    test    rax, rax
+    jz      @NonTd_IoReadFifo16
+
+    sub     rsp, 020h
+    call    TdIoReadFifo16
+    add     rsp, 020h
+    ret
+
+@NonTd_IoReadFifo16:
     xchg    rcx, rdx
     xchg    rdi, r8             ; rdi: buffer address; r8: save rdi
 
@@ -147,6 +240,16 @@ ASM_PFX(IoReadFifo16):
 ;------------------------------------------------------------------------------
 global ASM_PFX(IoReadFifo32)
 ASM_PFX(IoReadFifo32):
+    call    ASM_PFX(TdxNoRepIo)
+    test    rax, rax
+    jz      @NonTd_IoReadFifo32
+
+    sub     rsp, 020h
+    call    TdIoReadFifo32
+    add     rsp, 020h
+    ret
+
+@NonTd_IoReadFifo32:
     xchg    rcx, rdx
     xchg    rdi, r8             ; rdi: buffer address; r8: save rdi
 
@@ -183,6 +286,16 @@ ASM_PFX(IoReadFifo32):
 ;------------------------------------------------------------------------------
 global ASM_PFX(IoWriteFifo8)
 ASM_PFX(IoWriteFifo8):
+    call    ASM_PFX(TdxNoRepIo)
+    test    rax, rax
+    jz      @NonTd_IoWriteFifo8
+
+    sub     rsp, 020h
+    call    TdIoWriteFifo8
+    add     rsp, 020h
+    ret
+
+@NonTd_IoWriteFifo8:
     xchg    rcx, rdx
     xchg    rsi, r8             ; rsi: buffer address; r8: save rsi
 
@@ -219,6 +332,16 @@ ASM_PFX(IoWriteFifo8):
 ;------------------------------------------------------------------------------
 global ASM_PFX(IoWriteFifo16)
 ASM_PFX(IoWriteFifo16):
+    call    ASM_PFX(TdxNoRepIo)
+    test    rax, rax
+    jz      @NonTd_IoWriteFifo16
+
+    sub     rsp, 020h
+    call    TdIoWriteFifo16
+    add     rsp, 020h
+    ret
+
+@NonTd_IoWriteFifo16:
     xchg    rcx, rdx
     xchg    rsi, r8             ; rsi: buffer address; r8: save rsi
 
@@ -255,6 +378,16 @@ ASM_PFX(IoWriteFifo16):
 ;------------------------------------------------------------------------------
 global ASM_PFX(IoWriteFifo32)
 ASM_PFX(IoWriteFifo32):
+    call    ASM_PFX(TdxNoRepIo)
+    test    rax, rax
+    jz      @NonTd_IoWriteFifo32
+
+    sub     rsp, 020h
+    call    TdIoWriteFifo32
+    add     rsp, 020h
+    ret
+
+@NonTd_IoWriteFifo32:
     xchg    rcx, rdx
     xchg    rsi, r8             ; rsi: buffer address; r8: save rsi
 
-- 
2.29.2.windows.2


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

* [PATCH 08/23] UefiCpuPkg: Support TDX in BaseXApicX2ApicLib
  2021-08-12 11:56 [PATCH 00/23] Enable Intel TDX in OvmfPkg (SEC/PEI) Min Xu
                   ` (6 preceding siblings ...)
  2021-08-12 11:56 ` [PATCH 07/23] MdePkg: Update BaseIoLibIntrinsicSev to support Tdx Min Xu
@ 2021-08-12 11:56 ` Min Xu
  2021-08-12 11:56 ` [PATCH 09/23] UefiCpuPkg: Add VmTdExitLibNull Min Xu
                   ` (15 subsequent siblings)
  23 siblings, 0 replies; 64+ messages in thread
From: Min Xu @ 2021-08-12 11:56 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Eric Dong, Ray Ni, Rahul Kumar, Brijesh Singh,
	Erdem Aktas, James Bottomley, Jiewen Yao, Tom Lendacky

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   | 172 +++++++++++++++++-
 .../BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf |   2 +
 UefiCpuPkg/UefiCpuPkg.dsc                     |   2 +
 3 files changed, 168 insertions(+), 8 deletions(-)

diff --git a/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c b/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c
index cdcbca046191..793ea61b50fa 100644
--- a/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c
+++ b/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c
@@ -23,11 +23,166 @@
 #include <Library/TimerLib.h>
 #include <Library/PcdLib.h>
 #include <Library/UefiCpuLib.h>
+#include <IndustryStandard/Tdx.h>
+#include <Library/TdxLib.h>
+#include <Library/TdxProbeLib.h>
 
 //
 // Library internal functions
 //
 
+/**
+  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) && TdxIsEnabled ()) {
+    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) && TdxIsEnabled ()) {
+    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) && TdxIsEnabled ()) {
+    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) && TdxIsEnabled ()) {
+    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 +232,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 +263,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 +308,7 @@ ReadLocalApicReg (
     ASSERT (MmioOffset != XAPIC_ICR_HIGH_OFFSET);
 
     MsrIndex = (UINT32)(MmioOffset >> 4) + X2APIC_MSR_BASE_ADDRESS;
-    return AsmReadMsr32 (MsrIndex);
+    return ReadMsrReg32 (MsrIndex);
   }
 }
 
@@ -202,7 +357,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 +464,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 +505,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..2367a3349008 100644
--- a/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf
+++ b/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf
@@ -39,6 +39,8 @@
   IoLib
   PcdLib
   UefiCpuLib
+  TdxLib
+  TdxProbeLib
 
 [Pcd]
   gUefiCpuPkgTokenSpaceGuid.PcdCpuInitIpiDelayInMicroSeconds  ## SOMETIMES_CONSUMES
diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc
index 699c91626bd8..47768b10d5be 100644
--- a/UefiCpuPkg/UefiCpuPkg.dsc
+++ b/UefiCpuPkg/UefiCpuPkg.dsc
@@ -61,6 +61,8 @@
   TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf
   VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf
   MicrocodeLib|UefiCpuPkg/Library/MicrocodeLib/MicrocodeLib.inf
+  TdxProbeLib|MdePkg/Library/TdxProbeLib/TdxProbeLib.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] 64+ messages in thread

* [PATCH 09/23] UefiCpuPkg: Add VmTdExitLibNull
  2021-08-12 11:56 [PATCH 00/23] Enable Intel TDX in OvmfPkg (SEC/PEI) Min Xu
                   ` (7 preceding siblings ...)
  2021-08-12 11:56 ` [PATCH 08/23] UefiCpuPkg: Support TDX in BaseXApicX2ApicLib Min Xu
@ 2021-08-12 11:56 ` Min Xu
  2021-08-12 11:56 ` [PATCH 10/23] OvmfPkg: Prepare OvmfPkg to use the VmTdExitLib library Min Xu
                   ` (14 subsequent siblings)
  23 siblings, 0 replies; 64+ messages in thread
From: Min Xu @ 2021-08-12 11:56 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Brijesh Singh, Erdem Aktas, James Bottomley, Jiewen Yao,
	Tom Lendacky, Eric Dong, Ray Ni, Rahul Kumar

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

PcdTdxIsEnabled indicates if Tdx is enabled.

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                     |  9 ++++
 UefiCpuPkg/UefiCpuPkg.dsc                     |  2 +
 5 files changed, 129 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..fdc7f9ff48e9 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 }}
@@ -396,5 +399,11 @@
   # @Prompt SEV-ES Status
   gUefiCpuPkgTokenSpaceGuid.PcdSevEsIsEnabled|FALSE|BOOLEAN|0x60000016
 
+  ## This dynamic PCD indicates whether Intel TDX is enabled
+  #   TRUE  - Intel TDX is enabled
+  #   FALSE - Intel TDX is not enabled
+  # @Prompt Intel TDX Status
+  gUefiCpuPkgTokenSpaceGuid.PcdTdxIsEnabled|FALSE|BOOLEAN|0x60000017
+
 [UserExtensions.TianoCore."ExtraFiles"]
   UefiCpuPkgExtra.uni
diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc
index 47768b10d5be..a7853f6f6097 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
   TdxProbeLib|MdePkg/Library/TdxProbeLib/TdxProbeLib.inf
   TdxLib|MdePkg/Library/TdxLib/TdxLib.inf
@@ -160,6 +161,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] 64+ messages in thread

* [PATCH 10/23] OvmfPkg: Prepare OvmfPkg to use the VmTdExitLib library
  2021-08-12 11:56 [PATCH 00/23] Enable Intel TDX in OvmfPkg (SEC/PEI) Min Xu
                   ` (8 preceding siblings ...)
  2021-08-12 11:56 ` [PATCH 09/23] UefiCpuPkg: Add VmTdExitLibNull Min Xu
@ 2021-08-12 11:56 ` Min Xu
  2021-08-12 11:56 ` [PATCH 11/23] OvmfPkg: Implement library support for VmTdExitLib in Ovmf Min Xu
                   ` (13 subsequent siblings)
  23 siblings, 0 replies; 64+ messages in thread
From: Min Xu @ 2021-08-12 11:56 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky

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

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 d1d92c97bae3..1e1765060e3f 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 a467ab7090fb..2eadb51683c9 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 e56b83d95e09..3376c4f4c2f9 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 3c1ca6bfd493..d8d559dacca6 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] 64+ messages in thread

* [PATCH 11/23] OvmfPkg: Implement library support for VmTdExitLib in Ovmf
  2021-08-12 11:56 [PATCH 00/23] Enable Intel TDX in OvmfPkg (SEC/PEI) Min Xu
                   ` (9 preceding siblings ...)
  2021-08-12 11:56 ` [PATCH 10/23] OvmfPkg: Prepare OvmfPkg to use the VmTdExitLib library Min Xu
@ 2021-08-12 11:56 ` Min Xu
  2021-08-12 11:56 ` [PATCH 12/23] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VE exception Min Xu
                   ` (12 subsequent siblings)
  23 siblings, 0 replies; 64+ messages in thread
From: Min Xu @ 2021-08-12 11:56 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   |  41 ++
 .../Library/VmTdExitLib/VmTdExitVeHandler.c   | 515 ++++++++++++++++++
 OvmfPkg/OvmfPkg.dec                           |   3 +
 3 files changed, 559 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..0d9430034330
--- /dev/null
+++ b/OvmfPkg/Library/VmTdExitLib/VmTdExitLib.inf
@@ -0,0 +1,41 @@
+## @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 ccda130f0ef6..8d1f3b03488c 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -342,6 +342,9 @@
   ## Size of the Ovmf image in KB
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfImageSizeInKb|0|UINT32|0x4f
 
+  ## Ignore the VE halt in Tdx
+  gUefiOvmfPkgTokenSpaceGuid.PcdIgnoreVeHalt|FALSE|BOOLEAN|0x50
+
 [PcdsDynamic, PcdsDynamicEx]
   gUefiOvmfPkgTokenSpaceGuid.PcdEmuVariableEvent|0|UINT64|2
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashVariablesEnable|FALSE|BOOLEAN|0x10
-- 
2.29.2.windows.2


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

* [PATCH 12/23] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VE exception
  2021-08-12 11:56 [PATCH 00/23] Enable Intel TDX in OvmfPkg (SEC/PEI) Min Xu
                   ` (10 preceding siblings ...)
  2021-08-12 11:56 ` [PATCH 11/23] OvmfPkg: Implement library support for VmTdExitLib in Ovmf Min Xu
@ 2021-08-12 11:56 ` Min Xu
  2021-08-12 11:56 ` [PATCH 13/23] UefiCpuPkg: Enable Tdx support in MpInitLib Min Xu
                   ` (11 subsequent siblings)
  23 siblings, 0 replies; 64+ messages in thread
From: Min Xu @ 2021-08-12 11:56 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Brijesh Singh, Erdem Aktas, James Bottomley, Jiewen Yao,
	Tom Lendacky, Eric Dong, Ray Ni, Rahul Kumar

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] 64+ messages in thread

* [PATCH 13/23] UefiCpuPkg: Enable Tdx support in MpInitLib
  2021-08-12 11:56 [PATCH 00/23] Enable Intel TDX in OvmfPkg (SEC/PEI) Min Xu
                   ` (11 preceding siblings ...)
  2021-08-12 11:56 ` [PATCH 12/23] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VE exception Min Xu
@ 2021-08-12 11:56 ` Min Xu
  2021-08-12 11:56 ` [PATCH 14/23] OvmfPkg: Update SecEntry.nasm to support Tdx Min Xu
                   ` (10 subsequent siblings)
  23 siblings, 0 replies; 64+ messages in thread
From: Min Xu @ 2021-08-12 11:56 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Brijesh Singh, Erdem Aktas, James Bottomley, Jiewen Yao,
	Tom Lendacky, Eric Dong, Ray Ni, Rahul Kumar

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 |   5 +
 UefiCpuPkg/Library/MpInitLib/DxeMpLib.c       |  14 +-
 UefiCpuPkg/Library/MpInitLib/MpIntelTdx.h     | 107 +++++++++++++
 UefiCpuPkg/Library/MpInitLib/MpLib.c          |  26 ++++
 UefiCpuPkg/Library/MpInitLib/MpLibTdx.c       | 142 ++++++++++++++++++
 UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c   | 117 +++++++++++++++
 UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf |   5 +
 .../Library/MpInitLib/X64/IntelTdcall.nasm    | 120 +++++++++++++++
 8 files changed, 535 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..2e1cc34d2657 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
@@ -76,3 +80,4 @@
   gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase                       ## SOMETIMES_CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard                      ## CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase                           ## CONSUMES
+  gUefiCpuPkgTokenSpaceGuid.PcdTdxIsEnabled                            ## CONSUMES
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..cbb45d2eaf0a
--- /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
+MyTdCall (
+  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..2c4445ff02b6
--- /dev/null
+++ b/UefiCpuPkg/Library/MpInitLib/MpLibTdx.c
@@ -0,0 +1,142 @@
+/** @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/PcdLib.h>
+#include <Library/DebugLib.h>
+#include <IndustryStandard/Tdx.h>
+
+
+/**
+  Gets detailed MP-related information on the requested processor at the
+  instant this call is made. This service may only be called from the BSP.
+
+  @param[in]  ProcessorNumber       The handle number of processor.
+  @param[out] ProcessorInfoBuffer   A pointer to the buffer where information for
+                                    the requested processor is deposited.
+  @param[out]  HealthData            Return processor health data.
+
+  @retval EFI_SUCCESS             Processor information was returned.
+  @retval EFI_DEVICE_ERROR        The calling processor is an AP.
+  @retval EFI_INVALID_PARAMETER   ProcessorInfoBuffer is NULL.
+  @retval EFI_NOT_FOUND           The processor with the handle specified by
+                                  ProcessorNumber does not exist in the platform.
+  @retval EFI_NOT_READY           MP Initialize Library is not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+TdxMpInitLibGetProcessorInfo (
+  IN  UINTN                      ProcessorNumber,
+  OUT EFI_PROCESSOR_INFORMATION  *ProcessorInfoBuffer,
+  OUT EFI_HEALTH_FLAGS           *HealthData  OPTIONAL
+  )
+{
+  EFI_STATUS              Status;
+  TD_RETURN_DATA          TdReturnData;
+
+  if (ProcessorInfoBuffer == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Status = MyTdCall(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 = MyTdCall(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
+  )
+{
+  return PcdGetBool (PcdTdxIsEnabled);
+}
diff --git a/UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c b/UefiCpuPkg/Library/MpInitLib/MpLibTdxNull.c
new file mode 100644
index 000000000000..b00c8deefb5f
--- /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
+MyTdCall (
+  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..fe246b74aaef 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
@@ -65,6 +69,7 @@
   gUefiCpuPkgTokenSpaceGuid.PcdSevEsIsEnabled                      ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase                   ## SOMETIMES_CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase                       ## CONSUMES
+  gUefiCpuPkgTokenSpaceGuid.PcdTdxIsEnabled                        ## CONSUMES
 
 [Ppis]
   gEdkiiPeiShadowMicrocodePpiGuid        ## SOMETIMES_CONSUMES
diff --git a/UefiCpuPkg/Library/MpInitLib/X64/IntelTdcall.nasm b/UefiCpuPkg/Library/MpInitLib/X64/IntelTdcall.nasm
new file mode 100644
index 000000000000..9f83b9e73acb
--- /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
+
+;  TdCall (
+;    UINT64  Leaf,    // Rcx
+;    UINT64  P1,      // Rdx
+;    UINT64  P2,      // R8
+;    UINT64  P3,      // R9
+;    UINT64  Results, // rsp + 0x28
+;    )
+global ASM_PFX(MyTdCall)
+ASM_PFX(MyTdCall):
+       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] 64+ messages in thread

* [PATCH 14/23] OvmfPkg: Update SecEntry.nasm to support Tdx
  2021-08-12 11:56 [PATCH 00/23] Enable Intel TDX in OvmfPkg (SEC/PEI) Min Xu
                   ` (12 preceding siblings ...)
  2021-08-12 11:56 ` [PATCH 13/23] UefiCpuPkg: Enable Tdx support in MpInitLib Min Xu
@ 2021-08-12 11:56 ` Min Xu
  2021-08-12 11:56 ` [PATCH 15/23] OvmfPkg: Add IntelTdx.h in OvmfPkg/Include/IndustryStandard Min Xu
                   ` (9 subsequent siblings)
  23 siblings, 0 replies; 64+ messages in thread
From: Min Xu @ 2021-08-12 11:56 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky

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

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     | 313 ++++++++++++++++++++++++++++++
 3 files changed, 365 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 7f78dcee2772..75cd5ee7264b 100644
--- a/OvmfPkg/Sec/SecMain.inf
+++ b/OvmfPkg/Sec/SecMain.inf
@@ -70,6 +70,7 @@
   gUefiOvmfPkgTokenSpaceGuid.PcdGuidedExtractHandlerTableSize
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfDecompressionScratchEnd
   gEfiMdeModulePkgTokenSpaceGuid.PcdInitValueInTempStack
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupBase
 
 [FeaturePcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire
diff --git a/OvmfPkg/Sec/X64/SecEntry.nasm b/OvmfPkg/Sec/X64/SecEntry.nasm
index 1cc680a70716..8c4d9047e070 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,31 @@ extern ASM_PFX(SecCoreStartupWithStack)
 global ASM_PFX(_ModuleEntryPoint)
 ASM_PFX(_ModuleEntryPoint):
 
+    ;
+    ; Td guest flag is stored in TDX_WORK_AREA which is in Mailbox[0x10,0x20]
+    ;
+    %define CC_WORK_AREA FixedPcdGet32 (PcdSevEsWorkAreaBase)
+    mov     eax, CC_WORK_AREA
+    cmp     byte[eax], 2
+    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 +97,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] 64+ messages in thread

* [PATCH 15/23] OvmfPkg: Add IntelTdx.h in OvmfPkg/Include/IndustryStandard
  2021-08-12 11:56 [PATCH 00/23] Enable Intel TDX in OvmfPkg (SEC/PEI) Min Xu
                   ` (13 preceding siblings ...)
  2021-08-12 11:56 ` [PATCH 14/23] OvmfPkg: Update SecEntry.nasm to support Tdx Min Xu
@ 2021-08-12 11:56 ` Min Xu
  2021-08-12 11:56 ` [PATCH 16/23] OvmfPkg: Add TdxMailboxLib Min Xu
                   ` (8 subsequent siblings)
  23 siblings, 0 replies; 64+ messages in thread
From: Min Xu @ 2021-08-12 11:56 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky

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

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] 64+ messages in thread

* [PATCH 16/23] OvmfPkg: Add TdxMailboxLib
  2021-08-12 11:56 [PATCH 00/23] Enable Intel TDX in OvmfPkg (SEC/PEI) Min Xu
                   ` (14 preceding siblings ...)
  2021-08-12 11:56 ` [PATCH 15/23] OvmfPkg: Add IntelTdx.h in OvmfPkg/Include/IndustryStandard Min Xu
@ 2021-08-12 11:56 ` Min Xu
  2021-08-12 11:56 ` [PATCH 17/23] MdePkg: Add EFI_RESOURCE_ATTRIBUTE_ENCRYPTED in PiHob.h Min Xu
                   ` (7 subsequent siblings)
  23 siblings, 0 replies; 64+ messages in thread
From: Min Xu @ 2021-08-12 11:56 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky

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

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 8d1f3b03488c..d478a4b8e418 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] 64+ messages in thread

* [PATCH 17/23] MdePkg: Add EFI_RESOURCE_ATTRIBUTE_ENCRYPTED in PiHob.h
  2021-08-12 11:56 [PATCH 00/23] Enable Intel TDX in OvmfPkg (SEC/PEI) Min Xu
                   ` (15 preceding siblings ...)
  2021-08-12 11:56 ` [PATCH 16/23] OvmfPkg: Add TdxMailboxLib Min Xu
@ 2021-08-12 11:56 ` Min Xu
  2021-08-12 11:56 ` [PATCH 18/23] OvmfPkg: Enable Tdx in SecMain.c Min Xu
                   ` (6 subsequent siblings)
  23 siblings, 0 replies; 64+ messages in thread
From: Min Xu @ 2021-08-12 11:56 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky

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

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

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

diff --git a/MdePkg/Include/Pi/PiHob.h b/MdePkg/Include/Pi/PiHob.h
index 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] 64+ messages in thread

* [PATCH 18/23] OvmfPkg: Enable Tdx in SecMain.c
  2021-08-12 11:56 [PATCH 00/23] Enable Intel TDX in OvmfPkg (SEC/PEI) Min Xu
                   ` (16 preceding siblings ...)
  2021-08-12 11:56 ` [PATCH 17/23] MdePkg: Add EFI_RESOURCE_ATTRIBUTE_ENCRYPTED in PiHob.h Min Xu
@ 2021-08-12 11:56 ` Min Xu
  2021-08-19  6:49   ` [edk2-devel] " Gerd Hoffmann
  2021-08-12 11:56 ` [PATCH 19/23] OvmfPkg: Check Tdx in QemuFwCfgPei to avoid DMA operation Min Xu
                   ` (5 subsequent siblings)
  23 siblings, 1 reply; 64+ messages in thread
From: Min Xu @ 2021-08-12 11:56 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky

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

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.

2 PCDs are added for page accepting. They're the default settings of the
chunk size and the Accept page size.

4 Tdx specific libs are used by OvmfPkgX64:
 - VmTdExitLib
 - TdxLib
 - TdxProbeLib
 - 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    |   3 +
 OvmfPkg/OvmfPkgIa32X64.dsc |   3 +
 OvmfPkg/OvmfPkgX64.dsc     |   5 +-
 OvmfPkg/Sec/IntelTdx.c     | 608 +++++++++++++++++++++++++++++++++++++
 OvmfPkg/Sec/IntelTdx.h     |  33 ++
 OvmfPkg/Sec/SecMain.c      |  43 ++-
 OvmfPkg/Sec/SecMain.inf    |   6 +
 8 files changed, 700 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 d478a4b8e418..a9765f2a60be 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -349,6 +349,12 @@
   ## Ignore the VE halt in Tdx
   gUefiOvmfPkgTokenSpaceGuid.PcdIgnoreVeHalt|FALSE|BOOLEAN|0x50
 
+  ## The chunk size of Tdx accept page
+  gUefiOvmfPkgTokenSpaceGuid.PcdTdxAcceptChunkSize|0x2000000|UINT64|0x51
+
+  ## The Tdx accept page size. 0x1000(4k),0x200000(2M)
+  gUefiOvmfPkgTokenSpaceGuid.PcdTdxAcceptPageSize|0x1000|UINT64|0x52
+
 [PcdsDynamic, PcdsDynamicEx]
   gUefiOvmfPkgTokenSpaceGuid.PcdEmuVariableEvent|0|UINT64|2
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashVariablesEnable|FALSE|BOOLEAN|0x10
diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
index 1e1765060e3f..27c70d233c68 100644
--- a/OvmfPkg/OvmfPkgIa32.dsc
+++ b/OvmfPkg/OvmfPkgIa32.dsc
@@ -244,6 +244,9 @@
   BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf
   VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf
   VmTdExitLib|UefiCpuPkg/Library/VmTdExitLibNull/VmTdExitLibNull.inf
+  TdxLib|MdePkg/Library/TdxLib/TdxLib.inf
+  TdxProbeLib|MdePkg/Library/TdxProbeLib/TdxProbeLib.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 2eadb51683c9..54c664382ef1 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -248,6 +248,9 @@
   BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf
   VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf
   VmTdExitLib|UefiCpuPkg/Library/VmTdExitLibNull/VmTdExitLibNull.inf
+  TdxLib|MdePkg/Library/TdxLib/TdxLib.inf
+  TdxProbeLib|MdePkg/Library/TdxProbeLib/TdxProbeLib.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 3376c4f4c2f9..b2e07233ebd6 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -247,7 +247,10 @@
 [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
+  TdxProbeLib|MdePkg/Library/TdxProbeLib/TdxProbeLib.inf
+  TdxMailboxLib|OvmfPkg/Library/TdxMailboxLib/TdxMailboxLib.inf
 
 [LibraryClasses.common.SEC]
   TimerLib|OvmfPkg/Library/AcpiTimerLib/BaseRomAcpiTimerLib.inf
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 e166a9389a1a..9792d7abe2d3 100644
--- a/OvmfPkg/Sec/SecMain.c
+++ b/OvmfPkg/Sec/SecMain.c
@@ -29,8 +29,11 @@
 #include <Library/MemEncryptSevLib.h>
 #include <Register/Amd/Ghcb.h>
 #include <Register/Amd/Msr.h>
-
+#include <IndustryStandard/Tdx.h>
+#include <Library/TdxLib.h>
+#include <Library/TdxProbeLib.h>
 #include <Ppi/TemporaryRamSupport.h>
+#include "IntelTdx.h"
 
 #define SEC_IDT_ENTRY_COUNT  34
 
@@ -844,6 +847,19 @@ SecCoreStartupWithStack (
   UINT32                      Index;
   volatile UINT8              *Table;
 
+#if defined (MDE_CPU_X64)
+  if (TdxIsEnabled ()) {
+    //
+    // 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
@@ -861,13 +877,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];
     }
@@ -913,6 +936,14 @@ SecCoreStartupWithStack (
     AsmEnableCache ();
   }
 
+  if (TdxIsEnabled ()) {
+    //
+    // 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 75cd5ee7264b..7d19ce1f4524 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,9 @@
   ExtractGuidedSectionLib
   LocalApicLib
   CpuExceptionHandlerLib
+  TdxLib
+  TdxMailboxLib
+  TdxProbeLib
 
 [Ppis]
   gEfiTemporaryRamSupportPpiGuid                # PPI ALWAYS_PRODUCED
@@ -71,6 +75,8 @@
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfDecompressionScratchEnd
   gEfiMdeModulePkgTokenSpaceGuid.PcdInitValueInTempStack
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBackupBase
+  gUefiOvmfPkgTokenSpaceGuid.PcdTdxAcceptChunkSize
+  gUefiOvmfPkgTokenSpaceGuid.PcdTdxAcceptPageSize
 
 [FeaturePcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire
-- 
2.29.2.windows.2


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

* [PATCH 19/23] OvmfPkg: Check Tdx in QemuFwCfgPei to avoid DMA operation
  2021-08-12 11:56 [PATCH 00/23] Enable Intel TDX in OvmfPkg (SEC/PEI) Min Xu
                   ` (17 preceding siblings ...)
  2021-08-12 11:56 ` [PATCH 18/23] OvmfPkg: Enable Tdx in SecMain.c Min Xu
@ 2021-08-12 11:56 ` Min Xu
  2021-08-12 11:56 ` [PATCH 20/23] MdePkg: Add AllocatePagesWithMemoryType support in PeiMemoryAllocationLib Min Xu
                   ` (4 subsequent siblings)
  23 siblings, 0 replies; 64+ messages in thread
From: Min Xu @ 2021-08-12 11:56 UTC (permalink / raw)
  To: devel
  Cc: Min Xu, Ard Biesheuvel, Jordan Justen, Brijesh Singh, Erdem Aktas,
	James Bottomley, Jiewen Yao, Tom Lendacky

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

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>
---
 OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPei.c      | 15 +++++++++++++++
 OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPeiLib.inf |  1 +
 2 files changed, 16 insertions(+)

diff --git a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPei.c b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPei.c
index ecabd88fab66..aae5f2fcb51f 100644
--- a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPei.c
+++ b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPei.c
@@ -14,6 +14,7 @@
 #include <Library/DebugLib.h>
 #include <Library/QemuFwCfgLib.h>
 #include <Library/MemEncryptSevLib.h>
+#include <Library/TdxProbeLib.h>
 
 #include "QemuFwCfgLibInternal.h"
 
@@ -82,6 +83,14 @@ QemuFwCfgInitialize (
     //
     if (MemEncryptSevIsEnabled ()) {
       DEBUG ((DEBUG_INFO, "SEV: QemuFwCfg fallback to IO Port interface.\n"));
+    } else if (TdxIsEnabled ()) {
+      //
+      // 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 +171,12 @@ InternalQemuFwCfgDmaBytes (
   //
   ASSERT (!MemEncryptSevIsEnabled ());
 
+  //
+  // TDX does not support DMA operations in PEI stage, we should
+  // not have reached here.
+  //
+  ASSERT (!TdxIsEnabled ());
+
   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..808cb16f75e1 100644
--- a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPeiLib.inf
+++ b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPeiLib.inf
@@ -42,4 +42,5 @@
   IoLib
   MemoryAllocationLib
   MemEncryptSevLib
+  TdxProbeLib
 
-- 
2.29.2.windows.2


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

* [PATCH 20/23] MdePkg: Add AllocatePagesWithMemoryType support in PeiMemoryAllocationLib
  2021-08-12 11:56 [PATCH 00/23] Enable Intel TDX in OvmfPkg (SEC/PEI) Min Xu
                   ` (18 preceding siblings ...)
  2021-08-12 11:56 ` [PATCH 19/23] OvmfPkg: Check Tdx in QemuFwCfgPei to avoid DMA operation Min Xu
@ 2021-08-12 11:56 ` Min Xu
  2021-08-12 20:43   ` Michael D Kinney
  2021-08-12 11:57 ` [PATCH 21/23] OvmfPkg: Add PcdUse1GPageTable support for TDX Min Xu
                   ` (3 subsequent siblings)
  23 siblings, 1 reply; 64+ messages in thread
From: Min Xu @ 2021-08-12 11:56 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

Allocates one or more 4KB pages of given type MemoryType.

Allocates the number of 4KB pages of MemoryType 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.

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/Library/MemoryAllocationLib.h  | 21 +++++++++++++++
 .../MemoryAllocationLib.c                     | 27 +++++++++++++++++++
 2 files changed, 48 insertions(+)

diff --git a/MdePkg/Include/Library/MemoryAllocationLib.h b/MdePkg/Include/Library/MemoryAllocationLib.h
index 65a30cf146dd..2bdc0592ef3e 100644
--- a/MdePkg/Include/Library/MemoryAllocationLib.h
+++ b/MdePkg/Include/Library/MemoryAllocationLib.h
@@ -484,4 +484,25 @@ FreePool (
   IN VOID   *Buffer
   );
 
+/**
+  Allocates one or more 4KB pages of given type MemoryType.
+
+  Allocates the number of 4KB pages of MemoryType 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  MemoryType            Type of memory to use for this allocation.
+  @param  Pages                 The number of 4 KB pages to allocate.
+
+  @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocatePagesWithMemoryType (
+  IN UINTN            MemoryType,
+  IN UINTN            Pages
+  );
+
 #endif
diff --git a/MdePkg/Library/PeiMemoryAllocationLib/MemoryAllocationLib.c b/MdePkg/Library/PeiMemoryAllocationLib/MemoryAllocationLib.c
index b3f9df74f139..dcb313349729 100644
--- a/MdePkg/Library/PeiMemoryAllocationLib/MemoryAllocationLib.c
+++ b/MdePkg/Library/PeiMemoryAllocationLib/MemoryAllocationLib.c
@@ -839,4 +839,31 @@ FreePool (
   //
 }
 
+/**
+  Allocates one or more 4KB pages of given type MemoryType.
 
+  Allocates the number of 4KB pages of MemoryType 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  MemoryType            Type of memory to use for this allocation.
+  @param  Pages                 The number of 4 KB pages to allocate.
+
+  @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+AllocatePagesWithMemoryType (
+  IN UINTN            MemoryType,
+  IN UINTN            Pages
+  )
+{
+  if (MemoryType >= EfiMaxMemoryType) {
+    ASSERT (FALSE);
+    return NULL;
+  }
+
+  return InternalAllocatePages (MemoryType, Pages);
+}
-- 
2.29.2.windows.2


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

* [PATCH 21/23] OvmfPkg: Add PcdUse1GPageTable support for TDX
  2021-08-12 11:56 [PATCH 00/23] Enable Intel TDX in OvmfPkg (SEC/PEI) Min Xu
                   ` (19 preceding siblings ...)
  2021-08-12 11:56 ` [PATCH 20/23] MdePkg: Add AllocatePagesWithMemoryType support in PeiMemoryAllocationLib Min Xu
@ 2021-08-12 11:57 ` Min Xu
  2021-08-12 11:57 ` [PATCH 22/23] MdeModulePkg: EFER should not be changed in TDX Min Xu
                   ` (2 subsequent siblings)
  23 siblings, 0 replies; 64+ messages in thread
From: Min Xu @ 2021-08-12 11:57 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 uses 1G page table. But PcdUse1GPageTable is set to FALSE
by default in OvmfPkgX64.dsc. It gives no chance to support 1G page
table. To support 1G page table in TDX this PCD is set to TRUE in
OvmfPkgX64.dsc.

>From the code in VirtualMemory.c (MdeModulePkg\Core\DxeIplPeim\X64),
even PcdUse1GPageTable is TRUE, Page1GSupport is FALSE until more
checking is done. So setting PcdUse1GPageTable to TRUE is to give a
chance to check if 1G page table is supported.
  Page1GSupport = FALSE;
  if (PcdGetBool(PcdUse1GPageTable)) {
    AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
    if (RegEax >= 0x80000001) {
      AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);
      if ((RegEdx & BIT26) != 0) {
        Page1GSupport = TRUE;
      }
    }
  }

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/OvmfPkgX64.dsc | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index b2e07233ebd6..97c923423d3f 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -576,6 +576,10 @@
   gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesCode|0x100
   gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesData|0x100
 
+  #
+  # TDX need 1G PageTable support
+  gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable|TRUE
+
   #
   # Network Pcds
   #
-- 
2.29.2.windows.2


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

* [PATCH 22/23] MdeModulePkg: EFER should not be changed in TDX
  2021-08-12 11:56 [PATCH 00/23] Enable Intel TDX in OvmfPkg (SEC/PEI) Min Xu
                   ` (20 preceding siblings ...)
  2021-08-12 11:57 ` [PATCH 21/23] OvmfPkg: Add PcdUse1GPageTable support for TDX Min Xu
@ 2021-08-12 11:57 ` Min Xu
  2021-08-12 11:57 ` [PATCH 23/23] OvmfPkg: Update PlatformPei to support TDX Min Xu
  2021-08-31 10:45 ` [edk2-devel] [PATCH 00/23] Enable Intel TDX in OvmfPkg (SEC/PEI) Gerd Hoffmann
  23 siblings, 0 replies; 64+ messages in thread
From: Min Xu @ 2021-08-12 11:57 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] 64+ messages in thread

* [PATCH 23/23] OvmfPkg: Update PlatformPei to support TDX
  2021-08-12 11:56 [PATCH 00/23] Enable Intel TDX in OvmfPkg (SEC/PEI) Min Xu
                   ` (21 preceding siblings ...)
  2021-08-12 11:57 ` [PATCH 22/23] MdeModulePkg: EFER should not be changed in TDX Min Xu
@ 2021-08-12 11:57 ` Min Xu
  2021-08-31 10:45 ` [edk2-devel] [PATCH 00/23] Enable Intel TDX in OvmfPkg (SEC/PEI) Gerd Hoffmann
  23 siblings, 0 replies; 64+ messages in thread
From: Min Xu @ 2021-08-12 11:57 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   |   9 +-
 OvmfPkg/PlatformPei/IntelTdx.c         | 268 +++++++++++++++++++++++++
 OvmfPkg/PlatformPei/IntelTdxNull.c     |  35 ++++
 OvmfPkg/PlatformPei/MemDetect.c        |  20 +-
 OvmfPkg/PlatformPei/Platform.c         |   2 +
 OvmfPkg/PlatformPei/Platform.h         |  17 ++
 OvmfPkg/PlatformPei/PlatformPei.inf    |  14 ++
 OvmfPkg/PlatformPei/X64/ApRunLoop.nasm |  83 ++++++++
 9 files changed, 447 insertions(+), 2 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 a9765f2a60be..2ad0b5de25e1 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..36451d0c9c24 100644
--- a/OvmfPkg/PlatformPei/FeatureControl.c
+++ b/OvmfPkg/PlatformPei/FeatureControl.c
@@ -12,6 +12,9 @@
 #include <Library/QemuFwCfgLib.h>
 #include <Ppi/MpServices.h>
 #include <Register/ArchitecturalMsr.h>
+#include <Library/TdxProbeLib.h>
+#include <Library/TdxLib.h>
+#include <IndustryStandard/Tdx.h>
 
 #include "Platform.h"
 
@@ -37,7 +40,11 @@ WriteFeatureControl (
   IN OUT VOID *WorkSpace
   )
 {
-  AsmWriteMsr64 (MSR_IA32_FEATURE_CONTROL, mFeatureControlValue);
+  if (TdxIsEnabled ()) {
+    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..598286d8ae2b
--- /dev/null
+++ b/OvmfPkg/PlatformPei/IntelTdx.c
@@ -0,0 +1,268 @@
+/** @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/TdxProbeLib.h>
+#include "Platform.h"
+
+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;
+  EFI_PHYSICAL_ADDRESS        PhysicalEnd;
+
+  //
+  // 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;
+      PhysicalEnd = Hob.ResourceDescriptor->PhysicalStart + Hob.ResourceDescriptor->ResourceLength;
+
+      //
+      // We mark each resource that we issue AcceptPage to with EFI_RESOURCE_SYSTEM_MEMORY
+      //
+      if ((Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) &&
+        (PhysicalEnd <= BASE_4GB)) {
+        ResourceAttribute |= EFI_RESOURCE_ATTRIBUTE_ENCRYPTED;
+      }
+      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
+  )
+{
+  VOID                        *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;
+
+  Address = AllocatePagesWithMemoryType (EfiACPIMemoryNVS, RelocationPages);
+  ApLoopFunc = (VOID *) ((UINTN) Address + EFI_PAGE_SIZE);
+
+  CopyMem (
+    ApLoopFunc,
+    RelocationMap.RelocateApLoopFuncAddress,
+    RelocationMap.RelocateApLoopFuncSize
+    );
+
+  DEBUG ((DEBUG_INFO, "Ap Relocation: mailbox %p, 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;
+
+  if (!TdxIsEnabled ()) {
+    return;
+  }
+
+  PcdStatus = PcdSetBoolS (PcdTdxIsEnabled, TRUE);
+  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..871f213fca48
--- /dev/null
+++ b/OvmfPkg/PlatformPei/IntelTdxNull.c
@@ -0,0 +1,35 @@
+/** @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>
+
+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 2deec128f464..d36cd362f667 100644
--- a/OvmfPkg/PlatformPei/MemDetect.c
+++ b/OvmfPkg/PlatformPei/MemDetect.c
@@ -35,6 +35,8 @@ Module Name:
 #include <Library/MtrrLib.h>
 #include <Library/QemuFwCfgLib.h>
 #include <Library/QemuFwCfgSimpleParserLib.h>
+#include <Library/TdxLib.h>
+#include <Library/TdxProbeLib.h>
 
 #include "Platform.h"
 #include "Cmos.h"
@@ -484,6 +486,7 @@ AddressWidthInitialization (
   )
 {
   UINT64 FirstNonAddress;
+  UINT64 TdxSharedPageMask;
 
   //
   // As guest-physical memory size grows, the permanent PEI RAM requirements
@@ -511,6 +514,17 @@ AddressWidthInitialization (
   if (mPhysMemAddressWidth <= 36) {
     mPhysMemAddressWidth = 36;
   }
+
+  if (TdxIsEnabled ()) {
+    TdxSharedPageMask = TdSharedPageMask ();
+    if (TdxSharedPageMask == (1ULL << 47)) {
+      mPhysMemAddressWidth = 48;
+    } else {
+      DEBUG ((DEBUG_ERROR, "Currently only PhysMemAddressWidth = 48 is supported in TDX.\n"));
+      ASSERT (FALSE);
+    }
+  }
+
   ASSERT (mPhysMemAddressWidth <= 48);
 }
 
@@ -815,7 +829,11 @@ InitializeRamRegions (
   VOID
   )
 {
-  QemuInitializeRam ();
+  if (TdxIsEnabled ()) {
+    TdxPublishRamRegions ();
+  } else {
+    QemuInitializeRam ();
+  }
 
   if (mS3Supported && mBootMode != BOOT_ON_S3_RESUME) {
     //
diff --git a/OvmfPkg/PlatformPei/Platform.c b/OvmfPkg/PlatformPei/Platform.c
index d3a20122a2ea..4be3c4bd1d3c 100644
--- a/OvmfPkg/PlatformPei/Platform.c
+++ b/OvmfPkg/PlatformPei/Platform.c
@@ -35,6 +35,7 @@
 #include <IndustryStandard/Q35MchIch9.h>
 #include <IndustryStandard/QemuCpuHotplug.h>
 #include <OvmfPlatforms.h>
+#include <Library/TdxProbeLib.h>
 
 #include "Platform.h"
 #include "Cmos.h"
@@ -742,6 +743,7 @@ InitializePlatform (
 
   InstallClearCacheCallback ();
   AmdSevInitialize ();
+  IntelTdxInitialize ();
   MiscInitialization ();
   InstallFeatureControlCallback ();
 
diff --git a/OvmfPkg/PlatformPei/Platform.h b/OvmfPkg/PlatformPei/Platform.h
index 8b1d270c2b0b..89121bcb8a41 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,22 @@ AmdSevInitialize (
   VOID
   );
 
+VOID
+TdxPublishRamRegions (
+  VOID
+  );
+
+VOID
+AsmGetRelocationMap (
+  OUT MP_RELOCATION_MAP    *AddressMap
+  );
+
+
+VOID
+IntelTdxInitialize (
+  VOID
+  );
+
 extern EFI_BOOT_MODE mBootMode;
 
 extern BOOLEAN mS3Supported;
diff --git a/OvmfPkg/PlatformPei/PlatformPei.inf b/OvmfPkg/PlatformPei/PlatformPei.inf
index 89d1f7636870..80f2b3a52ac9 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,10 @@
   MtrrLib
   MemEncryptSevLib
   PcdLib
+  TdxProbeLib
+  TdxMailboxLib
+  TdxLib
+  MemoryAllocationLib
 
 [Pcd]
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfPeiMemFvBase
@@ -106,6 +118,8 @@
   gUefiCpuPkgTokenSpaceGuid.PcdCpuBootLogicalProcessorNumber
   gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize
   gUefiCpuPkgTokenSpaceGuid.PcdSevEsIsEnabled
+  gUefiCpuPkgTokenSpaceGuid.PcdTdxIsEnabled
+  gEfiMdeModulePkgTokenSpaceGuid.PcdIa32EferChangeAllowed
 
 [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] 64+ messages in thread

* Re: [PATCH 20/23] MdePkg: Add AllocatePagesWithMemoryType support in PeiMemoryAllocationLib
  2021-08-12 11:56 ` [PATCH 20/23] MdePkg: Add AllocatePagesWithMemoryType support in PeiMemoryAllocationLib Min Xu
@ 2021-08-12 20:43   ` Michael D Kinney
  2021-08-15  2:51     ` Min Xu
  0 siblings, 1 reply; 64+ messages in thread
From: Michael D Kinney @ 2021-08-12 20:43 UTC (permalink / raw)
  To: Xu, Min M, devel@edk2.groups.io, Kinney, Michael D
  Cc: Liming Gao, Liu, Zhiguang, Yao, Jiewen

Hi Min,

This patch adds a new API to the lib class.

That type of change requires updates to all the lib instances.

In the design of the MemoryAllocationLib, of a type specific allocation
was needed, a new API was added for that type.  What memory types
are needed that require this new API.

If a variety of memory types are required, then why not
just use the PeiServicesLib API:

EFI_STATUS
EFIAPI
PeiServicesAllocatePages (
  IN EFI_MEMORY_TYPE            MemoryType,
  IN UINTN                      Pages,
  OUT EFI_PHYSICAL_ADDRESS      *Memory
  );

Thanks,

Mike

> -----Original Message-----
> From: Xu, Min M <min.m.xu@intel.com>
> Sent: Thursday, August 12, 2021 4:57 AM
> To: devel@edk2.groups.io
> Cc: Xu, Min M <min.m.xu@intel.com>; Kinney, Michael D <michael.d.kinney@intel.com>; Liming Gao <gaoliming@byosoft.com.cn>;
> Liu, Zhiguang <zhiguang.liu@intel.com>; Yao, Jiewen <jiewen.yao@intel.com>
> Subject: [PATCH 20/23] MdePkg: Add AllocatePagesWithMemoryType support in PeiMemoryAllocationLib
> 
> RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
> 
> Allocates one or more 4KB pages of given type MemoryType.
> 
> Allocates the number of 4KB pages of MemoryType 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.
> 
> 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/Library/MemoryAllocationLib.h  | 21 +++++++++++++++
>  .../MemoryAllocationLib.c                     | 27 +++++++++++++++++++
>  2 files changed, 48 insertions(+)
> 
> diff --git a/MdePkg/Include/Library/MemoryAllocationLib.h b/MdePkg/Include/Library/MemoryAllocationLib.h
> index 65a30cf146dd..2bdc0592ef3e 100644
> --- a/MdePkg/Include/Library/MemoryAllocationLib.h
> +++ b/MdePkg/Include/Library/MemoryAllocationLib.h
> @@ -484,4 +484,25 @@ FreePool (
>    IN VOID   *Buffer
>    );
> 
> +/**
> +  Allocates one or more 4KB pages of given type MemoryType.
> +
> +  Allocates the number of 4KB pages of MemoryType 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  MemoryType            Type of memory to use for this allocation.
> +  @param  Pages                 The number of 4 KB pages to allocate.
> +
> +  @return A pointer to the allocated buffer or NULL if allocation fails.
> +
> +**/
> +VOID *
> +EFIAPI
> +AllocatePagesWithMemoryType (
> +  IN UINTN            MemoryType,
> +  IN UINTN            Pages
> +  );
> +
>  #endif
> diff --git a/MdePkg/Library/PeiMemoryAllocationLib/MemoryAllocationLib.c
> b/MdePkg/Library/PeiMemoryAllocationLib/MemoryAllocationLib.c
> index b3f9df74f139..dcb313349729 100644
> --- a/MdePkg/Library/PeiMemoryAllocationLib/MemoryAllocationLib.c
> +++ b/MdePkg/Library/PeiMemoryAllocationLib/MemoryAllocationLib.c
> @@ -839,4 +839,31 @@ FreePool (
>    //
>  }
> 
> +/**
> +  Allocates one or more 4KB pages of given type MemoryType.
> 
> +  Allocates the number of 4KB pages of MemoryType 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  MemoryType            Type of memory to use for this allocation.
> +  @param  Pages                 The number of 4 KB pages to allocate.
> +
> +  @return A pointer to the allocated buffer or NULL if allocation fails.
> +
> +**/
> +VOID *
> +EFIAPI
> +AllocatePagesWithMemoryType (
> +  IN UINTN            MemoryType,
> +  IN UINTN            Pages
> +  )
> +{
> +  if (MemoryType >= EfiMaxMemoryType) {
> +    ASSERT (FALSE);
> +    return NULL;
> +  }
> +
> +  return InternalAllocatePages (MemoryType, Pages);
> +}
> --
> 2.29.2.windows.2


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

* Re: [PATCH 04/23] MdePkg: Add Tdx.h
  2021-08-12 11:56 ` [PATCH 04/23] MdePkg: Add Tdx.h Min Xu
@ 2021-08-12 20:52   ` Michael D Kinney
  2021-08-12 22:57     ` Min Xu
  0 siblings, 1 reply; 64+ messages in thread
From: Michael D Kinney @ 2021-08-12 20:52 UTC (permalink / raw)
  To: Xu, Min M, devel@edk2.groups.io, Kinney, Michael D
  Cc: Liming Gao, Liu, Zhiguang

Hi Min,

Please add the link to the public documentation to the
Tdx.h file header

Thanks,

Mike

> -----Original Message-----
> From: Xu, Min M <min.m.xu@intel.com>
> Sent: Thursday, August 12, 2021 4:57 AM
> To: devel@edk2.groups.io
> Cc: Xu, Min M <min.m.xu@intel.com>; Kinney, Michael D <michael.d.kinney@intel.com>; Liming Gao <gaoliming@byosoft.com.cn>;
> Liu, Zhiguang <zhiguang.liu@intel.com>
> Subject: [PATCH 04/23] MdePkg: Add Tdx.h
> 
> 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>
> Signed-off-by: Min Xu <min.m.xu@intel.com>
> ---
>  MdePkg/Include/IndustryStandard/Tdx.h | 200 ++++++++++++++++++++++++++
>  1 file changed, 200 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..c50470708b56
> --- /dev/null
> +++ b/MdePkg/Include/IndustryStandard/Tdx.h
> @@ -0,0 +1,200 @@
> +/** @file
> +  Intel Trust Domain Extension definitions
> +
> +  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	[flat|nested] 64+ messages in thread

* Re: [PATCH 04/23] MdePkg: Add Tdx.h
  2021-08-12 20:52   ` Michael D Kinney
@ 2021-08-12 22:57     ` Min Xu
  0 siblings, 0 replies; 64+ messages in thread
From: Min Xu @ 2021-08-12 22:57 UTC (permalink / raw)
  To: Kinney, Michael D, devel@edk2.groups.io; +Cc: Liming Gao, Liu, Zhiguang

Thanks for the reminder. I will add the link in the header in next version.

> -----Original Message-----
> From: Kinney, Michael D <michael.d.kinney@intel.com>
> Sent: Friday, August 13, 2021 4:52 AM
> To: Xu, Min M <min.m.xu@intel.com>; devel@edk2.groups.io; Kinney, Michael
> D <michael.d.kinney@intel.com>
> Cc: Liming Gao <gaoliming@byosoft.com.cn>; Liu, Zhiguang
> <zhiguang.liu@intel.com>
> Subject: RE: [PATCH 04/23] MdePkg: Add Tdx.h
> 
> Hi Min,
> 
> Please add the link to the public documentation to the Tdx.h file header
> 
> Thanks,
> 
> Mike
> 
> > -----Original Message-----
> > From: Xu, Min M <min.m.xu@intel.com>
> > Sent: Thursday, August 12, 2021 4:57 AM
> > To: devel@edk2.groups.io
> > Cc: Xu, Min M <min.m.xu@intel.com>; Kinney, Michael D
> > <michael.d.kinney@intel.com>; Liming Gao <gaoliming@byosoft.com.cn>;
> > Liu, Zhiguang <zhiguang.liu@intel.com>
> > Subject: [PATCH 04/23] MdePkg: Add Tdx.h
> >
> > 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>
> > Signed-off-by: Min Xu <min.m.xu@intel.com>
> > ---
> >  MdePkg/Include/IndustryStandard/Tdx.h | 200
> > ++++++++++++++++++++++++++
> >  1 file changed, 200 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..c50470708b56
> > --- /dev/null
> > +++ b/MdePkg/Include/IndustryStandard/Tdx.h
> > @@ -0,0 +1,200 @@
> > +/** @file
> > +  Intel Trust Domain Extension definitions
> > +
> > +  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	[flat|nested] 64+ messages in thread

* Re: [PATCH 20/23] MdePkg: Add AllocatePagesWithMemoryType support in PeiMemoryAllocationLib
  2021-08-12 20:43   ` Michael D Kinney
@ 2021-08-15  2:51     ` Min Xu
  0 siblings, 0 replies; 64+ messages in thread
From: Min Xu @ 2021-08-15  2:51 UTC (permalink / raw)
  To: Kinney, Michael D, devel@edk2.groups.io
  Cc: Liming Gao, Liu, Zhiguang, Yao, Jiewen

Thanks much for the reminder. You're right. I will update my code in the next version.

> -----Original Message-----
> From: Kinney, Michael D <michael.d.kinney@intel.com>
> Sent: Friday, August 13, 2021 4:43 AM
> To: Xu, Min M <min.m.xu@intel.com>; devel@edk2.groups.io; Kinney,
> Michael D <michael.d.kinney@intel.com>
> Cc: Liming Gao <gaoliming@byosoft.com.cn>; Liu, Zhiguang
> <zhiguang.liu@intel.com>; Yao, Jiewen <jiewen.yao@intel.com>
> Subject: RE: [PATCH 20/23] MdePkg: Add AllocatePagesWithMemoryType
> support in PeiMemoryAllocationLib
> 
> Hi Min,
> 
> This patch adds a new API to the lib class.
> 
> That type of change requires updates to all the lib instances.
> 
> In the design of the MemoryAllocationLib, of a type specific allocation was
> needed, a new API was added for that type.  What memory types are needed
> that require this new API.
> 
> If a variety of memory types are required, then why not just use the
> PeiServicesLib API:
> 
> EFI_STATUS
> EFIAPI
> PeiServicesAllocatePages (
>   IN EFI_MEMORY_TYPE            MemoryType,
>   IN UINTN                      Pages,
>   OUT EFI_PHYSICAL_ADDRESS      *Memory
>   );
> 
> Thanks,
> 
> Mike
> 
> > -----Original Message-----
> > From: Xu, Min M <min.m.xu@intel.com>
> > Sent: Thursday, August 12, 2021 4:57 AM
> > To: devel@edk2.groups.io
> > Cc: Xu, Min M <min.m.xu@intel.com>; Kinney, Michael D
> > <michael.d.kinney@intel.com>; Liming Gao <gaoliming@byosoft.com.cn>;
> > Liu, Zhiguang <zhiguang.liu@intel.com>; Yao, Jiewen
> > <jiewen.yao@intel.com>
> > Subject: [PATCH 20/23] MdePkg: Add AllocatePagesWithMemoryType
> support
> > in PeiMemoryAllocationLib
> >
> > RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
> >
> > Allocates one or more 4KB pages of given type MemoryType.
> >
> > Allocates the number of 4KB pages of MemoryType 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.
> >
> > 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/Library/MemoryAllocationLib.h  | 21 +++++++++++++++
> >  .../MemoryAllocationLib.c                     | 27 +++++++++++++++++++
> >  2 files changed, 48 insertions(+)
> >
> > diff --git a/MdePkg/Include/Library/MemoryAllocationLib.h
> > b/MdePkg/Include/Library/MemoryAllocationLib.h
> > index 65a30cf146dd..2bdc0592ef3e 100644
> > --- a/MdePkg/Include/Library/MemoryAllocationLib.h
> > +++ b/MdePkg/Include/Library/MemoryAllocationLib.h
> > @@ -484,4 +484,25 @@ FreePool (
> >    IN VOID   *Buffer
> >    );
> >
> > +/**
> > +  Allocates one or more 4KB pages of given type MemoryType.
> > +
> > +  Allocates the number of 4KB pages of MemoryType 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  MemoryType            Type of memory to use for this allocation.
> > +  @param  Pages                 The number of 4 KB pages to allocate.
> > +
> > +  @return A pointer to the allocated buffer or NULL if allocation fails.
> > +
> > +**/
> > +VOID *
> > +EFIAPI
> > +AllocatePagesWithMemoryType (
> > +  IN UINTN            MemoryType,
> > +  IN UINTN            Pages
> > +  );
> > +
> >  #endif
> > diff --git
> > a/MdePkg/Library/PeiMemoryAllocationLib/MemoryAllocationLib.c
> > b/MdePkg/Library/PeiMemoryAllocationLib/MemoryAllocationLib.c
> > index b3f9df74f139..dcb313349729 100644
> > --- a/MdePkg/Library/PeiMemoryAllocationLib/MemoryAllocationLib.c
> > +++ b/MdePkg/Library/PeiMemoryAllocationLib/MemoryAllocationLib.c
> > @@ -839,4 +839,31 @@ FreePool (
> >    //
> >  }
> >
> > +/**
> > +  Allocates one or more 4KB pages of given type MemoryType.
> >
> > +  Allocates the number of 4KB pages of MemoryType 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  MemoryType            Type of memory to use for this allocation.
> > +  @param  Pages                 The number of 4 KB pages to allocate.
> > +
> > +  @return A pointer to the allocated buffer or NULL if allocation fails.
> > +
> > +**/
> > +VOID *
> > +EFIAPI
> > +AllocatePagesWithMemoryType (
> > +  IN UINTN            MemoryType,
> > +  IN UINTN            Pages
> > +  )
> > +{
> > +  if (MemoryType >= EfiMaxMemoryType) {
> > +    ASSERT (FALSE);
> > +    return NULL;
> > +  }
> > +
> > +  return InternalAllocatePages (MemoryType, Pages); }
> > --
> > 2.29.2.windows.2


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

* Re: [edk2-devel] [PATCH 05/23] MdePkg: Add TdxProbeLib to probe Intel Tdx
  2021-08-12 11:56 ` [PATCH 05/23] MdePkg: Add TdxProbeLib to probe Intel Tdx Min Xu
@ 2021-08-16  9:43   ` Gerd Hoffmann
  2021-08-17  0:14     ` Min Xu
  2021-09-11  1:14   ` Erdem Aktas
  1 sibling, 1 reply; 64+ messages in thread
From: Gerd Hoffmann @ 2021-08-16  9:43 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

> +++ b/MdePkg/Library/TdxProbeLib/X64/TdProbe.nasm

Any specific reason why you code up your own instead of using the
existing cpuid functions in BaseLib ?

take care,
  Gerd


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

* Re: [edk2-devel] [PATCH 05/23] MdePkg: Add TdxProbeLib to probe Intel Tdx
  2021-08-16  9:43   ` [edk2-devel] " Gerd Hoffmann
@ 2021-08-17  0:14     ` Min Xu
  2021-08-17  8:20       ` Gerd Hoffmann
  0 siblings, 1 reply; 64+ messages in thread
From: Min Xu @ 2021-08-17  0:14 UTC (permalink / raw)
  To: devel@edk2.groups.io, kraxel@redhat.com
  Cc: Kinney, Michael D, Liming Gao, Liu, Zhiguang, Brijesh Singh,
	Erdem Aktas, James Bottomley, Yao, Jiewen, Tom Lendacky

On Monday, August 16, 2021 5:43 PM, Gerd Hoffmann wrote:
> > +++ b/MdePkg/Library/TdxProbeLib/X64/TdProbe.nasm
> 
> Any specific reason why you code up your own instead of using the existing
> cpuid functions in BaseLib ?
Actually there is no specific reason. I am not sure if AsmCpuid is a preferred way
in this situation? If yes I will update my code to use AsmCpuid.
> 
Thanks!
Min

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

* Re: [edk2-devel] [PATCH 05/23] MdePkg: Add TdxProbeLib to probe Intel Tdx
  2021-08-17  0:14     ` Min Xu
@ 2021-08-17  8:20       ` Gerd Hoffmann
  2021-08-17  8:43         ` Min Xu
  0 siblings, 1 reply; 64+ messages in thread
From: Gerd Hoffmann @ 2021-08-17  8:20 UTC (permalink / raw)
  To: devel, min.m.xu
  Cc: Kinney, Michael D, Liming Gao, Liu, Zhiguang, Brijesh Singh,
	Erdem Aktas, James Bottomley, Yao, Jiewen, Tom Lendacky

On Tue, Aug 17, 2021 at 12:14:44AM +0000, Min Xu wrote:
> On Monday, August 16, 2021 5:43 PM, Gerd Hoffmann wrote:
> > > +++ b/MdePkg/Library/TdxProbeLib/X64/TdProbe.nasm
> > 
> > Any specific reason why you code up your own instead of using the existing
> > cpuid functions in BaseLib ?
> Actually there is no specific reason. I am not sure if AsmCpuid is a preferred way
> in this situation?

I'm pretty sure it is preferred over duplicating code.

Early setup code (before stack setup where you can't do calls)
is a different story.

Also: Why there are separate TdxProbeLib + TdxLib libs?

take care,
  Gerd


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

* Re: [edk2-devel] [PATCH 07/23] MdePkg: Update BaseIoLibIntrinsicSev to support Tdx
  2021-08-12 11:56 ` [PATCH 07/23] MdePkg: Update BaseIoLibIntrinsicSev to support Tdx Min Xu
@ 2021-08-17  8:38   ` Gerd Hoffmann
  2021-08-18  5:54     ` Min Xu
  2021-09-11  1:15   ` Erdem Aktas
  1 sibling, 1 reply; 64+ messages in thread
From: Gerd Hoffmann @ 2021-08-17  8:38 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

  Hi,

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

Sorry, I'm a bit late to the party, but what is the overall long plan
here?

IIRC some of the TDX features require a separate firmware binary.  So,
if we need a separate binary anyway at some point in the future, isn't
it simpler then to use a separate firmware binary right from the start?

You can simply add a Tdx-specific variant of the library
(BaseIoLibIntrinsicTdx.inf) and switch at compile time instead of
having runtime switches all over the place.

take care,
  Gerd


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

* Re: [edk2-devel] [PATCH 05/23] MdePkg: Add TdxProbeLib to probe Intel Tdx
  2021-08-17  8:20       ` Gerd Hoffmann
@ 2021-08-17  8:43         ` Min Xu
  2021-08-17  8:58           ` Gerd Hoffmann
  0 siblings, 1 reply; 64+ messages in thread
From: Min Xu @ 2021-08-17  8:43 UTC (permalink / raw)
  To: devel@edk2.groups.io, kraxel@redhat.com
  Cc: Kinney, Michael D, Liming Gao, Liu, Zhiguang, Brijesh Singh,
	Erdem Aktas, James Bottomley, Yao, Jiewen, Tom Lendacky

On August 17, 2021 4:21 PM, Gerd Hoffmann wrote:
> On Tue, Aug 17, 2021 at 12:14:44AM +0000, Min Xu wrote:
> > On Monday, August 16, 2021 5:43 PM, Gerd Hoffmann wrote:
> > > > +++ b/MdePkg/Library/TdxProbeLib/X64/TdProbe.nasm
> > >
> > > Any specific reason why you code up your own instead of using the
> > > existing cpuid functions in BaseLib ?
> > Actually there is no specific reason. I am not sure if AsmCpuid is a
> > preferred way in this situation?
> 
> I'm pretty sure it is preferred over duplicating code.
Thanks for reminder. I will use AsmCpuid  in my next version.
> 
> Early setup code (before stack setup where you can't do calls) is a different story.
> 
> Also: Why there are separate TdxProbeLib + TdxLib libs?
This is because TdxLib wrap the operations of TdCall and TdVmcall. While TdxProbeLib
is a library to probe (call CPUID(0x21)) if it is td guest or not. I am open to merge these 2
libs into one if the community think it is a right way.
> 
> take care,
>   Gerd
> 
> 
> 
> 
> 


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

* Re: [edk2-devel] [PATCH 05/23] MdePkg: Add TdxProbeLib to probe Intel Tdx
  2021-08-17  8:43         ` Min Xu
@ 2021-08-17  8:58           ` Gerd Hoffmann
  0 siblings, 0 replies; 64+ messages in thread
From: Gerd Hoffmann @ 2021-08-17  8:58 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,

> > Also: Why there are separate TdxProbeLib + TdxLib libs?
> This is because TdxLib wrap the operations of TdCall and TdVmcall. While TdxProbeLib
> is a library to probe (call CPUID(0x21)) if it is td guest or not. I am open to merge these 2
> libs into one if the community think it is a right way.

My expectation is that you would need either none (build without tdx
support) or both (build with tdx support).  If that is correct I don't
see the point in splitting this into two libs.

take care,
  Gerd


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

* Re: [edk2-devel] [PATCH 07/23] MdePkg: Update BaseIoLibIntrinsicSev to support Tdx
  2021-08-17  8:38   ` [edk2-devel] " Gerd Hoffmann
@ 2021-08-18  5:54     ` Min Xu
  2021-08-19  6:30       ` Gerd Hoffmann
  0 siblings, 1 reply; 64+ messages in thread
From: Min Xu @ 2021-08-18  5:54 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 August 17, 2021 4:38 PM, Gerd Hoffmann wrote:
> 
>   Hi,
> 
> > 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.
> 
> Sorry, I'm a bit late to the party, but what is the overall long plan here?
>
Yes there are discussions about the TDVF (Trust Domain Virtual Firmware).
https://edk2.groups.io/g/devel/topic/83283616#76022
The design slides and recorded meeting are in below link:
https://edk2.groups.io/g/devel/files/Designs/2021/0611

> 
> IIRC some of the TDX features require a separate firmware binary.  So, if we
> need a separate binary anyway at some point in the future, isn't it simpler then
> to use a separate firmware binary right from the start?
> 
> You can simply add a Tdx-specific variant of the library
> (BaseIoLibIntrinsicTdx.inf) and switch at compile time instead of having runtime
> switches all over the place.
> 
TDVF has 2 Config for upstream. See https://edk2.groups.io/g/devel/message/76367
Config-A merge the *basic* TDVF features to existing OvmfX64Pkg.dsc. (Align with existing SEV).
OvmfX64Pkg.dsc includes SEV/TDX/normal OVMF basic boot capability. The final binary can run on SEV/TDX/normal OVMF
So we have to probe the Td guest in run-time and switch to the corresponding I/O routine.
The solution of using a separate firmware binary is not feasible in this situation.

Thanks.
Min

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

* Re: [edk2-devel] [PATCH 07/23] MdePkg: Update BaseIoLibIntrinsicSev to support Tdx
  2021-08-18  5:54     ` Min Xu
@ 2021-08-19  6:30       ` Gerd Hoffmann
  2021-08-19 13:12         ` Min Xu
  0 siblings, 1 reply; 64+ messages in thread
From: Gerd Hoffmann @ 2021-08-19  6:30 UTC (permalink / raw)
  To: devel, min.m.xu
  Cc: Kinney, Michael D, Liming Gao, Liu, Zhiguang, Brijesh Singh,
	Erdem Aktas, James Bottomley, Yao, Jiewen, Tom Lendacky

  Hi,

> > IIRC some of the TDX features require a separate firmware binary.  So, if we
> > need a separate binary anyway at some point in the future, isn't it simpler then
> > to use a separate firmware binary right from the start?
> > 
> > You can simply add a Tdx-specific variant of the library
> > (BaseIoLibIntrinsicTdx.inf) and switch at compile time instead of having runtime
> > switches all over the place.
> > 
> TDVF has 2 Config for upstream. See https://edk2.groups.io/g/devel/message/76367
> Config-A merge the *basic* TDVF features to existing OvmfX64Pkg.dsc. (Align with existing SEV).

Hmm, so we'll have two variants with two feature sets.

One more question:  How does this align with the WorkArea changes posted
yesterday?  The WorkArea gets a mode field for SEV / TDX / normal, so
I think you should be able to use that instead of invoking cpuid each
time you need to know whenever tdx is active or not.

take care,
  Gerd


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

* Re: [edk2-devel] [PATCH 18/23] OvmfPkg: Enable Tdx in SecMain.c
  2021-08-12 11:56 ` [PATCH 18/23] OvmfPkg: Enable Tdx in SecMain.c Min Xu
@ 2021-08-19  6:49   ` Gerd Hoffmann
  2021-08-19 14:27     ` Min Xu
  0 siblings, 1 reply; 64+ messages in thread
From: Gerd Hoffmann @ 2021-08-19  6: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,

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

What kind of information is passed to the guest here?

qemu has fw_cfg to pass information from the VMM to the guest firmware.
What are the reasons to not use fw_cfg?

thanks,
  Gerd


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

* Re: [edk2-devel] [PATCH 07/23] MdePkg: Update BaseIoLibIntrinsicSev to support Tdx
  2021-08-19  6:30       ` Gerd Hoffmann
@ 2021-08-19 13:12         ` Min Xu
  2021-08-20  6:41           ` Gerd Hoffmann
  0 siblings, 1 reply; 64+ messages in thread
From: Min Xu @ 2021-08-19 13:12 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 August 19, 2021 2:31 PM, Gerd Hoffmann wrote:
> > > IIRC some of the TDX features require a separate firmware binary.
> > > So, if we need a separate binary anyway at some point in the future,
> > > isn't it simpler then to use a separate firmware binary right from the start?
> > >
> > > You can simply add a Tdx-specific variant of the library
> > > (BaseIoLibIntrinsicTdx.inf) and switch at compile time instead of
> > > having runtime switches all over the place.
> > >
> > TDVF has 2 Config for upstream. See
> > https://edk2.groups.io/g/devel/message/76367
> > Config-A merge the *basic* TDVF features to existing OvmfX64Pkg.dsc.
> (Align with existing SEV).
> 
> Hmm, so we'll have two variants with two feature sets.
> 
> One more question:  How does this align with the WorkArea changes posted
> yesterday?  The WorkArea gets a mode field for SEV / TDX / normal, so I think
> you should be able to use that instead of invoking cpuid each time you need
> to know whenever tdx is active or not.
We don't want to make the TdxProbeLib depend on the WorkArea. CPUID(0x21)
makes TdxProbeLib less dependency.  For Intel TDX the WorkArea is designed to
be used in ResetVector phase.
> 
Thanks!
Min

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

* Re: [edk2-devel] [PATCH 18/23] OvmfPkg: Enable Tdx in SecMain.c
  2021-08-19  6:49   ` [edk2-devel] " Gerd Hoffmann
@ 2021-08-19 14:27     ` Min Xu
  2021-08-20  7:22       ` Gerd Hoffmann
  0 siblings, 1 reply; 64+ messages in thread
From: Min Xu @ 2021-08-19 14:27 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 August 19, 2021 2:50 PM, Gerd Hoffmann wrote:
> > +/**
> > +  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.
> 
> What kind of information is passed to the guest here?
Please see https://software.intel.com/content/dam/develop/external/us/en/documents/tdx-virtual-firmware-design-guide-rev-1.pdf
Section 4.2 TD Hand-Off Block (HOB)
> 
> qemu has fw_cfg to pass information from the VMM to the guest firmware.
> What are the reasons to not use fw_cfg?
Not all the VMM support fw_cfg. Cloud-Hypervisor is the example. 
https://github.com/cloud-hypervisor/cloud-hypervisor
TD Hob list gives Cloud-Hypervisor a chance to pass information to guest firmware. 
For example, ACPI can be downloaded from QEMU via fw_cfg to firmware. But
Cloud-Hypervisor cannot pass ACPI via fw_cfg. In this situation, TD Hob can resolve
this problem.
> 
> thanks,
>   Gerd


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

* Re: [edk2-devel] [PATCH 07/23] MdePkg: Update BaseIoLibIntrinsicSev to support Tdx
  2021-08-19 13:12         ` Min Xu
@ 2021-08-20  6:41           ` Gerd Hoffmann
  0 siblings, 0 replies; 64+ messages in thread
From: Gerd Hoffmann @ 2021-08-20  6:41 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,

> > One more question:  How does this align with the WorkArea changes posted
> > yesterday?  The WorkArea gets a mode field for SEV / TDX / normal, so I think
> > you should be able to use that instead of invoking cpuid each time you need
> > to know whenever tdx is active or not.
> We don't want to make the TdxProbeLib depend on the WorkArea.

Why?

> CPUID(0x21) makes TdxProbeLib less dependency.  For Intel TDX the
> WorkArea is designed to be used in ResetVector phase.

I don't see why the dependency is a problem.  TDX-enabled builds need
both TdxProbeLib / TdxLib and WorkArea anyway.

Each cpuid instruction is a vmexit, and the code invokes cpuid twice for
each io / mmio access.

take care,
  Gerd


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

* Re: [edk2-devel] [PATCH 18/23] OvmfPkg: Enable Tdx in SecMain.c
  2021-08-19 14:27     ` Min Xu
@ 2021-08-20  7:22       ` Gerd Hoffmann
  2021-08-24 12:07         ` Min Xu
  0 siblings, 1 reply; 64+ messages in thread
From: Gerd Hoffmann @ 2021-08-20  7:22 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 Thu, Aug 19, 2021 at 02:27:16PM +0000, Min Xu wrote:
> On August 19, 2021 2:50 PM, Gerd Hoffmann wrote:
> > > +/**
> > > +  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.
> > 
> > What kind of information is passed to the guest here?
> Please see https://software.intel.com/content/dam/develop/external/us/en/documents/tdx-virtual-firmware-design-guide-rev-1.pdf
> Section 4.2 TD Hand-Off Block (HOB)

So basically the physical memory map.
qemu has etc/e820 for that.

> > qemu has fw_cfg to pass information from the VMM to the guest firmware.
> > What are the reasons to not use fw_cfg?
> Not all the VMM support fw_cfg. Cloud-Hypervisor is the example. 

I can't see any support for Cloud-Hypervisor in OVMF.

Also FreeBSD's bhyve doesn't support fw_cfg either and has its own
ways to detect memory.  Cloud-Hypervisor can surely do that too.

So, why does this matter?

> https://github.com/cloud-hypervisor/cloud-hypervisor
> TD Hob list gives Cloud-Hypervisor a chance to pass information to guest firmware. 
> For example, ACPI can be downloaded from QEMU via fw_cfg to firmware. But
> Cloud-Hypervisor cannot pass ACPI via fw_cfg. In this situation, TD Hob can resolve
> this problem.

Sure, but again, why does this matter?  For qemu?

I don't like the idea to have TDX take a completely different code paths.
That increases the code complexity and makes testing harder for no good
reason.

take care,
  Gerd


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

* Re: [edk2-devel] [PATCH 18/23] OvmfPkg: Enable Tdx in SecMain.c
  2021-08-20  7:22       ` Gerd Hoffmann
@ 2021-08-24 12:07         ` Min Xu
  2021-08-24 12:55           ` Ard Biesheuvel
  2021-08-25  6:22           ` Gerd Hoffmann
  0 siblings, 2 replies; 64+ messages in thread
From: Min Xu @ 2021-08-24 12:07 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 August 20, 2021 3:23 PM, Gerd Hoffmann wrote:
> On Thu, Aug 19, 2021 at 02:27:16PM +0000, Min Xu wrote:
> > On August 19, 2021 2:50 PM, Gerd Hoffmann wrote:
> > > > +/**
> > > > +  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.
> > >
> > > What kind of information is passed to the guest here?
> > Please see
> >
> https://software.intel.com/content/dam/develop/external/us/en/document
> > s/tdx-virtual-firmware-design-guide-rev-1.pdf
> > Section 4.2 TD Hand-Off Block (HOB)
> 
> So basically the physical memory map.
> qemu has etc/e820 for that.
> 
> > > qemu has fw_cfg to pass information from the VMM to the guest
> firmware.
> > > What are the reasons to not use fw_cfg?
> > Not all the VMM support fw_cfg. Cloud-Hypervisor is the example.
> 
> I can't see any support for Cloud-Hypervisor in OVMF.
Right that currently OVMF is not supported by Cloud-Hypervisor in Td guest. But we're
planning to support Cloud-Hypervisor to launch OVMF in Td guest and have done
some POC.
> 
> Also FreeBSD's bhyve doesn't support fw_cfg either and has its own ways to
> detect memory.  Cloud-Hypervisor can surely do that too.
> 
> So, why does this matter?
Yes, Cloud-Hypervisor has some POC to launch OVMF in Non-Td guest. In that POC
Cloud-Hypervisor leverage a 4k page in MEMFD and pass ACPI data to guest
Firmware in that memory.
https://github.com/cloud-hypervisor/edk2 "ch" branch
https://github.com/cloud-hypervisor/edk2/commit/52cb72a748ef70833100ca664f6c2a704c28a93f
> 
> > https://github.com/cloud-hypervisor/cloud-hypervisor
> > TD Hob list gives Cloud-Hypervisor a chance to pass information to guest
> firmware.
> > For example, ACPI can be downloaded from QEMU via fw_cfg to firmware.
> > But Cloud-Hypervisor cannot pass ACPI via fw_cfg. In this situation,
> > TD Hob can resolve this problem.
> 
> Sure, but again, why does this matter?  For qemu?
I don't quite understand the question here(For qumu?).
What I mean in my last answer is that TD Hob can resolve the problem when the host VMM
doesn't support fw_cfg communication mechanism. 
For the host VMMs which doesn't support fw_cfg, when ACPI data need to be passed to guest
firmware, a 4k page (to hold ACPI data) is added in MEMFD. Then when SMBIOS is needed,
shall we add another page in MEMFD? If the ACPI data is too big to be held in a 4k page, then
the size of the reserved memory region in MEMFD is the restriction.
> 
> I don't like the idea to have TDX take a completely different code paths.
> That increases the code complexity and makes testing harder for no good
> reason.
TD Hob is not a completely different code path. This is a useful supplement to the fw_cfg which
is not supported by some host VMM. 
>From another perspective TD Hob can be treated as a set of launch parameter by host VMM. 
It provides the flexibility for the host VMM to bring up the guest firmware with more parameters.
Another benefit is that TD Hob can be measured into some secure register (for example, in TD guest
it is RTMR registers, like the TPM PCR) so that attestation can be done based on the measurement.

Thanks Gerd for the comments. I am not sure if my explanation addressed your concern. Your comments
is always welcomed.
> 

Thanks!
Min

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

* Re: [edk2-devel] [PATCH 18/23] OvmfPkg: Enable Tdx in SecMain.c
  2021-08-24 12:07         ` Min Xu
@ 2021-08-24 12:55           ` Ard Biesheuvel
  2021-08-25  6:10             ` Yao, Jiewen
  2021-08-25  6:22           ` Gerd Hoffmann
  1 sibling, 1 reply; 64+ messages in thread
From: Ard Biesheuvel @ 2021-08-24 12:55 UTC (permalink / raw)
  To: Xu, Min M
  Cc: Gerd Hoffmann, devel@edk2.groups.io, Ard Biesheuvel,
	Justen, Jordan L, Brijesh Singh, Erdem Aktas, James Bottomley,
	Yao, Jiewen, Tom Lendacky

On Tue, 24 Aug 2021 at 14:07, Xu, Min M <min.m.xu@intel.com> wrote:
>
> On August 20, 2021 3:23 PM, Gerd Hoffmann wrote:
> > On Thu, Aug 19, 2021 at 02:27:16PM +0000, Min Xu wrote:
> > > On August 19, 2021 2:50 PM, Gerd Hoffmann wrote:
> > > > > +/**
> > > > > +  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.
> > > >
> > > > What kind of information is passed to the guest here?
> > > Please see
> > >
> > https://software.intel.com/content/dam/develop/external/us/en/document
> > > s/tdx-virtual-firmware-design-guide-rev-1.pdf
> > > Section 4.2 TD Hand-Off Block (HOB)
> >
> > So basically the physical memory map.
> > qemu has etc/e820 for that.
> >
> > > > qemu has fw_cfg to pass information from the VMM to the guest
> > firmware.
> > > > What are the reasons to not use fw_cfg?
> > > Not all the VMM support fw_cfg. Cloud-Hypervisor is the example.
> >
> > I can't see any support for Cloud-Hypervisor in OVMF.
> Right that currently OVMF is not supported by Cloud-Hypervisor in Td guest. But we're
> planning to support Cloud-Hypervisor to launch OVMF in Td guest and have done
> some POC.

If cloud hypervisor support is coming to OVMF, please contribute those
patches first, so they can be discussed in public. Adding special
facilities here to accommodate out of tree functionality that may look
completely differently after review is not the right way to approach
this.

-- 
Ard.


> >
> > Also FreeBSD's bhyve doesn't support fw_cfg either and has its own ways to
> > detect memory.  Cloud-Hypervisor can surely do that too.
> >
> > So, why does this matter?
> Yes, Cloud-Hypervisor has some POC to launch OVMF in Non-Td guest. In that POC
> Cloud-Hypervisor leverage a 4k page in MEMFD and pass ACPI data to guest
> Firmware in that memory.
> https://github.com/cloud-hypervisor/edk2 "ch" branch
> https://github.com/cloud-hypervisor/edk2/commit/52cb72a748ef70833100ca664f6c2a704c28a93f
> >
> > > https://github.com/cloud-hypervisor/cloud-hypervisor
> > > TD Hob list gives Cloud-Hypervisor a chance to pass information to guest
> > firmware.
> > > For example, ACPI can be downloaded from QEMU via fw_cfg to firmware.
> > > But Cloud-Hypervisor cannot pass ACPI via fw_cfg. In this situation,
> > > TD Hob can resolve this problem.
> >
> > Sure, but again, why does this matter?  For qemu?
> I don't quite understand the question here(For qumu?).
> What I mean in my last answer is that TD Hob can resolve the problem when the host VMM
> doesn't support fw_cfg communication mechanism.
> For the host VMMs which doesn't support fw_cfg, when ACPI data need to be passed to guest
> firmware, a 4k page (to hold ACPI data) is added in MEMFD. Then when SMBIOS is needed,
> shall we add another page in MEMFD? If the ACPI data is too big to be held in a 4k page, then
> the size of the reserved memory region in MEMFD is the restriction.
> >
> > I don't like the idea to have TDX take a completely different code paths.
> > That increases the code complexity and makes testing harder for no good
> > reason.
> TD Hob is not a completely different code path. This is a useful supplement to the fw_cfg which
> is not supported by some host VMM.
> From another perspective TD Hob can be treated as a set of launch parameter by host VMM.
> It provides the flexibility for the host VMM to bring up the guest firmware with more parameters.
> Another benefit is that TD Hob can be measured into some secure register (for example, in TD guest
> it is RTMR registers, like the TPM PCR) so that attestation can be done based on the measurement.
>
> Thanks Gerd for the comments. I am not sure if my explanation addressed your concern. Your comments
> is always welcomed.
> >
>
> Thanks!
> Min

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

* Re: [edk2-devel] [PATCH 18/23] OvmfPkg: Enable Tdx in SecMain.c
  2021-08-24 12:55           ` Ard Biesheuvel
@ 2021-08-25  6:10             ` Yao, Jiewen
  2021-08-25  7:52               ` Gerd Hoffmann
  0 siblings, 1 reply; 64+ messages in thread
From: Yao, Jiewen @ 2021-08-25  6:10 UTC (permalink / raw)
  To: Ard Biesheuvel, Xu, Min M
  Cc: Gerd Hoffmann, devel@edk2.groups.io, Ard Biesheuvel,
	Justen, Jordan L, Brijesh Singh, Erdem Aktas, James Bottomley,
	Tom Lendacky

HI Ard and Gerd
I am not sure if I fully understand the argument here.

In TDX architecture, the VMM provides a pointer to the TD guest as initial parameter. We define the detail information there to be TD Hob. This solution is generic to all hypervisor.

fw_cfg is just a KVM/QEMU specific way to pass some parameter, but not all parameter.
For example, OVMF today still get the memory size from CMOS.
https://github.com/tianocore/edk2/blob/master/OvmfPkg/PlatformPei/MemDetect.c#L278

In TDVF design, we choose the use TDX defined initial pointer to pass the initial memory information - TD_HOB, instead of CMOS region.
Please help me understand what is the real concern here.



I understand the QEMU specific fw_cfg (https://github.com/qemu/qemu/blob/master/docs/specs/fw_cfg.txt).
If you want to use fw_cfg to pass some QEMU specific parameter, it is still possible.
For security reason, any input from the IO device must be measured by the TD guest.

That means, if you get the same data twice from the fw_cfg, the TDVF must measure them twice. And TDVF may need handle the case that the data in first call is different with the data in second call.
I can see potential attack surface there from architecture perspective.

Using HOB in the initial pointer can be an alternative pattern to mitigate such risk. We just need measure them once then any component can use that. Also, it can help the people to evaluate the RTMR hash and TD event log data for the configuration in attestation flow, because the configuration is independent with the code execution flow.

Please be aware that confidential computing (TDX) changes the threat model completely, any input from VMM is considered as malicious. Current solution might be OK for normal OVMF. But it does not mean the same solution is still the best one for confidential computing use case.


Thank you
Yao Jiewen


> -----Original Message-----
> From: Ard Biesheuvel <ardb@kernel.org>
> Sent: Tuesday, August 24, 2021 8:56 PM
> To: Xu, Min M <min.m.xu@intel.com>
> Cc: Gerd Hoffmann <kraxel@redhat.com>; devel@edk2.groups.io; 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 18/23] OvmfPkg: Enable Tdx in SecMain.c
> 
> On Tue, 24 Aug 2021 at 14:07, Xu, Min M <min.m.xu@intel.com> wrote:
> >
> > On August 20, 2021 3:23 PM, Gerd Hoffmann wrote:
> > > On Thu, Aug 19, 2021 at 02:27:16PM +0000, Min Xu wrote:
> > > > On August 19, 2021 2:50 PM, Gerd Hoffmann wrote:
> > > > > > +/**
> > > > > > +  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.
> > > > >
> > > > > What kind of information is passed to the guest here?
> > > > Please see
> > > >
> > > https://software.intel.com/content/dam/develop/external/us/en/document
> > > > s/tdx-virtual-firmware-design-guide-rev-1.pdf
> > > > Section 4.2 TD Hand-Off Block (HOB)
> > >
> > > So basically the physical memory map.
> > > qemu has etc/e820 for that.
> > >
> > > > > qemu has fw_cfg to pass information from the VMM to the guest
> > > firmware.
> > > > > What are the reasons to not use fw_cfg?
> > > > Not all the VMM support fw_cfg. Cloud-Hypervisor is the example.
> > >
> > > I can't see any support for Cloud-Hypervisor in OVMF.
> > Right that currently OVMF is not supported by Cloud-Hypervisor in Td guest.
> But we're
> > planning to support Cloud-Hypervisor to launch OVMF in Td guest and have
> done
> > some POC.
> 
> If cloud hypervisor support is coming to OVMF, please contribute those
> patches first, so they can be discussed in public. Adding special
> facilities here to accommodate out of tree functionality that may look
> completely differently after review is not the right way to approach
> this.
> 
> --
> Ard.
> 
> 
> > >
> > > Also FreeBSD's bhyve doesn't support fw_cfg either and has its own ways to
> > > detect memory.  Cloud-Hypervisor can surely do that too.
> > >
> > > So, why does this matter?
> > Yes, Cloud-Hypervisor has some POC to launch OVMF in Non-Td guest. In that
> POC
> > Cloud-Hypervisor leverage a 4k page in MEMFD and pass ACPI data to guest
> > Firmware in that memory.
> > https://github.com/cloud-hypervisor/edk2 "ch" branch
> > https://github.com/cloud-
> hypervisor/edk2/commit/52cb72a748ef70833100ca664f6c2a704c28a93f
> > >
> > > > https://github.com/cloud-hypervisor/cloud-hypervisor
> > > > TD Hob list gives Cloud-Hypervisor a chance to pass information to guest
> > > firmware.
> > > > For example, ACPI can be downloaded from QEMU via fw_cfg to firmware.
> > > > But Cloud-Hypervisor cannot pass ACPI via fw_cfg. In this situation,
> > > > TD Hob can resolve this problem.
> > >
> > > Sure, but again, why does this matter?  For qemu?
> > I don't quite understand the question here(For qumu?).
> > What I mean in my last answer is that TD Hob can resolve the problem when
> the host VMM
> > doesn't support fw_cfg communication mechanism.
> > For the host VMMs which doesn't support fw_cfg, when ACPI data need to be
> passed to guest
> > firmware, a 4k page (to hold ACPI data) is added in MEMFD. Then when
> SMBIOS is needed,
> > shall we add another page in MEMFD? If the ACPI data is too big to be held in a
> 4k page, then
> > the size of the reserved memory region in MEMFD is the restriction.
> > >
> > > I don't like the idea to have TDX take a completely different code paths.
> > > That increases the code complexity and makes testing harder for no good
> > > reason.
> > TD Hob is not a completely different code path. This is a useful supplement to
> the fw_cfg which
> > is not supported by some host VMM.
> > From another perspective TD Hob can be treated as a set of launch parameter
> by host VMM.
> > It provides the flexibility for the host VMM to bring up the guest firmware with
> more parameters.
> > Another benefit is that TD Hob can be measured into some secure register (for
> example, in TD guest
> > it is RTMR registers, like the TPM PCR) so that attestation can be done based
> on the measurement.
> >
> > Thanks Gerd for the comments. I am not sure if my explanation addressed your
> concern. Your comments
> > is always welcomed.
> > >
> >
> > Thanks!
> > Min

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

* Re: [edk2-devel] [PATCH 18/23] OvmfPkg: Enable Tdx in SecMain.c
  2021-08-24 12:07         ` Min Xu
  2021-08-24 12:55           ` Ard Biesheuvel
@ 2021-08-25  6:22           ` Gerd Hoffmann
  1 sibling, 0 replies; 64+ messages in thread
From: Gerd Hoffmann @ 2021-08-25  6:22 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

  Hi,

> > I can't see any support for Cloud-Hypervisor in OVMF.
> Right that currently OVMF is not supported by Cloud-Hypervisor in Td guest. But we're
> planning to support Cloud-Hypervisor to launch OVMF in Td guest and have done
> some POC.

> > Also FreeBSD's bhyve doesn't support fw_cfg either and has its own ways to
> > detect memory.  Cloud-Hypervisor can surely do that too.
> > 
> > So, why does this matter?
> Yes, Cloud-Hypervisor has some POC to launch OVMF in Non-Td guest. In that POC
> Cloud-Hypervisor leverage a 4k page in MEMFD and pass ACPI data to guest
> Firmware in that memory.
> https://github.com/cloud-hypervisor/edk2 "ch" branch
> https://github.com/cloud-hypervisor/edk2/commit/52cb72a748ef70833100ca664f6c2a704c28a93f

Post the Cloud-Hypervisor patches to the list for review if you want
them included in OVMF.  out-of-tree patches lingering in some random
branch @ github do not matter.

> > > https://github.com/cloud-hypervisor/cloud-hypervisor
> > > TD Hob list gives Cloud-Hypervisor a chance to pass information to guest
> > firmware.
> > > For example, ACPI can be downloaded from QEMU via fw_cfg to firmware.
> > > But Cloud-Hypervisor cannot pass ACPI via fw_cfg. In this situation,
> > > TD Hob can resolve this problem.
> > 
> > Sure, but again, why does this matter?  For qemu?
> I don't quite understand the question here(For qumu?).

Well, each VMM has different interfaces for guest <-> host
communication.  qemu/kvm uses fw_cfg.  Xen and Bhyve have something
different, and Cloud-Hypervisor seems to have something different again.

> What I mean in my last answer is that TD Hob can resolve the problem
> when the host VMM doesn't support fw_cfg communication mechanism. 

Sure.  If Cloud-Hypervisor wants use that (for both TDX and non-TDX
probably), fine.  Submit the patches and we can discuss details.

But why do you want switch qemu/kvm from fw_cfg to TD Hob?

> > I don't like the idea to have TDX take a completely different code
> > paths.  That increases the code complexity and makes testing harder
> > for no good reason.

> TD Hob is not a completely different code path. This is a useful
> supplement to the fw_cfg which is not supported by some host VMM. 

The code uses that unconditionally though and not only in case fw_cfg
is not available.

> From another perspective TD Hob can be treated as a set of launch
> parameter by host VMM.  It provides the flexibility for the host VMM
> to bring up the guest firmware with more parameters.

I'm wondering what you are running on the host?  I assumed we are
discussing qemu/kvm as VMM, is that actually the case?  Or do you
use Cloud Hypervisor?

qemu doesn't provide a TD Hob.  So, when running qemu you probably have
some out-of-tree patches adding that.  Have you submitted them upstream?
What is the status?

I suspect you need to come up with some *very* good arguments to get
that accepted.  The need to bring parameters to the guest firmware is
the reason why fw_cfg exists in the first place ...

> Another benefit is that TD Hob can be measured into some secure
> register (for example, in TD guest it is RTMR registers, like the TPM
> PCR) so that attestation can be done based on the measurement.

fw_cfg is measured too (according to one of the tdx pdfs, don't remember
which one).

take care,
  Gerd


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

* Re: [edk2-devel] [PATCH 18/23] OvmfPkg: Enable Tdx in SecMain.c
  2021-08-25  6:10             ` Yao, Jiewen
@ 2021-08-25  7:52               ` Gerd Hoffmann
  2021-08-25  9:07                 ` Yao, Jiewen
  0 siblings, 1 reply; 64+ messages in thread
From: Gerd Hoffmann @ 2021-08-25  7:52 UTC (permalink / raw)
  To: Yao, Jiewen
  Cc: Ard Biesheuvel, Xu, Min M, devel@edk2.groups.io, Ard Biesheuvel,
	Justen, Jordan L, Brijesh Singh, Erdem Aktas, James Bottomley,
	Tom Lendacky

  Hi,

> fw_cfg is just a KVM/QEMU specific way to pass some parameter, but not
> all parameter.  For example, OVMF today still get the memory size from
> CMOS.
> https://github.com/tianocore/edk2/blob/master/OvmfPkg/PlatformPei/MemDetect.c#L278

Patches to fix that are on the list.

> In TDVF design, we choose the use TDX defined initial pointer to pass
> the initial memory information - TD_HOB, instead of CMOS region.
> Please help me understand what is the real concern here.

Well, qemu settled to the fw_cfg design or a number of reasons.  It is
pretty flexible for example.  The firmware can ask for the information
it needs at any time and can store it as it pleases.

I'd suggest to not take it for granted that an additional alternative
way to do basically the same thing will be accepted to upstream qemu.
Submit your patches to qemu-devel to discuss that.

> That means, if you get the same data twice from the fw_cfg, the TDVF
> must measure them twice. And TDVF may need handle the case that the
> data in first call is different with the data in second call.

Most fw_cfg entries are constant anyway, so we can easily avoid a second
call by caching the results of the first call if that helps TDVF.

> Using HOB in the initial pointer can be an alternative pattern to
> mitigate such risk. We just need measure them once then any component
> can use that. Also, it can help the people to evaluate the RTMR hash
> and TD event log data for the configuration in attestation flow,
> because the configuration is independent with the code execution flow.

Well, it covers only the memory map, correct?  All other configuration
is still loaded from fw_cfg.  I can't see the improvement here.

How do you pass the HOB to the guest?  Copy data to guest ram?  Map a
ro page into guest address space?  What happens on VM reset?

> Please be aware that confidential computing (TDX) changes the threat
> model completely, any input from VMM is considered as malicious.
> Current solution might be OK for normal OVMF. But it does not mean the
> same solution is still the best one for confidential computing use
> case.

Well, SEV seems to be happy with fw_cfg.
Any input from AMD on the topic?

take care,
  Gerd


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

* Re: [edk2-devel] [PATCH 18/23] OvmfPkg: Enable Tdx in SecMain.c
  2021-08-25  7:52               ` Gerd Hoffmann
@ 2021-08-25  9:07                 ` Yao, Jiewen
  2021-08-25 14:51                   ` Gerd Hoffmann
  0 siblings, 1 reply; 64+ messages in thread
From: Yao, Jiewen @ 2021-08-25  9:07 UTC (permalink / raw)
  To: devel@edk2.groups.io, kraxel@redhat.com
  Cc: Ard Biesheuvel, Xu, Min M, Ard Biesheuvel, Justen, Jordan L,
	Brijesh Singh, Erdem Aktas, James Bottomley, Tom Lendacky

Comment below:

> -----Original Message-----
> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Gerd
> Hoffmann
> Sent: Wednesday, August 25, 2021 3:52 PM
> To: Yao, Jiewen <jiewen.yao@intel.com>
> Cc: Ard Biesheuvel <ardb@kernel.org>; Xu, Min M <min.m.xu@intel.com>;
> devel@edk2.groups.io; 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 18/23] OvmfPkg: Enable Tdx in SecMain.c
> 
>   Hi,
> 
> > fw_cfg is just a KVM/QEMU specific way to pass some parameter, but not
> > all parameter.  For example, OVMF today still get the memory size from
> > CMOS.
> >
> https://github.com/tianocore/edk2/blob/master/OvmfPkg/PlatformPei/MemDe
> tect.c#L278
> 
> Patches to fix that are on the list.

[Jiewen] Surprisingly. It was sent one week ago.
I obviously miss that email.

Please file a Bugzilla and include me in CC list next time.

> 
> > In TDVF design, we choose the use TDX defined initial pointer to pass
> > the initial memory information - TD_HOB, instead of CMOS region.
> > Please help me understand what is the real concern here.
> 
> Well, qemu settled to the fw_cfg design or a number of reasons.  It is
> pretty flexible for example.  The firmware can ask for the information
> it needs at any time and can store it as it pleases.
> 
> I'd suggest to not take it for granted that an additional alternative
> way to do basically the same thing will be accepted to upstream qemu.
> Submit your patches to qemu-devel to discuss that.

[Jiewen] I think Intel Linux team is doing that separately.

> 
> > That means, if you get the same data twice from the fw_cfg, the TDVF
> > must measure them twice. And TDVF may need handle the case that the
> > data in first call is different with the data in second call.
> 
> Most fw_cfg entries are constant anyway, so we can easily avoid a second
> call by caching the results of the first call if that helps TDVF.


[Jiewen] It is possible. We can have multiple ways:
1) Per usage cache. However, that means every driver need use its own way to cache the data, either PCD or HOB in PEI phase. Also driver A need to know clearly that driver B will use the same data, then it will cache otherwise it will not cache. I treat it as a huge burden for the developer.
2) Always cache per driver. That means every driver need follow the same pattern: search cache, if miss the get it and cache it. But it still cannot guarantee the data order in different path architecturally.
3) Always cache in one common driver. One driver can get all data one time and cache them. That can resolve the data order problem. I am not sure if that is desired. But I cannot see too much difference between passing data at entry point.

> 
> > Using HOB in the initial pointer can be an alternative pattern to
> > mitigate such risk. We just need measure them once then any component
> > can use that. Also, it can help the people to evaluate the RTMR hash
> > and TD event log data for the configuration in attestation flow,
> > because the configuration is independent with the code execution flow.
> 
> Well, it covers only the memory map, correct?  All other configuration
> is still loaded from fw_cfg.  I can't see the improvement here.

[Jiewen] At this point of time, memory map is the most important parameter in the TD Hob, because we do need the memory information at the TD entrypoint. That is mandatory for any TD boot.

The fw_cfg is still allowed in the TDVF design guide, just because we feel it is a burden to convert everything suddenly.
I hope to limit the configuration from VMM. Most fw_cfg will NOT be used for TDVF, for example, "etc/smi", "etc/tpm", "etc/edk2/https/cacerts", "etc/msr_feature_control", "etc/system-states", especially in the container use case.

The flexibility is a double-sward.
You can treat the TD Hob as the boot parameter for the kernel, here is the kernel == TDVF.
Having a static way to get configuration data in memory at one time is the simplest solution, from my perspective. 


> 
> How do you pass the HOB to the guest?  Copy data to guest ram?  Map a
> ro page into guest address space?  What happens on VM reset?
[Jiewen] Yes, VMM will prepare the memory information based upon TDVF metadata.
The VMM need copy TD HOB data to a predefined memory region according to TDVF metadata.

I don't fully understand the VM reset question. I try to answer. But if that is not what you are asking, please clarify.

This action that VMM initiates TD HOB happens when the VMM launches a TD guest.
After that the region will becomes TD private memory and own by TD. VMM can no longer access it (no read/no write).
If VM reset, then this memory is gone.
If VMM need launch a new TD, the VMM need initiate the data again.



> 
> > Please be aware that confidential computing (TDX) changes the threat
> > model completely, any input from VMM is considered as malicious.
> > Current solution might be OK for normal OVMF. But it does not mean the
> > same solution is still the best one for confidential computing use
> > case.
> 
> Well, SEV seems to be happy with fw_cfg.
> Any input from AMD on the topic?



> 
> take care,
>   Gerd
> 
> 
> 
> 
> 


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

* Re: [edk2-devel] [PATCH 18/23] OvmfPkg: Enable Tdx in SecMain.c
  2021-08-25  9:07                 ` Yao, Jiewen
@ 2021-08-25 14:51                   ` Gerd Hoffmann
  2021-08-25 16:28                     ` Yao, Jiewen
  0 siblings, 1 reply; 64+ messages in thread
From: Gerd Hoffmann @ 2021-08-25 14:51 UTC (permalink / raw)
  To: Yao, Jiewen
  Cc: devel@edk2.groups.io, Ard Biesheuvel, Xu, Min M, Ard Biesheuvel,
	Justen, Jordan L, Brijesh Singh, Erdem Aktas, James Bottomley,
	Tom Lendacky

  Hi,

> > > In TDVF design, we choose the use TDX defined initial pointer to pass
> > > the initial memory information - TD_HOB, instead of CMOS region.
> > > Please help me understand what is the real concern here.
> > 
> > Well, qemu settled to the fw_cfg design or a number of reasons.  It is
> > pretty flexible for example.  The firmware can ask for the information
> > it needs at any time and can store it as it pleases.
> > 
> > I'd suggest to not take it for granted that an additional alternative
> > way to do basically the same thing will be accepted to upstream qemu.
> > Submit your patches to qemu-devel to discuss that.
> 
> [Jiewen] I think Intel Linux team is doing that separately.

Please ask them to send the patches.  Changes like this obviously need
coordination and agreement between qemu and edk2 projects, and ideally
both guest and host code is reviewed in parallel.

> > Most fw_cfg entries are constant anyway, so we can easily avoid a second
> > call by caching the results of the first call if that helps TDVF.
> 
> [Jiewen] It is possible. We can have multiple ways:
> 1) Per usage cache. However, that means every driver need use its own way to cache the data, either PCD or HOB in PEI phase. Also driver A need to know clearly that driver B will use the same data, then it will cache otherwise it will not cache. I treat it as a huge burden for the developer.
> 2) Always cache per driver. That means every driver need follow the same pattern: search cache, if miss the get it and cache it. But it still cannot guarantee the data order in different path architecturally.
> 3) Always cache in one common driver. One driver can get all data one time and cache them. That can resolve the data order problem. I am not sure if that is desired. But I cannot see too much difference between passing data at entry point.

Not investigated yet.  seabios fw_cfg handling is close to (3) for small
items (not kernel or initrd or other large data sets) so I think I would
look into that first.

> > > Using HOB in the initial pointer can be an alternative pattern to
> > > mitigate such risk. We just need measure them once then any component
> > > can use that. Also, it can help the people to evaluate the RTMR hash
> > > and TD event log data for the configuration in attestation flow,
> > > because the configuration is independent with the code execution flow.
> > 
> > Well, it covers only the memory map, correct?  All other configuration
> > is still loaded from fw_cfg.  I can't see the improvement here.
> 
> [Jiewen] At this point of time, memory map is the most important
> parameter in the TD Hob, because we do need the memory information at
> the TD entrypoint. That is mandatory for any TD boot.

Well, I can see that the memory map is kind of special here because you
need that quite early in the firmware initialization workflow.

> The fw_cfg is still allowed in the TDVF design guide, just because we
> feel it is a burden to convert everything suddenly.

What is the longer-term plan here?

Does it make sense to special-case the memory map?

If we want handle other fw_cfg items that way too later on, shouldn't we
better check how we can improve the fw_cfg interface so it works better
with confidential computing?

> > How do you pass the HOB to the guest?  Copy data to guest ram?  Map a
> > ro page into guest address space?  What happens on VM reset?

> [Jiewen] Yes, VMM will prepare the memory information based upon TDVF
> metadata.  The VMM need copy TD HOB data to a predefined memory region
> according to TDVF metadata.

Is all that documented somewhere?  The TVDF design overview focuses on
the guest/firmware side of things, so it isn't very helpful here.

Did I mention posting the qemu patches would be a good idea?

> I don't fully understand the VM reset question. I try to answer. But if that is not what you are asking, please clarify.

What happens if you reboot the guest?

On non-TDX guests the VM will be reset, the cpu will jump to the reset
vector (executing from rom / flash), firmware will re-initialize
everything and re-load any config information it needs from fw_cfg

> This action that VMM initiates TD HOB happens when the VMM launches a TD guest.
> After that the region will becomes TD private memory and own by TD. VMM can no longer access it (no read/no write).
> If VM reset, then this memory is gone.
> If VMM need launch a new TD, the VMM need initiate the data again.

Sounds like reset is not supported, you need to stop and re-start the
guest instead.  Is that correct?

take care,
  Gerd


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

* Re: [edk2-devel] [PATCH 18/23] OvmfPkg: Enable Tdx in SecMain.c
  2021-08-25 14:51                   ` Gerd Hoffmann
@ 2021-08-25 16:28                     ` Yao, Jiewen
  2021-08-26  8:31                       ` Gerd Hoffmann
  0 siblings, 1 reply; 64+ messages in thread
From: Yao, Jiewen @ 2021-08-25 16:28 UTC (permalink / raw)
  To: kraxel@redhat.com
  Cc: devel@edk2.groups.io, Ard Biesheuvel, Xu, Min M, Ard Biesheuvel,
	Justen, Jordan L, Brijesh Singh, Erdem Aktas, James Bottomley,
	Tom Lendacky, Yamahata, Isaku

Comment below:

> -----Original Message-----
> From: kraxel@redhat.com <kraxel@redhat.com>
> Sent: Wednesday, August 25, 2021 10:52 PM
> To: Yao, Jiewen <jiewen.yao@intel.com>
> Cc: devel@edk2.groups.io; Ard Biesheuvel <ardb@kernel.org>; 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 18/23] OvmfPkg: Enable Tdx in SecMain.c
> 
>   Hi,
> 
> > > > In TDVF design, we choose the use TDX defined initial pointer to pass
> > > > the initial memory information - TD_HOB, instead of CMOS region.
> > > > Please help me understand what is the real concern here.
> > >
> > > Well, qemu settled to the fw_cfg design or a number of reasons.  It is
> > > pretty flexible for example.  The firmware can ask for the information
> > > it needs at any time and can store it as it pleases.
> > >
> > > I'd suggest to not take it for granted that an additional alternative
> > > way to do basically the same thing will be accepted to upstream qemu.
> > > Submit your patches to qemu-devel to discuss that.
> >
> > [Jiewen] I think Intel Linux team is doing that separately.
> 
> Please ask them to send the patches.  Changes like this obviously need
> coordination and agreement between qemu and edk2 projects, and ideally
> both guest and host code is reviewed in parallel.

[Jiewen] Sure.

I add Yamahata, Isaku <isaku.yamahata@intel.com> here. He can help answer the KVM/QEMU related question.

Some reference for QEMU:
https://lists.nongnu.org/archive/html/qemu-devel/2021-07/msg01682.html
in patchwork, https://patchwork.kernel.org/project/qemu-devel/cover/cover.1625704980.git.isaku.yamahata@intel.com/

And I guess you probably need look at the KVM as well.



> 
> > > Most fw_cfg entries are constant anyway, so we can easily avoid a second
> > > call by caching the results of the first call if that helps TDVF.
> >
> > [Jiewen] It is possible. We can have multiple ways:
> > 1) Per usage cache. However, that means every driver need use its own way to
> cache the data, either PCD or HOB in PEI phase. Also driver A need to know
> clearly that driver B will use the same data, then it will cache otherwise it will
> not cache. I treat it as a huge burden for the developer.
> > 2) Always cache per driver. That means every driver need follow the same
> pattern: search cache, if miss the get it and cache it. But it still cannot guarantee
> the data order in different path architecturally.
> > 3) Always cache in one common driver. One driver can get all data one time
> and cache them. That can resolve the data order problem. I am not sure if that is
> desired. But I cannot see too much difference between passing data at entry
> point.
> 
> Not investigated yet.  seabios fw_cfg handling is close to (3) for small
> items (not kernel or initrd or other large data sets) so I think I would
> look into that first.

[Jiewen] I don't think it is urgent at this moment.


> 
> > > > Using HOB in the initial pointer can be an alternative pattern to
> > > > mitigate such risk. We just need measure them once then any component
> > > > can use that. Also, it can help the people to evaluate the RTMR hash
> > > > and TD event log data for the configuration in attestation flow,
> > > > because the configuration is independent with the code execution flow.
> > >
> > > Well, it covers only the memory map, correct?  All other configuration
> > > is still loaded from fw_cfg.  I can't see the improvement here.
> >
> > [Jiewen] At this point of time, memory map is the most important
> > parameter in the TD Hob, because we do need the memory information at
> > the TD entrypoint. That is mandatory for any TD boot.
> 
> Well, I can see that the memory map is kind of special here because you
> need that quite early in the firmware initialization workflow.

[Jiewen] That is correct.


> 
> > The fw_cfg is still allowed in the TDVF design guide, just because we
> > feel it is a burden to convert everything suddenly.
> 
> What is the longer-term plan here?
> 
> Does it make sense to special-case the memory map?
> 
> If we want handle other fw_cfg items that way too later on, shouldn't we
> better check how we can improve the fw_cfg interface so it works better
> with confidential computing?

[Jiewen] So far, my hope is to limit the fw_cfg as much as possible.
My worry is that we have to measure fw_cfg everywhere. If we miss one place, it will be a completeness vulnerability for trusted computing.

I also think if we can add measurement code inside of fw_cfg get function.
Then we need improve the FwCfg API - Current style: QemuFwCfgSelectItem() + QemuFwCfgReadxxx() is not friendly for measurement. For example, we can combine them and do QemuFwCfgSelectRead ().

The QemuFwCfgWritexxx() interface may also bring inconsistency issue. If we use this API, we have 2 copy data. One is in TDVF (trusted), and the other is in VMM/QEMU (untrusted). What if the VMM modifies its untrusted copy?


What I can see is many potential attack surfaces. :-(


> 
> > > How do you pass the HOB to the guest?  Copy data to guest ram?  Map a
> > > ro page into guest address space?  What happens on VM reset?
> 
> > [Jiewen] Yes, VMM will prepare the memory information based upon TDVF
> > metadata.  The VMM need copy TD HOB data to a predefined memory region
> > according to TDVF metadata.
> 
> Is all that documented somewhere?  The TVDF design overview focuses on
> the guest/firmware side of things, so it isn't very helpful here.

[Jiewen] The TDX architecture define this architecture way, the RCX/R9 refer is the pointer.

We have a couple of TDX document at https://software.intel.com/content/www/us/en/develop/articles/intel-trust-domain-extensions.html

https://software.intel.com/content/dam/develop/external/us/en/documents/tdx-module-1eas-v0.85.039.pdf
Section 8.1 defines the VCPU init state. The RCX/R8 hold the launch parameter.

https://software.intel.com/content/dam/develop/external/us/en/documents/tdx-virtual-firmware-design-guide-rev-1.pdf
Section 4.1.2 describes the TD HOB usage for RCX/R8. Section 7 adds more detail on memory map reporting.

Please let me know if you need any other information.


> 
> Did I mention posting the qemu patches would be a good idea?
> 
> > I don't fully understand the VM reset question. I try to answer. But if that is not
> what you are asking, please clarify.
> 
> What happens if you reboot the guest?
> 
> On non-TDX guests the VM will be reset, the cpu will jump to the reset
> vector (executing from rom / flash), firmware will re-initialize
> everything and re-load any config information it needs from fw_cfg
> 
> > This action that VMM initiates TD HOB happens when the VMM launches a TD
> guest.
> > After that the region will becomes TD private memory and own by TD. VMM
> can no longer access it (no read/no write).
> > If VM reset, then this memory is gone.
> > If VMM need launch a new TD, the VMM need initiate the data again.
> 
> Sounds like reset is not supported, you need to stop and re-start the
> guest instead.  Is that correct?

[Jiewen] That is correct. In our definition, reset == stop + restart.


> 
> take care,
>   Gerd


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

* Re: [edk2-devel] [PATCH 18/23] OvmfPkg: Enable Tdx in SecMain.c
  2021-08-25 16:28                     ` Yao, Jiewen
@ 2021-08-26  8:31                       ` Gerd Hoffmann
  2021-08-26 16:58                         ` Yao, Jiewen
  0 siblings, 1 reply; 64+ messages in thread
From: Gerd Hoffmann @ 2021-08-26  8:31 UTC (permalink / raw)
  To: Yao, Jiewen
  Cc: devel@edk2.groups.io, Ard Biesheuvel, Xu, Min M, Ard Biesheuvel,
	Justen, Jordan L, Brijesh Singh, Erdem Aktas, James Bottomley,
	Tom Lendacky, Yamahata, Isaku

  Hi,

> Some reference for QEMU:
> https://lists.nongnu.org/archive/html/qemu-devel/2021-07/msg01682.html

Ah, good.  /me adds an entry to the todo list.

> > > The fw_cfg is still allowed in the TDVF design guide, just because we
> > > feel it is a burden to convert everything suddenly.
> > 
> > What is the longer-term plan here?
> > 
> > Does it make sense to special-case the memory map?
> > 
> > If we want handle other fw_cfg items that way too later on, shouldn't we
> > better check how we can improve the fw_cfg interface so it works better
> > with confidential computing?
> 
> [Jiewen] So far, my hope is to limit the fw_cfg as much as possible.
> My worry is that we have to measure fw_cfg everywhere. If we miss one place, it will be a completeness vulnerability for trusted computing.
> 
> I also think if we can add measurement code inside of fw_cfg get function.
> Then we need improve the FwCfg API - Current style: QemuFwCfgSelectItem() + QemuFwCfgReadxxx() is not friendly for measurement. For example, we can combine them and do QemuFwCfgSelectRead ().

I was more thinking about a completely different way to pass (constant)
fw_cfg data.  Something like defining a fw_cfg hob and adding that to the
td hob.  QemuFwCfgLib could lookup the hob and use that when it finds
the needed entry there.

In case the entry is not there try use io instead.  We'll continue to
need that for the acpi tables for example, these entries are not
constant.  qemu will adapt them when the firmware maps hardware
resources referenced in acpi tables (mmconfig region, power management
registers, ...).

> The QemuFwCfgWritexxx() interface may also bring inconsistency issue.
> If we use this API, we have 2 copy data.

Do you need any writable fw_cfg entries in TDX mode?

'git grep' shows the ramfb driver, smi feature negotiation and s3
support use QemuFwCfgWrite()

> One is in TDVF (trusted), and
> the other is in VMM/QEMU (untrusted). What if the VMM modifies its
> untrusted copy?

> What I can see is many potential attack surfaces. :-(

Well, you have to trust VMM/QEMU to a certain degree.  TDX can prevent
data leaking, but it can't prevent VMM misbehaving.

> Please let me know if you need any other information.

Sure.  For now I have to read more docs and patches ...

take care,
  Gerd


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

* Re: [edk2-devel] [PATCH 18/23] OvmfPkg: Enable Tdx in SecMain.c
  2021-08-26  8:31                       ` Gerd Hoffmann
@ 2021-08-26 16:58                         ` Yao, Jiewen
  0 siblings, 0 replies; 64+ messages in thread
From: Yao, Jiewen @ 2021-08-26 16:58 UTC (permalink / raw)
  To: devel@edk2.groups.io, kraxel@redhat.com
  Cc: Ard Biesheuvel, Xu, Min M, Ard Biesheuvel, Justen, Jordan L,
	Brijesh Singh, Erdem Aktas, James Bottomley, Tom Lendacky,
	Yamahata, Isaku

Comment below:

> -----Original Message-----
> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Gerd
> Hoffmann
> Sent: Thursday, August 26, 2021 4:32 PM
> To: Yao, Jiewen <jiewen.yao@intel.com>
> Cc: devel@edk2.groups.io; Ard Biesheuvel <ardb@kernel.org>; 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>;
> Yamahata, Isaku <isaku.yamahata@intel.com>
> Subject: Re: [edk2-devel] [PATCH 18/23] OvmfPkg: Enable Tdx in SecMain.c
> 
>   Hi,
> 
> > Some reference for QEMU:
> > https://lists.nongnu.org/archive/html/qemu-devel/2021-07/msg01682.html
> 
> Ah, good.  /me adds an entry to the todo list.
> 
> > > > The fw_cfg is still allowed in the TDVF design guide, just because we
> > > > feel it is a burden to convert everything suddenly.
> > >
> > > What is the longer-term plan here?
> > >
> > > Does it make sense to special-case the memory map?
> > >
> > > If we want handle other fw_cfg items that way too later on, shouldn't we
> > > better check how we can improve the fw_cfg interface so it works better
> > > with confidential computing?
> >
> > [Jiewen] So far, my hope is to limit the fw_cfg as much as possible.
> > My worry is that we have to measure fw_cfg everywhere. If we miss one place,
> it will be a completeness vulnerability for trusted computing.
> >
> > I also think if we can add measurement code inside of fw_cfg get function.
> > Then we need improve the FwCfg API - Current style: QemuFwCfgSelectItem()
> + QemuFwCfgReadxxx() is not friendly for measurement. For example, we can
> combine them and do QemuFwCfgSelectRead ().
> 
> I was more thinking about a completely different way to pass (constant)
> fw_cfg data.  Something like defining a fw_cfg hob and adding that to the
> td hob.  QemuFwCfgLib could lookup the hob and use that when it finds
> the needed entry there.
> 
> In case the entry is not there try use io instead.  We'll continue to
> need that for the acpi tables for example, these entries are not
> constant.  qemu will adapt them when the firmware maps hardware
> resources referenced in acpi tables (mmconfig region, power management
> registers, ...).

[Jiewen] That is great idea. I really like it.


> 
> > The QemuFwCfgWritexxx() interface may also bring inconsistency issue.
> > If we use this API, we have 2 copy data.
> 
> Do you need any writable fw_cfg entries in TDX mode?

[Jiewen] I hope NOT to support writable fw_cfg.
In our TDX design, we even don't want to support SetVariable to NV Storage, just to reduce the risk.


> 
> 'git grep' shows the ramfb driver, smi feature negotiation and s3
> support use QemuFwCfgWrite()

[Jiewen] TDVF does not support SMM, and TDVF does not support S3. 

> 
> > One is in TDVF (trusted), and
> > the other is in VMM/QEMU (untrusted). What if the VMM modifies its
> > untrusted copy?
> 
> > What I can see is many potential attack surfaces. :-(
> 
> Well, you have to trust VMM/QEMU to a certain degree.  TDX can prevent
> data leaking, but it can't prevent VMM misbehaving.

[Jiewen] Yes, you are right. It is "in certain degree".

The threat model is :
TD cannot resist the deny-of-service (DOS) attack from VMM/QEMU.
TD need maintain the integrity and confidentiality, to avoid tamper and information disclosure.


If VMM misbehaving causes the system hang or guest device error, it is OK.
But if VMM misbehaving causes a TD secret leak to QEMU or TD tampered without being detected by measurement register (MRTD or RTMR), that is NOT acceptable.

If we allow the misbehaving, then we have to do thorough analysis to understand the impact.
If we can think of a way to avoid the possibility of misbehaving, then we know we are good. :-) That is our preference so far.


> 
> > Please let me know if you need any other information.
> 
> Sure.  For now I have to read more docs and patches ...
> 
> take care,
>   Gerd
> 
> 
> 
> 
> 


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

* Re: [edk2-devel] [PATCH 00/23] Enable Intel TDX in OvmfPkg (SEC/PEI)
  2021-08-12 11:56 [PATCH 00/23] Enable Intel TDX in OvmfPkg (SEC/PEI) Min Xu
                   ` (22 preceding siblings ...)
  2021-08-12 11:57 ` [PATCH 23/23] OvmfPkg: Update PlatformPei to support TDX Min Xu
@ 2021-08-31 10:45 ` Gerd Hoffmann
  2021-09-01  5:41   ` Min Xu
  23 siblings, 1 reply; 64+ messages in thread
From: Gerd Hoffmann @ 2021-08-31 10:45 UTC (permalink / raw)
  To: devel, min.m.xu
  Cc: 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

  Hi,

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

So, coming back to this after reading through a bunch of docs and
patches with some high-level questions.  The whitepaper lists two
ovmf configs:

  (1) config-a, supporting normal/sev/tdx with basic features.
  (2) config-b, supporting normal/tdx with more features.

What of this is implemented by this patch series?
config-a?  completely?  parts of it?

The whitepaper also doesn't explain very well why we have two
configurations in the first place.  It describes *what* are the
differences but not *why* they are there.

Apparently some of the additional features supported by config-b
are either more difficult or impossible to implement in config-a.
Is that correct?  Is that explained in more detail somewhere?

thanks,
  Gerd


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

* Re: [edk2-devel] [PATCH 00/23] Enable Intel TDX in OvmfPkg (SEC/PEI)
  2021-08-31 10:45 ` [edk2-devel] [PATCH 00/23] Enable Intel TDX in OvmfPkg (SEC/PEI) Gerd Hoffmann
@ 2021-09-01  5:41   ` Min Xu
  2021-09-01  6:25     ` Gerd Hoffmann
  0 siblings, 1 reply; 64+ messages in thread
From: Min Xu @ 2021-09-01  5:41 UTC (permalink / raw)
  To: Gerd Hoffmann, devel@edk2.groups.io
  Cc: Brijesh Singh, Dong, Eric, Erdem Aktas, Wu, Hao A, Wang, Jian J,
	James Bottomley, Yao, Jiewen, Liming Gao, Kinney, Michael D,
	Ni, Ray, Kumar, Rahul1, Tom Lendacky, Liu, Zhiguang

On August 31, 2021 6:46 PM, Gerd Hoffmann wrote:
>   Hi,
> 
> > [TDX]: https://software.intel.com/content/dam/develop/external/us/en/
> > documents/tdx-whitepaper-final9-17.pdf
> 
> So, coming back to this after reading through a bunch of docs and patches with
> some high-level questions.  The whitepaper lists two ovmf configs:
> 
>   (1) config-a, supporting normal/sev/tdx with basic features.
>   (2) config-b, supporting normal/tdx with more features.
> 
> What of this is implemented by this patch series?
> config-a?  completely?  parts of it?
Because the total patch-sets for TDVF upstreaming is too big and there are 2 configurations.
So we split the upstreaming into below waves.
                 Config-A          Config-B               Phase
Wave-1        Y                       Y                    ResetVector
Wave-2        Y                       N                      SEC/PEI
Wave-3        Y                       N                        DXE
Wave-4        N                       Y                        SEC (PEI is skipped)
Wave-5        N                       Y                        DXE

So this patch-set is wave-2 and for Config-A (SEC/PEI).

> 
> The whitepaper also doesn't explain very well why we have two configurations
> in the first place.  It describes *what* are the differences but not *why* they are
> there.
The whitepaper describes the TDVF as a standalone image. It is *not* one image.
It can only run on TD guest.
Then came the *One Image* requirement. TDVF should be able to run on Legacy guest, 
Td guest, even SEV guest with ONE image. Things become very complicated. 
See discussion in  https://edk2.groups.io/g/devel/topic/83283616#76022
> 
> Apparently some of the additional features supported by config-b are either
> more difficult or impossible to implement in config-a.
> Is that correct?  Is that explained in more detail somewhere?
It's correct. Some additional features are not supported in Config-A. For example the TD
RTMR based measured boot. 
There are design slides, recorded meetings in below link
https://edk2.groups.io/g/devel/files/Designs/2021/0611
Any questions please let us know. We will try our best to answer/address your concerns. 

Thanks!
Min

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

* Re: [edk2-devel] [PATCH 00/23] Enable Intel TDX in OvmfPkg (SEC/PEI)
  2021-09-01  5:41   ` Min Xu
@ 2021-09-01  6:25     ` Gerd Hoffmann
  0 siblings, 0 replies; 64+ messages in thread
From: Gerd Hoffmann @ 2021-09-01  6:25 UTC (permalink / raw)
  To: Xu, Min M
  Cc: devel@edk2.groups.io, Brijesh Singh, Dong, Eric, Erdem Aktas,
	Wu, Hao A, Wang, Jian J, James Bottomley, Yao, Jiewen, Liming Gao,
	Kinney, Michael D, Ni, Ray, Kumar, Rahul1, Tom Lendacky,
	Liu, Zhiguang

  Hi,

> Because the total patch-sets for TDVF upstreaming is too big and there are 2 configurations.
> So we split the upstreaming into below waves.
>                  Config-A          Config-B               Phase
> Wave-1        Y                       Y                    ResetVector
> Wave-2        Y                       N                      SEC/PEI
> Wave-3        Y                       N                        DXE
> Wave-4        N                       Y                        SEC (PEI is skipped)
> Wave-5        N                       Y                        DXE
> 
> So this patch-set is wave-2 and for Config-A (SEC/PEI).

Thanks (please add that info to the cover letter in the future).

> > Apparently some of the additional features supported by config-b are either
> > more difficult or impossible to implement in config-a.
> > Is that correct?  Is that explained in more detail somewhere?
> It's correct. Some additional features are not supported in Config-A. For example the TD
> RTMR based measured boot. 

Why is TD RTMR based measured boot not supported in Config-A?

I'm trying to understand why we need Config-B.  Having two variants
with completely different initialization code paths (with/without PEI)
doesn't look like a good plan to me.  I'd rather support everything in
Config-A if possible.

take care,
  Gerd


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

* Re: [PATCH 02/23] OvmfPkg/Sec: Update the check logic in SevEsIsEnabled
  2021-08-12 11:56 ` [PATCH 02/23] OvmfPkg/Sec: Update the check logic in SevEsIsEnabled Min Xu
@ 2021-09-11  1:13   ` Erdem Aktas
  2021-09-13  3:04     ` Min Xu
  0 siblings, 1 reply; 64+ messages in thread
From: Erdem Aktas @ 2021-09-11  1:13 UTC (permalink / raw)
  To: Min Xu
  Cc: edk2-devel-groups-io, Ard Biesheuvel, Jordan Justen,
	Brijesh Singh, James Bottomley, Jiewen Yao, Tom Lendacky

On Thu, Aug 12, 2021 at 2:57 PM Min Xu <min.m.xu@intel.com> wrote:
>
> RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
>
> SevEsIsEnabled return TRUE if SevEsWorkArea->SevEsEnabled is non-zero.
s/return/returns

> It is correct when SevEsWorkArea is only used by SEV. After Intel TDX
> is enabled in Ovmf, the SevEsWorkArea is shared by TDX and SEV. (This
> is to avoid the waist of memory region in MEMFD). The value of
s/waist/waste

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

* Re: [PATCH 03/23] OvmfPkg/ResetVector: Enable Intel TDX in ResetVector of Ovmf
  2021-08-12 11:56 ` [PATCH 03/23] OvmfPkg/ResetVector: Enable Intel TDX in ResetVector of Ovmf Min Xu
@ 2021-09-11  1:14   ` Erdem Aktas
  2021-09-13  6:06     ` Min Xu
  0 siblings, 1 reply; 64+ messages in thread
From: Erdem Aktas @ 2021-09-11  1:14 UTC (permalink / raw)
  To: Min Xu
  Cc: edk2-devel-groups-io, Ard Biesheuvel, Jordan Justen,
	Brijesh Singh, James Bottomley, Jiewen Yao, Tom Lendacky

On Thu, Aug 12, 2021 at 2:57 PM Min Xu <min.m.xu@intel.com> wrote:
>
> +;
> +; Check if it is Intel Tdx
> +;
> +; Modified: EAX, EBX, ECX, EDX
> +;
> +; If it is Intel Tdx, EAX is zero
> +; If it is not Intel Tdx, EAX is non-zero
> +;
> +IsTdx:
IsTdx returns 0 when TDX is enabled in CPUID but IsTdxEnabled return 1
when TDX is enabled. Is this intentional?

here is how IsTdxEnabled defined.
; If TDX is enabled then EAX will be 1
; If TDX is disabled then EAX will be 0.
;
IsTdxEnabled:

> +TdxApWait:
> +    cmp     byte[TDX_WORK_AREA_PGTBL_READY], 0
> +    je      TdxApWait
Don't we need memory fence before  je      TdxApWait. I did not check
what the compiler generates for this loop.


-Erdem

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

* Re: [PATCH 05/23] MdePkg: Add TdxProbeLib to probe Intel Tdx
  2021-08-12 11:56 ` [PATCH 05/23] MdePkg: Add TdxProbeLib to probe Intel Tdx Min Xu
  2021-08-16  9:43   ` [edk2-devel] " Gerd Hoffmann
@ 2021-09-11  1:14   ` Erdem Aktas
  2021-09-13  6:11     ` [edk2-devel] " Min Xu
  1 sibling, 1 reply; 64+ messages in thread
From: Erdem Aktas @ 2021-09-11  1:14 UTC (permalink / raw)
  To: Min Xu
  Cc: edk2-devel-groups-io, Michael D Kinney, Liming Gao, Zhiguang Liu,
	Brijesh Singh, James Bottomley, Jiewen Yao, Tom Lendacky

On Thu, Aug 12, 2021 at 2:57 PM Min Xu <min.m.xu@intel.com> wrote:
> +
> +#include <Library/BaseLib.h>
> +#include "InternalTdxProbe.h"
> +
> +/**
> +  TDX only works in X64. So allways return -1 to indicate Non-Td.
s/allways/always

Also, -1 or 1? PROBE_NOT_TD_GUEST is defined as 1.

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

* Re: [PATCH 06/23] MdePkg: Add TdxLib to wrap Tdx operations
  2021-08-12 11:56 ` [PATCH 06/23] MdePkg: Add TdxLib to wrap Tdx operations Min Xu
@ 2021-09-11  1:15   ` Erdem Aktas
  0 siblings, 0 replies; 64+ messages in thread
From: Erdem Aktas @ 2021-09-11  1:15 UTC (permalink / raw)
  To: Min Xu
  Cc: edk2-devel-groups-io, Michael D Kinney, Liming Gao, Zhiguang Liu,
	Brijesh Singh, James Bottomley, Jiewen Yao, Tom Lendacky

On Thu, Aug 12, 2021 at 2:57 PM Min Xu <min.m.xu@intel.com> wrote:
>  - TdMaxVCpuNum    : Get the maximum number of virutal CPUs.
s/virutal/virtual

>  - TdVCpuNum       : Get the number of virtual CPUs. (In some case VMM may
>                      add more vCPU in runtime).
s/case/cases
How is this possible considering that once the TD is finalized, there
should not be any new vcpu added, right? Am I missing something here?


> +++ b/MdePkg/Library/TdxLib/X64/Tdcall.nasm
> @@ -0,0 +1,120 @@
> +;------------------------------------------------------------------------------
....
> +%macro tdcall_regs_preamble 2
is this even used in this file?


> +    ; Zero out unused (for standard TDVMCALL) registers to avoid leaking
> +    ; secrets to the VMM.
this is for TDCALL right, there is no leaking to the tdx module.


> +
> +    xor ebx, ebx
> +    xor esi, esi
> +    xor edi, edi
> +
> +    xor edx, edx
> +    xor ebp, ebp
zeroing only the lower 32bit values? why not the higher 32bit value if
leaking is the concern?


> +++ b/MdePkg/Library/TdxLib/X64/Tdvmcall.nasm

> +%define TDVMCALL_EXPOSE_REGS_MASK       0xffec
Should we expose only the minimum number of registers needed for the TDVMCALL?


>
> +%macro tdcall_regs_preamble 2
> +    mov rax, %1
> +
> +    mov ecx, %2
should not we make sure that the higher 32bit of RCX is 0? RCX [63:32]
are reserved and always need to be 0.

> +    ; R10 = 0 (standard TDVMCALL)
> +
> +    xor r10d, r10d
> +
> +    ; Zero out unused (for standard TDVMCALL) registers to avoid leaking
> +    ; secrets to the VMM.

Is not rcx the bitmap of the registers that will be exposed to VMM?
unused registers should be set 0 in the bitmap, why zeroing them?

> +
> +    xor ebx, ebx
> +    xor esi, esi
> +    xor edi, edi

> +    xor edx, edx
> +    xor ebp, ebp
if we are concerned about leaking some data, why xor only the lower 32bits?

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

* Re: [PATCH 07/23] MdePkg: Update BaseIoLibIntrinsicSev to support Tdx
  2021-08-12 11:56 ` [PATCH 07/23] MdePkg: Update BaseIoLibIntrinsicSev to support Tdx Min Xu
  2021-08-17  8:38   ` [edk2-devel] " Gerd Hoffmann
@ 2021-09-11  1:15   ` Erdem Aktas
  2021-09-28  8:33     ` [edk2-devel] " Min Xu
  1 sibling, 1 reply; 64+ messages in thread
From: Erdem Aktas @ 2021-09-11  1:15 UTC (permalink / raw)
  To: Min Xu
  Cc: edk2-devel-groups-io, Michael D Kinney, Liming Gao, Zhiguang Liu,
	Brijesh Singh, James Bottomley, Jiewen Yao, Tom Lendacky

On Thu, Aug 12, 2021 at 2:57 PM Min Xu <min.m.xu@intel.com> wrote:
 > +UINT8
> +EFIAPI
> +TdMmioRead8 (
> +  IN      UINTN                     Address
> +  )
> +{
> +  UINT64                             Value;
> +  UINT64                             Status;
> +
> +  Address |= TdSharedPageMask ();

Why is the SharedBit set? VMM does not care if the sharedbit is set.
Actually it should not even be aware of it.
> +  MemoryFence ();
> +  Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_1, TDVMCALL_ACCESS_READ, Address, 0, &Value);
> +  if (Status != 0) {
So for some reason, MMIO read fails, we are doing a memory read. Why
should an MMIO read fail? Could you elaborate which use case this
covers?

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

* Re: [PATCH 02/23] OvmfPkg/Sec: Update the check logic in SevEsIsEnabled
  2021-09-11  1:13   ` Erdem Aktas
@ 2021-09-13  3:04     ` Min Xu
  0 siblings, 0 replies; 64+ messages in thread
From: Min Xu @ 2021-09-13  3:04 UTC (permalink / raw)
  To: Erdem Aktas
  Cc: edk2-devel-groups-io, Ard Biesheuvel, Justen, Jordan L,
	Brijesh Singh, James Bottomley, Yao, Jiewen, Tom Lendacky

On September 11, 2021 9:14 AM, Erdem Aktas wrote:
> >
> > RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429
> >
> > SevEsIsEnabled return TRUE if SevEsWorkArea->SevEsEnabled is non-zero.
> s/return/returns
> 
> > It is correct when SevEsWorkArea is only used by SEV. After Intel TDX
> > is enabled in Ovmf, the SevEsWorkArea is shared by TDX and SEV. (This
> > is to avoid the waist of memory region in MEMFD). The value of
> s/waist/waste
Thanks for reminder. Will fixed in next version.

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

* Re: [PATCH 03/23] OvmfPkg/ResetVector: Enable Intel TDX in ResetVector of Ovmf
  2021-09-11  1:14   ` Erdem Aktas
@ 2021-09-13  6:06     ` Min Xu
  2021-09-14  2:16       ` Erdem Aktas
  0 siblings, 1 reply; 64+ messages in thread
From: Min Xu @ 2021-09-13  6:06 UTC (permalink / raw)
  To: Erdem Aktas
  Cc: edk2-devel-groups-io, Ard Biesheuvel, Justen, Jordan L,
	Brijesh Singh, James Bottomley, Yao, Jiewen, Tom Lendacky

On September 11, 2021 9:14 AM, Erdem Aktas wrote:
> 
> On Thu, Aug 12, 2021 at 2:57 PM Min Xu <min.m.xu@intel.com> wrote:
> >
> > +;
> > +; Check if it is Intel Tdx
> > +;
> > +; Modified: EAX, EBX, ECX, EDX
> > +;
> > +; If it is Intel Tdx, EAX is zero
> > +; If it is not Intel Tdx, EAX is non-zero ;
> > +IsTdx:
> IsTdx returns 0 when TDX is enabled in CPUID but IsTdxEnabled return 1
> when TDX is enabled. Is this intentional?
I will make the return result of IsTdx and IsTdxEnabled consistent.
If it is Intel TDX, EAX is 1, otherwise it is 0.
> 
> here is how IsTdxEnabled defined.
> ; If TDX is enabled then EAX will be 1
> ; If TDX is disabled then EAX will be 0.
> ;
> IsTdxEnabled:
> 
> > +TdxApWait:
> > +    cmp     byte[TDX_WORK_AREA_PGTBL_READY], 0
> > +    je      TdxApWait
> Don't we need memory fence before  je      TdxApWait. I did not check
> what the compiler generates for this loop.
Below is the code compiler generated for this loop. (VS2017/release)
   106                                                          <1> TdxApWait:
   107 0000070B 803D04B0800000      <1>     cmp     byte[TDX_WORK_AREA_PGTBL_READY], 0
   108 00000712 74F7                             <1>     je          TdxApWait
   109 00000714 EB17                             <1>     jmp      ExitInitTdxWorkarea

This is the code lfence is added.
   106                                                          <1> TdxApWait:
   107 0000070B 803D04B0800000      <1>     cmp     byte[TDX_WORK_AREA_PGTBL_READY], 0
   108 00000712 0FAEE8                         <1>     lfence
   109 00000715 74F4                              <1>     je         TdxApWait
   110 00000717 EB17                              <1>     jmp     ExitInitTdxWorkarea

I am not sure if lfence is needed.
> 

Thanks!
Min

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

* Re: [edk2-devel] [PATCH 05/23] MdePkg: Add TdxProbeLib to probe Intel Tdx
  2021-09-11  1:14   ` Erdem Aktas
@ 2021-09-13  6:11     ` Min Xu
  0 siblings, 0 replies; 64+ messages in thread
From: Min Xu @ 2021-09-13  6:11 UTC (permalink / raw)
  To: devel@edk2.groups.io, erdemaktas@google.com
  Cc: Kinney, Michael D, Liming Gao, Liu, Zhiguang, Brijesh Singh,
	James Bottomley, Yao, Jiewen, Tom Lendacky

On September 11, 2021 9:15 AM, Erden Aktas wrote:
> On Thu, Aug 12, 2021 at 2:57 PM Min Xu <min.m.xu@intel.com> wrote:
> > +
> > +#include <Library/BaseLib.h>
> > +#include "InternalTdxProbe.h"
> > +
> > +/**
> > +  TDX only works in X64. So allways return -1 to indicate Non-Td.
> s/allways/always
> 
> Also, -1 or 1? PROBE_NOT_TD_GUEST is defined as 1.
> 
TdxProbeLib will be removed in next version.
According to the discussion a new PCD (ConfidentialComputingCategory)
will be added to record the type of VM Guest, such as Legacy guest, SEV guest,
TDX guest, etc.
Thus this PCD will be checked when the SEV or TDX to be determined.

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

* Re: [PATCH 03/23] OvmfPkg/ResetVector: Enable Intel TDX in ResetVector of Ovmf
  2021-09-13  6:06     ` Min Xu
@ 2021-09-14  2:16       ` Erdem Aktas
  0 siblings, 0 replies; 64+ messages in thread
From: Erdem Aktas @ 2021-09-14  2:16 UTC (permalink / raw)
  To: Xu, Min M
  Cc: edk2-devel-groups-io, Ard Biesheuvel, Justen, Jordan L,
	Brijesh Singh, James Bottomley, Yao, Jiewen, Tom Lendacky

On Mon, Sep 13, 2021 at 9:06 AM Xu, Min M <min.m.xu@intel.com> wrote:
>
> > > +TdxApWait:
> > > +    cmp     byte[TDX_WORK_AREA_PGTBL_READY], 0
> > > +    je      TdxApWait
> > Don't we need memory fence before  je      TdxApWait. I did not check
> > what the compiler generates for this loop.
> Below is the code compiler generated for this loop. (VS2017/release)
>    106                                                          <1> TdxApWait:
>    107 0000070B 803D04B0800000      <1>     cmp     byte[TDX_WORK_AREA_PGTBL_READY], 0
>    108 00000712 74F7                             <1>     je          TdxApWait
>    109 00000714 EB17                             <1>     jmp      ExitInitTdxWorkarea
>
> This is the code lfence is added.
>    106                                                          <1> TdxApWait:
>    107 0000070B 803D04B0800000      <1>     cmp     byte[TDX_WORK_AREA_PGTBL_READY], 0
>    108 00000712 0FAEE8                         <1>     lfence
>    109 00000715 74F4                              <1>     je         TdxApWait
>    110 00000717 EB17                              <1>     jmp     ExitInitTdxWorkarea
>
> I am not sure if lfence is needed.

Thanks Min! You are right, I also checked it with GCC5 and saw the same output.
Thanks for checking it.

-Erdem

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

* Re: [edk2-devel] [PATCH 07/23] MdePkg: Update BaseIoLibIntrinsicSev to support Tdx
  2021-09-11  1:15   ` Erdem Aktas
@ 2021-09-28  8:33     ` Min Xu
  0 siblings, 0 replies; 64+ messages in thread
From: Min Xu @ 2021-09-28  8:33 UTC (permalink / raw)
  To: devel@edk2.groups.io, erdemaktas@google.com
  Cc: Kinney, Michael D, Liming Gao, Liu, Zhiguang, Brijesh Singh,
	James Bottomley, Yao, Jiewen, Tom Lendacky

On September 11, 2021 9:16 AM, Erdem Aktas wrote:
> 
> On Thu, Aug 12, 2021 at 2:57 PM Min Xu <min.m.xu@intel.com> wrote:
>  > +UINT8
> > +EFIAPI
> > +TdMmioRead8 (
> > +  IN      UINTN                     Address
> > +  )
> > +{
> > +  UINT64                             Value;
> > +  UINT64                             Status;
> > +
> > +  Address |= TdSharedPageMask ();
> 
> Why is the SharedBit set? VMM does not care if the sharedbit is set.
> Actually it should not even be aware of it.
>
That is because GPA for MMIO region that VMM emulates must be shared region.  i.e. shared bit must be set.
See Section 12.3 in below link.
https://software.intel.com/content/dam/develop/external/us/en/documents/tdx-module-1.0-public-spec-v0.931.pdf
>
> > +  MemoryFence ();
> > +  Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_1,
> > + TDVMCALL_ACCESS_READ, Address, 0, &Value);  if (Status != 0) {
> So for some reason, MMIO read fails, we are doing a memory read. Why
> should an MMIO read fail? Could you elaborate which use case this covers?
If invalid operands provided by TD, e.g., MMIO address, TDG.VP.VMCALL_INVALID_OPERAND is returned.
See Section 3.7 Table 3-21 in below link:
https://software.intel.com/content/dam/develop/external/us/en/documents/intel-tdx-guest-hypervisor-communication-interface-1.0-344426-002.pdf
> 
Thanks!
Min

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

end of thread, other threads:[~2021-09-28  8:33 UTC | newest]

Thread overview: 64+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2021-08-12 11:56 [PATCH 00/23] Enable Intel TDX in OvmfPkg (SEC/PEI) Min Xu
2021-08-12 11:56 ` [PATCH 01/23] OvmfPkg: Add Tdx BFV/CFV PCDs and PcdOvmfImageSizeInKb Min Xu
2021-08-12 11:56 ` [PATCH 02/23] OvmfPkg/Sec: Update the check logic in SevEsIsEnabled Min Xu
2021-09-11  1:13   ` Erdem Aktas
2021-09-13  3:04     ` Min Xu
2021-08-12 11:56 ` [PATCH 03/23] OvmfPkg/ResetVector: Enable Intel TDX in ResetVector of Ovmf Min Xu
2021-09-11  1:14   ` Erdem Aktas
2021-09-13  6:06     ` Min Xu
2021-09-14  2:16       ` Erdem Aktas
2021-08-12 11:56 ` [PATCH 04/23] MdePkg: Add Tdx.h Min Xu
2021-08-12 20:52   ` Michael D Kinney
2021-08-12 22:57     ` Min Xu
2021-08-12 11:56 ` [PATCH 05/23] MdePkg: Add TdxProbeLib to probe Intel Tdx Min Xu
2021-08-16  9:43   ` [edk2-devel] " Gerd Hoffmann
2021-08-17  0:14     ` Min Xu
2021-08-17  8:20       ` Gerd Hoffmann
2021-08-17  8:43         ` Min Xu
2021-08-17  8:58           ` Gerd Hoffmann
2021-09-11  1:14   ` Erdem Aktas
2021-09-13  6:11     ` [edk2-devel] " Min Xu
2021-08-12 11:56 ` [PATCH 06/23] MdePkg: Add TdxLib to wrap Tdx operations Min Xu
2021-09-11  1:15   ` Erdem Aktas
2021-08-12 11:56 ` [PATCH 07/23] MdePkg: Update BaseIoLibIntrinsicSev to support Tdx Min Xu
2021-08-17  8:38   ` [edk2-devel] " Gerd Hoffmann
2021-08-18  5:54     ` Min Xu
2021-08-19  6:30       ` Gerd Hoffmann
2021-08-19 13:12         ` Min Xu
2021-08-20  6:41           ` Gerd Hoffmann
2021-09-11  1:15   ` Erdem Aktas
2021-09-28  8:33     ` [edk2-devel] " Min Xu
2021-08-12 11:56 ` [PATCH 08/23] UefiCpuPkg: Support TDX in BaseXApicX2ApicLib Min Xu
2021-08-12 11:56 ` [PATCH 09/23] UefiCpuPkg: Add VmTdExitLibNull Min Xu
2021-08-12 11:56 ` [PATCH 10/23] OvmfPkg: Prepare OvmfPkg to use the VmTdExitLib library Min Xu
2021-08-12 11:56 ` [PATCH 11/23] OvmfPkg: Implement library support for VmTdExitLib in Ovmf Min Xu
2021-08-12 11:56 ` [PATCH 12/23] UefiCpuPkg/CpuExceptionHandler: Add base support for the #VE exception Min Xu
2021-08-12 11:56 ` [PATCH 13/23] UefiCpuPkg: Enable Tdx support in MpInitLib Min Xu
2021-08-12 11:56 ` [PATCH 14/23] OvmfPkg: Update SecEntry.nasm to support Tdx Min Xu
2021-08-12 11:56 ` [PATCH 15/23] OvmfPkg: Add IntelTdx.h in OvmfPkg/Include/IndustryStandard Min Xu
2021-08-12 11:56 ` [PATCH 16/23] OvmfPkg: Add TdxMailboxLib Min Xu
2021-08-12 11:56 ` [PATCH 17/23] MdePkg: Add EFI_RESOURCE_ATTRIBUTE_ENCRYPTED in PiHob.h Min Xu
2021-08-12 11:56 ` [PATCH 18/23] OvmfPkg: Enable Tdx in SecMain.c Min Xu
2021-08-19  6:49   ` [edk2-devel] " Gerd Hoffmann
2021-08-19 14:27     ` Min Xu
2021-08-20  7:22       ` Gerd Hoffmann
2021-08-24 12:07         ` Min Xu
2021-08-24 12:55           ` Ard Biesheuvel
2021-08-25  6:10             ` Yao, Jiewen
2021-08-25  7:52               ` Gerd Hoffmann
2021-08-25  9:07                 ` Yao, Jiewen
2021-08-25 14:51                   ` Gerd Hoffmann
2021-08-25 16:28                     ` Yao, Jiewen
2021-08-26  8:31                       ` Gerd Hoffmann
2021-08-26 16:58                         ` Yao, Jiewen
2021-08-25  6:22           ` Gerd Hoffmann
2021-08-12 11:56 ` [PATCH 19/23] OvmfPkg: Check Tdx in QemuFwCfgPei to avoid DMA operation Min Xu
2021-08-12 11:56 ` [PATCH 20/23] MdePkg: Add AllocatePagesWithMemoryType support in PeiMemoryAllocationLib Min Xu
2021-08-12 20:43   ` Michael D Kinney
2021-08-15  2:51     ` Min Xu
2021-08-12 11:57 ` [PATCH 21/23] OvmfPkg: Add PcdUse1GPageTable support for TDX Min Xu
2021-08-12 11:57 ` [PATCH 22/23] MdeModulePkg: EFER should not be changed in TDX Min Xu
2021-08-12 11:57 ` [PATCH 23/23] OvmfPkg: Update PlatformPei to support TDX Min Xu
2021-08-31 10:45 ` [edk2-devel] [PATCH 00/23] Enable Intel TDX in OvmfPkg (SEC/PEI) Gerd Hoffmann
2021-09-01  5:41   ` Min Xu
2021-09-01  6:25     ` Gerd Hoffmann

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