KVM: Hoist SVM's get_cs_db_l_bits into core code.
[safe/jmp/linux-2.6] / drivers / kvm / svm.c
index a83ff01..35f3f83 100644 (file)
@@ -16,6 +16,7 @@
 
 #include "kvm_svm.h"
 #include "x86_emulate.h"
+#include "irq.h"
 
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -375,8 +376,6 @@ static __init int svm_hardware_setup(void)
        void *iopm_va, *msrpm_va;
        int r;
 
-       kvm_emulator_want_group7_invlpg();
-
        iopm_pages = alloc_pages(GFP_KERNEL, IOPM_ALLOC_ORDER);
 
        if (!iopm_pages)
@@ -572,6 +571,12 @@ static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id)
        if (err)
                goto free_svm;
 
+       if (irqchip_in_kernel(kvm)) {
+               err = kvm_create_lapic(&svm->vcpu);
+               if (err < 0)
+                       goto free_svm;
+       }
+
        page = alloc_page(GFP_KERNEL);
        if (!page) {
                err = -ENOMEM;
@@ -626,6 +631,7 @@ static void svm_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
                delta = vcpu->host_tsc - tsc_this;
                svm->vmcb->control.tsc_offset += delta;
                vcpu->cpu = cpu;
+               kvm_migrate_apic_timer(vcpu);
        }
 
        for (i = 0; i < NR_HOST_SAVE_USER_MSRS; i++)
@@ -718,14 +724,6 @@ static void svm_get_segment(struct kvm_vcpu *vcpu,
        var->unusable = !var->present;
 }
 
-static void svm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l)
-{
-       struct vmcb_seg *s = svm_seg(vcpu, VCPU_SREG_CS);
-
-       *db = (s->attrib >> SVM_SELECTOR_DB_SHIFT) & 1;
-       *l = (s->attrib >> SVM_SELECTOR_L_SHIFT) & 1;
-}
-
 static void svm_get_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
@@ -836,6 +834,16 @@ static int svm_guest_debug(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg)
        return -EOPNOTSUPP;
 }
 
+static int svm_get_irq(struct kvm_vcpu *vcpu)
+{
+       struct vcpu_svm *svm = to_svm(vcpu);
+       u32 exit_int_info = svm->vmcb->control.exit_int_info;
+
+       if (is_external_interrupt(exit_int_info))
+               return exit_int_info & SVM_EVTINJ_VEC_MASK;
+       return -1;
+}
+
 static void load_host_msrs(struct kvm_vcpu *vcpu)
 {
 #ifdef CONFIG_X86_64
@@ -863,11 +871,6 @@ static void new_asid(struct vcpu_svm *svm, struct svm_cpu_data *svm_data)
        svm->vmcb->control.asid = svm_data->next_asid++;
 }
 
-static void svm_invlpg(struct kvm_vcpu *vcpu, gva_t address)
-{
-       invlpga(address, to_svm(vcpu)->vmcb->control.asid); // is needed?
-}
-
 static unsigned long svm_get_dr(struct kvm_vcpu *vcpu, int dr)
 {
        return to_svm(vcpu)->db_regs[dr];
@@ -921,7 +924,8 @@ static int pf_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
        enum emulation_result er;
        int r;
 
-       if (is_external_interrupt(exit_int_info))
+       if (!irqchip_in_kernel(kvm) &&
+               is_external_interrupt(exit_int_info))
                push_irq(&svm->vcpu, exit_int_info & SVM_EVTINJ_VEC_MASK);
 
        mutex_lock(&kvm->lock);
@@ -1005,8 +1009,7 @@ static int io_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
        rep = (io_info & SVM_IOIO_REP_MASK) != 0;
        down = (svm->vmcb->save.rflags & X86_EFLAGS_DF) != 0;
 
-       return kvm_setup_pio(&svm->vcpu, kvm_run, in, size, 1, 0,
-                            down, 0, rep, port);
+       return kvm_emulate_pio(&svm->vcpu, kvm_run, in, size, port);
 }
 
 static int nop_on_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
@@ -1186,6 +1189,8 @@ static int msr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
 static int interrupt_window_interception(struct vcpu_svm *svm,
                                   struct kvm_run *kvm_run)
 {
+       svm->vmcb->control.intercept &= ~(1ULL << INTERCEPT_VINTR);
+       svm->vmcb->control.int_ctl &= ~V_IRQ_MASK;
        /*
         * If the user space waits to inject interrupts, exit as soon as
         * possible
@@ -1290,22 +1295,66 @@ static void pre_svm_run(struct vcpu_svm *svm)
 }
 
 
-static inline void inject_irq(struct vcpu_svm *svm)
+static inline void svm_inject_irq(struct vcpu_svm *svm, int irq)
 {
        struct vmcb_control_area *control;
 
        control = &svm->vmcb->control;
-       control->int_vector = pop_irq(&svm->vcpu);
+       control->int_vector = irq;
        control->int_ctl &= ~V_INTR_PRIO_MASK;
        control->int_ctl |= V_IRQ_MASK |
                ((/*control->int_vector >> 4*/ 0xf) << V_INTR_PRIO_SHIFT);
 }
 
-static void reput_irq(struct vcpu_svm *svm)
+static void svm_set_irq(struct kvm_vcpu *vcpu, int irq)
+{
+       struct vcpu_svm *svm = to_svm(vcpu);
+
+       svm_inject_irq(svm, irq);
+}
+
+static void svm_intr_assist(struct vcpu_svm *svm)
+{
+       struct vmcb *vmcb = svm->vmcb;
+       int intr_vector = -1;
+       struct kvm_vcpu *vcpu = &svm->vcpu;
+
+       kvm_inject_pending_timer_irqs(vcpu);
+       if ((vmcb->control.exit_int_info & SVM_EVTINJ_VALID) &&
+           ((vmcb->control.exit_int_info & SVM_EVTINJ_TYPE_MASK) == 0)) {
+               intr_vector = vmcb->control.exit_int_info &
+                             SVM_EVTINJ_VEC_MASK;
+               vmcb->control.exit_int_info = 0;
+               svm_inject_irq(svm, intr_vector);
+               return;
+       }
+
+       if (vmcb->control.int_ctl & V_IRQ_MASK)
+               return;
+
+       if (!kvm_cpu_has_interrupt(vcpu))
+               return;
+
+       if (!(vmcb->save.rflags & X86_EFLAGS_IF) ||
+           (vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK) ||
+           (vmcb->control.event_inj & SVM_EVTINJ_VALID)) {
+               /* unable to deliver irq, set pending irq */
+               vmcb->control.intercept |= (1ULL << INTERCEPT_VINTR);
+               svm_inject_irq(svm, 0x0);
+               return;
+       }
+       /* Okay, we can deliver the interrupt: grab it and update PIC state. */
+       intr_vector = kvm_cpu_get_interrupt(vcpu);
+       svm_inject_irq(svm, intr_vector);
+       kvm_timer_intr_post(vcpu, intr_vector);
+}
+
+static void kvm_reput_irq(struct vcpu_svm *svm)
 {
        struct vmcb_control_area *control = &svm->vmcb->control;
 
-       if (control->int_ctl & V_IRQ_MASK) {
+       if ((control->int_ctl & V_IRQ_MASK)
+           && !irqchip_in_kernel(svm->vcpu.kvm)) {
                control->int_ctl &= ~V_IRQ_MASK;
                push_irq(&svm->vcpu, control->int_vector);
        }
@@ -1314,6 +1363,19 @@ static void reput_irq(struct vcpu_svm *svm)
                !(control->int_state & SVM_INTERRUPT_SHADOW_MASK);
 }
 
+static void svm_do_inject_vector(struct vcpu_svm *svm)
+{
+       struct kvm_vcpu *vcpu = &svm->vcpu;
+       int word_index = __ffs(vcpu->irq_summary);
+       int bit_index = __ffs(vcpu->irq_pending[word_index]);
+       int irq = word_index * BITS_PER_LONG + bit_index;
+
+       clear_bit(bit_index, &vcpu->irq_pending[word_index]);
+       if (!vcpu->irq_pending[word_index])
+               clear_bit(word_index, &vcpu->irq_summary);
+       svm_inject_irq(svm, irq);
+}
+
 static void do_interrupt_requests(struct vcpu_svm *svm,
                                       struct kvm_run *kvm_run)
 {
@@ -1327,7 +1389,7 @@ static void do_interrupt_requests(struct vcpu_svm *svm,
                /*
                 * If interrupts enabled, and not blocked by sti or mov ss. Good.
                 */
-               inject_irq(svm);
+               svm_do_inject_vector(svm);
 
        /*
         * Interrupts blocked.  Wait for unblock.
@@ -1342,12 +1404,15 @@ static void do_interrupt_requests(struct vcpu_svm *svm,
 static void post_kvm_run_save(struct vcpu_svm *svm,
                              struct kvm_run *kvm_run)
 {
-       kvm_run->ready_for_interrupt_injection
-               = (svm->vcpu.interrupt_window_open &&
-                  svm->vcpu.irq_summary == 0);
+       if (irqchip_in_kernel(svm->vcpu.kvm))
+               kvm_run->ready_for_interrupt_injection = 1;
+       else
+               kvm_run->ready_for_interrupt_injection =
+                                        (svm->vcpu.interrupt_window_open &&
+                                         svm->vcpu.irq_summary == 0);
        kvm_run->if_flag = (svm->vmcb->save.rflags & X86_EFLAGS_IF) != 0;
-       kvm_run->cr8 = svm->vcpu.cr8;
-       kvm_run->apic_base = svm->vcpu.apic_base;
+       kvm_run->cr8 = get_cr8(&svm->vcpu);
+       kvm_run->apic_base = kvm_get_apic_base(&svm->vcpu);
 }
 
 /*
@@ -1399,11 +1464,21 @@ again:
        if (unlikely(r))
                return r;
 
-       if (!vcpu->mmio_read_completed)
-               do_interrupt_requests(svm, kvm_run);
-
        clgi();
 
+       if (signal_pending(current)) {
+               stgi();
+               ++vcpu->stat.signal_exits;
+               post_kvm_run_save(svm, kvm_run);
+               kvm_run->exit_reason = KVM_EXIT_INTR;
+               return -EINTR;
+       }
+
+       if (irqchip_in_kernel(vcpu->kvm))
+               svm_intr_assist(svm);
+       else if (!vcpu->mmio_read_completed)
+               do_interrupt_requests(svm, kvm_run);
+
        vcpu->guest_mode = 1;
        if (vcpu->requests)
                if (test_and_clear_bit(KVM_TLB_FLUSH, &vcpu->requests))
@@ -1569,7 +1644,7 @@ again:
 
        stgi();
 
-       reput_irq(svm);
+       kvm_reput_irq(svm);
 
        svm->next_rip = 0;
 
@@ -1583,13 +1658,6 @@ again:
 
        r = handle_exit(svm, kvm_run);
        if (r > 0) {
-               if (signal_pending(current)) {
-                       ++vcpu->stat.signal_exits;
-                       post_kvm_run_save(svm, kvm_run);
-                       kvm_run->exit_reason = KVM_EXIT_INTR;
-                       return -EINTR;
-               }
-
                if (dm_request_for_irq_injection(svm, kvm_run)) {
                        ++vcpu->stat.request_irq_exits;
                        post_kvm_run_save(svm, kvm_run);
@@ -1695,7 +1763,7 @@ static struct kvm_arch_ops svm_arch_ops = {
        .get_segment_base = svm_get_segment_base,
        .get_segment = svm_get_segment,
        .set_segment = svm_set_segment,
-       .get_cs_db_l_bits = svm_get_cs_db_l_bits,
+       .get_cs_db_l_bits = kvm_get_cs_db_l_bits,
        .decache_cr4_guest_bits = svm_decache_cr4_guest_bits,
        .set_cr0 = svm_set_cr0,
        .set_cr3 = svm_set_cr3,
@@ -1712,7 +1780,6 @@ static struct kvm_arch_ops svm_arch_ops = {
        .get_rflags = svm_get_rflags,
        .set_rflags = svm_set_rflags,
 
-       .invlpg = svm_invlpg,
        .tlb_flush = svm_flush_tlb,
        .inject_page_fault = svm_inject_page_fault,
 
@@ -1721,6 +1788,8 @@ static struct kvm_arch_ops svm_arch_ops = {
        .run = svm_vcpu_run,
        .skip_emulated_instruction = skip_emulated_instruction,
        .patch_hypercall = svm_patch_hypercall,
+       .get_irq = svm_get_irq,
+       .set_irq = svm_set_irq,
 };
 
 static int __init svm_init(void)