summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile14
-rw-r--r--kvm.c438
-rw-r--r--kvm_irq.c33
-rw-r--r--kvm_irq_comm.c554
-rw-r--r--kvm_x86.c45
5 files changed, 563 insertions, 521 deletions
diff --git a/Makefile b/Makefile
index e9994c8..9c51696 100644
--- a/Makefile
+++ b/Makefile
@@ -16,7 +16,7 @@ CSTYLE=$(KERNEL_SOURCE)/usr/src/tools/scripts/cstyle
all: kvm kvm.so
-kvm: kvm.c kvm_x86.c kvm_emulate.c kvm.h kvm_x86host.h msr.h bitops.h kvm_subr.c kvm_irq.c kvm_i8254.c kvm_lapic.c kvm_mmu.c kvm_iodev.c kvm_ioapic.c kvm_vmx.c kvm_i8259.c kvm_coalesced_mmio.c
+kvm: kvm.c kvm_x86.c kvm_emulate.c kvm.h kvm_x86host.h msr.h bitops.h kvm_subr.c kvm_irq.c kvm_i8254.c kvm_lapic.c kvm_mmu.c kvm_iodev.c kvm_ioapic.c kvm_vmx.c kvm_i8259.c kvm_coalesced_mmio.c kvm_irq_comm.c
$(CC) $(CFLAGS) $(INCLUDEDIR) kvm.c
$(CC) $(CFLAGS) $(INCLUDEDIR) kvm_x86.c
$(CC) $(CFLAGS) $(INCLUDEDIR) kvm_emulate.c
@@ -30,6 +30,7 @@ kvm: kvm.c kvm_x86.c kvm_emulate.c kvm.h kvm_x86host.h msr.h bitops.h kvm_subr.c
$(CC) $(CFLAGS) $(INCLUDEDIR) kvm_vmx.c
$(CC) $(CFLAGS) $(INCLUDEDIR) kvm_i8259.c
$(CC) $(CFLAGS) $(INCLUDEDIR) kvm_coalesced_mmio.c
+ $(CC) $(CFLAGS) $(INCLUDEDIR) kvm_irq_comm.c
$(CTFCONVERT) -i -L VERSION kvm.o
$(CTFCONVERT) -i -L VERSION kvm_x86.o
$(CTFCONVERT) -i -L VERSION kvm_emulate.o
@@ -42,9 +43,10 @@ kvm: kvm.c kvm_x86.c kvm_emulate.c kvm.h kvm_x86host.h msr.h bitops.h kvm_subr.c
$(CTFCONVERT) -i -L VERSION kvm_ioapic.o
$(CTFCONVERT) -i -L VERSION kvm_vmx.o
$(CTFCONVERT) -i -L VERSION kvm_i8259.o
- $(CC) $(CFLAGS) $(INCLUDEDIR) kvm_coalesced_mmio.o
- $(LD) -r -o kvm kvm.o kvm_x86.o kvm_emulate.o kvm_subr.o kvm_irq.o kvm_i8254.o kvm_lapic.o kvm_mmu.o kvm_iodev.o kvm_ioapic.o kvm_vmx.o kvm_i8259.o kvm_coalesced_mmio.o
- $(CTFMERGE) -L VERSION -o kvm kvm.o kvm_x86.o kvm_emulate.o kvm_subr.o kvm_irq.o kvm_i8254.o kvm_lapic.o kvm_mmu.o kvm_iodev.o kvm_ioapic.o kvm_vmx.o kvm_i8259.o kvm_coalesced_mmio.o
+ $(CTFCONVERT) -i -L VERSION kvm_coalesced_mmio.o
+ $(CTFCONVERT) -i -L VERSION kvm_irq_comm.o
+ $(LD) -r -o kvm kvm.o kvm_x86.o kvm_emulate.o kvm_subr.o kvm_irq.o kvm_i8254.o kvm_lapic.o kvm_mmu.o kvm_iodev.o kvm_ioapic.o kvm_vmx.o kvm_i8259.o kvm_coalesced_mmio.o kvm_irq_comm.o
+ $(CTFMERGE) -L VERSION -o kvm kvm.o kvm_x86.o kvm_emulate.o kvm_subr.o kvm_irq.o kvm_i8254.o kvm_lapic.o kvm_mmu.o kvm_iodev.o kvm_ioapic.o kvm_vmx.o kvm_i8259.o kvm_coalesced_mmio.o kvm_irq_comm.o
kvm.so: kvm_mdb.c
gcc -m64 -shared \
@@ -57,8 +59,8 @@ install: kvm
@pfexec cp kvm.conf /usr/kernel/drv
check:
- @$(CSTYLE) kvm.c kvm_mdb.c kvm_emulate.c kvm_x86.c kvm_irq.c kvm_lapic.c kvm_i8254.c kvm_mmu.c kvm_iodev.c kvm_subr.c kvm_ioapic.c kvm_vmx.c kvm_i8259.c kvm_coalesced_mmio.c
- @./tools/xxxcheck kvm_x86.c kvm.c kvm_irq.c kvm_lapic.c kvm_i8254.c kvm_mmu.c kvm_iodev.c kvm_ioapic.c kvm_vmx.c kvm_i8259.c kvm_coalesced_mmio.c
+ @$(CSTYLE) kvm.c kvm_mdb.c kvm_emulate.c kvm_x86.c kvm_irq.c kvm_lapic.c kvm_i8254.c kvm_mmu.c kvm_iodev.c kvm_subr.c kvm_ioapic.c kvm_vmx.c kvm_i8259.c kvm_coalesced_mmio.c kvm_irq_comm.c
+ @./tools/xxxcheck kvm_x86.c kvm.c kvm_irq.c kvm_lapic.c kvm_i8254.c kvm_mmu.c kvm_iodev.c kvm_ioapic.c kvm_vmx.c kvm_i8259.c kvm_coalesced_mmio.c kvm_irq_comm.c
load: install
@echo "==> Loading kvm module"
diff --git a/kvm.c b/kvm.c
index 60cbd28..7df7a2e 100644
--- a/kvm.c
+++ b/kvm.c
@@ -246,6 +246,7 @@ extern void kvm_mmu_sync_roots(struct kvm_vcpu *);
extern void kvm_mmu_flush_tlb(struct kvm_vcpu *);
extern void kvm_mmu_unload(struct kvm_vcpu *vcpu);
extern int kvm_pic_set_irq(void *, int, int);
+extern
/*
* Find the first cleared bit in a memory region.
@@ -5671,38 +5672,6 @@ page_address(page_t *page)
return (hat_kpm_mapin_pfn(page->p_pagenum));
}
-void
-kvm_notify_acked_irq(struct kvm *kvm, unsigned irqchip, unsigned pin)
-{
- struct kvm_irq_ack_notifier *kian;
- struct hlist_node *n;
- int gsi;
-
- KVM_TRACE2(ack__irq, unsigned int, irqchip, unsigned int, pin);
-
-#ifdef XXX
- rcu_read_lock();
-
- gsi = rcu_dereference(kvm->irq_routing)->chip[irqchip][pin];
-#else
- XXX_KVM_SYNC_PROBE;
-#endif
- gsi = (kvm->irq_routing)->chip[irqchip][pin];
-
- if (gsi != -1) {
- for (kian = list_head(&kvm->irq_ack_notifier_list);
- kian != NULL;
- kian = list_next(&kvm->irq_ack_notifier_list, kian)) {
- if (kian->gsi == gsi)
- kian->irq_acked(kian);
- }
- }
-#ifdef XXX
- rcu_read_unlock();
-#else
- XXX_KVM_SYNC_PROBE;
-#endif
-}
/*
* Read pending interrupt vector and intack.
@@ -6469,306 +6438,6 @@ kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu,
extern void kvm_vcpu_kick(struct kvm_vcpu *vcpu);
-void
-kvm_fire_mask_notifiers(struct kvm *kvm, int irq, int mask)
-{
- struct kvm_irq_mask_notifier *kimn;
-
-#ifdef XXX
- rcu_read_lock();
-#else
- XXX_KVM_SYNC_PROBE;
-#endif
-
- for (kimn = list_head(&kvm->mask_notifier_list); kimn != NULL;
- kimn = list_next(&kvm->mask_notifier_list, kimn)) {
- if (kimn->irq == irq)
- kimn->func(kimn, mask);
- }
-
-#ifdef XXX
- rcu_read_unlock();
-#else
- XXX_KVM_SYNC_PROBE;
-#endif
-}
-
-
-
-static inline int
-kvm_irq_line_state(unsigned long *irq_state, int irq_source_id, int level)
-{
- /* Logical OR for level trig interrupt */
- if (level) {
- set_bit(irq_source_id, irq_state);
- } else {
- clear_bit(irq_source_id, irq_state);
- }
-
- return (!!(*irq_state));
-}
-
-
-
-static int
-kvm_set_pic_irq(struct kvm_kernel_irq_routing_entry *e,
- struct kvm *kvm, int irq_source_id, int level)
-{
-#ifdef CONFIG_X86
- struct kvm_pic *pic = pic_irqchip(kvm);
- level = kvm_irq_line_state(&pic->irq_states[e->irqchip.pin],
- irq_source_id, level);
- return (kvm_pic_set_irq(pic, e->irqchip.pin, level));
-#else
- return (-1);
-#endif
-}
-
-static int
-kvm_set_ioapic_irq(struct kvm_kernel_irq_routing_entry *e,
- struct kvm *kvm, int irq_source_id, int level)
-{
- struct kvm_ioapic *ioapic = kvm->arch.vioapic;
- level = kvm_irq_line_state(&ioapic->irq_states[e->irqchip.pin],
- irq_source_id, level);
-
- return (kvm_ioapic_set_irq(ioapic, e->irqchip.pin, level));
-}
-
-static int
-kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, struct kvm *kvm,
- int irq_source_id, int level)
-{
- struct kvm_lapic_irq irq;
-
- if (!level)
- return (-1);
-
- KVM_TRACE2(msi__set__irq, uintptr_t, e->msi.address_lo,
- uintptr_t, e->msi.data);
-
- irq.dest_id = (e->msi.address_lo & MSI_ADDR_DEST_ID_MASK) >>
- MSI_ADDR_DEST_ID_SHIFT;
- irq.vector = (e->msi.data & MSI_DATA_VECTOR_MASK) >>
- MSI_DATA_VECTOR_SHIFT;
- irq.dest_mode = (1 << MSI_ADDR_DEST_MODE_SHIFT) & e->msi.address_lo;
- irq.trig_mode = (1 << MSI_DATA_TRIGGER_SHIFT) & e->msi.data;
- irq.delivery_mode = e->msi.data & 0x700;
- irq.level = 1;
- irq.shorthand = 0;
-
- /* TODO Deal with RH bit of MSI message address */
- return (kvm_irq_delivery_to_apic(kvm, NULL, &irq));
-}
-
-static int
-setup_routing_entry(struct kvm_irq_routing_table *rt,
- struct kvm_kernel_irq_routing_entry *e,
- const struct kvm_irq_routing_entry *ue)
-{
- int r = -EINVAL;
- int delta;
- unsigned max_pin;
- struct kvm_kernel_irq_routing_entry *ei;
-
- /*
- * Do not allow GSI to be mapped to the same irqchip more than once.
- * Allow only one to one mapping between GSI and MSI.
- */
- for (ei = list_head(&rt->map[ue->gsi]); ei != NULL;
- ei = list_next(&rt->map[ue->gsi], ei)) {
- if (ei->type == KVM_IRQ_ROUTING_MSI ||
- ue->u.irqchip.irqchip == ei->irqchip.irqchip)
- return (r);
- }
-
- e->gsi = ue->gsi;
- e->type = ue->type;
- switch (ue->type) {
- case KVM_IRQ_ROUTING_IRQCHIP:
- delta = 0;
- switch (ue->u.irqchip.irqchip) {
- case KVM_IRQCHIP_PIC_MASTER:
- e->set = kvm_set_pic_irq;
- max_pin = 16;
- break;
- case KVM_IRQCHIP_PIC_SLAVE:
- e->set = kvm_set_pic_irq;
- max_pin = 16;
- delta = 8;
- break;
- case KVM_IRQCHIP_IOAPIC:
- max_pin = KVM_IOAPIC_NUM_PINS;
- e->set = kvm_set_ioapic_irq;
- break;
- default:
- goto out;
- }
- e->irqchip.irqchip = ue->u.irqchip.irqchip;
- e->irqchip.pin = ue->u.irqchip.pin + delta;
- if (e->irqchip.pin >= max_pin)
- goto out;
- rt->chip[ue->u.irqchip.irqchip][e->irqchip.pin] = ue->gsi;
- break;
- case KVM_IRQ_ROUTING_MSI:
- e->set = kvm_set_msi;
- e->msi.address_lo = ue->u.msi.address_lo;
- e->msi.address_hi = ue->u.msi.address_hi;
- e->msi.data = ue->u.msi.data;
- break;
- default:
- goto out;
- }
-
- list_insert_head(&rt->map[e->gsi], e);
- r = 0;
-out:
- return (r);
-}
-
-int
-kvm_set_irq_routing(struct kvm *kvm, const struct kvm_irq_routing_entry *ue,
- unsigned nr, unsigned flags)
-{
- struct kvm_irq_routing_table *new, *old;
- uint32_t i, j, nr_rt_entries = 0;
- size_t sz = sizeof (struct kvm_kernel_irq_routing_entry);
- int r;
-
- for (i = 0; i < nr; ++i) {
- if (ue[i].gsi >= KVM_MAX_IRQ_ROUTES)
- return (-EINVAL);
- nr_rt_entries = max(nr_rt_entries, ue[i].gsi);
- }
-
- nr_rt_entries += 1;
-
-#ifdef XXX
- new = kmem_zalloc(sizeof (*new) + (nr_rt_entries * sizeof (list_t)) +
- (nr * sz), KM_SLEEP);
-
- new->rt_entries = (void *)&new->map[nr_rt_entries];
-#else
- XXX_KVM_PROBE;
- new = kmem_zalloc(sizeof (*new), KM_SLEEP);
-
- for (i = 0; i < KVM_MAX_IRQ_ROUTES; i++) {
- list_create(&new->map[i], sz,
- offsetof(struct kvm_kernel_irq_routing_entry, link));
- }
-
- new->rt_entries = kmem_zalloc(sz * nr, KM_SLEEP);
-
-#endif
-
- new->nr_rt_entries = nr_rt_entries;
- for (i = 0; i < 3; i++)
- for (j = 0; j < KVM_IOAPIC_NUM_PINS; j++)
- new->chip[i][j] = -1;
-
- for (i = 0; i < nr; ++i) {
- r = -EINVAL;
- if (ue->flags)
- goto out;
- r = setup_routing_entry(new,
- (struct kvm_kernel_irq_routing_entry *)
- ((caddr_t)new->rt_entries + (i * sz)), ue);
-
- if (r)
- goto out;
- ++ue;
- }
-
- mutex_enter(&kvm->irq_lock);
- old = kvm->irq_routing;
-#ifdef XXX
- rcu_assign_pointer(kvm->irq_routing, new);
-#else
- XXX_KVM_SYNC_PROBE;
- kvm->irq_routing = new;
-#endif
- mutex_exit(&kvm->irq_lock);
-#ifdef XXX
- synchronize_rcu();
-#else
- XXX_KVM_SYNC_PROBE;
-#endif
-
- new = old;
- r = 0;
-
-out:
- if (new) {
- if (new->rt_entries != NULL)
- kmem_free(new->rt_entries, sz * nr);
-
- kmem_free(new, sizeof (*new));
- }
- return (r);
-}
-
-#define IOAPIC_ROUTING_ENTRY(irq) \
- { \
- .gsi = irq, \
- .type = KVM_IRQ_ROUTING_IRQCHIP, \
- .u.irqchip.irqchip = KVM_IRQCHIP_IOAPIC, \
- .u.irqchip.pin = (irq) \
- }
-
-#define ROUTING_ENTRY1(irq) IOAPIC_ROUTING_ENTRY(irq)
-
-#ifdef CONFIG_X86
-#define PIC_ROUTING_ENTRY(irq) \
- { \
- .gsi = irq, \
- .type = KVM_IRQ_ROUTING_IRQCHIP, \
- .u.irqchip.irqchip = SELECT_PIC(irq), \
- .u.irqchip.pin = (irq) % 8 \
- }
-
-#define ROUTING_ENTRY2(irq) \
- IOAPIC_ROUTING_ENTRY(irq), PIC_ROUTING_ENTRY(irq)
-#else
-#define ROUTING_ENTRY2(irq) \
- IOAPIC_ROUTING_ENTRY(irq)
-#endif
-
-static const struct kvm_irq_routing_entry default_routing[] = {
- ROUTING_ENTRY2(0), ROUTING_ENTRY2(1),
- ROUTING_ENTRY2(2), ROUTING_ENTRY2(3),
- ROUTING_ENTRY2(4), ROUTING_ENTRY2(5),
- ROUTING_ENTRY2(6), ROUTING_ENTRY2(7),
- ROUTING_ENTRY2(8), ROUTING_ENTRY2(9),
- ROUTING_ENTRY2(10), ROUTING_ENTRY2(11),
- ROUTING_ENTRY2(12), ROUTING_ENTRY2(13),
- ROUTING_ENTRY2(14), ROUTING_ENTRY2(15),
- ROUTING_ENTRY1(16), ROUTING_ENTRY1(17),
- ROUTING_ENTRY1(18), ROUTING_ENTRY1(19),
- ROUTING_ENTRY1(20), ROUTING_ENTRY1(21),
- ROUTING_ENTRY1(22), ROUTING_ENTRY1(23),
-#ifdef CONFIG_IA64
- ROUTING_ENTRY1(24), ROUTING_ENTRY1(25),
- ROUTING_ENTRY1(26), ROUTING_ENTRY1(27),
- ROUTING_ENTRY1(28), ROUTING_ENTRY1(29),
- ROUTING_ENTRY1(30), ROUTING_ENTRY1(31),
- ROUTING_ENTRY1(32), ROUTING_ENTRY1(33),
- ROUTING_ENTRY1(34), ROUTING_ENTRY1(35),
- ROUTING_ENTRY1(36), ROUTING_ENTRY1(37),
- ROUTING_ENTRY1(38), ROUTING_ENTRY1(39),
- ROUTING_ENTRY1(40), ROUTING_ENTRY1(41),
- ROUTING_ENTRY1(42), ROUTING_ENTRY1(43),
- ROUTING_ENTRY1(44), ROUTING_ENTRY1(45),
- ROUTING_ENTRY1(46), ROUTING_ENTRY1(47),
-#endif
-};
-
-int
-kvm_setup_default_irq_routing(struct kvm *kvm)
-{
- return (kvm_set_irq_routing(kvm, default_routing,
- ARRAY_SIZE(default_routing), 0));
-}
-
static int
kvm_vm_ioctl_set_identity_map_addr(struct kvm *kvm, uint64_t ident_addr)
{
@@ -6776,28 +6445,6 @@ kvm_vm_ioctl_set_identity_map_addr(struct kvm *kvm, uint64_t ident_addr)
return (0);
}
-int
-kvm_request_irq_source_id(struct kvm *kvm)
-{
- unsigned long *bitmap = &kvm->arch.irq_sources_bitmap;
- int irq_source_id;
-
- mutex_enter(&kvm->irq_lock);
- irq_source_id = find_first_zero_bit(bitmap, 64);
-
- if (irq_source_id >= 64) {
- irq_source_id = -EFAULT;
- goto unlock;
- }
-
- ASSERT(irq_source_id != KVM_USERSPACE_IRQ_SOURCE_ID);
- set_bit(irq_source_id, bitmap);
-unlock:
- mutex_exit(&kvm->irq_lock);
-
- return (irq_source_id);
-}
-
void
kvm_timer_fire(void *arg)
{
@@ -6820,42 +6467,7 @@ kvm_timer_fire(void *arg)
mutex_exit(&vcpu->kvcpu_kick_lock);
}
-void
-kvm_register_irq_ack_notifier(struct kvm *kvm,
- struct kvm_irq_ack_notifier *kian)
-{
- mutex_enter(&kvm->irq_lock);
- list_insert_head(&kvm->irq_ack_notifier_list, kian);
- mutex_exit(&kvm->irq_lock);
-}
-
-void
-kvm_unregister_irq_ack_notifier(struct kvm *kvm,
- struct kvm_irq_ack_notifier *kian)
-{
- mutex_enter(&kvm->irq_lock);
- list_remove(&kvm->irq_ack_notifier_list, kian);
- mutex_exit(&kvm->irq_lock);
-}
-
-void
-kvm_register_irq_mask_notifier(struct kvm *kvm, int irq,
- struct kvm_irq_mask_notifier *kimn)
-{
- mutex_enter(&kvm->irq_lock);
- kimn->irq = irq;
- list_insert_head(&kvm->mask_notifier_list, kimn);
- mutex_exit(&kvm->irq_lock);
-}
-void
-kvm_unregister_irq_mask_notifier(struct kvm *kvm, int irq,
- struct kvm_irq_mask_notifier *kimn)
-{
- mutex_enter(&kvm->irq_lock);
- list_remove(&kvm->mask_notifier_list, kimn);
- mutex_exit(&kvm->irq_lock);
-}
static int
kvm_vcpu_ioctl_get_lapic(struct kvm_vcpu *vcpu, struct kvm_lapic_state *s)
@@ -6938,54 +6550,6 @@ kvm_vm_ioctl_set_irqchip(struct kvm *kvm, struct kvm_irqchip *chip)
return (r);
}
-/*
- * Return value:
- * < 0 Interrupt was ignored (masked or not delivered for other reasons)
- * = 0 Interrupt was coalesced (previous irq is still pending)
- * > 0 Number of CPUs interrupt was delivered to
- */
-int
-kvm_set_irq(struct kvm *kvm, int irq_source_id, uint32_t irq, int level)
-{
- struct kvm_kernel_irq_routing_entry *e, irq_set[KVM_NR_IRQCHIPS];
- int ret = -1, i = 0;
- struct kvm_irq_routing_table *irq_rt;
-
- /*
- * Not possible to detect if the guest uses the PIC or the
- * IOAPIC. So set the bit in both. The guest will ignore
- * writes to the unused one.
- */
-#ifdef XXX
- rcu_read_lock();
- irq_rt = rcu_dereference(kvm->irq_routing);
-#else
- XXX_KVM_SYNC_PROBE;
- irq_rt = kvm->irq_routing;
-#endif
- if (irq < irq_rt->nr_rt_entries) {
- for (e = list_head(&irq_rt->map[irq]); e != NULL;
- e = list_next(&irq_rt->map[irq], e)) {
- irq_set[i++] = *e;
- }
- }
-#ifdef XXX
- rcu_read_unlock();
-#else
- XXX_KVM_SYNC_PROBE;
-#endif
-
- while (i--) {
- int r;
- r = irq_set[i].set(&irq_set[i], kvm, irq_source_id, level);
- if (r < 0)
- continue;
-
- ret = r + ((ret < 0) ? 0 : ret);
- }
-
- return (ret);
-}
static int
kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq)
diff --git a/kvm_irq.c b/kvm_irq.c
index 55bbf81..ec70d82 100644
--- a/kvm_irq.c
+++ b/kvm_irq.c
@@ -60,39 +60,6 @@ kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu)
}
void
-kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id)
-{
- int i;
-
- ASSERT(irq_source_id != KVM_USERSPACE_IRQ_SOURCE_ID);
-
- mutex_enter(&kvm->irq_lock);
- if (irq_source_id < 0 ||
- irq_source_id >= BITS_PER_LONG) {
-#ifdef XXX
- printk(KERN_ERR "kvm: IRQ source ID out of range!\n");
-#else
- XXX_KVM_PROBE;
-#endif
- goto unlock;
- }
- clear_bit(irq_source_id, &kvm->arch.irq_sources_bitmap);
- if (!irqchip_in_kernel(kvm))
- goto unlock;
-
- for (i = 0; i < KVM_IOAPIC_NUM_PINS; i++) {
- clear_bit(irq_source_id, &kvm->arch.vioapic->irq_states[i]);
- if (i >= 16)
- continue;
-#ifdef CONFIG_X86
- clear_bit(irq_source_id, &pic_irqchip(kvm)->irq_states[i]);
-#endif
- }
-unlock:
- mutex_exit(&kvm->irq_lock);
-}
-
-void
__kvm_migrate_timers(struct kvm_vcpu *vcpu)
{
__kvm_migrate_apic_timer(vcpu);
diff --git a/kvm_irq_comm.c b/kvm_irq_comm.c
new file mode 100644
index 0000000..aa4cf14
--- /dev/null
+++ b/kvm_irq_comm.c
@@ -0,0 +1,554 @@
+/*
+ * irq_comm.c: Common API for in kernel interrupt controller
+ * Copyright (c) 2007, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ * Authors:
+ * Yaozu (Eddie) Dong <Eddie.dong@intel.com>
+ *
+ */
+
+/*
+ * XXX Need proper header files!
+ */
+#include "msr.h"
+#include "irqflags.h"
+#include "kvm_host.h"
+#include "kvm_x86host.h"
+#include "kvm_iodev.h"
+#include "kvm.h"
+#include "apicdef.h"
+#include "kvm_lapic.h"
+#include "kvm_ioapic.h"
+#include "irq.h"
+
+extern long find_first_zero_bit(const unsigned long *, unsigned long);
+extern int kvm_pic_set_irq(void *, int, int);
+
+static int
+kvm_irq_line_state(unsigned long *irq_state, int irq_source_id, int level)
+{
+ /* Logical OR for level trig interrupt */
+ if (level) {
+ set_bit(irq_source_id, irq_state);
+ } else {
+ clear_bit(irq_source_id, irq_state);
+ }
+
+ return (!!(*irq_state));
+}
+
+static int
+kvm_set_pic_irq(struct kvm_kernel_irq_routing_entry *e,
+ struct kvm *kvm, int irq_source_id, int level)
+{
+#ifdef CONFIG_X86
+ struct kvm_pic *pic = pic_irqchip(kvm);
+ level = kvm_irq_line_state(&pic->irq_states[e->irqchip.pin],
+ irq_source_id, level);
+ return (kvm_pic_set_irq(pic, e->irqchip.pin, level));
+#else
+ return (-1);
+#endif
+}
+
+static int
+kvm_set_ioapic_irq(struct kvm_kernel_irq_routing_entry *e,
+ struct kvm *kvm, int irq_source_id, int level)
+{
+ struct kvm_ioapic *ioapic = kvm->arch.vioapic;
+ level = kvm_irq_line_state(&ioapic->irq_states[e->irqchip.pin],
+ irq_source_id, level);
+
+ return (kvm_ioapic_set_irq(ioapic, e->irqchip.pin, level));
+}
+
+static int
+kvm_is_dm_lowest_prio(struct kvm_lapic_irq *irq)
+{
+#ifdef CONFIG_IA64
+ return (irq->delivery_mode ==
+ (IOSAPIC_LOWEST_PRIORITY << IOSAPIC_DELIVERY_SHIFT));
+#else
+ return (irq->delivery_mode == APIC_DM_LOWEST);
+#endif
+}
+
+int
+kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src,
+ struct kvm_lapic_irq *irq)
+{
+ int i, r = -1;
+ struct kvm_vcpu *vcpu, *lowest = NULL;
+
+ if (irq->dest_mode == 0 && irq->dest_id == 0xff &&
+ kvm_is_dm_lowest_prio(irq))
+ cmn_err(CE_NOTE, "kvm: apic: phys broadcast and lowest prio\n");
+
+ kvm_for_each_vcpu(i, vcpu, kvm) {
+ if (!kvm_apic_present(vcpu))
+ continue;
+
+ if (!kvm_apic_match_dest(vcpu, src, irq->shorthand,
+ irq->dest_id, irq->dest_mode))
+ continue;
+
+ if (!kvm_is_dm_lowest_prio(irq)) {
+ if (r < 0)
+ r = 0;
+ r += kvm_apic_set_irq(vcpu, irq);
+ } else {
+ if (!lowest)
+ lowest = vcpu;
+ else if (kvm_apic_compare_prio(vcpu, lowest) < 0)
+ lowest = vcpu;
+ }
+ }
+ if (lowest)
+ r = kvm_apic_set_irq(lowest, irq);
+
+ return (r);
+}
+
+static int
+kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, struct kvm *kvm,
+ int irq_source_id, int level)
+{
+ struct kvm_lapic_irq irq;
+
+ if (!level)
+ return (-1);
+
+ KVM_TRACE2(msi__set__irq, uintptr_t, e->msi.address_lo,
+ uintptr_t, e->msi.data);
+
+ irq.dest_id = (e->msi.address_lo & MSI_ADDR_DEST_ID_MASK) >>
+ MSI_ADDR_DEST_ID_SHIFT;
+ irq.vector = (e->msi.data & MSI_DATA_VECTOR_MASK) >>
+ MSI_DATA_VECTOR_SHIFT;
+ irq.dest_mode = (1 << MSI_ADDR_DEST_MODE_SHIFT) & e->msi.address_lo;
+ irq.trig_mode = (1 << MSI_DATA_TRIGGER_SHIFT) & e->msi.data;
+ irq.delivery_mode = e->msi.data & 0x700;
+ irq.level = 1;
+ irq.shorthand = 0;
+
+ /* TODO Deal with RH bit of MSI message address */
+ return (kvm_irq_delivery_to_apic(kvm, NULL, &irq));
+}
+
+/*
+ * Return value:
+ * < 0 Interrupt was ignored (masked or not delivered for other reasons)
+ * = 0 Interrupt was coalesced (previous irq is still pending)
+ * > 0 Number of CPUs interrupt was delivered to
+ */
+int
+kvm_set_irq(struct kvm *kvm, int irq_source_id, uint32_t irq, int level)
+{
+ struct kvm_kernel_irq_routing_entry *e, irq_set[KVM_NR_IRQCHIPS];
+ int ret = -1, i = 0;
+ struct kvm_irq_routing_table *irq_rt;
+
+ /*
+ * Not possible to detect if the guest uses the PIC or the
+ * IOAPIC. So set the bit in both. The guest will ignore
+ * writes to the unused one.
+ */
+#ifdef XXX
+ rcu_read_lock();
+ irq_rt = rcu_dereference(kvm->irq_routing);
+#else
+ XXX_KVM_SYNC_PROBE;
+ irq_rt = kvm->irq_routing;
+#endif
+ if (irq < irq_rt->nr_rt_entries) {
+ for (e = list_head(&irq_rt->map[irq]); e != NULL;
+ e = list_next(&irq_rt->map[irq], e)) {
+ irq_set[i++] = *e;
+ }
+ }
+#ifdef XXX
+ rcu_read_unlock();
+#else
+ XXX_KVM_SYNC_PROBE;
+#endif
+
+ while (i--) {
+ int r;
+ r = irq_set[i].set(&irq_set[i], kvm, irq_source_id, level);
+ if (r < 0)
+ continue;
+
+ ret = r + ((ret < 0) ? 0 : ret);
+ }
+
+ return (ret);
+}
+
+void
+kvm_notify_acked_irq(struct kvm *kvm, unsigned irqchip, unsigned pin)
+{
+ struct kvm_irq_ack_notifier *kian;
+ struct hlist_node *n;
+ int gsi;
+
+ KVM_TRACE2(ack__irq, unsigned int, irqchip, unsigned int, pin);
+
+#ifdef XXX
+ rcu_read_lock();
+
+ gsi = rcu_dereference(kvm->irq_routing)->chip[irqchip][pin];
+#else
+ XXX_KVM_SYNC_PROBE;
+#endif
+ gsi = (kvm->irq_routing)->chip[irqchip][pin];
+
+ if (gsi != -1) {
+ for (kian = list_head(&kvm->irq_ack_notifier_list);
+ kian != NULL;
+ kian = list_next(&kvm->irq_ack_notifier_list, kian)) {
+ if (kian->gsi == gsi)
+ kian->irq_acked(kian);
+ }
+ }
+#ifdef XXX
+ rcu_read_unlock();
+#else
+ XXX_KVM_SYNC_PROBE;
+#endif
+}
+
+void
+kvm_register_irq_ack_notifier(struct kvm *kvm,
+ struct kvm_irq_ack_notifier *kian)
+{
+ mutex_enter(&kvm->irq_lock);
+ list_insert_head(&kvm->irq_ack_notifier_list, kian);
+ mutex_exit(&kvm->irq_lock);
+}
+
+void
+kvm_unregister_irq_ack_notifier(struct kvm *kvm,
+ struct kvm_irq_ack_notifier *kian)
+{
+ mutex_enter(&kvm->irq_lock);
+ list_remove(&kvm->irq_ack_notifier_list, kian);
+ mutex_exit(&kvm->irq_lock);
+}
+
+int
+kvm_request_irq_source_id(struct kvm *kvm)
+{
+ unsigned long *bitmap = &kvm->arch.irq_sources_bitmap;
+ int irq_source_id;
+
+ mutex_enter(&kvm->irq_lock);
+ irq_source_id = find_first_zero_bit(bitmap, 64);
+
+ if (irq_source_id >= 64) {
+ irq_source_id = -EFAULT;
+ goto unlock;
+ }
+
+ ASSERT(irq_source_id != KVM_USERSPACE_IRQ_SOURCE_ID);
+ set_bit(irq_source_id, bitmap);
+unlock:
+ mutex_exit(&kvm->irq_lock);
+
+ return (irq_source_id);
+}
+
+void
+kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id)
+{
+ int i;
+
+ ASSERT(irq_source_id != KVM_USERSPACE_IRQ_SOURCE_ID);
+
+ mutex_enter(&kvm->irq_lock);
+ if (irq_source_id < 0 ||
+ irq_source_id >= BITS_PER_LONG) {
+#ifdef XXX
+ printk(KERN_ERR "kvm: IRQ source ID out of range!\n");
+#else
+ XXX_KVM_PROBE;
+#endif
+ goto unlock;
+ }
+ clear_bit(irq_source_id, &kvm->arch.irq_sources_bitmap);
+ if (!irqchip_in_kernel(kvm))
+ goto unlock;
+
+ for (i = 0; i < KVM_IOAPIC_NUM_PINS; i++) {
+ clear_bit(irq_source_id, &kvm->arch.vioapic->irq_states[i]);
+ if (i >= 16)
+ continue;
+#ifdef CONFIG_X86
+ clear_bit(irq_source_id, &pic_irqchip(kvm)->irq_states[i]);
+#endif
+ }
+unlock:
+ mutex_exit(&kvm->irq_lock);
+}
+
+void
+kvm_register_irq_mask_notifier(struct kvm *kvm, int irq,
+ struct kvm_irq_mask_notifier *kimn)
+{
+ mutex_enter(&kvm->irq_lock);
+ kimn->irq = irq;
+ list_insert_head(&kvm->mask_notifier_list, kimn);
+ mutex_exit(&kvm->irq_lock);
+}
+
+void
+kvm_unregister_irq_mask_notifier(struct kvm *kvm, int irq,
+ struct kvm_irq_mask_notifier *kimn)
+{
+ mutex_enter(&kvm->irq_lock);
+ list_remove(&kvm->mask_notifier_list, kimn);
+ mutex_exit(&kvm->irq_lock);
+}
+
+void
+kvm_fire_mask_notifiers(struct kvm *kvm, int irq, int mask)
+{
+ struct kvm_irq_mask_notifier *kimn;
+
+#ifdef XXX
+ rcu_read_lock();
+#else
+ XXX_KVM_SYNC_PROBE;
+#endif
+
+ for (kimn = list_head(&kvm->mask_notifier_list); kimn != NULL;
+ kimn = list_next(&kvm->mask_notifier_list, kimn)) {
+ if (kimn->irq == irq)
+ kimn->func(kimn, mask);
+ }
+
+#ifdef XXX
+ rcu_read_unlock();
+#else
+ XXX_KVM_SYNC_PROBE;
+#endif
+}
+
+static int
+setup_routing_entry(struct kvm_irq_routing_table *rt,
+ struct kvm_kernel_irq_routing_entry *e,
+ const struct kvm_irq_routing_entry *ue)
+{
+ int r = -EINVAL;
+ int delta;
+ unsigned max_pin;
+ struct kvm_kernel_irq_routing_entry *ei;
+
+ /*
+ * Do not allow GSI to be mapped to the same irqchip more than once.
+ * Allow only one to one mapping between GSI and MSI.
+ */
+ for (ei = list_head(&rt->map[ue->gsi]); ei != NULL;
+ ei = list_next(&rt->map[ue->gsi], ei)) {
+ if (ei->type == KVM_IRQ_ROUTING_MSI ||
+ ue->u.irqchip.irqchip == ei->irqchip.irqchip)
+ return (r);
+ }
+
+ e->gsi = ue->gsi;
+ e->type = ue->type;
+ switch (ue->type) {
+ case KVM_IRQ_ROUTING_IRQCHIP:
+ delta = 0;
+ switch (ue->u.irqchip.irqchip) {
+ case KVM_IRQCHIP_PIC_MASTER:
+ e->set = kvm_set_pic_irq;
+ max_pin = 16;
+ break;
+ case KVM_IRQCHIP_PIC_SLAVE:
+ e->set = kvm_set_pic_irq;
+ max_pin = 16;
+ delta = 8;
+ break;
+ case KVM_IRQCHIP_IOAPIC:
+ max_pin = KVM_IOAPIC_NUM_PINS;
+ e->set = kvm_set_ioapic_irq;
+ break;
+ default:
+ goto out;
+ }
+ e->irqchip.irqchip = ue->u.irqchip.irqchip;
+ e->irqchip.pin = ue->u.irqchip.pin + delta;
+ if (e->irqchip.pin >= max_pin)
+ goto out;
+ rt->chip[ue->u.irqchip.irqchip][e->irqchip.pin] = ue->gsi;
+ break;
+ case KVM_IRQ_ROUTING_MSI:
+ e->set = kvm_set_msi;
+ e->msi.address_lo = ue->u.msi.address_lo;
+ e->msi.address_hi = ue->u.msi.address_hi;
+ e->msi.data = ue->u.msi.data;
+ break;
+ default:
+ goto out;
+ }
+
+ list_insert_head(&rt->map[e->gsi], e);
+ r = 0;
+out:
+ return (r);
+}
+
+int
+kvm_set_irq_routing(struct kvm *kvm, const struct kvm_irq_routing_entry *ue,
+ unsigned nr, unsigned flags)
+{
+ struct kvm_irq_routing_table *new, *old;
+ uint32_t i, j, nr_rt_entries = 0;
+ size_t sz = sizeof (struct kvm_kernel_irq_routing_entry);
+ int r;
+
+ for (i = 0; i < nr; ++i) {
+ if (ue[i].gsi >= KVM_MAX_IRQ_ROUTES)
+ return (-EINVAL);
+ nr_rt_entries = max(nr_rt_entries, ue[i].gsi);
+ }
+
+ nr_rt_entries += 1;
+
+#ifdef XXX
+ new = kmem_zalloc(sizeof (*new) + (nr_rt_entries * sizeof (list_t)) +
+ (nr * sz), KM_SLEEP);
+
+ new->rt_entries = (void *)&new->map[nr_rt_entries];
+#else
+ XXX_KVM_PROBE;
+ new = kmem_zalloc(sizeof (*new), KM_SLEEP);
+
+ for (i = 0; i < KVM_MAX_IRQ_ROUTES; i++) {
+ list_create(&new->map[i], sz,
+ offsetof(struct kvm_kernel_irq_routing_entry, link));
+ }
+
+ new->rt_entries = kmem_zalloc(sz * nr, KM_SLEEP);
+
+#endif
+
+ new->nr_rt_entries = nr_rt_entries;
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < KVM_IOAPIC_NUM_PINS; j++)
+ new->chip[i][j] = -1;
+
+ for (i = 0; i < nr; ++i) {
+ r = -EINVAL;
+ if (ue->flags)
+ goto out;
+ r = setup_routing_entry(new,
+ (struct kvm_kernel_irq_routing_entry *)
+ ((caddr_t)new->rt_entries + (i * sz)), ue);
+
+ if (r)
+ goto out;
+ ++ue;
+ }
+
+ mutex_enter(&kvm->irq_lock);
+ old = kvm->irq_routing;
+#ifdef XXX
+ rcu_assign_pointer(kvm->irq_routing, new);
+#else
+ XXX_KVM_SYNC_PROBE;
+ kvm->irq_routing = new;
+#endif
+ mutex_exit(&kvm->irq_lock);
+#ifdef XXX
+ synchronize_rcu();
+#else
+ XXX_KVM_SYNC_PROBE;
+#endif
+
+ new = old;
+ r = 0;
+
+out:
+ if (new) {
+ if (new->rt_entries != NULL)
+ kmem_free(new->rt_entries, sz * nr);
+
+ kmem_free(new, sizeof (*new));
+ }
+ return (r);
+}
+
+#define IOAPIC_ROUTING_ENTRY(irq) \
+ { \
+ .gsi = irq, \
+ .type = KVM_IRQ_ROUTING_IRQCHIP, \
+ .u.irqchip.irqchip = KVM_IRQCHIP_IOAPIC, \
+ .u.irqchip.pin = (irq) \
+ }
+
+#define ROUTING_ENTRY1(irq) IOAPIC_ROUTING_ENTRY(irq)
+
+#ifdef CONFIG_X86
+#define PIC_ROUTING_ENTRY(irq) \
+ { \
+ .gsi = irq, \
+ .type = KVM_IRQ_ROUTING_IRQCHIP, \
+ .u.irqchip.irqchip = SELECT_PIC(irq), \
+ .u.irqchip.pin = (irq) % 8 \
+ }
+
+#define ROUTING_ENTRY2(irq) \
+ IOAPIC_ROUTING_ENTRY(irq), PIC_ROUTING_ENTRY(irq)
+#else
+#define ROUTING_ENTRY2(irq) \
+ IOAPIC_ROUTING_ENTRY(irq)
+#endif
+
+static const struct kvm_irq_routing_entry default_routing[] = {
+ ROUTING_ENTRY2(0), ROUTING_ENTRY2(1),
+ ROUTING_ENTRY2(2), ROUTING_ENTRY2(3),
+ ROUTING_ENTRY2(4), ROUTING_ENTRY2(5),
+ ROUTING_ENTRY2(6), ROUTING_ENTRY2(7),
+ ROUTING_ENTRY2(8), ROUTING_ENTRY2(9),
+ ROUTING_ENTRY2(10), ROUTING_ENTRY2(11),
+ ROUTING_ENTRY2(12), ROUTING_ENTRY2(13),
+ ROUTING_ENTRY2(14), ROUTING_ENTRY2(15),
+ ROUTING_ENTRY1(16), ROUTING_ENTRY1(17),
+ ROUTING_ENTRY1(18), ROUTING_ENTRY1(19),
+ ROUTING_ENTRY1(20), ROUTING_ENTRY1(21),
+ ROUTING_ENTRY1(22), ROUTING_ENTRY1(23),
+#ifdef CONFIG_IA64
+ ROUTING_ENTRY1(24), ROUTING_ENTRY1(25),
+ ROUTING_ENTRY1(26), ROUTING_ENTRY1(27),
+ ROUTING_ENTRY1(28), ROUTING_ENTRY1(29),
+ ROUTING_ENTRY1(30), ROUTING_ENTRY1(31),
+ ROUTING_ENTRY1(32), ROUTING_ENTRY1(33),
+ ROUTING_ENTRY1(34), ROUTING_ENTRY1(35),
+ ROUTING_ENTRY1(36), ROUTING_ENTRY1(37),
+ ROUTING_ENTRY1(38), ROUTING_ENTRY1(39),
+ ROUTING_ENTRY1(40), ROUTING_ENTRY1(41),
+ ROUTING_ENTRY1(42), ROUTING_ENTRY1(43),
+ ROUTING_ENTRY1(44), ROUTING_ENTRY1(45),
+ ROUTING_ENTRY1(46), ROUTING_ENTRY1(47),
+#endif
+};
+
+int
+kvm_setup_default_irq_routing(struct kvm *kvm)
+{
+ return (kvm_set_irq_routing(kvm, default_routing,
+ ARRAY_SIZE(default_routing), 0));
+}
diff --git a/kvm_x86.c b/kvm_x86.c
index f30f474..3ba6155 100644
--- a/kvm_x86.c
+++ b/kvm_x86.c
@@ -468,16 +468,6 @@ apic_x2apic_mode(struct kvm_lapic *apic)
extern unsigned long kvm_rip_read(struct kvm_vcpu *vcpu);
-inline static int
-kvm_is_dm_lowest_prio(struct kvm_lapic_irq *irq)
-{
-#ifdef CONFIG_IA64
- return (irq->delivery_mode ==
- (IOSAPIC_LOWEST_PRIORITY << IOSAPIC_DELIVERY_SHIFT));
-#else
- return (irq->delivery_mode == APIC_DM_LOWEST);
-#endif
-}
void
kvm_inject_nmi(struct kvm_vcpu *vcpu)
@@ -485,41 +475,6 @@ kvm_inject_nmi(struct kvm_vcpu *vcpu)
vcpu->arch.nmi_pending = 1;
}
-int
-kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src,
- struct kvm_lapic_irq *irq)
-{
- int i, r = -1;
- struct kvm_vcpu *vcpu, *lowest = NULL;
-
- if (irq->dest_mode == 0 && irq->dest_id == 0xff &&
- kvm_is_dm_lowest_prio(irq))
- cmn_err(CE_NOTE, "kvm: apic: phys broadcast and lowest prio\n");
-
- kvm_for_each_vcpu(i, vcpu, kvm) {
- if (!kvm_apic_present(vcpu))
- continue;
-
- if (!kvm_apic_match_dest(vcpu, src, irq->shorthand,
- irq->dest_id, irq->dest_mode))
- continue;
-
- if (!kvm_is_dm_lowest_prio(irq)) {
- if (r < 0)
- r = 0;
- r += kvm_apic_set_irq(vcpu, irq);
- } else {
- if (!lowest)
- lowest = vcpu;
- else if (kvm_apic_compare_prio(vcpu, lowest) < 0)
- lowest = vcpu;
- }
- }
- if (lowest)
- r = kvm_apic_set_irq(lowest, irq);
-
- return (r);
-}
static int
ioapic_deliver(struct kvm_ioapic *ioapic, int irq)