2) IA-32 Intel(R) Architecture Software Developer's Manual Volume 2:Instruction Set Reference, Intel\r
3) IA-32 Intel(R) Architecture Software Developer's Manual Volume 3:System Programmer's Guide, Intel\r
\r
-Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>\r
Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>\r
\r
SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
+#include <Register/Intel/Cpuid.h>\r
#include "DxeIpl.h"\r
#include "VirtualMemory.h"\r
\r
)\r
{\r
UINT32 RegEax;\r
+ CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS_ECX EcxFlags;\r
UINT32 RegEdx;\r
UINT8 PhysicalAddressBits;\r
EFI_PHYSICAL_ADDRESS PageAddress;\r
+ UINTN IndexOfPml5Entries;\r
UINTN IndexOfPml4Entries;\r
UINTN IndexOfPdpEntries;\r
UINTN IndexOfPageDirectoryEntries;\r
+ UINT32 NumberOfPml5EntriesNeeded;\r
UINT32 NumberOfPml4EntriesNeeded;\r
UINT32 NumberOfPdpEntriesNeeded;\r
+ PAGE_MAP_AND_DIRECTORY_POINTER *PageMapLevel5Entry;\r
PAGE_MAP_AND_DIRECTORY_POINTER *PageMapLevel4Entry;\r
PAGE_MAP_AND_DIRECTORY_POINTER *PageMap;\r
PAGE_MAP_AND_DIRECTORY_POINTER *PageDirectoryPointerEntry;\r
UINTN TotalPagesNum;\r
UINTN BigPageAddress;\r
VOID *Hob;\r
+ BOOLEAN Page5LevelSupport;\r
BOOLEAN Page1GSupport;\r
PAGE_TABLE_1G_ENTRY *PageDirectory1GEntry;\r
UINT64 AddressEncMask;\r
+ IA32_CR4 Cr4;\r
\r
//\r
// Make sure AddressEncMask is contained to smallest supported address field\r
}\r
}\r
\r
+ Page5LevelSupport = FALSE;\r
+ if (PcdGetBool (PcdUse5LevelPageTable)) {\r
+ AsmCpuidEx (\r
+ CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS, CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS_SUB_LEAF_INFO, NULL,\r
+ &EcxFlags.Uint32, NULL, NULL\r
+ );\r
+ if (EcxFlags.Bits.FiveLevelPage != 0) {\r
+ Page5LevelSupport = TRUE;\r
+ }\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "AddressBits=%u 5LevelPaging=%u 1GPage=%u\n", PhysicalAddressBits, Page5LevelSupport, Page1GSupport));\r
+\r
//\r
- // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.\r
+ // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses\r
+ // when 5-Level Paging is disabled,\r
+ // due to either unsupported by HW, or disabled by PCD.\r
//\r
ASSERT (PhysicalAddressBits <= 52);\r
- if (PhysicalAddressBits > 48) {\r
+ if (!Page5LevelSupport && PhysicalAddressBits > 48) {\r
PhysicalAddressBits = 48;\r
}\r
\r
//\r
// Calculate the table entries needed.\r
//\r
- if (PhysicalAddressBits <= 39 ) {\r
- NumberOfPml4EntriesNeeded = 1;\r
- NumberOfPdpEntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 30));\r
- } else {\r
- NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 39));\r
- NumberOfPdpEntriesNeeded = 512;\r
+ NumberOfPml5EntriesNeeded = 1;\r
+ if (PhysicalAddressBits > 48) {\r
+ NumberOfPml5EntriesNeeded = (UINT32) LShiftU64 (1, PhysicalAddressBits - 48);\r
+ PhysicalAddressBits = 48;\r
+ }\r
+\r
+ NumberOfPml4EntriesNeeded = 1;\r
+ if (PhysicalAddressBits > 39) {\r
+ NumberOfPml4EntriesNeeded = (UINT32) LShiftU64 (1, PhysicalAddressBits - 39);\r
+ PhysicalAddressBits = 39;\r
}\r
\r
+ NumberOfPdpEntriesNeeded = 1;\r
+ ASSERT (PhysicalAddressBits > 30);\r
+ NumberOfPdpEntriesNeeded = (UINT32) LShiftU64 (1, PhysicalAddressBits - 30);\r
+\r
//\r
// Pre-allocate big pages to avoid later allocations.\r
//\r
if (!Page1GSupport) {\r
- TotalPagesNum = (NumberOfPdpEntriesNeeded + 1) * NumberOfPml4EntriesNeeded + 1;\r
+ TotalPagesNum = ((NumberOfPdpEntriesNeeded + 1) * NumberOfPml4EntriesNeeded + 1) * NumberOfPml5EntriesNeeded + 1;\r
} else {\r
- TotalPagesNum = NumberOfPml4EntriesNeeded + 1;\r
+ TotalPagesNum = (NumberOfPml4EntriesNeeded + 1) * NumberOfPml5EntriesNeeded + 1;\r
+ }\r
+\r
+ //\r
+ // Substract the one page occupied by PML5 entries if 5-Level Paging is disabled.\r
+ //\r
+ if (!Page5LevelSupport) {\r
+ TotalPagesNum--;\r
}\r
+\r
+ DEBUG ((DEBUG_INFO, "Pml5=%u Pml4=%u Pdp=%u TotalPage=%Lu\n",\r
+ NumberOfPml5EntriesNeeded, NumberOfPml4EntriesNeeded,\r
+ NumberOfPdpEntriesNeeded, (UINT64)TotalPagesNum));\r
+\r
BigPageAddress = (UINTN) AllocatePageTableMemory (TotalPagesNum);\r
ASSERT (BigPageAddress != 0);\r
\r
// By architecture only one PageMapLevel4 exists - so lets allocate storage for it.\r
//\r
PageMap = (VOID *) BigPageAddress;\r
- BigPageAddress += SIZE_4KB;\r
-\r
- PageMapLevel4Entry = PageMap;\r
- PageAddress = 0;\r
- for (IndexOfPml4Entries = 0; IndexOfPml4Entries < NumberOfPml4EntriesNeeded; IndexOfPml4Entries++, PageMapLevel4Entry++) {\r
+ if (Page5LevelSupport) {\r
//\r
- // Each PML4 entry points to a page of Page Directory Pointer entires.\r
- // So lets allocate space for them and fill them in in the IndexOfPdpEntries loop.\r
+ // By architecture only one PageMapLevel5 exists - so lets allocate storage for it.\r
//\r
- PageDirectoryPointerEntry = (VOID *) BigPageAddress;\r
- BigPageAddress += SIZE_4KB;\r
+ PageMapLevel5Entry = PageMap;\r
+ BigPageAddress += SIZE_4KB;\r
+ }\r
+ PageAddress = 0;\r
\r
+ for ( IndexOfPml5Entries = 0\r
+ ; IndexOfPml5Entries < NumberOfPml5EntriesNeeded\r
+ ; IndexOfPml5Entries++, PageMapLevel5Entry++) {\r
//\r
- // Make a PML4 Entry\r
+ // Each PML5 entry points to a page of PML4 entires.\r
+ // So lets allocate space for them and fill them in in the IndexOfPml4Entries loop.\r
+ // When 5-Level Paging is disabled, below allocation happens only once.\r
//\r
- PageMapLevel4Entry->Uint64 = (UINT64)(UINTN)PageDirectoryPointerEntry | AddressEncMask;\r
- PageMapLevel4Entry->Bits.ReadWrite = 1;\r
- PageMapLevel4Entry->Bits.Present = 1;\r
+ PageMapLevel4Entry = (VOID *) BigPageAddress;\r
+ BigPageAddress += SIZE_4KB;\r
\r
- if (Page1GSupport) {\r
- PageDirectory1GEntry = (VOID *) PageDirectoryPointerEntry;\r
+ if (Page5LevelSupport) {\r
+ //\r
+ // Make a PML5 Entry\r
+ //\r
+ PageMapLevel5Entry->Uint64 = (UINT64) (UINTN) PageMapLevel4Entry | AddressEncMask;\r
+ PageMapLevel5Entry->Bits.ReadWrite = 1;\r
+ PageMapLevel5Entry->Bits.Present = 1;\r
+ }\r
\r
- for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectory1GEntry++, PageAddress += SIZE_1GB) {\r
- if (ToSplitPageTable (PageAddress, SIZE_1GB, StackBase, StackSize)) {\r
- Split1GPageTo2M (PageAddress, (UINT64 *) PageDirectory1GEntry, StackBase, StackSize);\r
- } else {\r
- //\r
- // Fill in the Page Directory entries\r
- //\r
- PageDirectory1GEntry->Uint64 = (UINT64)PageAddress | AddressEncMask;\r
- PageDirectory1GEntry->Bits.ReadWrite = 1;\r
- PageDirectory1GEntry->Bits.Present = 1;\r
- PageDirectory1GEntry->Bits.MustBe1 = 1;\r
- }\r
- }\r
- } else {\r
- for (IndexOfPdpEntries = 0; IndexOfPdpEntries < NumberOfPdpEntriesNeeded; IndexOfPdpEntries++, PageDirectoryPointerEntry++) {\r
- //\r
- // Each Directory Pointer entries points to a page of Page Directory entires.\r
- // So allocate space for them and fill them in in the IndexOfPageDirectoryEntries loop.\r
- //\r
- PageDirectoryEntry = (VOID *) BigPageAddress;\r
- BigPageAddress += SIZE_4KB;\r
+ for ( IndexOfPml4Entries = 0\r
+ ; IndexOfPml4Entries < (NumberOfPml5EntriesNeeded == 1 ? NumberOfPml4EntriesNeeded : 512)\r
+ ; IndexOfPml4Entries++, PageMapLevel4Entry++) {\r
+ //\r
+ // Each PML4 entry points to a page of Page Directory Pointer entires.\r
+ // So lets allocate space for them and fill them in in the IndexOfPdpEntries loop.\r
+ //\r
+ PageDirectoryPointerEntry = (VOID *) BigPageAddress;\r
+ BigPageAddress += SIZE_4KB;\r
\r
- //\r
- // Fill in a Page Directory Pointer Entries\r
- //\r
- PageDirectoryPointerEntry->Uint64 = (UINT64)(UINTN)PageDirectoryEntry | AddressEncMask;\r
- PageDirectoryPointerEntry->Bits.ReadWrite = 1;\r
- PageDirectoryPointerEntry->Bits.Present = 1;\r
+ //\r
+ // Make a PML4 Entry\r
+ //\r
+ PageMapLevel4Entry->Uint64 = (UINT64)(UINTN)PageDirectoryPointerEntry | AddressEncMask;\r
+ PageMapLevel4Entry->Bits.ReadWrite = 1;\r
+ PageMapLevel4Entry->Bits.Present = 1;\r
\r
- for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PageAddress += SIZE_2MB) {\r
- if (ToSplitPageTable (PageAddress, SIZE_2MB, StackBase, StackSize)) {\r
- //\r
- // Need to split this 2M page that covers NULL or stack range.\r
- //\r
- Split2MPageTo4K (PageAddress, (UINT64 *) PageDirectoryEntry, StackBase, StackSize);\r
+ if (Page1GSupport) {\r
+ PageDirectory1GEntry = (VOID *) PageDirectoryPointerEntry;\r
+\r
+ for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectory1GEntry++, PageAddress += SIZE_1GB) {\r
+ if (ToSplitPageTable (PageAddress, SIZE_1GB, StackBase, StackSize)) {\r
+ Split1GPageTo2M (PageAddress, (UINT64 *) PageDirectory1GEntry, StackBase, StackSize);\r
} else {\r
//\r
// Fill in the Page Directory entries\r
//\r
- PageDirectoryEntry->Uint64 = (UINT64)PageAddress | AddressEncMask;\r
- PageDirectoryEntry->Bits.ReadWrite = 1;\r
- PageDirectoryEntry->Bits.Present = 1;\r
- PageDirectoryEntry->Bits.MustBe1 = 1;\r
+ PageDirectory1GEntry->Uint64 = (UINT64)PageAddress | AddressEncMask;\r
+ PageDirectory1GEntry->Bits.ReadWrite = 1;\r
+ PageDirectory1GEntry->Bits.Present = 1;\r
+ PageDirectory1GEntry->Bits.MustBe1 = 1;\r
}\r
}\r
- }\r
+ } else {\r
+ for ( IndexOfPdpEntries = 0\r
+ ; IndexOfPdpEntries < (NumberOfPml4EntriesNeeded == 1 ? NumberOfPdpEntriesNeeded : 512)\r
+ ; IndexOfPdpEntries++, PageDirectoryPointerEntry++) {\r
+ //\r
+ // Each Directory Pointer entries points to a page of Page Directory entires.\r
+ // So allocate space for them and fill them in in the IndexOfPageDirectoryEntries loop.\r
+ //\r
+ PageDirectoryEntry = (VOID *) BigPageAddress;\r
+ BigPageAddress += SIZE_4KB;\r
\r
- for (; IndexOfPdpEntries < 512; IndexOfPdpEntries++, PageDirectoryPointerEntry++) {\r
- ZeroMem (\r
- PageDirectoryPointerEntry,\r
- sizeof(PAGE_MAP_AND_DIRECTORY_POINTER)\r
- );\r
+ //\r
+ // Fill in a Page Directory Pointer Entries\r
+ //\r
+ PageDirectoryPointerEntry->Uint64 = (UINT64)(UINTN)PageDirectoryEntry | AddressEncMask;\r
+ PageDirectoryPointerEntry->Bits.ReadWrite = 1;\r
+ PageDirectoryPointerEntry->Bits.Present = 1;\r
+\r
+ for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PageAddress += SIZE_2MB) {\r
+ if (ToSplitPageTable (PageAddress, SIZE_2MB, StackBase, StackSize)) {\r
+ //\r
+ // Need to split this 2M page that covers NULL or stack range.\r
+ //\r
+ Split2MPageTo4K (PageAddress, (UINT64 *) PageDirectoryEntry, StackBase, StackSize);\r
+ } else {\r
+ //\r
+ // Fill in the Page Directory entries\r
+ //\r
+ PageDirectoryEntry->Uint64 = (UINT64)PageAddress | AddressEncMask;\r
+ PageDirectoryEntry->Bits.ReadWrite = 1;\r
+ PageDirectoryEntry->Bits.Present = 1;\r
+ PageDirectoryEntry->Bits.MustBe1 = 1;\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // Fill with null entry for unused PDPTE\r
+ //\r
+ ZeroMem (PageDirectoryPointerEntry, (512 - IndexOfPdpEntries) * sizeof(PAGE_MAP_AND_DIRECTORY_POINTER));\r
}\r
}\r
+\r
+ //\r
+ // For the PML4 entries we are not using fill in a null entry.\r
+ //\r
+ ZeroMem (PageMapLevel4Entry, (512 - IndexOfPml4Entries) * sizeof (PAGE_MAP_AND_DIRECTORY_POINTER));\r
}\r
\r
- //\r
- // For the PML4 entries we are not using fill in a null entry.\r
- //\r
- for (; IndexOfPml4Entries < 512; IndexOfPml4Entries++, PageMapLevel4Entry++) {\r
- ZeroMem (\r
- PageMapLevel4Entry,\r
- sizeof (PAGE_MAP_AND_DIRECTORY_POINTER)\r
- );\r
+ if (Page5LevelSupport) {\r
+ Cr4.UintN = AsmReadCr4 ();\r
+ Cr4.Bits.LA57 = 1;\r
+ AsmWriteCr4 (Cr4.UintN);\r
+ //\r
+ // For the PML5 entries we are not using fill in a null entry.\r
+ //\r
+ ZeroMem (PageMapLevel5Entry, (512 - IndexOfPml5Entries) * sizeof (PAGE_MAP_AND_DIRECTORY_POINTER));\r
}\r
\r
//\r