1 /* $OpenBSD: db_interface.c,v 1.7 2021/05/30 15:05:32 visa 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 bcopy(frame->fixreg, ddb_regs.fixreg, 90 32 * sizeof(u_int32_t)); 91 ddb_regs.srr0 = frame->srr0; 92 ddb_regs.srr1 = frame->srr1; 93 94 s = splhigh(); 95 db_active++; 96 cnpollc(1); 97 db_trap(T_BREAKPOINT, 0); 98 cnpollc(0); 99 db_active--; 100 splx(s); 101 102 bcopy(ddb_regs.fixreg, frame->fixreg, 103 32 * sizeof(u_int32_t)); 104 #ifdef MULTIPROCESSOR 105 if (!db_switch_cpu) 106 ddb_state = DDB_STATE_EXITING; 107 } 108 #endif 109 return 1; 110 } 111 return 0; 112 } 113 114 int 115 db_enter_ddb(void) 116 { 117 #ifdef MULTIPROCESSOR 118 int i; 119 struct cpu_info *ci = curcpu(); 120 121 db_mtx_enter(&ddb_mp_mutex); 122 123 /* If we are first in, grab ddb and stop all other CPUs */ 124 if (ddb_state == DDB_STATE_NOT_RUNNING) { 125 ddb_active_cpu = cpu_number(); 126 ddb_state = DDB_STATE_RUNNING; 127 ci->ci_ddb_paused = CI_DDB_INDDB; 128 db_mtx_leave(&ddb_mp_mutex); 129 for (i = 0; i < ncpus; i++) { 130 if (i != cpu_number() && 131 cpu_info[i].ci_ddb_paused != CI_DDB_STOPPED) { 132 cpu_info[i].ci_ddb_paused = CI_DDB_SHOULDSTOP; 133 ppc_send_ipi(&cpu_info[i], PPC_IPI_DDB); 134 } 135 } 136 return (1); 137 } 138 139 /* Leaving ddb completely. Start all other CPUs and return 0 */ 140 if (ddb_active_cpu == cpu_number() && ddb_state == DDB_STATE_EXITING) { 141 for (i = 0; i < ncpus; i++) { 142 cpu_info[i].ci_ddb_paused = CI_DDB_RUNNING; 143 } 144 db_mtx_leave(&ddb_mp_mutex); 145 return (0); 146 } 147 148 /* We are switching to another CPU. ddb_ddbproc_cmd() has made sure 149 * it is waiting for ddb, we just have to set ddb_active_cpu. */ 150 if (ddb_active_cpu == cpu_number() && db_switch_cpu) { 151 ci->ci_ddb_paused = CI_DDB_SHOULDSTOP; 152 db_switch_cpu = 0; 153 ddb_active_cpu = db_switch_to_cpu; 154 cpu_info[db_switch_to_cpu].ci_ddb_paused = CI_DDB_ENTERDDB; 155 } 156 157 /* Wait until we should enter ddb or resume */ 158 while (ddb_active_cpu != cpu_number() && 159 ci->ci_ddb_paused != CI_DDB_RUNNING) { 160 if (ci->ci_ddb_paused == CI_DDB_SHOULDSTOP) 161 ci->ci_ddb_paused = CI_DDB_STOPPED; 162 db_mtx_leave(&ddb_mp_mutex); 163 164 /* Busy wait without locking, we will confirm with lock later */ 165 while (ddb_active_cpu != cpu_number() && 166 ci->ci_ddb_paused != CI_DDB_RUNNING) 167 ; /* Do nothing */ 168 169 db_mtx_enter(&ddb_mp_mutex); 170 } 171 172 /* Either enter ddb or exit */ 173 if (ddb_active_cpu == cpu_number() && ddb_state == DDB_STATE_RUNNING) { 174 ci->ci_ddb_paused = CI_DDB_INDDB; 175 db_mtx_leave(&ddb_mp_mutex); 176 return (1); 177 } else { 178 db_mtx_leave(&ddb_mp_mutex); 179 return (0); 180 } 181 #else 182 return (1); 183 #endif 184 } 185 186 #ifdef MULTIPROCESSOR 187 void 188 ppc_ipi_db(struct cpu_info *ci) 189 { 190 db_enter(); 191 } 192 193 void 194 db_cpuinfo_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 195 { 196 int i; 197 198 for (i = 0; i < ncpus; i++) { 199 db_printf("%c%4d: ", (i == cpu_number()) ? '*' : ' ', 200 cpu_info[i].ci_cpuid); 201 switch(cpu_info[i].ci_ddb_paused) { 202 case CI_DDB_RUNNING: 203 db_printf("running\n"); 204 break; 205 case CI_DDB_SHOULDSTOP: 206 db_printf("stopping\n"); 207 break; 208 case CI_DDB_STOPPED: 209 db_printf("stopped\n"); 210 break; 211 case CI_DDB_ENTERDDB: 212 db_printf("entering ddb\n"); 213 break; 214 case CI_DDB_INDDB: 215 db_printf("ddb\n"); 216 break; 217 default: 218 db_printf("? (%d)\n", 219 cpu_info[i].ci_ddb_paused); 220 break; 221 } 222 } 223 } 224 #endif 225 226 struct db_command db_machine_command_table[] = { 227 #ifdef MULTIPROCESSOR 228 { "cpuinfo", db_cpuinfo_cmd, 0, NULL }, 229 { "startcpu", db_startproc_cmd, 0, NULL }, 230 { "stopcpu", db_stopproc_cmd, 0, NULL }, 231 { "ddbcpu", db_ddbproc_cmd, 0, NULL }, 232 #endif 233 { (char *)NULL } 234 }; 235 236 void 237 db_machine_init(void) 238 { 239 #ifdef MULTIPROCESSOR 240 int i; 241 #endif 242 243 db_machine_commands_install(db_machine_command_table); 244 #ifdef MULTIPROCESSOR 245 for (i = 0; i < ncpus; i++) { 246 cpu_info[i].ci_ddb_paused = CI_DDB_RUNNING; 247 } 248 #endif 249 } 250 251 #ifdef MULTIPROCESSOR 252 void 253 db_ddbproc_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 254 { 255 int cpu_n; 256 257 if (have_addr) { 258 cpu_n = addr; 259 if (cpu_n >= 0 && cpu_n < ncpus && 260 cpu_n != cpu_number()) { 261 db_switch_to_cpu = cpu_n; 262 db_switch_cpu = 1; 263 db_cmd_loop_done = 1; 264 } else { 265 db_printf("Invalid cpu %d\n", (int)addr); 266 } 267 } else { 268 db_printf("CPU not specified\n"); 269 } 270 } 271 272 void 273 db_startproc_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 274 { 275 int cpu_n; 276 277 if (have_addr) { 278 cpu_n = addr; 279 if (cpu_n >= 0 && cpu_n < ncpus && 280 cpu_n != cpu_number()) 281 db_startcpu(cpu_n); 282 else 283 db_printf("Invalid cpu %d\n", (int)addr); 284 } else { 285 for (cpu_n = 0; cpu_n < ncpus; cpu_n++) { 286 if (cpu_n != cpu_number()) { 287 db_startcpu(cpu_n); 288 } 289 } 290 } 291 } 292 293 void 294 db_stopproc_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 295 { 296 int cpu_n; 297 298 if (have_addr) { 299 cpu_n = addr; 300 if (cpu_n >= 0 && cpu_n < ncpus && 301 cpu_n != cpu_number()) 302 db_stopcpu(cpu_n); 303 else 304 db_printf("Invalid cpu %d\n", (int)addr); 305 } else { 306 for (cpu_n = 0; cpu_n < ncpus; cpu_n++) { 307 if (cpu_n != cpu_number()) { 308 db_stopcpu(cpu_n); 309 } 310 } 311 } 312 } 313 314 void 315 db_startcpu(int cpu) 316 { 317 if (cpu != cpu_number() && cpu < ncpus) { 318 db_mtx_enter(&ddb_mp_mutex); 319 cpu_info[cpu].ci_ddb_paused = CI_DDB_RUNNING; 320 db_mtx_leave(&ddb_mp_mutex); 321 } 322 } 323 324 void 325 db_stopcpu(int cpu) 326 { 327 db_mtx_enter(&ddb_mp_mutex); 328 if (cpu != cpu_number() && cpu < ncpus && 329 cpu_info[cpu].ci_ddb_paused != CI_DDB_STOPPED) { 330 cpu_info[cpu].ci_ddb_paused = CI_DDB_SHOULDSTOP; 331 db_mtx_leave(&ddb_mp_mutex); 332 ppc_send_ipi(&cpu_info[cpu], PPC_IPI_DDB); 333 } else { 334 db_mtx_leave(&ddb_mp_mutex); 335 } 336 } 337 #endif 338