]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/x86/kvm/vmx.c
KVM: Ignore DEBUGCTL MSRs with no effect
[linux-2.6-omap-h63xx.git] / arch / x86 / kvm / vmx.c
index ed4fe8e72ad093309aacc66d28b3ec2553dcd7b5..ddb49e34697b7374dfedec9841c0e906298e4d6d 100644 (file)
@@ -58,6 +58,7 @@ struct vmcs {
 struct vcpu_vmx {
        struct kvm_vcpu       vcpu;
        struct list_head      local_vcpus_link;
+       unsigned long         host_rsp;
        int                   launched;
        u8                    fail;
        u32                   idt_vectoring_info;
@@ -470,7 +471,7 @@ static void update_exception_bitmap(struct kvm_vcpu *vcpu)
        if (!vcpu->fpu_active)
                eb |= 1u << NM_VECTOR;
        if (vcpu->guest_debug.enabled)
-               eb |= 1u << 1;
+               eb |= 1u << DB_VECTOR;
        if (vcpu->arch.rmode.active)
                eb = ~0;
        if (vm_need_ept())
@@ -735,12 +736,30 @@ static void skip_emulated_instruction(struct kvm_vcpu *vcpu)
 static void vmx_queue_exception(struct kvm_vcpu *vcpu, unsigned nr,
                                bool has_error_code, u32 error_code)
 {
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
+
+       if (has_error_code)
+               vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, error_code);
+
+       if (vcpu->arch.rmode.active) {
+               vmx->rmode.irq.pending = true;
+               vmx->rmode.irq.vector = nr;
+               vmx->rmode.irq.rip = kvm_rip_read(vcpu);
+               if (nr == BP_VECTOR)
+                       vmx->rmode.irq.rip++;
+               vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
+                            nr | INTR_TYPE_SOFT_INTR
+                            | (has_error_code ? INTR_INFO_DELIVER_CODE_MASK : 0)
+                            | INTR_INFO_VALID_MASK);
+               vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, 1);
+               kvm_rip_write(vcpu, vmx->rmode.irq.rip - 1);
+               return;
+       }
+
        vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
                     nr | INTR_TYPE_EXCEPTION
                     | (has_error_code ? INTR_INFO_DELIVER_CODE_MASK : 0)
                     | INTR_INFO_VALID_MASK);
-       if (has_error_code)
-               vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, error_code);
 }
 
 static bool vmx_exception_injected(struct kvm_vcpu *vcpu)
@@ -1002,17 +1021,9 @@ static int set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg)
 
 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;
+       if (!vcpu->arch.interrupt.pending)
+               return -1;
+       return vcpu->arch.interrupt.nr;
 }
 
 static __init int cpu_has_kvm_support(void)
@@ -2232,9 +2243,6 @@ static void kvm_guest_debug_pre(struct kvm_vcpu *vcpu)
 static int handle_rmode_exception(struct kvm_vcpu *vcpu,
                                  int vec, u32 err_code)
 {
-       if (!vcpu->arch.rmode.active)
-               return 0;
-
        /*
         * Instruction with address size override prefix opcode 0x67
         * Cause the #SS fault with 0 error code in VM86 mode.
@@ -2242,6 +2250,25 @@ static int handle_rmode_exception(struct kvm_vcpu *vcpu,
        if (((vec == GP_VECTOR) || (vec == SS_VECTOR)) && err_code == 0)
                if (emulate_instruction(vcpu, NULL, 0, 0, 0) == EMULATE_DONE)
                        return 1;
+       /*
+        * Forward all other exceptions that are valid in real mode.
+        * FIXME: Breaks guest debugging in real mode, needs to be fixed with
+        *        the required debugging infrastructure rework.
+        */
+       switch (vec) {
+       case DE_VECTOR:
+       case DB_VECTOR:
+       case BP_VECTOR:
+       case OF_VECTOR:
+       case BR_VECTOR:
+       case UD_VECTOR:
+       case DF_VECTOR:
+       case SS_VECTOR:
+       case GP_VECTOR:
+       case MF_VECTOR:
+               kvm_queue_exception(vcpu, vec);
+               return 1;
+       }
        return 0;
 }
 
@@ -2293,7 +2320,7 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
                cr2 = vmcs_readl(EXIT_QUALIFICATION);
                KVMTRACE_3D(PAGE_FAULT, vcpu, error_code, (u32)cr2,
                            (u32)((u64)cr2 >> 32), handler);
-               if (vect_info & VECTORING_INFO_VALID_MASK)
+               if (vcpu->arch.interrupt.pending || vcpu->arch.exception.pending)
                        kvm_mmu_unprotect_page_virt(vcpu, cr2);
                return kvm_mmu_page_fault(vcpu, cr2, error_code);
        }
@@ -2864,51 +2891,20 @@ static void vmx_complete_interrupts(struct vcpu_vmx *vmx)
                        kvm_queue_exception(&vmx->vcpu, vector);
                vmx->idt_vectoring_info = 0;
        }
+       kvm_clear_interrupt_queue(&vmx->vcpu);
+       if (idtv_info_valid && type == INTR_TYPE_EXT_INTR) {
+               kvm_queue_interrupt(&vmx->vcpu, vector);
+               vmx->idt_vectoring_info = 0;
+       }
 }
 
 static void vmx_intr_assist(struct kvm_vcpu *vcpu)
 {
-       struct vcpu_vmx *vmx = to_vmx(vcpu);
-       u32 idtv_info_field, intr_info_field;
-       int vector;
+       u32 intr_info_field;
 
        update_tpr_threshold(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 */
-                       if (printk_ratelimit())
-                               printk(KERN_ERR "Fault when IDT_Vectoring\n");
-               }
-               enable_intr_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->arch.rmode.active) {
-                       u8 vect = idtv_info_field & VECTORING_INFO_VECTOR_MASK;
-
-                       vmx_inject_irq(vcpu, vect);
-                       enable_intr_window(vcpu);
-                       return;
-               }
-
-               KVMTRACE_1D(REDELIVER_EVT, vcpu, idtv_info_field, handler);
-
-               vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, idtv_info_field
-                               & ~INTR_INFO_RESVD_BITS_MASK);
-               vmcs_write32(VM_ENTRY_INSTRUCTION_LEN,
-                               vmcs_read32(VM_EXIT_INSTRUCTION_LEN));
-
-               if (unlikely(idtv_info_field & INTR_INFO_DELIVER_CODE_MASK))
-                       vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE,
-                               vmcs_read32(IDT_VECTORING_ERROR_CODE));
-               enable_intr_window(vcpu);
-               return;
-       }
        if (cpu_has_virtual_nmis()) {
                if (vcpu->arch.nmi_pending && !vcpu->arch.nmi_injected) {
                        if (vmx_nmi_enabled(vcpu)) {
@@ -2925,14 +2921,16 @@ static void vmx_intr_assist(struct kvm_vcpu *vcpu)
                        return;
                }
        }
-       if (!kvm_cpu_has_interrupt(vcpu))
-               return;
-       if (vmx_irq_enabled(vcpu)) {
-               vector = kvm_cpu_get_interrupt(vcpu);
-               vmx_inject_irq(vcpu, vector);
-               kvm_timer_intr_post(vcpu, vector);
-       } else
-               enable_irq_window(vcpu);
+       if (!vcpu->arch.interrupt.pending && kvm_cpu_has_interrupt(vcpu)) {
+               if (vmx_irq_enabled(vcpu))
+                       kvm_queue_interrupt(vcpu, kvm_cpu_get_interrupt(vcpu));
+               else
+                       enable_irq_window(vcpu);
+       }
+       if (vcpu->arch.interrupt.pending) {
+               vmx_inject_irq(vcpu, vcpu->arch.interrupt.nr);
+               kvm_timer_intr_post(vcpu, vcpu->arch.interrupt.nr);
+       }
 }
 
 /*
@@ -2958,6 +2956,14 @@ static void fixup_rmode_irq(struct vcpu_vmx *vmx)
                | vmx->rmode.irq.vector;
 }
 
+#ifdef CONFIG_X86_64
+#define R "r"
+#define Q "q"
+#else
+#define R "e"
+#define Q "l"
+#endif
+
 static void vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
@@ -2975,26 +2981,25 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 
        asm(
                /* Store host registers */
-#ifdef CONFIG_X86_64
-               "push %%rdx; push %%rbp;"
-               "push %%rcx \n\t"
-#else
-               "push %%edx; push %%ebp;"
-               "push %%ecx \n\t"
-#endif
+               "push %%"R"dx; push %%"R"bp;"
+               "push %%"R"cx \n\t"
+               "cmp %%"R"sp, %c[host_rsp](%0) \n\t"
+               "je 1f \n\t"
+               "mov %%"R"sp, %c[host_rsp](%0) \n\t"
                __ex(ASM_VMX_VMWRITE_RSP_RDX) "\n\t"
+               "1: \n\t"
                /* Check if vmlaunch of vmresume is needed */
                "cmpl $0, %c[launched](%0) \n\t"
                /* Load guest registers.  Don't clobber flags. */
+               "mov %c[cr2](%0), %%"R"ax \n\t"
+               "mov %%"R"ax, %%cr2 \n\t"
+               "mov %c[rax](%0), %%"R"ax \n\t"
+               "mov %c[rbx](%0), %%"R"bx \n\t"
+               "mov %c[rdx](%0), %%"R"dx \n\t"
+               "mov %c[rsi](%0), %%"R"si \n\t"
+               "mov %c[rdi](%0), %%"R"di \n\t"
+               "mov %c[rbp](%0), %%"R"bp \n\t"
 #ifdef CONFIG_X86_64
-               "mov %c[cr2](%0), %%rax \n\t"
-               "mov %%rax, %%cr2 \n\t"
-               "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"
@@ -3003,18 +3008,9 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
                "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](%0), %%eax \n\t"
-               "mov %%eax,   %%cr2 \n\t"
-               "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
+               "mov %c[rcx](%0), %%"R"cx \n\t" /* kills %0 (ecx) */
+
                /* Enter guest mode */
                "jne .Llaunched \n\t"
                __ex(ASM_VMX_VMLAUNCH) "\n\t"
@@ -3022,15 +3018,15 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
                ".Llaunched: " __ex(ASM_VMX_VMRESUME) "\n\t"
                ".Lkvm_vmx_return: "
                /* Save guest registers, load host registers, keep flags */
+               "xchg %0,     (%%"R"sp) \n\t"
+               "mov %%"R"ax, %c[rax](%0) \n\t"
+               "mov %%"R"bx, %c[rbx](%0) \n\t"
+               "push"Q" (%%"R"sp); pop"Q" %c[rcx](%0) \n\t"
+               "mov %%"R"dx, %c[rdx](%0) \n\t"
+               "mov %%"R"si, %c[rsi](%0) \n\t"
+               "mov %%"R"di, %c[rdi](%0) \n\t"
+               "mov %%"R"bp, %c[rbp](%0) \n\t"
 #ifdef CONFIG_X86_64
-               "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"
@@ -3039,28 +3035,16 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
                "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](%0) \n\t"
-
-               "pop  %%rbp; pop  %%rbp; pop  %%rdx \n\t"
-#else
-               "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](%0) \n\t"
-
-               "pop %%ebp; pop %%ebp; pop %%edx \n\t"
 #endif
+               "mov %%cr2, %%"R"ax   \n\t"
+               "mov %%"R"ax, %c[cr2](%0) \n\t"
+
+               "pop  %%"R"bp; pop  %%"R"bp; pop  %%"R"dx \n\t"
                "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)),
+               [host_rsp]"i"(offsetof(struct vcpu_vmx, host_rsp)),
                [rax]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_RAX])),
                [rbx]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_RBX])),
                [rcx]"i"(offsetof(struct vcpu_vmx, vcpu.arch.regs[VCPU_REGS_RCX])),
@@ -3080,11 +3064,9 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 #endif
                [cr2]"i"(offsetof(struct vcpu_vmx, vcpu.arch.cr2))
              : "cc", "memory"
+               , R"bx", R"di", R"si"
 #ifdef CONFIG_X86_64
-               , "rbx", "rdi", "rsi"
                , "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
-#else
-               , "ebx", "edi", "rsi"
 #endif
              );
 
@@ -3114,6 +3096,9 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
        vmx_complete_interrupts(vmx);
 }
 
+#undef R
+#undef Q
+
 static void vmx_free_vmcs(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);