diff options
author | Jan Kiszka <jan.kiszka@web.de> | 2009-10-18 07:24:44 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2009-12-03 02:32:19 -0500 |
commit | 94fe45da48f921d01d8ff02a0ad54ee9c326d7f0 (patch) | |
tree | 7bf7482bcbe690313909d5f2770384f853562a2d /arch/x86/kvm/x86.c | |
parent | ffde22ac53b6d6b1d7206f1172176a667eead778 (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.c | 47 |
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 | } |
236 | EXPORT_SYMBOL_GPL(kvm_require_cpl); | 236 | EXPORT_SYMBOL_GPL(kvm_require_cpl); |
237 | 237 | ||
238 | unsigned 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 | } | ||
247 | EXPORT_SYMBOL_GPL(kvm_get_rflags); | ||
248 | |||
249 | void 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 | } | ||
255 | EXPORT_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 | ||
5021 | unsigned 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 | } | ||
5030 | EXPORT_SYMBOL_GPL(kvm_get_rflags); | ||
5031 | |||
5032 | void 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 | } | ||
5041 | EXPORT_SYMBOL_GPL(kvm_set_rflags); | ||
5042 | |||
5034 | EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_exit); | 5043 | EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_exit); |
5035 | EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_inj_virq); | 5044 | EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_inj_virq); |
5036 | EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_page_fault); | 5045 | EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_page_fault); |