aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2014-02-21 04:32:27 -0500
committerPaolo Bonzini <pbonzini@redhat.com>2014-03-11 05:46:04 -0400
commitfacb0139698923dc7b7d15cafbb319219969f4fd (patch)
treed2f4e83b00ecfc8d744c8f8af5510bca5a8185cc
parent5315c716b69f47e1751d09e16c7bd5b559419531 (diff)
KVM: svm: Allow the guest to run with dirty debug registers
When not running in guest-debug mode (i.e. the guest controls the debug registers, having to take an exit for each DR access is a waste of time. If the guest gets into a state where each context switch causes DR to be saved and restored, this can take away as much as 40% of the execution time from the guest. If the guest is running with vcpu->arch.db == vcpu->arch.eff_db, we can let it write freely to the debug registers and reload them on the next exit. We still need to exit on the first access, so that the KVM_DEBUGREG_WONT_EXIT flag is set in switch_db_regs; after that, further accesses to the debug registers will not cause a vmexit. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r--arch/x86/kvm/svm.c28
1 files changed, 28 insertions, 0 deletions
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 86d802be602d..a449c3d76cba 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -34,6 +34,7 @@
34#include <asm/perf_event.h> 34#include <asm/perf_event.h>
35#include <asm/tlbflush.h> 35#include <asm/tlbflush.h>
36#include <asm/desc.h> 36#include <asm/desc.h>
37#include <asm/debugreg.h>
37#include <asm/kvm_para.h> 38#include <asm/kvm_para.h>
38 39
39#include <asm/virtext.h> 40#include <asm/virtext.h>
@@ -1683,6 +1684,21 @@ static void svm_set_dr6(struct kvm_vcpu *vcpu, unsigned long value)
1683 mark_dirty(svm->vmcb, VMCB_DR); 1684 mark_dirty(svm->vmcb, VMCB_DR);
1684} 1685}
1685 1686
1687static void svm_sync_dirty_debug_regs(struct kvm_vcpu *vcpu)
1688{
1689 struct vcpu_svm *svm = to_svm(vcpu);
1690
1691 get_debugreg(vcpu->arch.db[0], 0);
1692 get_debugreg(vcpu->arch.db[1], 1);
1693 get_debugreg(vcpu->arch.db[2], 2);
1694 get_debugreg(vcpu->arch.db[3], 3);
1695 vcpu->arch.dr6 = svm_get_dr6(vcpu);
1696 vcpu->arch.dr7 = svm->vmcb->save.dr7;
1697
1698 vcpu->arch.switch_db_regs &= ~KVM_DEBUGREG_WONT_EXIT;
1699 set_dr_intercepts(svm);
1700}
1701
1686static void svm_set_dr7(struct kvm_vcpu *vcpu, unsigned long value) 1702static void svm_set_dr7(struct kvm_vcpu *vcpu, unsigned long value)
1687{ 1703{
1688 struct vcpu_svm *svm = to_svm(vcpu); 1704 struct vcpu_svm *svm = to_svm(vcpu);
@@ -2974,6 +2990,17 @@ static int dr_interception(struct vcpu_svm *svm)
2974 unsigned long val; 2990 unsigned long val;
2975 int err; 2991 int err;
2976 2992
2993 if (svm->vcpu.guest_debug == 0) {
2994 /*
2995 * No more DR vmexits; force a reload of the debug registers
2996 * and reenter on this instruction. The next vmexit will
2997 * retrieve the full state of the debug registers.
2998 */
2999 clr_dr_intercepts(svm);
3000 svm->vcpu.arch.switch_db_regs |= KVM_DEBUGREG_WONT_EXIT;
3001 return 1;
3002 }
3003
2977 if (!boot_cpu_has(X86_FEATURE_DECODEASSISTS)) 3004 if (!boot_cpu_has(X86_FEATURE_DECODEASSISTS))
2978 return emulate_on_interception(svm); 3005 return emulate_on_interception(svm);
2979 3006
@@ -4300,6 +4327,7 @@ static struct kvm_x86_ops svm_x86_ops = {
4300 .get_dr6 = svm_get_dr6, 4327 .get_dr6 = svm_get_dr6,
4301 .set_dr6 = svm_set_dr6, 4328 .set_dr6 = svm_set_dr6,
4302 .set_dr7 = svm_set_dr7, 4329 .set_dr7 = svm_set_dr7,
4330 .sync_dirty_debug_regs = svm_sync_dirty_debug_regs,
4303 .cache_reg = svm_cache_reg, 4331 .cache_reg = svm_cache_reg,
4304 .get_rflags = svm_get_rflags, 4332 .get_rflags = svm_get_rflags,
4305 .set_rflags = svm_set_rflags, 4333 .set_rflags = svm_set_rflags,