MP Implementation 1/2: Get the APIC code working again, sweetly integrate the
[dragonfly.git] / sys / platform / pc32 / i386 / db_interface.c
... / ...
CommitLineData
1/*
2 * Mach Operating System
3 * Copyright (c) 1991,1990 Carnegie Mellon University
4 * All Rights Reserved.
5 *
6 * Permission to use, copy, modify and distribute this software and its
7 * documentation is hereby granted, provided that both the copyright
8 * notice and this permission notice appear in all copies of the
9 * software, derivative works or modified versions, and any portions
10 * thereof, and that both notices appear in supporting documentation.
11 *
12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15 *
16 * Carnegie Mellon requests users of this software to return to
17 *
18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
19 * School of Computer Science
20 * Carnegie Mellon University
21 * Pittsburgh PA 15213-3890
22 *
23 * any improvements or extensions that they make and grant Carnegie the
24 * rights to redistribute these changes.
25 *
26 * $FreeBSD: src/sys/i386/i386/db_interface.c,v 1.48.2.1 2000/07/07 00:38:46 obrien Exp $
27 * $DragonFly: src/sys/platform/pc32/i386/db_interface.c,v 1.4 2003/07/06 21:23:48 dillon Exp $
28 */
29
30/*
31 * Interface to new debugger.
32 */
33#include <sys/param.h>
34#include <sys/systm.h>
35#include <sys/reboot.h>
36#include <sys/cons.h>
37
38#include <machine/cpu.h>
39#ifdef SMP
40#include <machine/smp.h>
41#include <machine/smptests.h> /** CPUSTOP_ON_DDBBREAK */
42#endif
43#include <machine/globaldata.h>
44
45#include <vm/vm.h>
46#include <vm/pmap.h>
47
48#include <ddb/ddb.h>
49
50#include <setjmp.h>
51
52static jmp_buf *db_nofault = 0;
53extern jmp_buf db_jmpbuf;
54
55extern void gdb_handle_exception __P((db_regs_t *, int, int));
56
57int db_active;
58db_regs_t ddb_regs;
59
60static jmp_buf db_global_jmpbuf;
61static int db_global_jmpbuf_valid;
62
63#ifdef __GNUC__
64#define rss() ({u_short ss; __asm __volatile("mov %%ss,%0" : "=r" (ss)); ss;})
65#endif
66
67#define VERBOSE_CPUSTOP_ON_DDBBREAK
68
69/*
70 * kdb_trap - field a TRACE or BPT trap
71 */
72int
73kdb_trap(type, code, regs)
74 int type, code;
75 register struct i386_saved_state *regs;
76{
77 volatile int ddb_mode = !(boothowto & RB_GDB);
78
79 /*
80 * XXX try to do nothing if the console is in graphics mode.
81 * Handle trace traps (and hardware breakpoints...) by ignoring
82 * them except for forgetting about them. Return 0 for other
83 * traps to say that we haven't done anything. The trap handler
84 * will usually panic. We should handle breakpoint traps for
85 * our breakpoints by disarming our breakpoints and fixing up
86 * %eip.
87 */
88 if (cons_unavail && ddb_mode) {
89 if (type == T_TRCTRAP) {
90 regs->tf_eflags &= ~PSL_T;
91 return (1);
92 }
93 return (0);
94 }
95
96 switch (type) {
97 case T_BPTFLT: /* breakpoint */
98 case T_TRCTRAP: /* debug exception */
99 break;
100
101 default:
102 /*
103 * XXX this is almost useless now. In most cases,
104 * trap_fatal() has already printed a much more verbose
105 * message. However, it is dangerous to print things in
106 * trap_fatal() - printf() might be reentered and trap.
107 * The debugger should be given control first.
108 */
109 if (ddb_mode)
110 db_printf("kernel: type %d trap, code=%x\n", type, code);
111
112 if (db_nofault) {
113 jmp_buf *no_fault = db_nofault;
114 db_nofault = 0;
115 longjmp(*no_fault, 1);
116 }
117 }
118
119 /*
120 * This handles unexpected traps in ddb commands, including calls to
121 * non-ddb functions. db_nofault only applies to memory accesses by
122 * internal ddb commands.
123 */
124 if (db_global_jmpbuf_valid)
125 longjmp(db_global_jmpbuf, 1);
126
127 /*
128 * XXX We really should switch to a local stack here.
129 */
130 ddb_regs = *regs;
131
132 /*
133 * If in kernel mode, esp and ss are not saved, so dummy them up.
134 */
135 if (ISPL(regs->tf_cs) == 0) {
136 ddb_regs.tf_esp = (int)&regs->tf_esp;
137 ddb_regs.tf_ss = rss();
138 }
139
140#ifdef SMP
141#ifdef CPUSTOP_ON_DDBBREAK
142
143#if defined(VERBOSE_CPUSTOP_ON_DDBBREAK)
144 db_printf("\nCPU%d stopping CPUs: 0x%08x\n",
145 mycpu->gd_cpuid, mycpu->gd_other_cpus);
146#endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */
147
148 /* We stop all CPUs except ourselves (obviously) */
149 stop_cpus(mycpu->gd_other_cpus);
150
151#if defined(VERBOSE_CPUSTOP_ON_DDBBREAK)
152 db_printf(" stopped\n");
153#endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */
154
155#endif /* CPUSTOP_ON_DDBBREAK */
156#endif /* SMP */
157
158 (void) setjmp(db_global_jmpbuf);
159 db_global_jmpbuf_valid = TRUE;
160 db_active++;
161 if (ddb_mode) {
162 cndbctl(TRUE);
163 db_trap(type, code);
164 cndbctl(FALSE);
165 } else
166 gdb_handle_exception(&ddb_regs, type, code);
167 db_active--;
168 db_global_jmpbuf_valid = FALSE;
169
170#ifdef SMP
171#ifdef CPUSTOP_ON_DDBBREAK
172
173#if defined(VERBOSE_CPUSTOP_ON_DDBBREAK)
174 db_printf("\nCPU%d restarting CPUs: 0x%08x\n",
175 mycpu->gd_cpuid, stopped_cpus);
176#endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */
177
178 /* Restart all the CPUs we previously stopped */
179 if (stopped_cpus != mycpu->gd_other_cpus && smp_started != 0) {
180 db_printf("whoa, other_cpus: 0x%08x, stopped_cpus: 0x%08x\n",
181 mycpu->gd_other_cpus, stopped_cpus);
182 panic("stop_cpus() failed");
183 }
184 restart_cpus(stopped_cpus);
185
186#if defined(VERBOSE_CPUSTOP_ON_DDBBREAK)
187 db_printf(" restarted\n");
188#endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */
189
190#endif /* CPUSTOP_ON_DDBBREAK */
191#endif /* SMP */
192
193 regs->tf_eip = ddb_regs.tf_eip;
194 regs->tf_eflags = ddb_regs.tf_eflags;
195 regs->tf_eax = ddb_regs.tf_eax;
196 regs->tf_ecx = ddb_regs.tf_ecx;
197 regs->tf_edx = ddb_regs.tf_edx;
198 regs->tf_ebx = ddb_regs.tf_ebx;
199
200 /*
201 * If in user mode, the saved ESP and SS were valid, restore them.
202 */
203 if (ISPL(regs->tf_cs)) {
204 regs->tf_esp = ddb_regs.tf_esp;
205 regs->tf_ss = ddb_regs.tf_ss & 0xffff;
206 }
207
208 regs->tf_ebp = ddb_regs.tf_ebp;
209 regs->tf_esi = ddb_regs.tf_esi;
210 regs->tf_edi = ddb_regs.tf_edi;
211 regs->tf_es = ddb_regs.tf_es & 0xffff;
212 regs->tf_fs = ddb_regs.tf_fs & 0xffff;
213 regs->tf_cs = ddb_regs.tf_cs & 0xffff;
214 regs->tf_ds = ddb_regs.tf_ds & 0xffff;
215 return (1);
216}
217
218/*
219 * Read bytes from kernel address space for debugger.
220 */
221void
222db_read_bytes(addr, size, data)
223 vm_offset_t addr;
224 register size_t size;
225 register char *data;
226{
227 register char *src;
228
229 db_nofault = &db_jmpbuf;
230
231 src = (char *)addr;
232 while (size-- > 0)
233 *data++ = *src++;
234
235 db_nofault = 0;
236}
237
238/*
239 * Write bytes to kernel address space for debugger.
240 */
241void
242db_write_bytes(addr, size, data)
243 vm_offset_t addr;
244 register size_t size;
245 register char *data;
246{
247 register char *dst;
248
249 unsigned *ptep0 = NULL;
250 unsigned oldmap0 = 0;
251 vm_offset_t addr1;
252 unsigned *ptep1 = NULL;
253 unsigned oldmap1 = 0;
254
255 db_nofault = &db_jmpbuf;
256
257 if (addr > trunc_page((vm_offset_t)btext) - size &&
258 addr < round_page((vm_offset_t)etext)) {
259
260 ptep0 = pmap_pte(kernel_pmap, addr);
261 oldmap0 = *ptep0;
262 *ptep0 |= PG_RW;
263
264 /* Map another page if the data crosses a page boundary. */
265 if ((*ptep0 & PG_PS) == 0) {
266 addr1 = trunc_page(addr + size - 1);
267 if (trunc_page(addr) != addr1) {
268 ptep1 = pmap_pte(kernel_pmap, addr1);
269 oldmap1 = *ptep1;
270 *ptep1 |= PG_RW;
271 }
272 } else {
273 addr1 = trunc_4mpage(addr + size - 1);
274 if (trunc_4mpage(addr) != addr1) {
275 ptep1 = pmap_pte(kernel_pmap, addr1);
276 oldmap1 = *ptep1;
277 *ptep1 |= PG_RW;
278 }
279 }
280
281 invltlb();
282 }
283
284 dst = (char *)addr;
285
286 while (size-- > 0)
287 *dst++ = *data++;
288
289 db_nofault = 0;
290
291 if (ptep0) {
292 *ptep0 = oldmap0;
293
294 if (ptep1)
295 *ptep1 = oldmap1;
296
297 invltlb();
298 }
299}
300
301/*
302 * XXX
303 * Move this to machdep.c and allow it to be called if any debugger is
304 * installed.
305 */
306void
307Debugger(msg)
308 const char *msg;
309{
310 static volatile u_char in_Debugger;
311
312 /*
313 * XXX
314 * Do nothing if the console is in graphics mode. This is
315 * OK if the call is for the debugger hotkey but not if the call
316 * is a weak form of panicing.
317 */
318 if (cons_unavail && !(boothowto & RB_GDB))
319 return;
320
321 if (!in_Debugger) {
322 in_Debugger = 1;
323 db_printf("Debugger(\"%s\")\n", msg);
324 breakpoint();
325 in_Debugger = 0;
326 }
327}