xref: /openbmc/linux/arch/x86/kvm/svm/svm_onhyperv.h (revision 38dfa830)
11e0c7d40SVineeth Pillai /* SPDX-License-Identifier: GPL-2.0-only */
21e0c7d40SVineeth Pillai /*
31e0c7d40SVineeth Pillai  * KVM L1 hypervisor optimizations on Hyper-V for SVM.
41e0c7d40SVineeth Pillai  */
51e0c7d40SVineeth Pillai 
61e0c7d40SVineeth Pillai #ifndef __ARCH_X86_KVM_SVM_ONHYPERV_H__
71e0c7d40SVineeth Pillai #define __ARCH_X86_KVM_SVM_ONHYPERV_H__
81e0c7d40SVineeth Pillai 
91e0c7d40SVineeth Pillai #if IS_ENABLED(CONFIG_HYPERV)
101e0c7d40SVineeth Pillai #include <asm/mshyperv.h>
111e0c7d40SVineeth Pillai 
121e0c7d40SVineeth Pillai #include "hyperv.h"
131e0c7d40SVineeth Pillai #include "kvm_onhyperv.h"
141e0c7d40SVineeth Pillai 
151e0c7d40SVineeth Pillai static struct kvm_x86_ops svm_x86_ops;
161e0c7d40SVineeth Pillai 
171e0c7d40SVineeth Pillai /*
181e0c7d40SVineeth Pillai  * Hyper-V uses the software reserved 32 bytes in VMCB
191e0c7d40SVineeth Pillai  * control area to expose SVM enlightenments to guests.
201e0c7d40SVineeth Pillai  */
211e0c7d40SVineeth Pillai struct hv_enlightenments {
221e0c7d40SVineeth Pillai 	struct __packed hv_enlightenments_control {
231e0c7d40SVineeth Pillai 		u32 nested_flush_hypercall:1;
241e0c7d40SVineeth Pillai 		u32 msr_bitmap:1;
251e0c7d40SVineeth Pillai 		u32 enlightened_npt_tlb: 1;
261e0c7d40SVineeth Pillai 		u32 reserved:29;
271e0c7d40SVineeth Pillai 	} __packed hv_enlightenments_control;
281e0c7d40SVineeth Pillai 	u32 hv_vp_id;
291e0c7d40SVineeth Pillai 	u64 hv_vm_id;
301e0c7d40SVineeth Pillai 	u64 partition_assist_page;
311e0c7d40SVineeth Pillai 	u64 reserved;
321e0c7d40SVineeth Pillai } __packed;
331e0c7d40SVineeth Pillai 
34c4327f15SVineeth Pillai /*
35c4327f15SVineeth Pillai  * Hyper-V uses the software reserved clean bit in VMCB
36c4327f15SVineeth Pillai  */
37c4327f15SVineeth Pillai #define VMCB_HV_NESTED_ENLIGHTENMENTS VMCB_SW
38c4327f15SVineeth Pillai 
391183646aSVineeth Pillai int svm_hv_enable_direct_tlbflush(struct kvm_vcpu *vcpu);
401183646aSVineeth Pillai 
411e0c7d40SVineeth Pillai static inline void svm_hv_init_vmcb(struct vmcb *vmcb)
421e0c7d40SVineeth Pillai {
431e0c7d40SVineeth Pillai 	struct hv_enlightenments *hve =
441e0c7d40SVineeth Pillai 		(struct hv_enlightenments *)vmcb->control.reserved_sw;
451e0c7d40SVineeth Pillai 
461e0c7d40SVineeth Pillai 	if (npt_enabled &&
471e0c7d40SVineeth Pillai 	    ms_hyperv.nested_features & HV_X64_NESTED_ENLIGHTENED_TLB)
481e0c7d40SVineeth Pillai 		hve->hv_enlightenments_control.enlightened_npt_tlb = 1;
49*38dfa830SVitaly Kuznetsov 
50*38dfa830SVitaly Kuznetsov 	if (ms_hyperv.nested_features & HV_X64_NESTED_MSR_BITMAP)
51*38dfa830SVitaly Kuznetsov 		hve->hv_enlightenments_control.msr_bitmap = 1;
521e0c7d40SVineeth Pillai }
531e0c7d40SVineeth Pillai 
541e0c7d40SVineeth Pillai static inline void svm_hv_hardware_setup(void)
551e0c7d40SVineeth Pillai {
561e0c7d40SVineeth Pillai 	if (npt_enabled &&
571e0c7d40SVineeth Pillai 	    ms_hyperv.nested_features & HV_X64_NESTED_ENLIGHTENED_TLB) {
581e0c7d40SVineeth Pillai 		pr_info("kvm: Hyper-V enlightened NPT TLB flush enabled\n");
591e0c7d40SVineeth Pillai 		svm_x86_ops.tlb_remote_flush = hv_remote_flush_tlb;
601e0c7d40SVineeth Pillai 		svm_x86_ops.tlb_remote_flush_with_range =
611e0c7d40SVineeth Pillai 				hv_remote_flush_tlb_with_range;
621e0c7d40SVineeth Pillai 	}
631183646aSVineeth Pillai 
641183646aSVineeth Pillai 	if (ms_hyperv.nested_features & HV_X64_NESTED_DIRECT_FLUSH) {
651183646aSVineeth Pillai 		int cpu;
661183646aSVineeth Pillai 
671183646aSVineeth Pillai 		pr_info("kvm: Hyper-V Direct TLB Flush enabled\n");
681183646aSVineeth Pillai 		for_each_online_cpu(cpu) {
691183646aSVineeth Pillai 			struct hv_vp_assist_page *vp_ap =
701183646aSVineeth Pillai 				hv_get_vp_assist_page(cpu);
711183646aSVineeth Pillai 
721183646aSVineeth Pillai 			if (!vp_ap)
731183646aSVineeth Pillai 				continue;
741183646aSVineeth Pillai 
751183646aSVineeth Pillai 			vp_ap->nested_control.features.directhypercall = 1;
761183646aSVineeth Pillai 		}
771183646aSVineeth Pillai 		svm_x86_ops.enable_direct_tlbflush =
781183646aSVineeth Pillai 				svm_hv_enable_direct_tlbflush;
791183646aSVineeth Pillai 	}
801e0c7d40SVineeth Pillai }
811e0c7d40SVineeth Pillai 
82c4327f15SVineeth Pillai static inline void svm_hv_vmcb_dirty_nested_enlightenments(
83c4327f15SVineeth Pillai 		struct kvm_vcpu *vcpu)
84c4327f15SVineeth Pillai {
85c4327f15SVineeth Pillai 	struct vmcb *vmcb = to_svm(vcpu)->vmcb;
86c4327f15SVineeth Pillai 	struct hv_enlightenments *hve =
87c4327f15SVineeth Pillai 		(struct hv_enlightenments *)vmcb->control.reserved_sw;
88c4327f15SVineeth Pillai 
89c4327f15SVineeth Pillai 	/*
90c4327f15SVineeth Pillai 	 * vmcb can be NULL if called during early vcpu init.
91c4327f15SVineeth Pillai 	 * And its okay not to mark vmcb dirty during vcpu init
92c4327f15SVineeth Pillai 	 * as we mark it dirty unconditionally towards end of vcpu
93c4327f15SVineeth Pillai 	 * init phase.
94c4327f15SVineeth Pillai 	 */
953fa5e8fdSPaolo Bonzini 	if (vmcb_is_clean(vmcb, VMCB_HV_NESTED_ENLIGHTENMENTS) &&
96c4327f15SVineeth Pillai 	    hve->hv_enlightenments_control.msr_bitmap)
97c4327f15SVineeth Pillai 		vmcb_mark_dirty(vmcb, VMCB_HV_NESTED_ENLIGHTENMENTS);
98c4327f15SVineeth Pillai }
991183646aSVineeth Pillai 
1001183646aSVineeth Pillai static inline void svm_hv_update_vp_id(struct vmcb *vmcb,
1011183646aSVineeth Pillai 		struct kvm_vcpu *vcpu)
1021183646aSVineeth Pillai {
1031183646aSVineeth Pillai 	struct hv_enlightenments *hve =
1041183646aSVineeth Pillai 		(struct hv_enlightenments *)vmcb->control.reserved_sw;
1051183646aSVineeth Pillai 	u32 vp_index = kvm_hv_get_vpindex(vcpu);
1061183646aSVineeth Pillai 
1071183646aSVineeth Pillai 	if (hve->hv_vp_id != vp_index) {
1081183646aSVineeth Pillai 		hve->hv_vp_id = vp_index;
1091183646aSVineeth Pillai 		vmcb_mark_dirty(vmcb, VMCB_HV_NESTED_ENLIGHTENMENTS);
1101183646aSVineeth Pillai 	}
1111183646aSVineeth Pillai }
1121e0c7d40SVineeth Pillai #else
1131e0c7d40SVineeth Pillai 
1141e0c7d40SVineeth Pillai static inline void svm_hv_init_vmcb(struct vmcb *vmcb)
1151e0c7d40SVineeth Pillai {
1161e0c7d40SVineeth Pillai }
1171e0c7d40SVineeth Pillai 
1181e0c7d40SVineeth Pillai static inline void svm_hv_hardware_setup(void)
1191e0c7d40SVineeth Pillai {
1201e0c7d40SVineeth Pillai }
121c4327f15SVineeth Pillai 
122c4327f15SVineeth Pillai static inline void svm_hv_vmcb_dirty_nested_enlightenments(
123c4327f15SVineeth Pillai 		struct kvm_vcpu *vcpu)
124c4327f15SVineeth Pillai {
125c4327f15SVineeth Pillai }
1261183646aSVineeth Pillai 
1271183646aSVineeth Pillai static inline void svm_hv_update_vp_id(struct vmcb *vmcb,
1281183646aSVineeth Pillai 		struct kvm_vcpu *vcpu)
1291183646aSVineeth Pillai {
1301183646aSVineeth Pillai }
1311e0c7d40SVineeth Pillai #endif /* CONFIG_HYPERV */
1321e0c7d40SVineeth Pillai 
1331e0c7d40SVineeth Pillai #endif /* __ARCH_X86_KVM_SVM_ONHYPERV_H__ */
134