The qdev link property array gives the IRS a pointer to each CPU that is connected to it, but the CPU also needs a pointer to the IRS so that it can issue commands. Set this up in a similar way to how we do it for the GICv3: have the GIC's realize function call gicv5_set_gicv5state() to set a pointer in the CPUARMState.
The CPU will only allow this link to be made if it actually implements the GICv5 CPU interface; it will be the responsibility of the board code to configure the CPU to have a GICv5 cpuif if it wants to connect a GICv5 to it. Signed-off-by: Peter Maydell <[email protected]> --- hw/intc/arm_gicv5_common.c | 9 +++++++++ include/hw/intc/arm_gicv5_stream.h | 32 ++++++++++++++++++++++++++++++ target/arm/cpu.c | 16 +++++++++++++++ target/arm/cpu.h | 2 ++ 4 files changed, 59 insertions(+) create mode 100644 include/hw/intc/arm_gicv5_stream.h diff --git a/hw/intc/arm_gicv5_common.c b/hw/intc/arm_gicv5_common.c index 620ae3b88f..046dcdf5a3 100644 --- a/hw/intc/arm_gicv5_common.c +++ b/hw/intc/arm_gicv5_common.c @@ -8,6 +8,7 @@ #include "qemu/osdep.h" #include "hw/intc/arm_gicv5_common.h" +#include "hw/intc/arm_gicv5_stream.h" #include "hw/core/qdev-properties.h" #include "qapi/error.h" #include "trace.h" @@ -129,6 +130,14 @@ static void gicv5_common_realize(DeviceState *dev, Error **errp) return; } + for (int i = 0; i < cs->num_cpus; i++) { + if (!gicv5_set_gicv5state(cs->cpus[i], cs)) { + error_setg(errp, + "CPU %d does not implement GICv5 CPU interface", i); + return; + } + } + address_space_init(&cs->dma_as, cs->dma, "gicv5-sysmem"); trace_gicv5_common_realize(cs->irsid, cs->num_cpus, diff --git a/include/hw/intc/arm_gicv5_stream.h b/include/hw/intc/arm_gicv5_stream.h new file mode 100644 index 0000000000..9b9c2e4b60 --- /dev/null +++ b/include/hw/intc/arm_gicv5_stream.h @@ -0,0 +1,32 @@ +/* + * Interface between GICv5 CPU interface and GICv5 IRS + * Loosely modelled on the GICv5 Stream Protocol interface documented + * in the GICv5 specification. + * + * Copyright (c) 2025 Linaro Limited + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_INTC_ARM_GICV5_STREAM_H +#define HW_INTC_ARM_GICV5_STREAM_H + +#include "target/arm/cpu-qom.h" + +typedef struct GICv5Common GICv5Common; + +/** + * gicv5_set_gicv5state + * @cpu: CPU object to tell about its IRS + * @cs: the GIC IRS it is connected to + * + * 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 + * connected to. + * + * Returns true on success, false if the CPU doesn't implement + * the GICv5 CPU interface. + */ +bool gicv5_set_gicv5state(ARMCPU *cpu, GICv5Common *cs); + +#endif diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 10f8280eef..ef2afca6b9 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -41,6 +41,7 @@ #include "hw/core/boards.h" #ifdef CONFIG_TCG #include "hw/intc/armv7m_nvic.h" +#include "hw/intc/arm_gicv5_stream.h" #endif /* CONFIG_TCG */ #endif /* !CONFIG_USER_ONLY */ #include "system/tcg.h" @@ -1085,6 +1086,21 @@ static void arm_cpu_dump_state(CPUState *cs, FILE *f, int flags) } } +#ifndef CONFIG_USER_ONLY +bool gicv5_set_gicv5state(ARMCPU *cpu, GICv5Common *cs) +{ + /* + * Set this CPU's gicv5state pointer to point to the GIC that we are + * connected to. + */ + if (!cpu_isar_feature(aa64_gcie, cpu)) { + return false; + } + cpu->env.gicv5state = cs; + return true; +} +#endif + uint64_t arm_build_mp_affinity(int idx, uint8_t clustersz) { uint32_t Aff1 = idx / clustersz; diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 657ff4ab20..16de0ebfa8 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -812,6 +812,8 @@ 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; #else /* CONFIG_USER_ONLY */ /* For usermode syscall translation. */ bool eabi; -- 2.43.0
