public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Min Xu" <min.m.xu@intel.com>
To: devel@edk2.groups.io
Cc: Min Xu <min.m.xu@intel.com>,
	Ard Biesheuvel <ardb+tianocore@kernel.org>,
	Jordan Justen <jordan.l.justen@intel.com>,
	Brijesh Singh <brijesh.singh@amd.com>,
	Erdem Aktas <erdemaktas@google.com>,
	James Bottomley <jejb@linux.ibm.com>,
	Jiewen Yao <jiewen.yao@intel.com>,
	Tom Lendacky <thomas.lendacky@amd.com>,
	Gerd Hoffmann <kraxel@redhat.com>
Subject: [PATCH V5 27/33] OvmfPkg/BaseMemEncryptTdxLib: Add TDX helper library
Date: Sun, 23 Jan 2022 09:36:58 +0800	[thread overview]
Message-ID: <113d9d5ef138ae717d13a819471dff0304b12c2e.1642899774.git.min.m.xu@intel.com> (raw)
In-Reply-To: <cover.1642899774.git.min.m.xu@intel.com>

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

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

Please be noted, there a lot of duplicated codes for Page Table
operations. These codes should be moved to a common library
(PageTablesLib) so that it is more friendly for review and maintain.
There is a new feature requirement
https://bugzilla.tianocore.org/show_bug.cgi?id=847 which is to
implement the library. After the lib is introduced, BaseMemEncryptTdxLib
will be refactored.

Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 OvmfPkg/Include/Library/MemEncryptTdxLib.h    |  81 ++
 .../BaseMemEncryptTdxLib.inf                  |  44 +
 .../BaseMemEncryptTdxLibNull.inf              |  35 +
 .../BaseMemoryEncryptionNull.c                |  90 ++
 .../BaseMemEncryptTdxLib/MemoryEncryption.c   | 948 ++++++++++++++++++
 .../BaseMemEncryptTdxLib/VirtualMemory.h      | 181 ++++
 OvmfPkg/OvmfPkg.dec                           |   4 +
 OvmfPkg/OvmfPkgIa32.dsc                       |   1 +
 OvmfPkg/OvmfPkgIa32X64.dsc                    |   1 +
 9 files changed, 1385 insertions(+)
 create mode 100644 OvmfPkg/Include/Library/MemEncryptTdxLib.h
 create mode 100644 OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLib.inf
 create mode 100644 OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemEncryptTdxLibNull.inf
 create mode 100644 OvmfPkg/Library/BaseMemEncryptTdxLib/BaseMemoryEncryptionNull.c
 create mode 100644 OvmfPkg/Library/BaseMemEncryptTdxLib/MemoryEncryption.c
 create mode 100644 OvmfPkg/Library/BaseMemEncryptTdxLib/VirtualMemory.h

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


  parent reply	other threads:[~2022-01-23  1:39 UTC|newest]

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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=113d9d5ef138ae717d13a819471dff0304b12c2e.1642899774.git.min.m.xu@intel.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox