From 90cb46614c2040875c2595c3ca778f813acf06da Mon Sep 17 00:00:00 2001 From: Gleb Natapov Date: Wed, 4 Feb 2009 17:30:01 +0200 Subject: [PATCH] Handle IRQ status injection in userspace This allows timers to keep track of injected and colaesced interrupts. Signed-off-by: Gleb Natapov Signed-off-by: Avi Kivity --- hw/apic.c | 5 +++++ hw/i8259.c | 11 ++++++++--- hw/pc.h | 1 + kvm/libkvm/kvm-common.h | 2 ++ kvm/libkvm/libkvm.c | 19 ++++++++++++++++--- kvm/libkvm/libkvm.h | 2 +- kvm/user/main.c | 2 +- qemu-kvm.c | 4 ++-- qemu-kvm.h | 2 +- 9 files changed, 37 insertions(+), 11 deletions(-) diff --git a/hw/apic.c b/hw/apic.c index 124e8211f9..7e4332a461 100644 --- a/hw/apic.c +++ b/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/hw/i8259.c b/hw/i8259.c index 927df11ab3..9cb39413cc 100644 --- a/hw/i8259.c +++ b/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/hw/pc.h b/hw/pc.h index ea73e30651..d02ba351ab 100644 --- a/hw/pc.h +++ b/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/kvm/libkvm/kvm-common.h b/kvm/libkvm/kvm-common.h index d4fffbedfc..de1ada2e5f 100644 --- a/kvm/libkvm/kvm-common.h +++ b/kvm/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/kvm/libkvm/libkvm.c b/kvm/libkvm/libkvm.c index a559a0deb2..0ac1c28223 100644 --- a/kvm/libkvm/libkvm.c +++ b/kvm/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/kvm/libkvm/libkvm.h b/kvm/libkvm/libkvm.h index f6d653c161..0239cb6728 100644 --- a/kvm/libkvm/libkvm.h +++ b/kvm/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/kvm/user/main.c b/kvm/user/main.c index 93c74187ff..1530ae2f4f 100644 --- a/kvm/user/main.c +++ b/kvm/user/main.c @@ -200,7 +200,7 @@ static int irqchip_io(void *opaque, int size, int is_write, addr -= IRQCHIP_IO_BASE; if (is_write) { - kvm_set_irq_level(kvm, addr, *value); + kvm_set_irq_level(kvm, addr, *value, NULL); } return 0; } diff --git a/qemu-kvm.c b/qemu-kvm.c index ada1012d72..6893cfe4bf 100644 --- a/qemu-kvm.c +++ b/qemu-kvm.c @@ -1271,9 +1271,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-kvm.h b/qemu-kvm.h index e7acd2efc0..d8b17a2222 100644 --- a/qemu-kvm.h +++ b/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); -- 2.11.4.GIT