blob: 06fa44b5c647130e7beb65514d2573e15016cb02 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Routines providing a simple monitor for use on the PowerMac.
3 *
4 * Copyright (C) 1996 Paul Mackerras.
5 */
6#include <linux/config.h>
7#include <linux/errno.h>
8#include <linux/sched.h>
9#include <linux/smp.h>
10#include <linux/interrupt.h>
11#include <linux/bitops.h>
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -070012#include <linux/kallsyms.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <asm/ptrace.h>
14#include <asm/string.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include <asm/machdep.h>
16#include <asm/xmon.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include "nonstdio.h"
18#include "privinst.h"
19
20#define scanhex xmon_scanhex
21#define skipbl xmon_skipbl
22
23#ifdef CONFIG_SMP
24static unsigned long cpus_in_xmon = 0;
25static unsigned long got_xmon = 0;
26static volatile int take_xmon = -1;
27#endif /* CONFIG_SMP */
28
29static unsigned adrs;
30static int size = 1;
31static unsigned ndump = 64;
32static unsigned nidump = 16;
33static unsigned ncsum = 4096;
34static int termch;
35
36static u_int bus_error_jmp[100];
37#define setjmp xmon_setjmp
38#define longjmp xmon_longjmp
39
40/* Breakpoint stuff */
41struct bpt {
42 unsigned address;
43 unsigned instr;
44 unsigned count;
45 unsigned char enabled;
46};
47
48#define NBPTS 16
49static struct bpt bpts[NBPTS];
50static struct bpt dabr;
51static struct bpt iabr;
52static unsigned bpinstr = 0x7fe00008; /* trap */
53
54/* Prototypes */
55extern void (*debugger_fault_handler)(struct pt_regs *);
56static int cmds(struct pt_regs *);
57static int mread(unsigned, void *, int);
58static int mwrite(unsigned, void *, int);
59static void handle_fault(struct pt_regs *);
60static void byterev(unsigned char *, int);
61static void memex(void);
62static int bsesc(void);
63static void dump(void);
64static void prdump(unsigned, int);
65#ifdef __MWERKS__
66static void prndump(unsigned, int);
67static int nvreadb(unsigned);
68#endif
69static int ppc_inst_dump(unsigned, int);
70void print_address(unsigned);
71static int getsp(void);
72static void dump_hash_table(void);
73static void backtrace(struct pt_regs *);
74static void excprint(struct pt_regs *);
75static void prregs(struct pt_regs *);
76static void memops(int);
77static void memlocate(void);
78static void memzcan(void);
79static void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned);
80int skipbl(void);
81int scanhex(unsigned *valp);
82static void scannl(void);
83static int hexdigit(int);
84void getstring(char *, int);
85static void flush_input(void);
86static int inchar(void);
87static void take_input(char *);
88/* static void openforth(void); */
89static unsigned read_spr(int);
90static void write_spr(int, unsigned);
91static void super_regs(void);
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -070092static void symbol_lookup(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -070093static void remove_bpts(void);
94static void insert_bpts(void);
95static struct bpt *at_breakpoint(unsigned pc);
96static void bpt_cmds(void);
akpm@osdl.org198e2f12006-01-12 01:05:30 -080097void cacheflush(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -070098#ifdef CONFIG_SMP
99static void cpu_cmd(void);
100#endif /* CONFIG_SMP */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101static void csum(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102static void bootcmds(void);
103static void proccall(void);
104static void printtime(void);
105
106extern int print_insn_big_powerpc(FILE *, unsigned long, unsigned);
107extern void printf(const char *fmt, ...);
108extern int putchar(int ch);
109extern int setjmp(u_int *);
110extern void longjmp(u_int *, int);
111
112extern void xmon_enter(void);
113extern void xmon_leave(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114
115static unsigned start_tb[NR_CPUS][2];
116static unsigned stop_tb[NR_CPUS][2];
117
118#define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
119
120#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
121 || ('a' <= (c) && (c) <= 'f') \
122 || ('A' <= (c) && (c) <= 'F'))
123#define isalnum(c) (('0' <= (c) && (c) <= '9') \
124 || ('a' <= (c) && (c) <= 'z') \
125 || ('A' <= (c) && (c) <= 'Z'))
126#define isspace(c) (c == ' ' || c == '\t' || c == 10 || c == 13 || c == 0)
127
128static char *help_string = "\
129Commands:\n\
130 d dump bytes\n\
131 di dump instructions\n\
132 df dump float values\n\
133 dd dump double values\n\
134 e print exception information\n\
135 h dump hash table\n\
136 m examine/change memory\n\
137 mm move a block of memory\n\
138 ms set a block of memory\n\
139 md compare two blocks of memory\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 r print registers\n\
141 S print special registers\n\
142 t print backtrace\n\
Olaf Heringd49b3402005-10-28 17:46:17 -0700143 la lookup address\n\
144 ls lookup symbol\n\
145 C checksum\n\
146 p call function with arguments\n\
147 T print time\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148 x exit monitor\n\
Olaf Heringd49b3402005-10-28 17:46:17 -0700149 zr reboot\n\
150 zh halt\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151";
152
153static int xmon_trace[NR_CPUS];
154#define SSTEP 1 /* stepping because of 's' command */
155#define BRSTEP 2 /* stepping over breakpoint */
156
157static struct pt_regs *xmon_regs[NR_CPUS];
158
159extern inline void sync(void)
160{
161 asm volatile("sync; isync");
162}
163
164extern inline void __delay(unsigned int loops)
165{
166 if (loops != 0)
167 __asm__ __volatile__("mtctr %0; 1: bdnz 1b" : :
168 "r" (loops) : "ctr");
169}
170
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -0700171/* Print an address in numeric and symbolic form (if possible) */
172static void xmon_print_symbol(unsigned long address, const char *mid,
173 const char *after)
174{
175 char *modname;
176 const char *name = NULL;
177 unsigned long offset, size;
178 static char tmpstr[128];
179
180 printf("%.8lx", address);
181 if (setjmp(bus_error_jmp) == 0) {
182 debugger_fault_handler = handle_fault;
183 sync();
184 name = kallsyms_lookup(address, &size, &offset, &modname,
185 tmpstr);
186 sync();
187 /* wait a little while to see if we get a machine check */
188 __delay(200);
189 }
190 debugger_fault_handler = NULL;
191
192 if (name) {
193 printf("%s%s+%#lx/%#lx", mid, name, offset, size);
194 if (modname)
195 printf(" [%s]", modname);
196 }
197 printf("%s", after);
198}
199
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200static void get_tb(unsigned *p)
201{
202 unsigned hi, lo, hiagain;
203
204 if ((get_pvr() >> 16) == 1)
205 return;
206
207 do {
208 asm volatile("mftbu %0; mftb %1; mftbu %2"
209 : "=r" (hi), "=r" (lo), "=r" (hiagain));
210 } while (hi != hiagain);
211 p[0] = hi;
212 p[1] = lo;
213}
214
Benjamin Herrenschmidt7b007de2005-11-07 16:43:44 +1100215int xmon(struct pt_regs *excp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216{
217 struct pt_regs regs;
218 int msr, cmd;
219
220 get_tb(stop_tb[smp_processor_id()]);
221 if (excp == NULL) {
222 asm volatile ("stw 0,0(%0)\n\
223 lwz 0,0(1)\n\
224 stw 0,4(%0)\n\
225 stmw 2,8(%0)" : : "b" (&regs));
226 regs.nip = regs.link = ((unsigned long *)regs.gpr[1])[1];
227 regs.msr = get_msr();
228 regs.ctr = get_ctr();
229 regs.xer = get_xer();
230 regs.ccr = get_cr();
231 regs.trap = 0;
232 excp = &regs;
233 }
234
235 msr = get_msr();
236 set_msr(msr & ~0x8000); /* disable interrupts */
237 xmon_regs[smp_processor_id()] = excp;
238 xmon_enter();
239 excprint(excp);
240#ifdef CONFIG_SMP
241 if (test_and_set_bit(smp_processor_id(), &cpus_in_xmon))
242 for (;;)
243 ;
244 while (test_and_set_bit(0, &got_xmon)) {
245 if (take_xmon == smp_processor_id()) {
246 take_xmon = -1;
247 break;
248 }
249 }
250 /*
251 * XXX: breakpoints are removed while any cpu is in xmon
252 */
253#endif /* CONFIG_SMP */
254 remove_bpts();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 cmd = cmds(excp);
256 if (cmd == 's') {
257 xmon_trace[smp_processor_id()] = SSTEP;
258 excp->msr |= 0x400;
259 } else if (at_breakpoint(excp->nip)) {
260 xmon_trace[smp_processor_id()] = BRSTEP;
261 excp->msr |= 0x400;
262 } else {
263 xmon_trace[smp_processor_id()] = 0;
264 insert_bpts();
265 }
266 xmon_leave();
267 xmon_regs[smp_processor_id()] = NULL;
268#ifdef CONFIG_SMP
269 clear_bit(0, &got_xmon);
270 clear_bit(smp_processor_id(), &cpus_in_xmon);
271#endif /* CONFIG_SMP */
272 set_msr(msr); /* restore interrupt enable */
273 get_tb(start_tb[smp_processor_id()]);
Benjamin Herrenschmidt7b007de2005-11-07 16:43:44 +1100274
275 return cmd != 'X';
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276}
277
278irqreturn_t
279xmon_irq(int irq, void *d, struct pt_regs *regs)
280{
281 unsigned long flags;
282 local_irq_save(flags);
283 printf("Keyboard interrupt\n");
284 xmon(regs);
285 local_irq_restore(flags);
286 return IRQ_HANDLED;
287}
288
289int
290xmon_bpt(struct pt_regs *regs)
291{
292 struct bpt *bp;
293
294 bp = at_breakpoint(regs->nip);
295 if (!bp)
296 return 0;
297 if (bp->count) {
298 --bp->count;
299 remove_bpts();
300 excprint(regs);
301 xmon_trace[smp_processor_id()] = BRSTEP;
302 regs->msr |= 0x400;
303 } else {
304 xmon(regs);
305 }
306 return 1;
307}
308
309int
310xmon_sstep(struct pt_regs *regs)
311{
312 if (!xmon_trace[smp_processor_id()])
313 return 0;
314 if (xmon_trace[smp_processor_id()] == BRSTEP) {
315 xmon_trace[smp_processor_id()] = 0;
316 insert_bpts();
317 } else {
318 xmon(regs);
319 }
320 return 1;
321}
322
323int
324xmon_dabr_match(struct pt_regs *regs)
325{
326 if (dabr.enabled && dabr.count) {
327 --dabr.count;
328 remove_bpts();
329 excprint(regs);
330 xmon_trace[smp_processor_id()] = BRSTEP;
331 regs->msr |= 0x400;
332 } else {
333 dabr.instr = regs->nip;
334 xmon(regs);
335 }
336 return 1;
337}
338
339int
340xmon_iabr_match(struct pt_regs *regs)
341{
342 if (iabr.enabled && iabr.count) {
343 --iabr.count;
344 remove_bpts();
345 excprint(regs);
346 xmon_trace[smp_processor_id()] = BRSTEP;
347 regs->msr |= 0x400;
348 } else {
349 xmon(regs);
350 }
351 return 1;
352}
353
354static struct bpt *
355at_breakpoint(unsigned pc)
356{
357 int i;
358 struct bpt *bp;
359
360 if (dabr.enabled && pc == dabr.instr)
361 return &dabr;
362 if (iabr.enabled && pc == iabr.address)
363 return &iabr;
364 bp = bpts;
365 for (i = 0; i < NBPTS; ++i, ++bp)
366 if (bp->enabled && pc == bp->address)
367 return bp;
368 return NULL;
369}
370
371static void
372insert_bpts(void)
373{
374 int i;
375 struct bpt *bp;
376
377 bp = bpts;
378 for (i = 0; i < NBPTS; ++i, ++bp) {
379 if (!bp->enabled)
380 continue;
381 if (mread(bp->address, &bp->instr, 4) != 4
382 || mwrite(bp->address, &bpinstr, 4) != 4) {
383 printf("Couldn't insert breakpoint at %x, disabling\n",
384 bp->address);
385 bp->enabled = 0;
386 }
387 store_inst((void *) bp->address);
388 }
389#if !defined(CONFIG_8xx)
390 if (dabr.enabled)
391 set_dabr(dabr.address);
392 if (iabr.enabled)
393 set_iabr(iabr.address);
394#endif
395}
396
397static void
398remove_bpts(void)
399{
400 int i;
401 struct bpt *bp;
402 unsigned instr;
403
404#if !defined(CONFIG_8xx)
405 set_dabr(0);
406 set_iabr(0);
407#endif
408 bp = bpts;
409 for (i = 0; i < NBPTS; ++i, ++bp) {
410 if (!bp->enabled)
411 continue;
412 if (mread(bp->address, &instr, 4) == 4
413 && instr == bpinstr
414 && mwrite(bp->address, &bp->instr, 4) != 4)
415 printf("Couldn't remove breakpoint at %x\n",
416 bp->address);
417 store_inst((void *) bp->address);
418 }
419}
420
421static char *last_cmd;
422
423/* Command interpreting routine */
424static int
425cmds(struct pt_regs *excp)
426{
427 int cmd;
428
429 last_cmd = NULL;
430 for(;;) {
431#ifdef CONFIG_SMP
432 printf("%d:", smp_processor_id());
433#endif /* CONFIG_SMP */
434 printf("mon> ");
435 fflush(stdout);
436 flush_input();
437 termch = 0;
438 cmd = skipbl();
439 if( cmd == '\n' ) {
440 if (last_cmd == NULL)
441 continue;
442 take_input(last_cmd);
443 last_cmd = NULL;
444 cmd = inchar();
445 }
446 switch (cmd) {
447 case 'm':
448 cmd = inchar();
449 switch (cmd) {
450 case 'm':
451 case 's':
452 case 'd':
453 memops(cmd);
454 break;
455 case 'l':
456 memlocate();
457 break;
458 case 'z':
459 memzcan();
460 break;
461 default:
462 termch = cmd;
463 memex();
464 }
465 break;
466 case 'd':
467 dump();
468 break;
469 case 'l':
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -0700470 symbol_lookup();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 break;
472 case 'r':
473 if (excp != NULL)
474 prregs(excp); /* print regs */
475 break;
476 case 'e':
477 if (excp == NULL)
478 printf("No exception information\n");
479 else
480 excprint(excp);
481 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 case 'S':
483 super_regs();
484 break;
485 case 't':
486 backtrace(excp);
487 break;
488 case 'f':
489 cacheflush();
490 break;
491 case 'h':
492 dump_hash_table();
493 break;
494 case 's':
495 case 'x':
496 case EOF:
497 return cmd;
498 case '?':
499 printf(help_string);
500 break;
501 default:
502 printf("Unrecognized command: ");
503 if( ' ' < cmd && cmd <= '~' )
504 putchar(cmd);
505 else
506 printf("\\x%x", cmd);
507 printf(" (type ? for help)\n");
508 break;
509 case 'b':
510 bpt_cmds();
511 break;
512 case 'C':
513 csum();
514 break;
515#ifdef CONFIG_SMP
516 case 'c':
517 cpu_cmd();
518 break;
519#endif /* CONFIG_SMP */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 case 'z':
521 bootcmds();
522 break;
523 case 'p':
524 proccall();
525 break;
526 case 'T':
527 printtime();
528 break;
529 }
530 }
531}
532
533extern unsigned tb_to_us;
534
535#define mulhwu(x,y) \
536({unsigned z; asm ("mulhwu %0,%1,%2" : "=r" (z) : "r" (x), "r" (y)); z;})
537
538static void printtime(void)
539{
540 unsigned int delta;
541
542 delta = stop_tb[smp_processor_id()][1]
543 - start_tb[smp_processor_id()][1];
544 delta = mulhwu(tb_to_us, delta);
545 printf("%u.%06u seconds\n", delta / 1000000, delta % 1000000);
546}
547
548static void bootcmds(void)
549{
550 int cmd;
551
552 cmd = inchar();
553 if (cmd == 'r')
554 ppc_md.restart(NULL);
555 else if (cmd == 'h')
556 ppc_md.halt();
557 else if (cmd == 'p')
558 ppc_md.power_off();
559}
560
561#ifdef CONFIG_SMP
562static void cpu_cmd(void)
563{
564 unsigned cpu;
565 int timeout;
566 int cmd;
567
568 cmd = inchar();
569 if (cmd == 'i') {
570 /* interrupt other cpu(s) */
571 cpu = MSG_ALL_BUT_SELF;
572 if (scanhex(&cpu))
573 smp_send_xmon_break(cpu);
574 return;
575 }
576 termch = cmd;
577 if (!scanhex(&cpu)) {
578 /* print cpus waiting or in xmon */
579 printf("cpus stopped:");
580 for (cpu = 0; cpu < NR_CPUS; ++cpu) {
581 if (test_bit(cpu, &cpus_in_xmon)) {
582 printf(" %d", cpu);
583 if (cpu == smp_processor_id())
584 printf("*", cpu);
585 }
586 }
587 printf("\n");
588 return;
589 }
590 /* try to switch to cpu specified */
591 take_xmon = cpu;
592 timeout = 10000000;
593 while (take_xmon >= 0) {
594 if (--timeout == 0) {
595 /* yes there's a race here */
596 take_xmon = -1;
597 printf("cpu %u didn't take control\n", cpu);
598 return;
599 }
600 }
601 /* now have to wait to be given control back */
602 while (test_and_set_bit(0, &got_xmon)) {
603 if (take_xmon == smp_processor_id()) {
604 take_xmon = -1;
605 break;
606 }
607 }
608}
609#endif /* CONFIG_SMP */
610
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611
612static unsigned short fcstab[256] = {
613 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
614 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
615 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
616 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
617 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
618 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
619 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
620 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
621 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
622 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
623 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
624 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
625 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
626 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
627 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
628 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
629 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
630 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
631 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
632 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
633 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
634 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
635 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
636 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
637 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
638 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
639 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
640 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
641 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
642 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
643 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
644 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
645};
646
647#define FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
648
649static void
650csum(void)
651{
652 unsigned int i;
653 unsigned short fcs;
654 unsigned char v;
655
656 if (!scanhex(&adrs))
657 return;
658 if (!scanhex(&ncsum))
659 return;
660 fcs = 0xffff;
661 for (i = 0; i < ncsum; ++i) {
662 if (mread(adrs+i, &v, 1) == 0) {
663 printf("csum stopped at %x\n", adrs+i);
664 break;
665 }
666 fcs = FCS(fcs, v);
667 }
668 printf("%x\n", fcs);
669}
670
671static void
672bpt_cmds(void)
673{
674 int cmd;
675 unsigned a;
676 int mode, i;
677 struct bpt *bp;
678
679 cmd = inchar();
680 switch (cmd) {
681#if !defined(CONFIG_8xx)
682 case 'd':
683 mode = 7;
684 cmd = inchar();
685 if (cmd == 'r')
686 mode = 5;
687 else if (cmd == 'w')
688 mode = 6;
689 else
690 termch = cmd;
691 cmd = inchar();
692 if (cmd == 'p')
693 mode &= ~4;
694 else
695 termch = cmd;
696 dabr.address = 0;
697 dabr.count = 0;
698 dabr.enabled = scanhex(&dabr.address);
699 scanhex(&dabr.count);
700 if (dabr.enabled)
701 dabr.address = (dabr.address & ~7) | mode;
702 break;
703 case 'i':
704 cmd = inchar();
705 if (cmd == 'p')
706 mode = 2;
707 else
708 mode = 3;
709 iabr.address = 0;
710 iabr.count = 0;
711 iabr.enabled = scanhex(&iabr.address);
712 if (iabr.enabled)
713 iabr.address |= mode;
714 scanhex(&iabr.count);
715 break;
716#endif
717 case 'c':
718 if (!scanhex(&a)) {
719 /* clear all breakpoints */
720 for (i = 0; i < NBPTS; ++i)
721 bpts[i].enabled = 0;
722 iabr.enabled = 0;
723 dabr.enabled = 0;
724 printf("All breakpoints cleared\n");
725 } else {
726 bp = at_breakpoint(a);
727 if (bp == 0) {
728 printf("No breakpoint at %x\n", a);
729 } else {
730 bp->enabled = 0;
731 }
732 }
733 break;
734 default:
735 termch = cmd;
736 if (!scanhex(&a)) {
737 /* print all breakpoints */
738 printf("type address count\n");
739 if (dabr.enabled) {
740 printf("data %.8x %8x [", dabr.address & ~7,
741 dabr.count);
742 if (dabr.address & 1)
743 printf("r");
744 if (dabr.address & 2)
745 printf("w");
746 if (!(dabr.address & 4))
747 printf("p");
748 printf("]\n");
749 }
750 if (iabr.enabled)
751 printf("inst %.8x %8x\n", iabr.address & ~3,
752 iabr.count);
753 for (bp = bpts; bp < &bpts[NBPTS]; ++bp)
754 if (bp->enabled)
755 printf("trap %.8x %8x\n", bp->address,
756 bp->count);
757 break;
758 }
759 bp = at_breakpoint(a);
760 if (bp == 0) {
761 for (bp = bpts; bp < &bpts[NBPTS]; ++bp)
762 if (!bp->enabled)
763 break;
764 if (bp >= &bpts[NBPTS]) {
765 printf("Sorry, no free breakpoints\n");
766 break;
767 }
768 }
769 bp->enabled = 1;
770 bp->address = a;
771 bp->count = 0;
772 scanhex(&bp->count);
773 break;
774 }
775}
776
777static void
778backtrace(struct pt_regs *excp)
779{
780 unsigned sp;
781 unsigned stack[2];
782 struct pt_regs regs;
783 extern char ret_from_except, ret_from_except_full, ret_from_syscall;
784
785 printf("backtrace:\n");
786
787 if (excp != NULL)
788 sp = excp->gpr[1];
789 else
790 sp = getsp();
791 scanhex(&sp);
792 scannl();
793 for (; sp != 0; sp = stack[0]) {
794 if (mread(sp, stack, sizeof(stack)) != sizeof(stack))
795 break;
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -0700796 printf("[%.8lx] ", stack);
797 xmon_print_symbol(stack[1], " ", "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 if (stack[1] == (unsigned) &ret_from_except
799 || stack[1] == (unsigned) &ret_from_except_full
800 || stack[1] == (unsigned) &ret_from_syscall) {
801 if (mread(sp+16, &regs, sizeof(regs)) != sizeof(regs))
802 break;
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -0700803 printf("exception:%x [%x] %x\n", regs.trap, sp+16,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 regs.nip);
805 sp = regs.gpr[1];
806 if (mread(sp, stack, sizeof(stack)) != sizeof(stack))
807 break;
808 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 }
810}
811
812int
813getsp(void)
814{
815 int x;
816
817 asm("mr %0,1" : "=r" (x) :);
818 return x;
819}
820
821void
822excprint(struct pt_regs *fp)
823{
824 int trap;
825
826#ifdef CONFIG_SMP
827 printf("cpu %d: ", smp_processor_id());
828#endif /* CONFIG_SMP */
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -0700829 printf("vector: %x at pc=", fp->trap);
830 xmon_print_symbol(fp->nip, ": ", ", lr=");
831 xmon_print_symbol(fp->link, ": ", "\n");
832 printf("msr = %x, sp = %x [%x]\n", fp->msr, fp->gpr[1], fp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 trap = TRAP(fp);
834 if (trap == 0x300 || trap == 0x600)
835 printf("dar = %x, dsisr = %x\n", fp->dar, fp->dsisr);
836 if (current)
837 printf("current = %x, pid = %d, comm = %s\n",
838 current, current->pid, current->comm);
839}
840
841void
842prregs(struct pt_regs *fp)
843{
844 int n;
845 unsigned base;
846
847 if (scanhex(&base))
848 fp = (struct pt_regs *) base;
849 for (n = 0; n < 32; ++n) {
850 printf("R%.2d = %.8x%s", n, fp->gpr[n],
851 (n & 3) == 3? "\n": " ");
852 if (n == 12 && !FULL_REGS(fp)) {
853 printf("\n");
854 break;
855 }
856 }
857 printf("pc = %.8x msr = %.8x lr = %.8x cr = %.8x\n",
858 fp->nip, fp->msr, fp->link, fp->ccr);
859 printf("ctr = %.8x xer = %.8x trap = %4x\n",
860 fp->ctr, fp->xer, fp->trap);
861}
862
863void
864cacheflush(void)
865{
866 int cmd;
867 unsigned nflush;
868
869 cmd = inchar();
870 if (cmd != 'i')
871 termch = cmd;
872 scanhex(&adrs);
873 if (termch != '\n')
874 termch = 0;
875 nflush = 1;
876 scanhex(&nflush);
877 nflush = (nflush + 31) / 32;
878 if (cmd != 'i') {
879 for (; nflush > 0; --nflush, adrs += 0x20)
880 cflush((void *) adrs);
881 } else {
882 for (; nflush > 0; --nflush, adrs += 0x20)
883 cinval((void *) adrs);
884 }
885}
886
887unsigned int
888read_spr(int n)
889{
890 unsigned int instrs[2];
891 int (*code)(void);
892
893 instrs[0] = 0x7c6002a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
894 instrs[1] = 0x4e800020;
895 store_inst(instrs);
896 store_inst(instrs+1);
897 code = (int (*)(void)) instrs;
898 return code();
899}
900
901void
902write_spr(int n, unsigned int val)
903{
904 unsigned int instrs[2];
905 int (*code)(unsigned int);
906
907 instrs[0] = 0x7c6003a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
908 instrs[1] = 0x4e800020;
909 store_inst(instrs);
910 store_inst(instrs+1);
911 code = (int (*)(unsigned int)) instrs;
912 code(val);
913}
914
915static unsigned int regno;
916extern char exc_prolog;
917extern char dec_exc;
918
919void
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920super_regs(void)
921{
922 int i, cmd;
923 unsigned val;
924
925 cmd = skipbl();
926 if (cmd == '\n') {
927 printf("msr = %x, pvr = %x\n", get_msr(), get_pvr());
928 printf("sprg0-3 = %x %x %x %x\n", get_sprg0(), get_sprg1(),
929 get_sprg2(), get_sprg3());
930 printf("srr0 = %x, srr1 = %x\n", get_srr0(), get_srr1());
931#ifdef CONFIG_PPC_STD_MMU
932 printf("sr0-15 =");
933 for (i = 0; i < 16; ++i)
934 printf(" %x", get_sr(i));
935 printf("\n");
936#endif
937 asm("mr %0,1" : "=r" (i) :);
938 printf("sp = %x ", i);
939 asm("mr %0,2" : "=r" (i) :);
940 printf("toc = %x\n", i);
941 return;
942 }
943
944 scanhex(&regno);
945 switch (cmd) {
946 case 'w':
947 val = read_spr(regno);
948 scanhex(&val);
949 write_spr(regno, val);
950 /* fall through */
951 case 'r':
952 printf("spr %x = %x\n", regno, read_spr(regno));
953 break;
954 case 's':
955 val = get_sr(regno);
956 scanhex(&val);
957 set_sr(regno, val);
958 break;
959 case 'm':
960 val = get_msr();
961 scanhex(&val);
962 set_msr(val);
963 break;
964 }
965 scannl();
966}
967
968#ifndef CONFIG_PPC_STD_MMU
969static void
970dump_hash_table(void)
971{
972 printf("This CPU doesn't have a hash table.\n");
973}
974#else
975
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976static void
977dump_hash_table_seg(unsigned seg, unsigned start, unsigned end)
978{
979 extern void *Hash;
980 extern unsigned long Hash_size;
981 unsigned *htab = Hash;
982 unsigned hsize = Hash_size;
983 unsigned v, hmask, va, last_va = 0;
984 int found, last_found, i;
985 unsigned *hg, w1, last_w2 = 0, last_va0 = 0;
986
987 last_found = 0;
988 hmask = hsize / 64 - 1;
989 va = start;
990 start = (start >> 12) & 0xffff;
991 end = (end >> 12) & 0xffff;
992 for (v = start; v < end; ++v) {
993 found = 0;
994 hg = htab + (((v ^ seg) & hmask) * 16);
995 w1 = 0x80000000 | (seg << 7) | (v >> 10);
996 for (i = 0; i < 8; ++i, hg += 2) {
997 if (*hg == w1) {
998 found = 1;
999 break;
1000 }
1001 }
1002 if (!found) {
1003 w1 ^= 0x40;
1004 hg = htab + ((~(v ^ seg) & hmask) * 16);
1005 for (i = 0; i < 8; ++i, hg += 2) {
1006 if (*hg == w1) {
1007 found = 1;
1008 break;
1009 }
1010 }
1011 }
1012 if (!(last_found && found && (hg[1] & ~0x180) == last_w2 + 4096)) {
1013 if (last_found) {
1014 if (last_va != last_va0)
1015 printf(" ... %x", last_va);
1016 printf("\n");
1017 }
1018 if (found) {
1019 printf("%x to %x", va, hg[1]);
1020 last_va0 = va;
1021 }
1022 last_found = found;
1023 }
1024 if (found) {
1025 last_w2 = hg[1] & ~0x180;
1026 last_va = va;
1027 }
1028 va += 4096;
1029 }
1030 if (last_found)
1031 printf(" ... %x\n", last_va);
1032}
1033
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034static unsigned hash_ctx;
1035static unsigned hash_start;
1036static unsigned hash_end;
1037
1038static void
1039dump_hash_table(void)
1040{
1041 int seg;
1042 unsigned seg_start, seg_end;
1043
1044 hash_ctx = 0;
1045 hash_start = 0;
1046 hash_end = 0xfffff000;
1047 scanhex(&hash_ctx);
1048 scanhex(&hash_start);
1049 scanhex(&hash_end);
1050 printf("Mappings for context %x\n", hash_ctx);
1051 seg_start = hash_start;
1052 for (seg = hash_start >> 28; seg <= hash_end >> 28; ++seg) {
1053 seg_end = (seg << 28) | 0x0ffff000;
1054 if (seg_end > hash_end)
1055 seg_end = hash_end;
1056 dump_hash_table_seg((hash_ctx << 4) + (seg * 0x111),
1057 seg_start, seg_end);
1058 seg_start = seg_end + 0x1000;
1059 }
1060}
1061#endif /* CONFIG_PPC_STD_MMU */
1062
1063/*
1064 * Stuff for reading and writing memory safely
1065 */
1066
1067int
1068mread(unsigned adrs, void *buf, int size)
1069{
1070 volatile int n;
1071 char *p, *q;
1072
1073 n = 0;
1074 if( setjmp(bus_error_jmp) == 0 ){
1075 debugger_fault_handler = handle_fault;
1076 sync();
1077 p = (char *) adrs;
1078 q = (char *) buf;
1079 switch (size) {
1080 case 2: *(short *)q = *(short *)p; break;
1081 case 4: *(int *)q = *(int *)p; break;
1082 default:
1083 for( ; n < size; ++n ) {
1084 *q++ = *p++;
1085 sync();
1086 }
1087 }
1088 sync();
1089 /* wait a little while to see if we get a machine check */
1090 __delay(200);
1091 n = size;
1092 }
1093 debugger_fault_handler = NULL;
1094 return n;
1095}
1096
1097int
1098mwrite(unsigned adrs, void *buf, int size)
1099{
1100 volatile int n;
1101 char *p, *q;
1102
1103 n = 0;
1104 if( setjmp(bus_error_jmp) == 0 ){
1105 debugger_fault_handler = handle_fault;
1106 sync();
1107 p = (char *) adrs;
1108 q = (char *) buf;
1109 switch (size) {
1110 case 2: *(short *)p = *(short *)q; break;
1111 case 4: *(int *)p = *(int *)q; break;
1112 default:
1113 for( ; n < size; ++n ) {
1114 *p++ = *q++;
1115 sync();
1116 }
1117 }
1118 sync();
1119 n = size;
1120 } else {
1121 printf("*** Error writing address %x\n", adrs + n);
1122 }
1123 debugger_fault_handler = NULL;
1124 return n;
1125}
1126
1127static int fault_type;
1128static int fault_except;
1129static char *fault_chars[] = { "--", "**", "##" };
1130
1131static void
1132handle_fault(struct pt_regs *regs)
1133{
1134 fault_except = TRAP(regs);
1135 fault_type = TRAP(regs) == 0x200? 0: TRAP(regs) == 0x300? 1: 2;
1136 longjmp(bus_error_jmp, 1);
1137}
1138
1139#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t))
1140
1141void
1142byterev(unsigned char *val, int size)
1143{
1144 int t;
1145
1146 switch (size) {
1147 case 2:
1148 SWAP(val[0], val[1], t);
1149 break;
1150 case 4:
1151 SWAP(val[0], val[3], t);
1152 SWAP(val[1], val[2], t);
1153 break;
1154 }
1155}
1156
1157static int brev;
1158static int mnoread;
1159
1160void
1161memex(void)
1162{
1163 int cmd, inc, i, nslash;
1164 unsigned n;
1165 unsigned char val[4];
1166
1167 last_cmd = "m\n";
1168 scanhex(&adrs);
1169 while ((cmd = skipbl()) != '\n') {
1170 switch( cmd ){
1171 case 'b': size = 1; break;
1172 case 'w': size = 2; break;
1173 case 'l': size = 4; break;
1174 case 'r': brev = !brev; break;
1175 case 'n': mnoread = 1; break;
1176 case '.': mnoread = 0; break;
1177 }
1178 }
1179 if( size <= 0 )
1180 size = 1;
1181 else if( size > 4 )
1182 size = 4;
1183 for(;;){
1184 if (!mnoread)
1185 n = mread(adrs, val, size);
1186 printf("%.8x%c", adrs, brev? 'r': ' ');
1187 if (!mnoread) {
1188 if (brev)
1189 byterev(val, size);
1190 putchar(' ');
1191 for (i = 0; i < n; ++i)
1192 printf("%.2x", val[i]);
1193 for (; i < size; ++i)
1194 printf("%s", fault_chars[fault_type]);
1195 }
1196 putchar(' ');
1197 inc = size;
1198 nslash = 0;
1199 for(;;){
1200 if( scanhex(&n) ){
1201 for (i = 0; i < size; ++i)
1202 val[i] = n >> (i * 8);
1203 if (!brev)
1204 byterev(val, size);
1205 mwrite(adrs, val, size);
1206 inc = size;
1207 }
1208 cmd = skipbl();
1209 if (cmd == '\n')
1210 break;
1211 inc = 0;
1212 switch (cmd) {
1213 case '\'':
1214 for(;;){
1215 n = inchar();
1216 if( n == '\\' )
1217 n = bsesc();
1218 else if( n == '\'' )
1219 break;
1220 for (i = 0; i < size; ++i)
1221 val[i] = n >> (i * 8);
1222 if (!brev)
1223 byterev(val, size);
1224 mwrite(adrs, val, size);
1225 adrs += size;
1226 }
1227 adrs -= size;
1228 inc = size;
1229 break;
1230 case ',':
1231 adrs += size;
1232 break;
1233 case '.':
1234 mnoread = 0;
1235 break;
1236 case ';':
1237 break;
1238 case 'x':
1239 case EOF:
1240 scannl();
1241 return;
1242 case 'b':
1243 case 'v':
1244 size = 1;
1245 break;
1246 case 'w':
1247 size = 2;
1248 break;
1249 case 'l':
1250 size = 4;
1251 break;
1252 case '^':
1253 adrs -= size;
1254 break;
1255 break;
1256 case '/':
1257 if (nslash > 0)
1258 adrs -= 1 << nslash;
1259 else
1260 nslash = 0;
1261 nslash += 4;
1262 adrs += 1 << nslash;
1263 break;
1264 case '\\':
1265 if (nslash < 0)
1266 adrs += 1 << -nslash;
1267 else
1268 nslash = 0;
1269 nslash -= 4;
1270 adrs -= 1 << -nslash;
1271 break;
1272 case 'm':
1273 scanhex(&adrs);
1274 break;
1275 case 'n':
1276 mnoread = 1;
1277 break;
1278 case 'r':
1279 brev = !brev;
1280 break;
1281 case '<':
1282 n = size;
1283 scanhex(&n);
1284 adrs -= n;
1285 break;
1286 case '>':
1287 n = size;
1288 scanhex(&n);
1289 adrs += n;
1290 break;
1291 }
1292 }
1293 adrs += inc;
1294 }
1295}
1296
1297int
1298bsesc(void)
1299{
1300 int c;
1301
1302 c = inchar();
1303 switch( c ){
1304 case 'n': c = '\n'; break;
1305 case 'r': c = '\r'; break;
1306 case 'b': c = '\b'; break;
1307 case 't': c = '\t'; break;
1308 }
1309 return c;
1310}
1311
1312void
1313dump(void)
1314{
1315 int c;
1316
1317 c = inchar();
1318 if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
1319 termch = c;
1320 scanhex(&adrs);
1321 if( termch != '\n')
1322 termch = 0;
1323 if( c == 'i' ){
1324 scanhex(&nidump);
1325 if( nidump == 0 )
1326 nidump = 16;
1327 adrs += ppc_inst_dump(adrs, nidump);
1328 last_cmd = "di\n";
1329 } else {
1330 scanhex(&ndump);
1331 if( ndump == 0 )
1332 ndump = 64;
1333 prdump(adrs, ndump);
1334 adrs += ndump;
1335 last_cmd = "d\n";
1336 }
1337}
1338
1339void
1340prdump(unsigned adrs, int ndump)
1341{
1342 register int n, m, c, r, nr;
1343 unsigned char temp[16];
1344
1345 for( n = ndump; n > 0; ){
1346 printf("%.8x", adrs);
1347 putchar(' ');
1348 r = n < 16? n: 16;
1349 nr = mread(adrs, temp, r);
1350 adrs += nr;
1351 for( m = 0; m < r; ++m ){
1352 putchar((m & 3) == 0 && m > 0? '.': ' ');
1353 if( m < nr )
1354 printf("%.2x", temp[m]);
1355 else
1356 printf("%s", fault_chars[fault_type]);
1357 }
1358 for(; m < 16; ++m )
1359 printf(" ");
1360 printf(" |");
1361 for( m = 0; m < r; ++m ){
1362 if( m < nr ){
1363 c = temp[m];
1364 putchar(' ' <= c && c <= '~'? c: '.');
1365 } else
1366 putchar(' ');
1367 }
1368 n -= r;
1369 for(; m < 16; ++m )
1370 putchar(' ');
1371 printf("|\n");
1372 if( nr < r )
1373 break;
1374 }
1375}
1376
1377int
1378ppc_inst_dump(unsigned adr, int count)
1379{
1380 int nr, dotted;
1381 unsigned first_adr;
1382 unsigned long inst, last_inst = 0;
1383 unsigned char val[4];
1384
1385 dotted = 0;
1386 for (first_adr = adr; count > 0; --count, adr += 4){
1387 nr = mread(adr, val, 4);
1388 if( nr == 0 ){
1389 const char *x = fault_chars[fault_type];
1390 printf("%.8x %s%s%s%s\n", adr, x, x, x, x);
1391 break;
1392 }
1393 inst = GETWORD(val);
1394 if (adr > first_adr && inst == last_inst) {
1395 if (!dotted) {
1396 printf(" ...\n");
1397 dotted = 1;
1398 }
1399 continue;
1400 }
1401 dotted = 0;
1402 last_inst = inst;
1403 printf("%.8x ", adr);
1404 printf("%.8x\t", inst);
1405 print_insn_big_powerpc(stdout, inst, adr); /* always returns 4 */
1406 printf("\n");
1407 }
1408 return adr - first_adr;
1409}
1410
1411void
1412print_address(unsigned addr)
1413{
1414 printf("0x%x", addr);
1415}
1416
1417/*
1418 * Memory operations - move, set, print differences
1419 */
1420static unsigned mdest; /* destination address */
1421static unsigned msrc; /* source address */
1422static unsigned mval; /* byte value to set memory to */
1423static unsigned mcount; /* # bytes to affect */
1424static unsigned mdiffs; /* max # differences to print */
1425
1426void
1427memops(int cmd)
1428{
1429 scanhex(&mdest);
1430 if( termch != '\n' )
1431 termch = 0;
1432 scanhex(cmd == 's'? &mval: &msrc);
1433 if( termch != '\n' )
1434 termch = 0;
1435 scanhex(&mcount);
1436 switch( cmd ){
1437 case 'm':
1438 memmove((void *)mdest, (void *)msrc, mcount);
1439 break;
1440 case 's':
1441 memset((void *)mdest, mval, mcount);
1442 break;
1443 case 'd':
1444 if( termch != '\n' )
1445 termch = 0;
1446 scanhex(&mdiffs);
1447 memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
1448 break;
1449 }
1450}
1451
1452void
1453memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
1454{
1455 unsigned n, prt;
1456
1457 prt = 0;
1458 for( n = nb; n > 0; --n )
1459 if( *p1++ != *p2++ )
1460 if( ++prt <= maxpr )
1461 printf("%.8x %.2x # %.8x %.2x\n", (unsigned)p1 - 1,
1462 p1[-1], (unsigned)p2 - 1, p2[-1]);
1463 if( prt > maxpr )
1464 printf("Total of %d differences\n", prt);
1465}
1466
1467static unsigned mend;
1468static unsigned mask;
1469
1470void
1471memlocate(void)
1472{
1473 unsigned a, n;
1474 unsigned char val[4];
1475
1476 last_cmd = "ml";
1477 scanhex(&mdest);
1478 if (termch != '\n') {
1479 termch = 0;
1480 scanhex(&mend);
1481 if (termch != '\n') {
1482 termch = 0;
1483 scanhex(&mval);
1484 mask = ~0;
1485 if (termch != '\n') termch = 0;
1486 scanhex(&mask);
1487 }
1488 }
1489 n = 0;
1490 for (a = mdest; a < mend; a += 4) {
1491 if (mread(a, val, 4) == 4
1492 && ((GETWORD(val) ^ mval) & mask) == 0) {
1493 printf("%.8x: %.8x\n", a, GETWORD(val));
1494 if (++n >= 10)
1495 break;
1496 }
1497 }
1498}
1499
1500static unsigned mskip = 0x1000;
1501static unsigned mlim = 0xffffffff;
1502
1503void
1504memzcan(void)
1505{
1506 unsigned char v;
1507 unsigned a;
1508 int ok, ook;
1509
1510 scanhex(&mdest);
1511 if (termch != '\n') termch = 0;
1512 scanhex(&mskip);
1513 if (termch != '\n') termch = 0;
1514 scanhex(&mlim);
1515 ook = 0;
1516 for (a = mdest; a < mlim; a += mskip) {
1517 ok = mread(a, &v, 1);
1518 if (ok && !ook) {
1519 printf("%.8x .. ", a);
1520 fflush(stdout);
1521 } else if (!ok && ook)
1522 printf("%.8x\n", a - mskip);
1523 ook = ok;
1524 if (a + mskip < a)
1525 break;
1526 }
1527 if (ook)
1528 printf("%.8x\n", a - mskip);
1529}
1530
1531void proccall(void)
1532{
1533 unsigned int args[8];
1534 unsigned int ret;
1535 int i;
1536 typedef unsigned int (*callfunc_t)(unsigned int, unsigned int,
1537 unsigned int, unsigned int, unsigned int,
1538 unsigned int, unsigned int, unsigned int);
1539 callfunc_t func;
1540
1541 scanhex(&adrs);
1542 if (termch != '\n')
1543 termch = 0;
1544 for (i = 0; i < 8; ++i)
1545 args[i] = 0;
1546 for (i = 0; i < 8; ++i) {
1547 if (!scanhex(&args[i]) || termch == '\n')
1548 break;
1549 termch = 0;
1550 }
1551 func = (callfunc_t) adrs;
1552 ret = 0;
1553 if (setjmp(bus_error_jmp) == 0) {
1554 debugger_fault_handler = handle_fault;
1555 sync();
1556 ret = func(args[0], args[1], args[2], args[3],
1557 args[4], args[5], args[6], args[7]);
1558 sync();
1559 printf("return value is %x\n", ret);
1560 } else {
1561 printf("*** %x exception occurred\n", fault_except);
1562 }
1563 debugger_fault_handler = NULL;
1564}
1565
1566/* Input scanning routines */
1567int
1568skipbl(void)
1569{
1570 int c;
1571
1572 if( termch != 0 ){
1573 c = termch;
1574 termch = 0;
1575 } else
1576 c = inchar();
1577 while( c == ' ' || c == '\t' )
1578 c = inchar();
1579 return c;
1580}
1581
1582#define N_PTREGS 44
1583static char *regnames[N_PTREGS] = {
1584 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
1585 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
1586 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
1587 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
1588 "pc", "msr", "or3", "ctr", "lr", "xer", "ccr", "mq",
1589 "trap", "dar", "dsisr", "res"
1590};
1591
1592int
1593scanhex(unsigned *vp)
1594{
1595 int c, d;
1596 unsigned v;
1597
1598 c = skipbl();
1599 if (c == '%') {
1600 /* parse register name */
1601 char regname[8];
1602 int i;
1603
1604 for (i = 0; i < sizeof(regname) - 1; ++i) {
1605 c = inchar();
1606 if (!isalnum(c)) {
1607 termch = c;
1608 break;
1609 }
1610 regname[i] = c;
1611 }
1612 regname[i] = 0;
1613 for (i = 0; i < N_PTREGS; ++i) {
1614 if (strcmp(regnames[i], regname) == 0) {
1615 unsigned *rp = (unsigned *)
1616 xmon_regs[smp_processor_id()];
1617 if (rp == NULL) {
1618 printf("regs not available\n");
1619 return 0;
1620 }
1621 *vp = rp[i];
1622 return 1;
1623 }
1624 }
1625 printf("invalid register name '%%%s'\n", regname);
1626 return 0;
1627 } else if (c == '$') {
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07001628 static char symname[128];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 int i;
1630 for (i=0; i<63; i++) {
1631 c = inchar();
1632 if (isspace(c)) {
1633 termch = c;
1634 break;
1635 }
1636 symname[i] = c;
1637 }
1638 symname[i++] = 0;
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07001639 *vp = 0;
1640 if (setjmp(bus_error_jmp) == 0) {
1641 debugger_fault_handler = handle_fault;
1642 sync();
1643 *vp = kallsyms_lookup_name(symname);
1644 sync();
1645 }
1646 debugger_fault_handler = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647 if (!(*vp)) {
1648 printf("unknown symbol\n");
1649 return 0;
1650 }
1651 return 1;
1652 }
1653
1654 d = hexdigit(c);
1655 if( d == EOF ){
1656 termch = c;
1657 return 0;
1658 }
1659 v = 0;
1660 do {
1661 v = (v << 4) + d;
1662 c = inchar();
1663 d = hexdigit(c);
1664 } while( d != EOF );
1665 termch = c;
1666 *vp = v;
1667 return 1;
1668}
1669
1670void
1671scannl(void)
1672{
1673 int c;
1674
1675 c = termch;
1676 termch = 0;
1677 while( c != '\n' )
1678 c = inchar();
1679}
1680
1681int hexdigit(int c)
1682{
1683 if( '0' <= c && c <= '9' )
1684 return c - '0';
1685 if( 'A' <= c && c <= 'F' )
1686 return c - ('A' - 10);
1687 if( 'a' <= c && c <= 'f' )
1688 return c - ('a' - 10);
1689 return EOF;
1690}
1691
1692void
1693getstring(char *s, int size)
1694{
1695 int c;
1696
1697 c = skipbl();
1698 do {
1699 if( size > 1 ){
1700 *s++ = c;
1701 --size;
1702 }
1703 c = inchar();
1704 } while( c != ' ' && c != '\t' && c != '\n' );
1705 termch = c;
1706 *s = 0;
1707}
1708
1709static char line[256];
1710static char *lineptr;
1711
1712void
1713flush_input(void)
1714{
1715 lineptr = NULL;
1716}
1717
1718int
1719inchar(void)
1720{
1721 if (lineptr == NULL || *lineptr == 0) {
1722 if (fgets(line, sizeof(line), stdin) == NULL) {
1723 lineptr = NULL;
1724 return EOF;
1725 }
1726 lineptr = line;
1727 }
1728 return *lineptr++;
1729}
1730
1731void
1732take_input(char *str)
1733{
1734 lineptr = str;
1735}
1736
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07001737static void
1738symbol_lookup(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739{
1740 int type = inchar();
1741 unsigned addr;
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07001742 static char tmp[128];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07001744 switch (type) {
1745 case 'a':
1746 if (scanhex(&addr))
1747 xmon_print_symbol(addr, ": ", "\n");
1748 termch = 0;
1749 break;
1750 case 's':
1751 getstring(tmp, 64);
1752 if (setjmp(bus_error_jmp) == 0) {
1753 debugger_fault_handler = handle_fault;
1754 sync();
1755 addr = kallsyms_lookup_name(tmp);
1756 if (addr)
1757 printf("%s: %lx\n", tmp, addr);
1758 else
1759 printf("Symbol '%s' not found.\n", tmp);
1760 sync();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761 }
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07001762 debugger_fault_handler = NULL;
1763 termch = 0;
1764 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765 }
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07001766}
1767