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