From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1Mvego-0001xh-IK for qemu-devel@nongnu.org; Wed, 07 Oct 2009 18:08:54 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1Mvegj-0001ub-GQ for qemu-devel@nongnu.org; Wed, 07 Oct 2009 18:08:53 -0400 Received: from [199.232.76.173] (port=51539 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Mvegj-0001uS-Al for qemu-devel@nongnu.org; Wed, 07 Oct 2009 18:08:49 -0400 Received: from mx1.redhat.com ([209.132.183.28]:29666) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1Mvegi-0006tK-LM for qemu-devel@nongnu.org; Wed, 07 Oct 2009 18:08:49 -0400 From: Glauber Costa Date: Wed, 7 Oct 2009 19:08:32 -0300 Message-Id: <1254953315-5761-7-git-send-email-glommer@redhat.com> In-Reply-To: <1254953315-5761-6-git-send-email-glommer@redhat.com> References: <1254953315-5761-1-git-send-email-glommer@redhat.com> <1254953315-5761-2-git-send-email-glommer@redhat.com> <1254953315-5761-3-git-send-email-glommer@redhat.com> <1254953315-5761-4-git-send-email-glommer@redhat.com> <1254953315-5761-5-git-send-email-glommer@redhat.com> <1254953315-5761-6-git-send-email-glommer@redhat.com> Subject: [Qemu-devel] [PATCH v2 6/9] provide in-kernel i8259 chip List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: aliguori@us.ibm.com This patch provides kvm with an in-kernel i8259 chip. We are currently not enabling it. The code is heavily based on what's in qemu-kvm.git. Signed-off-by: Glauber Costa --- hw/i8259.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/pc.h | 1 + kvm-all.c | 24 ++++++++++++ kvm.h | 2 + 4 files changed, 149 insertions(+), 0 deletions(-) diff --git a/hw/i8259.c b/hw/i8259.c index 3de22e3..d07dd1c 100644 --- a/hw/i8259.c +++ b/hw/i8259.c @@ -26,6 +26,7 @@ #include "isa.h" #include "monitor.h" #include "qemu-timer.h" +#include "kvm.h" /* debug PIC */ //#define DEBUG_PIC @@ -446,9 +447,96 @@ static uint32_t elcr_ioport_read(void *opaque, uint32_t addr1) return s->elcr; } +static int kvm_kernel_pic_load_from_user(PicState *s) +{ + int r = 0; +#if defined(KVM_CAP_IRQCHIP) && defined(TARGET_I386) + struct kvm_irqchip chip; + struct kvm_pic_state *kpic; + + if (!(kvm_enabled() && kvm_irqchip_in_kernel())) + return 0; + + chip.chip_id = (&s->pics_state->pics[0] == s) ? + KVM_IRQCHIP_PIC_MASTER : + KVM_IRQCHIP_PIC_SLAVE; + kpic = &chip.chip.pic; + + kpic->last_irr = s->last_irr; + kpic->irr = s->irr; + kpic->imr = s->imr; + kpic->isr = s->isr; + kpic->priority_add = s->priority_add; + kpic->irq_base = s->irq_base; + kpic->read_reg_select = s->read_reg_select; + kpic->poll = s->poll; + kpic->special_mask = s->special_mask; + kpic->init_state = s->init_state; + kpic->auto_eoi = s->auto_eoi; + kpic->rotate_on_auto_eoi = s->rotate_on_auto_eoi; + kpic->special_fully_nested_mode = s->special_fully_nested_mode; + kpic->init4 = s->init4; + kpic->elcr = s->elcr; + kpic->elcr_mask = s->elcr_mask; + + r = kvm_set_irqchip(&chip); +#endif + return r; +} + +static void kvm_kernel_pic_save_to_user(PicState *s) +{ +#if defined(KVM_CAP_IRQCHIP) && defined(TARGET_I386) + struct kvm_irqchip chip; + struct kvm_pic_state *kpic; + + if (!(kvm_enabled() && kvm_irqchip_in_kernel())) + return; + + chip.chip_id = (&s->pics_state->pics[0] == s) ? + KVM_IRQCHIP_PIC_MASTER : + KVM_IRQCHIP_PIC_SLAVE; + kvm_get_irqchip(&chip); + kpic = &chip.chip.pic; + + s->last_irr = kpic->last_irr; + s->irr = kpic->irr; + s->imr = kpic->imr; + s->isr = kpic->isr; + s->priority_add = kpic->priority_add; + s->irq_base = kpic->irq_base; + s->read_reg_select = kpic->read_reg_select; + s->poll = kpic->poll; + s->special_mask = kpic->special_mask; + s->init_state = kpic->init_state; + s->auto_eoi = kpic->auto_eoi; + s->rotate_on_auto_eoi = kpic->rotate_on_auto_eoi; + s->special_fully_nested_mode = kpic->special_fully_nested_mode; + s->init4 = kpic->init4; + s->elcr = kpic->elcr; + s->elcr_mask = kpic->elcr_mask; +#endif +} + +static int i8259_post_load(void *opaque, int version_id) +{ + PicState *s = (void *)opaque; + + return kvm_kernel_pic_load_from_user(s); +} + +static void i8259_pre_save(void *opaque) +{ + PicState *s = (void *)opaque; + + kvm_kernel_pic_save_to_user(s); +} + static const VMStateDescription vmstate_pic = { .name = "i8259", .version_id = 1, + .pre_save = i8259_pre_save, + .post_load = i8259_post_load, .minimum_version_id = 1, .minimum_version_id_old = 1, .fields = (VMStateField []) { @@ -535,3 +623,37 @@ qemu_irq *i8259_init(qemu_irq parent_irq) isa_pic = s; return qemu_allocate_irqs(i8259_set_irq, s, 16); } + +#if defined(KVM_CAP_IRQCHIP) && defined(TARGET_I386) +static void kvm_i8259_set_irq(void *opaque, int irq, int level) +{ + int pic_ret; + if (kvm_set_irq(irq, level, &pic_ret)) { + if (pic_ret != 0) + apic_set_irq_delivered(); + return; + } +} + +static void kvm_pic_init1(int io_addr, PicState *s) +{ + vmstate_register(io_addr, &vmstate_pic, s); + qemu_register_reset(pic_reset, s); +} + +qemu_irq *kvm_i8259_init(qemu_irq parent_irq) +{ + PicState2 *s; + + s = qemu_mallocz(sizeof(PicState2)); + + kvm_pic_init1(0x20, &s->pics[0]); + kvm_pic_init1(0xa0, &s->pics[1]); + s->parent_irq = parent_irq; + s->pics[0].pics_state = s; + s->pics[1].pics_state = s; + isa_pic = s; + return qemu_allocate_irqs(kvm_i8259_set_irq, s, 24); +} +#endif + diff --git a/hw/pc.h b/hw/pc.h index 15d0140..5eed584 100644 --- a/hw/pc.h +++ b/hw/pc.h @@ -27,6 +27,7 @@ extern PicState2 *isa_pic; void pic_set_irq(int irq, int level); void pic_set_irq_new(void *opaque, int irq, int level); qemu_irq *i8259_init(qemu_irq parent_irq); +qemu_irq *kvm_i8259_init(qemu_irq parent_irq); int pic_read_irq(PicState2 *s); void pic_update_irq(PicState2 *s); uint32_t pic_intack_read(PicState2 *s); diff --git a/kvm-all.c b/kvm-all.c index d795285..e98024a 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -431,6 +431,30 @@ int kvm_get_irqchip(struct kvm_irqchip *chip) } #endif +int kvm_set_irq(int irq, int level, int *status) +{ + struct kvm_irq_level event; + int r; + + if (!kvm_state->irqchip_in_kernel) { + return 0; + } + + event.level = level; + event.irq = irq; + + r = kvm_vm_ioctl(kvm_state, KVM_IRQ_LINE_STATUS, &event); + + if (r < 0) + return 0; + + if (status) { + *status = event.status; + } + + return 1; +} + int kvm_init(int smp_cpus) { static const char upgrade_note[] = diff --git a/kvm.h b/kvm.h index 099b55e..f0c9201 100644 --- a/kvm.h +++ b/kvm.h @@ -67,6 +67,8 @@ int kvm_irqchip_in_kernel(void); int kvm_set_irqchip(struct kvm_irqchip *chip); int kvm_get_irqchip(struct kvm_irqchip *chip); +int kvm_set_irq(int irq, int level, int *status); + /* internal API */ struct KVMState; -- 1.6.2.5