@samitouri / QOSamiQemu / commits / 9edad4ff31

target/arm: GICv5 cpuif: Implement ICC_HPPIR_EL1

Implement ICC_HPPIR_EL1, which the guest can use to read the current highest priority pending interrupt. Like APR, PCR and CR0, this is banked, with the _EL1 register reading the answer for the current logical interrupt domain, and the _EL3 register reading the answer for the EL3 interrupt domain. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com> Message-id: 20260327111700.795099-47-peter.maydell@linaro.org

Peter Maydell committed Mar 27, 2026 at 11:16 UTC 9edad4ff31cbb2f1e46e80e8f33699a5a387201f
3 files changed +84
hw/intc/arm_gicv5.c
+10
@@ -527,6 +527,16 @@ static void irs_recall_hppis(GICv5 *s, GICv5Domain domain)
527 }
528 }
529
530 +GICv5PendingIrq gicv5_get_hppi(GICv5Common *cs, GICv5Domain domain,
531 + uint32_t iaffid)
532 +{
533 + GICv5 *s = ARM_GICV5(cs);
534 + int cpuidx = irs_cpuidx_from_iaffid(cs, iaffid);
535 +
536 + assert(cpuidx >= 0);
537 + return s->hppi[domain][cpuidx];
538 +}
539 +
540 static hwaddr l1_iste_addr(GICv5Common *cs, const GICv5ISTConfig *cfg,
541 uint32_t id)
542 {
include/hw/intc/arm_gicv5_stream.h
+13
@@ -175,4 +175,17 @@ uint64_t gicv5_request_config(GICv5Common *cs, uint32_t id, GICv5Domain domain,
175 */
176 void gicv5_forward_interrupt(ARMCPU *cpu, GICv5Domain domain);
177
178 +/**
179 + * gicv5_get_hppi
180 + * @cs: GIC IRS to query
181 + * @domain: interrupt domain to act on
182 + * @iaffid: IAFFID of this CPU interface
183 + *
184 + * Ask the IRS for the highest priority pending interrupt that it has
185 + * for this CPU. This returns the equivalent of what in the stream
186 + * protocol is the outstanding interrupt sent with a Forward packet.
187 + */
188 +GICv5PendingIrq gicv5_get_hppi(GICv5Common *cs, GICv5Domain domain,
189 + uint32_t iaffid);
190 +
191 #endif
target/arm/tcg/gicv5-cpuif.c
+61
@@ -51,6 +51,10 @@ FIELD(ICC_CR0, PID, 38, 1)
51
52 FIELD(ICC_PCR, PRIORITY, 0, 5)
53
54 +FIELD(ICC_HPPIR_EL1, ID, 0, 24)
55 +FIELD(ICC_HPPIR_EL1, TYPE, 29, 3)
56 +FIELD(ICC_HPPIR_EL1, HPPIV, 32, 1)
57 +
58 /*
59 * We implement 24 bits of interrupt ID, the mandated 5 bits of priority,
60 * and no legacy GICv3.3 vcpu interface (yet)
@@ -114,6 +118,51 @@ static uint64_t gic_running_prio(CPUARMState *env, GICv5Domain domain)
118 return hap < 32 ? hap : PRIO_IDLE;
119 }
120
121 +static GICv5PendingIrq gic_hppi(CPUARMState *env, GICv5Domain domain)
122 +{
123 + /*
124 + * Return the current highest priority pending interrupt for the
125 + * specified domain, if it has sufficient priority to preempt. The
126 + * intid field of the return value will be in the format of the
127 + * ICC_HPPIR register (and will be zero if and only if there is no
128 + * interrupt that can preempt).
129 + */
130 +
131 + GICv5Common *gic = gicv5_get_gic(env);
132 + GICv5PendingIrq best, irs_hppi;
133 +
134 + if (!(env->gicv5_cpuif.icc_cr0[domain] & R_ICC_CR0_EN_MASK)) {
135 + /* If cpuif is disabled there is no HPPI */
136 + return (GICv5PendingIrq) { .intid = 0, .prio = PRIO_IDLE };
137 + }
138 +
139 + irs_hppi = gicv5_get_hppi(gic, domain, env->gicv5_iaffid);
140 +
141 + /*
142 + * If the best PPI and the best interrupt from the IRS have the
143 + * same priority, it's IMPDEF which we pick (R_VVBPS). We choose
144 + * the PPI.
145 + */
146 + if (env->gicv5_cpuif.ppi_hppi[domain].prio <= irs_hppi.prio) {
147 + best = env->gicv5_cpuif.ppi_hppi[domain];
148 + } else {
149 + best = irs_hppi;
150 + }
151 +
152 + /*
153 + * D_MSQKF: an interrupt has sufficient priority if its priority
154 + * is higher than the current running priority and equal to or
155 + * higher than the priority mask.
156 + */
157 + if (best.prio == PRIO_IDLE ||
158 + best.prio > env->gicv5_cpuif.icc_pcr[domain] ||
159 + best.prio >= gic_running_prio(env, domain)) {
160 + return (GICv5PendingIrq) { .intid = 0, .prio = PRIO_IDLE };
161 + }
162 + best.intid |= R_ICC_HPPIR_EL1_HPPIV_MASK;
163 + return best;
164 +}
165 +
166 static void gic_recalc_ppi_hppi(CPUARMState *env)
167 {
168 /*
@@ -407,6 +456,13 @@ static void gic_icc_pcr_el1_reset(CPUARMState *env, const ARMCPRegInfo *ri)
456 }
457 }
458
459 +static uint64_t gic_icc_hppir_el1_read(CPUARMState *env, const ARMCPRegInfo *ri)
460 +{
461 + GICv5Domain domain = gicv5_logical_domain(env);
462 + GICv5PendingIrq hppi = gic_hppi(env, domain);
463 + return hppi.intid;
464 +}
465 +
466 static const ARMCPRegInfo gicv5_cpuif_reginfo[] = {
467 /*
468 * Barrier: wait until the effects of a cpuif system register
@@ -522,6 +578,11 @@ static const ARMCPRegInfo gicv5_cpuif_reginfo[] = {
578 .fieldoffset = offsetof(CPUARMState, gicv5_cpuif.ppi_hm[1]),
579 .resetvalue = PPI_HMR1_RESET,
580 },
581 + { .name = "ICC_HPPIR_EL1", .state = ARM_CP_STATE_AA64,
582 + .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 10, .opc2 = 3,
583 + .access = PL1_R, .type = ARM_CP_IO | ARM_CP_NO_RAW,
584 + .readfn = gic_icc_hppir_el1_read,
585 + },
586 { .name = "ICC_PPI_ENABLER0_EL1", .state = ARM_CP_STATE_AA64,
587 .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 10, .opc2 = 6,
588 .access = PL1_RW, .type = ARM_CP_IO | ARM_CP_NO_RAW,