AsmWriteCr0 (AsmReadCr0 () | BIT16);\r
}\r
\r
+RETURN_STATUS\r
+EFIAPI\r
+InternalMemEncryptSevCreateIdentityMap1G (\r
+ IN PHYSICAL_ADDRESS Cr3BaseAddress,\r
+ IN PHYSICAL_ADDRESS PhysicalAddress,\r
+ IN UINTN Length\r
+ )\r
+{\r
+ PAGE_MAP_AND_DIRECTORY_POINTER *PageMapLevel4Entry;\r
+ PAGE_TABLE_1G_ENTRY *PageDirectory1GEntry;\r
+ UINT64 PgTableMask;\r
+ UINT64 AddressEncMask;\r
+ BOOLEAN IsWpEnabled;\r
+ RETURN_STATUS Status;\r
+\r
+ //\r
+ // Set PageMapLevel4Entry to suppress incorrect compiler/analyzer warnings.\r
+ //\r
+ PageMapLevel4Entry = NULL;\r
+\r
+ DEBUG ((\r
+ DEBUG_VERBOSE,\r
+ "%a:%a: Cr3Base=0x%Lx Physical=0x%Lx Length=0x%Lx\n",\r
+ gEfiCallerBaseName,\r
+ __FUNCTION__,\r
+ Cr3BaseAddress,\r
+ PhysicalAddress,\r
+ (UINT64)Length\r
+ ));\r
+\r
+ if (Length == 0) {\r
+ return RETURN_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Check if we have a valid memory encryption mask\r
+ //\r
+ AddressEncMask = InternalGetMemEncryptionAddressMask ();\r
+ if (!AddressEncMask) {\r
+ return RETURN_ACCESS_DENIED;\r
+ }\r
+\r
+ PgTableMask = AddressEncMask | EFI_PAGE_MASK;\r
+\r
+ //\r
+ // Make sure that the page table is changeable.\r
+ //\r
+ IsWpEnabled = IsReadOnlyPageWriteProtected ();\r
+ if (IsWpEnabled) {\r
+ DisableReadOnlyPageWriteProtect ();\r
+ }\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ while (Length) {\r
+ //\r
+ // If Cr3BaseAddress is not specified then read the current CR3\r
+ //\r
+ if (Cr3BaseAddress == 0) {\r
+ Cr3BaseAddress = AsmReadCr3 ();\r
+ }\r
+\r
+ PageMapLevel4Entry = (VOID *)(Cr3BaseAddress & ~PgTableMask);\r
+ PageMapLevel4Entry += PML4_OFFSET (PhysicalAddress);\r
+ if (!PageMapLevel4Entry->Bits.Present) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "%a:%a: bad PML4 for Physical=0x%Lx\n",\r
+ gEfiCallerBaseName,\r
+ __FUNCTION__,\r
+ PhysicalAddress\r
+ ));\r
+ Status = RETURN_NO_MAPPING;\r
+ goto Done;\r
+ }\r
+\r
+ PageDirectory1GEntry = (VOID *)(\r
+ (PageMapLevel4Entry->Bits.PageTableBaseAddress <<\r
+ 12) & ~PgTableMask\r
+ );\r
+ PageDirectory1GEntry += PDP_OFFSET (PhysicalAddress);\r
+ if (!PageDirectory1GEntry->Bits.Present) {\r
+ PageDirectory1GEntry->Bits.Present = 1;\r
+ PageDirectory1GEntry->Bits.MustBe1 = 1;\r
+ PageDirectory1GEntry->Bits.MustBeZero = 0;\r
+ PageDirectory1GEntry->Bits.ReadWrite = 1;\r
+ PageDirectory1GEntry->Uint64 |= (UINT64)PhysicalAddress | AddressEncMask;\r
+ }\r
+\r
+ if (Length <= BIT30) {\r
+ Length = 0;\r
+ } else {\r
+ Length -= BIT30;\r
+ }\r
+\r
+ PhysicalAddress += BIT30;\r
+ }\r
+\r
+ //\r
+ // Flush TLB\r
+ //\r
+ CpuFlushTlb ();\r
+\r
+Done:\r
+ //\r
+ // Restore page table write protection, if any.\r
+ //\r
+ if (IsWpEnabled) {\r
+ EnableReadOnlyPageWriteProtect ();\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
/**\r
This function either sets or clears memory encryption bit for the memory\r
region specified by PhysicalAddress and Length from the current page table\r
\r
#include <Uefi/UefiBaseType.h>\r
#include <Library/BaseLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/DebugLib.h>\r
#include <Library/MemEncryptSevLib.h>\r
\r
#include "SnpPageStateChange.h"\r
+#include "VirtualMemory.h"\r
\r
typedef struct {\r
UINT64 StartAddress;\r
{\r
PHYSICAL_ADDRESS EndAddress;\r
SNP_PRE_VALIDATED_RANGE OverlapRange;\r
+ EFI_STATUS Status;\r
\r
if (!MemEncryptSevSnpIsEnabled ()) {\r
return;\r
\r
EndAddress = BaseAddress + EFI_PAGES_TO_SIZE (NumPages);\r
\r
+ //\r
+ // The page table used in PEI can address up to 4GB memory. If we are asked to\r
+ // validate a range above the 4GB, then create an identity mapping so that the\r
+ // PVALIDATE instruction can execute correctly. If the page table entry is not\r
+ // present then PVALIDATE will #GP.\r
+ //\r
+ if (BaseAddress >= SIZE_4GB) {\r
+ Status = InternalMemEncryptSevCreateIdentityMap1G (\r
+ 0,\r
+ BaseAddress,\r
+ EFI_PAGES_TO_SIZE (NumPages)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ASSERT (FALSE);\r
+ CpuDeadLoop ();\r
+ }\r
+ }\r
+\r
while (BaseAddress < EndAddress) {\r
//\r
// Check if the range overlaps with the pre-validated ranges.\r
IN UINTN Length\r
);\r
\r
+/**\r
+ Create 1GB identity mapping for the specified virtual address range.\r
+\r
+ The function is preliminary used by the SEV-SNP page state change\r
+ APIs to build the page table required before issuing the PVALIDATE\r
+ instruction. The function must be removed after the EDK2 core is\r
+ enhanced to do the lazy validation.\r
+\r
+ @param[in] Cr3BaseAddress Cr3 Base Address (if zero then use\r
+ current CR3)\r
+ @param[in] VirtualAddress Virtual address\r
+ @param[in] Length Length of virtual address range\r
+\r
+ @retval RETURN_INVALID_PARAMETER Number of pages is zero.\r
+\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+InternalMemEncryptSevCreateIdentityMap1G (\r
+ IN PHYSICAL_ADDRESS Cr3BaseAddress,\r
+ IN PHYSICAL_ADDRESS PhysicalAddress,\r
+ IN UINTN Length\r
+ );\r
+\r
#endif\r