blob: f56ffef4defa7f0b3724fea942afda436008d3a8 [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>
Paul Mackerrasf78541dc2005-10-28 22:53:37 +100040
41#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include <asm/hvcall.h>
Paul Mackerrasf78541dc2005-10-28 22:53:37 +100043#include <asm/paca.h>
44#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070045
46#include "nonstdio.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070047
48#define scanhex xmon_scanhex
49#define skipbl xmon_skipbl
50
51#ifdef CONFIG_SMP
52cpumask_t cpus_in_xmon = CPU_MASK_NONE;
53static unsigned long xmon_taken = 1;
54static int xmon_owner;
55static int xmon_gate;
56#endif /* CONFIG_SMP */
57
58static unsigned long in_xmon = 0;
59
60static unsigned long adrs;
61static int size = 1;
62#define MAX_DUMP (128 * 1024)
63static unsigned long ndump = 64;
64static unsigned long nidump = 16;
65static unsigned long ncsum = 4096;
66static int termch;
67static char tmpstr[128];
68
Paul Mackerrasf78541dc2005-10-28 22:53:37 +100069#define JMP_BUF_LEN 23
Linus Torvalds1da177e2005-04-16 15:20:36 -070070static long bus_error_jmp[JMP_BUF_LEN];
71static int catch_memory_errors;
72static long *xmon_fault_jmp[NR_CPUS];
73#define setjmp xmon_setjmp
74#define longjmp xmon_longjmp
75
76/* Breakpoint stuff */
77struct bpt {
78 unsigned long address;
79 unsigned int instr[2];
80 atomic_t ref_count;
81 int enabled;
82 unsigned long pad;
83};
84
85/* Bits in bpt.enabled */
86#define BP_IABR_TE 1 /* IABR translation enabled */
87#define BP_IABR 2
88#define BP_TRAP 8
89#define BP_DABR 0x10
90
91#define NBPTS 256
92static struct bpt bpts[NBPTS];
93static struct bpt dabr;
94static struct bpt *iabr;
95static unsigned bpinstr = 0x7fe00008; /* trap */
96
97#define BP_NUM(bp) ((bp) - bpts + 1)
98
99/* Prototypes */
100static int cmds(struct pt_regs *);
101static int mread(unsigned long, void *, int);
102static int mwrite(unsigned long, void *, int);
103static int handle_fault(struct pt_regs *);
104static void byterev(unsigned char *, int);
105static void memex(void);
106static int bsesc(void);
107static void dump(void);
108static void prdump(unsigned long, long);
109static int ppc_inst_dump(unsigned long, long, int);
110void print_address(unsigned long);
111static void backtrace(struct pt_regs *);
112static void excprint(struct pt_regs *);
113static void prregs(struct pt_regs *);
114static void memops(int);
115static void memlocate(void);
116static void memzcan(void);
117static void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned);
118int skipbl(void);
119int scanhex(unsigned long *valp);
120static void scannl(void);
121static int hexdigit(int);
122void getstring(char *, int);
123static void flush_input(void);
124static int inchar(void);
125static void take_input(char *);
126static unsigned long read_spr(int);
127static void write_spr(int, unsigned long);
128static void super_regs(void);
129static void remove_bpts(void);
130static void insert_bpts(void);
131static void remove_cpu_bpts(void);
132static void insert_cpu_bpts(void);
133static struct bpt *at_breakpoint(unsigned long pc);
134static struct bpt *in_breakpoint_table(unsigned long pc, unsigned long *offp);
135static int do_step(struct pt_regs *);
136static void bpt_cmds(void);
137static void cacheflush(void);
138static int cpu_cmd(void);
139static void csum(void);
140static void bootcmds(void);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000141static void proccall(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142void dump_segments(void);
143static void symbol_lookup(void);
Olaf Hering26c8af52006-09-08 16:29:21 +0200144static void xmon_show_stack(unsigned long sp, unsigned long lr,
145 unsigned long pc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146static void xmon_print_symbol(unsigned long address, const char *mid,
147 const char *after);
148static const char *getvecname(unsigned long vec);
149
Olaf Hering26c8af52006-09-08 16:29:21 +0200150int xmon_no_auto_backtrace;
151
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152extern int print_insn_powerpc(unsigned long, unsigned long, int);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000153
154extern void xmon_enter(void);
155extern void xmon_leave(void);
156
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000157extern long setjmp(long *);
158extern void longjmp(long *, long);
159extern void xmon_save_regs(struct pt_regs *);
160
161#ifdef CONFIG_PPC64
162#define REG "%.16lx"
163#define REGS_PER_LINE 4
164#define LAST_VOLATILE 13
165#else
166#define REG "%.8lx"
167#define REGS_PER_LINE 8
168#define LAST_VOLATILE 12
169#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170
171#define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
172
173#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
174 || ('a' <= (c) && (c) <= 'f') \
175 || ('A' <= (c) && (c) <= 'F'))
176#define isalnum(c) (('0' <= (c) && (c) <= '9') \
177 || ('a' <= (c) && (c) <= 'z') \
178 || ('A' <= (c) && (c) <= 'Z'))
179#define isspace(c) (c == ' ' || c == '\t' || c == 10 || c == 13 || c == 0)
180
181static char *help_string = "\
182Commands:\n\
183 b show breakpoints\n\
184 bd set data breakpoint\n\
185 bi set instruction breakpoint\n\
186 bc clear breakpoint\n"
187#ifdef CONFIG_SMP
188 "\
189 c print cpus stopped in xmon\n\
190 c# try to switch to cpu number h (in hex)\n"
191#endif
192 "\
193 C checksum\n\
194 d dump bytes\n\
195 di dump instructions\n\
196 df dump float values\n\
197 dd dump double values\n\
Olaf Hering7e5b5932006-03-08 20:40:28 +0100198 dr dump stream of raw bytes\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 e print exception information\n\
200 f flush cache\n\
201 la lookup symbol+offset of specified address\n\
202 ls lookup address of specified symbol\n\
203 m examine/change memory\n\
204 mm move a block of memory\n\
205 ms set a block of memory\n\
206 md compare two blocks of memory\n\
207 ml locate a block of memory\n\
208 mz zero a block of memory\n\
209 mi show information about memory allocation\n\
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000210 p call a procedure\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 r print registers\n\
212 s single step\n\
213 S print special registers\n\
214 t print backtrace\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 x exit monitor and recover\n\
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000216 X exit monitor and dont recover\n"
217#ifdef CONFIG_PPC64
218" u dump segment table or SLB\n"
219#endif
220#ifdef CONFIG_PPC_STD_MMU_32
221" u dump segment registers\n"
222#endif
223" ? help\n"
224" zr reboot\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 zh halt\n"
226;
227
228static struct pt_regs *xmon_regs;
229
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000230static inline void sync(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231{
232 asm volatile("sync; isync");
233}
234
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000235static inline void store_inst(void *p)
236{
237 asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p));
238}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000240static inline void cflush(void *p)
241{
242 asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p));
243}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000245static inline void cinval(void *p)
246{
247 asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p));
248}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249
250/*
251 * Disable surveillance (the service processor watchdog function)
252 * while we are in xmon.
253 * XXX we should re-enable it when we leave. :)
254 */
255#define SURVEILLANCE_TOKEN 9000
256
257static inline void disable_surveillance(void)
258{
259#ifdef CONFIG_PPC_PSERIES
260 /* Since this can't be a module, args should end up below 4GB. */
261 static struct rtas_args args;
262
263 /*
264 * At this point we have got all the cpus we can into
265 * xmon, so there is hopefully no other cpu calling RTAS
266 * at the moment, even though we don't take rtas.lock.
267 * If we did try to take rtas.lock there would be a
268 * real possibility of deadlock.
269 */
270 args.token = rtas_token("set-indicator");
271 if (args.token == RTAS_UNKNOWN_SERVICE)
272 return;
273 args.nargs = 3;
274 args.nret = 1;
275 args.rets = &args.args[3];
276 args.args[0] = SURVEILLANCE_TOKEN;
277 args.args[1] = 0;
278 args.args[2] = 0;
279 enter_rtas(__pa(&args));
280#endif /* CONFIG_PPC_PSERIES */
281}
282
283#ifdef CONFIG_SMP
284static int xmon_speaker;
285
286static void get_output_lock(void)
287{
288 int me = smp_processor_id() + 0x100;
289 int last_speaker = 0, prev;
290 long timeout;
291
292 if (xmon_speaker == me)
293 return;
294 for (;;) {
295 if (xmon_speaker == 0) {
296 last_speaker = cmpxchg(&xmon_speaker, 0, me);
297 if (last_speaker == 0)
298 return;
299 }
300 timeout = 10000000;
301 while (xmon_speaker == last_speaker) {
302 if (--timeout > 0)
303 continue;
304 /* hostile takeover */
305 prev = cmpxchg(&xmon_speaker, last_speaker, me);
306 if (prev == last_speaker)
307 return;
308 break;
309 }
310 }
311}
312
313static void release_output_lock(void)
314{
315 xmon_speaker = 0;
316}
317#endif
318
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000319static int xmon_core(struct pt_regs *regs, int fromipi)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320{
321 int cmd = 0;
322 unsigned long msr;
323 struct bpt *bp;
324 long recurse_jmp[JMP_BUF_LEN];
325 unsigned long offset;
326#ifdef CONFIG_SMP
327 int cpu;
328 int secondary;
329 unsigned long timeout;
330#endif
331
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000332 msr = mfmsr();
333 mtmsr(msr & ~MSR_EE); /* disable interrupts */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334
335 bp = in_breakpoint_table(regs->nip, &offset);
336 if (bp != NULL) {
337 regs->nip = bp->address + offset;
338 atomic_dec(&bp->ref_count);
339 }
340
341 remove_cpu_bpts();
342
343#ifdef CONFIG_SMP
344 cpu = smp_processor_id();
345 if (cpu_isset(cpu, cpus_in_xmon)) {
346 get_output_lock();
347 excprint(regs);
348 printf("cpu 0x%x: Exception %lx %s in xmon, "
349 "returning to main loop\n",
350 cpu, regs->trap, getvecname(TRAP(regs)));
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000351 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 longjmp(xmon_fault_jmp[cpu], 1);
353 }
354
355 if (setjmp(recurse_jmp) != 0) {
356 if (!in_xmon || !xmon_gate) {
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000357 get_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 printf("xmon: WARNING: bad recursive fault "
359 "on cpu 0x%x\n", cpu);
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000360 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 goto waiting;
362 }
363 secondary = !(xmon_taken && cpu == xmon_owner);
364 goto cmdloop;
365 }
366
367 xmon_fault_jmp[cpu] = recurse_jmp;
368 cpu_set(cpu, cpus_in_xmon);
369
370 bp = NULL;
371 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF))
372 bp = at_breakpoint(regs->nip);
373 if (bp || (regs->msr & MSR_RI) == 0)
374 fromipi = 0;
375
376 if (!fromipi) {
377 get_output_lock();
378 excprint(regs);
379 if (bp) {
380 printf("cpu 0x%x stopped at breakpoint 0x%x (",
381 cpu, BP_NUM(bp));
382 xmon_print_symbol(regs->nip, " ", ")\n");
383 }
384 if ((regs->msr & MSR_RI) == 0)
385 printf("WARNING: exception is not recoverable, "
386 "can't continue\n");
387 release_output_lock();
388 }
389
390 waiting:
391 secondary = 1;
392 while (secondary && !xmon_gate) {
393 if (in_xmon == 0) {
394 if (fromipi)
395 goto leave;
396 secondary = test_and_set_bit(0, &in_xmon);
397 }
398 barrier();
399 }
400
401 if (!secondary && !xmon_gate) {
402 /* we are the first cpu to come in */
403 /* interrupt other cpu(s) */
404 int ncpus = num_online_cpus();
405
406 xmon_owner = cpu;
407 mb();
408 if (ncpus > 1) {
409 smp_send_debugger_break(MSG_ALL_BUT_SELF);
410 /* wait for other cpus to come in */
411 for (timeout = 100000000; timeout != 0; --timeout) {
412 if (cpus_weight(cpus_in_xmon) >= ncpus)
413 break;
414 barrier();
415 }
416 }
417 remove_bpts();
418 disable_surveillance();
419 /* for breakpoint or single step, print the current instr. */
420 if (bp || TRAP(regs) == 0xd00)
421 ppc_inst_dump(regs->nip, 1, 0);
422 printf("enter ? for help\n");
423 mb();
424 xmon_gate = 1;
425 barrier();
426 }
427
428 cmdloop:
429 while (in_xmon) {
430 if (secondary) {
431 if (cpu == xmon_owner) {
432 if (!test_and_set_bit(0, &xmon_taken)) {
433 secondary = 0;
434 continue;
435 }
436 /* missed it */
437 while (cpu == xmon_owner)
438 barrier();
439 }
440 barrier();
441 } else {
442 cmd = cmds(regs);
443 if (cmd != 0) {
444 /* exiting xmon */
445 insert_bpts();
446 xmon_gate = 0;
447 wmb();
448 in_xmon = 0;
449 break;
450 }
451 /* have switched to some other cpu */
452 secondary = 1;
453 }
454 }
455 leave:
456 cpu_clear(cpu, cpus_in_xmon);
457 xmon_fault_jmp[cpu] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458#else
459 /* UP is simple... */
460 if (in_xmon) {
461 printf("Exception %lx %s in xmon, returning to main loop\n",
462 regs->trap, getvecname(TRAP(regs)));
463 longjmp(xmon_fault_jmp[0], 1);
464 }
465 if (setjmp(recurse_jmp) == 0) {
466 xmon_fault_jmp[0] = recurse_jmp;
467 in_xmon = 1;
468
469 excprint(regs);
470 bp = at_breakpoint(regs->nip);
471 if (bp) {
472 printf("Stopped at breakpoint %x (", BP_NUM(bp));
473 xmon_print_symbol(regs->nip, " ", ")\n");
474 }
475 if ((regs->msr & MSR_RI) == 0)
476 printf("WARNING: exception is not recoverable, "
477 "can't continue\n");
478 remove_bpts();
479 disable_surveillance();
480 /* for breakpoint or single step, print the current instr. */
481 if (bp || TRAP(regs) == 0xd00)
482 ppc_inst_dump(regs->nip, 1, 0);
483 printf("enter ? for help\n");
484 }
485
486 cmd = cmds(regs);
487
488 insert_bpts();
489 in_xmon = 0;
490#endif
491
492 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF)) {
493 bp = at_breakpoint(regs->nip);
494 if (bp != NULL) {
495 int stepped = emulate_step(regs, bp->instr[0]);
496 if (stepped == 0) {
497 regs->nip = (unsigned long) &bp->instr[0];
498 atomic_inc(&bp->ref_count);
499 } else if (stepped < 0) {
500 printf("Couldn't single-step %s instruction\n",
501 (IS_RFID(bp->instr[0])? "rfid": "mtmsrd"));
502 }
503 }
504 }
505
506 insert_cpu_bpts();
507
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000508 mtmsr(msr); /* restore interrupt enable */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509
Paul Mackerras0a730ae2006-10-03 21:32:49 +1000510 return cmd != 'X' && cmd != EOF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511}
512
513int xmon(struct pt_regs *excp)
514{
515 struct pt_regs regs;
516
517 if (excp == NULL) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000518 xmon_save_regs(&regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 excp = &regs;
520 }
521 return xmon_core(excp, 0);
522}
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000523EXPORT_SYMBOL(xmon);
524
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000525irqreturn_t xmon_irq(int irq, void *d)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000526{
527 unsigned long flags;
528 local_irq_save(flags);
529 printf("Keyboard interrupt\n");
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000530 xmon(get_irq_regs());
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000531 local_irq_restore(flags);
532 return IRQ_HANDLED;
533}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000535static int xmon_bpt(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536{
537 struct bpt *bp;
538 unsigned long offset;
539
540 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF))
541 return 0;
542
543 /* Are we at the trap at bp->instr[1] for some bp? */
544 bp = in_breakpoint_table(regs->nip, &offset);
545 if (bp != NULL && offset == 4) {
546 regs->nip = bp->address + 4;
547 atomic_dec(&bp->ref_count);
548 return 1;
549 }
550
551 /* Are we at a breakpoint? */
552 bp = at_breakpoint(regs->nip);
553 if (!bp)
554 return 0;
555
556 xmon_core(regs, 0);
557
558 return 1;
559}
560
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000561static int xmon_sstep(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562{
563 if (user_mode(regs))
564 return 0;
565 xmon_core(regs, 0);
566 return 1;
567}
568
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000569static int xmon_dabr_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570{
571 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF))
572 return 0;
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000573 if (dabr.enabled == 0)
574 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 xmon_core(regs, 0);
576 return 1;
577}
578
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000579static int xmon_iabr_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;
583 if (iabr == 0)
584 return 0;
585 xmon_core(regs, 0);
586 return 1;
587}
588
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000589static int xmon_ipi(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590{
591#ifdef CONFIG_SMP
592 if (in_xmon && !cpu_isset(smp_processor_id(), cpus_in_xmon))
593 xmon_core(regs, 1);
594#endif
595 return 0;
596}
597
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000598static int xmon_fault_handler(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599{
600 struct bpt *bp;
601 unsigned long offset;
602
603 if (in_xmon && catch_memory_errors)
604 handle_fault(regs); /* doesn't return */
605
606 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF)) {
607 bp = in_breakpoint_table(regs->nip, &offset);
608 if (bp != NULL) {
609 regs->nip = bp->address + offset;
610 atomic_dec(&bp->ref_count);
611 }
612 }
613
614 return 0;
615}
616
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617static struct bpt *at_breakpoint(unsigned long pc)
618{
619 int i;
620 struct bpt *bp;
621
622 bp = bpts;
623 for (i = 0; i < NBPTS; ++i, ++bp)
624 if (bp->enabled && pc == bp->address)
625 return bp;
626 return NULL;
627}
628
629static struct bpt *in_breakpoint_table(unsigned long nip, unsigned long *offp)
630{
631 unsigned long off;
632
633 off = nip - (unsigned long) bpts;
634 if (off >= sizeof(bpts))
635 return NULL;
636 off %= sizeof(struct bpt);
637 if (off != offsetof(struct bpt, instr[0])
638 && off != offsetof(struct bpt, instr[1]))
639 return NULL;
640 *offp = off - offsetof(struct bpt, instr[0]);
641 return (struct bpt *) (nip - off);
642}
643
644static struct bpt *new_breakpoint(unsigned long a)
645{
646 struct bpt *bp;
647
648 a &= ~3UL;
649 bp = at_breakpoint(a);
650 if (bp)
651 return bp;
652
653 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
654 if (!bp->enabled && atomic_read(&bp->ref_count) == 0) {
655 bp->address = a;
656 bp->instr[1] = bpinstr;
657 store_inst(&bp->instr[1]);
658 return bp;
659 }
660 }
661
662 printf("Sorry, no free breakpoints. Please clear one first.\n");
663 return NULL;
664}
665
666static void insert_bpts(void)
667{
668 int i;
669 struct bpt *bp;
670
671 bp = bpts;
672 for (i = 0; i < NBPTS; ++i, ++bp) {
673 if ((bp->enabled & (BP_TRAP|BP_IABR)) == 0)
674 continue;
675 if (mread(bp->address, &bp->instr[0], 4) != 4) {
676 printf("Couldn't read instruction at %lx, "
677 "disabling breakpoint there\n", bp->address);
678 bp->enabled = 0;
679 continue;
680 }
681 if (IS_MTMSRD(bp->instr[0]) || IS_RFID(bp->instr[0])) {
682 printf("Breakpoint at %lx is on an mtmsrd or rfid "
683 "instruction, disabling it\n", bp->address);
684 bp->enabled = 0;
685 continue;
686 }
687 store_inst(&bp->instr[0]);
688 if (bp->enabled & BP_IABR)
689 continue;
690 if (mwrite(bp->address, &bpinstr, 4) != 4) {
691 printf("Couldn't write instruction at %lx, "
692 "disabling breakpoint there\n", bp->address);
693 bp->enabled &= ~BP_TRAP;
694 continue;
695 }
696 store_inst((void *)bp->address);
697 }
698}
699
700static void insert_cpu_bpts(void)
701{
702 if (dabr.enabled)
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000703 set_dabr(dabr.address | (dabr.enabled & 7));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 if (iabr && cpu_has_feature(CPU_FTR_IABR))
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000705 mtspr(SPRN_IABR, iabr->address
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 | (iabr->enabled & (BP_IABR|BP_IABR_TE)));
707}
708
709static void remove_bpts(void)
710{
711 int i;
712 struct bpt *bp;
713 unsigned instr;
714
715 bp = bpts;
716 for (i = 0; i < NBPTS; ++i, ++bp) {
717 if ((bp->enabled & (BP_TRAP|BP_IABR)) != BP_TRAP)
718 continue;
719 if (mread(bp->address, &instr, 4) == 4
720 && instr == bpinstr
721 && mwrite(bp->address, &bp->instr, 4) != 4)
722 printf("Couldn't remove breakpoint at %lx\n",
723 bp->address);
724 else
725 store_inst((void *)bp->address);
726 }
727}
728
729static void remove_cpu_bpts(void)
730{
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000731 set_dabr(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 if (cpu_has_feature(CPU_FTR_IABR))
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000733 mtspr(SPRN_IABR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734}
735
736/* Command interpreting routine */
737static char *last_cmd;
738
739static int
740cmds(struct pt_regs *excp)
741{
742 int cmd = 0;
743
744 last_cmd = NULL;
745 xmon_regs = excp;
Olaf Hering26c8af52006-09-08 16:29:21 +0200746
747 if (!xmon_no_auto_backtrace) {
748 xmon_no_auto_backtrace = 1;
749 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
750 }
751
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 for(;;) {
753#ifdef CONFIG_SMP
754 printf("%x:", smp_processor_id());
755#endif /* CONFIG_SMP */
756 printf("mon> ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 flush_input();
758 termch = 0;
759 cmd = skipbl();
760 if( cmd == '\n' ) {
761 if (last_cmd == NULL)
762 continue;
763 take_input(last_cmd);
764 last_cmd = NULL;
765 cmd = inchar();
766 }
767 switch (cmd) {
768 case 'm':
769 cmd = inchar();
770 switch (cmd) {
771 case 'm':
772 case 's':
773 case 'd':
774 memops(cmd);
775 break;
776 case 'l':
777 memlocate();
778 break;
779 case 'z':
780 memzcan();
781 break;
782 case 'i':
783 show_mem();
784 break;
785 default:
786 termch = cmd;
787 memex();
788 }
789 break;
790 case 'd':
791 dump();
792 break;
793 case 'l':
794 symbol_lookup();
795 break;
796 case 'r':
797 prregs(excp); /* print regs */
798 break;
799 case 'e':
800 excprint(excp);
801 break;
802 case 'S':
803 super_regs();
804 break;
805 case 't':
806 backtrace(excp);
807 break;
808 case 'f':
809 cacheflush();
810 break;
811 case 's':
812 if (do_step(excp))
813 return cmd;
814 break;
815 case 'x':
816 case 'X':
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100817 return cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 case EOF:
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100819 printf(" <no input ...>\n");
820 mdelay(2000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 return cmd;
822 case '?':
823 printf(help_string);
824 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 case 'b':
826 bpt_cmds();
827 break;
828 case 'C':
829 csum();
830 break;
831 case 'c':
832 if (cpu_cmd())
833 return 0;
834 break;
835 case 'z':
836 bootcmds();
837 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000838 case 'p':
839 proccall();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000841#ifdef CONFIG_PPC_STD_MMU
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 case 'u':
843 dump_segments();
844 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000845#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 default:
847 printf("Unrecognized command: ");
848 do {
849 if (' ' < cmd && cmd <= '~')
850 putchar(cmd);
851 else
852 printf("\\x%x", cmd);
853 cmd = inchar();
854 } while (cmd != '\n');
855 printf(" (type ? for help)\n");
856 break;
857 }
858 }
859}
860
861/*
862 * Step a single instruction.
863 * Some instructions we emulate, others we execute with MSR_SE set.
864 */
865static int do_step(struct pt_regs *regs)
866{
867 unsigned int instr;
868 int stepped;
869
870 /* check we are in 64-bit kernel mode, translation enabled */
871 if ((regs->msr & (MSR_SF|MSR_PR|MSR_IR)) == (MSR_SF|MSR_IR)) {
872 if (mread(regs->nip, &instr, 4) == 4) {
873 stepped = emulate_step(regs, instr);
874 if (stepped < 0) {
875 printf("Couldn't single-step %s instruction\n",
876 (IS_RFID(instr)? "rfid": "mtmsrd"));
877 return 0;
878 }
879 if (stepped > 0) {
880 regs->trap = 0xd00 | (regs->trap & 1);
881 printf("stepped to ");
882 xmon_print_symbol(regs->nip, " ", "\n");
883 ppc_inst_dump(regs->nip, 1, 0);
884 return 0;
885 }
886 }
887 }
888 regs->msr |= MSR_SE;
889 return 1;
890}
891
892static void bootcmds(void)
893{
894 int cmd;
895
896 cmd = inchar();
897 if (cmd == 'r')
898 ppc_md.restart(NULL);
899 else if (cmd == 'h')
900 ppc_md.halt();
901 else if (cmd == 'p')
902 ppc_md.power_off();
903}
904
905static int cpu_cmd(void)
906{
907#ifdef CONFIG_SMP
908 unsigned long cpu;
909 int timeout;
910 int count;
911
912 if (!scanhex(&cpu)) {
913 /* print cpus waiting or in xmon */
914 printf("cpus stopped:");
915 count = 0;
916 for (cpu = 0; cpu < NR_CPUS; ++cpu) {
917 if (cpu_isset(cpu, cpus_in_xmon)) {
918 if (count == 0)
919 printf(" %x", cpu);
920 ++count;
921 } else {
922 if (count > 1)
923 printf("-%x", cpu - 1);
924 count = 0;
925 }
926 }
927 if (count > 1)
928 printf("-%x", NR_CPUS - 1);
929 printf("\n");
930 return 0;
931 }
932 /* try to switch to cpu specified */
933 if (!cpu_isset(cpu, cpus_in_xmon)) {
934 printf("cpu 0x%x isn't in xmon\n", cpu);
935 return 0;
936 }
937 xmon_taken = 0;
938 mb();
939 xmon_owner = cpu;
940 timeout = 10000000;
941 while (!xmon_taken) {
942 if (--timeout == 0) {
943 if (test_and_set_bit(0, &xmon_taken))
944 break;
945 /* take control back */
946 mb();
947 xmon_owner = smp_processor_id();
948 printf("cpu %u didn't take control\n", cpu);
949 return 0;
950 }
951 barrier();
952 }
953 return 1;
954#else
955 return 0;
956#endif /* CONFIG_SMP */
957}
958
959static unsigned short fcstab[256] = {
960 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
961 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
962 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
963 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
964 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
965 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
966 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
967 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
968 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
969 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
970 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
971 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
972 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
973 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
974 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
975 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
976 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
977 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
978 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
979 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
980 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
981 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
982 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
983 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
984 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
985 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
986 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
987 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
988 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
989 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
990 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
991 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
992};
993
994#define FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
995
996static void
997csum(void)
998{
999 unsigned int i;
1000 unsigned short fcs;
1001 unsigned char v;
1002
1003 if (!scanhex(&adrs))
1004 return;
1005 if (!scanhex(&ncsum))
1006 return;
1007 fcs = 0xffff;
1008 for (i = 0; i < ncsum; ++i) {
1009 if (mread(adrs+i, &v, 1) == 0) {
1010 printf("csum stopped at %x\n", adrs+i);
1011 break;
1012 }
1013 fcs = FCS(fcs, v);
1014 }
1015 printf("%x\n", fcs);
1016}
1017
1018/*
1019 * Check if this is a suitable place to put a breakpoint.
1020 */
1021static long check_bp_loc(unsigned long addr)
1022{
1023 unsigned int instr;
1024
1025 addr &= ~3;
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001026 if (!is_kernel_addr(addr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 printf("Breakpoints may only be placed at kernel addresses\n");
1028 return 0;
1029 }
1030 if (!mread(addr, &instr, sizeof(instr))) {
1031 printf("Can't read instruction at address %lx\n", addr);
1032 return 0;
1033 }
1034 if (IS_MTMSRD(instr) || IS_RFID(instr)) {
1035 printf("Breakpoints may not be placed on mtmsrd or rfid "
1036 "instructions\n");
1037 return 0;
1038 }
1039 return 1;
1040}
1041
1042static char *breakpoint_help_string =
1043 "Breakpoint command usage:\n"
1044 "b show breakpoints\n"
1045 "b <addr> [cnt] set breakpoint at given instr addr\n"
1046 "bc clear all breakpoints\n"
1047 "bc <n/addr> clear breakpoint number n or at addr\n"
1048 "bi <addr> [cnt] set hardware instr breakpoint (POWER3/RS64 only)\n"
1049 "bd <addr> [cnt] set hardware data breakpoint\n"
1050 "";
1051
1052static void
1053bpt_cmds(void)
1054{
1055 int cmd;
1056 unsigned long a;
1057 int mode, i;
1058 struct bpt *bp;
1059 const char badaddr[] = "Only kernel addresses are permitted "
1060 "for breakpoints\n";
1061
1062 cmd = inchar();
1063 switch (cmd) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001064#ifndef CONFIG_8xx
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 case 'd': /* bd - hardware data breakpoint */
1066 mode = 7;
1067 cmd = inchar();
1068 if (cmd == 'r')
1069 mode = 5;
1070 else if (cmd == 'w')
1071 mode = 6;
1072 else
1073 termch = cmd;
1074 dabr.address = 0;
1075 dabr.enabled = 0;
1076 if (scanhex(&dabr.address)) {
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001077 if (!is_kernel_addr(dabr.address)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 printf(badaddr);
1079 break;
1080 }
1081 dabr.address &= ~7;
1082 dabr.enabled = mode | BP_DABR;
1083 }
1084 break;
1085
1086 case 'i': /* bi - hardware instr breakpoint */
1087 if (!cpu_has_feature(CPU_FTR_IABR)) {
1088 printf("Hardware instruction breakpoint "
1089 "not supported on this cpu\n");
1090 break;
1091 }
1092 if (iabr) {
1093 iabr->enabled &= ~(BP_IABR | BP_IABR_TE);
1094 iabr = NULL;
1095 }
1096 if (!scanhex(&a))
1097 break;
1098 if (!check_bp_loc(a))
1099 break;
1100 bp = new_breakpoint(a);
1101 if (bp != NULL) {
1102 bp->enabled |= BP_IABR | BP_IABR_TE;
1103 iabr = bp;
1104 }
1105 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001106#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107
1108 case 'c':
1109 if (!scanhex(&a)) {
1110 /* clear all breakpoints */
1111 for (i = 0; i < NBPTS; ++i)
1112 bpts[i].enabled = 0;
1113 iabr = NULL;
1114 dabr.enabled = 0;
1115 printf("All breakpoints cleared\n");
1116 break;
1117 }
1118
1119 if (a <= NBPTS && a >= 1) {
1120 /* assume a breakpoint number */
1121 bp = &bpts[a-1]; /* bp nums are 1 based */
1122 } else {
1123 /* assume a breakpoint address */
1124 bp = at_breakpoint(a);
1125 if (bp == 0) {
1126 printf("No breakpoint at %x\n", a);
1127 break;
1128 }
1129 }
1130
1131 printf("Cleared breakpoint %x (", BP_NUM(bp));
1132 xmon_print_symbol(bp->address, " ", ")\n");
1133 bp->enabled = 0;
1134 break;
1135
1136 default:
1137 termch = cmd;
1138 cmd = skipbl();
1139 if (cmd == '?') {
1140 printf(breakpoint_help_string);
1141 break;
1142 }
1143 termch = cmd;
1144 if (!scanhex(&a)) {
1145 /* print all breakpoints */
1146 printf(" type address\n");
1147 if (dabr.enabled) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001148 printf(" data "REG" [", dabr.address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 if (dabr.enabled & 1)
1150 printf("r");
1151 if (dabr.enabled & 2)
1152 printf("w");
1153 printf("]\n");
1154 }
1155 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
1156 if (!bp->enabled)
1157 continue;
1158 printf("%2x %s ", BP_NUM(bp),
1159 (bp->enabled & BP_IABR)? "inst": "trap");
1160 xmon_print_symbol(bp->address, " ", "\n");
1161 }
1162 break;
1163 }
1164
1165 if (!check_bp_loc(a))
1166 break;
1167 bp = new_breakpoint(a);
1168 if (bp != NULL)
1169 bp->enabled |= BP_TRAP;
1170 break;
1171 }
1172}
1173
1174/* Very cheap human name for vector lookup. */
1175static
1176const char *getvecname(unsigned long vec)
1177{
1178 char *ret;
1179
1180 switch (vec) {
1181 case 0x100: ret = "(System Reset)"; break;
1182 case 0x200: ret = "(Machine Check)"; break;
1183 case 0x300: ret = "(Data Access)"; break;
1184 case 0x380: ret = "(Data SLB Access)"; break;
1185 case 0x400: ret = "(Instruction Access)"; break;
1186 case 0x480: ret = "(Instruction SLB Access)"; break;
1187 case 0x500: ret = "(Hardware Interrupt)"; break;
1188 case 0x600: ret = "(Alignment)"; break;
1189 case 0x700: ret = "(Program Check)"; break;
1190 case 0x800: ret = "(FPU Unavailable)"; break;
1191 case 0x900: ret = "(Decrementer)"; break;
1192 case 0xc00: ret = "(System Call)"; break;
1193 case 0xd00: ret = "(Single Step)"; break;
1194 case 0xf00: ret = "(Performance Monitor)"; break;
1195 case 0xf20: ret = "(Altivec Unavailable)"; break;
1196 case 0x1300: ret = "(Instruction Breakpoint)"; break;
1197 default: ret = "";
1198 }
1199 return ret;
1200}
1201
1202static void get_function_bounds(unsigned long pc, unsigned long *startp,
1203 unsigned long *endp)
1204{
1205 unsigned long size, offset;
1206 const char *name;
1207 char *modname;
1208
1209 *startp = *endp = 0;
1210 if (pc == 0)
1211 return;
1212 if (setjmp(bus_error_jmp) == 0) {
1213 catch_memory_errors = 1;
1214 sync();
1215 name = kallsyms_lookup(pc, &size, &offset, &modname, tmpstr);
1216 if (name != NULL) {
1217 *startp = pc - offset;
1218 *endp = pc - offset + size;
1219 }
1220 sync();
1221 }
1222 catch_memory_errors = 0;
1223}
1224
1225static int xmon_depth_to_print = 64;
1226
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001227#ifdef CONFIG_PPC64
1228#define LRSAVE_OFFSET 0x10
1229#define REG_FRAME_MARKER 0x7265677368657265ul /* "regshere" */
1230#define MARKER_OFFSET 0x60
1231#define REGS_OFFSET 0x70
1232#else
1233#define LRSAVE_OFFSET 4
1234#define REG_FRAME_MARKER 0x72656773
1235#define MARKER_OFFSET 8
1236#define REGS_OFFSET 16
1237#endif
1238
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239static void xmon_show_stack(unsigned long sp, unsigned long lr,
1240 unsigned long pc)
1241{
1242 unsigned long ip;
1243 unsigned long newsp;
1244 unsigned long marker;
1245 int count = 0;
1246 struct pt_regs regs;
1247
1248 do {
1249 if (sp < PAGE_OFFSET) {
1250 if (sp != 0)
1251 printf("SP (%lx) is in userspace\n", sp);
1252 break;
1253 }
1254
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001255 if (!mread(sp + LRSAVE_OFFSET, &ip, sizeof(unsigned long))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 || !mread(sp, &newsp, sizeof(unsigned long))) {
1257 printf("Couldn't read stack frame at %lx\n", sp);
1258 break;
1259 }
1260
1261 /*
1262 * For the first stack frame, try to work out if
1263 * LR and/or the saved LR value in the bottommost
1264 * stack frame are valid.
1265 */
1266 if ((pc | lr) != 0) {
1267 unsigned long fnstart, fnend;
1268 unsigned long nextip;
1269 int printip = 1;
1270
1271 get_function_bounds(pc, &fnstart, &fnend);
1272 nextip = 0;
1273 if (newsp > sp)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001274 mread(newsp + LRSAVE_OFFSET, &nextip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275 sizeof(unsigned long));
1276 if (lr == ip) {
1277 if (lr < PAGE_OFFSET
1278 || (fnstart <= lr && lr < fnend))
1279 printip = 0;
1280 } else if (lr == nextip) {
1281 printip = 0;
1282 } else if (lr >= PAGE_OFFSET
1283 && !(fnstart <= lr && lr < fnend)) {
1284 printf("[link register ] ");
1285 xmon_print_symbol(lr, " ", "\n");
1286 }
1287 if (printip) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001288 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 xmon_print_symbol(ip, " ", " (unreliable)\n");
1290 }
1291 pc = lr = 0;
1292
1293 } else {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001294 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 xmon_print_symbol(ip, " ", "\n");
1296 }
1297
1298 /* Look for "regshere" marker to see if this is
1299 an exception frame. */
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001300 if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long))
1301 && marker == REG_FRAME_MARKER) {
1302 if (mread(sp + REGS_OFFSET, &regs, sizeof(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303 != sizeof(regs)) {
1304 printf("Couldn't read registers at %lx\n",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001305 sp + REGS_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 break;
1307 }
1308 printf("--- Exception: %lx %s at ", regs.trap,
1309 getvecname(TRAP(&regs)));
1310 pc = regs.nip;
1311 lr = regs.link;
1312 xmon_print_symbol(pc, " ", "\n");
1313 }
1314
1315 if (newsp == 0)
1316 break;
1317
1318 sp = newsp;
1319 } while (count++ < xmon_depth_to_print);
1320}
1321
1322static void backtrace(struct pt_regs *excp)
1323{
1324 unsigned long sp;
1325
1326 if (scanhex(&sp))
1327 xmon_show_stack(sp, 0, 0);
1328 else
1329 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
1330 scannl();
1331}
1332
1333static void print_bug_trap(struct pt_regs *regs)
1334{
1335 struct bug_entry *bug;
1336 unsigned long addr;
1337
1338 if (regs->msr & MSR_PR)
1339 return; /* not in kernel */
1340 addr = regs->nip; /* address of trap instruction */
1341 if (addr < PAGE_OFFSET)
1342 return;
1343 bug = find_bug(regs->nip);
1344 if (bug == NULL)
1345 return;
1346 if (bug->line & BUG_WARNING_TRAP)
1347 return;
1348
1349 printf("kernel BUG in %s at %s:%d!\n",
1350 bug->function, bug->file, (unsigned int)bug->line);
1351}
1352
1353void excprint(struct pt_regs *fp)
1354{
1355 unsigned long trap;
1356
1357#ifdef CONFIG_SMP
1358 printf("cpu 0x%x: ", smp_processor_id());
1359#endif /* CONFIG_SMP */
1360
1361 trap = TRAP(fp);
1362 printf("Vector: %lx %s at [%lx]\n", fp->trap, getvecname(trap), fp);
1363 printf(" pc: ");
1364 xmon_print_symbol(fp->nip, ": ", "\n");
1365
1366 printf(" lr: ", fp->link);
1367 xmon_print_symbol(fp->link, ": ", "\n");
1368
1369 printf(" sp: %lx\n", fp->gpr[1]);
1370 printf(" msr: %lx\n", fp->msr);
1371
1372 if (trap == 0x300 || trap == 0x380 || trap == 0x600) {
1373 printf(" dar: %lx\n", fp->dar);
1374 if (trap != 0x380)
1375 printf(" dsisr: %lx\n", fp->dsisr);
1376 }
1377
1378 printf(" current = 0x%lx\n", current);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001379#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 printf(" paca = 0x%lx\n", get_paca());
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001381#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 if (current) {
1383 printf(" pid = %ld, comm = %s\n",
1384 current->pid, current->comm);
1385 }
1386
1387 if (trap == 0x700)
1388 print_bug_trap(fp);
1389}
1390
1391void prregs(struct pt_regs *fp)
1392{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001393 int n, trap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 unsigned long base;
1395 struct pt_regs regs;
1396
1397 if (scanhex(&base)) {
1398 if (setjmp(bus_error_jmp) == 0) {
1399 catch_memory_errors = 1;
1400 sync();
1401 regs = *(struct pt_regs *)base;
1402 sync();
1403 __delay(200);
1404 } else {
1405 catch_memory_errors = 0;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001406 printf("*** Error reading registers from "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 base);
1408 return;
1409 }
1410 catch_memory_errors = 0;
1411 fp = &regs;
1412 }
1413
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001414#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415 if (FULL_REGS(fp)) {
1416 for (n = 0; n < 16; ++n)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001417 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418 n, fp->gpr[n], n+16, fp->gpr[n+16]);
1419 } else {
1420 for (n = 0; n < 7; ++n)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001421 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 n, fp->gpr[n], n+7, fp->gpr[n+7]);
1423 }
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001424#else
1425 for (n = 0; n < 32; ++n) {
1426 printf("R%.2d = %.8x%s", n, fp->gpr[n],
1427 (n & 3) == 3? "\n": " ");
1428 if (n == 12 && !FULL_REGS(fp)) {
1429 printf("\n");
1430 break;
1431 }
1432 }
1433#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434 printf("pc = ");
1435 xmon_print_symbol(fp->nip, " ", "\n");
1436 printf("lr = ");
1437 xmon_print_symbol(fp->link, " ", "\n");
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001438 printf("msr = "REG" cr = %.8lx\n", fp->msr, fp->ccr);
1439 printf("ctr = "REG" xer = "REG" trap = %4lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440 fp->ctr, fp->xer, fp->trap);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001441 trap = TRAP(fp);
1442 if (trap == 0x300 || trap == 0x380 || trap == 0x600)
1443 printf("dar = "REG" dsisr = %.8lx\n", fp->dar, fp->dsisr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444}
1445
1446void cacheflush(void)
1447{
1448 int cmd;
1449 unsigned long nflush;
1450
1451 cmd = inchar();
1452 if (cmd != 'i')
1453 termch = cmd;
1454 scanhex((void *)&adrs);
1455 if (termch != '\n')
1456 termch = 0;
1457 nflush = 1;
1458 scanhex(&nflush);
1459 nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES;
1460 if (setjmp(bus_error_jmp) == 0) {
1461 catch_memory_errors = 1;
1462 sync();
1463
1464 if (cmd != 'i') {
1465 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1466 cflush((void *) adrs);
1467 } else {
1468 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1469 cinval((void *) adrs);
1470 }
1471 sync();
1472 /* wait a little while to see if we get a machine check */
1473 __delay(200);
1474 }
1475 catch_memory_errors = 0;
1476}
1477
1478unsigned long
1479read_spr(int n)
1480{
1481 unsigned int instrs[2];
1482 unsigned long (*code)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 unsigned long ret = -1UL;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001484#ifdef CONFIG_PPC64
1485 unsigned long opd[3];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487 opd[0] = (unsigned long)instrs;
1488 opd[1] = 0;
1489 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001490 code = (unsigned long (*)(void)) opd;
1491#else
1492 code = (unsigned long (*)(void)) instrs;
1493#endif
1494
1495 /* mfspr r3,n; blr */
1496 instrs[0] = 0x7c6002a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1497 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 store_inst(instrs);
1499 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500
1501 if (setjmp(bus_error_jmp) == 0) {
1502 catch_memory_errors = 1;
1503 sync();
1504
1505 ret = code();
1506
1507 sync();
1508 /* wait a little while to see if we get a machine check */
1509 __delay(200);
1510 n = size;
1511 }
1512
1513 return ret;
1514}
1515
1516void
1517write_spr(int n, unsigned long val)
1518{
1519 unsigned int instrs[2];
1520 unsigned long (*code)(unsigned long);
Paul Mackerras548cceb2005-11-11 22:36:34 +11001521#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 unsigned long opd[3];
1523
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 opd[0] = (unsigned long)instrs;
1525 opd[1] = 0;
1526 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001527 code = (unsigned long (*)(unsigned long)) opd;
1528#else
1529 code = (unsigned long (*)(unsigned long)) instrs;
1530#endif
1531
1532 instrs[0] = 0x7c6003a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1533 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 store_inst(instrs);
1535 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536
1537 if (setjmp(bus_error_jmp) == 0) {
1538 catch_memory_errors = 1;
1539 sync();
1540
1541 code(val);
1542
1543 sync();
1544 /* wait a little while to see if we get a machine check */
1545 __delay(200);
1546 n = size;
1547 }
1548}
1549
1550static unsigned long regno;
1551extern char exc_prolog;
1552extern char dec_exc;
1553
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001554void super_regs(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555{
1556 int cmd;
1557 unsigned long val;
1558#ifdef CONFIG_PPC_ISERIES
1559 struct paca_struct *ptrPaca = NULL;
1560 struct lppaca *ptrLpPaca = NULL;
1561 struct ItLpRegSave *ptrLpRegSave = NULL;
1562#endif
1563
1564 cmd = skipbl();
1565 if (cmd == '\n') {
1566 unsigned long sp, toc;
1567 asm("mr %0,1" : "=r" (sp) :);
1568 asm("mr %0,2" : "=r" (toc) :);
1569
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001570 printf("msr = "REG" sprg0= "REG"\n",
1571 mfmsr(), mfspr(SPRN_SPRG0));
1572 printf("pvr = "REG" sprg1= "REG"\n",
1573 mfspr(SPRN_PVR), mfspr(SPRN_SPRG1));
1574 printf("dec = "REG" sprg2= "REG"\n",
1575 mfspr(SPRN_DEC), mfspr(SPRN_SPRG2));
1576 printf("sp = "REG" sprg3= "REG"\n", sp, mfspr(SPRN_SPRG3));
1577 printf("toc = "REG" dar = "REG"\n", toc, mfspr(SPRN_DAR));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578#ifdef CONFIG_PPC_ISERIES
1579 // Dump out relevant Paca data areas.
1580 printf("Paca: \n");
1581 ptrPaca = get_paca();
1582
1583 printf(" Local Processor Control Area (LpPaca): \n");
1584 ptrLpPaca = ptrPaca->lppaca_ptr;
1585 printf(" Saved Srr0=%.16lx Saved Srr1=%.16lx \n",
1586 ptrLpPaca->saved_srr0, ptrLpPaca->saved_srr1);
1587 printf(" Saved Gpr3=%.16lx Saved Gpr4=%.16lx \n",
1588 ptrLpPaca->saved_gpr3, ptrLpPaca->saved_gpr4);
1589 printf(" Saved Gpr5=%.16lx \n", ptrLpPaca->saved_gpr5);
1590
1591 printf(" Local Processor Register Save Area (LpRegSave): \n");
1592 ptrLpRegSave = ptrPaca->reg_save_ptr;
1593 printf(" Saved Sprg0=%.16lx Saved Sprg1=%.16lx \n",
1594 ptrLpRegSave->xSPRG0, ptrLpRegSave->xSPRG0);
1595 printf(" Saved Sprg2=%.16lx Saved Sprg3=%.16lx \n",
1596 ptrLpRegSave->xSPRG2, ptrLpRegSave->xSPRG3);
1597 printf(" Saved Msr =%.16lx Saved Nia =%.16lx \n",
1598 ptrLpRegSave->xMSR, ptrLpRegSave->xNIA);
1599#endif
1600
1601 return;
1602 }
1603
1604 scanhex(&regno);
1605 switch (cmd) {
1606 case 'w':
1607 val = read_spr(regno);
1608 scanhex(&val);
1609 write_spr(regno, val);
1610 /* fall through */
1611 case 'r':
1612 printf("spr %lx = %lx\n", regno, read_spr(regno));
1613 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614 }
1615 scannl();
1616}
1617
1618/*
1619 * Stuff for reading and writing memory safely
1620 */
1621int
1622mread(unsigned long adrs, void *buf, int size)
1623{
1624 volatile int n;
1625 char *p, *q;
1626
1627 n = 0;
1628 if (setjmp(bus_error_jmp) == 0) {
1629 catch_memory_errors = 1;
1630 sync();
1631 p = (char *)adrs;
1632 q = (char *)buf;
1633 switch (size) {
1634 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001635 *(u16 *)q = *(u16 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636 break;
1637 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001638 *(u32 *)q = *(u32 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 break;
1640 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001641 *(u64 *)q = *(u64 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 break;
1643 default:
1644 for( ; n < size; ++n) {
1645 *q++ = *p++;
1646 sync();
1647 }
1648 }
1649 sync();
1650 /* wait a little while to see if we get a machine check */
1651 __delay(200);
1652 n = size;
1653 }
1654 catch_memory_errors = 0;
1655 return n;
1656}
1657
1658int
1659mwrite(unsigned long adrs, void *buf, int size)
1660{
1661 volatile int n;
1662 char *p, *q;
1663
1664 n = 0;
1665 if (setjmp(bus_error_jmp) == 0) {
1666 catch_memory_errors = 1;
1667 sync();
1668 p = (char *) adrs;
1669 q = (char *) buf;
1670 switch (size) {
1671 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001672 *(u16 *)p = *(u16 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 break;
1674 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001675 *(u32 *)p = *(u32 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676 break;
1677 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001678 *(u64 *)p = *(u64 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679 break;
1680 default:
1681 for ( ; n < size; ++n) {
1682 *p++ = *q++;
1683 sync();
1684 }
1685 }
1686 sync();
1687 /* wait a little while to see if we get a machine check */
1688 __delay(200);
1689 n = size;
1690 } else {
1691 printf("*** Error writing address %x\n", adrs + n);
1692 }
1693 catch_memory_errors = 0;
1694 return n;
1695}
1696
1697static int fault_type;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001698static int fault_except;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699static char *fault_chars[] = { "--", "**", "##" };
1700
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001701static int handle_fault(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001703 fault_except = TRAP(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 switch (TRAP(regs)) {
1705 case 0x200:
1706 fault_type = 0;
1707 break;
1708 case 0x300:
1709 case 0x380:
1710 fault_type = 1;
1711 break;
1712 default:
1713 fault_type = 2;
1714 }
1715
1716 longjmp(bus_error_jmp, 1);
1717
1718 return 0;
1719}
1720
1721#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t))
1722
1723void
1724byterev(unsigned char *val, int size)
1725{
1726 int t;
1727
1728 switch (size) {
1729 case 2:
1730 SWAP(val[0], val[1], t);
1731 break;
1732 case 4:
1733 SWAP(val[0], val[3], t);
1734 SWAP(val[1], val[2], t);
1735 break;
1736 case 8: /* is there really any use for this? */
1737 SWAP(val[0], val[7], t);
1738 SWAP(val[1], val[6], t);
1739 SWAP(val[2], val[5], t);
1740 SWAP(val[3], val[4], t);
1741 break;
1742 }
1743}
1744
1745static int brev;
1746static int mnoread;
1747
1748static char *memex_help_string =
1749 "Memory examine command usage:\n"
1750 "m [addr] [flags] examine/change memory\n"
1751 " addr is optional. will start where left off.\n"
1752 " flags may include chars from this set:\n"
1753 " b modify by bytes (default)\n"
1754 " w modify by words (2 byte)\n"
1755 " l modify by longs (4 byte)\n"
1756 " d modify by doubleword (8 byte)\n"
1757 " r toggle reverse byte order mode\n"
1758 " n do not read memory (for i/o spaces)\n"
1759 " . ok to read (default)\n"
1760 "NOTE: flags are saved as defaults\n"
1761 "";
1762
1763static char *memex_subcmd_help_string =
1764 "Memory examine subcommands:\n"
1765 " hexval write this val to current location\n"
1766 " 'string' write chars from string to this location\n"
1767 " ' increment address\n"
1768 " ^ decrement address\n"
1769 " / increment addr by 0x10. //=0x100, ///=0x1000, etc\n"
1770 " \\ decrement addr by 0x10. \\\\=0x100, \\\\\\=0x1000, etc\n"
1771 " ` clear no-read flag\n"
1772 " ; stay at this addr\n"
1773 " v change to byte mode\n"
1774 " w change to word (2 byte) mode\n"
1775 " l change to long (4 byte) mode\n"
1776 " u change to doubleword (8 byte) mode\n"
1777 " m addr change current addr\n"
1778 " n toggle no-read flag\n"
1779 " r toggle byte reverse flag\n"
1780 " < count back up count bytes\n"
1781 " > count skip forward count bytes\n"
1782 " x exit this mode\n"
1783 "";
1784
1785void
1786memex(void)
1787{
1788 int cmd, inc, i, nslash;
1789 unsigned long n;
1790 unsigned char val[16];
1791
1792 scanhex((void *)&adrs);
1793 cmd = skipbl();
1794 if (cmd == '?') {
1795 printf(memex_help_string);
1796 return;
1797 } else {
1798 termch = cmd;
1799 }
1800 last_cmd = "m\n";
1801 while ((cmd = skipbl()) != '\n') {
1802 switch( cmd ){
1803 case 'b': size = 1; break;
1804 case 'w': size = 2; break;
1805 case 'l': size = 4; break;
1806 case 'd': size = 8; break;
1807 case 'r': brev = !brev; break;
1808 case 'n': mnoread = 1; break;
1809 case '.': mnoread = 0; break;
1810 }
1811 }
1812 if( size <= 0 )
1813 size = 1;
1814 else if( size > 8 )
1815 size = 8;
1816 for(;;){
1817 if (!mnoread)
1818 n = mread(adrs, val, size);
Paul Mackerrase1449ed2005-11-10 14:30:20 +11001819 printf(REG"%c", adrs, brev? 'r': ' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820 if (!mnoread) {
1821 if (brev)
1822 byterev(val, size);
1823 putchar(' ');
1824 for (i = 0; i < n; ++i)
1825 printf("%.2x", val[i]);
1826 for (; i < size; ++i)
1827 printf("%s", fault_chars[fault_type]);
1828 }
1829 putchar(' ');
1830 inc = size;
1831 nslash = 0;
1832 for(;;){
1833 if( scanhex(&n) ){
1834 for (i = 0; i < size; ++i)
1835 val[i] = n >> (i * 8);
1836 if (!brev)
1837 byterev(val, size);
1838 mwrite(adrs, val, size);
1839 inc = size;
1840 }
1841 cmd = skipbl();
1842 if (cmd == '\n')
1843 break;
1844 inc = 0;
1845 switch (cmd) {
1846 case '\'':
1847 for(;;){
1848 n = inchar();
1849 if( n == '\\' )
1850 n = bsesc();
1851 else if( n == '\'' )
1852 break;
1853 for (i = 0; i < size; ++i)
1854 val[i] = n >> (i * 8);
1855 if (!brev)
1856 byterev(val, size);
1857 mwrite(adrs, val, size);
1858 adrs += size;
1859 }
1860 adrs -= size;
1861 inc = size;
1862 break;
1863 case ',':
1864 adrs += size;
1865 break;
1866 case '.':
1867 mnoread = 0;
1868 break;
1869 case ';':
1870 break;
1871 case 'x':
1872 case EOF:
1873 scannl();
1874 return;
1875 case 'b':
1876 case 'v':
1877 size = 1;
1878 break;
1879 case 'w':
1880 size = 2;
1881 break;
1882 case 'l':
1883 size = 4;
1884 break;
1885 case 'u':
1886 size = 8;
1887 break;
1888 case '^':
1889 adrs -= size;
1890 break;
1891 break;
1892 case '/':
1893 if (nslash > 0)
1894 adrs -= 1 << nslash;
1895 else
1896 nslash = 0;
1897 nslash += 4;
1898 adrs += 1 << nslash;
1899 break;
1900 case '\\':
1901 if (nslash < 0)
1902 adrs += 1 << -nslash;
1903 else
1904 nslash = 0;
1905 nslash -= 4;
1906 adrs -= 1 << -nslash;
1907 break;
1908 case 'm':
1909 scanhex((void *)&adrs);
1910 break;
1911 case 'n':
1912 mnoread = 1;
1913 break;
1914 case 'r':
1915 brev = !brev;
1916 break;
1917 case '<':
1918 n = size;
1919 scanhex(&n);
1920 adrs -= n;
1921 break;
1922 case '>':
1923 n = size;
1924 scanhex(&n);
1925 adrs += n;
1926 break;
1927 case '?':
1928 printf(memex_subcmd_help_string);
1929 break;
1930 }
1931 }
1932 adrs += inc;
1933 }
1934}
1935
1936int
1937bsesc(void)
1938{
1939 int c;
1940
1941 c = inchar();
1942 switch( c ){
1943 case 'n': c = '\n'; break;
1944 case 'r': c = '\r'; break;
1945 case 'b': c = '\b'; break;
1946 case 't': c = '\t'; break;
1947 }
1948 return c;
1949}
1950
Olaf Hering7e5b5932006-03-08 20:40:28 +01001951static void xmon_rawdump (unsigned long adrs, long ndump)
1952{
1953 long n, m, r, nr;
1954 unsigned char temp[16];
1955
1956 for (n = ndump; n > 0;) {
1957 r = n < 16? n: 16;
1958 nr = mread(adrs, temp, r);
1959 adrs += nr;
1960 for (m = 0; m < r; ++m) {
1961 if (m < nr)
1962 printf("%.2x", temp[m]);
1963 else
1964 printf("%s", fault_chars[fault_type]);
1965 }
1966 n -= r;
1967 if (nr < r)
1968 break;
1969 }
1970 printf("\n");
1971}
1972
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
1974 || ('a' <= (c) && (c) <= 'f') \
1975 || ('A' <= (c) && (c) <= 'F'))
1976void
1977dump(void)
1978{
1979 int c;
1980
1981 c = inchar();
1982 if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
1983 termch = c;
1984 scanhex((void *)&adrs);
1985 if (termch != '\n')
1986 termch = 0;
1987 if (c == 'i') {
1988 scanhex(&nidump);
1989 if (nidump == 0)
1990 nidump = 16;
1991 else if (nidump > MAX_DUMP)
1992 nidump = MAX_DUMP;
1993 adrs += ppc_inst_dump(adrs, nidump, 1);
1994 last_cmd = "di\n";
Olaf Hering7e5b5932006-03-08 20:40:28 +01001995 } else if (c == 'r') {
1996 scanhex(&ndump);
1997 if (ndump == 0)
1998 ndump = 64;
1999 xmon_rawdump(adrs, ndump);
2000 adrs += ndump;
2001 last_cmd = "dr\n";
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002 } else {
2003 scanhex(&ndump);
2004 if (ndump == 0)
2005 ndump = 64;
2006 else if (ndump > MAX_DUMP)
2007 ndump = MAX_DUMP;
2008 prdump(adrs, ndump);
2009 adrs += ndump;
2010 last_cmd = "d\n";
2011 }
2012}
2013
2014void
2015prdump(unsigned long adrs, long ndump)
2016{
2017 long n, m, c, r, nr;
2018 unsigned char temp[16];
2019
2020 for (n = ndump; n > 0;) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002021 printf(REG, adrs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022 putchar(' ');
2023 r = n < 16? n: 16;
2024 nr = mread(adrs, temp, r);
2025 adrs += nr;
2026 for (m = 0; m < r; ++m) {
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002027 if ((m & (sizeof(long) - 1)) == 0 && m > 0)
2028 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 if (m < nr)
2030 printf("%.2x", temp[m]);
2031 else
2032 printf("%s", fault_chars[fault_type]);
2033 }
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002034 for (; m < 16; ++m) {
2035 if ((m & (sizeof(long) - 1)) == 0)
2036 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037 printf(" ");
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002038 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039 printf(" |");
2040 for (m = 0; m < r; ++m) {
2041 if (m < nr) {
2042 c = temp[m];
2043 putchar(' ' <= c && c <= '~'? c: '.');
2044 } else
2045 putchar(' ');
2046 }
2047 n -= r;
2048 for (; m < 16; ++m)
2049 putchar(' ');
2050 printf("|\n");
2051 if (nr < r)
2052 break;
2053 }
2054}
2055
2056int
2057ppc_inst_dump(unsigned long adr, long count, int praddr)
2058{
2059 int nr, dotted;
2060 unsigned long first_adr;
2061 unsigned long inst, last_inst = 0;
2062 unsigned char val[4];
2063
2064 dotted = 0;
2065 for (first_adr = adr; count > 0; --count, adr += 4) {
2066 nr = mread(adr, val, 4);
2067 if (nr == 0) {
2068 if (praddr) {
2069 const char *x = fault_chars[fault_type];
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002070 printf(REG" %s%s%s%s\n", adr, x, x, x, x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071 }
2072 break;
2073 }
2074 inst = GETWORD(val);
2075 if (adr > first_adr && inst == last_inst) {
2076 if (!dotted) {
2077 printf(" ...\n");
2078 dotted = 1;
2079 }
2080 continue;
2081 }
2082 dotted = 0;
2083 last_inst = inst;
2084 if (praddr)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002085 printf(REG" %.8x", adr, inst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086 printf("\t");
2087 print_insn_powerpc(inst, adr, 0); /* always returns 4 */
2088 printf("\n");
2089 }
2090 return adr - first_adr;
2091}
2092
2093void
2094print_address(unsigned long addr)
2095{
2096 xmon_print_symbol(addr, "\t# ", "");
2097}
2098
2099
2100/*
2101 * Memory operations - move, set, print differences
2102 */
2103static unsigned long mdest; /* destination address */
2104static unsigned long msrc; /* source address */
2105static unsigned long mval; /* byte value to set memory to */
2106static unsigned long mcount; /* # bytes to affect */
2107static unsigned long mdiffs; /* max # differences to print */
2108
2109void
2110memops(int cmd)
2111{
2112 scanhex((void *)&mdest);
2113 if( termch != '\n' )
2114 termch = 0;
2115 scanhex((void *)(cmd == 's'? &mval: &msrc));
2116 if( termch != '\n' )
2117 termch = 0;
2118 scanhex((void *)&mcount);
2119 switch( cmd ){
2120 case 'm':
2121 memmove((void *)mdest, (void *)msrc, mcount);
2122 break;
2123 case 's':
2124 memset((void *)mdest, mval, mcount);
2125 break;
2126 case 'd':
2127 if( termch != '\n' )
2128 termch = 0;
2129 scanhex((void *)&mdiffs);
2130 memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
2131 break;
2132 }
2133}
2134
2135void
2136memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
2137{
2138 unsigned n, prt;
2139
2140 prt = 0;
2141 for( n = nb; n > 0; --n )
2142 if( *p1++ != *p2++ )
2143 if( ++prt <= maxpr )
2144 printf("%.16x %.2x # %.16x %.2x\n", p1 - 1,
2145 p1[-1], p2 - 1, p2[-1]);
2146 if( prt > maxpr )
2147 printf("Total of %d differences\n", prt);
2148}
2149
2150static unsigned mend;
2151static unsigned mask;
2152
2153void
2154memlocate(void)
2155{
2156 unsigned a, n;
2157 unsigned char val[4];
2158
2159 last_cmd = "ml";
2160 scanhex((void *)&mdest);
2161 if (termch != '\n') {
2162 termch = 0;
2163 scanhex((void *)&mend);
2164 if (termch != '\n') {
2165 termch = 0;
2166 scanhex((void *)&mval);
2167 mask = ~0;
2168 if (termch != '\n') termch = 0;
2169 scanhex((void *)&mask);
2170 }
2171 }
2172 n = 0;
2173 for (a = mdest; a < mend; a += 4) {
2174 if (mread(a, val, 4) == 4
2175 && ((GETWORD(val) ^ mval) & mask) == 0) {
2176 printf("%.16x: %.16x\n", a, GETWORD(val));
2177 if (++n >= 10)
2178 break;
2179 }
2180 }
2181}
2182
2183static unsigned long mskip = 0x1000;
2184static unsigned long mlim = 0xffffffff;
2185
2186void
2187memzcan(void)
2188{
2189 unsigned char v;
2190 unsigned a;
2191 int ok, ook;
2192
2193 scanhex(&mdest);
2194 if (termch != '\n') termch = 0;
2195 scanhex(&mskip);
2196 if (termch != '\n') termch = 0;
2197 scanhex(&mlim);
2198 ook = 0;
2199 for (a = mdest; a < mlim; a += mskip) {
2200 ok = mread(a, &v, 1);
2201 if (ok && !ook) {
2202 printf("%.8x .. ", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203 } else if (!ok && ook)
2204 printf("%.8x\n", a - mskip);
2205 ook = ok;
2206 if (a + mskip < a)
2207 break;
2208 }
2209 if (ook)
2210 printf("%.8x\n", a - mskip);
2211}
2212
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002213void proccall(void)
2214{
2215 unsigned long args[8];
2216 unsigned long ret;
2217 int i;
2218 typedef unsigned long (*callfunc_t)(unsigned long, unsigned long,
2219 unsigned long, unsigned long, unsigned long,
2220 unsigned long, unsigned long, unsigned long);
2221 callfunc_t func;
2222
2223 if (!scanhex(&adrs))
2224 return;
2225 if (termch != '\n')
2226 termch = 0;
2227 for (i = 0; i < 8; ++i)
2228 args[i] = 0;
2229 for (i = 0; i < 8; ++i) {
2230 if (!scanhex(&args[i]) || termch == '\n')
2231 break;
2232 termch = 0;
2233 }
2234 func = (callfunc_t) adrs;
2235 ret = 0;
2236 if (setjmp(bus_error_jmp) == 0) {
2237 catch_memory_errors = 1;
2238 sync();
2239 ret = func(args[0], args[1], args[2], args[3],
2240 args[4], args[5], args[6], args[7]);
2241 sync();
2242 printf("return value is %x\n", ret);
2243 } else {
2244 printf("*** %x exception occurred\n", fault_except);
2245 }
2246 catch_memory_errors = 0;
2247}
2248
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249/* Input scanning routines */
2250int
2251skipbl(void)
2252{
2253 int c;
2254
2255 if( termch != 0 ){
2256 c = termch;
2257 termch = 0;
2258 } else
2259 c = inchar();
2260 while( c == ' ' || c == '\t' )
2261 c = inchar();
2262 return c;
2263}
2264
2265#define N_PTREGS 44
2266static char *regnames[N_PTREGS] = {
2267 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
2268 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
2269 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
2270 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002271 "pc", "msr", "or3", "ctr", "lr", "xer", "ccr",
2272#ifdef CONFIG_PPC64
2273 "softe",
2274#else
2275 "mq",
2276#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002277 "trap", "dar", "dsisr", "res"
2278};
2279
2280int
2281scanhex(unsigned long *vp)
2282{
2283 int c, d;
2284 unsigned long v;
2285
2286 c = skipbl();
2287 if (c == '%') {
2288 /* parse register name */
2289 char regname[8];
2290 int i;
2291
2292 for (i = 0; i < sizeof(regname) - 1; ++i) {
2293 c = inchar();
2294 if (!isalnum(c)) {
2295 termch = c;
2296 break;
2297 }
2298 regname[i] = c;
2299 }
2300 regname[i] = 0;
2301 for (i = 0; i < N_PTREGS; ++i) {
2302 if (strcmp(regnames[i], regname) == 0) {
2303 if (xmon_regs == NULL) {
2304 printf("regs not available\n");
2305 return 0;
2306 }
2307 *vp = ((unsigned long *)xmon_regs)[i];
2308 return 1;
2309 }
2310 }
2311 printf("invalid register name '%%%s'\n", regname);
2312 return 0;
2313 }
2314
2315 /* skip leading "0x" if any */
2316
2317 if (c == '0') {
2318 c = inchar();
2319 if (c == 'x') {
2320 c = inchar();
2321 } else {
2322 d = hexdigit(c);
2323 if (d == EOF) {
2324 termch = c;
2325 *vp = 0;
2326 return 1;
2327 }
2328 }
2329 } else if (c == '$') {
2330 int i;
2331 for (i=0; i<63; i++) {
2332 c = inchar();
2333 if (isspace(c)) {
2334 termch = c;
2335 break;
2336 }
2337 tmpstr[i] = c;
2338 }
2339 tmpstr[i++] = 0;
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07002340 *vp = 0;
2341 if (setjmp(bus_error_jmp) == 0) {
2342 catch_memory_errors = 1;
2343 sync();
2344 *vp = kallsyms_lookup_name(tmpstr);
2345 sync();
2346 }
2347 catch_memory_errors = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348 if (!(*vp)) {
2349 printf("unknown symbol '%s'\n", tmpstr);
2350 return 0;
2351 }
2352 return 1;
2353 }
2354
2355 d = hexdigit(c);
2356 if (d == EOF) {
2357 termch = c;
2358 return 0;
2359 }
2360 v = 0;
2361 do {
2362 v = (v << 4) + d;
2363 c = inchar();
2364 d = hexdigit(c);
2365 } while (d != EOF);
2366 termch = c;
2367 *vp = v;
2368 return 1;
2369}
2370
2371void
2372scannl(void)
2373{
2374 int c;
2375
2376 c = termch;
2377 termch = 0;
2378 while( c != '\n' )
2379 c = inchar();
2380}
2381
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002382int hexdigit(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383{
2384 if( '0' <= c && c <= '9' )
2385 return c - '0';
2386 if( 'A' <= c && c <= 'F' )
2387 return c - ('A' - 10);
2388 if( 'a' <= c && c <= 'f' )
2389 return c - ('a' - 10);
2390 return EOF;
2391}
2392
2393void
2394getstring(char *s, int size)
2395{
2396 int c;
2397
2398 c = skipbl();
2399 do {
2400 if( size > 1 ){
2401 *s++ = c;
2402 --size;
2403 }
2404 c = inchar();
2405 } while( c != ' ' && c != '\t' && c != '\n' );
2406 termch = c;
2407 *s = 0;
2408}
2409
2410static char line[256];
2411static char *lineptr;
2412
2413void
2414flush_input(void)
2415{
2416 lineptr = NULL;
2417}
2418
2419int
2420inchar(void)
2421{
2422 if (lineptr == NULL || *lineptr == 0) {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002423 if (xmon_gets(line, sizeof(line)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424 lineptr = NULL;
2425 return EOF;
2426 }
2427 lineptr = line;
2428 }
2429 return *lineptr++;
2430}
2431
2432void
2433take_input(char *str)
2434{
2435 lineptr = str;
2436}
2437
2438
2439static void
2440symbol_lookup(void)
2441{
2442 int type = inchar();
2443 unsigned long addr;
2444 static char tmp[64];
2445
2446 switch (type) {
2447 case 'a':
2448 if (scanhex(&addr))
2449 xmon_print_symbol(addr, ": ", "\n");
2450 termch = 0;
2451 break;
2452 case 's':
2453 getstring(tmp, 64);
2454 if (setjmp(bus_error_jmp) == 0) {
2455 catch_memory_errors = 1;
2456 sync();
2457 addr = kallsyms_lookup_name(tmp);
2458 if (addr)
2459 printf("%s: %lx\n", tmp, addr);
2460 else
2461 printf("Symbol '%s' not found.\n", tmp);
2462 sync();
2463 }
2464 catch_memory_errors = 0;
2465 termch = 0;
2466 break;
2467 }
2468}
2469
2470
2471/* Print an address in numeric and symbolic form (if possible) */
2472static void xmon_print_symbol(unsigned long address, const char *mid,
2473 const char *after)
2474{
2475 char *modname;
2476 const char *name = NULL;
2477 unsigned long offset, size;
2478
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002479 printf(REG, address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480 if (setjmp(bus_error_jmp) == 0) {
2481 catch_memory_errors = 1;
2482 sync();
2483 name = kallsyms_lookup(address, &size, &offset, &modname,
2484 tmpstr);
2485 sync();
2486 /* wait a little while to see if we get a machine check */
2487 __delay(200);
2488 }
2489
2490 catch_memory_errors = 0;
2491
2492 if (name) {
2493 printf("%s%s+%#lx/%#lx", mid, name, offset, size);
2494 if (modname)
2495 printf(" [%s]", modname);
2496 }
2497 printf("%s", after);
2498}
2499
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002500#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501static void dump_slb(void)
2502{
2503 int i;
2504 unsigned long tmp;
2505
2506 printf("SLB contents of cpu %x\n", smp_processor_id());
2507
2508 for (i = 0; i < SLB_NUM_ENTRIES; i++) {
2509 asm volatile("slbmfee %0,%1" : "=r" (tmp) : "r" (i));
2510 printf("%02d %016lx ", i, tmp);
2511
2512 asm volatile("slbmfev %0,%1" : "=r" (tmp) : "r" (i));
2513 printf("%016lx\n", tmp);
2514 }
2515}
2516
2517static void dump_stab(void)
2518{
2519 int i;
2520 unsigned long *tmp = (unsigned long *)get_paca()->stab_addr;
2521
2522 printf("Segment table contents of cpu %x\n", smp_processor_id());
2523
2524 for (i = 0; i < PAGE_SIZE/16; i++) {
2525 unsigned long a, b;
2526
2527 a = *tmp++;
2528 b = *tmp++;
2529
2530 if (a || b) {
2531 printf("%03d %016lx ", i, a);
2532 printf("%016lx\n", b);
2533 }
2534 }
2535}
2536
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002537void dump_segments(void)
2538{
2539 if (cpu_has_feature(CPU_FTR_SLB))
2540 dump_slb();
2541 else
2542 dump_stab();
2543}
2544#endif
2545
2546#ifdef CONFIG_PPC_STD_MMU_32
2547void dump_segments(void)
2548{
2549 int i;
2550
2551 printf("sr0-15 =");
2552 for (i = 0; i < 16; ++i)
2553 printf(" %x", mfsrin(i));
2554 printf("\n");
2555}
2556#endif
2557
Olaf Heringb13cfd172005-08-04 19:26:42 +02002558void xmon_init(int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559{
Olaf Heringb13cfd172005-08-04 19:26:42 +02002560 if (enable) {
2561 __debugger = xmon;
2562 __debugger_ipi = xmon_ipi;
2563 __debugger_bpt = xmon_bpt;
2564 __debugger_sstep = xmon_sstep;
2565 __debugger_iabr_match = xmon_iabr_match;
2566 __debugger_dabr_match = xmon_dabr_match;
2567 __debugger_fault_handler = xmon_fault_handler;
2568 } else {
2569 __debugger = NULL;
2570 __debugger_ipi = NULL;
2571 __debugger_bpt = NULL;
2572 __debugger_sstep = NULL;
2573 __debugger_iabr_match = NULL;
2574 __debugger_dabr_match = NULL;
2575 __debugger_fault_handler = NULL;
2576 }
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002577 xmon_map_scc();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578}
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002579
2580#ifdef CONFIG_MAGIC_SYSRQ
David Howells7d12e782006-10-05 14:55:46 +01002581static void sysrq_handle_xmon(int key, struct tty_struct *tty)
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002582{
2583 /* ensure xmon is enabled */
2584 xmon_init(1);
David Howells7d12e782006-10-05 14:55:46 +01002585 debugger(get_irq_regs());
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002586}
2587
2588static struct sysrq_key_op sysrq_xmon_op =
2589{
2590 .handler = sysrq_handle_xmon,
2591 .help_msg = "Xmon",
2592 .action_msg = "Entering xmon",
2593};
2594
2595static int __init setup_xmon_sysrq(void)
2596{
2597 register_sysrq_key('x', &sysrq_xmon_op);
2598 return 0;
2599}
2600__initcall(setup_xmon_sysrq);
2601#endif /* CONFIG_MAGIC_SYSRQ */
Michael Ellerman476792832006-10-03 14:12:08 +10002602
2603int __initdata xmon_early, xmon_off;
2604
2605static int __init early_parse_xmon(char *p)
2606{
2607 if (!p || strncmp(p, "early", 5) == 0) {
2608 /* just "xmon" is equivalent to "xmon=early" */
2609 xmon_init(1);
2610 xmon_early = 1;
2611 } else if (strncmp(p, "on", 2) == 0)
2612 xmon_init(1);
2613 else if (strncmp(p, "off", 3) == 0)
2614 xmon_off = 1;
2615 else if (strncmp(p, "nobt", 4) == 0)
2616 xmon_no_auto_backtrace = 1;
2617 else
2618 return 1;
2619
2620 return 0;
2621}
2622early_param("xmon", early_parse_xmon);
2623
2624void __init xmon_setup(void)
2625{
2626#ifdef CONFIG_XMON_DEFAULT
2627 if (!xmon_off)
2628 xmon_init(1);
2629#endif
2630 if (xmon_early)
2631 debugger(NULL);
2632}