18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci#ifndef _ASM_X86_KVM_PARA_H
38c2ecf20Sopenharmony_ci#define _ASM_X86_KVM_PARA_H
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci#include <asm/processor.h>
68c2ecf20Sopenharmony_ci#include <asm/alternative.h>
78c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
88c2ecf20Sopenharmony_ci#include <uapi/asm/kvm_para.h>
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#ifdef CONFIG_KVM_GUEST
118c2ecf20Sopenharmony_cibool kvm_check_and_clear_guest_paused(void);
128c2ecf20Sopenharmony_ci#else
138c2ecf20Sopenharmony_cistatic inline bool kvm_check_and_clear_guest_paused(void)
148c2ecf20Sopenharmony_ci{
158c2ecf20Sopenharmony_ci	return false;
168c2ecf20Sopenharmony_ci}
178c2ecf20Sopenharmony_ci#endif /* CONFIG_KVM_GUEST */
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#define KVM_HYPERCALL \
208c2ecf20Sopenharmony_ci        ALTERNATIVE("vmcall", "vmmcall", X86_FEATURE_VMMCALL)
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci/* For KVM hypercalls, a three-byte sequence of either the vmcall or the vmmcall
238c2ecf20Sopenharmony_ci * instruction.  The hypervisor may replace it with something else but only the
248c2ecf20Sopenharmony_ci * instructions are guaranteed to be supported.
258c2ecf20Sopenharmony_ci *
268c2ecf20Sopenharmony_ci * Up to four arguments may be passed in rbx, rcx, rdx, and rsi respectively.
278c2ecf20Sopenharmony_ci * The hypercall number should be placed in rax and the return value will be
288c2ecf20Sopenharmony_ci * placed in rax.  No other registers will be clobbered unless explicitly
298c2ecf20Sopenharmony_ci * noted by the particular hypercall.
308c2ecf20Sopenharmony_ci */
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_cistatic inline long kvm_hypercall0(unsigned int nr)
338c2ecf20Sopenharmony_ci{
348c2ecf20Sopenharmony_ci	long ret;
358c2ecf20Sopenharmony_ci	asm volatile(KVM_HYPERCALL
368c2ecf20Sopenharmony_ci		     : "=a"(ret)
378c2ecf20Sopenharmony_ci		     : "a"(nr)
388c2ecf20Sopenharmony_ci		     : "memory");
398c2ecf20Sopenharmony_ci	return ret;
408c2ecf20Sopenharmony_ci}
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistatic inline long kvm_hypercall1(unsigned int nr, unsigned long p1)
438c2ecf20Sopenharmony_ci{
448c2ecf20Sopenharmony_ci	long ret;
458c2ecf20Sopenharmony_ci	asm volatile(KVM_HYPERCALL
468c2ecf20Sopenharmony_ci		     : "=a"(ret)
478c2ecf20Sopenharmony_ci		     : "a"(nr), "b"(p1)
488c2ecf20Sopenharmony_ci		     : "memory");
498c2ecf20Sopenharmony_ci	return ret;
508c2ecf20Sopenharmony_ci}
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_cistatic inline long kvm_hypercall2(unsigned int nr, unsigned long p1,
538c2ecf20Sopenharmony_ci				  unsigned long p2)
548c2ecf20Sopenharmony_ci{
558c2ecf20Sopenharmony_ci	long ret;
568c2ecf20Sopenharmony_ci	asm volatile(KVM_HYPERCALL
578c2ecf20Sopenharmony_ci		     : "=a"(ret)
588c2ecf20Sopenharmony_ci		     : "a"(nr), "b"(p1), "c"(p2)
598c2ecf20Sopenharmony_ci		     : "memory");
608c2ecf20Sopenharmony_ci	return ret;
618c2ecf20Sopenharmony_ci}
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_cistatic inline long kvm_hypercall3(unsigned int nr, unsigned long p1,
648c2ecf20Sopenharmony_ci				  unsigned long p2, unsigned long p3)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	long ret;
678c2ecf20Sopenharmony_ci	asm volatile(KVM_HYPERCALL
688c2ecf20Sopenharmony_ci		     : "=a"(ret)
698c2ecf20Sopenharmony_ci		     : "a"(nr), "b"(p1), "c"(p2), "d"(p3)
708c2ecf20Sopenharmony_ci		     : "memory");
718c2ecf20Sopenharmony_ci	return ret;
728c2ecf20Sopenharmony_ci}
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_cistatic inline long kvm_hypercall4(unsigned int nr, unsigned long p1,
758c2ecf20Sopenharmony_ci				  unsigned long p2, unsigned long p3,
768c2ecf20Sopenharmony_ci				  unsigned long p4)
778c2ecf20Sopenharmony_ci{
788c2ecf20Sopenharmony_ci	long ret;
798c2ecf20Sopenharmony_ci	asm volatile(KVM_HYPERCALL
808c2ecf20Sopenharmony_ci		     : "=a"(ret)
818c2ecf20Sopenharmony_ci		     : "a"(nr), "b"(p1), "c"(p2), "d"(p3), "S"(p4)
828c2ecf20Sopenharmony_ci		     : "memory");
838c2ecf20Sopenharmony_ci	return ret;
848c2ecf20Sopenharmony_ci}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci#ifdef CONFIG_KVM_GUEST
878c2ecf20Sopenharmony_civoid kvmclock_init(void);
888c2ecf20Sopenharmony_civoid kvmclock_disable(void);
898c2ecf20Sopenharmony_cibool kvm_para_available(void);
908c2ecf20Sopenharmony_ciunsigned int kvm_arch_para_features(void);
918c2ecf20Sopenharmony_ciunsigned int kvm_arch_para_hints(void);
928c2ecf20Sopenharmony_civoid kvm_async_pf_task_wait_schedule(u32 token);
938c2ecf20Sopenharmony_civoid kvm_async_pf_task_wake(u32 token);
948c2ecf20Sopenharmony_ciu32 kvm_read_and_reset_apf_flags(void);
958c2ecf20Sopenharmony_cibool __kvm_handle_async_pf(struct pt_regs *regs, u32 token);
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ciDECLARE_STATIC_KEY_FALSE(kvm_async_pf_enabled);
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_cistatic __always_inline bool kvm_handle_async_pf(struct pt_regs *regs, u32 token)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci	if (static_branch_unlikely(&kvm_async_pf_enabled))
1028c2ecf20Sopenharmony_ci		return __kvm_handle_async_pf(regs, token);
1038c2ecf20Sopenharmony_ci	else
1048c2ecf20Sopenharmony_ci		return false;
1058c2ecf20Sopenharmony_ci}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci#ifdef CONFIG_PARAVIRT_SPINLOCKS
1088c2ecf20Sopenharmony_civoid __init kvm_spinlock_init(void);
1098c2ecf20Sopenharmony_ci#else /* !CONFIG_PARAVIRT_SPINLOCKS */
1108c2ecf20Sopenharmony_cistatic inline void kvm_spinlock_init(void)
1118c2ecf20Sopenharmony_ci{
1128c2ecf20Sopenharmony_ci}
1138c2ecf20Sopenharmony_ci#endif /* CONFIG_PARAVIRT_SPINLOCKS */
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci#else /* CONFIG_KVM_GUEST */
1168c2ecf20Sopenharmony_ci#define kvm_async_pf_task_wait_schedule(T) do {} while(0)
1178c2ecf20Sopenharmony_ci#define kvm_async_pf_task_wake(T) do {} while(0)
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_cistatic inline bool kvm_para_available(void)
1208c2ecf20Sopenharmony_ci{
1218c2ecf20Sopenharmony_ci	return false;
1228c2ecf20Sopenharmony_ci}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_cistatic inline unsigned int kvm_arch_para_features(void)
1258c2ecf20Sopenharmony_ci{
1268c2ecf20Sopenharmony_ci	return 0;
1278c2ecf20Sopenharmony_ci}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_cistatic inline unsigned int kvm_arch_para_hints(void)
1308c2ecf20Sopenharmony_ci{
1318c2ecf20Sopenharmony_ci	return 0;
1328c2ecf20Sopenharmony_ci}
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_cistatic inline u32 kvm_read_and_reset_apf_flags(void)
1358c2ecf20Sopenharmony_ci{
1368c2ecf20Sopenharmony_ci	return 0;
1378c2ecf20Sopenharmony_ci}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_cistatic __always_inline bool kvm_handle_async_pf(struct pt_regs *regs, u32 token)
1408c2ecf20Sopenharmony_ci{
1418c2ecf20Sopenharmony_ci	return false;
1428c2ecf20Sopenharmony_ci}
1438c2ecf20Sopenharmony_ci#endif
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci#endif /* _ASM_X86_KVM_PARA_H */
146