1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21#include "qemu/osdep.h"
22#include "gic_internal.h"
23#include "hw/arm/linux-boot-if.h"
24#include "qapi/error.h"
25#include "hw/fdt_generic_util.h"
26
27#include "hw/fdt_generic_devices.h"
28
29static int gic_pre_save(void *opaque)
30{
31 GICState *s = (GICState *)opaque;
32 ARMGICCommonClass *c = ARM_GIC_COMMON_GET_CLASS(s);
33
34 if (c->pre_save) {
35 c->pre_save(s);
36 }
37
38 return 0;
39}
40
41static int gic_post_load(void *opaque, int version_id)
42{
43 GICState *s = (GICState *)opaque;
44 ARMGICCommonClass *c = ARM_GIC_COMMON_GET_CLASS(s);
45
46 if (c->post_load) {
47 c->post_load(s);
48 }
49 return 0;
50}
51
52static const VMStateDescription vmstate_gic_irq_state = {
53 .name = "arm_gic_irq_state",
54 .version_id = 1,
55 .minimum_version_id = 1,
56 .fields = (VMStateField[]) {
57 VMSTATE_UINT8(enabled, gic_irq_state),
58 VMSTATE_UINT8(pending, gic_irq_state),
59 VMSTATE_UINT8(active, gic_irq_state),
60 VMSTATE_UINT8(level, gic_irq_state),
61 VMSTATE_BOOL(model, gic_irq_state),
62 VMSTATE_BOOL(edge_trigger, gic_irq_state),
63 VMSTATE_END_OF_LIST()
64 }
65};
66
67static const VMStateDescription vmstate_gic = {
68 .name = "arm_gic",
69 .version_id = 8,
70 .minimum_version_id = 8,
71 .pre_save = gic_pre_save,
72 .post_load = gic_post_load,
73 .fields = (VMStateField[]) {
74 VMSTATE_BOOL(enabled, GICState),
75 VMSTATE_UINT32_ARRAY(ctrl, GICState, GIC_NCPU),
76 VMSTATE_STRUCT_ARRAY(irq_state, GICState, GIC_MAXIRQ, 1,
77 vmstate_gic_irq_state, gic_irq_state),
78 VMSTATE_UINT8_ARRAY(irq_target, GICState, GIC_MAXIRQ),
79 VMSTATE_UINT8_2DARRAY(priority1, GICState, GIC_INTERNAL, GIC_NCPU),
80 VMSTATE_UINT8_ARRAY(priority2, GICState, GIC_MAXIRQ - GIC_INTERNAL),
81 VMSTATE_UINT16_2DARRAY(last_active, GICState, GIC_MAXIRQ, GIC_NCPU),
82 VMSTATE_UINT8_2DARRAY(sgi_pending, GICState, GIC_NR_SGIS, GIC_NCPU),
83 VMSTATE_UINT16_ARRAY(priority_mask, GICState, GIC_NCPU),
84 VMSTATE_UINT16_ARRAY(running_irq, GICState, GIC_NCPU),
85 VMSTATE_UINT16_ARRAY(running_priority, GICState, GIC_NCPU),
86 VMSTATE_UINT16_ARRAY(current_pending, GICState, GIC_NCPU),
87 VMSTATE_UINT8_ARRAY(bpr, GICState, GIC_NCPU),
88 VMSTATE_UINT8_ARRAY(abpr, GICState, GIC_NCPU),
89 VMSTATE_UINT32_2DARRAY(apr, GICState, GIC_NR_APRS, GIC_NCPU),
90 VMSTATE_UINT32_ARRAY(gich.hcr, GICState, GIC_N_REALCPU),
91 VMSTATE_UINT32_ARRAY(gich.vtr, GICState, GIC_N_REALCPU),
92 VMSTATE_UINT32_ARRAY(gich.misr, GICState, GIC_N_REALCPU),
93 VMSTATE_UINT64_ARRAY(gich.eisr, GICState, GIC_N_REALCPU),
94 VMSTATE_UINT64_ARRAY(gich.elrsr, GICState, GIC_N_REALCPU),
95 VMSTATE_UINT32_ARRAY(gich.apr, GICState, GIC_N_REALCPU),
96 VMSTATE_UINT32_2DARRAY(gich.lr, GICState, GIC_N_REALCPU, GICV_NR_LR),
97 VMSTATE_UINT32_ARRAY(gich.pending_prio, GICState, GIC_N_REALCPU),
98 VMSTATE_UINT8_ARRAY(gich.pending_lrn, GICState, GIC_N_REALCPU),
99 VMSTATE_END_OF_LIST()
100 }
101};
102
103void gic_init_irqs_and_mmio(GICState *s, qemu_irq_handler handler,
104 const MemoryRegionOps *ops)
105{
106 SysBusDevice *sbd = SYS_BUS_DEVICE(s);
107 int i = s->num_irq - GIC_INTERNAL;
108
109
110
111
112
113
114
115
116 i += (GIC_INTERNAL * s->num_cpu);
117 qdev_init_gpio_in(DEVICE(s), handler, i);
118
119 for (i = 0; i < s->num_cpu; i++) {
120 sysbus_init_irq(sbd, &s->parent_irq[i]);
121 }
122 for (i = 0; i < s->num_cpu; i++) {
123 sysbus_init_irq(sbd, &s->parent_fiq[i]);
124 }
125 for (i = 0; i < s->num_cpu; i++) {
126 sysbus_init_irq(sbd, &s->parent_virq[i]);
127 }
128 for (i = 0; i < s->num_cpu; i++) {
129 sysbus_init_irq(sbd, &s->parent_vfiq[i]);
130 }
131
132
133 memory_region_init_io(&s->iomem, OBJECT(s), ops, s, "gic_dist", 0x1000);
134 sysbus_init_mmio(sbd, &s->iomem);
135
136
137
138
139 memory_region_init_io(&s->cpuiomem[0], OBJECT(s), ops ? &ops[1] : NULL,
140 s, "gic_cpu", s->revision == 2 ? 0x2000 : 0x100);
141 sysbus_init_mmio(sbd, &s->cpuiomem[0]);
142}
143
144static void arm_gic_common_realize(DeviceState *dev, Error **errp)
145{
146 GICState *s = ARM_GIC_COMMON(dev);
147 int num_irq = s->num_irq;
148
149 if (!s->num_cpu) {
150 s->num_cpu = fdt_generic_num_cpus;
151 }
152
153 if (s->num_cpu > GIC_NCPU) {
154 error_setg(errp, "requested %u CPUs exceeds GIC maximum %d",
155 s->num_cpu, GIC_NCPU);
156 return;
157 }
158 s->num_irq += GIC_BASE_IRQ;
159 if (s->num_irq > GIC_MAXIRQ) {
160 error_setg(errp,
161 "requested %u interrupt lines exceeds GIC maximum %d",
162 num_irq, GIC_MAXIRQ);
163 return;
164 }
165
166
167
168
169 if (s->num_irq < 32 || (s->num_irq % 32)) {
170 error_setg(errp,
171 "%d interrupt lines unsupported: not divisible by 32",
172 num_irq);
173 return;
174 }
175}
176
177static void arm_gic_common_reset(DeviceState *dev)
178{
179 GICState *s = ARM_GIC_COMMON(dev);
180 int i;
181 int resetprio;
182
183
184
185
186
187
188
189
190 if (s->security_extn && s->irq_reset_nonsecure) {
191 resetprio = 0x80;
192 } else {
193 resetprio = 0;
194 }
195
196 memset(s->irq_state, 0, GIC_MAXIRQ * sizeof(gic_irq_state));
197 for (i = 0 ; i < GIC_NCPU; i++) {
198 if (s->revision == REV_11MPCORE) {
199 s->priority_mask[i] = 0xf0;
200 } else {
201 s->priority_mask[i] = resetprio;
202 }
203 s->current_pending[i] = 1023;
204 s->running_irq[i] = 1023;
205 s->running_priority[i] = 0x100;
206 s->ctrl[i] = 0;
207 }
208 for (i = 0; i < GIC_NR_SGIS; i++) {
209 GIC_SET_ENABLED(i, ALL_CPU_MASK);
210 GIC_SET_EDGE_TRIGGER(i);
211 }
212 if (s->num_cpu == 1) {
213
214 for (i = 0; i < GIC_MAXIRQ; i++) {
215 s->irq_target[i] = 1;
216 }
217 }
218
219 if (s->security_extn && s->irq_reset_nonsecure) {
220 for (i = 0 ; i < s->num_irq; ++i) {
221 s->irq_state[i].group = 1;
222 }
223 }
224
225 if (!s->c_iidr) {
226 s->c_iidr |= s->revision << 16;
227 s->c_iidr |= 0x43B;
228 }
229 s->enabled = false;
230}
231
232static int arm_gic_common_fdt_get_irq(FDTGenericIntc *obj, qemu_irq *irqs,
233 uint32_t *cells, int ncells, int max,
234 Error **errp)
235{
236 GICState *gs = ARM_GIC_COMMON(obj);
237 int cpu = 0;
238 uint32_t idx;
239
240 if (ncells != 3) {
241 error_setg(errp, "ARM GIC requires 3 interrupt cells, %d cells given",
242 ncells);
243 return 0;
244 }
245 idx = cells[1];
246
247 switch (cells[0]) {
248 case 0:
249 if (idx >= gs->num_irq) {
250 error_setg(errp, "ARM GIC SPI has maximum index of %" PRId32 ", "
251 "index %" PRId32 " given", gs->num_irq - 1, idx);
252 return 0;
253 }
254 (*irqs) = qdev_get_gpio_in(DEVICE(obj), cells[1]);
255 return 1;
256 case 1:
257 if (idx >= 16) {
258 error_setg(errp, "ARM GIC PPI has maximum index of 15, "
259 "index %" PRId32 " given", idx);
260 return 0;
261 }
262 for (cpu = 0; cpu < max && cpu < gs->num_cpu; cpu++) {
263 if (cells[2] & 1 << (cpu + 8)) {
264 *irqs = qdev_get_gpio_in(DEVICE(obj),
265 gs->num_irq - 16 + idx + cpu * 32);
266 }
267 irqs++;
268 }
269 return cpu;
270 default:
271 error_setg(errp, "Invalid cell 0 value in interrupt binding: %d",
272 cells[0]);
273 return 0;
274 }
275}
276
277static void arm_gic_common_linux_init(ARMLinuxBootIf *obj,
278 bool secure_boot)
279{
280 GICState *s = ARM_GIC_COMMON(obj);
281
282 if (!s->disable_linux_gic_init && s->security_extn && !secure_boot) {
283
284
285
286
287
288
289
290 s->irq_reset_nonsecure = true;
291 }
292}
293
294static Property arm_gic_common_properties[] = {
295 DEFINE_PROP_UINT32("num-cpu", GICState, num_cpu, 0),
296 DEFINE_PROP_UINT32("num-irq", GICState, num_irq, 96),
297
298
299
300 DEFINE_PROP_UINT32("revision", GICState, revision, 1),
301 DEFINE_PROP_BOOL("disable-linux-gic-init", GICState,
302 disable_linux_gic_init, false),
303 DEFINE_PROP_UINT32("map-stride", GICState, map_stride, 0x1000),
304
305 DEFINE_PROP_UINT32("int-id", GICState, c_iidr, 0),
306
307 DEFINE_PROP_BOOL("has-security-extensions", GICState, security_extn, true),
308 DEFINE_PROP_END_OF_LIST(),
309};
310
311static void arm_gic_common_class_init(ObjectClass *klass, void *data)
312{
313 DeviceClass *dc = DEVICE_CLASS(klass);
314 FDTGenericIntcClass *fgic = FDT_GENERIC_INTC_CLASS(klass);
315 ARMLinuxBootIfClass *albifc = ARM_LINUX_BOOT_IF_CLASS(klass);
316
317 dc->reset = arm_gic_common_reset;
318 dc->realize = arm_gic_common_realize;
319 dc->props = arm_gic_common_properties;
320 dc->vmsd = &vmstate_gic;
321 fgic->get_irq = arm_gic_common_fdt_get_irq;
322 albifc->arm_linux_init = arm_gic_common_linux_init;
323}
324
325static const TypeInfo arm_gic_common_type = {
326 .name = TYPE_ARM_GIC_COMMON,
327 .parent = TYPE_SYS_BUS_DEVICE,
328 .instance_size = sizeof(GICState),
329 .class_size = sizeof(ARMGICCommonClass),
330 .class_init = arm_gic_common_class_init,
331 .interfaces = (InterfaceInfo[]) {
332 { TYPE_ARM_LINUX_BOOT_IF },
333 { TYPE_FDT_GENERIC_INTC },
334 { TYPE_FDT_GENERIC_GPIO },
335 { }
336 },
337 .abstract = true,
338};
339
340static void register_types(void)
341{
342 type_register_static(&arm_gic_common_type);
343}
344
345type_init(register_types)
346