]> err.no Git - linux-2.6/blobdiff - drivers/kvm/kvm_main.c
KVM: Don't assign vcpu->cr3 if it's invalid: check first, set last
[linux-2.6] / drivers / kvm / kvm_main.c
index 1b206f197c6b5a4d2cd015ea57fcf554ef1a772b..5dc60170278241235d34009b6094b63fcd10c7b3 100644 (file)
@@ -53,8 +53,10 @@ static LIST_HEAD(vm_list);
 static cpumask_t cpus_hardware_enabled;
 
 struct kvm_arch_ops *kvm_arch_ops;
+struct kmem_cache *kvm_vcpu_cache;
+EXPORT_SYMBOL_GPL(kvm_vcpu_cache);
 
-static void hardware_disable(void *ignored);
+static __read_mostly struct preempt_ops kvm_preempt_ops;
 
 #define STAT_OFFSET(x) offsetof(struct kvm_vcpu, stat.x)
 
@@ -84,10 +86,17 @@ static struct dentry *debugfs_dir;
 
 #define MAX_IO_MSRS 256
 
-#define CR0_RESEVED_BITS 0xffffffff1ffaffc0ULL
-#define LMSW_GUEST_MASK 0x0eULL
-#define CR4_RESEVED_BITS (~((1ULL << 11) - 1))
-#define CR8_RESEVED_BITS (~0x0fULL)
+#define CR0_RESERVED_BITS                                              \
+       (~(unsigned long)(X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS \
+                         | X86_CR0_ET | X86_CR0_NE | X86_CR0_WP | X86_CR0_AM \
+                         | X86_CR0_NW | X86_CR0_CD | X86_CR0_PG))
+#define CR4_RESERVED_BITS                                              \
+       (~(unsigned long)(X86_CR4_VME | X86_CR4_PVI | X86_CR4_TSD | X86_CR4_DE\
+                         | X86_CR4_PSE | X86_CR4_PAE | X86_CR4_MCE     \
+                         | X86_CR4_PGE | X86_CR4_PCE | X86_CR4_OSFXSR  \
+                         | X86_CR4_OSXMMEXCPT | X86_CR4_VMXE))
+
+#define CR8_RESERVED_BITS (~(unsigned long)X86_CR8_TPR)
 #define EFER_RESERVED_BITS 0xfffffffffffff2fe
 
 #ifdef CONFIG_X86_64
@@ -139,82 +148,14 @@ static inline int valid_vcpu(int n)
        return likely(n >= 0 && n < KVM_MAX_VCPUS);
 }
 
-int kvm_read_guest(struct kvm_vcpu *vcpu, gva_t addr, unsigned long size,
-                  void *dest)
-{
-       unsigned char *host_buf = dest;
-       unsigned long req_size = size;
-
-       while (size) {
-               hpa_t paddr;
-               unsigned now;
-               unsigned offset;
-               hva_t guest_buf;
-
-               paddr = gva_to_hpa(vcpu, addr);
-
-               if (is_error_hpa(paddr))
-                       break;
-
-               guest_buf = (hva_t)kmap_atomic(
-                                       pfn_to_page(paddr >> PAGE_SHIFT),
-                                       KM_USER0);
-               offset = addr & ~PAGE_MASK;
-               guest_buf |= offset;
-               now = min(size, PAGE_SIZE - offset);
-               memcpy(host_buf, (void*)guest_buf, now);
-               host_buf += now;
-               addr += now;
-               size -= now;
-               kunmap_atomic((void *)(guest_buf & PAGE_MASK), KM_USER0);
-       }
-       return req_size - size;
-}
-EXPORT_SYMBOL_GPL(kvm_read_guest);
-
-int kvm_write_guest(struct kvm_vcpu *vcpu, gva_t addr, unsigned long size,
-                   void *data)
-{
-       unsigned char *host_buf = data;
-       unsigned long req_size = size;
-
-       while (size) {
-               hpa_t paddr;
-               unsigned now;
-               unsigned offset;
-               hva_t guest_buf;
-               gfn_t gfn;
-
-               paddr = gva_to_hpa(vcpu, addr);
-
-               if (is_error_hpa(paddr))
-                       break;
-
-               gfn = vcpu->mmu.gva_to_gpa(vcpu, addr) >> PAGE_SHIFT;
-               mark_page_dirty(vcpu->kvm, gfn);
-               guest_buf = (hva_t)kmap_atomic(
-                               pfn_to_page(paddr >> PAGE_SHIFT), KM_USER0);
-               offset = addr & ~PAGE_MASK;
-               guest_buf |= offset;
-               now = min(size, PAGE_SIZE - offset);
-               memcpy((void*)guest_buf, host_buf, now);
-               host_buf += now;
-               addr += now;
-               size -= now;
-               kunmap_atomic((void *)(guest_buf & PAGE_MASK), KM_USER0);
-       }
-       return req_size - size;
-}
-EXPORT_SYMBOL_GPL(kvm_write_guest);
-
 void kvm_load_guest_fpu(struct kvm_vcpu *vcpu)
 {
        if (!vcpu->fpu_active || vcpu->guest_fpu_loaded)
                return;
 
        vcpu->guest_fpu_loaded = 1;
-       fx_save(vcpu->host_fx_image);
-       fx_restore(vcpu->guest_fx_image);
+       fx_save(&vcpu->host_fx_image);
+       fx_restore(&vcpu->guest_fx_image);
 }
 EXPORT_SYMBOL_GPL(kvm_load_guest_fpu);
 
@@ -224,8 +165,8 @@ void kvm_put_guest_fpu(struct kvm_vcpu *vcpu)
                return;
 
        vcpu->guest_fpu_loaded = 0;
-       fx_save(vcpu->guest_fx_image);
-       fx_restore(vcpu->host_fx_image);
+       fx_save(&vcpu->guest_fx_image);
+       fx_restore(&vcpu->host_fx_image);
 }
 EXPORT_SYMBOL_GPL(kvm_put_guest_fpu);
 
@@ -234,30 +175,21 @@ EXPORT_SYMBOL_GPL(kvm_put_guest_fpu);
  */
 static void vcpu_load(struct kvm_vcpu *vcpu)
 {
-       mutex_lock(&vcpu->mutex);
-       kvm_arch_ops->vcpu_load(vcpu);
-}
-
-/*
- * Switches to specified vcpu, until a matching vcpu_put(). Will return NULL
- * if the slot is not populated.
- */
-static struct kvm_vcpu *vcpu_load_slot(struct kvm *kvm, int slot)
-{
-       struct kvm_vcpu *vcpu = &kvm->vcpus[slot];
+       int cpu;
 
        mutex_lock(&vcpu->mutex);
-       if (!vcpu->vmcs) {
-               mutex_unlock(&vcpu->mutex);
-               return NULL;
-       }
-       kvm_arch_ops->vcpu_load(vcpu);
-       return vcpu;
+       cpu = get_cpu();
+       preempt_notifier_register(&vcpu->preempt_notifier);
+       kvm_arch_ops->vcpu_load(vcpu, cpu);
+       put_cpu();
 }
 
 static void vcpu_put(struct kvm_vcpu *vcpu)
 {
+       preempt_disable();
        kvm_arch_ops->vcpu_put(vcpu);
+       preempt_notifier_unregister(&vcpu->preempt_notifier);
+       preempt_enable();
        mutex_unlock(&vcpu->mutex);
 }
 
@@ -278,8 +210,10 @@ void kvm_flush_remote_tlbs(struct kvm *kvm)
        atomic_set(&completed, 0);
        cpus_clear(cpus);
        needed = 0;
-       for (i = 0; i < kvm->nvcpus; ++i) {
-               vcpu = &kvm->vcpus[i];
+       for (i = 0; i < KVM_MAX_VCPUS; ++i) {
+               vcpu = kvm->vcpus[i];
+               if (!vcpu)
+                       continue;
                if (test_and_set_bit(KVM_TLB_FLUSH, &vcpu->requests))
                        continue;
                cpu = vcpu->cpu;
@@ -303,29 +237,68 @@ void kvm_flush_remote_tlbs(struct kvm *kvm)
        }
 }
 
+int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id)
+{
+       struct page *page;
+       int r;
+
+       mutex_init(&vcpu->mutex);
+       vcpu->cpu = -1;
+       vcpu->mmu.root_hpa = INVALID_PAGE;
+       vcpu->kvm = kvm;
+       vcpu->vcpu_id = id;
+
+       page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+       if (!page) {
+               r = -ENOMEM;
+               goto fail;
+       }
+       vcpu->run = page_address(page);
+
+       page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+       if (!page) {
+               r = -ENOMEM;
+               goto fail_free_run;
+       }
+       vcpu->pio_data = page_address(page);
+
+       r = kvm_mmu_create(vcpu);
+       if (r < 0)
+               goto fail_free_pio_data;
+
+       return 0;
+
+fail_free_pio_data:
+       free_page((unsigned long)vcpu->pio_data);
+fail_free_run:
+       free_page((unsigned long)vcpu->run);
+fail:
+       return -ENOMEM;
+}
+EXPORT_SYMBOL_GPL(kvm_vcpu_init);
+
+void kvm_vcpu_uninit(struct kvm_vcpu *vcpu)
+{
+       kvm_mmu_destroy(vcpu);
+       free_page((unsigned long)vcpu->pio_data);
+       free_page((unsigned long)vcpu->run);
+}
+EXPORT_SYMBOL_GPL(kvm_vcpu_uninit);
+
 static struct kvm *kvm_create_vm(void)
 {
        struct kvm *kvm = kzalloc(sizeof(struct kvm), GFP_KERNEL);
-       int i;
 
        if (!kvm)
                return ERR_PTR(-ENOMEM);
 
        kvm_io_bus_init(&kvm->pio_bus);
-       spin_lock_init(&kvm->lock);
+       mutex_init(&kvm->lock);
        INIT_LIST_HEAD(&kvm->active_mmu_pages);
+       kvm_io_bus_init(&kvm->mmio_bus);
        spin_lock(&kvm_lock);
        list_add(&kvm->vm_list, &vm_list);
        spin_unlock(&kvm_lock);
-       kvm_io_bus_init(&kvm->mmio_bus);
-       for (i = 0; i < KVM_MAX_VCPUS; ++i) {
-               struct kvm_vcpu *vcpu = &kvm->vcpus[i];
-
-               mutex_init(&vcpu->mutex);
-               vcpu->cpu = -1;
-               vcpu->kvm = kvm;
-               vcpu->mmu.root_hpa = INVALID_PAGE;
-       }
        return kvm;
 }
 
@@ -370,7 +343,7 @@ static void free_pio_guest_pages(struct kvm_vcpu *vcpu)
 {
        int i;
 
-       for (i = 0; i < 2; ++i)
+       for (i = 0; i < ARRAY_SIZE(vcpu->pio.guest_pages); ++i)
                if (vcpu->pio.guest_pages[i]) {
                        __free_page(vcpu->pio.guest_pages[i]);
                        vcpu->pio.guest_pages[i] = NULL;
@@ -379,30 +352,11 @@ static void free_pio_guest_pages(struct kvm_vcpu *vcpu)
 
 static void kvm_unload_vcpu_mmu(struct kvm_vcpu *vcpu)
 {
-       if (!vcpu->vmcs)
-               return;
-
        vcpu_load(vcpu);
        kvm_mmu_unload(vcpu);
        vcpu_put(vcpu);
 }
 
-static void kvm_free_vcpu(struct kvm_vcpu *vcpu)
-{
-       if (!vcpu->vmcs)
-               return;
-
-       vcpu_load(vcpu);
-       kvm_mmu_destroy(vcpu);
-       vcpu_put(vcpu);
-       kvm_arch_ops->vcpu_free(vcpu);
-       free_page((unsigned long)vcpu->run);
-       vcpu->run = NULL;
-       free_page((unsigned long)vcpu->pio_data);
-       vcpu->pio_data = NULL;
-       free_pio_guest_pages(vcpu);
-}
-
 static void kvm_free_vcpus(struct kvm *kvm)
 {
        unsigned int i;
@@ -411,9 +365,15 @@ static void kvm_free_vcpus(struct kvm *kvm)
         * Unpin any mmu pages first.
         */
        for (i = 0; i < KVM_MAX_VCPUS; ++i)
-               kvm_unload_vcpu_mmu(&kvm->vcpus[i]);
-       for (i = 0; i < KVM_MAX_VCPUS; ++i)
-               kvm_free_vcpu(&kvm->vcpus[i]);
+               if (kvm->vcpus[i])
+                       kvm_unload_vcpu_mmu(kvm->vcpus[i]);
+       for (i = 0; i < KVM_MAX_VCPUS; ++i) {
+               if (kvm->vcpus[i]) {
+                       kvm_arch_ops->vcpu_free(kvm->vcpus[i]);
+                       kvm->vcpus[i] = NULL;
+               }
+       }
+
 }
 
 static int kvm_dev_release(struct inode *inode, struct file *filp)
@@ -454,58 +414,60 @@ static int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3)
        gfn_t pdpt_gfn = cr3 >> PAGE_SHIFT;
        unsigned offset = ((cr3 & (PAGE_SIZE-1)) >> 5) << 2;
        int i;
-       u64 pdpte;
        u64 *pdpt;
        int ret;
        struct page *page;
+       u64 pdpte[ARRAY_SIZE(vcpu->pdptrs)];
 
-       spin_lock(&vcpu->kvm->lock);
+       mutex_lock(&vcpu->kvm->lock);
        page = gfn_to_page(vcpu->kvm, pdpt_gfn);
-       /* FIXME: !page - emulate? 0xff? */
+       if (!page) {
+               ret = 0;
+               goto out;
+       }
+
        pdpt = kmap_atomic(page, KM_USER0);
+       memcpy(pdpte, pdpt+offset, sizeof(pdpte));
+       kunmap_atomic(pdpt, KM_USER0);
 
-       ret = 1;
-       for (i = 0; i < 4; ++i) {
-               pdpte = pdpt[offset + i];
-               if ((pdpte & 1) && (pdpte & 0xfffffff0000001e6ull)) {
+       for (i = 0; i < ARRAY_SIZE(pdpte); ++i) {
+               if ((pdpte[i] & 1) && (pdpte[i] & 0xfffffff0000001e6ull)) {
                        ret = 0;
                        goto out;
                }
        }
+       ret = 1;
 
-       for (i = 0; i < 4; ++i)
-               vcpu->pdptrs[i] = pdpt[offset + i];
-
+       memcpy(vcpu->pdptrs, pdpte, sizeof(vcpu->pdptrs));
 out:
-       kunmap_atomic(pdpt, KM_USER0);
-       spin_unlock(&vcpu->kvm->lock);
+       mutex_unlock(&vcpu->kvm->lock);
 
        return ret;
 }
 
 void set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
 {
-       if (cr0 & CR0_RESEVED_BITS) {
+       if (cr0 & CR0_RESERVED_BITS) {
                printk(KERN_DEBUG "set_cr0: 0x%lx #GP, reserved bits 0x%lx\n",
                       cr0, vcpu->cr0);
                inject_gp(vcpu);
                return;
        }
 
-       if ((cr0 & CR0_NW_MASK) && !(cr0 & CR0_CD_MASK)) {
+       if ((cr0 & X86_CR0_NW) && !(cr0 & X86_CR0_CD)) {
                printk(KERN_DEBUG "set_cr0: #GP, CD == 0 && NW == 1\n");
                inject_gp(vcpu);
                return;
        }
 
-       if ((cr0 & CR0_PG_MASK) && !(cr0 & CR0_PE_MASK)) {
+       if ((cr0 & X86_CR0_PG) && !(cr0 & X86_CR0_PE)) {
                printk(KERN_DEBUG "set_cr0: #GP, set PG flag "
                       "and a clear PE flag\n");
                inject_gp(vcpu);
                return;
        }
 
-       if (!is_paging(vcpu) && (cr0 & CR0_PG_MASK)) {
+       if (!is_paging(vcpu) && (cr0 & X86_CR0_PG)) {
 #ifdef CONFIG_X86_64
                if ((vcpu->shadow_efer & EFER_LME)) {
                        int cs_db, cs_l;
@@ -538,9 +500,9 @@ void set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
        kvm_arch_ops->set_cr0(vcpu, cr0);
        vcpu->cr0 = cr0;
 
-       spin_lock(&vcpu->kvm->lock);
+       mutex_lock(&vcpu->kvm->lock);
        kvm_mmu_reset_context(vcpu);
-       spin_unlock(&vcpu->kvm->lock);
+       mutex_unlock(&vcpu->kvm->lock);
        return;
 }
 EXPORT_SYMBOL_GPL(set_cr0);
@@ -553,62 +515,71 @@ EXPORT_SYMBOL_GPL(lmsw);
 
 void set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
 {
-       if (cr4 & CR4_RESEVED_BITS) {
+       if (cr4 & CR4_RESERVED_BITS) {
                printk(KERN_DEBUG "set_cr4: #GP, reserved bits\n");
                inject_gp(vcpu);
                return;
        }
 
        if (is_long_mode(vcpu)) {
-               if (!(cr4 & CR4_PAE_MASK)) {
+               if (!(cr4 & X86_CR4_PAE)) {
                        printk(KERN_DEBUG "set_cr4: #GP, clearing PAE while "
                               "in long mode\n");
                        inject_gp(vcpu);
                        return;
                }
-       } else if (is_paging(vcpu) && !is_pae(vcpu) && (cr4 & CR4_PAE_MASK)
+       } else if (is_paging(vcpu) && !is_pae(vcpu) && (cr4 & X86_CR4_PAE)
                   && !load_pdptrs(vcpu, vcpu->cr3)) {
                printk(KERN_DEBUG "set_cr4: #GP, pdptrs reserved bits\n");
                inject_gp(vcpu);
+               return;
        }
 
-       if (cr4 & CR4_VMXE_MASK) {
+       if (cr4 & X86_CR4_VMXE) {
                printk(KERN_DEBUG "set_cr4: #GP, setting VMXE\n");
                inject_gp(vcpu);
                return;
        }
        kvm_arch_ops->set_cr4(vcpu, cr4);
-       spin_lock(&vcpu->kvm->lock);
+       mutex_lock(&vcpu->kvm->lock);
        kvm_mmu_reset_context(vcpu);
-       spin_unlock(&vcpu->kvm->lock);
+       mutex_unlock(&vcpu->kvm->lock);
 }
 EXPORT_SYMBOL_GPL(set_cr4);
 
 void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
 {
        if (is_long_mode(vcpu)) {
-               if (cr3 & CR3_L_MODE_RESEVED_BITS) {
+               if (cr3 & CR3_L_MODE_RESERVED_BITS) {
                        printk(KERN_DEBUG "set_cr3: #GP, reserved bits\n");
                        inject_gp(vcpu);
                        return;
                }
        } else {
-               if (cr3 & CR3_RESEVED_BITS) {
-                       printk(KERN_DEBUG "set_cr3: #GP, reserved bits\n");
-                       inject_gp(vcpu);
-                       return;
-               }
-               if (is_paging(vcpu) && is_pae(vcpu) &&
-                   !load_pdptrs(vcpu, cr3)) {
-                       printk(KERN_DEBUG "set_cr3: #GP, pdptrs "
-                              "reserved bits\n");
-                       inject_gp(vcpu);
-                       return;
+               if (is_pae(vcpu)) {
+                       if (cr3 & CR3_PAE_RESERVED_BITS) {
+                               printk(KERN_DEBUG
+                                      "set_cr3: #GP, reserved bits\n");
+                               inject_gp(vcpu);
+                               return;
+                       }
+                       if (is_paging(vcpu) && !load_pdptrs(vcpu, cr3)) {
+                               printk(KERN_DEBUG "set_cr3: #GP, pdptrs "
+                                      "reserved bits\n");
+                               inject_gp(vcpu);
+                               return;
+                       }
+               } else {
+                       if (cr3 & CR3_NONPAE_RESERVED_BITS) {
+                               printk(KERN_DEBUG
+                                      "set_cr3: #GP, reserved bits\n");
+                               inject_gp(vcpu);
+                               return;
+                       }
                }
        }
 
-       vcpu->cr3 = cr3;
-       spin_lock(&vcpu->kvm->lock);
+       mutex_lock(&vcpu->kvm->lock);
        /*
         * Does the new cr3 value map to physical memory? (Note, we
         * catch an invalid cr3 even in real-mode, because it would
@@ -620,15 +591,17 @@ void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
         */
        if (unlikely(!gfn_to_memslot(vcpu->kvm, cr3 >> PAGE_SHIFT)))
                inject_gp(vcpu);
-       else
+       else {
+               vcpu->cr3 = cr3;
                vcpu->mmu.new_cr3(vcpu);
-       spin_unlock(&vcpu->kvm->lock);
+       }
+       mutex_unlock(&vcpu->kvm->lock);
 }
 EXPORT_SYMBOL_GPL(set_cr3);
 
 void set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8)
 {
-       if ( cr8 & CR8_RESEVED_BITS) {
+       if (cr8 & CR8_RESERVED_BITS) {
                printk(KERN_DEBUG "set_cr8: #GP, reserved bits 0x%lx\n", cr8);
                inject_gp(vcpu);
                return;
@@ -639,37 +612,23 @@ EXPORT_SYMBOL_GPL(set_cr8);
 
 void fx_init(struct kvm_vcpu *vcpu)
 {
-       struct __attribute__ ((__packed__)) fx_image_s {
-               u16 control; //fcw
-               u16 status; //fsw
-               u16 tag; // ftw
-               u16 opcode; //fop
-               u64 ip; // fpu ip
-               u64 operand;// fpu dp
-               u32 mxcsr;
-               u32 mxcsr_mask;
+       unsigned after_mxcsr_mask;
 
-       } *fx_image;
-
-       fx_save(vcpu->host_fx_image);
+       /* Initialize guest FPU by resetting ours and saving into guest's */
+       preempt_disable();
+       fx_save(&vcpu->host_fx_image);
        fpu_init();
-       fx_save(vcpu->guest_fx_image);
-       fx_restore(vcpu->host_fx_image);
+       fx_save(&vcpu->guest_fx_image);
+       fx_restore(&vcpu->host_fx_image);
+       preempt_enable();
 
-       fx_image = (struct fx_image_s *)vcpu->guest_fx_image;
-       fx_image->mxcsr = 0x1f80;
-       memset(vcpu->guest_fx_image + sizeof(struct fx_image_s),
-              0, FX_IMAGE_SIZE - sizeof(struct fx_image_s));
+       after_mxcsr_mask = offsetof(struct i387_fxsave_struct, st_space);
+       vcpu->guest_fx_image.mxcsr = 0x1f80;
+       memset((void *)&vcpu->guest_fx_image + after_mxcsr_mask,
+              0, sizeof(struct i387_fxsave_struct) - after_mxcsr_mask);
 }
 EXPORT_SYMBOL_GPL(fx_init);
 
-static void do_remove_write_access(struct kvm_vcpu *vcpu, int slot)
-{
-       spin_lock(&vcpu->kvm->lock);
-       kvm_mmu_slot_remove_write_access(vcpu, slot);
-       spin_unlock(&vcpu->kvm->lock);
-}
-
 /*
  * Allocate some memory and give it an address in the guest physical address
  * space.
@@ -706,7 +665,7 @@ static int kvm_vm_ioctl_set_memory_region(struct kvm *kvm,
                mem->flags &= ~KVM_MEM_LOG_DIRTY_PAGES;
 
 raced:
-       spin_lock(&kvm->lock);
+       mutex_lock(&kvm->lock);
 
        memory_config_version = kvm->memory_config_version;
        new = old = *memslot;
@@ -735,7 +694,7 @@ raced:
         * Do memory allocations outside lock.  memory_config_version will
         * detect any races.
         */
-       spin_unlock(&kvm->lock);
+       mutex_unlock(&kvm->lock);
 
        /* Deallocate if slot is being removed */
        if (!npages)
@@ -774,10 +733,10 @@ raced:
                memset(new.dirty_bitmap, 0, dirty_bytes);
        }
 
-       spin_lock(&kvm->lock);
+       mutex_lock(&kvm->lock);
 
        if (memory_config_version != kvm->memory_config_version) {
-               spin_unlock(&kvm->lock);
+               mutex_unlock(&kvm->lock);
                kvm_free_physmem_slot(&new, &old);
                goto raced;
        }
@@ -792,25 +751,16 @@ raced:
        *memslot = new;
        ++kvm->memory_config_version;
 
-       spin_unlock(&kvm->lock);
-
-       for (i = 0; i < KVM_MAX_VCPUS; ++i) {
-               struct kvm_vcpu *vcpu;
+       kvm_mmu_slot_remove_write_access(kvm, mem->slot);
+       kvm_flush_remote_tlbs(kvm);
 
-               vcpu = vcpu_load_slot(kvm, i);
-               if (!vcpu)
-                       continue;
-               if (new.flags & KVM_MEM_LOG_DIRTY_PAGES)
-                       do_remove_write_access(vcpu, mem->slot);
-               kvm_mmu_reset_context(vcpu);
-               vcpu_put(vcpu);
-       }
+       mutex_unlock(&kvm->lock);
 
        kvm_free_physmem_slot(&old, &new);
        return 0;
 
 out_unlock:
-       spin_unlock(&kvm->lock);
+       mutex_unlock(&kvm->lock);
 out_free:
        kvm_free_physmem_slot(&new, &old);
 out:
@@ -826,17 +776,16 @@ static int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
        struct kvm_memory_slot *memslot;
        int r, i;
        int n;
-       int cleared;
        unsigned long any = 0;
 
-       spin_lock(&kvm->lock);
+       mutex_lock(&kvm->lock);
 
        /*
         * Prevent changes to guest memory configuration even while the lock
         * is not taken.
         */
        ++kvm->busy;
-       spin_unlock(&kvm->lock);
+       mutex_unlock(&kvm->lock);
        r = -EINVAL;
        if (log->slot >= KVM_MEMORY_SLOTS)
                goto out;
@@ -855,30 +804,21 @@ static int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
        if (copy_to_user(log->dirty_bitmap, memslot->dirty_bitmap, n))
                goto out;
 
+       /* If nothing is dirty, don't bother messing with page tables. */
        if (any) {
-               cleared = 0;
-               for (i = 0; i < KVM_MAX_VCPUS; ++i) {
-                       struct kvm_vcpu *vcpu;
-
-                       vcpu = vcpu_load_slot(kvm, i);
-                       if (!vcpu)
-                               continue;
-                       if (!cleared) {
-                               do_remove_write_access(vcpu, log->slot);
-                               memset(memslot->dirty_bitmap, 0, n);
-                               cleared = 1;
-                       }
-                       kvm_arch_ops->tlb_flush(vcpu);
-                       vcpu_put(vcpu);
-               }
+               mutex_lock(&kvm->lock);
+               kvm_mmu_slot_remove_write_access(kvm, log->slot);
+               kvm_flush_remote_tlbs(kvm);
+               memset(memslot->dirty_bitmap, 0, n);
+               mutex_unlock(&kvm->lock);
        }
 
        r = 0;
 
 out:
-       spin_lock(&kvm->lock);
+       mutex_lock(&kvm->lock);
        --kvm->busy;
-       spin_unlock(&kvm->lock);
+       mutex_unlock(&kvm->lock);
        return r;
 }
 
@@ -908,7 +848,7 @@ static int kvm_vm_ioctl_set_memory_alias(struct kvm *kvm,
            < alias->target_phys_addr)
                goto out;
 
-       spin_lock(&kvm->lock);
+       mutex_lock(&kvm->lock);
 
        p = &kvm->aliases[alias->slot];
        p->base_gfn = alias->guest_phys_addr >> PAGE_SHIFT;
@@ -920,13 +860,9 @@ static int kvm_vm_ioctl_set_memory_alias(struct kvm *kvm,
                        break;
        kvm->naliases = n;
 
-       spin_unlock(&kvm->lock);
+       kvm_mmu_zap_all(kvm);
 
-       vcpu_load(&kvm->vcpus[0]);
-       spin_lock(&kvm->lock);
-       kvm_mmu_zap_all(&kvm->vcpus[0]);
-       spin_unlock(&kvm->lock);
-       vcpu_put(&kvm->vcpus[0]);
+       mutex_unlock(&kvm->lock);
 
        return 0;
 
@@ -1005,12 +941,11 @@ void mark_page_dirty(struct kvm *kvm, gfn_t gfn)
        }
 }
 
-static int emulator_read_std(unsigned long addr,
+int emulator_read_std(unsigned long addr,
                             void *val,
                             unsigned int bytes,
-                            struct x86_emulate_ctxt *ctxt)
+                            struct kvm_vcpu *vcpu)
 {
-       struct kvm_vcpu *vcpu = ctxt->vcpu;
        void *data = val;
 
        while (bytes) {
@@ -1040,11 +975,12 @@ static int emulator_read_std(unsigned long addr,
 
        return X86EMUL_CONTINUE;
 }
+EXPORT_SYMBOL_GPL(emulator_read_std);
 
 static int emulator_write_std(unsigned long addr,
                              const void *val,
                              unsigned int bytes,
-                             struct x86_emulate_ctxt *ctxt)
+                             struct kvm_vcpu *vcpu)
 {
        printk(KERN_ERR "emulator_write_std: addr %lx n %d\n",
               addr, bytes);
@@ -1071,9 +1007,8 @@ static struct kvm_io_device *vcpu_find_pio_dev(struct kvm_vcpu *vcpu,
 static int emulator_read_emulated(unsigned long addr,
                                  void *val,
                                  unsigned int bytes,
-                                 struct x86_emulate_ctxt *ctxt)
+                                 struct kvm_vcpu *vcpu)
 {
-       struct kvm_vcpu      *vcpu = ctxt->vcpu;
        struct kvm_io_device *mmio_dev;
        gpa_t                 gpa;
 
@@ -1081,7 +1016,7 @@ static int emulator_read_emulated(unsigned long addr,
                memcpy(val, vcpu->mmio_data, bytes);
                vcpu->mmio_read_completed = 0;
                return X86EMUL_CONTINUE;
-       } else if (emulator_read_std(addr, val, bytes, ctxt)
+       } else if (emulator_read_std(addr, val, bytes, vcpu)
                   == X86EMUL_CONTINUE)
                return X86EMUL_CONTINUE;
 
@@ -1111,7 +1046,6 @@ static int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa,
 {
        struct page *page;
        void *virt;
-       unsigned offset = offset_in_page(gpa);
 
        if (((gpa + bytes - 1) >> PAGE_SHIFT) != (gpa >> PAGE_SHIFT))
                return 0;
@@ -1120,20 +1054,17 @@ static int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa,
                return 0;
        mark_page_dirty(vcpu->kvm, gpa >> PAGE_SHIFT);
        virt = kmap_atomic(page, KM_USER0);
-       if (memcmp(virt + offset_in_page(gpa), val, bytes)) {
-               kvm_mmu_pte_write(vcpu, gpa, virt + offset, val, bytes);
-               memcpy(virt + offset_in_page(gpa), val, bytes);
-       }
+       kvm_mmu_pte_write(vcpu, gpa, val, bytes);
+       memcpy(virt + offset_in_page(gpa), val, bytes);
        kunmap_atomic(virt, KM_USER0);
        return 1;
 }
 
-static int emulator_write_emulated(unsigned long addr,
-                                  const void *val,
-                                  unsigned int bytes,
-                                  struct x86_emulate_ctxt *ctxt)
+static int emulator_write_emulated_onepage(unsigned long addr,
+                                          const void *val,
+                                          unsigned int bytes,
+                                          struct kvm_vcpu *vcpu)
 {
-       struct kvm_vcpu      *vcpu = ctxt->vcpu;
        struct kvm_io_device *mmio_dev;
        gpa_t                 gpa = vcpu->mmu.gva_to_gpa(vcpu, addr);
 
@@ -1163,11 +1094,32 @@ static int emulator_write_emulated(unsigned long addr,
        return X86EMUL_CONTINUE;
 }
 
+int emulator_write_emulated(unsigned long addr,
+                                  const void *val,
+                                  unsigned int bytes,
+                                  struct kvm_vcpu *vcpu)
+{
+       /* Crossing a page boundary? */
+       if (((addr + bytes - 1) ^ addr) & PAGE_MASK) {
+               int rc, now;
+
+               now = -addr & ~PAGE_MASK;
+               rc = emulator_write_emulated_onepage(addr, val, now, vcpu);
+               if (rc != X86EMUL_CONTINUE)
+                       return rc;
+               addr += now;
+               val += now;
+               bytes -= now;
+       }
+       return emulator_write_emulated_onepage(addr, val, bytes, vcpu);
+}
+EXPORT_SYMBOL_GPL(emulator_write_emulated);
+
 static int emulator_cmpxchg_emulated(unsigned long addr,
                                     const void *old,
                                     const void *new,
                                     unsigned int bytes,
-                                    struct x86_emulate_ctxt *ctxt)
+                                    struct kvm_vcpu *vcpu)
 {
        static int reported;
 
@@ -1175,7 +1127,7 @@ static int emulator_cmpxchg_emulated(unsigned long addr,
                reported = 1;
                printk(KERN_WARNING "kvm: emulating exchange as write\n");
        }
-       return emulator_write_emulated(addr, new, bytes, ctxt);
+       return emulator_write_emulated(addr, new, bytes, vcpu);
 }
 
 static unsigned long get_segment_base(struct kvm_vcpu *vcpu, int seg)
@@ -1192,7 +1144,7 @@ int emulate_clts(struct kvm_vcpu *vcpu)
 {
        unsigned long cr0;
 
-       cr0 = vcpu->cr0 & ~CR0_TS_MASK;
+       cr0 = vcpu->cr0 & ~X86_CR0_TS;
        kvm_arch_ops->set_cr0(vcpu, cr0);
        return X86EMUL_CONTINUE;
 }
@@ -1237,7 +1189,7 @@ static void report_emulation_failure(struct x86_emulate_ctxt *ctxt)
        if (reported)
                return;
 
-       emulator_read_std(rip_linear, (void *)opcodes, 4, ctxt);
+       emulator_read_std(rip_linear, (void *)opcodes, 4, ctxt->vcpu);
 
        printk(KERN_ERR "emulation failed but !mmio_needed?"
               " rip %lx %02x %02x %02x %02x\n",
@@ -1294,6 +1246,7 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
        r = x86_emulate_memop(&emulate_ctxt, &emulate_ops);
 
        if ((r || vcpu->mmio_is_write) && run) {
+               run->exit_reason = KVM_EXIT_MMIO;
                run->mmio.phys_addr = vcpu->mmio_phys_addr;
                memcpy(run->mmio.data, vcpu->mmio_data, 8);
                run->mmio.len = vcpu->mmio_size;
@@ -1361,6 +1314,7 @@ int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run)
        }
        switch (nr) {
        default:
+               run->hypercall.nr = nr;
                run->hypercall.args[0] = a0;
                run->hypercall.args[1] = a1;
                run->hypercall.args[2] = a2;
@@ -1471,7 +1425,7 @@ static int vcpu_register_para(struct kvm_vcpu *vcpu, gpa_t para_state_gpa)
 
        mark_page_dirty(vcpu->kvm, para_state_gpa >> PAGE_SHIFT);
        para_state_page = pfn_to_page(para_state_hpa >> PAGE_SHIFT);
-       para_state = kmap_atomic(para_state_page, KM_USER0);
+       para_state = kmap(para_state_page);
 
        printk(KERN_DEBUG "....  guest version: %d\n", para_state->guest_version);
        printk(KERN_DEBUG "....           size: %d\n", para_state->size);
@@ -1507,7 +1461,7 @@ static int vcpu_register_para(struct kvm_vcpu *vcpu, gpa_t para_state_gpa)
 
        para_state->ret = 0;
 err_kunmap_skip:
-       kunmap_atomic(para_state, KM_USER0);
+       kunmap(para_state_page);
        return 0;
 err_gp:
        return 1;
@@ -1567,7 +1521,7 @@ EXPORT_SYMBOL_GPL(kvm_get_msr_common);
  * Returns 0 on success, non-0 otherwise.
  * Assumes vcpu_load() was already called.
  */
-static int get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
+int kvm_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
 {
        return kvm_arch_ops->get_msr(vcpu, msr_index, pdata);
 }
@@ -1645,7 +1599,7 @@ EXPORT_SYMBOL_GPL(kvm_set_msr_common);
  * Returns 0 on success, non-0 otherwise.
  * Assumes vcpu_load() was already called.
  */
-static int set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
+int kvm_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
 {
        return kvm_arch_ops->set_msr(vcpu, msr_index, data);
 }
@@ -1654,30 +1608,10 @@ void kvm_resched(struct kvm_vcpu *vcpu)
 {
        if (!need_resched())
                return;
-       vcpu_put(vcpu);
        cond_resched();
-       vcpu_load(vcpu);
 }
 EXPORT_SYMBOL_GPL(kvm_resched);
 
-void load_msrs(struct vmx_msr_entry *e, int n)
-{
-       int i;
-
-       for (i = 0; i < n; ++i)
-               wrmsrl(e[i].index, e[i].data);
-}
-EXPORT_SYMBOL_GPL(load_msrs);
-
-void save_msrs(struct vmx_msr_entry *e, int n)
-{
-       int i;
-
-       for (i = 0; i < n; ++i)
-               rdmsrl(e[i].index, e[i].data);
-}
-EXPORT_SYMBOL_GPL(save_msrs);
-
 void kvm_emulate_cpuid(struct kvm_vcpu *vcpu)
 {
        int i;
@@ -1722,11 +1656,9 @@ static int pio_copy_data(struct kvm_vcpu *vcpu)
        unsigned bytes;
        int nr_pages = vcpu->pio.guest_pages[1] ? 2 : 1;
 
-       kvm_arch_ops->vcpu_put(vcpu);
        q = vmap(vcpu->pio.guest_pages, nr_pages, VM_READ|VM_WRITE,
                 PAGE_KERNEL);
        if (!q) {
-               kvm_arch_ops->vcpu_load(vcpu);
                free_pio_guest_pages(vcpu);
                return -ENOMEM;
        }
@@ -1738,7 +1670,6 @@ static int pio_copy_data(struct kvm_vcpu *vcpu)
                memcpy(p, q, bytes);
        q -= vcpu->pio.guest_page_offset;
        vunmap(q);
-       kvm_arch_ops->vcpu_load(vcpu);
        free_pio_guest_pages(vcpu);
        return 0;
 }
@@ -1792,18 +1723,35 @@ static int complete_pio(struct kvm_vcpu *vcpu)
        return 0;
 }
 
-void kernel_pio(struct kvm_io_device *pio_dev, struct kvm_vcpu *vcpu)
+static void kernel_pio(struct kvm_io_device *pio_dev,
+                      struct kvm_vcpu *vcpu,
+                      void *pd)
 {
        /* TODO: String I/O for in kernel device */
 
        if (vcpu->pio.in)
                kvm_iodevice_read(pio_dev, vcpu->pio.port,
                                  vcpu->pio.size,
-                                 vcpu->pio_data);
+                                 pd);
        else
                kvm_iodevice_write(pio_dev, vcpu->pio.port,
                                   vcpu->pio.size,
-                                  vcpu->pio_data);
+                                  pd);
+}
+
+static void pio_string_write(struct kvm_io_device *pio_dev,
+                            struct kvm_vcpu *vcpu)
+{
+       struct kvm_pio_request *io = &vcpu->pio;
+       void *pd = vcpu->pio_data;
+       int i;
+
+       for (i = 0; i < io->cur_count; i++) {
+               kvm_iodevice_write(pio_dev, io->port,
+                                  io->size,
+                                  pd);
+               pd += io->size;
+       }
 }
 
 int kvm_setup_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
@@ -1811,7 +1759,7 @@ int kvm_setup_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
                  gva_t address, int rep, unsigned port)
 {
        unsigned now, in_page;
-       int i;
+       int i, ret = 0;
        int nr_pages = 1;
        struct page *page;
        struct kvm_io_device *pio_dev;
@@ -1838,15 +1786,12 @@ int kvm_setup_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
                memcpy(vcpu->pio_data, &vcpu->regs[VCPU_REGS_RAX], 4);
                kvm_arch_ops->decache_regs(vcpu);
                if (pio_dev) {
-                       kernel_pio(pio_dev, vcpu);
+                       kernel_pio(pio_dev, vcpu, vcpu->pio_data);
                        complete_pio(vcpu);
                        return 1;
                }
                return 0;
        }
-       /* TODO: String I/O for in kernel device */
-       if (pio_dev)
-               printk(KERN_ERR "kvm_setup_pio: no string io support\n");
 
        if (!count) {
                kvm_arch_ops->skip_emulated_instruction(vcpu);
@@ -1881,12 +1826,12 @@ int kvm_setup_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
        vcpu->pio.cur_count = now;
 
        for (i = 0; i < nr_pages; ++i) {
-               spin_lock(&vcpu->kvm->lock);
+               mutex_lock(&vcpu->kvm->lock);
                page = gva_to_page(vcpu, address + i * PAGE_SIZE);
                if (page)
                        get_page(page);
                vcpu->pio.guest_pages[i] = page;
-               spin_unlock(&vcpu->kvm->lock);
+               mutex_unlock(&vcpu->kvm->lock);
                if (!page) {
                        inject_gp(vcpu);
                        free_pio_guest_pages(vcpu);
@@ -1894,9 +1839,21 @@ int kvm_setup_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
                }
        }
 
-       if (!vcpu->pio.in)
-               return pio_copy_data(vcpu);
-       return 0;
+       if (!vcpu->pio.in) {
+               /* string PIO write */
+               ret = pio_copy_data(vcpu);
+               if (ret >= 0 && pio_dev) {
+                       pio_string_write(pio_dev, vcpu);
+                       complete_pio(vcpu);
+                       if (vcpu->pio.count == 0)
+                               ret = 1;
+               }
+       } else if (pio_dev)
+               printk(KERN_ERR "no string pio read support yet, "
+                      "port %x size %d count %ld\n",
+                       port, size, count);
+
+       return ret;
 }
 EXPORT_SYMBOL_GPL(kvm_setup_pio);
 
@@ -1929,7 +1886,6 @@ static int kvm_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
                        /*
                         * Read-modify-write.  Back to userspace.
                         */
-                       kvm_run->exit_reason = KVM_EXIT_MMIO;
                        r = 0;
                        goto out;
                }
@@ -2122,7 +2078,7 @@ static int kvm_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
        memcpy(vcpu->irq_pending, sregs->interrupt_bitmap,
               sizeof vcpu->irq_pending);
        vcpu->irq_summary = 0;
-       for (i = 0; i < NR_IRQ_WORDS; ++i)
+       for (i = 0; i < ARRAY_SIZE(vcpu->irq_pending); ++i)
                if (vcpu->irq_pending[i])
                        __set_bit(i, &vcpu->irq_summary);
 
@@ -2183,7 +2139,7 @@ static __init void kvm_init_msr_list(void)
  */
 static int do_set_msr(struct kvm_vcpu *vcpu, unsigned index, u64 *data)
 {
-       return set_msr(vcpu, index, *data);
+       return kvm_set_msr(vcpu, index, *data);
 }
 
 /*
@@ -2268,13 +2224,13 @@ static int kvm_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
        gpa_t gpa;
 
        vcpu_load(vcpu);
-       spin_lock(&vcpu->kvm->lock);
+       mutex_lock(&vcpu->kvm->lock);
        gpa = vcpu->mmu.gva_to_gpa(vcpu, vaddr);
        tr->physical_address = gpa;
        tr->valid = gpa != UNMAPPED_GVA;
        tr->writeable = 1;
        tr->usermode = 0;
-       spin_unlock(&vcpu->kvm->lock);
+       mutex_unlock(&vcpu->kvm->lock);
        vcpu_put(vcpu);
 
        return 0;
@@ -2317,7 +2273,6 @@ static struct page *kvm_vcpu_nopage(struct vm_area_struct *vma,
        unsigned long pgoff;
        struct page *page;
 
-       *type = VM_FAULT_MINOR;
        pgoff = ((address - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
        if (pgoff == 0)
                page = virt_to_page(vcpu->run);
@@ -2326,6 +2281,9 @@ static struct page *kvm_vcpu_nopage(struct vm_area_struct *vma,
        else
                return NOPAGE_SIGBUS;
        get_page(page);
+       if (type != NULL)
+               *type = VM_FAULT_MINOR;
+
        return page;
 }
 
@@ -2378,74 +2336,52 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, int n)
 {
        int r;
        struct kvm_vcpu *vcpu;
-       struct page *page;
 
-       r = -EINVAL;
        if (!valid_vcpu(n))
-               goto out;
-
-       vcpu = &kvm->vcpus[n];
-
-       mutex_lock(&vcpu->mutex);
-
-       if (vcpu->vmcs) {
-               mutex_unlock(&vcpu->mutex);
-               return -EEXIST;
-       }
-
-       page = alloc_page(GFP_KERNEL | __GFP_ZERO);
-       r = -ENOMEM;
-       if (!page)
-               goto out_unlock;
-       vcpu->run = page_address(page);
-
-       page = alloc_page(GFP_KERNEL | __GFP_ZERO);
-       r = -ENOMEM;
-       if (!page)
-               goto out_free_run;
-       vcpu->pio_data = page_address(page);
+               return -EINVAL;
 
-       vcpu->host_fx_image = (char*)ALIGN((hva_t)vcpu->fx_buf,
-                                          FX_IMAGE_ALIGN);
-       vcpu->guest_fx_image = vcpu->host_fx_image + FX_IMAGE_SIZE;
-       vcpu->cr0 = 0x10;
+       vcpu = kvm_arch_ops->vcpu_create(kvm, n);
+       if (IS_ERR(vcpu))
+               return PTR_ERR(vcpu);
 
-       r = kvm_arch_ops->vcpu_create(vcpu);
-       if (r < 0)
-               goto out_free_vcpus;
+       preempt_notifier_init(&vcpu->preempt_notifier, &kvm_preempt_ops);
 
-       r = kvm_mmu_create(vcpu);
-       if (r < 0)
-               goto out_free_vcpus;
+       /* We do fxsave: this must be aligned. */
+       BUG_ON((unsigned long)&vcpu->host_fx_image & 0xF);
 
-       kvm_arch_ops->vcpu_load(vcpu);
+       vcpu_load(vcpu);
        r = kvm_mmu_setup(vcpu);
-       if (r >= 0)
-               r = kvm_arch_ops->vcpu_setup(vcpu);
        vcpu_put(vcpu);
-
        if (r < 0)
-               goto out_free_vcpus;
+               goto free_vcpu;
 
+       mutex_lock(&kvm->lock);
+       if (kvm->vcpus[n]) {
+               r = -EEXIST;
+               mutex_unlock(&kvm->lock);
+               goto mmu_unload;
+       }
+       kvm->vcpus[n] = vcpu;
+       mutex_unlock(&kvm->lock);
+
+       /* Now it's all set up, let userspace reach it */
        r = create_vcpu_fd(vcpu);
        if (r < 0)
-               goto out_free_vcpus;
+               goto unlink;
+       return r;
 
-       spin_lock(&kvm_lock);
-       if (n >= kvm->nvcpus)
-               kvm->nvcpus = n + 1;
-       spin_unlock(&kvm_lock);
+unlink:
+       mutex_lock(&kvm->lock);
+       kvm->vcpus[n] = NULL;
+       mutex_unlock(&kvm->lock);
 
-       return r;
+mmu_unload:
+       vcpu_load(vcpu);
+       kvm_mmu_unload(vcpu);
+       vcpu_put(vcpu);
 
-out_free_vcpus:
-       kvm_free_vcpu(vcpu);
-out_free_run:
-       free_page((unsigned long)vcpu->run);
-       vcpu->run = NULL;
-out_unlock:
-       mutex_unlock(&vcpu->mutex);
-out:
+free_vcpu:
+       kvm_arch_ops->vcpu_free(vcpu);
        return r;
 }
 
@@ -2464,9 +2400,9 @@ static void cpuid_fix_nx_cap(struct kvm_vcpu *vcpu)
                        break;
                }
        }
-       if (entry && (entry->edx & EFER_NX) && !(efer & EFER_NX)) {
+       if (entry && (entry->edx & (1 << 20)) && !(efer & EFER_NX)) {
                entry->edx &= ~(1 << 20);
-               printk(KERN_INFO ": guest NX capability removed\n");
+               printk(KERN_INFO "kvm: guest NX capability removed\n");
        }
 }
 
@@ -2525,7 +2461,7 @@ struct fxsave {
 
 static int kvm_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
 {
-       struct fxsave *fxsave = (struct fxsave *)vcpu->guest_fx_image;
+       struct fxsave *fxsave = (struct fxsave *)&vcpu->guest_fx_image;
 
        vcpu_load(vcpu);
 
@@ -2545,7 +2481,7 @@ static int kvm_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
 
 static int kvm_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
 {
-       struct fxsave *fxsave = (struct fxsave *)vcpu->guest_fx_image;
+       struct fxsave *fxsave = (struct fxsave *)&vcpu->guest_fx_image;
 
        vcpu_load(vcpu);
 
@@ -2667,7 +2603,7 @@ static long kvm_vcpu_ioctl(struct file *filp,
                break;
        }
        case KVM_GET_MSRS:
-               r = msr_io(vcpu, argp, get_msr, 1);
+               r = msr_io(vcpu, argp, kvm_get_msr, 1);
                break;
        case KVM_SET_MSRS:
                r = msr_io(vcpu, argp, do_set_msr, 0);
@@ -2800,12 +2736,14 @@ static struct page *kvm_vm_nopage(struct vm_area_struct *vma,
        unsigned long pgoff;
        struct page *page;
 
-       *type = VM_FAULT_MINOR;
        pgoff = ((address - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
        page = gfn_to_page(kvm, pgoff);
        if (!page)
                return NOPAGE_SIGBUS;
        get_page(page);
+       if (type != NULL)
+               *type = VM_FAULT_MINOR;
+
        return page;
 }
 
@@ -2925,25 +2863,6 @@ static struct miscdevice kvm_dev = {
        &kvm_chardev_ops,
 };
 
-static int kvm_reboot(struct notifier_block *notifier, unsigned long val,
-                       void *v)
-{
-       if (val == SYS_RESTART) {
-               /*
-                * Some (well, at least mine) BIOSes hang on reboot if
-                * in vmx root mode.
-                */
-               printk(KERN_INFO "kvm: exiting hardware virtualization\n");
-               on_each_cpu(hardware_disable, NULL, 0, 1);
-       }
-       return NOTIFY_OK;
-}
-
-static struct notifier_block kvm_reboot_notifier = {
-       .notifier_call = kvm_reboot,
-       .priority = 0,
-};
-
 /*
  * Make sure that a cpu that is being hot-unplugged does not have any vcpus
  * cached on it.
@@ -2957,7 +2876,9 @@ static void decache_vcpus_on_cpu(int cpu)
        spin_lock(&kvm_lock);
        list_for_each_entry(vm, &vm_list, vm_list)
                for (i = 0; i < KVM_MAX_VCPUS; ++i) {
-                       vcpu = &vm->vcpus[i];
+                       vcpu = vm->vcpus[i];
+                       if (!vcpu)
+                               continue;
                        /*
                         * If the vcpu is locked, then it is running on some
                         * other cpu and therefore it is not cached on the
@@ -3006,6 +2927,10 @@ static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val,
        switch (val) {
        case CPU_DYING:
        case CPU_DYING_FROZEN:
+               printk(KERN_INFO "kvm: disabling virtualization on CPU%d\n",
+                      cpu);
+               hardware_disable(NULL);
+               break;
        case CPU_UP_CANCELED:
        case CPU_UP_CANCELED_FROZEN:
                printk(KERN_INFO "kvm: disabling virtualization on CPU%d\n",
@@ -3022,6 +2947,25 @@ static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val,
        return NOTIFY_OK;
 }
 
+static int kvm_reboot(struct notifier_block *notifier, unsigned long val,
+                       void *v)
+{
+       if (val == SYS_RESTART) {
+               /*
+                * Some (well, at least mine) BIOSes hang on reboot if
+                * in vmx root mode.
+                */
+               printk(KERN_INFO "kvm: exiting hardware virtualization\n");
+               on_each_cpu(hardware_disable, NULL, 0, 1);
+       }
+       return NOTIFY_OK;
+}
+
+static struct notifier_block kvm_reboot_notifier = {
+       .notifier_call = kvm_reboot,
+       .priority = 0,
+};
+
 void kvm_io_bus_init(struct kvm_io_bus *bus)
 {
        memset(bus, 0, sizeof(*bus));
@@ -3075,8 +3019,9 @@ static u64 stat_get(void *_offset)
        spin_lock(&kvm_lock);
        list_for_each_entry(kvm, &vm_list, vm_list)
                for (i = 0; i < KVM_MAX_VCPUS; ++i) {
-                       vcpu = &kvm->vcpus[i];
-                       total += *(u32 *)((void *)vcpu + offset);
+                       vcpu = kvm->vcpus[i];
+                       if (vcpu)
+                               total += *(u32 *)((void *)vcpu + offset);
                }
        spin_unlock(&kvm_lock);
        return total;
@@ -3133,9 +3078,32 @@ static struct sys_device kvm_sysdev = {
 
 hpa_t bad_page_address;
 
-int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module)
+static inline
+struct kvm_vcpu *preempt_notifier_to_vcpu(struct preempt_notifier *pn)
+{
+       return container_of(pn, struct kvm_vcpu, preempt_notifier);
+}
+
+static void kvm_sched_in(struct preempt_notifier *pn, int cpu)
+{
+       struct kvm_vcpu *vcpu = preempt_notifier_to_vcpu(pn);
+
+       kvm_arch_ops->vcpu_load(vcpu, cpu);
+}
+
+static void kvm_sched_out(struct preempt_notifier *pn,
+                         struct task_struct *next)
+{
+       struct kvm_vcpu *vcpu = preempt_notifier_to_vcpu(pn);
+
+       kvm_arch_ops->vcpu_put(vcpu);
+}
+
+int kvm_init_arch(struct kvm_arch_ops *ops, unsigned int vcpu_size,
+                 struct module *module)
 {
        int r;
+       int cpu;
 
        if (kvm_arch_ops) {
                printk(KERN_ERR "kvm: already loaded the other module\n");
@@ -3157,6 +3125,14 @@ int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module)
        if (r < 0)
                goto out;
 
+       for_each_online_cpu(cpu) {
+               smp_call_function_single(cpu,
+                               kvm_arch_ops->check_processor_compatibility,
+                               &r, 0, 1);
+               if (r < 0)
+                       goto out_free_0;
+       }
+
        on_each_cpu(hardware_enable, NULL, 0, 1);
        r = register_cpu_notifier(&kvm_cpu_notifier);
        if (r)
@@ -3171,6 +3147,14 @@ int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module)
        if (r)
                goto out_free_3;
 
+       /* A kmem cache lets us meet the alignment requirements of fx_save. */
+       kvm_vcpu_cache = kmem_cache_create("kvm_vcpu", vcpu_size,
+                                          __alignof__(struct kvm_vcpu), 0, 0);
+       if (!kvm_vcpu_cache) {
+               r = -ENOMEM;
+               goto out_free_4;
+       }
+
        kvm_chardev_ops.owner = module;
 
        r = misc_register(&kvm_dev);
@@ -3179,9 +3163,14 @@ int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module)
                goto out_free;
        }
 
+       kvm_preempt_ops.sched_in = kvm_sched_in;
+       kvm_preempt_ops.sched_out = kvm_sched_out;
+
        return r;
 
 out_free:
+       kmem_cache_destroy(kvm_vcpu_cache);
+out_free_4:
        sysdev_unregister(&kvm_sysdev);
 out_free_3:
        sysdev_class_unregister(&kvm_sysdev_class);
@@ -3190,6 +3179,7 @@ out_free_2:
        unregister_cpu_notifier(&kvm_cpu_notifier);
 out_free_1:
        on_each_cpu(hardware_disable, NULL, 0, 1);
+out_free_0:
        kvm_arch_ops->hardware_unsetup();
 out:
        kvm_arch_ops = NULL;
@@ -3199,6 +3189,7 @@ out:
 void kvm_exit_arch(void)
 {
        misc_deregister(&kvm_dev);
+       kmem_cache_destroy(kvm_vcpu_cache);
        sysdev_unregister(&kvm_sysdev);
        sysdev_class_unregister(&kvm_sysdev_class);
        unregister_reboot_notifier(&kvm_reboot_notifier);