diff options
author | Paolo Bonzini <pbonzini@redhat.com> | 2014-02-21 04:32:27 -0500 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2014-03-11 05:46:04 -0400 |
commit | facb0139698923dc7b7d15cafbb319219969f4fd (patch) | |
tree | d2f4e83b00ecfc8d744c8f8af5510bca5a8185cc | |
parent | 5315c716b69f47e1751d09e16c7bd5b559419531 (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.c | 28 |
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 | ||
1687 | static 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 | |||
1686 | static void svm_set_dr7(struct kvm_vcpu *vcpu, unsigned long value) | 1702 | static 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, |