Skip to content

Commit

Permalink
KVM: arm/arm64: vgic-new: Add userland access to VGIC dist registers
Browse files Browse the repository at this point in the history
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.

From Christoffer:
When accessing the VGIC state from userspace we really don't want a VCPU
to be messing with the state at the same time, and the API specifies
that we should return -EBUSY if any VCPUs are running.
Check and prevent VCPUs from running by grabbing their mutexes, one by
one, and error out if we fail.
(Note: This could potentially be simplified to just do a simple check
and see if any VCPUs are running, and return -EBUSY then, without
enforcing the locking throughout the duration of the uaccess, if we
think that taking/releasing all these mutexes for every single GIC
register access is too heavyweight.)

Signed-off-by: Andre Przywara <[email protected]>
Signed-off-by: Christoffer Dall <[email protected]>
  • Loading branch information
Andre-ARM authored and chazy committed May 20, 2016
1 parent c3199f2 commit 7d450e2
Showing 1 changed file with 54 additions and 1 deletion.
55 changes: 54 additions & 1 deletion virt/kvm/arm/vgic/vgic-kvm-device.c
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,60 @@ 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;
int vcpu_lock_idx = -1;

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;
}

/*
* 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 (!mutex_trylock(&tmp_vcpu->mutex))
goto out;
vcpu_lock_idx = c;
}

switch (attr->group) {
case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
ret = -EINVAL;
break;
case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
ret = vgic_v2_dist_uaccess(vcpu, is_write, addr, reg);
break;
default:
ret = -EINVAL;
break;
}

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;
}

/* V2 ops */
Expand Down

0 comments on commit 7d450e2

Please sign in to comment.