xref: /openbmc/linux/arch/x86/kernel/paravirt.c (revision 9a55fdbe)
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>
2950af5eadSPaul Gortmaker #include <asm/debugreg.h>
30b1df07bdSGlauber de Oliveira Costa #include <asm/desc.h>
31b1df07bdSGlauber de Oliveira Costa #include <asm/setup.h>
32a312b37bSEduardo Habkost #include <asm/pgtable.h>
33b1df07bdSGlauber de Oliveira Costa #include <asm/time.h>
34eba0045fSJeremy Fitzhardinge #include <asm/pgalloc.h>
35b1df07bdSGlauber de Oliveira Costa #include <asm/irq.h>
36b1df07bdSGlauber de Oliveira Costa #include <asm/delay.h>
37b1df07bdSGlauber de Oliveira Costa #include <asm/fixmap.h>
38b1df07bdSGlauber de Oliveira Costa #include <asm/apic.h>
39b1df07bdSGlauber de Oliveira Costa #include <asm/tlbflush.h>
40b1df07bdSGlauber de Oliveira Costa #include <asm/timer.h>
41f05e798aSDavid Howells #include <asm/special_insns.h>
42b1df07bdSGlauber de Oliveira Costa 
43b1df07bdSGlauber de Oliveira Costa /* nop stub */
44b1df07bdSGlauber de Oliveira Costa void _paravirt_nop(void)
45b1df07bdSGlauber de Oliveira Costa {
46b1df07bdSGlauber de Oliveira Costa }
47b1df07bdSGlauber de Oliveira Costa 
4841edafdbSJeremy Fitzhardinge /* identity function, which can be inlined */
4941edafdbSJeremy Fitzhardinge u32 _paravirt_ident_32(u32 x)
5041edafdbSJeremy Fitzhardinge {
5141edafdbSJeremy Fitzhardinge 	return x;
5241edafdbSJeremy Fitzhardinge }
5341edafdbSJeremy Fitzhardinge 
5441edafdbSJeremy Fitzhardinge u64 _paravirt_ident_64(u64 x)
5541edafdbSJeremy Fitzhardinge {
5641edafdbSJeremy Fitzhardinge 	return x;
5741edafdbSJeremy Fitzhardinge }
5841edafdbSJeremy Fitzhardinge 
596f30c1acSThomas Gleixner void __init default_banner(void)
60b1df07bdSGlauber de Oliveira Costa {
61b1df07bdSGlauber de Oliveira Costa 	printk(KERN_INFO "Booting paravirtualized kernel on %s\n",
62b1df07bdSGlauber de Oliveira Costa 	       pv_info.name);
63b1df07bdSGlauber de Oliveira Costa }
64b1df07bdSGlauber de Oliveira Costa 
65b1df07bdSGlauber de Oliveira Costa /* Simple instruction patching code. */
66b1df07bdSGlauber de Oliveira Costa #define DEF_NATIVE(ops, name, code)					\
67b1df07bdSGlauber de Oliveira Costa 	extern const char start_##ops##_##name[], end_##ops##_##name[];	\
68b1df07bdSGlauber de Oliveira Costa 	asm("start_" #ops "_" #name ": " code "; end_" #ops "_" #name ":")
69b1df07bdSGlauber de Oliveira Costa 
70b1df07bdSGlauber de Oliveira Costa /* Undefined instruction for dealing with missing ops pointers. */
71b1df07bdSGlauber de Oliveira Costa static const unsigned char ud2a[] = { 0x0f, 0x0b };
72b1df07bdSGlauber de Oliveira Costa 
73b1df07bdSGlauber de Oliveira Costa unsigned paravirt_patch_nop(void)
74b1df07bdSGlauber de Oliveira Costa {
75b1df07bdSGlauber de Oliveira Costa 	return 0;
76b1df07bdSGlauber de Oliveira Costa }
77b1df07bdSGlauber de Oliveira Costa 
78b1df07bdSGlauber de Oliveira Costa unsigned paravirt_patch_ignore(unsigned len)
79b1df07bdSGlauber de Oliveira Costa {
80b1df07bdSGlauber de Oliveira Costa 	return len;
81b1df07bdSGlauber de Oliveira Costa }
82b1df07bdSGlauber de Oliveira Costa 
83b1df07bdSGlauber de Oliveira Costa struct branch {
84b1df07bdSGlauber de Oliveira Costa 	unsigned char opcode;
85b1df07bdSGlauber de Oliveira Costa 	u32 delta;
86b1df07bdSGlauber de Oliveira Costa } __attribute__((packed));
87b1df07bdSGlauber de Oliveira Costa 
88b1df07bdSGlauber de Oliveira Costa unsigned paravirt_patch_call(void *insnbuf,
89b1df07bdSGlauber de Oliveira Costa 			     const void *target, u16 tgt_clobbers,
90b1df07bdSGlauber de Oliveira Costa 			     unsigned long addr, u16 site_clobbers,
91b1df07bdSGlauber de Oliveira Costa 			     unsigned len)
92b1df07bdSGlauber de Oliveira Costa {
93b1df07bdSGlauber de Oliveira Costa 	struct branch *b = insnbuf;
94b1df07bdSGlauber de Oliveira Costa 	unsigned long delta = (unsigned long)target - (addr+5);
95b1df07bdSGlauber de Oliveira Costa 
96b1df07bdSGlauber de Oliveira Costa 	if (tgt_clobbers & ~site_clobbers)
97b1df07bdSGlauber de Oliveira Costa 		return len;	/* target would clobber too much for this site */
98b1df07bdSGlauber de Oliveira Costa 	if (len < 5)
99b1df07bdSGlauber de Oliveira Costa 		return len;	/* call too long for patch site */
100b1df07bdSGlauber de Oliveira Costa 
101b1df07bdSGlauber de Oliveira Costa 	b->opcode = 0xe8; /* call */
102b1df07bdSGlauber de Oliveira Costa 	b->delta = delta;
103b1df07bdSGlauber de Oliveira Costa 	BUILD_BUG_ON(sizeof(*b) != 5);
104b1df07bdSGlauber de Oliveira Costa 
105b1df07bdSGlauber de Oliveira Costa 	return 5;
106b1df07bdSGlauber de Oliveira Costa }
107b1df07bdSGlauber de Oliveira Costa 
108b1df07bdSGlauber de Oliveira Costa unsigned paravirt_patch_jmp(void *insnbuf, const void *target,
109b1df07bdSGlauber de Oliveira Costa 			    unsigned long addr, unsigned len)
110b1df07bdSGlauber de Oliveira Costa {
111b1df07bdSGlauber de Oliveira Costa 	struct branch *b = insnbuf;
112b1df07bdSGlauber de Oliveira Costa 	unsigned long delta = (unsigned long)target - (addr+5);
113b1df07bdSGlauber de Oliveira Costa 
114b1df07bdSGlauber de Oliveira Costa 	if (len < 5)
115b1df07bdSGlauber de Oliveira Costa 		return len;	/* call too long for patch site */
116b1df07bdSGlauber de Oliveira Costa 
117b1df07bdSGlauber de Oliveira Costa 	b->opcode = 0xe9;	/* jmp */
118b1df07bdSGlauber de Oliveira Costa 	b->delta = delta;
119b1df07bdSGlauber de Oliveira Costa 
120b1df07bdSGlauber de Oliveira Costa 	return 5;
121b1df07bdSGlauber de Oliveira Costa }
122b1df07bdSGlauber de Oliveira Costa 
123b1df07bdSGlauber de Oliveira Costa /* Neat trick to map patch type back to the call within the
124b1df07bdSGlauber de Oliveira Costa  * corresponding structure. */
125b1df07bdSGlauber de Oliveira Costa static void *get_call_destination(u8 type)
126b1df07bdSGlauber de Oliveira Costa {
127b1df07bdSGlauber de Oliveira Costa 	struct paravirt_patch_template tmpl = {
128b1df07bdSGlauber de Oliveira Costa 		.pv_init_ops = pv_init_ops,
129b1df07bdSGlauber de Oliveira Costa 		.pv_time_ops = pv_time_ops,
130b1df07bdSGlauber de Oliveira Costa 		.pv_cpu_ops = pv_cpu_ops,
131b1df07bdSGlauber de Oliveira Costa 		.pv_irq_ops = pv_irq_ops,
132b1df07bdSGlauber de Oliveira Costa 		.pv_apic_ops = pv_apic_ops,
133b1df07bdSGlauber de Oliveira Costa 		.pv_mmu_ops = pv_mmu_ops,
134b4ecc126SJeremy Fitzhardinge #ifdef CONFIG_PARAVIRT_SPINLOCKS
13574d4affdSJeremy Fitzhardinge 		.pv_lock_ops = pv_lock_ops,
136b4ecc126SJeremy Fitzhardinge #endif
137b1df07bdSGlauber de Oliveira Costa 	};
138b1df07bdSGlauber de Oliveira Costa 	return *((void **)&tmpl + type);
139b1df07bdSGlauber de Oliveira Costa }
140b1df07bdSGlauber de Oliveira Costa 
141b1df07bdSGlauber de Oliveira Costa unsigned paravirt_patch_default(u8 type, u16 clobbers, void *insnbuf,
142b1df07bdSGlauber de Oliveira Costa 				unsigned long addr, unsigned len)
143b1df07bdSGlauber de Oliveira Costa {
144b1df07bdSGlauber de Oliveira Costa 	void *opfunc = get_call_destination(type);
145b1df07bdSGlauber de Oliveira Costa 	unsigned ret;
146b1df07bdSGlauber de Oliveira Costa 
147b1df07bdSGlauber de Oliveira Costa 	if (opfunc == NULL)
148b1df07bdSGlauber de Oliveira Costa 		/* If there's no function, patch it with a ud2a (BUG) */
149b1df07bdSGlauber de Oliveira Costa 		ret = paravirt_patch_insns(insnbuf, len, ud2a, ud2a+sizeof(ud2a));
15041edafdbSJeremy Fitzhardinge 	else if (opfunc == _paravirt_nop)
151b1df07bdSGlauber de Oliveira Costa 		/* If the operation is a nop, then nop the callsite */
152b1df07bdSGlauber de Oliveira Costa 		ret = paravirt_patch_nop();
15341edafdbSJeremy Fitzhardinge 
15441edafdbSJeremy Fitzhardinge 	/* identity functions just return their single argument */
15541edafdbSJeremy Fitzhardinge 	else if (opfunc == _paravirt_ident_32)
15641edafdbSJeremy Fitzhardinge 		ret = paravirt_patch_ident_32(insnbuf, len);
15741edafdbSJeremy Fitzhardinge 	else if (opfunc == _paravirt_ident_64)
15841edafdbSJeremy Fitzhardinge 		ret = paravirt_patch_ident_64(insnbuf, len);
15941edafdbSJeremy Fitzhardinge 
160b1df07bdSGlauber de Oliveira Costa 	else if (type == PARAVIRT_PATCH(pv_cpu_ops.iret) ||
161d75cd22fSJeremy Fitzhardinge 		 type == PARAVIRT_PATCH(pv_cpu_ops.irq_enable_sysexit) ||
1622be29982SJeremy Fitzhardinge 		 type == PARAVIRT_PATCH(pv_cpu_ops.usergs_sysret32) ||
1632be29982SJeremy Fitzhardinge 		 type == PARAVIRT_PATCH(pv_cpu_ops.usergs_sysret64))
164b1df07bdSGlauber de Oliveira Costa 		/* If operation requires a jmp, then jmp */
165b1df07bdSGlauber de Oliveira Costa 		ret = paravirt_patch_jmp(insnbuf, opfunc, addr, len);
166b1df07bdSGlauber de Oliveira Costa 	else
167b1df07bdSGlauber de Oliveira Costa 		/* Otherwise call the function; assume target could
168b1df07bdSGlauber de Oliveira Costa 		   clobber any caller-save reg */
169b1df07bdSGlauber de Oliveira Costa 		ret = paravirt_patch_call(insnbuf, opfunc, CLBR_ANY,
170b1df07bdSGlauber de Oliveira Costa 					  addr, clobbers, len);
171b1df07bdSGlauber de Oliveira Costa 
172b1df07bdSGlauber de Oliveira Costa 	return ret;
173b1df07bdSGlauber de Oliveira Costa }
174b1df07bdSGlauber de Oliveira Costa 
175b1df07bdSGlauber de Oliveira Costa unsigned paravirt_patch_insns(void *insnbuf, unsigned len,
176b1df07bdSGlauber de Oliveira Costa 			      const char *start, const char *end)
177b1df07bdSGlauber de Oliveira Costa {
178b1df07bdSGlauber de Oliveira Costa 	unsigned insn_len = end - start;
179b1df07bdSGlauber de Oliveira Costa 
180b1df07bdSGlauber de Oliveira Costa 	if (insn_len > len || start == NULL)
181b1df07bdSGlauber de Oliveira Costa 		insn_len = len;
182b1df07bdSGlauber de Oliveira Costa 	else
183b1df07bdSGlauber de Oliveira Costa 		memcpy(insnbuf, start, insn_len);
184b1df07bdSGlauber de Oliveira Costa 
185b1df07bdSGlauber de Oliveira Costa 	return insn_len;
186b1df07bdSGlauber de Oliveira Costa }
187b1df07bdSGlauber de Oliveira Costa 
188b1df07bdSGlauber de Oliveira Costa static void native_flush_tlb(void)
189b1df07bdSGlauber de Oliveira Costa {
190b1df07bdSGlauber de Oliveira Costa 	__native_flush_tlb();
191b1df07bdSGlauber de Oliveira Costa }
192b1df07bdSGlauber de Oliveira Costa 
193b1df07bdSGlauber de Oliveira Costa /*
194b1df07bdSGlauber de Oliveira Costa  * Global pages have to be flushed a bit differently. Not a real
195b1df07bdSGlauber de Oliveira Costa  * performance problem because this does not happen often.
196b1df07bdSGlauber de Oliveira Costa  */
197b1df07bdSGlauber de Oliveira Costa static void native_flush_tlb_global(void)
198b1df07bdSGlauber de Oliveira Costa {
199b1df07bdSGlauber de Oliveira Costa 	__native_flush_tlb_global();
200b1df07bdSGlauber de Oliveira Costa }
201b1df07bdSGlauber de Oliveira Costa 
202b1df07bdSGlauber de Oliveira Costa static void native_flush_tlb_single(unsigned long addr)
203b1df07bdSGlauber de Oliveira Costa {
204b1df07bdSGlauber de Oliveira Costa 	__native_flush_tlb_single(addr);
205b1df07bdSGlauber de Oliveira Costa }
206b1df07bdSGlauber de Oliveira Costa 
207c5905afbSIngo Molnar struct static_key paravirt_steal_enabled;
208c5905afbSIngo Molnar struct static_key paravirt_steal_rq_enabled;
2093c404b57SGlauber Costa 
2103c404b57SGlauber Costa static u64 native_steal_clock(int cpu)
2113c404b57SGlauber Costa {
2123c404b57SGlauber Costa 	return 0;
2133c404b57SGlauber Costa }
2143c404b57SGlauber Costa 
215b1df07bdSGlauber de Oliveira Costa /* These are in entry.S */
216b1df07bdSGlauber de Oliveira Costa extern void native_iret(void);
217d75cd22fSJeremy Fitzhardinge extern void native_irq_enable_sysexit(void);
2182be29982SJeremy Fitzhardinge extern void native_usergs_sysret32(void);
2192be29982SJeremy Fitzhardinge extern void native_usergs_sysret64(void);
220b1df07bdSGlauber de Oliveira Costa 
221b1df07bdSGlauber de Oliveira Costa static struct resource reserve_ioports = {
222b1df07bdSGlauber de Oliveira Costa 	.start = 0,
223b1df07bdSGlauber de Oliveira Costa 	.end = IO_SPACE_LIMIT,
224b1df07bdSGlauber de Oliveira Costa 	.name = "paravirt-ioport",
225b1df07bdSGlauber de Oliveira Costa 	.flags = IORESOURCE_IO | IORESOURCE_BUSY,
226b1df07bdSGlauber de Oliveira Costa };
227b1df07bdSGlauber de Oliveira Costa 
228b1df07bdSGlauber de Oliveira Costa /*
229b1df07bdSGlauber de Oliveira Costa  * Reserve the whole legacy IO space to prevent any legacy drivers
230b1df07bdSGlauber de Oliveira Costa  * from wasting time probing for their hardware.  This is a fairly
231b1df07bdSGlauber de Oliveira Costa  * brute-force approach to disabling all non-virtual drivers.
232b1df07bdSGlauber de Oliveira Costa  *
233b1df07bdSGlauber de Oliveira Costa  * Note that this must be called very early to have any effect.
234b1df07bdSGlauber de Oliveira Costa  */
235b1df07bdSGlauber de Oliveira Costa int paravirt_disable_iospace(void)
236b1df07bdSGlauber de Oliveira Costa {
237f7743fe6SJeremy Fitzhardinge 	return request_resource(&ioport_resource, &reserve_ioports);
238b1df07bdSGlauber de Oliveira Costa }
239b1df07bdSGlauber de Oliveira Costa 
240b1df07bdSGlauber de Oliveira Costa static DEFINE_PER_CPU(enum paravirt_lazy_mode, paravirt_lazy_mode) = PARAVIRT_LAZY_NONE;
241b1df07bdSGlauber de Oliveira Costa 
242b1df07bdSGlauber de Oliveira Costa static inline void enter_lazy(enum paravirt_lazy_mode mode)
243b1df07bdSGlauber de Oliveira Costa {
244c6ae41e7SAlex Shi 	BUG_ON(this_cpu_read(paravirt_lazy_mode) != PARAVIRT_LAZY_NONE);
245b1df07bdSGlauber de Oliveira Costa 
246c6ae41e7SAlex Shi 	this_cpu_write(paravirt_lazy_mode, mode);
247b1df07bdSGlauber de Oliveira Costa }
248b1df07bdSGlauber de Oliveira Costa 
249b407fc57SJeremy Fitzhardinge static void leave_lazy(enum paravirt_lazy_mode mode)
250b1df07bdSGlauber de Oliveira Costa {
251c6ae41e7SAlex Shi 	BUG_ON(this_cpu_read(paravirt_lazy_mode) != mode);
252b1df07bdSGlauber de Oliveira Costa 
253c6ae41e7SAlex Shi 	this_cpu_write(paravirt_lazy_mode, PARAVIRT_LAZY_NONE);
254b1df07bdSGlauber de Oliveira Costa }
255b1df07bdSGlauber de Oliveira Costa 
256b1df07bdSGlauber de Oliveira Costa void paravirt_enter_lazy_mmu(void)
257b1df07bdSGlauber de Oliveira Costa {
258b1df07bdSGlauber de Oliveira Costa 	enter_lazy(PARAVIRT_LAZY_MMU);
259b1df07bdSGlauber de Oliveira Costa }
260b1df07bdSGlauber de Oliveira Costa 
261b1df07bdSGlauber de Oliveira Costa void paravirt_leave_lazy_mmu(void)
262b1df07bdSGlauber de Oliveira Costa {
263b407fc57SJeremy Fitzhardinge 	leave_lazy(PARAVIRT_LAZY_MMU);
264b1df07bdSGlauber de Oliveira Costa }
265b1df07bdSGlauber de Oliveira Costa 
266511ba86eSBoris Ostrovsky void paravirt_flush_lazy_mmu(void)
267511ba86eSBoris Ostrovsky {
268511ba86eSBoris Ostrovsky 	preempt_disable();
269511ba86eSBoris Ostrovsky 
270511ba86eSBoris Ostrovsky 	if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU) {
271511ba86eSBoris Ostrovsky 		arch_leave_lazy_mmu_mode();
272511ba86eSBoris Ostrovsky 		arch_enter_lazy_mmu_mode();
273511ba86eSBoris Ostrovsky 	}
274511ba86eSBoris Ostrovsky 
275511ba86eSBoris Ostrovsky 	preempt_enable();
276511ba86eSBoris Ostrovsky }
277511ba86eSBoris Ostrovsky 
278224101edSJeremy Fitzhardinge void paravirt_start_context_switch(struct task_struct *prev)
279b1df07bdSGlauber de Oliveira Costa {
2802829b449SJeremy Fitzhardinge 	BUG_ON(preemptible());
2812829b449SJeremy Fitzhardinge 
282c6ae41e7SAlex Shi 	if (this_cpu_read(paravirt_lazy_mode) == PARAVIRT_LAZY_MMU) {
283b407fc57SJeremy Fitzhardinge 		arch_leave_lazy_mmu_mode();
284224101edSJeremy Fitzhardinge 		set_ti_thread_flag(task_thread_info(prev), TIF_LAZY_MMU_UPDATES);
285b407fc57SJeremy Fitzhardinge 	}
286b1df07bdSGlauber de Oliveira Costa 	enter_lazy(PARAVIRT_LAZY_CPU);
287b1df07bdSGlauber de Oliveira Costa }
288b1df07bdSGlauber de Oliveira Costa 
289224101edSJeremy Fitzhardinge void paravirt_end_context_switch(struct task_struct *next)
290b1df07bdSGlauber de Oliveira Costa {
2912829b449SJeremy Fitzhardinge 	BUG_ON(preemptible());
2922829b449SJeremy Fitzhardinge 
293b407fc57SJeremy Fitzhardinge 	leave_lazy(PARAVIRT_LAZY_CPU);
294b407fc57SJeremy Fitzhardinge 
295224101edSJeremy Fitzhardinge 	if (test_and_clear_ti_thread_flag(task_thread_info(next), TIF_LAZY_MMU_UPDATES))
296b407fc57SJeremy Fitzhardinge 		arch_enter_lazy_mmu_mode();
297b1df07bdSGlauber de Oliveira Costa }
298b1df07bdSGlauber de Oliveira Costa 
299b1df07bdSGlauber de Oliveira Costa enum paravirt_lazy_mode paravirt_get_lazy_mode(void)
300b1df07bdSGlauber de Oliveira Costa {
301b8bcfe99SJeremy Fitzhardinge 	if (in_interrupt())
302b8bcfe99SJeremy Fitzhardinge 		return PARAVIRT_LAZY_NONE;
303b8bcfe99SJeremy Fitzhardinge 
304c6ae41e7SAlex Shi 	return this_cpu_read(paravirt_lazy_mode);
305b1df07bdSGlauber de Oliveira Costa }
306b1df07bdSGlauber de Oliveira Costa 
307b1df07bdSGlauber de Oliveira Costa struct pv_info pv_info = {
308b1df07bdSGlauber de Oliveira Costa 	.name = "bare hardware",
309b1df07bdSGlauber de Oliveira Costa 	.paravirt_enabled = 0,
310b1df07bdSGlauber de Oliveira Costa 	.kernel_rpl = 0,
311b1df07bdSGlauber de Oliveira Costa 	.shared_kernel_pmd = 1,	/* Only used when CONFIG_X86_PAE is set */
312318f5a2aSAndy Lutomirski 
313318f5a2aSAndy Lutomirski #ifdef CONFIG_X86_64
314318f5a2aSAndy Lutomirski 	.extra_user_64bit_cs = __USER_CS,
315318f5a2aSAndy Lutomirski #endif
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 };
321b1df07bdSGlauber de Oliveira Costa 
322b1df07bdSGlauber de Oliveira Costa struct pv_time_ops pv_time_ops = {
323b1df07bdSGlauber de Oliveira Costa 	.sched_clock = native_sched_clock,
3243c404b57SGlauber Costa 	.steal_clock = native_steal_clock,
325b1df07bdSGlauber de Oliveira Costa };
326b1df07bdSGlauber de Oliveira Costa 
3279a55fdbeSAndi Kleen __visible struct pv_irq_ops pv_irq_ops = {
328ecb93d1cSJeremy Fitzhardinge 	.save_fl = __PV_IS_CALLEE_SAVE(native_save_fl),
329ecb93d1cSJeremy Fitzhardinge 	.restore_fl = __PV_IS_CALLEE_SAVE(native_restore_fl),
330ecb93d1cSJeremy Fitzhardinge 	.irq_disable = __PV_IS_CALLEE_SAVE(native_irq_disable),
331ecb93d1cSJeremy Fitzhardinge 	.irq_enable = __PV_IS_CALLEE_SAVE(native_irq_enable),
332b1df07bdSGlauber de Oliveira Costa 	.safe_halt = native_safe_halt,
333b1df07bdSGlauber de Oliveira Costa 	.halt = native_halt,
334fab58420SJeremy Fitzhardinge #ifdef CONFIG_X86_64
335fab58420SJeremy Fitzhardinge 	.adjust_exception_frame = paravirt_nop,
336fab58420SJeremy Fitzhardinge #endif
337b1df07bdSGlauber de Oliveira Costa };
338b1df07bdSGlauber de Oliveira Costa 
3399a55fdbeSAndi Kleen __visible struct pv_cpu_ops pv_cpu_ops = {
340b1df07bdSGlauber de Oliveira Costa 	.cpuid = native_cpuid,
341b1df07bdSGlauber de Oliveira Costa 	.get_debugreg = native_get_debugreg,
342b1df07bdSGlauber de Oliveira Costa 	.set_debugreg = native_set_debugreg,
343b1df07bdSGlauber de Oliveira Costa 	.clts = native_clts,
344b1df07bdSGlauber de Oliveira Costa 	.read_cr0 = native_read_cr0,
345b1df07bdSGlauber de Oliveira Costa 	.write_cr0 = native_write_cr0,
346b1df07bdSGlauber de Oliveira Costa 	.read_cr4 = native_read_cr4,
347b1df07bdSGlauber de Oliveira Costa 	.read_cr4_safe = native_read_cr4_safe,
348b1df07bdSGlauber de Oliveira Costa 	.write_cr4 = native_write_cr4,
34988b4755fSGlauber de Oliveira Costa #ifdef CONFIG_X86_64
35088b4755fSGlauber de Oliveira Costa 	.read_cr8 = native_read_cr8,
35188b4755fSGlauber de Oliveira Costa 	.write_cr8 = native_write_cr8,
35288b4755fSGlauber de Oliveira Costa #endif
353b1df07bdSGlauber de Oliveira Costa 	.wbinvd = native_wbinvd,
354b1df07bdSGlauber de Oliveira Costa 	.read_msr = native_read_msr_safe,
355b1df07bdSGlauber de Oliveira Costa 	.write_msr = native_write_msr_safe,
356b1df07bdSGlauber de Oliveira Costa 	.read_tsc = native_read_tsc,
357b1df07bdSGlauber de Oliveira Costa 	.read_pmc = native_read_pmc,
358e5aaac44SGlauber de Oliveira Costa 	.read_tscp = native_read_tscp,
359b1df07bdSGlauber de Oliveira Costa 	.load_tr_desc = native_load_tr_desc,
360b1df07bdSGlauber de Oliveira Costa 	.set_ldt = native_set_ldt,
361b1df07bdSGlauber de Oliveira Costa 	.load_gdt = native_load_gdt,
362b1df07bdSGlauber de Oliveira Costa 	.load_idt = native_load_idt,
363b1df07bdSGlauber de Oliveira Costa 	.store_idt = native_store_idt,
364b1df07bdSGlauber de Oliveira Costa 	.store_tr = native_store_tr,
365b1df07bdSGlauber de Oliveira Costa 	.load_tls = native_load_tls,
3669f9d489aSJeremy Fitzhardinge #ifdef CONFIG_X86_64
3679f9d489aSJeremy Fitzhardinge 	.load_gs_index = native_load_gs_index,
3689f9d489aSJeremy Fitzhardinge #endif
369b1df07bdSGlauber de Oliveira Costa 	.write_ldt_entry = native_write_ldt_entry,
370b1df07bdSGlauber de Oliveira Costa 	.write_gdt_entry = native_write_gdt_entry,
371b1df07bdSGlauber de Oliveira Costa 	.write_idt_entry = native_write_idt_entry,
37238ffbe66SJeremy Fitzhardinge 
37338ffbe66SJeremy Fitzhardinge 	.alloc_ldt = paravirt_nop,
37438ffbe66SJeremy Fitzhardinge 	.free_ldt = paravirt_nop,
37538ffbe66SJeremy Fitzhardinge 
376b1df07bdSGlauber de Oliveira Costa 	.load_sp0 = native_load_sp0,
377b1df07bdSGlauber de Oliveira Costa 
378102d0a4bSJeremy Fitzhardinge #if defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION)
379d75cd22fSJeremy Fitzhardinge 	.irq_enable_sysexit = native_irq_enable_sysexit,
380102d0a4bSJeremy Fitzhardinge #endif
3812be29982SJeremy Fitzhardinge #ifdef CONFIG_X86_64
382102d0a4bSJeremy Fitzhardinge #ifdef CONFIG_IA32_EMULATION
3832be29982SJeremy Fitzhardinge 	.usergs_sysret32 = native_usergs_sysret32,
384102d0a4bSJeremy Fitzhardinge #endif
3852be29982SJeremy Fitzhardinge 	.usergs_sysret64 = native_usergs_sysret64,
386d75cd22fSJeremy Fitzhardinge #endif
387b1df07bdSGlauber de Oliveira Costa 	.iret = native_iret,
388e801f864SGlauber de Oliveira Costa 	.swapgs = native_swapgs,
389b1df07bdSGlauber de Oliveira Costa 
390b1df07bdSGlauber de Oliveira Costa 	.set_iopl_mask = native_set_iopl_mask,
391b1df07bdSGlauber de Oliveira Costa 	.io_delay = native_io_delay,
392b1df07bdSGlauber de Oliveira Costa 
393224101edSJeremy Fitzhardinge 	.start_context_switch = paravirt_nop,
394224101edSJeremy Fitzhardinge 	.end_context_switch = paravirt_nop,
395b1df07bdSGlauber de Oliveira Costa };
396b1df07bdSGlauber de Oliveira Costa 
397b1df07bdSGlauber de Oliveira Costa struct pv_apic_ops pv_apic_ops = {
398b1df07bdSGlauber de Oliveira Costa #ifdef CONFIG_X86_LOCAL_APIC
399b1df07bdSGlauber de Oliveira Costa 	.startup_ipi_hook = paravirt_nop,
400b1df07bdSGlauber de Oliveira Costa #endif
401b1df07bdSGlauber de Oliveira Costa };
402b1df07bdSGlauber de Oliveira Costa 
40341edafdbSJeremy Fitzhardinge #if defined(CONFIG_X86_32) && !defined(CONFIG_X86_PAE)
40441edafdbSJeremy Fitzhardinge /* 32-bit pagetable entries */
405da5de7c2SJeremy Fitzhardinge #define PTE_IDENT	__PV_IS_CALLEE_SAVE(_paravirt_ident_32)
40641edafdbSJeremy Fitzhardinge #else
40741edafdbSJeremy Fitzhardinge /* 64-bit pagetable entries */
408da5de7c2SJeremy Fitzhardinge #define PTE_IDENT	__PV_IS_CALLEE_SAVE(_paravirt_ident_64)
40941edafdbSJeremy Fitzhardinge #endif
41041edafdbSJeremy Fitzhardinge 
411b1df07bdSGlauber de Oliveira Costa struct pv_mmu_ops pv_mmu_ops = {
412b1df07bdSGlauber de Oliveira Costa 
413b1df07bdSGlauber de Oliveira Costa 	.read_cr2 = native_read_cr2,
414b1df07bdSGlauber de Oliveira Costa 	.write_cr2 = native_write_cr2,
415b1df07bdSGlauber de Oliveira Costa 	.read_cr3 = native_read_cr3,
416b1df07bdSGlauber de Oliveira Costa 	.write_cr3 = native_write_cr3,
417b1df07bdSGlauber de Oliveira Costa 
418b1df07bdSGlauber de Oliveira Costa 	.flush_tlb_user = native_flush_tlb,
419b1df07bdSGlauber de Oliveira Costa 	.flush_tlb_kernel = native_flush_tlb_global,
420b1df07bdSGlauber de Oliveira Costa 	.flush_tlb_single = native_flush_tlb_single,
421b1df07bdSGlauber de Oliveira Costa 	.flush_tlb_others = native_flush_tlb_others,
422b1df07bdSGlauber de Oliveira Costa 
423eba0045fSJeremy Fitzhardinge 	.pgd_alloc = __paravirt_pgd_alloc,
424eba0045fSJeremy Fitzhardinge 	.pgd_free = paravirt_nop,
425eba0045fSJeremy Fitzhardinge 
4266944a9c8SJeremy Fitzhardinge 	.alloc_pte = paravirt_nop,
4276944a9c8SJeremy Fitzhardinge 	.alloc_pmd = paravirt_nop,
4282761fa09SJeremy Fitzhardinge 	.alloc_pud = paravirt_nop,
4296944a9c8SJeremy Fitzhardinge 	.release_pte = paravirt_nop,
4306944a9c8SJeremy Fitzhardinge 	.release_pmd = paravirt_nop,
4312761fa09SJeremy Fitzhardinge 	.release_pud = paravirt_nop,
432b1df07bdSGlauber de Oliveira Costa 
433b1df07bdSGlauber de Oliveira Costa 	.set_pte = native_set_pte,
434b1df07bdSGlauber de Oliveira Costa 	.set_pte_at = native_set_pte_at,
435b1df07bdSGlauber de Oliveira Costa 	.set_pmd = native_set_pmd,
436331127f7SAndrea Arcangeli 	.set_pmd_at = native_set_pmd_at,
437b1df07bdSGlauber de Oliveira Costa 	.pte_update = paravirt_nop,
438b1df07bdSGlauber de Oliveira Costa 	.pte_update_defer = paravirt_nop,
439331127f7SAndrea Arcangeli 	.pmd_update = paravirt_nop,
440331127f7SAndrea Arcangeli 	.pmd_update_defer = paravirt_nop,
441b1df07bdSGlauber de Oliveira Costa 
44208b882c6SJeremy Fitzhardinge 	.ptep_modify_prot_start = __ptep_modify_prot_start,
44308b882c6SJeremy Fitzhardinge 	.ptep_modify_prot_commit = __ptep_modify_prot_commit,
44408b882c6SJeremy Fitzhardinge 
445f95f2f7bSEduardo Habkost #if PAGETABLE_LEVELS >= 3
446b1df07bdSGlauber de Oliveira Costa #ifdef CONFIG_X86_PAE
447b1df07bdSGlauber de Oliveira Costa 	.set_pte_atomic = native_set_pte_atomic,
448b1df07bdSGlauber de Oliveira Costa 	.pte_clear = native_pte_clear,
449b1df07bdSGlauber de Oliveira Costa 	.pmd_clear = native_pmd_clear,
450f95f2f7bSEduardo Habkost #endif
451f95f2f7bSEduardo Habkost 	.set_pud = native_set_pud,
452da5de7c2SJeremy Fitzhardinge 
453da5de7c2SJeremy Fitzhardinge 	.pmd_val = PTE_IDENT,
454da5de7c2SJeremy Fitzhardinge 	.make_pmd = PTE_IDENT,
455f95f2f7bSEduardo Habkost 
456f95f2f7bSEduardo Habkost #if PAGETABLE_LEVELS == 4
457da5de7c2SJeremy Fitzhardinge 	.pud_val = PTE_IDENT,
458da5de7c2SJeremy Fitzhardinge 	.make_pud = PTE_IDENT,
459da5de7c2SJeremy Fitzhardinge 
460f95f2f7bSEduardo Habkost 	.set_pgd = native_set_pgd,
461b1df07bdSGlauber de Oliveira Costa #endif
462f95f2f7bSEduardo Habkost #endif /* PAGETABLE_LEVELS >= 3 */
463b1df07bdSGlauber de Oliveira Costa 
464da5de7c2SJeremy Fitzhardinge 	.pte_val = PTE_IDENT,
465da5de7c2SJeremy Fitzhardinge 	.pgd_val = PTE_IDENT,
466b1df07bdSGlauber de Oliveira Costa 
467da5de7c2SJeremy Fitzhardinge 	.make_pte = PTE_IDENT,
468da5de7c2SJeremy Fitzhardinge 	.make_pgd = PTE_IDENT,
469b1df07bdSGlauber de Oliveira Costa 
470b1df07bdSGlauber de Oliveira Costa 	.dup_mmap = paravirt_nop,
471b1df07bdSGlauber de Oliveira Costa 	.exit_mmap = paravirt_nop,
472b1df07bdSGlauber de Oliveira Costa 	.activate_mm = paravirt_nop,
473b1df07bdSGlauber de Oliveira Costa 
474b1df07bdSGlauber de Oliveira Costa 	.lazy_mode = {
475b1df07bdSGlauber de Oliveira Costa 		.enter = paravirt_nop,
476b1df07bdSGlauber de Oliveira Costa 		.leave = paravirt_nop,
477511ba86eSBoris Ostrovsky 		.flush = paravirt_nop,
478b1df07bdSGlauber de Oliveira Costa 	},
479aeaaa59cSJeremy Fitzhardinge 
480aeaaa59cSJeremy Fitzhardinge 	.set_fixmap = native_set_fixmap,
481b1df07bdSGlauber de Oliveira Costa };
482b1df07bdSGlauber de Oliveira Costa 
483b1df07bdSGlauber de Oliveira Costa EXPORT_SYMBOL_GPL(pv_time_ops);
484b1df07bdSGlauber de Oliveira Costa EXPORT_SYMBOL    (pv_cpu_ops);
485b1df07bdSGlauber de Oliveira Costa EXPORT_SYMBOL    (pv_mmu_ops);
486b1df07bdSGlauber de Oliveira Costa EXPORT_SYMBOL_GPL(pv_apic_ops);
487b1df07bdSGlauber de Oliveira Costa EXPORT_SYMBOL_GPL(pv_info);
488b1df07bdSGlauber de Oliveira Costa EXPORT_SYMBOL    (pv_irq_ops);
489