ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / ppc64 / xmon / xmon.c
1 /*
2  * Routines providing a simple monitor for use on the PowerMac.
3  *
4  * Copyright (C) 1996 Paul Mackerras.
5  *
6  *      This program is free software; you can redistribute it and/or
7  *      modify it under the terms of the GNU General Public License
8  *      as published by the Free Software Foundation; either version
9  *      2 of the License, or (at your option) any later version.
10  */
11 #include <linux/config.h>
12 #include <linux/errno.h>
13 #include <linux/sched.h>
14 #include <linux/smp.h>
15 #include <linux/mm.h>
16 #include <linux/reboot.h>
17 #include <linux/delay.h>
18 #include <linux/kallsyms.h>
19 #include <linux/cpumask.h>
20
21 #include <asm/ptrace.h>
22 #include <asm/string.h>
23 #include <asm/prom.h>
24 #include <asm/machdep.h>
25 #include <asm/processor.h>
26 #include <asm/pgtable.h>
27 #include <asm/mmu.h>
28 #include <asm/mmu_context.h>
29 #include <asm/naca.h>
30 #include <asm/paca.h>
31 #include <asm/ppcdebug.h>
32 #include <asm/cputable.h>
33
34 #include "nonstdio.h"
35 #include "privinst.h"
36
37 #define scanhex xmon_scanhex
38 #define skipbl  xmon_skipbl
39
40 #ifdef CONFIG_SMP
41 volatile cpumask_t cpus_in_xmon = CPU_MASK_NONE;
42 static unsigned long got_xmon = 0;
43 static volatile int take_xmon = -1;
44 static volatile int leaving_xmon = 0;
45 #endif /* CONFIG_SMP */
46
47 static unsigned long adrs;
48 static int size = 1;
49 static unsigned long ndump = 64;
50 static unsigned long nidump = 16;
51 static unsigned long ncsum = 4096;
52 static int termch;
53 static char tmpstr[128];
54
55 static u_int bus_error_jmp[100];
56 #define setjmp xmon_setjmp
57 #define longjmp xmon_longjmp
58
59 /* Breakpoint stuff */
60 struct bpt {
61         unsigned long address;
62         unsigned instr;
63         unsigned long count;
64         unsigned char enabled;
65 };
66
67 #define NBPTS   16
68 static struct bpt bpts[NBPTS];
69 static struct bpt dabr;
70 static struct bpt iabr;
71 static unsigned bpinstr = 0x7fe00008;   /* trap */
72
73 /* Prototypes */
74 static int cmds(struct pt_regs *);
75 static int mread(unsigned long, void *, int);
76 static int mwrite(unsigned long, void *, int);
77 static int handle_fault(struct pt_regs *);
78 static void byterev(unsigned char *, int);
79 static void memex(void);
80 static int bsesc(void);
81 static void dump(void);
82 static void prdump(unsigned long, long);
83 static int ppc_inst_dump(unsigned long, long);
84 void print_address(unsigned long);
85 static void backtrace(struct pt_regs *);
86 static void excprint(struct pt_regs *);
87 static void prregs(struct pt_regs *);
88 static void memops(int);
89 static void memlocate(void);
90 static void memzcan(void);
91 static void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned);
92 int skipbl(void);
93 int scanhex(unsigned long *valp);
94 static void scannl(void);
95 static int hexdigit(int);
96 void getstring(char *, int);
97 static void flush_input(void);
98 static int inchar(void);
99 static void take_input(char *);
100 /* static void openforth(void); */
101 static unsigned long read_spr(int);
102 static void write_spr(int, unsigned long);
103 static void super_regs(void);
104 static void remove_bpts(void);
105 static void insert_bpts(void);
106 static struct bpt *at_breakpoint(unsigned long pc);
107 static void bpt_cmds(void);
108 static void cacheflush(void);
109 #ifdef CONFIG_SMP
110 static void cpu_cmd(void);
111 #endif /* CONFIG_SMP */
112 static void csum(void);
113 static void bootcmds(void);
114 void dump_segments(void);
115 static void symbol_lookup(void);
116
117 static void debug_trace(void);
118
119 extern int print_insn_big_powerpc(FILE *, unsigned long, unsigned long);
120 extern void printf(const char *fmt, ...);
121 extern void xmon_vfprintf(void *f, const char *fmt, va_list ap);
122 extern int xmon_putc(int c, void *f);
123 extern int putchar(int ch);
124 extern int xmon_read_poll(void);
125 extern int setjmp(u_int *);
126 extern void longjmp(u_int *, int);
127 extern unsigned long _ASR;
128
129 pte_t *find_linux_pte(pgd_t *pgdir, unsigned long va);  /* from htab.c */
130
131 #define GETWORD(v)      (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
132
133 #define isxdigit(c)     (('0' <= (c) && (c) <= '9') \
134                          || ('a' <= (c) && (c) <= 'f') \
135                          || ('A' <= (c) && (c) <= 'F'))
136 #define isalnum(c)      (('0' <= (c) && (c) <= '9') \
137                          || ('a' <= (c) && (c) <= 'z') \
138                          || ('A' <= (c) && (c) <= 'Z'))
139 #define isspace(c)      (c == ' ' || c == '\t' || c == 10 || c == 13 || c == 0)
140
141 static char *help_string = "\
142 Commands:\n\
143   b     show breakpoints\n\
144   bd    set data breakpoint\n\
145   bi    set instruction breakpoint\n\
146   bc    clear breakpoint\n"
147 #ifdef CONFIG_SMP
148   "\
149   c     print cpus stopped in xmon\n\
150   ci    send xmon interrupt to all other cpus\n\
151   c#    try to switch to cpu number h (in hex)\n"
152 #endif
153   "\
154   C     checksum\n\
155   d     dump bytes\n\
156   di    dump instructions\n\
157   df    dump float values\n\
158   dd    dump double values\n\
159   e     print exception information\n\
160   f     flush cache\n\
161   la    lookup symbol+offset of specified address\n\
162   ls    lookup address of specified symbol\n\
163   m     examine/change memory\n\
164   mm    move a block of memory\n\
165   ms    set a block of memory\n\
166   md    compare two blocks of memory\n\
167   ml    locate a block of memory\n\
168   mz    zero a block of memory\n\
169   mi    show information about memory allocation\n\
170   p     show the task list\n\
171   r     print registers\n\
172   s     single step\n\
173   S     print special registers\n\
174   t     print backtrace\n\
175   T     Enable/Disable PPCDBG flags\n\
176   x     exit monitor and recover\n\
177   X     exit monitor and dont recover\n\
178   u     dump segment table or SLB\n\
179   ?     help\n"
180   "\
181   zr    reboot\n\
182   zh    halt\n"
183 ;
184
185 static int xmon_trace[NR_CPUS];
186 #define SSTEP   1               /* stepping because of 's' command */
187 #define BRSTEP  2               /* stepping over breakpoint */
188
189 static struct pt_regs *xmon_regs[NR_CPUS];
190
191 void __xmon_print_symbol(const char *fmt, unsigned long address);
192 #define xmon_print_symbol(fmt, addr)            \
193 do {                                            \
194         __check_printsym_format(fmt, "");       \
195         __xmon_print_symbol(fmt, addr);         \
196 } while(0)
197
198 /*
199  * Stuff for reading and writing memory safely
200  */
201 extern inline void sync(void)
202 {
203         asm volatile("sync; isync");
204 }
205
206 /* (Ref: 64-bit PowerPC ELF ABI Spplement; Ian Lance Taylor, Zembu Labs).
207  A PPC stack frame looks like this:
208
209  High Address
210     Back Chain
211     FP reg save area
212     GP reg save area
213     Local var space
214     Parameter save area         (SP+48)
215     TOC save area               (SP+40)
216     link editor doubleword      (SP+32)
217     compiler doubleword         (SP+24)
218     LR save                     (SP+16)
219     CR save                     (SP+8)
220     Back Chain                  (SP+0)
221
222  Note that the LR (ret addr) may not be saved in the current frame if
223  no functions have been called from the current function.
224  */
225
226 #define SURVEILLANCE_TOKEN      9000
227
228 static inline void disable_surveillance(void)
229 {
230 #ifndef CONFIG_PPC_ISERIES
231         rtas_call(rtas_token("set-indicator"), 3, 1, NULL, SURVEILLANCE_TOKEN,
232                   0, 0);
233 #endif
234 }
235
236 int
237 xmon(struct pt_regs *excp)
238 {
239         struct pt_regs regs;
240         int cmd = 0;
241         unsigned long msr;
242
243         if (excp == NULL) {
244                 /* Ok, grab regs as they are now.
245                  This won't do a particularily good job because the
246                  prologue has already been executed.
247                  ToDo: We could reach back into the callers save
248                  area to do a better job of representing the
249                  caller's state.
250                  */
251                 asm volatile ("std      0,0(%0)\n\
252                         std     1,8(%0)\n\
253                         std     2,16(%0)\n\
254                         std     3,24(%0)\n\
255                         std     4,32(%0)\n\
256                         std     5,40(%0)\n\
257                         std     6,48(%0)\n\
258                         std     7,56(%0)\n\
259                         std     8,64(%0)\n\
260                         std     9,72(%0)\n\
261                         std     10,80(%0)\n\
262                         std     11,88(%0)\n\
263                         std     12,96(%0)\n\
264                         std     13,104(%0)\n\
265                         std     14,112(%0)\n\
266                         std     15,120(%0)\n\
267                         std     16,128(%0)\n\
268                         std     17,136(%0)\n\
269                         std     18,144(%0)\n\
270                         std     19,152(%0)\n\
271                         std     20,160(%0)\n\
272                         std     21,168(%0)\n\
273                         std     22,176(%0)\n\
274                         std     23,184(%0)\n\
275                         std     24,192(%0)\n\
276                         std     25,200(%0)\n\
277                         std     26,208(%0)\n\
278                         std     27,216(%0)\n\
279                         std     28,224(%0)\n\
280                         std     29,232(%0)\n\
281                         std     30,240(%0)\n\
282                         std     31,248(%0)" : : "b" (&regs));
283
284                 regs.nip = regs.link = ((unsigned long *)(regs.gpr[1]))[2];
285                 regs.msr = get_msr();
286                 regs.ctr = get_ctr();
287                 regs.xer = get_xer();
288                 regs.ccr = get_cr();
289                 regs.trap = 0;
290                 excp = &regs;
291         }
292
293         msr = get_msr();
294         set_msrd(msr & ~MSR_EE);        /* disable interrupts */
295         xmon_regs[smp_processor_id()] = excp;
296         excprint(excp);
297 #ifdef CONFIG_SMP
298         leaving_xmon = 0;
299         /* possible race condition here if a CPU is held up and gets
300          * here while we are exiting */
301         if (cpu_test_and_set(smp_processor_id(), cpus_in_xmon)) {
302                 /* xmon probably caused an exception itself */
303                 printf("We are already in xmon\n");
304                 for (;;)
305                         cpu_relax();
306         }
307         while (test_and_set_bit(0, &got_xmon)) {
308                 if (take_xmon == smp_processor_id()) {
309                         take_xmon = -1;
310                         break;
311                 }
312                 cpu_relax();
313         }
314         /*
315          * XXX: breakpoints are removed while any cpu is in xmon
316          */
317 #endif /* CONFIG_SMP */
318         remove_bpts();
319         disable_surveillance();
320         printf("press ? for help ");
321         cmd = cmds(excp);
322         if (cmd == 's') {
323                 xmon_trace[smp_processor_id()] = SSTEP;
324                 excp->msr |= MSR_SE;
325 #ifdef CONFIG_SMP               
326                 take_xmon = smp_processor_id();
327 #endif          
328         } else if (at_breakpoint(excp->nip)) {
329                 xmon_trace[smp_processor_id()] = BRSTEP;
330                 excp->msr |= MSR_SE;
331         } else {
332                 xmon_trace[smp_processor_id()] = 0;
333                 insert_bpts();
334         }
335         xmon_regs[smp_processor_id()] = 0;
336 #ifdef CONFIG_SMP
337         leaving_xmon = 1;
338         if (cmd != 's')
339                 clear_bit(0, &got_xmon);
340         cpu_clear(smp_processor_id(), cpus_in_xmon);
341 #endif /* CONFIG_SMP */
342         set_msrd(msr);          /* restore interrupt enable */
343
344         if (cmd == 'X')
345                 return 0;
346
347         return 1;
348 }
349
350 int
351 xmon_bpt(struct pt_regs *regs)
352 {
353         struct bpt *bp;
354
355         bp = at_breakpoint(regs->nip);
356         if (!bp)
357                 return 0;
358         if (bp->count) {
359                 --bp->count;
360                 remove_bpts();
361                 excprint(regs);
362                 xmon_trace[smp_processor_id()] = BRSTEP;
363                 regs->msr |= MSR_SE;
364         } else {
365                 printf("Stopped at breakpoint %x (%lx ", (bp - bpts) + 1,
366                         bp->address);
367                 xmon_print_symbol("%s)\n", bp->address);
368                 xmon(regs);
369         }
370         return 1;
371 }
372
373 int
374 xmon_sstep(struct pt_regs *regs)
375 {
376         if (!xmon_trace[smp_processor_id()])
377                 return 0;
378         if (xmon_trace[smp_processor_id()] == BRSTEP) {
379                 xmon_trace[smp_processor_id()] = 0;
380                 insert_bpts();
381         } else {
382                 xmon(regs);
383         }
384         return 1;
385 }
386
387 int
388 xmon_dabr_match(struct pt_regs *regs)
389 {
390         if (dabr.enabled && dabr.count) {
391                 --dabr.count;
392                 remove_bpts();
393                 excprint(regs);
394                 xmon_trace[smp_processor_id()] = BRSTEP;
395                 regs->msr |= MSR_SE;
396         } else {
397                 dabr.instr = regs->nip;
398                 xmon(regs);
399         }
400         return 1;
401 }
402
403 int
404 xmon_iabr_match(struct pt_regs *regs)
405 {
406         if (iabr.enabled && iabr.count) {
407                 --iabr.count;
408                 remove_bpts();
409                 excprint(regs);
410                 xmon_trace[smp_processor_id()] = BRSTEP;
411                 regs->msr |= MSR_SE;
412         } else {
413                 xmon(regs);
414         }
415         return 1;
416 }
417
418 static struct bpt *
419 at_breakpoint(unsigned long pc)
420 {
421         int i;
422         struct bpt *bp;
423
424         if (dabr.enabled && pc == dabr.instr)
425                 return &dabr;
426         if (iabr.enabled && pc == iabr.address)
427                 return &iabr;
428         bp = bpts;
429         for (i = 0; i < NBPTS; ++i, ++bp)
430                 if (bp->enabled && pc == bp->address)
431                         return bp;
432         return 0;
433 }
434
435 static void
436 insert_bpts()
437 {
438         int i;
439         struct bpt *bp;
440
441         bp = bpts;
442         for (i = 0; i < NBPTS; ++i, ++bp) {
443                 if (!bp->enabled)
444                         continue;
445                 if (mread(bp->address, &bp->instr, 4) != 4
446                     || mwrite(bp->address, &bpinstr, 4) != 4) {
447                         printf("Couldn't insert breakpoint at %x, disabling\n",
448                                bp->address);
449                         bp->enabled = 0;
450                 } else {
451                         store_inst((void *)bp->address);
452                 }
453         }
454
455         if (dabr.enabled)
456                 set_dabr(dabr.address);
457         if ((cur_cpu_spec->cpu_features & CPU_FTR_IABR) && iabr.enabled)
458                 set_iabr(iabr.address);
459 }
460
461 static void
462 remove_bpts()
463 {
464         int i;
465         struct bpt *bp;
466         unsigned instr;
467
468         set_dabr(0);
469         if ((cur_cpu_spec->cpu_features & CPU_FTR_IABR))
470                 set_iabr(0);
471
472         bp = bpts;
473         for (i = 0; i < NBPTS; ++i, ++bp) {
474                 if (!bp->enabled)
475                         continue;
476                 if (mread(bp->address, &instr, 4) == 4
477                     && instr == bpinstr
478                     && mwrite(bp->address, &bp->instr, 4) != 4)
479                         printf("Couldn't remove breakpoint at %x\n",
480                                bp->address);
481                 else
482                         store_inst((void *)bp->address);
483         }
484 }
485
486 static char *last_cmd;
487
488 /* Command interpreting routine */
489 static int
490 cmds(struct pt_regs *excp)
491 {
492         int cmd = 0;
493
494         last_cmd = NULL;
495         for(;;) {
496 #ifdef CONFIG_SMP
497                 /* Need to check if we should take any commands on
498                    this CPU. */
499                 if (leaving_xmon)
500                         return cmd;
501                 printf("%d:", smp_processor_id());
502 #endif /* CONFIG_SMP */
503                 printf("mon> ");
504                 fflush(stdout);
505                 flush_input();
506                 termch = 0;
507                 cmd = skipbl();
508                 if( cmd == '\n' ) {
509                         if (last_cmd == NULL)
510                                 continue;
511                         take_input(last_cmd);
512                         last_cmd = NULL;
513                         cmd = inchar();
514                 }
515                 switch (cmd) {
516                 case 'm':
517                         cmd = inchar();
518                         switch (cmd) {
519                         case 'm':
520                         case 's':
521                         case 'd':
522                                 memops(cmd);
523                                 break;
524                         case 'l':
525                                 memlocate();
526                                 break;
527                         case 'z':
528                                 memzcan();
529                                 break;
530                         case 'i':
531                                 show_mem();
532                                 break;
533                         default:
534                                 termch = cmd;
535                                 memex();
536                         }
537                         break;
538                 case 'd':
539                         dump();
540                         break;
541                 case 'l':
542                         symbol_lookup();
543                         break;
544                 case 'r':
545                         prregs(excp);   /* print regs */
546                         break;
547                 case 'e':
548                         if (excp == NULL)
549                                 printf("No exception information\n");
550                         else
551                                 excprint(excp);
552                         break;
553                 case 'S':
554                         super_regs();
555                         break;
556                 case 't':
557                         backtrace(excp);
558                         break;
559                 case 'f':
560                         cacheflush();
561                         break;
562                 case 's':
563                 case 'x':
564                 case 'X':
565                 case EOF:
566                         return cmd;
567                 case '?':
568                         printf(help_string);
569                         break;
570                 case 'p':
571                         show_state();
572                         break;
573                 case 'b':
574                         bpt_cmds();
575                         break;
576                 case 'C':
577                         csum();
578                         break;
579 #ifdef CONFIG_SMP
580                 case 'c':
581                         cpu_cmd();
582                         break;
583 #endif /* CONFIG_SMP */
584                 case 'z':
585                         bootcmds();
586                 case 'T':
587                         debug_trace();
588                         break;
589                 case 'u':
590                         dump_segments();
591                         break;
592                 default:
593                         printf("Unrecognized command: ");
594                         do {
595                                 if( ' ' < cmd && cmd <= '~' )
596                                         putchar(cmd);
597                                 else
598                                         printf("\\x%x", cmd);
599                                 cmd = inchar();
600                         } while (cmd != '\n'); 
601                         printf(" (type ? for help)\n");
602                         break;
603                 }
604                 cpu_relax();
605         }
606 }
607
608 static void bootcmds(void)
609 {
610         int cmd;
611
612         cmd = inchar();
613         if (cmd == 'r')
614                 ppc_md.restart(NULL);
615         else if (cmd == 'h')
616                 ppc_md.halt();
617         else if (cmd == 'p')
618                 ppc_md.power_off();
619 }
620
621 #ifdef CONFIG_SMP
622 static void cpu_cmd(void)
623 {
624         unsigned long cpu;
625         int timeout;
626         int cmd;
627
628         cmd = inchar();
629         if (cmd == 'i') {
630                 printf("stopping all cpus\n");
631                 /* interrupt other cpu(s) */
632                 cpu = MSG_ALL_BUT_SELF;
633                 smp_send_debugger_break(cpu);
634                 return;
635         }
636         termch = cmd;
637         if (!scanhex(&cpu)) {
638                 /* print cpus waiting or in xmon */
639                 printf("cpus stopped:");
640                 for (cpu = 0; cpu < NR_CPUS; ++cpu) {
641                         if (cpu_isset(cpu, cpus_in_xmon)) {
642                                 printf(" %x", cpu);
643                                 if (cpu == smp_processor_id())
644                                         printf("*", cpu);
645                         }
646                 }
647                 printf("\n");
648                 return;
649         }
650         /* try to switch to cpu specified */
651         take_xmon = cpu;
652         timeout = 10000000;
653         while (take_xmon >= 0) {
654                 if (--timeout == 0) {
655                         /* yes there's a race here */
656                         take_xmon = -1;
657                         printf("cpu %u didn't take control\n", cpu);
658                         return;
659                 }
660         }
661         /* now have to wait to be given control back */
662         while (test_and_set_bit(0, &got_xmon)) {
663                 if (take_xmon == smp_processor_id()) {
664                         take_xmon = -1;
665                         break;
666                 }
667                 cpu_relax();
668         }
669 }
670 #endif /* CONFIG_SMP */
671
672 static unsigned short fcstab[256] = {
673         0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
674         0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
675         0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
676         0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
677         0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
678         0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
679         0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
680         0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
681         0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
682         0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
683         0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
684         0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
685         0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
686         0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
687         0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
688         0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
689         0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
690         0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
691         0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
692         0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
693         0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
694         0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
695         0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
696         0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
697         0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
698         0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
699         0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
700         0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
701         0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
702         0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
703         0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
704         0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
705 };
706
707 #define FCS(fcs, c)     (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
708
709 static void
710 csum(void)
711 {
712         unsigned int i;
713         unsigned short fcs;
714         unsigned char v;
715
716         if (!scanhex(&adrs))
717                 return;
718         if (!scanhex(&ncsum))
719                 return;
720         fcs = 0xffff;
721         for (i = 0; i < ncsum; ++i) {
722                 if (mread(adrs+i, &v, 1) == 0) {
723                         printf("csum stopped at %x\n", adrs+i);
724                         break;
725                 }
726                 fcs = FCS(fcs, v);
727         }
728         printf("%x\n", fcs);
729 }
730
731 static char *breakpoint_help_string = 
732     "Breakpoint command usage:\n"
733     "b                show breakpoints\n"
734     "b <addr> [cnt]   set breakpoint at given instr addr\n"
735     "bc               clear all breakpoints\n"
736     "bc <n/addr>      clear breakpoint number n or at addr\n"
737     "bi <addr> [cnt]  set hardware instr breakpoint (broken?)\n"
738     "bd <addr> [cnt]  set hardware data breakpoint (broken?)\n"
739     "";
740
741 static void
742 bpt_cmds(void)
743 {
744         int cmd;
745         unsigned long a;
746         int mode, i;
747         struct bpt *bp;
748
749         cmd = inchar();
750         switch (cmd) {
751         case 'd':       /* bd - hardware data breakpoint */
752                 mode = 7;
753                 cmd = inchar();
754                 if (cmd == 'r')
755                         mode = 5;
756                 else if (cmd == 'w')
757                         mode = 6;
758                 else
759                         termch = cmd;
760                 dabr.address = 0;
761                 dabr.count = 0;
762                 dabr.enabled = scanhex(&dabr.address);
763                 scanhex(&dabr.count);
764                 if (dabr.enabled)
765                         dabr.address = (dabr.address & ~7) | mode;
766                 break;
767         case 'i':       /* bi - hardware instr breakpoint */
768                 if (!(cur_cpu_spec->cpu_features & CPU_FTR_IABR)) {
769                         printf("Not implemented on POWER4\n");
770                         break;
771                 }
772                 iabr.address = 0;
773                 iabr.count = 0;
774                 iabr.enabled = scanhex(&iabr.address);
775                 if (iabr.enabled)
776                         iabr.address |= 3;
777                 scanhex(&iabr.count);
778                 break;
779         case 'c':
780                 if (!scanhex(&a)) {
781                         /* clear all breakpoints */
782                         for (i = 0; i < NBPTS; ++i)
783                                 bpts[i].enabled = 0;
784                         iabr.enabled = 0;
785                         dabr.enabled = 0;
786                         printf("All breakpoints cleared\n");
787                 } else {
788                         if (a <= NBPTS && a >= 1) {
789                                 /* assume a breakpoint number */
790                                 --a;    /* bp nums are 1 based */
791                                 bp = &bpts[a];
792                         } else {
793                                 /* assume a breakpoint address */
794                                 bp = at_breakpoint(a);
795                         }
796                         if (bp == 0) {
797                                 printf("No breakpoint at %x\n", a);
798                         } else {
799                                 printf("Cleared breakpoint %x (%lx ", 
800                                         (bp - bpts) + 1, bp->address);
801                                 xmon_print_symbol("%s)\n", bp->address);
802                                 bp->enabled = 0;
803                         }
804                 }
805                 break;
806         case '?':
807                 printf(breakpoint_help_string);
808                 break;
809         default:
810                 termch = cmd;
811                 cmd = skipbl();
812                 if (cmd == '?') {
813                         printf(breakpoint_help_string);
814                         break;
815                 }
816                 termch = cmd;
817                 if (!scanhex(&a)) {
818                         /* print all breakpoints */
819                         int bpnum;
820
821                         printf("   type            address    count\n");
822                         if (dabr.enabled) {
823                                 printf("   data   %.16lx %8x [", dabr.address & ~7,
824                                        dabr.count);
825                                 if (dabr.address & 1)
826                                         printf("r");
827                                 if (dabr.address & 2)
828                                         printf("w");
829                                 printf("]\n");
830                         }
831                         if (iabr.enabled)
832                                 printf("   inst   %.16lx %8x\n", iabr.address & ~3,
833                                        iabr.count);
834                         for (bp = bpts, bpnum = 1; bp < &bpts[NBPTS]; ++bp, ++bpnum)
835                                 if (bp->enabled) {
836                                         printf("%2x trap   %.16lx %8x  ",
837                                                 bpnum, bp->address, bp->count);
838                                         xmon_print_symbol("%s\n", bp->address);
839                                 }
840                         break;
841                 }
842                 
843                 if (systemcfg->platform != PLATFORM_POWERMAC &&
844                    !(systemcfg->platform & PLATFORM_PSERIES)) {
845                         printf("Not supported for this platform\n");
846                         break;
847                 }
848
849                 bp = at_breakpoint(a);
850                 if (bp == 0) {
851                         for (bp = bpts; bp < &bpts[NBPTS]; ++bp)
852                                 if (!bp->enabled)
853                                         break;
854                         if (bp >= &bpts[NBPTS]) {
855                                 printf("Sorry, no free breakpoints.  Please clear one first.\n");
856                                 break;
857                         }
858                 }
859                 bp->enabled = 1;
860                 bp->address = a;
861                 bp->count = 0;
862                 scanhex(&bp->count);
863                 printf("Set breakpoint %2x trap   %.16lx %8x  ", (bp-bpts) + 1, 
864                         bp->address, bp->count);
865                 xmon_print_symbol("%s\n", bp->address);
866                 break;
867         }
868 }
869
870 /* Very cheap human name for vector lookup. */
871 static
872 const char *getvecname(unsigned long vec)
873 {
874         char *ret;
875         switch (vec) {
876         case 0x100:     ret = "(System Reset)"; break; 
877         case 0x200:     ret = "(Machine Check)"; break; 
878         case 0x300:     ret = "(Data Access)"; break; 
879         case 0x380:     ret = "(Data SLB Access)"; break;
880         case 0x400:     ret = "(Instruction Access)"; break; 
881         case 0x480:     ret = "(Instruction SLB Access)"; break;
882         case 0x500:     ret = "(Hardware Interrupt)"; break; 
883         case 0x600:     ret = "(Alignment)"; break; 
884         case 0x700:     ret = "(Program Check)"; break; 
885         case 0x800:     ret = "(FPU Unavailable)"; break; 
886         case 0x900:     ret = "(Decrementer)"; break; 
887         case 0xc00:     ret = "(System Call)"; break; 
888         case 0xd00:     ret = "(Single Step)"; break; 
889         case 0xf00:     ret = "(Performance Monitor)"; break; 
890         default: ret = "";
891         }
892         return ret;
893 }
894
895 /*
896  * Most of our exceptions are in the form:
897  *    bl handler
898  *    b .ret_from_exception
899  * and this currently fails to catch them.
900  */
901 static inline int exception_frame(unsigned long ip)
902 {
903         extern void *ret_from_syscall_1, *ret_from_syscall_2, *ret_from_except;
904
905         if ((ip == (unsigned long)ret_from_syscall_1) ||
906             (ip == (unsigned long)ret_from_syscall_2) ||
907             (ip == (unsigned long)ret_from_except))
908                 return 1;
909
910         return 0;
911 }
912
913 static int xmon_depth_to_print = 64;
914
915 static void xmon_show_stack(unsigned long sp)
916 {
917         unsigned long ip;
918         unsigned long newsp;
919         int count = 0;
920         struct pt_regs regs;
921
922         do {
923                 if (sp < PAGE_OFFSET) {
924                         printf("SP in userspace\n");
925                         break;
926                 }
927
928                 if (!mread((sp + 16), &ip, sizeof(unsigned long)))
929                         break;
930
931                 printf("[%016lx] [%016lx] ", sp, ip);
932                 xmon_print_symbol("%s\n", ip);
933
934                 if (exception_frame(ip)) {
935                         if (mread(sp+112, &regs, sizeof(regs)) != sizeof(regs))
936                                 break;
937
938                         printf("  exception: %lx %s regs %lx\n", regs.trap,
939                                getvecname(regs.trap), sp+112);
940                 }
941
942                 if (!mread(sp, &newsp, sizeof(unsigned long)))
943                         break;
944                 if (newsp < sp)
945                         break;
946
947                 sp = newsp;
948         } while (count++ < xmon_depth_to_print);
949 }
950
951 static void backtrace(struct pt_regs *excp)
952 {
953         unsigned long sp;
954
955         if (excp == NULL)
956                 sp = __get_SP();
957         else
958                 sp = excp->gpr[1];
959
960         scanhex(&sp);
961         scannl();
962
963         xmon_show_stack(sp);
964 }
965
966 spinlock_t exception_print_lock = SPIN_LOCK_UNLOCKED;
967
968 void excprint(struct pt_regs *fp)
969 {
970         unsigned long flags;
971
972         spin_lock_irqsave(&exception_print_lock, flags);
973
974 #ifdef CONFIG_SMP
975         printf("cpu %d: ", smp_processor_id());
976 #endif /* CONFIG_SMP */
977
978         printf("Vector: %lx %s at [%lx]\n", fp->trap, getvecname(fp->trap), fp);
979         printf("    pc: %lx", fp->nip);
980         xmon_print_symbol(" (%s)\n", fp->nip);
981
982         printf("    lr: %lx", fp->link);
983         xmon_print_symbol(" (%s)\n", fp->link);
984
985         printf("    sp: %lx\n", fp->gpr[1]);
986         printf("   msr: %lx\n", fp->msr);
987
988         if (fp->trap == 0x300 || fp->trap == 0x380 || fp->trap == 0x600) {
989                 printf("   dar: %lx\n", fp->dar);
990                 printf(" dsisr: %lx\n", fp->dsisr);
991         }
992
993         printf("  current = 0x%lx\n", current);
994         printf("  paca    = 0x%lx\n", get_paca());
995         if (current) {
996                 printf("    pid   = %ld, comm = %s\n",
997                        current->pid, current->comm);
998         }
999
1000         spin_unlock_irqrestore(&exception_print_lock, flags);
1001 }
1002
1003 void prregs(struct pt_regs *fp)
1004 {
1005         int n;
1006         unsigned long base;
1007
1008         if (scanhex((void *)&base))
1009                 fp = (struct pt_regs *) base;
1010
1011         if (setjmp(bus_error_jmp) == 0) {
1012                 __debugger_fault_handler = handle_fault;
1013                 sync();
1014                 for (n = 0; n < 16; ++n)
1015                         printf("R%.2ld = %.16lx   R%.2ld = %.16lx\n", n,
1016                                fp->gpr[n], n+16, fp->gpr[n+16]);
1017                 printf("pc  = %.16lx   msr = %.16lx\nlr  = %.16lx   "
1018                        "cr  = %.16lx\n", fp->nip, fp->msr, fp->link, fp->ccr);
1019                 printf("ctr = %.16lx   xer = %.16lx   trap = %8lx\n",
1020                        fp->ctr, fp->xer, fp->trap);
1021
1022                 sync();
1023                 /* wait a little while to see if we get a machine check */
1024                 __delay(200);
1025         } else {
1026                 printf("*** Error reading regs\n");
1027         }
1028 }
1029
1030 void
1031 cacheflush(void)
1032 {
1033         int cmd;
1034         unsigned long nflush;
1035
1036         cmd = inchar();
1037         if (cmd != 'i')
1038                 termch = cmd;
1039         scanhex((void *)&adrs);
1040         if (termch != '\n')
1041                 termch = 0;
1042         nflush = 1;
1043         scanhex(&nflush);
1044         nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES;
1045         if (setjmp(bus_error_jmp) == 0) {
1046                 __debugger_fault_handler = handle_fault;
1047                 sync();
1048
1049                 if (cmd != 'i') {
1050                         for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1051                                 cflush((void *) adrs);
1052                 } else {
1053                         for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1054                                 cinval((void *) adrs);
1055                 }
1056                 sync();
1057                 /* wait a little while to see if we get a machine check */
1058                 __delay(200);
1059         }
1060         __debugger_fault_handler = 0;
1061 }
1062
1063 unsigned long
1064 read_spr(int n)
1065 {
1066         unsigned int instrs[2];
1067         unsigned long (*code)(void);
1068         unsigned long opd[3];
1069         unsigned long ret = -1UL;
1070
1071         instrs[0] = 0x7c6002a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1072         instrs[1] = 0x4e800020;
1073         opd[0] = (unsigned long)instrs;
1074         opd[1] = 0;
1075         opd[2] = 0;
1076         store_inst(instrs);
1077         store_inst(instrs+1);
1078         code = (unsigned long (*)(void)) opd;
1079
1080         if (setjmp(bus_error_jmp) == 0) {
1081                 __debugger_fault_handler = handle_fault;
1082                 sync();
1083
1084                 ret = code();
1085
1086                 sync();
1087                 /* wait a little while to see if we get a machine check */
1088                 __delay(200);
1089         } else {
1090                 printf("*** Error reading spr %x\n", n);
1091         }
1092
1093         __debugger_fault_handler = 0;
1094
1095         return ret;
1096 }
1097
1098 void
1099 write_spr(int n, unsigned long val)
1100 {
1101         unsigned int instrs[2];
1102         unsigned long (*code)(unsigned long);
1103         unsigned long opd[3];
1104
1105         instrs[0] = 0x7c6003a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1106         instrs[1] = 0x4e800020;
1107         opd[0] = (unsigned long)instrs;
1108         opd[1] = 0;
1109         opd[2] = 0;
1110         store_inst(instrs);
1111         store_inst(instrs+1);
1112         code = (unsigned long (*)(unsigned long)) opd;
1113
1114         if (setjmp(bus_error_jmp) == 0) {
1115                 __debugger_fault_handler = handle_fault;
1116                 sync();
1117
1118                 code(val);
1119
1120                 sync();
1121                 /* wait a little while to see if we get a machine check */
1122                 __delay(200);
1123         } else {
1124                 printf("*** Error writing spr %x\n", n);
1125         }
1126
1127         __debugger_fault_handler = 0;
1128 }
1129
1130 static unsigned long regno;
1131 extern char exc_prolog;
1132 extern char dec_exc;
1133
1134 void
1135 super_regs()
1136 {
1137         int cmd;
1138         unsigned long val;
1139 #ifdef CONFIG_PPC_ISERIES
1140         struct paca_struct *ptrPaca = NULL;
1141         struct ItLpPaca *ptrLpPaca = NULL;
1142         struct ItLpRegSave *ptrLpRegSave = NULL;
1143 #endif
1144
1145         cmd = skipbl();
1146         if (cmd == '\n') {
1147                 unsigned long sp, toc;
1148                 asm("mr %0,1" : "=r" (sp) :);
1149                 asm("mr %0,2" : "=r" (toc) :);
1150
1151                 printf("msr  = %.16lx  sprg0= %.16lx\n", get_msr(), get_sprg0());
1152                 printf("pvr  = %.16lx  sprg1= %.16lx\n", get_pvr(), get_sprg1()); 
1153                 printf("dec  = %.16lx  sprg2= %.16lx\n", get_dec(), get_sprg2());
1154                 printf("sp   = %.16lx  sprg3= %.16lx\n", sp, get_sprg3());
1155                 printf("toc  = %.16lx  dar  = %.16lx\n", toc, get_dar());
1156                 printf("srr0 = %.16lx  srr1 = %.16lx\n", get_srr0(), get_srr1());
1157 #ifdef CONFIG_PPC_ISERIES
1158                 // Dump out relevant Paca data areas.
1159                 printf("Paca: \n");
1160                 ptrPaca = get_paca();
1161     
1162                 printf("  Local Processor Control Area (LpPaca): \n");
1163                 ptrLpPaca = ptrPaca->xLpPacaPtr;
1164                 printf("    Saved Srr0=%.16lx  Saved Srr1=%.16lx \n", ptrLpPaca->xSavedSrr0, ptrLpPaca->xSavedSrr1);
1165                 printf("    Saved Gpr3=%.16lx  Saved Gpr4=%.16lx \n", ptrLpPaca->xSavedGpr3, ptrLpPaca->xSavedGpr4);
1166                 printf("    Saved Gpr5=%.16lx \n", ptrLpPaca->xSavedGpr5);
1167     
1168                 printf("  Local Processor Register Save Area (LpRegSave): \n");
1169                 ptrLpRegSave = ptrPaca->xLpRegSavePtr;
1170                 printf("    Saved Sprg0=%.16lx  Saved Sprg1=%.16lx \n", ptrLpRegSave->xSPRG0, ptrLpRegSave->xSPRG0);
1171                 printf("    Saved Sprg2=%.16lx  Saved Sprg3=%.16lx \n", ptrLpRegSave->xSPRG2, ptrLpRegSave->xSPRG3);
1172                 printf("    Saved Msr  =%.16lx  Saved Nia  =%.16lx \n", ptrLpRegSave->xMSR, ptrLpRegSave->xNIA);
1173 #endif
1174
1175                 return;
1176         }
1177
1178         scanhex(&regno);
1179         switch (cmd) {
1180         case 'w':
1181                 val = read_spr(regno);
1182                 scanhex(&val);
1183                 write_spr(regno, val);
1184                 /* fall through */
1185         case 'r':
1186                 printf("spr %lx = %lx\n", regno, read_spr(regno));
1187                 break;
1188         case 'm':
1189                 val = get_msr();
1190                 scanhex(&val);
1191                 set_msrd(val);
1192                 break;
1193         }
1194         scannl();
1195 }
1196
1197 int
1198 mread(unsigned long adrs, void *buf, int size)
1199 {
1200         volatile int n;
1201         char *p, *q;
1202
1203         n = 0;
1204         if (setjmp(bus_error_jmp) == 0) {
1205                 __debugger_fault_handler = handle_fault;
1206                 sync();
1207                 p = (char *)adrs;
1208                 q = (char *)buf;
1209                 switch (size) {
1210                 case 2:
1211                         *(short *)q = *(short *)p;
1212                         break;
1213                 case 4:
1214                         *(int *)q = *(int *)p;
1215                         break;
1216                 case 8:
1217                         *(long *)q = *(long *)p;
1218                         break;
1219                 default:
1220                         for( ; n < size; ++n) {
1221                                 *q++ = *p++;
1222                                 sync();
1223                         }
1224                 }
1225                 sync();
1226                 /* wait a little while to see if we get a machine check */
1227                 __delay(200);
1228                 n = size;
1229         }
1230         __debugger_fault_handler = 0;
1231         return n;
1232 }
1233
1234 int
1235 mwrite(unsigned long adrs, void *buf, int size)
1236 {
1237         volatile int n;
1238         char *p, *q;
1239
1240         n = 0;
1241         if (setjmp(bus_error_jmp) == 0) {
1242                 __debugger_fault_handler = handle_fault;
1243                 sync();
1244                 p = (char *) adrs;
1245                 q = (char *) buf;
1246                 switch (size) {
1247                 case 2:
1248                         *(short *)p = *(short *)q;
1249                         break;
1250                 case 4:
1251                         *(int *)p = *(int *)q;
1252                         break;
1253                 case 8:
1254                         *(long *)p = *(long *)q;
1255                         break;
1256                 default:
1257                         for ( ; n < size; ++n) {
1258                                 *p++ = *q++;
1259                                 sync();
1260                         }
1261                 }
1262                 sync();
1263                 /* wait a little while to see if we get a machine check */
1264                 __delay(200);
1265                 n = size;
1266         } else {
1267                 printf("*** Error writing address %x\n", adrs + n);
1268         }
1269         __debugger_fault_handler = 0;
1270         return n;
1271 }
1272
1273 static int fault_type;
1274 static char *fault_chars[] = { "--", "**", "##" };
1275
1276 static int
1277 handle_fault(struct pt_regs *regs)
1278 {
1279         switch (regs->trap) {
1280         case 0x200:
1281                 fault_type = 0;
1282                 break;
1283         case 0x300:
1284         case 0x380:
1285                 fault_type = 1;
1286                 break;
1287         default:
1288                 fault_type = 2;
1289         }
1290
1291         longjmp(bus_error_jmp, 1);
1292
1293         return 0;
1294 }
1295
1296 #define SWAP(a, b, t)   ((t) = (a), (a) = (b), (b) = (t))
1297
1298 void
1299 byterev(unsigned char *val, int size)
1300 {
1301         int t;
1302         
1303         switch (size) {
1304         case 2:
1305                 SWAP(val[0], val[1], t);
1306                 break;
1307         case 4:
1308                 SWAP(val[0], val[3], t);
1309                 SWAP(val[1], val[2], t);
1310                 break;
1311         case 8: /* is there really any use for this? */
1312                 SWAP(val[0], val[7], t);
1313                 SWAP(val[1], val[6], t);
1314                 SWAP(val[2], val[5], t);
1315                 SWAP(val[3], val[4], t);
1316                 break;
1317         }
1318 }
1319
1320 static int brev;
1321 static int mnoread;
1322
1323 static char *memex_help_string = 
1324     "Memory examine command usage:\n"
1325     "m [addr] [flags] examine/change memory\n"
1326     "  addr is optional.  will start where left off.\n"
1327     "  flags may include chars from this set:\n"
1328     "    b   modify by bytes (default)\n"
1329     "    w   modify by words (2 byte)\n"
1330     "    l   modify by longs (4 byte)\n"
1331     "    d   modify by doubleword (8 byte)\n"
1332     "    r   toggle reverse byte order mode\n"
1333     "    n   do not read memory (for i/o spaces)\n"
1334     "    .   ok to read (default)\n"
1335     "NOTE: flags are saved as defaults\n"
1336     "";
1337
1338 static char *memex_subcmd_help_string = 
1339     "Memory examine subcommands:\n"
1340     "  hexval   write this val to current location\n"
1341     "  'string' write chars from string to this location\n"
1342     "  '        increment address\n"
1343     "  ^        decrement address\n"
1344     "  /        increment addr by 0x10.  //=0x100, ///=0x1000, etc\n"
1345     "  \\        decrement addr by 0x10.  \\\\=0x100, \\\\\\=0x1000, etc\n"
1346     "  `        clear no-read flag\n"
1347     "  ;        stay at this addr\n"
1348     "  v        change to byte mode\n"
1349     "  w        change to word (2 byte) mode\n"
1350     "  l        change to long (4 byte) mode\n"
1351     "  u        change to doubleword (8 byte) mode\n"
1352     "  m addr   change current addr\n"
1353     "  n        toggle no-read flag\n"
1354     "  r        toggle byte reverse flag\n"
1355     "  < count  back up count bytes\n"
1356     "  > count  skip forward count bytes\n"
1357     "  x        exit this mode\n"
1358     "";
1359
1360 void
1361 memex()
1362 {
1363         int cmd, inc, i, nslash;
1364         unsigned long n;
1365         unsigned char val[16];
1366
1367         scanhex((void *)&adrs);
1368         cmd = skipbl();
1369         if (cmd == '?') {
1370                 printf(memex_help_string);
1371                 return;
1372         } else {
1373                 termch = cmd;
1374         }
1375         last_cmd = "m\n";
1376         while ((cmd = skipbl()) != '\n') {
1377                 switch( cmd ){
1378                 case 'b':       size = 1;       break;
1379                 case 'w':       size = 2;       break;
1380                 case 'l':       size = 4;       break;
1381                 case 'd':       size = 8;       break;
1382                 case 'r':       brev = !brev;   break;
1383                 case 'n':       mnoread = 1;    break;
1384                 case '.':       mnoread = 0;    break;
1385                 }
1386         }
1387         if( size <= 0 )
1388                 size = 1;
1389         else if( size > 8 )
1390                 size = 8;
1391         for(;;){
1392                 if (!mnoread)
1393                         n = mread(adrs, val, size);
1394                 printf("%.16x%c", adrs, brev? 'r': ' ');
1395                 if (!mnoread) {
1396                         if (brev)
1397                                 byterev(val, size);
1398                         putchar(' ');
1399                         for (i = 0; i < n; ++i)
1400                                 printf("%.2x", val[i]);
1401                         for (; i < size; ++i)
1402                                 printf("%s", fault_chars[fault_type]);
1403                 }
1404                 putchar(' ');
1405                 inc = size;
1406                 nslash = 0;
1407                 for(;;){
1408                         if( scanhex(&n) ){
1409                                 for (i = 0; i < size; ++i)
1410                                         val[i] = n >> (i * 8);
1411                                 if (!brev)
1412                                         byterev(val, size);
1413                                 mwrite(adrs, val, size);
1414                                 inc = size;
1415                         }
1416                         cmd = skipbl();
1417                         if (cmd == '\n')
1418                                 break;
1419                         inc = 0;
1420                         switch (cmd) {
1421                         case '\'':
1422                                 for(;;){
1423                                         n = inchar();
1424                                         if( n == '\\' )
1425                                                 n = bsesc();
1426                                         else if( n == '\'' )
1427                                                 break;
1428                                         for (i = 0; i < size; ++i)
1429                                                 val[i] = n >> (i * 8);
1430                                         if (!brev)
1431                                                 byterev(val, size);
1432                                         mwrite(adrs, val, size);
1433                                         adrs += size;
1434                                 }
1435                                 adrs -= size;
1436                                 inc = size;
1437                                 break;
1438                         case ',':
1439                                 adrs += size;
1440                                 break;
1441                         case '.':
1442                                 mnoread = 0;
1443                                 break;
1444                         case ';':
1445                                 break;
1446                         case 'x':
1447                         case EOF:
1448                                 scannl();
1449                                 return;
1450                         case 'b':
1451                         case 'v':
1452                                 size = 1;
1453                                 break;
1454                         case 'w':
1455                                 size = 2;
1456                                 break;
1457                         case 'l':
1458                                 size = 4;
1459                                 break;
1460                         case 'u':
1461                                 size = 8;
1462                                 break;
1463                         case '^':
1464                                 adrs -= size;
1465                                 break;
1466                                 break;
1467                         case '/':
1468                                 if (nslash > 0)
1469                                         adrs -= 1 << nslash;
1470                                 else
1471                                         nslash = 0;
1472                                 nslash += 4;
1473                                 adrs += 1 << nslash;
1474                                 break;
1475                         case '\\':
1476                                 if (nslash < 0)
1477                                         adrs += 1 << -nslash;
1478                                 else
1479                                         nslash = 0;
1480                                 nslash -= 4;
1481                                 adrs -= 1 << -nslash;
1482                                 break;
1483                         case 'm':
1484                                 scanhex((void *)&adrs);
1485                                 break;
1486                         case 'n':
1487                                 mnoread = 1;
1488                                 break;
1489                         case 'r':
1490                                 brev = !brev;
1491                                 break;
1492                         case '<':
1493                                 n = size;
1494                                 scanhex(&n);
1495                                 adrs -= n;
1496                                 break;
1497                         case '>':
1498                                 n = size;
1499                                 scanhex(&n);
1500                                 adrs += n;
1501                                 break;
1502                         case '?':
1503                                 printf(memex_subcmd_help_string);
1504                                 break;
1505                         }
1506                 }
1507                 adrs += inc;
1508         }
1509 }
1510
1511 int
1512 bsesc()
1513 {
1514         int c;
1515
1516         c = inchar();
1517         switch( c ){
1518         case 'n':       c = '\n';       break;
1519         case 'r':       c = '\r';       break;
1520         case 'b':       c = '\b';       break;
1521         case 't':       c = '\t';       break;
1522         }
1523         return c;
1524 }
1525
1526 #define isxdigit(c)     (('0' <= (c) && (c) <= '9') \
1527                          || ('a' <= (c) && (c) <= 'f') \
1528                          || ('A' <= (c) && (c) <= 'F'))
1529 void
1530 dump()
1531 {
1532         int c;
1533
1534         c = inchar();
1535         if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
1536                 termch = c;
1537         scanhex((void *)&adrs);
1538         if( termch != '\n')
1539                 termch = 0;
1540         if( c == 'i' ){
1541                 scanhex(&nidump);
1542                 if( nidump == 0 )
1543                         nidump = 16;
1544                 adrs += ppc_inst_dump(adrs, nidump);
1545                 last_cmd = "di\n";
1546         } else {
1547                 scanhex(&ndump);
1548                 if( ndump == 0 )
1549                         ndump = 64;
1550                 prdump(adrs, ndump);
1551                 adrs += ndump;
1552                 last_cmd = "d\n";
1553         }
1554 }
1555
1556 void
1557 prdump(unsigned long adrs, long ndump)
1558 {
1559         long n, m, c, r, nr;
1560         unsigned char temp[16];
1561
1562         for( n = ndump; n > 0; ){
1563                 printf("%.16lx", adrs);
1564                 putchar(' ');
1565                 r = n < 16? n: 16;
1566                 nr = mread(adrs, temp, r);
1567                 adrs += nr;
1568                 for( m = 0; m < r; ++m ){
1569                         if ((m & 7) == 0 && m > 0)
1570                             putchar(' ');
1571                         if( m < nr )
1572                                 printf("%.2x", temp[m]);
1573                         else
1574                                 printf("%s", fault_chars[fault_type]);
1575                 }
1576                 for(; m < 16; ++m )
1577                         printf("   ");
1578                 printf("  |");
1579                 for( m = 0; m < r; ++m ){
1580                         if( m < nr ){
1581                                 c = temp[m];
1582                                 putchar(' ' <= c && c <= '~'? c: '.');
1583                         } else
1584                                 putchar(' ');
1585                 }
1586                 n -= r;
1587                 for(; m < 16; ++m )
1588                         putchar(' ');
1589                 printf("|\n");
1590                 if( nr < r )
1591                         break;
1592         }
1593 }
1594
1595 int
1596 ppc_inst_dump(unsigned long adr, long count)
1597 {
1598         int nr, dotted;
1599         unsigned long first_adr;
1600         unsigned long inst, last_inst;
1601         unsigned char val[4];
1602
1603         dotted = 0;
1604         for (first_adr = adr; count > 0; --count, adr += 4){
1605                 nr = mread(adr, val, 4);
1606                 if( nr == 0 ){
1607                         const char *x = fault_chars[fault_type];
1608                         printf("%.16lx  %s%s%s%s\n", adr, x, x, x, x);
1609                         break;
1610                 }
1611                 inst = GETWORD(val);
1612                 if (adr > first_adr && inst == last_inst) {
1613                         if (!dotted) {
1614                                 printf(" ...\n");
1615                                 dotted = 1;
1616                         }
1617                         continue;
1618                 }
1619                 dotted = 0;
1620                 last_inst = inst;
1621                 printf("%.16lx  ", adr);
1622                 printf("%.8x\t", inst);
1623                 print_insn_big_powerpc(stdout, inst, adr);      /* always returns 4 */
1624                 printf("\n");
1625         }
1626         return adr - first_adr;
1627 }
1628
1629 void
1630 print_address(unsigned long addr)
1631 {
1632         const char *name;
1633         char *modname;
1634         long size, offset;
1635
1636         name = kallsyms_lookup(addr, &size, &offset, &modname, tmpstr);
1637
1638         if (name) {
1639                 if (modname)
1640                         printf("0x%lx\t# %s:%s+0x%lx", addr, modname, name, offset);
1641                 else
1642                         printf("0x%lx\t# %s+0x%lx", addr, name, offset);
1643         } else
1644                 printf("0x%lx", addr);
1645 }
1646
1647
1648 /*
1649  * Memory operations - move, set, print differences
1650  */
1651 static unsigned long mdest;             /* destination address */
1652 static unsigned long msrc;              /* source address */
1653 static unsigned long mval;              /* byte value to set memory to */
1654 static unsigned long mcount;            /* # bytes to affect */
1655 static unsigned long mdiffs;            /* max # differences to print */
1656
1657 void
1658 memops(int cmd)
1659 {
1660         scanhex((void *)&mdest);
1661         if( termch != '\n' )
1662                 termch = 0;
1663         scanhex((void *)(cmd == 's'? &mval: &msrc));
1664         if( termch != '\n' )
1665                 termch = 0;
1666         scanhex((void *)&mcount);
1667         switch( cmd ){
1668         case 'm':
1669                 memmove((void *)mdest, (void *)msrc, mcount);
1670                 break;
1671         case 's':
1672                 memset((void *)mdest, mval, mcount);
1673                 break;
1674         case 'd':
1675                 if( termch != '\n' )
1676                         termch = 0;
1677                 scanhex((void *)&mdiffs);
1678                 memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
1679                 break;
1680         }
1681 }
1682
1683 void
1684 memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
1685 {
1686         unsigned n, prt;
1687
1688         prt = 0;
1689         for( n = nb; n > 0; --n )
1690                 if( *p1++ != *p2++ )
1691                         if( ++prt <= maxpr )
1692                                 printf("%.16x %.2x # %.16x %.2x\n", p1 - 1,
1693                                         p1[-1], p2 - 1, p2[-1]);
1694         if( prt > maxpr )
1695                 printf("Total of %d differences\n", prt);
1696 }
1697
1698 static unsigned mend;
1699 static unsigned mask;
1700
1701 void
1702 memlocate()
1703 {
1704         unsigned a, n;
1705         unsigned char val[4];
1706
1707         last_cmd = "ml";
1708         scanhex((void *)&mdest);
1709         if (termch != '\n') {
1710                 termch = 0;
1711                 scanhex((void *)&mend);
1712                 if (termch != '\n') {
1713                         termch = 0;
1714                         scanhex((void *)&mval);
1715                         mask = ~0;
1716                         if (termch != '\n') termch = 0;
1717                         scanhex((void *)&mask);
1718                 }
1719         }
1720         n = 0;
1721         for (a = mdest; a < mend; a += 4) {
1722                 if (mread(a, val, 4) == 4
1723                         && ((GETWORD(val) ^ mval) & mask) == 0) {
1724                         printf("%.16x:  %.16x\n", a, GETWORD(val));
1725                         if (++n >= 10)
1726                                 break;
1727                 }
1728         }
1729 }
1730
1731 static unsigned long mskip = 0x1000;
1732 static unsigned long mlim = 0xffffffff;
1733
1734 void
1735 memzcan()
1736 {
1737         unsigned char v;
1738         unsigned a;
1739         int ok, ook;
1740
1741         scanhex(&mdest);
1742         if (termch != '\n') termch = 0;
1743         scanhex(&mskip);
1744         if (termch != '\n') termch = 0;
1745         scanhex(&mlim);
1746         ook = 0;
1747         for (a = mdest; a < mlim; a += mskip) {
1748                 ok = mread(a, &v, 1);
1749                 if (ok && !ook) {
1750                         printf("%.8x .. ", a);
1751                         fflush(stdout);
1752                 } else if (!ok && ook)
1753                         printf("%.8x\n", a - mskip);
1754                 ook = ok;
1755                 if (a + mskip < a)
1756                         break;
1757         }
1758         if (ook)
1759                 printf("%.8x\n", a - mskip);
1760 }
1761
1762 /* Input scanning routines */
1763 int
1764 skipbl()
1765 {
1766         int c;
1767
1768         if( termch != 0 ){
1769                 c = termch;
1770                 termch = 0;
1771         } else
1772                 c = inchar();
1773         while( c == ' ' || c == '\t' )
1774                 c = inchar();
1775         return c;
1776 }
1777
1778 #define N_PTREGS        44
1779 static char *regnames[N_PTREGS] = {
1780         "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
1781         "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
1782         "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
1783         "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
1784         "pc", "msr", "or3", "ctr", "lr", "xer", "ccr", "mq",
1785         "trap", "dar", "dsisr", "res"
1786 };
1787
1788 int
1789 scanhex(vp)
1790 unsigned long *vp;
1791 {
1792         int c, d;
1793         unsigned long v;
1794
1795         c = skipbl();
1796         if (c == '%') {
1797                 /* parse register name */
1798                 char regname[8];
1799                 int i;
1800
1801                 for (i = 0; i < sizeof(regname) - 1; ++i) {
1802                         c = inchar();
1803                         if (!isalnum(c)) {
1804                                 termch = c;
1805                                 break;
1806                         }
1807                         regname[i] = c;
1808                 }
1809                 regname[i] = 0;
1810                 for (i = 0; i < N_PTREGS; ++i) {
1811                         if (strcmp(regnames[i], regname) == 0) {
1812                                 unsigned long *rp = (unsigned long *)
1813                                         xmon_regs[smp_processor_id()];
1814                                 if (rp == NULL) {
1815                                         printf("regs not available\n");
1816                                         return 0;
1817                                 }
1818                                 *vp = rp[i];
1819                                 return 1;
1820                         }
1821                 }
1822                 printf("invalid register name '%%%s'\n", regname);
1823                 return 0;
1824         }
1825
1826         /* skip leading "0x" if any */
1827
1828         if (c == '0') {
1829                 c = inchar();
1830                 if (c == 'x')
1831                         c = inchar();
1832         } else if (c == '$') {
1833                 int i;
1834                 for (i=0; i<63; i++) {
1835                         c = inchar();
1836                         if (isspace(c)) {
1837                                 termch = c;
1838                                 break;
1839                         }
1840                         tmpstr[i] = c;
1841                 }
1842                 tmpstr[i++] = 0;
1843                 *vp = kallsyms_lookup_name(tmpstr);
1844                 if (!(*vp)) {
1845                         printf("unknown symbol '%s'\n", tmpstr);
1846                         return 0;
1847                 }
1848                 return 1;
1849         }
1850
1851         d = hexdigit(c);
1852         if (d == EOF) {
1853                 termch = c;
1854                 return 0;
1855         }
1856         v = 0;
1857         do {
1858                 v = (v << 4) + d;
1859                 c = inchar();
1860                 d = hexdigit(c);
1861         } while (d != EOF);
1862         termch = c;
1863         *vp = v;
1864         return 1;
1865 }
1866
1867 void
1868 scannl()
1869 {
1870         int c;
1871
1872         c = termch;
1873         termch = 0;
1874         while( c != '\n' )
1875                 c = inchar();
1876 }
1877
1878 int
1879 hexdigit(int c)
1880 {
1881         if( '0' <= c && c <= '9' )
1882                 return c - '0';
1883         if( 'A' <= c && c <= 'F' )
1884                 return c - ('A' - 10);
1885         if( 'a' <= c && c <= 'f' )
1886                 return c - ('a' - 10);
1887         return EOF;
1888 }
1889
1890 void
1891 getstring(char *s, int size)
1892 {
1893         int c;
1894
1895         c = skipbl();
1896         do {
1897                 if( size > 1 ){
1898                         *s++ = c;
1899                         --size;
1900                 }
1901                 c = inchar();
1902         } while( c != ' ' && c != '\t' && c != '\n' );
1903         termch = c;
1904         *s = 0;
1905 }
1906
1907 static char line[256];
1908 static char *lineptr;
1909
1910 void
1911 flush_input()
1912 {
1913         lineptr = NULL;
1914 }
1915
1916 int
1917 inchar()
1918 {
1919         if (lineptr == NULL || *lineptr == 0) {
1920                 if (fgets(line, sizeof(line), stdin) == NULL) {
1921                         lineptr = NULL;
1922                         return EOF;
1923                 }
1924                 lineptr = line;
1925         }
1926         return *lineptr++;
1927 }
1928
1929 void
1930 take_input(str)
1931 char *str;
1932 {
1933         lineptr = str;
1934 }
1935
1936
1937 static void
1938 symbol_lookup(void)
1939 {
1940         int type = inchar();
1941         unsigned long addr;
1942         static char tmp[64];
1943
1944         switch (type) {
1945         case 'a':
1946                 if (scanhex(&addr)) {
1947                         printf("%lx: ", addr);
1948                         xmon_print_symbol("%s\n", addr);
1949                 }
1950                 termch = 0;
1951                 break;
1952         case 's':
1953                 getstring(tmp, 64);
1954                 if (setjmp(bus_error_jmp) == 0) {
1955                         __debugger_fault_handler = handle_fault;
1956                         sync();
1957                         addr = kallsyms_lookup_name(tmp);
1958                         if (addr)
1959                                 printf("%s: %lx\n", tmp, addr);
1960                         else
1961                                 printf("Symbol '%s' not found.\n", tmp);
1962                         sync();
1963                 }
1964                 __debugger_fault_handler = 0;
1965                 termch = 0;
1966                 break;
1967         }
1968 }
1969
1970
1971 /* xmon version of __print_symbol */
1972 void __xmon_print_symbol(const char *fmt, unsigned long address)
1973 {
1974         char *modname;
1975         const char *name;
1976         unsigned long offset, size;
1977
1978         if (setjmp(bus_error_jmp) == 0) {
1979                 __debugger_fault_handler = handle_fault;
1980                 sync();
1981                 name = kallsyms_lookup(address, &size, &offset, &modname,
1982                                        tmpstr);
1983                 sync();
1984                 /* wait a little while to see if we get a machine check */
1985                 __delay(200);
1986         } else {
1987                 name = "symbol lookup failed";
1988         }
1989
1990         __debugger_fault_handler = 0;
1991
1992         if (!name) {
1993                 char addrstr[sizeof("0x%lx") + (BITS_PER_LONG*3/10)];
1994
1995                 sprintf(addrstr, "0x%lx", address);
1996                 printf(fmt, addrstr);
1997                 return;
1998         }
1999
2000         if (modname) {
2001                 /* This is pretty small. */
2002                 char buffer[sizeof("%s+%#lx/%#lx [%s]")
2003                            + strlen(name) + 2*(BITS_PER_LONG*3/10)
2004                            + strlen(modname)];
2005
2006                 sprintf(buffer, "%s+%#lx/%#lx [%s]",
2007                         name, offset, size, modname);
2008                 printf(fmt, buffer);
2009         } else {
2010                 char buffer[sizeof("%s+%#lx/%#lx")
2011                            + strlen(name) + 2*(BITS_PER_LONG*3/10)];
2012
2013                 sprintf(buffer, "%s+%#lx/%#lx", name, offset, size);
2014                 printf(fmt, buffer);
2015         }
2016 }
2017
2018 static void debug_trace(void)
2019 {
2020         unsigned long val, cmd, on;
2021
2022         cmd = skipbl();
2023         if (cmd == '\n') {
2024                 /* show current state */
2025                 unsigned long i;
2026                 printf("naca->debug_switch = 0x%lx\n", naca->debug_switch);
2027                 for (i = 0; i < PPCDBG_NUM_FLAGS ;i++) {
2028                         on = PPCDBG_BITVAL(i) & naca->debug_switch;
2029                         printf("%02x %s %12s   ", i, on ? "on " : "off",  trace_names[i] ? trace_names[i] : "");
2030                         if (((i+1) % 3) == 0)
2031                                 printf("\n");
2032                 }
2033                 printf("\n");
2034                 return;
2035         }
2036         while (cmd != '\n') {
2037                 on = 1; /* default if no sign given */
2038                 while (cmd == '+' || cmd == '-') {
2039                         on = (cmd == '+');
2040                         cmd = inchar();
2041                         if (cmd == ' ' || cmd == '\n') {  /* Turn on or off based on + or - */
2042                                 naca->debug_switch = on ? PPCDBG_ALL:PPCDBG_NONE;
2043                                 printf("Setting all values to %s...\n", on ? "on" : "off");
2044                                 if (cmd == '\n') return;
2045                                 else cmd = skipbl(); 
2046                         }
2047                         else
2048                                 termch = cmd;
2049                 }
2050                 termch = cmd;   /* not +/- ... let scanhex see it */
2051                 scanhex((void *)&val);
2052                 if (val >= 64) {
2053                         printf("Value %x out of range:\n", val);
2054                         return;
2055                 }
2056                 if (on) {
2057                         naca->debug_switch |= PPCDBG_BITVAL(val);
2058                         printf("enable debug %x %s\n", val, trace_names[val] ? trace_names[val] : "");
2059                 } else {
2060                         naca->debug_switch &= ~PPCDBG_BITVAL(val);
2061                         printf("disable debug %x %s\n", val, trace_names[val] ? trace_names[val] : "");
2062                 }
2063                 cmd = skipbl();
2064         }
2065 }
2066
2067 static void dump_slb(void)
2068 {
2069         int i;
2070         unsigned long tmp;
2071
2072         printf("SLB contents of cpu %d\n", smp_processor_id());
2073
2074         for (i = 0; i < naca->slb_size; i++) {
2075                 asm volatile("slbmfee  %0,%1" : "=r" (tmp) : "r" (i));
2076                 printf("%02d %016lx ", i, tmp);
2077
2078                 asm volatile("slbmfev  %0,%1" : "=r" (tmp) : "r" (i));
2079                 printf("%016lx\n", tmp);
2080         }
2081 }
2082
2083 static void dump_stab(void)
2084 {
2085         int i;
2086         unsigned long *tmp = (unsigned long *)get_paca()->xStab_data.virt;
2087
2088         printf("Segment table contents of cpu %d\n", smp_processor_id());
2089
2090         for (i = 0; i < PAGE_SIZE/16; i++) {
2091                 unsigned long a, b;
2092
2093                 a = *tmp++;
2094                 b = *tmp++;
2095
2096                 if (a || b) {
2097                         printf("%03d %016lx ", i, a);
2098                         printf("%016lx\n", b);
2099                 }
2100         }
2101 }
2102
2103 void xmon_init(void)
2104 {
2105         __debugger = xmon;
2106         __debugger_bpt = xmon_bpt;
2107         __debugger_sstep = xmon_sstep;
2108         __debugger_iabr_match = xmon_iabr_match;
2109         __debugger_dabr_match = xmon_dabr_match;
2110 }
2111
2112 void dump_segments(void)
2113 {
2114         if (cur_cpu_spec->cpu_features & CPU_FTR_SLB)
2115                 dump_slb();
2116         else
2117                 dump_stab();
2118 }