|
@@ -1433,20 +1433,45 @@ out:
|
|
|
|
|
|
int kvm_vgic_create(struct kvm *kvm)
|
|
int kvm_vgic_create(struct kvm *kvm)
|
|
{
|
|
{
|
|
- int ret = 0;
|
|
|
|
|
|
+ int i, vcpu_lock_idx = -1, ret = 0;
|
|
|
|
+ struct kvm_vcpu *vcpu;
|
|
|
|
|
|
mutex_lock(&kvm->lock);
|
|
mutex_lock(&kvm->lock);
|
|
|
|
|
|
- if (atomic_read(&kvm->online_vcpus) || kvm->arch.vgic.vctrl_base) {
|
|
|
|
|
|
+ if (kvm->arch.vgic.vctrl_base) {
|
|
ret = -EEXIST;
|
|
ret = -EEXIST;
|
|
goto out;
|
|
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 while we create the vgic.
|
|
|
|
+ */
|
|
|
|
+ kvm_for_each_vcpu(i, vcpu, kvm) {
|
|
|
|
+ if (!mutex_trylock(&vcpu->mutex))
|
|
|
|
+ goto out_unlock;
|
|
|
|
+ vcpu_lock_idx = i;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ kvm_for_each_vcpu(i, vcpu, kvm) {
|
|
|
|
+ if (vcpu->arch.has_run_once) {
|
|
|
|
+ ret = -EBUSY;
|
|
|
|
+ goto out_unlock;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
spin_lock_init(&kvm->arch.vgic.lock);
|
|
spin_lock_init(&kvm->arch.vgic.lock);
|
|
kvm->arch.vgic.vctrl_base = vgic_vctrl_base;
|
|
kvm->arch.vgic.vctrl_base = vgic_vctrl_base;
|
|
kvm->arch.vgic.vgic_dist_base = VGIC_ADDR_UNDEF;
|
|
kvm->arch.vgic.vgic_dist_base = VGIC_ADDR_UNDEF;
|
|
kvm->arch.vgic.vgic_cpu_base = VGIC_ADDR_UNDEF;
|
|
kvm->arch.vgic.vgic_cpu_base = VGIC_ADDR_UNDEF;
|
|
|
|
|
|
|
|
+out_unlock:
|
|
|
|
+ for (; vcpu_lock_idx >= 0; vcpu_lock_idx--) {
|
|
|
|
+ vcpu = kvm_get_vcpu(kvm, vcpu_lock_idx);
|
|
|
|
+ mutex_unlock(&vcpu->mutex);
|
|
|
|
+ }
|
|
|
|
+
|
|
out:
|
|
out:
|
|
mutex_unlock(&kvm->lock);
|
|
mutex_unlock(&kvm->lock);
|
|
return ret;
|
|
return ret;
|
|
@@ -1510,3 +1535,37 @@ int kvm_vgic_set_addr(struct kvm *kvm, unsigned long type, u64 addr)
|
|
mutex_unlock(&kvm->lock);
|
|
mutex_unlock(&kvm->lock);
|
|
return r;
|
|
return r;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+static int vgic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
|
|
|
|
+{
|
|
|
|
+ return -ENXIO;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int vgic_get_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
|
|
|
|
+{
|
|
|
|
+ return -ENXIO;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int vgic_has_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
|
|
|
|
+{
|
|
|
|
+ return -ENXIO;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void vgic_destroy(struct kvm_device *dev)
|
|
|
|
+{
|
|
|
|
+ kfree(dev);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int vgic_create(struct kvm_device *dev, u32 type)
|
|
|
|
+{
|
|
|
|
+ return kvm_vgic_create(dev->kvm);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+struct kvm_device_ops kvm_arm_vgic_v2_ops = {
|
|
|
|
+ .name = "kvm-arm-vgic",
|
|
|
|
+ .create = vgic_create,
|
|
|
|
+ .destroy = vgic_destroy,
|
|
|
|
+ .set_attr = vgic_set_attr,
|
|
|
|
+ .get_attr = vgic_get_attr,
|
|
|
|
+ .has_attr = vgic_has_attr,
|
|
|
|
+};
|