Commit f26e6af7 authored by Oliver Upton's avatar Oliver Upton
Browse files

KVM: arm64: vgic-v3: Allow access to GICD_IIDR prior to initialization



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: default avatarEric Auger <eric.auger@redhat.com>
Reviewed-by: default avatarMarc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20250724062805.2658919-4-oliver.upton@linux.dev


Signed-off-by: default avatarOliver Upton <oliver.upton@linux.dev>
parent ef364c5b
Loading
Loading
Loading
Loading
+1 −8
Original line number Diff line number Diff line
@@ -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;
}
+19 −1
Original line number Diff line number Diff line
@@ -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;
	}