+/**\r
+ Calculate the maximum support address.\r
+\r
+ @return the maximum support address.\r
+**/\r
+UINT8\r
+CalculateMaximumSupportAddress (\r
+ VOID\r
+ )\r
+{\r
+ UINT32 RegEax;\r
+ UINT8 PhysicalAddressBits;\r
+ VOID *Hob;\r
+\r
+ //\r
+ // Get physical address bits supported.\r
+ //\r
+ Hob = GetFirstHob (EFI_HOB_TYPE_CPU);\r
+ if (Hob != NULL) {\r
+ PhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace;\r
+ } else {\r
+ AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
+ if (RegEax >= 0x80000008) {\r
+ AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
+ PhysicalAddressBits = (UINT8) RegEax;\r
+ } else {\r
+ PhysicalAddressBits = 36;\r
+ }\r
+ }\r
+ return PhysicalAddressBits;\r
+}\r
+\r
+/**\r
+ Set static page table.\r
+\r
+ @param[in] PageTable Address of page table.\r
+**/\r
+VOID\r
+SetStaticPageTable (\r
+ IN UINTN PageTable\r
+ )\r
+{\r
+ UINT64 PageAddress;\r
+ UINTN NumberOfPml5EntriesNeeded;\r
+ UINTN NumberOfPml4EntriesNeeded;\r
+ UINTN NumberOfPdpEntriesNeeded;\r
+ UINTN IndexOfPml5Entries;\r
+ UINTN IndexOfPml4Entries;\r
+ UINTN IndexOfPdpEntries;\r
+ UINTN IndexOfPageDirectoryEntries;\r
+ UINT64 *PageMapLevel5Entry;\r
+ UINT64 *PageMapLevel4Entry;\r
+ UINT64 *PageMap;\r
+ UINT64 *PageDirectoryPointerEntry;\r
+ UINT64 *PageDirectory1GEntry;\r
+ UINT64 *PageDirectoryEntry;\r
+\r
+ //\r
+ // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses\r
+ // when 5-Level Paging is disabled.\r
+ //\r
+ ASSERT (mPhysicalAddressBits <= 52);\r
+ if (!m5LevelPagingSupport && mPhysicalAddressBits > 48) {\r
+ mPhysicalAddressBits = 48;\r
+ }\r
+\r
+ NumberOfPml5EntriesNeeded = 1;\r
+ if (mPhysicalAddressBits > 48) {\r
+ NumberOfPml5EntriesNeeded = (UINTN) LShiftU64 (1, mPhysicalAddressBits - 48);\r
+ mPhysicalAddressBits = 48;\r
+ }\r
+\r
+ NumberOfPml4EntriesNeeded = 1;\r
+ if (mPhysicalAddressBits > 39) {\r
+ NumberOfPml4EntriesNeeded = (UINTN) LShiftU64 (1, mPhysicalAddressBits - 39);\r
+ mPhysicalAddressBits = 39;\r
+ }\r
+\r
+ NumberOfPdpEntriesNeeded = 1;\r
+ ASSERT (mPhysicalAddressBits > 30);\r
+ NumberOfPdpEntriesNeeded = (UINTN) LShiftU64 (1, mPhysicalAddressBits - 30);\r
+\r
+ //\r
+ // By architecture only one PageMapLevel4 exists - so lets allocate storage for it.\r
+ //\r
+ PageMap = (VOID *) PageTable;\r
+\r
+ PageMapLevel4Entry = PageMap;\r
+ PageMapLevel5Entry = NULL;\r
+ if (m5LevelPagingSupport) {\r
+ //\r
+ // By architecture only one PageMapLevel5 exists - so lets allocate storage for it.\r
+ //\r
+ PageMapLevel5Entry = PageMap;\r
+ }\r
+ PageAddress = 0;\r
+\r
+ for ( IndexOfPml5Entries = 0\r
+ ; IndexOfPml5Entries < NumberOfPml5EntriesNeeded\r
+ ; IndexOfPml5Entries++, PageMapLevel5Entry++) {\r
+ //\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
+ if (m5LevelPagingSupport) {\r
+ PageMapLevel4Entry = (UINT64 *) ((*PageMapLevel5Entry) & ~mAddressEncMask & gPhyMask);\r
+ if (PageMapLevel4Entry == NULL) {\r
+ PageMapLevel4Entry = AllocatePageTableMemory (1);\r
+ ASSERT(PageMapLevel4Entry != NULL);\r
+ ZeroMem (PageMapLevel4Entry, EFI_PAGES_TO_SIZE(1));\r
+\r
+ *PageMapLevel5Entry = (UINT64)(UINTN)PageMapLevel4Entry | mAddressEncMask | PAGE_ATTRIBUTE_BITS;\r
+ }\r
+ }\r
+\r
+ for (IndexOfPml4Entries = 0; IndexOfPml4Entries < (NumberOfPml5EntriesNeeded == 1 ? NumberOfPml4EntriesNeeded : 512); IndexOfPml4Entries++, PageMapLevel4Entry++) {\r
+ //\r
+ // Each PML4 entry points to a page of Page Directory Pointer entries.\r
+ //\r
+ PageDirectoryPointerEntry = (UINT64 *) ((*PageMapLevel4Entry) & ~mAddressEncMask & gPhyMask);\r
+ if (PageDirectoryPointerEntry == NULL) {\r
+ PageDirectoryPointerEntry = AllocatePageTableMemory (1);\r
+ ASSERT(PageDirectoryPointerEntry != NULL);\r
+ ZeroMem (PageDirectoryPointerEntry, EFI_PAGES_TO_SIZE(1));\r
+\r
+ *PageMapLevel4Entry = (UINT64)(UINTN)PageDirectoryPointerEntry | mAddressEncMask | PAGE_ATTRIBUTE_BITS;\r
+ }\r
+\r
+ if (m1GPageTableSupport) {\r
+ PageDirectory1GEntry = PageDirectoryPointerEntry;\r
+ for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectory1GEntry++, PageAddress += SIZE_1GB) {\r
+ if (IndexOfPml4Entries == 0 && IndexOfPageDirectoryEntries < 4) {\r
+ //\r
+ // Skip the < 4G entries\r
+ //\r
+ continue;\r
+ }\r
+ //\r
+ // Fill in the Page Directory entries\r
+ //\r
+ *PageDirectory1GEntry = PageAddress | mAddressEncMask | IA32_PG_PS | PAGE_ATTRIBUTE_BITS;\r
+ }\r
+ } else {\r
+ PageAddress = BASE_4GB;\r
+ for (IndexOfPdpEntries = 0; IndexOfPdpEntries < (NumberOfPml4EntriesNeeded == 1 ? NumberOfPdpEntriesNeeded : 512); IndexOfPdpEntries++, PageDirectoryPointerEntry++) {\r
+ if (IndexOfPml4Entries == 0 && IndexOfPdpEntries < 4) {\r
+ //\r
+ // Skip the < 4G entries\r
+ //\r
+ continue;\r
+ }\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 = (UINT64 *) ((*PageDirectoryPointerEntry) & ~mAddressEncMask & gPhyMask);\r
+ if (PageDirectoryEntry == NULL) {\r
+ PageDirectoryEntry = AllocatePageTableMemory (1);\r
+ ASSERT(PageDirectoryEntry != NULL);\r
+ ZeroMem (PageDirectoryEntry, EFI_PAGES_TO_SIZE(1));\r
+\r
+ //\r
+ // Fill in a Page Directory Pointer Entries\r
+ //\r
+ *PageDirectoryPointerEntry = (UINT64)(UINTN)PageDirectoryEntry | mAddressEncMask | PAGE_ATTRIBUTE_BITS;\r
+ }\r
+\r
+ for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PageAddress += SIZE_2MB) {\r
+ //\r
+ // Fill in the Page Directory entries\r
+ //\r
+ *PageDirectoryEntry = PageAddress | mAddressEncMask | IA32_PG_PS | PAGE_ATTRIBUTE_BITS;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+}\r
+\r