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