xref: /kvm-unit-tests/x86/debug.c (revision 302fbd56b98e84640a1316c3c71854b06c8b83c4)
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