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