blob: b988b5addf864a581ff8c36e177379c32ba92518 [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>
Anton Blancharda71d64b2014-08-05 14:55:00 +100027#include <linux/nmi.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070028
29#include <asm/ptrace.h>
30#include <asm/string.h>
31#include <asm/prom.h>
32#include <asm/machdep.h>
Paul Mackerrasf78541dc2005-10-28 22:53:37 +100033#include <asm/xmon.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <asm/processor.h>
35#include <asm/pgtable.h>
36#include <asm/mmu.h>
37#include <asm/mmu_context.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include <asm/cputable.h>
39#include <asm/rtas.h>
40#include <asm/sstep.h>
Paul Mackerrasf583ffc2006-10-10 11:47:07 +100041#include <asm/irq_regs.h>
Michael Ellermanff8a8f22006-10-24 18:31:27 +020042#include <asm/spu.h>
43#include <asm/spu_priv1.h>
Michael Neulingc3b75bd2008-01-18 15:50:30 +110044#include <asm/setjmp.h>
Anton Vorontsov322b4392008-12-17 10:08:55 +000045#include <asm/reg.h>
David Howellsae3a1972012-03-28 18:30:02 +010046#include <asm/debug.h>
Michael Neuling9422de32012-12-20 14:06:44 +000047#include <asm/hw_breakpoint.h>
Paul Mackerrasf78541dc2005-10-28 22:53:37 +100048
49#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -070050#include <asm/hvcall.h>
Paul Mackerrasf78541dc2005-10-28 22:53:37 +100051#include <asm/paca.h>
52#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070053
54#include "nonstdio.h"
Michael Ellermane0426042006-11-23 00:46:45 +010055#include "dis-asm.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070056
Linus Torvalds1da177e2005-04-16 15:20:36 -070057#ifdef CONFIG_SMP
Michael Ellerman1c8950f2008-05-08 14:27:17 +100058static cpumask_t cpus_in_xmon = CPU_MASK_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070059static unsigned long xmon_taken = 1;
60static int xmon_owner;
61static int xmon_gate;
Michael Ellermanddadb6b2012-09-13 23:01:31 +000062#else
63#define xmon_owner 0
Linus Torvalds1da177e2005-04-16 15:20:36 -070064#endif /* CONFIG_SMP */
65
Anton Blanchard5be34922010-01-12 00:50:14 +000066static unsigned long in_xmon __read_mostly = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070067
68static unsigned long adrs;
69static int size = 1;
70#define MAX_DUMP (128 * 1024)
71static unsigned long ndump = 64;
72static unsigned long nidump = 16;
73static unsigned long ncsum = 4096;
74static int termch;
75static char tmpstr[128];
76
Linus Torvalds1da177e2005-04-16 15:20:36 -070077static long bus_error_jmp[JMP_BUF_LEN];
78static int catch_memory_errors;
79static long *xmon_fault_jmp[NR_CPUS];
Linus Torvalds1da177e2005-04-16 15:20:36 -070080
81/* Breakpoint stuff */
82struct bpt {
83 unsigned long address;
84 unsigned int instr[2];
85 atomic_t ref_count;
86 int enabled;
87 unsigned long pad;
88};
89
90/* Bits in bpt.enabled */
91#define BP_IABR_TE 1 /* IABR translation enabled */
92#define BP_IABR 2
93#define BP_TRAP 8
94#define BP_DABR 0x10
95
96#define NBPTS 256
97static struct bpt bpts[NBPTS];
98static struct bpt dabr;
99static struct bpt *iabr;
100static unsigned bpinstr = 0x7fe00008; /* trap */
101
102#define BP_NUM(bp) ((bp) - bpts + 1)
103
104/* Prototypes */
105static int cmds(struct pt_regs *);
106static int mread(unsigned long, void *, int);
107static int mwrite(unsigned long, void *, int);
108static int handle_fault(struct pt_regs *);
109static void byterev(unsigned char *, int);
110static void memex(void);
111static int bsesc(void);
112static void dump(void);
113static void prdump(unsigned long, long);
114static int ppc_inst_dump(unsigned long, long, int);
Vinay Sridharf312deb2009-05-14 23:13:07 +0000115static void dump_log_buf(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116static void backtrace(struct pt_regs *);
117static void excprint(struct pt_regs *);
118static void prregs(struct pt_regs *);
119static void memops(int);
120static void memlocate(void);
121static void memzcan(void);
122static void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned);
123int skipbl(void);
124int scanhex(unsigned long *valp);
125static void scannl(void);
126static int hexdigit(int);
127void getstring(char *, int);
128static void flush_input(void);
129static int inchar(void);
130static void take_input(char *);
131static unsigned long read_spr(int);
132static void write_spr(int, unsigned long);
133static void super_regs(void);
134static void remove_bpts(void);
135static void insert_bpts(void);
136static void remove_cpu_bpts(void);
137static void insert_cpu_bpts(void);
138static struct bpt *at_breakpoint(unsigned long pc);
139static struct bpt *in_breakpoint_table(unsigned long pc, unsigned long *offp);
140static int do_step(struct pt_regs *);
141static void bpt_cmds(void);
142static void cacheflush(void);
143static int cpu_cmd(void);
144static void csum(void);
145static void bootcmds(void);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000146static void proccall(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147void dump_segments(void);
148static void symbol_lookup(void);
Olaf Hering26c8af52006-09-08 16:29:21 +0200149static void xmon_show_stack(unsigned long sp, unsigned long lr,
150 unsigned long pc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151static void xmon_print_symbol(unsigned long address, const char *mid,
152 const char *after);
153static const char *getvecname(unsigned long vec);
154
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200155static int do_spu_cmd(void);
156
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100157#ifdef CONFIG_44x
158static void dump_tlb_44x(void);
159#endif
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +1000160#ifdef CONFIG_PPC_BOOK3E
161static void dump_tlb_book3e(void);
162#endif
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100163
Michael Ellerman9f1067c22008-05-08 14:27:16 +1000164static int xmon_no_auto_backtrace;
Olaf Hering26c8af52006-09-08 16:29:21 +0200165
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000166extern void xmon_enter(void);
167extern void xmon_leave(void);
168
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000169#ifdef CONFIG_PPC64
170#define REG "%.16lx"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000171#else
172#define REG "%.8lx"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000173#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174
Philippe Bergheaud72eceef2013-12-02 10:10:12 +0100175#ifdef __LITTLE_ENDIAN__
176#define GETWORD(v) (((v)[3] << 24) + ((v)[2] << 16) + ((v)[1] << 8) + (v)[0])
177#else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178#define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
Philippe Bergheaud72eceef2013-12-02 10:10:12 +0100179#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180
181#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
182 || ('a' <= (c) && (c) <= 'f') \
183 || ('A' <= (c) && (c) <= 'F'))
184#define isalnum(c) (('0' <= (c) && (c) <= '9') \
185 || ('a' <= (c) && (c) <= 'z') \
186 || ('A' <= (c) && (c) <= 'Z'))
187#define isspace(c) (c == ' ' || c == '\t' || c == 10 || c == 13 || c == 0)
188
189static char *help_string = "\
190Commands:\n\
191 b show breakpoints\n\
192 bd set data breakpoint\n\
193 bi set instruction breakpoint\n\
194 bc clear breakpoint\n"
195#ifdef CONFIG_SMP
196 "\
197 c print cpus stopped in xmon\n\
198 c# try to switch to cpu number h (in hex)\n"
199#endif
200 "\
201 C checksum\n\
202 d dump bytes\n\
203 di dump instructions\n\
204 df dump float values\n\
205 dd dump double values\n\
Michael Ellermanddadb6b2012-09-13 23:01:31 +0000206 dl dump the kernel log buffer\n"
207#ifdef CONFIG_PPC64
208 "\
209 dp[#] dump paca for current cpu, or cpu #\n\
210 dpa dump paca for all possible cpus\n"
211#endif
212 "\
Olaf Hering7e5b5932006-03-08 20:40:28 +0100213 dr dump stream of raw bytes\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 e print exception information\n\
215 f flush cache\n\
216 la lookup symbol+offset of specified address\n\
217 ls lookup address of specified symbol\n\
218 m examine/change memory\n\
219 mm move a block of memory\n\
220 ms set a block of memory\n\
221 md compare two blocks of memory\n\
222 ml locate a block of memory\n\
223 mz zero a block of memory\n\
224 mi show information about memory allocation\n\
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000225 p call a procedure\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 r print registers\n\
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200227 s single step\n"
Arnd Bergmanne0555952006-11-27 19:18:55 +0100228#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200229" ss stop execution on all spus\n\
Michael Ellermana8984972006-10-24 18:31:28 +0200230 sr restore execution on stopped spus\n\
Michael Ellerman24a24c82006-11-23 00:46:41 +0100231 sf # dump spu fields for spu # (in hex)\n\
Michael Ellermanc99176a2007-02-26 18:14:06 +0900232 sd # dump spu local store for spu # (in hex)\n\
Michael Ellermanaf89fb82006-11-23 00:46:44 +0100233 sdi # disassemble spu local store for spu # (in hex)\n"
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200234#endif
235" S print special registers\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 t print backtrace\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 x exit monitor and recover\n\
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000238 X exit monitor and dont recover\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000239#if defined(CONFIG_PPC64) && !defined(CONFIG_PPC_BOOK3E)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000240" u dump segment table or SLB\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000241#elif defined(CONFIG_PPC_STD_MMU_32)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000242" u dump segment registers\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000243#elif defined(CONFIG_44x) || defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100244" u dump TLB\n"
245#endif
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000246" ? help\n"
247" zr reboot\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 zh halt\n"
249;
250
251static struct pt_regs *xmon_regs;
252
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000253static inline void sync(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254{
255 asm volatile("sync; isync");
256}
257
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000258static inline void store_inst(void *p)
259{
260 asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p));
261}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000263static inline void cflush(void *p)
264{
265 asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p));
266}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000268static inline void cinval(void *p)
269{
270 asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p));
271}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272
273/*
274 * Disable surveillance (the service processor watchdog function)
275 * while we are in xmon.
276 * XXX we should re-enable it when we leave. :)
277 */
278#define SURVEILLANCE_TOKEN 9000
279
280static inline void disable_surveillance(void)
281{
282#ifdef CONFIG_PPC_PSERIES
283 /* Since this can't be a module, args should end up below 4GB. */
284 static struct rtas_args args;
285
286 /*
287 * At this point we have got all the cpus we can into
288 * xmon, so there is hopefully no other cpu calling RTAS
289 * at the moment, even though we don't take rtas.lock.
290 * If we did try to take rtas.lock there would be a
291 * real possibility of deadlock.
292 */
293 args.token = rtas_token("set-indicator");
294 if (args.token == RTAS_UNKNOWN_SERVICE)
295 return;
296 args.nargs = 3;
297 args.nret = 1;
298 args.rets = &args.args[3];
299 args.args[0] = SURVEILLANCE_TOKEN;
300 args.args[1] = 0;
301 args.args[2] = 0;
302 enter_rtas(__pa(&args));
303#endif /* CONFIG_PPC_PSERIES */
304}
305
306#ifdef CONFIG_SMP
307static int xmon_speaker;
308
309static void get_output_lock(void)
310{
311 int me = smp_processor_id() + 0x100;
312 int last_speaker = 0, prev;
313 long timeout;
314
315 if (xmon_speaker == me)
316 return;
Michael Ellerman730efb62013-12-23 23:46:04 +1100317
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 for (;;) {
Michael Ellerman730efb62013-12-23 23:46:04 +1100319 last_speaker = cmpxchg(&xmon_speaker, 0, me);
320 if (last_speaker == 0)
321 return;
322
Michael Ellerman15075892013-12-23 23:46:05 +1100323 /*
324 * Wait a full second for the lock, we might be on a slow
325 * console, but check every 100us.
326 */
327 timeout = 10000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 while (xmon_speaker == last_speaker) {
Michael Ellerman15075892013-12-23 23:46:05 +1100329 if (--timeout > 0) {
330 udelay(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 continue;
Michael Ellerman15075892013-12-23 23:46:05 +1100332 }
333
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 /* hostile takeover */
335 prev = cmpxchg(&xmon_speaker, last_speaker, me);
336 if (prev == last_speaker)
337 return;
338 break;
339 }
340 }
341}
342
343static void release_output_lock(void)
344{
345 xmon_speaker = 0;
346}
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000347
348int cpus_are_in_xmon(void)
349{
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000350 return !cpumask_empty(&cpus_in_xmon);
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000351}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352#endif
353
Josh Boyerdaf8f402009-09-23 03:51:04 +0000354static inline int unrecoverable_excp(struct pt_regs *regs)
355{
Jimi Xenidis08f6d6a2011-09-29 12:05:28 +0000356#if defined(CONFIG_4xx) || defined(CONFIG_PPC_BOOK3E)
Jimi Xenidis66857b32011-09-23 05:40:46 +0000357 /* We have no MSR_RI bit on 4xx or Book3e, so we simply return false */
Josh Boyerdaf8f402009-09-23 03:51:04 +0000358 return 0;
359#else
360 return ((regs->msr & MSR_RI) == 0);
361#endif
362}
363
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000364static int xmon_core(struct pt_regs *regs, int fromipi)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365{
366 int cmd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 struct bpt *bp;
368 long recurse_jmp[JMP_BUF_LEN];
369 unsigned long offset;
Anton Blanchardf13659e2007-03-21 01:48:34 +1100370 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371#ifdef CONFIG_SMP
372 int cpu;
373 int secondary;
374 unsigned long timeout;
375#endif
376
Anton Blanchardf13659e2007-03-21 01:48:34 +1100377 local_irq_save(flags);
Anton Blancharda71d64b2014-08-05 14:55:00 +1000378 hard_irq_disable();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379
380 bp = in_breakpoint_table(regs->nip, &offset);
381 if (bp != NULL) {
382 regs->nip = bp->address + offset;
383 atomic_dec(&bp->ref_count);
384 }
385
386 remove_cpu_bpts();
387
388#ifdef CONFIG_SMP
389 cpu = smp_processor_id();
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000390 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 get_output_lock();
392 excprint(regs);
393 printf("cpu 0x%x: Exception %lx %s in xmon, "
394 "returning to main loop\n",
395 cpu, regs->trap, getvecname(TRAP(regs)));
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000396 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 longjmp(xmon_fault_jmp[cpu], 1);
398 }
399
400 if (setjmp(recurse_jmp) != 0) {
401 if (!in_xmon || !xmon_gate) {
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000402 get_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 printf("xmon: WARNING: bad recursive fault "
404 "on cpu 0x%x\n", cpu);
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000405 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 goto waiting;
407 }
408 secondary = !(xmon_taken && cpu == xmon_owner);
409 goto cmdloop;
410 }
411
412 xmon_fault_jmp[cpu] = recurse_jmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413
414 bp = NULL;
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000415 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 bp = at_breakpoint(regs->nip);
Josh Boyerdaf8f402009-09-23 03:51:04 +0000417 if (bp || unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 fromipi = 0;
419
420 if (!fromipi) {
421 get_output_lock();
422 excprint(regs);
423 if (bp) {
Michael Ellerman736256e2014-05-26 21:02:14 +1000424 printf("cpu 0x%x stopped at breakpoint 0x%lx (",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 cpu, BP_NUM(bp));
426 xmon_print_symbol(regs->nip, " ", ")\n");
427 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000428 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 printf("WARNING: exception is not recoverable, "
430 "can't continue\n");
431 release_output_lock();
432 }
433
Michael Ellermand2b496e2013-12-23 23:46:06 +1100434 cpumask_set_cpu(cpu, &cpus_in_xmon);
435
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 waiting:
437 secondary = 1;
438 while (secondary && !xmon_gate) {
439 if (in_xmon == 0) {
440 if (fromipi)
441 goto leave;
442 secondary = test_and_set_bit(0, &in_xmon);
443 }
444 barrier();
445 }
446
447 if (!secondary && !xmon_gate) {
448 /* we are the first cpu to come in */
449 /* interrupt other cpu(s) */
450 int ncpus = num_online_cpus();
451
452 xmon_owner = cpu;
453 mb();
454 if (ncpus > 1) {
Milton Millere0476372011-05-10 19:29:06 +0000455 smp_send_debugger_break();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 /* wait for other cpus to come in */
457 for (timeout = 100000000; timeout != 0; --timeout) {
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000458 if (cpumask_weight(&cpus_in_xmon) >= ncpus)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 break;
460 barrier();
461 }
462 }
463 remove_bpts();
464 disable_surveillance();
465 /* for breakpoint or single step, print the current instr. */
466 if (bp || TRAP(regs) == 0xd00)
467 ppc_inst_dump(regs->nip, 1, 0);
468 printf("enter ? for help\n");
469 mb();
470 xmon_gate = 1;
471 barrier();
472 }
473
474 cmdloop:
475 while (in_xmon) {
476 if (secondary) {
477 if (cpu == xmon_owner) {
478 if (!test_and_set_bit(0, &xmon_taken)) {
479 secondary = 0;
480 continue;
481 }
482 /* missed it */
483 while (cpu == xmon_owner)
484 barrier();
485 }
486 barrier();
487 } else {
488 cmd = cmds(regs);
489 if (cmd != 0) {
490 /* exiting xmon */
491 insert_bpts();
492 xmon_gate = 0;
493 wmb();
494 in_xmon = 0;
495 break;
496 }
497 /* have switched to some other cpu */
498 secondary = 1;
499 }
500 }
501 leave:
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000502 cpumask_clear_cpu(cpu, &cpus_in_xmon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 xmon_fault_jmp[cpu] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504#else
505 /* UP is simple... */
506 if (in_xmon) {
507 printf("Exception %lx %s in xmon, returning to main loop\n",
508 regs->trap, getvecname(TRAP(regs)));
509 longjmp(xmon_fault_jmp[0], 1);
510 }
511 if (setjmp(recurse_jmp) == 0) {
512 xmon_fault_jmp[0] = recurse_jmp;
513 in_xmon = 1;
514
515 excprint(regs);
516 bp = at_breakpoint(regs->nip);
517 if (bp) {
Michael Ellerman736256e2014-05-26 21:02:14 +1000518 printf("Stopped at breakpoint %lx (", BP_NUM(bp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 xmon_print_symbol(regs->nip, " ", ")\n");
520 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000521 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 printf("WARNING: exception is not recoverable, "
523 "can't continue\n");
524 remove_bpts();
525 disable_surveillance();
526 /* for breakpoint or single step, print the current instr. */
527 if (bp || TRAP(regs) == 0xd00)
528 ppc_inst_dump(regs->nip, 1, 0);
529 printf("enter ? for help\n");
530 }
531
532 cmd = cmds(regs);
533
534 insert_bpts();
535 in_xmon = 0;
536#endif
537
Josh Boyercdd39042009-10-05 04:46:05 +0000538#ifdef CONFIG_BOOKE
539 if (regs->msr & MSR_DE) {
540 bp = at_breakpoint(regs->nip);
541 if (bp != NULL) {
542 regs->nip = (unsigned long) &bp->instr[0];
543 atomic_inc(&bp->ref_count);
544 }
545 }
546#else
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000547 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 bp = at_breakpoint(regs->nip);
549 if (bp != NULL) {
550 int stepped = emulate_step(regs, bp->instr[0]);
551 if (stepped == 0) {
552 regs->nip = (unsigned long) &bp->instr[0];
553 atomic_inc(&bp->ref_count);
554 } else if (stepped < 0) {
555 printf("Couldn't single-step %s instruction\n",
556 (IS_RFID(bp->instr[0])? "rfid": "mtmsrd"));
557 }
558 }
559 }
Josh Boyercdd39042009-10-05 04:46:05 +0000560#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 insert_cpu_bpts();
562
Anton Blancharda71d64b2014-08-05 14:55:00 +1000563 touch_nmi_watchdog();
Anton Blanchardf13659e2007-03-21 01:48:34 +1100564 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565
Paul Mackerras0a730ae2006-10-03 21:32:49 +1000566 return cmd != 'X' && cmd != EOF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567}
568
569int xmon(struct pt_regs *excp)
570{
571 struct pt_regs regs;
572
573 if (excp == NULL) {
Anton Vorontsov322b4392008-12-17 10:08:55 +0000574 ppc_save_regs(&regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 excp = &regs;
576 }
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200577
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 return xmon_core(excp, 0);
579}
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000580EXPORT_SYMBOL(xmon);
581
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000582irqreturn_t xmon_irq(int irq, void *d)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000583{
584 unsigned long flags;
585 local_irq_save(flags);
586 printf("Keyboard interrupt\n");
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000587 xmon(get_irq_regs());
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000588 local_irq_restore(flags);
589 return IRQ_HANDLED;
590}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000592static int xmon_bpt(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593{
594 struct bpt *bp;
595 unsigned long offset;
596
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000597 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 return 0;
599
600 /* Are we at the trap at bp->instr[1] for some bp? */
601 bp = in_breakpoint_table(regs->nip, &offset);
602 if (bp != NULL && offset == 4) {
603 regs->nip = bp->address + 4;
604 atomic_dec(&bp->ref_count);
605 return 1;
606 }
607
608 /* Are we at a breakpoint? */
609 bp = at_breakpoint(regs->nip);
610 if (!bp)
611 return 0;
612
613 xmon_core(regs, 0);
614
615 return 1;
616}
617
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000618static int xmon_sstep(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619{
620 if (user_mode(regs))
621 return 0;
622 xmon_core(regs, 0);
623 return 1;
624}
625
Michael Neuling9422de32012-12-20 14:06:44 +0000626static int xmon_break_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000628 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 return 0;
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000630 if (dabr.enabled == 0)
631 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 xmon_core(regs, 0);
633 return 1;
634}
635
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000636static int xmon_iabr_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000638 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 return 0;
Michael Ellerman9f1067c22008-05-08 14:27:16 +1000640 if (iabr == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 return 0;
642 xmon_core(regs, 0);
643 return 1;
644}
645
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000646static int xmon_ipi(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647{
648#ifdef CONFIG_SMP
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000649 if (in_xmon && !cpumask_test_cpu(smp_processor_id(), &cpus_in_xmon))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 xmon_core(regs, 1);
651#endif
652 return 0;
653}
654
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000655static int xmon_fault_handler(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656{
657 struct bpt *bp;
658 unsigned long offset;
659
660 if (in_xmon && catch_memory_errors)
661 handle_fault(regs); /* doesn't return */
662
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000663 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 bp = in_breakpoint_table(regs->nip, &offset);
665 if (bp != NULL) {
666 regs->nip = bp->address + offset;
667 atomic_dec(&bp->ref_count);
668 }
669 }
670
671 return 0;
672}
673
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674static struct bpt *at_breakpoint(unsigned long pc)
675{
676 int i;
677 struct bpt *bp;
678
679 bp = bpts;
680 for (i = 0; i < NBPTS; ++i, ++bp)
681 if (bp->enabled && pc == bp->address)
682 return bp;
683 return NULL;
684}
685
686static struct bpt *in_breakpoint_table(unsigned long nip, unsigned long *offp)
687{
688 unsigned long off;
689
690 off = nip - (unsigned long) bpts;
691 if (off >= sizeof(bpts))
692 return NULL;
693 off %= sizeof(struct bpt);
694 if (off != offsetof(struct bpt, instr[0])
695 && off != offsetof(struct bpt, instr[1]))
696 return NULL;
697 *offp = off - offsetof(struct bpt, instr[0]);
698 return (struct bpt *) (nip - off);
699}
700
701static struct bpt *new_breakpoint(unsigned long a)
702{
703 struct bpt *bp;
704
705 a &= ~3UL;
706 bp = at_breakpoint(a);
707 if (bp)
708 return bp;
709
710 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
711 if (!bp->enabled && atomic_read(&bp->ref_count) == 0) {
712 bp->address = a;
713 bp->instr[1] = bpinstr;
714 store_inst(&bp->instr[1]);
715 return bp;
716 }
717 }
718
719 printf("Sorry, no free breakpoints. Please clear one first.\n");
720 return NULL;
721}
722
723static void insert_bpts(void)
724{
725 int i;
726 struct bpt *bp;
727
728 bp = bpts;
729 for (i = 0; i < NBPTS; ++i, ++bp) {
730 if ((bp->enabled & (BP_TRAP|BP_IABR)) == 0)
731 continue;
732 if (mread(bp->address, &bp->instr[0], 4) != 4) {
733 printf("Couldn't read instruction at %lx, "
734 "disabling breakpoint there\n", bp->address);
735 bp->enabled = 0;
736 continue;
737 }
738 if (IS_MTMSRD(bp->instr[0]) || IS_RFID(bp->instr[0])) {
739 printf("Breakpoint at %lx is on an mtmsrd or rfid "
740 "instruction, disabling it\n", bp->address);
741 bp->enabled = 0;
742 continue;
743 }
744 store_inst(&bp->instr[0]);
745 if (bp->enabled & BP_IABR)
746 continue;
747 if (mwrite(bp->address, &bpinstr, 4) != 4) {
748 printf("Couldn't write instruction at %lx, "
749 "disabling breakpoint there\n", bp->address);
750 bp->enabled &= ~BP_TRAP;
751 continue;
752 }
753 store_inst((void *)bp->address);
754 }
755}
756
757static void insert_cpu_bpts(void)
758{
Michael Neuling9422de32012-12-20 14:06:44 +0000759 struct arch_hw_breakpoint brk;
760
761 if (dabr.enabled) {
762 brk.address = dabr.address;
763 brk.type = (dabr.enabled & HW_BRK_TYPE_DABR) | HW_BRK_TYPE_PRIV_ALL;
764 brk.len = 8;
Paul Gortmaker21f58502014-04-29 15:25:17 -0400765 __set_breakpoint(&brk);
Michael Neuling9422de32012-12-20 14:06:44 +0000766 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 if (iabr && cpu_has_feature(CPU_FTR_IABR))
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000768 mtspr(SPRN_IABR, iabr->address
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 | (iabr->enabled & (BP_IABR|BP_IABR_TE)));
770}
771
772static void remove_bpts(void)
773{
774 int i;
775 struct bpt *bp;
776 unsigned instr;
777
778 bp = bpts;
779 for (i = 0; i < NBPTS; ++i, ++bp) {
780 if ((bp->enabled & (BP_TRAP|BP_IABR)) != BP_TRAP)
781 continue;
782 if (mread(bp->address, &instr, 4) == 4
783 && instr == bpinstr
784 && mwrite(bp->address, &bp->instr, 4) != 4)
785 printf("Couldn't remove breakpoint at %lx\n",
786 bp->address);
787 else
788 store_inst((void *)bp->address);
789 }
790}
791
792static void remove_cpu_bpts(void)
793{
Michael Neuling9422de32012-12-20 14:06:44 +0000794 hw_breakpoint_disable();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 if (cpu_has_feature(CPU_FTR_IABR))
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000796 mtspr(SPRN_IABR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797}
798
799/* Command interpreting routine */
800static char *last_cmd;
801
802static int
803cmds(struct pt_regs *excp)
804{
805 int cmd = 0;
806
807 last_cmd = NULL;
808 xmon_regs = excp;
Olaf Hering26c8af52006-09-08 16:29:21 +0200809
810 if (!xmon_no_auto_backtrace) {
811 xmon_no_auto_backtrace = 1;
812 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
813 }
814
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 for(;;) {
816#ifdef CONFIG_SMP
817 printf("%x:", smp_processor_id());
818#endif /* CONFIG_SMP */
819 printf("mon> ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 flush_input();
821 termch = 0;
822 cmd = skipbl();
823 if( cmd == '\n' ) {
824 if (last_cmd == NULL)
825 continue;
826 take_input(last_cmd);
827 last_cmd = NULL;
828 cmd = inchar();
829 }
830 switch (cmd) {
831 case 'm':
832 cmd = inchar();
833 switch (cmd) {
834 case 'm':
835 case 's':
836 case 'd':
837 memops(cmd);
838 break;
839 case 'l':
840 memlocate();
841 break;
842 case 'z':
843 memzcan();
844 break;
845 case 'i':
David Rientjesb2b755b2011-03-24 15:18:15 -0700846 show_mem(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 break;
848 default:
849 termch = cmd;
850 memex();
851 }
852 break;
853 case 'd':
854 dump();
855 break;
856 case 'l':
857 symbol_lookup();
858 break;
859 case 'r':
860 prregs(excp); /* print regs */
861 break;
862 case 'e':
863 excprint(excp);
864 break;
865 case 'S':
866 super_regs();
867 break;
868 case 't':
869 backtrace(excp);
870 break;
871 case 'f':
872 cacheflush();
873 break;
874 case 's':
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200875 if (do_spu_cmd() == 0)
876 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 if (do_step(excp))
878 return cmd;
879 break;
880 case 'x':
881 case 'X':
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100882 return cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 case EOF:
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100884 printf(" <no input ...>\n");
885 mdelay(2000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 return cmd;
887 case '?':
Ishizaki Kou4d404ed2007-07-18 19:26:40 +1000888 xmon_puts(help_string);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 case 'b':
891 bpt_cmds();
892 break;
893 case 'C':
894 csum();
895 break;
896 case 'c':
897 if (cpu_cmd())
898 return 0;
899 break;
900 case 'z':
901 bootcmds();
902 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000903 case 'p':
904 proccall();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000906#ifdef CONFIG_PPC_STD_MMU
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 case 'u':
908 dump_segments();
909 break;
Jimi Xenidis79873e82011-09-29 11:25:10 +0000910#elif defined(CONFIG_4xx)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100911 case 'u':
912 dump_tlb_44x();
913 break;
Jimi Xenidis79873e82011-09-29 11:25:10 +0000914#elif defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +1000915 case 'u':
916 dump_tlb_book3e();
917 break;
918#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 default:
920 printf("Unrecognized command: ");
Michael Ellermane3bc8042012-08-23 22:09:13 +0000921 do {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 if (' ' < cmd && cmd <= '~')
923 putchar(cmd);
924 else
925 printf("\\x%x", cmd);
926 cmd = inchar();
Michael Ellermane3bc8042012-08-23 22:09:13 +0000927 } while (cmd != '\n');
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 printf(" (type ? for help)\n");
929 break;
930 }
931 }
932}
933
Josh Boyercdd39042009-10-05 04:46:05 +0000934#ifdef CONFIG_BOOKE
935static int do_step(struct pt_regs *regs)
936{
937 regs->msr |= MSR_DE;
938 mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
939 return 1;
940}
941#else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942/*
943 * Step a single instruction.
944 * Some instructions we emulate, others we execute with MSR_SE set.
945 */
946static int do_step(struct pt_regs *regs)
947{
948 unsigned int instr;
949 int stepped;
950
951 /* check we are in 64-bit kernel mode, translation enabled */
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000952 if ((regs->msr & (MSR_64BIT|MSR_PR|MSR_IR)) == (MSR_64BIT|MSR_IR)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 if (mread(regs->nip, &instr, 4) == 4) {
954 stepped = emulate_step(regs, instr);
955 if (stepped < 0) {
956 printf("Couldn't single-step %s instruction\n",
957 (IS_RFID(instr)? "rfid": "mtmsrd"));
958 return 0;
959 }
960 if (stepped > 0) {
961 regs->trap = 0xd00 | (regs->trap & 1);
962 printf("stepped to ");
963 xmon_print_symbol(regs->nip, " ", "\n");
964 ppc_inst_dump(regs->nip, 1, 0);
965 return 0;
966 }
967 }
968 }
969 regs->msr |= MSR_SE;
970 return 1;
971}
Josh Boyercdd39042009-10-05 04:46:05 +0000972#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973
974static void bootcmds(void)
975{
976 int cmd;
977
978 cmd = inchar();
979 if (cmd == 'r')
980 ppc_md.restart(NULL);
981 else if (cmd == 'h')
982 ppc_md.halt();
983 else if (cmd == 'p')
984 ppc_md.power_off();
985}
986
987static int cpu_cmd(void)
988{
989#ifdef CONFIG_SMP
Paul Mackerrasfd3bb912013-09-03 20:16:23 +1000990 unsigned long cpu, first_cpu, last_cpu;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 int timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992
993 if (!scanhex(&cpu)) {
994 /* print cpus waiting or in xmon */
995 printf("cpus stopped:");
Paul Mackerrasfd3bb912013-09-03 20:16:23 +1000996 last_cpu = first_cpu = NR_CPUS;
Anton Blanchardbc1d7702012-06-28 19:28:57 +0000997 for_each_possible_cpu(cpu) {
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000998 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Paul Mackerrasfd3bb912013-09-03 20:16:23 +1000999 if (cpu == last_cpu + 1) {
1000 last_cpu = cpu;
1001 } else {
1002 if (last_cpu != first_cpu)
Michael Ellerman736256e2014-05-26 21:02:14 +10001003 printf("-0x%lx", last_cpu);
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001004 last_cpu = first_cpu = cpu;
Michael Ellerman736256e2014-05-26 21:02:14 +10001005 printf(" 0x%lx", cpu);
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001006 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 }
1008 }
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001009 if (last_cpu != first_cpu)
Michael Ellerman736256e2014-05-26 21:02:14 +10001010 printf("-0x%lx", last_cpu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 printf("\n");
1012 return 0;
1013 }
1014 /* try to switch to cpu specified */
KOSAKI Motohiro104699c2011-04-28 05:07:23 +00001015 if (!cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 printf("cpu 0x%x isn't in xmon\n", cpu);
1017 return 0;
1018 }
1019 xmon_taken = 0;
1020 mb();
1021 xmon_owner = cpu;
1022 timeout = 10000000;
1023 while (!xmon_taken) {
1024 if (--timeout == 0) {
1025 if (test_and_set_bit(0, &xmon_taken))
1026 break;
1027 /* take control back */
1028 mb();
1029 xmon_owner = smp_processor_id();
Michael Ellerman736256e2014-05-26 21:02:14 +10001030 printf("cpu 0x%x didn't take control\n", cpu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 return 0;
1032 }
1033 barrier();
1034 }
1035 return 1;
1036#else
1037 return 0;
1038#endif /* CONFIG_SMP */
1039}
1040
1041static unsigned short fcstab[256] = {
1042 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
1043 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
1044 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
1045 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
1046 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
1047 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
1048 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
1049 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
1050 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
1051 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
1052 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
1053 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
1054 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
1055 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
1056 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
1057 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
1058 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
1059 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
1060 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
1061 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
1062 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
1063 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
1064 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
1065 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
1066 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
1067 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
1068 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
1069 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
1070 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
1071 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
1072 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
1073 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
1074};
1075
1076#define FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
1077
1078static void
1079csum(void)
1080{
1081 unsigned int i;
1082 unsigned short fcs;
1083 unsigned char v;
1084
1085 if (!scanhex(&adrs))
1086 return;
1087 if (!scanhex(&ncsum))
1088 return;
1089 fcs = 0xffff;
1090 for (i = 0; i < ncsum; ++i) {
1091 if (mread(adrs+i, &v, 1) == 0) {
Michael Ellerman736256e2014-05-26 21:02:14 +10001092 printf("csum stopped at "REG"\n", adrs+i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 break;
1094 }
1095 fcs = FCS(fcs, v);
1096 }
1097 printf("%x\n", fcs);
1098}
1099
1100/*
1101 * Check if this is a suitable place to put a breakpoint.
1102 */
1103static long check_bp_loc(unsigned long addr)
1104{
1105 unsigned int instr;
1106
1107 addr &= ~3;
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001108 if (!is_kernel_addr(addr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 printf("Breakpoints may only be placed at kernel addresses\n");
1110 return 0;
1111 }
1112 if (!mread(addr, &instr, sizeof(instr))) {
1113 printf("Can't read instruction at address %lx\n", addr);
1114 return 0;
1115 }
1116 if (IS_MTMSRD(instr) || IS_RFID(instr)) {
1117 printf("Breakpoints may not be placed on mtmsrd or rfid "
1118 "instructions\n");
1119 return 0;
1120 }
1121 return 1;
1122}
1123
Michael Ellermane3bc8042012-08-23 22:09:13 +00001124static char *breakpoint_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 "Breakpoint command usage:\n"
1126 "b show breakpoints\n"
1127 "b <addr> [cnt] set breakpoint at given instr addr\n"
1128 "bc clear all breakpoints\n"
1129 "bc <n/addr> clear breakpoint number n or at addr\n"
1130 "bi <addr> [cnt] set hardware instr breakpoint (POWER3/RS64 only)\n"
1131 "bd <addr> [cnt] set hardware data breakpoint\n"
1132 "";
1133
1134static void
1135bpt_cmds(void)
1136{
1137 int cmd;
1138 unsigned long a;
1139 int mode, i;
1140 struct bpt *bp;
1141 const char badaddr[] = "Only kernel addresses are permitted "
1142 "for breakpoints\n";
1143
1144 cmd = inchar();
1145 switch (cmd) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001146#ifndef CONFIG_8xx
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 case 'd': /* bd - hardware data breakpoint */
1148 mode = 7;
1149 cmd = inchar();
1150 if (cmd == 'r')
1151 mode = 5;
1152 else if (cmd == 'w')
1153 mode = 6;
1154 else
1155 termch = cmd;
1156 dabr.address = 0;
1157 dabr.enabled = 0;
1158 if (scanhex(&dabr.address)) {
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001159 if (!is_kernel_addr(dabr.address)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 printf(badaddr);
1161 break;
1162 }
Michael Neuling9422de32012-12-20 14:06:44 +00001163 dabr.address &= ~HW_BRK_TYPE_DABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 dabr.enabled = mode | BP_DABR;
1165 }
1166 break;
1167
1168 case 'i': /* bi - hardware instr breakpoint */
1169 if (!cpu_has_feature(CPU_FTR_IABR)) {
1170 printf("Hardware instruction breakpoint "
1171 "not supported on this cpu\n");
1172 break;
1173 }
1174 if (iabr) {
1175 iabr->enabled &= ~(BP_IABR | BP_IABR_TE);
1176 iabr = NULL;
1177 }
1178 if (!scanhex(&a))
1179 break;
1180 if (!check_bp_loc(a))
1181 break;
1182 bp = new_breakpoint(a);
1183 if (bp != NULL) {
1184 bp->enabled |= BP_IABR | BP_IABR_TE;
1185 iabr = bp;
1186 }
1187 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001188#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189
1190 case 'c':
1191 if (!scanhex(&a)) {
1192 /* clear all breakpoints */
1193 for (i = 0; i < NBPTS; ++i)
1194 bpts[i].enabled = 0;
1195 iabr = NULL;
1196 dabr.enabled = 0;
1197 printf("All breakpoints cleared\n");
1198 break;
1199 }
1200
1201 if (a <= NBPTS && a >= 1) {
1202 /* assume a breakpoint number */
1203 bp = &bpts[a-1]; /* bp nums are 1 based */
1204 } else {
1205 /* assume a breakpoint address */
1206 bp = at_breakpoint(a);
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001207 if (bp == NULL) {
Michael Ellerman736256e2014-05-26 21:02:14 +10001208 printf("No breakpoint at %lx\n", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209 break;
1210 }
1211 }
1212
Michael Ellerman736256e2014-05-26 21:02:14 +10001213 printf("Cleared breakpoint %lx (", BP_NUM(bp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214 xmon_print_symbol(bp->address, " ", ")\n");
1215 bp->enabled = 0;
1216 break;
1217
1218 default:
1219 termch = cmd;
Michael Ellermane3bc8042012-08-23 22:09:13 +00001220 cmd = skipbl();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 if (cmd == '?') {
1222 printf(breakpoint_help_string);
1223 break;
1224 }
1225 termch = cmd;
1226 if (!scanhex(&a)) {
1227 /* print all breakpoints */
1228 printf(" type address\n");
1229 if (dabr.enabled) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001230 printf(" data "REG" [", dabr.address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231 if (dabr.enabled & 1)
1232 printf("r");
1233 if (dabr.enabled & 2)
1234 printf("w");
1235 printf("]\n");
1236 }
1237 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
1238 if (!bp->enabled)
1239 continue;
1240 printf("%2x %s ", BP_NUM(bp),
1241 (bp->enabled & BP_IABR)? "inst": "trap");
1242 xmon_print_symbol(bp->address, " ", "\n");
1243 }
1244 break;
1245 }
1246
1247 if (!check_bp_loc(a))
1248 break;
1249 bp = new_breakpoint(a);
1250 if (bp != NULL)
1251 bp->enabled |= BP_TRAP;
1252 break;
1253 }
1254}
1255
1256/* Very cheap human name for vector lookup. */
1257static
1258const char *getvecname(unsigned long vec)
1259{
1260 char *ret;
1261
1262 switch (vec) {
1263 case 0x100: ret = "(System Reset)"; break;
1264 case 0x200: ret = "(Machine Check)"; break;
1265 case 0x300: ret = "(Data Access)"; break;
1266 case 0x380: ret = "(Data SLB Access)"; break;
1267 case 0x400: ret = "(Instruction Access)"; break;
1268 case 0x480: ret = "(Instruction SLB Access)"; break;
1269 case 0x500: ret = "(Hardware Interrupt)"; break;
1270 case 0x600: ret = "(Alignment)"; break;
1271 case 0x700: ret = "(Program Check)"; break;
1272 case 0x800: ret = "(FPU Unavailable)"; break;
1273 case 0x900: ret = "(Decrementer)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001274 case 0x980: ret = "(Hypervisor Decrementer)"; break;
1275 case 0xa00: ret = "(Doorbell)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276 case 0xc00: ret = "(System Call)"; break;
1277 case 0xd00: ret = "(Single Step)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001278 case 0xe40: ret = "(Emulation Assist)"; break;
1279 case 0xe60: ret = "(HMI)"; break;
1280 case 0xe80: ret = "(Hypervisor Doorbell)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281 case 0xf00: ret = "(Performance Monitor)"; break;
1282 case 0xf20: ret = "(Altivec Unavailable)"; break;
1283 case 0x1300: ret = "(Instruction Breakpoint)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001284 case 0x1500: ret = "(Denormalisation)"; break;
1285 case 0x1700: ret = "(Altivec Assist)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 default: ret = "";
1287 }
1288 return ret;
1289}
1290
1291static void get_function_bounds(unsigned long pc, unsigned long *startp,
1292 unsigned long *endp)
1293{
1294 unsigned long size, offset;
1295 const char *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296
1297 *startp = *endp = 0;
1298 if (pc == 0)
1299 return;
1300 if (setjmp(bus_error_jmp) == 0) {
1301 catch_memory_errors = 1;
1302 sync();
Alexey Dobriyanffb45122007-05-08 00:28:41 -07001303 name = kallsyms_lookup(pc, &size, &offset, NULL, tmpstr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 if (name != NULL) {
1305 *startp = pc - offset;
1306 *endp = pc - offset + size;
1307 }
1308 sync();
1309 }
1310 catch_memory_errors = 0;
1311}
1312
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001313#define LRSAVE_OFFSET (STACK_FRAME_LR_SAVE * sizeof(unsigned long))
1314#define MARKER_OFFSET (STACK_FRAME_MARKER * sizeof(unsigned long))
1315
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316static void xmon_show_stack(unsigned long sp, unsigned long lr,
1317 unsigned long pc)
1318{
Michael Ellerman0104cd62012-10-09 04:20:36 +00001319 int max_to_print = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 unsigned long ip;
1321 unsigned long newsp;
1322 unsigned long marker;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 struct pt_regs regs;
1324
Michael Ellerman0104cd62012-10-09 04:20:36 +00001325 while (max_to_print--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 if (sp < PAGE_OFFSET) {
1327 if (sp != 0)
1328 printf("SP (%lx) is in userspace\n", sp);
1329 break;
1330 }
1331
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001332 if (!mread(sp + LRSAVE_OFFSET, &ip, sizeof(unsigned long))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 || !mread(sp, &newsp, sizeof(unsigned long))) {
1334 printf("Couldn't read stack frame at %lx\n", sp);
1335 break;
1336 }
1337
1338 /*
1339 * For the first stack frame, try to work out if
1340 * LR and/or the saved LR value in the bottommost
1341 * stack frame are valid.
1342 */
1343 if ((pc | lr) != 0) {
1344 unsigned long fnstart, fnend;
1345 unsigned long nextip;
1346 int printip = 1;
1347
1348 get_function_bounds(pc, &fnstart, &fnend);
1349 nextip = 0;
1350 if (newsp > sp)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001351 mread(newsp + LRSAVE_OFFSET, &nextip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 sizeof(unsigned long));
1353 if (lr == ip) {
1354 if (lr < PAGE_OFFSET
1355 || (fnstart <= lr && lr < fnend))
1356 printip = 0;
1357 } else if (lr == nextip) {
1358 printip = 0;
1359 } else if (lr >= PAGE_OFFSET
1360 && !(fnstart <= lr && lr < fnend)) {
1361 printf("[link register ] ");
1362 xmon_print_symbol(lr, " ", "\n");
1363 }
1364 if (printip) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001365 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 xmon_print_symbol(ip, " ", " (unreliable)\n");
1367 }
1368 pc = lr = 0;
1369
1370 } else {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001371 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 xmon_print_symbol(ip, " ", "\n");
1373 }
1374
1375 /* Look for "regshere" marker to see if this is
1376 an exception frame. */
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001377 if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long))
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001378 && marker == STACK_FRAME_REGS_MARKER) {
Michael Ellermanc4de3802012-10-09 04:20:35 +00001379 if (mread(sp + STACK_FRAME_OVERHEAD, &regs, sizeof(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 != sizeof(regs)) {
1381 printf("Couldn't read registers at %lx\n",
Michael Ellermanc4de3802012-10-09 04:20:35 +00001382 sp + STACK_FRAME_OVERHEAD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 break;
1384 }
Michael Ellermane3bc8042012-08-23 22:09:13 +00001385 printf("--- Exception: %lx %s at ", regs.trap,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386 getvecname(TRAP(&regs)));
1387 pc = regs.nip;
1388 lr = regs.link;
1389 xmon_print_symbol(pc, " ", "\n");
1390 }
1391
1392 if (newsp == 0)
1393 break;
1394
1395 sp = newsp;
Michael Ellerman0104cd62012-10-09 04:20:36 +00001396 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397}
1398
1399static void backtrace(struct pt_regs *excp)
1400{
1401 unsigned long sp;
1402
1403 if (scanhex(&sp))
1404 xmon_show_stack(sp, 0, 0);
1405 else
1406 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
1407 scannl();
1408}
1409
1410static void print_bug_trap(struct pt_regs *regs)
1411{
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001412#ifdef CONFIG_BUG
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001413 const struct bug_entry *bug;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 unsigned long addr;
1415
1416 if (regs->msr & MSR_PR)
1417 return; /* not in kernel */
1418 addr = regs->nip; /* address of trap instruction */
1419 if (addr < PAGE_OFFSET)
1420 return;
1421 bug = find_bug(regs->nip);
1422 if (bug == NULL)
1423 return;
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001424 if (is_warning_bug(bug))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 return;
1426
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001427#ifdef CONFIG_DEBUG_BUGVERBOSE
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001428 printf("kernel BUG at %s:%u!\n",
1429 bug->file, bug->line);
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001430#else
1431 printf("kernel BUG at %p!\n", (void *)bug->bug_addr);
1432#endif
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001433#endif /* CONFIG_BUG */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434}
1435
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001436static void excprint(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437{
1438 unsigned long trap;
1439
1440#ifdef CONFIG_SMP
1441 printf("cpu 0x%x: ", smp_processor_id());
1442#endif /* CONFIG_SMP */
1443
1444 trap = TRAP(fp);
1445 printf("Vector: %lx %s at [%lx]\n", fp->trap, getvecname(trap), fp);
1446 printf(" pc: ");
1447 xmon_print_symbol(fp->nip, ": ", "\n");
1448
1449 printf(" lr: ", fp->link);
1450 xmon_print_symbol(fp->link, ": ", "\n");
1451
1452 printf(" sp: %lx\n", fp->gpr[1]);
1453 printf(" msr: %lx\n", fp->msr);
1454
Aneesh Kumar K.Vce541522013-04-28 09:37:26 +00001455 if (trap == 0x300 || trap == 0x380 || trap == 0x600 || trap == 0x200) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 printf(" dar: %lx\n", fp->dar);
1457 if (trap != 0x380)
1458 printf(" dsisr: %lx\n", fp->dsisr);
1459 }
1460
1461 printf(" current = 0x%lx\n", current);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001462#ifdef CONFIG_PPC64
Benjamin Herrenschmidt7230c562012-03-06 18:27:59 +11001463 printf(" paca = 0x%lx\t softe: %d\t irq_happened: 0x%02x\n",
1464 local_paca, local_paca->soft_enabled, local_paca->irq_happened);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001465#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 if (current) {
1467 printf(" pid = %ld, comm = %s\n",
1468 current->pid, current->comm);
1469 }
1470
1471 if (trap == 0x700)
1472 print_bug_trap(fp);
1473}
1474
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001475static void prregs(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001477 int n, trap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 unsigned long base;
1479 struct pt_regs regs;
1480
1481 if (scanhex(&base)) {
1482 if (setjmp(bus_error_jmp) == 0) {
1483 catch_memory_errors = 1;
1484 sync();
1485 regs = *(struct pt_regs *)base;
1486 sync();
1487 __delay(200);
1488 } else {
1489 catch_memory_errors = 0;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001490 printf("*** Error reading registers from "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 base);
1492 return;
1493 }
1494 catch_memory_errors = 0;
1495 fp = &regs;
1496 }
1497
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001498#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 if (FULL_REGS(fp)) {
1500 for (n = 0; n < 16; ++n)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001501 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 n, fp->gpr[n], n+16, fp->gpr[n+16]);
1503 } else {
1504 for (n = 0; n < 7; ++n)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001505 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 n, fp->gpr[n], n+7, fp->gpr[n+7]);
1507 }
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001508#else
1509 for (n = 0; n < 32; ++n) {
1510 printf("R%.2d = %.8x%s", n, fp->gpr[n],
1511 (n & 3) == 3? "\n": " ");
1512 if (n == 12 && !FULL_REGS(fp)) {
1513 printf("\n");
1514 break;
1515 }
1516 }
1517#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 printf("pc = ");
1519 xmon_print_symbol(fp->nip, " ", "\n");
Paul Mackerras48404f22011-05-01 19:48:20 +00001520 if (TRAP(fp) != 0xc00 && cpu_has_feature(CPU_FTR_CFAR)) {
1521 printf("cfar= ");
1522 xmon_print_symbol(fp->orig_gpr3, " ", "\n");
1523 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 printf("lr = ");
1525 xmon_print_symbol(fp->link, " ", "\n");
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001526 printf("msr = "REG" cr = %.8lx\n", fp->msr, fp->ccr);
1527 printf("ctr = "REG" xer = "REG" trap = %4lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528 fp->ctr, fp->xer, fp->trap);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001529 trap = TRAP(fp);
1530 if (trap == 0x300 || trap == 0x380 || trap == 0x600)
1531 printf("dar = "REG" dsisr = %.8lx\n", fp->dar, fp->dsisr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532}
1533
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001534static void cacheflush(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535{
1536 int cmd;
1537 unsigned long nflush;
1538
1539 cmd = inchar();
1540 if (cmd != 'i')
1541 termch = cmd;
1542 scanhex((void *)&adrs);
1543 if (termch != '\n')
1544 termch = 0;
1545 nflush = 1;
1546 scanhex(&nflush);
1547 nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES;
1548 if (setjmp(bus_error_jmp) == 0) {
1549 catch_memory_errors = 1;
1550 sync();
1551
1552 if (cmd != 'i') {
1553 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1554 cflush((void *) adrs);
1555 } else {
1556 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1557 cinval((void *) adrs);
1558 }
1559 sync();
1560 /* wait a little while to see if we get a machine check */
1561 __delay(200);
1562 }
1563 catch_memory_errors = 0;
1564}
1565
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001566static unsigned long
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567read_spr(int n)
1568{
1569 unsigned int instrs[2];
1570 unsigned long (*code)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571 unsigned long ret = -1UL;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001572#ifdef CONFIG_PPC64
1573 unsigned long opd[3];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 opd[0] = (unsigned long)instrs;
1576 opd[1] = 0;
1577 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001578 code = (unsigned long (*)(void)) opd;
1579#else
1580 code = (unsigned long (*)(void)) instrs;
1581#endif
1582
1583 /* mfspr r3,n; blr */
1584 instrs[0] = 0x7c6002a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1585 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 store_inst(instrs);
1587 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588
1589 if (setjmp(bus_error_jmp) == 0) {
1590 catch_memory_errors = 1;
1591 sync();
1592
1593 ret = code();
1594
1595 sync();
1596 /* wait a little while to see if we get a machine check */
1597 __delay(200);
1598 n = size;
1599 }
1600
1601 return ret;
1602}
1603
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001604static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605write_spr(int n, unsigned long val)
1606{
1607 unsigned int instrs[2];
1608 unsigned long (*code)(unsigned long);
Paul Mackerras548cceb2005-11-11 22:36:34 +11001609#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 unsigned long opd[3];
1611
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612 opd[0] = (unsigned long)instrs;
1613 opd[1] = 0;
1614 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001615 code = (unsigned long (*)(unsigned long)) opd;
1616#else
1617 code = (unsigned long (*)(unsigned long)) instrs;
1618#endif
1619
1620 instrs[0] = 0x7c6003a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1621 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622 store_inst(instrs);
1623 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624
1625 if (setjmp(bus_error_jmp) == 0) {
1626 catch_memory_errors = 1;
1627 sync();
1628
1629 code(val);
1630
1631 sync();
1632 /* wait a little while to see if we get a machine check */
1633 __delay(200);
1634 n = size;
1635 }
1636}
1637
1638static unsigned long regno;
1639extern char exc_prolog;
1640extern char dec_exc;
1641
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001642static void super_regs(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643{
1644 int cmd;
1645 unsigned long val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646
1647 cmd = skipbl();
1648 if (cmd == '\n') {
Michael Ellermane3bc8042012-08-23 22:09:13 +00001649 unsigned long sp, toc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 asm("mr %0,1" : "=r" (sp) :);
1651 asm("mr %0,2" : "=r" (toc) :);
1652
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001653 printf("msr = "REG" sprg0= "REG"\n",
1654 mfmsr(), mfspr(SPRN_SPRG0));
1655 printf("pvr = "REG" sprg1= "REG"\n",
Michael Ellermane3bc8042012-08-23 22:09:13 +00001656 mfspr(SPRN_PVR), mfspr(SPRN_SPRG1));
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001657 printf("dec = "REG" sprg2= "REG"\n",
1658 mfspr(SPRN_DEC), mfspr(SPRN_SPRG2));
1659 printf("sp = "REG" sprg3= "REG"\n", sp, mfspr(SPRN_SPRG3));
1660 printf("toc = "REG" dar = "REG"\n", toc, mfspr(SPRN_DAR));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661
1662 return;
1663 }
1664
1665 scanhex(&regno);
1666 switch (cmd) {
1667 case 'w':
1668 val = read_spr(regno);
1669 scanhex(&val);
1670 write_spr(regno, val);
1671 /* fall through */
1672 case 'r':
1673 printf("spr %lx = %lx\n", regno, read_spr(regno));
1674 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675 }
1676 scannl();
1677}
1678
1679/*
1680 * Stuff for reading and writing memory safely
1681 */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001682static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683mread(unsigned long adrs, void *buf, int size)
1684{
1685 volatile int n;
1686 char *p, *q;
1687
1688 n = 0;
1689 if (setjmp(bus_error_jmp) == 0) {
1690 catch_memory_errors = 1;
1691 sync();
1692 p = (char *)adrs;
1693 q = (char *)buf;
1694 switch (size) {
1695 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001696 *(u16 *)q = *(u16 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 break;
1698 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001699 *(u32 *)q = *(u32 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 break;
1701 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001702 *(u64 *)q = *(u64 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 break;
1704 default:
1705 for( ; n < size; ++n) {
1706 *q++ = *p++;
1707 sync();
1708 }
1709 }
1710 sync();
1711 /* wait a little while to see if we get a machine check */
1712 __delay(200);
1713 n = size;
1714 }
1715 catch_memory_errors = 0;
1716 return n;
1717}
1718
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001719static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720mwrite(unsigned long adrs, void *buf, int size)
1721{
1722 volatile int n;
1723 char *p, *q;
1724
1725 n = 0;
1726 if (setjmp(bus_error_jmp) == 0) {
1727 catch_memory_errors = 1;
1728 sync();
1729 p = (char *) adrs;
1730 q = (char *) buf;
1731 switch (size) {
1732 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001733 *(u16 *)p = *(u16 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 break;
1735 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001736 *(u32 *)p = *(u32 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737 break;
1738 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001739 *(u64 *)p = *(u64 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740 break;
1741 default:
1742 for ( ; n < size; ++n) {
1743 *p++ = *q++;
1744 sync();
1745 }
1746 }
1747 sync();
1748 /* wait a little while to see if we get a machine check */
1749 __delay(200);
1750 n = size;
1751 } else {
Michael Ellerman736256e2014-05-26 21:02:14 +10001752 printf("*** Error writing address "REG"\n", adrs + n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753 }
1754 catch_memory_errors = 0;
1755 return n;
1756}
1757
1758static int fault_type;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001759static int fault_except;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760static char *fault_chars[] = { "--", "**", "##" };
1761
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001762static int handle_fault(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001764 fault_except = TRAP(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765 switch (TRAP(regs)) {
1766 case 0x200:
1767 fault_type = 0;
1768 break;
1769 case 0x300:
1770 case 0x380:
1771 fault_type = 1;
1772 break;
1773 default:
1774 fault_type = 2;
1775 }
1776
1777 longjmp(bus_error_jmp, 1);
1778
1779 return 0;
1780}
1781
1782#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t))
1783
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001784static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785byterev(unsigned char *val, int size)
1786{
1787 int t;
1788
1789 switch (size) {
1790 case 2:
1791 SWAP(val[0], val[1], t);
1792 break;
1793 case 4:
1794 SWAP(val[0], val[3], t);
1795 SWAP(val[1], val[2], t);
1796 break;
1797 case 8: /* is there really any use for this? */
1798 SWAP(val[0], val[7], t);
1799 SWAP(val[1], val[6], t);
1800 SWAP(val[2], val[5], t);
1801 SWAP(val[3], val[4], t);
1802 break;
1803 }
1804}
1805
1806static int brev;
1807static int mnoread;
1808
Michael Ellermane3bc8042012-08-23 22:09:13 +00001809static char *memex_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810 "Memory examine command usage:\n"
1811 "m [addr] [flags] examine/change memory\n"
1812 " addr is optional. will start where left off.\n"
1813 " flags may include chars from this set:\n"
1814 " b modify by bytes (default)\n"
1815 " w modify by words (2 byte)\n"
1816 " l modify by longs (4 byte)\n"
1817 " d modify by doubleword (8 byte)\n"
1818 " r toggle reverse byte order mode\n"
1819 " n do not read memory (for i/o spaces)\n"
1820 " . ok to read (default)\n"
1821 "NOTE: flags are saved as defaults\n"
1822 "";
1823
Michael Ellermane3bc8042012-08-23 22:09:13 +00001824static char *memex_subcmd_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825 "Memory examine subcommands:\n"
1826 " hexval write this val to current location\n"
1827 " 'string' write chars from string to this location\n"
1828 " ' increment address\n"
1829 " ^ decrement address\n"
1830 " / increment addr by 0x10. //=0x100, ///=0x1000, etc\n"
1831 " \\ decrement addr by 0x10. \\\\=0x100, \\\\\\=0x1000, etc\n"
1832 " ` clear no-read flag\n"
1833 " ; stay at this addr\n"
1834 " v change to byte mode\n"
1835 " w change to word (2 byte) mode\n"
1836 " l change to long (4 byte) mode\n"
1837 " u change to doubleword (8 byte) mode\n"
1838 " m addr change current addr\n"
1839 " n toggle no-read flag\n"
1840 " r toggle byte reverse flag\n"
1841 " < count back up count bytes\n"
1842 " > count skip forward count bytes\n"
1843 " x exit this mode\n"
1844 "";
1845
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001846static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847memex(void)
1848{
1849 int cmd, inc, i, nslash;
1850 unsigned long n;
1851 unsigned char val[16];
1852
1853 scanhex((void *)&adrs);
1854 cmd = skipbl();
1855 if (cmd == '?') {
1856 printf(memex_help_string);
1857 return;
1858 } else {
1859 termch = cmd;
1860 }
1861 last_cmd = "m\n";
1862 while ((cmd = skipbl()) != '\n') {
1863 switch( cmd ){
1864 case 'b': size = 1; break;
1865 case 'w': size = 2; break;
1866 case 'l': size = 4; break;
1867 case 'd': size = 8; break;
1868 case 'r': brev = !brev; break;
1869 case 'n': mnoread = 1; break;
1870 case '.': mnoread = 0; break;
1871 }
1872 }
1873 if( size <= 0 )
1874 size = 1;
1875 else if( size > 8 )
1876 size = 8;
1877 for(;;){
1878 if (!mnoread)
1879 n = mread(adrs, val, size);
Paul Mackerrase1449ed2005-11-10 14:30:20 +11001880 printf(REG"%c", adrs, brev? 'r': ' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 if (!mnoread) {
1882 if (brev)
1883 byterev(val, size);
1884 putchar(' ');
1885 for (i = 0; i < n; ++i)
1886 printf("%.2x", val[i]);
1887 for (; i < size; ++i)
1888 printf("%s", fault_chars[fault_type]);
1889 }
1890 putchar(' ');
1891 inc = size;
1892 nslash = 0;
1893 for(;;){
1894 if( scanhex(&n) ){
1895 for (i = 0; i < size; ++i)
1896 val[i] = n >> (i * 8);
1897 if (!brev)
1898 byterev(val, size);
1899 mwrite(adrs, val, size);
1900 inc = size;
1901 }
1902 cmd = skipbl();
1903 if (cmd == '\n')
1904 break;
1905 inc = 0;
1906 switch (cmd) {
1907 case '\'':
1908 for(;;){
1909 n = inchar();
1910 if( n == '\\' )
1911 n = bsesc();
1912 else if( n == '\'' )
1913 break;
1914 for (i = 0; i < size; ++i)
1915 val[i] = n >> (i * 8);
1916 if (!brev)
1917 byterev(val, size);
1918 mwrite(adrs, val, size);
1919 adrs += size;
1920 }
1921 adrs -= size;
1922 inc = size;
1923 break;
1924 case ',':
1925 adrs += size;
1926 break;
1927 case '.':
1928 mnoread = 0;
1929 break;
1930 case ';':
1931 break;
1932 case 'x':
1933 case EOF:
1934 scannl();
1935 return;
1936 case 'b':
1937 case 'v':
1938 size = 1;
1939 break;
1940 case 'w':
1941 size = 2;
1942 break;
1943 case 'l':
1944 size = 4;
1945 break;
1946 case 'u':
1947 size = 8;
1948 break;
1949 case '^':
1950 adrs -= size;
1951 break;
1952 break;
1953 case '/':
1954 if (nslash > 0)
1955 adrs -= 1 << nslash;
1956 else
1957 nslash = 0;
1958 nslash += 4;
1959 adrs += 1 << nslash;
1960 break;
1961 case '\\':
1962 if (nslash < 0)
1963 adrs += 1 << -nslash;
1964 else
1965 nslash = 0;
1966 nslash -= 4;
1967 adrs -= 1 << -nslash;
1968 break;
1969 case 'm':
1970 scanhex((void *)&adrs);
1971 break;
1972 case 'n':
1973 mnoread = 1;
1974 break;
1975 case 'r':
1976 brev = !brev;
1977 break;
1978 case '<':
1979 n = size;
1980 scanhex(&n);
1981 adrs -= n;
1982 break;
1983 case '>':
1984 n = size;
1985 scanhex(&n);
1986 adrs += n;
1987 break;
1988 case '?':
1989 printf(memex_subcmd_help_string);
1990 break;
1991 }
1992 }
1993 adrs += inc;
1994 }
1995}
1996
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001997static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998bsesc(void)
1999{
2000 int c;
2001
2002 c = inchar();
2003 switch( c ){
2004 case 'n': c = '\n'; break;
2005 case 'r': c = '\r'; break;
2006 case 'b': c = '\b'; break;
2007 case 't': c = '\t'; break;
2008 }
2009 return c;
2010}
2011
Olaf Hering7e5b5932006-03-08 20:40:28 +01002012static void xmon_rawdump (unsigned long adrs, long ndump)
2013{
2014 long n, m, r, nr;
2015 unsigned char temp[16];
2016
2017 for (n = ndump; n > 0;) {
2018 r = n < 16? n: 16;
2019 nr = mread(adrs, temp, r);
2020 adrs += nr;
2021 for (m = 0; m < r; ++m) {
2022 if (m < nr)
2023 printf("%.2x", temp[m]);
2024 else
2025 printf("%s", fault_chars[fault_type]);
2026 }
2027 n -= r;
2028 if (nr < r)
2029 break;
2030 }
2031 printf("\n");
2032}
2033
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002034#ifdef CONFIG_PPC64
2035static void dump_one_paca(int cpu)
2036{
2037 struct paca_struct *p;
2038
2039 if (setjmp(bus_error_jmp) != 0) {
2040 printf("*** Error dumping paca for cpu 0x%x!\n", cpu);
2041 return;
2042 }
2043
2044 catch_memory_errors = 1;
2045 sync();
2046
2047 p = &paca[cpu];
2048
2049 printf("paca for cpu 0x%x @ %p:\n", cpu, p);
2050
2051 printf(" %-*s = %s\n", 16, "possible", cpu_possible(cpu) ? "yes" : "no");
2052 printf(" %-*s = %s\n", 16, "present", cpu_present(cpu) ? "yes" : "no");
2053 printf(" %-*s = %s\n", 16, "online", cpu_online(cpu) ? "yes" : "no");
2054
2055#define DUMP(paca, name, format) \
2056 printf(" %-*s = %#-*"format"\t(0x%lx)\n", 16, #name, 18, paca->name, \
2057 offsetof(struct paca_struct, name));
2058
2059 DUMP(p, lock_token, "x");
2060 DUMP(p, paca_index, "x");
2061 DUMP(p, kernel_toc, "lx");
2062 DUMP(p, kernelbase, "lx");
2063 DUMP(p, kernel_msr, "lx");
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002064 DUMP(p, emergency_sp, "p");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302065#ifdef CONFIG_PPC_BOOK3S_64
2066 DUMP(p, mc_emergency_sp, "p");
2067 DUMP(p, in_mce, "x");
2068#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002069 DUMP(p, data_offset, "lx");
2070 DUMP(p, hw_cpu_id, "x");
2071 DUMP(p, cpu_start, "x");
2072 DUMP(p, kexec_state, "x");
2073 DUMP(p, __current, "p");
2074 DUMP(p, kstack, "lx");
2075 DUMP(p, stab_rr, "lx");
2076 DUMP(p, saved_r1, "lx");
2077 DUMP(p, trap_save, "x");
2078 DUMP(p, soft_enabled, "x");
2079 DUMP(p, irq_happened, "x");
2080 DUMP(p, io_sync, "x");
2081 DUMP(p, irq_work_pending, "x");
2082 DUMP(p, nap_state_lost, "x");
2083
2084#undef DUMP
2085
2086 catch_memory_errors = 0;
2087 sync();
2088}
2089
2090static void dump_all_pacas(void)
2091{
2092 int cpu;
2093
2094 if (num_possible_cpus() == 0) {
2095 printf("No possible cpus, use 'dp #' to dump individual cpus\n");
2096 return;
2097 }
2098
2099 for_each_possible_cpu(cpu)
2100 dump_one_paca(cpu);
2101}
2102
2103static void dump_pacas(void)
2104{
2105 unsigned long num;
2106 int c;
2107
2108 c = inchar();
2109 if (c == 'a') {
2110 dump_all_pacas();
2111 return;
2112 }
2113
2114 termch = c; /* Put c back, it wasn't 'a' */
2115
2116 if (scanhex(&num))
2117 dump_one_paca(num);
2118 else
2119 dump_one_paca(xmon_owner);
2120}
2121#endif
2122
Linus Torvalds1da177e2005-04-16 15:20:36 -07002123#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
2124 || ('a' <= (c) && (c) <= 'f') \
2125 || ('A' <= (c) && (c) <= 'F'))
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002126static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002127dump(void)
2128{
2129 int c;
2130
2131 c = inchar();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002132
2133#ifdef CONFIG_PPC64
2134 if (c == 'p') {
2135 dump_pacas();
2136 return;
2137 }
2138#endif
2139
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140 if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
2141 termch = c;
2142 scanhex((void *)&adrs);
2143 if (termch != '\n')
2144 termch = 0;
2145 if (c == 'i') {
2146 scanhex(&nidump);
2147 if (nidump == 0)
2148 nidump = 16;
2149 else if (nidump > MAX_DUMP)
2150 nidump = MAX_DUMP;
2151 adrs += ppc_inst_dump(adrs, nidump, 1);
2152 last_cmd = "di\n";
Vinay Sridharf312deb2009-05-14 23:13:07 +00002153 } else if (c == 'l') {
2154 dump_log_buf();
Olaf Hering7e5b5932006-03-08 20:40:28 +01002155 } else if (c == 'r') {
2156 scanhex(&ndump);
2157 if (ndump == 0)
2158 ndump = 64;
2159 xmon_rawdump(adrs, ndump);
2160 adrs += ndump;
2161 last_cmd = "dr\n";
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162 } else {
2163 scanhex(&ndump);
2164 if (ndump == 0)
2165 ndump = 64;
2166 else if (ndump > MAX_DUMP)
2167 ndump = MAX_DUMP;
2168 prdump(adrs, ndump);
2169 adrs += ndump;
2170 last_cmd = "d\n";
2171 }
2172}
2173
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002174static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175prdump(unsigned long adrs, long ndump)
2176{
2177 long n, m, c, r, nr;
2178 unsigned char temp[16];
2179
2180 for (n = ndump; n > 0;) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002181 printf(REG, adrs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182 putchar(' ');
2183 r = n < 16? n: 16;
2184 nr = mread(adrs, temp, r);
2185 adrs += nr;
2186 for (m = 0; m < r; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002187 if ((m & (sizeof(long) - 1)) == 0 && m > 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002188 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002189 if (m < nr)
2190 printf("%.2x", temp[m]);
2191 else
2192 printf("%s", fault_chars[fault_type]);
2193 }
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002194 for (; m < 16; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002195 if ((m & (sizeof(long) - 1)) == 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002196 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197 printf(" ");
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002198 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199 printf(" |");
2200 for (m = 0; m < r; ++m) {
2201 if (m < nr) {
2202 c = temp[m];
2203 putchar(' ' <= c && c <= '~'? c: '.');
2204 } else
2205 putchar(' ');
2206 }
2207 n -= r;
2208 for (; m < 16; ++m)
2209 putchar(' ');
2210 printf("|\n");
2211 if (nr < r)
2212 break;
2213 }
2214}
2215
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002216typedef int (*instruction_dump_func)(unsigned long inst, unsigned long addr);
2217
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002218static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002219generic_inst_dump(unsigned long adr, long count, int praddr,
2220 instruction_dump_func dump_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221{
2222 int nr, dotted;
2223 unsigned long first_adr;
2224 unsigned long inst, last_inst = 0;
2225 unsigned char val[4];
2226
2227 dotted = 0;
2228 for (first_adr = adr; count > 0; --count, adr += 4) {
2229 nr = mread(adr, val, 4);
2230 if (nr == 0) {
2231 if (praddr) {
2232 const char *x = fault_chars[fault_type];
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002233 printf(REG" %s%s%s%s\n", adr, x, x, x, x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234 }
2235 break;
2236 }
2237 inst = GETWORD(val);
2238 if (adr > first_adr && inst == last_inst) {
2239 if (!dotted) {
2240 printf(" ...\n");
2241 dotted = 1;
2242 }
2243 continue;
2244 }
2245 dotted = 0;
2246 last_inst = inst;
2247 if (praddr)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002248 printf(REG" %.8x", adr, inst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249 printf("\t");
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002250 dump_func(inst, adr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251 printf("\n");
2252 }
2253 return adr - first_adr;
2254}
2255
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002256static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002257ppc_inst_dump(unsigned long adr, long count, int praddr)
2258{
2259 return generic_inst_dump(adr, count, praddr, print_insn_powerpc);
2260}
2261
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262void
2263print_address(unsigned long addr)
2264{
2265 xmon_print_symbol(addr, "\t# ", "");
2266}
2267
Vinay Sridharf312deb2009-05-14 23:13:07 +00002268void
2269dump_log_buf(void)
2270{
Michael Ellermanca5dd392012-08-23 22:09:12 +00002271 struct kmsg_dumper dumper = { .active = 1 };
2272 unsigned char buf[128];
2273 size_t len;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002274
Michael Ellermane3bc8042012-08-23 22:09:13 +00002275 if (setjmp(bus_error_jmp) != 0) {
Michael Ellermanca5dd392012-08-23 22:09:12 +00002276 printf("Error dumping printk buffer!\n");
Michael Ellermane3bc8042012-08-23 22:09:13 +00002277 return;
2278 }
Vinay Sridharf312deb2009-05-14 23:13:07 +00002279
Michael Ellermane3bc8042012-08-23 22:09:13 +00002280 catch_memory_errors = 1;
2281 sync();
Vinay Sridharf312deb2009-05-14 23:13:07 +00002282
Michael Ellermanca5dd392012-08-23 22:09:12 +00002283 kmsg_dump_rewind_nolock(&dumper);
2284 while (kmsg_dump_get_line_nolock(&dumper, false, buf, sizeof(buf), &len)) {
2285 buf[len] = '\0';
2286 printf("%s", buf);
2287 }
Vinay Sridharf312deb2009-05-14 23:13:07 +00002288
Michael Ellermane3bc8042012-08-23 22:09:13 +00002289 sync();
2290 /* wait a little while to see if we get a machine check */
2291 __delay(200);
2292 catch_memory_errors = 0;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002293}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294
2295/*
2296 * Memory operations - move, set, print differences
2297 */
2298static unsigned long mdest; /* destination address */
2299static unsigned long msrc; /* source address */
2300static unsigned long mval; /* byte value to set memory to */
2301static unsigned long mcount; /* # bytes to affect */
2302static unsigned long mdiffs; /* max # differences to print */
2303
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002304static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305memops(int cmd)
2306{
2307 scanhex((void *)&mdest);
2308 if( termch != '\n' )
2309 termch = 0;
2310 scanhex((void *)(cmd == 's'? &mval: &msrc));
2311 if( termch != '\n' )
2312 termch = 0;
2313 scanhex((void *)&mcount);
2314 switch( cmd ){
2315 case 'm':
2316 memmove((void *)mdest, (void *)msrc, mcount);
2317 break;
2318 case 's':
2319 memset((void *)mdest, mval, mcount);
2320 break;
2321 case 'd':
2322 if( termch != '\n' )
2323 termch = 0;
2324 scanhex((void *)&mdiffs);
2325 memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
2326 break;
2327 }
2328}
2329
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002330static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
2332{
2333 unsigned n, prt;
2334
2335 prt = 0;
2336 for( n = nb; n > 0; --n )
2337 if( *p1++ != *p2++ )
2338 if( ++prt <= maxpr )
2339 printf("%.16x %.2x # %.16x %.2x\n", p1 - 1,
2340 p1[-1], p2 - 1, p2[-1]);
2341 if( prt > maxpr )
2342 printf("Total of %d differences\n", prt);
2343}
2344
2345static unsigned mend;
2346static unsigned mask;
2347
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002348static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002349memlocate(void)
2350{
2351 unsigned a, n;
2352 unsigned char val[4];
2353
2354 last_cmd = "ml";
2355 scanhex((void *)&mdest);
2356 if (termch != '\n') {
2357 termch = 0;
2358 scanhex((void *)&mend);
2359 if (termch != '\n') {
2360 termch = 0;
2361 scanhex((void *)&mval);
2362 mask = ~0;
2363 if (termch != '\n') termch = 0;
2364 scanhex((void *)&mask);
2365 }
2366 }
2367 n = 0;
2368 for (a = mdest; a < mend; a += 4) {
2369 if (mread(a, val, 4) == 4
2370 && ((GETWORD(val) ^ mval) & mask) == 0) {
2371 printf("%.16x: %.16x\n", a, GETWORD(val));
2372 if (++n >= 10)
2373 break;
2374 }
2375 }
2376}
2377
2378static unsigned long mskip = 0x1000;
2379static unsigned long mlim = 0xffffffff;
2380
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002381static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382memzcan(void)
2383{
2384 unsigned char v;
2385 unsigned a;
2386 int ok, ook;
2387
2388 scanhex(&mdest);
2389 if (termch != '\n') termch = 0;
2390 scanhex(&mskip);
2391 if (termch != '\n') termch = 0;
2392 scanhex(&mlim);
2393 ook = 0;
2394 for (a = mdest; a < mlim; a += mskip) {
2395 ok = mread(a, &v, 1);
2396 if (ok && !ook) {
2397 printf("%.8x .. ", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002398 } else if (!ok && ook)
2399 printf("%.8x\n", a - mskip);
2400 ook = ok;
2401 if (a + mskip < a)
2402 break;
2403 }
2404 if (ook)
2405 printf("%.8x\n", a - mskip);
2406}
2407
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002408static void proccall(void)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002409{
2410 unsigned long args[8];
2411 unsigned long ret;
2412 int i;
2413 typedef unsigned long (*callfunc_t)(unsigned long, unsigned long,
2414 unsigned long, unsigned long, unsigned long,
2415 unsigned long, unsigned long, unsigned long);
2416 callfunc_t func;
2417
2418 if (!scanhex(&adrs))
2419 return;
2420 if (termch != '\n')
2421 termch = 0;
2422 for (i = 0; i < 8; ++i)
2423 args[i] = 0;
2424 for (i = 0; i < 8; ++i) {
2425 if (!scanhex(&args[i]) || termch == '\n')
2426 break;
2427 termch = 0;
2428 }
2429 func = (callfunc_t) adrs;
2430 ret = 0;
2431 if (setjmp(bus_error_jmp) == 0) {
2432 catch_memory_errors = 1;
2433 sync();
2434 ret = func(args[0], args[1], args[2], args[3],
2435 args[4], args[5], args[6], args[7]);
2436 sync();
Michael Ellerman736256e2014-05-26 21:02:14 +10002437 printf("return value is 0x%lx\n", ret);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002438 } else {
2439 printf("*** %x exception occurred\n", fault_except);
2440 }
2441 catch_memory_errors = 0;
2442}
2443
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444/* Input scanning routines */
2445int
2446skipbl(void)
2447{
2448 int c;
2449
2450 if( termch != 0 ){
2451 c = termch;
2452 termch = 0;
2453 } else
2454 c = inchar();
2455 while( c == ' ' || c == '\t' )
2456 c = inchar();
2457 return c;
2458}
2459
2460#define N_PTREGS 44
2461static char *regnames[N_PTREGS] = {
2462 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
2463 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
2464 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
2465 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002466 "pc", "msr", "or3", "ctr", "lr", "xer", "ccr",
2467#ifdef CONFIG_PPC64
2468 "softe",
2469#else
2470 "mq",
2471#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472 "trap", "dar", "dsisr", "res"
2473};
2474
2475int
2476scanhex(unsigned long *vp)
2477{
2478 int c, d;
2479 unsigned long v;
2480
2481 c = skipbl();
2482 if (c == '%') {
2483 /* parse register name */
2484 char regname[8];
2485 int i;
2486
2487 for (i = 0; i < sizeof(regname) - 1; ++i) {
2488 c = inchar();
2489 if (!isalnum(c)) {
2490 termch = c;
2491 break;
2492 }
2493 regname[i] = c;
2494 }
2495 regname[i] = 0;
2496 for (i = 0; i < N_PTREGS; ++i) {
2497 if (strcmp(regnames[i], regname) == 0) {
2498 if (xmon_regs == NULL) {
2499 printf("regs not available\n");
2500 return 0;
2501 }
2502 *vp = ((unsigned long *)xmon_regs)[i];
2503 return 1;
2504 }
2505 }
2506 printf("invalid register name '%%%s'\n", regname);
2507 return 0;
2508 }
2509
2510 /* skip leading "0x" if any */
2511
2512 if (c == '0') {
2513 c = inchar();
2514 if (c == 'x') {
2515 c = inchar();
2516 } else {
2517 d = hexdigit(c);
2518 if (d == EOF) {
2519 termch = c;
2520 *vp = 0;
2521 return 1;
2522 }
2523 }
2524 } else if (c == '$') {
2525 int i;
2526 for (i=0; i<63; i++) {
2527 c = inchar();
2528 if (isspace(c)) {
2529 termch = c;
2530 break;
2531 }
2532 tmpstr[i] = c;
2533 }
2534 tmpstr[i++] = 0;
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07002535 *vp = 0;
2536 if (setjmp(bus_error_jmp) == 0) {
2537 catch_memory_errors = 1;
2538 sync();
2539 *vp = kallsyms_lookup_name(tmpstr);
2540 sync();
2541 }
2542 catch_memory_errors = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002543 if (!(*vp)) {
2544 printf("unknown symbol '%s'\n", tmpstr);
2545 return 0;
2546 }
2547 return 1;
2548 }
2549
2550 d = hexdigit(c);
2551 if (d == EOF) {
2552 termch = c;
2553 return 0;
2554 }
2555 v = 0;
2556 do {
2557 v = (v << 4) + d;
2558 c = inchar();
2559 d = hexdigit(c);
2560 } while (d != EOF);
2561 termch = c;
2562 *vp = v;
2563 return 1;
2564}
2565
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002566static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002567scannl(void)
2568{
2569 int c;
2570
2571 c = termch;
2572 termch = 0;
2573 while( c != '\n' )
2574 c = inchar();
2575}
2576
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002577static int hexdigit(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578{
2579 if( '0' <= c && c <= '9' )
2580 return c - '0';
2581 if( 'A' <= c && c <= 'F' )
2582 return c - ('A' - 10);
2583 if( 'a' <= c && c <= 'f' )
2584 return c - ('a' - 10);
2585 return EOF;
2586}
2587
2588void
2589getstring(char *s, int size)
2590{
2591 int c;
2592
2593 c = skipbl();
2594 do {
2595 if( size > 1 ){
2596 *s++ = c;
2597 --size;
2598 }
2599 c = inchar();
2600 } while( c != ' ' && c != '\t' && c != '\n' );
2601 termch = c;
2602 *s = 0;
2603}
2604
2605static char line[256];
2606static char *lineptr;
2607
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002608static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609flush_input(void)
2610{
2611 lineptr = NULL;
2612}
2613
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002614static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002615inchar(void)
2616{
2617 if (lineptr == NULL || *lineptr == 0) {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002618 if (xmon_gets(line, sizeof(line)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619 lineptr = NULL;
2620 return EOF;
2621 }
2622 lineptr = line;
2623 }
2624 return *lineptr++;
2625}
2626
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002627static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628take_input(char *str)
2629{
2630 lineptr = str;
2631}
2632
2633
2634static void
2635symbol_lookup(void)
2636{
2637 int type = inchar();
2638 unsigned long addr;
2639 static char tmp[64];
2640
2641 switch (type) {
2642 case 'a':
2643 if (scanhex(&addr))
2644 xmon_print_symbol(addr, ": ", "\n");
2645 termch = 0;
2646 break;
2647 case 's':
2648 getstring(tmp, 64);
2649 if (setjmp(bus_error_jmp) == 0) {
2650 catch_memory_errors = 1;
2651 sync();
2652 addr = kallsyms_lookup_name(tmp);
2653 if (addr)
2654 printf("%s: %lx\n", tmp, addr);
2655 else
2656 printf("Symbol '%s' not found.\n", tmp);
2657 sync();
2658 }
2659 catch_memory_errors = 0;
2660 termch = 0;
2661 break;
2662 }
2663}
2664
2665
2666/* Print an address in numeric and symbolic form (if possible) */
2667static void xmon_print_symbol(unsigned long address, const char *mid,
2668 const char *after)
2669{
2670 char *modname;
2671 const char *name = NULL;
2672 unsigned long offset, size;
2673
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002674 printf(REG, address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675 if (setjmp(bus_error_jmp) == 0) {
2676 catch_memory_errors = 1;
2677 sync();
2678 name = kallsyms_lookup(address, &size, &offset, &modname,
2679 tmpstr);
2680 sync();
2681 /* wait a little while to see if we get a machine check */
2682 __delay(200);
2683 }
2684
2685 catch_memory_errors = 0;
2686
2687 if (name) {
2688 printf("%s%s+%#lx/%#lx", mid, name, offset, size);
2689 if (modname)
2690 printf(" [%s]", modname);
2691 }
2692 printf("%s", after);
2693}
2694
Benjamin Herrenschmidt2d27cfd2009-07-23 23:15:59 +00002695#ifdef CONFIG_PPC_BOOK3S_64
Michael Ellerman13b3d132014-07-10 12:29:20 +10002696void dump_segments(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697{
2698 int i;
will schmidtb3b95952007-12-07 08:22:23 +11002699 unsigned long esid,vsid,valid;
2700 unsigned long llp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701
Michael Ellerman736256e2014-05-26 21:02:14 +10002702 printf("SLB contents of cpu 0x%x\n", smp_processor_id());
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703
Michael Neuling584f8b72007-12-06 17:24:48 +11002704 for (i = 0; i < mmu_slb_size; i++) {
will schmidtb3b95952007-12-07 08:22:23 +11002705 asm volatile("slbmfee %0,%1" : "=r" (esid) : "r" (i));
2706 asm volatile("slbmfev %0,%1" : "=r" (vsid) : "r" (i));
2707 valid = (esid & SLB_ESID_V);
2708 if (valid | esid | vsid) {
2709 printf("%02d %016lx %016lx", i, esid, vsid);
2710 if (valid) {
2711 llp = vsid & SLB_VSID_LLP;
2712 if (vsid & SLB_VSID_B_1T) {
2713 printf(" 1T ESID=%9lx VSID=%13lx LLP:%3lx \n",
2714 GET_ESID_1T(esid),
2715 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT_1T,
2716 llp);
2717 } else {
2718 printf(" 256M ESID=%9lx VSID=%13lx LLP:%3lx \n",
2719 GET_ESID(esid),
2720 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT,
2721 llp);
2722 }
2723 } else
2724 printf("\n");
2725 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726 }
2727}
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002728#endif
2729
2730#ifdef CONFIG_PPC_STD_MMU_32
2731void dump_segments(void)
2732{
2733 int i;
2734
2735 printf("sr0-15 =");
2736 for (i = 0; i < 16; ++i)
2737 printf(" %x", mfsrin(i));
2738 printf("\n");
2739}
2740#endif
2741
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11002742#ifdef CONFIG_44x
2743static void dump_tlb_44x(void)
2744{
2745 int i;
2746
2747 for (i = 0; i < PPC44x_TLB_SIZE; i++) {
2748 unsigned long w0,w1,w2;
2749 asm volatile("tlbre %0,%1,0" : "=r" (w0) : "r" (i));
2750 asm volatile("tlbre %0,%1,1" : "=r" (w1) : "r" (i));
2751 asm volatile("tlbre %0,%1,2" : "=r" (w2) : "r" (i));
2752 printf("[%02x] %08x %08x %08x ", i, w0, w1, w2);
2753 if (w0 & PPC44x_TLB_VALID) {
2754 printf("V %08x -> %01x%08x %c%c%c%c%c",
2755 w0 & PPC44x_TLB_EPN_MASK,
2756 w1 & PPC44x_TLB_ERPN_MASK,
2757 w1 & PPC44x_TLB_RPN_MASK,
2758 (w2 & PPC44x_TLB_W) ? 'W' : 'w',
2759 (w2 & PPC44x_TLB_I) ? 'I' : 'i',
2760 (w2 & PPC44x_TLB_M) ? 'M' : 'm',
2761 (w2 & PPC44x_TLB_G) ? 'G' : 'g',
2762 (w2 & PPC44x_TLB_E) ? 'E' : 'e');
2763 }
2764 printf("\n");
2765 }
2766}
2767#endif /* CONFIG_44x */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002768
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +10002769#ifdef CONFIG_PPC_BOOK3E
2770static void dump_tlb_book3e(void)
2771{
2772 u32 mmucfg, pidmask, lpidmask;
2773 u64 ramask;
2774 int i, tlb, ntlbs, pidsz, lpidsz, rasz, lrat = 0;
2775 int mmu_version;
2776 static const char *pgsz_names[] = {
2777 " 1K",
2778 " 2K",
2779 " 4K",
2780 " 8K",
2781 " 16K",
2782 " 32K",
2783 " 64K",
2784 "128K",
2785 "256K",
2786 "512K",
2787 " 1M",
2788 " 2M",
2789 " 4M",
2790 " 8M",
2791 " 16M",
2792 " 32M",
2793 " 64M",
2794 "128M",
2795 "256M",
2796 "512M",
2797 " 1G",
2798 " 2G",
2799 " 4G",
2800 " 8G",
2801 " 16G",
2802 " 32G",
2803 " 64G",
2804 "128G",
2805 "256G",
2806 "512G",
2807 " 1T",
2808 " 2T",
2809 };
2810
2811 /* Gather some infos about the MMU */
2812 mmucfg = mfspr(SPRN_MMUCFG);
2813 mmu_version = (mmucfg & 3) + 1;
2814 ntlbs = ((mmucfg >> 2) & 3) + 1;
2815 pidsz = ((mmucfg >> 6) & 0x1f) + 1;
2816 lpidsz = (mmucfg >> 24) & 0xf;
2817 rasz = (mmucfg >> 16) & 0x7f;
2818 if ((mmu_version > 1) && (mmucfg & 0x10000))
2819 lrat = 1;
2820 printf("Book3E MMU MAV=%d.0,%d TLBs,%d-bit PID,%d-bit LPID,%d-bit RA\n",
2821 mmu_version, ntlbs, pidsz, lpidsz, rasz);
2822 pidmask = (1ul << pidsz) - 1;
2823 lpidmask = (1ul << lpidsz) - 1;
2824 ramask = (1ull << rasz) - 1;
2825
2826 for (tlb = 0; tlb < ntlbs; tlb++) {
2827 u32 tlbcfg;
2828 int nent, assoc, new_cc = 1;
2829 printf("TLB %d:\n------\n", tlb);
2830 switch(tlb) {
2831 case 0:
2832 tlbcfg = mfspr(SPRN_TLB0CFG);
2833 break;
2834 case 1:
2835 tlbcfg = mfspr(SPRN_TLB1CFG);
2836 break;
2837 case 2:
2838 tlbcfg = mfspr(SPRN_TLB2CFG);
2839 break;
2840 case 3:
2841 tlbcfg = mfspr(SPRN_TLB3CFG);
2842 break;
2843 default:
2844 printf("Unsupported TLB number !\n");
2845 continue;
2846 }
2847 nent = tlbcfg & 0xfff;
2848 assoc = (tlbcfg >> 24) & 0xff;
2849 for (i = 0; i < nent; i++) {
2850 u32 mas0 = MAS0_TLBSEL(tlb);
2851 u32 mas1 = MAS1_TSIZE(BOOK3E_PAGESZ_4K);
2852 u64 mas2 = 0;
2853 u64 mas7_mas3;
2854 int esel = i, cc = i;
2855
2856 if (assoc != 0) {
2857 cc = i / assoc;
2858 esel = i % assoc;
2859 mas2 = cc * 0x1000;
2860 }
2861
2862 mas0 |= MAS0_ESEL(esel);
2863 mtspr(SPRN_MAS0, mas0);
2864 mtspr(SPRN_MAS1, mas1);
2865 mtspr(SPRN_MAS2, mas2);
2866 asm volatile("tlbre 0,0,0" : : : "memory");
2867 mas1 = mfspr(SPRN_MAS1);
2868 mas2 = mfspr(SPRN_MAS2);
2869 mas7_mas3 = mfspr(SPRN_MAS7_MAS3);
2870 if (assoc && (i % assoc) == 0)
2871 new_cc = 1;
2872 if (!(mas1 & MAS1_VALID))
2873 continue;
2874 if (assoc == 0)
2875 printf("%04x- ", i);
2876 else if (new_cc)
2877 printf("%04x-%c", cc, 'A' + esel);
2878 else
2879 printf(" |%c", 'A' + esel);
2880 new_cc = 0;
2881 printf(" %016llx %04x %s %c%c AS%c",
2882 mas2 & ~0x3ffull,
2883 (mas1 >> 16) & 0x3fff,
2884 pgsz_names[(mas1 >> 7) & 0x1f],
2885 mas1 & MAS1_IND ? 'I' : ' ',
2886 mas1 & MAS1_IPROT ? 'P' : ' ',
2887 mas1 & MAS1_TS ? '1' : '0');
2888 printf(" %c%c%c%c%c%c%c",
2889 mas2 & MAS2_X0 ? 'a' : ' ',
2890 mas2 & MAS2_X1 ? 'v' : ' ',
2891 mas2 & MAS2_W ? 'w' : ' ',
2892 mas2 & MAS2_I ? 'i' : ' ',
2893 mas2 & MAS2_M ? 'm' : ' ',
2894 mas2 & MAS2_G ? 'g' : ' ',
2895 mas2 & MAS2_E ? 'e' : ' ');
2896 printf(" %016llx", mas7_mas3 & ramask & ~0x7ffull);
2897 if (mas1 & MAS1_IND)
2898 printf(" %s\n",
2899 pgsz_names[(mas7_mas3 >> 1) & 0x1f]);
2900 else
2901 printf(" U%c%c%c S%c%c%c\n",
2902 mas7_mas3 & MAS3_UX ? 'x' : ' ',
2903 mas7_mas3 & MAS3_UW ? 'w' : ' ',
2904 mas7_mas3 & MAS3_UR ? 'r' : ' ',
2905 mas7_mas3 & MAS3_SX ? 'x' : ' ',
2906 mas7_mas3 & MAS3_SW ? 'w' : ' ',
2907 mas7_mas3 & MAS3_SR ? 'r' : ' ');
2908 }
2909 }
2910}
2911#endif /* CONFIG_PPC_BOOK3E */
2912
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002913static void xmon_init(int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914{
Olaf Heringb13cfd172005-08-04 19:26:42 +02002915 if (enable) {
2916 __debugger = xmon;
2917 __debugger_ipi = xmon_ipi;
2918 __debugger_bpt = xmon_bpt;
2919 __debugger_sstep = xmon_sstep;
2920 __debugger_iabr_match = xmon_iabr_match;
Michael Neuling9422de32012-12-20 14:06:44 +00002921 __debugger_break_match = xmon_break_match;
Olaf Heringb13cfd172005-08-04 19:26:42 +02002922 __debugger_fault_handler = xmon_fault_handler;
2923 } else {
2924 __debugger = NULL;
2925 __debugger_ipi = NULL;
2926 __debugger_bpt = NULL;
2927 __debugger_sstep = NULL;
2928 __debugger_iabr_match = NULL;
Michael Neuling9422de32012-12-20 14:06:44 +00002929 __debugger_break_match = NULL;
Olaf Heringb13cfd172005-08-04 19:26:42 +02002930 __debugger_fault_handler = NULL;
2931 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002932}
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002933
2934#ifdef CONFIG_MAGIC_SYSRQ
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07002935static void sysrq_handle_xmon(int key)
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002936{
2937 /* ensure xmon is enabled */
2938 xmon_init(1);
David Howells7d12e782006-10-05 14:55:46 +01002939 debugger(get_irq_regs());
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002940}
2941
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07002942static struct sysrq_key_op sysrq_xmon_op = {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002943 .handler = sysrq_handle_xmon,
zhangwei(Jovi)90a102e2013-04-30 15:28:54 -07002944 .help_msg = "xmon(x)",
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002945 .action_msg = "Entering xmon",
2946};
2947
2948static int __init setup_xmon_sysrq(void)
2949{
2950 register_sysrq_key('x', &sysrq_xmon_op);
2951 return 0;
2952}
2953__initcall(setup_xmon_sysrq);
2954#endif /* CONFIG_MAGIC_SYSRQ */
Michael Ellerman476792832006-10-03 14:12:08 +10002955
Olaf Heringf5e6a282007-06-24 16:57:08 +10002956static int __initdata xmon_early, xmon_off;
Michael Ellerman476792832006-10-03 14:12:08 +10002957
2958static int __init early_parse_xmon(char *p)
2959{
2960 if (!p || strncmp(p, "early", 5) == 0) {
2961 /* just "xmon" is equivalent to "xmon=early" */
2962 xmon_init(1);
2963 xmon_early = 1;
2964 } else if (strncmp(p, "on", 2) == 0)
2965 xmon_init(1);
2966 else if (strncmp(p, "off", 3) == 0)
2967 xmon_off = 1;
2968 else if (strncmp(p, "nobt", 4) == 0)
2969 xmon_no_auto_backtrace = 1;
2970 else
2971 return 1;
2972
2973 return 0;
2974}
2975early_param("xmon", early_parse_xmon);
2976
2977void __init xmon_setup(void)
2978{
2979#ifdef CONFIG_XMON_DEFAULT
2980 if (!xmon_off)
2981 xmon_init(1);
2982#endif
2983 if (xmon_early)
2984 debugger(NULL);
2985}
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002986
Arnd Bergmanne0555952006-11-27 19:18:55 +01002987#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002988
2989struct spu_info {
2990 struct spu *spu;
2991 u64 saved_mfc_sr1_RW;
2992 u32 saved_spu_runcntl_RW;
Michael Ellerman24a24c82006-11-23 00:46:41 +01002993 unsigned long dump_addr;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002994 u8 stopped_ok;
2995};
2996
2997#define XMON_NUM_SPUS 16 /* Enough for current hardware */
2998
2999static struct spu_info spu_info[XMON_NUM_SPUS];
3000
3001void xmon_register_spus(struct list_head *list)
3002{
3003 struct spu *spu;
3004
3005 list_for_each_entry(spu, list, full_list) {
3006 if (spu->number >= XMON_NUM_SPUS) {
3007 WARN_ON(1);
3008 continue;
3009 }
3010
3011 spu_info[spu->number].spu = spu;
3012 spu_info[spu->number].stopped_ok = 0;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003013 spu_info[spu->number].dump_addr = (unsigned long)
3014 spu_info[spu->number].spu->local_store;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003015 }
3016}
3017
3018static void stop_spus(void)
3019{
3020 struct spu *spu;
3021 int i;
3022 u64 tmp;
3023
3024 for (i = 0; i < XMON_NUM_SPUS; i++) {
3025 if (!spu_info[i].spu)
3026 continue;
3027
3028 if (setjmp(bus_error_jmp) == 0) {
3029 catch_memory_errors = 1;
3030 sync();
3031
3032 spu = spu_info[i].spu;
3033
3034 spu_info[i].saved_spu_runcntl_RW =
3035 in_be32(&spu->problem->spu_runcntl_RW);
3036
3037 tmp = spu_mfc_sr1_get(spu);
3038 spu_info[i].saved_mfc_sr1_RW = tmp;
3039
3040 tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
3041 spu_mfc_sr1_set(spu, tmp);
3042
3043 sync();
3044 __delay(200);
3045
3046 spu_info[i].stopped_ok = 1;
Michael Ellerman2a144422006-11-23 00:46:40 +01003047
3048 printf("Stopped spu %.2d (was %s)\n", i,
3049 spu_info[i].saved_spu_runcntl_RW ?
3050 "running" : "stopped");
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003051 } else {
3052 catch_memory_errors = 0;
3053 printf("*** Error stopping spu %.2d\n", i);
3054 }
3055 catch_memory_errors = 0;
3056 }
3057}
3058
3059static void restart_spus(void)
3060{
3061 struct spu *spu;
3062 int i;
3063
3064 for (i = 0; i < XMON_NUM_SPUS; i++) {
3065 if (!spu_info[i].spu)
3066 continue;
3067
3068 if (!spu_info[i].stopped_ok) {
3069 printf("*** Error, spu %d was not successfully stopped"
3070 ", not restarting\n", i);
3071 continue;
3072 }
3073
3074 if (setjmp(bus_error_jmp) == 0) {
3075 catch_memory_errors = 1;
3076 sync();
3077
3078 spu = spu_info[i].spu;
3079 spu_mfc_sr1_set(spu, spu_info[i].saved_mfc_sr1_RW);
3080 out_be32(&spu->problem->spu_runcntl_RW,
3081 spu_info[i].saved_spu_runcntl_RW);
3082
3083 sync();
3084 __delay(200);
3085
3086 printf("Restarted spu %.2d\n", i);
3087 } else {
3088 catch_memory_errors = 0;
3089 printf("*** Error restarting spu %.2d\n", i);
3090 }
3091 catch_memory_errors = 0;
3092 }
3093}
3094
Michael Ellermana8984972006-10-24 18:31:28 +02003095#define DUMP_WIDTH 23
Michael Ellerman437a0702006-11-23 00:46:39 +01003096#define DUMP_VALUE(format, field, value) \
Michael Ellermana8984972006-10-24 18:31:28 +02003097do { \
3098 if (setjmp(bus_error_jmp) == 0) { \
3099 catch_memory_errors = 1; \
3100 sync(); \
3101 printf(" %-*s = "format"\n", DUMP_WIDTH, \
Michael Ellerman437a0702006-11-23 00:46:39 +01003102 #field, value); \
Michael Ellermana8984972006-10-24 18:31:28 +02003103 sync(); \
3104 __delay(200); \
3105 } else { \
3106 catch_memory_errors = 0; \
3107 printf(" %-*s = *** Error reading field.\n", \
3108 DUMP_WIDTH, #field); \
3109 } \
3110 catch_memory_errors = 0; \
3111} while (0)
3112
Michael Ellerman437a0702006-11-23 00:46:39 +01003113#define DUMP_FIELD(obj, format, field) \
3114 DUMP_VALUE(format, field, obj->field)
3115
Michael Ellermana8984972006-10-24 18:31:28 +02003116static void dump_spu_fields(struct spu *spu)
3117{
3118 printf("Dumping spu fields at address %p:\n", spu);
3119
3120 DUMP_FIELD(spu, "0x%x", number);
3121 DUMP_FIELD(spu, "%s", name);
Michael Ellermana8984972006-10-24 18:31:28 +02003122 DUMP_FIELD(spu, "0x%lx", local_store_phys);
3123 DUMP_FIELD(spu, "0x%p", local_store);
3124 DUMP_FIELD(spu, "0x%lx", ls_size);
3125 DUMP_FIELD(spu, "0x%x", node);
3126 DUMP_FIELD(spu, "0x%lx", flags);
Michael Ellermana8984972006-10-24 18:31:28 +02003127 DUMP_FIELD(spu, "%d", class_0_pending);
Luke Browningf3d69e02008-04-27 18:41:55 +00003128 DUMP_FIELD(spu, "0x%lx", class_0_dar);
Luke Browningf3d69e02008-04-27 18:41:55 +00003129 DUMP_FIELD(spu, "0x%lx", class_1_dar);
3130 DUMP_FIELD(spu, "0x%lx", class_1_dsisr);
Michael Ellermana8984972006-10-24 18:31:28 +02003131 DUMP_FIELD(spu, "0x%lx", irqs[0]);
3132 DUMP_FIELD(spu, "0x%lx", irqs[1]);
3133 DUMP_FIELD(spu, "0x%lx", irqs[2]);
3134 DUMP_FIELD(spu, "0x%x", slb_replace);
3135 DUMP_FIELD(spu, "%d", pid);
Michael Ellermana8984972006-10-24 18:31:28 +02003136 DUMP_FIELD(spu, "0x%p", mm);
3137 DUMP_FIELD(spu, "0x%p", ctx);
3138 DUMP_FIELD(spu, "0x%p", rq);
3139 DUMP_FIELD(spu, "0x%p", timestamp);
3140 DUMP_FIELD(spu, "0x%lx", problem_phys);
3141 DUMP_FIELD(spu, "0x%p", problem);
Michael Ellerman437a0702006-11-23 00:46:39 +01003142 DUMP_VALUE("0x%x", problem->spu_runcntl_RW,
3143 in_be32(&spu->problem->spu_runcntl_RW));
3144 DUMP_VALUE("0x%x", problem->spu_status_R,
3145 in_be32(&spu->problem->spu_status_R));
3146 DUMP_VALUE("0x%x", problem->spu_npc_RW,
3147 in_be32(&spu->problem->spu_npc_RW));
Michael Ellermana8984972006-10-24 18:31:28 +02003148 DUMP_FIELD(spu, "0x%p", priv2);
Michael Ellermana9852392006-11-23 00:46:50 +01003149 DUMP_FIELD(spu, "0x%p", pdata);
Michael Ellermana8984972006-10-24 18:31:28 +02003150}
3151
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003152int
3153spu_inst_dump(unsigned long adr, long count, int praddr)
3154{
3155 return generic_inst_dump(adr, count, praddr, print_insn_spu);
3156}
3157
3158static void dump_spu_ls(unsigned long num, int subcmd)
Michael Ellerman24a24c82006-11-23 00:46:41 +01003159{
3160 unsigned long offset, addr, ls_addr;
3161
3162 if (setjmp(bus_error_jmp) == 0) {
3163 catch_memory_errors = 1;
3164 sync();
3165 ls_addr = (unsigned long)spu_info[num].spu->local_store;
3166 sync();
3167 __delay(200);
3168 } else {
3169 catch_memory_errors = 0;
3170 printf("*** Error: accessing spu info for spu %d\n", num);
3171 return;
3172 }
3173 catch_memory_errors = 0;
3174
3175 if (scanhex(&offset))
3176 addr = ls_addr + offset;
3177 else
3178 addr = spu_info[num].dump_addr;
3179
3180 if (addr >= ls_addr + LS_SIZE) {
3181 printf("*** Error: address outside of local store\n");
3182 return;
3183 }
3184
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003185 switch (subcmd) {
3186 case 'i':
3187 addr += spu_inst_dump(addr, 16, 1);
3188 last_cmd = "sdi\n";
3189 break;
3190 default:
3191 prdump(addr, 64);
3192 addr += 64;
3193 last_cmd = "sd\n";
3194 break;
3195 }
Michael Ellerman24a24c82006-11-23 00:46:41 +01003196
3197 spu_info[num].dump_addr = addr;
3198}
3199
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003200static int do_spu_cmd(void)
3201{
Michael Ellerman24a24c82006-11-23 00:46:41 +01003202 static unsigned long num = 0;
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003203 int cmd, subcmd = 0;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003204
3205 cmd = inchar();
3206 switch (cmd) {
3207 case 's':
3208 stop_spus();
3209 break;
3210 case 'r':
3211 restart_spus();
3212 break;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003213 case 'd':
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003214 subcmd = inchar();
3215 if (isxdigit(subcmd) || subcmd == '\n')
3216 termch = subcmd;
3217 case 'f':
Michael Ellerman24a24c82006-11-23 00:46:41 +01003218 scanhex(&num);
3219 if (num >= XMON_NUM_SPUS || !spu_info[num].spu) {
Michael Ellermana8984972006-10-24 18:31:28 +02003220 printf("*** Error: invalid spu number\n");
Michael Ellerman24a24c82006-11-23 00:46:41 +01003221 return 0;
3222 }
3223
3224 switch (cmd) {
3225 case 'f':
3226 dump_spu_fields(spu_info[num].spu);
3227 break;
3228 default:
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003229 dump_spu_ls(num, subcmd);
Michael Ellerman24a24c82006-11-23 00:46:41 +01003230 break;
3231 }
3232
Michael Ellermana8984972006-10-24 18:31:28 +02003233 break;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003234 default:
3235 return -1;
3236 }
3237
3238 return 0;
3239}
Arnd Bergmanne0555952006-11-27 19:18:55 +01003240#else /* ! CONFIG_SPU_BASE */
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003241static int do_spu_cmd(void)
3242{
3243 return -1;
3244}
3245#endif