]> pilppa.org Git - linux-2.6-omap-h63xx.git/blob - arch/x86/kernel/efi_32.c
x86 boot: use E820 memory map on EFI 32 platform
[linux-2.6-omap-h63xx.git] / arch / x86 / kernel / efi_32.c
1 /*
2  * Extensible Firmware Interface
3  *
4  * Based on Extensible Firmware Interface Specification version 1.0
5  *
6  * Copyright (C) 1999 VA Linux Systems
7  * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
8  * Copyright (C) 1999-2002 Hewlett-Packard Co.
9  *      David Mosberger-Tang <davidm@hpl.hp.com>
10  *      Stephane Eranian <eranian@hpl.hp.com>
11  *
12  * All EFI Runtime Services are not implemented yet as EFI only
13  * supports physical mode addressing on SoftSDV. This is to be fixed
14  * in a future version.  --drummond 1999-07-20
15  *
16  * Implemented EFI runtime services and virtual mode calls.  --davidm
17  *
18  * Goutham Rao: <goutham.rao@intel.com>
19  *      Skip non-WB memory and ignore empty memory ranges.
20  */
21
22 #include <linux/kernel.h>
23 #include <linux/init.h>
24 #include <linux/mm.h>
25 #include <linux/types.h>
26 #include <linux/time.h>
27 #include <linux/spinlock.h>
28 #include <linux/bootmem.h>
29 #include <linux/ioport.h>
30 #include <linux/module.h>
31 #include <linux/efi.h>
32 #include <linux/kexec.h>
33
34 #include <asm/setup.h>
35 #include <asm/io.h>
36 #include <asm/page.h>
37 #include <asm/pgtable.h>
38 #include <asm/processor.h>
39 #include <asm/desc.h>
40 #include <asm/tlbflush.h>
41
42 #define PFX             "EFI: "
43
44 /*
45  * To make EFI call EFI runtime service in physical addressing mode we need
46  * prelog/epilog before/after the invocation to disable interrupt, to
47  * claim EFI runtime service handler exclusively and to duplicate a memory in
48  * low memory space say 0 - 3G.
49  */
50
51 static unsigned long efi_rt_eflags;
52 static DEFINE_SPINLOCK(efi_rt_lock);
53 static pgd_t efi_bak_pg_dir_pointer[2];
54
55 void efi_call_phys_prelog(void) __acquires(efi_rt_lock)
56 {
57         unsigned long cr4;
58         unsigned long temp;
59         struct desc_ptr gdt_descr;
60
61         spin_lock(&efi_rt_lock);
62         local_irq_save(efi_rt_eflags);
63
64         /*
65          * If I don't have PSE, I should just duplicate two entries in page
66          * directory. If I have PSE, I just need to duplicate one entry in
67          * page directory.
68          */
69         cr4 = read_cr4();
70
71         if (cr4 & X86_CR4_PSE) {
72                 efi_bak_pg_dir_pointer[0].pgd =
73                     swapper_pg_dir[pgd_index(0)].pgd;
74                 swapper_pg_dir[0].pgd =
75                     swapper_pg_dir[pgd_index(PAGE_OFFSET)].pgd;
76         } else {
77                 efi_bak_pg_dir_pointer[0].pgd =
78                     swapper_pg_dir[pgd_index(0)].pgd;
79                 efi_bak_pg_dir_pointer[1].pgd =
80                     swapper_pg_dir[pgd_index(0x400000)].pgd;
81                 swapper_pg_dir[pgd_index(0)].pgd =
82                     swapper_pg_dir[pgd_index(PAGE_OFFSET)].pgd;
83                 temp = PAGE_OFFSET + 0x400000;
84                 swapper_pg_dir[pgd_index(0x400000)].pgd =
85                     swapper_pg_dir[pgd_index(temp)].pgd;
86         }
87
88         /*
89          * After the lock is released, the original page table is restored.
90          */
91         local_flush_tlb();
92
93         gdt_descr.address = __pa(get_cpu_gdt_table(0));
94         gdt_descr.size = GDT_SIZE - 1;
95         load_gdt(&gdt_descr);
96 }
97
98 void efi_call_phys_epilog(void) __releases(efi_rt_lock)
99 {
100         unsigned long cr4;
101         struct desc_ptr gdt_descr;
102
103         gdt_descr.address = (unsigned long)get_cpu_gdt_table(0);
104         gdt_descr.size = GDT_SIZE - 1;
105         load_gdt(&gdt_descr);
106
107         cr4 = read_cr4();
108
109         if (cr4 & X86_CR4_PSE) {
110                 swapper_pg_dir[pgd_index(0)].pgd =
111                     efi_bak_pg_dir_pointer[0].pgd;
112         } else {
113                 swapper_pg_dir[pgd_index(0)].pgd =
114                     efi_bak_pg_dir_pointer[0].pgd;
115                 swapper_pg_dir[pgd_index(0x400000)].pgd =
116                     efi_bak_pg_dir_pointer[1].pgd;
117         }
118
119         /*
120          * After the lock is released, the original page table is restored.
121          */
122         local_flush_tlb();
123
124         local_irq_restore(efi_rt_eflags);
125         spin_unlock(&efi_rt_lock);
126 }
127
128 /*
129  * We need to map the EFI memory map again after paging_init().
130  */
131 void __init efi_map_memmap(void)
132 {
133         memmap.map = NULL;
134
135         memmap.map = bt_ioremap((unsigned long) memmap.phys_map,
136                         (memmap.nr_map * memmap.desc_size));
137         if (memmap.map == NULL)
138                 printk(KERN_ERR PFX "Could not remap the EFI memmap!\n");
139
140         memmap.map_end = memmap.map + (memmap.nr_map * memmap.desc_size);
141 }