diff mbox

[v4,46/56] KVM: arm/arm64: vgic-new: Add userland access to VGIC dist registers

Message ID 20160518151223.GK6666@cbox
State New
Headers show

Commit Message

Christoffer Dall May 18, 2016, 3:12 p.m. UTC
On Wed, May 18, 2016 at 03:06:10PM +0100, Andre Przywara wrote:
> Hi,

> 

> On 18/05/16 14:57, Christoffer Dall wrote:

> > On Mon, May 16, 2016 at 10:53:34AM +0100, Andre Przywara wrote:

> >> Userland may want to save and restore the state of the in-kernel VGIC,

> >> so we provide the code which takes a userland request and translate

> >> that into calls to our MMIO framework.

> >>

> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

> >> ---

> >>  virt/kvm/arm/vgic/vgic-kvm-device.c | 50 ++++++++++++++++++++++++++++++++++++-

> >>  1 file changed, 49 insertions(+), 1 deletion(-)

> >>

> >> diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c

> >> index 78621283..c3ec453 100644

> >> --- a/virt/kvm/arm/vgic/vgic-kvm-device.c

> >> +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c

> >> @@ -238,7 +238,55 @@ static int vgic_attr_regs_access(struct kvm_device *dev,

> >>  				 struct kvm_device_attr *attr,

> >>  				 u32 *reg, bool is_write)

> >>  {

> >> -	return -ENXIO;

> >> +	gpa_t addr;

> >> +	int cpuid, ret, c;

> >> +	struct kvm_vcpu *vcpu, *tmp_vcpu;

> >> +

> >> +	cpuid = (attr->attr & KVM_DEV_ARM_VGIC_CPUID_MASK) >>

> >> +		 KVM_DEV_ARM_VGIC_CPUID_SHIFT;

> >> +	vcpu = kvm_get_vcpu(dev->kvm, cpuid);

> >> +	addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;

> >> +

> >> +	mutex_lock(&dev->kvm->lock);

> >> +

> >> +	ret = vgic_init(dev->kvm);

> >> +	if (ret)

> >> +		goto out;

> >> +

> >> +	if (cpuid >= atomic_read(&dev->kvm->online_vcpus)) {

> >> +		ret = -EINVAL;

> >> +		goto out;

> >> +	}

> >> +

> >> +	/*

> >> +	 * Ensure that no other VCPU is running by checking the vcpu->cpu

> >> +	 * field.  If no other VPCUs are running we can safely access the VGIC

> >> +	 * state, because even if another VPU is run after this point, that

> >> +	 * VCPU will not touch the vgic state, because it will block on

> >> +	 * getting the vgic->lock in kvm_vgic_sync_hwstate().

> >> +	 */

> > 

> > We still have a problem here.  Want me to write a patch?

> 

> Aargh, this somehow got lost in my pile of "comments to address", sorry!

> Short answer: yes, please.

> Last thing I did was following your suggestion from last time about

> refactoring the check from kvm_vgic_create(): I think this doesn't help,

> because it's only a check and we return -EBUSY or so instead of actually

> enforcing VCPUs to exit. So if you could try to use your fancy new

> make-the-guest-exit feature here?

> 

Am I missing something completely or why doesn't this work:



Thanks,
-Christoffer

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
diff mbox

Patch

diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
index 237d753..0130c4b 100644
--- a/virt/kvm/arm/vgic/vgic-kvm-device.c
+++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
@@ -241,6 +241,7 @@  static int vgic_attr_regs_access(struct kvm_device *dev,
 	gpa_t addr;
 	int cpuid, ret, c;
 	struct kvm_vcpu *vcpu, *tmp_vcpu;
+	int vcpu_lock_idx = -1;
 
 	cpuid = (attr->attr & KVM_DEV_ARM_VGIC_CPUID_MASK) >>
 		 KVM_DEV_ARM_VGIC_CPUID_SHIFT;
@@ -259,17 +260,16 @@  static int vgic_attr_regs_access(struct kvm_device *dev,
 	}
 
 	/*
-	 * Ensure that no other VCPU is running by checking the vcpu->cpu
-	 * field.  If no other VPCUs are running we can safely access the VGIC
-	 * state, because even if another VPU is run after this point, that
-	 * VCPU will not touch the vgic state, because it will block on
-	 * getting the vgic->lock in kvm_vgic_sync_hwstate().
+	 * Any time a vcpu is run, vcpu_load is called which tries to grab the
+	 * vcpu->mutex.  By grabbing the vcpu->mutex of all VCPUs we ensure
+	 * that no other VCPUs are run and fiddle with the vgic state while we
+	 * access it.
 	 */
+	ret = -EBUSY;
 	kvm_for_each_vcpu(c, tmp_vcpu, dev->kvm) {
-		if (unlikely(tmp_vcpu->cpu != -1)) {
-			ret = -EBUSY;
+		if (!mutex_trylock(&tmp_vcpu->mutex))
 			goto out;
-		}
+		vcpu_lock_idx = c;
 	}
 
 	switch (attr->group) {
@@ -285,6 +285,11 @@  static int vgic_attr_regs_access(struct kvm_device *dev,
 	}
 
 out:
+	for (; vcpu_lock_idx >= 0; vcpu_lock_idx--) {
+		tmp_vcpu = kvm_get_vcpu(dev->kvm, vcpu_lock_idx);
+		mutex_unlock(&tmp_vcpu->mutex);
+	}
+
 	mutex_unlock(&dev->kvm->lock);
 	return ret;
 }