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
db_enter()66 db_enter()
67 {
68 ddb_trap();
69 }
70
71 int
db_trap_glue(struct trapframe * frame)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
db_enter_ddb(void)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
ppc_ipi_db(struct cpu_info * ci)186 ppc_ipi_db(struct cpu_info *ci)
187 {
188 db_enter();
189 }
190
191 void
db_cpuinfo_cmd(db_expr_t addr,int have_addr,db_expr_t count,char * modif)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
db_machine_init(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
db_ddbproc_cmd(db_expr_t addr,int have_addr,db_expr_t count,char * modif)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
db_startproc_cmd(db_expr_t addr,int have_addr,db_expr_t count,char * modif)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
db_stopproc_cmd(db_expr_t addr,int have_addr,db_expr_t count,char * modif)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
db_startcpu(int cpu)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
db_stopcpu(int cpu)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