]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
KVM: arm64: gic-v5: Create and initialise vgic_v5
authorSascha Bischoff <Sascha.Bischoff@arm.com>
Thu, 19 Mar 2026 15:56:59 +0000 (15:56 +0000)
committerMarc Zyngier <maz@kernel.org>
Thu, 19 Mar 2026 18:21:28 +0000 (18:21 +0000)
Update kvm_vgic_create to create a vgic_v5 device. When creating a
vgic, FEAT_GCIE in the ID_AA64PFR2 is only exposed to vgic_v5-based
guests, and is hidden otherwise. GIC in ~ID_AA64PFR0_EL1 is never
exposed for a vgic_v5 guest.

When initialising a vgic_v5, skip kvm_vgic_dist_init as GICv5 doesn't
support one. The current vgic_v5 implementation only supports PPIs, so
no SPIs are initialised either.

The current vgic_v5 support doesn't extend to nested guests. Therefore,
the init of vgic_v5 for a nested guest is failed in vgic_v5_init.

As the current vgic_v5 doesn't require any resources to be mapped,
vgic_v5_map_resources is simply used to check that the vgic has indeed
been initialised. Again, this will change as more GICv5 support is
merged in.

Signed-off-by: Sascha Bischoff <sascha.bischoff@arm.com>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Link: https://patch.msgid.link/20260319154937.3619520-29-sascha.bischoff@arm.com
Signed-off-by: Marc Zyngier <maz@kernel.org>
arch/arm64/kvm/vgic/vgic-init.c
arch/arm64/kvm/vgic/vgic-v5.c
arch/arm64/kvm/vgic/vgic.h
include/kvm/arm_vgic.h

index e0366e8c144d543dfdee06a0631a4ec36f618d31..75185651ff64cee582a25076b18fbc78f0f69415 100644 (file)
@@ -66,7 +66,7 @@ static int vgic_allocate_private_irqs_locked(struct kvm_vcpu *vcpu, u32 type);
  * or through the generic KVM_CREATE_DEVICE API ioctl.
  * irqchip_in_kernel() tells you if this function succeeded or not.
  * @kvm: kvm struct pointer
- * @type: KVM_DEV_TYPE_ARM_VGIC_V[23]
+ * @type: KVM_DEV_TYPE_ARM_VGIC_V[235]
  */
 int kvm_vgic_create(struct kvm *kvm, u32 type)
 {
@@ -131,8 +131,11 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
 
        if (type == KVM_DEV_TYPE_ARM_VGIC_V2)
                kvm->max_vcpus = VGIC_V2_MAX_CPUS;
-       else
+       else if (type == KVM_DEV_TYPE_ARM_VGIC_V3)
                kvm->max_vcpus = VGIC_V3_MAX_CPUS;
+       else if (type == KVM_DEV_TYPE_ARM_VGIC_V5)
+               kvm->max_vcpus = min(VGIC_V5_MAX_CPUS,
+                                    kvm_vgic_global_state.max_gic_vcpus);
 
        if (atomic_read(&kvm->online_vcpus) > kvm->max_vcpus) {
                ret = -E2BIG;
@@ -426,22 +429,28 @@ int vgic_init(struct kvm *kvm)
        if (kvm->created_vcpus != atomic_read(&kvm->online_vcpus))
                return -EBUSY;
 
-       /* freeze the number of spis */
-       if (!dist->nr_spis)
-               dist->nr_spis = VGIC_NR_IRQS_LEGACY - VGIC_NR_PRIVATE_IRQS;
+       if (!vgic_is_v5(kvm)) {
+               /* freeze the number of spis */
+               if (!dist->nr_spis)
+                       dist->nr_spis = VGIC_NR_IRQS_LEGACY - VGIC_NR_PRIVATE_IRQS;
 
-       ret = kvm_vgic_dist_init(kvm, dist->nr_spis);
-       if (ret)
-               goto out;
+               ret = kvm_vgic_dist_init(kvm, dist->nr_spis);
+               if (ret)
+                       return ret;
 
-       /*
-        * Ensure vPEs are allocated if direct IRQ injection (e.g. vSGIs,
-        * vLPIs) is supported.
-        */
-       if (vgic_supports_direct_irqs(kvm)) {
-               ret = vgic_v4_init(kvm);
+               /*
+                * Ensure vPEs are allocated if direct IRQ injection (e.g. vSGIs,
+                * vLPIs) is supported.
+                */
+               if (vgic_supports_direct_irqs(kvm)) {
+                       ret = vgic_v4_init(kvm);
+                       if (ret)
+                               return ret;
+               }
+       } else {
+               ret = vgic_v5_init(kvm);
                if (ret)
-                       goto out;
+                       return ret;
        }
 
        kvm_for_each_vcpu(idx, vcpu, kvm)
@@ -449,12 +458,12 @@ int vgic_init(struct kvm *kvm)
 
        ret = kvm_vgic_setup_default_irq_routing(kvm);
        if (ret)
-               goto out;
+               return ret;
 
        vgic_debug_init(kvm);
        dist->initialized = true;
-out:
-       return ret;
+
+       return 0;
 }
 
 static void kvm_vgic_dist_destroy(struct kvm *kvm)
@@ -598,6 +607,7 @@ int vgic_lazy_init(struct kvm *kvm)
 int kvm_vgic_map_resources(struct kvm *kvm)
 {
        struct vgic_dist *dist = &kvm->arch.vgic;
+       bool needs_dist = true;
        enum vgic_type type;
        gpa_t dist_base;
        int ret = 0;
@@ -616,12 +626,16 @@ int kvm_vgic_map_resources(struct kvm *kvm)
        if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V2) {
                ret = vgic_v2_map_resources(kvm);
                type = VGIC_V2;
-       } else {
+       } else if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3) {
                ret = vgic_v3_map_resources(kvm);
                type = VGIC_V3;
+       } else {
+               ret = vgic_v5_map_resources(kvm);
+               type = VGIC_V5;
+               needs_dist = false;
        }
 
-       if (ret)
+       if (ret || !needs_dist)
                goto out;
 
        dist_base = dist->vgic_dist_base;
index b84324f0a31147c2cb886eeb03f496a3763ea0a8..14e1fad913f06be7e7cb1de5e4d3948ecd57d0f4 100644 (file)
@@ -87,6 +87,32 @@ int vgic_v5_probe(const struct gic_kvm_info *info)
        return 0;
 }
 
+int vgic_v5_init(struct kvm *kvm)
+{
+       struct kvm_vcpu *vcpu;
+       unsigned long idx;
+
+       if (vgic_initialized(kvm))
+               return 0;
+
+       kvm_for_each_vcpu(idx, vcpu, kvm) {
+               if (vcpu_has_nv(vcpu)) {
+                       kvm_err("Nested GICv5 VMs are currently unsupported\n");
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
+int vgic_v5_map_resources(struct kvm *kvm)
+{
+       if (!vgic_initialized(kvm))
+               return -EBUSY;
+
+       return 0;
+}
+
 int vgic_v5_finalize_ppi_state(struct kvm *kvm)
 {
        struct kvm_vcpu *vcpu0;
index 8f15f7472458e489eced92d9ac491a7f9ec90a8b..0f1986fcd7d0ad62f593cfa8a3ed439b85aca979 100644 (file)
@@ -364,6 +364,8 @@ void vgic_debug_init(struct kvm *kvm);
 void vgic_debug_destroy(struct kvm *kvm);
 
 int vgic_v5_probe(const struct gic_kvm_info *info);
+int vgic_v5_init(struct kvm *kvm);
+int vgic_v5_map_resources(struct kvm *kvm);
 void vgic_v5_set_ppi_ops(struct kvm_vcpu *vcpu, u32 vintid);
 bool vgic_v5_has_pending_ppi(struct kvm_vcpu *vcpu);
 void vgic_v5_flush_ppi_state(struct kvm_vcpu *vcpu);
index a28cf765f3eb5a454d88fe5ae629747d26613888..a5ddccf7ef3b04716d922d1776ac8c0189ecc434 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/irqchip/arm-gic-v4.h>
 #include <linux/irqchip/arm-gic-v5.h>
 
+#define VGIC_V5_MAX_CPUS       512
 #define VGIC_V3_MAX_CPUS       512
 #define VGIC_V2_MAX_CPUS       8
 #define VGIC_NR_IRQS_LEGACY     256