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