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