@samitouri / QOSamiQemu / commits / e244989abb

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, &reg);
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, &reg);
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, &reg);
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, &reg);
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 + &reg);
471 + c->gicr_igroupr0 = reg;
472 + hv_gic_get_redistributor_reg(vcpu, HV_GIC_REDISTRIBUTOR_REG_GICR_ISENABLER0,
473 + &reg);
474 + c->gicr_ienabler0 = reg;
475 + hv_gic_get_redistributor_reg(vcpu, HV_GIC_REDISTRIBUTOR_REG_GICR_ICFGR1,
476 + &reg);
477 + c->edge_trigger = half_unshuffle32(reg >> 1) << 16;
478 + hv_gic_get_redistributor_reg(vcpu, HV_GIC_REDISTRIBUTOR_REG_GICR_ISPENDR0,
479 + &reg);
480 + c->gicr_ipendr0 = reg;
481 + hv_gic_get_redistributor_reg(vcpu, HV_GIC_REDISTRIBUTOR_REG_GICR_ISACTIVER0,
482 + &reg);
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, &reg);
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, &reg);
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 >*/