xref: /openbmc/linux/arch/x86/kernel/paravirt.c (revision dd2f4a00)
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>
26376e2424SMasami Hiramatsu #include <linux/kprobes.h>
27b1df07bdSGlauber de Oliveira Costa 
28b1df07bdSGlauber de Oliveira Costa #include <asm/bug.h>
29b1df07bdSGlauber de Oliveira Costa #include <asm/paravirt.h>
3050af5eadSPaul Gortmaker #include <asm/debugreg.h>
31b1df07bdSGlauber de Oliveira Costa #include <asm/desc.h>
32b1df07bdSGlauber de Oliveira Costa #include <asm/setup.h>
33a312b37bSEduardo Habkost #include <asm/pgtable.h>
34b1df07bdSGlauber de Oliveira Costa #include <asm/time.h>
35eba0045fSJeremy Fitzhardinge #include <asm/pgalloc.h>
36b1df07bdSGlauber de Oliveira Costa #include <asm/irq.h>
37b1df07bdSGlauber de Oliveira Costa #include <asm/delay.h>
38b1df07bdSGlauber de Oliveira Costa #include <asm/fixmap.h>
39b1df07bdSGlauber de Oliveira Costa #include <asm/apic.h>
40b1df07bdSGlauber de Oliveira Costa #include <asm/tlbflush.h>
41b1df07bdSGlauber de Oliveira Costa #include <asm/timer.h>
42f05e798aSDavid Howells #include <asm/special_insns.h>
43b1df07bdSGlauber de Oliveira Costa 
44fc57a7c6SAndy Lutomirski /*
45fc57a7c6SAndy Lutomirski  * nop stub, which must not clobber anything *including the stack* to
46fc57a7c6SAndy Lutomirski  * avoid confusing the entry prologues.
47fc57a7c6SAndy Lutomirski  */
48fc57a7c6SAndy Lutomirski extern void _paravirt_nop(void);
49fc57a7c6SAndy Lutomirski asm (".pushsection .entry.text, \"ax\"\n"
50fc57a7c6SAndy Lutomirski      ".global _paravirt_nop\n"
51fc57a7c6SAndy Lutomirski      "_paravirt_nop:\n\t"
52fc57a7c6SAndy Lutomirski      "ret\n\t"
53fc57a7c6SAndy Lutomirski      ".size _paravirt_nop, . - _paravirt_nop\n\t"
54fc57a7c6SAndy Lutomirski      ".type _paravirt_nop, @function\n\t"
55fc57a7c6SAndy Lutomirski      ".popsection");
56b1df07bdSGlauber de Oliveira Costa 
5741edafdbSJeremy Fitzhardinge /* identity function, which can be inlined */
5841edafdbSJeremy Fitzhardinge u32 _paravirt_ident_32(u32 x)
5941edafdbSJeremy Fitzhardinge {
6041edafdbSJeremy Fitzhardinge 	return x;
6141edafdbSJeremy Fitzhardinge }
6241edafdbSJeremy Fitzhardinge 
6341edafdbSJeremy Fitzhardinge u64 _paravirt_ident_64(u64 x)
6441edafdbSJeremy Fitzhardinge {
6541edafdbSJeremy Fitzhardinge 	return x;
6641edafdbSJeremy Fitzhardinge }
6741edafdbSJeremy Fitzhardinge 
686f30c1acSThomas Gleixner void __init default_banner(void)
69b1df07bdSGlauber de Oliveira Costa {
70b1df07bdSGlauber de Oliveira Costa 	printk(KERN_INFO "Booting paravirtualized kernel on %s\n",
71b1df07bdSGlauber de Oliveira Costa 	       pv_info.name);
72b1df07bdSGlauber de Oliveira Costa }
73b1df07bdSGlauber de Oliveira Costa 
74b1df07bdSGlauber de Oliveira Costa /* Undefined instruction for dealing with missing ops pointers. */
75b1df07bdSGlauber de Oliveira Costa static const unsigned char ud2a[] = { 0x0f, 0x0b };
76b1df07bdSGlauber de Oliveira Costa 
77b1df07bdSGlauber de Oliveira Costa struct branch {
78b1df07bdSGlauber de Oliveira Costa 	unsigned char opcode;
79b1df07bdSGlauber de Oliveira Costa 	u32 delta;
80b1df07bdSGlauber de Oliveira Costa } __attribute__((packed));
81b1df07bdSGlauber de Oliveira Costa 
82b1df07bdSGlauber de Oliveira Costa unsigned paravirt_patch_call(void *insnbuf,
83b1df07bdSGlauber de Oliveira Costa 			     const void *target, u16 tgt_clobbers,
84b1df07bdSGlauber de Oliveira Costa 			     unsigned long addr, u16 site_clobbers,
85b1df07bdSGlauber de Oliveira Costa 			     unsigned len)
86b1df07bdSGlauber de Oliveira Costa {
87b1df07bdSGlauber de Oliveira Costa 	struct branch *b = insnbuf;
88b1df07bdSGlauber de Oliveira Costa 	unsigned long delta = (unsigned long)target - (addr+5);
89b1df07bdSGlauber de Oliveira Costa 
90b1df07bdSGlauber de Oliveira Costa 	if (tgt_clobbers & ~site_clobbers)
91b1df07bdSGlauber de Oliveira Costa 		return len;	/* target would clobber too much for this site */
92b1df07bdSGlauber de Oliveira Costa 	if (len < 5)
93b1df07bdSGlauber de Oliveira Costa 		return len;	/* call too long for patch site */
94b1df07bdSGlauber de Oliveira Costa 
95b1df07bdSGlauber de Oliveira Costa 	b->opcode = 0xe8; /* call */
96b1df07bdSGlauber de Oliveira Costa 	b->delta = delta;
97b1df07bdSGlauber de Oliveira Costa 	BUILD_BUG_ON(sizeof(*b) != 5);
98b1df07bdSGlauber de Oliveira Costa 
99b1df07bdSGlauber de Oliveira Costa 	return 5;
100b1df07bdSGlauber de Oliveira Costa }
101b1df07bdSGlauber de Oliveira Costa 
102b1df07bdSGlauber de Oliveira Costa unsigned paravirt_patch_jmp(void *insnbuf, const void *target,
103b1df07bdSGlauber de Oliveira Costa 			    unsigned long addr, unsigned len)
104b1df07bdSGlauber de Oliveira Costa {
105b1df07bdSGlauber de Oliveira Costa 	struct branch *b = insnbuf;
106b1df07bdSGlauber de Oliveira Costa 	unsigned long delta = (unsigned long)target - (addr+5);
107b1df07bdSGlauber de Oliveira Costa 
108b1df07bdSGlauber de Oliveira Costa 	if (len < 5)
109b1df07bdSGlauber de Oliveira Costa 		return len;	/* call too long for patch site */
110b1df07bdSGlauber de Oliveira Costa 
111b1df07bdSGlauber de Oliveira Costa 	b->opcode = 0xe9;	/* jmp */
112b1df07bdSGlauber de Oliveira Costa 	b->delta = delta;
113b1df07bdSGlauber de Oliveira Costa 
114b1df07bdSGlauber de Oliveira Costa 	return 5;
115b1df07bdSGlauber de Oliveira Costa }
116b1df07bdSGlauber de Oliveira Costa 
117b1df07bdSGlauber de Oliveira Costa /* Neat trick to map patch type back to the call within the
118b1df07bdSGlauber de Oliveira Costa  * corresponding structure. */
119b1df07bdSGlauber de Oliveira Costa static void *get_call_destination(u8 type)
120b1df07bdSGlauber de Oliveira Costa {
121b1df07bdSGlauber de Oliveira Costa 	struct paravirt_patch_template tmpl = {
122b1df07bdSGlauber de Oliveira Costa 		.pv_init_ops = pv_init_ops,
123b1df07bdSGlauber de Oliveira Costa 		.pv_time_ops = pv_time_ops,
124b1df07bdSGlauber de Oliveira Costa 		.pv_cpu_ops = pv_cpu_ops,
125b1df07bdSGlauber de Oliveira Costa 		.pv_irq_ops = pv_irq_ops,
126b1df07bdSGlauber de Oliveira Costa 		.pv_mmu_ops = pv_mmu_ops,
127b4ecc126SJeremy Fitzhardinge #ifdef CONFIG_PARAVIRT_SPINLOCKS
12874d4affdSJeremy Fitzhardinge 		.pv_lock_ops = pv_lock_ops,
129b4ecc126SJeremy Fitzhardinge #endif
130b1df07bdSGlauber de Oliveira Costa 	};
131b1df07bdSGlauber de Oliveira Costa 	return *((void **)&tmpl + type);
132b1df07bdSGlauber de Oliveira Costa }
133b1df07bdSGlauber de Oliveira Costa 
134b1df07bdSGlauber de Oliveira Costa unsigned paravirt_patch_default(u8 type, u16 clobbers, void *insnbuf,
135b1df07bdSGlauber de Oliveira Costa 				unsigned long addr, unsigned len)
136b1df07bdSGlauber de Oliveira Costa {
137b1df07bdSGlauber de Oliveira Costa 	void *opfunc = get_call_destination(type);
138b1df07bdSGlauber de Oliveira Costa 	unsigned ret;
139b1df07bdSGlauber de Oliveira Costa 
140b1df07bdSGlauber de Oliveira Costa 	if (opfunc == NULL)
141b1df07bdSGlauber de Oliveira Costa 		/* If there's no function, patch it with a ud2a (BUG) */
142b1df07bdSGlauber de Oliveira Costa 		ret = paravirt_patch_insns(insnbuf, len, ud2a, ud2a+sizeof(ud2a));
14341edafdbSJeremy Fitzhardinge 	else if (opfunc == _paravirt_nop)
14479f1d836SBorislav Petkov 		ret = 0;
14541edafdbSJeremy Fitzhardinge 
14641edafdbSJeremy Fitzhardinge 	/* identity functions just return their single argument */
14741edafdbSJeremy Fitzhardinge 	else if (opfunc == _paravirt_ident_32)
14841edafdbSJeremy Fitzhardinge 		ret = paravirt_patch_ident_32(insnbuf, len);
14941edafdbSJeremy Fitzhardinge 	else if (opfunc == _paravirt_ident_64)
15041edafdbSJeremy Fitzhardinge 		ret = paravirt_patch_ident_64(insnbuf, len);
15141edafdbSJeremy Fitzhardinge 
152b1df07bdSGlauber de Oliveira Costa 	else if (type == PARAVIRT_PATCH(pv_cpu_ops.iret) ||
1532be29982SJeremy Fitzhardinge 		 type == PARAVIRT_PATCH(pv_cpu_ops.usergs_sysret64))
154b1df07bdSGlauber de Oliveira Costa 		/* If operation requires a jmp, then jmp */
155b1df07bdSGlauber de Oliveira Costa 		ret = paravirt_patch_jmp(insnbuf, opfunc, addr, len);
156b1df07bdSGlauber de Oliveira Costa 	else
157b1df07bdSGlauber de Oliveira Costa 		/* Otherwise call the function; assume target could
158b1df07bdSGlauber de Oliveira Costa 		   clobber any caller-save reg */
159b1df07bdSGlauber de Oliveira Costa 		ret = paravirt_patch_call(insnbuf, opfunc, CLBR_ANY,
160b1df07bdSGlauber de Oliveira Costa 					  addr, clobbers, len);
161b1df07bdSGlauber de Oliveira Costa 
162b1df07bdSGlauber de Oliveira Costa 	return ret;
163b1df07bdSGlauber de Oliveira Costa }
164b1df07bdSGlauber de Oliveira Costa 
165b1df07bdSGlauber de Oliveira Costa unsigned paravirt_patch_insns(void *insnbuf, unsigned len,
166b1df07bdSGlauber de Oliveira Costa 			      const char *start, const char *end)
167b1df07bdSGlauber de Oliveira Costa {
168b1df07bdSGlauber de Oliveira Costa 	unsigned insn_len = end - start;
169b1df07bdSGlauber de Oliveira Costa 
170b1df07bdSGlauber de Oliveira Costa 	if (insn_len > len || start == NULL)
171b1df07bdSGlauber de Oliveira Costa 		insn_len = len;
172b1df07bdSGlauber de Oliveira Costa 	else
173b1df07bdSGlauber de Oliveira Costa 		memcpy(insnbuf, start, insn_len);
174b1df07bdSGlauber de Oliveira Costa 
175b1df07bdSGlauber de Oliveira Costa 	return insn_len;
176b1df07bdSGlauber de Oliveira Costa }
177b1df07bdSGlauber de Oliveira Costa 
178b1df07bdSGlauber de Oliveira Costa static void native_flush_tlb(void)
179b1df07bdSGlauber de Oliveira Costa {
180b1df07bdSGlauber de Oliveira Costa 	__native_flush_tlb();
181b1df07bdSGlauber de Oliveira Costa }
182b1df07bdSGlauber de Oliveira Costa 
183b1df07bdSGlauber de Oliveira Costa /*
184b1df07bdSGlauber de Oliveira Costa  * Global pages have to be flushed a bit differently. Not a real
185b1df07bdSGlauber de Oliveira Costa  * performance problem because this does not happen often.
186b1df07bdSGlauber de Oliveira Costa  */
187b1df07bdSGlauber de Oliveira Costa static void native_flush_tlb_global(void)
188b1df07bdSGlauber de Oliveira Costa {
189b1df07bdSGlauber de Oliveira Costa 	__native_flush_tlb_global();
190b1df07bdSGlauber de Oliveira Costa }
191b1df07bdSGlauber de Oliveira Costa 
192b1df07bdSGlauber de Oliveira Costa static void native_flush_tlb_single(unsigned long addr)
193b1df07bdSGlauber de Oliveira Costa {
194b1df07bdSGlauber de Oliveira Costa 	__native_flush_tlb_single(addr);
195b1df07bdSGlauber de Oliveira Costa }
196b1df07bdSGlauber de Oliveira Costa 
197c5905afbSIngo Molnar struct static_key paravirt_steal_enabled;
198c5905afbSIngo Molnar struct static_key paravirt_steal_rq_enabled;
1993c404b57SGlauber Costa 
2003c404b57SGlauber Costa static u64 native_steal_clock(int cpu)
2013c404b57SGlauber Costa {
2023c404b57SGlauber Costa 	return 0;
2033c404b57SGlauber Costa }
2043c404b57SGlauber Costa 
205b1df07bdSGlauber de Oliveira Costa /* These are in entry.S */
206b1df07bdSGlauber de Oliveira Costa extern void native_iret(void);
2072be29982SJeremy Fitzhardinge extern void native_usergs_sysret64(void);
208b1df07bdSGlauber de Oliveira Costa 
209b1df07bdSGlauber de Oliveira Costa static struct resource reserve_ioports = {
210b1df07bdSGlauber de Oliveira Costa 	.start = 0,
211b1df07bdSGlauber de Oliveira Costa 	.end = IO_SPACE_LIMIT,
212b1df07bdSGlauber de Oliveira Costa 	.name = "paravirt-ioport",
213b1df07bdSGlauber de Oliveira Costa 	.flags = IORESOURCE_IO | IORESOURCE_BUSY,
214b1df07bdSGlauber de Oliveira Costa };
215b1df07bdSGlauber de Oliveira Costa 
216b1df07bdSGlauber de Oliveira Costa /*
217b1df07bdSGlauber de Oliveira Costa  * Reserve the whole legacy IO space to prevent any legacy drivers
218b1df07bdSGlauber de Oliveira Costa  * from wasting time probing for their hardware.  This is a fairly
219b1df07bdSGlauber de Oliveira Costa  * brute-force approach to disabling all non-virtual drivers.
220b1df07bdSGlauber de Oliveira Costa  *
221b1df07bdSGlauber de Oliveira Costa  * Note that this must be called very early to have any effect.
222b1df07bdSGlauber de Oliveira Costa  */
223b1df07bdSGlauber de Oliveira Costa int paravirt_disable_iospace(void)
224b1df07bdSGlauber de Oliveira Costa {
225f7743fe6SJeremy Fitzhardinge 	return request_resource(&ioport_resource, &reserve_ioports);
226b1df07bdSGlauber de Oliveira Costa }
227b1df07bdSGlauber de Oliveira Costa 
228b1df07bdSGlauber de Oliveira Costa static DEFINE_PER_CPU(enum paravirt_lazy_mode, paravirt_lazy_mode) = PARAVIRT_LAZY_NONE;
229b1df07bdSGlauber de Oliveira Costa 
230b1df07bdSGlauber de Oliveira Costa static inline void enter_lazy(enum paravirt_lazy_mode mode)
231b1df07bdSGlauber de Oliveira Costa {
232c6ae41e7SAlex Shi 	BUG_ON(this_cpu_read(paravirt_lazy_mode) != PARAVIRT_LAZY_NONE);
233b1df07bdSGlauber de Oliveira Costa 
234c6ae41e7SAlex Shi 	this_cpu_write(paravirt_lazy_mode, mode);
235b1df07bdSGlauber de Oliveira Costa }
236b1df07bdSGlauber de Oliveira Costa 
237b407fc57SJeremy Fitzhardinge static void leave_lazy(enum paravirt_lazy_mode mode)
238b1df07bdSGlauber de Oliveira Costa {
239c6ae41e7SAlex Shi 	BUG_ON(this_cpu_read(paravirt_lazy_mode) != mode);
240b1df07bdSGlauber de Oliveira Costa 
241c6ae41e7SAlex Shi 	this_cpu_write(paravirt_lazy_mode, PARAVIRT_LAZY_NONE);
242b1df07bdSGlauber de Oliveira Costa }
243b1df07bdSGlauber de Oliveira Costa 
244b1df07bdSGlauber de Oliveira Costa void paravirt_enter_lazy_mmu(void)
245b1df07bdSGlauber de Oliveira Costa {
246b1df07bdSGlauber de Oliveira Costa 	enter_lazy(PARAVIRT_LAZY_MMU);
247b1df07bdSGlauber de Oliveira Costa }
248b1df07bdSGlauber de Oliveira Costa 
249b1df07bdSGlauber de Oliveira Costa void paravirt_leave_lazy_mmu(void)
250b1df07bdSGlauber de Oliveira Costa {
251b407fc57SJeremy Fitzhardinge 	leave_lazy(PARAVIRT_LAZY_MMU);
252b1df07bdSGlauber de Oliveira Costa }
253b1df07bdSGlauber de Oliveira Costa 
254511ba86eSBoris Ostrovsky void paravirt_flush_lazy_mmu(void)
255511ba86eSBoris Ostrovsky {
256511ba86eSBoris Ostrovsky 	preempt_disable();
257511ba86eSBoris Ostrovsky 
258511ba86eSBoris Ostrovsky 	if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU) {
259511ba86eSBoris Ostrovsky 		arch_leave_lazy_mmu_mode();
260511ba86eSBoris Ostrovsky 		arch_enter_lazy_mmu_mode();
261511ba86eSBoris Ostrovsky 	}
262511ba86eSBoris Ostrovsky 
263511ba86eSBoris Ostrovsky 	preempt_enable();
264511ba86eSBoris Ostrovsky }
265511ba86eSBoris Ostrovsky 
266224101edSJeremy Fitzhardinge void paravirt_start_context_switch(struct task_struct *prev)
267b1df07bdSGlauber de Oliveira Costa {
2682829b449SJeremy Fitzhardinge 	BUG_ON(preemptible());
2692829b449SJeremy Fitzhardinge 
270c6ae41e7SAlex Shi 	if (this_cpu_read(paravirt_lazy_mode) == PARAVIRT_LAZY_MMU) {
271b407fc57SJeremy Fitzhardinge 		arch_leave_lazy_mmu_mode();
272224101edSJeremy Fitzhardinge 		set_ti_thread_flag(task_thread_info(prev), TIF_LAZY_MMU_UPDATES);
273b407fc57SJeremy Fitzhardinge 	}
274b1df07bdSGlauber de Oliveira Costa 	enter_lazy(PARAVIRT_LAZY_CPU);
275b1df07bdSGlauber de Oliveira Costa }
276b1df07bdSGlauber de Oliveira Costa 
277224101edSJeremy Fitzhardinge void paravirt_end_context_switch(struct task_struct *next)
278b1df07bdSGlauber de Oliveira Costa {
2792829b449SJeremy Fitzhardinge 	BUG_ON(preemptible());
2802829b449SJeremy Fitzhardinge 
281b407fc57SJeremy Fitzhardinge 	leave_lazy(PARAVIRT_LAZY_CPU);
282b407fc57SJeremy Fitzhardinge 
283224101edSJeremy Fitzhardinge 	if (test_and_clear_ti_thread_flag(task_thread_info(next), TIF_LAZY_MMU_UPDATES))
284b407fc57SJeremy Fitzhardinge 		arch_enter_lazy_mmu_mode();
285b1df07bdSGlauber de Oliveira Costa }
286b1df07bdSGlauber de Oliveira Costa 
287b1df07bdSGlauber de Oliveira Costa enum paravirt_lazy_mode paravirt_get_lazy_mode(void)
288b1df07bdSGlauber de Oliveira Costa {
289b8bcfe99SJeremy Fitzhardinge 	if (in_interrupt())
290b8bcfe99SJeremy Fitzhardinge 		return PARAVIRT_LAZY_NONE;
291b8bcfe99SJeremy Fitzhardinge 
292c6ae41e7SAlex Shi 	return this_cpu_read(paravirt_lazy_mode);
293b1df07bdSGlauber de Oliveira Costa }
294b1df07bdSGlauber de Oliveira Costa 
295b1df07bdSGlauber de Oliveira Costa struct pv_info pv_info = {
296b1df07bdSGlauber de Oliveira Costa 	.name = "bare hardware",
297b1df07bdSGlauber de Oliveira Costa 	.paravirt_enabled = 0,
298b1df07bdSGlauber de Oliveira Costa 	.kernel_rpl = 0,
299b1df07bdSGlauber de Oliveira Costa 	.shared_kernel_pmd = 1,	/* Only used when CONFIG_X86_PAE is set */
300318f5a2aSAndy Lutomirski 
301318f5a2aSAndy Lutomirski #ifdef CONFIG_X86_64
302318f5a2aSAndy Lutomirski 	.extra_user_64bit_cs = __USER_CS,
303318f5a2aSAndy Lutomirski #endif
304b1df07bdSGlauber de Oliveira Costa };
305b1df07bdSGlauber de Oliveira Costa 
306b1df07bdSGlauber de Oliveira Costa struct pv_init_ops pv_init_ops = {
307b1df07bdSGlauber de Oliveira Costa 	.patch = native_patch,
308b1df07bdSGlauber de Oliveira Costa };
309b1df07bdSGlauber de Oliveira Costa 
310b1df07bdSGlauber de Oliveira Costa struct pv_time_ops pv_time_ops = {
311b1df07bdSGlauber de Oliveira Costa 	.sched_clock = native_sched_clock,
3123c404b57SGlauber Costa 	.steal_clock = native_steal_clock,
313b1df07bdSGlauber de Oliveira Costa };
314b1df07bdSGlauber de Oliveira Costa 
3159a55fdbeSAndi Kleen __visible struct pv_irq_ops pv_irq_ops = {
316ecb93d1cSJeremy Fitzhardinge 	.save_fl = __PV_IS_CALLEE_SAVE(native_save_fl),
317ecb93d1cSJeremy Fitzhardinge 	.restore_fl = __PV_IS_CALLEE_SAVE(native_restore_fl),
318ecb93d1cSJeremy Fitzhardinge 	.irq_disable = __PV_IS_CALLEE_SAVE(native_irq_disable),
319ecb93d1cSJeremy Fitzhardinge 	.irq_enable = __PV_IS_CALLEE_SAVE(native_irq_enable),
320b1df07bdSGlauber de Oliveira Costa 	.safe_halt = native_safe_halt,
321b1df07bdSGlauber de Oliveira Costa 	.halt = native_halt,
322fab58420SJeremy Fitzhardinge #ifdef CONFIG_X86_64
323fab58420SJeremy Fitzhardinge 	.adjust_exception_frame = paravirt_nop,
324fab58420SJeremy Fitzhardinge #endif
325b1df07bdSGlauber de Oliveira Costa };
326b1df07bdSGlauber de Oliveira Costa 
3279a55fdbeSAndi Kleen __visible struct pv_cpu_ops pv_cpu_ops = {
328b1df07bdSGlauber de Oliveira Costa 	.cpuid = native_cpuid,
329b1df07bdSGlauber de Oliveira Costa 	.get_debugreg = native_get_debugreg,
330b1df07bdSGlauber de Oliveira Costa 	.set_debugreg = native_set_debugreg,
331b1df07bdSGlauber de Oliveira Costa 	.clts = native_clts,
332b1df07bdSGlauber de Oliveira Costa 	.read_cr0 = native_read_cr0,
333b1df07bdSGlauber de Oliveira Costa 	.write_cr0 = native_write_cr0,
334b1df07bdSGlauber de Oliveira Costa 	.read_cr4 = native_read_cr4,
335b1df07bdSGlauber de Oliveira Costa 	.read_cr4_safe = native_read_cr4_safe,
336b1df07bdSGlauber de Oliveira Costa 	.write_cr4 = native_write_cr4,
33788b4755fSGlauber de Oliveira Costa #ifdef CONFIG_X86_64
33888b4755fSGlauber de Oliveira Costa 	.read_cr8 = native_read_cr8,
33988b4755fSGlauber de Oliveira Costa 	.write_cr8 = native_write_cr8,
34088b4755fSGlauber de Oliveira Costa #endif
341b1df07bdSGlauber de Oliveira Costa 	.wbinvd = native_wbinvd,
342dd2f4a00SAndy Lutomirski 	.read_msr = native_read_msr,
343dd2f4a00SAndy Lutomirski 	.write_msr = native_write_msr,
344c2ee03b2SAndy Lutomirski 	.read_msr_safe = native_read_msr_safe,
345c2ee03b2SAndy Lutomirski 	.write_msr_safe = native_write_msr_safe,
346b1df07bdSGlauber de Oliveira Costa 	.read_pmc = native_read_pmc,
347b1df07bdSGlauber de Oliveira Costa 	.load_tr_desc = native_load_tr_desc,
348b1df07bdSGlauber de Oliveira Costa 	.set_ldt = native_set_ldt,
349b1df07bdSGlauber de Oliveira Costa 	.load_gdt = native_load_gdt,
350b1df07bdSGlauber de Oliveira Costa 	.load_idt = native_load_idt,
351b1df07bdSGlauber de Oliveira Costa 	.store_idt = native_store_idt,
352b1df07bdSGlauber de Oliveira Costa 	.store_tr = native_store_tr,
353b1df07bdSGlauber de Oliveira Costa 	.load_tls = native_load_tls,
3549f9d489aSJeremy Fitzhardinge #ifdef CONFIG_X86_64
3559f9d489aSJeremy Fitzhardinge 	.load_gs_index = native_load_gs_index,
3569f9d489aSJeremy Fitzhardinge #endif
357b1df07bdSGlauber de Oliveira Costa 	.write_ldt_entry = native_write_ldt_entry,
358b1df07bdSGlauber de Oliveira Costa 	.write_gdt_entry = native_write_gdt_entry,
359b1df07bdSGlauber de Oliveira Costa 	.write_idt_entry = native_write_idt_entry,
36038ffbe66SJeremy Fitzhardinge 
36138ffbe66SJeremy Fitzhardinge 	.alloc_ldt = paravirt_nop,
36238ffbe66SJeremy Fitzhardinge 	.free_ldt = paravirt_nop,
36338ffbe66SJeremy Fitzhardinge 
364b1df07bdSGlauber de Oliveira Costa 	.load_sp0 = native_load_sp0,
365b1df07bdSGlauber de Oliveira Costa 
3662be29982SJeremy Fitzhardinge #ifdef CONFIG_X86_64
3672be29982SJeremy Fitzhardinge 	.usergs_sysret64 = native_usergs_sysret64,
368d75cd22fSJeremy Fitzhardinge #endif
369b1df07bdSGlauber de Oliveira Costa 	.iret = native_iret,
370e801f864SGlauber de Oliveira Costa 	.swapgs = native_swapgs,
371b1df07bdSGlauber de Oliveira Costa 
372b1df07bdSGlauber de Oliveira Costa 	.set_iopl_mask = native_set_iopl_mask,
373b1df07bdSGlauber de Oliveira Costa 	.io_delay = native_io_delay,
374b1df07bdSGlauber de Oliveira Costa 
375224101edSJeremy Fitzhardinge 	.start_context_switch = paravirt_nop,
376224101edSJeremy Fitzhardinge 	.end_context_switch = paravirt_nop,
377b1df07bdSGlauber de Oliveira Costa };
378b1df07bdSGlauber de Oliveira Costa 
37980271972SMasami Hiramatsu /* At this point, native_get/set_debugreg has real function entries */
380376e2424SMasami Hiramatsu NOKPROBE_SYMBOL(native_get_debugreg);
38180271972SMasami Hiramatsu NOKPROBE_SYMBOL(native_set_debugreg);
38280271972SMasami Hiramatsu NOKPROBE_SYMBOL(native_load_idt);
383376e2424SMasami Hiramatsu 
38441edafdbSJeremy Fitzhardinge #if defined(CONFIG_X86_32) && !defined(CONFIG_X86_PAE)
38541edafdbSJeremy Fitzhardinge /* 32-bit pagetable entries */
386da5de7c2SJeremy Fitzhardinge #define PTE_IDENT	__PV_IS_CALLEE_SAVE(_paravirt_ident_32)
38741edafdbSJeremy Fitzhardinge #else
38841edafdbSJeremy Fitzhardinge /* 64-bit pagetable entries */
389da5de7c2SJeremy Fitzhardinge #define PTE_IDENT	__PV_IS_CALLEE_SAVE(_paravirt_ident_64)
39041edafdbSJeremy Fitzhardinge #endif
39141edafdbSJeremy Fitzhardinge 
392b1df07bdSGlauber de Oliveira Costa struct pv_mmu_ops pv_mmu_ops = {
393b1df07bdSGlauber de Oliveira Costa 
394b1df07bdSGlauber de Oliveira Costa 	.read_cr2 = native_read_cr2,
395b1df07bdSGlauber de Oliveira Costa 	.write_cr2 = native_write_cr2,
396b1df07bdSGlauber de Oliveira Costa 	.read_cr3 = native_read_cr3,
397b1df07bdSGlauber de Oliveira Costa 	.write_cr3 = native_write_cr3,
398b1df07bdSGlauber de Oliveira Costa 
399b1df07bdSGlauber de Oliveira Costa 	.flush_tlb_user = native_flush_tlb,
400b1df07bdSGlauber de Oliveira Costa 	.flush_tlb_kernel = native_flush_tlb_global,
401b1df07bdSGlauber de Oliveira Costa 	.flush_tlb_single = native_flush_tlb_single,
402b1df07bdSGlauber de Oliveira Costa 	.flush_tlb_others = native_flush_tlb_others,
403b1df07bdSGlauber de Oliveira Costa 
404eba0045fSJeremy Fitzhardinge 	.pgd_alloc = __paravirt_pgd_alloc,
405eba0045fSJeremy Fitzhardinge 	.pgd_free = paravirt_nop,
406eba0045fSJeremy Fitzhardinge 
4076944a9c8SJeremy Fitzhardinge 	.alloc_pte = paravirt_nop,
4086944a9c8SJeremy Fitzhardinge 	.alloc_pmd = paravirt_nop,
4092761fa09SJeremy Fitzhardinge 	.alloc_pud = paravirt_nop,
4106944a9c8SJeremy Fitzhardinge 	.release_pte = paravirt_nop,
4116944a9c8SJeremy Fitzhardinge 	.release_pmd = paravirt_nop,
4122761fa09SJeremy Fitzhardinge 	.release_pud = paravirt_nop,
413b1df07bdSGlauber de Oliveira Costa 
414b1df07bdSGlauber de Oliveira Costa 	.set_pte = native_set_pte,
415b1df07bdSGlauber de Oliveira Costa 	.set_pte_at = native_set_pte_at,
416b1df07bdSGlauber de Oliveira Costa 	.set_pmd = native_set_pmd,
417331127f7SAndrea Arcangeli 	.set_pmd_at = native_set_pmd_at,
418b1df07bdSGlauber de Oliveira Costa 	.pte_update = paravirt_nop,
419b1df07bdSGlauber de Oliveira Costa 
42008b882c6SJeremy Fitzhardinge 	.ptep_modify_prot_start = __ptep_modify_prot_start,
42108b882c6SJeremy Fitzhardinge 	.ptep_modify_prot_commit = __ptep_modify_prot_commit,
42208b882c6SJeremy Fitzhardinge 
42398233368SKirill A. Shutemov #if CONFIG_PGTABLE_LEVELS >= 3
424b1df07bdSGlauber de Oliveira Costa #ifdef CONFIG_X86_PAE
425b1df07bdSGlauber de Oliveira Costa 	.set_pte_atomic = native_set_pte_atomic,
426b1df07bdSGlauber de Oliveira Costa 	.pte_clear = native_pte_clear,
427b1df07bdSGlauber de Oliveira Costa 	.pmd_clear = native_pmd_clear,
428f95f2f7bSEduardo Habkost #endif
429f95f2f7bSEduardo Habkost 	.set_pud = native_set_pud,
430da5de7c2SJeremy Fitzhardinge 
431da5de7c2SJeremy Fitzhardinge 	.pmd_val = PTE_IDENT,
432da5de7c2SJeremy Fitzhardinge 	.make_pmd = PTE_IDENT,
433f95f2f7bSEduardo Habkost 
43498233368SKirill A. Shutemov #if CONFIG_PGTABLE_LEVELS == 4
435da5de7c2SJeremy Fitzhardinge 	.pud_val = PTE_IDENT,
436da5de7c2SJeremy Fitzhardinge 	.make_pud = PTE_IDENT,
437da5de7c2SJeremy Fitzhardinge 
438f95f2f7bSEduardo Habkost 	.set_pgd = native_set_pgd,
439b1df07bdSGlauber de Oliveira Costa #endif
44098233368SKirill A. Shutemov #endif /* CONFIG_PGTABLE_LEVELS >= 3 */
441b1df07bdSGlauber de Oliveira Costa 
442da5de7c2SJeremy Fitzhardinge 	.pte_val = PTE_IDENT,
443da5de7c2SJeremy Fitzhardinge 	.pgd_val = PTE_IDENT,
444b1df07bdSGlauber de Oliveira Costa 
445da5de7c2SJeremy Fitzhardinge 	.make_pte = PTE_IDENT,
446da5de7c2SJeremy Fitzhardinge 	.make_pgd = PTE_IDENT,
447b1df07bdSGlauber de Oliveira Costa 
448b1df07bdSGlauber de Oliveira Costa 	.dup_mmap = paravirt_nop,
449b1df07bdSGlauber de Oliveira Costa 	.exit_mmap = paravirt_nop,
450b1df07bdSGlauber de Oliveira Costa 	.activate_mm = paravirt_nop,
451b1df07bdSGlauber de Oliveira Costa 
452b1df07bdSGlauber de Oliveira Costa 	.lazy_mode = {
453b1df07bdSGlauber de Oliveira Costa 		.enter = paravirt_nop,
454b1df07bdSGlauber de Oliveira Costa 		.leave = paravirt_nop,
455511ba86eSBoris Ostrovsky 		.flush = paravirt_nop,
456b1df07bdSGlauber de Oliveira Costa 	},
457aeaaa59cSJeremy Fitzhardinge 
458aeaaa59cSJeremy Fitzhardinge 	.set_fixmap = native_set_fixmap,
459b1df07bdSGlauber de Oliveira Costa };
460b1df07bdSGlauber de Oliveira Costa 
461b1df07bdSGlauber de Oliveira Costa EXPORT_SYMBOL_GPL(pv_time_ops);
462b1df07bdSGlauber de Oliveira Costa EXPORT_SYMBOL    (pv_cpu_ops);
463b1df07bdSGlauber de Oliveira Costa EXPORT_SYMBOL    (pv_mmu_ops);
464b1df07bdSGlauber de Oliveira Costa EXPORT_SYMBOL_GPL(pv_info);
465b1df07bdSGlauber de Oliveira Costa EXPORT_SYMBOL    (pv_irq_ops);
466