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