OvmfPkg/BaseMemcryptSevLib: Add SEV helper library

Add Secure Encrypted Virtualization (SEV) helper library.
The library provides the routines to:
-  set or clear memory encryption bit for a given memory region.
-  query whether SEV is enabled.

Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
Acked-by: Jordan Justen <jordan.l.justen@intel.com>
This commit is contained in:
Brijesh Singh 2017-07-06 09:21:12 -04:00 committed by Jordan Justen
parent 97353a9c91
commit a1f2261425
10 changed files with 1015 additions and 0 deletions

View File

@ -0,0 +1,81 @@
/** @file
Define Secure Encrypted Virtualization (SEV) base library helper function
Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
This program and the accompanying materials are licensed and made available
under the terms and conditions of the BSD License which accompanies this
distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef _MEM_ENCRYPT_SEV_LIB_H_
#define _MEM_ENCRYPT_SEV_LIB_H_
#include <Base.h>
/**
Returns a boolean to indicate whether SEV is enabled
@retval TRUE SEV is active
@retval FALSE SEV is not enabled
**/
BOOLEAN
EFIAPI
MemEncryptSevIsEnabled (
VOID
);
/**
This function clears memory encryption bit for the memory region specified
by BaseAddress and Number of pages from the current page table context.
@param[in] BaseAddress The physical address that is the start address
of a memory region.
@param[in] NumberOfPages The number of pages from start memory region.
@param[in] Flush Flush the caches before clearing the bit
(mostly TRUE except MMIO addresses)
@retval RETURN_SUCCESS The attributes were cleared for the memory region.
@retval RETURN_INVALID_PARAMETER Number of pages is zero.
@retval RETURN_UNSUPPORTED Clearing memory encryption attribute is not
supported
**/
RETURN_STATUS
EFIAPI
MemEncryptSevClearPageEncMask (
IN PHYSICAL_ADDRESS Cr3BaseAddress,
IN PHYSICAL_ADDRESS BaseAddress,
IN UINTN NumberOfPages,
IN BOOLEAN CacheFlush
);
/**
This function sets memory encryption bit for the memory region specified by
BaseAddress and Number of pages from the current page table context.
@param[in] BaseAddress The physical address that is the start address
of a memory region.
@param[in] NumberOfPages The number of pages from start memory region.
@param[in] Flush Flush the caches before clearing the bit
(mostly TRUE except MMIO addresses)
@retval RETURN_SUCCESS The attributes were set for the memory region.
@retval RETURN_INVALID_PARAMETER Number of pages is zero.
@retval RETURN_UNSUPPORTED Clearing memory encryption attribute is not
supported
**/
RETURN_STATUS
EFIAPI
MemEncryptSevSetPageEncMask (
IN PHYSICAL_ADDRESS Cr3BaseAddress,
IN PHYSICAL_ADDRESS BaseAddress,
IN UINTN NumberOfPages,
IN BOOLEAN CacheFlush
);
#endif // _MEM_ENCRYPT_SEV_LIB_H_

View File

@ -0,0 +1,50 @@
## @file
# Library provides the helper functions for SEV guest
#
# Copyright (c) 2017 Advanced Micro Devices. All rights reserved.<BR>
#
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD
# License which accompanies this distribution. The full text of the license
# may be found at http://opensource.org/licenses/bsd-license.php
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
#
##
[Defines]
INF_VERSION = 1.25
BASE_NAME = MemEncryptSevLib
FILE_GUID = c1594631-3888-4be4-949f-9c630dbc842b
MODULE_TYPE = BASE
VERSION_STRING = 1.0
LIBRARY_CLASS = MemEncryptSevLib|PEIM DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_DRIVER
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64
#
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
OvmfPkg/OvmfPkg.dec
UefiCpuPkg/UefiCpuPkg.dec
[Sources.X64]
MemEncryptSevLibInternal.c
X64/MemEncryptSevLib.c
X64/VirtualMemory.c
[Sources.IA32]
MemEncryptSevLibInternal.c
Ia32/MemEncryptSevLib.c
[LibraryClasses]
BaseLib
CpuLib
CacheMaintenanceLib
DebugLib
MemoryAllocationLib

View File

@ -0,0 +1,84 @@
/** @file
Secure Encrypted Virtualization (SEV) library helper function
Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD
License which accompanies this distribution. The full text of the license may
be found at http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include <Register/Cpuid.h>
#include <Register/Amd/Cpuid.h>
#include <Register/Amd/Msr.h>
#include <Library/MemEncryptSevLib.h>
/**
This function clears memory encryption bit for the memory region specified
by BaseAddress and Number of pages from the current page table context.
@param[in] Cr3BaseAddress Cr3 Base Address (if zero then use current CR3)
@param[in] BaseAddress The physical address that is the start address
of a memory region.
@param[in] NumberOfPages The number of pages from start memory region.
@param[in] Flush Flush the caches before clearing the bit
(mostly TRUE except MMIO addresses)
@retval RETURN_SUCCESS The attributes were cleared for the memory region.
@retval RETURN_INVALID_PARAMETER Number of pages is zero.
@retval RETURN_UNSUPPORTED Clearing memory encryption attribute is not
supported
**/
RETURN_STATUS
EFIAPI
MemEncryptSevClearPageEncMask (
IN PHYSICAL_ADDRESS Cr3BaseAddress,
IN PHYSICAL_ADDRESS BaseAddress,
IN UINTN NumberOfPages,
IN BOOLEAN Flush
)
{
//
// Memory encryption bit is not accessible in 32-bit mode
//
return RETURN_UNSUPPORTED;
}
/**
This function sets memory encryption bit for the memory region specified by
BaseAddress and Number of pages from the current page table context.
@param[in] Cr3BaseAddress Cr3 Base Address (if zero then use current CR3)
@param[in] BaseAddress The physical address that is the start address
of a memory region.
@param[in] NumberOfPages The number of pages from start memory region.
@param[in] Flush Flush the caches before clearing the bit
(mostly TRUE except MMIO addresses)
@retval RETURN_SUCCESS The attributes were set for the memory region.
@retval RETURN_INVALID_PARAMETER Number of pages is zero.
@retval RETURN_UNSUPPORTED Clearing memory encryption attribute is not
supported
**/
RETURN_STATUS
EFIAPI
MemEncryptSevSetPageEncMask (
IN PHYSICAL_ADDRESS Cr3BaseAddress,
IN PHYSICAL_ADDRESS BaseAddress,
IN UINTN NumberOfPages,
IN BOOLEAN Flush
)
{
//
// Memory encryption bit is not accessible in 32-bit mode
//
return RETURN_UNSUPPORTED;
}

View File

@ -0,0 +1,90 @@
/** @file
Secure Encrypted Virtualization (SEV) library helper function
Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD
License which accompanies this distribution. The full text of the license may
be found at http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include <Register/Cpuid.h>
#include <Register/Amd/Cpuid.h>
#include <Register/Amd/Msr.h>
#include <Library/MemEncryptSevLib.h>
STATIC BOOLEAN mSevStatus = FALSE;
STATIC BOOLEAN mSevStatusChecked = FALSE;
/**
Returns a boolean to indicate whether SEV is enabled
@retval TRUE SEV is enabled
@retval FALSE SEV is not enabled
**/
STATIC
BOOLEAN
EFIAPI
InternalMemEncryptSevIsEnabled (
VOID
)
{
UINT32 RegEax;
MSR_SEV_STATUS_REGISTER Msr;
CPUID_MEMORY_ENCRYPTION_INFO_EAX Eax;
//
// Check if memory encryption leaf exist
//
AsmCpuid (CPUID_EXTENDED_FUNCTION, &RegEax, NULL, NULL, NULL);
if (RegEax >= CPUID_MEMORY_ENCRYPTION_INFO) {
//
// CPUID Fn8000_001F[EAX] Bit 1 (Sev supported)
//
AsmCpuid (CPUID_MEMORY_ENCRYPTION_INFO, &Eax.Uint32, NULL, NULL, NULL);
if (Eax.Bits.SevBit) {
//
// Check MSR_0xC0010131 Bit 0 (Sev Enabled)
//
Msr.Uint32 = AsmReadMsr32 (MSR_SEV_STATUS);
if (Msr.Bits.SevBit) {
return TRUE;
}
}
}
return FALSE;
}
/**
Returns a boolean to indicate whether SEV is enabled
@retval TRUE SEV is enabled
@retval FALSE SEV is not enabled
**/
BOOLEAN
EFIAPI
MemEncryptSevIsEnabled (
VOID
)
{
if (mSevStatusChecked) {
return mSevStatus;
}
mSevStatus = InternalMemEncryptSevIsEnabled();
mSevStatusChecked = TRUE;
return mSevStatus;
}

View File

@ -0,0 +1,84 @@
/** @file
Secure Encrypted Virtualization (SEV) library helper function
Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD
License which accompanies this distribution. The full text of the license may
be found at http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include <Register/Cpuid.h>
#include <Register/Amd/Cpuid.h>
#include <Register/Amd/Msr.h>
#include <Library/MemEncryptSevLib.h>
#include "VirtualMemory.h"
/**
This function clears memory encryption bit for the memory region specified by
BaseAddress and Number of pages from the current page table context.
@param[in] Cr3BaseAddress Cr3 Base Address (if zero then use current CR3)
@param[in] BaseAddress The physical address that is the start address
of a memory region.
@param[in] NumberOfPages The number of pages from start memory region.
@param[in] Flush Flush the caches before clearing the bit
(mostly TRUE except MMIO addresses)
@retval RETURN_SUCCESS The attributes were cleared for the memory
region.
@retval RETURN_INVALID_PARAMETER Number of pages is zero.
@retval RETURN_UNSUPPORTED Clearing the memory encryption attribute is
not supported
**/
RETURN_STATUS
EFIAPI
MemEncryptSevClearPageEncMask (
IN PHYSICAL_ADDRESS Cr3BaseAddress,
IN PHYSICAL_ADDRESS BaseAddress,
IN UINTN NumPages,
IN BOOLEAN Flush
)
{
return InternalMemEncryptSevSetMemoryDecrypted (Cr3BaseAddress, BaseAddress, EFI_PAGES_TO_SIZE(NumPages), Flush);
}
/**
This function clears memory encryption bit for the memory region specified by
BaseAddress and Number of pages from the current page table context.
@param[in] Cr3BaseAddress Cr3 Base Address (if zero then use current CR3)
@param[in] BaseAddress The physical address that is the start address
of a memory region.
@param[in] NumberOfPages The number of pages from start memory region.
@param[in] Flush Flush the caches before clearing the bit
(mostly TRUE except MMIO addresses)
@retval RETURN_SUCCESS The attributes were cleared for the memory
region.
@retval RETURN_INVALID_PARAMETER Number of pages is zero.
@retval RETURN_UNSUPPORTED Clearing the memory encryption attribute is
not supported
**/
RETURN_STATUS
EFIAPI
MemEncryptSevSetPageEncMask (
IN PHYSICAL_ADDRESS Cr3BaseAddress,
IN PHYSICAL_ADDRESS BaseAddress,
IN UINTN NumPages,
IN BOOLEAN Flush
)
{
return InternalMemEncryptSevSetMemoryEncrypted (Cr3BaseAddress, BaseAddress, EFI_PAGES_TO_SIZE(NumPages), Flush);
}

View File

@ -0,0 +1,439 @@
/** @file
Virtual Memory Management Services to set or clear the memory encryption bit
Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Code is derived from MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c
**/
#include <Library/CpuLib.h>
#include <Register/Cpuid.h>
#include <Register/Amd/Cpuid.h>
#include "VirtualMemory.h"
STATIC BOOLEAN mAddressEncMaskChecked = FALSE;
STATIC UINT64 mAddressEncMask;
typedef enum {
SetCBit,
ClearCBit
} MAP_RANGE_MODE;
/**
Get the memory encryption mask
@param[out] EncryptionMask contains the pte mask.
**/
STATIC
UINT64
GetMemEncryptionAddressMask (
VOID
)
{
UINT64 EncryptionMask;
CPUID_MEMORY_ENCRYPTION_INFO_EBX Ebx;
if (mAddressEncMaskChecked) {
return mAddressEncMask;
}
//
// CPUID Fn8000_001F[EBX] Bit 0:5 (memory encryption bit position)
//
AsmCpuid (CPUID_MEMORY_ENCRYPTION_INFO, NULL, &Ebx.Uint32, NULL, NULL);
EncryptionMask = LShiftU64 (1, Ebx.Bits.PtePosBits);
mAddressEncMask = EncryptionMask & PAGING_1G_ADDRESS_MASK_64;
mAddressEncMaskChecked = TRUE;
return mAddressEncMask;
}
/**
Split 2M page to 4K.
@param[in] PhysicalAddress Start physical address the 2M page covered.
@param[in, out] PageEntry2M Pointer to 2M page entry.
@param[in] StackBase Stack base address.
@param[in] StackSize Stack size.
**/
STATIC
VOID
Split2MPageTo4K (
IN PHYSICAL_ADDRESS PhysicalAddress,
IN OUT UINT64 *PageEntry2M,
IN PHYSICAL_ADDRESS StackBase,
IN UINTN StackSize
)
{
PHYSICAL_ADDRESS PhysicalAddress4K;
UINTN IndexOfPageTableEntries;
PAGE_TABLE_4K_ENTRY *PageTableEntry, *PageTableEntry1;
UINT64 AddressEncMask;
PageTableEntry = AllocatePages(1);
PageTableEntry1 = PageTableEntry;
AddressEncMask = GetMemEncryptionAddressMask ();
ASSERT (PageTableEntry != NULL);
ASSERT (*PageEntry2M & AddressEncMask);
PhysicalAddress4K = PhysicalAddress;
for (IndexOfPageTableEntries = 0; IndexOfPageTableEntries < 512; IndexOfPageTableEntries++, PageTableEntry++, PhysicalAddress4K += SIZE_4KB) {
//
// Fill in the Page Table entries
//
PageTableEntry->Uint64 = (UINT64) PhysicalAddress4K | AddressEncMask;
PageTableEntry->Bits.ReadWrite = 1;
PageTableEntry->Bits.Present = 1;
if ((PhysicalAddress4K >= StackBase) && (PhysicalAddress4K < StackBase + StackSize)) {
//
// Set Nx bit for stack.
//
PageTableEntry->Bits.Nx = 1;
}
}
//
// Fill in 2M page entry.
//
*PageEntry2M = (UINT64) (UINTN) PageTableEntry1 | IA32_PG_P | IA32_PG_RW | AddressEncMask;
}
/**
Split 1G page to 2M.
@param[in] PhysicalAddress Start physical address the 1G page covered.
@param[in, out] PageEntry1G Pointer to 1G page entry.
@param[in] StackBase Stack base address.
@param[in] StackSize Stack size.
**/
STATIC
VOID
Split1GPageTo2M (
IN PHYSICAL_ADDRESS PhysicalAddress,
IN OUT UINT64 *PageEntry1G,
IN PHYSICAL_ADDRESS StackBase,
IN UINTN StackSize
)
{
PHYSICAL_ADDRESS PhysicalAddress2M;
UINTN IndexOfPageDirectoryEntries;
PAGE_TABLE_ENTRY *PageDirectoryEntry;
UINT64 AddressEncMask;
PageDirectoryEntry = AllocatePages(1);
AddressEncMask = GetMemEncryptionAddressMask ();
ASSERT (PageDirectoryEntry != NULL);
ASSERT (*PageEntry1G & GetMemEncryptionAddressMask ());
//
// Fill in 1G page entry.
//
*PageEntry1G = (UINT64) (UINTN) PageDirectoryEntry | IA32_PG_P | IA32_PG_RW | AddressEncMask;
PhysicalAddress2M = PhysicalAddress;
for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PhysicalAddress2M += SIZE_2MB) {
if ((PhysicalAddress2M < StackBase + StackSize) && ((PhysicalAddress2M + SIZE_2MB) > StackBase)) {
//
// Need to split this 2M page that covers stack range.
//
Split2MPageTo4K (PhysicalAddress2M, (UINT64 *) PageDirectoryEntry, StackBase, StackSize);
} else {
//
// Fill in the Page Directory entries
//
PageDirectoryEntry->Uint64 = (UINT64) PhysicalAddress2M | AddressEncMask;
PageDirectoryEntry->Bits.ReadWrite = 1;
PageDirectoryEntry->Bits.Present = 1;
PageDirectoryEntry->Bits.MustBe1 = 1;
}
}
}
/**
Set or Clear the memory encryption bit
@param[in] PagetablePoint Page table entry pointer (PTE).
@param[in] Mode Set or Clear encryption bit
**/
STATIC VOID
SetOrClearCBit(
IN OUT UINT64* PageTablePointer,
IN MAP_RANGE_MODE Mode
)
{
UINT64 AddressEncMask;
AddressEncMask = GetMemEncryptionAddressMask ();
if (Mode == SetCBit) {
*PageTablePointer |= AddressEncMask;
} else {
*PageTablePointer &= ~AddressEncMask;
}
}
/**
This function either sets or clears memory encryption 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 mask 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] PhysicalAddress The physical address that is the start
address of a memory region.
@param[in] Length The length of memory region
@param[in] Mode Set or Clear mode
@param[in] Flush Flush the caches before applying the
encryption mask
@retval RETURN_SUCCESS The attributes were cleared for the memory
region.
@retval RETURN_INVALID_PARAMETER Number of pages is zero.
@retval RETURN_UNSUPPORTED Setting the memory encyrption attribute is
not supported
**/
STATIC
RETURN_STATUS
EFIAPI
SetMemoryEncDec (
IN PHYSICAL_ADDRESS Cr3BaseAddress,
IN PHYSICAL_ADDRESS PhysicalAddress,
IN UINTN Length,
IN MAP_RANGE_MODE Mode,
IN BOOLEAN CacheFlush
)
{
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 AddressEncMask;
//
// Check if we have a valid memory encryption mask
//
AddressEncMask = GetMemEncryptionAddressMask ();
if (!AddressEncMask) {
return RETURN_ACCESS_DENIED;
}
PgTableMask = AddressEncMask | EFI_PAGE_MASK;
if (Length == 0) {
return RETURN_INVALID_PARAMETER;
}
//
// We are going to change the memory encryption attribute from C=0 -> C=1 or
// vice versa Flush the caches to ensure that data is written into memory with
// correct C-bit
//
if (CacheFlush) {
WriteBackInvalidateDataCacheRange((VOID*) (UINTN)PhysicalAddress, Length);
}
while (Length)
{
//
// If Cr3BaseAddress is not specified then read the current CR3
//
if (Cr3BaseAddress == 0) {
Cr3BaseAddress = AsmReadCr3();
}
PageMapLevel4Entry = (VOID*) (Cr3BaseAddress & ~PgTableMask);
PageMapLevel4Entry += PML4_OFFSET(PhysicalAddress);
if (!PageMapLevel4Entry->Bits.Present) {
DEBUG ((DEBUG_WARN,
"%a:%a ERROR bad PML4 for %lx\n", gEfiCallerBaseName, __FUNCTION__,
PhysicalAddress));
return RETURN_NO_MAPPING;
}
PageDirectory1GEntry = (VOID*) ((PageMapLevel4Entry->Bits.PageTableBaseAddress<<12) & ~PgTableMask);
PageDirectory1GEntry += PDP_OFFSET(PhysicalAddress);
if (!PageDirectory1GEntry->Bits.Present) {
DEBUG ((DEBUG_WARN,
"%a:%a ERROR bad PDPE for %lx\n", gEfiCallerBaseName,
__FUNCTION__, PhysicalAddress));
return RETURN_NO_MAPPING;
}
//
// 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)) && Length >= BIT30) {
SetOrClearCBit(&PageDirectory1GEntry->Uint64, Mode);
DEBUG ((DEBUG_VERBOSE,
"%a:%a Updated 1GB entry for %lx\n", gEfiCallerBaseName,
__FUNCTION__, PhysicalAddress));
PhysicalAddress += BIT30;
Length -= BIT30;
} else {
//
// We must split the page
//
DEBUG ((DEBUG_VERBOSE,
"%a:%a Spliting 1GB page\n", gEfiCallerBaseName, __FUNCTION__));
Split1GPageTo2M(((UINT64)PageDirectory1GEntry->Bits.PageTableBaseAddress)<<30, (UINT64*) PageDirectory1GEntry, 0, 0);
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_WARN,
"%a:%a ERROR bad PDE for %lx\n", gEfiCallerBaseName, __FUNCTION__,
PhysicalAddress));
return RETURN_NO_MAPPING;
}
//
// 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)) && Length >= BIT21) {
SetOrClearCBit (&PageDirectory2MEntry->Uint64, Mode);
PhysicalAddress += BIT21;
Length -= BIT21;
} else {
//
// We must split up this page into 4K pages
//
DEBUG ((DEBUG_VERBOSE,
"%a:%a Spliting 2MB page at %lx\n", gEfiCallerBaseName,__FUNCTION__,
PhysicalAddress));
Split2MPageTo4K (((UINT64)PageDirectory2MEntry->Bits.PageTableBaseAddress) << 21, (UINT64*) PageDirectory2MEntry, 0, 0);
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_WARN,
"%a:%a ERROR bad PTE for %lx\n", gEfiCallerBaseName,
__FUNCTION__, PhysicalAddress));
return RETURN_NO_MAPPING;
}
SetOrClearCBit (&PageTableEntry->Uint64, Mode);
PhysicalAddress += EFI_PAGE_SIZE;
Length -= EFI_PAGE_SIZE;
}
}
}
//
// Flush TLB
//
CpuFlushTlb();
return RETURN_SUCCESS;
}
/**
This function clears memory encryption bit for the memory region specified by
PhysicalAddress and length from the current page table context.
@param[in] PhysicalAddress The physical address that is the start
address of a memory region.
@param[in] Length The length of memory region
@param[in] Flush Flush the caches before applying the
encryption mask
@retval RETURN_SUCCESS The attributes were cleared for the memory
region.
@retval RETURN_INVALID_PARAMETER Number of pages is zero.
@retval RETURN_UNSUPPORTED Setting the memory encyrption attribute is
not supported
**/
RETURN_STATUS
EFIAPI
InternalMemEncryptSevSetMemoryDecrypted (
IN PHYSICAL_ADDRESS Cr3BaseAddress,
IN PHYSICAL_ADDRESS PhysicalAddress,
IN UINTN Length,
IN BOOLEAN Flush
)
{
DEBUG ((DEBUG_VERBOSE,
"%a:%a Clear C-bit Cr3 %Lx Base %Lx Length %Lx flush %d\n",
gEfiCallerBaseName, __FUNCTION__, Cr3BaseAddress, PhysicalAddress, Length,
Flush));
return SetMemoryEncDec (Cr3BaseAddress, PhysicalAddress, Length, ClearCBit, Flush);
}
/**
This function sets memory encryption bit for the memory region specified by
PhysicalAddress and length from the current page table context.
@param[in] PhysicalAddress The physical address that is the start address
of a memory region.
@param[in] Length The length of memory region
@param[in] Flush Flush the caches before applying the
encryption mask
@retval RETURN_SUCCESS The attributes were cleared for the memory
region.
@retval RETURN_INVALID_PARAMETER Number of pages is zero.
@retval RETURN_UNSUPPORTED Setting the memory encyrption attribute is
not supported
**/
RETURN_STATUS
EFIAPI
InternalMemEncryptSevSetMemoryEncrypted (
IN PHYSICAL_ADDRESS Cr3BaseAddress,
IN PHYSICAL_ADDRESS PhysicalAddress,
IN UINTN Length,
IN BOOLEAN Flush
)
{
DEBUG ((DEBUG_VERBOSE,
"%a:%a Set C-bit Cr3 %Lx Base %Lx Length %Lx flush %d\n",
gEfiCallerBaseName, __FUNCTION__, Cr3BaseAddress, PhysicalAddress, Length,
Flush));
return SetMemoryEncDec (Cr3BaseAddress, PhysicalAddress, Length, SetCBit, Flush);
}

View File

@ -0,0 +1,184 @@
/** @file
Virtual Memory Management Services to set or clear the memory encryption bit
Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Code is derived from MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.h
**/
#ifndef __VIRTUAL_MEMORY__
#define __VIRTUAL_MEMORY__
#include <Uefi.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/CacheMaintenanceLib.h>
#define SYS_CODE64_SEL 0x38
#pragma pack(1)
//
// Page-Map Level-4 Offset (PML4) and
// Page-Directory-Pointer Offset (PDPE) entries 4K & 2MB
//
typedef union {
struct {
UINT64 Present:1; // 0 = Not present in memory, 1 = Present in memory
UINT64 ReadWrite:1; // 0 = Read-Only, 1= Read/Write
UINT64 UserSupervisor:1; // 0 = Supervisor, 1=User
UINT64 WriteThrough:1; // 0 = Write-Back caching, 1=Write-Through caching
UINT64 CacheDisabled:1; // 0 = Cached, 1=Non-Cached
UINT64 Accessed:1; // 0 = Not accessed, 1 = Accessed (set by CPU)
UINT64 Reserved:1; // Reserved
UINT64 MustBeZero:2; // Must Be Zero
UINT64 Available:3; // Available for use by system software
UINT64 PageTableBaseAddress:40; // Page Table Base Address
UINT64 AvabilableHigh:11; // Available for use by system software
UINT64 Nx:1; // No Execute bit
} Bits;
UINT64 Uint64;
} PAGE_MAP_AND_DIRECTORY_POINTER;
//
// Page Table Entry 4KB
//
typedef union {
struct {
UINT64 Present:1; // 0 = Not present in memory, 1 = Present in memory
UINT64 ReadWrite:1; // 0 = Read-Only, 1= Read/Write
UINT64 UserSupervisor:1; // 0 = Supervisor, 1=User
UINT64 WriteThrough:1; // 0 = Write-Back caching, 1=Write-Through caching
UINT64 CacheDisabled:1; // 0 = Cached, 1=Non-Cached
UINT64 Accessed:1; // 0 = Not accessed, 1 = Accessed (set by CPU)
UINT64 Dirty:1; // 0 = Not Dirty, 1 = written by processor on access to page
UINT64 PAT:1; //
UINT64 Global:1; // 0 = Not global page, 1 = global page TLB not cleared on CR3 write
UINT64 Available:3; // Available for use by system software
UINT64 PageTableBaseAddress:40; // Page Table Base Address
UINT64 AvabilableHigh:11; // Available for use by system software
UINT64 Nx:1; // 0 = Execute Code, 1 = No Code Execution
} Bits;
UINT64 Uint64;
} PAGE_TABLE_4K_ENTRY;
//
// Page Table Entry 2MB
//
typedef union {
struct {
UINT64 Present:1; // 0 = Not present in memory, 1 = Present in memory
UINT64 ReadWrite:1; // 0 = Read-Only, 1= Read/Write
UINT64 UserSupervisor:1; // 0 = Supervisor, 1=User
UINT64 WriteThrough:1; // 0 = Write-Back caching, 1=Write-Through caching
UINT64 CacheDisabled:1; // 0 = Cached, 1=Non-Cached
UINT64 Accessed:1; // 0 = Not accessed, 1 = Accessed (set by CPU)
UINT64 Dirty:1; // 0 = Not Dirty, 1 = written by processor on access to page
UINT64 MustBe1:1; // Must be 1
UINT64 Global:1; // 0 = Not global page, 1 = global page TLB not cleared on CR3 write
UINT64 Available:3; // Available for use by system software
UINT64 PAT:1; //
UINT64 MustBeZero:8; // Must be zero;
UINT64 PageTableBaseAddress:31; // Page Table Base Address
UINT64 AvabilableHigh:11; // Available for use by system software
UINT64 Nx:1; // 0 = Execute Code, 1 = No Code Execution
} Bits;
UINT64 Uint64;
} PAGE_TABLE_ENTRY;
//
// Page Table Entry 1GB
//
typedef union {
struct {
UINT64 Present:1; // 0 = Not present in memory, 1 = Present in memory
UINT64 ReadWrite:1; // 0 = Read-Only, 1= Read/Write
UINT64 UserSupervisor:1; // 0 = Supervisor, 1=User
UINT64 WriteThrough:1; // 0 = Write-Back caching, 1=Write-Through caching
UINT64 CacheDisabled:1; // 0 = Cached, 1=Non-Cached
UINT64 Accessed:1; // 0 = Not accessed, 1 = Accessed (set by CPU)
UINT64 Dirty:1; // 0 = Not Dirty, 1 = written by processor on access to page
UINT64 MustBe1:1; // Must be 1
UINT64 Global:1; // 0 = Not global page, 1 = global page TLB not cleared on CR3 write
UINT64 Available:3; // Available for use by system software
UINT64 PAT:1; //
UINT64 MustBeZero:17; // Must be zero;
UINT64 PageTableBaseAddress:22; // Page Table Base Address
UINT64 AvabilableHigh:11; // Available for use by system software
UINT64 Nx:1; // 0 = Execute Code, 1 = No Code Execution
} Bits;
UINT64 Uint64;
} PAGE_TABLE_1G_ENTRY;
#pragma pack()
#define IA32_PG_P BIT0
#define IA32_PG_RW BIT1
#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)
#define PAGING_1G_ADDRESS_MASK_64 0x000FFFFFC0000000ull
/**
This function clears memory encryption bit for the memory region specified by PhysicalAddress
and length from the current page table context.
@param[in] PhysicalAddress The physical address that is the start address of a memory region.
@param[in] Length The length of memory region
@param[in] Flush Flush the caches before applying the encryption mask
@retval RETURN_SUCCESS The attributes were cleared for the memory region.
@retval RETURN_INVALID_PARAMETER Number of pages is zero.
@retval RETURN_UNSUPPORTED Setting the memory encyrption attribute is not supported
**/
RETURN_STATUS
EFIAPI
InternalMemEncryptSevSetMemoryDecrypted (
IN PHYSICAL_ADDRESS Cr3BaseAddress,
IN PHYSICAL_ADDRESS PhysicalAddress,
IN UINT64 Length,
IN BOOLEAN CacheFlush
);
/**
This function sets memory encryption bit for the memory region specified by
PhysicalAddress and length from the current page table context.
@param[in] PhysicalAddress The physical address that is the start address
of a memory region.
@param[in] Length The length of memory region
@param[in] Flush Flush the caches before applying the
encryption mask
@retval RETURN_SUCCESS The attributes were cleared for the memory region.
@retval RETURN_INVALID_PARAMETER Number of pages is zero.
@retval RETURN_UNSUPPORTED Setting the memory encyrption attribute is
not supported
**/
RETURN_STATUS
EFIAPI
InternalMemEncryptSevSetMemoryEncrypted (
IN PHYSICAL_ADDRESS Cr3BaseAddress,
IN PHYSICAL_ADDRESS PhysicalAddress,
IN UINT64 Length,
IN BOOLEAN CacheFlush
);
#endif

View File

@ -145,6 +145,7 @@
QemuFwCfgLib|OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLib.inf
VirtioLib|OvmfPkg/Library/VirtioLib/VirtioLib.inf
LoadLinuxLib|OvmfPkg/Library/LoadLinuxLib/LoadLinuxLib.inf
MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/BaseMemEncryptSevLib.inf
!if $(SMM_REQUIRE) == FALSE
LockBoxLib|OvmfPkg/Library/LockBoxLib/LockBoxBaseLib.inf
!endif

View File

@ -150,6 +150,7 @@
QemuFwCfgLib|OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLib.inf
VirtioLib|OvmfPkg/Library/VirtioLib/VirtioLib.inf
LoadLinuxLib|OvmfPkg/Library/LoadLinuxLib/LoadLinuxLib.inf
MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/BaseMemEncryptSevLib.inf
!if $(SMM_REQUIRE) == FALSE
LockBoxLib|OvmfPkg/Library/LockBoxLib/LockBoxBaseLib.inf
!endif

View File

@ -150,6 +150,7 @@
QemuFwCfgLib|OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLib.inf
VirtioLib|OvmfPkg/Library/VirtioLib/VirtioLib.inf
LoadLinuxLib|OvmfPkg/Library/LoadLinuxLib/LoadLinuxLib.inf
MemEncryptSevLib|OvmfPkg/Library/BaseMemEncryptSevLib/BaseMemEncryptSevLib.inf
!if $(SMM_REQUIRE) == FALSE
LockBoxLib|OvmfPkg/Library/LockBoxLib/LockBoxBaseLib.inf
!endif