xref: /qemu/hw/i386/kvm/i8259.c (revision 2b85e0cd)
154976b75SPaolo Bonzini /*
254976b75SPaolo Bonzini  * KVM in-kernel PIC (i8259) support
354976b75SPaolo Bonzini  *
454976b75SPaolo Bonzini  * Copyright (c) 2011 Siemens AG
554976b75SPaolo Bonzini  *
654976b75SPaolo Bonzini  * Authors:
754976b75SPaolo Bonzini  *  Jan Kiszka          <jan.kiszka@siemens.com>
854976b75SPaolo Bonzini  *
954976b75SPaolo Bonzini  * This work is licensed under the terms of the GNU GPL version 2.
1054976b75SPaolo Bonzini  * See the COPYING file in the top-level directory.
1154976b75SPaolo Bonzini  */
120b8fa32fSMarkus Armbruster 
13b6a0aa05SPeter Maydell #include "qemu/osdep.h"
1454976b75SPaolo Bonzini #include "hw/isa/i8259_internal.h"
15852c27e2SPaolo Bonzini #include "hw/intc/i8259.h"
160b8fa32fSMarkus Armbruster #include "qemu/module.h"
17*2b85e0cdSThomas Huth #include "hw/intc/kvm_irqcount.h"
1864552b6bSMarkus Armbruster #include "hw/irq.h"
1954976b75SPaolo Bonzini #include "sysemu/kvm.h"
20db1015e9SEduardo Habkost #include "qom/object.h"
2154976b75SPaolo Bonzini 
2249fdb0c1SAndreas Färber #define TYPE_KVM_I8259 "kvm-i8259"
23db1015e9SEduardo Habkost typedef struct KVMPICClass KVMPICClass;
248110fa1dSEduardo Habkost DECLARE_CLASS_CHECKERS(KVMPICClass, KVM_PIC,
258110fa1dSEduardo Habkost                        TYPE_KVM_I8259)
26d2628b7dSAndreas Färber 
27d2628b7dSAndreas Färber /**
28d2628b7dSAndreas Färber  * KVMPICClass:
29d2628b7dSAndreas Färber  * @parent_realize: The parent's realizefn.
30d2628b7dSAndreas Färber  */
31db1015e9SEduardo Habkost struct KVMPICClass {
32d2628b7dSAndreas Färber     PICCommonClass parent_class;
33d2628b7dSAndreas Färber 
34d2628b7dSAndreas Färber     DeviceRealize parent_realize;
35db1015e9SEduardo Habkost };
3649fdb0c1SAndreas Färber 
kvm_pic_get(PICCommonState * s)3754976b75SPaolo Bonzini static void kvm_pic_get(PICCommonState *s)
3854976b75SPaolo Bonzini {
3954976b75SPaolo Bonzini     struct kvm_irqchip chip;
4054976b75SPaolo Bonzini     struct kvm_pic_state *kpic;
4154976b75SPaolo Bonzini     int ret;
4254976b75SPaolo Bonzini 
4354976b75SPaolo Bonzini     chip.chip_id = s->master ? KVM_IRQCHIP_PIC_MASTER : KVM_IRQCHIP_PIC_SLAVE;
4454976b75SPaolo Bonzini     ret = kvm_vm_ioctl(kvm_state, KVM_GET_IRQCHIP, &chip);
4554976b75SPaolo Bonzini     if (ret < 0) {
46d84451d3SDmitry Voronetskiy         fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(-ret));
4754976b75SPaolo Bonzini         abort();
4854976b75SPaolo Bonzini     }
4954976b75SPaolo Bonzini 
5054976b75SPaolo Bonzini     kpic = &chip.chip.pic;
5154976b75SPaolo Bonzini 
5254976b75SPaolo Bonzini     s->last_irr = kpic->last_irr;
5354976b75SPaolo Bonzini     s->irr = kpic->irr;
5454976b75SPaolo Bonzini     s->imr = kpic->imr;
5554976b75SPaolo Bonzini     s->isr = kpic->isr;
5654976b75SPaolo Bonzini     s->priority_add = kpic->priority_add;
5754976b75SPaolo Bonzini     s->irq_base = kpic->irq_base;
5854976b75SPaolo Bonzini     s->read_reg_select = kpic->read_reg_select;
5954976b75SPaolo Bonzini     s->poll = kpic->poll;
6054976b75SPaolo Bonzini     s->special_mask = kpic->special_mask;
6154976b75SPaolo Bonzini     s->init_state = kpic->init_state;
6254976b75SPaolo Bonzini     s->auto_eoi = kpic->auto_eoi;
6354976b75SPaolo Bonzini     s->rotate_on_auto_eoi = kpic->rotate_on_auto_eoi;
6454976b75SPaolo Bonzini     s->special_fully_nested_mode = kpic->special_fully_nested_mode;
6554976b75SPaolo Bonzini     s->init4 = kpic->init4;
6654976b75SPaolo Bonzini     s->elcr = kpic->elcr;
6754976b75SPaolo Bonzini     s->elcr_mask = kpic->elcr_mask;
6854976b75SPaolo Bonzini }
6954976b75SPaolo Bonzini 
kvm_pic_put(PICCommonState * s)7054976b75SPaolo Bonzini static void kvm_pic_put(PICCommonState *s)
7154976b75SPaolo Bonzini {
7254976b75SPaolo Bonzini     struct kvm_irqchip chip;
7354976b75SPaolo Bonzini     struct kvm_pic_state *kpic;
7454976b75SPaolo Bonzini     int ret;
7554976b75SPaolo Bonzini 
7654976b75SPaolo Bonzini     chip.chip_id = s->master ? KVM_IRQCHIP_PIC_MASTER : KVM_IRQCHIP_PIC_SLAVE;
7754976b75SPaolo Bonzini 
7854976b75SPaolo Bonzini     kpic = &chip.chip.pic;
7954976b75SPaolo Bonzini 
8054976b75SPaolo Bonzini     kpic->last_irr = s->last_irr;
8154976b75SPaolo Bonzini     kpic->irr = s->irr;
8254976b75SPaolo Bonzini     kpic->imr = s->imr;
8354976b75SPaolo Bonzini     kpic->isr = s->isr;
8454976b75SPaolo Bonzini     kpic->priority_add = s->priority_add;
8554976b75SPaolo Bonzini     kpic->irq_base = s->irq_base;
8654976b75SPaolo Bonzini     kpic->read_reg_select = s->read_reg_select;
8754976b75SPaolo Bonzini     kpic->poll = s->poll;
8854976b75SPaolo Bonzini     kpic->special_mask = s->special_mask;
8954976b75SPaolo Bonzini     kpic->init_state = s->init_state;
9054976b75SPaolo Bonzini     kpic->auto_eoi = s->auto_eoi;
9154976b75SPaolo Bonzini     kpic->rotate_on_auto_eoi = s->rotate_on_auto_eoi;
9254976b75SPaolo Bonzini     kpic->special_fully_nested_mode = s->special_fully_nested_mode;
9354976b75SPaolo Bonzini     kpic->init4 = s->init4;
9454976b75SPaolo Bonzini     kpic->elcr = s->elcr;
9554976b75SPaolo Bonzini     kpic->elcr_mask = s->elcr_mask;
9654976b75SPaolo Bonzini 
9754976b75SPaolo Bonzini     ret = kvm_vm_ioctl(kvm_state, KVM_SET_IRQCHIP, &chip);
9854976b75SPaolo Bonzini     if (ret < 0) {
99d84451d3SDmitry Voronetskiy         fprintf(stderr, "KVM_SET_IRQCHIP failed: %s\n", strerror(-ret));
10054976b75SPaolo Bonzini         abort();
10154976b75SPaolo Bonzini     }
10254976b75SPaolo Bonzini }
10354976b75SPaolo Bonzini 
kvm_pic_reset(DeviceState * dev)10454976b75SPaolo Bonzini static void kvm_pic_reset(DeviceState *dev)
10554976b75SPaolo Bonzini {
10629bb5317SAndreas Färber     PICCommonState *s = PIC_COMMON(dev);
10754976b75SPaolo Bonzini 
10854976b75SPaolo Bonzini     s->elcr = 0;
10954976b75SPaolo Bonzini     pic_reset_common(s);
11054976b75SPaolo Bonzini 
11154976b75SPaolo Bonzini     kvm_pic_put(s);
11254976b75SPaolo Bonzini }
11354976b75SPaolo Bonzini 
kvm_pic_set_irq(void * opaque,int irq,int level)11454976b75SPaolo Bonzini static void kvm_pic_set_irq(void *opaque, int irq, int level)
11554976b75SPaolo Bonzini {
11654976b75SPaolo Bonzini     int delivered;
11754976b75SPaolo Bonzini 
118e267d164SPeter Xu     pic_stat_update_irq(irq, level);
11954976b75SPaolo Bonzini     delivered = kvm_set_irq(kvm_state, irq, level);
120*2b85e0cdSThomas Huth     kvm_report_irq_delivered(delivered);
12154976b75SPaolo Bonzini }
12254976b75SPaolo Bonzini 
kvm_pic_realize(DeviceState * dev,Error ** errp)123d2628b7dSAndreas Färber static void kvm_pic_realize(DeviceState *dev, Error **errp)
12454976b75SPaolo Bonzini {
125d2628b7dSAndreas Färber     PICCommonState *s = PIC_COMMON(dev);
126d2628b7dSAndreas Färber     KVMPICClass *kpc = KVM_PIC_GET_CLASS(dev);
127d2628b7dSAndreas Färber 
128257a7430SPaolo Bonzini     memory_region_init_io(&s->base_io, OBJECT(dev), NULL, NULL, "kvm-pic", 2);
129257a7430SPaolo Bonzini     memory_region_init_io(&s->elcr_io, OBJECT(dev), NULL, NULL, "kvm-elcr", 1);
130d2628b7dSAndreas Färber 
131d2628b7dSAndreas Färber     kpc->parent_realize(dev, errp);
13254976b75SPaolo Bonzini }
13354976b75SPaolo Bonzini 
kvm_i8259_init(ISABus * bus)13454976b75SPaolo Bonzini qemu_irq *kvm_i8259_init(ISABus *bus)
13554976b75SPaolo Bonzini {
13649fdb0c1SAndreas Färber     i8259_init_chip(TYPE_KVM_I8259, bus, true);
13749fdb0c1SAndreas Färber     i8259_init_chip(TYPE_KVM_I8259, bus, false);
13854976b75SPaolo Bonzini 
13954976b75SPaolo Bonzini     return qemu_allocate_irqs(kvm_pic_set_irq, NULL, ISA_NUM_IRQS);
14054976b75SPaolo Bonzini }
14154976b75SPaolo Bonzini 
kvm_i8259_class_init(ObjectClass * klass,void * data)14254976b75SPaolo Bonzini static void kvm_i8259_class_init(ObjectClass *klass, void *data)
14354976b75SPaolo Bonzini {
144d2628b7dSAndreas Färber     KVMPICClass *kpc = KVM_PIC_CLASS(klass);
14554976b75SPaolo Bonzini     PICCommonClass *k = PIC_COMMON_CLASS(klass);
14654976b75SPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
14754976b75SPaolo Bonzini 
14854976b75SPaolo Bonzini     dc->reset     = kvm_pic_reset;
149bf853881SPhilippe Mathieu-Daudé     device_class_set_parent_realize(dc, kvm_pic_realize, &kpc->parent_realize);
15054976b75SPaolo Bonzini     k->pre_save   = kvm_pic_get;
15154976b75SPaolo Bonzini     k->post_load  = kvm_pic_put;
15254976b75SPaolo Bonzini }
15354976b75SPaolo Bonzini 
15454976b75SPaolo Bonzini static const TypeInfo kvm_i8259_info = {
15549fdb0c1SAndreas Färber     .name = TYPE_KVM_I8259,
15654976b75SPaolo Bonzini     .parent = TYPE_PIC_COMMON,
15754976b75SPaolo Bonzini     .instance_size = sizeof(PICCommonState),
15854976b75SPaolo Bonzini     .class_init = kvm_i8259_class_init,
159d2628b7dSAndreas Färber     .class_size = sizeof(KVMPICClass),
16054976b75SPaolo Bonzini };
16154976b75SPaolo Bonzini 
kvm_pic_register_types(void)16254976b75SPaolo Bonzini static void kvm_pic_register_types(void)
16354976b75SPaolo Bonzini {
16454976b75SPaolo Bonzini     type_register_static(&kvm_i8259_info);
16554976b75SPaolo Bonzini }
16654976b75SPaolo Bonzini 
16754976b75SPaolo Bonzini type_init(kvm_pic_register_types)
168