[PATCH v13 06/28] hw/arm: virt: cleanly fail on attempt to use the platform vGIC together with ITS

Mohamed Mediouni posted 28 patches 1 week, 1 day ago
Maintainers: Cameron Esfahani <dirty@apple.com>, Roman Bolshakov <rbolshakov@ddn.com>, Phil Dennis-Jordan <phil@philjordan.eu>, Mads Ynddal <mads@ynddal.dk>, Pedro Barbuda <pbarbuda@microsoft.com>, Mohamed Mediouni <mohamed@unpredictable.fr>, Peter Maydell <peter.maydell@linaro.org>, Shannon Zhao <shannon.zhaosl@gmail.com>, "Michael S. Tsirkin" <mst@redhat.com>, Igor Mammedov <imammedo@redhat.com>, Ani Sinha <anisinha@redhat.com>, Paolo Bonzini <pbonzini@redhat.com>, Richard Henderson <richard.henderson@linaro.org>, Eduardo Habkost <eduardo@habkost.net>, Marcel Apfelbaum <marcel.apfelbaum@gmail.com>, "Philippe Mathieu-Daudé" <philmd@linaro.org>, Yanan Wang <wangyanan55@huawei.com>, Zhao Liu <zhao1.liu@intel.com>, "Marc-André Lureau" <marcandre.lureau@redhat.com>, "Daniel P. Berrangé" <berrange@redhat.com>, Alexander Graf <agraf@csgraf.de>
[PATCH v13 06/28] hw/arm: virt: cleanly fail on attempt to use the platform vGIC together with ITS
Posted by Mohamed Mediouni 1 week, 1 day ago
Switch its to a tristate.

Windows Hypervisor Platform's vGIC doesn't support ITS.
Deal with this by reporting to the user and exiting.

Regular configuration: GICv3 + ITS
New default configuration with WHPX: GICv3 with GICv2m
And its=off explicitly for the newest machine version: GICv3 + GICv2m

Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
---
 hw/arm/virt-acpi-build.c | 14 ++++++------
 hw/arm/virt.c            | 46 +++++++++++++++++++++++++++++++---------
 include/hw/arm/virt.h    |  4 +++-
 3 files changed, 46 insertions(+), 18 deletions(-)

diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 40ea6b6dd5..86024a1a73 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -473,7 +473,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
         nb_nodes = num_smmus + 1; /* RC and SMMUv3 */
         rc_mapping_count = rc_smmu_idmaps_len;
 
-        if (vms->its) {
+        if (virt_is_its_enabled(vms)) {
             /*
              * Knowing the ID ranges from the RC to the SMMU, it's possible to
              * determine the ID ranges from RC that go directly to ITS.
@@ -484,7 +484,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
             rc_mapping_count += rc_its_idmaps->len;
         }
     } else {
-        if (vms->its) {
+        if (virt_is_its_enabled(vms)) {
             nb_nodes = 2; /* RC and ITS */
             rc_mapping_count = 1; /* Direct map to ITS */
         } else {
@@ -499,7 +499,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
     build_append_int_noprefix(table_data, IORT_NODE_OFFSET, 4);
     build_append_int_noprefix(table_data, 0, 4); /* Reserved */
 
-    if (vms->its) {
+    if (virt_is_its_enabled(vms)) {
         /* Table 12 ITS Group Format */
         build_append_int_noprefix(table_data, 0 /* ITS Group */, 1); /* Type */
         node_size =  20 /* fixed header size */ + 4 /* 1 GIC ITS Identifier */;
@@ -518,7 +518,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
         int smmu_mapping_count, offset_to_id_array;
         int irq = sdev->irq;
 
-        if (vms->its) {
+        if (virt_is_its_enabled(vms)) {
             smmu_mapping_count = 1; /* ITS Group node */
             offset_to_id_array = SMMU_V3_ENTRY_SIZE; /* Just after the header */
         } else {
@@ -611,7 +611,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
             }
         }
 
-        if (vms->its) {
+        if (virt_is_its_enabled(vms)) {
             /*
              * Map bypassed (don't go through the SMMU) RIDs (input) to
              * ITS Group node directly: RC -> ITS.
@@ -946,7 +946,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
                                           memmap[VIRT_HIGH_GIC_REDIST2].size);
         }
 
-        if (vms->its) {
+        if (virt_is_its_enabled(vms)) {
             /*
              * ACPI spec, Revision 6.0 Errata A
              * (original 6.0 definition has invalid Length)
@@ -962,7 +962,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
         }
     }
 
-    if (!(vms->gic_version != VIRT_GIC_VERSION_2 && vms->its)
+    if (!(vms->gic_version != VIRT_GIC_VERSION_2 && virt_is_its_enabled(vms))
      && !vms->no_gicv3_with_gicv2m) {
         const uint16_t spi_base = vms->irqmap[VIRT_GIC_V2M] + ARM_SPI_BASE;
 
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 0fb8dcb07d..dcdb740586 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -737,7 +737,7 @@ static void create_its(VirtMachineState *vms)
 {
     DeviceState *dev;
 
-    assert(vms->its);
+    assert(virt_is_its_enabled(vms));
     if (!kvm_irqchip_in_kernel() && !vms->tcg_its) {
         /*
          * Do nothing if ITS is neither supported by the host nor emulated by
@@ -746,6 +746,15 @@ static void create_its(VirtMachineState *vms)
         return;
     }
 
+    if (whpx_enabled() && vms->tcg_its) {
+        /*
+         * Signal to the user when ITS is neither supported by the host
+         * nor emulated by the machine.
+         */
+        info_report("ITS not supported on WHPX.");
+        exit(1);
+    }
+
     dev = qdev_new(its_class_name());
 
     object_property_set_link(OBJECT(dev), "parent-gicv3", OBJECT(vms->gic),
@@ -957,7 +966,7 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem)
 
     fdt_add_gic_node(vms);
 
-    if (vms->gic_version != VIRT_GIC_VERSION_2 && vms->its) {
+    if (vms->gic_version != VIRT_GIC_VERSION_2 && virt_is_its_enabled(vms)) {
         create_its(vms);
     } else if (vms->gic_version != VIRT_GIC_VERSION_2 && !vms->no_gicv3_with_gicv2m) {
         create_v2m(vms);
@@ -2699,18 +2708,34 @@ static void virt_set_highmem_mmio_size(Object *obj, Visitor *v,
     extended_memmap[VIRT_HIGH_PCIE_MMIO].size = size;
 }
 
-static bool virt_get_its(Object *obj, Error **errp)
+bool virt_is_its_enabled(VirtMachineState *vms)
+{
+    if (vms->its == ON_OFF_AUTO_OFF) {
+        return false;
+    }
+    if (vms->its == ON_OFF_AUTO_AUTO) {
+        if (whpx_enabled()) {
+            return false;
+        }
+    }
+    return true;
+}
+
+static void virt_get_its(Object *obj, Visitor *v, const char *name,
+                          void *opaque, Error **errp)
 {
     VirtMachineState *vms = VIRT_MACHINE(obj);
+    OnOffAuto its = vms->its;
 
-    return vms->its;
+    visit_type_OnOffAuto(v, name, &its, errp);
 }
 
-static void virt_set_its(Object *obj, bool value, Error **errp)
+static void virt_set_its(Object *obj, Visitor *v, const char *name,
+                          void *opaque, Error **errp)
 {
     VirtMachineState *vms = VIRT_MACHINE(obj);
 
-    vms->its = value;
+    visit_type_OnOffAuto(v, name, &vms->its, errp);
 }
 
 static bool virt_get_dtb_randomness(Object *obj, Error **errp)
@@ -3427,8 +3452,9 @@ static void virt_machine_class_init(ObjectClass *oc, const void *data)
                                           "guest CPU which implements the ARM "
                                           "Memory Tagging Extension");
 
-    object_class_property_add_bool(oc, "its", virt_get_its,
-                                   virt_set_its);
+    object_class_property_add(oc, "its", "OnOffAuto",
+        virt_get_its, virt_set_its,
+        NULL, NULL);
     object_class_property_set_description(oc, "its",
                                           "Set on/off to enable/disable "
                                           "ITS instantiation");
@@ -3488,8 +3514,8 @@ static void virt_instance_init(Object *obj)
     vms->highmem_mmio = true;
     vms->highmem_redists = true;
 
-    /* Default allows ITS instantiation */
-    vms->its = true;
+    /* Default allows ITS instantiation if available */
+    vms->its = ON_OFF_AUTO_AUTO;
     /* Allow ITS emulation if the machine version supports it */
     vms->tcg_its = !vmc->no_tcg_its;
     vms->no_gicv3_with_gicv2m = false;
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index c5bc47ee88..394b70c62e 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -147,7 +147,7 @@ struct VirtMachineState {
     bool highmem_ecam;
     bool highmem_mmio;
     bool highmem_redists;
-    bool its;
+    OnOffAuto its;
     bool tcg_its;
     bool virt;
     bool ras;
@@ -216,4 +216,6 @@ static inline int virt_gicv3_redist_region_count(VirtMachineState *vms)
             vms->highmem_redists) ? 2 : 1;
 }
 
+bool virt_is_its_enabled(VirtMachineState *vms);
+
 #endif /* QEMU_ARM_VIRT_H */
-- 
2.50.1 (Apple Git-155)
Re: [PATCH v13 06/28] hw/arm: virt: cleanly fail on attempt to use the platform vGIC together with ITS
Posted by Akihiko Odaki 4 days, 23 hours ago
On 2025/12/30 9:03, Mohamed Mediouni wrote:
> Switch its to a tristate.
> 
> Windows Hypervisor Platform's vGIC doesn't support ITS.
> Deal with this by reporting to the user and exiting.
> 
> Regular configuration: GICv3 + ITS
> New default configuration with WHPX: GICv3 with GICv2m
> And its=off explicitly for the newest machine version: GICv3 + GICv2m
> 
> Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
> Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
> ---
>   hw/arm/virt-acpi-build.c | 14 ++++++------
>   hw/arm/virt.c            | 46 +++++++++++++++++++++++++++++++---------
>   include/hw/arm/virt.h    |  4 +++-
>   3 files changed, 46 insertions(+), 18 deletions(-)
> 
> diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
> index 40ea6b6dd5..86024a1a73 100644
> --- a/hw/arm/virt-acpi-build.c
> +++ b/hw/arm/virt-acpi-build.c
> @@ -473,7 +473,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
>           nb_nodes = num_smmus + 1; /* RC and SMMUv3 */
>           rc_mapping_count = rc_smmu_idmaps_len;
>   
> -        if (vms->its) {
> +        if (virt_is_its_enabled(vms)) {
>               /*
>                * Knowing the ID ranges from the RC to the SMMU, it's possible to
>                * determine the ID ranges from RC that go directly to ITS.
> @@ -484,7 +484,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
>               rc_mapping_count += rc_its_idmaps->len;
>           }
>       } else {
> -        if (vms->its) {
> +        if (virt_is_its_enabled(vms)) {
>               nb_nodes = 2; /* RC and ITS */
>               rc_mapping_count = 1; /* Direct map to ITS */
>           } else {
> @@ -499,7 +499,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
>       build_append_int_noprefix(table_data, IORT_NODE_OFFSET, 4);
>       build_append_int_noprefix(table_data, 0, 4); /* Reserved */
>   
> -    if (vms->its) {
> +    if (virt_is_its_enabled(vms)) {
>           /* Table 12 ITS Group Format */
>           build_append_int_noprefix(table_data, 0 /* ITS Group */, 1); /* Type */
>           node_size =  20 /* fixed header size */ + 4 /* 1 GIC ITS Identifier */;
> @@ -518,7 +518,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
>           int smmu_mapping_count, offset_to_id_array;
>           int irq = sdev->irq;
>   
> -        if (vms->its) {
> +        if (virt_is_its_enabled(vms)) {
>               smmu_mapping_count = 1; /* ITS Group node */
>               offset_to_id_array = SMMU_V3_ENTRY_SIZE; /* Just after the header */
>           } else {
> @@ -611,7 +611,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
>               }
>           }
>   
> -        if (vms->its) {
> +        if (virt_is_its_enabled(vms)) {
>               /*
>                * Map bypassed (don't go through the SMMU) RIDs (input) to
>                * ITS Group node directly: RC -> ITS.
> @@ -946,7 +946,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
>                                             memmap[VIRT_HIGH_GIC_REDIST2].size);
>           }
>   
> -        if (vms->its) {
> +        if (virt_is_its_enabled(vms)) {
>               /*
>                * ACPI spec, Revision 6.0 Errata A
>                * (original 6.0 definition has invalid Length)
> @@ -962,7 +962,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
>           }
>       }
>   
> -    if (!(vms->gic_version != VIRT_GIC_VERSION_2 && vms->its)
> +    if (!(vms->gic_version != VIRT_GIC_VERSION_2 && virt_is_its_enabled(vms))
>        && !vms->no_gicv3_with_gicv2m) {
>           const uint16_t spi_base = vms->irqmap[VIRT_GIC_V2M] + ARM_SPI_BASE;
>   
> diff --git a/hw/arm/virt.c b/hw/arm/virt.c
> index 0fb8dcb07d..dcdb740586 100644
> --- a/hw/arm/virt.c
> +++ b/hw/arm/virt.c
> @@ -737,7 +737,7 @@ static void create_its(VirtMachineState *vms)
>   {
>       DeviceState *dev;
>   
> -    assert(vms->its);
> +    assert(virt_is_its_enabled(vms));
>       if (!kvm_irqchip_in_kernel() && !vms->tcg_its) {
>           /*
>            * Do nothing if ITS is neither supported by the host nor emulated by
> @@ -746,6 +746,15 @@ static void create_its(VirtMachineState *vms)
>           return;
>       }
>   
> +    if (whpx_enabled() && vms->tcg_its) {
> +        /*
> +         * Signal to the user when ITS is neither supported by the host
> +         * nor emulated by the machine.
> +         */
> +        info_report("ITS not supported on WHPX.");

This use of info_report() is unusual. Any other configuration problems 
are reported with error_report() in this file. Please maintain consistency.

> +        exit(1);
> +    }
> +
>       dev = qdev_new(its_class_name());
>   
>       object_property_set_link(OBJECT(dev), "parent-gicv3", OBJECT(vms->gic),
> @@ -957,7 +966,7 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem)
>   
>       fdt_add_gic_node(vms);
>   
> -    if (vms->gic_version != VIRT_GIC_VERSION_2 && vms->its) {
> +    if (vms->gic_version != VIRT_GIC_VERSION_2 && virt_is_its_enabled(vms)) {
>           create_its(vms);
>       } else if (vms->gic_version != VIRT_GIC_VERSION_2 && !vms->no_gicv3_with_gicv2m) {
>           create_v2m(vms);
> @@ -2699,18 +2708,34 @@ static void virt_set_highmem_mmio_size(Object *obj, Visitor *v,
>       extended_memmap[VIRT_HIGH_PCIE_MMIO].size = size;
>   }
>   
> -static bool virt_get_its(Object *obj, Error **errp)
> +bool virt_is_its_enabled(VirtMachineState *vms)
> +{
> +    if (vms->its == ON_OFF_AUTO_OFF) {
> +        return false;
> +    }
> +    if (vms->its == ON_OFF_AUTO_AUTO) {
> +        if (whpx_enabled()) {
> +            return false;
> +        }
> +    }
> +    return true;
> +}
> +
> +static void virt_get_its(Object *obj, Visitor *v, const char *name,
> +                          void *opaque, Error **errp)
>   {
>       VirtMachineState *vms = VIRT_MACHINE(obj);
> +    OnOffAuto its = vms->its;
>   
> -    return vms->its;
> +    visit_type_OnOffAuto(v, name, &its, errp);
>   }
>   
> -static void virt_set_its(Object *obj, bool value, Error **errp)
> +static void virt_set_its(Object *obj, Visitor *v, const char *name,
> +                          void *opaque, Error **errp)
>   {
>       VirtMachineState *vms = VIRT_MACHINE(obj);
>   
> -    vms->its = value;
> +    visit_type_OnOffAuto(v, name, &vms->its, errp);
>   }
>   
>   static bool virt_get_dtb_randomness(Object *obj, Error **errp)
> @@ -3427,8 +3452,9 @@ static void virt_machine_class_init(ObjectClass *oc, const void *data)
>                                             "guest CPU which implements the ARM "
>                                             "Memory Tagging Extension");
>   
> -    object_class_property_add_bool(oc, "its", virt_get_its,
> -                                   virt_set_its);
> +    object_class_property_add(oc, "its", "OnOffAuto",
> +        virt_get_its, virt_set_its,
> +        NULL, NULL);
>       object_class_property_set_description(oc, "its",
>                                             "Set on/off to enable/disable "
>                                             "ITS instantiation");
> @@ -3488,8 +3514,8 @@ static void virt_instance_init(Object *obj)
>       vms->highmem_mmio = true;
>       vms->highmem_redists = true;
>   
> -    /* Default allows ITS instantiation */
> -    vms->its = true;
> +    /* Default allows ITS instantiation if available */
> +    vms->its = ON_OFF_AUTO_AUTO;
>       /* Allow ITS emulation if the machine version supports it */
>       vms->tcg_its = !vmc->no_tcg_its;
>       vms->no_gicv3_with_gicv2m = false;
> diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
> index c5bc47ee88..394b70c62e 100644
> --- a/include/hw/arm/virt.h
> +++ b/include/hw/arm/virt.h
> @@ -147,7 +147,7 @@ struct VirtMachineState {
>       bool highmem_ecam;
>       bool highmem_mmio;
>       bool highmem_redists;
> -    bool its;
> +    OnOffAuto its;
>       bool tcg_its;
>       bool virt;
>       bool ras;
> @@ -216,4 +216,6 @@ static inline int virt_gicv3_redist_region_count(VirtMachineState *vms)
>               vms->highmem_redists) ? 2 : 1;
>   }
>   
> +bool virt_is_its_enabled(VirtMachineState *vms);
> +
>   #endif /* QEMU_ARM_VIRT_H */
Re: [PATCH v13 06/28] hw/arm: virt: cleanly fail on attempt to use the platform vGIC together with ITS
Posted by Akihiko Odaki 4 days, 18 hours ago
On 2026/01/02 19:24, Akihiko Odaki wrote:
> On 2025/12/30 9:03, Mohamed Mediouni wrote:
>> Switch its to a tristate.
>>
>> Windows Hypervisor Platform's vGIC doesn't support ITS.
>> Deal with this by reporting to the user and exiting.
>>
>> Regular configuration: GICv3 + ITS
>> New default configuration with WHPX: GICv3 with GICv2m
>> And its=off explicitly for the newest machine version: GICv3 + GICv2m
>>
>> Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
>> Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
>> ---
>>   hw/arm/virt-acpi-build.c | 14 ++++++------
>>   hw/arm/virt.c            | 46 +++++++++++++++++++++++++++++++---------
>>   include/hw/arm/virt.h    |  4 +++-
>>   3 files changed, 46 insertions(+), 18 deletions(-)
>>
>> diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
>> index 40ea6b6dd5..86024a1a73 100644
>> --- a/hw/arm/virt-acpi-build.c
>> +++ b/hw/arm/virt-acpi-build.c
>> @@ -473,7 +473,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, 
>> VirtMachineState *vms)
>>           nb_nodes = num_smmus + 1; /* RC and SMMUv3 */
>>           rc_mapping_count = rc_smmu_idmaps_len;
>> -        if (vms->its) {
>> +        if (virt_is_its_enabled(vms)) {
>>               /*
>>                * Knowing the ID ranges from the RC to the SMMU, it's 
>> possible to
>>                * determine the ID ranges from RC that go directly to ITS.
>> @@ -484,7 +484,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, 
>> VirtMachineState *vms)
>>               rc_mapping_count += rc_its_idmaps->len;
>>           }
>>       } else {
>> -        if (vms->its) {
>> +        if (virt_is_its_enabled(vms)) {
>>               nb_nodes = 2; /* RC and ITS */
>>               rc_mapping_count = 1; /* Direct map to ITS */
>>           } else {
>> @@ -499,7 +499,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, 
>> VirtMachineState *vms)
>>       build_append_int_noprefix(table_data, IORT_NODE_OFFSET, 4);
>>       build_append_int_noprefix(table_data, 0, 4); /* Reserved */
>> -    if (vms->its) {
>> +    if (virt_is_its_enabled(vms)) {
>>           /* Table 12 ITS Group Format */
>>           build_append_int_noprefix(table_data, 0 /* ITS Group */, 
>> 1); /* Type */
>>           node_size =  20 /* fixed header size */ + 4 /* 1 GIC ITS 
>> Identifier */;
>> @@ -518,7 +518,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, 
>> VirtMachineState *vms)
>>           int smmu_mapping_count, offset_to_id_array;
>>           int irq = sdev->irq;
>> -        if (vms->its) {
>> +        if (virt_is_its_enabled(vms)) {
>>               smmu_mapping_count = 1; /* ITS Group node */
>>               offset_to_id_array = SMMU_V3_ENTRY_SIZE; /* Just after 
>> the header */
>>           } else {
>> @@ -611,7 +611,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, 
>> VirtMachineState *vms)
>>               }
>>           }
>> -        if (vms->its) {
>> +        if (virt_is_its_enabled(vms)) {
>>               /*
>>                * Map bypassed (don't go through the SMMU) RIDs (input) to
>>                * ITS Group node directly: RC -> ITS.
>> @@ -946,7 +946,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, 
>> VirtMachineState *vms)
>>                                             
>> memmap[VIRT_HIGH_GIC_REDIST2].size);
>>           }
>> -        if (vms->its) {
>> +        if (virt_is_its_enabled(vms)) {
>>               /*
>>                * ACPI spec, Revision 6.0 Errata A
>>                * (original 6.0 definition has invalid Length)
>> @@ -962,7 +962,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, 
>> VirtMachineState *vms)
>>           }
>>       }
>> -    if (!(vms->gic_version != VIRT_GIC_VERSION_2 && vms->its)
>> +    if (!(vms->gic_version != VIRT_GIC_VERSION_2 && 
>> virt_is_its_enabled(vms))
>>        && !vms->no_gicv3_with_gicv2m) {
>>           const uint16_t spi_base = vms->irqmap[VIRT_GIC_V2M] + 
>> ARM_SPI_BASE;
>> diff --git a/hw/arm/virt.c b/hw/arm/virt.c
>> index 0fb8dcb07d..dcdb740586 100644
>> --- a/hw/arm/virt.c
>> +++ b/hw/arm/virt.c
>> @@ -737,7 +737,7 @@ static void create_its(VirtMachineState *vms)
>>   {
>>       DeviceState *dev;
>> -    assert(vms->its);
>> +    assert(virt_is_its_enabled(vms));
>>       if (!kvm_irqchip_in_kernel() && !vms->tcg_its) {
>>           /*
>>            * Do nothing if ITS is neither supported by the host nor 
>> emulated by
>> @@ -746,6 +746,15 @@ static void create_its(VirtMachineState *vms)
>>           return;
>>       }
>> +    if (whpx_enabled() && vms->tcg_its) {

The check of vms->tcg_its is apparently extraneous and should be removed.

tcg_its is a compatibility flag that tells not to emulate ITS when kvm 
is enabled for old machine versions and has nothing to do with whpx. 
Having vms->tcg_its in the condition lets the machine create ITS for old 
machine versions even if whpx is enabled.

ITS should be disabled whenever whpx is enabled since "ITS is neither 
supported by the host nor emulated by the machine" as the following 
comment points out.

>> +        /*
>> +         * Signal to the user when ITS is neither supported by the host
>> +         * nor emulated by the machine.
>> +         */
>> +        info_report("ITS not supported on WHPX.");
> 
> This use of info_report() is unusual. Any other configuration problems 
> are reported with error_report() in this file. Please maintain consistency.
> 
>> +        exit(1);
>> +    }
>> +
>>       dev = qdev_new(its_class_name());
>>       object_property_set_link(OBJECT(dev), "parent-gicv3", 
>> OBJECT(vms->gic),
>> @@ -957,7 +966,7 @@ static void create_gic(VirtMachineState *vms, 
>> MemoryRegion *mem)
>>       fdt_add_gic_node(vms);
>> -    if (vms->gic_version != VIRT_GIC_VERSION_2 && vms->its) {
>> +    if (vms->gic_version != VIRT_GIC_VERSION_2 && 
>> virt_is_its_enabled(vms)) {
>>           create_its(vms);
>>       } else if (vms->gic_version != VIRT_GIC_VERSION_2 && !vms- 
>> >no_gicv3_with_gicv2m) {
>>           create_v2m(vms);
>> @@ -2699,18 +2708,34 @@ static void virt_set_highmem_mmio_size(Object 
>> *obj, Visitor *v,
>>       extended_memmap[VIRT_HIGH_PCIE_MMIO].size = size;
>>   }
>> -static bool virt_get_its(Object *obj, Error **errp)
>> +bool virt_is_its_enabled(VirtMachineState *vms)
>> +{
>> +    if (vms->its == ON_OFF_AUTO_OFF) {
>> +        return false;
>> +    }
>> +    if (vms->its == ON_OFF_AUTO_AUTO) {
>> +        if (whpx_enabled()) {
>> +            return false;
>> +        }
>> +    }
>> +    return true;
>> +}
>> +
>> +static void virt_get_its(Object *obj, Visitor *v, const char *name,
>> +                          void *opaque, Error **errp)
>>   {
>>       VirtMachineState *vms = VIRT_MACHINE(obj);
>> +    OnOffAuto its = vms->its;
>> -    return vms->its;
>> +    visit_type_OnOffAuto(v, name, &its, errp);
>>   }
>> -static void virt_set_its(Object *obj, bool value, Error **errp)
>> +static void virt_set_its(Object *obj, Visitor *v, const char *name,
>> +                          void *opaque, Error **errp)
>>   {
>>       VirtMachineState *vms = VIRT_MACHINE(obj);
>> -    vms->its = value;
>> +    visit_type_OnOffAuto(v, name, &vms->its, errp);
>>   }
>>   static bool virt_get_dtb_randomness(Object *obj, Error **errp)
>> @@ -3427,8 +3452,9 @@ static void virt_machine_class_init(ObjectClass 
>> *oc, const void *data)
>>                                             "guest CPU which 
>> implements the ARM "
>>                                             "Memory Tagging Extension");
>> -    object_class_property_add_bool(oc, "its", virt_get_its,
>> -                                   virt_set_its);
>> +    object_class_property_add(oc, "its", "OnOffAuto",
>> +        virt_get_its, virt_set_its,
>> +        NULL, NULL);
>>       object_class_property_set_description(oc, "its",
>>                                             "Set on/off to enable/ 
>> disable "
>>                                             "ITS instantiation");
>> @@ -3488,8 +3514,8 @@ static void virt_instance_init(Object *obj)
>>       vms->highmem_mmio = true;
>>       vms->highmem_redists = true;
>> -    /* Default allows ITS instantiation */
>> -    vms->its = true;
>> +    /* Default allows ITS instantiation if available */
>> +    vms->its = ON_OFF_AUTO_AUTO;
>>       /* Allow ITS emulation if the machine version supports it */
>>       vms->tcg_its = !vmc->no_tcg_its;
>>       vms->no_gicv3_with_gicv2m = false;
>> diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
>> index c5bc47ee88..394b70c62e 100644
>> --- a/include/hw/arm/virt.h
>> +++ b/include/hw/arm/virt.h
>> @@ -147,7 +147,7 @@ struct VirtMachineState {
>>       bool highmem_ecam;
>>       bool highmem_mmio;
>>       bool highmem_redists;
>> -    bool its;
>> +    OnOffAuto its;
>>       bool tcg_its;
>>       bool virt;
>>       bool ras;
>> @@ -216,4 +216,6 @@ static inline int 
>> virt_gicv3_redist_region_count(VirtMachineState *vms)
>>               vms->highmem_redists) ? 2 : 1;
>>   }
>> +bool virt_is_its_enabled(VirtMachineState *vms);
>> +
>>   #endif /* QEMU_ARM_VIRT_H */
>