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