Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

KVM: x86: don't disable APICv memslot when inhibited

Thanks to the former patches, it is now possible to keep the APICv
memslot always enabled, and it will be invisible to the guest
when it is inhibited

This code is based on a suggestion from Sean Christopherson:
https://lkml.org/lkml/2021/7/19/2970

Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com>
Message-Id: <20210810205251.424103-9-mlevitsk@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

authored by

Maxim Levitsky and committed by
Paolo Bonzini
36222b11 9cc13d60

+14 -32
-1
arch/x86/include/asm/kvm-x86-ops.h
··· 72 72 KVM_X86_OP(enable_irq_window) 73 73 KVM_X86_OP(update_cr8_intercept) 74 74 KVM_X86_OP(check_apicv_inhibit_reasons) 75 - KVM_X86_OP_NULL(pre_update_apicv_exec_ctrl) 76 75 KVM_X86_OP(refresh_apicv_exec_ctrl) 77 76 KVM_X86_OP(hwapic_irr_update) 78 77 KVM_X86_OP(hwapic_isr_update)
-1
arch/x86/include/asm/kvm_host.h
··· 1352 1352 void (*enable_irq_window)(struct kvm_vcpu *vcpu); 1353 1353 void (*update_cr8_intercept)(struct kvm_vcpu *vcpu, int tpr, int irr); 1354 1354 bool (*check_apicv_inhibit_reasons)(ulong bit); 1355 - void (*pre_update_apicv_exec_ctrl)(struct kvm *kvm, bool activate); 1356 1355 void (*refresh_apicv_exec_ctrl)(struct kvm_vcpu *vcpu); 1357 1356 void (*hwapic_irr_update)(struct kvm_vcpu *vcpu, int max_irr); 1358 1357 void (*hwapic_isr_update)(struct kvm_vcpu *vcpu, int isr);
+6 -15
arch/x86/kvm/svm/avic.c
··· 225 225 * field of the VMCB. Therefore, we set up the 226 226 * APIC_ACCESS_PAGE_PRIVATE_MEMSLOT (4KB) here. 227 227 */ 228 - static int avic_update_access_page(struct kvm *kvm, bool activate) 228 + static int avic_alloc_access_page(struct kvm *kvm) 229 229 { 230 230 void __user *ret; 231 231 int r = 0; 232 232 233 233 mutex_lock(&kvm->slots_lock); 234 - /* 235 - * During kvm_destroy_vm(), kvm_pit_set_reinject() could trigger 236 - * APICv mode change, which update APIC_ACCESS_PAGE_PRIVATE_MEMSLOT 237 - * memory region. So, we need to ensure that kvm->mm == current->mm. 238 - */ 239 - if ((kvm->arch.apic_access_memslot_enabled == activate) || 240 - (kvm->mm != current->mm)) 234 + 235 + if (kvm->arch.apic_access_memslot_enabled) 241 236 goto out; 242 237 243 238 ret = __x86_set_memory_region(kvm, 244 239 APIC_ACCESS_PAGE_PRIVATE_MEMSLOT, 245 240 APIC_DEFAULT_PHYS_BASE, 246 - activate ? PAGE_SIZE : 0); 241 + PAGE_SIZE); 247 242 if (IS_ERR(ret)) { 248 243 r = PTR_ERR(ret); 249 244 goto out; 250 245 } 251 246 252 - kvm->arch.apic_access_memslot_enabled = activate; 247 + kvm->arch.apic_access_memslot_enabled = true; 253 248 out: 254 249 mutex_unlock(&kvm->slots_lock); 255 250 return r; ··· 265 270 if (kvm_apicv_activated(vcpu->kvm)) { 266 271 int ret; 267 272 268 - ret = avic_update_access_page(vcpu->kvm, true); 273 + ret = avic_alloc_access_page(vcpu->kvm); 269 274 if (ret) 270 275 return ret; 271 276 } ··· 913 918 return supported & BIT(bit); 914 919 } 915 920 916 - void svm_pre_update_apicv_exec_ctrl(struct kvm *kvm, bool activate) 917 - { 918 - avic_update_access_page(kvm, activate); 919 - } 920 921 921 922 static inline int 922 923 avic_update_iommu_vcpu_affinity(struct kvm_vcpu *vcpu, int cpu, bool r)
-1
arch/x86/kvm/svm/svm.c
··· 4581 4581 .set_virtual_apic_mode = svm_set_virtual_apic_mode, 4582 4582 .refresh_apicv_exec_ctrl = svm_refresh_apicv_exec_ctrl, 4583 4583 .check_apicv_inhibit_reasons = svm_check_apicv_inhibit_reasons, 4584 - .pre_update_apicv_exec_ctrl = svm_pre_update_apicv_exec_ctrl, 4585 4584 .load_eoi_exitmap = svm_load_eoi_exitmap, 4586 4585 .hwapic_irr_update = svm_hwapic_irr_update, 4587 4586 .hwapic_isr_update = svm_hwapic_isr_update,
-1
arch/x86/kvm/svm/svm.h
··· 534 534 void svm_set_virtual_apic_mode(struct kvm_vcpu *vcpu); 535 535 void svm_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu); 536 536 bool svm_check_apicv_inhibit_reasons(ulong bit); 537 - void svm_pre_update_apicv_exec_ctrl(struct kvm *kvm, bool activate); 538 537 void svm_load_eoi_exitmap(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap); 539 538 void svm_hwapic_irr_update(struct kvm_vcpu *vcpu, int max_irr); 540 539 void svm_hwapic_isr_update(struct kvm_vcpu *vcpu, int max_isr);
+8 -13
arch/x86/kvm/x86.c
··· 9255 9255 } 9256 9256 EXPORT_SYMBOL_GPL(kvm_vcpu_update_apicv); 9257 9257 9258 - /* 9259 - * NOTE: Do not hold any lock prior to calling this. 9260 - * 9261 - * In particular, kvm_request_apicv_update() expects kvm->srcu not to be 9262 - * locked, because it calls __x86_set_memory_region() which does 9263 - * synchronize_srcu(&kvm->srcu). 9264 - */ 9265 9258 void kvm_request_apicv_update(struct kvm *kvm, bool activate, ulong bit) 9266 9259 { 9267 9260 unsigned long old, new, expected; ··· 9275 9282 old = cmpxchg(&kvm->arch.apicv_inhibit_reasons, expected, new); 9276 9283 } while (old != expected); 9277 9284 9278 - if (!!old == !!new) 9279 - return; 9285 + if (!!old != !!new) { 9286 + trace_kvm_apicv_update_request(activate, bit); 9287 + kvm_make_all_cpus_request(kvm, KVM_REQ_APICV_UPDATE); 9288 + if (new) { 9289 + unsigned long gfn = gpa_to_gfn(APIC_DEFAULT_PHYS_BASE); 9280 9290 9281 - trace_kvm_apicv_update_request(activate, bit); 9282 - if (kvm_x86_ops.pre_update_apicv_exec_ctrl) 9283 - static_call(kvm_x86_pre_update_apicv_exec_ctrl)(kvm, activate); 9291 + kvm_zap_gfn_range(kvm, gfn, gfn+1); 9292 + } 9293 + } 9284 9294 9285 - kvm_make_all_cpus_request(kvm, KVM_REQ_APICV_UPDATE); 9286 9295 } 9287 9296 EXPORT_SYMBOL_GPL(kvm_request_apicv_update); 9288 9297