blob: 3a56a639a92e88962a0b7c1274e9d8330d6e218e [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>
Michael Ellermanca5dd392012-08-23 22:09:12 +000020#include <linux/kmsg_dump.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <linux/cpumask.h>
Paul Gortmaker4b16f8e2011-07-22 18:24:23 -040022#include <linux/export.h>
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +110023#include <linux/sysrq.h>
Andrew Morton4694ca02005-11-13 16:06:50 -080024#include <linux/interrupt.h>
David Howells7d12e782006-10-05 14:55:46 +010025#include <linux/irq.h>
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -080026#include <linux/bug.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070027
28#include <asm/ptrace.h>
29#include <asm/string.h>
30#include <asm/prom.h>
31#include <asm/machdep.h>
Paul Mackerrasf78541d2005-10-28 22:53:37 +100032#include <asm/xmon.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <asm/processor.h>
34#include <asm/pgtable.h>
35#include <asm/mmu.h>
36#include <asm/mmu_context.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#include <asm/cputable.h>
38#include <asm/rtas.h>
39#include <asm/sstep.h>
Paul Mackerrasf583ffc2006-10-10 11:47:07 +100040#include <asm/irq_regs.h>
Michael Ellermanff8a8f22006-10-24 18:31:27 +020041#include <asm/spu.h>
42#include <asm/spu_priv1.h>
Michael Neulingc3b75bd2008-01-18 15:50:30 +110043#include <asm/setjmp.h>
Anton Vorontsov322b4392008-12-17 10:08:55 +000044#include <asm/reg.h>
David Howellsae3a1972012-03-28 18:30:02 +010045#include <asm/debug.h>
Paul Mackerrasf78541d2005-10-28 22:53:37 +100046
47#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -070048#include <asm/hvcall.h>
Paul Mackerrasf78541d2005-10-28 22:53:37 +100049#include <asm/paca.h>
50#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
52#include "nonstdio.h"
Michael Ellermane0426042006-11-23 00:46:45 +010053#include "dis-asm.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070054
55#define scanhex xmon_scanhex
56#define skipbl xmon_skipbl
57
58#ifdef CONFIG_SMP
Michael Ellerman1c8950f2008-05-08 14:27:17 +100059static cpumask_t cpus_in_xmon = CPU_MASK_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070060static unsigned long xmon_taken = 1;
61static int xmon_owner;
62static int xmon_gate;
Michael Ellermanddadb6b2012-09-13 23:01:31 +000063#else
64#define xmon_owner 0
Linus Torvalds1da177e2005-04-16 15:20:36 -070065#endif /* CONFIG_SMP */
66
Anton Blanchard5be34922010-01-12 00:50:14 +000067static unsigned long in_xmon __read_mostly = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
69static unsigned long adrs;
70static int size = 1;
71#define MAX_DUMP (128 * 1024)
72static unsigned long ndump = 64;
73static unsigned long nidump = 16;
74static unsigned long ncsum = 4096;
75static int termch;
76static char tmpstr[128];
77
Linus Torvalds1da177e2005-04-16 15:20:36 -070078static long bus_error_jmp[JMP_BUF_LEN];
79static int catch_memory_errors;
80static long *xmon_fault_jmp[NR_CPUS];
Linus Torvalds1da177e2005-04-16 15:20:36 -070081
82/* Breakpoint stuff */
83struct bpt {
84 unsigned long address;
85 unsigned int instr[2];
86 atomic_t ref_count;
87 int enabled;
88 unsigned long pad;
89};
90
91/* Bits in bpt.enabled */
92#define BP_IABR_TE 1 /* IABR translation enabled */
93#define BP_IABR 2
94#define BP_TRAP 8
95#define BP_DABR 0x10
96
97#define NBPTS 256
98static struct bpt bpts[NBPTS];
99static struct bpt dabr;
100static struct bpt *iabr;
101static unsigned bpinstr = 0x7fe00008; /* trap */
102
103#define BP_NUM(bp) ((bp) - bpts + 1)
104
105/* Prototypes */
106static int cmds(struct pt_regs *);
107static int mread(unsigned long, void *, int);
108static int mwrite(unsigned long, void *, int);
109static int handle_fault(struct pt_regs *);
110static void byterev(unsigned char *, int);
111static void memex(void);
112static int bsesc(void);
113static void dump(void);
114static void prdump(unsigned long, long);
115static int ppc_inst_dump(unsigned long, long, int);
Vinay Sridharf312deb2009-05-14 23:13:07 +0000116static void dump_log_buf(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117static void backtrace(struct pt_regs *);
118static void excprint(struct pt_regs *);
119static void prregs(struct pt_regs *);
120static void memops(int);
121static void memlocate(void);
122static void memzcan(void);
123static void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned);
124int skipbl(void);
125int scanhex(unsigned long *valp);
126static void scannl(void);
127static int hexdigit(int);
128void getstring(char *, int);
129static void flush_input(void);
130static int inchar(void);
131static void take_input(char *);
132static unsigned long read_spr(int);
133static void write_spr(int, unsigned long);
134static void super_regs(void);
135static void remove_bpts(void);
136static void insert_bpts(void);
137static void remove_cpu_bpts(void);
138static void insert_cpu_bpts(void);
139static struct bpt *at_breakpoint(unsigned long pc);
140static struct bpt *in_breakpoint_table(unsigned long pc, unsigned long *offp);
141static int do_step(struct pt_regs *);
142static void bpt_cmds(void);
143static void cacheflush(void);
144static int cpu_cmd(void);
145static void csum(void);
146static void bootcmds(void);
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000147static void proccall(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148void dump_segments(void);
149static void symbol_lookup(void);
Olaf Hering26c8af52006-09-08 16:29:21 +0200150static void xmon_show_stack(unsigned long sp, unsigned long lr,
151 unsigned long pc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152static void xmon_print_symbol(unsigned long address, const char *mid,
153 const char *after);
154static const char *getvecname(unsigned long vec);
155
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200156static int do_spu_cmd(void);
157
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100158#ifdef CONFIG_44x
159static void dump_tlb_44x(void);
160#endif
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +1000161#ifdef CONFIG_PPC_BOOK3E
162static void dump_tlb_book3e(void);
163#endif
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100164
Michael Ellerman9f1067c22008-05-08 14:27:16 +1000165static int xmon_no_auto_backtrace;
Olaf Hering26c8af52006-09-08 16:29:21 +0200166
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000167extern void xmon_enter(void);
168extern void xmon_leave(void);
169
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000170#ifdef CONFIG_PPC64
171#define REG "%.16lx"
172#define REGS_PER_LINE 4
173#define LAST_VOLATILE 13
174#else
175#define REG "%.8lx"
176#define REGS_PER_LINE 8
177#define LAST_VOLATILE 12
178#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179
180#define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
181
182#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
183 || ('a' <= (c) && (c) <= 'f') \
184 || ('A' <= (c) && (c) <= 'F'))
185#define isalnum(c) (('0' <= (c) && (c) <= '9') \
186 || ('a' <= (c) && (c) <= 'z') \
187 || ('A' <= (c) && (c) <= 'Z'))
188#define isspace(c) (c == ' ' || c == '\t' || c == 10 || c == 13 || c == 0)
189
190static char *help_string = "\
191Commands:\n\
192 b show breakpoints\n\
193 bd set data breakpoint\n\
194 bi set instruction breakpoint\n\
195 bc clear breakpoint\n"
196#ifdef CONFIG_SMP
197 "\
198 c print cpus stopped in xmon\n\
199 c# try to switch to cpu number h (in hex)\n"
200#endif
201 "\
202 C checksum\n\
203 d dump bytes\n\
204 di dump instructions\n\
205 df dump float values\n\
206 dd dump double values\n\
Michael Ellermanddadb6b2012-09-13 23:01:31 +0000207 dl dump the kernel log buffer\n"
208#ifdef CONFIG_PPC64
209 "\
210 dp[#] dump paca for current cpu, or cpu #\n\
211 dpa dump paca for all possible cpus\n"
212#endif
213 "\
Olaf Hering7e5b5932006-03-08 20:40:28 +0100214 dr dump stream of raw bytes\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 e print exception information\n\
216 f flush cache\n\
217 la lookup symbol+offset of specified address\n\
218 ls lookup address of specified symbol\n\
219 m examine/change memory\n\
220 mm move a block of memory\n\
221 ms set a block of memory\n\
222 md compare two blocks of memory\n\
223 ml locate a block of memory\n\
224 mz zero a block of memory\n\
225 mi show information about memory allocation\n\
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000226 p call a procedure\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 r print registers\n\
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200228 s single step\n"
Arnd Bergmanne0555952006-11-27 19:18:55 +0100229#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200230" ss stop execution on all spus\n\
Michael Ellermana8984972006-10-24 18:31:28 +0200231 sr restore execution on stopped spus\n\
Michael Ellerman24a24c82006-11-23 00:46:41 +0100232 sf # dump spu fields for spu # (in hex)\n\
Michael Ellermanc99176a2007-02-26 18:14:06 +0900233 sd # dump spu local store for spu # (in hex)\n\
Michael Ellermanaf89fb82006-11-23 00:46:44 +0100234 sdi # disassemble spu local store for spu # (in hex)\n"
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200235#endif
236" S print special registers\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 t print backtrace\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 x exit monitor and recover\n\
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000239 X exit monitor and dont recover\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000240#if defined(CONFIG_PPC64) && !defined(CONFIG_PPC_BOOK3E)
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000241" u dump segment table or SLB\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000242#elif defined(CONFIG_PPC_STD_MMU_32)
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000243" u dump segment registers\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000244#elif defined(CONFIG_44x) || defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100245" u dump TLB\n"
246#endif
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000247" ? help\n"
248" zr reboot\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 zh halt\n"
250;
251
252static struct pt_regs *xmon_regs;
253
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000254static inline void sync(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255{
256 asm volatile("sync; isync");
257}
258
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000259static inline void store_inst(void *p)
260{
261 asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p));
262}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000264static inline void cflush(void *p)
265{
266 asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p));
267}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000269static inline void cinval(void *p)
270{
271 asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p));
272}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273
274/*
275 * Disable surveillance (the service processor watchdog function)
276 * while we are in xmon.
277 * XXX we should re-enable it when we leave. :)
278 */
279#define SURVEILLANCE_TOKEN 9000
280
281static inline void disable_surveillance(void)
282{
283#ifdef CONFIG_PPC_PSERIES
284 /* Since this can't be a module, args should end up below 4GB. */
285 static struct rtas_args args;
286
287 /*
288 * At this point we have got all the cpus we can into
289 * xmon, so there is hopefully no other cpu calling RTAS
290 * at the moment, even though we don't take rtas.lock.
291 * If we did try to take rtas.lock there would be a
292 * real possibility of deadlock.
293 */
294 args.token = rtas_token("set-indicator");
295 if (args.token == RTAS_UNKNOWN_SERVICE)
296 return;
297 args.nargs = 3;
298 args.nret = 1;
299 args.rets = &args.args[3];
300 args.args[0] = SURVEILLANCE_TOKEN;
301 args.args[1] = 0;
302 args.args[2] = 0;
303 enter_rtas(__pa(&args));
304#endif /* CONFIG_PPC_PSERIES */
305}
306
307#ifdef CONFIG_SMP
308static int xmon_speaker;
309
310static void get_output_lock(void)
311{
312 int me = smp_processor_id() + 0x100;
313 int last_speaker = 0, prev;
314 long timeout;
315
316 if (xmon_speaker == me)
317 return;
318 for (;;) {
319 if (xmon_speaker == 0) {
320 last_speaker = cmpxchg(&xmon_speaker, 0, me);
321 if (last_speaker == 0)
322 return;
323 }
324 timeout = 10000000;
325 while (xmon_speaker == last_speaker) {
326 if (--timeout > 0)
327 continue;
328 /* hostile takeover */
329 prev = cmpxchg(&xmon_speaker, last_speaker, me);
330 if (prev == last_speaker)
331 return;
332 break;
333 }
334 }
335}
336
337static void release_output_lock(void)
338{
339 xmon_speaker = 0;
340}
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000341
342int cpus_are_in_xmon(void)
343{
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000344 return !cpumask_empty(&cpus_in_xmon);
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000345}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346#endif
347
Josh Boyerdaf8f402009-09-23 03:51:04 +0000348static inline int unrecoverable_excp(struct pt_regs *regs)
349{
Jimi Xenidis08f6d6a2011-09-29 12:05:28 +0000350#if defined(CONFIG_4xx) || defined(CONFIG_PPC_BOOK3E)
Jimi Xenidis66857b32011-09-23 05:40:46 +0000351 /* We have no MSR_RI bit on 4xx or Book3e, so we simply return false */
Josh Boyerdaf8f402009-09-23 03:51:04 +0000352 return 0;
353#else
354 return ((regs->msr & MSR_RI) == 0);
355#endif
356}
357
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000358static int xmon_core(struct pt_regs *regs, int fromipi)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359{
360 int cmd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 struct bpt *bp;
362 long recurse_jmp[JMP_BUF_LEN];
363 unsigned long offset;
Anton Blanchardf13659e2007-03-21 01:48:34 +1100364 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365#ifdef CONFIG_SMP
366 int cpu;
367 int secondary;
368 unsigned long timeout;
369#endif
370
Anton Blanchardf13659e2007-03-21 01:48:34 +1100371 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372
373 bp = in_breakpoint_table(regs->nip, &offset);
374 if (bp != NULL) {
375 regs->nip = bp->address + offset;
376 atomic_dec(&bp->ref_count);
377 }
378
379 remove_cpu_bpts();
380
381#ifdef CONFIG_SMP
382 cpu = smp_processor_id();
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000383 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 get_output_lock();
385 excprint(regs);
386 printf("cpu 0x%x: Exception %lx %s in xmon, "
387 "returning to main loop\n",
388 cpu, regs->trap, getvecname(TRAP(regs)));
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000389 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 longjmp(xmon_fault_jmp[cpu], 1);
391 }
392
393 if (setjmp(recurse_jmp) != 0) {
394 if (!in_xmon || !xmon_gate) {
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000395 get_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 printf("xmon: WARNING: bad recursive fault "
397 "on cpu 0x%x\n", cpu);
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000398 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 goto waiting;
400 }
401 secondary = !(xmon_taken && cpu == xmon_owner);
402 goto cmdloop;
403 }
404
405 xmon_fault_jmp[cpu] = recurse_jmp;
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000406 cpumask_set_cpu(cpu, &cpus_in_xmon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407
408 bp = NULL;
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000409 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 bp = at_breakpoint(regs->nip);
Josh Boyerdaf8f402009-09-23 03:51:04 +0000411 if (bp || unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 fromipi = 0;
413
414 if (!fromipi) {
415 get_output_lock();
416 excprint(regs);
417 if (bp) {
418 printf("cpu 0x%x stopped at breakpoint 0x%x (",
419 cpu, BP_NUM(bp));
420 xmon_print_symbol(regs->nip, " ", ")\n");
421 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000422 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 printf("WARNING: exception is not recoverable, "
424 "can't continue\n");
425 release_output_lock();
426 }
427
428 waiting:
429 secondary = 1;
430 while (secondary && !xmon_gate) {
431 if (in_xmon == 0) {
432 if (fromipi)
433 goto leave;
434 secondary = test_and_set_bit(0, &in_xmon);
435 }
436 barrier();
437 }
438
439 if (!secondary && !xmon_gate) {
440 /* we are the first cpu to come in */
441 /* interrupt other cpu(s) */
442 int ncpus = num_online_cpus();
443
444 xmon_owner = cpu;
445 mb();
446 if (ncpus > 1) {
Milton Millere0476372011-05-10 19:29:06 +0000447 smp_send_debugger_break();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 /* wait for other cpus to come in */
449 for (timeout = 100000000; timeout != 0; --timeout) {
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000450 if (cpumask_weight(&cpus_in_xmon) >= ncpus)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 break;
452 barrier();
453 }
454 }
455 remove_bpts();
456 disable_surveillance();
457 /* for breakpoint or single step, print the current instr. */
458 if (bp || TRAP(regs) == 0xd00)
459 ppc_inst_dump(regs->nip, 1, 0);
460 printf("enter ? for help\n");
461 mb();
462 xmon_gate = 1;
463 barrier();
464 }
465
466 cmdloop:
467 while (in_xmon) {
468 if (secondary) {
469 if (cpu == xmon_owner) {
470 if (!test_and_set_bit(0, &xmon_taken)) {
471 secondary = 0;
472 continue;
473 }
474 /* missed it */
475 while (cpu == xmon_owner)
476 barrier();
477 }
478 barrier();
479 } else {
480 cmd = cmds(regs);
481 if (cmd != 0) {
482 /* exiting xmon */
483 insert_bpts();
484 xmon_gate = 0;
485 wmb();
486 in_xmon = 0;
487 break;
488 }
489 /* have switched to some other cpu */
490 secondary = 1;
491 }
492 }
493 leave:
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000494 cpumask_clear_cpu(cpu, &cpus_in_xmon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 xmon_fault_jmp[cpu] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496#else
497 /* UP is simple... */
498 if (in_xmon) {
499 printf("Exception %lx %s in xmon, returning to main loop\n",
500 regs->trap, getvecname(TRAP(regs)));
501 longjmp(xmon_fault_jmp[0], 1);
502 }
503 if (setjmp(recurse_jmp) == 0) {
504 xmon_fault_jmp[0] = recurse_jmp;
505 in_xmon = 1;
506
507 excprint(regs);
508 bp = at_breakpoint(regs->nip);
509 if (bp) {
510 printf("Stopped at breakpoint %x (", BP_NUM(bp));
511 xmon_print_symbol(regs->nip, " ", ")\n");
512 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000513 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 printf("WARNING: exception is not recoverable, "
515 "can't continue\n");
516 remove_bpts();
517 disable_surveillance();
518 /* for breakpoint or single step, print the current instr. */
519 if (bp || TRAP(regs) == 0xd00)
520 ppc_inst_dump(regs->nip, 1, 0);
521 printf("enter ? for help\n");
522 }
523
524 cmd = cmds(regs);
525
526 insert_bpts();
527 in_xmon = 0;
528#endif
529
Josh Boyercdd39042009-10-05 04:46:05 +0000530#ifdef CONFIG_BOOKE
531 if (regs->msr & MSR_DE) {
532 bp = at_breakpoint(regs->nip);
533 if (bp != NULL) {
534 regs->nip = (unsigned long) &bp->instr[0];
535 atomic_inc(&bp->ref_count);
536 }
537 }
538#else
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000539 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 bp = at_breakpoint(regs->nip);
541 if (bp != NULL) {
542 int stepped = emulate_step(regs, bp->instr[0]);
543 if (stepped == 0) {
544 regs->nip = (unsigned long) &bp->instr[0];
545 atomic_inc(&bp->ref_count);
546 } else if (stepped < 0) {
547 printf("Couldn't single-step %s instruction\n",
548 (IS_RFID(bp->instr[0])? "rfid": "mtmsrd"));
549 }
550 }
551 }
Josh Boyercdd39042009-10-05 04:46:05 +0000552#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 insert_cpu_bpts();
554
Anton Blanchardf13659e2007-03-21 01:48:34 +1100555 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556
Paul Mackerras0a730ae2006-10-03 21:32:49 +1000557 return cmd != 'X' && cmd != EOF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558}
559
560int xmon(struct pt_regs *excp)
561{
562 struct pt_regs regs;
563
564 if (excp == NULL) {
Anton Vorontsov322b4392008-12-17 10:08:55 +0000565 ppc_save_regs(&regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 excp = &regs;
567 }
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200568
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 return xmon_core(excp, 0);
570}
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000571EXPORT_SYMBOL(xmon);
572
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000573irqreturn_t xmon_irq(int irq, void *d)
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000574{
575 unsigned long flags;
576 local_irq_save(flags);
577 printf("Keyboard interrupt\n");
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000578 xmon(get_irq_regs());
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000579 local_irq_restore(flags);
580 return IRQ_HANDLED;
581}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000583static int xmon_bpt(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584{
585 struct bpt *bp;
586 unsigned long offset;
587
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000588 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 return 0;
590
591 /* Are we at the trap at bp->instr[1] for some bp? */
592 bp = in_breakpoint_table(regs->nip, &offset);
593 if (bp != NULL && offset == 4) {
594 regs->nip = bp->address + 4;
595 atomic_dec(&bp->ref_count);
596 return 1;
597 }
598
599 /* Are we at a breakpoint? */
600 bp = at_breakpoint(regs->nip);
601 if (!bp)
602 return 0;
603
604 xmon_core(regs, 0);
605
606 return 1;
607}
608
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000609static int xmon_sstep(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610{
611 if (user_mode(regs))
612 return 0;
613 xmon_core(regs, 0);
614 return 1;
615}
616
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000617static int xmon_dabr_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000619 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 return 0;
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000621 if (dabr.enabled == 0)
622 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 xmon_core(regs, 0);
624 return 1;
625}
626
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000627static int xmon_iabr_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000629 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 return 0;
Michael Ellerman9f1067c22008-05-08 14:27:16 +1000631 if (iabr == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 return 0;
633 xmon_core(regs, 0);
634 return 1;
635}
636
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000637static int xmon_ipi(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638{
639#ifdef CONFIG_SMP
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000640 if (in_xmon && !cpumask_test_cpu(smp_processor_id(), &cpus_in_xmon))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 xmon_core(regs, 1);
642#endif
643 return 0;
644}
645
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000646static int xmon_fault_handler(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647{
648 struct bpt *bp;
649 unsigned long offset;
650
651 if (in_xmon && catch_memory_errors)
652 handle_fault(regs); /* doesn't return */
653
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000654 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 bp = in_breakpoint_table(regs->nip, &offset);
656 if (bp != NULL) {
657 regs->nip = bp->address + offset;
658 atomic_dec(&bp->ref_count);
659 }
660 }
661
662 return 0;
663}
664
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665static struct bpt *at_breakpoint(unsigned long pc)
666{
667 int i;
668 struct bpt *bp;
669
670 bp = bpts;
671 for (i = 0; i < NBPTS; ++i, ++bp)
672 if (bp->enabled && pc == bp->address)
673 return bp;
674 return NULL;
675}
676
677static struct bpt *in_breakpoint_table(unsigned long nip, unsigned long *offp)
678{
679 unsigned long off;
680
681 off = nip - (unsigned long) bpts;
682 if (off >= sizeof(bpts))
683 return NULL;
684 off %= sizeof(struct bpt);
685 if (off != offsetof(struct bpt, instr[0])
686 && off != offsetof(struct bpt, instr[1]))
687 return NULL;
688 *offp = off - offsetof(struct bpt, instr[0]);
689 return (struct bpt *) (nip - off);
690}
691
692static struct bpt *new_breakpoint(unsigned long a)
693{
694 struct bpt *bp;
695
696 a &= ~3UL;
697 bp = at_breakpoint(a);
698 if (bp)
699 return bp;
700
701 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
702 if (!bp->enabled && atomic_read(&bp->ref_count) == 0) {
703 bp->address = a;
704 bp->instr[1] = bpinstr;
705 store_inst(&bp->instr[1]);
706 return bp;
707 }
708 }
709
710 printf("Sorry, no free breakpoints. Please clear one first.\n");
711 return NULL;
712}
713
714static void insert_bpts(void)
715{
716 int i;
717 struct bpt *bp;
718
719 bp = bpts;
720 for (i = 0; i < NBPTS; ++i, ++bp) {
721 if ((bp->enabled & (BP_TRAP|BP_IABR)) == 0)
722 continue;
723 if (mread(bp->address, &bp->instr[0], 4) != 4) {
724 printf("Couldn't read instruction at %lx, "
725 "disabling breakpoint there\n", bp->address);
726 bp->enabled = 0;
727 continue;
728 }
729 if (IS_MTMSRD(bp->instr[0]) || IS_RFID(bp->instr[0])) {
730 printf("Breakpoint at %lx is on an mtmsrd or rfid "
731 "instruction, disabling it\n", bp->address);
732 bp->enabled = 0;
733 continue;
734 }
735 store_inst(&bp->instr[0]);
736 if (bp->enabled & BP_IABR)
737 continue;
738 if (mwrite(bp->address, &bpinstr, 4) != 4) {
739 printf("Couldn't write instruction at %lx, "
740 "disabling breakpoint there\n", bp->address);
741 bp->enabled &= ~BP_TRAP;
742 continue;
743 }
744 store_inst((void *)bp->address);
745 }
746}
747
748static void insert_cpu_bpts(void)
749{
750 if (dabr.enabled)
Michael Neuling4474ef02012-09-06 21:24:56 +0000751 set_dabr(dabr.address | (dabr.enabled & 7), DABRX_ALL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 if (iabr && cpu_has_feature(CPU_FTR_IABR))
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000753 mtspr(SPRN_IABR, iabr->address
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 | (iabr->enabled & (BP_IABR|BP_IABR_TE)));
755}
756
757static void remove_bpts(void)
758{
759 int i;
760 struct bpt *bp;
761 unsigned instr;
762
763 bp = bpts;
764 for (i = 0; i < NBPTS; ++i, ++bp) {
765 if ((bp->enabled & (BP_TRAP|BP_IABR)) != BP_TRAP)
766 continue;
767 if (mread(bp->address, &instr, 4) == 4
768 && instr == bpinstr
769 && mwrite(bp->address, &bp->instr, 4) != 4)
770 printf("Couldn't remove breakpoint at %lx\n",
771 bp->address);
772 else
773 store_inst((void *)bp->address);
774 }
775}
776
777static void remove_cpu_bpts(void)
778{
Michael Neuling4474ef02012-09-06 21:24:56 +0000779 set_dabr(0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 if (cpu_has_feature(CPU_FTR_IABR))
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000781 mtspr(SPRN_IABR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782}
783
784/* Command interpreting routine */
785static char *last_cmd;
786
787static int
788cmds(struct pt_regs *excp)
789{
790 int cmd = 0;
791
792 last_cmd = NULL;
793 xmon_regs = excp;
Olaf Hering26c8af52006-09-08 16:29:21 +0200794
795 if (!xmon_no_auto_backtrace) {
796 xmon_no_auto_backtrace = 1;
797 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
798 }
799
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 for(;;) {
801#ifdef CONFIG_SMP
802 printf("%x:", smp_processor_id());
803#endif /* CONFIG_SMP */
804 printf("mon> ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 flush_input();
806 termch = 0;
807 cmd = skipbl();
808 if( cmd == '\n' ) {
809 if (last_cmd == NULL)
810 continue;
811 take_input(last_cmd);
812 last_cmd = NULL;
813 cmd = inchar();
814 }
815 switch (cmd) {
816 case 'm':
817 cmd = inchar();
818 switch (cmd) {
819 case 'm':
820 case 's':
821 case 'd':
822 memops(cmd);
823 break;
824 case 'l':
825 memlocate();
826 break;
827 case 'z':
828 memzcan();
829 break;
830 case 'i':
David Rientjesb2b755b2011-03-24 15:18:15 -0700831 show_mem(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 break;
833 default:
834 termch = cmd;
835 memex();
836 }
837 break;
838 case 'd':
839 dump();
840 break;
841 case 'l':
842 symbol_lookup();
843 break;
844 case 'r':
845 prregs(excp); /* print regs */
846 break;
847 case 'e':
848 excprint(excp);
849 break;
850 case 'S':
851 super_regs();
852 break;
853 case 't':
854 backtrace(excp);
855 break;
856 case 'f':
857 cacheflush();
858 break;
859 case 's':
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200860 if (do_spu_cmd() == 0)
861 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 if (do_step(excp))
863 return cmd;
864 break;
865 case 'x':
866 case 'X':
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100867 return cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 case EOF:
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100869 printf(" <no input ...>\n");
870 mdelay(2000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 return cmd;
872 case '?':
Ishizaki Kou4d404ed2007-07-18 19:26:40 +1000873 xmon_puts(help_string);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 case 'b':
876 bpt_cmds();
877 break;
878 case 'C':
879 csum();
880 break;
881 case 'c':
882 if (cpu_cmd())
883 return 0;
884 break;
885 case 'z':
886 bootcmds();
887 break;
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000888 case 'p':
889 proccall();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 break;
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000891#ifdef CONFIG_PPC_STD_MMU
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 case 'u':
893 dump_segments();
894 break;
Jimi Xenidis79873e82011-09-29 11:25:10 +0000895#elif defined(CONFIG_4xx)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100896 case 'u':
897 dump_tlb_44x();
898 break;
Jimi Xenidis79873e82011-09-29 11:25:10 +0000899#elif defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +1000900 case 'u':
901 dump_tlb_book3e();
902 break;
903#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 default:
905 printf("Unrecognized command: ");
Michael Ellermane3bc8042012-08-23 22:09:13 +0000906 do {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 if (' ' < cmd && cmd <= '~')
908 putchar(cmd);
909 else
910 printf("\\x%x", cmd);
911 cmd = inchar();
Michael Ellermane3bc8042012-08-23 22:09:13 +0000912 } while (cmd != '\n');
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 printf(" (type ? for help)\n");
914 break;
915 }
916 }
917}
918
Josh Boyercdd39042009-10-05 04:46:05 +0000919#ifdef CONFIG_BOOKE
920static int do_step(struct pt_regs *regs)
921{
922 regs->msr |= MSR_DE;
923 mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
924 return 1;
925}
926#else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927/*
928 * Step a single instruction.
929 * Some instructions we emulate, others we execute with MSR_SE set.
930 */
931static int do_step(struct pt_regs *regs)
932{
933 unsigned int instr;
934 int stepped;
935
936 /* check we are in 64-bit kernel mode, translation enabled */
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000937 if ((regs->msr & (MSR_64BIT|MSR_PR|MSR_IR)) == (MSR_64BIT|MSR_IR)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 if (mread(regs->nip, &instr, 4) == 4) {
939 stepped = emulate_step(regs, instr);
940 if (stepped < 0) {
941 printf("Couldn't single-step %s instruction\n",
942 (IS_RFID(instr)? "rfid": "mtmsrd"));
943 return 0;
944 }
945 if (stepped > 0) {
946 regs->trap = 0xd00 | (regs->trap & 1);
947 printf("stepped to ");
948 xmon_print_symbol(regs->nip, " ", "\n");
949 ppc_inst_dump(regs->nip, 1, 0);
950 return 0;
951 }
952 }
953 }
954 regs->msr |= MSR_SE;
955 return 1;
956}
Josh Boyercdd39042009-10-05 04:46:05 +0000957#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958
959static void bootcmds(void)
960{
961 int cmd;
962
963 cmd = inchar();
964 if (cmd == 'r')
965 ppc_md.restart(NULL);
966 else if (cmd == 'h')
967 ppc_md.halt();
968 else if (cmd == 'p')
969 ppc_md.power_off();
970}
971
972static int cpu_cmd(void)
973{
974#ifdef CONFIG_SMP
975 unsigned long cpu;
976 int timeout;
977 int count;
978
979 if (!scanhex(&cpu)) {
980 /* print cpus waiting or in xmon */
981 printf("cpus stopped:");
982 count = 0;
Anton Blanchardbc1d7702012-06-28 19:28:57 +0000983 for_each_possible_cpu(cpu) {
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000984 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 if (count == 0)
986 printf(" %x", cpu);
987 ++count;
988 } else {
989 if (count > 1)
990 printf("-%x", cpu - 1);
991 count = 0;
992 }
993 }
994 if (count > 1)
995 printf("-%x", NR_CPUS - 1);
996 printf("\n");
997 return 0;
998 }
999 /* try to switch to cpu specified */
KOSAKI Motohiro104699c2011-04-28 05:07:23 +00001000 if (!cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 printf("cpu 0x%x isn't in xmon\n", cpu);
1002 return 0;
1003 }
1004 xmon_taken = 0;
1005 mb();
1006 xmon_owner = cpu;
1007 timeout = 10000000;
1008 while (!xmon_taken) {
1009 if (--timeout == 0) {
1010 if (test_and_set_bit(0, &xmon_taken))
1011 break;
1012 /* take control back */
1013 mb();
1014 xmon_owner = smp_processor_id();
1015 printf("cpu %u didn't take control\n", cpu);
1016 return 0;
1017 }
1018 barrier();
1019 }
1020 return 1;
1021#else
1022 return 0;
1023#endif /* CONFIG_SMP */
1024}
1025
1026static unsigned short fcstab[256] = {
1027 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
1028 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
1029 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
1030 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
1031 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
1032 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
1033 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
1034 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
1035 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
1036 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
1037 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
1038 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
1039 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
1040 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
1041 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
1042 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
1043 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
1044 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
1045 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
1046 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
1047 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
1048 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
1049 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
1050 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
1051 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
1052 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
1053 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
1054 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
1055 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
1056 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
1057 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
1058 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
1059};
1060
1061#define FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
1062
1063static void
1064csum(void)
1065{
1066 unsigned int i;
1067 unsigned short fcs;
1068 unsigned char v;
1069
1070 if (!scanhex(&adrs))
1071 return;
1072 if (!scanhex(&ncsum))
1073 return;
1074 fcs = 0xffff;
1075 for (i = 0; i < ncsum; ++i) {
1076 if (mread(adrs+i, &v, 1) == 0) {
1077 printf("csum stopped at %x\n", adrs+i);
1078 break;
1079 }
1080 fcs = FCS(fcs, v);
1081 }
1082 printf("%x\n", fcs);
1083}
1084
1085/*
1086 * Check if this is a suitable place to put a breakpoint.
1087 */
1088static long check_bp_loc(unsigned long addr)
1089{
1090 unsigned int instr;
1091
1092 addr &= ~3;
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001093 if (!is_kernel_addr(addr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 printf("Breakpoints may only be placed at kernel addresses\n");
1095 return 0;
1096 }
1097 if (!mread(addr, &instr, sizeof(instr))) {
1098 printf("Can't read instruction at address %lx\n", addr);
1099 return 0;
1100 }
1101 if (IS_MTMSRD(instr) || IS_RFID(instr)) {
1102 printf("Breakpoints may not be placed on mtmsrd or rfid "
1103 "instructions\n");
1104 return 0;
1105 }
1106 return 1;
1107}
1108
Michael Ellermane3bc8042012-08-23 22:09:13 +00001109static char *breakpoint_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 "Breakpoint command usage:\n"
1111 "b show breakpoints\n"
1112 "b <addr> [cnt] set breakpoint at given instr addr\n"
1113 "bc clear all breakpoints\n"
1114 "bc <n/addr> clear breakpoint number n or at addr\n"
1115 "bi <addr> [cnt] set hardware instr breakpoint (POWER3/RS64 only)\n"
1116 "bd <addr> [cnt] set hardware data breakpoint\n"
1117 "";
1118
1119static void
1120bpt_cmds(void)
1121{
1122 int cmd;
1123 unsigned long a;
1124 int mode, i;
1125 struct bpt *bp;
1126 const char badaddr[] = "Only kernel addresses are permitted "
1127 "for breakpoints\n";
1128
1129 cmd = inchar();
1130 switch (cmd) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001131#ifndef CONFIG_8xx
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 case 'd': /* bd - hardware data breakpoint */
1133 mode = 7;
1134 cmd = inchar();
1135 if (cmd == 'r')
1136 mode = 5;
1137 else if (cmd == 'w')
1138 mode = 6;
1139 else
1140 termch = cmd;
1141 dabr.address = 0;
1142 dabr.enabled = 0;
1143 if (scanhex(&dabr.address)) {
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001144 if (!is_kernel_addr(dabr.address)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 printf(badaddr);
1146 break;
1147 }
1148 dabr.address &= ~7;
1149 dabr.enabled = mode | BP_DABR;
1150 }
1151 break;
1152
1153 case 'i': /* bi - hardware instr breakpoint */
1154 if (!cpu_has_feature(CPU_FTR_IABR)) {
1155 printf("Hardware instruction breakpoint "
1156 "not supported on this cpu\n");
1157 break;
1158 }
1159 if (iabr) {
1160 iabr->enabled &= ~(BP_IABR | BP_IABR_TE);
1161 iabr = NULL;
1162 }
1163 if (!scanhex(&a))
1164 break;
1165 if (!check_bp_loc(a))
1166 break;
1167 bp = new_breakpoint(a);
1168 if (bp != NULL) {
1169 bp->enabled |= BP_IABR | BP_IABR_TE;
1170 iabr = bp;
1171 }
1172 break;
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001173#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174
1175 case 'c':
1176 if (!scanhex(&a)) {
1177 /* clear all breakpoints */
1178 for (i = 0; i < NBPTS; ++i)
1179 bpts[i].enabled = 0;
1180 iabr = NULL;
1181 dabr.enabled = 0;
1182 printf("All breakpoints cleared\n");
1183 break;
1184 }
1185
1186 if (a <= NBPTS && a >= 1) {
1187 /* assume a breakpoint number */
1188 bp = &bpts[a-1]; /* bp nums are 1 based */
1189 } else {
1190 /* assume a breakpoint address */
1191 bp = at_breakpoint(a);
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001192 if (bp == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 printf("No breakpoint at %x\n", a);
1194 break;
1195 }
1196 }
1197
1198 printf("Cleared breakpoint %x (", BP_NUM(bp));
1199 xmon_print_symbol(bp->address, " ", ")\n");
1200 bp->enabled = 0;
1201 break;
1202
1203 default:
1204 termch = cmd;
Michael Ellermane3bc8042012-08-23 22:09:13 +00001205 cmd = skipbl();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 if (cmd == '?') {
1207 printf(breakpoint_help_string);
1208 break;
1209 }
1210 termch = cmd;
1211 if (!scanhex(&a)) {
1212 /* print all breakpoints */
1213 printf(" type address\n");
1214 if (dabr.enabled) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001215 printf(" data "REG" [", dabr.address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 if (dabr.enabled & 1)
1217 printf("r");
1218 if (dabr.enabled & 2)
1219 printf("w");
1220 printf("]\n");
1221 }
1222 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
1223 if (!bp->enabled)
1224 continue;
1225 printf("%2x %s ", BP_NUM(bp),
1226 (bp->enabled & BP_IABR)? "inst": "trap");
1227 xmon_print_symbol(bp->address, " ", "\n");
1228 }
1229 break;
1230 }
1231
1232 if (!check_bp_loc(a))
1233 break;
1234 bp = new_breakpoint(a);
1235 if (bp != NULL)
1236 bp->enabled |= BP_TRAP;
1237 break;
1238 }
1239}
1240
1241/* Very cheap human name for vector lookup. */
1242static
1243const char *getvecname(unsigned long vec)
1244{
1245 char *ret;
1246
1247 switch (vec) {
1248 case 0x100: ret = "(System Reset)"; break;
1249 case 0x200: ret = "(Machine Check)"; break;
1250 case 0x300: ret = "(Data Access)"; break;
1251 case 0x380: ret = "(Data SLB Access)"; break;
1252 case 0x400: ret = "(Instruction Access)"; break;
1253 case 0x480: ret = "(Instruction SLB Access)"; break;
1254 case 0x500: ret = "(Hardware Interrupt)"; break;
1255 case 0x600: ret = "(Alignment)"; break;
1256 case 0x700: ret = "(Program Check)"; break;
1257 case 0x800: ret = "(FPU Unavailable)"; break;
1258 case 0x900: ret = "(Decrementer)"; break;
1259 case 0xc00: ret = "(System Call)"; break;
1260 case 0xd00: ret = "(Single Step)"; break;
1261 case 0xf00: ret = "(Performance Monitor)"; break;
1262 case 0xf20: ret = "(Altivec Unavailable)"; break;
1263 case 0x1300: ret = "(Instruction Breakpoint)"; break;
1264 default: ret = "";
1265 }
1266 return ret;
1267}
1268
1269static void get_function_bounds(unsigned long pc, unsigned long *startp,
1270 unsigned long *endp)
1271{
1272 unsigned long size, offset;
1273 const char *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274
1275 *startp = *endp = 0;
1276 if (pc == 0)
1277 return;
1278 if (setjmp(bus_error_jmp) == 0) {
1279 catch_memory_errors = 1;
1280 sync();
Alexey Dobriyanffb45122007-05-08 00:28:41 -07001281 name = kallsyms_lookup(pc, &size, &offset, NULL, tmpstr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 if (name != NULL) {
1283 *startp = pc - offset;
1284 *endp = pc - offset + size;
1285 }
1286 sync();
1287 }
1288 catch_memory_errors = 0;
1289}
1290
1291static int xmon_depth_to_print = 64;
1292
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001293#define LRSAVE_OFFSET (STACK_FRAME_LR_SAVE * sizeof(unsigned long))
1294#define MARKER_OFFSET (STACK_FRAME_MARKER * sizeof(unsigned long))
1295
1296#ifdef __powerpc64__
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001297#define REGS_OFFSET 0x70
1298#else
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001299#define REGS_OFFSET 16
1300#endif
1301
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302static void xmon_show_stack(unsigned long sp, unsigned long lr,
1303 unsigned long pc)
1304{
1305 unsigned long ip;
1306 unsigned long newsp;
1307 unsigned long marker;
1308 int count = 0;
1309 struct pt_regs regs;
1310
1311 do {
1312 if (sp < PAGE_OFFSET) {
1313 if (sp != 0)
1314 printf("SP (%lx) is in userspace\n", sp);
1315 break;
1316 }
1317
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001318 if (!mread(sp + LRSAVE_OFFSET, &ip, sizeof(unsigned long))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 || !mread(sp, &newsp, sizeof(unsigned long))) {
1320 printf("Couldn't read stack frame at %lx\n", sp);
1321 break;
1322 }
1323
1324 /*
1325 * For the first stack frame, try to work out if
1326 * LR and/or the saved LR value in the bottommost
1327 * stack frame are valid.
1328 */
1329 if ((pc | lr) != 0) {
1330 unsigned long fnstart, fnend;
1331 unsigned long nextip;
1332 int printip = 1;
1333
1334 get_function_bounds(pc, &fnstart, &fnend);
1335 nextip = 0;
1336 if (newsp > sp)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001337 mread(newsp + LRSAVE_OFFSET, &nextip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 sizeof(unsigned long));
1339 if (lr == ip) {
1340 if (lr < PAGE_OFFSET
1341 || (fnstart <= lr && lr < fnend))
1342 printip = 0;
1343 } else if (lr == nextip) {
1344 printip = 0;
1345 } else if (lr >= PAGE_OFFSET
1346 && !(fnstart <= lr && lr < fnend)) {
1347 printf("[link register ] ");
1348 xmon_print_symbol(lr, " ", "\n");
1349 }
1350 if (printip) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001351 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 xmon_print_symbol(ip, " ", " (unreliable)\n");
1353 }
1354 pc = lr = 0;
1355
1356 } else {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001357 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 xmon_print_symbol(ip, " ", "\n");
1359 }
1360
1361 /* Look for "regshere" marker to see if this is
1362 an exception frame. */
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001363 if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long))
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001364 && marker == STACK_FRAME_REGS_MARKER) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001365 if (mread(sp + REGS_OFFSET, &regs, sizeof(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 != sizeof(regs)) {
1367 printf("Couldn't read registers at %lx\n",
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001368 sp + REGS_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 break;
1370 }
Michael Ellermane3bc8042012-08-23 22:09:13 +00001371 printf("--- Exception: %lx %s at ", regs.trap,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 getvecname(TRAP(&regs)));
1373 pc = regs.nip;
1374 lr = regs.link;
1375 xmon_print_symbol(pc, " ", "\n");
1376 }
1377
1378 if (newsp == 0)
1379 break;
1380
1381 sp = newsp;
1382 } while (count++ < xmon_depth_to_print);
1383}
1384
1385static void backtrace(struct pt_regs *excp)
1386{
1387 unsigned long sp;
1388
1389 if (scanhex(&sp))
1390 xmon_show_stack(sp, 0, 0);
1391 else
1392 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
1393 scannl();
1394}
1395
1396static void print_bug_trap(struct pt_regs *regs)
1397{
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001398#ifdef CONFIG_BUG
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001399 const struct bug_entry *bug;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400 unsigned long addr;
1401
1402 if (regs->msr & MSR_PR)
1403 return; /* not in kernel */
1404 addr = regs->nip; /* address of trap instruction */
1405 if (addr < PAGE_OFFSET)
1406 return;
1407 bug = find_bug(regs->nip);
1408 if (bug == NULL)
1409 return;
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001410 if (is_warning_bug(bug))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 return;
1412
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001413#ifdef CONFIG_DEBUG_BUGVERBOSE
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001414 printf("kernel BUG at %s:%u!\n",
1415 bug->file, bug->line);
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001416#else
1417 printf("kernel BUG at %p!\n", (void *)bug->bug_addr);
1418#endif
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001419#endif /* CONFIG_BUG */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420}
1421
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001422static void excprint(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423{
1424 unsigned long trap;
1425
1426#ifdef CONFIG_SMP
1427 printf("cpu 0x%x: ", smp_processor_id());
1428#endif /* CONFIG_SMP */
1429
1430 trap = TRAP(fp);
1431 printf("Vector: %lx %s at [%lx]\n", fp->trap, getvecname(trap), fp);
1432 printf(" pc: ");
1433 xmon_print_symbol(fp->nip, ": ", "\n");
1434
1435 printf(" lr: ", fp->link);
1436 xmon_print_symbol(fp->link, ": ", "\n");
1437
1438 printf(" sp: %lx\n", fp->gpr[1]);
1439 printf(" msr: %lx\n", fp->msr);
1440
1441 if (trap == 0x300 || trap == 0x380 || trap == 0x600) {
1442 printf(" dar: %lx\n", fp->dar);
1443 if (trap != 0x380)
1444 printf(" dsisr: %lx\n", fp->dsisr);
1445 }
1446
1447 printf(" current = 0x%lx\n", current);
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001448#ifdef CONFIG_PPC64
Benjamin Herrenschmidt7230c562012-03-06 18:27:59 +11001449 printf(" paca = 0x%lx\t softe: %d\t irq_happened: 0x%02x\n",
1450 local_paca, local_paca->soft_enabled, local_paca->irq_happened);
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001451#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 if (current) {
1453 printf(" pid = %ld, comm = %s\n",
1454 current->pid, current->comm);
1455 }
1456
1457 if (trap == 0x700)
1458 print_bug_trap(fp);
1459}
1460
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001461static void prregs(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462{
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001463 int n, trap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 unsigned long base;
1465 struct pt_regs regs;
1466
1467 if (scanhex(&base)) {
1468 if (setjmp(bus_error_jmp) == 0) {
1469 catch_memory_errors = 1;
1470 sync();
1471 regs = *(struct pt_regs *)base;
1472 sync();
1473 __delay(200);
1474 } else {
1475 catch_memory_errors = 0;
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001476 printf("*** Error reading registers from "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 base);
1478 return;
1479 }
1480 catch_memory_errors = 0;
1481 fp = &regs;
1482 }
1483
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001484#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 if (FULL_REGS(fp)) {
1486 for (n = 0; n < 16; ++n)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001487 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488 n, fp->gpr[n], n+16, fp->gpr[n+16]);
1489 } else {
1490 for (n = 0; n < 7; ++n)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001491 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 n, fp->gpr[n], n+7, fp->gpr[n+7]);
1493 }
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001494#else
1495 for (n = 0; n < 32; ++n) {
1496 printf("R%.2d = %.8x%s", n, fp->gpr[n],
1497 (n & 3) == 3? "\n": " ");
1498 if (n == 12 && !FULL_REGS(fp)) {
1499 printf("\n");
1500 break;
1501 }
1502 }
1503#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504 printf("pc = ");
1505 xmon_print_symbol(fp->nip, " ", "\n");
Paul Mackerras48404f22011-05-01 19:48:20 +00001506 if (TRAP(fp) != 0xc00 && cpu_has_feature(CPU_FTR_CFAR)) {
1507 printf("cfar= ");
1508 xmon_print_symbol(fp->orig_gpr3, " ", "\n");
1509 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510 printf("lr = ");
1511 xmon_print_symbol(fp->link, " ", "\n");
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001512 printf("msr = "REG" cr = %.8lx\n", fp->msr, fp->ccr);
1513 printf("ctr = "REG" xer = "REG" trap = %4lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514 fp->ctr, fp->xer, fp->trap);
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001515 trap = TRAP(fp);
1516 if (trap == 0x300 || trap == 0x380 || trap == 0x600)
1517 printf("dar = "REG" dsisr = %.8lx\n", fp->dar, fp->dsisr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518}
1519
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001520static void cacheflush(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521{
1522 int cmd;
1523 unsigned long nflush;
1524
1525 cmd = inchar();
1526 if (cmd != 'i')
1527 termch = cmd;
1528 scanhex((void *)&adrs);
1529 if (termch != '\n')
1530 termch = 0;
1531 nflush = 1;
1532 scanhex(&nflush);
1533 nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES;
1534 if (setjmp(bus_error_jmp) == 0) {
1535 catch_memory_errors = 1;
1536 sync();
1537
1538 if (cmd != 'i') {
1539 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1540 cflush((void *) adrs);
1541 } else {
1542 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1543 cinval((void *) adrs);
1544 }
1545 sync();
1546 /* wait a little while to see if we get a machine check */
1547 __delay(200);
1548 }
1549 catch_memory_errors = 0;
1550}
1551
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001552static unsigned long
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553read_spr(int n)
1554{
1555 unsigned int instrs[2];
1556 unsigned long (*code)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 unsigned long ret = -1UL;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001558#ifdef CONFIG_PPC64
1559 unsigned long opd[3];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 opd[0] = (unsigned long)instrs;
1562 opd[1] = 0;
1563 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001564 code = (unsigned long (*)(void)) opd;
1565#else
1566 code = (unsigned long (*)(void)) instrs;
1567#endif
1568
1569 /* mfspr r3,n; blr */
1570 instrs[0] = 0x7c6002a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1571 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 store_inst(instrs);
1573 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574
1575 if (setjmp(bus_error_jmp) == 0) {
1576 catch_memory_errors = 1;
1577 sync();
1578
1579 ret = code();
1580
1581 sync();
1582 /* wait a little while to see if we get a machine check */
1583 __delay(200);
1584 n = size;
1585 }
1586
1587 return ret;
1588}
1589
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001590static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591write_spr(int n, unsigned long val)
1592{
1593 unsigned int instrs[2];
1594 unsigned long (*code)(unsigned long);
Paul Mackerras548cceb2005-11-11 22:36:34 +11001595#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 unsigned long opd[3];
1597
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 opd[0] = (unsigned long)instrs;
1599 opd[1] = 0;
1600 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001601 code = (unsigned long (*)(unsigned long)) opd;
1602#else
1603 code = (unsigned long (*)(unsigned long)) instrs;
1604#endif
1605
1606 instrs[0] = 0x7c6003a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1607 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 store_inst(instrs);
1609 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610
1611 if (setjmp(bus_error_jmp) == 0) {
1612 catch_memory_errors = 1;
1613 sync();
1614
1615 code(val);
1616
1617 sync();
1618 /* wait a little while to see if we get a machine check */
1619 __delay(200);
1620 n = size;
1621 }
1622}
1623
1624static unsigned long regno;
1625extern char exc_prolog;
1626extern char dec_exc;
1627
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001628static void super_regs(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629{
1630 int cmd;
1631 unsigned long val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632
1633 cmd = skipbl();
1634 if (cmd == '\n') {
Michael Ellermane3bc8042012-08-23 22:09:13 +00001635 unsigned long sp, toc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636 asm("mr %0,1" : "=r" (sp) :);
1637 asm("mr %0,2" : "=r" (toc) :);
1638
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001639 printf("msr = "REG" sprg0= "REG"\n",
1640 mfmsr(), mfspr(SPRN_SPRG0));
1641 printf("pvr = "REG" sprg1= "REG"\n",
Michael Ellermane3bc8042012-08-23 22:09:13 +00001642 mfspr(SPRN_PVR), mfspr(SPRN_SPRG1));
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001643 printf("dec = "REG" sprg2= "REG"\n",
1644 mfspr(SPRN_DEC), mfspr(SPRN_SPRG2));
1645 printf("sp = "REG" sprg3= "REG"\n", sp, mfspr(SPRN_SPRG3));
1646 printf("toc = "REG" dar = "REG"\n", toc, mfspr(SPRN_DAR));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647
1648 return;
1649 }
1650
1651 scanhex(&regno);
1652 switch (cmd) {
1653 case 'w':
1654 val = read_spr(regno);
1655 scanhex(&val);
1656 write_spr(regno, val);
1657 /* fall through */
1658 case 'r':
1659 printf("spr %lx = %lx\n", regno, read_spr(regno));
1660 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661 }
1662 scannl();
1663}
1664
1665/*
1666 * Stuff for reading and writing memory safely
1667 */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001668static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669mread(unsigned long adrs, void *buf, int size)
1670{
1671 volatile int n;
1672 char *p, *q;
1673
1674 n = 0;
1675 if (setjmp(bus_error_jmp) == 0) {
1676 catch_memory_errors = 1;
1677 sync();
1678 p = (char *)adrs;
1679 q = (char *)buf;
1680 switch (size) {
1681 case 2:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001682 *(u16 *)q = *(u16 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 break;
1684 case 4:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001685 *(u32 *)q = *(u32 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 break;
1687 case 8:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001688 *(u64 *)q = *(u64 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689 break;
1690 default:
1691 for( ; n < size; ++n) {
1692 *q++ = *p++;
1693 sync();
1694 }
1695 }
1696 sync();
1697 /* wait a little while to see if we get a machine check */
1698 __delay(200);
1699 n = size;
1700 }
1701 catch_memory_errors = 0;
1702 return n;
1703}
1704
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001705static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706mwrite(unsigned long adrs, void *buf, int size)
1707{
1708 volatile int n;
1709 char *p, *q;
1710
1711 n = 0;
1712 if (setjmp(bus_error_jmp) == 0) {
1713 catch_memory_errors = 1;
1714 sync();
1715 p = (char *) adrs;
1716 q = (char *) buf;
1717 switch (size) {
1718 case 2:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001719 *(u16 *)p = *(u16 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 break;
1721 case 4:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001722 *(u32 *)p = *(u32 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 break;
1724 case 8:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001725 *(u64 *)p = *(u64 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726 break;
1727 default:
1728 for ( ; n < size; ++n) {
1729 *p++ = *q++;
1730 sync();
1731 }
1732 }
1733 sync();
1734 /* wait a little while to see if we get a machine check */
1735 __delay(200);
1736 n = size;
1737 } else {
1738 printf("*** Error writing address %x\n", adrs + n);
1739 }
1740 catch_memory_errors = 0;
1741 return n;
1742}
1743
1744static int fault_type;
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001745static int fault_except;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746static char *fault_chars[] = { "--", "**", "##" };
1747
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001748static int handle_fault(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749{
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001750 fault_except = TRAP(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 switch (TRAP(regs)) {
1752 case 0x200:
1753 fault_type = 0;
1754 break;
1755 case 0x300:
1756 case 0x380:
1757 fault_type = 1;
1758 break;
1759 default:
1760 fault_type = 2;
1761 }
1762
1763 longjmp(bus_error_jmp, 1);
1764
1765 return 0;
1766}
1767
1768#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t))
1769
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001770static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771byterev(unsigned char *val, int size)
1772{
1773 int t;
1774
1775 switch (size) {
1776 case 2:
1777 SWAP(val[0], val[1], t);
1778 break;
1779 case 4:
1780 SWAP(val[0], val[3], t);
1781 SWAP(val[1], val[2], t);
1782 break;
1783 case 8: /* is there really any use for this? */
1784 SWAP(val[0], val[7], t);
1785 SWAP(val[1], val[6], t);
1786 SWAP(val[2], val[5], t);
1787 SWAP(val[3], val[4], t);
1788 break;
1789 }
1790}
1791
1792static int brev;
1793static int mnoread;
1794
Michael Ellermane3bc8042012-08-23 22:09:13 +00001795static char *memex_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 "Memory examine command usage:\n"
1797 "m [addr] [flags] examine/change memory\n"
1798 " addr is optional. will start where left off.\n"
1799 " flags may include chars from this set:\n"
1800 " b modify by bytes (default)\n"
1801 " w modify by words (2 byte)\n"
1802 " l modify by longs (4 byte)\n"
1803 " d modify by doubleword (8 byte)\n"
1804 " r toggle reverse byte order mode\n"
1805 " n do not read memory (for i/o spaces)\n"
1806 " . ok to read (default)\n"
1807 "NOTE: flags are saved as defaults\n"
1808 "";
1809
Michael Ellermane3bc8042012-08-23 22:09:13 +00001810static char *memex_subcmd_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811 "Memory examine subcommands:\n"
1812 " hexval write this val to current location\n"
1813 " 'string' write chars from string to this location\n"
1814 " ' increment address\n"
1815 " ^ decrement address\n"
1816 " / increment addr by 0x10. //=0x100, ///=0x1000, etc\n"
1817 " \\ decrement addr by 0x10. \\\\=0x100, \\\\\\=0x1000, etc\n"
1818 " ` clear no-read flag\n"
1819 " ; stay at this addr\n"
1820 " v change to byte mode\n"
1821 " w change to word (2 byte) mode\n"
1822 " l change to long (4 byte) mode\n"
1823 " u change to doubleword (8 byte) mode\n"
1824 " m addr change current addr\n"
1825 " n toggle no-read flag\n"
1826 " r toggle byte reverse flag\n"
1827 " < count back up count bytes\n"
1828 " > count skip forward count bytes\n"
1829 " x exit this mode\n"
1830 "";
1831
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001832static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833memex(void)
1834{
1835 int cmd, inc, i, nslash;
1836 unsigned long n;
1837 unsigned char val[16];
1838
1839 scanhex((void *)&adrs);
1840 cmd = skipbl();
1841 if (cmd == '?') {
1842 printf(memex_help_string);
1843 return;
1844 } else {
1845 termch = cmd;
1846 }
1847 last_cmd = "m\n";
1848 while ((cmd = skipbl()) != '\n') {
1849 switch( cmd ){
1850 case 'b': size = 1; break;
1851 case 'w': size = 2; break;
1852 case 'l': size = 4; break;
1853 case 'd': size = 8; break;
1854 case 'r': brev = !brev; break;
1855 case 'n': mnoread = 1; break;
1856 case '.': mnoread = 0; break;
1857 }
1858 }
1859 if( size <= 0 )
1860 size = 1;
1861 else if( size > 8 )
1862 size = 8;
1863 for(;;){
1864 if (!mnoread)
1865 n = mread(adrs, val, size);
Paul Mackerrase1449ed2005-11-10 14:30:20 +11001866 printf(REG"%c", adrs, brev? 'r': ' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867 if (!mnoread) {
1868 if (brev)
1869 byterev(val, size);
1870 putchar(' ');
1871 for (i = 0; i < n; ++i)
1872 printf("%.2x", val[i]);
1873 for (; i < size; ++i)
1874 printf("%s", fault_chars[fault_type]);
1875 }
1876 putchar(' ');
1877 inc = size;
1878 nslash = 0;
1879 for(;;){
1880 if( scanhex(&n) ){
1881 for (i = 0; i < size; ++i)
1882 val[i] = n >> (i * 8);
1883 if (!brev)
1884 byterev(val, size);
1885 mwrite(adrs, val, size);
1886 inc = size;
1887 }
1888 cmd = skipbl();
1889 if (cmd == '\n')
1890 break;
1891 inc = 0;
1892 switch (cmd) {
1893 case '\'':
1894 for(;;){
1895 n = inchar();
1896 if( n == '\\' )
1897 n = bsesc();
1898 else if( n == '\'' )
1899 break;
1900 for (i = 0; i < size; ++i)
1901 val[i] = n >> (i * 8);
1902 if (!brev)
1903 byterev(val, size);
1904 mwrite(adrs, val, size);
1905 adrs += size;
1906 }
1907 adrs -= size;
1908 inc = size;
1909 break;
1910 case ',':
1911 adrs += size;
1912 break;
1913 case '.':
1914 mnoread = 0;
1915 break;
1916 case ';':
1917 break;
1918 case 'x':
1919 case EOF:
1920 scannl();
1921 return;
1922 case 'b':
1923 case 'v':
1924 size = 1;
1925 break;
1926 case 'w':
1927 size = 2;
1928 break;
1929 case 'l':
1930 size = 4;
1931 break;
1932 case 'u':
1933 size = 8;
1934 break;
1935 case '^':
1936 adrs -= size;
1937 break;
1938 break;
1939 case '/':
1940 if (nslash > 0)
1941 adrs -= 1 << nslash;
1942 else
1943 nslash = 0;
1944 nslash += 4;
1945 adrs += 1 << nslash;
1946 break;
1947 case '\\':
1948 if (nslash < 0)
1949 adrs += 1 << -nslash;
1950 else
1951 nslash = 0;
1952 nslash -= 4;
1953 adrs -= 1 << -nslash;
1954 break;
1955 case 'm':
1956 scanhex((void *)&adrs);
1957 break;
1958 case 'n':
1959 mnoread = 1;
1960 break;
1961 case 'r':
1962 brev = !brev;
1963 break;
1964 case '<':
1965 n = size;
1966 scanhex(&n);
1967 adrs -= n;
1968 break;
1969 case '>':
1970 n = size;
1971 scanhex(&n);
1972 adrs += n;
1973 break;
1974 case '?':
1975 printf(memex_subcmd_help_string);
1976 break;
1977 }
1978 }
1979 adrs += inc;
1980 }
1981}
1982
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001983static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984bsesc(void)
1985{
1986 int c;
1987
1988 c = inchar();
1989 switch( c ){
1990 case 'n': c = '\n'; break;
1991 case 'r': c = '\r'; break;
1992 case 'b': c = '\b'; break;
1993 case 't': c = '\t'; break;
1994 }
1995 return c;
1996}
1997
Olaf Hering7e5b5932006-03-08 20:40:28 +01001998static void xmon_rawdump (unsigned long adrs, long ndump)
1999{
2000 long n, m, r, nr;
2001 unsigned char temp[16];
2002
2003 for (n = ndump; n > 0;) {
2004 r = n < 16? n: 16;
2005 nr = mread(adrs, temp, r);
2006 adrs += nr;
2007 for (m = 0; m < r; ++m) {
2008 if (m < nr)
2009 printf("%.2x", temp[m]);
2010 else
2011 printf("%s", fault_chars[fault_type]);
2012 }
2013 n -= r;
2014 if (nr < r)
2015 break;
2016 }
2017 printf("\n");
2018}
2019
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002020#ifdef CONFIG_PPC64
2021static void dump_one_paca(int cpu)
2022{
2023 struct paca_struct *p;
2024
2025 if (setjmp(bus_error_jmp) != 0) {
2026 printf("*** Error dumping paca for cpu 0x%x!\n", cpu);
2027 return;
2028 }
2029
2030 catch_memory_errors = 1;
2031 sync();
2032
2033 p = &paca[cpu];
2034
2035 printf("paca for cpu 0x%x @ %p:\n", cpu, p);
2036
2037 printf(" %-*s = %s\n", 16, "possible", cpu_possible(cpu) ? "yes" : "no");
2038 printf(" %-*s = %s\n", 16, "present", cpu_present(cpu) ? "yes" : "no");
2039 printf(" %-*s = %s\n", 16, "online", cpu_online(cpu) ? "yes" : "no");
2040
2041#define DUMP(paca, name, format) \
2042 printf(" %-*s = %#-*"format"\t(0x%lx)\n", 16, #name, 18, paca->name, \
2043 offsetof(struct paca_struct, name));
2044
2045 DUMP(p, lock_token, "x");
2046 DUMP(p, paca_index, "x");
2047 DUMP(p, kernel_toc, "lx");
2048 DUMP(p, kernelbase, "lx");
2049 DUMP(p, kernel_msr, "lx");
2050#ifdef CONFIG_PPC_STD_MMU_64
2051 DUMP(p, stab_real, "lx");
2052 DUMP(p, stab_addr, "lx");
2053#endif
2054 DUMP(p, emergency_sp, "p");
2055 DUMP(p, data_offset, "lx");
2056 DUMP(p, hw_cpu_id, "x");
2057 DUMP(p, cpu_start, "x");
2058 DUMP(p, kexec_state, "x");
2059 DUMP(p, __current, "p");
2060 DUMP(p, kstack, "lx");
2061 DUMP(p, stab_rr, "lx");
2062 DUMP(p, saved_r1, "lx");
2063 DUMP(p, trap_save, "x");
2064 DUMP(p, soft_enabled, "x");
2065 DUMP(p, irq_happened, "x");
2066 DUMP(p, io_sync, "x");
2067 DUMP(p, irq_work_pending, "x");
2068 DUMP(p, nap_state_lost, "x");
2069
2070#undef DUMP
2071
2072 catch_memory_errors = 0;
2073 sync();
2074}
2075
2076static void dump_all_pacas(void)
2077{
2078 int cpu;
2079
2080 if (num_possible_cpus() == 0) {
2081 printf("No possible cpus, use 'dp #' to dump individual cpus\n");
2082 return;
2083 }
2084
2085 for_each_possible_cpu(cpu)
2086 dump_one_paca(cpu);
2087}
2088
2089static void dump_pacas(void)
2090{
2091 unsigned long num;
2092 int c;
2093
2094 c = inchar();
2095 if (c == 'a') {
2096 dump_all_pacas();
2097 return;
2098 }
2099
2100 termch = c; /* Put c back, it wasn't 'a' */
2101
2102 if (scanhex(&num))
2103 dump_one_paca(num);
2104 else
2105 dump_one_paca(xmon_owner);
2106}
2107#endif
2108
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
2110 || ('a' <= (c) && (c) <= 'f') \
2111 || ('A' <= (c) && (c) <= 'F'))
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002112static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113dump(void)
2114{
2115 int c;
2116
2117 c = inchar();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002118
2119#ifdef CONFIG_PPC64
2120 if (c == 'p') {
2121 dump_pacas();
2122 return;
2123 }
2124#endif
2125
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126 if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
2127 termch = c;
2128 scanhex((void *)&adrs);
2129 if (termch != '\n')
2130 termch = 0;
2131 if (c == 'i') {
2132 scanhex(&nidump);
2133 if (nidump == 0)
2134 nidump = 16;
2135 else if (nidump > MAX_DUMP)
2136 nidump = MAX_DUMP;
2137 adrs += ppc_inst_dump(adrs, nidump, 1);
2138 last_cmd = "di\n";
Vinay Sridharf312deb2009-05-14 23:13:07 +00002139 } else if (c == 'l') {
2140 dump_log_buf();
Olaf Hering7e5b5932006-03-08 20:40:28 +01002141 } else if (c == 'r') {
2142 scanhex(&ndump);
2143 if (ndump == 0)
2144 ndump = 64;
2145 xmon_rawdump(adrs, ndump);
2146 adrs += ndump;
2147 last_cmd = "dr\n";
Linus Torvalds1da177e2005-04-16 15:20:36 -07002148 } else {
2149 scanhex(&ndump);
2150 if (ndump == 0)
2151 ndump = 64;
2152 else if (ndump > MAX_DUMP)
2153 ndump = MAX_DUMP;
2154 prdump(adrs, ndump);
2155 adrs += ndump;
2156 last_cmd = "d\n";
2157 }
2158}
2159
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002160static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161prdump(unsigned long adrs, long ndump)
2162{
2163 long n, m, c, r, nr;
2164 unsigned char temp[16];
2165
2166 for (n = ndump; n > 0;) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002167 printf(REG, adrs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168 putchar(' ');
2169 r = n < 16? n: 16;
2170 nr = mread(adrs, temp, r);
2171 adrs += nr;
2172 for (m = 0; m < r; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002173 if ((m & (sizeof(long) - 1)) == 0 && m > 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002174 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 if (m < nr)
2176 printf("%.2x", temp[m]);
2177 else
2178 printf("%s", fault_chars[fault_type]);
2179 }
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002180 for (; m < 16; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002181 if ((m & (sizeof(long) - 1)) == 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002182 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183 printf(" ");
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002184 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185 printf(" |");
2186 for (m = 0; m < r; ++m) {
2187 if (m < nr) {
2188 c = temp[m];
2189 putchar(' ' <= c && c <= '~'? c: '.');
2190 } else
2191 putchar(' ');
2192 }
2193 n -= r;
2194 for (; m < 16; ++m)
2195 putchar(' ');
2196 printf("|\n");
2197 if (nr < r)
2198 break;
2199 }
2200}
2201
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002202typedef int (*instruction_dump_func)(unsigned long inst, unsigned long addr);
2203
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002204static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002205generic_inst_dump(unsigned long adr, long count, int praddr,
2206 instruction_dump_func dump_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207{
2208 int nr, dotted;
2209 unsigned long first_adr;
2210 unsigned long inst, last_inst = 0;
2211 unsigned char val[4];
2212
2213 dotted = 0;
2214 for (first_adr = adr; count > 0; --count, adr += 4) {
2215 nr = mread(adr, val, 4);
2216 if (nr == 0) {
2217 if (praddr) {
2218 const char *x = fault_chars[fault_type];
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002219 printf(REG" %s%s%s%s\n", adr, x, x, x, x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220 }
2221 break;
2222 }
2223 inst = GETWORD(val);
2224 if (adr > first_adr && inst == last_inst) {
2225 if (!dotted) {
2226 printf(" ...\n");
2227 dotted = 1;
2228 }
2229 continue;
2230 }
2231 dotted = 0;
2232 last_inst = inst;
2233 if (praddr)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002234 printf(REG" %.8x", adr, inst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235 printf("\t");
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002236 dump_func(inst, adr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237 printf("\n");
2238 }
2239 return adr - first_adr;
2240}
2241
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002242static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002243ppc_inst_dump(unsigned long adr, long count, int praddr)
2244{
2245 return generic_inst_dump(adr, count, praddr, print_insn_powerpc);
2246}
2247
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248void
2249print_address(unsigned long addr)
2250{
2251 xmon_print_symbol(addr, "\t# ", "");
2252}
2253
Vinay Sridharf312deb2009-05-14 23:13:07 +00002254void
2255dump_log_buf(void)
2256{
Michael Ellermanca5dd392012-08-23 22:09:12 +00002257 struct kmsg_dumper dumper = { .active = 1 };
2258 unsigned char buf[128];
2259 size_t len;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002260
Michael Ellermane3bc8042012-08-23 22:09:13 +00002261 if (setjmp(bus_error_jmp) != 0) {
Michael Ellermanca5dd392012-08-23 22:09:12 +00002262 printf("Error dumping printk buffer!\n");
Michael Ellermane3bc8042012-08-23 22:09:13 +00002263 return;
2264 }
Vinay Sridharf312deb2009-05-14 23:13:07 +00002265
Michael Ellermane3bc8042012-08-23 22:09:13 +00002266 catch_memory_errors = 1;
2267 sync();
Vinay Sridharf312deb2009-05-14 23:13:07 +00002268
Michael Ellermanca5dd392012-08-23 22:09:12 +00002269 kmsg_dump_rewind_nolock(&dumper);
2270 while (kmsg_dump_get_line_nolock(&dumper, false, buf, sizeof(buf), &len)) {
2271 buf[len] = '\0';
2272 printf("%s", buf);
2273 }
Vinay Sridharf312deb2009-05-14 23:13:07 +00002274
Michael Ellermane3bc8042012-08-23 22:09:13 +00002275 sync();
2276 /* wait a little while to see if we get a machine check */
2277 __delay(200);
2278 catch_memory_errors = 0;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002279}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280
2281/*
2282 * Memory operations - move, set, print differences
2283 */
2284static unsigned long mdest; /* destination address */
2285static unsigned long msrc; /* source address */
2286static unsigned long mval; /* byte value to set memory to */
2287static unsigned long mcount; /* # bytes to affect */
2288static unsigned long mdiffs; /* max # differences to print */
2289
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002290static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291memops(int cmd)
2292{
2293 scanhex((void *)&mdest);
2294 if( termch != '\n' )
2295 termch = 0;
2296 scanhex((void *)(cmd == 's'? &mval: &msrc));
2297 if( termch != '\n' )
2298 termch = 0;
2299 scanhex((void *)&mcount);
2300 switch( cmd ){
2301 case 'm':
2302 memmove((void *)mdest, (void *)msrc, mcount);
2303 break;
2304 case 's':
2305 memset((void *)mdest, mval, mcount);
2306 break;
2307 case 'd':
2308 if( termch != '\n' )
2309 termch = 0;
2310 scanhex((void *)&mdiffs);
2311 memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
2312 break;
2313 }
2314}
2315
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002316static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
2318{
2319 unsigned n, prt;
2320
2321 prt = 0;
2322 for( n = nb; n > 0; --n )
2323 if( *p1++ != *p2++ )
2324 if( ++prt <= maxpr )
2325 printf("%.16x %.2x # %.16x %.2x\n", p1 - 1,
2326 p1[-1], p2 - 1, p2[-1]);
2327 if( prt > maxpr )
2328 printf("Total of %d differences\n", prt);
2329}
2330
2331static unsigned mend;
2332static unsigned mask;
2333
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002334static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335memlocate(void)
2336{
2337 unsigned a, n;
2338 unsigned char val[4];
2339
2340 last_cmd = "ml";
2341 scanhex((void *)&mdest);
2342 if (termch != '\n') {
2343 termch = 0;
2344 scanhex((void *)&mend);
2345 if (termch != '\n') {
2346 termch = 0;
2347 scanhex((void *)&mval);
2348 mask = ~0;
2349 if (termch != '\n') termch = 0;
2350 scanhex((void *)&mask);
2351 }
2352 }
2353 n = 0;
2354 for (a = mdest; a < mend; a += 4) {
2355 if (mread(a, val, 4) == 4
2356 && ((GETWORD(val) ^ mval) & mask) == 0) {
2357 printf("%.16x: %.16x\n", a, GETWORD(val));
2358 if (++n >= 10)
2359 break;
2360 }
2361 }
2362}
2363
2364static unsigned long mskip = 0x1000;
2365static unsigned long mlim = 0xffffffff;
2366
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002367static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368memzcan(void)
2369{
2370 unsigned char v;
2371 unsigned a;
2372 int ok, ook;
2373
2374 scanhex(&mdest);
2375 if (termch != '\n') termch = 0;
2376 scanhex(&mskip);
2377 if (termch != '\n') termch = 0;
2378 scanhex(&mlim);
2379 ook = 0;
2380 for (a = mdest; a < mlim; a += mskip) {
2381 ok = mread(a, &v, 1);
2382 if (ok && !ook) {
2383 printf("%.8x .. ", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002384 } else if (!ok && ook)
2385 printf("%.8x\n", a - mskip);
2386 ook = ok;
2387 if (a + mskip < a)
2388 break;
2389 }
2390 if (ook)
2391 printf("%.8x\n", a - mskip);
2392}
2393
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002394static void proccall(void)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002395{
2396 unsigned long args[8];
2397 unsigned long ret;
2398 int i;
2399 typedef unsigned long (*callfunc_t)(unsigned long, unsigned long,
2400 unsigned long, unsigned long, unsigned long,
2401 unsigned long, unsigned long, unsigned long);
2402 callfunc_t func;
2403
2404 if (!scanhex(&adrs))
2405 return;
2406 if (termch != '\n')
2407 termch = 0;
2408 for (i = 0; i < 8; ++i)
2409 args[i] = 0;
2410 for (i = 0; i < 8; ++i) {
2411 if (!scanhex(&args[i]) || termch == '\n')
2412 break;
2413 termch = 0;
2414 }
2415 func = (callfunc_t) adrs;
2416 ret = 0;
2417 if (setjmp(bus_error_jmp) == 0) {
2418 catch_memory_errors = 1;
2419 sync();
2420 ret = func(args[0], args[1], args[2], args[3],
2421 args[4], args[5], args[6], args[7]);
2422 sync();
2423 printf("return value is %x\n", ret);
2424 } else {
2425 printf("*** %x exception occurred\n", fault_except);
2426 }
2427 catch_memory_errors = 0;
2428}
2429
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430/* Input scanning routines */
2431int
2432skipbl(void)
2433{
2434 int c;
2435
2436 if( termch != 0 ){
2437 c = termch;
2438 termch = 0;
2439 } else
2440 c = inchar();
2441 while( c == ' ' || c == '\t' )
2442 c = inchar();
2443 return c;
2444}
2445
2446#define N_PTREGS 44
2447static char *regnames[N_PTREGS] = {
2448 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
2449 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
2450 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
2451 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002452 "pc", "msr", "or3", "ctr", "lr", "xer", "ccr",
2453#ifdef CONFIG_PPC64
2454 "softe",
2455#else
2456 "mq",
2457#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002458 "trap", "dar", "dsisr", "res"
2459};
2460
2461int
2462scanhex(unsigned long *vp)
2463{
2464 int c, d;
2465 unsigned long v;
2466
2467 c = skipbl();
2468 if (c == '%') {
2469 /* parse register name */
2470 char regname[8];
2471 int i;
2472
2473 for (i = 0; i < sizeof(regname) - 1; ++i) {
2474 c = inchar();
2475 if (!isalnum(c)) {
2476 termch = c;
2477 break;
2478 }
2479 regname[i] = c;
2480 }
2481 regname[i] = 0;
2482 for (i = 0; i < N_PTREGS; ++i) {
2483 if (strcmp(regnames[i], regname) == 0) {
2484 if (xmon_regs == NULL) {
2485 printf("regs not available\n");
2486 return 0;
2487 }
2488 *vp = ((unsigned long *)xmon_regs)[i];
2489 return 1;
2490 }
2491 }
2492 printf("invalid register name '%%%s'\n", regname);
2493 return 0;
2494 }
2495
2496 /* skip leading "0x" if any */
2497
2498 if (c == '0') {
2499 c = inchar();
2500 if (c == 'x') {
2501 c = inchar();
2502 } else {
2503 d = hexdigit(c);
2504 if (d == EOF) {
2505 termch = c;
2506 *vp = 0;
2507 return 1;
2508 }
2509 }
2510 } else if (c == '$') {
2511 int i;
2512 for (i=0; i<63; i++) {
2513 c = inchar();
2514 if (isspace(c)) {
2515 termch = c;
2516 break;
2517 }
2518 tmpstr[i] = c;
2519 }
2520 tmpstr[i++] = 0;
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07002521 *vp = 0;
2522 if (setjmp(bus_error_jmp) == 0) {
2523 catch_memory_errors = 1;
2524 sync();
2525 *vp = kallsyms_lookup_name(tmpstr);
2526 sync();
2527 }
2528 catch_memory_errors = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529 if (!(*vp)) {
2530 printf("unknown symbol '%s'\n", tmpstr);
2531 return 0;
2532 }
2533 return 1;
2534 }
2535
2536 d = hexdigit(c);
2537 if (d == EOF) {
2538 termch = c;
2539 return 0;
2540 }
2541 v = 0;
2542 do {
2543 v = (v << 4) + d;
2544 c = inchar();
2545 d = hexdigit(c);
2546 } while (d != EOF);
2547 termch = c;
2548 *vp = v;
2549 return 1;
2550}
2551
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002552static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553scannl(void)
2554{
2555 int c;
2556
2557 c = termch;
2558 termch = 0;
2559 while( c != '\n' )
2560 c = inchar();
2561}
2562
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002563static int hexdigit(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564{
2565 if( '0' <= c && c <= '9' )
2566 return c - '0';
2567 if( 'A' <= c && c <= 'F' )
2568 return c - ('A' - 10);
2569 if( 'a' <= c && c <= 'f' )
2570 return c - ('a' - 10);
2571 return EOF;
2572}
2573
2574void
2575getstring(char *s, int size)
2576{
2577 int c;
2578
2579 c = skipbl();
2580 do {
2581 if( size > 1 ){
2582 *s++ = c;
2583 --size;
2584 }
2585 c = inchar();
2586 } while( c != ' ' && c != '\t' && c != '\n' );
2587 termch = c;
2588 *s = 0;
2589}
2590
2591static char line[256];
2592static char *lineptr;
2593
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002594static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002595flush_input(void)
2596{
2597 lineptr = NULL;
2598}
2599
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002600static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601inchar(void)
2602{
2603 if (lineptr == NULL || *lineptr == 0) {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002604 if (xmon_gets(line, sizeof(line)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605 lineptr = NULL;
2606 return EOF;
2607 }
2608 lineptr = line;
2609 }
2610 return *lineptr++;
2611}
2612
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002613static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614take_input(char *str)
2615{
2616 lineptr = str;
2617}
2618
2619
2620static void
2621symbol_lookup(void)
2622{
2623 int type = inchar();
2624 unsigned long addr;
2625 static char tmp[64];
2626
2627 switch (type) {
2628 case 'a':
2629 if (scanhex(&addr))
2630 xmon_print_symbol(addr, ": ", "\n");
2631 termch = 0;
2632 break;
2633 case 's':
2634 getstring(tmp, 64);
2635 if (setjmp(bus_error_jmp) == 0) {
2636 catch_memory_errors = 1;
2637 sync();
2638 addr = kallsyms_lookup_name(tmp);
2639 if (addr)
2640 printf("%s: %lx\n", tmp, addr);
2641 else
2642 printf("Symbol '%s' not found.\n", tmp);
2643 sync();
2644 }
2645 catch_memory_errors = 0;
2646 termch = 0;
2647 break;
2648 }
2649}
2650
2651
2652/* Print an address in numeric and symbolic form (if possible) */
2653static void xmon_print_symbol(unsigned long address, const char *mid,
2654 const char *after)
2655{
2656 char *modname;
2657 const char *name = NULL;
2658 unsigned long offset, size;
2659
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002660 printf(REG, address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661 if (setjmp(bus_error_jmp) == 0) {
2662 catch_memory_errors = 1;
2663 sync();
2664 name = kallsyms_lookup(address, &size, &offset, &modname,
2665 tmpstr);
2666 sync();
2667 /* wait a little while to see if we get a machine check */
2668 __delay(200);
2669 }
2670
2671 catch_memory_errors = 0;
2672
2673 if (name) {
2674 printf("%s%s+%#lx/%#lx", mid, name, offset, size);
2675 if (modname)
2676 printf(" [%s]", modname);
2677 }
2678 printf("%s", after);
2679}
2680
Benjamin Herrenschmidt2d27cfd2009-07-23 23:15:59 +00002681#ifdef CONFIG_PPC_BOOK3S_64
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682static void dump_slb(void)
2683{
2684 int i;
will schmidtb3b95952007-12-07 08:22:23 +11002685 unsigned long esid,vsid,valid;
2686 unsigned long llp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687
2688 printf("SLB contents of cpu %x\n", smp_processor_id());
2689
Michael Neuling584f8b72007-12-06 17:24:48 +11002690 for (i = 0; i < mmu_slb_size; i++) {
will schmidtb3b95952007-12-07 08:22:23 +11002691 asm volatile("slbmfee %0,%1" : "=r" (esid) : "r" (i));
2692 asm volatile("slbmfev %0,%1" : "=r" (vsid) : "r" (i));
2693 valid = (esid & SLB_ESID_V);
2694 if (valid | esid | vsid) {
2695 printf("%02d %016lx %016lx", i, esid, vsid);
2696 if (valid) {
2697 llp = vsid & SLB_VSID_LLP;
2698 if (vsid & SLB_VSID_B_1T) {
2699 printf(" 1T ESID=%9lx VSID=%13lx LLP:%3lx \n",
2700 GET_ESID_1T(esid),
2701 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT_1T,
2702 llp);
2703 } else {
2704 printf(" 256M ESID=%9lx VSID=%13lx LLP:%3lx \n",
2705 GET_ESID(esid),
2706 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT,
2707 llp);
2708 }
2709 } else
2710 printf("\n");
2711 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712 }
2713}
2714
2715static void dump_stab(void)
2716{
2717 int i;
Benjamin Herrenschmidt7ac21cd2012-03-02 10:10:09 +11002718 unsigned long *tmp = (unsigned long *)local_paca->stab_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719
2720 printf("Segment table contents of cpu %x\n", smp_processor_id());
2721
2722 for (i = 0; i < PAGE_SIZE/16; i++) {
2723 unsigned long a, b;
2724
2725 a = *tmp++;
2726 b = *tmp++;
2727
2728 if (a || b) {
2729 printf("%03d %016lx ", i, a);
2730 printf("%016lx\n", b);
2731 }
2732 }
2733}
2734
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002735void dump_segments(void)
2736{
Matt Evans44ae3ab2011-04-06 19:48:50 +00002737 if (mmu_has_feature(MMU_FTR_SLB))
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002738 dump_slb();
2739 else
2740 dump_stab();
2741}
2742#endif
2743
2744#ifdef CONFIG_PPC_STD_MMU_32
2745void dump_segments(void)
2746{
2747 int i;
2748
2749 printf("sr0-15 =");
2750 for (i = 0; i < 16; ++i)
2751 printf(" %x", mfsrin(i));
2752 printf("\n");
2753}
2754#endif
2755
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11002756#ifdef CONFIG_44x
2757static void dump_tlb_44x(void)
2758{
2759 int i;
2760
2761 for (i = 0; i < PPC44x_TLB_SIZE; i++) {
2762 unsigned long w0,w1,w2;
2763 asm volatile("tlbre %0,%1,0" : "=r" (w0) : "r" (i));
2764 asm volatile("tlbre %0,%1,1" : "=r" (w1) : "r" (i));
2765 asm volatile("tlbre %0,%1,2" : "=r" (w2) : "r" (i));
2766 printf("[%02x] %08x %08x %08x ", i, w0, w1, w2);
2767 if (w0 & PPC44x_TLB_VALID) {
2768 printf("V %08x -> %01x%08x %c%c%c%c%c",
2769 w0 & PPC44x_TLB_EPN_MASK,
2770 w1 & PPC44x_TLB_ERPN_MASK,
2771 w1 & PPC44x_TLB_RPN_MASK,
2772 (w2 & PPC44x_TLB_W) ? 'W' : 'w',
2773 (w2 & PPC44x_TLB_I) ? 'I' : 'i',
2774 (w2 & PPC44x_TLB_M) ? 'M' : 'm',
2775 (w2 & PPC44x_TLB_G) ? 'G' : 'g',
2776 (w2 & PPC44x_TLB_E) ? 'E' : 'e');
2777 }
2778 printf("\n");
2779 }
2780}
2781#endif /* CONFIG_44x */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002782
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +10002783#ifdef CONFIG_PPC_BOOK3E
2784static void dump_tlb_book3e(void)
2785{
2786 u32 mmucfg, pidmask, lpidmask;
2787 u64 ramask;
2788 int i, tlb, ntlbs, pidsz, lpidsz, rasz, lrat = 0;
2789 int mmu_version;
2790 static const char *pgsz_names[] = {
2791 " 1K",
2792 " 2K",
2793 " 4K",
2794 " 8K",
2795 " 16K",
2796 " 32K",
2797 " 64K",
2798 "128K",
2799 "256K",
2800 "512K",
2801 " 1M",
2802 " 2M",
2803 " 4M",
2804 " 8M",
2805 " 16M",
2806 " 32M",
2807 " 64M",
2808 "128M",
2809 "256M",
2810 "512M",
2811 " 1G",
2812 " 2G",
2813 " 4G",
2814 " 8G",
2815 " 16G",
2816 " 32G",
2817 " 64G",
2818 "128G",
2819 "256G",
2820 "512G",
2821 " 1T",
2822 " 2T",
2823 };
2824
2825 /* Gather some infos about the MMU */
2826 mmucfg = mfspr(SPRN_MMUCFG);
2827 mmu_version = (mmucfg & 3) + 1;
2828 ntlbs = ((mmucfg >> 2) & 3) + 1;
2829 pidsz = ((mmucfg >> 6) & 0x1f) + 1;
2830 lpidsz = (mmucfg >> 24) & 0xf;
2831 rasz = (mmucfg >> 16) & 0x7f;
2832 if ((mmu_version > 1) && (mmucfg & 0x10000))
2833 lrat = 1;
2834 printf("Book3E MMU MAV=%d.0,%d TLBs,%d-bit PID,%d-bit LPID,%d-bit RA\n",
2835 mmu_version, ntlbs, pidsz, lpidsz, rasz);
2836 pidmask = (1ul << pidsz) - 1;
2837 lpidmask = (1ul << lpidsz) - 1;
2838 ramask = (1ull << rasz) - 1;
2839
2840 for (tlb = 0; tlb < ntlbs; tlb++) {
2841 u32 tlbcfg;
2842 int nent, assoc, new_cc = 1;
2843 printf("TLB %d:\n------\n", tlb);
2844 switch(tlb) {
2845 case 0:
2846 tlbcfg = mfspr(SPRN_TLB0CFG);
2847 break;
2848 case 1:
2849 tlbcfg = mfspr(SPRN_TLB1CFG);
2850 break;
2851 case 2:
2852 tlbcfg = mfspr(SPRN_TLB2CFG);
2853 break;
2854 case 3:
2855 tlbcfg = mfspr(SPRN_TLB3CFG);
2856 break;
2857 default:
2858 printf("Unsupported TLB number !\n");
2859 continue;
2860 }
2861 nent = tlbcfg & 0xfff;
2862 assoc = (tlbcfg >> 24) & 0xff;
2863 for (i = 0; i < nent; i++) {
2864 u32 mas0 = MAS0_TLBSEL(tlb);
2865 u32 mas1 = MAS1_TSIZE(BOOK3E_PAGESZ_4K);
2866 u64 mas2 = 0;
2867 u64 mas7_mas3;
2868 int esel = i, cc = i;
2869
2870 if (assoc != 0) {
2871 cc = i / assoc;
2872 esel = i % assoc;
2873 mas2 = cc * 0x1000;
2874 }
2875
2876 mas0 |= MAS0_ESEL(esel);
2877 mtspr(SPRN_MAS0, mas0);
2878 mtspr(SPRN_MAS1, mas1);
2879 mtspr(SPRN_MAS2, mas2);
2880 asm volatile("tlbre 0,0,0" : : : "memory");
2881 mas1 = mfspr(SPRN_MAS1);
2882 mas2 = mfspr(SPRN_MAS2);
2883 mas7_mas3 = mfspr(SPRN_MAS7_MAS3);
2884 if (assoc && (i % assoc) == 0)
2885 new_cc = 1;
2886 if (!(mas1 & MAS1_VALID))
2887 continue;
2888 if (assoc == 0)
2889 printf("%04x- ", i);
2890 else if (new_cc)
2891 printf("%04x-%c", cc, 'A' + esel);
2892 else
2893 printf(" |%c", 'A' + esel);
2894 new_cc = 0;
2895 printf(" %016llx %04x %s %c%c AS%c",
2896 mas2 & ~0x3ffull,
2897 (mas1 >> 16) & 0x3fff,
2898 pgsz_names[(mas1 >> 7) & 0x1f],
2899 mas1 & MAS1_IND ? 'I' : ' ',
2900 mas1 & MAS1_IPROT ? 'P' : ' ',
2901 mas1 & MAS1_TS ? '1' : '0');
2902 printf(" %c%c%c%c%c%c%c",
2903 mas2 & MAS2_X0 ? 'a' : ' ',
2904 mas2 & MAS2_X1 ? 'v' : ' ',
2905 mas2 & MAS2_W ? 'w' : ' ',
2906 mas2 & MAS2_I ? 'i' : ' ',
2907 mas2 & MAS2_M ? 'm' : ' ',
2908 mas2 & MAS2_G ? 'g' : ' ',
2909 mas2 & MAS2_E ? 'e' : ' ');
2910 printf(" %016llx", mas7_mas3 & ramask & ~0x7ffull);
2911 if (mas1 & MAS1_IND)
2912 printf(" %s\n",
2913 pgsz_names[(mas7_mas3 >> 1) & 0x1f]);
2914 else
2915 printf(" U%c%c%c S%c%c%c\n",
2916 mas7_mas3 & MAS3_UX ? 'x' : ' ',
2917 mas7_mas3 & MAS3_UW ? 'w' : ' ',
2918 mas7_mas3 & MAS3_UR ? 'r' : ' ',
2919 mas7_mas3 & MAS3_SX ? 'x' : ' ',
2920 mas7_mas3 & MAS3_SW ? 'w' : ' ',
2921 mas7_mas3 & MAS3_SR ? 'r' : ' ');
2922 }
2923 }
2924}
2925#endif /* CONFIG_PPC_BOOK3E */
2926
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002927static void xmon_init(int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928{
Olaf Heringb13cfd12005-08-04 19:26:42 +02002929 if (enable) {
2930 __debugger = xmon;
2931 __debugger_ipi = xmon_ipi;
2932 __debugger_bpt = xmon_bpt;
2933 __debugger_sstep = xmon_sstep;
2934 __debugger_iabr_match = xmon_iabr_match;
2935 __debugger_dabr_match = xmon_dabr_match;
2936 __debugger_fault_handler = xmon_fault_handler;
2937 } else {
2938 __debugger = NULL;
2939 __debugger_ipi = NULL;
2940 __debugger_bpt = NULL;
2941 __debugger_sstep = NULL;
2942 __debugger_iabr_match = NULL;
2943 __debugger_dabr_match = NULL;
2944 __debugger_fault_handler = NULL;
2945 }
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002946 xmon_map_scc();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947}
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002948
2949#ifdef CONFIG_MAGIC_SYSRQ
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07002950static void sysrq_handle_xmon(int key)
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002951{
2952 /* ensure xmon is enabled */
2953 xmon_init(1);
David Howells7d12e782006-10-05 14:55:46 +01002954 debugger(get_irq_regs());
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002955}
2956
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07002957static struct sysrq_key_op sysrq_xmon_op = {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002958 .handler = sysrq_handle_xmon,
2959 .help_msg = "Xmon",
2960 .action_msg = "Entering xmon",
2961};
2962
2963static int __init setup_xmon_sysrq(void)
2964{
2965 register_sysrq_key('x', &sysrq_xmon_op);
2966 return 0;
2967}
2968__initcall(setup_xmon_sysrq);
2969#endif /* CONFIG_MAGIC_SYSRQ */
Michael Ellerman476792832006-10-03 14:12:08 +10002970
Olaf Heringf5e6a282007-06-24 16:57:08 +10002971static int __initdata xmon_early, xmon_off;
Michael Ellerman476792832006-10-03 14:12:08 +10002972
2973static int __init early_parse_xmon(char *p)
2974{
2975 if (!p || strncmp(p, "early", 5) == 0) {
2976 /* just "xmon" is equivalent to "xmon=early" */
2977 xmon_init(1);
2978 xmon_early = 1;
2979 } else if (strncmp(p, "on", 2) == 0)
2980 xmon_init(1);
2981 else if (strncmp(p, "off", 3) == 0)
2982 xmon_off = 1;
2983 else if (strncmp(p, "nobt", 4) == 0)
2984 xmon_no_auto_backtrace = 1;
2985 else
2986 return 1;
2987
2988 return 0;
2989}
2990early_param("xmon", early_parse_xmon);
2991
2992void __init xmon_setup(void)
2993{
2994#ifdef CONFIG_XMON_DEFAULT
2995 if (!xmon_off)
2996 xmon_init(1);
2997#endif
2998 if (xmon_early)
2999 debugger(NULL);
3000}
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003001
Arnd Bergmanne0555952006-11-27 19:18:55 +01003002#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003003
3004struct spu_info {
3005 struct spu *spu;
3006 u64 saved_mfc_sr1_RW;
3007 u32 saved_spu_runcntl_RW;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003008 unsigned long dump_addr;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003009 u8 stopped_ok;
3010};
3011
3012#define XMON_NUM_SPUS 16 /* Enough for current hardware */
3013
3014static struct spu_info spu_info[XMON_NUM_SPUS];
3015
3016void xmon_register_spus(struct list_head *list)
3017{
3018 struct spu *spu;
3019
3020 list_for_each_entry(spu, list, full_list) {
3021 if (spu->number >= XMON_NUM_SPUS) {
3022 WARN_ON(1);
3023 continue;
3024 }
3025
3026 spu_info[spu->number].spu = spu;
3027 spu_info[spu->number].stopped_ok = 0;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003028 spu_info[spu->number].dump_addr = (unsigned long)
3029 spu_info[spu->number].spu->local_store;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003030 }
3031}
3032
3033static void stop_spus(void)
3034{
3035 struct spu *spu;
3036 int i;
3037 u64 tmp;
3038
3039 for (i = 0; i < XMON_NUM_SPUS; i++) {
3040 if (!spu_info[i].spu)
3041 continue;
3042
3043 if (setjmp(bus_error_jmp) == 0) {
3044 catch_memory_errors = 1;
3045 sync();
3046
3047 spu = spu_info[i].spu;
3048
3049 spu_info[i].saved_spu_runcntl_RW =
3050 in_be32(&spu->problem->spu_runcntl_RW);
3051
3052 tmp = spu_mfc_sr1_get(spu);
3053 spu_info[i].saved_mfc_sr1_RW = tmp;
3054
3055 tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
3056 spu_mfc_sr1_set(spu, tmp);
3057
3058 sync();
3059 __delay(200);
3060
3061 spu_info[i].stopped_ok = 1;
Michael Ellerman2a144422006-11-23 00:46:40 +01003062
3063 printf("Stopped spu %.2d (was %s)\n", i,
3064 spu_info[i].saved_spu_runcntl_RW ?
3065 "running" : "stopped");
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003066 } else {
3067 catch_memory_errors = 0;
3068 printf("*** Error stopping spu %.2d\n", i);
3069 }
3070 catch_memory_errors = 0;
3071 }
3072}
3073
3074static void restart_spus(void)
3075{
3076 struct spu *spu;
3077 int i;
3078
3079 for (i = 0; i < XMON_NUM_SPUS; i++) {
3080 if (!spu_info[i].spu)
3081 continue;
3082
3083 if (!spu_info[i].stopped_ok) {
3084 printf("*** Error, spu %d was not successfully stopped"
3085 ", not restarting\n", i);
3086 continue;
3087 }
3088
3089 if (setjmp(bus_error_jmp) == 0) {
3090 catch_memory_errors = 1;
3091 sync();
3092
3093 spu = spu_info[i].spu;
3094 spu_mfc_sr1_set(spu, spu_info[i].saved_mfc_sr1_RW);
3095 out_be32(&spu->problem->spu_runcntl_RW,
3096 spu_info[i].saved_spu_runcntl_RW);
3097
3098 sync();
3099 __delay(200);
3100
3101 printf("Restarted spu %.2d\n", i);
3102 } else {
3103 catch_memory_errors = 0;
3104 printf("*** Error restarting spu %.2d\n", i);
3105 }
3106 catch_memory_errors = 0;
3107 }
3108}
3109
Michael Ellermana8984972006-10-24 18:31:28 +02003110#define DUMP_WIDTH 23
Michael Ellerman437a0702006-11-23 00:46:39 +01003111#define DUMP_VALUE(format, field, value) \
Michael Ellermana8984972006-10-24 18:31:28 +02003112do { \
3113 if (setjmp(bus_error_jmp) == 0) { \
3114 catch_memory_errors = 1; \
3115 sync(); \
3116 printf(" %-*s = "format"\n", DUMP_WIDTH, \
Michael Ellerman437a0702006-11-23 00:46:39 +01003117 #field, value); \
Michael Ellermana8984972006-10-24 18:31:28 +02003118 sync(); \
3119 __delay(200); \
3120 } else { \
3121 catch_memory_errors = 0; \
3122 printf(" %-*s = *** Error reading field.\n", \
3123 DUMP_WIDTH, #field); \
3124 } \
3125 catch_memory_errors = 0; \
3126} while (0)
3127
Michael Ellerman437a0702006-11-23 00:46:39 +01003128#define DUMP_FIELD(obj, format, field) \
3129 DUMP_VALUE(format, field, obj->field)
3130
Michael Ellermana8984972006-10-24 18:31:28 +02003131static void dump_spu_fields(struct spu *spu)
3132{
3133 printf("Dumping spu fields at address %p:\n", spu);
3134
3135 DUMP_FIELD(spu, "0x%x", number);
3136 DUMP_FIELD(spu, "%s", name);
Michael Ellermana8984972006-10-24 18:31:28 +02003137 DUMP_FIELD(spu, "0x%lx", local_store_phys);
3138 DUMP_FIELD(spu, "0x%p", local_store);
3139 DUMP_FIELD(spu, "0x%lx", ls_size);
3140 DUMP_FIELD(spu, "0x%x", node);
3141 DUMP_FIELD(spu, "0x%lx", flags);
Michael Ellermana8984972006-10-24 18:31:28 +02003142 DUMP_FIELD(spu, "%d", class_0_pending);
Luke Browningf3d69e02008-04-27 18:41:55 +00003143 DUMP_FIELD(spu, "0x%lx", class_0_dar);
Luke Browningf3d69e02008-04-27 18:41:55 +00003144 DUMP_FIELD(spu, "0x%lx", class_1_dar);
3145 DUMP_FIELD(spu, "0x%lx", class_1_dsisr);
Michael Ellermana8984972006-10-24 18:31:28 +02003146 DUMP_FIELD(spu, "0x%lx", irqs[0]);
3147 DUMP_FIELD(spu, "0x%lx", irqs[1]);
3148 DUMP_FIELD(spu, "0x%lx", irqs[2]);
3149 DUMP_FIELD(spu, "0x%x", slb_replace);
3150 DUMP_FIELD(spu, "%d", pid);
Michael Ellermana8984972006-10-24 18:31:28 +02003151 DUMP_FIELD(spu, "0x%p", mm);
3152 DUMP_FIELD(spu, "0x%p", ctx);
3153 DUMP_FIELD(spu, "0x%p", rq);
3154 DUMP_FIELD(spu, "0x%p", timestamp);
3155 DUMP_FIELD(spu, "0x%lx", problem_phys);
3156 DUMP_FIELD(spu, "0x%p", problem);
Michael Ellerman437a0702006-11-23 00:46:39 +01003157 DUMP_VALUE("0x%x", problem->spu_runcntl_RW,
3158 in_be32(&spu->problem->spu_runcntl_RW));
3159 DUMP_VALUE("0x%x", problem->spu_status_R,
3160 in_be32(&spu->problem->spu_status_R));
3161 DUMP_VALUE("0x%x", problem->spu_npc_RW,
3162 in_be32(&spu->problem->spu_npc_RW));
Michael Ellermana8984972006-10-24 18:31:28 +02003163 DUMP_FIELD(spu, "0x%p", priv2);
Michael Ellermana9852392006-11-23 00:46:50 +01003164 DUMP_FIELD(spu, "0x%p", pdata);
Michael Ellermana8984972006-10-24 18:31:28 +02003165}
3166
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003167int
3168spu_inst_dump(unsigned long adr, long count, int praddr)
3169{
3170 return generic_inst_dump(adr, count, praddr, print_insn_spu);
3171}
3172
3173static void dump_spu_ls(unsigned long num, int subcmd)
Michael Ellerman24a24c82006-11-23 00:46:41 +01003174{
3175 unsigned long offset, addr, ls_addr;
3176
3177 if (setjmp(bus_error_jmp) == 0) {
3178 catch_memory_errors = 1;
3179 sync();
3180 ls_addr = (unsigned long)spu_info[num].spu->local_store;
3181 sync();
3182 __delay(200);
3183 } else {
3184 catch_memory_errors = 0;
3185 printf("*** Error: accessing spu info for spu %d\n", num);
3186 return;
3187 }
3188 catch_memory_errors = 0;
3189
3190 if (scanhex(&offset))
3191 addr = ls_addr + offset;
3192 else
3193 addr = spu_info[num].dump_addr;
3194
3195 if (addr >= ls_addr + LS_SIZE) {
3196 printf("*** Error: address outside of local store\n");
3197 return;
3198 }
3199
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003200 switch (subcmd) {
3201 case 'i':
3202 addr += spu_inst_dump(addr, 16, 1);
3203 last_cmd = "sdi\n";
3204 break;
3205 default:
3206 prdump(addr, 64);
3207 addr += 64;
3208 last_cmd = "sd\n";
3209 break;
3210 }
Michael Ellerman24a24c82006-11-23 00:46:41 +01003211
3212 spu_info[num].dump_addr = addr;
3213}
3214
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003215static int do_spu_cmd(void)
3216{
Michael Ellerman24a24c82006-11-23 00:46:41 +01003217 static unsigned long num = 0;
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003218 int cmd, subcmd = 0;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003219
3220 cmd = inchar();
3221 switch (cmd) {
3222 case 's':
3223 stop_spus();
3224 break;
3225 case 'r':
3226 restart_spus();
3227 break;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003228 case 'd':
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003229 subcmd = inchar();
3230 if (isxdigit(subcmd) || subcmd == '\n')
3231 termch = subcmd;
3232 case 'f':
Michael Ellerman24a24c82006-11-23 00:46:41 +01003233 scanhex(&num);
3234 if (num >= XMON_NUM_SPUS || !spu_info[num].spu) {
Michael Ellermana8984972006-10-24 18:31:28 +02003235 printf("*** Error: invalid spu number\n");
Michael Ellerman24a24c82006-11-23 00:46:41 +01003236 return 0;
3237 }
3238
3239 switch (cmd) {
3240 case 'f':
3241 dump_spu_fields(spu_info[num].spu);
3242 break;
3243 default:
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003244 dump_spu_ls(num, subcmd);
Michael Ellerman24a24c82006-11-23 00:46:41 +01003245 break;
3246 }
3247
Michael Ellermana8984972006-10-24 18:31:28 +02003248 break;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003249 default:
3250 return -1;
3251 }
3252
3253 return 0;
3254}
Arnd Bergmanne0555952006-11-27 19:18:55 +01003255#else /* ! CONFIG_SPU_BASE */
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003256static int do_spu_cmd(void)
3257{
3258 return -1;
3259}
3260#endif