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