1 /* $OpenBSD: db_interface.c,v 1.10 2022/04/14 19:47:11 naddy 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 const 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 240 for (i = 0; i < ncpus; i++) { 241 cpu_info[i].ci_ddb_paused = CI_DDB_RUNNING; 242 } 243 #endif 244 } 245 246 #ifdef MULTIPROCESSOR 247 void 248 db_ddbproc_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 249 { 250 int cpu_n; 251 252 if (have_addr) { 253 cpu_n = addr; 254 if (cpu_n >= 0 && cpu_n < ncpus && 255 cpu_n != cpu_number()) { 256 db_switch_to_cpu = cpu_n; 257 db_switch_cpu = 1; 258 db_cmd_loop_done = 1; 259 } else { 260 db_printf("Invalid cpu %d\n", (int)addr); 261 } 262 } else { 263 db_printf("CPU not specified\n"); 264 } 265 } 266 267 void 268 db_startproc_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 269 { 270 int cpu_n; 271 272 if (have_addr) { 273 cpu_n = addr; 274 if (cpu_n >= 0 && cpu_n < ncpus && 275 cpu_n != cpu_number()) 276 db_startcpu(cpu_n); 277 else 278 db_printf("Invalid cpu %d\n", (int)addr); 279 } else { 280 for (cpu_n = 0; cpu_n < ncpus; cpu_n++) { 281 if (cpu_n != cpu_number()) { 282 db_startcpu(cpu_n); 283 } 284 } 285 } 286 } 287 288 void 289 db_stopproc_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) 290 { 291 int cpu_n; 292 293 if (have_addr) { 294 cpu_n = addr; 295 if (cpu_n >= 0 && cpu_n < ncpus && 296 cpu_n != cpu_number()) 297 db_stopcpu(cpu_n); 298 else 299 db_printf("Invalid cpu %d\n", (int)addr); 300 } else { 301 for (cpu_n = 0; cpu_n < ncpus; cpu_n++) { 302 if (cpu_n != cpu_number()) { 303 db_stopcpu(cpu_n); 304 } 305 } 306 } 307 } 308 309 void 310 db_startcpu(int cpu) 311 { 312 if (cpu != cpu_number() && cpu < ncpus) { 313 db_mtx_enter(&ddb_mp_mutex); 314 cpu_info[cpu].ci_ddb_paused = CI_DDB_RUNNING; 315 db_mtx_leave(&ddb_mp_mutex); 316 } 317 } 318 319 void 320 db_stopcpu(int cpu) 321 { 322 db_mtx_enter(&ddb_mp_mutex); 323 if (cpu != cpu_number() && cpu < ncpus && 324 cpu_info[cpu].ci_ddb_paused != CI_DDB_STOPPED) { 325 cpu_info[cpu].ci_ddb_paused = CI_DDB_SHOULDSTOP; 326 db_mtx_leave(&ddb_mp_mutex); 327 ppc_send_ipi(&cpu_info[cpu], PPC_IPI_DDB); 328 } else { 329 db_mtx_leave(&ddb_mp_mutex); 330 } 331 } 332 #endif 333