]>
Commit | Line | Data |
---|---|---|
d3561b7f RR |
1 | /* Paravirtualization interfaces |
2 | Copyright (C) 2006 Rusty Russell IBM Corporation | |
3 | ||
4 | This program is free software; you can redistribute it and/or modify | |
5 | it under the terms of the GNU General Public License as published by | |
6 | the Free Software Foundation; either version 2 of the License, or | |
7 | (at your option) any later version. | |
8 | ||
9 | This program is distributed in the hope that it will be useful, | |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | GNU General Public License for more details. | |
13 | ||
14 | You should have received a copy of the GNU General Public License | |
15 | along with this program; if not, write to the Free Software | |
16 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
17 | */ | |
18 | #include <linux/errno.h> | |
19 | #include <linux/module.h> | |
20 | #include <linux/efi.h> | |
21 | #include <linux/bcd.h> | |
c9ccf30d | 22 | #include <linux/start_kernel.h> |
d3561b7f RR |
23 | |
24 | #include <asm/bug.h> | |
25 | #include <asm/paravirt.h> | |
26 | #include <asm/desc.h> | |
27 | #include <asm/setup.h> | |
28 | #include <asm/arch_hooks.h> | |
29 | #include <asm/time.h> | |
30 | #include <asm/irq.h> | |
31 | #include <asm/delay.h> | |
13623d79 RR |
32 | #include <asm/fixmap.h> |
33 | #include <asm/apic.h> | |
da181a8b | 34 | #include <asm/tlbflush.h> |
6cb9a835 | 35 | #include <asm/timer.h> |
d3561b7f RR |
36 | |
37 | /* nop stub */ | |
45876233 | 38 | void _paravirt_nop(void) |
d3561b7f RR |
39 | { |
40 | } | |
41 | ||
42 | static void __init default_banner(void) | |
43 | { | |
44 | printk(KERN_INFO "Booting paravirtualized kernel on %s\n", | |
45 | paravirt_ops.name); | |
46 | } | |
47 | ||
48 | char *memory_setup(void) | |
49 | { | |
50 | return paravirt_ops.memory_setup(); | |
51 | } | |
52 | ||
139ec7c4 RR |
53 | /* Simple instruction patching code. */ |
54 | #define DEF_NATIVE(name, code) \ | |
55 | extern const char start_##name[], end_##name[]; \ | |
56 | asm("start_" #name ": " code "; end_" #name ":") | |
57 | DEF_NATIVE(cli, "cli"); | |
58 | DEF_NATIVE(sti, "sti"); | |
59 | DEF_NATIVE(popf, "push %eax; popf"); | |
60 | DEF_NATIVE(pushf, "pushf; pop %eax"); | |
61 | DEF_NATIVE(pushf_cli, "pushf; pop %eax; cli"); | |
62 | DEF_NATIVE(iret, "iret"); | |
63 | DEF_NATIVE(sti_sysexit, "sti; sysexit"); | |
64 | ||
65 | static const struct native_insns | |
66 | { | |
67 | const char *start, *end; | |
68 | } native_insns[] = { | |
69 | [PARAVIRT_IRQ_DISABLE] = { start_cli, end_cli }, | |
70 | [PARAVIRT_IRQ_ENABLE] = { start_sti, end_sti }, | |
71 | [PARAVIRT_RESTORE_FLAGS] = { start_popf, end_popf }, | |
72 | [PARAVIRT_SAVE_FLAGS] = { start_pushf, end_pushf }, | |
73 | [PARAVIRT_SAVE_FLAGS_IRQ_DISABLE] = { start_pushf_cli, end_pushf_cli }, | |
74 | [PARAVIRT_INTERRUPT_RETURN] = { start_iret, end_iret }, | |
75 | [PARAVIRT_STI_SYSEXIT] = { start_sti_sysexit, end_sti_sysexit }, | |
76 | }; | |
77 | ||
78 | static unsigned native_patch(u8 type, u16 clobbers, void *insns, unsigned len) | |
79 | { | |
80 | unsigned int insn_len; | |
81 | ||
82 | /* Don't touch it if we don't have a replacement */ | |
83 | if (type >= ARRAY_SIZE(native_insns) || !native_insns[type].start) | |
84 | return len; | |
85 | ||
86 | insn_len = native_insns[type].end - native_insns[type].start; | |
87 | ||
88 | /* Similarly if we can't fit replacement. */ | |
89 | if (len < insn_len) | |
90 | return len; | |
91 | ||
92 | memcpy(insns, native_insns[type].start, insn_len); | |
93 | return insn_len; | |
94 | } | |
95 | ||
d3561b7f RR |
96 | void init_IRQ(void) |
97 | { | |
98 | paravirt_ops.init_IRQ(); | |
99 | } | |
100 | ||
1a1eecd1 | 101 | static void native_flush_tlb(void) |
da181a8b RR |
102 | { |
103 | __native_flush_tlb(); | |
104 | } | |
105 | ||
106 | /* | |
107 | * Global pages have to be flushed a bit differently. Not a real | |
108 | * performance problem because this does not happen often. | |
109 | */ | |
1a1eecd1 | 110 | static void native_flush_tlb_global(void) |
da181a8b RR |
111 | { |
112 | __native_flush_tlb_global(); | |
113 | } | |
114 | ||
1a1eecd1 | 115 | static void native_flush_tlb_single(u32 addr) |
da181a8b RR |
116 | { |
117 | __native_flush_tlb_single(addr); | |
118 | } | |
119 | ||
120 | #ifndef CONFIG_X86_PAE | |
1a1eecd1 | 121 | static void native_set_pte(pte_t *ptep, pte_t pteval) |
da181a8b RR |
122 | { |
123 | *ptep = pteval; | |
124 | } | |
125 | ||
1a1eecd1 | 126 | static void native_set_pte_at(struct mm_struct *mm, u32 addr, pte_t *ptep, pte_t pteval) |
da181a8b RR |
127 | { |
128 | *ptep = pteval; | |
129 | } | |
130 | ||
1a1eecd1 | 131 | static void native_set_pmd(pmd_t *pmdp, pmd_t pmdval) |
da181a8b RR |
132 | { |
133 | *pmdp = pmdval; | |
134 | } | |
135 | ||
136 | #else /* CONFIG_X86_PAE */ | |
137 | ||
1a1eecd1 | 138 | static void native_set_pte(pte_t *ptep, pte_t pte) |
da181a8b RR |
139 | { |
140 | ptep->pte_high = pte.pte_high; | |
141 | smp_wmb(); | |
142 | ptep->pte_low = pte.pte_low; | |
143 | } | |
144 | ||
1a1eecd1 | 145 | static void native_set_pte_at(struct mm_struct *mm, u32 addr, pte_t *ptep, pte_t pte) |
da181a8b RR |
146 | { |
147 | ptep->pte_high = pte.pte_high; | |
148 | smp_wmb(); | |
149 | ptep->pte_low = pte.pte_low; | |
150 | } | |
151 | ||
1a1eecd1 | 152 | static void native_set_pte_present(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte) |
da181a8b RR |
153 | { |
154 | ptep->pte_low = 0; | |
155 | smp_wmb(); | |
156 | ptep->pte_high = pte.pte_high; | |
157 | smp_wmb(); | |
158 | ptep->pte_low = pte.pte_low; | |
159 | } | |
160 | ||
1a1eecd1 | 161 | static void native_set_pte_atomic(pte_t *ptep, pte_t pteval) |
da181a8b RR |
162 | { |
163 | set_64bit((unsigned long long *)ptep,pte_val(pteval)); | |
164 | } | |
165 | ||
1a1eecd1 | 166 | static void native_set_pmd(pmd_t *pmdp, pmd_t pmdval) |
da181a8b RR |
167 | { |
168 | set_64bit((unsigned long long *)pmdp,pmd_val(pmdval)); | |
169 | } | |
170 | ||
1a1eecd1 | 171 | static void native_set_pud(pud_t *pudp, pud_t pudval) |
da181a8b RR |
172 | { |
173 | *pudp = pudval; | |
174 | } | |
175 | ||
1a1eecd1 | 176 | static void native_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) |
da181a8b RR |
177 | { |
178 | ptep->pte_low = 0; | |
179 | smp_wmb(); | |
180 | ptep->pte_high = 0; | |
181 | } | |
182 | ||
1a1eecd1 | 183 | static void native_pmd_clear(pmd_t *pmd) |
da181a8b RR |
184 | { |
185 | u32 *tmp = (u32 *)pmd; | |
186 | *tmp = 0; | |
187 | smp_wmb(); | |
188 | *(tmp + 1) = 0; | |
189 | } | |
190 | #endif /* CONFIG_X86_PAE */ | |
191 | ||
d3561b7f | 192 | /* These are in entry.S */ |
1a1eecd1 AK |
193 | extern void native_iret(void); |
194 | extern void native_irq_enable_sysexit(void); | |
d3561b7f RR |
195 | |
196 | static int __init print_banner(void) | |
197 | { | |
198 | paravirt_ops.banner(); | |
199 | return 0; | |
200 | } | |
201 | core_initcall(print_banner); | |
202 | ||
203 | struct paravirt_ops paravirt_ops = { | |
204 | .name = "bare hardware", | |
205 | .paravirt_enabled = 0, | |
206 | .kernel_rpl = 0, | |
207 | ||
139ec7c4 | 208 | .patch = native_patch, |
d3561b7f | 209 | .banner = default_banner, |
45876233 | 210 | .arch_setup = paravirt_nop, |
d3561b7f RR |
211 | .memory_setup = machine_specific_memory_setup, |
212 | .get_wallclock = native_get_wallclock, | |
213 | .set_wallclock = native_set_wallclock, | |
e30fab3a | 214 | .time_init = hpet_time_init, |
d3561b7f RR |
215 | .init_IRQ = native_init_IRQ, |
216 | ||
217 | .cpuid = native_cpuid, | |
218 | .get_debugreg = native_get_debugreg, | |
219 | .set_debugreg = native_set_debugreg, | |
220 | .clts = native_clts, | |
221 | .read_cr0 = native_read_cr0, | |
222 | .write_cr0 = native_write_cr0, | |
223 | .read_cr2 = native_read_cr2, | |
224 | .write_cr2 = native_write_cr2, | |
225 | .read_cr3 = native_read_cr3, | |
226 | .write_cr3 = native_write_cr3, | |
227 | .read_cr4 = native_read_cr4, | |
228 | .read_cr4_safe = native_read_cr4_safe, | |
229 | .write_cr4 = native_write_cr4, | |
230 | .save_fl = native_save_fl, | |
231 | .restore_fl = native_restore_fl, | |
232 | .irq_disable = native_irq_disable, | |
233 | .irq_enable = native_irq_enable, | |
234 | .safe_halt = native_safe_halt, | |
235 | .halt = native_halt, | |
236 | .wbinvd = native_wbinvd, | |
90a0a06a RR |
237 | .read_msr = native_read_msr_safe, |
238 | .write_msr = native_write_msr_safe, | |
d3561b7f RR |
239 | .read_tsc = native_read_tsc, |
240 | .read_pmc = native_read_pmc, | |
6cb9a835 | 241 | .get_scheduled_cycles = native_read_tsc, |
1182d852 | 242 | .get_cpu_khz = native_calculate_cpu_khz, |
d3561b7f RR |
243 | .load_tr_desc = native_load_tr_desc, |
244 | .set_ldt = native_set_ldt, | |
245 | .load_gdt = native_load_gdt, | |
246 | .load_idt = native_load_idt, | |
247 | .store_gdt = native_store_gdt, | |
248 | .store_idt = native_store_idt, | |
249 | .store_tr = native_store_tr, | |
250 | .load_tls = native_load_tls, | |
90a0a06a RR |
251 | .write_ldt_entry = write_dt_entry, |
252 | .write_gdt_entry = write_dt_entry, | |
253 | .write_idt_entry = write_dt_entry, | |
d3561b7f RR |
254 | .load_esp0 = native_load_esp0, |
255 | ||
256 | .set_iopl_mask = native_set_iopl_mask, | |
257 | .io_delay = native_io_delay, | |
d3561b7f | 258 | |
13623d79 RR |
259 | #ifdef CONFIG_X86_LOCAL_APIC |
260 | .apic_write = native_apic_write, | |
261 | .apic_write_atomic = native_apic_write_atomic, | |
262 | .apic_read = native_apic_read, | |
bbab4f3b ZA |
263 | .setup_boot_clock = setup_boot_APIC_clock, |
264 | .setup_secondary_clock = setup_secondary_APIC_clock, | |
13623d79 | 265 | #endif |
45876233 | 266 | .set_lazy_mode = paravirt_nop, |
13623d79 | 267 | |
da181a8b RR |
268 | .flush_tlb_user = native_flush_tlb, |
269 | .flush_tlb_kernel = native_flush_tlb_global, | |
270 | .flush_tlb_single = native_flush_tlb_single, | |
271 | ||
45876233 | 272 | .map_pt_hook = paravirt_nop, |
9a1c13e9 | 273 | |
45876233 JF |
274 | .alloc_pt = paravirt_nop, |
275 | .alloc_pd = paravirt_nop, | |
276 | .alloc_pd_clone = paravirt_nop, | |
277 | .release_pt = paravirt_nop, | |
278 | .release_pd = paravirt_nop, | |
c119ecce | 279 | |
da181a8b RR |
280 | .set_pte = native_set_pte, |
281 | .set_pte_at = native_set_pte_at, | |
282 | .set_pmd = native_set_pmd, | |
45876233 JF |
283 | .pte_update = paravirt_nop, |
284 | .pte_update_defer = paravirt_nop, | |
da181a8b RR |
285 | #ifdef CONFIG_X86_PAE |
286 | .set_pte_atomic = native_set_pte_atomic, | |
287 | .set_pte_present = native_set_pte_present, | |
288 | .set_pud = native_set_pud, | |
289 | .pte_clear = native_pte_clear, | |
290 | .pmd_clear = native_pmd_clear, | |
291 | #endif | |
292 | ||
d3561b7f RR |
293 | .irq_enable_sysexit = native_irq_enable_sysexit, |
294 | .iret = native_iret, | |
ae5da273 | 295 | |
45876233 | 296 | .startup_ipi_hook = paravirt_nop, |
d3561b7f | 297 | }; |
0dbe5a11 IM |
298 | |
299 | /* | |
300 | * NOTE: CONFIG_PARAVIRT is experimental and the paravirt_ops | |
301 | * semantics are subject to change. Hence we only do this | |
302 | * internal-only export of this, until it gets sorted out and | |
303 | * all lowlevel CPU ops used by modules are separately exported. | |
304 | */ | |
305 | EXPORT_SYMBOL_GPL(paravirt_ops); |