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