xref: /openbmc/linux/arch/x86/kernel/paravirt.c (revision 224101ed)
1b1df07bdSGlauber de Oliveira Costa /*  Paravirtualization interfaces
2b1df07bdSGlauber de Oliveira Costa     Copyright (C) 2006 Rusty Russell IBM Corporation
3b1df07bdSGlauber de Oliveira Costa 
4b1df07bdSGlauber de Oliveira Costa     This program is free software; you can redistribute it and/or modify
5b1df07bdSGlauber de Oliveira Costa     it under the terms of the GNU General Public License as published by
6b1df07bdSGlauber de Oliveira Costa     the Free Software Foundation; either version 2 of the License, or
7b1df07bdSGlauber de Oliveira Costa     (at your option) any later version.
8b1df07bdSGlauber de Oliveira Costa 
9b1df07bdSGlauber de Oliveira Costa     This program is distributed in the hope that it will be useful,
10b1df07bdSGlauber de Oliveira Costa     but WITHOUT ANY WARRANTY; without even the implied warranty of
11b1df07bdSGlauber de Oliveira Costa     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12b1df07bdSGlauber de Oliveira Costa     GNU General Public License for more details.
13b1df07bdSGlauber de Oliveira Costa 
14b1df07bdSGlauber de Oliveira Costa     You should have received a copy of the GNU General Public License
15b1df07bdSGlauber de Oliveira Costa     along with this program; if not, write to the Free Software
16b1df07bdSGlauber de Oliveira Costa     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17b1df07bdSGlauber de Oliveira Costa 
18b1df07bdSGlauber de Oliveira Costa     2007 - x86_64 support added by Glauber de Oliveira Costa, Red Hat Inc
19b1df07bdSGlauber de Oliveira Costa */
20b1df07bdSGlauber de Oliveira Costa 
21b1df07bdSGlauber de Oliveira Costa #include <linux/errno.h>
22b1df07bdSGlauber de Oliveira Costa #include <linux/module.h>
23b1df07bdSGlauber de Oliveira Costa #include <linux/efi.h>
24b1df07bdSGlauber de Oliveira Costa #include <linux/bcd.h>
25b1df07bdSGlauber de Oliveira Costa #include <linux/highmem.h>
26b1df07bdSGlauber de Oliveira Costa 
27b1df07bdSGlauber de Oliveira Costa #include <asm/bug.h>
28b1df07bdSGlauber de Oliveira Costa #include <asm/paravirt.h>
29b1df07bdSGlauber de Oliveira Costa #include <asm/desc.h>
30b1df07bdSGlauber de Oliveira Costa #include <asm/setup.h>
31a312b37bSEduardo Habkost #include <asm/pgtable.h>
32b1df07bdSGlauber de Oliveira Costa #include <asm/time.h>
33eba0045fSJeremy Fitzhardinge #include <asm/pgalloc.h>
34b1df07bdSGlauber de Oliveira Costa #include <asm/irq.h>
35b1df07bdSGlauber de Oliveira Costa #include <asm/delay.h>
36b1df07bdSGlauber de Oliveira Costa #include <asm/fixmap.h>
37b1df07bdSGlauber de Oliveira Costa #include <asm/apic.h>
38b1df07bdSGlauber de Oliveira Costa #include <asm/tlbflush.h>
39b1df07bdSGlauber de Oliveira Costa #include <asm/timer.h>
40b1df07bdSGlauber de Oliveira Costa 
41b1df07bdSGlauber de Oliveira Costa /* nop stub */
42b1df07bdSGlauber de Oliveira Costa void _paravirt_nop(void)
43b1df07bdSGlauber de Oliveira Costa {
44b1df07bdSGlauber de Oliveira Costa }
45b1df07bdSGlauber de Oliveira Costa 
4641edafdbSJeremy Fitzhardinge /* identity function, which can be inlined */
4741edafdbSJeremy Fitzhardinge u32 _paravirt_ident_32(u32 x)
4841edafdbSJeremy Fitzhardinge {
4941edafdbSJeremy Fitzhardinge 	return x;
5041edafdbSJeremy Fitzhardinge }
5141edafdbSJeremy Fitzhardinge 
5241edafdbSJeremy Fitzhardinge u64 _paravirt_ident_64(u64 x)
5341edafdbSJeremy Fitzhardinge {
5441edafdbSJeremy Fitzhardinge 	return x;
5541edafdbSJeremy Fitzhardinge }
5641edafdbSJeremy Fitzhardinge 
57b1df07bdSGlauber de Oliveira Costa static void __init default_banner(void)
58b1df07bdSGlauber de Oliveira Costa {
59b1df07bdSGlauber de Oliveira Costa 	printk(KERN_INFO "Booting paravirtualized kernel on %s\n",
60b1df07bdSGlauber de Oliveira Costa 	       pv_info.name);
61b1df07bdSGlauber de Oliveira Costa }
62b1df07bdSGlauber de Oliveira Costa 
63b1df07bdSGlauber de Oliveira Costa char *memory_setup(void)
64b1df07bdSGlauber de Oliveira Costa {
65b1df07bdSGlauber de Oliveira Costa 	return pv_init_ops.memory_setup();
66b1df07bdSGlauber de Oliveira Costa }
67b1df07bdSGlauber de Oliveira Costa 
68b1df07bdSGlauber de Oliveira Costa /* Simple instruction patching code. */
69b1df07bdSGlauber de Oliveira Costa #define DEF_NATIVE(ops, name, code)					\
70b1df07bdSGlauber de Oliveira Costa 	extern const char start_##ops##_##name[], end_##ops##_##name[];	\
71b1df07bdSGlauber de Oliveira Costa 	asm("start_" #ops "_" #name ": " code "; end_" #ops "_" #name ":")
72b1df07bdSGlauber de Oliveira Costa 
73b1df07bdSGlauber de Oliveira Costa /* Undefined instruction for dealing with missing ops pointers. */
74b1df07bdSGlauber de Oliveira Costa static const unsigned char ud2a[] = { 0x0f, 0x0b };
75b1df07bdSGlauber de Oliveira Costa 
76b1df07bdSGlauber de Oliveira Costa unsigned paravirt_patch_nop(void)
77b1df07bdSGlauber de Oliveira Costa {
78b1df07bdSGlauber de Oliveira Costa 	return 0;
79b1df07bdSGlauber de Oliveira Costa }
80b1df07bdSGlauber de Oliveira Costa 
81b1df07bdSGlauber de Oliveira Costa unsigned paravirt_patch_ignore(unsigned len)
82b1df07bdSGlauber de Oliveira Costa {
83b1df07bdSGlauber de Oliveira Costa 	return len;
84b1df07bdSGlauber de Oliveira Costa }
85b1df07bdSGlauber de Oliveira Costa 
86b1df07bdSGlauber de Oliveira Costa struct branch {
87b1df07bdSGlauber de Oliveira Costa 	unsigned char opcode;
88b1df07bdSGlauber de Oliveira Costa 	u32 delta;
89b1df07bdSGlauber de Oliveira Costa } __attribute__((packed));
90b1df07bdSGlauber de Oliveira Costa 
91b1df07bdSGlauber de Oliveira Costa unsigned paravirt_patch_call(void *insnbuf,
92b1df07bdSGlauber de Oliveira Costa 			     const void *target, u16 tgt_clobbers,
93b1df07bdSGlauber de Oliveira Costa 			     unsigned long addr, u16 site_clobbers,
94b1df07bdSGlauber de Oliveira Costa 			     unsigned len)
95b1df07bdSGlauber de Oliveira Costa {
96b1df07bdSGlauber de Oliveira Costa 	struct branch *b = insnbuf;
97b1df07bdSGlauber de Oliveira Costa 	unsigned long delta = (unsigned long)target - (addr+5);
98b1df07bdSGlauber de Oliveira Costa 
99b1df07bdSGlauber de Oliveira Costa 	if (tgt_clobbers & ~site_clobbers)
100b1df07bdSGlauber de Oliveira Costa 		return len;	/* target would clobber too much for this site */
101b1df07bdSGlauber de Oliveira Costa 	if (len < 5)
102b1df07bdSGlauber de Oliveira Costa 		return len;	/* call too long for patch site */
103b1df07bdSGlauber de Oliveira Costa 
104b1df07bdSGlauber de Oliveira Costa 	b->opcode = 0xe8; /* call */
105b1df07bdSGlauber de Oliveira Costa 	b->delta = delta;
106b1df07bdSGlauber de Oliveira Costa 	BUILD_BUG_ON(sizeof(*b) != 5);
107b1df07bdSGlauber de Oliveira Costa 
108b1df07bdSGlauber de Oliveira Costa 	return 5;
109b1df07bdSGlauber de Oliveira Costa }
110b1df07bdSGlauber de Oliveira Costa 
111b1df07bdSGlauber de Oliveira Costa unsigned paravirt_patch_jmp(void *insnbuf, const void *target,
112b1df07bdSGlauber de Oliveira Costa 			    unsigned long addr, unsigned len)
113b1df07bdSGlauber de Oliveira Costa {
114b1df07bdSGlauber de Oliveira Costa 	struct branch *b = insnbuf;
115b1df07bdSGlauber de Oliveira Costa 	unsigned long delta = (unsigned long)target - (addr+5);
116b1df07bdSGlauber de Oliveira Costa 
117b1df07bdSGlauber de Oliveira Costa 	if (len < 5)
118b1df07bdSGlauber de Oliveira Costa 		return len;	/* call too long for patch site */
119b1df07bdSGlauber de Oliveira Costa 
120b1df07bdSGlauber de Oliveira Costa 	b->opcode = 0xe9;	/* jmp */
121b1df07bdSGlauber de Oliveira Costa 	b->delta = delta;
122b1df07bdSGlauber de Oliveira Costa 
123b1df07bdSGlauber de Oliveira Costa 	return 5;
124b1df07bdSGlauber de Oliveira Costa }
125b1df07bdSGlauber de Oliveira Costa 
126b1df07bdSGlauber de Oliveira Costa /* Neat trick to map patch type back to the call within the
127b1df07bdSGlauber de Oliveira Costa  * corresponding structure. */
128b1df07bdSGlauber de Oliveira Costa static void *get_call_destination(u8 type)
129b1df07bdSGlauber de Oliveira Costa {
130b1df07bdSGlauber de Oliveira Costa 	struct paravirt_patch_template tmpl = {
131b1df07bdSGlauber de Oliveira Costa 		.pv_init_ops = pv_init_ops,
132b1df07bdSGlauber de Oliveira Costa 		.pv_time_ops = pv_time_ops,
133b1df07bdSGlauber de Oliveira Costa 		.pv_cpu_ops = pv_cpu_ops,
134b1df07bdSGlauber de Oliveira Costa 		.pv_irq_ops = pv_irq_ops,
135b1df07bdSGlauber de Oliveira Costa 		.pv_apic_ops = pv_apic_ops,
136b1df07bdSGlauber de Oliveira Costa 		.pv_mmu_ops = pv_mmu_ops,
13774d4affdSJeremy Fitzhardinge 		.pv_lock_ops = pv_lock_ops,
138b1df07bdSGlauber de Oliveira Costa 	};
139b1df07bdSGlauber de Oliveira Costa 	return *((void **)&tmpl + type);
140b1df07bdSGlauber de Oliveira Costa }
141b1df07bdSGlauber de Oliveira Costa 
142b1df07bdSGlauber de Oliveira Costa unsigned paravirt_patch_default(u8 type, u16 clobbers, void *insnbuf,
143b1df07bdSGlauber de Oliveira Costa 				unsigned long addr, unsigned len)
144b1df07bdSGlauber de Oliveira Costa {
145b1df07bdSGlauber de Oliveira Costa 	void *opfunc = get_call_destination(type);
146b1df07bdSGlauber de Oliveira Costa 	unsigned ret;
147b1df07bdSGlauber de Oliveira Costa 
148b1df07bdSGlauber de Oliveira Costa 	if (opfunc == NULL)
149b1df07bdSGlauber de Oliveira Costa 		/* If there's no function, patch it with a ud2a (BUG) */
150b1df07bdSGlauber de Oliveira Costa 		ret = paravirt_patch_insns(insnbuf, len, ud2a, ud2a+sizeof(ud2a));
15141edafdbSJeremy Fitzhardinge 	else if (opfunc == _paravirt_nop)
152b1df07bdSGlauber de Oliveira Costa 		/* If the operation is a nop, then nop the callsite */
153b1df07bdSGlauber de Oliveira Costa 		ret = paravirt_patch_nop();
15441edafdbSJeremy Fitzhardinge 
15541edafdbSJeremy Fitzhardinge 	/* identity functions just return their single argument */
15641edafdbSJeremy Fitzhardinge 	else if (opfunc == _paravirt_ident_32)
15741edafdbSJeremy Fitzhardinge 		ret = paravirt_patch_ident_32(insnbuf, len);
15841edafdbSJeremy Fitzhardinge 	else if (opfunc == _paravirt_ident_64)
15941edafdbSJeremy Fitzhardinge 		ret = paravirt_patch_ident_64(insnbuf, len);
16041edafdbSJeremy Fitzhardinge 
161b1df07bdSGlauber de Oliveira Costa 	else if (type == PARAVIRT_PATCH(pv_cpu_ops.iret) ||
162d75cd22fSJeremy Fitzhardinge 		 type == PARAVIRT_PATCH(pv_cpu_ops.irq_enable_sysexit) ||
1632be29982SJeremy Fitzhardinge 		 type == PARAVIRT_PATCH(pv_cpu_ops.usergs_sysret32) ||
1642be29982SJeremy Fitzhardinge 		 type == PARAVIRT_PATCH(pv_cpu_ops.usergs_sysret64))
165b1df07bdSGlauber de Oliveira Costa 		/* If operation requires a jmp, then jmp */
166b1df07bdSGlauber de Oliveira Costa 		ret = paravirt_patch_jmp(insnbuf, opfunc, addr, len);
167b1df07bdSGlauber de Oliveira Costa 	else
168b1df07bdSGlauber de Oliveira Costa 		/* Otherwise call the function; assume target could
169b1df07bdSGlauber de Oliveira Costa 		   clobber any caller-save reg */
170b1df07bdSGlauber de Oliveira Costa 		ret = paravirt_patch_call(insnbuf, opfunc, CLBR_ANY,
171b1df07bdSGlauber de Oliveira Costa 					  addr, clobbers, len);
172b1df07bdSGlauber de Oliveira Costa 
173b1df07bdSGlauber de Oliveira Costa 	return ret;
174b1df07bdSGlauber de Oliveira Costa }
175b1df07bdSGlauber de Oliveira Costa 
176b1df07bdSGlauber de Oliveira Costa unsigned paravirt_patch_insns(void *insnbuf, unsigned len,
177b1df07bdSGlauber de Oliveira Costa 			      const char *start, const char *end)
178b1df07bdSGlauber de Oliveira Costa {
179b1df07bdSGlauber de Oliveira Costa 	unsigned insn_len = end - start;
180b1df07bdSGlauber de Oliveira Costa 
181b1df07bdSGlauber de Oliveira Costa 	if (insn_len > len || start == NULL)
182b1df07bdSGlauber de Oliveira Costa 		insn_len = len;
183b1df07bdSGlauber de Oliveira Costa 	else
184b1df07bdSGlauber de Oliveira Costa 		memcpy(insnbuf, start, insn_len);
185b1df07bdSGlauber de Oliveira Costa 
186b1df07bdSGlauber de Oliveira Costa 	return insn_len;
187b1df07bdSGlauber de Oliveira Costa }
188b1df07bdSGlauber de Oliveira Costa 
189b1df07bdSGlauber de Oliveira Costa void init_IRQ(void)
190b1df07bdSGlauber de Oliveira Costa {
191b1df07bdSGlauber de Oliveira Costa 	pv_irq_ops.init_IRQ();
192b1df07bdSGlauber de Oliveira Costa }
193b1df07bdSGlauber de Oliveira Costa 
194b1df07bdSGlauber de Oliveira Costa static void native_flush_tlb(void)
195b1df07bdSGlauber de Oliveira Costa {
196b1df07bdSGlauber de Oliveira Costa 	__native_flush_tlb();
197b1df07bdSGlauber de Oliveira Costa }
198b1df07bdSGlauber de Oliveira Costa 
199b1df07bdSGlauber de Oliveira Costa /*
200b1df07bdSGlauber de Oliveira Costa  * Global pages have to be flushed a bit differently. Not a real
201b1df07bdSGlauber de Oliveira Costa  * performance problem because this does not happen often.
202b1df07bdSGlauber de Oliveira Costa  */
203b1df07bdSGlauber de Oliveira Costa static void native_flush_tlb_global(void)
204b1df07bdSGlauber de Oliveira Costa {
205b1df07bdSGlauber de Oliveira Costa 	__native_flush_tlb_global();
206b1df07bdSGlauber de Oliveira Costa }
207b1df07bdSGlauber de Oliveira Costa 
208b1df07bdSGlauber de Oliveira Costa static void native_flush_tlb_single(unsigned long addr)
209b1df07bdSGlauber de Oliveira Costa {
210b1df07bdSGlauber de Oliveira Costa 	__native_flush_tlb_single(addr);
211b1df07bdSGlauber de Oliveira Costa }
212b1df07bdSGlauber de Oliveira Costa 
213b1df07bdSGlauber de Oliveira Costa /* These are in entry.S */
214b1df07bdSGlauber de Oliveira Costa extern void native_iret(void);
215d75cd22fSJeremy Fitzhardinge extern void native_irq_enable_sysexit(void);
2162be29982SJeremy Fitzhardinge extern void native_usergs_sysret32(void);
2172be29982SJeremy Fitzhardinge extern void native_usergs_sysret64(void);
218b1df07bdSGlauber de Oliveira Costa 
219b1df07bdSGlauber de Oliveira Costa static int __init print_banner(void)
220b1df07bdSGlauber de Oliveira Costa {
221b1df07bdSGlauber de Oliveira Costa 	pv_init_ops.banner();
222b1df07bdSGlauber de Oliveira Costa 	return 0;
223b1df07bdSGlauber de Oliveira Costa }
224b1df07bdSGlauber de Oliveira Costa core_initcall(print_banner);
225b1df07bdSGlauber de Oliveira Costa 
226b1df07bdSGlauber de Oliveira Costa static struct resource reserve_ioports = {
227b1df07bdSGlauber de Oliveira Costa 	.start = 0,
228b1df07bdSGlauber de Oliveira Costa 	.end = IO_SPACE_LIMIT,
229b1df07bdSGlauber de Oliveira Costa 	.name = "paravirt-ioport",
230b1df07bdSGlauber de Oliveira Costa 	.flags = IORESOURCE_IO | IORESOURCE_BUSY,
231b1df07bdSGlauber de Oliveira Costa };
232b1df07bdSGlauber de Oliveira Costa 
233b1df07bdSGlauber de Oliveira Costa /*
234b1df07bdSGlauber de Oliveira Costa  * Reserve the whole legacy IO space to prevent any legacy drivers
235b1df07bdSGlauber de Oliveira Costa  * from wasting time probing for their hardware.  This is a fairly
236b1df07bdSGlauber de Oliveira Costa  * brute-force approach to disabling all non-virtual drivers.
237b1df07bdSGlauber de Oliveira Costa  *
238b1df07bdSGlauber de Oliveira Costa  * Note that this must be called very early to have any effect.
239b1df07bdSGlauber de Oliveira Costa  */
240b1df07bdSGlauber de Oliveira Costa int paravirt_disable_iospace(void)
241b1df07bdSGlauber de Oliveira Costa {
242f7743fe6SJeremy Fitzhardinge 	return request_resource(&ioport_resource, &reserve_ioports);
243b1df07bdSGlauber de Oliveira Costa }
244b1df07bdSGlauber de Oliveira Costa 
245b1df07bdSGlauber de Oliveira Costa static DEFINE_PER_CPU(enum paravirt_lazy_mode, paravirt_lazy_mode) = PARAVIRT_LAZY_NONE;
246b1df07bdSGlauber de Oliveira Costa 
247b1df07bdSGlauber de Oliveira Costa static inline void enter_lazy(enum paravirt_lazy_mode mode)
248b1df07bdSGlauber de Oliveira Costa {
249bfd074e0SGlauber de Oliveira Costa 	BUG_ON(__get_cpu_var(paravirt_lazy_mode) != PARAVIRT_LAZY_NONE);
250b1df07bdSGlauber de Oliveira Costa 	BUG_ON(preemptible());
251b1df07bdSGlauber de Oliveira Costa 
252bfd074e0SGlauber de Oliveira Costa 	__get_cpu_var(paravirt_lazy_mode) = mode;
253b1df07bdSGlauber de Oliveira Costa }
254b1df07bdSGlauber de Oliveira Costa 
255b407fc57SJeremy Fitzhardinge static void leave_lazy(enum paravirt_lazy_mode mode)
256b1df07bdSGlauber de Oliveira Costa {
257bfd074e0SGlauber de Oliveira Costa 	BUG_ON(__get_cpu_var(paravirt_lazy_mode) != mode);
258b1df07bdSGlauber de Oliveira Costa 	BUG_ON(preemptible());
259b1df07bdSGlauber de Oliveira Costa 
260bfd074e0SGlauber de Oliveira Costa 	__get_cpu_var(paravirt_lazy_mode) = PARAVIRT_LAZY_NONE;
261b1df07bdSGlauber de Oliveira Costa }
262b1df07bdSGlauber de Oliveira Costa 
263b1df07bdSGlauber de Oliveira Costa void paravirt_enter_lazy_mmu(void)
264b1df07bdSGlauber de Oliveira Costa {
265b1df07bdSGlauber de Oliveira Costa 	enter_lazy(PARAVIRT_LAZY_MMU);
266b1df07bdSGlauber de Oliveira Costa }
267b1df07bdSGlauber de Oliveira Costa 
268b1df07bdSGlauber de Oliveira Costa void paravirt_leave_lazy_mmu(void)
269b1df07bdSGlauber de Oliveira Costa {
270b407fc57SJeremy Fitzhardinge 	leave_lazy(PARAVIRT_LAZY_MMU);
271b1df07bdSGlauber de Oliveira Costa }
272b1df07bdSGlauber de Oliveira Costa 
273224101edSJeremy Fitzhardinge void paravirt_start_context_switch(struct task_struct *prev)
274b1df07bdSGlauber de Oliveira Costa {
275b407fc57SJeremy Fitzhardinge 	if (percpu_read(paravirt_lazy_mode) == PARAVIRT_LAZY_MMU) {
276b407fc57SJeremy Fitzhardinge 		arch_leave_lazy_mmu_mode();
277224101edSJeremy Fitzhardinge 		set_ti_thread_flag(task_thread_info(prev), TIF_LAZY_MMU_UPDATES);
278b407fc57SJeremy Fitzhardinge 	}
279b1df07bdSGlauber de Oliveira Costa 	enter_lazy(PARAVIRT_LAZY_CPU);
280b1df07bdSGlauber de Oliveira Costa }
281b1df07bdSGlauber de Oliveira Costa 
282224101edSJeremy Fitzhardinge void paravirt_end_context_switch(struct task_struct *next)
283b1df07bdSGlauber de Oliveira Costa {
284b407fc57SJeremy Fitzhardinge 	leave_lazy(PARAVIRT_LAZY_CPU);
285b407fc57SJeremy Fitzhardinge 
286224101edSJeremy Fitzhardinge 	if (test_and_clear_ti_thread_flag(task_thread_info(next), TIF_LAZY_MMU_UPDATES))
287b407fc57SJeremy Fitzhardinge 		arch_enter_lazy_mmu_mode();
288b1df07bdSGlauber de Oliveira Costa }
289b1df07bdSGlauber de Oliveira Costa 
290b1df07bdSGlauber de Oliveira Costa enum paravirt_lazy_mode paravirt_get_lazy_mode(void)
291b1df07bdSGlauber de Oliveira Costa {
292b8bcfe99SJeremy Fitzhardinge 	if (in_interrupt())
293b8bcfe99SJeremy Fitzhardinge 		return PARAVIRT_LAZY_NONE;
294b8bcfe99SJeremy Fitzhardinge 
295bfd074e0SGlauber de Oliveira Costa 	return __get_cpu_var(paravirt_lazy_mode);
296b1df07bdSGlauber de Oliveira Costa }
297b1df07bdSGlauber de Oliveira Costa 
298d85cf93dSJeremy Fitzhardinge void arch_flush_lazy_mmu_mode(void)
299d85cf93dSJeremy Fitzhardinge {
300d85cf93dSJeremy Fitzhardinge 	preempt_disable();
301d85cf93dSJeremy Fitzhardinge 
302d85cf93dSJeremy Fitzhardinge 	if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU) {
30334b0900dSThomas Gleixner 		WARN_ON(preempt_count() == 1);
304d85cf93dSJeremy Fitzhardinge 		arch_leave_lazy_mmu_mode();
305d85cf93dSJeremy Fitzhardinge 		arch_enter_lazy_mmu_mode();
306d85cf93dSJeremy Fitzhardinge 	}
307d85cf93dSJeremy Fitzhardinge 
308d85cf93dSJeremy Fitzhardinge 	preempt_enable();
309d85cf93dSJeremy Fitzhardinge }
310d85cf93dSJeremy Fitzhardinge 
311b1df07bdSGlauber de Oliveira Costa struct pv_info pv_info = {
312b1df07bdSGlauber de Oliveira Costa 	.name = "bare hardware",
313b1df07bdSGlauber de Oliveira Costa 	.paravirt_enabled = 0,
314b1df07bdSGlauber de Oliveira Costa 	.kernel_rpl = 0,
315b1df07bdSGlauber de Oliveira Costa 	.shared_kernel_pmd = 1,	/* Only used when CONFIG_X86_PAE is set */
316b1df07bdSGlauber de Oliveira Costa };
317b1df07bdSGlauber de Oliveira Costa 
318b1df07bdSGlauber de Oliveira Costa struct pv_init_ops pv_init_ops = {
319b1df07bdSGlauber de Oliveira Costa 	.patch = native_patch,
320b1df07bdSGlauber de Oliveira Costa 	.banner = default_banner,
321b1df07bdSGlauber de Oliveira Costa 	.arch_setup = paravirt_nop,
322b1df07bdSGlauber de Oliveira Costa 	.memory_setup = machine_specific_memory_setup,
323b1df07bdSGlauber de Oliveira Costa };
324b1df07bdSGlauber de Oliveira Costa 
325b1df07bdSGlauber de Oliveira Costa struct pv_time_ops pv_time_ops = {
326b1df07bdSGlauber de Oliveira Costa 	.time_init = hpet_time_init,
327b1df07bdSGlauber de Oliveira Costa 	.get_wallclock = native_get_wallclock,
328b1df07bdSGlauber de Oliveira Costa 	.set_wallclock = native_set_wallclock,
329b1df07bdSGlauber de Oliveira Costa 	.sched_clock = native_sched_clock,
330e93ef949SAlok Kataria 	.get_tsc_khz = native_calibrate_tsc,
331b1df07bdSGlauber de Oliveira Costa };
332b1df07bdSGlauber de Oliveira Costa 
333b1df07bdSGlauber de Oliveira Costa struct pv_irq_ops pv_irq_ops = {
334b1df07bdSGlauber de Oliveira Costa 	.init_IRQ = native_init_IRQ,
335ecb93d1cSJeremy Fitzhardinge 	.save_fl = __PV_IS_CALLEE_SAVE(native_save_fl),
336ecb93d1cSJeremy Fitzhardinge 	.restore_fl = __PV_IS_CALLEE_SAVE(native_restore_fl),
337ecb93d1cSJeremy Fitzhardinge 	.irq_disable = __PV_IS_CALLEE_SAVE(native_irq_disable),
338ecb93d1cSJeremy Fitzhardinge 	.irq_enable = __PV_IS_CALLEE_SAVE(native_irq_enable),
339b1df07bdSGlauber de Oliveira Costa 	.safe_halt = native_safe_halt,
340b1df07bdSGlauber de Oliveira Costa 	.halt = native_halt,
341fab58420SJeremy Fitzhardinge #ifdef CONFIG_X86_64
342fab58420SJeremy Fitzhardinge 	.adjust_exception_frame = paravirt_nop,
343fab58420SJeremy Fitzhardinge #endif
344b1df07bdSGlauber de Oliveira Costa };
345b1df07bdSGlauber de Oliveira Costa 
346b1df07bdSGlauber de Oliveira Costa struct pv_cpu_ops pv_cpu_ops = {
347b1df07bdSGlauber de Oliveira Costa 	.cpuid = native_cpuid,
348b1df07bdSGlauber de Oliveira Costa 	.get_debugreg = native_get_debugreg,
349b1df07bdSGlauber de Oliveira Costa 	.set_debugreg = native_set_debugreg,
350b1df07bdSGlauber de Oliveira Costa 	.clts = native_clts,
351b1df07bdSGlauber de Oliveira Costa 	.read_cr0 = native_read_cr0,
352b1df07bdSGlauber de Oliveira Costa 	.write_cr0 = native_write_cr0,
353b1df07bdSGlauber de Oliveira Costa 	.read_cr4 = native_read_cr4,
354b1df07bdSGlauber de Oliveira Costa 	.read_cr4_safe = native_read_cr4_safe,
355b1df07bdSGlauber de Oliveira Costa 	.write_cr4 = native_write_cr4,
35688b4755fSGlauber de Oliveira Costa #ifdef CONFIG_X86_64
35788b4755fSGlauber de Oliveira Costa 	.read_cr8 = native_read_cr8,
35888b4755fSGlauber de Oliveira Costa 	.write_cr8 = native_write_cr8,
35988b4755fSGlauber de Oliveira Costa #endif
360b1df07bdSGlauber de Oliveira Costa 	.wbinvd = native_wbinvd,
361b1df07bdSGlauber de Oliveira Costa 	.read_msr = native_read_msr_safe,
362b05f78f5SYinghai Lu 	.read_msr_amd = native_read_msr_amd_safe,
363b1df07bdSGlauber de Oliveira Costa 	.write_msr = native_write_msr_safe,
364b1df07bdSGlauber de Oliveira Costa 	.read_tsc = native_read_tsc,
365b1df07bdSGlauber de Oliveira Costa 	.read_pmc = native_read_pmc,
366e5aaac44SGlauber de Oliveira Costa 	.read_tscp = native_read_tscp,
367b1df07bdSGlauber de Oliveira Costa 	.load_tr_desc = native_load_tr_desc,
368b1df07bdSGlauber de Oliveira Costa 	.set_ldt = native_set_ldt,
369b1df07bdSGlauber de Oliveira Costa 	.load_gdt = native_load_gdt,
370b1df07bdSGlauber de Oliveira Costa 	.load_idt = native_load_idt,
371b1df07bdSGlauber de Oliveira Costa 	.store_gdt = native_store_gdt,
372b1df07bdSGlauber de Oliveira Costa 	.store_idt = native_store_idt,
373b1df07bdSGlauber de Oliveira Costa 	.store_tr = native_store_tr,
374b1df07bdSGlauber de Oliveira Costa 	.load_tls = native_load_tls,
3759f9d489aSJeremy Fitzhardinge #ifdef CONFIG_X86_64
3769f9d489aSJeremy Fitzhardinge 	.load_gs_index = native_load_gs_index,
3779f9d489aSJeremy Fitzhardinge #endif
378b1df07bdSGlauber de Oliveira Costa 	.write_ldt_entry = native_write_ldt_entry,
379b1df07bdSGlauber de Oliveira Costa 	.write_gdt_entry = native_write_gdt_entry,
380b1df07bdSGlauber de Oliveira Costa 	.write_idt_entry = native_write_idt_entry,
38138ffbe66SJeremy Fitzhardinge 
38238ffbe66SJeremy Fitzhardinge 	.alloc_ldt = paravirt_nop,
38338ffbe66SJeremy Fitzhardinge 	.free_ldt = paravirt_nop,
38438ffbe66SJeremy Fitzhardinge 
385b1df07bdSGlauber de Oliveira Costa 	.load_sp0 = native_load_sp0,
386b1df07bdSGlauber de Oliveira Costa 
387102d0a4bSJeremy Fitzhardinge #if defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION)
388d75cd22fSJeremy Fitzhardinge 	.irq_enable_sysexit = native_irq_enable_sysexit,
389102d0a4bSJeremy Fitzhardinge #endif
3902be29982SJeremy Fitzhardinge #ifdef CONFIG_X86_64
391102d0a4bSJeremy Fitzhardinge #ifdef CONFIG_IA32_EMULATION
3922be29982SJeremy Fitzhardinge 	.usergs_sysret32 = native_usergs_sysret32,
393102d0a4bSJeremy Fitzhardinge #endif
3942be29982SJeremy Fitzhardinge 	.usergs_sysret64 = native_usergs_sysret64,
395d75cd22fSJeremy Fitzhardinge #endif
396b1df07bdSGlauber de Oliveira Costa 	.iret = native_iret,
397e801f864SGlauber de Oliveira Costa 	.swapgs = native_swapgs,
398b1df07bdSGlauber de Oliveira Costa 
399b1df07bdSGlauber de Oliveira Costa 	.set_iopl_mask = native_set_iopl_mask,
400b1df07bdSGlauber de Oliveira Costa 	.io_delay = native_io_delay,
401b1df07bdSGlauber de Oliveira Costa 
402224101edSJeremy Fitzhardinge 	.start_context_switch = paravirt_nop,
403224101edSJeremy Fitzhardinge 	.end_context_switch = paravirt_nop,
404b1df07bdSGlauber de Oliveira Costa };
405b1df07bdSGlauber de Oliveira Costa 
406b1df07bdSGlauber de Oliveira Costa struct pv_apic_ops pv_apic_ops = {
407b1df07bdSGlauber de Oliveira Costa #ifdef CONFIG_X86_LOCAL_APIC
408b1df07bdSGlauber de Oliveira Costa 	.setup_boot_clock = setup_boot_APIC_clock,
409b1df07bdSGlauber de Oliveira Costa 	.setup_secondary_clock = setup_secondary_APIC_clock,
410b1df07bdSGlauber de Oliveira Costa 	.startup_ipi_hook = paravirt_nop,
411b1df07bdSGlauber de Oliveira Costa #endif
412b1df07bdSGlauber de Oliveira Costa };
413b1df07bdSGlauber de Oliveira Costa 
41441edafdbSJeremy Fitzhardinge #if defined(CONFIG_X86_32) && !defined(CONFIG_X86_PAE)
41541edafdbSJeremy Fitzhardinge /* 32-bit pagetable entries */
416da5de7c2SJeremy Fitzhardinge #define PTE_IDENT	__PV_IS_CALLEE_SAVE(_paravirt_ident_32)
41741edafdbSJeremy Fitzhardinge #else
41841edafdbSJeremy Fitzhardinge /* 64-bit pagetable entries */
419da5de7c2SJeremy Fitzhardinge #define PTE_IDENT	__PV_IS_CALLEE_SAVE(_paravirt_ident_64)
42041edafdbSJeremy Fitzhardinge #endif
42141edafdbSJeremy Fitzhardinge 
422b1df07bdSGlauber de Oliveira Costa struct pv_mmu_ops pv_mmu_ops = {
423d8dd8eecSEduardo Habkost #ifndef CONFIG_X86_64
424b1df07bdSGlauber de Oliveira Costa 	.pagetable_setup_start = native_pagetable_setup_start,
425b1df07bdSGlauber de Oliveira Costa 	.pagetable_setup_done = native_pagetable_setup_done,
426a312b37bSEduardo Habkost #else
427a312b37bSEduardo Habkost 	.pagetable_setup_start = paravirt_nop,
428a312b37bSEduardo Habkost 	.pagetable_setup_done = paravirt_nop,
429d8dd8eecSEduardo Habkost #endif
430b1df07bdSGlauber de Oliveira Costa 
431b1df07bdSGlauber de Oliveira Costa 	.read_cr2 = native_read_cr2,
432b1df07bdSGlauber de Oliveira Costa 	.write_cr2 = native_write_cr2,
433b1df07bdSGlauber de Oliveira Costa 	.read_cr3 = native_read_cr3,
434b1df07bdSGlauber de Oliveira Costa 	.write_cr3 = native_write_cr3,
435b1df07bdSGlauber de Oliveira Costa 
436b1df07bdSGlauber de Oliveira Costa 	.flush_tlb_user = native_flush_tlb,
437b1df07bdSGlauber de Oliveira Costa 	.flush_tlb_kernel = native_flush_tlb_global,
438b1df07bdSGlauber de Oliveira Costa 	.flush_tlb_single = native_flush_tlb_single,
439b1df07bdSGlauber de Oliveira Costa 	.flush_tlb_others = native_flush_tlb_others,
440b1df07bdSGlauber de Oliveira Costa 
441eba0045fSJeremy Fitzhardinge 	.pgd_alloc = __paravirt_pgd_alloc,
442eba0045fSJeremy Fitzhardinge 	.pgd_free = paravirt_nop,
443eba0045fSJeremy Fitzhardinge 
4446944a9c8SJeremy Fitzhardinge 	.alloc_pte = paravirt_nop,
4456944a9c8SJeremy Fitzhardinge 	.alloc_pmd = paravirt_nop,
4466944a9c8SJeremy Fitzhardinge 	.alloc_pmd_clone = paravirt_nop,
4472761fa09SJeremy Fitzhardinge 	.alloc_pud = paravirt_nop,
4486944a9c8SJeremy Fitzhardinge 	.release_pte = paravirt_nop,
4496944a9c8SJeremy Fitzhardinge 	.release_pmd = paravirt_nop,
4502761fa09SJeremy Fitzhardinge 	.release_pud = paravirt_nop,
451b1df07bdSGlauber de Oliveira Costa 
452b1df07bdSGlauber de Oliveira Costa 	.set_pte = native_set_pte,
453b1df07bdSGlauber de Oliveira Costa 	.set_pte_at = native_set_pte_at,
454b1df07bdSGlauber de Oliveira Costa 	.set_pmd = native_set_pmd,
455b1df07bdSGlauber de Oliveira Costa 	.pte_update = paravirt_nop,
456b1df07bdSGlauber de Oliveira Costa 	.pte_update_defer = paravirt_nop,
457b1df07bdSGlauber de Oliveira Costa 
45808b882c6SJeremy Fitzhardinge 	.ptep_modify_prot_start = __ptep_modify_prot_start,
45908b882c6SJeremy Fitzhardinge 	.ptep_modify_prot_commit = __ptep_modify_prot_commit,
46008b882c6SJeremy Fitzhardinge 
461b1df07bdSGlauber de Oliveira Costa #ifdef CONFIG_HIGHPTE
462b1df07bdSGlauber de Oliveira Costa 	.kmap_atomic_pte = kmap_atomic,
463b1df07bdSGlauber de Oliveira Costa #endif
464b1df07bdSGlauber de Oliveira Costa 
465f95f2f7bSEduardo Habkost #if PAGETABLE_LEVELS >= 3
466b1df07bdSGlauber de Oliveira Costa #ifdef CONFIG_X86_PAE
467b1df07bdSGlauber de Oliveira Costa 	.set_pte_atomic = native_set_pte_atomic,
468b1df07bdSGlauber de Oliveira Costa 	.set_pte_present = native_set_pte_present,
469b1df07bdSGlauber de Oliveira Costa 	.pte_clear = native_pte_clear,
470b1df07bdSGlauber de Oliveira Costa 	.pmd_clear = native_pmd_clear,
471f95f2f7bSEduardo Habkost #endif
472f95f2f7bSEduardo Habkost 	.set_pud = native_set_pud,
473da5de7c2SJeremy Fitzhardinge 
474da5de7c2SJeremy Fitzhardinge 	.pmd_val = PTE_IDENT,
475da5de7c2SJeremy Fitzhardinge 	.make_pmd = PTE_IDENT,
476f95f2f7bSEduardo Habkost 
477f95f2f7bSEduardo Habkost #if PAGETABLE_LEVELS == 4
478da5de7c2SJeremy Fitzhardinge 	.pud_val = PTE_IDENT,
479da5de7c2SJeremy Fitzhardinge 	.make_pud = PTE_IDENT,
480da5de7c2SJeremy Fitzhardinge 
481f95f2f7bSEduardo Habkost 	.set_pgd = native_set_pgd,
482b1df07bdSGlauber de Oliveira Costa #endif
483f95f2f7bSEduardo Habkost #endif /* PAGETABLE_LEVELS >= 3 */
484b1df07bdSGlauber de Oliveira Costa 
485da5de7c2SJeremy Fitzhardinge 	.pte_val = PTE_IDENT,
486da5de7c2SJeremy Fitzhardinge 	.pgd_val = PTE_IDENT,
487b1df07bdSGlauber de Oliveira Costa 
488da5de7c2SJeremy Fitzhardinge 	.make_pte = PTE_IDENT,
489da5de7c2SJeremy Fitzhardinge 	.make_pgd = PTE_IDENT,
490b1df07bdSGlauber de Oliveira Costa 
491b1df07bdSGlauber de Oliveira Costa 	.dup_mmap = paravirt_nop,
492b1df07bdSGlauber de Oliveira Costa 	.exit_mmap = paravirt_nop,
493b1df07bdSGlauber de Oliveira Costa 	.activate_mm = paravirt_nop,
494b1df07bdSGlauber de Oliveira Costa 
495b1df07bdSGlauber de Oliveira Costa 	.lazy_mode = {
496b1df07bdSGlauber de Oliveira Costa 		.enter = paravirt_nop,
497b1df07bdSGlauber de Oliveira Costa 		.leave = paravirt_nop,
498b1df07bdSGlauber de Oliveira Costa 	},
499aeaaa59cSJeremy Fitzhardinge 
500aeaaa59cSJeremy Fitzhardinge 	.set_fixmap = native_set_fixmap,
501b1df07bdSGlauber de Oliveira Costa };
502b1df07bdSGlauber de Oliveira Costa 
503b1df07bdSGlauber de Oliveira Costa EXPORT_SYMBOL_GPL(pv_time_ops);
504b1df07bdSGlauber de Oliveira Costa EXPORT_SYMBOL    (pv_cpu_ops);
505b1df07bdSGlauber de Oliveira Costa EXPORT_SYMBOL    (pv_mmu_ops);
506b1df07bdSGlauber de Oliveira Costa EXPORT_SYMBOL_GPL(pv_apic_ops);
507b1df07bdSGlauber de Oliveira Costa EXPORT_SYMBOL_GPL(pv_info);
508b1df07bdSGlauber de Oliveira Costa EXPORT_SYMBOL    (pv_irq_ops);
509