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