[POWERPC] Allow xmon to build without CONFIG_DEBUG_BUGVERBOSE
[linux-2.6] / arch / powerpc / xmon / xmon.c
1 /*
2  * Routines providing a simple monitor for use on the PowerMac.
3  *
4  * Copyright (C) 1996-2005 Paul Mackerras.
5  * Copyright (C) 2001 PPC64 Team, IBM Corp
6  * Copyrignt (C) 2006 Michael Ellerman, IBM Corp
7  *
8  *      This program is free software; you can redistribute it and/or
9  *      modify it under the terms of the GNU General Public License
10  *      as published by the Free Software Foundation; either version
11  *      2 of the License, or (at your option) any later version.
12  */
13 #include <linux/errno.h>
14 #include <linux/sched.h>
15 #include <linux/smp.h>
16 #include <linux/mm.h>
17 #include <linux/reboot.h>
18 #include <linux/delay.h>
19 #include <linux/kallsyms.h>
20 #include <linux/cpumask.h>
21 #include <linux/module.h>
22 #include <linux/sysrq.h>
23 #include <linux/interrupt.h>
24 #include <linux/irq.h>
25 #include <linux/bug.h>
26
27 #include <asm/ptrace.h>
28 #include <asm/string.h>
29 #include <asm/prom.h>
30 #include <asm/machdep.h>
31 #include <asm/xmon.h>
32 #include <asm/processor.h>
33 #include <asm/pgtable.h>
34 #include <asm/mmu.h>
35 #include <asm/mmu_context.h>
36 #include <asm/cputable.h>
37 #include <asm/rtas.h>
38 #include <asm/sstep.h>
39 #include <asm/irq_regs.h>
40 #include <asm/spu.h>
41 #include <asm/spu_priv1.h>
42 #include <asm/firmware.h>
43
44 #ifdef CONFIG_PPC64
45 #include <asm/hvcall.h>
46 #include <asm/paca.h>
47 #include <asm/iseries/it_lp_reg_save.h>
48 #endif
49
50 #include "nonstdio.h"
51 #include "dis-asm.h"
52
53 #define scanhex xmon_scanhex
54 #define skipbl  xmon_skipbl
55
56 #ifdef CONFIG_SMP
57 cpumask_t cpus_in_xmon = CPU_MASK_NONE;
58 static unsigned long xmon_taken = 1;
59 static int xmon_owner;
60 static int xmon_gate;
61 #endif /* CONFIG_SMP */
62
63 static unsigned long in_xmon = 0;
64
65 static unsigned long adrs;
66 static int size = 1;
67 #define MAX_DUMP (128 * 1024)
68 static unsigned long ndump = 64;
69 static unsigned long nidump = 16;
70 static unsigned long ncsum = 4096;
71 static int termch;
72 static char tmpstr[128];
73
74 #define JMP_BUF_LEN     23
75 static long bus_error_jmp[JMP_BUF_LEN];
76 static int catch_memory_errors;
77 static long *xmon_fault_jmp[NR_CPUS];
78 #define setjmp xmon_setjmp
79 #define longjmp xmon_longjmp
80
81 /* Breakpoint stuff */
82 struct bpt {
83         unsigned long   address;
84         unsigned int    instr[2];
85         atomic_t        ref_count;
86         int             enabled;
87         unsigned long   pad;
88 };
89
90 /* Bits in bpt.enabled */
91 #define BP_IABR_TE      1               /* IABR translation enabled */
92 #define BP_IABR         2
93 #define BP_TRAP         8
94 #define BP_DABR         0x10
95
96 #define NBPTS   256
97 static struct bpt bpts[NBPTS];
98 static struct bpt dabr;
99 static struct bpt *iabr;
100 static unsigned bpinstr = 0x7fe00008;   /* trap */
101
102 #define BP_NUM(bp)      ((bp) - bpts + 1)
103
104 /* Prototypes */
105 static int cmds(struct pt_regs *);
106 static int mread(unsigned long, void *, int);
107 static int mwrite(unsigned long, void *, int);
108 static int handle_fault(struct pt_regs *);
109 static void byterev(unsigned char *, int);
110 static void memex(void);
111 static int bsesc(void);
112 static void dump(void);
113 static void prdump(unsigned long, long);
114 static int ppc_inst_dump(unsigned long, long, int);
115 static void backtrace(struct pt_regs *);
116 static void excprint(struct pt_regs *);
117 static void prregs(struct pt_regs *);
118 static void memops(int);
119 static void memlocate(void);
120 static void memzcan(void);
121 static void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned);
122 int skipbl(void);
123 int scanhex(unsigned long *valp);
124 static void scannl(void);
125 static int hexdigit(int);
126 void getstring(char *, int);
127 static void flush_input(void);
128 static int inchar(void);
129 static void take_input(char *);
130 static unsigned long read_spr(int);
131 static void write_spr(int, unsigned long);
132 static void super_regs(void);
133 static void remove_bpts(void);
134 static void insert_bpts(void);
135 static void remove_cpu_bpts(void);
136 static void insert_cpu_bpts(void);
137 static struct bpt *at_breakpoint(unsigned long pc);
138 static struct bpt *in_breakpoint_table(unsigned long pc, unsigned long *offp);
139 static int  do_step(struct pt_regs *);
140 static void bpt_cmds(void);
141 static void cacheflush(void);
142 static int  cpu_cmd(void);
143 static void csum(void);
144 static void bootcmds(void);
145 static void proccall(void);
146 void dump_segments(void);
147 static void symbol_lookup(void);
148 static void xmon_show_stack(unsigned long sp, unsigned long lr,
149                             unsigned long pc);
150 static void xmon_print_symbol(unsigned long address, const char *mid,
151                               const char *after);
152 static const char *getvecname(unsigned long vec);
153
154 static int do_spu_cmd(void);
155
156 int xmon_no_auto_backtrace;
157
158 extern void xmon_enter(void);
159 extern void xmon_leave(void);
160
161 extern long setjmp(long *);
162 extern void longjmp(long *, long);
163 extern void xmon_save_regs(struct pt_regs *);
164
165 #ifdef CONFIG_PPC64
166 #define REG             "%.16lx"
167 #define REGS_PER_LINE   4
168 #define LAST_VOLATILE   13
169 #else
170 #define REG             "%.8lx"
171 #define REGS_PER_LINE   8
172 #define LAST_VOLATILE   12
173 #endif
174
175 #define GETWORD(v)      (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
176
177 #define isxdigit(c)     (('0' <= (c) && (c) <= '9') \
178                          || ('a' <= (c) && (c) <= 'f') \
179                          || ('A' <= (c) && (c) <= 'F'))
180 #define isalnum(c)      (('0' <= (c) && (c) <= '9') \
181                          || ('a' <= (c) && (c) <= 'z') \
182                          || ('A' <= (c) && (c) <= 'Z'))
183 #define isspace(c)      (c == ' ' || c == '\t' || c == 10 || c == 13 || c == 0)
184
185 static char *help_string = "\
186 Commands:\n\
187   b     show breakpoints\n\
188   bd    set data breakpoint\n\
189   bi    set instruction breakpoint\n\
190   bc    clear breakpoint\n"
191 #ifdef CONFIG_SMP
192   "\
193   c     print cpus stopped in xmon\n\
194   c#    try to switch to cpu number h (in hex)\n"
195 #endif
196   "\
197   C     checksum\n\
198   d     dump bytes\n\
199   di    dump instructions\n\
200   df    dump float values\n\
201   dd    dump double values\n\
202   dr    dump stream of raw bytes\n\
203   e     print exception information\n\
204   f     flush cache\n\
205   la    lookup symbol+offset of specified address\n\
206   ls    lookup address of specified symbol\n\
207   m     examine/change memory\n\
208   mm    move a block of memory\n\
209   ms    set a block of memory\n\
210   md    compare two blocks of memory\n\
211   ml    locate a block of memory\n\
212   mz    zero a block of memory\n\
213   mi    show information about memory allocation\n\
214   p     call a procedure\n\
215   r     print registers\n\
216   s     single step\n"
217 #ifdef CONFIG_SPU_BASE
218 "  ss   stop execution on all spus\n\
219   sr    restore execution on stopped spus\n\
220   sf  # dump spu fields for spu # (in hex)\n\
221   sd  # dump spu local store for spu # (in hex)\n\
222   sdi # disassemble spu local store for spu # (in hex)\n"
223 #endif
224 "  S    print special registers\n\
225   t     print backtrace\n\
226   x     exit monitor and recover\n\
227   X     exit monitor and dont recover\n"
228 #ifdef CONFIG_PPC64
229 "  u    dump segment table or SLB\n"
230 #endif
231 #ifdef CONFIG_PPC_STD_MMU_32
232 "  u    dump segment registers\n"
233 #endif
234 "  ?    help\n"
235 "  zr   reboot\n\
236   zh    halt\n"
237 ;
238
239 static struct pt_regs *xmon_regs;
240
241 static inline void sync(void)
242 {
243         asm volatile("sync; isync");
244 }
245
246 static inline void store_inst(void *p)
247 {
248         asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p));
249 }
250
251 static inline void cflush(void *p)
252 {
253         asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p));
254 }
255
256 static inline void cinval(void *p)
257 {
258         asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p));
259 }
260
261 /*
262  * Disable surveillance (the service processor watchdog function)
263  * while we are in xmon.
264  * XXX we should re-enable it when we leave. :)
265  */
266 #define SURVEILLANCE_TOKEN      9000
267
268 static inline void disable_surveillance(void)
269 {
270 #ifdef CONFIG_PPC_PSERIES
271         /* Since this can't be a module, args should end up below 4GB. */
272         static struct rtas_args args;
273
274         /*
275          * At this point we have got all the cpus we can into
276          * xmon, so there is hopefully no other cpu calling RTAS
277          * at the moment, even though we don't take rtas.lock.
278          * If we did try to take rtas.lock there would be a
279          * real possibility of deadlock.
280          */
281         args.token = rtas_token("set-indicator");
282         if (args.token == RTAS_UNKNOWN_SERVICE)
283                 return;
284         args.nargs = 3;
285         args.nret = 1;
286         args.rets = &args.args[3];
287         args.args[0] = SURVEILLANCE_TOKEN;
288         args.args[1] = 0;
289         args.args[2] = 0;
290         enter_rtas(__pa(&args));
291 #endif /* CONFIG_PPC_PSERIES */
292 }
293
294 #ifdef CONFIG_SMP
295 static int xmon_speaker;
296
297 static void get_output_lock(void)
298 {
299         int me = smp_processor_id() + 0x100;
300         int last_speaker = 0, prev;
301         long timeout;
302
303         if (xmon_speaker == me)
304                 return;
305         for (;;) {
306                 if (xmon_speaker == 0) {
307                         last_speaker = cmpxchg(&xmon_speaker, 0, me);
308                         if (last_speaker == 0)
309                                 return;
310                 }
311                 timeout = 10000000;
312                 while (xmon_speaker == last_speaker) {
313                         if (--timeout > 0)
314                                 continue;
315                         /* hostile takeover */
316                         prev = cmpxchg(&xmon_speaker, last_speaker, me);
317                         if (prev == last_speaker)
318                                 return;
319                         break;
320                 }
321         }
322 }
323
324 static void release_output_lock(void)
325 {
326         xmon_speaker = 0;
327 }
328 #endif
329
330 static int xmon_core(struct pt_regs *regs, int fromipi)
331 {
332         int cmd = 0;
333         unsigned long msr;
334         struct bpt *bp;
335         long recurse_jmp[JMP_BUF_LEN];
336         unsigned long offset;
337 #ifdef CONFIG_SMP
338         int cpu;
339         int secondary;
340         unsigned long timeout;
341 #endif
342
343         msr = mfmsr();
344         mtmsr(msr & ~MSR_EE);   /* disable interrupts */
345
346         bp = in_breakpoint_table(regs->nip, &offset);
347         if (bp != NULL) {
348                 regs->nip = bp->address + offset;
349                 atomic_dec(&bp->ref_count);
350         }
351
352         remove_cpu_bpts();
353
354 #ifdef CONFIG_SMP
355         cpu = smp_processor_id();
356         if (cpu_isset(cpu, cpus_in_xmon)) {
357                 get_output_lock();
358                 excprint(regs);
359                 printf("cpu 0x%x: Exception %lx %s in xmon, "
360                        "returning to main loop\n",
361                        cpu, regs->trap, getvecname(TRAP(regs)));
362                 release_output_lock();
363                 longjmp(xmon_fault_jmp[cpu], 1);
364         }
365
366         if (setjmp(recurse_jmp) != 0) {
367                 if (!in_xmon || !xmon_gate) {
368                         get_output_lock();
369                         printf("xmon: WARNING: bad recursive fault "
370                                "on cpu 0x%x\n", cpu);
371                         release_output_lock();
372                         goto waiting;
373                 }
374                 secondary = !(xmon_taken && cpu == xmon_owner);
375                 goto cmdloop;
376         }
377
378         xmon_fault_jmp[cpu] = recurse_jmp;
379         cpu_set(cpu, cpus_in_xmon);
380
381         bp = NULL;
382         if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF))
383                 bp = at_breakpoint(regs->nip);
384         if (bp || (regs->msr & MSR_RI) == 0)
385                 fromipi = 0;
386
387         if (!fromipi) {
388                 get_output_lock();
389                 excprint(regs);
390                 if (bp) {
391                         printf("cpu 0x%x stopped at breakpoint 0x%x (",
392                                cpu, BP_NUM(bp));
393                         xmon_print_symbol(regs->nip, " ", ")\n");
394                 }
395                 if ((regs->msr & MSR_RI) == 0)
396                         printf("WARNING: exception is not recoverable, "
397                                "can't continue\n");
398                 release_output_lock();
399         }
400
401  waiting:
402         secondary = 1;
403         while (secondary && !xmon_gate) {
404                 if (in_xmon == 0) {
405                         if (fromipi)
406                                 goto leave;
407                         secondary = test_and_set_bit(0, &in_xmon);
408                 }
409                 barrier();
410         }
411
412         if (!secondary && !xmon_gate) {
413                 /* we are the first cpu to come in */
414                 /* interrupt other cpu(s) */
415                 int ncpus = num_online_cpus();
416
417                 xmon_owner = cpu;
418                 mb();
419                 if (ncpus > 1) {
420                         smp_send_debugger_break(MSG_ALL_BUT_SELF);
421                         /* wait for other cpus to come in */
422                         for (timeout = 100000000; timeout != 0; --timeout) {
423                                 if (cpus_weight(cpus_in_xmon) >= ncpus)
424                                         break;
425                                 barrier();
426                         }
427                 }
428                 remove_bpts();
429                 disable_surveillance();
430                 /* for breakpoint or single step, print the current instr. */
431                 if (bp || TRAP(regs) == 0xd00)
432                         ppc_inst_dump(regs->nip, 1, 0);
433                 printf("enter ? for help\n");
434                 mb();
435                 xmon_gate = 1;
436                 barrier();
437         }
438
439  cmdloop:
440         while (in_xmon) {
441                 if (secondary) {
442                         if (cpu == xmon_owner) {
443                                 if (!test_and_set_bit(0, &xmon_taken)) {
444                                         secondary = 0;
445                                         continue;
446                                 }
447                                 /* missed it */
448                                 while (cpu == xmon_owner)
449                                         barrier();
450                         }
451                         barrier();
452                 } else {
453                         cmd = cmds(regs);
454                         if (cmd != 0) {
455                                 /* exiting xmon */
456                                 insert_bpts();
457                                 xmon_gate = 0;
458                                 wmb();
459                                 in_xmon = 0;
460                                 break;
461                         }
462                         /* have switched to some other cpu */
463                         secondary = 1;
464                 }
465         }
466  leave:
467         cpu_clear(cpu, cpus_in_xmon);
468         xmon_fault_jmp[cpu] = NULL;
469 #else
470         /* UP is simple... */
471         if (in_xmon) {
472                 printf("Exception %lx %s in xmon, returning to main loop\n",
473                        regs->trap, getvecname(TRAP(regs)));
474                 longjmp(xmon_fault_jmp[0], 1);
475         }
476         if (setjmp(recurse_jmp) == 0) {
477                 xmon_fault_jmp[0] = recurse_jmp;
478                 in_xmon = 1;
479
480                 excprint(regs);
481                 bp = at_breakpoint(regs->nip);
482                 if (bp) {
483                         printf("Stopped at breakpoint %x (", BP_NUM(bp));
484                         xmon_print_symbol(regs->nip, " ", ")\n");
485                 }
486                 if ((regs->msr & MSR_RI) == 0)
487                         printf("WARNING: exception is not recoverable, "
488                                "can't continue\n");
489                 remove_bpts();
490                 disable_surveillance();
491                 /* for breakpoint or single step, print the current instr. */
492                 if (bp || TRAP(regs) == 0xd00)
493                         ppc_inst_dump(regs->nip, 1, 0);
494                 printf("enter ? for help\n");
495         }
496
497         cmd = cmds(regs);
498
499         insert_bpts();
500         in_xmon = 0;
501 #endif
502
503         if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF)) {
504                 bp = at_breakpoint(regs->nip);
505                 if (bp != NULL) {
506                         int stepped = emulate_step(regs, bp->instr[0]);
507                         if (stepped == 0) {
508                                 regs->nip = (unsigned long) &bp->instr[0];
509                                 atomic_inc(&bp->ref_count);
510                         } else if (stepped < 0) {
511                                 printf("Couldn't single-step %s instruction\n",
512                                     (IS_RFID(bp->instr[0])? "rfid": "mtmsrd"));
513                         }
514                 }
515         }
516
517         insert_cpu_bpts();
518
519         mtmsr(msr);             /* restore interrupt enable */
520
521         return cmd != 'X' && cmd != EOF;
522 }
523
524 int xmon(struct pt_regs *excp)
525 {
526         struct pt_regs regs;
527
528         if (excp == NULL) {
529                 xmon_save_regs(&regs);
530                 excp = &regs;
531         }
532
533         return xmon_core(excp, 0);
534 }
535 EXPORT_SYMBOL(xmon);
536
537 irqreturn_t xmon_irq(int irq, void *d)
538 {
539         unsigned long flags;
540         local_irq_save(flags);
541         printf("Keyboard interrupt\n");
542         xmon(get_irq_regs());
543         local_irq_restore(flags);
544         return IRQ_HANDLED;
545 }
546
547 static int xmon_bpt(struct pt_regs *regs)
548 {
549         struct bpt *bp;
550         unsigned long offset;
551
552         if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF))
553                 return 0;
554
555         /* Are we at the trap at bp->instr[1] for some bp? */
556         bp = in_breakpoint_table(regs->nip, &offset);
557         if (bp != NULL && offset == 4) {
558                 regs->nip = bp->address + 4;
559                 atomic_dec(&bp->ref_count);
560                 return 1;
561         }
562
563         /* Are we at a breakpoint? */
564         bp = at_breakpoint(regs->nip);
565         if (!bp)
566                 return 0;
567
568         xmon_core(regs, 0);
569
570         return 1;
571 }
572
573 static int xmon_sstep(struct pt_regs *regs)
574 {
575         if (user_mode(regs))
576                 return 0;
577         xmon_core(regs, 0);
578         return 1;
579 }
580
581 static int xmon_dabr_match(struct pt_regs *regs)
582 {
583         if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF))
584                 return 0;
585         if (dabr.enabled == 0)
586                 return 0;
587         xmon_core(regs, 0);
588         return 1;
589 }
590
591 static int xmon_iabr_match(struct pt_regs *regs)
592 {
593         if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF))
594                 return 0;
595         if (iabr == 0)
596                 return 0;
597         xmon_core(regs, 0);
598         return 1;
599 }
600
601 static int xmon_ipi(struct pt_regs *regs)
602 {
603 #ifdef CONFIG_SMP
604         if (in_xmon && !cpu_isset(smp_processor_id(), cpus_in_xmon))
605                 xmon_core(regs, 1);
606 #endif
607         return 0;
608 }
609
610 static int xmon_fault_handler(struct pt_regs *regs)
611 {
612         struct bpt *bp;
613         unsigned long offset;
614
615         if (in_xmon && catch_memory_errors)
616                 handle_fault(regs);     /* doesn't return */
617
618         if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF)) {
619                 bp = in_breakpoint_table(regs->nip, &offset);
620                 if (bp != NULL) {
621                         regs->nip = bp->address + offset;
622                         atomic_dec(&bp->ref_count);
623                 }
624         }
625
626         return 0;
627 }
628
629 static struct bpt *at_breakpoint(unsigned long pc)
630 {
631         int i;
632         struct bpt *bp;
633
634         bp = bpts;
635         for (i = 0; i < NBPTS; ++i, ++bp)
636                 if (bp->enabled && pc == bp->address)
637                         return bp;
638         return NULL;
639 }
640
641 static struct bpt *in_breakpoint_table(unsigned long nip, unsigned long *offp)
642 {
643         unsigned long off;
644
645         off = nip - (unsigned long) bpts;
646         if (off >= sizeof(bpts))
647                 return NULL;
648         off %= sizeof(struct bpt);
649         if (off != offsetof(struct bpt, instr[0])
650             && off != offsetof(struct bpt, instr[1]))
651                 return NULL;
652         *offp = off - offsetof(struct bpt, instr[0]);
653         return (struct bpt *) (nip - off);
654 }
655
656 static struct bpt *new_breakpoint(unsigned long a)
657 {
658         struct bpt *bp;
659
660         a &= ~3UL;
661         bp = at_breakpoint(a);
662         if (bp)
663                 return bp;
664
665         for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
666                 if (!bp->enabled && atomic_read(&bp->ref_count) == 0) {
667                         bp->address = a;
668                         bp->instr[1] = bpinstr;
669                         store_inst(&bp->instr[1]);
670                         return bp;
671                 }
672         }
673
674         printf("Sorry, no free breakpoints.  Please clear one first.\n");
675         return NULL;
676 }
677
678 static void insert_bpts(void)
679 {
680         int i;
681         struct bpt *bp;
682
683         bp = bpts;
684         for (i = 0; i < NBPTS; ++i, ++bp) {
685                 if ((bp->enabled & (BP_TRAP|BP_IABR)) == 0)
686                         continue;
687                 if (mread(bp->address, &bp->instr[0], 4) != 4) {
688                         printf("Couldn't read instruction at %lx, "
689                                "disabling breakpoint there\n", bp->address);
690                         bp->enabled = 0;
691                         continue;
692                 }
693                 if (IS_MTMSRD(bp->instr[0]) || IS_RFID(bp->instr[0])) {
694                         printf("Breakpoint at %lx is on an mtmsrd or rfid "
695                                "instruction, disabling it\n", bp->address);
696                         bp->enabled = 0;
697                         continue;
698                 }
699                 store_inst(&bp->instr[0]);
700                 if (bp->enabled & BP_IABR)
701                         continue;
702                 if (mwrite(bp->address, &bpinstr, 4) != 4) {
703                         printf("Couldn't write instruction at %lx, "
704                                "disabling breakpoint there\n", bp->address);
705                         bp->enabled &= ~BP_TRAP;
706                         continue;
707                 }
708                 store_inst((void *)bp->address);
709         }
710 }
711
712 static void insert_cpu_bpts(void)
713 {
714         if (dabr.enabled)
715                 set_dabr(dabr.address | (dabr.enabled & 7));
716         if (iabr && cpu_has_feature(CPU_FTR_IABR))
717                 mtspr(SPRN_IABR, iabr->address
718                          | (iabr->enabled & (BP_IABR|BP_IABR_TE)));
719 }
720
721 static void remove_bpts(void)
722 {
723         int i;
724         struct bpt *bp;
725         unsigned instr;
726
727         bp = bpts;
728         for (i = 0; i < NBPTS; ++i, ++bp) {
729                 if ((bp->enabled & (BP_TRAP|BP_IABR)) != BP_TRAP)
730                         continue;
731                 if (mread(bp->address, &instr, 4) == 4
732                     && instr == bpinstr
733                     && mwrite(bp->address, &bp->instr, 4) != 4)
734                         printf("Couldn't remove breakpoint at %lx\n",
735                                bp->address);
736                 else
737                         store_inst((void *)bp->address);
738         }
739 }
740
741 static void remove_cpu_bpts(void)
742 {
743         set_dabr(0);
744         if (cpu_has_feature(CPU_FTR_IABR))
745                 mtspr(SPRN_IABR, 0);
746 }
747
748 /* Command interpreting routine */
749 static char *last_cmd;
750
751 static int
752 cmds(struct pt_regs *excp)
753 {
754         int cmd = 0;
755
756         last_cmd = NULL;
757         xmon_regs = excp;
758
759         if (!xmon_no_auto_backtrace) {
760                 xmon_no_auto_backtrace = 1;
761                 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
762         }
763
764         for(;;) {
765 #ifdef CONFIG_SMP
766                 printf("%x:", smp_processor_id());
767 #endif /* CONFIG_SMP */
768                 printf("mon> ");
769                 flush_input();
770                 termch = 0;
771                 cmd = skipbl();
772                 if( cmd == '\n' ) {
773                         if (last_cmd == NULL)
774                                 continue;
775                         take_input(last_cmd);
776                         last_cmd = NULL;
777                         cmd = inchar();
778                 }
779                 switch (cmd) {
780                 case 'm':
781                         cmd = inchar();
782                         switch (cmd) {
783                         case 'm':
784                         case 's':
785                         case 'd':
786                                 memops(cmd);
787                                 break;
788                         case 'l':
789                                 memlocate();
790                                 break;
791                         case 'z':
792                                 memzcan();
793                                 break;
794                         case 'i':
795                                 show_mem();
796                                 break;
797                         default:
798                                 termch = cmd;
799                                 memex();
800                         }
801                         break;
802                 case 'd':
803                         dump();
804                         break;
805                 case 'l':
806                         symbol_lookup();
807                         break;
808                 case 'r':
809                         prregs(excp);   /* print regs */
810                         break;
811                 case 'e':
812                         excprint(excp);
813                         break;
814                 case 'S':
815                         super_regs();
816                         break;
817                 case 't':
818                         backtrace(excp);
819                         break;
820                 case 'f':
821                         cacheflush();
822                         break;
823                 case 's':
824                         if (do_spu_cmd() == 0)
825                                 break;
826                         if (do_step(excp))
827                                 return cmd;
828                         break;
829                 case 'x':
830                 case 'X':
831                         return cmd;
832                 case EOF:
833                         printf(" <no input ...>\n");
834                         mdelay(2000);
835                         return cmd;
836                 case '?':
837                         printf(help_string);
838                         break;
839                 case 'b':
840                         bpt_cmds();
841                         break;
842                 case 'C':
843                         csum();
844                         break;
845                 case 'c':
846                         if (cpu_cmd())
847                                 return 0;
848                         break;
849                 case 'z':
850                         bootcmds();
851                         break;
852                 case 'p':
853                         proccall();
854                         break;
855 #ifdef CONFIG_PPC_STD_MMU
856                 case 'u':
857                         dump_segments();
858                         break;
859 #endif
860                 default:
861                         printf("Unrecognized command: ");
862                         do {
863                                 if (' ' < cmd && cmd <= '~')
864                                         putchar(cmd);
865                                 else
866                                         printf("\\x%x", cmd);
867                                 cmd = inchar();
868                         } while (cmd != '\n'); 
869                         printf(" (type ? for help)\n");
870                         break;
871                 }
872         }
873 }
874
875 /*
876  * Step a single instruction.
877  * Some instructions we emulate, others we execute with MSR_SE set.
878  */
879 static int do_step(struct pt_regs *regs)
880 {
881         unsigned int instr;
882         int stepped;
883
884         /* check we are in 64-bit kernel mode, translation enabled */
885         if ((regs->msr & (MSR_SF|MSR_PR|MSR_IR)) == (MSR_SF|MSR_IR)) {
886                 if (mread(regs->nip, &instr, 4) == 4) {
887                         stepped = emulate_step(regs, instr);
888                         if (stepped < 0) {
889                                 printf("Couldn't single-step %s instruction\n",
890                                        (IS_RFID(instr)? "rfid": "mtmsrd"));
891                                 return 0;
892                         }
893                         if (stepped > 0) {
894                                 regs->trap = 0xd00 | (regs->trap & 1);
895                                 printf("stepped to ");
896                                 xmon_print_symbol(regs->nip, " ", "\n");
897                                 ppc_inst_dump(regs->nip, 1, 0);
898                                 return 0;
899                         }
900                 }
901         }
902         regs->msr |= MSR_SE;
903         return 1;
904 }
905
906 static void bootcmds(void)
907 {
908         int cmd;
909
910         cmd = inchar();
911         if (cmd == 'r')
912                 ppc_md.restart(NULL);
913         else if (cmd == 'h')
914                 ppc_md.halt();
915         else if (cmd == 'p')
916                 ppc_md.power_off();
917 }
918
919 static int cpu_cmd(void)
920 {
921 #ifdef CONFIG_SMP
922         unsigned long cpu;
923         int timeout;
924         int count;
925
926         if (!scanhex(&cpu)) {
927                 /* print cpus waiting or in xmon */
928                 printf("cpus stopped:");
929                 count = 0;
930                 for (cpu = 0; cpu < NR_CPUS; ++cpu) {
931                         if (cpu_isset(cpu, cpus_in_xmon)) {
932                                 if (count == 0)
933                                         printf(" %x", cpu);
934                                 ++count;
935                         } else {
936                                 if (count > 1)
937                                         printf("-%x", cpu - 1);
938                                 count = 0;
939                         }
940                 }
941                 if (count > 1)
942                         printf("-%x", NR_CPUS - 1);
943                 printf("\n");
944                 return 0;
945         }
946         /* try to switch to cpu specified */
947         if (!cpu_isset(cpu, cpus_in_xmon)) {
948                 printf("cpu 0x%x isn't in xmon\n", cpu);
949                 return 0;
950         }
951         xmon_taken = 0;
952         mb();
953         xmon_owner = cpu;
954         timeout = 10000000;
955         while (!xmon_taken) {
956                 if (--timeout == 0) {
957                         if (test_and_set_bit(0, &xmon_taken))
958                                 break;
959                         /* take control back */
960                         mb();
961                         xmon_owner = smp_processor_id();
962                         printf("cpu %u didn't take control\n", cpu);
963                         return 0;
964                 }
965                 barrier();
966         }
967         return 1;
968 #else
969         return 0;
970 #endif /* CONFIG_SMP */
971 }
972
973 static unsigned short fcstab[256] = {
974         0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
975         0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
976         0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
977         0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
978         0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
979         0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
980         0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
981         0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
982         0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
983         0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
984         0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
985         0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
986         0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
987         0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
988         0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
989         0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
990         0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
991         0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
992         0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
993         0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
994         0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
995         0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
996         0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
997         0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
998         0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
999         0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
1000         0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
1001         0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
1002         0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
1003         0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
1004         0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
1005         0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
1006 };
1007
1008 #define FCS(fcs, c)     (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
1009
1010 static void
1011 csum(void)
1012 {
1013         unsigned int i;
1014         unsigned short fcs;
1015         unsigned char v;
1016
1017         if (!scanhex(&adrs))
1018                 return;
1019         if (!scanhex(&ncsum))
1020                 return;
1021         fcs = 0xffff;
1022         for (i = 0; i < ncsum; ++i) {
1023                 if (mread(adrs+i, &v, 1) == 0) {
1024                         printf("csum stopped at %x\n", adrs+i);
1025                         break;
1026                 }
1027                 fcs = FCS(fcs, v);
1028         }
1029         printf("%x\n", fcs);
1030 }
1031
1032 /*
1033  * Check if this is a suitable place to put a breakpoint.
1034  */
1035 static long check_bp_loc(unsigned long addr)
1036 {
1037         unsigned int instr;
1038
1039         addr &= ~3;
1040         if (!is_kernel_addr(addr)) {
1041                 printf("Breakpoints may only be placed at kernel addresses\n");
1042                 return 0;
1043         }
1044         if (!mread(addr, &instr, sizeof(instr))) {
1045                 printf("Can't read instruction at address %lx\n", addr);
1046                 return 0;
1047         }
1048         if (IS_MTMSRD(instr) || IS_RFID(instr)) {
1049                 printf("Breakpoints may not be placed on mtmsrd or rfid "
1050                        "instructions\n");
1051                 return 0;
1052         }
1053         return 1;
1054 }
1055
1056 static char *breakpoint_help_string = 
1057     "Breakpoint command usage:\n"
1058     "b                show breakpoints\n"
1059     "b <addr> [cnt]   set breakpoint at given instr addr\n"
1060     "bc               clear all breakpoints\n"
1061     "bc <n/addr>      clear breakpoint number n or at addr\n"
1062     "bi <addr> [cnt]  set hardware instr breakpoint (POWER3/RS64 only)\n"
1063     "bd <addr> [cnt]  set hardware data breakpoint\n"
1064     "";
1065
1066 static void
1067 bpt_cmds(void)
1068 {
1069         int cmd;
1070         unsigned long a;
1071         int mode, i;
1072         struct bpt *bp;
1073         const char badaddr[] = "Only kernel addresses are permitted "
1074                 "for breakpoints\n";
1075
1076         cmd = inchar();
1077         switch (cmd) {
1078 #ifndef CONFIG_8xx
1079         case 'd':       /* bd - hardware data breakpoint */
1080                 mode = 7;
1081                 cmd = inchar();
1082                 if (cmd == 'r')
1083                         mode = 5;
1084                 else if (cmd == 'w')
1085                         mode = 6;
1086                 else
1087                         termch = cmd;
1088                 dabr.address = 0;
1089                 dabr.enabled = 0;
1090                 if (scanhex(&dabr.address)) {
1091                         if (!is_kernel_addr(dabr.address)) {
1092                                 printf(badaddr);
1093                                 break;
1094                         }
1095                         dabr.address &= ~7;
1096                         dabr.enabled = mode | BP_DABR;
1097                 }
1098                 break;
1099
1100         case 'i':       /* bi - hardware instr breakpoint */
1101                 if (!cpu_has_feature(CPU_FTR_IABR)) {
1102                         printf("Hardware instruction breakpoint "
1103                                "not supported on this cpu\n");
1104                         break;
1105                 }
1106                 if (iabr) {
1107                         iabr->enabled &= ~(BP_IABR | BP_IABR_TE);
1108                         iabr = NULL;
1109                 }
1110                 if (!scanhex(&a))
1111                         break;
1112                 if (!check_bp_loc(a))
1113                         break;
1114                 bp = new_breakpoint(a);
1115                 if (bp != NULL) {
1116                         bp->enabled |= BP_IABR | BP_IABR_TE;
1117                         iabr = bp;
1118                 }
1119                 break;
1120 #endif
1121
1122         case 'c':
1123                 if (!scanhex(&a)) {
1124                         /* clear all breakpoints */
1125                         for (i = 0; i < NBPTS; ++i)
1126                                 bpts[i].enabled = 0;
1127                         iabr = NULL;
1128                         dabr.enabled = 0;
1129                         printf("All breakpoints cleared\n");
1130                         break;
1131                 }
1132
1133                 if (a <= NBPTS && a >= 1) {
1134                         /* assume a breakpoint number */
1135                         bp = &bpts[a-1];        /* bp nums are 1 based */
1136                 } else {
1137                         /* assume a breakpoint address */
1138                         bp = at_breakpoint(a);
1139                         if (bp == 0) {
1140                                 printf("No breakpoint at %x\n", a);
1141                                 break;
1142                         }
1143                 }
1144
1145                 printf("Cleared breakpoint %x (", BP_NUM(bp));
1146                 xmon_print_symbol(bp->address, " ", ")\n");
1147                 bp->enabled = 0;
1148                 break;
1149
1150         default:
1151                 termch = cmd;
1152                 cmd = skipbl();
1153                 if (cmd == '?') {
1154                         printf(breakpoint_help_string);
1155                         break;
1156                 }
1157                 termch = cmd;
1158                 if (!scanhex(&a)) {
1159                         /* print all breakpoints */
1160                         printf("   type            address\n");
1161                         if (dabr.enabled) {
1162                                 printf("   data   "REG"  [", dabr.address);
1163                                 if (dabr.enabled & 1)
1164                                         printf("r");
1165                                 if (dabr.enabled & 2)
1166                                         printf("w");
1167                                 printf("]\n");
1168                         }
1169                         for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
1170                                 if (!bp->enabled)
1171                                         continue;
1172                                 printf("%2x %s   ", BP_NUM(bp),
1173                                     (bp->enabled & BP_IABR)? "inst": "trap");
1174                                 xmon_print_symbol(bp->address, "  ", "\n");
1175                         }
1176                         break;
1177                 }
1178
1179                 if (!check_bp_loc(a))
1180                         break;
1181                 bp = new_breakpoint(a);
1182                 if (bp != NULL)
1183                         bp->enabled |= BP_TRAP;
1184                 break;
1185         }
1186 }
1187
1188 /* Very cheap human name for vector lookup. */
1189 static
1190 const char *getvecname(unsigned long vec)
1191 {
1192         char *ret;
1193
1194         switch (vec) {
1195         case 0x100:     ret = "(System Reset)"; break;
1196         case 0x200:     ret = "(Machine Check)"; break;
1197         case 0x300:     ret = "(Data Access)"; break;
1198         case 0x380:     ret = "(Data SLB Access)"; break;
1199         case 0x400:     ret = "(Instruction Access)"; break;
1200         case 0x480:     ret = "(Instruction SLB Access)"; break;
1201         case 0x500:     ret = "(Hardware Interrupt)"; break;
1202         case 0x600:     ret = "(Alignment)"; break;
1203         case 0x700:     ret = "(Program Check)"; break;
1204         case 0x800:     ret = "(FPU Unavailable)"; break;
1205         case 0x900:     ret = "(Decrementer)"; break;
1206         case 0xc00:     ret = "(System Call)"; break;
1207         case 0xd00:     ret = "(Single Step)"; break;
1208         case 0xf00:     ret = "(Performance Monitor)"; break;
1209         case 0xf20:     ret = "(Altivec Unavailable)"; break;
1210         case 0x1300:    ret = "(Instruction Breakpoint)"; break;
1211         default: ret = "";
1212         }
1213         return ret;
1214 }
1215
1216 static void get_function_bounds(unsigned long pc, unsigned long *startp,
1217                                 unsigned long *endp)
1218 {
1219         unsigned long size, offset;
1220         const char *name;
1221         char *modname;
1222
1223         *startp = *endp = 0;
1224         if (pc == 0)
1225                 return;
1226         if (setjmp(bus_error_jmp) == 0) {
1227                 catch_memory_errors = 1;
1228                 sync();
1229                 name = kallsyms_lookup(pc, &size, &offset, &modname, tmpstr);
1230                 if (name != NULL) {
1231                         *startp = pc - offset;
1232                         *endp = pc - offset + size;
1233                 }
1234                 sync();
1235         }
1236         catch_memory_errors = 0;
1237 }
1238
1239 static int xmon_depth_to_print = 64;
1240
1241 #ifdef CONFIG_PPC64
1242 #define LRSAVE_OFFSET           0x10
1243 #define REG_FRAME_MARKER        0x7265677368657265ul    /* "regshere" */
1244 #define MARKER_OFFSET           0x60
1245 #define REGS_OFFSET             0x70
1246 #else
1247 #define LRSAVE_OFFSET           4
1248 #define REG_FRAME_MARKER        0x72656773
1249 #define MARKER_OFFSET           8
1250 #define REGS_OFFSET             16
1251 #endif
1252
1253 static void xmon_show_stack(unsigned long sp, unsigned long lr,
1254                             unsigned long pc)
1255 {
1256         unsigned long ip;
1257         unsigned long newsp;
1258         unsigned long marker;
1259         int count = 0;
1260         struct pt_regs regs;
1261
1262         do {
1263                 if (sp < PAGE_OFFSET) {
1264                         if (sp != 0)
1265                                 printf("SP (%lx) is in userspace\n", sp);
1266                         break;
1267                 }
1268
1269                 if (!mread(sp + LRSAVE_OFFSET, &ip, sizeof(unsigned long))
1270                     || !mread(sp, &newsp, sizeof(unsigned long))) {
1271                         printf("Couldn't read stack frame at %lx\n", sp);
1272                         break;
1273                 }
1274
1275                 /*
1276                  * For the first stack frame, try to work out if
1277                  * LR and/or the saved LR value in the bottommost
1278                  * stack frame are valid.
1279                  */
1280                 if ((pc | lr) != 0) {
1281                         unsigned long fnstart, fnend;
1282                         unsigned long nextip;
1283                         int printip = 1;
1284
1285                         get_function_bounds(pc, &fnstart, &fnend);
1286                         nextip = 0;
1287                         if (newsp > sp)
1288                                 mread(newsp + LRSAVE_OFFSET, &nextip,
1289                                       sizeof(unsigned long));
1290                         if (lr == ip) {
1291                                 if (lr < PAGE_OFFSET
1292                                     || (fnstart <= lr && lr < fnend))
1293                                         printip = 0;
1294                         } else if (lr == nextip) {
1295                                 printip = 0;
1296                         } else if (lr >= PAGE_OFFSET
1297                                    && !(fnstart <= lr && lr < fnend)) {
1298                                 printf("[link register   ] ");
1299                                 xmon_print_symbol(lr, " ", "\n");
1300                         }
1301                         if (printip) {
1302                                 printf("["REG"] ", sp);
1303                                 xmon_print_symbol(ip, " ", " (unreliable)\n");
1304                         }
1305                         pc = lr = 0;
1306
1307                 } else {
1308                         printf("["REG"] ", sp);
1309                         xmon_print_symbol(ip, " ", "\n");
1310                 }
1311
1312                 /* Look for "regshere" marker to see if this is
1313                    an exception frame. */
1314                 if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long))
1315                     && marker == REG_FRAME_MARKER) {
1316                         if (mread(sp + REGS_OFFSET, &regs, sizeof(regs))
1317                             != sizeof(regs)) {
1318                                 printf("Couldn't read registers at %lx\n",
1319                                        sp + REGS_OFFSET);
1320                                 break;
1321                         }
1322                         printf("--- Exception: %lx %s at ", regs.trap,
1323                                getvecname(TRAP(&regs)));
1324                         pc = regs.nip;
1325                         lr = regs.link;
1326                         xmon_print_symbol(pc, " ", "\n");
1327                 }
1328
1329                 if (newsp == 0)
1330                         break;
1331
1332                 sp = newsp;
1333         } while (count++ < xmon_depth_to_print);
1334 }
1335
1336 static void backtrace(struct pt_regs *excp)
1337 {
1338         unsigned long sp;
1339
1340         if (scanhex(&sp))
1341                 xmon_show_stack(sp, 0, 0);
1342         else
1343                 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
1344         scannl();
1345 }
1346
1347 static void print_bug_trap(struct pt_regs *regs)
1348 {
1349         const struct bug_entry *bug;
1350         unsigned long addr;
1351
1352         if (regs->msr & MSR_PR)
1353                 return;         /* not in kernel */
1354         addr = regs->nip;       /* address of trap instruction */
1355         if (addr < PAGE_OFFSET)
1356                 return;
1357         bug = find_bug(regs->nip);
1358         if (bug == NULL)
1359                 return;
1360         if (is_warning_bug(bug))
1361                 return;
1362
1363 #ifdef CONFIG_DEBUG_BUGVERBOSE
1364         printf("kernel BUG at %s:%u!\n",
1365                bug->file, bug->line);
1366 #else
1367         printf("kernel BUG at %p!\n", (void *)bug->bug_addr);
1368 #endif
1369 }
1370
1371 void excprint(struct pt_regs *fp)
1372 {
1373         unsigned long trap;
1374
1375 #ifdef CONFIG_SMP
1376         printf("cpu 0x%x: ", smp_processor_id());
1377 #endif /* CONFIG_SMP */
1378
1379         trap = TRAP(fp);
1380         printf("Vector: %lx %s at [%lx]\n", fp->trap, getvecname(trap), fp);
1381         printf("    pc: ");
1382         xmon_print_symbol(fp->nip, ": ", "\n");
1383
1384         printf("    lr: ", fp->link);
1385         xmon_print_symbol(fp->link, ": ", "\n");
1386
1387         printf("    sp: %lx\n", fp->gpr[1]);
1388         printf("   msr: %lx\n", fp->msr);
1389
1390         if (trap == 0x300 || trap == 0x380 || trap == 0x600) {
1391                 printf("   dar: %lx\n", fp->dar);
1392                 if (trap != 0x380)
1393                         printf(" dsisr: %lx\n", fp->dsisr);
1394         }
1395
1396         printf("  current = 0x%lx\n", current);
1397 #ifdef CONFIG_PPC64
1398         printf("  paca    = 0x%lx\n", get_paca());
1399 #endif
1400         if (current) {
1401                 printf("    pid   = %ld, comm = %s\n",
1402                        current->pid, current->comm);
1403         }
1404
1405         if (trap == 0x700)
1406                 print_bug_trap(fp);
1407 }
1408
1409 void prregs(struct pt_regs *fp)
1410 {
1411         int n, trap;
1412         unsigned long base;
1413         struct pt_regs regs;
1414
1415         if (scanhex(&base)) {
1416                 if (setjmp(bus_error_jmp) == 0) {
1417                         catch_memory_errors = 1;
1418                         sync();
1419                         regs = *(struct pt_regs *)base;
1420                         sync();
1421                         __delay(200);
1422                 } else {
1423                         catch_memory_errors = 0;
1424                         printf("*** Error reading registers from "REG"\n",
1425                                base);
1426                         return;
1427                 }
1428                 catch_memory_errors = 0;
1429                 fp = &regs;
1430         }
1431
1432 #ifdef CONFIG_PPC64
1433         if (FULL_REGS(fp)) {
1434                 for (n = 0; n < 16; ++n)
1435                         printf("R%.2ld = "REG"   R%.2ld = "REG"\n",
1436                                n, fp->gpr[n], n+16, fp->gpr[n+16]);
1437         } else {
1438                 for (n = 0; n < 7; ++n)
1439                         printf("R%.2ld = "REG"   R%.2ld = "REG"\n",
1440                                n, fp->gpr[n], n+7, fp->gpr[n+7]);
1441         }
1442 #else
1443         for (n = 0; n < 32; ++n) {
1444                 printf("R%.2d = %.8x%s", n, fp->gpr[n],
1445                        (n & 3) == 3? "\n": "   ");
1446                 if (n == 12 && !FULL_REGS(fp)) {
1447                         printf("\n");
1448                         break;
1449                 }
1450         }
1451 #endif
1452         printf("pc  = ");
1453         xmon_print_symbol(fp->nip, " ", "\n");
1454         printf("lr  = ");
1455         xmon_print_symbol(fp->link, " ", "\n");
1456         printf("msr = "REG"   cr  = %.8lx\n", fp->msr, fp->ccr);
1457         printf("ctr = "REG"   xer = "REG"   trap = %4lx\n",
1458                fp->ctr, fp->xer, fp->trap);
1459         trap = TRAP(fp);
1460         if (trap == 0x300 || trap == 0x380 || trap == 0x600)
1461                 printf("dar = "REG"   dsisr = %.8lx\n", fp->dar, fp->dsisr);
1462 }
1463
1464 void cacheflush(void)
1465 {
1466         int cmd;
1467         unsigned long nflush;
1468
1469         cmd = inchar();
1470         if (cmd != 'i')
1471                 termch = cmd;
1472         scanhex((void *)&adrs);
1473         if (termch != '\n')
1474                 termch = 0;
1475         nflush = 1;
1476         scanhex(&nflush);
1477         nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES;
1478         if (setjmp(bus_error_jmp) == 0) {
1479                 catch_memory_errors = 1;
1480                 sync();
1481
1482                 if (cmd != 'i') {
1483                         for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1484                                 cflush((void *) adrs);
1485                 } else {
1486                         for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1487                                 cinval((void *) adrs);
1488                 }
1489                 sync();
1490                 /* wait a little while to see if we get a machine check */
1491                 __delay(200);
1492         }
1493         catch_memory_errors = 0;
1494 }
1495
1496 unsigned long
1497 read_spr(int n)
1498 {
1499         unsigned int instrs[2];
1500         unsigned long (*code)(void);
1501         unsigned long ret = -1UL;
1502 #ifdef CONFIG_PPC64
1503         unsigned long opd[3];
1504
1505         opd[0] = (unsigned long)instrs;
1506         opd[1] = 0;
1507         opd[2] = 0;
1508         code = (unsigned long (*)(void)) opd;
1509 #else
1510         code = (unsigned long (*)(void)) instrs;
1511 #endif
1512
1513         /* mfspr r3,n; blr */
1514         instrs[0] = 0x7c6002a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1515         instrs[1] = 0x4e800020;
1516         store_inst(instrs);
1517         store_inst(instrs+1);
1518
1519         if (setjmp(bus_error_jmp) == 0) {
1520                 catch_memory_errors = 1;
1521                 sync();
1522
1523                 ret = code();
1524
1525                 sync();
1526                 /* wait a little while to see if we get a machine check */
1527                 __delay(200);
1528                 n = size;
1529         }
1530
1531         return ret;
1532 }
1533
1534 void
1535 write_spr(int n, unsigned long val)
1536 {
1537         unsigned int instrs[2];
1538         unsigned long (*code)(unsigned long);
1539 #ifdef CONFIG_PPC64
1540         unsigned long opd[3];
1541
1542         opd[0] = (unsigned long)instrs;
1543         opd[1] = 0;
1544         opd[2] = 0;
1545         code = (unsigned long (*)(unsigned long)) opd;
1546 #else
1547         code = (unsigned long (*)(unsigned long)) instrs;
1548 #endif
1549
1550         instrs[0] = 0x7c6003a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1551         instrs[1] = 0x4e800020;
1552         store_inst(instrs);
1553         store_inst(instrs+1);
1554
1555         if (setjmp(bus_error_jmp) == 0) {
1556                 catch_memory_errors = 1;
1557                 sync();
1558
1559                 code(val);
1560
1561                 sync();
1562                 /* wait a little while to see if we get a machine check */
1563                 __delay(200);
1564                 n = size;
1565         }
1566 }
1567
1568 static unsigned long regno;
1569 extern char exc_prolog;
1570 extern char dec_exc;
1571
1572 void super_regs(void)
1573 {
1574         int cmd;
1575         unsigned long val;
1576
1577         cmd = skipbl();
1578         if (cmd == '\n') {
1579                 unsigned long sp, toc;
1580                 asm("mr %0,1" : "=r" (sp) :);
1581                 asm("mr %0,2" : "=r" (toc) :);
1582
1583                 printf("msr  = "REG"  sprg0= "REG"\n",
1584                        mfmsr(), mfspr(SPRN_SPRG0));
1585                 printf("pvr  = "REG"  sprg1= "REG"\n",
1586                        mfspr(SPRN_PVR), mfspr(SPRN_SPRG1)); 
1587                 printf("dec  = "REG"  sprg2= "REG"\n",
1588                        mfspr(SPRN_DEC), mfspr(SPRN_SPRG2));
1589                 printf("sp   = "REG"  sprg3= "REG"\n", sp, mfspr(SPRN_SPRG3));
1590                 printf("toc  = "REG"  dar  = "REG"\n", toc, mfspr(SPRN_DAR));
1591 #ifdef CONFIG_PPC_ISERIES
1592                 if (firmware_has_feature(FW_FEATURE_ISERIES)) {
1593                         struct paca_struct *ptrPaca;
1594                         struct lppaca *ptrLpPaca;
1595                         struct ItLpRegSave *ptrLpRegSave;
1596
1597                         /* Dump out relevant Paca data areas. */
1598                         printf("Paca: \n");
1599                         ptrPaca = get_paca();
1600
1601                         printf("  Local Processor Control Area (LpPaca): \n");
1602                         ptrLpPaca = ptrPaca->lppaca_ptr;
1603                         printf("    Saved Srr0=%.16lx  Saved Srr1=%.16lx \n",
1604                                ptrLpPaca->saved_srr0, ptrLpPaca->saved_srr1);
1605                         printf("    Saved Gpr3=%.16lx  Saved Gpr4=%.16lx \n",
1606                                ptrLpPaca->saved_gpr3, ptrLpPaca->saved_gpr4);
1607                         printf("    Saved Gpr5=%.16lx \n", ptrLpPaca->saved_gpr5);
1608
1609                         printf("  Local Processor Register Save Area (LpRegSave): \n");
1610                         ptrLpRegSave = ptrPaca->reg_save_ptr;
1611                         printf("    Saved Sprg0=%.16lx  Saved Sprg1=%.16lx \n",
1612                                ptrLpRegSave->xSPRG0, ptrLpRegSave->xSPRG0);
1613                         printf("    Saved Sprg2=%.16lx  Saved Sprg3=%.16lx \n",
1614                                ptrLpRegSave->xSPRG2, ptrLpRegSave->xSPRG3);
1615                         printf("    Saved Msr  =%.16lx  Saved Nia  =%.16lx \n",
1616                                ptrLpRegSave->xMSR, ptrLpRegSave->xNIA);
1617                 }
1618 #endif
1619
1620                 return;
1621         }
1622
1623         scanhex(&regno);
1624         switch (cmd) {
1625         case 'w':
1626                 val = read_spr(regno);
1627                 scanhex(&val);
1628                 write_spr(regno, val);
1629                 /* fall through */
1630         case 'r':
1631                 printf("spr %lx = %lx\n", regno, read_spr(regno));
1632                 break;
1633         }
1634         scannl();
1635 }
1636
1637 /*
1638  * Stuff for reading and writing memory safely
1639  */
1640 int
1641 mread(unsigned long adrs, void *buf, int size)
1642 {
1643         volatile int n;
1644         char *p, *q;
1645
1646         n = 0;
1647         if (setjmp(bus_error_jmp) == 0) {
1648                 catch_memory_errors = 1;
1649                 sync();
1650                 p = (char *)adrs;
1651                 q = (char *)buf;
1652                 switch (size) {
1653                 case 2:
1654                         *(u16 *)q = *(u16 *)p;
1655                         break;
1656                 case 4:
1657                         *(u32 *)q = *(u32 *)p;
1658                         break;
1659                 case 8:
1660                         *(u64 *)q = *(u64 *)p;
1661                         break;
1662                 default:
1663                         for( ; n < size; ++n) {
1664                                 *q++ = *p++;
1665                                 sync();
1666                         }
1667                 }
1668                 sync();
1669                 /* wait a little while to see if we get a machine check */
1670                 __delay(200);
1671                 n = size;
1672         }
1673         catch_memory_errors = 0;
1674         return n;
1675 }
1676
1677 int
1678 mwrite(unsigned long adrs, void *buf, int size)
1679 {
1680         volatile int n;
1681         char *p, *q;
1682
1683         n = 0;
1684         if (setjmp(bus_error_jmp) == 0) {
1685                 catch_memory_errors = 1;
1686                 sync();
1687                 p = (char *) adrs;
1688                 q = (char *) buf;
1689                 switch (size) {
1690                 case 2:
1691                         *(u16 *)p = *(u16 *)q;
1692                         break;
1693                 case 4:
1694                         *(u32 *)p = *(u32 *)q;
1695                         break;
1696                 case 8:
1697                         *(u64 *)p = *(u64 *)q;
1698                         break;
1699                 default:
1700                         for ( ; n < size; ++n) {
1701                                 *p++ = *q++;
1702                                 sync();
1703                         }
1704                 }
1705                 sync();
1706                 /* wait a little while to see if we get a machine check */
1707                 __delay(200);
1708                 n = size;
1709         } else {
1710                 printf("*** Error writing address %x\n", adrs + n);
1711         }
1712         catch_memory_errors = 0;
1713         return n;
1714 }
1715
1716 static int fault_type;
1717 static int fault_except;
1718 static char *fault_chars[] = { "--", "**", "##" };
1719
1720 static int handle_fault(struct pt_regs *regs)
1721 {
1722         fault_except = TRAP(regs);
1723         switch (TRAP(regs)) {
1724         case 0x200:
1725                 fault_type = 0;
1726                 break;
1727         case 0x300:
1728         case 0x380:
1729                 fault_type = 1;
1730                 break;
1731         default:
1732                 fault_type = 2;
1733         }
1734
1735         longjmp(bus_error_jmp, 1);
1736
1737         return 0;
1738 }
1739
1740 #define SWAP(a, b, t)   ((t) = (a), (a) = (b), (b) = (t))
1741
1742 void
1743 byterev(unsigned char *val, int size)
1744 {
1745         int t;
1746         
1747         switch (size) {
1748         case 2:
1749                 SWAP(val[0], val[1], t);
1750                 break;
1751         case 4:
1752                 SWAP(val[0], val[3], t);
1753                 SWAP(val[1], val[2], t);
1754                 break;
1755         case 8: /* is there really any use for this? */
1756                 SWAP(val[0], val[7], t);
1757                 SWAP(val[1], val[6], t);
1758                 SWAP(val[2], val[5], t);
1759                 SWAP(val[3], val[4], t);
1760                 break;
1761         }
1762 }
1763
1764 static int brev;
1765 static int mnoread;
1766
1767 static char *memex_help_string = 
1768     "Memory examine command usage:\n"
1769     "m [addr] [flags] examine/change memory\n"
1770     "  addr is optional.  will start where left off.\n"
1771     "  flags may include chars from this set:\n"
1772     "    b   modify by bytes (default)\n"
1773     "    w   modify by words (2 byte)\n"
1774     "    l   modify by longs (4 byte)\n"
1775     "    d   modify by doubleword (8 byte)\n"
1776     "    r   toggle reverse byte order mode\n"
1777     "    n   do not read memory (for i/o spaces)\n"
1778     "    .   ok to read (default)\n"
1779     "NOTE: flags are saved as defaults\n"
1780     "";
1781
1782 static char *memex_subcmd_help_string = 
1783     "Memory examine subcommands:\n"
1784     "  hexval   write this val to current location\n"
1785     "  'string' write chars from string to this location\n"
1786     "  '        increment address\n"
1787     "  ^        decrement address\n"
1788     "  /        increment addr by 0x10.  //=0x100, ///=0x1000, etc\n"
1789     "  \\        decrement addr by 0x10.  \\\\=0x100, \\\\\\=0x1000, etc\n"
1790     "  `        clear no-read flag\n"
1791     "  ;        stay at this addr\n"
1792     "  v        change to byte mode\n"
1793     "  w        change to word (2 byte) mode\n"
1794     "  l        change to long (4 byte) mode\n"
1795     "  u        change to doubleword (8 byte) mode\n"
1796     "  m addr   change current addr\n"
1797     "  n        toggle no-read flag\n"
1798     "  r        toggle byte reverse flag\n"
1799     "  < count  back up count bytes\n"
1800     "  > count  skip forward count bytes\n"
1801     "  x        exit this mode\n"
1802     "";
1803
1804 void
1805 memex(void)
1806 {
1807         int cmd, inc, i, nslash;
1808         unsigned long n;
1809         unsigned char val[16];
1810
1811         scanhex((void *)&adrs);
1812         cmd = skipbl();
1813         if (cmd == '?') {
1814                 printf(memex_help_string);
1815                 return;
1816         } else {
1817                 termch = cmd;
1818         }
1819         last_cmd = "m\n";
1820         while ((cmd = skipbl()) != '\n') {
1821                 switch( cmd ){
1822                 case 'b':       size = 1;       break;
1823                 case 'w':       size = 2;       break;
1824                 case 'l':       size = 4;       break;
1825                 case 'd':       size = 8;       break;
1826                 case 'r':       brev = !brev;   break;
1827                 case 'n':       mnoread = 1;    break;
1828                 case '.':       mnoread = 0;    break;
1829                 }
1830         }
1831         if( size <= 0 )
1832                 size = 1;
1833         else if( size > 8 )
1834                 size = 8;
1835         for(;;){
1836                 if (!mnoread)
1837                         n = mread(adrs, val, size);
1838                 printf(REG"%c", adrs, brev? 'r': ' ');
1839                 if (!mnoread) {
1840                         if (brev)
1841                                 byterev(val, size);
1842                         putchar(' ');
1843                         for (i = 0; i < n; ++i)
1844                                 printf("%.2x", val[i]);
1845                         for (; i < size; ++i)
1846                                 printf("%s", fault_chars[fault_type]);
1847                 }
1848                 putchar(' ');
1849                 inc = size;
1850                 nslash = 0;
1851                 for(;;){
1852                         if( scanhex(&n) ){
1853                                 for (i = 0; i < size; ++i)
1854                                         val[i] = n >> (i * 8);
1855                                 if (!brev)
1856                                         byterev(val, size);
1857                                 mwrite(adrs, val, size);
1858                                 inc = size;
1859                         }
1860                         cmd = skipbl();
1861                         if (cmd == '\n')
1862                                 break;
1863                         inc = 0;
1864                         switch (cmd) {
1865                         case '\'':
1866                                 for(;;){
1867                                         n = inchar();
1868                                         if( n == '\\' )
1869                                                 n = bsesc();
1870                                         else if( n == '\'' )
1871                                                 break;
1872                                         for (i = 0; i < size; ++i)
1873                                                 val[i] = n >> (i * 8);
1874                                         if (!brev)
1875                                                 byterev(val, size);
1876                                         mwrite(adrs, val, size);
1877                                         adrs += size;
1878                                 }
1879                                 adrs -= size;
1880                                 inc = size;
1881                                 break;
1882                         case ',':
1883                                 adrs += size;
1884                                 break;
1885                         case '.':
1886                                 mnoread = 0;
1887                                 break;
1888                         case ';':
1889                                 break;
1890                         case 'x':
1891                         case EOF:
1892                                 scannl();
1893                                 return;
1894                         case 'b':
1895                         case 'v':
1896                                 size = 1;
1897                                 break;
1898                         case 'w':
1899                                 size = 2;
1900                                 break;
1901                         case 'l':
1902                                 size = 4;
1903                                 break;
1904                         case 'u':
1905                                 size = 8;
1906                                 break;
1907                         case '^':
1908                                 adrs -= size;
1909                                 break;
1910                                 break;
1911                         case '/':
1912                                 if (nslash > 0)
1913                                         adrs -= 1 << nslash;
1914                                 else
1915                                         nslash = 0;
1916                                 nslash += 4;
1917                                 adrs += 1 << nslash;
1918                                 break;
1919                         case '\\':
1920                                 if (nslash < 0)
1921                                         adrs += 1 << -nslash;
1922                                 else
1923                                         nslash = 0;
1924                                 nslash -= 4;
1925                                 adrs -= 1 << -nslash;
1926                                 break;
1927                         case 'm':
1928                                 scanhex((void *)&adrs);
1929                                 break;
1930                         case 'n':
1931                                 mnoread = 1;
1932                                 break;
1933                         case 'r':
1934                                 brev = !brev;
1935                                 break;
1936                         case '<':
1937                                 n = size;
1938                                 scanhex(&n);
1939                                 adrs -= n;
1940                                 break;
1941                         case '>':
1942                                 n = size;
1943                                 scanhex(&n);
1944                                 adrs += n;
1945                                 break;
1946                         case '?':
1947                                 printf(memex_subcmd_help_string);
1948                                 break;
1949                         }
1950                 }
1951                 adrs += inc;
1952         }
1953 }
1954
1955 int
1956 bsesc(void)
1957 {
1958         int c;
1959
1960         c = inchar();
1961         switch( c ){
1962         case 'n':       c = '\n';       break;
1963         case 'r':       c = '\r';       break;
1964         case 'b':       c = '\b';       break;
1965         case 't':       c = '\t';       break;
1966         }
1967         return c;
1968 }
1969
1970 static void xmon_rawdump (unsigned long adrs, long ndump)
1971 {
1972         long n, m, r, nr;
1973         unsigned char temp[16];
1974
1975         for (n = ndump; n > 0;) {
1976                 r = n < 16? n: 16;
1977                 nr = mread(adrs, temp, r);
1978                 adrs += nr;
1979                 for (m = 0; m < r; ++m) {
1980                         if (m < nr)
1981                                 printf("%.2x", temp[m]);
1982                         else
1983                                 printf("%s", fault_chars[fault_type]);
1984                 }
1985                 n -= r;
1986                 if (nr < r)
1987                         break;
1988         }
1989         printf("\n");
1990 }
1991
1992 #define isxdigit(c)     (('0' <= (c) && (c) <= '9') \
1993                          || ('a' <= (c) && (c) <= 'f') \
1994                          || ('A' <= (c) && (c) <= 'F'))
1995 void
1996 dump(void)
1997 {
1998         int c;
1999
2000         c = inchar();
2001         if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
2002                 termch = c;
2003         scanhex((void *)&adrs);
2004         if (termch != '\n')
2005                 termch = 0;
2006         if (c == 'i') {
2007                 scanhex(&nidump);
2008                 if (nidump == 0)
2009                         nidump = 16;
2010                 else if (nidump > MAX_DUMP)
2011                         nidump = MAX_DUMP;
2012                 adrs += ppc_inst_dump(adrs, nidump, 1);
2013                 last_cmd = "di\n";
2014         } else if (c == 'r') {
2015                 scanhex(&ndump);
2016                 if (ndump == 0)
2017                         ndump = 64;
2018                 xmon_rawdump(adrs, ndump);
2019                 adrs += ndump;
2020                 last_cmd = "dr\n";
2021         } else {
2022                 scanhex(&ndump);
2023                 if (ndump == 0)
2024                         ndump = 64;
2025                 else if (ndump > MAX_DUMP)
2026                         ndump = MAX_DUMP;
2027                 prdump(adrs, ndump);
2028                 adrs += ndump;
2029                 last_cmd = "d\n";
2030         }
2031 }
2032
2033 void
2034 prdump(unsigned long adrs, long ndump)
2035 {
2036         long n, m, c, r, nr;
2037         unsigned char temp[16];
2038
2039         for (n = ndump; n > 0;) {
2040                 printf(REG, adrs);
2041                 putchar(' ');
2042                 r = n < 16? n: 16;
2043                 nr = mread(adrs, temp, r);
2044                 adrs += nr;
2045                 for (m = 0; m < r; ++m) {
2046                         if ((m & (sizeof(long) - 1)) == 0 && m > 0)
2047                                 putchar(' ');
2048                         if (m < nr)
2049                                 printf("%.2x", temp[m]);
2050                         else
2051                                 printf("%s", fault_chars[fault_type]);
2052                 }
2053                 for (; m < 16; ++m) {
2054                         if ((m & (sizeof(long) - 1)) == 0)
2055                                 putchar(' ');
2056                         printf("  ");
2057                 }
2058                 printf("  |");
2059                 for (m = 0; m < r; ++m) {
2060                         if (m < nr) {
2061                                 c = temp[m];
2062                                 putchar(' ' <= c && c <= '~'? c: '.');
2063                         } else
2064                                 putchar(' ');
2065                 }
2066                 n -= r;
2067                 for (; m < 16; ++m)
2068                         putchar(' ');
2069                 printf("|\n");
2070                 if (nr < r)
2071                         break;
2072         }
2073 }
2074
2075 typedef int (*instruction_dump_func)(unsigned long inst, unsigned long addr);
2076
2077 int
2078 generic_inst_dump(unsigned long adr, long count, int praddr,
2079                         instruction_dump_func dump_func)
2080 {
2081         int nr, dotted;
2082         unsigned long first_adr;
2083         unsigned long inst, last_inst = 0;
2084         unsigned char val[4];
2085
2086         dotted = 0;
2087         for (first_adr = adr; count > 0; --count, adr += 4) {
2088                 nr = mread(adr, val, 4);
2089                 if (nr == 0) {
2090                         if (praddr) {
2091                                 const char *x = fault_chars[fault_type];
2092                                 printf(REG"  %s%s%s%s\n", adr, x, x, x, x);
2093                         }
2094                         break;
2095                 }
2096                 inst = GETWORD(val);
2097                 if (adr > first_adr && inst == last_inst) {
2098                         if (!dotted) {
2099                                 printf(" ...\n");
2100                                 dotted = 1;
2101                         }
2102                         continue;
2103                 }
2104                 dotted = 0;
2105                 last_inst = inst;
2106                 if (praddr)
2107                         printf(REG"  %.8x", adr, inst);
2108                 printf("\t");
2109                 dump_func(inst, adr);
2110                 printf("\n");
2111         }
2112         return adr - first_adr;
2113 }
2114
2115 int
2116 ppc_inst_dump(unsigned long adr, long count, int praddr)
2117 {
2118         return generic_inst_dump(adr, count, praddr, print_insn_powerpc);
2119 }
2120
2121 void
2122 print_address(unsigned long addr)
2123 {
2124         xmon_print_symbol(addr, "\t# ", "");
2125 }
2126
2127
2128 /*
2129  * Memory operations - move, set, print differences
2130  */
2131 static unsigned long mdest;             /* destination address */
2132 static unsigned long msrc;              /* source address */
2133 static unsigned long mval;              /* byte value to set memory to */
2134 static unsigned long mcount;            /* # bytes to affect */
2135 static unsigned long mdiffs;            /* max # differences to print */
2136
2137 void
2138 memops(int cmd)
2139 {
2140         scanhex((void *)&mdest);
2141         if( termch != '\n' )
2142                 termch = 0;
2143         scanhex((void *)(cmd == 's'? &mval: &msrc));
2144         if( termch != '\n' )
2145                 termch = 0;
2146         scanhex((void *)&mcount);
2147         switch( cmd ){
2148         case 'm':
2149                 memmove((void *)mdest, (void *)msrc, mcount);
2150                 break;
2151         case 's':
2152                 memset((void *)mdest, mval, mcount);
2153                 break;
2154         case 'd':
2155                 if( termch != '\n' )
2156                         termch = 0;
2157                 scanhex((void *)&mdiffs);
2158                 memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
2159                 break;
2160         }
2161 }
2162
2163 void
2164 memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
2165 {
2166         unsigned n, prt;
2167
2168         prt = 0;
2169         for( n = nb; n > 0; --n )
2170                 if( *p1++ != *p2++ )
2171                         if( ++prt <= maxpr )
2172                                 printf("%.16x %.2x # %.16x %.2x\n", p1 - 1,
2173                                         p1[-1], p2 - 1, p2[-1]);
2174         if( prt > maxpr )
2175                 printf("Total of %d differences\n", prt);
2176 }
2177
2178 static unsigned mend;
2179 static unsigned mask;
2180
2181 void
2182 memlocate(void)
2183 {
2184         unsigned a, n;
2185         unsigned char val[4];
2186
2187         last_cmd = "ml";
2188         scanhex((void *)&mdest);
2189         if (termch != '\n') {
2190                 termch = 0;
2191                 scanhex((void *)&mend);
2192                 if (termch != '\n') {
2193                         termch = 0;
2194                         scanhex((void *)&mval);
2195                         mask = ~0;
2196                         if (termch != '\n') termch = 0;
2197                         scanhex((void *)&mask);
2198                 }
2199         }
2200         n = 0;
2201         for (a = mdest; a < mend; a += 4) {
2202                 if (mread(a, val, 4) == 4
2203                         && ((GETWORD(val) ^ mval) & mask) == 0) {
2204                         printf("%.16x:  %.16x\n", a, GETWORD(val));
2205                         if (++n >= 10)
2206                                 break;
2207                 }
2208         }
2209 }
2210
2211 static unsigned long mskip = 0x1000;
2212 static unsigned long mlim = 0xffffffff;
2213
2214 void
2215 memzcan(void)
2216 {
2217         unsigned char v;
2218         unsigned a;
2219         int ok, ook;
2220
2221         scanhex(&mdest);
2222         if (termch != '\n') termch = 0;
2223         scanhex(&mskip);
2224         if (termch != '\n') termch = 0;
2225         scanhex(&mlim);
2226         ook = 0;
2227         for (a = mdest; a < mlim; a += mskip) {
2228                 ok = mread(a, &v, 1);
2229                 if (ok && !ook) {
2230                         printf("%.8x .. ", a);
2231                 } else if (!ok && ook)
2232                         printf("%.8x\n", a - mskip);
2233                 ook = ok;
2234                 if (a + mskip < a)
2235                         break;
2236         }
2237         if (ook)
2238                 printf("%.8x\n", a - mskip);
2239 }
2240
2241 void proccall(void)
2242 {
2243         unsigned long args[8];
2244         unsigned long ret;
2245         int i;
2246         typedef unsigned long (*callfunc_t)(unsigned long, unsigned long,
2247                         unsigned long, unsigned long, unsigned long,
2248                         unsigned long, unsigned long, unsigned long);
2249         callfunc_t func;
2250
2251         if (!scanhex(&adrs))
2252                 return;
2253         if (termch != '\n')
2254                 termch = 0;
2255         for (i = 0; i < 8; ++i)
2256                 args[i] = 0;
2257         for (i = 0; i < 8; ++i) {
2258                 if (!scanhex(&args[i]) || termch == '\n')
2259                         break;
2260                 termch = 0;
2261         }
2262         func = (callfunc_t) adrs;
2263         ret = 0;
2264         if (setjmp(bus_error_jmp) == 0) {
2265                 catch_memory_errors = 1;
2266                 sync();
2267                 ret = func(args[0], args[1], args[2], args[3],
2268                            args[4], args[5], args[6], args[7]);
2269                 sync();
2270                 printf("return value is %x\n", ret);
2271         } else {
2272                 printf("*** %x exception occurred\n", fault_except);
2273         }
2274         catch_memory_errors = 0;
2275 }
2276
2277 /* Input scanning routines */
2278 int
2279 skipbl(void)
2280 {
2281         int c;
2282
2283         if( termch != 0 ){
2284                 c = termch;
2285                 termch = 0;
2286         } else
2287                 c = inchar();
2288         while( c == ' ' || c == '\t' )
2289                 c = inchar();
2290         return c;
2291 }
2292
2293 #define N_PTREGS        44
2294 static char *regnames[N_PTREGS] = {
2295         "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
2296         "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
2297         "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
2298         "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
2299         "pc", "msr", "or3", "ctr", "lr", "xer", "ccr",
2300 #ifdef CONFIG_PPC64
2301         "softe",
2302 #else
2303         "mq",
2304 #endif
2305         "trap", "dar", "dsisr", "res"
2306 };
2307
2308 int
2309 scanhex(unsigned long *vp)
2310 {
2311         int c, d;
2312         unsigned long v;
2313
2314         c = skipbl();
2315         if (c == '%') {
2316                 /* parse register name */
2317                 char regname[8];
2318                 int i;
2319
2320                 for (i = 0; i < sizeof(regname) - 1; ++i) {
2321                         c = inchar();
2322                         if (!isalnum(c)) {
2323                                 termch = c;
2324                                 break;
2325                         }
2326                         regname[i] = c;
2327                 }
2328                 regname[i] = 0;
2329                 for (i = 0; i < N_PTREGS; ++i) {
2330                         if (strcmp(regnames[i], regname) == 0) {
2331                                 if (xmon_regs == NULL) {
2332                                         printf("regs not available\n");
2333                                         return 0;
2334                                 }
2335                                 *vp = ((unsigned long *)xmon_regs)[i];
2336                                 return 1;
2337                         }
2338                 }
2339                 printf("invalid register name '%%%s'\n", regname);
2340                 return 0;
2341         }
2342
2343         /* skip leading "0x" if any */
2344
2345         if (c == '0') {
2346                 c = inchar();
2347                 if (c == 'x') {
2348                         c = inchar();
2349                 } else {
2350                         d = hexdigit(c);
2351                         if (d == EOF) {
2352                                 termch = c;
2353                                 *vp = 0;
2354                                 return 1;
2355                         }
2356                 }
2357         } else if (c == '$') {
2358                 int i;
2359                 for (i=0; i<63; i++) {
2360                         c = inchar();
2361                         if (isspace(c)) {
2362                                 termch = c;
2363                                 break;
2364                         }
2365                         tmpstr[i] = c;
2366                 }
2367                 tmpstr[i++] = 0;
2368                 *vp = 0;
2369                 if (setjmp(bus_error_jmp) == 0) {
2370                         catch_memory_errors = 1;
2371                         sync();
2372                         *vp = kallsyms_lookup_name(tmpstr);
2373                         sync();
2374                 }
2375                 catch_memory_errors = 0;
2376                 if (!(*vp)) {
2377                         printf("unknown symbol '%s'\n", tmpstr);
2378                         return 0;
2379                 }
2380                 return 1;
2381         }
2382
2383         d = hexdigit(c);
2384         if (d == EOF) {
2385                 termch = c;
2386                 return 0;
2387         }
2388         v = 0;
2389         do {
2390                 v = (v << 4) + d;
2391                 c = inchar();
2392                 d = hexdigit(c);
2393         } while (d != EOF);
2394         termch = c;
2395         *vp = v;
2396         return 1;
2397 }
2398
2399 void
2400 scannl(void)
2401 {
2402         int c;
2403
2404         c = termch;
2405         termch = 0;
2406         while( c != '\n' )
2407                 c = inchar();
2408 }
2409
2410 int hexdigit(int c)
2411 {
2412         if( '0' <= c && c <= '9' )
2413                 return c - '0';
2414         if( 'A' <= c && c <= 'F' )
2415                 return c - ('A' - 10);
2416         if( 'a' <= c && c <= 'f' )
2417                 return c - ('a' - 10);
2418         return EOF;
2419 }
2420
2421 void
2422 getstring(char *s, int size)
2423 {
2424         int c;
2425
2426         c = skipbl();
2427         do {
2428                 if( size > 1 ){
2429                         *s++ = c;
2430                         --size;
2431                 }
2432                 c = inchar();
2433         } while( c != ' ' && c != '\t' && c != '\n' );
2434         termch = c;
2435         *s = 0;
2436 }
2437
2438 static char line[256];
2439 static char *lineptr;
2440
2441 void
2442 flush_input(void)
2443 {
2444         lineptr = NULL;
2445 }
2446
2447 int
2448 inchar(void)
2449 {
2450         if (lineptr == NULL || *lineptr == 0) {
2451                 if (xmon_gets(line, sizeof(line)) == NULL) {
2452                         lineptr = NULL;
2453                         return EOF;
2454                 }
2455                 lineptr = line;
2456         }
2457         return *lineptr++;
2458 }
2459
2460 void
2461 take_input(char *str)
2462 {
2463         lineptr = str;
2464 }
2465
2466
2467 static void
2468 symbol_lookup(void)
2469 {
2470         int type = inchar();
2471         unsigned long addr;
2472         static char tmp[64];
2473
2474         switch (type) {
2475         case 'a':
2476                 if (scanhex(&addr))
2477                         xmon_print_symbol(addr, ": ", "\n");
2478                 termch = 0;
2479                 break;
2480         case 's':
2481                 getstring(tmp, 64);
2482                 if (setjmp(bus_error_jmp) == 0) {
2483                         catch_memory_errors = 1;
2484                         sync();
2485                         addr = kallsyms_lookup_name(tmp);
2486                         if (addr)
2487                                 printf("%s: %lx\n", tmp, addr);
2488                         else
2489                                 printf("Symbol '%s' not found.\n", tmp);
2490                         sync();
2491                 }
2492                 catch_memory_errors = 0;
2493                 termch = 0;
2494                 break;
2495         }
2496 }
2497
2498
2499 /* Print an address in numeric and symbolic form (if possible) */
2500 static void xmon_print_symbol(unsigned long address, const char *mid,
2501                               const char *after)
2502 {
2503         char *modname;
2504         const char *name = NULL;
2505         unsigned long offset, size;
2506
2507         printf(REG, address);
2508         if (setjmp(bus_error_jmp) == 0) {
2509                 catch_memory_errors = 1;
2510                 sync();
2511                 name = kallsyms_lookup(address, &size, &offset, &modname,
2512                                        tmpstr);
2513                 sync();
2514                 /* wait a little while to see if we get a machine check */
2515                 __delay(200);
2516         }
2517
2518         catch_memory_errors = 0;
2519
2520         if (name) {
2521                 printf("%s%s+%#lx/%#lx", mid, name, offset, size);
2522                 if (modname)
2523                         printf(" [%s]", modname);
2524         }
2525         printf("%s", after);
2526 }
2527
2528 #ifdef CONFIG_PPC64
2529 static void dump_slb(void)
2530 {
2531         int i;
2532         unsigned long tmp;
2533
2534         printf("SLB contents of cpu %x\n", smp_processor_id());
2535
2536         for (i = 0; i < SLB_NUM_ENTRIES; i++) {
2537                 asm volatile("slbmfee  %0,%1" : "=r" (tmp) : "r" (i));
2538                 printf("%02d %016lx ", i, tmp);
2539
2540                 asm volatile("slbmfev  %0,%1" : "=r" (tmp) : "r" (i));
2541                 printf("%016lx\n", tmp);
2542         }
2543 }
2544
2545 static void dump_stab(void)
2546 {
2547         int i;
2548         unsigned long *tmp = (unsigned long *)get_paca()->stab_addr;
2549
2550         printf("Segment table contents of cpu %x\n", smp_processor_id());
2551
2552         for (i = 0; i < PAGE_SIZE/16; i++) {
2553                 unsigned long a, b;
2554
2555                 a = *tmp++;
2556                 b = *tmp++;
2557
2558                 if (a || b) {
2559                         printf("%03d %016lx ", i, a);
2560                         printf("%016lx\n", b);
2561                 }
2562         }
2563 }
2564
2565 void dump_segments(void)
2566 {
2567         if (cpu_has_feature(CPU_FTR_SLB))
2568                 dump_slb();
2569         else
2570                 dump_stab();
2571 }
2572 #endif
2573
2574 #ifdef CONFIG_PPC_STD_MMU_32
2575 void dump_segments(void)
2576 {
2577         int i;
2578
2579         printf("sr0-15 =");
2580         for (i = 0; i < 16; ++i)
2581                 printf(" %x", mfsrin(i));
2582         printf("\n");
2583 }
2584 #endif
2585
2586 void xmon_init(int enable)
2587 {
2588 #ifdef CONFIG_PPC_ISERIES
2589         if (firmware_has_feature(FW_FEATURE_ISERIES))
2590                 return;
2591 #endif
2592         if (enable) {
2593                 __debugger = xmon;
2594                 __debugger_ipi = xmon_ipi;
2595                 __debugger_bpt = xmon_bpt;
2596                 __debugger_sstep = xmon_sstep;
2597                 __debugger_iabr_match = xmon_iabr_match;
2598                 __debugger_dabr_match = xmon_dabr_match;
2599                 __debugger_fault_handler = xmon_fault_handler;
2600         } else {
2601                 __debugger = NULL;
2602                 __debugger_ipi = NULL;
2603                 __debugger_bpt = NULL;
2604                 __debugger_sstep = NULL;
2605                 __debugger_iabr_match = NULL;
2606                 __debugger_dabr_match = NULL;
2607                 __debugger_fault_handler = NULL;
2608         }
2609         xmon_map_scc();
2610 }
2611
2612 #ifdef CONFIG_MAGIC_SYSRQ
2613 static void sysrq_handle_xmon(int key, struct tty_struct *tty) 
2614 {
2615         /* ensure xmon is enabled */
2616         xmon_init(1);
2617         debugger(get_irq_regs());
2618 }
2619
2620 static struct sysrq_key_op sysrq_xmon_op = 
2621 {
2622         .handler =      sysrq_handle_xmon,
2623         .help_msg =     "Xmon",
2624         .action_msg =   "Entering xmon",
2625 };
2626
2627 static int __init setup_xmon_sysrq(void)
2628 {
2629 #ifdef CONFIG_PPC_ISERIES
2630         if (firmware_has_feature(FW_FEATURE_ISERIES))
2631                 return 0;
2632 #endif
2633         register_sysrq_key('x', &sysrq_xmon_op);
2634         return 0;
2635 }
2636 __initcall(setup_xmon_sysrq);
2637 #endif /* CONFIG_MAGIC_SYSRQ */
2638
2639 int __initdata xmon_early, xmon_off;
2640
2641 static int __init early_parse_xmon(char *p)
2642 {
2643         if (!p || strncmp(p, "early", 5) == 0) {
2644                 /* just "xmon" is equivalent to "xmon=early" */
2645                 xmon_init(1);
2646                 xmon_early = 1;
2647         } else if (strncmp(p, "on", 2) == 0)
2648                 xmon_init(1);
2649         else if (strncmp(p, "off", 3) == 0)
2650                 xmon_off = 1;
2651         else if (strncmp(p, "nobt", 4) == 0)
2652                 xmon_no_auto_backtrace = 1;
2653         else
2654                 return 1;
2655
2656         return 0;
2657 }
2658 early_param("xmon", early_parse_xmon);
2659
2660 void __init xmon_setup(void)
2661 {
2662 #ifdef CONFIG_XMON_DEFAULT
2663         if (!xmon_off)
2664                 xmon_init(1);
2665 #endif
2666         if (xmon_early)
2667                 debugger(NULL);
2668 }
2669
2670 #ifdef CONFIG_SPU_BASE
2671
2672 struct spu_info {
2673         struct spu *spu;
2674         u64 saved_mfc_sr1_RW;
2675         u32 saved_spu_runcntl_RW;
2676         unsigned long dump_addr;
2677         u8 stopped_ok;
2678 };
2679
2680 #define XMON_NUM_SPUS   16      /* Enough for current hardware */
2681
2682 static struct spu_info spu_info[XMON_NUM_SPUS];
2683
2684 void xmon_register_spus(struct list_head *list)
2685 {
2686         struct spu *spu;
2687
2688         list_for_each_entry(spu, list, full_list) {
2689                 if (spu->number >= XMON_NUM_SPUS) {
2690                         WARN_ON(1);
2691                         continue;
2692                 }
2693
2694                 spu_info[spu->number].spu = spu;
2695                 spu_info[spu->number].stopped_ok = 0;
2696                 spu_info[spu->number].dump_addr = (unsigned long)
2697                                 spu_info[spu->number].spu->local_store;
2698         }
2699 }
2700
2701 static void stop_spus(void)
2702 {
2703         struct spu *spu;
2704         int i;
2705         u64 tmp;
2706
2707         for (i = 0; i < XMON_NUM_SPUS; i++) {
2708                 if (!spu_info[i].spu)
2709                         continue;
2710
2711                 if (setjmp(bus_error_jmp) == 0) {
2712                         catch_memory_errors = 1;
2713                         sync();
2714
2715                         spu = spu_info[i].spu;
2716
2717                         spu_info[i].saved_spu_runcntl_RW =
2718                                 in_be32(&spu->problem->spu_runcntl_RW);
2719
2720                         tmp = spu_mfc_sr1_get(spu);
2721                         spu_info[i].saved_mfc_sr1_RW = tmp;
2722
2723                         tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
2724                         spu_mfc_sr1_set(spu, tmp);
2725
2726                         sync();
2727                         __delay(200);
2728
2729                         spu_info[i].stopped_ok = 1;
2730
2731                         printf("Stopped spu %.2d (was %s)\n", i,
2732                                         spu_info[i].saved_spu_runcntl_RW ?
2733                                         "running" : "stopped");
2734                 } else {
2735                         catch_memory_errors = 0;
2736                         printf("*** Error stopping spu %.2d\n", i);
2737                 }
2738                 catch_memory_errors = 0;
2739         }
2740 }
2741
2742 static void restart_spus(void)
2743 {
2744         struct spu *spu;
2745         int i;
2746
2747         for (i = 0; i < XMON_NUM_SPUS; i++) {
2748                 if (!spu_info[i].spu)
2749                         continue;
2750
2751                 if (!spu_info[i].stopped_ok) {
2752                         printf("*** Error, spu %d was not successfully stopped"
2753                                         ", not restarting\n", i);
2754                         continue;
2755                 }
2756
2757                 if (setjmp(bus_error_jmp) == 0) {
2758                         catch_memory_errors = 1;
2759                         sync();
2760
2761                         spu = spu_info[i].spu;
2762                         spu_mfc_sr1_set(spu, spu_info[i].saved_mfc_sr1_RW);
2763                         out_be32(&spu->problem->spu_runcntl_RW,
2764                                         spu_info[i].saved_spu_runcntl_RW);
2765
2766                         sync();
2767                         __delay(200);
2768
2769                         printf("Restarted spu %.2d\n", i);
2770                 } else {
2771                         catch_memory_errors = 0;
2772                         printf("*** Error restarting spu %.2d\n", i);
2773                 }
2774                 catch_memory_errors = 0;
2775         }
2776 }
2777
2778 #define DUMP_WIDTH      23
2779 #define DUMP_VALUE(format, field, value)                                \
2780 do {                                                                    \
2781         if (setjmp(bus_error_jmp) == 0) {                               \
2782                 catch_memory_errors = 1;                                \
2783                 sync();                                                 \
2784                 printf("  %-*s = "format"\n", DUMP_WIDTH,               \
2785                                 #field, value);                         \
2786                 sync();                                                 \
2787                 __delay(200);                                           \
2788         } else {                                                        \
2789                 catch_memory_errors = 0;                                \
2790                 printf("  %-*s = *** Error reading field.\n",           \
2791                                         DUMP_WIDTH, #field);            \
2792         }                                                               \
2793         catch_memory_errors = 0;                                        \
2794 } while (0)
2795
2796 #define DUMP_FIELD(obj, format, field)  \
2797         DUMP_VALUE(format, field, obj->field)
2798
2799 static void dump_spu_fields(struct spu *spu)
2800 {
2801         printf("Dumping spu fields at address %p:\n", spu);
2802
2803         DUMP_FIELD(spu, "0x%x", number);
2804         DUMP_FIELD(spu, "%s", name);
2805         DUMP_FIELD(spu, "0x%lx", local_store_phys);
2806         DUMP_FIELD(spu, "0x%p", local_store);
2807         DUMP_FIELD(spu, "0x%lx", ls_size);
2808         DUMP_FIELD(spu, "0x%x", node);
2809         DUMP_FIELD(spu, "0x%lx", flags);
2810         DUMP_FIELD(spu, "0x%lx", dar);
2811         DUMP_FIELD(spu, "0x%lx", dsisr);
2812         DUMP_FIELD(spu, "%d", class_0_pending);
2813         DUMP_FIELD(spu, "0x%lx", irqs[0]);
2814         DUMP_FIELD(spu, "0x%lx", irqs[1]);
2815         DUMP_FIELD(spu, "0x%lx", irqs[2]);
2816         DUMP_FIELD(spu, "0x%x", slb_replace);
2817         DUMP_FIELD(spu, "%d", pid);
2818         DUMP_FIELD(spu, "0x%p", mm);
2819         DUMP_FIELD(spu, "0x%p", ctx);
2820         DUMP_FIELD(spu, "0x%p", rq);
2821         DUMP_FIELD(spu, "0x%p", timestamp);
2822         DUMP_FIELD(spu, "0x%lx", problem_phys);
2823         DUMP_FIELD(spu, "0x%p", problem);
2824         DUMP_VALUE("0x%x", problem->spu_runcntl_RW,
2825                         in_be32(&spu->problem->spu_runcntl_RW));
2826         DUMP_VALUE("0x%x", problem->spu_status_R,
2827                         in_be32(&spu->problem->spu_status_R));
2828         DUMP_VALUE("0x%x", problem->spu_npc_RW,
2829                         in_be32(&spu->problem->spu_npc_RW));
2830         DUMP_FIELD(spu, "0x%p", priv2);
2831         DUMP_FIELD(spu, "0x%p", pdata);
2832 }
2833
2834 int
2835 spu_inst_dump(unsigned long adr, long count, int praddr)
2836 {
2837         return generic_inst_dump(adr, count, praddr, print_insn_spu);
2838 }
2839
2840 static void dump_spu_ls(unsigned long num, int subcmd)
2841 {
2842         unsigned long offset, addr, ls_addr;
2843
2844         if (setjmp(bus_error_jmp) == 0) {
2845                 catch_memory_errors = 1;
2846                 sync();
2847                 ls_addr = (unsigned long)spu_info[num].spu->local_store;
2848                 sync();
2849                 __delay(200);
2850         } else {
2851                 catch_memory_errors = 0;
2852                 printf("*** Error: accessing spu info for spu %d\n", num);
2853                 return;
2854         }
2855         catch_memory_errors = 0;
2856
2857         if (scanhex(&offset))
2858                 addr = ls_addr + offset;
2859         else
2860                 addr = spu_info[num].dump_addr;
2861
2862         if (addr >= ls_addr + LS_SIZE) {
2863                 printf("*** Error: address outside of local store\n");
2864                 return;
2865         }
2866
2867         switch (subcmd) {
2868         case 'i':
2869                 addr += spu_inst_dump(addr, 16, 1);
2870                 last_cmd = "sdi\n";
2871                 break;
2872         default:
2873                 prdump(addr, 64);
2874                 addr += 64;
2875                 last_cmd = "sd\n";
2876                 break;
2877         }
2878
2879         spu_info[num].dump_addr = addr;
2880 }
2881
2882 static int do_spu_cmd(void)
2883 {
2884         static unsigned long num = 0;
2885         int cmd, subcmd = 0;
2886
2887         cmd = inchar();
2888         switch (cmd) {
2889         case 's':
2890                 stop_spus();
2891                 break;
2892         case 'r':
2893                 restart_spus();
2894                 break;
2895         case 'd':
2896                 subcmd = inchar();
2897                 if (isxdigit(subcmd) || subcmd == '\n')
2898                         termch = subcmd;
2899         case 'f':
2900                 scanhex(&num);
2901                 if (num >= XMON_NUM_SPUS || !spu_info[num].spu) {
2902                         printf("*** Error: invalid spu number\n");
2903                         return 0;
2904                 }
2905
2906                 switch (cmd) {
2907                 case 'f':
2908                         dump_spu_fields(spu_info[num].spu);
2909                         break;
2910                 default:
2911                         dump_spu_ls(num, subcmd);
2912                         break;
2913                 }
2914
2915                 break;
2916         default:
2917                 return -1;
2918         }
2919
2920         return 0;
2921 }
2922 #else /* ! CONFIG_SPU_BASE */
2923 static int do_spu_cmd(void)
2924 {
2925         return -1;
2926 }
2927 #endif