Skip to content

Commit 3e013d0

Browse files
committed
KVM: nVMX: Switch to vmcs01 to update PML controls on-demand if L2 is active
If KVM toggles "CPU dirty logging", a.k.a. Page-Modification Logging (PML), while L2 is active, temporarily load vmcs01 and immediately update the relevant controls instead of deferring the update until the next nested VM-Exit. For PML, deferring the update is relatively straightforward, but for several APICv related updates, deferring updates creates ordering and state consistency problems, e.g. KVM at-large thinks APICv is enabled, but vmcs01 is still running with stale (and effectively unknown) state. Convert PML first precisely because it's the simplest case to handle: if something is broken with the vmcs01 <=> vmcs02 dance, then hopefully bugs will bisect here. Reviewed-by: Chao Gao <chao.gao@intel.com> Link: https://patch.msgid.link/20260109034532.1012993-3-seanjc@google.com Signed-off-by: Sean Christopherson <seanjc@google.com>
1 parent c3a9a27 commit 3e013d0

3 files changed

Lines changed: 36 additions & 10 deletions

File tree

arch/x86/kvm/vmx/nested.c

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5131,11 +5131,6 @@ void __nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason,
51315131
vmx_set_virtual_apic_mode(vcpu);
51325132
}
51335133

5134-
if (vmx->nested.update_vmcs01_cpu_dirty_logging) {
5135-
vmx->nested.update_vmcs01_cpu_dirty_logging = false;
5136-
vmx_update_cpu_dirty_logging(vcpu);
5137-
}
5138-
51395134
nested_put_vmcs12_pages(vcpu);
51405135

51415136
if (vmx->nested.reload_vmcs01_apic_access_page) {

arch/x86/kvm/vmx/vmx.c

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1594,6 +1594,41 @@ void vmx_vcpu_put(struct kvm_vcpu *vcpu)
15941594
vmx_prepare_switch_to_host(to_vmx(vcpu));
15951595
}
15961596

1597+
static void vmx_switch_loaded_vmcs(struct kvm_vcpu *vcpu,
1598+
struct loaded_vmcs *vmcs)
1599+
{
1600+
struct vcpu_vmx *vmx = to_vmx(vcpu);
1601+
int cpu;
1602+
1603+
cpu = get_cpu();
1604+
vmx->loaded_vmcs = vmcs;
1605+
vmx_vcpu_load_vmcs(vcpu, cpu);
1606+
put_cpu();
1607+
}
1608+
1609+
static void vmx_load_vmcs01(struct kvm_vcpu *vcpu)
1610+
{
1611+
struct vcpu_vmx *vmx = to_vmx(vcpu);
1612+
1613+
if (!is_guest_mode(vcpu)) {
1614+
WARN_ON_ONCE(vmx->loaded_vmcs != &vmx->vmcs01);
1615+
return;
1616+
}
1617+
1618+
WARN_ON_ONCE(vmx->loaded_vmcs != &vmx->nested.vmcs02);
1619+
vmx_switch_loaded_vmcs(vcpu, &vmx->vmcs01);
1620+
}
1621+
1622+
static void vmx_put_vmcs01(struct kvm_vcpu *vcpu)
1623+
{
1624+
if (!is_guest_mode(vcpu))
1625+
return;
1626+
1627+
vmx_switch_loaded_vmcs(vcpu, &to_vmx(vcpu)->nested.vmcs02);
1628+
}
1629+
DEFINE_GUARD(vmx_vmcs01, struct kvm_vcpu *,
1630+
vmx_load_vmcs01(_T), vmx_put_vmcs01(_T))
1631+
15971632
bool vmx_emulation_required(struct kvm_vcpu *vcpu)
15981633
{
15991634
return emulate_invalid_guest_state && !vmx_guest_state_valid(vcpu);
@@ -8276,10 +8311,7 @@ void vmx_update_cpu_dirty_logging(struct kvm_vcpu *vcpu)
82768311
if (WARN_ON_ONCE(!enable_pml))
82778312
return;
82788313

8279-
if (is_guest_mode(vcpu)) {
8280-
vmx->nested.update_vmcs01_cpu_dirty_logging = true;
8281-
return;
8282-
}
8314+
guard(vmx_vmcs01)(vcpu);
82838315

82848316
/*
82858317
* Note, nr_memslots_dirty_logging can be changed concurrent with this

arch/x86/kvm/vmx/vmx.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,6 @@ struct nested_vmx {
133133

134134
bool change_vmcs01_virtual_apic_mode;
135135
bool reload_vmcs01_apic_access_page;
136-
bool update_vmcs01_cpu_dirty_logging;
137136
bool update_vmcs01_apicv_status;
138137
bool update_vmcs01_hwapic_isr;
139138

0 commit comments

Comments
 (0)