As per the AMD APM[1], DR6[BusLockDetect] bit is unmodified for any source of #DB exception other than Bus Lock (and AMD HW is working correctly as per the spec). KUT debug test initializes DR6[BusLockDetect] with 0 before executing each test and thus the bit remains 0 at the #DB exception for sources other than Bus Lock. Since DR6[BusLockDetect] bit has opposite polarity, as in, value 0 indicates the condition, KUT tests are interpreting it as #DB due to Bus Lock and thus they are failing. Fix this by initializing DR6 with a valid default value before running the test. [1]: AMD64 Architecture Programmer's Manual Pub. 40332, Rev. 4.07 - June 2023, Vol 2, 13.1.3.6 Bus Lock Trap https://bugzilla.kernel.org/attachment.cgi?id=304653 Note: Although Intel SDM (December 2024, Vol 3B, 19.2.3 Debug Status Register (DR6)) stats the same "Other debug exceptions do not modify this bit", HW seems to be resetting DR6[BusLockDetect] to 1 for #DB with non-BusLock sources? In any case, initializing DR6 with correct value is semantically correct on Intel as well, so this should not have any regression on Intel platforms. Reported-by: Sean Christopherson <seanjc@xxxxxxxxxx> Closes: https://bugzilla.kernel.org/show_bug.cgi?id=219787#c13 Signed-off-by: Ravi Bangoria <ravi.bangoria@xxxxxxx> --- x86/debug.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/x86/debug.c b/x86/debug.c index f493567c..2b1084a2 100644 --- a/x86/debug.c +++ b/x86/debug.c @@ -93,7 +93,7 @@ static void __run_single_step_db_test(db_test_fn test, db_report_fn report_fn) bool ign; n = 0; - write_dr6(0); + write_dr6(DR6_ACTIVE_LOW); start = test(); report_fn(start, ""); @@ -107,7 +107,7 @@ static void __run_single_step_db_test(db_test_fn test, db_report_fn report_fn) return; n = 0; - write_dr6(0); + write_dr6(DR6_ACTIVE_LOW); /* * Run the test in usermode. Use the expected start RIP from the first @@ -339,6 +339,7 @@ static noinline unsigned long singlestep_with_movss_blocking_and_dr7_gd(void) * General Detect #DB. */ asm volatile( + "mov $0xffff0ff0, %%rcx\n\t" "xor %0, %0\n\t" "pushf\n\t" "pop %%rax\n\t" @@ -347,7 +348,7 @@ static noinline unsigned long singlestep_with_movss_blocking_and_dr7_gd(void) "mov %%ss, %%ax\n\t" "popf\n\t" "mov %%ax, %%ss\n\t" - "1: mov %0, %%dr6\n\t" + "1: mov %%rcx, %%dr6\n\t" "and $~(1<<8),%%rax\n\t" "push %%rax\n\t" "popf\n\t" @@ -433,7 +434,7 @@ int main(int ac, char **av) write_cr4(cr4 | X86_CR4_DE); read_dr4(); report(got_ud, "DR4 read got #UD with CR4.DE == 1"); - write_dr6(0); + write_dr6(DR6_ACTIVE_LOW); extern unsigned char sw_bp; asm volatile("int3; sw_bp:"); @@ -460,7 +461,7 @@ int main(int ac, char **av) n = 0; extern unsigned char hw_bp2; write_dr0(&hw_bp2); - write_dr6(DR6_BS | DR6_TRAP1); + write_dr6(DR6_BS | DR6_TRAP1 | DR6_ACTIVE_LOW); asm volatile("hw_bp2: nop"); report(n == 1 && db_addr[0] == ((unsigned long)&hw_bp2) && @@ -477,7 +478,7 @@ int main(int ac, char **av) n = 0; write_dr1((void *)&value); - write_dr6(DR6_BS); + write_dr6(DR6_BS | DR6_ACTIVE_LOW); write_dr7(0x00d0040a); // 4-byte write extern unsigned char hw_wp1; @@ -491,7 +492,7 @@ int main(int ac, char **av) "hw watchpoint (test that dr6.BS is not cleared)"); n = 0; - write_dr6(0); + write_dr6(DR6_ACTIVE_LOW); extern unsigned char hw_wp2; asm volatile( @@ -504,7 +505,7 @@ int main(int ac, char **av) "hw watchpoint (test that dr6.BS is not set)"); n = 0; - write_dr6(0); + write_dr6(DR6_ACTIVE_LOW); extern unsigned char sw_icebp; asm volatile(".byte 0xf1; sw_icebp:"); report(n == 1 && -- 2.43.0