1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22#include "qemu/osdep.h"
23#include "qapi/error.h"
24#include "qemu/module.h"
25#include "monitor/monitor.h"
26#include "hw/i386/ioapic.h"
27#include "hw/i386/ioapic_internal.h"
28#include "hw/intc/intc.h"
29#include "hw/sysbus.h"
30
31
32
33
34
35
36
37int ioapic_no;
38
39void ioapic_stat_update_irq(IOAPICCommonState *s, int irq, int level)
40{
41 if (level != s->irq_level[irq]) {
42 s->irq_level[irq] = level;
43 if (level == 1) {
44 s->irq_count[irq]++;
45 }
46 }
47}
48
49static bool ioapic_get_statistics(InterruptStatsProvider *obj,
50 uint64_t **irq_counts,
51 unsigned int *nb_irqs)
52{
53 IOAPICCommonState *s = IOAPIC_COMMON(obj);
54
55 *irq_counts = s->irq_count;
56 *nb_irqs = IOAPIC_NUM_PINS;
57
58 return true;
59}
60
61static void ioapic_irr_dump(Monitor *mon, const char *name, uint32_t bitmap)
62{
63 int i;
64
65 monitor_printf(mon, "%-10s ", name);
66 if (bitmap == 0) {
67 monitor_printf(mon, "(none)\n");
68 return;
69 }
70 for (i = 0; i < IOAPIC_NUM_PINS; i++) {
71 if (bitmap & (1 << i)) {
72 monitor_printf(mon, "%-2u ", i);
73 }
74 }
75 monitor_printf(mon, "\n");
76}
77
78void ioapic_print_redtbl(Monitor *mon, IOAPICCommonState *s)
79{
80 static const char *delm_str[] = {
81 "fixed", "lowest", "SMI", "...", "NMI", "INIT", "...", "extINT"};
82 uint32_t remote_irr = 0;
83 int i;
84
85 monitor_printf(mon, "ioapic0: ver=0x%x id=0x%02x sel=0x%02x",
86 s->version, s->id, s->ioregsel);
87 if (s->ioregsel) {
88 monitor_printf(mon, " (redir[%u])\n",
89 (s->ioregsel - IOAPIC_REG_REDTBL_BASE) >> 1);
90 } else {
91 monitor_printf(mon, "\n");
92 }
93 for (i = 0; i < IOAPIC_NUM_PINS; i++) {
94 uint64_t entry = s->ioredtbl[i];
95 uint32_t delm = (uint32_t)((entry & IOAPIC_LVT_DELIV_MODE) >>
96 IOAPIC_LVT_DELIV_MODE_SHIFT);
97 monitor_printf(mon, " pin %-2u 0x%016"PRIx64" dest=%"PRIx64
98 " vec=%-3"PRIu64" %s %-5s %-6s %-6s %s\n",
99 i, entry,
100 (entry >> IOAPIC_LVT_DEST_SHIFT) &
101 (entry & IOAPIC_LVT_DEST_MODE ? 0xff : 0xf),
102 entry & IOAPIC_VECTOR_MASK,
103 entry & IOAPIC_LVT_POLARITY ? "active-lo" : "active-hi",
104 entry & IOAPIC_LVT_TRIGGER_MODE ? "level" : "edge",
105 entry & IOAPIC_LVT_MASKED ? "masked" : "",
106 delm_str[delm],
107 entry & IOAPIC_LVT_DEST_MODE ? "logical" : "physical");
108
109 remote_irr |= entry & IOAPIC_LVT_TRIGGER_MODE ?
110 (entry & IOAPIC_LVT_REMOTE_IRR ? (1 << i) : 0) : 0;
111 }
112 ioapic_irr_dump(mon, " IRR", s->irr);
113 ioapic_irr_dump(mon, " Remote IRR", remote_irr);
114}
115
116void ioapic_reset_common(DeviceState *dev)
117{
118 IOAPICCommonState *s = IOAPIC_COMMON(dev);
119 int i;
120
121 s->id = 0;
122 s->ioregsel = 0;
123 s->irr = 0;
124 for (i = 0; i < IOAPIC_NUM_PINS; i++) {
125 s->ioredtbl[i] = 1 << IOAPIC_LVT_MASKED_SHIFT;
126 }
127}
128
129static int ioapic_dispatch_pre_save(void *opaque)
130{
131 IOAPICCommonState *s = IOAPIC_COMMON(opaque);
132 IOAPICCommonClass *info = IOAPIC_COMMON_GET_CLASS(s);
133
134 if (info->pre_save) {
135 info->pre_save(s);
136 }
137
138 return 0;
139}
140
141static int ioapic_dispatch_post_load(void *opaque, int version_id)
142{
143 IOAPICCommonState *s = IOAPIC_COMMON(opaque);
144 IOAPICCommonClass *info = IOAPIC_COMMON_GET_CLASS(s);
145
146 if (info->post_load) {
147 info->post_load(s);
148 }
149 return 0;
150}
151
152static void ioapic_common_realize(DeviceState *dev, Error **errp)
153{
154 IOAPICCommonState *s = IOAPIC_COMMON(dev);
155 IOAPICCommonClass *info;
156
157 if (ioapic_no >= MAX_IOAPICS) {
158 error_setg(errp, "Only %d ioapics allowed", MAX_IOAPICS);
159 return;
160 }
161
162 info = IOAPIC_COMMON_GET_CLASS(s);
163 info->realize(dev, errp);
164
165 sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->io_memory);
166 ioapic_no++;
167}
168
169static void ioapic_print_info(InterruptStatsProvider *obj,
170 Monitor *mon)
171{
172 IOAPICCommonState *s = IOAPIC_COMMON(obj);
173
174 ioapic_dispatch_pre_save(s);
175 ioapic_print_redtbl(mon, s);
176}
177
178static const VMStateDescription vmstate_ioapic_common = {
179 .name = "ioapic",
180 .version_id = 3,
181 .minimum_version_id = 1,
182 .pre_save = ioapic_dispatch_pre_save,
183 .post_load = ioapic_dispatch_post_load,
184 .fields = (VMStateField[]) {
185 VMSTATE_UINT8(id, IOAPICCommonState),
186 VMSTATE_UINT8(ioregsel, IOAPICCommonState),
187 VMSTATE_UNUSED_V(2, 8),
188 VMSTATE_UINT32_V(irr, IOAPICCommonState, 2),
189 VMSTATE_UINT64_ARRAY(ioredtbl, IOAPICCommonState, IOAPIC_NUM_PINS),
190 VMSTATE_END_OF_LIST()
191 }
192};
193
194static void ioapic_common_class_init(ObjectClass *klass, void *data)
195{
196 DeviceClass *dc = DEVICE_CLASS(klass);
197 InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(klass);
198
199 dc->realize = ioapic_common_realize;
200 dc->vmsd = &vmstate_ioapic_common;
201 ic->print_info = ioapic_print_info;
202 ic->get_statistics = ioapic_get_statistics;
203}
204
205static const TypeInfo ioapic_common_type = {
206 .name = TYPE_IOAPIC_COMMON,
207 .parent = TYPE_SYS_BUS_DEVICE,
208 .instance_size = sizeof(IOAPICCommonState),
209 .class_size = sizeof(IOAPICCommonClass),
210 .class_init = ioapic_common_class_init,
211 .abstract = true,
212 .interfaces = (InterfaceInfo[]) {
213 { TYPE_INTERRUPT_STATS_PROVIDER },
214 { }
215 },
216};
217
218static void ioapic_common_register_types(void)
219{
220 type_register_static(&ioapic_common_type);
221}
222
223type_init(ioapic_common_register_types)
224