add gd_other_cpus
[dragonfly.git] / sys / platform / pc32 / i386 / db_interface.c
CommitLineData
984263bc
MD
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 $
1de703da 27 * $DragonFly: src/sys/platform/pc32/i386/db_interface.c,v 1.2 2003/06/17 04:28:35 dillon Exp $
984263bc
MD
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
44#include <vm/vm.h>
45#include <vm/pmap.h>
46
47#include <ddb/ddb.h>
48
49#include <setjmp.h>
50
51static jmp_buf *db_nofault = 0;
52extern jmp_buf db_jmpbuf;
53
54extern void gdb_handle_exception __P((db_regs_t *, int, int));
55
56int db_active;
57db_regs_t ddb_regs;
58
59static jmp_buf db_global_jmpbuf;
60static int db_global_jmpbuf_valid;
61
62#ifdef __GNUC__
63#define rss() ({u_short ss; __asm __volatile("mov %%ss,%0" : "=r" (ss)); ss;})
64#endif
65
66/*
67 * kdb_trap - field a TRACE or BPT trap
68 */
69int
70kdb_trap(type, code, regs)
71 int type, code;
72 register struct i386_saved_state *regs;
73{
74 volatile int ddb_mode = !(boothowto & RB_GDB);
75
76 /*
77 * XXX try to do nothing if the console is in graphics mode.
78 * Handle trace traps (and hardware breakpoints...) by ignoring
79 * them except for forgetting about them. Return 0 for other
80 * traps to say that we haven't done anything. The trap handler
81 * will usually panic. We should handle breakpoint traps for
82 * our breakpoints by disarming our breakpoints and fixing up
83 * %eip.
84 */
85 if (cons_unavail && ddb_mode) {
86 if (type == T_TRCTRAP) {
87 regs->tf_eflags &= ~PSL_T;
88 return (1);
89 }
90 return (0);
91 }
92
93 switch (type) {
94 case T_BPTFLT: /* breakpoint */
95 case T_TRCTRAP: /* debug exception */
96 break;
97
98 default:
99 /*
100 * XXX this is almost useless now. In most cases,
101 * trap_fatal() has already printed a much more verbose
102 * message. However, it is dangerous to print things in
103 * trap_fatal() - printf() might be reentered and trap.
104 * The debugger should be given control first.
105 */
106 if (ddb_mode)
107 db_printf("kernel: type %d trap, code=%x\n", type, code);
108
109 if (db_nofault) {
110 jmp_buf *no_fault = db_nofault;
111 db_nofault = 0;
112 longjmp(*no_fault, 1);
113 }
114 }
115
116 /*
117 * This handles unexpected traps in ddb commands, including calls to
118 * non-ddb functions. db_nofault only applies to memory accesses by
119 * internal ddb commands.
120 */
121 if (db_global_jmpbuf_valid)
122 longjmp(db_global_jmpbuf, 1);
123
124 /*
125 * XXX We really should switch to a local stack here.
126 */
127 ddb_regs = *regs;
128
129 /*
130 * If in kernel mode, esp and ss are not saved, so dummy them up.
131 */
132 if (ISPL(regs->tf_cs) == 0) {
133 ddb_regs.tf_esp = (int)&regs->tf_esp;
134 ddb_regs.tf_ss = rss();
135 }
136
137#ifdef SMP
138#ifdef CPUSTOP_ON_DDBBREAK
139
140#if defined(VERBOSE_CPUSTOP_ON_DDBBREAK)
141 db_printf("\nCPU%d stopping CPUs: 0x%08x\n", cpuid, other_cpus);
142#endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */
143
144 /* We stop all CPUs except ourselves (obviously) */
145 stop_cpus(other_cpus);
146
147#if defined(VERBOSE_CPUSTOP_ON_DDBBREAK)
148 db_printf(" stopped\n");
149#endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */
150
151#endif /* CPUSTOP_ON_DDBBREAK */
152#endif /* SMP */
153
154 (void) setjmp(db_global_jmpbuf);
155 db_global_jmpbuf_valid = TRUE;
156 db_active++;
157 if (ddb_mode) {
158 cndbctl(TRUE);
159 db_trap(type, code);
160 cndbctl(FALSE);
161 } else
162 gdb_handle_exception(&ddb_regs, type, code);
163 db_active--;
164 db_global_jmpbuf_valid = FALSE;
165
166#ifdef SMP
167#ifdef CPUSTOP_ON_DDBBREAK
168
169#if defined(VERBOSE_CPUSTOP_ON_DDBBREAK)
170 db_printf("\nCPU%d restarting CPUs: 0x%08x\n", cpuid, stopped_cpus);
171#endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */
172
173 /* Restart all the CPUs we previously stopped */
174 if (stopped_cpus != other_cpus && smp_started != 0) {
175 db_printf("whoa, other_cpus: 0x%08x, stopped_cpus: 0x%08x\n",
176 other_cpus, stopped_cpus);
177 panic("stop_cpus() failed");
178 }
179 restart_cpus(stopped_cpus);
180
181#if defined(VERBOSE_CPUSTOP_ON_DDBBREAK)
182 db_printf(" restarted\n");
183#endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */
184
185#endif /* CPUSTOP_ON_DDBBREAK */
186#endif /* SMP */
187
188 regs->tf_eip = ddb_regs.tf_eip;
189 regs->tf_eflags = ddb_regs.tf_eflags;
190 regs->tf_eax = ddb_regs.tf_eax;
191 regs->tf_ecx = ddb_regs.tf_ecx;
192 regs->tf_edx = ddb_regs.tf_edx;
193 regs->tf_ebx = ddb_regs.tf_ebx;
194
195 /*
196 * If in user mode, the saved ESP and SS were valid, restore them.
197 */
198 if (ISPL(regs->tf_cs)) {
199 regs->tf_esp = ddb_regs.tf_esp;
200 regs->tf_ss = ddb_regs.tf_ss & 0xffff;
201 }
202
203 regs->tf_ebp = ddb_regs.tf_ebp;
204 regs->tf_esi = ddb_regs.tf_esi;
205 regs->tf_edi = ddb_regs.tf_edi;
206 regs->tf_es = ddb_regs.tf_es & 0xffff;
207 regs->tf_fs = ddb_regs.tf_fs & 0xffff;
208 regs->tf_cs = ddb_regs.tf_cs & 0xffff;
209 regs->tf_ds = ddb_regs.tf_ds & 0xffff;
210 return (1);
211}
212
213/*
214 * Read bytes from kernel address space for debugger.
215 */
216void
217db_read_bytes(addr, size, data)
218 vm_offset_t addr;
219 register size_t size;
220 register char *data;
221{
222 register char *src;
223
224 db_nofault = &db_jmpbuf;
225
226 src = (char *)addr;
227 while (size-- > 0)
228 *data++ = *src++;
229
230 db_nofault = 0;
231}
232
233/*
234 * Write bytes to kernel address space for debugger.
235 */
236void
237db_write_bytes(addr, size, data)
238 vm_offset_t addr;
239 register size_t size;
240 register char *data;
241{
242 register char *dst;
243
244 unsigned *ptep0 = NULL;
245 unsigned oldmap0 = 0;
246 vm_offset_t addr1;
247 unsigned *ptep1 = NULL;
248 unsigned oldmap1 = 0;
249
250 db_nofault = &db_jmpbuf;
251
252 if (addr > trunc_page((vm_offset_t)btext) - size &&
253 addr < round_page((vm_offset_t)etext)) {
254
255 ptep0 = pmap_pte(kernel_pmap, addr);
256 oldmap0 = *ptep0;
257 *ptep0 |= PG_RW;
258
259 /* Map another page if the data crosses a page boundary. */
260 if ((*ptep0 & PG_PS) == 0) {
261 addr1 = trunc_page(addr + size - 1);
262 if (trunc_page(addr) != addr1) {
263 ptep1 = pmap_pte(kernel_pmap, addr1);
264 oldmap1 = *ptep1;
265 *ptep1 |= PG_RW;
266 }
267 } else {
268 addr1 = trunc_4mpage(addr + size - 1);
269 if (trunc_4mpage(addr) != addr1) {
270 ptep1 = pmap_pte(kernel_pmap, addr1);
271 oldmap1 = *ptep1;
272 *ptep1 |= PG_RW;
273 }
274 }
275
276 invltlb();
277 }
278
279 dst = (char *)addr;
280
281 while (size-- > 0)
282 *dst++ = *data++;
283
284 db_nofault = 0;
285
286 if (ptep0) {
287 *ptep0 = oldmap0;
288
289 if (ptep1)
290 *ptep1 = oldmap1;
291
292 invltlb();
293 }
294}
295
296/*
297 * XXX
298 * Move this to machdep.c and allow it to be called if any debugger is
299 * installed.
300 */
301void
302Debugger(msg)
303 const char *msg;
304{
305 static volatile u_char in_Debugger;
306
307 /*
308 * XXX
309 * Do nothing if the console is in graphics mode. This is
310 * OK if the call is for the debugger hotkey but not if the call
311 * is a weak form of panicing.
312 */
313 if (cons_unavail && !(boothowto & RB_GDB))
314 return;
315
316 if (!in_Debugger) {
317 in_Debugger = 1;
318 db_printf("Debugger(\"%s\")\n", msg);
319 breakpoint();
320 in_Debugger = 0;
321 }
322}