diff options
author | Max Bruning <max@joyent.com> | 2011-05-18 22:28:02 -0700 |
---|---|---|
committer | Max Bruning <max@joyent.com> | 2011-05-18 22:28:02 -0700 |
commit | 2b9c6b5cbe083dcc307820bbf2c99d78ce4dd1d9 (patch) | |
tree | d3d953b12e328cde074e0718ca02f2b8d0aa44b0 | |
parent | 5e259ec6e518babe3a8cf98d08854780d5b2bd84 (diff) | |
download | illumos-kvm-2b9c6b5cbe083dcc307820bbf2c99d78ce4dd1d9.tar.gz |
HVM-217 hat_pfnum call results in mutex_enter: adaptive at high PIL panic
-rw-r--r-- | kvm.c | 29 | ||||
-rw-r--r-- | kvm.h | 2 | ||||
-rw-r--r-- | kvm_i8254.c | 70 | ||||
-rw-r--r-- | kvm_irq.c | 7 | ||||
-rw-r--r-- | kvm_lapic.c | 18 | ||||
-rw-r--r-- | kvm_subr.c | 2 | ||||
-rw-r--r-- | kvm_x86.c | 65 |
7 files changed, 117 insertions, 76 deletions
@@ -2251,11 +2251,7 @@ kvm_mmu_zap_page(struct kvm *kvm, struct kvm_mmu_page *sp) sp->role.invalid = 1; if (!list_link_active(&sp->link)) list_insert_head(&kvm->arch.active_mmu_pages, sp); -#ifdef XXX kvm_reload_remote_mmus(kvm); -#else - XXX_KVM_PROBE; -#endif } kvm_mmu_reset_last_pte_updated(kvm); @@ -4644,20 +4640,18 @@ out: #define __ex(x) __kvm_handle_fault_on_reboot(x) void -vmcs_clear(struct vmcs *vmcs) +vmcs_clear(uint64_t vmcs_pa) { unsigned char error; - uint64_t phys_addr = (hat_getpfnum(kas.a_hat, (caddr_t)vmcs) << - PAGESHIFT) | ((uint64_t)vmcs & PAGEOFFSET); /*CSTYLED*/ __asm__ volatile (__ex(ASM_VMX_VMCLEAR_RAX) "\n\tsetna %0\n" - : "=g"(error) : "a"(&phys_addr), "m"(phys_addr) + : "=g"(error) : "a"(&vmcs_pa), "m"(vmcs_pa) : "cc", "memory"); if (error) - cmn_err(CE_PANIC, "kvm: vmclear fail: %p/%lx\n", - vmcs, phys_addr); + cmn_err(CE_PANIC, "kvm: vmclear fail: %lx\n", + vmcs_pa); } void @@ -4669,7 +4663,7 @@ __vcpu_clear(void *arg) vmx->vmcs->revision_id = vmcs_config.revision_id; if (vmx->vcpu.cpu == cpu) - vmcs_clear(vmx->vmcs); + vmcs_clear(vmx->vmcs_pa); if (current_vmcs[cpu] == vmx->vmcs) current_vmcs[cpu] = NULL; @@ -5019,6 +5013,11 @@ vmx_vcpu_setup(struct vcpu_vmx *vmx) return (0); } +static void kvm_migrate_timers(struct kvm_vcpu *vcpu) +{ + set_bit(KVM_REQ_MIGRATE_TIMER, &vcpu->requests); +} + /* * Switches to specified vcpu, until a matching vcpu_put(), but assumes * vcpu mutex is already taken. @@ -5033,11 +5032,7 @@ vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu) if (vcpu->cpu != cpu) { vcpu_clear(vmx); -#ifdef XXX kvm_migrate_timers(vcpu); -#else - XXX_KVM_PROBE; -#endif set_bit(KVM_REQ_TLB_FLUSH, &vcpu->requests); #ifdef XXX kpreempt_disable(); @@ -12007,11 +12002,7 @@ vcpu_enter_guest(struct kvm_vcpu *vcpu) if (vcpu->requests) { if (test_and_clear_bit(KVM_REQ_MIGRATE_TIMER, &vcpu->requests)) { -#ifdef XXX __kvm_migrate_timers(vcpu); -#else - XXX_KVM_PROBE; -#endif } if (test_and_clear_bit(KVM_REQ_KVMCLOCK_UPDATE, &vcpu->requests)) { @@ -1818,6 +1818,8 @@ typedef struct vcpu_vmx { uint64_t msr_guest_kernel_gs_base; #endif struct vmcs *vmcs; + uint64_t vmcs_pa; /* physical address of vmcs for this vmx */ + struct { int loaded; unsigned short fs_sel, gs_sel, ldt_sel; diff --git a/kvm_i8254.c b/kvm_i8254.c index 78fef5a..bc8fd1b 100644 --- a/kvm_i8254.c +++ b/kvm_i8254.c @@ -755,32 +755,6 @@ fail: return (NULL); } -void -kvm_free_pit(struct kvm *kvmp) -{ - struct kvm_timer *kptp; - - if (kvmp->arch.vpit == NULL) - return; - - mutex_enter(&kvmp->arch.vpit->pit_state.lock); - kvm_unregister_irq_mask_notifier(kvmp, 0, - &kvmp->arch.vpit->mask_notifier); - kvm_unregister_irq_ack_notifier(kvmp, - &kvmp->arch.vpit->pit_state.irq_ack_notifier); - mutex_exit(&kvmp->arch.vpit->pit_state.lock); - - mutex_enter(&cpu_lock); - kptp = &kvmp->arch.vpit->pit_state.pit_timer; - if (kptp->active) - cyclic_remove(kptp->kvm_cyclic_id); - mutex_exit(&cpu_lock); - mutex_destroy(&kvmp->arch.vpit->pit_state.lock); - kvm_free_irq_source_id(kvmp, kvmp->arch.vpit->irq_source_id); - kmem_free(kvmp->arch.vpit, sizeof (struct kvm_pit)); - kvmp->arch.vpit = NULL; -} - static void __inject_pit_timer_intr(struct kvm *kvm) { @@ -839,3 +813,47 @@ kvm_inject_pit_timer_irqs(struct kvm_vcpu *vcpu) __inject_pit_timer_intr(kvm); } } + +void +kvm_free_pit(struct kvm *kvmp) +{ + struct kvm_timer *kptp; + + if (kvmp->arch.vpit == NULL) + return; + + mutex_enter(&kvmp->arch.vpit->pit_state.lock); + kvm_unregister_irq_mask_notifier(kvmp, 0, + &kvmp->arch.vpit->mask_notifier); + kvm_unregister_irq_ack_notifier(kvmp, + &kvmp->arch.vpit->pit_state.irq_ack_notifier); + mutex_exit(&kvmp->arch.vpit->pit_state.lock); + + mutex_enter(&cpu_lock); + kptp = &kvmp->arch.vpit->pit_state.pit_timer; + if (kptp->active) + cyclic_remove(kptp->kvm_cyclic_id); + mutex_exit(&cpu_lock); + mutex_destroy(&kvmp->arch.vpit->pit_state.lock); + kvm_free_irq_source_id(kvmp, kvmp->arch.vpit->irq_source_id); + kmem_free(kvmp->arch.vpit, sizeof (struct kvm_pit)); + kvmp->arch.vpit = NULL; +} + +void +__kvm_migrate_pit_timer(struct kvm_vcpu *vcpu) +{ +#ifdef XXX + struct kvm_pit *pit = vcpu->kvm->arch.vpit; + struct hrtimer *timer; + + if (!kvm_vcpu_is_bsp(vcpu) || !pit) + return; + + timer = &pit->pit_state.pit_timer.timer; + if (hrtimer_cancel_p(timer)) + kvm_hrtimer_start_expires(timer, HRTIMER_MODE_ABS); +#else + XXX_KVM_PROBE; +#endif +} @@ -91,3 +91,10 @@ kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id) unlock: mutex_exit(&kvm->irq_lock); } + +void +__kvm_migrate_timers(struct kvm_vcpu *vcpu) +{ + __kvm_migrate_apic_timer(vcpu); + __kvm_migrate_pit_timer(vcpu); +} diff --git a/kvm_lapic.c b/kvm_lapic.c index 3253137..54db1e6 100644 --- a/kvm_lapic.c +++ b/kvm_lapic.c @@ -122,3 +122,21 @@ kvm_free_lapic(struct kvm_vcpu *vcpu) kmem_free(vcpu->arch.apic, sizeof (struct kvm_lapic)); } + +void +__kvm_migrate_apic_timer(struct kvm_vcpu *vcpu) +{ +#ifdef XXX + struct kvm_lapic *apic = vcpu->arch.apic; + struct hrtimer *timer; + + if (!apic) + return; + + timer = &apic->lapic_timer.timer; + if (hrtimer_cancel_p(timer)) + kvm_hrtimer_start_expires(timer, HRTIMER_MODE_ABS); +#else + XXX_KVM_PROBE; +#endif +} @@ -184,7 +184,7 @@ unsigned long kvm_read_tr_base(void) return segment_base(tr); } -static int +int kvm_xcall_func(kvm_xcall_t func, void *arg) { (*func)(arg); @@ -22,6 +22,7 @@ #include <sys/mman.h> #include <sys/mach_mmu.h> #include <sys/int_limits.h> +#include <sys/x_call.h> #include "msr-index.h" #include "msr.h" @@ -1714,7 +1715,7 @@ extern int enable_ept; extern int enable_unrestricted_guest; extern int emulate_invalid_guest_state; -extern void vmcs_clear(struct vmcs *vmcs); +extern void vmcs_clear(uint64_t vmcs_pa); extern void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu); extern void vmx_vcpu_put(struct kvm_vcpu *vcpu); @@ -1835,6 +1836,9 @@ vmx_create_vcpu(struct kvm *kvm, unsigned int id) return (NULL); } + vmx->vmcs_pa = (hat_getpfnum(kas.a_hat, (caddr_t)vmx->vmcs) << + PAGESHIFT) | ((int64_t)(vmx->vmcs) & 0xfff); + kpreempt_disable(); cpu = curthread->t_cpu->cpu_seqid; @@ -1842,7 +1846,7 @@ vmx_create_vcpu(struct kvm *kvm, unsigned int id) cmn_err(CE_NOTE, "vmcs revision_id = %x\n", vmcs_config.revision_id); vmx->vmcs->revision_id = vmcs_config.revision_id; - vmcs_clear(vmx->vmcs); + vmcs_clear(vmx->vmcs_pa); vmx_vcpu_load(&vmx->vcpu, cpu); err = vmx_vcpu_setup(vmx); @@ -3872,51 +3876,52 @@ kvm_read_guest_atomic(struct kvm *kvm, gpa_t gpa, void *data, unsigned long len) return (0); } +extern void kvm_xcall(processorid_t cpu, kvm_xcall_t func, void *arg); +extern int kvm_xcall_func(kvm_xcall_t func, void *arg); + +static void +ack_flush(void *_completed) +{ +} + +extern int kvm_xcall_func(kvm_xcall_t func, void *arg); + int make_all_cpus_request(struct kvm *kvm, unsigned int req) { - int i, cpu, me; + int i; + cpuset_t set; + processorid_t me, cpu; #ifdef XXX_KVM_DECLARATION cpumask_var_t cpus; #endif - int called = 1; + int called = 0; struct kvm_vcpu *vcpu; -#ifdef XXX - zalloc_cpumask_var(&cpus, GFP_ATOMIC); + CPUSET_ZERO(set); + mutex_enter(&kvm->requests_lock); - me = smp_processor_id(); - kvm_for_each_vcpu(i, vcpu, kvm) { -#else - XXX_KVM_PROBE; + me = curthread->t_cpu->cpu_id; for (i = 0; i < 1; i++) { vcpu = kvm->vcpus[i]; if (!vcpu) - return (0); -#endif - + break; if (test_and_set_bit(req, &vcpu->requests)) continue; cpu = vcpu->cpu; -#ifdef XXX - if (cpus != NULL && cpu != -1 && cpu != me) - cpumask_set_cpu(cpu, cpus); -#else - XXX_KVM_PROBE; -#endif + if (cpu != -1 && cpu != me) + CPUSET_ADD(set, cpu); + } + if (CPUSET_ISNULL(set)) + kvm_xcall(KVM_CPUALL, ack_flush, NULL); + else { + kpreempt_disable(); + xc_sync((xc_arg_t) ack_flush, (xc_arg_t) NULL, + 0, CPUSET2BV(set), (xc_func_t) kvm_xcall_func); + kpreempt_enable(); } -#ifdef XXX - if (unlikely(cpus == NULL)) - smp_call_function_many(cpu_online_mask, ack_flush, NULL, 1); - else if (!cpumask_empty(cpus)) - smp_call_function_many(cpus, ack_flush, NULL, 1); - else - called = false; mutex_exit(&kvm->requests_lock); - free_cpumask_var(cpus); -#else - XXX_KVM_PROBE; -#endif + called = 1; return (called); } |