]> git.proxmox.com Git - mirror_edk2.git/commitdiff
ArmPkg/CpuDxe ARM: avoid splitting page table sections unnecessarily
authorArd Biesheuvel <ard.biesheuvel@linaro.org>
Thu, 2 Mar 2017 10:36:13 +0000 (10:36 +0000)
committerArd Biesheuvel <ard.biesheuvel@linaro.org>
Tue, 7 Mar 2017 08:10:01 +0000 (09:10 +0100)
Currently, any range passed to CpuArchProtocol::SetMemoryAttributes is
fully broken down into page mappings if the start or the size of the
region happens to be misaliged relative to the section size of 1 MB.

This is going to result in memory being wasted on second level page tables
when we enable strict memory permissions, given that we remap the entire
RAM space non-executable (modulo the code bits) when the CpuArchProtocol
is installed.

So refactor the code to iterate over the range in a way that ensures
that all naturally aligned section sized subregions are not broken up.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org>
ArmPkg/Drivers/CpuDxe/Arm/Mmu.c

index 89e429925ba92cf0ef6da7ea8eb9cd5135b2b5ce..16d6fcef9f1ca8cc09ffea0690ca6f7153d9c62f 100644 (file)
@@ -679,6 +679,11 @@ SetMemoryAttributes (
   )\r
 {\r
   EFI_STATUS    Status;\r
+  UINT64        ChunkLength;\r
+\r
+  if (Length == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
 \r
   //\r
   // Ignore invocations that only modify permission bits\r
@@ -687,14 +692,44 @@ SetMemoryAttributes (
     return EFI_SUCCESS;\r
   }\r
 \r
-  if(((BaseAddress & 0xFFFFF) == 0) && ((Length & 0xFFFFF) == 0)) {\r
-    // Is the base and length a multiple of 1 MB?\r
-    DEBUG ((EFI_D_PAGE, "SetMemoryAttributes(): MMU section 0x%x length 0x%x to %lx\n", (UINTN)BaseAddress, (UINTN)Length, Attributes));\r
-    Status = UpdateSectionEntries (BaseAddress, Length, Attributes, VirtualMask);\r
-  } else {\r
-    // Base and/or length is not a multiple of 1 MB\r
-    DEBUG ((EFI_D_PAGE, "SetMemoryAttributes(): MMU page 0x%x length 0x%x to %lx\n", (UINTN)BaseAddress, (UINTN)Length, Attributes));\r
-    Status = UpdatePageEntries (BaseAddress, Length, Attributes, VirtualMask);\r
+  while (Length > 0) {\r
+    if ((BaseAddress % TT_DESCRIPTOR_SECTION_SIZE == 0) &&\r
+        Length >= TT_DESCRIPTOR_SECTION_SIZE) {\r
+\r
+      ChunkLength = Length - Length % TT_DESCRIPTOR_SECTION_SIZE;\r
+\r
+      DEBUG ((DEBUG_PAGE,\r
+        "SetMemoryAttributes(): MMU section 0x%lx length 0x%lx to %lx\n",\r
+        BaseAddress, ChunkLength, Attributes));\r
+\r
+      Status = UpdateSectionEntries (BaseAddress, ChunkLength, Attributes,\r
+                 VirtualMask);\r
+    } else {\r
+\r
+      //\r
+      // Process page by page until the next section boundary, but only if\r
+      // we have more than a section's worth of area to deal with after that.\r
+      //\r
+      ChunkLength = TT_DESCRIPTOR_SECTION_SIZE -\r
+                    (BaseAddress % TT_DESCRIPTOR_SECTION_SIZE);\r
+      if (ChunkLength + TT_DESCRIPTOR_SECTION_SIZE > Length) {\r
+        ChunkLength = Length;\r
+      }\r
+\r
+      DEBUG ((DEBUG_PAGE,\r
+        "SetMemoryAttributes(): MMU page 0x%lx length 0x%lx to %lx\n",\r
+        BaseAddress, ChunkLength, Attributes));\r
+\r
+      Status = UpdatePageEntries (BaseAddress, ChunkLength, Attributes,\r
+                 VirtualMask);\r
+    }\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+\r
+    BaseAddress += ChunkLength;\r
+    Length -= ChunkLength;\r
   }\r
 \r
   // Flush d-cache so descriptors make it back to uncached memory for subsequent table walks\r