On Hypervisor.framework for macOS and WHPX for Windows, the provided environment is a GICv3 without ITS.
As such, support a GICv3 w/ GICv2m for that scenario.
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
---
hw/arm/virt-acpi-build.c | 5 ++++-
hw/arm/virt.c | 8 ++++++++
include/hw/arm/virt.h | 2 ++
3 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 03b4342574..40ea6b6dd5 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -960,7 +960,10 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
build_append_int_noprefix(table_data, memmap[VIRT_GIC_ITS].base, 8);
build_append_int_noprefix(table_data, 0, 4); /* Reserved */
}
- } else {
+ }
+
+ if (!(vms->gic_version != VIRT_GIC_VERSION_2 && vms->its)
+ && !vms->no_gicv3_with_gicv2m) {
const uint16_t spi_base = vms->irqmap[VIRT_GIC_V2M] + ARM_SPI_BASE;
/* 5.2.12.16 GIC MSI Frame Structure */
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 4badc1a734..275f26d439 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -959,6 +959,8 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem)
if (vms->gic_version != VIRT_GIC_VERSION_2 && vms->its) {
create_its(vms);
+ } else if (vms->gic_version != VIRT_GIC_VERSION_2 && !vms->no_gicv3_with_gicv2m) {
+ create_v2m(vms);
} else if (vms->gic_version == VIRT_GIC_VERSION_2) {
create_v2m(vms);
}
@@ -2449,6 +2451,8 @@ static void machvirt_init(MachineState *machine)
vms->ns_el2_virt_timer_irq = ns_el2_virt_timer_present() &&
!vmc->no_ns_el2_virt_timer_irq;
+ vms->no_gicv3_with_gicv2m = vmc->no_gicv3_with_gicv2m;
+
fdt_add_timer_nodes(vms);
fdt_add_cpu_nodes(vms);
@@ -3497,6 +3501,7 @@ static void virt_instance_init(Object *obj)
vms->its = true;
/* Allow ITS emulation if the machine version supports it */
vms->tcg_its = !vmc->no_tcg_its;
+ vms->no_gicv3_with_gicv2m = false;
/* Default disallows iommu instantiation */
vms->iommu = VIRT_IOMMU_NONE;
@@ -3549,7 +3554,10 @@ DEFINE_VIRT_MACHINE_AS_LATEST(11, 0)
static void virt_machine_10_2_options(MachineClass *mc)
{
+ VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc));
+
virt_machine_11_0_options(mc);
+ vmc->no_gicv3_with_gicv2m = true;
compat_props_add(mc->compat_props, hw_compat_10_2, hw_compat_10_2_len);
}
DEFINE_VIRT_MACHINE(10, 2)
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index 5907d41dbb..b7e59b8c63 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -130,6 +130,7 @@ struct VirtMachineClass {
bool no_cpu_topology;
bool no_tcg_lpa2;
bool no_ns_el2_virt_timer_irq;
+ bool no_gicv3_with_gicv2m;
bool no_nested_smmu;
};
@@ -178,6 +179,7 @@ struct VirtMachineState {
char *oem_id;
char *oem_table_id;
bool ns_el2_virt_timer_irq;
+ bool no_gicv3_with_gicv2m;
CXLState cxl_devices_state;
bool legacy_smmuv3_present;
MemoryRegion *sysmem;
--
2.50.1 (Apple Git-155)
On Fri, 16 Jan 2026 at 13:52, Mohamed Mediouni <mohamed@unpredictable.fr> wrote:
>
> On Hypervisor.framework for macOS and WHPX for Windows, the provided environment is a GICv3 without ITS.
>
> As such, support a GICv3 w/ GICv2m for that scenario.
>
> Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
>
> Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
> ---
> hw/arm/virt-acpi-build.c | 5 ++++-
> hw/arm/virt.c | 8 ++++++++
> include/hw/arm/virt.h | 2 ++
> 3 files changed, 14 insertions(+), 1 deletion(-)
>
> diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
> index 03b4342574..40ea6b6dd5 100644
> --- a/hw/arm/virt-acpi-build.c
> +++ b/hw/arm/virt-acpi-build.c
> @@ -960,7 +960,10 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
> build_append_int_noprefix(table_data, memmap[VIRT_GIC_ITS].base, 8);
> build_append_int_noprefix(table_data, 0, 4); /* Reserved */
> }
> - } else {
> + }
> +
> + if (!(vms->gic_version != VIRT_GIC_VERSION_2 && vms->its)
> + && !vms->no_gicv3_with_gicv2m) {
> const uint16_t spi_base = vms->irqmap[VIRT_GIC_V2M] + ARM_SPI_BASE;
>
> /* 5.2.12.16 GIC MSI Frame Structure */
> diff --git a/hw/arm/virt.c b/hw/arm/virt.c
> index 4badc1a734..275f26d439 100644
> --- a/hw/arm/virt.c
> +++ b/hw/arm/virt.c
> @@ -959,6 +959,8 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem)
>
> if (vms->gic_version != VIRT_GIC_VERSION_2 && vms->its) {
> create_its(vms);
> + } else if (vms->gic_version != VIRT_GIC_VERSION_2 && !vms->no_gicv3_with_gicv2m) {
> + create_v2m(vms);
> } else if (vms->gic_version == VIRT_GIC_VERSION_2) {
> create_v2m(vms);
> }
> @@ -2449,6 +2451,8 @@ static void machvirt_init(MachineState *machine)
> vms->ns_el2_virt_timer_irq = ns_el2_virt_timer_present() &&
> !vmc->no_ns_el2_virt_timer_irq;
>
> + vms->no_gicv3_with_gicv2m = vmc->no_gicv3_with_gicv2m;
> +
> fdt_add_timer_nodes(vms);
> fdt_add_cpu_nodes(vms);
>
> @@ -3497,6 +3501,7 @@ static void virt_instance_init(Object *obj)
> vms->its = true;
> /* Allow ITS emulation if the machine version supports it */
> vms->tcg_its = !vmc->no_tcg_its;
> + vms->no_gicv3_with_gicv2m = false;
>
> /* Default disallows iommu instantiation */
> vms->iommu = VIRT_IOMMU_NONE;
> @@ -3549,7 +3554,10 @@ DEFINE_VIRT_MACHINE_AS_LATEST(11, 0)
>
> static void virt_machine_10_2_options(MachineClass *mc)
> {
> + VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc));
> +
> virt_machine_11_0_options(mc);
> + vmc->no_gicv3_with_gicv2m = true;
> compat_props_add(mc->compat_props, hw_compat_10_2, hw_compat_10_2_len);
> }
The MSI controller selection logic is already pretty confusing,
and this is making it more complicated. I don't think we should
need this machine back compatibility, because currently there
is no setup where you can have a GICv3 that doesn't also have
either an ITS or no MSI controller.
I think also that we can make the code cleaner if we:
(1) clean the existing "pick an MSI controller" logic up
so that we do it up front, the same way we do "pick a GIC
version"
(2) add the new "msi" property and deprecate the old "its" one
(3) then add the gicv3-with-gicv2m-on-hvf logic to that
I see this series adds an "msi" property, but it also
makes the old "its" property an OnOffAuto -- do we really
need both ?
I wrote some code for this this afternoon before I realised
that you'd done the "msi" property in that series (so the
duplication with your work is my fault). I'll send them
out as an RFC to give an idea of what I have in mind.
thanks
-- PMM
> On 20. Jan 2026, at 19:02, Peter Maydell <peter.maydell@linaro.org> wrote: > The MSI controller selection logic is already pretty confusing, > and this is making it more complicated. I don't think we should > need this machine back compatibility, because currently there > is no setup where you can have a GICv3 that doesn't also have > either an ITS or no MSI controller. > Hello, This was to replicate the “no_tcg_its” where this was done when introducing TCG. And for the purpose of VM save/restore on HVF with the older machine type continuing to work as expected. Also worth noting that for HVF specifically GICv3 + ITS works today when using kernel-irqchip=off and that only kernel-irqchip=on to leverage the hardware vGIC doesn’t support it. > I think also that we can make the code cleaner if we: > (1) clean the existing "pick an MSI controller" logic up > so that we do it up front, the same way we do "pick a GIC > version" > (2) add the new "msi" property and deprecate the old "its" one > (3) then add the gicv3-with-gicv2m-on-hvf logic to that > > I see this series adds an "msi" property, but it also > makes the old "its" property an OnOffAuto -- do we really > need both ? The “rework MSI-X configuration” patch in the series flips the “its” property back to a bool. Would it be better to reorder that earlier in the series or keep it as is? Squashing the “hw/arm: virt: cleanly fail on attempt to use the platform vGIC together with ITS” commit with “rework MSI-X configuration” is an option too. Thank you, -Mohamed > I wrote some code for this this afternoon before I realised > that you'd done the "msi" property in that series (so the > duplication with your work is my fault). I'll send them > out as an RFC to give an idea of what I have in mind.
On Tue, 20 Jan 2026 at 18:44, Mohamed Mediouni <mohamed@unpredictable.fr> wrote: > > > > > On 20. Jan 2026, at 19:02, Peter Maydell <peter.maydell@linaro.org> wrote: > > > > The MSI controller selection logic is already pretty confusing, > > and this is making it more complicated. I don't think we should > > need this machine back compatibility, because currently there > > is no setup where you can have a GICv3 that doesn't also have > > either an ITS or no MSI controller. > > > Hello, > > This was to replicate the “no_tcg_its” where this was done when introducing TCG. > And for the purpose of VM save/restore on HVF with the older machine type continuing to work as expected. no_tcg_its is there for backwards compatibility: on older QEMU versions before we added the TCG ITS, if you said "-machine virt,gic-version=3 -accel tcg" you didn't get an ITS; we wanted to change the default in new machine versions, so we needed the back compat switch. What is the command line that works today and where we want to go from "default to GICv3 without ITS or v2m" to "default to GICv3 with v2m" ? I might have missed it but back last year when I was looking at the current configs I didn't think we had one. thanks -- PMM
> On 21. Jan 2026, at 10:27, Peter Maydell <peter.maydell@linaro.org> wrote: > > On Tue, 20 Jan 2026 at 18:44, Mohamed Mediouni <mohamed@unpredictable.fr> wrote: >> >> >> >>> On 20. Jan 2026, at 19:02, Peter Maydell <peter.maydell@linaro.org> wrote: >> >> >>> The MSI controller selection logic is already pretty confusing, >>> and this is making it more complicated. I don't think we should >>> need this machine back compatibility, because currently there >>> is no setup where you can have a GICv3 that doesn't also have >>> either an ITS or no MSI controller. >>> >> Hello, >> >> This was to replicate the “no_tcg_its” where this was done when introducing TCG. >> And for the purpose of VM save/restore on HVF with the older machine type continuing to work as expected. > > no_tcg_its is there for backwards compatibility: on older > QEMU versions before we added the TCG ITS, if you said > "-machine virt,gic-version=3 -accel tcg" you didn't get an > ITS; we wanted to change the default in new machine versions, > so we needed the back compat switch. > > What is the command line that works today and where we > want to go from "default to GICv3 without ITS or v2m" > to "default to GICv3 with v2m" ? I might have missed it > but back last year when I was looking at the current > configs I didn't think we had one. Hello, None, was thinking about what its=off should mean but perhaps the right behaviour to do there is to have it mean no MSI-X controller. The no_gicv3_with_gicv2m flag is solely used for the its config option (which is legacy) and not used for the msi config option. Will make the next patch rev make its=off mean no MSI-X controller at all and remove the no_gicv3_with_gicv2m flag then. > thanks > -- PMM
On Wed, 21 Jan 2026 at 10:19, Mohamed Mediouni <mohamed@unpredictable.fr> wrote:
>
>
>
> > On 21. Jan 2026, at 10:27, Peter Maydell <peter.maydell@linaro.org> wrote:
> >
> > On Tue, 20 Jan 2026 at 18:44, Mohamed Mediouni <mohamed@unpredictable.fr> wrote:
> >>
> >>
> >>
> >>> On 20. Jan 2026, at 19:02, Peter Maydell <peter.maydell@linaro.org> wrote:
> >>
> >>
> >>> The MSI controller selection logic is already pretty confusing,
> >>> and this is making it more complicated. I don't think we should
> >>> need this machine back compatibility, because currently there
> >>> is no setup where you can have a GICv3 that doesn't also have
> >>> either an ITS or no MSI controller.
> >>>
> >> Hello,
> >>
> >> This was to replicate the “no_tcg_its” where this was done when introducing TCG.
> >> And for the purpose of VM save/restore on HVF with the older machine type continuing to work as expected.
> >
> > no_tcg_its is there for backwards compatibility: on older
> > QEMU versions before we added the TCG ITS, if you said
> > "-machine virt,gic-version=3 -accel tcg" you didn't get an
> > ITS; we wanted to change the default in new machine versions,
> > so we needed the back compat switch.
> >
> > What is the command line that works today and where we
> > want to go from "default to GICv3 without ITS or v2m"
> > to "default to GICv3 with v2m" ? I might have missed it
> > but back last year when I was looking at the current
> > configs I didn't think we had one.
> Hello,
>
> None, was thinking about what its=off should mean but perhaps
> the right behaviour to do there is to have it mean no MSI-X controller.
Yeah, this is a bit tricky. I think that at the moment
we allow "gic-version=2,its=off" and you still get a gicv2m.
So we need to retain that behaviour (though I doubt anybody
is deliberately using it), which I think means we do need
the its option to be an on/off/auto one. On the other
hand that means that the finalize_msi_controller() logic
(see https://patchew.org/QEMU/20260120180339.1416328-1-peter.maydell@linaro.org/
that I posted yesterday) can look relatively neat:
if (vms->its != auto) {
/*
* User set the legacy "its" option, which traditionally
* meant "ignored if GICv2 (always provide GICv2m), enable
* or disable ITS for GICv3".
* Translate into its "msi" option equivalent:
* - "its=no" means "msi=gicv2m" for a GICv2, "msi=none"
* for GICv3 and up.
* - "its=yes" means "msi=auto"
*/
if (vms->msi_controller != VIRT_MSI_CTRL_NOSEL) {
error("msi and its options cannot be used together");
exit(1);
}
if (vms->its == off) {
if (vms->gic_version == VIRT_GIC_VERSION_2) {
vms->msi_controller = VIRT_MSI_CTRL_GICV2M;
} else {
vms->msi_controller = VIRT_MSI_CTRL_NONE;
}
}
/* for vms->its == on we leave msi_controller at NOSEL */
}
if (vms->msi_controller != VIRT_MSI_CTRL_NOSEL) {
/*
* User specified an "msi" option: check what they
* specified, and use it.
*/
if (vms->msi_controller == VIRT_MSI_CTRL_ITS &&
vms->gic_version == VIRT_GIC_VERSION_2) {
error_report("A GICv2 cannot use an ITS");
exit(1);
}
/* other error checks here as needed */
return;
}
/* logic to pick the best msi_controller goes here */
This puts all the option handling code in one function that
has three parts:
* deal with the legacy its= option by converting it to
the equivalent msi= option
* error check any explicitly set msi option
* pick an msi for the user if they didn't specify
Then the rest of the code in virt.c doesn't need to care
about the option flags or back-compat stuff directly, it
can look at just the final resulting msi_controller setting.
thanks
-- PMM
> On 21. Jan 2026, at 12:33, Peter Maydell <peter.maydell@linaro.org> wrote:
>
> which I think means we do need
> the its option to be an on/off/auto one
Hello,
Would this be ok instead?
typedef enum VirtMSIControllerType {
VIRT_MSI_CTRL_NONE,
/* This value is overriden at runtime.*/
VIRT_MSI_CTRL_AUTO,
/* Legacy option: its=off provides a GICv2m when using GICv2.*/
VIRT_MSI_LEGACY_OPT_ITS_OFF,
VIRT_MSI_CTRL_GICV2M,
VIRT_MSI_CTRL_ITS,
} VirtMSIControllerType;
Combined with:
static void finalize_msi_controller(VirtMachineState *vms)
{
if (vms->msi_controller == VIRT_MSI_LEGACY_OPT_ITS_OFF) {
if (vms->gic_version == 2) {
vms->msi_controller = VIRT_MSI_CTRL_GICV2M;
}
else {
vms->msi_controller = VIRT_MSI_CTRL_NONE;
}
}
Thank you,
-Mohamed
On Wed, 21 Jan 2026 at 12:00, Mohamed Mediouni <mohamed@unpredictable.fr> wrote:
>
>
>
> > On 21. Jan 2026, at 12:33, Peter Maydell <peter.maydell@linaro.org> wrote:
> >
> > which I think means we do need
> > the its option to be an on/off/auto one
>
> Hello,
>
> Would this be ok instead?
>
> typedef enum VirtMSIControllerType {
> VIRT_MSI_CTRL_NONE,
> /* This value is overriden at runtime.*/
> VIRT_MSI_CTRL_AUTO,
> /* Legacy option: its=off provides a GICv2m when using GICv2.*/
> VIRT_MSI_LEGACY_OPT_ITS_OFF,
> VIRT_MSI_CTRL_GICV2M,
> VIRT_MSI_CTRL_ITS,
> } VirtMSIControllerType;
>
> Combined with:
>
> static void finalize_msi_controller(VirtMachineState *vms)
> {
> if (vms->msi_controller == VIRT_MSI_LEGACY_OPT_ITS_OFF) {
> if (vms->gic_version == 2) {
> vms->msi_controller = VIRT_MSI_CTRL_GICV2M;
> }
> else {
> vms->msi_controller = VIRT_MSI_CTRL_NONE;
> }
> }
Is this with the idea that the its option get/set
functions would set msi_controller (to ITS_OFF or ITS) ?
thanks
-- PMM
> On 21. Jan 2026, at 13:19, Peter Maydell <peter.maydell@linaro.org> wrote:
>
> On Wed, 21 Jan 2026 at 12:00, Mohamed Mediouni <mohamed@unpredictable.fr> wrote:
>>
>>
>>
>>> On 21. Jan 2026, at 12:33, Peter Maydell <peter.maydell@linaro.org> wrote:
>>>
>>> which I think means we do need
>>> the its option to be an on/off/auto one
>>
>> Hello,
>>
>> Would this be ok instead?
>>
>> typedef enum VirtMSIControllerType {
>> VIRT_MSI_CTRL_NONE,
>> /* This value is overriden at runtime.*/
>> VIRT_MSI_CTRL_AUTO,
>> /* Legacy option: its=off provides a GICv2m when using GICv2.*/
>> VIRT_MSI_LEGACY_OPT_ITS_OFF,
>> VIRT_MSI_CTRL_GICV2M,
>> VIRT_MSI_CTRL_ITS,
>> } VirtMSIControllerType;
>>
>> Combined with:
>>
>> static void finalize_msi_controller(VirtMachineState *vms)
>> {
>> if (vms->msi_controller == VIRT_MSI_LEGACY_OPT_ITS_OFF) {
>> if (vms->gic_version == 2) {
>> vms->msi_controller = VIRT_MSI_CTRL_GICV2M;
>> }
>> else {
>> vms->msi_controller = VIRT_MSI_CTRL_NONE;
>> }
>> }
>
> Is this with the idea that the its option get/set
> functions would set msi_controller (to ITS_OFF or ITS) ?
>
Yes, vms->its is completely gone in my tree.
Going to post a rev with it soon, would you prefer to have it separate instead of a whole WHPX series?
> thanks
> -- PMM
On Wed, 21 Jan 2026 at 12:27, Mohamed Mediouni <mohamed@unpredictable.fr> wrote:
>
>
>
> > On 21. Jan 2026, at 13:19, Peter Maydell <peter.maydell@linaro.org> wrote:
> >
> > On Wed, 21 Jan 2026 at 12:00, Mohamed Mediouni <mohamed@unpredictable.fr> wrote:
> >>
> >>
> >>
> >>> On 21. Jan 2026, at 12:33, Peter Maydell <peter.maydell@linaro.org> wrote:
> >>>
> >>> which I think means we do need
> >>> the its option to be an on/off/auto one
> >>
> >> Hello,
> >>
> >> Would this be ok instead?
> >>
> >> typedef enum VirtMSIControllerType {
> >> VIRT_MSI_CTRL_NONE,
> >> /* This value is overriden at runtime.*/
> >> VIRT_MSI_CTRL_AUTO,
> >> /* Legacy option: its=off provides a GICv2m when using GICv2.*/
> >> VIRT_MSI_LEGACY_OPT_ITS_OFF,
> >> VIRT_MSI_CTRL_GICV2M,
> >> VIRT_MSI_CTRL_ITS,
> >> } VirtMSIControllerType;
> >>
> >> Combined with:
> >>
> >> static void finalize_msi_controller(VirtMachineState *vms)
> >> {
> >> if (vms->msi_controller == VIRT_MSI_LEGACY_OPT_ITS_OFF) {
> >> if (vms->gic_version == 2) {
> >> vms->msi_controller = VIRT_MSI_CTRL_GICV2M;
> >> }
> >> else {
> >> vms->msi_controller = VIRT_MSI_CTRL_NONE;
> >> }
> >> }
> >
> > Is this with the idea that the its option get/set
> > functions would set msi_controller (to ITS_OFF or ITS) ?
> >
> Yes, vms->its is completely gone in my tree.
That sounds like a good cleanup -- I was hoping to get
rid of vms->its but didn't quite see the way to doing it.
> Going to post a rev with it soon, would you prefer to have
> it separate instead of a whole WHPX series?
If these cleanup patches are at the start of the series
you might as well post the whole lot with the WHPX patches.
thanks
-- PMM
© 2016 - 2026 Red Hat, Inc.