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