accel, hw/arm, include/system/hvf: infrastructure changes for HVF vGIC
Misc changes needed for HVF vGIC enablement. Note: x86_64 macOS exposes interrupt controller virtualisation since macOS 12. Keeping an #ifdef here in case we end up supporting that... However, given that x86_64 macOS is on its way out, it'll probably (?) not be supported in QEMU. Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr> Message-id: 20260429190532.26538-4-mohamed@unpredictable.fr Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Mohamed Mediouni committed
May 5, 2026 at 09:25 UTC
2a3c965516fc53c3742e5efaae0487c514577ea6
6 files changed
+74
-4
accel/hvf/hvf-all.c
+46
@@ -10,6 +10,8 @@
10
11
#include "qemu/osdep.h"
12
#include "qemu/error-report.h"
13
+#include "qapi/error.h"
14
+#include "qapi/qapi-visit-common.h"
15
#include "accel/accel-ops.h"
16
#include "exec/cpu-common.h"
17
#include "system/address-spaces.h"
@@ -21,6 +23,7 @@
23
#include "trace.h"
24
25
bool hvf_allowed;
26
+bool hvf_kernel_irqchip;
27
28
const char *hvf_return_string(hv_return_t ret)
29
{
@@ -216,6 +219,43 @@ static int hvf_gdbstub_sstep_flags(AccelState *as)
219
return SSTEP_ENABLE | SSTEP_NOIRQ;
220
}
221
222
+static void hvf_set_kernel_irqchip(Object *obj, Visitor *v,
223
+ const char *name, void *opaque,
224
+ Error **errp)
225
+{
226
+ OnOffSplit mode;
227
+ if (!visit_type_OnOffSplit(v, name, &mode, errp)) {
228
+ return;
229
+ }
230
+
231
+ switch (mode) {
232
+ case ON_OFF_SPLIT_ON:
233
+#ifdef HOST_X86_64
234
+ /* macOS 12 onwards exposes an HVF virtual APIC. */
235
+ error_setg(errp, "HVF: kernel irqchip is not currently implemented for x86.");
236
+ break;
237
+#else
238
+ hvf_kernel_irqchip = true;
239
+ break;
240
+#endif
241
+
242
+ case ON_OFF_SPLIT_OFF:
243
+ hvf_kernel_irqchip = false;
244
+ break;
245
+
246
+ case ON_OFF_SPLIT_SPLIT:
247
+ error_setg(errp, "HVF: split irqchip is not supported on HVF.");
248
+ break;
249
+
250
+ default:
251
+ /*
252
+ * The value was checked in visit_type_OnOffSplit() above. If
253
+ * we get here, then something is wrong in QEMU.
254
+ */
255
+ abort();
256
+ }
257
+}
258
+
259
static void hvf_accel_class_init(ObjectClass *oc, const void *data)
260
{
261
AccelClass *ac = ACCEL_CLASS(oc);
@@ -223,6 +263,12 @@ static void hvf_accel_class_init(ObjectClass *oc, const void *data)
263
ac->init_machine = hvf_accel_init;
264
ac->allowed = &hvf_allowed;
265
ac->gdbstub_supported_sstep_flags = hvf_gdbstub_sstep_flags;
266
+ hvf_kernel_irqchip = false;
267
+ object_class_property_add(oc, "kernel-irqchip", "on|off|split",
268
+ NULL, hvf_set_kernel_irqchip,
269
+ NULL, NULL);
270
+ object_class_property_set_description(oc, "kernel-irqchip",
271
+ "Configure HVF irqchip");
272
}
273
274
static const TypeInfo hvf_accel_type = {
accel/stubs/hvf-stub.c
+1
@@ -10,3 +10,4 @@
10
#include "system/hvf.h"
11
12
bool hvf_allowed;
13
+bool hvf_kernel_irqchip;
hw/arm/virt.c
+19
-4
@@ -1163,7 +1163,7 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem)
1163
* interrupts; there are always 32 of the former (mandated by GIC spec).
1164
*/
1165
qdev_prop_set_uint32(vms->gic, "num-irq", NUM_IRQS + 32);
1166
- if (!kvm_irqchip_in_kernel()) {
1166
+ if (!kvm_irqchip_in_kernel() && !hvf_irqchip_in_kernel()) {
1167
qdev_prop_set_bit(vms->gic, "has-security-extensions", vms->secure);
1168
}
1169
@@ -1186,7 +1186,8 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem)
1186
qdev_prop_set_array(vms->gic, "redist-region-count",
1187
redist_region_count);
1188
1189
- if (!kvm_irqchip_in_kernel()) {
1189
+ if (!kvm_irqchip_in_kernel() &&
1190
+ !(hvf_enabled() && hvf_irqchip_in_kernel())) {
1191
if (vms->tcg_its) {
1192
object_property_set_link(OBJECT(vms->gic), "sysmem",
1193
OBJECT(mem), &error_fatal);
@@ -1197,7 +1198,7 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem)
1198
ARCH_GIC_MAINT_IRQ);
1199
}
1200
} else {
1200
- if (!kvm_irqchip_in_kernel()) {
1201
+ if (!kvm_irqchip_in_kernel() && !hvf_irqchip_in_kernel()) {
1202
qdev_prop_set_bit(vms->gic, "has-virtualization-extensions",
1203
vms->virt);
1204
}
@@ -2444,7 +2445,15 @@ static void finalize_gic_version(VirtMachineState *vms)
2445
accel_name = "KVM with kernel-irqchip=off";
2446
} else if (whpx_enabled()) {
2447
gics_supported |= VIRT_GIC_VERSION_3_MASK;
2447
- } else if (tcg_enabled() || hvf_enabled() || qtest_enabled()) {
2448
+ } else if (hvf_enabled()) {
2449
+ if (!hvf_irqchip_in_kernel()) {
2450
+ gics_supported |= VIRT_GIC_VERSION_2_MASK;
2451
+ }
2452
+ /* Hypervisor.framework doesn't expose EL2<->1 transition notifiers */
2453
+ if (!(!hvf_irqchip_in_kernel() && vms->virt)) {
2454
+ gics_supported |= VIRT_GIC_VERSION_3_MASK;
2455
+ }
2456
+ } else if (tcg_enabled() || qtest_enabled()) {
2457
gics_supported |= VIRT_GIC_VERSION_2_MASK;
2458
if (module_object_class_by_name("arm-gicv3")) {
2459
gics_supported |= VIRT_GIC_VERSION_3_MASK;
@@ -2486,6 +2495,8 @@ static void finalize_msi_controller(VirtMachineState *vms)
2495
vms->msi_controller = VIRT_MSI_CTRL_GICV2M;
2496
} else if (whpx_enabled()) {
2497
vms->msi_controller = VIRT_MSI_CTRL_GICV2M;
2498
+ } else if (hvf_enabled() && hvf_irqchip_in_kernel()) {
2499
+ vms->msi_controller = VIRT_MSI_CTRL_GICV2M;
2500
} else {
2501
vms->msi_controller = VIRT_MSI_CTRL_ITS;
2502
}
@@ -2505,6 +2516,10 @@ static void finalize_msi_controller(VirtMachineState *vms)
2516
error_report("ITS not supported on WHPX.");
2517
exit(1);
2518
}
2519
+ if (hvf_enabled() && hvf_irqchip_in_kernel()) {
2520
+ error_report("ITS not supported on HVF when using the hardware vGIC.");
2521
+ exit(1);
2522
+ }
2523
}
2524
2525
assert(vms->msi_controller != VIRT_MSI_CTRL_AUTO);
hw/intc/arm_gicv3_common.c
+3
@@ -33,6 +33,7 @@
33
#include "hw/arm/linux-boot-if.h"
34
#include "system/kvm.h"
35
#include "system/whpx.h"
36
+#include "system/hvf.h"
37
38
39
static void gicv3_gicd_no_migration_shift_bug_post_load(GICv3State *cs)
@@ -659,6 +660,8 @@ const char *gicv3_class_name(void)
660
return "kvm-arm-gicv3";
661
} else if (whpx_enabled()) {
662
return TYPE_WHPX_GICV3;
663
+ } else if (hvf_enabled() && hvf_irqchip_in_kernel()) {
664
+ return TYPE_HVF_GICV3;
665
} else {
666
if (kvm_enabled()) {
667
error_report("Userspace GICv3 is not supported with KVM");
include/system/hvf.h
+3
@@ -26,8 +26,11 @@
26
#ifdef CONFIG_HVF_IS_POSSIBLE
27
extern bool hvf_allowed;
28
#define hvf_enabled() (hvf_allowed)
29
+extern bool hvf_kernel_irqchip;
30
+#define hvf_irqchip_in_kernel() (hvf_kernel_irqchip)
31
#else /* !CONFIG_HVF_IS_POSSIBLE */
32
#define hvf_enabled() 0
33
+#define hvf_irqchip_in_kernel() 0
34
#endif /* !CONFIG_HVF_IS_POSSIBLE */
35
36
#define TYPE_HVF_ACCEL ACCEL_CLASS_NAME("hvf")
system/vl.c
+2
@@ -1781,6 +1781,8 @@ static void qemu_apply_legacy_machine_options(QDict *qdict)
1781
false);
1782
object_register_sugar_prop(ACCEL_CLASS_NAME("whpx"), "kernel-irqchip", value,
1783
false);
1784
+ object_register_sugar_prop(ACCEL_CLASS_NAME("hvf"), "kernel-irqchip", value,
1785
+ false);
1786
qdict_del(qdict, "kernel-irqchip");
1787
}
1788