x86: EFI: Back efi_ioremap with init_memory_mapping instead of FIX_MAP
authorHuang Ying <ying.huang@intel.com>
Wed, 4 Mar 2009 02:58:33 +0000 (10:58 +0800)
committerIngo Molnar <mingo@elte.hu>
Wed, 4 Mar 2009 18:20:16 +0000 (19:20 +0100)
Impact: Fix boot failure on EFI system with large runtime memory range

Brian Maly reported that some EFI system with large runtime memory
range can not boot. Because the FIX_MAP used to map runtime memory
range is smaller than run time memory range.

This patch fixes this issue by re-implement efi_ioremap() with
init_memory_mapping().

Reported-and-tested-by: Brian Maly <bmaly@redhat.com>
Signed-off-by: Huang Ying <ying.huang@intel.com>
Cc: Brian Maly <bmaly@redhat.com>
Cc: Yinghai Lu <yinghai@kernel.org>
LKML-Reference: <1236135513.6204.306.camel@yhuang-dev.sh.intel.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
arch/x86/include/asm/efi.h
arch/x86/include/asm/fixmap_64.h
arch/x86/kernel/efi.c
arch/x86/kernel/efi_64.c

index ca5ffb2856b6810ec399a48ec98cc36d020edd69..edc90f23e70814a80491b45db2409656c1b35be4 100644 (file)
@@ -37,8 +37,6 @@ extern unsigned long asmlinkage efi_call_phys(void *, ...);
 
 #else /* !CONFIG_X86_32 */
 
-#define MAX_EFI_IO_PAGES       100
-
 extern u64 efi_call0(void *fp);
 extern u64 efi_call1(void *fp, u64 arg1);
 extern u64 efi_call2(void *fp, u64 arg1, u64 arg2);
index 00a30ab9b1a5ba466a44c165e1d553d36a77cd19..8be740977db8eb3a4d82c8871830556c06850de4 100644 (file)
@@ -16,7 +16,6 @@
 #include <asm/apicdef.h>
 #include <asm/page.h>
 #include <asm/vsyscall.h>
-#include <asm/efi.h>
 
 /*
  * Here we define all the compile-time 'special' virtual
@@ -43,9 +42,6 @@ enum fixed_addresses {
        FIX_APIC_BASE,  /* local (CPU) APIC) -- required for SMP or not */
        FIX_IO_APIC_BASE_0,
        FIX_IO_APIC_BASE_END = FIX_IO_APIC_BASE_0 + MAX_IO_APICS - 1,
-       FIX_EFI_IO_MAP_LAST_PAGE,
-       FIX_EFI_IO_MAP_FIRST_PAGE = FIX_EFI_IO_MAP_LAST_PAGE
-                                 + MAX_EFI_IO_PAGES - 1,
 #ifdef CONFIG_PARAVIRT
        FIX_PARAVIRT_BOOTMAP,
 #endif
index 1119d247fe11d87aceaa2e42f770bd773a9c1ea2..eb1ef3b67dd50278c7ce88bd92f5895d7f06ede6 100644 (file)
@@ -467,7 +467,7 @@ void __init efi_enter_virtual_mode(void)
        efi_memory_desc_t *md;
        efi_status_t status;
        unsigned long size;
-       u64 end, systab, addr, npages;
+       u64 end, systab, addr, npages, end_pfn;
        void *p, *va;
 
        efi.systab = NULL;
@@ -479,7 +479,10 @@ void __init efi_enter_virtual_mode(void)
                size = md->num_pages << EFI_PAGE_SHIFT;
                end = md->phys_addr + size;
 
-               if (PFN_UP(end) <= max_low_pfn_mapped)
+               end_pfn = PFN_UP(end);
+               if (end_pfn <= max_low_pfn_mapped
+                   || (end_pfn > (1UL << (32 - PAGE_SHIFT))
+                       && end_pfn <= max_pfn_mapped))
                        va = __va(md->phys_addr);
                else
                        va = efi_ioremap(md->phys_addr, size);
index 652c5287215fdb9500e4013794d559cfc4ace801..cb783b92c50cce5b9d123c8bff127ba967a9b230 100644 (file)
@@ -99,24 +99,11 @@ void __init efi_call_phys_epilog(void)
 
 void __iomem *__init efi_ioremap(unsigned long phys_addr, unsigned long size)
 {
-       static unsigned pages_mapped __initdata;
-       unsigned i, pages;
-       unsigned long offset;
+       unsigned long last_map_pfn;
 
-       pages = PFN_UP(phys_addr + size) - PFN_DOWN(phys_addr);
-       offset = phys_addr & ~PAGE_MASK;
-       phys_addr &= PAGE_MASK;
-
-       if (pages_mapped + pages > MAX_EFI_IO_PAGES)
+       last_map_pfn = init_memory_mapping(phys_addr, phys_addr + size);
+       if ((last_map_pfn << PAGE_SHIFT) < phys_addr + size)
                return NULL;
 
-       for (i = 0; i < pages; i++) {
-               __set_fixmap(FIX_EFI_IO_MAP_FIRST_PAGE - pages_mapped,
-                            phys_addr, PAGE_KERNEL);
-               phys_addr += PAGE_SIZE;
-               pages_mapped++;
-       }
-
-       return (void __iomem *)__fix_to_virt(FIX_EFI_IO_MAP_FIRST_PAGE - \
-                                            (pages_mapped - pages)) + offset;
+       return (void __iomem *)__va(phys_addr);
 }