]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ArmPkg/Library/ArmMmuLib/AArch64/ArmMmuLibCore.c
ArmPkg/ArmMmuLib: support page tables in cacheable memory only
[mirror_edk2.git] / ArmPkg / Library / ArmMmuLib / AArch64 / ArmMmuLibCore.c
index 1ff584ec9eec69ebc62764b058cb60b9b75d60e5..c78297084207366b32c135563000c36884f5c04b 100644 (file)
@@ -553,12 +553,12 @@ ArmConfigureMmu (
   )\r
 {\r
   VOID*                         TranslationTable;\r
+  VOID*                         TranslationTableBuffer;\r
   UINT32                        TranslationTableAttribute;\r
-  ARM_MEMORY_REGION_DESCRIPTOR *MemoryTableEntry;\r
   UINT64                        MaxAddress;\r
-  UINT64                        TopAddress;\r
   UINTN                         T0SZ;\r
   UINTN                         RootTableEntryCount;\r
+  UINTN                         RootTableEntrySize;\r
   UINT64                        TCR;\r
   RETURN_STATUS                 Status;\r
 \r
@@ -567,16 +567,8 @@ ArmConfigureMmu (
     return RETURN_INVALID_PARAMETER;\r
   }\r
 \r
-  // Identify the highest address of the memory table\r
-  MaxAddress = MemoryTable->PhysicalBase + MemoryTable->Length - 1;\r
-  MemoryTableEntry = MemoryTable;\r
-  while (MemoryTableEntry->Length != 0) {\r
-    TopAddress = MemoryTableEntry->PhysicalBase + MemoryTableEntry->Length - 1;\r
-    if (TopAddress > MaxAddress) {\r
-      MaxAddress = TopAddress;\r
-    }\r
-    MemoryTableEntry++;\r
-  }\r
+  // Cover the entire GCD memory space\r
+  MaxAddress = (1UL << PcdGet8 (PcdPrePiCpuMemorySize)) - 1;\r
 \r
   // Lookup the Table Level to get the information\r
   LookupAddresstoRootTable (MaxAddress, &T0SZ, &RootTableEntryCount);\r
@@ -635,11 +627,35 @@ ArmConfigureMmu (
     return RETURN_UNSUPPORTED;\r
   }\r
 \r
+  //\r
+  // Translation table walks are always cache coherent on ARMv8-A, so cache\r
+  // maintenance on page tables is never needed. Since there is a risk of\r
+  // loss of coherency when using mismatched attributes, and given that memory\r
+  // is mapped cacheable except for extraordinary cases (such as non-coherent\r
+  // DMA), have the page table walker perform cached accesses as well, and\r
+  // assert below that that matches the attributes we use for CPU accesses to\r
+  // the region.\r
+  //\r
+  TCR |= TCR_SH_INNER_SHAREABLE |\r
+         TCR_RGN_OUTER_WRITE_BACK_ALLOC |\r
+         TCR_RGN_INNER_WRITE_BACK_ALLOC;\r
+\r
   // Set TCR\r
   ArmSetTCR (TCR);\r
 \r
-  // Allocate pages for translation table\r
-  TranslationTable = AllocatePages (1);\r
+  // Allocate pages for translation table. Pool allocations are 8 byte aligned,\r
+  // but we may require a higher alignment based on the size of the root table.\r
+  RootTableEntrySize = RootTableEntryCount * sizeof(UINT64);\r
+  if (RootTableEntrySize < EFI_PAGE_SIZE / 2) {\r
+    TranslationTableBuffer = AllocatePool (2 * RootTableEntrySize - 8);\r
+    //\r
+    // Naturally align the root table. Preserves possible NULL value\r
+    //\r
+    TranslationTable = (VOID *)((UINTN)(TranslationTableBuffer - 1) | (RootTableEntrySize - 1)) + 1;\r
+  } else {\r
+    TranslationTable = AllocatePages (1);\r
+    TranslationTableBuffer = NULL;\r
+  }\r
   if (TranslationTable == NULL) {\r
     return RETURN_OUT_OF_RESOURCES;\r
   }\r
@@ -653,10 +669,10 @@ ArmConfigureMmu (
   }\r
 \r
   if (TranslationTableSize != NULL) {\r
-    *TranslationTableSize = RootTableEntryCount * sizeof(UINT64);\r
+    *TranslationTableSize = RootTableEntrySize;\r
   }\r
 \r
-  ZeroMem (TranslationTable, RootTableEntryCount * sizeof(UINT64));\r
+  ZeroMem (TranslationTable, RootTableEntrySize);\r
 \r
   // Disable MMU and caches. ArmDisableMmu() also invalidates the TLBs\r
   ArmDisableMmu ();\r
@@ -669,11 +685,15 @@ ArmConfigureMmu (
 \r
   TranslationTableAttribute = TT_ATTR_INDX_INVALID;\r
   while (MemoryTable->Length != 0) {\r
-    // Find the memory attribute for the Translation Table\r
-    if (((UINTN)TranslationTable >= MemoryTable->PhysicalBase) &&\r
-        ((UINTN)TranslationTable <= MemoryTable->PhysicalBase - 1 + MemoryTable->Length)) {\r
-      TranslationTableAttribute = MemoryTable->Attributes;\r
-    }\r
+\r
+    DEBUG_CODE_BEGIN ();\r
+      // Find the memory attribute for the Translation Table\r
+      if ((UINTN)TranslationTable >= MemoryTable->PhysicalBase &&\r
+          (UINTN)TranslationTable + RootTableEntrySize <= MemoryTable->PhysicalBase +\r
+                                                          MemoryTable->Length) {\r
+        TranslationTableAttribute = MemoryTable->Attributes;\r
+      }\r
+    DEBUG_CODE_END ();\r
 \r
     Status = FillTranslationTable (TranslationTable, MemoryTable);\r
     if (RETURN_ERROR (Status)) {\r
@@ -682,26 +702,8 @@ ArmConfigureMmu (
     MemoryTable++;\r
   }\r
 \r
-  // Translate the Memory Attributes into Translation Table Register Attributes\r
-  if ((TranslationTableAttribute == ARM_MEMORY_REGION_ATTRIBUTE_UNCACHED_UNBUFFERED) ||\r
-      (TranslationTableAttribute == ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_UNCACHED_UNBUFFERED)) {\r
-    TCR |= TCR_SH_NON_SHAREABLE | TCR_RGN_OUTER_NON_CACHEABLE | TCR_RGN_INNER_NON_CACHEABLE;\r
-  } else if ((TranslationTableAttribute == ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK) ||\r
-      (TranslationTableAttribute == ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_WRITE_BACK)) {\r
-    TCR |= TCR_SH_INNER_SHAREABLE | TCR_RGN_OUTER_WRITE_BACK_ALLOC | TCR_RGN_INNER_WRITE_BACK_ALLOC;\r
-  } else if ((TranslationTableAttribute == ARM_MEMORY_REGION_ATTRIBUTE_WRITE_THROUGH) ||\r
-      (TranslationTableAttribute == ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_WRITE_THROUGH)) {\r
-    TCR |= TCR_SH_NON_SHAREABLE | TCR_RGN_OUTER_WRITE_THROUGH | TCR_RGN_INNER_WRITE_THROUGH;\r
-  } else {\r
-    // If we failed to find a mapping that contains the root translation table then it probably means the translation table\r
-    // is not mapped in the given memory map.\r
-    ASSERT (0);\r
-    Status = RETURN_UNSUPPORTED;\r
-    goto FREE_TRANSLATION_TABLE;\r
-  }\r
-\r
-  // Set again TCR after getting the Translation Table attributes\r
-  ArmSetTCR (TCR);\r
+  ASSERT (TranslationTableAttribute == ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK ||\r
+          TranslationTableAttribute == ARM_MEMORY_REGION_ATTRIBUTE_NONSECURE_WRITE_BACK);\r
 \r
   ArmSetMAIR (MAIR_ATTR(TT_ATTR_INDX_DEVICE_MEMORY, MAIR_ATTR_DEVICE_MEMORY) |                      // mapped to EFI_MEMORY_UC\r
               MAIR_ATTR(TT_ATTR_INDX_MEMORY_NON_CACHEABLE, MAIR_ATTR_NORMAL_MEMORY_NON_CACHEABLE) | // mapped to EFI_MEMORY_WC\r
@@ -716,7 +718,11 @@ ArmConfigureMmu (
   return RETURN_SUCCESS;\r
 \r
 FREE_TRANSLATION_TABLE:\r
-  FreePages (TranslationTable, 1);\r
+  if (TranslationTableBuffer != NULL) {\r
+    FreePool (TranslationTableBuffer);\r
+  } else {\r
+    FreePages (TranslationTable, 1);\r
+  }\r
   return Status;\r
 }\r
 \r