Skip to content

Commit 7c69661

Browse files
sean-jcbonzini
authored andcommitted
KVM: nVMX: Defer APICv updates while L2 is active until L1 is active
Defer APICv updates that occur while L2 is active until nested VM-Exit, i.e. until L1 regains control. vmx_refresh_apicv_exec_ctrl() assumes L1 is active and (a) stomps all over vmcs02 and (b) neglects to ever updated vmcs01. E.g. if vmcs12 doesn't enable the TPR shadow for L2 (and thus no APICv controls), L1 performs nested VM-Enter APICv inhibited, and APICv becomes unhibited while L2 is active, KVM will set various APICv controls in vmcs02 and trigger a failed VM-Entry. The kicker is that, unless running with nested_early_check=1, KVM blames L1 and chaos ensues. In all cases, ignoring vmcs02 and always deferring the inhibition change to vmcs01 is correct (or at least acceptable). The ABSENT and DISABLE inhibitions cannot truly change while L2 is active (see below). IRQ_BLOCKING can change, but it is firmly a best effort debug feature. Furthermore, only L2's APIC is accelerated/virtualized to the full extent possible, e.g. even if L1 passes through its APIC to L2, normal MMIO/MSR interception will apply to the virtual APIC managed by KVM. The exception is the SELF_IPI register when x2APIC is enabled, but that's an acceptable hole. Lastly, Hyper-V's Auto EOI can technically be toggled if L1 exposes the MSRs to L2, but for that to work in any sane capacity, L1 would need to pass through IRQs to L2 as well, and IRQs must be intercepted to enable virtual interrupt delivery. I.e. exposing Auto EOI to L2 and enabling VID for L2 are, for all intents and purposes, mutually exclusive. Lack of dynamic toggling is also why this scenario is all but impossible to encounter in KVM's current form. But a future patch will pend an APICv update request _during_ vCPU creation to plug a race where a vCPU that's being created doesn't get included in the "all vCPUs request" because it's not yet visible to other vCPUs. If userspaces restores L2 after VM creation (hello, KVM selftests), the first KVM_RUN will occur while L2 is active and thus service the APICv update request made during VM creation. Cc: stable@vger.kernel.org Signed-off-by: Sean Christopherson <seanjc@google.com> Message-Id: <20220420013732.3308816-3-seanjc@google.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
1 parent 80f0497 commit 7c69661

File tree

3 files changed

+11
-0
lines changed

3 files changed

+11
-0
lines changed

arch/x86/kvm/vmx/nested.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4618,6 +4618,11 @@ void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason,
46184618
kvm_make_request(KVM_REQ_APIC_PAGE_RELOAD, vcpu);
46194619
}
46204620

4621+
if (vmx->nested.update_vmcs01_apicv_status) {
4622+
vmx->nested.update_vmcs01_apicv_status = false;
4623+
kvm_make_request(KVM_REQ_APICV_UPDATE, vcpu);
4624+
}
4625+
46214626
if ((vm_exit_reason != -1) &&
46224627
(enable_shadow_vmcs || evmptr_is_valid(vmx->nested.hv_evmcs_vmptr)))
46234628
vmx->nested.need_vmcs12_to_shadow_sync = true;

arch/x86/kvm/vmx/vmx.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4174,6 +4174,11 @@ static void vmx_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu)
41744174
{
41754175
struct vcpu_vmx *vmx = to_vmx(vcpu);
41764176

4177+
if (is_guest_mode(vcpu)) {
4178+
vmx->nested.update_vmcs01_apicv_status = true;
4179+
return;
4180+
}
4181+
41774182
pin_controls_set(vmx, vmx_pin_based_exec_ctrl(vmx));
41784183
if (cpu_has_secondary_exec_ctrls()) {
41794184
if (kvm_vcpu_apicv_active(vcpu))

arch/x86/kvm/vmx/vmx.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ struct nested_vmx {
183183
bool change_vmcs01_virtual_apic_mode;
184184
bool reload_vmcs01_apic_access_page;
185185
bool update_vmcs01_cpu_dirty_logging;
186+
bool update_vmcs01_apicv_status;
186187

187188
/*
188189
* Enlightened VMCS has been enabled. It does not mean that L1 has to

0 commit comments

Comments
 (0)