mirror of https://github.com/acidanthera/audk.git
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>
This commit is contained in:
parent
5b0ce08a3e
commit
df809efe13
|
@ -679,6 +679,11 @@ SetMemoryAttributes (
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
EFI_STATUS Status;
|
EFI_STATUS Status;
|
||||||
|
UINT64 ChunkLength;
|
||||||
|
|
||||||
|
if (Length == 0) {
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Ignore invocations that only modify permission bits
|
// Ignore invocations that only modify permission bits
|
||||||
|
@ -687,14 +692,44 @@ SetMemoryAttributes (
|
||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(((BaseAddress & 0xFFFFF) == 0) && ((Length & 0xFFFFF) == 0)) {
|
while (Length > 0) {
|
||||||
// Is the base and length a multiple of 1 MB?
|
if ((BaseAddress % TT_DESCRIPTOR_SECTION_SIZE == 0) &&
|
||||||
DEBUG ((EFI_D_PAGE, "SetMemoryAttributes(): MMU section 0x%x length 0x%x to %lx\n", (UINTN)BaseAddress, (UINTN)Length, Attributes));
|
Length >= TT_DESCRIPTOR_SECTION_SIZE) {
|
||||||
Status = UpdateSectionEntries (BaseAddress, Length, Attributes, VirtualMask);
|
|
||||||
} else {
|
ChunkLength = Length - Length % TT_DESCRIPTOR_SECTION_SIZE;
|
||||||
// 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));
|
DEBUG ((DEBUG_PAGE,
|
||||||
Status = UpdatePageEntries (BaseAddress, Length, Attributes, VirtualMask);
|
"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
|
// Flush d-cache so descriptors make it back to uncached memory for subsequent table walks
|
||||||
|
|
Loading…
Reference in New Issue