IA32_PAGE_LEVEL MaxLeafLevel;\r
IA32_MAP_ATTRIBUTE ParentAttribute;\r
BOOLEAN LocalIsModified;\r
+ UINTN Index;\r
+ IA32_PAGING_ENTRY *PagingEntry;\r
+ UINT8 BufferInStack[SIZE_4KB - 1 + MAX_PAE_PDPTE_NUM * sizeof (IA32_PAGING_ENTRY)];\r
\r
if (Length == 0) {\r
return RETURN_SUCCESS;\r
}\r
\r
- if ((PagingMode == Paging32bit) || (PagingMode == PagingPae) || (PagingMode >= PagingModeMax)) {\r
+ if ((PagingMode == Paging32bit) || (PagingMode >= PagingModeMax)) {\r
//\r
// 32bit paging is never supported.\r
- // PAE paging will be supported later.\r
//\r
return RETURN_UNSUPPORTED;\r
}\r
\r
MaxLeafLevel = (IA32_PAGE_LEVEL)(UINT8)PagingMode;\r
MaxLevel = (IA32_PAGE_LEVEL)(UINT8)(PagingMode >> 8);\r
- MaxLinearAddress = LShiftU64 (1, 12 + MaxLevel * 9);\r
+ MaxLinearAddress = (PagingMode == PagingPae) ? LShiftU64 (1, 32) : LShiftU64 (1, 12 + MaxLevel * 9);\r
\r
if ((LinearAddress > MaxLinearAddress) || (Length > MaxLinearAddress - LinearAddress)) {\r
//\r
- // Maximum linear address is (1 << 48) or (1 << 57)\r
+ // Maximum linear address is (1 << 32), (1 << 48) or (1 << 57)\r
//\r
return RETURN_INVALID_PARAMETER;\r
}\r
\r
TopPagingEntry.Uintn = *PageTable;\r
if (TopPagingEntry.Uintn != 0) {\r
+ if (PagingMode == PagingPae) {\r
+ //\r
+ // Create 4 temporary PDPTE at a 4k-aligned address.\r
+ // Copy the original PDPTE content and set ReadWrite, UserSupervisor to 1, set Nx to 0.\r
+ //\r
+ TopPagingEntry.Uintn = ALIGN_VALUE ((UINTN)BufferInStack, BASE_4KB);\r
+ PagingEntry = (IA32_PAGING_ENTRY *)(TopPagingEntry.Uintn);\r
+ CopyMem (PagingEntry, (VOID *)(*PageTable), MAX_PAE_PDPTE_NUM * sizeof (IA32_PAGING_ENTRY));\r
+ for (Index = 0; Index < MAX_PAE_PDPTE_NUM; Index++) {\r
+ PagingEntry[Index].Pnle.Bits.ReadWrite = 1;\r
+ PagingEntry[Index].Pnle.Bits.UserSupervisor = 1;\r
+ PagingEntry[Index].Pnle.Bits.Nx = 0;\r
+ }\r
+ }\r
+\r
TopPagingEntry.Pce.Present = 1;\r
TopPagingEntry.Pce.ReadWrite = 1;\r
TopPagingEntry.Pce.UserSupervisor = 1;\r
);\r
\r
if (!RETURN_ERROR (Status)) {\r
- *PageTable = (UINTN)(TopPagingEntry.Uintn & IA32_PE_BASE_ADDRESS_MASK_40);\r
+ PagingEntry = (IA32_PAGING_ENTRY *)(UINTN)(TopPagingEntry.Uintn & IA32_PE_BASE_ADDRESS_MASK_40);\r
+\r
+ if (PagingMode == PagingPae) {\r
+ //\r
+ // These MustBeZero fields are treated as RW and other attributes by the common map logic. So they might be set to 1.\r
+ //\r
+ for (Index = 0; Index < MAX_PAE_PDPTE_NUM; Index++) {\r
+ PagingEntry[Index].PdptePae.Bits.MustBeZero = 0;\r
+ PagingEntry[Index].PdptePae.Bits.MustBeZero2 = 0;\r
+ PagingEntry[Index].PdptePae.Bits.MustBeZero3 = 0;\r
+ }\r
+\r
+ if (*PageTable != 0) {\r
+ //\r
+ // Copy temp PDPTE to original PDPTE.\r
+ //\r
+ CopyMem ((VOID *)(*PageTable), PagingEntry, MAX_PAE_PDPTE_NUM * sizeof (IA32_PAGING_ENTRY));\r
+ }\r
+ }\r
+\r
+ if (*PageTable == 0) {\r
+ //\r
+ // Do not assign the *PageTable when it's an existing page table.\r
+ // If it's an existing PAE page table, PagingEntry is the temp buffer in stack.\r
+ //\r
+ *PageTable = (UINTN)PagingEntry;\r
+ }\r
}\r
\r
return Status;\r
/** @file\r
This library implements CpuPageTableLib that are generic for IA32 family CPU.\r
\r
- Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>\r
+ Copyright (c) 2022 - 2023, Intel Corporation. All rights reserved.<BR>\r
SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
PageTableLibParsePnle (\r
IN UINT64 PageTableBaseAddress,\r
IN UINTN Level,\r
+ IN UINTN MaxLevel,\r
IN UINT64 RegionStart,\r
IN IA32_MAP_ATTRIBUTE *ParentMapAttribute,\r
IN OUT IA32_MAP_ENTRY *Map,\r
UINTN Index;\r
IA32_MAP_ATTRIBUTE MapAttribute;\r
UINT64 RegionLength;\r
+ UINTN PagingEntryNumber;\r
\r
ASSERT (OneEntry != NULL);\r
\r
- PagingEntry = (IA32_PAGING_ENTRY *)(UINTN)PageTableBaseAddress;\r
- RegionLength = REGION_LENGTH (Level);\r
+ PagingEntry = (IA32_PAGING_ENTRY *)(UINTN)PageTableBaseAddress;\r
+ RegionLength = REGION_LENGTH (Level);\r
+ PagingEntryNumber = ((MaxLevel == 3) && (Level == 3)) ? MAX_PAE_PDPTE_NUM : 512;\r
\r
- for (Index = 0; Index < 512; Index++, RegionStart += RegionLength) {\r
+ for (Index = 0; Index < PagingEntryNumber; Index++, RegionStart += RegionLength) {\r
if (PagingEntry[Index].Pce.Present == 0) {\r
continue;\r
}\r
PageTableLibParsePnle (\r
IA32_PNLE_PAGE_TABLE_BASE_ADDRESS (&PagingEntry[Index].Pnle),\r
Level - 1,\r
+ MaxLevel,\r
RegionStart,\r
&MapAttribute,\r
Map,\r
IA32_MAP_ENTRY *LastEntry;\r
IA32_MAP_ENTRY OneEntry;\r
UINTN MaxLevel;\r
+ UINTN Index;\r
+ IA32_PAGING_ENTRY BufferInStack[MAX_PAE_PDPTE_NUM];\r
\r
if ((PagingMode == Paging32bit) || (PagingMode >= PagingModeMax)) {\r
//\r
return RETURN_SUCCESS;\r
}\r
\r
+ if (PagingMode == PagingPae) {\r
+ CopyMem (BufferInStack, (VOID *)PageTable, sizeof (BufferInStack));\r
+ for (Index = 0; Index < MAX_PAE_PDPTE_NUM; Index++) {\r
+ BufferInStack[Index].Pnle.Bits.ReadWrite = 1;\r
+ BufferInStack[Index].Pnle.Bits.UserSupervisor = 1;\r
+ BufferInStack[Index].Pnle.Bits.Nx = 0;\r
+ }\r
+\r
+ PageTable = (UINTN)BufferInStack;\r
+ }\r
+\r
//\r
// Page table layout is as below:\r
//\r
MapCapacity = *MapCount;\r
*MapCount = 0;\r
LastEntry = NULL;\r
- PageTableLibParsePnle ((UINT64)PageTable, MaxLevel, 0, &NopAttribute, Map, MapCount, MapCapacity, &LastEntry, &OneEntry);\r
+ PageTableLibParsePnle ((UINT64)PageTable, MaxLevel, MaxLevel, 0, &NopAttribute, Map, MapCount, MapCapacity, &LastEntry, &OneEntry);\r
\r
if (*MapCount > MapCapacity) {\r
return RETURN_BUFFER_TOO_SMALL;\r