KVM: Make unloading of FPU state when putting vcpu arch-independent
[pandora-kernel.git] / drivers / kvm / vmx.c
index cd999c0..0c082fa 100644 (file)
@@ -16,7 +16,9 @@
  */
 
 #include "kvm.h"
+#include "x86.h"
 #include "x86_emulate.h"
+#include "irq.h"
 #include "vmx.h"
 #include "segment_descriptor.h"
 
@@ -24,8 +26,8 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/highmem.h>
-#include <linux/profile.h>
 #include <linux/sched.h>
+#include <linux/moduleparam.h>
 
 #include <asm/io.h>
 #include <asm/desc.h>
@@ -33,6 +35,9 @@
 MODULE_AUTHOR("Qumranet");
 MODULE_LICENSE("GPL");
 
+static int bypass_guest_pf = 1;
+module_param(bypass_guest_pf, bool, 0);
+
 struct vmcs {
        u32 revision_id;
        u32 abort;
@@ -42,6 +47,8 @@ struct vmcs {
 struct vcpu_vmx {
        struct kvm_vcpu       vcpu;
        int                   launched;
+       u8                    fail;
+       u32                   idt_vectoring_info;
        struct kvm_msr_entry *guest_msrs;
        struct kvm_msr_entry *host_msrs;
        int                   nmsrs;
@@ -54,9 +61,17 @@ struct vcpu_vmx {
        struct {
                int           loaded;
                u16           fs_sel, gs_sel, ldt_sel;
-               int           fs_gs_ldt_reload_needed;
-       }host_state;
-
+               int           gs_ldt_reload_needed;
+               int           fs_reload_needed;
+               int           guest_efer_loaded;
+       } host_state;
+       struct {
+               struct {
+                       bool pending;
+                       u8 vector;
+                       unsigned rip;
+               } irq;
+       } rmode;
 };
 
 static inline struct vcpu_vmx *to_vmx(struct kvm_vcpu *vcpu)
@@ -72,14 +87,13 @@ static DEFINE_PER_CPU(struct vmcs *, current_vmcs);
 static struct page *vmx_io_bitmap_a;
 static struct page *vmx_io_bitmap_b;
 
-#define EFER_SAVE_RESTORE_BITS ((u64)EFER_SCE)
-
 static struct vmcs_config {
        int size;
        int order;
        u32 revision_id;
        u32 pin_based_exec_ctrl;
        u32 cpu_based_exec_ctrl;
+       u32 cpu_based_2nd_exec_ctrl;
        u32 vmexit_ctrl;
        u32 vmentry_ctrl;
 } vmcs_config;
@@ -136,18 +150,6 @@ static void save_msrs(struct kvm_msr_entry *e, int n)
                rdmsrl(e[i].index, e[i].data);
 }
 
-static inline u64 msr_efer_save_restore_bits(struct kvm_msr_entry msr)
-{
-       return (u64)msr.data & EFER_SAVE_RESTORE_BITS;
-}
-
-static inline int msr_efer_need_save_restore(struct vcpu_vmx *vmx)
-{
-       int efer_offset = vmx->msr_offset_efer;
-       return msr_efer_save_restore_bits(vmx->host_msrs[efer_offset]) !=
-               msr_efer_save_restore_bits(vmx->guest_msrs[efer_offset]);
-}
-
 static inline int is_page_fault(u32 intr_info)
 {
        return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK |
@@ -162,12 +164,52 @@ static inline int is_no_device(u32 intr_info)
                (INTR_TYPE_EXCEPTION | NM_VECTOR | INTR_INFO_VALID_MASK);
 }
 
+static inline int is_invalid_opcode(u32 intr_info)
+{
+       return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK |
+                            INTR_INFO_VALID_MASK)) ==
+               (INTR_TYPE_EXCEPTION | UD_VECTOR | INTR_INFO_VALID_MASK);
+}
+
 static inline int is_external_interrupt(u32 intr_info)
 {
        return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VALID_MASK))
                == (INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK);
 }
 
+static inline int cpu_has_vmx_tpr_shadow(void)
+{
+       return (vmcs_config.cpu_based_exec_ctrl & CPU_BASED_TPR_SHADOW);
+}
+
+static inline int vm_need_tpr_shadow(struct kvm *kvm)
+{
+       return ((cpu_has_vmx_tpr_shadow()) && (irqchip_in_kernel(kvm)));
+}
+
+static inline int cpu_has_secondary_exec_ctrls(void)
+{
+       return (vmcs_config.cpu_based_exec_ctrl &
+               CPU_BASED_ACTIVATE_SECONDARY_CONTROLS);
+}
+
+static inline int vm_need_secondary_exec_ctrls(struct kvm *kvm)
+{
+       return ((cpu_has_secondary_exec_ctrls()) && (irqchip_in_kernel(kvm)));
+}
+
+static inline int cpu_has_vmx_virtualize_apic_accesses(void)
+{
+       return (vmcs_config.cpu_based_2nd_exec_ctrl &
+               SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES);
+}
+
+static inline int vm_need_virtualize_apic_accesses(struct kvm *kvm)
+{
+       return ((cpu_has_vmx_virtualize_apic_accesses()) &&
+               (irqchip_in_kernel(kvm)));
+}
+
 static int __find_msr_index(struct vcpu_vmx *vmx, u32 msr)
 {
        int i;
@@ -215,11 +257,9 @@ static void __vcpu_clear(void *arg)
 
 static void vcpu_clear(struct vcpu_vmx *vmx)
 {
-       if (vmx->vcpu.cpu != raw_smp_processor_id() && vmx->vcpu.cpu != -1)
-               smp_call_function_single(vmx->vcpu.cpu, __vcpu_clear,
-                                        vmx, 0, 1);
-       else
-               __vcpu_clear(vmx);
+       if (vmx->vcpu.cpu == -1)
+               return;
+       smp_call_function_single(vmx->vcpu.cpu, __vcpu_clear, vmx, 0, 1);
        vmx->launched = 0;
 }
 
@@ -263,7 +303,7 @@ static void vmcs_writel(unsigned long field, unsigned long value)
        u8 error;
 
        asm volatile (ASM_VMX_VMWRITE_RAX_RDX "; setna %0"
-                      : "=q"(error) : "a"(value), "d"(field) : "cc" );
+                      : "=q"(error) : "a"(value), "d"(field) : "cc");
        if (unlikely(error))
                vmwrite_error(field, value);
 }
@@ -303,7 +343,7 @@ static void update_exception_bitmap(struct kvm_vcpu *vcpu)
 {
        u32 eb;
 
-       eb = 1u << PF_VECTOR;
+       eb = (1u << PF_VECTOR) | (1u << UD_VECTOR);
        if (!vcpu->fpu_active)
                eb |= 1u << NM_VECTOR;
        if (vcpu->guest_debug.enabled)
@@ -332,18 +372,46 @@ static void reload_tss(void)
 
 static void load_transition_efer(struct vcpu_vmx *vmx)
 {
-       u64 trans_efer;
        int efer_offset = vmx->msr_offset_efer;
+       u64 host_efer = vmx->host_msrs[efer_offset].data;
+       u64 guest_efer = vmx->guest_msrs[efer_offset].data;
+       u64 ignore_bits;
 
-       trans_efer = vmx->host_msrs[efer_offset].data;
-       trans_efer &= ~EFER_SAVE_RESTORE_BITS;
-       trans_efer |= msr_efer_save_restore_bits(vmx->guest_msrs[efer_offset]);
-       wrmsrl(MSR_EFER, trans_efer);
+       if (efer_offset < 0)
+               return;
+       /*
+        * NX is emulated; LMA and LME handled by hardware; SCE meaninless
+        * outside long mode
+        */
+       ignore_bits = EFER_NX | EFER_SCE;
+#ifdef CONFIG_X86_64
+       ignore_bits |= EFER_LMA | EFER_LME;
+       /* SCE is meaningful only in long mode on Intel */
+       if (guest_efer & EFER_LMA)
+               ignore_bits &= ~(u64)EFER_SCE;
+#endif
+       if ((guest_efer & ~ignore_bits) == (host_efer & ~ignore_bits))
+               return;
+
+       vmx->host_state.guest_efer_loaded = 1;
+       guest_efer &= ~ignore_bits;
+       guest_efer |= host_efer & ignore_bits;
+       wrmsrl(MSR_EFER, guest_efer);
        vmx->vcpu.stat.efer_reload++;
 }
 
-static void vmx_save_host_state(struct vcpu_vmx *vmx)
+static void reload_host_efer(struct vcpu_vmx *vmx)
+{
+       if (vmx->host_state.guest_efer_loaded) {
+               vmx->host_state.guest_efer_loaded = 0;
+               load_msrs(vmx->host_msrs + vmx->msr_offset_efer, 1);
+       }
+}
+
+static void vmx_save_host_state(struct kvm_vcpu *vcpu)
 {
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
+
        if (vmx->host_state.loaded)
                return;
 
@@ -353,20 +421,21 @@ static void vmx_save_host_state(struct vcpu_vmx *vmx)
         * allow segment selectors with cpl > 0 or ti == 1.
         */
        vmx->host_state.ldt_sel = read_ldt();
-       vmx->host_state.fs_gs_ldt_reload_needed = vmx->host_state.ldt_sel;
+       vmx->host_state.gs_ldt_reload_needed = vmx->host_state.ldt_sel;
        vmx->host_state.fs_sel = read_fs();
-       if (!(vmx->host_state.fs_sel & 7))
+       if (!(vmx->host_state.fs_sel & 7)) {
                vmcs_write16(HOST_FS_SELECTOR, vmx->host_state.fs_sel);
-       else {
+               vmx->host_state.fs_reload_needed = 0;
+       } else {
                vmcs_write16(HOST_FS_SELECTOR, 0);
-               vmx->host_state.fs_gs_ldt_reload_needed = 1;
+               vmx->host_state.fs_reload_needed = 1;
        }
        vmx->host_state.gs_sel = read_gs();
        if (!(vmx->host_state.gs_sel & 7))
                vmcs_write16(HOST_GS_SELECTOR, vmx->host_state.gs_sel);
        else {
                vmcs_write16(HOST_GS_SELECTOR, 0);
-               vmx->host_state.fs_gs_ldt_reload_needed = 1;
+               vmx->host_state.gs_ldt_reload_needed = 1;
        }
 
 #ifdef CONFIG_X86_64
@@ -378,14 +447,13 @@ static void vmx_save_host_state(struct vcpu_vmx *vmx)
 #endif
 
 #ifdef CONFIG_X86_64
-       if (is_long_mode(&vmx->vcpu)) {
+       if (is_long_mode(&vmx->vcpu))
                save_msrs(vmx->host_msrs +
                          vmx->msr_offset_kernel_gs_base, 1);
-       }
+
 #endif
        load_msrs(vmx->guest_msrs, vmx->save_nmsrs);
-       if (msr_efer_need_save_restore(vmx))
-               load_transition_efer(vmx);
+       load_transition_efer(vmx);
 }
 
 static void vmx_load_host_state(struct vcpu_vmx *vmx)
@@ -395,10 +463,12 @@ static void vmx_load_host_state(struct vcpu_vmx *vmx)
        if (!vmx->host_state.loaded)
                return;
 
+       ++vmx->vcpu.stat.host_state_reload;
        vmx->host_state.loaded = 0;
-       if (vmx->host_state.fs_gs_ldt_reload_needed) {
-               load_ldt(vmx->host_state.ldt_sel);
+       if (vmx->host_state.fs_reload_needed)
                load_fs(vmx->host_state.fs_sel);
+       if (vmx->host_state.gs_ldt_reload_needed) {
+               load_ldt(vmx->host_state.ldt_sel);
                /*
                 * If we have to reload gs, we must take care to
                 * preserve our gs base.
@@ -409,13 +479,11 @@ static void vmx_load_host_state(struct vcpu_vmx *vmx)
                wrmsrl(MSR_GS_BASE, vmcs_readl(HOST_GS_BASE));
 #endif
                local_irq_restore(flags);
-
-               reload_tss();
        }
+       reload_tss();
        save_msrs(vmx->guest_msrs, vmx->save_nmsrs);
        load_msrs(vmx->host_msrs, vmx->save_nmsrs);
-       if (msr_efer_need_save_restore(vmx))
-               load_msrs(vmx->host_msrs + vmx->msr_offset_efer, 1);
+       reload_host_efer(vmx);
 }
 
 /*
@@ -428,8 +496,10 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
        u64 phys_addr = __pa(vmx->vmcs);
        u64 tsc_this, delta;
 
-       if (vcpu->cpu != cpu)
+       if (vcpu->cpu != cpu) {
                vcpu_clear(vmx);
+               kvm_migrate_apic_timer(vcpu);
+       }
 
        if (per_cpu(current_vmcs, cpu) != vmx->vmcs) {
                u8 error;
@@ -471,7 +541,6 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 static void vmx_vcpu_put(struct kvm_vcpu *vcpu)
 {
        vmx_load_host_state(to_vmx(vcpu));
-       kvm_put_guest_fpu(vcpu);
 }
 
 static void vmx_fpu_activate(struct kvm_vcpu *vcpu)
@@ -506,6 +575,8 @@ static unsigned long vmx_get_rflags(struct kvm_vcpu *vcpu)
 
 static void vmx_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
 {
+       if (vcpu->rmode.active)
+               rflags |= X86_EFLAGS_IOPL | X86_EFLAGS_VM;
        vmcs_writel(GUEST_RFLAGS, rflags);
 }
 
@@ -541,6 +612,14 @@ static void vmx_inject_gp(struct kvm_vcpu *vcpu, unsigned error_code)
                     INTR_INFO_VALID_MASK);
 }
 
+static void vmx_inject_ud(struct kvm_vcpu *vcpu)
+{
+       vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
+                    UD_VECTOR |
+                    INTR_TYPE_EXCEPTION |
+                    INTR_INFO_VALID_MASK);
+}
+
 /*
  * Swap MSR entry in host/guest MSR entry array.
  */
@@ -693,8 +772,10 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
 #ifdef CONFIG_X86_64
        case MSR_EFER:
                ret = kvm_set_msr_common(vcpu, msr_index, data);
-               if (vmx->host_state.loaded)
+               if (vmx->host_state.loaded) {
+                       reload_host_efer(vmx);
                        load_transition_efer(vmx);
+               }
                break;
        case MSR_FS_BASE:
                vmcs_writel(GUEST_FS_BASE, data);
@@ -787,6 +868,21 @@ static int set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg)
        return 0;
 }
 
+static int vmx_get_irq(struct kvm_vcpu *vcpu)
+{
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
+       u32 idtv_info_field;
+
+       idtv_info_field = vmx->idt_vectoring_info;
+       if (idtv_info_field & INTR_INFO_VALID_MASK) {
+               if (is_external_interrupt(idtv_info_field))
+                       return idtv_info_field & VECTORING_INFO_VECTOR_MASK;
+               else
+                       printk(KERN_DEBUG "pending exception: not handled yet\n");
+       }
+       return -1;
+}
+
 static __init int cpu_has_kvm_support(void)
 {
        unsigned long ecx = cpuid_ecx(1);
@@ -830,7 +926,7 @@ static void hardware_disable(void *garbage)
 }
 
 static __init int adjust_vmx_controls(u32 ctl_min, u32 ctl_opt,
-                                     u32 msr, u32result)
+                                     u32 msr, u32 *result)
 {
        u32 vmx_msr_low, vmx_msr_high;
        u32 ctl = ctl_min | ctl_opt;
@@ -854,6 +950,7 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf)
        u32 min, opt;
        u32 _pin_based_exec_control = 0;
        u32 _cpu_based_exec_control = 0;
+       u32 _cpu_based_2nd_exec_control = 0;
        u32 _vmexit_control = 0;
        u32 _vmentry_control = 0;
 
@@ -871,10 +968,29 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf)
              CPU_BASED_USE_IO_BITMAPS |
              CPU_BASED_MOV_DR_EXITING |
              CPU_BASED_USE_TSC_OFFSETING;
-       opt = 0;
+       opt = CPU_BASED_TPR_SHADOW |
+             CPU_BASED_ACTIVATE_SECONDARY_CONTROLS;
        if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PROCBASED_CTLS,
                                &_cpu_based_exec_control) < 0)
                return -EIO;
+#ifdef CONFIG_X86_64
+       if ((_cpu_based_exec_control & CPU_BASED_TPR_SHADOW))
+               _cpu_based_exec_control &= ~CPU_BASED_CR8_LOAD_EXITING &
+                                          ~CPU_BASED_CR8_STORE_EXITING;
+#endif
+       if (_cpu_based_exec_control & CPU_BASED_ACTIVATE_SECONDARY_CONTROLS) {
+               min = 0;
+               opt = SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES |
+                       SECONDARY_EXEC_WBINVD_EXITING;
+               if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PROCBASED_CTLS2,
+                                       &_cpu_based_2nd_exec_control) < 0)
+                       return -EIO;
+       }
+#ifndef CONFIG_X86_64
+       if (!(_cpu_based_2nd_exec_control &
+                               SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES))
+               _cpu_based_exec_control &= ~CPU_BASED_TPR_SHADOW;
+#endif
 
        min = 0;
 #ifdef CONFIG_X86_64
@@ -912,6 +1028,7 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf)
 
        vmcs_conf->pin_based_exec_ctrl = _pin_based_exec_control;
        vmcs_conf->cpu_based_exec_ctrl = _cpu_based_exec_control;
+       vmcs_conf->cpu_based_2nd_exec_ctrl = _cpu_based_2nd_exec_control;
        vmcs_conf->vmexit_ctrl         = _vmexit_control;
        vmcs_conf->vmentry_ctrl        = _vmentry_control;
 
@@ -1008,7 +1125,7 @@ static void enter_pmode(struct kvm_vcpu *vcpu)
        vmcs_write32(GUEST_TR_AR_BYTES, vcpu->rmode.tr.ar);
 
        flags = vmcs_readl(GUEST_RFLAGS);
-       flags &= ~(IOPL_MASK | X86_EFLAGS_VM);
+       flags &= ~(X86_EFLAGS_IOPL | X86_EFLAGS_VM);
        flags |= (vcpu->rmode.save_iopl << IOPL_SHIFT);
        vmcs_writel(GUEST_RFLAGS, flags);
 
@@ -1030,10 +1147,14 @@ static void enter_pmode(struct kvm_vcpu *vcpu)
        vmcs_write32(GUEST_CS_AR_BYTES, 0x9b);
 }
 
-static int rmode_tss_base(struct kvm* kvm)
+static gva_t rmode_tss_base(struct kvm *kvm)
 {
-       gfn_t base_gfn = kvm->memslots[0].base_gfn + kvm->memslots[0].npages - 3;
-       return base_gfn << PAGE_SHIFT;
+       if (!kvm->tss_addr) {
+               gfn_t base_gfn = kvm->memslots[0].base_gfn +
+                                kvm->memslots[0].npages - 3;
+               return base_gfn << PAGE_SHIFT;
+       }
+       return kvm->tss_addr;
 }
 
 static void fix_rmode_seg(int seg, struct kvm_save_segment *save)
@@ -1065,9 +1186,9 @@ static void enter_rmode(struct kvm_vcpu *vcpu)
        vmcs_write32(GUEST_TR_AR_BYTES, 0x008b);
 
        flags = vmcs_readl(GUEST_RFLAGS);
-       vcpu->rmode.save_iopl = (flags & IOPL_MASK) >> IOPL_SHIFT;
+       vcpu->rmode.save_iopl = (flags & X86_EFLAGS_IOPL) >> IOPL_SHIFT;
 
-       flags |= IOPL_MASK | X86_EFLAGS_VM;
+       flags |= X86_EFLAGS_IOPL | X86_EFLAGS_VM;
 
        vmcs_writel(GUEST_RFLAGS, flags);
        vmcs_writel(GUEST_CR4, vmcs_readl(GUEST_CR4) | X86_CR4_VME);
@@ -1088,6 +1209,7 @@ static void enter_rmode(struct kvm_vcpu *vcpu)
        fix_rmode_seg(VCPU_SREG_GS, &vcpu->rmode.gs);
        fix_rmode_seg(VCPU_SREG_FS, &vcpu->rmode.fs);
 
+       kvm_mmu_reset_context(vcpu);
        init_rmode_tss(vcpu->kvm);
 }
 
@@ -1312,35 +1434,30 @@ static void vmx_set_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
        vmcs_writel(GUEST_GDTR_BASE, dt->base);
 }
 
-static int init_rmode_tss(struct kvmkvm)
+static int init_rmode_tss(struct kvm *kvm)
 {
-       struct page *p1, *p2, *p3;
        gfn_t fn = rmode_tss_base(kvm) >> PAGE_SHIFT;
-       char *page;
-
-       p1 = gfn_to_page(kvm, fn++);
-       p2 = gfn_to_page(kvm, fn++);
-       p3 = gfn_to_page(kvm, fn);
+       u16 data = 0;
+       int r;
 
-       if (!p1 || !p2 || !p3) {
-               kvm_printf(kvm,"%s: gfn_to_page failed\n", __FUNCTION__);
+       r = kvm_clear_guest_page(kvm, fn, 0, PAGE_SIZE);
+       if (r < 0)
+               return 0;
+       data = TSS_BASE_SIZE + TSS_REDIRECTION_SIZE;
+       r = kvm_write_guest_page(kvm, fn++, &data, 0x66, sizeof(u16));
+       if (r < 0)
+               return 0;
+       r = kvm_clear_guest_page(kvm, fn++, 0, PAGE_SIZE);
+       if (r < 0)
+               return 0;
+       r = kvm_clear_guest_page(kvm, fn, 0, PAGE_SIZE);
+       if (r < 0)
+               return 0;
+       data = ~0;
+       r = kvm_write_guest_page(kvm, fn, &data, RMODE_TSS_SIZE - 2 * PAGE_SIZE - 1,
+                       sizeof(u8));
+       if (r < 0)
                return 0;
-       }
-
-       page = kmap_atomic(p1, KM_USER0);
-       clear_page(page);
-       *(u16*)(page + 0x66) = TSS_BASE_SIZE + TSS_REDIRECTION_SIZE;
-       kunmap_atomic(page, KM_USER0);
-
-       page = kmap_atomic(p2, KM_USER0);
-       clear_page(page);
-       kunmap_atomic(page, KM_USER0);
-
-       page = kmap_atomic(p3, KM_USER0);
-       clear_page(page);
-       *(page + RMODE_TSS_SIZE - 2 * PAGE_SIZE - 1) = ~0;
-       kunmap_atomic(page, KM_USER0);
-
        return 1;
 }
 
@@ -1354,6 +1471,27 @@ static void seg_setup(int seg)
        vmcs_write32(sf->ar_bytes, 0x93);
 }
 
+static int alloc_apic_access_page(struct kvm *kvm)
+{
+       struct kvm_userspace_memory_region kvm_userspace_mem;
+       int r = 0;
+
+       mutex_lock(&kvm->lock);
+       if (kvm->apic_access_page)
+               goto out;
+       kvm_userspace_mem.slot = APIC_ACCESS_PAGE_PRIVATE_MEMSLOT;
+       kvm_userspace_mem.flags = 0;
+       kvm_userspace_mem.guest_phys_addr = 0xfee00000ULL;
+       kvm_userspace_mem.memory_size = PAGE_SIZE;
+       r = __kvm_set_memory_region(kvm, &kvm_userspace_mem, 0);
+       if (r)
+               goto out;
+       kvm->apic_access_page = gfn_to_page(kvm, 0xfee00);
+out:
+       mutex_unlock(&kvm->lock);
+       return r;
+}
+
 /*
  * Sets up the vmcs for emulated real mode.
  */
@@ -1364,87 +1502,37 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
        unsigned long a;
        struct descriptor_table dt;
        int i;
-       int ret = 0;
        unsigned long kvm_vmx_return;
-
-       if (!init_rmode_tss(vmx->vcpu.kvm)) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       vmx->vcpu.regs[VCPU_REGS_RDX] = get_rdx_init_val();
-       vmx->vcpu.cr8 = 0;
-       vmx->vcpu.apic_base = 0xfee00000 | MSR_IA32_APICBASE_ENABLE;
-       if (vmx->vcpu.vcpu_id == 0)
-               vmx->vcpu.apic_base |= MSR_IA32_APICBASE_BSP;
-
-       fx_init(&vmx->vcpu);
-
-       /*
-        * GUEST_CS_BASE should really be 0xffff0000, but VT vm86 mode
-        * insists on having GUEST_CS_BASE == GUEST_CS_SELECTOR << 4.  Sigh.
-        */
-       vmcs_write16(GUEST_CS_SELECTOR, 0xf000);
-       vmcs_writel(GUEST_CS_BASE, 0x000f0000);
-       vmcs_write32(GUEST_CS_LIMIT, 0xffff);
-       vmcs_write32(GUEST_CS_AR_BYTES, 0x9b);
-
-       seg_setup(VCPU_SREG_DS);
-       seg_setup(VCPU_SREG_ES);
-       seg_setup(VCPU_SREG_FS);
-       seg_setup(VCPU_SREG_GS);
-       seg_setup(VCPU_SREG_SS);
-
-       vmcs_write16(GUEST_TR_SELECTOR, 0);
-       vmcs_writel(GUEST_TR_BASE, 0);
-       vmcs_write32(GUEST_TR_LIMIT, 0xffff);
-       vmcs_write32(GUEST_TR_AR_BYTES, 0x008b);
-
-       vmcs_write16(GUEST_LDTR_SELECTOR, 0);
-       vmcs_writel(GUEST_LDTR_BASE, 0);
-       vmcs_write32(GUEST_LDTR_LIMIT, 0xffff);
-       vmcs_write32(GUEST_LDTR_AR_BYTES, 0x00082);
-
-       vmcs_write32(GUEST_SYSENTER_CS, 0);
-       vmcs_writel(GUEST_SYSENTER_ESP, 0);
-       vmcs_writel(GUEST_SYSENTER_EIP, 0);
-
-       vmcs_writel(GUEST_RFLAGS, 0x02);
-       vmcs_writel(GUEST_RIP, 0xfff0);
-       vmcs_writel(GUEST_RSP, 0);
-
-       //todo: dr0 = dr1 = dr2 = dr3 = 0; dr6 = 0xffff0ff0
-       vmcs_writel(GUEST_DR7, 0x400);
-
-       vmcs_writel(GUEST_GDTR_BASE, 0);
-       vmcs_write32(GUEST_GDTR_LIMIT, 0xffff);
-
-       vmcs_writel(GUEST_IDTR_BASE, 0);
-       vmcs_write32(GUEST_IDTR_LIMIT, 0xffff);
-
-       vmcs_write32(GUEST_ACTIVITY_STATE, 0);
-       vmcs_write32(GUEST_INTERRUPTIBILITY_INFO, 0);
-       vmcs_write32(GUEST_PENDING_DBG_EXCEPTIONS, 0);
+       u32 exec_control;
 
        /* I/O */
        vmcs_write64(IO_BITMAP_A, page_to_phys(vmx_io_bitmap_a));
        vmcs_write64(IO_BITMAP_B, page_to_phys(vmx_io_bitmap_b));
 
-       guest_write_tsc(0);
-
        vmcs_write64(VMCS_LINK_POINTER, -1ull); /* 22.3.1.5 */
 
-       /* Special registers */
-       vmcs_write64(GUEST_IA32_DEBUGCTL, 0);
-
        /* Control */
        vmcs_write32(PIN_BASED_VM_EXEC_CONTROL,
                vmcs_config.pin_based_exec_ctrl);
-       vmcs_write32(CPU_BASED_VM_EXEC_CONTROL,
-               vmcs_config.cpu_based_exec_ctrl);
 
-       vmcs_write32(PAGE_FAULT_ERROR_CODE_MASK, 0);
-       vmcs_write32(PAGE_FAULT_ERROR_CODE_MATCH, 0);
+       exec_control = vmcs_config.cpu_based_exec_ctrl;
+       if (!vm_need_tpr_shadow(vmx->vcpu.kvm)) {
+               exec_control &= ~CPU_BASED_TPR_SHADOW;
+#ifdef CONFIG_X86_64
+               exec_control |= CPU_BASED_CR8_STORE_EXITING |
+                               CPU_BASED_CR8_LOAD_EXITING;
+#endif
+       }
+       if (!vm_need_secondary_exec_ctrls(vmx->vcpu.kvm))
+               exec_control &= ~CPU_BASED_ACTIVATE_SECONDARY_CONTROLS;
+       vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, exec_control);
+
+       if (vm_need_secondary_exec_ctrls(vmx->vcpu.kvm))
+               vmcs_write32(SECONDARY_VM_EXEC_CONTROL,
+                            vmcs_config.cpu_based_2nd_exec_ctrl);
+
+       vmcs_write32(PAGE_FAULT_ERROR_CODE_MASK, !!bypass_guest_pf);
+       vmcs_write32(PAGE_FAULT_ERROR_CODE_MATCH, !!bypass_guest_pf);
        vmcs_write32(CR3_TARGET_COUNT, 0);           /* 22.2.1 */
 
        vmcs_writel(HOST_CR0, read_cr0());  /* 22.2.3 */
@@ -1472,7 +1560,7 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
        get_idt(&dt);
        vmcs_writel(HOST_IDTR_BASE, dt.base);   /* 22.2.4 */
 
-       asm ("mov $.Lkvm_vmx_return, %0" : "=r"(kvm_vmx_return));
+       asm("mov $.Lkvm_vmx_return, %0" : "=r"(kvm_vmx_return));
        vmcs_writel(HOST_RIP, kvm_vmx_return); /* 22.2.5 */
        vmcs_write32(VM_EXIT_MSR_STORE_COUNT, 0);
        vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, 0);
@@ -1503,25 +1591,120 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
                ++vmx->nmsrs;
        }
 
-       setup_msrs(vmx);
-
        vmcs_write32(VM_EXIT_CONTROLS, vmcs_config.vmexit_ctrl);
 
        /* 22.2.1, 20.8.1 */
        vmcs_write32(VM_ENTRY_CONTROLS, vmcs_config.vmentry_ctrl);
 
+       vmcs_writel(CR0_GUEST_HOST_MASK, ~0UL);
+       vmcs_writel(CR4_GUEST_HOST_MASK, KVM_GUEST_CR4_MASK);
+
+       if (vm_need_virtualize_apic_accesses(vmx->vcpu.kvm))
+               if (alloc_apic_access_page(vmx->vcpu.kvm) != 0)
+                       return -ENOMEM;
+
+       return 0;
+}
+
+static int vmx_vcpu_reset(struct kvm_vcpu *vcpu)
+{
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
+       u64 msr;
+       int ret;
+
+       if (!init_rmode_tss(vmx->vcpu.kvm)) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       vmx->vcpu.rmode.active = 0;
+
+       vmx->vcpu.regs[VCPU_REGS_RDX] = get_rdx_init_val();
+       set_cr8(&vmx->vcpu, 0);
+       msr = 0xfee00000 | MSR_IA32_APICBASE_ENABLE;
+       if (vmx->vcpu.vcpu_id == 0)
+               msr |= MSR_IA32_APICBASE_BSP;
+       kvm_set_apic_base(&vmx->vcpu, msr);
+
+       fx_init(&vmx->vcpu);
+
+       /*
+        * GUEST_CS_BASE should really be 0xffff0000, but VT vm86 mode
+        * insists on having GUEST_CS_BASE == GUEST_CS_SELECTOR << 4.  Sigh.
+        */
+       if (vmx->vcpu.vcpu_id == 0) {
+               vmcs_write16(GUEST_CS_SELECTOR, 0xf000);
+               vmcs_writel(GUEST_CS_BASE, 0x000f0000);
+       } else {
+               vmcs_write16(GUEST_CS_SELECTOR, vmx->vcpu.sipi_vector << 8);
+               vmcs_writel(GUEST_CS_BASE, vmx->vcpu.sipi_vector << 12);
+       }
+       vmcs_write32(GUEST_CS_LIMIT, 0xffff);
+       vmcs_write32(GUEST_CS_AR_BYTES, 0x9b);
+
+       seg_setup(VCPU_SREG_DS);
+       seg_setup(VCPU_SREG_ES);
+       seg_setup(VCPU_SREG_FS);
+       seg_setup(VCPU_SREG_GS);
+       seg_setup(VCPU_SREG_SS);
+
+       vmcs_write16(GUEST_TR_SELECTOR, 0);
+       vmcs_writel(GUEST_TR_BASE, 0);
+       vmcs_write32(GUEST_TR_LIMIT, 0xffff);
+       vmcs_write32(GUEST_TR_AR_BYTES, 0x008b);
+
+       vmcs_write16(GUEST_LDTR_SELECTOR, 0);
+       vmcs_writel(GUEST_LDTR_BASE, 0);
+       vmcs_write32(GUEST_LDTR_LIMIT, 0xffff);
+       vmcs_write32(GUEST_LDTR_AR_BYTES, 0x00082);
+
+       vmcs_write32(GUEST_SYSENTER_CS, 0);
+       vmcs_writel(GUEST_SYSENTER_ESP, 0);
+       vmcs_writel(GUEST_SYSENTER_EIP, 0);
+
+       vmcs_writel(GUEST_RFLAGS, 0x02);
+       if (vmx->vcpu.vcpu_id == 0)
+               vmcs_writel(GUEST_RIP, 0xfff0);
+       else
+               vmcs_writel(GUEST_RIP, 0);
+       vmcs_writel(GUEST_RSP, 0);
+
+       /* todo: dr0 = dr1 = dr2 = dr3 = 0; dr6 = 0xffff0ff0 */
+       vmcs_writel(GUEST_DR7, 0x400);
+
+       vmcs_writel(GUEST_GDTR_BASE, 0);
+       vmcs_write32(GUEST_GDTR_LIMIT, 0xffff);
+
+       vmcs_writel(GUEST_IDTR_BASE, 0);
+       vmcs_write32(GUEST_IDTR_LIMIT, 0xffff);
+
+       vmcs_write32(GUEST_ACTIVITY_STATE, 0);
+       vmcs_write32(GUEST_INTERRUPTIBILITY_INFO, 0);
+       vmcs_write32(GUEST_PENDING_DBG_EXCEPTIONS, 0);
+
+       guest_write_tsc(0);
+
+       /* Special registers */
+       vmcs_write64(GUEST_IA32_DEBUGCTL, 0);
+
+       setup_msrs(vmx);
+
        vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, 0);  /* 22.2.1 */
 
-#ifdef CONFIG_X86_64
-       vmcs_writel(VIRTUAL_APIC_PAGE_ADDR, 0);
-       vmcs_writel(TPR_THRESHOLD, 0);
-#endif
+       if (cpu_has_vmx_tpr_shadow()) {
+               vmcs_write64(VIRTUAL_APIC_PAGE_ADDR, 0);
+               if (vm_need_tpr_shadow(vmx->vcpu.kvm))
+                       vmcs_write64(VIRTUAL_APIC_PAGE_ADDR,
+                                    page_to_phys(vmx->vcpu.apic->regs_page));
+               vmcs_write32(TPR_THRESHOLD, 0);
+       }
 
-       vmcs_writel(CR0_GUEST_HOST_MASK, ~0UL);
-       vmcs_writel(CR4_GUEST_HOST_MASK, KVM_GUEST_CR4_MASK);
+       if (vm_need_virtualize_apic_accesses(vmx->vcpu.kvm))
+               vmcs_write64(APIC_ACCESS_ADDR,
+                            page_to_phys(vmx->vcpu.kvm->apic_access_page));
 
        vmx->vcpu.cr0 = 0x60000010;
-       vmx_set_cr0(&vmx->vcpu, vmx->vcpu.cr0); // enter rmode
+       vmx_set_cr0(&vmx->vcpu, vmx->vcpu.cr0); /* enter rmode */
        vmx_set_cr4(&vmx->vcpu, 0);
 #ifdef CONFIG_X86_64
        vmx_set_efer(&vmx->vcpu, 0);
@@ -1535,49 +1718,22 @@ out:
        return ret;
 }
 
-static void inject_rmode_irq(struct kvm_vcpu *vcpu, int irq)
+static void vmx_inject_irq(struct kvm_vcpu *vcpu, int irq)
 {
-       u16 ent[2];
-       u16 cs;
-       u16 ip;
-       unsigned long flags;
-       unsigned long ss_base = vmcs_readl(GUEST_SS_BASE);
-       u16 sp =  vmcs_readl(GUEST_RSP);
-       u32 ss_limit = vmcs_read32(GUEST_SS_LIMIT);
-
-       if (sp > ss_limit || sp < 6 ) {
-               vcpu_printf(vcpu, "%s: #SS, rsp 0x%lx ss 0x%lx limit 0x%x\n",
-                           __FUNCTION__,
-                           vmcs_readl(GUEST_RSP),
-                           vmcs_readl(GUEST_SS_BASE),
-                           vmcs_read32(GUEST_SS_LIMIT));
-               return;
-       }
-
-       if (emulator_read_std(irq * sizeof(ent), &ent, sizeof(ent), vcpu) !=
-                                                       X86EMUL_CONTINUE) {
-               vcpu_printf(vcpu, "%s: read guest err\n", __FUNCTION__);
-               return;
-       }
-
-       flags =  vmcs_readl(GUEST_RFLAGS);
-       cs =  vmcs_readl(GUEST_CS_BASE) >> 4;
-       ip =  vmcs_readl(GUEST_RIP);
-
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
 
-       if (emulator_write_emulated(ss_base + sp - 2, &flags, 2, vcpu) != X86EMUL_CONTINUE ||
-           emulator_write_emulated(ss_base + sp - 4, &cs, 2, vcpu) != X86EMUL_CONTINUE ||
-           emulator_write_emulated(ss_base + sp - 6, &ip, 2, vcpu) != X86EMUL_CONTINUE) {
-               vcpu_printf(vcpu, "%s: write guest err\n", __FUNCTION__);
+       if (vcpu->rmode.active) {
+               vmx->rmode.irq.pending = true;
+               vmx->rmode.irq.vector = irq;
+               vmx->rmode.irq.rip = vmcs_readl(GUEST_RIP);
+               vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
+                            irq | INTR_TYPE_SOFT_INTR | INTR_INFO_VALID_MASK);
+               vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, 1);
+               vmcs_writel(GUEST_RIP, vmx->rmode.irq.rip - 1);
                return;
        }
-
-       vmcs_writel(GUEST_RFLAGS, flags &
-                   ~( X86_EFLAGS_IF | X86_EFLAGS_AC | X86_EFLAGS_TF));
-       vmcs_write16(GUEST_CS_SELECTOR, ent[1]) ;
-       vmcs_writel(GUEST_CS_BASE, ent[1] << 4);
-       vmcs_writel(GUEST_RIP, ent[0]);
-       vmcs_writel(GUEST_RSP, (vmcs_readl(GUEST_RSP) & ~0xffff) | (sp - 6));
+       vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
+                       irq | INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK);
 }
 
 static void kvm_do_inject_irq(struct kvm_vcpu *vcpu)
@@ -1589,13 +1745,7 @@ static void kvm_do_inject_irq(struct kvm_vcpu *vcpu)
        clear_bit(bit_index, &vcpu->irq_pending[word_index]);
        if (!vcpu->irq_pending[word_index])
                clear_bit(word_index, &vcpu->irq_summary);
-
-       if (vcpu->rmode.active) {
-               inject_rmode_irq(vcpu, irq);
-               return;
-       }
-       vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
-                       irq | INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK);
+       vmx_inject_irq(vcpu, irq);
 }
 
 
@@ -1628,6 +1778,23 @@ static void do_interrupt_requests(struct kvm_vcpu *vcpu,
        vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control);
 }
 
+static int vmx_set_tss_addr(struct kvm *kvm, unsigned int addr)
+{
+       int ret;
+       struct kvm_userspace_memory_region tss_mem = {
+               .slot = 8,
+               .guest_phys_addr = addr,
+               .memory_size = PAGE_SIZE * 3,
+               .flags = 0,
+       };
+
+       ret = kvm_set_memory_region(kvm, &tss_mem, 0);
+       if (ret)
+               return ret;
+       kvm->tss_addr = addr;
+       return 0;
+}
+
 static void kvm_guest_debug_pre(struct kvm_vcpu *vcpu)
 {
        struct kvm_guest_debug *dbg = &vcpu->guest_debug;
@@ -1657,77 +1824,56 @@ static int handle_rmode_exception(struct kvm_vcpu *vcpu,
         * Cause the #SS fault with 0 error code in VM86 mode.
         */
        if (((vec == GP_VECTOR) || (vec == SS_VECTOR)) && err_code == 0)
-               if (emulate_instruction(vcpu, NULL, 0, 0) == EMULATE_DONE)
+               if (emulate_instruction(vcpu, NULL, 0, 0, 0) == EMULATE_DONE)
                        return 1;
        return 0;
 }
 
 static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 {
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
        u32 intr_info, error_code;
        unsigned long cr2, rip;
        u32 vect_info;
        enum emulation_result er;
-       int r;
 
-       vect_info = vmcs_read32(IDT_VECTORING_INFO_FIELD);
+       vect_info = vmx->idt_vectoring_info;
        intr_info = vmcs_read32(VM_EXIT_INTR_INFO);
 
        if ((vect_info & VECTORING_INFO_VALID_MASK) &&
-                                               !is_page_fault(intr_info)) {
+                                               !is_page_fault(intr_info))
                printk(KERN_ERR "%s: unexpected, vectoring info 0x%x "
                       "intr info 0x%x\n", __FUNCTION__, vect_info, intr_info);
-       }
 
-       if (is_external_interrupt(vect_info)) {
+       if (!irqchip_in_kernel(vcpu->kvm) && is_external_interrupt(vect_info)) {
                int irq = vect_info & VECTORING_INFO_VECTOR_MASK;
                set_bit(irq, vcpu->irq_pending);
                set_bit(irq / BITS_PER_LONG, &vcpu->irq_summary);
        }
 
-       if ((intr_info & INTR_INFO_INTR_TYPE_MASK) == 0x200) { /* nmi */
-               asm ("int $2");
-               return 1;
-       }
+       if ((intr_info & INTR_INFO_INTR_TYPE_MASK) == 0x200) /* nmi */
+               return 1;  /* already handled by vmx_vcpu_run() */
 
        if (is_no_device(intr_info)) {
                vmx_fpu_activate(vcpu);
                return 1;
        }
 
+       if (is_invalid_opcode(intr_info)) {
+               er = emulate_instruction(vcpu, kvm_run, 0, 0, 0);
+               if (er != EMULATE_DONE)
+                       vmx_inject_ud(vcpu);
+
+               return 1;
+       }
+
        error_code = 0;
        rip = vmcs_readl(GUEST_RIP);
        if (intr_info & INTR_INFO_DELIEVER_CODE_MASK)
                error_code = vmcs_read32(VM_EXIT_INTR_ERROR_CODE);
        if (is_page_fault(intr_info)) {
                cr2 = vmcs_readl(EXIT_QUALIFICATION);
-
-               mutex_lock(&vcpu->kvm->lock);
-               r = kvm_mmu_page_fault(vcpu, cr2, error_code);
-               if (r < 0) {
-                       mutex_unlock(&vcpu->kvm->lock);
-                       return r;
-               }
-               if (!r) {
-                       mutex_unlock(&vcpu->kvm->lock);
-                       return 1;
-               }
-
-               er = emulate_instruction(vcpu, kvm_run, cr2, error_code);
-               mutex_unlock(&vcpu->kvm->lock);
-
-               switch (er) {
-               case EMULATE_DONE:
-                       return 1;
-               case EMULATE_DO_MMIO:
-                       ++vcpu->stat.mmio_exits;
-                       return 0;
-                case EMULATE_FAIL:
-                       vcpu_printf(vcpu, "%s: emulate fail\n", __FUNCTION__);
-                       break;
-               default:
-                       BUG();
-               }
+               return kvm_mmu_page_fault(vcpu, cr2, error_code);
        }
 
        if (vcpu->rmode.active &&
@@ -1740,7 +1886,8 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
                return 1;
        }
 
-       if ((intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK)) == (INTR_TYPE_EXCEPTION | 1)) {
+       if ((intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK)) ==
+           (INTR_TYPE_EXCEPTION | 1)) {
                kvm_run->exit_reason = KVM_EXIT_DEBUG;
                return 0;
        }
@@ -1765,16 +1912,17 @@ static int handle_triple_fault(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 
 static int handle_io(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 {
-       u64 exit_qualification;
+       unsigned long exit_qualification;
        int size, down, in, string, rep;
        unsigned port;
 
        ++vcpu->stat.io_exits;
-       exit_qualification = vmcs_read64(EXIT_QUALIFICATION);
+       exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
        string = (exit_qualification & 16) != 0;
 
        if (string) {
-               if (emulate_instruction(vcpu, kvm_run, 0, 0) == EMULATE_DO_MMIO)
+               if (emulate_instruction(vcpu,
+                                       kvm_run, 0, 0, 0) == EMULATE_DO_MMIO)
                        return 0;
                return 1;
        }
@@ -1797,16 +1945,15 @@ vmx_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall)
        hypercall[0] = 0x0f;
        hypercall[1] = 0x01;
        hypercall[2] = 0xc1;
-       hypercall[3] = 0xc3;
 }
 
 static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 {
-       u64 exit_qualification;
+       unsigned long exit_qualification;
        int cr;
        int reg;
 
-       exit_qualification = vmcs_read64(EXIT_QUALIFICATION);
+       exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
        cr = exit_qualification & 15;
        reg = (exit_qualification >> 8) & 15;
        switch ((exit_qualification >> 4) & 3) {
@@ -1853,7 +2000,7 @@ static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
                        return 1;
                case 8:
                        vcpu_load_rsp_rip(vcpu);
-                       vcpu->regs[reg] = vcpu->cr8;
+                       vcpu->regs[reg] = get_cr8(vcpu);
                        vcpu_put_rsp_rip(vcpu);
                        skip_emulated_instruction(vcpu);
                        return 1;
@@ -1875,7 +2022,7 @@ static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 
 static int handle_dr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 {
-       u64 exit_qualification;
+       unsigned long exit_qualification;
        unsigned long val;
        int dr, reg;
 
@@ -1883,7 +2030,7 @@ static int handle_dr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
         * FIXME: this code assumes the host is debugging the guest.
         *        need to deal with guest debugging itself too.
         */
-       exit_qualification = vmcs_read64(EXIT_QUALIFICATION);
+       exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
        dr = exit_qualification & 7;
        reg = (exit_qualification >> 8) & 15;
        vcpu_load_rsp_rip(vcpu);
@@ -1946,19 +2093,21 @@ static int handle_wrmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
        return 1;
 }
 
-static void post_kvm_run_save(struct kvm_vcpu *vcpu,
-                             struct kvm_run *kvm_run)
+static int handle_tpr_below_threshold(struct kvm_vcpu *vcpu,
+                                     struct kvm_run *kvm_run)
 {
-       kvm_run->if_flag = (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) != 0;
-       kvm_run->cr8 = vcpu->cr8;
-       kvm_run->apic_base = vcpu->apic_base;
-       kvm_run->ready_for_interrupt_injection = (vcpu->interrupt_window_open &&
-                                                 vcpu->irq_summary == 0);
+       return 1;
 }
 
 static int handle_interrupt_window(struct kvm_vcpu *vcpu,
                                   struct kvm_run *kvm_run)
 {
+       u32 cpu_based_vm_exec_control;
+
+       /* clear pending irq */
+       cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL);
+       cpu_based_vm_exec_control &= ~CPU_BASED_VIRTUAL_INTR_PENDING;
+       vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control);
        /*
         * If the user space waits to inject interrupts, exit as soon as
         * possible
@@ -1981,7 +2130,35 @@ static int handle_halt(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 static int handle_vmcall(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 {
        skip_emulated_instruction(vcpu);
-       return kvm_hypercall(vcpu, kvm_run);
+       kvm_emulate_hypercall(vcpu);
+       return 1;
+}
+
+static int handle_wbinvd(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+       skip_emulated_instruction(vcpu);
+       /* TODO: Add support for VT-d/pass-through device */
+       return 1;
+}
+
+static int handle_apic_access(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+       u64 exit_qualification;
+       enum emulation_result er;
+       unsigned long offset;
+
+       exit_qualification = vmcs_read64(EXIT_QUALIFICATION);
+       offset = exit_qualification & 0xffful;
+
+       er = emulate_instruction(vcpu, kvm_run, 0, 0, 0);
+
+       if (er !=  EMULATE_DONE) {
+               printk(KERN_ERR
+                      "Fail to handle apic access vmexit! Offset is 0x%lx\n",
+                      offset);
+               return -ENOTSUPP;
+       }
+       return 1;
 }
 
 /*
@@ -2003,6 +2180,9 @@ static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu,
        [EXIT_REASON_PENDING_INTERRUPT]       = handle_interrupt_window,
        [EXIT_REASON_HLT]                     = handle_halt,
        [EXIT_REASON_VMCALL]                  = handle_vmcall,
+       [EXIT_REASON_TPR_BELOW_THRESHOLD]     = handle_tpr_below_threshold,
+       [EXIT_REASON_APIC_ACCESS]             = handle_apic_access,
+       [EXIT_REASON_WBINVD]                  = handle_wbinvd,
 };
 
 static const int kvm_vmx_max_exit_handlers =
@@ -2014,11 +2194,19 @@ static const int kvm_vmx_max_exit_handlers =
  */
 static int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 {
-       u32 vectoring_info = vmcs_read32(IDT_VECTORING_INFO_FIELD);
        u32 exit_reason = vmcs_read32(VM_EXIT_REASON);
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
+       u32 vectoring_info = vmx->idt_vectoring_info;
+
+       if (unlikely(vmx->fail)) {
+               kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY;
+               kvm_run->fail_entry.hardware_entry_failure_reason
+                       = vmcs_read32(VM_INSTRUCTION_ERROR);
+               return 0;
+       }
 
-       if ( (vectoring_info & VECTORING_INFO_VALID_MASK) &&
-                               exit_reason != EXIT_REASON_EXCEPTION_NMI )
+       if ((vectoring_info & VECTORING_INFO_VALID_MASK) &&
+                               exit_reason != EXIT_REASON_EXCEPTION_NMI)
                printk(KERN_WARNING "%s: unexpected, valid vectoring info and "
                       "exit reason is 0x%x\n", __FUNCTION__, exit_reason);
        if (exit_reason < kvm_vmx_max_exit_handlers
@@ -2031,113 +2219,167 @@ static int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
        return 0;
 }
 
-/*
- * Check if userspace requested an interrupt window, and that the
- * interrupt window is open.
- *
- * No need to exit to userspace if we already have an interrupt queued.
- */
-static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu,
-                                         struct kvm_run *kvm_run)
+static void vmx_flush_tlb(struct kvm_vcpu *vcpu)
 {
-       return (!vcpu->irq_summary &&
-               kvm_run->request_interrupt_window &&
-               vcpu->interrupt_window_open &&
-               (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF));
 }
 
-static void vmx_flush_tlb(struct kvm_vcpu *vcpu)
+static void update_tpr_threshold(struct kvm_vcpu *vcpu)
 {
+       int max_irr, tpr;
+
+       if (!vm_need_tpr_shadow(vcpu->kvm))
+               return;
+
+       if (!kvm_lapic_enabled(vcpu) ||
+           ((max_irr = kvm_lapic_find_highest_irr(vcpu)) == -1)) {
+               vmcs_write32(TPR_THRESHOLD, 0);
+               return;
+       }
+
+       tpr = (kvm_lapic_get_cr8(vcpu) & 0x0f) << 4;
+       vmcs_write32(TPR_THRESHOLD, (max_irr > tpr) ? tpr >> 4 : max_irr >> 4);
 }
 
-static int vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static void enable_irq_window(struct kvm_vcpu *vcpu)
+{
+       u32 cpu_based_vm_exec_control;
+
+       cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL);
+       cpu_based_vm_exec_control |= CPU_BASED_VIRTUAL_INTR_PENDING;
+       vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control);
+}
+
+static void vmx_intr_assist(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
-       u8 fail;
-       int r;
+       u32 idtv_info_field, intr_info_field;
+       int has_ext_irq, interrupt_window_open;
+       int vector;
+
+       update_tpr_threshold(vcpu);
+
+       has_ext_irq = kvm_cpu_has_interrupt(vcpu);
+       intr_info_field = vmcs_read32(VM_ENTRY_INTR_INFO_FIELD);
+       idtv_info_field = vmx->idt_vectoring_info;
+       if (intr_info_field & INTR_INFO_VALID_MASK) {
+               if (idtv_info_field & INTR_INFO_VALID_MASK) {
+                       /* TODO: fault when IDT_Vectoring */
+                       printk(KERN_ERR "Fault when IDT_Vectoring\n");
+               }
+               if (has_ext_irq)
+                       enable_irq_window(vcpu);
+               return;
+       }
+       if (unlikely(idtv_info_field & INTR_INFO_VALID_MASK)) {
+               if ((idtv_info_field & VECTORING_INFO_TYPE_MASK)
+                   == INTR_TYPE_EXT_INTR
+                   && vcpu->rmode.active) {
+                       u8 vect = idtv_info_field & VECTORING_INFO_VECTOR_MASK;
+
+                       vmx_inject_irq(vcpu, vect);
+                       if (unlikely(has_ext_irq))
+                               enable_irq_window(vcpu);
+                       return;
+               }
 
-preempted:
-       if (vcpu->guest_debug.enabled)
-               kvm_guest_debug_pre(vcpu);
+               vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, idtv_info_field);
+               vmcs_write32(VM_ENTRY_INSTRUCTION_LEN,
+                               vmcs_read32(VM_EXIT_INSTRUCTION_LEN));
 
-again:
-       r = kvm_mmu_reload(vcpu);
-       if (unlikely(r))
-               goto out;
+               if (unlikely(idtv_info_field & INTR_INFO_DELIEVER_CODE_MASK))
+                       vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE,
+                               vmcs_read32(IDT_VECTORING_ERROR_CODE));
+               if (unlikely(has_ext_irq))
+                       enable_irq_window(vcpu);
+               return;
+       }
+       if (!has_ext_irq)
+               return;
+       interrupt_window_open =
+               ((vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) &&
+                (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0);
+       if (interrupt_window_open) {
+               vector = kvm_cpu_get_interrupt(vcpu);
+               vmx_inject_irq(vcpu, vector);
+               kvm_timer_intr_post(vcpu, vector);
+       } else
+               enable_irq_window(vcpu);
+}
 
-       preempt_disable();
+/*
+ * Failure to inject an interrupt should give us the information
+ * in IDT_VECTORING_INFO_FIELD.  However, if the failure occurs
+ * when fetching the interrupt redirection bitmap in the real-mode
+ * tss, this doesn't happen.  So we do it ourselves.
+ */
+static void fixup_rmode_irq(struct vcpu_vmx *vmx)
+{
+       vmx->rmode.irq.pending = 0;
+       if (vmcs_readl(GUEST_RIP) + 1 != vmx->rmode.irq.rip)
+               return;
+       vmcs_writel(GUEST_RIP, vmx->rmode.irq.rip);
+       if (vmx->idt_vectoring_info & VECTORING_INFO_VALID_MASK) {
+               vmx->idt_vectoring_info &= ~VECTORING_INFO_TYPE_MASK;
+               vmx->idt_vectoring_info |= INTR_TYPE_EXT_INTR;
+               return;
+       }
+       vmx->idt_vectoring_info =
+               VECTORING_INFO_VALID_MASK
+               | INTR_TYPE_EXT_INTR
+               | vmx->rmode.irq.vector;
+}
 
-       vmx_save_host_state(vmx);
-       kvm_load_guest_fpu(vcpu);
+static void vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
+       u32 intr_info;
 
        /*
         * Loading guest fpu may have cleared host cr0.ts
         */
        vmcs_writel(HOST_CR0, read_cr0());
 
-       local_irq_disable();
-
-       if (signal_pending(current)) {
-               local_irq_enable();
-               preempt_enable();
-               r = -EINTR;
-               kvm_run->exit_reason = KVM_EXIT_INTR;
-               ++vcpu->stat.signal_exits;
-               goto out;
-       }
-
-       if (!vcpu->mmio_read_completed)
-               do_interrupt_requests(vcpu, kvm_run);
-
-       vcpu->guest_mode = 1;
-       if (vcpu->requests)
-               if (test_and_clear_bit(KVM_TLB_FLUSH, &vcpu->requests))
-                   vmx_flush_tlb(vcpu);
-
-       asm (
+       asm(
                /* Store host registers */
 #ifdef CONFIG_X86_64
-               "push %%rax; push %%rbx; push %%rdx;"
-               "push %%rsi; push %%rdi; push %%rbp;"
-               "push %%r8;  push %%r9;  push %%r10; push %%r11;"
-               "push %%r12; push %%r13; push %%r14; push %%r15;"
+               "push %%rdx; push %%rbp;"
                "push %%rcx \n\t"
-               ASM_VMX_VMWRITE_RSP_RDX "\n\t"
 #else
-               "pusha; push %%ecx \n\t"
-               ASM_VMX_VMWRITE_RSP_RDX "\n\t"
+               "push %%edx; push %%ebp;"
+               "push %%ecx \n\t"
 #endif
+               ASM_VMX_VMWRITE_RSP_RDX "\n\t"
                /* Check if vmlaunch of vmresume is needed */
-               "cmp $0, %1 \n\t"
+               "cmpl $0, %c[launched](%0) \n\t"
                /* Load guest registers.  Don't clobber flags. */
 #ifdef CONFIG_X86_64
-               "mov %c[cr2](%3), %%rax \n\t"
+               "mov %c[cr2](%0), %%rax \n\t"
                "mov %%rax, %%cr2 \n\t"
-               "mov %c[rax](%3), %%rax \n\t"
-               "mov %c[rbx](%3), %%rbx \n\t"
-               "mov %c[rdx](%3), %%rdx \n\t"
-               "mov %c[rsi](%3), %%rsi \n\t"
-               "mov %c[rdi](%3), %%rdi \n\t"
-               "mov %c[rbp](%3), %%rbp \n\t"
-               "mov %c[r8](%3),  %%r8  \n\t"
-               "mov %c[r9](%3),  %%r9  \n\t"
-               "mov %c[r10](%3), %%r10 \n\t"
-               "mov %c[r11](%3), %%r11 \n\t"
-               "mov %c[r12](%3), %%r12 \n\t"
-               "mov %c[r13](%3), %%r13 \n\t"
-               "mov %c[r14](%3), %%r14 \n\t"
-               "mov %c[r15](%3), %%r15 \n\t"
-               "mov %c[rcx](%3), %%rcx \n\t" /* kills %3 (rcx) */
+               "mov %c[rax](%0), %%rax \n\t"
+               "mov %c[rbx](%0), %%rbx \n\t"
+               "mov %c[rdx](%0), %%rdx \n\t"
+               "mov %c[rsi](%0), %%rsi \n\t"
+               "mov %c[rdi](%0), %%rdi \n\t"
+               "mov %c[rbp](%0), %%rbp \n\t"
+               "mov %c[r8](%0),  %%r8  \n\t"
+               "mov %c[r9](%0),  %%r9  \n\t"
+               "mov %c[r10](%0), %%r10 \n\t"
+               "mov %c[r11](%0), %%r11 \n\t"
+               "mov %c[r12](%0), %%r12 \n\t"
+               "mov %c[r13](%0), %%r13 \n\t"
+               "mov %c[r14](%0), %%r14 \n\t"
+               "mov %c[r15](%0), %%r15 \n\t"
+               "mov %c[rcx](%0), %%rcx \n\t" /* kills %0 (rcx) */
 #else
-               "mov %c[cr2](%3), %%eax \n\t"
+               "mov %c[cr2](%0), %%eax \n\t"
                "mov %%eax,   %%cr2 \n\t"
-               "mov %c[rax](%3), %%eax \n\t"
-               "mov %c[rbx](%3), %%ebx \n\t"
-               "mov %c[rdx](%3), %%edx \n\t"
-               "mov %c[rsi](%3), %%esi \n\t"
-               "mov %c[rdi](%3), %%edi \n\t"
-               "mov %c[rbp](%3), %%ebp \n\t"
-               "mov %c[rcx](%3), %%ecx \n\t" /* kills %3 (ecx) */
+               "mov %c[rax](%0), %%eax \n\t"
+               "mov %c[rbx](%0), %%ebx \n\t"
+               "mov %c[rdx](%0), %%edx \n\t"
+               "mov %c[rsi](%0), %%esi \n\t"
+               "mov %c[rdi](%0), %%edi \n\t"
+               "mov %c[rbp](%0), %%ebp \n\t"
+               "mov %c[rcx](%0), %%ecx \n\t" /* kills %0 (ecx) */
 #endif
                /* Enter guest mode */
                "jne .Llaunched \n\t"
@@ -2147,123 +2389,94 @@ again:
                ".Lkvm_vmx_return: "
                /* Save guest registers, load host registers, keep flags */
 #ifdef CONFIG_X86_64
-               "xchg %3,     (%%rsp) \n\t"
-               "mov %%rax, %c[rax](%3) \n\t"
-               "mov %%rbx, %c[rbx](%3) \n\t"
-               "pushq (%%rsp); popq %c[rcx](%3) \n\t"
-               "mov %%rdx, %c[rdx](%3) \n\t"
-               "mov %%rsi, %c[rsi](%3) \n\t"
-               "mov %%rdi, %c[rdi](%3) \n\t"
-               "mov %%rbp, %c[rbp](%3) \n\t"
-               "mov %%r8,  %c[r8](%3) \n\t"
-               "mov %%r9,  %c[r9](%3) \n\t"
-               "mov %%r10, %c[r10](%3) \n\t"
-               "mov %%r11, %c[r11](%3) \n\t"
-               "mov %%r12, %c[r12](%3) \n\t"
-               "mov %%r13, %c[r13](%3) \n\t"
-               "mov %%r14, %c[r14](%3) \n\t"
-               "mov %%r15, %c[r15](%3) \n\t"
+               "xchg %0,     (%%rsp) \n\t"
+               "mov %%rax, %c[rax](%0) \n\t"
+               "mov %%rbx, %c[rbx](%0) \n\t"
+               "pushq (%%rsp); popq %c[rcx](%0) \n\t"
+               "mov %%rdx, %c[rdx](%0) \n\t"
+               "mov %%rsi, %c[rsi](%0) \n\t"
+               "mov %%rdi, %c[rdi](%0) \n\t"
+               "mov %%rbp, %c[rbp](%0) \n\t"
+               "mov %%r8,  %c[r8](%0) \n\t"
+               "mov %%r9,  %c[r9](%0) \n\t"
+               "mov %%r10, %c[r10](%0) \n\t"
+               "mov %%r11, %c[r11](%0) \n\t"
+               "mov %%r12, %c[r12](%0) \n\t"
+               "mov %%r13, %c[r13](%0) \n\t"
+               "mov %%r14, %c[r14](%0) \n\t"
+               "mov %%r15, %c[r15](%0) \n\t"
                "mov %%cr2, %%rax   \n\t"
-               "mov %%rax, %c[cr2](%3) \n\t"
-               "mov (%%rsp), %3 \n\t"
+               "mov %%rax, %c[cr2](%0) \n\t"
 
-               "pop  %%rcx; pop  %%r15; pop  %%r14; pop  %%r13; pop  %%r12;"
-               "pop  %%r11; pop  %%r10; pop  %%r9;  pop  %%r8;"
-               "pop  %%rbp; pop  %%rdi; pop  %%rsi;"
-               "pop  %%rdx; pop  %%rbx; pop  %%rax \n\t"
+               "pop  %%rbp; pop  %%rbp; pop  %%rdx \n\t"
 #else
-               "xchg %3, (%%esp) \n\t"
-               "mov %%eax, %c[rax](%3) \n\t"
-               "mov %%ebx, %c[rbx](%3) \n\t"
-               "pushl (%%esp); popl %c[rcx](%3) \n\t"
-               "mov %%edx, %c[rdx](%3) \n\t"
-               "mov %%esi, %c[rsi](%3) \n\t"
-               "mov %%edi, %c[rdi](%3) \n\t"
-               "mov %%ebp, %c[rbp](%3) \n\t"
+               "xchg %0, (%%esp) \n\t"
+               "mov %%eax, %c[rax](%0) \n\t"
+               "mov %%ebx, %c[rbx](%0) \n\t"
+               "pushl (%%esp); popl %c[rcx](%0) \n\t"
+               "mov %%edx, %c[rdx](%0) \n\t"
+               "mov %%esi, %c[rsi](%0) \n\t"
+               "mov %%edi, %c[rdi](%0) \n\t"
+               "mov %%ebp, %c[rbp](%0) \n\t"
                "mov %%cr2, %%eax  \n\t"
-               "mov %%eax, %c[cr2](%3) \n\t"
-               "mov (%%esp), %3 \n\t"
+               "mov %%eax, %c[cr2](%0) \n\t"
 
-               "pop %%ecx; popa \n\t"
+               "pop %%ebp; pop %%ebp; pop %%edx \n\t"
 #endif
-               "setbe %0 \n\t"
-             : "=q" (fail)
-             : "r"(vmx->launched), "d"((unsigned long)HOST_RSP),
-               "c"(vcpu),
-               [rax]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RAX])),
-               [rbx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RBX])),
-               [rcx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RCX])),
-               [rdx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RDX])),
-               [rsi]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RSI])),
-               [rdi]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RDI])),
-               [rbp]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RBP])),
+               "setbe %c[fail](%0) \n\t"
+             : : "c"(vmx), "d"((unsigned long)HOST_RSP),
+               [launched]"i"(offsetof(struct vcpu_vmx, launched)),
+               [fail]"i"(offsetof(struct vcpu_vmx, fail)),
+               [rax]"i"(offsetof(struct vcpu_vmx, vcpu.regs[VCPU_REGS_RAX])),
+               [rbx]"i"(offsetof(struct vcpu_vmx, vcpu.regs[VCPU_REGS_RBX])),
+               [rcx]"i"(offsetof(struct vcpu_vmx, vcpu.regs[VCPU_REGS_RCX])),
+               [rdx]"i"(offsetof(struct vcpu_vmx, vcpu.regs[VCPU_REGS_RDX])),
+               [rsi]"i"(offsetof(struct vcpu_vmx, vcpu.regs[VCPU_REGS_RSI])),
+               [rdi]"i"(offsetof(struct vcpu_vmx, vcpu.regs[VCPU_REGS_RDI])),
+               [rbp]"i"(offsetof(struct vcpu_vmx, vcpu.regs[VCPU_REGS_RBP])),
 #ifdef CONFIG_X86_64
-               [r8 ]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R8 ])),
-               [r9 ]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R9 ])),
-               [r10]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R10])),
-               [r11]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R11])),
-               [r12]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R12])),
-               [r13]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R13])),
-               [r14]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R14])),
-               [r15]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R15])),
+               [r8]"i"(offsetof(struct vcpu_vmx, vcpu.regs[VCPU_REGS_R8])),
+               [r9]"i"(offsetof(struct vcpu_vmx, vcpu.regs[VCPU_REGS_R9])),
+               [r10]"i"(offsetof(struct vcpu_vmx, vcpu.regs[VCPU_REGS_R10])),
+               [r11]"i"(offsetof(struct vcpu_vmx, vcpu.regs[VCPU_REGS_R11])),
+               [r12]"i"(offsetof(struct vcpu_vmx, vcpu.regs[VCPU_REGS_R12])),
+               [r13]"i"(offsetof(struct vcpu_vmx, vcpu.regs[VCPU_REGS_R13])),
+               [r14]"i"(offsetof(struct vcpu_vmx, vcpu.regs[VCPU_REGS_R14])),
+               [r15]"i"(offsetof(struct vcpu_vmx, vcpu.regs[VCPU_REGS_R15])),
 #endif
-               [cr2]"i"(offsetof(struct kvm_vcpu, cr2))
-             : "cc", "memory" );
-
-       vcpu->guest_mode = 0;
-       local_irq_enable();
+               [cr2]"i"(offsetof(struct vcpu_vmx, vcpu.cr2))
+             : "cc", "memory"
+#ifdef CONFIG_X86_64
+               , "rbx", "rdi", "rsi"
+               , "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
+#else
+               , "ebx", "edi", "rsi"
+#endif
+             );
 
-       ++vcpu->stat.exits;
+       vmx->idt_vectoring_info = vmcs_read32(IDT_VECTORING_INFO_FIELD);
+       if (vmx->rmode.irq.pending)
+               fixup_rmode_irq(vmx);
 
-       vcpu->interrupt_window_open = (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0;
+       vcpu->interrupt_window_open =
+               (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0;
 
-       asm ("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS));
+       asm("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS));
        vmx->launched = 1;
 
-       preempt_enable();
-
-       if (unlikely(fail)) {
-               kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY;
-               kvm_run->fail_entry.hardware_entry_failure_reason
-                       = vmcs_read32(VM_INSTRUCTION_ERROR);
-               r = 0;
-               goto out;
-       }
-       /*
-        * Profile KVM exit RIPs:
-        */
-       if (unlikely(prof_on == KVM_PROFILING))
-               profile_hit(KVM_PROFILING, (void *)vmcs_readl(GUEST_RIP));
-
-       r = kvm_handle_exit(kvm_run, vcpu);
-       if (r > 0) {
-               if (dm_request_for_irq_injection(vcpu, kvm_run)) {
-                       r = -EINTR;
-                       kvm_run->exit_reason = KVM_EXIT_INTR;
-                       ++vcpu->stat.request_irq_exits;
-                       goto out;
-               }
-               if (!need_resched()) {
-                       ++vcpu->stat.light_exits;
-                       goto again;
-               }
-       }
-
-out:
-       if (r > 0) {
-               kvm_resched(vcpu);
-               goto preempted;
-       }
+       intr_info = vmcs_read32(VM_EXIT_INTR_INFO);
 
-       post_kvm_run_save(vcpu, kvm_run);
-       return r;
+       /* We need to handle NMIs before interrupts are enabled */
+       if ((intr_info & INTR_INFO_INTR_TYPE_MASK) == 0x200) /* nmi */
+               asm("int $2");
 }
 
 static void vmx_inject_page_fault(struct kvm_vcpu *vcpu,
                                  unsigned long addr,
                                  u32 err_code)
 {
-       u32 vect_info = vmcs_read32(IDT_VECTORING_INFO_FIELD);
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
+       u32 vect_info = vmx->idt_vectoring_info;
 
        ++vcpu->stat.pf_guest;
 
@@ -2377,7 +2590,7 @@ static void __init vmx_check_processor_compat(void *rtn)
        }
 }
 
-static struct kvm_arch_ops vmx_arch_ops = {
+static struct kvm_x86_ops vmx_x86_ops = {
        .cpu_has_kvm_support = cpu_has_kvm_support,
        .disabled_by_bios = vmx_disabled_by_bios,
        .hardware_setup = hardware_setup,
@@ -2388,12 +2601,15 @@ static struct kvm_arch_ops vmx_arch_ops = {
 
        .vcpu_create = vmx_create_vcpu,
        .vcpu_free = vmx_free_vcpu,
+       .vcpu_reset = vmx_vcpu_reset,
 
+       .prepare_guest_switch = vmx_save_host_state,
        .vcpu_load = vmx_vcpu_load,
        .vcpu_put = vmx_vcpu_put,
        .vcpu_decache = vmx_vcpu_decache,
 
        .set_guest_debug = set_guest_debug,
+       .guest_debug_pre = kvm_guest_debug_pre,
        .get_msr = vmx_get_msr,
        .set_msr = vmx_set_msr,
        .get_segment_base = vmx_get_segment_base,
@@ -2422,8 +2638,15 @@ static struct kvm_arch_ops vmx_arch_ops = {
        .inject_gp = vmx_inject_gp,
 
        .run = vmx_vcpu_run,
+       .handle_exit = kvm_handle_exit,
        .skip_emulated_instruction = skip_emulated_instruction,
        .patch_hypercall = vmx_patch_hypercall,
+       .get_irq = vmx_get_irq,
+       .set_irq = vmx_inject_irq,
+       .inject_pending_irq = vmx_intr_assist,
+       .inject_pending_vectors = do_interrupt_requests,
+
+       .set_tss_addr = vmx_set_tss_addr,
 };
 
 static int __init vmx_init(void)
@@ -2454,10 +2677,13 @@ static int __init vmx_init(void)
        memset(iova, 0xff, PAGE_SIZE);
        kunmap(vmx_io_bitmap_b);
 
-       r = kvm_init_arch(&vmx_arch_ops, sizeof(struct vcpu_vmx), THIS_MODULE);
+       r = kvm_init(&vmx_x86_ops, sizeof(struct vcpu_vmx), THIS_MODULE);
        if (r)
                goto out1;
 
+       if (bypass_guest_pf)
+               kvm_mmu_set_nonpresent_ptes(~0xffeull, 0ull);
+
        return 0;
 
 out1:
@@ -2472,7 +2698,7 @@ static void __exit vmx_exit(void)
        __free_page(vmx_io_bitmap_b);
        __free_page(vmx_io_bitmap_a);
 
-       kvm_exit_arch();
+       kvm_exit();
 }
 
 module_init(vmx_init)