BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3108 Update the MemEncryptSevLib library to include an interface that can report the encryption state on a range of memory. The values will represent the range as being unencrypted, encrypted, a mix of unencrypted and encrypted, and error (e.g. ranges that aren't mapped). Cc: Jordan Justen <jordan.l.justen@intel.com> Cc: Laszlo Ersek <lersek@redhat.com> Cc: Ard Biesheuvel <ard.biesheuvel@arm.com> Cc: Brijesh Singh <brijesh.singh@amd.com> Acked-by: Laszlo Ersek <lersek@redhat.com> Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com> Message-Id: <0d98f4d42a2b67310c29bac7bcdcf1eda6835847.1610045305.git.thomas.lendacky@amd.com>
		
			
				
	
	
		
			208 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			208 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
 | 
						|
  Virtual Memory Management Services to test an address range encryption state
 | 
						|
 | 
						|
  Copyright (c) 2020, AMD Incorporated. All rights reserved.<BR>
 | 
						|
 | 
						|
  SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include <Library/CpuLib.h>
 | 
						|
#include <Library/MemEncryptSevLib.h>
 | 
						|
 | 
						|
#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;
 | 
						|
}
 |