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)®s->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 = ®s; 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