blob: 6a2ed8b319f04edda1837fd3f5d59bb3c324b3a0 [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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-10-28 22:53:37 +100042
43#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#include <asm/hvcall.h>
Paul Mackerrasf78541d2005-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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-10-28 22:53:37 +1000157
158extern void xmon_enter(void);
159extern void xmon_leave(void);
160
Paul Mackerrasf78541d2005-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 Mackerrasf78541d2005-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\
219 sr restore execution on stopped spus\n"
220#endif
221" S print special registers\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 t print backtrace\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 x exit monitor and recover\n\
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000224 X exit monitor and dont recover\n"
225#ifdef CONFIG_PPC64
226" u dump segment table or SLB\n"
227#endif
228#ifdef CONFIG_PPC_STD_MMU_32
229" u dump segment registers\n"
230#endif
231" ? help\n"
232" zr reboot\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233 zh halt\n"
234;
235
236static struct pt_regs *xmon_regs;
237
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000238static inline void sync(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239{
240 asm volatile("sync; isync");
241}
242
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000243static inline void store_inst(void *p)
244{
245 asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p));
246}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000248static inline void cflush(void *p)
249{
250 asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p));
251}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000253static inline void cinval(void *p)
254{
255 asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p));
256}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257
258/*
259 * Disable surveillance (the service processor watchdog function)
260 * while we are in xmon.
261 * XXX we should re-enable it when we leave. :)
262 */
263#define SURVEILLANCE_TOKEN 9000
264
265static inline void disable_surveillance(void)
266{
267#ifdef CONFIG_PPC_PSERIES
268 /* Since this can't be a module, args should end up below 4GB. */
269 static struct rtas_args args;
270
271 /*
272 * At this point we have got all the cpus we can into
273 * xmon, so there is hopefully no other cpu calling RTAS
274 * at the moment, even though we don't take rtas.lock.
275 * If we did try to take rtas.lock there would be a
276 * real possibility of deadlock.
277 */
278 args.token = rtas_token("set-indicator");
279 if (args.token == RTAS_UNKNOWN_SERVICE)
280 return;
281 args.nargs = 3;
282 args.nret = 1;
283 args.rets = &args.args[3];
284 args.args[0] = SURVEILLANCE_TOKEN;
285 args.args[1] = 0;
286 args.args[2] = 0;
287 enter_rtas(__pa(&args));
288#endif /* CONFIG_PPC_PSERIES */
289}
290
291#ifdef CONFIG_SMP
292static int xmon_speaker;
293
294static void get_output_lock(void)
295{
296 int me = smp_processor_id() + 0x100;
297 int last_speaker = 0, prev;
298 long timeout;
299
300 if (xmon_speaker == me)
301 return;
302 for (;;) {
303 if (xmon_speaker == 0) {
304 last_speaker = cmpxchg(&xmon_speaker, 0, me);
305 if (last_speaker == 0)
306 return;
307 }
308 timeout = 10000000;
309 while (xmon_speaker == last_speaker) {
310 if (--timeout > 0)
311 continue;
312 /* hostile takeover */
313 prev = cmpxchg(&xmon_speaker, last_speaker, me);
314 if (prev == last_speaker)
315 return;
316 break;
317 }
318 }
319}
320
321static void release_output_lock(void)
322{
323 xmon_speaker = 0;
324}
325#endif
326
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000327static int xmon_core(struct pt_regs *regs, int fromipi)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328{
329 int cmd = 0;
330 unsigned long msr;
331 struct bpt *bp;
332 long recurse_jmp[JMP_BUF_LEN];
333 unsigned long offset;
334#ifdef CONFIG_SMP
335 int cpu;
336 int secondary;
337 unsigned long timeout;
338#endif
339
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000340 msr = mfmsr();
341 mtmsr(msr & ~MSR_EE); /* disable interrupts */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342
343 bp = in_breakpoint_table(regs->nip, &offset);
344 if (bp != NULL) {
345 regs->nip = bp->address + offset;
346 atomic_dec(&bp->ref_count);
347 }
348
349 remove_cpu_bpts();
350
351#ifdef CONFIG_SMP
352 cpu = smp_processor_id();
353 if (cpu_isset(cpu, cpus_in_xmon)) {
354 get_output_lock();
355 excprint(regs);
356 printf("cpu 0x%x: Exception %lx %s in xmon, "
357 "returning to main loop\n",
358 cpu, regs->trap, getvecname(TRAP(regs)));
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000359 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 longjmp(xmon_fault_jmp[cpu], 1);
361 }
362
363 if (setjmp(recurse_jmp) != 0) {
364 if (!in_xmon || !xmon_gate) {
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000365 get_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 printf("xmon: WARNING: bad recursive fault "
367 "on cpu 0x%x\n", cpu);
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000368 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 goto waiting;
370 }
371 secondary = !(xmon_taken && cpu == xmon_owner);
372 goto cmdloop;
373 }
374
375 xmon_fault_jmp[cpu] = recurse_jmp;
376 cpu_set(cpu, cpus_in_xmon);
377
378 bp = NULL;
379 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF))
380 bp = at_breakpoint(regs->nip);
381 if (bp || (regs->msr & MSR_RI) == 0)
382 fromipi = 0;
383
384 if (!fromipi) {
385 get_output_lock();
386 excprint(regs);
387 if (bp) {
388 printf("cpu 0x%x stopped at breakpoint 0x%x (",
389 cpu, BP_NUM(bp));
390 xmon_print_symbol(regs->nip, " ", ")\n");
391 }
392 if ((regs->msr & MSR_RI) == 0)
393 printf("WARNING: exception is not recoverable, "
394 "can't continue\n");
395 release_output_lock();
396 }
397
398 waiting:
399 secondary = 1;
400 while (secondary && !xmon_gate) {
401 if (in_xmon == 0) {
402 if (fromipi)
403 goto leave;
404 secondary = test_and_set_bit(0, &in_xmon);
405 }
406 barrier();
407 }
408
409 if (!secondary && !xmon_gate) {
410 /* we are the first cpu to come in */
411 /* interrupt other cpu(s) */
412 int ncpus = num_online_cpus();
413
414 xmon_owner = cpu;
415 mb();
416 if (ncpus > 1) {
417 smp_send_debugger_break(MSG_ALL_BUT_SELF);
418 /* wait for other cpus to come in */
419 for (timeout = 100000000; timeout != 0; --timeout) {
420 if (cpus_weight(cpus_in_xmon) >= ncpus)
421 break;
422 barrier();
423 }
424 }
425 remove_bpts();
426 disable_surveillance();
427 /* for breakpoint or single step, print the current instr. */
428 if (bp || TRAP(regs) == 0xd00)
429 ppc_inst_dump(regs->nip, 1, 0);
430 printf("enter ? for help\n");
431 mb();
432 xmon_gate = 1;
433 barrier();
434 }
435
436 cmdloop:
437 while (in_xmon) {
438 if (secondary) {
439 if (cpu == xmon_owner) {
440 if (!test_and_set_bit(0, &xmon_taken)) {
441 secondary = 0;
442 continue;
443 }
444 /* missed it */
445 while (cpu == xmon_owner)
446 barrier();
447 }
448 barrier();
449 } else {
450 cmd = cmds(regs);
451 if (cmd != 0) {
452 /* exiting xmon */
453 insert_bpts();
454 xmon_gate = 0;
455 wmb();
456 in_xmon = 0;
457 break;
458 }
459 /* have switched to some other cpu */
460 secondary = 1;
461 }
462 }
463 leave:
464 cpu_clear(cpu, cpus_in_xmon);
465 xmon_fault_jmp[cpu] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466#else
467 /* UP is simple... */
468 if (in_xmon) {
469 printf("Exception %lx %s in xmon, returning to main loop\n",
470 regs->trap, getvecname(TRAP(regs)));
471 longjmp(xmon_fault_jmp[0], 1);
472 }
473 if (setjmp(recurse_jmp) == 0) {
474 xmon_fault_jmp[0] = recurse_jmp;
475 in_xmon = 1;
476
477 excprint(regs);
478 bp = at_breakpoint(regs->nip);
479 if (bp) {
480 printf("Stopped at breakpoint %x (", BP_NUM(bp));
481 xmon_print_symbol(regs->nip, " ", ")\n");
482 }
483 if ((regs->msr & MSR_RI) == 0)
484 printf("WARNING: exception is not recoverable, "
485 "can't continue\n");
486 remove_bpts();
487 disable_surveillance();
488 /* for breakpoint or single step, print the current instr. */
489 if (bp || TRAP(regs) == 0xd00)
490 ppc_inst_dump(regs->nip, 1, 0);
491 printf("enter ? for help\n");
492 }
493
494 cmd = cmds(regs);
495
496 insert_bpts();
497 in_xmon = 0;
498#endif
499
500 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF)) {
501 bp = at_breakpoint(regs->nip);
502 if (bp != NULL) {
503 int stepped = emulate_step(regs, bp->instr[0]);
504 if (stepped == 0) {
505 regs->nip = (unsigned long) &bp->instr[0];
506 atomic_inc(&bp->ref_count);
507 } else if (stepped < 0) {
508 printf("Couldn't single-step %s instruction\n",
509 (IS_RFID(bp->instr[0])? "rfid": "mtmsrd"));
510 }
511 }
512 }
513
514 insert_cpu_bpts();
515
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000516 mtmsr(msr); /* restore interrupt enable */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517
Paul Mackerras0a730ae2006-10-03 21:32:49 +1000518 return cmd != 'X' && cmd != EOF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519}
520
521int xmon(struct pt_regs *excp)
522{
523 struct pt_regs regs;
524
525 if (excp == NULL) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000526 xmon_save_regs(&regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 excp = &regs;
528 }
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200529
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 return xmon_core(excp, 0);
531}
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000532EXPORT_SYMBOL(xmon);
533
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000534irqreturn_t xmon_irq(int irq, void *d)
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000535{
536 unsigned long flags;
537 local_irq_save(flags);
538 printf("Keyboard interrupt\n");
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000539 xmon(get_irq_regs());
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000540 local_irq_restore(flags);
541 return IRQ_HANDLED;
542}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000544static int xmon_bpt(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545{
546 struct bpt *bp;
547 unsigned long offset;
548
549 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF))
550 return 0;
551
552 /* Are we at the trap at bp->instr[1] for some bp? */
553 bp = in_breakpoint_table(regs->nip, &offset);
554 if (bp != NULL && offset == 4) {
555 regs->nip = bp->address + 4;
556 atomic_dec(&bp->ref_count);
557 return 1;
558 }
559
560 /* Are we at a breakpoint? */
561 bp = at_breakpoint(regs->nip);
562 if (!bp)
563 return 0;
564
565 xmon_core(regs, 0);
566
567 return 1;
568}
569
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000570static int xmon_sstep(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571{
572 if (user_mode(regs))
573 return 0;
574 xmon_core(regs, 0);
575 return 1;
576}
577
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000578static int xmon_dabr_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579{
580 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF))
581 return 0;
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000582 if (dabr.enabled == 0)
583 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 xmon_core(regs, 0);
585 return 1;
586}
587
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000588static int xmon_iabr_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589{
590 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF))
591 return 0;
592 if (iabr == 0)
593 return 0;
594 xmon_core(regs, 0);
595 return 1;
596}
597
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000598static int xmon_ipi(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599{
600#ifdef CONFIG_SMP
601 if (in_xmon && !cpu_isset(smp_processor_id(), cpus_in_xmon))
602 xmon_core(regs, 1);
603#endif
604 return 0;
605}
606
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000607static int xmon_fault_handler(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608{
609 struct bpt *bp;
610 unsigned long offset;
611
612 if (in_xmon && catch_memory_errors)
613 handle_fault(regs); /* doesn't return */
614
615 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF)) {
616 bp = in_breakpoint_table(regs->nip, &offset);
617 if (bp != NULL) {
618 regs->nip = bp->address + offset;
619 atomic_dec(&bp->ref_count);
620 }
621 }
622
623 return 0;
624}
625
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626static struct bpt *at_breakpoint(unsigned long pc)
627{
628 int i;
629 struct bpt *bp;
630
631 bp = bpts;
632 for (i = 0; i < NBPTS; ++i, ++bp)
633 if (bp->enabled && pc == bp->address)
634 return bp;
635 return NULL;
636}
637
638static struct bpt *in_breakpoint_table(unsigned long nip, unsigned long *offp)
639{
640 unsigned long off;
641
642 off = nip - (unsigned long) bpts;
643 if (off >= sizeof(bpts))
644 return NULL;
645 off %= sizeof(struct bpt);
646 if (off != offsetof(struct bpt, instr[0])
647 && off != offsetof(struct bpt, instr[1]))
648 return NULL;
649 *offp = off - offsetof(struct bpt, instr[0]);
650 return (struct bpt *) (nip - off);
651}
652
653static struct bpt *new_breakpoint(unsigned long a)
654{
655 struct bpt *bp;
656
657 a &= ~3UL;
658 bp = at_breakpoint(a);
659 if (bp)
660 return bp;
661
662 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
663 if (!bp->enabled && atomic_read(&bp->ref_count) == 0) {
664 bp->address = a;
665 bp->instr[1] = bpinstr;
666 store_inst(&bp->instr[1]);
667 return bp;
668 }
669 }
670
671 printf("Sorry, no free breakpoints. Please clear one first.\n");
672 return NULL;
673}
674
675static void insert_bpts(void)
676{
677 int i;
678 struct bpt *bp;
679
680 bp = bpts;
681 for (i = 0; i < NBPTS; ++i, ++bp) {
682 if ((bp->enabled & (BP_TRAP|BP_IABR)) == 0)
683 continue;
684 if (mread(bp->address, &bp->instr[0], 4) != 4) {
685 printf("Couldn't read instruction at %lx, "
686 "disabling breakpoint there\n", bp->address);
687 bp->enabled = 0;
688 continue;
689 }
690 if (IS_MTMSRD(bp->instr[0]) || IS_RFID(bp->instr[0])) {
691 printf("Breakpoint at %lx is on an mtmsrd or rfid "
692 "instruction, disabling it\n", bp->address);
693 bp->enabled = 0;
694 continue;
695 }
696 store_inst(&bp->instr[0]);
697 if (bp->enabled & BP_IABR)
698 continue;
699 if (mwrite(bp->address, &bpinstr, 4) != 4) {
700 printf("Couldn't write instruction at %lx, "
701 "disabling breakpoint there\n", bp->address);
702 bp->enabled &= ~BP_TRAP;
703 continue;
704 }
705 store_inst((void *)bp->address);
706 }
707}
708
709static void insert_cpu_bpts(void)
710{
711 if (dabr.enabled)
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000712 set_dabr(dabr.address | (dabr.enabled & 7));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 if (iabr && cpu_has_feature(CPU_FTR_IABR))
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000714 mtspr(SPRN_IABR, iabr->address
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 | (iabr->enabled & (BP_IABR|BP_IABR_TE)));
716}
717
718static void remove_bpts(void)
719{
720 int i;
721 struct bpt *bp;
722 unsigned instr;
723
724 bp = bpts;
725 for (i = 0; i < NBPTS; ++i, ++bp) {
726 if ((bp->enabled & (BP_TRAP|BP_IABR)) != BP_TRAP)
727 continue;
728 if (mread(bp->address, &instr, 4) == 4
729 && instr == bpinstr
730 && mwrite(bp->address, &bp->instr, 4) != 4)
731 printf("Couldn't remove breakpoint at %lx\n",
732 bp->address);
733 else
734 store_inst((void *)bp->address);
735 }
736}
737
738static void remove_cpu_bpts(void)
739{
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000740 set_dabr(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 if (cpu_has_feature(CPU_FTR_IABR))
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000742 mtspr(SPRN_IABR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743}
744
745/* Command interpreting routine */
746static char *last_cmd;
747
748static int
749cmds(struct pt_regs *excp)
750{
751 int cmd = 0;
752
753 last_cmd = NULL;
754 xmon_regs = excp;
Olaf Hering26c8af52006-09-08 16:29:21 +0200755
756 if (!xmon_no_auto_backtrace) {
757 xmon_no_auto_backtrace = 1;
758 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
759 }
760
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 for(;;) {
762#ifdef CONFIG_SMP
763 printf("%x:", smp_processor_id());
764#endif /* CONFIG_SMP */
765 printf("mon> ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 flush_input();
767 termch = 0;
768 cmd = skipbl();
769 if( cmd == '\n' ) {
770 if (last_cmd == NULL)
771 continue;
772 take_input(last_cmd);
773 last_cmd = NULL;
774 cmd = inchar();
775 }
776 switch (cmd) {
777 case 'm':
778 cmd = inchar();
779 switch (cmd) {
780 case 'm':
781 case 's':
782 case 'd':
783 memops(cmd);
784 break;
785 case 'l':
786 memlocate();
787 break;
788 case 'z':
789 memzcan();
790 break;
791 case 'i':
792 show_mem();
793 break;
794 default:
795 termch = cmd;
796 memex();
797 }
798 break;
799 case 'd':
800 dump();
801 break;
802 case 'l':
803 symbol_lookup();
804 break;
805 case 'r':
806 prregs(excp); /* print regs */
807 break;
808 case 'e':
809 excprint(excp);
810 break;
811 case 'S':
812 super_regs();
813 break;
814 case 't':
815 backtrace(excp);
816 break;
817 case 'f':
818 cacheflush();
819 break;
820 case 's':
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200821 if (do_spu_cmd() == 0)
822 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 if (do_step(excp))
824 return cmd;
825 break;
826 case 'x':
827 case 'X':
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100828 return cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 case EOF:
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100830 printf(" <no input ...>\n");
831 mdelay(2000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 return cmd;
833 case '?':
834 printf(help_string);
835 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 case 'b':
837 bpt_cmds();
838 break;
839 case 'C':
840 csum();
841 break;
842 case 'c':
843 if (cpu_cmd())
844 return 0;
845 break;
846 case 'z':
847 bootcmds();
848 break;
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000849 case 'p':
850 proccall();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 break;
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000852#ifdef CONFIG_PPC_STD_MMU
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 case 'u':
854 dump_segments();
855 break;
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000856#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 default:
858 printf("Unrecognized command: ");
859 do {
860 if (' ' < cmd && cmd <= '~')
861 putchar(cmd);
862 else
863 printf("\\x%x", cmd);
864 cmd = inchar();
865 } while (cmd != '\n');
866 printf(" (type ? for help)\n");
867 break;
868 }
869 }
870}
871
872/*
873 * Step a single instruction.
874 * Some instructions we emulate, others we execute with MSR_SE set.
875 */
876static int do_step(struct pt_regs *regs)
877{
878 unsigned int instr;
879 int stepped;
880
881 /* check we are in 64-bit kernel mode, translation enabled */
882 if ((regs->msr & (MSR_SF|MSR_PR|MSR_IR)) == (MSR_SF|MSR_IR)) {
883 if (mread(regs->nip, &instr, 4) == 4) {
884 stepped = emulate_step(regs, instr);
885 if (stepped < 0) {
886 printf("Couldn't single-step %s instruction\n",
887 (IS_RFID(instr)? "rfid": "mtmsrd"));
888 return 0;
889 }
890 if (stepped > 0) {
891 regs->trap = 0xd00 | (regs->trap & 1);
892 printf("stepped to ");
893 xmon_print_symbol(regs->nip, " ", "\n");
894 ppc_inst_dump(regs->nip, 1, 0);
895 return 0;
896 }
897 }
898 }
899 regs->msr |= MSR_SE;
900 return 1;
901}
902
903static void bootcmds(void)
904{
905 int cmd;
906
907 cmd = inchar();
908 if (cmd == 'r')
909 ppc_md.restart(NULL);
910 else if (cmd == 'h')
911 ppc_md.halt();
912 else if (cmd == 'p')
913 ppc_md.power_off();
914}
915
916static int cpu_cmd(void)
917{
918#ifdef CONFIG_SMP
919 unsigned long cpu;
920 int timeout;
921 int count;
922
923 if (!scanhex(&cpu)) {
924 /* print cpus waiting or in xmon */
925 printf("cpus stopped:");
926 count = 0;
927 for (cpu = 0; cpu < NR_CPUS; ++cpu) {
928 if (cpu_isset(cpu, cpus_in_xmon)) {
929 if (count == 0)
930 printf(" %x", cpu);
931 ++count;
932 } else {
933 if (count > 1)
934 printf("-%x", cpu - 1);
935 count = 0;
936 }
937 }
938 if (count > 1)
939 printf("-%x", NR_CPUS - 1);
940 printf("\n");
941 return 0;
942 }
943 /* try to switch to cpu specified */
944 if (!cpu_isset(cpu, cpus_in_xmon)) {
945 printf("cpu 0x%x isn't in xmon\n", cpu);
946 return 0;
947 }
948 xmon_taken = 0;
949 mb();
950 xmon_owner = cpu;
951 timeout = 10000000;
952 while (!xmon_taken) {
953 if (--timeout == 0) {
954 if (test_and_set_bit(0, &xmon_taken))
955 break;
956 /* take control back */
957 mb();
958 xmon_owner = smp_processor_id();
959 printf("cpu %u didn't take control\n", cpu);
960 return 0;
961 }
962 barrier();
963 }
964 return 1;
965#else
966 return 0;
967#endif /* CONFIG_SMP */
968}
969
970static unsigned short fcstab[256] = {
971 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
972 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
973 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
974 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
975 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
976 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
977 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
978 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
979 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
980 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
981 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
982 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
983 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
984 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
985 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
986 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
987 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
988 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
989 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
990 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
991 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
992 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
993 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
994 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
995 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
996 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
997 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
998 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
999 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
1000 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
1001 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
1002 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
1003};
1004
1005#define FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
1006
1007static void
1008csum(void)
1009{
1010 unsigned int i;
1011 unsigned short fcs;
1012 unsigned char v;
1013
1014 if (!scanhex(&adrs))
1015 return;
1016 if (!scanhex(&ncsum))
1017 return;
1018 fcs = 0xffff;
1019 for (i = 0; i < ncsum; ++i) {
1020 if (mread(adrs+i, &v, 1) == 0) {
1021 printf("csum stopped at %x\n", adrs+i);
1022 break;
1023 }
1024 fcs = FCS(fcs, v);
1025 }
1026 printf("%x\n", fcs);
1027}
1028
1029/*
1030 * Check if this is a suitable place to put a breakpoint.
1031 */
1032static long check_bp_loc(unsigned long addr)
1033{
1034 unsigned int instr;
1035
1036 addr &= ~3;
Michael Ellerman51fae6d2005-12-04 18:39:15 +11001037 if (!is_kernel_addr(addr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 printf("Breakpoints may only be placed at kernel addresses\n");
1039 return 0;
1040 }
1041 if (!mread(addr, &instr, sizeof(instr))) {
1042 printf("Can't read instruction at address %lx\n", addr);
1043 return 0;
1044 }
1045 if (IS_MTMSRD(instr) || IS_RFID(instr)) {
1046 printf("Breakpoints may not be placed on mtmsrd or rfid "
1047 "instructions\n");
1048 return 0;
1049 }
1050 return 1;
1051}
1052
1053static char *breakpoint_help_string =
1054 "Breakpoint command usage:\n"
1055 "b show breakpoints\n"
1056 "b <addr> [cnt] set breakpoint at given instr addr\n"
1057 "bc clear all breakpoints\n"
1058 "bc <n/addr> clear breakpoint number n or at addr\n"
1059 "bi <addr> [cnt] set hardware instr breakpoint (POWER3/RS64 only)\n"
1060 "bd <addr> [cnt] set hardware data breakpoint\n"
1061 "";
1062
1063static void
1064bpt_cmds(void)
1065{
1066 int cmd;
1067 unsigned long a;
1068 int mode, i;
1069 struct bpt *bp;
1070 const char badaddr[] = "Only kernel addresses are permitted "
1071 "for breakpoints\n";
1072
1073 cmd = inchar();
1074 switch (cmd) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001075#ifndef CONFIG_8xx
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 case 'd': /* bd - hardware data breakpoint */
1077 mode = 7;
1078 cmd = inchar();
1079 if (cmd == 'r')
1080 mode = 5;
1081 else if (cmd == 'w')
1082 mode = 6;
1083 else
1084 termch = cmd;
1085 dabr.address = 0;
1086 dabr.enabled = 0;
1087 if (scanhex(&dabr.address)) {
Michael Ellerman51fae6d2005-12-04 18:39:15 +11001088 if (!is_kernel_addr(dabr.address)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 printf(badaddr);
1090 break;
1091 }
1092 dabr.address &= ~7;
1093 dabr.enabled = mode | BP_DABR;
1094 }
1095 break;
1096
1097 case 'i': /* bi - hardware instr breakpoint */
1098 if (!cpu_has_feature(CPU_FTR_IABR)) {
1099 printf("Hardware instruction breakpoint "
1100 "not supported on this cpu\n");
1101 break;
1102 }
1103 if (iabr) {
1104 iabr->enabled &= ~(BP_IABR | BP_IABR_TE);
1105 iabr = NULL;
1106 }
1107 if (!scanhex(&a))
1108 break;
1109 if (!check_bp_loc(a))
1110 break;
1111 bp = new_breakpoint(a);
1112 if (bp != NULL) {
1113 bp->enabled |= BP_IABR | BP_IABR_TE;
1114 iabr = bp;
1115 }
1116 break;
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001117#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118
1119 case 'c':
1120 if (!scanhex(&a)) {
1121 /* clear all breakpoints */
1122 for (i = 0; i < NBPTS; ++i)
1123 bpts[i].enabled = 0;
1124 iabr = NULL;
1125 dabr.enabled = 0;
1126 printf("All breakpoints cleared\n");
1127 break;
1128 }
1129
1130 if (a <= NBPTS && a >= 1) {
1131 /* assume a breakpoint number */
1132 bp = &bpts[a-1]; /* bp nums are 1 based */
1133 } else {
1134 /* assume a breakpoint address */
1135 bp = at_breakpoint(a);
1136 if (bp == 0) {
1137 printf("No breakpoint at %x\n", a);
1138 break;
1139 }
1140 }
1141
1142 printf("Cleared breakpoint %x (", BP_NUM(bp));
1143 xmon_print_symbol(bp->address, " ", ")\n");
1144 bp->enabled = 0;
1145 break;
1146
1147 default:
1148 termch = cmd;
1149 cmd = skipbl();
1150 if (cmd == '?') {
1151 printf(breakpoint_help_string);
1152 break;
1153 }
1154 termch = cmd;
1155 if (!scanhex(&a)) {
1156 /* print all breakpoints */
1157 printf(" type address\n");
1158 if (dabr.enabled) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001159 printf(" data "REG" [", dabr.address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 if (dabr.enabled & 1)
1161 printf("r");
1162 if (dabr.enabled & 2)
1163 printf("w");
1164 printf("]\n");
1165 }
1166 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
1167 if (!bp->enabled)
1168 continue;
1169 printf("%2x %s ", BP_NUM(bp),
1170 (bp->enabled & BP_IABR)? "inst": "trap");
1171 xmon_print_symbol(bp->address, " ", "\n");
1172 }
1173 break;
1174 }
1175
1176 if (!check_bp_loc(a))
1177 break;
1178 bp = new_breakpoint(a);
1179 if (bp != NULL)
1180 bp->enabled |= BP_TRAP;
1181 break;
1182 }
1183}
1184
1185/* Very cheap human name for vector lookup. */
1186static
1187const char *getvecname(unsigned long vec)
1188{
1189 char *ret;
1190
1191 switch (vec) {
1192 case 0x100: ret = "(System Reset)"; break;
1193 case 0x200: ret = "(Machine Check)"; break;
1194 case 0x300: ret = "(Data Access)"; break;
1195 case 0x380: ret = "(Data SLB Access)"; break;
1196 case 0x400: ret = "(Instruction Access)"; break;
1197 case 0x480: ret = "(Instruction SLB Access)"; break;
1198 case 0x500: ret = "(Hardware Interrupt)"; break;
1199 case 0x600: ret = "(Alignment)"; break;
1200 case 0x700: ret = "(Program Check)"; break;
1201 case 0x800: ret = "(FPU Unavailable)"; break;
1202 case 0x900: ret = "(Decrementer)"; break;
1203 case 0xc00: ret = "(System Call)"; break;
1204 case 0xd00: ret = "(Single Step)"; break;
1205 case 0xf00: ret = "(Performance Monitor)"; break;
1206 case 0xf20: ret = "(Altivec Unavailable)"; break;
1207 case 0x1300: ret = "(Instruction Breakpoint)"; break;
1208 default: ret = "";
1209 }
1210 return ret;
1211}
1212
1213static void get_function_bounds(unsigned long pc, unsigned long *startp,
1214 unsigned long *endp)
1215{
1216 unsigned long size, offset;
1217 const char *name;
1218 char *modname;
1219
1220 *startp = *endp = 0;
1221 if (pc == 0)
1222 return;
1223 if (setjmp(bus_error_jmp) == 0) {
1224 catch_memory_errors = 1;
1225 sync();
1226 name = kallsyms_lookup(pc, &size, &offset, &modname, tmpstr);
1227 if (name != NULL) {
1228 *startp = pc - offset;
1229 *endp = pc - offset + size;
1230 }
1231 sync();
1232 }
1233 catch_memory_errors = 0;
1234}
1235
1236static int xmon_depth_to_print = 64;
1237
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001238#ifdef CONFIG_PPC64
1239#define LRSAVE_OFFSET 0x10
1240#define REG_FRAME_MARKER 0x7265677368657265ul /* "regshere" */
1241#define MARKER_OFFSET 0x60
1242#define REGS_OFFSET 0x70
1243#else
1244#define LRSAVE_OFFSET 4
1245#define REG_FRAME_MARKER 0x72656773
1246#define MARKER_OFFSET 8
1247#define REGS_OFFSET 16
1248#endif
1249
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250static void xmon_show_stack(unsigned long sp, unsigned long lr,
1251 unsigned long pc)
1252{
1253 unsigned long ip;
1254 unsigned long newsp;
1255 unsigned long marker;
1256 int count = 0;
1257 struct pt_regs regs;
1258
1259 do {
1260 if (sp < PAGE_OFFSET) {
1261 if (sp != 0)
1262 printf("SP (%lx) is in userspace\n", sp);
1263 break;
1264 }
1265
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001266 if (!mread(sp + LRSAVE_OFFSET, &ip, sizeof(unsigned long))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267 || !mread(sp, &newsp, sizeof(unsigned long))) {
1268 printf("Couldn't read stack frame at %lx\n", sp);
1269 break;
1270 }
1271
1272 /*
1273 * For the first stack frame, try to work out if
1274 * LR and/or the saved LR value in the bottommost
1275 * stack frame are valid.
1276 */
1277 if ((pc | lr) != 0) {
1278 unsigned long fnstart, fnend;
1279 unsigned long nextip;
1280 int printip = 1;
1281
1282 get_function_bounds(pc, &fnstart, &fnend);
1283 nextip = 0;
1284 if (newsp > sp)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001285 mread(newsp + LRSAVE_OFFSET, &nextip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 sizeof(unsigned long));
1287 if (lr == ip) {
1288 if (lr < PAGE_OFFSET
1289 || (fnstart <= lr && lr < fnend))
1290 printip = 0;
1291 } else if (lr == nextip) {
1292 printip = 0;
1293 } else if (lr >= PAGE_OFFSET
1294 && !(fnstart <= lr && lr < fnend)) {
1295 printf("[link register ] ");
1296 xmon_print_symbol(lr, " ", "\n");
1297 }
1298 if (printip) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001299 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 xmon_print_symbol(ip, " ", " (unreliable)\n");
1301 }
1302 pc = lr = 0;
1303
1304 } else {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001305 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 xmon_print_symbol(ip, " ", "\n");
1307 }
1308
1309 /* Look for "regshere" marker to see if this is
1310 an exception frame. */
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001311 if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long))
1312 && marker == REG_FRAME_MARKER) {
1313 if (mread(sp + REGS_OFFSET, &regs, sizeof(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 != sizeof(regs)) {
1315 printf("Couldn't read registers at %lx\n",
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001316 sp + REGS_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 break;
1318 }
1319 printf("--- Exception: %lx %s at ", regs.trap,
1320 getvecname(TRAP(&regs)));
1321 pc = regs.nip;
1322 lr = regs.link;
1323 xmon_print_symbol(pc, " ", "\n");
1324 }
1325
1326 if (newsp == 0)
1327 break;
1328
1329 sp = newsp;
1330 } while (count++ < xmon_depth_to_print);
1331}
1332
1333static void backtrace(struct pt_regs *excp)
1334{
1335 unsigned long sp;
1336
1337 if (scanhex(&sp))
1338 xmon_show_stack(sp, 0, 0);
1339 else
1340 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
1341 scannl();
1342}
1343
1344static void print_bug_trap(struct pt_regs *regs)
1345{
1346 struct bug_entry *bug;
1347 unsigned long addr;
1348
1349 if (regs->msr & MSR_PR)
1350 return; /* not in kernel */
1351 addr = regs->nip; /* address of trap instruction */
1352 if (addr < PAGE_OFFSET)
1353 return;
1354 bug = find_bug(regs->nip);
1355 if (bug == NULL)
1356 return;
1357 if (bug->line & BUG_WARNING_TRAP)
1358 return;
1359
1360 printf("kernel BUG in %s at %s:%d!\n",
1361 bug->function, bug->file, (unsigned int)bug->line);
1362}
1363
1364void excprint(struct pt_regs *fp)
1365{
1366 unsigned long trap;
1367
1368#ifdef CONFIG_SMP
1369 printf("cpu 0x%x: ", smp_processor_id());
1370#endif /* CONFIG_SMP */
1371
1372 trap = TRAP(fp);
1373 printf("Vector: %lx %s at [%lx]\n", fp->trap, getvecname(trap), fp);
1374 printf(" pc: ");
1375 xmon_print_symbol(fp->nip, ": ", "\n");
1376
1377 printf(" lr: ", fp->link);
1378 xmon_print_symbol(fp->link, ": ", "\n");
1379
1380 printf(" sp: %lx\n", fp->gpr[1]);
1381 printf(" msr: %lx\n", fp->msr);
1382
1383 if (trap == 0x300 || trap == 0x380 || trap == 0x600) {
1384 printf(" dar: %lx\n", fp->dar);
1385 if (trap != 0x380)
1386 printf(" dsisr: %lx\n", fp->dsisr);
1387 }
1388
1389 printf(" current = 0x%lx\n", current);
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001390#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 printf(" paca = 0x%lx\n", get_paca());
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001392#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393 if (current) {
1394 printf(" pid = %ld, comm = %s\n",
1395 current->pid, current->comm);
1396 }
1397
1398 if (trap == 0x700)
1399 print_bug_trap(fp);
1400}
1401
1402void prregs(struct pt_regs *fp)
1403{
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001404 int n, trap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405 unsigned long base;
1406 struct pt_regs regs;
1407
1408 if (scanhex(&base)) {
1409 if (setjmp(bus_error_jmp) == 0) {
1410 catch_memory_errors = 1;
1411 sync();
1412 regs = *(struct pt_regs *)base;
1413 sync();
1414 __delay(200);
1415 } else {
1416 catch_memory_errors = 0;
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001417 printf("*** Error reading registers from "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418 base);
1419 return;
1420 }
1421 catch_memory_errors = 0;
1422 fp = &regs;
1423 }
1424
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001425#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426 if (FULL_REGS(fp)) {
1427 for (n = 0; n < 16; ++n)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001428 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429 n, fp->gpr[n], n+16, fp->gpr[n+16]);
1430 } else {
1431 for (n = 0; n < 7; ++n)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001432 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433 n, fp->gpr[n], n+7, fp->gpr[n+7]);
1434 }
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001435#else
1436 for (n = 0; n < 32; ++n) {
1437 printf("R%.2d = %.8x%s", n, fp->gpr[n],
1438 (n & 3) == 3? "\n": " ");
1439 if (n == 12 && !FULL_REGS(fp)) {
1440 printf("\n");
1441 break;
1442 }
1443 }
1444#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445 printf("pc = ");
1446 xmon_print_symbol(fp->nip, " ", "\n");
1447 printf("lr = ");
1448 xmon_print_symbol(fp->link, " ", "\n");
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001449 printf("msr = "REG" cr = %.8lx\n", fp->msr, fp->ccr);
1450 printf("ctr = "REG" xer = "REG" trap = %4lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 fp->ctr, fp->xer, fp->trap);
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001452 trap = TRAP(fp);
1453 if (trap == 0x300 || trap == 0x380 || trap == 0x600)
1454 printf("dar = "REG" dsisr = %.8lx\n", fp->dar, fp->dsisr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455}
1456
1457void cacheflush(void)
1458{
1459 int cmd;
1460 unsigned long nflush;
1461
1462 cmd = inchar();
1463 if (cmd != 'i')
1464 termch = cmd;
1465 scanhex((void *)&adrs);
1466 if (termch != '\n')
1467 termch = 0;
1468 nflush = 1;
1469 scanhex(&nflush);
1470 nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES;
1471 if (setjmp(bus_error_jmp) == 0) {
1472 catch_memory_errors = 1;
1473 sync();
1474
1475 if (cmd != 'i') {
1476 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1477 cflush((void *) adrs);
1478 } else {
1479 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1480 cinval((void *) adrs);
1481 }
1482 sync();
1483 /* wait a little while to see if we get a machine check */
1484 __delay(200);
1485 }
1486 catch_memory_errors = 0;
1487}
1488
1489unsigned long
1490read_spr(int n)
1491{
1492 unsigned int instrs[2];
1493 unsigned long (*code)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 unsigned long ret = -1UL;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001495#ifdef CONFIG_PPC64
1496 unsigned long opd[3];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 opd[0] = (unsigned long)instrs;
1499 opd[1] = 0;
1500 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001501 code = (unsigned long (*)(void)) opd;
1502#else
1503 code = (unsigned long (*)(void)) instrs;
1504#endif
1505
1506 /* mfspr r3,n; blr */
1507 instrs[0] = 0x7c6002a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1508 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 store_inst(instrs);
1510 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511
1512 if (setjmp(bus_error_jmp) == 0) {
1513 catch_memory_errors = 1;
1514 sync();
1515
1516 ret = code();
1517
1518 sync();
1519 /* wait a little while to see if we get a machine check */
1520 __delay(200);
1521 n = size;
1522 }
1523
1524 return ret;
1525}
1526
1527void
1528write_spr(int n, unsigned long val)
1529{
1530 unsigned int instrs[2];
1531 unsigned long (*code)(unsigned long);
Paul Mackerras548cceb2005-11-11 22:36:34 +11001532#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 unsigned long opd[3];
1534
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 opd[0] = (unsigned long)instrs;
1536 opd[1] = 0;
1537 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001538 code = (unsigned long (*)(unsigned long)) opd;
1539#else
1540 code = (unsigned long (*)(unsigned long)) instrs;
1541#endif
1542
1543 instrs[0] = 0x7c6003a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1544 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545 store_inst(instrs);
1546 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547
1548 if (setjmp(bus_error_jmp) == 0) {
1549 catch_memory_errors = 1;
1550 sync();
1551
1552 code(val);
1553
1554 sync();
1555 /* wait a little while to see if we get a machine check */
1556 __delay(200);
1557 n = size;
1558 }
1559}
1560
1561static unsigned long regno;
1562extern char exc_prolog;
1563extern char dec_exc;
1564
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001565void super_regs(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566{
1567 int cmd;
1568 unsigned long val;
1569#ifdef CONFIG_PPC_ISERIES
1570 struct paca_struct *ptrPaca = NULL;
1571 struct lppaca *ptrLpPaca = NULL;
1572 struct ItLpRegSave *ptrLpRegSave = NULL;
1573#endif
1574
1575 cmd = skipbl();
1576 if (cmd == '\n') {
1577 unsigned long sp, toc;
1578 asm("mr %0,1" : "=r" (sp) :);
1579 asm("mr %0,2" : "=r" (toc) :);
1580
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001581 printf("msr = "REG" sprg0= "REG"\n",
1582 mfmsr(), mfspr(SPRN_SPRG0));
1583 printf("pvr = "REG" sprg1= "REG"\n",
1584 mfspr(SPRN_PVR), mfspr(SPRN_SPRG1));
1585 printf("dec = "REG" sprg2= "REG"\n",
1586 mfspr(SPRN_DEC), mfspr(SPRN_SPRG2));
1587 printf("sp = "REG" sprg3= "REG"\n", sp, mfspr(SPRN_SPRG3));
1588 printf("toc = "REG" dar = "REG"\n", toc, mfspr(SPRN_DAR));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589#ifdef CONFIG_PPC_ISERIES
1590 // Dump out relevant Paca data areas.
1591 printf("Paca: \n");
1592 ptrPaca = get_paca();
1593
1594 printf(" Local Processor Control Area (LpPaca): \n");
1595 ptrLpPaca = ptrPaca->lppaca_ptr;
1596 printf(" Saved Srr0=%.16lx Saved Srr1=%.16lx \n",
1597 ptrLpPaca->saved_srr0, ptrLpPaca->saved_srr1);
1598 printf(" Saved Gpr3=%.16lx Saved Gpr4=%.16lx \n",
1599 ptrLpPaca->saved_gpr3, ptrLpPaca->saved_gpr4);
1600 printf(" Saved Gpr5=%.16lx \n", ptrLpPaca->saved_gpr5);
1601
1602 printf(" Local Processor Register Save Area (LpRegSave): \n");
1603 ptrLpRegSave = ptrPaca->reg_save_ptr;
1604 printf(" Saved Sprg0=%.16lx Saved Sprg1=%.16lx \n",
1605 ptrLpRegSave->xSPRG0, ptrLpRegSave->xSPRG0);
1606 printf(" Saved Sprg2=%.16lx Saved Sprg3=%.16lx \n",
1607 ptrLpRegSave->xSPRG2, ptrLpRegSave->xSPRG3);
1608 printf(" Saved Msr =%.16lx Saved Nia =%.16lx \n",
1609 ptrLpRegSave->xMSR, ptrLpRegSave->xNIA);
1610#endif
1611
1612 return;
1613 }
1614
1615 scanhex(&regno);
1616 switch (cmd) {
1617 case 'w':
1618 val = read_spr(regno);
1619 scanhex(&val);
1620 write_spr(regno, val);
1621 /* fall through */
1622 case 'r':
1623 printf("spr %lx = %lx\n", regno, read_spr(regno));
1624 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625 }
1626 scannl();
1627}
1628
1629/*
1630 * Stuff for reading and writing memory safely
1631 */
1632int
1633mread(unsigned long adrs, void *buf, int size)
1634{
1635 volatile int n;
1636 char *p, *q;
1637
1638 n = 0;
1639 if (setjmp(bus_error_jmp) == 0) {
1640 catch_memory_errors = 1;
1641 sync();
1642 p = (char *)adrs;
1643 q = (char *)buf;
1644 switch (size) {
1645 case 2:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001646 *(u16 *)q = *(u16 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647 break;
1648 case 4:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001649 *(u32 *)q = *(u32 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 break;
1651 case 8:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001652 *(u64 *)q = *(u64 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 break;
1654 default:
1655 for( ; n < size; ++n) {
1656 *q++ = *p++;
1657 sync();
1658 }
1659 }
1660 sync();
1661 /* wait a little while to see if we get a machine check */
1662 __delay(200);
1663 n = size;
1664 }
1665 catch_memory_errors = 0;
1666 return n;
1667}
1668
1669int
1670mwrite(unsigned long adrs, void *buf, int size)
1671{
1672 volatile int n;
1673 char *p, *q;
1674
1675 n = 0;
1676 if (setjmp(bus_error_jmp) == 0) {
1677 catch_memory_errors = 1;
1678 sync();
1679 p = (char *) adrs;
1680 q = (char *) buf;
1681 switch (size) {
1682 case 2:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001683 *(u16 *)p = *(u16 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684 break;
1685 case 4:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001686 *(u32 *)p = *(u32 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687 break;
1688 case 8:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001689 *(u64 *)p = *(u64 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 break;
1691 default:
1692 for ( ; n < size; ++n) {
1693 *p++ = *q++;
1694 sync();
1695 }
1696 }
1697 sync();
1698 /* wait a little while to see if we get a machine check */
1699 __delay(200);
1700 n = size;
1701 } else {
1702 printf("*** Error writing address %x\n", adrs + n);
1703 }
1704 catch_memory_errors = 0;
1705 return n;
1706}
1707
1708static int fault_type;
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001709static int fault_except;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710static char *fault_chars[] = { "--", "**", "##" };
1711
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001712static int handle_fault(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713{
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001714 fault_except = TRAP(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 switch (TRAP(regs)) {
1716 case 0x200:
1717 fault_type = 0;
1718 break;
1719 case 0x300:
1720 case 0x380:
1721 fault_type = 1;
1722 break;
1723 default:
1724 fault_type = 2;
1725 }
1726
1727 longjmp(bus_error_jmp, 1);
1728
1729 return 0;
1730}
1731
1732#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t))
1733
1734void
1735byterev(unsigned char *val, int size)
1736{
1737 int t;
1738
1739 switch (size) {
1740 case 2:
1741 SWAP(val[0], val[1], t);
1742 break;
1743 case 4:
1744 SWAP(val[0], val[3], t);
1745 SWAP(val[1], val[2], t);
1746 break;
1747 case 8: /* is there really any use for this? */
1748 SWAP(val[0], val[7], t);
1749 SWAP(val[1], val[6], t);
1750 SWAP(val[2], val[5], t);
1751 SWAP(val[3], val[4], t);
1752 break;
1753 }
1754}
1755
1756static int brev;
1757static int mnoread;
1758
1759static char *memex_help_string =
1760 "Memory examine command usage:\n"
1761 "m [addr] [flags] examine/change memory\n"
1762 " addr is optional. will start where left off.\n"
1763 " flags may include chars from this set:\n"
1764 " b modify by bytes (default)\n"
1765 " w modify by words (2 byte)\n"
1766 " l modify by longs (4 byte)\n"
1767 " d modify by doubleword (8 byte)\n"
1768 " r toggle reverse byte order mode\n"
1769 " n do not read memory (for i/o spaces)\n"
1770 " . ok to read (default)\n"
1771 "NOTE: flags are saved as defaults\n"
1772 "";
1773
1774static char *memex_subcmd_help_string =
1775 "Memory examine subcommands:\n"
1776 " hexval write this val to current location\n"
1777 " 'string' write chars from string to this location\n"
1778 " ' increment address\n"
1779 " ^ decrement address\n"
1780 " / increment addr by 0x10. //=0x100, ///=0x1000, etc\n"
1781 " \\ decrement addr by 0x10. \\\\=0x100, \\\\\\=0x1000, etc\n"
1782 " ` clear no-read flag\n"
1783 " ; stay at this addr\n"
1784 " v change to byte mode\n"
1785 " w change to word (2 byte) mode\n"
1786 " l change to long (4 byte) mode\n"
1787 " u change to doubleword (8 byte) mode\n"
1788 " m addr change current addr\n"
1789 " n toggle no-read flag\n"
1790 " r toggle byte reverse flag\n"
1791 " < count back up count bytes\n"
1792 " > count skip forward count bytes\n"
1793 " x exit this mode\n"
1794 "";
1795
1796void
1797memex(void)
1798{
1799 int cmd, inc, i, nslash;
1800 unsigned long n;
1801 unsigned char val[16];
1802
1803 scanhex((void *)&adrs);
1804 cmd = skipbl();
1805 if (cmd == '?') {
1806 printf(memex_help_string);
1807 return;
1808 } else {
1809 termch = cmd;
1810 }
1811 last_cmd = "m\n";
1812 while ((cmd = skipbl()) != '\n') {
1813 switch( cmd ){
1814 case 'b': size = 1; break;
1815 case 'w': size = 2; break;
1816 case 'l': size = 4; break;
1817 case 'd': size = 8; break;
1818 case 'r': brev = !brev; break;
1819 case 'n': mnoread = 1; break;
1820 case '.': mnoread = 0; break;
1821 }
1822 }
1823 if( size <= 0 )
1824 size = 1;
1825 else if( size > 8 )
1826 size = 8;
1827 for(;;){
1828 if (!mnoread)
1829 n = mread(adrs, val, size);
Paul Mackerrase1449ed2005-11-10 14:30:20 +11001830 printf(REG"%c", adrs, brev? 'r': ' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831 if (!mnoread) {
1832 if (brev)
1833 byterev(val, size);
1834 putchar(' ');
1835 for (i = 0; i < n; ++i)
1836 printf("%.2x", val[i]);
1837 for (; i < size; ++i)
1838 printf("%s", fault_chars[fault_type]);
1839 }
1840 putchar(' ');
1841 inc = size;
1842 nslash = 0;
1843 for(;;){
1844 if( scanhex(&n) ){
1845 for (i = 0; i < size; ++i)
1846 val[i] = n >> (i * 8);
1847 if (!brev)
1848 byterev(val, size);
1849 mwrite(adrs, val, size);
1850 inc = size;
1851 }
1852 cmd = skipbl();
1853 if (cmd == '\n')
1854 break;
1855 inc = 0;
1856 switch (cmd) {
1857 case '\'':
1858 for(;;){
1859 n = inchar();
1860 if( n == '\\' )
1861 n = bsesc();
1862 else if( n == '\'' )
1863 break;
1864 for (i = 0; i < size; ++i)
1865 val[i] = n >> (i * 8);
1866 if (!brev)
1867 byterev(val, size);
1868 mwrite(adrs, val, size);
1869 adrs += size;
1870 }
1871 adrs -= size;
1872 inc = size;
1873 break;
1874 case ',':
1875 adrs += size;
1876 break;
1877 case '.':
1878 mnoread = 0;
1879 break;
1880 case ';':
1881 break;
1882 case 'x':
1883 case EOF:
1884 scannl();
1885 return;
1886 case 'b':
1887 case 'v':
1888 size = 1;
1889 break;
1890 case 'w':
1891 size = 2;
1892 break;
1893 case 'l':
1894 size = 4;
1895 break;
1896 case 'u':
1897 size = 8;
1898 break;
1899 case '^':
1900 adrs -= size;
1901 break;
1902 break;
1903 case '/':
1904 if (nslash > 0)
1905 adrs -= 1 << nslash;
1906 else
1907 nslash = 0;
1908 nslash += 4;
1909 adrs += 1 << nslash;
1910 break;
1911 case '\\':
1912 if (nslash < 0)
1913 adrs += 1 << -nslash;
1914 else
1915 nslash = 0;
1916 nslash -= 4;
1917 adrs -= 1 << -nslash;
1918 break;
1919 case 'm':
1920 scanhex((void *)&adrs);
1921 break;
1922 case 'n':
1923 mnoread = 1;
1924 break;
1925 case 'r':
1926 brev = !brev;
1927 break;
1928 case '<':
1929 n = size;
1930 scanhex(&n);
1931 adrs -= n;
1932 break;
1933 case '>':
1934 n = size;
1935 scanhex(&n);
1936 adrs += n;
1937 break;
1938 case '?':
1939 printf(memex_subcmd_help_string);
1940 break;
1941 }
1942 }
1943 adrs += inc;
1944 }
1945}
1946
1947int
1948bsesc(void)
1949{
1950 int c;
1951
1952 c = inchar();
1953 switch( c ){
1954 case 'n': c = '\n'; break;
1955 case 'r': c = '\r'; break;
1956 case 'b': c = '\b'; break;
1957 case 't': c = '\t'; break;
1958 }
1959 return c;
1960}
1961
Olaf Hering7e5b5932006-03-08 20:40:28 +01001962static void xmon_rawdump (unsigned long adrs, long ndump)
1963{
1964 long n, m, r, nr;
1965 unsigned char temp[16];
1966
1967 for (n = ndump; n > 0;) {
1968 r = n < 16? n: 16;
1969 nr = mread(adrs, temp, r);
1970 adrs += nr;
1971 for (m = 0; m < r; ++m) {
1972 if (m < nr)
1973 printf("%.2x", temp[m]);
1974 else
1975 printf("%s", fault_chars[fault_type]);
1976 }
1977 n -= r;
1978 if (nr < r)
1979 break;
1980 }
1981 printf("\n");
1982}
1983
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
1985 || ('a' <= (c) && (c) <= 'f') \
1986 || ('A' <= (c) && (c) <= 'F'))
1987void
1988dump(void)
1989{
1990 int c;
1991
1992 c = inchar();
1993 if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
1994 termch = c;
1995 scanhex((void *)&adrs);
1996 if (termch != '\n')
1997 termch = 0;
1998 if (c == 'i') {
1999 scanhex(&nidump);
2000 if (nidump == 0)
2001 nidump = 16;
2002 else if (nidump > MAX_DUMP)
2003 nidump = MAX_DUMP;
2004 adrs += ppc_inst_dump(adrs, nidump, 1);
2005 last_cmd = "di\n";
Olaf Hering7e5b5932006-03-08 20:40:28 +01002006 } else if (c == 'r') {
2007 scanhex(&ndump);
2008 if (ndump == 0)
2009 ndump = 64;
2010 xmon_rawdump(adrs, ndump);
2011 adrs += ndump;
2012 last_cmd = "dr\n";
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013 } else {
2014 scanhex(&ndump);
2015 if (ndump == 0)
2016 ndump = 64;
2017 else if (ndump > MAX_DUMP)
2018 ndump = MAX_DUMP;
2019 prdump(adrs, ndump);
2020 adrs += ndump;
2021 last_cmd = "d\n";
2022 }
2023}
2024
2025void
2026prdump(unsigned long adrs, long ndump)
2027{
2028 long n, m, c, r, nr;
2029 unsigned char temp[16];
2030
2031 for (n = ndump; n > 0;) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002032 printf(REG, adrs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 putchar(' ');
2034 r = n < 16? n: 16;
2035 nr = mread(adrs, temp, r);
2036 adrs += nr;
2037 for (m = 0; m < r; ++m) {
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002038 if ((m & (sizeof(long) - 1)) == 0 && m > 0)
2039 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040 if (m < nr)
2041 printf("%.2x", temp[m]);
2042 else
2043 printf("%s", fault_chars[fault_type]);
2044 }
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002045 for (; m < 16; ++m) {
2046 if ((m & (sizeof(long) - 1)) == 0)
2047 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048 printf(" ");
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002049 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002050 printf(" |");
2051 for (m = 0; m < r; ++m) {
2052 if (m < nr) {
2053 c = temp[m];
2054 putchar(' ' <= c && c <= '~'? c: '.');
2055 } else
2056 putchar(' ');
2057 }
2058 n -= r;
2059 for (; m < 16; ++m)
2060 putchar(' ');
2061 printf("|\n");
2062 if (nr < r)
2063 break;
2064 }
2065}
2066
2067int
2068ppc_inst_dump(unsigned long adr, long count, int praddr)
2069{
2070 int nr, dotted;
2071 unsigned long first_adr;
2072 unsigned long inst, last_inst = 0;
2073 unsigned char val[4];
2074
2075 dotted = 0;
2076 for (first_adr = adr; count > 0; --count, adr += 4) {
2077 nr = mread(adr, val, 4);
2078 if (nr == 0) {
2079 if (praddr) {
2080 const char *x = fault_chars[fault_type];
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002081 printf(REG" %s%s%s%s\n", adr, x, x, x, x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082 }
2083 break;
2084 }
2085 inst = GETWORD(val);
2086 if (adr > first_adr && inst == last_inst) {
2087 if (!dotted) {
2088 printf(" ...\n");
2089 dotted = 1;
2090 }
2091 continue;
2092 }
2093 dotted = 0;
2094 last_inst = inst;
2095 if (praddr)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002096 printf(REG" %.8x", adr, inst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097 printf("\t");
2098 print_insn_powerpc(inst, adr, 0); /* always returns 4 */
2099 printf("\n");
2100 }
2101 return adr - first_adr;
2102}
2103
2104void
2105print_address(unsigned long addr)
2106{
2107 xmon_print_symbol(addr, "\t# ", "");
2108}
2109
2110
2111/*
2112 * Memory operations - move, set, print differences
2113 */
2114static unsigned long mdest; /* destination address */
2115static unsigned long msrc; /* source address */
2116static unsigned long mval; /* byte value to set memory to */
2117static unsigned long mcount; /* # bytes to affect */
2118static unsigned long mdiffs; /* max # differences to print */
2119
2120void
2121memops(int cmd)
2122{
2123 scanhex((void *)&mdest);
2124 if( termch != '\n' )
2125 termch = 0;
2126 scanhex((void *)(cmd == 's'? &mval: &msrc));
2127 if( termch != '\n' )
2128 termch = 0;
2129 scanhex((void *)&mcount);
2130 switch( cmd ){
2131 case 'm':
2132 memmove((void *)mdest, (void *)msrc, mcount);
2133 break;
2134 case 's':
2135 memset((void *)mdest, mval, mcount);
2136 break;
2137 case 'd':
2138 if( termch != '\n' )
2139 termch = 0;
2140 scanhex((void *)&mdiffs);
2141 memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
2142 break;
2143 }
2144}
2145
2146void
2147memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
2148{
2149 unsigned n, prt;
2150
2151 prt = 0;
2152 for( n = nb; n > 0; --n )
2153 if( *p1++ != *p2++ )
2154 if( ++prt <= maxpr )
2155 printf("%.16x %.2x # %.16x %.2x\n", p1 - 1,
2156 p1[-1], p2 - 1, p2[-1]);
2157 if( prt > maxpr )
2158 printf("Total of %d differences\n", prt);
2159}
2160
2161static unsigned mend;
2162static unsigned mask;
2163
2164void
2165memlocate(void)
2166{
2167 unsigned a, n;
2168 unsigned char val[4];
2169
2170 last_cmd = "ml";
2171 scanhex((void *)&mdest);
2172 if (termch != '\n') {
2173 termch = 0;
2174 scanhex((void *)&mend);
2175 if (termch != '\n') {
2176 termch = 0;
2177 scanhex((void *)&mval);
2178 mask = ~0;
2179 if (termch != '\n') termch = 0;
2180 scanhex((void *)&mask);
2181 }
2182 }
2183 n = 0;
2184 for (a = mdest; a < mend; a += 4) {
2185 if (mread(a, val, 4) == 4
2186 && ((GETWORD(val) ^ mval) & mask) == 0) {
2187 printf("%.16x: %.16x\n", a, GETWORD(val));
2188 if (++n >= 10)
2189 break;
2190 }
2191 }
2192}
2193
2194static unsigned long mskip = 0x1000;
2195static unsigned long mlim = 0xffffffff;
2196
2197void
2198memzcan(void)
2199{
2200 unsigned char v;
2201 unsigned a;
2202 int ok, ook;
2203
2204 scanhex(&mdest);
2205 if (termch != '\n') termch = 0;
2206 scanhex(&mskip);
2207 if (termch != '\n') termch = 0;
2208 scanhex(&mlim);
2209 ook = 0;
2210 for (a = mdest; a < mlim; a += mskip) {
2211 ok = mread(a, &v, 1);
2212 if (ok && !ook) {
2213 printf("%.8x .. ", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214 } else if (!ok && ook)
2215 printf("%.8x\n", a - mskip);
2216 ook = ok;
2217 if (a + mskip < a)
2218 break;
2219 }
2220 if (ook)
2221 printf("%.8x\n", a - mskip);
2222}
2223
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002224void proccall(void)
2225{
2226 unsigned long args[8];
2227 unsigned long ret;
2228 int i;
2229 typedef unsigned long (*callfunc_t)(unsigned long, unsigned long,
2230 unsigned long, unsigned long, unsigned long,
2231 unsigned long, unsigned long, unsigned long);
2232 callfunc_t func;
2233
2234 if (!scanhex(&adrs))
2235 return;
2236 if (termch != '\n')
2237 termch = 0;
2238 for (i = 0; i < 8; ++i)
2239 args[i] = 0;
2240 for (i = 0; i < 8; ++i) {
2241 if (!scanhex(&args[i]) || termch == '\n')
2242 break;
2243 termch = 0;
2244 }
2245 func = (callfunc_t) adrs;
2246 ret = 0;
2247 if (setjmp(bus_error_jmp) == 0) {
2248 catch_memory_errors = 1;
2249 sync();
2250 ret = func(args[0], args[1], args[2], args[3],
2251 args[4], args[5], args[6], args[7]);
2252 sync();
2253 printf("return value is %x\n", ret);
2254 } else {
2255 printf("*** %x exception occurred\n", fault_except);
2256 }
2257 catch_memory_errors = 0;
2258}
2259
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260/* Input scanning routines */
2261int
2262skipbl(void)
2263{
2264 int c;
2265
2266 if( termch != 0 ){
2267 c = termch;
2268 termch = 0;
2269 } else
2270 c = inchar();
2271 while( c == ' ' || c == '\t' )
2272 c = inchar();
2273 return c;
2274}
2275
2276#define N_PTREGS 44
2277static char *regnames[N_PTREGS] = {
2278 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
2279 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
2280 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
2281 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002282 "pc", "msr", "or3", "ctr", "lr", "xer", "ccr",
2283#ifdef CONFIG_PPC64
2284 "softe",
2285#else
2286 "mq",
2287#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288 "trap", "dar", "dsisr", "res"
2289};
2290
2291int
2292scanhex(unsigned long *vp)
2293{
2294 int c, d;
2295 unsigned long v;
2296
2297 c = skipbl();
2298 if (c == '%') {
2299 /* parse register name */
2300 char regname[8];
2301 int i;
2302
2303 for (i = 0; i < sizeof(regname) - 1; ++i) {
2304 c = inchar();
2305 if (!isalnum(c)) {
2306 termch = c;
2307 break;
2308 }
2309 regname[i] = c;
2310 }
2311 regname[i] = 0;
2312 for (i = 0; i < N_PTREGS; ++i) {
2313 if (strcmp(regnames[i], regname) == 0) {
2314 if (xmon_regs == NULL) {
2315 printf("regs not available\n");
2316 return 0;
2317 }
2318 *vp = ((unsigned long *)xmon_regs)[i];
2319 return 1;
2320 }
2321 }
2322 printf("invalid register name '%%%s'\n", regname);
2323 return 0;
2324 }
2325
2326 /* skip leading "0x" if any */
2327
2328 if (c == '0') {
2329 c = inchar();
2330 if (c == 'x') {
2331 c = inchar();
2332 } else {
2333 d = hexdigit(c);
2334 if (d == EOF) {
2335 termch = c;
2336 *vp = 0;
2337 return 1;
2338 }
2339 }
2340 } else if (c == '$') {
2341 int i;
2342 for (i=0; i<63; i++) {
2343 c = inchar();
2344 if (isspace(c)) {
2345 termch = c;
2346 break;
2347 }
2348 tmpstr[i] = c;
2349 }
2350 tmpstr[i++] = 0;
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07002351 *vp = 0;
2352 if (setjmp(bus_error_jmp) == 0) {
2353 catch_memory_errors = 1;
2354 sync();
2355 *vp = kallsyms_lookup_name(tmpstr);
2356 sync();
2357 }
2358 catch_memory_errors = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359 if (!(*vp)) {
2360 printf("unknown symbol '%s'\n", tmpstr);
2361 return 0;
2362 }
2363 return 1;
2364 }
2365
2366 d = hexdigit(c);
2367 if (d == EOF) {
2368 termch = c;
2369 return 0;
2370 }
2371 v = 0;
2372 do {
2373 v = (v << 4) + d;
2374 c = inchar();
2375 d = hexdigit(c);
2376 } while (d != EOF);
2377 termch = c;
2378 *vp = v;
2379 return 1;
2380}
2381
2382void
2383scannl(void)
2384{
2385 int c;
2386
2387 c = termch;
2388 termch = 0;
2389 while( c != '\n' )
2390 c = inchar();
2391}
2392
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002393int hexdigit(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394{
2395 if( '0' <= c && c <= '9' )
2396 return c - '0';
2397 if( 'A' <= c && c <= 'F' )
2398 return c - ('A' - 10);
2399 if( 'a' <= c && c <= 'f' )
2400 return c - ('a' - 10);
2401 return EOF;
2402}
2403
2404void
2405getstring(char *s, int size)
2406{
2407 int c;
2408
2409 c = skipbl();
2410 do {
2411 if( size > 1 ){
2412 *s++ = c;
2413 --size;
2414 }
2415 c = inchar();
2416 } while( c != ' ' && c != '\t' && c != '\n' );
2417 termch = c;
2418 *s = 0;
2419}
2420
2421static char line[256];
2422static char *lineptr;
2423
2424void
2425flush_input(void)
2426{
2427 lineptr = NULL;
2428}
2429
2430int
2431inchar(void)
2432{
2433 if (lineptr == NULL || *lineptr == 0) {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002434 if (xmon_gets(line, sizeof(line)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435 lineptr = NULL;
2436 return EOF;
2437 }
2438 lineptr = line;
2439 }
2440 return *lineptr++;
2441}
2442
2443void
2444take_input(char *str)
2445{
2446 lineptr = str;
2447}
2448
2449
2450static void
2451symbol_lookup(void)
2452{
2453 int type = inchar();
2454 unsigned long addr;
2455 static char tmp[64];
2456
2457 switch (type) {
2458 case 'a':
2459 if (scanhex(&addr))
2460 xmon_print_symbol(addr, ": ", "\n");
2461 termch = 0;
2462 break;
2463 case 's':
2464 getstring(tmp, 64);
2465 if (setjmp(bus_error_jmp) == 0) {
2466 catch_memory_errors = 1;
2467 sync();
2468 addr = kallsyms_lookup_name(tmp);
2469 if (addr)
2470 printf("%s: %lx\n", tmp, addr);
2471 else
2472 printf("Symbol '%s' not found.\n", tmp);
2473 sync();
2474 }
2475 catch_memory_errors = 0;
2476 termch = 0;
2477 break;
2478 }
2479}
2480
2481
2482/* Print an address in numeric and symbolic form (if possible) */
2483static void xmon_print_symbol(unsigned long address, const char *mid,
2484 const char *after)
2485{
2486 char *modname;
2487 const char *name = NULL;
2488 unsigned long offset, size;
2489
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002490 printf(REG, address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491 if (setjmp(bus_error_jmp) == 0) {
2492 catch_memory_errors = 1;
2493 sync();
2494 name = kallsyms_lookup(address, &size, &offset, &modname,
2495 tmpstr);
2496 sync();
2497 /* wait a little while to see if we get a machine check */
2498 __delay(200);
2499 }
2500
2501 catch_memory_errors = 0;
2502
2503 if (name) {
2504 printf("%s%s+%#lx/%#lx", mid, name, offset, size);
2505 if (modname)
2506 printf(" [%s]", modname);
2507 }
2508 printf("%s", after);
2509}
2510
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002511#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07002512static void dump_slb(void)
2513{
2514 int i;
2515 unsigned long tmp;
2516
2517 printf("SLB contents of cpu %x\n", smp_processor_id());
2518
2519 for (i = 0; i < SLB_NUM_ENTRIES; i++) {
2520 asm volatile("slbmfee %0,%1" : "=r" (tmp) : "r" (i));
2521 printf("%02d %016lx ", i, tmp);
2522
2523 asm volatile("slbmfev %0,%1" : "=r" (tmp) : "r" (i));
2524 printf("%016lx\n", tmp);
2525 }
2526}
2527
2528static void dump_stab(void)
2529{
2530 int i;
2531 unsigned long *tmp = (unsigned long *)get_paca()->stab_addr;
2532
2533 printf("Segment table contents of cpu %x\n", smp_processor_id());
2534
2535 for (i = 0; i < PAGE_SIZE/16; i++) {
2536 unsigned long a, b;
2537
2538 a = *tmp++;
2539 b = *tmp++;
2540
2541 if (a || b) {
2542 printf("%03d %016lx ", i, a);
2543 printf("%016lx\n", b);
2544 }
2545 }
2546}
2547
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002548void dump_segments(void)
2549{
2550 if (cpu_has_feature(CPU_FTR_SLB))
2551 dump_slb();
2552 else
2553 dump_stab();
2554}
2555#endif
2556
2557#ifdef CONFIG_PPC_STD_MMU_32
2558void dump_segments(void)
2559{
2560 int i;
2561
2562 printf("sr0-15 =");
2563 for (i = 0; i < 16; ++i)
2564 printf(" %x", mfsrin(i));
2565 printf("\n");
2566}
2567#endif
2568
Olaf Heringb13cfd12005-08-04 19:26:42 +02002569void xmon_init(int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570{
Olaf Heringb13cfd12005-08-04 19:26:42 +02002571 if (enable) {
2572 __debugger = xmon;
2573 __debugger_ipi = xmon_ipi;
2574 __debugger_bpt = xmon_bpt;
2575 __debugger_sstep = xmon_sstep;
2576 __debugger_iabr_match = xmon_iabr_match;
2577 __debugger_dabr_match = xmon_dabr_match;
2578 __debugger_fault_handler = xmon_fault_handler;
2579 } else {
2580 __debugger = NULL;
2581 __debugger_ipi = NULL;
2582 __debugger_bpt = NULL;
2583 __debugger_sstep = NULL;
2584 __debugger_iabr_match = NULL;
2585 __debugger_dabr_match = NULL;
2586 __debugger_fault_handler = NULL;
2587 }
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002588 xmon_map_scc();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589}
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002590
2591#ifdef CONFIG_MAGIC_SYSRQ
David Howells7d12e782006-10-05 14:55:46 +01002592static void sysrq_handle_xmon(int key, struct tty_struct *tty)
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002593{
2594 /* ensure xmon is enabled */
2595 xmon_init(1);
David Howells7d12e782006-10-05 14:55:46 +01002596 debugger(get_irq_regs());
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002597}
2598
2599static struct sysrq_key_op sysrq_xmon_op =
2600{
2601 .handler = sysrq_handle_xmon,
2602 .help_msg = "Xmon",
2603 .action_msg = "Entering xmon",
2604};
2605
2606static int __init setup_xmon_sysrq(void)
2607{
2608 register_sysrq_key('x', &sysrq_xmon_op);
2609 return 0;
2610}
2611__initcall(setup_xmon_sysrq);
2612#endif /* CONFIG_MAGIC_SYSRQ */
Michael Ellerman476792832006-10-03 14:12:08 +10002613
2614int __initdata xmon_early, xmon_off;
2615
2616static int __init early_parse_xmon(char *p)
2617{
2618 if (!p || strncmp(p, "early", 5) == 0) {
2619 /* just "xmon" is equivalent to "xmon=early" */
2620 xmon_init(1);
2621 xmon_early = 1;
2622 } else if (strncmp(p, "on", 2) == 0)
2623 xmon_init(1);
2624 else if (strncmp(p, "off", 3) == 0)
2625 xmon_off = 1;
2626 else if (strncmp(p, "nobt", 4) == 0)
2627 xmon_no_auto_backtrace = 1;
2628 else
2629 return 1;
2630
2631 return 0;
2632}
2633early_param("xmon", early_parse_xmon);
2634
2635void __init xmon_setup(void)
2636{
2637#ifdef CONFIG_XMON_DEFAULT
2638 if (!xmon_off)
2639 xmon_init(1);
2640#endif
2641 if (xmon_early)
2642 debugger(NULL);
2643}
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002644
2645#ifdef CONFIG_PPC_CELL
2646
2647struct spu_info {
2648 struct spu *spu;
2649 u64 saved_mfc_sr1_RW;
2650 u32 saved_spu_runcntl_RW;
2651 u8 stopped_ok;
2652};
2653
2654#define XMON_NUM_SPUS 16 /* Enough for current hardware */
2655
2656static struct spu_info spu_info[XMON_NUM_SPUS];
2657
2658void xmon_register_spus(struct list_head *list)
2659{
2660 struct spu *spu;
2661
2662 list_for_each_entry(spu, list, full_list) {
2663 if (spu->number >= XMON_NUM_SPUS) {
2664 WARN_ON(1);
2665 continue;
2666 }
2667
2668 spu_info[spu->number].spu = spu;
2669 spu_info[spu->number].stopped_ok = 0;
2670 }
2671}
2672
2673static void stop_spus(void)
2674{
2675 struct spu *spu;
2676 int i;
2677 u64 tmp;
2678
2679 for (i = 0; i < XMON_NUM_SPUS; i++) {
2680 if (!spu_info[i].spu)
2681 continue;
2682
2683 if (setjmp(bus_error_jmp) == 0) {
2684 catch_memory_errors = 1;
2685 sync();
2686
2687 spu = spu_info[i].spu;
2688
2689 spu_info[i].saved_spu_runcntl_RW =
2690 in_be32(&spu->problem->spu_runcntl_RW);
2691
2692 tmp = spu_mfc_sr1_get(spu);
2693 spu_info[i].saved_mfc_sr1_RW = tmp;
2694
2695 tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
2696 spu_mfc_sr1_set(spu, tmp);
2697
2698 sync();
2699 __delay(200);
2700
2701 spu_info[i].stopped_ok = 1;
2702 printf("Stopped spu %.2d\n", i);
2703 } else {
2704 catch_memory_errors = 0;
2705 printf("*** Error stopping spu %.2d\n", i);
2706 }
2707 catch_memory_errors = 0;
2708 }
2709}
2710
2711static void restart_spus(void)
2712{
2713 struct spu *spu;
2714 int i;
2715
2716 for (i = 0; i < XMON_NUM_SPUS; i++) {
2717 if (!spu_info[i].spu)
2718 continue;
2719
2720 if (!spu_info[i].stopped_ok) {
2721 printf("*** Error, spu %d was not successfully stopped"
2722 ", not restarting\n", i);
2723 continue;
2724 }
2725
2726 if (setjmp(bus_error_jmp) == 0) {
2727 catch_memory_errors = 1;
2728 sync();
2729
2730 spu = spu_info[i].spu;
2731 spu_mfc_sr1_set(spu, spu_info[i].saved_mfc_sr1_RW);
2732 out_be32(&spu->problem->spu_runcntl_RW,
2733 spu_info[i].saved_spu_runcntl_RW);
2734
2735 sync();
2736 __delay(200);
2737
2738 printf("Restarted spu %.2d\n", i);
2739 } else {
2740 catch_memory_errors = 0;
2741 printf("*** Error restarting spu %.2d\n", i);
2742 }
2743 catch_memory_errors = 0;
2744 }
2745}
2746
2747static int do_spu_cmd(void)
2748{
2749 int cmd;
2750
2751 cmd = inchar();
2752 switch (cmd) {
2753 case 's':
2754 stop_spus();
2755 break;
2756 case 'r':
2757 restart_spus();
2758 break;
2759 default:
2760 return -1;
2761 }
2762
2763 return 0;
2764}
2765#else /* ! CONFIG_PPC_CELL */
2766static int do_spu_cmd(void)
2767{
2768 return -1;
2769}
2770#endif