Signed-off-by: Gleb Natapov <gleb@xxxxxxxxxx> diff --git a/libkvm/kvm-common.h b/libkvm/kvm-common.h index d4fffbe..de1ada2 100644 --- a/libkvm/kvm-common.h +++ b/libkvm/kvm-common.h @@ -55,6 +55,8 @@ struct kvm_context { int no_irqchip_creation; /// in-kernel irqchip status int irqchip_in_kernel; + /// ioctl to use to inject interrupts + int irqchip_inject_ioctl; /// do not create in-kernel pit if set int no_pit_creation; /// in-kernel pit status diff --git a/libkvm/libkvm.c b/libkvm/libkvm.c index 80300c9..8725eba 100644 --- a/libkvm/libkvm.c +++ b/libkvm/libkvm.c @@ -435,8 +435,16 @@ void kvm_create_irqchip(kvm_context_t kvm) r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_IRQCHIP); if (r > 0) { /* kernel irqchip supported */ r = ioctl(kvm->vm_fd, KVM_CREATE_IRQCHIP); - if (r >= 0) + if (r >= 0) { + kvm->irqchip_inject_ioctl = KVM_IRQ_LINE; +#if defined(KVM_CAP_IRQ_INJECT_STATUS) && defined(KVM_IRQ_LINE_STATUS) + r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, + KVM_CAP_IRQ_INJECT_STATUS); + if (r > 0) + kvm->irqchip_inject_ioctl = KVM_IRQ_LINE_STATUS; +#endif kvm->irqchip_in_kernel = 1; + } else fprintf(stderr, "Create kernel PIC irqchip failed\n"); } @@ -646,7 +654,7 @@ int kvm_get_dirty_pages_range(kvm_context_t kvm, unsigned long phys_addr, #ifdef KVM_CAP_IRQCHIP -int kvm_set_irq_level(kvm_context_t kvm, int irq, int level) +int kvm_set_irq_level(kvm_context_t kvm, int irq, int level, int *status) { struct kvm_irq_level event; int r; @@ -655,9 +663,14 @@ int kvm_set_irq_level(kvm_context_t kvm, int irq, int level) return 0; event.level = level; event.irq = irq; - r = ioctl(kvm->vm_fd, KVM_IRQ_LINE, &event); + r = ioctl(kvm->vm_fd, kvm->irqchip_inject_ioctl, &event); if (r == -1) perror("kvm_set_irq_level"); + + if (status) + *status = (kvm->irqchip_inject_ioctl == KVM_IRQ_LINE) ? + 1 : event.status; + return 1; } diff --git a/libkvm/libkvm.h b/libkvm/libkvm.h index e79e4fd..f047086 100644 --- a/libkvm/libkvm.h +++ b/libkvm/libkvm.h @@ -525,7 +525,7 @@ int kvm_get_mem_map_range(kvm_context_t kvm, unsigned long phys_addr, unsigned long len, void *buf, void *opaque, int (*cb)(unsigned long start,unsigned long len, void* bitmap, void* opaque)); -int kvm_set_irq_level(kvm_context_t kvm, int irq, int level); +int kvm_set_irq_level(kvm_context_t kvm, int irq, int level, int *status); int kvm_dirty_pages_log_enable_slot(kvm_context_t kvm, uint64_t phys_start, diff --git a/qemu/hw/apic.c b/qemu/hw/apic.c index 782b398..416eee9 100644 --- a/qemu/hw/apic.c +++ b/qemu/hw/apic.c @@ -377,6 +377,11 @@ int apic_get_irq_delivered(void) return apic_irq_delivered; } +void apic_set_irq_delivered(void) +{ + apic_irq_delivered = 1; +} + static void apic_set_irq(APICState *s, int vector_num, int trigger_mode) { apic_irq_delivered += !get_bit(s->irr, vector_num); diff --git a/qemu/hw/i8259.c b/qemu/hw/i8259.c index 6d41a5e..9da4360 100644 --- a/qemu/hw/i8259.c +++ b/qemu/hw/i8259.c @@ -186,9 +186,14 @@ static void i8259_set_irq(void *opaque, int irq, int level) { PicState2 *s = opaque; #ifdef KVM_CAP_IRQCHIP - if (kvm_enabled()) - if (kvm_set_irq(irq, level)) - return; + if (kvm_enabled()) { + int pic_ret; + if (kvm_set_irq(irq, level, &pic_ret)) { + if (pic_ret != 0) + apic_set_irq_delivered(); + return; + } + } #endif #if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT) if (level != irq_level[irq]) { diff --git a/qemu/hw/pc.h b/qemu/hw/pc.h index 2abf23f..1ccbe8b 100644 --- a/qemu/hw/pc.h +++ b/qemu/hw/pc.h @@ -48,6 +48,7 @@ IOAPICState *ioapic_init(void); void ioapic_set_irq(void *opaque, int vector, int level); void apic_reset_irq_delivered(void); int apic_get_irq_delivered(void); +void apic_set_irq_delivered(void); /* i8254.c */ diff --git a/qemu/qemu-kvm.c b/qemu/qemu-kvm.c index 5ff63ad..9b2d516 100644 --- a/qemu/qemu-kvm.c +++ b/qemu/qemu-kvm.c @@ -1266,9 +1266,9 @@ int kvm_get_phys_ram_page_bitmap(unsigned char *bitmap) #ifdef KVM_CAP_IRQCHIP -int kvm_set_irq(int irq, int level) +int kvm_set_irq(int irq, int level, int *status) { - return kvm_set_irq_level(kvm_context, irq, level); + return kvm_set_irq_level(kvm_context, irq, level, status); } #endif diff --git a/qemu/qemu-kvm.h b/qemu/qemu-kvm.h index 042dd93..755b351 100644 --- a/qemu/qemu-kvm.h +++ b/qemu/qemu-kvm.h @@ -31,7 +31,7 @@ int kvm_update_guest_debug(CPUState *env, unsigned long reinject_trap); int kvm_qemu_init_env(CPUState *env); int kvm_qemu_check_extension(int ext); void kvm_apic_init(CPUState *env); -int kvm_set_irq(int irq, int level); +int kvm_set_irq(int irq, int level, int *status); int kvm_physical_memory_set_dirty_tracking(int enable); int kvm_update_dirty_pages_log(void); -- Gleb. -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html