Merge tag 'kvm-x86-generic-7.3' of https://github.com/kvm-x86/linux into HEAD

KVM arch-neutral and documentation changes for 7.3

 - Remove kvm_debugfs_dir if kvm_init() fails after creating KVM's debugfs.

 - Document some of the "fun" gotchas with the APIC base when creating IRQCHIPs
   on x86.

 - Add a per-VM bitmap to track which vCPU IDs have been "claimed" but for
   which the vCPU isn't yet online, and use the bitmap to reject duplicate IDs
   before calling into arch code.  This allows arch code to consume vcpu_id
   without having to worry about cross-vCPU clobbering (at least s390 and x86
   have had related bugs).

 - Zero a vCPU's entry in VMX's Posted Interrupt Descriptor table used for IPI
   virtualization when the vCPU is freed to fix a use-after-free where hardware
   will write to a freed vCPU's PID.
This commit is contained in:
Paolo Bonzini
2026-08-18 13:13:25 +02:00
4 changed files with 27 additions and 2 deletions
+14 -1
View File
@@ -856,12 +856,21 @@ Writes the floating point state to the vcpu.
Creates an interrupt controller model in the kernel.
On x86, creates a virtual ioapic, a virtual PIC (two PICs, nested), and sets up
future vcpus to have a local APIC. IRQ routing for GSIs 0-15 is set to both
PIC and IOAPIC; GSI 16-23 only go to the IOAPIC.
PIC and IOAPIC; GSI 16-23 only go to the IOAPIC. This ioctl can only be
called before creating any vcpus.
On arm64, a GICv2 is created. Any other GIC versions require the usage of
KVM_CREATE_DEVICE, which also supports creating a GICv2. Using
KVM_CREATE_DEVICE is preferred over KVM_CREATE_IRQCHIP for GICv2.
On s390, a dummy irq routing table is created.
On x86, subsequent vcpu creation may install a private 4 KiB memory slot at the
default APIC base address (0xfee00000). User memory regions must not overlap
this address; doing so will cause vcpu creation to fail with ``EEXIST``, or the
memory region to be rejected if created after the vcpu. This occurs when
APIC access acceleration is enabled (APICv on Intel, AVIC on AMD), which is
the default on supported hardware. The same constraint applies when using
``KVM_CAP_SPLIT_IRQCHIP``.
Note that on s390 the KVM_CAP_S390_IRQCHIP vm capability needs to be enabled
before KVM_CREATE_IRQCHIP can be used.
@@ -7933,6 +7942,10 @@ used in the IRQ routing table. The first args[0] MSI routes are reserved
for the IOAPIC pins. Whenever the LAPIC receives an EOI for these routes,
a KVM_EXIT_IOAPIC_EOI vmexit will be reported to userspace.
As with ``KVM_CREATE_IRQCHIP``, subsequent vcpu creation may install a private
memory slot at the APIC base address (0xfee00000) that must not overlap user
memory regions. See ``KVM_CREATE_IRQCHIP`` for details.
Fails if VCPU has already been created, or if the irqchip is already in the
kernel (i.e. KVM_CREATE_IRQCHIP has already been called).
+3
View File
@@ -7681,6 +7681,9 @@ void vmx_vcpu_free(struct kvm_vcpu *vcpu)
nested_vmx_free_vcpu(vcpu);
free_loaded_vmcs(vmx->loaded_vmcs);
free_page((unsigned long)vmx->ve_info);
if (vmx_can_use_ipiv(vcpu))
WRITE_ONCE(to_kvm_vmx(vcpu->kvm)->pid_table[vcpu->vcpu_id], 0);
}
int vmx_vcpu_create(struct kvm_vcpu *vcpu)
+1
View File
@@ -791,6 +791,7 @@ struct kvm {
/* The current active memslot set for each address space */
struct kvm_memslots __rcu *memslots[KVM_MAX_NR_ADDRESS_SPACES];
struct xarray vcpu_array;
DECLARE_BITMAP(vcpu_ids, KVM_MAX_VCPU_IDS);
/*
* Protected by slots_lock, but can be read outside if an
* incorrect answer is acceptable.
+9 -1
View File
@@ -4174,6 +4174,11 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, unsigned long id)
return -EINVAL;
}
if (test_bit(id, kvm->vcpu_ids)) {
mutex_unlock(&kvm->lock);
return -EEXIST;
}
r = kvm_arch_vcpu_precreate(kvm, id);
if (r) {
mutex_unlock(&kvm->lock);
@@ -4181,6 +4186,7 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, unsigned long id)
}
kvm->created_vcpus++;
__set_bit(id, kvm->vcpu_ids);
mutex_unlock(&kvm->lock);
vcpu = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL_ACCOUNT);
@@ -4212,7 +4218,7 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, unsigned long id)
mutex_lock(&kvm->lock);
if (kvm_get_vcpu_by_id(kvm, id)) {
if (WARN_ON_ONCE(kvm_get_vcpu_by_id(kvm, id))) {
r = -EEXIST;
goto unlock_vcpu_destroy;
}
@@ -4266,6 +4272,7 @@ vcpu_free:
vcpu_decrement:
mutex_lock(&kvm->lock);
kvm->created_vcpus--;
__clear_bit(id, kvm->vcpu_ids);
mutex_unlock(&kvm->lock);
return r;
}
@@ -6554,6 +6561,7 @@ err_virt:
err_gmem:
kvm_vfio_ops_exit();
err_vfio:
debugfs_remove_recursive(kvm_debugfs_dir);
kvm_async_pf_deinit();
err_async_pf:
kvm_irqfd_exit();