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:
Brijesh Singh via groups.io
2021-12-09 11:27:45 +08:00
committed by mergify[bot]
parent 11b15336f0
commit d39f8d88ec
3 changed files with 160 additions and 0 deletions

View File

@ -536,6 +536,120 @@ EnableReadOnlyPageWriteProtect (
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
region specified by PhysicalAddress and Length from the current page table