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