1 /* $NetBSD: db_interface.c,v 1.44 2026/11/07 22:20:10 thorpej 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 (at) 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.44 2026/11/07 22:20:10 thorpej Exp $"); 37 38 #include "opt_ddb.h" 39 #include "opt_multiprocessor.h" 40 41 #include "lapic.h" 42 43 #include <sys/param.h> 44 #include <sys/proc.h> 45 #include <sys/reboot.h> 46 #include <sys/systm.h> 47 #include <sys/atomic.h> 48 #include <sys/cpu.h> 49 50 #include <dev/cons.h> 51 52 #include <machine/cpufunc.h> 53 #include <machine/db_machdep.h> 54 #include <machine/cpuvar.h> 55 #if NIOAPIC > 0 56 #include <machine/i82093var.h> 57 #endif 58 #if NLAPIC > 0 59 #include <machine/i82489reg.h> 60 #include <machine/i82489var.h> 61 #endif 62 63 #include <ddb/db_sym.h> 64 #include <ddb/db_command.h> 65 #include <ddb/db_extern.h> 66 #include <ddb/db_access.h> 67 #include <ddb/db_output.h> 68 #include <ddb/ddbvar.h> 69 70 extern const char *const trap_type[]; 71 extern int trap_types; 72 73 #ifdef MULTIPROCESSOR 74 /* ddb_regs defined as a macro */ 75 db_regs_t *ddb_regp = NULL; 76 #else 77 db_regs_t ddb_regs; 78 #endif 79 80 void db_mach_cpu (db_expr_t, bool, db_expr_t, const char *); 81 82 const struct db_command db_machine_command_table[] = { 83 #ifdef MULTIPROCESSOR 84 { DDB_ADD_CMD("cpu", db_mach_cpu, 0, 85 "switch to another cpu", "cpu-no", NULL) }, 86 #endif 87 { DDB_END_CMD }, 88 }; 89 90 void kdbprinttrap(int, int); 91 #ifdef MULTIPROCESSOR 92 extern void ddb_ipi(struct trapframe); 93 static void ddb_suspend(struct trapframe *); 94 #ifndef XENPV 95 int ddb_vec; 96 #endif /* XENPV */ 97 static bool ddb_mp_online; 98 #endif 99 100 #define NOCPU -1 101 102 int ddb_cpu = NOCPU; 103 104 typedef void (vector)(void); 105 extern vector Xintr_ddbipi, Xintr_x2apic_ddbipi; 106 107 void 108 db_machine_init(void) 109 { 110 111 #ifdef MULTIPROCESSOR 112 #ifndef XENPV 113 struct idt_vec *iv = &(cpu_info_primary.ci_idtvec); 114 vector *handler = &Xintr_ddbipi; 115 idt_descriptor_t *idt = iv->iv_idt; 116 #if NLAPIC > 0 117 if (lapic_is_x2apic()) 118 handler = &Xintr_x2apic_ddbipi; 119 #endif 120 ddb_vec = idt_vec_alloc(iv, 0xf0, 0xff); 121 KASSERT(ddb_vec > 0); 122 set_idtgate(&idt[ddb_vec], handler, 1, SDT_SYS386IGT, SEL_KPL, 123 GSEL(GCODE_SEL, SEL_KPL)); 124 #else 125 /* Initialised as part of xen_ipi_init() */ 126 #endif /* XENPV */ 127 #endif 128 } 129 130 #ifdef MULTIPROCESSOR 131 132 __cpu_simple_lock_t db_lock; 133 134 static int 135 db_suspend_others(void) 136 { 137 int cpu_me = cpu_number(); 138 int win; 139 140 #ifndef XENPV 141 if (ddb_vec == 0) 142 return 1; 143 #endif /* XENPV */ 144 145 __cpu_simple_lock(&db_lock); 146 if (ddb_cpu == NOCPU) 147 ddb_cpu = cpu_me; 148 win = (ddb_cpu == cpu_me); 149 __cpu_simple_unlock(&db_lock); 150 if (win) { 151 #ifdef XENPV 152 xen_broadcast_ipi(XEN_IPI_DDB); 153 #else 154 #if NLAPIC > 0 155 if (ddb_vec != 0) 156 x86_ipi(ddb_vec, LAPIC_DEST_ALLEXCL, 157 LAPIC_DLMODE_FIXED); 158 #endif 159 #endif /* XENPV */ 160 } 161 ddb_mp_online = x86_mp_online; 162 x86_mp_online = false; 163 return win; 164 } 165 166 static void 167 db_resume_others(void) 168 { 169 CPU_INFO_ITERATOR cii; 170 struct cpu_info *ci; 171 172 x86_mp_online = ddb_mp_online; 173 __cpu_simple_lock(&db_lock); 174 ddb_cpu = NOCPU; 175 __cpu_simple_unlock(&db_lock); 176 177 for (CPU_INFO_FOREACH(cii, ci)) { 178 if (ci->ci_flags & CPUF_PAUSE) 179 atomic_and_32(&ci->ci_flags, ~CPUF_PAUSE); 180 } 181 } 182 183 #endif 184 185 /* 186 * Print trap reason. 187 */ 188 void 189 kdbprinttrap(int type, int code) 190 { 191 db_printf("kernel: "); 192 if (type >= trap_types || type < 0) 193 db_printf("type %d", type); 194 else 195 db_printf("%s", trap_type[type]); 196 db_printf(" trap, code=%x\n", code); 197 } 198 199 /* 200 * kdb_trap - field a TRACE or BPT trap 201 */ 202 int 203 kdb_trap(int type, int code, db_regs_t *regs) 204 { 205 int s; 206 #ifdef MULTIPROCESSOR 207 db_regs_t dbreg; 208 #endif 209 210 switch (type) { 211 case T_NMI: /* NMI */ 212 printf("NMI ... going to debugger\n"); 213 /*FALLTHROUGH*/ 214 case T_BPTFLT: /* breakpoint */ 215 case T_TRCTRAP: /* single_step */ 216 case -1: /* keyboard interrupt */ 217 break; 218 default: 219 if (!db_onpanic && db_recover == 0) 220 return (0); 221 222 kdbprinttrap(type, code); 223 if (db_recover != 0) { 224 db_error("Faulted in DDB; continuing...\n"); 225 /*NOTREACHED*/ 226 } 227 } 228 229 #ifdef MULTIPROCESSOR 230 if (!db_suspend_others()) { 231 ddb_suspend(regs); 232 } else { 233 curcpu()->ci_ddb_regs = &dbreg; 234 ddb_regp = &dbreg; 235 #endif 236 237 ddb_regs = *regs; 238 239 ddb_regs.tf_cs &= 0xffff; 240 ddb_regs.tf_ds &= 0xffff; 241 ddb_regs.tf_es &= 0xffff; 242 ddb_regs.tf_fs &= 0xffff; 243 ddb_regs.tf_gs &= 0xffff; 244 ddb_regs.tf_ss &= 0xffff; 245 246 s = splhigh(); 247 db_active++; 248 cnpollc(true); 249 db_trap(type, code); 250 cnpollc(false); 251 db_active--; 252 splx(s); 253 #ifdef MULTIPROCESSOR 254 db_resume_others(); 255 } 256 /* Restore dbreg because ddb_regp can be changed by db_mach_cpu */ 257 ddb_regp = &dbreg; 258 #endif 259 260 *regs = ddb_regs; 261 #ifdef MULTIPROCESSOR 262 ddb_regp = NULL; 263 #endif 264 265 return (1); 266 } 267 268 void 269 cpu_Debugger(void) 270 { 271 breakpoint(); 272 } 273 274 #ifdef MULTIPROCESSOR 275 276 /* 277 * Called when we receive a debugger IPI (inter-processor interrupt). 278 * As with trap() in trap.c, this function is called from an assembly 279 * language IDT gate entry routine which prepares a suitable stack frame, 280 * and restores this frame after the exception has been processed. Note 281 * that the effect is as if the arguments were passed call by reference. 282 */ 283 284 void 285 ddb_ipi(struct trapframe frame) 286 { 287 288 ddb_suspend(&frame); 289 } 290 291 static void 292 ddb_suspend(struct trapframe *frame) 293 { 294 volatile struct cpu_info *ci = curcpu(); 295 db_regs_t regs; 296 297 regs = *frame; 298 299 ci->ci_ddb_regs = ®s; 300 301 atomic_or_32(&ci->ci_flags, CPUF_PAUSE); 302 303 while (ci->ci_flags & CPUF_PAUSE) 304 x86_pause(); 305 ci->ci_ddb_regs = 0; 306 tlbflushg(); 307 } 308 309 310 extern void cpu_debug_dump(void); /* XXX */ 311 312 /* 313 * XXX sync with sys/arch/i386/i386/db_interface.c 314 * XXX sync with usr.sbin/crash/arch/x86.c 315 */ 316 void 317 db_mach_cpu(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif) 318 { 319 struct cpu_info *ci; 320 if (!have_addr) { 321 cpu_debug_dump(); 322 return; 323 } 324 325 if (addr < 0) { 326 db_printf("%ld: CPU out of range\n", addr); 327 return; 328 } 329 ci = cpu_lookup(addr); 330 if (ci == NULL) { 331 db_printf("CPU %ld not configured\n", addr); 332 return; 333 } 334 if (ci != curcpu()) { 335 if (!(ci->ci_flags & CPUF_PAUSE)) { 336 db_printf("CPU %ld not paused\n", addr); 337 return; 338 } 339 } 340 if (ci->ci_ddb_regs == 0) { 341 db_printf("CPU %ld has no saved regs\n", addr); 342 return; 343 } 344 db_printf("using CPU %ld", addr); 345 ddb_regp = ci->ci_ddb_regs; 346 } 347 348 #endif 349