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