]> err.no Git - linux-2.6/blobdiff - virt/kvm/kvm_main.c
Merge branch 'x86-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6] / virt / kvm / kvm_main.c
index f9dd20606c406a97f056d655f1072f7abbd7e4b4..a845890b680062365930b89a63ba4536c0fa6670 100644 (file)
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 
+#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET
+#include "coalesced_mmio.h"
+#endif
+
 MODULE_AUTHOR("Qumranet");
 MODULE_LICENSE("GPL");
 
@@ -65,6 +69,8 @@ struct dentry *kvm_debugfs_dir;
 static long kvm_vcpu_ioctl(struct file *file, unsigned int ioctl,
                           unsigned long arg);
 
+bool kvm_rebooting;
+
 static inline int valid_vcpu(int n)
 {
        return likely(n >= 0 && n < KVM_MAX_VCPUS);
@@ -99,10 +105,11 @@ static void ack_flush(void *_completed)
 
 void kvm_flush_remote_tlbs(struct kvm *kvm)
 {
-       int i, cpu;
+       int i, cpu, me;
        cpumask_t cpus;
        struct kvm_vcpu *vcpu;
 
+       me = get_cpu();
        cpus_clear(cpus);
        for (i = 0; i < KVM_MAX_VCPUS; ++i) {
                vcpu = kvm->vcpus[i];
@@ -111,21 +118,24 @@ void kvm_flush_remote_tlbs(struct kvm *kvm)
                if (test_and_set_bit(KVM_REQ_TLB_FLUSH, &vcpu->requests))
                        continue;
                cpu = vcpu->cpu;
-               if (cpu != -1 && cpu != raw_smp_processor_id())
+               if (cpu != -1 && cpu != me)
                        cpu_set(cpu, cpus);
        }
        if (cpus_empty(cpus))
-               return;
+               goto out;
        ++kvm->stat.remote_tlb_flush;
        smp_call_function_mask(cpus, ack_flush, NULL, 1);
+out:
+       put_cpu();
 }
 
 void kvm_reload_remote_mmus(struct kvm *kvm)
 {
-       int i, cpu;
+       int i, cpu, me;
        cpumask_t cpus;
        struct kvm_vcpu *vcpu;
 
+       me = get_cpu();
        cpus_clear(cpus);
        for (i = 0; i < KVM_MAX_VCPUS; ++i) {
                vcpu = kvm->vcpus[i];
@@ -134,12 +144,14 @@ void kvm_reload_remote_mmus(struct kvm *kvm)
                if (test_and_set_bit(KVM_REQ_MMU_RELOAD, &vcpu->requests))
                        continue;
                cpu = vcpu->cpu;
-               if (cpu != -1 && cpu != raw_smp_processor_id())
+               if (cpu != -1 && cpu != me)
                        cpu_set(cpu, cpus);
        }
        if (cpus_empty(cpus))
-               return;
+               goto out;
        smp_call_function_mask(cpus, ack_flush, NULL, 1);
+out:
+       put_cpu();
 }
 
 
@@ -183,10 +195,23 @@ EXPORT_SYMBOL_GPL(kvm_vcpu_uninit);
 static struct kvm *kvm_create_vm(void)
 {
        struct kvm *kvm = kvm_arch_create_vm();
+#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET
+       struct page *page;
+#endif
 
        if (IS_ERR(kvm))
                goto out;
 
+#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET
+       page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+       if (!page) {
+               kfree(kvm);
+               return ERR_PTR(-ENOMEM);
+       }
+       kvm->coalesced_mmio_ring =
+                       (struct kvm_coalesced_mmio_ring *)page_address(page);
+#endif
+
        kvm->mm = current->mm;
        atomic_inc(&kvm->mm->mm_count);
        spin_lock_init(&kvm->mmu_lock);
@@ -198,6 +223,9 @@ static struct kvm *kvm_create_vm(void)
        spin_lock(&kvm_lock);
        list_add(&kvm->vm_list, &vm_list);
        spin_unlock(&kvm_lock);
+#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET
+       kvm_coalesced_mmio_init(kvm);
+#endif
 out:
        return kvm;
 }
@@ -240,6 +268,10 @@ static void kvm_destroy_vm(struct kvm *kvm)
        spin_unlock(&kvm_lock);
        kvm_io_bus_destroy(&kvm->pio_bus);
        kvm_io_bus_destroy(&kvm->mmio_bus);
+#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET
+       if (kvm->coalesced_mmio_ring != NULL)
+               free_page((unsigned long)kvm->coalesced_mmio_ring);
+#endif
        kvm_arch_destroy_vm(kvm);
        mmdrop(mm);
 }
@@ -333,6 +365,7 @@ int __kvm_set_memory_region(struct kvm *kvm,
        r = -ENOMEM;
 
        /* Allocate if a slot is being created */
+#ifndef CONFIG_S390
        if (npages && !new.rmap) {
                new.rmap = vmalloc(npages * sizeof(struct page *));
 
@@ -373,10 +406,14 @@ int __kvm_set_memory_region(struct kvm *kvm,
                        goto out_free;
                memset(new.dirty_bitmap, 0, dirty_bytes);
        }
+#endif /* not defined CONFIG_S390 */
 
        if (mem->slot >= kvm->nmemslots)
                kvm->nmemslots = mem->slot + 1;
 
+       if (!npages)
+               kvm_arch_flush_shadow(kvm);
+
        *memslot = new;
 
        r = kvm_arch_set_memory_region(kvm, mem, old, user_alloc);
@@ -823,6 +860,10 @@ static int kvm_vcpu_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 #ifdef CONFIG_X86
        else if (vmf->pgoff == KVM_PIO_PAGE_OFFSET)
                page = virt_to_page(vcpu->arch.pio_data);
+#endif
+#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET
+       else if (vmf->pgoff == KVM_COALESCED_MMIO_PAGE_OFFSET)
+               page = virt_to_page(vcpu->kvm->coalesced_mmio_ring);
 #endif
        else
                return VM_FAULT_SIGBUS;
@@ -861,7 +902,7 @@ static const struct file_operations kvm_vcpu_fops = {
  */
 static int create_vcpu_fd(struct kvm_vcpu *vcpu)
 {
-       int fd = anon_inode_getfd("kvm-vcpu", &kvm_vcpu_fops, vcpu);
+       int fd = anon_inode_getfd("kvm-vcpu", &kvm_vcpu_fops, vcpu, 0);
        if (fd < 0)
                kvm_put_kvm(vcpu->kvm);
        return fd;
@@ -1146,6 +1187,32 @@ static long kvm_vm_ioctl(struct file *filp,
                        goto out;
                break;
        }
+#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET
+       case KVM_REGISTER_COALESCED_MMIO: {
+               struct kvm_coalesced_mmio_zone zone;
+               r = -EFAULT;
+               if (copy_from_user(&zone, argp, sizeof zone))
+                       goto out;
+               r = -ENXIO;
+               r = kvm_vm_ioctl_register_coalesced_mmio(kvm, &zone);
+               if (r)
+                       goto out;
+               r = 0;
+               break;
+       }
+       case KVM_UNREGISTER_COALESCED_MMIO: {
+               struct kvm_coalesced_mmio_zone zone;
+               r = -EFAULT;
+               if (copy_from_user(&zone, argp, sizeof zone))
+                       goto out;
+               r = -ENXIO;
+               r = kvm_vm_ioctl_unregister_coalesced_mmio(kvm, &zone);
+               if (r)
+                       goto out;
+               r = 0;
+               break;
+       }
+#endif
        default:
                r = kvm_arch_vm_ioctl(filp, ioctl, arg);
        }
@@ -1194,7 +1261,7 @@ static int kvm_dev_ioctl_create_vm(void)
        kvm = kvm_create_vm();
        if (IS_ERR(kvm))
                return PTR_ERR(kvm);
-       fd = anon_inode_getfd("kvm-vm", &kvm_vm_fops, kvm);
+       fd = anon_inode_getfd("kvm-vm", &kvm_vm_fops, kvm, 0);
        if (fd < 0)
                kvm_put_kvm(kvm);
 
@@ -1229,6 +1296,9 @@ static long kvm_dev_ioctl(struct file *filp,
                r = PAGE_SIZE;     /* struct kvm_run */
 #ifdef CONFIG_X86
                r += PAGE_SIZE;    /* pio data page */
+#endif
+#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET
+               r += PAGE_SIZE;    /* coalesced mmio ring page */
 #endif
                break;
        case KVM_TRACE_ENABLE:
@@ -1271,7 +1341,6 @@ static void hardware_disable(void *junk)
        if (!cpu_isset(cpu, cpus_hardware_enabled))
                return;
        cpu_clear(cpu, cpus_hardware_enabled);
-       decache_vcpus_on_cpu(cpu);
        kvm_arch_hardware_disable(NULL);
 }
 
@@ -1301,6 +1370,18 @@ static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val,
        return NOTIFY_OK;
 }
 
+
+asmlinkage void kvm_handle_fault_on_reboot(void)
+{
+       if (kvm_rebooting)
+               /* spin while reset goes on */
+               while (true)
+                       ;
+       /* Fault while not rebooting.  We want the trace. */
+       BUG();
+}
+EXPORT_SYMBOL_GPL(kvm_handle_fault_on_reboot);
+
 static int kvm_reboot(struct notifier_block *notifier, unsigned long val,
                      void *v)
 {
@@ -1310,6 +1391,7 @@ static int kvm_reboot(struct notifier_block *notifier, unsigned long val,
                 * in vmx root mode.
                 */
                printk(KERN_INFO "kvm: exiting hardware virtualization\n");
+               kvm_rebooting = true;
                on_each_cpu(hardware_disable, NULL, 1);
        }
        return NOTIFY_OK;
@@ -1336,14 +1418,15 @@ void kvm_io_bus_destroy(struct kvm_io_bus *bus)
        }
 }
 
-struct kvm_io_device *kvm_io_bus_find_dev(struct kvm_io_bus *bus, gpa_t addr)
+struct kvm_io_device *kvm_io_bus_find_dev(struct kvm_io_bus *bus,
+                                         gpa_t addr, int len, int is_write)
 {
        int i;
 
        for (i = 0; i < bus->dev_count; i++) {
                struct kvm_io_device *pos = bus->devs[i];
 
-               if (pos->in_range(pos, addr))
+               if (pos->in_range(pos, addr, len, is_write))
                        return pos;
        }