xref: /openbsd-src/sys/arch/powerpc/ddb/db_interface.c (revision c7e8ea31cd41a963f06f0a8ba93948b06aa6b4a4)
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