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