1 
2 #include <stdbool.h>
3 #include <stdint.h>
4 
5 #include <sys/kassert.h>
6 #include <sys/kconfig.h>
7 #include <sys/kdebug.h>
8 #include <sys/mp.h>
9 
10 #include <machine/amd64.h>
11 #include <machine/amd64op.h>
12 #include <machine/atomic.h>
13 #include <machine/trap.h>
14 #include <machine/lapic.h>
15 #include <machine/mp.h>
16 
17 TrapFrame *frames[MAX_CPUS];
18 
19 volatile static uint64_t debugLock = 0;
20 volatile static uint64_t debugCmd = 0;
21 volatile static uint64_t debugHalted = 0;
22 
23 void
Debug_HaltCPUs()24 Debug_HaltCPUs()
25 {
26     debugCmd = 0;
27 
28     if (MP_GetCPUs() == 1)
29 	return;
30 
31     LAPIC_BroadcastNMI(T_DEBUGIPI);
32 
33     // Wait for processors to enter
34     while (debugHalted < (MP_GetCPUs() - 1)) {
35 	pause();
36     }
37 }
38 
39 void
Debug_ResumeCPUs()40 Debug_ResumeCPUs()
41 {
42     debugCmd = 1;
43 
44     // Wait for processors to resume
45     while (debugHalted > 0) {
46 	pause();
47     }
48 }
49 
50 void
Debug_HaltIPI(TrapFrame * tf)51 Debug_HaltIPI(TrapFrame *tf)
52 {
53     MP_SetState(CPUSTATE_HALTED);
54     __sync_fetch_and_add(&debugHalted, 1);
55 
56     frames[CPU()] = tf;
57 
58     while (debugCmd == 0) {
59 	pause();
60     }
61 
62     __sync_fetch_and_sub(&debugHalted, 1);
63     MP_SetState(CPUSTATE_BOOTED);
64 }
65 
66 void
Debug_Breakpoint(TrapFrame * tf)67 Debug_Breakpoint(TrapFrame *tf)
68 {
69     frames[CPU()] = tf;
70 
71     // Should probably force all cores into the debugger
72     while(atomic_swap_uint64(&debugLock, 1) == 1) {
73 	// Wait to acquire debugger lock
74     }
75 
76     // Stop all processors
77     Debug_HaltCPUs();
78 
79     // Enter prompt
80     Debug_Prompt();
81 
82     // Resume all processors
83     Debug_ResumeCPUs();
84     atomic_set_uint64(&debugLock, 0);
85 }
86 
87 static void
Debug_Registers(int argc,const char * argv[])88 Debug_Registers(int argc, const char *argv[])
89 {
90     TrapFrame *tf = frames[CPU()];
91 
92     if (argc == 2) {
93 	int cpuNo = Debug_StrToInt(argv[1]);
94 	if (cpuNo >= MAX_CPUS) {
95 	    kprintf("Invalid CPU number\n");
96 	    return;
97 	}
98 	tf = frames[cpuNo];
99     }
100 
101     kprintf("Interrupt %d Error Code: %016llx\n",
102             tf->vector, tf->errcode);
103     kprintf("cr0: %016llx cr2: %016llx\n",
104             read_cr0(), read_cr2());
105     kprintf("cr3: %016llx cr4: %016llx\n",
106             read_cr3(), read_cr4());
107     kprintf("dr0: %016llx dr1: %016llx dr2: %016llx\n",
108             read_dr0(), read_dr1(), read_dr2());
109     kprintf("dr3: %016llx dr6: %016llx dr7: %016llx\n",
110             read_dr3(), read_dr6(), read_dr7());
111     kprintf("rip: %04x:%016llx rsp: %04x:%016llx\n",
112             tf->cs, tf->rip, tf->ss, tf->rsp);
113     kprintf("rflags: %016llx ds: %04x es: %04x fs: %04x gs: %04x\n",
114             tf->rflags, read_ds(), read_es(), read_fs(), read_gs());
115     kprintf("rax: %016llx rbx: %016llx rcx: %016llx\n",
116             tf->rax, tf->rbx, tf->rcx);
117     kprintf("rdx: %016llx rsi: %016llx rdi: %016llx\n",
118             tf->rdx, tf->rsi, tf->rdi);
119     kprintf("rbp: %016llx r8:  %016llx r9:  %016llx\n",
120             tf->rbp, tf->r8, tf->r9);
121     kprintf("r10: %016llx r11: %016llx r12: %016llx\n",
122             tf->r10, tf->r11, tf->r12);
123     kprintf("r13: %016llx r14: %016llx r15: %016llx\n",
124             tf->r13, tf->r14, tf->r15);
125 }
126 
127 REGISTER_DBGCMD(registers, "Show CPU registers", Debug_Registers);
128 
129 static void
Debug_Backtrace(int argc,const char * argv[])130 Debug_Backtrace(int argc, const char *argv[])
131 {
132     TrapFrame *tf = frames[CPU()];
133     uint64_t *ptr;
134     uint64_t rip;
135     uint64_t rbp;
136 
137     if (argc == 2) {
138 	int cpuNo = Debug_StrToInt(argv[1]);
139 	if (cpuNo >= MAX_CPUS) {
140 	    kprintf("Invalid CPU number\n");
141 	    return;
142 	}
143 	tf = frames[cpuNo];
144     }
145 
146     rip = tf->rip;
147     rbp = tf->rbp;
148 
149     kprintf("%-16s %-16s\n", "IP Pointer", "Base Pointer");
150     while (3) {
151 	kprintf("%016llx %016llx\n", rip, rbp);
152 	ptr = (uint64_t *)rbp;
153 	if (rbp == 0ULL || rip == 0ULL) {
154 	    break;
155 	}
156 	rbp = ptr[0];
157 	rip = ptr[1];
158     }
159 }
160 
161 REGISTER_DBGCMD(backtrace, "Print backtrace", Debug_Backtrace);
162 
163 static void
Debug_SetBreakpoint(int argc,const char * argv[])164 Debug_SetBreakpoint(int argc, const char *argv[])
165 {
166     if (argc != 2) {
167 	kprintf("bkpt [ADDR]");
168 	return;
169     }
170 
171     uint64_t addr = Debug_StrToInt(argv[1]);
172 
173     uint32_t flags = read_dr7();
174 
175     if (!(flags & DR7_DR0G)) {
176 	write_dr0(addr);
177 	write_dr7(flags | DR7_DR0G);
178     } else if (!(flags & DR7_DR1G)) {
179 	write_dr1(addr);
180 	write_dr7(flags | DR7_DR1G);
181     } else if (!(flags & DR7_DR2G)) {
182 	write_dr2(addr);
183 	write_dr7(flags | DR7_DR2G);
184     } else if (!(flags & DR7_DR3G)) {
185 	write_dr3(addr);
186 	write_dr7(flags | DR7_DR3G);
187     } else {
188 	kprintf("No more breakpoints left!\n");
189     }
190 }
191 
192 REGISTER_DBGCMD(bkpt, "Set breakpoint", Debug_SetBreakpoint);
193 
194 static void
Debug_ClearBreakpoint(int argc,const char * argv[])195 Debug_ClearBreakpoint(int argc, const char *argv[])
196 {
197     if (argc != 2) {
198 	kprintf("clrbkpt [0-3]");
199 	return;
200     }
201 
202     uint32_t flags = read_dr7();
203     switch (argv[1][0]) {
204 	case '0':
205 	    flags &= ~DR7_DR0G;
206 	    break;
207 	case '1':
208 	    flags &= ~DR7_DR1G;
209 	    break;
210 	case '2':
211 	    flags &= ~DR7_DR2G;
212 	    break;
213 	case '3':
214 	    flags &= ~DR7_DR3G;
215 	    break;
216 	default:
217 	    kprintf("Specify a breakpoint between 0-3\n");
218     }
219 
220     write_dr7(flags);
221 }
222 
223 REGISTER_DBGCMD(clrbkpt, "Clear breakpoint", Debug_ClearBreakpoint);
224 
225 static void
Debug_ListBreakpoints(int argc,const char * argv[])226 Debug_ListBreakpoints(int argc, const char *argv[])
227 {
228     uint32_t flags = read_dr7();
229 
230     if (flags & DR7_DR0G) {
231 	kprintf("DR0: 0x%lx\n", read_dr0());
232     }
233     if (flags & DR7_DR1G) {
234 	kprintf("DR1: 0x%lx\n", read_dr1());
235     }
236     if (flags & DR7_DR2G) {
237 	kprintf("DR2: 0x%lx\n", read_dr2());
238     }
239     if (flags & DR7_DR3G) {
240 	kprintf("DR3: 0x%lx\n", read_dr3());
241     }
242 }
243 
244 REGISTER_DBGCMD(bkpts, "List breakpoint", Debug_ListBreakpoints);
245 
246 static void
Debug_Reboot(int argc,const char * argv[])247 Debug_Reboot(int argc, const char *argv[])
248 {
249     /*
250      * Triple fault the core by loading a non-canonical address into CR3.  We
251      * should use ACPI, or even the keyboard controller if it exists.
252      */
253     write_cr3(0x8000000000000000ULL);
254 }
255 
256 REGISTER_DBGCMD(reboot, "Reboot computer", Debug_Reboot);
257 
258