Skip to content

Commit 389fbbe

Browse files
committed
KVM: SVM: Don't defer NMI unblocking until next exit for 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: 916b54a ("KVM: x86: Move HF_NMI_MASK and HF_IRET_MASK into "struct vcpu_svm"") Fixes: 4444dfe ("KVM: SVM: Add NMI support for an SEV-ES guest") Cc: Tom Lendacky <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Sean Christopherson <[email protected]>
1 parent 90cbf6d commit 389fbbe

File tree

2 files changed

+9
-6
lines changed

2 files changed

+9
-6
lines changed

arch/x86/kvm/svm/sev.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2900,7 +2900,10 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu)
29002900
svm->sev_es.ghcb_sa);
29012901
break;
29022902
case SVM_VMGEXIT_NMI_COMPLETE:
2903-
ret = svm_invoke_exit_handler(vcpu, SVM_EXIT_IRET);
2903+
++vcpu->stat.nmi_window_exits;
2904+
svm->nmi_masked = false;
2905+
kvm_make_request(KVM_REQ_EVENT, vcpu);
2906+
ret = 1;
29042907
break;
29052908
case SVM_VMGEXIT_AP_HLT_LOOP:
29062909
ret = kvm_emulate_ap_reset_hold(vcpu);

arch/x86/kvm/svm/svm.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2535,12 +2535,13 @@ static int iret_interception(struct kvm_vcpu *vcpu)
25352535
{
25362536
struct vcpu_svm *svm = to_svm(vcpu);
25372537

2538+
WARN_ON_ONCE(sev_es_guest(vcpu->kvm));
2539+
25382540
++vcpu->stat.nmi_window_exits;
25392541
svm->awaiting_iret_completion = true;
25402542

25412543
svm_clr_iret_intercept(svm);
2542-
if (!sev_es_guest(vcpu->kvm))
2543-
svm->nmi_iret_rip = kvm_rip_read(vcpu);
2544+
svm->nmi_iret_rip = kvm_rip_read(vcpu);
25442545

25452546
kvm_make_request(KVM_REQ_EVENT, vcpu);
25462547
return 1;
@@ -3950,12 +3951,11 @@ static void svm_complete_interrupts(struct kvm_vcpu *vcpu)
39503951
svm->soft_int_injected = false;
39513952

39523953
/*
3953-
* If we've made progress since setting HF_IRET_MASK, we've
3954+
* If we've made progress since setting awaiting_iret_completion, we've
39543955
* executed an IRET and can allow NMI injection.
39553956
*/
39563957
if (svm->awaiting_iret_completion &&
3957-
(sev_es_guest(vcpu->kvm) ||
3958-
kvm_rip_read(vcpu) != svm->nmi_iret_rip)) {
3958+
kvm_rip_read(vcpu) != svm->nmi_iret_rip) {
39593959
svm->awaiting_iret_completion = false;
39603960
svm->nmi_masked = false;
39613961
kvm_make_request(KVM_REQ_EVENT, vcpu);

0 commit comments

Comments
 (0)