]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ArmPkg/Library/ArmMmuLib/AArch64/ArmMmuLibCore.c
ArmPkg/CpuDxe: move PageAttributeToGcdAttribute() out of ArmMmuLib
[mirror_edk2.git] / ArmPkg / Library / ArmMmuLib / AArch64 / ArmMmuLibCore.c
index d78918cf7ba80f0c0837aaddfee50b78fa2b36e6..d16e847218b7495c871675e289a561485ac02241 100644 (file)
@@ -57,51 +57,6 @@ ArmMemoryAttributeToPageAttribute (
   }\r
 }\r
 \r
-UINT64\r
-PageAttributeToGcdAttribute (\r
-  IN UINT64 PageAttributes\r
-  )\r
-{\r
-  UINT64  GcdAttributes;\r
-\r
-  switch (PageAttributes & TT_ATTR_INDX_MASK) {\r
-  case TT_ATTR_INDX_DEVICE_MEMORY:\r
-    GcdAttributes = EFI_MEMORY_UC;\r
-    break;\r
-  case TT_ATTR_INDX_MEMORY_NON_CACHEABLE:\r
-    GcdAttributes = EFI_MEMORY_WC;\r
-    break;\r
-  case TT_ATTR_INDX_MEMORY_WRITE_THROUGH:\r
-    GcdAttributes = EFI_MEMORY_WT;\r
-    break;\r
-  case TT_ATTR_INDX_MEMORY_WRITE_BACK:\r
-    GcdAttributes = EFI_MEMORY_WB;\r
-    break;\r
-  default:\r
-    DEBUG ((DEBUG_ERROR,\r
-      "PageAttributeToGcdAttribute: PageAttributes:0x%lX not supported.\n",\r
-      PageAttributes));\r
-    ASSERT (0);\r
-    // The Global Coherency Domain (GCD) value is defined as a bit set.\r
-    // Returning 0 means no attribute has been set.\r
-    GcdAttributes = 0;\r
-  }\r
-\r
-  // Determine protection attributes\r
-  if (((PageAttributes & TT_AP_MASK) == TT_AP_NO_RO) ||\r
-      ((PageAttributes & TT_AP_MASK) == TT_AP_RO_RO)) {\r
-    // Read only cases map to write-protect\r
-    GcdAttributes |= EFI_MEMORY_RO;\r
-  }\r
-\r
-  // Process eXecute Never attribute\r
-  if ((PageAttributes & (TT_PXN_MASK | TT_UXN_MASK)) != 0) {\r
-    GcdAttributes |= EFI_MEMORY_XP;\r
-  }\r
-\r
-  return GcdAttributes;\r
-}\r
-\r
 #define MIN_T0SZ        16\r
 #define BITS_PER_LEVEL  9\r
 \r
@@ -162,6 +117,36 @@ FreePageTablesRecursive (
   FreePages (TranslationTable, 1);\r
 }\r
 \r
+STATIC\r
+BOOLEAN\r
+IsBlockEntry (\r
+  IN  UINT64  Entry,\r
+  IN  UINTN   Level\r
+  )\r
+{\r
+  if (Level == 3) {\r
+    return (Entry & TT_TYPE_MASK) == TT_TYPE_BLOCK_ENTRY_LEVEL3;\r
+  }\r
+  return (Entry & TT_TYPE_MASK) == TT_TYPE_BLOCK_ENTRY;\r
+}\r
+\r
+STATIC\r
+BOOLEAN\r
+IsTableEntry (\r
+  IN  UINT64  Entry,\r
+  IN  UINTN   Level\r
+  )\r
+{\r
+  if (Level == 3) {\r
+    //\r
+    // TT_TYPE_TABLE_ENTRY aliases TT_TYPE_BLOCK_ENTRY_LEVEL3\r
+    // so we need to take the level into account as well.\r
+    //\r
+    return FALSE;\r
+  }\r
+  return (Entry & TT_TYPE_MASK) == TT_TYPE_TABLE_ENTRY;\r
+}\r
+\r
 STATIC\r
 EFI_STATUS\r
 UpdateRegionMappingRecursive (\r
@@ -199,11 +184,15 @@ 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
+    // 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
-    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 ((*Entry & TT_TYPE_MASK) != TT_TYPE_TABLE_ENTRY) {\r
+      if (!IsTableEntry (*Entry, Level)) {\r
         //\r
         // No table entry exists yet, so we need to allocate a page table\r
         // for the next level.\r
@@ -221,7 +210,9 @@ UpdateRegionMappingRecursive (
           InvalidateDataCacheRange (TranslationTable, EFI_PAGE_SIZE);\r
         }\r
 \r
-        if ((*Entry & TT_TYPE_MASK) == TT_TYPE_BLOCK_ENTRY) {\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
           // the new table with the attributes of the block entry it replaces.\r
@@ -238,8 +229,6 @@ UpdateRegionMappingRecursive (
             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
@@ -252,7 +241,7 @@ UpdateRegionMappingRecursive (
                  AttributeSetMask, AttributeClearMask, TranslationTable,\r
                  Level + 1);\r
       if (EFI_ERROR (Status)) {\r
-        if ((*Entry & TT_TYPE_MASK) != TT_TYPE_TABLE_ENTRY) {\r
+        if (!IsTableEntry (*Entry, Level)) {\r
           //\r
           // We are creating a new table entry, so on failure, we can free all\r
           // allocations we made recursively, given that the whole subhierarchy\r
@@ -265,10 +254,10 @@ UpdateRegionMappingRecursive (
         return Status;\r
       }\r
 \r
-      if ((*Entry & TT_TYPE_MASK) != TT_TYPE_TABLE_ENTRY) {\r
+      if (!IsTableEntry (*Entry, Level)) {\r
         EntryValue = (UINTN)TranslationTable | TT_TYPE_TABLE_ENTRY;\r
         ReplaceTableEntry (Entry, EntryValue, RegionStart,\r
-                           (*Entry & TT_TYPE_MASK) == TT_TYPE_BLOCK_ENTRY);\r
+          IsBlockEntry (*Entry, Level));\r
       }\r
     } else {\r
       EntryValue = (*Entry & AttributeClearMask) | AttributeSetMask;\r
@@ -276,7 +265,20 @@ UpdateRegionMappingRecursive (
       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