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