mirror of https://github.com/acidanthera/audk.git
MdeModulePkg/DxeIpl: Create 5-level page table for long mode
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2008 DxeIpl is responsible to create page table for DXE phase running either in long mode or in 32bit mode with certain protection mechanism enabled (refer to ToBuildPageTable()). The patch updates DxeIpl to create 5-level page table for DXE phase running in long mode when PcdUse5LevelPageTable is TRUE and CPU supports 5-level page table. Signed-off-by: Ray Ni <ray.ni@intel.com> Reviewed-by: Eric Dong <eric.dong@intel.com> Regression-tested-by: Laszlo Ersek <lersek@redhat.com> Reviewed-by: Hao A Wu <hao.a.wu@intel.com> Signed-off-by: Eric Dong <eric.dong@intel.com>
This commit is contained in:
parent
236d5c66c4
commit
b3527dedc3
|
@ -110,6 +110,7 @@
|
||||||
gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask ## CONSUMES
|
gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask ## CONSUMES
|
||||||
gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPropertyMask ## CONSUMES
|
gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPropertyMask ## CONSUMES
|
||||||
gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard ## CONSUMES
|
gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard ## CONSUMES
|
||||||
|
gEfiMdeModulePkgTokenSpaceGuid.PcdUse5LevelPageTable ## SOMETIMES_CONSUMES
|
||||||
|
|
||||||
[Pcd.IA32,Pcd.X64,Pcd.ARM,Pcd.AARCH64]
|
[Pcd.IA32,Pcd.X64,Pcd.ARM,Pcd.AARCH64]
|
||||||
gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack ## SOMETIMES_CONSUMES
|
gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack ## SOMETIMES_CONSUMES
|
||||||
|
|
|
@ -15,13 +15,14 @@
|
||||||
2) IA-32 Intel(R) Architecture Software Developer's Manual Volume 2:Instruction Set Reference, Intel
|
2) IA-32 Intel(R) Architecture Software Developer's Manual Volume 2:Instruction Set Reference, Intel
|
||||||
3) IA-32 Intel(R) Architecture Software Developer's Manual Volume 3:System Programmer's Guide, Intel
|
3) IA-32 Intel(R) Architecture Software Developer's Manual Volume 3:System Programmer's Guide, Intel
|
||||||
|
|
||||||
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
|
Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
|
||||||
Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
|
Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
|
||||||
|
|
||||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||||
|
|
||||||
**/
|
**/
|
||||||
|
|
||||||
|
#include <Register/Intel/Cpuid.h>
|
||||||
#include "DxeIpl.h"
|
#include "DxeIpl.h"
|
||||||
#include "VirtualMemory.h"
|
#include "VirtualMemory.h"
|
||||||
|
|
||||||
|
@ -626,14 +627,18 @@ CreateIdentityMappingPageTables (
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
UINT32 RegEax;
|
UINT32 RegEax;
|
||||||
|
CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS_ECX EcxFlags;
|
||||||
UINT32 RegEdx;
|
UINT32 RegEdx;
|
||||||
UINT8 PhysicalAddressBits;
|
UINT8 PhysicalAddressBits;
|
||||||
EFI_PHYSICAL_ADDRESS PageAddress;
|
EFI_PHYSICAL_ADDRESS PageAddress;
|
||||||
|
UINTN IndexOfPml5Entries;
|
||||||
UINTN IndexOfPml4Entries;
|
UINTN IndexOfPml4Entries;
|
||||||
UINTN IndexOfPdpEntries;
|
UINTN IndexOfPdpEntries;
|
||||||
UINTN IndexOfPageDirectoryEntries;
|
UINTN IndexOfPageDirectoryEntries;
|
||||||
|
UINT32 NumberOfPml5EntriesNeeded;
|
||||||
UINT32 NumberOfPml4EntriesNeeded;
|
UINT32 NumberOfPml4EntriesNeeded;
|
||||||
UINT32 NumberOfPdpEntriesNeeded;
|
UINT32 NumberOfPdpEntriesNeeded;
|
||||||
|
PAGE_MAP_AND_DIRECTORY_POINTER *PageMapLevel5Entry;
|
||||||
PAGE_MAP_AND_DIRECTORY_POINTER *PageMapLevel4Entry;
|
PAGE_MAP_AND_DIRECTORY_POINTER *PageMapLevel4Entry;
|
||||||
PAGE_MAP_AND_DIRECTORY_POINTER *PageMap;
|
PAGE_MAP_AND_DIRECTORY_POINTER *PageMap;
|
||||||
PAGE_MAP_AND_DIRECTORY_POINTER *PageDirectoryPointerEntry;
|
PAGE_MAP_AND_DIRECTORY_POINTER *PageDirectoryPointerEntry;
|
||||||
|
@ -641,9 +646,11 @@ CreateIdentityMappingPageTables (
|
||||||
UINTN TotalPagesNum;
|
UINTN TotalPagesNum;
|
||||||
UINTN BigPageAddress;
|
UINTN BigPageAddress;
|
||||||
VOID *Hob;
|
VOID *Hob;
|
||||||
|
BOOLEAN Page5LevelSupport;
|
||||||
BOOLEAN Page1GSupport;
|
BOOLEAN Page1GSupport;
|
||||||
PAGE_TABLE_1G_ENTRY *PageDirectory1GEntry;
|
PAGE_TABLE_1G_ENTRY *PageDirectory1GEntry;
|
||||||
UINT64 AddressEncMask;
|
UINT64 AddressEncMask;
|
||||||
|
IA32_CR4 Cr4;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Make sure AddressEncMask is contained to smallest supported address field
|
// Make sure AddressEncMask is contained to smallest supported address field
|
||||||
|
@ -677,33 +684,68 @@ CreateIdentityMappingPageTables (
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Page5LevelSupport = FALSE;
|
||||||
|
if (PcdGetBool (PcdUse5LevelPageTable)) {
|
||||||
|
AsmCpuidEx (
|
||||||
|
CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS, CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS_SUB_LEAF_INFO, NULL,
|
||||||
|
&EcxFlags.Uint32, NULL, NULL
|
||||||
|
);
|
||||||
|
if (EcxFlags.Bits.FiveLevelPage != 0) {
|
||||||
|
Page5LevelSupport = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG ((DEBUG_INFO, "AddressBits=%u 5LevelPaging=%u 1GPage=%u\n", PhysicalAddressBits, Page5LevelSupport, Page1GSupport));
|
||||||
|
|
||||||
//
|
//
|
||||||
// IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.
|
// IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses
|
||||||
|
// when 5-Level Paging is disabled,
|
||||||
|
// due to either unsupported by HW, or disabled by PCD.
|
||||||
//
|
//
|
||||||
ASSERT (PhysicalAddressBits <= 52);
|
ASSERT (PhysicalAddressBits <= 52);
|
||||||
if (PhysicalAddressBits > 48) {
|
if (!Page5LevelSupport && PhysicalAddressBits > 48) {
|
||||||
PhysicalAddressBits = 48;
|
PhysicalAddressBits = 48;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Calculate the table entries needed.
|
// Calculate the table entries needed.
|
||||||
//
|
//
|
||||||
if (PhysicalAddressBits <= 39 ) {
|
NumberOfPml5EntriesNeeded = 1;
|
||||||
NumberOfPml4EntriesNeeded = 1;
|
if (PhysicalAddressBits > 48) {
|
||||||
NumberOfPdpEntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 30));
|
NumberOfPml5EntriesNeeded = (UINT32) LShiftU64 (1, PhysicalAddressBits - 48);
|
||||||
} else {
|
PhysicalAddressBits = 48;
|
||||||
NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 39));
|
|
||||||
NumberOfPdpEntriesNeeded = 512;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NumberOfPml4EntriesNeeded = 1;
|
||||||
|
if (PhysicalAddressBits > 39) {
|
||||||
|
NumberOfPml4EntriesNeeded = (UINT32) LShiftU64 (1, PhysicalAddressBits - 39);
|
||||||
|
PhysicalAddressBits = 39;
|
||||||
|
}
|
||||||
|
|
||||||
|
NumberOfPdpEntriesNeeded = 1;
|
||||||
|
ASSERT (PhysicalAddressBits > 30);
|
||||||
|
NumberOfPdpEntriesNeeded = (UINT32) LShiftU64 (1, PhysicalAddressBits - 30);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Pre-allocate big pages to avoid later allocations.
|
// Pre-allocate big pages to avoid later allocations.
|
||||||
//
|
//
|
||||||
if (!Page1GSupport) {
|
if (!Page1GSupport) {
|
||||||
TotalPagesNum = (NumberOfPdpEntriesNeeded + 1) * NumberOfPml4EntriesNeeded + 1;
|
TotalPagesNum = ((NumberOfPdpEntriesNeeded + 1) * NumberOfPml4EntriesNeeded + 1) * NumberOfPml5EntriesNeeded + 1;
|
||||||
} else {
|
} else {
|
||||||
TotalPagesNum = NumberOfPml4EntriesNeeded + 1;
|
TotalPagesNum = (NumberOfPml4EntriesNeeded + 1) * NumberOfPml5EntriesNeeded + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Substract the one page occupied by PML5 entries if 5-Level Paging is disabled.
|
||||||
|
//
|
||||||
|
if (!Page5LevelSupport) {
|
||||||
|
TotalPagesNum--;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG ((DEBUG_INFO, "Pml5=%u Pml4=%u Pdp=%u TotalPage=%Lu\n",
|
||||||
|
NumberOfPml5EntriesNeeded, NumberOfPml4EntriesNeeded,
|
||||||
|
NumberOfPdpEntriesNeeded, (UINT64)TotalPagesNum));
|
||||||
|
|
||||||
BigPageAddress = (UINTN) AllocatePageTableMemory (TotalPagesNum);
|
BigPageAddress = (UINTN) AllocatePageTableMemory (TotalPagesNum);
|
||||||
ASSERT (BigPageAddress != 0);
|
ASSERT (BigPageAddress != 0);
|
||||||
|
|
||||||
|
@ -711,92 +753,125 @@ CreateIdentityMappingPageTables (
|
||||||
// By architecture only one PageMapLevel4 exists - so lets allocate storage for it.
|
// By architecture only one PageMapLevel4 exists - so lets allocate storage for it.
|
||||||
//
|
//
|
||||||
PageMap = (VOID *) BigPageAddress;
|
PageMap = (VOID *) BigPageAddress;
|
||||||
BigPageAddress += SIZE_4KB;
|
if (Page5LevelSupport) {
|
||||||
|
//
|
||||||
PageMapLevel4Entry = PageMap;
|
// By architecture only one PageMapLevel5 exists - so lets allocate storage for it.
|
||||||
|
//
|
||||||
|
PageMapLevel5Entry = PageMap;
|
||||||
|
BigPageAddress += SIZE_4KB;
|
||||||
|
}
|
||||||
PageAddress = 0;
|
PageAddress = 0;
|
||||||
for (IndexOfPml4Entries = 0; IndexOfPml4Entries < NumberOfPml4EntriesNeeded; IndexOfPml4Entries++, PageMapLevel4Entry++) {
|
|
||||||
|
for ( IndexOfPml5Entries = 0
|
||||||
|
; IndexOfPml5Entries < NumberOfPml5EntriesNeeded
|
||||||
|
; IndexOfPml5Entries++, PageMapLevel5Entry++) {
|
||||||
//
|
//
|
||||||
// Each PML4 entry points to a page of Page Directory Pointer entires.
|
// Each PML5 entry points to a page of PML4 entires.
|
||||||
// So lets allocate space for them and fill them in in the IndexOfPdpEntries loop.
|
// So lets allocate space for them and fill them in in the IndexOfPml4Entries loop.
|
||||||
|
// When 5-Level Paging is disabled, below allocation happens only once.
|
||||||
//
|
//
|
||||||
PageDirectoryPointerEntry = (VOID *) BigPageAddress;
|
PageMapLevel4Entry = (VOID *) BigPageAddress;
|
||||||
BigPageAddress += SIZE_4KB;
|
BigPageAddress += SIZE_4KB;
|
||||||
|
|
||||||
//
|
if (Page5LevelSupport) {
|
||||||
// Make a PML4 Entry
|
//
|
||||||
//
|
// Make a PML5 Entry
|
||||||
PageMapLevel4Entry->Uint64 = (UINT64)(UINTN)PageDirectoryPointerEntry | AddressEncMask;
|
//
|
||||||
PageMapLevel4Entry->Bits.ReadWrite = 1;
|
PageMapLevel5Entry->Uint64 = (UINT64) (UINTN) PageMapLevel4Entry | AddressEncMask;
|
||||||
PageMapLevel4Entry->Bits.Present = 1;
|
PageMapLevel5Entry->Bits.ReadWrite = 1;
|
||||||
|
PageMapLevel5Entry->Bits.Present = 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (Page1GSupport) {
|
for ( IndexOfPml4Entries = 0
|
||||||
PageDirectory1GEntry = (VOID *) PageDirectoryPointerEntry;
|
; IndexOfPml4Entries < (NumberOfPml5EntriesNeeded == 1 ? NumberOfPml4EntriesNeeded : 512)
|
||||||
|
; IndexOfPml4Entries++, PageMapLevel4Entry++) {
|
||||||
|
//
|
||||||
|
// Each PML4 entry points to a page of Page Directory Pointer entires.
|
||||||
|
// So lets allocate space for them and fill them in in the IndexOfPdpEntries loop.
|
||||||
|
//
|
||||||
|
PageDirectoryPointerEntry = (VOID *) BigPageAddress;
|
||||||
|
BigPageAddress += SIZE_4KB;
|
||||||
|
|
||||||
for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectory1GEntry++, PageAddress += SIZE_1GB) {
|
//
|
||||||
if (ToSplitPageTable (PageAddress, SIZE_1GB, StackBase, StackSize)) {
|
// Make a PML4 Entry
|
||||||
Split1GPageTo2M (PageAddress, (UINT64 *) PageDirectory1GEntry, StackBase, StackSize);
|
//
|
||||||
} else {
|
PageMapLevel4Entry->Uint64 = (UINT64)(UINTN)PageDirectoryPointerEntry | AddressEncMask;
|
||||||
//
|
PageMapLevel4Entry->Bits.ReadWrite = 1;
|
||||||
// Fill in the Page Directory entries
|
PageMapLevel4Entry->Bits.Present = 1;
|
||||||
//
|
|
||||||
PageDirectory1GEntry->Uint64 = (UINT64)PageAddress | AddressEncMask;
|
|
||||||
PageDirectory1GEntry->Bits.ReadWrite = 1;
|
|
||||||
PageDirectory1GEntry->Bits.Present = 1;
|
|
||||||
PageDirectory1GEntry->Bits.MustBe1 = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (IndexOfPdpEntries = 0; IndexOfPdpEntries < NumberOfPdpEntriesNeeded; IndexOfPdpEntries++, PageDirectoryPointerEntry++) {
|
|
||||||
//
|
|
||||||
// Each Directory Pointer entries points to a page of Page Directory entires.
|
|
||||||
// So allocate space for them and fill them in in the IndexOfPageDirectoryEntries loop.
|
|
||||||
//
|
|
||||||
PageDirectoryEntry = (VOID *) BigPageAddress;
|
|
||||||
BigPageAddress += SIZE_4KB;
|
|
||||||
|
|
||||||
//
|
if (Page1GSupport) {
|
||||||
// Fill in a Page Directory Pointer Entries
|
PageDirectory1GEntry = (VOID *) PageDirectoryPointerEntry;
|
||||||
//
|
|
||||||
PageDirectoryPointerEntry->Uint64 = (UINT64)(UINTN)PageDirectoryEntry | AddressEncMask;
|
|
||||||
PageDirectoryPointerEntry->Bits.ReadWrite = 1;
|
|
||||||
PageDirectoryPointerEntry->Bits.Present = 1;
|
|
||||||
|
|
||||||
for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PageAddress += SIZE_2MB) {
|
for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectory1GEntry++, PageAddress += SIZE_1GB) {
|
||||||
if (ToSplitPageTable (PageAddress, SIZE_2MB, StackBase, StackSize)) {
|
if (ToSplitPageTable (PageAddress, SIZE_1GB, StackBase, StackSize)) {
|
||||||
//
|
Split1GPageTo2M (PageAddress, (UINT64 *) PageDirectory1GEntry, StackBase, StackSize);
|
||||||
// Need to split this 2M page that covers NULL or stack range.
|
|
||||||
//
|
|
||||||
Split2MPageTo4K (PageAddress, (UINT64 *) PageDirectoryEntry, StackBase, StackSize);
|
|
||||||
} else {
|
} else {
|
||||||
//
|
//
|
||||||
// Fill in the Page Directory entries
|
// Fill in the Page Directory entries
|
||||||
//
|
//
|
||||||
PageDirectoryEntry->Uint64 = (UINT64)PageAddress | AddressEncMask;
|
PageDirectory1GEntry->Uint64 = (UINT64)PageAddress | AddressEncMask;
|
||||||
PageDirectoryEntry->Bits.ReadWrite = 1;
|
PageDirectory1GEntry->Bits.ReadWrite = 1;
|
||||||
PageDirectoryEntry->Bits.Present = 1;
|
PageDirectory1GEntry->Bits.Present = 1;
|
||||||
PageDirectoryEntry->Bits.MustBe1 = 1;
|
PageDirectory1GEntry->Bits.MustBe1 = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
|
for ( IndexOfPdpEntries = 0
|
||||||
|
; IndexOfPdpEntries < (NumberOfPml4EntriesNeeded == 1 ? NumberOfPdpEntriesNeeded : 512)
|
||||||
|
; IndexOfPdpEntries++, PageDirectoryPointerEntry++) {
|
||||||
|
//
|
||||||
|
// Each Directory Pointer entries points to a page of Page Directory entires.
|
||||||
|
// So allocate space for them and fill them in in the IndexOfPageDirectoryEntries loop.
|
||||||
|
//
|
||||||
|
PageDirectoryEntry = (VOID *) BigPageAddress;
|
||||||
|
BigPageAddress += SIZE_4KB;
|
||||||
|
|
||||||
for (; IndexOfPdpEntries < 512; IndexOfPdpEntries++, PageDirectoryPointerEntry++) {
|
//
|
||||||
ZeroMem (
|
// Fill in a Page Directory Pointer Entries
|
||||||
PageDirectoryPointerEntry,
|
//
|
||||||
sizeof(PAGE_MAP_AND_DIRECTORY_POINTER)
|
PageDirectoryPointerEntry->Uint64 = (UINT64)(UINTN)PageDirectoryEntry | AddressEncMask;
|
||||||
);
|
PageDirectoryPointerEntry->Bits.ReadWrite = 1;
|
||||||
|
PageDirectoryPointerEntry->Bits.Present = 1;
|
||||||
|
|
||||||
|
for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PageAddress += SIZE_2MB) {
|
||||||
|
if (ToSplitPageTable (PageAddress, SIZE_2MB, StackBase, StackSize)) {
|
||||||
|
//
|
||||||
|
// Need to split this 2M page that covers NULL or stack range.
|
||||||
|
//
|
||||||
|
Split2MPageTo4K (PageAddress, (UINT64 *) PageDirectoryEntry, StackBase, StackSize);
|
||||||
|
} else {
|
||||||
|
//
|
||||||
|
// Fill in the Page Directory entries
|
||||||
|
//
|
||||||
|
PageDirectoryEntry->Uint64 = (UINT64)PageAddress | AddressEncMask;
|
||||||
|
PageDirectoryEntry->Bits.ReadWrite = 1;
|
||||||
|
PageDirectoryEntry->Bits.Present = 1;
|
||||||
|
PageDirectoryEntry->Bits.MustBe1 = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Fill with null entry for unused PDPTE
|
||||||
|
//
|
||||||
|
ZeroMem (PageDirectoryPointerEntry, (512 - IndexOfPdpEntries) * sizeof(PAGE_MAP_AND_DIRECTORY_POINTER));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// For the PML4 entries we are not using fill in a null entry.
|
||||||
|
//
|
||||||
|
ZeroMem (PageMapLevel4Entry, (512 - IndexOfPml4Entries) * sizeof (PAGE_MAP_AND_DIRECTORY_POINTER));
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
if (Page5LevelSupport) {
|
||||||
// For the PML4 entries we are not using fill in a null entry.
|
Cr4.UintN = AsmReadCr4 ();
|
||||||
//
|
Cr4.Bits.LA57 = 1;
|
||||||
for (; IndexOfPml4Entries < 512; IndexOfPml4Entries++, PageMapLevel4Entry++) {
|
AsmWriteCr4 (Cr4.UintN);
|
||||||
ZeroMem (
|
//
|
||||||
PageMapLevel4Entry,
|
// For the PML5 entries we are not using fill in a null entry.
|
||||||
sizeof (PAGE_MAP_AND_DIRECTORY_POINTER)
|
//
|
||||||
);
|
ZeroMem (PageMapLevel5Entry, (512 - IndexOfPml5Entries) * sizeof (PAGE_MAP_AND_DIRECTORY_POINTER));
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
Loading…
Reference in New Issue