aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm/x86.c
diff options
context:
space:
mode:
authorJan Kiszka <jan.kiszka@web.de>2009-10-18 07:24:44 -0400
committerAvi Kivity <avi@redhat.com>2009-12-03 02:32:19 -0500
commit94fe45da48f921d01d8ff02a0ad54ee9c326d7f0 (patch)
tree7bf7482bcbe690313909d5f2770384f853562a2d /arch/x86/kvm/x86.c
parentffde22ac53b6d6b1d7206f1172176a667eead778 (diff)
KVM: x86: Fix guest single-stepping while interruptible
Commit 705c5323 opened the doors of hell by unconditionally injecting single-step flags as long as guest_debug signaled this. This doesn't work when the guest branches into some interrupt or exception handler and triggers a vmexit with flag reloading. Fix it by saving cs:rip when user space requests single-stepping and restricting the trace flag injection to this guest code position. Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Diffstat (limited to 'arch/x86/kvm/x86.c')
-rw-r--r--arch/x86/kvm/x86.c47
1 files changed, 28 insertions, 19 deletions
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index bb842db3ee7c..13f30aac460b 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -235,25 +235,6 @@ bool kvm_require_cpl(struct kvm_vcpu *vcpu, int required_cpl)
235} 235}
236EXPORT_SYMBOL_GPL(kvm_require_cpl); 236EXPORT_SYMBOL_GPL(kvm_require_cpl);
237 237
238unsigned long kvm_get_rflags(struct kvm_vcpu *vcpu)
239{
240 unsigned long rflags;
241
242 rflags = kvm_x86_ops->get_rflags(vcpu);
243 if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
244 rflags &= ~(unsigned long)(X86_EFLAGS_TF | X86_EFLAGS_RF);
245 return rflags;
246}
247EXPORT_SYMBOL_GPL(kvm_get_rflags);
248
249void kvm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
250{
251 if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
252 rflags |= X86_EFLAGS_TF | X86_EFLAGS_RF;
253 kvm_x86_ops->set_rflags(vcpu, rflags);
254}
255EXPORT_SYMBOL_GPL(kvm_set_rflags);
256
257/* 238/*
258 * Load the pae pdptrs. Return true is they are all valid. 239 * Load the pae pdptrs. Return true is they are all valid.
259 */ 240 */
@@ -4565,6 +4546,12 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
4565 vcpu->arch.switch_db_regs = (vcpu->arch.dr7 & DR7_BP_EN_MASK); 4546 vcpu->arch.switch_db_regs = (vcpu->arch.dr7 & DR7_BP_EN_MASK);
4566 } 4547 }
4567 4548
4549 if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) {
4550 vcpu->arch.singlestep_cs =
4551 get_segment_selector(vcpu, VCPU_SREG_CS);
4552 vcpu->arch.singlestep_rip = kvm_rip_read(vcpu);
4553 }
4554
4568 /* 4555 /*
4569 * Trigger an rflags update that will inject or remove the trace 4556 * Trigger an rflags update that will inject or remove the trace
4570 * flags. 4557 * flags.
@@ -5031,6 +5018,28 @@ int kvm_arch_interrupt_allowed(struct kvm_vcpu *vcpu)
5031 return kvm_x86_ops->interrupt_allowed(vcpu); 5018 return kvm_x86_ops->interrupt_allowed(vcpu);
5032} 5019}
5033 5020
5021unsigned long kvm_get_rflags(struct kvm_vcpu *vcpu)
5022{
5023 unsigned long rflags;
5024
5025 rflags = kvm_x86_ops->get_rflags(vcpu);
5026 if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
5027 rflags &= ~(unsigned long)(X86_EFLAGS_TF | X86_EFLAGS_RF);
5028 return rflags;
5029}
5030EXPORT_SYMBOL_GPL(kvm_get_rflags);
5031
5032void kvm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
5033{
5034 if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP &&
5035 vcpu->arch.singlestep_cs ==
5036 get_segment_selector(vcpu, VCPU_SREG_CS) &&
5037 vcpu->arch.singlestep_rip == kvm_rip_read(vcpu))
5038 rflags |= X86_EFLAGS_TF | X86_EFLAGS_RF;
5039 kvm_x86_ops->set_rflags(vcpu, rflags);
5040}
5041EXPORT_SYMBOL_GPL(kvm_set_rflags);
5042
5034EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_exit); 5043EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_exit);
5035EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_inj_virq); 5044EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_inj_virq);
5036EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_page_fault); 5045EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_page_fault);