x86: EFI_PAGE_SHIFT fix
authorHuang, Ying <ying.huang@intel.com>
Mon, 25 Feb 2008 07:18:37 +0000 (15:18 +0800)
committerIngo Molnar <mingo@elte.hu>
Sat, 19 Apr 2008 17:19:54 +0000 (19:19 +0200)
Make x86 EFI code works when EFI_PAGE_SHIFT != PAGE_SHIFT. The
memrage_efi_to_native() provided in this patch can be used on other
EFI platform such as IA64 too.

This patch has been tested on Intel x86_64 platform with EFI 64/32
firmware.

Signed-off-by: Huang Ying <ying.huang@intel.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
arch/x86/kernel/efi.c
arch/x86/kernel/efi_64.c
include/linux/efi.h

index 759e02bec0708f955764907ec380e6eb737c6dfa..77d424cf68b38e6b919f55b6fd895436e887fd74 100644 (file)
@@ -383,6 +383,7 @@ static void __init runtime_code_page_mkexec(void)
 {
        efi_memory_desc_t *md;
        void *p;
+       u64 addr, npages;
 
        /* Make EFI runtime service code area executable */
        for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
@@ -391,7 +392,10 @@ static void __init runtime_code_page_mkexec(void)
                if (md->type != EFI_RUNTIME_SERVICES_CODE)
                        continue;
 
-               set_memory_x(md->virt_addr, md->num_pages);
+               addr = md->virt_addr;
+               npages = md->num_pages;
+               memrange_efi_to_native(&addr, &npages);
+               set_memory_x(addr, npages);
        }
 }
 
@@ -408,7 +412,7 @@ void __init efi_enter_virtual_mode(void)
        efi_memory_desc_t *md;
        efi_status_t status;
        unsigned long size;
-       u64 end, systab;
+       u64 end, systab, addr, npages;
        void *p, *va;
 
        efi.systab = NULL;
@@ -420,7 +424,7 @@ void __init efi_enter_virtual_mode(void)
                size = md->num_pages << EFI_PAGE_SHIFT;
                end = md->phys_addr + size;
 
-               if ((end >> PAGE_SHIFT) <= max_pfn_mapped)
+               if (PFN_UP(end) <= max_pfn_mapped)
                        va = __va(md->phys_addr);
                else
                        va = efi_ioremap(md->phys_addr, size);
@@ -433,8 +437,12 @@ void __init efi_enter_virtual_mode(void)
                        continue;
                }
 
-               if (!(md->attribute & EFI_MEMORY_WB))
-                       set_memory_uc(md->virt_addr, md->num_pages);
+               if (!(md->attribute & EFI_MEMORY_WB)) {
+                       addr = md->virt_addr;
+                       npages = md->num_pages;
+                       memrange_efi_to_native(&addr, &npages);
+                       set_memory_uc(addr, npages);
+               }
 
                systab = (u64) (unsigned long) efi_phys.systab;
                if (md->phys_addr <= systab && systab < end) {
index d143a1e76b301737c6fc34f2a0d6da656b787038..d0060fdcccac1658968db527f4c05d791b056e6b 100644 (file)
@@ -105,14 +105,14 @@ void __init efi_reserve_bootmem(void)
 
 void __iomem * __init efi_ioremap(unsigned long phys_addr, unsigned long size)
 {
-       static unsigned pages_mapped;
+       static unsigned pages_mapped __initdata;
        unsigned i, pages;
+       unsigned long offset;
 
-       /* phys_addr and size must be page aligned */
-       if ((phys_addr & ~PAGE_MASK) || (size & ~PAGE_MASK))
-               return NULL;
+       pages = PFN_UP(phys_addr + size) - PFN_DOWN(phys_addr);
+       offset = phys_addr & ~PAGE_MASK;
+       phys_addr &= PAGE_MASK;
 
-       pages = size >> PAGE_SHIFT;
        if (pages_mapped + pages > MAX_EFI_IO_PAGES)
                return NULL;
 
@@ -124,5 +124,5 @@ void __iomem * __init efi_ioremap(unsigned long phys_addr, unsigned long size)
        }
 
        return (void __iomem *)__fix_to_virt(FIX_EFI_IO_MAP_FIRST_PAGE - \
-                                            (pages_mapped - pages));
+                                            (pages_mapped - pages)) + offset;
 }
index 14813b5958022bbc608430999729b6519a58a246..a5f359a7ad0ef84d2829872f904f50014abe71f9 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/proc_fs.h>
 #include <linux/rtc.h>
 #include <linux/ioport.h>
+#include <linux/pfn.h>
 
 #include <asm/page.h>
 #include <asm/system.h>
@@ -394,4 +395,10 @@ struct efi_generic_dev_path {
        u16 length;
 } __attribute ((packed));
 
+static inline void memrange_efi_to_native(u64 *addr, u64 *npages)
+{
+       *npages = PFN_UP(*addr + (*npages<<EFI_PAGE_SHIFT)) - PFN_DOWN(*addr);
+       *addr &= PAGE_MASK;
+}
+
 #endif /* _LINUX_EFI_H */