]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
KVM: arm64: vgic-v3: Allow access to GICD_IIDR prior to initialization
authorOliver Upton <oliver.upton@linux.dev>
Thu, 24 Jul 2025 06:28:02 +0000 (23:28 -0700)
committerOliver Upton <oliver.upton@linux.dev>
Sat, 26 Jul 2025 15:37:45 +0000 (08:37 -0700)
KVM allows userspace to write GICD_IIDR for backwards-compatibility with
older kernels, where new implementation revisions have new features.
Unfortunately this is allowed to happen at runtime, and ripping features
out from underneath a running guest is a terrible idea.

While we can't do anything about the ABI, prepare for more ID-like
registers by allowing access to GICD_IIDR prior to VGIC initialization.
Hoist initializaiton of the default value to kvm_vgic_create() and
discard the incorrect comment that assumed userspace could access the
register before initialization (until now).

Subsequent changes will allow the VMM to further provision the GIC
feature set, e.g. the presence of nASSGIcap.

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20250724062805.2658919-4-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

index 0d8bc2ac627a2b642414159c007a79de7cc640ba..31462ba093c9b95e9c8d316045017190643d8edb 100644 (file)
@@ -157,6 +157,7 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
 
        kvm->arch.vgic.in_kernel = true;
        kvm->arch.vgic.vgic_model = type;
+       kvm->arch.vgic.implementation_rev = KVM_VGIC_IMP_REV_LATEST;
 
        kvm->arch.vgic.vgic_dist_base = VGIC_ADDR_UNDEF;
 
@@ -408,15 +409,7 @@ int vgic_init(struct kvm *kvm)
                goto out;
 
        vgic_debug_init(kvm);
-
-       /*
-        * If userspace didn't set the GIC implementation revision,
-        * default to the latest and greatest. You know want it.
-        */
-       if (!dist->implementation_rev)
-               dist->implementation_rev = KVM_VGIC_IMP_REV_LATEST;
        dist->initialized = true;
-
 out:
        return ret;
 }
index 00c011cc86278a8aec298320166459d7d5648165..8e24d550d9d29c0606b9a9373add944dc846f4e3 100644 (file)
@@ -5,6 +5,7 @@
  * Copyright (C) 2015 ARM Ltd.
  * Author: Marc Zyngier <marc.zyngier@arm.com>
  */
+#include <linux/irqchip/arm-gic-v3.h>
 #include <linux/kvm_host.h>
 #include <kvm/arm_vgic.h>
 #include <linux/uaccess.h>
@@ -503,6 +504,23 @@ int vgic_v3_parse_attr(struct kvm_device *dev, struct kvm_device_attr *attr,
        return 0;
 }
 
+/*
+ * Allow access to certain ID-like registers prior to VGIC initialization,
+ * thereby allowing the VMM to provision the features / sizing of the VGIC.
+ */
+static bool reg_allowed_pre_init(struct kvm_device_attr *attr)
+{
+       if (attr->group != KVM_DEV_ARM_VGIC_GRP_DIST_REGS)
+               return false;
+
+       switch (attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK) {
+       case GICD_IIDR:
+               return true;
+       default:
+               return false;
+       }
+}
+
 /*
  * vgic_v3_attr_regs_access - allows user space to access VGIC v3 state
  *
@@ -552,7 +570,7 @@ static int vgic_v3_attr_regs_access(struct kvm_device *dev,
 
        mutex_lock(&dev->kvm->arch.config_lock);
 
-       if (!vgic_initialized(dev->kvm)) {
+       if (!(vgic_initialized(dev->kvm) || reg_allowed_pre_init(attr))) {
                ret = -EBUSY;
                goto out;
        }