/** @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;
}