162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*  Paravirtualization interfaces
362306a36Sopenharmony_ci    Copyright (C) 2006 Rusty Russell IBM Corporation
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci    2007 - x86_64 support added by Glauber de Oliveira Costa, Red Hat Inc
762306a36Sopenharmony_ci*/
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/errno.h>
1062306a36Sopenharmony_ci#include <linux/init.h>
1162306a36Sopenharmony_ci#include <linux/export.h>
1262306a36Sopenharmony_ci#include <linux/efi.h>
1362306a36Sopenharmony_ci#include <linux/bcd.h>
1462306a36Sopenharmony_ci#include <linux/highmem.h>
1562306a36Sopenharmony_ci#include <linux/kprobes.h>
1662306a36Sopenharmony_ci#include <linux/pgtable.h>
1762306a36Sopenharmony_ci#include <linux/static_call.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include <asm/bug.h>
2062306a36Sopenharmony_ci#include <asm/paravirt.h>
2162306a36Sopenharmony_ci#include <asm/debugreg.h>
2262306a36Sopenharmony_ci#include <asm/desc.h>
2362306a36Sopenharmony_ci#include <asm/setup.h>
2462306a36Sopenharmony_ci#include <asm/time.h>
2562306a36Sopenharmony_ci#include <asm/pgalloc.h>
2662306a36Sopenharmony_ci#include <asm/irq.h>
2762306a36Sopenharmony_ci#include <asm/delay.h>
2862306a36Sopenharmony_ci#include <asm/fixmap.h>
2962306a36Sopenharmony_ci#include <asm/apic.h>
3062306a36Sopenharmony_ci#include <asm/tlbflush.h>
3162306a36Sopenharmony_ci#include <asm/timer.h>
3262306a36Sopenharmony_ci#include <asm/special_insns.h>
3362306a36Sopenharmony_ci#include <asm/tlb.h>
3462306a36Sopenharmony_ci#include <asm/io_bitmap.h>
3562306a36Sopenharmony_ci#include <asm/gsseg.h>
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci/*
3862306a36Sopenharmony_ci * nop stub, which must not clobber anything *including the stack* to
3962306a36Sopenharmony_ci * avoid confusing the entry prologues.
4062306a36Sopenharmony_ci */
4162306a36Sopenharmony_ciDEFINE_PARAVIRT_ASM(_paravirt_nop, "", .entry.text);
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci/* stub always returning 0. */
4462306a36Sopenharmony_ciDEFINE_PARAVIRT_ASM(paravirt_ret0, "xor %eax,%eax", .entry.text);
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_civoid __init default_banner(void)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	printk(KERN_INFO "Booting paravirtualized kernel on %s\n",
4962306a36Sopenharmony_ci	       pv_info.name);
5062306a36Sopenharmony_ci}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci/* Undefined instruction for dealing with missing ops pointers. */
5362306a36Sopenharmony_cinoinstr void paravirt_BUG(void)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	BUG();
5662306a36Sopenharmony_ci}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistatic unsigned paravirt_patch_call(void *insn_buff, const void *target,
5962306a36Sopenharmony_ci				    unsigned long addr, unsigned len)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	__text_gen_insn(insn_buff, CALL_INSN_OPCODE,
6262306a36Sopenharmony_ci			(void *)addr, target, CALL_INSN_SIZE);
6362306a36Sopenharmony_ci	return CALL_INSN_SIZE;
6462306a36Sopenharmony_ci}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci#ifdef CONFIG_PARAVIRT_XXL
6762306a36Sopenharmony_ciDEFINE_PARAVIRT_ASM(_paravirt_ident_64, "mov %rdi, %rax", .text);
6862306a36Sopenharmony_ciDEFINE_PARAVIRT_ASM(pv_native_save_fl, "pushf; pop %rax", .noinstr.text);
6962306a36Sopenharmony_ciDEFINE_PARAVIRT_ASM(pv_native_irq_disable, "cli", .noinstr.text);
7062306a36Sopenharmony_ciDEFINE_PARAVIRT_ASM(pv_native_irq_enable, "sti", .noinstr.text);
7162306a36Sopenharmony_ciDEFINE_PARAVIRT_ASM(pv_native_read_cr2, "mov %cr2, %rax", .noinstr.text);
7262306a36Sopenharmony_ci#endif
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ciDEFINE_STATIC_KEY_TRUE(virt_spin_lock_key);
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_civoid __init native_pv_lock_init(void)
7762306a36Sopenharmony_ci{
7862306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_PARAVIRT_SPINLOCKS) &&
7962306a36Sopenharmony_ci	    !boot_cpu_has(X86_FEATURE_HYPERVISOR))
8062306a36Sopenharmony_ci		static_branch_disable(&virt_spin_lock_key);
8162306a36Sopenharmony_ci}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistatic void native_tlb_remove_table(struct mmu_gather *tlb, void *table)
8462306a36Sopenharmony_ci{
8562306a36Sopenharmony_ci	tlb_remove_page(tlb, table);
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ciunsigned int paravirt_patch(u8 type, void *insn_buff, unsigned long addr,
8962306a36Sopenharmony_ci			    unsigned int len)
9062306a36Sopenharmony_ci{
9162306a36Sopenharmony_ci	/*
9262306a36Sopenharmony_ci	 * Neat trick to map patch type back to the call within the
9362306a36Sopenharmony_ci	 * corresponding structure.
9462306a36Sopenharmony_ci	 */
9562306a36Sopenharmony_ci	void *opfunc = *((void **)&pv_ops + type);
9662306a36Sopenharmony_ci	unsigned ret;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	if (opfunc == NULL)
9962306a36Sopenharmony_ci		/* If there's no function, patch it with paravirt_BUG() */
10062306a36Sopenharmony_ci		ret = paravirt_patch_call(insn_buff, paravirt_BUG, addr, len);
10162306a36Sopenharmony_ci	else if (opfunc == _paravirt_nop)
10262306a36Sopenharmony_ci		ret = 0;
10362306a36Sopenharmony_ci	else
10462306a36Sopenharmony_ci		/* Otherwise call the function. */
10562306a36Sopenharmony_ci		ret = paravirt_patch_call(insn_buff, opfunc, addr, len);
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	return ret;
10862306a36Sopenharmony_ci}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_cistruct static_key paravirt_steal_enabled;
11162306a36Sopenharmony_cistruct static_key paravirt_steal_rq_enabled;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_cistatic u64 native_steal_clock(int cpu)
11462306a36Sopenharmony_ci{
11562306a36Sopenharmony_ci	return 0;
11662306a36Sopenharmony_ci}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ciDEFINE_STATIC_CALL(pv_steal_clock, native_steal_clock);
11962306a36Sopenharmony_ciDEFINE_STATIC_CALL(pv_sched_clock, native_sched_clock);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_civoid paravirt_set_sched_clock(u64 (*func)(void))
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	static_call_update(pv_sched_clock, func);
12462306a36Sopenharmony_ci}
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci/* These are in entry.S */
12762306a36Sopenharmony_cistatic struct resource reserve_ioports = {
12862306a36Sopenharmony_ci	.start = 0,
12962306a36Sopenharmony_ci	.end = IO_SPACE_LIMIT,
13062306a36Sopenharmony_ci	.name = "paravirt-ioport",
13162306a36Sopenharmony_ci	.flags = IORESOURCE_IO | IORESOURCE_BUSY,
13262306a36Sopenharmony_ci};
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci/*
13562306a36Sopenharmony_ci * Reserve the whole legacy IO space to prevent any legacy drivers
13662306a36Sopenharmony_ci * from wasting time probing for their hardware.  This is a fairly
13762306a36Sopenharmony_ci * brute-force approach to disabling all non-virtual drivers.
13862306a36Sopenharmony_ci *
13962306a36Sopenharmony_ci * Note that this must be called very early to have any effect.
14062306a36Sopenharmony_ci */
14162306a36Sopenharmony_ciint paravirt_disable_iospace(void)
14262306a36Sopenharmony_ci{
14362306a36Sopenharmony_ci	return request_resource(&ioport_resource, &reserve_ioports);
14462306a36Sopenharmony_ci}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci#ifdef CONFIG_PARAVIRT_XXL
14762306a36Sopenharmony_cistatic noinstr void pv_native_write_cr2(unsigned long val)
14862306a36Sopenharmony_ci{
14962306a36Sopenharmony_ci	native_write_cr2(val);
15062306a36Sopenharmony_ci}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cistatic noinstr unsigned long pv_native_get_debugreg(int regno)
15362306a36Sopenharmony_ci{
15462306a36Sopenharmony_ci	return native_get_debugreg(regno);
15562306a36Sopenharmony_ci}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_cistatic noinstr void pv_native_set_debugreg(int regno, unsigned long val)
15862306a36Sopenharmony_ci{
15962306a36Sopenharmony_ci	native_set_debugreg(regno, val);
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_cinoinstr void pv_native_wbinvd(void)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	native_wbinvd();
16562306a36Sopenharmony_ci}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_cistatic noinstr void pv_native_safe_halt(void)
16862306a36Sopenharmony_ci{
16962306a36Sopenharmony_ci	native_safe_halt();
17062306a36Sopenharmony_ci}
17162306a36Sopenharmony_ci#endif
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_cistruct pv_info pv_info = {
17462306a36Sopenharmony_ci	.name = "bare hardware",
17562306a36Sopenharmony_ci#ifdef CONFIG_PARAVIRT_XXL
17662306a36Sopenharmony_ci	.extra_user_64bit_cs = __USER_CS,
17762306a36Sopenharmony_ci#endif
17862306a36Sopenharmony_ci};
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci/* 64-bit pagetable entries */
18162306a36Sopenharmony_ci#define PTE_IDENT	__PV_IS_CALLEE_SAVE(_paravirt_ident_64)
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistruct paravirt_patch_template pv_ops = {
18462306a36Sopenharmony_ci	/* Cpu ops. */
18562306a36Sopenharmony_ci	.cpu.io_delay		= native_io_delay,
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci#ifdef CONFIG_PARAVIRT_XXL
18862306a36Sopenharmony_ci	.cpu.cpuid		= native_cpuid,
18962306a36Sopenharmony_ci	.cpu.get_debugreg	= pv_native_get_debugreg,
19062306a36Sopenharmony_ci	.cpu.set_debugreg	= pv_native_set_debugreg,
19162306a36Sopenharmony_ci	.cpu.read_cr0		= native_read_cr0,
19262306a36Sopenharmony_ci	.cpu.write_cr0		= native_write_cr0,
19362306a36Sopenharmony_ci	.cpu.write_cr4		= native_write_cr4,
19462306a36Sopenharmony_ci	.cpu.wbinvd		= pv_native_wbinvd,
19562306a36Sopenharmony_ci	.cpu.read_msr		= native_read_msr,
19662306a36Sopenharmony_ci	.cpu.write_msr		= native_write_msr,
19762306a36Sopenharmony_ci	.cpu.read_msr_safe	= native_read_msr_safe,
19862306a36Sopenharmony_ci	.cpu.write_msr_safe	= native_write_msr_safe,
19962306a36Sopenharmony_ci	.cpu.read_pmc		= native_read_pmc,
20062306a36Sopenharmony_ci	.cpu.load_tr_desc	= native_load_tr_desc,
20162306a36Sopenharmony_ci	.cpu.set_ldt		= native_set_ldt,
20262306a36Sopenharmony_ci	.cpu.load_gdt		= native_load_gdt,
20362306a36Sopenharmony_ci	.cpu.load_idt		= native_load_idt,
20462306a36Sopenharmony_ci	.cpu.store_tr		= native_store_tr,
20562306a36Sopenharmony_ci	.cpu.load_tls		= native_load_tls,
20662306a36Sopenharmony_ci	.cpu.load_gs_index	= native_load_gs_index,
20762306a36Sopenharmony_ci	.cpu.write_ldt_entry	= native_write_ldt_entry,
20862306a36Sopenharmony_ci	.cpu.write_gdt_entry	= native_write_gdt_entry,
20962306a36Sopenharmony_ci	.cpu.write_idt_entry	= native_write_idt_entry,
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	.cpu.alloc_ldt		= paravirt_nop,
21262306a36Sopenharmony_ci	.cpu.free_ldt		= paravirt_nop,
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	.cpu.load_sp0		= native_load_sp0,
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci#ifdef CONFIG_X86_IOPL_IOPERM
21762306a36Sopenharmony_ci	.cpu.invalidate_io_bitmap	= native_tss_invalidate_io_bitmap,
21862306a36Sopenharmony_ci	.cpu.update_io_bitmap		= native_tss_update_io_bitmap,
21962306a36Sopenharmony_ci#endif
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	.cpu.start_context_switch	= paravirt_nop,
22262306a36Sopenharmony_ci	.cpu.end_context_switch		= paravirt_nop,
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	/* Irq ops. */
22562306a36Sopenharmony_ci	.irq.save_fl		= __PV_IS_CALLEE_SAVE(pv_native_save_fl),
22662306a36Sopenharmony_ci	.irq.irq_disable	= __PV_IS_CALLEE_SAVE(pv_native_irq_disable),
22762306a36Sopenharmony_ci	.irq.irq_enable		= __PV_IS_CALLEE_SAVE(pv_native_irq_enable),
22862306a36Sopenharmony_ci	.irq.safe_halt		= pv_native_safe_halt,
22962306a36Sopenharmony_ci	.irq.halt		= native_halt,
23062306a36Sopenharmony_ci#endif /* CONFIG_PARAVIRT_XXL */
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	/* Mmu ops. */
23362306a36Sopenharmony_ci	.mmu.flush_tlb_user	= native_flush_tlb_local,
23462306a36Sopenharmony_ci	.mmu.flush_tlb_kernel	= native_flush_tlb_global,
23562306a36Sopenharmony_ci	.mmu.flush_tlb_one_user	= native_flush_tlb_one_user,
23662306a36Sopenharmony_ci	.mmu.flush_tlb_multi	= native_flush_tlb_multi,
23762306a36Sopenharmony_ci	.mmu.tlb_remove_table	= native_tlb_remove_table,
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	.mmu.exit_mmap		= paravirt_nop,
24062306a36Sopenharmony_ci	.mmu.notify_page_enc_status_changed	= paravirt_nop,
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci#ifdef CONFIG_PARAVIRT_XXL
24362306a36Sopenharmony_ci	.mmu.read_cr2		= __PV_IS_CALLEE_SAVE(pv_native_read_cr2),
24462306a36Sopenharmony_ci	.mmu.write_cr2		= pv_native_write_cr2,
24562306a36Sopenharmony_ci	.mmu.read_cr3		= __native_read_cr3,
24662306a36Sopenharmony_ci	.mmu.write_cr3		= native_write_cr3,
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	.mmu.pgd_alloc		= __paravirt_pgd_alloc,
24962306a36Sopenharmony_ci	.mmu.pgd_free		= paravirt_nop,
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	.mmu.alloc_pte		= paravirt_nop,
25262306a36Sopenharmony_ci	.mmu.alloc_pmd		= paravirt_nop,
25362306a36Sopenharmony_ci	.mmu.alloc_pud		= paravirt_nop,
25462306a36Sopenharmony_ci	.mmu.alloc_p4d		= paravirt_nop,
25562306a36Sopenharmony_ci	.mmu.release_pte	= paravirt_nop,
25662306a36Sopenharmony_ci	.mmu.release_pmd	= paravirt_nop,
25762306a36Sopenharmony_ci	.mmu.release_pud	= paravirt_nop,
25862306a36Sopenharmony_ci	.mmu.release_p4d	= paravirt_nop,
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	.mmu.set_pte		= native_set_pte,
26162306a36Sopenharmony_ci	.mmu.set_pmd		= native_set_pmd,
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	.mmu.ptep_modify_prot_start	= __ptep_modify_prot_start,
26462306a36Sopenharmony_ci	.mmu.ptep_modify_prot_commit	= __ptep_modify_prot_commit,
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	.mmu.set_pud		= native_set_pud,
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	.mmu.pmd_val		= PTE_IDENT,
26962306a36Sopenharmony_ci	.mmu.make_pmd		= PTE_IDENT,
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	.mmu.pud_val		= PTE_IDENT,
27262306a36Sopenharmony_ci	.mmu.make_pud		= PTE_IDENT,
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	.mmu.set_p4d		= native_set_p4d,
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci#if CONFIG_PGTABLE_LEVELS >= 5
27762306a36Sopenharmony_ci	.mmu.p4d_val		= PTE_IDENT,
27862306a36Sopenharmony_ci	.mmu.make_p4d		= PTE_IDENT,
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	.mmu.set_pgd		= native_set_pgd,
28162306a36Sopenharmony_ci#endif /* CONFIG_PGTABLE_LEVELS >= 5 */
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	.mmu.pte_val		= PTE_IDENT,
28462306a36Sopenharmony_ci	.mmu.pgd_val		= PTE_IDENT,
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	.mmu.make_pte		= PTE_IDENT,
28762306a36Sopenharmony_ci	.mmu.make_pgd		= PTE_IDENT,
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	.mmu.enter_mmap		= paravirt_nop,
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	.mmu.lazy_mode = {
29262306a36Sopenharmony_ci		.enter		= paravirt_nop,
29362306a36Sopenharmony_ci		.leave		= paravirt_nop,
29462306a36Sopenharmony_ci		.flush		= paravirt_nop,
29562306a36Sopenharmony_ci	},
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	.mmu.set_fixmap		= native_set_fixmap,
29862306a36Sopenharmony_ci#endif /* CONFIG_PARAVIRT_XXL */
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci#if defined(CONFIG_PARAVIRT_SPINLOCKS)
30162306a36Sopenharmony_ci	/* Lock ops. */
30262306a36Sopenharmony_ci#ifdef CONFIG_SMP
30362306a36Sopenharmony_ci	.lock.queued_spin_lock_slowpath	= native_queued_spin_lock_slowpath,
30462306a36Sopenharmony_ci	.lock.queued_spin_unlock	=
30562306a36Sopenharmony_ci				PV_CALLEE_SAVE(__native_queued_spin_unlock),
30662306a36Sopenharmony_ci	.lock.wait			= paravirt_nop,
30762306a36Sopenharmony_ci	.lock.kick			= paravirt_nop,
30862306a36Sopenharmony_ci	.lock.vcpu_is_preempted		=
30962306a36Sopenharmony_ci				PV_CALLEE_SAVE(__native_vcpu_is_preempted),
31062306a36Sopenharmony_ci#endif /* SMP */
31162306a36Sopenharmony_ci#endif
31262306a36Sopenharmony_ci};
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci#ifdef CONFIG_PARAVIRT_XXL
31562306a36Sopenharmony_ciNOKPROBE_SYMBOL(native_load_idt);
31662306a36Sopenharmony_ci#endif
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ciEXPORT_SYMBOL(pv_ops);
31962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pv_info);
320