hw/intc: Add hvf vGIC interrupt controller support
This opens up the door to nested virtualisation support. Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org> Message-id: 20260429190532.26538-2-mohamed@unpredictable.fr Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Mohamed Mediouni committed
May 5, 2026 at 09:25 UTC
e244989abb678c5127ee6e752a48a50980e37ea6
3 files changed
+751
hw/intc/arm_gicv3_hvf.c
new
+749
@@ -0,0 +1,749 @@
1
+/* SPDX-License-Identifier: GPL-2.0-or-later */
2
+/*
3
+ * ARM Generic Interrupt Controller using HVF platform support
4
+ *
5
+ * Copyright (c) 2025 Mohamed Mediouni
6
+ * Based on vGICv3 KVM code by Pavel Fedin
7
+ *
8
+ */
9
+
10
+#include "qemu/osdep.h"
11
+#include "qapi/error.h"
12
+#include "hw/intc/arm_gicv3_common.h"
13
+#include "qemu/error-report.h"
14
+#include "qemu/module.h"
15
+#include "system/runstate.h"
16
+#include "system/hvf.h"
17
+#include "system/hvf_int.h"
18
+#include "hvf_arm.h"
19
+#include "gicv3_internal.h"
20
+#include "vgic_common.h"
21
+#include "qom/object.h"
22
+#include "target/arm/cpregs.h"
23
+#include <Hypervisor/Hypervisor.h>
24
+
25
+/*
26
+ * For the GIC, override the check outright, as availability is checked
27
+ * elsewhere
28
+ */
29
+#pragma clang diagnostic push
30
+#pragma clang diagnostic ignored "-Wunguarded-availability"
31
+
32
+struct HVFARMGICv3Class {
33
+ ARMGICv3CommonClass parent_class;
34
+ DeviceRealize parent_realize;
35
+ ResettablePhases parent_phases;
36
+};
37
+
38
+typedef struct HVFARMGICv3Class HVFARMGICv3Class;
39
+
40
+/* This is reusing the GICv3State typedef from ARM_GICV3_ITS_COMMON */
41
+DECLARE_OBJ_CHECKERS(GICv3State, HVFARMGICv3Class,
42
+ HVF_GICV3, TYPE_HVF_GICV3);
43
+
44
+/*
45
+ * Loop through each distributor IRQ related register; since bits
46
+ * corresponding to SPIs and PPIs are RAZ/WI when affinity routing
47
+ * is enabled, we skip those.
48
+ */
49
+#define for_each_dist_irq_reg(_irq, _max, _field_width) \
50
+ for (_irq = GIC_INTERNAL; _irq < _max; _irq += (32 / _field_width))
51
+
52
+/*
53
+ * Wrap calls to the vGIC APIs to assert_hvf_ok()
54
+ * as a macro to keep the code clean.
55
+ */
56
+#define hv_gic_get_distributor_reg(offset, reg) \
57
+ assert_hvf_ok(hv_gic_get_distributor_reg(offset, reg))
58
+
59
+#define hv_gic_set_distributor_reg(offset, reg) \
60
+ assert_hvf_ok(hv_gic_set_distributor_reg(offset, reg))
61
+
62
+#define hv_gic_get_redistributor_reg(vcpu, reg, value) \
63
+ assert_hvf_ok(hv_gic_get_redistributor_reg(vcpu, reg, value))
64
+
65
+#define hv_gic_set_redistributor_reg(vcpu, reg, value) \
66
+ assert_hvf_ok(hv_gic_set_redistributor_reg(vcpu, reg, value))
67
+
68
+#define hv_gic_get_icc_reg(vcpu, reg, value) \
69
+ assert_hvf_ok(hv_gic_get_icc_reg(vcpu, reg, value))
70
+
71
+#define hv_gic_set_icc_reg(vcpu, reg, value) \
72
+ assert_hvf_ok(hv_gic_set_icc_reg(vcpu, reg, value))
73
+
74
+#define hv_gic_get_ich_reg(vcpu, reg, value) \
75
+ assert_hvf_ok(hv_gic_get_ich_reg(vcpu, reg, value))
76
+
77
+#define hv_gic_set_ich_reg(vcpu, reg, value) \
78
+ assert_hvf_ok(hv_gic_set_ich_reg(vcpu, reg, value))
79
+
80
+static void hvf_dist_get_priority(GICv3State *s,
81
+ hv_gic_distributor_reg_t offset,
82
+ uint8_t *bmp)
83
+{
84
+ uint64_t reg;
85
+ uint32_t *field;
86
+ int irq;
87
+ field = (uint32_t *)(bmp);
88
+
89
+ for_each_dist_irq_reg(irq, s->num_irq, 8) {
90
+ hv_gic_get_distributor_reg(offset, ®);
91
+ *field = reg;
92
+ offset += 4;
93
+ field++;
94
+ }
95
+}
96
+
97
+static void hvf_dist_put_priority(GICv3State *s,
98
+ hv_gic_distributor_reg_t offset,
99
+ uint8_t *bmp)
100
+{
101
+ uint32_t reg, *field;
102
+ int irq;
103
+ field = (uint32_t *)(bmp);
104
+
105
+ for_each_dist_irq_reg(irq, s->num_irq, 8) {
106
+ reg = *field;
107
+ hv_gic_set_distributor_reg(offset, reg);
108
+ offset += 4;
109
+ field++;
110
+ }
111
+}
112
+
113
+static void hvf_dist_get_edge_trigger(GICv3State *s,
114
+ hv_gic_distributor_reg_t offset,
115
+ uint32_t *bmp)
116
+{
117
+ uint64_t reg;
118
+ int irq;
119
+
120
+ for_each_dist_irq_reg(irq, s->num_irq, 2) {
121
+ hv_gic_get_distributor_reg(offset, ®);
122
+ reg = half_unshuffle32(reg >> 1);
123
+ if (irq % 32 != 0) {
124
+ reg = (reg << 16);
125
+ }
126
+ *gic_bmp_ptr32(bmp, irq) |= reg;
127
+ offset += 4;
128
+ }
129
+}
130
+
131
+static void hvf_dist_put_edge_trigger(GICv3State *s,
132
+ hv_gic_distributor_reg_t offset,
133
+ uint32_t *bmp)
134
+{
135
+ uint32_t reg;
136
+ int irq;
137
+
138
+ for_each_dist_irq_reg(irq, s->num_irq, 2) {
139
+ reg = *gic_bmp_ptr32(bmp, irq);
140
+ if (irq % 32 != 0) {
141
+ reg = (reg & 0xffff0000) >> 16;
142
+ } else {
143
+ reg = reg & 0xffff;
144
+ }
145
+ reg = half_shuffle32(reg) << 1;
146
+ hv_gic_set_distributor_reg(offset, reg);
147
+ offset += 4;
148
+ }
149
+}
150
+
151
+/* Read a bitmap register group from the kernel VGIC. */
152
+static void hvf_dist_getbmp(GICv3State *s, hv_gic_distributor_reg_t offset,
153
+ uint32_t *bmp)
154
+{
155
+ uint64_t reg;
156
+ int irq;
157
+
158
+ for_each_dist_irq_reg(irq, s->num_irq, 1) {
159
+ hv_gic_get_distributor_reg(offset, ®);
160
+ *gic_bmp_ptr32(bmp, irq) = reg;
161
+ offset += 4;
162
+ }
163
+}
164
+
165
+static void hvf_dist_putbmp(GICv3State *s, hv_gic_distributor_reg_t offset,
166
+ hv_gic_distributor_reg_t clroffset, uint32_t *bmp)
167
+{
168
+ uint32_t reg;
169
+ int irq;
170
+
171
+ for_each_dist_irq_reg(irq, s->num_irq, 1) {
172
+ /*
173
+ * If this bitmap is a set/clear register pair, first write to the
174
+ * clear-reg to clear all bits before using the set-reg to write
175
+ * the 1 bits.
176
+ */
177
+ if (clroffset != 0) {
178
+ reg = 0;
179
+ hv_gic_set_distributor_reg(clroffset, reg);
180
+ clroffset += 4;
181
+ }
182
+ reg = *gic_bmp_ptr32(bmp, irq);
183
+ hv_gic_set_distributor_reg(offset, reg);
184
+ offset += 4;
185
+ }
186
+}
187
+
188
+static void hvf_gicv3_check(GICv3State *s)
189
+{
190
+ uint64_t reg;
191
+ uint32_t num_irq;
192
+
193
+ /* Sanity checking s->num_irq */
194
+ hv_gic_get_distributor_reg(HV_GIC_DISTRIBUTOR_REG_GICD_TYPER, ®);
195
+ num_irq = ((reg & 0x1f) + 1) * 32;
196
+
197
+ if (num_irq < s->num_irq) {
198
+ error_report("Model requests %u IRQs, but HVF supports max %u",
199
+ s->num_irq, num_irq);
200
+ abort();
201
+ }
202
+}
203
+
204
+static void hvf_gicv3_put_cpu_el2(CPUState *cpu_state, run_on_cpu_data arg)
205
+{
206
+ int num_pri_bits;
207
+
208
+ /* Redistributor state */
209
+ GICv3CPUState *c = arg.host_ptr;
210
+ hv_vcpu_t vcpu = c->cpu->accel->fd;
211
+
212
+ hv_gic_set_ich_reg(vcpu, HV_GIC_ICH_REG_VMCR_EL2, c->ich_vmcr_el2);
213
+ hv_gic_set_ich_reg(vcpu, HV_GIC_ICH_REG_HCR_EL2, c->ich_hcr_el2);
214
+
215
+ for (int i = 0; i < GICV3_LR_MAX; i++) {
216
+ hv_gic_set_ich_reg(vcpu, HV_GIC_ICH_REG_LR0_EL2, c->ich_lr_el2[i]);
217
+ }
218
+
219
+ num_pri_bits = c->vpribits;
220
+
221
+ switch (num_pri_bits) {
222
+ case 7:
223
+ hv_gic_set_ich_reg(vcpu, HV_GIC_ICH_REG_AP0R0_EL2 + 3,
224
+ c->ich_apr[GICV3_G0][3]);
225
+ hv_gic_set_ich_reg(vcpu, HV_GIC_ICH_REG_AP0R0_EL2 + 2,
226
+ c->ich_apr[GICV3_G0][2]);
227
+ /* fall through */
228
+ case 6:
229
+ hv_gic_set_ich_reg(vcpu, HV_GIC_ICH_REG_AP0R0_EL2 + 1,
230
+ c->ich_apr[GICV3_G0][1]);
231
+ /* fall through */
232
+ default:
233
+ hv_gic_set_ich_reg(vcpu, HV_GIC_ICH_REG_AP0R0_EL2,
234
+ c->ich_apr[GICV3_G0][0]);
235
+ }
236
+
237
+ switch (num_pri_bits) {
238
+ case 7:
239
+ hv_gic_set_ich_reg(vcpu, HV_GIC_ICH_REG_AP1R0_EL2 + 3,
240
+ c->ich_apr[GICV3_G1NS][3]);
241
+ hv_gic_set_ich_reg(vcpu, HV_GIC_ICH_REG_AP1R0_EL2 + 2,
242
+ c->ich_apr[GICV3_G1NS][2]);
243
+ /* fall through */
244
+ case 6:
245
+ hv_gic_set_ich_reg(vcpu, HV_GIC_ICH_REG_AP1R0_EL2 + 1,
246
+ c->ich_apr[GICV3_G1NS][1]);
247
+ /* fall through */
248
+ default:
249
+ hv_gic_set_ich_reg(vcpu, HV_GIC_ICH_REG_AP1R0_EL2,
250
+ c->ich_apr[GICV3_G1NS][0]);
251
+ }
252
+}
253
+
254
+static void hvf_gicv3_put_cpu(CPUState *cpu_state, run_on_cpu_data arg)
255
+{
256
+ uint32_t reg;
257
+ uint64_t reg64;
258
+ int i, num_pri_bits;
259
+
260
+ /* Redistributor state */
261
+ GICv3CPUState *c = arg.host_ptr;
262
+ hv_vcpu_t vcpu = c->cpu->accel->fd;
263
+
264
+ reg = c->gicr_waker;
265
+ hv_gic_set_redistributor_reg(vcpu, HV_GIC_REDISTRIBUTOR_REG_GICR_IGROUPR0, reg);
266
+
267
+ reg = c->gicr_igroupr0;
268
+ hv_gic_set_redistributor_reg(vcpu, HV_GIC_REDISTRIBUTOR_REG_GICR_IGROUPR0, reg);
269
+
270
+ reg = ~0;
271
+ hv_gic_set_redistributor_reg(vcpu, HV_GIC_REDISTRIBUTOR_REG_GICR_ICENABLER0, reg);
272
+ reg = c->gicr_ienabler0;
273
+ hv_gic_set_redistributor_reg(vcpu, HV_GIC_REDISTRIBUTOR_REG_GICR_ISENABLER0, reg);
274
+
275
+ /* Restore config before pending so we treat level/edge correctly */
276
+ reg = half_shuffle32(c->edge_trigger >> 16) << 1;
277
+ hv_gic_set_redistributor_reg(vcpu, HV_GIC_REDISTRIBUTOR_REG_GICR_ICFGR1, reg);
278
+
279
+ reg = ~0;
280
+ hv_gic_set_redistributor_reg(vcpu, HV_GIC_REDISTRIBUTOR_REG_GICR_ICPENDR0, reg);
281
+ reg = c->gicr_ipendr0;
282
+ hv_gic_set_redistributor_reg(vcpu, HV_GIC_REDISTRIBUTOR_REG_GICR_ISPENDR0, reg);
283
+
284
+ reg = ~0;
285
+ hv_gic_set_redistributor_reg(vcpu, HV_GIC_REDISTRIBUTOR_REG_GICR_ICACTIVER0, reg);
286
+ reg = c->gicr_iactiver0;
287
+ hv_gic_set_redistributor_reg(vcpu, HV_GIC_REDISTRIBUTOR_REG_GICR_ISACTIVER0, reg);
288
+
289
+ for (i = 0; i < GIC_INTERNAL; i += 4) {
290
+ reg = c->gicr_ipriorityr[i] |
291
+ (c->gicr_ipriorityr[i + 1] << 8) |
292
+ (c->gicr_ipriorityr[i + 2] << 16) |
293
+ (c->gicr_ipriorityr[i + 3] << 24);
294
+ hv_gic_set_redistributor_reg(vcpu,
295
+ HV_GIC_REDISTRIBUTOR_REG_GICR_IPRIORITYR0 + i, reg);
296
+ }
297
+
298
+ /* CPU interface state */
299
+ hv_gic_set_icc_reg(vcpu, HV_GIC_ICC_REG_SRE_EL1, c->icc_sre_el1);
300
+
301
+ hv_gic_set_icc_reg(vcpu, HV_GIC_ICC_REG_CTLR_EL1,
302
+ c->icc_ctlr_el1[GICV3_NS]);
303
+ hv_gic_set_icc_reg(vcpu, HV_GIC_ICC_REG_IGRPEN0_EL1,
304
+ c->icc_igrpen[GICV3_G0]);
305
+ hv_gic_set_icc_reg(vcpu, HV_GIC_ICC_REG_IGRPEN1_EL1,
306
+ c->icc_igrpen[GICV3_G1NS]);
307
+ hv_gic_set_icc_reg(vcpu, HV_GIC_ICC_REG_PMR_EL1, c->icc_pmr_el1);
308
+ hv_gic_set_icc_reg(vcpu, HV_GIC_ICC_REG_BPR0_EL1, c->icc_bpr[GICV3_G0]);
309
+ hv_gic_set_icc_reg(vcpu, HV_GIC_ICC_REG_BPR1_EL1, c->icc_bpr[GICV3_G1NS]);
310
+
311
+ num_pri_bits = ((c->icc_ctlr_el1[GICV3_NS] &
312
+ ICC_CTLR_EL1_PRIBITS_MASK) >>
313
+ ICC_CTLR_EL1_PRIBITS_SHIFT) + 1;
314
+
315
+ switch (num_pri_bits) {
316
+ case 7:
317
+ reg64 = c->icc_apr[GICV3_G0][3];
318
+ hv_gic_set_icc_reg(vcpu, HV_GIC_ICC_REG_AP0R0_EL1 + 3, reg64);
319
+ reg64 = c->icc_apr[GICV3_G0][2];
320
+ hv_gic_set_icc_reg(vcpu, HV_GIC_ICC_REG_AP0R0_EL1 + 2, reg64);
321
+ /* fall through */
322
+ case 6:
323
+ reg64 = c->icc_apr[GICV3_G0][1];
324
+ hv_gic_set_icc_reg(vcpu, HV_GIC_ICC_REG_AP0R0_EL1 + 1, reg64);
325
+ /* fall through */
326
+ default:
327
+ reg64 = c->icc_apr[GICV3_G0][0];
328
+ hv_gic_set_icc_reg(vcpu, HV_GIC_ICC_REG_AP0R0_EL1, reg64);
329
+ }
330
+
331
+ switch (num_pri_bits) {
332
+ case 7:
333
+ reg64 = c->icc_apr[GICV3_G1NS][3];
334
+ hv_gic_set_icc_reg(vcpu, HV_GIC_ICC_REG_AP1R0_EL1 + 3, reg64);
335
+ reg64 = c->icc_apr[GICV3_G1NS][2];
336
+ hv_gic_set_icc_reg(vcpu, HV_GIC_ICC_REG_AP1R0_EL1 + 2, reg64);
337
+ /* fall through */
338
+ case 6:
339
+ reg64 = c->icc_apr[GICV3_G1NS][1];
340
+ hv_gic_set_icc_reg(vcpu, HV_GIC_ICC_REG_AP1R0_EL1 + 1, reg64);
341
+ /* fall through */
342
+ default:
343
+ reg64 = c->icc_apr[GICV3_G1NS][0];
344
+ hv_gic_set_icc_reg(vcpu, HV_GIC_ICC_REG_AP1R0_EL1, reg64);
345
+ }
346
+
347
+ /* Registers beyond this point are with nested virt only */
348
+ if (c->gic->maint_irq) {
349
+ hvf_gicv3_put_cpu_el2(cpu_state, arg);
350
+ }
351
+}
352
+
353
+static void hvf_gicv3_put(GICv3State *s)
354
+{
355
+ uint32_t reg;
356
+ int ncpu, i;
357
+
358
+ hvf_gicv3_check(s);
359
+
360
+ reg = s->gicd_ctlr;
361
+ hv_gic_set_distributor_reg(HV_GIC_DISTRIBUTOR_REG_GICD_CTLR, reg);
362
+
363
+ /* per-CPU state */
364
+
365
+ for (ncpu = 0; ncpu < s->num_cpu; ncpu++) {
366
+ run_on_cpu_data data;
367
+ data.host_ptr = &s->cpu[ncpu];
368
+ run_on_cpu(s->cpu[ncpu].cpu, hvf_gicv3_put_cpu, data);
369
+ }
370
+
371
+ /* s->enable bitmap -> GICD_ISENABLERn */
372
+ hvf_dist_putbmp(s, HV_GIC_DISTRIBUTOR_REG_GICD_ISENABLER0,
373
+ HV_GIC_DISTRIBUTOR_REG_GICD_ICENABLER0, s->enabled);
374
+
375
+ /* s->group bitmap -> GICD_IGROUPRn */
376
+ hvf_dist_putbmp(s, HV_GIC_DISTRIBUTOR_REG_GICD_IGROUPR0,
377
+ 0, s->group);
378
+
379
+ /*
380
+ * Restore targets before pending to ensure the pending state is set on
381
+ * the appropriate CPU interfaces in the kernel
382
+ */
383
+
384
+ /* s->gicd_irouter[irq] -> GICD_IROUTERn */
385
+ for (i = GIC_INTERNAL; i < s->num_irq; i++) {
386
+ uint32_t offset = HV_GIC_DISTRIBUTOR_REG_GICD_IROUTER32 + (8 * i)
387
+ - (8 * GIC_INTERNAL);
388
+ hv_gic_set_distributor_reg(offset, s->gicd_irouter[i]);
389
+ }
390
+
391
+ /*
392
+ * s->trigger bitmap -> GICD_ICFGRn
393
+ * (restore configuration registers before pending IRQs so we treat
394
+ * level/edge correctly)
395
+ */
396
+ hvf_dist_put_edge_trigger(s, HV_GIC_DISTRIBUTOR_REG_GICD_ICFGR0, s->edge_trigger);
397
+
398
+ /* s->pending bitmap -> GICD_ISPENDRn */
399
+ hvf_dist_putbmp(s, HV_GIC_DISTRIBUTOR_REG_GICD_ISPENDR0,
400
+ HV_GIC_DISTRIBUTOR_REG_GICD_ICPENDR0, s->pending);
401
+
402
+ /* s->active bitmap -> GICD_ISACTIVERn */
403
+ hvf_dist_putbmp(s, HV_GIC_DISTRIBUTOR_REG_GICD_ISACTIVER0,
404
+ HV_GIC_DISTRIBUTOR_REG_GICD_ICACTIVER0, s->active);
405
+
406
+ /* s->gicd_ipriority[] -> GICD_IPRIORITYRn */
407
+ hvf_dist_put_priority(s, HV_GIC_DISTRIBUTOR_REG_GICD_IPRIORITYR0, s->gicd_ipriority);
408
+}
409
+
410
+static void hvf_gicv3_get_cpu_el2(CPUState *cpu_state, run_on_cpu_data arg)
411
+{
412
+ int num_pri_bits;
413
+
414
+ /* Redistributor state */
415
+ GICv3CPUState *c = arg.host_ptr;
416
+ hv_vcpu_t vcpu = c->cpu->accel->fd;
417
+
418
+ hv_gic_get_ich_reg(vcpu, HV_GIC_ICH_REG_VMCR_EL2, &c->ich_vmcr_el2);
419
+ hv_gic_get_ich_reg(vcpu, HV_GIC_ICH_REG_HCR_EL2, &c->ich_hcr_el2);
420
+
421
+ for (int i = 0; i < GICV3_LR_MAX; i++) {
422
+ hv_gic_get_ich_reg(vcpu, HV_GIC_ICH_REG_LR0_EL2, &c->ich_lr_el2[i]);
423
+ }
424
+
425
+ num_pri_bits = c->vpribits;
426
+
427
+ switch (num_pri_bits) {
428
+ case 7:
429
+ hv_gic_get_ich_reg(vcpu, HV_GIC_ICH_REG_AP0R0_EL2 + 3,
430
+ &c->ich_apr[GICV3_G0][3]);
431
+ hv_gic_get_ich_reg(vcpu, HV_GIC_ICH_REG_AP0R0_EL2 + 2,
432
+ &c->ich_apr[GICV3_G0][2]);
433
+ /* fall through */
434
+ case 6:
435
+ hv_gic_get_ich_reg(vcpu, HV_GIC_ICH_REG_AP0R0_EL2 + 1,
436
+ &c->ich_apr[GICV3_G0][1]);
437
+ /* fall through */
438
+ default:
439
+ hv_gic_get_ich_reg(vcpu, HV_GIC_ICH_REG_AP0R0_EL2,
440
+ &c->ich_apr[GICV3_G0][0]);
441
+ }
442
+
443
+ switch (num_pri_bits) {
444
+ case 7:
445
+ hv_gic_get_ich_reg(vcpu, HV_GIC_ICH_REG_AP1R0_EL2 + 3,
446
+ &c->ich_apr[GICV3_G1NS][3]);
447
+ hv_gic_get_ich_reg(vcpu, HV_GIC_ICH_REG_AP1R0_EL2 + 2,
448
+ &c->ich_apr[GICV3_G1NS][2]);
449
+ /* fall through */
450
+ case 6:
451
+ hv_gic_get_ich_reg(vcpu, HV_GIC_ICH_REG_AP1R0_EL2 + 1,
452
+ &c->ich_apr[GICV3_G1NS][1]);
453
+ /* fall through */
454
+ default:
455
+ hv_gic_get_ich_reg(vcpu, HV_GIC_ICH_REG_AP1R0_EL2,
456
+ &c->ich_apr[GICV3_G1NS][0]);
457
+ }
458
+}
459
+
460
+static void hvf_gicv3_get_cpu(CPUState *cpu_state, run_on_cpu_data arg)
461
+{
462
+ uint64_t reg;
463
+ int i, num_pri_bits;
464
+
465
+ /* Redistributor state */
466
+ GICv3CPUState *c = arg.host_ptr;
467
+ hv_vcpu_t vcpu = c->cpu->accel->fd;
468
+
469
+ hv_gic_get_redistributor_reg(vcpu, HV_GIC_REDISTRIBUTOR_REG_GICR_IGROUPR0,
470
+ ®);
471
+ c->gicr_igroupr0 = reg;
472
+ hv_gic_get_redistributor_reg(vcpu, HV_GIC_REDISTRIBUTOR_REG_GICR_ISENABLER0,
473
+ ®);
474
+ c->gicr_ienabler0 = reg;
475
+ hv_gic_get_redistributor_reg(vcpu, HV_GIC_REDISTRIBUTOR_REG_GICR_ICFGR1,
476
+ ®);
477
+ c->edge_trigger = half_unshuffle32(reg >> 1) << 16;
478
+ hv_gic_get_redistributor_reg(vcpu, HV_GIC_REDISTRIBUTOR_REG_GICR_ISPENDR0,
479
+ ®);
480
+ c->gicr_ipendr0 = reg;
481
+ hv_gic_get_redistributor_reg(vcpu, HV_GIC_REDISTRIBUTOR_REG_GICR_ISACTIVER0,
482
+ ®);
483
+ c->gicr_iactiver0 = reg;
484
+
485
+ for (i = 0; i < GIC_INTERNAL; i += 4) {
486
+ hv_gic_get_redistributor_reg(
487
+ vcpu, HV_GIC_REDISTRIBUTOR_REG_GICR_IPRIORITYR0 + i, ®);
488
+ c->gicr_ipriorityr[i] = extract32(reg, 0, 8);
489
+ c->gicr_ipriorityr[i + 1] = extract32(reg, 8, 8);
490
+ c->gicr_ipriorityr[i + 2] = extract32(reg, 16, 8);
491
+ c->gicr_ipriorityr[i + 3] = extract32(reg, 24, 8);
492
+ }
493
+
494
+ /* CPU interface */
495
+ hv_gic_get_icc_reg(vcpu, HV_GIC_ICC_REG_SRE_EL1, &c->icc_sre_el1);
496
+
497
+ hv_gic_get_icc_reg(vcpu, HV_GIC_ICC_REG_CTLR_EL1,
498
+ &c->icc_ctlr_el1[GICV3_NS]);
499
+ hv_gic_get_icc_reg(vcpu, HV_GIC_ICC_REG_IGRPEN0_EL1,
500
+ &c->icc_igrpen[GICV3_G0]);
501
+ hv_gic_get_icc_reg(vcpu, HV_GIC_ICC_REG_IGRPEN1_EL1,
502
+ &c->icc_igrpen[GICV3_G1NS]);
503
+ hv_gic_get_icc_reg(vcpu, HV_GIC_ICC_REG_PMR_EL1, &c->icc_pmr_el1);
504
+ hv_gic_get_icc_reg(vcpu, HV_GIC_ICC_REG_BPR0_EL1, &c->icc_bpr[GICV3_G0]);
505
+ hv_gic_get_icc_reg(vcpu, HV_GIC_ICC_REG_BPR1_EL1, &c->icc_bpr[GICV3_G1NS]);
506
+ num_pri_bits = ((c->icc_ctlr_el1[GICV3_NS] & ICC_CTLR_EL1_PRIBITS_MASK) >>
507
+ ICC_CTLR_EL1_PRIBITS_SHIFT) +
508
+ 1;
509
+
510
+ switch (num_pri_bits) {
511
+ case 7:
512
+ hv_gic_get_icc_reg(vcpu, HV_GIC_ICC_REG_AP0R0_EL1 + 3,
513
+ &c->icc_apr[GICV3_G0][3]);
514
+ hv_gic_get_icc_reg(vcpu, HV_GIC_ICC_REG_AP0R0_EL1 + 2,
515
+ &c->icc_apr[GICV3_G0][2]);
516
+ /* fall through */
517
+ case 6:
518
+ hv_gic_get_icc_reg(vcpu, HV_GIC_ICC_REG_AP0R0_EL1 + 1,
519
+ &c->icc_apr[GICV3_G0][1]);
520
+ /* fall through */
521
+ default:
522
+ hv_gic_get_icc_reg(vcpu, HV_GIC_ICC_REG_AP0R0_EL1,
523
+ &c->icc_apr[GICV3_G0][0]);
524
+ }
525
+
526
+ switch (num_pri_bits) {
527
+ case 7:
528
+ hv_gic_get_icc_reg(vcpu, HV_GIC_ICC_REG_AP1R0_EL1 + 3,
529
+ &c->icc_apr[GICV3_G1NS][3]);
530
+ hv_gic_get_icc_reg(vcpu, HV_GIC_ICC_REG_AP1R0_EL1 + 2,
531
+ &c->icc_apr[GICV3_G1NS][2]);
532
+ /* fall through */
533
+ case 6:
534
+ hv_gic_get_icc_reg(vcpu, HV_GIC_ICC_REG_AP1R0_EL1 + 1,
535
+ &c->icc_apr[GICV3_G1NS][1]);
536
+ /* fall through */
537
+ default:
538
+ hv_gic_get_icc_reg(vcpu, HV_GIC_ICC_REG_AP1R0_EL1,
539
+ &c->icc_apr[GICV3_G1NS][0]);
540
+ }
541
+
542
+ /* Registers beyond this point are with nested virt only */
543
+ if (c->gic->maint_irq) {
544
+ hvf_gicv3_get_cpu_el2(cpu_state, arg);
545
+ }
546
+}
547
+
548
+static void hvf_gicv3_get(GICv3State *s)
549
+{
550
+ uint64_t reg;
551
+ int ncpu, i;
552
+
553
+ hvf_gicv3_check(s);
554
+
555
+ hv_gic_get_distributor_reg(HV_GIC_DISTRIBUTOR_REG_GICD_CTLR, ®);
556
+ s->gicd_ctlr = reg;
557
+
558
+ /* Redistributor state (one per CPU) */
559
+
560
+ for (ncpu = 0; ncpu < s->num_cpu; ncpu++) {
561
+ run_on_cpu_data data;
562
+ data.host_ptr = &s->cpu[ncpu];
563
+ run_on_cpu(s->cpu[ncpu].cpu, hvf_gicv3_get_cpu, data);
564
+ }
565
+
566
+ /* GICD_IGROUPRn -> s->group bitmap */
567
+ hvf_dist_getbmp(s, HV_GIC_DISTRIBUTOR_REG_GICD_IGROUPR0, s->group);
568
+
569
+ /* GICD_ISENABLERn -> s->enabled bitmap */
570
+ hvf_dist_getbmp(s, HV_GIC_DISTRIBUTOR_REG_GICD_ISENABLER0, s->enabled);
571
+
572
+ /* GICD_ISPENDRn -> s->pending bitmap */
573
+ hvf_dist_getbmp(s, HV_GIC_DISTRIBUTOR_REG_GICD_ISPENDR0, s->pending);
574
+
575
+ /* GICD_ISACTIVERn -> s->active bitmap */
576
+ hvf_dist_getbmp(s, HV_GIC_DISTRIBUTOR_REG_GICD_ISACTIVER0, s->active);
577
+
578
+ /* GICD_ICFGRn -> s->trigger bitmap */
579
+ hvf_dist_get_edge_trigger(s, HV_GIC_DISTRIBUTOR_REG_GICD_ICFGR0,
580
+ s->edge_trigger);
581
+
582
+ /* GICD_IPRIORITYRn -> s->gicd_ipriority[] */
583
+ hvf_dist_get_priority(s, HV_GIC_DISTRIBUTOR_REG_GICD_IPRIORITYR0,
584
+ s->gicd_ipriority);
585
+
586
+ /* GICD_IROUTERn -> s->gicd_irouter[irq] */
587
+ for (i = GIC_INTERNAL; i < s->num_irq; i++) {
588
+ uint32_t offset = HV_GIC_DISTRIBUTOR_REG_GICD_IROUTER32
589
+ + (8 * i) - (8 * GIC_INTERNAL);
590
+ hv_gic_get_distributor_reg(offset, &s->gicd_irouter[i]);
591
+ }
592
+}
593
+
594
+static void hvf_gicv3_set_irq(void *opaque, int irq, int level)
595
+{
596
+ GICv3State *s = opaque;
597
+ if (irq > s->num_irq) {
598
+ return;
599
+ }
600
+ hv_gic_set_spi(GIC_INTERNAL + irq, !!level);
601
+}
602
+
603
+static void hvf_gicv3_icc_reset(CPUARMState *env, const ARMCPRegInfo *ri)
604
+{
605
+ GICv3CPUState *c;
606
+
607
+ c = env->gicv3state;
608
+ c->icc_pmr_el1 = 0;
609
+ /*
610
+ * Architecturally the reset value of the ICC_BPR registers
611
+ * is UNKNOWN. We set them all to 0 here; when the kernel
612
+ * uses these values to program the ICH_VMCR_EL2 fields that
613
+ * determine the guest-visible ICC_BPR register values, the
614
+ * hardware's "writing a value less than the minimum sets
615
+ * the field to the minimum value" behaviour will result in
616
+ * them effectively resetting to the correct minimum value
617
+ * for the host GIC.
618
+ */
619
+ c->icc_bpr[GICV3_G0] = 0;
620
+ c->icc_bpr[GICV3_G1] = 0;
621
+ c->icc_bpr[GICV3_G1NS] = 0;
622
+
623
+ c->icc_sre_el1 = 0x7;
624
+ memset(c->icc_apr, 0, sizeof(c->icc_apr));
625
+ memset(c->icc_igrpen, 0, sizeof(c->icc_igrpen));
626
+}
627
+
628
+static void hvf_gicv3_reset_hold(Object *obj, ResetType type)
629
+{
630
+ GICv3State *s = ARM_GICV3_COMMON(obj);
631
+ HVFARMGICv3Class *kgc = HVF_GICV3_GET_CLASS(s);
632
+
633
+ if (kgc->parent_phases.hold) {
634
+ kgc->parent_phases.hold(obj, type);
635
+ }
636
+
637
+ hvf_gicv3_put(s);
638
+}
639
+
640
+
641
+/*
642
+ * CPU interface registers of GIC needs to be reset on CPU reset.
643
+ * For the calling arm_gicv3_icc_reset() on CPU reset, we register
644
+ * below ARMCPRegInfo. As we reset the whole cpu interface under single
645
+ * register reset, we define only one register of CPU interface instead
646
+ * of defining all the registers.
647
+ */
648
+static const ARMCPRegInfo gicv3_cpuif_reginfo[] = {
649
+ { .name = "ICC_CTLR_EL1", .state = ARM_CP_STATE_BOTH,
650
+ .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 12, .opc2 = 4,
651
+ /*
652
+ * If ARM_CP_NOP is used, resetfn is not called,
653
+ * So ARM_CP_NO_RAW is appropriate type.
654
+ */
655
+ .type = ARM_CP_NO_RAW,
656
+ .access = PL1_RW,
657
+ .readfn = arm_cp_read_zero,
658
+ .writefn = arm_cp_write_ignore,
659
+ /*
660
+ * We hang the whole cpu interface reset routine off here
661
+ * rather than parcelling it out into one little function
662
+ * per register
663
+ */
664
+ .resetfn = hvf_gicv3_icc_reset,
665
+ },
666
+};
667
+
668
+static void hvf_gicv3_realize(DeviceState *dev, Error **errp)
669
+{
670
+ ERRP_GUARD();
671
+ GICv3State *s = HVF_GICV3(dev);
672
+ HVFARMGICv3Class *kgc = HVF_GICV3_GET_CLASS(s);
673
+ int i;
674
+
675
+ kgc->parent_realize(dev, errp);
676
+ if (*errp) {
677
+ return;
678
+ }
679
+
680
+ if (s->revision != 3) {
681
+ error_setg(errp, "unsupported GIC revision %d for platform GIC",
682
+ s->revision);
683
+ }
684
+
685
+ if (s->security_extn) {
686
+ error_setg(errp, "the platform vGICv3 does not implement the "
687
+ "security extensions");
688
+ return;
689
+ }
690
+
691
+ if (s->nmi_support) {
692
+ error_setg(errp, "NMI is not supported with the platform GIC");
693
+ return;
694
+ }
695
+
696
+ if (s->nb_redist_regions > 1) {
697
+ error_setg(errp, "Multiple VGICv3 redistributor regions are not "
698
+ "supported by HVF");
699
+ error_append_hint(errp, "A maximum of %d VCPUs can be used",
700
+ s->redist_region_count[0]);
701
+ return;
702
+ }
703
+
704
+ gicv3_init_irqs_and_mmio(s, hvf_gicv3_set_irq, NULL);
705
+
706
+ for (i = 0; i < s->num_cpu; i++) {
707
+ ARMCPU *cpu = ARM_CPU(qemu_get_cpu(i));
708
+
709
+ define_arm_cp_regs(cpu, gicv3_cpuif_reginfo);
710
+ }
711
+
712
+ if (s->maint_irq && s->maint_irq != HV_GIC_INT_MAINTENANCE) {
713
+ error_setg(errp, "vGIC maintenance IRQ mismatch with the hardcoded one in HVF.");
714
+ return;
715
+ }
716
+}
717
+
718
+static void hvf_gicv3_class_init(ObjectClass *klass, const void *data)
719
+{
720
+ DeviceClass *dc = DEVICE_CLASS(klass);
721
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
722
+ ARMGICv3CommonClass *agcc = ARM_GICV3_COMMON_CLASS(klass);
723
+ HVFARMGICv3Class *kgc = HVF_GICV3_CLASS(klass);
724
+
725
+ agcc->pre_save = hvf_gicv3_get;
726
+ agcc->post_load = hvf_gicv3_put;
727
+
728
+ device_class_set_parent_realize(dc, hvf_gicv3_realize,
729
+ &kgc->parent_realize);
730
+ resettable_class_set_parent_phases(rc, NULL, hvf_gicv3_reset_hold, NULL,
731
+ &kgc->parent_phases);
732
+}
733
+
734
+static const TypeInfo hvf_arm_gicv3_info = {
735
+ .name = TYPE_HVF_GICV3,
736
+ .parent = TYPE_ARM_GICV3_COMMON,
737
+ .instance_size = sizeof(GICv3State),
738
+ .class_init = hvf_gicv3_class_init,
739
+ .class_size = sizeof(HVFARMGICv3Class),
740
+};
741
+
742
+static void hvf_gicv3_register_types(void)
743
+{
744
+ type_register_static(&hvf_arm_gicv3_info);
745
+}
746
+
747
+type_init(hvf_gicv3_register_types)
748
+
749
+#pragma clang diagnostic pop
hw/intc/meson.build
+1
@@ -42,6 +42,7 @@ arm_common_ss.add(when: 'CONFIG_ARM_GIC', if_true: files('arm_gicv3_cpuif_common
42
arm_common_ss.add(when: 'CONFIG_ARM_GICV3', if_true: files('arm_gicv3_cpuif.c'))
43
specific_ss.add(when: 'CONFIG_ARM_GIC_KVM', if_true: files('arm_gic_kvm.c'))
44
specific_ss.add(when: ['CONFIG_WHPX', 'TARGET_AARCH64'], if_true: files('arm_gicv3_whpx.c'))
45
+specific_ss.add(when: ['CONFIG_HVF', 'CONFIG_ARM_GICV3'], if_true: files('arm_gicv3_hvf.c'))
46
specific_ss.add(when: ['CONFIG_ARM_GIC_KVM', 'TARGET_AARCH64'], if_true: files('arm_gicv3_kvm.c', 'arm_gicv3_its_kvm.c'))
47
arm_common_ss.add(when: 'CONFIG_ARM_V7M', if_true: files('armv7m_nvic.c'))
48
specific_ss.add(when: 'CONFIG_GRLIB', if_true: files('grlib_irqmp.c'))
include/hw/intc/arm_gicv3_common.h
+1
@@ -315,6 +315,7 @@ DECLARE_OBJ_CHECKERS(GICv3State, ARMGICv3CommonClass,
315
316
/* Types for GICv3 kernel-irqchip */
317
#define TYPE_WHPX_GICV3 "whpx-arm-gicv3"
318
+#define TYPE_HVF_GICV3 "hvf-arm-gicv3"
319
320
struct ARMGICv3CommonClass {
321
/*< private >*/