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