* [PATCH v2 1/5] hvf: arm: advertise ID_AA64PFR0_EL1.GIC
2026-09-04 4:37 [PATCH v2 0/5] hvf: arm: add experimental VHE (x-vhe) toggle Mohamed Mediouni
@ 2026-09-04 4:37 ` Mohamed Mediouni
2026-09-28 15:54 ` Peter Maydell
2026-09-04 4:37 ` [PATCH v2 2/5] hvf: arm: add experimental VHE toggle Mohamed Mediouni
` (4 subsequent siblings)
5 siblings, 1 reply; 9+ messages in thread
From: Mohamed Mediouni @ 2026-09-04 4:37 UTC (permalink / raw)
To: qemu-devel
Cc: Phil Dennis-Jordan, Roman Bolshakov, qemu-arm, Peter Maydell,
Alexander Graf, Mohamed Mediouni
For the kernel-irqchip=on case, advertise ID_AA64PFR0_EL1.GIC.
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
---
target/arm/hvf/hvf.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
index da3ec521fc..f881d6cc67 100644
--- a/target/arm/hvf/hvf.c
+++ b/target/arm/hvf/hvf.c
@@ -1229,6 +1229,18 @@ static bool hvf_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
FIELD_DP64_IDREG(&host_isar, ID_AA64PFR1, SME, 0);
}
+ /*
+ * On HVF, kernel-irqchip implies GICv3.
+ * The kernel-irqchip=off,gic-version=3 legacy case also supports
+ * the host CPU interface but advertising it in ID_AA64PFR0_EL1
+ * is not implemented yet.
+ */
+
+ if (hvf_irqchip_in_kernel()) {
+ /* Advertise the GIC system register interface */
+ FIELD_DP64_IDREG(&host_isar, ID_AA64PFR0, GIC, 1);
+ }
+
ahcf->isar = host_isar;
/*
--
2.54.0 (Apple Git-156)
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH v2 1/5] hvf: arm: advertise ID_AA64PFR0_EL1.GIC
2026-09-04 4:37 ` [PATCH v2 1/5] hvf: arm: advertise ID_AA64PFR0_EL1.GIC Mohamed Mediouni
@ 2026-09-28 15:54 ` Peter Maydell
2026-09-28 21:40 ` Mohamed Mediouni
0 siblings, 1 reply; 9+ messages in thread
From: Peter Maydell @ 2026-09-28 15:54 UTC (permalink / raw)
To: Mohamed Mediouni
Cc: qemu-devel, Phil Dennis-Jordan, Roman Bolshakov, qemu-arm,
Alexander Graf
On Fri, 4 Sept 2026 at 05:37, Mohamed Mediouni <mohamed@unpredictable.fr> wrote:
>
> For the kernel-irqchip=on case, advertise ID_AA64PFR0_EL1.GIC.
>
> Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
> ---
> target/arm/hvf/hvf.c | 12 ++++++++++++
> 1 file changed, 12 insertions(+)
>
> diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
> index da3ec521fc..f881d6cc67 100644
> --- a/target/arm/hvf/hvf.c
> +++ b/target/arm/hvf/hvf.c
> @@ -1229,6 +1229,18 @@ static bool hvf_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
> FIELD_DP64_IDREG(&host_isar, ID_AA64PFR1, SME, 0);
> }
>
> + /*
> + * On HVF, kernel-irqchip implies GICv3.
> + * The kernel-irqchip=off,gic-version=3 legacy case also supports
> + * the host CPU interface but advertising it in ID_AA64PFR0_EL1
> + * is not implemented yet.
> + */
> +
> + if (hvf_irqchip_in_kernel()) {
> + /* Advertise the GIC system register interface */
> + FIELD_DP64_IDREG(&host_isar, ID_AA64PFR0, GIC, 1);
> + }
How does this interact with the existing code in
hvf_arch_init_vcpu() that does:
pfr = GET_IDREG(&arm_cpu->isar, ID_AA64PFR0);
pfr |= env->gicv3state ? (1 << 24) : 0;
ret = hv_vcpu_set_sys_reg(cpu->accel->fd, HV_SYS_REG_ID_AA64PFR0_EL1, pfr);
?
env->gicv3state should be non-NULL for both HVF and TCG
GICv3, I think, so aren't we already advertising the GIC
in ID_AA64PFR0 ?
thanks
-- PMM
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH v2 1/5] hvf: arm: advertise ID_AA64PFR0_EL1.GIC
2026-09-28 15:54 ` Peter Maydell
@ 2026-09-28 21:40 ` Mohamed Mediouni
0 siblings, 0 replies; 9+ messages in thread
From: Mohamed Mediouni @ 2026-09-28 21:40 UTC (permalink / raw)
To: Peter Maydell
Cc: qemu-devel, Phil Dennis-Jordan, Roman Bolshakov, qemu-arm,
Alexander Graf
> On 28. Sep 2026, at 17:54, Peter Maydell <peter.maydell@linaro.org> wrote:
>
> On Fri, 4 Sept 2026 at 05:37, Mohamed Mediouni <mohamed@unpredictable.fr> wrote:
>>
>> For the kernel-irqchip=on case, advertise ID_AA64PFR0_EL1.GIC.
>>
>> Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
>> ---
>> target/arm/hvf/hvf.c | 12 ++++++++++++
>> 1 file changed, 12 insertions(+)
>>
>> diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
>> index da3ec521fc..f881d6cc67 100644
>> --- a/target/arm/hvf/hvf.c
>> +++ b/target/arm/hvf/hvf.c
>> @@ -1229,6 +1229,18 @@ static bool hvf_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
>> FIELD_DP64_IDREG(&host_isar, ID_AA64PFR1, SME, 0);
>> }
>>
>> + /*
>> + * On HVF, kernel-irqchip implies GICv3.
>> + * The kernel-irqchip=off,gic-version=3 legacy case also supports
>> + * the host CPU interface but advertising it in ID_AA64PFR0_EL1
>> + * is not implemented yet.
>> + */
>> +
>> + if (hvf_irqchip_in_kernel()) {
>> + /* Advertise the GIC system register interface */
>> + FIELD_DP64_IDREG(&host_isar, ID_AA64PFR0, GIC, 1);
>> + }
>
> How does this interact with the existing code in
> hvf_arch_init_vcpu() that does:
>
> pfr = GET_IDREG(&arm_cpu->isar, ID_AA64PFR0);
> pfr |= env->gicv3state ? (1 << 24) : 0;
> ret = hv_vcpu_set_sys_reg(cpu->accel->fd, HV_SYS_REG_ID_AA64PFR0_EL1, pfr);
>
> ?
>
> env->gicv3state should be non-NULL for both HVF and TCG
> GICv3, I think, so aren't we already advertising the GIC
> in ID_AA64PFR0 ?
Hi,
Without this patch HVF GICv3 doesn’t show up, will look deeper at why that check
you noted is not effective…
Maybe it’s a question of ordering?
>
> thanks
> -- PMM
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v2 2/5] hvf: arm: add experimental VHE toggle
2026-09-04 4:37 [PATCH v2 0/5] hvf: arm: add experimental VHE (x-vhe) toggle Mohamed Mediouni
2026-09-04 4:37 ` [PATCH v2 1/5] hvf: arm: advertise ID_AA64PFR0_EL1.GIC Mohamed Mediouni
@ 2026-09-04 4:37 ` Mohamed Mediouni
2026-09-04 4:37 ` [PATCH v2 3/5] hvf: arm: advertise EL3 support when VHE is on Mohamed Mediouni
` (3 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Mohamed Mediouni @ 2026-09-04 4:37 UTC (permalink / raw)
To: qemu-devel
Cc: Phil Dennis-Jordan, Roman Bolshakov, qemu-arm, Peter Maydell,
Alexander Graf, Mohamed Mediouni
macOS 27.0 ships with an experimental VHE enablement
private API. Expose support for it as x-vhe.
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
---
accel/hvf/hvf-all.c | 2 +
include/system/hvf_int.h | 1 +
target/arm/hvf/hvf.c | 89 ++++++++++++++++++++++++++++++++++++++++
target/i386/hvf/hvf.c | 4 ++
4 files changed, 96 insertions(+)
diff --git a/accel/hvf/hvf-all.c b/accel/hvf/hvf-all.c
index 8bd9154a50..bbff3c6867 100644
--- a/accel/hvf/hvf-all.c
+++ b/accel/hvf/hvf-all.c
@@ -282,6 +282,8 @@ static void hvf_accel_class_init(ObjectClass *oc, const void *data)
NULL, NULL);
object_class_property_set_description(oc, "kernel-irqchip",
"Configure HVF irqchip");
+
+ hvf_arch_accel_class_init(oc);
}
static const TypeInfo hvf_accel_type = {
diff --git a/include/system/hvf_int.h b/include/system/hvf_int.h
index a01691ce17..44ae2e7c4c 100644
--- a/include/system/hvf_int.h
+++ b/include/system/hvf_int.h
@@ -110,5 +110,6 @@ int hvf_update_guest_debug(CPUState *cpu);
bool hvf_arch_cpu_realize(CPUState *cpu, Error **errp);
uint32_t hvf_arch_get_default_ipa_bit_size(void);
uint32_t hvf_arch_get_max_ipa_bit_size(void);
+void hvf_arch_accel_class_init(ObjectClass *oc);
#endif
diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
index f881d6cc67..b61554e108 100644
--- a/target/arm/hvf/hvf.c
+++ b/target/arm/hvf/hvf.c
@@ -22,6 +22,7 @@
#include "cpu-sysregs.h"
#include <mach/mach_time.h>
+#include <dlfcn.h>
#include "system/address-spaces.h"
#include "system/memory.h"
@@ -39,6 +40,7 @@
#include "target/arm/trace.h"
#include "trace.h"
#include "migration/vmstate.h"
+#include "migration/blocker.h"
#include "gdbstub/enums.h"
@@ -1132,6 +1134,60 @@ static void clamp_id_aa64mmfr0_parange_to_ipa_size(ARMISARegisters *isar)
SET_IDREG(isar, ID_AA64MMFR0, id_aa64mmfr0);
}
+bool hvf_vhe;
+
+static void hvf_set_vhe(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
+{
+ OnOffAuto mode;
+
+ if (!visit_type_OnOffAuto(v, name, &mode, errp)) {
+ return;
+ }
+
+ switch (mode) {
+ case ON_OFF_AUTO_ON:
+ if (__builtin_available(macOS 27.0, *)) {
+ hvf_vhe = true;
+ } else {
+ error_report("VHE emulation not supported on this system.");
+ }
+ break;
+
+ case ON_OFF_AUTO_OFF:
+ hvf_vhe = false;
+ break;
+
+ case ON_OFF_AUTO_AUTO:
+ /* Experimental feature as of macOS 27.0 */
+ hvf_vhe = false;
+ break;
+ default:
+ /*
+ * The value was checked in visit_type_OnOffAuto() above. If
+ * we get here, then something is wrong in QEMU.
+ */
+ abort();
+ }
+}
+
+static bool hvf_get_vhe(void)
+{
+ return hvf_vhe;
+}
+
+void hvf_arch_accel_class_init(ObjectClass *oc)
+{
+ hvf_vhe = false;
+
+ object_class_property_add(oc, "x-vhe", "OnOffAuto",
+ NULL, hvf_set_vhe,
+ NULL, NULL);
+ object_class_property_set_description(oc, "x-vhe",
+ "Configure experimental VHE enablement");
+}
+
static bool hvf_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
{
ARMISARegisters host_isar = {};
@@ -1227,6 +1283,9 @@ static bool hvf_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
if (hvf_nested_virt_enabled()) {
/* SME is not implemented with nested virt on the Apple side */
FIELD_DP64_IDREG(&host_isar, ID_AA64PFR1, SME, 0);
+ if (hvf_get_vhe()) {
+ FIELD_DP64_IDREG(&host_isar, ID_AA64MMFR1, VH, 0x1);
+ }
}
/*
@@ -1357,6 +1416,36 @@ hv_return_t hvf_arch_vm_create(MachineState *ms, uint32_t pa_range)
}
}
+ if (hvf_get_vhe()) {
+ Error *vhe_migration_blocker = NULL;
+ Error* errp;
+
+ void* hvf = dlopen("/System/Library/Frameworks/Hypervisor.framework/Versions/A/Hypervisor", RTLD_LOCAL);
+
+ if (!hvf) {
+ /* Unreachable. */
+ error_report("Failed to dlopen() Hypervisor.framework.");
+ goto cleanup;
+ }
+
+ /* Experimental API: might change before release. */
+ hv_return_t (*_hv_vm_config_set_vhe_enabled)(hv_vm_config_t cfg, bool vhe) = dlsym(hvf, "_hv_vm_config_set_vhe_enabled");
+ if (!_hv_vm_config_set_vhe_enabled) {
+ error_report("_hv_vm_config_set_vhe_enabled API not available.");
+ goto cleanup;
+ }
+ _hv_vm_config_set_vhe_enabled(config, true);
+
+ error_setg(&vhe_migration_blocker,
+ "Live migration disabled because VHE support is experimental");
+ if (migrate_add_blocker(&vhe_migration_blocker, &errp)) {
+ error_report("Failed to add migration blocker.");
+ goto cleanup;
+ }
+
+ dlclose(hvf);
+ }
+
ret = hv_vm_create(config);
if (hvf_irqchip_in_kernel()) {
if (__builtin_available(macOS 15.0, *)) {
diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c
index 150598418e..5a39a82492 100644
--- a/target/i386/hvf/hvf.c
+++ b/target/i386/hvf/hvf.c
@@ -1068,3 +1068,7 @@ void hvf_arch_remove_all_gdbstub_hw_breakpoints(void)
void hvf_arch_update_guest_debug(CPUState *cpu)
{
}
+
+void hvf_arch_accel_class_init(ObjectClass *oc)
+{
+}
--
2.54.0 (Apple Git-156)
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH v2 3/5] hvf: arm: advertise EL3 support when VHE is on
2026-09-04 4:37 [PATCH v2 0/5] hvf: arm: add experimental VHE (x-vhe) toggle Mohamed Mediouni
2026-09-04 4:37 ` [PATCH v2 1/5] hvf: arm: advertise ID_AA64PFR0_EL1.GIC Mohamed Mediouni
2026-09-04 4:37 ` [PATCH v2 2/5] hvf: arm: add experimental VHE toggle Mohamed Mediouni
@ 2026-09-04 4:37 ` Mohamed Mediouni
2026-09-04 4:37 ` [PATCH v2 4/5] hvf: arm: expose E2H0 Mohamed Mediouni
` (2 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Mohamed Mediouni @ 2026-09-04 4:37 UTC (permalink / raw)
To: qemu-devel
Cc: Phil Dennis-Jordan, Roman Bolshakov, qemu-arm, Peter Maydell,
Alexander Graf, Mohamed Mediouni
This replicates the typical KVM configuration, and Hyper-V
wants it.
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
---
target/arm/hvf/hvf.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
index b61554e108..c54a92c2aa 100644
--- a/target/arm/hvf/hvf.c
+++ b/target/arm/hvf/hvf.c
@@ -1286,6 +1286,8 @@ static bool hvf_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
if (hvf_get_vhe()) {
FIELD_DP64_IDREG(&host_isar, ID_AA64MMFR1, VH, 0x1);
}
+ /* Hyper-V doesn't launch if EL3 isn't advertised. */
+ FIELD_DP64_IDREG(&host_isar, ID_AA64PFR0, EL3, 0x1);
}
/*
--
2.54.0 (Apple Git-156)
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH v2 4/5] hvf: arm: expose E2H0
2026-09-04 4:37 [PATCH v2 0/5] hvf: arm: add experimental VHE (x-vhe) toggle Mohamed Mediouni
` (2 preceding siblings ...)
2026-09-04 4:37 ` [PATCH v2 3/5] hvf: arm: advertise EL3 support when VHE is on Mohamed Mediouni
@ 2026-09-04 4:37 ` Mohamed Mediouni
2026-09-04 4:37 ` [PATCH v2 5/5] hvf: arm: ignore accesses to CNTKCTL_EL12 Mohamed Mediouni
2026-09-28 15:55 ` [PATCH v2 0/5] hvf: arm: add experimental VHE (x-vhe) toggle Peter Maydell
5 siblings, 0 replies; 9+ messages in thread
From: Mohamed Mediouni @ 2026-09-04 4:37 UTC (permalink / raw)
To: qemu-devel
Cc: Phil Dennis-Jordan, Roman Bolshakov, qemu-arm, Peter Maydell,
Alexander Graf, Mohamed Mediouni
In the VHE mode, nVHE is not available. As such, only expose VHE.
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
---
target/arm/hvf/hvf.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
index c54a92c2aa..47eeaa0f30 100644
--- a/target/arm/hvf/hvf.c
+++ b/target/arm/hvf/hvf.c
@@ -1285,6 +1285,7 @@ static bool hvf_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
FIELD_DP64_IDREG(&host_isar, ID_AA64PFR1, SME, 0);
if (hvf_get_vhe()) {
FIELD_DP64_IDREG(&host_isar, ID_AA64MMFR1, VH, 0x1);
+ FIELD_DP64_IDREG(&host_isar, ID_AA64MMFR4, E2H0, 0xf);
}
/* Hyper-V doesn't launch if EL3 isn't advertised. */
FIELD_DP64_IDREG(&host_isar, ID_AA64PFR0, EL3, 0x1);
--
2.54.0 (Apple Git-156)
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH v2 5/5] hvf: arm: ignore accesses to CNTKCTL_EL12
2026-09-04 4:37 [PATCH v2 0/5] hvf: arm: add experimental VHE (x-vhe) toggle Mohamed Mediouni
` (3 preceding siblings ...)
2026-09-04 4:37 ` [PATCH v2 4/5] hvf: arm: expose E2H0 Mohamed Mediouni
@ 2026-09-04 4:37 ` Mohamed Mediouni
2026-09-28 15:55 ` [PATCH v2 0/5] hvf: arm: add experimental VHE (x-vhe) toggle Peter Maydell
5 siblings, 0 replies; 9+ messages in thread
From: Mohamed Mediouni @ 2026-09-04 4:37 UTC (permalink / raw)
To: qemu-devel
Cc: Phil Dennis-Jordan, Roman Bolshakov, qemu-arm, Peter Maydell,
Alexander Graf, Mohamed Mediouni
This makes KVM work, with runnable virtual machines.
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
---
target/arm/hvf/hvf.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
index 47eeaa0f30..c32c705ddd 100644
--- a/target/arm/hvf/hvf.c
+++ b/target/arm/hvf/hvf.c
@@ -305,6 +305,10 @@ void hvf_arm_init_debug(void)
#define SYSREG_CNTHCTL_EL2 SYSREG(3, 4, 14, 1, 0)
#define SYSREG_MDCCINT_EL1 SYSREG(2, 0, 0, 2, 0)
+/* VHE registers */
+#define SYSREG_CNTKCTL_EL12 SYSREG(3, 5, 14, 1, 0)
+
+
#define WFX_IS_WFE (1 << 0)
#define TMR_CTL_ENABLE (1 << 0)
@@ -1857,6 +1861,9 @@ static int hvf_sysreg_read(CPUState *cpu, uint32_t reg, uint64_t *val)
assert_hvf_ok(hv_vcpu_get_sys_reg(cpu->accel->fd, HV_SYS_REG_CNTHCTL_EL2, val));
}
return 0;
+ case SYSREG_CNTKCTL_EL12:
+ /* Ignore for now */
+ return 0;
case SYSREG_MDCCINT_EL1:
assert_hvf_ok(hv_vcpu_get_sys_reg(cpu->accel->fd, HV_SYS_REG_MDCCINT_EL1, val));
return 0;
@@ -2155,6 +2162,9 @@ static int hvf_sysreg_write(CPUState *cpu, uint32_t reg, uint64_t val)
assert_hvf_ok(hv_vcpu_set_sys_reg(cpu->accel->fd, HV_SYS_REG_CNTHCTL_EL2, val));
}
return 0;
+ case SYSREG_CNTKCTL_EL12:
+ /* Ignore for now */
+ return 0;
case SYSREG_MDCCINT_EL1:
assert_hvf_ok(hv_vcpu_set_sys_reg(cpu->accel->fd, HV_SYS_REG_MDCCINT_EL1, val));
return 0;
--
2.54.0 (Apple Git-156)
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH v2 0/5] hvf: arm: add experimental VHE (x-vhe) toggle
2026-09-04 4:37 [PATCH v2 0/5] hvf: arm: add experimental VHE (x-vhe) toggle Mohamed Mediouni
` (4 preceding siblings ...)
2026-09-04 4:37 ` [PATCH v2 5/5] hvf: arm: ignore accesses to CNTKCTL_EL12 Mohamed Mediouni
@ 2026-09-28 15:55 ` Peter Maydell
5 siblings, 0 replies; 9+ messages in thread
From: Peter Maydell @ 2026-09-28 15:55 UTC (permalink / raw)
To: Mohamed Mediouni
Cc: qemu-devel, Phil Dennis-Jordan, Roman Bolshakov, qemu-arm,
Alexander Graf
On Fri, 4 Sept 2026 at 05:37, Mohamed Mediouni <mohamed@unpredictable.fr> wrote:
>
> macOS 27.0 has a pre-release VHE implementation. Add support for it in QEMU.
>
> The first patch in the series is an independent bugfix that should be backported to QEMU 11.1 too.
>
> v2:
>
> Add:
> hvf: arm: expose E2H0
> hvf: arm: ignore accesses to CNTKCTL_EL12
>
> This is to have working KVM under the VHE configuration.
>
> Mohamed Mediouni (5):
> hvf: arm: advertise ID_AA64PFR0_EL1.GIC
> hvf: arm: add experimental VHE toggle
> hvf: arm: advertise EL3 support when VHE is on
> hvf: arm: expose E2H0
> hvf: arm: ignore accesses to CNTKCTL_EL12
I would prefer to wait with this until the interface for
VHE is not a "private API you have to get at by playing
games with dlopen()" setup.
thanks
-- PMM
^ permalink raw reply [flat|nested] 9+ messages in thread