Skip to content

Commit

Permalink
UefiCpuPkg/PiSmmCpu: Enable 5 level paging when CPU supports
Browse files Browse the repository at this point in the history
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>
(cherry picked from commit 7365eb2)
  • Loading branch information
niruiyu committed Jul 12, 2019
1 parent 6e5a33d commit 4eee0cc
Show file tree
Hide file tree
Showing 5 changed files with 561 additions and 300 deletions.
20 changes: 19 additions & 1 deletion UefiCpuPkg/PiSmmCpuDxeSmm/SmmCpuMemoryManagement.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,18 +125,36 @@ GetPageTableEntry (
UINTN Index2;
UINTN Index3;
UINTN Index4;
UINTN Index5;
UINT64 *L1PageTable;
UINT64 *L2PageTable;
UINT64 *L3PageTable;
UINT64 *L4PageTable;
UINT64 *L5PageTable;
IA32_CR4 Cr4;
BOOLEAN Enable5LevelPaging;

Index5 = ((UINTN)RShiftU64 (Address, 48)) & PAGING_PAE_INDEX_MASK;
Index4 = ((UINTN)RShiftU64 (Address, 39)) & PAGING_PAE_INDEX_MASK;
Index3 = ((UINTN)Address >> 30) & PAGING_PAE_INDEX_MASK;
Index2 = ((UINTN)Address >> 21) & PAGING_PAE_INDEX_MASK;
Index1 = ((UINTN)Address >> 12) & PAGING_PAE_INDEX_MASK;

Cr4.UintN = AsmReadCr4 ();
Enable5LevelPaging = (BOOLEAN) (Cr4.Bits.LA57 == 1);

if (sizeof(UINTN) == sizeof(UINT64)) {
L4PageTable = (UINT64 *)GetPageTableBase ();
if (Enable5LevelPaging) {
L5PageTable = (UINT64 *)GetPageTableBase ();
if (L5PageTable[Index5] == 0) {
*PageAttribute = PageNone;
return NULL;
}

L4PageTable = (UINT64 *)(UINTN)(L5PageTable[Index5] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64);
} else {
L4PageTable = (UINT64 *)GetPageTableBase ();
}
if (L4PageTable[Index4] == 0) {
*PageAttribute = PageNone;
return NULL;
Expand Down
272 changes: 169 additions & 103 deletions UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.c
Original file line number Diff line number Diff line change
Expand Up @@ -534,177 +534,229 @@ 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
//
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 PDPT entry does not exist, skip it
//
continue;
}
if ((*Pdpt & IA32_PG_PS) != 0) {
//
// If PD entry does not exist, skip it
// This is 1G entry, skip it
//
continue;
}
Address = (((PdptIndex << 9) + PdIndex) << 21);
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
);

//
// 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.
// If it is 2M page, check IsAddressSplit()
//
ASSERT (Address == (*Pd & PHYSICAL_ADDRESS_MASK));
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));

Pt = AllocatePageTableMemory (1);
ASSERT (Pt != NULL);

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[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
// 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
//
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;
for (PdptIndex = 0; PdptIndex < NumberOfPdptEntries; PdptIndex++, Pdpt++) {
if ((*Pdpt & IA32_PG_P) == 0) {
//
// If PDPT entry does not exist, skip it
//
continue;
}
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 ((*Pdpt & IA32_PG_PS) != 0) {
//
// If PD entry does not exist, skip it
// This is 1G entry, set NX bit and skip it
//
if (mXdSupported) {
*Pdpt = *Pdpt | IA32_PG_NX;
}
continue;
}
Address = (((PdptIndex << 9) + PdIndex) << 21);

if ((*Pd & IA32_PG_PS) != 0) {
// 2MB page

if (!IsAddressValid (Address, &Nx)) {
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) {
//
// Patch to remove Present flag and RW flag
// If PD entry does not exist, skip it
//
*Pd = *Pd & (INTN)(INT32)(~PAGE_ATTRIBUTE_BITS);
}
if (Nx && mXdSupported) {
*Pd = *Pd | IA32_PG_NX;
}
} 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++) {
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;
}
} else {
// 4KB page
Pt = (UINT64 *)(UINTN)(*Pd & ~mAddressEncMask & PHYSICAL_ADDRESS_MASK);
if (Pt == 0) {
continue;
}
Address += SIZE_4KB;
} // end for PT
} // end if PS
} // end for PD
} // end for PDPT
} // end for PML4
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
Expand Down Expand Up @@ -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
Expand Down
Loading

0 comments on commit 4eee0cc

Please sign in to comment.