master
c 215 lines 7.36 KB
Raw
1 /*
2 * Common base class for GICv5 IRS
3 *
4 * Copyright (c) 2025 Linaro Limited
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9 #include "qemu/osdep.h"
10 #include "hw/intc/arm_gicv5_common.h"
11 #include "hw/intc/arm_gicv5_stream.h"
12 #include "hw/core/qdev-properties.h"
13 #include "qapi/error.h"
14 #include "trace.h"
15
16 OBJECT_DEFINE_ABSTRACT_TYPE(GICv5Common, gicv5_common, ARM_GICV5_COMMON, SYS_BUS_DEVICE)
17
18 /* Any value > 2^24 is out of the valid range for this property */
19 #define GICV5_SPI_IRS_RANGE_NOT_SET 0xffffffff
20
21 static bool bad_frame_accepts(void *opaque, hwaddr addr, unsigned size,
22 bool is_write, MemTxAttrs attrs)
23 {
24 return false;
25 }
26
27 /*
28 * Used for the sysbus MMIO regions corresponding to IRS frames where
29 * this IRS does not implement the interrupt domain. It's probably a
30 * board/SoC error to create an IRS and try to wire up this MMIO
31 * region, but if it does then the region will behave as unassigned
32 * memory (generating a decode error). These frames are just here so
33 * that changing which domains are implemented doesn't reorder which
34 * sysbus MMIO region is which.
35 */
36 static const MemoryRegionOps bad_frame_ops = {
37 .valid.accepts = bad_frame_accepts,
38 .endianness = DEVICE_LITTLE_ENDIAN,
39 };
40
41 void gicv5_common_init_irqs_and_mmio(GICv5Common *cs,
42 qemu_irq_handler handler,
43 const MemoryRegionOps config_ops[NUM_GICV5_DOMAINS])
44 {
45 SysBusDevice *sbd = SYS_BUS_DEVICE(cs);
46
47 if (cs->spi_irs_range) {
48 qdev_init_gpio_in(DEVICE(cs), handler, cs->spi_irs_range);
49 }
50
51 for (int i = 0; i < NUM_GICV5_DOMAINS; i++) {
52 g_autofree char *memname = g_strdup_printf("gicv5-irs-%d", i);
53 const MemoryRegionOps *ops = gicv5_domain_implemented(cs, i) ?
54 &config_ops[i] : &bad_frame_ops;
55 memory_region_init_io(&cs->iomem[i], OBJECT(cs), ops, cs,
56 memname, IRS_CONFIG_FRAME_SIZE);
57 sysbus_init_mmio(sbd, &cs->iomem[i]);
58 }
59 }
60
61 static void gicv5_common_reset_hold(Object *obj, ResetType type)
62 {
63 GICv5Common *cs = ARM_GICV5_COMMON(obj);
64
65 memset(cs->irs_ist_baser, 0, sizeof(cs->irs_ist_baser));
66 memset(cs->irs_ist_cfgr, 0, sizeof(cs->irs_ist_cfgr));
67 memset(cs->irs_cr0, 0, sizeof(cs->irs_cr0));
68 memset(cs->irs_cr1, 0, sizeof(cs->irs_cr1));
69 memset(cs->irs_pe_selr, 0, sizeof(cs->irs_pe_selr));
70
71 if (cs->spi) {
72 GICv5Domain mp_domain;
73
74 /*
75 * D_YGLYC, D_TVVRZ: SPIs reset to edge-triggered, inactive,
76 * idle, disabled, targeted routing mode, not assigned to a
77 * VM, and assigned to the most-privileged interrupt domain.
78 * Other state is UNKNOWN: we choose to zero it.
79 */
80 memset(cs->spi, 0, cs->spi_irs_range * sizeof(*cs->spi));
81
82 /*
83 * The most-privileged interrupt domain is effectively the
84 * first in the list (EL3, S, NS) that we implement.
85 */
86 if (gicv5_domain_implemented(cs, GICV5_ID_EL3)) {
87 mp_domain = GICV5_ID_EL3;
88 } else if (gicv5_domain_implemented(cs, GICV5_ID_S)) {
89 mp_domain = GICV5_ID_S;
90 } else {
91 mp_domain = GICV5_ID_NS;
92 }
93
94 for (int i = 0; i < cs->spi_irs_range; i++) {
95 cs->spi[i].domain = mp_domain;
96 }
97 }
98
99 for (int i = 0; i < NUM_GICV5_DOMAINS; i++) {
100 /*
101 * We reset irs_spi_selr to an invalid value so that our reset
102 * value for IRS_SPI_STATUSR.V is correctly 0. The guest can
103 * never read IRS_SPI_SELR directly.
104 */
105 cs->irs_spi_selr[i] = cs->spi_base + cs->spi_irs_range;
106 }
107 }
108
109 static void gicv5_common_init(Object *obj)
110 {
111 }
112
113 static void gicv5_common_finalize(Object *obj)
114 {
115 }
116
117 static void gicv5_common_realize(DeviceState *dev, Error **errp)
118 {
119 GICv5Common *cs = ARM_GICV5_COMMON(dev);
120
121 if (cs->num_cpus == 0) {
122 error_setg(errp, "The cpus array property must have at least one CPU");
123 return;
124 }
125 if (cs->num_cpus >= (1 << 16)) {
126 /* We'll hit other QEMU limits long before this one :-) */
127 error_setg(errp, "Number of CPUs exceeds GICv5 architectural maximum");
128 return;
129 }
130 if (cs->num_cpus != cs->num_cpu_iaffids) {
131 error_setg(errp, "The cpu-iaffids array property must be the same size "
132 "as the cpus array property");
133 return;
134 }
135 if (cs->irsid >= (1 << 16)) {
136 error_setg(errp, "irsid (%u) is more than 2^16-1", cs->irsid);
137 return;
138 }
139 if (cs->spi_range > (1 << 24)) {
140 /*
141 * Note that IRS_IDR5.SPI_RANGE is a 25 bit field but the largest
142 * architecturally permitted value is 2^24 (not 2^25-1), hence
143 * use of > in the range check.
144 */
145 error_setg(errp, "spi-range (%u) is more than 2^24", cs->spi_range);
146 return;
147 }
148 if (cs->spi_irs_range == GICV5_SPI_IRS_RANGE_NOT_SET) {
149 /* spi-irs-range defaults to same as spi-range */
150 cs->spi_irs_range = cs->spi_range;
151 }
152 if (cs->spi_irs_range > (1 << 24)) {
153 /* Similarly IRS_IDR6.SPI_IRS_RANGE */
154 error_setg(errp, "spi-irs-range (%u) is more than 2^24",
155 cs->spi_irs_range);
156 return;
157 }
158 if (cs->spi_base >= (1 << 24)) {
159 /* IRS_IDR7.SPI_BASE is a 24-bit field, so range check is >= */
160 error_setg(errp, "spi-base (%u) is more than 2^24-1", cs->spi_base);
161 return;
162 }
163 /* range checks above mean we know this addition won't overflow */
164 if (cs->spi_base + cs->spi_irs_range > cs->spi_range) {
165 error_setg(errp, "spi-base (%u) + spi-irs-range (%u) is "
166 "more than spi-range (%u)",
167 cs->spi_base, cs->spi_irs_range, cs->spi_range);
168 return;
169 }
170 if (!cs->dma) {
171 error_setg(errp, "sysmem link property not set");
172 return;
173 }
174
175 for (int i = 0; i < cs->num_cpus; i++) {
176 if (!gicv5_set_gicv5state(cs->cpus[i], cs, cs->cpu_iaffids[i])) {
177 error_setg(errp,
178 "CPU %d (IAFFID 0x%x) does not implement GICv5 CPU interface",
179 i, cs->cpu_iaffids[i]);
180 return;
181 }
182 }
183
184 address_space_init(&cs->dma_as, cs->dma, "gicv5-sysmem");
185
186 cs->spi = g_new0(GICv5SPIState, cs->spi_irs_range);
187
188 trace_gicv5_common_realize(cs->irsid, cs->num_cpus,
189 cs->spi_base, cs->spi_irs_range, cs->spi_range);
190 }
191
192 static const Property arm_gicv5_common_properties[] = {
193 DEFINE_PROP_LINK_ARRAY("cpus", GICv5Common, num_cpus,
194 cpus, TYPE_ARM_CPU, ARMCPU *),
195 DEFINE_PROP_ARRAY("cpu-iaffids", GICv5Common, num_cpu_iaffids,
196 cpu_iaffids, qdev_prop_uint32, uint32_t),
197 DEFINE_PROP_UINT32("irsid", GICv5Common, irsid, 0),
198 DEFINE_PROP_UINT32("spi-range", GICv5Common, spi_range, 0),
199 DEFINE_PROP_UINT32("spi-base", GICv5Common, spi_base, 0),
200 DEFINE_PROP_UINT32("spi-irs-range", GICv5Common, spi_irs_range,
201 GICV5_SPI_IRS_RANGE_NOT_SET),
202 DEFINE_PROP_LINK("sysmem", GICv5Common, dma, TYPE_MEMORY_REGION,
203 MemoryRegion *),
204 };
205
206 static void gicv5_common_class_init(ObjectClass *oc, const void *data)
207 {
208 ResettableClass *rc = RESETTABLE_CLASS(oc);
209 DeviceClass *dc = DEVICE_CLASS(oc);
210
211 rc->phases.hold = gicv5_common_reset_hold;
212
213 dc->realize = gicv5_common_realize;
214 device_class_set_props(dc, arm_gicv5_common_properties);
215 }