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; 491e0c7d40SVineeth Pillai } 501e0c7d40SVineeth Pillai 511e0c7d40SVineeth Pillai static inline void svm_hv_hardware_setup(void) 521e0c7d40SVineeth Pillai { 531e0c7d40SVineeth Pillai if (npt_enabled && 541e0c7d40SVineeth Pillai ms_hyperv.nested_features & HV_X64_NESTED_ENLIGHTENED_TLB) { 551e0c7d40SVineeth Pillai pr_info("kvm: Hyper-V enlightened NPT TLB flush enabled\n"); 561e0c7d40SVineeth Pillai svm_x86_ops.tlb_remote_flush = hv_remote_flush_tlb; 571e0c7d40SVineeth Pillai svm_x86_ops.tlb_remote_flush_with_range = 581e0c7d40SVineeth Pillai hv_remote_flush_tlb_with_range; 591e0c7d40SVineeth Pillai } 601183646aSVineeth Pillai 611183646aSVineeth Pillai if (ms_hyperv.nested_features & HV_X64_NESTED_DIRECT_FLUSH) { 621183646aSVineeth Pillai int cpu; 631183646aSVineeth Pillai 641183646aSVineeth Pillai pr_info("kvm: Hyper-V Direct TLB Flush enabled\n"); 651183646aSVineeth Pillai for_each_online_cpu(cpu) { 661183646aSVineeth Pillai struct hv_vp_assist_page *vp_ap = 671183646aSVineeth Pillai hv_get_vp_assist_page(cpu); 681183646aSVineeth Pillai 691183646aSVineeth Pillai if (!vp_ap) 701183646aSVineeth Pillai continue; 711183646aSVineeth Pillai 721183646aSVineeth Pillai vp_ap->nested_control.features.directhypercall = 1; 731183646aSVineeth Pillai } 741183646aSVineeth Pillai svm_x86_ops.enable_direct_tlbflush = 751183646aSVineeth Pillai svm_hv_enable_direct_tlbflush; 761183646aSVineeth Pillai } 771e0c7d40SVineeth Pillai } 781e0c7d40SVineeth Pillai 79c4327f15SVineeth Pillai static inline void svm_hv_vmcb_dirty_nested_enlightenments( 80c4327f15SVineeth Pillai struct kvm_vcpu *vcpu) 81c4327f15SVineeth Pillai { 82c4327f15SVineeth Pillai struct vmcb *vmcb = to_svm(vcpu)->vmcb; 83c4327f15SVineeth Pillai struct hv_enlightenments *hve = 84c4327f15SVineeth Pillai (struct hv_enlightenments *)vmcb->control.reserved_sw; 85c4327f15SVineeth Pillai 86c4327f15SVineeth Pillai /* 87c4327f15SVineeth Pillai * vmcb can be NULL if called during early vcpu init. 88c4327f15SVineeth Pillai * And its okay not to mark vmcb dirty during vcpu init 89c4327f15SVineeth Pillai * as we mark it dirty unconditionally towards end of vcpu 90c4327f15SVineeth Pillai * init phase. 91c4327f15SVineeth Pillai */ 92*3fa5e8fdSPaolo Bonzini if (vmcb_is_clean(vmcb, VMCB_HV_NESTED_ENLIGHTENMENTS) && 93c4327f15SVineeth Pillai hve->hv_enlightenments_control.msr_bitmap) 94c4327f15SVineeth Pillai vmcb_mark_dirty(vmcb, VMCB_HV_NESTED_ENLIGHTENMENTS); 95c4327f15SVineeth Pillai } 961183646aSVineeth Pillai 971183646aSVineeth Pillai static inline void svm_hv_update_vp_id(struct vmcb *vmcb, 981183646aSVineeth Pillai struct kvm_vcpu *vcpu) 991183646aSVineeth Pillai { 1001183646aSVineeth Pillai struct hv_enlightenments *hve = 1011183646aSVineeth Pillai (struct hv_enlightenments *)vmcb->control.reserved_sw; 1021183646aSVineeth Pillai u32 vp_index = kvm_hv_get_vpindex(vcpu); 1031183646aSVineeth Pillai 1041183646aSVineeth Pillai if (hve->hv_vp_id != vp_index) { 1051183646aSVineeth Pillai hve->hv_vp_id = vp_index; 1061183646aSVineeth Pillai vmcb_mark_dirty(vmcb, VMCB_HV_NESTED_ENLIGHTENMENTS); 1071183646aSVineeth Pillai } 1081183646aSVineeth Pillai } 1091e0c7d40SVineeth Pillai #else 1101e0c7d40SVineeth Pillai 1111e0c7d40SVineeth Pillai static inline void svm_hv_init_vmcb(struct vmcb *vmcb) 1121e0c7d40SVineeth Pillai { 1131e0c7d40SVineeth Pillai } 1141e0c7d40SVineeth Pillai 1151e0c7d40SVineeth Pillai static inline void svm_hv_hardware_setup(void) 1161e0c7d40SVineeth Pillai { 1171e0c7d40SVineeth Pillai } 118c4327f15SVineeth Pillai 119c4327f15SVineeth Pillai static inline void svm_hv_vmcb_dirty_nested_enlightenments( 120c4327f15SVineeth Pillai struct kvm_vcpu *vcpu) 121c4327f15SVineeth Pillai { 122c4327f15SVineeth Pillai } 1231183646aSVineeth Pillai 1241183646aSVineeth Pillai static inline void svm_hv_update_vp_id(struct vmcb *vmcb, 1251183646aSVineeth Pillai struct kvm_vcpu *vcpu) 1261183646aSVineeth Pillai { 1271183646aSVineeth Pillai } 1281e0c7d40SVineeth Pillai #endif /* CONFIG_HYPERV */ 1291e0c7d40SVineeth Pillai 1301e0c7d40SVineeth Pillai #endif /* __ARCH_X86_KVM_SVM_ONHYPERV_H__ */ 131