target/arm: Add has_gcie property to enable FEAT_GCIE
Add a has_gcie QOM property to the CPU which allows the board code to enable FEAT_GCIE, the GICv5 CPU interface. Enabling the GICv5 CPU interface comes with a significant restriction: because the GICv5 architecture is Armv9, it assumes the Armv9 requirement that only EL0 (userspace) may be in AArch32. So there are no GIC control system registers defined for AArch32. We force AArch32 at ELs 1, 2 and 3 to disabled, to avoid a guest being able to get into an EL where interrupts are completely broken. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com> Message-id: 20260327111700.795099-55-peter.maydell@linaro.org
Peter Maydell committed
Mar 27, 2026 at 11:16 UTC
d934f21b870df843783e883bb56afe7331079fd5
2 files changed
+47
target/arm/cpu.c
+45
@@ -1270,6 +1270,9 @@ static const Property arm_cpu_has_el2_property =
1270
1271
static const Property arm_cpu_has_el3_property =
1272
DEFINE_PROP_BOOL("has_el3", ARMCPU, has_el3, true);
1273
+
1274
+static const Property arm_cpu_has_gcie_property =
1275
+ DEFINE_PROP_BOOL("has_gcie", ARMCPU, has_gcie, false);
1276
#endif
1277
1278
static const Property arm_cpu_cfgend_property =
@@ -1526,6 +1529,11 @@ static void arm_cpu_post_init(Object *obj)
1529
object_property_add_uint64_ptr(obj, "rvbar",
1530
&cpu->rvbar_prop,
1531
OBJ_PROP_FLAG_READWRITE);
1532
+
1533
+ /* We only allow GICv5 on a 64-bit v8 CPU */
1534
+ if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
1535
+ qdev_property_add_static(DEVICE(obj), &arm_cpu_has_gcie_property);
1536
+ }
1537
}
1538
1539
if (arm_feature(&cpu->env, ARM_FEATURE_EL3)) {
@@ -1826,6 +1834,12 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
1834
current_accel_name());
1835
return;
1836
}
1837
+ if (cpu->has_gcie) {
1838
+ error_setg(errp,
1839
+ "Cannot enable %s when guest CPU has GICv5 enabled",
1840
+ current_accel_name());
1841
+ return;
1842
+ }
1843
}
1844
#endif
1845
@@ -2163,6 +2177,37 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
2177
FIELD_DP32_IDREG(isar, ID_PFR1, VIRTUALIZATION, 0);
2178
}
2179
2180
+ /* Report FEAT_GCIE in our ID registers if property was set */
2181
+ FIELD_DP64_IDREG(isar, ID_AA64PFR2, GCIE, cpu->has_gcie);
2182
+ if (cpu_isar_feature(aa64_gcie, cpu)) {
2183
+ if (!arm_feature(env, ARM_FEATURE_AARCH64)) {
2184
+ /*
2185
+ * We only create the have_gcie property for AArch64 CPUs,
2186
+ * but the user might have tried aarch64=off with has_gcie=on.
2187
+ */
2188
+ error_setg(errp, "Cannot both enable has_gcie and disable aarch64");
2189
+ return;
2190
+ }
2191
+
2192
+ /*
2193
+ * FEAT_GCIE implies Armv9, which implies no AArch32 above EL0.
2194
+ * Usually we don't strictly insist on this kind of feature
2195
+ * dependency, but in this case we enforce it, because the
2196
+ * GICv5 CPU interface has no AArch32 versions of its system
2197
+ * registers, so interrupts wouldn't work if we allowed AArch32
2198
+ * in EL1 or above. Downgrade "AArch32 and AArch64" to "AArch64".
2199
+ */
2200
+ if (cpu_isar_feature(aa64_aa32_el3, cpu)) {
2201
+ FIELD_DP64_IDREG(isar, ID_AA64PFR0, EL3, 1);
2202
+ }
2203
+ if (cpu_isar_feature(aa64_aa32_el2, cpu)) {
2204
+ FIELD_DP64_IDREG(isar, ID_AA64PFR0, EL2, 1);
2205
+ }
2206
+ if (cpu_isar_feature(aa64_aa32_el1, cpu)) {
2207
+ FIELD_DP64_IDREG(isar, ID_AA64PFR0, EL1, 1);
2208
+ }
2209
+ }
2210
+
2211
if (cpu_isar_feature(aa64_mte, cpu)) {
2212
/*
2213
* The architectural range of GM blocksize is 2-6, however qemu
target/arm/cpu.h
+2
@@ -1031,6 +1031,8 @@ struct ArchCPU {
1031
bool has_neon;
1032
/* CPU has M-profile DSP extension */
1033
bool has_dsp;
1034
+ /* CPU has FEAT_GCIE GICv5 CPU interface */
1035
+ bool has_gcie;
1036
1037
/* CPU has memory protection unit */
1038
bool has_mpu;