mirror of https://github.com/acidanthera/audk.git
OvmfPkg/MemEncryptSevLib: add support to validate > 4GB memory in PEI phase
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3275 The initial page built during the SEC phase is used by the MemEncryptSevSnpValidateSystemRam() for the system RAM validation. The page validation process requires using the PVALIDATE instruction; the instruction accepts a virtual address of the memory region that needs to be validated. If hardware encounters a page table walk failure (due to page-not-present) then it raises #GP. The initial page table built in SEC phase address up to 4GB. Add an internal function to extend the page table to cover > 4GB. The function builds 1GB entries in the page table for access > 4GB. This will provide the support to call PVALIDATE instruction for the virtual address > 4GB in PEI phase. Cc: Michael Roth <michael.roth@amd.com> Cc: James Bottomley <jejb@linux.ibm.com> Cc: Min Xu <min.m.xu@intel.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Tom Lendacky <thomas.lendacky@amd.com> Cc: Jordan Justen <jordan.l.justen@intel.com> Cc: Ard Biesheuvel <ardb+tianocore@kernel.org> Cc: Erdem Aktas <erdemaktas@google.com> Cc: Gerd Hoffmann <kraxel@redhat.com> Acked-by: Jiewen Yao <Jiewen.yao@intel.com> Acked-by: Gerd Hoffmann <kraxel@redhat.com> Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
This commit is contained in:
parent
11b15336f0
commit
d39f8d88ec
|
@ -536,6 +536,120 @@ EnableReadOnlyPageWriteProtect (
|
||||||
AsmWriteCr0 (AsmReadCr0 () | BIT16);
|
AsmWriteCr0 (AsmReadCr0 () | BIT16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RETURN_STATUS
|
||||||
|
EFIAPI
|
||||||
|
InternalMemEncryptSevCreateIdentityMap1G (
|
||||||
|
IN PHYSICAL_ADDRESS Cr3BaseAddress,
|
||||||
|
IN PHYSICAL_ADDRESS PhysicalAddress,
|
||||||
|
IN UINTN Length
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PAGE_MAP_AND_DIRECTORY_POINTER *PageMapLevel4Entry;
|
||||||
|
PAGE_TABLE_1G_ENTRY *PageDirectory1GEntry;
|
||||||
|
UINT64 PgTableMask;
|
||||||
|
UINT64 AddressEncMask;
|
||||||
|
BOOLEAN IsWpEnabled;
|
||||||
|
RETURN_STATUS Status;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Set PageMapLevel4Entry to suppress incorrect compiler/analyzer warnings.
|
||||||
|
//
|
||||||
|
PageMapLevel4Entry = NULL;
|
||||||
|
|
||||||
|
DEBUG ((
|
||||||
|
DEBUG_VERBOSE,
|
||||||
|
"%a:%a: Cr3Base=0x%Lx Physical=0x%Lx Length=0x%Lx\n",
|
||||||
|
gEfiCallerBaseName,
|
||||||
|
__FUNCTION__,
|
||||||
|
Cr3BaseAddress,
|
||||||
|
PhysicalAddress,
|
||||||
|
(UINT64)Length
|
||||||
|
));
|
||||||
|
|
||||||
|
if (Length == 0) {
|
||||||
|
return RETURN_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Check if we have a valid memory encryption mask
|
||||||
|
//
|
||||||
|
AddressEncMask = InternalGetMemEncryptionAddressMask ();
|
||||||
|
if (!AddressEncMask) {
|
||||||
|
return RETURN_ACCESS_DENIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
PgTableMask = AddressEncMask | EFI_PAGE_MASK;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Make sure that the page table is changeable.
|
||||||
|
//
|
||||||
|
IsWpEnabled = IsReadOnlyPageWriteProtected ();
|
||||||
|
if (IsWpEnabled) {
|
||||||
|
DisableReadOnlyPageWriteProtect ();
|
||||||
|
}
|
||||||
|
|
||||||
|
Status = EFI_SUCCESS;
|
||||||
|
|
||||||
|
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_ERROR,
|
||||||
|
"%a:%a: bad PML4 for Physical=0x%Lx\n",
|
||||||
|
gEfiCallerBaseName,
|
||||||
|
__FUNCTION__,
|
||||||
|
PhysicalAddress
|
||||||
|
));
|
||||||
|
Status = RETURN_NO_MAPPING;
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
PageDirectory1GEntry = (VOID *)(
|
||||||
|
(PageMapLevel4Entry->Bits.PageTableBaseAddress <<
|
||||||
|
12) & ~PgTableMask
|
||||||
|
);
|
||||||
|
PageDirectory1GEntry += PDP_OFFSET (PhysicalAddress);
|
||||||
|
if (!PageDirectory1GEntry->Bits.Present) {
|
||||||
|
PageDirectory1GEntry->Bits.Present = 1;
|
||||||
|
PageDirectory1GEntry->Bits.MustBe1 = 1;
|
||||||
|
PageDirectory1GEntry->Bits.MustBeZero = 0;
|
||||||
|
PageDirectory1GEntry->Bits.ReadWrite = 1;
|
||||||
|
PageDirectory1GEntry->Uint64 |= (UINT64)PhysicalAddress | AddressEncMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Length <= BIT30) {
|
||||||
|
Length = 0;
|
||||||
|
} else {
|
||||||
|
Length -= BIT30;
|
||||||
|
}
|
||||||
|
|
||||||
|
PhysicalAddress += BIT30;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Flush TLB
|
||||||
|
//
|
||||||
|
CpuFlushTlb ();
|
||||||
|
|
||||||
|
Done:
|
||||||
|
//
|
||||||
|
// Restore page table write protection, if any.
|
||||||
|
//
|
||||||
|
if (IsWpEnabled) {
|
||||||
|
EnableReadOnlyPageWriteProtect ();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
This function either sets or clears memory encryption bit for the memory
|
This function either sets or clears memory encryption bit for the memory
|
||||||
region specified by PhysicalAddress and Length from the current page table
|
region specified by PhysicalAddress and Length from the current page table
|
||||||
|
|
|
@ -10,9 +10,12 @@
|
||||||
|
|
||||||
#include <Uefi/UefiBaseType.h>
|
#include <Uefi/UefiBaseType.h>
|
||||||
#include <Library/BaseLib.h>
|
#include <Library/BaseLib.h>
|
||||||
|
#include <Library/PcdLib.h>
|
||||||
|
#include <Library/DebugLib.h>
|
||||||
#include <Library/MemEncryptSevLib.h>
|
#include <Library/MemEncryptSevLib.h>
|
||||||
|
|
||||||
#include "SnpPageStateChange.h"
|
#include "SnpPageStateChange.h"
|
||||||
|
#include "VirtualMemory.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
UINT64 StartAddress;
|
UINT64 StartAddress;
|
||||||
|
@ -70,6 +73,7 @@ MemEncryptSevSnpPreValidateSystemRam (
|
||||||
{
|
{
|
||||||
PHYSICAL_ADDRESS EndAddress;
|
PHYSICAL_ADDRESS EndAddress;
|
||||||
SNP_PRE_VALIDATED_RANGE OverlapRange;
|
SNP_PRE_VALIDATED_RANGE OverlapRange;
|
||||||
|
EFI_STATUS Status;
|
||||||
|
|
||||||
if (!MemEncryptSevSnpIsEnabled ()) {
|
if (!MemEncryptSevSnpIsEnabled ()) {
|
||||||
return;
|
return;
|
||||||
|
@ -77,6 +81,24 @@ MemEncryptSevSnpPreValidateSystemRam (
|
||||||
|
|
||||||
EndAddress = BaseAddress + EFI_PAGES_TO_SIZE (NumPages);
|
EndAddress = BaseAddress + EFI_PAGES_TO_SIZE (NumPages);
|
||||||
|
|
||||||
|
//
|
||||||
|
// The page table used in PEI can address up to 4GB memory. If we are asked to
|
||||||
|
// validate a range above the 4GB, then create an identity mapping so that the
|
||||||
|
// PVALIDATE instruction can execute correctly. If the page table entry is not
|
||||||
|
// present then PVALIDATE will #GP.
|
||||||
|
//
|
||||||
|
if (BaseAddress >= SIZE_4GB) {
|
||||||
|
Status = InternalMemEncryptSevCreateIdentityMap1G (
|
||||||
|
0,
|
||||||
|
BaseAddress,
|
||||||
|
EFI_PAGES_TO_SIZE (NumPages)
|
||||||
|
);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
ASSERT (FALSE);
|
||||||
|
CpuDeadLoop ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
while (BaseAddress < EndAddress) {
|
while (BaseAddress < EndAddress) {
|
||||||
//
|
//
|
||||||
// Check if the range overlaps with the pre-validated ranges.
|
// Check if the range overlaps with the pre-validated ranges.
|
||||||
|
|
|
@ -144,4 +144,28 @@ InternalMemEncryptSevClearMmioPageEncMask (
|
||||||
IN UINTN Length
|
IN UINTN Length
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Create 1GB identity mapping for the specified virtual address range.
|
||||||
|
|
||||||
|
The function is preliminary used by the SEV-SNP page state change
|
||||||
|
APIs to build the page table required before issuing the PVALIDATE
|
||||||
|
instruction. The function must be removed after the EDK2 core is
|
||||||
|
enhanced to do the lazy validation.
|
||||||
|
|
||||||
|
@param[in] Cr3BaseAddress Cr3 Base Address (if zero then use
|
||||||
|
current CR3)
|
||||||
|
@param[in] VirtualAddress Virtual address
|
||||||
|
@param[in] Length Length of virtual address range
|
||||||
|
|
||||||
|
@retval RETURN_INVALID_PARAMETER Number of pages is zero.
|
||||||
|
|
||||||
|
**/
|
||||||
|
RETURN_STATUS
|
||||||
|
EFIAPI
|
||||||
|
InternalMemEncryptSevCreateIdentityMap1G (
|
||||||
|
IN PHYSICAL_ADDRESS Cr3BaseAddress,
|
||||||
|
IN PHYSICAL_ADDRESS PhysicalAddress,
|
||||||
|
IN UINTN Length
|
||||||
|
);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue