X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fkvm%2Fsvm.c;h=4e04e49a2f1c35f626fa24d3d5d3f1ea5d115869;hb=68fbda7de07e56eb90dd6e58a162527411b388b1;hp=a347b61644cd0f8f7e30f7ff1036964ead938578;hpb=b6958ce44a11a9e9425d2b67a653b1ca2a27796f;p=linux-2.6 diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c index a347b61644..4e04e49a2f 100644 --- a/drivers/kvm/svm.c +++ b/drivers/kvm/svm.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include @@ -50,6 +49,8 @@ MODULE_LICENSE("GPL"); #define SVM_FEATURE_LBRV (1 << 1) #define SVM_DEATURE_SVML (1 << 2) +static void kvm_reput_irq(struct vcpu_svm *svm); + static inline struct vcpu_svm *to_svm(struct kvm_vcpu *vcpu) { return container_of(vcpu, struct vcpu_svm, vcpu); @@ -376,8 +377,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) @@ -495,6 +494,7 @@ static void init_vmcb(struct vmcb *vmcb) */ /* (1ULL << INTERCEPT_SELECTIVE_CR0) | */ (1ULL << INTERCEPT_CPUID) | + (1ULL << INTERCEPT_INVD) | (1ULL << INTERCEPT_HLT) | (1ULL << INTERCEPT_INVLPGA) | (1ULL << INTERCEPT_IOIO_PROT) | @@ -508,6 +508,7 @@ static void init_vmcb(struct vmcb *vmcb) (1ULL << INTERCEPT_STGI) | (1ULL << INTERCEPT_CLGI) | (1ULL << INTERCEPT_SKINIT) | + (1ULL << INTERCEPT_WBINVD) | (1ULL << INTERCEPT_MONITOR) | (1ULL << INTERCEPT_MWAIT); @@ -557,6 +558,19 @@ static void init_vmcb(struct vmcb *vmcb) /* rdx = ?? */ } +static void svm_vcpu_reset(struct kvm_vcpu *vcpu) +{ + struct vcpu_svm *svm = to_svm(vcpu); + + init_vmcb(svm->vmcb); + + if (vcpu->vcpu_id != 0) { + svm->vmcb->save.rip = 0; + svm->vmcb->save.cs.base = svm->vcpu.sipi_vector << 12; + svm->vmcb->save.cs.selector = svm->vcpu.sipi_vector << 8; + } +} + static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id) { struct vcpu_svm *svm; @@ -633,6 +647,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++) @@ -648,6 +663,7 @@ static void svm_vcpu_put(struct kvm_vcpu *vcpu) wrmsrl(host_save_user_msrs[i], svm->host_user_msrs[i]); rdtscll(vcpu->host_tsc); + kvm_put_guest_fpu(vcpu); } static void svm_vcpu_decache(struct kvm_vcpu *vcpu) @@ -725,14 +741,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); @@ -843,6 +851,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 @@ -870,11 +888,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]; @@ -956,7 +969,7 @@ static int pf_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) ++svm->vcpu.stat.mmio_exits; return 0; case EMULATE_FAIL: - vcpu_printf(&svm->vcpu, "%s: emulate fail\n", __FUNCTION__); + kvm_report_emulation_failure(&svm->vcpu, "pagetable"); break; default: BUG(); @@ -1237,6 +1250,7 @@ static int (*svm_exit_handlers[])(struct vcpu_svm *svm, [SVM_EXIT_VINTR] = interrupt_window_interception, /* [SVM_EXIT_CR0_SEL_WRITE] = emulate_on_interception, */ [SVM_EXIT_CPUID] = cpuid_interception, + [SVM_EXIT_INVD] = emulate_on_interception, [SVM_EXIT_HLT] = halt_interception, [SVM_EXIT_INVLPG] = emulate_on_interception, [SVM_EXIT_INVLPGA] = invalid_op_interception, @@ -1251,15 +1265,26 @@ static int (*svm_exit_handlers[])(struct vcpu_svm *svm, [SVM_EXIT_STGI] = invalid_op_interception, [SVM_EXIT_CLGI] = invalid_op_interception, [SVM_EXIT_SKINIT] = invalid_op_interception, + [SVM_EXIT_WBINVD] = emulate_on_interception, [SVM_EXIT_MONITOR] = invalid_op_interception, [SVM_EXIT_MWAIT] = invalid_op_interception, }; -static int handle_exit(struct vcpu_svm *svm, struct kvm_run *kvm_run) +static int handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) { + struct vcpu_svm *svm = to_svm(vcpu); u32 exit_code = svm->vmcb->control.exit_code; + kvm_reput_irq(svm); + + if (svm->vmcb->control.exit_code == SVM_EXIT_ERR) { + kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY; + kvm_run->fail_entry.hardware_entry_failure_reason + = svm->vmcb->control.exit_code; + return 0; + } + if (is_external_interrupt(svm->vmcb->control.exit_int_info) && exit_code != SVM_EXIT_EXCP_BASE + PF_VECTOR) printk(KERN_ERR "%s: unexpected exit_ini_info 0x%x " @@ -1310,11 +1335,20 @@ static inline void svm_inject_irq(struct vcpu_svm *svm, int irq) ((/*control->int_vector >> 4*/ 0xf) << V_INTR_PRIO_SHIFT); } -static void svm_intr_assist(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 kvm_vcpu *vcpu) +{ + struct vcpu_svm *svm = to_svm(vcpu); struct vmcb *vmcb = svm->vmcb; int intr_vector = -1; + 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 & @@ -1327,7 +1361,7 @@ static void svm_intr_assist(struct vcpu_svm *svm) if (vmcb->control.int_ctl & V_IRQ_MASK) return; - if (!kvm_cpu_has_interrupt(&svm->vcpu)) + if (!kvm_cpu_has_interrupt(vcpu)) return; if (!(vmcb->save.rflags & X86_EFLAGS_IF) || @@ -1339,8 +1373,9 @@ static void svm_intr_assist(struct vcpu_svm *svm) return; } /* Okay, we can deliver the interrupt: grab it and update PIC state. */ - intr_vector = kvm_cpu_get_interrupt(&svm->vcpu); + 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) @@ -1370,9 +1405,10 @@ static void svm_do_inject_vector(struct vcpu_svm *svm) svm_inject_irq(svm, irq); } -static void do_interrupt_requests(struct vcpu_svm *svm, +static void do_interrupt_requests(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { + struct vcpu_svm *svm = to_svm(vcpu); struct vmcb_control_area *control = &svm->vmcb->control; svm->vcpu.interrupt_window_open = @@ -1395,35 +1431,6 @@ static void do_interrupt_requests(struct vcpu_svm *svm, control->intercept &= ~(1ULL << INTERCEPT_VINTR); } -static void post_kvm_run_save(struct vcpu_svm *svm, - struct kvm_run *kvm_run) -{ - 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 = get_cr8(&svm->vcpu); - kvm_run->apic_base = kvm_get_apic_base(&svm->vcpu); -} - -/* - * 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 vcpu_svm *svm, - struct kvm_run *kvm_run) -{ - return (!svm->vcpu.irq_summary && - kvm_run->request_interrupt_window && - svm->vcpu.interrupt_window_open && - (svm->vmcb->save.rflags & X86_EFLAGS_IF)); -} - static void save_db_regs(unsigned long *db_regs) { asm volatile ("mov %%dr0, %0" : "=r"(db_regs[0])); @@ -1445,38 +1452,16 @@ static void svm_flush_tlb(struct kvm_vcpu *vcpu) force_new_asid(vcpu); } -static int svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +static void svm_prepare_guest_switch(struct kvm_vcpu *vcpu) +{ +} + +static void svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { struct vcpu_svm *svm = to_svm(vcpu); u16 fs_selector; u16 gs_selector; u16 ldt_selector; - int r; - -again: - r = kvm_mmu_reload(vcpu); - if (unlikely(r)) - return r; - - 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)) - svm_flush_tlb(vcpu); pre_svm_run(svm); @@ -1495,10 +1480,9 @@ again: load_db_regs(svm->db_regs); } - if (vcpu->fpu_active) { - fx_save(&vcpu->host_fx_image); - fx_restore(&vcpu->guest_fx_image); - } + clgi(); + + local_irq_enable(); asm volatile ( #ifdef CONFIG_X86_64 @@ -1606,13 +1590,6 @@ again: #endif : "cc", "memory" ); - vcpu->guest_mode = 0; - - if (vcpu->fpu_active) { - fx_save(&vcpu->guest_fx_image); - fx_restore(&vcpu->host_fx_image); - } - if ((svm->vmcb->save.dr7 & 0xff)) load_db_regs(svm->host_db_regs); @@ -1629,40 +1606,11 @@ again: reload_tss(vcpu); - /* - * Profile KVM exit RIPs: - */ - if (unlikely(prof_on == KVM_PROFILING)) - profile_hit(KVM_PROFILING, - (void *)(unsigned long)svm->vmcb->save.rip); + local_irq_disable(); stgi(); - kvm_reput_irq(svm); - svm->next_rip = 0; - - if (svm->vmcb->control.exit_code == SVM_EXIT_ERR) { - kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY; - kvm_run->fail_entry.hardware_entry_failure_reason - = svm->vmcb->control.exit_code; - post_kvm_run_save(svm, kvm_run); - return 0; - } - - r = handle_exit(svm, kvm_run); - if (r > 0) { - if (dm_request_for_irq_injection(svm, kvm_run)) { - ++vcpu->stat.request_irq_exits; - post_kvm_run_save(svm, kvm_run); - kvm_run->exit_reason = KVM_EXIT_INTR; - return -EINTR; - } - kvm_resched(vcpu); - goto again; - } - post_kvm_run_save(svm, kvm_run); - return r; } static void svm_set_cr3(struct kvm_vcpu *vcpu, unsigned long root) @@ -1735,7 +1683,7 @@ static void svm_check_processor_compat(void *rtn) *(int *)rtn = 0; } -static struct kvm_arch_ops svm_arch_ops = { +static struct kvm_x86_ops svm_x86_ops = { .cpu_has_kvm_support = has_svm, .disabled_by_bios = is_disabled, .hardware_setup = svm_hardware_setup, @@ -1746,7 +1694,9 @@ static struct kvm_arch_ops svm_arch_ops = { .vcpu_create = svm_create_vcpu, .vcpu_free = svm_free_vcpu, + .vcpu_reset = svm_vcpu_reset, + .prepare_guest_switch = svm_prepare_guest_switch, .vcpu_load = svm_vcpu_load, .vcpu_put = svm_vcpu_put, .vcpu_decache = svm_vcpu_decache, @@ -1757,7 +1707,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, @@ -1774,26 +1724,30 @@ 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, .inject_gp = svm_inject_gp, .run = svm_vcpu_run, + .handle_exit = handle_exit, .skip_emulated_instruction = skip_emulated_instruction, .patch_hypercall = svm_patch_hypercall, + .get_irq = svm_get_irq, + .set_irq = svm_set_irq, + .inject_pending_irq = svm_intr_assist, + .inject_pending_vectors = do_interrupt_requests, }; static int __init svm_init(void) { - return kvm_init_arch(&svm_arch_ops, sizeof(struct vcpu_svm), + return kvm_init_x86(&svm_x86_ops, sizeof(struct vcpu_svm), THIS_MODULE); } static void __exit svm_exit(void) { - kvm_exit_arch(); + kvm_exit_x86(); } module_init(svm_init)