summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Bruning <max@joyent.com>2011-05-18 22:28:02 -0700
committerMax Bruning <max@joyent.com>2011-05-18 22:28:02 -0700
commit2b9c6b5cbe083dcc307820bbf2c99d78ce4dd1d9 (patch)
treed3d953b12e328cde074e0718ca02f2b8d0aa44b0
parent5e259ec6e518babe3a8cf98d08854780d5b2bd84 (diff)
downloadillumos-kvm-2b9c6b5cbe083dcc307820bbf2c99d78ce4dd1d9.tar.gz
HVM-217 hat_pfnum call results in mutex_enter: adaptive at high PIL panic
-rw-r--r--kvm.c29
-rw-r--r--kvm.h2
-rw-r--r--kvm_i8254.c70
-rw-r--r--kvm_irq.c7
-rw-r--r--kvm_lapic.c18
-rw-r--r--kvm_subr.c2
-rw-r--r--kvm_x86.c65
7 files changed, 117 insertions, 76 deletions
diff --git a/kvm.c b/kvm.c
index 0e054f8..ac96d15 100644
--- a/kvm.c
+++ b/kvm.c
@@ -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)) {
diff --git a/kvm.h b/kvm.h
index 3f2ac61..dfe7280 100644
--- a/kvm.h
+++ b/kvm.h
@@ -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
+}
diff --git a/kvm_irq.c b/kvm_irq.c
index 7d698b6..d943ac9 100644
--- a/kvm_irq.c
+++ b/kvm_irq.c
@@ -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
+}
diff --git a/kvm_subr.c b/kvm_subr.c
index 44f045c..b384a29 100644
--- a/kvm_subr.c
+++ b/kvm_subr.c
@@ -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);
diff --git a/kvm_x86.c b/kvm_x86.c
index 0b8ccc6..d678552 100644
--- a/kvm_x86.c
+++ b/kvm_x86.c
@@ -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);
}