xref: /kvm-unit-tests/x86/debug.c (revision 478027f559bd6d04bb9fb458c0db73f67a6bc69e)
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 
12 #include "libcflat.h"
13 #include "desc.h"
14 
15 static volatile unsigned long bp_addr[10], dr6[10];
16 static volatile unsigned int n;
17 static volatile unsigned long value;
18 
19 static unsigned long get_dr6(void)
20 {
21 	unsigned long value;
22 
23 	asm volatile("mov %%dr6,%0" : "=r" (value));
24 	return value;
25 }
26 
27 static void set_dr0(void *value)
28 {
29 	asm volatile("mov %0,%%dr0" : : "r" (value));
30 }
31 
32 static void set_dr1(void *value)
33 {
34 	asm volatile("mov %0,%%dr1" : : "r" (value));
35 }
36 
37 static void set_dr7(unsigned long value)
38 {
39 	asm volatile("mov %0,%%dr7" : : "r" (value));
40 }
41 
42 static void handle_db(struct ex_regs *regs)
43 {
44 	bp_addr[n] = regs->rip;
45 	dr6[n] = get_dr6();
46 
47 	if (dr6[n] & 0x1)
48 		regs->rflags |= (1 << 16);
49 
50 	if (++n >= 10) {
51 		regs->rflags &= ~(1 << 8);
52 		set_dr7(0x00000400);
53 	}
54 }
55 
56 static void handle_bp(struct ex_regs *regs)
57 {
58 	bp_addr[0] = regs->rip;
59 }
60 
61 int main(int ac, char **av)
62 {
63 	unsigned long start;
64 
65 	setup_idt();
66 	handle_exception(DB_VECTOR, handle_db);
67 	handle_exception(BP_VECTOR, handle_bp);
68 
69 sw_bp:
70 	asm volatile("int3");
71 	report("#BP", bp_addr[0] == (unsigned long)&&sw_bp + 1);
72 
73 	set_dr0(&&hw_bp);
74 	set_dr7(0x00000402);
75 hw_bp:
76 	asm volatile("nop");
77 	report("hw breakpoint",
78 	       n == 1 &&
79 	       bp_addr[0] == ((unsigned long)&&hw_bp) && dr6[0] == 0xffff0ff1);
80 
81 	n = 0;
82 	asm volatile(
83 		"pushf\n\t"
84 		"pop %%rax\n\t"
85 		"or $(1<<8),%%rax\n\t"
86 		"push %%rax\n\t"
87 		"lea (%%rip),%0\n\t"
88 		"popf\n\t"
89 		"and $~(1<<8),%%rax\n\t"
90 		"push %%rax\n\t"
91 		"popf\n\t"
92 		: "=g" (start) : : "rax");
93 	report("single step",
94 	       n == 3 &&
95 	       bp_addr[0] == start+1+6 && dr6[0] == 0xffff4ff0 &&
96 	       bp_addr[1] == start+1+6+1 && dr6[1] == 0xffff4ff0 &&
97 	       bp_addr[2] == start+1+6+1+1 && dr6[2] == 0xffff4ff0);
98 
99 	n = 0;
100 	set_dr1((void *)&value);
101 	set_dr7(0x00d0040a);
102 
103 	asm volatile(
104 		"mov $42,%%rax\n\t"
105 		"mov %%rax,%0\n\t"
106 		: "=m" (value) : : "rax");
107 hw_wp:
108 	report("hw watchpoint",
109 	       n == 1 &&
110 	       bp_addr[0] == ((unsigned long)&&hw_wp) && dr6[0] == 0xffff4ff2);
111 
112 	return 0;
113 }
114