blob: 13f85defabed97a6cb7323c31b1272f50d6e29e5 [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
975 unsigned long cpu;
976 int timeout;
977 int count;
978
979 if (!scanhex(&cpu)) {
980 /* print cpus waiting or in xmon */
981 printf("cpus stopped:");
982 count = 0;
Anton Blanchardbc1d7702012-06-28 19:28:57 +0000983 for_each_possible_cpu(cpu) {
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000984 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 if (count == 0)
986 printf(" %x", cpu);
987 ++count;
988 } else {
989 if (count > 1)
990 printf("-%x", cpu - 1);
991 count = 0;
992 }
993 }
994 if (count > 1)
995 printf("-%x", NR_CPUS - 1);
996 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;
1259 case 0xc00: ret = "(System Call)"; break;
1260 case 0xd00: ret = "(Single Step)"; break;
1261 case 0xf00: ret = "(Performance Monitor)"; break;
1262 case 0xf20: ret = "(Altivec Unavailable)"; break;
1263 case 0x1300: ret = "(Instruction Breakpoint)"; break;
1264 default: ret = "";
1265 }
1266 return ret;
1267}
1268
1269static void get_function_bounds(unsigned long pc, unsigned long *startp,
1270 unsigned long *endp)
1271{
1272 unsigned long size, offset;
1273 const char *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274
1275 *startp = *endp = 0;
1276 if (pc == 0)
1277 return;
1278 if (setjmp(bus_error_jmp) == 0) {
1279 catch_memory_errors = 1;
1280 sync();
Alexey Dobriyanffb45122007-05-08 00:28:41 -07001281 name = kallsyms_lookup(pc, &size, &offset, NULL, tmpstr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 if (name != NULL) {
1283 *startp = pc - offset;
1284 *endp = pc - offset + size;
1285 }
1286 sync();
1287 }
1288 catch_memory_errors = 0;
1289}
1290
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001291#define LRSAVE_OFFSET (STACK_FRAME_LR_SAVE * sizeof(unsigned long))
1292#define MARKER_OFFSET (STACK_FRAME_MARKER * sizeof(unsigned long))
1293
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294static void xmon_show_stack(unsigned long sp, unsigned long lr,
1295 unsigned long pc)
1296{
Michael Ellerman0104cd62012-10-09 04:20:36 +00001297 int max_to_print = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 unsigned long ip;
1299 unsigned long newsp;
1300 unsigned long marker;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 struct pt_regs regs;
1302
Michael Ellerman0104cd62012-10-09 04:20:36 +00001303 while (max_to_print--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 if (sp < PAGE_OFFSET) {
1305 if (sp != 0)
1306 printf("SP (%lx) is in userspace\n", sp);
1307 break;
1308 }
1309
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001310 if (!mread(sp + LRSAVE_OFFSET, &ip, sizeof(unsigned long))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 || !mread(sp, &newsp, sizeof(unsigned long))) {
1312 printf("Couldn't read stack frame at %lx\n", sp);
1313 break;
1314 }
1315
1316 /*
1317 * For the first stack frame, try to work out if
1318 * LR and/or the saved LR value in the bottommost
1319 * stack frame are valid.
1320 */
1321 if ((pc | lr) != 0) {
1322 unsigned long fnstart, fnend;
1323 unsigned long nextip;
1324 int printip = 1;
1325
1326 get_function_bounds(pc, &fnstart, &fnend);
1327 nextip = 0;
1328 if (newsp > sp)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001329 mread(newsp + LRSAVE_OFFSET, &nextip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 sizeof(unsigned long));
1331 if (lr == ip) {
1332 if (lr < PAGE_OFFSET
1333 || (fnstart <= lr && lr < fnend))
1334 printip = 0;
1335 } else if (lr == nextip) {
1336 printip = 0;
1337 } else if (lr >= PAGE_OFFSET
1338 && !(fnstart <= lr && lr < fnend)) {
1339 printf("[link register ] ");
1340 xmon_print_symbol(lr, " ", "\n");
1341 }
1342 if (printip) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001343 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 xmon_print_symbol(ip, " ", " (unreliable)\n");
1345 }
1346 pc = lr = 0;
1347
1348 } else {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001349 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 xmon_print_symbol(ip, " ", "\n");
1351 }
1352
1353 /* Look for "regshere" marker to see if this is
1354 an exception frame. */
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001355 if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long))
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001356 && marker == STACK_FRAME_REGS_MARKER) {
Michael Ellermanc4de3802012-10-09 04:20:35 +00001357 if (mread(sp + STACK_FRAME_OVERHEAD, &regs, sizeof(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 != sizeof(regs)) {
1359 printf("Couldn't read registers at %lx\n",
Michael Ellermanc4de3802012-10-09 04:20:35 +00001360 sp + STACK_FRAME_OVERHEAD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 break;
1362 }
Michael Ellermane3bc8042012-08-23 22:09:13 +00001363 printf("--- Exception: %lx %s at ", regs.trap,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 getvecname(TRAP(&regs)));
1365 pc = regs.nip;
1366 lr = regs.link;
1367 xmon_print_symbol(pc, " ", "\n");
1368 }
1369
1370 if (newsp == 0)
1371 break;
1372
1373 sp = newsp;
Michael Ellerman0104cd62012-10-09 04:20:36 +00001374 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375}
1376
1377static void backtrace(struct pt_regs *excp)
1378{
1379 unsigned long sp;
1380
1381 if (scanhex(&sp))
1382 xmon_show_stack(sp, 0, 0);
1383 else
1384 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
1385 scannl();
1386}
1387
1388static void print_bug_trap(struct pt_regs *regs)
1389{
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001390#ifdef CONFIG_BUG
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001391 const struct bug_entry *bug;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 unsigned long addr;
1393
1394 if (regs->msr & MSR_PR)
1395 return; /* not in kernel */
1396 addr = regs->nip; /* address of trap instruction */
1397 if (addr < PAGE_OFFSET)
1398 return;
1399 bug = find_bug(regs->nip);
1400 if (bug == NULL)
1401 return;
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001402 if (is_warning_bug(bug))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403 return;
1404
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001405#ifdef CONFIG_DEBUG_BUGVERBOSE
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001406 printf("kernel BUG at %s:%u!\n",
1407 bug->file, bug->line);
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001408#else
1409 printf("kernel BUG at %p!\n", (void *)bug->bug_addr);
1410#endif
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001411#endif /* CONFIG_BUG */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412}
1413
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001414static void excprint(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415{
1416 unsigned long trap;
1417
1418#ifdef CONFIG_SMP
1419 printf("cpu 0x%x: ", smp_processor_id());
1420#endif /* CONFIG_SMP */
1421
1422 trap = TRAP(fp);
1423 printf("Vector: %lx %s at [%lx]\n", fp->trap, getvecname(trap), fp);
1424 printf(" pc: ");
1425 xmon_print_symbol(fp->nip, ": ", "\n");
1426
1427 printf(" lr: ", fp->link);
1428 xmon_print_symbol(fp->link, ": ", "\n");
1429
1430 printf(" sp: %lx\n", fp->gpr[1]);
1431 printf(" msr: %lx\n", fp->msr);
1432
1433 if (trap == 0x300 || trap == 0x380 || trap == 0x600) {
1434 printf(" dar: %lx\n", fp->dar);
1435 if (trap != 0x380)
1436 printf(" dsisr: %lx\n", fp->dsisr);
1437 }
1438
1439 printf(" current = 0x%lx\n", current);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001440#ifdef CONFIG_PPC64
Benjamin Herrenschmidt7230c562012-03-06 18:27:59 +11001441 printf(" paca = 0x%lx\t softe: %d\t irq_happened: 0x%02x\n",
1442 local_paca, local_paca->soft_enabled, local_paca->irq_happened);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001443#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444 if (current) {
1445 printf(" pid = %ld, comm = %s\n",
1446 current->pid, current->comm);
1447 }
1448
1449 if (trap == 0x700)
1450 print_bug_trap(fp);
1451}
1452
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001453static void prregs(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001455 int n, trap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 unsigned long base;
1457 struct pt_regs regs;
1458
1459 if (scanhex(&base)) {
1460 if (setjmp(bus_error_jmp) == 0) {
1461 catch_memory_errors = 1;
1462 sync();
1463 regs = *(struct pt_regs *)base;
1464 sync();
1465 __delay(200);
1466 } else {
1467 catch_memory_errors = 0;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001468 printf("*** Error reading registers from "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469 base);
1470 return;
1471 }
1472 catch_memory_errors = 0;
1473 fp = &regs;
1474 }
1475
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001476#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 if (FULL_REGS(fp)) {
1478 for (n = 0; n < 16; ++n)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001479 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 n, fp->gpr[n], n+16, fp->gpr[n+16]);
1481 } else {
1482 for (n = 0; n < 7; ++n)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001483 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484 n, fp->gpr[n], n+7, fp->gpr[n+7]);
1485 }
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001486#else
1487 for (n = 0; n < 32; ++n) {
1488 printf("R%.2d = %.8x%s", n, fp->gpr[n],
1489 (n & 3) == 3? "\n": " ");
1490 if (n == 12 && !FULL_REGS(fp)) {
1491 printf("\n");
1492 break;
1493 }
1494 }
1495#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 printf("pc = ");
1497 xmon_print_symbol(fp->nip, " ", "\n");
Paul Mackerras48404f22011-05-01 19:48:20 +00001498 if (TRAP(fp) != 0xc00 && cpu_has_feature(CPU_FTR_CFAR)) {
1499 printf("cfar= ");
1500 xmon_print_symbol(fp->orig_gpr3, " ", "\n");
1501 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 printf("lr = ");
1503 xmon_print_symbol(fp->link, " ", "\n");
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001504 printf("msr = "REG" cr = %.8lx\n", fp->msr, fp->ccr);
1505 printf("ctr = "REG" xer = "REG" trap = %4lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 fp->ctr, fp->xer, fp->trap);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001507 trap = TRAP(fp);
1508 if (trap == 0x300 || trap == 0x380 || trap == 0x600)
1509 printf("dar = "REG" dsisr = %.8lx\n", fp->dar, fp->dsisr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510}
1511
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001512static void cacheflush(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513{
1514 int cmd;
1515 unsigned long nflush;
1516
1517 cmd = inchar();
1518 if (cmd != 'i')
1519 termch = cmd;
1520 scanhex((void *)&adrs);
1521 if (termch != '\n')
1522 termch = 0;
1523 nflush = 1;
1524 scanhex(&nflush);
1525 nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES;
1526 if (setjmp(bus_error_jmp) == 0) {
1527 catch_memory_errors = 1;
1528 sync();
1529
1530 if (cmd != 'i') {
1531 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1532 cflush((void *) adrs);
1533 } else {
1534 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1535 cinval((void *) adrs);
1536 }
1537 sync();
1538 /* wait a little while to see if we get a machine check */
1539 __delay(200);
1540 }
1541 catch_memory_errors = 0;
1542}
1543
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001544static unsigned long
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545read_spr(int n)
1546{
1547 unsigned int instrs[2];
1548 unsigned long (*code)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 unsigned long ret = -1UL;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001550#ifdef CONFIG_PPC64
1551 unsigned long opd[3];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 opd[0] = (unsigned long)instrs;
1554 opd[1] = 0;
1555 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001556 code = (unsigned long (*)(void)) opd;
1557#else
1558 code = (unsigned long (*)(void)) instrs;
1559#endif
1560
1561 /* mfspr r3,n; blr */
1562 instrs[0] = 0x7c6002a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1563 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 store_inst(instrs);
1565 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566
1567 if (setjmp(bus_error_jmp) == 0) {
1568 catch_memory_errors = 1;
1569 sync();
1570
1571 ret = code();
1572
1573 sync();
1574 /* wait a little while to see if we get a machine check */
1575 __delay(200);
1576 n = size;
1577 }
1578
1579 return ret;
1580}
1581
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001582static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583write_spr(int n, unsigned long val)
1584{
1585 unsigned int instrs[2];
1586 unsigned long (*code)(unsigned long);
Paul Mackerras548cceb2005-11-11 22:36:34 +11001587#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588 unsigned long opd[3];
1589
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 opd[0] = (unsigned long)instrs;
1591 opd[1] = 0;
1592 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001593 code = (unsigned long (*)(unsigned long)) opd;
1594#else
1595 code = (unsigned long (*)(unsigned long)) instrs;
1596#endif
1597
1598 instrs[0] = 0x7c6003a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1599 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600 store_inst(instrs);
1601 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602
1603 if (setjmp(bus_error_jmp) == 0) {
1604 catch_memory_errors = 1;
1605 sync();
1606
1607 code(val);
1608
1609 sync();
1610 /* wait a little while to see if we get a machine check */
1611 __delay(200);
1612 n = size;
1613 }
1614}
1615
1616static unsigned long regno;
1617extern char exc_prolog;
1618extern char dec_exc;
1619
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001620static void super_regs(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621{
1622 int cmd;
1623 unsigned long val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624
1625 cmd = skipbl();
1626 if (cmd == '\n') {
Michael Ellermane3bc8042012-08-23 22:09:13 +00001627 unsigned long sp, toc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628 asm("mr %0,1" : "=r" (sp) :);
1629 asm("mr %0,2" : "=r" (toc) :);
1630
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001631 printf("msr = "REG" sprg0= "REG"\n",
1632 mfmsr(), mfspr(SPRN_SPRG0));
1633 printf("pvr = "REG" sprg1= "REG"\n",
Michael Ellermane3bc8042012-08-23 22:09:13 +00001634 mfspr(SPRN_PVR), mfspr(SPRN_SPRG1));
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001635 printf("dec = "REG" sprg2= "REG"\n",
1636 mfspr(SPRN_DEC), mfspr(SPRN_SPRG2));
1637 printf("sp = "REG" sprg3= "REG"\n", sp, mfspr(SPRN_SPRG3));
1638 printf("toc = "REG" dar = "REG"\n", toc, mfspr(SPRN_DAR));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639
1640 return;
1641 }
1642
1643 scanhex(&regno);
1644 switch (cmd) {
1645 case 'w':
1646 val = read_spr(regno);
1647 scanhex(&val);
1648 write_spr(regno, val);
1649 /* fall through */
1650 case 'r':
1651 printf("spr %lx = %lx\n", regno, read_spr(regno));
1652 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 }
1654 scannl();
1655}
1656
1657/*
1658 * Stuff for reading and writing memory safely
1659 */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001660static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661mread(unsigned long adrs, void *buf, int size)
1662{
1663 volatile int n;
1664 char *p, *q;
1665
1666 n = 0;
1667 if (setjmp(bus_error_jmp) == 0) {
1668 catch_memory_errors = 1;
1669 sync();
1670 p = (char *)adrs;
1671 q = (char *)buf;
1672 switch (size) {
1673 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001674 *(u16 *)q = *(u16 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675 break;
1676 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001677 *(u32 *)q = *(u32 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678 break;
1679 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001680 *(u64 *)q = *(u64 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681 break;
1682 default:
1683 for( ; n < size; ++n) {
1684 *q++ = *p++;
1685 sync();
1686 }
1687 }
1688 sync();
1689 /* wait a little while to see if we get a machine check */
1690 __delay(200);
1691 n = size;
1692 }
1693 catch_memory_errors = 0;
1694 return n;
1695}
1696
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001697static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698mwrite(unsigned long adrs, void *buf, int size)
1699{
1700 volatile int n;
1701 char *p, *q;
1702
1703 n = 0;
1704 if (setjmp(bus_error_jmp) == 0) {
1705 catch_memory_errors = 1;
1706 sync();
1707 p = (char *) adrs;
1708 q = (char *) buf;
1709 switch (size) {
1710 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001711 *(u16 *)p = *(u16 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712 break;
1713 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001714 *(u32 *)p = *(u32 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 break;
1716 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001717 *(u64 *)p = *(u64 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 break;
1719 default:
1720 for ( ; n < size; ++n) {
1721 *p++ = *q++;
1722 sync();
1723 }
1724 }
1725 sync();
1726 /* wait a little while to see if we get a machine check */
1727 __delay(200);
1728 n = size;
1729 } else {
1730 printf("*** Error writing address %x\n", adrs + n);
1731 }
1732 catch_memory_errors = 0;
1733 return n;
1734}
1735
1736static int fault_type;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001737static int fault_except;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738static char *fault_chars[] = { "--", "**", "##" };
1739
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001740static int handle_fault(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001742 fault_except = TRAP(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 switch (TRAP(regs)) {
1744 case 0x200:
1745 fault_type = 0;
1746 break;
1747 case 0x300:
1748 case 0x380:
1749 fault_type = 1;
1750 break;
1751 default:
1752 fault_type = 2;
1753 }
1754
1755 longjmp(bus_error_jmp, 1);
1756
1757 return 0;
1758}
1759
1760#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t))
1761
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001762static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763byterev(unsigned char *val, int size)
1764{
1765 int t;
1766
1767 switch (size) {
1768 case 2:
1769 SWAP(val[0], val[1], t);
1770 break;
1771 case 4:
1772 SWAP(val[0], val[3], t);
1773 SWAP(val[1], val[2], t);
1774 break;
1775 case 8: /* is there really any use for this? */
1776 SWAP(val[0], val[7], t);
1777 SWAP(val[1], val[6], t);
1778 SWAP(val[2], val[5], t);
1779 SWAP(val[3], val[4], t);
1780 break;
1781 }
1782}
1783
1784static int brev;
1785static int mnoread;
1786
Michael Ellermane3bc8042012-08-23 22:09:13 +00001787static char *memex_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788 "Memory examine command usage:\n"
1789 "m [addr] [flags] examine/change memory\n"
1790 " addr is optional. will start where left off.\n"
1791 " flags may include chars from this set:\n"
1792 " b modify by bytes (default)\n"
1793 " w modify by words (2 byte)\n"
1794 " l modify by longs (4 byte)\n"
1795 " d modify by doubleword (8 byte)\n"
1796 " r toggle reverse byte order mode\n"
1797 " n do not read memory (for i/o spaces)\n"
1798 " . ok to read (default)\n"
1799 "NOTE: flags are saved as defaults\n"
1800 "";
1801
Michael Ellermane3bc8042012-08-23 22:09:13 +00001802static char *memex_subcmd_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803 "Memory examine subcommands:\n"
1804 " hexval write this val to current location\n"
1805 " 'string' write chars from string to this location\n"
1806 " ' increment address\n"
1807 " ^ decrement address\n"
1808 " / increment addr by 0x10. //=0x100, ///=0x1000, etc\n"
1809 " \\ decrement addr by 0x10. \\\\=0x100, \\\\\\=0x1000, etc\n"
1810 " ` clear no-read flag\n"
1811 " ; stay at this addr\n"
1812 " v change to byte mode\n"
1813 " w change to word (2 byte) mode\n"
1814 " l change to long (4 byte) mode\n"
1815 " u change to doubleword (8 byte) mode\n"
1816 " m addr change current addr\n"
1817 " n toggle no-read flag\n"
1818 " r toggle byte reverse flag\n"
1819 " < count back up count bytes\n"
1820 " > count skip forward count bytes\n"
1821 " x exit this mode\n"
1822 "";
1823
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001824static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825memex(void)
1826{
1827 int cmd, inc, i, nslash;
1828 unsigned long n;
1829 unsigned char val[16];
1830
1831 scanhex((void *)&adrs);
1832 cmd = skipbl();
1833 if (cmd == '?') {
1834 printf(memex_help_string);
1835 return;
1836 } else {
1837 termch = cmd;
1838 }
1839 last_cmd = "m\n";
1840 while ((cmd = skipbl()) != '\n') {
1841 switch( cmd ){
1842 case 'b': size = 1; break;
1843 case 'w': size = 2; break;
1844 case 'l': size = 4; break;
1845 case 'd': size = 8; break;
1846 case 'r': brev = !brev; break;
1847 case 'n': mnoread = 1; break;
1848 case '.': mnoread = 0; break;
1849 }
1850 }
1851 if( size <= 0 )
1852 size = 1;
1853 else if( size > 8 )
1854 size = 8;
1855 for(;;){
1856 if (!mnoread)
1857 n = mread(adrs, val, size);
Paul Mackerrase1449ed2005-11-10 14:30:20 +11001858 printf(REG"%c", adrs, brev? 'r': ' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 if (!mnoread) {
1860 if (brev)
1861 byterev(val, size);
1862 putchar(' ');
1863 for (i = 0; i < n; ++i)
1864 printf("%.2x", val[i]);
1865 for (; i < size; ++i)
1866 printf("%s", fault_chars[fault_type]);
1867 }
1868 putchar(' ');
1869 inc = size;
1870 nslash = 0;
1871 for(;;){
1872 if( scanhex(&n) ){
1873 for (i = 0; i < size; ++i)
1874 val[i] = n >> (i * 8);
1875 if (!brev)
1876 byterev(val, size);
1877 mwrite(adrs, val, size);
1878 inc = size;
1879 }
1880 cmd = skipbl();
1881 if (cmd == '\n')
1882 break;
1883 inc = 0;
1884 switch (cmd) {
1885 case '\'':
1886 for(;;){
1887 n = inchar();
1888 if( n == '\\' )
1889 n = bsesc();
1890 else if( n == '\'' )
1891 break;
1892 for (i = 0; i < size; ++i)
1893 val[i] = n >> (i * 8);
1894 if (!brev)
1895 byterev(val, size);
1896 mwrite(adrs, val, size);
1897 adrs += size;
1898 }
1899 adrs -= size;
1900 inc = size;
1901 break;
1902 case ',':
1903 adrs += size;
1904 break;
1905 case '.':
1906 mnoread = 0;
1907 break;
1908 case ';':
1909 break;
1910 case 'x':
1911 case EOF:
1912 scannl();
1913 return;
1914 case 'b':
1915 case 'v':
1916 size = 1;
1917 break;
1918 case 'w':
1919 size = 2;
1920 break;
1921 case 'l':
1922 size = 4;
1923 break;
1924 case 'u':
1925 size = 8;
1926 break;
1927 case '^':
1928 adrs -= size;
1929 break;
1930 break;
1931 case '/':
1932 if (nslash > 0)
1933 adrs -= 1 << nslash;
1934 else
1935 nslash = 0;
1936 nslash += 4;
1937 adrs += 1 << nslash;
1938 break;
1939 case '\\':
1940 if (nslash < 0)
1941 adrs += 1 << -nslash;
1942 else
1943 nslash = 0;
1944 nslash -= 4;
1945 adrs -= 1 << -nslash;
1946 break;
1947 case 'm':
1948 scanhex((void *)&adrs);
1949 break;
1950 case 'n':
1951 mnoread = 1;
1952 break;
1953 case 'r':
1954 brev = !brev;
1955 break;
1956 case '<':
1957 n = size;
1958 scanhex(&n);
1959 adrs -= n;
1960 break;
1961 case '>':
1962 n = size;
1963 scanhex(&n);
1964 adrs += n;
1965 break;
1966 case '?':
1967 printf(memex_subcmd_help_string);
1968 break;
1969 }
1970 }
1971 adrs += inc;
1972 }
1973}
1974
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001975static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976bsesc(void)
1977{
1978 int c;
1979
1980 c = inchar();
1981 switch( c ){
1982 case 'n': c = '\n'; break;
1983 case 'r': c = '\r'; break;
1984 case 'b': c = '\b'; break;
1985 case 't': c = '\t'; break;
1986 }
1987 return c;
1988}
1989
Olaf Hering7e5b5932006-03-08 20:40:28 +01001990static void xmon_rawdump (unsigned long adrs, long ndump)
1991{
1992 long n, m, r, nr;
1993 unsigned char temp[16];
1994
1995 for (n = ndump; n > 0;) {
1996 r = n < 16? n: 16;
1997 nr = mread(adrs, temp, r);
1998 adrs += nr;
1999 for (m = 0; m < r; ++m) {
2000 if (m < nr)
2001 printf("%.2x", temp[m]);
2002 else
2003 printf("%s", fault_chars[fault_type]);
2004 }
2005 n -= r;
2006 if (nr < r)
2007 break;
2008 }
2009 printf("\n");
2010}
2011
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002012#ifdef CONFIG_PPC64
2013static void dump_one_paca(int cpu)
2014{
2015 struct paca_struct *p;
2016
2017 if (setjmp(bus_error_jmp) != 0) {
2018 printf("*** Error dumping paca for cpu 0x%x!\n", cpu);
2019 return;
2020 }
2021
2022 catch_memory_errors = 1;
2023 sync();
2024
2025 p = &paca[cpu];
2026
2027 printf("paca for cpu 0x%x @ %p:\n", cpu, p);
2028
2029 printf(" %-*s = %s\n", 16, "possible", cpu_possible(cpu) ? "yes" : "no");
2030 printf(" %-*s = %s\n", 16, "present", cpu_present(cpu) ? "yes" : "no");
2031 printf(" %-*s = %s\n", 16, "online", cpu_online(cpu) ? "yes" : "no");
2032
2033#define DUMP(paca, name, format) \
2034 printf(" %-*s = %#-*"format"\t(0x%lx)\n", 16, #name, 18, paca->name, \
2035 offsetof(struct paca_struct, name));
2036
2037 DUMP(p, lock_token, "x");
2038 DUMP(p, paca_index, "x");
2039 DUMP(p, kernel_toc, "lx");
2040 DUMP(p, kernelbase, "lx");
2041 DUMP(p, kernel_msr, "lx");
2042#ifdef CONFIG_PPC_STD_MMU_64
2043 DUMP(p, stab_real, "lx");
2044 DUMP(p, stab_addr, "lx");
2045#endif
2046 DUMP(p, emergency_sp, "p");
2047 DUMP(p, data_offset, "lx");
2048 DUMP(p, hw_cpu_id, "x");
2049 DUMP(p, cpu_start, "x");
2050 DUMP(p, kexec_state, "x");
2051 DUMP(p, __current, "p");
2052 DUMP(p, kstack, "lx");
2053 DUMP(p, stab_rr, "lx");
2054 DUMP(p, saved_r1, "lx");
2055 DUMP(p, trap_save, "x");
2056 DUMP(p, soft_enabled, "x");
2057 DUMP(p, irq_happened, "x");
2058 DUMP(p, io_sync, "x");
2059 DUMP(p, irq_work_pending, "x");
2060 DUMP(p, nap_state_lost, "x");
2061
2062#undef DUMP
2063
2064 catch_memory_errors = 0;
2065 sync();
2066}
2067
2068static void dump_all_pacas(void)
2069{
2070 int cpu;
2071
2072 if (num_possible_cpus() == 0) {
2073 printf("No possible cpus, use 'dp #' to dump individual cpus\n");
2074 return;
2075 }
2076
2077 for_each_possible_cpu(cpu)
2078 dump_one_paca(cpu);
2079}
2080
2081static void dump_pacas(void)
2082{
2083 unsigned long num;
2084 int c;
2085
2086 c = inchar();
2087 if (c == 'a') {
2088 dump_all_pacas();
2089 return;
2090 }
2091
2092 termch = c; /* Put c back, it wasn't 'a' */
2093
2094 if (scanhex(&num))
2095 dump_one_paca(num);
2096 else
2097 dump_one_paca(xmon_owner);
2098}
2099#endif
2100
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
2102 || ('a' <= (c) && (c) <= 'f') \
2103 || ('A' <= (c) && (c) <= 'F'))
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002104static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105dump(void)
2106{
2107 int c;
2108
2109 c = inchar();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002110
2111#ifdef CONFIG_PPC64
2112 if (c == 'p') {
2113 dump_pacas();
2114 return;
2115 }
2116#endif
2117
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118 if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
2119 termch = c;
2120 scanhex((void *)&adrs);
2121 if (termch != '\n')
2122 termch = 0;
2123 if (c == 'i') {
2124 scanhex(&nidump);
2125 if (nidump == 0)
2126 nidump = 16;
2127 else if (nidump > MAX_DUMP)
2128 nidump = MAX_DUMP;
2129 adrs += ppc_inst_dump(adrs, nidump, 1);
2130 last_cmd = "di\n";
Vinay Sridharf312deb2009-05-14 23:13:07 +00002131 } else if (c == 'l') {
2132 dump_log_buf();
Olaf Hering7e5b5932006-03-08 20:40:28 +01002133 } else if (c == 'r') {
2134 scanhex(&ndump);
2135 if (ndump == 0)
2136 ndump = 64;
2137 xmon_rawdump(adrs, ndump);
2138 adrs += ndump;
2139 last_cmd = "dr\n";
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140 } else {
2141 scanhex(&ndump);
2142 if (ndump == 0)
2143 ndump = 64;
2144 else if (ndump > MAX_DUMP)
2145 ndump = MAX_DUMP;
2146 prdump(adrs, ndump);
2147 adrs += ndump;
2148 last_cmd = "d\n";
2149 }
2150}
2151
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002152static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153prdump(unsigned long adrs, long ndump)
2154{
2155 long n, m, c, r, nr;
2156 unsigned char temp[16];
2157
2158 for (n = ndump; n > 0;) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002159 printf(REG, adrs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160 putchar(' ');
2161 r = n < 16? n: 16;
2162 nr = mread(adrs, temp, r);
2163 adrs += nr;
2164 for (m = 0; m < r; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002165 if ((m & (sizeof(long) - 1)) == 0 && m > 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002166 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167 if (m < nr)
2168 printf("%.2x", temp[m]);
2169 else
2170 printf("%s", fault_chars[fault_type]);
2171 }
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002172 for (; m < 16; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002173 if ((m & (sizeof(long) - 1)) == 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002174 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 printf(" ");
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002176 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177 printf(" |");
2178 for (m = 0; m < r; ++m) {
2179 if (m < nr) {
2180 c = temp[m];
2181 putchar(' ' <= c && c <= '~'? c: '.');
2182 } else
2183 putchar(' ');
2184 }
2185 n -= r;
2186 for (; m < 16; ++m)
2187 putchar(' ');
2188 printf("|\n");
2189 if (nr < r)
2190 break;
2191 }
2192}
2193
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002194typedef int (*instruction_dump_func)(unsigned long inst, unsigned long addr);
2195
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002196static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002197generic_inst_dump(unsigned long adr, long count, int praddr,
2198 instruction_dump_func dump_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199{
2200 int nr, dotted;
2201 unsigned long first_adr;
2202 unsigned long inst, last_inst = 0;
2203 unsigned char val[4];
2204
2205 dotted = 0;
2206 for (first_adr = adr; count > 0; --count, adr += 4) {
2207 nr = mread(adr, val, 4);
2208 if (nr == 0) {
2209 if (praddr) {
2210 const char *x = fault_chars[fault_type];
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002211 printf(REG" %s%s%s%s\n", adr, x, x, x, x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212 }
2213 break;
2214 }
2215 inst = GETWORD(val);
2216 if (adr > first_adr && inst == last_inst) {
2217 if (!dotted) {
2218 printf(" ...\n");
2219 dotted = 1;
2220 }
2221 continue;
2222 }
2223 dotted = 0;
2224 last_inst = inst;
2225 if (praddr)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002226 printf(REG" %.8x", adr, inst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227 printf("\t");
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002228 dump_func(inst, adr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229 printf("\n");
2230 }
2231 return adr - first_adr;
2232}
2233
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002234static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002235ppc_inst_dump(unsigned long adr, long count, int praddr)
2236{
2237 return generic_inst_dump(adr, count, praddr, print_insn_powerpc);
2238}
2239
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240void
2241print_address(unsigned long addr)
2242{
2243 xmon_print_symbol(addr, "\t# ", "");
2244}
2245
Vinay Sridharf312deb2009-05-14 23:13:07 +00002246void
2247dump_log_buf(void)
2248{
Michael Ellermanca5dd392012-08-23 22:09:12 +00002249 struct kmsg_dumper dumper = { .active = 1 };
2250 unsigned char buf[128];
2251 size_t len;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002252
Michael Ellermane3bc8042012-08-23 22:09:13 +00002253 if (setjmp(bus_error_jmp) != 0) {
Michael Ellermanca5dd392012-08-23 22:09:12 +00002254 printf("Error dumping printk buffer!\n");
Michael Ellermane3bc8042012-08-23 22:09:13 +00002255 return;
2256 }
Vinay Sridharf312deb2009-05-14 23:13:07 +00002257
Michael Ellermane3bc8042012-08-23 22:09:13 +00002258 catch_memory_errors = 1;
2259 sync();
Vinay Sridharf312deb2009-05-14 23:13:07 +00002260
Michael Ellermanca5dd392012-08-23 22:09:12 +00002261 kmsg_dump_rewind_nolock(&dumper);
2262 while (kmsg_dump_get_line_nolock(&dumper, false, buf, sizeof(buf), &len)) {
2263 buf[len] = '\0';
2264 printf("%s", buf);
2265 }
Vinay Sridharf312deb2009-05-14 23:13:07 +00002266
Michael Ellermane3bc8042012-08-23 22:09:13 +00002267 sync();
2268 /* wait a little while to see if we get a machine check */
2269 __delay(200);
2270 catch_memory_errors = 0;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002271}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002272
2273/*
2274 * Memory operations - move, set, print differences
2275 */
2276static unsigned long mdest; /* destination address */
2277static unsigned long msrc; /* source address */
2278static unsigned long mval; /* byte value to set memory to */
2279static unsigned long mcount; /* # bytes to affect */
2280static unsigned long mdiffs; /* max # differences to print */
2281
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002282static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283memops(int cmd)
2284{
2285 scanhex((void *)&mdest);
2286 if( termch != '\n' )
2287 termch = 0;
2288 scanhex((void *)(cmd == 's'? &mval: &msrc));
2289 if( termch != '\n' )
2290 termch = 0;
2291 scanhex((void *)&mcount);
2292 switch( cmd ){
2293 case 'm':
2294 memmove((void *)mdest, (void *)msrc, mcount);
2295 break;
2296 case 's':
2297 memset((void *)mdest, mval, mcount);
2298 break;
2299 case 'd':
2300 if( termch != '\n' )
2301 termch = 0;
2302 scanhex((void *)&mdiffs);
2303 memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
2304 break;
2305 }
2306}
2307
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002308static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
2310{
2311 unsigned n, prt;
2312
2313 prt = 0;
2314 for( n = nb; n > 0; --n )
2315 if( *p1++ != *p2++ )
2316 if( ++prt <= maxpr )
2317 printf("%.16x %.2x # %.16x %.2x\n", p1 - 1,
2318 p1[-1], p2 - 1, p2[-1]);
2319 if( prt > maxpr )
2320 printf("Total of %d differences\n", prt);
2321}
2322
2323static unsigned mend;
2324static unsigned mask;
2325
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002326static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327memlocate(void)
2328{
2329 unsigned a, n;
2330 unsigned char val[4];
2331
2332 last_cmd = "ml";
2333 scanhex((void *)&mdest);
2334 if (termch != '\n') {
2335 termch = 0;
2336 scanhex((void *)&mend);
2337 if (termch != '\n') {
2338 termch = 0;
2339 scanhex((void *)&mval);
2340 mask = ~0;
2341 if (termch != '\n') termch = 0;
2342 scanhex((void *)&mask);
2343 }
2344 }
2345 n = 0;
2346 for (a = mdest; a < mend; a += 4) {
2347 if (mread(a, val, 4) == 4
2348 && ((GETWORD(val) ^ mval) & mask) == 0) {
2349 printf("%.16x: %.16x\n", a, GETWORD(val));
2350 if (++n >= 10)
2351 break;
2352 }
2353 }
2354}
2355
2356static unsigned long mskip = 0x1000;
2357static unsigned long mlim = 0xffffffff;
2358
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002359static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360memzcan(void)
2361{
2362 unsigned char v;
2363 unsigned a;
2364 int ok, ook;
2365
2366 scanhex(&mdest);
2367 if (termch != '\n') termch = 0;
2368 scanhex(&mskip);
2369 if (termch != '\n') termch = 0;
2370 scanhex(&mlim);
2371 ook = 0;
2372 for (a = mdest; a < mlim; a += mskip) {
2373 ok = mread(a, &v, 1);
2374 if (ok && !ook) {
2375 printf("%.8x .. ", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376 } else if (!ok && ook)
2377 printf("%.8x\n", a - mskip);
2378 ook = ok;
2379 if (a + mskip < a)
2380 break;
2381 }
2382 if (ook)
2383 printf("%.8x\n", a - mskip);
2384}
2385
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002386static void proccall(void)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002387{
2388 unsigned long args[8];
2389 unsigned long ret;
2390 int i;
2391 typedef unsigned long (*callfunc_t)(unsigned long, unsigned long,
2392 unsigned long, unsigned long, unsigned long,
2393 unsigned long, unsigned long, unsigned long);
2394 callfunc_t func;
2395
2396 if (!scanhex(&adrs))
2397 return;
2398 if (termch != '\n')
2399 termch = 0;
2400 for (i = 0; i < 8; ++i)
2401 args[i] = 0;
2402 for (i = 0; i < 8; ++i) {
2403 if (!scanhex(&args[i]) || termch == '\n')
2404 break;
2405 termch = 0;
2406 }
2407 func = (callfunc_t) adrs;
2408 ret = 0;
2409 if (setjmp(bus_error_jmp) == 0) {
2410 catch_memory_errors = 1;
2411 sync();
2412 ret = func(args[0], args[1], args[2], args[3],
2413 args[4], args[5], args[6], args[7]);
2414 sync();
2415 printf("return value is %x\n", ret);
2416 } else {
2417 printf("*** %x exception occurred\n", fault_except);
2418 }
2419 catch_memory_errors = 0;
2420}
2421
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422/* Input scanning routines */
2423int
2424skipbl(void)
2425{
2426 int c;
2427
2428 if( termch != 0 ){
2429 c = termch;
2430 termch = 0;
2431 } else
2432 c = inchar();
2433 while( c == ' ' || c == '\t' )
2434 c = inchar();
2435 return c;
2436}
2437
2438#define N_PTREGS 44
2439static char *regnames[N_PTREGS] = {
2440 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
2441 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
2442 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
2443 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002444 "pc", "msr", "or3", "ctr", "lr", "xer", "ccr",
2445#ifdef CONFIG_PPC64
2446 "softe",
2447#else
2448 "mq",
2449#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450 "trap", "dar", "dsisr", "res"
2451};
2452
2453int
2454scanhex(unsigned long *vp)
2455{
2456 int c, d;
2457 unsigned long v;
2458
2459 c = skipbl();
2460 if (c == '%') {
2461 /* parse register name */
2462 char regname[8];
2463 int i;
2464
2465 for (i = 0; i < sizeof(regname) - 1; ++i) {
2466 c = inchar();
2467 if (!isalnum(c)) {
2468 termch = c;
2469 break;
2470 }
2471 regname[i] = c;
2472 }
2473 regname[i] = 0;
2474 for (i = 0; i < N_PTREGS; ++i) {
2475 if (strcmp(regnames[i], regname) == 0) {
2476 if (xmon_regs == NULL) {
2477 printf("regs not available\n");
2478 return 0;
2479 }
2480 *vp = ((unsigned long *)xmon_regs)[i];
2481 return 1;
2482 }
2483 }
2484 printf("invalid register name '%%%s'\n", regname);
2485 return 0;
2486 }
2487
2488 /* skip leading "0x" if any */
2489
2490 if (c == '0') {
2491 c = inchar();
2492 if (c == 'x') {
2493 c = inchar();
2494 } else {
2495 d = hexdigit(c);
2496 if (d == EOF) {
2497 termch = c;
2498 *vp = 0;
2499 return 1;
2500 }
2501 }
2502 } else if (c == '$') {
2503 int i;
2504 for (i=0; i<63; i++) {
2505 c = inchar();
2506 if (isspace(c)) {
2507 termch = c;
2508 break;
2509 }
2510 tmpstr[i] = c;
2511 }
2512 tmpstr[i++] = 0;
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07002513 *vp = 0;
2514 if (setjmp(bus_error_jmp) == 0) {
2515 catch_memory_errors = 1;
2516 sync();
2517 *vp = kallsyms_lookup_name(tmpstr);
2518 sync();
2519 }
2520 catch_memory_errors = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521 if (!(*vp)) {
2522 printf("unknown symbol '%s'\n", tmpstr);
2523 return 0;
2524 }
2525 return 1;
2526 }
2527
2528 d = hexdigit(c);
2529 if (d == EOF) {
2530 termch = c;
2531 return 0;
2532 }
2533 v = 0;
2534 do {
2535 v = (v << 4) + d;
2536 c = inchar();
2537 d = hexdigit(c);
2538 } while (d != EOF);
2539 termch = c;
2540 *vp = v;
2541 return 1;
2542}
2543
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002544static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545scannl(void)
2546{
2547 int c;
2548
2549 c = termch;
2550 termch = 0;
2551 while( c != '\n' )
2552 c = inchar();
2553}
2554
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002555static int hexdigit(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556{
2557 if( '0' <= c && c <= '9' )
2558 return c - '0';
2559 if( 'A' <= c && c <= 'F' )
2560 return c - ('A' - 10);
2561 if( 'a' <= c && c <= 'f' )
2562 return c - ('a' - 10);
2563 return EOF;
2564}
2565
2566void
2567getstring(char *s, int size)
2568{
2569 int c;
2570
2571 c = skipbl();
2572 do {
2573 if( size > 1 ){
2574 *s++ = c;
2575 --size;
2576 }
2577 c = inchar();
2578 } while( c != ' ' && c != '\t' && c != '\n' );
2579 termch = c;
2580 *s = 0;
2581}
2582
2583static char line[256];
2584static char *lineptr;
2585
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002586static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587flush_input(void)
2588{
2589 lineptr = NULL;
2590}
2591
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002592static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593inchar(void)
2594{
2595 if (lineptr == NULL || *lineptr == 0) {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002596 if (xmon_gets(line, sizeof(line)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597 lineptr = NULL;
2598 return EOF;
2599 }
2600 lineptr = line;
2601 }
2602 return *lineptr++;
2603}
2604
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002605static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606take_input(char *str)
2607{
2608 lineptr = str;
2609}
2610
2611
2612static void
2613symbol_lookup(void)
2614{
2615 int type = inchar();
2616 unsigned long addr;
2617 static char tmp[64];
2618
2619 switch (type) {
2620 case 'a':
2621 if (scanhex(&addr))
2622 xmon_print_symbol(addr, ": ", "\n");
2623 termch = 0;
2624 break;
2625 case 's':
2626 getstring(tmp, 64);
2627 if (setjmp(bus_error_jmp) == 0) {
2628 catch_memory_errors = 1;
2629 sync();
2630 addr = kallsyms_lookup_name(tmp);
2631 if (addr)
2632 printf("%s: %lx\n", tmp, addr);
2633 else
2634 printf("Symbol '%s' not found.\n", tmp);
2635 sync();
2636 }
2637 catch_memory_errors = 0;
2638 termch = 0;
2639 break;
2640 }
2641}
2642
2643
2644/* Print an address in numeric and symbolic form (if possible) */
2645static void xmon_print_symbol(unsigned long address, const char *mid,
2646 const char *after)
2647{
2648 char *modname;
2649 const char *name = NULL;
2650 unsigned long offset, size;
2651
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002652 printf(REG, address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653 if (setjmp(bus_error_jmp) == 0) {
2654 catch_memory_errors = 1;
2655 sync();
2656 name = kallsyms_lookup(address, &size, &offset, &modname,
2657 tmpstr);
2658 sync();
2659 /* wait a little while to see if we get a machine check */
2660 __delay(200);
2661 }
2662
2663 catch_memory_errors = 0;
2664
2665 if (name) {
2666 printf("%s%s+%#lx/%#lx", mid, name, offset, size);
2667 if (modname)
2668 printf(" [%s]", modname);
2669 }
2670 printf("%s", after);
2671}
2672
Benjamin Herrenschmidt2d27cfd2009-07-23 23:15:59 +00002673#ifdef CONFIG_PPC_BOOK3S_64
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674static void dump_slb(void)
2675{
2676 int i;
will schmidtb3b95952007-12-07 08:22:23 +11002677 unsigned long esid,vsid,valid;
2678 unsigned long llp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679
2680 printf("SLB contents of cpu %x\n", smp_processor_id());
2681
Michael Neuling584f8b72007-12-06 17:24:48 +11002682 for (i = 0; i < mmu_slb_size; i++) {
will schmidtb3b95952007-12-07 08:22:23 +11002683 asm volatile("slbmfee %0,%1" : "=r" (esid) : "r" (i));
2684 asm volatile("slbmfev %0,%1" : "=r" (vsid) : "r" (i));
2685 valid = (esid & SLB_ESID_V);
2686 if (valid | esid | vsid) {
2687 printf("%02d %016lx %016lx", i, esid, vsid);
2688 if (valid) {
2689 llp = vsid & SLB_VSID_LLP;
2690 if (vsid & SLB_VSID_B_1T) {
2691 printf(" 1T ESID=%9lx VSID=%13lx LLP:%3lx \n",
2692 GET_ESID_1T(esid),
2693 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT_1T,
2694 llp);
2695 } else {
2696 printf(" 256M ESID=%9lx VSID=%13lx LLP:%3lx \n",
2697 GET_ESID(esid),
2698 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT,
2699 llp);
2700 }
2701 } else
2702 printf("\n");
2703 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704 }
2705}
2706
2707static void dump_stab(void)
2708{
2709 int i;
Benjamin Herrenschmidt7ac21cd2012-03-02 10:10:09 +11002710 unsigned long *tmp = (unsigned long *)local_paca->stab_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711
2712 printf("Segment table contents of cpu %x\n", smp_processor_id());
2713
2714 for (i = 0; i < PAGE_SIZE/16; i++) {
2715 unsigned long a, b;
2716
2717 a = *tmp++;
2718 b = *tmp++;
2719
2720 if (a || b) {
2721 printf("%03d %016lx ", i, a);
2722 printf("%016lx\n", b);
2723 }
2724 }
2725}
2726
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002727void dump_segments(void)
2728{
Matt Evans44ae3ab2011-04-06 19:48:50 +00002729 if (mmu_has_feature(MMU_FTR_SLB))
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002730 dump_slb();
2731 else
2732 dump_stab();
2733}
2734#endif
2735
2736#ifdef CONFIG_PPC_STD_MMU_32
2737void dump_segments(void)
2738{
2739 int i;
2740
2741 printf("sr0-15 =");
2742 for (i = 0; i < 16; ++i)
2743 printf(" %x", mfsrin(i));
2744 printf("\n");
2745}
2746#endif
2747
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11002748#ifdef CONFIG_44x
2749static void dump_tlb_44x(void)
2750{
2751 int i;
2752
2753 for (i = 0; i < PPC44x_TLB_SIZE; i++) {
2754 unsigned long w0,w1,w2;
2755 asm volatile("tlbre %0,%1,0" : "=r" (w0) : "r" (i));
2756 asm volatile("tlbre %0,%1,1" : "=r" (w1) : "r" (i));
2757 asm volatile("tlbre %0,%1,2" : "=r" (w2) : "r" (i));
2758 printf("[%02x] %08x %08x %08x ", i, w0, w1, w2);
2759 if (w0 & PPC44x_TLB_VALID) {
2760 printf("V %08x -> %01x%08x %c%c%c%c%c",
2761 w0 & PPC44x_TLB_EPN_MASK,
2762 w1 & PPC44x_TLB_ERPN_MASK,
2763 w1 & PPC44x_TLB_RPN_MASK,
2764 (w2 & PPC44x_TLB_W) ? 'W' : 'w',
2765 (w2 & PPC44x_TLB_I) ? 'I' : 'i',
2766 (w2 & PPC44x_TLB_M) ? 'M' : 'm',
2767 (w2 & PPC44x_TLB_G) ? 'G' : 'g',
2768 (w2 & PPC44x_TLB_E) ? 'E' : 'e');
2769 }
2770 printf("\n");
2771 }
2772}
2773#endif /* CONFIG_44x */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002774
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +10002775#ifdef CONFIG_PPC_BOOK3E
2776static void dump_tlb_book3e(void)
2777{
2778 u32 mmucfg, pidmask, lpidmask;
2779 u64 ramask;
2780 int i, tlb, ntlbs, pidsz, lpidsz, rasz, lrat = 0;
2781 int mmu_version;
2782 static const char *pgsz_names[] = {
2783 " 1K",
2784 " 2K",
2785 " 4K",
2786 " 8K",
2787 " 16K",
2788 " 32K",
2789 " 64K",
2790 "128K",
2791 "256K",
2792 "512K",
2793 " 1M",
2794 " 2M",
2795 " 4M",
2796 " 8M",
2797 " 16M",
2798 " 32M",
2799 " 64M",
2800 "128M",
2801 "256M",
2802 "512M",
2803 " 1G",
2804 " 2G",
2805 " 4G",
2806 " 8G",
2807 " 16G",
2808 " 32G",
2809 " 64G",
2810 "128G",
2811 "256G",
2812 "512G",
2813 " 1T",
2814 " 2T",
2815 };
2816
2817 /* Gather some infos about the MMU */
2818 mmucfg = mfspr(SPRN_MMUCFG);
2819 mmu_version = (mmucfg & 3) + 1;
2820 ntlbs = ((mmucfg >> 2) & 3) + 1;
2821 pidsz = ((mmucfg >> 6) & 0x1f) + 1;
2822 lpidsz = (mmucfg >> 24) & 0xf;
2823 rasz = (mmucfg >> 16) & 0x7f;
2824 if ((mmu_version > 1) && (mmucfg & 0x10000))
2825 lrat = 1;
2826 printf("Book3E MMU MAV=%d.0,%d TLBs,%d-bit PID,%d-bit LPID,%d-bit RA\n",
2827 mmu_version, ntlbs, pidsz, lpidsz, rasz);
2828 pidmask = (1ul << pidsz) - 1;
2829 lpidmask = (1ul << lpidsz) - 1;
2830 ramask = (1ull << rasz) - 1;
2831
2832 for (tlb = 0; tlb < ntlbs; tlb++) {
2833 u32 tlbcfg;
2834 int nent, assoc, new_cc = 1;
2835 printf("TLB %d:\n------\n", tlb);
2836 switch(tlb) {
2837 case 0:
2838 tlbcfg = mfspr(SPRN_TLB0CFG);
2839 break;
2840 case 1:
2841 tlbcfg = mfspr(SPRN_TLB1CFG);
2842 break;
2843 case 2:
2844 tlbcfg = mfspr(SPRN_TLB2CFG);
2845 break;
2846 case 3:
2847 tlbcfg = mfspr(SPRN_TLB3CFG);
2848 break;
2849 default:
2850 printf("Unsupported TLB number !\n");
2851 continue;
2852 }
2853 nent = tlbcfg & 0xfff;
2854 assoc = (tlbcfg >> 24) & 0xff;
2855 for (i = 0; i < nent; i++) {
2856 u32 mas0 = MAS0_TLBSEL(tlb);
2857 u32 mas1 = MAS1_TSIZE(BOOK3E_PAGESZ_4K);
2858 u64 mas2 = 0;
2859 u64 mas7_mas3;
2860 int esel = i, cc = i;
2861
2862 if (assoc != 0) {
2863 cc = i / assoc;
2864 esel = i % assoc;
2865 mas2 = cc * 0x1000;
2866 }
2867
2868 mas0 |= MAS0_ESEL(esel);
2869 mtspr(SPRN_MAS0, mas0);
2870 mtspr(SPRN_MAS1, mas1);
2871 mtspr(SPRN_MAS2, mas2);
2872 asm volatile("tlbre 0,0,0" : : : "memory");
2873 mas1 = mfspr(SPRN_MAS1);
2874 mas2 = mfspr(SPRN_MAS2);
2875 mas7_mas3 = mfspr(SPRN_MAS7_MAS3);
2876 if (assoc && (i % assoc) == 0)
2877 new_cc = 1;
2878 if (!(mas1 & MAS1_VALID))
2879 continue;
2880 if (assoc == 0)
2881 printf("%04x- ", i);
2882 else if (new_cc)
2883 printf("%04x-%c", cc, 'A' + esel);
2884 else
2885 printf(" |%c", 'A' + esel);
2886 new_cc = 0;
2887 printf(" %016llx %04x %s %c%c AS%c",
2888 mas2 & ~0x3ffull,
2889 (mas1 >> 16) & 0x3fff,
2890 pgsz_names[(mas1 >> 7) & 0x1f],
2891 mas1 & MAS1_IND ? 'I' : ' ',
2892 mas1 & MAS1_IPROT ? 'P' : ' ',
2893 mas1 & MAS1_TS ? '1' : '0');
2894 printf(" %c%c%c%c%c%c%c",
2895 mas2 & MAS2_X0 ? 'a' : ' ',
2896 mas2 & MAS2_X1 ? 'v' : ' ',
2897 mas2 & MAS2_W ? 'w' : ' ',
2898 mas2 & MAS2_I ? 'i' : ' ',
2899 mas2 & MAS2_M ? 'm' : ' ',
2900 mas2 & MAS2_G ? 'g' : ' ',
2901 mas2 & MAS2_E ? 'e' : ' ');
2902 printf(" %016llx", mas7_mas3 & ramask & ~0x7ffull);
2903 if (mas1 & MAS1_IND)
2904 printf(" %s\n",
2905 pgsz_names[(mas7_mas3 >> 1) & 0x1f]);
2906 else
2907 printf(" U%c%c%c S%c%c%c\n",
2908 mas7_mas3 & MAS3_UX ? 'x' : ' ',
2909 mas7_mas3 & MAS3_UW ? 'w' : ' ',
2910 mas7_mas3 & MAS3_UR ? 'r' : ' ',
2911 mas7_mas3 & MAS3_SX ? 'x' : ' ',
2912 mas7_mas3 & MAS3_SW ? 'w' : ' ',
2913 mas7_mas3 & MAS3_SR ? 'r' : ' ');
2914 }
2915 }
2916}
2917#endif /* CONFIG_PPC_BOOK3E */
2918
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002919static void xmon_init(int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920{
Olaf Heringb13cfd172005-08-04 19:26:42 +02002921 if (enable) {
2922 __debugger = xmon;
2923 __debugger_ipi = xmon_ipi;
2924 __debugger_bpt = xmon_bpt;
2925 __debugger_sstep = xmon_sstep;
2926 __debugger_iabr_match = xmon_iabr_match;
Michael Neuling9422de32012-12-20 14:06:44 +00002927 __debugger_break_match = xmon_break_match;
Olaf Heringb13cfd172005-08-04 19:26:42 +02002928 __debugger_fault_handler = xmon_fault_handler;
2929 } else {
2930 __debugger = NULL;
2931 __debugger_ipi = NULL;
2932 __debugger_bpt = NULL;
2933 __debugger_sstep = NULL;
2934 __debugger_iabr_match = NULL;
Michael Neuling9422de32012-12-20 14:06:44 +00002935 __debugger_break_match = NULL;
Olaf Heringb13cfd172005-08-04 19:26:42 +02002936 __debugger_fault_handler = NULL;
2937 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002938}
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002939
2940#ifdef CONFIG_MAGIC_SYSRQ
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07002941static void sysrq_handle_xmon(int key)
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002942{
2943 /* ensure xmon is enabled */
2944 xmon_init(1);
David Howells7d12e782006-10-05 14:55:46 +01002945 debugger(get_irq_regs());
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002946}
2947
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07002948static struct sysrq_key_op sysrq_xmon_op = {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002949 .handler = sysrq_handle_xmon,
2950 .help_msg = "Xmon",
2951 .action_msg = "Entering xmon",
2952};
2953
2954static int __init setup_xmon_sysrq(void)
2955{
2956 register_sysrq_key('x', &sysrq_xmon_op);
2957 return 0;
2958}
2959__initcall(setup_xmon_sysrq);
2960#endif /* CONFIG_MAGIC_SYSRQ */
Michael Ellerman476792832006-10-03 14:12:08 +10002961
Olaf Heringf5e6a282007-06-24 16:57:08 +10002962static int __initdata xmon_early, xmon_off;
Michael Ellerman476792832006-10-03 14:12:08 +10002963
2964static int __init early_parse_xmon(char *p)
2965{
2966 if (!p || strncmp(p, "early", 5) == 0) {
2967 /* just "xmon" is equivalent to "xmon=early" */
2968 xmon_init(1);
2969 xmon_early = 1;
2970 } else if (strncmp(p, "on", 2) == 0)
2971 xmon_init(1);
2972 else if (strncmp(p, "off", 3) == 0)
2973 xmon_off = 1;
2974 else if (strncmp(p, "nobt", 4) == 0)
2975 xmon_no_auto_backtrace = 1;
2976 else
2977 return 1;
2978
2979 return 0;
2980}
2981early_param("xmon", early_parse_xmon);
2982
2983void __init xmon_setup(void)
2984{
2985#ifdef CONFIG_XMON_DEFAULT
2986 if (!xmon_off)
2987 xmon_init(1);
2988#endif
2989 if (xmon_early)
2990 debugger(NULL);
2991}
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002992
Arnd Bergmanne0555952006-11-27 19:18:55 +01002993#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002994
2995struct spu_info {
2996 struct spu *spu;
2997 u64 saved_mfc_sr1_RW;
2998 u32 saved_spu_runcntl_RW;
Michael Ellerman24a24c82006-11-23 00:46:41 +01002999 unsigned long dump_addr;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003000 u8 stopped_ok;
3001};
3002
3003#define XMON_NUM_SPUS 16 /* Enough for current hardware */
3004
3005static struct spu_info spu_info[XMON_NUM_SPUS];
3006
3007void xmon_register_spus(struct list_head *list)
3008{
3009 struct spu *spu;
3010
3011 list_for_each_entry(spu, list, full_list) {
3012 if (spu->number >= XMON_NUM_SPUS) {
3013 WARN_ON(1);
3014 continue;
3015 }
3016
3017 spu_info[spu->number].spu = spu;
3018 spu_info[spu->number].stopped_ok = 0;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003019 spu_info[spu->number].dump_addr = (unsigned long)
3020 spu_info[spu->number].spu->local_store;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003021 }
3022}
3023
3024static void stop_spus(void)
3025{
3026 struct spu *spu;
3027 int i;
3028 u64 tmp;
3029
3030 for (i = 0; i < XMON_NUM_SPUS; i++) {
3031 if (!spu_info[i].spu)
3032 continue;
3033
3034 if (setjmp(bus_error_jmp) == 0) {
3035 catch_memory_errors = 1;
3036 sync();
3037
3038 spu = spu_info[i].spu;
3039
3040 spu_info[i].saved_spu_runcntl_RW =
3041 in_be32(&spu->problem->spu_runcntl_RW);
3042
3043 tmp = spu_mfc_sr1_get(spu);
3044 spu_info[i].saved_mfc_sr1_RW = tmp;
3045
3046 tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
3047 spu_mfc_sr1_set(spu, tmp);
3048
3049 sync();
3050 __delay(200);
3051
3052 spu_info[i].stopped_ok = 1;
Michael Ellerman2a144422006-11-23 00:46:40 +01003053
3054 printf("Stopped spu %.2d (was %s)\n", i,
3055 spu_info[i].saved_spu_runcntl_RW ?
3056 "running" : "stopped");
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003057 } else {
3058 catch_memory_errors = 0;
3059 printf("*** Error stopping spu %.2d\n", i);
3060 }
3061 catch_memory_errors = 0;
3062 }
3063}
3064
3065static void restart_spus(void)
3066{
3067 struct spu *spu;
3068 int i;
3069
3070 for (i = 0; i < XMON_NUM_SPUS; i++) {
3071 if (!spu_info[i].spu)
3072 continue;
3073
3074 if (!spu_info[i].stopped_ok) {
3075 printf("*** Error, spu %d was not successfully stopped"
3076 ", not restarting\n", i);
3077 continue;
3078 }
3079
3080 if (setjmp(bus_error_jmp) == 0) {
3081 catch_memory_errors = 1;
3082 sync();
3083
3084 spu = spu_info[i].spu;
3085 spu_mfc_sr1_set(spu, spu_info[i].saved_mfc_sr1_RW);
3086 out_be32(&spu->problem->spu_runcntl_RW,
3087 spu_info[i].saved_spu_runcntl_RW);
3088
3089 sync();
3090 __delay(200);
3091
3092 printf("Restarted spu %.2d\n", i);
3093 } else {
3094 catch_memory_errors = 0;
3095 printf("*** Error restarting spu %.2d\n", i);
3096 }
3097 catch_memory_errors = 0;
3098 }
3099}
3100
Michael Ellermana8984972006-10-24 18:31:28 +02003101#define DUMP_WIDTH 23
Michael Ellerman437a0702006-11-23 00:46:39 +01003102#define DUMP_VALUE(format, field, value) \
Michael Ellermana8984972006-10-24 18:31:28 +02003103do { \
3104 if (setjmp(bus_error_jmp) == 0) { \
3105 catch_memory_errors = 1; \
3106 sync(); \
3107 printf(" %-*s = "format"\n", DUMP_WIDTH, \
Michael Ellerman437a0702006-11-23 00:46:39 +01003108 #field, value); \
Michael Ellermana8984972006-10-24 18:31:28 +02003109 sync(); \
3110 __delay(200); \
3111 } else { \
3112 catch_memory_errors = 0; \
3113 printf(" %-*s = *** Error reading field.\n", \
3114 DUMP_WIDTH, #field); \
3115 } \
3116 catch_memory_errors = 0; \
3117} while (0)
3118
Michael Ellerman437a0702006-11-23 00:46:39 +01003119#define DUMP_FIELD(obj, format, field) \
3120 DUMP_VALUE(format, field, obj->field)
3121
Michael Ellermana8984972006-10-24 18:31:28 +02003122static void dump_spu_fields(struct spu *spu)
3123{
3124 printf("Dumping spu fields at address %p:\n", spu);
3125
3126 DUMP_FIELD(spu, "0x%x", number);
3127 DUMP_FIELD(spu, "%s", name);
Michael Ellermana8984972006-10-24 18:31:28 +02003128 DUMP_FIELD(spu, "0x%lx", local_store_phys);
3129 DUMP_FIELD(spu, "0x%p", local_store);
3130 DUMP_FIELD(spu, "0x%lx", ls_size);
3131 DUMP_FIELD(spu, "0x%x", node);
3132 DUMP_FIELD(spu, "0x%lx", flags);
Michael Ellermana8984972006-10-24 18:31:28 +02003133 DUMP_FIELD(spu, "%d", class_0_pending);
Luke Browningf3d69e02008-04-27 18:41:55 +00003134 DUMP_FIELD(spu, "0x%lx", class_0_dar);
Luke Browningf3d69e02008-04-27 18:41:55 +00003135 DUMP_FIELD(spu, "0x%lx", class_1_dar);
3136 DUMP_FIELD(spu, "0x%lx", class_1_dsisr);
Michael Ellermana8984972006-10-24 18:31:28 +02003137 DUMP_FIELD(spu, "0x%lx", irqs[0]);
3138 DUMP_FIELD(spu, "0x%lx", irqs[1]);
3139 DUMP_FIELD(spu, "0x%lx", irqs[2]);
3140 DUMP_FIELD(spu, "0x%x", slb_replace);
3141 DUMP_FIELD(spu, "%d", pid);
Michael Ellermana8984972006-10-24 18:31:28 +02003142 DUMP_FIELD(spu, "0x%p", mm);
3143 DUMP_FIELD(spu, "0x%p", ctx);
3144 DUMP_FIELD(spu, "0x%p", rq);
3145 DUMP_FIELD(spu, "0x%p", timestamp);
3146 DUMP_FIELD(spu, "0x%lx", problem_phys);
3147 DUMP_FIELD(spu, "0x%p", problem);
Michael Ellerman437a0702006-11-23 00:46:39 +01003148 DUMP_VALUE("0x%x", problem->spu_runcntl_RW,
3149 in_be32(&spu->problem->spu_runcntl_RW));
3150 DUMP_VALUE("0x%x", problem->spu_status_R,
3151 in_be32(&spu->problem->spu_status_R));
3152 DUMP_VALUE("0x%x", problem->spu_npc_RW,
3153 in_be32(&spu->problem->spu_npc_RW));
Michael Ellermana8984972006-10-24 18:31:28 +02003154 DUMP_FIELD(spu, "0x%p", priv2);
Michael Ellermana9852392006-11-23 00:46:50 +01003155 DUMP_FIELD(spu, "0x%p", pdata);
Michael Ellermana8984972006-10-24 18:31:28 +02003156}
3157
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003158int
3159spu_inst_dump(unsigned long adr, long count, int praddr)
3160{
3161 return generic_inst_dump(adr, count, praddr, print_insn_spu);
3162}
3163
3164static void dump_spu_ls(unsigned long num, int subcmd)
Michael Ellerman24a24c82006-11-23 00:46:41 +01003165{
3166 unsigned long offset, addr, ls_addr;
3167
3168 if (setjmp(bus_error_jmp) == 0) {
3169 catch_memory_errors = 1;
3170 sync();
3171 ls_addr = (unsigned long)spu_info[num].spu->local_store;
3172 sync();
3173 __delay(200);
3174 } else {
3175 catch_memory_errors = 0;
3176 printf("*** Error: accessing spu info for spu %d\n", num);
3177 return;
3178 }
3179 catch_memory_errors = 0;
3180
3181 if (scanhex(&offset))
3182 addr = ls_addr + offset;
3183 else
3184 addr = spu_info[num].dump_addr;
3185
3186 if (addr >= ls_addr + LS_SIZE) {
3187 printf("*** Error: address outside of local store\n");
3188 return;
3189 }
3190
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003191 switch (subcmd) {
3192 case 'i':
3193 addr += spu_inst_dump(addr, 16, 1);
3194 last_cmd = "sdi\n";
3195 break;
3196 default:
3197 prdump(addr, 64);
3198 addr += 64;
3199 last_cmd = "sd\n";
3200 break;
3201 }
Michael Ellerman24a24c82006-11-23 00:46:41 +01003202
3203 spu_info[num].dump_addr = addr;
3204}
3205
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003206static int do_spu_cmd(void)
3207{
Michael Ellerman24a24c82006-11-23 00:46:41 +01003208 static unsigned long num = 0;
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003209 int cmd, subcmd = 0;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003210
3211 cmd = inchar();
3212 switch (cmd) {
3213 case 's':
3214 stop_spus();
3215 break;
3216 case 'r':
3217 restart_spus();
3218 break;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003219 case 'd':
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003220 subcmd = inchar();
3221 if (isxdigit(subcmd) || subcmd == '\n')
3222 termch = subcmd;
3223 case 'f':
Michael Ellerman24a24c82006-11-23 00:46:41 +01003224 scanhex(&num);
3225 if (num >= XMON_NUM_SPUS || !spu_info[num].spu) {
Michael Ellermana8984972006-10-24 18:31:28 +02003226 printf("*** Error: invalid spu number\n");
Michael Ellerman24a24c82006-11-23 00:46:41 +01003227 return 0;
3228 }
3229
3230 switch (cmd) {
3231 case 'f':
3232 dump_spu_fields(spu_info[num].spu);
3233 break;
3234 default:
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003235 dump_spu_ls(num, subcmd);
Michael Ellerman24a24c82006-11-23 00:46:41 +01003236 break;
3237 }
3238
Michael Ellermana8984972006-10-24 18:31:28 +02003239 break;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003240 default:
3241 return -1;
3242 }
3243
3244 return 0;
3245}
Arnd Bergmanne0555952006-11-27 19:18:55 +01003246#else /* ! CONFIG_SPU_BASE */
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003247static int do_spu_cmd(void)
3248{
3249 return -1;
3250}
3251#endif