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