]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
KVM: x86: Honor KVM_GUESTDBG_USE_HW_BP when emulating MOV DR (in emulator)
authorHou Wenlong <houwenlong.hwl@antgroup.com>
Fri, 15 May 2026 22:26:32 +0000 (15:26 -0700)
committerSean Christopherson <seanjc@google.com>
Thu, 21 May 2026 21:33:12 +0000 (14:33 -0700)
When emulating a MOV DR instruction, honor KVM_GUESTDBG_USE_HW_BP when
checking DR7.GD, and if there is a general-detect #DB, route it to host
userspace as appropriate.  Consulting only the guest's actual DR7 causes
KVM to fail to report a DR access to userspace (assuming the guest itself
doesn't have DR7.GD=1).

Fixes: ae675ef01cd8 ("KVM: x86: Wire-up hardware breakpoints for guest debugging")
Suggested-by: Lai Jiangshan <jiangshan.ljs@antgroup.com>
Signed-off-by: Hou Wenlong <houwenlong.hwl@antgroup.com>
[sean: only expose effective DR7 to emulator, massage changelog]
Link: https://patch.msgid.link/20260515222638.1949982-5-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
arch/x86/kvm/emulate.c
arch/x86/kvm/kvm_emulate.h
arch/x86/kvm/x86.c

index 510244555a74bc54600b5f5ae61a0b5a6d53c6bd..dd0e19af49972042955b6e3a285470d7e33a36aa 100644 (file)
@@ -3848,7 +3848,7 @@ static int check_dr_read(struct x86_emulate_ctxt *ctxt)
        if ((cr4 & X86_CR4_DE) && (dr == 4 || dr == 5))
                return emulate_ud(ctxt);
 
-       if (ctxt->ops->get_dr(ctxt, 7) & DR7_GD)
+       if (ctxt->ops->get_effective_dr7(ctxt) & DR7_GD)
                return emulate_db(ctxt, DR6_BD);
 
        return X86EMUL_CONTINUE;
index bb2a2aee0e13cd48793f31efe005c7b33ae0a454..ee5004beeb4d11da8f4f694161a9ef014fed8f49 100644 (file)
@@ -215,6 +215,7 @@ struct x86_emulate_ops {
        ulong (*get_cr)(struct x86_emulate_ctxt *ctxt, int cr);
        int (*set_cr)(struct x86_emulate_ctxt *ctxt, int cr, ulong val);
        int (*cpl)(struct x86_emulate_ctxt *ctxt);
+       ulong (*get_effective_dr7)(struct x86_emulate_ctxt *ctxt);
        ulong (*get_dr)(struct x86_emulate_ctxt *ctxt, int dr);
        int (*set_dr)(struct x86_emulate_ctxt *ctxt, int dr, ulong value);
        int (*set_msr_with_filter)(struct x86_emulate_ctxt *ctxt, u32 msr_index, u64 data);
index af6f3b5d2f3d85cfa5a60206a63d847958c5776d..42ab2fd0cb9f6f45a9f6f429c56bf0b286d348d2 100644 (file)
@@ -1606,6 +1606,14 @@ unsigned long kvm_get_dr(struct kvm_vcpu *vcpu, int dr)
 }
 EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_get_dr);
 
+static unsigned long kvm_get_effective_dr7(struct kvm_vcpu *vcpu)
+{
+       if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)
+               return vcpu->arch.guest_debug_dr7;
+
+       return vcpu->arch.dr7;
+}
+
 int kvm_emulate_rdpmc(struct kvm_vcpu *vcpu)
 {
        u32 pmc = kvm_rcx_read(vcpu);
@@ -8549,6 +8557,11 @@ static void emulator_wbinvd(struct x86_emulate_ctxt *ctxt)
        kvm_emulate_wbinvd_noskip(emul_to_vcpu(ctxt));
 }
 
+static unsigned long emulator_get_effective_dr7(struct x86_emulate_ctxt *ctxt)
+{
+       return kvm_get_effective_dr7(emul_to_vcpu(ctxt));
+}
+
 static unsigned long emulator_get_dr(struct x86_emulate_ctxt *ctxt, int dr)
 {
        return kvm_get_dr(emul_to_vcpu(ctxt), dr);
@@ -8931,6 +8944,7 @@ static const struct x86_emulate_ops emulate_ops = {
        .get_cr              = emulator_get_cr,
        .set_cr              = emulator_set_cr,
        .cpl                 = emulator_get_cpl,
+       .get_effective_dr7   = emulator_get_effective_dr7,
        .get_dr              = emulator_get_dr,
        .set_dr              = emulator_set_dr,
        .set_msr_with_filter = emulator_set_msr_with_filter,
@@ -8977,23 +8991,36 @@ static void toggle_interruptibility(struct kvm_vcpu *vcpu, u32 mask)
        }
 }
 
-static void kvm_inject_emulated_db(struct kvm_vcpu *vcpu, unsigned long dr6)
+static int kvm_inject_emulated_db(struct kvm_vcpu *vcpu, unsigned long dr6)
 {
+       struct kvm_run *kvm_run = vcpu->run;
+
+       if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP) {
+               kvm_run->debug.arch.dr6 = dr6 | DR6_ACTIVE_LOW;
+               kvm_run->debug.arch.pc = kvm_get_linear_rip(vcpu);
+               kvm_run->debug.arch.exception = DB_VECTOR;
+               kvm_run->exit_reason = KVM_EXIT_DEBUG;
+               return 0;
+       }
+
        kvm_queue_exception_p(vcpu, DB_VECTOR, dr6);
+       return 1;
 }
 
-static void inject_emulated_exception(struct kvm_vcpu *vcpu)
+static int inject_emulated_exception(struct kvm_vcpu *vcpu)
 {
        struct x86_exception *ex = &vcpu->arch.emulate_ctxt->exception;
 
        if (ex->vector == DB_VECTOR)
-               kvm_inject_emulated_db(vcpu, ex->dr6);
-       else if (ex->vector == PF_VECTOR)
+               return kvm_inject_emulated_db(vcpu, ex->dr6);
+
+       if (ex->vector == PF_VECTOR)
                kvm_inject_emulated_page_fault(vcpu, ex);
        else if (ex->error_code_valid)
                kvm_queue_exception_e(vcpu, ex->vector, ex->error_code);
        else
                kvm_queue_exception(vcpu, ex->vector);
+       return 1;
 }
 
 static struct x86_emulate_ctxt *alloc_emulate_ctxt(struct kvm_vcpu *vcpu)
@@ -9502,8 +9529,7 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa,
                                 */
                                WARN_ON_ONCE(ctxt->exception.vector == UD_VECTOR ||
                                             exception_type(ctxt->exception.vector) == EXCPT_TRAP);
-                               inject_emulated_exception(vcpu);
-                               return 1;
+                               return inject_emulated_exception(vcpu);
                        }
                        return handle_emulation_failure(vcpu, emulation_type);
                }
@@ -9598,8 +9624,7 @@ restart:
        if (ctxt->have_exception) {
                WARN_ON_ONCE(vcpu->mmio_needed && !vcpu->mmio_is_write);
                vcpu->mmio_needed = false;
-               r = 1;
-               inject_emulated_exception(vcpu);
+               r = inject_emulated_exception(vcpu);
        } else if (vcpu->arch.pio.count) {
                if (!vcpu->arch.pio.in) {
                        /* FIXME: return into emulator if single-stepping.  */