]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/Library/CpuPageTableLib/CpuPageTableMap.c
CpuPageTableLib: Fix parent attributes are not inherited properly
[mirror_edk2.git] / UefiCpuPkg / Library / CpuPageTableLib / CpuPageTableMap.c
index d02fd5efa2eefa1c87e071ee6ab8092d71c6d89e..db24205cbde847d5cadfb2c4b5d2007b120e78ab 100644 (file)
@@ -183,18 +183,32 @@ PageTableLibSetPle (
 \r
   @param[in] Pnle      Pointer to IA32_PML5, IA32_PML4, IA32_PDPTE or IA32_PDE. All share the same structure definition.\r
   @param[in] Attribute The attribute of the page directory referenced by the non-leaf.\r
+  @param[in] Mask      The mask of the page directory referenced by the non-leaf.\r
 **/\r
 VOID\r
 PageTableLibSetPnle (\r
   IN IA32_PAGE_NON_LEAF_ENTRY  *Pnle,\r
-  IN IA32_MAP_ATTRIBUTE        *Attribute\r
+  IN IA32_MAP_ATTRIBUTE        *Attribute,\r
+  IN IA32_MAP_ATTRIBUTE        *Mask\r
   )\r
 {\r
-  Pnle->Bits.Present        = Attribute->Bits.Present;\r
-  Pnle->Bits.ReadWrite      = Attribute->Bits.ReadWrite;\r
-  Pnle->Bits.UserSupervisor = Attribute->Bits.UserSupervisor;\r
-  Pnle->Bits.Nx             = Attribute->Bits.Nx;\r
-  Pnle->Bits.Accessed       = 0;\r
+  if (Mask->Bits.Present) {\r
+    Pnle->Bits.Present = Attribute->Bits.Present;\r
+  }\r
+\r
+  if (Mask->Bits.ReadWrite) {\r
+    Pnle->Bits.ReadWrite = Attribute->Bits.ReadWrite;\r
+  }\r
+\r
+  if (Mask->Bits.UserSupervisor) {\r
+    Pnle->Bits.UserSupervisor = Attribute->Bits.UserSupervisor;\r
+  }\r
+\r
+  if (Mask->Bits.Nx) {\r
+    Pnle->Bits.Nx = Attribute->Bits.Nx;\r
+  }\r
+\r
+  Pnle->Bits.Accessed = 0;\r
 \r
   //\r
   // Set the attributes (WT, CD, A) to 0.\r
@@ -210,6 +224,7 @@ PageTableLibSetPnle (
   Update page table to map [LinearAddress, LinearAddress + Length) with specified attribute in the specified level.\r
 \r
   @param[in]      ParentPagingEntry The pointer to the page table entry to update.\r
+  @param[in]      ParentAttribute   The accumulated attribute of all parents' attribute.\r
   @param[in]      Modify            FALSE to indicate Buffer is not used and BufferSize is increased by the required buffer size.\r
   @param[in]      Buffer            The free buffer to be used for page table creation/updating.\r
                                     When Modify is TRUE, it's used from the end.\r
@@ -232,6 +247,7 @@ PageTableLibSetPnle (
 RETURN_STATUS\r
 PageTableLibMapInLevel (\r
   IN     IA32_PAGING_ENTRY   *ParentPagingEntry,\r
+  IN     IA32_MAP_ATTRIBUTE  *ParentAttribute,\r
   IN     BOOLEAN             Modify,\r
   IN     VOID                *Buffer,\r
   IN OUT INTN                *BufferSize,\r
@@ -248,6 +264,7 @@ PageTableLibMapInLevel (
   UINTN               BitStart;\r
   UINTN               Index;\r
   IA32_PAGING_ENTRY   *PagingEntry;\r
+  IA32_PAGING_ENTRY   *CurrentPagingEntry;\r
   UINT64              RegionLength;\r
   UINT64              SubLength;\r
   UINT64              SubOffset;\r
@@ -258,6 +275,8 @@ PageTableLibMapInLevel (
   IA32_MAP_ATTRIBUTE  NopAttribute;\r
   BOOLEAN             CreateNew;\r
   IA32_PAGING_ENTRY   OneOfPagingEntry;\r
+  IA32_MAP_ATTRIBUTE  ChildAttribute;\r
+  IA32_MAP_ATTRIBUTE  ChildMask;\r
 \r
   ASSERT (Level != 0);\r
   ASSERT ((Attribute != NULL) && (Mask != NULL));\r
@@ -290,7 +309,7 @@ PageTableLibMapInLevel (
       //\r
       // Set default attribute bits for PML5E/PML4E/PDPTE/PDE.\r
       //\r
-      PageTableLibSetPnle (&ParentPagingEntry->Pnle, &NopAttribute);\r
+      PageTableLibSetPnle (&ParentPagingEntry->Pnle, &NopAttribute, &AllOneMask);\r
     } else {\r
       //\r
       // Just make sure Present and MustBeZero (PageSize) bits are accurate.\r
@@ -306,7 +325,7 @@ PageTableLibMapInLevel (
     // Use NOP attributes as the attribute of grand-parents because CPU will consider\r
     // the actual attributes of grand-parents when determing the memory type.\r
     //\r
-    PleBAttribute.Uint64 = PageTableLibGetPleBMapAttribute (&ParentPagingEntry->PleB, &NopAttribute);\r
+    PleBAttribute.Uint64 = PageTableLibGetPleBMapAttribute (&ParentPagingEntry->PleB, ParentAttribute);\r
     if ((IA32_MAP_ATTRIBUTE_ATTRIBUTES (&PleBAttribute) & IA32_MAP_ATTRIBUTE_ATTRIBUTES (Mask))\r
         == (IA32_MAP_ATTRIBUTE_ATTRIBUTES (Attribute) & IA32_MAP_ATTRIBUTE_ATTRIBUTES (Mask)))\r
     {\r
@@ -333,7 +352,7 @@ PageTableLibMapInLevel (
       // Note: Should NOT inherit the attributes from the original entry because a zero RW bit\r
       //       will make the entire region read-only even the child entries set the RW bit.\r
       //\r
-      PageTableLibSetPnle (&ParentPagingEntry->Pnle, &NopAttribute);\r
+      PageTableLibSetPnle (&ParentPagingEntry->Pnle, &NopAttribute, &AllOneMask);\r
 \r
       RegionLength = REGION_LENGTH (Level);\r
       PagingEntry  = (IA32_PAGING_ENTRY *)(UINTN)IA32_PNLE_PAGE_TABLE_BASE_ADDRESS (&ParentPagingEntry->Pnle);\r
@@ -342,6 +361,77 @@ PageTableLibMapInLevel (
         SubOffset                += RegionLength;\r
       }\r
     }\r
+  } else {\r
+    //\r
+    // It's a non-leaf entry\r
+    //\r
+    ChildAttribute.Uint64 = 0;\r
+    ChildMask.Uint64      = 0;\r
+\r
+    //\r
+    // If the inheritable attributes in the parent entry conflicts with the requested attributes,\r
+    //   let the child entries take the parent attributes and\r
+    //   loosen the attribute in the parent entry\r
+    // E.g.: when PDPTE[0].ReadWrite = 0 but caller wants to map [0-2MB] as ReadWrite = 1 (PDE[0].ReadWrite = 1)\r
+    //            we need to change PDPTE[0].ReadWrite = 1 and let all PDE[0-255].ReadWrite = 0 in this step.\r
+    //       when PDPTE[0].Nx = 1 but caller wants to map [0-2MB] as Nx = 0 (PDT[0].Nx = 0)\r
+    //            we need to change PDPTE[0].Nx = 0 and let all PDE[0-255].Nx = 1 in this step.\r
+    if ((ParentPagingEntry->Pnle.Bits.Present == 0) && (Mask->Bits.Present == 1) && (Attribute->Bits.Present == 1)) {\r
+      if (Modify) {\r
+        ParentPagingEntry->Pnle.Bits.Present = 1;\r
+      }\r
+\r
+      ChildAttribute.Bits.Present = 0;\r
+      ChildMask.Bits.Present      = 1;\r
+    }\r
+\r
+    if ((ParentPagingEntry->Pnle.Bits.ReadWrite == 0) && (Mask->Bits.ReadWrite == 1) && (Attribute->Bits.ReadWrite == 1)) {\r
+      if (Modify) {\r
+        ParentPagingEntry->Pnle.Bits.ReadWrite = 1;\r
+      }\r
+\r
+      ChildAttribute.Bits.ReadWrite = 0;\r
+      ChildMask.Bits.ReadWrite      = 1;\r
+    }\r
+\r
+    if ((ParentPagingEntry->Pnle.Bits.UserSupervisor == 0) && (Mask->Bits.UserSupervisor == 1) && (Attribute->Bits.UserSupervisor == 1)) {\r
+      if (Modify) {\r
+        ParentPagingEntry->Pnle.Bits.UserSupervisor = 1;\r
+      }\r
+\r
+      ChildAttribute.Bits.UserSupervisor = 0;\r
+      ChildMask.Bits.UserSupervisor      = 1;\r
+    }\r
+\r
+    if ((ParentPagingEntry->Pnle.Bits.Nx == 1) && (Mask->Bits.Nx == 1) && (Attribute->Bits.Nx == 0)) {\r
+      if (Modify) {\r
+        ParentPagingEntry->Pnle.Bits.Nx = 0;\r
+      }\r
+\r
+      ChildAttribute.Bits.Nx = 1;\r
+      ChildMask.Bits.Nx      = 1;\r
+    }\r
+\r
+    if (ChildMask.Uint64 != 0) {\r
+      if (Modify) {\r
+        //\r
+        // Update child entries to use restrictive attribute inherited from parent.\r
+        // e.g.: Set PDE[0-255].ReadWrite = 0\r
+        //\r
+        PagingEntry = (IA32_PAGING_ENTRY *)(UINTN)IA32_PNLE_PAGE_TABLE_BASE_ADDRESS (&ParentPagingEntry->Pnle);\r
+        for (Index = 0; Index < 512; Index++) {\r
+          if (PagingEntry[Index].Pce.Present == 0) {\r
+            continue;\r
+          }\r
+\r
+          if (IsPle (&PagingEntry[Index], Level)) {\r
+            PageTableLibSetPle (Level - 1, &PagingEntry[Index], 0, &ChildAttribute, &ChildMask);\r
+          } else {\r
+            PageTableLibSetPnle (&PagingEntry[Index].Pnle, &ChildAttribute, &ChildMask);\r
+          }\r
+        }\r
+      }\r
+    }\r
   }\r
 \r
   //\r
@@ -354,23 +444,27 @@ PageTableLibMapInLevel (
   RegionMask   = RegionLength - 1;\r
   RegionStart  = (LinearAddress + Offset) & ~RegionMask;\r
 \r
+  ParentAttribute->Uint64 = PageTableLibGetPnleMapAttribute (&ParentPagingEntry->Pnle, ParentAttribute);\r
+\r
   //\r
   // Apply the attribute.\r
   //\r
   PagingEntry = (IA32_PAGING_ENTRY *)(UINTN)IA32_PNLE_PAGE_TABLE_BASE_ADDRESS (&ParentPagingEntry->Pnle);\r
   while (Offset < Length && Index < 512) {\r
-    SubLength = MIN (Length - Offset, RegionStart + RegionLength - (LinearAddress + Offset));\r
+    CurrentPagingEntry = (!Modify && CreateNew) ? &OneOfPagingEntry : &PagingEntry[Index];\r
+    SubLength          = MIN (Length - Offset, RegionStart + RegionLength - (LinearAddress + Offset));\r
     if ((Level <= MaxLeafLevel) &&\r
         (((LinearAddress + Offset) & RegionMask) == 0) &&\r
         (((IA32_MAP_ATTRIBUTE_PAGE_TABLE_BASE_ADDRESS (Attribute) + Offset) & RegionMask) == 0) &&\r
-        (SubLength == RegionLength)\r
+        (SubLength == RegionLength) &&\r
+        ((CurrentPagingEntry->Pce.Present == 0) || IsPle (CurrentPagingEntry, Level))\r
         )\r
     {\r
       //\r
       // Create one entry mapping the entire region (1G, 2M or 4K).\r
       //\r
       if (Modify) {\r
-        PageTableLibSetPle (Level, &PagingEntry[Index], Offset, Attribute, Mask);\r
+        PageTableLibSetPle (Level, CurrentPagingEntry, Offset, Attribute, Mask);\r
       }\r
     } else {\r
       //\r
@@ -382,7 +476,8 @@ PageTableLibMapInLevel (
       //      but the length is SMALLER than the RegionLength.\r
       //\r
       Status = PageTableLibMapInLevel (\r
-                 (!Modify && CreateNew) ? &OneOfPagingEntry : &PagingEntry[Index],\r
+                 CurrentPagingEntry,\r
+                 ParentAttribute,\r
                  Modify,\r
                  Buffer,\r
                  BufferSize,\r
@@ -446,12 +541,13 @@ PageTableMap (
   IN     IA32_MAP_ATTRIBUTE  *Mask\r
   )\r
 {\r
-  RETURN_STATUS      Status;\r
-  IA32_PAGING_ENTRY  TopPagingEntry;\r
-  INTN               RequiredSize;\r
-  UINT64             MaxLinearAddress;\r
-  UINTN              MaxLevel;\r
-  UINTN              MaxLeafLevel;\r
+  RETURN_STATUS       Status;\r
+  IA32_PAGING_ENTRY   TopPagingEntry;\r
+  INTN                RequiredSize;\r
+  UINT64              MaxLinearAddress;\r
+  UINTN               MaxLevel;\r
+  UINTN               MaxLeafLevel;\r
+  IA32_MAP_ATTRIBUTE  ParentAttribute;\r
 \r
   if ((PagingMode == Paging32bit) || (PagingMode == PagingPae) || (PagingMode >= PagingModeMax)) {\r
     //\r
@@ -496,15 +592,26 @@ PageTableMap (
 \r
   TopPagingEntry.Uintn = *PageTable;\r
   if (TopPagingEntry.Uintn != 0) {\r
-    TopPagingEntry.Pce.Present = 1;\r
+    TopPagingEntry.Pce.Present        = 1;\r
+    TopPagingEntry.Pce.ReadWrite      = 1;\r
+    TopPagingEntry.Pce.UserSupervisor = 1;\r
+    TopPagingEntry.Pce.Nx             = 0;\r
   }\r
 \r
+  ParentAttribute.Uint64                    = 0;\r
+  ParentAttribute.Bits.PageTableBaseAddress = 1;\r
+  ParentAttribute.Bits.Present              = 1;\r
+  ParentAttribute.Bits.ReadWrite            = 1;\r
+  ParentAttribute.Bits.UserSupervisor       = 1;\r
+  ParentAttribute.Bits.Nx                   = 0;\r
+\r
   //\r
   // Query the required buffer size without modifying the page table.\r
   //\r
   RequiredSize = 0;\r
   Status       = PageTableLibMapInLevel (\r
                    &TopPagingEntry,\r
+                   &ParentAttribute,\r
                    FALSE,\r
                    NULL,\r
                    &RequiredSize,\r
@@ -534,8 +641,16 @@ PageTableMap (
   //\r
   // Update the page table when the supplied buffer is sufficient.\r
   //\r
+  ParentAttribute.Uint64                    = 0;\r
+  ParentAttribute.Bits.PageTableBaseAddress = 1;\r
+  ParentAttribute.Bits.Present              = 1;\r
+  ParentAttribute.Bits.ReadWrite            = 1;\r
+  ParentAttribute.Bits.UserSupervisor       = 1;\r
+  ParentAttribute.Bits.Nx                   = 0;\r
+\r
   Status = PageTableLibMapInLevel (\r
              &TopPagingEntry,\r
+             &ParentAttribute,\r
              TRUE,\r
              Buffer,\r
              (INTN *)BufferSize,\r