1 /* 2 * Test for x86 debugging facilities 3 * 4 * Copyright (c) Siemens AG, 2014 5 * 6 * Authors: 7 * Jan Kiszka <jan.kiszka@siemens.com> 8 * 9 * This work is licensed under the terms of the GNU GPL, version 2. 10 */ 11 #include <asm/debugreg.h> 12 13 #include "libcflat.h" 14 #include "processor.h" 15 #include "desc.h" 16 #include "usermode.h" 17 18 static volatile unsigned long bp_addr; 19 static volatile unsigned long db_addr[10], dr6[10]; 20 static volatile unsigned int n; 21 static volatile unsigned long value; 22 23 static inline void write_dr4(ulong val) 24 { 25 asm volatile ("mov %0, %%dr4" : : "r"(val) : "memory"); 26 } 27 28 static inline ulong read_dr4(void) 29 { 30 ulong val; 31 asm volatile ("mov %%dr4, %0" : "=r"(val)); 32 return val; 33 } 34 35 static void handle_db(struct ex_regs *regs) 36 { 37 db_addr[n] = regs->rip; 38 dr6[n] = read_dr6(); 39 40 if (dr6[n] & 0x1) 41 regs->rflags |= X86_EFLAGS_RF; 42 43 if (++n >= 10) { 44 regs->rflags &= ~X86_EFLAGS_TF; 45 write_dr7(0x00000400); 46 } 47 } 48 49 static inline bool is_single_step_db(unsigned long dr6_val) 50 { 51 return dr6_val == (DR6_ACTIVE_LOW | DR6_BS); 52 } 53 54 static inline bool is_general_detect_db(unsigned long dr6_val) 55 { 56 return dr6_val == (DR6_ACTIVE_LOW | DR6_BD); 57 } 58 59 static inline bool is_icebp_db(unsigned long dr6_val) 60 { 61 return dr6_val == DR6_ACTIVE_LOW; 62 } 63 64 extern unsigned char handle_db_save_rip; 65 asm("handle_db_save_rip:\n" 66 "stc\n" 67 "nop;nop;nop\n" 68 "rclq $1, n(%rip)\n" 69 "iretq\n"); 70 71 static void handle_bp(struct ex_regs *regs) 72 { 73 bp_addr = regs->rip; 74 } 75 76 bool got_ud; 77 static void handle_ud(struct ex_regs *regs) 78 { 79 unsigned long cr4 = read_cr4(); 80 write_cr4(cr4 & ~X86_CR4_DE); 81 got_ud = 1; 82 } 83 84 typedef unsigned long (*db_test_fn)(void); 85 typedef void (*db_report_fn)(unsigned long, const char *); 86 87 static unsigned long singlestep_with_movss_blocking_and_dr7_gd(void); 88 static unsigned long singlestep_with_sti_hlt(void); 89 90 static void __run_single_step_db_test(db_test_fn test, db_report_fn report_fn) 91 { 92 unsigned long start; 93 bool ign; 94 95 n = 0; 96 write_dr6(0); 97 98 start = test(); 99 report_fn(start, ""); 100 101 /* 102 * MOV DR #GPs at CPL>0, don't try to run the DR7.GD test in usermode. 103 * Likewise for HLT. 104 */ 105 if (test == singlestep_with_movss_blocking_and_dr7_gd 106 || test == singlestep_with_sti_hlt) 107 return; 108 109 n = 0; 110 write_dr6(0); 111 112 /* 113 * Run the test in usermode. Use the expected start RIP from the first 114 * run, the usermode framework doesn't make it easy to get the expected 115 * RIP out of the test, and it shouldn't change in any case. Run the 116 * test with IOPL=3 so that it can use OUT, CLI, STI, etc... 117 */ 118 set_iopl(3); 119 run_in_user((usermode_func)test, GP_VECTOR, 0, 0, 0, 0, &ign); 120 set_iopl(0); 121 122 report_fn(start, "Usermode "); 123 } 124 125 #define run_ss_db_test(name) __run_single_step_db_test(name, report_##name) 126 127 static void report_singlestep_basic(unsigned long start, const char *usermode) 128 { 129 report(n == 3 && 130 is_single_step_db(dr6[0]) && db_addr[0] == start && 131 is_single_step_db(dr6[1]) && db_addr[1] == start + 1 && 132 is_single_step_db(dr6[2]) && db_addr[2] == start + 1 + 1, 133 "%sSingle-step #DB basic test", usermode); 134 } 135 136 static noinline unsigned long singlestep_basic(void) 137 { 138 unsigned long start; 139 140 /* 141 * After being enabled, single-step breakpoints have a one instruction 142 * delay before the first #DB is generated. 143 */ 144 asm volatile ( 145 "pushf\n\t" 146 "pop %%rax\n\t" 147 "or $(1<<8),%%rax\n\t" 148 "push %%rax\n\t" 149 "popf\n\t" 150 "and $~(1<<8),%%rax\n\t" 151 "1:push %%rax\n\t" 152 "popf\n\t" 153 "lea 1b(%%rip), %0\n\t" 154 : "=r" (start) : : "rax" 155 ); 156 return start; 157 } 158 159 static void report_singlestep_emulated_instructions(unsigned long start, 160 const char *usermode) 161 { 162 report(n == 7 && 163 is_single_step_db(dr6[0]) && db_addr[0] == start && 164 is_single_step_db(dr6[1]) && db_addr[1] == start + 1 && 165 is_single_step_db(dr6[2]) && db_addr[2] == start + 1 + 3 && 166 is_single_step_db(dr6[3]) && db_addr[3] == start + 1 + 3 + 2 && 167 is_single_step_db(dr6[4]) && db_addr[4] == start + 1 + 3 + 2 + 5 && 168 is_single_step_db(dr6[5]) && db_addr[5] == start + 1 + 3 + 2 + 5 + 1 && 169 is_single_step_db(dr6[6]) && db_addr[6] == start + 1 + 3 + 2 + 5 + 1 + 1, 170 "%sSingle-step #DB on emulated instructions", usermode); 171 } 172 173 static noinline unsigned long singlestep_emulated_instructions(void) 174 { 175 unsigned long start; 176 177 /* 178 * Verify single-step #DB are generated correctly on emulated 179 * instructions, e.g. CPUID and RDMSR. 180 */ 181 asm volatile ( 182 "pushf\n\t" 183 "pop %%rax\n\t" 184 "or $(1<<8),%%rax\n\t" 185 "push %%rax\n\t" 186 "popf\n\t" 187 "and $~(1<<8),%%rax\n\t" 188 "1:push %%rax\n\t" 189 "xor %%rax,%%rax\n\t" 190 "cpuid\n\t" 191 "movl $0x3fd, %%edx\n\t" 192 "inb %%dx, %%al\n\t" 193 "popf\n\t" 194 "lea 1b(%%rip),%0\n\t" 195 : "=r" (start) : : "rax", "ebx", "ecx", "edx" 196 ); 197 return start; 198 } 199 200 static void report_singlestep_with_sti_blocking(unsigned long start, 201 const char *usermode) 202 { 203 report(n == 4 && 204 is_single_step_db(dr6[0]) && db_addr[0] == start && 205 is_single_step_db(dr6[1]) && db_addr[1] == start + 6 && 206 is_single_step_db(dr6[2]) && db_addr[2] == start + 6 + 1 && 207 is_single_step_db(dr6[3]) && db_addr[3] == start + 6 + 1 + 1, 208 "%sSingle-step #DB w/ STI blocking", usermode); 209 } 210 211 212 static noinline unsigned long singlestep_with_sti_blocking(void) 213 { 214 unsigned long start_rip; 215 216 /* 217 * STI blocking doesn't suppress #DBs, thus the first single-step #DB 218 * should arrive after the standard one instruction delay. 219 */ 220 asm volatile( 221 "cli\n\t" 222 "pushf\n\t" 223 "pop %%rax\n\t" 224 "or $(1<<8),%%rax\n\t" 225 "push %%rax\n\t" 226 "popf\n\t" 227 "sti\n\t" 228 "1:and $~(1<<8),%%rax\n\t" 229 "push %%rax\n\t" 230 "popf\n\t" 231 "lea 1b(%%rip),%0\n\t" 232 : "=r" (start_rip) : : "rax" 233 ); 234 return start_rip; 235 } 236 237 static void report_singlestep_with_movss_blocking(unsigned long start, 238 const char *usermode) 239 { 240 report(n == 3 && 241 is_single_step_db(dr6[0]) && db_addr[0] == start && 242 is_single_step_db(dr6[1]) && db_addr[1] == start + 1 && 243 is_single_step_db(dr6[2]) && db_addr[2] == start + 1 + 1, 244 "%sSingle-step #DB w/ MOVSS blocking", usermode); 245 } 246 247 static noinline unsigned long singlestep_with_movss_blocking(void) 248 { 249 unsigned long start_rip; 250 251 /* 252 * MOVSS blocking suppresses single-step #DBs (and select other #DBs), 253 * thus the first single-step #DB should occur after MOVSS blocking 254 * expires, i.e. two instructions after #DBs are enabled in this case. 255 */ 256 asm volatile( 257 "pushf\n\t" 258 "pop %%rax\n\t" 259 "or $(1<<8),%%rax\n\t" 260 "push %%rax\n\t" 261 "mov %%ss, %%ax\n\t" 262 "popf\n\t" 263 "mov %%ax, %%ss\n\t" 264 "and $~(1<<8),%%rax\n\t" 265 "1: push %%rax\n\t" 266 "popf\n\t" 267 "lea 1b(%%rip),%0\n\t" 268 : "=r" (start_rip) : : "rax" 269 ); 270 return start_rip; 271 } 272 273 274 static void report_singlestep_with_movss_blocking_and_icebp(unsigned long start, 275 const char *usermode) 276 { 277 report(n == 4 && 278 is_icebp_db(dr6[0]) && db_addr[0] == start && 279 is_single_step_db(dr6[1]) && db_addr[1] == start + 6 && 280 is_single_step_db(dr6[2]) && db_addr[2] == start + 6 + 1 && 281 is_single_step_db(dr6[3]) && db_addr[3] == start + 6 + 1 + 1, 282 "%sSingle-Step + ICEBP #DB w/ MOVSS blocking", usermode); 283 } 284 285 static noinline unsigned long singlestep_with_movss_blocking_and_icebp(void) 286 { 287 unsigned long start; 288 289 /* 290 * ICEBP, a.k.a. INT1 or int1icebrk, is an oddball. It generates a 291 * trap-like #DB, is intercepted if #DBs are intercepted, and manifests 292 * as a #DB VM-Exit, but the VM-Exit occurs on the ICEBP itself, i.e. 293 * it's treated as an instruction intercept. Verify that ICEBP is 294 * correctly emulated as a trap-like #DB when intercepted, and that 295 * MOVSS blocking is handled correctly with respect to single-step 296 * breakpoints being enabled. 297 */ 298 asm volatile( 299 "pushf\n\t" 300 "pop %%rax\n\t" 301 "or $(1<<8),%%rax\n\t" 302 "push %%rax\n\t" 303 "mov %%ss, %%ax\n\t" 304 "popf\n\t" 305 "mov %%ax, %%ss\n\t" 306 ".byte 0xf1;" 307 "1:and $~(1<<8),%%rax\n\t" 308 "push %%rax\n\t" 309 "popf\n\t" 310 "lea 1b(%%rip),%0\n\t" 311 : "=r" (start) : : "rax" 312 ); 313 return start; 314 } 315 316 static void report_singlestep_with_movss_blocking_and_dr7_gd(unsigned long start, 317 const char *ign) 318 { 319 report(n == 5 && 320 is_general_detect_db(dr6[0]) && db_addr[0] == start && 321 is_single_step_db(dr6[1]) && db_addr[1] == start + 3 && 322 is_single_step_db(dr6[2]) && db_addr[2] == start + 3 + 6 && 323 is_single_step_db(dr6[3]) && db_addr[3] == start + 3 + 6 + 1 && 324 is_single_step_db(dr6[4]) && db_addr[4] == start + 3 + 6 + 1 + 1, 325 "Single-step #DB w/ MOVSS blocking and DR7.GD=1"); 326 } 327 328 static noinline unsigned long singlestep_with_movss_blocking_and_dr7_gd(void) 329 { 330 unsigned long start_rip; 331 332 write_dr7(DR7_GD); 333 334 /* 335 * MOVSS blocking does NOT suppress General Detect #DBs, which have 336 * fault-like behavior. Note, DR7.GD is cleared by the CPU upon 337 * successful delivery of the #DB. DR6.BD is NOT cleared by the CPU, 338 * but the MOV DR6 below will be re-executed after handling the 339 * General Detect #DB. 340 */ 341 asm volatile( 342 "xor %0, %0\n\t" 343 "pushf\n\t" 344 "pop %%rax\n\t" 345 "or $(1<<8),%%rax\n\t" 346 "push %%rax\n\t" 347 "mov %%ss, %%ax\n\t" 348 "popf\n\t" 349 "mov %%ax, %%ss\n\t" 350 "1: mov %0, %%dr6\n\t" 351 "and $~(1<<8),%%rax\n\t" 352 "push %%rax\n\t" 353 "popf\n\t" 354 "lea 1b(%%rip),%0\n\t" 355 : "=r" (start_rip) : : "rax" 356 ); 357 return start_rip; 358 } 359 360 static void report_singlestep_with_sti_hlt(unsigned long start, 361 const char *usermode) 362 { 363 report(n == 5 && 364 is_single_step_db(dr6[0]) && db_addr[0] == start && 365 is_single_step_db(dr6[1]) && db_addr[1] == start + 1 && 366 is_single_step_db(dr6[2]) && db_addr[2] == start + 1 + 6 && 367 is_single_step_db(dr6[3]) && db_addr[3] == start + 1 + 6 + 1 && 368 is_single_step_db(dr6[4]) && db_addr[4] == start + 1 + 6 + 1 + 1, 369 "%sSingle-step #DB w/ STI;HLT", usermode); 370 } 371 372 #define APIC_LVT_TIMER_VECTOR (0xee) 373 374 static void lvtt_handler(isr_regs_t *regs) 375 { 376 eoi(); 377 } 378 379 static noinline unsigned long singlestep_with_sti_hlt(void) 380 { 381 unsigned long start_rip; 382 383 cli(); 384 385 handle_irq(APIC_LVT_TIMER_VECTOR, lvtt_handler); 386 apic_write(APIC_LVTT, APIC_LVT_TIMER_ONESHOT | 387 APIC_LVT_TIMER_VECTOR); 388 apic_write(APIC_TDCR, 0x0000000b); 389 apic_write(APIC_TMICT, 1000000); 390 391 /* 392 * STI blocking doesn't suppress #DBs, thus the first single-step #DB 393 * should arrive after the standard one instruction delay. 394 */ 395 asm volatile( 396 "pushf\n\t" 397 "pop %%rax\n\t" 398 "or $(1<<8),%%rax\n\t" 399 "push %%rax\n\t" 400 "popf\n\t" 401 "sti\n\t" 402 "1:hlt;\n\t" 403 "and $~(1<<8),%%rax\n\t" 404 "push %%rax\n\t" 405 "popf\n\t" 406 "lea 1b(%%rip),%0\n\t" 407 : "=r" (start_rip) : : "rax" 408 ); 409 return start_rip; 410 } 411 412 int main(int ac, char **av) 413 { 414 unsigned long cr4; 415 416 handle_exception(DB_VECTOR, handle_db); 417 handle_exception(BP_VECTOR, handle_bp); 418 handle_exception(UD_VECTOR, handle_ud); 419 420 /* 421 * DR4 is an alias for DR6 (and DR5 aliases DR7) if CR4.DE is NOT set, 422 * and is reserved if CR4.DE=1 (Debug Extensions enabled). 423 */ 424 got_ud = 0; 425 cr4 = read_cr4(); 426 write_cr4(cr4 & ~X86_CR4_DE); 427 write_dr4(0); 428 write_dr6(DR6_ACTIVE_LOW | DR6_BS | DR6_TRAP1); 429 report(read_dr4() == (DR6_ACTIVE_LOW | DR6_BS | DR6_TRAP1) && !got_ud, 430 "DR4==DR6 with CR4.DE == 0"); 431 432 cr4 = read_cr4(); 433 write_cr4(cr4 | X86_CR4_DE); 434 read_dr4(); 435 report(got_ud, "DR4 read got #UD with CR4.DE == 1"); 436 write_dr6(0); 437 438 extern unsigned char sw_bp; 439 asm volatile("int3; sw_bp:"); 440 report(bp_addr == (unsigned long)&sw_bp, "#BP"); 441 442 /* 443 * The CPU sets/clears bits 0-3 (trap bits for DR0-3) on #DB based on 444 * whether or not the corresponding DR0-3 got a match. All other bits 445 * in DR6 are set if and only if their associated breakpoint condition 446 * is active, and are never cleared by the CPU. Verify a match on DR0 447 * is reported correctly, and that DR6.BS is not set when single-step 448 * breakpoints are disabled, but is left set (if set by software). 449 */ 450 n = 0; 451 extern unsigned char hw_bp1; 452 write_dr0(&hw_bp1); 453 write_dr7(DR7_FIXED_1 | DR7_GLOBAL_ENABLE_DR0); 454 asm volatile("hw_bp1: nop"); 455 report(n == 1 && 456 db_addr[0] == ((unsigned long)&hw_bp1) && 457 dr6[0] == (DR6_ACTIVE_LOW | DR6_TRAP0), 458 "hw breakpoint (test that dr6.BS is not set)"); 459 460 n = 0; 461 extern unsigned char hw_bp2; 462 write_dr0(&hw_bp2); 463 write_dr6(DR6_BS | DR6_TRAP1); 464 asm volatile("hw_bp2: nop"); 465 report(n == 1 && 466 db_addr[0] == ((unsigned long)&hw_bp2) && 467 dr6[0] == (DR6_ACTIVE_LOW | DR6_BS | DR6_TRAP0), 468 "hw breakpoint (test that dr6.BS is not cleared)"); 469 470 run_ss_db_test(singlestep_basic); 471 run_ss_db_test(singlestep_emulated_instructions); 472 run_ss_db_test(singlestep_with_sti_blocking); 473 run_ss_db_test(singlestep_with_movss_blocking); 474 run_ss_db_test(singlestep_with_movss_blocking_and_icebp); 475 run_ss_db_test(singlestep_with_movss_blocking_and_dr7_gd); 476 run_ss_db_test(singlestep_with_sti_hlt); 477 478 n = 0; 479 write_dr1((void *)&value); 480 write_dr6(DR6_BS); 481 write_dr7(0x00d0040a); // 4-byte write 482 483 extern unsigned char hw_wp1; 484 asm volatile( 485 "mov $42,%%rax\n\t" 486 "mov %%rax,%0\n\t; hw_wp1:" 487 : "=m" (value) : : "rax"); 488 report(n == 1 && 489 db_addr[0] == ((unsigned long)&hw_wp1) && 490 dr6[0] == (DR6_ACTIVE_LOW | DR6_BS | DR6_TRAP1), 491 "hw watchpoint (test that dr6.BS is not cleared)"); 492 493 n = 0; 494 write_dr6(0); 495 496 extern unsigned char hw_wp2; 497 asm volatile( 498 "mov $42,%%rax\n\t" 499 "mov %%rax,%0\n\t; hw_wp2:" 500 : "=m" (value) : : "rax"); 501 report(n == 1 && 502 db_addr[0] == ((unsigned long)&hw_wp2) && 503 dr6[0] == (DR6_ACTIVE_LOW | DR6_TRAP1), 504 "hw watchpoint (test that dr6.BS is not set)"); 505 506 n = 0; 507 write_dr6(0); 508 extern unsigned char sw_icebp; 509 asm volatile(".byte 0xf1; sw_icebp:"); 510 report(n == 1 && 511 db_addr[0] == (unsigned long)&sw_icebp && dr6[0] == DR6_ACTIVE_LOW, 512 "icebp"); 513 514 write_dr7(0x400); 515 value = KERNEL_DS; 516 write_dr7(0x00f0040a); // 4-byte read or write 517 518 /* 519 * Each invocation of the handler should shift n by 1 and set bit 0 to 1. 520 * We expect a single invocation, so n should become 3. If the entry 521 * RIP is wrong, or if the handler is executed more than once, the value 522 * will not match. 523 */ 524 set_idt_entry(1, &handle_db_save_rip, 0); 525 526 n = 1; 527 asm volatile( 528 "clc\n\t" 529 "mov %0,%%ss\n\t" 530 ".byte 0x2e, 0x2e, 0xf1" 531 : "=m" (value) : : "rax"); 532 report(n == 3, "MOV SS + watchpoint + ICEBP"); 533 534 /* 535 * Here the #DB handler is invoked twice, once as a software exception 536 * and once as a software interrupt. 537 */ 538 n = 1; 539 asm volatile( 540 "clc\n\t" 541 "mov %0,%%ss\n\t" 542 "int $1" 543 : "=m" (value) : : "rax"); 544 report(n == 7, "MOV SS + watchpoint + int $1"); 545 546 /* 547 * Here the #DB and #BP handlers are invoked once each. 548 */ 549 n = 1; 550 bp_addr = 0; 551 asm volatile( 552 "mov %0,%%ss\n\t" 553 ".byte 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0xcc\n\t" 554 "sw_bp2:" 555 : "=m" (value) : : "rax"); 556 extern unsigned char sw_bp2; 557 report(n == 3 && bp_addr == (unsigned long)&sw_bp2, 558 "MOV SS + watchpoint + INT3"); 559 return report_summary(); 560 } 561