Skip to content

Commit 4c4a6f7

Browse files
bonzinirkrcmar
authored andcommitted
KVM: nVMX: track NMI blocking state separately for each VMCS
vmx_recover_nmi_blocking is using a cached value of the guest interruptibility info, which is stored in vmx->nmi_known_unmasked. vmx_recover_nmi_blocking is run for both normal and nested guests, so the cached value must be per-VMCS. This fixes eventinj.flat in a nested non-EPT environment. With EPT it works, because the EPT violation handler doesn't have the vmx->nmi_known_unmasked optimization (it is unnecessary because, unlike vmx_recover_nmi_blocking, it can just look at the exit qualification). Thanks to Wanpeng Li for debugging the testcase and providing an initial patch. Signed-off-by: Paolo Bonzini <[email protected]> Signed-off-by: Radim Krčmář <[email protected]>
1 parent f85c758 commit 4c4a6f7

File tree

1 file changed

+14
-10
lines changed

1 file changed

+14
-10
lines changed

arch/x86/kvm/vmx.c

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,8 @@ struct loaded_vmcs {
198198
struct vmcs *vmcs;
199199
struct vmcs *shadow_vmcs;
200200
int cpu;
201-
int launched;
201+
bool launched;
202+
bool nmi_known_unmasked;
202203
struct list_head loaded_vmcss_on_cpu_link;
203204
};
204205

@@ -5510,10 +5511,8 @@ static void vmx_inject_nmi(struct kvm_vcpu *vcpu)
55105511
{
55115512
struct vcpu_vmx *vmx = to_vmx(vcpu);
55125513

5513-
if (!is_guest_mode(vcpu)) {
5514-
++vcpu->stat.nmi_injections;
5515-
vmx->nmi_known_unmasked = false;
5516-
}
5514+
++vcpu->stat.nmi_injections;
5515+
vmx->loaded_vmcs->nmi_known_unmasked = false;
55175516

55185517
if (vmx->rmode.vm86_active) {
55195518
if (kvm_inject_realmode_interrupt(vcpu, NMI_VECTOR, 0) != EMULATE_DONE)
@@ -5527,16 +5526,21 @@ static void vmx_inject_nmi(struct kvm_vcpu *vcpu)
55275526

55285527
static bool vmx_get_nmi_mask(struct kvm_vcpu *vcpu)
55295528
{
5530-
if (to_vmx(vcpu)->nmi_known_unmasked)
5529+
struct vcpu_vmx *vmx = to_vmx(vcpu);
5530+
bool masked;
5531+
5532+
if (vmx->loaded_vmcs->nmi_known_unmasked)
55315533
return false;
5532-
return vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & GUEST_INTR_STATE_NMI;
5534+
masked = vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & GUEST_INTR_STATE_NMI;
5535+
vmx->loaded_vmcs->nmi_known_unmasked = !masked;
5536+
return masked;
55335537
}
55345538

55355539
static void vmx_set_nmi_mask(struct kvm_vcpu *vcpu, bool masked)
55365540
{
55375541
struct vcpu_vmx *vmx = to_vmx(vcpu);
55385542

5539-
vmx->nmi_known_unmasked = !masked;
5543+
vmx->loaded_vmcs->nmi_known_unmasked = !masked;
55405544
if (masked)
55415545
vmcs_set_bits(GUEST_INTERRUPTIBILITY_INFO,
55425546
GUEST_INTR_STATE_NMI);
@@ -8736,7 +8740,7 @@ static void vmx_recover_nmi_blocking(struct vcpu_vmx *vmx)
87368740

87378741
idtv_info_valid = vmx->idt_vectoring_info & VECTORING_INFO_VALID_MASK;
87388742

8739-
if (vmx->nmi_known_unmasked)
8743+
if (vmx->loaded_vmcs->nmi_known_unmasked)
87408744
return;
87418745
/*
87428746
* Can't use vmx->exit_intr_info since we're not sure what
@@ -8760,7 +8764,7 @@ static void vmx_recover_nmi_blocking(struct vcpu_vmx *vmx)
87608764
vmcs_set_bits(GUEST_INTERRUPTIBILITY_INFO,
87618765
GUEST_INTR_STATE_NMI);
87628766
else
8763-
vmx->nmi_known_unmasked =
8767+
vmx->loaded_vmcs->nmi_known_unmasked =
87648768
!(vmcs_read32(GUEST_INTERRUPTIBILITY_INFO)
87658769
& GUEST_INTR_STATE_NMI);
87668770
}

0 commit comments

Comments
 (0)