blob: b07909850f77151b393f73a30bac727a79ea9921 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Routines providing a simple monitor for use on the PowerMac.
3 *
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11004 * Copyright (C) 1996-2005 Paul Mackerras.
Michael Ellerman476792832006-10-03 14:12:08 +10005 * Copyright (C) 2001 PPC64 Team, IBM Corp
6 * Copyrignt (C) 2006 Michael Ellerman, IBM Corp
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <linux/errno.h>
14#include <linux/sched.h>
15#include <linux/smp.h>
16#include <linux/mm.h>
17#include <linux/reboot.h>
18#include <linux/delay.h>
19#include <linux/kallsyms.h>
Michael Ellermanca5dd392012-08-23 22:09:12 +000020#include <linux/kmsg_dump.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <linux/cpumask.h>
Paul Gortmaker4b16f8e2011-07-22 18:24:23 -040022#include <linux/export.h>
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +110023#include <linux/sysrq.h>
Andrew Morton4694ca02005-11-13 16:06:50 -080024#include <linux/interrupt.h>
David Howells7d12e782006-10-05 14:55:46 +010025#include <linux/irq.h>
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -080026#include <linux/bug.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070027
28#include <asm/ptrace.h>
29#include <asm/string.h>
30#include <asm/prom.h>
31#include <asm/machdep.h>
Paul Mackerrasf78541d2005-10-28 22:53:37 +100032#include <asm/xmon.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <asm/processor.h>
34#include <asm/pgtable.h>
35#include <asm/mmu.h>
36#include <asm/mmu_context.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#include <asm/cputable.h>
38#include <asm/rtas.h>
39#include <asm/sstep.h>
Paul Mackerrasf583ffc2006-10-10 11:47:07 +100040#include <asm/irq_regs.h>
Michael Ellermanff8a8f22006-10-24 18:31:27 +020041#include <asm/spu.h>
42#include <asm/spu_priv1.h>
Michael Neulingc3b75bd2008-01-18 15:50:30 +110043#include <asm/setjmp.h>
Anton Vorontsov322b4392008-12-17 10:08:55 +000044#include <asm/reg.h>
David Howellsae3a1972012-03-28 18:30:02 +010045#include <asm/debug.h>
Michael Neuling9422de32012-12-20 14:06:44 +000046#include <asm/hw_breakpoint.h>
Paul Mackerrasf78541d2005-10-28 22:53:37 +100047
48#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <asm/hvcall.h>
Paul Mackerrasf78541d2005-10-28 22:53:37 +100050#include <asm/paca.h>
51#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070052
53#include "nonstdio.h"
Michael Ellermane0426042006-11-23 00:46:45 +010054#include "dis-asm.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070055
Linus Torvalds1da177e2005-04-16 15:20:36 -070056#ifdef CONFIG_SMP
Michael Ellerman1c8950f2008-05-08 14:27:17 +100057static cpumask_t cpus_in_xmon = CPU_MASK_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070058static unsigned long xmon_taken = 1;
59static int xmon_owner;
60static int xmon_gate;
Michael Ellermanddadb6b2012-09-13 23:01:31 +000061#else
62#define xmon_owner 0
Linus Torvalds1da177e2005-04-16 15:20:36 -070063#endif /* CONFIG_SMP */
64
Anton Blanchard5be34922010-01-12 00:50:14 +000065static unsigned long in_xmon __read_mostly = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
67static unsigned long adrs;
68static int size = 1;
69#define MAX_DUMP (128 * 1024)
70static unsigned long ndump = 64;
71static unsigned long nidump = 16;
72static unsigned long ncsum = 4096;
73static int termch;
74static char tmpstr[128];
75
Linus Torvalds1da177e2005-04-16 15:20:36 -070076static long bus_error_jmp[JMP_BUF_LEN];
77static int catch_memory_errors;
78static long *xmon_fault_jmp[NR_CPUS];
Linus Torvalds1da177e2005-04-16 15:20:36 -070079
80/* Breakpoint stuff */
81struct bpt {
82 unsigned long address;
83 unsigned int instr[2];
84 atomic_t ref_count;
85 int enabled;
86 unsigned long pad;
87};
88
89/* Bits in bpt.enabled */
90#define BP_IABR_TE 1 /* IABR translation enabled */
91#define BP_IABR 2
92#define BP_TRAP 8
93#define BP_DABR 0x10
94
95#define NBPTS 256
96static struct bpt bpts[NBPTS];
97static struct bpt dabr;
98static struct bpt *iabr;
99static unsigned bpinstr = 0x7fe00008; /* trap */
100
101#define BP_NUM(bp) ((bp) - bpts + 1)
102
103/* Prototypes */
104static int cmds(struct pt_regs *);
105static int mread(unsigned long, void *, int);
106static int mwrite(unsigned long, void *, int);
107static int handle_fault(struct pt_regs *);
108static void byterev(unsigned char *, int);
109static void memex(void);
110static int bsesc(void);
111static void dump(void);
112static void prdump(unsigned long, long);
113static int ppc_inst_dump(unsigned long, long, int);
Vinay Sridharf312deb2009-05-14 23:13:07 +0000114static void dump_log_buf(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115static void backtrace(struct pt_regs *);
116static void excprint(struct pt_regs *);
117static void prregs(struct pt_regs *);
118static void memops(int);
119static void memlocate(void);
120static void memzcan(void);
121static void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned);
122int skipbl(void);
123int scanhex(unsigned long *valp);
124static void scannl(void);
125static int hexdigit(int);
126void getstring(char *, int);
127static void flush_input(void);
128static int inchar(void);
129static void take_input(char *);
130static unsigned long read_spr(int);
131static void write_spr(int, unsigned long);
132static void super_regs(void);
133static void remove_bpts(void);
134static void insert_bpts(void);
135static void remove_cpu_bpts(void);
136static void insert_cpu_bpts(void);
137static struct bpt *at_breakpoint(unsigned long pc);
138static struct bpt *in_breakpoint_table(unsigned long pc, unsigned long *offp);
139static int do_step(struct pt_regs *);
140static void bpt_cmds(void);
141static void cacheflush(void);
142static int cpu_cmd(void);
143static void csum(void);
144static void bootcmds(void);
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000145static void proccall(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146void dump_segments(void);
147static void symbol_lookup(void);
Olaf Hering26c8af52006-09-08 16:29:21 +0200148static void xmon_show_stack(unsigned long sp, unsigned long lr,
149 unsigned long pc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150static void xmon_print_symbol(unsigned long address, const char *mid,
151 const char *after);
152static const char *getvecname(unsigned long vec);
153
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200154static int do_spu_cmd(void);
155
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100156#ifdef CONFIG_44x
157static void dump_tlb_44x(void);
158#endif
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +1000159#ifdef CONFIG_PPC_BOOK3E
160static void dump_tlb_book3e(void);
161#endif
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100162
Michael Ellerman9f1067c22008-05-08 14:27:16 +1000163static int xmon_no_auto_backtrace;
Olaf Hering26c8af52006-09-08 16:29:21 +0200164
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000165extern void xmon_enter(void);
166extern void xmon_leave(void);
167
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000168#ifdef CONFIG_PPC64
169#define REG "%.16lx"
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000170#else
171#define REG "%.8lx"
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000172#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173
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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407
408 bp = NULL;
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000409 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 bp = at_breakpoint(regs->nip);
Josh Boyerdaf8f402009-09-23 03:51:04 +0000411 if (bp || unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 fromipi = 0;
413
414 if (!fromipi) {
415 get_output_lock();
416 excprint(regs);
417 if (bp) {
418 printf("cpu 0x%x stopped at breakpoint 0x%x (",
419 cpu, BP_NUM(bp));
420 xmon_print_symbol(regs->nip, " ", ")\n");
421 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000422 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 printf("WARNING: exception is not recoverable, "
424 "can't continue\n");
425 release_output_lock();
426 }
427
Michael Ellermand2b496e2013-12-23 23:46:06 +1100428 cpumask_set_cpu(cpu, &cpus_in_xmon);
429
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 waiting:
431 secondary = 1;
432 while (secondary && !xmon_gate) {
433 if (in_xmon == 0) {
434 if (fromipi)
435 goto leave;
436 secondary = test_and_set_bit(0, &in_xmon);
437 }
438 barrier();
439 }
440
441 if (!secondary && !xmon_gate) {
442 /* we are the first cpu to come in */
443 /* interrupt other cpu(s) */
444 int ncpus = num_online_cpus();
445
446 xmon_owner = cpu;
447 mb();
448 if (ncpus > 1) {
Milton Millere0476372011-05-10 19:29:06 +0000449 smp_send_debugger_break();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 /* wait for other cpus to come in */
451 for (timeout = 100000000; timeout != 0; --timeout) {
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000452 if (cpumask_weight(&cpus_in_xmon) >= ncpus)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 break;
454 barrier();
455 }
456 }
457 remove_bpts();
458 disable_surveillance();
459 /* for breakpoint or single step, print the current instr. */
460 if (bp || TRAP(regs) == 0xd00)
461 ppc_inst_dump(regs->nip, 1, 0);
462 printf("enter ? for help\n");
463 mb();
464 xmon_gate = 1;
465 barrier();
466 }
467
468 cmdloop:
469 while (in_xmon) {
470 if (secondary) {
471 if (cpu == xmon_owner) {
472 if (!test_and_set_bit(0, &xmon_taken)) {
473 secondary = 0;
474 continue;
475 }
476 /* missed it */
477 while (cpu == xmon_owner)
478 barrier();
479 }
480 barrier();
481 } else {
482 cmd = cmds(regs);
483 if (cmd != 0) {
484 /* exiting xmon */
485 insert_bpts();
486 xmon_gate = 0;
487 wmb();
488 in_xmon = 0;
489 break;
490 }
491 /* have switched to some other cpu */
492 secondary = 1;
493 }
494 }
495 leave:
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000496 cpumask_clear_cpu(cpu, &cpus_in_xmon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 xmon_fault_jmp[cpu] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498#else
499 /* UP is simple... */
500 if (in_xmon) {
501 printf("Exception %lx %s in xmon, returning to main loop\n",
502 regs->trap, getvecname(TRAP(regs)));
503 longjmp(xmon_fault_jmp[0], 1);
504 }
505 if (setjmp(recurse_jmp) == 0) {
506 xmon_fault_jmp[0] = recurse_jmp;
507 in_xmon = 1;
508
509 excprint(regs);
510 bp = at_breakpoint(regs->nip);
511 if (bp) {
512 printf("Stopped at breakpoint %x (", BP_NUM(bp));
513 xmon_print_symbol(regs->nip, " ", ")\n");
514 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000515 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 printf("WARNING: exception is not recoverable, "
517 "can't continue\n");
518 remove_bpts();
519 disable_surveillance();
520 /* for breakpoint or single step, print the current instr. */
521 if (bp || TRAP(regs) == 0xd00)
522 ppc_inst_dump(regs->nip, 1, 0);
523 printf("enter ? for help\n");
524 }
525
526 cmd = cmds(regs);
527
528 insert_bpts();
529 in_xmon = 0;
530#endif
531
Josh Boyercdd39042009-10-05 04:46:05 +0000532#ifdef CONFIG_BOOKE
533 if (regs->msr & MSR_DE) {
534 bp = at_breakpoint(regs->nip);
535 if (bp != NULL) {
536 regs->nip = (unsigned long) &bp->instr[0];
537 atomic_inc(&bp->ref_count);
538 }
539 }
540#else
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000541 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 bp = at_breakpoint(regs->nip);
543 if (bp != NULL) {
544 int stepped = emulate_step(regs, bp->instr[0]);
545 if (stepped == 0) {
546 regs->nip = (unsigned long) &bp->instr[0];
547 atomic_inc(&bp->ref_count);
548 } else if (stepped < 0) {
549 printf("Couldn't single-step %s instruction\n",
550 (IS_RFID(bp->instr[0])? "rfid": "mtmsrd"));
551 }
552 }
553 }
Josh Boyercdd39042009-10-05 04:46:05 +0000554#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 insert_cpu_bpts();
556
Anton Blanchardf13659e2007-03-21 01:48:34 +1100557 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558
Paul Mackerras0a730ae2006-10-03 21:32:49 +1000559 return cmd != 'X' && cmd != EOF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560}
561
562int xmon(struct pt_regs *excp)
563{
564 struct pt_regs regs;
565
566 if (excp == NULL) {
Anton Vorontsov322b4392008-12-17 10:08:55 +0000567 ppc_save_regs(&regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 excp = &regs;
569 }
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200570
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 return xmon_core(excp, 0);
572}
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000573EXPORT_SYMBOL(xmon);
574
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000575irqreturn_t xmon_irq(int irq, void *d)
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000576{
577 unsigned long flags;
578 local_irq_save(flags);
579 printf("Keyboard interrupt\n");
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000580 xmon(get_irq_regs());
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000581 local_irq_restore(flags);
582 return IRQ_HANDLED;
583}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000585static int xmon_bpt(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586{
587 struct bpt *bp;
588 unsigned long offset;
589
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000590 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 return 0;
592
593 /* Are we at the trap at bp->instr[1] for some bp? */
594 bp = in_breakpoint_table(regs->nip, &offset);
595 if (bp != NULL && offset == 4) {
596 regs->nip = bp->address + 4;
597 atomic_dec(&bp->ref_count);
598 return 1;
599 }
600
601 /* Are we at a breakpoint? */
602 bp = at_breakpoint(regs->nip);
603 if (!bp)
604 return 0;
605
606 xmon_core(regs, 0);
607
608 return 1;
609}
610
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000611static int xmon_sstep(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612{
613 if (user_mode(regs))
614 return 0;
615 xmon_core(regs, 0);
616 return 1;
617}
618
Michael Neuling9422de32012-12-20 14:06:44 +0000619static int xmon_break_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000621 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 return 0;
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000623 if (dabr.enabled == 0)
624 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 xmon_core(regs, 0);
626 return 1;
627}
628
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000629static int xmon_iabr_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000631 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 return 0;
Michael Ellerman9f1067c22008-05-08 14:27:16 +1000633 if (iabr == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 return 0;
635 xmon_core(regs, 0);
636 return 1;
637}
638
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000639static int xmon_ipi(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640{
641#ifdef CONFIG_SMP
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000642 if (in_xmon && !cpumask_test_cpu(smp_processor_id(), &cpus_in_xmon))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 xmon_core(regs, 1);
644#endif
645 return 0;
646}
647
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000648static int xmon_fault_handler(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649{
650 struct bpt *bp;
651 unsigned long offset;
652
653 if (in_xmon && catch_memory_errors)
654 handle_fault(regs); /* doesn't return */
655
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000656 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 bp = in_breakpoint_table(regs->nip, &offset);
658 if (bp != NULL) {
659 regs->nip = bp->address + offset;
660 atomic_dec(&bp->ref_count);
661 }
662 }
663
664 return 0;
665}
666
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667static struct bpt *at_breakpoint(unsigned long pc)
668{
669 int i;
670 struct bpt *bp;
671
672 bp = bpts;
673 for (i = 0; i < NBPTS; ++i, ++bp)
674 if (bp->enabled && pc == bp->address)
675 return bp;
676 return NULL;
677}
678
679static struct bpt *in_breakpoint_table(unsigned long nip, unsigned long *offp)
680{
681 unsigned long off;
682
683 off = nip - (unsigned long) bpts;
684 if (off >= sizeof(bpts))
685 return NULL;
686 off %= sizeof(struct bpt);
687 if (off != offsetof(struct bpt, instr[0])
688 && off != offsetof(struct bpt, instr[1]))
689 return NULL;
690 *offp = off - offsetof(struct bpt, instr[0]);
691 return (struct bpt *) (nip - off);
692}
693
694static struct bpt *new_breakpoint(unsigned long a)
695{
696 struct bpt *bp;
697
698 a &= ~3UL;
699 bp = at_breakpoint(a);
700 if (bp)
701 return bp;
702
703 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
704 if (!bp->enabled && atomic_read(&bp->ref_count) == 0) {
705 bp->address = a;
706 bp->instr[1] = bpinstr;
707 store_inst(&bp->instr[1]);
708 return bp;
709 }
710 }
711
712 printf("Sorry, no free breakpoints. Please clear one first.\n");
713 return NULL;
714}
715
716static void insert_bpts(void)
717{
718 int i;
719 struct bpt *bp;
720
721 bp = bpts;
722 for (i = 0; i < NBPTS; ++i, ++bp) {
723 if ((bp->enabled & (BP_TRAP|BP_IABR)) == 0)
724 continue;
725 if (mread(bp->address, &bp->instr[0], 4) != 4) {
726 printf("Couldn't read instruction at %lx, "
727 "disabling breakpoint there\n", bp->address);
728 bp->enabled = 0;
729 continue;
730 }
731 if (IS_MTMSRD(bp->instr[0]) || IS_RFID(bp->instr[0])) {
732 printf("Breakpoint at %lx is on an mtmsrd or rfid "
733 "instruction, disabling it\n", bp->address);
734 bp->enabled = 0;
735 continue;
736 }
737 store_inst(&bp->instr[0]);
738 if (bp->enabled & BP_IABR)
739 continue;
740 if (mwrite(bp->address, &bpinstr, 4) != 4) {
741 printf("Couldn't write instruction at %lx, "
742 "disabling breakpoint there\n", bp->address);
743 bp->enabled &= ~BP_TRAP;
744 continue;
745 }
746 store_inst((void *)bp->address);
747 }
748}
749
750static void insert_cpu_bpts(void)
751{
Michael Neuling9422de32012-12-20 14:06:44 +0000752 struct arch_hw_breakpoint brk;
753
754 if (dabr.enabled) {
755 brk.address = dabr.address;
756 brk.type = (dabr.enabled & HW_BRK_TYPE_DABR) | HW_BRK_TYPE_PRIV_ALL;
757 brk.len = 8;
Michael Neulingb9818c32013-01-10 14:25:34 +0000758 set_breakpoint(&brk);
Michael Neuling9422de32012-12-20 14:06:44 +0000759 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 if (iabr && cpu_has_feature(CPU_FTR_IABR))
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000761 mtspr(SPRN_IABR, iabr->address
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 | (iabr->enabled & (BP_IABR|BP_IABR_TE)));
763}
764
765static void remove_bpts(void)
766{
767 int i;
768 struct bpt *bp;
769 unsigned instr;
770
771 bp = bpts;
772 for (i = 0; i < NBPTS; ++i, ++bp) {
773 if ((bp->enabled & (BP_TRAP|BP_IABR)) != BP_TRAP)
774 continue;
775 if (mread(bp->address, &instr, 4) == 4
776 && instr == bpinstr
777 && mwrite(bp->address, &bp->instr, 4) != 4)
778 printf("Couldn't remove breakpoint at %lx\n",
779 bp->address);
780 else
781 store_inst((void *)bp->address);
782 }
783}
784
785static void remove_cpu_bpts(void)
786{
Michael Neuling9422de32012-12-20 14:06:44 +0000787 hw_breakpoint_disable();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 if (cpu_has_feature(CPU_FTR_IABR))
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000789 mtspr(SPRN_IABR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790}
791
792/* Command interpreting routine */
793static char *last_cmd;
794
795static int
796cmds(struct pt_regs *excp)
797{
798 int cmd = 0;
799
800 last_cmd = NULL;
801 xmon_regs = excp;
Olaf Hering26c8af52006-09-08 16:29:21 +0200802
803 if (!xmon_no_auto_backtrace) {
804 xmon_no_auto_backtrace = 1;
805 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
806 }
807
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 for(;;) {
809#ifdef CONFIG_SMP
810 printf("%x:", smp_processor_id());
811#endif /* CONFIG_SMP */
812 printf("mon> ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 flush_input();
814 termch = 0;
815 cmd = skipbl();
816 if( cmd == '\n' ) {
817 if (last_cmd == NULL)
818 continue;
819 take_input(last_cmd);
820 last_cmd = NULL;
821 cmd = inchar();
822 }
823 switch (cmd) {
824 case 'm':
825 cmd = inchar();
826 switch (cmd) {
827 case 'm':
828 case 's':
829 case 'd':
830 memops(cmd);
831 break;
832 case 'l':
833 memlocate();
834 break;
835 case 'z':
836 memzcan();
837 break;
838 case 'i':
David Rientjesb2b755b2011-03-24 15:18:15 -0700839 show_mem(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 break;
841 default:
842 termch = cmd;
843 memex();
844 }
845 break;
846 case 'd':
847 dump();
848 break;
849 case 'l':
850 symbol_lookup();
851 break;
852 case 'r':
853 prregs(excp); /* print regs */
854 break;
855 case 'e':
856 excprint(excp);
857 break;
858 case 'S':
859 super_regs();
860 break;
861 case 't':
862 backtrace(excp);
863 break;
864 case 'f':
865 cacheflush();
866 break;
867 case 's':
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200868 if (do_spu_cmd() == 0)
869 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 if (do_step(excp))
871 return cmd;
872 break;
873 case 'x':
874 case 'X':
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100875 return cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 case EOF:
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100877 printf(" <no input ...>\n");
878 mdelay(2000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 return cmd;
880 case '?':
Ishizaki Kou4d404ed2007-07-18 19:26:40 +1000881 xmon_puts(help_string);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 case 'b':
884 bpt_cmds();
885 break;
886 case 'C':
887 csum();
888 break;
889 case 'c':
890 if (cpu_cmd())
891 return 0;
892 break;
893 case 'z':
894 bootcmds();
895 break;
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000896 case 'p':
897 proccall();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 break;
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000899#ifdef CONFIG_PPC_STD_MMU
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 case 'u':
901 dump_segments();
902 break;
Jimi Xenidis79873e82011-09-29 11:25:10 +0000903#elif defined(CONFIG_4xx)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100904 case 'u':
905 dump_tlb_44x();
906 break;
Jimi Xenidis79873e82011-09-29 11:25:10 +0000907#elif defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +1000908 case 'u':
909 dump_tlb_book3e();
910 break;
911#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 default:
913 printf("Unrecognized command: ");
Michael Ellermane3bc8042012-08-23 22:09:13 +0000914 do {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 if (' ' < cmd && cmd <= '~')
916 putchar(cmd);
917 else
918 printf("\\x%x", cmd);
919 cmd = inchar();
Michael Ellermane3bc8042012-08-23 22:09:13 +0000920 } while (cmd != '\n');
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 printf(" (type ? for help)\n");
922 break;
923 }
924 }
925}
926
Josh Boyercdd39042009-10-05 04:46:05 +0000927#ifdef CONFIG_BOOKE
928static int do_step(struct pt_regs *regs)
929{
930 regs->msr |= MSR_DE;
931 mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
932 return 1;
933}
934#else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935/*
936 * Step a single instruction.
937 * Some instructions we emulate, others we execute with MSR_SE set.
938 */
939static int do_step(struct pt_regs *regs)
940{
941 unsigned int instr;
942 int stepped;
943
944 /* check we are in 64-bit kernel mode, translation enabled */
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000945 if ((regs->msr & (MSR_64BIT|MSR_PR|MSR_IR)) == (MSR_64BIT|MSR_IR)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 if (mread(regs->nip, &instr, 4) == 4) {
947 stepped = emulate_step(regs, instr);
948 if (stepped < 0) {
949 printf("Couldn't single-step %s instruction\n",
950 (IS_RFID(instr)? "rfid": "mtmsrd"));
951 return 0;
952 }
953 if (stepped > 0) {
954 regs->trap = 0xd00 | (regs->trap & 1);
955 printf("stepped to ");
956 xmon_print_symbol(regs->nip, " ", "\n");
957 ppc_inst_dump(regs->nip, 1, 0);
958 return 0;
959 }
960 }
961 }
962 regs->msr |= MSR_SE;
963 return 1;
964}
Josh Boyercdd39042009-10-05 04:46:05 +0000965#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966
967static void bootcmds(void)
968{
969 int cmd;
970
971 cmd = inchar();
972 if (cmd == 'r')
973 ppc_md.restart(NULL);
974 else if (cmd == 'h')
975 ppc_md.halt();
976 else if (cmd == 'p')
977 ppc_md.power_off();
978}
979
980static int cpu_cmd(void)
981{
982#ifdef CONFIG_SMP
Paul Mackerrasfd3bb912013-09-03 20:16:23 +1000983 unsigned long cpu, first_cpu, last_cpu;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 int timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985
986 if (!scanhex(&cpu)) {
987 /* print cpus waiting or in xmon */
988 printf("cpus stopped:");
Paul Mackerrasfd3bb912013-09-03 20:16:23 +1000989 last_cpu = first_cpu = NR_CPUS;
Anton Blanchardbc1d7702012-06-28 19:28:57 +0000990 for_each_possible_cpu(cpu) {
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000991 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Paul Mackerrasfd3bb912013-09-03 20:16:23 +1000992 if (cpu == last_cpu + 1) {
993 last_cpu = cpu;
994 } else {
995 if (last_cpu != first_cpu)
996 printf("-%lx", last_cpu);
997 last_cpu = first_cpu = cpu;
998 printf(" %lx", cpu);
999 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 }
1001 }
Paul Mackerrasfd3bb912013-09-03 20:16:23 +10001002 if (last_cpu != first_cpu)
1003 printf("-%lx", last_cpu);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 printf("\n");
1005 return 0;
1006 }
1007 /* try to switch to cpu specified */
KOSAKI Motohiro104699c2011-04-28 05:07:23 +00001008 if (!cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 printf("cpu 0x%x isn't in xmon\n", cpu);
1010 return 0;
1011 }
1012 xmon_taken = 0;
1013 mb();
1014 xmon_owner = cpu;
1015 timeout = 10000000;
1016 while (!xmon_taken) {
1017 if (--timeout == 0) {
1018 if (test_and_set_bit(0, &xmon_taken))
1019 break;
1020 /* take control back */
1021 mb();
1022 xmon_owner = smp_processor_id();
1023 printf("cpu %u didn't take control\n", cpu);
1024 return 0;
1025 }
1026 barrier();
1027 }
1028 return 1;
1029#else
1030 return 0;
1031#endif /* CONFIG_SMP */
1032}
1033
1034static unsigned short fcstab[256] = {
1035 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
1036 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
1037 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
1038 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
1039 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
1040 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
1041 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
1042 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
1043 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
1044 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
1045 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
1046 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
1047 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
1048 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
1049 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
1050 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
1051 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
1052 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
1053 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
1054 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
1055 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
1056 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
1057 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
1058 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
1059 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
1060 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
1061 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
1062 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
1063 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
1064 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
1065 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
1066 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
1067};
1068
1069#define FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
1070
1071static void
1072csum(void)
1073{
1074 unsigned int i;
1075 unsigned short fcs;
1076 unsigned char v;
1077
1078 if (!scanhex(&adrs))
1079 return;
1080 if (!scanhex(&ncsum))
1081 return;
1082 fcs = 0xffff;
1083 for (i = 0; i < ncsum; ++i) {
1084 if (mread(adrs+i, &v, 1) == 0) {
1085 printf("csum stopped at %x\n", adrs+i);
1086 break;
1087 }
1088 fcs = FCS(fcs, v);
1089 }
1090 printf("%x\n", fcs);
1091}
1092
1093/*
1094 * Check if this is a suitable place to put a breakpoint.
1095 */
1096static long check_bp_loc(unsigned long addr)
1097{
1098 unsigned int instr;
1099
1100 addr &= ~3;
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001101 if (!is_kernel_addr(addr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 printf("Breakpoints may only be placed at kernel addresses\n");
1103 return 0;
1104 }
1105 if (!mread(addr, &instr, sizeof(instr))) {
1106 printf("Can't read instruction at address %lx\n", addr);
1107 return 0;
1108 }
1109 if (IS_MTMSRD(instr) || IS_RFID(instr)) {
1110 printf("Breakpoints may not be placed on mtmsrd or rfid "
1111 "instructions\n");
1112 return 0;
1113 }
1114 return 1;
1115}
1116
Michael Ellermane3bc8042012-08-23 22:09:13 +00001117static char *breakpoint_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 "Breakpoint command usage:\n"
1119 "b show breakpoints\n"
1120 "b <addr> [cnt] set breakpoint at given instr addr\n"
1121 "bc clear all breakpoints\n"
1122 "bc <n/addr> clear breakpoint number n or at addr\n"
1123 "bi <addr> [cnt] set hardware instr breakpoint (POWER3/RS64 only)\n"
1124 "bd <addr> [cnt] set hardware data breakpoint\n"
1125 "";
1126
1127static void
1128bpt_cmds(void)
1129{
1130 int cmd;
1131 unsigned long a;
1132 int mode, i;
1133 struct bpt *bp;
1134 const char badaddr[] = "Only kernel addresses are permitted "
1135 "for breakpoints\n";
1136
1137 cmd = inchar();
1138 switch (cmd) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001139#ifndef CONFIG_8xx
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 case 'd': /* bd - hardware data breakpoint */
1141 mode = 7;
1142 cmd = inchar();
1143 if (cmd == 'r')
1144 mode = 5;
1145 else if (cmd == 'w')
1146 mode = 6;
1147 else
1148 termch = cmd;
1149 dabr.address = 0;
1150 dabr.enabled = 0;
1151 if (scanhex(&dabr.address)) {
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001152 if (!is_kernel_addr(dabr.address)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 printf(badaddr);
1154 break;
1155 }
Michael Neuling9422de32012-12-20 14:06:44 +00001156 dabr.address &= ~HW_BRK_TYPE_DABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 dabr.enabled = mode | BP_DABR;
1158 }
1159 break;
1160
1161 case 'i': /* bi - hardware instr breakpoint */
1162 if (!cpu_has_feature(CPU_FTR_IABR)) {
1163 printf("Hardware instruction breakpoint "
1164 "not supported on this cpu\n");
1165 break;
1166 }
1167 if (iabr) {
1168 iabr->enabled &= ~(BP_IABR | BP_IABR_TE);
1169 iabr = NULL;
1170 }
1171 if (!scanhex(&a))
1172 break;
1173 if (!check_bp_loc(a))
1174 break;
1175 bp = new_breakpoint(a);
1176 if (bp != NULL) {
1177 bp->enabled |= BP_IABR | BP_IABR_TE;
1178 iabr = bp;
1179 }
1180 break;
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001181#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182
1183 case 'c':
1184 if (!scanhex(&a)) {
1185 /* clear all breakpoints */
1186 for (i = 0; i < NBPTS; ++i)
1187 bpts[i].enabled = 0;
1188 iabr = NULL;
1189 dabr.enabled = 0;
1190 printf("All breakpoints cleared\n");
1191 break;
1192 }
1193
1194 if (a <= NBPTS && a >= 1) {
1195 /* assume a breakpoint number */
1196 bp = &bpts[a-1]; /* bp nums are 1 based */
1197 } else {
1198 /* assume a breakpoint address */
1199 bp = at_breakpoint(a);
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001200 if (bp == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 printf("No breakpoint at %x\n", a);
1202 break;
1203 }
1204 }
1205
1206 printf("Cleared breakpoint %x (", BP_NUM(bp));
1207 xmon_print_symbol(bp->address, " ", ")\n");
1208 bp->enabled = 0;
1209 break;
1210
1211 default:
1212 termch = cmd;
Michael Ellermane3bc8042012-08-23 22:09:13 +00001213 cmd = skipbl();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214 if (cmd == '?') {
1215 printf(breakpoint_help_string);
1216 break;
1217 }
1218 termch = cmd;
1219 if (!scanhex(&a)) {
1220 /* print all breakpoints */
1221 printf(" type address\n");
1222 if (dabr.enabled) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001223 printf(" data "REG" [", dabr.address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 if (dabr.enabled & 1)
1225 printf("r");
1226 if (dabr.enabled & 2)
1227 printf("w");
1228 printf("]\n");
1229 }
1230 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
1231 if (!bp->enabled)
1232 continue;
1233 printf("%2x %s ", BP_NUM(bp),
1234 (bp->enabled & BP_IABR)? "inst": "trap");
1235 xmon_print_symbol(bp->address, " ", "\n");
1236 }
1237 break;
1238 }
1239
1240 if (!check_bp_loc(a))
1241 break;
1242 bp = new_breakpoint(a);
1243 if (bp != NULL)
1244 bp->enabled |= BP_TRAP;
1245 break;
1246 }
1247}
1248
1249/* Very cheap human name for vector lookup. */
1250static
1251const char *getvecname(unsigned long vec)
1252{
1253 char *ret;
1254
1255 switch (vec) {
1256 case 0x100: ret = "(System Reset)"; break;
1257 case 0x200: ret = "(Machine Check)"; break;
1258 case 0x300: ret = "(Data Access)"; break;
1259 case 0x380: ret = "(Data SLB Access)"; break;
1260 case 0x400: ret = "(Instruction Access)"; break;
1261 case 0x480: ret = "(Instruction SLB Access)"; break;
1262 case 0x500: ret = "(Hardware Interrupt)"; break;
1263 case 0x600: ret = "(Alignment)"; break;
1264 case 0x700: ret = "(Program Check)"; break;
1265 case 0x800: ret = "(FPU Unavailable)"; break;
1266 case 0x900: ret = "(Decrementer)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001267 case 0x980: ret = "(Hypervisor Decrementer)"; break;
1268 case 0xa00: ret = "(Doorbell)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269 case 0xc00: ret = "(System Call)"; break;
1270 case 0xd00: ret = "(Single Step)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001271 case 0xe40: ret = "(Emulation Assist)"; break;
1272 case 0xe60: ret = "(HMI)"; break;
1273 case 0xe80: ret = "(Hypervisor Doorbell)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 case 0xf00: ret = "(Performance Monitor)"; break;
1275 case 0xf20: ret = "(Altivec Unavailable)"; break;
1276 case 0x1300: ret = "(Instruction Breakpoint)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001277 case 0x1500: ret = "(Denormalisation)"; break;
1278 case 0x1700: ret = "(Altivec Assist)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279 default: ret = "";
1280 }
1281 return ret;
1282}
1283
1284static void get_function_bounds(unsigned long pc, unsigned long *startp,
1285 unsigned long *endp)
1286{
1287 unsigned long size, offset;
1288 const char *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289
1290 *startp = *endp = 0;
1291 if (pc == 0)
1292 return;
1293 if (setjmp(bus_error_jmp) == 0) {
1294 catch_memory_errors = 1;
1295 sync();
Alexey Dobriyanffb45122007-05-08 00:28:41 -07001296 name = kallsyms_lookup(pc, &size, &offset, NULL, tmpstr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 if (name != NULL) {
1298 *startp = pc - offset;
1299 *endp = pc - offset + size;
1300 }
1301 sync();
1302 }
1303 catch_memory_errors = 0;
1304}
1305
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001306#define LRSAVE_OFFSET (STACK_FRAME_LR_SAVE * sizeof(unsigned long))
1307#define MARKER_OFFSET (STACK_FRAME_MARKER * sizeof(unsigned long))
1308
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309static void xmon_show_stack(unsigned long sp, unsigned long lr,
1310 unsigned long pc)
1311{
Michael Ellerman0104cd62012-10-09 04:20:36 +00001312 int max_to_print = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 unsigned long ip;
1314 unsigned long newsp;
1315 unsigned long marker;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 struct pt_regs regs;
1317
Michael Ellerman0104cd62012-10-09 04:20:36 +00001318 while (max_to_print--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 if (sp < PAGE_OFFSET) {
1320 if (sp != 0)
1321 printf("SP (%lx) is in userspace\n", sp);
1322 break;
1323 }
1324
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001325 if (!mread(sp + LRSAVE_OFFSET, &ip, sizeof(unsigned long))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 || !mread(sp, &newsp, sizeof(unsigned long))) {
1327 printf("Couldn't read stack frame at %lx\n", sp);
1328 break;
1329 }
1330
1331 /*
1332 * For the first stack frame, try to work out if
1333 * LR and/or the saved LR value in the bottommost
1334 * stack frame are valid.
1335 */
1336 if ((pc | lr) != 0) {
1337 unsigned long fnstart, fnend;
1338 unsigned long nextip;
1339 int printip = 1;
1340
1341 get_function_bounds(pc, &fnstart, &fnend);
1342 nextip = 0;
1343 if (newsp > sp)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001344 mread(newsp + LRSAVE_OFFSET, &nextip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 sizeof(unsigned long));
1346 if (lr == ip) {
1347 if (lr < PAGE_OFFSET
1348 || (fnstart <= lr && lr < fnend))
1349 printip = 0;
1350 } else if (lr == nextip) {
1351 printip = 0;
1352 } else if (lr >= PAGE_OFFSET
1353 && !(fnstart <= lr && lr < fnend)) {
1354 printf("[link register ] ");
1355 xmon_print_symbol(lr, " ", "\n");
1356 }
1357 if (printip) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001358 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 xmon_print_symbol(ip, " ", " (unreliable)\n");
1360 }
1361 pc = lr = 0;
1362
1363 } else {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001364 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 xmon_print_symbol(ip, " ", "\n");
1366 }
1367
1368 /* Look for "regshere" marker to see if this is
1369 an exception frame. */
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001370 if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long))
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001371 && marker == STACK_FRAME_REGS_MARKER) {
Michael Ellermanc4de3802012-10-09 04:20:35 +00001372 if (mread(sp + STACK_FRAME_OVERHEAD, &regs, sizeof(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 != sizeof(regs)) {
1374 printf("Couldn't read registers at %lx\n",
Michael Ellermanc4de3802012-10-09 04:20:35 +00001375 sp + STACK_FRAME_OVERHEAD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 break;
1377 }
Michael Ellermane3bc8042012-08-23 22:09:13 +00001378 printf("--- Exception: %lx %s at ", regs.trap,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 getvecname(TRAP(&regs)));
1380 pc = regs.nip;
1381 lr = regs.link;
1382 xmon_print_symbol(pc, " ", "\n");
1383 }
1384
1385 if (newsp == 0)
1386 break;
1387
1388 sp = newsp;
Michael Ellerman0104cd62012-10-09 04:20:36 +00001389 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390}
1391
1392static void backtrace(struct pt_regs *excp)
1393{
1394 unsigned long sp;
1395
1396 if (scanhex(&sp))
1397 xmon_show_stack(sp, 0, 0);
1398 else
1399 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
1400 scannl();
1401}
1402
1403static void print_bug_trap(struct pt_regs *regs)
1404{
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001405#ifdef CONFIG_BUG
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001406 const struct bug_entry *bug;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 unsigned long addr;
1408
1409 if (regs->msr & MSR_PR)
1410 return; /* not in kernel */
1411 addr = regs->nip; /* address of trap instruction */
1412 if (addr < PAGE_OFFSET)
1413 return;
1414 bug = find_bug(regs->nip);
1415 if (bug == NULL)
1416 return;
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001417 if (is_warning_bug(bug))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418 return;
1419
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001420#ifdef CONFIG_DEBUG_BUGVERBOSE
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001421 printf("kernel BUG at %s:%u!\n",
1422 bug->file, bug->line);
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001423#else
1424 printf("kernel BUG at %p!\n", (void *)bug->bug_addr);
1425#endif
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001426#endif /* CONFIG_BUG */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427}
1428
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001429static void excprint(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430{
1431 unsigned long trap;
1432
1433#ifdef CONFIG_SMP
1434 printf("cpu 0x%x: ", smp_processor_id());
1435#endif /* CONFIG_SMP */
1436
1437 trap = TRAP(fp);
1438 printf("Vector: %lx %s at [%lx]\n", fp->trap, getvecname(trap), fp);
1439 printf(" pc: ");
1440 xmon_print_symbol(fp->nip, ": ", "\n");
1441
1442 printf(" lr: ", fp->link);
1443 xmon_print_symbol(fp->link, ": ", "\n");
1444
1445 printf(" sp: %lx\n", fp->gpr[1]);
1446 printf(" msr: %lx\n", fp->msr);
1447
Aneesh Kumar K.Vce541522013-04-28 09:37:26 +00001448 if (trap == 0x300 || trap == 0x380 || trap == 0x600 || trap == 0x200) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 printf(" dar: %lx\n", fp->dar);
1450 if (trap != 0x380)
1451 printf(" dsisr: %lx\n", fp->dsisr);
1452 }
1453
1454 printf(" current = 0x%lx\n", current);
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001455#ifdef CONFIG_PPC64
Benjamin Herrenschmidt7230c562012-03-06 18:27:59 +11001456 printf(" paca = 0x%lx\t softe: %d\t irq_happened: 0x%02x\n",
1457 local_paca, local_paca->soft_enabled, local_paca->irq_happened);
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001458#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 if (current) {
1460 printf(" pid = %ld, comm = %s\n",
1461 current->pid, current->comm);
1462 }
1463
1464 if (trap == 0x700)
1465 print_bug_trap(fp);
1466}
1467
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001468static void prregs(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469{
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001470 int n, trap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471 unsigned long base;
1472 struct pt_regs regs;
1473
1474 if (scanhex(&base)) {
1475 if (setjmp(bus_error_jmp) == 0) {
1476 catch_memory_errors = 1;
1477 sync();
1478 regs = *(struct pt_regs *)base;
1479 sync();
1480 __delay(200);
1481 } else {
1482 catch_memory_errors = 0;
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001483 printf("*** Error reading registers from "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484 base);
1485 return;
1486 }
1487 catch_memory_errors = 0;
1488 fp = &regs;
1489 }
1490
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001491#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 if (FULL_REGS(fp)) {
1493 for (n = 0; n < 16; ++n)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001494 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 n, fp->gpr[n], n+16, fp->gpr[n+16]);
1496 } else {
1497 for (n = 0; n < 7; ++n)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001498 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 n, fp->gpr[n], n+7, fp->gpr[n+7]);
1500 }
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001501#else
1502 for (n = 0; n < 32; ++n) {
1503 printf("R%.2d = %.8x%s", n, fp->gpr[n],
1504 (n & 3) == 3? "\n": " ");
1505 if (n == 12 && !FULL_REGS(fp)) {
1506 printf("\n");
1507 break;
1508 }
1509 }
1510#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 printf("pc = ");
1512 xmon_print_symbol(fp->nip, " ", "\n");
Paul Mackerras48404f22011-05-01 19:48:20 +00001513 if (TRAP(fp) != 0xc00 && cpu_has_feature(CPU_FTR_CFAR)) {
1514 printf("cfar= ");
1515 xmon_print_symbol(fp->orig_gpr3, " ", "\n");
1516 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517 printf("lr = ");
1518 xmon_print_symbol(fp->link, " ", "\n");
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001519 printf("msr = "REG" cr = %.8lx\n", fp->msr, fp->ccr);
1520 printf("ctr = "REG" xer = "REG" trap = %4lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 fp->ctr, fp->xer, fp->trap);
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001522 trap = TRAP(fp);
1523 if (trap == 0x300 || trap == 0x380 || trap == 0x600)
1524 printf("dar = "REG" dsisr = %.8lx\n", fp->dar, fp->dsisr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525}
1526
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001527static void cacheflush(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528{
1529 int cmd;
1530 unsigned long nflush;
1531
1532 cmd = inchar();
1533 if (cmd != 'i')
1534 termch = cmd;
1535 scanhex((void *)&adrs);
1536 if (termch != '\n')
1537 termch = 0;
1538 nflush = 1;
1539 scanhex(&nflush);
1540 nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES;
1541 if (setjmp(bus_error_jmp) == 0) {
1542 catch_memory_errors = 1;
1543 sync();
1544
1545 if (cmd != 'i') {
1546 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1547 cflush((void *) adrs);
1548 } else {
1549 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1550 cinval((void *) adrs);
1551 }
1552 sync();
1553 /* wait a little while to see if we get a machine check */
1554 __delay(200);
1555 }
1556 catch_memory_errors = 0;
1557}
1558
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001559static unsigned long
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560read_spr(int n)
1561{
1562 unsigned int instrs[2];
1563 unsigned long (*code)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 unsigned long ret = -1UL;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001565#ifdef CONFIG_PPC64
1566 unsigned long opd[3];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568 opd[0] = (unsigned long)instrs;
1569 opd[1] = 0;
1570 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001571 code = (unsigned long (*)(void)) opd;
1572#else
1573 code = (unsigned long (*)(void)) instrs;
1574#endif
1575
1576 /* mfspr r3,n; blr */
1577 instrs[0] = 0x7c6002a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1578 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 store_inst(instrs);
1580 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581
1582 if (setjmp(bus_error_jmp) == 0) {
1583 catch_memory_errors = 1;
1584 sync();
1585
1586 ret = code();
1587
1588 sync();
1589 /* wait a little while to see if we get a machine check */
1590 __delay(200);
1591 n = size;
1592 }
1593
1594 return ret;
1595}
1596
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001597static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598write_spr(int n, unsigned long val)
1599{
1600 unsigned int instrs[2];
1601 unsigned long (*code)(unsigned long);
Paul Mackerras548cceb2005-11-11 22:36:34 +11001602#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 unsigned long opd[3];
1604
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605 opd[0] = (unsigned long)instrs;
1606 opd[1] = 0;
1607 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001608 code = (unsigned long (*)(unsigned long)) opd;
1609#else
1610 code = (unsigned long (*)(unsigned long)) instrs;
1611#endif
1612
1613 instrs[0] = 0x7c6003a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1614 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 store_inst(instrs);
1616 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617
1618 if (setjmp(bus_error_jmp) == 0) {
1619 catch_memory_errors = 1;
1620 sync();
1621
1622 code(val);
1623
1624 sync();
1625 /* wait a little while to see if we get a machine check */
1626 __delay(200);
1627 n = size;
1628 }
1629}
1630
1631static unsigned long regno;
1632extern char exc_prolog;
1633extern char dec_exc;
1634
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001635static void super_regs(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636{
1637 int cmd;
1638 unsigned long val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639
1640 cmd = skipbl();
1641 if (cmd == '\n') {
Michael Ellermane3bc8042012-08-23 22:09:13 +00001642 unsigned long sp, toc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 asm("mr %0,1" : "=r" (sp) :);
1644 asm("mr %0,2" : "=r" (toc) :);
1645
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001646 printf("msr = "REG" sprg0= "REG"\n",
1647 mfmsr(), mfspr(SPRN_SPRG0));
1648 printf("pvr = "REG" sprg1= "REG"\n",
Michael Ellermane3bc8042012-08-23 22:09:13 +00001649 mfspr(SPRN_PVR), mfspr(SPRN_SPRG1));
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001650 printf("dec = "REG" sprg2= "REG"\n",
1651 mfspr(SPRN_DEC), mfspr(SPRN_SPRG2));
1652 printf("sp = "REG" sprg3= "REG"\n", sp, mfspr(SPRN_SPRG3));
1653 printf("toc = "REG" dar = "REG"\n", toc, mfspr(SPRN_DAR));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654
1655 return;
1656 }
1657
1658 scanhex(&regno);
1659 switch (cmd) {
1660 case 'w':
1661 val = read_spr(regno);
1662 scanhex(&val);
1663 write_spr(regno, val);
1664 /* fall through */
1665 case 'r':
1666 printf("spr %lx = %lx\n", regno, read_spr(regno));
1667 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 }
1669 scannl();
1670}
1671
1672/*
1673 * Stuff for reading and writing memory safely
1674 */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001675static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676mread(unsigned long adrs, void *buf, int size)
1677{
1678 volatile int n;
1679 char *p, *q;
1680
1681 n = 0;
1682 if (setjmp(bus_error_jmp) == 0) {
1683 catch_memory_errors = 1;
1684 sync();
1685 p = (char *)adrs;
1686 q = (char *)buf;
1687 switch (size) {
1688 case 2:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001689 *(u16 *)q = *(u16 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 break;
1691 case 4:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001692 *(u32 *)q = *(u32 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 break;
1694 case 8:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001695 *(u64 *)q = *(u64 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 break;
1697 default:
1698 for( ; n < size; ++n) {
1699 *q++ = *p++;
1700 sync();
1701 }
1702 }
1703 sync();
1704 /* wait a little while to see if we get a machine check */
1705 __delay(200);
1706 n = size;
1707 }
1708 catch_memory_errors = 0;
1709 return n;
1710}
1711
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001712static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713mwrite(unsigned long adrs, void *buf, int size)
1714{
1715 volatile int n;
1716 char *p, *q;
1717
1718 n = 0;
1719 if (setjmp(bus_error_jmp) == 0) {
1720 catch_memory_errors = 1;
1721 sync();
1722 p = (char *) adrs;
1723 q = (char *) buf;
1724 switch (size) {
1725 case 2:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001726 *(u16 *)p = *(u16 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 break;
1728 case 4:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001729 *(u32 *)p = *(u32 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 break;
1731 case 8:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001732 *(u64 *)p = *(u64 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 break;
1734 default:
1735 for ( ; n < size; ++n) {
1736 *p++ = *q++;
1737 sync();
1738 }
1739 }
1740 sync();
1741 /* wait a little while to see if we get a machine check */
1742 __delay(200);
1743 n = size;
1744 } else {
1745 printf("*** Error writing address %x\n", adrs + n);
1746 }
1747 catch_memory_errors = 0;
1748 return n;
1749}
1750
1751static int fault_type;
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001752static int fault_except;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753static char *fault_chars[] = { "--", "**", "##" };
1754
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001755static int handle_fault(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756{
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001757 fault_except = TRAP(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 switch (TRAP(regs)) {
1759 case 0x200:
1760 fault_type = 0;
1761 break;
1762 case 0x300:
1763 case 0x380:
1764 fault_type = 1;
1765 break;
1766 default:
1767 fault_type = 2;
1768 }
1769
1770 longjmp(bus_error_jmp, 1);
1771
1772 return 0;
1773}
1774
1775#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t))
1776
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001777static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778byterev(unsigned char *val, int size)
1779{
1780 int t;
1781
1782 switch (size) {
1783 case 2:
1784 SWAP(val[0], val[1], t);
1785 break;
1786 case 4:
1787 SWAP(val[0], val[3], t);
1788 SWAP(val[1], val[2], t);
1789 break;
1790 case 8: /* is there really any use for this? */
1791 SWAP(val[0], val[7], t);
1792 SWAP(val[1], val[6], t);
1793 SWAP(val[2], val[5], t);
1794 SWAP(val[3], val[4], t);
1795 break;
1796 }
1797}
1798
1799static int brev;
1800static int mnoread;
1801
Michael Ellermane3bc8042012-08-23 22:09:13 +00001802static char *memex_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803 "Memory examine command usage:\n"
1804 "m [addr] [flags] examine/change memory\n"
1805 " addr is optional. will start where left off.\n"
1806 " flags may include chars from this set:\n"
1807 " b modify by bytes (default)\n"
1808 " w modify by words (2 byte)\n"
1809 " l modify by longs (4 byte)\n"
1810 " d modify by doubleword (8 byte)\n"
1811 " r toggle reverse byte order mode\n"
1812 " n do not read memory (for i/o spaces)\n"
1813 " . ok to read (default)\n"
1814 "NOTE: flags are saved as defaults\n"
1815 "";
1816
Michael Ellermane3bc8042012-08-23 22:09:13 +00001817static char *memex_subcmd_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818 "Memory examine subcommands:\n"
1819 " hexval write this val to current location\n"
1820 " 'string' write chars from string to this location\n"
1821 " ' increment address\n"
1822 " ^ decrement address\n"
1823 " / increment addr by 0x10. //=0x100, ///=0x1000, etc\n"
1824 " \\ decrement addr by 0x10. \\\\=0x100, \\\\\\=0x1000, etc\n"
1825 " ` clear no-read flag\n"
1826 " ; stay at this addr\n"
1827 " v change to byte mode\n"
1828 " w change to word (2 byte) mode\n"
1829 " l change to long (4 byte) mode\n"
1830 " u change to doubleword (8 byte) mode\n"
1831 " m addr change current addr\n"
1832 " n toggle no-read flag\n"
1833 " r toggle byte reverse flag\n"
1834 " < count back up count bytes\n"
1835 " > count skip forward count bytes\n"
1836 " x exit this mode\n"
1837 "";
1838
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001839static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840memex(void)
1841{
1842 int cmd, inc, i, nslash;
1843 unsigned long n;
1844 unsigned char val[16];
1845
1846 scanhex((void *)&adrs);
1847 cmd = skipbl();
1848 if (cmd == '?') {
1849 printf(memex_help_string);
1850 return;
1851 } else {
1852 termch = cmd;
1853 }
1854 last_cmd = "m\n";
1855 while ((cmd = skipbl()) != '\n') {
1856 switch( cmd ){
1857 case 'b': size = 1; break;
1858 case 'w': size = 2; break;
1859 case 'l': size = 4; break;
1860 case 'd': size = 8; break;
1861 case 'r': brev = !brev; break;
1862 case 'n': mnoread = 1; break;
1863 case '.': mnoread = 0; break;
1864 }
1865 }
1866 if( size <= 0 )
1867 size = 1;
1868 else if( size > 8 )
1869 size = 8;
1870 for(;;){
1871 if (!mnoread)
1872 n = mread(adrs, val, size);
Paul Mackerrase1449ed2005-11-10 14:30:20 +11001873 printf(REG"%c", adrs, brev? 'r': ' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 if (!mnoread) {
1875 if (brev)
1876 byterev(val, size);
1877 putchar(' ');
1878 for (i = 0; i < n; ++i)
1879 printf("%.2x", val[i]);
1880 for (; i < size; ++i)
1881 printf("%s", fault_chars[fault_type]);
1882 }
1883 putchar(' ');
1884 inc = size;
1885 nslash = 0;
1886 for(;;){
1887 if( scanhex(&n) ){
1888 for (i = 0; i < size; ++i)
1889 val[i] = n >> (i * 8);
1890 if (!brev)
1891 byterev(val, size);
1892 mwrite(adrs, val, size);
1893 inc = size;
1894 }
1895 cmd = skipbl();
1896 if (cmd == '\n')
1897 break;
1898 inc = 0;
1899 switch (cmd) {
1900 case '\'':
1901 for(;;){
1902 n = inchar();
1903 if( n == '\\' )
1904 n = bsesc();
1905 else if( n == '\'' )
1906 break;
1907 for (i = 0; i < size; ++i)
1908 val[i] = n >> (i * 8);
1909 if (!brev)
1910 byterev(val, size);
1911 mwrite(adrs, val, size);
1912 adrs += size;
1913 }
1914 adrs -= size;
1915 inc = size;
1916 break;
1917 case ',':
1918 adrs += size;
1919 break;
1920 case '.':
1921 mnoread = 0;
1922 break;
1923 case ';':
1924 break;
1925 case 'x':
1926 case EOF:
1927 scannl();
1928 return;
1929 case 'b':
1930 case 'v':
1931 size = 1;
1932 break;
1933 case 'w':
1934 size = 2;
1935 break;
1936 case 'l':
1937 size = 4;
1938 break;
1939 case 'u':
1940 size = 8;
1941 break;
1942 case '^':
1943 adrs -= size;
1944 break;
1945 break;
1946 case '/':
1947 if (nslash > 0)
1948 adrs -= 1 << nslash;
1949 else
1950 nslash = 0;
1951 nslash += 4;
1952 adrs += 1 << nslash;
1953 break;
1954 case '\\':
1955 if (nslash < 0)
1956 adrs += 1 << -nslash;
1957 else
1958 nslash = 0;
1959 nslash -= 4;
1960 adrs -= 1 << -nslash;
1961 break;
1962 case 'm':
1963 scanhex((void *)&adrs);
1964 break;
1965 case 'n':
1966 mnoread = 1;
1967 break;
1968 case 'r':
1969 brev = !brev;
1970 break;
1971 case '<':
1972 n = size;
1973 scanhex(&n);
1974 adrs -= n;
1975 break;
1976 case '>':
1977 n = size;
1978 scanhex(&n);
1979 adrs += n;
1980 break;
1981 case '?':
1982 printf(memex_subcmd_help_string);
1983 break;
1984 }
1985 }
1986 adrs += inc;
1987 }
1988}
1989
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001990static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991bsesc(void)
1992{
1993 int c;
1994
1995 c = inchar();
1996 switch( c ){
1997 case 'n': c = '\n'; break;
1998 case 'r': c = '\r'; break;
1999 case 'b': c = '\b'; break;
2000 case 't': c = '\t'; break;
2001 }
2002 return c;
2003}
2004
Olaf Hering7e5b5932006-03-08 20:40:28 +01002005static void xmon_rawdump (unsigned long adrs, long ndump)
2006{
2007 long n, m, r, nr;
2008 unsigned char temp[16];
2009
2010 for (n = ndump; n > 0;) {
2011 r = n < 16? n: 16;
2012 nr = mread(adrs, temp, r);
2013 adrs += nr;
2014 for (m = 0; m < r; ++m) {
2015 if (m < nr)
2016 printf("%.2x", temp[m]);
2017 else
2018 printf("%s", fault_chars[fault_type]);
2019 }
2020 n -= r;
2021 if (nr < r)
2022 break;
2023 }
2024 printf("\n");
2025}
2026
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002027#ifdef CONFIG_PPC64
2028static void dump_one_paca(int cpu)
2029{
2030 struct paca_struct *p;
2031
2032 if (setjmp(bus_error_jmp) != 0) {
2033 printf("*** Error dumping paca for cpu 0x%x!\n", cpu);
2034 return;
2035 }
2036
2037 catch_memory_errors = 1;
2038 sync();
2039
2040 p = &paca[cpu];
2041
2042 printf("paca for cpu 0x%x @ %p:\n", cpu, p);
2043
2044 printf(" %-*s = %s\n", 16, "possible", cpu_possible(cpu) ? "yes" : "no");
2045 printf(" %-*s = %s\n", 16, "present", cpu_present(cpu) ? "yes" : "no");
2046 printf(" %-*s = %s\n", 16, "online", cpu_online(cpu) ? "yes" : "no");
2047
2048#define DUMP(paca, name, format) \
2049 printf(" %-*s = %#-*"format"\t(0x%lx)\n", 16, #name, 18, paca->name, \
2050 offsetof(struct paca_struct, name));
2051
2052 DUMP(p, lock_token, "x");
2053 DUMP(p, paca_index, "x");
2054 DUMP(p, kernel_toc, "lx");
2055 DUMP(p, kernelbase, "lx");
2056 DUMP(p, kernel_msr, "lx");
2057#ifdef CONFIG_PPC_STD_MMU_64
2058 DUMP(p, stab_real, "lx");
2059 DUMP(p, stab_addr, "lx");
2060#endif
2061 DUMP(p, emergency_sp, "p");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302062#ifdef CONFIG_PPC_BOOK3S_64
2063 DUMP(p, mc_emergency_sp, "p");
2064 DUMP(p, in_mce, "x");
2065#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002066 DUMP(p, data_offset, "lx");
2067 DUMP(p, hw_cpu_id, "x");
2068 DUMP(p, cpu_start, "x");
2069 DUMP(p, kexec_state, "x");
2070 DUMP(p, __current, "p");
2071 DUMP(p, kstack, "lx");
2072 DUMP(p, stab_rr, "lx");
2073 DUMP(p, saved_r1, "lx");
2074 DUMP(p, trap_save, "x");
2075 DUMP(p, soft_enabled, "x");
2076 DUMP(p, irq_happened, "x");
2077 DUMP(p, io_sync, "x");
2078 DUMP(p, irq_work_pending, "x");
2079 DUMP(p, nap_state_lost, "x");
2080
2081#undef DUMP
2082
2083 catch_memory_errors = 0;
2084 sync();
2085}
2086
2087static void dump_all_pacas(void)
2088{
2089 int cpu;
2090
2091 if (num_possible_cpus() == 0) {
2092 printf("No possible cpus, use 'dp #' to dump individual cpus\n");
2093 return;
2094 }
2095
2096 for_each_possible_cpu(cpu)
2097 dump_one_paca(cpu);
2098}
2099
2100static void dump_pacas(void)
2101{
2102 unsigned long num;
2103 int c;
2104
2105 c = inchar();
2106 if (c == 'a') {
2107 dump_all_pacas();
2108 return;
2109 }
2110
2111 termch = c; /* Put c back, it wasn't 'a' */
2112
2113 if (scanhex(&num))
2114 dump_one_paca(num);
2115 else
2116 dump_one_paca(xmon_owner);
2117}
2118#endif
2119
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
2121 || ('a' <= (c) && (c) <= 'f') \
2122 || ('A' <= (c) && (c) <= 'F'))
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002123static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124dump(void)
2125{
2126 int c;
2127
2128 c = inchar();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002129
2130#ifdef CONFIG_PPC64
2131 if (c == 'p') {
2132 dump_pacas();
2133 return;
2134 }
2135#endif
2136
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137 if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
2138 termch = c;
2139 scanhex((void *)&adrs);
2140 if (termch != '\n')
2141 termch = 0;
2142 if (c == 'i') {
2143 scanhex(&nidump);
2144 if (nidump == 0)
2145 nidump = 16;
2146 else if (nidump > MAX_DUMP)
2147 nidump = MAX_DUMP;
2148 adrs += ppc_inst_dump(adrs, nidump, 1);
2149 last_cmd = "di\n";
Vinay Sridharf312deb2009-05-14 23:13:07 +00002150 } else if (c == 'l') {
2151 dump_log_buf();
Olaf Hering7e5b5932006-03-08 20:40:28 +01002152 } else if (c == 'r') {
2153 scanhex(&ndump);
2154 if (ndump == 0)
2155 ndump = 64;
2156 xmon_rawdump(adrs, ndump);
2157 adrs += ndump;
2158 last_cmd = "dr\n";
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159 } else {
2160 scanhex(&ndump);
2161 if (ndump == 0)
2162 ndump = 64;
2163 else if (ndump > MAX_DUMP)
2164 ndump = MAX_DUMP;
2165 prdump(adrs, ndump);
2166 adrs += ndump;
2167 last_cmd = "d\n";
2168 }
2169}
2170
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002171static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172prdump(unsigned long adrs, long ndump)
2173{
2174 long n, m, c, r, nr;
2175 unsigned char temp[16];
2176
2177 for (n = ndump; n > 0;) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002178 printf(REG, adrs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179 putchar(' ');
2180 r = n < 16? n: 16;
2181 nr = mread(adrs, temp, r);
2182 adrs += nr;
2183 for (m = 0; m < r; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002184 if ((m & (sizeof(long) - 1)) == 0 && m > 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002185 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186 if (m < nr)
2187 printf("%.2x", temp[m]);
2188 else
2189 printf("%s", fault_chars[fault_type]);
2190 }
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002191 for (; m < 16; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002192 if ((m & (sizeof(long) - 1)) == 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002193 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002194 printf(" ");
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002195 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196 printf(" |");
2197 for (m = 0; m < r; ++m) {
2198 if (m < nr) {
2199 c = temp[m];
2200 putchar(' ' <= c && c <= '~'? c: '.');
2201 } else
2202 putchar(' ');
2203 }
2204 n -= r;
2205 for (; m < 16; ++m)
2206 putchar(' ');
2207 printf("|\n");
2208 if (nr < r)
2209 break;
2210 }
2211}
2212
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002213typedef int (*instruction_dump_func)(unsigned long inst, unsigned long addr);
2214
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002215static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002216generic_inst_dump(unsigned long adr, long count, int praddr,
2217 instruction_dump_func dump_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218{
2219 int nr, dotted;
2220 unsigned long first_adr;
2221 unsigned long inst, last_inst = 0;
2222 unsigned char val[4];
2223
2224 dotted = 0;
2225 for (first_adr = adr; count > 0; --count, adr += 4) {
2226 nr = mread(adr, val, 4);
2227 if (nr == 0) {
2228 if (praddr) {
2229 const char *x = fault_chars[fault_type];
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002230 printf(REG" %s%s%s%s\n", adr, x, x, x, x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231 }
2232 break;
2233 }
2234 inst = GETWORD(val);
2235 if (adr > first_adr && inst == last_inst) {
2236 if (!dotted) {
2237 printf(" ...\n");
2238 dotted = 1;
2239 }
2240 continue;
2241 }
2242 dotted = 0;
2243 last_inst = inst;
2244 if (praddr)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002245 printf(REG" %.8x", adr, inst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246 printf("\t");
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002247 dump_func(inst, adr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248 printf("\n");
2249 }
2250 return adr - first_adr;
2251}
2252
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002253static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002254ppc_inst_dump(unsigned long adr, long count, int praddr)
2255{
2256 return generic_inst_dump(adr, count, praddr, print_insn_powerpc);
2257}
2258
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259void
2260print_address(unsigned long addr)
2261{
2262 xmon_print_symbol(addr, "\t# ", "");
2263}
2264
Vinay Sridharf312deb2009-05-14 23:13:07 +00002265void
2266dump_log_buf(void)
2267{
Michael Ellermanca5dd392012-08-23 22:09:12 +00002268 struct kmsg_dumper dumper = { .active = 1 };
2269 unsigned char buf[128];
2270 size_t len;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002271
Michael Ellermane3bc8042012-08-23 22:09:13 +00002272 if (setjmp(bus_error_jmp) != 0) {
Michael Ellermanca5dd392012-08-23 22:09:12 +00002273 printf("Error dumping printk buffer!\n");
Michael Ellermane3bc8042012-08-23 22:09:13 +00002274 return;
2275 }
Vinay Sridharf312deb2009-05-14 23:13:07 +00002276
Michael Ellermane3bc8042012-08-23 22:09:13 +00002277 catch_memory_errors = 1;
2278 sync();
Vinay Sridharf312deb2009-05-14 23:13:07 +00002279
Michael Ellermanca5dd392012-08-23 22:09:12 +00002280 kmsg_dump_rewind_nolock(&dumper);
2281 while (kmsg_dump_get_line_nolock(&dumper, false, buf, sizeof(buf), &len)) {
2282 buf[len] = '\0';
2283 printf("%s", buf);
2284 }
Vinay Sridharf312deb2009-05-14 23:13:07 +00002285
Michael Ellermane3bc8042012-08-23 22:09:13 +00002286 sync();
2287 /* wait a little while to see if we get a machine check */
2288 __delay(200);
2289 catch_memory_errors = 0;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002290}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291
2292/*
2293 * Memory operations - move, set, print differences
2294 */
2295static unsigned long mdest; /* destination address */
2296static unsigned long msrc; /* source address */
2297static unsigned long mval; /* byte value to set memory to */
2298static unsigned long mcount; /* # bytes to affect */
2299static unsigned long mdiffs; /* max # differences to print */
2300
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002301static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302memops(int cmd)
2303{
2304 scanhex((void *)&mdest);
2305 if( termch != '\n' )
2306 termch = 0;
2307 scanhex((void *)(cmd == 's'? &mval: &msrc));
2308 if( termch != '\n' )
2309 termch = 0;
2310 scanhex((void *)&mcount);
2311 switch( cmd ){
2312 case 'm':
2313 memmove((void *)mdest, (void *)msrc, mcount);
2314 break;
2315 case 's':
2316 memset((void *)mdest, mval, mcount);
2317 break;
2318 case 'd':
2319 if( termch != '\n' )
2320 termch = 0;
2321 scanhex((void *)&mdiffs);
2322 memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
2323 break;
2324 }
2325}
2326
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002327static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
2329{
2330 unsigned n, prt;
2331
2332 prt = 0;
2333 for( n = nb; n > 0; --n )
2334 if( *p1++ != *p2++ )
2335 if( ++prt <= maxpr )
2336 printf("%.16x %.2x # %.16x %.2x\n", p1 - 1,
2337 p1[-1], p2 - 1, p2[-1]);
2338 if( prt > maxpr )
2339 printf("Total of %d differences\n", prt);
2340}
2341
2342static unsigned mend;
2343static unsigned mask;
2344
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002345static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002346memlocate(void)
2347{
2348 unsigned a, n;
2349 unsigned char val[4];
2350
2351 last_cmd = "ml";
2352 scanhex((void *)&mdest);
2353 if (termch != '\n') {
2354 termch = 0;
2355 scanhex((void *)&mend);
2356 if (termch != '\n') {
2357 termch = 0;
2358 scanhex((void *)&mval);
2359 mask = ~0;
2360 if (termch != '\n') termch = 0;
2361 scanhex((void *)&mask);
2362 }
2363 }
2364 n = 0;
2365 for (a = mdest; a < mend; a += 4) {
2366 if (mread(a, val, 4) == 4
2367 && ((GETWORD(val) ^ mval) & mask) == 0) {
2368 printf("%.16x: %.16x\n", a, GETWORD(val));
2369 if (++n >= 10)
2370 break;
2371 }
2372 }
2373}
2374
2375static unsigned long mskip = 0x1000;
2376static unsigned long mlim = 0xffffffff;
2377
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002378static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379memzcan(void)
2380{
2381 unsigned char v;
2382 unsigned a;
2383 int ok, ook;
2384
2385 scanhex(&mdest);
2386 if (termch != '\n') termch = 0;
2387 scanhex(&mskip);
2388 if (termch != '\n') termch = 0;
2389 scanhex(&mlim);
2390 ook = 0;
2391 for (a = mdest; a < mlim; a += mskip) {
2392 ok = mread(a, &v, 1);
2393 if (ok && !ook) {
2394 printf("%.8x .. ", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395 } else if (!ok && ook)
2396 printf("%.8x\n", a - mskip);
2397 ook = ok;
2398 if (a + mskip < a)
2399 break;
2400 }
2401 if (ook)
2402 printf("%.8x\n", a - mskip);
2403}
2404
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002405static void proccall(void)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002406{
2407 unsigned long args[8];
2408 unsigned long ret;
2409 int i;
2410 typedef unsigned long (*callfunc_t)(unsigned long, unsigned long,
2411 unsigned long, unsigned long, unsigned long,
2412 unsigned long, unsigned long, unsigned long);
2413 callfunc_t func;
2414
2415 if (!scanhex(&adrs))
2416 return;
2417 if (termch != '\n')
2418 termch = 0;
2419 for (i = 0; i < 8; ++i)
2420 args[i] = 0;
2421 for (i = 0; i < 8; ++i) {
2422 if (!scanhex(&args[i]) || termch == '\n')
2423 break;
2424 termch = 0;
2425 }
2426 func = (callfunc_t) adrs;
2427 ret = 0;
2428 if (setjmp(bus_error_jmp) == 0) {
2429 catch_memory_errors = 1;
2430 sync();
2431 ret = func(args[0], args[1], args[2], args[3],
2432 args[4], args[5], args[6], args[7]);
2433 sync();
2434 printf("return value is %x\n", ret);
2435 } else {
2436 printf("*** %x exception occurred\n", fault_except);
2437 }
2438 catch_memory_errors = 0;
2439}
2440
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441/* Input scanning routines */
2442int
2443skipbl(void)
2444{
2445 int c;
2446
2447 if( termch != 0 ){
2448 c = termch;
2449 termch = 0;
2450 } else
2451 c = inchar();
2452 while( c == ' ' || c == '\t' )
2453 c = inchar();
2454 return c;
2455}
2456
2457#define N_PTREGS 44
2458static char *regnames[N_PTREGS] = {
2459 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
2460 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
2461 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
2462 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002463 "pc", "msr", "or3", "ctr", "lr", "xer", "ccr",
2464#ifdef CONFIG_PPC64
2465 "softe",
2466#else
2467 "mq",
2468#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469 "trap", "dar", "dsisr", "res"
2470};
2471
2472int
2473scanhex(unsigned long *vp)
2474{
2475 int c, d;
2476 unsigned long v;
2477
2478 c = skipbl();
2479 if (c == '%') {
2480 /* parse register name */
2481 char regname[8];
2482 int i;
2483
2484 for (i = 0; i < sizeof(regname) - 1; ++i) {
2485 c = inchar();
2486 if (!isalnum(c)) {
2487 termch = c;
2488 break;
2489 }
2490 regname[i] = c;
2491 }
2492 regname[i] = 0;
2493 for (i = 0; i < N_PTREGS; ++i) {
2494 if (strcmp(regnames[i], regname) == 0) {
2495 if (xmon_regs == NULL) {
2496 printf("regs not available\n");
2497 return 0;
2498 }
2499 *vp = ((unsigned long *)xmon_regs)[i];
2500 return 1;
2501 }
2502 }
2503 printf("invalid register name '%%%s'\n", regname);
2504 return 0;
2505 }
2506
2507 /* skip leading "0x" if any */
2508
2509 if (c == '0') {
2510 c = inchar();
2511 if (c == 'x') {
2512 c = inchar();
2513 } else {
2514 d = hexdigit(c);
2515 if (d == EOF) {
2516 termch = c;
2517 *vp = 0;
2518 return 1;
2519 }
2520 }
2521 } else if (c == '$') {
2522 int i;
2523 for (i=0; i<63; i++) {
2524 c = inchar();
2525 if (isspace(c)) {
2526 termch = c;
2527 break;
2528 }
2529 tmpstr[i] = c;
2530 }
2531 tmpstr[i++] = 0;
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07002532 *vp = 0;
2533 if (setjmp(bus_error_jmp) == 0) {
2534 catch_memory_errors = 1;
2535 sync();
2536 *vp = kallsyms_lookup_name(tmpstr);
2537 sync();
2538 }
2539 catch_memory_errors = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540 if (!(*vp)) {
2541 printf("unknown symbol '%s'\n", tmpstr);
2542 return 0;
2543 }
2544 return 1;
2545 }
2546
2547 d = hexdigit(c);
2548 if (d == EOF) {
2549 termch = c;
2550 return 0;
2551 }
2552 v = 0;
2553 do {
2554 v = (v << 4) + d;
2555 c = inchar();
2556 d = hexdigit(c);
2557 } while (d != EOF);
2558 termch = c;
2559 *vp = v;
2560 return 1;
2561}
2562
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002563static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564scannl(void)
2565{
2566 int c;
2567
2568 c = termch;
2569 termch = 0;
2570 while( c != '\n' )
2571 c = inchar();
2572}
2573
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002574static int hexdigit(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575{
2576 if( '0' <= c && c <= '9' )
2577 return c - '0';
2578 if( 'A' <= c && c <= 'F' )
2579 return c - ('A' - 10);
2580 if( 'a' <= c && c <= 'f' )
2581 return c - ('a' - 10);
2582 return EOF;
2583}
2584
2585void
2586getstring(char *s, int size)
2587{
2588 int c;
2589
2590 c = skipbl();
2591 do {
2592 if( size > 1 ){
2593 *s++ = c;
2594 --size;
2595 }
2596 c = inchar();
2597 } while( c != ' ' && c != '\t' && c != '\n' );
2598 termch = c;
2599 *s = 0;
2600}
2601
2602static char line[256];
2603static char *lineptr;
2604
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002605static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606flush_input(void)
2607{
2608 lineptr = NULL;
2609}
2610
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002611static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612inchar(void)
2613{
2614 if (lineptr == NULL || *lineptr == 0) {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002615 if (xmon_gets(line, sizeof(line)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616 lineptr = NULL;
2617 return EOF;
2618 }
2619 lineptr = line;
2620 }
2621 return *lineptr++;
2622}
2623
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002624static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625take_input(char *str)
2626{
2627 lineptr = str;
2628}
2629
2630
2631static void
2632symbol_lookup(void)
2633{
2634 int type = inchar();
2635 unsigned long addr;
2636 static char tmp[64];
2637
2638 switch (type) {
2639 case 'a':
2640 if (scanhex(&addr))
2641 xmon_print_symbol(addr, ": ", "\n");
2642 termch = 0;
2643 break;
2644 case 's':
2645 getstring(tmp, 64);
2646 if (setjmp(bus_error_jmp) == 0) {
2647 catch_memory_errors = 1;
2648 sync();
2649 addr = kallsyms_lookup_name(tmp);
2650 if (addr)
2651 printf("%s: %lx\n", tmp, addr);
2652 else
2653 printf("Symbol '%s' not found.\n", tmp);
2654 sync();
2655 }
2656 catch_memory_errors = 0;
2657 termch = 0;
2658 break;
2659 }
2660}
2661
2662
2663/* Print an address in numeric and symbolic form (if possible) */
2664static void xmon_print_symbol(unsigned long address, const char *mid,
2665 const char *after)
2666{
2667 char *modname;
2668 const char *name = NULL;
2669 unsigned long offset, size;
2670
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002671 printf(REG, address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672 if (setjmp(bus_error_jmp) == 0) {
2673 catch_memory_errors = 1;
2674 sync();
2675 name = kallsyms_lookup(address, &size, &offset, &modname,
2676 tmpstr);
2677 sync();
2678 /* wait a little while to see if we get a machine check */
2679 __delay(200);
2680 }
2681
2682 catch_memory_errors = 0;
2683
2684 if (name) {
2685 printf("%s%s+%#lx/%#lx", mid, name, offset, size);
2686 if (modname)
2687 printf(" [%s]", modname);
2688 }
2689 printf("%s", after);
2690}
2691
Benjamin Herrenschmidt2d27cfd2009-07-23 23:15:59 +00002692#ifdef CONFIG_PPC_BOOK3S_64
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693static void dump_slb(void)
2694{
2695 int i;
will schmidtb3b95952007-12-07 08:22:23 +11002696 unsigned long esid,vsid,valid;
2697 unsigned long llp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698
2699 printf("SLB contents of cpu %x\n", smp_processor_id());
2700
Michael Neuling584f8b72007-12-06 17:24:48 +11002701 for (i = 0; i < mmu_slb_size; i++) {
will schmidtb3b95952007-12-07 08:22:23 +11002702 asm volatile("slbmfee %0,%1" : "=r" (esid) : "r" (i));
2703 asm volatile("slbmfev %0,%1" : "=r" (vsid) : "r" (i));
2704 valid = (esid & SLB_ESID_V);
2705 if (valid | esid | vsid) {
2706 printf("%02d %016lx %016lx", i, esid, vsid);
2707 if (valid) {
2708 llp = vsid & SLB_VSID_LLP;
2709 if (vsid & SLB_VSID_B_1T) {
2710 printf(" 1T ESID=%9lx VSID=%13lx LLP:%3lx \n",
2711 GET_ESID_1T(esid),
2712 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT_1T,
2713 llp);
2714 } else {
2715 printf(" 256M ESID=%9lx VSID=%13lx LLP:%3lx \n",
2716 GET_ESID(esid),
2717 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT,
2718 llp);
2719 }
2720 } else
2721 printf("\n");
2722 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 }
2724}
2725
2726static void dump_stab(void)
2727{
2728 int i;
Benjamin Herrenschmidt7ac21cd2012-03-02 10:10:09 +11002729 unsigned long *tmp = (unsigned long *)local_paca->stab_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730
2731 printf("Segment table contents of cpu %x\n", smp_processor_id());
2732
2733 for (i = 0; i < PAGE_SIZE/16; i++) {
2734 unsigned long a, b;
2735
2736 a = *tmp++;
2737 b = *tmp++;
2738
2739 if (a || b) {
2740 printf("%03d %016lx ", i, a);
2741 printf("%016lx\n", b);
2742 }
2743 }
2744}
2745
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002746void dump_segments(void)
2747{
Matt Evans44ae3ab2011-04-06 19:48:50 +00002748 if (mmu_has_feature(MMU_FTR_SLB))
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002749 dump_slb();
2750 else
2751 dump_stab();
2752}
2753#endif
2754
2755#ifdef CONFIG_PPC_STD_MMU_32
2756void dump_segments(void)
2757{
2758 int i;
2759
2760 printf("sr0-15 =");
2761 for (i = 0; i < 16; ++i)
2762 printf(" %x", mfsrin(i));
2763 printf("\n");
2764}
2765#endif
2766
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11002767#ifdef CONFIG_44x
2768static void dump_tlb_44x(void)
2769{
2770 int i;
2771
2772 for (i = 0; i < PPC44x_TLB_SIZE; i++) {
2773 unsigned long w0,w1,w2;
2774 asm volatile("tlbre %0,%1,0" : "=r" (w0) : "r" (i));
2775 asm volatile("tlbre %0,%1,1" : "=r" (w1) : "r" (i));
2776 asm volatile("tlbre %0,%1,2" : "=r" (w2) : "r" (i));
2777 printf("[%02x] %08x %08x %08x ", i, w0, w1, w2);
2778 if (w0 & PPC44x_TLB_VALID) {
2779 printf("V %08x -> %01x%08x %c%c%c%c%c",
2780 w0 & PPC44x_TLB_EPN_MASK,
2781 w1 & PPC44x_TLB_ERPN_MASK,
2782 w1 & PPC44x_TLB_RPN_MASK,
2783 (w2 & PPC44x_TLB_W) ? 'W' : 'w',
2784 (w2 & PPC44x_TLB_I) ? 'I' : 'i',
2785 (w2 & PPC44x_TLB_M) ? 'M' : 'm',
2786 (w2 & PPC44x_TLB_G) ? 'G' : 'g',
2787 (w2 & PPC44x_TLB_E) ? 'E' : 'e');
2788 }
2789 printf("\n");
2790 }
2791}
2792#endif /* CONFIG_44x */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002793
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +10002794#ifdef CONFIG_PPC_BOOK3E
2795static void dump_tlb_book3e(void)
2796{
2797 u32 mmucfg, pidmask, lpidmask;
2798 u64 ramask;
2799 int i, tlb, ntlbs, pidsz, lpidsz, rasz, lrat = 0;
2800 int mmu_version;
2801 static const char *pgsz_names[] = {
2802 " 1K",
2803 " 2K",
2804 " 4K",
2805 " 8K",
2806 " 16K",
2807 " 32K",
2808 " 64K",
2809 "128K",
2810 "256K",
2811 "512K",
2812 " 1M",
2813 " 2M",
2814 " 4M",
2815 " 8M",
2816 " 16M",
2817 " 32M",
2818 " 64M",
2819 "128M",
2820 "256M",
2821 "512M",
2822 " 1G",
2823 " 2G",
2824 " 4G",
2825 " 8G",
2826 " 16G",
2827 " 32G",
2828 " 64G",
2829 "128G",
2830 "256G",
2831 "512G",
2832 " 1T",
2833 " 2T",
2834 };
2835
2836 /* Gather some infos about the MMU */
2837 mmucfg = mfspr(SPRN_MMUCFG);
2838 mmu_version = (mmucfg & 3) + 1;
2839 ntlbs = ((mmucfg >> 2) & 3) + 1;
2840 pidsz = ((mmucfg >> 6) & 0x1f) + 1;
2841 lpidsz = (mmucfg >> 24) & 0xf;
2842 rasz = (mmucfg >> 16) & 0x7f;
2843 if ((mmu_version > 1) && (mmucfg & 0x10000))
2844 lrat = 1;
2845 printf("Book3E MMU MAV=%d.0,%d TLBs,%d-bit PID,%d-bit LPID,%d-bit RA\n",
2846 mmu_version, ntlbs, pidsz, lpidsz, rasz);
2847 pidmask = (1ul << pidsz) - 1;
2848 lpidmask = (1ul << lpidsz) - 1;
2849 ramask = (1ull << rasz) - 1;
2850
2851 for (tlb = 0; tlb < ntlbs; tlb++) {
2852 u32 tlbcfg;
2853 int nent, assoc, new_cc = 1;
2854 printf("TLB %d:\n------\n", tlb);
2855 switch(tlb) {
2856 case 0:
2857 tlbcfg = mfspr(SPRN_TLB0CFG);
2858 break;
2859 case 1:
2860 tlbcfg = mfspr(SPRN_TLB1CFG);
2861 break;
2862 case 2:
2863 tlbcfg = mfspr(SPRN_TLB2CFG);
2864 break;
2865 case 3:
2866 tlbcfg = mfspr(SPRN_TLB3CFG);
2867 break;
2868 default:
2869 printf("Unsupported TLB number !\n");
2870 continue;
2871 }
2872 nent = tlbcfg & 0xfff;
2873 assoc = (tlbcfg >> 24) & 0xff;
2874 for (i = 0; i < nent; i++) {
2875 u32 mas0 = MAS0_TLBSEL(tlb);
2876 u32 mas1 = MAS1_TSIZE(BOOK3E_PAGESZ_4K);
2877 u64 mas2 = 0;
2878 u64 mas7_mas3;
2879 int esel = i, cc = i;
2880
2881 if (assoc != 0) {
2882 cc = i / assoc;
2883 esel = i % assoc;
2884 mas2 = cc * 0x1000;
2885 }
2886
2887 mas0 |= MAS0_ESEL(esel);
2888 mtspr(SPRN_MAS0, mas0);
2889 mtspr(SPRN_MAS1, mas1);
2890 mtspr(SPRN_MAS2, mas2);
2891 asm volatile("tlbre 0,0,0" : : : "memory");
2892 mas1 = mfspr(SPRN_MAS1);
2893 mas2 = mfspr(SPRN_MAS2);
2894 mas7_mas3 = mfspr(SPRN_MAS7_MAS3);
2895 if (assoc && (i % assoc) == 0)
2896 new_cc = 1;
2897 if (!(mas1 & MAS1_VALID))
2898 continue;
2899 if (assoc == 0)
2900 printf("%04x- ", i);
2901 else if (new_cc)
2902 printf("%04x-%c", cc, 'A' + esel);
2903 else
2904 printf(" |%c", 'A' + esel);
2905 new_cc = 0;
2906 printf(" %016llx %04x %s %c%c AS%c",
2907 mas2 & ~0x3ffull,
2908 (mas1 >> 16) & 0x3fff,
2909 pgsz_names[(mas1 >> 7) & 0x1f],
2910 mas1 & MAS1_IND ? 'I' : ' ',
2911 mas1 & MAS1_IPROT ? 'P' : ' ',
2912 mas1 & MAS1_TS ? '1' : '0');
2913 printf(" %c%c%c%c%c%c%c",
2914 mas2 & MAS2_X0 ? 'a' : ' ',
2915 mas2 & MAS2_X1 ? 'v' : ' ',
2916 mas2 & MAS2_W ? 'w' : ' ',
2917 mas2 & MAS2_I ? 'i' : ' ',
2918 mas2 & MAS2_M ? 'm' : ' ',
2919 mas2 & MAS2_G ? 'g' : ' ',
2920 mas2 & MAS2_E ? 'e' : ' ');
2921 printf(" %016llx", mas7_mas3 & ramask & ~0x7ffull);
2922 if (mas1 & MAS1_IND)
2923 printf(" %s\n",
2924 pgsz_names[(mas7_mas3 >> 1) & 0x1f]);
2925 else
2926 printf(" U%c%c%c S%c%c%c\n",
2927 mas7_mas3 & MAS3_UX ? 'x' : ' ',
2928 mas7_mas3 & MAS3_UW ? 'w' : ' ',
2929 mas7_mas3 & MAS3_UR ? 'r' : ' ',
2930 mas7_mas3 & MAS3_SX ? 'x' : ' ',
2931 mas7_mas3 & MAS3_SW ? 'w' : ' ',
2932 mas7_mas3 & MAS3_SR ? 'r' : ' ');
2933 }
2934 }
2935}
2936#endif /* CONFIG_PPC_BOOK3E */
2937
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002938static void xmon_init(int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002939{
Olaf Heringb13cfd172005-08-04 19:26:42 +02002940 if (enable) {
2941 __debugger = xmon;
2942 __debugger_ipi = xmon_ipi;
2943 __debugger_bpt = xmon_bpt;
2944 __debugger_sstep = xmon_sstep;
2945 __debugger_iabr_match = xmon_iabr_match;
Michael Neuling9422de32012-12-20 14:06:44 +00002946 __debugger_break_match = xmon_break_match;
Olaf Heringb13cfd172005-08-04 19:26:42 +02002947 __debugger_fault_handler = xmon_fault_handler;
2948 } else {
2949 __debugger = NULL;
2950 __debugger_ipi = NULL;
2951 __debugger_bpt = NULL;
2952 __debugger_sstep = NULL;
2953 __debugger_iabr_match = NULL;
Michael Neuling9422de32012-12-20 14:06:44 +00002954 __debugger_break_match = NULL;
Olaf Heringb13cfd172005-08-04 19:26:42 +02002955 __debugger_fault_handler = NULL;
2956 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957}
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002958
2959#ifdef CONFIG_MAGIC_SYSRQ
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07002960static void sysrq_handle_xmon(int key)
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002961{
2962 /* ensure xmon is enabled */
2963 xmon_init(1);
David Howells7d12e782006-10-05 14:55:46 +01002964 debugger(get_irq_regs());
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002965}
2966
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07002967static struct sysrq_key_op sysrq_xmon_op = {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002968 .handler = sysrq_handle_xmon,
zhangwei(Jovi)90a102e2013-04-30 15:28:54 -07002969 .help_msg = "xmon(x)",
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002970 .action_msg = "Entering xmon",
2971};
2972
2973static int __init setup_xmon_sysrq(void)
2974{
2975 register_sysrq_key('x', &sysrq_xmon_op);
2976 return 0;
2977}
2978__initcall(setup_xmon_sysrq);
2979#endif /* CONFIG_MAGIC_SYSRQ */
Michael Ellerman476792832006-10-03 14:12:08 +10002980
Olaf Heringf5e6a282007-06-24 16:57:08 +10002981static int __initdata xmon_early, xmon_off;
Michael Ellerman476792832006-10-03 14:12:08 +10002982
2983static int __init early_parse_xmon(char *p)
2984{
2985 if (!p || strncmp(p, "early", 5) == 0) {
2986 /* just "xmon" is equivalent to "xmon=early" */
2987 xmon_init(1);
2988 xmon_early = 1;
2989 } else if (strncmp(p, "on", 2) == 0)
2990 xmon_init(1);
2991 else if (strncmp(p, "off", 3) == 0)
2992 xmon_off = 1;
2993 else if (strncmp(p, "nobt", 4) == 0)
2994 xmon_no_auto_backtrace = 1;
2995 else
2996 return 1;
2997
2998 return 0;
2999}
3000early_param("xmon", early_parse_xmon);
3001
3002void __init xmon_setup(void)
3003{
3004#ifdef CONFIG_XMON_DEFAULT
3005 if (!xmon_off)
3006 xmon_init(1);
3007#endif
3008 if (xmon_early)
3009 debugger(NULL);
3010}
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003011
Arnd Bergmanne0555952006-11-27 19:18:55 +01003012#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003013
3014struct spu_info {
3015 struct spu *spu;
3016 u64 saved_mfc_sr1_RW;
3017 u32 saved_spu_runcntl_RW;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003018 unsigned long dump_addr;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003019 u8 stopped_ok;
3020};
3021
3022#define XMON_NUM_SPUS 16 /* Enough for current hardware */
3023
3024static struct spu_info spu_info[XMON_NUM_SPUS];
3025
3026void xmon_register_spus(struct list_head *list)
3027{
3028 struct spu *spu;
3029
3030 list_for_each_entry(spu, list, full_list) {
3031 if (spu->number >= XMON_NUM_SPUS) {
3032 WARN_ON(1);
3033 continue;
3034 }
3035
3036 spu_info[spu->number].spu = spu;
3037 spu_info[spu->number].stopped_ok = 0;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003038 spu_info[spu->number].dump_addr = (unsigned long)
3039 spu_info[spu->number].spu->local_store;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003040 }
3041}
3042
3043static void stop_spus(void)
3044{
3045 struct spu *spu;
3046 int i;
3047 u64 tmp;
3048
3049 for (i = 0; i < XMON_NUM_SPUS; i++) {
3050 if (!spu_info[i].spu)
3051 continue;
3052
3053 if (setjmp(bus_error_jmp) == 0) {
3054 catch_memory_errors = 1;
3055 sync();
3056
3057 spu = spu_info[i].spu;
3058
3059 spu_info[i].saved_spu_runcntl_RW =
3060 in_be32(&spu->problem->spu_runcntl_RW);
3061
3062 tmp = spu_mfc_sr1_get(spu);
3063 spu_info[i].saved_mfc_sr1_RW = tmp;
3064
3065 tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
3066 spu_mfc_sr1_set(spu, tmp);
3067
3068 sync();
3069 __delay(200);
3070
3071 spu_info[i].stopped_ok = 1;
Michael Ellerman2a144422006-11-23 00:46:40 +01003072
3073 printf("Stopped spu %.2d (was %s)\n", i,
3074 spu_info[i].saved_spu_runcntl_RW ?
3075 "running" : "stopped");
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003076 } else {
3077 catch_memory_errors = 0;
3078 printf("*** Error stopping spu %.2d\n", i);
3079 }
3080 catch_memory_errors = 0;
3081 }
3082}
3083
3084static void restart_spus(void)
3085{
3086 struct spu *spu;
3087 int i;
3088
3089 for (i = 0; i < XMON_NUM_SPUS; i++) {
3090 if (!spu_info[i].spu)
3091 continue;
3092
3093 if (!spu_info[i].stopped_ok) {
3094 printf("*** Error, spu %d was not successfully stopped"
3095 ", not restarting\n", i);
3096 continue;
3097 }
3098
3099 if (setjmp(bus_error_jmp) == 0) {
3100 catch_memory_errors = 1;
3101 sync();
3102
3103 spu = spu_info[i].spu;
3104 spu_mfc_sr1_set(spu, spu_info[i].saved_mfc_sr1_RW);
3105 out_be32(&spu->problem->spu_runcntl_RW,
3106 spu_info[i].saved_spu_runcntl_RW);
3107
3108 sync();
3109 __delay(200);
3110
3111 printf("Restarted spu %.2d\n", i);
3112 } else {
3113 catch_memory_errors = 0;
3114 printf("*** Error restarting spu %.2d\n", i);
3115 }
3116 catch_memory_errors = 0;
3117 }
3118}
3119
Michael Ellermana8984972006-10-24 18:31:28 +02003120#define DUMP_WIDTH 23
Michael Ellerman437a0702006-11-23 00:46:39 +01003121#define DUMP_VALUE(format, field, value) \
Michael Ellermana8984972006-10-24 18:31:28 +02003122do { \
3123 if (setjmp(bus_error_jmp) == 0) { \
3124 catch_memory_errors = 1; \
3125 sync(); \
3126 printf(" %-*s = "format"\n", DUMP_WIDTH, \
Michael Ellerman437a0702006-11-23 00:46:39 +01003127 #field, value); \
Michael Ellermana8984972006-10-24 18:31:28 +02003128 sync(); \
3129 __delay(200); \
3130 } else { \
3131 catch_memory_errors = 0; \
3132 printf(" %-*s = *** Error reading field.\n", \
3133 DUMP_WIDTH, #field); \
3134 } \
3135 catch_memory_errors = 0; \
3136} while (0)
3137
Michael Ellerman437a0702006-11-23 00:46:39 +01003138#define DUMP_FIELD(obj, format, field) \
3139 DUMP_VALUE(format, field, obj->field)
3140
Michael Ellermana8984972006-10-24 18:31:28 +02003141static void dump_spu_fields(struct spu *spu)
3142{
3143 printf("Dumping spu fields at address %p:\n", spu);
3144
3145 DUMP_FIELD(spu, "0x%x", number);
3146 DUMP_FIELD(spu, "%s", name);
Michael Ellermana8984972006-10-24 18:31:28 +02003147 DUMP_FIELD(spu, "0x%lx", local_store_phys);
3148 DUMP_FIELD(spu, "0x%p", local_store);
3149 DUMP_FIELD(spu, "0x%lx", ls_size);
3150 DUMP_FIELD(spu, "0x%x", node);
3151 DUMP_FIELD(spu, "0x%lx", flags);
Michael Ellermana8984972006-10-24 18:31:28 +02003152 DUMP_FIELD(spu, "%d", class_0_pending);
Luke Browningf3d69e02008-04-27 18:41:55 +00003153 DUMP_FIELD(spu, "0x%lx", class_0_dar);
Luke Browningf3d69e02008-04-27 18:41:55 +00003154 DUMP_FIELD(spu, "0x%lx", class_1_dar);
3155 DUMP_FIELD(spu, "0x%lx", class_1_dsisr);
Michael Ellermana8984972006-10-24 18:31:28 +02003156 DUMP_FIELD(spu, "0x%lx", irqs[0]);
3157 DUMP_FIELD(spu, "0x%lx", irqs[1]);
3158 DUMP_FIELD(spu, "0x%lx", irqs[2]);
3159 DUMP_FIELD(spu, "0x%x", slb_replace);
3160 DUMP_FIELD(spu, "%d", pid);
Michael Ellermana8984972006-10-24 18:31:28 +02003161 DUMP_FIELD(spu, "0x%p", mm);
3162 DUMP_FIELD(spu, "0x%p", ctx);
3163 DUMP_FIELD(spu, "0x%p", rq);
3164 DUMP_FIELD(spu, "0x%p", timestamp);
3165 DUMP_FIELD(spu, "0x%lx", problem_phys);
3166 DUMP_FIELD(spu, "0x%p", problem);
Michael Ellerman437a0702006-11-23 00:46:39 +01003167 DUMP_VALUE("0x%x", problem->spu_runcntl_RW,
3168 in_be32(&spu->problem->spu_runcntl_RW));
3169 DUMP_VALUE("0x%x", problem->spu_status_R,
3170 in_be32(&spu->problem->spu_status_R));
3171 DUMP_VALUE("0x%x", problem->spu_npc_RW,
3172 in_be32(&spu->problem->spu_npc_RW));
Michael Ellermana8984972006-10-24 18:31:28 +02003173 DUMP_FIELD(spu, "0x%p", priv2);
Michael Ellermana9852392006-11-23 00:46:50 +01003174 DUMP_FIELD(spu, "0x%p", pdata);
Michael Ellermana8984972006-10-24 18:31:28 +02003175}
3176
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003177int
3178spu_inst_dump(unsigned long adr, long count, int praddr)
3179{
3180 return generic_inst_dump(adr, count, praddr, print_insn_spu);
3181}
3182
3183static void dump_spu_ls(unsigned long num, int subcmd)
Michael Ellerman24a24c82006-11-23 00:46:41 +01003184{
3185 unsigned long offset, addr, ls_addr;
3186
3187 if (setjmp(bus_error_jmp) == 0) {
3188 catch_memory_errors = 1;
3189 sync();
3190 ls_addr = (unsigned long)spu_info[num].spu->local_store;
3191 sync();
3192 __delay(200);
3193 } else {
3194 catch_memory_errors = 0;
3195 printf("*** Error: accessing spu info for spu %d\n", num);
3196 return;
3197 }
3198 catch_memory_errors = 0;
3199
3200 if (scanhex(&offset))
3201 addr = ls_addr + offset;
3202 else
3203 addr = spu_info[num].dump_addr;
3204
3205 if (addr >= ls_addr + LS_SIZE) {
3206 printf("*** Error: address outside of local store\n");
3207 return;
3208 }
3209
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003210 switch (subcmd) {
3211 case 'i':
3212 addr += spu_inst_dump(addr, 16, 1);
3213 last_cmd = "sdi\n";
3214 break;
3215 default:
3216 prdump(addr, 64);
3217 addr += 64;
3218 last_cmd = "sd\n";
3219 break;
3220 }
Michael Ellerman24a24c82006-11-23 00:46:41 +01003221
3222 spu_info[num].dump_addr = addr;
3223}
3224
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003225static int do_spu_cmd(void)
3226{
Michael Ellerman24a24c82006-11-23 00:46:41 +01003227 static unsigned long num = 0;
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003228 int cmd, subcmd = 0;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003229
3230 cmd = inchar();
3231 switch (cmd) {
3232 case 's':
3233 stop_spus();
3234 break;
3235 case 'r':
3236 restart_spus();
3237 break;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003238 case 'd':
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003239 subcmd = inchar();
3240 if (isxdigit(subcmd) || subcmd == '\n')
3241 termch = subcmd;
3242 case 'f':
Michael Ellerman24a24c82006-11-23 00:46:41 +01003243 scanhex(&num);
3244 if (num >= XMON_NUM_SPUS || !spu_info[num].spu) {
Michael Ellermana8984972006-10-24 18:31:28 +02003245 printf("*** Error: invalid spu number\n");
Michael Ellerman24a24c82006-11-23 00:46:41 +01003246 return 0;
3247 }
3248
3249 switch (cmd) {
3250 case 'f':
3251 dump_spu_fields(spu_info[num].spu);
3252 break;
3253 default:
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003254 dump_spu_ls(num, subcmd);
Michael Ellerman24a24c82006-11-23 00:46:41 +01003255 break;
3256 }
3257
Michael Ellermana8984972006-10-24 18:31:28 +02003258 break;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003259 default:
3260 return -1;
3261 }
3262
3263 return 0;
3264}
Arnd Bergmanne0555952006-11-27 19:18:55 +01003265#else /* ! CONFIG_SPU_BASE */
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003266static int do_spu_cmd(void)
3267{
3268 return -1;
3269}
3270#endif