]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ArmPkg/Drivers/CpuDxe/Arm/Mmu.c
ArmPkg/CpuDxe ARM: avoid unnecessary cache/TLB maintenance
[mirror_edk2.git] / ArmPkg / Drivers / CpuDxe / Arm / Mmu.c
index 16d6fcef9f1ca8cc09ffea0690ca6f7153d9c62f..a2993cf16a35eb95cc36edd6ac5cf4d43117aec3 100644 (file)
@@ -347,10 +347,11 @@ SyncCacheConfig (
 \r
 EFI_STATUS\r
 UpdatePageEntries (\r
-  IN EFI_PHYSICAL_ADDRESS      BaseAddress,\r
-  IN UINT64                    Length,\r
-  IN UINT64                    Attributes,\r
-  IN EFI_PHYSICAL_ADDRESS      VirtualMask\r
+  IN  EFI_PHYSICAL_ADDRESS      BaseAddress,\r
+  IN  UINT64                    Length,\r
+  IN  UINT64                    Attributes,\r
+  IN  EFI_PHYSICAL_ADDRESS      VirtualMask,\r
+  OUT BOOLEAN                   *FlushTlbs OPTIONAL\r
   )\r
 {\r
   EFI_STATUS    Status;\r
@@ -446,6 +447,9 @@ UpdatePageEntries (
 \r
       // Re-read descriptor\r
       Descriptor = FirstLevelTable[FirstLevelIdx];\r
+      if (FlushTlbs != NULL) {\r
+        *FlushTlbs = TRUE;\r
+      }\r
     }\r
 \r
     // Obtain page table base address\r
@@ -471,15 +475,16 @@ UpdatePageEntries (
 \r
     if (CurrentPageTableEntry  != PageTableEntry) {\r
       Mva = (VOID *)(UINTN)((((UINTN)FirstLevelIdx) << TT_DESCRIPTOR_SECTION_BASE_SHIFT) + (PageTableIndex << TT_DESCRIPTOR_PAGE_BASE_SHIFT));\r
-      if ((CurrentPageTableEntry & TT_DESCRIPTOR_PAGE_CACHEABLE_MASK) == TT_DESCRIPTOR_PAGE_CACHEABLE_MASK) {\r
-        // The current section mapping is cacheable so Clean/Invalidate the MVA of the page\r
-        // Note assumes switch(Attributes), not ARMv7 possibilities\r
-        WriteBackInvalidateDataCacheRange (Mva, TT_DESCRIPTOR_PAGE_SIZE);\r
-      }\r
 \r
       // Only need to update if we are changing the entry\r
       PageTable[PageTableIndex] = PageTableEntry;\r
       ArmUpdateTranslationTableEntry ((VOID *)&PageTable[PageTableIndex], Mva);\r
+\r
+      // Clean/invalidate the cache for this page, but only\r
+      // if we are modifying the memory type attributes\r
+      if (((CurrentPageTableEntry ^ PageTableEntry) & TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK) != 0) {\r
+        WriteBackInvalidateDataCacheRange (Mva, TT_DESCRIPTOR_PAGE_SIZE);\r
+      }\r
     }\r
 \r
     Status = EFI_SUCCESS;\r
@@ -581,7 +586,12 @@ UpdateSectionEntries (
     // has this descriptor already been coverted to pages?\r
     if (TT_DESCRIPTOR_SECTION_TYPE_IS_PAGE_TABLE(CurrentDescriptor)) {\r
       // forward this 1MB range to page table function instead\r
-      Status = UpdatePageEntries ((FirstLevelIdx + i) << TT_DESCRIPTOR_SECTION_BASE_SHIFT, TT_DESCRIPTOR_SECTION_SIZE, Attributes, VirtualMask);\r
+      Status = UpdatePageEntries (\r
+                 (FirstLevelIdx + i) << TT_DESCRIPTOR_SECTION_BASE_SHIFT,\r
+                 TT_DESCRIPTOR_SECTION_SIZE,\r
+                 Attributes,\r
+                 VirtualMask,\r
+                 NULL);\r
     } else {\r
       // still a section entry\r
 \r
@@ -596,15 +606,16 @@ UpdateSectionEntries (
 \r
       if (CurrentDescriptor  != Descriptor) {\r
         Mva = (VOID *)(UINTN)(((UINTN)FirstLevelTable) << TT_DESCRIPTOR_SECTION_BASE_SHIFT);\r
-        if ((CurrentDescriptor & TT_DESCRIPTOR_SECTION_CACHEABLE_MASK) == TT_DESCRIPTOR_SECTION_CACHEABLE_MASK) {\r
-          // The current section mapping is cacheable so Clean/Invalidate the MVA of the section\r
-          // Note assumes switch(Attributes), not ARMv7 possabilities\r
-          WriteBackInvalidateDataCacheRange (Mva, SIZE_1MB);\r
-        }\r
 \r
         // Only need to update if we are changing the descriptor\r
         FirstLevelTable[FirstLevelIdx + i] = Descriptor;\r
         ArmUpdateTranslationTableEntry ((VOID *)&FirstLevelTable[FirstLevelIdx + i], Mva);\r
+\r
+        // Clean/invalidate the cache for this section, but only\r
+        // if we are modifying the memory type attributes\r
+        if (((CurrentDescriptor ^ Descriptor) & TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK) != 0) {\r
+          WriteBackInvalidateDataCacheRange (Mva, SIZE_1MB);\r
+        }\r
       }\r
 \r
       Status = EFI_SUCCESS;\r
@@ -680,6 +691,7 @@ SetMemoryAttributes (
 {\r
   EFI_STATUS    Status;\r
   UINT64        ChunkLength;\r
+  BOOLEAN       FlushTlbs;\r
 \r
   if (Length == 0) {\r
     return EFI_SUCCESS;\r
@@ -692,6 +704,7 @@ SetMemoryAttributes (
     return EFI_SUCCESS;\r
   }\r
 \r
+  FlushTlbs = FALSE;\r
   while (Length > 0) {\r
     if ((BaseAddress % TT_DESCRIPTOR_SECTION_SIZE == 0) &&\r
         Length >= TT_DESCRIPTOR_SECTION_SIZE) {\r
@@ -704,6 +717,8 @@ SetMemoryAttributes (
 \r
       Status = UpdateSectionEntries (BaseAddress, ChunkLength, Attributes,\r
                  VirtualMask);\r
+\r
+      FlushTlbs = TRUE;\r
     } else {\r
 \r
       //\r
@@ -721,7 +736,7 @@ SetMemoryAttributes (
         BaseAddress, ChunkLength, Attributes));\r
 \r
       Status = UpdatePageEntries (BaseAddress, ChunkLength, Attributes,\r
-                 VirtualMask);\r
+                 VirtualMask, &FlushTlbs);\r
     }\r
 \r
     if (EFI_ERROR (Status)) {\r
@@ -732,16 +747,9 @@ SetMemoryAttributes (
     Length -= ChunkLength;\r
   }\r
 \r
-  // Flush d-cache so descriptors make it back to uncached memory for subsequent table walks\r
-  // flush and invalidate pages\r
-  //TODO: Do we really need to invalidate the caches everytime we change the memory attributes ?\r
-  ArmCleanInvalidateDataCache ();\r
-\r
-  ArmInvalidateInstructionCache ();\r
-\r
-  // Invalidate all TLB entries so changes are synced\r
-  ArmInvalidateTlb ();\r
-\r
+  if (FlushTlbs) {\r
+    ArmInvalidateTlb ();\r
+  }\r
   return Status;\r
 }\r
 \r