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