summaryrefslogtreecommitdiffstats
path: root/ArmPkg/Drivers
diff options
context:
space:
mode:
authorArd Biesheuvel <ard.biesheuvel@linaro.org>2017-03-02 10:36:13 +0000
committerArd Biesheuvel <ard.biesheuvel@linaro.org>2017-03-07 09:10:01 +0100
commitdf809efe13921326f2f8d7fc5654787b29ae8a8d (patch)
tree65347c3597b5808e096ee1eae01a82c7031aecc5 /ArmPkg/Drivers
parent5b0ce08a3ee87a9d3fd3ecabfb1a94b5a209fb6c (diff)
downloadedk2-df809efe13921326f2f8d7fc5654787b29ae8a8d.tar.gz
edk2-df809efe13921326f2f8d7fc5654787b29ae8a8d.tar.bz2
edk2-df809efe13921326f2f8d7fc5654787b29ae8a8d.zip
ArmPkg/CpuDxe ARM: avoid splitting page table sections unnecessarily
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>
Diffstat (limited to 'ArmPkg/Drivers')
-rw-r--r--ArmPkg/Drivers/CpuDxe/Arm/Mmu.c51
1 files changed, 43 insertions, 8 deletions
diff --git a/ArmPkg/Drivers/CpuDxe/Arm/Mmu.c b/ArmPkg/Drivers/CpuDxe/Arm/Mmu.c
index 89e429925b..16d6fcef9f 100644
--- a/ArmPkg/Drivers/CpuDxe/Arm/Mmu.c
+++ b/ArmPkg/Drivers/CpuDxe/Arm/Mmu.c
@@ -679,6 +679,11 @@ SetMemoryAttributes (
)
{
EFI_STATUS Status;
+ UINT64 ChunkLength;
+
+ if (Length == 0) {
+ return EFI_SUCCESS;
+ }
//
// Ignore invocations that only modify permission bits
@@ -687,14 +692,44 @@ SetMemoryAttributes (
return EFI_SUCCESS;
}
- if(((BaseAddress & 0xFFFFF) == 0) && ((Length & 0xFFFFF) == 0)) {
- // Is the base and length a multiple of 1 MB?
- DEBUG ((EFI_D_PAGE, "SetMemoryAttributes(): MMU section 0x%x length 0x%x to %lx\n", (UINTN)BaseAddress, (UINTN)Length, Attributes));
- Status = UpdateSectionEntries (BaseAddress, Length, Attributes, VirtualMask);
- } else {
- // Base and/or length is not a multiple of 1 MB
- DEBUG ((EFI_D_PAGE, "SetMemoryAttributes(): MMU page 0x%x length 0x%x to %lx\n", (UINTN)BaseAddress, (UINTN)Length, Attributes));
- Status = UpdatePageEntries (BaseAddress, Length, Attributes, VirtualMask);
+ while (Length > 0) {
+ if ((BaseAddress % TT_DESCRIPTOR_SECTION_SIZE == 0) &&
+ Length >= TT_DESCRIPTOR_SECTION_SIZE) {
+
+ ChunkLength = Length - Length % TT_DESCRIPTOR_SECTION_SIZE;
+
+ DEBUG ((DEBUG_PAGE,
+ "SetMemoryAttributes(): MMU section 0x%lx length 0x%lx to %lx\n",
+ BaseAddress, ChunkLength, Attributes));
+
+ Status = UpdateSectionEntries (BaseAddress, ChunkLength, Attributes,
+ VirtualMask);
+ } else {
+
+ //
+ // Process page by page until the next section boundary, but only if
+ // we have more than a section's worth of area to deal with after that.
+ //
+ ChunkLength = TT_DESCRIPTOR_SECTION_SIZE -
+ (BaseAddress % TT_DESCRIPTOR_SECTION_SIZE);
+ if (ChunkLength + TT_DESCRIPTOR_SECTION_SIZE > Length) {
+ ChunkLength = Length;
+ }
+
+ DEBUG ((DEBUG_PAGE,
+ "SetMemoryAttributes(): MMU page 0x%lx length 0x%lx to %lx\n",
+ BaseAddress, ChunkLength, Attributes));
+
+ Status = UpdatePageEntries (BaseAddress, ChunkLength, Attributes,
+ VirtualMask);
+ }
+
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ BaseAddress += ChunkLength;
+ Length -= ChunkLength;
}
// Flush d-cache so descriptors make it back to uncached memory for subsequent table walks