1 /* $OpenBSD: db_interface.c,v 1.8 2022/01/28 18:37:40 gkoehler Exp $ */ 2 /* $NetBSD: db_interface.c,v 1.12 2001/07/22 11:29:46 wiz Exp $ */ 3 4 /* 5 * Mach Operating System 6 * Copyright (c) 1991,1990 Carnegie Mellon University 7 * All Rights Reserved. 8 * 9 * Permission to use, copy, modify and distribute this software and its 10 * documentation is hereby granted, provided that both the copyright 11 * notice and this permission notice appear in all copies of the 12 * software, derivative works or modified versions, and any portions 13 * thereof, and that both notices appear in supporting documentation. 14 * 15 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 16 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 17 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 18 * 19 * Carnegie Mellon requests users of this software to return to 20 * 21 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 22 * School of Computer Science 23 * Carnegie Mellon University 24 * Pittsburgh PA 15213-3890 25 * 26 * any improvements or extensions that they make and grant Carnegie the 27 * rights to redistribute these changes. 28 * 29 * db_interface.c,v 2.4 1991/02/05 17:11:13 mrt (CMU) 30 */ 31 32 #include <sys/param.h> 33 #include <sys/proc.h> 34 #include <sys/systm.h> 35 #include <sys/mutex.h> 36 37 #include <dev/cons.h> 38 39 #include <machine/db_machdep.h> 40 #include <ddb/db_extern.h> 41 #include <ddb/db_interface.h> 42 #include <ddb/db_command.h> 43 #include <ddb/db_output.h> 44 #include <ddb/db_run.h> 45 46 #ifdef MULTIPROCESSOR 47 struct db_mutex ddb_mp_mutex = DB_MUTEX_INITIALIZER; 48 volatile int ddb_state = DDB_STATE_NOT_RUNNING; 49 volatile cpuid_t ddb_active_cpu; 50 int db_switch_cpu; 51 long db_switch_to_cpu; 52 #endif 53 54 extern db_regs_t ddb_regs; 55 56 #ifdef MULTIPROCESSOR 57 void db_cpuinfo_cmd(db_expr_t, int, db_expr_t, char *); 58 void db_startproc_cmd(db_expr_t, int, db_expr_t, char *); 59 void db_stopproc_cmd(db_expr_t, int, db_expr_t, char *); 60 void db_ddbproc_cmd(db_expr_t, int, db_expr_t, char *); 61 #endif 62 63 int db_trap_glue(struct trapframe *frame); /* called from locore */ 64 65 void 66 db_enter() 67 { 68 ddb_trap(); 69 } 70 71 int 72 db_trap_glue(struct trapframe *frame) 73 { 74 int s; 75 76 if (!(frame->srr1 & PSL_PR) 77 && (frame->exc == EXC_TRC 78 || (frame->exc == EXC_PGM && (frame->srr1 & 0x20000)) 79 || frame->exc == EXC_BPT)) { 80 81 #ifdef MULTIPROCESSOR 82 db_mtx_enter(&ddb_mp_mutex); 83 if (ddb_state == DDB_STATE_EXITING) 84 ddb_state = DDB_STATE_NOT_RUNNING; 85 db_mtx_leave(&ddb_mp_mutex); 86 87 while (db_enter_ddb()) { 88 #endif 89 ddb_regs = *frame; 90 91 s = splhigh(); 92 db_active++; 93 cnpollc(1); 94 db_trap(T_BREAKPOINT, 0); 95 cnpollc(0); 96 db_active--; 97 splx(s); 98 99 *frame = ddb_regs; 100 #ifdef MULTIPROCESSOR 101 if (!db_switch_cpu) 102 ddb_state = DDB_STATE_EXITING; 103 } 104 #endif 105 return 1; 106 } 107 return 0; 108 } 109 110 int 111 db_enter_ddb(void) 112 { 113 #ifdef MULTIPROCESSOR 114 int i; 115 struct cpu_info *ci = curcpu(); 116 117 db_mtx_enter(&ddb_mp_mutex); 118 119 /* If we are first in, grab ddb and stop all other CPUs */ 120 if (ddb_state == DDB_STATE_NOT_RUNNING) { 121 ddb_active_cpu = cpu_number(); 122 ddb_state = DDB_STATE_RUNNING; 123 ci->ci_ddb_paused = CI_DDB_INDDB; 124 db_mtx_leave(&ddb_mp_mutex); 125 for (i = 0; i < ncpus; i++) { 126 if (i != cpu_number() && 127 cpu_info[i].ci_ddb_paused != CI_DDB_STOPPED) { 128 cpu_info[i].ci_ddb_paused = CI_DDB_SHOULDSTOP; 129 ppc_send_ipi(&cpu_info[i], PPC_IPI_DDB); 130 } 131 } 132 /* ipi is slow. Try not to db_active++ too early. */ 133 delay(100); 134 return (1); 135 } 136 137 /* Leaving ddb completely. Start all other CPUs and return 0 */ 138 if (ddb_active_cpu == cpu_number() && ddb_state == DDB_STATE_EXITING) { 139 for (i = 0; i < ncpus; i++) { 140 cpu_info[i].ci_ddb_paused = CI_DDB_RUNNING; 141 } 142 db_mtx_leave(&ddb_mp_mutex); 143 return (0); 144 } 145 146 /* We are switching to another CPU. ddb_ddbproc_cmd() has made sure 147 * it is waiting for ddb, we just have to set ddb_active_cpu. */ 148 if (ddb_active_cpu == cpu_number() && db_switch_cpu) { 149 ci->ci_ddb_paused = CI_DDB_SHOULDSTOP; 150 db_switch_cpu = 0; 151 ddb_active_cpu = db_switch_to_cpu; 152 cpu_info[db_switch_to_cpu].ci_ddb_paused = CI_DDB_ENTERDDB; 153 } 154 155 /* Wait until we should enter ddb or resume */ 156 while (ddb_active_cpu != cpu_number() && 157 ci->ci_ddb_paused != CI_DDB_RUNNING) { 158 if (ci->ci_ddb_paused == CI_DDB_SHOULDSTOP) 159 ci->ci_ddb_paused = CI_DDB_STOPPED; 160 db_mtx_leave(&ddb_mp_mutex); 161 162 /* Busy wait without locking, we will confirm with lock later */ 163 while (ddb_active_cpu != cpu_number() && 164 ci->ci_ddb_paused != CI_DDB_RUNNING) 165 ; /* Do nothing */ 166 167 db_mtx_enter(&ddb_mp_mutex); 168 } 169 170 /* Either enter ddb or exit */ 171 if (ddb_active_cpu == cpu_number() && ddb_state == DDB_STATE_RUNNING) { 172 ci->ci_ddb_paused = CI_DDB_INDDB; 173 db_mtx_leave(&ddb_mp_mutex); 174 return (1); 175 } else { 176 db_mtx_leave(&ddb_mp_mutex); 177 return (0); 178 } 179 #else 180 return (1); 181 #endif 182 } 183 184 #ifdef MULTIPROCESSOR 185 void 186 ppc_ipi_db(struct cpu_info *ci) 187 { 188 db_enter(); 189 } 190 191 void 192 db_cpuinfo_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 193 { 194 int i; 195 196 for (i = 0; i < ncpus; i++) { 197 db_printf("%c%4d: ", (i == cpu_number()) ? '*' : ' ', 198 cpu_info[i].ci_cpuid); 199 switch(cpu_info[i].ci_ddb_paused) { 200 case CI_DDB_RUNNING: 201 db_printf("running\n"); 202 break; 203 case CI_DDB_SHOULDSTOP: 204 db_printf("stopping\n"); 205 break; 206 case CI_DDB_STOPPED: 207 db_printf("stopped\n"); 208 break; 209 case CI_DDB_ENTERDDB: 210 db_printf("entering ddb\n"); 211 break; 212 case CI_DDB_INDDB: 213 db_printf("ddb\n"); 214 break; 215 default: 216 db_printf("? (%d)\n", 217 cpu_info[i].ci_ddb_paused); 218 break; 219 } 220 } 221 } 222 #endif 223 224 struct db_command db_machine_command_table[] = { 225 #ifdef MULTIPROCESSOR 226 { "cpuinfo", db_cpuinfo_cmd, 0, NULL }, 227 { "startcpu", db_startproc_cmd, 0, NULL }, 228 { "stopcpu", db_stopproc_cmd, 0, NULL }, 229 { "ddbcpu", db_ddbproc_cmd, 0, NULL }, 230 #endif 231 { (char *)NULL } 232 }; 233 234 void 235 db_machine_init(void) 236 { 237 #ifdef MULTIPROCESSOR 238 int i; 239 #endif 240 241 db_machine_commands_install(db_machine_command_table); 242 #ifdef MULTIPROCESSOR 243 for (i = 0; i < ncpus; i++) { 244 cpu_info[i].ci_ddb_paused = CI_DDB_RUNNING; 245 } 246 #endif 247 } 248 249 #ifdef MULTIPROCESSOR 250 void 251 db_ddbproc_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 252 { 253 int cpu_n; 254 255 if (have_addr) { 256 cpu_n = addr; 257 if (cpu_n >= 0 && cpu_n < ncpus && 258 cpu_n != cpu_number()) { 259 db_switch_to_cpu = cpu_n; 260 db_switch_cpu = 1; 261 db_cmd_loop_done = 1; 262 } else { 263 db_printf("Invalid cpu %d\n", (int)addr); 264 } 265 } else { 266 db_printf("CPU not specified\n"); 267 } 268 } 269 270 void 271 db_startproc_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 272 { 273 int cpu_n; 274 275 if (have_addr) { 276 cpu_n = addr; 277 if (cpu_n >= 0 && cpu_n < ncpus && 278 cpu_n != cpu_number()) 279 db_startcpu(cpu_n); 280 else 281 db_printf("Invalid cpu %d\n", (int)addr); 282 } else { 283 for (cpu_n = 0; cpu_n < ncpus; cpu_n++) { 284 if (cpu_n != cpu_number()) { 285 db_startcpu(cpu_n); 286 } 287 } 288 } 289 } 290 291 void 292 db_stopproc_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 293 { 294 int cpu_n; 295 296 if (have_addr) { 297 cpu_n = addr; 298 if (cpu_n >= 0 && cpu_n < ncpus && 299 cpu_n != cpu_number()) 300 db_stopcpu(cpu_n); 301 else 302 db_printf("Invalid cpu %d\n", (int)addr); 303 } else { 304 for (cpu_n = 0; cpu_n < ncpus; cpu_n++) { 305 if (cpu_n != cpu_number()) { 306 db_stopcpu(cpu_n); 307 } 308 } 309 } 310 } 311 312 void 313 db_startcpu(int cpu) 314 { 315 if (cpu != cpu_number() && cpu < ncpus) { 316 db_mtx_enter(&ddb_mp_mutex); 317 cpu_info[cpu].ci_ddb_paused = CI_DDB_RUNNING; 318 db_mtx_leave(&ddb_mp_mutex); 319 } 320 } 321 322 void 323 db_stopcpu(int cpu) 324 { 325 db_mtx_enter(&ddb_mp_mutex); 326 if (cpu != cpu_number() && cpu < ncpus && 327 cpu_info[cpu].ci_ddb_paused != CI_DDB_STOPPED) { 328 cpu_info[cpu].ci_ddb_paused = CI_DDB_SHOULDSTOP; 329 db_mtx_leave(&ddb_mp_mutex); 330 ppc_send_ipi(&cpu_info[cpu], PPC_IPI_DDB); 331 } else { 332 db_mtx_leave(&ddb_mp_mutex); 333 } 334 } 335 #endif 336