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