Started adding pthread code to spawn the "CPUs". Added some debugging
[dragonfly/vkernel-mp.git] / sys / platform / vkernel / i386 / db_interface.c
blobc6f187dc85ead1488fbd95b2e6578dc0c8aabdc3
1 /*
2 * Mach Operating System
3 * Copyright (c) 1991,1990 Carnegie Mellon University
4 * All Rights Reserved.
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.
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.
16 * Carnegie Mellon requests users of this software to return to
18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
19 * School of Computer Science
20 * Carnegie Mellon University
21 * Pittsburgh PA 15213-3890
23 * any improvements or extensions that they make and grant Carnegie the
24 * rights to redistribute these changes.
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/vkernel/i386/db_interface.c,v 1.3 2007/01/09 01:20:17 dillon Exp $
31 * Interface to new debugger.
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/reboot.h>
36 #include <sys/cons.h>
37 #include <sys/vkernel.h>
39 #include <machine/cpu.h>
40 #include <machine/smp.h>
41 #include <machine/globaldata.h>
42 #include <machine/md_var.h>
44 #include <vm/vm.h>
45 #include <vm/pmap.h>
47 #include <ddb/ddb.h>
49 #include <setjmp.h>
51 static jmp_buf *db_nofault = 0;
52 extern jmp_buf db_jmpbuf;
54 extern void gdb_handle_exception (db_regs_t *, int, int);
56 int db_active;
57 db_regs_t ddb_regs;
59 static jmp_buf db_global_jmpbuf;
60 static int db_global_jmpbuf_valid;
62 #ifdef __GNUC__
63 #define rss() ({u_short ss; __asm __volatile("mov %%ss,%0" : "=r" (ss)); ss;})
64 #endif
67 * kdb_trap - field a TRACE or BPT trap
69 int
70 kdb_trap(int type, int code, struct i386_saved_state *regs)
72 volatile int ddb_mode = !(boothowto & RB_GDB);
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.
83 if (cons_unavail && ddb_mode) {
84 if (type == T_TRCTRAP) {
85 regs->tf_eflags &= ~PSL_T;
86 return (1);
88 return (0);
91 switch (type) {
92 case T_BPTFLT: /* breakpoint */
93 case T_TRCTRAP: /* debug exception */
94 break;
96 default:
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
101 * trap_fatal() - kprintf() might be reentered and trap.
102 * The debugger should be given control first.
104 if (ddb_mode)
105 db_printf("kernel: type %d trap, code=%x\n", type, code);
107 if (db_nofault) {
108 jmp_buf *no_fault = db_nofault;
109 db_nofault = 0;
110 longjmp(*no_fault, 1);
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.
119 if (db_global_jmpbuf_valid)
120 longjmp(db_global_jmpbuf, 1);
123 * XXX We really should switch to a local stack here.
125 ddb_regs = *regs;
128 * If in kernel mode, esp and ss are not saved, so dummy them up.
130 if (ISPL(regs->tf_cs) == 0) {
131 ddb_regs.tf_esp = (int)&regs->tf_esp;
132 ddb_regs.tf_ss = rss();
135 #ifdef SMP
136 db_printf("\nCPU%d stopping CPUs: 0x%08x\n",
137 mycpu->gd_cpuid, mycpu->gd_other_cpus);
139 /* We stop all CPUs except ourselves (obviously) */
140 stop_cpus(mycpu->gd_other_cpus);
142 db_printf(" stopped\n");
143 #endif /* SMP */
145 setjmp(db_global_jmpbuf);
146 db_global_jmpbuf_valid = TRUE;
147 db_active++;
148 vcons_set_mode(1);
149 if (ddb_mode) {
150 cndbctl(TRUE);
151 db_trap(type, code);
152 cndbctl(FALSE);
153 } else
154 gdb_handle_exception(&ddb_regs, type, code);
155 db_active--;
156 vcons_set_mode(0);
157 db_global_jmpbuf_valid = FALSE;
159 #ifdef SMP
160 db_printf("\nCPU%d restarting CPUs: 0x%08x\n",
161 mycpu->gd_cpuid, stopped_cpus);
163 /* Restart all the CPUs we previously stopped */
164 if (stopped_cpus != mycpu->gd_other_cpus) {
165 db_printf("whoa, other_cpus: 0x%08x, stopped_cpus: 0x%08x\n",
166 mycpu->gd_other_cpus, stopped_cpus);
167 panic("stop_cpus() failed");
169 restart_cpus(stopped_cpus);
171 db_printf(" restarted\n");
172 #endif /* SMP */
174 regs->tf_eip = ddb_regs.tf_eip;
175 regs->tf_eflags = ddb_regs.tf_eflags;
176 regs->tf_eax = ddb_regs.tf_eax;
177 regs->tf_ecx = ddb_regs.tf_ecx;
178 regs->tf_edx = ddb_regs.tf_edx;
179 regs->tf_ebx = ddb_regs.tf_ebx;
182 * If in user mode, the saved ESP and SS were valid, restore them.
184 if (ISPL(regs->tf_cs)) {
185 regs->tf_esp = ddb_regs.tf_esp;
186 regs->tf_ss = ddb_regs.tf_ss & 0xffff;
189 regs->tf_ebp = ddb_regs.tf_ebp;
190 regs->tf_esi = ddb_regs.tf_esi;
191 regs->tf_edi = ddb_regs.tf_edi;
192 regs->tf_es = ddb_regs.tf_es & 0xffff;
193 regs->tf_fs = ddb_regs.tf_fs & 0xffff;
194 regs->tf_gs = ddb_regs.tf_gs & 0xffff;
195 regs->tf_cs = ddb_regs.tf_cs & 0xffff;
196 regs->tf_ds = ddb_regs.tf_ds & 0xffff;
197 return (1);
201 * Read bytes from kernel address space for debugger.
203 void
204 db_read_bytes(vm_offset_t addr, size_t size, char *data)
206 char *src;
208 db_nofault = &db_jmpbuf;
210 src = (char *)addr;
211 while (size-- > 0)
212 *data++ = *src++;
214 db_nofault = 0;
218 * Write bytes to kernel address space for debugger.
220 void
221 db_write_bytes(vm_offset_t addr, size_t size, char *data)
223 char *dst;
224 #if 0
225 vpte_t *ptep0 = NULL;
226 vpte_t oldmap0 = 0;
227 vm_offset_t addr1;
228 vpte_t *ptep1 = NULL;
229 vpte_t oldmap1 = 0;
230 #endif
232 db_nofault = &db_jmpbuf;
233 #if 0
234 if (addr > trunc_page((vm_offset_t)btext) - size &&
235 addr < round_page((vm_offset_t)etext)) {
237 ptep0 = pmap_kpte(addr);
238 oldmap0 = *ptep0;
239 *ptep0 |= VPTE_W;
241 /* Map another page if the data crosses a page boundary. */
242 if ((*ptep0 & PG_PS) == 0) {
243 addr1 = trunc_page(addr + size - 1);
244 if (trunc_page(addr) != addr1) {
245 ptep1 = pmap_kpte(addr1);
246 oldmap1 = *ptep1;
247 *ptep1 |= VPTE_W;
249 } else {
250 addr1 = trunc_4mpage(addr + size - 1);
251 if (trunc_4mpage(addr) != addr1) {
252 ptep1 = pmap_kpte(addr1);
253 oldmap1 = *ptep1;
254 *ptep1 |= VPTE_W;
258 cpu_invltlb();
260 #endif
262 dst = (char *)addr;
264 while (size-- > 0)
265 *dst++ = *data++;
267 db_nofault = 0;
269 #if 0
270 if (ptep0) {
271 *ptep0 = oldmap0;
273 if (ptep1)
274 *ptep1 = oldmap1;
276 cpu_invltlb();
278 #endif
282 * The debugger sometimes needs to know the actual KVM address represented
283 * by the instruction pointer, stack pointer, or base pointer. Normally
284 * the actual KVM address is simply the contents of the register. However,
285 * if the debugger is entered from the BIOS or VM86 we need to figure out
286 * the offset from the segment register.
288 db_addr_t
289 PC_REGS(db_regs_t *regs)
291 return(regs->tf_eip);
294 db_addr_t
295 SP_REGS(db_regs_t *regs)
297 return(regs->tf_esp);
300 db_addr_t
301 BP_REGS(db_regs_t *regs)
303 return(regs->tf_ebp);
307 * XXX
308 * Move this to machdep.c and allow it to be called if any debugger is
309 * installed.
311 void
312 Debugger(const char *msg)
314 static volatile u_char in_Debugger;
317 * XXX
318 * Do nothing if the console is in graphics mode. This is
319 * OK if the call is for the debugger hotkey but not if the call
320 * is a weak form of panicing.
322 if (cons_unavail && !(boothowto & RB_GDB))
323 return;
325 if (!in_Debugger) {
326 in_Debugger = 1;
327 db_printf("Debugger(\"%s\")\n", msg);
328 breakpoint();
329 in_Debugger = 0;