aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/platform
diff options
context:
space:
mode:
authorMatthew Garrett <mjg@redhat.com>2011-05-05 15:19:44 -0400
committerH. Peter Anvin <hpa@linux.intel.com>2011-05-09 15:14:34 -0400
commit202f9d0a41809e3424af5f61489b48b622824aed (patch)
treebc599572343d4d5a903a64ab3c5ed14739c1880c /arch/x86/platform
parent9cd2b07c197e3ff594fc04f5fb3d86efbeab6ad8 (diff)
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: Matthew Garrett <mjg@redhat.com> Link: http://lkml.kernel.org/r/1304623186-18261-3-git-send-email-mjg@redhat.com Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Diffstat (limited to 'arch/x86/platform')
-rw-r--r--arch/x86/platform/efi/efi.c30
1 files changed, 29 insertions, 1 deletions
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index 7daae27e975..a46a73ecc5f 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -498,13 +498,41 @@ static void __init runtime_code_page_mkexec(void)
498 */ 498 */
499void __init efi_enter_virtual_mode(void) 499void __init efi_enter_virtual_mode(void)
500{ 500{
501 efi_memory_desc_t *md; 501 efi_memory_desc_t *md, *prev_md = NULL;
502 efi_status_t status; 502 efi_status_t status;
503 unsigned long size; 503 unsigned long size;
504 u64 end, systab, addr, npages, end_pfn; 504 u64 end, systab, addr, npages, end_pfn;
505 void *p, *va; 505 void *p, *va;
506 506
507 efi.systab = NULL; 507 efi.systab = NULL;
508
509 /* Merge contiguous regions of the same type and attribute */
510 for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
511 u64 prev_size;
512 md = p;
513
514 if (!prev_md) {
515 prev_md = md;
516 continue;
517 }
518
519 if (prev_md->type != md->type ||
520 prev_md->attribute != md->attribute) {
521 prev_md = md;
522 continue;
523 }
524
525 prev_size = prev_md->num_pages << EFI_PAGE_SHIFT;
526
527 if (md->phys_addr == (prev_md->phys_addr + prev_size)) {
528 prev_md->num_pages += md->num_pages;
529 md->type = EFI_RESERVED_TYPE;
530 md->attribute = 0;
531 continue;
532 }
533 prev_md = md;
534 }
535
508 for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { 536 for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
509 md = p; 537 md = p;
510 if (!(md->attribute & EFI_MEMORY_RUNTIME)) 538 if (!(md->attribute & EFI_MEMORY_RUNTIME))