Home | History | Annotate | Line # | Download | only in powerpc
db_interface.c revision 1.43.2.1
      1 /*	$NetBSD: db_interface.c,v 1.43.2.1 2010/04/30 14:39:45 uebayasi 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.43.2.1 2010/04/30 14:39:45 uebayasi Exp $");
      6 
      7 #define USERACC
      8 
      9 #include "opt_ddb.h"
     10 #include "opt_kgdb.h"
     11 #include "opt_ppcarch.h"
     12 
     13 #include <sys/param.h>
     14 #include <sys/proc.h>
     15 #include <sys/systm.h>
     16 
     17 #include <dev/cons.h>
     18 
     19 #include <machine/db_machdep.h>
     20 #include <machine/frame.h>
     21 #include <powerpc/spr.h>
     22 #include <powerpc/cpu.h>
     23 #include <powerpc/bat.h>
     24 #include <powerpc/pte.h>
     25 
     26 #if defined (PPC_OEA) || defined(PPC_OEA64) || defined (PPC_OEA64_BRIDGE)
     27 #include <powerpc/oea/spr.h>
     28 #endif
     29 
     30 #ifdef PPC_IBM4XX
     31 #include <powerpc/ibm4xx/spr.h>
     32 #include <machine/tlb.h>
     33 #include <uvm/uvm_extern.h>
     34 #endif
     35 
     36 #ifdef PPC_BOOKE
     37 #include <powerpc/booke/spr.h>
     38 #endif
     39 
     40 #ifdef DDB
     41 #include <ddb/db_sym.h>
     42 #include <ddb/db_command.h>
     43 #include <ddb/db_extern.h>
     44 #include <ddb/db_access.h>
     45 #include <ddb/db_lex.h>
     46 #include <ddb/db_output.h>
     47 #include <ddb/ddbvar.h>
     48 #endif
     49 
     50 #ifdef KGDB
     51 #include <sys/kgdb.h>
     52 #define db_printf printf
     53 #endif
     54 
     55 #include <dev/ofw/openfirm.h>
     56 
     57 int	db_active = 0;
     58 
     59 db_regs_t ddb_regs;
     60 
     61 void ddb_trap(void);				/* Call into trap_subr.S */
     62 int ddb_trap_glue(struct trapframe *);		/* Called from trap_subr.S */
     63 #if defined (PPC_OEA) || defined(PPC_OEA64) || defined (PPC_OEA64_BRIDGE)
     64 static void db_show_bat(db_expr_t, bool, db_expr_t, const char *);
     65 static void db_show_mmu(db_expr_t, bool, db_expr_t, const char *);
     66 #endif /* PPC_OEA || PPC_OEA64 || PPC_OEA64_BRIDGE */
     67 #ifdef PPC_IBM4XX
     68 static void db_ppc4xx_ctx(db_expr_t, bool, db_expr_t, const char *);
     69 static void db_ppc4xx_pv(db_expr_t, bool, db_expr_t, const char *);
     70 static void db_ppc4xx_reset(db_expr_t, bool, db_expr_t, const char *);
     71 static void db_ppc4xx_tf(db_expr_t, bool, db_expr_t, const char *);
     72 static void db_ppc4xx_dumptlb(db_expr_t, bool, db_expr_t, const char *);
     73 static void db_ppc4xx_dcr(db_expr_t, bool, db_expr_t, const char *);
     74 static db_expr_t db_ppc4xx_mfdcr(db_expr_t);
     75 static void db_ppc4xx_mtdcr(db_expr_t, db_expr_t);
     76 #ifdef USERACC
     77 static void db_ppc4xx_useracc(db_expr_t, bool, db_expr_t, const char *);
     78 #endif
     79 #endif /* PPC_IBM4XX */
     80 
     81 #ifdef DDB
     82 const struct db_command db_machine_command_table[] = {
     83 #if defined (PPC_OEA) || defined(PPC_OEA64) || defined (PPC_OEA64_BRIDGE)
     84 	{ DDB_ADD_CMD("bat",	db_show_bat,		0,
     85 	  "Print BAT register translations", NULL,NULL) },
     86 	{ DDB_ADD_CMD("mmu",	db_show_mmu,		0,
     87 	  "Print MMU registers", NULL,NULL) },
     88 #endif /* PPC_OEA || PPC_OEA64 || PPC_OEA64_BRIDGE */
     89 #ifdef PPC_IBM4XX
     90 	{ DDB_ADD_CMD("ctx",	db_ppc4xx_ctx,		0,
     91 	  "Print process MMU context information", NULL,NULL) },
     92 	{ DDB_ADD_CMD("pv",	db_ppc4xx_pv,		0,
     93 	  "Print PA->VA mapping information",
     94 	  "address",
     95 	  "   address:\tphysical address to look up") },
     96 	{ DDB_ADD_CMD("reset",	db_ppc4xx_reset,	0,
     97 	  "Reset the system ", NULL,NULL) },
     98 	{ DDB_ADD_CMD("tf",	db_ppc4xx_tf,		0,
     99 	  "Display the contents of the trapframe",
    100 	  "address",
    101 	  "   address:\tthe struct trapframe to print") },
    102 	{ DDB_ADD_CMD("tlb",	db_ppc4xx_dumptlb,	0,
    103 	  "Display instruction translation storage buffer information.",
    104 	  NULL,NULL) },
    105 	{ DDB_ADD_CMD("dcr",	db_ppc4xx_dcr,		CS_MORE|CS_SET_DOT,
    106 	  "Set the DCR register",
    107 	  "dcr",
    108 	  "   dcr:\tNew DCR value (between 0x0 and 0x3ff)") },
    109 #ifdef USERACC
    110 	{ DDB_ADD_CMD("user",	db_ppc4xx_useracc,	0,
    111 	   "Display user memory.", "[address][,count]",
    112 	   "   address:\tuserspace address to start\n"
    113 	   "   count:\tnumber of bytes to display") },
    114 #endif
    115 #endif /* PPC_IBM4XX */
    116 	{ DDB_ADD_CMD(NULL,	NULL,			0,
    117 	  NULL,NULL,NULL) }
    118 };
    119 
    120 void
    121 cpu_Debugger(void)
    122 {
    123 	ddb_trap();
    124 }
    125 #endif
    126 
    127 int
    128 ddb_trap_glue(struct trapframe *frame)
    129 {
    130 #ifdef PPC_IBM4XX
    131 	if ((frame->srr1 & PSL_PR) == 0)
    132 		return kdb_trap(frame->exc, frame);
    133 #else /* PPC_OEA */
    134 	if ((frame->srr1 & PSL_PR) == 0 &&
    135 	    (frame->exc == EXC_TRC ||
    136 	     frame->exc == EXC_RUNMODETRC ||
    137 	     (frame->exc == EXC_PGM && (frame->srr1 & 0x20000)) ||
    138 	     frame->exc == EXC_BPT ||
    139 	     frame->exc == EXC_DSI)) {
    140 		int type = frame->exc;
    141 		if (type == EXC_PGM && (frame->srr1 & 0x20000)) {
    142 			type = T_BREAKPOINT;
    143 		}
    144 		return kdb_trap(type, frame);
    145 	}
    146 #endif
    147 	return 0;
    148 }
    149 
    150 int
    151 kdb_trap(int type, void *v)
    152 {
    153 	struct trapframe *frame = v;
    154 
    155 #ifdef DDB
    156 	if (db_recover != 0 && (type != -1 && type != T_BREAKPOINT)) {
    157 		db_error("Faulted in DDB; continuing...\n");
    158 		/* NOTREACHED */
    159 	}
    160 #endif
    161 
    162 	/* XXX Should switch to kdb's own stack here. */
    163 
    164 	memcpy(DDB_REGS->r, frame->fixreg, 32 * sizeof(u_int32_t));
    165 	DDB_REGS->iar = frame->srr0;
    166 	DDB_REGS->msr = frame->srr1;
    167 	DDB_REGS->lr = frame->lr;
    168 	DDB_REGS->ctr = frame->ctr;
    169 	DDB_REGS->cr = frame->cr;
    170 	DDB_REGS->xer = frame->xer;
    171 #ifdef PPC_OEA
    172 	DDB_REGS->mq = frame->tf_xtra[TF_MQ];
    173 #endif
    174 #ifdef PPC_IBM4XX
    175 	DDB_REGS->dear = frame->dar;
    176 	DDB_REGS->esr = frame->tf_xtra[TF_ESR];
    177 	DDB_REGS->pid = frame->tf_xtra[TF_PID];
    178 #endif
    179 
    180 #ifdef DDB
    181 	db_active++;
    182 	cnpollc(1);
    183 	db_trap(type, 0);
    184 	cnpollc(0);
    185 	db_active--;
    186 #elif defined(KGDB)
    187 	if (!kgdb_trap(type, DDB_REGS))
    188 		return 0;
    189 #endif
    190 
    191 	/* KGDB isn't smart about advancing PC if we
    192 	 * take a breakpoint trap after kgdb_active is set.
    193 	 * Therefore, we help out here.
    194 	 */
    195 	if (IS_BREAKPOINT_TRAP(type, 0)) {
    196 		int bkpt;
    197 		db_read_bytes(PC_REGS(DDB_REGS),BKPT_SIZE,(void *)&bkpt);
    198 		if (bkpt== BKPT_INST) {
    199 			PC_REGS(DDB_REGS) += BKPT_SIZE;
    200 		}
    201 	}
    202 
    203 	memcpy(frame->fixreg, DDB_REGS->r, 32 * sizeof(u_int32_t));
    204 	frame->srr0 = DDB_REGS->iar;
    205 	frame->srr1 = DDB_REGS->msr;
    206 	frame->lr = DDB_REGS->lr;
    207 	frame->ctr = DDB_REGS->ctr;
    208 	frame->cr = DDB_REGS->cr;
    209 	frame->xer = DDB_REGS->xer;
    210 #ifdef PPC_OEA
    211 	frame->tf_xtra[TF_MQ] = DDB_REGS->mq;
    212 #endif
    213 #ifdef PPC_IBM4XX
    214 	frame->dar = DDB_REGS->dear;
    215 	frame->tf_xtra[TF_ESR] = DDB_REGS->esr;
    216 	frame->tf_xtra[TF_PID] = DDB_REGS->pid;
    217 #endif
    218 
    219 	return 1;
    220 }
    221 
    222 #if defined (PPC_OEA) || defined(PPC_OEA64) || defined (PPC_OEA64_BRIDGE)
    223 static void
    224 print_battranslation(struct bat *bat, unsigned int blidx)
    225 {
    226 	static const char *const batsizes[] = {
    227 		"128kB",
    228 		"256kB",
    229 		"512kB",
    230 		"1MB",
    231 		"2MB",
    232 		"4MB",
    233 		"8MB",
    234 		"16MB",
    235 		"32MB",
    236 		"64MB",
    237 		"128MB",
    238 		"256MB"
    239 	};
    240 	vsize_t len;
    241 
    242 	len = (0x20000L << blidx) - 1;
    243 	db_printf("\t%08lx %08lx %5s: 0x%08lx..0x%08lx -> 0x%08lx physical\n",
    244 	    bat->batu, bat->batl, batsizes[blidx], bat->batu & ~len,
    245 	    (bat->batu & ~len) + len, bat->batl & ~len);
    246 }
    247 
    248 static void
    249 print_batmodes(register_t super, register_t user, register_t pp)
    250 {
    251 	static const char *const accessmodes[] = {
    252 		"none",
    253 		"ro soft",
    254 		"read/write",
    255 		"read only"
    256 	};
    257 
    258 	db_printf("\tvalid: %c%c  access: %-10s  memory:",
    259 	    super ? 'S' : '-', user ? 'U' : '-', accessmodes[pp]);
    260 }
    261 
    262 static void
    263 print_wimg(register_t wimg)
    264 {
    265 	if (wimg & BAT_W)
    266 		db_printf(" wrthrough");
    267 	if (wimg & BAT_I)
    268 		db_printf(" nocache");
    269 	if (wimg & BAT_M)
    270 		db_printf(" coherent");
    271 	if (wimg & BAT_G)
    272 		db_printf(" guard");
    273 }
    274 
    275 static void
    276 print_bat(struct bat *bat)
    277 {
    278 	if ((bat->batu & BAT_V) == 0) {
    279 		db_printf("\tdisabled\n\n");
    280 		return;
    281 	}
    282 	print_battranslation(bat, 30 - __builtin_clz((bat->batu & BAT_BL)|2));
    283 	print_batmodes(bat->batu & BAT_Vs, bat->batu & BAT_Vu,
    284 	    bat->batl & BAT_PP);
    285 	print_wimg(bat->batl & BAT_WIMG);
    286 	db_printf("\n");
    287 }
    288 
    289 #ifdef PPC_OEA601
    290 static void
    291 print_bat601(struct bat *bat)
    292 {
    293 	if ((bat->batl & BAT601_V) == 0) {
    294 		db_printf("\tdisabled\n\n");
    295 		return;
    296 	}
    297 	print_battranslation(bat, 32 - __builtin_clz(bat->batl & BAT601_BSM));
    298 	print_batmodes(bat->batu & BAT601_Ks, bat->batu & BAT601_Ku,
    299 	    bat->batu & BAT601_PP);
    300 	print_wimg(bat->batu & (BAT601_W | BAT601_I | BAT601_M));
    301 	db_printf("\n");
    302 }
    303 #endif
    304 
    305 static void
    306 db_show_bat(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif)
    307 {
    308 	struct bat ibat[4];
    309 	struct bat dbat[4];
    310 	unsigned int cpuvers;
    311 	int i;
    312 
    313 	cpuvers = mfpvr() >> 16;
    314 
    315 	__asm volatile ("mfibatu %0,0" : "=r"(ibat[0].batu));
    316 	__asm volatile ("mfibatl %0,0" : "=r"(ibat[0].batl));
    317 	__asm volatile ("mfibatu %0,1" : "=r"(ibat[1].batu));
    318 	__asm volatile ("mfibatl %0,1" : "=r"(ibat[1].batl));
    319 	__asm volatile ("mfibatu %0,2" : "=r"(ibat[2].batu));
    320 	__asm volatile ("mfibatl %0,2" : "=r"(ibat[2].batl));
    321 	__asm volatile ("mfibatu %0,3" : "=r"(ibat[3].batu));
    322 	__asm volatile ("mfibatl %0,3" : "=r"(ibat[3].batl));
    323 
    324 	if (cpuvers != MPC601) {
    325 		/* The 601 has only four unified BATs */
    326 		__asm volatile ("mfdbatu %0,0" : "=r"(dbat[0].batu));
    327 		__asm volatile ("mfdbatl %0,0" : "=r"(dbat[0].batl));
    328 		__asm volatile ("mfdbatu %0,1" : "=r"(dbat[1].batu));
    329 		__asm volatile ("mfdbatl %0,1" : "=r"(dbat[1].batl));
    330 		__asm volatile ("mfdbatu %0,2" : "=r"(dbat[2].batu));
    331 		__asm volatile ("mfdbatl %0,2" : "=r"(dbat[2].batl));
    332 		__asm volatile ("mfdbatu %0,3" : "=r"(dbat[3].batu));
    333 		__asm volatile ("mfdbatl %0,3" : "=r"(dbat[3].batl));
    334 	}
    335 
    336 	for (i = 0; i < 4; i++) {
    337 #ifdef PPC_OEA601
    338 		if (cpuvers == MPC601) {
    339 			db_printf("bat%d:", i);
    340 			print_bat601(&ibat[i]);
    341 		} else
    342 #endif
    343 		{
    344 			db_printf("ibat%d:", i);
    345 			print_bat(&ibat[i]);
    346 		}
    347 	}
    348 	if (cpuvers != MPC601) {
    349 		for (i = 0; i < 4; i++) {
    350 			db_printf("dbat%d:", i);
    351 			print_bat(&dbat[i]);
    352 		}
    353 	}
    354 }
    355 
    356 static void
    357 db_show_mmu(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif)
    358 {
    359 	paddr_t sdr1;
    360 #if !defined(PPC_OEA64) && !defined(PPC_OEA64_BRIDGE)
    361 	register_t sr;
    362 	vaddr_t saddr;
    363 	int i;
    364 #endif
    365 
    366 	__asm volatile ("mfsdr1 %0" : "=r"(sdr1));
    367 	db_printf("sdr1\t\t0x%08lx\n", sdr1);
    368 
    369 #if defined(PPC_OEA64) || defined(PPC_OEA64_BRIDGE)
    370 	__asm volatile ("mfasr %0" : "=r"(sdr1));
    371 	db_printf("asr\t\t0x%08lx\n", sdr1);
    372 #else
    373 	saddr = 0;
    374 	for (i = 0; i<= 0xf; i++) {
    375 		if ((i & 3) == 0)
    376 			db_printf("sr%d-%d\t\t", i, i+3);
    377 		__asm volatile ("mfsrin %0,%1" : "=r"(sr) : "r"(saddr));
    378 		db_printf("0x%08lx   %c", sr, (i&3) == 3 ? '\n' : ' ');
    379 		saddr += 1 << ADDR_SR_SHFT;
    380 	}
    381 #endif
    382 }
    383 #endif /* PPC_OEA || PPC_OEA64 || PPC_OEA64_BRIDGE */
    384 
    385 #ifdef PPC_IBM4XX
    386 db_addr_t
    387 branch_taken(int inst, db_addr_t pc, db_regs_t *regs)
    388 {
    389 
    390 	if ((inst & M_B ) == I_B || (inst & M_B ) == I_BL) {
    391 		db_expr_t off;
    392 		off = ((db_expr_t)((inst & 0x03fffffc) << 6)) >> 6;
    393 		return (((inst & 0x2) ? 0 : pc) + off);
    394 	}
    395 
    396 	if ((inst & M_BC) == I_BC || (inst & M_BC) == I_BCL) {
    397 		db_expr_t off;
    398 		off = ((db_expr_t)((inst & 0x0000fffc) << 16)) >> 16;
    399 		return (((inst & 0x2) ? 0 : pc) + off);
    400 	}
    401 
    402 	if ((inst & M_RTS) == I_RTS || (inst & M_RTS) == I_BLRL)
    403 		return (regs->lr);
    404 
    405 	if ((inst & M_BCTR) == I_BCTR || (inst & M_BCTR) == I_BCTRL)
    406 		return (regs->ctr);
    407 
    408 	db_printf("branch_taken: can't figure out branch target for 0x%x!\n",
    409 	    inst);
    410 	return (0);
    411 }
    412 
    413 
    414 #ifdef DDB
    415 static void
    416 db_ppc4xx_ctx(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif)
    417 {
    418 	struct proc *p;
    419 
    420 	/* XXX LOCKING XXX */
    421 	for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) {
    422 		if (p->p_stat) {
    423 			db_printf("process %p:", p);
    424 			db_printf("pid:%d pmap:%p ctx:%d %s\n",
    425 				p->p_pid, p->p_vmspace->vm_map.pmap,
    426 				p->p_vmspace->vm_map.pmap->pm_ctx,
    427 				p->p_comm);
    428 		}
    429 	}
    430 	return;
    431 }
    432 
    433 static void
    434 db_ppc4xx_pv(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif)
    435 {
    436 	struct pv_entry {
    437 		struct pv_entry *pv_next;	/* Linked list of mappings */
    438 		vaddr_t pv_va;			/* virtual address of mapping */
    439 		struct pmap *pv_pm;
    440 	};
    441 	struct pv_entry *pa_to_pv(paddr_t);
    442 	struct pv_entry *pv;
    443 
    444 	if (!have_addr) {
    445 		db_printf("pv: <pa>\n");
    446 		return;
    447 	}
    448 	pv = pa_to_pv(addr);
    449 	db_printf("pv at %p\n", pv);
    450 	while (pv && pv->pv_pm) {
    451 		db_printf("next %p va %p pmap %p\n", pv->pv_next,
    452 			(void *)pv->pv_va, pv->pv_pm);
    453 		pv = pv->pv_next;
    454 	}
    455 }
    456 
    457 static void
    458 db_ppc4xx_reset(db_expr_t addr, bool have_addr, db_expr_t count,
    459     const char *modif)
    460 {
    461 	printf("Reseting...\n");
    462 	ppc4xx_reset();
    463 }
    464 
    465 static void
    466 db_ppc4xx_tf(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif)
    467 {
    468 	struct trapframe *f;
    469 
    470 
    471 	if (have_addr) {
    472 		f = (struct trapframe *)addr;
    473 
    474 		db_printf("r0-r3:  \t%8.8lx %8.8lx %8.8lx %8.8lx\n",
    475 			f->fixreg[0], f->fixreg[1],
    476 			f->fixreg[2], f->fixreg[3]);
    477 		db_printf("r4-r7:  \t%8.8lx %8.8lx %8.8lx %8.8lx\n",
    478 			f->fixreg[4], f->fixreg[5],
    479 			f->fixreg[6], f->fixreg[7]);
    480 		db_printf("r8-r11: \t%8.8lx %8.8lx %8.8lx %8.8lx\n",
    481 			f->fixreg[8], f->fixreg[9],
    482 			f->fixreg[10], f->fixreg[11]);
    483 		db_printf("r12-r15:\t%8.8lx %8.8lx %8.8lx %8.8lx\n",
    484 			f->fixreg[12], f->fixreg[13],
    485 			f->fixreg[14], f->fixreg[15]);
    486 		db_printf("r16-r19:\t%8.8lx %8.8lx %8.8lx %8.8lx\n",
    487 			f->fixreg[16], f->fixreg[17],
    488 			f->fixreg[18], f->fixreg[19]);
    489 		db_printf("r20-r23:\t%8.8lx %8.8lx %8.8lx %8.8lx\n",
    490 			f->fixreg[20], f->fixreg[21],
    491 			f->fixreg[22], f->fixreg[23]);
    492 		db_printf("r24-r27:\t%8.8lx %8.8lx %8.8lx %8.8lx\n",
    493 			f->fixreg[24], f->fixreg[25],
    494 			f->fixreg[26], f->fixreg[27]);
    495 		db_printf("r28-r31:\t%8.8lx %8.8lx %8.8lx %8.8lx\n",
    496 			f->fixreg[28], f->fixreg[29],
    497 			f->fixreg[30], f->fixreg[31]);
    498 
    499 		db_printf("lr: %8.8lx cr: %8.8x xer: %8.8x ctr: %8.8lx\n",
    500 			f->lr, f->cr, f->xer, f->ctr);
    501 		db_printf("srr0(pc): %8.8lx srr1(msr): %8.8lx "
    502 			"dear: %8.8lx esr: %8.8x\n",
    503 			f->srr0, f->srr1, f->dar, f->tf_xtra[TF_ESR]);
    504 		db_printf("exc: %8.8x pid: %8.8x\n",
    505 			f->exc, f->tf_xtra[TF_PID]);
    506 	}
    507 	return;
    508 }
    509 
    510 static const char *const tlbsizes[] = {
    511 	  "1kB",
    512 	  "4kB",
    513 	 "16kB",
    514 	 "64kB",
    515 	"256kB",
    516 	  "1MB",
    517 	  "4MB",
    518 	 "16MB"
    519 };
    520 
    521 static void
    522 db_ppc4xx_dumptlb(db_expr_t addr, bool have_addr, db_expr_t count,
    523     const char *modif)
    524 {
    525 	int i, zone, tlbsize;
    526 	u_int zpr, pid, opid, msr;
    527 	u_long tlblo, tlbhi, tlbmask;
    528 
    529 	zpr = mfspr(SPR_ZPR);
    530 	for (i = 0; i < NTLB; i++) {
    531 		__asm volatile("mfmsr %3;"
    532 			"mfpid %4;"
    533 			"li %0,0;"
    534 			"mtmsr %0;"
    535 			"sync; isync;"
    536 			"tlbrelo %0,%5;"
    537 			"tlbrehi %1,%5;"
    538 			"mfpid %2;"
    539 			"mtpid %4;"
    540 			"mtmsr %3;"
    541 			"sync; isync"
    542 			: "=&r" (tlblo), "=&r" (tlbhi), "=r" (pid),
    543 			"=&r" (msr), "=&r" (opid) : "r" (i));
    544 
    545 		if (strchr(modif, 'v') && !(tlbhi & TLB_VALID))
    546 			continue;
    547 
    548 		tlbsize = (tlbhi & TLB_SIZE_MASK) >> TLB_SIZE_SHFT;
    549 		/* map tlbsize 0 .. 7 to masks for 1kB .. 16MB */
    550 		tlbmask = ~(1 << (tlbsize * 2 + 10)) + 1;
    551 
    552 		if (have_addr && ((tlbhi & tlbmask) != (addr & tlbmask)))
    553 			continue;
    554 
    555 		zone = (tlblo & TLB_ZSEL_MASK) >> TLB_ZSEL_SHFT;
    556 		db_printf("tlb%c%2d", tlbhi & TLB_VALID ? ' ' : '*', i);
    557 		db_printf("  PID %3d EPN 0x%08lx %-5s",
    558 		    pid,
    559 		    tlbhi & tlbmask,
    560 		    tlbsizes[tlbsize]);
    561 		db_printf("  RPN 0x%08lx  ZONE %2d%c  %s %s %c%c%c%c%c %s",
    562 		    tlblo & tlbmask,
    563 		    zone,
    564 		    "NTTA"[(zpr >> ((15 - zone) * 2)) & 3],
    565 		    tlblo & TLB_EX ? "EX" : "  ",
    566 		    tlblo & TLB_WR ? "WR" : "  ",
    567 		    tlblo & TLB_W ? 'W' : ' ',
    568 		    tlblo & TLB_I ? 'I' : ' ',
    569 		    tlblo & TLB_M ? 'M' : ' ',
    570 		    tlblo & TLB_G ? 'G' : ' ',
    571 		    tlbhi & TLB_ENDIAN ? 'E' : ' ',
    572 		    tlbhi & TLB_U0 ? "U0" : "  ");
    573 		db_printf("\n");
    574 	}
    575 }
    576 
    577 static void
    578 db_ppc4xx_dcr(db_expr_t address, bool have_addr, db_expr_t count,
    579     const char *modif)
    580 {
    581 	db_expr_t new_value;
    582 	db_expr_t addr;
    583 
    584 	if (address < 0 || address > 0x3ff)
    585 		db_error("Invalid DCR address (Valid range is 0x0 - 0x3ff)\n");
    586 
    587 	addr = address;
    588 
    589 	while (db_expression(&new_value)) {
    590 		db_printf("dcr 0x%lx\t\t%s = ", addr,
    591 		    db_num_to_str(db_ppc4xx_mfdcr(addr)));
    592 		db_ppc4xx_mtdcr(addr, new_value);
    593 		db_printf("%s\n", db_num_to_str(db_ppc4xx_mfdcr(addr)));
    594 		addr += 1;
    595 	}
    596 
    597 	if (addr == address) {
    598 		db_next = (db_addr_t)addr + 1;
    599 		db_prev = (db_addr_t)addr;
    600 		db_printf("dcr 0x%lx\t\t%s\n", addr,
    601 		    db_num_to_str(db_ppc4xx_mfdcr(addr)));
    602 	} else {
    603 		db_next = (db_addr_t)addr;
    604 		db_prev = (db_addr_t)addr - 1;
    605 	}
    606 
    607 	db_skip_to_eol();
    608 }
    609 
    610 /*
    611  * XXX Grossness Alert! XXX
    612  *
    613  * Please look away now if you don't like self-modifying code
    614  */
    615 static u_int32_t db_ppc4xx_dcrfunc[4];
    616 
    617 static db_expr_t
    618 db_ppc4xx_mfdcr(db_expr_t reg)
    619 {
    620 	db_expr_t (*func)(void);
    621 
    622 	reg = (((reg & 0x1f) << 5) | ((reg >> 5) & 0x1f)) << 11;
    623 	db_ppc4xx_dcrfunc[0] = 0x7c0004ac;		/* sync */
    624 	db_ppc4xx_dcrfunc[1] = 0x4c00012c;		/* isync */
    625 	db_ppc4xx_dcrfunc[2] = 0x7c600286 | reg;	/* mfdcr reg, r3 */
    626 	db_ppc4xx_dcrfunc[3] = 0x4e800020;		/* blr */
    627 
    628 	__syncicache((void *)db_ppc4xx_dcrfunc, sizeof(db_ppc4xx_dcrfunc));
    629 	func = (db_expr_t (*)(void))(void *)db_ppc4xx_dcrfunc;
    630 
    631 	return ((*func)());
    632 }
    633 
    634 static void
    635 db_ppc4xx_mtdcr(db_expr_t reg, db_expr_t val)
    636 {
    637 	db_expr_t (*func)(db_expr_t);
    638 
    639 	reg = (((reg & 0x1f) << 5) | ((reg >> 5) & 0x1f)) << 11;
    640 	db_ppc4xx_dcrfunc[0] = 0x7c0004ac;		/* sync */
    641 	db_ppc4xx_dcrfunc[1] = 0x4c00012c;		/* isync */
    642 	db_ppc4xx_dcrfunc[2] = 0x7c600386 | reg;	/* mtdcr r3, reg */
    643 	db_ppc4xx_dcrfunc[3] = 0x4e800020;		/* blr */
    644 
    645 	__syncicache((void *)db_ppc4xx_dcrfunc, sizeof(db_ppc4xx_dcrfunc));
    646 	func = (db_expr_t (*)(db_expr_t))(void *)db_ppc4xx_dcrfunc;
    647 
    648 	(*func)(val);
    649 }
    650 
    651 #ifdef USERACC
    652 static void
    653 db_ppc4xx_useracc(db_expr_t addr, bool have_addr, db_expr_t count,
    654     const char *modif)
    655 {
    656 	static paddr_t oldaddr = -1;
    657 	int instr = 0;
    658 	int data;
    659 	extern vaddr_t opc_disasm(vaddr_t loc, int);
    660 
    661 
    662 	if (!have_addr) {
    663 		addr = oldaddr;
    664 	}
    665 	if (addr == -1) {
    666 		db_printf("no address\n");
    667 		return;
    668 	}
    669 	addr &= ~0x3; /* align */
    670 	{
    671 		const char *cp = modif;
    672 		char c;
    673 		while ((c = *cp++) != 0)
    674 			if (c == 'i')
    675 				instr = 1;
    676 	}
    677 	while (count--) {
    678 		if (db_print_position() == 0) {
    679 			/* Always print the address. */
    680 			db_printf("%8.4lx:\t", addr);
    681 		}
    682 		oldaddr=addr;
    683 		copyin((void *)addr, &data, sizeof(data));
    684 		if (instr) {
    685 			opc_disasm(addr, data);
    686 		} else {
    687 			db_printf("%4.4x\n", data);
    688 		}
    689 		addr += 4;
    690 		db_end_line();
    691 	}
    692 
    693 }
    694 #endif
    695 
    696 #endif /* DDB */
    697 
    698 #endif /* PPC_IBM4XX */
    699