KVM: arm-vgic: Support KVM_CREATE_DEVICE for VGIC
authorChristoffer Dall <christoffer.dall@linaro.org>
Fri, 25 Oct 2013 16:29:18 +0000 (17:29 +0100)
committerChristoffer Dall <christoffer.dall@linaro.org>
Thu, 2 Oct 2014 15:18:24 +0000 (17:18 +0200)
Support creating the ARM VGIC device through the KVM_CREATE_DEVICE
ioctl, which can then later be leveraged to use the
KVM_{GET/SET}_DEVICE_ATTR, which is useful both for setting addresses in
a more generic API than the ARM-specific one and is useful for
save/restore of VGIC state.

Adds KVM_CAP_DEVICE_CTRL to ARM capabilities.

Note that we change the check for creating a VGIC from bailing out if
any VCPUs were created, to bailing out if any VCPUs were ever run.  This
is an important distinction that shouldn't break anything, but allows
creating the VGIC after the VCPUs have been created.

Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
(cherry picked from commit 7330672befe6269e575f79b924a7068b26c144b4)
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Documentation/virtual/kvm/devices/arm-vgic.txt [new file with mode: 0644]
arch/arm/kvm/arm.c
include/linux/kvm_host.h
include/uapi/linux/kvm.h
virt/kvm/arm/vgic.c
virt/kvm/kvm_main.c

diff --git a/Documentation/virtual/kvm/devices/arm-vgic.txt b/Documentation/virtual/kvm/devices/arm-vgic.txt
new file mode 100644 (file)
index 0000000..38f27f7
--- /dev/null
@@ -0,0 +1,10 @@
+ARM Virtual Generic Interrupt Controller (VGIC)
+===============================================
+
+Device types supported:
+  KVM_DEV_TYPE_ARM_VGIC_V2     ARM Generic Interrupt Controller v2.0
+
+Only one VGIC instance may be instantiated through either this API or the
+legacy KVM_CREATE_IRQCHIP api.  The created VGIC will act as the VM interrupt
+controller, requiring emulated user-space devices to inject interrupts to the
+VGIC instead of directly to CPUs.
index ea8da1f4fe495d12a97f8803433a178eb65cb0e8..fcb68bb96176d43ea00f613a03be1076c3d828ee 100644 (file)
@@ -191,6 +191,7 @@ int kvm_dev_ioctl_check_extension(long ext)
        case KVM_CAP_IRQCHIP:
                r = vgic_present;
                break;
+       case KVM_CAP_DEVICE_CTRL:
        case KVM_CAP_USER_MEMORY:
        case KVM_CAP_SYNC_MMU:
        case KVM_CAP_DESTROY_MEMORY_REGION_WORKS:
index 9c0f8545df73ec8f78d2c4054d5ed5b87242316e..1dfc17255ee0f8ca2b6b7a6b4f4286822b922a95 100644 (file)
@@ -1045,6 +1045,7 @@ struct kvm_device *kvm_device_from_filp(struct file *filp);
 extern struct kvm_device_ops kvm_mpic_ops;
 extern struct kvm_device_ops kvm_xics_ops;
 extern struct kvm_device_ops kvm_vfio_ops;
+extern struct kvm_device_ops kvm_arm_vgic_v2_ops;
 
 #ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT
 
index d5b8501cebfde6e5625321fbe22c21641be9cbad..56347ab54cf7230a173f5258ec7ea63b79a945bd 100644 (file)
@@ -848,6 +848,7 @@ struct kvm_device_attr {
 #define  KVM_DEV_VFIO_GROUP                    1
 #define   KVM_DEV_VFIO_GROUP_ADD                       1
 #define   KVM_DEV_VFIO_GROUP_DEL                       2
+#define KVM_DEV_TYPE_ARM_VGIC_V2       5
 
 /*
  * ioctls for VM fds
index 5e9df47778fb3caee11eac298b54f8dad76eecf1..b15d6c17a0905609db65d419f4c9877099a0dae3 100644 (file)
@@ -1433,20 +1433,45 @@ out:
 
 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);
 
-       if (atomic_read(&kvm->online_vcpus) || kvm->arch.vgic.vctrl_base) {
+       if (kvm->arch.vgic.vctrl_base) {
                ret = -EEXIST;
                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);
        kvm->arch.vgic.vctrl_base = vgic_vctrl_base;
        kvm->arch.vgic.vgic_dist_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:
        mutex_unlock(&kvm->lock);
        return ret;
@@ -1510,3 +1535,37 @@ int kvm_vgic_set_addr(struct kvm *kvm, unsigned long type, u64 addr)
        mutex_unlock(&kvm->lock);
        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,
+};
index cb9a865c8e01135e3fc17086cec0cf2bf7f5963e..e9a43b6455bea2e231c95067a801aee27276bab3 100644 (file)
@@ -2271,6 +2271,11 @@ static int kvm_ioctl_create_device(struct kvm *kvm,
        case KVM_DEV_TYPE_VFIO:
                ops = &kvm_vfio_ops;
                break;
+#endif
+#ifdef CONFIG_KVM_ARM_VGIC
+       case KVM_DEV_TYPE_ARM_VGIC_V2:
+               ops = &kvm_arm_vgic_v2_ops;
+               break;
 #endif
        default:
                return -ENODEV;