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