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