1478027f5SJan Kiszka /* 2478027f5SJan Kiszka * Test for x86 debugging facilities 3478027f5SJan Kiszka * 4478027f5SJan Kiszka * Copyright (c) Siemens AG, 2014 5478027f5SJan Kiszka * 6478027f5SJan Kiszka * Authors: 7478027f5SJan Kiszka * Jan Kiszka <jan.kiszka@siemens.com> 8478027f5SJan Kiszka * 9478027f5SJan Kiszka * This work is licensed under the terms of the GNU GPL, version 2. 10478027f5SJan Kiszka */ 11f1dcfd54SSean Christopherson #include <asm/debugreg.h> 12478027f5SJan Kiszka 13*8d9218bbSSean Christopherson #include "atomic.h" 14478027f5SJan Kiszka #include "libcflat.h" 152b934609SXiaoyao Li #include "processor.h" 16478027f5SJan Kiszka #include "desc.h" 17b8a4530dSSean Christopherson #include "usermode.h" 18478027f5SJan Kiszka 19230db53fSPaolo Bonzini static volatile unsigned long bp_addr; 20230db53fSPaolo Bonzini static volatile unsigned long db_addr[10], dr6[10]; 21478027f5SJan Kiszka static volatile unsigned int n; 22478027f5SJan Kiszka static volatile unsigned long value; 23478027f5SJan Kiszka 247f8f7356SKrish Sadhukhan static inline void write_dr4(ulong val) 252c6863b2SPaolo Bonzini { 267f8f7356SKrish Sadhukhan asm volatile ("mov %0, %%dr4" : : "r"(val) : "memory"); 272c6863b2SPaolo Bonzini } 282c6863b2SPaolo Bonzini 297f8f7356SKrish Sadhukhan static inline ulong read_dr4(void) 30478027f5SJan Kiszka { 317f8f7356SKrish Sadhukhan ulong val; 327f8f7356SKrish Sadhukhan asm volatile ("mov %%dr4, %0" : "=r"(val)); 337f8f7356SKrish Sadhukhan return val; 34478027f5SJan Kiszka } 35478027f5SJan Kiszka 36478027f5SJan Kiszka static void handle_db(struct ex_regs *regs) 37478027f5SJan Kiszka { 38230db53fSPaolo Bonzini db_addr[n] = regs->rip; 397f8f7356SKrish Sadhukhan dr6[n] = read_dr6(); 40478027f5SJan Kiszka 41478027f5SJan Kiszka if (dr6[n] & 0x1) 429734b423SSean Christopherson regs->rflags |= X86_EFLAGS_RF; 43478027f5SJan Kiszka 44478027f5SJan Kiszka if (++n >= 10) { 459734b423SSean Christopherson regs->rflags &= ~X86_EFLAGS_TF; 467f8f7356SKrish Sadhukhan write_dr7(0x00000400); 47478027f5SJan Kiszka } 48478027f5SJan Kiszka } 49478027f5SJan Kiszka 509734b423SSean Christopherson static inline bool is_single_step_db(unsigned long dr6_val) 519734b423SSean Christopherson { 52f1dcfd54SSean Christopherson return dr6_val == (DR6_ACTIVE_LOW | DR6_BS); 539734b423SSean Christopherson } 549734b423SSean Christopherson 55bc0dd8bdSSean Christopherson static inline bool is_general_detect_db(unsigned long dr6_val) 56bc0dd8bdSSean Christopherson { 57bc0dd8bdSSean Christopherson return dr6_val == (DR6_ACTIVE_LOW | DR6_BD); 58bc0dd8bdSSean Christopherson } 59bc0dd8bdSSean Christopherson 609734b423SSean Christopherson static inline bool is_icebp_db(unsigned long dr6_val) 619734b423SSean Christopherson { 62f1dcfd54SSean Christopherson return dr6_val == DR6_ACTIVE_LOW; 639734b423SSean Christopherson } 649734b423SSean Christopherson 65a094abddSPaolo Bonzini extern unsigned char handle_db_save_rip; 66a094abddSPaolo Bonzini asm("handle_db_save_rip:\n" 67a094abddSPaolo Bonzini "stc\n" 68a094abddSPaolo Bonzini "nop;nop;nop\n" 69a094abddSPaolo Bonzini "rclq $1, n(%rip)\n" 70a094abddSPaolo Bonzini "iretq\n"); 71a094abddSPaolo Bonzini 72478027f5SJan Kiszka static void handle_bp(struct ex_regs *regs) 73478027f5SJan Kiszka { 74230db53fSPaolo Bonzini bp_addr = regs->rip; 75478027f5SJan Kiszka } 76478027f5SJan Kiszka 772c6863b2SPaolo Bonzini bool got_ud; 782c6863b2SPaolo Bonzini static void handle_ud(struct ex_regs *regs) 792c6863b2SPaolo Bonzini { 802c6863b2SPaolo Bonzini unsigned long cr4 = read_cr4(); 812c6863b2SPaolo Bonzini write_cr4(cr4 & ~X86_CR4_DE); 822c6863b2SPaolo Bonzini got_ud = 1; 832c6863b2SPaolo Bonzini } 842c6863b2SPaolo Bonzini 85*8d9218bbSSean Christopherson static bool got_ac; 86*8d9218bbSSean Christopherson static void handle_ac(struct ex_regs *regs) 87*8d9218bbSSean Christopherson { 88*8d9218bbSSean Christopherson got_ac = true; 89*8d9218bbSSean Christopherson } 90*8d9218bbSSean Christopherson 919734b423SSean Christopherson typedef unsigned long (*db_test_fn)(void); 92b8a4530dSSean Christopherson typedef void (*db_report_fn)(unsigned long, const char *); 939734b423SSean Christopherson 94bc0dd8bdSSean Christopherson static unsigned long singlestep_with_movss_blocking_and_dr7_gd(void); 95302fbd56SPaolo Bonzini static unsigned long singlestep_with_sti_hlt(void); 96bc0dd8bdSSean Christopherson 979734b423SSean Christopherson static void __run_single_step_db_test(db_test_fn test, db_report_fn report_fn) 98478027f5SJan Kiszka { 99478027f5SJan Kiszka unsigned long start; 100b8a4530dSSean Christopherson bool ign; 1019734b423SSean Christopherson 1029734b423SSean Christopherson n = 0; 1039734b423SSean Christopherson write_dr6(0); 1049734b423SSean Christopherson 1059734b423SSean Christopherson start = test(); 106b8a4530dSSean Christopherson report_fn(start, ""); 107b8a4530dSSean Christopherson 108302fbd56SPaolo Bonzini /* 109302fbd56SPaolo Bonzini * MOV DR #GPs at CPL>0, don't try to run the DR7.GD test in usermode. 110302fbd56SPaolo Bonzini * Likewise for HLT. 111302fbd56SPaolo Bonzini */ 112302fbd56SPaolo Bonzini if (test == singlestep_with_movss_blocking_and_dr7_gd 113302fbd56SPaolo Bonzini || test == singlestep_with_sti_hlt) 114bc0dd8bdSSean Christopherson return; 115bc0dd8bdSSean Christopherson 116b8a4530dSSean Christopherson n = 0; 117b8a4530dSSean Christopherson write_dr6(0); 118bc0dd8bdSSean Christopherson 119b8a4530dSSean Christopherson /* 120b8a4530dSSean Christopherson * Run the test in usermode. Use the expected start RIP from the first 121b8a4530dSSean Christopherson * run, the usermode framework doesn't make it easy to get the expected 122b8a4530dSSean Christopherson * RIP out of the test, and it shouldn't change in any case. Run the 123b8a4530dSSean Christopherson * test with IOPL=3 so that it can use OUT, CLI, STI, etc... 124b8a4530dSSean Christopherson */ 125b8a4530dSSean Christopherson set_iopl(3); 126b8a4530dSSean Christopherson run_in_user((usermode_func)test, GP_VECTOR, 0, 0, 0, 0, &ign); 127b8a4530dSSean Christopherson set_iopl(0); 128b8a4530dSSean Christopherson 129b8a4530dSSean Christopherson report_fn(start, "Usermode "); 1309734b423SSean Christopherson } 1319734b423SSean Christopherson 1329734b423SSean Christopherson #define run_ss_db_test(name) __run_single_step_db_test(name, report_##name) 1339734b423SSean Christopherson 134b8a4530dSSean Christopherson static void report_singlestep_basic(unsigned long start, const char *usermode) 1359734b423SSean Christopherson { 1369734b423SSean Christopherson report(n == 3 && 1379734b423SSean Christopherson is_single_step_db(dr6[0]) && db_addr[0] == start && 1389734b423SSean Christopherson is_single_step_db(dr6[1]) && db_addr[1] == start + 1 && 1399734b423SSean Christopherson is_single_step_db(dr6[2]) && db_addr[2] == start + 1 + 1, 140b8a4530dSSean Christopherson "%sSingle-step #DB basic test", usermode); 1419734b423SSean Christopherson } 1429734b423SSean Christopherson 14320de8c3bSAaron Lewis static noinline unsigned long singlestep_basic(void) 1449734b423SSean Christopherson { 1459734b423SSean Christopherson unsigned long start; 1469734b423SSean Christopherson 1479734b423SSean Christopherson /* 1489734b423SSean Christopherson * After being enabled, single-step breakpoints have a one instruction 1499734b423SSean Christopherson * delay before the first #DB is generated. 1509734b423SSean Christopherson */ 1519734b423SSean Christopherson asm volatile ( 1529734b423SSean Christopherson "pushf\n\t" 1539734b423SSean Christopherson "pop %%rax\n\t" 1549734b423SSean Christopherson "or $(1<<8),%%rax\n\t" 1559734b423SSean Christopherson "push %%rax\n\t" 1569734b423SSean Christopherson "popf\n\t" 1579734b423SSean Christopherson "and $~(1<<8),%%rax\n\t" 1589734b423SSean Christopherson "1:push %%rax\n\t" 1599734b423SSean Christopherson "popf\n\t" 160cc6931d3SZhenzhong Duan "lea 1b(%%rip), %0\n\t" 1619734b423SSean Christopherson : "=r" (start) : : "rax" 1629734b423SSean Christopherson ); 1639734b423SSean Christopherson return start; 1649734b423SSean Christopherson } 1659734b423SSean Christopherson 166b8a4530dSSean Christopherson static void report_singlestep_emulated_instructions(unsigned long start, 167b8a4530dSSean Christopherson const char *usermode) 1689734b423SSean Christopherson { 1699734b423SSean Christopherson report(n == 7 && 1709734b423SSean Christopherson is_single_step_db(dr6[0]) && db_addr[0] == start && 1719734b423SSean Christopherson is_single_step_db(dr6[1]) && db_addr[1] == start + 1 && 1729734b423SSean Christopherson is_single_step_db(dr6[2]) && db_addr[2] == start + 1 + 3 && 1739734b423SSean Christopherson is_single_step_db(dr6[3]) && db_addr[3] == start + 1 + 3 + 2 && 1749734b423SSean Christopherson is_single_step_db(dr6[4]) && db_addr[4] == start + 1 + 3 + 2 + 5 && 1756bfb9572SSean Christopherson is_single_step_db(dr6[5]) && db_addr[5] == start + 1 + 3 + 2 + 5 + 1 && 1766bfb9572SSean Christopherson is_single_step_db(dr6[6]) && db_addr[6] == start + 1 + 3 + 2 + 5 + 1 + 1, 177b8a4530dSSean Christopherson "%sSingle-step #DB on emulated instructions", usermode); 1789734b423SSean Christopherson } 1799734b423SSean Christopherson 18020de8c3bSAaron Lewis static noinline unsigned long singlestep_emulated_instructions(void) 1819734b423SSean Christopherson { 1829734b423SSean Christopherson unsigned long start; 1839734b423SSean Christopherson 1849734b423SSean Christopherson /* 1859734b423SSean Christopherson * Verify single-step #DB are generated correctly on emulated 1869734b423SSean Christopherson * instructions, e.g. CPUID and RDMSR. 1879734b423SSean Christopherson */ 1889734b423SSean Christopherson asm volatile ( 1899734b423SSean Christopherson "pushf\n\t" 1909734b423SSean Christopherson "pop %%rax\n\t" 1919734b423SSean Christopherson "or $(1<<8),%%rax\n\t" 1929734b423SSean Christopherson "push %%rax\n\t" 1939734b423SSean Christopherson "popf\n\t" 1949734b423SSean Christopherson "and $~(1<<8),%%rax\n\t" 1959734b423SSean Christopherson "1:push %%rax\n\t" 1969734b423SSean Christopherson "xor %%rax,%%rax\n\t" 1979734b423SSean Christopherson "cpuid\n\t" 1986bfb9572SSean Christopherson "movl $0x3fd, %%edx\n\t" 1996bfb9572SSean Christopherson "inb %%dx, %%al\n\t" 2009734b423SSean Christopherson "popf\n\t" 201cc6931d3SZhenzhong Duan "lea 1b(%%rip),%0\n\t" 2029734b423SSean Christopherson : "=r" (start) : : "rax", "ebx", "ecx", "edx" 2039734b423SSean Christopherson ); 2049734b423SSean Christopherson return start; 2059734b423SSean Christopherson } 2069734b423SSean Christopherson 207bc0dd8bdSSean Christopherson static void report_singlestep_with_sti_blocking(unsigned long start, 208bc0dd8bdSSean Christopherson const char *usermode) 209bc0dd8bdSSean Christopherson { 210bc0dd8bdSSean Christopherson report(n == 4 && 211bc0dd8bdSSean Christopherson is_single_step_db(dr6[0]) && db_addr[0] == start && 212bc0dd8bdSSean Christopherson is_single_step_db(dr6[1]) && db_addr[1] == start + 6 && 213bc0dd8bdSSean Christopherson is_single_step_db(dr6[2]) && db_addr[2] == start + 6 + 1 && 214bc0dd8bdSSean Christopherson is_single_step_db(dr6[3]) && db_addr[3] == start + 6 + 1 + 1, 215bc0dd8bdSSean Christopherson "%sSingle-step #DB w/ STI blocking", usermode); 216bc0dd8bdSSean Christopherson } 217bc0dd8bdSSean Christopherson 218bc0dd8bdSSean Christopherson 21920de8c3bSAaron Lewis static noinline unsigned long singlestep_with_sti_blocking(void) 220bc0dd8bdSSean Christopherson { 221bc0dd8bdSSean Christopherson unsigned long start_rip; 222bc0dd8bdSSean Christopherson 223bc0dd8bdSSean Christopherson /* 224bc0dd8bdSSean Christopherson * STI blocking doesn't suppress #DBs, thus the first single-step #DB 225bc0dd8bdSSean Christopherson * should arrive after the standard one instruction delay. 226bc0dd8bdSSean Christopherson */ 227bc0dd8bdSSean Christopherson asm volatile( 228bc0dd8bdSSean Christopherson "cli\n\t" 229bc0dd8bdSSean Christopherson "pushf\n\t" 230bc0dd8bdSSean Christopherson "pop %%rax\n\t" 231bc0dd8bdSSean Christopherson "or $(1<<8),%%rax\n\t" 232bc0dd8bdSSean Christopherson "push %%rax\n\t" 233bc0dd8bdSSean Christopherson "popf\n\t" 234bc0dd8bdSSean Christopherson "sti\n\t" 235bc0dd8bdSSean Christopherson "1:and $~(1<<8),%%rax\n\t" 236bc0dd8bdSSean Christopherson "push %%rax\n\t" 237bc0dd8bdSSean Christopherson "popf\n\t" 238cc6931d3SZhenzhong Duan "lea 1b(%%rip),%0\n\t" 239bc0dd8bdSSean Christopherson : "=r" (start_rip) : : "rax" 240bc0dd8bdSSean Christopherson ); 241bc0dd8bdSSean Christopherson return start_rip; 242bc0dd8bdSSean Christopherson } 243bc0dd8bdSSean Christopherson 244bc0dd8bdSSean Christopherson static void report_singlestep_with_movss_blocking(unsigned long start, 245bc0dd8bdSSean Christopherson const char *usermode) 246bc0dd8bdSSean Christopherson { 247bc0dd8bdSSean Christopherson report(n == 3 && 248bc0dd8bdSSean Christopherson is_single_step_db(dr6[0]) && db_addr[0] == start && 249bc0dd8bdSSean Christopherson is_single_step_db(dr6[1]) && db_addr[1] == start + 1 && 250bc0dd8bdSSean Christopherson is_single_step_db(dr6[2]) && db_addr[2] == start + 1 + 1, 251bc0dd8bdSSean Christopherson "%sSingle-step #DB w/ MOVSS blocking", usermode); 252bc0dd8bdSSean Christopherson } 253bc0dd8bdSSean Christopherson 25420de8c3bSAaron Lewis static noinline unsigned long singlestep_with_movss_blocking(void) 255bc0dd8bdSSean Christopherson { 256bc0dd8bdSSean Christopherson unsigned long start_rip; 257bc0dd8bdSSean Christopherson 258bc0dd8bdSSean Christopherson /* 259bc0dd8bdSSean Christopherson * MOVSS blocking suppresses single-step #DBs (and select other #DBs), 260bc0dd8bdSSean Christopherson * thus the first single-step #DB should occur after MOVSS blocking 261bc0dd8bdSSean Christopherson * expires, i.e. two instructions after #DBs are enabled in this case. 262bc0dd8bdSSean Christopherson */ 263bc0dd8bdSSean Christopherson asm volatile( 264bc0dd8bdSSean Christopherson "pushf\n\t" 265bc0dd8bdSSean Christopherson "pop %%rax\n\t" 266bc0dd8bdSSean Christopherson "or $(1<<8),%%rax\n\t" 267bc0dd8bdSSean Christopherson "push %%rax\n\t" 268bc0dd8bdSSean Christopherson "mov %%ss, %%ax\n\t" 269bc0dd8bdSSean Christopherson "popf\n\t" 270bc0dd8bdSSean Christopherson "mov %%ax, %%ss\n\t" 271bc0dd8bdSSean Christopherson "and $~(1<<8),%%rax\n\t" 272bc0dd8bdSSean Christopherson "1: push %%rax\n\t" 273bc0dd8bdSSean Christopherson "popf\n\t" 274cc6931d3SZhenzhong Duan "lea 1b(%%rip),%0\n\t" 275bc0dd8bdSSean Christopherson : "=r" (start_rip) : : "rax" 276bc0dd8bdSSean Christopherson ); 277bc0dd8bdSSean Christopherson return start_rip; 278bc0dd8bdSSean Christopherson } 279bc0dd8bdSSean Christopherson 280bc0dd8bdSSean Christopherson 281bc0dd8bdSSean Christopherson static void report_singlestep_with_movss_blocking_and_icebp(unsigned long start, 282bc0dd8bdSSean Christopherson const char *usermode) 283bc0dd8bdSSean Christopherson { 284bc0dd8bdSSean Christopherson report(n == 4 && 285bc0dd8bdSSean Christopherson is_icebp_db(dr6[0]) && db_addr[0] == start && 286bc0dd8bdSSean Christopherson is_single_step_db(dr6[1]) && db_addr[1] == start + 6 && 287bc0dd8bdSSean Christopherson is_single_step_db(dr6[2]) && db_addr[2] == start + 6 + 1 && 288bc0dd8bdSSean Christopherson is_single_step_db(dr6[3]) && db_addr[3] == start + 6 + 1 + 1, 289bc0dd8bdSSean Christopherson "%sSingle-Step + ICEBP #DB w/ MOVSS blocking", usermode); 290bc0dd8bdSSean Christopherson } 291bc0dd8bdSSean Christopherson 29220de8c3bSAaron Lewis static noinline unsigned long singlestep_with_movss_blocking_and_icebp(void) 293bc0dd8bdSSean Christopherson { 294bc0dd8bdSSean Christopherson unsigned long start; 295bc0dd8bdSSean Christopherson 296bc0dd8bdSSean Christopherson /* 297bc0dd8bdSSean Christopherson * ICEBP, a.k.a. INT1 or int1icebrk, is an oddball. It generates a 298bc0dd8bdSSean Christopherson * trap-like #DB, is intercepted if #DBs are intercepted, and manifests 299bc0dd8bdSSean Christopherson * as a #DB VM-Exit, but the VM-Exit occurs on the ICEBP itself, i.e. 300bc0dd8bdSSean Christopherson * it's treated as an instruction intercept. Verify that ICEBP is 301bc0dd8bdSSean Christopherson * correctly emulated as a trap-like #DB when intercepted, and that 302bc0dd8bdSSean Christopherson * MOVSS blocking is handled correctly with respect to single-step 303bc0dd8bdSSean Christopherson * breakpoints being enabled. 304bc0dd8bdSSean Christopherson */ 305bc0dd8bdSSean Christopherson asm volatile( 306bc0dd8bdSSean Christopherson "pushf\n\t" 307bc0dd8bdSSean Christopherson "pop %%rax\n\t" 308bc0dd8bdSSean Christopherson "or $(1<<8),%%rax\n\t" 309bc0dd8bdSSean Christopherson "push %%rax\n\t" 310bc0dd8bdSSean Christopherson "mov %%ss, %%ax\n\t" 311bc0dd8bdSSean Christopherson "popf\n\t" 312bc0dd8bdSSean Christopherson "mov %%ax, %%ss\n\t" 313bc0dd8bdSSean Christopherson ".byte 0xf1;" 314bc0dd8bdSSean Christopherson "1:and $~(1<<8),%%rax\n\t" 315bc0dd8bdSSean Christopherson "push %%rax\n\t" 316bc0dd8bdSSean Christopherson "popf\n\t" 317cc6931d3SZhenzhong Duan "lea 1b(%%rip),%0\n\t" 318bc0dd8bdSSean Christopherson : "=r" (start) : : "rax" 319bc0dd8bdSSean Christopherson ); 320bc0dd8bdSSean Christopherson return start; 321bc0dd8bdSSean Christopherson } 322bc0dd8bdSSean Christopherson 323bc0dd8bdSSean Christopherson static void report_singlestep_with_movss_blocking_and_dr7_gd(unsigned long start, 324bc0dd8bdSSean Christopherson const char *ign) 325bc0dd8bdSSean Christopherson { 326bc0dd8bdSSean Christopherson report(n == 5 && 327bc0dd8bdSSean Christopherson is_general_detect_db(dr6[0]) && db_addr[0] == start && 328bc0dd8bdSSean Christopherson is_single_step_db(dr6[1]) && db_addr[1] == start + 3 && 329bc0dd8bdSSean Christopherson is_single_step_db(dr6[2]) && db_addr[2] == start + 3 + 6 && 330bc0dd8bdSSean Christopherson is_single_step_db(dr6[3]) && db_addr[3] == start + 3 + 6 + 1 && 331bc0dd8bdSSean Christopherson is_single_step_db(dr6[4]) && db_addr[4] == start + 3 + 6 + 1 + 1, 332bc0dd8bdSSean Christopherson "Single-step #DB w/ MOVSS blocking and DR7.GD=1"); 333bc0dd8bdSSean Christopherson } 334bc0dd8bdSSean Christopherson 33520de8c3bSAaron Lewis static noinline unsigned long singlestep_with_movss_blocking_and_dr7_gd(void) 336bc0dd8bdSSean Christopherson { 337bc0dd8bdSSean Christopherson unsigned long start_rip; 338bc0dd8bdSSean Christopherson 339bc0dd8bdSSean Christopherson write_dr7(DR7_GD); 340bc0dd8bdSSean Christopherson 341bc0dd8bdSSean Christopherson /* 342bc0dd8bdSSean Christopherson * MOVSS blocking does NOT suppress General Detect #DBs, which have 343bc0dd8bdSSean Christopherson * fault-like behavior. Note, DR7.GD is cleared by the CPU upon 344bc0dd8bdSSean Christopherson * successful delivery of the #DB. DR6.BD is NOT cleared by the CPU, 345bc0dd8bdSSean Christopherson * but the MOV DR6 below will be re-executed after handling the 346bc0dd8bdSSean Christopherson * General Detect #DB. 347bc0dd8bdSSean Christopherson */ 348bc0dd8bdSSean Christopherson asm volatile( 349bc0dd8bdSSean Christopherson "xor %0, %0\n\t" 350bc0dd8bdSSean Christopherson "pushf\n\t" 351bc0dd8bdSSean Christopherson "pop %%rax\n\t" 352bc0dd8bdSSean Christopherson "or $(1<<8),%%rax\n\t" 353bc0dd8bdSSean Christopherson "push %%rax\n\t" 354bc0dd8bdSSean Christopherson "mov %%ss, %%ax\n\t" 355bc0dd8bdSSean Christopherson "popf\n\t" 356bc0dd8bdSSean Christopherson "mov %%ax, %%ss\n\t" 357bc0dd8bdSSean Christopherson "1: mov %0, %%dr6\n\t" 358bc0dd8bdSSean Christopherson "and $~(1<<8),%%rax\n\t" 359bc0dd8bdSSean Christopherson "push %%rax\n\t" 360bc0dd8bdSSean Christopherson "popf\n\t" 361cc6931d3SZhenzhong Duan "lea 1b(%%rip),%0\n\t" 362bc0dd8bdSSean Christopherson : "=r" (start_rip) : : "rax" 363bc0dd8bdSSean Christopherson ); 364bc0dd8bdSSean Christopherson return start_rip; 365bc0dd8bdSSean Christopherson } 366bc0dd8bdSSean Christopherson 367302fbd56SPaolo Bonzini static void report_singlestep_with_sti_hlt(unsigned long start, 368302fbd56SPaolo Bonzini const char *usermode) 369302fbd56SPaolo Bonzini { 370302fbd56SPaolo Bonzini report(n == 5 && 371302fbd56SPaolo Bonzini is_single_step_db(dr6[0]) && db_addr[0] == start && 372302fbd56SPaolo Bonzini is_single_step_db(dr6[1]) && db_addr[1] == start + 1 && 373302fbd56SPaolo Bonzini is_single_step_db(dr6[2]) && db_addr[2] == start + 1 + 6 && 374302fbd56SPaolo Bonzini is_single_step_db(dr6[3]) && db_addr[3] == start + 1 + 6 + 1 && 375302fbd56SPaolo Bonzini is_single_step_db(dr6[4]) && db_addr[4] == start + 1 + 6 + 1 + 1, 376302fbd56SPaolo Bonzini "%sSingle-step #DB w/ STI;HLT", usermode); 377302fbd56SPaolo Bonzini } 378302fbd56SPaolo Bonzini 379302fbd56SPaolo Bonzini #define APIC_LVT_TIMER_VECTOR (0xee) 380302fbd56SPaolo Bonzini 381302fbd56SPaolo Bonzini static void lvtt_handler(isr_regs_t *regs) 382302fbd56SPaolo Bonzini { 383302fbd56SPaolo Bonzini eoi(); 384302fbd56SPaolo Bonzini } 385302fbd56SPaolo Bonzini 386302fbd56SPaolo Bonzini static noinline unsigned long singlestep_with_sti_hlt(void) 387302fbd56SPaolo Bonzini { 388302fbd56SPaolo Bonzini unsigned long start_rip; 389302fbd56SPaolo Bonzini 390302fbd56SPaolo Bonzini cli(); 391302fbd56SPaolo Bonzini 392302fbd56SPaolo Bonzini handle_irq(APIC_LVT_TIMER_VECTOR, lvtt_handler); 393302fbd56SPaolo Bonzini apic_write(APIC_LVTT, APIC_LVT_TIMER_ONESHOT | 394302fbd56SPaolo Bonzini APIC_LVT_TIMER_VECTOR); 395302fbd56SPaolo Bonzini apic_write(APIC_TDCR, 0x0000000b); 396302fbd56SPaolo Bonzini apic_write(APIC_TMICT, 1000000); 397302fbd56SPaolo Bonzini 398302fbd56SPaolo Bonzini /* 399302fbd56SPaolo Bonzini * STI blocking doesn't suppress #DBs, thus the first single-step #DB 400302fbd56SPaolo Bonzini * should arrive after the standard one instruction delay. 401302fbd56SPaolo Bonzini */ 402302fbd56SPaolo Bonzini asm volatile( 403302fbd56SPaolo Bonzini "pushf\n\t" 404302fbd56SPaolo Bonzini "pop %%rax\n\t" 405302fbd56SPaolo Bonzini "or $(1<<8),%%rax\n\t" 406302fbd56SPaolo Bonzini "push %%rax\n\t" 407302fbd56SPaolo Bonzini "popf\n\t" 408302fbd56SPaolo Bonzini "sti\n\t" 409302fbd56SPaolo Bonzini "1:hlt;\n\t" 410302fbd56SPaolo Bonzini "and $~(1<<8),%%rax\n\t" 411302fbd56SPaolo Bonzini "push %%rax\n\t" 412302fbd56SPaolo Bonzini "popf\n\t" 413302fbd56SPaolo Bonzini "lea 1b(%%rip),%0\n\t" 414302fbd56SPaolo Bonzini : "=r" (start_rip) : : "rax" 415302fbd56SPaolo Bonzini ); 416302fbd56SPaolo Bonzini return start_rip; 417302fbd56SPaolo Bonzini } 418302fbd56SPaolo Bonzini 419*8d9218bbSSean Christopherson static noinline uint64_t bus_lock(uint64_t magic) 420*8d9218bbSSean Christopherson { 421*8d9218bbSSean Christopherson uint8_t buffer[128] __attribute__((aligned(64))) = { }; 422*8d9218bbSSean Christopherson atomic64_t *val = (atomic64_t *)&buffer[60]; 423*8d9218bbSSean Christopherson 424*8d9218bbSSean Christopherson atomic64_cmpxchg(val, 0, magic); 425*8d9218bbSSean Christopherson return READ_ONCE(*(uint64_t *)val); 426*8d9218bbSSean Christopherson } 427*8d9218bbSSean Christopherson 428*8d9218bbSSean Christopherson static void bus_lock_test(void) 429*8d9218bbSSean Christopherson { 430*8d9218bbSSean Christopherson const uint64_t magic = 0xdeadbeefdeadbeefull; 431*8d9218bbSSean Christopherson bool bus_lock_db = false; 432*8d9218bbSSean Christopherson uint64_t val; 433*8d9218bbSSean Christopherson 434*8d9218bbSSean Christopherson /* 435*8d9218bbSSean Christopherson * Generate a bus lock (via a locked access that splits cache lines) 436*8d9218bbSSean Christopherson * in CPL0 and again in CPL3 (Bus Lock Detect only affects CPL3), and 437*8d9218bbSSean Christopherson * verify that no #AC or #DB is generated (the relevant features are 438*8d9218bbSSean Christopherson * not enabled). 439*8d9218bbSSean Christopherson */ 440*8d9218bbSSean Christopherson val = bus_lock(magic); 441*8d9218bbSSean Christopherson report(!got_ac && !n && val == magic, 442*8d9218bbSSean Christopherson "CPL0 Split Lock #AC = %u (#DB = %u), val = %lx (wanted %lx)", 443*8d9218bbSSean Christopherson got_ac, n, val, magic); 444*8d9218bbSSean Christopherson 445*8d9218bbSSean Christopherson val = run_in_user((usermode_func)bus_lock, DB_VECTOR, magic, 0, 0, 0, &bus_lock_db); 446*8d9218bbSSean Christopherson report(!bus_lock_db && val == magic, 447*8d9218bbSSean Christopherson "CPL3 Bus Lock #DB = %u, val = %lx (wanted %lx)", 448*8d9218bbSSean Christopherson bus_lock_db, val, magic); 449*8d9218bbSSean Christopherson 450*8d9218bbSSean Christopherson n = 0; 451*8d9218bbSSean Christopherson got_ac = false; 452*8d9218bbSSean Christopherson } 453*8d9218bbSSean Christopherson 4549734b423SSean Christopherson int main(int ac, char **av) 4559734b423SSean Christopherson { 4562c6863b2SPaolo Bonzini unsigned long cr4; 457478027f5SJan Kiszka 458478027f5SJan Kiszka handle_exception(DB_VECTOR, handle_db); 459478027f5SJan Kiszka handle_exception(BP_VECTOR, handle_bp); 4602c6863b2SPaolo Bonzini handle_exception(UD_VECTOR, handle_ud); 461*8d9218bbSSean Christopherson handle_exception(AC_VECTOR, handle_ac); 462*8d9218bbSSean Christopherson 463*8d9218bbSSean Christopherson bus_lock_test(); 4642c6863b2SPaolo Bonzini 4659734b423SSean Christopherson /* 4669734b423SSean Christopherson * DR4 is an alias for DR6 (and DR5 aliases DR7) if CR4.DE is NOT set, 4679734b423SSean Christopherson * and is reserved if CR4.DE=1 (Debug Extensions enabled). 4689734b423SSean Christopherson */ 4692c6863b2SPaolo Bonzini got_ud = 0; 4702c6863b2SPaolo Bonzini cr4 = read_cr4(); 4712c6863b2SPaolo Bonzini write_cr4(cr4 & ~X86_CR4_DE); 4727f8f7356SKrish Sadhukhan write_dr4(0); 473f1dcfd54SSean Christopherson write_dr6(DR6_ACTIVE_LOW | DR6_BS | DR6_TRAP1); 474f1dcfd54SSean Christopherson report(read_dr4() == (DR6_ACTIVE_LOW | DR6_BS | DR6_TRAP1) && !got_ud, 475f1dcfd54SSean Christopherson "DR4==DR6 with CR4.DE == 0"); 4762c6863b2SPaolo Bonzini 4772c6863b2SPaolo Bonzini cr4 = read_cr4(); 4782c6863b2SPaolo Bonzini write_cr4(cr4 | X86_CR4_DE); 4797f8f7356SKrish Sadhukhan read_dr4(); 4809734b423SSean Christopherson report(got_ud, "DR4 read got #UD with CR4.DE == 1"); 4817f8f7356SKrish Sadhukhan write_dr6(0); 482478027f5SJan Kiszka 483c68a7ff0SPaolo Bonzini extern unsigned char sw_bp; 484c68a7ff0SPaolo Bonzini asm volatile("int3; sw_bp:"); 485a299895bSThomas Huth report(bp_addr == (unsigned long)&sw_bp, "#BP"); 486478027f5SJan Kiszka 4879734b423SSean Christopherson /* 4889734b423SSean Christopherson * The CPU sets/clears bits 0-3 (trap bits for DR0-3) on #DB based on 4899734b423SSean Christopherson * whether or not the corresponding DR0-3 got a match. All other bits 4909734b423SSean Christopherson * in DR6 are set if and only if their associated breakpoint condition 4919734b423SSean Christopherson * is active, and are never cleared by the CPU. Verify a match on DR0 4929734b423SSean Christopherson * is reported correctly, and that DR6.BS is not set when single-step 4939734b423SSean Christopherson * breakpoints are disabled, but is left set (if set by software). 4949734b423SSean Christopherson */ 4959e486280SPaolo Bonzini n = 0; 496c68a7ff0SPaolo Bonzini extern unsigned char hw_bp1; 4977f8f7356SKrish Sadhukhan write_dr0(&hw_bp1); 498f1dcfd54SSean Christopherson write_dr7(DR7_FIXED_1 | DR7_GLOBAL_ENABLE_DR0); 499c68a7ff0SPaolo Bonzini asm volatile("hw_bp1: nop"); 500a299895bSThomas Huth report(n == 1 && 501f1dcfd54SSean Christopherson db_addr[0] == ((unsigned long)&hw_bp1) && 502f1dcfd54SSean Christopherson dr6[0] == (DR6_ACTIVE_LOW | DR6_TRAP0), 503a299895bSThomas Huth "hw breakpoint (test that dr6.BS is not set)"); 504478027f5SJan Kiszka 505478027f5SJan Kiszka n = 0; 506c68a7ff0SPaolo Bonzini extern unsigned char hw_bp2; 5077f8f7356SKrish Sadhukhan write_dr0(&hw_bp2); 508f1dcfd54SSean Christopherson write_dr6(DR6_BS | DR6_TRAP1); 509c68a7ff0SPaolo Bonzini asm volatile("hw_bp2: nop"); 510a299895bSThomas Huth report(n == 1 && 511f1dcfd54SSean Christopherson db_addr[0] == ((unsigned long)&hw_bp2) && 512f1dcfd54SSean Christopherson dr6[0] == (DR6_ACTIVE_LOW | DR6_BS | DR6_TRAP0), 513a299895bSThomas Huth "hw breakpoint (test that dr6.BS is not cleared)"); 5149e486280SPaolo Bonzini 5159734b423SSean Christopherson run_ss_db_test(singlestep_basic); 5169734b423SSean Christopherson run_ss_db_test(singlestep_emulated_instructions); 517bc0dd8bdSSean Christopherson run_ss_db_test(singlestep_with_sti_blocking); 518bc0dd8bdSSean Christopherson run_ss_db_test(singlestep_with_movss_blocking); 519bc0dd8bdSSean Christopherson run_ss_db_test(singlestep_with_movss_blocking_and_icebp); 520bc0dd8bdSSean Christopherson run_ss_db_test(singlestep_with_movss_blocking_and_dr7_gd); 521302fbd56SPaolo Bonzini run_ss_db_test(singlestep_with_sti_hlt); 5220a982d78SKyle Huey 523478027f5SJan Kiszka n = 0; 5247f8f7356SKrish Sadhukhan write_dr1((void *)&value); 5254879ca8bSSean Christopherson write_dr6(DR6_BS); 5267f8f7356SKrish Sadhukhan write_dr7(0x00d0040a); // 4-byte write 527478027f5SJan Kiszka 528c68a7ff0SPaolo Bonzini extern unsigned char hw_wp1; 529478027f5SJan Kiszka asm volatile( 530478027f5SJan Kiszka "mov $42,%%rax\n\t" 531c68a7ff0SPaolo Bonzini "mov %%rax,%0\n\t; hw_wp1:" 532478027f5SJan Kiszka : "=m" (value) : : "rax"); 533a299895bSThomas Huth report(n == 1 && 534f1dcfd54SSean Christopherson db_addr[0] == ((unsigned long)&hw_wp1) && 535f1dcfd54SSean Christopherson dr6[0] == (DR6_ACTIVE_LOW | DR6_BS | DR6_TRAP1), 536a299895bSThomas Huth "hw watchpoint (test that dr6.BS is not cleared)"); 5379e486280SPaolo Bonzini 5389e486280SPaolo Bonzini n = 0; 5397f8f7356SKrish Sadhukhan write_dr6(0); 5409e486280SPaolo Bonzini 541c68a7ff0SPaolo Bonzini extern unsigned char hw_wp2; 5429e486280SPaolo Bonzini asm volatile( 5439e486280SPaolo Bonzini "mov $42,%%rax\n\t" 544c68a7ff0SPaolo Bonzini "mov %%rax,%0\n\t; hw_wp2:" 5459e486280SPaolo Bonzini : "=m" (value) : : "rax"); 546a299895bSThomas Huth report(n == 1 && 547f1dcfd54SSean Christopherson db_addr[0] == ((unsigned long)&hw_wp2) && 548f1dcfd54SSean Christopherson dr6[0] == (DR6_ACTIVE_LOW | DR6_TRAP1), 549a299895bSThomas Huth "hw watchpoint (test that dr6.BS is not set)"); 5509e486280SPaolo Bonzini 5519e486280SPaolo Bonzini n = 0; 5527f8f7356SKrish Sadhukhan write_dr6(0); 553c68a7ff0SPaolo Bonzini extern unsigned char sw_icebp; 554c68a7ff0SPaolo Bonzini asm volatile(".byte 0xf1; sw_icebp:"); 555a299895bSThomas Huth report(n == 1 && 556f1dcfd54SSean Christopherson db_addr[0] == (unsigned long)&sw_icebp && dr6[0] == DR6_ACTIVE_LOW, 557a299895bSThomas Huth "icebp"); 558478027f5SJan Kiszka 5597f8f7356SKrish Sadhukhan write_dr7(0x400); 560a094abddSPaolo Bonzini value = KERNEL_DS; 5617f8f7356SKrish Sadhukhan write_dr7(0x00f0040a); // 4-byte read or write 562a094abddSPaolo Bonzini 563a094abddSPaolo Bonzini /* 564a094abddSPaolo Bonzini * Each invocation of the handler should shift n by 1 and set bit 0 to 1. 565a094abddSPaolo Bonzini * We expect a single invocation, so n should become 3. If the entry 566a094abddSPaolo Bonzini * RIP is wrong, or if the handler is executed more than once, the value 567a094abddSPaolo Bonzini * will not match. 568a094abddSPaolo Bonzini */ 569a094abddSPaolo Bonzini set_idt_entry(1, &handle_db_save_rip, 0); 570a094abddSPaolo Bonzini 571a094abddSPaolo Bonzini n = 1; 572a094abddSPaolo Bonzini asm volatile( 573a094abddSPaolo Bonzini "clc\n\t" 574a094abddSPaolo Bonzini "mov %0,%%ss\n\t" 575a094abddSPaolo Bonzini ".byte 0x2e, 0x2e, 0xf1" 576a094abddSPaolo Bonzini : "=m" (value) : : "rax"); 577a299895bSThomas Huth report(n == 3, "MOV SS + watchpoint + ICEBP"); 578a094abddSPaolo Bonzini 579a094abddSPaolo Bonzini /* 580a094abddSPaolo Bonzini * Here the #DB handler is invoked twice, once as a software exception 581a094abddSPaolo Bonzini * and once as a software interrupt. 582a094abddSPaolo Bonzini */ 583a094abddSPaolo Bonzini n = 1; 584a094abddSPaolo Bonzini asm volatile( 585a094abddSPaolo Bonzini "clc\n\t" 586a094abddSPaolo Bonzini "mov %0,%%ss\n\t" 587a094abddSPaolo Bonzini "int $1" 588a094abddSPaolo Bonzini : "=m" (value) : : "rax"); 589a299895bSThomas Huth report(n == 7, "MOV SS + watchpoint + int $1"); 590a094abddSPaolo Bonzini 591a094abddSPaolo Bonzini /* 592a094abddSPaolo Bonzini * Here the #DB and #BP handlers are invoked once each. 593a094abddSPaolo Bonzini */ 594a094abddSPaolo Bonzini n = 1; 595a094abddSPaolo Bonzini bp_addr = 0; 596a094abddSPaolo Bonzini asm volatile( 597a094abddSPaolo Bonzini "mov %0,%%ss\n\t" 598a094abddSPaolo Bonzini ".byte 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0xcc\n\t" 599a094abddSPaolo Bonzini "sw_bp2:" 600a094abddSPaolo Bonzini : "=m" (value) : : "rax"); 601a094abddSPaolo Bonzini extern unsigned char sw_bp2; 602a299895bSThomas Huth report(n == 3 && bp_addr == (unsigned long)&sw_bp2, 603a299895bSThomas Huth "MOV SS + watchpoint + INT3"); 60486065ca2SAndrew Jones return report_summary(); 605478027f5SJan Kiszka } 606