diff --git a/OvmfPkg/Include/Library/MemEncryptSevLib.h b/OvmfPkg/Include/Library/MemEncryptSevLib.h
index 872abe6725..ec470b8d03 100644
--- a/OvmfPkg/Include/Library/MemEncryptSevLib.h
+++ b/OvmfPkg/Include/Library/MemEncryptSevLib.h
@@ -33,6 +33,16 @@ typedef struct _SEC_SEV_ES_WORK_AREA {
UINT64 EncryptionMask;
} SEC_SEV_ES_WORK_AREA;
+//
+// Memory encryption address range states.
+//
+typedef enum {
+ MemEncryptSevAddressRangeUnencrypted,
+ MemEncryptSevAddressRangeEncrypted,
+ MemEncryptSevAddressRangeMixed,
+ MemEncryptSevAddressRangeError,
+} MEM_ENCRYPT_SEV_ADDRESS_RANGE_STATE;
+
/**
Returns a boolean to indicate whether SEV-ES is enabled.
@@ -147,4 +157,27 @@ MemEncryptSevGetEncryptionMask (
VOID
);
+/**
+ Returns the encryption state of the specified virtual address range.
+
+ @param[in] Cr3BaseAddress Cr3 Base Address (if zero then use
+ current CR3)
+ @param[in] BaseAddress Base address to check
+ @param[in] Length Length of virtual address range
+
+ @retval MemEncryptSevAddressRangeUnencrypted Address range is mapped
+ unencrypted
+ @retval MemEncryptSevAddressRangeEncrypted Address range is mapped
+ encrypted
+ @retval MemEncryptSevAddressRangeMixed Address range is mapped mixed
+ @retval MemEncryptSevAddressRangeError Address range is not mapped
+**/
+MEM_ENCRYPT_SEV_ADDRESS_RANGE_STATE
+EFIAPI
+MemEncryptSevGetAddressRangeState (
+ IN PHYSICAL_ADDRESS Cr3BaseAddress,
+ IN PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN Length
+ );
+
#endif // _MEM_ENCRYPT_SEV_LIB_H_
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf b/OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf
index 4480e4cc7c..8e3b8ddd5a 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/DxeMemEncryptSevLib.inf
@@ -36,6 +36,7 @@
[Sources.X64]
X64/MemEncryptSevLib.c
X64/PeiDxeVirtualMemory.c
+ X64/VirtualMemory.c
X64/VirtualMemory.h
[Sources.IA32]
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/Ia32/MemEncryptSevLib.c b/OvmfPkg/Library/BaseMemEncryptSevLib/Ia32/MemEncryptSevLib.c
index b4f6e5738e..12a5bf495b 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/Ia32/MemEncryptSevLib.c
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/Ia32/MemEncryptSevLib.c
@@ -2,7 +2,7 @@
Secure Encrypted Virtualization (SEV) library helper function
- Copyright (c) 2017, AMD Incorporated. All rights reserved.
+ Copyright (c) 2017 - 2020, AMD Incorporated. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
@@ -82,3 +82,32 @@ MemEncryptSevSetPageEncMask (
//
return RETURN_UNSUPPORTED;
}
+
+/**
+ Returns the encryption state of the specified virtual address range.
+
+ @param[in] Cr3BaseAddress Cr3 Base Address (if zero then use
+ current CR3)
+ @param[in] BaseAddress Base address to check
+ @param[in] Length Length of virtual address range
+
+ @retval MemEncryptSevAddressRangeUnencrypted Address range is mapped
+ unencrypted
+ @retval MemEncryptSevAddressRangeEncrypted Address range is mapped
+ encrypted
+ @retval MemEncryptSevAddressRangeMixed Address range is mapped mixed
+ @retval MemEncryptSevAddressRangeError Address range is not mapped
+**/
+MEM_ENCRYPT_SEV_ADDRESS_RANGE_STATE
+EFIAPI
+MemEncryptSevGetAddressRangeState (
+ IN PHYSICAL_ADDRESS Cr3BaseAddress,
+ IN PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN Length
+ )
+{
+ //
+ // Memory is always encrypted in 32-bit mode
+ //
+ return MemEncryptSevAddressRangeEncrypted;
+}
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf b/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf
index 0697f1dab5..03a78c32df 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/PeiMemEncryptSevLib.inf
@@ -36,6 +36,7 @@
[Sources.X64]
X64/MemEncryptSevLib.c
X64/PeiDxeVirtualMemory.c
+ X64/VirtualMemory.c
X64/VirtualMemory.h
[Sources.IA32]
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLib.inf b/OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLib.inf
index 7cd0111fe4..279c38bfbc 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLib.inf
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/SecMemEncryptSevLib.inf
@@ -35,6 +35,7 @@
[Sources.X64]
X64/MemEncryptSevLib.c
X64/SecVirtualMemory.c
+ X64/VirtualMemory.c
X64/VirtualMemory.h
[Sources.IA32]
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/MemEncryptSevLib.c b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/MemEncryptSevLib.c
index cf0921e214..4fea6a6be0 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/MemEncryptSevLib.c
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/MemEncryptSevLib.c
@@ -2,7 +2,7 @@
Secure Encrypted Virtualization (SEV) library helper function
- Copyright (c) 2017, AMD Incorporated. All rights reserved.
+ Copyright (c) 2017 - 2020, AMD Incorporated. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
@@ -88,3 +88,33 @@ MemEncryptSevSetPageEncMask (
Flush
);
}
+
+/**
+ Returns the encryption state of the specified virtual address range.
+
+ @param[in] Cr3BaseAddress Cr3 Base Address (if zero then use
+ current CR3)
+ @param[in] BaseAddress Base address to check
+ @param[in] Length Length of virtual address range
+
+ @retval MemEncryptSevAddressRangeUnencrypted Address range is mapped
+ unencrypted
+ @retval MemEncryptSevAddressRangeEncrypted Address range is mapped
+ encrypted
+ @retval MemEncryptSevAddressRangeMixed Address range is mapped mixed
+ @retval MemEncryptSevAddressRangeError Address range is not mapped
+**/
+MEM_ENCRYPT_SEV_ADDRESS_RANGE_STATE
+EFIAPI
+MemEncryptSevGetAddressRangeState (
+ IN PHYSICAL_ADDRESS Cr3BaseAddress,
+ IN PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN Length
+ )
+{
+ return InternalMemEncryptSevGetAddressRangeState (
+ Cr3BaseAddress,
+ BaseAddress,
+ Length
+ );
+}
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiDxeVirtualMemory.c b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiDxeVirtualMemory.c
index 3a5bab657b..d3455e812b 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiDxeVirtualMemory.c
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/PeiDxeVirtualMemory.c
@@ -28,14 +28,14 @@ typedef enum {
} MAP_RANGE_MODE;
/**
- Get the memory encryption mask
+ Return the pagetable memory encryption mask.
- @param[out] EncryptionMask contains the pte mask.
+ @return The pagetable memory encryption mask.
**/
-STATIC
UINT64
-GetMemEncryptionAddressMask (
+EFIAPI
+InternalGetMemEncryptionAddressMask (
VOID
)
{
@@ -200,7 +200,7 @@ Split2MPageTo4K (
PageTableEntry1 = PageTableEntry;
- AddressEncMask = GetMemEncryptionAddressMask ();
+ AddressEncMask = InternalGetMemEncryptionAddressMask ();
ASSERT (PageTableEntry != NULL);
ASSERT (*PageEntry2M & AddressEncMask);
@@ -286,7 +286,7 @@ SetPageTablePoolReadOnly (
LevelSize[3] = SIZE_1GB;
LevelSize[4] = SIZE_512GB;
- AddressEncMask = GetMemEncryptionAddressMask();
+ AddressEncMask = InternalGetMemEncryptionAddressMask();
PageTable = (UINT64 *)(UINTN)PageTableBase;
PoolUnitSize = PAGE_TABLE_POOL_UNIT_SIZE;
@@ -431,7 +431,7 @@ Split1GPageTo2M (
PageDirectoryEntry = AllocatePageTableMemory(1);
- AddressEncMask = GetMemEncryptionAddressMask ();
+ AddressEncMask = InternalGetMemEncryptionAddressMask ();
ASSERT (PageDirectoryEntry != NULL);
ASSERT (*PageEntry1G & AddressEncMask);
//
@@ -485,7 +485,7 @@ SetOrClearCBit(
{
UINT64 AddressEncMask;
- AddressEncMask = GetMemEncryptionAddressMask ();
+ AddressEncMask = InternalGetMemEncryptionAddressMask ();
if (Mode == SetCBit) {
*PageTablePointer |= AddressEncMask;
@@ -527,6 +527,7 @@ DisableReadOnlyPageWriteProtect (
/**
Enable Write Protect on pages marked as read-only.
**/
+STATIC
VOID
EnableReadOnlyPageWriteProtect (
VOID
@@ -605,7 +606,7 @@ SetMemoryEncDec (
//
// Check if we have a valid memory encryption mask
//
- AddressEncMask = GetMemEncryptionAddressMask ();
+ AddressEncMask = InternalGetMemEncryptionAddressMask ();
if (!AddressEncMask) {
return RETURN_ACCESS_DENIED;
}
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SecVirtualMemory.c b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SecVirtualMemory.c
index 5c337ea0b8..bca5e3febb 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SecVirtualMemory.c
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/SecVirtualMemory.c
@@ -13,6 +13,26 @@
#include "VirtualMemory.h"
+/**
+ Return the pagetable memory encryption mask.
+
+ @return The pagetable memory encryption mask.
+
+**/
+UINT64
+EFIAPI
+InternalGetMemEncryptionAddressMask (
+ VOID
+ )
+{
+ UINT64 EncryptionMask;
+
+ EncryptionMask = MemEncryptSevGetEncryptionMask ();
+ EncryptionMask &= PAGING_1G_ADDRESS_MASK_64;
+
+ return EncryptionMask;
+}
+
/**
This function clears memory encryption bit for the memory region specified by
PhysicalAddress and Length from the current page table context.
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.c b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.c
new file mode 100644
index 0000000000..36aabcf556
--- /dev/null
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.c
@@ -0,0 +1,207 @@
+/** @file
+
+ Virtual Memory Management Services to test an address range encryption state
+
+ Copyright (c) 2020, AMD Incorporated. All rights reserved.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include
+#include
+
+#include "VirtualMemory.h"
+
+/**
+ Returns the (updated) address range state based upon the page table
+ entry.
+
+ @param[in] CurrentState The current address range state
+ @param[in] PageDirectoryEntry The page table entry to check
+ @param[in] AddressEncMask The encryption mask
+
+ @retval MemEncryptSevAddressRangeUnencrypted Address range is mapped
+ unencrypted
+ @retval MemEncryptSevAddressRangeEncrypted Address range is mapped
+ encrypted
+ @retval MemEncryptSevAddressRangeMixed Address range is mapped mixed
+**/
+STATIC
+MEM_ENCRYPT_SEV_ADDRESS_RANGE_STATE
+UpdateAddressState (
+ IN MEM_ENCRYPT_SEV_ADDRESS_RANGE_STATE CurrentState,
+ IN UINT64 PageDirectoryEntry,
+ IN UINT64 AddressEncMask
+ )
+{
+ if (CurrentState == MemEncryptSevAddressRangeEncrypted) {
+ if ((PageDirectoryEntry & AddressEncMask) == 0) {
+ CurrentState = MemEncryptSevAddressRangeMixed;
+ }
+ } else if (CurrentState == MemEncryptSevAddressRangeUnencrypted) {
+ if ((PageDirectoryEntry & AddressEncMask) != 0) {
+ CurrentState = MemEncryptSevAddressRangeMixed;
+ }
+ } else if (CurrentState == MemEncryptSevAddressRangeError) {
+ //
+ // First address check, set initial state
+ //
+ if ((PageDirectoryEntry & AddressEncMask) == 0) {
+ CurrentState = MemEncryptSevAddressRangeUnencrypted;
+ } else {
+ CurrentState = MemEncryptSevAddressRangeEncrypted;
+ }
+ }
+
+ return CurrentState;
+}
+
+/**
+ Returns the encryption state of the specified virtual address range.
+
+ @param[in] Cr3BaseAddress Cr3 Base Address (if zero then use
+ current CR3)
+ @param[in] BaseAddress Base address to check
+ @param[in] Length Length of virtual address range
+
+ @retval MemEncryptSevAddressRangeUnencrypted Address range is mapped
+ unencrypted
+ @retval MemEncryptSevAddressRangeEncrypted Address range is mapped
+ encrypted
+ @retval MemEncryptSevAddressRangeMixed Address range is mapped mixed
+ @retval MemEncryptSevAddressRangeError Address range is not mapped
+**/
+MEM_ENCRYPT_SEV_ADDRESS_RANGE_STATE
+EFIAPI
+InternalMemEncryptSevGetAddressRangeState (
+ IN PHYSICAL_ADDRESS Cr3BaseAddress,
+ IN PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN Length
+ )
+{
+ 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 AddressEncMask;
+ UINT64 PgTableMask;
+ PHYSICAL_ADDRESS Address;
+ PHYSICAL_ADDRESS AddressEnd;
+ MEM_ENCRYPT_SEV_ADDRESS_RANGE_STATE State;
+
+ //
+ // If Cr3BaseAddress is not specified then read the current CR3
+ //
+ if (Cr3BaseAddress == 0) {
+ Cr3BaseAddress = AsmReadCr3();
+ }
+
+ AddressEncMask = MemEncryptSevGetEncryptionMask ();
+ AddressEncMask &= PAGING_1G_ADDRESS_MASK_64;
+
+ PgTableMask = AddressEncMask | EFI_PAGE_MASK;
+
+ State = MemEncryptSevAddressRangeError;
+
+ //
+ // Encryption is on a page basis, so start at the beginning of the
+ // virtual address page boundary and walk page-by-page.
+ //
+ Address = (PHYSICAL_ADDRESS) (UINTN) BaseAddress & ~EFI_PAGE_MASK;
+ AddressEnd = (PHYSICAL_ADDRESS)
+ (UINTN) (BaseAddress + Length);
+
+ while (Address < AddressEnd) {
+ PageMapLevel4Entry = (VOID*) (Cr3BaseAddress & ~PgTableMask);
+ PageMapLevel4Entry += PML4_OFFSET (Address);
+ if (!PageMapLevel4Entry->Bits.Present) {
+ return MemEncryptSevAddressRangeError;
+ }
+
+ PageDirectory1GEntry = (VOID *) (
+ (PageMapLevel4Entry->Bits.PageTableBaseAddress <<
+ 12) & ~PgTableMask
+ );
+ PageDirectory1GEntry += PDP_OFFSET (Address);
+ if (!PageDirectory1GEntry->Bits.Present) {
+ return MemEncryptSevAddressRangeError;
+ }
+
+ //
+ // If the MustBe1 bit is not 1, it's not actually a 1GB entry
+ //
+ if (PageDirectory1GEntry->Bits.MustBe1) {
+ //
+ // Valid 1GB page
+ //
+ State = UpdateAddressState (
+ State,
+ PageDirectory1GEntry->Uint64,
+ AddressEncMask
+ );
+
+ Address += BIT30;
+ continue;
+ }
+
+ //
+ // Actually a PDP
+ //
+ PageUpperDirectoryPointerEntry =
+ (PAGE_MAP_AND_DIRECTORY_POINTER *) PageDirectory1GEntry;
+ PageDirectory2MEntry =
+ (VOID *) (
+ (PageUpperDirectoryPointerEntry->Bits.PageTableBaseAddress <<
+ 12) & ~PgTableMask
+ );
+ PageDirectory2MEntry += PDE_OFFSET (Address);
+ if (!PageDirectory2MEntry->Bits.Present) {
+ return MemEncryptSevAddressRangeError;
+ }
+
+ //
+ // If the MustBe1 bit is not a 1, it's not a 2MB entry
+ //
+ if (PageDirectory2MEntry->Bits.MustBe1) {
+ //
+ // Valid 2MB page
+ //
+ State = UpdateAddressState (
+ State,
+ PageDirectory2MEntry->Uint64,
+ AddressEncMask
+ );
+
+ Address += BIT21;
+ continue;
+ }
+
+ //
+ // Actually a PMD
+ //
+ PageDirectoryPointerEntry =
+ (PAGE_MAP_AND_DIRECTORY_POINTER *)PageDirectory2MEntry;
+ PageTableEntry =
+ (VOID *)(
+ (PageDirectoryPointerEntry->Bits.PageTableBaseAddress <<
+ 12) & ~PgTableMask
+ );
+ PageTableEntry += PTE_OFFSET (Address);
+ if (!PageTableEntry->Bits.Present) {
+ return MemEncryptSevAddressRangeError;
+ }
+
+ State = UpdateAddressState (
+ State,
+ PageTableEntry->Uint64,
+ AddressEncMask
+ );
+
+ Address += EFI_PAGE_SIZE;
+ }
+
+ return State;
+}
diff --git a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.h b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.h
index 26d26cd922..996f94f07e 100644
--- a/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.h
+++ b/OvmfPkg/Library/BaseMemEncryptSevLib/X64/VirtualMemory.h
@@ -3,7 +3,7 @@
Virtual Memory Management Services to set or clear the memory encryption bit
Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.
- Copyright (c) 2017, AMD Incorporated. All rights reserved.
+ Copyright (c) 2017 - 2020, AMD Incorporated. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
@@ -178,7 +178,17 @@ typedef struct {
UINTN FreePages;
} PAGE_TABLE_POOL;
+/**
+ Return the pagetable memory encryption mask.
+ @return The pagetable memory encryption mask.
+
+**/
+UINT64
+EFIAPI
+InternalGetMemEncryptionAddressMask (
+ VOID
+ );
/**
This function clears memory encryption bit for the memory region specified by
@@ -234,4 +244,27 @@ InternalMemEncryptSevSetMemoryEncrypted (
IN BOOLEAN Flush
);
+/**
+ Returns the encryption state of the specified virtual address range.
+
+ @param[in] Cr3BaseAddress Cr3 Base Address (if zero then use
+ current CR3)
+ @param[in] BaseAddress Base address to check
+ @param[in] Length Length of virtual address range
+
+ @retval MemEncryptSevAddressRangeUnencrypted Address range is mapped
+ unencrypted
+ @retval MemEncryptSevAddressRangeEncrypted Address range is mapped
+ encrypted
+ @retval MemEncryptSevAddressRangeMixed Address range is mapped mixed
+ @retval MemEncryptSevAddressRangeError Address range is not mapped
+**/
+MEM_ENCRYPT_SEV_ADDRESS_RANGE_STATE
+EFIAPI
+InternalMemEncryptSevGetAddressRangeState (
+ IN PHYSICAL_ADDRESS Cr3BaseAddress,
+ IN PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN Length
+ );
+
#endif