xref: /openbsd-src/sys/arch/powerpc64/powerpc64/db_interface.c (revision 3fe80b7fb1a5bd0bd4a7a666724b5696fc175a21)
1 /*	$OpenBSD: db_interface.c,v 1.6 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/systm.h>
34 #include <sys/mutex.h>
35 
36 #include <dev/cons.h>
37 #include <dev/ofw/fdt.h>
38 
39 #include <machine/db_machdep.h>
40 #include <ddb/db_command.h>
41 #include <ddb/db_elf.h>
42 #include <ddb/db_extern.h>
43 #include <ddb/db_output.h>
44 #include <ddb/db_run.h>
45 #include <ddb/db_sym.h>
46 
47 extern db_regs_t ddb_regs; /* db_trace.c */
48 extern db_symtab_t db_symtab; /* ddb/db_elf.c */
49 extern struct fdt_reg initrd_reg; /* machdep.c */
50 
51 #ifdef MULTIPROCESSOR
52 
53 struct db_mutex ddb_mp_mutex = DB_MUTEX_INITIALIZER;
54 volatile int ddb_state = DDB_STATE_NOT_RUNNING;
55 volatile cpuid_t ddb_active_cpu;
56 int	db_switch_cpu;
57 long	db_switch_to_cpu;
58 
59 void db_cpuinfo_cmd(db_expr_t, int, db_expr_t, char *);
60 void db_startproc_cmd(db_expr_t, int, db_expr_t, char *);
61 void db_stopproc_cmd(db_expr_t, int, db_expr_t, char *);
62 void db_ddbproc_cmd(db_expr_t, int, db_expr_t, char *);
63 
64 void db_stopcpu(int cpu);
65 void db_startcpu(int cpu);
66 int db_enter_ddb(void);
67 
68 #endif
69 
70 const struct db_command db_machine_command_table[] = {
71 #ifdef MULTIPROCESSOR
72 	{ "cpuinfo",    db_cpuinfo_cmd,         0,      NULL },
73 	{ "startcpu",   db_startproc_cmd,       0,      NULL },
74 	{ "stopcpu",    db_stopproc_cmd,        0,      NULL },
75 	{ "ddbcpu",     db_ddbproc_cmd,         0,      NULL },
76 #endif
77 	{ (char *)NULL }
78 };
79 
80 void
db_machine_init(void)81 db_machine_init(void)
82 {
83 	db_expr_t val;
84 	uint64_t a, b;
85 	char *prop_start, *prop_end;
86 	void *node;
87 #ifdef MULTIPROCESSOR
88 	int i;
89 #endif
90 
91 	/*
92 	 * petitboot loads the kernel without symbols.
93 	 * If an initrd exists, try to load symbols from there.
94 	 */
95 	node = fdt_find_node("/chosen");
96 	if (fdt_node_property(node, "linux,initrd-start", &prop_start) != 8 ||
97 	    fdt_node_property(node, "linux,initrd-end", &prop_end) != 8) {
98 		printf("[ no initrd ]\n");
99 		return;
100 	}
101 
102 	a = bemtoh64((uint64_t *)prop_start);
103 	b = bemtoh64((uint64_t *)prop_end);
104 	initrd_reg.addr = trunc_page(a);
105 	initrd_reg.size = round_page(b) - initrd_reg.addr;
106 	db_elf_sym_init(b - a, (char *)a, (char *)b, "initrd");
107 
108 	/* The kernel is PIE. Add an offset to most symbols. */
109 	if (db_symbol_by_name("db_machine_init", &val) != NULL) {
110 		Elf_Sym *symp, *symtab_start, *symtab_end;
111 		Elf_Addr offset;
112 
113 		symtab_start = STAB_TO_SYMSTART(&db_symtab);
114 		symtab_end = STAB_TO_SYMEND(&db_symtab);
115 
116 		offset = (Elf_Addr)db_machine_init - (Elf_Addr)val;
117 		for (symp = symtab_start; symp < symtab_end; symp++) {
118 			if (symp->st_shndx != SHN_ABS)
119 				symp->st_value += offset;
120 		}
121 	}
122 
123 #ifdef MULTIPROCESSOR
124 	for (i = 0; i < ncpus; i++) {
125 		cpu_info[i].ci_ddb_paused = CI_DDB_RUNNING;
126 	}
127 #endif
128 }
129 
130 void
db_ktrap(int type,db_regs_t * frame)131 db_ktrap(int type, db_regs_t *frame)
132 {
133 	int s;
134 
135 #ifdef MULTIPROCESSOR
136 	db_mtx_enter(&ddb_mp_mutex);
137 	if (ddb_state == DDB_STATE_EXITING)
138 		ddb_state = DDB_STATE_NOT_RUNNING;
139 	db_mtx_leave(&ddb_mp_mutex);
140 
141 	while (db_enter_ddb()) {
142 #endif
143 		ddb_regs = *frame;
144 
145 		s = splhigh();
146 		db_active++;
147 		cnpollc(1);
148 		db_trap(type, 0);
149 		cnpollc(0);
150 		db_active--;
151 		splx(s);
152 
153 		*frame = ddb_regs;
154 #ifdef MULTIPROCESSOR
155 		if (!db_switch_cpu)
156 			ddb_state = DDB_STATE_EXITING;
157 	}
158 #endif
159 }
160 
161 #ifdef MULTIPROCESSOR
162 
163 int
db_enter_ddb(void)164 db_enter_ddb(void)
165 {
166 	struct cpu_info *ci = curcpu();
167 	int i;
168 
169 	db_mtx_enter(&ddb_mp_mutex);
170 
171 	/* If we are first in, grab ddb and stop all other CPUs */
172 	if (ddb_state == DDB_STATE_NOT_RUNNING) {
173 		ddb_active_cpu = cpu_number();
174 		ddb_state = DDB_STATE_RUNNING;
175 		ci->ci_ddb_paused = CI_DDB_INDDB;
176 		db_mtx_leave(&ddb_mp_mutex);
177 		for (i = 0; i < ncpus; i++) {
178 			if (i != cpu_number() &&
179 			    cpu_info[i].ci_ddb_paused != CI_DDB_STOPPED) {
180 				cpu_info[i].ci_ddb_paused = CI_DDB_SHOULDSTOP;
181 				intr_send_ipi(&cpu_info[i], IPI_DDB);
182 			}
183 		}
184 		return (1);
185 	}
186 
187 	/* Leaving ddb completely.  Start all other CPUs and return 0 */
188 	if (ddb_active_cpu == cpu_number() && ddb_state == DDB_STATE_EXITING) {
189 		for (i = 0; i < ncpus; i++) {
190 			cpu_info[i].ci_ddb_paused = CI_DDB_RUNNING;
191 		}
192 		db_mtx_leave(&ddb_mp_mutex);
193 		return (0);
194 	}
195 
196 	/* We are switching to another CPU. ddb_ddbproc_cmd() has made sure
197 	 * it is waiting for ddb, we just have to set ddb_active_cpu. */
198 	if (ddb_active_cpu == cpu_number() && db_switch_cpu) {
199 		ci->ci_ddb_paused = CI_DDB_SHOULDSTOP;
200 		db_switch_cpu = 0;
201 		ddb_active_cpu = db_switch_to_cpu;
202 		cpu_info[db_switch_to_cpu].ci_ddb_paused = CI_DDB_ENTERDDB;
203 	}
204 
205 	/* Wait until we should enter ddb or resume */
206 	while (ddb_active_cpu != cpu_number() &&
207 	    ci->ci_ddb_paused != CI_DDB_RUNNING) {
208 		if (ci->ci_ddb_paused == CI_DDB_SHOULDSTOP)
209 			ci->ci_ddb_paused = CI_DDB_STOPPED;
210 		db_mtx_leave(&ddb_mp_mutex);
211 
212 		/* Busy wait without locking, we will confirm with lock later */
213 		while (ddb_active_cpu != cpu_number() &&
214 		    ci->ci_ddb_paused != CI_DDB_RUNNING)
215 			;	/* Do nothing */
216 
217 		db_mtx_enter(&ddb_mp_mutex);
218 	}
219 
220 	/* Either enter ddb or exit */
221 	if (ddb_active_cpu == cpu_number() && ddb_state == DDB_STATE_RUNNING) {
222 		ci->ci_ddb_paused = CI_DDB_INDDB;
223 		db_mtx_leave(&ddb_mp_mutex);
224 		return (1);
225 	} else {
226 		db_mtx_leave(&ddb_mp_mutex);
227 		return (0);
228 	}
229 }
230 
231 void
db_cpuinfo_cmd(db_expr_t addr,int have_addr,db_expr_t count,char * modif)232 db_cpuinfo_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
233 {
234 	int i;
235 
236 	for (i = 0; i < ncpus; i++) {
237 		db_printf("%c%4d: ", (i == cpu_number()) ? '*' : ' ',
238 		    cpu_info[i].ci_cpuid);
239 		switch(cpu_info[i].ci_ddb_paused) {
240 		case CI_DDB_RUNNING:
241 			db_printf("running\n");
242 			break;
243 		case CI_DDB_SHOULDSTOP:
244 			db_printf("stopping\n");
245 			break;
246 		case CI_DDB_STOPPED:
247 			db_printf("stopped\n");
248 			break;
249 		case CI_DDB_ENTERDDB:
250 			db_printf("entering ddb\n");
251 			break;
252 		case CI_DDB_INDDB:
253 			db_printf("ddb\n");
254 			break;
255 		default:
256 			db_printf("? (%d)\n",
257 			    cpu_info[i].ci_ddb_paused);
258 			break;
259 		}
260 	}
261 }
262 
263 void
db_ddbproc_cmd(db_expr_t addr,int have_addr,db_expr_t count,char * modif)264 db_ddbproc_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
265 {
266 	int cpu_n;
267 
268 	if (have_addr) {
269 		cpu_n = addr;
270 		if (cpu_n >= 0 && cpu_n < ncpus &&
271 		    cpu_n != cpu_number()) {
272 			db_switch_to_cpu = cpu_n;
273 			db_switch_cpu = 1;
274 			db_cmd_loop_done = 1;
275 		} else {
276 			db_printf("Invalid cpu %d\n", (int)addr);
277 		}
278 	} else {
279 		db_printf("CPU not specified\n");
280 	}
281 }
282 
283 void
db_startproc_cmd(db_expr_t addr,int have_addr,db_expr_t count,char * modif)284 db_startproc_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
285 {
286 	int cpu_n;
287 
288 	if (have_addr) {
289 		cpu_n = addr;
290 		if (cpu_n >= 0 && cpu_n < ncpus &&
291 		    cpu_n != cpu_number())
292 			db_startcpu(cpu_n);
293 		else
294 			db_printf("Invalid cpu %d\n", (int)addr);
295 	} else {
296 		for (cpu_n = 0; cpu_n < ncpus; cpu_n++) {
297 			if (cpu_n != cpu_number()) {
298 				db_startcpu(cpu_n);
299 			}
300 		}
301 	}
302 }
303 
304 void
db_stopproc_cmd(db_expr_t addr,int have_addr,db_expr_t count,char * modif)305 db_stopproc_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
306 {
307 	int cpu_n;
308 
309 	if (have_addr) {
310 		cpu_n = addr;
311 		if (cpu_n >= 0 && cpu_n < ncpus &&
312 		    cpu_n != cpu_number())
313 			db_stopcpu(cpu_n);
314 		else
315 			db_printf("Invalid cpu %d\n", (int)addr);
316 	} else {
317 		for (cpu_n = 0; cpu_n < ncpus; cpu_n++) {
318 			if (cpu_n != cpu_number()) {
319 				db_stopcpu(cpu_n);
320 			}
321 		}
322 	}
323 }
324 
325 void
db_startcpu(int cpu)326 db_startcpu(int cpu)
327 {
328 	if (cpu != cpu_number() && cpu < ncpus) {
329 		db_mtx_enter(&ddb_mp_mutex);
330 		cpu_info[cpu].ci_ddb_paused = CI_DDB_RUNNING;
331 		db_mtx_leave(&ddb_mp_mutex);
332 	}
333 }
334 
335 void
db_stopcpu(int cpu)336 db_stopcpu(int cpu)
337 {
338 	db_mtx_enter(&ddb_mp_mutex);
339 	if (cpu != cpu_number() && cpu < ncpus &&
340 	    cpu_info[cpu].ci_ddb_paused != CI_DDB_STOPPED) {
341 		cpu_info[cpu].ci_ddb_paused = CI_DDB_SHOULDSTOP;
342 		db_mtx_leave(&ddb_mp_mutex);
343 		intr_send_ipi(&cpu_info[cpu], IPI_DDB);
344 	} else {
345 		db_mtx_leave(&ddb_mp_mutex);
346 	}
347 }
348 
349 #endif
350