]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - virt/kvm/kvm_main.c
Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus
[karo-tx-linux.git] / virt / kvm / kvm_main.c
index 1fc942048521085a960074affc2663d93a70e93e..ae88b719bd2e477bbdb729f0b55555ebc869fcef 100644 (file)
@@ -217,9 +217,9 @@ void kvm_make_mclock_inprogress_request(struct kvm *kvm)
        make_all_cpus_request(kvm, KVM_REQ_MCLOCK_INPROGRESS);
 }
 
-void kvm_make_update_eoibitmap_request(struct kvm *kvm)
+void kvm_make_scan_ioapic_request(struct kvm *kvm)
 {
-       make_all_cpus_request(kvm, KVM_REQ_EOIBITMAP);
+       make_all_cpus_request(kvm, KVM_REQ_SCAN_IOAPIC);
 }
 
 int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id)
@@ -244,6 +244,7 @@ int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id)
 
        kvm_vcpu_set_in_spin_loop(vcpu, false);
        kvm_vcpu_set_dy_eligible(vcpu, false);
+       vcpu->preempted = false;
 
        r = kvm_arch_vcpu_init(vcpu);
        if (r < 0)
@@ -503,6 +504,7 @@ static struct kvm *kvm_create_vm(unsigned long type)
        mutex_init(&kvm->irq_lock);
        mutex_init(&kvm->slots_lock);
        atomic_set(&kvm->users_count, 1);
+       INIT_LIST_HEAD(&kvm->devices);
 
        r = kvm_init_mmu_notifier(kvm);
        if (r)
@@ -580,6 +582,19 @@ void kvm_free_physmem(struct kvm *kvm)
        kfree(kvm->memslots);
 }
 
+static void kvm_destroy_devices(struct kvm *kvm)
+{
+       struct list_head *node, *tmp;
+
+       list_for_each_safe(node, tmp, &kvm->devices) {
+               struct kvm_device *dev =
+                       list_entry(node, struct kvm_device, vm_node);
+
+               list_del(node);
+               dev->ops->destroy(dev);
+       }
+}
+
 static void kvm_destroy_vm(struct kvm *kvm)
 {
        int i;
@@ -599,6 +614,7 @@ static void kvm_destroy_vm(struct kvm *kvm)
        kvm_arch_flush_shadow_all(kvm);
 #endif
        kvm_arch_destroy_vm(kvm);
+       kvm_destroy_devices(kvm);
        kvm_free_physmem(kvm);
        cleanup_srcu_struct(&kvm->srcu);
        kvm_arch_free_vm(kvm);
@@ -718,24 +734,6 @@ static struct kvm_memslots *install_new_memslots(struct kvm *kvm,
        return old_memslots; 
 }
 
-/*
- * KVM_SET_USER_MEMORY_REGION ioctl allows the following operations:
- * - create a new memory slot
- * - delete an existing memory slot
- * - modify an existing memory slot
- *   -- move it in the guest physical memory space
- *   -- just change its flags
- *
- * Since flags can be changed by some of these operations, the following
- * differentiation is the best we can do for __kvm_set_memory_region():
- */
-enum kvm_mr_change {
-       KVM_MR_CREATE,
-       KVM_MR_DELETE,
-       KVM_MR_MOVE,
-       KVM_MR_FLAGS_ONLY,
-};
-
 /*
  * Allocate some memory and give it an address in the guest physical address
  * space.
@@ -745,8 +743,7 @@ enum kvm_mr_change {
  * Must be called holding mmap_sem for write.
  */
 int __kvm_set_memory_region(struct kvm *kvm,
-                           struct kvm_userspace_memory_region *mem,
-                           bool user_alloc)
+                           struct kvm_userspace_memory_region *mem)
 {
        int r;
        gfn_t base_gfn;
@@ -767,7 +764,7 @@ int __kvm_set_memory_region(struct kvm *kvm,
        if (mem->guest_phys_addr & (PAGE_SIZE - 1))
                goto out;
        /* We can read the guest memory with __xxx_user() later on. */
-       if (user_alloc &&
+       if ((mem->slot < KVM_USER_MEM_SLOTS) &&
            ((mem->userspace_addr & (PAGE_SIZE - 1)) ||
             !access_ok(VERIFY_WRITE,
                        (void __user *)(unsigned long)mem->userspace_addr,
@@ -875,7 +872,7 @@ int __kvm_set_memory_region(struct kvm *kvm,
                slots = old_memslots;
        }
 
-       r = kvm_arch_prepare_memory_region(kvm, &new, old, mem, user_alloc);
+       r = kvm_arch_prepare_memory_region(kvm, &new, mem, change);
        if (r)
                goto out_slots;
 
@@ -915,7 +912,7 @@ int __kvm_set_memory_region(struct kvm *kvm,
 
        old_memslots = install_new_memslots(kvm, slots, &new);
 
-       kvm_arch_commit_memory_region(kvm, mem, old, user_alloc);
+       kvm_arch_commit_memory_region(kvm, mem, &old, change);
 
        kvm_free_physmem_slot(&old, &new);
        kfree(old_memslots);
@@ -932,26 +929,23 @@ out:
 EXPORT_SYMBOL_GPL(__kvm_set_memory_region);
 
 int kvm_set_memory_region(struct kvm *kvm,
-                         struct kvm_userspace_memory_region *mem,
-                         bool user_alloc)
+                         struct kvm_userspace_memory_region *mem)
 {
        int r;
 
        mutex_lock(&kvm->slots_lock);
-       r = __kvm_set_memory_region(kvm, mem, user_alloc);
+       r = __kvm_set_memory_region(kvm, mem);
        mutex_unlock(&kvm->slots_lock);
        return r;
 }
 EXPORT_SYMBOL_GPL(kvm_set_memory_region);
 
 int kvm_vm_ioctl_set_memory_region(struct kvm *kvm,
-                                  struct
-                                  kvm_userspace_memory_region *mem,
-                                  bool user_alloc)
+                                  struct kvm_userspace_memory_region *mem)
 {
        if (mem->slot >= KVM_USER_MEM_SLOTS)
                return -EINVAL;
-       return kvm_set_memory_region(kvm, mem, user_alloc);
+       return kvm_set_memory_region(kvm, mem);
 }
 
 int kvm_get_dirty_log(struct kvm *kvm,
@@ -1099,7 +1093,7 @@ static int kvm_read_hva_atomic(void *data, void __user *hva, int len)
        return __copy_from_user_inatomic(data, hva, len);
 }
 
-int get_user_page_nowait(struct task_struct *tsk, struct mm_struct *mm,
+static int get_user_page_nowait(struct task_struct *tsk, struct mm_struct *mm,
        unsigned long start, int write, struct page **page)
 {
        int flags = FOLL_TOUCH | FOLL_NOWAIT | FOLL_HWPOISON | FOLL_GET;
@@ -1719,6 +1713,7 @@ void kvm_vcpu_kick(struct kvm_vcpu *vcpu)
                        smp_send_reschedule(cpu);
        put_cpu();
 }
+EXPORT_SYMBOL_GPL(kvm_vcpu_kick);
 #endif /* !CONFIG_S390 */
 
 void kvm_resched(struct kvm_vcpu *vcpu)
@@ -1816,6 +1811,8 @@ void kvm_vcpu_on_spin(struct kvm_vcpu *me)
                                continue;
                        } else if (pass && i > last_boosted_vcpu)
                                break;
+                       if (!ACCESS_ONCE(vcpu->preempted))
+                               continue;
                        if (vcpu == me)
                                continue;
                        if (waitqueue_active(&vcpu->wq))
@@ -2204,6 +2201,119 @@ out:
 }
 #endif
 
+static int kvm_device_ioctl_attr(struct kvm_device *dev,
+                                int (*accessor)(struct kvm_device *dev,
+                                                struct kvm_device_attr *attr),
+                                unsigned long arg)
+{
+       struct kvm_device_attr attr;
+
+       if (!accessor)
+               return -EPERM;
+
+       if (copy_from_user(&attr, (void __user *)arg, sizeof(attr)))
+               return -EFAULT;
+
+       return accessor(dev, &attr);
+}
+
+static long kvm_device_ioctl(struct file *filp, unsigned int ioctl,
+                            unsigned long arg)
+{
+       struct kvm_device *dev = filp->private_data;
+
+       switch (ioctl) {
+       case KVM_SET_DEVICE_ATTR:
+               return kvm_device_ioctl_attr(dev, dev->ops->set_attr, arg);
+       case KVM_GET_DEVICE_ATTR:
+               return kvm_device_ioctl_attr(dev, dev->ops->get_attr, arg);
+       case KVM_HAS_DEVICE_ATTR:
+               return kvm_device_ioctl_attr(dev, dev->ops->has_attr, arg);
+       default:
+               if (dev->ops->ioctl)
+                       return dev->ops->ioctl(dev, ioctl, arg);
+
+               return -ENOTTY;
+       }
+}
+
+static int kvm_device_release(struct inode *inode, struct file *filp)
+{
+       struct kvm_device *dev = filp->private_data;
+       struct kvm *kvm = dev->kvm;
+
+       kvm_put_kvm(kvm);
+       return 0;
+}
+
+static const struct file_operations kvm_device_fops = {
+       .unlocked_ioctl = kvm_device_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl = kvm_device_ioctl,
+#endif
+       .release = kvm_device_release,
+};
+
+struct kvm_device *kvm_device_from_filp(struct file *filp)
+{
+       if (filp->f_op != &kvm_device_fops)
+               return NULL;
+
+       return filp->private_data;
+}
+
+static int kvm_ioctl_create_device(struct kvm *kvm,
+                                  struct kvm_create_device *cd)
+{
+       struct kvm_device_ops *ops = NULL;
+       struct kvm_device *dev;
+       bool test = cd->flags & KVM_CREATE_DEVICE_TEST;
+       int ret;
+
+       switch (cd->type) {
+#ifdef CONFIG_KVM_MPIC
+       case KVM_DEV_TYPE_FSL_MPIC_20:
+       case KVM_DEV_TYPE_FSL_MPIC_42:
+               ops = &kvm_mpic_ops;
+               break;
+#endif
+#ifdef CONFIG_KVM_XICS
+       case KVM_DEV_TYPE_XICS:
+               ops = &kvm_xics_ops;
+               break;
+#endif
+       default:
+               return -ENODEV;
+       }
+
+       if (test)
+               return 0;
+
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev)
+               return -ENOMEM;
+
+       dev->ops = ops;
+       dev->kvm = kvm;
+
+       ret = ops->create(dev, cd->type);
+       if (ret < 0) {
+               kfree(dev);
+               return ret;
+       }
+
+       ret = anon_inode_getfd(ops->name, &kvm_device_fops, dev, O_RDWR);
+       if (ret < 0) {
+               ops->destroy(dev);
+               return ret;
+       }
+
+       list_add(&dev->vm_node, &kvm->devices);
+       kvm_get_kvm(kvm);
+       cd->fd = ret;
+       return 0;
+}
+
 static long kvm_vm_ioctl(struct file *filp,
                           unsigned int ioctl, unsigned long arg)
 {
@@ -2225,7 +2335,7 @@ static long kvm_vm_ioctl(struct file *filp,
                                                sizeof kvm_userspace_mem))
                        goto out;
 
-               r = kvm_vm_ioctl_set_memory_region(kvm, &kvm_userspace_mem, true);
+               r = kvm_vm_ioctl_set_memory_region(kvm, &kvm_userspace_mem);
                break;
        }
        case KVM_GET_DIRTY_LOG: {
@@ -2304,7 +2414,8 @@ static long kvm_vm_ioctl(struct file *filp,
                if (copy_from_user(&irq_event, argp, sizeof irq_event))
                        goto out;
 
-               r = kvm_vm_ioctl_irq_line(kvm, &irq_event);
+               r = kvm_vm_ioctl_irq_line(kvm, &irq_event,
+                                       ioctl == KVM_IRQ_LINE_STATUS);
                if (r)
                        goto out;
 
@@ -2318,6 +2429,54 @@ static long kvm_vm_ioctl(struct file *filp,
                break;
        }
 #endif
+#ifdef CONFIG_HAVE_KVM_IRQ_ROUTING
+       case KVM_SET_GSI_ROUTING: {
+               struct kvm_irq_routing routing;
+               struct kvm_irq_routing __user *urouting;
+               struct kvm_irq_routing_entry *entries;
+
+               r = -EFAULT;
+               if (copy_from_user(&routing, argp, sizeof(routing)))
+                       goto out;
+               r = -EINVAL;
+               if (routing.nr >= KVM_MAX_IRQ_ROUTES)
+                       goto out;
+               if (routing.flags)
+                       goto out;
+               r = -ENOMEM;
+               entries = vmalloc(routing.nr * sizeof(*entries));
+               if (!entries)
+                       goto out;
+               r = -EFAULT;
+               urouting = argp;
+               if (copy_from_user(entries, urouting->entries,
+                                  routing.nr * sizeof(*entries)))
+                       goto out_free_irq_routing;
+               r = kvm_set_irq_routing(kvm, entries, routing.nr,
+                                       routing.flags);
+       out_free_irq_routing:
+               vfree(entries);
+               break;
+       }
+#endif /* CONFIG_HAVE_KVM_IRQ_ROUTING */
+       case KVM_CREATE_DEVICE: {
+               struct kvm_create_device cd;
+
+               r = -EFAULT;
+               if (copy_from_user(&cd, argp, sizeof(cd)))
+                       goto out;
+
+               r = kvm_ioctl_create_device(kvm, &cd);
+               if (r)
+                       goto out;
+
+               r = -EFAULT;
+               if (copy_to_user(argp, &cd, sizeof(cd)))
+                       goto out;
+
+               r = 0;
+               break;
+       }
        default:
                r = kvm_arch_vm_ioctl(filp, ioctl, arg);
                if (r == -ENOTTY)
@@ -2446,9 +2605,12 @@ static long kvm_dev_ioctl_check_extension_generic(long arg)
        case KVM_CAP_INTERNAL_ERROR_DATA:
 #ifdef CONFIG_HAVE_KVM_MSI
        case KVM_CAP_SIGNAL_MSI:
+#endif
+#ifdef CONFIG_HAVE_KVM_IRQ_ROUTING
+       case KVM_CAP_IRQFD_RESAMPLE:
 #endif
                return 1;
-#ifdef KVM_CAP_IRQ_ROUTING
+#ifdef CONFIG_HAVE_KVM_IRQ_ROUTING
        case KVM_CAP_IRQ_ROUTING:
                return KVM_MAX_IRQ_ROUTES;
 #endif
@@ -2618,14 +2780,6 @@ static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val,
        return NOTIFY_OK;
 }
 
-
-asmlinkage void kvm_spurious_fault(void)
-{
-       /* Fault while not rebooting.  We want the trace. */
-       BUG();
-}
-EXPORT_SYMBOL_GPL(kvm_spurious_fault);
-
 static int kvm_reboot(struct notifier_block *notifier, unsigned long val,
                      void *v)
 {
@@ -2658,7 +2812,7 @@ static void kvm_io_bus_destroy(struct kvm_io_bus *bus)
        kfree(bus);
 }
 
-int kvm_io_bus_sort_cmp(const void *p1, const void *p2)
+static int kvm_io_bus_sort_cmp(const void *p1, const void *p2)
 {
        const struct kvm_io_range *r1 = p1;
        const struct kvm_io_range *r2 = p2;
@@ -2670,7 +2824,7 @@ int kvm_io_bus_sort_cmp(const void *p1, const void *p2)
        return 0;
 }
 
-int kvm_io_bus_insert_dev(struct kvm_io_bus *bus, struct kvm_io_device *dev,
+static int kvm_io_bus_insert_dev(struct kvm_io_bus *bus, struct kvm_io_device *dev,
                          gpa_t addr, int len)
 {
        bus->range[bus->dev_count++] = (struct kvm_io_range) {
@@ -2685,7 +2839,7 @@ int kvm_io_bus_insert_dev(struct kvm_io_bus *bus, struct kvm_io_device *dev,
        return 0;
 }
 
-int kvm_io_bus_get_first_dev(struct kvm_io_bus *bus,
+static int kvm_io_bus_get_first_dev(struct kvm_io_bus *bus,
                             gpa_t addr, int len)
 {
        struct kvm_io_range *range, key;
@@ -2929,6 +3083,8 @@ struct kvm_vcpu *preempt_notifier_to_vcpu(struct preempt_notifier *pn)
 static void kvm_sched_in(struct preempt_notifier *pn, int cpu)
 {
        struct kvm_vcpu *vcpu = preempt_notifier_to_vcpu(pn);
+       if (vcpu->preempted)
+               vcpu->preempted = false;
 
        kvm_arch_vcpu_load(vcpu, cpu);
 }
@@ -2938,6 +3094,8 @@ static void kvm_sched_out(struct preempt_notifier *pn,
 {
        struct kvm_vcpu *vcpu = preempt_notifier_to_vcpu(pn);
 
+       if (current->state == TASK_RUNNING)
+               vcpu->preempted = true;
        kvm_arch_vcpu_put(vcpu);
 }
 
@@ -2947,6 +3105,9 @@ int kvm_init(void *opaque, unsigned vcpu_size, unsigned vcpu_align,
        int r;
        int cpu;
 
+       r = kvm_irqfd_init();
+       if (r)
+               goto out_irqfd;
        r = kvm_arch_init(opaque);
        if (r)
                goto out_fail;
@@ -3027,6 +3188,8 @@ out_free_0a:
 out_free_0:
        kvm_arch_exit();
 out_fail:
+       kvm_irqfd_exit();
+out_irqfd:
        return r;
 }
 EXPORT_SYMBOL_GPL(kvm_init);
@@ -3043,6 +3206,7 @@ void kvm_exit(void)
        on_each_cpu(hardware_disable_nolock, NULL, 1);
        kvm_arch_hardware_unsetup();
        kvm_arch_exit();
+       kvm_irqfd_exit();
        free_cpumask_var(cpus_hardware_enabled);
 }
 EXPORT_SYMBOL_GPL(kvm_exit);