x86: EFI: Back efi_ioremap with init_memory_mapping instead of FIX_MAP
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>
This commit is contained in:
parent
ff0c087490
commit
dd39ecf522
|
@ -37,8 +37,6 @@ extern unsigned long asmlinkage efi_call_phys(void *, ...);
|
||||||
|
|
||||||
#else /* !CONFIG_X86_32 */
|
#else /* !CONFIG_X86_32 */
|
||||||
|
|
||||||
#define MAX_EFI_IO_PAGES 100
|
|
||||||
|
|
||||||
extern u64 efi_call0(void *fp);
|
extern u64 efi_call0(void *fp);
|
||||||
extern u64 efi_call1(void *fp, u64 arg1);
|
extern u64 efi_call1(void *fp, u64 arg1);
|
||||||
extern u64 efi_call2(void *fp, u64 arg1, u64 arg2);
|
extern u64 efi_call2(void *fp, u64 arg1, u64 arg2);
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
#include <asm/apicdef.h>
|
#include <asm/apicdef.h>
|
||||||
#include <asm/page.h>
|
#include <asm/page.h>
|
||||||
#include <asm/vsyscall.h>
|
#include <asm/vsyscall.h>
|
||||||
#include <asm/efi.h>
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Here we define all the compile-time 'special' virtual
|
* 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_APIC_BASE, /* local (CPU) APIC) -- required for SMP or not */
|
||||||
FIX_IO_APIC_BASE_0,
|
FIX_IO_APIC_BASE_0,
|
||||||
FIX_IO_APIC_BASE_END = FIX_IO_APIC_BASE_0 + MAX_IO_APICS - 1,
|
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
|
#ifdef CONFIG_PARAVIRT
|
||||||
FIX_PARAVIRT_BOOTMAP,
|
FIX_PARAVIRT_BOOTMAP,
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -467,7 +467,7 @@ void __init efi_enter_virtual_mode(void)
|
||||||
efi_memory_desc_t *md;
|
efi_memory_desc_t *md;
|
||||||
efi_status_t status;
|
efi_status_t status;
|
||||||
unsigned long size;
|
unsigned long size;
|
||||||
u64 end, systab, addr, npages;
|
u64 end, systab, addr, npages, end_pfn;
|
||||||
void *p, *va;
|
void *p, *va;
|
||||||
|
|
||||||
efi.systab = NULL;
|
efi.systab = NULL;
|
||||||
|
@ -479,7 +479,10 @@ void __init efi_enter_virtual_mode(void)
|
||||||
size = md->num_pages << EFI_PAGE_SHIFT;
|
size = md->num_pages << EFI_PAGE_SHIFT;
|
||||||
end = md->phys_addr + size;
|
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);
|
va = __va(md->phys_addr);
|
||||||
else
|
else
|
||||||
va = efi_ioremap(md->phys_addr, size);
|
va = efi_ioremap(md->phys_addr, size);
|
||||||
|
|
|
@ -99,24 +99,11 @@ void __init efi_call_phys_epilog(void)
|
||||||
|
|
||||||
void __iomem *__init efi_ioremap(unsigned long phys_addr, unsigned long size)
|
void __iomem *__init efi_ioremap(unsigned long phys_addr, unsigned long size)
|
||||||
{
|
{
|
||||||
static unsigned pages_mapped __initdata;
|
unsigned long last_map_pfn;
|
||||||
unsigned i, pages;
|
|
||||||
unsigned long offset;
|
|
||||||
|
|
||||||
pages = PFN_UP(phys_addr + size) - PFN_DOWN(phys_addr);
|
last_map_pfn = init_memory_mapping(phys_addr, phys_addr + size);
|
||||||
offset = phys_addr & ~PAGE_MASK;
|
if ((last_map_pfn << PAGE_SHIFT) < phys_addr + size)
|
||||||
phys_addr &= PAGE_MASK;
|
|
||||||
|
|
||||||
if (pages_mapped + pages > MAX_EFI_IO_PAGES)
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
for (i = 0; i < pages; i++) {
|
return (void __iomem *)__va(phys_addr);
|
||||||
__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;
|
|
||||||
}
|
}
|
||||||
|
|
Reference in New Issue