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