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