Annotation of sys/arch/amd64/amd64/db_interface.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: db_interface.c,v 1.11 2007/01/15 23:19:05 jsg 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/proc.h>
38: #include <sys/reboot.h>
39: #include <sys/systm.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/i82489reg.h>
50: #include <machine/atomic.h>
51:
52: #include <ddb/db_sym.h>
53: #include <ddb/db_command.h>
54: #include <ddb/db_extern.h>
55: #include <ddb/db_access.h>
56: #include <ddb/db_output.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: extern label_t *db_recover;
65: extern char *trap_type[];
66: extern int trap_types;
67: extern boolean_t db_cmd_loop_done;
68:
69: #ifdef MULTIPROCESSOR
70: struct mutex ddb_mp_mutex = MUTEX_INITIALIZER(IPL_HIGH);
71: volatile int ddb_state = DDB_STATE_NOT_RUNNING;
72: volatile cpuid_t ddb_active_cpu;
73: boolean_t db_switch_cpu;
74: long db_switch_to_cpu;
75: #endif
76:
77: int db_active;
78: db_regs_t ddb_regs;
79:
80: void kdbprinttrap(int, int);
81: #ifdef MULTIPROCESSOR
82: void db_cpuinfo_cmd(db_expr_t, int, db_expr_t, char *);
83: void db_startproc_cmd(db_expr_t, int, db_expr_t, char *);
84: void db_stopproc_cmd(db_expr_t, int, db_expr_t, char *);
85: void db_ddbproc_cmd(db_expr_t, int, db_expr_t, char *);
86: int db_cpuid2apic(int);
87: #endif
88:
89: /*
90: * Print trap reason.
91: */
92: void
93: kdbprinttrap(int type, int code)
94: {
95: db_printf("kernel: ");
96: if (type >= trap_types || type < 0)
97: db_printf("type %d", type);
98: else
99: db_printf("%s", trap_type[type]);
100: db_printf(" trap, code=%x\n", code);
101: }
102:
103: /*
104: * kdb_trap - field a TRACE or BPT trap
105: */
106: int
107: kdb_trap(int type, int code, db_regs_t *regs)
108: {
109: int s;
110:
111: switch (type) {
112: case T_BPTFLT: /* breakpoint */
113: case T_TRCTRAP: /* single_step */
114: case T_NMI: /* NMI */
115: case -1: /* keyboard interrupt */
116: break;
117: default:
118: if (!db_panic)
119: return (0);
120:
121: kdbprinttrap(type, code);
122: if (db_recover != 0) {
123: db_error("Faulted in DDB; continuing...\n");
124: /*NOTREACHED*/
125: }
126: }
127:
128: #ifdef MULTIPROCESSOR
129: mtx_enter(&ddb_mp_mutex);
130: if (ddb_state == DDB_STATE_EXITING)
131: ddb_state = DDB_STATE_NOT_RUNNING;
132: mtx_leave(&ddb_mp_mutex);
133: while (db_enter_ddb()) {
134: #endif
135:
136: ddb_regs = *regs;
137:
138: ddb_regs.tf_cs &= 0xffff;
139: ddb_regs.tf_ds &= 0xffff;
140: ddb_regs.tf_es &= 0xffff;
141: ddb_regs.tf_fs &= 0xffff;
142: ddb_regs.tf_gs &= 0xffff;
143: ddb_regs.tf_ss &= 0xffff;
144:
145: s = splhigh();
146: db_active++;
147: cnpollc(TRUE);
148: db_trap(type, code);
149: cnpollc(FALSE);
150: db_active--;
151: splx(s);
152:
153: *regs = ddb_regs;
154:
155: #ifdef MULTIPROCESSOR
156: if (!db_switch_cpu)
157: ddb_state = DDB_STATE_EXITING;
158: }
159: #endif
160: return (1);
161: }
162:
163:
164: #ifdef MULTIPROCESSOR
165: int
166: db_cpuid2apic(int id)
167: {
168: int apic;
169:
170: for (apic = 0; apic < X86_MAXPROCS; apic++) {
171: if (cpu_info[apic] != NULL &&
172: CPU_INFO_UNIT(cpu_info[apic]) == id)
173: return (apic);
174: }
175: return (-1);
176: }
177:
178: void
179: db_cpuinfo_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
180: {
181: int i;
182:
183: for (i = 0; i < X86_MAXPROCS; i++) {
184: if (cpu_info[i] != NULL) {
185: db_printf("%c%4d: ", (i == cpu_number()) ? '*' : ' ',
186: CPU_INFO_UNIT(cpu_info[i]));
187: switch(cpu_info[i]->ci_ddb_paused) {
188: case CI_DDB_RUNNING:
189: db_printf("running\n");
190: break;
191: case CI_DDB_SHOULDSTOP:
192: db_printf("stopping\n");
193: break;
194: case CI_DDB_STOPPED:
195: db_printf("stopped\n");
196: break;
197: case CI_DDB_ENTERDDB:
198: db_printf("entering ddb\n");
199: break;
200: case CI_DDB_INDDB:
201: db_printf("ddb\n");
202: break;
203: default:
204: db_printf("? (%d)\n",
205: cpu_info[i]->ci_ddb_paused);
206: break;
207: }
208: }
209: }
210: }
211:
212: void
213: db_startproc_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
214: {
215: int apic;
216:
217: if (have_addr) {
218: apic = db_cpuid2apic(addr);
219: if (apic >= 0 && apic < X86_MAXPROCS &&
220: cpu_info[apic] != NULL && apic != cpu_number())
221: db_startcpu(apic);
222: else
223: db_printf("Invalid cpu %d\n", (int)addr);
224: } else {
225: for (apic = 0; apic < X86_MAXPROCS; apic++) {
226: if (cpu_info[apic] != NULL && apic != cpu_number()) {
227: db_startcpu(apic);
228: }
229: }
230: }
231: }
232:
233: void
234: db_stopproc_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
235: {
236: int apic;
237:
238: if (have_addr) {
239: apic = db_cpuid2apic(addr);
240: if (apic >= 0 && apic < X86_MAXPROCS &&
241: cpu_info[apic] != NULL && apic != cpu_number())
242: db_stopcpu(apic);
243: else
244: db_printf("Invalid cpu %d\n", (int)addr);
245: } else {
246: for (apic = 0; apic < X86_MAXPROCS; apic++) {
247: if (cpu_info[apic] != NULL && apic != cpu_number()) {
248: db_stopcpu(apic);
249: }
250: }
251: }
252: }
253:
254: void
255: db_ddbproc_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
256: {
257: int apic;
258:
259: if (have_addr) {
260: apic = db_cpuid2apic(addr);
261: if (apic >= 0 && apic < X86_MAXPROCS &&
262: cpu_info[apic] != NULL && apic != cpu_number()) {
263: db_stopcpu(apic);
264: db_switch_to_cpu = apic;
265: db_switch_cpu = 1;
266: db_cmd_loop_done = 1;
267: } else {
268: db_printf("Invalid cpu %d\n", (int)addr);
269: }
270: } else {
271: db_printf("CPU not specified\n");
272: }
273: }
274:
275: int
276: db_enter_ddb(void)
277: {
278: int i;
279:
280: mtx_enter(&ddb_mp_mutex);
281:
282: /* If we are first in, grab ddb and stop all other CPUs */
283: if (ddb_state == DDB_STATE_NOT_RUNNING) {
284: ddb_active_cpu = cpu_number();
285: ddb_state = DDB_STATE_RUNNING;
286: curcpu()->ci_ddb_paused = CI_DDB_INDDB;
287: mtx_leave(&ddb_mp_mutex);
288: for (i = 0; i < X86_MAXPROCS; i++) {
289: if (cpu_info[i] != NULL && i != cpu_number() &&
290: cpu_info[i]->ci_ddb_paused != CI_DDB_STOPPED) {
291: cpu_info[i]->ci_ddb_paused = CI_DDB_SHOULDSTOP;
292: x86_send_ipi(cpu_info[i], X86_IPI_DDB);
293: }
294: }
295: return (1);
296: }
297:
298: /* Leaving ddb completely. Start all other CPUs and return 0 */
299: if (ddb_active_cpu == cpu_number() && ddb_state == DDB_STATE_EXITING) {
300: for (i = 0; i < X86_MAXPROCS; i++) {
301: if (cpu_info[i] != NULL) {
302: cpu_info[i]->ci_ddb_paused = CI_DDB_RUNNING;
303: }
304: }
305: mtx_leave(&ddb_mp_mutex);
306: return (0);
307: }
308:
309: /* We're switching to another CPU. db_ddbproc_cmd() has made sure
310: * it is waiting for ddb, we just have to set ddb_active_cpu. */
311: if (ddb_active_cpu == cpu_number() && db_switch_cpu) {
312: curcpu()->ci_ddb_paused = CI_DDB_SHOULDSTOP;
313: db_switch_cpu = 0;
314: ddb_active_cpu = db_switch_to_cpu;
315: cpu_info[db_switch_to_cpu]->ci_ddb_paused = CI_DDB_ENTERDDB;
316: }
317:
318: /* Wait until we should enter ddb or resume */
319: while (ddb_active_cpu != cpu_number() &&
320: curcpu()->ci_ddb_paused != CI_DDB_RUNNING) {
321: if (curcpu()->ci_ddb_paused == CI_DDB_SHOULDSTOP)
322: curcpu()->ci_ddb_paused = CI_DDB_STOPPED;
323: mtx_leave(&ddb_mp_mutex);
324:
325: /* Busy wait without locking, we'll confirm with lock later */
326: while (ddb_active_cpu != cpu_number() &&
327: curcpu()->ci_ddb_paused != CI_DDB_RUNNING)
328: ; /* Do nothing */
329:
330: mtx_enter(&ddb_mp_mutex);
331: }
332:
333: /* Either enter ddb or exit */
334: if (ddb_active_cpu == cpu_number() && ddb_state == DDB_STATE_RUNNING) {
335: curcpu()->ci_ddb_paused = CI_DDB_INDDB;
336: mtx_leave(&ddb_mp_mutex);
337: return (1);
338: } else {
339: mtx_leave(&ddb_mp_mutex);
340: return (0);
341: }
342: }
343:
344: void
345: db_startcpu(int cpu)
346: {
347: if (cpu != cpu_number() && cpu_info[cpu] != NULL) {
348: mtx_enter(&ddb_mp_mutex);
349: cpu_info[cpu]->ci_ddb_paused = CI_DDB_RUNNING;
350: mtx_leave(&ddb_mp_mutex);
351: }
352: }
353:
354: void
355: db_stopcpu(int cpu)
356: {
357: mtx_enter(&ddb_mp_mutex);
358: if (cpu != cpu_number() && cpu_info[cpu] != NULL &&
359: cpu_info[cpu]->ci_ddb_paused != CI_DDB_STOPPED) {
360: cpu_info[cpu]->ci_ddb_paused = CI_DDB_SHOULDSTOP;
361: mtx_leave(&ddb_mp_mutex);
362: x86_send_ipi(cpu_info[cpu], X86_IPI_DDB);
363: } else {
364: mtx_leave(&ddb_mp_mutex);
365: }
366: }
367:
368: void
369: x86_ipi_db(struct cpu_info *ci)
370: {
371: Debugger();
372: }
373: #endif /* MULTIPROCESSOR */
374:
375: #if NACPI > 0
376: struct db_command db_acpi_cmds[] = {
377: { "disasm", db_acpi_disasm, CS_OWN, NULL },
378: { "showval", db_acpi_showval, CS_OWN, NULL },
379: { "tree", db_acpi_tree, 0, NULL },
380: { "trace", db_acpi_trace, 0, NULL },
381: { NULL, NULL, 0, NULL }
382: };
383: #endif /* NACPI > 0 */
384:
385: struct db_command db_machine_command_table[] = {
386: #ifdef MULTIPROCESSOR
387: { "cpuinfo", db_cpuinfo_cmd, 0, 0 },
388: { "startcpu", db_startproc_cmd, 0, 0 },
389: { "stopcpu", db_stopproc_cmd, 0, 0 },
390: { "ddbcpu", db_ddbproc_cmd, 0, 0 },
391: #endif
392: #if NACPI > 0
393: { "acpi", NULL, 0, db_acpi_cmds },
394: #endif /* NACPI > 0 */
395: { (char *)0, },
396: };
397:
398: void
399: db_machine_init(void)
400: {
401: #ifdef MULTIPROCESSOR
402: int i;
403: #endif
404:
405: db_machine_commands_install(db_machine_command_table);
406: #ifdef MULTIPROCESSOR
407: for (i = 0; i < X86_MAXPROCS; i++) {
408: if (cpu_info[i] != NULL)
409: cpu_info[i]->ci_ddb_paused = CI_DDB_RUNNING;
410: }
411: #endif
412: }
413:
414: void
415: Debugger(void)
416: {
417: breakpoint();
418: }
CVSweb