Skip to content

Commit 49df639

Browse files
stevenrutherfordbonzini
authored andcommitted
KVM: x86: Split the APIC from the rest of IRQCHIP.
First patch in a series which enables the relocation of the PIC/IOAPIC to userspace. Adds capability KVM_CAP_SPLIT_IRQCHIP; KVM_CAP_SPLIT_IRQCHIP enables the construction of LAPICs without the rest of the irqchip. Compile tested for x86. Signed-off-by: Steve Rutherford <srutherford@google.com> Suggested-by: Andrew Honig <ahonig@google.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
1 parent 4ca7dd8 commit 49df639

File tree

10 files changed

+75
-7
lines changed

10 files changed

+75
-7
lines changed

Documentation/virtual/kvm/api.txt

+17
Original file line numberDiff line numberDiff line change
@@ -3627,6 +3627,23 @@ struct {
36273627

36283628
KVM handlers should exit to userspace with rc = -EREMOTE.
36293629

3630+
7.5 KVM_CAP_SPLIT_IRQCHIP
3631+
3632+
Architectures: x86
3633+
Parameters: None
3634+
Returns: 0 on success, -1 on error
3635+
3636+
Create a local apic for each processor in the kernel. This can be used
3637+
instead of KVM_CREATE_IRQCHIP if the userspace VMM wishes to emulate the
3638+
IOAPIC and PIC (and also the PIT, even though this has to be enabled
3639+
separately).
3640+
3641+
This supersedes KVM_CREATE_IRQCHIP, creating only local APICs, but no in kernel
3642+
IOAPIC or PIC. This also enables in kernel routing of interrupt requests.
3643+
3644+
Fails if VCPU has already been created, or if the irqchip is already in the
3645+
kernel (i.e. KVM_CREATE_IRQCHIP has already been called).
3646+
36303647

36313648
8. Other capabilities.
36323649
----------------------

arch/x86/include/asm/kvm_host.h

+2
Original file line numberDiff line numberDiff line change
@@ -684,6 +684,8 @@ struct kvm_arch {
684684
u32 bsp_vcpu_id;
685685

686686
u64 disabled_quirks;
687+
688+
bool irqchip_split;
687689
};
688690

689691
struct kvm_vm_stat {

arch/x86/kvm/i8254.c

+3-1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include <linux/kvm_host.h>
3636
#include <linux/slab.h>
3737

38+
#include "ioapic.h"
3839
#include "irq.h"
3940
#include "i8254.h"
4041
#include "x86.h"
@@ -333,7 +334,8 @@ static void create_pit_timer(struct kvm *kvm, u32 val, int is_period)
333334
struct kvm_kpit_state *ps = &kvm->arch.vpit->pit_state;
334335
s64 interval;
335336

336-
if (!irqchip_in_kernel(kvm) || ps->flags & KVM_PIT_FLAGS_HPET_LEGACY)
337+
if (!ioapic_in_kernel(kvm) ||
338+
ps->flags & KVM_PIT_FLAGS_HPET_LEGACY)
337339
return;
338340

339341
interval = muldiv64(val, NSEC_PER_SEC, KVM_PIT_FREQ);

arch/x86/kvm/ioapic.h

+8
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,14 @@ static inline struct kvm_ioapic *ioapic_irqchip(struct kvm *kvm)
9797
return kvm->arch.vioapic;
9898
}
9999

100+
static inline int ioapic_in_kernel(struct kvm *kvm)
101+
{
102+
int ret;
103+
104+
ret = (ioapic_irqchip(kvm) != NULL);
105+
return ret;
106+
}
107+
100108
void kvm_rtc_eoi_tracking_restore_one(struct kvm_vcpu *vcpu);
101109
bool kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source,
102110
int short_hand, unsigned int dest, int dest_mode);

arch/x86/kvm/irq.h

+10-1
Original file line numberDiff line numberDiff line change
@@ -83,13 +83,22 @@ static inline struct kvm_pic *pic_irqchip(struct kvm *kvm)
8383
return kvm->arch.vpic;
8484
}
8585

86+
static inline int irqchip_split(struct kvm *kvm)
87+
{
88+
return kvm->arch.irqchip_split;
89+
}
90+
8691
static inline int irqchip_in_kernel(struct kvm *kvm)
8792
{
8893
struct kvm_pic *vpic = pic_irqchip(kvm);
94+
bool ret;
95+
96+
ret = (vpic != NULL);
97+
ret |= irqchip_split(kvm);
8998

9099
/* Read vpic before kvm->irq_routing. */
91100
smp_rmb();
92-
return vpic != NULL;
101+
return ret;
93102
}
94103

95104
static inline int lapic_in_kernel(struct kvm_vcpu *vcpu)

arch/x86/kvm/irq_comm.c

+8-1
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ void kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id)
208208
goto unlock;
209209
}
210210
clear_bit(irq_source_id, &kvm->arch.irq_sources_bitmap);
211-
if (!irqchip_in_kernel(kvm))
211+
if (!ioapic_in_kernel(kvm))
212212
goto unlock;
213213

214214
kvm_ioapic_clear_all(kvm->arch.vioapic, irq_source_id);
@@ -328,3 +328,10 @@ int kvm_setup_default_irq_routing(struct kvm *kvm)
328328
return kvm_set_irq_routing(kvm, default_routing,
329329
ARRAY_SIZE(default_routing), 0);
330330
}
331+
332+
static const struct kvm_irq_routing_entry empty_routing[] = {};
333+
334+
int kvm_setup_empty_irq_routing(struct kvm *kvm)
335+
{
336+
return kvm_set_irq_routing(kvm, empty_routing, 0, 0);
337+
}

arch/x86/kvm/lapic.c

+4-2
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,8 @@ static void recalculate_apic_map(struct kvm *kvm)
209209
if (old)
210210
kfree_rcu(old, rcu);
211211

212-
kvm_vcpu_request_scan_ioapic(kvm);
212+
if (ioapic_in_kernel(kvm))
213+
kvm_vcpu_request_scan_ioapic(kvm);
213214
}
214215

215216
static inline void apic_set_spiv(struct kvm_lapic *apic, u32 val)
@@ -1845,7 +1846,8 @@ void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu,
18451846
kvm_x86_ops->hwapic_isr_update(vcpu->kvm,
18461847
apic_find_highest_isr(apic));
18471848
kvm_make_request(KVM_REQ_EVENT, vcpu);
1848-
kvm_rtc_eoi_tracking_restore_one(vcpu);
1849+
if (ioapic_in_kernel(vcpu->kvm))
1850+
kvm_rtc_eoi_tracking_restore_one(vcpu);
18491851
}
18501852

18511853
void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu)

arch/x86/kvm/x86.c

+21-2
Original file line numberDiff line numberDiff line change
@@ -2448,6 +2448,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
24482448
case KVM_CAP_ENABLE_CAP_VM:
24492449
case KVM_CAP_DISABLE_QUIRKS:
24502450
case KVM_CAP_SET_BOOT_CPU_ID:
2451+
case KVM_CAP_SPLIT_IRQCHIP:
24512452
#ifdef CONFIG_KVM_DEVICE_ASSIGNMENT
24522453
case KVM_CAP_ASSIGN_DEV_IRQ:
24532454
case KVM_CAP_PCI_2_3:
@@ -3555,6 +3556,24 @@ static int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
35553556
kvm->arch.disabled_quirks = cap->args[0];
35563557
r = 0;
35573558
break;
3559+
case KVM_CAP_SPLIT_IRQCHIP: {
3560+
mutex_lock(&kvm->lock);
3561+
r = -EEXIST;
3562+
if (irqchip_in_kernel(kvm))
3563+
goto split_irqchip_unlock;
3564+
if (atomic_read(&kvm->online_vcpus))
3565+
goto split_irqchip_unlock;
3566+
r = kvm_setup_empty_irq_routing(kvm);
3567+
if (r)
3568+
goto split_irqchip_unlock;
3569+
/* Pairs with irqchip_in_kernel. */
3570+
smp_wmb();
3571+
kvm->arch.irqchip_split = true;
3572+
r = 0;
3573+
split_irqchip_unlock:
3574+
mutex_unlock(&kvm->lock);
3575+
break;
3576+
}
35583577
default:
35593578
r = -EINVAL;
35603579
break;
@@ -3668,7 +3687,7 @@ long kvm_arch_vm_ioctl(struct file *filp,
36683687
}
36693688

36703689
r = -ENXIO;
3671-
if (!irqchip_in_kernel(kvm))
3690+
if (!irqchip_in_kernel(kvm) || irqchip_split(kvm))
36723691
goto get_irqchip_out;
36733692
r = kvm_vm_ioctl_get_irqchip(kvm, chip);
36743693
if (r)
@@ -3692,7 +3711,7 @@ long kvm_arch_vm_ioctl(struct file *filp,
36923711
}
36933712

36943713
r = -ENXIO;
3695-
if (!irqchip_in_kernel(kvm))
3714+
if (!irqchip_in_kernel(kvm) || irqchip_split(kvm))
36963715
goto set_irqchip_out;
36973716
r = kvm_vm_ioctl_set_irqchip(kvm, chip);
36983717
if (r)

include/linux/kvm_host.h

+1
Original file line numberDiff line numberDiff line change
@@ -1002,6 +1002,7 @@ static inline int mmu_notifier_retry(struct kvm *kvm, unsigned long mmu_seq)
10021002
#endif
10031003

10041004
int kvm_setup_default_irq_routing(struct kvm *kvm);
1005+
int kvm_setup_empty_irq_routing(struct kvm *kvm);
10051006
int kvm_set_irq_routing(struct kvm *kvm,
10061007
const struct kvm_irq_routing_entry *entries,
10071008
unsigned nr,

include/uapi/linux/kvm.h

+1
Original file line numberDiff line numberDiff line change
@@ -824,6 +824,7 @@ struct kvm_ppc_smmu_info {
824824
#define KVM_CAP_MULTI_ADDRESS_SPACE 118
825825
#define KVM_CAP_GUEST_DEBUG_HW_BPS 119
826826
#define KVM_CAP_GUEST_DEBUG_HW_WPS 120
827+
#define KVM_CAP_SPLIT_IRQCHIP 121
827828

828829
#ifdef KVM_CAP_IRQ_ROUTING
829830

0 commit comments

Comments
 (0)