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