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 | ||
d3561b7f | 120 | /* These are in entry.S */ |
1a1eecd1 AK |
121 | extern void native_iret(void); |
122 | extern void native_irq_enable_sysexit(void); | |
d3561b7f RR |
123 | |
124 | static int __init print_banner(void) | |
125 | { | |
126 | paravirt_ops.banner(); | |
127 | return 0; | |
128 | } | |
129 | core_initcall(print_banner); | |
130 | ||
131 | struct paravirt_ops paravirt_ops = { | |
132 | .name = "bare hardware", | |
133 | .paravirt_enabled = 0, | |
134 | .kernel_rpl = 0, | |
5311ab62 | 135 | .shared_kernel_pmd = 1, /* Only used when CONFIG_X86_PAE is set */ |
d3561b7f | 136 | |
139ec7c4 | 137 | .patch = native_patch, |
d3561b7f | 138 | .banner = default_banner, |
45876233 | 139 | .arch_setup = paravirt_nop, |
d3561b7f RR |
140 | .memory_setup = machine_specific_memory_setup, |
141 | .get_wallclock = native_get_wallclock, | |
142 | .set_wallclock = native_set_wallclock, | |
e30fab3a | 143 | .time_init = hpet_time_init, |
d3561b7f RR |
144 | .init_IRQ = native_init_IRQ, |
145 | ||
146 | .cpuid = native_cpuid, | |
147 | .get_debugreg = native_get_debugreg, | |
148 | .set_debugreg = native_set_debugreg, | |
149 | .clts = native_clts, | |
150 | .read_cr0 = native_read_cr0, | |
151 | .write_cr0 = native_write_cr0, | |
152 | .read_cr2 = native_read_cr2, | |
153 | .write_cr2 = native_write_cr2, | |
154 | .read_cr3 = native_read_cr3, | |
155 | .write_cr3 = native_write_cr3, | |
156 | .read_cr4 = native_read_cr4, | |
157 | .read_cr4_safe = native_read_cr4_safe, | |
158 | .write_cr4 = native_write_cr4, | |
159 | .save_fl = native_save_fl, | |
160 | .restore_fl = native_restore_fl, | |
161 | .irq_disable = native_irq_disable, | |
162 | .irq_enable = native_irq_enable, | |
163 | .safe_halt = native_safe_halt, | |
164 | .halt = native_halt, | |
165 | .wbinvd = native_wbinvd, | |
90a0a06a RR |
166 | .read_msr = native_read_msr_safe, |
167 | .write_msr = native_write_msr_safe, | |
d3561b7f RR |
168 | .read_tsc = native_read_tsc, |
169 | .read_pmc = native_read_pmc, | |
6cb9a835 | 170 | .get_scheduled_cycles = native_read_tsc, |
1182d852 | 171 | .get_cpu_khz = native_calculate_cpu_khz, |
d3561b7f RR |
172 | .load_tr_desc = native_load_tr_desc, |
173 | .set_ldt = native_set_ldt, | |
174 | .load_gdt = native_load_gdt, | |
175 | .load_idt = native_load_idt, | |
176 | .store_gdt = native_store_gdt, | |
177 | .store_idt = native_store_idt, | |
178 | .store_tr = native_store_tr, | |
179 | .load_tls = native_load_tls, | |
90a0a06a RR |
180 | .write_ldt_entry = write_dt_entry, |
181 | .write_gdt_entry = write_dt_entry, | |
182 | .write_idt_entry = write_dt_entry, | |
d3561b7f RR |
183 | .load_esp0 = native_load_esp0, |
184 | ||
185 | .set_iopl_mask = native_set_iopl_mask, | |
186 | .io_delay = native_io_delay, | |
d3561b7f | 187 | |
13623d79 RR |
188 | #ifdef CONFIG_X86_LOCAL_APIC |
189 | .apic_write = native_apic_write, | |
190 | .apic_write_atomic = native_apic_write_atomic, | |
191 | .apic_read = native_apic_read, | |
bbab4f3b ZA |
192 | .setup_boot_clock = setup_boot_APIC_clock, |
193 | .setup_secondary_clock = setup_secondary_APIC_clock, | |
13623d79 | 194 | #endif |
45876233 | 195 | .set_lazy_mode = paravirt_nop, |
13623d79 | 196 | |
b239fb25 JF |
197 | .pagetable_setup_start = native_pagetable_setup_start, |
198 | .pagetable_setup_done = native_pagetable_setup_done, | |
199 | ||
da181a8b RR |
200 | .flush_tlb_user = native_flush_tlb, |
201 | .flush_tlb_kernel = native_flush_tlb_global, | |
202 | .flush_tlb_single = native_flush_tlb_single, | |
203 | ||
45876233 | 204 | .map_pt_hook = paravirt_nop, |
9a1c13e9 | 205 | |
45876233 JF |
206 | .alloc_pt = paravirt_nop, |
207 | .alloc_pd = paravirt_nop, | |
208 | .alloc_pd_clone = paravirt_nop, | |
209 | .release_pt = paravirt_nop, | |
210 | .release_pd = paravirt_nop, | |
c119ecce | 211 | |
da181a8b RR |
212 | .set_pte = native_set_pte, |
213 | .set_pte_at = native_set_pte_at, | |
214 | .set_pmd = native_set_pmd, | |
45876233 JF |
215 | .pte_update = paravirt_nop, |
216 | .pte_update_defer = paravirt_nop, | |
3dc494e8 JF |
217 | |
218 | .ptep_get_and_clear = native_ptep_get_and_clear, | |
219 | ||
da181a8b RR |
220 | #ifdef CONFIG_X86_PAE |
221 | .set_pte_atomic = native_set_pte_atomic, | |
222 | .set_pte_present = native_set_pte_present, | |
223 | .set_pud = native_set_pud, | |
224 | .pte_clear = native_pte_clear, | |
225 | .pmd_clear = native_pmd_clear, | |
3dc494e8 JF |
226 | |
227 | .pmd_val = native_pmd_val, | |
228 | .make_pmd = native_make_pmd, | |
da181a8b RR |
229 | #endif |
230 | ||
3dc494e8 JF |
231 | .pte_val = native_pte_val, |
232 | .pgd_val = native_pgd_val, | |
233 | ||
234 | .make_pte = native_make_pte, | |
235 | .make_pgd = native_make_pgd, | |
236 | ||
d3561b7f RR |
237 | .irq_enable_sysexit = native_irq_enable_sysexit, |
238 | .iret = native_iret, | |
ae5da273 | 239 | |
45876233 | 240 | .startup_ipi_hook = paravirt_nop, |
d3561b7f | 241 | }; |
0dbe5a11 IM |
242 | |
243 | /* | |
244 | * NOTE: CONFIG_PARAVIRT is experimental and the paravirt_ops | |
245 | * semantics are subject to change. Hence we only do this | |
246 | * internal-only export of this, until it gets sorted out and | |
247 | * all lowlevel CPU ops used by modules are separately exported. | |
248 | */ | |
249 | EXPORT_SYMBOL_GPL(paravirt_ops); |