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