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