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