kernel: Make SMP support default (and non-optional).
[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 $
27 */
28
29/*
30 * Interface to new debugger.
31 */
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/reboot.h>
35#include <sys/cons.h>
33bb509e 36#include <sys/thread.h>
984263bc
MD
37
38#include <machine/cpu.h>
984263bc 39#include <machine/smp.h>
72740893 40#include <machine/globaldata.h>
984263bc
MD
41
42#include <vm/vm.h>
43#include <vm/pmap.h>
44
45#include <ddb/ddb.h>
46
33bb509e
MD
47#include <sys/thread2.h>
48
984263bc
MD
49#include <setjmp.h>
50
4090d6ff 51static jmp_buf *db_nofault = NULL;
984263bc
MD
52extern jmp_buf db_jmpbuf;
53
3ae0cd58 54extern void gdb_handle_exception (db_regs_t *, int, int);
984263bc
MD
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
f123d5a1 70kdb_trap(int type, int code, struct i386_saved_state *regs)
984263bc
MD
71{
72 volatile int ddb_mode = !(boothowto & RB_GDB);
73
74 /*
75 * XXX try to do nothing if the console is in graphics mode.
76 * Handle trace traps (and hardware breakpoints...) by ignoring
77 * them except for forgetting about them. Return 0 for other
78 * traps to say that we haven't done anything. The trap handler
79 * will usually panic. We should handle breakpoint traps for
80 * our breakpoints by disarming our breakpoints and fixing up
81 * %eip.
82 */
83 if (cons_unavail && ddb_mode) {
84 if (type == T_TRCTRAP) {
85 regs->tf_eflags &= ~PSL_T;
86 return (1);
87 }
88 return (0);
89 }
90
91 switch (type) {
92 case T_BPTFLT: /* breakpoint */
93 case T_TRCTRAP: /* debug exception */
94 break;
95
96 default:
97 /*
98 * XXX this is almost useless now. In most cases,
99 * trap_fatal() has already printed a much more verbose
100 * message. However, it is dangerous to print things in
26be20a0 101 * trap_fatal() - kprintf() might be reentered and trap.
984263bc
MD
102 * The debugger should be given control first.
103 */
104 if (ddb_mode)
105 db_printf("kernel: type %d trap, code=%x\n", type, code);
106
107 if (db_nofault) {
108 jmp_buf *no_fault = db_nofault;
4090d6ff 109 db_nofault = NULL;
984263bc
MD
110 longjmp(*no_fault, 1);
111 }
112 }
113
114 /*
115 * This handles unexpected traps in ddb commands, including calls to
116 * non-ddb functions. db_nofault only applies to memory accesses by
117 * internal ddb commands.
118 */
119 if (db_global_jmpbuf_valid)
120 longjmp(db_global_jmpbuf, 1);
121
122 /*
123 * XXX We really should switch to a local stack here.
124 */
125 ddb_regs = *regs;
126
127 /*
128 * If in kernel mode, esp and ss are not saved, so dummy them up.
129 */
130 if (ISPL(regs->tf_cs) == 0) {
131 ddb_regs.tf_esp = (int)&regs->tf_esp;
132 ddb_regs.tf_ss = rss();
133 }
134
33bb509e 135 crit_enter();
8a8d5d85
MD
136 db_printf("\nCPU%d stopping CPUs: 0x%08x\n",
137 mycpu->gd_cpuid, mycpu->gd_other_cpus);
984263bc
MD
138
139 /* We stop all CPUs except ourselves (obviously) */
72740893 140 stop_cpus(mycpu->gd_other_cpus);
984263bc 141
984263bc 142 db_printf(" stopped\n");
984263bc 143
09e6e929 144 setjmp(db_global_jmpbuf);
984263bc
MD
145 db_global_jmpbuf_valid = TRUE;
146 db_active++;
147 if (ddb_mode) {
148 cndbctl(TRUE);
149 db_trap(type, code);
150 cndbctl(FALSE);
151 } else
152 gdb_handle_exception(&ddb_regs, type, code);
153 db_active--;
154 db_global_jmpbuf_valid = FALSE;
155
8a8d5d85
MD
156 db_printf("\nCPU%d restarting CPUs: 0x%08x\n",
157 mycpu->gd_cpuid, stopped_cpus);
984263bc
MD
158
159 /* Restart all the CPUs we previously stopped */
0f7a3396 160 if (stopped_cpus != mycpu->gd_other_cpus) {
984263bc 161 db_printf("whoa, other_cpus: 0x%08x, stopped_cpus: 0x%08x\n",
72740893 162 mycpu->gd_other_cpus, stopped_cpus);
984263bc
MD
163 panic("stop_cpus() failed");
164 }
165 restart_cpus(stopped_cpus);
166
984263bc 167 db_printf(" restarted\n");
33bb509e 168 crit_exit();
984263bc
MD
169
170 regs->tf_eip = ddb_regs.tf_eip;
171 regs->tf_eflags = ddb_regs.tf_eflags;
172 regs->tf_eax = ddb_regs.tf_eax;
173 regs->tf_ecx = ddb_regs.tf_ecx;
174 regs->tf_edx = ddb_regs.tf_edx;
175 regs->tf_ebx = ddb_regs.tf_ebx;
176
177 /*
178 * If in user mode, the saved ESP and SS were valid, restore them.
179 */
180 if (ISPL(regs->tf_cs)) {
181 regs->tf_esp = ddb_regs.tf_esp;
182 regs->tf_ss = ddb_regs.tf_ss & 0xffff;
183 }
184
185 regs->tf_ebp = ddb_regs.tf_ebp;
186 regs->tf_esi = ddb_regs.tf_esi;
187 regs->tf_edi = ddb_regs.tf_edi;
188 regs->tf_es = ddb_regs.tf_es & 0xffff;
189 regs->tf_fs = ddb_regs.tf_fs & 0xffff;
4e7c41c5 190 regs->tf_gs = ddb_regs.tf_gs & 0xffff;
984263bc
MD
191 regs->tf_cs = ddb_regs.tf_cs & 0xffff;
192 regs->tf_ds = ddb_regs.tf_ds & 0xffff;
193 return (1);
194}
195
196/*
197 * Read bytes from kernel address space for debugger.
198 */
199void
f123d5a1 200db_read_bytes(vm_offset_t addr, size_t size, char *data)
984263bc 201{
c9faf524 202 char *src;
984263bc
MD
203
204 db_nofault = &db_jmpbuf;
205
206 src = (char *)addr;
207 while (size-- > 0)
208 *data++ = *src++;
209
4090d6ff 210 db_nofault = NULL;
984263bc
MD
211}
212
213/*
214 * Write bytes to kernel address space for debugger.
215 */
216void
f123d5a1 217db_write_bytes(vm_offset_t addr, size_t size, char *data)
984263bc 218{
c9faf524 219 char *dst;
984263bc
MD
220
221 unsigned *ptep0 = NULL;
222 unsigned oldmap0 = 0;
223 vm_offset_t addr1;
224 unsigned *ptep1 = NULL;
225 unsigned oldmap1 = 0;
226
227 db_nofault = &db_jmpbuf;
228
229 if (addr > trunc_page((vm_offset_t)btext) - size &&
230 addr < round_page((vm_offset_t)etext)) {
231
4107b0c0 232 ptep0 = pmap_kernel_pte(addr);
984263bc
MD
233 oldmap0 = *ptep0;
234 *ptep0 |= PG_RW;
235
236 /* Map another page if the data crosses a page boundary. */
237 if ((*ptep0 & PG_PS) == 0) {
238 addr1 = trunc_page(addr + size - 1);
239 if (trunc_page(addr) != addr1) {
4107b0c0 240 ptep1 = pmap_kernel_pte(addr1);
984263bc
MD
241 oldmap1 = *ptep1;
242 *ptep1 |= PG_RW;
243 }
244 } else {
245 addr1 = trunc_4mpage(addr + size - 1);
246 if (trunc_4mpage(addr) != addr1) {
4107b0c0 247 ptep1 = pmap_kernel_pte(addr1);
984263bc
MD
248 oldmap1 = *ptep1;
249 *ptep1 |= PG_RW;
250 }
251 }
252
0f7a3396 253 cpu_invltlb();
984263bc
MD
254 }
255
256 dst = (char *)addr;
257
258 while (size-- > 0)
259 *dst++ = *data++;
260
4090d6ff 261 db_nofault = NULL;
984263bc
MD
262
263 if (ptep0) {
264 *ptep0 = oldmap0;
265
266 if (ptep1)
267 *ptep1 = oldmap1;
268
0f7a3396 269 cpu_invltlb();
984263bc
MD
270 }
271}
272
55a2e6d4
MD
273/*
274 * The debugger sometimes needs to know the actual KVM address represented
275 * by the instruction pointer, stack pointer, or base pointer. Normally
276 * the actual KVM address is simply the contents of the register. However,
277 * if the debugger is entered from the BIOS or VM86 we need to figure out
278 * the offset from the segment register.
279 */
280db_addr_t
281PC_REGS(db_regs_t *regs)
282{
283 struct soft_segment_descriptor softseg;
284
285 sdtossd(&gdt[mycpu->gd_cpuid * NGDT + IDXSEL(regs->tf_cs & 0xffff)].sd, &softseg);
286 return(regs->tf_eip + softseg.ssd_base);
287}
288
289db_addr_t
290SP_REGS(db_regs_t *regs)
291{
292 struct soft_segment_descriptor softseg;
293
294 sdtossd(&gdt[mycpu->gd_cpuid * NGDT + IDXSEL(regs->tf_ss & 0xffff)].sd, &softseg);
295 return(regs->tf_esp + softseg.ssd_base);
296}
297
298db_addr_t
299BP_REGS(db_regs_t *regs)
300{
301 struct soft_segment_descriptor softseg;
302
303 sdtossd(&gdt[mycpu->gd_cpuid * NGDT + IDXSEL(regs->tf_ds & 0xffff)].sd, &softseg);
179247f2 304 return(regs->tf_ebp + softseg.ssd_base);
55a2e6d4
MD
305}
306
984263bc
MD
307/*
308 * XXX
309 * Move this to machdep.c and allow it to be called if any debugger is
310 * installed.
311 */
312void
f123d5a1 313Debugger(const char *msg)
984263bc
MD
314{
315 static volatile u_char in_Debugger;
316
317 /*
318 * XXX
319 * Do nothing if the console is in graphics mode. This is
320 * OK if the call is for the debugger hotkey but not if the call
321 * is a weak form of panicing.
322 */
323 if (cons_unavail && !(boothowto & RB_GDB))
324 return;
325
326 if (!in_Debugger) {
327 in_Debugger = 1;
328 db_printf("Debugger(\"%s\")\n", msg);
329 breakpoint();
330 in_Debugger = 0;
331 }
332}