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