xref: /openbmc/linux/arch/x86/kernel/paravirt.c (revision 7e437202)
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>
22186f4360SPaul Gortmaker #include <linux/init.h>
23186f4360SPaul Gortmaker #include <linux/export.h>
24b1df07bdSGlauber de Oliveira Costa #include <linux/efi.h>
25b1df07bdSGlauber de Oliveira Costa #include <linux/bcd.h>
26b1df07bdSGlauber de Oliveira Costa #include <linux/highmem.h>
27376e2424SMasami Hiramatsu #include <linux/kprobes.h>
28b1df07bdSGlauber de Oliveira Costa 
29b1df07bdSGlauber de Oliveira Costa #include <asm/bug.h>
30b1df07bdSGlauber de Oliveira Costa #include <asm/paravirt.h>
3150af5eadSPaul Gortmaker #include <asm/debugreg.h>
32b1df07bdSGlauber de Oliveira Costa #include <asm/desc.h>
33b1df07bdSGlauber de Oliveira Costa #include <asm/setup.h>
34a312b37bSEduardo Habkost #include <asm/pgtable.h>
35b1df07bdSGlauber de Oliveira Costa #include <asm/time.h>
36eba0045fSJeremy Fitzhardinge #include <asm/pgalloc.h>
37b1df07bdSGlauber de Oliveira Costa #include <asm/irq.h>
38b1df07bdSGlauber de Oliveira Costa #include <asm/delay.h>
39b1df07bdSGlauber de Oliveira Costa #include <asm/fixmap.h>
40b1df07bdSGlauber de Oliveira Costa #include <asm/apic.h>
41b1df07bdSGlauber de Oliveira Costa #include <asm/tlbflush.h>
42b1df07bdSGlauber de Oliveira Costa #include <asm/timer.h>
43f05e798aSDavid Howells #include <asm/special_insns.h>
4448a8b97cSPeter Zijlstra #include <asm/tlb.h>
45b1df07bdSGlauber de Oliveira Costa 
46fc57a7c6SAndy Lutomirski /*
47fc57a7c6SAndy Lutomirski  * nop stub, which must not clobber anything *including the stack* to
48fc57a7c6SAndy Lutomirski  * avoid confusing the entry prologues.
49fc57a7c6SAndy Lutomirski  */
50fc57a7c6SAndy Lutomirski extern void _paravirt_nop(void);
51fc57a7c6SAndy Lutomirski asm (".pushsection .entry.text, \"ax\"\n"
52fc57a7c6SAndy Lutomirski      ".global _paravirt_nop\n"
53fc57a7c6SAndy Lutomirski      "_paravirt_nop:\n\t"
54fc57a7c6SAndy Lutomirski      "ret\n\t"
55fc57a7c6SAndy Lutomirski      ".size _paravirt_nop, . - _paravirt_nop\n\t"
56fc57a7c6SAndy Lutomirski      ".type _paravirt_nop, @function\n\t"
57fc57a7c6SAndy Lutomirski      ".popsection");
58b1df07bdSGlauber de Oliveira Costa 
5941edafdbSJeremy Fitzhardinge /* identity function, which can be inlined */
6015301a57SSteven Rostedt u32 notrace _paravirt_ident_32(u32 x)
6141edafdbSJeremy Fitzhardinge {
6241edafdbSJeremy Fitzhardinge 	return x;
6341edafdbSJeremy Fitzhardinge }
6441edafdbSJeremy Fitzhardinge 
6515301a57SSteven Rostedt u64 notrace _paravirt_ident_64(u64 x)
6641edafdbSJeremy Fitzhardinge {
6741edafdbSJeremy Fitzhardinge 	return x;
6841edafdbSJeremy Fitzhardinge }
6941edafdbSJeremy Fitzhardinge 
706f30c1acSThomas Gleixner void __init default_banner(void)
71b1df07bdSGlauber de Oliveira Costa {
72b1df07bdSGlauber de Oliveira Costa 	printk(KERN_INFO "Booting paravirtualized kernel on %s\n",
73b1df07bdSGlauber de Oliveira Costa 	       pv_info.name);
74b1df07bdSGlauber de Oliveira Costa }
75b1df07bdSGlauber de Oliveira Costa 
76b1df07bdSGlauber de Oliveira Costa /* Undefined instruction for dealing with missing ops pointers. */
77b1df07bdSGlauber de Oliveira Costa static const unsigned char ud2a[] = { 0x0f, 0x0b };
78b1df07bdSGlauber de Oliveira Costa 
79b1df07bdSGlauber de Oliveira Costa struct branch {
80b1df07bdSGlauber de Oliveira Costa 	unsigned char opcode;
81b1df07bdSGlauber de Oliveira Costa 	u32 delta;
82b1df07bdSGlauber de Oliveira Costa } __attribute__((packed));
83b1df07bdSGlauber de Oliveira Costa 
847e437202SJuergen Gross static unsigned paravirt_patch_call(void *insnbuf,
85b1df07bdSGlauber de Oliveira Costa 				    const void *target, u16 tgt_clobbers,
86b1df07bdSGlauber de Oliveira Costa 				    unsigned long addr, u16 site_clobbers,
87b1df07bdSGlauber de Oliveira Costa 				    unsigned len)
88b1df07bdSGlauber de Oliveira Costa {
89b1df07bdSGlauber de Oliveira Costa 	struct branch *b = insnbuf;
90b1df07bdSGlauber de Oliveira Costa 	unsigned long delta = (unsigned long)target - (addr+5);
91b1df07bdSGlauber de Oliveira Costa 
925800dc5cSPeter Zijlstra 	if (len < 5) {
935800dc5cSPeter Zijlstra #ifdef CONFIG_RETPOLINE
945800dc5cSPeter Zijlstra 		WARN_ONCE("Failing to patch indirect CALL in %ps\n", (void *)addr);
955800dc5cSPeter Zijlstra #endif
96b1df07bdSGlauber de Oliveira Costa 		return len;	/* call too long for patch site */
975800dc5cSPeter Zijlstra 	}
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 
1067e437202SJuergen Gross static 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 
1125800dc5cSPeter Zijlstra 	if (len < 5) {
1135800dc5cSPeter Zijlstra #ifdef CONFIG_RETPOLINE
1145800dc5cSPeter Zijlstra 		WARN_ONCE("Failing to patch indirect JMP in %ps\n", (void *)addr);
1155800dc5cSPeter Zijlstra #endif
116b1df07bdSGlauber de Oliveira Costa 		return len;	/* call too long for patch site */
1175800dc5cSPeter Zijlstra 	}
118b1df07bdSGlauber de Oliveira Costa 
119b1df07bdSGlauber de Oliveira Costa 	b->opcode = 0xe9;	/* jmp */
120b1df07bdSGlauber de Oliveira Costa 	b->delta = delta;
121b1df07bdSGlauber de Oliveira Costa 
122b1df07bdSGlauber de Oliveira Costa 	return 5;
123b1df07bdSGlauber de Oliveira Costa }
124b1df07bdSGlauber de Oliveira Costa 
1259043442bSJuergen Gross DEFINE_STATIC_KEY_TRUE(virt_spin_lock_key);
1269043442bSJuergen Gross 
1279043442bSJuergen Gross void __init native_pv_lock_init(void)
1289043442bSJuergen Gross {
1299043442bSJuergen Gross 	if (!static_cpu_has(X86_FEATURE_HYPERVISOR))
1309043442bSJuergen Gross 		static_branch_disable(&virt_spin_lock_key);
1319043442bSJuergen Gross }
1329043442bSJuergen Gross 
1339043442bSJuergen Gross /*
1349043442bSJuergen Gross  * Neat trick to map patch type back to the call within the
1359043442bSJuergen Gross  * corresponding structure.
1369043442bSJuergen Gross  */
137b1df07bdSGlauber de Oliveira Costa static void *get_call_destination(u8 type)
138b1df07bdSGlauber de Oliveira Costa {
139b1df07bdSGlauber de Oliveira Costa 	struct paravirt_patch_template tmpl = {
140b1df07bdSGlauber de Oliveira Costa 		.pv_init_ops = pv_init_ops,
141b1df07bdSGlauber de Oliveira Costa 		.pv_time_ops = pv_time_ops,
142b1df07bdSGlauber de Oliveira Costa 		.pv_cpu_ops = pv_cpu_ops,
143b1df07bdSGlauber de Oliveira Costa 		.pv_irq_ops = pv_irq_ops,
144b1df07bdSGlauber de Oliveira Costa 		.pv_mmu_ops = pv_mmu_ops,
145b4ecc126SJeremy Fitzhardinge #ifdef CONFIG_PARAVIRT_SPINLOCKS
14674d4affdSJeremy Fitzhardinge 		.pv_lock_ops = pv_lock_ops,
147b4ecc126SJeremy Fitzhardinge #endif
148b1df07bdSGlauber de Oliveira Costa 	};
149b1df07bdSGlauber de Oliveira Costa 	return *((void **)&tmpl + type);
150b1df07bdSGlauber de Oliveira Costa }
151b1df07bdSGlauber de Oliveira Costa 
152b1df07bdSGlauber de Oliveira Costa unsigned paravirt_patch_default(u8 type, u16 clobbers, void *insnbuf,
153b1df07bdSGlauber de Oliveira Costa 				unsigned long addr, unsigned len)
154b1df07bdSGlauber de Oliveira Costa {
155b1df07bdSGlauber de Oliveira Costa 	void *opfunc = get_call_destination(type);
156b1df07bdSGlauber de Oliveira Costa 	unsigned ret;
157b1df07bdSGlauber de Oliveira Costa 
158b1df07bdSGlauber de Oliveira Costa 	if (opfunc == NULL)
159b1df07bdSGlauber de Oliveira Costa 		/* If there's no function, patch it with a ud2a (BUG) */
160b1df07bdSGlauber de Oliveira Costa 		ret = paravirt_patch_insns(insnbuf, len, ud2a, ud2a+sizeof(ud2a));
16141edafdbSJeremy Fitzhardinge 	else if (opfunc == _paravirt_nop)
16279f1d836SBorislav Petkov 		ret = 0;
16341edafdbSJeremy Fitzhardinge 
16441edafdbSJeremy Fitzhardinge 	/* identity functions just return their single argument */
16541edafdbSJeremy Fitzhardinge 	else if (opfunc == _paravirt_ident_32)
16641edafdbSJeremy Fitzhardinge 		ret = paravirt_patch_ident_32(insnbuf, len);
16741edafdbSJeremy Fitzhardinge 	else if (opfunc == _paravirt_ident_64)
16841edafdbSJeremy Fitzhardinge 		ret = paravirt_patch_ident_64(insnbuf, len);
16941edafdbSJeremy Fitzhardinge 
170b1df07bdSGlauber de Oliveira Costa 	else if (type == PARAVIRT_PATCH(pv_cpu_ops.iret) ||
1712be29982SJeremy Fitzhardinge 		 type == PARAVIRT_PATCH(pv_cpu_ops.usergs_sysret64))
172b1df07bdSGlauber de Oliveira Costa 		/* If operation requires a jmp, then jmp */
173b1df07bdSGlauber de Oliveira Costa 		ret = paravirt_patch_jmp(insnbuf, opfunc, addr, len);
174b1df07bdSGlauber de Oliveira Costa 	else
175b1df07bdSGlauber de Oliveira Costa 		/* Otherwise call the function; assume target could
176b1df07bdSGlauber de Oliveira Costa 		   clobber any caller-save reg */
177b1df07bdSGlauber de Oliveira Costa 		ret = paravirt_patch_call(insnbuf, opfunc, CLBR_ANY,
178b1df07bdSGlauber de Oliveira Costa 					  addr, clobbers, len);
179b1df07bdSGlauber de Oliveira Costa 
180b1df07bdSGlauber de Oliveira Costa 	return ret;
181b1df07bdSGlauber de Oliveira Costa }
182b1df07bdSGlauber de Oliveira Costa 
183b1df07bdSGlauber de Oliveira Costa unsigned paravirt_patch_insns(void *insnbuf, unsigned len,
184b1df07bdSGlauber de Oliveira Costa 			      const char *start, const char *end)
185b1df07bdSGlauber de Oliveira Costa {
186b1df07bdSGlauber de Oliveira Costa 	unsigned insn_len = end - start;
187b1df07bdSGlauber de Oliveira Costa 
188b1df07bdSGlauber de Oliveira Costa 	if (insn_len > len || start == NULL)
189b1df07bdSGlauber de Oliveira Costa 		insn_len = len;
190b1df07bdSGlauber de Oliveira Costa 	else
191b1df07bdSGlauber de Oliveira Costa 		memcpy(insnbuf, start, insn_len);
192b1df07bdSGlauber de Oliveira Costa 
193b1df07bdSGlauber de Oliveira Costa 	return insn_len;
194b1df07bdSGlauber de Oliveira Costa }
195b1df07bdSGlauber de Oliveira Costa 
196b1df07bdSGlauber de Oliveira Costa static void native_flush_tlb(void)
197b1df07bdSGlauber de Oliveira Costa {
198b1df07bdSGlauber de Oliveira Costa 	__native_flush_tlb();
199b1df07bdSGlauber de Oliveira Costa }
200b1df07bdSGlauber de Oliveira Costa 
201b1df07bdSGlauber de Oliveira Costa /*
202b1df07bdSGlauber de Oliveira Costa  * Global pages have to be flushed a bit differently. Not a real
203b1df07bdSGlauber de Oliveira Costa  * performance problem because this does not happen often.
204b1df07bdSGlauber de Oliveira Costa  */
205b1df07bdSGlauber de Oliveira Costa static void native_flush_tlb_global(void)
206b1df07bdSGlauber de Oliveira Costa {
207b1df07bdSGlauber de Oliveira Costa 	__native_flush_tlb_global();
208b1df07bdSGlauber de Oliveira Costa }
209b1df07bdSGlauber de Oliveira Costa 
2101299ef1dSAndy Lutomirski static void native_flush_tlb_one_user(unsigned long addr)
211b1df07bdSGlauber de Oliveira Costa {
2121299ef1dSAndy Lutomirski 	__native_flush_tlb_one_user(addr);
213b1df07bdSGlauber de Oliveira Costa }
214b1df07bdSGlauber de Oliveira Costa 
215c5905afbSIngo Molnar struct static_key paravirt_steal_enabled;
216c5905afbSIngo Molnar struct static_key paravirt_steal_rq_enabled;
2173c404b57SGlauber Costa 
2183c404b57SGlauber Costa static u64 native_steal_clock(int cpu)
2193c404b57SGlauber Costa {
2203c404b57SGlauber Costa 	return 0;
2213c404b57SGlauber Costa }
2223c404b57SGlauber Costa 
223b1df07bdSGlauber de Oliveira Costa /* These are in entry.S */
224b1df07bdSGlauber de Oliveira Costa extern void native_iret(void);
2252be29982SJeremy Fitzhardinge extern void native_usergs_sysret64(void);
226b1df07bdSGlauber de Oliveira Costa 
227b1df07bdSGlauber de Oliveira Costa static struct resource reserve_ioports = {
228b1df07bdSGlauber de Oliveira Costa 	.start = 0,
229b1df07bdSGlauber de Oliveira Costa 	.end = IO_SPACE_LIMIT,
230b1df07bdSGlauber de Oliveira Costa 	.name = "paravirt-ioport",
231b1df07bdSGlauber de Oliveira Costa 	.flags = IORESOURCE_IO | IORESOURCE_BUSY,
232b1df07bdSGlauber de Oliveira Costa };
233b1df07bdSGlauber de Oliveira Costa 
234b1df07bdSGlauber de Oliveira Costa /*
235b1df07bdSGlauber de Oliveira Costa  * Reserve the whole legacy IO space to prevent any legacy drivers
236b1df07bdSGlauber de Oliveira Costa  * from wasting time probing for their hardware.  This is a fairly
237b1df07bdSGlauber de Oliveira Costa  * brute-force approach to disabling all non-virtual drivers.
238b1df07bdSGlauber de Oliveira Costa  *
239b1df07bdSGlauber de Oliveira Costa  * Note that this must be called very early to have any effect.
240b1df07bdSGlauber de Oliveira Costa  */
241b1df07bdSGlauber de Oliveira Costa int paravirt_disable_iospace(void)
242b1df07bdSGlauber de Oliveira Costa {
243f7743fe6SJeremy Fitzhardinge 	return request_resource(&ioport_resource, &reserve_ioports);
244b1df07bdSGlauber de Oliveira Costa }
245b1df07bdSGlauber de Oliveira Costa 
246b1df07bdSGlauber de Oliveira Costa static DEFINE_PER_CPU(enum paravirt_lazy_mode, paravirt_lazy_mode) = PARAVIRT_LAZY_NONE;
247b1df07bdSGlauber de Oliveira Costa 
248b1df07bdSGlauber de Oliveira Costa static inline void enter_lazy(enum paravirt_lazy_mode mode)
249b1df07bdSGlauber de Oliveira Costa {
250c6ae41e7SAlex Shi 	BUG_ON(this_cpu_read(paravirt_lazy_mode) != PARAVIRT_LAZY_NONE);
251b1df07bdSGlauber de Oliveira Costa 
252c6ae41e7SAlex Shi 	this_cpu_write(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 {
257c6ae41e7SAlex Shi 	BUG_ON(this_cpu_read(paravirt_lazy_mode) != mode);
258b1df07bdSGlauber de Oliveira Costa 
259c6ae41e7SAlex Shi 	this_cpu_write(paravirt_lazy_mode, PARAVIRT_LAZY_NONE);
260b1df07bdSGlauber de Oliveira Costa }
261b1df07bdSGlauber de Oliveira Costa 
262b1df07bdSGlauber de Oliveira Costa void paravirt_enter_lazy_mmu(void)
263b1df07bdSGlauber de Oliveira Costa {
264b1df07bdSGlauber de Oliveira Costa 	enter_lazy(PARAVIRT_LAZY_MMU);
265b1df07bdSGlauber de Oliveira Costa }
266b1df07bdSGlauber de Oliveira Costa 
267b1df07bdSGlauber de Oliveira Costa void paravirt_leave_lazy_mmu(void)
268b1df07bdSGlauber de Oliveira Costa {
269b407fc57SJeremy Fitzhardinge 	leave_lazy(PARAVIRT_LAZY_MMU);
270b1df07bdSGlauber de Oliveira Costa }
271b1df07bdSGlauber de Oliveira Costa 
272511ba86eSBoris Ostrovsky void paravirt_flush_lazy_mmu(void)
273511ba86eSBoris Ostrovsky {
274511ba86eSBoris Ostrovsky 	preempt_disable();
275511ba86eSBoris Ostrovsky 
276511ba86eSBoris Ostrovsky 	if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU) {
277511ba86eSBoris Ostrovsky 		arch_leave_lazy_mmu_mode();
278511ba86eSBoris Ostrovsky 		arch_enter_lazy_mmu_mode();
279511ba86eSBoris Ostrovsky 	}
280511ba86eSBoris Ostrovsky 
281511ba86eSBoris Ostrovsky 	preempt_enable();
282511ba86eSBoris Ostrovsky }
283511ba86eSBoris Ostrovsky 
284224101edSJeremy Fitzhardinge void paravirt_start_context_switch(struct task_struct *prev)
285b1df07bdSGlauber de Oliveira Costa {
2862829b449SJeremy Fitzhardinge 	BUG_ON(preemptible());
2872829b449SJeremy Fitzhardinge 
288c6ae41e7SAlex Shi 	if (this_cpu_read(paravirt_lazy_mode) == PARAVIRT_LAZY_MMU) {
289b407fc57SJeremy Fitzhardinge 		arch_leave_lazy_mmu_mode();
290224101edSJeremy Fitzhardinge 		set_ti_thread_flag(task_thread_info(prev), TIF_LAZY_MMU_UPDATES);
291b407fc57SJeremy Fitzhardinge 	}
292b1df07bdSGlauber de Oliveira Costa 	enter_lazy(PARAVIRT_LAZY_CPU);
293b1df07bdSGlauber de Oliveira Costa }
294b1df07bdSGlauber de Oliveira Costa 
295224101edSJeremy Fitzhardinge void paravirt_end_context_switch(struct task_struct *next)
296b1df07bdSGlauber de Oliveira Costa {
2972829b449SJeremy Fitzhardinge 	BUG_ON(preemptible());
2982829b449SJeremy Fitzhardinge 
299b407fc57SJeremy Fitzhardinge 	leave_lazy(PARAVIRT_LAZY_CPU);
300b407fc57SJeremy Fitzhardinge 
301224101edSJeremy Fitzhardinge 	if (test_and_clear_ti_thread_flag(task_thread_info(next), TIF_LAZY_MMU_UPDATES))
302b407fc57SJeremy Fitzhardinge 		arch_enter_lazy_mmu_mode();
303b1df07bdSGlauber de Oliveira Costa }
304b1df07bdSGlauber de Oliveira Costa 
305b1df07bdSGlauber de Oliveira Costa enum paravirt_lazy_mode paravirt_get_lazy_mode(void)
306b1df07bdSGlauber de Oliveira Costa {
307b8bcfe99SJeremy Fitzhardinge 	if (in_interrupt())
308b8bcfe99SJeremy Fitzhardinge 		return PARAVIRT_LAZY_NONE;
309b8bcfe99SJeremy Fitzhardinge 
310c6ae41e7SAlex Shi 	return this_cpu_read(paravirt_lazy_mode);
311b1df07bdSGlauber de Oliveira Costa }
312b1df07bdSGlauber de Oliveira Costa 
313b1df07bdSGlauber de Oliveira Costa struct pv_info pv_info = {
314b1df07bdSGlauber de Oliveira Costa 	.name = "bare hardware",
315b1df07bdSGlauber de Oliveira Costa 	.kernel_rpl = 0,
316b1df07bdSGlauber de Oliveira Costa 	.shared_kernel_pmd = 1,	/* Only used when CONFIG_X86_PAE is set */
317318f5a2aSAndy Lutomirski 
318318f5a2aSAndy Lutomirski #ifdef CONFIG_X86_64
319318f5a2aSAndy Lutomirski 	.extra_user_64bit_cs = __USER_CS,
320318f5a2aSAndy Lutomirski #endif
321b1df07bdSGlauber de Oliveira Costa };
322b1df07bdSGlauber de Oliveira Costa 
323b1df07bdSGlauber de Oliveira Costa struct pv_init_ops pv_init_ops = {
324b1df07bdSGlauber de Oliveira Costa 	.patch = native_patch,
325b1df07bdSGlauber de Oliveira Costa };
326b1df07bdSGlauber de Oliveira Costa 
327b1df07bdSGlauber de Oliveira Costa struct pv_time_ops pv_time_ops = {
328b1df07bdSGlauber de Oliveira Costa 	.sched_clock = native_sched_clock,
3293c404b57SGlauber Costa 	.steal_clock = native_steal_clock,
330b1df07bdSGlauber de Oliveira Costa };
331b1df07bdSGlauber de Oliveira Costa 
3329a55fdbeSAndi Kleen __visible struct pv_irq_ops pv_irq_ops = {
333ecb93d1cSJeremy Fitzhardinge 	.save_fl = __PV_IS_CALLEE_SAVE(native_save_fl),
334ecb93d1cSJeremy Fitzhardinge 	.restore_fl = __PV_IS_CALLEE_SAVE(native_restore_fl),
335ecb93d1cSJeremy Fitzhardinge 	.irq_disable = __PV_IS_CALLEE_SAVE(native_irq_disable),
336ecb93d1cSJeremy Fitzhardinge 	.irq_enable = __PV_IS_CALLEE_SAVE(native_irq_enable),
337b1df07bdSGlauber de Oliveira Costa 	.safe_halt = native_safe_halt,
338b1df07bdSGlauber de Oliveira Costa 	.halt = native_halt,
339b1df07bdSGlauber de Oliveira Costa };
340b1df07bdSGlauber de Oliveira Costa 
3419a55fdbeSAndi Kleen __visible struct pv_cpu_ops pv_cpu_ops = {
342b1df07bdSGlauber de Oliveira Costa 	.cpuid = native_cpuid,
343b1df07bdSGlauber de Oliveira Costa 	.get_debugreg = native_get_debugreg,
344b1df07bdSGlauber de Oliveira Costa 	.set_debugreg = native_set_debugreg,
345b1df07bdSGlauber de Oliveira Costa 	.read_cr0 = native_read_cr0,
346b1df07bdSGlauber de Oliveira Costa 	.write_cr0 = native_write_cr0,
347b1df07bdSGlauber de Oliveira Costa 	.write_cr4 = native_write_cr4,
34888b4755fSGlauber de Oliveira Costa #ifdef CONFIG_X86_64
34988b4755fSGlauber de Oliveira Costa 	.read_cr8 = native_read_cr8,
35088b4755fSGlauber de Oliveira Costa 	.write_cr8 = native_write_cr8,
35188b4755fSGlauber de Oliveira Costa #endif
352b1df07bdSGlauber de Oliveira Costa 	.wbinvd = native_wbinvd,
353dd2f4a00SAndy Lutomirski 	.read_msr = native_read_msr,
354dd2f4a00SAndy Lutomirski 	.write_msr = native_write_msr,
355c2ee03b2SAndy Lutomirski 	.read_msr_safe = native_read_msr_safe,
356c2ee03b2SAndy Lutomirski 	.write_msr_safe = native_write_msr_safe,
357b1df07bdSGlauber de Oliveira Costa 	.read_pmc = native_read_pmc,
358b1df07bdSGlauber de Oliveira Costa 	.load_tr_desc = native_load_tr_desc,
359b1df07bdSGlauber de Oliveira Costa 	.set_ldt = native_set_ldt,
360b1df07bdSGlauber de Oliveira Costa 	.load_gdt = native_load_gdt,
361b1df07bdSGlauber de Oliveira Costa 	.load_idt = native_load_idt,
362b1df07bdSGlauber de Oliveira Costa 	.store_tr = native_store_tr,
363b1df07bdSGlauber de Oliveira Costa 	.load_tls = native_load_tls,
3649f9d489aSJeremy Fitzhardinge #ifdef CONFIG_X86_64
3659f9d489aSJeremy Fitzhardinge 	.load_gs_index = native_load_gs_index,
3669f9d489aSJeremy Fitzhardinge #endif
367b1df07bdSGlauber de Oliveira Costa 	.write_ldt_entry = native_write_ldt_entry,
368b1df07bdSGlauber de Oliveira Costa 	.write_gdt_entry = native_write_gdt_entry,
369b1df07bdSGlauber de Oliveira Costa 	.write_idt_entry = native_write_idt_entry,
37038ffbe66SJeremy Fitzhardinge 
37138ffbe66SJeremy Fitzhardinge 	.alloc_ldt = paravirt_nop,
37238ffbe66SJeremy Fitzhardinge 	.free_ldt = paravirt_nop,
37338ffbe66SJeremy Fitzhardinge 
374b1df07bdSGlauber de Oliveira Costa 	.load_sp0 = native_load_sp0,
375b1df07bdSGlauber de Oliveira Costa 
3762be29982SJeremy Fitzhardinge #ifdef CONFIG_X86_64
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 
38980271972SMasami Hiramatsu /* At this point, native_get/set_debugreg has real function entries */
390376e2424SMasami Hiramatsu NOKPROBE_SYMBOL(native_get_debugreg);
39180271972SMasami Hiramatsu NOKPROBE_SYMBOL(native_set_debugreg);
39280271972SMasami Hiramatsu NOKPROBE_SYMBOL(native_load_idt);
393376e2424SMasami Hiramatsu 
39441edafdbSJeremy Fitzhardinge #if defined(CONFIG_X86_32) && !defined(CONFIG_X86_PAE)
39541edafdbSJeremy Fitzhardinge /* 32-bit pagetable entries */
396da5de7c2SJeremy Fitzhardinge #define PTE_IDENT	__PV_IS_CALLEE_SAVE(_paravirt_ident_32)
39741edafdbSJeremy Fitzhardinge #else
39841edafdbSJeremy Fitzhardinge /* 64-bit pagetable entries */
399da5de7c2SJeremy Fitzhardinge #define PTE_IDENT	__PV_IS_CALLEE_SAVE(_paravirt_ident_64)
40041edafdbSJeremy Fitzhardinge #endif
40141edafdbSJeremy Fitzhardinge 
402404f6aacSKees Cook struct pv_mmu_ops pv_mmu_ops __ro_after_init = {
403b1df07bdSGlauber de Oliveira Costa 
404b1df07bdSGlauber de Oliveira Costa 	.read_cr2 = native_read_cr2,
405b1df07bdSGlauber de Oliveira Costa 	.write_cr2 = native_write_cr2,
4066c690ee1SAndy Lutomirski 	.read_cr3 = __native_read_cr3,
407b1df07bdSGlauber de Oliveira Costa 	.write_cr3 = native_write_cr3,
408b1df07bdSGlauber de Oliveira Costa 
409b1df07bdSGlauber de Oliveira Costa 	.flush_tlb_user = native_flush_tlb,
410b1df07bdSGlauber de Oliveira Costa 	.flush_tlb_kernel = native_flush_tlb_global,
4111299ef1dSAndy Lutomirski 	.flush_tlb_one_user = native_flush_tlb_one_user,
412b1df07bdSGlauber de Oliveira Costa 	.flush_tlb_others = native_flush_tlb_others,
41348a8b97cSPeter Zijlstra 	.tlb_remove_table = (void (*)(struct mmu_gather *, void *))tlb_remove_page,
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,
421335437fbSKirill A. Shutemov 	.alloc_p4d = paravirt_nop,
4226944a9c8SJeremy Fitzhardinge 	.release_pte = paravirt_nop,
4236944a9c8SJeremy Fitzhardinge 	.release_pmd = paravirt_nop,
4242761fa09SJeremy Fitzhardinge 	.release_pud = paravirt_nop,
425335437fbSKirill A. Shutemov 	.release_p4d = paravirt_nop,
426b1df07bdSGlauber de Oliveira Costa 
427b1df07bdSGlauber de Oliveira Costa 	.set_pte = native_set_pte,
428b1df07bdSGlauber de Oliveira Costa 	.set_pte_at = native_set_pte_at,
429b1df07bdSGlauber de Oliveira Costa 	.set_pmd = native_set_pmd,
430b1df07bdSGlauber de Oliveira Costa 
43108b882c6SJeremy Fitzhardinge 	.ptep_modify_prot_start = __ptep_modify_prot_start,
43208b882c6SJeremy Fitzhardinge 	.ptep_modify_prot_commit = __ptep_modify_prot_commit,
43308b882c6SJeremy Fitzhardinge 
43498233368SKirill A. Shutemov #if CONFIG_PGTABLE_LEVELS >= 3
435b1df07bdSGlauber de Oliveira Costa #ifdef CONFIG_X86_PAE
436b1df07bdSGlauber de Oliveira Costa 	.set_pte_atomic = native_set_pte_atomic,
437b1df07bdSGlauber de Oliveira Costa 	.pte_clear = native_pte_clear,
438b1df07bdSGlauber de Oliveira Costa 	.pmd_clear = native_pmd_clear,
439f95f2f7bSEduardo Habkost #endif
440f95f2f7bSEduardo Habkost 	.set_pud = native_set_pud,
441da5de7c2SJeremy Fitzhardinge 
442da5de7c2SJeremy Fitzhardinge 	.pmd_val = PTE_IDENT,
443da5de7c2SJeremy Fitzhardinge 	.make_pmd = PTE_IDENT,
444f95f2f7bSEduardo Habkost 
445f2a6a705SKirill A. Shutemov #if CONFIG_PGTABLE_LEVELS >= 4
446da5de7c2SJeremy Fitzhardinge 	.pud_val = PTE_IDENT,
447da5de7c2SJeremy Fitzhardinge 	.make_pud = PTE_IDENT,
448da5de7c2SJeremy Fitzhardinge 
449f2a6a705SKirill A. Shutemov 	.set_p4d = native_set_p4d,
450f2a6a705SKirill A. Shutemov 
451f2a6a705SKirill A. Shutemov #if CONFIG_PGTABLE_LEVELS >= 5
452335437fbSKirill A. Shutemov 	.p4d_val = PTE_IDENT,
453335437fbSKirill A. Shutemov 	.make_p4d = PTE_IDENT,
454335437fbSKirill A. Shutemov 
455335437fbSKirill A. Shutemov 	.set_pgd = native_set_pgd,
456335437fbSKirill A. Shutemov #endif /* CONFIG_PGTABLE_LEVELS >= 5 */
457f2a6a705SKirill A. Shutemov #endif /* CONFIG_PGTABLE_LEVELS >= 4 */
45898233368SKirill A. Shutemov #endif /* CONFIG_PGTABLE_LEVELS >= 3 */
459b1df07bdSGlauber de Oliveira Costa 
460da5de7c2SJeremy Fitzhardinge 	.pte_val = PTE_IDENT,
461da5de7c2SJeremy Fitzhardinge 	.pgd_val = PTE_IDENT,
462b1df07bdSGlauber de Oliveira Costa 
463da5de7c2SJeremy Fitzhardinge 	.make_pte = PTE_IDENT,
464da5de7c2SJeremy Fitzhardinge 	.make_pgd = PTE_IDENT,
465b1df07bdSGlauber de Oliveira Costa 
466b1df07bdSGlauber de Oliveira Costa 	.dup_mmap = paravirt_nop,
467b1df07bdSGlauber de Oliveira Costa 	.exit_mmap = paravirt_nop,
468b1df07bdSGlauber de Oliveira Costa 	.activate_mm = paravirt_nop,
469b1df07bdSGlauber de Oliveira Costa 
470b1df07bdSGlauber de Oliveira Costa 	.lazy_mode = {
471b1df07bdSGlauber de Oliveira Costa 		.enter = paravirt_nop,
472b1df07bdSGlauber de Oliveira Costa 		.leave = paravirt_nop,
473511ba86eSBoris Ostrovsky 		.flush = paravirt_nop,
474b1df07bdSGlauber de Oliveira Costa 	},
475aeaaa59cSJeremy Fitzhardinge 
476aeaaa59cSJeremy Fitzhardinge 	.set_fixmap = native_set_fixmap,
477b1df07bdSGlauber de Oliveira Costa };
478b1df07bdSGlauber de Oliveira Costa 
479b1df07bdSGlauber de Oliveira Costa EXPORT_SYMBOL_GPL(pv_time_ops);
480b1df07bdSGlauber de Oliveira Costa EXPORT_SYMBOL    (pv_cpu_ops);
481b1df07bdSGlauber de Oliveira Costa EXPORT_SYMBOL    (pv_mmu_ops);
482b1df07bdSGlauber de Oliveira Costa EXPORT_SYMBOL_GPL(pv_info);
483b1df07bdSGlauber de Oliveira Costa EXPORT_SYMBOL    (pv_irq_ops);
484