]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ArmPkg/Library/ArmMmuLib/AArch64/ArmMmuLibCore.c
ArmPkg/ArmMmuLib AARCH64: preserve attributes when replacing a table entry
[mirror_edk2.git] / ArmPkg / Library / ArmMmuLib / AArch64 / ArmMmuLibCore.c
index 0680ba36d9079f47024b519101c6ce6acf2b2289..3b10ef58f0a28aa04ca4fbd92cd74e2c0e0a4cca 100644 (file)
@@ -229,8 +229,12 @@ UpdateRegionMappingRecursive (
     // than a block, and recurse to create the block or page entries at\r
     // the next level. No block mappings are allowed at all at level 0,\r
     // so in that case, we have to recurse unconditionally.\r
     // than a block, and recurse to create the block or page entries at\r
     // the next level. No block mappings are allowed at all at level 0,\r
     // so in that case, we have to recurse unconditionally.\r
+    // If we are changing a table entry and the AttributeClearMask is non-zero,\r
+    // we cannot replace it with a block entry without potentially losing\r
+    // attribute information, so keep the table entry in that case.\r
     //\r
     //\r
-    if (Level == 0 || ((RegionStart | BlockEnd) & BlockMask) != 0) {\r
+    if (Level == 0 || ((RegionStart | BlockEnd) & BlockMask) != 0 ||\r
+        (IsTableEntry (*Entry, Level) && AttributeClearMask != 0)) {\r
       ASSERT (Level < 3);\r
 \r
       if (!IsTableEntry (*Entry, Level)) {\r
       ASSERT (Level < 3);\r
 \r
       if (!IsTableEntry (*Entry, Level)) {\r
@@ -251,6 +255,8 @@ UpdateRegionMappingRecursive (
           InvalidateDataCacheRange (TranslationTable, EFI_PAGE_SIZE);\r
         }\r
 \r
           InvalidateDataCacheRange (TranslationTable, EFI_PAGE_SIZE);\r
         }\r
 \r
+        ZeroMem (TranslationTable, EFI_PAGE_SIZE);\r
+\r
         if (IsBlockEntry (*Entry, Level)) {\r
           //\r
           // We are splitting an existing block entry, so we have to populate\r
         if (IsBlockEntry (*Entry, Level)) {\r
           //\r
           // We are splitting an existing block entry, so we have to populate\r
@@ -268,8 +274,6 @@ UpdateRegionMappingRecursive (
             FreePages (TranslationTable, 1);\r
             return Status;\r
           }\r
             FreePages (TranslationTable, 1);\r
             return Status;\r
           }\r
-        } else {\r
-          ZeroMem (TranslationTable, EFI_PAGE_SIZE);\r
         }\r
       } else {\r
         TranslationTable = (VOID *)(UINTN)(*Entry & TT_ADDRESS_MASK_BLOCK_ENTRY);\r
         }\r
       } else {\r
         TranslationTable = (VOID *)(UINTN)(*Entry & TT_ADDRESS_MASK_BLOCK_ENTRY);\r
@@ -306,7 +310,20 @@ UpdateRegionMappingRecursive (
       EntryValue |= (Level == 3) ? TT_TYPE_BLOCK_ENTRY_LEVEL3\r
                                  : TT_TYPE_BLOCK_ENTRY;\r
 \r
       EntryValue |= (Level == 3) ? TT_TYPE_BLOCK_ENTRY_LEVEL3\r
                                  : TT_TYPE_BLOCK_ENTRY;\r
 \r
-      ReplaceTableEntry (Entry, EntryValue, RegionStart, FALSE);\r
+      if (IsTableEntry (*Entry, Level)) {\r
+        //\r
+        // We are replacing a table entry with a block entry. This is only\r
+        // possible if we are keeping none of the original attributes.\r
+        // We can free the table entry's page table, and all the ones below\r
+        // it, since we are dropping the only possible reference to it.\r
+        //\r
+        ASSERT (AttributeClearMask == 0);\r
+        TranslationTable = (VOID *)(UINTN)(*Entry & TT_ADDRESS_MASK_BLOCK_ENTRY);\r
+        ReplaceTableEntry (Entry, EntryValue, RegionStart, TRUE);\r
+        FreePageTablesRecursive (TranslationTable, Level + 1);\r
+      } else {\r
+        ReplaceTableEntry (Entry, EntryValue, RegionStart, FALSE);\r
+      }\r
     }\r
   }\r
   return EFI_SUCCESS;\r
     }\r
   }\r
   return EFI_SUCCESS;\r