Add in a probe function for GICv5 which enables support for GICv3
guests on a GICv5 host, if FEAT_GCIE_LEGACY is support.
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>
---
arch/arm64/kvm/vgic/vgic-init.c | 3 ++
arch/arm64/kvm/vgic/vgic-v5.c | 50 +++++++++++++++++++++++++++++++++
arch/arm64/kvm/vgic/vgic.h | 2 ++
3 files changed, 55 insertions(+)
diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
index 5f6506e297c1..2ec3da04a607 100644
--- a/arch/arm64/kvm/vgic/vgic-init.c
+++ b/arch/arm64/kvm/vgic/vgic-init.c
@@ -724,6 +724,9 @@ int kvm_vgic_hyp_init(void)
kvm_info("GIC system register CPU interface enabled\n");
}
break;
+ case GIC_V5:
+ ret = vgic_v5_probe(gic_kvm_info);
+ break;
default:
ret = -ENODEV;
}
diff --git a/arch/arm64/kvm/vgic/vgic-v5.c b/arch/arm64/kvm/vgic/vgic-v5.c
index 57199449ca0f..5d0cfcbbefa7 100644
--- a/arch/arm64/kvm/vgic/vgic-v5.c
+++ b/arch/arm64/kvm/vgic/vgic-v5.c
@@ -1,9 +1,59 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <kvm/arm_vgic.h>
+#include <linux/irqchip/arm-vgic-info.h>
#include "vgic.h"
+/**
+ * vgic_v5_probe - probe for a VGICv5 compatible interrupt controller
+ * @info: pointer to the GIC description
+ *
+ * Returns 0 if the VGICv5 has been probed successfully, returns an error code
+ * otherwise.
+ */
+int vgic_v5_probe(const struct gic_kvm_info *info)
+{
+ u64 ich_vtr_el2;
+ int ret;
+
+ if (!info->has_gcie_v3_compat)
+ return -ENODEV;
+
+ kvm_vgic_global_state.type = VGIC_V5;
+ kvm_vgic_global_state.has_gcie_v3_compat = true;
+ static_branch_enable(&kvm_vgic_global_state.gicv5_cpuif);
+
+ /* 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;
+ kvm_vgic_global_state.can_emulate_gicv2 = false;
+ kvm_vgic_global_state.has_gicv4 = false;
+ kvm_vgic_global_state.has_gicv4_1 = false;
+
+ ich_vtr_el2 = kvm_call_hyp_ret(__vgic_v3_get_gic_config);
+ kvm_vgic_global_state.ich_vtr_el2 = (u32)ich_vtr_el2;
+
+ /*
+ * The ListRegs field is 5 bits, but there is an architectural
+ * maximum of 16 list registers. Just ignore bit 4...
+ */
+ kvm_vgic_global_state.nr_lr = (ich_vtr_el2 & 0xf) + 1;
+
+ ret = kvm_register_vgic_device(KVM_DEV_TYPE_ARM_VGIC_V3);
+ if (ret) {
+ kvm_err("Cannot register GICv3-legacy KVM device.\n");
+ return ret;
+ }
+
+ static_branch_enable(&kvm_vgic_global_state.gicv3_cpuif);
+ kvm_info("GCIE legacy system register CPU interface\n");
+
+ return 0;
+}
+
inline bool kvm_vgic_in_v3_compat_mode(void)
{
if (static_branch_unlikely(&kvm_vgic_global_state.gicv5_cpuif) &&
diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h
index 5c78eb915a22..a5292cad60ff 100644
--- a/arch/arm64/kvm/vgic/vgic.h
+++ b/arch/arm64/kvm/vgic/vgic.h
@@ -308,6 +308,8 @@ int vgic_init(struct kvm *kvm);
void vgic_debug_init(struct kvm *kvm);
void vgic_debug_destroy(struct kvm *kvm);
+int vgic_v5_probe(const struct gic_kvm_info *info);
+
static inline int vgic_v3_max_apr_idx(struct kvm_vcpu *vcpu)
{
struct vgic_cpu *cpu_if = &vcpu->arch.vgic_cpu;
--
2.34.1
On Fri, Jun 20, 2025 at 04:07:52PM +0000, Sascha Bischoff wrote: > +/** > + * vgic_v5_probe - probe for a VGICv5 compatible interrupt controller > + * @info: pointer to the GIC description > + * > + * Returns 0 if the VGICv5 has been probed successfully, returns an error code > + * otherwise. > + */ nit: avoid kerneldoc style This actually generates documentation as well as build warnings when we screw up the format. I'd only do this sort of thing for sufficiently public functions. Thanks, Oliver > +int vgic_v5_probe(const struct gic_kvm_info *info) > +{ > + u64 ich_vtr_el2; > + int ret; > + > + if (!info->has_gcie_v3_compat) > + return -ENODEV; > + > + kvm_vgic_global_state.type = VGIC_V5; > + kvm_vgic_global_state.has_gcie_v3_compat = true; > + static_branch_enable(&kvm_vgic_global_state.gicv5_cpuif); > + > + /* 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; > + kvm_vgic_global_state.can_emulate_gicv2 = false; > + kvm_vgic_global_state.has_gicv4 = false; > + kvm_vgic_global_state.has_gicv4_1 = false; > + > + ich_vtr_el2 = kvm_call_hyp_ret(__vgic_v3_get_gic_config); > + kvm_vgic_global_state.ich_vtr_el2 = (u32)ich_vtr_el2; > + > + /* > + * The ListRegs field is 5 bits, but there is an architectural > + * maximum of 16 list registers. Just ignore bit 4... > + */ > + kvm_vgic_global_state.nr_lr = (ich_vtr_el2 & 0xf) + 1; > + > + ret = kvm_register_vgic_device(KVM_DEV_TYPE_ARM_VGIC_V3); > + if (ret) { > + kvm_err("Cannot register GICv3-legacy KVM device.\n"); > + return ret; > + } > + > + static_branch_enable(&kvm_vgic_global_state.gicv3_cpuif); > + kvm_info("GCIE legacy system register CPU interface\n"); > + > + return 0; > +} > + > inline bool kvm_vgic_in_v3_compat_mode(void) > { > if (static_branch_unlikely(&kvm_vgic_global_state.gicv5_cpuif) && > diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h > index 5c78eb915a22..a5292cad60ff 100644 > --- a/arch/arm64/kvm/vgic/vgic.h > +++ b/arch/arm64/kvm/vgic/vgic.h > @@ -308,6 +308,8 @@ int vgic_init(struct kvm *kvm); > void vgic_debug_init(struct kvm *kvm); > void vgic_debug_destroy(struct kvm *kvm); > > +int vgic_v5_probe(const struct gic_kvm_info *info); > + > static inline int vgic_v3_max_apr_idx(struct kvm_vcpu *vcpu) > { > struct vgic_cpu *cpu_if = &vcpu->arch.vgic_cpu; > -- > 2.34.1
On Fri, 2025-06-20 at 13:25 -0700, Oliver Upton wrote: > On Fri, Jun 20, 2025 at 04:07:52PM +0000, Sascha Bischoff wrote: > > +/** > > + * vgic_v5_probe - probe for a VGICv5 compatible interrupt > > controller > > + * @info: pointer to the GIC description > > + * > > + * Returns 0 if the VGICv5 has been probed successfully, returns > > an error code > > + * otherwise. > > + */ > > nit: avoid kerneldoc style > > This actually generates documentation as well as build warnings when > we > screw up the format. I'd only do this sort of thing for sufficiently > public functions. > > Thanks, > Oliver Done. Have made this into a non-kernel-doc comment. FWIW, this was mimicking what is done for vgic_v3_probe. Thanks, Sascha >
© 2016 - 2025 Red Hat, Inc.