blob: d712b23974ecab2490edfb1fcc618d517042034c [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 Mackerrasf78541dc2005-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 Mackerrasf78541dc2005-10-28 22:53:37 +100047
48#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <asm/hvcall.h>
Paul Mackerrasf78541dc2005-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 Mackerrasf78541dc2005-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 Mackerrasf78541dc2005-10-28 22:53:37 +1000165extern void xmon_enter(void);
166extern void xmon_leave(void);
167
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000168#ifdef CONFIG_PPC64
169#define REG "%.16lx"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000170#else
171#define REG "%.8lx"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000172#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173
174#define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
175
176#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
177 || ('a' <= (c) && (c) <= 'f') \
178 || ('A' <= (c) && (c) <= 'F'))
179#define isalnum(c) (('0' <= (c) && (c) <= '9') \
180 || ('a' <= (c) && (c) <= 'z') \
181 || ('A' <= (c) && (c) <= 'Z'))
182#define isspace(c) (c == ' ' || c == '\t' || c == 10 || c == 13 || c == 0)
183
184static char *help_string = "\
185Commands:\n\
186 b show breakpoints\n\
187 bd set data breakpoint\n\
188 bi set instruction breakpoint\n\
189 bc clear breakpoint\n"
190#ifdef CONFIG_SMP
191 "\
192 c print cpus stopped in xmon\n\
193 c# try to switch to cpu number h (in hex)\n"
194#endif
195 "\
196 C checksum\n\
197 d dump bytes\n\
198 di dump instructions\n\
199 df dump float values\n\
200 dd dump double values\n\
Michael Ellermanddadb6b2012-09-13 23:01:31 +0000201 dl dump the kernel log buffer\n"
202#ifdef CONFIG_PPC64
203 "\
204 dp[#] dump paca for current cpu, or cpu #\n\
205 dpa dump paca for all possible cpus\n"
206#endif
207 "\
Olaf Hering7e5b5932006-03-08 20:40:28 +0100208 dr dump stream of raw bytes\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 e print exception information\n\
210 f flush cache\n\
211 la lookup symbol+offset of specified address\n\
212 ls lookup address of specified symbol\n\
213 m examine/change memory\n\
214 mm move a block of memory\n\
215 ms set a block of memory\n\
216 md compare two blocks of memory\n\
217 ml locate a block of memory\n\
218 mz zero a block of memory\n\
219 mi show information about memory allocation\n\
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000220 p call a procedure\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 r print registers\n\
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200222 s single step\n"
Arnd Bergmanne0555952006-11-27 19:18:55 +0100223#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200224" ss stop execution on all spus\n\
Michael Ellermana8984972006-10-24 18:31:28 +0200225 sr restore execution on stopped spus\n\
Michael Ellerman24a24c82006-11-23 00:46:41 +0100226 sf # dump spu fields for spu # (in hex)\n\
Michael Ellermanc99176a2007-02-26 18:14:06 +0900227 sd # dump spu local store for spu # (in hex)\n\
Michael Ellermanaf89fb82006-11-23 00:46:44 +0100228 sdi # disassemble spu local store for spu # (in hex)\n"
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200229#endif
230" S print special registers\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 t print backtrace\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 x exit monitor and recover\n\
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000233 X exit monitor and dont recover\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000234#if defined(CONFIG_PPC64) && !defined(CONFIG_PPC_BOOK3E)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000235" u dump segment table or SLB\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000236#elif defined(CONFIG_PPC_STD_MMU_32)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000237" u dump segment registers\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000238#elif defined(CONFIG_44x) || defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100239" u dump TLB\n"
240#endif
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000241" ? help\n"
242" zr reboot\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 zh halt\n"
244;
245
246static struct pt_regs *xmon_regs;
247
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000248static inline void sync(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249{
250 asm volatile("sync; isync");
251}
252
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000253static inline void store_inst(void *p)
254{
255 asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p));
256}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000258static inline void cflush(void *p)
259{
260 asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p));
261}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000263static inline void cinval(void *p)
264{
265 asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p));
266}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267
268/*
269 * Disable surveillance (the service processor watchdog function)
270 * while we are in xmon.
271 * XXX we should re-enable it when we leave. :)
272 */
273#define SURVEILLANCE_TOKEN 9000
274
275static inline void disable_surveillance(void)
276{
277#ifdef CONFIG_PPC_PSERIES
278 /* Since this can't be a module, args should end up below 4GB. */
279 static struct rtas_args args;
280
281 /*
282 * At this point we have got all the cpus we can into
283 * xmon, so there is hopefully no other cpu calling RTAS
284 * at the moment, even though we don't take rtas.lock.
285 * If we did try to take rtas.lock there would be a
286 * real possibility of deadlock.
287 */
288 args.token = rtas_token("set-indicator");
289 if (args.token == RTAS_UNKNOWN_SERVICE)
290 return;
291 args.nargs = 3;
292 args.nret = 1;
293 args.rets = &args.args[3];
294 args.args[0] = SURVEILLANCE_TOKEN;
295 args.args[1] = 0;
296 args.args[2] = 0;
297 enter_rtas(__pa(&args));
298#endif /* CONFIG_PPC_PSERIES */
299}
300
301#ifdef CONFIG_SMP
302static int xmon_speaker;
303
304static void get_output_lock(void)
305{
306 int me = smp_processor_id() + 0x100;
307 int last_speaker = 0, prev;
308 long timeout;
309
310 if (xmon_speaker == me)
311 return;
Michael Ellerman730efb62013-12-23 23:46:04 +1100312
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 for (;;) {
Michael Ellerman730efb62013-12-23 23:46:04 +1100314 last_speaker = cmpxchg(&xmon_speaker, 0, me);
315 if (last_speaker == 0)
316 return;
317
Michael Ellerman15075892013-12-23 23:46:05 +1100318 /*
319 * Wait a full second for the lock, we might be on a slow
320 * console, but check every 100us.
321 */
322 timeout = 10000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 while (xmon_speaker == last_speaker) {
Michael Ellerman15075892013-12-23 23:46:05 +1100324 if (--timeout > 0) {
325 udelay(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 continue;
Michael Ellerman15075892013-12-23 23:46:05 +1100327 }
328
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 /* hostile takeover */
330 prev = cmpxchg(&xmon_speaker, last_speaker, me);
331 if (prev == last_speaker)
332 return;
333 break;
334 }
335 }
336}
337
338static void release_output_lock(void)
339{
340 xmon_speaker = 0;
341}
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000342
343int cpus_are_in_xmon(void)
344{
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000345 return !cpumask_empty(&cpus_in_xmon);
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000346}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347#endif
348
Josh Boyerdaf8f402009-09-23 03:51:04 +0000349static inline int unrecoverable_excp(struct pt_regs *regs)
350{
Jimi Xenidis08f6d6a2011-09-29 12:05:28 +0000351#if defined(CONFIG_4xx) || defined(CONFIG_PPC_BOOK3E)
Jimi Xenidis66857b32011-09-23 05:40:46 +0000352 /* We have no MSR_RI bit on 4xx or Book3e, so we simply return false */
Josh Boyerdaf8f402009-09-23 03:51:04 +0000353 return 0;
354#else
355 return ((regs->msr & MSR_RI) == 0);
356#endif
357}
358
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000359static int xmon_core(struct pt_regs *regs, int fromipi)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360{
361 int cmd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 struct bpt *bp;
363 long recurse_jmp[JMP_BUF_LEN];
364 unsigned long offset;
Anton Blanchardf13659e2007-03-21 01:48:34 +1100365 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366#ifdef CONFIG_SMP
367 int cpu;
368 int secondary;
369 unsigned long timeout;
370#endif
371
Anton Blanchardf13659e2007-03-21 01:48:34 +1100372 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373
374 bp = in_breakpoint_table(regs->nip, &offset);
375 if (bp != NULL) {
376 regs->nip = bp->address + offset;
377 atomic_dec(&bp->ref_count);
378 }
379
380 remove_cpu_bpts();
381
382#ifdef CONFIG_SMP
383 cpu = smp_processor_id();
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000384 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 get_output_lock();
386 excprint(regs);
387 printf("cpu 0x%x: Exception %lx %s in xmon, "
388 "returning to main loop\n",
389 cpu, regs->trap, getvecname(TRAP(regs)));
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000390 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 longjmp(xmon_fault_jmp[cpu], 1);
392 }
393
394 if (setjmp(recurse_jmp) != 0) {
395 if (!in_xmon || !xmon_gate) {
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000396 get_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 printf("xmon: WARNING: bad recursive fault "
398 "on cpu 0x%x\n", cpu);
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000399 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 goto waiting;
401 }
402 secondary = !(xmon_taken && cpu == xmon_owner);
403 goto cmdloop;
404 }
405
406 xmon_fault_jmp[cpu] = recurse_jmp;
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000407 cpumask_set_cpu(cpu, &cpus_in_xmon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408
409 bp = NULL;
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000410 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 bp = at_breakpoint(regs->nip);
Josh Boyerdaf8f402009-09-23 03:51:04 +0000412 if (bp || unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 fromipi = 0;
414
415 if (!fromipi) {
416 get_output_lock();
417 excprint(regs);
418 if (bp) {
419 printf("cpu 0x%x stopped at breakpoint 0x%x (",
420 cpu, BP_NUM(bp));
421 xmon_print_symbol(regs->nip, " ", ")\n");
422 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000423 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 printf("WARNING: exception is not recoverable, "
425 "can't continue\n");
426 release_output_lock();
427 }
428
429 waiting:
430 secondary = 1;
431 while (secondary && !xmon_gate) {
432 if (in_xmon == 0) {
433 if (fromipi)
434 goto leave;
435 secondary = test_and_set_bit(0, &in_xmon);
436 }
437 barrier();
438 }
439
440 if (!secondary && !xmon_gate) {
441 /* we are the first cpu to come in */
442 /* interrupt other cpu(s) */
443 int ncpus = num_online_cpus();
444
445 xmon_owner = cpu;
446 mb();
447 if (ncpus > 1) {
Milton Millere0476372011-05-10 19:29:06 +0000448 smp_send_debugger_break();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 /* wait for other cpus to come in */
450 for (timeout = 100000000; timeout != 0; --timeout) {
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000451 if (cpumask_weight(&cpus_in_xmon) >= ncpus)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 break;
453 barrier();
454 }
455 }
456 remove_bpts();
457 disable_surveillance();
458 /* for breakpoint or single step, print the current instr. */
459 if (bp || TRAP(regs) == 0xd00)
460 ppc_inst_dump(regs->nip, 1, 0);
461 printf("enter ? for help\n");
462 mb();
463 xmon_gate = 1;
464 barrier();
465 }
466
467 cmdloop:
468 while (in_xmon) {
469 if (secondary) {
470 if (cpu == xmon_owner) {
471 if (!test_and_set_bit(0, &xmon_taken)) {
472 secondary = 0;
473 continue;
474 }
475 /* missed it */
476 while (cpu == xmon_owner)
477 barrier();
478 }
479 barrier();
480 } else {
481 cmd = cmds(regs);
482 if (cmd != 0) {
483 /* exiting xmon */
484 insert_bpts();
485 xmon_gate = 0;
486 wmb();
487 in_xmon = 0;
488 break;
489 }
490 /* have switched to some other cpu */
491 secondary = 1;
492 }
493 }
494 leave:
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000495 cpumask_clear_cpu(cpu, &cpus_in_xmon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 xmon_fault_jmp[cpu] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497#else
498 /* UP is simple... */
499 if (in_xmon) {
500 printf("Exception %lx %s in xmon, returning to main loop\n",
501 regs->trap, getvecname(TRAP(regs)));
502 longjmp(xmon_fault_jmp[0], 1);
503 }
504 if (setjmp(recurse_jmp) == 0) {
505 xmon_fault_jmp[0] = recurse_jmp;
506 in_xmon = 1;
507
508 excprint(regs);
509 bp = at_breakpoint(regs->nip);
510 if (bp) {
511 printf("Stopped at breakpoint %x (", BP_NUM(bp));
512 xmon_print_symbol(regs->nip, " ", ")\n");
513 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000514 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 printf("WARNING: exception is not recoverable, "
516 "can't continue\n");
517 remove_bpts();
518 disable_surveillance();
519 /* for breakpoint or single step, print the current instr. */
520 if (bp || TRAP(regs) == 0xd00)
521 ppc_inst_dump(regs->nip, 1, 0);
522 printf("enter ? for help\n");
523 }
524
525 cmd = cmds(regs);
526
527 insert_bpts();
528 in_xmon = 0;
529#endif
530
Josh Boyercdd39042009-10-05 04:46:05 +0000531#ifdef CONFIG_BOOKE
532 if (regs->msr & MSR_DE) {
533 bp = at_breakpoint(regs->nip);
534 if (bp != NULL) {
535 regs->nip = (unsigned long) &bp->instr[0];
536 atomic_inc(&bp->ref_count);
537 }
538 }
539#else
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000540 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 bp = at_breakpoint(regs->nip);
542 if (bp != NULL) {
543 int stepped = emulate_step(regs, bp->instr[0]);
544 if (stepped == 0) {
545 regs->nip = (unsigned long) &bp->instr[0];
546 atomic_inc(&bp->ref_count);
547 } else if (stepped < 0) {
548 printf("Couldn't single-step %s instruction\n",
549 (IS_RFID(bp->instr[0])? "rfid": "mtmsrd"));
550 }
551 }
552 }
Josh Boyercdd39042009-10-05 04:46:05 +0000553#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 insert_cpu_bpts();
555
Anton Blanchardf13659e2007-03-21 01:48:34 +1100556 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557
Paul Mackerras0a730ae2006-10-03 21:32:49 +1000558 return cmd != 'X' && cmd != EOF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559}
560
561int xmon(struct pt_regs *excp)
562{
563 struct pt_regs regs;
564
565 if (excp == NULL) {
Anton Vorontsov322b4392008-12-17 10:08:55 +0000566 ppc_save_regs(&regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 excp = &regs;
568 }
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200569
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 return xmon_core(excp, 0);
571}
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000572EXPORT_SYMBOL(xmon);
573
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000574irqreturn_t xmon_irq(int irq, void *d)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000575{
576 unsigned long flags;
577 local_irq_save(flags);
578 printf("Keyboard interrupt\n");
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000579 xmon(get_irq_regs());
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000580 local_irq_restore(flags);
581 return IRQ_HANDLED;
582}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000584static int xmon_bpt(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585{
586 struct bpt *bp;
587 unsigned long offset;
588
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000589 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 return 0;
591
592 /* Are we at the trap at bp->instr[1] for some bp? */
593 bp = in_breakpoint_table(regs->nip, &offset);
594 if (bp != NULL && offset == 4) {
595 regs->nip = bp->address + 4;
596 atomic_dec(&bp->ref_count);
597 return 1;
598 }
599
600 /* Are we at a breakpoint? */
601 bp = at_breakpoint(regs->nip);
602 if (!bp)
603 return 0;
604
605 xmon_core(regs, 0);
606
607 return 1;
608}
609
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000610static int xmon_sstep(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611{
612 if (user_mode(regs))
613 return 0;
614 xmon_core(regs, 0);
615 return 1;
616}
617
Michael Neuling9422de32012-12-20 14:06:44 +0000618static int xmon_break_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000620 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 return 0;
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000622 if (dabr.enabled == 0)
623 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 xmon_core(regs, 0);
625 return 1;
626}
627
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000628static int xmon_iabr_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000630 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 return 0;
Michael Ellerman9f1067c22008-05-08 14:27:16 +1000632 if (iabr == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 return 0;
634 xmon_core(regs, 0);
635 return 1;
636}
637
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000638static int xmon_ipi(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639{
640#ifdef CONFIG_SMP
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000641 if (in_xmon && !cpumask_test_cpu(smp_processor_id(), &cpus_in_xmon))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 xmon_core(regs, 1);
643#endif
644 return 0;
645}
646
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000647static int xmon_fault_handler(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648{
649 struct bpt *bp;
650 unsigned long offset;
651
652 if (in_xmon && catch_memory_errors)
653 handle_fault(regs); /* doesn't return */
654
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000655 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 bp = in_breakpoint_table(regs->nip, &offset);
657 if (bp != NULL) {
658 regs->nip = bp->address + offset;
659 atomic_dec(&bp->ref_count);
660 }
661 }
662
663 return 0;
664}
665
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666static struct bpt *at_breakpoint(unsigned long pc)
667{
668 int i;
669 struct bpt *bp;
670
671 bp = bpts;
672 for (i = 0; i < NBPTS; ++i, ++bp)
673 if (bp->enabled && pc == bp->address)
674 return bp;
675 return NULL;
676}
677
678static struct bpt *in_breakpoint_table(unsigned long nip, unsigned long *offp)
679{
680 unsigned long off;
681
682 off = nip - (unsigned long) bpts;
683 if (off >= sizeof(bpts))
684 return NULL;
685 off %= sizeof(struct bpt);
686 if (off != offsetof(struct bpt, instr[0])
687 && off != offsetof(struct bpt, instr[1]))
688 return NULL;
689 *offp = off - offsetof(struct bpt, instr[0]);
690 return (struct bpt *) (nip - off);
691}
692
693static struct bpt *new_breakpoint(unsigned long a)
694{
695 struct bpt *bp;
696
697 a &= ~3UL;
698 bp = at_breakpoint(a);
699 if (bp)
700 return bp;
701
702 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
703 if (!bp->enabled && atomic_read(&bp->ref_count) == 0) {
704 bp->address = a;
705 bp->instr[1] = bpinstr;
706 store_inst(&bp->instr[1]);
707 return bp;
708 }
709 }
710
711 printf("Sorry, no free breakpoints. Please clear one first.\n");
712 return NULL;
713}
714
715static void insert_bpts(void)
716{
717 int i;
718 struct bpt *bp;
719
720 bp = bpts;
721 for (i = 0; i < NBPTS; ++i, ++bp) {
722 if ((bp->enabled & (BP_TRAP|BP_IABR)) == 0)
723 continue;
724 if (mread(bp->address, &bp->instr[0], 4) != 4) {
725 printf("Couldn't read instruction at %lx, "
726 "disabling breakpoint there\n", bp->address);
727 bp->enabled = 0;
728 continue;
729 }
730 if (IS_MTMSRD(bp->instr[0]) || IS_RFID(bp->instr[0])) {
731 printf("Breakpoint at %lx is on an mtmsrd or rfid "
732 "instruction, disabling it\n", bp->address);
733 bp->enabled = 0;
734 continue;
735 }
736 store_inst(&bp->instr[0]);
737 if (bp->enabled & BP_IABR)
738 continue;
739 if (mwrite(bp->address, &bpinstr, 4) != 4) {
740 printf("Couldn't write instruction at %lx, "
741 "disabling breakpoint there\n", bp->address);
742 bp->enabled &= ~BP_TRAP;
743 continue;
744 }
745 store_inst((void *)bp->address);
746 }
747}
748
749static void insert_cpu_bpts(void)
750{
Michael Neuling9422de32012-12-20 14:06:44 +0000751 struct arch_hw_breakpoint brk;
752
753 if (dabr.enabled) {
754 brk.address = dabr.address;
755 brk.type = (dabr.enabled & HW_BRK_TYPE_DABR) | HW_BRK_TYPE_PRIV_ALL;
756 brk.len = 8;
Michael Neulingb9818c32013-01-10 14:25:34 +0000757 set_breakpoint(&brk);
Michael Neuling9422de32012-12-20 14:06:44 +0000758 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 if (iabr && cpu_has_feature(CPU_FTR_IABR))
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000760 mtspr(SPRN_IABR, iabr->address
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 | (iabr->enabled & (BP_IABR|BP_IABR_TE)));
762}
763
764static void remove_bpts(void)
765{
766 int i;
767 struct bpt *bp;
768 unsigned instr;
769
770 bp = bpts;
771 for (i = 0; i < NBPTS; ++i, ++bp) {
772 if ((bp->enabled & (BP_TRAP|BP_IABR)) != BP_TRAP)
773 continue;
774 if (mread(bp->address, &instr, 4) == 4
775 && instr == bpinstr
776 && mwrite(bp->address, &bp->instr, 4) != 4)
777 printf("Couldn't remove breakpoint at %lx\n",
778 bp->address);
779 else
780 store_inst((void *)bp->address);
781 }
782}
783
784static void remove_cpu_bpts(void)
785{
Michael Neuling9422de32012-12-20 14:06:44 +0000786 hw_breakpoint_disable();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 if (cpu_has_feature(CPU_FTR_IABR))
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000788 mtspr(SPRN_IABR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789}
790
791/* Command interpreting routine */
792static char *last_cmd;
793
794static int
795cmds(struct pt_regs *excp)
796{
797 int cmd = 0;
798
799 last_cmd = NULL;
800 xmon_regs = excp;
Olaf Hering26c8af52006-09-08 16:29:21 +0200801
802 if (!xmon_no_auto_backtrace) {
803 xmon_no_auto_backtrace = 1;
804 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
805 }
806
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 for(;;) {
808#ifdef CONFIG_SMP
809 printf("%x:", smp_processor_id());
810#endif /* CONFIG_SMP */
811 printf("mon> ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 flush_input();
813 termch = 0;
814 cmd = skipbl();
815 if( cmd == '\n' ) {
816 if (last_cmd == NULL)
817 continue;
818 take_input(last_cmd);
819 last_cmd = NULL;
820 cmd = inchar();
821 }
822 switch (cmd) {
823 case 'm':
824 cmd = inchar();
825 switch (cmd) {
826 case 'm':
827 case 's':
828 case 'd':
829 memops(cmd);
830 break;
831 case 'l':
832 memlocate();
833 break;
834 case 'z':
835 memzcan();
836 break;
837 case 'i':
David Rientjesb2b755b2011-03-24 15:18:15 -0700838 show_mem(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 break;
840 default:
841 termch = cmd;
842 memex();
843 }
844 break;
845 case 'd':
846 dump();
847 break;
848 case 'l':
849 symbol_lookup();
850 break;
851 case 'r':
852 prregs(excp); /* print regs */
853 break;
854 case 'e':
855 excprint(excp);
856 break;
857 case 'S':
858 super_regs();
859 break;
860 case 't':
861 backtrace(excp);
862 break;
863 case 'f':
864 cacheflush();
865 break;
866 case 's':
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200867 if (do_spu_cmd() == 0)
868 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 if (do_step(excp))
870 return cmd;
871 break;
872 case 'x':
873 case 'X':
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100874 return cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 case EOF:
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100876 printf(" <no input ...>\n");
877 mdelay(2000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 return cmd;
879 case '?':
Ishizaki Kou4d404ed2007-07-18 19:26:40 +1000880 xmon_puts(help_string);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 case 'b':
883 bpt_cmds();
884 break;
885 case 'C':
886 csum();
887 break;
888 case 'c':
889 if (cpu_cmd())
890 return 0;
891 break;
892 case 'z':
893 bootcmds();
894 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000895 case 'p':
896 proccall();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000898#ifdef CONFIG_PPC_STD_MMU
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 case 'u':
900 dump_segments();
901 break;
Jimi Xenidis79873e82011-09-29 11:25:10 +0000902#elif defined(CONFIG_4xx)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100903 case 'u':
904 dump_tlb_44x();
905 break;
Jimi Xenidis79873e82011-09-29 11:25:10 +0000906#elif defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +1000907 case 'u':
908 dump_tlb_book3e();
909 break;
910#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 default:
912 printf("Unrecognized command: ");
Michael Ellermane3bc8042012-08-23 22:09:13 +0000913 do {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 if (' ' < cmd && cmd <= '~')
915 putchar(cmd);
916 else
917 printf("\\x%x", cmd);
918 cmd = inchar();
Michael Ellermane3bc8042012-08-23 22:09:13 +0000919 } while (cmd != '\n');
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 printf(" (type ? for help)\n");
921 break;
922 }
923 }
924}
925
Josh Boyercdd39042009-10-05 04:46:05 +0000926#ifdef CONFIG_BOOKE
927static int do_step(struct pt_regs *regs)
928{
929 regs->msr |= MSR_DE;
930 mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
931 return 1;
932}
933#else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934/*
935 * Step a single instruction.
936 * Some instructions we emulate, others we execute with MSR_SE set.
937 */
938static int do_step(struct pt_regs *regs)
939{
940 unsigned int instr;
941 int stepped;
942
943 /* check we are in 64-bit kernel mode, translation enabled */
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000944 if ((regs->msr & (MSR_64BIT|MSR_PR|MSR_IR)) == (MSR_64BIT|MSR_IR)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 if (mread(regs->nip, &instr, 4) == 4) {
946 stepped = emulate_step(regs, instr);
947 if (stepped < 0) {
948 printf("Couldn't single-step %s instruction\n",
949 (IS_RFID(instr)? "rfid": "mtmsrd"));
950 return 0;
951 }
952 if (stepped > 0) {
953 regs->trap = 0xd00 | (regs->trap & 1);
954 printf("stepped to ");
955 xmon_print_symbol(regs->nip, " ", "\n");
956 ppc_inst_dump(regs->nip, 1, 0);
957 return 0;
958 }
959 }
960 }
961 regs->msr |= MSR_SE;
962 return 1;
963}
Josh Boyercdd39042009-10-05 04:46:05 +0000964#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965
966static void bootcmds(void)
967{
968 int cmd;
969
970 cmd = inchar();
971 if (cmd == 'r')
972 ppc_md.restart(NULL);
973 else if (cmd == 'h')
974 ppc_md.halt();
975 else if (cmd == 'p')
976 ppc_md.power_off();
977}
978
979static int cpu_cmd(void)
980{
981#ifdef CONFIG_SMP
Paul Mackerrasfd3bb912013-09-03 20:16:23 +1000982 unsigned long cpu, first_cpu, last_cpu;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 int timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984
985 if (!scanhex(&cpu)) {
986 /* print cpus waiting or in xmon */
987 printf("cpus stopped:");
Paul Mackerrasfd3bb912013-09-03 20:16:23 +1000988 last_cpu = first_cpu = NR_CPUS;
Anton Blanchardbc1d7702012-06-28 19:28:57 +0000989 for_each_possible_cpu(cpu) {
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000990 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Paul Mackerrasfd3bb912013-09-03 20:16:23 +1000991 if (cpu == last_cpu + 1) {
992 last_cpu = cpu;
993 } else {
994 if (last_cpu != first_cpu)
995 printf("-%lx", last_cpu);
996 last_cpu = first_cpu = cpu;
997 printf(" %lx", cpu);
998 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 }
1000 }
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001001 if (last_cpu != first_cpu)
1002 printf("-%lx", last_cpu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 printf("\n");
1004 return 0;
1005 }
1006 /* try to switch to cpu specified */
KOSAKI Motohiro104699c2011-04-28 05:07:23 +00001007 if (!cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 printf("cpu 0x%x isn't in xmon\n", cpu);
1009 return 0;
1010 }
1011 xmon_taken = 0;
1012 mb();
1013 xmon_owner = cpu;
1014 timeout = 10000000;
1015 while (!xmon_taken) {
1016 if (--timeout == 0) {
1017 if (test_and_set_bit(0, &xmon_taken))
1018 break;
1019 /* take control back */
1020 mb();
1021 xmon_owner = smp_processor_id();
1022 printf("cpu %u didn't take control\n", cpu);
1023 return 0;
1024 }
1025 barrier();
1026 }
1027 return 1;
1028#else
1029 return 0;
1030#endif /* CONFIG_SMP */
1031}
1032
1033static unsigned short fcstab[256] = {
1034 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
1035 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
1036 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
1037 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
1038 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
1039 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
1040 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
1041 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
1042 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
1043 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
1044 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
1045 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
1046 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
1047 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
1048 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
1049 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
1050 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
1051 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
1052 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
1053 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
1054 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
1055 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
1056 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
1057 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
1058 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
1059 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
1060 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
1061 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
1062 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
1063 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
1064 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
1065 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
1066};
1067
1068#define FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
1069
1070static void
1071csum(void)
1072{
1073 unsigned int i;
1074 unsigned short fcs;
1075 unsigned char v;
1076
1077 if (!scanhex(&adrs))
1078 return;
1079 if (!scanhex(&ncsum))
1080 return;
1081 fcs = 0xffff;
1082 for (i = 0; i < ncsum; ++i) {
1083 if (mread(adrs+i, &v, 1) == 0) {
1084 printf("csum stopped at %x\n", adrs+i);
1085 break;
1086 }
1087 fcs = FCS(fcs, v);
1088 }
1089 printf("%x\n", fcs);
1090}
1091
1092/*
1093 * Check if this is a suitable place to put a breakpoint.
1094 */
1095static long check_bp_loc(unsigned long addr)
1096{
1097 unsigned int instr;
1098
1099 addr &= ~3;
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001100 if (!is_kernel_addr(addr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 printf("Breakpoints may only be placed at kernel addresses\n");
1102 return 0;
1103 }
1104 if (!mread(addr, &instr, sizeof(instr))) {
1105 printf("Can't read instruction at address %lx\n", addr);
1106 return 0;
1107 }
1108 if (IS_MTMSRD(instr) || IS_RFID(instr)) {
1109 printf("Breakpoints may not be placed on mtmsrd or rfid "
1110 "instructions\n");
1111 return 0;
1112 }
1113 return 1;
1114}
1115
Michael Ellermane3bc8042012-08-23 22:09:13 +00001116static char *breakpoint_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 "Breakpoint command usage:\n"
1118 "b show breakpoints\n"
1119 "b <addr> [cnt] set breakpoint at given instr addr\n"
1120 "bc clear all breakpoints\n"
1121 "bc <n/addr> clear breakpoint number n or at addr\n"
1122 "bi <addr> [cnt] set hardware instr breakpoint (POWER3/RS64 only)\n"
1123 "bd <addr> [cnt] set hardware data breakpoint\n"
1124 "";
1125
1126static void
1127bpt_cmds(void)
1128{
1129 int cmd;
1130 unsigned long a;
1131 int mode, i;
1132 struct bpt *bp;
1133 const char badaddr[] = "Only kernel addresses are permitted "
1134 "for breakpoints\n";
1135
1136 cmd = inchar();
1137 switch (cmd) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001138#ifndef CONFIG_8xx
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 case 'd': /* bd - hardware data breakpoint */
1140 mode = 7;
1141 cmd = inchar();
1142 if (cmd == 'r')
1143 mode = 5;
1144 else if (cmd == 'w')
1145 mode = 6;
1146 else
1147 termch = cmd;
1148 dabr.address = 0;
1149 dabr.enabled = 0;
1150 if (scanhex(&dabr.address)) {
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001151 if (!is_kernel_addr(dabr.address)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 printf(badaddr);
1153 break;
1154 }
Michael Neuling9422de32012-12-20 14:06:44 +00001155 dabr.address &= ~HW_BRK_TYPE_DABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 dabr.enabled = mode | BP_DABR;
1157 }
1158 break;
1159
1160 case 'i': /* bi - hardware instr breakpoint */
1161 if (!cpu_has_feature(CPU_FTR_IABR)) {
1162 printf("Hardware instruction breakpoint "
1163 "not supported on this cpu\n");
1164 break;
1165 }
1166 if (iabr) {
1167 iabr->enabled &= ~(BP_IABR | BP_IABR_TE);
1168 iabr = NULL;
1169 }
1170 if (!scanhex(&a))
1171 break;
1172 if (!check_bp_loc(a))
1173 break;
1174 bp = new_breakpoint(a);
1175 if (bp != NULL) {
1176 bp->enabled |= BP_IABR | BP_IABR_TE;
1177 iabr = bp;
1178 }
1179 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001180#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181
1182 case 'c':
1183 if (!scanhex(&a)) {
1184 /* clear all breakpoints */
1185 for (i = 0; i < NBPTS; ++i)
1186 bpts[i].enabled = 0;
1187 iabr = NULL;
1188 dabr.enabled = 0;
1189 printf("All breakpoints cleared\n");
1190 break;
1191 }
1192
1193 if (a <= NBPTS && a >= 1) {
1194 /* assume a breakpoint number */
1195 bp = &bpts[a-1]; /* bp nums are 1 based */
1196 } else {
1197 /* assume a breakpoint address */
1198 bp = at_breakpoint(a);
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001199 if (bp == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 printf("No breakpoint at %x\n", a);
1201 break;
1202 }
1203 }
1204
1205 printf("Cleared breakpoint %x (", BP_NUM(bp));
1206 xmon_print_symbol(bp->address, " ", ")\n");
1207 bp->enabled = 0;
1208 break;
1209
1210 default:
1211 termch = cmd;
Michael Ellermane3bc8042012-08-23 22:09:13 +00001212 cmd = skipbl();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 if (cmd == '?') {
1214 printf(breakpoint_help_string);
1215 break;
1216 }
1217 termch = cmd;
1218 if (!scanhex(&a)) {
1219 /* print all breakpoints */
1220 printf(" type address\n");
1221 if (dabr.enabled) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001222 printf(" data "REG" [", dabr.address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 if (dabr.enabled & 1)
1224 printf("r");
1225 if (dabr.enabled & 2)
1226 printf("w");
1227 printf("]\n");
1228 }
1229 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
1230 if (!bp->enabled)
1231 continue;
1232 printf("%2x %s ", BP_NUM(bp),
1233 (bp->enabled & BP_IABR)? "inst": "trap");
1234 xmon_print_symbol(bp->address, " ", "\n");
1235 }
1236 break;
1237 }
1238
1239 if (!check_bp_loc(a))
1240 break;
1241 bp = new_breakpoint(a);
1242 if (bp != NULL)
1243 bp->enabled |= BP_TRAP;
1244 break;
1245 }
1246}
1247
1248/* Very cheap human name for vector lookup. */
1249static
1250const char *getvecname(unsigned long vec)
1251{
1252 char *ret;
1253
1254 switch (vec) {
1255 case 0x100: ret = "(System Reset)"; break;
1256 case 0x200: ret = "(Machine Check)"; break;
1257 case 0x300: ret = "(Data Access)"; break;
1258 case 0x380: ret = "(Data SLB Access)"; break;
1259 case 0x400: ret = "(Instruction Access)"; break;
1260 case 0x480: ret = "(Instruction SLB Access)"; break;
1261 case 0x500: ret = "(Hardware Interrupt)"; break;
1262 case 0x600: ret = "(Alignment)"; break;
1263 case 0x700: ret = "(Program Check)"; break;
1264 case 0x800: ret = "(FPU Unavailable)"; break;
1265 case 0x900: ret = "(Decrementer)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001266 case 0x980: ret = "(Hypervisor Decrementer)"; break;
1267 case 0xa00: ret = "(Doorbell)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 case 0xc00: ret = "(System Call)"; break;
1269 case 0xd00: ret = "(Single Step)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001270 case 0xe40: ret = "(Emulation Assist)"; break;
1271 case 0xe60: ret = "(HMI)"; break;
1272 case 0xe80: ret = "(Hypervisor Doorbell)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 case 0xf00: ret = "(Performance Monitor)"; break;
1274 case 0xf20: ret = "(Altivec Unavailable)"; break;
1275 case 0x1300: ret = "(Instruction Breakpoint)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001276 case 0x1500: ret = "(Denormalisation)"; break;
1277 case 0x1700: ret = "(Altivec Assist)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 default: ret = "";
1279 }
1280 return ret;
1281}
1282
1283static void get_function_bounds(unsigned long pc, unsigned long *startp,
1284 unsigned long *endp)
1285{
1286 unsigned long size, offset;
1287 const char *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288
1289 *startp = *endp = 0;
1290 if (pc == 0)
1291 return;
1292 if (setjmp(bus_error_jmp) == 0) {
1293 catch_memory_errors = 1;
1294 sync();
Alexey Dobriyanffb45122007-05-08 00:28:41 -07001295 name = kallsyms_lookup(pc, &size, &offset, NULL, tmpstr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 if (name != NULL) {
1297 *startp = pc - offset;
1298 *endp = pc - offset + size;
1299 }
1300 sync();
1301 }
1302 catch_memory_errors = 0;
1303}
1304
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001305#define LRSAVE_OFFSET (STACK_FRAME_LR_SAVE * sizeof(unsigned long))
1306#define MARKER_OFFSET (STACK_FRAME_MARKER * sizeof(unsigned long))
1307
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308static void xmon_show_stack(unsigned long sp, unsigned long lr,
1309 unsigned long pc)
1310{
Michael Ellerman0104cd62012-10-09 04:20:36 +00001311 int max_to_print = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 unsigned long ip;
1313 unsigned long newsp;
1314 unsigned long marker;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 struct pt_regs regs;
1316
Michael Ellerman0104cd62012-10-09 04:20:36 +00001317 while (max_to_print--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 if (sp < PAGE_OFFSET) {
1319 if (sp != 0)
1320 printf("SP (%lx) is in userspace\n", sp);
1321 break;
1322 }
1323
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001324 if (!mread(sp + LRSAVE_OFFSET, &ip, sizeof(unsigned long))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 || !mread(sp, &newsp, sizeof(unsigned long))) {
1326 printf("Couldn't read stack frame at %lx\n", sp);
1327 break;
1328 }
1329
1330 /*
1331 * For the first stack frame, try to work out if
1332 * LR and/or the saved LR value in the bottommost
1333 * stack frame are valid.
1334 */
1335 if ((pc | lr) != 0) {
1336 unsigned long fnstart, fnend;
1337 unsigned long nextip;
1338 int printip = 1;
1339
1340 get_function_bounds(pc, &fnstart, &fnend);
1341 nextip = 0;
1342 if (newsp > sp)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001343 mread(newsp + LRSAVE_OFFSET, &nextip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 sizeof(unsigned long));
1345 if (lr == ip) {
1346 if (lr < PAGE_OFFSET
1347 || (fnstart <= lr && lr < fnend))
1348 printip = 0;
1349 } else if (lr == nextip) {
1350 printip = 0;
1351 } else if (lr >= PAGE_OFFSET
1352 && !(fnstart <= lr && lr < fnend)) {
1353 printf("[link register ] ");
1354 xmon_print_symbol(lr, " ", "\n");
1355 }
1356 if (printip) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001357 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 xmon_print_symbol(ip, " ", " (unreliable)\n");
1359 }
1360 pc = lr = 0;
1361
1362 } else {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001363 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 xmon_print_symbol(ip, " ", "\n");
1365 }
1366
1367 /* Look for "regshere" marker to see if this is
1368 an exception frame. */
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001369 if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long))
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001370 && marker == STACK_FRAME_REGS_MARKER) {
Michael Ellermanc4de3802012-10-09 04:20:35 +00001371 if (mread(sp + STACK_FRAME_OVERHEAD, &regs, sizeof(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 != sizeof(regs)) {
1373 printf("Couldn't read registers at %lx\n",
Michael Ellermanc4de3802012-10-09 04:20:35 +00001374 sp + STACK_FRAME_OVERHEAD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 break;
1376 }
Michael Ellermane3bc8042012-08-23 22:09:13 +00001377 printf("--- Exception: %lx %s at ", regs.trap,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 getvecname(TRAP(&regs)));
1379 pc = regs.nip;
1380 lr = regs.link;
1381 xmon_print_symbol(pc, " ", "\n");
1382 }
1383
1384 if (newsp == 0)
1385 break;
1386
1387 sp = newsp;
Michael Ellerman0104cd62012-10-09 04:20:36 +00001388 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389}
1390
1391static void backtrace(struct pt_regs *excp)
1392{
1393 unsigned long sp;
1394
1395 if (scanhex(&sp))
1396 xmon_show_stack(sp, 0, 0);
1397 else
1398 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
1399 scannl();
1400}
1401
1402static void print_bug_trap(struct pt_regs *regs)
1403{
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001404#ifdef CONFIG_BUG
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001405 const struct bug_entry *bug;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 unsigned long addr;
1407
1408 if (regs->msr & MSR_PR)
1409 return; /* not in kernel */
1410 addr = regs->nip; /* address of trap instruction */
1411 if (addr < PAGE_OFFSET)
1412 return;
1413 bug = find_bug(regs->nip);
1414 if (bug == NULL)
1415 return;
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001416 if (is_warning_bug(bug))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417 return;
1418
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001419#ifdef CONFIG_DEBUG_BUGVERBOSE
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001420 printf("kernel BUG at %s:%u!\n",
1421 bug->file, bug->line);
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001422#else
1423 printf("kernel BUG at %p!\n", (void *)bug->bug_addr);
1424#endif
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001425#endif /* CONFIG_BUG */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426}
1427
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001428static void excprint(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429{
1430 unsigned long trap;
1431
1432#ifdef CONFIG_SMP
1433 printf("cpu 0x%x: ", smp_processor_id());
1434#endif /* CONFIG_SMP */
1435
1436 trap = TRAP(fp);
1437 printf("Vector: %lx %s at [%lx]\n", fp->trap, getvecname(trap), fp);
1438 printf(" pc: ");
1439 xmon_print_symbol(fp->nip, ": ", "\n");
1440
1441 printf(" lr: ", fp->link);
1442 xmon_print_symbol(fp->link, ": ", "\n");
1443
1444 printf(" sp: %lx\n", fp->gpr[1]);
1445 printf(" msr: %lx\n", fp->msr);
1446
Aneesh Kumar K.Vce541522013-04-28 09:37:26 +00001447 if (trap == 0x300 || trap == 0x380 || trap == 0x600 || trap == 0x200) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 printf(" dar: %lx\n", fp->dar);
1449 if (trap != 0x380)
1450 printf(" dsisr: %lx\n", fp->dsisr);
1451 }
1452
1453 printf(" current = 0x%lx\n", current);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001454#ifdef CONFIG_PPC64
Benjamin Herrenschmidt7230c562012-03-06 18:27:59 +11001455 printf(" paca = 0x%lx\t softe: %d\t irq_happened: 0x%02x\n",
1456 local_paca, local_paca->soft_enabled, local_paca->irq_happened);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001457#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 if (current) {
1459 printf(" pid = %ld, comm = %s\n",
1460 current->pid, current->comm);
1461 }
1462
1463 if (trap == 0x700)
1464 print_bug_trap(fp);
1465}
1466
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001467static void prregs(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001469 int n, trap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470 unsigned long base;
1471 struct pt_regs regs;
1472
1473 if (scanhex(&base)) {
1474 if (setjmp(bus_error_jmp) == 0) {
1475 catch_memory_errors = 1;
1476 sync();
1477 regs = *(struct pt_regs *)base;
1478 sync();
1479 __delay(200);
1480 } else {
1481 catch_memory_errors = 0;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001482 printf("*** Error reading registers from "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 base);
1484 return;
1485 }
1486 catch_memory_errors = 0;
1487 fp = &regs;
1488 }
1489
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001490#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 if (FULL_REGS(fp)) {
1492 for (n = 0; n < 16; ++n)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001493 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 n, fp->gpr[n], n+16, fp->gpr[n+16]);
1495 } else {
1496 for (n = 0; n < 7; ++n)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001497 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 n, fp->gpr[n], n+7, fp->gpr[n+7]);
1499 }
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001500#else
1501 for (n = 0; n < 32; ++n) {
1502 printf("R%.2d = %.8x%s", n, fp->gpr[n],
1503 (n & 3) == 3? "\n": " ");
1504 if (n == 12 && !FULL_REGS(fp)) {
1505 printf("\n");
1506 break;
1507 }
1508 }
1509#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510 printf("pc = ");
1511 xmon_print_symbol(fp->nip, " ", "\n");
Paul Mackerras48404f22011-05-01 19:48:20 +00001512 if (TRAP(fp) != 0xc00 && cpu_has_feature(CPU_FTR_CFAR)) {
1513 printf("cfar= ");
1514 xmon_print_symbol(fp->orig_gpr3, " ", "\n");
1515 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 printf("lr = ");
1517 xmon_print_symbol(fp->link, " ", "\n");
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001518 printf("msr = "REG" cr = %.8lx\n", fp->msr, fp->ccr);
1519 printf("ctr = "REG" xer = "REG" trap = %4lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520 fp->ctr, fp->xer, fp->trap);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001521 trap = TRAP(fp);
1522 if (trap == 0x300 || trap == 0x380 || trap == 0x600)
1523 printf("dar = "REG" dsisr = %.8lx\n", fp->dar, fp->dsisr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524}
1525
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001526static void cacheflush(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527{
1528 int cmd;
1529 unsigned long nflush;
1530
1531 cmd = inchar();
1532 if (cmd != 'i')
1533 termch = cmd;
1534 scanhex((void *)&adrs);
1535 if (termch != '\n')
1536 termch = 0;
1537 nflush = 1;
1538 scanhex(&nflush);
1539 nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES;
1540 if (setjmp(bus_error_jmp) == 0) {
1541 catch_memory_errors = 1;
1542 sync();
1543
1544 if (cmd != 'i') {
1545 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1546 cflush((void *) adrs);
1547 } else {
1548 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1549 cinval((void *) adrs);
1550 }
1551 sync();
1552 /* wait a little while to see if we get a machine check */
1553 __delay(200);
1554 }
1555 catch_memory_errors = 0;
1556}
1557
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001558static unsigned long
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559read_spr(int n)
1560{
1561 unsigned int instrs[2];
1562 unsigned long (*code)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 unsigned long ret = -1UL;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001564#ifdef CONFIG_PPC64
1565 unsigned long opd[3];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567 opd[0] = (unsigned long)instrs;
1568 opd[1] = 0;
1569 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001570 code = (unsigned long (*)(void)) opd;
1571#else
1572 code = (unsigned long (*)(void)) instrs;
1573#endif
1574
1575 /* mfspr r3,n; blr */
1576 instrs[0] = 0x7c6002a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1577 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578 store_inst(instrs);
1579 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580
1581 if (setjmp(bus_error_jmp) == 0) {
1582 catch_memory_errors = 1;
1583 sync();
1584
1585 ret = code();
1586
1587 sync();
1588 /* wait a little while to see if we get a machine check */
1589 __delay(200);
1590 n = size;
1591 }
1592
1593 return ret;
1594}
1595
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001596static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597write_spr(int n, unsigned long val)
1598{
1599 unsigned int instrs[2];
1600 unsigned long (*code)(unsigned long);
Paul Mackerras548cceb2005-11-11 22:36:34 +11001601#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 unsigned long opd[3];
1603
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604 opd[0] = (unsigned long)instrs;
1605 opd[1] = 0;
1606 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001607 code = (unsigned long (*)(unsigned long)) opd;
1608#else
1609 code = (unsigned long (*)(unsigned long)) instrs;
1610#endif
1611
1612 instrs[0] = 0x7c6003a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1613 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614 store_inst(instrs);
1615 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616
1617 if (setjmp(bus_error_jmp) == 0) {
1618 catch_memory_errors = 1;
1619 sync();
1620
1621 code(val);
1622
1623 sync();
1624 /* wait a little while to see if we get a machine check */
1625 __delay(200);
1626 n = size;
1627 }
1628}
1629
1630static unsigned long regno;
1631extern char exc_prolog;
1632extern char dec_exc;
1633
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001634static void super_regs(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635{
1636 int cmd;
1637 unsigned long val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638
1639 cmd = skipbl();
1640 if (cmd == '\n') {
Michael Ellermane3bc8042012-08-23 22:09:13 +00001641 unsigned long sp, toc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 asm("mr %0,1" : "=r" (sp) :);
1643 asm("mr %0,2" : "=r" (toc) :);
1644
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001645 printf("msr = "REG" sprg0= "REG"\n",
1646 mfmsr(), mfspr(SPRN_SPRG0));
1647 printf("pvr = "REG" sprg1= "REG"\n",
Michael Ellermane3bc8042012-08-23 22:09:13 +00001648 mfspr(SPRN_PVR), mfspr(SPRN_SPRG1));
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001649 printf("dec = "REG" sprg2= "REG"\n",
1650 mfspr(SPRN_DEC), mfspr(SPRN_SPRG2));
1651 printf("sp = "REG" sprg3= "REG"\n", sp, mfspr(SPRN_SPRG3));
1652 printf("toc = "REG" dar = "REG"\n", toc, mfspr(SPRN_DAR));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653
1654 return;
1655 }
1656
1657 scanhex(&regno);
1658 switch (cmd) {
1659 case 'w':
1660 val = read_spr(regno);
1661 scanhex(&val);
1662 write_spr(regno, val);
1663 /* fall through */
1664 case 'r':
1665 printf("spr %lx = %lx\n", regno, read_spr(regno));
1666 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667 }
1668 scannl();
1669}
1670
1671/*
1672 * Stuff for reading and writing memory safely
1673 */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001674static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675mread(unsigned long adrs, void *buf, int size)
1676{
1677 volatile int n;
1678 char *p, *q;
1679
1680 n = 0;
1681 if (setjmp(bus_error_jmp) == 0) {
1682 catch_memory_errors = 1;
1683 sync();
1684 p = (char *)adrs;
1685 q = (char *)buf;
1686 switch (size) {
1687 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001688 *(u16 *)q = *(u16 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689 break;
1690 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001691 *(u32 *)q = *(u32 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692 break;
1693 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001694 *(u64 *)q = *(u64 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695 break;
1696 default:
1697 for( ; n < size; ++n) {
1698 *q++ = *p++;
1699 sync();
1700 }
1701 }
1702 sync();
1703 /* wait a little while to see if we get a machine check */
1704 __delay(200);
1705 n = size;
1706 }
1707 catch_memory_errors = 0;
1708 return n;
1709}
1710
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001711static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712mwrite(unsigned long adrs, void *buf, int size)
1713{
1714 volatile int n;
1715 char *p, *q;
1716
1717 n = 0;
1718 if (setjmp(bus_error_jmp) == 0) {
1719 catch_memory_errors = 1;
1720 sync();
1721 p = (char *) adrs;
1722 q = (char *) buf;
1723 switch (size) {
1724 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001725 *(u16 *)p = *(u16 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726 break;
1727 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001728 *(u32 *)p = *(u32 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729 break;
1730 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001731 *(u64 *)p = *(u64 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 break;
1733 default:
1734 for ( ; n < size; ++n) {
1735 *p++ = *q++;
1736 sync();
1737 }
1738 }
1739 sync();
1740 /* wait a little while to see if we get a machine check */
1741 __delay(200);
1742 n = size;
1743 } else {
1744 printf("*** Error writing address %x\n", adrs + n);
1745 }
1746 catch_memory_errors = 0;
1747 return n;
1748}
1749
1750static int fault_type;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001751static int fault_except;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752static char *fault_chars[] = { "--", "**", "##" };
1753
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001754static int handle_fault(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001756 fault_except = TRAP(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 switch (TRAP(regs)) {
1758 case 0x200:
1759 fault_type = 0;
1760 break;
1761 case 0x300:
1762 case 0x380:
1763 fault_type = 1;
1764 break;
1765 default:
1766 fault_type = 2;
1767 }
1768
1769 longjmp(bus_error_jmp, 1);
1770
1771 return 0;
1772}
1773
1774#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t))
1775
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001776static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777byterev(unsigned char *val, int size)
1778{
1779 int t;
1780
1781 switch (size) {
1782 case 2:
1783 SWAP(val[0], val[1], t);
1784 break;
1785 case 4:
1786 SWAP(val[0], val[3], t);
1787 SWAP(val[1], val[2], t);
1788 break;
1789 case 8: /* is there really any use for this? */
1790 SWAP(val[0], val[7], t);
1791 SWAP(val[1], val[6], t);
1792 SWAP(val[2], val[5], t);
1793 SWAP(val[3], val[4], t);
1794 break;
1795 }
1796}
1797
1798static int brev;
1799static int mnoread;
1800
Michael Ellermane3bc8042012-08-23 22:09:13 +00001801static char *memex_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802 "Memory examine command usage:\n"
1803 "m [addr] [flags] examine/change memory\n"
1804 " addr is optional. will start where left off.\n"
1805 " flags may include chars from this set:\n"
1806 " b modify by bytes (default)\n"
1807 " w modify by words (2 byte)\n"
1808 " l modify by longs (4 byte)\n"
1809 " d modify by doubleword (8 byte)\n"
1810 " r toggle reverse byte order mode\n"
1811 " n do not read memory (for i/o spaces)\n"
1812 " . ok to read (default)\n"
1813 "NOTE: flags are saved as defaults\n"
1814 "";
1815
Michael Ellermane3bc8042012-08-23 22:09:13 +00001816static char *memex_subcmd_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817 "Memory examine subcommands:\n"
1818 " hexval write this val to current location\n"
1819 " 'string' write chars from string to this location\n"
1820 " ' increment address\n"
1821 " ^ decrement address\n"
1822 " / increment addr by 0x10. //=0x100, ///=0x1000, etc\n"
1823 " \\ decrement addr by 0x10. \\\\=0x100, \\\\\\=0x1000, etc\n"
1824 " ` clear no-read flag\n"
1825 " ; stay at this addr\n"
1826 " v change to byte mode\n"
1827 " w change to word (2 byte) mode\n"
1828 " l change to long (4 byte) mode\n"
1829 " u change to doubleword (8 byte) mode\n"
1830 " m addr change current addr\n"
1831 " n toggle no-read flag\n"
1832 " r toggle byte reverse flag\n"
1833 " < count back up count bytes\n"
1834 " > count skip forward count bytes\n"
1835 " x exit this mode\n"
1836 "";
1837
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001838static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839memex(void)
1840{
1841 int cmd, inc, i, nslash;
1842 unsigned long n;
1843 unsigned char val[16];
1844
1845 scanhex((void *)&adrs);
1846 cmd = skipbl();
1847 if (cmd == '?') {
1848 printf(memex_help_string);
1849 return;
1850 } else {
1851 termch = cmd;
1852 }
1853 last_cmd = "m\n";
1854 while ((cmd = skipbl()) != '\n') {
1855 switch( cmd ){
1856 case 'b': size = 1; break;
1857 case 'w': size = 2; break;
1858 case 'l': size = 4; break;
1859 case 'd': size = 8; break;
1860 case 'r': brev = !brev; break;
1861 case 'n': mnoread = 1; break;
1862 case '.': mnoread = 0; break;
1863 }
1864 }
1865 if( size <= 0 )
1866 size = 1;
1867 else if( size > 8 )
1868 size = 8;
1869 for(;;){
1870 if (!mnoread)
1871 n = mread(adrs, val, size);
Paul Mackerrase1449ed2005-11-10 14:30:20 +11001872 printf(REG"%c", adrs, brev? 'r': ' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 if (!mnoread) {
1874 if (brev)
1875 byterev(val, size);
1876 putchar(' ');
1877 for (i = 0; i < n; ++i)
1878 printf("%.2x", val[i]);
1879 for (; i < size; ++i)
1880 printf("%s", fault_chars[fault_type]);
1881 }
1882 putchar(' ');
1883 inc = size;
1884 nslash = 0;
1885 for(;;){
1886 if( scanhex(&n) ){
1887 for (i = 0; i < size; ++i)
1888 val[i] = n >> (i * 8);
1889 if (!brev)
1890 byterev(val, size);
1891 mwrite(adrs, val, size);
1892 inc = size;
1893 }
1894 cmd = skipbl();
1895 if (cmd == '\n')
1896 break;
1897 inc = 0;
1898 switch (cmd) {
1899 case '\'':
1900 for(;;){
1901 n = inchar();
1902 if( n == '\\' )
1903 n = bsesc();
1904 else if( n == '\'' )
1905 break;
1906 for (i = 0; i < size; ++i)
1907 val[i] = n >> (i * 8);
1908 if (!brev)
1909 byterev(val, size);
1910 mwrite(adrs, val, size);
1911 adrs += size;
1912 }
1913 adrs -= size;
1914 inc = size;
1915 break;
1916 case ',':
1917 adrs += size;
1918 break;
1919 case '.':
1920 mnoread = 0;
1921 break;
1922 case ';':
1923 break;
1924 case 'x':
1925 case EOF:
1926 scannl();
1927 return;
1928 case 'b':
1929 case 'v':
1930 size = 1;
1931 break;
1932 case 'w':
1933 size = 2;
1934 break;
1935 case 'l':
1936 size = 4;
1937 break;
1938 case 'u':
1939 size = 8;
1940 break;
1941 case '^':
1942 adrs -= size;
1943 break;
1944 break;
1945 case '/':
1946 if (nslash > 0)
1947 adrs -= 1 << nslash;
1948 else
1949 nslash = 0;
1950 nslash += 4;
1951 adrs += 1 << nslash;
1952 break;
1953 case '\\':
1954 if (nslash < 0)
1955 adrs += 1 << -nslash;
1956 else
1957 nslash = 0;
1958 nslash -= 4;
1959 adrs -= 1 << -nslash;
1960 break;
1961 case 'm':
1962 scanhex((void *)&adrs);
1963 break;
1964 case 'n':
1965 mnoread = 1;
1966 break;
1967 case 'r':
1968 brev = !brev;
1969 break;
1970 case '<':
1971 n = size;
1972 scanhex(&n);
1973 adrs -= n;
1974 break;
1975 case '>':
1976 n = size;
1977 scanhex(&n);
1978 adrs += n;
1979 break;
1980 case '?':
1981 printf(memex_subcmd_help_string);
1982 break;
1983 }
1984 }
1985 adrs += inc;
1986 }
1987}
1988
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001989static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990bsesc(void)
1991{
1992 int c;
1993
1994 c = inchar();
1995 switch( c ){
1996 case 'n': c = '\n'; break;
1997 case 'r': c = '\r'; break;
1998 case 'b': c = '\b'; break;
1999 case 't': c = '\t'; break;
2000 }
2001 return c;
2002}
2003
Olaf Hering7e5b5932006-03-08 20:40:28 +01002004static void xmon_rawdump (unsigned long adrs, long ndump)
2005{
2006 long n, m, r, nr;
2007 unsigned char temp[16];
2008
2009 for (n = ndump; n > 0;) {
2010 r = n < 16? n: 16;
2011 nr = mread(adrs, temp, r);
2012 adrs += nr;
2013 for (m = 0; m < r; ++m) {
2014 if (m < nr)
2015 printf("%.2x", temp[m]);
2016 else
2017 printf("%s", fault_chars[fault_type]);
2018 }
2019 n -= r;
2020 if (nr < r)
2021 break;
2022 }
2023 printf("\n");
2024}
2025
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002026#ifdef CONFIG_PPC64
2027static void dump_one_paca(int cpu)
2028{
2029 struct paca_struct *p;
2030
2031 if (setjmp(bus_error_jmp) != 0) {
2032 printf("*** Error dumping paca for cpu 0x%x!\n", cpu);
2033 return;
2034 }
2035
2036 catch_memory_errors = 1;
2037 sync();
2038
2039 p = &paca[cpu];
2040
2041 printf("paca for cpu 0x%x @ %p:\n", cpu, p);
2042
2043 printf(" %-*s = %s\n", 16, "possible", cpu_possible(cpu) ? "yes" : "no");
2044 printf(" %-*s = %s\n", 16, "present", cpu_present(cpu) ? "yes" : "no");
2045 printf(" %-*s = %s\n", 16, "online", cpu_online(cpu) ? "yes" : "no");
2046
2047#define DUMP(paca, name, format) \
2048 printf(" %-*s = %#-*"format"\t(0x%lx)\n", 16, #name, 18, paca->name, \
2049 offsetof(struct paca_struct, name));
2050
2051 DUMP(p, lock_token, "x");
2052 DUMP(p, paca_index, "x");
2053 DUMP(p, kernel_toc, "lx");
2054 DUMP(p, kernelbase, "lx");
2055 DUMP(p, kernel_msr, "lx");
2056#ifdef CONFIG_PPC_STD_MMU_64
2057 DUMP(p, stab_real, "lx");
2058 DUMP(p, stab_addr, "lx");
2059#endif
2060 DUMP(p, emergency_sp, "p");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302061#ifdef CONFIG_PPC_BOOK3S_64
2062 DUMP(p, mc_emergency_sp, "p");
2063 DUMP(p, in_mce, "x");
2064#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002065 DUMP(p, data_offset, "lx");
2066 DUMP(p, hw_cpu_id, "x");
2067 DUMP(p, cpu_start, "x");
2068 DUMP(p, kexec_state, "x");
2069 DUMP(p, __current, "p");
2070 DUMP(p, kstack, "lx");
2071 DUMP(p, stab_rr, "lx");
2072 DUMP(p, saved_r1, "lx");
2073 DUMP(p, trap_save, "x");
2074 DUMP(p, soft_enabled, "x");
2075 DUMP(p, irq_happened, "x");
2076 DUMP(p, io_sync, "x");
2077 DUMP(p, irq_work_pending, "x");
2078 DUMP(p, nap_state_lost, "x");
2079
2080#undef DUMP
2081
2082 catch_memory_errors = 0;
2083 sync();
2084}
2085
2086static void dump_all_pacas(void)
2087{
2088 int cpu;
2089
2090 if (num_possible_cpus() == 0) {
2091 printf("No possible cpus, use 'dp #' to dump individual cpus\n");
2092 return;
2093 }
2094
2095 for_each_possible_cpu(cpu)
2096 dump_one_paca(cpu);
2097}
2098
2099static void dump_pacas(void)
2100{
2101 unsigned long num;
2102 int c;
2103
2104 c = inchar();
2105 if (c == 'a') {
2106 dump_all_pacas();
2107 return;
2108 }
2109
2110 termch = c; /* Put c back, it wasn't 'a' */
2111
2112 if (scanhex(&num))
2113 dump_one_paca(num);
2114 else
2115 dump_one_paca(xmon_owner);
2116}
2117#endif
2118
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
2120 || ('a' <= (c) && (c) <= 'f') \
2121 || ('A' <= (c) && (c) <= 'F'))
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002122static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002123dump(void)
2124{
2125 int c;
2126
2127 c = inchar();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002128
2129#ifdef CONFIG_PPC64
2130 if (c == 'p') {
2131 dump_pacas();
2132 return;
2133 }
2134#endif
2135
Linus Torvalds1da177e2005-04-16 15:20:36 -07002136 if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
2137 termch = c;
2138 scanhex((void *)&adrs);
2139 if (termch != '\n')
2140 termch = 0;
2141 if (c == 'i') {
2142 scanhex(&nidump);
2143 if (nidump == 0)
2144 nidump = 16;
2145 else if (nidump > MAX_DUMP)
2146 nidump = MAX_DUMP;
2147 adrs += ppc_inst_dump(adrs, nidump, 1);
2148 last_cmd = "di\n";
Vinay Sridharf312deb2009-05-14 23:13:07 +00002149 } else if (c == 'l') {
2150 dump_log_buf();
Olaf Hering7e5b5932006-03-08 20:40:28 +01002151 } else if (c == 'r') {
2152 scanhex(&ndump);
2153 if (ndump == 0)
2154 ndump = 64;
2155 xmon_rawdump(adrs, ndump);
2156 adrs += ndump;
2157 last_cmd = "dr\n";
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158 } else {
2159 scanhex(&ndump);
2160 if (ndump == 0)
2161 ndump = 64;
2162 else if (ndump > MAX_DUMP)
2163 ndump = MAX_DUMP;
2164 prdump(adrs, ndump);
2165 adrs += ndump;
2166 last_cmd = "d\n";
2167 }
2168}
2169
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002170static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002171prdump(unsigned long adrs, long ndump)
2172{
2173 long n, m, c, r, nr;
2174 unsigned char temp[16];
2175
2176 for (n = ndump; n > 0;) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002177 printf(REG, adrs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178 putchar(' ');
2179 r = n < 16? n: 16;
2180 nr = mread(adrs, temp, r);
2181 adrs += nr;
2182 for (m = 0; m < r; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002183 if ((m & (sizeof(long) - 1)) == 0 && m > 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002184 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185 if (m < nr)
2186 printf("%.2x", temp[m]);
2187 else
2188 printf("%s", fault_chars[fault_type]);
2189 }
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002190 for (; m < 16; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002191 if ((m & (sizeof(long) - 1)) == 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002192 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193 printf(" ");
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002194 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195 printf(" |");
2196 for (m = 0; m < r; ++m) {
2197 if (m < nr) {
2198 c = temp[m];
2199 putchar(' ' <= c && c <= '~'? c: '.');
2200 } else
2201 putchar(' ');
2202 }
2203 n -= r;
2204 for (; m < 16; ++m)
2205 putchar(' ');
2206 printf("|\n");
2207 if (nr < r)
2208 break;
2209 }
2210}
2211
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002212typedef int (*instruction_dump_func)(unsigned long inst, unsigned long addr);
2213
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002214static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002215generic_inst_dump(unsigned long adr, long count, int praddr,
2216 instruction_dump_func dump_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217{
2218 int nr, dotted;
2219 unsigned long first_adr;
2220 unsigned long inst, last_inst = 0;
2221 unsigned char val[4];
2222
2223 dotted = 0;
2224 for (first_adr = adr; count > 0; --count, adr += 4) {
2225 nr = mread(adr, val, 4);
2226 if (nr == 0) {
2227 if (praddr) {
2228 const char *x = fault_chars[fault_type];
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002229 printf(REG" %s%s%s%s\n", adr, x, x, x, x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230 }
2231 break;
2232 }
2233 inst = GETWORD(val);
2234 if (adr > first_adr && inst == last_inst) {
2235 if (!dotted) {
2236 printf(" ...\n");
2237 dotted = 1;
2238 }
2239 continue;
2240 }
2241 dotted = 0;
2242 last_inst = inst;
2243 if (praddr)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002244 printf(REG" %.8x", adr, inst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002245 printf("\t");
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002246 dump_func(inst, adr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247 printf("\n");
2248 }
2249 return adr - first_adr;
2250}
2251
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002252static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002253ppc_inst_dump(unsigned long adr, long count, int praddr)
2254{
2255 return generic_inst_dump(adr, count, praddr, print_insn_powerpc);
2256}
2257
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258void
2259print_address(unsigned long addr)
2260{
2261 xmon_print_symbol(addr, "\t# ", "");
2262}
2263
Vinay Sridharf312deb2009-05-14 23:13:07 +00002264void
2265dump_log_buf(void)
2266{
Michael Ellermanca5dd392012-08-23 22:09:12 +00002267 struct kmsg_dumper dumper = { .active = 1 };
2268 unsigned char buf[128];
2269 size_t len;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002270
Michael Ellermane3bc8042012-08-23 22:09:13 +00002271 if (setjmp(bus_error_jmp) != 0) {
Michael Ellermanca5dd392012-08-23 22:09:12 +00002272 printf("Error dumping printk buffer!\n");
Michael Ellermane3bc8042012-08-23 22:09:13 +00002273 return;
2274 }
Vinay Sridharf312deb2009-05-14 23:13:07 +00002275
Michael Ellermane3bc8042012-08-23 22:09:13 +00002276 catch_memory_errors = 1;
2277 sync();
Vinay Sridharf312deb2009-05-14 23:13:07 +00002278
Michael Ellermanca5dd392012-08-23 22:09:12 +00002279 kmsg_dump_rewind_nolock(&dumper);
2280 while (kmsg_dump_get_line_nolock(&dumper, false, buf, sizeof(buf), &len)) {
2281 buf[len] = '\0';
2282 printf("%s", buf);
2283 }
Vinay Sridharf312deb2009-05-14 23:13:07 +00002284
Michael Ellermane3bc8042012-08-23 22:09:13 +00002285 sync();
2286 /* wait a little while to see if we get a machine check */
2287 __delay(200);
2288 catch_memory_errors = 0;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002289}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290
2291/*
2292 * Memory operations - move, set, print differences
2293 */
2294static unsigned long mdest; /* destination address */
2295static unsigned long msrc; /* source address */
2296static unsigned long mval; /* byte value to set memory to */
2297static unsigned long mcount; /* # bytes to affect */
2298static unsigned long mdiffs; /* max # differences to print */
2299
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002300static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301memops(int cmd)
2302{
2303 scanhex((void *)&mdest);
2304 if( termch != '\n' )
2305 termch = 0;
2306 scanhex((void *)(cmd == 's'? &mval: &msrc));
2307 if( termch != '\n' )
2308 termch = 0;
2309 scanhex((void *)&mcount);
2310 switch( cmd ){
2311 case 'm':
2312 memmove((void *)mdest, (void *)msrc, mcount);
2313 break;
2314 case 's':
2315 memset((void *)mdest, mval, mcount);
2316 break;
2317 case 'd':
2318 if( termch != '\n' )
2319 termch = 0;
2320 scanhex((void *)&mdiffs);
2321 memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
2322 break;
2323 }
2324}
2325
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002326static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
2328{
2329 unsigned n, prt;
2330
2331 prt = 0;
2332 for( n = nb; n > 0; --n )
2333 if( *p1++ != *p2++ )
2334 if( ++prt <= maxpr )
2335 printf("%.16x %.2x # %.16x %.2x\n", p1 - 1,
2336 p1[-1], p2 - 1, p2[-1]);
2337 if( prt > maxpr )
2338 printf("Total of %d differences\n", prt);
2339}
2340
2341static unsigned mend;
2342static unsigned mask;
2343
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002344static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345memlocate(void)
2346{
2347 unsigned a, n;
2348 unsigned char val[4];
2349
2350 last_cmd = "ml";
2351 scanhex((void *)&mdest);
2352 if (termch != '\n') {
2353 termch = 0;
2354 scanhex((void *)&mend);
2355 if (termch != '\n') {
2356 termch = 0;
2357 scanhex((void *)&mval);
2358 mask = ~0;
2359 if (termch != '\n') termch = 0;
2360 scanhex((void *)&mask);
2361 }
2362 }
2363 n = 0;
2364 for (a = mdest; a < mend; a += 4) {
2365 if (mread(a, val, 4) == 4
2366 && ((GETWORD(val) ^ mval) & mask) == 0) {
2367 printf("%.16x: %.16x\n", a, GETWORD(val));
2368 if (++n >= 10)
2369 break;
2370 }
2371 }
2372}
2373
2374static unsigned long mskip = 0x1000;
2375static unsigned long mlim = 0xffffffff;
2376
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002377static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378memzcan(void)
2379{
2380 unsigned char v;
2381 unsigned a;
2382 int ok, ook;
2383
2384 scanhex(&mdest);
2385 if (termch != '\n') termch = 0;
2386 scanhex(&mskip);
2387 if (termch != '\n') termch = 0;
2388 scanhex(&mlim);
2389 ook = 0;
2390 for (a = mdest; a < mlim; a += mskip) {
2391 ok = mread(a, &v, 1);
2392 if (ok && !ook) {
2393 printf("%.8x .. ", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394 } else if (!ok && ook)
2395 printf("%.8x\n", a - mskip);
2396 ook = ok;
2397 if (a + mskip < a)
2398 break;
2399 }
2400 if (ook)
2401 printf("%.8x\n", a - mskip);
2402}
2403
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002404static void proccall(void)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002405{
2406 unsigned long args[8];
2407 unsigned long ret;
2408 int i;
2409 typedef unsigned long (*callfunc_t)(unsigned long, unsigned long,
2410 unsigned long, unsigned long, unsigned long,
2411 unsigned long, unsigned long, unsigned long);
2412 callfunc_t func;
2413
2414 if (!scanhex(&adrs))
2415 return;
2416 if (termch != '\n')
2417 termch = 0;
2418 for (i = 0; i < 8; ++i)
2419 args[i] = 0;
2420 for (i = 0; i < 8; ++i) {
2421 if (!scanhex(&args[i]) || termch == '\n')
2422 break;
2423 termch = 0;
2424 }
2425 func = (callfunc_t) adrs;
2426 ret = 0;
2427 if (setjmp(bus_error_jmp) == 0) {
2428 catch_memory_errors = 1;
2429 sync();
2430 ret = func(args[0], args[1], args[2], args[3],
2431 args[4], args[5], args[6], args[7]);
2432 sync();
2433 printf("return value is %x\n", ret);
2434 } else {
2435 printf("*** %x exception occurred\n", fault_except);
2436 }
2437 catch_memory_errors = 0;
2438}
2439
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440/* Input scanning routines */
2441int
2442skipbl(void)
2443{
2444 int c;
2445
2446 if( termch != 0 ){
2447 c = termch;
2448 termch = 0;
2449 } else
2450 c = inchar();
2451 while( c == ' ' || c == '\t' )
2452 c = inchar();
2453 return c;
2454}
2455
2456#define N_PTREGS 44
2457static char *regnames[N_PTREGS] = {
2458 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
2459 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
2460 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
2461 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002462 "pc", "msr", "or3", "ctr", "lr", "xer", "ccr",
2463#ifdef CONFIG_PPC64
2464 "softe",
2465#else
2466 "mq",
2467#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468 "trap", "dar", "dsisr", "res"
2469};
2470
2471int
2472scanhex(unsigned long *vp)
2473{
2474 int c, d;
2475 unsigned long v;
2476
2477 c = skipbl();
2478 if (c == '%') {
2479 /* parse register name */
2480 char regname[8];
2481 int i;
2482
2483 for (i = 0; i < sizeof(regname) - 1; ++i) {
2484 c = inchar();
2485 if (!isalnum(c)) {
2486 termch = c;
2487 break;
2488 }
2489 regname[i] = c;
2490 }
2491 regname[i] = 0;
2492 for (i = 0; i < N_PTREGS; ++i) {
2493 if (strcmp(regnames[i], regname) == 0) {
2494 if (xmon_regs == NULL) {
2495 printf("regs not available\n");
2496 return 0;
2497 }
2498 *vp = ((unsigned long *)xmon_regs)[i];
2499 return 1;
2500 }
2501 }
2502 printf("invalid register name '%%%s'\n", regname);
2503 return 0;
2504 }
2505
2506 /* skip leading "0x" if any */
2507
2508 if (c == '0') {
2509 c = inchar();
2510 if (c == 'x') {
2511 c = inchar();
2512 } else {
2513 d = hexdigit(c);
2514 if (d == EOF) {
2515 termch = c;
2516 *vp = 0;
2517 return 1;
2518 }
2519 }
2520 } else if (c == '$') {
2521 int i;
2522 for (i=0; i<63; i++) {
2523 c = inchar();
2524 if (isspace(c)) {
2525 termch = c;
2526 break;
2527 }
2528 tmpstr[i] = c;
2529 }
2530 tmpstr[i++] = 0;
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07002531 *vp = 0;
2532 if (setjmp(bus_error_jmp) == 0) {
2533 catch_memory_errors = 1;
2534 sync();
2535 *vp = kallsyms_lookup_name(tmpstr);
2536 sync();
2537 }
2538 catch_memory_errors = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539 if (!(*vp)) {
2540 printf("unknown symbol '%s'\n", tmpstr);
2541 return 0;
2542 }
2543 return 1;
2544 }
2545
2546 d = hexdigit(c);
2547 if (d == EOF) {
2548 termch = c;
2549 return 0;
2550 }
2551 v = 0;
2552 do {
2553 v = (v << 4) + d;
2554 c = inchar();
2555 d = hexdigit(c);
2556 } while (d != EOF);
2557 termch = c;
2558 *vp = v;
2559 return 1;
2560}
2561
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002562static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563scannl(void)
2564{
2565 int c;
2566
2567 c = termch;
2568 termch = 0;
2569 while( c != '\n' )
2570 c = inchar();
2571}
2572
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002573static int hexdigit(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574{
2575 if( '0' <= c && c <= '9' )
2576 return c - '0';
2577 if( 'A' <= c && c <= 'F' )
2578 return c - ('A' - 10);
2579 if( 'a' <= c && c <= 'f' )
2580 return c - ('a' - 10);
2581 return EOF;
2582}
2583
2584void
2585getstring(char *s, int size)
2586{
2587 int c;
2588
2589 c = skipbl();
2590 do {
2591 if( size > 1 ){
2592 *s++ = c;
2593 --size;
2594 }
2595 c = inchar();
2596 } while( c != ' ' && c != '\t' && c != '\n' );
2597 termch = c;
2598 *s = 0;
2599}
2600
2601static char line[256];
2602static char *lineptr;
2603
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002604static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605flush_input(void)
2606{
2607 lineptr = NULL;
2608}
2609
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002610static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611inchar(void)
2612{
2613 if (lineptr == NULL || *lineptr == 0) {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002614 if (xmon_gets(line, sizeof(line)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002615 lineptr = NULL;
2616 return EOF;
2617 }
2618 lineptr = line;
2619 }
2620 return *lineptr++;
2621}
2622
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002623static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624take_input(char *str)
2625{
2626 lineptr = str;
2627}
2628
2629
2630static void
2631symbol_lookup(void)
2632{
2633 int type = inchar();
2634 unsigned long addr;
2635 static char tmp[64];
2636
2637 switch (type) {
2638 case 'a':
2639 if (scanhex(&addr))
2640 xmon_print_symbol(addr, ": ", "\n");
2641 termch = 0;
2642 break;
2643 case 's':
2644 getstring(tmp, 64);
2645 if (setjmp(bus_error_jmp) == 0) {
2646 catch_memory_errors = 1;
2647 sync();
2648 addr = kallsyms_lookup_name(tmp);
2649 if (addr)
2650 printf("%s: %lx\n", tmp, addr);
2651 else
2652 printf("Symbol '%s' not found.\n", tmp);
2653 sync();
2654 }
2655 catch_memory_errors = 0;
2656 termch = 0;
2657 break;
2658 }
2659}
2660
2661
2662/* Print an address in numeric and symbolic form (if possible) */
2663static void xmon_print_symbol(unsigned long address, const char *mid,
2664 const char *after)
2665{
2666 char *modname;
2667 const char *name = NULL;
2668 unsigned long offset, size;
2669
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002670 printf(REG, address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671 if (setjmp(bus_error_jmp) == 0) {
2672 catch_memory_errors = 1;
2673 sync();
2674 name = kallsyms_lookup(address, &size, &offset, &modname,
2675 tmpstr);
2676 sync();
2677 /* wait a little while to see if we get a machine check */
2678 __delay(200);
2679 }
2680
2681 catch_memory_errors = 0;
2682
2683 if (name) {
2684 printf("%s%s+%#lx/%#lx", mid, name, offset, size);
2685 if (modname)
2686 printf(" [%s]", modname);
2687 }
2688 printf("%s", after);
2689}
2690
Benjamin Herrenschmidt2d27cfd2009-07-23 23:15:59 +00002691#ifdef CONFIG_PPC_BOOK3S_64
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692static void dump_slb(void)
2693{
2694 int i;
will schmidtb3b95952007-12-07 08:22:23 +11002695 unsigned long esid,vsid,valid;
2696 unsigned long llp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697
2698 printf("SLB contents of cpu %x\n", smp_processor_id());
2699
Michael Neuling584f8b72007-12-06 17:24:48 +11002700 for (i = 0; i < mmu_slb_size; i++) {
will schmidtb3b95952007-12-07 08:22:23 +11002701 asm volatile("slbmfee %0,%1" : "=r" (esid) : "r" (i));
2702 asm volatile("slbmfev %0,%1" : "=r" (vsid) : "r" (i));
2703 valid = (esid & SLB_ESID_V);
2704 if (valid | esid | vsid) {
2705 printf("%02d %016lx %016lx", i, esid, vsid);
2706 if (valid) {
2707 llp = vsid & SLB_VSID_LLP;
2708 if (vsid & SLB_VSID_B_1T) {
2709 printf(" 1T ESID=%9lx VSID=%13lx LLP:%3lx \n",
2710 GET_ESID_1T(esid),
2711 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT_1T,
2712 llp);
2713 } else {
2714 printf(" 256M ESID=%9lx VSID=%13lx LLP:%3lx \n",
2715 GET_ESID(esid),
2716 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT,
2717 llp);
2718 }
2719 } else
2720 printf("\n");
2721 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722 }
2723}
2724
2725static void dump_stab(void)
2726{
2727 int i;
Benjamin Herrenschmidt7ac21cd2012-03-02 10:10:09 +11002728 unsigned long *tmp = (unsigned long *)local_paca->stab_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729
2730 printf("Segment table contents of cpu %x\n", smp_processor_id());
2731
2732 for (i = 0; i < PAGE_SIZE/16; i++) {
2733 unsigned long a, b;
2734
2735 a = *tmp++;
2736 b = *tmp++;
2737
2738 if (a || b) {
2739 printf("%03d %016lx ", i, a);
2740 printf("%016lx\n", b);
2741 }
2742 }
2743}
2744
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002745void dump_segments(void)
2746{
Matt Evans44ae3ab2011-04-06 19:48:50 +00002747 if (mmu_has_feature(MMU_FTR_SLB))
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002748 dump_slb();
2749 else
2750 dump_stab();
2751}
2752#endif
2753
2754#ifdef CONFIG_PPC_STD_MMU_32
2755void dump_segments(void)
2756{
2757 int i;
2758
2759 printf("sr0-15 =");
2760 for (i = 0; i < 16; ++i)
2761 printf(" %x", mfsrin(i));
2762 printf("\n");
2763}
2764#endif
2765
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11002766#ifdef CONFIG_44x
2767static void dump_tlb_44x(void)
2768{
2769 int i;
2770
2771 for (i = 0; i < PPC44x_TLB_SIZE; i++) {
2772 unsigned long w0,w1,w2;
2773 asm volatile("tlbre %0,%1,0" : "=r" (w0) : "r" (i));
2774 asm volatile("tlbre %0,%1,1" : "=r" (w1) : "r" (i));
2775 asm volatile("tlbre %0,%1,2" : "=r" (w2) : "r" (i));
2776 printf("[%02x] %08x %08x %08x ", i, w0, w1, w2);
2777 if (w0 & PPC44x_TLB_VALID) {
2778 printf("V %08x -> %01x%08x %c%c%c%c%c",
2779 w0 & PPC44x_TLB_EPN_MASK,
2780 w1 & PPC44x_TLB_ERPN_MASK,
2781 w1 & PPC44x_TLB_RPN_MASK,
2782 (w2 & PPC44x_TLB_W) ? 'W' : 'w',
2783 (w2 & PPC44x_TLB_I) ? 'I' : 'i',
2784 (w2 & PPC44x_TLB_M) ? 'M' : 'm',
2785 (w2 & PPC44x_TLB_G) ? 'G' : 'g',
2786 (w2 & PPC44x_TLB_E) ? 'E' : 'e');
2787 }
2788 printf("\n");
2789 }
2790}
2791#endif /* CONFIG_44x */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002792
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +10002793#ifdef CONFIG_PPC_BOOK3E
2794static void dump_tlb_book3e(void)
2795{
2796 u32 mmucfg, pidmask, lpidmask;
2797 u64 ramask;
2798 int i, tlb, ntlbs, pidsz, lpidsz, rasz, lrat = 0;
2799 int mmu_version;
2800 static const char *pgsz_names[] = {
2801 " 1K",
2802 " 2K",
2803 " 4K",
2804 " 8K",
2805 " 16K",
2806 " 32K",
2807 " 64K",
2808 "128K",
2809 "256K",
2810 "512K",
2811 " 1M",
2812 " 2M",
2813 " 4M",
2814 " 8M",
2815 " 16M",
2816 " 32M",
2817 " 64M",
2818 "128M",
2819 "256M",
2820 "512M",
2821 " 1G",
2822 " 2G",
2823 " 4G",
2824 " 8G",
2825 " 16G",
2826 " 32G",
2827 " 64G",
2828 "128G",
2829 "256G",
2830 "512G",
2831 " 1T",
2832 " 2T",
2833 };
2834
2835 /* Gather some infos about the MMU */
2836 mmucfg = mfspr(SPRN_MMUCFG);
2837 mmu_version = (mmucfg & 3) + 1;
2838 ntlbs = ((mmucfg >> 2) & 3) + 1;
2839 pidsz = ((mmucfg >> 6) & 0x1f) + 1;
2840 lpidsz = (mmucfg >> 24) & 0xf;
2841 rasz = (mmucfg >> 16) & 0x7f;
2842 if ((mmu_version > 1) && (mmucfg & 0x10000))
2843 lrat = 1;
2844 printf("Book3E MMU MAV=%d.0,%d TLBs,%d-bit PID,%d-bit LPID,%d-bit RA\n",
2845 mmu_version, ntlbs, pidsz, lpidsz, rasz);
2846 pidmask = (1ul << pidsz) - 1;
2847 lpidmask = (1ul << lpidsz) - 1;
2848 ramask = (1ull << rasz) - 1;
2849
2850 for (tlb = 0; tlb < ntlbs; tlb++) {
2851 u32 tlbcfg;
2852 int nent, assoc, new_cc = 1;
2853 printf("TLB %d:\n------\n", tlb);
2854 switch(tlb) {
2855 case 0:
2856 tlbcfg = mfspr(SPRN_TLB0CFG);
2857 break;
2858 case 1:
2859 tlbcfg = mfspr(SPRN_TLB1CFG);
2860 break;
2861 case 2:
2862 tlbcfg = mfspr(SPRN_TLB2CFG);
2863 break;
2864 case 3:
2865 tlbcfg = mfspr(SPRN_TLB3CFG);
2866 break;
2867 default:
2868 printf("Unsupported TLB number !\n");
2869 continue;
2870 }
2871 nent = tlbcfg & 0xfff;
2872 assoc = (tlbcfg >> 24) & 0xff;
2873 for (i = 0; i < nent; i++) {
2874 u32 mas0 = MAS0_TLBSEL(tlb);
2875 u32 mas1 = MAS1_TSIZE(BOOK3E_PAGESZ_4K);
2876 u64 mas2 = 0;
2877 u64 mas7_mas3;
2878 int esel = i, cc = i;
2879
2880 if (assoc != 0) {
2881 cc = i / assoc;
2882 esel = i % assoc;
2883 mas2 = cc * 0x1000;
2884 }
2885
2886 mas0 |= MAS0_ESEL(esel);
2887 mtspr(SPRN_MAS0, mas0);
2888 mtspr(SPRN_MAS1, mas1);
2889 mtspr(SPRN_MAS2, mas2);
2890 asm volatile("tlbre 0,0,0" : : : "memory");
2891 mas1 = mfspr(SPRN_MAS1);
2892 mas2 = mfspr(SPRN_MAS2);
2893 mas7_mas3 = mfspr(SPRN_MAS7_MAS3);
2894 if (assoc && (i % assoc) == 0)
2895 new_cc = 1;
2896 if (!(mas1 & MAS1_VALID))
2897 continue;
2898 if (assoc == 0)
2899 printf("%04x- ", i);
2900 else if (new_cc)
2901 printf("%04x-%c", cc, 'A' + esel);
2902 else
2903 printf(" |%c", 'A' + esel);
2904 new_cc = 0;
2905 printf(" %016llx %04x %s %c%c AS%c",
2906 mas2 & ~0x3ffull,
2907 (mas1 >> 16) & 0x3fff,
2908 pgsz_names[(mas1 >> 7) & 0x1f],
2909 mas1 & MAS1_IND ? 'I' : ' ',
2910 mas1 & MAS1_IPROT ? 'P' : ' ',
2911 mas1 & MAS1_TS ? '1' : '0');
2912 printf(" %c%c%c%c%c%c%c",
2913 mas2 & MAS2_X0 ? 'a' : ' ',
2914 mas2 & MAS2_X1 ? 'v' : ' ',
2915 mas2 & MAS2_W ? 'w' : ' ',
2916 mas2 & MAS2_I ? 'i' : ' ',
2917 mas2 & MAS2_M ? 'm' : ' ',
2918 mas2 & MAS2_G ? 'g' : ' ',
2919 mas2 & MAS2_E ? 'e' : ' ');
2920 printf(" %016llx", mas7_mas3 & ramask & ~0x7ffull);
2921 if (mas1 & MAS1_IND)
2922 printf(" %s\n",
2923 pgsz_names[(mas7_mas3 >> 1) & 0x1f]);
2924 else
2925 printf(" U%c%c%c S%c%c%c\n",
2926 mas7_mas3 & MAS3_UX ? 'x' : ' ',
2927 mas7_mas3 & MAS3_UW ? 'w' : ' ',
2928 mas7_mas3 & MAS3_UR ? 'r' : ' ',
2929 mas7_mas3 & MAS3_SX ? 'x' : ' ',
2930 mas7_mas3 & MAS3_SW ? 'w' : ' ',
2931 mas7_mas3 & MAS3_SR ? 'r' : ' ');
2932 }
2933 }
2934}
2935#endif /* CONFIG_PPC_BOOK3E */
2936
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002937static void xmon_init(int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002938{
Olaf Heringb13cfd172005-08-04 19:26:42 +02002939 if (enable) {
2940 __debugger = xmon;
2941 __debugger_ipi = xmon_ipi;
2942 __debugger_bpt = xmon_bpt;
2943 __debugger_sstep = xmon_sstep;
2944 __debugger_iabr_match = xmon_iabr_match;
Michael Neuling9422de32012-12-20 14:06:44 +00002945 __debugger_break_match = xmon_break_match;
Olaf Heringb13cfd172005-08-04 19:26:42 +02002946 __debugger_fault_handler = xmon_fault_handler;
2947 } else {
2948 __debugger = NULL;
2949 __debugger_ipi = NULL;
2950 __debugger_bpt = NULL;
2951 __debugger_sstep = NULL;
2952 __debugger_iabr_match = NULL;
Michael Neuling9422de32012-12-20 14:06:44 +00002953 __debugger_break_match = NULL;
Olaf Heringb13cfd172005-08-04 19:26:42 +02002954 __debugger_fault_handler = NULL;
2955 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002956}
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002957
2958#ifdef CONFIG_MAGIC_SYSRQ
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07002959static void sysrq_handle_xmon(int key)
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002960{
2961 /* ensure xmon is enabled */
2962 xmon_init(1);
David Howells7d12e782006-10-05 14:55:46 +01002963 debugger(get_irq_regs());
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002964}
2965
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07002966static struct sysrq_key_op sysrq_xmon_op = {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002967 .handler = sysrq_handle_xmon,
zhangwei(Jovi)90a102e2013-04-30 15:28:54 -07002968 .help_msg = "xmon(x)",
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002969 .action_msg = "Entering xmon",
2970};
2971
2972static int __init setup_xmon_sysrq(void)
2973{
2974 register_sysrq_key('x', &sysrq_xmon_op);
2975 return 0;
2976}
2977__initcall(setup_xmon_sysrq);
2978#endif /* CONFIG_MAGIC_SYSRQ */
Michael Ellerman476792832006-10-03 14:12:08 +10002979
Olaf Heringf5e6a282007-06-24 16:57:08 +10002980static int __initdata xmon_early, xmon_off;
Michael Ellerman476792832006-10-03 14:12:08 +10002981
2982static int __init early_parse_xmon(char *p)
2983{
2984 if (!p || strncmp(p, "early", 5) == 0) {
2985 /* just "xmon" is equivalent to "xmon=early" */
2986 xmon_init(1);
2987 xmon_early = 1;
2988 } else if (strncmp(p, "on", 2) == 0)
2989 xmon_init(1);
2990 else if (strncmp(p, "off", 3) == 0)
2991 xmon_off = 1;
2992 else if (strncmp(p, "nobt", 4) == 0)
2993 xmon_no_auto_backtrace = 1;
2994 else
2995 return 1;
2996
2997 return 0;
2998}
2999early_param("xmon", early_parse_xmon);
3000
3001void __init xmon_setup(void)
3002{
3003#ifdef CONFIG_XMON_DEFAULT
3004 if (!xmon_off)
3005 xmon_init(1);
3006#endif
3007 if (xmon_early)
3008 debugger(NULL);
3009}
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003010
Arnd Bergmanne0555952006-11-27 19:18:55 +01003011#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003012
3013struct spu_info {
3014 struct spu *spu;
3015 u64 saved_mfc_sr1_RW;
3016 u32 saved_spu_runcntl_RW;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003017 unsigned long dump_addr;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003018 u8 stopped_ok;
3019};
3020
3021#define XMON_NUM_SPUS 16 /* Enough for current hardware */
3022
3023static struct spu_info spu_info[XMON_NUM_SPUS];
3024
3025void xmon_register_spus(struct list_head *list)
3026{
3027 struct spu *spu;
3028
3029 list_for_each_entry(spu, list, full_list) {
3030 if (spu->number >= XMON_NUM_SPUS) {
3031 WARN_ON(1);
3032 continue;
3033 }
3034
3035 spu_info[spu->number].spu = spu;
3036 spu_info[spu->number].stopped_ok = 0;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003037 spu_info[spu->number].dump_addr = (unsigned long)
3038 spu_info[spu->number].spu->local_store;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003039 }
3040}
3041
3042static void stop_spus(void)
3043{
3044 struct spu *spu;
3045 int i;
3046 u64 tmp;
3047
3048 for (i = 0; i < XMON_NUM_SPUS; i++) {
3049 if (!spu_info[i].spu)
3050 continue;
3051
3052 if (setjmp(bus_error_jmp) == 0) {
3053 catch_memory_errors = 1;
3054 sync();
3055
3056 spu = spu_info[i].spu;
3057
3058 spu_info[i].saved_spu_runcntl_RW =
3059 in_be32(&spu->problem->spu_runcntl_RW);
3060
3061 tmp = spu_mfc_sr1_get(spu);
3062 spu_info[i].saved_mfc_sr1_RW = tmp;
3063
3064 tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
3065 spu_mfc_sr1_set(spu, tmp);
3066
3067 sync();
3068 __delay(200);
3069
3070 spu_info[i].stopped_ok = 1;
Michael Ellerman2a144422006-11-23 00:46:40 +01003071
3072 printf("Stopped spu %.2d (was %s)\n", i,
3073 spu_info[i].saved_spu_runcntl_RW ?
3074 "running" : "stopped");
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003075 } else {
3076 catch_memory_errors = 0;
3077 printf("*** Error stopping spu %.2d\n", i);
3078 }
3079 catch_memory_errors = 0;
3080 }
3081}
3082
3083static void restart_spus(void)
3084{
3085 struct spu *spu;
3086 int i;
3087
3088 for (i = 0; i < XMON_NUM_SPUS; i++) {
3089 if (!spu_info[i].spu)
3090 continue;
3091
3092 if (!spu_info[i].stopped_ok) {
3093 printf("*** Error, spu %d was not successfully stopped"
3094 ", not restarting\n", i);
3095 continue;
3096 }
3097
3098 if (setjmp(bus_error_jmp) == 0) {
3099 catch_memory_errors = 1;
3100 sync();
3101
3102 spu = spu_info[i].spu;
3103 spu_mfc_sr1_set(spu, spu_info[i].saved_mfc_sr1_RW);
3104 out_be32(&spu->problem->spu_runcntl_RW,
3105 spu_info[i].saved_spu_runcntl_RW);
3106
3107 sync();
3108 __delay(200);
3109
3110 printf("Restarted spu %.2d\n", i);
3111 } else {
3112 catch_memory_errors = 0;
3113 printf("*** Error restarting spu %.2d\n", i);
3114 }
3115 catch_memory_errors = 0;
3116 }
3117}
3118
Michael Ellermana8984972006-10-24 18:31:28 +02003119#define DUMP_WIDTH 23
Michael Ellerman437a0702006-11-23 00:46:39 +01003120#define DUMP_VALUE(format, field, value) \
Michael Ellermana8984972006-10-24 18:31:28 +02003121do { \
3122 if (setjmp(bus_error_jmp) == 0) { \
3123 catch_memory_errors = 1; \
3124 sync(); \
3125 printf(" %-*s = "format"\n", DUMP_WIDTH, \
Michael Ellerman437a0702006-11-23 00:46:39 +01003126 #field, value); \
Michael Ellermana8984972006-10-24 18:31:28 +02003127 sync(); \
3128 __delay(200); \
3129 } else { \
3130 catch_memory_errors = 0; \
3131 printf(" %-*s = *** Error reading field.\n", \
3132 DUMP_WIDTH, #field); \
3133 } \
3134 catch_memory_errors = 0; \
3135} while (0)
3136
Michael Ellerman437a0702006-11-23 00:46:39 +01003137#define DUMP_FIELD(obj, format, field) \
3138 DUMP_VALUE(format, field, obj->field)
3139
Michael Ellermana8984972006-10-24 18:31:28 +02003140static void dump_spu_fields(struct spu *spu)
3141{
3142 printf("Dumping spu fields at address %p:\n", spu);
3143
3144 DUMP_FIELD(spu, "0x%x", number);
3145 DUMP_FIELD(spu, "%s", name);
Michael Ellermana8984972006-10-24 18:31:28 +02003146 DUMP_FIELD(spu, "0x%lx", local_store_phys);
3147 DUMP_FIELD(spu, "0x%p", local_store);
3148 DUMP_FIELD(spu, "0x%lx", ls_size);
3149 DUMP_FIELD(spu, "0x%x", node);
3150 DUMP_FIELD(spu, "0x%lx", flags);
Michael Ellermana8984972006-10-24 18:31:28 +02003151 DUMP_FIELD(spu, "%d", class_0_pending);
Luke Browningf3d69e02008-04-27 18:41:55 +00003152 DUMP_FIELD(spu, "0x%lx", class_0_dar);
Luke Browningf3d69e02008-04-27 18:41:55 +00003153 DUMP_FIELD(spu, "0x%lx", class_1_dar);
3154 DUMP_FIELD(spu, "0x%lx", class_1_dsisr);
Michael Ellermana8984972006-10-24 18:31:28 +02003155 DUMP_FIELD(spu, "0x%lx", irqs[0]);
3156 DUMP_FIELD(spu, "0x%lx", irqs[1]);
3157 DUMP_FIELD(spu, "0x%lx", irqs[2]);
3158 DUMP_FIELD(spu, "0x%x", slb_replace);
3159 DUMP_FIELD(spu, "%d", pid);
Michael Ellermana8984972006-10-24 18:31:28 +02003160 DUMP_FIELD(spu, "0x%p", mm);
3161 DUMP_FIELD(spu, "0x%p", ctx);
3162 DUMP_FIELD(spu, "0x%p", rq);
3163 DUMP_FIELD(spu, "0x%p", timestamp);
3164 DUMP_FIELD(spu, "0x%lx", problem_phys);
3165 DUMP_FIELD(spu, "0x%p", problem);
Michael Ellerman437a0702006-11-23 00:46:39 +01003166 DUMP_VALUE("0x%x", problem->spu_runcntl_RW,
3167 in_be32(&spu->problem->spu_runcntl_RW));
3168 DUMP_VALUE("0x%x", problem->spu_status_R,
3169 in_be32(&spu->problem->spu_status_R));
3170 DUMP_VALUE("0x%x", problem->spu_npc_RW,
3171 in_be32(&spu->problem->spu_npc_RW));
Michael Ellermana8984972006-10-24 18:31:28 +02003172 DUMP_FIELD(spu, "0x%p", priv2);
Michael Ellermana9852392006-11-23 00:46:50 +01003173 DUMP_FIELD(spu, "0x%p", pdata);
Michael Ellermana8984972006-10-24 18:31:28 +02003174}
3175
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003176int
3177spu_inst_dump(unsigned long adr, long count, int praddr)
3178{
3179 return generic_inst_dump(adr, count, praddr, print_insn_spu);
3180}
3181
3182static void dump_spu_ls(unsigned long num, int subcmd)
Michael Ellerman24a24c82006-11-23 00:46:41 +01003183{
3184 unsigned long offset, addr, ls_addr;
3185
3186 if (setjmp(bus_error_jmp) == 0) {
3187 catch_memory_errors = 1;
3188 sync();
3189 ls_addr = (unsigned long)spu_info[num].spu->local_store;
3190 sync();
3191 __delay(200);
3192 } else {
3193 catch_memory_errors = 0;
3194 printf("*** Error: accessing spu info for spu %d\n", num);
3195 return;
3196 }
3197 catch_memory_errors = 0;
3198
3199 if (scanhex(&offset))
3200 addr = ls_addr + offset;
3201 else
3202 addr = spu_info[num].dump_addr;
3203
3204 if (addr >= ls_addr + LS_SIZE) {
3205 printf("*** Error: address outside of local store\n");
3206 return;
3207 }
3208
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003209 switch (subcmd) {
3210 case 'i':
3211 addr += spu_inst_dump(addr, 16, 1);
3212 last_cmd = "sdi\n";
3213 break;
3214 default:
3215 prdump(addr, 64);
3216 addr += 64;
3217 last_cmd = "sd\n";
3218 break;
3219 }
Michael Ellerman24a24c82006-11-23 00:46:41 +01003220
3221 spu_info[num].dump_addr = addr;
3222}
3223
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003224static int do_spu_cmd(void)
3225{
Michael Ellerman24a24c82006-11-23 00:46:41 +01003226 static unsigned long num = 0;
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003227 int cmd, subcmd = 0;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003228
3229 cmd = inchar();
3230 switch (cmd) {
3231 case 's':
3232 stop_spus();
3233 break;
3234 case 'r':
3235 restart_spus();
3236 break;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003237 case 'd':
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003238 subcmd = inchar();
3239 if (isxdigit(subcmd) || subcmd == '\n')
3240 termch = subcmd;
3241 case 'f':
Michael Ellerman24a24c82006-11-23 00:46:41 +01003242 scanhex(&num);
3243 if (num >= XMON_NUM_SPUS || !spu_info[num].spu) {
Michael Ellermana8984972006-10-24 18:31:28 +02003244 printf("*** Error: invalid spu number\n");
Michael Ellerman24a24c82006-11-23 00:46:41 +01003245 return 0;
3246 }
3247
3248 switch (cmd) {
3249 case 'f':
3250 dump_spu_fields(spu_info[num].spu);
3251 break;
3252 default:
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003253 dump_spu_ls(num, subcmd);
Michael Ellerman24a24c82006-11-23 00:46:41 +01003254 break;
3255 }
3256
Michael Ellermana8984972006-10-24 18:31:28 +02003257 break;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003258 default:
3259 return -1;
3260 }
3261
3262 return 0;
3263}
Arnd Bergmanne0555952006-11-27 19:18:55 +01003264#else /* ! CONFIG_SPU_BASE */
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003265static int do_spu_cmd(void)
3266{
3267 return -1;
3268}
3269#endif