Home | History | Annotate | Line # | Download | only in powerpc
db_interface.c revision 1.41
      1 /*	$NetBSD: db_interface.c,v 1.41 2010/01/28 12:37:45 phx 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.41 2010/01/28 12:37:45 phx 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 
     25 #ifdef PPC_IBM4XX
     26 #include <machine/tlb.h>
     27 #include <uvm/uvm_extern.h>
     28 #endif
     29 
     30 #ifdef DDB
     31 #include <ddb/db_sym.h>
     32 #include <ddb/db_command.h>
     33 #include <ddb/db_extern.h>
     34 #include <ddb/db_access.h>
     35 #include <ddb/db_lex.h>
     36 #include <ddb/db_output.h>
     37 #include <ddb/ddbvar.h>
     38 #endif
     39 
     40 #ifdef KGDB
     41 #include <sys/kgdb.h>
     42 #define db_printf printf
     43 #endif
     44 
     45 #include <dev/ofw/openfirm.h>
     46 
     47 int	db_active = 0;
     48 
     49 db_regs_t ddb_regs;
     50 
     51 void ddb_trap(void);				/* Call into trap_subr.S */
     52 int ddb_trap_glue(struct trapframe *);		/* Called from trap_subr.S */
     53 static void db_show_bat(db_expr_t, bool, db_expr_t, const char *);
     54 #ifdef PPC_IBM4XX
     55 static void db_ppc4xx_ctx(db_expr_t, bool, db_expr_t, const char *);
     56 static void db_ppc4xx_pv(db_expr_t, bool, db_expr_t, const char *);
     57 static void db_ppc4xx_reset(db_expr_t, bool, db_expr_t, const char *);
     58 static void db_ppc4xx_tf(db_expr_t, bool, db_expr_t, const char *);
     59 static void db_ppc4xx_dumptlb(db_expr_t, bool, db_expr_t, const char *);
     60 static void db_ppc4xx_dcr(db_expr_t, bool, db_expr_t, const char *);
     61 static db_expr_t db_ppc4xx_mfdcr(db_expr_t);
     62 static void db_ppc4xx_mtdcr(db_expr_t, db_expr_t);
     63 #ifdef USERACC
     64 static void db_ppc4xx_useracc(db_expr_t, bool, db_expr_t, const char *);
     65 #endif
     66 #endif /* PPC_IBM4XX */
     67 
     68 #ifdef DDB
     69 const struct db_command db_machine_command_table[] = {
     70 	{ DDB_ADD_CMD("bat",	db_show_bat,		0,
     71 	  "Show BAT register translations", NULL,NULL) },
     72 #ifdef PPC_IBM4XX
     73 	{ DDB_ADD_CMD("ctx",	db_ppc4xx_ctx,		0,
     74 	  "Print process MMU context information", NULL,NULL) },
     75 	{ DDB_ADD_CMD("pv",	db_ppc4xx_pv,		0,
     76 	  "Print PA->VA mapping information",
     77 	  "address",
     78 	  "   address:\tphysical address to look up") },
     79 	{ DDB_ADD_CMD("reset",	db_ppc4xx_reset,	0,
     80 	  "Reset the system ", NULL,NULL) },
     81 	{ DDB_ADD_CMD("tf",	db_ppc4xx_tf,		0,
     82 	  "Display the contents of the trapframe",
     83 	  "address",
     84 	  "   address:\tthe struct trapframe to print") },
     85 	{ DDB_ADD_CMD("tlb",	db_ppc4xx_dumptlb,	0,
     86 	  "Display instruction translation storage buffer information.",
     87 	  NULL,NULL) },
     88 	{ DDB_ADD_CMD("dcr",	db_ppc4xx_dcr,		CS_MORE|CS_SET_DOT,
     89 	  "Set the DCR register",
     90 	  "dcr",
     91 	  "   dcr:\tNew DCR value (between 0x0 and 0x3ff)") },
     92 #ifdef USERACC
     93 	{ DDB_ADD_CMD("user",	db_ppc4xx_useracc,	0,
     94 	   "Display user memory.", "[address][,count]",
     95 	   "   address:\tuserspace address to start\n"
     96 	   "   count:\tnumber of bytes to display") },
     97 #endif
     98 #endif /* PPC_IBM4XX */
     99 	{ DDB_ADD_CMD(NULL,	NULL,			0,
    100 	  NULL,NULL,NULL) }
    101 };
    102 
    103 void
    104 cpu_Debugger(void)
    105 {
    106 	ddb_trap();
    107 }
    108 #endif
    109 
    110 int
    111 ddb_trap_glue(struct trapframe *frame)
    112 {
    113 #ifdef PPC_IBM4XX
    114 	if ((frame->srr1 & PSL_PR) == 0)
    115 		return kdb_trap(frame->exc, frame);
    116 #else /* PPC_OEA */
    117 	if ((frame->srr1 & PSL_PR) == 0 &&
    118 	    (frame->exc == EXC_TRC ||
    119 	     frame->exc == EXC_RUNMODETRC ||
    120 	     (frame->exc == EXC_PGM && (frame->srr1 & 0x20000)) ||
    121 	     frame->exc == EXC_BPT ||
    122 	     frame->exc == EXC_DSI)) {
    123 		int type = frame->exc;
    124 		if (type == EXC_PGM && (frame->srr1 & 0x20000)) {
    125 			type = T_BREAKPOINT;
    126 		}
    127 		return kdb_trap(type, frame);
    128 	}
    129 #endif
    130 	return 0;
    131 }
    132 
    133 int
    134 kdb_trap(int type, void *v)
    135 {
    136 	struct trapframe *frame = v;
    137 
    138 #ifdef DDB
    139 	if (db_recover != 0 && (type != -1 && type != T_BREAKPOINT)) {
    140 		db_error("Faulted in DDB; continuing...\n");
    141 		/* NOTREACHED */
    142 	}
    143 #endif
    144 
    145 	/* XXX Should switch to kdb's own stack here. */
    146 
    147 	memcpy(DDB_REGS->r, frame->fixreg, 32 * sizeof(u_int32_t));
    148 	DDB_REGS->iar = frame->srr0;
    149 	DDB_REGS->msr = frame->srr1;
    150 	DDB_REGS->lr = frame->lr;
    151 	DDB_REGS->ctr = frame->ctr;
    152 	DDB_REGS->cr = frame->cr;
    153 	DDB_REGS->xer = frame->xer;
    154 #ifdef PPC_OEA
    155 	DDB_REGS->mq = frame->tf_xtra[TF_MQ];
    156 #endif
    157 #ifdef PPC_IBM4XX
    158 	DDB_REGS->dear = frame->dar;
    159 	DDB_REGS->esr = frame->tf_xtra[TF_ESR];
    160 	DDB_REGS->pid = frame->tf_xtra[TF_PID];
    161 #endif
    162 
    163 #ifdef DDB
    164 	db_active++;
    165 	cnpollc(1);
    166 	db_trap(type, 0);
    167 	cnpollc(0);
    168 	db_active--;
    169 #elif defined(KGDB)
    170 	if (!kgdb_trap(type, DDB_REGS))
    171 		return 0;
    172 #endif
    173 
    174 	/* KGDB isn't smart about advancing PC if we
    175 	 * take a breakpoint trap after kgdb_active is set.
    176 	 * Therefore, we help out here.
    177 	 */
    178 	if (IS_BREAKPOINT_TRAP(type, 0)) {
    179 		int bkpt;
    180 		db_read_bytes(PC_REGS(DDB_REGS),BKPT_SIZE,(void *)&bkpt);
    181 		if (bkpt== BKPT_INST) {
    182 			PC_REGS(DDB_REGS) += BKPT_SIZE;
    183 		}
    184 	}
    185 
    186 	memcpy(frame->fixreg, DDB_REGS->r, 32 * sizeof(u_int32_t));
    187 	frame->srr0 = DDB_REGS->iar;
    188 	frame->srr1 = DDB_REGS->msr;
    189 	frame->lr = DDB_REGS->lr;
    190 	frame->ctr = DDB_REGS->ctr;
    191 	frame->cr = DDB_REGS->cr;
    192 	frame->xer = DDB_REGS->xer;
    193 #ifdef PPC_OEA
    194 	frame->tf_xtra[TF_MQ] = DDB_REGS->mq;
    195 #endif
    196 #ifdef PPC_IBM4XX
    197 	frame->dar = DDB_REGS->dear;
    198 	frame->tf_xtra[TF_ESR] = DDB_REGS->esr;
    199 	frame->tf_xtra[TF_PID] = DDB_REGS->pid;
    200 #endif
    201 
    202 	return 1;
    203 }
    204 
    205 static void
    206 db_show_bat(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif)
    207 {
    208 	unsinged int cpuvers;
    209 	struct bat ibat[4];
    210 	struct bat dbat[4];
    211 
    212 	cpuvers = mfpvr() >> 16;
    213 
    214 #ifdef PPC_OEA601
    215 	if (cpuvers == MPC601) {
    216 		/* The 601 has four unified BATs with a different layout. */
    217 
    218 	} else
    219 #endif
    220 	{
    221 	}
    222 }
    223 
    224 #ifdef PPC_IBM4XX
    225 db_addr_t
    226 branch_taken(int inst, db_addr_t pc, db_regs_t *regs)
    227 {
    228 
    229 	if ((inst & M_B ) == I_B || (inst & M_B ) == I_BL) {
    230 		db_expr_t off;
    231 		off = ((db_expr_t)((inst & 0x03fffffc) << 6)) >> 6;
    232 		return (((inst & 0x2) ? 0 : pc) + off);
    233 	}
    234 
    235 	if ((inst & M_BC) == I_BC || (inst & M_BC) == I_BCL) {
    236 		db_expr_t off;
    237 		off = ((db_expr_t)((inst & 0x0000fffc) << 16)) >> 16;
    238 		return (((inst & 0x2) ? 0 : pc) + off);
    239 	}
    240 
    241 	if ((inst & M_RTS) == I_RTS || (inst & M_RTS) == I_BLRL)
    242 		return (regs->lr);
    243 
    244 	if ((inst & M_BCTR) == I_BCTR || (inst & M_BCTR) == I_BCTRL)
    245 		return (regs->ctr);
    246 
    247 	db_printf("branch_taken: can't figure out branch target for 0x%x!\n",
    248 	    inst);
    249 	return (0);
    250 }
    251 
    252 
    253 #ifdef DDB
    254 static void
    255 db_ppc4xx_ctx(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif)
    256 {
    257 	struct proc *p;
    258 
    259 	/* XXX LOCKING XXX */
    260 	for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) {
    261 		if (p->p_stat) {
    262 			db_printf("process %p:", p);
    263 			db_printf("pid:%d pmap:%p ctx:%d %s\n",
    264 				p->p_pid, p->p_vmspace->vm_map.pmap,
    265 				p->p_vmspace->vm_map.pmap->pm_ctx,
    266 				p->p_comm);
    267 		}
    268 	}
    269 	return;
    270 }
    271 
    272 static void
    273 db_ppc4xx_pv(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif)
    274 {
    275 	struct pv_entry {
    276 		struct pv_entry *pv_next;	/* Linked list of mappings */
    277 		vaddr_t pv_va;			/* virtual address of mapping */
    278 		struct pmap *pv_pm;
    279 	};
    280 	struct pv_entry *pa_to_pv(paddr_t);
    281 	struct pv_entry *pv;
    282 
    283 	if (!have_addr) {
    284 		db_printf("pv: <pa>\n");
    285 		return;
    286 	}
    287 	pv = pa_to_pv(addr);
    288 	db_printf("pv at %p\n", pv);
    289 	while (pv && pv->pv_pm) {
    290 		db_printf("next %p va %p pmap %p\n", pv->pv_next,
    291 			(void *)pv->pv_va, pv->pv_pm);
    292 		pv = pv->pv_next;
    293 	}
    294 }
    295 
    296 static void
    297 db_ppc4xx_reset(db_expr_t addr, bool have_addr, db_expr_t count,
    298     const char *modif)
    299 {
    300 	printf("Reseting...\n");
    301 	ppc4xx_reset();
    302 }
    303 
    304 static void
    305 db_ppc4xx_tf(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif)
    306 {
    307 	struct trapframe *f;
    308 
    309 
    310 	if (have_addr) {
    311 		f = (struct trapframe *)addr;
    312 
    313 		db_printf("r0-r3:  \t%8.8lx %8.8lx %8.8lx %8.8lx\n",
    314 			f->fixreg[0], f->fixreg[1],
    315 			f->fixreg[2], f->fixreg[3]);
    316 		db_printf("r4-r7:  \t%8.8lx %8.8lx %8.8lx %8.8lx\n",
    317 			f->fixreg[4], f->fixreg[5],
    318 			f->fixreg[6], f->fixreg[7]);
    319 		db_printf("r8-r11: \t%8.8lx %8.8lx %8.8lx %8.8lx\n",
    320 			f->fixreg[8], f->fixreg[9],
    321 			f->fixreg[10], f->fixreg[11]);
    322 		db_printf("r12-r15:\t%8.8lx %8.8lx %8.8lx %8.8lx\n",
    323 			f->fixreg[12], f->fixreg[13],
    324 			f->fixreg[14], f->fixreg[15]);
    325 		db_printf("r16-r19:\t%8.8lx %8.8lx %8.8lx %8.8lx\n",
    326 			f->fixreg[16], f->fixreg[17],
    327 			f->fixreg[18], f->fixreg[19]);
    328 		db_printf("r20-r23:\t%8.8lx %8.8lx %8.8lx %8.8lx\n",
    329 			f->fixreg[20], f->fixreg[21],
    330 			f->fixreg[22], f->fixreg[23]);
    331 		db_printf("r24-r27:\t%8.8lx %8.8lx %8.8lx %8.8lx\n",
    332 			f->fixreg[24], f->fixreg[25],
    333 			f->fixreg[26], f->fixreg[27]);
    334 		db_printf("r28-r31:\t%8.8lx %8.8lx %8.8lx %8.8lx\n",
    335 			f->fixreg[28], f->fixreg[29],
    336 			f->fixreg[30], f->fixreg[31]);
    337 
    338 		db_printf("lr: %8.8lx cr: %8.8x xer: %8.8x ctr: %8.8lx\n",
    339 			f->lr, f->cr, f->xer, f->ctr);
    340 		db_printf("srr0(pc): %8.8lx srr1(msr): %8.8lx "
    341 			"dear: %8.8lx esr: %8.8x\n",
    342 			f->srr0, f->srr1, f->dar, f->tf_xtra[TF_ESR]);
    343 		db_printf("exc: %8.8x pid: %8.8x\n",
    344 			f->exc, f->tf_xtra[TF_PID]);
    345 	}
    346 	return;
    347 }
    348 
    349 static const char *const tlbsizes[] = {
    350 	  "1kB",
    351 	  "4kB",
    352 	 "16kB",
    353 	 "64kB",
    354 	"256kB",
    355 	  "1MB",
    356 	  "4MB",
    357 	 "16MB"
    358 };
    359 
    360 static void
    361 db_ppc4xx_dumptlb(db_expr_t addr, bool have_addr, db_expr_t count,
    362     const char *modif)
    363 {
    364 	int i, zone, tlbsize;
    365 	u_int zpr, pid, opid, msr;
    366 	u_long tlblo, tlbhi, tlbmask;
    367 
    368 	zpr = mfspr(SPR_ZPR);
    369 	for (i = 0; i < NTLB; i++) {
    370 		__asm volatile("mfmsr %3;"
    371 			"mfpid %4;"
    372 			"li %0,0;"
    373 			"mtmsr %0;"
    374 			"sync; isync;"
    375 			"tlbrelo %0,%5;"
    376 			"tlbrehi %1,%5;"
    377 			"mfpid %2;"
    378 			"mtpid %4;"
    379 			"mtmsr %3;"
    380 			"sync; isync"
    381 			: "=&r" (tlblo), "=&r" (tlbhi), "=r" (pid),
    382 			"=&r" (msr), "=&r" (opid) : "r" (i));
    383 
    384 		if (strchr(modif, 'v') && !(tlbhi & TLB_VALID))
    385 			continue;
    386 
    387 		tlbsize = (tlbhi & TLB_SIZE_MASK) >> TLB_SIZE_SHFT;
    388 		/* map tlbsize 0 .. 7 to masks for 1kB .. 16MB */
    389 		tlbmask = ~(1 << (tlbsize * 2 + 10)) + 1;
    390 
    391 		if (have_addr && ((tlbhi & tlbmask) != (addr & tlbmask)))
    392 			continue;
    393 
    394 		zone = (tlblo & TLB_ZSEL_MASK) >> TLB_ZSEL_SHFT;
    395 		db_printf("tlb%c%2d", tlbhi & TLB_VALID ? ' ' : '*', i);
    396 		db_printf("  PID %3d EPN 0x%08lx %-5s",
    397 		    pid,
    398 		    tlbhi & tlbmask,
    399 		    tlbsizes[tlbsize]);
    400 		db_printf("  RPN 0x%08lx  ZONE %2d%c  %s %s %c%c%c%c%c %s",
    401 		    tlblo & tlbmask,
    402 		    zone,
    403 		    "NTTA"[(zpr >> ((15 - zone) * 2)) & 3],
    404 		    tlblo & TLB_EX ? "EX" : "  ",
    405 		    tlblo & TLB_WR ? "WR" : "  ",
    406 		    tlblo & TLB_W ? 'W' : ' ',
    407 		    tlblo & TLB_I ? 'I' : ' ',
    408 		    tlblo & TLB_M ? 'M' : ' ',
    409 		    tlblo & TLB_G ? 'G' : ' ',
    410 		    tlbhi & TLB_ENDIAN ? 'E' : ' ',
    411 		    tlbhi & TLB_U0 ? "U0" : "  ");
    412 		db_printf("\n");
    413 	}
    414 }
    415 
    416 static void
    417 db_ppc4xx_dcr(db_expr_t address, bool have_addr, db_expr_t count,
    418     const char *modif)
    419 {
    420 	db_expr_t new_value;
    421 	db_expr_t addr;
    422 
    423 	if (address < 0 || address > 0x3ff)
    424 		db_error("Invalid DCR address (Valid range is 0x0 - 0x3ff)\n");
    425 
    426 	addr = address;
    427 
    428 	while (db_expression(&new_value)) {
    429 		db_printf("dcr 0x%lx\t\t%s = ", addr,
    430 		    db_num_to_str(db_ppc4xx_mfdcr(addr)));
    431 		db_ppc4xx_mtdcr(addr, new_value);
    432 		db_printf("%s\n", db_num_to_str(db_ppc4xx_mfdcr(addr)));
    433 		addr += 1;
    434 	}
    435 
    436 	if (addr == address) {
    437 		db_next = (db_addr_t)addr + 1;
    438 		db_prev = (db_addr_t)addr;
    439 		db_printf("dcr 0x%lx\t\t%s\n", addr,
    440 		    db_num_to_str(db_ppc4xx_mfdcr(addr)));
    441 	} else {
    442 		db_next = (db_addr_t)addr;
    443 		db_prev = (db_addr_t)addr - 1;
    444 	}
    445 
    446 	db_skip_to_eol();
    447 }
    448 
    449 /*
    450  * XXX Grossness Alert! XXX
    451  *
    452  * Please look away now if you don't like self-modifying code
    453  */
    454 static u_int32_t db_ppc4xx_dcrfunc[4];
    455 
    456 static db_expr_t
    457 db_ppc4xx_mfdcr(db_expr_t reg)
    458 {
    459 	db_expr_t (*func)(void);
    460 
    461 	reg = (((reg & 0x1f) << 5) | ((reg >> 5) & 0x1f)) << 11;
    462 	db_ppc4xx_dcrfunc[0] = 0x7c0004ac;		/* sync */
    463 	db_ppc4xx_dcrfunc[1] = 0x4c00012c;		/* isync */
    464 	db_ppc4xx_dcrfunc[2] = 0x7c600286 | reg;	/* mfdcr reg, r3 */
    465 	db_ppc4xx_dcrfunc[3] = 0x4e800020;		/* blr */
    466 
    467 	__syncicache((void *)db_ppc4xx_dcrfunc, sizeof(db_ppc4xx_dcrfunc));
    468 	func = (db_expr_t (*)(void))(void *)db_ppc4xx_dcrfunc;
    469 
    470 	return ((*func)());
    471 }
    472 
    473 static void
    474 db_ppc4xx_mtdcr(db_expr_t reg, db_expr_t val)
    475 {
    476 	db_expr_t (*func)(db_expr_t);
    477 
    478 	reg = (((reg & 0x1f) << 5) | ((reg >> 5) & 0x1f)) << 11;
    479 	db_ppc4xx_dcrfunc[0] = 0x7c0004ac;		/* sync */
    480 	db_ppc4xx_dcrfunc[1] = 0x4c00012c;		/* isync */
    481 	db_ppc4xx_dcrfunc[2] = 0x7c600386 | reg;	/* mtdcr r3, reg */
    482 	db_ppc4xx_dcrfunc[3] = 0x4e800020;		/* blr */
    483 
    484 	__syncicache((void *)db_ppc4xx_dcrfunc, sizeof(db_ppc4xx_dcrfunc));
    485 	func = (db_expr_t (*)(db_expr_t))(void *)db_ppc4xx_dcrfunc;
    486 
    487 	(*func)(val);
    488 }
    489 
    490 #ifdef USERACC
    491 static void
    492 db_ppc4xx_useracc(db_expr_t addr, bool have_addr, db_expr_t count,
    493     const char *modif)
    494 {
    495 	static paddr_t oldaddr = -1;
    496 	int instr = 0;
    497 	int data;
    498 	extern vaddr_t opc_disasm(vaddr_t loc, int);
    499 
    500 
    501 	if (!have_addr) {
    502 		addr = oldaddr;
    503 	}
    504 	if (addr == -1) {
    505 		db_printf("no address\n");
    506 		return;
    507 	}
    508 	addr &= ~0x3; /* align */
    509 	{
    510 		const char *cp = modif;
    511 		char c;
    512 		while ((c = *cp++) != 0)
    513 			if (c == 'i')
    514 				instr = 1;
    515 	}
    516 	while (count--) {
    517 		if (db_print_position() == 0) {
    518 			/* Always print the address. */
    519 			db_printf("%8.4lx:\t", addr);
    520 		}
    521 		oldaddr=addr;
    522 		copyin((void *)addr, &data, sizeof(data));
    523 		if (instr) {
    524 			opc_disasm(addr, data);
    525 		} else {
    526 			db_printf("%4.4x\n", data);
    527 		}
    528 		addr += 4;
    529 		db_end_line();
    530 	}
    531 
    532 }
    533 #endif
    534 
    535 #endif /* DDB */
    536 
    537 #endif /* PPC_IBM4XX */
    538