blob: 00fd7647f80746cb8fc2fd463b4fc2ac64dff907 [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>
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -080025#include <linux/bug.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026
27#include <asm/ptrace.h>
28#include <asm/string.h>
29#include <asm/prom.h>
30#include <asm/machdep.h>
Paul Mackerrasf78541d2005-10-28 22:53:37 +100031#include <asm/xmon.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <asm/processor.h>
33#include <asm/pgtable.h>
34#include <asm/mmu.h>
35#include <asm/mmu_context.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include <asm/cputable.h>
37#include <asm/rtas.h>
38#include <asm/sstep.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>
Michael Neulingc3b75bd2008-01-18 15:50:30 +110043#include <asm/setjmp.h>
Paul Mackerrasf78541d2005-10-28 22:53:37 +100044
45#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -070046#include <asm/hvcall.h>
Paul Mackerrasf78541d2005-10-28 22:53:37 +100047#include <asm/paca.h>
48#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
50#include "nonstdio.h"
Michael Ellermane0426042006-11-23 00:46:45 +010051#include "dis-asm.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070052
53#define scanhex xmon_scanhex
54#define skipbl xmon_skipbl
55
56#ifdef CONFIG_SMP
57cpumask_t cpus_in_xmon = CPU_MASK_NONE;
58static unsigned long xmon_taken = 1;
59static int xmon_owner;
60static int xmon_gate;
61#endif /* CONFIG_SMP */
62
63static unsigned long in_xmon = 0;
64
65static unsigned long adrs;
66static int size = 1;
67#define MAX_DUMP (128 * 1024)
68static unsigned long ndump = 64;
69static unsigned long nidump = 16;
70static unsigned long ncsum = 4096;
71static int termch;
72static char tmpstr[128];
73
Linus Torvalds1da177e2005-04-16 15:20:36 -070074static long bus_error_jmp[JMP_BUF_LEN];
75static int catch_memory_errors;
76static long *xmon_fault_jmp[NR_CPUS];
Linus Torvalds1da177e2005-04-16 15:20:36 -070077
78/* Breakpoint stuff */
79struct bpt {
80 unsigned long address;
81 unsigned int instr[2];
82 atomic_t ref_count;
83 int enabled;
84 unsigned long pad;
85};
86
87/* Bits in bpt.enabled */
88#define BP_IABR_TE 1 /* IABR translation enabled */
89#define BP_IABR 2
90#define BP_TRAP 8
91#define BP_DABR 0x10
92
93#define NBPTS 256
94static struct bpt bpts[NBPTS];
95static struct bpt dabr;
96static struct bpt *iabr;
97static unsigned bpinstr = 0x7fe00008; /* trap */
98
99#define BP_NUM(bp) ((bp) - bpts + 1)
100
101/* Prototypes */
102static int cmds(struct pt_regs *);
103static int mread(unsigned long, void *, int);
104static int mwrite(unsigned long, void *, int);
105static int handle_fault(struct pt_regs *);
106static void byterev(unsigned char *, int);
107static void memex(void);
108static int bsesc(void);
109static void dump(void);
110static void prdump(unsigned long, long);
111static int ppc_inst_dump(unsigned long, long, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112static void backtrace(struct pt_regs *);
113static void excprint(struct pt_regs *);
114static void prregs(struct pt_regs *);
115static void memops(int);
116static void memlocate(void);
117static void memzcan(void);
118static void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned);
119int skipbl(void);
120int scanhex(unsigned long *valp);
121static void scannl(void);
122static int hexdigit(int);
123void getstring(char *, int);
124static void flush_input(void);
125static int inchar(void);
126static void take_input(char *);
127static unsigned long read_spr(int);
128static void write_spr(int, unsigned long);
129static void super_regs(void);
130static void remove_bpts(void);
131static void insert_bpts(void);
132static void remove_cpu_bpts(void);
133static void insert_cpu_bpts(void);
134static struct bpt *at_breakpoint(unsigned long pc);
135static struct bpt *in_breakpoint_table(unsigned long pc, unsigned long *offp);
136static int do_step(struct pt_regs *);
137static void bpt_cmds(void);
138static void cacheflush(void);
139static int cpu_cmd(void);
140static void csum(void);
141static void bootcmds(void);
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000142static void proccall(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143void dump_segments(void);
144static void symbol_lookup(void);
Olaf Hering26c8af52006-09-08 16:29:21 +0200145static void xmon_show_stack(unsigned long sp, unsigned long lr,
146 unsigned long pc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147static void xmon_print_symbol(unsigned long address, const char *mid,
148 const char *after);
149static const char *getvecname(unsigned long vec);
150
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200151static int do_spu_cmd(void);
152
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100153#ifdef CONFIG_44x
154static void dump_tlb_44x(void);
155#endif
156
Olaf Hering26c8af52006-09-08 16:29:21 +0200157int xmon_no_auto_backtrace;
158
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000159extern void xmon_enter(void);
160extern void xmon_leave(void);
161
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000162extern void xmon_save_regs(struct pt_regs *);
163
164#ifdef CONFIG_PPC64
165#define REG "%.16lx"
166#define REGS_PER_LINE 4
167#define LAST_VOLATILE 13
168#else
169#define REG "%.8lx"
170#define REGS_PER_LINE 8
171#define LAST_VOLATILE 12
172#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173
174#define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
175
176#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
177 || ('a' <= (c) && (c) <= 'f') \
178 || ('A' <= (c) && (c) <= 'F'))
179#define isalnum(c) (('0' <= (c) && (c) <= '9') \
180 || ('a' <= (c) && (c) <= 'z') \
181 || ('A' <= (c) && (c) <= 'Z'))
182#define isspace(c) (c == ' ' || c == '\t' || c == 10 || c == 13 || c == 0)
183
184static char *help_string = "\
185Commands:\n\
186 b show breakpoints\n\
187 bd set data breakpoint\n\
188 bi set instruction breakpoint\n\
189 bc clear breakpoint\n"
190#ifdef CONFIG_SMP
191 "\
192 c print cpus stopped in xmon\n\
193 c# try to switch to cpu number h (in hex)\n"
194#endif
195 "\
196 C checksum\n\
197 d dump bytes\n\
198 di dump instructions\n\
199 df dump float values\n\
200 dd dump double values\n\
Olaf Hering7e5b5932006-03-08 20:40:28 +0100201 dr dump stream of raw bytes\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 e print exception information\n\
203 f flush cache\n\
204 la lookup symbol+offset of specified address\n\
205 ls lookup address of specified symbol\n\
206 m examine/change memory\n\
207 mm move a block of memory\n\
208 ms set a block of memory\n\
209 md compare two blocks of memory\n\
210 ml locate a block of memory\n\
211 mz zero a block of memory\n\
212 mi show information about memory allocation\n\
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000213 p call a procedure\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 r print registers\n\
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200215 s single step\n"
Arnd Bergmanne0555952006-11-27 19:18:55 +0100216#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200217" ss stop execution on all spus\n\
Michael Ellermana8984972006-10-24 18:31:28 +0200218 sr restore execution on stopped spus\n\
Michael Ellerman24a24c82006-11-23 00:46:41 +0100219 sf # dump spu fields for spu # (in hex)\n\
Michael Ellermanc99176a2007-02-26 18:14:06 +0900220 sd # dump spu local store for spu # (in hex)\n\
Michael Ellermanaf89fb82006-11-23 00:46:44 +0100221 sdi # disassemble spu local store 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
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100233#ifdef CONFIG_44x
234" u dump TLB\n"
235#endif
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000236" ? 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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 struct bpt *bp;
336 long recurse_jmp[JMP_BUF_LEN];
337 unsigned long offset;
Anton Blanchardf13659e2007-03-21 01:48:34 +1100338 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339#ifdef CONFIG_SMP
340 int cpu;
341 int secondary;
342 unsigned long timeout;
343#endif
344
Anton Blanchardf13659e2007-03-21 01:48:34 +1100345 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346
347 bp = in_breakpoint_table(regs->nip, &offset);
348 if (bp != NULL) {
349 regs->nip = bp->address + offset;
350 atomic_dec(&bp->ref_count);
351 }
352
353 remove_cpu_bpts();
354
355#ifdef CONFIG_SMP
356 cpu = smp_processor_id();
357 if (cpu_isset(cpu, cpus_in_xmon)) {
358 get_output_lock();
359 excprint(regs);
360 printf("cpu 0x%x: Exception %lx %s in xmon, "
361 "returning to main loop\n",
362 cpu, regs->trap, getvecname(TRAP(regs)));
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000363 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 longjmp(xmon_fault_jmp[cpu], 1);
365 }
366
367 if (setjmp(recurse_jmp) != 0) {
368 if (!in_xmon || !xmon_gate) {
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000369 get_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 printf("xmon: WARNING: bad recursive fault "
371 "on cpu 0x%x\n", cpu);
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000372 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 goto waiting;
374 }
375 secondary = !(xmon_taken && cpu == xmon_owner);
376 goto cmdloop;
377 }
378
379 xmon_fault_jmp[cpu] = recurse_jmp;
380 cpu_set(cpu, cpus_in_xmon);
381
382 bp = NULL;
383 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF))
384 bp = at_breakpoint(regs->nip);
385 if (bp || (regs->msr & MSR_RI) == 0)
386 fromipi = 0;
387
388 if (!fromipi) {
389 get_output_lock();
390 excprint(regs);
391 if (bp) {
392 printf("cpu 0x%x stopped at breakpoint 0x%x (",
393 cpu, BP_NUM(bp));
394 xmon_print_symbol(regs->nip, " ", ")\n");
395 }
396 if ((regs->msr & MSR_RI) == 0)
397 printf("WARNING: exception is not recoverable, "
398 "can't continue\n");
399 release_output_lock();
400 }
401
402 waiting:
403 secondary = 1;
404 while (secondary && !xmon_gate) {
405 if (in_xmon == 0) {
406 if (fromipi)
407 goto leave;
408 secondary = test_and_set_bit(0, &in_xmon);
409 }
410 barrier();
411 }
412
413 if (!secondary && !xmon_gate) {
414 /* we are the first cpu to come in */
415 /* interrupt other cpu(s) */
416 int ncpus = num_online_cpus();
417
418 xmon_owner = cpu;
419 mb();
420 if (ncpus > 1) {
421 smp_send_debugger_break(MSG_ALL_BUT_SELF);
422 /* wait for other cpus to come in */
423 for (timeout = 100000000; timeout != 0; --timeout) {
424 if (cpus_weight(cpus_in_xmon) >= ncpus)
425 break;
426 barrier();
427 }
428 }
429 remove_bpts();
430 disable_surveillance();
431 /* for breakpoint or single step, print the current instr. */
432 if (bp || TRAP(regs) == 0xd00)
433 ppc_inst_dump(regs->nip, 1, 0);
434 printf("enter ? for help\n");
435 mb();
436 xmon_gate = 1;
437 barrier();
438 }
439
440 cmdloop:
441 while (in_xmon) {
442 if (secondary) {
443 if (cpu == xmon_owner) {
444 if (!test_and_set_bit(0, &xmon_taken)) {
445 secondary = 0;
446 continue;
447 }
448 /* missed it */
449 while (cpu == xmon_owner)
450 barrier();
451 }
452 barrier();
453 } else {
454 cmd = cmds(regs);
455 if (cmd != 0) {
456 /* exiting xmon */
457 insert_bpts();
458 xmon_gate = 0;
459 wmb();
460 in_xmon = 0;
461 break;
462 }
463 /* have switched to some other cpu */
464 secondary = 1;
465 }
466 }
467 leave:
468 cpu_clear(cpu, cpus_in_xmon);
469 xmon_fault_jmp[cpu] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470#else
471 /* UP is simple... */
472 if (in_xmon) {
473 printf("Exception %lx %s in xmon, returning to main loop\n",
474 regs->trap, getvecname(TRAP(regs)));
475 longjmp(xmon_fault_jmp[0], 1);
476 }
477 if (setjmp(recurse_jmp) == 0) {
478 xmon_fault_jmp[0] = recurse_jmp;
479 in_xmon = 1;
480
481 excprint(regs);
482 bp = at_breakpoint(regs->nip);
483 if (bp) {
484 printf("Stopped at breakpoint %x (", BP_NUM(bp));
485 xmon_print_symbol(regs->nip, " ", ")\n");
486 }
487 if ((regs->msr & MSR_RI) == 0)
488 printf("WARNING: exception is not recoverable, "
489 "can't continue\n");
490 remove_bpts();
491 disable_surveillance();
492 /* for breakpoint or single step, print the current instr. */
493 if (bp || TRAP(regs) == 0xd00)
494 ppc_inst_dump(regs->nip, 1, 0);
495 printf("enter ? for help\n");
496 }
497
498 cmd = cmds(regs);
499
500 insert_bpts();
501 in_xmon = 0;
502#endif
503
504 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF)) {
505 bp = at_breakpoint(regs->nip);
506 if (bp != NULL) {
507 int stepped = emulate_step(regs, bp->instr[0]);
508 if (stepped == 0) {
509 regs->nip = (unsigned long) &bp->instr[0];
510 atomic_inc(&bp->ref_count);
511 } else if (stepped < 0) {
512 printf("Couldn't single-step %s instruction\n",
513 (IS_RFID(bp->instr[0])? "rfid": "mtmsrd"));
514 }
515 }
516 }
517
518 insert_cpu_bpts();
519
Anton Blanchardf13659e2007-03-21 01:48:34 +1100520 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521
Paul Mackerras0a730ae2006-10-03 21:32:49 +1000522 return cmd != 'X' && cmd != EOF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523}
524
525int xmon(struct pt_regs *excp)
526{
527 struct pt_regs regs;
528
529 if (excp == NULL) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000530 xmon_save_regs(&regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 excp = &regs;
532 }
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200533
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 return xmon_core(excp, 0);
535}
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000536EXPORT_SYMBOL(xmon);
537
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000538irqreturn_t xmon_irq(int irq, void *d)
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000539{
540 unsigned long flags;
541 local_irq_save(flags);
542 printf("Keyboard interrupt\n");
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000543 xmon(get_irq_regs());
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000544 local_irq_restore(flags);
545 return IRQ_HANDLED;
546}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000548static int xmon_bpt(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549{
550 struct bpt *bp;
551 unsigned long offset;
552
553 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF))
554 return 0;
555
556 /* Are we at the trap at bp->instr[1] for some bp? */
557 bp = in_breakpoint_table(regs->nip, &offset);
558 if (bp != NULL && offset == 4) {
559 regs->nip = bp->address + 4;
560 atomic_dec(&bp->ref_count);
561 return 1;
562 }
563
564 /* Are we at a breakpoint? */
565 bp = at_breakpoint(regs->nip);
566 if (!bp)
567 return 0;
568
569 xmon_core(regs, 0);
570
571 return 1;
572}
573
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000574static int xmon_sstep(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575{
576 if (user_mode(regs))
577 return 0;
578 xmon_core(regs, 0);
579 return 1;
580}
581
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000582static int xmon_dabr_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583{
584 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF))
585 return 0;
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000586 if (dabr.enabled == 0)
587 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 xmon_core(regs, 0);
589 return 1;
590}
591
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000592static int xmon_iabr_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593{
594 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF))
595 return 0;
596 if (iabr == 0)
597 return 0;
598 xmon_core(regs, 0);
599 return 1;
600}
601
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000602static int xmon_ipi(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603{
604#ifdef CONFIG_SMP
605 if (in_xmon && !cpu_isset(smp_processor_id(), cpus_in_xmon))
606 xmon_core(regs, 1);
607#endif
608 return 0;
609}
610
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000611static int xmon_fault_handler(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612{
613 struct bpt *bp;
614 unsigned long offset;
615
616 if (in_xmon && catch_memory_errors)
617 handle_fault(regs); /* doesn't return */
618
619 if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF)) {
620 bp = in_breakpoint_table(regs->nip, &offset);
621 if (bp != NULL) {
622 regs->nip = bp->address + offset;
623 atomic_dec(&bp->ref_count);
624 }
625 }
626
627 return 0;
628}
629
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630static struct bpt *at_breakpoint(unsigned long pc)
631{
632 int i;
633 struct bpt *bp;
634
635 bp = bpts;
636 for (i = 0; i < NBPTS; ++i, ++bp)
637 if (bp->enabled && pc == bp->address)
638 return bp;
639 return NULL;
640}
641
642static struct bpt *in_breakpoint_table(unsigned long nip, unsigned long *offp)
643{
644 unsigned long off;
645
646 off = nip - (unsigned long) bpts;
647 if (off >= sizeof(bpts))
648 return NULL;
649 off %= sizeof(struct bpt);
650 if (off != offsetof(struct bpt, instr[0])
651 && off != offsetof(struct bpt, instr[1]))
652 return NULL;
653 *offp = off - offsetof(struct bpt, instr[0]);
654 return (struct bpt *) (nip - off);
655}
656
657static struct bpt *new_breakpoint(unsigned long a)
658{
659 struct bpt *bp;
660
661 a &= ~3UL;
662 bp = at_breakpoint(a);
663 if (bp)
664 return bp;
665
666 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
667 if (!bp->enabled && atomic_read(&bp->ref_count) == 0) {
668 bp->address = a;
669 bp->instr[1] = bpinstr;
670 store_inst(&bp->instr[1]);
671 return bp;
672 }
673 }
674
675 printf("Sorry, no free breakpoints. Please clear one first.\n");
676 return NULL;
677}
678
679static void insert_bpts(void)
680{
681 int i;
682 struct bpt *bp;
683
684 bp = bpts;
685 for (i = 0; i < NBPTS; ++i, ++bp) {
686 if ((bp->enabled & (BP_TRAP|BP_IABR)) == 0)
687 continue;
688 if (mread(bp->address, &bp->instr[0], 4) != 4) {
689 printf("Couldn't read instruction at %lx, "
690 "disabling breakpoint there\n", bp->address);
691 bp->enabled = 0;
692 continue;
693 }
694 if (IS_MTMSRD(bp->instr[0]) || IS_RFID(bp->instr[0])) {
695 printf("Breakpoint at %lx is on an mtmsrd or rfid "
696 "instruction, disabling it\n", bp->address);
697 bp->enabled = 0;
698 continue;
699 }
700 store_inst(&bp->instr[0]);
701 if (bp->enabled & BP_IABR)
702 continue;
703 if (mwrite(bp->address, &bpinstr, 4) != 4) {
704 printf("Couldn't write instruction at %lx, "
705 "disabling breakpoint there\n", bp->address);
706 bp->enabled &= ~BP_TRAP;
707 continue;
708 }
709 store_inst((void *)bp->address);
710 }
711}
712
713static void insert_cpu_bpts(void)
714{
715 if (dabr.enabled)
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000716 set_dabr(dabr.address | (dabr.enabled & 7));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 if (iabr && cpu_has_feature(CPU_FTR_IABR))
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000718 mtspr(SPRN_IABR, iabr->address
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 | (iabr->enabled & (BP_IABR|BP_IABR_TE)));
720}
721
722static void remove_bpts(void)
723{
724 int i;
725 struct bpt *bp;
726 unsigned instr;
727
728 bp = bpts;
729 for (i = 0; i < NBPTS; ++i, ++bp) {
730 if ((bp->enabled & (BP_TRAP|BP_IABR)) != BP_TRAP)
731 continue;
732 if (mread(bp->address, &instr, 4) == 4
733 && instr == bpinstr
734 && mwrite(bp->address, &bp->instr, 4) != 4)
735 printf("Couldn't remove breakpoint at %lx\n",
736 bp->address);
737 else
738 store_inst((void *)bp->address);
739 }
740}
741
742static void remove_cpu_bpts(void)
743{
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000744 set_dabr(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 if (cpu_has_feature(CPU_FTR_IABR))
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000746 mtspr(SPRN_IABR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747}
748
749/* Command interpreting routine */
750static char *last_cmd;
751
752static int
753cmds(struct pt_regs *excp)
754{
755 int cmd = 0;
756
757 last_cmd = NULL;
758 xmon_regs = excp;
Olaf Hering26c8af52006-09-08 16:29:21 +0200759
760 if (!xmon_no_auto_backtrace) {
761 xmon_no_auto_backtrace = 1;
762 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
763 }
764
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 for(;;) {
766#ifdef CONFIG_SMP
767 printf("%x:", smp_processor_id());
768#endif /* CONFIG_SMP */
769 printf("mon> ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 flush_input();
771 termch = 0;
772 cmd = skipbl();
773 if( cmd == '\n' ) {
774 if (last_cmd == NULL)
775 continue;
776 take_input(last_cmd);
777 last_cmd = NULL;
778 cmd = inchar();
779 }
780 switch (cmd) {
781 case 'm':
782 cmd = inchar();
783 switch (cmd) {
784 case 'm':
785 case 's':
786 case 'd':
787 memops(cmd);
788 break;
789 case 'l':
790 memlocate();
791 break;
792 case 'z':
793 memzcan();
794 break;
795 case 'i':
796 show_mem();
797 break;
798 default:
799 termch = cmd;
800 memex();
801 }
802 break;
803 case 'd':
804 dump();
805 break;
806 case 'l':
807 symbol_lookup();
808 break;
809 case 'r':
810 prregs(excp); /* print regs */
811 break;
812 case 'e':
813 excprint(excp);
814 break;
815 case 'S':
816 super_regs();
817 break;
818 case 't':
819 backtrace(excp);
820 break;
821 case 'f':
822 cacheflush();
823 break;
824 case 's':
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200825 if (do_spu_cmd() == 0)
826 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 if (do_step(excp))
828 return cmd;
829 break;
830 case 'x':
831 case 'X':
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100832 return cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 case EOF:
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100834 printf(" <no input ...>\n");
835 mdelay(2000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 return cmd;
837 case '?':
Ishizaki Kou4d404ed2007-07-18 19:26:40 +1000838 xmon_puts(help_string);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 case 'b':
841 bpt_cmds();
842 break;
843 case 'C':
844 csum();
845 break;
846 case 'c':
847 if (cpu_cmd())
848 return 0;
849 break;
850 case 'z':
851 bootcmds();
852 break;
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000853 case 'p':
854 proccall();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 break;
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000856#ifdef CONFIG_PPC_STD_MMU
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 case 'u':
858 dump_segments();
859 break;
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000860#endif
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100861#ifdef CONFIG_4xx
862 case 'u':
863 dump_tlb_44x();
864 break;
865#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 default:
867 printf("Unrecognized command: ");
868 do {
869 if (' ' < cmd && cmd <= '~')
870 putchar(cmd);
871 else
872 printf("\\x%x", cmd);
873 cmd = inchar();
874 } while (cmd != '\n');
875 printf(" (type ? for help)\n");
876 break;
877 }
878 }
879}
880
881/*
882 * Step a single instruction.
883 * Some instructions we emulate, others we execute with MSR_SE set.
884 */
885static int do_step(struct pt_regs *regs)
886{
887 unsigned int instr;
888 int stepped;
889
890 /* check we are in 64-bit kernel mode, translation enabled */
891 if ((regs->msr & (MSR_SF|MSR_PR|MSR_IR)) == (MSR_SF|MSR_IR)) {
892 if (mread(regs->nip, &instr, 4) == 4) {
893 stepped = emulate_step(regs, instr);
894 if (stepped < 0) {
895 printf("Couldn't single-step %s instruction\n",
896 (IS_RFID(instr)? "rfid": "mtmsrd"));
897 return 0;
898 }
899 if (stepped > 0) {
900 regs->trap = 0xd00 | (regs->trap & 1);
901 printf("stepped to ");
902 xmon_print_symbol(regs->nip, " ", "\n");
903 ppc_inst_dump(regs->nip, 1, 0);
904 return 0;
905 }
906 }
907 }
908 regs->msr |= MSR_SE;
909 return 1;
910}
911
912static void bootcmds(void)
913{
914 int cmd;
915
916 cmd = inchar();
917 if (cmd == 'r')
918 ppc_md.restart(NULL);
919 else if (cmd == 'h')
920 ppc_md.halt();
921 else if (cmd == 'p')
922 ppc_md.power_off();
923}
924
925static int cpu_cmd(void)
926{
927#ifdef CONFIG_SMP
928 unsigned long cpu;
929 int timeout;
930 int count;
931
932 if (!scanhex(&cpu)) {
933 /* print cpus waiting or in xmon */
934 printf("cpus stopped:");
935 count = 0;
936 for (cpu = 0; cpu < NR_CPUS; ++cpu) {
937 if (cpu_isset(cpu, cpus_in_xmon)) {
938 if (count == 0)
939 printf(" %x", cpu);
940 ++count;
941 } else {
942 if (count > 1)
943 printf("-%x", cpu - 1);
944 count = 0;
945 }
946 }
947 if (count > 1)
948 printf("-%x", NR_CPUS - 1);
949 printf("\n");
950 return 0;
951 }
952 /* try to switch to cpu specified */
953 if (!cpu_isset(cpu, cpus_in_xmon)) {
954 printf("cpu 0x%x isn't in xmon\n", cpu);
955 return 0;
956 }
957 xmon_taken = 0;
958 mb();
959 xmon_owner = cpu;
960 timeout = 10000000;
961 while (!xmon_taken) {
962 if (--timeout == 0) {
963 if (test_and_set_bit(0, &xmon_taken))
964 break;
965 /* take control back */
966 mb();
967 xmon_owner = smp_processor_id();
968 printf("cpu %u didn't take control\n", cpu);
969 return 0;
970 }
971 barrier();
972 }
973 return 1;
974#else
975 return 0;
976#endif /* CONFIG_SMP */
977}
978
979static unsigned short fcstab[256] = {
980 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
981 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
982 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
983 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
984 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
985 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
986 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
987 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
988 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
989 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
990 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
991 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
992 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
993 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
994 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
995 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
996 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
997 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
998 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
999 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
1000 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
1001 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
1002 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
1003 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
1004 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
1005 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
1006 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
1007 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
1008 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
1009 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
1010 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
1011 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
1012};
1013
1014#define FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
1015
1016static void
1017csum(void)
1018{
1019 unsigned int i;
1020 unsigned short fcs;
1021 unsigned char v;
1022
1023 if (!scanhex(&adrs))
1024 return;
1025 if (!scanhex(&ncsum))
1026 return;
1027 fcs = 0xffff;
1028 for (i = 0; i < ncsum; ++i) {
1029 if (mread(adrs+i, &v, 1) == 0) {
1030 printf("csum stopped at %x\n", adrs+i);
1031 break;
1032 }
1033 fcs = FCS(fcs, v);
1034 }
1035 printf("%x\n", fcs);
1036}
1037
1038/*
1039 * Check if this is a suitable place to put a breakpoint.
1040 */
1041static long check_bp_loc(unsigned long addr)
1042{
1043 unsigned int instr;
1044
1045 addr &= ~3;
Michael Ellerman51fae6d2005-12-04 18:39:15 +11001046 if (!is_kernel_addr(addr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 printf("Breakpoints may only be placed at kernel addresses\n");
1048 return 0;
1049 }
1050 if (!mread(addr, &instr, sizeof(instr))) {
1051 printf("Can't read instruction at address %lx\n", addr);
1052 return 0;
1053 }
1054 if (IS_MTMSRD(instr) || IS_RFID(instr)) {
1055 printf("Breakpoints may not be placed on mtmsrd or rfid "
1056 "instructions\n");
1057 return 0;
1058 }
1059 return 1;
1060}
1061
1062static char *breakpoint_help_string =
1063 "Breakpoint command usage:\n"
1064 "b show breakpoints\n"
1065 "b <addr> [cnt] set breakpoint at given instr addr\n"
1066 "bc clear all breakpoints\n"
1067 "bc <n/addr> clear breakpoint number n or at addr\n"
1068 "bi <addr> [cnt] set hardware instr breakpoint (POWER3/RS64 only)\n"
1069 "bd <addr> [cnt] set hardware data breakpoint\n"
1070 "";
1071
1072static void
1073bpt_cmds(void)
1074{
1075 int cmd;
1076 unsigned long a;
1077 int mode, i;
1078 struct bpt *bp;
1079 const char badaddr[] = "Only kernel addresses are permitted "
1080 "for breakpoints\n";
1081
1082 cmd = inchar();
1083 switch (cmd) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001084#ifndef CONFIG_8xx
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 case 'd': /* bd - hardware data breakpoint */
1086 mode = 7;
1087 cmd = inchar();
1088 if (cmd == 'r')
1089 mode = 5;
1090 else if (cmd == 'w')
1091 mode = 6;
1092 else
1093 termch = cmd;
1094 dabr.address = 0;
1095 dabr.enabled = 0;
1096 if (scanhex(&dabr.address)) {
Michael Ellerman51fae6d2005-12-04 18:39:15 +11001097 if (!is_kernel_addr(dabr.address)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 printf(badaddr);
1099 break;
1100 }
1101 dabr.address &= ~7;
1102 dabr.enabled = mode | BP_DABR;
1103 }
1104 break;
1105
1106 case 'i': /* bi - hardware instr breakpoint */
1107 if (!cpu_has_feature(CPU_FTR_IABR)) {
1108 printf("Hardware instruction breakpoint "
1109 "not supported on this cpu\n");
1110 break;
1111 }
1112 if (iabr) {
1113 iabr->enabled &= ~(BP_IABR | BP_IABR_TE);
1114 iabr = NULL;
1115 }
1116 if (!scanhex(&a))
1117 break;
1118 if (!check_bp_loc(a))
1119 break;
1120 bp = new_breakpoint(a);
1121 if (bp != NULL) {
1122 bp->enabled |= BP_IABR | BP_IABR_TE;
1123 iabr = bp;
1124 }
1125 break;
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001126#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127
1128 case 'c':
1129 if (!scanhex(&a)) {
1130 /* clear all breakpoints */
1131 for (i = 0; i < NBPTS; ++i)
1132 bpts[i].enabled = 0;
1133 iabr = NULL;
1134 dabr.enabled = 0;
1135 printf("All breakpoints cleared\n");
1136 break;
1137 }
1138
1139 if (a <= NBPTS && a >= 1) {
1140 /* assume a breakpoint number */
1141 bp = &bpts[a-1]; /* bp nums are 1 based */
1142 } else {
1143 /* assume a breakpoint address */
1144 bp = at_breakpoint(a);
1145 if (bp == 0) {
1146 printf("No breakpoint at %x\n", a);
1147 break;
1148 }
1149 }
1150
1151 printf("Cleared breakpoint %x (", BP_NUM(bp));
1152 xmon_print_symbol(bp->address, " ", ")\n");
1153 bp->enabled = 0;
1154 break;
1155
1156 default:
1157 termch = cmd;
1158 cmd = skipbl();
1159 if (cmd == '?') {
1160 printf(breakpoint_help_string);
1161 break;
1162 }
1163 termch = cmd;
1164 if (!scanhex(&a)) {
1165 /* print all breakpoints */
1166 printf(" type address\n");
1167 if (dabr.enabled) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001168 printf(" data "REG" [", dabr.address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 if (dabr.enabled & 1)
1170 printf("r");
1171 if (dabr.enabled & 2)
1172 printf("w");
1173 printf("]\n");
1174 }
1175 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
1176 if (!bp->enabled)
1177 continue;
1178 printf("%2x %s ", BP_NUM(bp),
1179 (bp->enabled & BP_IABR)? "inst": "trap");
1180 xmon_print_symbol(bp->address, " ", "\n");
1181 }
1182 break;
1183 }
1184
1185 if (!check_bp_loc(a))
1186 break;
1187 bp = new_breakpoint(a);
1188 if (bp != NULL)
1189 bp->enabled |= BP_TRAP;
1190 break;
1191 }
1192}
1193
1194/* Very cheap human name for vector lookup. */
1195static
1196const char *getvecname(unsigned long vec)
1197{
1198 char *ret;
1199
1200 switch (vec) {
1201 case 0x100: ret = "(System Reset)"; break;
1202 case 0x200: ret = "(Machine Check)"; break;
1203 case 0x300: ret = "(Data Access)"; break;
1204 case 0x380: ret = "(Data SLB Access)"; break;
1205 case 0x400: ret = "(Instruction Access)"; break;
1206 case 0x480: ret = "(Instruction SLB Access)"; break;
1207 case 0x500: ret = "(Hardware Interrupt)"; break;
1208 case 0x600: ret = "(Alignment)"; break;
1209 case 0x700: ret = "(Program Check)"; break;
1210 case 0x800: ret = "(FPU Unavailable)"; break;
1211 case 0x900: ret = "(Decrementer)"; break;
1212 case 0xc00: ret = "(System Call)"; break;
1213 case 0xd00: ret = "(Single Step)"; break;
1214 case 0xf00: ret = "(Performance Monitor)"; break;
1215 case 0xf20: ret = "(Altivec Unavailable)"; break;
1216 case 0x1300: ret = "(Instruction Breakpoint)"; break;
1217 default: ret = "";
1218 }
1219 return ret;
1220}
1221
1222static void get_function_bounds(unsigned long pc, unsigned long *startp,
1223 unsigned long *endp)
1224{
1225 unsigned long size, offset;
1226 const char *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227
1228 *startp = *endp = 0;
1229 if (pc == 0)
1230 return;
1231 if (setjmp(bus_error_jmp) == 0) {
1232 catch_memory_errors = 1;
1233 sync();
Alexey Dobriyanffb45122007-05-08 00:28:41 -07001234 name = kallsyms_lookup(pc, &size, &offset, NULL, tmpstr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235 if (name != NULL) {
1236 *startp = pc - offset;
1237 *endp = pc - offset + size;
1238 }
1239 sync();
1240 }
1241 catch_memory_errors = 0;
1242}
1243
1244static int xmon_depth_to_print = 64;
1245
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001246#ifdef CONFIG_PPC64
1247#define LRSAVE_OFFSET 0x10
1248#define REG_FRAME_MARKER 0x7265677368657265ul /* "regshere" */
1249#define MARKER_OFFSET 0x60
1250#define REGS_OFFSET 0x70
1251#else
1252#define LRSAVE_OFFSET 4
1253#define REG_FRAME_MARKER 0x72656773
1254#define MARKER_OFFSET 8
1255#define REGS_OFFSET 16
1256#endif
1257
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258static void xmon_show_stack(unsigned long sp, unsigned long lr,
1259 unsigned long pc)
1260{
1261 unsigned long ip;
1262 unsigned long newsp;
1263 unsigned long marker;
1264 int count = 0;
1265 struct pt_regs regs;
1266
1267 do {
1268 if (sp < PAGE_OFFSET) {
1269 if (sp != 0)
1270 printf("SP (%lx) is in userspace\n", sp);
1271 break;
1272 }
1273
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001274 if (!mread(sp + LRSAVE_OFFSET, &ip, sizeof(unsigned long))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275 || !mread(sp, &newsp, sizeof(unsigned long))) {
1276 printf("Couldn't read stack frame at %lx\n", sp);
1277 break;
1278 }
1279
1280 /*
1281 * For the first stack frame, try to work out if
1282 * LR and/or the saved LR value in the bottommost
1283 * stack frame are valid.
1284 */
1285 if ((pc | lr) != 0) {
1286 unsigned long fnstart, fnend;
1287 unsigned long nextip;
1288 int printip = 1;
1289
1290 get_function_bounds(pc, &fnstart, &fnend);
1291 nextip = 0;
1292 if (newsp > sp)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001293 mread(newsp + LRSAVE_OFFSET, &nextip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 sizeof(unsigned long));
1295 if (lr == ip) {
1296 if (lr < PAGE_OFFSET
1297 || (fnstart <= lr && lr < fnend))
1298 printip = 0;
1299 } else if (lr == nextip) {
1300 printip = 0;
1301 } else if (lr >= PAGE_OFFSET
1302 && !(fnstart <= lr && lr < fnend)) {
1303 printf("[link register ] ");
1304 xmon_print_symbol(lr, " ", "\n");
1305 }
1306 if (printip) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001307 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 xmon_print_symbol(ip, " ", " (unreliable)\n");
1309 }
1310 pc = lr = 0;
1311
1312 } else {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001313 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 xmon_print_symbol(ip, " ", "\n");
1315 }
1316
1317 /* Look for "regshere" marker to see if this is
1318 an exception frame. */
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001319 if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long))
1320 && marker == REG_FRAME_MARKER) {
1321 if (mread(sp + REGS_OFFSET, &regs, sizeof(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 != sizeof(regs)) {
1323 printf("Couldn't read registers at %lx\n",
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001324 sp + REGS_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 break;
1326 }
1327 printf("--- Exception: %lx %s at ", regs.trap,
1328 getvecname(TRAP(&regs)));
1329 pc = regs.nip;
1330 lr = regs.link;
1331 xmon_print_symbol(pc, " ", "\n");
1332 }
1333
1334 if (newsp == 0)
1335 break;
1336
1337 sp = newsp;
1338 } while (count++ < xmon_depth_to_print);
1339}
1340
1341static void backtrace(struct pt_regs *excp)
1342{
1343 unsigned long sp;
1344
1345 if (scanhex(&sp))
1346 xmon_show_stack(sp, 0, 0);
1347 else
1348 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
1349 scannl();
1350}
1351
1352static void print_bug_trap(struct pt_regs *regs)
1353{
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001354 const struct bug_entry *bug;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 unsigned long addr;
1356
1357 if (regs->msr & MSR_PR)
1358 return; /* not in kernel */
1359 addr = regs->nip; /* address of trap instruction */
1360 if (addr < PAGE_OFFSET)
1361 return;
1362 bug = find_bug(regs->nip);
1363 if (bug == NULL)
1364 return;
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001365 if (is_warning_bug(bug))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 return;
1367
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001368#ifdef CONFIG_DEBUG_BUGVERBOSE
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001369 printf("kernel BUG at %s:%u!\n",
1370 bug->file, bug->line);
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001371#else
1372 printf("kernel BUG at %p!\n", (void *)bug->bug_addr);
1373#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374}
1375
1376void excprint(struct pt_regs *fp)
1377{
1378 unsigned long trap;
1379
1380#ifdef CONFIG_SMP
1381 printf("cpu 0x%x: ", smp_processor_id());
1382#endif /* CONFIG_SMP */
1383
1384 trap = TRAP(fp);
1385 printf("Vector: %lx %s at [%lx]\n", fp->trap, getvecname(trap), fp);
1386 printf(" pc: ");
1387 xmon_print_symbol(fp->nip, ": ", "\n");
1388
1389 printf(" lr: ", fp->link);
1390 xmon_print_symbol(fp->link, ": ", "\n");
1391
1392 printf(" sp: %lx\n", fp->gpr[1]);
1393 printf(" msr: %lx\n", fp->msr);
1394
1395 if (trap == 0x300 || trap == 0x380 || trap == 0x600) {
1396 printf(" dar: %lx\n", fp->dar);
1397 if (trap != 0x380)
1398 printf(" dsisr: %lx\n", fp->dsisr);
1399 }
1400
1401 printf(" current = 0x%lx\n", current);
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001402#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403 printf(" paca = 0x%lx\n", get_paca());
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001404#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405 if (current) {
1406 printf(" pid = %ld, comm = %s\n",
1407 current->pid, current->comm);
1408 }
1409
1410 if (trap == 0x700)
1411 print_bug_trap(fp);
1412}
1413
1414void prregs(struct pt_regs *fp)
1415{
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001416 int n, trap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417 unsigned long base;
1418 struct pt_regs regs;
1419
1420 if (scanhex(&base)) {
1421 if (setjmp(bus_error_jmp) == 0) {
1422 catch_memory_errors = 1;
1423 sync();
1424 regs = *(struct pt_regs *)base;
1425 sync();
1426 __delay(200);
1427 } else {
1428 catch_memory_errors = 0;
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001429 printf("*** Error reading registers from "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430 base);
1431 return;
1432 }
1433 catch_memory_errors = 0;
1434 fp = &regs;
1435 }
1436
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001437#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438 if (FULL_REGS(fp)) {
1439 for (n = 0; n < 16; ++n)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001440 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441 n, fp->gpr[n], n+16, fp->gpr[n+16]);
1442 } else {
1443 for (n = 0; n < 7; ++n)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001444 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445 n, fp->gpr[n], n+7, fp->gpr[n+7]);
1446 }
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001447#else
1448 for (n = 0; n < 32; ++n) {
1449 printf("R%.2d = %.8x%s", n, fp->gpr[n],
1450 (n & 3) == 3? "\n": " ");
1451 if (n == 12 && !FULL_REGS(fp)) {
1452 printf("\n");
1453 break;
1454 }
1455 }
1456#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457 printf("pc = ");
1458 xmon_print_symbol(fp->nip, " ", "\n");
1459 printf("lr = ");
1460 xmon_print_symbol(fp->link, " ", "\n");
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001461 printf("msr = "REG" cr = %.8lx\n", fp->msr, fp->ccr);
1462 printf("ctr = "REG" xer = "REG" trap = %4lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 fp->ctr, fp->xer, fp->trap);
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001464 trap = TRAP(fp);
1465 if (trap == 0x300 || trap == 0x380 || trap == 0x600)
1466 printf("dar = "REG" dsisr = %.8lx\n", fp->dar, fp->dsisr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467}
1468
1469void cacheflush(void)
1470{
1471 int cmd;
1472 unsigned long nflush;
1473
1474 cmd = inchar();
1475 if (cmd != 'i')
1476 termch = cmd;
1477 scanhex((void *)&adrs);
1478 if (termch != '\n')
1479 termch = 0;
1480 nflush = 1;
1481 scanhex(&nflush);
1482 nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES;
1483 if (setjmp(bus_error_jmp) == 0) {
1484 catch_memory_errors = 1;
1485 sync();
1486
1487 if (cmd != 'i') {
1488 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1489 cflush((void *) adrs);
1490 } else {
1491 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1492 cinval((void *) adrs);
1493 }
1494 sync();
1495 /* wait a little while to see if we get a machine check */
1496 __delay(200);
1497 }
1498 catch_memory_errors = 0;
1499}
1500
1501unsigned long
1502read_spr(int n)
1503{
1504 unsigned int instrs[2];
1505 unsigned long (*code)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 unsigned long ret = -1UL;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001507#ifdef CONFIG_PPC64
1508 unsigned long opd[3];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510 opd[0] = (unsigned long)instrs;
1511 opd[1] = 0;
1512 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001513 code = (unsigned long (*)(void)) opd;
1514#else
1515 code = (unsigned long (*)(void)) instrs;
1516#endif
1517
1518 /* mfspr r3,n; blr */
1519 instrs[0] = 0x7c6002a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1520 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 store_inst(instrs);
1522 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523
1524 if (setjmp(bus_error_jmp) == 0) {
1525 catch_memory_errors = 1;
1526 sync();
1527
1528 ret = code();
1529
1530 sync();
1531 /* wait a little while to see if we get a machine check */
1532 __delay(200);
1533 n = size;
1534 }
1535
1536 return ret;
1537}
1538
1539void
1540write_spr(int n, unsigned long val)
1541{
1542 unsigned int instrs[2];
1543 unsigned long (*code)(unsigned long);
Paul Mackerras548cceb2005-11-11 22:36:34 +11001544#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545 unsigned long opd[3];
1546
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 opd[0] = (unsigned long)instrs;
1548 opd[1] = 0;
1549 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001550 code = (unsigned long (*)(unsigned long)) opd;
1551#else
1552 code = (unsigned long (*)(unsigned long)) instrs;
1553#endif
1554
1555 instrs[0] = 0x7c6003a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1556 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 store_inst(instrs);
1558 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559
1560 if (setjmp(bus_error_jmp) == 0) {
1561 catch_memory_errors = 1;
1562 sync();
1563
1564 code(val);
1565
1566 sync();
1567 /* wait a little while to see if we get a machine check */
1568 __delay(200);
1569 n = size;
1570 }
1571}
1572
1573static unsigned long regno;
1574extern char exc_prolog;
1575extern char dec_exc;
1576
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001577void super_regs(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578{
1579 int cmd;
1580 unsigned long val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581
1582 cmd = skipbl();
1583 if (cmd == '\n') {
1584 unsigned long sp, toc;
1585 asm("mr %0,1" : "=r" (sp) :);
1586 asm("mr %0,2" : "=r" (toc) :);
1587
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001588 printf("msr = "REG" sprg0= "REG"\n",
1589 mfmsr(), mfspr(SPRN_SPRG0));
1590 printf("pvr = "REG" sprg1= "REG"\n",
1591 mfspr(SPRN_PVR), mfspr(SPRN_SPRG1));
1592 printf("dec = "REG" sprg2= "REG"\n",
1593 mfspr(SPRN_DEC), mfspr(SPRN_SPRG2));
1594 printf("sp = "REG" sprg3= "REG"\n", sp, mfspr(SPRN_SPRG3));
1595 printf("toc = "REG" dar = "REG"\n", toc, mfspr(SPRN_DAR));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596#ifdef CONFIG_PPC_ISERIES
Stephen Rothwell1d135812006-11-13 14:50:28 +11001597 if (firmware_has_feature(FW_FEATURE_ISERIES)) {
1598 struct paca_struct *ptrPaca;
1599 struct lppaca *ptrLpPaca;
Stephen Rothwell1d135812006-11-13 14:50:28 +11001600
1601 /* Dump out relevant Paca data areas. */
1602 printf("Paca: \n");
1603 ptrPaca = get_paca();
1604
1605 printf(" Local Processor Control Area (LpPaca): \n");
1606 ptrLpPaca = ptrPaca->lppaca_ptr;
1607 printf(" Saved Srr0=%.16lx Saved Srr1=%.16lx \n",
1608 ptrLpPaca->saved_srr0, ptrLpPaca->saved_srr1);
1609 printf(" Saved Gpr3=%.16lx Saved Gpr4=%.16lx \n",
1610 ptrLpPaca->saved_gpr3, ptrLpPaca->saved_gpr4);
1611 printf(" Saved Gpr5=%.16lx \n", ptrLpPaca->saved_gpr5);
Stephen Rothwell1d135812006-11-13 14:50:28 +11001612 }
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
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002070typedef int (*instruction_dump_func)(unsigned long inst, unsigned long addr);
2071
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002073generic_inst_dump(unsigned long adr, long count, int praddr,
2074 instruction_dump_func dump_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075{
2076 int nr, dotted;
2077 unsigned long first_adr;
2078 unsigned long inst, last_inst = 0;
2079 unsigned char val[4];
2080
2081 dotted = 0;
2082 for (first_adr = adr; count > 0; --count, adr += 4) {
2083 nr = mread(adr, val, 4);
2084 if (nr == 0) {
2085 if (praddr) {
2086 const char *x = fault_chars[fault_type];
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002087 printf(REG" %s%s%s%s\n", adr, x, x, x, x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002088 }
2089 break;
2090 }
2091 inst = GETWORD(val);
2092 if (adr > first_adr && inst == last_inst) {
2093 if (!dotted) {
2094 printf(" ...\n");
2095 dotted = 1;
2096 }
2097 continue;
2098 }
2099 dotted = 0;
2100 last_inst = inst;
2101 if (praddr)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002102 printf(REG" %.8x", adr, inst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103 printf("\t");
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002104 dump_func(inst, adr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105 printf("\n");
2106 }
2107 return adr - first_adr;
2108}
2109
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002110int
2111ppc_inst_dump(unsigned long adr, long count, int praddr)
2112{
2113 return generic_inst_dump(adr, count, praddr, print_insn_powerpc);
2114}
2115
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116void
2117print_address(unsigned long addr)
2118{
2119 xmon_print_symbol(addr, "\t# ", "");
2120}
2121
2122
2123/*
2124 * Memory operations - move, set, print differences
2125 */
2126static unsigned long mdest; /* destination address */
2127static unsigned long msrc; /* source address */
2128static unsigned long mval; /* byte value to set memory to */
2129static unsigned long mcount; /* # bytes to affect */
2130static unsigned long mdiffs; /* max # differences to print */
2131
2132void
2133memops(int cmd)
2134{
2135 scanhex((void *)&mdest);
2136 if( termch != '\n' )
2137 termch = 0;
2138 scanhex((void *)(cmd == 's'? &mval: &msrc));
2139 if( termch != '\n' )
2140 termch = 0;
2141 scanhex((void *)&mcount);
2142 switch( cmd ){
2143 case 'm':
2144 memmove((void *)mdest, (void *)msrc, mcount);
2145 break;
2146 case 's':
2147 memset((void *)mdest, mval, mcount);
2148 break;
2149 case 'd':
2150 if( termch != '\n' )
2151 termch = 0;
2152 scanhex((void *)&mdiffs);
2153 memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
2154 break;
2155 }
2156}
2157
2158void
2159memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
2160{
2161 unsigned n, prt;
2162
2163 prt = 0;
2164 for( n = nb; n > 0; --n )
2165 if( *p1++ != *p2++ )
2166 if( ++prt <= maxpr )
2167 printf("%.16x %.2x # %.16x %.2x\n", p1 - 1,
2168 p1[-1], p2 - 1, p2[-1]);
2169 if( prt > maxpr )
2170 printf("Total of %d differences\n", prt);
2171}
2172
2173static unsigned mend;
2174static unsigned mask;
2175
2176void
2177memlocate(void)
2178{
2179 unsigned a, n;
2180 unsigned char val[4];
2181
2182 last_cmd = "ml";
2183 scanhex((void *)&mdest);
2184 if (termch != '\n') {
2185 termch = 0;
2186 scanhex((void *)&mend);
2187 if (termch != '\n') {
2188 termch = 0;
2189 scanhex((void *)&mval);
2190 mask = ~0;
2191 if (termch != '\n') termch = 0;
2192 scanhex((void *)&mask);
2193 }
2194 }
2195 n = 0;
2196 for (a = mdest; a < mend; a += 4) {
2197 if (mread(a, val, 4) == 4
2198 && ((GETWORD(val) ^ mval) & mask) == 0) {
2199 printf("%.16x: %.16x\n", a, GETWORD(val));
2200 if (++n >= 10)
2201 break;
2202 }
2203 }
2204}
2205
2206static unsigned long mskip = 0x1000;
2207static unsigned long mlim = 0xffffffff;
2208
2209void
2210memzcan(void)
2211{
2212 unsigned char v;
2213 unsigned a;
2214 int ok, ook;
2215
2216 scanhex(&mdest);
2217 if (termch != '\n') termch = 0;
2218 scanhex(&mskip);
2219 if (termch != '\n') termch = 0;
2220 scanhex(&mlim);
2221 ook = 0;
2222 for (a = mdest; a < mlim; a += mskip) {
2223 ok = mread(a, &v, 1);
2224 if (ok && !ook) {
2225 printf("%.8x .. ", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226 } else if (!ok && ook)
2227 printf("%.8x\n", a - mskip);
2228 ook = ok;
2229 if (a + mskip < a)
2230 break;
2231 }
2232 if (ook)
2233 printf("%.8x\n", a - mskip);
2234}
2235
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002236void proccall(void)
2237{
2238 unsigned long args[8];
2239 unsigned long ret;
2240 int i;
2241 typedef unsigned long (*callfunc_t)(unsigned long, unsigned long,
2242 unsigned long, unsigned long, unsigned long,
2243 unsigned long, unsigned long, unsigned long);
2244 callfunc_t func;
2245
2246 if (!scanhex(&adrs))
2247 return;
2248 if (termch != '\n')
2249 termch = 0;
2250 for (i = 0; i < 8; ++i)
2251 args[i] = 0;
2252 for (i = 0; i < 8; ++i) {
2253 if (!scanhex(&args[i]) || termch == '\n')
2254 break;
2255 termch = 0;
2256 }
2257 func = (callfunc_t) adrs;
2258 ret = 0;
2259 if (setjmp(bus_error_jmp) == 0) {
2260 catch_memory_errors = 1;
2261 sync();
2262 ret = func(args[0], args[1], args[2], args[3],
2263 args[4], args[5], args[6], args[7]);
2264 sync();
2265 printf("return value is %x\n", ret);
2266 } else {
2267 printf("*** %x exception occurred\n", fault_except);
2268 }
2269 catch_memory_errors = 0;
2270}
2271
Linus Torvalds1da177e2005-04-16 15:20:36 -07002272/* Input scanning routines */
2273int
2274skipbl(void)
2275{
2276 int c;
2277
2278 if( termch != 0 ){
2279 c = termch;
2280 termch = 0;
2281 } else
2282 c = inchar();
2283 while( c == ' ' || c == '\t' )
2284 c = inchar();
2285 return c;
2286}
2287
2288#define N_PTREGS 44
2289static char *regnames[N_PTREGS] = {
2290 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
2291 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
2292 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
2293 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002294 "pc", "msr", "or3", "ctr", "lr", "xer", "ccr",
2295#ifdef CONFIG_PPC64
2296 "softe",
2297#else
2298 "mq",
2299#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300 "trap", "dar", "dsisr", "res"
2301};
2302
2303int
2304scanhex(unsigned long *vp)
2305{
2306 int c, d;
2307 unsigned long v;
2308
2309 c = skipbl();
2310 if (c == '%') {
2311 /* parse register name */
2312 char regname[8];
2313 int i;
2314
2315 for (i = 0; i < sizeof(regname) - 1; ++i) {
2316 c = inchar();
2317 if (!isalnum(c)) {
2318 termch = c;
2319 break;
2320 }
2321 regname[i] = c;
2322 }
2323 regname[i] = 0;
2324 for (i = 0; i < N_PTREGS; ++i) {
2325 if (strcmp(regnames[i], regname) == 0) {
2326 if (xmon_regs == NULL) {
2327 printf("regs not available\n");
2328 return 0;
2329 }
2330 *vp = ((unsigned long *)xmon_regs)[i];
2331 return 1;
2332 }
2333 }
2334 printf("invalid register name '%%%s'\n", regname);
2335 return 0;
2336 }
2337
2338 /* skip leading "0x" if any */
2339
2340 if (c == '0') {
2341 c = inchar();
2342 if (c == 'x') {
2343 c = inchar();
2344 } else {
2345 d = hexdigit(c);
2346 if (d == EOF) {
2347 termch = c;
2348 *vp = 0;
2349 return 1;
2350 }
2351 }
2352 } else if (c == '$') {
2353 int i;
2354 for (i=0; i<63; i++) {
2355 c = inchar();
2356 if (isspace(c)) {
2357 termch = c;
2358 break;
2359 }
2360 tmpstr[i] = c;
2361 }
2362 tmpstr[i++] = 0;
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07002363 *vp = 0;
2364 if (setjmp(bus_error_jmp) == 0) {
2365 catch_memory_errors = 1;
2366 sync();
2367 *vp = kallsyms_lookup_name(tmpstr);
2368 sync();
2369 }
2370 catch_memory_errors = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371 if (!(*vp)) {
2372 printf("unknown symbol '%s'\n", tmpstr);
2373 return 0;
2374 }
2375 return 1;
2376 }
2377
2378 d = hexdigit(c);
2379 if (d == EOF) {
2380 termch = c;
2381 return 0;
2382 }
2383 v = 0;
2384 do {
2385 v = (v << 4) + d;
2386 c = inchar();
2387 d = hexdigit(c);
2388 } while (d != EOF);
2389 termch = c;
2390 *vp = v;
2391 return 1;
2392}
2393
2394void
2395scannl(void)
2396{
2397 int c;
2398
2399 c = termch;
2400 termch = 0;
2401 while( c != '\n' )
2402 c = inchar();
2403}
2404
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002405int hexdigit(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406{
2407 if( '0' <= c && c <= '9' )
2408 return c - '0';
2409 if( 'A' <= c && c <= 'F' )
2410 return c - ('A' - 10);
2411 if( 'a' <= c && c <= 'f' )
2412 return c - ('a' - 10);
2413 return EOF;
2414}
2415
2416void
2417getstring(char *s, int size)
2418{
2419 int c;
2420
2421 c = skipbl();
2422 do {
2423 if( size > 1 ){
2424 *s++ = c;
2425 --size;
2426 }
2427 c = inchar();
2428 } while( c != ' ' && c != '\t' && c != '\n' );
2429 termch = c;
2430 *s = 0;
2431}
2432
2433static char line[256];
2434static char *lineptr;
2435
2436void
2437flush_input(void)
2438{
2439 lineptr = NULL;
2440}
2441
2442int
2443inchar(void)
2444{
2445 if (lineptr == NULL || *lineptr == 0) {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002446 if (xmon_gets(line, sizeof(line)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002447 lineptr = NULL;
2448 return EOF;
2449 }
2450 lineptr = line;
2451 }
2452 return *lineptr++;
2453}
2454
2455void
2456take_input(char *str)
2457{
2458 lineptr = str;
2459}
2460
2461
2462static void
2463symbol_lookup(void)
2464{
2465 int type = inchar();
2466 unsigned long addr;
2467 static char tmp[64];
2468
2469 switch (type) {
2470 case 'a':
2471 if (scanhex(&addr))
2472 xmon_print_symbol(addr, ": ", "\n");
2473 termch = 0;
2474 break;
2475 case 's':
2476 getstring(tmp, 64);
2477 if (setjmp(bus_error_jmp) == 0) {
2478 catch_memory_errors = 1;
2479 sync();
2480 addr = kallsyms_lookup_name(tmp);
2481 if (addr)
2482 printf("%s: %lx\n", tmp, addr);
2483 else
2484 printf("Symbol '%s' not found.\n", tmp);
2485 sync();
2486 }
2487 catch_memory_errors = 0;
2488 termch = 0;
2489 break;
2490 }
2491}
2492
2493
2494/* Print an address in numeric and symbolic form (if possible) */
2495static void xmon_print_symbol(unsigned long address, const char *mid,
2496 const char *after)
2497{
2498 char *modname;
2499 const char *name = NULL;
2500 unsigned long offset, size;
2501
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002502 printf(REG, address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002503 if (setjmp(bus_error_jmp) == 0) {
2504 catch_memory_errors = 1;
2505 sync();
2506 name = kallsyms_lookup(address, &size, &offset, &modname,
2507 tmpstr);
2508 sync();
2509 /* wait a little while to see if we get a machine check */
2510 __delay(200);
2511 }
2512
2513 catch_memory_errors = 0;
2514
2515 if (name) {
2516 printf("%s%s+%#lx/%#lx", mid, name, offset, size);
2517 if (modname)
2518 printf(" [%s]", modname);
2519 }
2520 printf("%s", after);
2521}
2522
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002523#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524static void dump_slb(void)
2525{
2526 int i;
will schmidtb3b95952007-12-07 08:22:23 +11002527 unsigned long esid,vsid,valid;
2528 unsigned long llp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529
2530 printf("SLB contents of cpu %x\n", smp_processor_id());
2531
Michael Neuling584f8b72007-12-06 17:24:48 +11002532 for (i = 0; i < mmu_slb_size; i++) {
will schmidtb3b95952007-12-07 08:22:23 +11002533 asm volatile("slbmfee %0,%1" : "=r" (esid) : "r" (i));
2534 asm volatile("slbmfev %0,%1" : "=r" (vsid) : "r" (i));
2535 valid = (esid & SLB_ESID_V);
2536 if (valid | esid | vsid) {
2537 printf("%02d %016lx %016lx", i, esid, vsid);
2538 if (valid) {
2539 llp = vsid & SLB_VSID_LLP;
2540 if (vsid & SLB_VSID_B_1T) {
2541 printf(" 1T ESID=%9lx VSID=%13lx LLP:%3lx \n",
2542 GET_ESID_1T(esid),
2543 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT_1T,
2544 llp);
2545 } else {
2546 printf(" 256M ESID=%9lx VSID=%13lx LLP:%3lx \n",
2547 GET_ESID(esid),
2548 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT,
2549 llp);
2550 }
2551 } else
2552 printf("\n");
2553 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554 }
2555}
2556
2557static void dump_stab(void)
2558{
2559 int i;
2560 unsigned long *tmp = (unsigned long *)get_paca()->stab_addr;
2561
2562 printf("Segment table contents of cpu %x\n", smp_processor_id());
2563
2564 for (i = 0; i < PAGE_SIZE/16; i++) {
2565 unsigned long a, b;
2566
2567 a = *tmp++;
2568 b = *tmp++;
2569
2570 if (a || b) {
2571 printf("%03d %016lx ", i, a);
2572 printf("%016lx\n", b);
2573 }
2574 }
2575}
2576
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002577void dump_segments(void)
2578{
2579 if (cpu_has_feature(CPU_FTR_SLB))
2580 dump_slb();
2581 else
2582 dump_stab();
2583}
2584#endif
2585
2586#ifdef CONFIG_PPC_STD_MMU_32
2587void dump_segments(void)
2588{
2589 int i;
2590
2591 printf("sr0-15 =");
2592 for (i = 0; i < 16; ++i)
2593 printf(" %x", mfsrin(i));
2594 printf("\n");
2595}
2596#endif
2597
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11002598#ifdef CONFIG_44x
2599static void dump_tlb_44x(void)
2600{
2601 int i;
2602
2603 for (i = 0; i < PPC44x_TLB_SIZE; i++) {
2604 unsigned long w0,w1,w2;
2605 asm volatile("tlbre %0,%1,0" : "=r" (w0) : "r" (i));
2606 asm volatile("tlbre %0,%1,1" : "=r" (w1) : "r" (i));
2607 asm volatile("tlbre %0,%1,2" : "=r" (w2) : "r" (i));
2608 printf("[%02x] %08x %08x %08x ", i, w0, w1, w2);
2609 if (w0 & PPC44x_TLB_VALID) {
2610 printf("V %08x -> %01x%08x %c%c%c%c%c",
2611 w0 & PPC44x_TLB_EPN_MASK,
2612 w1 & PPC44x_TLB_ERPN_MASK,
2613 w1 & PPC44x_TLB_RPN_MASK,
2614 (w2 & PPC44x_TLB_W) ? 'W' : 'w',
2615 (w2 & PPC44x_TLB_I) ? 'I' : 'i',
2616 (w2 & PPC44x_TLB_M) ? 'M' : 'm',
2617 (w2 & PPC44x_TLB_G) ? 'G' : 'g',
2618 (w2 & PPC44x_TLB_E) ? 'E' : 'e');
2619 }
2620 printf("\n");
2621 }
2622}
2623#endif /* CONFIG_44x */
Olaf Heringb13cfd12005-08-04 19:26:42 +02002624void xmon_init(int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625{
Stephen Rothwellbbb68172006-11-30 11:44:09 +11002626#ifdef CONFIG_PPC_ISERIES
2627 if (firmware_has_feature(FW_FEATURE_ISERIES))
2628 return;
2629#endif
Olaf Heringb13cfd12005-08-04 19:26:42 +02002630 if (enable) {
2631 __debugger = xmon;
2632 __debugger_ipi = xmon_ipi;
2633 __debugger_bpt = xmon_bpt;
2634 __debugger_sstep = xmon_sstep;
2635 __debugger_iabr_match = xmon_iabr_match;
2636 __debugger_dabr_match = xmon_dabr_match;
2637 __debugger_fault_handler = xmon_fault_handler;
2638 } else {
2639 __debugger = NULL;
2640 __debugger_ipi = NULL;
2641 __debugger_bpt = NULL;
2642 __debugger_sstep = NULL;
2643 __debugger_iabr_match = NULL;
2644 __debugger_dabr_match = NULL;
2645 __debugger_fault_handler = NULL;
2646 }
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002647 xmon_map_scc();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648}
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002649
2650#ifdef CONFIG_MAGIC_SYSRQ
David Howells7d12e782006-10-05 14:55:46 +01002651static void sysrq_handle_xmon(int key, struct tty_struct *tty)
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002652{
2653 /* ensure xmon is enabled */
2654 xmon_init(1);
David Howells7d12e782006-10-05 14:55:46 +01002655 debugger(get_irq_regs());
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002656}
2657
2658static struct sysrq_key_op sysrq_xmon_op =
2659{
2660 .handler = sysrq_handle_xmon,
2661 .help_msg = "Xmon",
2662 .action_msg = "Entering xmon",
2663};
2664
2665static int __init setup_xmon_sysrq(void)
2666{
Stephen Rothwellbbb68172006-11-30 11:44:09 +11002667#ifdef CONFIG_PPC_ISERIES
2668 if (firmware_has_feature(FW_FEATURE_ISERIES))
2669 return 0;
2670#endif
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002671 register_sysrq_key('x', &sysrq_xmon_op);
2672 return 0;
2673}
2674__initcall(setup_xmon_sysrq);
2675#endif /* CONFIG_MAGIC_SYSRQ */
Michael Ellerman476792832006-10-03 14:12:08 +10002676
Olaf Heringf5e6a282007-06-24 16:57:08 +10002677static int __initdata xmon_early, xmon_off;
Michael Ellerman476792832006-10-03 14:12:08 +10002678
2679static int __init early_parse_xmon(char *p)
2680{
2681 if (!p || strncmp(p, "early", 5) == 0) {
2682 /* just "xmon" is equivalent to "xmon=early" */
2683 xmon_init(1);
2684 xmon_early = 1;
2685 } else if (strncmp(p, "on", 2) == 0)
2686 xmon_init(1);
2687 else if (strncmp(p, "off", 3) == 0)
2688 xmon_off = 1;
2689 else if (strncmp(p, "nobt", 4) == 0)
2690 xmon_no_auto_backtrace = 1;
2691 else
2692 return 1;
2693
2694 return 0;
2695}
2696early_param("xmon", early_parse_xmon);
2697
2698void __init xmon_setup(void)
2699{
2700#ifdef CONFIG_XMON_DEFAULT
2701 if (!xmon_off)
2702 xmon_init(1);
2703#endif
2704 if (xmon_early)
2705 debugger(NULL);
2706}
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002707
Arnd Bergmanne0555952006-11-27 19:18:55 +01002708#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002709
2710struct spu_info {
2711 struct spu *spu;
2712 u64 saved_mfc_sr1_RW;
2713 u32 saved_spu_runcntl_RW;
Michael Ellerman24a24c82006-11-23 00:46:41 +01002714 unsigned long dump_addr;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002715 u8 stopped_ok;
2716};
2717
2718#define XMON_NUM_SPUS 16 /* Enough for current hardware */
2719
2720static struct spu_info spu_info[XMON_NUM_SPUS];
2721
2722void xmon_register_spus(struct list_head *list)
2723{
2724 struct spu *spu;
2725
2726 list_for_each_entry(spu, list, full_list) {
2727 if (spu->number >= XMON_NUM_SPUS) {
2728 WARN_ON(1);
2729 continue;
2730 }
2731
2732 spu_info[spu->number].spu = spu;
2733 spu_info[spu->number].stopped_ok = 0;
Michael Ellerman24a24c82006-11-23 00:46:41 +01002734 spu_info[spu->number].dump_addr = (unsigned long)
2735 spu_info[spu->number].spu->local_store;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002736 }
2737}
2738
2739static void stop_spus(void)
2740{
2741 struct spu *spu;
2742 int i;
2743 u64 tmp;
2744
2745 for (i = 0; i < XMON_NUM_SPUS; i++) {
2746 if (!spu_info[i].spu)
2747 continue;
2748
2749 if (setjmp(bus_error_jmp) == 0) {
2750 catch_memory_errors = 1;
2751 sync();
2752
2753 spu = spu_info[i].spu;
2754
2755 spu_info[i].saved_spu_runcntl_RW =
2756 in_be32(&spu->problem->spu_runcntl_RW);
2757
2758 tmp = spu_mfc_sr1_get(spu);
2759 spu_info[i].saved_mfc_sr1_RW = tmp;
2760
2761 tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
2762 spu_mfc_sr1_set(spu, tmp);
2763
2764 sync();
2765 __delay(200);
2766
2767 spu_info[i].stopped_ok = 1;
Michael Ellerman2a144422006-11-23 00:46:40 +01002768
2769 printf("Stopped spu %.2d (was %s)\n", i,
2770 spu_info[i].saved_spu_runcntl_RW ?
2771 "running" : "stopped");
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002772 } else {
2773 catch_memory_errors = 0;
2774 printf("*** Error stopping spu %.2d\n", i);
2775 }
2776 catch_memory_errors = 0;
2777 }
2778}
2779
2780static void restart_spus(void)
2781{
2782 struct spu *spu;
2783 int i;
2784
2785 for (i = 0; i < XMON_NUM_SPUS; i++) {
2786 if (!spu_info[i].spu)
2787 continue;
2788
2789 if (!spu_info[i].stopped_ok) {
2790 printf("*** Error, spu %d was not successfully stopped"
2791 ", not restarting\n", i);
2792 continue;
2793 }
2794
2795 if (setjmp(bus_error_jmp) == 0) {
2796 catch_memory_errors = 1;
2797 sync();
2798
2799 spu = spu_info[i].spu;
2800 spu_mfc_sr1_set(spu, spu_info[i].saved_mfc_sr1_RW);
2801 out_be32(&spu->problem->spu_runcntl_RW,
2802 spu_info[i].saved_spu_runcntl_RW);
2803
2804 sync();
2805 __delay(200);
2806
2807 printf("Restarted spu %.2d\n", i);
2808 } else {
2809 catch_memory_errors = 0;
2810 printf("*** Error restarting spu %.2d\n", i);
2811 }
2812 catch_memory_errors = 0;
2813 }
2814}
2815
Michael Ellermana8984972006-10-24 18:31:28 +02002816#define DUMP_WIDTH 23
Michael Ellerman437a0702006-11-23 00:46:39 +01002817#define DUMP_VALUE(format, field, value) \
Michael Ellermana8984972006-10-24 18:31:28 +02002818do { \
2819 if (setjmp(bus_error_jmp) == 0) { \
2820 catch_memory_errors = 1; \
2821 sync(); \
2822 printf(" %-*s = "format"\n", DUMP_WIDTH, \
Michael Ellerman437a0702006-11-23 00:46:39 +01002823 #field, value); \
Michael Ellermana8984972006-10-24 18:31:28 +02002824 sync(); \
2825 __delay(200); \
2826 } else { \
2827 catch_memory_errors = 0; \
2828 printf(" %-*s = *** Error reading field.\n", \
2829 DUMP_WIDTH, #field); \
2830 } \
2831 catch_memory_errors = 0; \
2832} while (0)
2833
Michael Ellerman437a0702006-11-23 00:46:39 +01002834#define DUMP_FIELD(obj, format, field) \
2835 DUMP_VALUE(format, field, obj->field)
2836
Michael Ellermana8984972006-10-24 18:31:28 +02002837static void dump_spu_fields(struct spu *spu)
2838{
2839 printf("Dumping spu fields at address %p:\n", spu);
2840
2841 DUMP_FIELD(spu, "0x%x", number);
2842 DUMP_FIELD(spu, "%s", name);
Michael Ellermana8984972006-10-24 18:31:28 +02002843 DUMP_FIELD(spu, "0x%lx", local_store_phys);
2844 DUMP_FIELD(spu, "0x%p", local_store);
2845 DUMP_FIELD(spu, "0x%lx", ls_size);
2846 DUMP_FIELD(spu, "0x%x", node);
2847 DUMP_FIELD(spu, "0x%lx", flags);
2848 DUMP_FIELD(spu, "0x%lx", dar);
2849 DUMP_FIELD(spu, "0x%lx", dsisr);
2850 DUMP_FIELD(spu, "%d", class_0_pending);
2851 DUMP_FIELD(spu, "0x%lx", irqs[0]);
2852 DUMP_FIELD(spu, "0x%lx", irqs[1]);
2853 DUMP_FIELD(spu, "0x%lx", irqs[2]);
2854 DUMP_FIELD(spu, "0x%x", slb_replace);
2855 DUMP_FIELD(spu, "%d", pid);
Michael Ellermana8984972006-10-24 18:31:28 +02002856 DUMP_FIELD(spu, "0x%p", mm);
2857 DUMP_FIELD(spu, "0x%p", ctx);
2858 DUMP_FIELD(spu, "0x%p", rq);
2859 DUMP_FIELD(spu, "0x%p", timestamp);
2860 DUMP_FIELD(spu, "0x%lx", problem_phys);
2861 DUMP_FIELD(spu, "0x%p", problem);
Michael Ellerman437a0702006-11-23 00:46:39 +01002862 DUMP_VALUE("0x%x", problem->spu_runcntl_RW,
2863 in_be32(&spu->problem->spu_runcntl_RW));
2864 DUMP_VALUE("0x%x", problem->spu_status_R,
2865 in_be32(&spu->problem->spu_status_R));
2866 DUMP_VALUE("0x%x", problem->spu_npc_RW,
2867 in_be32(&spu->problem->spu_npc_RW));
Michael Ellermana8984972006-10-24 18:31:28 +02002868 DUMP_FIELD(spu, "0x%p", priv2);
Michael Ellermana9852392006-11-23 00:46:50 +01002869 DUMP_FIELD(spu, "0x%p", pdata);
Michael Ellermana8984972006-10-24 18:31:28 +02002870}
2871
Michael Ellermanaf89fb82006-11-23 00:46:44 +01002872int
2873spu_inst_dump(unsigned long adr, long count, int praddr)
2874{
2875 return generic_inst_dump(adr, count, praddr, print_insn_spu);
2876}
2877
2878static void dump_spu_ls(unsigned long num, int subcmd)
Michael Ellerman24a24c82006-11-23 00:46:41 +01002879{
2880 unsigned long offset, addr, ls_addr;
2881
2882 if (setjmp(bus_error_jmp) == 0) {
2883 catch_memory_errors = 1;
2884 sync();
2885 ls_addr = (unsigned long)spu_info[num].spu->local_store;
2886 sync();
2887 __delay(200);
2888 } else {
2889 catch_memory_errors = 0;
2890 printf("*** Error: accessing spu info for spu %d\n", num);
2891 return;
2892 }
2893 catch_memory_errors = 0;
2894
2895 if (scanhex(&offset))
2896 addr = ls_addr + offset;
2897 else
2898 addr = spu_info[num].dump_addr;
2899
2900 if (addr >= ls_addr + LS_SIZE) {
2901 printf("*** Error: address outside of local store\n");
2902 return;
2903 }
2904
Michael Ellermanaf89fb82006-11-23 00:46:44 +01002905 switch (subcmd) {
2906 case 'i':
2907 addr += spu_inst_dump(addr, 16, 1);
2908 last_cmd = "sdi\n";
2909 break;
2910 default:
2911 prdump(addr, 64);
2912 addr += 64;
2913 last_cmd = "sd\n";
2914 break;
2915 }
Michael Ellerman24a24c82006-11-23 00:46:41 +01002916
2917 spu_info[num].dump_addr = addr;
2918}
2919
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002920static int do_spu_cmd(void)
2921{
Michael Ellerman24a24c82006-11-23 00:46:41 +01002922 static unsigned long num = 0;
Michael Ellermanaf89fb82006-11-23 00:46:44 +01002923 int cmd, subcmd = 0;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002924
2925 cmd = inchar();
2926 switch (cmd) {
2927 case 's':
2928 stop_spus();
2929 break;
2930 case 'r':
2931 restart_spus();
2932 break;
Michael Ellerman24a24c82006-11-23 00:46:41 +01002933 case 'd':
Michael Ellermanaf89fb82006-11-23 00:46:44 +01002934 subcmd = inchar();
2935 if (isxdigit(subcmd) || subcmd == '\n')
2936 termch = subcmd;
2937 case 'f':
Michael Ellerman24a24c82006-11-23 00:46:41 +01002938 scanhex(&num);
2939 if (num >= XMON_NUM_SPUS || !spu_info[num].spu) {
Michael Ellermana8984972006-10-24 18:31:28 +02002940 printf("*** Error: invalid spu number\n");
Michael Ellerman24a24c82006-11-23 00:46:41 +01002941 return 0;
2942 }
2943
2944 switch (cmd) {
2945 case 'f':
2946 dump_spu_fields(spu_info[num].spu);
2947 break;
2948 default:
Michael Ellermanaf89fb82006-11-23 00:46:44 +01002949 dump_spu_ls(num, subcmd);
Michael Ellerman24a24c82006-11-23 00:46:41 +01002950 break;
2951 }
2952
Michael Ellermana8984972006-10-24 18:31:28 +02002953 break;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002954 default:
2955 return -1;
2956 }
2957
2958 return 0;
2959}
Arnd Bergmanne0555952006-11-27 19:18:55 +01002960#else /* ! CONFIG_SPU_BASE */
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002961static int do_spu_cmd(void)
2962{
2963 return -1;
2964}
2965#endif