@samitouri / QOSamiQemu / commits / ce245ac695

target/arm: GICv5 cpuif: Calculate the highest priority PPI

When the state of PPIs changes, recalculate the highest priority PPI. In subsequent commits we will use this cached value to provide the HPPI info to the guest, decide whether to signal IRQ or FIQ, handle interrupt acknowldge from the guest, and so on. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com> Message-id: 20260327111700.795099-43-peter.maydell@linaro.org

Peter Maydell committed Mar 27, 2026 at 11:16 UTC ce245ac6957192e8295fe85e01eec722ca37ed29
6 files changed +89
include/hw/intc/arm_gicv5_types.h
+21
@@ -12,6 +12,8 @@
12 #ifndef HW_INTC_ARM_GICv5_TYPES_H
13 #define HW_INTC_ARM_GICv5_TYPES_H
14
15 +#include "hw/core/registerfields.h"
16 +
17 /*
18 * The GICv5 has four physical Interrupt Domains. This numbering must
19 * match the encoding used in IRS_IDR0.INT_DOM.
@@ -86,4 +88,23 @@ typedef enum GICv5TriggerMode {
88
89 #define PRIO_IDLE 0xff
90
91 +/*
92 + * We keep track of candidate highest possible pending interrupts
93 + * using this struct.
94 + *
95 + * Unlike GICv3, we don't need a separate NMI bool, because for GICv5
96 + * superpriority is signaled by @prio == 0.
97 + *
98 + * In this struct the intid includes the interrupt type in bits
99 + * [31:29] (i.e. it is in the form defined by R_TJPHS).
100 + */
101 +typedef struct GICv5PendingIrq {
102 + uint32_t intid;
103 + uint8_t prio;
104 +} GICv5PendingIrq;
105 +
106 +/* Fields in a generic 32-bit INTID, per R_TJPHS */
107 +FIELD(INTID, ID, 0, 24)
108 +FIELD(INTID, TYPE, 29, 3)
109 +
110 #endif
meson.build
+1
@@ -3688,6 +3688,7 @@ if have_system or have_user
3688 'hw/core',
3689 'target/arm',
3690 'target/arm/hvf',
3691 + 'target/arm/tcg',
3692 'target/hppa',
3693 'target/i386',
3694 'target/i386/kvm',
target/arm/cpu.h
+3
@@ -611,6 +611,9 @@ typedef struct CPUArchState {
611 uint64_t ppi_enable[GICV5_NUM_PPIS / 64];
612 /* The PRIO regs have 1 byte per PPI, so 8 PPIs to a register */
613 uint64_t ppi_priority[GICV5_NUM_PPIS / 8];
614 +
615 + /* Cached highest-priority pending PPI for each domain */
616 + GICv5PendingIrq ppi_hppi[NUM_GICV5_DOMAINS];
617 } gicv5_cpuif;
618
619 struct {
target/arm/tcg/gicv5-cpuif.c
+58
@@ -11,6 +11,7 @@
11 #include "internals.h"
12 #include "cpregs.h"
13 #include "hw/intc/arm_gicv5_stream.h"
14 +#include "trace.h"
15
16 FIELD(GIC_CDPRI, ID, 0, 24)
17 FIELD(GIC_CDPRI, TYPE, 29, 3)
@@ -105,6 +106,57 @@ static uint64_t gic_running_prio(CPUARMState *env, GICv5Domain domain)
106 return hap < 32 ? hap : PRIO_IDLE;
107 }
108
109 +static void gic_recalc_ppi_hppi(CPUARMState *env)
110 +{
111 + /*
112 + * Recalculate the HPPI PPI: this is the best PPI which is
113 + * enabled, pending and not active.
114 + */
115 + for (int i = 0; i < ARRAY_SIZE(env->gicv5_cpuif.ppi_hppi); i++) {
116 + env->gicv5_cpuif.ppi_hppi[i].intid = 0;
117 + env->gicv5_cpuif.ppi_hppi[i].prio = PRIO_IDLE;
118 + };
119 +
120 + for (int i = 0; i < ARRAY_SIZE(env->gicv5_cpuif.ppi_active); i++) {
121 + uint64_t en_pend_nact = env->gicv5_cpuif.ppi_enable[i] &
122 + env->gicv5_cpuif.ppi_pend[i] &
123 + ~env->gicv5_cpuif.ppi_active[i];
124 +
125 + while (en_pend_nact) {
126 + /*
127 + * When EL3 is supported ICC_PPI_DOMAINR<n>_EL3 tells us
128 + * the domain of each PPI. While we only support EL1, the
129 + * domain is always NS.
130 + */
131 + GICv5Domain ppi_domain = GICV5_ID_NS;
132 + uint8_t prio;
133 + int ppi;
134 + int bit = ctz64(en_pend_nact);
135 +
136 + en_pend_nact &= ~(1 << bit);
137 +
138 + ppi = i * 64 + bit;
139 + prio = extract64(env->gicv5_cpuif.ppi_priority[ppi / 8],
140 + (ppi & 7) * 8, 5);
141 +
142 + if (prio < env->gicv5_cpuif.ppi_hppi[ppi_domain].prio) {
143 + uint32_t intid = 0;
144 +
145 + intid = FIELD_DP32(intid, INTID, ID, ppi);
146 + intid = FIELD_DP32(intid, INTID, TYPE, GICV5_PPI);
147 + env->gicv5_cpuif.ppi_hppi[ppi_domain].intid = intid;
148 + env->gicv5_cpuif.ppi_hppi[ppi_domain].prio = prio;
149 + }
150 + }
151 + }
152 +
153 + for (int i = 0; i < ARRAY_SIZE(env->gicv5_cpuif.ppi_hppi); i++) {
154 + trace_gicv5_recalc_ppi_hppi(i,
155 + env->gicv5_cpuif.ppi_hppi[i].intid,
156 + env->gicv5_cpuif.ppi_hppi[i].prio);
157 + }
158 +}
159 +
160 static void gic_cddis_write(CPUARMState *env, const ARMCPRegInfo *ri,
161 uint64_t value)
162 {
@@ -200,6 +252,7 @@ static void gic_ppi_cactive_write(CPUARMState *env, const ARMCPRegInfo *ri,
252 {
253 uint64_t old = raw_read(env, ri);
254 raw_write(env, ri, old & ~value);
255 + gic_recalc_ppi_hppi(env);
256 }
257
258 static void gic_ppi_sactive_write(CPUARMState *env, const ARMCPRegInfo *ri,
@@ -207,6 +260,7 @@ static void gic_ppi_sactive_write(CPUARMState *env, const ARMCPRegInfo *ri,
260 {
261 uint64_t old = raw_read(env, ri);
262 raw_write(env, ri, old | value);
263 + gic_recalc_ppi_hppi(env);
264 }
265
266 static void gic_ppi_cpend_write(CPUARMState *env, const ARMCPRegInfo *ri,
@@ -217,6 +271,7 @@ static void gic_ppi_cpend_write(CPUARMState *env, const ARMCPRegInfo *ri,
271 uint64_t hm = env->gicv5_cpuif.ppi_hm[ri->opc2 & 1];
272 value &= ~hm;
273 raw_write(env, ri, old & ~value);
274 + gic_recalc_ppi_hppi(env);
275 }
276
277 static void gic_ppi_spend_write(CPUARMState *env, const ARMCPRegInfo *ri,
@@ -227,18 +282,21 @@ static void gic_ppi_spend_write(CPUARMState *env, const ARMCPRegInfo *ri,
282 uint64_t hm = env->gicv5_cpuif.ppi_hm[ri->opc2 & 1];
283 value &= ~hm;
284 raw_write(env, ri, old | value);
285 + gic_recalc_ppi_hppi(env);
286 }
287
288 static void gic_ppi_enable_write(CPUARMState *env, const ARMCPRegInfo *ri,
289 uint64_t value)
290 {
291 raw_write(env, ri, value);
292 + gic_recalc_ppi_hppi(env);
293 }
294
295 static void gic_ppi_priority_write(CPUARMState *env, const ARMCPRegInfo *ri,
296 uint64_t value)
297 {
298 raw_write(env, ri, value);
299 + gic_recalc_ppi_hppi(env);
300 }
301
302 /*
target/arm/tcg/trace-events new
+5
@@ -0,0 +1,5 @@
1 +# SPDX-License-Identifier: GPL-2.0-or-later
2 +# See docs/devel/tracing.rst for syntax documentation.
3 +
4 +# gicv5-cpuif.c
5 +gicv5_recalc_ppi_hppi(int domain, uint32_t id, uint8_t prio) "domain %d new PPI HPPI id 0x%x prio %u"
target/arm/tcg/trace.h new
+1
@@ -0,0 +1 @@
1 +#include "trace/trace-target_arm_tcg.h"