]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
KVM: arm64: vgic-v3: Allow userspace to write GICD_TYPER2.nASSGIcap
authorRaghavendra Rao Ananta <rananta@google.com>
Thu, 24 Jul 2025 06:28:03 +0000 (23:28 -0700)
committerOliver Upton <oliver.upton@linux.dev>
Sat, 26 Jul 2025 15:45:52 +0000 (08:45 -0700)
KVM unconditionally advertises GICD_TYPER2.nASSGIcap (which internally
implies vSGIs) on GICv4.1 systems. Allow userspace to change whether a
VM supports the feature. Only allow changes prior to VGIC initialization
as at that point vPEs need to be allocated for the VM.

For convenience, bundle support for vLPIs and vSGIs behind this feature,
allowing userspace to control vPE allocation for VMs in environments
that may be constrained on vPE IDs.

Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20250724062805.2658919-5-oliver.upton@linux.dev
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
arch/arm64/kvm/vgic/vgic-init.c
arch/arm64/kvm/vgic/vgic-kvm-device.c
arch/arm64/kvm/vgic/vgic-mmio-v3.c
arch/arm64/kvm/vgic/vgic.h
include/kvm/arm_vgic.h

index 31462ba093c9b95e9c8d316045017190643d8edb..6ec3535e142cfdbd20efb0199ebd545997c9bdbf 100644 (file)
@@ -166,6 +166,9 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
        else
                INIT_LIST_HEAD(&kvm->arch.vgic.rd_regions);
 
+       if (type == KVM_DEV_TYPE_ARM_VGIC_V3)
+               kvm->arch.vgic.nassgicap = system_supports_direct_sgis();
+
 out_unlock:
        mutex_unlock(&kvm->arch.config_lock);
        kvm_unlock_all_vcpus(kvm);
index 8e24d550d9d29c0606b9a9373add944dc846f4e3..3d1a776b716d7425ed509ec6a5594e3880c28f61 100644 (file)
@@ -515,6 +515,7 @@ static bool reg_allowed_pre_init(struct kvm_device_attr *attr)
 
        switch (attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK) {
        case GICD_IIDR:
+       case GICD_TYPER2:
                return true;
        default:
                return false;
index 8f0f460b6a615e674435617b7780e4d9e706d7a4..a3ef185209e99c5c7db1cc8cbd5ca6f354da2512 100644 (file)
@@ -53,11 +53,16 @@ bool vgic_supports_direct_msis(struct kvm *kvm)
        return kvm_vgic_global_state.has_gicv4 && vgic_has_its(kvm);
 }
 
-bool vgic_supports_direct_sgis(struct kvm *kvm)
+bool system_supports_direct_sgis(void)
 {
        return kvm_vgic_global_state.has_gicv4_1 && gic_cpuif_has_vsgi();
 }
 
+bool vgic_supports_direct_sgis(struct kvm *kvm)
+{
+       return kvm->arch.vgic.nassgicap;
+}
+
 /*
  * The Revision field in the IIDR have the following meanings:
  *
@@ -163,8 +168,18 @@ static int vgic_mmio_uaccess_write_v3_misc(struct kvm_vcpu *vcpu,
 
        switch (addr & 0x0c) {
        case GICD_TYPER2:
-               if (val != vgic_mmio_read_v3_misc(vcpu, addr, len))
+               reg = vgic_mmio_read_v3_misc(vcpu, addr, len);
+
+               if (reg == val)
+                       return 0;
+               if (vgic_initialized(vcpu->kvm))
+                       return -EBUSY;
+               if ((reg ^ val) & ~GICD_TYPER2_nASSGIcap)
                        return -EINVAL;
+               if (!system_supports_direct_sgis() && val)
+                       return -EINVAL;
+
+               dist->nassgicap = val & GICD_TYPER2_nASSGIcap;
                return 0;
        case GICD_IIDR:
                reg = vgic_mmio_read_v3_misc(vcpu, addr, len);
index ebf9ed6adeac1df3eee6ea1ee2a6c5cb8055f773..fb6d7c098ae6511a143fe20753dec4765a882b1a 100644 (file)
@@ -369,12 +369,21 @@ void vgic_its_invalidate_all_caches(struct kvm *kvm);
 int vgic_its_inv_lpi(struct kvm *kvm, struct vgic_irq *irq);
 int vgic_its_invall(struct kvm_vcpu *vcpu);
 
+bool system_supports_direct_sgis(void);
 bool vgic_supports_direct_msis(struct kvm *kvm);
 bool vgic_supports_direct_sgis(struct kvm *kvm);
 
 static inline bool vgic_supports_direct_irqs(struct kvm *kvm)
 {
-       return vgic_supports_direct_msis(kvm) || vgic_supports_direct_sgis(kvm);
+       /*
+        * Deliberately conflate vLPI and vSGI support on GICv4.1 hardware,
+        * indirectly allowing userspace to control whether or not vPEs are
+        * allocated for the VM.
+        */
+       if (system_supports_direct_sgis())
+               return vgic_supports_direct_sgis(kvm);
+
+       return vgic_supports_direct_msis(kvm);
 }
 
 int vgic_v4_init(struct kvm *kvm);
index 4a34f7f0a86488a0bda7cc95916e1a4e47b69a07..1b4886f3fb20490131f33b3ebb34e66866816d52 100644 (file)
@@ -264,6 +264,9 @@ struct vgic_dist {
        /* distributor enabled */
        bool                    enabled;
 
+       /* Supports SGIs without active state */
+       bool                    nassgicap;
+
        /* Wants SGIs without active state */
        bool                    nassgireq;