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