@samitouri / QOSamiQemu / commits / 1ec925f75d

hw/intc/arm_gicv5: Create and validate QOM properties

Add code to the GICv5 skeleton which creates the QOM properties which the board or SoC can use to configure the GIC, and the validation code to check they are in range. Generally these correspond to fields in the IRS ID registers, and the properties are named correspondingly. Notable here is that unlike the GICv3 (which assumes its connected CPUs are the system's CPUs starting from 0), we define a QOM array property which is an array of pointers to the CPUs, and a QOM array property which is an array of integers telling the GIC what the IAFFID (interrupt affinity ID) for each CPU is; so a board or SoC which wants to connect multiple CPUs to this GICv5 would do something like: QList *cpulist = qlist_new(), *iaffidlist = qlist_new(); for (int i = 0; i < ms->smp.cpus; i++) { qlist_append_link(cpulist, OBJECT(qemu_get_cpu(i))); qlist_append_int(iaffidlist, i); } qdev_prop_set_array(vms->gic, "cpus", cpulist); qdev_prop_set_array(vms->gic, "cpu-iaffids", iaffidlist); Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-id: 20260327111700.795099-8-peter.maydell@linaro.org

Peter Maydell committed Mar 27, 2026 at 11:16 UTC 1ec925f75de8ae1cc6369c1bd215b0715d0d329f
3 files changed +108
hw/intc/arm_gicv5_common.c
+80
@@ -8,9 +8,15 @@
8
9 #include "qemu/osdep.h"
10 #include "hw/intc/arm_gicv5_common.h"
11 +#include "hw/core/qdev-properties.h"
12 +#include "qapi/error.h"
13 +#include "trace.h"
14
15 OBJECT_DEFINE_ABSTRACT_TYPE(GICv5Common, gicv5_common, ARM_GICV5_COMMON, SYS_BUS_DEVICE)
16
17 +/* Any value > 2^24 is out of the valid range for this property */
18 +#define GICV5_SPI_IRS_RANGE_NOT_SET 0xffffffff
19 +
20 static bool bad_frame_accepts(void *opaque, hwaddr addr, unsigned size,
21 bool is_write, MemTxAttrs attrs)
22 {
@@ -58,9 +64,83 @@ static void gicv5_common_finalize(Object *obj)
64 {
65 }
66
67 +static void gicv5_common_realize(DeviceState *dev, Error **errp)
68 +{
69 + GICv5Common *cs = ARM_GICV5_COMMON(dev);
70 +
71 + if (cs->num_cpus == 0) {
72 + error_setg(errp, "The cpus array property must have at least one CPU");
73 + return;
74 + }
75 + if (cs->num_cpus >= (1 << 16)) {
76 + /* We'll hit other QEMU limits long before this one :-) */
77 + error_setg(errp, "Number of CPUs exceeds GICv5 architectural maximum");
78 + return;
79 + }
80 + if (cs->num_cpus != cs->num_cpu_iaffids) {
81 + error_setg(errp, "The cpu-iaffids array property must be the same size "
82 + "as the cpus array property");
83 + return;
84 + }
85 + if (cs->irsid >= (1 << 16)) {
86 + error_setg(errp, "irsid (%u) is more than 2^16-1", cs->irsid);
87 + return;
88 + }
89 + if (cs->spi_range > (1 << 24)) {
90 + /*
91 + * Note that IRS_IDR5.SPI_RANGE is a 25 bit field but the largest
92 + * architecturally permitted value is 2^24 (not 2^25-1), hence
93 + * use of > in the range check.
94 + */
95 + error_setg(errp, "spi-range (%u) is more than 2^24", cs->spi_range);
96 + return;
97 + }
98 + if (cs->spi_irs_range == GICV5_SPI_IRS_RANGE_NOT_SET) {
99 + /* spi-irs-range defaults to same as spi-range */
100 + cs->spi_irs_range = cs->spi_range;
101 + }
102 + if (cs->spi_irs_range > (1 << 24)) {
103 + /* Similarly IRS_IDR6.SPI_IRS_RANGE */
104 + error_setg(errp, "spi-irs-range (%u) is more than 2^24",
105 + cs->spi_irs_range);
106 + return;
107 + }
108 + if (cs->spi_base >= (1 << 24)) {
109 + /* IRS_IDR7.SPI_BASE is a 24-bit field, so range check is >= */
110 + error_setg(errp, "spi-base (%u) is more than 2^24-1", cs->spi_base);
111 + return;
112 + }
113 + /* range checks above mean we know this addition won't overflow */
114 + if (cs->spi_base + cs->spi_irs_range > cs->spi_range) {
115 + error_setg(errp, "spi-base (%u) + spi-irs-range (%u) is "
116 + "more than spi-range (%u)",
117 + cs->spi_base, cs->spi_irs_range, cs->spi_range);
118 + return;
119 + }
120 +
121 + trace_gicv5_common_realize(cs->irsid, cs->num_cpus,
122 + cs->spi_base, cs->spi_irs_range, cs->spi_range);
123 +}
124 +
125 +static const Property arm_gicv5_common_properties[] = {
126 + DEFINE_PROP_LINK_ARRAY("cpus", GICv5Common, num_cpus,
127 + cpus, TYPE_ARM_CPU, ARMCPU *),
128 + DEFINE_PROP_ARRAY("cpu-iaffids", GICv5Common, num_cpu_iaffids,
129 + cpu_iaffids, qdev_prop_uint32, uint32_t),
130 + DEFINE_PROP_UINT32("irsid", GICv5Common, irsid, 0),
131 + DEFINE_PROP_UINT32("spi-range", GICv5Common, spi_range, 0),
132 + DEFINE_PROP_UINT32("spi-base", GICv5Common, spi_base, 0),
133 + DEFINE_PROP_UINT32("spi-irs-range", GICv5Common, spi_irs_range,
134 + GICV5_SPI_IRS_RANGE_NOT_SET),
135 +};
136 +
137 static void gicv5_common_class_init(ObjectClass *oc, const void *data)
138 {
139 ResettableClass *rc = RESETTABLE_CLASS(oc);
140 + DeviceClass *dc = DEVICE_CLASS(oc);
141
142 rc->phases.hold = gicv5_common_reset_hold;
143 +
144 + dc->realize = gicv5_common_realize;
145 + device_class_set_props(dc, arm_gicv5_common_properties);
146 }
hw/intc/trace-events
+3
@@ -233,6 +233,9 @@ gicv5_badread(const char *domain, uint64_t offset, unsigned size) "GICv5 IRS %s
233 gicv5_write(const char *domain, uint64_t offset, uint64_t data, unsigned size) "GICv5 IRS %s config frame write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
234 gicv5_badwrite(const char *domain, uint64_t offset, uint64_t data, unsigned size) "GICv5 IRS %s config frame write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u: error"
235
236 +# arm_gicv5_common.c
237 +gicv5_common_realize(uint32_t irsid, uint32_t num_cpus, uint32_t spi_base, uint32_t spi_irs_range, uint32_t spi_range) "GICv5 IRS realized: IRS ID %u, %u CPUs, SPI base %u, SPI IRS range %u, SPI range %u"
238 +
239 # armv7m_nvic.c
240 nvic_recompute_state(int vectpending, int vectpending_prio, int exception_prio) "NVIC state recomputed: vectpending %d vectpending_prio %d exception_prio %d"
241 nvic_recompute_state_secure(int vectpending, bool vectpending_is_s_banked, int vectpending_prio, int exception_prio) "NVIC state recomputed: vectpending %d is_s_banked %d vectpending_prio %d exception_prio %d"
include/hw/intc/arm_gicv5_common.h
+25
@@ -12,10 +12,24 @@
12 #include "qom/object.h"
13 #include "hw/core/sysbus.h"
14 #include "hw/intc/arm_gicv5_types.h"
15 +#include "target/arm/cpu-qom.h"
16
17 /*
18 * QEMU interface:
19 *
20 + * + QOM array property "cpus": CPUState pointers to each CPU
21 + * connected to this IRS.
22 + * + QOM array property "cpu-iaffids": array of uint32_t giving the
23 + * IAFFID for each CPU in the "cpus" property array
24 + * + QOM property "irsid": unique identifier for this IRS in the system
25 + * (this is IRS_IDR0.IRSID); default is 0
26 + * + QOM property "spi-range": total number of SPIs in the system
27 + * IRS (this is IRS_IDR5.SPI_RANGE); must be set
28 + * + QOM property "spi-base": minimum SPI INTID.ID implemented on this
29 + * IRS (this is IRS_IDR7.SPI_BASE); default is 0
30 + * + QOM property "spi-irs-range": number of SPI INTID.ID managed on this
31 + * IRS (this is IRS_IDR6.SPI_IRS_RANGE); defaults to value of spi-range
32 + *
33 * sysbus MMIO regions (in order matching IRS_IDR0.INT_DOM encoding):
34 * - IRS config frame for the Secure Interrupt Domain
35 * - IRS config frame for the Non-secure Interrupt Domain
@@ -47,6 +61,17 @@ struct GICv5Common {
61
62 /* Bits here are set for each physical interrupt domain implemented */
63 uint8_t implemented_domains;
64 +
65 + /* Properties */
66 + uint32_t num_cpus;
67 + ARMCPU **cpus;
68 + uint32_t num_cpu_iaffids;
69 + uint32_t *cpu_iaffids;
70 +
71 + uint32_t irsid;
72 + uint32_t spi_base;
73 + uint32_t spi_irs_range;
74 + uint32_t spi_range;
75 };
76
77 struct GICv5CommonClass {