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