]> xenbits.xensource.com Git - ovmf.git/commitdiff
UefiCpuPkg/CpuPageTableLib: Enable PAE paging
authorDun Tan <dun.tan@intel.com>
Wed, 22 Mar 2023 07:20:20 +0000 (15:20 +0800)
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Mon, 27 Mar 2023 08:21:58 +0000 (08:21 +0000)
Modify CpuPageTableLib code to enable PAE paging.
In PageTableMap() API:
When creating new PAE page table, after creating page table,
set all MustBeZero fields of 4 PDPTE to 0. The MustBeZero
fields are treated as RW and other attributes by the common
map logic. So they might be set to 1.
When updating exsiting PAE page table, the special steps are:
1.Prepare 4K-aligned 32bytes memory in stack for 4 temp PDPTE.
2.Copy original 4 PDPTE to the 4 temp PDPTE and set the RW,
  UserSupervisor to 1 and set Nx of 4 temp PDPTE to 0.
4.After updating the page table, set the MustBeZero fields of
  4 temp PDPTE to 0.
5.Copy the temp PDPTE to original PDPTE.

In PageTableParse() API, also create 4 temp PDPTE in stack.
Copy original 4 PDPTE to the 4 temp PDPTE. Then set the RW,
UserSupervisor to 1 and set Nx of 4 temp PDPTE to 0. Finally
use the address of temp PDPTE as the page table address.

Signed-off-by: Dun Tan <dun.tan@intel.com>
Cc: Eric Dong <eric.dong@intel.com>
Reviewed-by: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Tested-by: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
UefiCpuPkg/Library/CpuPageTableLib/CpuPageTable.h
UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableMap.c
UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableParse.c

index 2c67ecb46947c127a53e9004e41586f657d0cb36..24da0ffb305b048be46a34ad822f804da2ff8907 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   Internal header for CpuPageTableLib.\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
@@ -20,6 +20,8 @@
 \r
 #define REGION_LENGTH(l)  LShiftU64 (1, (l) * 9 + 3)\r
 \r
+#define MAX_PAE_PDPTE_NUM  4\r
+\r
 typedef enum {\r
   Pte   = 1,\r
   Pde   = 2,\r
index 0d576ce39a974d848a000f6ffbc9830eeb681bc8..eff02619fa92d7175fa3a327a88f95e3ba7c47e4 100644 (file)
@@ -671,15 +671,17 @@ PageTableMap (
   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
@@ -716,17 +718,32 @@ PageTableMap (
 \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
@@ -801,7 +818,33 @@ PageTableMap (
              );\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
index 65490751ab61ae5a15577ffeb97a3eeaa69c3a65..37466e4e1082ee7e73b3516dc4148c998112ac51 100644 (file)
@@ -1,7 +1,7 @@
 /** @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
@@ -158,6 +158,7 @@ VOID
 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
@@ -171,13 +172,15 @@ PageTableLibParsePnle (
   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
@@ -228,6 +231,7 @@ PageTableLibParsePnle (
       PageTableLibParsePnle (\r
         IA32_PNLE_PAGE_TABLE_BASE_ADDRESS (&PagingEntry[Index].Pnle),\r
         Level - 1,\r
+        MaxLevel,\r
         RegionStart,\r
         &MapAttribute,\r
         Map,\r
@@ -269,6 +273,8 @@ PageTableParse (
   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
@@ -290,6 +296,17 @@ PageTableParse (
     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
@@ -319,7 +336,7 @@ PageTableParse (
   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