@samitouri / QOSamiQemu / commits / d7a75ea483

hw/arm, target/arm: nested virtualisation on HVF

Add hvf_arm_el2_supported for querying EL2 availability. An hvf_nested_virt_enable workaround is added as nested virt has to be enabled early on HVF. And adds hvf_nested_virt_enabled. Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr> Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org> Message-id: 20260429190532.26538-6-mohamed@unpredictable.fr Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Mohamed Mediouni committed May 5, 2026 at 09:25 UTC d7a75ea483a57add78b559cd181293e0136cc8c8
5 files changed +67 -2
accel/hvf/hvf-all.c
+6
@@ -24,6 +24,12 @@
24
25 bool hvf_allowed;
26 bool hvf_kernel_irqchip;
27 +bool hvf_nested_virt;
28 +
29 +void hvf_nested_virt_enable(bool nested_virt)
30 +{
31 + hvf_nested_virt = nested_virt;
32 +}
33
34 const char *hvf_return_string(hv_return_t ret)
35 {
accel/stubs/hvf-stub.c
+11
@@ -11,3 +11,14 @@
11
12 bool hvf_allowed;
13 bool hvf_kernel_irqchip;
14 +bool hvf_nested_virt;
15 +
16 +void hvf_nested_virt_enable(bool nested_virt)
17 +{
18 + /*
19 + * This is called unconditionally from hw/arm/virt.c
20 + * because we don't know if HVF is going to be used
21 + * as that step of initialisation happens later.
22 + * As such, do nothing here instead of marking as unreachable.
23 + */
24 +}
hw/arm/virt.c
+5
@@ -2987,6 +2987,11 @@ static void virt_set_virt(Object *obj, bool value, Error **errp)
2987 VirtMachineState *vms = VIRT_MACHINE(obj);
2988
2989 vms->virt = value;
2990 + /*
2991 + * At this point, HVF is not initialised yet.
2992 + * However, it needs to know if nested virt is enabled at init time.
2993 + */
2994 + hvf_nested_virt_enable(value);
2995 }
2996
2997 static bool virt_get_highmem(Object *obj, Error **errp)
include/system/hvf.h
+5
@@ -28,11 +28,16 @@ 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 +extern bool hvf_nested_virt;
32 +#define hvf_nested_virt_enabled() (hvf_nested_virt)
33 #else /* !CONFIG_HVF_IS_POSSIBLE */
34 #define hvf_enabled() 0
35 #define hvf_irqchip_in_kernel() 0
36 +#define hvf_nested_virt_enabled() 0
37 #endif /* !CONFIG_HVF_IS_POSSIBLE */
38
39 +void hvf_nested_virt_enable(bool nested_virt);
40 +
41 #define TYPE_HVF_ACCEL ACCEL_CLASS_NAME("hvf")
42
43 typedef struct HVFState HVFState;
target/arm/hvf/hvf.c
+40 -2
@@ -27,6 +27,7 @@
27 #include "system/memory.h"
28 #include "hw/core/boards.h"
29 #include "hw/core/irq.h"
30 +#include "hw/arm/virt.h"
31 #include "qemu/main-loop.h"
32 #include "system/cpus.h"
33 #include "arm-powerctl.h"
@@ -1103,6 +1104,10 @@ static bool hvf_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
1104 (1ULL << ARM_FEATURE_PMU) |
1105 (1ULL << ARM_FEATURE_GENERIC_TIMER);
1106
1107 + if (hvf_nested_virt_enabled()) {
1108 + ahcf->features |= 1ULL << ARM_FEATURE_EL2;
1109 + }
1110 +
1111 for (i = 0; i < ARRAY_SIZE(regs); i++) {
1112 r |= hv_vcpu_config_get_feature_reg(config, regs[i].reg,
1113 &host_isar.idregs[regs[i].index]);
@@ -1218,6 +1223,19 @@ void hvf_arch_vcpu_destroy(CPUState *cpu)
1223 assert_hvf_ok(ret);
1224 }
1225
1226 +static bool hvf_arm_el2_supported(void)
1227 +{
1228 + bool is_nested_virt_supported;
1229 + if (__builtin_available(macOS 15.0, *)) {
1230 + hv_return_t ret = hv_vm_config_get_el2_supported(&is_nested_virt_supported);
1231 + assert_hvf_ok(ret);
1232 + } else {
1233 + return false;
1234 + }
1235 + return is_nested_virt_supported;
1236 +}
1237 +
1238 +
1239 hv_return_t hvf_arch_vm_create(MachineState *ms, uint32_t pa_range)
1240 {
1241 hv_return_t ret;
@@ -1229,6 +1247,20 @@ hv_return_t hvf_arch_vm_create(MachineState *ms, uint32_t pa_range)
1247 }
1248 chosen_ipa_bit_size = pa_range;
1249
1250 + if (__builtin_available(macOS 15.0, *)) {
1251 + if (hvf_nested_virt_enabled()) {
1252 + if (!hvf_arm_el2_supported()) {
1253 + error_report("Nested virtualization not supported on this system.");
1254 + goto cleanup;
1255 + }
1256 + ret = hv_vm_config_set_el2_enabled(config, true);
1257 + if (ret != HV_SUCCESS) {
1258 + error_report("Failed to enable nested virtualization.");
1259 + goto cleanup;
1260 + }
1261 + }
1262 + }
1263 +
1264 ret = hv_vm_create(config);
1265 if (hvf_irqchip_in_kernel()) {
1266 if (__builtin_available(macOS 15.0, *)) {
@@ -1420,6 +1452,13 @@ static void hvf_psci_cpu_off(ARMCPU *arm_cpu)
1452 assert(ret == QEMU_ARM_POWERCTL_RET_SUCCESS);
1453 }
1454
1455 +static int hvf_psci_get_target_el(void)
1456 +{
1457 + if (hvf_nested_virt_enabled()) {
1458 + return 2;
1459 + }
1460 + return 1;
1461 +}
1462 /*
1463 * Handle a PSCI call.
1464 *
@@ -1441,7 +1480,6 @@ static bool hvf_handle_psci_call(CPUState *cpu, int *excp_ret)
1480 CPUState *target_cpu_state;
1481 ARMCPU *target_cpu;
1482 uint64_t entry;
1444 - int target_el = 1;
1483 int32_t ret = 0;
1484
1485 trace_arm_psci_call(param[0], param[1], param[2], param[3],
@@ -1495,7 +1533,7 @@ static bool hvf_handle_psci_call(CPUState *cpu, int *excp_ret)
1533 entry = param[2];
1534 context_id = param[3];
1535 ret = arm_set_cpu_on(mpidr, entry, context_id,
1498 - target_el, target_aarch64);
1536 + hvf_psci_get_target_el(), target_aarch64);
1537 break;
1538 case QEMU_PSCI_0_1_FN_CPU_OFF:
1539 case QEMU_PSCI_0_2_FN_CPU_OFF: