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

Sascha Bischoff Sascha.Bischoff at arm.com
Thu Mar 19 01:36:20 PDT 2026


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 at arm.com>
> > Signed-off-by: Timothy Hayes <timothy.hayes at arm.com>
> > Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
> > Reviewed-by: Jonathan Cameron <jonathan.cameron at huawei.com>
> > Reviewed-by: Joey Gouly <joey.gouly at 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



More information about the linux-arm-kernel mailing list