xref: /netbsd-src/sys/arch/powerpc/powerpc/db_interface.c (revision 6445c35a21a782cbd45a9beb089a2371aed3e8c1)
1 /*	$NetBSD: db_interface.c,v 1.61 2024/09/08 10:09:48 andvar Exp $ */
2 /*	$OpenBSD: db_interface.c,v 1.2 1996/12/28 06:21:50 rahnds Exp $	*/
3 
4 #include <sys/cdefs.h>
5 __KERNEL_RCSID(0, "$NetBSD: db_interface.c,v 1.61 2024/09/08 10:09:48 andvar Exp $");
6 
7 #define USERACC
8 
9 #ifdef _KERNEL_OPT
10 #include "opt_ddb.h"
11 #include "opt_kgdb.h"
12 #include "opt_multiprocessor.h"
13 #include "opt_ppcarch.h"
14 #endif
15 
16 #include <sys/param.h>
17 #include <sys/proc.h>
18 #include <sys/systm.h>
19 #include <sys/cpu.h>
20 #include <sys/atomic.h>
21 
22 #include <dev/cons.h>
23 
24 #include <powerpc/db_machdep.h>
25 #include <powerpc/frame.h>
26 #include <powerpc/spr.h>
27 #include <powerpc/pte.h>
28 #include <powerpc/psl.h>
29 
30 #if defined (PPC_OEA) || defined(PPC_OEA64) || defined (PPC_OEA64_BRIDGE)
31 #include <powerpc/oea/spr.h>
32 #include <powerpc/oea/bat.h>
33 #include <powerpc/oea/cpufeat.h>
34 #endif
35 
36 #ifdef PPC_IBM4XX
37 #include <powerpc/ibm4xx/cpu.h>
38 #include <powerpc/ibm4xx/spr.h>
39 #include <powerpc/ibm4xx/tlb.h>
40 #include <uvm/uvm_extern.h>
41 #endif
42 
43 #ifdef PPC_BOOKE
44 #include <powerpc/booke/cpuvar.h>
45 #include <powerpc/booke/spr.h>
46 #endif
47 
48 #ifdef DDB
49 #include <ddb/db_active.h>
50 #include <ddb/db_sym.h>
51 #include <ddb/db_command.h>
52 #include <ddb/db_extern.h>
53 #include <ddb/db_access.h>
54 #include <ddb/db_lex.h>
55 #include <ddb/db_output.h>
56 #include <ddb/db_run.h>	/* for db_continue_cmd() proto */
57 #include <ddb/ddbvar.h>
58 #endif
59 
60 #ifdef KGDB
61 #include <sys/kgdb.h>
62 #define db_printf printf
63 #endif
64 
65 #include <dev/ofw/openfirm.h>
66 
67 #define NOCPU   ~0
68 volatile u_int ddb_cpu = NOCPU;
69 
70 int	db_active = 0;
71 
72 db_regs_t ddb_regs;
73 
74 void ddb_trap(void);				/* Call into trap_subr.S */
75 int ddb_trap_glue(struct trapframe *);		/* Called from trap_subr.S */
76 #ifdef DDB
77 #if defined (PPC_OEA) || defined(PPC_OEA64) || defined (PPC_OEA64_BRIDGE)
78 static void db_show_bat(db_expr_t, bool, db_expr_t, const char *);
79 static void db_show_mmu(db_expr_t, bool, db_expr_t, const char *);
80 #endif /* PPC_OEA || PPC_OEA64 || PPC_OEA64_BRIDGE */
81 #ifdef PPC_IBM4XX
82 static void db_ppc4xx_ctx(db_expr_t, bool, db_expr_t, const char *);
83 static void db_ppc4xx_pv(db_expr_t, bool, db_expr_t, const char *);
84 static void db_ppc4xx_reset(db_expr_t, bool, db_expr_t, const char *);
85 static void db_ppc4xx_tf(db_expr_t, bool, db_expr_t, const char *);
86 static void db_ppc4xx_dumptlb(db_expr_t, bool, db_expr_t, const char *);
87 static void db_ppc4xx_dcr(db_expr_t, bool, db_expr_t, const char *);
88 static db_expr_t db_ppc4xx_mfdcr(db_expr_t);
89 static void db_ppc4xx_mtdcr(db_expr_t, db_expr_t);
90 #ifdef USERACC
91 static void db_ppc4xx_useracc(db_expr_t, bool, db_expr_t, const char *);
92 #endif
93 #endif /* PPC_IBM4XX */
94 
95 #ifdef PPC_BOOKE
96 static void db_ppcbooke_reset(db_expr_t, bool, db_expr_t, const char *);
97 static void db_ppcbooke_splhist(db_expr_t, bool, db_expr_t, const char *);
98 static void db_ppcbooke_tf(db_expr_t, bool, db_expr_t, const char *);
99 static void db_ppcbooke_dumptlb(db_expr_t, bool, db_expr_t, const char *);
100 #endif
101 
102 #ifdef MULTIPROCESSOR
103 static void db_mach_cpu(db_expr_t, bool, db_expr_t, const char *);
104 #endif	/* MULTIPROCESSOR */
105 
106 const struct db_command db_machine_command_table[] = {
107 #if defined (PPC_OEA) || defined(PPC_OEA64) || defined (PPC_OEA64_BRIDGE)
108 	{ DDB_ADD_CMD("bat",	db_show_bat,		0,
109 	  "Print BAT register translations", NULL,NULL) },
110 	{ DDB_ADD_CMD("mmu",	db_show_mmu,		0,
111 	  "Print MMU registers", NULL,NULL) },
112 #endif /* PPC_OEA || PPC_OEA64 || PPC_OEA64_BRIDGE */
113 #ifdef PPC_IBM4XX
114 	{ DDB_ADD_CMD("ctx",	db_ppc4xx_ctx,		0,
115 	  "Print process MMU context information", NULL,NULL) },
116 	{ DDB_ADD_CMD("pv",	db_ppc4xx_pv,		0,
117 	  "Print PA->VA mapping information",
118 	  "address",
119 	  "   address:\tphysical address to look up") },
120 	{ DDB_ADD_CMD("reset",	db_ppc4xx_reset,	0,
121 	  "Reset the system ", NULL,NULL) },
122 	{ DDB_ADD_CMD("tf",	db_ppc4xx_tf,		0,
123 	  "Display the contents of the trapframe",
124 	  "address",
125 	  "   address:\tthe struct trapframe to print") },
126 	{ DDB_ADD_CMD("tlb",	db_ppc4xx_dumptlb,	0,
127 	  "Display instruction translation storage buffer information.",
128 	  NULL,NULL) },
129 	{ DDB_ADD_CMD("dcr",	db_ppc4xx_dcr,		CS_MORE|CS_SET_DOT,
130 	  "Set the DCR register",
131 	  "dcr",
132 	  "   dcr:\tNew DCR value (between 0x0 and 0x3ff)") },
133 #ifdef USERACC
134 	{ DDB_ADD_CMD("user",	db_ppc4xx_useracc,	0,
135 	   "Display user memory.", "[address][,count]",
136 	   "   address:\tuserspace address to start\n"
137 	   "   count:\tnumber of bytes to display") },
138 #endif
139 #endif /* PPC_IBM4XX */
140 #ifdef PPC_BOOKE
141 	{ DDB_ADD_CMD("reset",	db_ppcbooke_reset,	0,
142 	  "Reset the system ", NULL,NULL) },
143 	{ DDB_ADD_CMD("tf",	db_ppcbooke_tf,		0,
144 	  "Display the contents of the trapframe",
145 	  "address",
146 	  "   address:\tthe struct trapframe to print") },
147 	{ DDB_ADD_CMD("splhist", db_ppcbooke_splhist,	0,
148 	  "Display the splraise/splx splx",
149 	  NULL, NULL) },
150 	{ DDB_ADD_CMD("tlb",	db_ppcbooke_dumptlb,	0,
151 	  "Display instruction translation storage buffer information.",
152 	  NULL,NULL) },
153 #endif /* PPC_BOOKE */
154 
155 #ifdef MULTIPROCESSOR
156 	{ DDB_ADD_CMD("cpu",	db_mach_cpu,	0,
157 	  "switch to another cpu", "cpu-no", NULL) },
158 #endif	/* MULTIPROCESSOR */
159 
160 	{ DDB_END_CMD },
161 };
162 
163 void
164 cpu_Debugger(void)
165 {
166 #ifdef PPC_BOOKE
167 	const register_t msr = mfmsr();
168 	__asm volatile("wrteei 0\n\ttweq\t1,1");
169 	mtmsr(msr);
170 	__asm volatile("isync");
171 #else
172 	ddb_trap();
173 #endif
174 }
175 #endif /* DDB */
176 
177 int
178 ddb_trap_glue(struct trapframe *tf)
179 {
180 #if defined(PPC_IBM4XX) || defined(PPC_BOOKE)
181 	if ((tf->tf_srr1 & PSL_PR) == 0)
182 		return kdb_trap(tf->tf_exc, tf);
183 #else /* PPC_OEA */
184 	if ((tf->tf_srr1 & PSL_PR) == 0 &&
185 	    (tf->tf_exc == EXC_TRC ||
186 	     tf->tf_exc == EXC_RUNMODETRC ||
187 	     (tf->tf_exc == EXC_PGM && (tf->tf_srr1 & 0x20000)) ||
188 	     tf->tf_exc == EXC_BPT ||
189 	     tf->tf_exc == EXC_DSI)) {
190 		int type = tf->tf_exc;
191 		if (type == EXC_PGM && (tf->tf_srr1 & 0x20000)) {
192 			type = T_BREAKPOINT;
193 		}
194 		return kdb_trap(type, tf);
195 	}
196 #endif
197 	return 0;
198 }
199 
200 int
201 kdb_trap(int type, void *v)
202 {
203 	struct trapframe *tf = v;
204 	int rv = 1;
205 	int s;
206 
207 #ifdef DDB
208 	if (db_recover != 0 && (type != -1 && type != T_BREAKPOINT)) {
209 		db_error("Faulted in DDB; continuing...\n");
210 		/* NOTREACHED */
211 	}
212 #endif
213 
214 	/* XXX Should switch to kdb's own stack here. */
215 
216 #ifdef MULTIPROCESSOR
217 	bool first_in_ddb = false;
218 	const u_int cpu_me = cpu_number();
219 	const u_int old_ddb_cpu = atomic_cas_uint(&ddb_cpu, NOCPU, cpu_me);
220 	if (old_ddb_cpu == NOCPU) {
221 		first_in_ddb = true;
222 		cpu_pause_others();
223 	} else {
224 		if (old_ddb_cpu != cpu_me) {
225 			KASSERT(cpu_is_paused(cpu_me));
226 			cpu_pause(tf);
227 			return 1;
228 		}
229 	}
230 	KASSERT(!cpu_is_paused(cpu_me));
231 #endif	/* MULTIPROCESSOR */
232 
233 	s = splhigh();
234 	memcpy(DDB_REGS->r, tf->tf_fixreg, 32 * sizeof(u_int32_t));
235 	DDB_REGS->iar = tf->tf_srr0;
236 	DDB_REGS->msr = tf->tf_srr1;
237 	DDB_REGS->lr = tf->tf_lr;
238 	DDB_REGS->ctr = tf->tf_ctr;
239 	DDB_REGS->cr = tf->tf_cr;
240 	DDB_REGS->xer = tf->tf_xer;
241 #ifdef PPC_OEA
242 	DDB_REGS->mq = tf->tf_mq;
243 #elif defined(PPC_IBM4XX) || defined(PPC_BOOKE)
244 	DDB_REGS->dear = tf->tf_dear;
245 	DDB_REGS->esr = tf->tf_esr;
246 	DDB_REGS->pid = tf->tf_pid;
247 #endif
248 
249 #ifdef DDB
250 	db_active++;
251 	cnpollc(1);
252 	db_trap(type, 0);
253 	cnpollc(0);
254 	db_active--;
255 #endif
256 #ifdef KGDB
257 	if (!kgdb_trap(type, DDB_REGS)) {
258 		rv = 0;
259 		goto out;
260 	}
261 #endif
262 
263 	/* KGDB isn't smart about advancing PC if we
264 	 * take a breakpoint trap after kgdb_active is set.
265 	 * Therefore, we help out here.
266 	 */
267 	if (IS_BREAKPOINT_TRAP(type, 0)) {
268 		int bkpt;
269 		db_read_bytes(PC_REGS(DDB_REGS),BKPT_SIZE,(void *)&bkpt);
270 		if (bkpt== BKPT_INST) {
271 			PC_REGS(DDB_REGS) += BKPT_SIZE;
272 		}
273 	}
274 
275 	memcpy(tf->tf_fixreg, DDB_REGS->r, 32 * sizeof(u_int32_t));
276 	tf->tf_srr0 = DDB_REGS->iar;
277 	tf->tf_srr1 = DDB_REGS->msr;
278 	tf->tf_lr = DDB_REGS->lr;
279 	tf->tf_ctr = DDB_REGS->ctr;
280 	tf->tf_cr = DDB_REGS->cr;
281 	tf->tf_xer = DDB_REGS->xer;
282 #ifdef PPC_OEA
283 	tf->tf_mq = DDB_REGS->mq;
284 #endif
285 #if defined(PPC_IBM4XX) || defined(PPC_BOOKE)
286 	tf->tf_dear = DDB_REGS->dear;
287 	tf->tf_esr = DDB_REGS->esr;
288 	tf->tf_pid = DDB_REGS->pid;
289 #endif
290 #ifdef KGDB
291  out:
292 #endif	/* KGDB */
293 	splx(s);
294 
295 #ifdef MULTIPROCESSOR
296 	if (atomic_cas_uint(&ddb_cpu, cpu_me, NOCPU) == cpu_me) {
297 		cpu_resume_others();
298 	} else {
299 		cpu_resume(ddb_cpu);
300 		if (first_in_ddb)
301 			cpu_pause(tf);
302 	}
303 #endif	/* MULTIPROCESSOR */
304 
305 	return rv;
306 }
307 
308 #ifdef DDB
309 #if defined (PPC_OEA) || defined(PPC_OEA64) || defined (PPC_OEA64_BRIDGE)
310 static void
311 print_battranslation(struct bat *bat, unsigned int blidx)
312 {
313 	static const char batsizes[][6] = {
314 		"128KB",
315 		"256KB",
316 		"512KB",
317 		"1MB",
318 		"2MB",
319 		"4MB",
320 		"8MB",
321 		"16MB",
322 		"32MB",
323 		"64MB",
324 		"128MB",
325 		"256MB",
326 		"512MB",
327 		"1GB",
328 		"2GB",
329 		"4GB",
330 	};
331 	vsize_t len;
332 
333 	len = (0x20000L << blidx) - 1;
334 	db_printf("\t%08lx %08lx %5s: 0x%08lx..0x%08lx -> 0x%08lx physical\n",
335 	    bat->batu, bat->batl, batsizes[blidx], bat->batu & ~len,
336 	    (bat->batu & ~len) + len, bat->batl & ~len);
337 }
338 
339 static void
340 print_batmodes(register_t super, register_t user, register_t pp)
341 {
342 	static const char *const accessmodes[] = {
343 		"none",
344 		"ro soft",
345 		"read/write",
346 		"read only"
347 	};
348 
349 	db_printf("\tvalid: %c%c  access: %-10s  memory:",
350 	    super ? 'S' : '-', user ? 'U' : '-', accessmodes[pp]);
351 }
352 
353 static void
354 print_wimg(register_t wimg)
355 {
356 	if (wimg & BAT_W)
357 		db_printf(" wrthrough");
358 	if (wimg & BAT_I)
359 		db_printf(" nocache");
360 	if (wimg & BAT_M)
361 		db_printf(" coherent");
362 	if (wimg & BAT_G)
363 		db_printf(" guard");
364 }
365 
366 static void
367 print_bat(struct bat *bat)
368 {
369 	if ((bat->batu & BAT_V) == 0) {
370 		db_printf("\tdisabled\n\n");
371 		return;
372 	}
373 	print_battranslation(bat,
374 	    30 - __builtin_clz((bat->batu & (BAT_XBL|BAT_BL))|2));
375 	print_batmodes(bat->batu & BAT_Vs, bat->batu & BAT_Vu,
376 	    bat->batl & BAT_PP);
377 	print_wimg(bat->batl & BAT_WIMG);
378 	db_printf("\n");
379 }
380 
381 #ifdef PPC_OEA601
382 static void
383 print_bat601(struct bat *bat)
384 {
385 	if ((bat->batl & BAT601_V) == 0) {
386 		db_printf("\tdisabled\n\n");
387 		return;
388 	}
389 	print_battranslation(bat, 32 - __builtin_clz(bat->batl & BAT601_BSM));
390 	print_batmodes(bat->batu & BAT601_Ks, bat->batu & BAT601_Ku,
391 	    bat->batu & BAT601_PP);
392 	print_wimg(bat->batu & (BAT601_W | BAT601_I | BAT601_M));
393 	db_printf("\n");
394 }
395 #endif
396 
397 static void
398 db_show_bat(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif)
399 {
400 	struct bat ibat[8];
401 	struct bat dbat[8];
402 	unsigned int cpuvers;
403 	u_int i;
404 	u_int maxbat = (oeacpufeat & OEACPU_HIGHBAT) ? 8 : 4;
405 
406 	if (oeacpufeat & OEACPU_NOBAT)
407 		return;
408 
409 	cpuvers = mfpvr() >> 16;
410 
411 	ibat[0].batu = mfspr(SPR_IBAT0U);
412 	ibat[0].batl = mfspr(SPR_IBAT0L);
413 	ibat[1].batu = mfspr(SPR_IBAT1U);
414 	ibat[1].batl = mfspr(SPR_IBAT1L);
415 	ibat[2].batu = mfspr(SPR_IBAT2U);
416 	ibat[2].batl = mfspr(SPR_IBAT2L);
417 	ibat[3].batu = mfspr(SPR_IBAT3U);
418 	ibat[3].batl = mfspr(SPR_IBAT3L);
419 	if (maxbat == 8) {
420 		ibat[4].batu = mfspr(SPR_IBAT4U);
421 		ibat[4].batl = mfspr(SPR_IBAT4L);
422 		ibat[5].batu = mfspr(SPR_IBAT5U);
423 		ibat[5].batl = mfspr(SPR_IBAT5L);
424 		ibat[6].batu = mfspr(SPR_IBAT6U);
425 		ibat[6].batl = mfspr(SPR_IBAT6L);
426 		ibat[7].batu = mfspr(SPR_IBAT7U);
427 		ibat[7].batl = mfspr(SPR_IBAT7L);
428 	}
429 
430 	if (cpuvers != MPC601) {
431 		/* The 601 has only four unified BATs */
432 		dbat[0].batu = mfspr(SPR_DBAT0U);
433 		dbat[0].batl = mfspr(SPR_DBAT0L);
434 		dbat[1].batu = mfspr(SPR_DBAT1U);
435 		dbat[1].batl = mfspr(SPR_DBAT1L);
436 		dbat[2].batu = mfspr(SPR_DBAT2U);
437 		dbat[2].batl = mfspr(SPR_DBAT2L);
438 		dbat[3].batu = mfspr(SPR_DBAT3U);
439 		dbat[3].batl = mfspr(SPR_DBAT3L);
440 		if (maxbat == 8) {
441 			dbat[4].batu = mfspr(SPR_DBAT4U);
442 			dbat[4].batl = mfspr(SPR_DBAT4L);
443 			dbat[5].batu = mfspr(SPR_DBAT5U);
444 			dbat[5].batl = mfspr(SPR_DBAT5L);
445 			dbat[6].batu = mfspr(SPR_DBAT6U);
446 			dbat[6].batl = mfspr(SPR_DBAT6L);
447 			dbat[7].batu = mfspr(SPR_DBAT7U);
448 			dbat[7].batl = mfspr(SPR_DBAT7L);
449 		}
450 	}
451 
452 	for (i = 0; i < maxbat; i++) {
453 #ifdef PPC_OEA601
454 		if (cpuvers == MPC601) {
455 			db_printf("bat[%u]:\n", i);
456 			print_bat601(&ibat[i]);
457 		} else
458 #endif
459 		{
460 			db_printf("ibat[%u]:\n", i);
461 			print_bat(&ibat[i]);
462 			db_printf("dbat[%u]:\n", i);
463 			print_bat(&dbat[i]);
464 		}
465 	}
466 }
467 
468 static void
469 db_show_mmu(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif)
470 {
471 	paddr_t sdr1;
472 
473 	__asm volatile ("mfsdr1 %0" : "=r"(sdr1));
474 	db_printf("sdr1\t\t0x%08lx\n", sdr1);
475 
476 #if defined(PPC_OEA64) || defined(PPC_OEA64_BRIDGE)
477 	if (oeacpufeat & (OEACPU_64|OEACPU_64_BRIDGE)) {
478 		__asm volatile ("mfasr %0" : "=r"(sdr1));
479 		db_printf("asr\t\t0x%08lx\n", sdr1);
480 	}
481 #endif
482 #if defined(PPC_OEA) || defined(PPC_OEA64_BRIDGE)
483 	if ((oeacpufeat & OEACPU_64) == 0) {
484 		vaddr_t saddr = 0;
485 		for (u_int i = 0; i <= 0xf; i++) {
486 			register_t sr;
487 			if ((i & 3) == 0)
488 				db_printf("sr%d-%d\t\t", i, i+3);
489 			__asm volatile ("mfsrin %0,%1" : "=r"(sr) : "r"(saddr));
490 			db_printf("0x%08lx   %c", sr, (i&3) == 3 ? '\n' : ' ');
491 			saddr += 1 << ADDR_SR_SHFT;
492 		}
493 	}
494 #endif
495 }
496 #endif /* PPC_OEA || PPC_OEA64 || PPC_OEA64_BRIDGE */
497 #endif /* DDB */
498 
499 #if defined(PPC_IBM4XX) || defined(PPC_BOOKE)
500 db_addr_t
501 branch_taken(int inst, db_addr_t pc, db_regs_t *regs)
502 {
503 
504 	if ((inst & M_B ) == I_B || (inst & M_B ) == I_BL) {
505 		db_expr_t off;
506 		off = ((db_expr_t)((inst & 0x03fffffc) << 6)) >> 6;
507 		return (((inst & 0x2) ? 0 : pc) + off);
508 	}
509 
510 	if ((inst & M_BC) == I_BC || (inst & M_BC) == I_BCL) {
511 		db_expr_t off;
512 		off = ((db_expr_t)((inst & 0x0000fffc) << 16)) >> 16;
513 		return (((inst & 0x2) ? 0 : pc) + off);
514 	}
515 
516 	if ((inst & M_RTS) == I_RTS || (inst & M_RTS) == I_BLRL)
517 		return (regs->lr);
518 
519 	if ((inst & M_BCTR) == I_BCTR || (inst & M_BCTR) == I_BCTRL)
520 		return (regs->ctr);
521 
522 	db_printf("branch_taken: can't figure out branch target for 0x%x!\n",
523 	    inst);
524 	return (0);
525 }
526 #endif /* PPC_IBM4XX || PPC_BOOKE */
527 
528 #ifdef DDB
529 #ifdef PPC_IBM4XX
530 static void
531 db_ppc4xx_ctx(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif)
532 {
533 	struct proc *p;
534 
535 	/* XXX LOCKING XXX */
536 	for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) {
537 		if (p->p_stat) {
538 			db_printf("process %p:", p);
539 			db_printf("pid:%d pmap:%p ctx:%d %s\n",
540 				p->p_pid, p->p_vmspace->vm_map.pmap,
541 				p->p_vmspace->vm_map.pmap->pm_ctx,
542 				p->p_comm);
543 		}
544 	}
545 	return;
546 }
547 
548 static void
549 db_ppc4xx_pv(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif)
550 {
551 	struct pv_entry {
552 		struct pv_entry *pv_next;	/* Linked list of mappings */
553 		vaddr_t pv_va;			/* virtual address of mapping */
554 		struct pmap *pv_pm;
555 	};
556 	struct pv_entry *pa_to_pv(paddr_t);
557 	struct pv_entry *pv;
558 
559 	if (!have_addr) {
560 		db_printf("pv: <pa>\n");
561 		return;
562 	}
563 	pv = pa_to_pv(addr);
564 	db_printf("pv at %p\n", pv);
565 	while (pv && pv->pv_pm) {
566 		db_printf("next %p va %p pmap %p\n", pv->pv_next,
567 			(void *)pv->pv_va, pv->pv_pm);
568 		pv = pv->pv_next;
569 	}
570 }
571 
572 static void
573 db_ppc4xx_reset(db_expr_t addr, bool have_addr, db_expr_t count,
574     const char *modif)
575 {
576 	printf("Resetting...\n");
577 	ppc4xx_reset();
578 }
579 
580 static void
581 db_ppc4xx_tf(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif)
582 {
583 	struct trapframe *tf;
584 
585 
586 	if (have_addr) {
587 		tf = (struct trapframe *)addr;
588 
589 		db_printf("r0-r3:  \t%8.8lx %8.8lx %8.8lx %8.8lx\n",
590 			tf->tf_fixreg[0], tf->tf_fixreg[1],
591 			tf->tf_fixreg[2], tf->tf_fixreg[3]);
592 		db_printf("r4-r7:  \t%8.8lx %8.8lx %8.8lx %8.8lx\n",
593 			tf->tf_fixreg[4], tf->tf_fixreg[5],
594 			tf->tf_fixreg[6], tf->tf_fixreg[7]);
595 		db_printf("r8-r11: \t%8.8lx %8.8lx %8.8lx %8.8lx\n",
596 			tf->tf_fixreg[8], tf->tf_fixreg[9],
597 			tf->tf_fixreg[10], tf->tf_fixreg[11]);
598 		db_printf("r12-r15:\t%8.8lx %8.8lx %8.8lx %8.8lx\n",
599 			tf->tf_fixreg[12], tf->tf_fixreg[13],
600 			tf->tf_fixreg[14], tf->tf_fixreg[15]);
601 		db_printf("r16-r19:\t%8.8lx %8.8lx %8.8lx %8.8lx\n",
602 			tf->tf_fixreg[16], tf->tf_fixreg[17],
603 			tf->tf_fixreg[18], tf->tf_fixreg[19]);
604 		db_printf("r20-r23:\t%8.8lx %8.8lx %8.8lx %8.8lx\n",
605 			tf->tf_fixreg[20], tf->tf_fixreg[21],
606 			tf->tf_fixreg[22], tf->tf_fixreg[23]);
607 		db_printf("r24-r27:\t%8.8lx %8.8lx %8.8lx %8.8lx\n",
608 			tf->tf_fixreg[24], tf->tf_fixreg[25],
609 			tf->tf_fixreg[26], tf->tf_fixreg[27]);
610 		db_printf("r28-r31:\t%8.8lx %8.8lx %8.8lx %8.8lx\n",
611 			tf->tf_fixreg[28], tf->tf_fixreg[29],
612 			tf->tf_fixreg[30], tf->tf_fixreg[31]);
613 
614 		db_printf("lr: %8.8lx cr: %8.8x xer: %8.8x ctr: %8.8lx\n",
615 			tf->tf_lr, tf->tf_cr, tf->tf_xer, tf->tf_ctr);
616 		db_printf("srr0(pc): %8.8lx srr1(msr): %8.8lx "
617 			"dear: %8.8lx esr: %8.8x\n",
618 			tf->tf_srr0, tf->tf_srr1, tf->tf_dear, tf->tf_esr);
619 		db_printf("exc: %8.8x pid: %8.8x\n",
620 			tf->tf_exc, tf->tf_pid);
621 	}
622 	return;
623 }
624 
625 static const char *const tlbsizes[] = {
626 	  "1kB",
627 	  "4kB",
628 	 "16kB",
629 	 "64kB",
630 	"256kB",
631 	  "1MB",
632 	  "4MB",
633 	 "16MB"
634 };
635 
636 static void
637 db_ppc4xx_dumptlb(db_expr_t addr, bool have_addr, db_expr_t count,
638     const char *modif)
639 {
640 	int i, zone, tlbsize;
641 	u_int zpr, pid, opid, msr;
642 	u_long tlblo, tlbhi, tlbmask;
643 
644 	zpr = mfspr(SPR_ZPR);
645 	for (i = 0; i < NTLB; i++) {
646 		__asm volatile("mfmsr %3;"
647 			MFPID(%4)
648 			"li %0,0;"
649 			"mtmsr %0;"
650 			"sync; isync;"
651 			"tlbrelo %0,%5;"
652 			"tlbrehi %1,%5;"
653 			MFPID(%2)
654 			MTPID(%4)
655 			"mtmsr %3;"
656 			"sync; isync"
657 			: "=&r" (tlblo), "=&r" (tlbhi), "=r" (pid),
658 			"=&r" (msr), "=&r" (opid) : "r" (i));
659 
660 		if (strchr(modif, 'v') && !(tlbhi & TLB_VALID))
661 			continue;
662 
663 		tlbsize = (tlbhi & TLB_SIZE_MASK) >> TLB_SIZE_SHFT;
664 		/* map tlbsize 0 .. 7 to masks for 1kB .. 16MB */
665 		tlbmask = ~(1 << (tlbsize * 2 + 10)) + 1;
666 
667 		if (have_addr && ((tlbhi & tlbmask) != (addr & tlbmask)))
668 			continue;
669 
670 		zone = (tlblo & TLB_ZSEL_MASK) >> TLB_ZSEL_SHFT;
671 		db_printf("tlb%c%2d", tlbhi & TLB_VALID ? ' ' : '*', i);
672 		db_printf("  PID %3d EPN 0x%08lx %-5s",
673 		    pid,
674 		    tlbhi & tlbmask,
675 		    tlbsizes[tlbsize]);
676 		db_printf("  RPN 0x%08lx  ZONE %2d%c  %s %s %c%c%c%c%c %s",
677 		    tlblo & tlbmask,
678 		    zone,
679 		    "NTTA"[(zpr >> ((15 - zone) * 2)) & 3],
680 		    tlblo & TLB_EX ? "EX" : "  ",
681 		    tlblo & TLB_WR ? "WR" : "  ",
682 		    tlblo & TLB_W ? 'W' : ' ',
683 		    tlblo & TLB_I ? 'I' : ' ',
684 		    tlblo & TLB_M ? 'M' : ' ',
685 		    tlblo & TLB_G ? 'G' : ' ',
686 		    tlbhi & TLB_ENDIAN ? 'E' : ' ',
687 		    tlbhi & TLB_U0 ? "U0" : "  ");
688 		db_printf("\n");
689 	}
690 }
691 
692 static void
693 db_ppc4xx_dcr(db_expr_t address, bool have_addr, db_expr_t count,
694     const char *modif)
695 {
696 	db_expr_t new_value;
697 	db_expr_t addr;
698 
699 	if (address < 0 || address > 0x3ff)
700 		db_error("Invalid DCR address (Valid range is 0x0 - 0x3ff)\n");
701 
702 	addr = address;
703 
704 	while (db_expression(&new_value)) {
705 		db_printf("dcr 0x%lx\t\t%s = ", addr,
706 		    db_num_to_str(db_ppc4xx_mfdcr(addr)));
707 		db_ppc4xx_mtdcr(addr, new_value);
708 		db_printf("%s\n", db_num_to_str(db_ppc4xx_mfdcr(addr)));
709 		addr += 1;
710 	}
711 
712 	if (addr == address) {
713 		db_next = (db_addr_t)addr + 1;
714 		db_prev = (db_addr_t)addr;
715 		db_printf("dcr 0x%lx\t\t%s\n", addr,
716 		    db_num_to_str(db_ppc4xx_mfdcr(addr)));
717 	} else {
718 		db_next = (db_addr_t)addr;
719 		db_prev = (db_addr_t)addr - 1;
720 	}
721 
722 	db_skip_to_eol();
723 }
724 
725 /*
726  * XXX Grossness Alert! XXX
727  *
728  * Please look away now if you don't like self-modifying code
729  */
730 static u_int32_t db_ppc4xx_dcrfunc[4];
731 
732 static db_expr_t
733 db_ppc4xx_mfdcr(db_expr_t reg)
734 {
735 	db_expr_t (*func)(void);
736 
737 	reg = (((reg & 0x1f) << 5) | ((reg >> 5) & 0x1f)) << 11;
738 	db_ppc4xx_dcrfunc[0] = 0x7c0004ac;		/* sync */
739 	db_ppc4xx_dcrfunc[1] = 0x4c00012c;		/* isync */
740 	db_ppc4xx_dcrfunc[2] = 0x7c600286 | reg;	/* mfdcr reg, r3 */
741 	db_ppc4xx_dcrfunc[3] = 0x4e800020;		/* blr */
742 
743 	__syncicache((void *)db_ppc4xx_dcrfunc, sizeof(db_ppc4xx_dcrfunc));
744 	func = (db_expr_t (*)(void))(void *)db_ppc4xx_dcrfunc;
745 
746 	return ((*func)());
747 }
748 
749 static void
750 db_ppc4xx_mtdcr(db_expr_t reg, db_expr_t val)
751 {
752 	db_expr_t (*func)(db_expr_t);
753 
754 	reg = (((reg & 0x1f) << 5) | ((reg >> 5) & 0x1f)) << 11;
755 	db_ppc4xx_dcrfunc[0] = 0x7c0004ac;		/* sync */
756 	db_ppc4xx_dcrfunc[1] = 0x4c00012c;		/* isync */
757 	db_ppc4xx_dcrfunc[2] = 0x7c600386 | reg;	/* mtdcr r3, reg */
758 	db_ppc4xx_dcrfunc[3] = 0x4e800020;		/* blr */
759 
760 	__syncicache((void *)db_ppc4xx_dcrfunc, sizeof(db_ppc4xx_dcrfunc));
761 	func = (db_expr_t (*)(db_expr_t))(void *)db_ppc4xx_dcrfunc;
762 
763 	(*func)(val);
764 }
765 
766 #ifdef USERACC
767 static void
768 db_ppc4xx_useracc(db_expr_t addr, bool have_addr, db_expr_t count,
769     const char *modif)
770 {
771 	static paddr_t oldaddr = -1;
772 	int instr = 0;
773 	int data;
774 	extern vaddr_t opc_disasm(vaddr_t loc, int);
775 
776 
777 	if (!have_addr) {
778 		addr = oldaddr;
779 	}
780 	if (addr == -1) {
781 		db_printf("no address\n");
782 		return;
783 	}
784 	addr &= ~0x3; /* align */
785 	{
786 		const char *cp = modif;
787 		char c;
788 		while ((c = *cp++) != 0)
789 			if (c == 'i')
790 				instr = 1;
791 	}
792 	while (count--) {
793 		if (db_print_position() == 0) {
794 			/* Always print the address. */
795 			db_printf("%8.4lx:\t", addr);
796 		}
797 		oldaddr=addr;
798 		copyin((void *)addr, &data, sizeof(data));
799 		if (instr) {
800 			opc_disasm(addr, data);
801 		} else {
802 			db_printf("%4.4x\n", data);
803 		}
804 		addr += 4;
805 		db_end_line();
806 	}
807 
808 }
809 #endif
810 
811 #endif /* PPC_IBM4XX */
812 
813 #ifdef PPC_BOOKE
814 static void
815 db_ppcbooke_reset(db_expr_t addr, bool have_addr, db_expr_t count,
816     const char *modif)
817 {
818 	printf("Resetting...\n");
819 	(*cpu_md_ops.md_cpu_reset)();
820 }
821 
822 static void
823 db_ppcbooke_splhist(db_expr_t addr, bool have_addr, db_expr_t count,
824     const char *modif)
825 {
826 	dump_splhist(curcpu(), db_printf);
827 }
828 
829 static void
830 db_ppcbooke_tf(db_expr_t addr, bool have_addr, db_expr_t count,
831     const char *modif)
832 {
833 	if (!have_addr)
834 		return;
835 
836 	dump_trapframe((const struct trapframe *)addr, db_printf);
837 }
838 
839 static void
840 db_ppcbooke_dumptlb(db_expr_t addr, bool have_addr, db_expr_t count,
841     const char *modif)
842 {
843 	tlb_dump(db_printf);
844 }
845 #endif /* PPC_BOOKE */
846 
847 #ifdef MULTIPROCESSOR
848 bool
849 ddb_running_on_this_cpu_p(void)
850 {
851 
852 	return ddb_cpu == cpu_number();
853 }
854 
855 bool
856 ddb_running_on_any_cpu_p(void)
857 {
858 
859 	return ddb_cpu != NOCPU;
860 }
861 
862 void
863 db_resume_others(void)
864 {
865 	u_int cpu_me = cpu_number();
866 
867 	if (atomic_cas_uint(&ddb_cpu, cpu_me, NOCPU) == cpu_me)
868 		cpu_resume_others();
869 }
870 
871 static void
872 db_mach_cpu(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif)
873 {
874 	CPU_INFO_ITERATOR cii;
875 	struct cpu_info *ci;
876 	bool found = false;
877 
878 	if (!have_addr) {
879 		cpu_debug_dump();
880 		return;
881 	}
882 
883 	if (addr < 0) {
884 		db_printf("%ld: CPU out of range\n", addr);
885 		return;
886 	}
887 	for (CPU_INFO_FOREACH(cii, ci)) {
888 		if (cpu_index(ci) == addr) {
889 			found = true;
890 			break;
891 		}
892 	}
893 	if (!found) {
894 		db_printf("CPU %ld not configured\n", addr);
895 		return;
896 	}
897 	if (ci != curcpu()) {
898 		if (!cpu_is_paused(cpu_index(ci))) {
899 			db_printf("CPU %ld not paused\n", (long)addr);
900 			return;
901 		}
902 		(void)atomic_cas_uint(&ddb_cpu, cpu_number(), cpu_index(ci));
903 		db_continue_cmd(0, false, 0, "");
904 	}
905 }
906 #endif	/* MULTIPROCESSOR */
907 #endif /* DDB */
908