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