Re: [PATCH v6 35/39] KVM: arm64: gic-v5: Probe for GICv5 device

Sascha Bischoff
2026-03-19T08:37:30Z

On Wed, 2026-03-18 at 15:34 +0000, Joey Gouly wrote:
> On Tue, Mar 17, 2026 at 11:49:02AM +0000, Sascha Bischoff wrote:
> > The basic GICv5 PPI support is now complete. Allow probing for a
> > native GICv5 rather than just the legacy support.
> >
> > The implementation doesn't support protected VMs with GICv5 at this
> > time. Therefore, if KVM has protected mode enabled the native GICv5
> > init is skipped, but legacy VMs are allowed if the hardware
> > supports
> > it.
> >
> > At this stage the GICv5 KVM implementation only supports PPIs, and
> > doesn't interact with the host IRS at all. This means that there is
> > no
> > need to check how many concurrent VMs or vCPUs per VM are supported
> > by
> > the IRS - the PPI support only requires the CPUIF. The support is
> > artificially limited to VGIC_V5_MAX_CPUS, i.e. 512, vCPUs per VM.
> >
> > With this change it becomes possible to run basic GICv5-based VMs,
> > provided that they only use PPIs.
> >
> > Co-authored-by: Timothy Hayes <timothy.hayes@arm.com>
> > Signed-off-by: Timothy Hayes <timothy.hayes@arm.com>
> > Signed-off-by: Sascha Bischoff <sascha.bischoff@arm.com>
> > Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
> > Reviewed-by: Joey Gouly <joey.gouly@arm.com>
> > ---
> >  arch/arm64/kvm/vgic/vgic-v5.c | 43 ++++++++++++++++++++++++++-----
> > ----
> >  1 file changed, 32 insertions(+), 11 deletions(-)
> >
> > diff --git a/arch/arm64/kvm/vgic/vgic-v5.c
> > b/arch/arm64/kvm/vgic/vgic-v5.c
> > index 32565bfbd1051..e491ae0e4f56e 100644
> > --- a/arch/arm64/kvm/vgic/vgic-v5.c
> > +++ b/arch/arm64/kvm/vgic/vgic-v5.c
> > @@ -39,24 +39,13 @@ static void vgic_v5_get_implemented_ppis(void)
> >
> >  /*
> >   * Probe for a vGICv5 compatible interrupt controller, returning 0
> > on success.
> > - * Currently only supports GICv3-based VMs on a GICv5 host, and
> > hence only
> > - * registers a VGIC_V3 device.
> >   */
> >  int vgic_v5_probe(const struct gic_kvm_info *info)
> >  {
> >   u64 ich_vtr_el2;
> >   int ret;
> >
> > - vgic_v5_get_implemented_ppis();
> > -
> > - if (!cpus_have_final_cap(ARM64_HAS_GICV5_LEGACY))
> > - return -ENODEV;
> > -
> >   kvm_vgic_global_state.type = VGIC_V5;
> > - kvm_vgic_global_state.has_gcie_v3_compat = true;
> > -
> > - /* We only support v3 compat mode - use vGICv3 limits */
> > - kvm_vgic_global_state.max_gic_vcpus = VGIC_V3_MAX_CPUS;
> >
> >   kvm_vgic_global_state.vcpu_base = 0;
> >   kvm_vgic_global_state.vctrl_base = NULL;
> > @@ -64,6 +53,34 @@ int vgic_v5_probe(const struct gic_kvm_info
> > *info)
> >   kvm_vgic_global_state.has_gicv4 = false;
> >   kvm_vgic_global_state.has_gicv4_1 = false;
> >
> > + /*
> > + * GICv5 is currently not supported in Protected mode.
> > Skip the
> > + * registration of GICv5 completely to make sure no guests
> > can create a
> > + * GICv5-based guest.
> > + */
> > + if (is_protected_kvm_enabled()) {
> > + kvm_info("GICv5-based guests are not supported
> > with pKVM\n");
> > + goto skip_v5;
> > + }
> > +
> > + kvm_vgic_global_state.max_gic_vcpus = VGIC_V5_MAX_CPUS;
> > +
> > + vgic_v5_get_implemented_ppis();
> > +
> > + ret = kvm_register_vgic_device(KVM_DEV_TYPE_ARM_VGIC_V5);
> > + if (ret) {
> > + kvm_err("Cannot register GICv5 KVM device.\n");
> > + goto skip_v5;
> > + }
> > +
> > + kvm_info("GCIE system register CPU interface\n");
> > +
> > +skip_v5:
> > + /* If we don't support the GICv3 compat mode we're done.
> > */
> > + if (!cpus_have_final_cap(ARM64_HAS_GICV5_LEGACY))
>
> If we jump to skip_v5 because we're in pKVM, but don't have
> ARM64_HAS_GICV5_LEGACY, this returns 0 but should probably be -
> ENODEV?
>
> Thanks,
> Joey

Yeah, I think you're probably right that we want to catch that case,
although by virtue of doing this it would block doing a userspace
irqchip on GICv5 hosts under pKVM or when GICv5 isn't registered for
whatever reason. I'm doubtful that this is an issue, however.

Something like this I think would solve it:

diff --git a/arch/arm64/kvm/vgic/vgic-v5.c b/arch/arm64/kvm/vgic/vgic-
v5.c
index ea2fbc6674903..0d69ed90bc4e0 100644
--- a/arch/arm64/kvm/vgic/vgic-v5.c
+++ b/arch/arm64/kvm/vgic/vgic-v5.c
@@ -42,6 +42,7 @@ static void vgic_v5_get_implemented_ppis(void)
*/
int vgic_v5_probe(const struct gic_kvm_info *info)
{
+ bool v5_registered = false;
u64 ich_vtr_el2;
int ret;

@@ -73,12 +74,16 @@ int vgic_v5_probe(const struct gic_kvm_info *info)
goto skip_v5;
}

+ v5_registered = true;
kvm_info("GCIE system register CPU interface\n");

skip_v5:
/* If we don't support the GICv3 compat mode we're done. */
- if (!cpus_have_final_cap(ARM64_HAS_GICV5_LEGACY))
+ if (!cpus_have_final_cap(ARM64_HAS_GICV5_LEGACY)) {
+ if (!v5_registered)
+ return -ENODEV;
return 0;
+ }

kvm_vgic_global_state.has_gcie_v3_compat = true;
ich_vtr_el2 = kvm_call_hyp_ret(__vgic_v3_get_gic_config);

Thanks,
Sascha

>
> > + return 0;
> > +
> > + kvm_vgic_global_state.has_gcie_v3_compat = true;
> >   ich_vtr_el2 =  kvm_call_hyp_ret(__vgic_v3_get_gic_config);
> >   kvm_vgic_global_state.ich_vtr_el2 = (u32)ich_vtr_el2;
> >
> > @@ -79,6 +96,10 @@ int vgic_v5_probe(const struct gic_kvm_info
> > *info)
> >   return ret;
> >   }
> >
> > + /* We potentially limit the max VCPUs further than we need
> > to here */
> > + kvm_vgic_global_state.max_gic_vcpus =
> > min(VGIC_V3_MAX_CPUS,
> > +
> > VGIC_V5_MAX_CPUS);
> > +
> >   static_branch_enable(&kvm_vgic_global_state.gicv3_cpuif);
> >   kvm_info("GCIE legacy system register CPU interface\n");
> >
> > --
> > 2.34.1