>From eb126f1c02b418df0b5dce9e3cdbd984fc4b0611 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 13 Jun 2023 16:08:18 -0700 Subject: [PATCH 1/2] KVM: SVM: Don't defer NMI unblocking until next exit f= or SEV-ES guests Immediately mark NMIs as unmasked in response to #VMGEXIT(NMI complete) instead of setting awaiting_iret_completion and waiting until the *next* VM-Exit to unmask NMIs. The whole point of "NMI complete" is that the guest is responsible for telling the hypervisor when it's safe to inject an NMI, i.e. there's no need to wait. And because there's no IRET to single-step, the next VM-Exit could be a long time coming, i.e. KVM could incorrectly hold an NMI pending for far longer than what is required and expected. Opportunistically fix a stale reference to HF_IRET_MASK. Fixes: 4444dfe4050b ("KVM: SVM: Add NMI support for an SEV-ES guest") Cc: Tom Lendacky Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/sev.c | 5 ++++- arch/x86/kvm/svm/svm.c | 10 +++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index d65578d8784d..9a0e74cb6cb9 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -2887,7 +2887,10 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu) svm->sev_es.ghcb_sa); break; case SVM_VMGEXIT_NMI_COMPLETE: - ret =3D svm_invoke_exit_handler(vcpu, SVM_EXIT_IRET); + ++vcpu->stat.nmi_window_exits; + svm->nmi_masked =3D false; + kvm_make_request(KVM_REQ_EVENT, vcpu); + ret =3D 1; break; case SVM_VMGEXIT_AP_HLT_LOOP: ret =3D kvm_emulate_ap_reset_hold(vcpu); diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index b29d0650582e..b284706edde2 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -2508,12 +2508,13 @@ static int iret_interception(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm =3D to_svm(vcpu); =20 + WARN_ON_ONCE(sev_es_guest(vcpu->kvm)); + ++vcpu->stat.nmi_window_exits; svm->awaiting_iret_completion =3D true; =20 svm_clr_iret_intercept(svm); - if (!sev_es_guest(vcpu->kvm)) - svm->nmi_iret_rip =3D kvm_rip_read(vcpu); + svm->nmi_iret_rip =3D kvm_rip_read(vcpu); =20 kvm_make_request(KVM_REQ_EVENT, vcpu); return 1; @@ -3916,12 +3917,11 @@ static void svm_complete_interrupts(struct kvm_vcpu= *vcpu) svm->soft_int_injected =3D false; =20 /* - * If we've made progress since setting HF_IRET_MASK, we've + * If we've made progress since setting awaiting_iret_completion, we've * executed an IRET and can allow NMI injection. */ if (svm->awaiting_iret_completion && - (sev_es_guest(vcpu->kvm) || - kvm_rip_read(vcpu) !=3D svm->nmi_iret_rip)) { + kvm_rip_read(vcpu) !=3D svm->nmi_iret_rip) { svm->awaiting_iret_completion =3D false; svm->nmi_masked =3D false; kvm_make_request(KVM_REQ_EVENT, vcpu); base-commit: 5e74470e279654d9fa8742184c8c89837b899078 --=20 2.41.0.162.gfafddb0af9-goog