|
@@ -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,
|
|
@@ -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;
|