db_interface.c revision 1.37.22.1 1 /* $NetBSD: db_interface.c,v 1.37.22.1 2007/11/06 23:21:00 matt 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.37.22.1 2007/11/06 23:21:00 matt 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, NULL,NULL,NULL) },
198 { DDB_ADD_CMD("pv", db_ppc4xx_pv, 0, NULL,NULL,NULL) },
199 { DDB_ADD_CMD("reset", db_ppc4xx_reset, 0, NULL,NULL,NULL) },
200 { DDB_ADD_CMD("tf", db_ppc4xx_tf, 0, NULL,NULL,NULL) },
201 { DDB_ADD_CMD("tlb", db_ppc4xx_dumptlb, 0, NULL,NULL,NULL) },
202 { DDB_ADD_CMD("dcr", db_ppc4xx_dcr, CS_MORE|CS_SET_DOT, NULL,NULL,NULL) },
203 #ifdef USERACC
204 { DDB_ADD_CMD("user", db_ppc4xx_useracc, 0, NULL,NULL,NULL) },
205 #endif
206 { DDB_ADD_CMD(NULL, NULL, 0, NULL,NULL,NULL) }
207 };
208
209 static void
210 db_ppc4xx_ctx(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif)
211 {
212 struct proc *p;
213
214 /* XXX LOCKING XXX */
215 for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) {
216 if (p->p_stat) {
217 db_printf("process %p:", p);
218 db_printf("pid:%d pmap:%p ctx:%d %s\n",
219 p->p_pid, p->p_vmspace->vm_map.pmap,
220 p->p_vmspace->vm_map.pmap->pm_ctx,
221 p->p_comm);
222 }
223 }
224 return;
225 }
226
227 static void
228 db_ppc4xx_pv(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif)
229 {
230 struct pv_entry {
231 struct pv_entry *pv_next; /* Linked list of mappings */
232 vaddr_t pv_va; /* virtual address of mapping */
233 struct pmap *pv_pm;
234 };
235 struct pv_entry *pa_to_pv(paddr_t);
236 struct pv_entry *pv;
237
238 if (!have_addr) {
239 db_printf("pv: <pa>\n");
240 return;
241 }
242 pv = pa_to_pv(addr);
243 db_printf("pv at %p\n", pv);
244 while (pv && pv->pv_pm) {
245 db_printf("next %p va %p pmap %p\n", pv->pv_next,
246 (void *)pv->pv_va, pv->pv_pm);
247 pv = pv->pv_next;
248 }
249 }
250
251 static void
252 db_ppc4xx_reset(db_expr_t addr, bool have_addr, db_expr_t count,
253 const char *modif)
254 {
255 printf("Reseting...\n");
256 ppc4xx_reset();
257 }
258
259 static void
260 db_ppc4xx_tf(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif)
261 {
262 struct trapframe *f;
263
264
265 if (have_addr) {
266 f = (struct trapframe *)addr;
267
268 db_printf("r0-r3: \t%8.8lx %8.8lx %8.8lx %8.8lx\n",
269 f->fixreg[0], f->fixreg[1],
270 f->fixreg[2], f->fixreg[3]);
271 db_printf("r4-r7: \t%8.8lx %8.8lx %8.8lx %8.8lx\n",
272 f->fixreg[4], f->fixreg[5],
273 f->fixreg[6], f->fixreg[7]);
274 db_printf("r8-r11: \t%8.8lx %8.8lx %8.8lx %8.8lx\n",
275 f->fixreg[8], f->fixreg[9],
276 f->fixreg[10], f->fixreg[11]);
277 db_printf("r12-r15:\t%8.8lx %8.8lx %8.8lx %8.8lx\n",
278 f->fixreg[12], f->fixreg[13],
279 f->fixreg[14], f->fixreg[15]);
280 db_printf("r16-r19:\t%8.8lx %8.8lx %8.8lx %8.8lx\n",
281 f->fixreg[16], f->fixreg[17],
282 f->fixreg[18], f->fixreg[19]);
283 db_printf("r20-r23:\t%8.8lx %8.8lx %8.8lx %8.8lx\n",
284 f->fixreg[20], f->fixreg[21],
285 f->fixreg[22], f->fixreg[23]);
286 db_printf("r24-r27:\t%8.8lx %8.8lx %8.8lx %8.8lx\n",
287 f->fixreg[24], f->fixreg[25],
288 f->fixreg[26], f->fixreg[27]);
289 db_printf("r28-r31:\t%8.8lx %8.8lx %8.8lx %8.8lx\n",
290 f->fixreg[28], f->fixreg[29],
291 f->fixreg[30], f->fixreg[31]);
292
293 db_printf("lr: %8.8lx cr: %8.8x xer: %8.8x ctr: %8.8lx\n",
294 f->lr, f->cr, f->xer, f->ctr);
295 db_printf("srr0(pc): %8.8lx srr1(msr): %8.8lx "
296 "dear: %8.8lx esr: %8.8x\n",
297 f->srr0, f->srr1, f->dar, f->tf_xtra[TF_ESR]);
298 db_printf("exc: %8.8x pid: %8.8x\n",
299 f->exc, f->tf_xtra[TF_PID]);
300 }
301 return;
302 }
303
304 static const char *const tlbsizes[] = {
305 "1kB",
306 "4kB",
307 "16kB",
308 "64kB",
309 "256kB",
310 "1MB",
311 "4MB",
312 "16MB"
313 };
314
315 static void
316 db_ppc4xx_dumptlb(db_expr_t addr, bool have_addr, db_expr_t count,
317 const char *modif)
318 {
319 int i, zone, tlbsize;
320 u_int zpr, pid, opid, msr;
321 u_long tlblo, tlbhi, tlbmask;
322
323 zpr = mfspr(SPR_ZPR);
324 for (i = 0; i < NTLB; i++) {
325 __asm volatile("mfmsr %3;"
326 "mfpid %4;"
327 "li %0,0;"
328 "mtmsr %0;"
329 "sync; isync;"
330 "tlbrelo %0,%5;"
331 "tlbrehi %1,%5;"
332 "mfpid %2;"
333 "mtpid %4;"
334 "mtmsr %3;"
335 "sync; isync"
336 : "=&r" (tlblo), "=&r" (tlbhi), "=r" (pid),
337 "=&r" (msr), "=&r" (opid) : "r" (i));
338
339 if (strchr(modif, 'v') && !(tlbhi & TLB_VALID))
340 continue;
341
342 tlbsize = (tlbhi & TLB_SIZE_MASK) >> TLB_SIZE_SHFT;
343 /* map tlbsize 0 .. 7 to masks for 1kB .. 16MB */
344 tlbmask = ~(1 << (tlbsize * 2 + 10)) + 1;
345
346 if (have_addr && ((tlbhi & tlbmask) != (addr & tlbmask)))
347 continue;
348
349 zone = (tlblo & TLB_ZSEL_MASK) >> TLB_ZSEL_SHFT;
350 db_printf("tlb%c%2d", tlbhi & TLB_VALID ? ' ' : '*', i);
351 db_printf(" PID %3d EPN 0x%08lx %-5s",
352 pid,
353 tlbhi & tlbmask,
354 tlbsizes[tlbsize]);
355 db_printf(" RPN 0x%08lx ZONE %2d%c %s %s %c%c%c%c%c %s",
356 tlblo & tlbmask,
357 zone,
358 "NTTA"[(zpr >> ((15 - zone) * 2)) & 3],
359 tlblo & TLB_EX ? "EX" : " ",
360 tlblo & TLB_WR ? "WR" : " ",
361 tlblo & TLB_W ? 'W' : ' ',
362 tlblo & TLB_I ? 'I' : ' ',
363 tlblo & TLB_M ? 'M' : ' ',
364 tlblo & TLB_G ? 'G' : ' ',
365 tlbhi & TLB_ENDIAN ? 'E' : ' ',
366 tlbhi & TLB_U0 ? "U0" : " ");
367 db_printf("\n");
368 }
369 }
370
371 static void
372 db_ppc4xx_dcr(db_expr_t address, bool have_addr, db_expr_t count,
373 const char *modif)
374 {
375 db_expr_t new_value;
376 db_expr_t addr;
377
378 if (address < 0 || address > 0x3ff)
379 db_error("Invalid DCR address (Valid range is 0x0 - 0x3ff)\n");
380
381 addr = address;
382
383 while (db_expression(&new_value)) {
384 db_printf("dcr 0x%lx\t\t%s = ", addr,
385 db_num_to_str(db_ppc4xx_mfdcr(addr)));
386 db_ppc4xx_mtdcr(addr, new_value);
387 db_printf("%s\n", db_num_to_str(db_ppc4xx_mfdcr(addr)));
388 addr += 1;
389 }
390
391 if (addr == address) {
392 db_next = (db_addr_t)addr + 1;
393 db_prev = (db_addr_t)addr;
394 db_printf("dcr 0x%lx\t\t%s\n", addr,
395 db_num_to_str(db_ppc4xx_mfdcr(addr)));
396 } else {
397 db_next = (db_addr_t)addr;
398 db_prev = (db_addr_t)addr - 1;
399 }
400
401 db_skip_to_eol();
402 }
403
404 /*
405 * XXX Grossness Alert! XXX
406 *
407 * Please look away now if you don't like self-modifying code
408 */
409 static u_int32_t db_ppc4xx_dcrfunc[4];
410
411 static db_expr_t
412 db_ppc4xx_mfdcr(db_expr_t reg)
413 {
414 db_expr_t (*func)(void);
415
416 reg = (((reg & 0x1f) << 5) | ((reg >> 5) & 0x1f)) << 11;
417 db_ppc4xx_dcrfunc[0] = 0x7c0004ac; /* sync */
418 db_ppc4xx_dcrfunc[1] = 0x4c00012c; /* isync */
419 db_ppc4xx_dcrfunc[2] = 0x7c600286 | reg; /* mfdcr reg, r3 */
420 db_ppc4xx_dcrfunc[3] = 0x4e800020; /* blr */
421
422 __syncicache((void *)db_ppc4xx_dcrfunc, sizeof(db_ppc4xx_dcrfunc));
423 func = (db_expr_t (*)(void))(void *)db_ppc4xx_dcrfunc;
424
425 return ((*func)());
426 }
427
428 static void
429 db_ppc4xx_mtdcr(db_expr_t reg, db_expr_t val)
430 {
431 db_expr_t (*func)(db_expr_t);
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] = 0x7c600386 | reg; /* mtdcr r3, reg */
437 db_ppc4xx_dcrfunc[3] = 0x4e800020; /* blr */
438
439 __syncicache((void *)db_ppc4xx_dcrfunc, sizeof(db_ppc4xx_dcrfunc));
440 func = (db_expr_t (*)(db_expr_t))(void *)db_ppc4xx_dcrfunc;
441
442 (*func)(val);
443 }
444
445 #ifdef USERACC
446 static void
447 db_ppc4xx_useracc(db_expr_t addr, bool have_addr, db_expr_t count,
448 const char *modif)
449 {
450 static paddr_t oldaddr = -1;
451 int instr = 0;
452 int data;
453 extern vaddr_t opc_disasm(vaddr_t loc, int);
454
455
456 if (!have_addr) {
457 addr = oldaddr;
458 }
459 if (addr == -1) {
460 db_printf("no address\n");
461 return;
462 }
463 addr &= ~0x3; /* align */
464 {
465 const char *cp = modif;
466 char c;
467 while ((c = *cp++) != 0)
468 if (c == 'i')
469 instr = 1;
470 }
471 while (count--) {
472 if (db_print_position() == 0) {
473 /* Always print the address. */
474 db_printf("%8.4lx:\t", addr);
475 }
476 oldaddr=addr;
477 copyin((void *)addr, &data, sizeof(data));
478 if (instr) {
479 opc_disasm(addr, data);
480 } else {
481 db_printf("%4.4x\n", data);
482 }
483 addr += 4;
484 db_end_line();
485 }
486
487 }
488 #endif
489
490 #endif /* DDB */
491
492 #endif /* PPC_IBM4XX */
493