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