UefiCpuPkg/PiSmmCpu: Enable 5 level paging when CPU supports
REF:https://bugzilla.tianocore.org/show_bug.cgi?id=1946 The patch changes SMM environment to use 5 level paging when CPU supports it. Signed-off-by: Ray Ni <ray.ni@intel.com> Cc: Eric Dong <eric.dong@intel.com> Regression-tested-by: Laszlo Ersek <lersek@redhat.com> Reviewed-by: Eric Dong <eric.dong@intel.com>
This commit is contained in:
@@ -534,43 +534,78 @@ InitPaging (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
UINT64 Pml5Entry;
|
||||
UINT64 Pml4Entry;
|
||||
UINT64 *Pml5;
|
||||
UINT64 *Pml4;
|
||||
UINT64 *Pdpt;
|
||||
UINT64 *Pd;
|
||||
UINT64 *Pt;
|
||||
UINTN Address;
|
||||
UINTN Pml5Index;
|
||||
UINTN Pml4Index;
|
||||
UINTN PdptIndex;
|
||||
UINTN PdIndex;
|
||||
UINTN PtIndex;
|
||||
UINTN NumberOfPdptEntries;
|
||||
UINTN NumberOfPml4Entries;
|
||||
UINTN NumberOfPml5Entries;
|
||||
UINTN SizeOfMemorySpace;
|
||||
BOOLEAN Nx;
|
||||
IA32_CR4 Cr4;
|
||||
BOOLEAN Enable5LevelPaging;
|
||||
|
||||
Cr4.UintN = AsmReadCr4 ();
|
||||
Enable5LevelPaging = (BOOLEAN) (Cr4.Bits.LA57 == 1);
|
||||
|
||||
if (sizeof (UINTN) == sizeof (UINT64)) {
|
||||
Pml4 = (UINT64*)(UINTN)mSmmProfileCr3;
|
||||
if (!Enable5LevelPaging) {
|
||||
Pml5Entry = (UINTN) mSmmProfileCr3 | IA32_PG_P;
|
||||
Pml5 = &Pml5Entry;
|
||||
} else {
|
||||
Pml5 = (UINT64*) (UINTN) mSmmProfileCr3;
|
||||
}
|
||||
SizeOfMemorySpace = HighBitSet64 (gPhyMask) + 1;
|
||||
//
|
||||
// Calculate the table entries of PML4E and PDPTE.
|
||||
//
|
||||
if (SizeOfMemorySpace <= 39 ) {
|
||||
NumberOfPml4Entries = 1;
|
||||
NumberOfPdptEntries = (UINT32)LShiftU64 (1, (SizeOfMemorySpace - 30));
|
||||
} else {
|
||||
NumberOfPml4Entries = (UINT32)LShiftU64 (1, (SizeOfMemorySpace - 39));
|
||||
NumberOfPdptEntries = 512;
|
||||
NumberOfPml5Entries = 1;
|
||||
if (SizeOfMemorySpace > 48) {
|
||||
NumberOfPml5Entries = (UINTN) LShiftU64 (1, SizeOfMemorySpace - 48);
|
||||
SizeOfMemorySpace = 48;
|
||||
}
|
||||
} else {
|
||||
|
||||
NumberOfPml4Entries = 1;
|
||||
if (SizeOfMemorySpace > 39) {
|
||||
NumberOfPml4Entries = (UINTN) LShiftU64 (1, SizeOfMemorySpace - 39);
|
||||
SizeOfMemorySpace = 39;
|
||||
}
|
||||
|
||||
NumberOfPdptEntries = 1;
|
||||
ASSERT (SizeOfMemorySpace > 30);
|
||||
NumberOfPdptEntries = (UINTN) LShiftU64 (1, SizeOfMemorySpace - 30);
|
||||
} else {
|
||||
Pml4Entry = (UINTN) mSmmProfileCr3 | IA32_PG_P;
|
||||
Pml4 = &Pml4Entry;
|
||||
Pml5Entry = (UINTN) Pml4 | IA32_PG_P;
|
||||
Pml5 = &Pml5Entry;
|
||||
NumberOfPml5Entries = 1;
|
||||
NumberOfPml4Entries = 1;
|
||||
NumberOfPdptEntries = 4;
|
||||
}
|
||||
|
||||
//
|
||||
// Go through page table and change 2MB-page into 4KB-page.
|
||||
//
|
||||
for (Pml4Index = 0; Pml4Index < NumberOfPml4Entries; Pml4Index++) {
|
||||
if (sizeof (UINTN) == sizeof (UINT64)) {
|
||||
for (Pml5Index = 0; Pml5Index < NumberOfPml5Entries; Pml5Index++) {
|
||||
if ((Pml5[Pml5Index] & IA32_PG_P) == 0) {
|
||||
//
|
||||
// If PML5 entry does not exist, skip it
|
||||
//
|
||||
continue;
|
||||
}
|
||||
Pml4 = (UINT64 *) (UINTN) (Pml5[Pml5Index] & PHYSICAL_ADDRESS_MASK);
|
||||
for (Pml4Index = 0; Pml4Index < NumberOfPml4Entries; Pml4Index++) {
|
||||
if ((Pml4[Pml4Index] & IA32_PG_P) == 0) {
|
||||
//
|
||||
// If PML4 entry does not exist, skip it
|
||||
@@ -578,63 +613,76 @@ InitPaging (
|
||||
continue;
|
||||
}
|
||||
Pdpt = (UINT64 *)(UINTN)(Pml4[Pml4Index] & ~mAddressEncMask & PHYSICAL_ADDRESS_MASK);
|
||||
} else {
|
||||
Pdpt = (UINT64*)(UINTN)mSmmProfileCr3;
|
||||
}
|
||||
for (PdptIndex = 0; PdptIndex < NumberOfPdptEntries; PdptIndex++, Pdpt++) {
|
||||
if ((*Pdpt & IA32_PG_P) == 0) {
|
||||
//
|
||||
// If PDPT entry does not exist, skip it
|
||||
//
|
||||
continue;
|
||||
}
|
||||
if ((*Pdpt & IA32_PG_PS) != 0) {
|
||||
//
|
||||
// This is 1G entry, skip it
|
||||
//
|
||||
continue;
|
||||
}
|
||||
Pd = (UINT64 *)(UINTN)(*Pdpt & ~mAddressEncMask & PHYSICAL_ADDRESS_MASK);
|
||||
if (Pd == 0) {
|
||||
continue;
|
||||
}
|
||||
for (PdIndex = 0; PdIndex < SIZE_4KB / sizeof (*Pd); PdIndex++, Pd++) {
|
||||
if ((*Pd & IA32_PG_P) == 0) {
|
||||
for (PdptIndex = 0; PdptIndex < NumberOfPdptEntries; PdptIndex++, Pdpt++) {
|
||||
if ((*Pdpt & IA32_PG_P) == 0) {
|
||||
//
|
||||
// If PD entry does not exist, skip it
|
||||
// If PDPT entry does not exist, skip it
|
||||
//
|
||||
continue;
|
||||
}
|
||||
Address = (((PdptIndex << 9) + PdIndex) << 21);
|
||||
|
||||
//
|
||||
// If it is 2M page, check IsAddressSplit()
|
||||
//
|
||||
if (((*Pd & IA32_PG_PS) != 0) && IsAddressSplit (Address)) {
|
||||
if ((*Pdpt & IA32_PG_PS) != 0) {
|
||||
//
|
||||
// Based on current page table, create 4KB page table for split area.
|
||||
// This is 1G entry, skip it
|
||||
//
|
||||
ASSERT (Address == (*Pd & PHYSICAL_ADDRESS_MASK));
|
||||
continue;
|
||||
}
|
||||
Pd = (UINT64 *)(UINTN)(*Pdpt & ~mAddressEncMask & PHYSICAL_ADDRESS_MASK);
|
||||
if (Pd == 0) {
|
||||
continue;
|
||||
}
|
||||
for (PdIndex = 0; PdIndex < SIZE_4KB / sizeof (*Pd); PdIndex++, Pd++) {
|
||||
if ((*Pd & IA32_PG_P) == 0) {
|
||||
//
|
||||
// If PD entry does not exist, skip it
|
||||
//
|
||||
continue;
|
||||
}
|
||||
Address = (UINTN) LShiftU64 (
|
||||
LShiftU64 (
|
||||
LShiftU64 ((Pml5Index << 9) + Pml4Index, 9) + PdptIndex,
|
||||
9
|
||||
) + PdIndex,
|
||||
21
|
||||
);
|
||||
|
||||
Pt = AllocatePageTableMemory (1);
|
||||
ASSERT (Pt != NULL);
|
||||
//
|
||||
// If it is 2M page, check IsAddressSplit()
|
||||
//
|
||||
if (((*Pd & IA32_PG_PS) != 0) && IsAddressSplit (Address)) {
|
||||
//
|
||||
// Based on current page table, create 4KB page table for split area.
|
||||
//
|
||||
ASSERT (Address == (*Pd & PHYSICAL_ADDRESS_MASK));
|
||||
|
||||
// Split it
|
||||
for (PtIndex = 0; PtIndex < SIZE_4KB / sizeof(*Pt); PtIndex++) {
|
||||
Pt[PtIndex] = Address + ((PtIndex << 12) | mAddressEncMask | PAGE_ATTRIBUTE_BITS);
|
||||
} // end for PT
|
||||
*Pd = (UINT64)(UINTN)Pt | mAddressEncMask | PAGE_ATTRIBUTE_BITS;
|
||||
} // end if IsAddressSplit
|
||||
} // end for PD
|
||||
} // end for PDPT
|
||||
} // end for PML4
|
||||
Pt = AllocatePageTableMemory (1);
|
||||
ASSERT (Pt != NULL);
|
||||
|
||||
*Pd = (UINTN) Pt | IA32_PG_RW | IA32_PG_P;
|
||||
|
||||
// Split it
|
||||
for (PtIndex = 0; PtIndex < SIZE_4KB / sizeof(*Pt); PtIndex++, Pt++) {
|
||||
*Pt = Address + ((PtIndex << 12) | mAddressEncMask | PAGE_ATTRIBUTE_BITS);
|
||||
} // end for PT
|
||||
*Pd = (UINT64)(UINTN)Pt | mAddressEncMask | PAGE_ATTRIBUTE_BITS;
|
||||
} // end if IsAddressSplit
|
||||
} // end for PD
|
||||
} // end for PDPT
|
||||
} // end for PML4
|
||||
} // end for PML5
|
||||
|
||||
//
|
||||
// Go through page table and set several page table entries to absent or execute-disable.
|
||||
//
|
||||
DEBUG ((EFI_D_INFO, "Patch page table start ...\n"));
|
||||
for (Pml4Index = 0; Pml4Index < NumberOfPml4Entries; Pml4Index++) {
|
||||
if (sizeof (UINTN) == sizeof (UINT64)) {
|
||||
for (Pml5Index = 0; Pml5Index < NumberOfPml5Entries; Pml5Index++) {
|
||||
if ((Pml5[Pml5Index] & IA32_PG_P) == 0) {
|
||||
//
|
||||
// If PML5 entry does not exist, skip it
|
||||
//
|
||||
continue;
|
||||
}
|
||||
Pml4 = (UINT64 *) (UINTN) (Pml5[Pml5Index] & PHYSICAL_ADDRESS_MASK);
|
||||
for (Pml4Index = 0; Pml4Index < NumberOfPml4Entries; Pml4Index++) {
|
||||
if ((Pml4[Pml4Index] & IA32_PG_P) == 0) {
|
||||
//
|
||||
// If PML4 entry does not exist, skip it
|
||||
@@ -642,69 +690,73 @@ InitPaging (
|
||||
continue;
|
||||
}
|
||||
Pdpt = (UINT64 *)(UINTN)(Pml4[Pml4Index] & ~mAddressEncMask & PHYSICAL_ADDRESS_MASK);
|
||||
} else {
|
||||
Pdpt = (UINT64*)(UINTN)mSmmProfileCr3;
|
||||
}
|
||||
for (PdptIndex = 0; PdptIndex < NumberOfPdptEntries; PdptIndex++, Pdpt++) {
|
||||
if ((*Pdpt & IA32_PG_P) == 0) {
|
||||
//
|
||||
// If PDPT entry does not exist, skip it
|
||||
//
|
||||
continue;
|
||||
}
|
||||
if ((*Pdpt & IA32_PG_PS) != 0) {
|
||||
//
|
||||
// This is 1G entry, set NX bit and skip it
|
||||
//
|
||||
if (mXdSupported) {
|
||||
*Pdpt = *Pdpt | IA32_PG_NX;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
Pd = (UINT64 *)(UINTN)(*Pdpt & ~mAddressEncMask & PHYSICAL_ADDRESS_MASK);
|
||||
if (Pd == 0) {
|
||||
continue;
|
||||
}
|
||||
for (PdIndex = 0; PdIndex < SIZE_4KB / sizeof (*Pd); PdIndex++, Pd++) {
|
||||
if ((*Pd & IA32_PG_P) == 0) {
|
||||
for (PdptIndex = 0; PdptIndex < NumberOfPdptEntries; PdptIndex++, Pdpt++) {
|
||||
if ((*Pdpt & IA32_PG_P) == 0) {
|
||||
//
|
||||
// If PD entry does not exist, skip it
|
||||
// If PDPT entry does not exist, skip it
|
||||
//
|
||||
continue;
|
||||
}
|
||||
Address = (((PdptIndex << 9) + PdIndex) << 21);
|
||||
|
||||
if ((*Pd & IA32_PG_PS) != 0) {
|
||||
// 2MB page
|
||||
|
||||
if (!IsAddressValid (Address, &Nx)) {
|
||||
//
|
||||
// Patch to remove Present flag and RW flag
|
||||
//
|
||||
*Pd = *Pd & (INTN)(INT32)(~PAGE_ATTRIBUTE_BITS);
|
||||
if ((*Pdpt & IA32_PG_PS) != 0) {
|
||||
//
|
||||
// This is 1G entry, set NX bit and skip it
|
||||
//
|
||||
if (mXdSupported) {
|
||||
*Pdpt = *Pdpt | IA32_PG_NX;
|
||||
}
|
||||
if (Nx && mXdSupported) {
|
||||
*Pd = *Pd | IA32_PG_NX;
|
||||
}
|
||||
} else {
|
||||
// 4KB page
|
||||
Pt = (UINT64 *)(UINTN)(*Pd & ~mAddressEncMask & PHYSICAL_ADDRESS_MASK);
|
||||
if (Pt == 0) {
|
||||
continue;
|
||||
}
|
||||
Pd = (UINT64 *)(UINTN)(*Pdpt & ~mAddressEncMask & PHYSICAL_ADDRESS_MASK);
|
||||
if (Pd == 0) {
|
||||
continue;
|
||||
}
|
||||
for (PdIndex = 0; PdIndex < SIZE_4KB / sizeof (*Pd); PdIndex++, Pd++) {
|
||||
if ((*Pd & IA32_PG_P) == 0) {
|
||||
//
|
||||
// If PD entry does not exist, skip it
|
||||
//
|
||||
continue;
|
||||
}
|
||||
for (PtIndex = 0; PtIndex < SIZE_4KB / sizeof(*Pt); PtIndex++, Pt++) {
|
||||
Address = (UINTN) LShiftU64 (
|
||||
LShiftU64 (
|
||||
LShiftU64 ((Pml5Index << 9) + Pml4Index, 9) + PdptIndex,
|
||||
9
|
||||
) + PdIndex,
|
||||
21
|
||||
);
|
||||
|
||||
if ((*Pd & IA32_PG_PS) != 0) {
|
||||
// 2MB page
|
||||
|
||||
if (!IsAddressValid (Address, &Nx)) {
|
||||
*Pt = *Pt & (INTN)(INT32)(~PAGE_ATTRIBUTE_BITS);
|
||||
//
|
||||
// Patch to remove Present flag and RW flag
|
||||
//
|
||||
*Pd = *Pd & (INTN)(INT32)(~PAGE_ATTRIBUTE_BITS);
|
||||
}
|
||||
if (Nx && mXdSupported) {
|
||||
*Pt = *Pt | IA32_PG_NX;
|
||||
*Pd = *Pd | IA32_PG_NX;
|
||||
}
|
||||
Address += SIZE_4KB;
|
||||
} // end for PT
|
||||
} // end if PS
|
||||
} // end for PD
|
||||
} // end for PDPT
|
||||
} // end for PML4
|
||||
} else {
|
||||
// 4KB page
|
||||
Pt = (UINT64 *)(UINTN)(*Pd & ~mAddressEncMask & PHYSICAL_ADDRESS_MASK);
|
||||
if (Pt == 0) {
|
||||
continue;
|
||||
}
|
||||
for (PtIndex = 0; PtIndex < SIZE_4KB / sizeof(*Pt); PtIndex++, Pt++) {
|
||||
if (!IsAddressValid (Address, &Nx)) {
|
||||
*Pt = *Pt & (INTN)(INT32)(~PAGE_ATTRIBUTE_BITS);
|
||||
}
|
||||
if (Nx && mXdSupported) {
|
||||
*Pt = *Pt | IA32_PG_NX;
|
||||
}
|
||||
Address += SIZE_4KB;
|
||||
} // end for PT
|
||||
} // end if PS
|
||||
} // end for PD
|
||||
} // end for PDPT
|
||||
} // end for PML4
|
||||
} // end for PML5
|
||||
|
||||
//
|
||||
// Flush TLB
|
||||
@@ -1156,6 +1208,20 @@ RestorePageTableBelow4G (
|
||||
{
|
||||
UINTN PTIndex;
|
||||
UINTN PFIndex;
|
||||
IA32_CR4 Cr4;
|
||||
BOOLEAN Enable5LevelPaging;
|
||||
|
||||
Cr4.UintN = AsmReadCr4 ();
|
||||
Enable5LevelPaging = (BOOLEAN) (Cr4.Bits.LA57 == 1);
|
||||
|
||||
//
|
||||
// PML5
|
||||
//
|
||||
if (Enable5LevelPaging) {
|
||||
PTIndex = (UINTN)BitFieldRead64 (PFAddress, 48, 56);
|
||||
ASSERT (PageTable[PTIndex] != 0);
|
||||
PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & PHYSICAL_ADDRESS_MASK);
|
||||
}
|
||||
|
||||
//
|
||||
// PML4
|
||||
|
Reference in New Issue
Block a user