Commit d88a57b2ac for qemu.org
commit d88a57b2ac7a5ee5b4157ac6c3edc50355e7e4de
Author: Peter Maydell <peter.maydell@linaro.org>
Date: Tue Oct 13 09:38:16 2026 +0100
hw/intc/arm_gicv5: Pass CPU index to CPU interface
In a real hardware GICv5, the IRS knows which CPU is talking to it
because each IRS<->cpuif link is a separate 1:1 connection. In
QEMU's implementation, the cpuif code calls functions like
gicv5_set_priority(), and currently we usually don't pass anything to
tell the IRS which cpuif is making the call, because mostly the IRS
doesn't need to care. There are a few places where it does need to
know, notably in gicv5_get_hppi(). Here we have the cpuif pass its
IAFFID; the IRS then looks that up by doing a linear search of the
cpu_iaffids[] array to get the index of the CPU.
For virtualization, many of the stream commands which don't currently
need to say which cpuif is making the call will have to start doing
so, because changing the state of a virtual interrupt requires the
IRS to look up the VPE which is resident on the calling cpuif. This
makes the IAFFID->cpuidx lookup seem increasingly awkward.
Change gicv5_set_gicv5state() to pass the IRS's CPU index value for
the cpuif as well as the guest-visible IAFFID, and make the stream
functions identify the cpuif by CPU index rather than IAFFID, to
avoid the unnecessary IAFFID->cpuidx lookup.
As this is now three GICv5-related things that we are keeping in the
CPU state struct, we push them into a sub-struct to keep them tidy.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
diff --git a/hw/intc/arm_gicv5_common.c b/hw/intc/arm_gicv5_common.c
index b155486af6..2920b11cc3 100644
--- a/hw/intc/arm_gicv5_common.c
+++ b/hw/intc/arm_gicv5_common.c
@@ -173,7 +173,7 @@ static void gicv5_common_realize(DeviceState *dev, Error **errp)
}
for (int i = 0; i < cs->num_cpus; i++) {
- if (!gicv5_set_gicv5state(cs->cpus[i], cs, cs->cpu_iaffids[i])) {
+ if (!gicv5_set_gicv5state(cs->cpus[i], cs, cs->cpu_iaffids[i], i)) {
error_setg(errp,
"CPU %d (IAFFID 0x%x) does not implement GICv5 CPU interface",
i, cs->cpu_iaffids[i]);
diff --git a/include/hw/intc/arm_gicv5_stream.h b/include/hw/intc/arm_gicv5_stream.h
index 3cc9f61155..f45072d8c5 100644
--- a/include/hw/intc/arm_gicv5_stream.h
+++ b/include/hw/intc/arm_gicv5_stream.h
@@ -20,7 +20,8 @@ typedef struct GICv5Common GICv5Common;
* gicv5_set_gicv5state
* @cpu: CPU object to tell about its IRS
* @cs: the GIC IRS it is connected to
- * @iaffid: the IAFFID of this CPU
+ * @iaffid: the IAFFID of this CPU (guest-visible)
+ * @cpuidx: the index of this CPU for this IRS (QEMU-internal)
*
* Set the CPU object's GICv5 pointer to point to this GIC IRS. The
* IRS must call this when it is realized, for each CPU it is
@@ -29,7 +30,8 @@ typedef struct GICv5Common GICv5Common;
* Returns true on success, false if the CPU doesn't implement the
* GICv5 CPU interface.
*/
-bool gicv5_set_gicv5state(ARMCPU *cpu, GICv5Common *cs, uint32_t iaffid);
+bool gicv5_set_gicv5state(ARMCPU *cpu, GICv5Common *cs, uint32_t iaffid,
+ uint32_t cpuidx);
/*
* The architected Stream Protocol is asynchronous; commands can be
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 0ae0d581be..71681447b2 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -1215,17 +1215,19 @@ static void arm_cpu_dump_state(CPUState *cs, FILE *f, int flags)
}
#ifndef CONFIG_USER_ONLY
-bool gicv5_set_gicv5state(ARMCPU *cpu, GICv5Common *cs, uint32_t iaffid)
+bool gicv5_set_gicv5state(ARMCPU *cpu, GICv5Common *cs, uint32_t iaffid,
+ uint32_t cpuidx)
{
/*
* Set this CPU's gicv5state pointer to point to the GIC that we are
- * connected to, and record our IAFFID.
+ * connected to, and record our IAFFID and CPU index.
*/
if (!cpu_isar_feature(aa64_gcie, cpu)) {
return false;
}
- cpu->env.gicv5state = cs;
- cpu->env.gicv5_iaffid = iaffid;
+ cpu->env.gicv5.gicv5state = cs;
+ cpu->env.gicv5.iaffid = iaffid;
+ cpu->env.gicv5.cpuidx = cpuidx;
return true;
}
#endif
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index dae79539b5..b2f393f501 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -816,10 +816,12 @@ typedef struct CPUArchState {
const struct arm_boot_info *boot_info;
/* Store GICv3CPUState to access from this struct */
void *gicv3state;
- /* Similarly, for a GICv5Common */
- void *gicv5state;
- /* For GICv5, this CPU's IAFFID */
- uint64_t gicv5_iaffid;
+ /* Information the GICv5 IRS passes to us */
+ struct {
+ void *gicv5state; /* GICv5Common struct */
+ uint64_t iaffid; /* this CPU's IAFFID */
+ uint32_t cpuidx; /* GIC IRS-internal index of this CPU */
+ } gicv5;
#else /* CONFIG_USER_ONLY */
/* For usermode syscall translation. */
bool eabi;
diff --git a/target/arm/tcg/gicv5-cpuif.c b/target/arm/tcg/gicv5-cpuif.c
index e7b80b8375..74c456f60c 100644
--- a/target/arm/tcg/gicv5-cpuif.c
+++ b/target/arm/tcg/gicv5-cpuif.c
@@ -87,7 +87,7 @@ FIELD(ICC_HPPIR_EL1, HPPIV, 32, 1)
static GICv5Common *gicv5_get_gic(CPUARMState *env)
{
- return env->gicv5state;
+ return env->gicv5.gicv5state;
}
static GICv5Domain gicv5_logical_domain(CPUARMState *env)
@@ -147,7 +147,7 @@ static GICv5PendingIrq gic_hppi(CPUARMState *env, GICv5Domain domain)
return GICV5_PENDING_IRQ_NONE;
}
- irs_hppi = gicv5_get_hppi(gic, domain, env->gicv5_iaffid);
+ irs_hppi = gicv5_get_hppi(gic, domain, env->gicv5.iaffid);
/*
* If the best PPI and the best interrupt from the IRS have the
@@ -788,7 +788,7 @@ static const ARMCPRegInfo gicv5_cpuif_reginfo[] = {
.opc0 = 3, .opc1 = 0, .crn = 12, .crm = 10, .opc2 = 5,
.access = PL1_R, .type = ARM_CP_NO_RAW,
/* ICC_IAFFIDR_EL1 holds the IAFFID only, in its low bits */
- .fieldoffset = offsetof(CPUARMState, gicv5_iaffid),
+ .fieldoffset = offsetof(CPUARMState, gicv5.iaffid),
/*
* The field is a constant value set in gicv5_set_gicv5state(),
* so don't allow it to be overwritten by reset.