blob: d199bfa2f1fa5ff6610c0413ff0795d6ca42c6a7 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Routines providing a simple monitor for use on the PowerMac.
3 *
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11004 * Copyright (C) 1996-2005 Paul Mackerras.
Michael Ellerman476792832006-10-03 14:12:08 +10005 * Copyright (C) 2001 PPC64 Team, IBM Corp
6 * Copyrignt (C) 2006 Michael Ellerman, IBM Corp
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <linux/errno.h>
14#include <linux/sched.h>
15#include <linux/smp.h>
16#include <linux/mm.h>
17#include <linux/reboot.h>
18#include <linux/delay.h>
19#include <linux/kallsyms.h>
Michael Ellermanca5dd392012-08-23 22:09:12 +000020#include <linux/kmsg_dump.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <linux/cpumask.h>
Paul Gortmaker4b16f8e2011-07-22 18:24:23 -040022#include <linux/export.h>
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +110023#include <linux/sysrq.h>
Andrew Morton4694ca02005-11-13 16:06:50 -080024#include <linux/interrupt.h>
David Howells7d12e782006-10-05 14:55:46 +010025#include <linux/irq.h>
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -080026#include <linux/bug.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070027
28#include <asm/ptrace.h>
29#include <asm/string.h>
30#include <asm/prom.h>
31#include <asm/machdep.h>
Paul Mackerrasf78541d2005-10-28 22:53:37 +100032#include <asm/xmon.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <asm/processor.h>
34#include <asm/pgtable.h>
35#include <asm/mmu.h>
36#include <asm/mmu_context.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#include <asm/cputable.h>
38#include <asm/rtas.h>
39#include <asm/sstep.h>
Paul Mackerrasf583ffc2006-10-10 11:47:07 +100040#include <asm/irq_regs.h>
Michael Ellermanff8a8f22006-10-24 18:31:27 +020041#include <asm/spu.h>
42#include <asm/spu_priv1.h>
Michael Neulingc3b75bd2008-01-18 15:50:30 +110043#include <asm/setjmp.h>
Anton Vorontsov322b4392008-12-17 10:08:55 +000044#include <asm/reg.h>
David Howellsae3a1972012-03-28 18:30:02 +010045#include <asm/debug.h>
Michael Neuling9422de32012-12-20 14:06:44 +000046#include <asm/hw_breakpoint.h>
Paul Mackerrasf78541d2005-10-28 22:53:37 +100047
48#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <asm/hvcall.h>
Paul Mackerrasf78541d2005-10-28 22:53:37 +100050#include <asm/paca.h>
51#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070052
53#include "nonstdio.h"
Michael Ellermane0426042006-11-23 00:46:45 +010054#include "dis-asm.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070055
Linus Torvalds1da177e2005-04-16 15:20:36 -070056#ifdef CONFIG_SMP
Michael Ellerman1c8950f2008-05-08 14:27:17 +100057static cpumask_t cpus_in_xmon = CPU_MASK_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070058static unsigned long xmon_taken = 1;
59static int xmon_owner;
60static int xmon_gate;
Michael Ellermanddadb6b2012-09-13 23:01:31 +000061#else
62#define xmon_owner 0
Linus Torvalds1da177e2005-04-16 15:20:36 -070063#endif /* CONFIG_SMP */
64
Anton Blanchard5be34922010-01-12 00:50:14 +000065static unsigned long in_xmon __read_mostly = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
67static unsigned long adrs;
68static int size = 1;
69#define MAX_DUMP (128 * 1024)
70static unsigned long ndump = 64;
71static unsigned long nidump = 16;
72static unsigned long ncsum = 4096;
73static int termch;
74static char tmpstr[128];
75
Linus Torvalds1da177e2005-04-16 15:20:36 -070076static long bus_error_jmp[JMP_BUF_LEN];
77static int catch_memory_errors;
78static long *xmon_fault_jmp[NR_CPUS];
Linus Torvalds1da177e2005-04-16 15:20:36 -070079
80/* Breakpoint stuff */
81struct bpt {
82 unsigned long address;
83 unsigned int instr[2];
84 atomic_t ref_count;
85 int enabled;
86 unsigned long pad;
87};
88
89/* Bits in bpt.enabled */
90#define BP_IABR_TE 1 /* IABR translation enabled */
91#define BP_IABR 2
92#define BP_TRAP 8
93#define BP_DABR 0x10
94
95#define NBPTS 256
96static struct bpt bpts[NBPTS];
97static struct bpt dabr;
98static struct bpt *iabr;
99static unsigned bpinstr = 0x7fe00008; /* trap */
100
101#define BP_NUM(bp) ((bp) - bpts + 1)
102
103/* Prototypes */
104static int cmds(struct pt_regs *);
105static int mread(unsigned long, void *, int);
106static int mwrite(unsigned long, void *, int);
107static int handle_fault(struct pt_regs *);
108static void byterev(unsigned char *, int);
109static void memex(void);
110static int bsesc(void);
111static void dump(void);
112static void prdump(unsigned long, long);
113static int ppc_inst_dump(unsigned long, long, int);
Vinay Sridharf312deb2009-05-14 23:13:07 +0000114static void dump_log_buf(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115static void backtrace(struct pt_regs *);
116static void excprint(struct pt_regs *);
117static void prregs(struct pt_regs *);
118static void memops(int);
119static void memlocate(void);
120static void memzcan(void);
121static void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned);
122int skipbl(void);
123int scanhex(unsigned long *valp);
124static void scannl(void);
125static int hexdigit(int);
126void getstring(char *, int);
127static void flush_input(void);
128static int inchar(void);
129static void take_input(char *);
130static unsigned long read_spr(int);
131static void write_spr(int, unsigned long);
132static void super_regs(void);
133static void remove_bpts(void);
134static void insert_bpts(void);
135static void remove_cpu_bpts(void);
136static void insert_cpu_bpts(void);
137static struct bpt *at_breakpoint(unsigned long pc);
138static struct bpt *in_breakpoint_table(unsigned long pc, unsigned long *offp);
139static int do_step(struct pt_regs *);
140static void bpt_cmds(void);
141static void cacheflush(void);
142static int cpu_cmd(void);
143static void csum(void);
144static void bootcmds(void);
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000145static void proccall(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146void dump_segments(void);
147static void symbol_lookup(void);
Olaf Hering26c8af52006-09-08 16:29:21 +0200148static void xmon_show_stack(unsigned long sp, unsigned long lr,
149 unsigned long pc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150static void xmon_print_symbol(unsigned long address, const char *mid,
151 const char *after);
152static const char *getvecname(unsigned long vec);
153
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200154static int do_spu_cmd(void);
155
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100156#ifdef CONFIG_44x
157static void dump_tlb_44x(void);
158#endif
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +1000159#ifdef CONFIG_PPC_BOOK3E
160static void dump_tlb_book3e(void);
161#endif
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100162
Michael Ellerman9f1067c22008-05-08 14:27:16 +1000163static int xmon_no_auto_backtrace;
Olaf Hering26c8af52006-09-08 16:29:21 +0200164
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000165extern void xmon_enter(void);
166extern void xmon_leave(void);
167
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000168#ifdef CONFIG_PPC64
169#define REG "%.16lx"
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000170#else
171#define REG "%.8lx"
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000172#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173
Philippe Bergheaud72eceef2013-12-02 10:10:12 +0100174#ifdef __LITTLE_ENDIAN__
175#define GETWORD(v) (((v)[3] << 24) + ((v)[2] << 16) + ((v)[1] << 8) + (v)[0])
176#else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177#define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
Philippe Bergheaud72eceef2013-12-02 10:10:12 +0100178#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179
180#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
181 || ('a' <= (c) && (c) <= 'f') \
182 || ('A' <= (c) && (c) <= 'F'))
183#define isalnum(c) (('0' <= (c) && (c) <= '9') \
184 || ('a' <= (c) && (c) <= 'z') \
185 || ('A' <= (c) && (c) <= 'Z'))
186#define isspace(c) (c == ' ' || c == '\t' || c == 10 || c == 13 || c == 0)
187
188static char *help_string = "\
189Commands:\n\
190 b show breakpoints\n\
191 bd set data breakpoint\n\
192 bi set instruction breakpoint\n\
193 bc clear breakpoint\n"
194#ifdef CONFIG_SMP
195 "\
196 c print cpus stopped in xmon\n\
197 c# try to switch to cpu number h (in hex)\n"
198#endif
199 "\
200 C checksum\n\
201 d dump bytes\n\
202 di dump instructions\n\
203 df dump float values\n\
204 dd dump double values\n\
Michael Ellermanddadb6b2012-09-13 23:01:31 +0000205 dl dump the kernel log buffer\n"
206#ifdef CONFIG_PPC64
207 "\
208 dp[#] dump paca for current cpu, or cpu #\n\
209 dpa dump paca for all possible cpus\n"
210#endif
211 "\
Olaf Hering7e5b5932006-03-08 20:40:28 +0100212 dr dump stream of raw bytes\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 e print exception information\n\
214 f flush cache\n\
215 la lookup symbol+offset of specified address\n\
216 ls lookup address of specified symbol\n\
217 m examine/change memory\n\
218 mm move a block of memory\n\
219 ms set a block of memory\n\
220 md compare two blocks of memory\n\
221 ml locate a block of memory\n\
222 mz zero a block of memory\n\
223 mi show information about memory allocation\n\
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000224 p call a procedure\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 r print registers\n\
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200226 s single step\n"
Arnd Bergmanne0555952006-11-27 19:18:55 +0100227#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200228" ss stop execution on all spus\n\
Michael Ellermana8984972006-10-24 18:31:28 +0200229 sr restore execution on stopped spus\n\
Michael Ellerman24a24c82006-11-23 00:46:41 +0100230 sf # dump spu fields for spu # (in hex)\n\
Michael Ellermanc99176a2007-02-26 18:14:06 +0900231 sd # dump spu local store for spu # (in hex)\n\
Michael Ellermanaf89fb82006-11-23 00:46:44 +0100232 sdi # disassemble spu local store for spu # (in hex)\n"
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200233#endif
234" S print special registers\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 t print backtrace\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 x exit monitor and recover\n\
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000237 X exit monitor and dont recover\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000238#if defined(CONFIG_PPC64) && !defined(CONFIG_PPC_BOOK3E)
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000239" u dump segment table or SLB\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000240#elif defined(CONFIG_PPC_STD_MMU_32)
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000241" u dump segment registers\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000242#elif defined(CONFIG_44x) || defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100243" u dump TLB\n"
244#endif
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000245" ? help\n"
246" zr reboot\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 zh halt\n"
248;
249
250static struct pt_regs *xmon_regs;
251
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000252static inline void sync(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253{
254 asm volatile("sync; isync");
255}
256
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000257static inline void store_inst(void *p)
258{
259 asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p));
260}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000262static inline void cflush(void *p)
263{
264 asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p));
265}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000267static inline void cinval(void *p)
268{
269 asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p));
270}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271
272/*
273 * Disable surveillance (the service processor watchdog function)
274 * while we are in xmon.
275 * XXX we should re-enable it when we leave. :)
276 */
277#define SURVEILLANCE_TOKEN 9000
278
279static inline void disable_surveillance(void)
280{
281#ifdef CONFIG_PPC_PSERIES
282 /* Since this can't be a module, args should end up below 4GB. */
283 static struct rtas_args args;
284
285 /*
286 * At this point we have got all the cpus we can into
287 * xmon, so there is hopefully no other cpu calling RTAS
288 * at the moment, even though we don't take rtas.lock.
289 * If we did try to take rtas.lock there would be a
290 * real possibility of deadlock.
291 */
292 args.token = rtas_token("set-indicator");
293 if (args.token == RTAS_UNKNOWN_SERVICE)
294 return;
295 args.nargs = 3;
296 args.nret = 1;
297 args.rets = &args.args[3];
298 args.args[0] = SURVEILLANCE_TOKEN;
299 args.args[1] = 0;
300 args.args[2] = 0;
301 enter_rtas(__pa(&args));
302#endif /* CONFIG_PPC_PSERIES */
303}
304
305#ifdef CONFIG_SMP
306static int xmon_speaker;
307
308static void get_output_lock(void)
309{
310 int me = smp_processor_id() + 0x100;
311 int last_speaker = 0, prev;
312 long timeout;
313
314 if (xmon_speaker == me)
315 return;
Michael Ellerman730efb62013-12-23 23:46:04 +1100316
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 for (;;) {
Michael Ellerman730efb62013-12-23 23:46:04 +1100318 last_speaker = cmpxchg(&xmon_speaker, 0, me);
319 if (last_speaker == 0)
320 return;
321
Michael Ellerman15075892013-12-23 23:46:05 +1100322 /*
323 * Wait a full second for the lock, we might be on a slow
324 * console, but check every 100us.
325 */
326 timeout = 10000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 while (xmon_speaker == last_speaker) {
Michael Ellerman15075892013-12-23 23:46:05 +1100328 if (--timeout > 0) {
329 udelay(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 continue;
Michael Ellerman15075892013-12-23 23:46:05 +1100331 }
332
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 /* hostile takeover */
334 prev = cmpxchg(&xmon_speaker, last_speaker, me);
335 if (prev == last_speaker)
336 return;
337 break;
338 }
339 }
340}
341
342static void release_output_lock(void)
343{
344 xmon_speaker = 0;
345}
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000346
347int cpus_are_in_xmon(void)
348{
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000349 return !cpumask_empty(&cpus_in_xmon);
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000350}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351#endif
352
Josh Boyerdaf8f402009-09-23 03:51:04 +0000353static inline int unrecoverable_excp(struct pt_regs *regs)
354{
Jimi Xenidis08f6d6a2011-09-29 12:05:28 +0000355#if defined(CONFIG_4xx) || defined(CONFIG_PPC_BOOK3E)
Jimi Xenidis66857b32011-09-23 05:40:46 +0000356 /* We have no MSR_RI bit on 4xx or Book3e, so we simply return false */
Josh Boyerdaf8f402009-09-23 03:51:04 +0000357 return 0;
358#else
359 return ((regs->msr & MSR_RI) == 0);
360#endif
361}
362
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000363static int xmon_core(struct pt_regs *regs, int fromipi)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364{
365 int cmd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 struct bpt *bp;
367 long recurse_jmp[JMP_BUF_LEN];
368 unsigned long offset;
Anton Blanchardf13659e2007-03-21 01:48:34 +1100369 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370#ifdef CONFIG_SMP
371 int cpu;
372 int secondary;
373 unsigned long timeout;
374#endif
375
Anton Blanchardf13659e2007-03-21 01:48:34 +1100376 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377
378 bp = in_breakpoint_table(regs->nip, &offset);
379 if (bp != NULL) {
380 regs->nip = bp->address + offset;
381 atomic_dec(&bp->ref_count);
382 }
383
384 remove_cpu_bpts();
385
386#ifdef CONFIG_SMP
387 cpu = smp_processor_id();
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000388 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 get_output_lock();
390 excprint(regs);
391 printf("cpu 0x%x: Exception %lx %s in xmon, "
392 "returning to main loop\n",
393 cpu, regs->trap, getvecname(TRAP(regs)));
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000394 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 longjmp(xmon_fault_jmp[cpu], 1);
396 }
397
398 if (setjmp(recurse_jmp) != 0) {
399 if (!in_xmon || !xmon_gate) {
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000400 get_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 printf("xmon: WARNING: bad recursive fault "
402 "on cpu 0x%x\n", cpu);
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000403 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 goto waiting;
405 }
406 secondary = !(xmon_taken && cpu == xmon_owner);
407 goto cmdloop;
408 }
409
410 xmon_fault_jmp[cpu] = recurse_jmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411
412 bp = NULL;
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000413 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 bp = at_breakpoint(regs->nip);
Josh Boyerdaf8f402009-09-23 03:51:04 +0000415 if (bp || unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 fromipi = 0;
417
418 if (!fromipi) {
419 get_output_lock();
420 excprint(regs);
421 if (bp) {
Michael Ellerman736256e2014-05-26 21:02:14 +1000422 printf("cpu 0x%x stopped at breakpoint 0x%lx (",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 cpu, BP_NUM(bp));
424 xmon_print_symbol(regs->nip, " ", ")\n");
425 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000426 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 printf("WARNING: exception is not recoverable, "
428 "can't continue\n");
429 release_output_lock();
430 }
431
Michael Ellermand2b496e2013-12-23 23:46:06 +1100432 cpumask_set_cpu(cpu, &cpus_in_xmon);
433
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 waiting:
435 secondary = 1;
436 while (secondary && !xmon_gate) {
437 if (in_xmon == 0) {
438 if (fromipi)
439 goto leave;
440 secondary = test_and_set_bit(0, &in_xmon);
441 }
442 barrier();
443 }
444
445 if (!secondary && !xmon_gate) {
446 /* we are the first cpu to come in */
447 /* interrupt other cpu(s) */
448 int ncpus = num_online_cpus();
449
450 xmon_owner = cpu;
451 mb();
452 if (ncpus > 1) {
Milton Millere0476372011-05-10 19:29:06 +0000453 smp_send_debugger_break();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 /* wait for other cpus to come in */
455 for (timeout = 100000000; timeout != 0; --timeout) {
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000456 if (cpumask_weight(&cpus_in_xmon) >= ncpus)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 break;
458 barrier();
459 }
460 }
461 remove_bpts();
462 disable_surveillance();
463 /* for breakpoint or single step, print the current instr. */
464 if (bp || TRAP(regs) == 0xd00)
465 ppc_inst_dump(regs->nip, 1, 0);
466 printf("enter ? for help\n");
467 mb();
468 xmon_gate = 1;
469 barrier();
470 }
471
472 cmdloop:
473 while (in_xmon) {
474 if (secondary) {
475 if (cpu == xmon_owner) {
476 if (!test_and_set_bit(0, &xmon_taken)) {
477 secondary = 0;
478 continue;
479 }
480 /* missed it */
481 while (cpu == xmon_owner)
482 barrier();
483 }
484 barrier();
485 } else {
486 cmd = cmds(regs);
487 if (cmd != 0) {
488 /* exiting xmon */
489 insert_bpts();
490 xmon_gate = 0;
491 wmb();
492 in_xmon = 0;
493 break;
494 }
495 /* have switched to some other cpu */
496 secondary = 1;
497 }
498 }
499 leave:
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000500 cpumask_clear_cpu(cpu, &cpus_in_xmon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 xmon_fault_jmp[cpu] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502#else
503 /* UP is simple... */
504 if (in_xmon) {
505 printf("Exception %lx %s in xmon, returning to main loop\n",
506 regs->trap, getvecname(TRAP(regs)));
507 longjmp(xmon_fault_jmp[0], 1);
508 }
509 if (setjmp(recurse_jmp) == 0) {
510 xmon_fault_jmp[0] = recurse_jmp;
511 in_xmon = 1;
512
513 excprint(regs);
514 bp = at_breakpoint(regs->nip);
515 if (bp) {
Michael Ellerman736256e2014-05-26 21:02:14 +1000516 printf("Stopped at breakpoint %lx (", BP_NUM(bp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 xmon_print_symbol(regs->nip, " ", ")\n");
518 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000519 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 printf("WARNING: exception is not recoverable, "
521 "can't continue\n");
522 remove_bpts();
523 disable_surveillance();
524 /* for breakpoint or single step, print the current instr. */
525 if (bp || TRAP(regs) == 0xd00)
526 ppc_inst_dump(regs->nip, 1, 0);
527 printf("enter ? for help\n");
528 }
529
530 cmd = cmds(regs);
531
532 insert_bpts();
533 in_xmon = 0;
534#endif
535
Josh Boyercdd39042009-10-05 04:46:05 +0000536#ifdef CONFIG_BOOKE
537 if (regs->msr & MSR_DE) {
538 bp = at_breakpoint(regs->nip);
539 if (bp != NULL) {
540 regs->nip = (unsigned long) &bp->instr[0];
541 atomic_inc(&bp->ref_count);
542 }
543 }
544#else
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000545 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 bp = at_breakpoint(regs->nip);
547 if (bp != NULL) {
548 int stepped = emulate_step(regs, bp->instr[0]);
549 if (stepped == 0) {
550 regs->nip = (unsigned long) &bp->instr[0];
551 atomic_inc(&bp->ref_count);
552 } else if (stepped < 0) {
553 printf("Couldn't single-step %s instruction\n",
554 (IS_RFID(bp->instr[0])? "rfid": "mtmsrd"));
555 }
556 }
557 }
Josh Boyercdd39042009-10-05 04:46:05 +0000558#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 insert_cpu_bpts();
560
Anton Blanchardf13659e2007-03-21 01:48:34 +1100561 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562
Paul Mackerras0a730ae2006-10-03 21:32:49 +1000563 return cmd != 'X' && cmd != EOF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564}
565
566int xmon(struct pt_regs *excp)
567{
568 struct pt_regs regs;
569
570 if (excp == NULL) {
Anton Vorontsov322b4392008-12-17 10:08:55 +0000571 ppc_save_regs(&regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 excp = &regs;
573 }
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200574
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 return xmon_core(excp, 0);
576}
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000577EXPORT_SYMBOL(xmon);
578
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000579irqreturn_t xmon_irq(int irq, void *d)
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000580{
581 unsigned long flags;
582 local_irq_save(flags);
583 printf("Keyboard interrupt\n");
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000584 xmon(get_irq_regs());
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000585 local_irq_restore(flags);
586 return IRQ_HANDLED;
587}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000589static int xmon_bpt(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590{
591 struct bpt *bp;
592 unsigned long offset;
593
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000594 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 return 0;
596
597 /* Are we at the trap at bp->instr[1] for some bp? */
598 bp = in_breakpoint_table(regs->nip, &offset);
599 if (bp != NULL && offset == 4) {
600 regs->nip = bp->address + 4;
601 atomic_dec(&bp->ref_count);
602 return 1;
603 }
604
605 /* Are we at a breakpoint? */
606 bp = at_breakpoint(regs->nip);
607 if (!bp)
608 return 0;
609
610 xmon_core(regs, 0);
611
612 return 1;
613}
614
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000615static int xmon_sstep(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616{
617 if (user_mode(regs))
618 return 0;
619 xmon_core(regs, 0);
620 return 1;
621}
622
Michael Neuling9422de32012-12-20 14:06:44 +0000623static int xmon_break_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000625 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 return 0;
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000627 if (dabr.enabled == 0)
628 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 xmon_core(regs, 0);
630 return 1;
631}
632
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000633static int xmon_iabr_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000635 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 return 0;
Michael Ellerman9f1067c22008-05-08 14:27:16 +1000637 if (iabr == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 return 0;
639 xmon_core(regs, 0);
640 return 1;
641}
642
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000643static int xmon_ipi(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644{
645#ifdef CONFIG_SMP
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000646 if (in_xmon && !cpumask_test_cpu(smp_processor_id(), &cpus_in_xmon))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 xmon_core(regs, 1);
648#endif
649 return 0;
650}
651
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000652static int xmon_fault_handler(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653{
654 struct bpt *bp;
655 unsigned long offset;
656
657 if (in_xmon && catch_memory_errors)
658 handle_fault(regs); /* doesn't return */
659
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000660 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 bp = in_breakpoint_table(regs->nip, &offset);
662 if (bp != NULL) {
663 regs->nip = bp->address + offset;
664 atomic_dec(&bp->ref_count);
665 }
666 }
667
668 return 0;
669}
670
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671static struct bpt *at_breakpoint(unsigned long pc)
672{
673 int i;
674 struct bpt *bp;
675
676 bp = bpts;
677 for (i = 0; i < NBPTS; ++i, ++bp)
678 if (bp->enabled && pc == bp->address)
679 return bp;
680 return NULL;
681}
682
683static struct bpt *in_breakpoint_table(unsigned long nip, unsigned long *offp)
684{
685 unsigned long off;
686
687 off = nip - (unsigned long) bpts;
688 if (off >= sizeof(bpts))
689 return NULL;
690 off %= sizeof(struct bpt);
691 if (off != offsetof(struct bpt, instr[0])
692 && off != offsetof(struct bpt, instr[1]))
693 return NULL;
694 *offp = off - offsetof(struct bpt, instr[0]);
695 return (struct bpt *) (nip - off);
696}
697
698static struct bpt *new_breakpoint(unsigned long a)
699{
700 struct bpt *bp;
701
702 a &= ~3UL;
703 bp = at_breakpoint(a);
704 if (bp)
705 return bp;
706
707 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
708 if (!bp->enabled && atomic_read(&bp->ref_count) == 0) {
709 bp->address = a;
710 bp->instr[1] = bpinstr;
711 store_inst(&bp->instr[1]);
712 return bp;
713 }
714 }
715
716 printf("Sorry, no free breakpoints. Please clear one first.\n");
717 return NULL;
718}
719
720static void insert_bpts(void)
721{
722 int i;
723 struct bpt *bp;
724
725 bp = bpts;
726 for (i = 0; i < NBPTS; ++i, ++bp) {
727 if ((bp->enabled & (BP_TRAP|BP_IABR)) == 0)
728 continue;
729 if (mread(bp->address, &bp->instr[0], 4) != 4) {
730 printf("Couldn't read instruction at %lx, "
731 "disabling breakpoint there\n", bp->address);
732 bp->enabled = 0;
733 continue;
734 }
735 if (IS_MTMSRD(bp->instr[0]) || IS_RFID(bp->instr[0])) {
736 printf("Breakpoint at %lx is on an mtmsrd or rfid "
737 "instruction, disabling it\n", bp->address);
738 bp->enabled = 0;
739 continue;
740 }
741 store_inst(&bp->instr[0]);
742 if (bp->enabled & BP_IABR)
743 continue;
744 if (mwrite(bp->address, &bpinstr, 4) != 4) {
745 printf("Couldn't write instruction at %lx, "
746 "disabling breakpoint there\n", bp->address);
747 bp->enabled &= ~BP_TRAP;
748 continue;
749 }
750 store_inst((void *)bp->address);
751 }
752}
753
754static void insert_cpu_bpts(void)
755{
Michael Neuling9422de32012-12-20 14:06:44 +0000756 struct arch_hw_breakpoint brk;
757
758 if (dabr.enabled) {
759 brk.address = dabr.address;
760 brk.type = (dabr.enabled & HW_BRK_TYPE_DABR) | HW_BRK_TYPE_PRIV_ALL;
761 brk.len = 8;
Paul Gortmaker21f58502014-04-29 15:25:17 -0400762 __set_breakpoint(&brk);
Michael Neuling9422de32012-12-20 14:06:44 +0000763 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 if (iabr && cpu_has_feature(CPU_FTR_IABR))
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000765 mtspr(SPRN_IABR, iabr->address
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 | (iabr->enabled & (BP_IABR|BP_IABR_TE)));
767}
768
769static void remove_bpts(void)
770{
771 int i;
772 struct bpt *bp;
773 unsigned instr;
774
775 bp = bpts;
776 for (i = 0; i < NBPTS; ++i, ++bp) {
777 if ((bp->enabled & (BP_TRAP|BP_IABR)) != BP_TRAP)
778 continue;
779 if (mread(bp->address, &instr, 4) == 4
780 && instr == bpinstr
781 && mwrite(bp->address, &bp->instr, 4) != 4)
782 printf("Couldn't remove breakpoint at %lx\n",
783 bp->address);
784 else
785 store_inst((void *)bp->address);
786 }
787}
788
789static void remove_cpu_bpts(void)
790{
Michael Neuling9422de32012-12-20 14:06:44 +0000791 hw_breakpoint_disable();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 if (cpu_has_feature(CPU_FTR_IABR))
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000793 mtspr(SPRN_IABR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794}
795
796/* Command interpreting routine */
797static char *last_cmd;
798
799static int
800cmds(struct pt_regs *excp)
801{
802 int cmd = 0;
803
804 last_cmd = NULL;
805 xmon_regs = excp;
Olaf Hering26c8af52006-09-08 16:29:21 +0200806
807 if (!xmon_no_auto_backtrace) {
808 xmon_no_auto_backtrace = 1;
809 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
810 }
811
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 for(;;) {
813#ifdef CONFIG_SMP
814 printf("%x:", smp_processor_id());
815#endif /* CONFIG_SMP */
816 printf("mon> ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 flush_input();
818 termch = 0;
819 cmd = skipbl();
820 if( cmd == '\n' ) {
821 if (last_cmd == NULL)
822 continue;
823 take_input(last_cmd);
824 last_cmd = NULL;
825 cmd = inchar();
826 }
827 switch (cmd) {
828 case 'm':
829 cmd = inchar();
830 switch (cmd) {
831 case 'm':
832 case 's':
833 case 'd':
834 memops(cmd);
835 break;
836 case 'l':
837 memlocate();
838 break;
839 case 'z':
840 memzcan();
841 break;
842 case 'i':
David Rientjesb2b755b2011-03-24 15:18:15 -0700843 show_mem(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 break;
845 default:
846 termch = cmd;
847 memex();
848 }
849 break;
850 case 'd':
851 dump();
852 break;
853 case 'l':
854 symbol_lookup();
855 break;
856 case 'r':
857 prregs(excp); /* print regs */
858 break;
859 case 'e':
860 excprint(excp);
861 break;
862 case 'S':
863 super_regs();
864 break;
865 case 't':
866 backtrace(excp);
867 break;
868 case 'f':
869 cacheflush();
870 break;
871 case 's':
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200872 if (do_spu_cmd() == 0)
873 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 if (do_step(excp))
875 return cmd;
876 break;
877 case 'x':
878 case 'X':
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100879 return cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 case EOF:
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100881 printf(" <no input ...>\n");
882 mdelay(2000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 return cmd;
884 case '?':
Ishizaki Kou4d404ed2007-07-18 19:26:40 +1000885 xmon_puts(help_string);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 case 'b':
888 bpt_cmds();
889 break;
890 case 'C':
891 csum();
892 break;
893 case 'c':
894 if (cpu_cmd())
895 return 0;
896 break;
897 case 'z':
898 bootcmds();
899 break;
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000900 case 'p':
901 proccall();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 break;
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000903#ifdef CONFIG_PPC_STD_MMU
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 case 'u':
905 dump_segments();
906 break;
Jimi Xenidis79873e82011-09-29 11:25:10 +0000907#elif defined(CONFIG_4xx)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100908 case 'u':
909 dump_tlb_44x();
910 break;
Jimi Xenidis79873e82011-09-29 11:25:10 +0000911#elif defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +1000912 case 'u':
913 dump_tlb_book3e();
914 break;
915#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 default:
917 printf("Unrecognized command: ");
Michael Ellermane3bc8042012-08-23 22:09:13 +0000918 do {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 if (' ' < cmd && cmd <= '~')
920 putchar(cmd);
921 else
922 printf("\\x%x", cmd);
923 cmd = inchar();
Michael Ellermane3bc8042012-08-23 22:09:13 +0000924 } while (cmd != '\n');
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 printf(" (type ? for help)\n");
926 break;
927 }
928 }
929}
930
Josh Boyercdd39042009-10-05 04:46:05 +0000931#ifdef CONFIG_BOOKE
932static int do_step(struct pt_regs *regs)
933{
934 regs->msr |= MSR_DE;
935 mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
936 return 1;
937}
938#else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939/*
940 * Step a single instruction.
941 * Some instructions we emulate, others we execute with MSR_SE set.
942 */
943static int do_step(struct pt_regs *regs)
944{
945 unsigned int instr;
946 int stepped;
947
948 /* check we are in 64-bit kernel mode, translation enabled */
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000949 if ((regs->msr & (MSR_64BIT|MSR_PR|MSR_IR)) == (MSR_64BIT|MSR_IR)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 if (mread(regs->nip, &instr, 4) == 4) {
951 stepped = emulate_step(regs, instr);
952 if (stepped < 0) {
953 printf("Couldn't single-step %s instruction\n",
954 (IS_RFID(instr)? "rfid": "mtmsrd"));
955 return 0;
956 }
957 if (stepped > 0) {
958 regs->trap = 0xd00 | (regs->trap & 1);
959 printf("stepped to ");
960 xmon_print_symbol(regs->nip, " ", "\n");
961 ppc_inst_dump(regs->nip, 1, 0);
962 return 0;
963 }
964 }
965 }
966 regs->msr |= MSR_SE;
967 return 1;
968}
Josh Boyercdd39042009-10-05 04:46:05 +0000969#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970
971static void bootcmds(void)
972{
973 int cmd;
974
975 cmd = inchar();
976 if (cmd == 'r')
977 ppc_md.restart(NULL);
978 else if (cmd == 'h')
979 ppc_md.halt();
980 else if (cmd == 'p')
981 ppc_md.power_off();
982}
983
984static int cpu_cmd(void)
985{
986#ifdef CONFIG_SMP
Paul Mackerrasfd3bb912013-09-03 20:16:23 +1000987 unsigned long cpu, first_cpu, last_cpu;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 int timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989
990 if (!scanhex(&cpu)) {
991 /* print cpus waiting or in xmon */
992 printf("cpus stopped:");
Paul Mackerrasfd3bb912013-09-03 20:16:23 +1000993 last_cpu = first_cpu = NR_CPUS;
Anton Blanchardbc1d7702012-06-28 19:28:57 +0000994 for_each_possible_cpu(cpu) {
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000995 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Paul Mackerrasfd3bb912013-09-03 20:16:23 +1000996 if (cpu == last_cpu + 1) {
997 last_cpu = cpu;
998 } else {
999 if (last_cpu != first_cpu)
Michael Ellerman736256e2014-05-26 21:02:14 +10001000 printf("-0x%lx", last_cpu);
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001001 last_cpu = first_cpu = cpu;
Michael Ellerman736256e2014-05-26 21:02:14 +10001002 printf(" 0x%lx", cpu);
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001003 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 }
1005 }
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001006 if (last_cpu != first_cpu)
Michael Ellerman736256e2014-05-26 21:02:14 +10001007 printf("-0x%lx", last_cpu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 printf("\n");
1009 return 0;
1010 }
1011 /* try to switch to cpu specified */
KOSAKI Motohiro104699c2011-04-28 05:07:23 +00001012 if (!cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 printf("cpu 0x%x isn't in xmon\n", cpu);
1014 return 0;
1015 }
1016 xmon_taken = 0;
1017 mb();
1018 xmon_owner = cpu;
1019 timeout = 10000000;
1020 while (!xmon_taken) {
1021 if (--timeout == 0) {
1022 if (test_and_set_bit(0, &xmon_taken))
1023 break;
1024 /* take control back */
1025 mb();
1026 xmon_owner = smp_processor_id();
Michael Ellerman736256e2014-05-26 21:02:14 +10001027 printf("cpu 0x%x didn't take control\n", cpu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 return 0;
1029 }
1030 barrier();
1031 }
1032 return 1;
1033#else
1034 return 0;
1035#endif /* CONFIG_SMP */
1036}
1037
1038static unsigned short fcstab[256] = {
1039 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
1040 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
1041 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
1042 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
1043 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
1044 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
1045 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
1046 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
1047 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
1048 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
1049 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
1050 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
1051 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
1052 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
1053 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
1054 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
1055 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
1056 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
1057 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
1058 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
1059 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
1060 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
1061 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
1062 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
1063 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
1064 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
1065 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
1066 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
1067 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
1068 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
1069 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
1070 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
1071};
1072
1073#define FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
1074
1075static void
1076csum(void)
1077{
1078 unsigned int i;
1079 unsigned short fcs;
1080 unsigned char v;
1081
1082 if (!scanhex(&adrs))
1083 return;
1084 if (!scanhex(&ncsum))
1085 return;
1086 fcs = 0xffff;
1087 for (i = 0; i < ncsum; ++i) {
1088 if (mread(adrs+i, &v, 1) == 0) {
Michael Ellerman736256e2014-05-26 21:02:14 +10001089 printf("csum stopped at "REG"\n", adrs+i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 break;
1091 }
1092 fcs = FCS(fcs, v);
1093 }
1094 printf("%x\n", fcs);
1095}
1096
1097/*
1098 * Check if this is a suitable place to put a breakpoint.
1099 */
1100static long check_bp_loc(unsigned long addr)
1101{
1102 unsigned int instr;
1103
1104 addr &= ~3;
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001105 if (!is_kernel_addr(addr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 printf("Breakpoints may only be placed at kernel addresses\n");
1107 return 0;
1108 }
1109 if (!mread(addr, &instr, sizeof(instr))) {
1110 printf("Can't read instruction at address %lx\n", addr);
1111 return 0;
1112 }
1113 if (IS_MTMSRD(instr) || IS_RFID(instr)) {
1114 printf("Breakpoints may not be placed on mtmsrd or rfid "
1115 "instructions\n");
1116 return 0;
1117 }
1118 return 1;
1119}
1120
Michael Ellermane3bc8042012-08-23 22:09:13 +00001121static char *breakpoint_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 "Breakpoint command usage:\n"
1123 "b show breakpoints\n"
1124 "b <addr> [cnt] set breakpoint at given instr addr\n"
1125 "bc clear all breakpoints\n"
1126 "bc <n/addr> clear breakpoint number n or at addr\n"
1127 "bi <addr> [cnt] set hardware instr breakpoint (POWER3/RS64 only)\n"
1128 "bd <addr> [cnt] set hardware data breakpoint\n"
1129 "";
1130
1131static void
1132bpt_cmds(void)
1133{
1134 int cmd;
1135 unsigned long a;
1136 int mode, i;
1137 struct bpt *bp;
1138 const char badaddr[] = "Only kernel addresses are permitted "
1139 "for breakpoints\n";
1140
1141 cmd = inchar();
1142 switch (cmd) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001143#ifndef CONFIG_8xx
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 case 'd': /* bd - hardware data breakpoint */
1145 mode = 7;
1146 cmd = inchar();
1147 if (cmd == 'r')
1148 mode = 5;
1149 else if (cmd == 'w')
1150 mode = 6;
1151 else
1152 termch = cmd;
1153 dabr.address = 0;
1154 dabr.enabled = 0;
1155 if (scanhex(&dabr.address)) {
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001156 if (!is_kernel_addr(dabr.address)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 printf(badaddr);
1158 break;
1159 }
Michael Neuling9422de32012-12-20 14:06:44 +00001160 dabr.address &= ~HW_BRK_TYPE_DABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 dabr.enabled = mode | BP_DABR;
1162 }
1163 break;
1164
1165 case 'i': /* bi - hardware instr breakpoint */
1166 if (!cpu_has_feature(CPU_FTR_IABR)) {
1167 printf("Hardware instruction breakpoint "
1168 "not supported on this cpu\n");
1169 break;
1170 }
1171 if (iabr) {
1172 iabr->enabled &= ~(BP_IABR | BP_IABR_TE);
1173 iabr = NULL;
1174 }
1175 if (!scanhex(&a))
1176 break;
1177 if (!check_bp_loc(a))
1178 break;
1179 bp = new_breakpoint(a);
1180 if (bp != NULL) {
1181 bp->enabled |= BP_IABR | BP_IABR_TE;
1182 iabr = bp;
1183 }
1184 break;
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001185#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186
1187 case 'c':
1188 if (!scanhex(&a)) {
1189 /* clear all breakpoints */
1190 for (i = 0; i < NBPTS; ++i)
1191 bpts[i].enabled = 0;
1192 iabr = NULL;
1193 dabr.enabled = 0;
1194 printf("All breakpoints cleared\n");
1195 break;
1196 }
1197
1198 if (a <= NBPTS && a >= 1) {
1199 /* assume a breakpoint number */
1200 bp = &bpts[a-1]; /* bp nums are 1 based */
1201 } else {
1202 /* assume a breakpoint address */
1203 bp = at_breakpoint(a);
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001204 if (bp == NULL) {
Michael Ellerman736256e2014-05-26 21:02:14 +10001205 printf("No breakpoint at %lx\n", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 break;
1207 }
1208 }
1209
Michael Ellerman736256e2014-05-26 21:02:14 +10001210 printf("Cleared breakpoint %lx (", BP_NUM(bp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 xmon_print_symbol(bp->address, " ", ")\n");
1212 bp->enabled = 0;
1213 break;
1214
1215 default:
1216 termch = cmd;
Michael Ellermane3bc8042012-08-23 22:09:13 +00001217 cmd = skipbl();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 if (cmd == '?') {
1219 printf(breakpoint_help_string);
1220 break;
1221 }
1222 termch = cmd;
1223 if (!scanhex(&a)) {
1224 /* print all breakpoints */
1225 printf(" type address\n");
1226 if (dabr.enabled) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001227 printf(" data "REG" [", dabr.address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 if (dabr.enabled & 1)
1229 printf("r");
1230 if (dabr.enabled & 2)
1231 printf("w");
1232 printf("]\n");
1233 }
1234 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
1235 if (!bp->enabled)
1236 continue;
1237 printf("%2x %s ", BP_NUM(bp),
1238 (bp->enabled & BP_IABR)? "inst": "trap");
1239 xmon_print_symbol(bp->address, " ", "\n");
1240 }
1241 break;
1242 }
1243
1244 if (!check_bp_loc(a))
1245 break;
1246 bp = new_breakpoint(a);
1247 if (bp != NULL)
1248 bp->enabled |= BP_TRAP;
1249 break;
1250 }
1251}
1252
1253/* Very cheap human name for vector lookup. */
1254static
1255const char *getvecname(unsigned long vec)
1256{
1257 char *ret;
1258
1259 switch (vec) {
1260 case 0x100: ret = "(System Reset)"; break;
1261 case 0x200: ret = "(Machine Check)"; break;
1262 case 0x300: ret = "(Data Access)"; break;
1263 case 0x380: ret = "(Data SLB Access)"; break;
1264 case 0x400: ret = "(Instruction Access)"; break;
1265 case 0x480: ret = "(Instruction SLB Access)"; break;
1266 case 0x500: ret = "(Hardware Interrupt)"; break;
1267 case 0x600: ret = "(Alignment)"; break;
1268 case 0x700: ret = "(Program Check)"; break;
1269 case 0x800: ret = "(FPU Unavailable)"; break;
1270 case 0x900: ret = "(Decrementer)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001271 case 0x980: ret = "(Hypervisor Decrementer)"; break;
1272 case 0xa00: ret = "(Doorbell)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 case 0xc00: ret = "(System Call)"; break;
1274 case 0xd00: ret = "(Single Step)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001275 case 0xe40: ret = "(Emulation Assist)"; break;
1276 case 0xe60: ret = "(HMI)"; break;
1277 case 0xe80: ret = "(Hypervisor Doorbell)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 case 0xf00: ret = "(Performance Monitor)"; break;
1279 case 0xf20: ret = "(Altivec Unavailable)"; break;
1280 case 0x1300: ret = "(Instruction Breakpoint)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001281 case 0x1500: ret = "(Denormalisation)"; break;
1282 case 0x1700: ret = "(Altivec Assist)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283 default: ret = "";
1284 }
1285 return ret;
1286}
1287
1288static void get_function_bounds(unsigned long pc, unsigned long *startp,
1289 unsigned long *endp)
1290{
1291 unsigned long size, offset;
1292 const char *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293
1294 *startp = *endp = 0;
1295 if (pc == 0)
1296 return;
1297 if (setjmp(bus_error_jmp) == 0) {
1298 catch_memory_errors = 1;
1299 sync();
Alexey Dobriyanffb45122007-05-08 00:28:41 -07001300 name = kallsyms_lookup(pc, &size, &offset, NULL, tmpstr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 if (name != NULL) {
1302 *startp = pc - offset;
1303 *endp = pc - offset + size;
1304 }
1305 sync();
1306 }
1307 catch_memory_errors = 0;
1308}
1309
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001310#define LRSAVE_OFFSET (STACK_FRAME_LR_SAVE * sizeof(unsigned long))
1311#define MARKER_OFFSET (STACK_FRAME_MARKER * sizeof(unsigned long))
1312
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313static void xmon_show_stack(unsigned long sp, unsigned long lr,
1314 unsigned long pc)
1315{
Michael Ellerman0104cd62012-10-09 04:20:36 +00001316 int max_to_print = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 unsigned long ip;
1318 unsigned long newsp;
1319 unsigned long marker;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 struct pt_regs regs;
1321
Michael Ellerman0104cd62012-10-09 04:20:36 +00001322 while (max_to_print--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 if (sp < PAGE_OFFSET) {
1324 if (sp != 0)
1325 printf("SP (%lx) is in userspace\n", sp);
1326 break;
1327 }
1328
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001329 if (!mread(sp + LRSAVE_OFFSET, &ip, sizeof(unsigned long))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 || !mread(sp, &newsp, sizeof(unsigned long))) {
1331 printf("Couldn't read stack frame at %lx\n", sp);
1332 break;
1333 }
1334
1335 /*
1336 * For the first stack frame, try to work out if
1337 * LR and/or the saved LR value in the bottommost
1338 * stack frame are valid.
1339 */
1340 if ((pc | lr) != 0) {
1341 unsigned long fnstart, fnend;
1342 unsigned long nextip;
1343 int printip = 1;
1344
1345 get_function_bounds(pc, &fnstart, &fnend);
1346 nextip = 0;
1347 if (newsp > sp)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001348 mread(newsp + LRSAVE_OFFSET, &nextip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 sizeof(unsigned long));
1350 if (lr == ip) {
1351 if (lr < PAGE_OFFSET
1352 || (fnstart <= lr && lr < fnend))
1353 printip = 0;
1354 } else if (lr == nextip) {
1355 printip = 0;
1356 } else if (lr >= PAGE_OFFSET
1357 && !(fnstart <= lr && lr < fnend)) {
1358 printf("[link register ] ");
1359 xmon_print_symbol(lr, " ", "\n");
1360 }
1361 if (printip) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001362 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 xmon_print_symbol(ip, " ", " (unreliable)\n");
1364 }
1365 pc = lr = 0;
1366
1367 } else {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001368 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 xmon_print_symbol(ip, " ", "\n");
1370 }
1371
1372 /* Look for "regshere" marker to see if this is
1373 an exception frame. */
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001374 if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long))
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001375 && marker == STACK_FRAME_REGS_MARKER) {
Michael Ellermanc4de3802012-10-09 04:20:35 +00001376 if (mread(sp + STACK_FRAME_OVERHEAD, &regs, sizeof(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377 != sizeof(regs)) {
1378 printf("Couldn't read registers at %lx\n",
Michael Ellermanc4de3802012-10-09 04:20:35 +00001379 sp + STACK_FRAME_OVERHEAD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 break;
1381 }
Michael Ellermane3bc8042012-08-23 22:09:13 +00001382 printf("--- Exception: %lx %s at ", regs.trap,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 getvecname(TRAP(&regs)));
1384 pc = regs.nip;
1385 lr = regs.link;
1386 xmon_print_symbol(pc, " ", "\n");
1387 }
1388
1389 if (newsp == 0)
1390 break;
1391
1392 sp = newsp;
Michael Ellerman0104cd62012-10-09 04:20:36 +00001393 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394}
1395
1396static void backtrace(struct pt_regs *excp)
1397{
1398 unsigned long sp;
1399
1400 if (scanhex(&sp))
1401 xmon_show_stack(sp, 0, 0);
1402 else
1403 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
1404 scannl();
1405}
1406
1407static void print_bug_trap(struct pt_regs *regs)
1408{
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001409#ifdef CONFIG_BUG
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001410 const struct bug_entry *bug;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 unsigned long addr;
1412
1413 if (regs->msr & MSR_PR)
1414 return; /* not in kernel */
1415 addr = regs->nip; /* address of trap instruction */
1416 if (addr < PAGE_OFFSET)
1417 return;
1418 bug = find_bug(regs->nip);
1419 if (bug == NULL)
1420 return;
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001421 if (is_warning_bug(bug))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 return;
1423
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001424#ifdef CONFIG_DEBUG_BUGVERBOSE
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001425 printf("kernel BUG at %s:%u!\n",
1426 bug->file, bug->line);
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001427#else
1428 printf("kernel BUG at %p!\n", (void *)bug->bug_addr);
1429#endif
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001430#endif /* CONFIG_BUG */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431}
1432
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001433static void excprint(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434{
1435 unsigned long trap;
1436
1437#ifdef CONFIG_SMP
1438 printf("cpu 0x%x: ", smp_processor_id());
1439#endif /* CONFIG_SMP */
1440
1441 trap = TRAP(fp);
1442 printf("Vector: %lx %s at [%lx]\n", fp->trap, getvecname(trap), fp);
1443 printf(" pc: ");
1444 xmon_print_symbol(fp->nip, ": ", "\n");
1445
1446 printf(" lr: ", fp->link);
1447 xmon_print_symbol(fp->link, ": ", "\n");
1448
1449 printf(" sp: %lx\n", fp->gpr[1]);
1450 printf(" msr: %lx\n", fp->msr);
1451
Aneesh Kumar K.Vce541522013-04-28 09:37:26 +00001452 if (trap == 0x300 || trap == 0x380 || trap == 0x600 || trap == 0x200) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 printf(" dar: %lx\n", fp->dar);
1454 if (trap != 0x380)
1455 printf(" dsisr: %lx\n", fp->dsisr);
1456 }
1457
1458 printf(" current = 0x%lx\n", current);
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001459#ifdef CONFIG_PPC64
Benjamin Herrenschmidt7230c562012-03-06 18:27:59 +11001460 printf(" paca = 0x%lx\t softe: %d\t irq_happened: 0x%02x\n",
1461 local_paca, local_paca->soft_enabled, local_paca->irq_happened);
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001462#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 if (current) {
1464 printf(" pid = %ld, comm = %s\n",
1465 current->pid, current->comm);
1466 }
1467
1468 if (trap == 0x700)
1469 print_bug_trap(fp);
1470}
1471
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001472static void prregs(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473{
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001474 int n, trap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475 unsigned long base;
1476 struct pt_regs regs;
1477
1478 if (scanhex(&base)) {
1479 if (setjmp(bus_error_jmp) == 0) {
1480 catch_memory_errors = 1;
1481 sync();
1482 regs = *(struct pt_regs *)base;
1483 sync();
1484 __delay(200);
1485 } else {
1486 catch_memory_errors = 0;
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001487 printf("*** Error reading registers from "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488 base);
1489 return;
1490 }
1491 catch_memory_errors = 0;
1492 fp = &regs;
1493 }
1494
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001495#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 if (FULL_REGS(fp)) {
1497 for (n = 0; n < 16; ++n)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001498 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 n, fp->gpr[n], n+16, fp->gpr[n+16]);
1500 } else {
1501 for (n = 0; n < 7; ++n)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001502 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503 n, fp->gpr[n], n+7, fp->gpr[n+7]);
1504 }
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001505#else
1506 for (n = 0; n < 32; ++n) {
1507 printf("R%.2d = %.8x%s", n, fp->gpr[n],
1508 (n & 3) == 3? "\n": " ");
1509 if (n == 12 && !FULL_REGS(fp)) {
1510 printf("\n");
1511 break;
1512 }
1513 }
1514#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515 printf("pc = ");
1516 xmon_print_symbol(fp->nip, " ", "\n");
Paul Mackerras48404f22011-05-01 19:48:20 +00001517 if (TRAP(fp) != 0xc00 && cpu_has_feature(CPU_FTR_CFAR)) {
1518 printf("cfar= ");
1519 xmon_print_symbol(fp->orig_gpr3, " ", "\n");
1520 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 printf("lr = ");
1522 xmon_print_symbol(fp->link, " ", "\n");
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001523 printf("msr = "REG" cr = %.8lx\n", fp->msr, fp->ccr);
1524 printf("ctr = "REG" xer = "REG" trap = %4lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 fp->ctr, fp->xer, fp->trap);
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001526 trap = TRAP(fp);
1527 if (trap == 0x300 || trap == 0x380 || trap == 0x600)
1528 printf("dar = "REG" dsisr = %.8lx\n", fp->dar, fp->dsisr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529}
1530
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001531static void cacheflush(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532{
1533 int cmd;
1534 unsigned long nflush;
1535
1536 cmd = inchar();
1537 if (cmd != 'i')
1538 termch = cmd;
1539 scanhex((void *)&adrs);
1540 if (termch != '\n')
1541 termch = 0;
1542 nflush = 1;
1543 scanhex(&nflush);
1544 nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES;
1545 if (setjmp(bus_error_jmp) == 0) {
1546 catch_memory_errors = 1;
1547 sync();
1548
1549 if (cmd != 'i') {
1550 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1551 cflush((void *) adrs);
1552 } else {
1553 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1554 cinval((void *) adrs);
1555 }
1556 sync();
1557 /* wait a little while to see if we get a machine check */
1558 __delay(200);
1559 }
1560 catch_memory_errors = 0;
1561}
1562
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001563static unsigned long
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564read_spr(int n)
1565{
1566 unsigned int instrs[2];
1567 unsigned long (*code)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568 unsigned long ret = -1UL;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001569#ifdef CONFIG_PPC64
1570 unsigned long opd[3];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 opd[0] = (unsigned long)instrs;
1573 opd[1] = 0;
1574 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001575 code = (unsigned long (*)(void)) opd;
1576#else
1577 code = (unsigned long (*)(void)) instrs;
1578#endif
1579
1580 /* mfspr r3,n; blr */
1581 instrs[0] = 0x7c6002a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1582 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 store_inst(instrs);
1584 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585
1586 if (setjmp(bus_error_jmp) == 0) {
1587 catch_memory_errors = 1;
1588 sync();
1589
1590 ret = code();
1591
1592 sync();
1593 /* wait a little while to see if we get a machine check */
1594 __delay(200);
1595 n = size;
1596 }
1597
1598 return ret;
1599}
1600
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001601static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602write_spr(int n, unsigned long val)
1603{
1604 unsigned int instrs[2];
1605 unsigned long (*code)(unsigned long);
Paul Mackerras548cceb2005-11-11 22:36:34 +11001606#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 unsigned long opd[3];
1608
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 opd[0] = (unsigned long)instrs;
1610 opd[1] = 0;
1611 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001612 code = (unsigned long (*)(unsigned long)) opd;
1613#else
1614 code = (unsigned long (*)(unsigned long)) instrs;
1615#endif
1616
1617 instrs[0] = 0x7c6003a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1618 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619 store_inst(instrs);
1620 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621
1622 if (setjmp(bus_error_jmp) == 0) {
1623 catch_memory_errors = 1;
1624 sync();
1625
1626 code(val);
1627
1628 sync();
1629 /* wait a little while to see if we get a machine check */
1630 __delay(200);
1631 n = size;
1632 }
1633}
1634
1635static unsigned long regno;
1636extern char exc_prolog;
1637extern char dec_exc;
1638
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001639static void super_regs(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640{
1641 int cmd;
1642 unsigned long val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643
1644 cmd = skipbl();
1645 if (cmd == '\n') {
Michael Ellermane3bc8042012-08-23 22:09:13 +00001646 unsigned long sp, toc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647 asm("mr %0,1" : "=r" (sp) :);
1648 asm("mr %0,2" : "=r" (toc) :);
1649
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001650 printf("msr = "REG" sprg0= "REG"\n",
1651 mfmsr(), mfspr(SPRN_SPRG0));
1652 printf("pvr = "REG" sprg1= "REG"\n",
Michael Ellermane3bc8042012-08-23 22:09:13 +00001653 mfspr(SPRN_PVR), mfspr(SPRN_SPRG1));
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001654 printf("dec = "REG" sprg2= "REG"\n",
1655 mfspr(SPRN_DEC), mfspr(SPRN_SPRG2));
1656 printf("sp = "REG" sprg3= "REG"\n", sp, mfspr(SPRN_SPRG3));
1657 printf("toc = "REG" dar = "REG"\n", toc, mfspr(SPRN_DAR));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658
1659 return;
1660 }
1661
1662 scanhex(&regno);
1663 switch (cmd) {
1664 case 'w':
1665 val = read_spr(regno);
1666 scanhex(&val);
1667 write_spr(regno, val);
1668 /* fall through */
1669 case 'r':
1670 printf("spr %lx = %lx\n", regno, read_spr(regno));
1671 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 }
1673 scannl();
1674}
1675
1676/*
1677 * Stuff for reading and writing memory safely
1678 */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001679static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680mread(unsigned long adrs, void *buf, int size)
1681{
1682 volatile int n;
1683 char *p, *q;
1684
1685 n = 0;
1686 if (setjmp(bus_error_jmp) == 0) {
1687 catch_memory_errors = 1;
1688 sync();
1689 p = (char *)adrs;
1690 q = (char *)buf;
1691 switch (size) {
1692 case 2:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001693 *(u16 *)q = *(u16 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 break;
1695 case 4:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001696 *(u32 *)q = *(u32 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 break;
1698 case 8:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001699 *(u64 *)q = *(u64 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 break;
1701 default:
1702 for( ; n < size; ++n) {
1703 *q++ = *p++;
1704 sync();
1705 }
1706 }
1707 sync();
1708 /* wait a little while to see if we get a machine check */
1709 __delay(200);
1710 n = size;
1711 }
1712 catch_memory_errors = 0;
1713 return n;
1714}
1715
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001716static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717mwrite(unsigned long adrs, void *buf, int size)
1718{
1719 volatile int n;
1720 char *p, *q;
1721
1722 n = 0;
1723 if (setjmp(bus_error_jmp) == 0) {
1724 catch_memory_errors = 1;
1725 sync();
1726 p = (char *) adrs;
1727 q = (char *) buf;
1728 switch (size) {
1729 case 2:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001730 *(u16 *)p = *(u16 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 break;
1732 case 4:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001733 *(u32 *)p = *(u32 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 break;
1735 case 8:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001736 *(u64 *)p = *(u64 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737 break;
1738 default:
1739 for ( ; n < size; ++n) {
1740 *p++ = *q++;
1741 sync();
1742 }
1743 }
1744 sync();
1745 /* wait a little while to see if we get a machine check */
1746 __delay(200);
1747 n = size;
1748 } else {
Michael Ellerman736256e2014-05-26 21:02:14 +10001749 printf("*** Error writing address "REG"\n", adrs + n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750 }
1751 catch_memory_errors = 0;
1752 return n;
1753}
1754
1755static int fault_type;
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001756static int fault_except;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757static char *fault_chars[] = { "--", "**", "##" };
1758
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001759static int handle_fault(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760{
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001761 fault_except = TRAP(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762 switch (TRAP(regs)) {
1763 case 0x200:
1764 fault_type = 0;
1765 break;
1766 case 0x300:
1767 case 0x380:
1768 fault_type = 1;
1769 break;
1770 default:
1771 fault_type = 2;
1772 }
1773
1774 longjmp(bus_error_jmp, 1);
1775
1776 return 0;
1777}
1778
1779#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t))
1780
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001781static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782byterev(unsigned char *val, int size)
1783{
1784 int t;
1785
1786 switch (size) {
1787 case 2:
1788 SWAP(val[0], val[1], t);
1789 break;
1790 case 4:
1791 SWAP(val[0], val[3], t);
1792 SWAP(val[1], val[2], t);
1793 break;
1794 case 8: /* is there really any use for this? */
1795 SWAP(val[0], val[7], t);
1796 SWAP(val[1], val[6], t);
1797 SWAP(val[2], val[5], t);
1798 SWAP(val[3], val[4], t);
1799 break;
1800 }
1801}
1802
1803static int brev;
1804static int mnoread;
1805
Michael Ellermane3bc8042012-08-23 22:09:13 +00001806static char *memex_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 "Memory examine command usage:\n"
1808 "m [addr] [flags] examine/change memory\n"
1809 " addr is optional. will start where left off.\n"
1810 " flags may include chars from this set:\n"
1811 " b modify by bytes (default)\n"
1812 " w modify by words (2 byte)\n"
1813 " l modify by longs (4 byte)\n"
1814 " d modify by doubleword (8 byte)\n"
1815 " r toggle reverse byte order mode\n"
1816 " n do not read memory (for i/o spaces)\n"
1817 " . ok to read (default)\n"
1818 "NOTE: flags are saved as defaults\n"
1819 "";
1820
Michael Ellermane3bc8042012-08-23 22:09:13 +00001821static char *memex_subcmd_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 "Memory examine subcommands:\n"
1823 " hexval write this val to current location\n"
1824 " 'string' write chars from string to this location\n"
1825 " ' increment address\n"
1826 " ^ decrement address\n"
1827 " / increment addr by 0x10. //=0x100, ///=0x1000, etc\n"
1828 " \\ decrement addr by 0x10. \\\\=0x100, \\\\\\=0x1000, etc\n"
1829 " ` clear no-read flag\n"
1830 " ; stay at this addr\n"
1831 " v change to byte mode\n"
1832 " w change to word (2 byte) mode\n"
1833 " l change to long (4 byte) mode\n"
1834 " u change to doubleword (8 byte) mode\n"
1835 " m addr change current addr\n"
1836 " n toggle no-read flag\n"
1837 " r toggle byte reverse flag\n"
1838 " < count back up count bytes\n"
1839 " > count skip forward count bytes\n"
1840 " x exit this mode\n"
1841 "";
1842
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001843static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844memex(void)
1845{
1846 int cmd, inc, i, nslash;
1847 unsigned long n;
1848 unsigned char val[16];
1849
1850 scanhex((void *)&adrs);
1851 cmd = skipbl();
1852 if (cmd == '?') {
1853 printf(memex_help_string);
1854 return;
1855 } else {
1856 termch = cmd;
1857 }
1858 last_cmd = "m\n";
1859 while ((cmd = skipbl()) != '\n') {
1860 switch( cmd ){
1861 case 'b': size = 1; break;
1862 case 'w': size = 2; break;
1863 case 'l': size = 4; break;
1864 case 'd': size = 8; break;
1865 case 'r': brev = !brev; break;
1866 case 'n': mnoread = 1; break;
1867 case '.': mnoread = 0; break;
1868 }
1869 }
1870 if( size <= 0 )
1871 size = 1;
1872 else if( size > 8 )
1873 size = 8;
1874 for(;;){
1875 if (!mnoread)
1876 n = mread(adrs, val, size);
Paul Mackerrase1449ed2005-11-10 14:30:20 +11001877 printf(REG"%c", adrs, brev? 'r': ' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878 if (!mnoread) {
1879 if (brev)
1880 byterev(val, size);
1881 putchar(' ');
1882 for (i = 0; i < n; ++i)
1883 printf("%.2x", val[i]);
1884 for (; i < size; ++i)
1885 printf("%s", fault_chars[fault_type]);
1886 }
1887 putchar(' ');
1888 inc = size;
1889 nslash = 0;
1890 for(;;){
1891 if( scanhex(&n) ){
1892 for (i = 0; i < size; ++i)
1893 val[i] = n >> (i * 8);
1894 if (!brev)
1895 byterev(val, size);
1896 mwrite(adrs, val, size);
1897 inc = size;
1898 }
1899 cmd = skipbl();
1900 if (cmd == '\n')
1901 break;
1902 inc = 0;
1903 switch (cmd) {
1904 case '\'':
1905 for(;;){
1906 n = inchar();
1907 if( n == '\\' )
1908 n = bsesc();
1909 else if( n == '\'' )
1910 break;
1911 for (i = 0; i < size; ++i)
1912 val[i] = n >> (i * 8);
1913 if (!brev)
1914 byterev(val, size);
1915 mwrite(adrs, val, size);
1916 adrs += size;
1917 }
1918 adrs -= size;
1919 inc = size;
1920 break;
1921 case ',':
1922 adrs += size;
1923 break;
1924 case '.':
1925 mnoread = 0;
1926 break;
1927 case ';':
1928 break;
1929 case 'x':
1930 case EOF:
1931 scannl();
1932 return;
1933 case 'b':
1934 case 'v':
1935 size = 1;
1936 break;
1937 case 'w':
1938 size = 2;
1939 break;
1940 case 'l':
1941 size = 4;
1942 break;
1943 case 'u':
1944 size = 8;
1945 break;
1946 case '^':
1947 adrs -= size;
1948 break;
1949 break;
1950 case '/':
1951 if (nslash > 0)
1952 adrs -= 1 << nslash;
1953 else
1954 nslash = 0;
1955 nslash += 4;
1956 adrs += 1 << nslash;
1957 break;
1958 case '\\':
1959 if (nslash < 0)
1960 adrs += 1 << -nslash;
1961 else
1962 nslash = 0;
1963 nslash -= 4;
1964 adrs -= 1 << -nslash;
1965 break;
1966 case 'm':
1967 scanhex((void *)&adrs);
1968 break;
1969 case 'n':
1970 mnoread = 1;
1971 break;
1972 case 'r':
1973 brev = !brev;
1974 break;
1975 case '<':
1976 n = size;
1977 scanhex(&n);
1978 adrs -= n;
1979 break;
1980 case '>':
1981 n = size;
1982 scanhex(&n);
1983 adrs += n;
1984 break;
1985 case '?':
1986 printf(memex_subcmd_help_string);
1987 break;
1988 }
1989 }
1990 adrs += inc;
1991 }
1992}
1993
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001994static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995bsesc(void)
1996{
1997 int c;
1998
1999 c = inchar();
2000 switch( c ){
2001 case 'n': c = '\n'; break;
2002 case 'r': c = '\r'; break;
2003 case 'b': c = '\b'; break;
2004 case 't': c = '\t'; break;
2005 }
2006 return c;
2007}
2008
Olaf Hering7e5b5932006-03-08 20:40:28 +01002009static void xmon_rawdump (unsigned long adrs, long ndump)
2010{
2011 long n, m, r, nr;
2012 unsigned char temp[16];
2013
2014 for (n = ndump; n > 0;) {
2015 r = n < 16? n: 16;
2016 nr = mread(adrs, temp, r);
2017 adrs += nr;
2018 for (m = 0; m < r; ++m) {
2019 if (m < nr)
2020 printf("%.2x", temp[m]);
2021 else
2022 printf("%s", fault_chars[fault_type]);
2023 }
2024 n -= r;
2025 if (nr < r)
2026 break;
2027 }
2028 printf("\n");
2029}
2030
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002031#ifdef CONFIG_PPC64
2032static void dump_one_paca(int cpu)
2033{
2034 struct paca_struct *p;
2035
2036 if (setjmp(bus_error_jmp) != 0) {
2037 printf("*** Error dumping paca for cpu 0x%x!\n", cpu);
2038 return;
2039 }
2040
2041 catch_memory_errors = 1;
2042 sync();
2043
2044 p = &paca[cpu];
2045
2046 printf("paca for cpu 0x%x @ %p:\n", cpu, p);
2047
2048 printf(" %-*s = %s\n", 16, "possible", cpu_possible(cpu) ? "yes" : "no");
2049 printf(" %-*s = %s\n", 16, "present", cpu_present(cpu) ? "yes" : "no");
2050 printf(" %-*s = %s\n", 16, "online", cpu_online(cpu) ? "yes" : "no");
2051
2052#define DUMP(paca, name, format) \
2053 printf(" %-*s = %#-*"format"\t(0x%lx)\n", 16, #name, 18, paca->name, \
2054 offsetof(struct paca_struct, name));
2055
2056 DUMP(p, lock_token, "x");
2057 DUMP(p, paca_index, "x");
2058 DUMP(p, kernel_toc, "lx");
2059 DUMP(p, kernelbase, "lx");
2060 DUMP(p, kernel_msr, "lx");
2061#ifdef CONFIG_PPC_STD_MMU_64
2062 DUMP(p, stab_real, "lx");
2063 DUMP(p, stab_addr, "lx");
2064#endif
2065 DUMP(p, emergency_sp, "p");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302066#ifdef CONFIG_PPC_BOOK3S_64
2067 DUMP(p, mc_emergency_sp, "p");
2068 DUMP(p, in_mce, "x");
2069#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002070 DUMP(p, data_offset, "lx");
2071 DUMP(p, hw_cpu_id, "x");
2072 DUMP(p, cpu_start, "x");
2073 DUMP(p, kexec_state, "x");
2074 DUMP(p, __current, "p");
2075 DUMP(p, kstack, "lx");
2076 DUMP(p, stab_rr, "lx");
2077 DUMP(p, saved_r1, "lx");
2078 DUMP(p, trap_save, "x");
2079 DUMP(p, soft_enabled, "x");
2080 DUMP(p, irq_happened, "x");
2081 DUMP(p, io_sync, "x");
2082 DUMP(p, irq_work_pending, "x");
2083 DUMP(p, nap_state_lost, "x");
2084
2085#undef DUMP
2086
2087 catch_memory_errors = 0;
2088 sync();
2089}
2090
2091static void dump_all_pacas(void)
2092{
2093 int cpu;
2094
2095 if (num_possible_cpus() == 0) {
2096 printf("No possible cpus, use 'dp #' to dump individual cpus\n");
2097 return;
2098 }
2099
2100 for_each_possible_cpu(cpu)
2101 dump_one_paca(cpu);
2102}
2103
2104static void dump_pacas(void)
2105{
2106 unsigned long num;
2107 int c;
2108
2109 c = inchar();
2110 if (c == 'a') {
2111 dump_all_pacas();
2112 return;
2113 }
2114
2115 termch = c; /* Put c back, it wasn't 'a' */
2116
2117 if (scanhex(&num))
2118 dump_one_paca(num);
2119 else
2120 dump_one_paca(xmon_owner);
2121}
2122#endif
2123
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
2125 || ('a' <= (c) && (c) <= 'f') \
2126 || ('A' <= (c) && (c) <= 'F'))
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002127static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128dump(void)
2129{
2130 int c;
2131
2132 c = inchar();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002133
2134#ifdef CONFIG_PPC64
2135 if (c == 'p') {
2136 dump_pacas();
2137 return;
2138 }
2139#endif
2140
Linus Torvalds1da177e2005-04-16 15:20:36 -07002141 if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
2142 termch = c;
2143 scanhex((void *)&adrs);
2144 if (termch != '\n')
2145 termch = 0;
2146 if (c == 'i') {
2147 scanhex(&nidump);
2148 if (nidump == 0)
2149 nidump = 16;
2150 else if (nidump > MAX_DUMP)
2151 nidump = MAX_DUMP;
2152 adrs += ppc_inst_dump(adrs, nidump, 1);
2153 last_cmd = "di\n";
Vinay Sridharf312deb2009-05-14 23:13:07 +00002154 } else if (c == 'l') {
2155 dump_log_buf();
Olaf Hering7e5b5932006-03-08 20:40:28 +01002156 } else if (c == 'r') {
2157 scanhex(&ndump);
2158 if (ndump == 0)
2159 ndump = 64;
2160 xmon_rawdump(adrs, ndump);
2161 adrs += ndump;
2162 last_cmd = "dr\n";
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163 } else {
2164 scanhex(&ndump);
2165 if (ndump == 0)
2166 ndump = 64;
2167 else if (ndump > MAX_DUMP)
2168 ndump = MAX_DUMP;
2169 prdump(adrs, ndump);
2170 adrs += ndump;
2171 last_cmd = "d\n";
2172 }
2173}
2174
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002175static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176prdump(unsigned long adrs, long ndump)
2177{
2178 long n, m, c, r, nr;
2179 unsigned char temp[16];
2180
2181 for (n = ndump; n > 0;) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002182 printf(REG, adrs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183 putchar(' ');
2184 r = n < 16? n: 16;
2185 nr = mread(adrs, temp, r);
2186 adrs += nr;
2187 for (m = 0; m < r; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002188 if ((m & (sizeof(long) - 1)) == 0 && m > 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002189 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190 if (m < nr)
2191 printf("%.2x", temp[m]);
2192 else
2193 printf("%s", fault_chars[fault_type]);
2194 }
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002195 for (; m < 16; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002196 if ((m & (sizeof(long) - 1)) == 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002197 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198 printf(" ");
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002199 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200 printf(" |");
2201 for (m = 0; m < r; ++m) {
2202 if (m < nr) {
2203 c = temp[m];
2204 putchar(' ' <= c && c <= '~'? c: '.');
2205 } else
2206 putchar(' ');
2207 }
2208 n -= r;
2209 for (; m < 16; ++m)
2210 putchar(' ');
2211 printf("|\n");
2212 if (nr < r)
2213 break;
2214 }
2215}
2216
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002217typedef int (*instruction_dump_func)(unsigned long inst, unsigned long addr);
2218
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002219static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002220generic_inst_dump(unsigned long adr, long count, int praddr,
2221 instruction_dump_func dump_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222{
2223 int nr, dotted;
2224 unsigned long first_adr;
2225 unsigned long inst, last_inst = 0;
2226 unsigned char val[4];
2227
2228 dotted = 0;
2229 for (first_adr = adr; count > 0; --count, adr += 4) {
2230 nr = mread(adr, val, 4);
2231 if (nr == 0) {
2232 if (praddr) {
2233 const char *x = fault_chars[fault_type];
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002234 printf(REG" %s%s%s%s\n", adr, x, x, x, x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235 }
2236 break;
2237 }
2238 inst = GETWORD(val);
2239 if (adr > first_adr && inst == last_inst) {
2240 if (!dotted) {
2241 printf(" ...\n");
2242 dotted = 1;
2243 }
2244 continue;
2245 }
2246 dotted = 0;
2247 last_inst = inst;
2248 if (praddr)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002249 printf(REG" %.8x", adr, inst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250 printf("\t");
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002251 dump_func(inst, adr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252 printf("\n");
2253 }
2254 return adr - first_adr;
2255}
2256
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002257static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002258ppc_inst_dump(unsigned long adr, long count, int praddr)
2259{
2260 return generic_inst_dump(adr, count, praddr, print_insn_powerpc);
2261}
2262
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263void
2264print_address(unsigned long addr)
2265{
2266 xmon_print_symbol(addr, "\t# ", "");
2267}
2268
Vinay Sridharf312deb2009-05-14 23:13:07 +00002269void
2270dump_log_buf(void)
2271{
Michael Ellermanca5dd392012-08-23 22:09:12 +00002272 struct kmsg_dumper dumper = { .active = 1 };
2273 unsigned char buf[128];
2274 size_t len;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002275
Michael Ellermane3bc8042012-08-23 22:09:13 +00002276 if (setjmp(bus_error_jmp) != 0) {
Michael Ellermanca5dd392012-08-23 22:09:12 +00002277 printf("Error dumping printk buffer!\n");
Michael Ellermane3bc8042012-08-23 22:09:13 +00002278 return;
2279 }
Vinay Sridharf312deb2009-05-14 23:13:07 +00002280
Michael Ellermane3bc8042012-08-23 22:09:13 +00002281 catch_memory_errors = 1;
2282 sync();
Vinay Sridharf312deb2009-05-14 23:13:07 +00002283
Michael Ellermanca5dd392012-08-23 22:09:12 +00002284 kmsg_dump_rewind_nolock(&dumper);
2285 while (kmsg_dump_get_line_nolock(&dumper, false, buf, sizeof(buf), &len)) {
2286 buf[len] = '\0';
2287 printf("%s", buf);
2288 }
Vinay Sridharf312deb2009-05-14 23:13:07 +00002289
Michael Ellermane3bc8042012-08-23 22:09:13 +00002290 sync();
2291 /* wait a little while to see if we get a machine check */
2292 __delay(200);
2293 catch_memory_errors = 0;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002294}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295
2296/*
2297 * Memory operations - move, set, print differences
2298 */
2299static unsigned long mdest; /* destination address */
2300static unsigned long msrc; /* source address */
2301static unsigned long mval; /* byte value to set memory to */
2302static unsigned long mcount; /* # bytes to affect */
2303static unsigned long mdiffs; /* max # differences to print */
2304
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002305static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306memops(int cmd)
2307{
2308 scanhex((void *)&mdest);
2309 if( termch != '\n' )
2310 termch = 0;
2311 scanhex((void *)(cmd == 's'? &mval: &msrc));
2312 if( termch != '\n' )
2313 termch = 0;
2314 scanhex((void *)&mcount);
2315 switch( cmd ){
2316 case 'm':
2317 memmove((void *)mdest, (void *)msrc, mcount);
2318 break;
2319 case 's':
2320 memset((void *)mdest, mval, mcount);
2321 break;
2322 case 'd':
2323 if( termch != '\n' )
2324 termch = 0;
2325 scanhex((void *)&mdiffs);
2326 memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
2327 break;
2328 }
2329}
2330
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002331static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002332memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
2333{
2334 unsigned n, prt;
2335
2336 prt = 0;
2337 for( n = nb; n > 0; --n )
2338 if( *p1++ != *p2++ )
2339 if( ++prt <= maxpr )
2340 printf("%.16x %.2x # %.16x %.2x\n", p1 - 1,
2341 p1[-1], p2 - 1, p2[-1]);
2342 if( prt > maxpr )
2343 printf("Total of %d differences\n", prt);
2344}
2345
2346static unsigned mend;
2347static unsigned mask;
2348
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002349static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350memlocate(void)
2351{
2352 unsigned a, n;
2353 unsigned char val[4];
2354
2355 last_cmd = "ml";
2356 scanhex((void *)&mdest);
2357 if (termch != '\n') {
2358 termch = 0;
2359 scanhex((void *)&mend);
2360 if (termch != '\n') {
2361 termch = 0;
2362 scanhex((void *)&mval);
2363 mask = ~0;
2364 if (termch != '\n') termch = 0;
2365 scanhex((void *)&mask);
2366 }
2367 }
2368 n = 0;
2369 for (a = mdest; a < mend; a += 4) {
2370 if (mread(a, val, 4) == 4
2371 && ((GETWORD(val) ^ mval) & mask) == 0) {
2372 printf("%.16x: %.16x\n", a, GETWORD(val));
2373 if (++n >= 10)
2374 break;
2375 }
2376 }
2377}
2378
2379static unsigned long mskip = 0x1000;
2380static unsigned long mlim = 0xffffffff;
2381
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002382static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383memzcan(void)
2384{
2385 unsigned char v;
2386 unsigned a;
2387 int ok, ook;
2388
2389 scanhex(&mdest);
2390 if (termch != '\n') termch = 0;
2391 scanhex(&mskip);
2392 if (termch != '\n') termch = 0;
2393 scanhex(&mlim);
2394 ook = 0;
2395 for (a = mdest; a < mlim; a += mskip) {
2396 ok = mread(a, &v, 1);
2397 if (ok && !ook) {
2398 printf("%.8x .. ", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399 } else if (!ok && ook)
2400 printf("%.8x\n", a - mskip);
2401 ook = ok;
2402 if (a + mskip < a)
2403 break;
2404 }
2405 if (ook)
2406 printf("%.8x\n", a - mskip);
2407}
2408
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002409static void proccall(void)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002410{
2411 unsigned long args[8];
2412 unsigned long ret;
2413 int i;
2414 typedef unsigned long (*callfunc_t)(unsigned long, unsigned long,
2415 unsigned long, unsigned long, unsigned long,
2416 unsigned long, unsigned long, unsigned long);
2417 callfunc_t func;
2418
2419 if (!scanhex(&adrs))
2420 return;
2421 if (termch != '\n')
2422 termch = 0;
2423 for (i = 0; i < 8; ++i)
2424 args[i] = 0;
2425 for (i = 0; i < 8; ++i) {
2426 if (!scanhex(&args[i]) || termch == '\n')
2427 break;
2428 termch = 0;
2429 }
2430 func = (callfunc_t) adrs;
2431 ret = 0;
2432 if (setjmp(bus_error_jmp) == 0) {
2433 catch_memory_errors = 1;
2434 sync();
2435 ret = func(args[0], args[1], args[2], args[3],
2436 args[4], args[5], args[6], args[7]);
2437 sync();
Michael Ellerman736256e2014-05-26 21:02:14 +10002438 printf("return value is 0x%lx\n", ret);
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002439 } else {
2440 printf("*** %x exception occurred\n", fault_except);
2441 }
2442 catch_memory_errors = 0;
2443}
2444
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445/* Input scanning routines */
2446int
2447skipbl(void)
2448{
2449 int c;
2450
2451 if( termch != 0 ){
2452 c = termch;
2453 termch = 0;
2454 } else
2455 c = inchar();
2456 while( c == ' ' || c == '\t' )
2457 c = inchar();
2458 return c;
2459}
2460
2461#define N_PTREGS 44
2462static char *regnames[N_PTREGS] = {
2463 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
2464 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
2465 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
2466 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002467 "pc", "msr", "or3", "ctr", "lr", "xer", "ccr",
2468#ifdef CONFIG_PPC64
2469 "softe",
2470#else
2471 "mq",
2472#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473 "trap", "dar", "dsisr", "res"
2474};
2475
2476int
2477scanhex(unsigned long *vp)
2478{
2479 int c, d;
2480 unsigned long v;
2481
2482 c = skipbl();
2483 if (c == '%') {
2484 /* parse register name */
2485 char regname[8];
2486 int i;
2487
2488 for (i = 0; i < sizeof(regname) - 1; ++i) {
2489 c = inchar();
2490 if (!isalnum(c)) {
2491 termch = c;
2492 break;
2493 }
2494 regname[i] = c;
2495 }
2496 regname[i] = 0;
2497 for (i = 0; i < N_PTREGS; ++i) {
2498 if (strcmp(regnames[i], regname) == 0) {
2499 if (xmon_regs == NULL) {
2500 printf("regs not available\n");
2501 return 0;
2502 }
2503 *vp = ((unsigned long *)xmon_regs)[i];
2504 return 1;
2505 }
2506 }
2507 printf("invalid register name '%%%s'\n", regname);
2508 return 0;
2509 }
2510
2511 /* skip leading "0x" if any */
2512
2513 if (c == '0') {
2514 c = inchar();
2515 if (c == 'x') {
2516 c = inchar();
2517 } else {
2518 d = hexdigit(c);
2519 if (d == EOF) {
2520 termch = c;
2521 *vp = 0;
2522 return 1;
2523 }
2524 }
2525 } else if (c == '$') {
2526 int i;
2527 for (i=0; i<63; i++) {
2528 c = inchar();
2529 if (isspace(c)) {
2530 termch = c;
2531 break;
2532 }
2533 tmpstr[i] = c;
2534 }
2535 tmpstr[i++] = 0;
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07002536 *vp = 0;
2537 if (setjmp(bus_error_jmp) == 0) {
2538 catch_memory_errors = 1;
2539 sync();
2540 *vp = kallsyms_lookup_name(tmpstr);
2541 sync();
2542 }
2543 catch_memory_errors = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544 if (!(*vp)) {
2545 printf("unknown symbol '%s'\n", tmpstr);
2546 return 0;
2547 }
2548 return 1;
2549 }
2550
2551 d = hexdigit(c);
2552 if (d == EOF) {
2553 termch = c;
2554 return 0;
2555 }
2556 v = 0;
2557 do {
2558 v = (v << 4) + d;
2559 c = inchar();
2560 d = hexdigit(c);
2561 } while (d != EOF);
2562 termch = c;
2563 *vp = v;
2564 return 1;
2565}
2566
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002567static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002568scannl(void)
2569{
2570 int c;
2571
2572 c = termch;
2573 termch = 0;
2574 while( c != '\n' )
2575 c = inchar();
2576}
2577
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002578static int hexdigit(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002579{
2580 if( '0' <= c && c <= '9' )
2581 return c - '0';
2582 if( 'A' <= c && c <= 'F' )
2583 return c - ('A' - 10);
2584 if( 'a' <= c && c <= 'f' )
2585 return c - ('a' - 10);
2586 return EOF;
2587}
2588
2589void
2590getstring(char *s, int size)
2591{
2592 int c;
2593
2594 c = skipbl();
2595 do {
2596 if( size > 1 ){
2597 *s++ = c;
2598 --size;
2599 }
2600 c = inchar();
2601 } while( c != ' ' && c != '\t' && c != '\n' );
2602 termch = c;
2603 *s = 0;
2604}
2605
2606static char line[256];
2607static char *lineptr;
2608
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002609static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610flush_input(void)
2611{
2612 lineptr = NULL;
2613}
2614
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002615static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616inchar(void)
2617{
2618 if (lineptr == NULL || *lineptr == 0) {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002619 if (xmon_gets(line, sizeof(line)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620 lineptr = NULL;
2621 return EOF;
2622 }
2623 lineptr = line;
2624 }
2625 return *lineptr++;
2626}
2627
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002628static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629take_input(char *str)
2630{
2631 lineptr = str;
2632}
2633
2634
2635static void
2636symbol_lookup(void)
2637{
2638 int type = inchar();
2639 unsigned long addr;
2640 static char tmp[64];
2641
2642 switch (type) {
2643 case 'a':
2644 if (scanhex(&addr))
2645 xmon_print_symbol(addr, ": ", "\n");
2646 termch = 0;
2647 break;
2648 case 's':
2649 getstring(tmp, 64);
2650 if (setjmp(bus_error_jmp) == 0) {
2651 catch_memory_errors = 1;
2652 sync();
2653 addr = kallsyms_lookup_name(tmp);
2654 if (addr)
2655 printf("%s: %lx\n", tmp, addr);
2656 else
2657 printf("Symbol '%s' not found.\n", tmp);
2658 sync();
2659 }
2660 catch_memory_errors = 0;
2661 termch = 0;
2662 break;
2663 }
2664}
2665
2666
2667/* Print an address in numeric and symbolic form (if possible) */
2668static void xmon_print_symbol(unsigned long address, const char *mid,
2669 const char *after)
2670{
2671 char *modname;
2672 const char *name = NULL;
2673 unsigned long offset, size;
2674
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002675 printf(REG, address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676 if (setjmp(bus_error_jmp) == 0) {
2677 catch_memory_errors = 1;
2678 sync();
2679 name = kallsyms_lookup(address, &size, &offset, &modname,
2680 tmpstr);
2681 sync();
2682 /* wait a little while to see if we get a machine check */
2683 __delay(200);
2684 }
2685
2686 catch_memory_errors = 0;
2687
2688 if (name) {
2689 printf("%s%s+%#lx/%#lx", mid, name, offset, size);
2690 if (modname)
2691 printf(" [%s]", modname);
2692 }
2693 printf("%s", after);
2694}
2695
Benjamin Herrenschmidt2d27cfd2009-07-23 23:15:59 +00002696#ifdef CONFIG_PPC_BOOK3S_64
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697static void dump_slb(void)
2698{
2699 int i;
will schmidtb3b95952007-12-07 08:22:23 +11002700 unsigned long esid,vsid,valid;
2701 unsigned long llp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702
Michael Ellerman736256e2014-05-26 21:02:14 +10002703 printf("SLB contents of cpu 0x%x\n", smp_processor_id());
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704
Michael Neuling584f8b72007-12-06 17:24:48 +11002705 for (i = 0; i < mmu_slb_size; i++) {
will schmidtb3b95952007-12-07 08:22:23 +11002706 asm volatile("slbmfee %0,%1" : "=r" (esid) : "r" (i));
2707 asm volatile("slbmfev %0,%1" : "=r" (vsid) : "r" (i));
2708 valid = (esid & SLB_ESID_V);
2709 if (valid | esid | vsid) {
2710 printf("%02d %016lx %016lx", i, esid, vsid);
2711 if (valid) {
2712 llp = vsid & SLB_VSID_LLP;
2713 if (vsid & SLB_VSID_B_1T) {
2714 printf(" 1T ESID=%9lx VSID=%13lx LLP:%3lx \n",
2715 GET_ESID_1T(esid),
2716 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT_1T,
2717 llp);
2718 } else {
2719 printf(" 256M ESID=%9lx VSID=%13lx LLP:%3lx \n",
2720 GET_ESID(esid),
2721 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT,
2722 llp);
2723 }
2724 } else
2725 printf("\n");
2726 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727 }
2728}
2729
2730static void dump_stab(void)
2731{
2732 int i;
Benjamin Herrenschmidt7ac21cd2012-03-02 10:10:09 +11002733 unsigned long *tmp = (unsigned long *)local_paca->stab_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734
Michael Ellerman736256e2014-05-26 21:02:14 +10002735 printf("Segment table contents of cpu 0x%x\n", smp_processor_id());
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736
2737 for (i = 0; i < PAGE_SIZE/16; i++) {
2738 unsigned long a, b;
2739
2740 a = *tmp++;
2741 b = *tmp++;
2742
2743 if (a || b) {
2744 printf("%03d %016lx ", i, a);
2745 printf("%016lx\n", b);
2746 }
2747 }
2748}
2749
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002750void dump_segments(void)
2751{
Matt Evans44ae3ab2011-04-06 19:48:50 +00002752 if (mmu_has_feature(MMU_FTR_SLB))
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002753 dump_slb();
2754 else
2755 dump_stab();
2756}
2757#endif
2758
2759#ifdef CONFIG_PPC_STD_MMU_32
2760void dump_segments(void)
2761{
2762 int i;
2763
2764 printf("sr0-15 =");
2765 for (i = 0; i < 16; ++i)
2766 printf(" %x", mfsrin(i));
2767 printf("\n");
2768}
2769#endif
2770
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11002771#ifdef CONFIG_44x
2772static void dump_tlb_44x(void)
2773{
2774 int i;
2775
2776 for (i = 0; i < PPC44x_TLB_SIZE; i++) {
2777 unsigned long w0,w1,w2;
2778 asm volatile("tlbre %0,%1,0" : "=r" (w0) : "r" (i));
2779 asm volatile("tlbre %0,%1,1" : "=r" (w1) : "r" (i));
2780 asm volatile("tlbre %0,%1,2" : "=r" (w2) : "r" (i));
2781 printf("[%02x] %08x %08x %08x ", i, w0, w1, w2);
2782 if (w0 & PPC44x_TLB_VALID) {
2783 printf("V %08x -> %01x%08x %c%c%c%c%c",
2784 w0 & PPC44x_TLB_EPN_MASK,
2785 w1 & PPC44x_TLB_ERPN_MASK,
2786 w1 & PPC44x_TLB_RPN_MASK,
2787 (w2 & PPC44x_TLB_W) ? 'W' : 'w',
2788 (w2 & PPC44x_TLB_I) ? 'I' : 'i',
2789 (w2 & PPC44x_TLB_M) ? 'M' : 'm',
2790 (w2 & PPC44x_TLB_G) ? 'G' : 'g',
2791 (w2 & PPC44x_TLB_E) ? 'E' : 'e');
2792 }
2793 printf("\n");
2794 }
2795}
2796#endif /* CONFIG_44x */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002797
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +10002798#ifdef CONFIG_PPC_BOOK3E
2799static void dump_tlb_book3e(void)
2800{
2801 u32 mmucfg, pidmask, lpidmask;
2802 u64 ramask;
2803 int i, tlb, ntlbs, pidsz, lpidsz, rasz, lrat = 0;
2804 int mmu_version;
2805 static const char *pgsz_names[] = {
2806 " 1K",
2807 " 2K",
2808 " 4K",
2809 " 8K",
2810 " 16K",
2811 " 32K",
2812 " 64K",
2813 "128K",
2814 "256K",
2815 "512K",
2816 " 1M",
2817 " 2M",
2818 " 4M",
2819 " 8M",
2820 " 16M",
2821 " 32M",
2822 " 64M",
2823 "128M",
2824 "256M",
2825 "512M",
2826 " 1G",
2827 " 2G",
2828 " 4G",
2829 " 8G",
2830 " 16G",
2831 " 32G",
2832 " 64G",
2833 "128G",
2834 "256G",
2835 "512G",
2836 " 1T",
2837 " 2T",
2838 };
2839
2840 /* Gather some infos about the MMU */
2841 mmucfg = mfspr(SPRN_MMUCFG);
2842 mmu_version = (mmucfg & 3) + 1;
2843 ntlbs = ((mmucfg >> 2) & 3) + 1;
2844 pidsz = ((mmucfg >> 6) & 0x1f) + 1;
2845 lpidsz = (mmucfg >> 24) & 0xf;
2846 rasz = (mmucfg >> 16) & 0x7f;
2847 if ((mmu_version > 1) && (mmucfg & 0x10000))
2848 lrat = 1;
2849 printf("Book3E MMU MAV=%d.0,%d TLBs,%d-bit PID,%d-bit LPID,%d-bit RA\n",
2850 mmu_version, ntlbs, pidsz, lpidsz, rasz);
2851 pidmask = (1ul << pidsz) - 1;
2852 lpidmask = (1ul << lpidsz) - 1;
2853 ramask = (1ull << rasz) - 1;
2854
2855 for (tlb = 0; tlb < ntlbs; tlb++) {
2856 u32 tlbcfg;
2857 int nent, assoc, new_cc = 1;
2858 printf("TLB %d:\n------\n", tlb);
2859 switch(tlb) {
2860 case 0:
2861 tlbcfg = mfspr(SPRN_TLB0CFG);
2862 break;
2863 case 1:
2864 tlbcfg = mfspr(SPRN_TLB1CFG);
2865 break;
2866 case 2:
2867 tlbcfg = mfspr(SPRN_TLB2CFG);
2868 break;
2869 case 3:
2870 tlbcfg = mfspr(SPRN_TLB3CFG);
2871 break;
2872 default:
2873 printf("Unsupported TLB number !\n");
2874 continue;
2875 }
2876 nent = tlbcfg & 0xfff;
2877 assoc = (tlbcfg >> 24) & 0xff;
2878 for (i = 0; i < nent; i++) {
2879 u32 mas0 = MAS0_TLBSEL(tlb);
2880 u32 mas1 = MAS1_TSIZE(BOOK3E_PAGESZ_4K);
2881 u64 mas2 = 0;
2882 u64 mas7_mas3;
2883 int esel = i, cc = i;
2884
2885 if (assoc != 0) {
2886 cc = i / assoc;
2887 esel = i % assoc;
2888 mas2 = cc * 0x1000;
2889 }
2890
2891 mas0 |= MAS0_ESEL(esel);
2892 mtspr(SPRN_MAS0, mas0);
2893 mtspr(SPRN_MAS1, mas1);
2894 mtspr(SPRN_MAS2, mas2);
2895 asm volatile("tlbre 0,0,0" : : : "memory");
2896 mas1 = mfspr(SPRN_MAS1);
2897 mas2 = mfspr(SPRN_MAS2);
2898 mas7_mas3 = mfspr(SPRN_MAS7_MAS3);
2899 if (assoc && (i % assoc) == 0)
2900 new_cc = 1;
2901 if (!(mas1 & MAS1_VALID))
2902 continue;
2903 if (assoc == 0)
2904 printf("%04x- ", i);
2905 else if (new_cc)
2906 printf("%04x-%c", cc, 'A' + esel);
2907 else
2908 printf(" |%c", 'A' + esel);
2909 new_cc = 0;
2910 printf(" %016llx %04x %s %c%c AS%c",
2911 mas2 & ~0x3ffull,
2912 (mas1 >> 16) & 0x3fff,
2913 pgsz_names[(mas1 >> 7) & 0x1f],
2914 mas1 & MAS1_IND ? 'I' : ' ',
2915 mas1 & MAS1_IPROT ? 'P' : ' ',
2916 mas1 & MAS1_TS ? '1' : '0');
2917 printf(" %c%c%c%c%c%c%c",
2918 mas2 & MAS2_X0 ? 'a' : ' ',
2919 mas2 & MAS2_X1 ? 'v' : ' ',
2920 mas2 & MAS2_W ? 'w' : ' ',
2921 mas2 & MAS2_I ? 'i' : ' ',
2922 mas2 & MAS2_M ? 'm' : ' ',
2923 mas2 & MAS2_G ? 'g' : ' ',
2924 mas2 & MAS2_E ? 'e' : ' ');
2925 printf(" %016llx", mas7_mas3 & ramask & ~0x7ffull);
2926 if (mas1 & MAS1_IND)
2927 printf(" %s\n",
2928 pgsz_names[(mas7_mas3 >> 1) & 0x1f]);
2929 else
2930 printf(" U%c%c%c S%c%c%c\n",
2931 mas7_mas3 & MAS3_UX ? 'x' : ' ',
2932 mas7_mas3 & MAS3_UW ? 'w' : ' ',
2933 mas7_mas3 & MAS3_UR ? 'r' : ' ',
2934 mas7_mas3 & MAS3_SX ? 'x' : ' ',
2935 mas7_mas3 & MAS3_SW ? 'w' : ' ',
2936 mas7_mas3 & MAS3_SR ? 'r' : ' ');
2937 }
2938 }
2939}
2940#endif /* CONFIG_PPC_BOOK3E */
2941
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002942static void xmon_init(int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002943{
Olaf Heringb13cfd172005-08-04 19:26:42 +02002944 if (enable) {
2945 __debugger = xmon;
2946 __debugger_ipi = xmon_ipi;
2947 __debugger_bpt = xmon_bpt;
2948 __debugger_sstep = xmon_sstep;
2949 __debugger_iabr_match = xmon_iabr_match;
Michael Neuling9422de32012-12-20 14:06:44 +00002950 __debugger_break_match = xmon_break_match;
Olaf Heringb13cfd172005-08-04 19:26:42 +02002951 __debugger_fault_handler = xmon_fault_handler;
2952 } else {
2953 __debugger = NULL;
2954 __debugger_ipi = NULL;
2955 __debugger_bpt = NULL;
2956 __debugger_sstep = NULL;
2957 __debugger_iabr_match = NULL;
Michael Neuling9422de32012-12-20 14:06:44 +00002958 __debugger_break_match = NULL;
Olaf Heringb13cfd172005-08-04 19:26:42 +02002959 __debugger_fault_handler = NULL;
2960 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961}
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002962
2963#ifdef CONFIG_MAGIC_SYSRQ
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07002964static void sysrq_handle_xmon(int key)
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002965{
2966 /* ensure xmon is enabled */
2967 xmon_init(1);
David Howells7d12e782006-10-05 14:55:46 +01002968 debugger(get_irq_regs());
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002969}
2970
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07002971static struct sysrq_key_op sysrq_xmon_op = {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002972 .handler = sysrq_handle_xmon,
zhangwei(Jovi)90a102e2013-04-30 15:28:54 -07002973 .help_msg = "xmon(x)",
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002974 .action_msg = "Entering xmon",
2975};
2976
2977static int __init setup_xmon_sysrq(void)
2978{
2979 register_sysrq_key('x', &sysrq_xmon_op);
2980 return 0;
2981}
2982__initcall(setup_xmon_sysrq);
2983#endif /* CONFIG_MAGIC_SYSRQ */
Michael Ellerman476792832006-10-03 14:12:08 +10002984
Olaf Heringf5e6a282007-06-24 16:57:08 +10002985static int __initdata xmon_early, xmon_off;
Michael Ellerman476792832006-10-03 14:12:08 +10002986
2987static int __init early_parse_xmon(char *p)
2988{
2989 if (!p || strncmp(p, "early", 5) == 0) {
2990 /* just "xmon" is equivalent to "xmon=early" */
2991 xmon_init(1);
2992 xmon_early = 1;
2993 } else if (strncmp(p, "on", 2) == 0)
2994 xmon_init(1);
2995 else if (strncmp(p, "off", 3) == 0)
2996 xmon_off = 1;
2997 else if (strncmp(p, "nobt", 4) == 0)
2998 xmon_no_auto_backtrace = 1;
2999 else
3000 return 1;
3001
3002 return 0;
3003}
3004early_param("xmon", early_parse_xmon);
3005
3006void __init xmon_setup(void)
3007{
3008#ifdef CONFIG_XMON_DEFAULT
3009 if (!xmon_off)
3010 xmon_init(1);
3011#endif
3012 if (xmon_early)
3013 debugger(NULL);
3014}
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003015
Arnd Bergmanne0555952006-11-27 19:18:55 +01003016#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003017
3018struct spu_info {
3019 struct spu *spu;
3020 u64 saved_mfc_sr1_RW;
3021 u32 saved_spu_runcntl_RW;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003022 unsigned long dump_addr;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003023 u8 stopped_ok;
3024};
3025
3026#define XMON_NUM_SPUS 16 /* Enough for current hardware */
3027
3028static struct spu_info spu_info[XMON_NUM_SPUS];
3029
3030void xmon_register_spus(struct list_head *list)
3031{
3032 struct spu *spu;
3033
3034 list_for_each_entry(spu, list, full_list) {
3035 if (spu->number >= XMON_NUM_SPUS) {
3036 WARN_ON(1);
3037 continue;
3038 }
3039
3040 spu_info[spu->number].spu = spu;
3041 spu_info[spu->number].stopped_ok = 0;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003042 spu_info[spu->number].dump_addr = (unsigned long)
3043 spu_info[spu->number].spu->local_store;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003044 }
3045}
3046
3047static void stop_spus(void)
3048{
3049 struct spu *spu;
3050 int i;
3051 u64 tmp;
3052
3053 for (i = 0; i < XMON_NUM_SPUS; i++) {
3054 if (!spu_info[i].spu)
3055 continue;
3056
3057 if (setjmp(bus_error_jmp) == 0) {
3058 catch_memory_errors = 1;
3059 sync();
3060
3061 spu = spu_info[i].spu;
3062
3063 spu_info[i].saved_spu_runcntl_RW =
3064 in_be32(&spu->problem->spu_runcntl_RW);
3065
3066 tmp = spu_mfc_sr1_get(spu);
3067 spu_info[i].saved_mfc_sr1_RW = tmp;
3068
3069 tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
3070 spu_mfc_sr1_set(spu, tmp);
3071
3072 sync();
3073 __delay(200);
3074
3075 spu_info[i].stopped_ok = 1;
Michael Ellerman2a144422006-11-23 00:46:40 +01003076
3077 printf("Stopped spu %.2d (was %s)\n", i,
3078 spu_info[i].saved_spu_runcntl_RW ?
3079 "running" : "stopped");
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003080 } else {
3081 catch_memory_errors = 0;
3082 printf("*** Error stopping spu %.2d\n", i);
3083 }
3084 catch_memory_errors = 0;
3085 }
3086}
3087
3088static void restart_spus(void)
3089{
3090 struct spu *spu;
3091 int i;
3092
3093 for (i = 0; i < XMON_NUM_SPUS; i++) {
3094 if (!spu_info[i].spu)
3095 continue;
3096
3097 if (!spu_info[i].stopped_ok) {
3098 printf("*** Error, spu %d was not successfully stopped"
3099 ", not restarting\n", i);
3100 continue;
3101 }
3102
3103 if (setjmp(bus_error_jmp) == 0) {
3104 catch_memory_errors = 1;
3105 sync();
3106
3107 spu = spu_info[i].spu;
3108 spu_mfc_sr1_set(spu, spu_info[i].saved_mfc_sr1_RW);
3109 out_be32(&spu->problem->spu_runcntl_RW,
3110 spu_info[i].saved_spu_runcntl_RW);
3111
3112 sync();
3113 __delay(200);
3114
3115 printf("Restarted spu %.2d\n", i);
3116 } else {
3117 catch_memory_errors = 0;
3118 printf("*** Error restarting spu %.2d\n", i);
3119 }
3120 catch_memory_errors = 0;
3121 }
3122}
3123
Michael Ellermana8984972006-10-24 18:31:28 +02003124#define DUMP_WIDTH 23
Michael Ellerman437a0702006-11-23 00:46:39 +01003125#define DUMP_VALUE(format, field, value) \
Michael Ellermana8984972006-10-24 18:31:28 +02003126do { \
3127 if (setjmp(bus_error_jmp) == 0) { \
3128 catch_memory_errors = 1; \
3129 sync(); \
3130 printf(" %-*s = "format"\n", DUMP_WIDTH, \
Michael Ellerman437a0702006-11-23 00:46:39 +01003131 #field, value); \
Michael Ellermana8984972006-10-24 18:31:28 +02003132 sync(); \
3133 __delay(200); \
3134 } else { \
3135 catch_memory_errors = 0; \
3136 printf(" %-*s = *** Error reading field.\n", \
3137 DUMP_WIDTH, #field); \
3138 } \
3139 catch_memory_errors = 0; \
3140} while (0)
3141
Michael Ellerman437a0702006-11-23 00:46:39 +01003142#define DUMP_FIELD(obj, format, field) \
3143 DUMP_VALUE(format, field, obj->field)
3144
Michael Ellermana8984972006-10-24 18:31:28 +02003145static void dump_spu_fields(struct spu *spu)
3146{
3147 printf("Dumping spu fields at address %p:\n", spu);
3148
3149 DUMP_FIELD(spu, "0x%x", number);
3150 DUMP_FIELD(spu, "%s", name);
Michael Ellermana8984972006-10-24 18:31:28 +02003151 DUMP_FIELD(spu, "0x%lx", local_store_phys);
3152 DUMP_FIELD(spu, "0x%p", local_store);
3153 DUMP_FIELD(spu, "0x%lx", ls_size);
3154 DUMP_FIELD(spu, "0x%x", node);
3155 DUMP_FIELD(spu, "0x%lx", flags);
Michael Ellermana8984972006-10-24 18:31:28 +02003156 DUMP_FIELD(spu, "%d", class_0_pending);
Luke Browningf3d69e02008-04-27 18:41:55 +00003157 DUMP_FIELD(spu, "0x%lx", class_0_dar);
Luke Browningf3d69e02008-04-27 18:41:55 +00003158 DUMP_FIELD(spu, "0x%lx", class_1_dar);
3159 DUMP_FIELD(spu, "0x%lx", class_1_dsisr);
Michael Ellermana8984972006-10-24 18:31:28 +02003160 DUMP_FIELD(spu, "0x%lx", irqs[0]);
3161 DUMP_FIELD(spu, "0x%lx", irqs[1]);
3162 DUMP_FIELD(spu, "0x%lx", irqs[2]);
3163 DUMP_FIELD(spu, "0x%x", slb_replace);
3164 DUMP_FIELD(spu, "%d", pid);
Michael Ellermana8984972006-10-24 18:31:28 +02003165 DUMP_FIELD(spu, "0x%p", mm);
3166 DUMP_FIELD(spu, "0x%p", ctx);
3167 DUMP_FIELD(spu, "0x%p", rq);
3168 DUMP_FIELD(spu, "0x%p", timestamp);
3169 DUMP_FIELD(spu, "0x%lx", problem_phys);
3170 DUMP_FIELD(spu, "0x%p", problem);
Michael Ellerman437a0702006-11-23 00:46:39 +01003171 DUMP_VALUE("0x%x", problem->spu_runcntl_RW,
3172 in_be32(&spu->problem->spu_runcntl_RW));
3173 DUMP_VALUE("0x%x", problem->spu_status_R,
3174 in_be32(&spu->problem->spu_status_R));
3175 DUMP_VALUE("0x%x", problem->spu_npc_RW,
3176 in_be32(&spu->problem->spu_npc_RW));
Michael Ellermana8984972006-10-24 18:31:28 +02003177 DUMP_FIELD(spu, "0x%p", priv2);
Michael Ellermana9852392006-11-23 00:46:50 +01003178 DUMP_FIELD(spu, "0x%p", pdata);
Michael Ellermana8984972006-10-24 18:31:28 +02003179}
3180
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003181int
3182spu_inst_dump(unsigned long adr, long count, int praddr)
3183{
3184 return generic_inst_dump(adr, count, praddr, print_insn_spu);
3185}
3186
3187static void dump_spu_ls(unsigned long num, int subcmd)
Michael Ellerman24a24c82006-11-23 00:46:41 +01003188{
3189 unsigned long offset, addr, ls_addr;
3190
3191 if (setjmp(bus_error_jmp) == 0) {
3192 catch_memory_errors = 1;
3193 sync();
3194 ls_addr = (unsigned long)spu_info[num].spu->local_store;
3195 sync();
3196 __delay(200);
3197 } else {
3198 catch_memory_errors = 0;
3199 printf("*** Error: accessing spu info for spu %d\n", num);
3200 return;
3201 }
3202 catch_memory_errors = 0;
3203
3204 if (scanhex(&offset))
3205 addr = ls_addr + offset;
3206 else
3207 addr = spu_info[num].dump_addr;
3208
3209 if (addr >= ls_addr + LS_SIZE) {
3210 printf("*** Error: address outside of local store\n");
3211 return;
3212 }
3213
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003214 switch (subcmd) {
3215 case 'i':
3216 addr += spu_inst_dump(addr, 16, 1);
3217 last_cmd = "sdi\n";
3218 break;
3219 default:
3220 prdump(addr, 64);
3221 addr += 64;
3222 last_cmd = "sd\n";
3223 break;
3224 }
Michael Ellerman24a24c82006-11-23 00:46:41 +01003225
3226 spu_info[num].dump_addr = addr;
3227}
3228
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003229static int do_spu_cmd(void)
3230{
Michael Ellerman24a24c82006-11-23 00:46:41 +01003231 static unsigned long num = 0;
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003232 int cmd, subcmd = 0;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003233
3234 cmd = inchar();
3235 switch (cmd) {
3236 case 's':
3237 stop_spus();
3238 break;
3239 case 'r':
3240 restart_spus();
3241 break;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003242 case 'd':
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003243 subcmd = inchar();
3244 if (isxdigit(subcmd) || subcmd == '\n')
3245 termch = subcmd;
3246 case 'f':
Michael Ellerman24a24c82006-11-23 00:46:41 +01003247 scanhex(&num);
3248 if (num >= XMON_NUM_SPUS || !spu_info[num].spu) {
Michael Ellermana8984972006-10-24 18:31:28 +02003249 printf("*** Error: invalid spu number\n");
Michael Ellerman24a24c82006-11-23 00:46:41 +01003250 return 0;
3251 }
3252
3253 switch (cmd) {
3254 case 'f':
3255 dump_spu_fields(spu_info[num].spu);
3256 break;
3257 default:
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003258 dump_spu_ls(num, subcmd);
Michael Ellerman24a24c82006-11-23 00:46:41 +01003259 break;
3260 }
3261
Michael Ellermana8984972006-10-24 18:31:28 +02003262 break;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003263 default:
3264 return -1;
3265 }
3266
3267 return 0;
3268}
Arnd Bergmanne0555952006-11-27 19:18:55 +01003269#else /* ! CONFIG_SPU_BASE */
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003270static int do_spu_cmd(void)
3271{
3272 return -1;
3273}
3274#endif