xref: /openbmc/linux/arch/x86/kernel/paravirt.c (revision 318f5a2a)
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 
576f30c1acSThomas Gleixner 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 /* Simple instruction patching code. */
64b1df07bdSGlauber de Oliveira Costa #define DEF_NATIVE(ops, name, code)					\
65b1df07bdSGlauber de Oliveira Costa 	extern const char start_##ops##_##name[], end_##ops##_##name[];	\
66b1df07bdSGlauber de Oliveira Costa 	asm("start_" #ops "_" #name ": " code "; end_" #ops "_" #name ":")
67b1df07bdSGlauber de Oliveira Costa 
68b1df07bdSGlauber de Oliveira Costa /* Undefined instruction for dealing with missing ops pointers. */
69b1df07bdSGlauber de Oliveira Costa static const unsigned char ud2a[] = { 0x0f, 0x0b };
70b1df07bdSGlauber de Oliveira Costa 
71b1df07bdSGlauber de Oliveira Costa unsigned paravirt_patch_nop(void)
72b1df07bdSGlauber de Oliveira Costa {
73b1df07bdSGlauber de Oliveira Costa 	return 0;
74b1df07bdSGlauber de Oliveira Costa }
75b1df07bdSGlauber de Oliveira Costa 
76b1df07bdSGlauber de Oliveira Costa unsigned paravirt_patch_ignore(unsigned len)
77b1df07bdSGlauber de Oliveira Costa {
78b1df07bdSGlauber de Oliveira Costa 	return len;
79b1df07bdSGlauber de Oliveira Costa }
80b1df07bdSGlauber de Oliveira Costa 
81b1df07bdSGlauber de Oliveira Costa struct branch {
82b1df07bdSGlauber de Oliveira Costa 	unsigned char opcode;
83b1df07bdSGlauber de Oliveira Costa 	u32 delta;
84b1df07bdSGlauber de Oliveira Costa } __attribute__((packed));
85b1df07bdSGlauber de Oliveira Costa 
86b1df07bdSGlauber de Oliveira Costa unsigned paravirt_patch_call(void *insnbuf,
87b1df07bdSGlauber de Oliveira Costa 			     const void *target, u16 tgt_clobbers,
88b1df07bdSGlauber de Oliveira Costa 			     unsigned long addr, u16 site_clobbers,
89b1df07bdSGlauber de Oliveira Costa 			     unsigned len)
90b1df07bdSGlauber de Oliveira Costa {
91b1df07bdSGlauber de Oliveira Costa 	struct branch *b = insnbuf;
92b1df07bdSGlauber de Oliveira Costa 	unsigned long delta = (unsigned long)target - (addr+5);
93b1df07bdSGlauber de Oliveira Costa 
94b1df07bdSGlauber de Oliveira Costa 	if (tgt_clobbers & ~site_clobbers)
95b1df07bdSGlauber de Oliveira Costa 		return len;	/* target would clobber too much for this site */
96b1df07bdSGlauber de Oliveira Costa 	if (len < 5)
97b1df07bdSGlauber de Oliveira Costa 		return len;	/* call too long for patch site */
98b1df07bdSGlauber de Oliveira Costa 
99b1df07bdSGlauber de Oliveira Costa 	b->opcode = 0xe8; /* call */
100b1df07bdSGlauber de Oliveira Costa 	b->delta = delta;
101b1df07bdSGlauber de Oliveira Costa 	BUILD_BUG_ON(sizeof(*b) != 5);
102b1df07bdSGlauber de Oliveira Costa 
103b1df07bdSGlauber de Oliveira Costa 	return 5;
104b1df07bdSGlauber de Oliveira Costa }
105b1df07bdSGlauber de Oliveira Costa 
106b1df07bdSGlauber de Oliveira Costa unsigned paravirt_patch_jmp(void *insnbuf, const void *target,
107b1df07bdSGlauber de Oliveira Costa 			    unsigned long addr, unsigned len)
108b1df07bdSGlauber de Oliveira Costa {
109b1df07bdSGlauber de Oliveira Costa 	struct branch *b = insnbuf;
110b1df07bdSGlauber de Oliveira Costa 	unsigned long delta = (unsigned long)target - (addr+5);
111b1df07bdSGlauber de Oliveira Costa 
112b1df07bdSGlauber de Oliveira Costa 	if (len < 5)
113b1df07bdSGlauber de Oliveira Costa 		return len;	/* call too long for patch site */
114b1df07bdSGlauber de Oliveira Costa 
115b1df07bdSGlauber de Oliveira Costa 	b->opcode = 0xe9;	/* jmp */
116b1df07bdSGlauber de Oliveira Costa 	b->delta = delta;
117b1df07bdSGlauber de Oliveira Costa 
118b1df07bdSGlauber de Oliveira Costa 	return 5;
119b1df07bdSGlauber de Oliveira Costa }
120b1df07bdSGlauber de Oliveira Costa 
121b1df07bdSGlauber de Oliveira Costa /* Neat trick to map patch type back to the call within the
122b1df07bdSGlauber de Oliveira Costa  * corresponding structure. */
123b1df07bdSGlauber de Oliveira Costa static void *get_call_destination(u8 type)
124b1df07bdSGlauber de Oliveira Costa {
125b1df07bdSGlauber de Oliveira Costa 	struct paravirt_patch_template tmpl = {
126b1df07bdSGlauber de Oliveira Costa 		.pv_init_ops = pv_init_ops,
127b1df07bdSGlauber de Oliveira Costa 		.pv_time_ops = pv_time_ops,
128b1df07bdSGlauber de Oliveira Costa 		.pv_cpu_ops = pv_cpu_ops,
129b1df07bdSGlauber de Oliveira Costa 		.pv_irq_ops = pv_irq_ops,
130b1df07bdSGlauber de Oliveira Costa 		.pv_apic_ops = pv_apic_ops,
131b1df07bdSGlauber de Oliveira Costa 		.pv_mmu_ops = pv_mmu_ops,
132b4ecc126SJeremy Fitzhardinge #ifdef CONFIG_PARAVIRT_SPINLOCKS
13374d4affdSJeremy Fitzhardinge 		.pv_lock_ops = pv_lock_ops,
134b4ecc126SJeremy Fitzhardinge #endif
135b1df07bdSGlauber de Oliveira Costa 	};
136b1df07bdSGlauber de Oliveira Costa 	return *((void **)&tmpl + type);
137b1df07bdSGlauber de Oliveira Costa }
138b1df07bdSGlauber de Oliveira Costa 
139b1df07bdSGlauber de Oliveira Costa unsigned paravirt_patch_default(u8 type, u16 clobbers, void *insnbuf,
140b1df07bdSGlauber de Oliveira Costa 				unsigned long addr, unsigned len)
141b1df07bdSGlauber de Oliveira Costa {
142b1df07bdSGlauber de Oliveira Costa 	void *opfunc = get_call_destination(type);
143b1df07bdSGlauber de Oliveira Costa 	unsigned ret;
144b1df07bdSGlauber de Oliveira Costa 
145b1df07bdSGlauber de Oliveira Costa 	if (opfunc == NULL)
146b1df07bdSGlauber de Oliveira Costa 		/* If there's no function, patch it with a ud2a (BUG) */
147b1df07bdSGlauber de Oliveira Costa 		ret = paravirt_patch_insns(insnbuf, len, ud2a, ud2a+sizeof(ud2a));
14841edafdbSJeremy Fitzhardinge 	else if (opfunc == _paravirt_nop)
149b1df07bdSGlauber de Oliveira Costa 		/* If the operation is a nop, then nop the callsite */
150b1df07bdSGlauber de Oliveira Costa 		ret = paravirt_patch_nop();
15141edafdbSJeremy Fitzhardinge 
15241edafdbSJeremy Fitzhardinge 	/* identity functions just return their single argument */
15341edafdbSJeremy Fitzhardinge 	else if (opfunc == _paravirt_ident_32)
15441edafdbSJeremy Fitzhardinge 		ret = paravirt_patch_ident_32(insnbuf, len);
15541edafdbSJeremy Fitzhardinge 	else if (opfunc == _paravirt_ident_64)
15641edafdbSJeremy Fitzhardinge 		ret = paravirt_patch_ident_64(insnbuf, len);
15741edafdbSJeremy Fitzhardinge 
158b1df07bdSGlauber de Oliveira Costa 	else if (type == PARAVIRT_PATCH(pv_cpu_ops.iret) ||
159d75cd22fSJeremy Fitzhardinge 		 type == PARAVIRT_PATCH(pv_cpu_ops.irq_enable_sysexit) ||
1602be29982SJeremy Fitzhardinge 		 type == PARAVIRT_PATCH(pv_cpu_ops.usergs_sysret32) ||
1612be29982SJeremy Fitzhardinge 		 type == PARAVIRT_PATCH(pv_cpu_ops.usergs_sysret64))
162b1df07bdSGlauber de Oliveira Costa 		/* If operation requires a jmp, then jmp */
163b1df07bdSGlauber de Oliveira Costa 		ret = paravirt_patch_jmp(insnbuf, opfunc, addr, len);
164b1df07bdSGlauber de Oliveira Costa 	else
165b1df07bdSGlauber de Oliveira Costa 		/* Otherwise call the function; assume target could
166b1df07bdSGlauber de Oliveira Costa 		   clobber any caller-save reg */
167b1df07bdSGlauber de Oliveira Costa 		ret = paravirt_patch_call(insnbuf, opfunc, CLBR_ANY,
168b1df07bdSGlauber de Oliveira Costa 					  addr, clobbers, len);
169b1df07bdSGlauber de Oliveira Costa 
170b1df07bdSGlauber de Oliveira Costa 	return ret;
171b1df07bdSGlauber de Oliveira Costa }
172b1df07bdSGlauber de Oliveira Costa 
173b1df07bdSGlauber de Oliveira Costa unsigned paravirt_patch_insns(void *insnbuf, unsigned len,
174b1df07bdSGlauber de Oliveira Costa 			      const char *start, const char *end)
175b1df07bdSGlauber de Oliveira Costa {
176b1df07bdSGlauber de Oliveira Costa 	unsigned insn_len = end - start;
177b1df07bdSGlauber de Oliveira Costa 
178b1df07bdSGlauber de Oliveira Costa 	if (insn_len > len || start == NULL)
179b1df07bdSGlauber de Oliveira Costa 		insn_len = len;
180b1df07bdSGlauber de Oliveira Costa 	else
181b1df07bdSGlauber de Oliveira Costa 		memcpy(insnbuf, start, insn_len);
182b1df07bdSGlauber de Oliveira Costa 
183b1df07bdSGlauber de Oliveira Costa 	return insn_len;
184b1df07bdSGlauber de Oliveira Costa }
185b1df07bdSGlauber de Oliveira Costa 
186b1df07bdSGlauber de Oliveira Costa static void native_flush_tlb(void)
187b1df07bdSGlauber de Oliveira Costa {
188b1df07bdSGlauber de Oliveira Costa 	__native_flush_tlb();
189b1df07bdSGlauber de Oliveira Costa }
190b1df07bdSGlauber de Oliveira Costa 
191b1df07bdSGlauber de Oliveira Costa /*
192b1df07bdSGlauber de Oliveira Costa  * Global pages have to be flushed a bit differently. Not a real
193b1df07bdSGlauber de Oliveira Costa  * performance problem because this does not happen often.
194b1df07bdSGlauber de Oliveira Costa  */
195b1df07bdSGlauber de Oliveira Costa static void native_flush_tlb_global(void)
196b1df07bdSGlauber de Oliveira Costa {
197b1df07bdSGlauber de Oliveira Costa 	__native_flush_tlb_global();
198b1df07bdSGlauber de Oliveira Costa }
199b1df07bdSGlauber de Oliveira Costa 
200b1df07bdSGlauber de Oliveira Costa static void native_flush_tlb_single(unsigned long addr)
201b1df07bdSGlauber de Oliveira Costa {
202b1df07bdSGlauber de Oliveira Costa 	__native_flush_tlb_single(addr);
203b1df07bdSGlauber de Oliveira Costa }
204b1df07bdSGlauber de Oliveira Costa 
205b1df07bdSGlauber de Oliveira Costa /* These are in entry.S */
206b1df07bdSGlauber de Oliveira Costa extern void native_iret(void);
207d75cd22fSJeremy Fitzhardinge extern void native_irq_enable_sysexit(void);
2082be29982SJeremy Fitzhardinge extern void native_usergs_sysret32(void);
2092be29982SJeremy Fitzhardinge extern void native_usergs_sysret64(void);
210b1df07bdSGlauber de Oliveira Costa 
211b1df07bdSGlauber de Oliveira Costa static struct resource reserve_ioports = {
212b1df07bdSGlauber de Oliveira Costa 	.start = 0,
213b1df07bdSGlauber de Oliveira Costa 	.end = IO_SPACE_LIMIT,
214b1df07bdSGlauber de Oliveira Costa 	.name = "paravirt-ioport",
215b1df07bdSGlauber de Oliveira Costa 	.flags = IORESOURCE_IO | IORESOURCE_BUSY,
216b1df07bdSGlauber de Oliveira Costa };
217b1df07bdSGlauber de Oliveira Costa 
218b1df07bdSGlauber de Oliveira Costa /*
219b1df07bdSGlauber de Oliveira Costa  * Reserve the whole legacy IO space to prevent any legacy drivers
220b1df07bdSGlauber de Oliveira Costa  * from wasting time probing for their hardware.  This is a fairly
221b1df07bdSGlauber de Oliveira Costa  * brute-force approach to disabling all non-virtual drivers.
222b1df07bdSGlauber de Oliveira Costa  *
223b1df07bdSGlauber de Oliveira Costa  * Note that this must be called very early to have any effect.
224b1df07bdSGlauber de Oliveira Costa  */
225b1df07bdSGlauber de Oliveira Costa int paravirt_disable_iospace(void)
226b1df07bdSGlauber de Oliveira Costa {
227f7743fe6SJeremy Fitzhardinge 	return request_resource(&ioport_resource, &reserve_ioports);
228b1df07bdSGlauber de Oliveira Costa }
229b1df07bdSGlauber de Oliveira Costa 
230b1df07bdSGlauber de Oliveira Costa static DEFINE_PER_CPU(enum paravirt_lazy_mode, paravirt_lazy_mode) = PARAVIRT_LAZY_NONE;
231b1df07bdSGlauber de Oliveira Costa 
232b1df07bdSGlauber de Oliveira Costa static inline void enter_lazy(enum paravirt_lazy_mode mode)
233b1df07bdSGlauber de Oliveira Costa {
234ab2f75f0SJeremy Fitzhardinge 	BUG_ON(percpu_read(paravirt_lazy_mode) != PARAVIRT_LAZY_NONE);
235b1df07bdSGlauber de Oliveira Costa 
236ab2f75f0SJeremy Fitzhardinge 	percpu_write(paravirt_lazy_mode, mode);
237b1df07bdSGlauber de Oliveira Costa }
238b1df07bdSGlauber de Oliveira Costa 
239b407fc57SJeremy Fitzhardinge static void leave_lazy(enum paravirt_lazy_mode mode)
240b1df07bdSGlauber de Oliveira Costa {
241ab2f75f0SJeremy Fitzhardinge 	BUG_ON(percpu_read(paravirt_lazy_mode) != mode);
242b1df07bdSGlauber de Oliveira Costa 
243ab2f75f0SJeremy Fitzhardinge 	percpu_write(paravirt_lazy_mode, PARAVIRT_LAZY_NONE);
244b1df07bdSGlauber de Oliveira Costa }
245b1df07bdSGlauber de Oliveira Costa 
246b1df07bdSGlauber de Oliveira Costa void paravirt_enter_lazy_mmu(void)
247b1df07bdSGlauber de Oliveira Costa {
248b1df07bdSGlauber de Oliveira Costa 	enter_lazy(PARAVIRT_LAZY_MMU);
249b1df07bdSGlauber de Oliveira Costa }
250b1df07bdSGlauber de Oliveira Costa 
251b1df07bdSGlauber de Oliveira Costa void paravirt_leave_lazy_mmu(void)
252b1df07bdSGlauber de Oliveira Costa {
253b407fc57SJeremy Fitzhardinge 	leave_lazy(PARAVIRT_LAZY_MMU);
254b1df07bdSGlauber de Oliveira Costa }
255b1df07bdSGlauber de Oliveira Costa 
256224101edSJeremy Fitzhardinge void paravirt_start_context_switch(struct task_struct *prev)
257b1df07bdSGlauber de Oliveira Costa {
2582829b449SJeremy Fitzhardinge 	BUG_ON(preemptible());
2592829b449SJeremy Fitzhardinge 
260b407fc57SJeremy Fitzhardinge 	if (percpu_read(paravirt_lazy_mode) == PARAVIRT_LAZY_MMU) {
261b407fc57SJeremy Fitzhardinge 		arch_leave_lazy_mmu_mode();
262224101edSJeremy Fitzhardinge 		set_ti_thread_flag(task_thread_info(prev), TIF_LAZY_MMU_UPDATES);
263b407fc57SJeremy Fitzhardinge 	}
264b1df07bdSGlauber de Oliveira Costa 	enter_lazy(PARAVIRT_LAZY_CPU);
265b1df07bdSGlauber de Oliveira Costa }
266b1df07bdSGlauber de Oliveira Costa 
267224101edSJeremy Fitzhardinge void paravirt_end_context_switch(struct task_struct *next)
268b1df07bdSGlauber de Oliveira Costa {
2692829b449SJeremy Fitzhardinge 	BUG_ON(preemptible());
2702829b449SJeremy Fitzhardinge 
271b407fc57SJeremy Fitzhardinge 	leave_lazy(PARAVIRT_LAZY_CPU);
272b407fc57SJeremy Fitzhardinge 
273224101edSJeremy Fitzhardinge 	if (test_and_clear_ti_thread_flag(task_thread_info(next), TIF_LAZY_MMU_UPDATES))
274b407fc57SJeremy Fitzhardinge 		arch_enter_lazy_mmu_mode();
275b1df07bdSGlauber de Oliveira Costa }
276b1df07bdSGlauber de Oliveira Costa 
277b1df07bdSGlauber de Oliveira Costa enum paravirt_lazy_mode paravirt_get_lazy_mode(void)
278b1df07bdSGlauber de Oliveira Costa {
279b8bcfe99SJeremy Fitzhardinge 	if (in_interrupt())
280b8bcfe99SJeremy Fitzhardinge 		return PARAVIRT_LAZY_NONE;
281b8bcfe99SJeremy Fitzhardinge 
282ab2f75f0SJeremy Fitzhardinge 	return percpu_read(paravirt_lazy_mode);
283b1df07bdSGlauber de Oliveira Costa }
284b1df07bdSGlauber de Oliveira Costa 
285d85cf93dSJeremy Fitzhardinge void arch_flush_lazy_mmu_mode(void)
286d85cf93dSJeremy Fitzhardinge {
287d85cf93dSJeremy Fitzhardinge 	preempt_disable();
288d85cf93dSJeremy Fitzhardinge 
289d85cf93dSJeremy Fitzhardinge 	if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU) {
290d85cf93dSJeremy Fitzhardinge 		arch_leave_lazy_mmu_mode();
291d85cf93dSJeremy Fitzhardinge 		arch_enter_lazy_mmu_mode();
292d85cf93dSJeremy Fitzhardinge 	}
293d85cf93dSJeremy Fitzhardinge 
294d85cf93dSJeremy Fitzhardinge 	preempt_enable();
295d85cf93dSJeremy Fitzhardinge }
296d85cf93dSJeremy Fitzhardinge 
297b1df07bdSGlauber de Oliveira Costa struct pv_info pv_info = {
298b1df07bdSGlauber de Oliveira Costa 	.name = "bare hardware",
299b1df07bdSGlauber de Oliveira Costa 	.paravirt_enabled = 0,
300b1df07bdSGlauber de Oliveira Costa 	.kernel_rpl = 0,
301b1df07bdSGlauber de Oliveira Costa 	.shared_kernel_pmd = 1,	/* Only used when CONFIG_X86_PAE is set */
302318f5a2aSAndy Lutomirski 
303318f5a2aSAndy Lutomirski #ifdef CONFIG_X86_64
304318f5a2aSAndy Lutomirski 	.extra_user_64bit_cs = __USER_CS,
305318f5a2aSAndy Lutomirski #endif
306b1df07bdSGlauber de Oliveira Costa };
307b1df07bdSGlauber de Oliveira Costa 
308b1df07bdSGlauber de Oliveira Costa struct pv_init_ops pv_init_ops = {
309b1df07bdSGlauber de Oliveira Costa 	.patch = native_patch,
310b1df07bdSGlauber de Oliveira Costa };
311b1df07bdSGlauber de Oliveira Costa 
312b1df07bdSGlauber de Oliveira Costa struct pv_time_ops pv_time_ops = {
313b1df07bdSGlauber de Oliveira Costa 	.sched_clock = native_sched_clock,
314b1df07bdSGlauber de Oliveira Costa };
315b1df07bdSGlauber de Oliveira Costa 
316b1df07bdSGlauber de Oliveira Costa struct pv_irq_ops pv_irq_ops = {
317ecb93d1cSJeremy Fitzhardinge 	.save_fl = __PV_IS_CALLEE_SAVE(native_save_fl),
318ecb93d1cSJeremy Fitzhardinge 	.restore_fl = __PV_IS_CALLEE_SAVE(native_restore_fl),
319ecb93d1cSJeremy Fitzhardinge 	.irq_disable = __PV_IS_CALLEE_SAVE(native_irq_disable),
320ecb93d1cSJeremy Fitzhardinge 	.irq_enable = __PV_IS_CALLEE_SAVE(native_irq_enable),
321b1df07bdSGlauber de Oliveira Costa 	.safe_halt = native_safe_halt,
322b1df07bdSGlauber de Oliveira Costa 	.halt = native_halt,
323fab58420SJeremy Fitzhardinge #ifdef CONFIG_X86_64
324fab58420SJeremy Fitzhardinge 	.adjust_exception_frame = paravirt_nop,
325fab58420SJeremy Fitzhardinge #endif
326b1df07bdSGlauber de Oliveira Costa };
327b1df07bdSGlauber de Oliveira Costa 
328b1df07bdSGlauber de Oliveira Costa struct pv_cpu_ops pv_cpu_ops = {
329b1df07bdSGlauber de Oliveira Costa 	.cpuid = native_cpuid,
330b1df07bdSGlauber de Oliveira Costa 	.get_debugreg = native_get_debugreg,
331b1df07bdSGlauber de Oliveira Costa 	.set_debugreg = native_set_debugreg,
332b1df07bdSGlauber de Oliveira Costa 	.clts = native_clts,
333b1df07bdSGlauber de Oliveira Costa 	.read_cr0 = native_read_cr0,
334b1df07bdSGlauber de Oliveira Costa 	.write_cr0 = native_write_cr0,
335b1df07bdSGlauber de Oliveira Costa 	.read_cr4 = native_read_cr4,
336b1df07bdSGlauber de Oliveira Costa 	.read_cr4_safe = native_read_cr4_safe,
337b1df07bdSGlauber de Oliveira Costa 	.write_cr4 = native_write_cr4,
33888b4755fSGlauber de Oliveira Costa #ifdef CONFIG_X86_64
33988b4755fSGlauber de Oliveira Costa 	.read_cr8 = native_read_cr8,
34088b4755fSGlauber de Oliveira Costa 	.write_cr8 = native_write_cr8,
34188b4755fSGlauber de Oliveira Costa #endif
342b1df07bdSGlauber de Oliveira Costa 	.wbinvd = native_wbinvd,
343b1df07bdSGlauber de Oliveira Costa 	.read_msr = native_read_msr_safe,
344132ec92fSBorislav Petkov 	.rdmsr_regs = native_rdmsr_safe_regs,
345b1df07bdSGlauber de Oliveira Costa 	.write_msr = native_write_msr_safe,
346132ec92fSBorislav Petkov 	.wrmsr_regs = native_wrmsr_safe_regs,
347b1df07bdSGlauber de Oliveira Costa 	.read_tsc = native_read_tsc,
348b1df07bdSGlauber de Oliveira Costa 	.read_pmc = native_read_pmc,
349e5aaac44SGlauber de Oliveira Costa 	.read_tscp = native_read_tscp,
350b1df07bdSGlauber de Oliveira Costa 	.load_tr_desc = native_load_tr_desc,
351b1df07bdSGlauber de Oliveira Costa 	.set_ldt = native_set_ldt,
352b1df07bdSGlauber de Oliveira Costa 	.load_gdt = native_load_gdt,
353b1df07bdSGlauber de Oliveira Costa 	.load_idt = native_load_idt,
354b1df07bdSGlauber de Oliveira Costa 	.store_gdt = native_store_gdt,
355b1df07bdSGlauber de Oliveira Costa 	.store_idt = native_store_idt,
356b1df07bdSGlauber de Oliveira Costa 	.store_tr = native_store_tr,
357b1df07bdSGlauber de Oliveira Costa 	.load_tls = native_load_tls,
3589f9d489aSJeremy Fitzhardinge #ifdef CONFIG_X86_64
3599f9d489aSJeremy Fitzhardinge 	.load_gs_index = native_load_gs_index,
3609f9d489aSJeremy Fitzhardinge #endif
361b1df07bdSGlauber de Oliveira Costa 	.write_ldt_entry = native_write_ldt_entry,
362b1df07bdSGlauber de Oliveira Costa 	.write_gdt_entry = native_write_gdt_entry,
363b1df07bdSGlauber de Oliveira Costa 	.write_idt_entry = native_write_idt_entry,
36438ffbe66SJeremy Fitzhardinge 
36538ffbe66SJeremy Fitzhardinge 	.alloc_ldt = paravirt_nop,
36638ffbe66SJeremy Fitzhardinge 	.free_ldt = paravirt_nop,
36738ffbe66SJeremy Fitzhardinge 
368b1df07bdSGlauber de Oliveira Costa 	.load_sp0 = native_load_sp0,
369b1df07bdSGlauber de Oliveira Costa 
370102d0a4bSJeremy Fitzhardinge #if defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION)
371d75cd22fSJeremy Fitzhardinge 	.irq_enable_sysexit = native_irq_enable_sysexit,
372102d0a4bSJeremy Fitzhardinge #endif
3732be29982SJeremy Fitzhardinge #ifdef CONFIG_X86_64
374102d0a4bSJeremy Fitzhardinge #ifdef CONFIG_IA32_EMULATION
3752be29982SJeremy Fitzhardinge 	.usergs_sysret32 = native_usergs_sysret32,
376102d0a4bSJeremy Fitzhardinge #endif
3772be29982SJeremy Fitzhardinge 	.usergs_sysret64 = native_usergs_sysret64,
378d75cd22fSJeremy Fitzhardinge #endif
379b1df07bdSGlauber de Oliveira Costa 	.iret = native_iret,
380e801f864SGlauber de Oliveira Costa 	.swapgs = native_swapgs,
381b1df07bdSGlauber de Oliveira Costa 
382b1df07bdSGlauber de Oliveira Costa 	.set_iopl_mask = native_set_iopl_mask,
383b1df07bdSGlauber de Oliveira Costa 	.io_delay = native_io_delay,
384b1df07bdSGlauber de Oliveira Costa 
385224101edSJeremy Fitzhardinge 	.start_context_switch = paravirt_nop,
386224101edSJeremy Fitzhardinge 	.end_context_switch = paravirt_nop,
387b1df07bdSGlauber de Oliveira Costa };
388b1df07bdSGlauber de Oliveira Costa 
389b1df07bdSGlauber de Oliveira Costa struct pv_apic_ops pv_apic_ops = {
390b1df07bdSGlauber de Oliveira Costa #ifdef CONFIG_X86_LOCAL_APIC
391b1df07bdSGlauber de Oliveira Costa 	.startup_ipi_hook = paravirt_nop,
392b1df07bdSGlauber de Oliveira Costa #endif
393b1df07bdSGlauber de Oliveira Costa };
394b1df07bdSGlauber de Oliveira Costa 
39541edafdbSJeremy Fitzhardinge #if defined(CONFIG_X86_32) && !defined(CONFIG_X86_PAE)
39641edafdbSJeremy Fitzhardinge /* 32-bit pagetable entries */
397da5de7c2SJeremy Fitzhardinge #define PTE_IDENT	__PV_IS_CALLEE_SAVE(_paravirt_ident_32)
39841edafdbSJeremy Fitzhardinge #else
39941edafdbSJeremy Fitzhardinge /* 64-bit pagetable entries */
400da5de7c2SJeremy Fitzhardinge #define PTE_IDENT	__PV_IS_CALLEE_SAVE(_paravirt_ident_64)
40141edafdbSJeremy Fitzhardinge #endif
40241edafdbSJeremy Fitzhardinge 
403b1df07bdSGlauber de Oliveira Costa struct pv_mmu_ops pv_mmu_ops = {
404b1df07bdSGlauber de Oliveira Costa 
405b1df07bdSGlauber de Oliveira Costa 	.read_cr2 = native_read_cr2,
406b1df07bdSGlauber de Oliveira Costa 	.write_cr2 = native_write_cr2,
407b1df07bdSGlauber de Oliveira Costa 	.read_cr3 = native_read_cr3,
408b1df07bdSGlauber de Oliveira Costa 	.write_cr3 = native_write_cr3,
409b1df07bdSGlauber de Oliveira Costa 
410b1df07bdSGlauber de Oliveira Costa 	.flush_tlb_user = native_flush_tlb,
411b1df07bdSGlauber de Oliveira Costa 	.flush_tlb_kernel = native_flush_tlb_global,
412b1df07bdSGlauber de Oliveira Costa 	.flush_tlb_single = native_flush_tlb_single,
413b1df07bdSGlauber de Oliveira Costa 	.flush_tlb_others = native_flush_tlb_others,
414b1df07bdSGlauber de Oliveira Costa 
415eba0045fSJeremy Fitzhardinge 	.pgd_alloc = __paravirt_pgd_alloc,
416eba0045fSJeremy Fitzhardinge 	.pgd_free = paravirt_nop,
417eba0045fSJeremy Fitzhardinge 
4186944a9c8SJeremy Fitzhardinge 	.alloc_pte = paravirt_nop,
4196944a9c8SJeremy Fitzhardinge 	.alloc_pmd = paravirt_nop,
4202761fa09SJeremy Fitzhardinge 	.alloc_pud = paravirt_nop,
4216944a9c8SJeremy Fitzhardinge 	.release_pte = paravirt_nop,
4226944a9c8SJeremy Fitzhardinge 	.release_pmd = paravirt_nop,
4232761fa09SJeremy Fitzhardinge 	.release_pud = paravirt_nop,
424b1df07bdSGlauber de Oliveira Costa 
425b1df07bdSGlauber de Oliveira Costa 	.set_pte = native_set_pte,
426b1df07bdSGlauber de Oliveira Costa 	.set_pte_at = native_set_pte_at,
427b1df07bdSGlauber de Oliveira Costa 	.set_pmd = native_set_pmd,
428331127f7SAndrea Arcangeli 	.set_pmd_at = native_set_pmd_at,
429b1df07bdSGlauber de Oliveira Costa 	.pte_update = paravirt_nop,
430b1df07bdSGlauber de Oliveira Costa 	.pte_update_defer = paravirt_nop,
431331127f7SAndrea Arcangeli 	.pmd_update = paravirt_nop,
432331127f7SAndrea Arcangeli 	.pmd_update_defer = paravirt_nop,
433b1df07bdSGlauber de Oliveira Costa 
43408b882c6SJeremy Fitzhardinge 	.ptep_modify_prot_start = __ptep_modify_prot_start,
43508b882c6SJeremy Fitzhardinge 	.ptep_modify_prot_commit = __ptep_modify_prot_commit,
43608b882c6SJeremy Fitzhardinge 
437f95f2f7bSEduardo Habkost #if PAGETABLE_LEVELS >= 3
438b1df07bdSGlauber de Oliveira Costa #ifdef CONFIG_X86_PAE
439b1df07bdSGlauber de Oliveira Costa 	.set_pte_atomic = native_set_pte_atomic,
440b1df07bdSGlauber de Oliveira Costa 	.pte_clear = native_pte_clear,
441b1df07bdSGlauber de Oliveira Costa 	.pmd_clear = native_pmd_clear,
442f95f2f7bSEduardo Habkost #endif
443f95f2f7bSEduardo Habkost 	.set_pud = native_set_pud,
444da5de7c2SJeremy Fitzhardinge 
445da5de7c2SJeremy Fitzhardinge 	.pmd_val = PTE_IDENT,
446da5de7c2SJeremy Fitzhardinge 	.make_pmd = PTE_IDENT,
447f95f2f7bSEduardo Habkost 
448f95f2f7bSEduardo Habkost #if PAGETABLE_LEVELS == 4
449da5de7c2SJeremy Fitzhardinge 	.pud_val = PTE_IDENT,
450da5de7c2SJeremy Fitzhardinge 	.make_pud = PTE_IDENT,
451da5de7c2SJeremy Fitzhardinge 
452f95f2f7bSEduardo Habkost 	.set_pgd = native_set_pgd,
453b1df07bdSGlauber de Oliveira Costa #endif
454f95f2f7bSEduardo Habkost #endif /* PAGETABLE_LEVELS >= 3 */
455b1df07bdSGlauber de Oliveira Costa 
456da5de7c2SJeremy Fitzhardinge 	.pte_val = PTE_IDENT,
457da5de7c2SJeremy Fitzhardinge 	.pgd_val = PTE_IDENT,
458b1df07bdSGlauber de Oliveira Costa 
459da5de7c2SJeremy Fitzhardinge 	.make_pte = PTE_IDENT,
460da5de7c2SJeremy Fitzhardinge 	.make_pgd = PTE_IDENT,
461b1df07bdSGlauber de Oliveira Costa 
462b1df07bdSGlauber de Oliveira Costa 	.dup_mmap = paravirt_nop,
463b1df07bdSGlauber de Oliveira Costa 	.exit_mmap = paravirt_nop,
464b1df07bdSGlauber de Oliveira Costa 	.activate_mm = paravirt_nop,
465b1df07bdSGlauber de Oliveira Costa 
466b1df07bdSGlauber de Oliveira Costa 	.lazy_mode = {
467b1df07bdSGlauber de Oliveira Costa 		.enter = paravirt_nop,
468b1df07bdSGlauber de Oliveira Costa 		.leave = paravirt_nop,
469b1df07bdSGlauber de Oliveira Costa 	},
470aeaaa59cSJeremy Fitzhardinge 
471aeaaa59cSJeremy Fitzhardinge 	.set_fixmap = native_set_fixmap,
472b1df07bdSGlauber de Oliveira Costa };
473b1df07bdSGlauber de Oliveira Costa 
474b1df07bdSGlauber de Oliveira Costa EXPORT_SYMBOL_GPL(pv_time_ops);
475b1df07bdSGlauber de Oliveira Costa EXPORT_SYMBOL    (pv_cpu_ops);
476b1df07bdSGlauber de Oliveira Costa EXPORT_SYMBOL    (pv_mmu_ops);
477b1df07bdSGlauber de Oliveira Costa EXPORT_SYMBOL_GPL(pv_apic_ops);
478b1df07bdSGlauber de Oliveira Costa EXPORT_SYMBOL_GPL(pv_info);
479b1df07bdSGlauber de Oliveira Costa EXPORT_SYMBOL    (pv_irq_ops);
480