@@ -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
+
@@ -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);
@@ -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[] =
@@ -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;
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 <glommer@redhat.com> --- hw/i8259.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/pc.h | 1 + kvm-all.c | 24 ++++++++++++ kvm.h | 2 + 4 files changed, 149 insertions(+), 0 deletions(-)