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>, Jian J Wang <jian.j.wang@intel.com>,
	Hao A Wu <hao.a.wu@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 V3 22/29] MdeModulePkg: Set shared bit in Mmio region for Tdx guest
Date: Mon,  1 Nov 2021 21:16:11 +0800	[thread overview]
Message-ID: <e0d04467201923e90703757486f10b872e6444e4.1635769996.git.min.m.xu@intel.com> (raw)
In-Reply-To: <cover.1635769996.git.min.m.xu@intel.com>

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

Qemu allows a ROM device to set to ROMD mode (default) or MMIO mode.
When it is in ROMD mode, the device is mapped to guest memory and
satisfies read access directly.

In EDK2 Option ROM is treated as MMIO region. So Tdx guest access
Option ROM via TDVMCALL(MMIO). But as explained above, since Qemu set
the Option ROM to ROMD mode, the call of TDVMCALL(MMIO) always return
INVALID_OPERAND. Tdvf then falls back to direct access. This requires
to set the shared bit to corresponding PageTable entry. Otherwise it
triggers GP fault.

The mmio region information is passed from VMM in TD Hob. So after the
1:1 identity mapping page table is created (before it is wrote to CR3),
this page table will be updated (set shared bit) based on the mmio region
information in the hob list.

PcdTdxSharedBitMask is created in MdeModulePkg.dec to indicate the shared
bit information. Its default value is 0 and it will be set in PlatformPei
driver if it is of Tdx guest.

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Hao A Wu <hao.a.wu@intel.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
 MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf       |   2 +
 .../Core/DxeIplPeim/Ia32/DxeLoadFunc.c        |   2 +-
 .../Core/DxeIplPeim/X64/DxeIplTdVmcall.nasm   | 146 ++++++++
 .../Core/DxeIplPeim/X64/VirtualMemory.c       | 325 +++++++++++++++++-
 .../Core/DxeIplPeim/X64/VirtualMemory.h       |  66 +++-
 MdeModulePkg/MdeModulePkg.dec                 |   6 +
 6 files changed, 539 insertions(+), 8 deletions(-)
 create mode 100644 MdeModulePkg/Core/DxeIplPeim/X64/DxeIplTdVmcall.nasm

diff --git a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf b/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
index 106b679b6bd0..b964277133c0 100644
--- a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
+++ b/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
@@ -43,6 +43,7 @@
   X64/VirtualMemory.h
   X64/VirtualMemory.c
   X64/DxeLoadFunc.c
+  X64/DxeIplTdVmcall.nasm
 
 [Sources.EBC]
   Ebc/DxeLoadFunc.c
@@ -118,6 +119,7 @@
   gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase                            ## CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize                            ## CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdIa32EferChangeAllowed               ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdTdxSharedBitMask                    ## CONSUMES
 
 [Pcd.IA32,Pcd.X64,Pcd.ARM,Pcd.AARCH64]
   gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack               ## SOMETIMES_CONSUMES
diff --git a/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c b/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
index 284b34818ca7..cd60f8139205 100644
--- a/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
+++ b/MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
@@ -123,7 +123,7 @@ Create4GPageTablesIa32Pae (
         //
         // Need to split this 2M page that covers stack range.
         //
-        Split2MPageTo4K (PhysicalAddress, (UINT64 *) PageDirectoryEntry, StackBase, StackSize, 0, 0);
+        Split2MPageTo4K (PhysicalAddress, (UINT64 *) PageDirectoryEntry, StackBase, StackSize, 0, 0, 0);
       } else {
         //
         // Fill in the Page Directory entries
diff --git a/MdeModulePkg/Core/DxeIplPeim/X64/DxeIplTdVmcall.nasm b/MdeModulePkg/Core/DxeIplPeim/X64/DxeIplTdVmcall.nasm
new file mode 100644
index 000000000000..c55de3b89f93
--- /dev/null
+++ b/MdeModulePkg/Core/DxeIplPeim/X64/DxeIplTdVmcall.nasm
@@ -0,0 +1,146 @@
+;------------------------------------------------------------------------------
+;*
+;* Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
+;* SPDX-License-Identifier: BSD-2-Clause-Patent
+;*
+;*
+;------------------------------------------------------------------------------
+
+DEFAULT REL
+SECTION .text
+
+%define TDVMCALL_EXPOSE_REGS_MASK       0xffec
+%define TDVMCALL                        0x0
+%define EXIT_REASON_CPUID               0xa
+
+%macro tdcall 0
+    db 0x66,0x0f,0x01,0xcc
+%endmacro
+
+%macro tdcall_push_regs 0
+    push rbp
+    mov  rbp, rsp
+    push r15
+    push r14
+    push r13
+    push r12
+    push rbx
+    push rsi
+    push rdi
+%endmacro
+
+%macro tdcall_pop_regs 0
+    pop rdi
+    pop rsi
+    pop rbx
+    pop r12
+    pop r13
+    pop r14
+    pop r15
+    pop rbp
+%endmacro
+
+%define number_of_regs_pushed 8
+%define number_of_parameters  4
+
+;
+; Keep these in sync for push_regs/pop_regs, code below
+; uses them to find 5th or greater parameters
+;
+%define first_variable_on_stack_offset \
+  ((number_of_regs_pushed * 8) + (number_of_parameters * 8) + 8)
+%define second_variable_on_stack_offset \
+  ((first_variable_on_stack_offset) + 8)
+
+%macro tdcall_regs_preamble 2
+    mov rax, %1
+
+    xor rcx, rcx
+    mov ecx, %2
+
+    ; R10 = 0 (standard TDVMCALL)
+
+    xor r10d, r10d
+
+    ; Zero out unused (for standard TDVMCALL) registers to avoid leaking
+    ; secrets to the VMM.
+
+    xor ebx, ebx
+    xor esi, esi
+    xor edi, edi
+
+    xor edx, edx
+    xor ebp, ebp
+    xor r8d, r8d
+    xor r9d, r9d
+%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
+;  DxeIplTdVmCall (
+;    UINT64  Leaf,  // Rcx
+;    UINT64  P1,  // Rdx
+;    UINT64  P2,  // R8
+;    UINT64  P3,  // R9
+;    UINT64  P4,  // rsp + 0x28
+;    UINT64  *Val // rsp + 0x30
+;    )
+global ASM_PFX(DxeIplTdVmCall)
+ASM_PFX(DxeIplTdVmCall):
+       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
diff --git a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
index 8a3b72509310..c7cb7f007b4f 100644
--- a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
+++ b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
@@ -26,6 +26,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
 #include "DxeIpl.h"
 #include "VirtualMemory.h"
 
+#define TDVMCALL_MAPGPA                 0x10001
+
 //
 // Global variable to keep track current available memory used as page table.
 //
@@ -340,6 +342,7 @@ AllocatePageTableMemory (
   @param[in]      StackSize             Stack size.
   @param[in]      GhcbBase              GHCB page area base address.
   @param[in]      GhcbSize              GHCB page area size.
+  @param[in]      SharedBitMask         Bit mask for Tdx shared memory.
 
 **/
 VOID
@@ -349,7 +352,8 @@ Split2MPageTo4K (
   IN EFI_PHYSICAL_ADDRESS               StackBase,
   IN UINTN                              StackSize,
   IN EFI_PHYSICAL_ADDRESS               GhcbBase,
-  IN UINTN                              GhcbSize
+  IN UINTN                              GhcbSize,
+  IN UINT64                             SharedBitMask
   )
 {
   EFI_PHYSICAL_ADDRESS                  PhysicalAddress4K;
@@ -361,6 +365,10 @@ Split2MPageTo4K (
   // Make sure AddressEncMask is contained to smallest supported address field
   //
   AddressEncMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) & PAGING_1G_ADDRESS_MASK_64;
+  if (SharedBitMask != 0) {
+    ASSERT (AddressEncMask == 0);
+    AddressEncMask = SharedBitMask;
+  }
 
   PageTableEntry = AllocatePageTableMemory (1);
   ASSERT (PageTableEntry != NULL);
@@ -418,6 +426,7 @@ Split2MPageTo4K (
   @param[in]      StackSize             Stack size.
   @param[in]      GhcbBase              GHCB page area base address.
   @param[in]      GhcbSize              GHCB page area size.
+  @param[in]      SharedBitMask         Bit mask for Tdx shared memory.
 
 **/
 VOID
@@ -427,7 +436,8 @@ Split1GPageTo2M (
   IN EFI_PHYSICAL_ADDRESS               StackBase,
   IN UINTN                              StackSize,
   IN EFI_PHYSICAL_ADDRESS               GhcbBase,
-  IN UINTN                              GhcbSize
+  IN UINTN                              GhcbSize,
+  IN UINT64                             SharedBitMask
   )
 {
   EFI_PHYSICAL_ADDRESS                  PhysicalAddress2M;
@@ -440,6 +450,11 @@ Split1GPageTo2M (
   //
   AddressEncMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) & PAGING_1G_ADDRESS_MASK_64;
 
+  if (SharedBitMask != 0) {
+    ASSERT (AddressEncMask == 0);
+    AddressEncMask = *PageEntry1G & SharedBitMask;
+  }
+
   PageDirectoryEntry = AllocatePageTableMemory (1);
   ASSERT (PageDirectoryEntry != NULL);
 
@@ -454,7 +469,7 @@ Split1GPageTo2M (
       //
       // Need to split this 2M page that covers NULL or stack range.
       //
-      Split2MPageTo4K (PhysicalAddress2M, (UINT64 *) PageDirectoryEntry, StackBase, StackSize, GhcbBase, GhcbSize);
+      Split2MPageTo4K (PhysicalAddress2M, (UINT64 *) PageDirectoryEntry, StackBase, StackSize, GhcbBase, GhcbSize, SharedBitMask == 0 ? 0 : AddressEncMask);
     } else {
       //
       // Fill in the Page Directory entries
@@ -647,6 +662,296 @@ EnablePageTableProtection (
   AsmWriteCr0 (AsmReadCr0() | CR0_WP);
 }
 
+#ifdef MDE_CPU_X64
+/**
+  Set the memory shared bit
+
+  @param[in,out]      PageTablePointer  Page table entry pointer (PTE).
+  @param[in]          PhysicalAddress   The physical address that is the start
+                                        address of a memory region
+  @param[in]          Length            Length of the memory region
+  @param[in]          SharedBitMask     Shared bit mask
+
+  @retval             Return status of DxeIplTdVmCall
+**/
+UINT64
+SetSharedBit(
+  IN   OUT     UINT64*                PageTablePointer,
+  IN           PHYSICAL_ADDRESS       PhysicalAddress,
+  IN           UINT64                 Length,
+  IN           UINT64                 SharedBitMask
+  )
+{
+  UINT64      Status;
+
+  *PageTablePointer |= SharedBitMask;
+  PhysicalAddress   |= SharedBitMask;
+
+  Status = DxeIplTdVmCall(TDVMCALL_MAPGPA, PhysicalAddress, Length, 0, 0, NULL);
+
+  return Status;
+}
+
+/**
+  This function sets the shared bit for the memory region specified by
+  PhysicalAddress and Length from the current page table  context.
+
+  The function iterates through the PhysicalAddress one page at a time, and set
+  or clears the memory encryption in the page table. If it encounters
+  that a given physical address range is part of large page then it attempts to
+  change the attribute at one go (based on size), otherwise it splits the
+  large pages into smaller (e.g 2M page into 4K pages) and then try to set or
+  clear the encryption bit on the smallest page size.
+
+  @param[in]  PageTableBaseAddress    Base Address of Page table
+  @param[in]  Page5LevelSupport       Indicates if Level-5 paging supported
+  @param[in]  SharedBitMask           Shared bit mask for the memory region
+  @param[in]  PhysicalAddress         The physical address that is the start
+                                      address of a memory region.
+  @param[in]  Pages                   Number of pages of memory region
+
+  @retval EFI_SUCCESS                 The shared bit is set successfully.
+  @retval EFI_INVALID_PARAMETER       Number of pages is zero.
+  @retval EFI_NO_MAPPING              Physical address is not mapped in PageTable
+**/
+EFI_STATUS
+SetMemorySharedBit (
+  IN    PHYSICAL_ADDRESS         PageTableBaseAddress,
+  IN    BOOLEAN                  Page5LevelSupport,
+  IN    UINT64                   SharedBitMask,
+  IN    PHYSICAL_ADDRESS         PhysicalAddress,
+  IN    UINTN                    Pages
+  )
+{
+  EFI_STATUS                     Status;
+  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                         ActiveSharedBitMask;
+  UINTN                          Length;
+
+  if (Pages == 0) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Status              = EFI_SUCCESS;
+  PageMapLevel4Entry  = NULL;
+  PgTableMask         = SharedBitMask | EFI_PAGE_MASK;
+  Length              = EFI_PAGES_TO_SIZE (Pages);
+
+  //
+  // If 5-level pages, adjust PageTableBaseAddress to point to first 4-level page directory,
+  // we will only have 1
+  //
+  if (Page5LevelSupport) {
+    PageTableBaseAddress = *(UINT64 *)PageTableBaseAddress & ~PgTableMask;
+  }
+
+  while (Length > 0) {
+    PageMapLevel4Entry  = (VOID*) (PageTableBaseAddress & ~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 = EFI_NO_MAPPING;
+      break;
+    }
+
+    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 = EFI_NO_MAPPING;
+      break;
+    }
+
+    //
+    // 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)) == 0 && Length >= BIT30) {
+        SetSharedBit (&PageDirectory1GEntry->Uint64, PhysicalAddress, BIT30, SharedBitMask);
+        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, 0, 0,
+          SharedBitMask
+          );
+        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 = EFI_NO_MAPPING;
+        break;
+      }
+      //
+      // 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)) == 0 && Length >= BIT21) {
+          SetSharedBit (&PageDirectory2MEntry->Uint64, PhysicalAddress, BIT21, SharedBitMask);
+          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
+            ));
+
+          ActiveSharedBitMask = PageDirectory2MEntry->Uint64 & SharedBitMask;
+
+          Split2MPageTo4K (
+            (UINT64)PageDirectory2MEntry->Bits.PageTableBaseAddress << 21,
+            (UINT64 *)PageDirectory2MEntry,
+            0, 0, 0, 0,
+            ActiveSharedBitMask
+            );
+          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 = EFI_NO_MAPPING;
+          break;
+        }
+        SetSharedBit (&PageTableEntry->Uint64, PhysicalAddress, EFI_PAGE_SIZE, SharedBitMask);
+        PhysicalAddress += EFI_PAGE_SIZE;
+        Length          -= EFI_PAGE_SIZE;
+      }
+    }
+  }
+
+  return Status;
+}
+
+/**
+  Set the shared bit for mmio region in Tdx guest.
+
+  In Tdx guest there are 2 ways to access mmio, TdVmcall or direct access.
+  For direct access, the shared bit of the PageTableEntry should be set.
+  The mmio region information is retrieved from hob list.
+
+  @param[in]  PageTableBaseAddress    Base Address of Page table.
+  @param[in]  Page5LevelSupport       Indicates if Level-5 paging is supported.
+
+  @retval EFI_SUCCESS                 The shared bit is set successfully.
+  @retval EFI_UNSUPPORTED             Setting the shared bit of memory region
+                                      is not supported
+**/
+EFI_STATUS
+DxeIplSetMmioSharedBit (
+  IN UINT64    PageTableBaseAddress,
+  IN BOOLEAN   Page5LevelSupport
+  )
+{
+  EFI_PEI_HOB_POINTERS      Hob;
+  UINT64                    SharedBitMask;
+
+  //
+  // Check if we have a valid memory shared bit mask
+  //
+  SharedBitMask = PcdGet64 (PcdTdxSharedBitMask) & PAGING_1G_ADDRESS_MASK_64;
+  if (SharedBitMask == 0) {
+    return EFI_UNSUPPORTED;
+  }
+
+
+  Hob.Raw = (UINT8 *) GetHobList ();
+
+  //
+  // Parse the HOB list until end of list or matching type is found.
+  //
+  while (!END_OF_HOB_LIST (Hob)) {
+    if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR
+        && Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_MEMORY_MAPPED_IO) {
+
+      SetMemorySharedBit (
+        PageTableBaseAddress,
+        Page5LevelSupport,
+        SharedBitMask,
+        Hob.ResourceDescriptor->PhysicalStart,
+        EFI_SIZE_TO_PAGES (Hob.ResourceDescriptor->ResourceLength));
+    }
+
+    Hob.Raw = GET_NEXT_HOB (Hob);
+  }
+
+  return EFI_SUCCESS;
+}
+
+#endif
+
 /**
   Allocates and fills in the Page Directory and Page Table Entries to
   establish a 1:1 Virtual to Physical mapping.
@@ -851,7 +1156,7 @@ CreateIdentityMappingPageTables (
 
         for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectory1GEntry++, PageAddress += SIZE_1GB) {
           if (ToSplitPageTable (PageAddress, SIZE_1GB, StackBase, StackSize, GhcbBase, GhcbSize)) {
-            Split1GPageTo2M (PageAddress, (UINT64 *) PageDirectory1GEntry, StackBase, StackSize, GhcbBase, GhcbSize);
+            Split1GPageTo2M (PageAddress, (UINT64 *) PageDirectory1GEntry, StackBase, StackSize, GhcbBase, GhcbSize, 0);
           } else {
             //
             // Fill in the Page Directory entries
@@ -885,7 +1190,7 @@ CreateIdentityMappingPageTables (
               //
               // Need to split this 2M page that covers NULL or stack range.
               //
-              Split2MPageTo4K (PageAddress, (UINT64 *) PageDirectoryEntry, StackBase, StackSize, GhcbBase, GhcbSize);
+              Split2MPageTo4K (PageAddress, (UINT64 *) PageDirectoryEntry, StackBase, StackSize, GhcbBase, GhcbSize, 0);
             } else {
               //
               // Fill in the Page Directory entries
@@ -921,6 +1226,15 @@ CreateIdentityMappingPageTables (
     ZeroMem (PageMapLevel5Entry, (512 - IndexOfPml5Entries) * sizeof (PAGE_MAP_AND_DIRECTORY_POINTER));
   }
 
+#ifdef MDE_CPU_X64
+  //
+  // Set shared bit for TDX
+  //
+  if (PcdGet64 (PcdTdxSharedBitMask) != 0) {
+    DxeIplSetMmioSharedBit ((UINTN)PageMap, Page5LevelSupport);
+  }
+#endif
+
   //
   // Protect the page table by marking the memory used for page table to be
   // read-only.
@@ -936,4 +1250,3 @@ CreateIdentityMappingPageTables (
 
   return (UINTN)PageMap;
 }
-
diff --git a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
index 6b7c38a441d6..6223bb69c403 100644
--- a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
+++ b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
@@ -19,6 +19,11 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
 
 #define SYS_CODE64_SEL 0x38
 
+#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)
 
 #pragma pack(1)
 
@@ -203,6 +208,7 @@ EnableExecuteDisableBit (
   @param[in]      StackSize             Stack size.
   @param[in]      GhcbBase              GHCB page area base address.
   @param[in]      GhcbSize              GHCB page area size.
+  @param[in]      SharedBitMask         Bit mask for Tdx shared memory.
 
 **/
 VOID
@@ -212,7 +218,8 @@ Split2MPageTo4K (
   IN EFI_PHYSICAL_ADDRESS               StackBase,
   IN UINTN                              StackSize,
   IN EFI_PHYSICAL_ADDRESS               GhcbBase,
-  IN UINTN                              GhcbSize
+  IN UINTN                              GhcbSize,
+  IN UINT64                             SharedBitMask
   );
 
 /**
@@ -327,4 +334,61 @@ AllocatePageTableMemory (
   IN UINTN           Pages
   );
 
+#ifdef MDE_CPU_X64
+/**
+  This function sets the shared bit for the memory region specified by
+  PhysicalAddress and Length from the current page table  context.
+
+  The function iterates through the PhysicalAddress one page at a time, and set
+  or clears the memory encryption in the page table. If it encounters
+  that a given physical address range is part of large page then it attempts to
+  change the attribute at one go (based on size), otherwise it splits the
+  large pages into smaller (e.g 2M page into 4K pages) and then try to set or
+  clear the encryption bit on the smallest page size.
+
+  @param[in]  PageTableBaseAddress    Base Address of Page table
+  @param[in]  Page5LevelSupport       Indicates if Level-5 paging supported
+  @param[in]  PhysicalAddress         The physical address that is the start
+                                      address of a memory region.
+  @param[in]  Pages                   Number of pages of memory region
+
+  @retval EFI_SUCCESS                 The shared bit is set successfully.
+  @retval EFI_INVALID_PARAMETER       Number of pages is zero.
+  @retval EFI_NO_MAPPING              Physical address is not mapped in PageTable
+**/
+EFI_STATUS
+SetMemorySharedBit (
+  IN    PHYSICAL_ADDRESS         PageTableBaseAddress,
+  IN    BOOLEAN                  Page5LevelSupport,
+  IN    UINT64                   SharedBitMask,
+  IN    PHYSICAL_ADDRESS         PhysicalAddress,
+  IN    UINTN                    Pages
+  );
+
+/**
+  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
+DxeIplTdVmCall (
+  IN UINT64          Leaf,
+  IN UINT64          Arg1,
+  IN UINT64          Arg2,
+  IN UINT64          Arg3,
+  IN UINT64          Arg4,
+  IN OUT VOID        *Results
+  );
+#endif
+
 #endif
diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec
index 007044a311c2..4d8f7f5cc55b 100644
--- a/MdeModulePkg/MdeModulePkg.dec
+++ b/MdeModulePkg/MdeModulePkg.dec
@@ -2143,6 +2143,12 @@
   # @Prompt The flag which indicates if IA32_EFER is allowed to be changed.
   gEfiMdeModulePkgTokenSpaceGuid.PcdIa32EferChangeAllowed|TRUE|BOOLEAN|0x00030009
 
+  ## This PCD holds the shared bit mask for page table entries when Tdx is enabled.
+  #  This mask should be applied to mmio region when creating 1:1 virtual to physical
+  #  mapping tables.
+  # @Prompt The shared bit mask when Intel Tdx is enabled.
+  gEfiMdeModulePkgTokenSpaceGuid.PcdTdxSharedBitMask|0x0|UINT64|0x0003000a
+
 [PcdsDynamicEx]
   ## This dynamic PCD enables the default variable setting.
   #  Its value is the default store ID value. The default value is zero as Standard default.
-- 
2.29.2.windows.2


  parent reply	other threads:[~2021-11-01 13:18 UTC|newest]

Thread overview: 107+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-11-01 13:15 [PATCH V3 00/29] Enable Intel TDX in OvmfPkg (Config-A) Min Xu
2021-11-01 13:15 ` [PATCH V3 01/29] MdePkg: Add Tdx.h Min Xu
2021-11-01 13:15 ` [PATCH V3 02/29] MdePkg: Add TdxLib to wrap Tdx operations Min Xu
2021-11-02 14:06   ` Gerd Hoffmann
2021-11-10  4:58     ` [edk2-devel] " Min Xu
2021-11-10 10:38   ` Erdem Aktas
2021-11-12  2:38     ` Min Xu
2021-11-12  2:42       ` Yao, Jiewen
2021-11-12  5:29         ` Min Xu
2021-11-12  5:33           ` Yao, Jiewen
2021-11-01 13:15 ` [PATCH V3 03/29] UefiCpuPkg: Extend VmgExitLibNull to handle #VE exception Min Xu
2021-11-02 14:11   ` Gerd Hoffmann
2021-11-01 13:15 ` [PATCH V3 04/29] OvmfPkg: Extend VmgExitLib " Min Xu
2021-11-02 14:23   ` Gerd Hoffmann
2021-11-10  6:46     ` Min Xu
2021-11-17  0:32   ` Erdem Aktas
2021-11-01 13:15 ` [PATCH V3 05/29] UefiCpuPkg/CpuExceptionHandler: Add base support for the " Min Xu
2021-11-02 14:24   ` Gerd Hoffmann
2021-11-01 13:15 ` [PATCH V3 06/29] MdePkg: Add helper functions for Tdx guest in BaseIoLibIntrinsic Min Xu
2021-11-01 13:15 ` [PATCH V3 07/29] MdePkg: Support mmio " Min Xu
2021-11-01 13:15 ` [PATCH V3 08/29] MdePkg: Support IoFifo " Min Xu
2021-11-01 13:15 ` [PATCH V3 09/29] MdePkg: Support IoRead/IoWrite " Min Xu
2021-11-01 13:15 ` [PATCH V3 10/29] UefiPayloadPkg: PreparePrepare UefiPayloadPkg to use TdxLib Min Xu
2021-11-01 15:31   ` Guo Dong
2021-11-01 15:58   ` Ma, Maurice
2021-11-02  0:07     ` Min Xu
2021-11-02 14:32   ` Gerd Hoffmann
2021-11-01 13:16 ` [PATCH V3 11/29] UefiCpuPkg: Support TDX in BaseXApicX2ApicLib Min Xu
2021-11-02 14:33   ` Gerd Hoffmann
2021-11-01 13:16 ` [PATCH V3 12/29] UefiCpuPkg: Define ConfidentialComputingGuestAttr Min Xu
2021-11-02 14:36   ` Gerd Hoffmann
2021-11-03  8:32     ` [edk2-devel] " Min Xu
2021-11-01 13:16 ` [PATCH V3 13/29] MdePkg: Add macro to check SEV/TDX guest Min Xu
2021-11-02 14:36   ` Gerd Hoffmann
2021-11-01 13:16 ` [PATCH V3 14/29] UefiCpuPkg: Enable Tdx support in MpInitLib Min Xu
2021-11-03  6:09   ` Gerd Hoffmann
2021-11-03 12:57     ` Min Xu
2021-11-04  8:10       ` Gerd Hoffmann
2021-11-04 15:21         ` Lendacky, Thomas
2021-11-04 23:24           ` Min Xu
2021-11-05  6:46             ` [edk2-devel] " Gerd Hoffmann
2021-11-05  6:53               ` Min Xu
2021-11-09  2:44               ` Min Xu
2021-11-01 13:16 ` [PATCH V3 15/29] OvmfPkg: Update SecEntry.nasm to support Tdx Min Xu
2021-11-03  6:30   ` Gerd Hoffmann
2021-11-16 12:11     ` Min Xu
2021-11-17 15:19       ` Gerd Hoffmann
2021-11-18  9:59         ` Yao, Jiewen
2021-11-19 15:11           ` Gerd Hoffmann
2021-11-20  3:18             ` Yao, Jiewen
2021-11-23 12:38               ` Gerd Hoffmann
2021-11-23 13:07                 ` Yao, Jiewen
2021-11-23 14:26                   ` James Bottomley
2021-11-23 14:36                     ` Yao, Jiewen
2021-11-23 14:51                       ` James Bottomley
2021-11-23 15:10                         ` Yao, Jiewen
2021-11-23 15:37                           ` [edk2-devel] " James Bottomley
2021-11-24  3:15                             ` Yao, Jiewen
2021-11-24  8:12                               ` Gerd Hoffmann
2021-11-24 11:08                                 ` Yao, Jiewen
2021-11-24 13:35                                   ` James Bottomley
2021-11-24 14:03                                     ` Yao, Jiewen
2021-11-24 14:07                                       ` James Bottomley
2021-11-24 14:59                                         ` Yao, Jiewen
2021-11-25  8:32                                           ` Gerd Hoffmann
2021-11-26  6:29                                             ` Yao, Jiewen
2021-12-01 13:55                                               ` Gerd Hoffmann
2021-12-02 13:22                                                 ` Yao, Jiewen
2021-12-06 14:57                                                   ` Gerd Hoffmann
2021-12-07  2:28                                                     ` Yao, Jiewen
2021-12-07  8:04                                                       ` Gerd Hoffmann
2021-12-08  5:13                                                         ` Min Xu
     [not found]                                         ` <16BA8381113E7B1B.22735@groups.io>
2021-11-24 15:30                                           ` Yao, Jiewen
     [not found]                             ` <16BA5D1709524394.9880@groups.io>
2021-11-24  3:21                               ` Yao, Jiewen
2021-11-01 13:16 ` [PATCH V3 16/29] OvmfPkg: Add IntelTdx.h in OvmfPkg/Include/IndustryStandard Min Xu
2021-11-01 13:16 ` [PATCH V3 17/29] OvmfPkg: Add TdxMailboxLib Min Xu
2021-11-01 13:16 ` [PATCH V3 18/29] MdePkg: Add EFI_RESOURCE_ATTRIBUTE_ENCRYPTED in PiHob.h Min Xu
2021-11-01 13:16 ` [PATCH V3 19/29] OvmfPkg: Enable Tdx in SecMain.c Min Xu
2021-11-01 13:16 ` [PATCH V3 20/29] OvmfPkg: Check Tdx in QemuFwCfgPei to avoid DMA operation Min Xu
2021-11-03  6:50   ` Gerd Hoffmann
2021-11-03 13:07     ` Min Xu
2021-11-03 13:35     ` Min Xu
2021-11-04 14:36       ` Brijesh Singh
2021-11-01 13:16 ` [PATCH V3 21/29] MdeModulePkg: EFER should not be changed in TDX Min Xu
2021-11-03  6:51   ` Gerd Hoffmann
2021-11-01 13:16 ` Min Xu [this message]
2021-11-03  6:57   ` [PATCH V3 22/29] MdeModulePkg: Set shared bit in Mmio region for Tdx guest Gerd Hoffmann
2021-11-04  7:03     ` [edk2-devel] " Min Xu
2021-11-01 13:16 ` [PATCH V3 23/29] UefiCpuPkg: Update AddressEncMask in CpuPageTable Min Xu
2021-11-03  7:00   ` Gerd Hoffmann
2021-11-22  3:09     ` [edk2-devel] " Ni, Ray
2021-12-07  3:50       ` Min Xu
2021-12-07  7:15         ` Gerd Hoffmann
2021-11-01 13:16 ` [PATCH V3 24/29] OvmfPkg: Update PlatformPei to support TDX Min Xu
2021-11-01 13:16 ` [PATCH V3 25/29] OvmfPkg: Update AcpiPlatformDxe to alter MADT table Min Xu
2021-11-01 13:16 ` [PATCH V3 26/29] OvmfPkg: Add TdxDxe driver Min Xu
2021-11-01 13:16 ` [PATCH V3 27/29] OvmfPkg/BaseMemEncryptTdxLib: Add TDX helper library Min Xu
2021-11-03  7:10   ` Gerd Hoffmann
2021-12-08  8:37     ` [edk2-devel] " Min Xu
2021-11-01 13:16 ` [PATCH V3 28/29] OvmfPkg/QemuFwCfgLib: Support Tdx in QemuFwCfgDxe Min Xu
2021-11-03  7:12   ` Gerd Hoffmann
2021-12-13  2:06     ` Min Xu
2021-11-01 13:16 ` [PATCH V3 29/29] OvmfPkg: Update IoMmuDxe to support TDX Min Xu
2021-11-03  7:17   ` Gerd Hoffmann
2021-12-13  2:39     ` [edk2-devel] " Min Xu
2021-12-13  6:42       ` Gerd Hoffmann
2021-12-13  7:33         ` 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=e0d04467201923e90703757486f10b872e6444e4.1635769996.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