xref: /openbsd-src/sys/arch/amd64/amd64/db_interface.c (revision 3fe80b7fb1a5bd0bd4a7a666724b5696fc175a21)
1 /*	$OpenBSD: db_interface.c,v 1.39 2022/04/14 19:47:10 naddy Exp $	*/
2 /*	$NetBSD: db_interface.c,v 1.1 2003/04/26 18:39:27 fvdl Exp $	*/
3 
4 /*
5  * Mach Operating System
6  * Copyright (c) 1991,1990 Carnegie Mellon University
7  * All Rights Reserved.
8  *
9  * Permission to use, copy, modify and distribute this software and its
10  * documentation is hereby granted, provided that both the copyright
11  * notice and this permission notice appear in all copies of the
12  * software, derivative works or modified versions, and any portions
13  * thereof, and that both notices appear in supporting documentation.
14  *
15  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
16  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
17  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
18  *
19  * Carnegie Mellon requests users of this software to return to
20  *
21  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
22  *  School of Computer Science
23  *  Carnegie Mellon University
24  *  Pittsburgh PA 15213-3890
25  *
26  * any improvements or extensions that they make and grant Carnegie the
27  * rights to redistribute these changes.
28  *
29  *	db_interface.c,v 2.4 1991/02/05 17:11:13 mrt (CMU)
30  */
31 
32 /*
33  * Interface to new debugger.
34  */
35 
36 #include <sys/param.h>
37 #include <sys/reboot.h>
38 #include <sys/systm.h>
39 #include <sys/mutex.h>
40 
41 #include <uvm/uvm_extern.h>
42 
43 #include <dev/cons.h>
44 
45 #include <machine/cpufunc.h>
46 #include <machine/db_machdep.h>
47 #include <machine/cpuvar.h>
48 #include <machine/i82093var.h>
49 #include <machine/atomic.h>
50 #include <machine/specialreg.h>
51 
52 #include <ddb/db_sym.h>
53 #include <ddb/db_command.h>
54 #include <ddb/db_extern.h>
55 #include <ddb/db_output.h>
56 #include <ddb/db_run.h>
57 #include <ddb/db_var.h>
58 
59 #include "acpi.h"
60 #if NACPI > 0
61 #include <dev/acpi/acpidebug.h>
62 #endif /* NACPI > 0 */
63 
64 #include "wsdisplay.h"
65 #if NWSDISPLAY > 0
66 #include <dev/wscons/wsdisplayvar.h>
67 #endif
68 
69 extern label_t *db_recover;
70 extern const char * const trap_type[];
71 extern const int trap_types;
72 
73 #ifdef MULTIPROCESSOR
74 struct db_mutex ddb_mp_mutex = DB_MUTEX_INITIALIZER;
75 volatile int ddb_state = DDB_STATE_NOT_RUNNING;
76 volatile cpuid_t ddb_active_cpu;
77 int		 db_switch_cpu;
78 long		 db_switch_to_cpu;
79 #endif
80 
81 db_regs_t ddb_regs;
82 
83 void db_printtrap(int, int);
84 #ifdef MULTIPROCESSOR
85 void db_cpuinfo_cmd(db_expr_t, int, db_expr_t, char *);
86 void db_startproc_cmd(db_expr_t, int, db_expr_t, char *);
87 void db_stopproc_cmd(db_expr_t, int, db_expr_t, char *);
88 void db_ddbproc_cmd(db_expr_t, int, db_expr_t, char *);
89 #endif
90 
91 /*
92  * Print trap reason.
93  */
94 void
db_printtrap(int type,int code)95 db_printtrap(int type, int code)
96 {
97 	db_printf("kernel: ");
98 	if (type >= trap_types || type < 0)
99 		db_printf("type %d", type);
100 	else
101 		db_printf("%s", trap_type[type]);
102 	db_printf(" trap, code=%x\n", code);
103 }
104 
105 /*
106  *  db_ktrap - field a TRACE or BPT trap
107  */
108 int
db_ktrap(int type,int code,db_regs_t * regs)109 db_ktrap(int type, int code, db_regs_t *regs)
110 {
111 	int s;
112 
113 #if NWSDISPLAY > 0
114 	wsdisplay_enter_ddb();
115 #endif
116 
117 	switch (type) {
118 	case T_BPTFLT:	/* breakpoint */
119 	case T_TRCTRAP:	/* single_step */
120 	case T_NMI:	/* NMI */
121 	case -1:	/* keyboard interrupt */
122 		break;
123 	default:
124 		if (!db_panic)
125 			return (0);
126 
127 		db_printtrap(type, code);
128 		if (db_recover != 0) {
129 			db_error("Faulted in DDB; continuing...\n");
130 			/*NOTREACHED*/
131 		}
132 	}
133 
134 #ifdef MULTIPROCESSOR
135 	db_mtx_enter(&ddb_mp_mutex);
136 	if (ddb_state == DDB_STATE_EXITING)
137 		ddb_state = DDB_STATE_NOT_RUNNING;
138 	db_mtx_leave(&ddb_mp_mutex);
139 	while (db_enter_ddb()) {
140 #endif
141 
142 	ddb_regs = *regs;
143 
144 	ddb_regs.tf_cs &= 0xffff;
145 	ddb_regs.tf_ss &= 0xffff;
146 
147 	s = splhigh();
148 	db_active++;
149 	cnpollc(1);
150 	db_trap(type, code);
151 	cnpollc(0);
152 	db_active--;
153 	splx(s);
154 
155 	*regs = ddb_regs;
156 
157 #ifdef MULTIPROCESSOR
158 		if (!db_switch_cpu)
159 			ddb_state = DDB_STATE_EXITING;
160 	}
161 #endif
162 	return (1);
163 }
164 
165 void
db_sysregs_cmd(db_expr_t addr,int have_addr,db_expr_t count,char * modif)166 db_sysregs_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
167 {
168 	int64_t idtr, gdtr;
169 	uint64_t cr;
170 	uint16_t ldtr, tr;
171 	uint64_t gsb;
172 
173 	__asm__ volatile("sidt %0" : "=m" (idtr));
174 	db_printf("idtr:   0x%08llx/%04llx\n", idtr >> 16, idtr & 0xffff);
175 
176 	__asm__ volatile("sgdt %0" : "=m" (gdtr));
177 	db_printf("gdtr:   0x%08llx/%04llx\n", gdtr >> 16, gdtr & 0xffff);
178 
179 	__asm__ volatile("sldt %0" : "=g" (ldtr));
180 	db_printf("ldtr:   0x%04x\n", ldtr);
181 
182 	__asm__ volatile("str %0" : "=g" (tr));
183 	db_printf("tr:     0x%04x\n", tr);
184 
185 	__asm__ volatile("movq %%cr0,%0" : "=r" (cr));
186 	db_printf("cr0:    0x%016llx\n", cr);
187 
188 	__asm__ volatile("movq %%cr2,%0" : "=r" (cr));
189 	db_printf("cr2:    0x%016llx\n", cr);
190 
191 	__asm__ volatile("movq %%cr3,%0" : "=r" (cr));
192 	db_printf("cr3:    0x%016llx\n", cr);
193 
194 	__asm__ volatile("movq %%cr4,%0" : "=r" (cr));
195 	db_printf("cr4:    0x%016llx\n", cr);
196 
197 	gsb = rdmsr(MSR_GSBASE);
198 	db_printf("gsb:    0x%016llx\n", gsb);
199 
200 	gsb = rdmsr(MSR_KERNELGSBASE);
201 	db_printf("kgsb:   0x%016llx\n", gsb);
202 }
203 
204 
205 #ifdef MULTIPROCESSOR
206 void
db_cpuinfo_cmd(db_expr_t addr,int have_addr,db_expr_t count,char * modif)207 db_cpuinfo_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
208 {
209 	int i;
210 
211 	for (i = 0; i < MAXCPUS; i++) {
212 		if (cpu_info[i] != NULL) {
213 			db_printf("%c%4d: ", (i == cpu_number()) ? '*' : ' ',
214 			    CPU_INFO_UNIT(cpu_info[i]));
215 			switch(cpu_info[i]->ci_ddb_paused) {
216 			case CI_DDB_RUNNING:
217 				db_printf("running\n");
218 				break;
219 			case CI_DDB_SHOULDSTOP:
220 				db_printf("stopping\n");
221 				break;
222 			case CI_DDB_STOPPED:
223 				db_printf("stopped\n");
224 				break;
225 			case CI_DDB_ENTERDDB:
226 				db_printf("entering ddb\n");
227 				break;
228 			case CI_DDB_INDDB:
229 				db_printf("ddb\n");
230 				break;
231 			default:
232 				db_printf("? (%d)\n",
233 				    cpu_info[i]->ci_ddb_paused);
234 				break;
235 			}
236 		}
237 	}
238 }
239 
240 void
db_startproc_cmd(db_expr_t addr,int have_addr,db_expr_t count,char * modif)241 db_startproc_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
242 {
243 	int i;
244 
245 	if (have_addr) {
246 		if (addr >= 0 && addr < MAXCPUS &&
247 		    cpu_info[addr] != NULL && addr != cpu_number())
248 			db_startcpu(addr);
249 		else
250 			db_printf("Invalid cpu %d\n", (int)addr);
251 	} else {
252 		for (i = 0; i < MAXCPUS; i++) {
253 			if (cpu_info[i] != NULL && i != cpu_number())
254 				db_startcpu(i);
255 		}
256 	}
257 }
258 
259 void
db_stopproc_cmd(db_expr_t addr,int have_addr,db_expr_t count,char * modif)260 db_stopproc_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
261 {
262 	int i;
263 
264 	if (have_addr) {
265 		if (addr >= 0 && addr < MAXCPUS &&
266 		    cpu_info[addr] != NULL && addr != cpu_number())
267 			db_stopcpu(addr);
268 		else
269 			db_printf("Invalid cpu %d\n", (int)addr);
270 	} else {
271 		for (i = 0; i < MAXCPUS; i++) {
272 			if (cpu_info[i] != NULL && i != cpu_number())
273 				db_stopcpu(i);
274 		}
275 	}
276 }
277 
278 void
db_ddbproc_cmd(db_expr_t addr,int have_addr,db_expr_t count,char * modif)279 db_ddbproc_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
280 {
281 	if (have_addr) {
282 		if (addr >= 0 && addr < MAXCPUS &&
283 		    cpu_info[addr] != NULL && addr != cpu_number()) {
284 			db_stopcpu(addr);
285 			db_switch_to_cpu = addr;
286 			db_switch_cpu = 1;
287 			db_cmd_loop_done = 1;
288 		} else {
289 			db_printf("Invalid cpu %d\n", (int)addr);
290 		}
291 	} else {
292 		db_printf("CPU not specified\n");
293 	}
294 }
295 
296 int
db_enter_ddb(void)297 db_enter_ddb(void)
298 {
299 	int i;
300 
301 	db_mtx_enter(&ddb_mp_mutex);
302 
303 	/* If we are first in, grab ddb and stop all other CPUs */
304 	if (ddb_state == DDB_STATE_NOT_RUNNING) {
305 		ddb_active_cpu = cpu_number();
306 		ddb_state = DDB_STATE_RUNNING;
307 		curcpu()->ci_ddb_paused = CI_DDB_INDDB;
308 		db_mtx_leave(&ddb_mp_mutex);
309 		for (i = 0; i < MAXCPUS; i++) {
310 			if (cpu_info[i] != NULL && i != cpu_number() &&
311 			    cpu_info[i]->ci_ddb_paused != CI_DDB_STOPPED) {
312 				cpu_info[i]->ci_ddb_paused = CI_DDB_SHOULDSTOP;
313 				x86_send_ipi(cpu_info[i], X86_IPI_DDB);
314 			}
315 		}
316 		return (1);
317 	}
318 
319 	/* Leaving ddb completely.  Start all other CPUs and return 0 */
320 	if (ddb_active_cpu == cpu_number() && ddb_state == DDB_STATE_EXITING) {
321 		for (i = 0; i < MAXCPUS; i++) {
322 			if (cpu_info[i] != NULL) {
323 				cpu_info[i]->ci_ddb_paused = CI_DDB_RUNNING;
324 			}
325 		}
326 		db_mtx_leave(&ddb_mp_mutex);
327 		return (0);
328 	}
329 
330 	/* We're switching to another CPU.  db_ddbproc_cmd() has made sure
331 	 * it is waiting for ddb, we just have to set ddb_active_cpu. */
332 	if (ddb_active_cpu == cpu_number() && db_switch_cpu) {
333 		curcpu()->ci_ddb_paused = CI_DDB_SHOULDSTOP;
334 		db_switch_cpu = 0;
335 		ddb_active_cpu = db_switch_to_cpu;
336 		cpu_info[db_switch_to_cpu]->ci_ddb_paused = CI_DDB_ENTERDDB;
337 	}
338 
339 	/* Wait until we should enter ddb or resume */
340 	while (ddb_active_cpu != cpu_number() &&
341 	    curcpu()->ci_ddb_paused != CI_DDB_RUNNING) {
342 		if (curcpu()->ci_ddb_paused == CI_DDB_SHOULDSTOP)
343 			curcpu()->ci_ddb_paused = CI_DDB_STOPPED;
344 		db_mtx_leave(&ddb_mp_mutex);
345 
346 		/* Busy wait without locking, we'll confirm with lock later */
347 		while (ddb_active_cpu != cpu_number() &&
348 		    curcpu()->ci_ddb_paused != CI_DDB_RUNNING)
349 			CPU_BUSY_CYCLE();
350 
351 		db_mtx_enter(&ddb_mp_mutex);
352 	}
353 
354 	/* Either enter ddb or exit */
355 	if (ddb_active_cpu == cpu_number() && ddb_state == DDB_STATE_RUNNING) {
356 		curcpu()->ci_ddb_paused = CI_DDB_INDDB;
357 		db_mtx_leave(&ddb_mp_mutex);
358 		return (1);
359 	} else {
360 		db_mtx_leave(&ddb_mp_mutex);
361 		return (0);
362 	}
363 }
364 
365 void
db_startcpu(int cpu)366 db_startcpu(int cpu)
367 {
368 	if (cpu != cpu_number() && cpu_info[cpu] != NULL) {
369 		db_mtx_enter(&ddb_mp_mutex);
370 		cpu_info[cpu]->ci_ddb_paused = CI_DDB_RUNNING;
371 		db_mtx_leave(&ddb_mp_mutex);
372 	}
373 }
374 
375 void
db_stopcpu(int cpu)376 db_stopcpu(int cpu)
377 {
378 	db_mtx_enter(&ddb_mp_mutex);
379 	if (cpu != cpu_number() && cpu_info[cpu] != NULL &&
380 	    cpu_info[cpu]->ci_ddb_paused != CI_DDB_STOPPED) {
381 		cpu_info[cpu]->ci_ddb_paused = CI_DDB_SHOULDSTOP;
382 		db_mtx_leave(&ddb_mp_mutex);
383 		x86_send_ipi(cpu_info[cpu], X86_IPI_DDB);
384 	} else {
385 		db_mtx_leave(&ddb_mp_mutex);
386 	}
387 }
388 
389 void
x86_ipi_db(struct cpu_info * ci)390 x86_ipi_db(struct cpu_info *ci)
391 {
392 	db_enter();
393 }
394 #endif /* MULTIPROCESSOR */
395 
396 #if NACPI > 0
397 const struct db_command db_acpi_cmds[] = {
398 	{ "disasm",	db_acpi_disasm,		CS_OWN,	NULL },
399 	{ "showval",	db_acpi_showval,	CS_OWN,	NULL },
400 	{ "tree",	db_acpi_tree,		0,	NULL },
401 	{ "trace",	db_acpi_trace,		0,	NULL },
402 	{ NULL,		NULL,			0,	NULL }
403 };
404 #endif /* NACPI > 0 */
405 
406 const struct db_command db_machine_command_table[] = {
407 #ifdef MULTIPROCESSOR
408 	{ "cpuinfo",	db_cpuinfo_cmd,		0,	0 },
409 	{ "startcpu",	db_startproc_cmd,	0,	0 },
410 	{ "stopcpu",	db_stopproc_cmd,	0,	0 },
411 	{ "ddbcpu",	db_ddbproc_cmd,		0,	0 },
412 	{ "sysregs",	db_sysregs_cmd,		0,	0 },
413 #endif
414 #if NACPI > 0
415 	{ "acpi",	NULL,			0,	db_acpi_cmds },
416 #endif /* NACPI > 0 */
417 	{ NULL, },
418 };
419 
420 void
db_machine_init(void)421 db_machine_init(void)
422 {
423 #ifdef MULTIPROCESSOR
424 	int i;
425 
426 	for (i = 0; i < MAXCPUS; i++) {
427 		if (cpu_info[i] != NULL)
428 			cpu_info[i]->ci_ddb_paused = CI_DDB_RUNNING;
429 	}
430 #endif
431 }
432 
433 void
db_enter(void)434 db_enter(void)
435 {
436 	breakpoint();
437 }
438