@samitouri / QOSamiQemu / commits / 2a3c965516

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