Commit | Line | Data |
---|---|---|
1da177e4 LT |
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 | ||
1da177e4 LT |
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> | |
1bc3b91a | 32 | #include <linux/kexec.h> |
1da177e4 LT |
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 | ||
1da177e4 LT |
42 | #define PFX "EFI: " |
43 | ||
1da177e4 LT |
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 | ||
e429795c | 55 | void efi_call_phys_prelog(void) __acquires(efi_rt_lock) |
1da177e4 LT |
56 | { |
57 | unsigned long cr4; | |
58 | unsigned long temp; | |
6b68f01b | 59 | struct desc_ptr gdt_descr; |
1da177e4 LT |
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 | */ | |
4bb0d3ec | 69 | cr4 = read_cr4(); |
1da177e4 LT |
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 | ||
4fbb5968 RR |
93 | gdt_descr.address = __pa(get_cpu_gdt_table(0)); |
94 | gdt_descr.size = GDT_SIZE - 1; | |
95 | load_gdt(&gdt_descr); | |
1da177e4 LT |
96 | } |
97 | ||
e429795c | 98 | void efi_call_phys_epilog(void) __releases(efi_rt_lock) |
1da177e4 LT |
99 | { |
100 | unsigned long cr4; | |
6b68f01b | 101 | struct desc_ptr gdt_descr; |
1da177e4 | 102 | |
4fbb5968 RR |
103 | gdt_descr.address = (unsigned long)get_cpu_gdt_table(0); |
104 | gdt_descr.size = GDT_SIZE - 1; | |
105 | load_gdt(&gdt_descr); | |
2b932f6c | 106 | |
4bb0d3ec | 107 | cr4 = read_cr4(); |
1da177e4 LT |
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 | ||
1da177e4 LT |
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 | ||
7ae65fd3 MT |
135 | memmap.map = bt_ioremap((unsigned long) memmap.phys_map, |
136 | (memmap.nr_map * memmap.desc_size)); | |
1da177e4 LT |
137 | if (memmap.map == NULL) |
138 | printk(KERN_ERR PFX "Could not remap the EFI memmap!\n"); | |
7ae65fd3 MT |
139 | |
140 | memmap.map_end = memmap.map + (memmap.nr_map * memmap.desc_size); | |
1da177e4 | 141 | } |