blob: a90731b3d44a3ea41052690975aefcd8b3ce2db7 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Routines providing a simple monitor for use on the PowerMac.
3 *
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11004 * Copyright (C) 1996-2005 Paul Mackerras.
Michael Ellerman476792832006-10-03 14:12:08 +10005 * Copyright (C) 2001 PPC64 Team, IBM Corp
6 * Copyrignt (C) 2006 Michael Ellerman, IBM Corp
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <linux/errno.h>
14#include <linux/sched.h>
15#include <linux/smp.h>
16#include <linux/mm.h>
17#include <linux/reboot.h>
18#include <linux/delay.h>
19#include <linux/kallsyms.h>
Michael Ellermanca5dd392012-08-23 22:09:12 +000020#include <linux/kmsg_dump.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <linux/cpumask.h>
Paul Gortmaker4b16f8e2011-07-22 18:24:23 -040022#include <linux/export.h>
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +110023#include <linux/sysrq.h>
Andrew Morton4694ca02005-11-13 16:06:50 -080024#include <linux/interrupt.h>
David Howells7d12e782006-10-05 14:55:46 +010025#include <linux/irq.h>
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -080026#include <linux/bug.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070027
28#include <asm/ptrace.h>
29#include <asm/string.h>
30#include <asm/prom.h>
31#include <asm/machdep.h>
Paul Mackerrasf78541dc2005-10-28 22:53:37 +100032#include <asm/xmon.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <asm/processor.h>
34#include <asm/pgtable.h>
35#include <asm/mmu.h>
36#include <asm/mmu_context.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#include <asm/cputable.h>
38#include <asm/rtas.h>
39#include <asm/sstep.h>
Paul Mackerrasf583ffc2006-10-10 11:47:07 +100040#include <asm/irq_regs.h>
Michael Ellermanff8a8f22006-10-24 18:31:27 +020041#include <asm/spu.h>
42#include <asm/spu_priv1.h>
Michael Neulingc3b75bd2008-01-18 15:50:30 +110043#include <asm/setjmp.h>
Anton Vorontsov322b4392008-12-17 10:08:55 +000044#include <asm/reg.h>
David Howellsae3a1972012-03-28 18:30:02 +010045#include <asm/debug.h>
Michael Neuling9422de32012-12-20 14:06:44 +000046#include <asm/hw_breakpoint.h>
Paul Mackerrasf78541dc2005-10-28 22:53:37 +100047
48#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <asm/hvcall.h>
Paul Mackerrasf78541dc2005-10-28 22:53:37 +100050#include <asm/paca.h>
51#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070052
53#include "nonstdio.h"
Michael Ellermane0426042006-11-23 00:46:45 +010054#include "dis-asm.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070055
Linus Torvalds1da177e2005-04-16 15:20:36 -070056#ifdef CONFIG_SMP
Michael Ellerman1c8950f2008-05-08 14:27:17 +100057static cpumask_t cpus_in_xmon = CPU_MASK_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070058static unsigned long xmon_taken = 1;
59static int xmon_owner;
60static int xmon_gate;
Michael Ellermanddadb6b2012-09-13 23:01:31 +000061#else
62#define xmon_owner 0
Linus Torvalds1da177e2005-04-16 15:20:36 -070063#endif /* CONFIG_SMP */
64
Anton Blanchard5be34922010-01-12 00:50:14 +000065static unsigned long in_xmon __read_mostly = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
67static unsigned long adrs;
68static int size = 1;
69#define MAX_DUMP (128 * 1024)
70static unsigned long ndump = 64;
71static unsigned long nidump = 16;
72static unsigned long ncsum = 4096;
73static int termch;
74static char tmpstr[128];
75
Linus Torvalds1da177e2005-04-16 15:20:36 -070076static long bus_error_jmp[JMP_BUF_LEN];
77static int catch_memory_errors;
78static long *xmon_fault_jmp[NR_CPUS];
Linus Torvalds1da177e2005-04-16 15:20:36 -070079
80/* Breakpoint stuff */
81struct bpt {
82 unsigned long address;
83 unsigned int instr[2];
84 atomic_t ref_count;
85 int enabled;
86 unsigned long pad;
87};
88
89/* Bits in bpt.enabled */
90#define BP_IABR_TE 1 /* IABR translation enabled */
91#define BP_IABR 2
92#define BP_TRAP 8
93#define BP_DABR 0x10
94
95#define NBPTS 256
96static struct bpt bpts[NBPTS];
97static struct bpt dabr;
98static struct bpt *iabr;
99static unsigned bpinstr = 0x7fe00008; /* trap */
100
101#define BP_NUM(bp) ((bp) - bpts + 1)
102
103/* Prototypes */
104static int cmds(struct pt_regs *);
105static int mread(unsigned long, void *, int);
106static int mwrite(unsigned long, void *, int);
107static int handle_fault(struct pt_regs *);
108static void byterev(unsigned char *, int);
109static void memex(void);
110static int bsesc(void);
111static void dump(void);
112static void prdump(unsigned long, long);
113static int ppc_inst_dump(unsigned long, long, int);
Vinay Sridharf312deb2009-05-14 23:13:07 +0000114static void dump_log_buf(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115static void backtrace(struct pt_regs *);
116static void excprint(struct pt_regs *);
117static void prregs(struct pt_regs *);
118static void memops(int);
119static void memlocate(void);
120static void memzcan(void);
121static void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned);
122int skipbl(void);
123int scanhex(unsigned long *valp);
124static void scannl(void);
125static int hexdigit(int);
126void getstring(char *, int);
127static void flush_input(void);
128static int inchar(void);
129static void take_input(char *);
130static unsigned long read_spr(int);
131static void write_spr(int, unsigned long);
132static void super_regs(void);
133static void remove_bpts(void);
134static void insert_bpts(void);
135static void remove_cpu_bpts(void);
136static void insert_cpu_bpts(void);
137static struct bpt *at_breakpoint(unsigned long pc);
138static struct bpt *in_breakpoint_table(unsigned long pc, unsigned long *offp);
139static int do_step(struct pt_regs *);
140static void bpt_cmds(void);
141static void cacheflush(void);
142static int cpu_cmd(void);
143static void csum(void);
144static void bootcmds(void);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000145static void proccall(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146void dump_segments(void);
147static void symbol_lookup(void);
Olaf Hering26c8af52006-09-08 16:29:21 +0200148static void xmon_show_stack(unsigned long sp, unsigned long lr,
149 unsigned long pc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150static void xmon_print_symbol(unsigned long address, const char *mid,
151 const char *after);
152static const char *getvecname(unsigned long vec);
153
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200154static int do_spu_cmd(void);
155
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100156#ifdef CONFIG_44x
157static void dump_tlb_44x(void);
158#endif
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +1000159#ifdef CONFIG_PPC_BOOK3E
160static void dump_tlb_book3e(void);
161#endif
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100162
Michael Ellerman9f1067c22008-05-08 14:27:16 +1000163static int xmon_no_auto_backtrace;
Olaf Hering26c8af52006-09-08 16:29:21 +0200164
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000165extern void xmon_enter(void);
166extern void xmon_leave(void);
167
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000168#ifdef CONFIG_PPC64
169#define REG "%.16lx"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000170#else
171#define REG "%.8lx"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000172#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173
174#define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
175
176#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
177 || ('a' <= (c) && (c) <= 'f') \
178 || ('A' <= (c) && (c) <= 'F'))
179#define isalnum(c) (('0' <= (c) && (c) <= '9') \
180 || ('a' <= (c) && (c) <= 'z') \
181 || ('A' <= (c) && (c) <= 'Z'))
182#define isspace(c) (c == ' ' || c == '\t' || c == 10 || c == 13 || c == 0)
183
184static char *help_string = "\
185Commands:\n\
186 b show breakpoints\n\
187 bd set data breakpoint\n\
188 bi set instruction breakpoint\n\
189 bc clear breakpoint\n"
190#ifdef CONFIG_SMP
191 "\
192 c print cpus stopped in xmon\n\
193 c# try to switch to cpu number h (in hex)\n"
194#endif
195 "\
196 C checksum\n\
197 d dump bytes\n\
198 di dump instructions\n\
199 df dump float values\n\
200 dd dump double values\n\
Michael Ellermanddadb6b2012-09-13 23:01:31 +0000201 dl dump the kernel log buffer\n"
202#ifdef CONFIG_PPC64
203 "\
204 dp[#] dump paca for current cpu, or cpu #\n\
205 dpa dump paca for all possible cpus\n"
206#endif
207 "\
Olaf Hering7e5b5932006-03-08 20:40:28 +0100208 dr dump stream of raw bytes\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 e print exception information\n\
210 f flush cache\n\
211 la lookup symbol+offset of specified address\n\
212 ls lookup address of specified symbol\n\
213 m examine/change memory\n\
214 mm move a block of memory\n\
215 ms set a block of memory\n\
216 md compare two blocks of memory\n\
217 ml locate a block of memory\n\
218 mz zero a block of memory\n\
219 mi show information about memory allocation\n\
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000220 p call a procedure\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 r print registers\n\
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200222 s single step\n"
Arnd Bergmanne0555952006-11-27 19:18:55 +0100223#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200224" ss stop execution on all spus\n\
Michael Ellermana8984972006-10-24 18:31:28 +0200225 sr restore execution on stopped spus\n\
Michael Ellerman24a24c82006-11-23 00:46:41 +0100226 sf # dump spu fields for spu # (in hex)\n\
Michael Ellermanc99176a2007-02-26 18:14:06 +0900227 sd # dump spu local store for spu # (in hex)\n\
Michael Ellermanaf89fb82006-11-23 00:46:44 +0100228 sdi # disassemble spu local store for spu # (in hex)\n"
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200229#endif
230" S print special registers\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 t print backtrace\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 x exit monitor and recover\n\
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000233 X exit monitor and dont recover\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000234#if defined(CONFIG_PPC64) && !defined(CONFIG_PPC_BOOK3E)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000235" u dump segment table or SLB\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000236#elif defined(CONFIG_PPC_STD_MMU_32)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000237" u dump segment registers\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000238#elif defined(CONFIG_44x) || defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100239" u dump TLB\n"
240#endif
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000241" ? help\n"
242" zr reboot\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 zh halt\n"
244;
245
246static struct pt_regs *xmon_regs;
247
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000248static inline void sync(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249{
250 asm volatile("sync; isync");
251}
252
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000253static inline void store_inst(void *p)
254{
255 asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p));
256}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000258static inline void cflush(void *p)
259{
260 asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p));
261}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000263static inline void cinval(void *p)
264{
265 asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p));
266}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267
268/*
269 * Disable surveillance (the service processor watchdog function)
270 * while we are in xmon.
271 * XXX we should re-enable it when we leave. :)
272 */
273#define SURVEILLANCE_TOKEN 9000
274
275static inline void disable_surveillance(void)
276{
277#ifdef CONFIG_PPC_PSERIES
278 /* Since this can't be a module, args should end up below 4GB. */
279 static struct rtas_args args;
280
281 /*
282 * At this point we have got all the cpus we can into
283 * xmon, so there is hopefully no other cpu calling RTAS
284 * at the moment, even though we don't take rtas.lock.
285 * If we did try to take rtas.lock there would be a
286 * real possibility of deadlock.
287 */
288 args.token = rtas_token("set-indicator");
289 if (args.token == RTAS_UNKNOWN_SERVICE)
290 return;
291 args.nargs = 3;
292 args.nret = 1;
293 args.rets = &args.args[3];
294 args.args[0] = SURVEILLANCE_TOKEN;
295 args.args[1] = 0;
296 args.args[2] = 0;
297 enter_rtas(__pa(&args));
298#endif /* CONFIG_PPC_PSERIES */
299}
300
301#ifdef CONFIG_SMP
302static int xmon_speaker;
303
304static void get_output_lock(void)
305{
306 int me = smp_processor_id() + 0x100;
307 int last_speaker = 0, prev;
308 long timeout;
309
310 if (xmon_speaker == me)
311 return;
312 for (;;) {
313 if (xmon_speaker == 0) {
314 last_speaker = cmpxchg(&xmon_speaker, 0, me);
315 if (last_speaker == 0)
316 return;
317 }
318 timeout = 10000000;
319 while (xmon_speaker == last_speaker) {
320 if (--timeout > 0)
321 continue;
322 /* hostile takeover */
323 prev = cmpxchg(&xmon_speaker, last_speaker, me);
324 if (prev == last_speaker)
325 return;
326 break;
327 }
328 }
329}
330
331static void release_output_lock(void)
332{
333 xmon_speaker = 0;
334}
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000335
336int cpus_are_in_xmon(void)
337{
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000338 return !cpumask_empty(&cpus_in_xmon);
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000339}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340#endif
341
Josh Boyerdaf8f402009-09-23 03:51:04 +0000342static inline int unrecoverable_excp(struct pt_regs *regs)
343{
Jimi Xenidis08f6d6a2011-09-29 12:05:28 +0000344#if defined(CONFIG_4xx) || defined(CONFIG_PPC_BOOK3E)
Jimi Xenidis66857b32011-09-23 05:40:46 +0000345 /* We have no MSR_RI bit on 4xx or Book3e, so we simply return false */
Josh Boyerdaf8f402009-09-23 03:51:04 +0000346 return 0;
347#else
348 return ((regs->msr & MSR_RI) == 0);
349#endif
350}
351
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000352static int xmon_core(struct pt_regs *regs, int fromipi)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353{
354 int cmd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 struct bpt *bp;
356 long recurse_jmp[JMP_BUF_LEN];
357 unsigned long offset;
Anton Blanchardf13659e2007-03-21 01:48:34 +1100358 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359#ifdef CONFIG_SMP
360 int cpu;
361 int secondary;
362 unsigned long timeout;
363#endif
364
Anton Blanchardf13659e2007-03-21 01:48:34 +1100365 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366
367 bp = in_breakpoint_table(regs->nip, &offset);
368 if (bp != NULL) {
369 regs->nip = bp->address + offset;
370 atomic_dec(&bp->ref_count);
371 }
372
373 remove_cpu_bpts();
374
375#ifdef CONFIG_SMP
376 cpu = smp_processor_id();
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000377 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 get_output_lock();
379 excprint(regs);
380 printf("cpu 0x%x: Exception %lx %s in xmon, "
381 "returning to main loop\n",
382 cpu, regs->trap, getvecname(TRAP(regs)));
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000383 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 longjmp(xmon_fault_jmp[cpu], 1);
385 }
386
387 if (setjmp(recurse_jmp) != 0) {
388 if (!in_xmon || !xmon_gate) {
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000389 get_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 printf("xmon: WARNING: bad recursive fault "
391 "on cpu 0x%x\n", cpu);
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000392 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 goto waiting;
394 }
395 secondary = !(xmon_taken && cpu == xmon_owner);
396 goto cmdloop;
397 }
398
399 xmon_fault_jmp[cpu] = recurse_jmp;
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000400 cpumask_set_cpu(cpu, &cpus_in_xmon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401
402 bp = NULL;
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000403 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 bp = at_breakpoint(regs->nip);
Josh Boyerdaf8f402009-09-23 03:51:04 +0000405 if (bp || unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 fromipi = 0;
407
408 if (!fromipi) {
409 get_output_lock();
410 excprint(regs);
411 if (bp) {
412 printf("cpu 0x%x stopped at breakpoint 0x%x (",
413 cpu, BP_NUM(bp));
414 xmon_print_symbol(regs->nip, " ", ")\n");
415 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000416 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 printf("WARNING: exception is not recoverable, "
418 "can't continue\n");
419 release_output_lock();
420 }
421
422 waiting:
423 secondary = 1;
424 while (secondary && !xmon_gate) {
425 if (in_xmon == 0) {
426 if (fromipi)
427 goto leave;
428 secondary = test_and_set_bit(0, &in_xmon);
429 }
430 barrier();
431 }
432
433 if (!secondary && !xmon_gate) {
434 /* we are the first cpu to come in */
435 /* interrupt other cpu(s) */
436 int ncpus = num_online_cpus();
437
438 xmon_owner = cpu;
439 mb();
440 if (ncpus > 1) {
Milton Millere0476372011-05-10 19:29:06 +0000441 smp_send_debugger_break();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 /* wait for other cpus to come in */
443 for (timeout = 100000000; timeout != 0; --timeout) {
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000444 if (cpumask_weight(&cpus_in_xmon) >= ncpus)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 break;
446 barrier();
447 }
448 }
449 remove_bpts();
450 disable_surveillance();
451 /* for breakpoint or single step, print the current instr. */
452 if (bp || TRAP(regs) == 0xd00)
453 ppc_inst_dump(regs->nip, 1, 0);
454 printf("enter ? for help\n");
455 mb();
456 xmon_gate = 1;
457 barrier();
458 }
459
460 cmdloop:
461 while (in_xmon) {
462 if (secondary) {
463 if (cpu == xmon_owner) {
464 if (!test_and_set_bit(0, &xmon_taken)) {
465 secondary = 0;
466 continue;
467 }
468 /* missed it */
469 while (cpu == xmon_owner)
470 barrier();
471 }
472 barrier();
473 } else {
474 cmd = cmds(regs);
475 if (cmd != 0) {
476 /* exiting xmon */
477 insert_bpts();
478 xmon_gate = 0;
479 wmb();
480 in_xmon = 0;
481 break;
482 }
483 /* have switched to some other cpu */
484 secondary = 1;
485 }
486 }
487 leave:
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000488 cpumask_clear_cpu(cpu, &cpus_in_xmon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 xmon_fault_jmp[cpu] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490#else
491 /* UP is simple... */
492 if (in_xmon) {
493 printf("Exception %lx %s in xmon, returning to main loop\n",
494 regs->trap, getvecname(TRAP(regs)));
495 longjmp(xmon_fault_jmp[0], 1);
496 }
497 if (setjmp(recurse_jmp) == 0) {
498 xmon_fault_jmp[0] = recurse_jmp;
499 in_xmon = 1;
500
501 excprint(regs);
502 bp = at_breakpoint(regs->nip);
503 if (bp) {
504 printf("Stopped at breakpoint %x (", BP_NUM(bp));
505 xmon_print_symbol(regs->nip, " ", ")\n");
506 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000507 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 printf("WARNING: exception is not recoverable, "
509 "can't continue\n");
510 remove_bpts();
511 disable_surveillance();
512 /* for breakpoint or single step, print the current instr. */
513 if (bp || TRAP(regs) == 0xd00)
514 ppc_inst_dump(regs->nip, 1, 0);
515 printf("enter ? for help\n");
516 }
517
518 cmd = cmds(regs);
519
520 insert_bpts();
521 in_xmon = 0;
522#endif
523
Josh Boyercdd39042009-10-05 04:46:05 +0000524#ifdef CONFIG_BOOKE
525 if (regs->msr & MSR_DE) {
526 bp = at_breakpoint(regs->nip);
527 if (bp != NULL) {
528 regs->nip = (unsigned long) &bp->instr[0];
529 atomic_inc(&bp->ref_count);
530 }
531 }
532#else
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000533 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 bp = at_breakpoint(regs->nip);
535 if (bp != NULL) {
536 int stepped = emulate_step(regs, bp->instr[0]);
537 if (stepped == 0) {
538 regs->nip = (unsigned long) &bp->instr[0];
539 atomic_inc(&bp->ref_count);
540 } else if (stepped < 0) {
541 printf("Couldn't single-step %s instruction\n",
542 (IS_RFID(bp->instr[0])? "rfid": "mtmsrd"));
543 }
544 }
545 }
Josh Boyercdd39042009-10-05 04:46:05 +0000546#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 insert_cpu_bpts();
548
Anton Blanchardf13659e2007-03-21 01:48:34 +1100549 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550
Paul Mackerras0a730ae2006-10-03 21:32:49 +1000551 return cmd != 'X' && cmd != EOF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552}
553
554int xmon(struct pt_regs *excp)
555{
556 struct pt_regs regs;
557
558 if (excp == NULL) {
Anton Vorontsov322b4392008-12-17 10:08:55 +0000559 ppc_save_regs(&regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 excp = &regs;
561 }
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200562
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 return xmon_core(excp, 0);
564}
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000565EXPORT_SYMBOL(xmon);
566
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000567irqreturn_t xmon_irq(int irq, void *d)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000568{
569 unsigned long flags;
570 local_irq_save(flags);
571 printf("Keyboard interrupt\n");
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000572 xmon(get_irq_regs());
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000573 local_irq_restore(flags);
574 return IRQ_HANDLED;
575}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000577static int xmon_bpt(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578{
579 struct bpt *bp;
580 unsigned long offset;
581
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000582 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 return 0;
584
585 /* Are we at the trap at bp->instr[1] for some bp? */
586 bp = in_breakpoint_table(regs->nip, &offset);
587 if (bp != NULL && offset == 4) {
588 regs->nip = bp->address + 4;
589 atomic_dec(&bp->ref_count);
590 return 1;
591 }
592
593 /* Are we at a breakpoint? */
594 bp = at_breakpoint(regs->nip);
595 if (!bp)
596 return 0;
597
598 xmon_core(regs, 0);
599
600 return 1;
601}
602
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000603static int xmon_sstep(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604{
605 if (user_mode(regs))
606 return 0;
607 xmon_core(regs, 0);
608 return 1;
609}
610
Michael Neuling9422de32012-12-20 14:06:44 +0000611static int xmon_break_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000613 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 return 0;
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000615 if (dabr.enabled == 0)
616 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 xmon_core(regs, 0);
618 return 1;
619}
620
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000621static int xmon_iabr_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000623 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 return 0;
Michael Ellerman9f1067c22008-05-08 14:27:16 +1000625 if (iabr == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 return 0;
627 xmon_core(regs, 0);
628 return 1;
629}
630
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000631static int xmon_ipi(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632{
633#ifdef CONFIG_SMP
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000634 if (in_xmon && !cpumask_test_cpu(smp_processor_id(), &cpus_in_xmon))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 xmon_core(regs, 1);
636#endif
637 return 0;
638}
639
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000640static int xmon_fault_handler(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641{
642 struct bpt *bp;
643 unsigned long offset;
644
645 if (in_xmon && catch_memory_errors)
646 handle_fault(regs); /* doesn't return */
647
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000648 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 bp = in_breakpoint_table(regs->nip, &offset);
650 if (bp != NULL) {
651 regs->nip = bp->address + offset;
652 atomic_dec(&bp->ref_count);
653 }
654 }
655
656 return 0;
657}
658
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659static struct bpt *at_breakpoint(unsigned long pc)
660{
661 int i;
662 struct bpt *bp;
663
664 bp = bpts;
665 for (i = 0; i < NBPTS; ++i, ++bp)
666 if (bp->enabled && pc == bp->address)
667 return bp;
668 return NULL;
669}
670
671static struct bpt *in_breakpoint_table(unsigned long nip, unsigned long *offp)
672{
673 unsigned long off;
674
675 off = nip - (unsigned long) bpts;
676 if (off >= sizeof(bpts))
677 return NULL;
678 off %= sizeof(struct bpt);
679 if (off != offsetof(struct bpt, instr[0])
680 && off != offsetof(struct bpt, instr[1]))
681 return NULL;
682 *offp = off - offsetof(struct bpt, instr[0]);
683 return (struct bpt *) (nip - off);
684}
685
686static struct bpt *new_breakpoint(unsigned long a)
687{
688 struct bpt *bp;
689
690 a &= ~3UL;
691 bp = at_breakpoint(a);
692 if (bp)
693 return bp;
694
695 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
696 if (!bp->enabled && atomic_read(&bp->ref_count) == 0) {
697 bp->address = a;
698 bp->instr[1] = bpinstr;
699 store_inst(&bp->instr[1]);
700 return bp;
701 }
702 }
703
704 printf("Sorry, no free breakpoints. Please clear one first.\n");
705 return NULL;
706}
707
708static void insert_bpts(void)
709{
710 int i;
711 struct bpt *bp;
712
713 bp = bpts;
714 for (i = 0; i < NBPTS; ++i, ++bp) {
715 if ((bp->enabled & (BP_TRAP|BP_IABR)) == 0)
716 continue;
717 if (mread(bp->address, &bp->instr[0], 4) != 4) {
718 printf("Couldn't read instruction at %lx, "
719 "disabling breakpoint there\n", bp->address);
720 bp->enabled = 0;
721 continue;
722 }
723 if (IS_MTMSRD(bp->instr[0]) || IS_RFID(bp->instr[0])) {
724 printf("Breakpoint at %lx is on an mtmsrd or rfid "
725 "instruction, disabling it\n", bp->address);
726 bp->enabled = 0;
727 continue;
728 }
729 store_inst(&bp->instr[0]);
730 if (bp->enabled & BP_IABR)
731 continue;
732 if (mwrite(bp->address, &bpinstr, 4) != 4) {
733 printf("Couldn't write instruction at %lx, "
734 "disabling breakpoint there\n", bp->address);
735 bp->enabled &= ~BP_TRAP;
736 continue;
737 }
738 store_inst((void *)bp->address);
739 }
740}
741
742static void insert_cpu_bpts(void)
743{
Michael Neuling9422de32012-12-20 14:06:44 +0000744 struct arch_hw_breakpoint brk;
745
746 if (dabr.enabled) {
747 brk.address = dabr.address;
748 brk.type = (dabr.enabled & HW_BRK_TYPE_DABR) | HW_BRK_TYPE_PRIV_ALL;
749 brk.len = 8;
Michael Neulingb9818c32013-01-10 14:25:34 +0000750 set_breakpoint(&brk);
Michael Neuling9422de32012-12-20 14:06:44 +0000751 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 if (iabr && cpu_has_feature(CPU_FTR_IABR))
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000753 mtspr(SPRN_IABR, iabr->address
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 | (iabr->enabled & (BP_IABR|BP_IABR_TE)));
755}
756
757static void remove_bpts(void)
758{
759 int i;
760 struct bpt *bp;
761 unsigned instr;
762
763 bp = bpts;
764 for (i = 0; i < NBPTS; ++i, ++bp) {
765 if ((bp->enabled & (BP_TRAP|BP_IABR)) != BP_TRAP)
766 continue;
767 if (mread(bp->address, &instr, 4) == 4
768 && instr == bpinstr
769 && mwrite(bp->address, &bp->instr, 4) != 4)
770 printf("Couldn't remove breakpoint at %lx\n",
771 bp->address);
772 else
773 store_inst((void *)bp->address);
774 }
775}
776
777static void remove_cpu_bpts(void)
778{
Michael Neuling9422de32012-12-20 14:06:44 +0000779 hw_breakpoint_disable();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 if (cpu_has_feature(CPU_FTR_IABR))
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000781 mtspr(SPRN_IABR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782}
783
784/* Command interpreting routine */
785static char *last_cmd;
786
787static int
788cmds(struct pt_regs *excp)
789{
790 int cmd = 0;
791
792 last_cmd = NULL;
793 xmon_regs = excp;
Olaf Hering26c8af52006-09-08 16:29:21 +0200794
795 if (!xmon_no_auto_backtrace) {
796 xmon_no_auto_backtrace = 1;
797 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
798 }
799
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 for(;;) {
801#ifdef CONFIG_SMP
802 printf("%x:", smp_processor_id());
803#endif /* CONFIG_SMP */
804 printf("mon> ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 flush_input();
806 termch = 0;
807 cmd = skipbl();
808 if( cmd == '\n' ) {
809 if (last_cmd == NULL)
810 continue;
811 take_input(last_cmd);
812 last_cmd = NULL;
813 cmd = inchar();
814 }
815 switch (cmd) {
816 case 'm':
817 cmd = inchar();
818 switch (cmd) {
819 case 'm':
820 case 's':
821 case 'd':
822 memops(cmd);
823 break;
824 case 'l':
825 memlocate();
826 break;
827 case 'z':
828 memzcan();
829 break;
830 case 'i':
David Rientjesb2b755b2011-03-24 15:18:15 -0700831 show_mem(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 break;
833 default:
834 termch = cmd;
835 memex();
836 }
837 break;
838 case 'd':
839 dump();
840 break;
841 case 'l':
842 symbol_lookup();
843 break;
844 case 'r':
845 prregs(excp); /* print regs */
846 break;
847 case 'e':
848 excprint(excp);
849 break;
850 case 'S':
851 super_regs();
852 break;
853 case 't':
854 backtrace(excp);
855 break;
856 case 'f':
857 cacheflush();
858 break;
859 case 's':
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200860 if (do_spu_cmd() == 0)
861 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 if (do_step(excp))
863 return cmd;
864 break;
865 case 'x':
866 case 'X':
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100867 return cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 case EOF:
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100869 printf(" <no input ...>\n");
870 mdelay(2000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 return cmd;
872 case '?':
Ishizaki Kou4d404ed2007-07-18 19:26:40 +1000873 xmon_puts(help_string);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 case 'b':
876 bpt_cmds();
877 break;
878 case 'C':
879 csum();
880 break;
881 case 'c':
882 if (cpu_cmd())
883 return 0;
884 break;
885 case 'z':
886 bootcmds();
887 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000888 case 'p':
889 proccall();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000891#ifdef CONFIG_PPC_STD_MMU
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 case 'u':
893 dump_segments();
894 break;
Jimi Xenidis79873e82011-09-29 11:25:10 +0000895#elif defined(CONFIG_4xx)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100896 case 'u':
897 dump_tlb_44x();
898 break;
Jimi Xenidis79873e82011-09-29 11:25:10 +0000899#elif defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +1000900 case 'u':
901 dump_tlb_book3e();
902 break;
903#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 default:
905 printf("Unrecognized command: ");
Michael Ellermane3bc8042012-08-23 22:09:13 +0000906 do {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 if (' ' < cmd && cmd <= '~')
908 putchar(cmd);
909 else
910 printf("\\x%x", cmd);
911 cmd = inchar();
Michael Ellermane3bc8042012-08-23 22:09:13 +0000912 } while (cmd != '\n');
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 printf(" (type ? for help)\n");
914 break;
915 }
916 }
917}
918
Josh Boyercdd39042009-10-05 04:46:05 +0000919#ifdef CONFIG_BOOKE
920static int do_step(struct pt_regs *regs)
921{
922 regs->msr |= MSR_DE;
923 mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
924 return 1;
925}
926#else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927/*
928 * Step a single instruction.
929 * Some instructions we emulate, others we execute with MSR_SE set.
930 */
931static int do_step(struct pt_regs *regs)
932{
933 unsigned int instr;
934 int stepped;
935
936 /* check we are in 64-bit kernel mode, translation enabled */
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000937 if ((regs->msr & (MSR_64BIT|MSR_PR|MSR_IR)) == (MSR_64BIT|MSR_IR)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 if (mread(regs->nip, &instr, 4) == 4) {
939 stepped = emulate_step(regs, instr);
940 if (stepped < 0) {
941 printf("Couldn't single-step %s instruction\n",
942 (IS_RFID(instr)? "rfid": "mtmsrd"));
943 return 0;
944 }
945 if (stepped > 0) {
946 regs->trap = 0xd00 | (regs->trap & 1);
947 printf("stepped to ");
948 xmon_print_symbol(regs->nip, " ", "\n");
949 ppc_inst_dump(regs->nip, 1, 0);
950 return 0;
951 }
952 }
953 }
954 regs->msr |= MSR_SE;
955 return 1;
956}
Josh Boyercdd39042009-10-05 04:46:05 +0000957#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958
959static void bootcmds(void)
960{
961 int cmd;
962
963 cmd = inchar();
964 if (cmd == 'r')
965 ppc_md.restart(NULL);
966 else if (cmd == 'h')
967 ppc_md.halt();
968 else if (cmd == 'p')
969 ppc_md.power_off();
970}
971
972static int cpu_cmd(void)
973{
974#ifdef CONFIG_SMP
Paul Mackerrasfd3bb912013-09-03 20:16:23 +1000975 unsigned long cpu, first_cpu, last_cpu;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 int timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977
978 if (!scanhex(&cpu)) {
979 /* print cpus waiting or in xmon */
980 printf("cpus stopped:");
Paul Mackerrasfd3bb912013-09-03 20:16:23 +1000981 last_cpu = first_cpu = NR_CPUS;
Anton Blanchardbc1d7702012-06-28 19:28:57 +0000982 for_each_possible_cpu(cpu) {
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000983 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Paul Mackerrasfd3bb912013-09-03 20:16:23 +1000984 if (cpu == last_cpu + 1) {
985 last_cpu = cpu;
986 } else {
987 if (last_cpu != first_cpu)
988 printf("-%lx", last_cpu);
989 last_cpu = first_cpu = cpu;
990 printf(" %lx", cpu);
991 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 }
993 }
Paul Mackerrasfd3bb912013-09-03 20:16:23 +1000994 if (last_cpu != first_cpu)
995 printf("-%lx", last_cpu);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 printf("\n");
997 return 0;
998 }
999 /* try to switch to cpu specified */
KOSAKI Motohiro104699c2011-04-28 05:07:23 +00001000 if (!cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 printf("cpu 0x%x isn't in xmon\n", cpu);
1002 return 0;
1003 }
1004 xmon_taken = 0;
1005 mb();
1006 xmon_owner = cpu;
1007 timeout = 10000000;
1008 while (!xmon_taken) {
1009 if (--timeout == 0) {
1010 if (test_and_set_bit(0, &xmon_taken))
1011 break;
1012 /* take control back */
1013 mb();
1014 xmon_owner = smp_processor_id();
1015 printf("cpu %u didn't take control\n", cpu);
1016 return 0;
1017 }
1018 barrier();
1019 }
1020 return 1;
1021#else
1022 return 0;
1023#endif /* CONFIG_SMP */
1024}
1025
1026static unsigned short fcstab[256] = {
1027 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
1028 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
1029 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
1030 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
1031 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
1032 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
1033 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
1034 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
1035 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
1036 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
1037 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
1038 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
1039 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
1040 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
1041 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
1042 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
1043 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
1044 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
1045 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
1046 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
1047 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
1048 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
1049 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
1050 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
1051 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
1052 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
1053 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
1054 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
1055 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
1056 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
1057 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
1058 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
1059};
1060
1061#define FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
1062
1063static void
1064csum(void)
1065{
1066 unsigned int i;
1067 unsigned short fcs;
1068 unsigned char v;
1069
1070 if (!scanhex(&adrs))
1071 return;
1072 if (!scanhex(&ncsum))
1073 return;
1074 fcs = 0xffff;
1075 for (i = 0; i < ncsum; ++i) {
1076 if (mread(adrs+i, &v, 1) == 0) {
1077 printf("csum stopped at %x\n", adrs+i);
1078 break;
1079 }
1080 fcs = FCS(fcs, v);
1081 }
1082 printf("%x\n", fcs);
1083}
1084
1085/*
1086 * Check if this is a suitable place to put a breakpoint.
1087 */
1088static long check_bp_loc(unsigned long addr)
1089{
1090 unsigned int instr;
1091
1092 addr &= ~3;
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001093 if (!is_kernel_addr(addr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 printf("Breakpoints may only be placed at kernel addresses\n");
1095 return 0;
1096 }
1097 if (!mread(addr, &instr, sizeof(instr))) {
1098 printf("Can't read instruction at address %lx\n", addr);
1099 return 0;
1100 }
1101 if (IS_MTMSRD(instr) || IS_RFID(instr)) {
1102 printf("Breakpoints may not be placed on mtmsrd or rfid "
1103 "instructions\n");
1104 return 0;
1105 }
1106 return 1;
1107}
1108
Michael Ellermane3bc8042012-08-23 22:09:13 +00001109static char *breakpoint_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 "Breakpoint command usage:\n"
1111 "b show breakpoints\n"
1112 "b <addr> [cnt] set breakpoint at given instr addr\n"
1113 "bc clear all breakpoints\n"
1114 "bc <n/addr> clear breakpoint number n or at addr\n"
1115 "bi <addr> [cnt] set hardware instr breakpoint (POWER3/RS64 only)\n"
1116 "bd <addr> [cnt] set hardware data breakpoint\n"
1117 "";
1118
1119static void
1120bpt_cmds(void)
1121{
1122 int cmd;
1123 unsigned long a;
1124 int mode, i;
1125 struct bpt *bp;
1126 const char badaddr[] = "Only kernel addresses are permitted "
1127 "for breakpoints\n";
1128
1129 cmd = inchar();
1130 switch (cmd) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001131#ifndef CONFIG_8xx
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 case 'd': /* bd - hardware data breakpoint */
1133 mode = 7;
1134 cmd = inchar();
1135 if (cmd == 'r')
1136 mode = 5;
1137 else if (cmd == 'w')
1138 mode = 6;
1139 else
1140 termch = cmd;
1141 dabr.address = 0;
1142 dabr.enabled = 0;
1143 if (scanhex(&dabr.address)) {
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001144 if (!is_kernel_addr(dabr.address)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 printf(badaddr);
1146 break;
1147 }
Michael Neuling9422de32012-12-20 14:06:44 +00001148 dabr.address &= ~HW_BRK_TYPE_DABR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 dabr.enabled = mode | BP_DABR;
1150 }
1151 break;
1152
1153 case 'i': /* bi - hardware instr breakpoint */
1154 if (!cpu_has_feature(CPU_FTR_IABR)) {
1155 printf("Hardware instruction breakpoint "
1156 "not supported on this cpu\n");
1157 break;
1158 }
1159 if (iabr) {
1160 iabr->enabled &= ~(BP_IABR | BP_IABR_TE);
1161 iabr = NULL;
1162 }
1163 if (!scanhex(&a))
1164 break;
1165 if (!check_bp_loc(a))
1166 break;
1167 bp = new_breakpoint(a);
1168 if (bp != NULL) {
1169 bp->enabled |= BP_IABR | BP_IABR_TE;
1170 iabr = bp;
1171 }
1172 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001173#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174
1175 case 'c':
1176 if (!scanhex(&a)) {
1177 /* clear all breakpoints */
1178 for (i = 0; i < NBPTS; ++i)
1179 bpts[i].enabled = 0;
1180 iabr = NULL;
1181 dabr.enabled = 0;
1182 printf("All breakpoints cleared\n");
1183 break;
1184 }
1185
1186 if (a <= NBPTS && a >= 1) {
1187 /* assume a breakpoint number */
1188 bp = &bpts[a-1]; /* bp nums are 1 based */
1189 } else {
1190 /* assume a breakpoint address */
1191 bp = at_breakpoint(a);
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001192 if (bp == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 printf("No breakpoint at %x\n", a);
1194 break;
1195 }
1196 }
1197
1198 printf("Cleared breakpoint %x (", BP_NUM(bp));
1199 xmon_print_symbol(bp->address, " ", ")\n");
1200 bp->enabled = 0;
1201 break;
1202
1203 default:
1204 termch = cmd;
Michael Ellermane3bc8042012-08-23 22:09:13 +00001205 cmd = skipbl();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 if (cmd == '?') {
1207 printf(breakpoint_help_string);
1208 break;
1209 }
1210 termch = cmd;
1211 if (!scanhex(&a)) {
1212 /* print all breakpoints */
1213 printf(" type address\n");
1214 if (dabr.enabled) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001215 printf(" data "REG" [", dabr.address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 if (dabr.enabled & 1)
1217 printf("r");
1218 if (dabr.enabled & 2)
1219 printf("w");
1220 printf("]\n");
1221 }
1222 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
1223 if (!bp->enabled)
1224 continue;
1225 printf("%2x %s ", BP_NUM(bp),
1226 (bp->enabled & BP_IABR)? "inst": "trap");
1227 xmon_print_symbol(bp->address, " ", "\n");
1228 }
1229 break;
1230 }
1231
1232 if (!check_bp_loc(a))
1233 break;
1234 bp = new_breakpoint(a);
1235 if (bp != NULL)
1236 bp->enabled |= BP_TRAP;
1237 break;
1238 }
1239}
1240
1241/* Very cheap human name for vector lookup. */
1242static
1243const char *getvecname(unsigned long vec)
1244{
1245 char *ret;
1246
1247 switch (vec) {
1248 case 0x100: ret = "(System Reset)"; break;
1249 case 0x200: ret = "(Machine Check)"; break;
1250 case 0x300: ret = "(Data Access)"; break;
1251 case 0x380: ret = "(Data SLB Access)"; break;
1252 case 0x400: ret = "(Instruction Access)"; break;
1253 case 0x480: ret = "(Instruction SLB Access)"; break;
1254 case 0x500: ret = "(Hardware Interrupt)"; break;
1255 case 0x600: ret = "(Alignment)"; break;
1256 case 0x700: ret = "(Program Check)"; break;
1257 case 0x800: ret = "(FPU Unavailable)"; break;
1258 case 0x900: ret = "(Decrementer)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001259 case 0x980: ret = "(Hypervisor Decrementer)"; break;
1260 case 0xa00: ret = "(Doorbell)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261 case 0xc00: ret = "(System Call)"; break;
1262 case 0xd00: ret = "(Single Step)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001263 case 0xe40: ret = "(Emulation Assist)"; break;
1264 case 0xe60: ret = "(HMI)"; break;
1265 case 0xe80: ret = "(Hypervisor Doorbell)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 case 0xf00: ret = "(Performance Monitor)"; break;
1267 case 0xf20: ret = "(Altivec Unavailable)"; break;
1268 case 0x1300: ret = "(Instruction Breakpoint)"; break;
Michael Ellerman660e0342013-08-15 15:22:16 +10001269 case 0x1500: ret = "(Denormalisation)"; break;
1270 case 0x1700: ret = "(Altivec Assist)"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271 default: ret = "";
1272 }
1273 return ret;
1274}
1275
1276static void get_function_bounds(unsigned long pc, unsigned long *startp,
1277 unsigned long *endp)
1278{
1279 unsigned long size, offset;
1280 const char *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281
1282 *startp = *endp = 0;
1283 if (pc == 0)
1284 return;
1285 if (setjmp(bus_error_jmp) == 0) {
1286 catch_memory_errors = 1;
1287 sync();
Alexey Dobriyanffb45122007-05-08 00:28:41 -07001288 name = kallsyms_lookup(pc, &size, &offset, NULL, tmpstr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 if (name != NULL) {
1290 *startp = pc - offset;
1291 *endp = pc - offset + size;
1292 }
1293 sync();
1294 }
1295 catch_memory_errors = 0;
1296}
1297
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001298#define LRSAVE_OFFSET (STACK_FRAME_LR_SAVE * sizeof(unsigned long))
1299#define MARKER_OFFSET (STACK_FRAME_MARKER * sizeof(unsigned long))
1300
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301static void xmon_show_stack(unsigned long sp, unsigned long lr,
1302 unsigned long pc)
1303{
Michael Ellerman0104cd62012-10-09 04:20:36 +00001304 int max_to_print = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 unsigned long ip;
1306 unsigned long newsp;
1307 unsigned long marker;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 struct pt_regs regs;
1309
Michael Ellerman0104cd62012-10-09 04:20:36 +00001310 while (max_to_print--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 if (sp < PAGE_OFFSET) {
1312 if (sp != 0)
1313 printf("SP (%lx) is in userspace\n", sp);
1314 break;
1315 }
1316
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001317 if (!mread(sp + LRSAVE_OFFSET, &ip, sizeof(unsigned long))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 || !mread(sp, &newsp, sizeof(unsigned long))) {
1319 printf("Couldn't read stack frame at %lx\n", sp);
1320 break;
1321 }
1322
1323 /*
1324 * For the first stack frame, try to work out if
1325 * LR and/or the saved LR value in the bottommost
1326 * stack frame are valid.
1327 */
1328 if ((pc | lr) != 0) {
1329 unsigned long fnstart, fnend;
1330 unsigned long nextip;
1331 int printip = 1;
1332
1333 get_function_bounds(pc, &fnstart, &fnend);
1334 nextip = 0;
1335 if (newsp > sp)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001336 mread(newsp + LRSAVE_OFFSET, &nextip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 sizeof(unsigned long));
1338 if (lr == ip) {
1339 if (lr < PAGE_OFFSET
1340 || (fnstart <= lr && lr < fnend))
1341 printip = 0;
1342 } else if (lr == nextip) {
1343 printip = 0;
1344 } else if (lr >= PAGE_OFFSET
1345 && !(fnstart <= lr && lr < fnend)) {
1346 printf("[link register ] ");
1347 xmon_print_symbol(lr, " ", "\n");
1348 }
1349 if (printip) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001350 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 xmon_print_symbol(ip, " ", " (unreliable)\n");
1352 }
1353 pc = lr = 0;
1354
1355 } else {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001356 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 xmon_print_symbol(ip, " ", "\n");
1358 }
1359
1360 /* Look for "regshere" marker to see if this is
1361 an exception frame. */
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001362 if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long))
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001363 && marker == STACK_FRAME_REGS_MARKER) {
Michael Ellermanc4de3802012-10-09 04:20:35 +00001364 if (mread(sp + STACK_FRAME_OVERHEAD, &regs, sizeof(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 != sizeof(regs)) {
1366 printf("Couldn't read registers at %lx\n",
Michael Ellermanc4de3802012-10-09 04:20:35 +00001367 sp + STACK_FRAME_OVERHEAD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 break;
1369 }
Michael Ellermane3bc8042012-08-23 22:09:13 +00001370 printf("--- Exception: %lx %s at ", regs.trap,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 getvecname(TRAP(&regs)));
1372 pc = regs.nip;
1373 lr = regs.link;
1374 xmon_print_symbol(pc, " ", "\n");
1375 }
1376
1377 if (newsp == 0)
1378 break;
1379
1380 sp = newsp;
Michael Ellerman0104cd62012-10-09 04:20:36 +00001381 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382}
1383
1384static void backtrace(struct pt_regs *excp)
1385{
1386 unsigned long sp;
1387
1388 if (scanhex(&sp))
1389 xmon_show_stack(sp, 0, 0);
1390 else
1391 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
1392 scannl();
1393}
1394
1395static void print_bug_trap(struct pt_regs *regs)
1396{
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001397#ifdef CONFIG_BUG
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001398 const struct bug_entry *bug;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 unsigned long addr;
1400
1401 if (regs->msr & MSR_PR)
1402 return; /* not in kernel */
1403 addr = regs->nip; /* address of trap instruction */
1404 if (addr < PAGE_OFFSET)
1405 return;
1406 bug = find_bug(regs->nip);
1407 if (bug == NULL)
1408 return;
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001409 if (is_warning_bug(bug))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 return;
1411
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001412#ifdef CONFIG_DEBUG_BUGVERBOSE
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001413 printf("kernel BUG at %s:%u!\n",
1414 bug->file, bug->line);
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001415#else
1416 printf("kernel BUG at %p!\n", (void *)bug->bug_addr);
1417#endif
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001418#endif /* CONFIG_BUG */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419}
1420
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001421static void excprint(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422{
1423 unsigned long trap;
1424
1425#ifdef CONFIG_SMP
1426 printf("cpu 0x%x: ", smp_processor_id());
1427#endif /* CONFIG_SMP */
1428
1429 trap = TRAP(fp);
1430 printf("Vector: %lx %s at [%lx]\n", fp->trap, getvecname(trap), fp);
1431 printf(" pc: ");
1432 xmon_print_symbol(fp->nip, ": ", "\n");
1433
1434 printf(" lr: ", fp->link);
1435 xmon_print_symbol(fp->link, ": ", "\n");
1436
1437 printf(" sp: %lx\n", fp->gpr[1]);
1438 printf(" msr: %lx\n", fp->msr);
1439
Aneesh Kumar K.Vce541522013-04-28 09:37:26 +00001440 if (trap == 0x300 || trap == 0x380 || trap == 0x600 || trap == 0x200) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441 printf(" dar: %lx\n", fp->dar);
1442 if (trap != 0x380)
1443 printf(" dsisr: %lx\n", fp->dsisr);
1444 }
1445
1446 printf(" current = 0x%lx\n", current);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001447#ifdef CONFIG_PPC64
Benjamin Herrenschmidt7230c562012-03-06 18:27:59 +11001448 printf(" paca = 0x%lx\t softe: %d\t irq_happened: 0x%02x\n",
1449 local_paca, local_paca->soft_enabled, local_paca->irq_happened);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001450#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 if (current) {
1452 printf(" pid = %ld, comm = %s\n",
1453 current->pid, current->comm);
1454 }
1455
1456 if (trap == 0x700)
1457 print_bug_trap(fp);
1458}
1459
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001460static void prregs(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001462 int n, trap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 unsigned long base;
1464 struct pt_regs regs;
1465
1466 if (scanhex(&base)) {
1467 if (setjmp(bus_error_jmp) == 0) {
1468 catch_memory_errors = 1;
1469 sync();
1470 regs = *(struct pt_regs *)base;
1471 sync();
1472 __delay(200);
1473 } else {
1474 catch_memory_errors = 0;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001475 printf("*** Error reading registers from "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 base);
1477 return;
1478 }
1479 catch_memory_errors = 0;
1480 fp = &regs;
1481 }
1482
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001483#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484 if (FULL_REGS(fp)) {
1485 for (n = 0; n < 16; ++n)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001486 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487 n, fp->gpr[n], n+16, fp->gpr[n+16]);
1488 } else {
1489 for (n = 0; n < 7; ++n)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001490 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 n, fp->gpr[n], n+7, fp->gpr[n+7]);
1492 }
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001493#else
1494 for (n = 0; n < 32; ++n) {
1495 printf("R%.2d = %.8x%s", n, fp->gpr[n],
1496 (n & 3) == 3? "\n": " ");
1497 if (n == 12 && !FULL_REGS(fp)) {
1498 printf("\n");
1499 break;
1500 }
1501 }
1502#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503 printf("pc = ");
1504 xmon_print_symbol(fp->nip, " ", "\n");
Paul Mackerras48404f22011-05-01 19:48:20 +00001505 if (TRAP(fp) != 0xc00 && cpu_has_feature(CPU_FTR_CFAR)) {
1506 printf("cfar= ");
1507 xmon_print_symbol(fp->orig_gpr3, " ", "\n");
1508 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 printf("lr = ");
1510 xmon_print_symbol(fp->link, " ", "\n");
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001511 printf("msr = "REG" cr = %.8lx\n", fp->msr, fp->ccr);
1512 printf("ctr = "REG" xer = "REG" trap = %4lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 fp->ctr, fp->xer, fp->trap);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001514 trap = TRAP(fp);
1515 if (trap == 0x300 || trap == 0x380 || trap == 0x600)
1516 printf("dar = "REG" dsisr = %.8lx\n", fp->dar, fp->dsisr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517}
1518
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001519static void cacheflush(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520{
1521 int cmd;
1522 unsigned long nflush;
1523
1524 cmd = inchar();
1525 if (cmd != 'i')
1526 termch = cmd;
1527 scanhex((void *)&adrs);
1528 if (termch != '\n')
1529 termch = 0;
1530 nflush = 1;
1531 scanhex(&nflush);
1532 nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES;
1533 if (setjmp(bus_error_jmp) == 0) {
1534 catch_memory_errors = 1;
1535 sync();
1536
1537 if (cmd != 'i') {
1538 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1539 cflush((void *) adrs);
1540 } else {
1541 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1542 cinval((void *) adrs);
1543 }
1544 sync();
1545 /* wait a little while to see if we get a machine check */
1546 __delay(200);
1547 }
1548 catch_memory_errors = 0;
1549}
1550
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001551static unsigned long
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552read_spr(int n)
1553{
1554 unsigned int instrs[2];
1555 unsigned long (*code)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556 unsigned long ret = -1UL;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001557#ifdef CONFIG_PPC64
1558 unsigned long opd[3];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560 opd[0] = (unsigned long)instrs;
1561 opd[1] = 0;
1562 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001563 code = (unsigned long (*)(void)) opd;
1564#else
1565 code = (unsigned long (*)(void)) instrs;
1566#endif
1567
1568 /* mfspr r3,n; blr */
1569 instrs[0] = 0x7c6002a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1570 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571 store_inst(instrs);
1572 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573
1574 if (setjmp(bus_error_jmp) == 0) {
1575 catch_memory_errors = 1;
1576 sync();
1577
1578 ret = code();
1579
1580 sync();
1581 /* wait a little while to see if we get a machine check */
1582 __delay(200);
1583 n = size;
1584 }
1585
1586 return ret;
1587}
1588
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001589static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590write_spr(int n, unsigned long val)
1591{
1592 unsigned int instrs[2];
1593 unsigned long (*code)(unsigned long);
Paul Mackerras548cceb2005-11-11 22:36:34 +11001594#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595 unsigned long opd[3];
1596
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597 opd[0] = (unsigned long)instrs;
1598 opd[1] = 0;
1599 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001600 code = (unsigned long (*)(unsigned long)) opd;
1601#else
1602 code = (unsigned long (*)(unsigned long)) instrs;
1603#endif
1604
1605 instrs[0] = 0x7c6003a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1606 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 store_inst(instrs);
1608 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609
1610 if (setjmp(bus_error_jmp) == 0) {
1611 catch_memory_errors = 1;
1612 sync();
1613
1614 code(val);
1615
1616 sync();
1617 /* wait a little while to see if we get a machine check */
1618 __delay(200);
1619 n = size;
1620 }
1621}
1622
1623static unsigned long regno;
1624extern char exc_prolog;
1625extern char dec_exc;
1626
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001627static void super_regs(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628{
1629 int cmd;
1630 unsigned long val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631
1632 cmd = skipbl();
1633 if (cmd == '\n') {
Michael Ellermane3bc8042012-08-23 22:09:13 +00001634 unsigned long sp, toc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 asm("mr %0,1" : "=r" (sp) :);
1636 asm("mr %0,2" : "=r" (toc) :);
1637
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001638 printf("msr = "REG" sprg0= "REG"\n",
1639 mfmsr(), mfspr(SPRN_SPRG0));
1640 printf("pvr = "REG" sprg1= "REG"\n",
Michael Ellermane3bc8042012-08-23 22:09:13 +00001641 mfspr(SPRN_PVR), mfspr(SPRN_SPRG1));
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001642 printf("dec = "REG" sprg2= "REG"\n",
1643 mfspr(SPRN_DEC), mfspr(SPRN_SPRG2));
1644 printf("sp = "REG" sprg3= "REG"\n", sp, mfspr(SPRN_SPRG3));
1645 printf("toc = "REG" dar = "REG"\n", toc, mfspr(SPRN_DAR));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646
1647 return;
1648 }
1649
1650 scanhex(&regno);
1651 switch (cmd) {
1652 case 'w':
1653 val = read_spr(regno);
1654 scanhex(&val);
1655 write_spr(regno, val);
1656 /* fall through */
1657 case 'r':
1658 printf("spr %lx = %lx\n", regno, read_spr(regno));
1659 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 }
1661 scannl();
1662}
1663
1664/*
1665 * Stuff for reading and writing memory safely
1666 */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001667static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668mread(unsigned long adrs, void *buf, int size)
1669{
1670 volatile int n;
1671 char *p, *q;
1672
1673 n = 0;
1674 if (setjmp(bus_error_jmp) == 0) {
1675 catch_memory_errors = 1;
1676 sync();
1677 p = (char *)adrs;
1678 q = (char *)buf;
1679 switch (size) {
1680 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001681 *(u16 *)q = *(u16 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682 break;
1683 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001684 *(u32 *)q = *(u32 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 break;
1686 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001687 *(u64 *)q = *(u64 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688 break;
1689 default:
1690 for( ; n < size; ++n) {
1691 *q++ = *p++;
1692 sync();
1693 }
1694 }
1695 sync();
1696 /* wait a little while to see if we get a machine check */
1697 __delay(200);
1698 n = size;
1699 }
1700 catch_memory_errors = 0;
1701 return n;
1702}
1703
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001704static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705mwrite(unsigned long adrs, void *buf, int size)
1706{
1707 volatile int n;
1708 char *p, *q;
1709
1710 n = 0;
1711 if (setjmp(bus_error_jmp) == 0) {
1712 catch_memory_errors = 1;
1713 sync();
1714 p = (char *) adrs;
1715 q = (char *) buf;
1716 switch (size) {
1717 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001718 *(u16 *)p = *(u16 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719 break;
1720 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001721 *(u32 *)p = *(u32 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722 break;
1723 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001724 *(u64 *)p = *(u64 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 break;
1726 default:
1727 for ( ; n < size; ++n) {
1728 *p++ = *q++;
1729 sync();
1730 }
1731 }
1732 sync();
1733 /* wait a little while to see if we get a machine check */
1734 __delay(200);
1735 n = size;
1736 } else {
1737 printf("*** Error writing address %x\n", adrs + n);
1738 }
1739 catch_memory_errors = 0;
1740 return n;
1741}
1742
1743static int fault_type;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001744static int fault_except;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745static char *fault_chars[] = { "--", "**", "##" };
1746
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001747static int handle_fault(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001749 fault_except = TRAP(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750 switch (TRAP(regs)) {
1751 case 0x200:
1752 fault_type = 0;
1753 break;
1754 case 0x300:
1755 case 0x380:
1756 fault_type = 1;
1757 break;
1758 default:
1759 fault_type = 2;
1760 }
1761
1762 longjmp(bus_error_jmp, 1);
1763
1764 return 0;
1765}
1766
1767#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t))
1768
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001769static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770byterev(unsigned char *val, int size)
1771{
1772 int t;
1773
1774 switch (size) {
1775 case 2:
1776 SWAP(val[0], val[1], t);
1777 break;
1778 case 4:
1779 SWAP(val[0], val[3], t);
1780 SWAP(val[1], val[2], t);
1781 break;
1782 case 8: /* is there really any use for this? */
1783 SWAP(val[0], val[7], t);
1784 SWAP(val[1], val[6], t);
1785 SWAP(val[2], val[5], t);
1786 SWAP(val[3], val[4], t);
1787 break;
1788 }
1789}
1790
1791static int brev;
1792static int mnoread;
1793
Michael Ellermane3bc8042012-08-23 22:09:13 +00001794static char *memex_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 "Memory examine command usage:\n"
1796 "m [addr] [flags] examine/change memory\n"
1797 " addr is optional. will start where left off.\n"
1798 " flags may include chars from this set:\n"
1799 " b modify by bytes (default)\n"
1800 " w modify by words (2 byte)\n"
1801 " l modify by longs (4 byte)\n"
1802 " d modify by doubleword (8 byte)\n"
1803 " r toggle reverse byte order mode\n"
1804 " n do not read memory (for i/o spaces)\n"
1805 " . ok to read (default)\n"
1806 "NOTE: flags are saved as defaults\n"
1807 "";
1808
Michael Ellermane3bc8042012-08-23 22:09:13 +00001809static char *memex_subcmd_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810 "Memory examine subcommands:\n"
1811 " hexval write this val to current location\n"
1812 " 'string' write chars from string to this location\n"
1813 " ' increment address\n"
1814 " ^ decrement address\n"
1815 " / increment addr by 0x10. //=0x100, ///=0x1000, etc\n"
1816 " \\ decrement addr by 0x10. \\\\=0x100, \\\\\\=0x1000, etc\n"
1817 " ` clear no-read flag\n"
1818 " ; stay at this addr\n"
1819 " v change to byte mode\n"
1820 " w change to word (2 byte) mode\n"
1821 " l change to long (4 byte) mode\n"
1822 " u change to doubleword (8 byte) mode\n"
1823 " m addr change current addr\n"
1824 " n toggle no-read flag\n"
1825 " r toggle byte reverse flag\n"
1826 " < count back up count bytes\n"
1827 " > count skip forward count bytes\n"
1828 " x exit this mode\n"
1829 "";
1830
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001831static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832memex(void)
1833{
1834 int cmd, inc, i, nslash;
1835 unsigned long n;
1836 unsigned char val[16];
1837
1838 scanhex((void *)&adrs);
1839 cmd = skipbl();
1840 if (cmd == '?') {
1841 printf(memex_help_string);
1842 return;
1843 } else {
1844 termch = cmd;
1845 }
1846 last_cmd = "m\n";
1847 while ((cmd = skipbl()) != '\n') {
1848 switch( cmd ){
1849 case 'b': size = 1; break;
1850 case 'w': size = 2; break;
1851 case 'l': size = 4; break;
1852 case 'd': size = 8; break;
1853 case 'r': brev = !brev; break;
1854 case 'n': mnoread = 1; break;
1855 case '.': mnoread = 0; break;
1856 }
1857 }
1858 if( size <= 0 )
1859 size = 1;
1860 else if( size > 8 )
1861 size = 8;
1862 for(;;){
1863 if (!mnoread)
1864 n = mread(adrs, val, size);
Paul Mackerrase1449ed2005-11-10 14:30:20 +11001865 printf(REG"%c", adrs, brev? 'r': ' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866 if (!mnoread) {
1867 if (brev)
1868 byterev(val, size);
1869 putchar(' ');
1870 for (i = 0; i < n; ++i)
1871 printf("%.2x", val[i]);
1872 for (; i < size; ++i)
1873 printf("%s", fault_chars[fault_type]);
1874 }
1875 putchar(' ');
1876 inc = size;
1877 nslash = 0;
1878 for(;;){
1879 if( scanhex(&n) ){
1880 for (i = 0; i < size; ++i)
1881 val[i] = n >> (i * 8);
1882 if (!brev)
1883 byterev(val, size);
1884 mwrite(adrs, val, size);
1885 inc = size;
1886 }
1887 cmd = skipbl();
1888 if (cmd == '\n')
1889 break;
1890 inc = 0;
1891 switch (cmd) {
1892 case '\'':
1893 for(;;){
1894 n = inchar();
1895 if( n == '\\' )
1896 n = bsesc();
1897 else if( n == '\'' )
1898 break;
1899 for (i = 0; i < size; ++i)
1900 val[i] = n >> (i * 8);
1901 if (!brev)
1902 byterev(val, size);
1903 mwrite(adrs, val, size);
1904 adrs += size;
1905 }
1906 adrs -= size;
1907 inc = size;
1908 break;
1909 case ',':
1910 adrs += size;
1911 break;
1912 case '.':
1913 mnoread = 0;
1914 break;
1915 case ';':
1916 break;
1917 case 'x':
1918 case EOF:
1919 scannl();
1920 return;
1921 case 'b':
1922 case 'v':
1923 size = 1;
1924 break;
1925 case 'w':
1926 size = 2;
1927 break;
1928 case 'l':
1929 size = 4;
1930 break;
1931 case 'u':
1932 size = 8;
1933 break;
1934 case '^':
1935 adrs -= size;
1936 break;
1937 break;
1938 case '/':
1939 if (nslash > 0)
1940 adrs -= 1 << nslash;
1941 else
1942 nslash = 0;
1943 nslash += 4;
1944 adrs += 1 << nslash;
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 'm':
1955 scanhex((void *)&adrs);
1956 break;
1957 case 'n':
1958 mnoread = 1;
1959 break;
1960 case 'r':
1961 brev = !brev;
1962 break;
1963 case '<':
1964 n = size;
1965 scanhex(&n);
1966 adrs -= n;
1967 break;
1968 case '>':
1969 n = size;
1970 scanhex(&n);
1971 adrs += n;
1972 break;
1973 case '?':
1974 printf(memex_subcmd_help_string);
1975 break;
1976 }
1977 }
1978 adrs += inc;
1979 }
1980}
1981
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001982static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983bsesc(void)
1984{
1985 int c;
1986
1987 c = inchar();
1988 switch( c ){
1989 case 'n': c = '\n'; break;
1990 case 'r': c = '\r'; break;
1991 case 'b': c = '\b'; break;
1992 case 't': c = '\t'; break;
1993 }
1994 return c;
1995}
1996
Olaf Hering7e5b5932006-03-08 20:40:28 +01001997static void xmon_rawdump (unsigned long adrs, long ndump)
1998{
1999 long n, m, r, nr;
2000 unsigned char temp[16];
2001
2002 for (n = ndump; n > 0;) {
2003 r = n < 16? n: 16;
2004 nr = mread(adrs, temp, r);
2005 adrs += nr;
2006 for (m = 0; m < r; ++m) {
2007 if (m < nr)
2008 printf("%.2x", temp[m]);
2009 else
2010 printf("%s", fault_chars[fault_type]);
2011 }
2012 n -= r;
2013 if (nr < r)
2014 break;
2015 }
2016 printf("\n");
2017}
2018
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002019#ifdef CONFIG_PPC64
2020static void dump_one_paca(int cpu)
2021{
2022 struct paca_struct *p;
2023
2024 if (setjmp(bus_error_jmp) != 0) {
2025 printf("*** Error dumping paca for cpu 0x%x!\n", cpu);
2026 return;
2027 }
2028
2029 catch_memory_errors = 1;
2030 sync();
2031
2032 p = &paca[cpu];
2033
2034 printf("paca for cpu 0x%x @ %p:\n", cpu, p);
2035
2036 printf(" %-*s = %s\n", 16, "possible", cpu_possible(cpu) ? "yes" : "no");
2037 printf(" %-*s = %s\n", 16, "present", cpu_present(cpu) ? "yes" : "no");
2038 printf(" %-*s = %s\n", 16, "online", cpu_online(cpu) ? "yes" : "no");
2039
2040#define DUMP(paca, name, format) \
2041 printf(" %-*s = %#-*"format"\t(0x%lx)\n", 16, #name, 18, paca->name, \
2042 offsetof(struct paca_struct, name));
2043
2044 DUMP(p, lock_token, "x");
2045 DUMP(p, paca_index, "x");
2046 DUMP(p, kernel_toc, "lx");
2047 DUMP(p, kernelbase, "lx");
2048 DUMP(p, kernel_msr, "lx");
2049#ifdef CONFIG_PPC_STD_MMU_64
2050 DUMP(p, stab_real, "lx");
2051 DUMP(p, stab_addr, "lx");
2052#endif
2053 DUMP(p, emergency_sp, "p");
Mahesh Salgaonkar729b0f72013-10-30 20:04:00 +05302054#ifdef CONFIG_PPC_BOOK3S_64
2055 DUMP(p, mc_emergency_sp, "p");
2056 DUMP(p, in_mce, "x");
2057#endif
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002058 DUMP(p, data_offset, "lx");
2059 DUMP(p, hw_cpu_id, "x");
2060 DUMP(p, cpu_start, "x");
2061 DUMP(p, kexec_state, "x");
2062 DUMP(p, __current, "p");
2063 DUMP(p, kstack, "lx");
2064 DUMP(p, stab_rr, "lx");
2065 DUMP(p, saved_r1, "lx");
2066 DUMP(p, trap_save, "x");
2067 DUMP(p, soft_enabled, "x");
2068 DUMP(p, irq_happened, "x");
2069 DUMP(p, io_sync, "x");
2070 DUMP(p, irq_work_pending, "x");
2071 DUMP(p, nap_state_lost, "x");
2072
2073#undef DUMP
2074
2075 catch_memory_errors = 0;
2076 sync();
2077}
2078
2079static void dump_all_pacas(void)
2080{
2081 int cpu;
2082
2083 if (num_possible_cpus() == 0) {
2084 printf("No possible cpus, use 'dp #' to dump individual cpus\n");
2085 return;
2086 }
2087
2088 for_each_possible_cpu(cpu)
2089 dump_one_paca(cpu);
2090}
2091
2092static void dump_pacas(void)
2093{
2094 unsigned long num;
2095 int c;
2096
2097 c = inchar();
2098 if (c == 'a') {
2099 dump_all_pacas();
2100 return;
2101 }
2102
2103 termch = c; /* Put c back, it wasn't 'a' */
2104
2105 if (scanhex(&num))
2106 dump_one_paca(num);
2107 else
2108 dump_one_paca(xmon_owner);
2109}
2110#endif
2111
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
2113 || ('a' <= (c) && (c) <= 'f') \
2114 || ('A' <= (c) && (c) <= 'F'))
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002115static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116dump(void)
2117{
2118 int c;
2119
2120 c = inchar();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002121
2122#ifdef CONFIG_PPC64
2123 if (c == 'p') {
2124 dump_pacas();
2125 return;
2126 }
2127#endif
2128
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129 if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
2130 termch = c;
2131 scanhex((void *)&adrs);
2132 if (termch != '\n')
2133 termch = 0;
2134 if (c == 'i') {
2135 scanhex(&nidump);
2136 if (nidump == 0)
2137 nidump = 16;
2138 else if (nidump > MAX_DUMP)
2139 nidump = MAX_DUMP;
2140 adrs += ppc_inst_dump(adrs, nidump, 1);
2141 last_cmd = "di\n";
Vinay Sridharf312deb2009-05-14 23:13:07 +00002142 } else if (c == 'l') {
2143 dump_log_buf();
Olaf Hering7e5b5932006-03-08 20:40:28 +01002144 } else if (c == 'r') {
2145 scanhex(&ndump);
2146 if (ndump == 0)
2147 ndump = 64;
2148 xmon_rawdump(adrs, ndump);
2149 adrs += ndump;
2150 last_cmd = "dr\n";
Linus Torvalds1da177e2005-04-16 15:20:36 -07002151 } else {
2152 scanhex(&ndump);
2153 if (ndump == 0)
2154 ndump = 64;
2155 else if (ndump > MAX_DUMP)
2156 ndump = MAX_DUMP;
2157 prdump(adrs, ndump);
2158 adrs += ndump;
2159 last_cmd = "d\n";
2160 }
2161}
2162
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002163static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164prdump(unsigned long adrs, long ndump)
2165{
2166 long n, m, c, r, nr;
2167 unsigned char temp[16];
2168
2169 for (n = ndump; n > 0;) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002170 printf(REG, adrs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002171 putchar(' ');
2172 r = n < 16? n: 16;
2173 nr = mread(adrs, temp, r);
2174 adrs += nr;
2175 for (m = 0; m < r; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002176 if ((m & (sizeof(long) - 1)) == 0 && m > 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002177 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178 if (m < nr)
2179 printf("%.2x", temp[m]);
2180 else
2181 printf("%s", fault_chars[fault_type]);
2182 }
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002183 for (; m < 16; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002184 if ((m & (sizeof(long) - 1)) == 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002185 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186 printf(" ");
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002187 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188 printf(" |");
2189 for (m = 0; m < r; ++m) {
2190 if (m < nr) {
2191 c = temp[m];
2192 putchar(' ' <= c && c <= '~'? c: '.');
2193 } else
2194 putchar(' ');
2195 }
2196 n -= r;
2197 for (; m < 16; ++m)
2198 putchar(' ');
2199 printf("|\n");
2200 if (nr < r)
2201 break;
2202 }
2203}
2204
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002205typedef int (*instruction_dump_func)(unsigned long inst, unsigned long addr);
2206
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002207static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002208generic_inst_dump(unsigned long adr, long count, int praddr,
2209 instruction_dump_func dump_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210{
2211 int nr, dotted;
2212 unsigned long first_adr;
2213 unsigned long inst, last_inst = 0;
2214 unsigned char val[4];
2215
2216 dotted = 0;
2217 for (first_adr = adr; count > 0; --count, adr += 4) {
2218 nr = mread(adr, val, 4);
2219 if (nr == 0) {
2220 if (praddr) {
2221 const char *x = fault_chars[fault_type];
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002222 printf(REG" %s%s%s%s\n", adr, x, x, x, x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223 }
2224 break;
2225 }
2226 inst = GETWORD(val);
2227 if (adr > first_adr && inst == last_inst) {
2228 if (!dotted) {
2229 printf(" ...\n");
2230 dotted = 1;
2231 }
2232 continue;
2233 }
2234 dotted = 0;
2235 last_inst = inst;
2236 if (praddr)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002237 printf(REG" %.8x", adr, inst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238 printf("\t");
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002239 dump_func(inst, adr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240 printf("\n");
2241 }
2242 return adr - first_adr;
2243}
2244
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002245static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002246ppc_inst_dump(unsigned long adr, long count, int praddr)
2247{
2248 return generic_inst_dump(adr, count, praddr, print_insn_powerpc);
2249}
2250
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251void
2252print_address(unsigned long addr)
2253{
2254 xmon_print_symbol(addr, "\t# ", "");
2255}
2256
Vinay Sridharf312deb2009-05-14 23:13:07 +00002257void
2258dump_log_buf(void)
2259{
Michael Ellermanca5dd392012-08-23 22:09:12 +00002260 struct kmsg_dumper dumper = { .active = 1 };
2261 unsigned char buf[128];
2262 size_t len;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002263
Michael Ellermane3bc8042012-08-23 22:09:13 +00002264 if (setjmp(bus_error_jmp) != 0) {
Michael Ellermanca5dd392012-08-23 22:09:12 +00002265 printf("Error dumping printk buffer!\n");
Michael Ellermane3bc8042012-08-23 22:09:13 +00002266 return;
2267 }
Vinay Sridharf312deb2009-05-14 23:13:07 +00002268
Michael Ellermane3bc8042012-08-23 22:09:13 +00002269 catch_memory_errors = 1;
2270 sync();
Vinay Sridharf312deb2009-05-14 23:13:07 +00002271
Michael Ellermanca5dd392012-08-23 22:09:12 +00002272 kmsg_dump_rewind_nolock(&dumper);
2273 while (kmsg_dump_get_line_nolock(&dumper, false, buf, sizeof(buf), &len)) {
2274 buf[len] = '\0';
2275 printf("%s", buf);
2276 }
Vinay Sridharf312deb2009-05-14 23:13:07 +00002277
Michael Ellermane3bc8042012-08-23 22:09:13 +00002278 sync();
2279 /* wait a little while to see if we get a machine check */
2280 __delay(200);
2281 catch_memory_errors = 0;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002282}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283
2284/*
2285 * Memory operations - move, set, print differences
2286 */
2287static unsigned long mdest; /* destination address */
2288static unsigned long msrc; /* source address */
2289static unsigned long mval; /* byte value to set memory to */
2290static unsigned long mcount; /* # bytes to affect */
2291static unsigned long mdiffs; /* max # differences to print */
2292
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002293static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294memops(int cmd)
2295{
2296 scanhex((void *)&mdest);
2297 if( termch != '\n' )
2298 termch = 0;
2299 scanhex((void *)(cmd == 's'? &mval: &msrc));
2300 if( termch != '\n' )
2301 termch = 0;
2302 scanhex((void *)&mcount);
2303 switch( cmd ){
2304 case 'm':
2305 memmove((void *)mdest, (void *)msrc, mcount);
2306 break;
2307 case 's':
2308 memset((void *)mdest, mval, mcount);
2309 break;
2310 case 'd':
2311 if( termch != '\n' )
2312 termch = 0;
2313 scanhex((void *)&mdiffs);
2314 memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
2315 break;
2316 }
2317}
2318
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002319static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
2321{
2322 unsigned n, prt;
2323
2324 prt = 0;
2325 for( n = nb; n > 0; --n )
2326 if( *p1++ != *p2++ )
2327 if( ++prt <= maxpr )
2328 printf("%.16x %.2x # %.16x %.2x\n", p1 - 1,
2329 p1[-1], p2 - 1, p2[-1]);
2330 if( prt > maxpr )
2331 printf("Total of %d differences\n", prt);
2332}
2333
2334static unsigned mend;
2335static unsigned mask;
2336
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002337static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338memlocate(void)
2339{
2340 unsigned a, n;
2341 unsigned char val[4];
2342
2343 last_cmd = "ml";
2344 scanhex((void *)&mdest);
2345 if (termch != '\n') {
2346 termch = 0;
2347 scanhex((void *)&mend);
2348 if (termch != '\n') {
2349 termch = 0;
2350 scanhex((void *)&mval);
2351 mask = ~0;
2352 if (termch != '\n') termch = 0;
2353 scanhex((void *)&mask);
2354 }
2355 }
2356 n = 0;
2357 for (a = mdest; a < mend; a += 4) {
2358 if (mread(a, val, 4) == 4
2359 && ((GETWORD(val) ^ mval) & mask) == 0) {
2360 printf("%.16x: %.16x\n", a, GETWORD(val));
2361 if (++n >= 10)
2362 break;
2363 }
2364 }
2365}
2366
2367static unsigned long mskip = 0x1000;
2368static unsigned long mlim = 0xffffffff;
2369
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002370static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371memzcan(void)
2372{
2373 unsigned char v;
2374 unsigned a;
2375 int ok, ook;
2376
2377 scanhex(&mdest);
2378 if (termch != '\n') termch = 0;
2379 scanhex(&mskip);
2380 if (termch != '\n') termch = 0;
2381 scanhex(&mlim);
2382 ook = 0;
2383 for (a = mdest; a < mlim; a += mskip) {
2384 ok = mread(a, &v, 1);
2385 if (ok && !ook) {
2386 printf("%.8x .. ", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387 } else if (!ok && ook)
2388 printf("%.8x\n", a - mskip);
2389 ook = ok;
2390 if (a + mskip < a)
2391 break;
2392 }
2393 if (ook)
2394 printf("%.8x\n", a - mskip);
2395}
2396
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002397static void proccall(void)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002398{
2399 unsigned long args[8];
2400 unsigned long ret;
2401 int i;
2402 typedef unsigned long (*callfunc_t)(unsigned long, unsigned long,
2403 unsigned long, unsigned long, unsigned long,
2404 unsigned long, unsigned long, unsigned long);
2405 callfunc_t func;
2406
2407 if (!scanhex(&adrs))
2408 return;
2409 if (termch != '\n')
2410 termch = 0;
2411 for (i = 0; i < 8; ++i)
2412 args[i] = 0;
2413 for (i = 0; i < 8; ++i) {
2414 if (!scanhex(&args[i]) || termch == '\n')
2415 break;
2416 termch = 0;
2417 }
2418 func = (callfunc_t) adrs;
2419 ret = 0;
2420 if (setjmp(bus_error_jmp) == 0) {
2421 catch_memory_errors = 1;
2422 sync();
2423 ret = func(args[0], args[1], args[2], args[3],
2424 args[4], args[5], args[6], args[7]);
2425 sync();
2426 printf("return value is %x\n", ret);
2427 } else {
2428 printf("*** %x exception occurred\n", fault_except);
2429 }
2430 catch_memory_errors = 0;
2431}
2432
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433/* Input scanning routines */
2434int
2435skipbl(void)
2436{
2437 int c;
2438
2439 if( termch != 0 ){
2440 c = termch;
2441 termch = 0;
2442 } else
2443 c = inchar();
2444 while( c == ' ' || c == '\t' )
2445 c = inchar();
2446 return c;
2447}
2448
2449#define N_PTREGS 44
2450static char *regnames[N_PTREGS] = {
2451 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
2452 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
2453 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
2454 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002455 "pc", "msr", "or3", "ctr", "lr", "xer", "ccr",
2456#ifdef CONFIG_PPC64
2457 "softe",
2458#else
2459 "mq",
2460#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461 "trap", "dar", "dsisr", "res"
2462};
2463
2464int
2465scanhex(unsigned long *vp)
2466{
2467 int c, d;
2468 unsigned long v;
2469
2470 c = skipbl();
2471 if (c == '%') {
2472 /* parse register name */
2473 char regname[8];
2474 int i;
2475
2476 for (i = 0; i < sizeof(regname) - 1; ++i) {
2477 c = inchar();
2478 if (!isalnum(c)) {
2479 termch = c;
2480 break;
2481 }
2482 regname[i] = c;
2483 }
2484 regname[i] = 0;
2485 for (i = 0; i < N_PTREGS; ++i) {
2486 if (strcmp(regnames[i], regname) == 0) {
2487 if (xmon_regs == NULL) {
2488 printf("regs not available\n");
2489 return 0;
2490 }
2491 *vp = ((unsigned long *)xmon_regs)[i];
2492 return 1;
2493 }
2494 }
2495 printf("invalid register name '%%%s'\n", regname);
2496 return 0;
2497 }
2498
2499 /* skip leading "0x" if any */
2500
2501 if (c == '0') {
2502 c = inchar();
2503 if (c == 'x') {
2504 c = inchar();
2505 } else {
2506 d = hexdigit(c);
2507 if (d == EOF) {
2508 termch = c;
2509 *vp = 0;
2510 return 1;
2511 }
2512 }
2513 } else if (c == '$') {
2514 int i;
2515 for (i=0; i<63; i++) {
2516 c = inchar();
2517 if (isspace(c)) {
2518 termch = c;
2519 break;
2520 }
2521 tmpstr[i] = c;
2522 }
2523 tmpstr[i++] = 0;
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07002524 *vp = 0;
2525 if (setjmp(bus_error_jmp) == 0) {
2526 catch_memory_errors = 1;
2527 sync();
2528 *vp = kallsyms_lookup_name(tmpstr);
2529 sync();
2530 }
2531 catch_memory_errors = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002532 if (!(*vp)) {
2533 printf("unknown symbol '%s'\n", tmpstr);
2534 return 0;
2535 }
2536 return 1;
2537 }
2538
2539 d = hexdigit(c);
2540 if (d == EOF) {
2541 termch = c;
2542 return 0;
2543 }
2544 v = 0;
2545 do {
2546 v = (v << 4) + d;
2547 c = inchar();
2548 d = hexdigit(c);
2549 } while (d != EOF);
2550 termch = c;
2551 *vp = v;
2552 return 1;
2553}
2554
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002555static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556scannl(void)
2557{
2558 int c;
2559
2560 c = termch;
2561 termch = 0;
2562 while( c != '\n' )
2563 c = inchar();
2564}
2565
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002566static int hexdigit(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002567{
2568 if( '0' <= c && c <= '9' )
2569 return c - '0';
2570 if( 'A' <= c && c <= 'F' )
2571 return c - ('A' - 10);
2572 if( 'a' <= c && c <= 'f' )
2573 return c - ('a' - 10);
2574 return EOF;
2575}
2576
2577void
2578getstring(char *s, int size)
2579{
2580 int c;
2581
2582 c = skipbl();
2583 do {
2584 if( size > 1 ){
2585 *s++ = c;
2586 --size;
2587 }
2588 c = inchar();
2589 } while( c != ' ' && c != '\t' && c != '\n' );
2590 termch = c;
2591 *s = 0;
2592}
2593
2594static char line[256];
2595static char *lineptr;
2596
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002597static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598flush_input(void)
2599{
2600 lineptr = NULL;
2601}
2602
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002603static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604inchar(void)
2605{
2606 if (lineptr == NULL || *lineptr == 0) {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002607 if (xmon_gets(line, sizeof(line)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608 lineptr = NULL;
2609 return EOF;
2610 }
2611 lineptr = line;
2612 }
2613 return *lineptr++;
2614}
2615
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002616static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617take_input(char *str)
2618{
2619 lineptr = str;
2620}
2621
2622
2623static void
2624symbol_lookup(void)
2625{
2626 int type = inchar();
2627 unsigned long addr;
2628 static char tmp[64];
2629
2630 switch (type) {
2631 case 'a':
2632 if (scanhex(&addr))
2633 xmon_print_symbol(addr, ": ", "\n");
2634 termch = 0;
2635 break;
2636 case 's':
2637 getstring(tmp, 64);
2638 if (setjmp(bus_error_jmp) == 0) {
2639 catch_memory_errors = 1;
2640 sync();
2641 addr = kallsyms_lookup_name(tmp);
2642 if (addr)
2643 printf("%s: %lx\n", tmp, addr);
2644 else
2645 printf("Symbol '%s' not found.\n", tmp);
2646 sync();
2647 }
2648 catch_memory_errors = 0;
2649 termch = 0;
2650 break;
2651 }
2652}
2653
2654
2655/* Print an address in numeric and symbolic form (if possible) */
2656static void xmon_print_symbol(unsigned long address, const char *mid,
2657 const char *after)
2658{
2659 char *modname;
2660 const char *name = NULL;
2661 unsigned long offset, size;
2662
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002663 printf(REG, address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664 if (setjmp(bus_error_jmp) == 0) {
2665 catch_memory_errors = 1;
2666 sync();
2667 name = kallsyms_lookup(address, &size, &offset, &modname,
2668 tmpstr);
2669 sync();
2670 /* wait a little while to see if we get a machine check */
2671 __delay(200);
2672 }
2673
2674 catch_memory_errors = 0;
2675
2676 if (name) {
2677 printf("%s%s+%#lx/%#lx", mid, name, offset, size);
2678 if (modname)
2679 printf(" [%s]", modname);
2680 }
2681 printf("%s", after);
2682}
2683
Benjamin Herrenschmidt2d27cfd2009-07-23 23:15:59 +00002684#ifdef CONFIG_PPC_BOOK3S_64
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685static void dump_slb(void)
2686{
2687 int i;
will schmidtb3b95952007-12-07 08:22:23 +11002688 unsigned long esid,vsid,valid;
2689 unsigned long llp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690
2691 printf("SLB contents of cpu %x\n", smp_processor_id());
2692
Michael Neuling584f8b72007-12-06 17:24:48 +11002693 for (i = 0; i < mmu_slb_size; i++) {
will schmidtb3b95952007-12-07 08:22:23 +11002694 asm volatile("slbmfee %0,%1" : "=r" (esid) : "r" (i));
2695 asm volatile("slbmfev %0,%1" : "=r" (vsid) : "r" (i));
2696 valid = (esid & SLB_ESID_V);
2697 if (valid | esid | vsid) {
2698 printf("%02d %016lx %016lx", i, esid, vsid);
2699 if (valid) {
2700 llp = vsid & SLB_VSID_LLP;
2701 if (vsid & SLB_VSID_B_1T) {
2702 printf(" 1T ESID=%9lx VSID=%13lx LLP:%3lx \n",
2703 GET_ESID_1T(esid),
2704 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT_1T,
2705 llp);
2706 } else {
2707 printf(" 256M ESID=%9lx VSID=%13lx LLP:%3lx \n",
2708 GET_ESID(esid),
2709 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT,
2710 llp);
2711 }
2712 } else
2713 printf("\n");
2714 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715 }
2716}
2717
2718static void dump_stab(void)
2719{
2720 int i;
Benjamin Herrenschmidt7ac21cd2012-03-02 10:10:09 +11002721 unsigned long *tmp = (unsigned long *)local_paca->stab_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722
2723 printf("Segment table contents of cpu %x\n", smp_processor_id());
2724
2725 for (i = 0; i < PAGE_SIZE/16; i++) {
2726 unsigned long a, b;
2727
2728 a = *tmp++;
2729 b = *tmp++;
2730
2731 if (a || b) {
2732 printf("%03d %016lx ", i, a);
2733 printf("%016lx\n", b);
2734 }
2735 }
2736}
2737
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002738void dump_segments(void)
2739{
Matt Evans44ae3ab2011-04-06 19:48:50 +00002740 if (mmu_has_feature(MMU_FTR_SLB))
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002741 dump_slb();
2742 else
2743 dump_stab();
2744}
2745#endif
2746
2747#ifdef CONFIG_PPC_STD_MMU_32
2748void dump_segments(void)
2749{
2750 int i;
2751
2752 printf("sr0-15 =");
2753 for (i = 0; i < 16; ++i)
2754 printf(" %x", mfsrin(i));
2755 printf("\n");
2756}
2757#endif
2758
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11002759#ifdef CONFIG_44x
2760static void dump_tlb_44x(void)
2761{
2762 int i;
2763
2764 for (i = 0; i < PPC44x_TLB_SIZE; i++) {
2765 unsigned long w0,w1,w2;
2766 asm volatile("tlbre %0,%1,0" : "=r" (w0) : "r" (i));
2767 asm volatile("tlbre %0,%1,1" : "=r" (w1) : "r" (i));
2768 asm volatile("tlbre %0,%1,2" : "=r" (w2) : "r" (i));
2769 printf("[%02x] %08x %08x %08x ", i, w0, w1, w2);
2770 if (w0 & PPC44x_TLB_VALID) {
2771 printf("V %08x -> %01x%08x %c%c%c%c%c",
2772 w0 & PPC44x_TLB_EPN_MASK,
2773 w1 & PPC44x_TLB_ERPN_MASK,
2774 w1 & PPC44x_TLB_RPN_MASK,
2775 (w2 & PPC44x_TLB_W) ? 'W' : 'w',
2776 (w2 & PPC44x_TLB_I) ? 'I' : 'i',
2777 (w2 & PPC44x_TLB_M) ? 'M' : 'm',
2778 (w2 & PPC44x_TLB_G) ? 'G' : 'g',
2779 (w2 & PPC44x_TLB_E) ? 'E' : 'e');
2780 }
2781 printf("\n");
2782 }
2783}
2784#endif /* CONFIG_44x */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002785
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +10002786#ifdef CONFIG_PPC_BOOK3E
2787static void dump_tlb_book3e(void)
2788{
2789 u32 mmucfg, pidmask, lpidmask;
2790 u64 ramask;
2791 int i, tlb, ntlbs, pidsz, lpidsz, rasz, lrat = 0;
2792 int mmu_version;
2793 static const char *pgsz_names[] = {
2794 " 1K",
2795 " 2K",
2796 " 4K",
2797 " 8K",
2798 " 16K",
2799 " 32K",
2800 " 64K",
2801 "128K",
2802 "256K",
2803 "512K",
2804 " 1M",
2805 " 2M",
2806 " 4M",
2807 " 8M",
2808 " 16M",
2809 " 32M",
2810 " 64M",
2811 "128M",
2812 "256M",
2813 "512M",
2814 " 1G",
2815 " 2G",
2816 " 4G",
2817 " 8G",
2818 " 16G",
2819 " 32G",
2820 " 64G",
2821 "128G",
2822 "256G",
2823 "512G",
2824 " 1T",
2825 " 2T",
2826 };
2827
2828 /* Gather some infos about the MMU */
2829 mmucfg = mfspr(SPRN_MMUCFG);
2830 mmu_version = (mmucfg & 3) + 1;
2831 ntlbs = ((mmucfg >> 2) & 3) + 1;
2832 pidsz = ((mmucfg >> 6) & 0x1f) + 1;
2833 lpidsz = (mmucfg >> 24) & 0xf;
2834 rasz = (mmucfg >> 16) & 0x7f;
2835 if ((mmu_version > 1) && (mmucfg & 0x10000))
2836 lrat = 1;
2837 printf("Book3E MMU MAV=%d.0,%d TLBs,%d-bit PID,%d-bit LPID,%d-bit RA\n",
2838 mmu_version, ntlbs, pidsz, lpidsz, rasz);
2839 pidmask = (1ul << pidsz) - 1;
2840 lpidmask = (1ul << lpidsz) - 1;
2841 ramask = (1ull << rasz) - 1;
2842
2843 for (tlb = 0; tlb < ntlbs; tlb++) {
2844 u32 tlbcfg;
2845 int nent, assoc, new_cc = 1;
2846 printf("TLB %d:\n------\n", tlb);
2847 switch(tlb) {
2848 case 0:
2849 tlbcfg = mfspr(SPRN_TLB0CFG);
2850 break;
2851 case 1:
2852 tlbcfg = mfspr(SPRN_TLB1CFG);
2853 break;
2854 case 2:
2855 tlbcfg = mfspr(SPRN_TLB2CFG);
2856 break;
2857 case 3:
2858 tlbcfg = mfspr(SPRN_TLB3CFG);
2859 break;
2860 default:
2861 printf("Unsupported TLB number !\n");
2862 continue;
2863 }
2864 nent = tlbcfg & 0xfff;
2865 assoc = (tlbcfg >> 24) & 0xff;
2866 for (i = 0; i < nent; i++) {
2867 u32 mas0 = MAS0_TLBSEL(tlb);
2868 u32 mas1 = MAS1_TSIZE(BOOK3E_PAGESZ_4K);
2869 u64 mas2 = 0;
2870 u64 mas7_mas3;
2871 int esel = i, cc = i;
2872
2873 if (assoc != 0) {
2874 cc = i / assoc;
2875 esel = i % assoc;
2876 mas2 = cc * 0x1000;
2877 }
2878
2879 mas0 |= MAS0_ESEL(esel);
2880 mtspr(SPRN_MAS0, mas0);
2881 mtspr(SPRN_MAS1, mas1);
2882 mtspr(SPRN_MAS2, mas2);
2883 asm volatile("tlbre 0,0,0" : : : "memory");
2884 mas1 = mfspr(SPRN_MAS1);
2885 mas2 = mfspr(SPRN_MAS2);
2886 mas7_mas3 = mfspr(SPRN_MAS7_MAS3);
2887 if (assoc && (i % assoc) == 0)
2888 new_cc = 1;
2889 if (!(mas1 & MAS1_VALID))
2890 continue;
2891 if (assoc == 0)
2892 printf("%04x- ", i);
2893 else if (new_cc)
2894 printf("%04x-%c", cc, 'A' + esel);
2895 else
2896 printf(" |%c", 'A' + esel);
2897 new_cc = 0;
2898 printf(" %016llx %04x %s %c%c AS%c",
2899 mas2 & ~0x3ffull,
2900 (mas1 >> 16) & 0x3fff,
2901 pgsz_names[(mas1 >> 7) & 0x1f],
2902 mas1 & MAS1_IND ? 'I' : ' ',
2903 mas1 & MAS1_IPROT ? 'P' : ' ',
2904 mas1 & MAS1_TS ? '1' : '0');
2905 printf(" %c%c%c%c%c%c%c",
2906 mas2 & MAS2_X0 ? 'a' : ' ',
2907 mas2 & MAS2_X1 ? 'v' : ' ',
2908 mas2 & MAS2_W ? 'w' : ' ',
2909 mas2 & MAS2_I ? 'i' : ' ',
2910 mas2 & MAS2_M ? 'm' : ' ',
2911 mas2 & MAS2_G ? 'g' : ' ',
2912 mas2 & MAS2_E ? 'e' : ' ');
2913 printf(" %016llx", mas7_mas3 & ramask & ~0x7ffull);
2914 if (mas1 & MAS1_IND)
2915 printf(" %s\n",
2916 pgsz_names[(mas7_mas3 >> 1) & 0x1f]);
2917 else
2918 printf(" U%c%c%c S%c%c%c\n",
2919 mas7_mas3 & MAS3_UX ? 'x' : ' ',
2920 mas7_mas3 & MAS3_UW ? 'w' : ' ',
2921 mas7_mas3 & MAS3_UR ? 'r' : ' ',
2922 mas7_mas3 & MAS3_SX ? 'x' : ' ',
2923 mas7_mas3 & MAS3_SW ? 'w' : ' ',
2924 mas7_mas3 & MAS3_SR ? 'r' : ' ');
2925 }
2926 }
2927}
2928#endif /* CONFIG_PPC_BOOK3E */
2929
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002930static void xmon_init(int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002931{
Olaf Heringb13cfd172005-08-04 19:26:42 +02002932 if (enable) {
2933 __debugger = xmon;
2934 __debugger_ipi = xmon_ipi;
2935 __debugger_bpt = xmon_bpt;
2936 __debugger_sstep = xmon_sstep;
2937 __debugger_iabr_match = xmon_iabr_match;
Michael Neuling9422de32012-12-20 14:06:44 +00002938 __debugger_break_match = xmon_break_match;
Olaf Heringb13cfd172005-08-04 19:26:42 +02002939 __debugger_fault_handler = xmon_fault_handler;
2940 } else {
2941 __debugger = NULL;
2942 __debugger_ipi = NULL;
2943 __debugger_bpt = NULL;
2944 __debugger_sstep = NULL;
2945 __debugger_iabr_match = NULL;
Michael Neuling9422de32012-12-20 14:06:44 +00002946 __debugger_break_match = NULL;
Olaf Heringb13cfd172005-08-04 19:26:42 +02002947 __debugger_fault_handler = NULL;
2948 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002949}
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002950
2951#ifdef CONFIG_MAGIC_SYSRQ
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07002952static void sysrq_handle_xmon(int key)
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002953{
2954 /* ensure xmon is enabled */
2955 xmon_init(1);
David Howells7d12e782006-10-05 14:55:46 +01002956 debugger(get_irq_regs());
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002957}
2958
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07002959static struct sysrq_key_op sysrq_xmon_op = {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002960 .handler = sysrq_handle_xmon,
zhangwei(Jovi)90a102e2013-04-30 15:28:54 -07002961 .help_msg = "xmon(x)",
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002962 .action_msg = "Entering xmon",
2963};
2964
2965static int __init setup_xmon_sysrq(void)
2966{
2967 register_sysrq_key('x', &sysrq_xmon_op);
2968 return 0;
2969}
2970__initcall(setup_xmon_sysrq);
2971#endif /* CONFIG_MAGIC_SYSRQ */
Michael Ellerman476792832006-10-03 14:12:08 +10002972
Olaf Heringf5e6a282007-06-24 16:57:08 +10002973static int __initdata xmon_early, xmon_off;
Michael Ellerman476792832006-10-03 14:12:08 +10002974
2975static int __init early_parse_xmon(char *p)
2976{
2977 if (!p || strncmp(p, "early", 5) == 0) {
2978 /* just "xmon" is equivalent to "xmon=early" */
2979 xmon_init(1);
2980 xmon_early = 1;
2981 } else if (strncmp(p, "on", 2) == 0)
2982 xmon_init(1);
2983 else if (strncmp(p, "off", 3) == 0)
2984 xmon_off = 1;
2985 else if (strncmp(p, "nobt", 4) == 0)
2986 xmon_no_auto_backtrace = 1;
2987 else
2988 return 1;
2989
2990 return 0;
2991}
2992early_param("xmon", early_parse_xmon);
2993
2994void __init xmon_setup(void)
2995{
2996#ifdef CONFIG_XMON_DEFAULT
2997 if (!xmon_off)
2998 xmon_init(1);
2999#endif
3000 if (xmon_early)
3001 debugger(NULL);
3002}
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003003
Arnd Bergmanne0555952006-11-27 19:18:55 +01003004#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003005
3006struct spu_info {
3007 struct spu *spu;
3008 u64 saved_mfc_sr1_RW;
3009 u32 saved_spu_runcntl_RW;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003010 unsigned long dump_addr;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003011 u8 stopped_ok;
3012};
3013
3014#define XMON_NUM_SPUS 16 /* Enough for current hardware */
3015
3016static struct spu_info spu_info[XMON_NUM_SPUS];
3017
3018void xmon_register_spus(struct list_head *list)
3019{
3020 struct spu *spu;
3021
3022 list_for_each_entry(spu, list, full_list) {
3023 if (spu->number >= XMON_NUM_SPUS) {
3024 WARN_ON(1);
3025 continue;
3026 }
3027
3028 spu_info[spu->number].spu = spu;
3029 spu_info[spu->number].stopped_ok = 0;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003030 spu_info[spu->number].dump_addr = (unsigned long)
3031 spu_info[spu->number].spu->local_store;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003032 }
3033}
3034
3035static void stop_spus(void)
3036{
3037 struct spu *spu;
3038 int i;
3039 u64 tmp;
3040
3041 for (i = 0; i < XMON_NUM_SPUS; i++) {
3042 if (!spu_info[i].spu)
3043 continue;
3044
3045 if (setjmp(bus_error_jmp) == 0) {
3046 catch_memory_errors = 1;
3047 sync();
3048
3049 spu = spu_info[i].spu;
3050
3051 spu_info[i].saved_spu_runcntl_RW =
3052 in_be32(&spu->problem->spu_runcntl_RW);
3053
3054 tmp = spu_mfc_sr1_get(spu);
3055 spu_info[i].saved_mfc_sr1_RW = tmp;
3056
3057 tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
3058 spu_mfc_sr1_set(spu, tmp);
3059
3060 sync();
3061 __delay(200);
3062
3063 spu_info[i].stopped_ok = 1;
Michael Ellerman2a144422006-11-23 00:46:40 +01003064
3065 printf("Stopped spu %.2d (was %s)\n", i,
3066 spu_info[i].saved_spu_runcntl_RW ?
3067 "running" : "stopped");
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003068 } else {
3069 catch_memory_errors = 0;
3070 printf("*** Error stopping spu %.2d\n", i);
3071 }
3072 catch_memory_errors = 0;
3073 }
3074}
3075
3076static void restart_spus(void)
3077{
3078 struct spu *spu;
3079 int i;
3080
3081 for (i = 0; i < XMON_NUM_SPUS; i++) {
3082 if (!spu_info[i].spu)
3083 continue;
3084
3085 if (!spu_info[i].stopped_ok) {
3086 printf("*** Error, spu %d was not successfully stopped"
3087 ", not restarting\n", i);
3088 continue;
3089 }
3090
3091 if (setjmp(bus_error_jmp) == 0) {
3092 catch_memory_errors = 1;
3093 sync();
3094
3095 spu = spu_info[i].spu;
3096 spu_mfc_sr1_set(spu, spu_info[i].saved_mfc_sr1_RW);
3097 out_be32(&spu->problem->spu_runcntl_RW,
3098 spu_info[i].saved_spu_runcntl_RW);
3099
3100 sync();
3101 __delay(200);
3102
3103 printf("Restarted spu %.2d\n", i);
3104 } else {
3105 catch_memory_errors = 0;
3106 printf("*** Error restarting spu %.2d\n", i);
3107 }
3108 catch_memory_errors = 0;
3109 }
3110}
3111
Michael Ellermana8984972006-10-24 18:31:28 +02003112#define DUMP_WIDTH 23
Michael Ellerman437a0702006-11-23 00:46:39 +01003113#define DUMP_VALUE(format, field, value) \
Michael Ellermana8984972006-10-24 18:31:28 +02003114do { \
3115 if (setjmp(bus_error_jmp) == 0) { \
3116 catch_memory_errors = 1; \
3117 sync(); \
3118 printf(" %-*s = "format"\n", DUMP_WIDTH, \
Michael Ellerman437a0702006-11-23 00:46:39 +01003119 #field, value); \
Michael Ellermana8984972006-10-24 18:31:28 +02003120 sync(); \
3121 __delay(200); \
3122 } else { \
3123 catch_memory_errors = 0; \
3124 printf(" %-*s = *** Error reading field.\n", \
3125 DUMP_WIDTH, #field); \
3126 } \
3127 catch_memory_errors = 0; \
3128} while (0)
3129
Michael Ellerman437a0702006-11-23 00:46:39 +01003130#define DUMP_FIELD(obj, format, field) \
3131 DUMP_VALUE(format, field, obj->field)
3132
Michael Ellermana8984972006-10-24 18:31:28 +02003133static void dump_spu_fields(struct spu *spu)
3134{
3135 printf("Dumping spu fields at address %p:\n", spu);
3136
3137 DUMP_FIELD(spu, "0x%x", number);
3138 DUMP_FIELD(spu, "%s", name);
Michael Ellermana8984972006-10-24 18:31:28 +02003139 DUMP_FIELD(spu, "0x%lx", local_store_phys);
3140 DUMP_FIELD(spu, "0x%p", local_store);
3141 DUMP_FIELD(spu, "0x%lx", ls_size);
3142 DUMP_FIELD(spu, "0x%x", node);
3143 DUMP_FIELD(spu, "0x%lx", flags);
Michael Ellermana8984972006-10-24 18:31:28 +02003144 DUMP_FIELD(spu, "%d", class_0_pending);
Luke Browningf3d69e02008-04-27 18:41:55 +00003145 DUMP_FIELD(spu, "0x%lx", class_0_dar);
Luke Browningf3d69e02008-04-27 18:41:55 +00003146 DUMP_FIELD(spu, "0x%lx", class_1_dar);
3147 DUMP_FIELD(spu, "0x%lx", class_1_dsisr);
Michael Ellermana8984972006-10-24 18:31:28 +02003148 DUMP_FIELD(spu, "0x%lx", irqs[0]);
3149 DUMP_FIELD(spu, "0x%lx", irqs[1]);
3150 DUMP_FIELD(spu, "0x%lx", irqs[2]);
3151 DUMP_FIELD(spu, "0x%x", slb_replace);
3152 DUMP_FIELD(spu, "%d", pid);
Michael Ellermana8984972006-10-24 18:31:28 +02003153 DUMP_FIELD(spu, "0x%p", mm);
3154 DUMP_FIELD(spu, "0x%p", ctx);
3155 DUMP_FIELD(spu, "0x%p", rq);
3156 DUMP_FIELD(spu, "0x%p", timestamp);
3157 DUMP_FIELD(spu, "0x%lx", problem_phys);
3158 DUMP_FIELD(spu, "0x%p", problem);
Michael Ellerman437a0702006-11-23 00:46:39 +01003159 DUMP_VALUE("0x%x", problem->spu_runcntl_RW,
3160 in_be32(&spu->problem->spu_runcntl_RW));
3161 DUMP_VALUE("0x%x", problem->spu_status_R,
3162 in_be32(&spu->problem->spu_status_R));
3163 DUMP_VALUE("0x%x", problem->spu_npc_RW,
3164 in_be32(&spu->problem->spu_npc_RW));
Michael Ellermana8984972006-10-24 18:31:28 +02003165 DUMP_FIELD(spu, "0x%p", priv2);
Michael Ellermana9852392006-11-23 00:46:50 +01003166 DUMP_FIELD(spu, "0x%p", pdata);
Michael Ellermana8984972006-10-24 18:31:28 +02003167}
3168
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003169int
3170spu_inst_dump(unsigned long adr, long count, int praddr)
3171{
3172 return generic_inst_dump(adr, count, praddr, print_insn_spu);
3173}
3174
3175static void dump_spu_ls(unsigned long num, int subcmd)
Michael Ellerman24a24c82006-11-23 00:46:41 +01003176{
3177 unsigned long offset, addr, ls_addr;
3178
3179 if (setjmp(bus_error_jmp) == 0) {
3180 catch_memory_errors = 1;
3181 sync();
3182 ls_addr = (unsigned long)spu_info[num].spu->local_store;
3183 sync();
3184 __delay(200);
3185 } else {
3186 catch_memory_errors = 0;
3187 printf("*** Error: accessing spu info for spu %d\n", num);
3188 return;
3189 }
3190 catch_memory_errors = 0;
3191
3192 if (scanhex(&offset))
3193 addr = ls_addr + offset;
3194 else
3195 addr = spu_info[num].dump_addr;
3196
3197 if (addr >= ls_addr + LS_SIZE) {
3198 printf("*** Error: address outside of local store\n");
3199 return;
3200 }
3201
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003202 switch (subcmd) {
3203 case 'i':
3204 addr += spu_inst_dump(addr, 16, 1);
3205 last_cmd = "sdi\n";
3206 break;
3207 default:
3208 prdump(addr, 64);
3209 addr += 64;
3210 last_cmd = "sd\n";
3211 break;
3212 }
Michael Ellerman24a24c82006-11-23 00:46:41 +01003213
3214 spu_info[num].dump_addr = addr;
3215}
3216
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003217static int do_spu_cmd(void)
3218{
Michael Ellerman24a24c82006-11-23 00:46:41 +01003219 static unsigned long num = 0;
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003220 int cmd, subcmd = 0;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003221
3222 cmd = inchar();
3223 switch (cmd) {
3224 case 's':
3225 stop_spus();
3226 break;
3227 case 'r':
3228 restart_spus();
3229 break;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003230 case 'd':
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003231 subcmd = inchar();
3232 if (isxdigit(subcmd) || subcmd == '\n')
3233 termch = subcmd;
3234 case 'f':
Michael Ellerman24a24c82006-11-23 00:46:41 +01003235 scanhex(&num);
3236 if (num >= XMON_NUM_SPUS || !spu_info[num].spu) {
Michael Ellermana8984972006-10-24 18:31:28 +02003237 printf("*** Error: invalid spu number\n");
Michael Ellerman24a24c82006-11-23 00:46:41 +01003238 return 0;
3239 }
3240
3241 switch (cmd) {
3242 case 'f':
3243 dump_spu_fields(spu_info[num].spu);
3244 break;
3245 default:
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003246 dump_spu_ls(num, subcmd);
Michael Ellerman24a24c82006-11-23 00:46:41 +01003247 break;
3248 }
3249
Michael Ellermana8984972006-10-24 18:31:28 +02003250 break;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003251 default:
3252 return -1;
3253 }
3254
3255 return 0;
3256}
Arnd Bergmanne0555952006-11-27 19:18:55 +01003257#else /* ! CONFIG_SPU_BASE */
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003258static int do_spu_cmd(void)
3259{
3260 return -1;
3261}
3262#endif