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
next prev 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