Skip to content

Commit

Permalink
KVM: x86: handle hardware breakpoints during emulation
Browse files Browse the repository at this point in the history
This lets debugging work better during emulation of invalid
guest state.

The check is done before emulating the instruction, and (in the case
of guest debugging) reuses EMULATE_DO_MMIO to exit with KVM_EXIT_DEBUG.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
  • Loading branch information
Paolo Bonzini committed Jul 29, 2013
1 parent ac0a48c commit 4a1e10d
Showing 1 changed file with 66 additions and 0 deletions.
66 changes: 66 additions & 0 deletions arch/x86/kvm/x86.c
Original file line number Diff line number Diff line change
Expand Up @@ -4956,6 +4956,62 @@ static bool retry_instruction(struct x86_emulate_ctxt *ctxt,
static int complete_emulated_mmio(struct kvm_vcpu *vcpu);
static int complete_emulated_pio(struct kvm_vcpu *vcpu);

static int kvm_vcpu_check_hw_bp(unsigned long addr, u32 type, u32 dr7,
unsigned long *db)
{
u32 dr6 = 0;
int i;
u32 enable, rwlen;

enable = dr7;
rwlen = dr7 >> 16;
for (i = 0; i < 4; i++, enable >>= 2, rwlen >>= 4)
if ((enable & 3) && (rwlen & 15) == type && db[i] == addr)
dr6 |= (1 << i);
return dr6;
}

static bool kvm_vcpu_check_breakpoint(struct kvm_vcpu *vcpu, int *r)
{
struct kvm_run *kvm_run = vcpu->run;
unsigned long eip = vcpu->arch.emulate_ctxt.eip;
u32 dr6 = 0;

if (unlikely(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP) &&
(vcpu->arch.guest_debug_dr7 & DR7_BP_EN_MASK)) {
dr6 = kvm_vcpu_check_hw_bp(eip, 0,
vcpu->arch.guest_debug_dr7,
vcpu->arch.eff_db);

if (dr6 != 0) {
kvm_run->debug.arch.dr6 = dr6 | DR6_FIXED_1;
kvm_run->debug.arch.pc = kvm_rip_read(vcpu) +
get_segment_base(vcpu, VCPU_SREG_CS);

kvm_run->debug.arch.exception = DB_VECTOR;
kvm_run->exit_reason = KVM_EXIT_DEBUG;
*r = EMULATE_USER_EXIT;
return true;
}
}

if (unlikely(vcpu->arch.dr7 & DR7_BP_EN_MASK)) {
dr6 = kvm_vcpu_check_hw_bp(eip, 0,
vcpu->arch.dr7,
vcpu->arch.db);

if (dr6 != 0) {
vcpu->arch.dr6 &= ~15;
vcpu->arch.dr6 |= dr6;
kvm_queue_exception(vcpu, DB_VECTOR);
*r = EMULATE_DONE;
return true;
}
}

return false;
}

int x86_emulate_instruction(struct kvm_vcpu *vcpu,
unsigned long cr2,
int emulation_type,
Expand All @@ -4976,6 +5032,16 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu,

if (!(emulation_type & EMULTYPE_NO_DECODE)) {
init_emulate_ctxt(vcpu);

/*
* We will reenter on the same instruction since
* we do not set complete_userspace_io. This does not
* handle watchpoints yet, those would be handled in
* the emulate_ops.
*/
if (kvm_vcpu_check_breakpoint(vcpu, &r))
return r;

ctxt->interruptibility = 0;
ctxt->have_exception = false;
ctxt->perm_ok = false;
Expand Down

0 comments on commit 4a1e10d

Please sign in to comment.