[PATCH 12/16] KVM: VMX: Leave the IPIv PID-table entry to the plane 0 vCPU

From: David Woodhouse

Date: Wed Nov 11 2026 - 17:33:28 EST


From: David Woodhouse <dwmw@xxxxxxxxxxxx>

The IPI virtualization PID table is indexed by vCPU ID, and a plane
vCPU has the same vCPU ID as its plane 0 twin. vmx_vcpu_create() for a
twin therefore repoints plane 0's entry at the twin's posted-interrupt
descriptor, and vmx_vcpu_free() for a twin (including the error path
of a failed KVM_CREATE_VCPU on a plane fd) clears it. Plane 0 is left
with no valid entry, or one naming a freed descriptor.

Nothing consumes the table while that is the case today: a VM with
planes has APICv inhibited, so IPIv stays off. But the entry must not
depend on that. Fill and clear it for the plane 0 vCPU only.

Fixes the IPIv PID-table handling for the plane vCPUs that "KVM:
Implement KVM_CREATE_VCPU ioctl for planes" creates.

Fixes: https://lore.kernel.org/all/20260608144252.351443-34-joro@xxxxxxxxxx/
Signed-off-by: David Woodhouse <dwmw@xxxxxxxxxxxx>
---
arch/x86/kvm/vmx/vmx.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 44d0e8eba45b..591c7745e3e9 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -7525,7 +7525,8 @@ void vmx_vcpu_free(struct kvm_vcpu *vcpu)
free_loaded_vmcs(vmx->loaded_vmcs);
free_page((unsigned long)vmx->ve_info);

- if (vmx_can_use_ipiv(vcpu))
+ /* See vmx_vcpu_create(): only the plane 0 vCPU owns the entry. */
+ if (vmx_can_use_ipiv(vcpu) && !vcpu->plane_level)
WRITE_ONCE(to_kvm_vmx(vcpu->kvm)->pid_table[vcpu->vcpu_id], 0);
}

@@ -7614,7 +7615,12 @@ int vmx_vcpu_create(struct kvm_vcpu *vcpu)
vmx->ve_info = page_to_virt(page);
}

- if (vmx_can_use_ipiv(vcpu))
+ /*
+ * The PID table is indexed by vCPU ID, which a plane vCPU shares
+ * with its plane 0 twin: only plane 0 fills the entry, or creating
+ * (and freeing) a twin would repoint (and clear) plane 0's.
+ */
+ if (vmx_can_use_ipiv(vcpu) && !vcpu->plane_level)
WRITE_ONCE(to_kvm_vmx(vcpu->kvm)->pid_table[vcpu->vcpu_id],
__pa(&vmx->vt.pi_desc) | PID_TABLE_ENTRY_VALID);

--
2.50.1