xref: /netbsd/sys/arch/i386/i386/db_interface.c (revision c4a72b64)
1 /*	$NetBSD: db_interface.c,v 1.38 2002/11/02 01:56:14 perry Exp $	*/
2 
3 /*
4  * Mach Operating System
5  * Copyright (c) 1991,1990 Carnegie Mellon University
6  * All Rights Reserved.
7  *
8  * Permission to use, copy, modify and distribute this software and its
9  * documentation is hereby granted, provided that both the copyright
10  * notice and this permission notice appear in all copies of the
11  * software, derivative works or modified versions, and any portions
12  * thereof, and that both notices appear in supporting documentation.
13  *
14  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
15  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
16  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
17  *
18  * Carnegie Mellon requests users of this software to return to
19  *
20  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
21  *  School of Computer Science
22  *  Carnegie Mellon University
23  *  Pittsburgh PA 15213-3890
24  *
25  * any improvements or extensions that they make and grant Carnegie the
26  * rights to redistribute these changes.
27  *
28  *	db_interface.c,v 2.4 1991/02/05 17:11:13 mrt (CMU)
29  */
30 
31 /*
32  * Interface to new debugger.
33  */
34 
35 #include <sys/cdefs.h>
36 __KERNEL_RCSID(0, "$NetBSD: db_interface.c,v 1.38 2002/11/02 01:56:14 perry Exp $");
37 
38 #include "opt_ddb.h"
39 
40 #include <sys/param.h>
41 #include <sys/proc.h>
42 #include <sys/reboot.h>
43 #include <sys/systm.h>
44 
45 #include <uvm/uvm_extern.h>
46 
47 #include <dev/cons.h>
48 
49 #include <machine/cpufunc.h>
50 #include <machine/db_machdep.h>
51 #include <machine/cpuvar.h>
52 #include <machine/i82093var.h>
53 #include <machine/i82489reg.h>
54 #include <machine/i82489var.h>
55 #include <machine/atomic.h>
56 
57 #include <ddb/db_sym.h>
58 #include <ddb/db_command.h>
59 #include <ddb/db_extern.h>
60 #include <ddb/db_access.h>
61 #include <ddb/db_output.h>
62 #include <ddb/ddbvar.h>
63 
64 extern char *trap_type[];
65 extern int trap_types;
66 
67 int	db_active = 0;
68 db_regs_t ddb_regs;	/* register state */
69 
70 void db_mach_cpu (db_expr_t, int, db_expr_t, char *);
71 
72 const struct db_command db_machine_command_table[] = {
73 #ifdef MULTIPROCESSOR
74 	{ "cpu",	db_mach_cpu,	0,	0 },
75 #endif
76 	{ (char *)0, },
77 };
78 
79 void kdbprinttrap __P((int, int));
80 #ifdef MULTIPROCESSOR
81 extern void ddb_ipi(int, struct trapframe);
82 extern void ddb_ipi_tss(struct i386tss *);
83 static void ddb_suspend(struct trapframe *);
84 int ddb_vec;
85 #endif
86 
87 db_regs_t *ddb_regp = 0;
88 
89 #define NOCPU -1
90 
91 int ddb_cpu = NOCPU;
92 
93 typedef void (vector) __P((void));
94 extern vector Xintrddbipi;
95 
96 void
97 db_machine_init()
98 {
99 
100 #ifdef MULTIPROCESSOR
101 	ddb_vec = idt_vec_alloc(0xf0, 0xff);
102 	setgate((struct gate_descriptor *)&idt[ddb_vec], &Xintrddbipi, 0,
103 	    SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
104 #endif
105 }
106 
107 #ifdef MULTIPROCESSOR
108 
109 __cpu_simple_lock_t db_lock;
110 
111 static int
112 db_suspend_others(void)
113 {
114 	int cpu_me = cpu_number();
115 	int win;
116 
117 	if (ddb_vec == 0)
118 		return 1;
119 
120 	__cpu_simple_lock(&db_lock);
121 	if (ddb_cpu == NOCPU)
122 		ddb_cpu = cpu_me;
123 	win = (ddb_cpu == cpu_me);
124 	__cpu_simple_unlock(&db_lock);
125 	if (win) {
126 		i386_ipi (ddb_vec, LAPIC_DEST_ALLEXCL, LAPIC_DLMODE_FIXED);
127 	}
128 	return win;
129 }
130 
131 static void
132 db_resume_others(void)
133 {
134 	int i;
135 
136 	__cpu_simple_lock(&db_lock);
137 	ddb_cpu = NOCPU;
138 	__cpu_simple_unlock(&db_lock);
139 
140 	for (i=0; i<I386_MAXPROCS; i++) {
141 		struct cpu_info *ci = cpu_info[i];
142 		if (ci == NULL)
143 			continue;
144 		if (ci->ci_flags & CPUF_PAUSE)
145 			i386_atomic_clearbits_l(&ci->ci_flags, CPUF_PAUSE);
146 	}
147 
148 }
149 
150 #endif
151 
152 /*
153  * Print trap reason.
154  */
155 void
156 kdbprinttrap(type, code)
157 	int type, code;
158 {
159 	db_printf("kernel: ");
160 	if (type >= trap_types || type < 0)
161 		db_printf("type %d", type);
162 	else
163 		db_printf("%s", trap_type[type]);
164 	db_printf(" trap, code=%x\n", code);
165 }
166 
167 /*
168  *  kdb_trap - field a TRACE or BPT trap
169  */
170 int
171 kdb_trap(type, code, regs)
172 	int type, code;
173 	db_regs_t *regs;
174 {
175 	int s, flags;
176 	db_regs_t dbreg;
177 
178 	flags = regs->tf_err & TC_FLAGMASK;
179 	regs->tf_err &= ~TC_FLAGMASK;
180 
181 	switch (type) {
182 	case T_BPTFLT:	/* breakpoint */
183 	case T_TRCTRAP:	/* single_step */
184 	case T_NMI:	/* NMI */
185 	case -1:	/* keyboard interrupt */
186 		break;
187 	default:
188 		if (!db_onpanic && db_recover==0)
189 			return (0);
190 
191 		kdbprinttrap(type, code);
192 		if (db_recover != 0) {
193 			db_error("Faulted in DDB; continuing...\n");
194 			/*NOTREACHED*/
195 		}
196 	}
197 
198 #ifdef MULTIPROCESSOR
199 	if (!db_suspend_others()) {
200 		ddb_suspend(regs);
201 	} else {
202 	curcpu()->ci_ddb_regs = &dbreg;
203 	ddb_regp = &dbreg;
204 #endif
205 	/* XXX Should switch to kdb's own stack here. */
206 	ddb_regs = *regs;
207 	if (!(flags & TC_TSS) && KERNELMODE(regs->tf_cs, regs->tf_eflags)) {
208 		/*
209 		 * Kernel mode - esp and ss not saved
210 		 */
211 		ddb_regs.tf_esp = (int)&regs->tf_esp;	/* kernel stack pointer */
212 		__asm("movw %%ss,%w0" : "=r" (ddb_regs.tf_ss));
213 	}
214 
215 	ddb_regs.tf_cs &= 0xffff;
216 	ddb_regs.tf_ds &= 0xffff;
217 	ddb_regs.tf_es &= 0xffff;
218 	ddb_regs.tf_fs &= 0xffff;
219 	ddb_regs.tf_gs &= 0xffff;
220 	ddb_regs.tf_ss &= 0xffff;
221 	s = splhigh();
222 	db_active++;
223 	cnpollc(TRUE);
224 	db_trap(type, code);
225 	cnpollc(FALSE);
226 	db_active--;
227 	splx(s);
228 #ifdef MULTIPROCESSOR
229 	db_resume_others();
230 	}
231 #endif
232 	ddb_regp = &dbreg;
233 
234 	regs->tf_gs     = ddb_regs.tf_gs;
235 	regs->tf_fs     = ddb_regs.tf_fs;
236 	regs->tf_es     = ddb_regs.tf_es;
237 	regs->tf_ds     = ddb_regs.tf_ds;
238 	regs->tf_edi    = ddb_regs.tf_edi;
239 	regs->tf_esi    = ddb_regs.tf_esi;
240 	regs->tf_ebp    = ddb_regs.tf_ebp;
241 	regs->tf_ebx    = ddb_regs.tf_ebx;
242 	regs->tf_edx    = ddb_regs.tf_edx;
243 	regs->tf_ecx    = ddb_regs.tf_ecx;
244 	regs->tf_eax    = ddb_regs.tf_eax;
245 	regs->tf_eip    = ddb_regs.tf_eip;
246 	regs->tf_cs     = ddb_regs.tf_cs;
247 	regs->tf_eflags = ddb_regs.tf_eflags;
248 	if (!(flags & TC_TSS) && !KERNELMODE(regs->tf_cs, regs->tf_eflags)) {
249 		/* ring transit - saved esp and ss valid */
250 		regs->tf_esp    = ddb_regs.tf_esp;
251 		regs->tf_ss     = ddb_regs.tf_ss;
252 	}
253 
254 #ifdef TRAPLOG
255 	wrmsr(MSR_DEBUGCTLMSR, 0x1);
256 #endif
257 
258 	return (1);
259 }
260 
261 void
262 cpu_Debugger()
263 {
264 	breakpoint();
265 }
266 
267 #ifdef MULTIPROCESSOR
268 
269 /*
270  * Called when we receive a debugger IPI (inter-processor interrupt).
271  * As with trap() in trap.c, this function is called from an assembly
272  * language IDT gate entry routine which prepares a suitable stack frame,
273  * and restores this frame after the exception has been processed. Note
274  * that the effect is as if the arguments were passed call by reference.
275  */
276 void
277 ddb_ipi(int cpl, struct trapframe frame)
278 {
279 
280 	ddb_suspend(&frame);
281 }
282 
283 void
284 ddb_ipi_tss(struct i386tss *tss)
285 {
286 	struct trapframe tf;
287 
288 	tf.tf_gs = tss->tss_gs;
289 	tf.tf_fs = tss->tss_fs;
290 	tf.tf_es = tss->__tss_es;
291 	tf.tf_ds = tss->__tss_ds;
292 	tf.tf_edi = tss->__tss_edi;
293 	tf.tf_esi = tss->__tss_esi;
294 	tf.tf_ebp = tss->tss_ebp;
295 	tf.tf_ebx = tss->__tss_ebx;
296 	tf.tf_edx = tss->__tss_edx;
297 	tf.tf_ecx = tss->__tss_ecx;
298 	tf.tf_eax = tss->__tss_eax;
299 	tf.tf_trapno = 0;
300 	tf.tf_err = TC_TSS;
301 	tf.tf_eip = tss->__tss_eip;
302 	tf.tf_cs = tss->__tss_cs;
303 	tf.tf_eflags = tss->__tss_eflags;
304 	tf.tf_esp = tss->tss_esp;
305 	tf.tf_ss = tss->__tss_ss;
306 
307 	ddb_suspend(&tf);
308 }
309 
310 static void
311 ddb_suspend(struct trapframe *frame)
312 {
313 	volatile struct cpu_info *ci = curcpu();
314 	db_regs_t regs;
315 	int flags;
316 
317 	regs = *frame;
318 	flags = regs.tf_err & TC_FLAGMASK;
319 	regs.tf_err &= ~TC_FLAGMASK;
320 	if (!(flags & TC_TSS) && KERNELMODE(regs.tf_cs, regs.tf_eflags)) {
321 		/*
322 		 * Kernel mode - esp and ss not saved
323 		 */
324 		regs.tf_esp = (int)&frame->tf_esp; /* kernel stack pointer */
325 		__asm("movw %%ss,%w0" : "=r" (regs.tf_ss));
326 	}
327 
328 	ci->ci_ddb_regs = &regs;
329 
330 	i386_atomic_setbits_l(&ci->ci_flags, CPUF_PAUSE);
331 
332 	while (ci->ci_flags & CPUF_PAUSE)
333 		;
334 	ci->ci_ddb_regs = 0;
335 }
336 
337 
338 extern void cpu_debug_dump(void); /* XXX */
339 
340 void
341 db_mach_cpu(addr, have_addr, count, modif)
342 	db_expr_t	addr;
343 	int		have_addr;
344 	db_expr_t	count;
345 	char *		modif;
346 {
347 	struct cpu_info *ci;
348 	if (!have_addr) {
349 		cpu_debug_dump();
350 		return;
351 	}
352 
353 	if ((addr < 0) || (addr >= I386_MAXPROCS)) {
354 		db_printf("%ld: cpu out of range\n", addr);
355 		return;
356 	}
357 	ci = cpu_info[addr];
358 	if (ci == NULL) {
359 		db_printf("cpu %ld not configured\n", addr);
360 		return;
361 	}
362 	if (ci != curcpu()) {
363 		if (!(ci->ci_flags & CPUF_PAUSE)) {
364 			db_printf("cpu %ld not paused\n", addr);
365 			return;
366 		}
367 	}
368 	if (ci->ci_ddb_regs == 0) {
369 		db_printf("cpu %ld has no saved regs\n", addr);
370 		return;
371 	}
372 	db_printf("using cpu %ld", addr);
373 	ddb_regp = ci->ci_ddb_regs;
374 }
375 
376 
377 #endif
378