]> err.no Git - linux-2.6/blob - arch/x86/kernel/efi_64.c
x86 boot: use E820 memory map on EFI 32 platform
[linux-2.6] / arch / x86 / kernel / efi_64.c
1 /*
2  * x86_64 specific EFI support functions
3  * Based on Extensible Firmware Interface Specification version 1.0
4  *
5  * Copyright (C) 2005-2008 Intel Co.
6  *      Fenghua Yu <fenghua.yu@intel.com>
7  *      Bibo Mao <bibo.mao@intel.com>
8  *      Chandramouli Narayanan <mouli@linux.intel.com>
9  *      Huang Ying <ying.huang@intel.com>
10  *
11  * Code to convert EFI to E820 map has been implemented in elilo bootloader
12  * based on a EFI patch by Edgar Hucek. Based on the E820 map, the page table
13  * is setup appropriately for EFI runtime code.
14  * - mouli 06/14/2007.
15  *
16  */
17
18 #include <linux/kernel.h>
19 #include <linux/init.h>
20 #include <linux/mm.h>
21 #include <linux/types.h>
22 #include <linux/spinlock.h>
23 #include <linux/bootmem.h>
24 #include <linux/ioport.h>
25 #include <linux/module.h>
26 #include <linux/efi.h>
27 #include <linux/uaccess.h>
28 #include <linux/io.h>
29 #include <linux/reboot.h>
30
31 #include <asm/setup.h>
32 #include <asm/page.h>
33 #include <asm/e820.h>
34 #include <asm/pgtable.h>
35 #include <asm/tlbflush.h>
36 #include <asm/cacheflush.h>
37 #include <asm/proto.h>
38 #include <asm/efi.h>
39
40 static pgd_t save_pgd __initdata;
41 static unsigned long efi_flags __initdata;
42
43 static int __init setup_noefi(char *arg)
44 {
45         efi_enabled = 0;
46         return 0;
47 }
48 early_param("noefi", setup_noefi);
49
50 static void __init early_mapping_set_exec(unsigned long start,
51                                           unsigned long end,
52                                           int executable)
53 {
54         pte_t *kpte;
55         int level;
56
57         while (start < end) {
58                 kpte = lookup_address((unsigned long)__va(start), &level);
59                 BUG_ON(!kpte);
60                 if (executable)
61                         set_pte(kpte, pte_mkexec(*kpte));
62                 else
63                         set_pte(kpte, __pte((pte_val(*kpte) | _PAGE_NX) & \
64                                             __supported_pte_mask));
65                 if (pte_huge(*kpte))
66                         start = (start + PMD_SIZE) & PMD_MASK;
67                 else
68                         start = (start + PAGE_SIZE) & PAGE_MASK;
69         }
70 }
71
72 static void __init early_runtime_code_mapping_set_exec(int executable)
73 {
74         efi_memory_desc_t *md;
75         void *p;
76
77         /* Make EFI runtime service code area executable */
78         for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
79                 md = p;
80                 if (md->type == EFI_RUNTIME_SERVICES_CODE) {
81                         unsigned long end;
82                         end = md->phys_addr + (md->num_pages << PAGE_SHIFT);
83                         early_mapping_set_exec(md->phys_addr, end, executable);
84                 }
85         }
86 }
87
88 void __init efi_call_phys_prelog(void)
89 {
90         unsigned long vaddress;
91
92         local_irq_save(efi_flags);
93         early_runtime_code_mapping_set_exec(1);
94         vaddress = (unsigned long)__va(0x0UL);
95         pgd_val(save_pgd) = pgd_val(*pgd_offset_k(0x0UL));
96         set_pgd(pgd_offset_k(0x0UL), *pgd_offset_k(vaddress));
97         __flush_tlb_all();
98 }
99
100 void __init efi_call_phys_epilog(void)
101 {
102         /*
103          * After the lock is released, the original page table is restored.
104          */
105         set_pgd(pgd_offset_k(0x0UL), save_pgd);
106         early_runtime_code_mapping_set_exec(0);
107         __flush_tlb_all();
108         local_irq_restore(efi_flags);
109 }
110
111 /*
112  * We need to map the EFI memory map again after init_memory_mapping().
113  */
114 void __init efi_map_memmap(void)
115 {
116         memmap.map = __va(memmap.phys_map);
117         memmap.map_end = memmap.map + (memmap.nr_map * memmap.desc_size);
118 }
119
120 void __init efi_reserve_bootmem(void)
121 {
122         reserve_bootmem_generic((unsigned long)memmap.phys_map,
123                                 memmap.nr_map * memmap.desc_size);
124 }
125
126 void __init runtime_code_page_mkexec(void)
127 {
128         efi_memory_desc_t *md;
129         void *p;
130
131         /* Make EFI runtime service code area executable */
132         for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
133                 md = p;
134                 if (md->type == EFI_RUNTIME_SERVICES_CODE)
135                         change_page_attr_addr(md->virt_addr,
136                                               md->num_pages,
137                                               PAGE_KERNEL_EXEC);
138         }
139         __flush_tlb_all();
140 }
141
142 void __iomem * __init efi_ioremap(unsigned long offset,
143                                   unsigned long size)
144 {
145         static unsigned pages_mapped;
146         unsigned long last_addr;
147         unsigned i, pages;
148
149         last_addr = offset + size - 1;
150         offset &= PAGE_MASK;
151         pages = (PAGE_ALIGN(last_addr) - offset) >> PAGE_SHIFT;
152         if (pages_mapped + pages > MAX_EFI_IO_PAGES)
153                 return NULL;
154
155         for (i = 0; i < pages; i++) {
156                 set_fixmap_nocache(FIX_EFI_IO_MAP_FIRST_PAGE - pages_mapped,
157                                    offset);
158                 offset += PAGE_SIZE;
159                 pages_mapped++;
160         }
161
162         return (void __iomem *)__fix_to_virt(FIX_EFI_IO_MAP_FIRST_PAGE - \
163                                              (pages_mapped - pages));
164 }