]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * KVM in-kernel PIC (i8259) support | |
3 | * | |
4 | * Copyright (c) 2011 Siemens AG | |
5 | * | |
6 | * Authors: | |
7 | * Jan Kiszka <[email protected]> | |
8 | * | |
9 | * This work is licensed under the terms of the GNU GPL version 2. | |
10 | * See the COPYING file in the top-level directory. | |
11 | */ | |
12 | ||
13 | #include "qemu/osdep.h" | |
14 | #include "hw/isa/i8259_internal.h" | |
15 | #include "hw/intc/i8259.h" | |
16 | #include "qemu/module.h" | |
17 | #include "hw/i386/apic_internal.h" | |
18 | #include "hw/irq.h" | |
19 | #include "sysemu/kvm.h" | |
20 | #include "qom/object.h" | |
21 | ||
22 | #define TYPE_KVM_I8259 "kvm-i8259" | |
23 | typedef struct KVMPICClass KVMPICClass; | |
24 | #define KVM_PIC_CLASS(class) \ | |
25 | OBJECT_CLASS_CHECK(KVMPICClass, (class), TYPE_KVM_I8259) | |
26 | #define KVM_PIC_GET_CLASS(obj) \ | |
27 | OBJECT_GET_CLASS(KVMPICClass, (obj), TYPE_KVM_I8259) | |
28 | ||
29 | /** | |
30 | * KVMPICClass: | |
31 | * @parent_realize: The parent's realizefn. | |
32 | */ | |
33 | struct KVMPICClass { | |
34 | PICCommonClass parent_class; | |
35 | ||
36 | DeviceRealize parent_realize; | |
37 | }; | |
38 | ||
39 | static void kvm_pic_get(PICCommonState *s) | |
40 | { | |
41 | struct kvm_irqchip chip; | |
42 | struct kvm_pic_state *kpic; | |
43 | int ret; | |
44 | ||
45 | chip.chip_id = s->master ? KVM_IRQCHIP_PIC_MASTER : KVM_IRQCHIP_PIC_SLAVE; | |
46 | ret = kvm_vm_ioctl(kvm_state, KVM_GET_IRQCHIP, &chip); | |
47 | if (ret < 0) { | |
48 | fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret)); | |
49 | abort(); | |
50 | } | |
51 | ||
52 | kpic = &chip.chip.pic; | |
53 | ||
54 | s->last_irr = kpic->last_irr; | |
55 | s->irr = kpic->irr; | |
56 | s->imr = kpic->imr; | |
57 | s->isr = kpic->isr; | |
58 | s->priority_add = kpic->priority_add; | |
59 | s->irq_base = kpic->irq_base; | |
60 | s->read_reg_select = kpic->read_reg_select; | |
61 | s->poll = kpic->poll; | |
62 | s->special_mask = kpic->special_mask; | |
63 | s->init_state = kpic->init_state; | |
64 | s->auto_eoi = kpic->auto_eoi; | |
65 | s->rotate_on_auto_eoi = kpic->rotate_on_auto_eoi; | |
66 | s->special_fully_nested_mode = kpic->special_fully_nested_mode; | |
67 | s->init4 = kpic->init4; | |
68 | s->elcr = kpic->elcr; | |
69 | s->elcr_mask = kpic->elcr_mask; | |
70 | } | |
71 | ||
72 | static void kvm_pic_put(PICCommonState *s) | |
73 | { | |
74 | struct kvm_irqchip chip; | |
75 | struct kvm_pic_state *kpic; | |
76 | int ret; | |
77 | ||
78 | chip.chip_id = s->master ? KVM_IRQCHIP_PIC_MASTER : KVM_IRQCHIP_PIC_SLAVE; | |
79 | ||
80 | kpic = &chip.chip.pic; | |
81 | ||
82 | kpic->last_irr = s->last_irr; | |
83 | kpic->irr = s->irr; | |
84 | kpic->imr = s->imr; | |
85 | kpic->isr = s->isr; | |
86 | kpic->priority_add = s->priority_add; | |
87 | kpic->irq_base = s->irq_base; | |
88 | kpic->read_reg_select = s->read_reg_select; | |
89 | kpic->poll = s->poll; | |
90 | kpic->special_mask = s->special_mask; | |
91 | kpic->init_state = s->init_state; | |
92 | kpic->auto_eoi = s->auto_eoi; | |
93 | kpic->rotate_on_auto_eoi = s->rotate_on_auto_eoi; | |
94 | kpic->special_fully_nested_mode = s->special_fully_nested_mode; | |
95 | kpic->init4 = s->init4; | |
96 | kpic->elcr = s->elcr; | |
97 | kpic->elcr_mask = s->elcr_mask; | |
98 | ||
99 | ret = kvm_vm_ioctl(kvm_state, KVM_SET_IRQCHIP, &chip); | |
100 | if (ret < 0) { | |
101 | fprintf(stderr, "KVM_SET_IRQCHIP failed: %s\n", strerror(ret)); | |
102 | abort(); | |
103 | } | |
104 | } | |
105 | ||
106 | static void kvm_pic_reset(DeviceState *dev) | |
107 | { | |
108 | PICCommonState *s = PIC_COMMON(dev); | |
109 | ||
110 | s->elcr = 0; | |
111 | pic_reset_common(s); | |
112 | ||
113 | kvm_pic_put(s); | |
114 | } | |
115 | ||
116 | static void kvm_pic_set_irq(void *opaque, int irq, int level) | |
117 | { | |
118 | int delivered; | |
119 | ||
120 | pic_stat_update_irq(irq, level); | |
121 | delivered = kvm_set_irq(kvm_state, irq, level); | |
122 | apic_report_irq_delivered(delivered); | |
123 | } | |
124 | ||
125 | static void kvm_pic_realize(DeviceState *dev, Error **errp) | |
126 | { | |
127 | PICCommonState *s = PIC_COMMON(dev); | |
128 | KVMPICClass *kpc = KVM_PIC_GET_CLASS(dev); | |
129 | ||
130 | memory_region_init_io(&s->base_io, OBJECT(dev), NULL, NULL, "kvm-pic", 2); | |
131 | memory_region_init_io(&s->elcr_io, OBJECT(dev), NULL, NULL, "kvm-elcr", 1); | |
132 | ||
133 | kpc->parent_realize(dev, errp); | |
134 | } | |
135 | ||
136 | qemu_irq *kvm_i8259_init(ISABus *bus) | |
137 | { | |
138 | i8259_init_chip(TYPE_KVM_I8259, bus, true); | |
139 | i8259_init_chip(TYPE_KVM_I8259, bus, false); | |
140 | ||
141 | return qemu_allocate_irqs(kvm_pic_set_irq, NULL, ISA_NUM_IRQS); | |
142 | } | |
143 | ||
144 | static void kvm_i8259_class_init(ObjectClass *klass, void *data) | |
145 | { | |
146 | KVMPICClass *kpc = KVM_PIC_CLASS(klass); | |
147 | PICCommonClass *k = PIC_COMMON_CLASS(klass); | |
148 | DeviceClass *dc = DEVICE_CLASS(klass); | |
149 | ||
150 | dc->reset = kvm_pic_reset; | |
151 | device_class_set_parent_realize(dc, kvm_pic_realize, &kpc->parent_realize); | |
152 | k->pre_save = kvm_pic_get; | |
153 | k->post_load = kvm_pic_put; | |
154 | } | |
155 | ||
156 | static const TypeInfo kvm_i8259_info = { | |
157 | .name = TYPE_KVM_I8259, | |
158 | .parent = TYPE_PIC_COMMON, | |
159 | .instance_size = sizeof(PICCommonState), | |
160 | .class_init = kvm_i8259_class_init, | |
161 | .class_size = sizeof(KVMPICClass), | |
162 | }; | |
163 | ||
164 | static void kvm_pic_register_types(void) | |
165 | { | |
166 | type_register_static(&kvm_i8259_info); | |
167 | } | |
168 | ||
169 | type_init(kvm_pic_register_types) |