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 */ 11478027f5SJan Kiszka 12478027f5SJan Kiszka #include "libcflat.h" 132b934609SXiaoyao Li #include "processor.h" 14478027f5SJan Kiszka #include "desc.h" 15*b8a4530dSSean Christopherson #include "usermode.h" 16478027f5SJan Kiszka 17230db53fSPaolo Bonzini static volatile unsigned long bp_addr; 18230db53fSPaolo Bonzini static volatile unsigned long db_addr[10], dr6[10]; 19478027f5SJan Kiszka static volatile unsigned int n; 20478027f5SJan Kiszka static volatile unsigned long value; 21478027f5SJan Kiszka 227f8f7356SKrish Sadhukhan static inline void write_dr4(ulong val) 232c6863b2SPaolo Bonzini { 247f8f7356SKrish Sadhukhan asm volatile ("mov %0, %%dr4" : : "r"(val) : "memory"); 252c6863b2SPaolo Bonzini } 262c6863b2SPaolo Bonzini 277f8f7356SKrish Sadhukhan static inline ulong read_dr4(void) 28478027f5SJan Kiszka { 297f8f7356SKrish Sadhukhan ulong val; 307f8f7356SKrish Sadhukhan asm volatile ("mov %%dr4, %0" : "=r"(val)); 317f8f7356SKrish Sadhukhan return val; 32478027f5SJan Kiszka } 33478027f5SJan Kiszka 34478027f5SJan Kiszka static void handle_db(struct ex_regs *regs) 35478027f5SJan Kiszka { 36230db53fSPaolo Bonzini db_addr[n] = regs->rip; 377f8f7356SKrish Sadhukhan dr6[n] = read_dr6(); 38478027f5SJan Kiszka 39478027f5SJan Kiszka if (dr6[n] & 0x1) 409734b423SSean Christopherson regs->rflags |= X86_EFLAGS_RF; 41478027f5SJan Kiszka 42478027f5SJan Kiszka if (++n >= 10) { 439734b423SSean Christopherson regs->rflags &= ~X86_EFLAGS_TF; 447f8f7356SKrish Sadhukhan write_dr7(0x00000400); 45478027f5SJan Kiszka } 46478027f5SJan Kiszka } 47478027f5SJan Kiszka 489734b423SSean Christopherson static inline bool is_single_step_db(unsigned long dr6_val) 499734b423SSean Christopherson { 509734b423SSean Christopherson return dr6_val == 0xffff4ff0; 519734b423SSean Christopherson } 529734b423SSean Christopherson 539734b423SSean Christopherson static inline bool is_icebp_db(unsigned long dr6_val) 549734b423SSean Christopherson { 559734b423SSean Christopherson return dr6_val == 0xffff0ff0; 569734b423SSean Christopherson } 579734b423SSean Christopherson 58a094abddSPaolo Bonzini extern unsigned char handle_db_save_rip; 59a094abddSPaolo Bonzini asm("handle_db_save_rip:\n" 60a094abddSPaolo Bonzini "stc\n" 61a094abddSPaolo Bonzini "nop;nop;nop\n" 62a094abddSPaolo Bonzini "rclq $1, n(%rip)\n" 63a094abddSPaolo Bonzini "iretq\n"); 64a094abddSPaolo Bonzini 65478027f5SJan Kiszka static void handle_bp(struct ex_regs *regs) 66478027f5SJan Kiszka { 67230db53fSPaolo Bonzini bp_addr = regs->rip; 68478027f5SJan Kiszka } 69478027f5SJan Kiszka 702c6863b2SPaolo Bonzini bool got_ud; 712c6863b2SPaolo Bonzini static void handle_ud(struct ex_regs *regs) 722c6863b2SPaolo Bonzini { 732c6863b2SPaolo Bonzini unsigned long cr4 = read_cr4(); 742c6863b2SPaolo Bonzini write_cr4(cr4 & ~X86_CR4_DE); 752c6863b2SPaolo Bonzini got_ud = 1; 762c6863b2SPaolo Bonzini } 772c6863b2SPaolo Bonzini 789734b423SSean Christopherson typedef unsigned long (*db_test_fn)(void); 79*b8a4530dSSean Christopherson typedef void (*db_report_fn)(unsigned long, const char *); 809734b423SSean Christopherson 819734b423SSean Christopherson static void __run_single_step_db_test(db_test_fn test, db_report_fn report_fn) 82478027f5SJan Kiszka { 83478027f5SJan Kiszka unsigned long start; 84*b8a4530dSSean Christopherson bool ign; 859734b423SSean Christopherson 869734b423SSean Christopherson n = 0; 879734b423SSean Christopherson write_dr6(0); 889734b423SSean Christopherson 899734b423SSean Christopherson start = test(); 90*b8a4530dSSean Christopherson report_fn(start, ""); 91*b8a4530dSSean Christopherson 92*b8a4530dSSean Christopherson n = 0; 93*b8a4530dSSean Christopherson write_dr6(0); 94*b8a4530dSSean Christopherson /* 95*b8a4530dSSean Christopherson * Run the test in usermode. Use the expected start RIP from the first 96*b8a4530dSSean Christopherson * run, the usermode framework doesn't make it easy to get the expected 97*b8a4530dSSean Christopherson * RIP out of the test, and it shouldn't change in any case. Run the 98*b8a4530dSSean Christopherson * test with IOPL=3 so that it can use OUT, CLI, STI, etc... 99*b8a4530dSSean Christopherson */ 100*b8a4530dSSean Christopherson set_iopl(3); 101*b8a4530dSSean Christopherson run_in_user((usermode_func)test, GP_VECTOR, 0, 0, 0, 0, &ign); 102*b8a4530dSSean Christopherson set_iopl(0); 103*b8a4530dSSean Christopherson 104*b8a4530dSSean Christopherson report_fn(start, "Usermode "); 1059734b423SSean Christopherson } 1069734b423SSean Christopherson 1079734b423SSean Christopherson #define run_ss_db_test(name) __run_single_step_db_test(name, report_##name) 1089734b423SSean Christopherson 109*b8a4530dSSean Christopherson static void report_singlestep_basic(unsigned long start, const char *usermode) 1109734b423SSean Christopherson { 1119734b423SSean Christopherson report(n == 3 && 1129734b423SSean Christopherson is_single_step_db(dr6[0]) && db_addr[0] == start && 1139734b423SSean Christopherson is_single_step_db(dr6[1]) && db_addr[1] == start + 1 && 1149734b423SSean Christopherson is_single_step_db(dr6[2]) && db_addr[2] == start + 1 + 1, 115*b8a4530dSSean Christopherson "%sSingle-step #DB basic test", usermode); 1169734b423SSean Christopherson } 1179734b423SSean Christopherson 1189734b423SSean Christopherson static unsigned long singlestep_basic(void) 1199734b423SSean Christopherson { 1209734b423SSean Christopherson unsigned long start; 1219734b423SSean Christopherson 1229734b423SSean Christopherson /* 1239734b423SSean Christopherson * After being enabled, single-step breakpoints have a one instruction 1249734b423SSean Christopherson * delay before the first #DB is generated. 1259734b423SSean Christopherson */ 1269734b423SSean Christopherson asm volatile ( 1279734b423SSean Christopherson "pushf\n\t" 1289734b423SSean Christopherson "pop %%rax\n\t" 1299734b423SSean Christopherson "or $(1<<8),%%rax\n\t" 1309734b423SSean Christopherson "push %%rax\n\t" 1319734b423SSean Christopherson "popf\n\t" 1329734b423SSean Christopherson "and $~(1<<8),%%rax\n\t" 1339734b423SSean Christopherson "1:push %%rax\n\t" 1349734b423SSean Christopherson "popf\n\t" 1359734b423SSean Christopherson "lea 1b, %0\n\t" 1369734b423SSean Christopherson : "=r" (start) : : "rax" 1379734b423SSean Christopherson ); 1389734b423SSean Christopherson return start; 1399734b423SSean Christopherson } 1409734b423SSean Christopherson 141*b8a4530dSSean Christopherson static void report_singlestep_emulated_instructions(unsigned long start, 142*b8a4530dSSean Christopherson const char *usermode) 1439734b423SSean Christopherson { 1449734b423SSean Christopherson report(n == 7 && 1459734b423SSean Christopherson is_single_step_db(dr6[0]) && db_addr[0] == start && 1469734b423SSean Christopherson is_single_step_db(dr6[1]) && db_addr[1] == start + 1 && 1479734b423SSean Christopherson is_single_step_db(dr6[2]) && db_addr[2] == start + 1 + 3 && 1489734b423SSean Christopherson is_single_step_db(dr6[3]) && db_addr[3] == start + 1 + 3 + 2 && 1499734b423SSean Christopherson is_single_step_db(dr6[4]) && db_addr[4] == start + 1 + 3 + 2 + 5 && 1506bfb9572SSean Christopherson is_single_step_db(dr6[5]) && db_addr[5] == start + 1 + 3 + 2 + 5 + 1 && 1516bfb9572SSean Christopherson is_single_step_db(dr6[6]) && db_addr[6] == start + 1 + 3 + 2 + 5 + 1 + 1, 152*b8a4530dSSean Christopherson "%sSingle-step #DB on emulated instructions", usermode); 1539734b423SSean Christopherson } 1549734b423SSean Christopherson 1559734b423SSean Christopherson static unsigned long singlestep_emulated_instructions(void) 1569734b423SSean Christopherson { 1579734b423SSean Christopherson unsigned long start; 1589734b423SSean Christopherson 1599734b423SSean Christopherson /* 1609734b423SSean Christopherson * Verify single-step #DB are generated correctly on emulated 1619734b423SSean Christopherson * instructions, e.g. CPUID and RDMSR. 1629734b423SSean Christopherson */ 1639734b423SSean Christopherson asm volatile ( 1649734b423SSean Christopherson "pushf\n\t" 1659734b423SSean Christopherson "pop %%rax\n\t" 1669734b423SSean Christopherson "or $(1<<8),%%rax\n\t" 1679734b423SSean Christopherson "push %%rax\n\t" 1689734b423SSean Christopherson "popf\n\t" 1699734b423SSean Christopherson "and $~(1<<8),%%rax\n\t" 1709734b423SSean Christopherson "1:push %%rax\n\t" 1719734b423SSean Christopherson "xor %%rax,%%rax\n\t" 1729734b423SSean Christopherson "cpuid\n\t" 1736bfb9572SSean Christopherson "movl $0x3fd, %%edx\n\t" 1746bfb9572SSean Christopherson "inb %%dx, %%al\n\t" 1759734b423SSean Christopherson "popf\n\t" 1769734b423SSean Christopherson "lea 1b,%0\n\t" 1779734b423SSean Christopherson : "=r" (start) : : "rax", "ebx", "ecx", "edx" 1789734b423SSean Christopherson ); 1799734b423SSean Christopherson return start; 1809734b423SSean Christopherson } 1819734b423SSean Christopherson 1829734b423SSean Christopherson int main(int ac, char **av) 1839734b423SSean Christopherson { 1842c6863b2SPaolo Bonzini unsigned long cr4; 185478027f5SJan Kiszka 186478027f5SJan Kiszka handle_exception(DB_VECTOR, handle_db); 187478027f5SJan Kiszka handle_exception(BP_VECTOR, handle_bp); 1882c6863b2SPaolo Bonzini handle_exception(UD_VECTOR, handle_ud); 1892c6863b2SPaolo Bonzini 1909734b423SSean Christopherson /* 1919734b423SSean Christopherson * DR4 is an alias for DR6 (and DR5 aliases DR7) if CR4.DE is NOT set, 1929734b423SSean Christopherson * and is reserved if CR4.DE=1 (Debug Extensions enabled). 1939734b423SSean Christopherson */ 1942c6863b2SPaolo Bonzini got_ud = 0; 1952c6863b2SPaolo Bonzini cr4 = read_cr4(); 1962c6863b2SPaolo Bonzini write_cr4(cr4 & ~X86_CR4_DE); 1977f8f7356SKrish Sadhukhan write_dr4(0); 1987f8f7356SKrish Sadhukhan write_dr6(0xffff4ff2); 1997f8f7356SKrish Sadhukhan report(read_dr4() == 0xffff4ff2 && !got_ud, "reading DR4 with CR4.DE == 0"); 2002c6863b2SPaolo Bonzini 2012c6863b2SPaolo Bonzini cr4 = read_cr4(); 2022c6863b2SPaolo Bonzini write_cr4(cr4 | X86_CR4_DE); 2037f8f7356SKrish Sadhukhan read_dr4(); 2049734b423SSean Christopherson report(got_ud, "DR4 read got #UD with CR4.DE == 1"); 2057f8f7356SKrish Sadhukhan write_dr6(0); 206478027f5SJan Kiszka 207c68a7ff0SPaolo Bonzini extern unsigned char sw_bp; 208c68a7ff0SPaolo Bonzini asm volatile("int3; sw_bp:"); 209a299895bSThomas Huth report(bp_addr == (unsigned long)&sw_bp, "#BP"); 210478027f5SJan Kiszka 2119734b423SSean Christopherson /* 2129734b423SSean Christopherson * The CPU sets/clears bits 0-3 (trap bits for DR0-3) on #DB based on 2139734b423SSean Christopherson * whether or not the corresponding DR0-3 got a match. All other bits 2149734b423SSean Christopherson * in DR6 are set if and only if their associated breakpoint condition 2159734b423SSean Christopherson * is active, and are never cleared by the CPU. Verify a match on DR0 2169734b423SSean Christopherson * is reported correctly, and that DR6.BS is not set when single-step 2179734b423SSean Christopherson * breakpoints are disabled, but is left set (if set by software). 2189734b423SSean Christopherson */ 2199e486280SPaolo Bonzini n = 0; 220c68a7ff0SPaolo Bonzini extern unsigned char hw_bp1; 2217f8f7356SKrish Sadhukhan write_dr0(&hw_bp1); 2227f8f7356SKrish Sadhukhan write_dr7(0x00000402); 223c68a7ff0SPaolo Bonzini asm volatile("hw_bp1: nop"); 224a299895bSThomas Huth report(n == 1 && 225a299895bSThomas Huth db_addr[0] == ((unsigned long)&hw_bp1) && dr6[0] == 0xffff0ff1, 226a299895bSThomas Huth "hw breakpoint (test that dr6.BS is not set)"); 227478027f5SJan Kiszka 228478027f5SJan Kiszka n = 0; 229c68a7ff0SPaolo Bonzini extern unsigned char hw_bp2; 2307f8f7356SKrish Sadhukhan write_dr0(&hw_bp2); 2317f8f7356SKrish Sadhukhan write_dr6(0x00004002); 232c68a7ff0SPaolo Bonzini asm volatile("hw_bp2: nop"); 233a299895bSThomas Huth report(n == 1 && 234a299895bSThomas Huth db_addr[0] == ((unsigned long)&hw_bp2) && dr6[0] == 0xffff4ff1, 235a299895bSThomas Huth "hw breakpoint (test that dr6.BS is not cleared)"); 2369e486280SPaolo Bonzini 2379734b423SSean Christopherson run_ss_db_test(singlestep_basic); 2389734b423SSean Christopherson run_ss_db_test(singlestep_emulated_instructions); 2390a982d78SKyle Huey 240478027f5SJan Kiszka n = 0; 2417f8f7356SKrish Sadhukhan write_dr1((void *)&value); 2427f8f7356SKrish Sadhukhan write_dr7(0x00d0040a); // 4-byte write 243478027f5SJan Kiszka 244c68a7ff0SPaolo Bonzini extern unsigned char hw_wp1; 245478027f5SJan Kiszka asm volatile( 246478027f5SJan Kiszka "mov $42,%%rax\n\t" 247c68a7ff0SPaolo Bonzini "mov %%rax,%0\n\t; hw_wp1:" 248478027f5SJan Kiszka : "=m" (value) : : "rax"); 249a299895bSThomas Huth report(n == 1 && 250a299895bSThomas Huth db_addr[0] == ((unsigned long)&hw_wp1) && dr6[0] == 0xffff4ff2, 251a299895bSThomas Huth "hw watchpoint (test that dr6.BS is not cleared)"); 2529e486280SPaolo Bonzini 2539e486280SPaolo Bonzini n = 0; 2547f8f7356SKrish Sadhukhan write_dr6(0); 2559e486280SPaolo Bonzini 256c68a7ff0SPaolo Bonzini extern unsigned char hw_wp2; 2579e486280SPaolo Bonzini asm volatile( 2589e486280SPaolo Bonzini "mov $42,%%rax\n\t" 259c68a7ff0SPaolo Bonzini "mov %%rax,%0\n\t; hw_wp2:" 2609e486280SPaolo Bonzini : "=m" (value) : : "rax"); 261a299895bSThomas Huth report(n == 1 && 262a299895bSThomas Huth db_addr[0] == ((unsigned long)&hw_wp2) && dr6[0] == 0xffff0ff2, 263a299895bSThomas Huth "hw watchpoint (test that dr6.BS is not set)"); 2649e486280SPaolo Bonzini 2659e486280SPaolo Bonzini n = 0; 2667f8f7356SKrish Sadhukhan write_dr6(0); 267c68a7ff0SPaolo Bonzini extern unsigned char sw_icebp; 268c68a7ff0SPaolo Bonzini asm volatile(".byte 0xf1; sw_icebp:"); 269a299895bSThomas Huth report(n == 1 && 270a299895bSThomas Huth db_addr[0] == (unsigned long)&sw_icebp && dr6[0] == 0xffff0ff0, 271a299895bSThomas Huth "icebp"); 272478027f5SJan Kiszka 2737f8f7356SKrish Sadhukhan write_dr7(0x400); 274a094abddSPaolo Bonzini value = KERNEL_DS; 2757f8f7356SKrish Sadhukhan write_dr7(0x00f0040a); // 4-byte read or write 276a094abddSPaolo Bonzini 277a094abddSPaolo Bonzini /* 278a094abddSPaolo Bonzini * Each invocation of the handler should shift n by 1 and set bit 0 to 1. 279a094abddSPaolo Bonzini * We expect a single invocation, so n should become 3. If the entry 280a094abddSPaolo Bonzini * RIP is wrong, or if the handler is executed more than once, the value 281a094abddSPaolo Bonzini * will not match. 282a094abddSPaolo Bonzini */ 283a094abddSPaolo Bonzini set_idt_entry(1, &handle_db_save_rip, 0); 284a094abddSPaolo Bonzini 285a094abddSPaolo Bonzini n = 1; 286a094abddSPaolo Bonzini asm volatile( 287a094abddSPaolo Bonzini "clc\n\t" 288a094abddSPaolo Bonzini "mov %0,%%ss\n\t" 289a094abddSPaolo Bonzini ".byte 0x2e, 0x2e, 0xf1" 290a094abddSPaolo Bonzini : "=m" (value) : : "rax"); 291a299895bSThomas Huth report(n == 3, "MOV SS + watchpoint + ICEBP"); 292a094abddSPaolo Bonzini 293a094abddSPaolo Bonzini /* 294a094abddSPaolo Bonzini * Here the #DB handler is invoked twice, once as a software exception 295a094abddSPaolo Bonzini * and once as a software interrupt. 296a094abddSPaolo Bonzini */ 297a094abddSPaolo Bonzini n = 1; 298a094abddSPaolo Bonzini asm volatile( 299a094abddSPaolo Bonzini "clc\n\t" 300a094abddSPaolo Bonzini "mov %0,%%ss\n\t" 301a094abddSPaolo Bonzini "int $1" 302a094abddSPaolo Bonzini : "=m" (value) : : "rax"); 303a299895bSThomas Huth report(n == 7, "MOV SS + watchpoint + int $1"); 304a094abddSPaolo Bonzini 305a094abddSPaolo Bonzini /* 306a094abddSPaolo Bonzini * Here the #DB and #BP handlers are invoked once each. 307a094abddSPaolo Bonzini */ 308a094abddSPaolo Bonzini n = 1; 309a094abddSPaolo Bonzini bp_addr = 0; 310a094abddSPaolo Bonzini asm volatile( 311a094abddSPaolo Bonzini "mov %0,%%ss\n\t" 312a094abddSPaolo Bonzini ".byte 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0xcc\n\t" 313a094abddSPaolo Bonzini "sw_bp2:" 314a094abddSPaolo Bonzini : "=m" (value) : : "rax"); 315a094abddSPaolo Bonzini extern unsigned char sw_bp2; 316a299895bSThomas Huth report(n == 3 && bp_addr == (unsigned long)&sw_bp2, 317a299895bSThomas Huth "MOV SS + watchpoint + INT3"); 31886065ca2SAndrew Jones return report_summary(); 319478027f5SJan Kiszka } 320