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