Merge ssh://master.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[linux-2.6] / arch / ppc / xmon / xmon.c
1 /*
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>
12 #include <linux/kallsyms.h>
13 #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 #include "nonstdio.h"
20 #include "privinst.h"
21
22 #define scanhex xmon_scanhex
23 #define skipbl  xmon_skipbl
24
25 #ifdef CONFIG_SMP
26 static unsigned long cpus_in_xmon = 0;
27 static unsigned long got_xmon = 0;
28 static volatile int take_xmon = -1;
29 #endif /* CONFIG_SMP */
30
31 static unsigned adrs;
32 static int size = 1;
33 static unsigned ndump = 64;
34 static unsigned nidump = 16;
35 static unsigned ncsum = 4096;
36 static int termch;
37
38 static u_int bus_error_jmp[100];
39 #define setjmp xmon_setjmp
40 #define longjmp xmon_longjmp
41
42 /* Breakpoint stuff */
43 struct bpt {
44         unsigned address;
45         unsigned instr;
46         unsigned count;
47         unsigned char enabled;
48 };
49
50 #define NBPTS   16
51 static struct bpt bpts[NBPTS];
52 static struct bpt dabr;
53 static struct bpt iabr;
54 static unsigned bpinstr = 0x7fe00008;   /* trap */
55
56 /* Prototypes */
57 extern void (*debugger_fault_handler)(struct pt_regs *);
58 static int cmds(struct pt_regs *);
59 static int mread(unsigned, void *, int);
60 static int mwrite(unsigned, void *, int);
61 static void handle_fault(struct pt_regs *);
62 static void byterev(unsigned char *, int);
63 static void memex(void);
64 static int bsesc(void);
65 static void dump(void);
66 static void prdump(unsigned, int);
67 #ifdef __MWERKS__
68 static void prndump(unsigned, int);
69 static int nvreadb(unsigned);
70 #endif
71 static int ppc_inst_dump(unsigned, int);
72 void print_address(unsigned);
73 static int getsp(void);
74 static void dump_hash_table(void);
75 static void backtrace(struct pt_regs *);
76 static void excprint(struct pt_regs *);
77 static void prregs(struct pt_regs *);
78 static void memops(int);
79 static void memlocate(void);
80 static void memzcan(void);
81 static void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned);
82 int skipbl(void);
83 int scanhex(unsigned *valp);
84 static void scannl(void);
85 static int hexdigit(int);
86 void getstring(char *, int);
87 static void flush_input(void);
88 static int inchar(void);
89 static void take_input(char *);
90 /* static void openforth(void); */
91 static unsigned read_spr(int);
92 static void write_spr(int, unsigned);
93 static void super_regs(void);
94 static void symbol_lookup(void);
95 static void remove_bpts(void);
96 static void insert_bpts(void);
97 static struct bpt *at_breakpoint(unsigned pc);
98 static void bpt_cmds(void);
99 void cacheflush(void);
100 #ifdef CONFIG_SMP
101 static void cpu_cmd(void);
102 #endif /* CONFIG_SMP */
103 static void csum(void);
104 #ifdef CONFIG_BOOTX_TEXT
105 static void vidcmds(void);
106 #endif
107 static void bootcmds(void);
108 static void proccall(void);
109 static void printtime(void);
110
111 extern int print_insn_big_powerpc(FILE *, unsigned long, unsigned);
112 extern void printf(const char *fmt, ...);
113 extern int putchar(int ch);
114 extern int setjmp(u_int *);
115 extern void longjmp(u_int *, int);
116
117 extern void xmon_enter(void);
118 extern void xmon_leave(void);
119
120 static unsigned start_tb[NR_CPUS][2];
121 static 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
133 static char *help_string = "\
134 Commands:\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\
145   r     print registers\n\
146   S     print special registers\n\
147   t     print backtrace\n\
148   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\
153   x     exit monitor\n\
154   zr    reboot\n\
155   zh    halt\n\
156 ";
157
158 static int xmon_trace[NR_CPUS];
159 #define SSTEP   1               /* stepping because of 's' command */
160 #define BRSTEP  2               /* stepping over breakpoint */
161
162 static struct pt_regs *xmon_regs[NR_CPUS];
163
164 extern inline void sync(void)
165 {
166         asm volatile("sync; isync");
167 }
168
169 extern 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
176 /* Print an address in numeric and symbolic form (if possible) */
177 static 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
205 static 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
220 int xmon(struct pt_regs *excp)
221 {
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();
260         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()]);
279
280         return cmd != 'X';
281 }
282
283 irqreturn_t
284 xmon_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
294 int
295 xmon_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
314 int
315 xmon_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
328 int
329 xmon_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
344 int
345 xmon_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
359 static struct bpt *
360 at_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
376 static void
377 insert_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
402 static void
403 remove_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
426 static char *last_cmd;
427
428 /* Command interpreting routine */
429 static int
430 cmds(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':
475                         symbol_lookup();
476                         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;
487                 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
543 extern 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
548 static 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
558 static 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
572 static 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
622 extern boot_infos_t disp_bi;
623
624 static 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
659 static 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
696 static void
697 csum(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
718 static void
719 bpt_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
824 static void
825 backtrace(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;
843                 printf("[%.8lx] ", stack);
844                 xmon_print_symbol(stack[1], " ", "\n");
845                 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;
850                         printf("exception:%x [%x] %x\n", regs.trap, sp+16,
851                                regs.nip);
852                         sp = regs.gpr[1];
853                         if (mread(sp, stack, sizeof(stack)) != sizeof(stack))
854                                 break;
855                 }
856         }
857 }
858
859 int
860 getsp(void)
861 {
862     int x;
863
864     asm("mr %0,1" : "=r" (x) :);
865     return x;
866 }
867
868 void
869 excprint(struct pt_regs *fp)
870 {
871         int trap;
872
873 #ifdef CONFIG_SMP
874         printf("cpu %d: ", smp_processor_id());
875 #endif /* CONFIG_SMP */
876         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);
880         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
888 void
889 prregs(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
910 void
911 cacheflush(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
934 unsigned int
935 read_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
948 void
949 write_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
962 static unsigned int regno;
963 extern char exc_prolog;
964 extern char dec_exc;
965
966 void
967 super_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
1016 static void
1017 dump_hash_table(void)
1018 {
1019         printf("This CPU doesn't have a hash table.\n");
1020 }
1021 #else
1022
1023 #ifndef CONFIG_PPC64BRIDGE
1024 static void
1025 dump_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 */
1083 static void
1084 dump_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
1142 static unsigned hash_ctx;
1143 static unsigned hash_start;
1144 static unsigned hash_end;
1145
1146 static void
1147 dump_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
1175 int
1176 mread(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
1205 int
1206 mwrite(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
1235 static int fault_type;
1236 static int fault_except;
1237 static char *fault_chars[] = { "--", "**", "##" };
1238
1239 static void
1240 handle_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
1249 void
1250 byterev(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
1265 static int brev;
1266 static int mnoread;
1267
1268 void
1269 memex(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
1405 int
1406 bsesc(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
1420 void
1421 dump(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
1447 void
1448 prdump(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
1485 int
1486 ppc_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
1519 void
1520 print_address(unsigned addr)
1521 {
1522         printf("0x%x", addr);
1523 }
1524
1525 /*
1526  * Memory operations - move, set, print differences
1527  */
1528 static unsigned mdest;          /* destination address */
1529 static unsigned msrc;           /* source address */
1530 static unsigned mval;           /* byte value to set memory to */
1531 static unsigned mcount;         /* # bytes to affect */
1532 static unsigned mdiffs;         /* max # differences to print */
1533
1534 void
1535 memops(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
1560 void
1561 memdiffs(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
1575 static unsigned mend;
1576 static unsigned mask;
1577
1578 void
1579 memlocate(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
1608 static unsigned mskip = 0x1000;
1609 static unsigned mlim = 0xffffffff;
1610
1611 void
1612 memzcan(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
1639 void 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 */
1675 int
1676 skipbl(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
1691 static 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
1700 int
1701 scanhex(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 == '$') {
1736                 static char symname[128];
1737                 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;
1747                 *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;
1755                 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
1778 void
1779 scannl(void)
1780 {
1781         int c;
1782
1783         c = termch;
1784         termch = 0;
1785         while( c != '\n' )
1786                 c = inchar();
1787 }
1788
1789 int 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
1800 void
1801 getstring(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
1817 static char line[256];
1818 static char *lineptr;
1819
1820 void
1821 flush_input(void)
1822 {
1823         lineptr = NULL;
1824 }
1825
1826 int
1827 inchar(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
1839 void
1840 take_input(char *str)
1841 {
1842         lineptr = str;
1843 }
1844
1845 static void
1846 symbol_lookup(void)
1847 {
1848         int type = inchar();
1849         unsigned addr;
1850         static char tmp[128];
1851
1852         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();
1869                 }
1870                 debugger_fault_handler = NULL;
1871                 termch = 0;
1872                 break;
1873         }
1874 }
1875