Merge branch 'devel' of master.kernel.org:/home/rmk/linux-2.6-arm
[sfrench/cifs-2.6.git] / 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                         xmon_puts(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
1221         *startp = *endp = 0;
1222         if (pc == 0)
1223                 return;
1224         if (setjmp(bus_error_jmp) == 0) {
1225                 catch_memory_errors = 1;
1226                 sync();
1227                 name = kallsyms_lookup(pc, &size, &offset, NULL, tmpstr);
1228                 if (name != NULL) {
1229                         *startp = pc - offset;
1230                         *endp = pc - offset + size;
1231                 }
1232                 sync();
1233         }
1234         catch_memory_errors = 0;
1235 }
1236
1237 static int xmon_depth_to_print = 64;
1238
1239 #ifdef CONFIG_PPC64
1240 #define LRSAVE_OFFSET           0x10
1241 #define REG_FRAME_MARKER        0x7265677368657265ul    /* "regshere" */
1242 #define MARKER_OFFSET           0x60
1243 #define REGS_OFFSET             0x70
1244 #else
1245 #define LRSAVE_OFFSET           4
1246 #define REG_FRAME_MARKER        0x72656773
1247 #define MARKER_OFFSET           8
1248 #define REGS_OFFSET             16
1249 #endif
1250
1251 static void xmon_show_stack(unsigned long sp, unsigned long lr,
1252                             unsigned long pc)
1253 {
1254         unsigned long ip;
1255         unsigned long newsp;
1256         unsigned long marker;
1257         int count = 0;
1258         struct pt_regs regs;
1259
1260         do {
1261                 if (sp < PAGE_OFFSET) {
1262                         if (sp != 0)
1263                                 printf("SP (%lx) is in userspace\n", sp);
1264                         break;
1265                 }
1266
1267                 if (!mread(sp + LRSAVE_OFFSET, &ip, sizeof(unsigned long))
1268                     || !mread(sp, &newsp, sizeof(unsigned long))) {
1269                         printf("Couldn't read stack frame at %lx\n", sp);
1270                         break;
1271                 }
1272
1273                 /*
1274                  * For the first stack frame, try to work out if
1275                  * LR and/or the saved LR value in the bottommost
1276                  * stack frame are valid.
1277                  */
1278                 if ((pc | lr) != 0) {
1279                         unsigned long fnstart, fnend;
1280                         unsigned long nextip;
1281                         int printip = 1;
1282
1283                         get_function_bounds(pc, &fnstart, &fnend);
1284                         nextip = 0;
1285                         if (newsp > sp)
1286                                 mread(newsp + LRSAVE_OFFSET, &nextip,
1287                                       sizeof(unsigned long));
1288                         if (lr == ip) {
1289                                 if (lr < PAGE_OFFSET
1290                                     || (fnstart <= lr && lr < fnend))
1291                                         printip = 0;
1292                         } else if (lr == nextip) {
1293                                 printip = 0;
1294                         } else if (lr >= PAGE_OFFSET
1295                                    && !(fnstart <= lr && lr < fnend)) {
1296                                 printf("[link register   ] ");
1297                                 xmon_print_symbol(lr, " ", "\n");
1298                         }
1299                         if (printip) {
1300                                 printf("["REG"] ", sp);
1301                                 xmon_print_symbol(ip, " ", " (unreliable)\n");
1302                         }
1303                         pc = lr = 0;
1304
1305                 } else {
1306                         printf("["REG"] ", sp);
1307                         xmon_print_symbol(ip, " ", "\n");
1308                 }
1309
1310                 /* Look for "regshere" marker to see if this is
1311                    an exception frame. */
1312                 if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long))
1313                     && marker == REG_FRAME_MARKER) {
1314                         if (mread(sp + REGS_OFFSET, &regs, sizeof(regs))
1315                             != sizeof(regs)) {
1316                                 printf("Couldn't read registers at %lx\n",
1317                                        sp + REGS_OFFSET);
1318                                 break;
1319                         }
1320                         printf("--- Exception: %lx %s at ", regs.trap,
1321                                getvecname(TRAP(&regs)));
1322                         pc = regs.nip;
1323                         lr = regs.link;
1324                         xmon_print_symbol(pc, " ", "\n");
1325                 }
1326
1327                 if (newsp == 0)
1328                         break;
1329
1330                 sp = newsp;
1331         } while (count++ < xmon_depth_to_print);
1332 }
1333
1334 static void backtrace(struct pt_regs *excp)
1335 {
1336         unsigned long sp;
1337
1338         if (scanhex(&sp))
1339                 xmon_show_stack(sp, 0, 0);
1340         else
1341                 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
1342         scannl();
1343 }
1344
1345 static void print_bug_trap(struct pt_regs *regs)
1346 {
1347         const struct bug_entry *bug;
1348         unsigned long addr;
1349
1350         if (regs->msr & MSR_PR)
1351                 return;         /* not in kernel */
1352         addr = regs->nip;       /* address of trap instruction */
1353         if (addr < PAGE_OFFSET)
1354                 return;
1355         bug = find_bug(regs->nip);
1356         if (bug == NULL)
1357                 return;
1358         if (is_warning_bug(bug))
1359                 return;
1360
1361 #ifdef CONFIG_DEBUG_BUGVERBOSE
1362         printf("kernel BUG at %s:%u!\n",
1363                bug->file, bug->line);
1364 #else
1365         printf("kernel BUG at %p!\n", (void *)bug->bug_addr);
1366 #endif
1367 }
1368
1369 void excprint(struct pt_regs *fp)
1370 {
1371         unsigned long trap;
1372
1373 #ifdef CONFIG_SMP
1374         printf("cpu 0x%x: ", smp_processor_id());
1375 #endif /* CONFIG_SMP */
1376
1377         trap = TRAP(fp);
1378         printf("Vector: %lx %s at [%lx]\n", fp->trap, getvecname(trap), fp);
1379         printf("    pc: ");
1380         xmon_print_symbol(fp->nip, ": ", "\n");
1381
1382         printf("    lr: ", fp->link);
1383         xmon_print_symbol(fp->link, ": ", "\n");
1384
1385         printf("    sp: %lx\n", fp->gpr[1]);
1386         printf("   msr: %lx\n", fp->msr);
1387
1388         if (trap == 0x300 || trap == 0x380 || trap == 0x600) {
1389                 printf("   dar: %lx\n", fp->dar);
1390                 if (trap != 0x380)
1391                         printf(" dsisr: %lx\n", fp->dsisr);
1392         }
1393
1394         printf("  current = 0x%lx\n", current);
1395 #ifdef CONFIG_PPC64
1396         printf("  paca    = 0x%lx\n", get_paca());
1397 #endif
1398         if (current) {
1399                 printf("    pid   = %ld, comm = %s\n",
1400                        current->pid, current->comm);
1401         }
1402
1403         if (trap == 0x700)
1404                 print_bug_trap(fp);
1405 }
1406
1407 void prregs(struct pt_regs *fp)
1408 {
1409         int n, trap;
1410         unsigned long base;
1411         struct pt_regs regs;
1412
1413         if (scanhex(&base)) {
1414                 if (setjmp(bus_error_jmp) == 0) {
1415                         catch_memory_errors = 1;
1416                         sync();
1417                         regs = *(struct pt_regs *)base;
1418                         sync();
1419                         __delay(200);
1420                 } else {
1421                         catch_memory_errors = 0;
1422                         printf("*** Error reading registers from "REG"\n",
1423                                base);
1424                         return;
1425                 }
1426                 catch_memory_errors = 0;
1427                 fp = &regs;
1428         }
1429
1430 #ifdef CONFIG_PPC64
1431         if (FULL_REGS(fp)) {
1432                 for (n = 0; n < 16; ++n)
1433                         printf("R%.2ld = "REG"   R%.2ld = "REG"\n",
1434                                n, fp->gpr[n], n+16, fp->gpr[n+16]);
1435         } else {
1436                 for (n = 0; n < 7; ++n)
1437                         printf("R%.2ld = "REG"   R%.2ld = "REG"\n",
1438                                n, fp->gpr[n], n+7, fp->gpr[n+7]);
1439         }
1440 #else
1441         for (n = 0; n < 32; ++n) {
1442                 printf("R%.2d = %.8x%s", n, fp->gpr[n],
1443                        (n & 3) == 3? "\n": "   ");
1444                 if (n == 12 && !FULL_REGS(fp)) {
1445                         printf("\n");
1446                         break;
1447                 }
1448         }
1449 #endif
1450         printf("pc  = ");
1451         xmon_print_symbol(fp->nip, " ", "\n");
1452         printf("lr  = ");
1453         xmon_print_symbol(fp->link, " ", "\n");
1454         printf("msr = "REG"   cr  = %.8lx\n", fp->msr, fp->ccr);
1455         printf("ctr = "REG"   xer = "REG"   trap = %4lx\n",
1456                fp->ctr, fp->xer, fp->trap);
1457         trap = TRAP(fp);
1458         if (trap == 0x300 || trap == 0x380 || trap == 0x600)
1459                 printf("dar = "REG"   dsisr = %.8lx\n", fp->dar, fp->dsisr);
1460 }
1461
1462 void cacheflush(void)
1463 {
1464         int cmd;
1465         unsigned long nflush;
1466
1467         cmd = inchar();
1468         if (cmd != 'i')
1469                 termch = cmd;
1470         scanhex((void *)&adrs);
1471         if (termch != '\n')
1472                 termch = 0;
1473         nflush = 1;
1474         scanhex(&nflush);
1475         nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES;
1476         if (setjmp(bus_error_jmp) == 0) {
1477                 catch_memory_errors = 1;
1478                 sync();
1479
1480                 if (cmd != 'i') {
1481                         for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1482                                 cflush((void *) adrs);
1483                 } else {
1484                         for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1485                                 cinval((void *) adrs);
1486                 }
1487                 sync();
1488                 /* wait a little while to see if we get a machine check */
1489                 __delay(200);
1490         }
1491         catch_memory_errors = 0;
1492 }
1493
1494 unsigned long
1495 read_spr(int n)
1496 {
1497         unsigned int instrs[2];
1498         unsigned long (*code)(void);
1499         unsigned long ret = -1UL;
1500 #ifdef CONFIG_PPC64
1501         unsigned long opd[3];
1502
1503         opd[0] = (unsigned long)instrs;
1504         opd[1] = 0;
1505         opd[2] = 0;
1506         code = (unsigned long (*)(void)) opd;
1507 #else
1508         code = (unsigned long (*)(void)) instrs;
1509 #endif
1510
1511         /* mfspr r3,n; blr */
1512         instrs[0] = 0x7c6002a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1513         instrs[1] = 0x4e800020;
1514         store_inst(instrs);
1515         store_inst(instrs+1);
1516
1517         if (setjmp(bus_error_jmp) == 0) {
1518                 catch_memory_errors = 1;
1519                 sync();
1520
1521                 ret = code();
1522
1523                 sync();
1524                 /* wait a little while to see if we get a machine check */
1525                 __delay(200);
1526                 n = size;
1527         }
1528
1529         return ret;
1530 }
1531
1532 void
1533 write_spr(int n, unsigned long val)
1534 {
1535         unsigned int instrs[2];
1536         unsigned long (*code)(unsigned long);
1537 #ifdef CONFIG_PPC64
1538         unsigned long opd[3];
1539
1540         opd[0] = (unsigned long)instrs;
1541         opd[1] = 0;
1542         opd[2] = 0;
1543         code = (unsigned long (*)(unsigned long)) opd;
1544 #else
1545         code = (unsigned long (*)(unsigned long)) instrs;
1546 #endif
1547
1548         instrs[0] = 0x7c6003a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1549         instrs[1] = 0x4e800020;
1550         store_inst(instrs);
1551         store_inst(instrs+1);
1552
1553         if (setjmp(bus_error_jmp) == 0) {
1554                 catch_memory_errors = 1;
1555                 sync();
1556
1557                 code(val);
1558
1559                 sync();
1560                 /* wait a little while to see if we get a machine check */
1561                 __delay(200);
1562                 n = size;
1563         }
1564 }
1565
1566 static unsigned long regno;
1567 extern char exc_prolog;
1568 extern char dec_exc;
1569
1570 void super_regs(void)
1571 {
1572         int cmd;
1573         unsigned long val;
1574
1575         cmd = skipbl();
1576         if (cmd == '\n') {
1577                 unsigned long sp, toc;
1578                 asm("mr %0,1" : "=r" (sp) :);
1579                 asm("mr %0,2" : "=r" (toc) :);
1580
1581                 printf("msr  = "REG"  sprg0= "REG"\n",
1582                        mfmsr(), mfspr(SPRN_SPRG0));
1583                 printf("pvr  = "REG"  sprg1= "REG"\n",
1584                        mfspr(SPRN_PVR), mfspr(SPRN_SPRG1)); 
1585                 printf("dec  = "REG"  sprg2= "REG"\n",
1586                        mfspr(SPRN_DEC), mfspr(SPRN_SPRG2));
1587                 printf("sp   = "REG"  sprg3= "REG"\n", sp, mfspr(SPRN_SPRG3));
1588                 printf("toc  = "REG"  dar  = "REG"\n", toc, mfspr(SPRN_DAR));
1589 #ifdef CONFIG_PPC_ISERIES
1590                 if (firmware_has_feature(FW_FEATURE_ISERIES)) {
1591                         struct paca_struct *ptrPaca;
1592                         struct lppaca *ptrLpPaca;
1593                         struct ItLpRegSave *ptrLpRegSave;
1594
1595                         /* Dump out relevant Paca data areas. */
1596                         printf("Paca: \n");
1597                         ptrPaca = get_paca();
1598
1599                         printf("  Local Processor Control Area (LpPaca): \n");
1600                         ptrLpPaca = ptrPaca->lppaca_ptr;
1601                         printf("    Saved Srr0=%.16lx  Saved Srr1=%.16lx \n",
1602                                ptrLpPaca->saved_srr0, ptrLpPaca->saved_srr1);
1603                         printf("    Saved Gpr3=%.16lx  Saved Gpr4=%.16lx \n",
1604                                ptrLpPaca->saved_gpr3, ptrLpPaca->saved_gpr4);
1605                         printf("    Saved Gpr5=%.16lx \n", ptrLpPaca->saved_gpr5);
1606
1607                         printf("  Local Processor Register Save Area (LpRegSave): \n");
1608                         ptrLpRegSave = ptrPaca->reg_save_ptr;
1609                         printf("    Saved Sprg0=%.16lx  Saved Sprg1=%.16lx \n",
1610                                ptrLpRegSave->xSPRG0, ptrLpRegSave->xSPRG0);
1611                         printf("    Saved Sprg2=%.16lx  Saved Sprg3=%.16lx \n",
1612                                ptrLpRegSave->xSPRG2, ptrLpRegSave->xSPRG3);
1613                         printf("    Saved Msr  =%.16lx  Saved Nia  =%.16lx \n",
1614                                ptrLpRegSave->xMSR, ptrLpRegSave->xNIA);
1615                 }
1616 #endif
1617
1618                 return;
1619         }
1620
1621         scanhex(&regno);
1622         switch (cmd) {
1623         case 'w':
1624                 val = read_spr(regno);
1625                 scanhex(&val);
1626                 write_spr(regno, val);
1627                 /* fall through */
1628         case 'r':
1629                 printf("spr %lx = %lx\n", regno, read_spr(regno));
1630                 break;
1631         }
1632         scannl();
1633 }
1634
1635 /*
1636  * Stuff for reading and writing memory safely
1637  */
1638 int
1639 mread(unsigned long adrs, void *buf, int size)
1640 {
1641         volatile int n;
1642         char *p, *q;
1643
1644         n = 0;
1645         if (setjmp(bus_error_jmp) == 0) {
1646                 catch_memory_errors = 1;
1647                 sync();
1648                 p = (char *)adrs;
1649                 q = (char *)buf;
1650                 switch (size) {
1651                 case 2:
1652                         *(u16 *)q = *(u16 *)p;
1653                         break;
1654                 case 4:
1655                         *(u32 *)q = *(u32 *)p;
1656                         break;
1657                 case 8:
1658                         *(u64 *)q = *(u64 *)p;
1659                         break;
1660                 default:
1661                         for( ; n < size; ++n) {
1662                                 *q++ = *p++;
1663                                 sync();
1664                         }
1665                 }
1666                 sync();
1667                 /* wait a little while to see if we get a machine check */
1668                 __delay(200);
1669                 n = size;
1670         }
1671         catch_memory_errors = 0;
1672         return n;
1673 }
1674
1675 int
1676 mwrite(unsigned long adrs, void *buf, int size)
1677 {
1678         volatile int n;
1679         char *p, *q;
1680
1681         n = 0;
1682         if (setjmp(bus_error_jmp) == 0) {
1683                 catch_memory_errors = 1;
1684                 sync();
1685                 p = (char *) adrs;
1686                 q = (char *) buf;
1687                 switch (size) {
1688                 case 2:
1689                         *(u16 *)p = *(u16 *)q;
1690                         break;
1691                 case 4:
1692                         *(u32 *)p = *(u32 *)q;
1693                         break;
1694                 case 8:
1695                         *(u64 *)p = *(u64 *)q;
1696                         break;
1697                 default:
1698                         for ( ; n < size; ++n) {
1699                                 *p++ = *q++;
1700                                 sync();
1701                         }
1702                 }
1703                 sync();
1704                 /* wait a little while to see if we get a machine check */
1705                 __delay(200);
1706                 n = size;
1707         } else {
1708                 printf("*** Error writing address %x\n", adrs + n);
1709         }
1710         catch_memory_errors = 0;
1711         return n;
1712 }
1713
1714 static int fault_type;
1715 static int fault_except;
1716 static char *fault_chars[] = { "--", "**", "##" };
1717
1718 static int handle_fault(struct pt_regs *regs)
1719 {
1720         fault_except = TRAP(regs);
1721         switch (TRAP(regs)) {
1722         case 0x200:
1723                 fault_type = 0;
1724                 break;
1725         case 0x300:
1726         case 0x380:
1727                 fault_type = 1;
1728                 break;
1729         default:
1730                 fault_type = 2;
1731         }
1732
1733         longjmp(bus_error_jmp, 1);
1734
1735         return 0;
1736 }
1737
1738 #define SWAP(a, b, t)   ((t) = (a), (a) = (b), (b) = (t))
1739
1740 void
1741 byterev(unsigned char *val, int size)
1742 {
1743         int t;
1744         
1745         switch (size) {
1746         case 2:
1747                 SWAP(val[0], val[1], t);
1748                 break;
1749         case 4:
1750                 SWAP(val[0], val[3], t);
1751                 SWAP(val[1], val[2], t);
1752                 break;
1753         case 8: /* is there really any use for this? */
1754                 SWAP(val[0], val[7], t);
1755                 SWAP(val[1], val[6], t);
1756                 SWAP(val[2], val[5], t);
1757                 SWAP(val[3], val[4], t);
1758                 break;
1759         }
1760 }
1761
1762 static int brev;
1763 static int mnoread;
1764
1765 static char *memex_help_string = 
1766     "Memory examine command usage:\n"
1767     "m [addr] [flags] examine/change memory\n"
1768     "  addr is optional.  will start where left off.\n"
1769     "  flags may include chars from this set:\n"
1770     "    b   modify by bytes (default)\n"
1771     "    w   modify by words (2 byte)\n"
1772     "    l   modify by longs (4 byte)\n"
1773     "    d   modify by doubleword (8 byte)\n"
1774     "    r   toggle reverse byte order mode\n"
1775     "    n   do not read memory (for i/o spaces)\n"
1776     "    .   ok to read (default)\n"
1777     "NOTE: flags are saved as defaults\n"
1778     "";
1779
1780 static char *memex_subcmd_help_string = 
1781     "Memory examine subcommands:\n"
1782     "  hexval   write this val to current location\n"
1783     "  'string' write chars from string to this location\n"
1784     "  '        increment address\n"
1785     "  ^        decrement address\n"
1786     "  /        increment addr by 0x10.  //=0x100, ///=0x1000, etc\n"
1787     "  \\        decrement addr by 0x10.  \\\\=0x100, \\\\\\=0x1000, etc\n"
1788     "  `        clear no-read flag\n"
1789     "  ;        stay at this addr\n"
1790     "  v        change to byte mode\n"
1791     "  w        change to word (2 byte) mode\n"
1792     "  l        change to long (4 byte) mode\n"
1793     "  u        change to doubleword (8 byte) mode\n"
1794     "  m addr   change current addr\n"
1795     "  n        toggle no-read flag\n"
1796     "  r        toggle byte reverse flag\n"
1797     "  < count  back up count bytes\n"
1798     "  > count  skip forward count bytes\n"
1799     "  x        exit this mode\n"
1800     "";
1801
1802 void
1803 memex(void)
1804 {
1805         int cmd, inc, i, nslash;
1806         unsigned long n;
1807         unsigned char val[16];
1808
1809         scanhex((void *)&adrs);
1810         cmd = skipbl();
1811         if (cmd == '?') {
1812                 printf(memex_help_string);
1813                 return;
1814         } else {
1815                 termch = cmd;
1816         }
1817         last_cmd = "m\n";
1818         while ((cmd = skipbl()) != '\n') {
1819                 switch( cmd ){
1820                 case 'b':       size = 1;       break;
1821                 case 'w':       size = 2;       break;
1822                 case 'l':       size = 4;       break;
1823                 case 'd':       size = 8;       break;
1824                 case 'r':       brev = !brev;   break;
1825                 case 'n':       mnoread = 1;    break;
1826                 case '.':       mnoread = 0;    break;
1827                 }
1828         }
1829         if( size <= 0 )
1830                 size = 1;
1831         else if( size > 8 )
1832                 size = 8;
1833         for(;;){
1834                 if (!mnoread)
1835                         n = mread(adrs, val, size);
1836                 printf(REG"%c", adrs, brev? 'r': ' ');
1837                 if (!mnoread) {
1838                         if (brev)
1839                                 byterev(val, size);
1840                         putchar(' ');
1841                         for (i = 0; i < n; ++i)
1842                                 printf("%.2x", val[i]);
1843                         for (; i < size; ++i)
1844                                 printf("%s", fault_chars[fault_type]);
1845                 }
1846                 putchar(' ');
1847                 inc = size;
1848                 nslash = 0;
1849                 for(;;){
1850                         if( scanhex(&n) ){
1851                                 for (i = 0; i < size; ++i)
1852                                         val[i] = n >> (i * 8);
1853                                 if (!brev)
1854                                         byterev(val, size);
1855                                 mwrite(adrs, val, size);
1856                                 inc = size;
1857                         }
1858                         cmd = skipbl();
1859                         if (cmd == '\n')
1860                                 break;
1861                         inc = 0;
1862                         switch (cmd) {
1863                         case '\'':
1864                                 for(;;){
1865                                         n = inchar();
1866                                         if( n == '\\' )
1867                                                 n = bsesc();
1868                                         else if( n == '\'' )
1869                                                 break;
1870                                         for (i = 0; i < size; ++i)
1871                                                 val[i] = n >> (i * 8);
1872                                         if (!brev)
1873                                                 byterev(val, size);
1874                                         mwrite(adrs, val, size);
1875                                         adrs += size;
1876                                 }
1877                                 adrs -= size;
1878                                 inc = size;
1879                                 break;
1880                         case ',':
1881                                 adrs += size;
1882                                 break;
1883                         case '.':
1884                                 mnoread = 0;
1885                                 break;
1886                         case ';':
1887                                 break;
1888                         case 'x':
1889                         case EOF:
1890                                 scannl();
1891                                 return;
1892                         case 'b':
1893                         case 'v':
1894                                 size = 1;
1895                                 break;
1896                         case 'w':
1897                                 size = 2;
1898                                 break;
1899                         case 'l':
1900                                 size = 4;
1901                                 break;
1902                         case 'u':
1903                                 size = 8;
1904                                 break;
1905                         case '^':
1906                                 adrs -= size;
1907                                 break;
1908                                 break;
1909                         case '/':
1910                                 if (nslash > 0)
1911                                         adrs -= 1 << nslash;
1912                                 else
1913                                         nslash = 0;
1914                                 nslash += 4;
1915                                 adrs += 1 << nslash;
1916                                 break;
1917                         case '\\':
1918                                 if (nslash < 0)
1919                                         adrs += 1 << -nslash;
1920                                 else
1921                                         nslash = 0;
1922                                 nslash -= 4;
1923                                 adrs -= 1 << -nslash;
1924                                 break;
1925                         case 'm':
1926                                 scanhex((void *)&adrs);
1927                                 break;
1928                         case 'n':
1929                                 mnoread = 1;
1930                                 break;
1931                         case 'r':
1932                                 brev = !brev;
1933                                 break;
1934                         case '<':
1935                                 n = size;
1936                                 scanhex(&n);
1937                                 adrs -= n;
1938                                 break;
1939                         case '>':
1940                                 n = size;
1941                                 scanhex(&n);
1942                                 adrs += n;
1943                                 break;
1944                         case '?':
1945                                 printf(memex_subcmd_help_string);
1946                                 break;
1947                         }
1948                 }
1949                 adrs += inc;
1950         }
1951 }
1952
1953 int
1954 bsesc(void)
1955 {
1956         int c;
1957
1958         c = inchar();
1959         switch( c ){
1960         case 'n':       c = '\n';       break;
1961         case 'r':       c = '\r';       break;
1962         case 'b':       c = '\b';       break;
1963         case 't':       c = '\t';       break;
1964         }
1965         return c;
1966 }
1967
1968 static void xmon_rawdump (unsigned long adrs, long ndump)
1969 {
1970         long n, m, r, nr;
1971         unsigned char temp[16];
1972
1973         for (n = ndump; n > 0;) {
1974                 r = n < 16? n: 16;
1975                 nr = mread(adrs, temp, r);
1976                 adrs += nr;
1977                 for (m = 0; m < r; ++m) {
1978                         if (m < nr)
1979                                 printf("%.2x", temp[m]);
1980                         else
1981                                 printf("%s", fault_chars[fault_type]);
1982                 }
1983                 n -= r;
1984                 if (nr < r)
1985                         break;
1986         }
1987         printf("\n");
1988 }
1989
1990 #define isxdigit(c)     (('0' <= (c) && (c) <= '9') \
1991                          || ('a' <= (c) && (c) <= 'f') \
1992                          || ('A' <= (c) && (c) <= 'F'))
1993 void
1994 dump(void)
1995 {
1996         int c;
1997
1998         c = inchar();
1999         if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
2000                 termch = c;
2001         scanhex((void *)&adrs);
2002         if (termch != '\n')
2003                 termch = 0;
2004         if (c == 'i') {
2005                 scanhex(&nidump);
2006                 if (nidump == 0)
2007                         nidump = 16;
2008                 else if (nidump > MAX_DUMP)
2009                         nidump = MAX_DUMP;
2010                 adrs += ppc_inst_dump(adrs, nidump, 1);
2011                 last_cmd = "di\n";
2012         } else if (c == 'r') {
2013                 scanhex(&ndump);
2014                 if (ndump == 0)
2015                         ndump = 64;
2016                 xmon_rawdump(adrs, ndump);
2017                 adrs += ndump;
2018                 last_cmd = "dr\n";
2019         } else {
2020                 scanhex(&ndump);
2021                 if (ndump == 0)
2022                         ndump = 64;
2023                 else if (ndump > MAX_DUMP)
2024                         ndump = MAX_DUMP;
2025                 prdump(adrs, ndump);
2026                 adrs += ndump;
2027                 last_cmd = "d\n";
2028         }
2029 }
2030
2031 void
2032 prdump(unsigned long adrs, long ndump)
2033 {
2034         long n, m, c, r, nr;
2035         unsigned char temp[16];
2036
2037         for (n = ndump; n > 0;) {
2038                 printf(REG, adrs);
2039                 putchar(' ');
2040                 r = n < 16? n: 16;
2041                 nr = mread(adrs, temp, r);
2042                 adrs += nr;
2043                 for (m = 0; m < r; ++m) {
2044                         if ((m & (sizeof(long) - 1)) == 0 && m > 0)
2045                                 putchar(' ');
2046                         if (m < nr)
2047                                 printf("%.2x", temp[m]);
2048                         else
2049                                 printf("%s", fault_chars[fault_type]);
2050                 }
2051                 for (; m < 16; ++m) {
2052                         if ((m & (sizeof(long) - 1)) == 0)
2053                                 putchar(' ');
2054                         printf("  ");
2055                 }
2056                 printf("  |");
2057                 for (m = 0; m < r; ++m) {
2058                         if (m < nr) {
2059                                 c = temp[m];
2060                                 putchar(' ' <= c && c <= '~'? c: '.');
2061                         } else
2062                                 putchar(' ');
2063                 }
2064                 n -= r;
2065                 for (; m < 16; ++m)
2066                         putchar(' ');
2067                 printf("|\n");
2068                 if (nr < r)
2069                         break;
2070         }
2071 }
2072
2073 typedef int (*instruction_dump_func)(unsigned long inst, unsigned long addr);
2074
2075 int
2076 generic_inst_dump(unsigned long adr, long count, int praddr,
2077                         instruction_dump_func dump_func)
2078 {
2079         int nr, dotted;
2080         unsigned long first_adr;
2081         unsigned long inst, last_inst = 0;
2082         unsigned char val[4];
2083
2084         dotted = 0;
2085         for (first_adr = adr; count > 0; --count, adr += 4) {
2086                 nr = mread(adr, val, 4);
2087                 if (nr == 0) {
2088                         if (praddr) {
2089                                 const char *x = fault_chars[fault_type];
2090                                 printf(REG"  %s%s%s%s\n", adr, x, x, x, x);
2091                         }
2092                         break;
2093                 }
2094                 inst = GETWORD(val);
2095                 if (adr > first_adr && inst == last_inst) {
2096                         if (!dotted) {
2097                                 printf(" ...\n");
2098                                 dotted = 1;
2099                         }
2100                         continue;
2101                 }
2102                 dotted = 0;
2103                 last_inst = inst;
2104                 if (praddr)
2105                         printf(REG"  %.8x", adr, inst);
2106                 printf("\t");
2107                 dump_func(inst, adr);
2108                 printf("\n");
2109         }
2110         return adr - first_adr;
2111 }
2112
2113 int
2114 ppc_inst_dump(unsigned long adr, long count, int praddr)
2115 {
2116         return generic_inst_dump(adr, count, praddr, print_insn_powerpc);
2117 }
2118
2119 void
2120 print_address(unsigned long addr)
2121 {
2122         xmon_print_symbol(addr, "\t# ", "");
2123 }
2124
2125
2126 /*
2127  * Memory operations - move, set, print differences
2128  */
2129 static unsigned long mdest;             /* destination address */
2130 static unsigned long msrc;              /* source address */
2131 static unsigned long mval;              /* byte value to set memory to */
2132 static unsigned long mcount;            /* # bytes to affect */
2133 static unsigned long mdiffs;            /* max # differences to print */
2134
2135 void
2136 memops(int cmd)
2137 {
2138         scanhex((void *)&mdest);
2139         if( termch != '\n' )
2140                 termch = 0;
2141         scanhex((void *)(cmd == 's'? &mval: &msrc));
2142         if( termch != '\n' )
2143                 termch = 0;
2144         scanhex((void *)&mcount);
2145         switch( cmd ){
2146         case 'm':
2147                 memmove((void *)mdest, (void *)msrc, mcount);
2148                 break;
2149         case 's':
2150                 memset((void *)mdest, mval, mcount);
2151                 break;
2152         case 'd':
2153                 if( termch != '\n' )
2154                         termch = 0;
2155                 scanhex((void *)&mdiffs);
2156                 memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
2157                 break;
2158         }
2159 }
2160
2161 void
2162 memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
2163 {
2164         unsigned n, prt;
2165
2166         prt = 0;
2167         for( n = nb; n > 0; --n )
2168                 if( *p1++ != *p2++ )
2169                         if( ++prt <= maxpr )
2170                                 printf("%.16x %.2x # %.16x %.2x\n", p1 - 1,
2171                                         p1[-1], p2 - 1, p2[-1]);
2172         if( prt > maxpr )
2173                 printf("Total of %d differences\n", prt);
2174 }
2175
2176 static unsigned mend;
2177 static unsigned mask;
2178
2179 void
2180 memlocate(void)
2181 {
2182         unsigned a, n;
2183         unsigned char val[4];
2184
2185         last_cmd = "ml";
2186         scanhex((void *)&mdest);
2187         if (termch != '\n') {
2188                 termch = 0;
2189                 scanhex((void *)&mend);
2190                 if (termch != '\n') {
2191                         termch = 0;
2192                         scanhex((void *)&mval);
2193                         mask = ~0;
2194                         if (termch != '\n') termch = 0;
2195                         scanhex((void *)&mask);
2196                 }
2197         }
2198         n = 0;
2199         for (a = mdest; a < mend; a += 4) {
2200                 if (mread(a, val, 4) == 4
2201                         && ((GETWORD(val) ^ mval) & mask) == 0) {
2202                         printf("%.16x:  %.16x\n", a, GETWORD(val));
2203                         if (++n >= 10)
2204                                 break;
2205                 }
2206         }
2207 }
2208
2209 static unsigned long mskip = 0x1000;
2210 static unsigned long mlim = 0xffffffff;
2211
2212 void
2213 memzcan(void)
2214 {
2215         unsigned char v;
2216         unsigned a;
2217         int ok, ook;
2218
2219         scanhex(&mdest);
2220         if (termch != '\n') termch = 0;
2221         scanhex(&mskip);
2222         if (termch != '\n') termch = 0;
2223         scanhex(&mlim);
2224         ook = 0;
2225         for (a = mdest; a < mlim; a += mskip) {
2226                 ok = mread(a, &v, 1);
2227                 if (ok && !ook) {
2228                         printf("%.8x .. ", a);
2229                 } else if (!ok && ook)
2230                         printf("%.8x\n", a - mskip);
2231                 ook = ok;
2232                 if (a + mskip < a)
2233                         break;
2234         }
2235         if (ook)
2236                 printf("%.8x\n", a - mskip);
2237 }
2238
2239 void proccall(void)
2240 {
2241         unsigned long args[8];
2242         unsigned long ret;
2243         int i;
2244         typedef unsigned long (*callfunc_t)(unsigned long, unsigned long,
2245                         unsigned long, unsigned long, unsigned long,
2246                         unsigned long, unsigned long, unsigned long);
2247         callfunc_t func;
2248
2249         if (!scanhex(&adrs))
2250                 return;
2251         if (termch != '\n')
2252                 termch = 0;
2253         for (i = 0; i < 8; ++i)
2254                 args[i] = 0;
2255         for (i = 0; i < 8; ++i) {
2256                 if (!scanhex(&args[i]) || termch == '\n')
2257                         break;
2258                 termch = 0;
2259         }
2260         func = (callfunc_t) adrs;
2261         ret = 0;
2262         if (setjmp(bus_error_jmp) == 0) {
2263                 catch_memory_errors = 1;
2264                 sync();
2265                 ret = func(args[0], args[1], args[2], args[3],
2266                            args[4], args[5], args[6], args[7]);
2267                 sync();
2268                 printf("return value is %x\n", ret);
2269         } else {
2270                 printf("*** %x exception occurred\n", fault_except);
2271         }
2272         catch_memory_errors = 0;
2273 }
2274
2275 /* Input scanning routines */
2276 int
2277 skipbl(void)
2278 {
2279         int c;
2280
2281         if( termch != 0 ){
2282                 c = termch;
2283                 termch = 0;
2284         } else
2285                 c = inchar();
2286         while( c == ' ' || c == '\t' )
2287                 c = inchar();
2288         return c;
2289 }
2290
2291 #define N_PTREGS        44
2292 static char *regnames[N_PTREGS] = {
2293         "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
2294         "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
2295         "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
2296         "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
2297         "pc", "msr", "or3", "ctr", "lr", "xer", "ccr",
2298 #ifdef CONFIG_PPC64
2299         "softe",
2300 #else
2301         "mq",
2302 #endif
2303         "trap", "dar", "dsisr", "res"
2304 };
2305
2306 int
2307 scanhex(unsigned long *vp)
2308 {
2309         int c, d;
2310         unsigned long v;
2311
2312         c = skipbl();
2313         if (c == '%') {
2314                 /* parse register name */
2315                 char regname[8];
2316                 int i;
2317
2318                 for (i = 0; i < sizeof(regname) - 1; ++i) {
2319                         c = inchar();
2320                         if (!isalnum(c)) {
2321                                 termch = c;
2322                                 break;
2323                         }
2324                         regname[i] = c;
2325                 }
2326                 regname[i] = 0;
2327                 for (i = 0; i < N_PTREGS; ++i) {
2328                         if (strcmp(regnames[i], regname) == 0) {
2329                                 if (xmon_regs == NULL) {
2330                                         printf("regs not available\n");
2331                                         return 0;
2332                                 }
2333                                 *vp = ((unsigned long *)xmon_regs)[i];
2334                                 return 1;
2335                         }
2336                 }
2337                 printf("invalid register name '%%%s'\n", regname);
2338                 return 0;
2339         }
2340
2341         /* skip leading "0x" if any */
2342
2343         if (c == '0') {
2344                 c = inchar();
2345                 if (c == 'x') {
2346                         c = inchar();
2347                 } else {
2348                         d = hexdigit(c);
2349                         if (d == EOF) {
2350                                 termch = c;
2351                                 *vp = 0;
2352                                 return 1;
2353                         }
2354                 }
2355         } else if (c == '$') {
2356                 int i;
2357                 for (i=0; i<63; i++) {
2358                         c = inchar();
2359                         if (isspace(c)) {
2360                                 termch = c;
2361                                 break;
2362                         }
2363                         tmpstr[i] = c;
2364                 }
2365                 tmpstr[i++] = 0;
2366                 *vp = 0;
2367                 if (setjmp(bus_error_jmp) == 0) {
2368                         catch_memory_errors = 1;
2369                         sync();
2370                         *vp = kallsyms_lookup_name(tmpstr);
2371                         sync();
2372                 }
2373                 catch_memory_errors = 0;
2374                 if (!(*vp)) {
2375                         printf("unknown symbol '%s'\n", tmpstr);
2376                         return 0;
2377                 }
2378                 return 1;
2379         }
2380
2381         d = hexdigit(c);
2382         if (d == EOF) {
2383                 termch = c;
2384                 return 0;
2385         }
2386         v = 0;
2387         do {
2388                 v = (v << 4) + d;
2389                 c = inchar();
2390                 d = hexdigit(c);
2391         } while (d != EOF);
2392         termch = c;
2393         *vp = v;
2394         return 1;
2395 }
2396
2397 void
2398 scannl(void)
2399 {
2400         int c;
2401
2402         c = termch;
2403         termch = 0;
2404         while( c != '\n' )
2405                 c = inchar();
2406 }
2407
2408 int hexdigit(int c)
2409 {
2410         if( '0' <= c && c <= '9' )
2411                 return c - '0';
2412         if( 'A' <= c && c <= 'F' )
2413                 return c - ('A' - 10);
2414         if( 'a' <= c && c <= 'f' )
2415                 return c - ('a' - 10);
2416         return EOF;
2417 }
2418
2419 void
2420 getstring(char *s, int size)
2421 {
2422         int c;
2423
2424         c = skipbl();
2425         do {
2426                 if( size > 1 ){
2427                         *s++ = c;
2428                         --size;
2429                 }
2430                 c = inchar();
2431         } while( c != ' ' && c != '\t' && c != '\n' );
2432         termch = c;
2433         *s = 0;
2434 }
2435
2436 static char line[256];
2437 static char *lineptr;
2438
2439 void
2440 flush_input(void)
2441 {
2442         lineptr = NULL;
2443 }
2444
2445 int
2446 inchar(void)
2447 {
2448         if (lineptr == NULL || *lineptr == 0) {
2449                 if (xmon_gets(line, sizeof(line)) == NULL) {
2450                         lineptr = NULL;
2451                         return EOF;
2452                 }
2453                 lineptr = line;
2454         }
2455         return *lineptr++;
2456 }
2457
2458 void
2459 take_input(char *str)
2460 {
2461         lineptr = str;
2462 }
2463
2464
2465 static void
2466 symbol_lookup(void)
2467 {
2468         int type = inchar();
2469         unsigned long addr;
2470         static char tmp[64];
2471
2472         switch (type) {
2473         case 'a':
2474                 if (scanhex(&addr))
2475                         xmon_print_symbol(addr, ": ", "\n");
2476                 termch = 0;
2477                 break;
2478         case 's':
2479                 getstring(tmp, 64);
2480                 if (setjmp(bus_error_jmp) == 0) {
2481                         catch_memory_errors = 1;
2482                         sync();
2483                         addr = kallsyms_lookup_name(tmp);
2484                         if (addr)
2485                                 printf("%s: %lx\n", tmp, addr);
2486                         else
2487                                 printf("Symbol '%s' not found.\n", tmp);
2488                         sync();
2489                 }
2490                 catch_memory_errors = 0;
2491                 termch = 0;
2492                 break;
2493         }
2494 }
2495
2496
2497 /* Print an address in numeric and symbolic form (if possible) */
2498 static void xmon_print_symbol(unsigned long address, const char *mid,
2499                               const char *after)
2500 {
2501         char *modname;
2502         const char *name = NULL;
2503         unsigned long offset, size;
2504
2505         printf(REG, address);
2506         if (setjmp(bus_error_jmp) == 0) {
2507                 catch_memory_errors = 1;
2508                 sync();
2509                 name = kallsyms_lookup(address, &size, &offset, &modname,
2510                                        tmpstr);
2511                 sync();
2512                 /* wait a little while to see if we get a machine check */
2513                 __delay(200);
2514         }
2515
2516         catch_memory_errors = 0;
2517
2518         if (name) {
2519                 printf("%s%s+%#lx/%#lx", mid, name, offset, size);
2520                 if (modname)
2521                         printf(" [%s]", modname);
2522         }
2523         printf("%s", after);
2524 }
2525
2526 #ifdef CONFIG_PPC64
2527 static void dump_slb(void)
2528 {
2529         int i;
2530         unsigned long tmp;
2531
2532         printf("SLB contents of cpu %x\n", smp_processor_id());
2533
2534         for (i = 0; i < SLB_NUM_ENTRIES; i++) {
2535                 asm volatile("slbmfee  %0,%1" : "=r" (tmp) : "r" (i));
2536                 printf("%02d %016lx ", i, tmp);
2537
2538                 asm volatile("slbmfev  %0,%1" : "=r" (tmp) : "r" (i));
2539                 printf("%016lx\n", tmp);
2540         }
2541 }
2542
2543 static void dump_stab(void)
2544 {
2545         int i;
2546         unsigned long *tmp = (unsigned long *)get_paca()->stab_addr;
2547
2548         printf("Segment table contents of cpu %x\n", smp_processor_id());
2549
2550         for (i = 0; i < PAGE_SIZE/16; i++) {
2551                 unsigned long a, b;
2552
2553                 a = *tmp++;
2554                 b = *tmp++;
2555
2556                 if (a || b) {
2557                         printf("%03d %016lx ", i, a);
2558                         printf("%016lx\n", b);
2559                 }
2560         }
2561 }
2562
2563 void dump_segments(void)
2564 {
2565         if (cpu_has_feature(CPU_FTR_SLB))
2566                 dump_slb();
2567         else
2568                 dump_stab();
2569 }
2570 #endif
2571
2572 #ifdef CONFIG_PPC_STD_MMU_32
2573 void dump_segments(void)
2574 {
2575         int i;
2576
2577         printf("sr0-15 =");
2578         for (i = 0; i < 16; ++i)
2579                 printf(" %x", mfsrin(i));
2580         printf("\n");
2581 }
2582 #endif
2583
2584 void xmon_init(int enable)
2585 {
2586 #ifdef CONFIG_PPC_ISERIES
2587         if (firmware_has_feature(FW_FEATURE_ISERIES))
2588                 return;
2589 #endif
2590         if (enable) {
2591                 __debugger = xmon;
2592                 __debugger_ipi = xmon_ipi;
2593                 __debugger_bpt = xmon_bpt;
2594                 __debugger_sstep = xmon_sstep;
2595                 __debugger_iabr_match = xmon_iabr_match;
2596                 __debugger_dabr_match = xmon_dabr_match;
2597                 __debugger_fault_handler = xmon_fault_handler;
2598         } else {
2599                 __debugger = NULL;
2600                 __debugger_ipi = NULL;
2601                 __debugger_bpt = NULL;
2602                 __debugger_sstep = NULL;
2603                 __debugger_iabr_match = NULL;
2604                 __debugger_dabr_match = NULL;
2605                 __debugger_fault_handler = NULL;
2606         }
2607         xmon_map_scc();
2608 }
2609
2610 #ifdef CONFIG_MAGIC_SYSRQ
2611 static void sysrq_handle_xmon(int key, struct tty_struct *tty) 
2612 {
2613         /* ensure xmon is enabled */
2614         xmon_init(1);
2615         debugger(get_irq_regs());
2616 }
2617
2618 static struct sysrq_key_op sysrq_xmon_op = 
2619 {
2620         .handler =      sysrq_handle_xmon,
2621         .help_msg =     "Xmon",
2622         .action_msg =   "Entering xmon",
2623 };
2624
2625 static int __init setup_xmon_sysrq(void)
2626 {
2627 #ifdef CONFIG_PPC_ISERIES
2628         if (firmware_has_feature(FW_FEATURE_ISERIES))
2629                 return 0;
2630 #endif
2631         register_sysrq_key('x', &sysrq_xmon_op);
2632         return 0;
2633 }
2634 __initcall(setup_xmon_sysrq);
2635 #endif /* CONFIG_MAGIC_SYSRQ */
2636
2637 static int __initdata xmon_early, xmon_off;
2638
2639 static int __init early_parse_xmon(char *p)
2640 {
2641         if (!p || strncmp(p, "early", 5) == 0) {
2642                 /* just "xmon" is equivalent to "xmon=early" */
2643                 xmon_init(1);
2644                 xmon_early = 1;
2645         } else if (strncmp(p, "on", 2) == 0)
2646                 xmon_init(1);
2647         else if (strncmp(p, "off", 3) == 0)
2648                 xmon_off = 1;
2649         else if (strncmp(p, "nobt", 4) == 0)
2650                 xmon_no_auto_backtrace = 1;
2651         else
2652                 return 1;
2653
2654         return 0;
2655 }
2656 early_param("xmon", early_parse_xmon);
2657
2658 void __init xmon_setup(void)
2659 {
2660 #ifdef CONFIG_XMON_DEFAULT
2661         if (!xmon_off)
2662                 xmon_init(1);
2663 #endif
2664         if (xmon_early)
2665                 debugger(NULL);
2666 }
2667
2668 #ifdef CONFIG_SPU_BASE
2669
2670 struct spu_info {
2671         struct spu *spu;
2672         u64 saved_mfc_sr1_RW;
2673         u32 saved_spu_runcntl_RW;
2674         unsigned long dump_addr;
2675         u8 stopped_ok;
2676 };
2677
2678 #define XMON_NUM_SPUS   16      /* Enough for current hardware */
2679
2680 static struct spu_info spu_info[XMON_NUM_SPUS];
2681
2682 void xmon_register_spus(struct list_head *list)
2683 {
2684         struct spu *spu;
2685
2686         list_for_each_entry(spu, list, full_list) {
2687                 if (spu->number >= XMON_NUM_SPUS) {
2688                         WARN_ON(1);
2689                         continue;
2690                 }
2691
2692                 spu_info[spu->number].spu = spu;
2693                 spu_info[spu->number].stopped_ok = 0;
2694                 spu_info[spu->number].dump_addr = (unsigned long)
2695                                 spu_info[spu->number].spu->local_store;
2696         }
2697 }
2698
2699 static void stop_spus(void)
2700 {
2701         struct spu *spu;
2702         int i;
2703         u64 tmp;
2704
2705         for (i = 0; i < XMON_NUM_SPUS; i++) {
2706                 if (!spu_info[i].spu)
2707                         continue;
2708
2709                 if (setjmp(bus_error_jmp) == 0) {
2710                         catch_memory_errors = 1;
2711                         sync();
2712
2713                         spu = spu_info[i].spu;
2714
2715                         spu_info[i].saved_spu_runcntl_RW =
2716                                 in_be32(&spu->problem->spu_runcntl_RW);
2717
2718                         tmp = spu_mfc_sr1_get(spu);
2719                         spu_info[i].saved_mfc_sr1_RW = tmp;
2720
2721                         tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
2722                         spu_mfc_sr1_set(spu, tmp);
2723
2724                         sync();
2725                         __delay(200);
2726
2727                         spu_info[i].stopped_ok = 1;
2728
2729                         printf("Stopped spu %.2d (was %s)\n", i,
2730                                         spu_info[i].saved_spu_runcntl_RW ?
2731                                         "running" : "stopped");
2732                 } else {
2733                         catch_memory_errors = 0;
2734                         printf("*** Error stopping spu %.2d\n", i);
2735                 }
2736                 catch_memory_errors = 0;
2737         }
2738 }
2739
2740 static void restart_spus(void)
2741 {
2742         struct spu *spu;
2743         int i;
2744
2745         for (i = 0; i < XMON_NUM_SPUS; i++) {
2746                 if (!spu_info[i].spu)
2747                         continue;
2748
2749                 if (!spu_info[i].stopped_ok) {
2750                         printf("*** Error, spu %d was not successfully stopped"
2751                                         ", not restarting\n", i);
2752                         continue;
2753                 }
2754
2755                 if (setjmp(bus_error_jmp) == 0) {
2756                         catch_memory_errors = 1;
2757                         sync();
2758
2759                         spu = spu_info[i].spu;
2760                         spu_mfc_sr1_set(spu, spu_info[i].saved_mfc_sr1_RW);
2761                         out_be32(&spu->problem->spu_runcntl_RW,
2762                                         spu_info[i].saved_spu_runcntl_RW);
2763
2764                         sync();
2765                         __delay(200);
2766
2767                         printf("Restarted spu %.2d\n", i);
2768                 } else {
2769                         catch_memory_errors = 0;
2770                         printf("*** Error restarting spu %.2d\n", i);
2771                 }
2772                 catch_memory_errors = 0;
2773         }
2774 }
2775
2776 #define DUMP_WIDTH      23
2777 #define DUMP_VALUE(format, field, value)                                \
2778 do {                                                                    \
2779         if (setjmp(bus_error_jmp) == 0) {                               \
2780                 catch_memory_errors = 1;                                \
2781                 sync();                                                 \
2782                 printf("  %-*s = "format"\n", DUMP_WIDTH,               \
2783                                 #field, value);                         \
2784                 sync();                                                 \
2785                 __delay(200);                                           \
2786         } else {                                                        \
2787                 catch_memory_errors = 0;                                \
2788                 printf("  %-*s = *** Error reading field.\n",           \
2789                                         DUMP_WIDTH, #field);            \
2790         }                                                               \
2791         catch_memory_errors = 0;                                        \
2792 } while (0)
2793
2794 #define DUMP_FIELD(obj, format, field)  \
2795         DUMP_VALUE(format, field, obj->field)
2796
2797 static void dump_spu_fields(struct spu *spu)
2798 {
2799         printf("Dumping spu fields at address %p:\n", spu);
2800
2801         DUMP_FIELD(spu, "0x%x", number);
2802         DUMP_FIELD(spu, "%s", name);
2803         DUMP_FIELD(spu, "0x%lx", local_store_phys);
2804         DUMP_FIELD(spu, "0x%p", local_store);
2805         DUMP_FIELD(spu, "0x%lx", ls_size);
2806         DUMP_FIELD(spu, "0x%x", node);
2807         DUMP_FIELD(spu, "0x%lx", flags);
2808         DUMP_FIELD(spu, "0x%lx", dar);
2809         DUMP_FIELD(spu, "0x%lx", dsisr);
2810         DUMP_FIELD(spu, "%d", class_0_pending);
2811         DUMP_FIELD(spu, "0x%lx", irqs[0]);
2812         DUMP_FIELD(spu, "0x%lx", irqs[1]);
2813         DUMP_FIELD(spu, "0x%lx", irqs[2]);
2814         DUMP_FIELD(spu, "0x%x", slb_replace);
2815         DUMP_FIELD(spu, "%d", pid);
2816         DUMP_FIELD(spu, "0x%p", mm);
2817         DUMP_FIELD(spu, "0x%p", ctx);
2818         DUMP_FIELD(spu, "0x%p", rq);
2819         DUMP_FIELD(spu, "0x%p", timestamp);
2820         DUMP_FIELD(spu, "0x%lx", problem_phys);
2821         DUMP_FIELD(spu, "0x%p", problem);
2822         DUMP_VALUE("0x%x", problem->spu_runcntl_RW,
2823                         in_be32(&spu->problem->spu_runcntl_RW));
2824         DUMP_VALUE("0x%x", problem->spu_status_R,
2825                         in_be32(&spu->problem->spu_status_R));
2826         DUMP_VALUE("0x%x", problem->spu_npc_RW,
2827                         in_be32(&spu->problem->spu_npc_RW));
2828         DUMP_FIELD(spu, "0x%p", priv2);
2829         DUMP_FIELD(spu, "0x%p", pdata);
2830 }
2831
2832 int
2833 spu_inst_dump(unsigned long adr, long count, int praddr)
2834 {
2835         return generic_inst_dump(adr, count, praddr, print_insn_spu);
2836 }
2837
2838 static void dump_spu_ls(unsigned long num, int subcmd)
2839 {
2840         unsigned long offset, addr, ls_addr;
2841
2842         if (setjmp(bus_error_jmp) == 0) {
2843                 catch_memory_errors = 1;
2844                 sync();
2845                 ls_addr = (unsigned long)spu_info[num].spu->local_store;
2846                 sync();
2847                 __delay(200);
2848         } else {
2849                 catch_memory_errors = 0;
2850                 printf("*** Error: accessing spu info for spu %d\n", num);
2851                 return;
2852         }
2853         catch_memory_errors = 0;
2854
2855         if (scanhex(&offset))
2856                 addr = ls_addr + offset;
2857         else
2858                 addr = spu_info[num].dump_addr;
2859
2860         if (addr >= ls_addr + LS_SIZE) {
2861                 printf("*** Error: address outside of local store\n");
2862                 return;
2863         }
2864
2865         switch (subcmd) {
2866         case 'i':
2867                 addr += spu_inst_dump(addr, 16, 1);
2868                 last_cmd = "sdi\n";
2869                 break;
2870         default:
2871                 prdump(addr, 64);
2872                 addr += 64;
2873                 last_cmd = "sd\n";
2874                 break;
2875         }
2876
2877         spu_info[num].dump_addr = addr;
2878 }
2879
2880 static int do_spu_cmd(void)
2881 {
2882         static unsigned long num = 0;
2883         int cmd, subcmd = 0;
2884
2885         cmd = inchar();
2886         switch (cmd) {
2887         case 's':
2888                 stop_spus();
2889                 break;
2890         case 'r':
2891                 restart_spus();
2892                 break;
2893         case 'd':
2894                 subcmd = inchar();
2895                 if (isxdigit(subcmd) || subcmd == '\n')
2896                         termch = subcmd;
2897         case 'f':
2898                 scanhex(&num);
2899                 if (num >= XMON_NUM_SPUS || !spu_info[num].spu) {
2900                         printf("*** Error: invalid spu number\n");
2901                         return 0;
2902                 }
2903
2904                 switch (cmd) {
2905                 case 'f':
2906                         dump_spu_fields(spu_info[num].spu);
2907                         break;
2908                 default:
2909                         dump_spu_ls(num, subcmd);
2910                         break;
2911                 }
2912
2913                 break;
2914         default:
2915                 return -1;
2916         }
2917
2918         return 0;
2919 }
2920 #else /* ! CONFIG_SPU_BASE */
2921 static int do_spu_cmd(void)
2922 {
2923         return -1;
2924 }
2925 #endif