]> err.no Git - linux-2.6/blobdiff - drivers/kvm/vmx.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/v4l-dvb
[linux-2.6] / drivers / kvm / vmx.c
index 044722bc1a7f4670f5bf7a96c413e15320828d3f..bb56ae3f89b601f9c2ae428dd92498f35b8aa181 100644 (file)
@@ -17,6 +17,7 @@
 
 #include "kvm.h"
 #include "x86_emulate.h"
+#include "irq.h"
 #include "vmx.h"
 #include "segment_descriptor.h"
 
@@ -24,7 +25,6 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/highmem.h>
-#include <linux/profile.h>
 #include <linux/sched.h>
 
 #include <asm/io.h>
@@ -42,6 +42,7 @@ struct vmcs {
 struct vcpu_vmx {
        struct kvm_vcpu       vcpu;
        int                   launched;
+       u8                    fail;
        struct kvm_msr_entry *guest_msrs;
        struct kvm_msr_entry *host_msrs;
        int                   nmsrs;
@@ -54,7 +55,8 @@ struct vcpu_vmx {
        struct {
                int           loaded;
                u16           fs_sel, gs_sel, ldt_sel;
-               int           fs_gs_ldt_reload_needed;
+               int           gs_ldt_reload_needed;
+               int           fs_reload_needed;
        }host_state;
 
 };
@@ -168,6 +170,16 @@ static inline int is_external_interrupt(u32 intr_info)
                == (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 int __find_msr_index(struct vcpu_vmx *vmx, u32 msr)
 {
        int i;
@@ -342,8 +354,10 @@ static void load_transition_efer(struct vcpu_vmx *vmx)
        vmx->vcpu.stat.efer_reload++;
 }
 
-static void vmx_save_host_state(struct vcpu_vmx *vmx)
+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 +367,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
@@ -396,9 +411,10 @@ static void vmx_load_host_state(struct vcpu_vmx *vmx)
                return;
 
        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,9 +425,8 @@ 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))
@@ -428,8 +443,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;
@@ -506,6 +523,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 |= IOPL_MASK | X86_EFLAGS_VM;
        vmcs_writel(GUEST_RFLAGS, rflags);
 }
 
@@ -787,6 +806,20 @@ 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)
+{
+       u32 idtv_info_field;
+
+       idtv_info_field = vmcs_read32(IDT_VECTORING_INFO_FIELD);
+       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("pending exception: not handled yet\n");
+       }
+       return -1;
+}
+
 static __init int cpu_has_kvm_support(void)
 {
        unsigned long ecx = cpuid_ecx(1);
@@ -871,10 +904,19 @@ 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;
+#ifdef CONFIG_X86_64
+       opt = CPU_BASED_TPR_SHADOW;
+#else
        opt = 0;
+#endif
        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
 
        min = 0;
 #ifdef CONFIG_X86_64
@@ -1030,7 +1072,7 @@ 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;
@@ -1088,6 +1130,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);
 }
 
@@ -1366,17 +1409,22 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
        int i;
        int ret = 0;
        unsigned long kvm_vmx_return;
+       u64 msr;
+       u32 exec_control;
 
        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();
-       vmx->vcpu.cr8 = 0;
-       vmx->vcpu.apic_base = 0xfee00000 | MSR_IA32_APICBASE_ENABLE;
+       set_cr8(&vmx->vcpu, 0);
+       msr = 0xfee00000 | MSR_IA32_APICBASE_ENABLE;
        if (vmx->vcpu.vcpu_id == 0)
-               vmx->vcpu.apic_base |= MSR_IA32_APICBASE_BSP;
+               msr |= MSR_IA32_APICBASE_BSP;
+       kvm_set_apic_base(&vmx->vcpu, msr);
 
        fx_init(&vmx->vcpu);
 
@@ -1384,8 +1432,13 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
         * 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);
+       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);
 
@@ -1410,7 +1463,10 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
        vmcs_writel(GUEST_SYSENTER_EIP, 0);
 
        vmcs_writel(GUEST_RFLAGS, 0x02);
-       vmcs_writel(GUEST_RIP, 0xfff0);
+       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
@@ -1440,8 +1496,16 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
        /* 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);
+
+       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
+       }
+       vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, exec_control);
 
        vmcs_write32(PAGE_FAULT_ERROR_CODE_MASK, 0);
        vmcs_write32(PAGE_FAULT_ERROR_CODE_MATCH, 0);
@@ -1513,8 +1577,11 @@ static int vmx_vcpu_setup(struct vcpu_vmx *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);
+       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);
 #endif
 
        vmcs_writel(CR0_GUEST_HOST_MASK, ~0UL);
@@ -1535,6 +1602,13 @@ out:
        return ret;
 }
 
+static void vmx_vcpu_reset(struct kvm_vcpu *vcpu)
+{
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
+
+       vmx_vcpu_setup(vmx);
+}
+
 static void inject_rmode_irq(struct kvm_vcpu *vcpu, int irq)
 {
        u16 ent[2];
@@ -1580,6 +1654,16 @@ static void inject_rmode_irq(struct kvm_vcpu *vcpu, int irq)
        vmcs_writel(GUEST_RSP, (vmcs_readl(GUEST_RSP) & ~0xffff) | (sp - 6));
 }
 
+static void vmx_inject_irq(struct kvm_vcpu *vcpu, int irq)
+{
+       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);
+}
+
 static void kvm_do_inject_irq(struct kvm_vcpu *vcpu)
 {
        int word_index = __ffs(vcpu->irq_summary);
@@ -1589,13 +1673,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);
 }
 
 
@@ -1679,16 +1757,14 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
                       "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);
@@ -1723,7 +1799,7 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
                        ++vcpu->stat.mmio_exits;
                        return 0;
                 case EMULATE_FAIL:
-                       vcpu_printf(vcpu, "%s: emulate fail\n", __FUNCTION__);
+                       kvm_report_emulation_failure(vcpu, "pagetable");
                        break;
                default:
                        BUG();
@@ -1765,12 +1841,12 @@ 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) {
@@ -1785,8 +1861,7 @@ static int handle_io(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
        rep = (exit_qualification & 32) != 0;
        port = exit_qualification >> 16;
 
-       return kvm_setup_pio(vcpu, kvm_run, in, size, 1, 0, down,
-                            0, rep, port);
+       return kvm_emulate_pio(vcpu, kvm_run, in, size, port);
 }
 
 static void
@@ -1803,11 +1878,11 @@ vmx_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall)
 
 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) {
@@ -1832,7 +1907,8 @@ static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
                        vcpu_load_rsp_rip(vcpu);
                        set_cr8(vcpu, vcpu->regs[reg]);
                        skip_emulated_instruction(vcpu);
-                       return 1;
+                       kvm_run->exit_reason = KVM_EXIT_SET_TPR;
+                       return 0;
                };
                break;
        case 2: /* clts */
@@ -1853,7 +1929,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 +1951,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 +1959,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 +2022,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
@@ -2003,6 +2081,7 @@ 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
 };
 
 static const int kvm_vmx_max_exit_handlers =
@@ -2016,6 +2095,14 @@ 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);
+
+       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 )
@@ -2031,60 +2118,92 @@ 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)
 {
-       struct vcpu_vmx *vmx = to_vmx(vcpu);
-       u8 fail;
-       int r;
+       u32 cpu_based_vm_exec_control;
 
-preempted:
-       if (vcpu->guest_debug.enabled)
-               kvm_guest_debug_pre(vcpu);
+       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);
+}
 
-again:
-       r = kvm_mmu_reload(vcpu);
-       if (unlikely(r))
-               goto out;
+static void vmx_intr_assist(struct kvm_vcpu *vcpu)
+{
+       u32 idtv_info_field, intr_info_field;
+       int has_ext_irq, interrupt_window_open;
+       int vector;
 
-       preempt_disable();
+       kvm_inject_pending_timer_irqs(vcpu);
+       update_tpr_threshold(vcpu);
 
-       if (!vcpu->mmio_read_completed)
-               do_interrupt_requests(vcpu, kvm_run);
+       has_ext_irq = kvm_cpu_has_interrupt(vcpu);
+       intr_info_field = vmcs_read32(VM_ENTRY_INTR_INFO_FIELD);
+       idtv_info_field = vmcs_read32(IDT_VECTORING_INFO_FIELD);
+       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)) {
+               vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, idtv_info_field);
+               vmcs_write32(VM_ENTRY_INSTRUCTION_LEN,
+                               vmcs_read32(VM_EXIT_INSTRUCTION_LEN));
+
+               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);
+}
 
-       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();
-
-       vcpu->guest_mode = 1;
-       if (vcpu->requests)
-               if (test_and_clear_bit(KVM_TLB_FLUSH, &vcpu->requests))
-                   vmx_flush_tlb(vcpu);
-
        asm (
                /* Store host registers */
 #ifdef CONFIG_X86_64
@@ -2178,7 +2297,7 @@ again:
                "pop %%ecx; popa \n\t"
 #endif
                "setbe %0 \n\t"
-             : "=q" (fail)
+             : "=q" (vmx->fail)
              : "r"(vmx->launched), "d"((unsigned long)HOST_RSP),
                "c"(vcpu),
                [rax]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RAX])),
@@ -2201,61 +2320,16 @@ again:
                [cr2]"i"(offsetof(struct kvm_vcpu, cr2))
              : "cc", "memory" );
 
-       vcpu->guest_mode = 0;
-       local_irq_enable();
-
-       ++vcpu->stat.exits;
-
        vcpu->interrupt_window_open = (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0;
 
        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) {
-               /* Give scheduler a change to reschedule. */
-               if (signal_pending(current)) {
-                       r = -EINTR;
-                       kvm_run->exit_reason = KVM_EXIT_INTR;
-                       ++vcpu->stat.signal_exits;
-                       goto out;
-               }
-
-               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,
@@ -2323,6 +2397,12 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id)
        if (err)
                goto free_vcpu;
 
+       if (irqchip_in_kernel(kvm)) {
+               err = kvm_create_lapic(&vmx->vcpu);
+               if (err < 0)
+                       goto free_vcpu;
+       }
+
        vmx->guest_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL);
        if (!vmx->guest_msrs) {
                err = -ENOMEM;
@@ -2376,7 +2456,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,
@@ -2387,12 +2467,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,
@@ -2421,8 +2504,13 @@ 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,
 };
 
 static int __init vmx_init(void)
@@ -2453,7 +2541,7 @@ 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_x86(&vmx_x86_ops, sizeof(struct vcpu_vmx), THIS_MODULE);
        if (r)
                goto out1;
 
@@ -2471,7 +2559,7 @@ static void __exit vmx_exit(void)
        __free_page(vmx_io_bitmap_b);
        __free_page(vmx_io_bitmap_a);
 
-       kvm_exit_arch();
+       kvm_exit_x86();
 }
 
 module_init(vmx_init)