Commit 202f9d0a authored by Matthew Garrett's avatar Matthew Garrett Committed by H. Peter Anvin

x86, efi: Merge contiguous memory regions of the same type and attribute

Some firmware implementations assume that physically contiguous regions
will be contiguous in virtual address space. This assumption is, obviously,
entirely unjustifiable. Said firmware implementations lack the good grace
to handle their failings in a measured and reasonable manner, instead
tending to shit all over address space and oopsing the kernel.

In an ideal universe these firmware implementations would simultaneously
catch fire and cease to be a problem, but since some of them are present
in attractively thin and shiny metal devices vanity wins out and some
poor developer spends an extended period of time surrounded by a
growing array of empty bottles until the underlying reason becomes
apparent. Said developer presents this patch, which simply merges
adjacent regions if they happen to be contiguous and have the same EFI
memory type and caching attributes.
Signed-off-by: default avatarMatthew Garrett <mjg@redhat.com>
Link: http://lkml.kernel.org/r/1304623186-18261-3-git-send-email-mjg@redhat.comSigned-off-by: default avatarH. Peter Anvin <hpa@linux.intel.com>
parent 9cd2b07c
...@@ -498,13 +498,41 @@ static void __init runtime_code_page_mkexec(void) ...@@ -498,13 +498,41 @@ static void __init runtime_code_page_mkexec(void)
*/ */
void __init efi_enter_virtual_mode(void) void __init efi_enter_virtual_mode(void)
{ {
efi_memory_desc_t *md; efi_memory_desc_t *md, *prev_md = NULL;
efi_status_t status; efi_status_t status;
unsigned long size; unsigned long size;
u64 end, systab, addr, npages, end_pfn; u64 end, systab, addr, npages, end_pfn;
void *p, *va; void *p, *va;
efi.systab = NULL; efi.systab = NULL;
/* Merge contiguous regions of the same type and attribute */
for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
u64 prev_size;
md = p;
if (!prev_md) {
prev_md = md;
continue;
}
if (prev_md->type != md->type ||
prev_md->attribute != md->attribute) {
prev_md = md;
continue;
}
prev_size = prev_md->num_pages << EFI_PAGE_SHIFT;
if (md->phys_addr == (prev_md->phys_addr + prev_size)) {
prev_md->num_pages += md->num_pages;
md->type = EFI_RESERVED_TYPE;
md->attribute = 0;
continue;
}
prev_md = md;
}
for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
md = p; md = p;
if (!(md->attribute & EFI_MEMORY_RUNTIME)) if (!(md->attribute & EFI_MEMORY_RUNTIME))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment