mirror of https://github.com/acidanthera/audk.git
UefiCpuPkg/CpuMpPei: Use CpuPageTableLib to set memory attribute.
Currently, there are code to set memory attribute in CpuMpPei module. However, the code doesn't handle the case of 5 level paging. Use the CpuPageTableLib to set memory attribute for two purpose: 1. Add 5 level paging support 2. Clean up code Reviewed-by: Ray Ni <ray.ni@intel.com> Cc: Rahul Kumar <rahul1.kumar@intel.com> Cc: Gerd Hoffmann <kraxel@redhat.com> Cc: Laszlo Ersek <lersek@redhat.com> Signed-off-by: Zhiguang Liu <zhiguang.liu@intel.com>
This commit is contained in:
parent
02d6f39bd5
commit
7e18c9a788
|
@ -15,50 +15,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
|
|||
#include <Guid/MigratedFvInfo.h>
|
||||
|
||||
#include "CpuMpPei.h"
|
||||
|
||||
#define IA32_PG_P BIT0
|
||||
#define IA32_PG_RW BIT1
|
||||
#define IA32_PG_U BIT2
|
||||
#define IA32_PG_A BIT5
|
||||
#define IA32_PG_D BIT6
|
||||
#define IA32_PG_PS BIT7
|
||||
#define IA32_PG_NX BIT63
|
||||
|
||||
#define PAGE_ATTRIBUTE_BITS (IA32_PG_RW | IA32_PG_P)
|
||||
#define PAGE_PROGATE_BITS (IA32_PG_D | IA32_PG_A | IA32_PG_NX | IA32_PG_U | \
|
||||
PAGE_ATTRIBUTE_BITS)
|
||||
|
||||
#define PAGING_PAE_INDEX_MASK 0x1FF
|
||||
#define PAGING_4K_ADDRESS_MASK_64 0x000FFFFFFFFFF000ull
|
||||
#define PAGING_2M_ADDRESS_MASK_64 0x000FFFFFFFE00000ull
|
||||
#define PAGING_1G_ADDRESS_MASK_64 0x000FFFFFC0000000ull
|
||||
#define PAGING_512G_ADDRESS_MASK_64 0x000FFF8000000000ull
|
||||
|
||||
typedef enum {
|
||||
PageNone = 0,
|
||||
PageMin = 1,
|
||||
Page4K = PageMin,
|
||||
Page2M = 2,
|
||||
Page1G = 3,
|
||||
Page512G = 4,
|
||||
PageMax = Page512G
|
||||
} PAGE_ATTRIBUTE;
|
||||
|
||||
typedef struct {
|
||||
PAGE_ATTRIBUTE Attribute;
|
||||
UINT64 Length;
|
||||
UINT64 AddressMask;
|
||||
UINTN AddressBitOffset;
|
||||
UINTN AddressBitLength;
|
||||
} PAGE_ATTRIBUTE_TABLE;
|
||||
|
||||
PAGE_ATTRIBUTE_TABLE mPageAttributeTable[] = {
|
||||
{ PageNone, 0, 0, 0, 0 },
|
||||
{ Page4K, SIZE_4KB, PAGING_4K_ADDRESS_MASK_64, 12, 9 },
|
||||
{ Page2M, SIZE_2MB, PAGING_2M_ADDRESS_MASK_64, 21, 9 },
|
||||
{ Page1G, SIZE_1GB, PAGING_1G_ADDRESS_MASK_64, 30, 9 },
|
||||
{ Page512G, SIZE_512GB, PAGING_512G_ADDRESS_MASK_64, 39, 9 },
|
||||
};
|
||||
|
||||
EFI_PEI_NOTIFY_DESCRIPTOR mPostMemNotifyList[] = {
|
||||
{
|
||||
|
@ -117,237 +74,101 @@ AllocatePageTableMemory (
|
|||
return Address;
|
||||
}
|
||||
|
||||
/**
|
||||
Get the type of top level page table.
|
||||
|
||||
@retval Page512G PML4 paging.
|
||||
@retval Page1G PAE paging.
|
||||
|
||||
**/
|
||||
PAGE_ATTRIBUTE
|
||||
GetPageTableTopLevelType (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
MSR_IA32_EFER_REGISTER MsrEfer;
|
||||
|
||||
MsrEfer.Uint64 = AsmReadMsr64 (MSR_CORE_IA32_EFER);
|
||||
|
||||
return (MsrEfer.Bits.LMA == 1) ? Page512G : Page1G;
|
||||
}
|
||||
|
||||
/**
|
||||
Return page table entry matching the address.
|
||||
|
||||
@param[in] Address The address to be checked.
|
||||
@param[out] PageAttributes The page attribute of the page entry.
|
||||
|
||||
@return The page entry.
|
||||
**/
|
||||
VOID *
|
||||
GetPageTableEntry (
|
||||
IN PHYSICAL_ADDRESS Address,
|
||||
OUT PAGE_ATTRIBUTE *PageAttribute
|
||||
)
|
||||
{
|
||||
INTN Level;
|
||||
UINTN Index;
|
||||
UINT64 *PageTable;
|
||||
UINT64 AddressEncMask;
|
||||
|
||||
AddressEncMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask);
|
||||
PageTable = (UINT64 *)(UINTN)(AsmReadCr3 () & PAGING_4K_ADDRESS_MASK_64);
|
||||
for (Level = (INTN)GetPageTableTopLevelType (); Level > 0; --Level) {
|
||||
Index = (UINTN)RShiftU64 (Address, mPageAttributeTable[Level].AddressBitOffset);
|
||||
Index &= PAGING_PAE_INDEX_MASK;
|
||||
|
||||
//
|
||||
// No mapping?
|
||||
//
|
||||
if (PageTable[Index] == 0) {
|
||||
*PageAttribute = PageNone;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//
|
||||
// Page memory?
|
||||
//
|
||||
if (((PageTable[Index] & IA32_PG_PS) != 0) || (Level == PageMin)) {
|
||||
*PageAttribute = (PAGE_ATTRIBUTE)Level;
|
||||
return &PageTable[Index];
|
||||
}
|
||||
|
||||
//
|
||||
// Page directory or table
|
||||
//
|
||||
PageTable = (UINT64 *)(UINTN)(PageTable[Index] &
|
||||
~AddressEncMask &
|
||||
PAGING_4K_ADDRESS_MASK_64);
|
||||
}
|
||||
|
||||
*PageAttribute = PageNone;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
This function splits one page entry to smaller page entries.
|
||||
|
||||
@param[in] PageEntry The page entry to be splitted.
|
||||
@param[in] PageAttribute The page attribute of the page entry.
|
||||
@param[in] SplitAttribute How to split the page entry.
|
||||
@param[in] Recursively Do the split recursively or not.
|
||||
|
||||
@retval RETURN_SUCCESS The page entry is splitted.
|
||||
@retval RETURN_INVALID_PARAMETER If target page attribute is invalid
|
||||
@retval RETURN_OUT_OF_RESOURCES No resource to split page entry.
|
||||
**/
|
||||
RETURN_STATUS
|
||||
SplitPage (
|
||||
IN UINT64 *PageEntry,
|
||||
IN PAGE_ATTRIBUTE PageAttribute,
|
||||
IN PAGE_ATTRIBUTE SplitAttribute,
|
||||
IN BOOLEAN Recursively
|
||||
)
|
||||
{
|
||||
UINT64 BaseAddress;
|
||||
UINT64 *NewPageEntry;
|
||||
UINTN Index;
|
||||
UINT64 AddressEncMask;
|
||||
PAGE_ATTRIBUTE SplitTo;
|
||||
|
||||
if ((SplitAttribute == PageNone) || (SplitAttribute >= PageAttribute)) {
|
||||
ASSERT (SplitAttribute != PageNone);
|
||||
ASSERT (SplitAttribute < PageAttribute);
|
||||
return RETURN_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
NewPageEntry = AllocatePageTableMemory (1);
|
||||
if (NewPageEntry == NULL) {
|
||||
ASSERT (NewPageEntry != NULL);
|
||||
return RETURN_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
//
|
||||
// One level down each step to achieve more compact page table.
|
||||
//
|
||||
SplitTo = PageAttribute - 1;
|
||||
AddressEncMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) &
|
||||
mPageAttributeTable[SplitTo].AddressMask;
|
||||
BaseAddress = *PageEntry &
|
||||
~PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) &
|
||||
mPageAttributeTable[PageAttribute].AddressMask;
|
||||
for (Index = 0; Index < SIZE_4KB / sizeof (UINT64); Index++) {
|
||||
NewPageEntry[Index] = BaseAddress | AddressEncMask |
|
||||
((*PageEntry) & PAGE_PROGATE_BITS);
|
||||
|
||||
if (SplitTo != PageMin) {
|
||||
NewPageEntry[Index] |= IA32_PG_PS;
|
||||
}
|
||||
|
||||
if (Recursively && (SplitTo > SplitAttribute)) {
|
||||
SplitPage (&NewPageEntry[Index], SplitTo, SplitAttribute, Recursively);
|
||||
}
|
||||
|
||||
BaseAddress += mPageAttributeTable[SplitTo].Length;
|
||||
}
|
||||
|
||||
(*PageEntry) = (UINT64)(UINTN)NewPageEntry | AddressEncMask | PAGE_ATTRIBUTE_BITS;
|
||||
|
||||
return RETURN_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
This function modifies the page attributes for the memory region specified
|
||||
by BaseAddress and Length from their current attributes to the attributes
|
||||
specified by Attributes.
|
||||
by BaseAddress and Length to not present.
|
||||
|
||||
Caller should make sure BaseAddress and Length is at page boundary.
|
||||
|
||||
@param[in] BaseAddress Start address of a memory region.
|
||||
@param[in] Length Size in bytes of the memory region.
|
||||
@param[in] Attributes Bit mask of attributes to modify.
|
||||
|
||||
@retval RETURN_SUCCESS The attributes were modified for the memory
|
||||
region.
|
||||
@retval RETURN_INVALID_PARAMETER Length is zero; or,
|
||||
Attributes specified an illegal combination
|
||||
of attributes that cannot be set together; or
|
||||
Addressis not 4KB aligned.
|
||||
@retval RETURN_SUCCESS The memory region is changed to not present.
|
||||
@retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify
|
||||
the attributes.
|
||||
@retval RETURN_UNSUPPORTED Cannot modify the attributes of given memory.
|
||||
|
||||
**/
|
||||
RETURN_STATUS
|
||||
EFIAPI
|
||||
ConvertMemoryPageAttributes (
|
||||
ConvertMemoryPageToNotPresent (
|
||||
IN PHYSICAL_ADDRESS BaseAddress,
|
||||
IN UINT64 Length,
|
||||
IN UINT64 Attributes
|
||||
IN UINT64 Length
|
||||
)
|
||||
{
|
||||
UINT64 *PageEntry;
|
||||
PAGE_ATTRIBUTE PageAttribute;
|
||||
RETURN_STATUS Status;
|
||||
EFI_PHYSICAL_ADDRESS MaximumAddress;
|
||||
EFI_STATUS Status;
|
||||
UINTN PageTable;
|
||||
EFI_PHYSICAL_ADDRESS Buffer;
|
||||
UINTN BufferSize;
|
||||
IA32_MAP_ATTRIBUTE MapAttribute;
|
||||
IA32_MAP_ATTRIBUTE MapMask;
|
||||
PAGING_MODE PagingMode;
|
||||
IA32_CR4 Cr4;
|
||||
BOOLEAN Page5LevelSupport;
|
||||
UINT32 RegEax;
|
||||
BOOLEAN Page1GSupport;
|
||||
CPUID_EXTENDED_CPU_SIG_EDX RegEdx;
|
||||
|
||||
if ((Length == 0) ||
|
||||
((BaseAddress & (SIZE_4KB - 1)) != 0) ||
|
||||
((Length & (SIZE_4KB - 1)) != 0))
|
||||
{
|
||||
ASSERT (Length > 0);
|
||||
ASSERT ((BaseAddress & (SIZE_4KB - 1)) == 0);
|
||||
ASSERT ((Length & (SIZE_4KB - 1)) == 0);
|
||||
if (sizeof (UINTN) == sizeof (UINT64)) {
|
||||
//
|
||||
// Check Page5Level Support or not.
|
||||
//
|
||||
Cr4.UintN = AsmReadCr4 ();
|
||||
Page5LevelSupport = (Cr4.Bits.LA57 ? TRUE : FALSE);
|
||||
|
||||
return RETURN_INVALID_PARAMETER;
|
||||
//
|
||||
// Check Page1G Support or not.
|
||||
//
|
||||
Page1GSupport = FALSE;
|
||||
AsmCpuid (CPUID_EXTENDED_FUNCTION, &RegEax, NULL, NULL, NULL);
|
||||
if (RegEax >= CPUID_EXTENDED_CPU_SIG) {
|
||||
AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, NULL, &RegEdx.Uint32);
|
||||
if (RegEdx.Bits.Page1GB != 0) {
|
||||
Page1GSupport = TRUE;
|
||||
}
|
||||
|
||||
MaximumAddress = (EFI_PHYSICAL_ADDRESS)MAX_UINT32;
|
||||
if ((BaseAddress > MaximumAddress) ||
|
||||
(Length > MaximumAddress) ||
|
||||
(BaseAddress > MaximumAddress - (Length - 1)))
|
||||
{
|
||||
return RETURN_UNSUPPORTED;
|
||||
}
|
||||
|
||||
//
|
||||
// Below logic is to check 2M/4K page to make sure we do not waste memory.
|
||||
// Decide Paging Mode according Page5LevelSupport & Page1GSupport.
|
||||
//
|
||||
while (Length != 0) {
|
||||
PageEntry = GetPageTableEntry (BaseAddress, &PageAttribute);
|
||||
if (PageEntry == NULL) {
|
||||
return RETURN_UNSUPPORTED;
|
||||
}
|
||||
|
||||
if (PageAttribute != Page4K) {
|
||||
Status = SplitPage (PageEntry, PageAttribute, Page4K, FALSE);
|
||||
if (RETURN_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Do it again until the page is 4K.
|
||||
//
|
||||
continue;
|
||||
}
|
||||
|
||||
//
|
||||
// Just take care of 'present' bit for Stack Guard.
|
||||
//
|
||||
if ((Attributes & IA32_PG_P) != 0) {
|
||||
*PageEntry |= (UINT64)IA32_PG_P;
|
||||
if (Page5LevelSupport) {
|
||||
PagingMode = Page1GSupport ? Paging5Level1GB : Paging5Level;
|
||||
} else {
|
||||
*PageEntry &= ~((UINT64)IA32_PG_P);
|
||||
PagingMode = Page1GSupport ? Paging4Level1GB : Paging4Level;
|
||||
}
|
||||
} else {
|
||||
PagingMode = PagingPae;
|
||||
}
|
||||
|
||||
MapAttribute.Uint64 = 0;
|
||||
MapMask.Uint64 = 0;
|
||||
MapMask.Bits.Present = 1;
|
||||
PageTable = AsmReadCr3 () & PAGING_4K_ADDRESS_MASK_64;
|
||||
BufferSize = 0;
|
||||
|
||||
//
|
||||
// Convert success, move to next
|
||||
// Get required buffer size for the pagetable that will be created.
|
||||
//
|
||||
BaseAddress += SIZE_4KB;
|
||||
Length -= SIZE_4KB;
|
||||
Status = PageTableMap (&PageTable, PagingMode, 0, &BufferSize, BaseAddress, Length, &MapAttribute, &MapMask, NULL);
|
||||
if (Status == EFI_BUFFER_TOO_SMALL) {
|
||||
//
|
||||
// Allocate required Buffer.
|
||||
//
|
||||
Status = PeiServicesAllocatePages (
|
||||
EfiBootServicesData,
|
||||
EFI_SIZE_TO_PAGES (BufferSize),
|
||||
&Buffer
|
||||
);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
return RETURN_SUCCESS;
|
||||
Status = PageTableMap (&PageTable, PagingMode, (VOID *)(UINTN)Buffer, &BufferSize, BaseAddress, Length, &MapAttribute, &MapMask, NULL);
|
||||
}
|
||||
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
AsmWriteCr3 (PageTable);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -516,7 +337,7 @@ SetupStackGuardPage (
|
|||
//
|
||||
// Set Guard page at stack base address.
|
||||
//
|
||||
ConvertMemoryPageAttributes (StackBase, EFI_PAGE_SIZE, 0);
|
||||
ConvertMemoryPageToNotPresent (StackBase, EFI_PAGE_SIZE);
|
||||
DEBUG ((
|
||||
DEBUG_INFO,
|
||||
"Stack Guard set at %lx [cpu%lu]!\n",
|
||||
|
@ -599,7 +420,7 @@ MemoryDiscoveredPpiNotifyCallback (
|
|||
// Enable #PF exception, so if the code access SPI after disable NEM, it will generate
|
||||
// the exception to avoid potential vulnerability.
|
||||
//
|
||||
ConvertMemoryPageAttributes (MigratedFvInfo->FvOrgBase, MigratedFvInfo->FvLength, 0);
|
||||
ConvertMemoryPageToNotPresent (MigratedFvInfo->FvOrgBase, MigratedFvInfo->FvLength);
|
||||
|
||||
Hob.Raw = GET_NEXT_HOB (Hob);
|
||||
Hob.Raw = GetNextGuidHob (&gEdkiiMigratedFvInfoGuid, Hob.Raw);
|
||||
|
|
Loading…
Reference in New Issue