blob: 9b49c65ee7a42f6f9d0b8dc436628c34bafb262b [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Routines providing a simple monitor for use on the PowerMac.
3 *
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11004 * Copyright (C) 1996-2005 Paul Mackerras.
Michael Ellerman476792832006-10-03 14:12:08 +10005 * Copyright (C) 2001 PPC64 Team, IBM Corp
6 * Copyrignt (C) 2006 Michael Ellerman, IBM Corp
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <linux/errno.h>
14#include <linux/sched.h>
15#include <linux/smp.h>
16#include <linux/mm.h>
17#include <linux/reboot.h>
18#include <linux/delay.h>
19#include <linux/kallsyms.h>
Michael Ellermanca5dd392012-08-23 22:09:12 +000020#include <linux/kmsg_dump.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <linux/cpumask.h>
Paul Gortmaker4b16f8e2011-07-22 18:24:23 -040022#include <linux/export.h>
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +110023#include <linux/sysrq.h>
Andrew Morton4694ca02005-11-13 16:06:50 -080024#include <linux/interrupt.h>
David Howells7d12e782006-10-05 14:55:46 +010025#include <linux/irq.h>
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -080026#include <linux/bug.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070027
28#include <asm/ptrace.h>
29#include <asm/string.h>
30#include <asm/prom.h>
31#include <asm/machdep.h>
Paul Mackerrasf78541d2005-10-28 22:53:37 +100032#include <asm/xmon.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <asm/processor.h>
34#include <asm/pgtable.h>
35#include <asm/mmu.h>
36#include <asm/mmu_context.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#include <asm/cputable.h>
38#include <asm/rtas.h>
39#include <asm/sstep.h>
Paul Mackerrasf583ffc2006-10-10 11:47:07 +100040#include <asm/irq_regs.h>
Michael Ellermanff8a8f22006-10-24 18:31:27 +020041#include <asm/spu.h>
42#include <asm/spu_priv1.h>
Michael Neulingc3b75bd2008-01-18 15:50:30 +110043#include <asm/setjmp.h>
Anton Vorontsov322b4392008-12-17 10:08:55 +000044#include <asm/reg.h>
David Howellsae3a1972012-03-28 18:30:02 +010045#include <asm/debug.h>
Paul Mackerrasf78541d2005-10-28 22:53:37 +100046
47#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -070048#include <asm/hvcall.h>
Paul Mackerrasf78541d2005-10-28 22:53:37 +100049#include <asm/paca.h>
50#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
52#include "nonstdio.h"
Michael Ellermane0426042006-11-23 00:46:45 +010053#include "dis-asm.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070054
55#define scanhex xmon_scanhex
56#define skipbl xmon_skipbl
57
58#ifdef CONFIG_SMP
Michael Ellerman1c8950f2008-05-08 14:27:17 +100059static cpumask_t cpus_in_xmon = CPU_MASK_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070060static unsigned long xmon_taken = 1;
61static int xmon_owner;
62static int xmon_gate;
63#endif /* CONFIG_SMP */
64
Anton Blanchard5be34922010-01-12 00:50:14 +000065static unsigned long in_xmon __read_mostly = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
67static unsigned long adrs;
68static int size = 1;
69#define MAX_DUMP (128 * 1024)
70static unsigned long ndump = 64;
71static unsigned long nidump = 16;
72static unsigned long ncsum = 4096;
73static int termch;
74static char tmpstr[128];
75
Linus Torvalds1da177e2005-04-16 15:20:36 -070076static long bus_error_jmp[JMP_BUF_LEN];
77static int catch_memory_errors;
78static long *xmon_fault_jmp[NR_CPUS];
Linus Torvalds1da177e2005-04-16 15:20:36 -070079
80/* Breakpoint stuff */
81struct bpt {
82 unsigned long address;
83 unsigned int instr[2];
84 atomic_t ref_count;
85 int enabled;
86 unsigned long pad;
87};
88
89/* Bits in bpt.enabled */
90#define BP_IABR_TE 1 /* IABR translation enabled */
91#define BP_IABR 2
92#define BP_TRAP 8
93#define BP_DABR 0x10
94
95#define NBPTS 256
96static struct bpt bpts[NBPTS];
97static struct bpt dabr;
98static struct bpt *iabr;
99static unsigned bpinstr = 0x7fe00008; /* trap */
100
101#define BP_NUM(bp) ((bp) - bpts + 1)
102
103/* Prototypes */
104static int cmds(struct pt_regs *);
105static int mread(unsigned long, void *, int);
106static int mwrite(unsigned long, void *, int);
107static int handle_fault(struct pt_regs *);
108static void byterev(unsigned char *, int);
109static void memex(void);
110static int bsesc(void);
111static void dump(void);
112static void prdump(unsigned long, long);
113static int ppc_inst_dump(unsigned long, long, int);
Vinay Sridharf312deb2009-05-14 23:13:07 +0000114static void dump_log_buf(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115static void backtrace(struct pt_regs *);
116static void excprint(struct pt_regs *);
117static void prregs(struct pt_regs *);
118static void memops(int);
119static void memlocate(void);
120static void memzcan(void);
121static void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned);
122int skipbl(void);
123int scanhex(unsigned long *valp);
124static void scannl(void);
125static int hexdigit(int);
126void getstring(char *, int);
127static void flush_input(void);
128static int inchar(void);
129static void take_input(char *);
130static unsigned long read_spr(int);
131static void write_spr(int, unsigned long);
132static void super_regs(void);
133static void remove_bpts(void);
134static void insert_bpts(void);
135static void remove_cpu_bpts(void);
136static void insert_cpu_bpts(void);
137static struct bpt *at_breakpoint(unsigned long pc);
138static struct bpt *in_breakpoint_table(unsigned long pc, unsigned long *offp);
139static int do_step(struct pt_regs *);
140static void bpt_cmds(void);
141static void cacheflush(void);
142static int cpu_cmd(void);
143static void csum(void);
144static void bootcmds(void);
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000145static void proccall(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146void dump_segments(void);
147static void symbol_lookup(void);
Olaf Hering26c8af52006-09-08 16:29:21 +0200148static void xmon_show_stack(unsigned long sp, unsigned long lr,
149 unsigned long pc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150static void xmon_print_symbol(unsigned long address, const char *mid,
151 const char *after);
152static const char *getvecname(unsigned long vec);
153
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200154static int do_spu_cmd(void);
155
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100156#ifdef CONFIG_44x
157static void dump_tlb_44x(void);
158#endif
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +1000159#ifdef CONFIG_PPC_BOOK3E
160static void dump_tlb_book3e(void);
161#endif
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100162
Michael Ellerman9f1067c22008-05-08 14:27:16 +1000163static int xmon_no_auto_backtrace;
Olaf Hering26c8af52006-09-08 16:29:21 +0200164
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000165extern void xmon_enter(void);
166extern void xmon_leave(void);
167
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000168#ifdef CONFIG_PPC64
169#define REG "%.16lx"
170#define REGS_PER_LINE 4
171#define LAST_VOLATILE 13
172#else
173#define REG "%.8lx"
174#define REGS_PER_LINE 8
175#define LAST_VOLATILE 12
176#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177
178#define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
179
180#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
181 || ('a' <= (c) && (c) <= 'f') \
182 || ('A' <= (c) && (c) <= 'F'))
183#define isalnum(c) (('0' <= (c) && (c) <= '9') \
184 || ('a' <= (c) && (c) <= 'z') \
185 || ('A' <= (c) && (c) <= 'Z'))
186#define isspace(c) (c == ' ' || c == '\t' || c == 10 || c == 13 || c == 0)
187
188static char *help_string = "\
189Commands:\n\
190 b show breakpoints\n\
191 bd set data breakpoint\n\
192 bi set instruction breakpoint\n\
193 bc clear breakpoint\n"
194#ifdef CONFIG_SMP
195 "\
196 c print cpus stopped in xmon\n\
197 c# try to switch to cpu number h (in hex)\n"
198#endif
199 "\
200 C checksum\n\
201 d dump bytes\n\
202 di dump instructions\n\
203 df dump float values\n\
204 dd dump double values\n\
Vinay Sridharf312deb2009-05-14 23:13:07 +0000205 dl dump the kernel log buffer\n\
Olaf Hering7e5b5932006-03-08 20:40:28 +0100206 dr dump stream of raw bytes\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 e print exception information\n\
208 f flush cache\n\
209 la lookup symbol+offset of specified address\n\
210 ls lookup address of specified symbol\n\
211 m examine/change memory\n\
212 mm move a block of memory\n\
213 ms set a block of memory\n\
214 md compare two blocks of memory\n\
215 ml locate a block of memory\n\
216 mz zero a block of memory\n\
217 mi show information about memory allocation\n\
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000218 p call a procedure\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 r print registers\n\
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200220 s single step\n"
Arnd Bergmanne0555952006-11-27 19:18:55 +0100221#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200222" ss stop execution on all spus\n\
Michael Ellermana8984972006-10-24 18:31:28 +0200223 sr restore execution on stopped spus\n\
Michael Ellerman24a24c82006-11-23 00:46:41 +0100224 sf # dump spu fields for spu # (in hex)\n\
Michael Ellermanc99176a2007-02-26 18:14:06 +0900225 sd # dump spu local store for spu # (in hex)\n\
Michael Ellermanaf89fb82006-11-23 00:46:44 +0100226 sdi # disassemble spu local store for spu # (in hex)\n"
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200227#endif
228" S print special registers\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 t print backtrace\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 x exit monitor and recover\n\
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000231 X exit monitor and dont recover\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000232#if defined(CONFIG_PPC64) && !defined(CONFIG_PPC_BOOK3E)
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000233" u dump segment table or SLB\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000234#elif defined(CONFIG_PPC_STD_MMU_32)
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000235" u dump segment registers\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000236#elif defined(CONFIG_44x) || defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100237" u dump TLB\n"
238#endif
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000239" ? help\n"
240" zr reboot\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 zh halt\n"
242;
243
244static struct pt_regs *xmon_regs;
245
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000246static inline void sync(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247{
248 asm volatile("sync; isync");
249}
250
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000251static inline void store_inst(void *p)
252{
253 asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p));
254}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000256static inline void cflush(void *p)
257{
258 asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p));
259}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000261static inline void cinval(void *p)
262{
263 asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p));
264}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265
266/*
267 * Disable surveillance (the service processor watchdog function)
268 * while we are in xmon.
269 * XXX we should re-enable it when we leave. :)
270 */
271#define SURVEILLANCE_TOKEN 9000
272
273static inline void disable_surveillance(void)
274{
275#ifdef CONFIG_PPC_PSERIES
276 /* Since this can't be a module, args should end up below 4GB. */
277 static struct rtas_args args;
278
279 /*
280 * At this point we have got all the cpus we can into
281 * xmon, so there is hopefully no other cpu calling RTAS
282 * at the moment, even though we don't take rtas.lock.
283 * If we did try to take rtas.lock there would be a
284 * real possibility of deadlock.
285 */
286 args.token = rtas_token("set-indicator");
287 if (args.token == RTAS_UNKNOWN_SERVICE)
288 return;
289 args.nargs = 3;
290 args.nret = 1;
291 args.rets = &args.args[3];
292 args.args[0] = SURVEILLANCE_TOKEN;
293 args.args[1] = 0;
294 args.args[2] = 0;
295 enter_rtas(__pa(&args));
296#endif /* CONFIG_PPC_PSERIES */
297}
298
299#ifdef CONFIG_SMP
300static int xmon_speaker;
301
302static void get_output_lock(void)
303{
304 int me = smp_processor_id() + 0x100;
305 int last_speaker = 0, prev;
306 long timeout;
307
308 if (xmon_speaker == me)
309 return;
310 for (;;) {
311 if (xmon_speaker == 0) {
312 last_speaker = cmpxchg(&xmon_speaker, 0, me);
313 if (last_speaker == 0)
314 return;
315 }
316 timeout = 10000000;
317 while (xmon_speaker == last_speaker) {
318 if (--timeout > 0)
319 continue;
320 /* hostile takeover */
321 prev = cmpxchg(&xmon_speaker, last_speaker, me);
322 if (prev == last_speaker)
323 return;
324 break;
325 }
326 }
327}
328
329static void release_output_lock(void)
330{
331 xmon_speaker = 0;
332}
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000333
334int cpus_are_in_xmon(void)
335{
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000336 return !cpumask_empty(&cpus_in_xmon);
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000337}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338#endif
339
Josh Boyerdaf8f402009-09-23 03:51:04 +0000340static inline int unrecoverable_excp(struct pt_regs *regs)
341{
Jimi Xenidis08f6d6a2011-09-29 12:05:28 +0000342#if defined(CONFIG_4xx) || defined(CONFIG_PPC_BOOK3E)
Jimi Xenidis66857b32011-09-23 05:40:46 +0000343 /* We have no MSR_RI bit on 4xx or Book3e, so we simply return false */
Josh Boyerdaf8f402009-09-23 03:51:04 +0000344 return 0;
345#else
346 return ((regs->msr & MSR_RI) == 0);
347#endif
348}
349
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000350static int xmon_core(struct pt_regs *regs, int fromipi)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351{
352 int cmd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 struct bpt *bp;
354 long recurse_jmp[JMP_BUF_LEN];
355 unsigned long offset;
Anton Blanchardf13659e2007-03-21 01:48:34 +1100356 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357#ifdef CONFIG_SMP
358 int cpu;
359 int secondary;
360 unsigned long timeout;
361#endif
362
Anton Blanchardf13659e2007-03-21 01:48:34 +1100363 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364
365 bp = in_breakpoint_table(regs->nip, &offset);
366 if (bp != NULL) {
367 regs->nip = bp->address + offset;
368 atomic_dec(&bp->ref_count);
369 }
370
371 remove_cpu_bpts();
372
373#ifdef CONFIG_SMP
374 cpu = smp_processor_id();
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000375 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 get_output_lock();
377 excprint(regs);
378 printf("cpu 0x%x: Exception %lx %s in xmon, "
379 "returning to main loop\n",
380 cpu, regs->trap, getvecname(TRAP(regs)));
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000381 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 longjmp(xmon_fault_jmp[cpu], 1);
383 }
384
385 if (setjmp(recurse_jmp) != 0) {
386 if (!in_xmon || !xmon_gate) {
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000387 get_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 printf("xmon: WARNING: bad recursive fault "
389 "on cpu 0x%x\n", cpu);
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000390 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 goto waiting;
392 }
393 secondary = !(xmon_taken && cpu == xmon_owner);
394 goto cmdloop;
395 }
396
397 xmon_fault_jmp[cpu] = recurse_jmp;
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000398 cpumask_set_cpu(cpu, &cpus_in_xmon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399
400 bp = NULL;
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000401 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 bp = at_breakpoint(regs->nip);
Josh Boyerdaf8f402009-09-23 03:51:04 +0000403 if (bp || unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 fromipi = 0;
405
406 if (!fromipi) {
407 get_output_lock();
408 excprint(regs);
409 if (bp) {
410 printf("cpu 0x%x stopped at breakpoint 0x%x (",
411 cpu, BP_NUM(bp));
412 xmon_print_symbol(regs->nip, " ", ")\n");
413 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000414 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 printf("WARNING: exception is not recoverable, "
416 "can't continue\n");
417 release_output_lock();
418 }
419
420 waiting:
421 secondary = 1;
422 while (secondary && !xmon_gate) {
423 if (in_xmon == 0) {
424 if (fromipi)
425 goto leave;
426 secondary = test_and_set_bit(0, &in_xmon);
427 }
428 barrier();
429 }
430
431 if (!secondary && !xmon_gate) {
432 /* we are the first cpu to come in */
433 /* interrupt other cpu(s) */
434 int ncpus = num_online_cpus();
435
436 xmon_owner = cpu;
437 mb();
438 if (ncpus > 1) {
Milton Millere0476372011-05-10 19:29:06 +0000439 smp_send_debugger_break();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 /* wait for other cpus to come in */
441 for (timeout = 100000000; timeout != 0; --timeout) {
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000442 if (cpumask_weight(&cpus_in_xmon) >= ncpus)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 break;
444 barrier();
445 }
446 }
447 remove_bpts();
448 disable_surveillance();
449 /* for breakpoint or single step, print the current instr. */
450 if (bp || TRAP(regs) == 0xd00)
451 ppc_inst_dump(regs->nip, 1, 0);
452 printf("enter ? for help\n");
453 mb();
454 xmon_gate = 1;
455 barrier();
456 }
457
458 cmdloop:
459 while (in_xmon) {
460 if (secondary) {
461 if (cpu == xmon_owner) {
462 if (!test_and_set_bit(0, &xmon_taken)) {
463 secondary = 0;
464 continue;
465 }
466 /* missed it */
467 while (cpu == xmon_owner)
468 barrier();
469 }
470 barrier();
471 } else {
472 cmd = cmds(regs);
473 if (cmd != 0) {
474 /* exiting xmon */
475 insert_bpts();
476 xmon_gate = 0;
477 wmb();
478 in_xmon = 0;
479 break;
480 }
481 /* have switched to some other cpu */
482 secondary = 1;
483 }
484 }
485 leave:
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000486 cpumask_clear_cpu(cpu, &cpus_in_xmon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 xmon_fault_jmp[cpu] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488#else
489 /* UP is simple... */
490 if (in_xmon) {
491 printf("Exception %lx %s in xmon, returning to main loop\n",
492 regs->trap, getvecname(TRAP(regs)));
493 longjmp(xmon_fault_jmp[0], 1);
494 }
495 if (setjmp(recurse_jmp) == 0) {
496 xmon_fault_jmp[0] = recurse_jmp;
497 in_xmon = 1;
498
499 excprint(regs);
500 bp = at_breakpoint(regs->nip);
501 if (bp) {
502 printf("Stopped at breakpoint %x (", BP_NUM(bp));
503 xmon_print_symbol(regs->nip, " ", ")\n");
504 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000505 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 printf("WARNING: exception is not recoverable, "
507 "can't continue\n");
508 remove_bpts();
509 disable_surveillance();
510 /* for breakpoint or single step, print the current instr. */
511 if (bp || TRAP(regs) == 0xd00)
512 ppc_inst_dump(regs->nip, 1, 0);
513 printf("enter ? for help\n");
514 }
515
516 cmd = cmds(regs);
517
518 insert_bpts();
519 in_xmon = 0;
520#endif
521
Josh Boyercdd39042009-10-05 04:46:05 +0000522#ifdef CONFIG_BOOKE
523 if (regs->msr & MSR_DE) {
524 bp = at_breakpoint(regs->nip);
525 if (bp != NULL) {
526 regs->nip = (unsigned long) &bp->instr[0];
527 atomic_inc(&bp->ref_count);
528 }
529 }
530#else
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000531 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 bp = at_breakpoint(regs->nip);
533 if (bp != NULL) {
534 int stepped = emulate_step(regs, bp->instr[0]);
535 if (stepped == 0) {
536 regs->nip = (unsigned long) &bp->instr[0];
537 atomic_inc(&bp->ref_count);
538 } else if (stepped < 0) {
539 printf("Couldn't single-step %s instruction\n",
540 (IS_RFID(bp->instr[0])? "rfid": "mtmsrd"));
541 }
542 }
543 }
Josh Boyercdd39042009-10-05 04:46:05 +0000544#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 insert_cpu_bpts();
546
Anton Blanchardf13659e2007-03-21 01:48:34 +1100547 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548
Paul Mackerras0a730ae2006-10-03 21:32:49 +1000549 return cmd != 'X' && cmd != EOF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550}
551
552int xmon(struct pt_regs *excp)
553{
554 struct pt_regs regs;
555
556 if (excp == NULL) {
Anton Vorontsov322b4392008-12-17 10:08:55 +0000557 ppc_save_regs(&regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 excp = &regs;
559 }
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200560
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 return xmon_core(excp, 0);
562}
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000563EXPORT_SYMBOL(xmon);
564
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000565irqreturn_t xmon_irq(int irq, void *d)
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000566{
567 unsigned long flags;
568 local_irq_save(flags);
569 printf("Keyboard interrupt\n");
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000570 xmon(get_irq_regs());
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000571 local_irq_restore(flags);
572 return IRQ_HANDLED;
573}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000575static int xmon_bpt(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576{
577 struct bpt *bp;
578 unsigned long offset;
579
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000580 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 return 0;
582
583 /* Are we at the trap at bp->instr[1] for some bp? */
584 bp = in_breakpoint_table(regs->nip, &offset);
585 if (bp != NULL && offset == 4) {
586 regs->nip = bp->address + 4;
587 atomic_dec(&bp->ref_count);
588 return 1;
589 }
590
591 /* Are we at a breakpoint? */
592 bp = at_breakpoint(regs->nip);
593 if (!bp)
594 return 0;
595
596 xmon_core(regs, 0);
597
598 return 1;
599}
600
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000601static int xmon_sstep(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602{
603 if (user_mode(regs))
604 return 0;
605 xmon_core(regs, 0);
606 return 1;
607}
608
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000609static int xmon_dabr_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000611 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 return 0;
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000613 if (dabr.enabled == 0)
614 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 xmon_core(regs, 0);
616 return 1;
617}
618
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000619static int xmon_iabr_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000621 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 return 0;
Michael Ellerman9f1067c22008-05-08 14:27:16 +1000623 if (iabr == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 return 0;
625 xmon_core(regs, 0);
626 return 1;
627}
628
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000629static int xmon_ipi(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630{
631#ifdef CONFIG_SMP
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000632 if (in_xmon && !cpumask_test_cpu(smp_processor_id(), &cpus_in_xmon))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 xmon_core(regs, 1);
634#endif
635 return 0;
636}
637
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000638static int xmon_fault_handler(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639{
640 struct bpt *bp;
641 unsigned long offset;
642
643 if (in_xmon && catch_memory_errors)
644 handle_fault(regs); /* doesn't return */
645
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000646 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 bp = in_breakpoint_table(regs->nip, &offset);
648 if (bp != NULL) {
649 regs->nip = bp->address + offset;
650 atomic_dec(&bp->ref_count);
651 }
652 }
653
654 return 0;
655}
656
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657static struct bpt *at_breakpoint(unsigned long pc)
658{
659 int i;
660 struct bpt *bp;
661
662 bp = bpts;
663 for (i = 0; i < NBPTS; ++i, ++bp)
664 if (bp->enabled && pc == bp->address)
665 return bp;
666 return NULL;
667}
668
669static struct bpt *in_breakpoint_table(unsigned long nip, unsigned long *offp)
670{
671 unsigned long off;
672
673 off = nip - (unsigned long) bpts;
674 if (off >= sizeof(bpts))
675 return NULL;
676 off %= sizeof(struct bpt);
677 if (off != offsetof(struct bpt, instr[0])
678 && off != offsetof(struct bpt, instr[1]))
679 return NULL;
680 *offp = off - offsetof(struct bpt, instr[0]);
681 return (struct bpt *) (nip - off);
682}
683
684static struct bpt *new_breakpoint(unsigned long a)
685{
686 struct bpt *bp;
687
688 a &= ~3UL;
689 bp = at_breakpoint(a);
690 if (bp)
691 return bp;
692
693 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
694 if (!bp->enabled && atomic_read(&bp->ref_count) == 0) {
695 bp->address = a;
696 bp->instr[1] = bpinstr;
697 store_inst(&bp->instr[1]);
698 return bp;
699 }
700 }
701
702 printf("Sorry, no free breakpoints. Please clear one first.\n");
703 return NULL;
704}
705
706static void insert_bpts(void)
707{
708 int i;
709 struct bpt *bp;
710
711 bp = bpts;
712 for (i = 0; i < NBPTS; ++i, ++bp) {
713 if ((bp->enabled & (BP_TRAP|BP_IABR)) == 0)
714 continue;
715 if (mread(bp->address, &bp->instr[0], 4) != 4) {
716 printf("Couldn't read instruction at %lx, "
717 "disabling breakpoint there\n", bp->address);
718 bp->enabled = 0;
719 continue;
720 }
721 if (IS_MTMSRD(bp->instr[0]) || IS_RFID(bp->instr[0])) {
722 printf("Breakpoint at %lx is on an mtmsrd or rfid "
723 "instruction, disabling it\n", bp->address);
724 bp->enabled = 0;
725 continue;
726 }
727 store_inst(&bp->instr[0]);
728 if (bp->enabled & BP_IABR)
729 continue;
730 if (mwrite(bp->address, &bpinstr, 4) != 4) {
731 printf("Couldn't write instruction at %lx, "
732 "disabling breakpoint there\n", bp->address);
733 bp->enabled &= ~BP_TRAP;
734 continue;
735 }
736 store_inst((void *)bp->address);
737 }
738}
739
740static void insert_cpu_bpts(void)
741{
742 if (dabr.enabled)
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000743 set_dabr(dabr.address | (dabr.enabled & 7));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 if (iabr && cpu_has_feature(CPU_FTR_IABR))
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000745 mtspr(SPRN_IABR, iabr->address
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 | (iabr->enabled & (BP_IABR|BP_IABR_TE)));
747}
748
749static void remove_bpts(void)
750{
751 int i;
752 struct bpt *bp;
753 unsigned instr;
754
755 bp = bpts;
756 for (i = 0; i < NBPTS; ++i, ++bp) {
757 if ((bp->enabled & (BP_TRAP|BP_IABR)) != BP_TRAP)
758 continue;
759 if (mread(bp->address, &instr, 4) == 4
760 && instr == bpinstr
761 && mwrite(bp->address, &bp->instr, 4) != 4)
762 printf("Couldn't remove breakpoint at %lx\n",
763 bp->address);
764 else
765 store_inst((void *)bp->address);
766 }
767}
768
769static void remove_cpu_bpts(void)
770{
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000771 set_dabr(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 if (cpu_has_feature(CPU_FTR_IABR))
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000773 mtspr(SPRN_IABR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774}
775
776/* Command interpreting routine */
777static char *last_cmd;
778
779static int
780cmds(struct pt_regs *excp)
781{
782 int cmd = 0;
783
784 last_cmd = NULL;
785 xmon_regs = excp;
Olaf Hering26c8af52006-09-08 16:29:21 +0200786
787 if (!xmon_no_auto_backtrace) {
788 xmon_no_auto_backtrace = 1;
789 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
790 }
791
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 for(;;) {
793#ifdef CONFIG_SMP
794 printf("%x:", smp_processor_id());
795#endif /* CONFIG_SMP */
796 printf("mon> ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 flush_input();
798 termch = 0;
799 cmd = skipbl();
800 if( cmd == '\n' ) {
801 if (last_cmd == NULL)
802 continue;
803 take_input(last_cmd);
804 last_cmd = NULL;
805 cmd = inchar();
806 }
807 switch (cmd) {
808 case 'm':
809 cmd = inchar();
810 switch (cmd) {
811 case 'm':
812 case 's':
813 case 'd':
814 memops(cmd);
815 break;
816 case 'l':
817 memlocate();
818 break;
819 case 'z':
820 memzcan();
821 break;
822 case 'i':
David Rientjesb2b755b2011-03-24 15:18:15 -0700823 show_mem(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 break;
825 default:
826 termch = cmd;
827 memex();
828 }
829 break;
830 case 'd':
831 dump();
832 break;
833 case 'l':
834 symbol_lookup();
835 break;
836 case 'r':
837 prregs(excp); /* print regs */
838 break;
839 case 'e':
840 excprint(excp);
841 break;
842 case 'S':
843 super_regs();
844 break;
845 case 't':
846 backtrace(excp);
847 break;
848 case 'f':
849 cacheflush();
850 break;
851 case 's':
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200852 if (do_spu_cmd() == 0)
853 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 if (do_step(excp))
855 return cmd;
856 break;
857 case 'x':
858 case 'X':
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100859 return cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 case EOF:
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100861 printf(" <no input ...>\n");
862 mdelay(2000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 return cmd;
864 case '?':
Ishizaki Kou4d404ed2007-07-18 19:26:40 +1000865 xmon_puts(help_string);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 case 'b':
868 bpt_cmds();
869 break;
870 case 'C':
871 csum();
872 break;
873 case 'c':
874 if (cpu_cmd())
875 return 0;
876 break;
877 case 'z':
878 bootcmds();
879 break;
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000880 case 'p':
881 proccall();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 break;
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000883#ifdef CONFIG_PPC_STD_MMU
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 case 'u':
885 dump_segments();
886 break;
Jimi Xenidis79873e82011-09-29 11:25:10 +0000887#elif defined(CONFIG_4xx)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100888 case 'u':
889 dump_tlb_44x();
890 break;
Jimi Xenidis79873e82011-09-29 11:25:10 +0000891#elif defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +1000892 case 'u':
893 dump_tlb_book3e();
894 break;
895#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 default:
897 printf("Unrecognized command: ");
Michael Ellermane3bc8042012-08-23 22:09:13 +0000898 do {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 if (' ' < cmd && cmd <= '~')
900 putchar(cmd);
901 else
902 printf("\\x%x", cmd);
903 cmd = inchar();
Michael Ellermane3bc8042012-08-23 22:09:13 +0000904 } while (cmd != '\n');
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 printf(" (type ? for help)\n");
906 break;
907 }
908 }
909}
910
Josh Boyercdd39042009-10-05 04:46:05 +0000911#ifdef CONFIG_BOOKE
912static int do_step(struct pt_regs *regs)
913{
914 regs->msr |= MSR_DE;
915 mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
916 return 1;
917}
918#else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919/*
920 * Step a single instruction.
921 * Some instructions we emulate, others we execute with MSR_SE set.
922 */
923static int do_step(struct pt_regs *regs)
924{
925 unsigned int instr;
926 int stepped;
927
928 /* check we are in 64-bit kernel mode, translation enabled */
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000929 if ((regs->msr & (MSR_64BIT|MSR_PR|MSR_IR)) == (MSR_64BIT|MSR_IR)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 if (mread(regs->nip, &instr, 4) == 4) {
931 stepped = emulate_step(regs, instr);
932 if (stepped < 0) {
933 printf("Couldn't single-step %s instruction\n",
934 (IS_RFID(instr)? "rfid": "mtmsrd"));
935 return 0;
936 }
937 if (stepped > 0) {
938 regs->trap = 0xd00 | (regs->trap & 1);
939 printf("stepped to ");
940 xmon_print_symbol(regs->nip, " ", "\n");
941 ppc_inst_dump(regs->nip, 1, 0);
942 return 0;
943 }
944 }
945 }
946 regs->msr |= MSR_SE;
947 return 1;
948}
Josh Boyercdd39042009-10-05 04:46:05 +0000949#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950
951static void bootcmds(void)
952{
953 int cmd;
954
955 cmd = inchar();
956 if (cmd == 'r')
957 ppc_md.restart(NULL);
958 else if (cmd == 'h')
959 ppc_md.halt();
960 else if (cmd == 'p')
961 ppc_md.power_off();
962}
963
964static int cpu_cmd(void)
965{
966#ifdef CONFIG_SMP
967 unsigned long cpu;
968 int timeout;
969 int count;
970
971 if (!scanhex(&cpu)) {
972 /* print cpus waiting or in xmon */
973 printf("cpus stopped:");
974 count = 0;
Anton Blanchardbc1d7702012-06-28 19:28:57 +0000975 for_each_possible_cpu(cpu) {
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000976 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 if (count == 0)
978 printf(" %x", cpu);
979 ++count;
980 } else {
981 if (count > 1)
982 printf("-%x", cpu - 1);
983 count = 0;
984 }
985 }
986 if (count > 1)
987 printf("-%x", NR_CPUS - 1);
988 printf("\n");
989 return 0;
990 }
991 /* try to switch to cpu specified */
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000992 if (!cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 printf("cpu 0x%x isn't in xmon\n", cpu);
994 return 0;
995 }
996 xmon_taken = 0;
997 mb();
998 xmon_owner = cpu;
999 timeout = 10000000;
1000 while (!xmon_taken) {
1001 if (--timeout == 0) {
1002 if (test_and_set_bit(0, &xmon_taken))
1003 break;
1004 /* take control back */
1005 mb();
1006 xmon_owner = smp_processor_id();
1007 printf("cpu %u didn't take control\n", cpu);
1008 return 0;
1009 }
1010 barrier();
1011 }
1012 return 1;
1013#else
1014 return 0;
1015#endif /* CONFIG_SMP */
1016}
1017
1018static unsigned short fcstab[256] = {
1019 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
1020 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
1021 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
1022 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
1023 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
1024 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
1025 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
1026 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
1027 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
1028 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
1029 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
1030 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
1031 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
1032 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
1033 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
1034 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
1035 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
1036 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
1037 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
1038 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
1039 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
1040 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
1041 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
1042 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
1043 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
1044 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
1045 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
1046 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
1047 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
1048 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
1049 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
1050 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
1051};
1052
1053#define FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
1054
1055static void
1056csum(void)
1057{
1058 unsigned int i;
1059 unsigned short fcs;
1060 unsigned char v;
1061
1062 if (!scanhex(&adrs))
1063 return;
1064 if (!scanhex(&ncsum))
1065 return;
1066 fcs = 0xffff;
1067 for (i = 0; i < ncsum; ++i) {
1068 if (mread(adrs+i, &v, 1) == 0) {
1069 printf("csum stopped at %x\n", adrs+i);
1070 break;
1071 }
1072 fcs = FCS(fcs, v);
1073 }
1074 printf("%x\n", fcs);
1075}
1076
1077/*
1078 * Check if this is a suitable place to put a breakpoint.
1079 */
1080static long check_bp_loc(unsigned long addr)
1081{
1082 unsigned int instr;
1083
1084 addr &= ~3;
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001085 if (!is_kernel_addr(addr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 printf("Breakpoints may only be placed at kernel addresses\n");
1087 return 0;
1088 }
1089 if (!mread(addr, &instr, sizeof(instr))) {
1090 printf("Can't read instruction at address %lx\n", addr);
1091 return 0;
1092 }
1093 if (IS_MTMSRD(instr) || IS_RFID(instr)) {
1094 printf("Breakpoints may not be placed on mtmsrd or rfid "
1095 "instructions\n");
1096 return 0;
1097 }
1098 return 1;
1099}
1100
Michael Ellermane3bc8042012-08-23 22:09:13 +00001101static char *breakpoint_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 "Breakpoint command usage:\n"
1103 "b show breakpoints\n"
1104 "b <addr> [cnt] set breakpoint at given instr addr\n"
1105 "bc clear all breakpoints\n"
1106 "bc <n/addr> clear breakpoint number n or at addr\n"
1107 "bi <addr> [cnt] set hardware instr breakpoint (POWER3/RS64 only)\n"
1108 "bd <addr> [cnt] set hardware data breakpoint\n"
1109 "";
1110
1111static void
1112bpt_cmds(void)
1113{
1114 int cmd;
1115 unsigned long a;
1116 int mode, i;
1117 struct bpt *bp;
1118 const char badaddr[] = "Only kernel addresses are permitted "
1119 "for breakpoints\n";
1120
1121 cmd = inchar();
1122 switch (cmd) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001123#ifndef CONFIG_8xx
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 case 'd': /* bd - hardware data breakpoint */
1125 mode = 7;
1126 cmd = inchar();
1127 if (cmd == 'r')
1128 mode = 5;
1129 else if (cmd == 'w')
1130 mode = 6;
1131 else
1132 termch = cmd;
1133 dabr.address = 0;
1134 dabr.enabled = 0;
1135 if (scanhex(&dabr.address)) {
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001136 if (!is_kernel_addr(dabr.address)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 printf(badaddr);
1138 break;
1139 }
1140 dabr.address &= ~7;
1141 dabr.enabled = mode | BP_DABR;
1142 }
1143 break;
1144
1145 case 'i': /* bi - hardware instr breakpoint */
1146 if (!cpu_has_feature(CPU_FTR_IABR)) {
1147 printf("Hardware instruction breakpoint "
1148 "not supported on this cpu\n");
1149 break;
1150 }
1151 if (iabr) {
1152 iabr->enabled &= ~(BP_IABR | BP_IABR_TE);
1153 iabr = NULL;
1154 }
1155 if (!scanhex(&a))
1156 break;
1157 if (!check_bp_loc(a))
1158 break;
1159 bp = new_breakpoint(a);
1160 if (bp != NULL) {
1161 bp->enabled |= BP_IABR | BP_IABR_TE;
1162 iabr = bp;
1163 }
1164 break;
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001165#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166
1167 case 'c':
1168 if (!scanhex(&a)) {
1169 /* clear all breakpoints */
1170 for (i = 0; i < NBPTS; ++i)
1171 bpts[i].enabled = 0;
1172 iabr = NULL;
1173 dabr.enabled = 0;
1174 printf("All breakpoints cleared\n");
1175 break;
1176 }
1177
1178 if (a <= NBPTS && a >= 1) {
1179 /* assume a breakpoint number */
1180 bp = &bpts[a-1]; /* bp nums are 1 based */
1181 } else {
1182 /* assume a breakpoint address */
1183 bp = at_breakpoint(a);
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001184 if (bp == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 printf("No breakpoint at %x\n", a);
1186 break;
1187 }
1188 }
1189
1190 printf("Cleared breakpoint %x (", BP_NUM(bp));
1191 xmon_print_symbol(bp->address, " ", ")\n");
1192 bp->enabled = 0;
1193 break;
1194
1195 default:
1196 termch = cmd;
Michael Ellermane3bc8042012-08-23 22:09:13 +00001197 cmd = skipbl();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198 if (cmd == '?') {
1199 printf(breakpoint_help_string);
1200 break;
1201 }
1202 termch = cmd;
1203 if (!scanhex(&a)) {
1204 /* print all breakpoints */
1205 printf(" type address\n");
1206 if (dabr.enabled) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001207 printf(" data "REG" [", dabr.address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 if (dabr.enabled & 1)
1209 printf("r");
1210 if (dabr.enabled & 2)
1211 printf("w");
1212 printf("]\n");
1213 }
1214 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
1215 if (!bp->enabled)
1216 continue;
1217 printf("%2x %s ", BP_NUM(bp),
1218 (bp->enabled & BP_IABR)? "inst": "trap");
1219 xmon_print_symbol(bp->address, " ", "\n");
1220 }
1221 break;
1222 }
1223
1224 if (!check_bp_loc(a))
1225 break;
1226 bp = new_breakpoint(a);
1227 if (bp != NULL)
1228 bp->enabled |= BP_TRAP;
1229 break;
1230 }
1231}
1232
1233/* Very cheap human name for vector lookup. */
1234static
1235const char *getvecname(unsigned long vec)
1236{
1237 char *ret;
1238
1239 switch (vec) {
1240 case 0x100: ret = "(System Reset)"; break;
1241 case 0x200: ret = "(Machine Check)"; break;
1242 case 0x300: ret = "(Data Access)"; break;
1243 case 0x380: ret = "(Data SLB Access)"; break;
1244 case 0x400: ret = "(Instruction Access)"; break;
1245 case 0x480: ret = "(Instruction SLB Access)"; break;
1246 case 0x500: ret = "(Hardware Interrupt)"; break;
1247 case 0x600: ret = "(Alignment)"; break;
1248 case 0x700: ret = "(Program Check)"; break;
1249 case 0x800: ret = "(FPU Unavailable)"; break;
1250 case 0x900: ret = "(Decrementer)"; break;
1251 case 0xc00: ret = "(System Call)"; break;
1252 case 0xd00: ret = "(Single Step)"; break;
1253 case 0xf00: ret = "(Performance Monitor)"; break;
1254 case 0xf20: ret = "(Altivec Unavailable)"; break;
1255 case 0x1300: ret = "(Instruction Breakpoint)"; break;
1256 default: ret = "";
1257 }
1258 return ret;
1259}
1260
1261static void get_function_bounds(unsigned long pc, unsigned long *startp,
1262 unsigned long *endp)
1263{
1264 unsigned long size, offset;
1265 const char *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266
1267 *startp = *endp = 0;
1268 if (pc == 0)
1269 return;
1270 if (setjmp(bus_error_jmp) == 0) {
1271 catch_memory_errors = 1;
1272 sync();
Alexey Dobriyanffb45122007-05-08 00:28:41 -07001273 name = kallsyms_lookup(pc, &size, &offset, NULL, tmpstr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 if (name != NULL) {
1275 *startp = pc - offset;
1276 *endp = pc - offset + size;
1277 }
1278 sync();
1279 }
1280 catch_memory_errors = 0;
1281}
1282
1283static int xmon_depth_to_print = 64;
1284
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001285#define LRSAVE_OFFSET (STACK_FRAME_LR_SAVE * sizeof(unsigned long))
1286#define MARKER_OFFSET (STACK_FRAME_MARKER * sizeof(unsigned long))
1287
1288#ifdef __powerpc64__
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001289#define REGS_OFFSET 0x70
1290#else
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001291#define REGS_OFFSET 16
1292#endif
1293
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294static void xmon_show_stack(unsigned long sp, unsigned long lr,
1295 unsigned long pc)
1296{
1297 unsigned long ip;
1298 unsigned long newsp;
1299 unsigned long marker;
1300 int count = 0;
1301 struct pt_regs regs;
1302
1303 do {
1304 if (sp < PAGE_OFFSET) {
1305 if (sp != 0)
1306 printf("SP (%lx) is in userspace\n", sp);
1307 break;
1308 }
1309
Paul Mackerrasf78541d2005-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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-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) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001357 if (mread(sp + REGS_OFFSET, &regs, sizeof(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 != sizeof(regs)) {
1359 printf("Couldn't read registers at %lx\n",
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001360 sp + REGS_OFFSET);
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;
1374 } while (count++ < xmon_depth_to_print);
1375}
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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-10-28 22:53:37 +10001674 *(u16 *)q = *(u16 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675 break;
1676 case 4:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001677 *(u32 *)q = *(u32 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678 break;
1679 case 8:
Paul Mackerrasf78541d2005-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 Mackerrasf78541d2005-10-28 22:53:37 +10001711 *(u16 *)p = *(u16 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712 break;
1713 case 4:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001714 *(u32 *)p = *(u32 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 break;
1716 case 8:
Paul Mackerrasf78541d2005-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 Mackerrasf78541d2005-10-28 22:53:37 +10001737static int fault_except;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738static char *fault_chars[] = { "--", "**", "##" };
1739
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001740static int handle_fault(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741{
Paul Mackerrasf78541d2005-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
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
2013 || ('a' <= (c) && (c) <= 'f') \
2014 || ('A' <= (c) && (c) <= 'F'))
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002015static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016dump(void)
2017{
2018 int c;
2019
2020 c = inchar();
2021 if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
2022 termch = c;
2023 scanhex((void *)&adrs);
2024 if (termch != '\n')
2025 termch = 0;
2026 if (c == 'i') {
2027 scanhex(&nidump);
2028 if (nidump == 0)
2029 nidump = 16;
2030 else if (nidump > MAX_DUMP)
2031 nidump = MAX_DUMP;
2032 adrs += ppc_inst_dump(adrs, nidump, 1);
2033 last_cmd = "di\n";
Vinay Sridharf312deb2009-05-14 23:13:07 +00002034 } else if (c == 'l') {
2035 dump_log_buf();
Olaf Hering7e5b5932006-03-08 20:40:28 +01002036 } else if (c == 'r') {
2037 scanhex(&ndump);
2038 if (ndump == 0)
2039 ndump = 64;
2040 xmon_rawdump(adrs, ndump);
2041 adrs += ndump;
2042 last_cmd = "dr\n";
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043 } else {
2044 scanhex(&ndump);
2045 if (ndump == 0)
2046 ndump = 64;
2047 else if (ndump > MAX_DUMP)
2048 ndump = MAX_DUMP;
2049 prdump(adrs, ndump);
2050 adrs += ndump;
2051 last_cmd = "d\n";
2052 }
2053}
2054
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002055static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056prdump(unsigned long adrs, long ndump)
2057{
2058 long n, m, c, r, nr;
2059 unsigned char temp[16];
2060
2061 for (n = ndump; n > 0;) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002062 printf(REG, adrs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063 putchar(' ');
2064 r = n < 16? n: 16;
2065 nr = mread(adrs, temp, r);
2066 adrs += nr;
2067 for (m = 0; m < r; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002068 if ((m & (sizeof(long) - 1)) == 0 && m > 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002069 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070 if (m < nr)
2071 printf("%.2x", temp[m]);
2072 else
2073 printf("%s", fault_chars[fault_type]);
2074 }
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002075 for (; m < 16; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002076 if ((m & (sizeof(long) - 1)) == 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002077 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078 printf(" ");
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002079 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080 printf(" |");
2081 for (m = 0; m < r; ++m) {
2082 if (m < nr) {
2083 c = temp[m];
2084 putchar(' ' <= c && c <= '~'? c: '.');
2085 } else
2086 putchar(' ');
2087 }
2088 n -= r;
2089 for (; m < 16; ++m)
2090 putchar(' ');
2091 printf("|\n");
2092 if (nr < r)
2093 break;
2094 }
2095}
2096
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002097typedef int (*instruction_dump_func)(unsigned long inst, unsigned long addr);
2098
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002099static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002100generic_inst_dump(unsigned long adr, long count, int praddr,
2101 instruction_dump_func dump_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102{
2103 int nr, dotted;
2104 unsigned long first_adr;
2105 unsigned long inst, last_inst = 0;
2106 unsigned char val[4];
2107
2108 dotted = 0;
2109 for (first_adr = adr; count > 0; --count, adr += 4) {
2110 nr = mread(adr, val, 4);
2111 if (nr == 0) {
2112 if (praddr) {
2113 const char *x = fault_chars[fault_type];
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002114 printf(REG" %s%s%s%s\n", adr, x, x, x, x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115 }
2116 break;
2117 }
2118 inst = GETWORD(val);
2119 if (adr > first_adr && inst == last_inst) {
2120 if (!dotted) {
2121 printf(" ...\n");
2122 dotted = 1;
2123 }
2124 continue;
2125 }
2126 dotted = 0;
2127 last_inst = inst;
2128 if (praddr)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002129 printf(REG" %.8x", adr, inst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002130 printf("\t");
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002131 dump_func(inst, adr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002132 printf("\n");
2133 }
2134 return adr - first_adr;
2135}
2136
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002137static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002138ppc_inst_dump(unsigned long adr, long count, int praddr)
2139{
2140 return generic_inst_dump(adr, count, praddr, print_insn_powerpc);
2141}
2142
Linus Torvalds1da177e2005-04-16 15:20:36 -07002143void
2144print_address(unsigned long addr)
2145{
2146 xmon_print_symbol(addr, "\t# ", "");
2147}
2148
Vinay Sridharf312deb2009-05-14 23:13:07 +00002149void
2150dump_log_buf(void)
2151{
Michael Ellermanca5dd392012-08-23 22:09:12 +00002152 struct kmsg_dumper dumper = { .active = 1 };
2153 unsigned char buf[128];
2154 size_t len;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002155
Michael Ellermane3bc8042012-08-23 22:09:13 +00002156 if (setjmp(bus_error_jmp) != 0) {
Michael Ellermanca5dd392012-08-23 22:09:12 +00002157 printf("Error dumping printk buffer!\n");
Michael Ellermane3bc8042012-08-23 22:09:13 +00002158 return;
2159 }
Vinay Sridharf312deb2009-05-14 23:13:07 +00002160
Michael Ellermane3bc8042012-08-23 22:09:13 +00002161 catch_memory_errors = 1;
2162 sync();
Vinay Sridharf312deb2009-05-14 23:13:07 +00002163
Michael Ellermanca5dd392012-08-23 22:09:12 +00002164 kmsg_dump_rewind_nolock(&dumper);
2165 while (kmsg_dump_get_line_nolock(&dumper, false, buf, sizeof(buf), &len)) {
2166 buf[len] = '\0';
2167 printf("%s", buf);
2168 }
Vinay Sridharf312deb2009-05-14 23:13:07 +00002169
Michael Ellermane3bc8042012-08-23 22:09:13 +00002170 sync();
2171 /* wait a little while to see if we get a machine check */
2172 __delay(200);
2173 catch_memory_errors = 0;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002174}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175
2176/*
2177 * Memory operations - move, set, print differences
2178 */
2179static unsigned long mdest; /* destination address */
2180static unsigned long msrc; /* source address */
2181static unsigned long mval; /* byte value to set memory to */
2182static unsigned long mcount; /* # bytes to affect */
2183static unsigned long mdiffs; /* max # differences to print */
2184
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002185static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186memops(int cmd)
2187{
2188 scanhex((void *)&mdest);
2189 if( termch != '\n' )
2190 termch = 0;
2191 scanhex((void *)(cmd == 's'? &mval: &msrc));
2192 if( termch != '\n' )
2193 termch = 0;
2194 scanhex((void *)&mcount);
2195 switch( cmd ){
2196 case 'm':
2197 memmove((void *)mdest, (void *)msrc, mcount);
2198 break;
2199 case 's':
2200 memset((void *)mdest, mval, mcount);
2201 break;
2202 case 'd':
2203 if( termch != '\n' )
2204 termch = 0;
2205 scanhex((void *)&mdiffs);
2206 memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
2207 break;
2208 }
2209}
2210
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002211static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
2213{
2214 unsigned n, prt;
2215
2216 prt = 0;
2217 for( n = nb; n > 0; --n )
2218 if( *p1++ != *p2++ )
2219 if( ++prt <= maxpr )
2220 printf("%.16x %.2x # %.16x %.2x\n", p1 - 1,
2221 p1[-1], p2 - 1, p2[-1]);
2222 if( prt > maxpr )
2223 printf("Total of %d differences\n", prt);
2224}
2225
2226static unsigned mend;
2227static unsigned mask;
2228
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002229static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230memlocate(void)
2231{
2232 unsigned a, n;
2233 unsigned char val[4];
2234
2235 last_cmd = "ml";
2236 scanhex((void *)&mdest);
2237 if (termch != '\n') {
2238 termch = 0;
2239 scanhex((void *)&mend);
2240 if (termch != '\n') {
2241 termch = 0;
2242 scanhex((void *)&mval);
2243 mask = ~0;
2244 if (termch != '\n') termch = 0;
2245 scanhex((void *)&mask);
2246 }
2247 }
2248 n = 0;
2249 for (a = mdest; a < mend; a += 4) {
2250 if (mread(a, val, 4) == 4
2251 && ((GETWORD(val) ^ mval) & mask) == 0) {
2252 printf("%.16x: %.16x\n", a, GETWORD(val));
2253 if (++n >= 10)
2254 break;
2255 }
2256 }
2257}
2258
2259static unsigned long mskip = 0x1000;
2260static unsigned long mlim = 0xffffffff;
2261
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002262static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263memzcan(void)
2264{
2265 unsigned char v;
2266 unsigned a;
2267 int ok, ook;
2268
2269 scanhex(&mdest);
2270 if (termch != '\n') termch = 0;
2271 scanhex(&mskip);
2272 if (termch != '\n') termch = 0;
2273 scanhex(&mlim);
2274 ook = 0;
2275 for (a = mdest; a < mlim; a += mskip) {
2276 ok = mread(a, &v, 1);
2277 if (ok && !ook) {
2278 printf("%.8x .. ", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279 } else if (!ok && ook)
2280 printf("%.8x\n", a - mskip);
2281 ook = ok;
2282 if (a + mskip < a)
2283 break;
2284 }
2285 if (ook)
2286 printf("%.8x\n", a - mskip);
2287}
2288
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002289static void proccall(void)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002290{
2291 unsigned long args[8];
2292 unsigned long ret;
2293 int i;
2294 typedef unsigned long (*callfunc_t)(unsigned long, unsigned long,
2295 unsigned long, unsigned long, unsigned long,
2296 unsigned long, unsigned long, unsigned long);
2297 callfunc_t func;
2298
2299 if (!scanhex(&adrs))
2300 return;
2301 if (termch != '\n')
2302 termch = 0;
2303 for (i = 0; i < 8; ++i)
2304 args[i] = 0;
2305 for (i = 0; i < 8; ++i) {
2306 if (!scanhex(&args[i]) || termch == '\n')
2307 break;
2308 termch = 0;
2309 }
2310 func = (callfunc_t) adrs;
2311 ret = 0;
2312 if (setjmp(bus_error_jmp) == 0) {
2313 catch_memory_errors = 1;
2314 sync();
2315 ret = func(args[0], args[1], args[2], args[3],
2316 args[4], args[5], args[6], args[7]);
2317 sync();
2318 printf("return value is %x\n", ret);
2319 } else {
2320 printf("*** %x exception occurred\n", fault_except);
2321 }
2322 catch_memory_errors = 0;
2323}
2324
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325/* Input scanning routines */
2326int
2327skipbl(void)
2328{
2329 int c;
2330
2331 if( termch != 0 ){
2332 c = termch;
2333 termch = 0;
2334 } else
2335 c = inchar();
2336 while( c == ' ' || c == '\t' )
2337 c = inchar();
2338 return c;
2339}
2340
2341#define N_PTREGS 44
2342static char *regnames[N_PTREGS] = {
2343 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
2344 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
2345 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
2346 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002347 "pc", "msr", "or3", "ctr", "lr", "xer", "ccr",
2348#ifdef CONFIG_PPC64
2349 "softe",
2350#else
2351 "mq",
2352#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353 "trap", "dar", "dsisr", "res"
2354};
2355
2356int
2357scanhex(unsigned long *vp)
2358{
2359 int c, d;
2360 unsigned long v;
2361
2362 c = skipbl();
2363 if (c == '%') {
2364 /* parse register name */
2365 char regname[8];
2366 int i;
2367
2368 for (i = 0; i < sizeof(regname) - 1; ++i) {
2369 c = inchar();
2370 if (!isalnum(c)) {
2371 termch = c;
2372 break;
2373 }
2374 regname[i] = c;
2375 }
2376 regname[i] = 0;
2377 for (i = 0; i < N_PTREGS; ++i) {
2378 if (strcmp(regnames[i], regname) == 0) {
2379 if (xmon_regs == NULL) {
2380 printf("regs not available\n");
2381 return 0;
2382 }
2383 *vp = ((unsigned long *)xmon_regs)[i];
2384 return 1;
2385 }
2386 }
2387 printf("invalid register name '%%%s'\n", regname);
2388 return 0;
2389 }
2390
2391 /* skip leading "0x" if any */
2392
2393 if (c == '0') {
2394 c = inchar();
2395 if (c == 'x') {
2396 c = inchar();
2397 } else {
2398 d = hexdigit(c);
2399 if (d == EOF) {
2400 termch = c;
2401 *vp = 0;
2402 return 1;
2403 }
2404 }
2405 } else if (c == '$') {
2406 int i;
2407 for (i=0; i<63; i++) {
2408 c = inchar();
2409 if (isspace(c)) {
2410 termch = c;
2411 break;
2412 }
2413 tmpstr[i] = c;
2414 }
2415 tmpstr[i++] = 0;
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07002416 *vp = 0;
2417 if (setjmp(bus_error_jmp) == 0) {
2418 catch_memory_errors = 1;
2419 sync();
2420 *vp = kallsyms_lookup_name(tmpstr);
2421 sync();
2422 }
2423 catch_memory_errors = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424 if (!(*vp)) {
2425 printf("unknown symbol '%s'\n", tmpstr);
2426 return 0;
2427 }
2428 return 1;
2429 }
2430
2431 d = hexdigit(c);
2432 if (d == EOF) {
2433 termch = c;
2434 return 0;
2435 }
2436 v = 0;
2437 do {
2438 v = (v << 4) + d;
2439 c = inchar();
2440 d = hexdigit(c);
2441 } while (d != EOF);
2442 termch = c;
2443 *vp = v;
2444 return 1;
2445}
2446
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002447static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002448scannl(void)
2449{
2450 int c;
2451
2452 c = termch;
2453 termch = 0;
2454 while( c != '\n' )
2455 c = inchar();
2456}
2457
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002458static int hexdigit(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459{
2460 if( '0' <= c && c <= '9' )
2461 return c - '0';
2462 if( 'A' <= c && c <= 'F' )
2463 return c - ('A' - 10);
2464 if( 'a' <= c && c <= 'f' )
2465 return c - ('a' - 10);
2466 return EOF;
2467}
2468
2469void
2470getstring(char *s, int size)
2471{
2472 int c;
2473
2474 c = skipbl();
2475 do {
2476 if( size > 1 ){
2477 *s++ = c;
2478 --size;
2479 }
2480 c = inchar();
2481 } while( c != ' ' && c != '\t' && c != '\n' );
2482 termch = c;
2483 *s = 0;
2484}
2485
2486static char line[256];
2487static char *lineptr;
2488
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002489static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490flush_input(void)
2491{
2492 lineptr = NULL;
2493}
2494
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002495static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496inchar(void)
2497{
2498 if (lineptr == NULL || *lineptr == 0) {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002499 if (xmon_gets(line, sizeof(line)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500 lineptr = NULL;
2501 return EOF;
2502 }
2503 lineptr = line;
2504 }
2505 return *lineptr++;
2506}
2507
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002508static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509take_input(char *str)
2510{
2511 lineptr = str;
2512}
2513
2514
2515static void
2516symbol_lookup(void)
2517{
2518 int type = inchar();
2519 unsigned long addr;
2520 static char tmp[64];
2521
2522 switch (type) {
2523 case 'a':
2524 if (scanhex(&addr))
2525 xmon_print_symbol(addr, ": ", "\n");
2526 termch = 0;
2527 break;
2528 case 's':
2529 getstring(tmp, 64);
2530 if (setjmp(bus_error_jmp) == 0) {
2531 catch_memory_errors = 1;
2532 sync();
2533 addr = kallsyms_lookup_name(tmp);
2534 if (addr)
2535 printf("%s: %lx\n", tmp, addr);
2536 else
2537 printf("Symbol '%s' not found.\n", tmp);
2538 sync();
2539 }
2540 catch_memory_errors = 0;
2541 termch = 0;
2542 break;
2543 }
2544}
2545
2546
2547/* Print an address in numeric and symbolic form (if possible) */
2548static void xmon_print_symbol(unsigned long address, const char *mid,
2549 const char *after)
2550{
2551 char *modname;
2552 const char *name = NULL;
2553 unsigned long offset, size;
2554
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002555 printf(REG, address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556 if (setjmp(bus_error_jmp) == 0) {
2557 catch_memory_errors = 1;
2558 sync();
2559 name = kallsyms_lookup(address, &size, &offset, &modname,
2560 tmpstr);
2561 sync();
2562 /* wait a little while to see if we get a machine check */
2563 __delay(200);
2564 }
2565
2566 catch_memory_errors = 0;
2567
2568 if (name) {
2569 printf("%s%s+%#lx/%#lx", mid, name, offset, size);
2570 if (modname)
2571 printf(" [%s]", modname);
2572 }
2573 printf("%s", after);
2574}
2575
Benjamin Herrenschmidt2d27cfd2009-07-23 23:15:59 +00002576#ifdef CONFIG_PPC_BOOK3S_64
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577static void dump_slb(void)
2578{
2579 int i;
will schmidtb3b95952007-12-07 08:22:23 +11002580 unsigned long esid,vsid,valid;
2581 unsigned long llp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002582
2583 printf("SLB contents of cpu %x\n", smp_processor_id());
2584
Michael Neuling584f8b72007-12-06 17:24:48 +11002585 for (i = 0; i < mmu_slb_size; i++) {
will schmidtb3b95952007-12-07 08:22:23 +11002586 asm volatile("slbmfee %0,%1" : "=r" (esid) : "r" (i));
2587 asm volatile("slbmfev %0,%1" : "=r" (vsid) : "r" (i));
2588 valid = (esid & SLB_ESID_V);
2589 if (valid | esid | vsid) {
2590 printf("%02d %016lx %016lx", i, esid, vsid);
2591 if (valid) {
2592 llp = vsid & SLB_VSID_LLP;
2593 if (vsid & SLB_VSID_B_1T) {
2594 printf(" 1T ESID=%9lx VSID=%13lx LLP:%3lx \n",
2595 GET_ESID_1T(esid),
2596 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT_1T,
2597 llp);
2598 } else {
2599 printf(" 256M ESID=%9lx VSID=%13lx LLP:%3lx \n",
2600 GET_ESID(esid),
2601 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT,
2602 llp);
2603 }
2604 } else
2605 printf("\n");
2606 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607 }
2608}
2609
2610static void dump_stab(void)
2611{
2612 int i;
Benjamin Herrenschmidt7ac21cd2012-03-02 10:10:09 +11002613 unsigned long *tmp = (unsigned long *)local_paca->stab_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614
2615 printf("Segment table contents of cpu %x\n", smp_processor_id());
2616
2617 for (i = 0; i < PAGE_SIZE/16; i++) {
2618 unsigned long a, b;
2619
2620 a = *tmp++;
2621 b = *tmp++;
2622
2623 if (a || b) {
2624 printf("%03d %016lx ", i, a);
2625 printf("%016lx\n", b);
2626 }
2627 }
2628}
2629
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002630void dump_segments(void)
2631{
Matt Evans44ae3ab2011-04-06 19:48:50 +00002632 if (mmu_has_feature(MMU_FTR_SLB))
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002633 dump_slb();
2634 else
2635 dump_stab();
2636}
2637#endif
2638
2639#ifdef CONFIG_PPC_STD_MMU_32
2640void dump_segments(void)
2641{
2642 int i;
2643
2644 printf("sr0-15 =");
2645 for (i = 0; i < 16; ++i)
2646 printf(" %x", mfsrin(i));
2647 printf("\n");
2648}
2649#endif
2650
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11002651#ifdef CONFIG_44x
2652static void dump_tlb_44x(void)
2653{
2654 int i;
2655
2656 for (i = 0; i < PPC44x_TLB_SIZE; i++) {
2657 unsigned long w0,w1,w2;
2658 asm volatile("tlbre %0,%1,0" : "=r" (w0) : "r" (i));
2659 asm volatile("tlbre %0,%1,1" : "=r" (w1) : "r" (i));
2660 asm volatile("tlbre %0,%1,2" : "=r" (w2) : "r" (i));
2661 printf("[%02x] %08x %08x %08x ", i, w0, w1, w2);
2662 if (w0 & PPC44x_TLB_VALID) {
2663 printf("V %08x -> %01x%08x %c%c%c%c%c",
2664 w0 & PPC44x_TLB_EPN_MASK,
2665 w1 & PPC44x_TLB_ERPN_MASK,
2666 w1 & PPC44x_TLB_RPN_MASK,
2667 (w2 & PPC44x_TLB_W) ? 'W' : 'w',
2668 (w2 & PPC44x_TLB_I) ? 'I' : 'i',
2669 (w2 & PPC44x_TLB_M) ? 'M' : 'm',
2670 (w2 & PPC44x_TLB_G) ? 'G' : 'g',
2671 (w2 & PPC44x_TLB_E) ? 'E' : 'e');
2672 }
2673 printf("\n");
2674 }
2675}
2676#endif /* CONFIG_44x */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002677
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +10002678#ifdef CONFIG_PPC_BOOK3E
2679static void dump_tlb_book3e(void)
2680{
2681 u32 mmucfg, pidmask, lpidmask;
2682 u64 ramask;
2683 int i, tlb, ntlbs, pidsz, lpidsz, rasz, lrat = 0;
2684 int mmu_version;
2685 static const char *pgsz_names[] = {
2686 " 1K",
2687 " 2K",
2688 " 4K",
2689 " 8K",
2690 " 16K",
2691 " 32K",
2692 " 64K",
2693 "128K",
2694 "256K",
2695 "512K",
2696 " 1M",
2697 " 2M",
2698 " 4M",
2699 " 8M",
2700 " 16M",
2701 " 32M",
2702 " 64M",
2703 "128M",
2704 "256M",
2705 "512M",
2706 " 1G",
2707 " 2G",
2708 " 4G",
2709 " 8G",
2710 " 16G",
2711 " 32G",
2712 " 64G",
2713 "128G",
2714 "256G",
2715 "512G",
2716 " 1T",
2717 " 2T",
2718 };
2719
2720 /* Gather some infos about the MMU */
2721 mmucfg = mfspr(SPRN_MMUCFG);
2722 mmu_version = (mmucfg & 3) + 1;
2723 ntlbs = ((mmucfg >> 2) & 3) + 1;
2724 pidsz = ((mmucfg >> 6) & 0x1f) + 1;
2725 lpidsz = (mmucfg >> 24) & 0xf;
2726 rasz = (mmucfg >> 16) & 0x7f;
2727 if ((mmu_version > 1) && (mmucfg & 0x10000))
2728 lrat = 1;
2729 printf("Book3E MMU MAV=%d.0,%d TLBs,%d-bit PID,%d-bit LPID,%d-bit RA\n",
2730 mmu_version, ntlbs, pidsz, lpidsz, rasz);
2731 pidmask = (1ul << pidsz) - 1;
2732 lpidmask = (1ul << lpidsz) - 1;
2733 ramask = (1ull << rasz) - 1;
2734
2735 for (tlb = 0; tlb < ntlbs; tlb++) {
2736 u32 tlbcfg;
2737 int nent, assoc, new_cc = 1;
2738 printf("TLB %d:\n------\n", tlb);
2739 switch(tlb) {
2740 case 0:
2741 tlbcfg = mfspr(SPRN_TLB0CFG);
2742 break;
2743 case 1:
2744 tlbcfg = mfspr(SPRN_TLB1CFG);
2745 break;
2746 case 2:
2747 tlbcfg = mfspr(SPRN_TLB2CFG);
2748 break;
2749 case 3:
2750 tlbcfg = mfspr(SPRN_TLB3CFG);
2751 break;
2752 default:
2753 printf("Unsupported TLB number !\n");
2754 continue;
2755 }
2756 nent = tlbcfg & 0xfff;
2757 assoc = (tlbcfg >> 24) & 0xff;
2758 for (i = 0; i < nent; i++) {
2759 u32 mas0 = MAS0_TLBSEL(tlb);
2760 u32 mas1 = MAS1_TSIZE(BOOK3E_PAGESZ_4K);
2761 u64 mas2 = 0;
2762 u64 mas7_mas3;
2763 int esel = i, cc = i;
2764
2765 if (assoc != 0) {
2766 cc = i / assoc;
2767 esel = i % assoc;
2768 mas2 = cc * 0x1000;
2769 }
2770
2771 mas0 |= MAS0_ESEL(esel);
2772 mtspr(SPRN_MAS0, mas0);
2773 mtspr(SPRN_MAS1, mas1);
2774 mtspr(SPRN_MAS2, mas2);
2775 asm volatile("tlbre 0,0,0" : : : "memory");
2776 mas1 = mfspr(SPRN_MAS1);
2777 mas2 = mfspr(SPRN_MAS2);
2778 mas7_mas3 = mfspr(SPRN_MAS7_MAS3);
2779 if (assoc && (i % assoc) == 0)
2780 new_cc = 1;
2781 if (!(mas1 & MAS1_VALID))
2782 continue;
2783 if (assoc == 0)
2784 printf("%04x- ", i);
2785 else if (new_cc)
2786 printf("%04x-%c", cc, 'A' + esel);
2787 else
2788 printf(" |%c", 'A' + esel);
2789 new_cc = 0;
2790 printf(" %016llx %04x %s %c%c AS%c",
2791 mas2 & ~0x3ffull,
2792 (mas1 >> 16) & 0x3fff,
2793 pgsz_names[(mas1 >> 7) & 0x1f],
2794 mas1 & MAS1_IND ? 'I' : ' ',
2795 mas1 & MAS1_IPROT ? 'P' : ' ',
2796 mas1 & MAS1_TS ? '1' : '0');
2797 printf(" %c%c%c%c%c%c%c",
2798 mas2 & MAS2_X0 ? 'a' : ' ',
2799 mas2 & MAS2_X1 ? 'v' : ' ',
2800 mas2 & MAS2_W ? 'w' : ' ',
2801 mas2 & MAS2_I ? 'i' : ' ',
2802 mas2 & MAS2_M ? 'm' : ' ',
2803 mas2 & MAS2_G ? 'g' : ' ',
2804 mas2 & MAS2_E ? 'e' : ' ');
2805 printf(" %016llx", mas7_mas3 & ramask & ~0x7ffull);
2806 if (mas1 & MAS1_IND)
2807 printf(" %s\n",
2808 pgsz_names[(mas7_mas3 >> 1) & 0x1f]);
2809 else
2810 printf(" U%c%c%c S%c%c%c\n",
2811 mas7_mas3 & MAS3_UX ? 'x' : ' ',
2812 mas7_mas3 & MAS3_UW ? 'w' : ' ',
2813 mas7_mas3 & MAS3_UR ? 'r' : ' ',
2814 mas7_mas3 & MAS3_SX ? 'x' : ' ',
2815 mas7_mas3 & MAS3_SW ? 'w' : ' ',
2816 mas7_mas3 & MAS3_SR ? 'r' : ' ');
2817 }
2818 }
2819}
2820#endif /* CONFIG_PPC_BOOK3E */
2821
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002822static void xmon_init(int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823{
Olaf Heringb13cfd12005-08-04 19:26:42 +02002824 if (enable) {
2825 __debugger = xmon;
2826 __debugger_ipi = xmon_ipi;
2827 __debugger_bpt = xmon_bpt;
2828 __debugger_sstep = xmon_sstep;
2829 __debugger_iabr_match = xmon_iabr_match;
2830 __debugger_dabr_match = xmon_dabr_match;
2831 __debugger_fault_handler = xmon_fault_handler;
2832 } else {
2833 __debugger = NULL;
2834 __debugger_ipi = NULL;
2835 __debugger_bpt = NULL;
2836 __debugger_sstep = NULL;
2837 __debugger_iabr_match = NULL;
2838 __debugger_dabr_match = NULL;
2839 __debugger_fault_handler = NULL;
2840 }
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002841 xmon_map_scc();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842}
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002843
2844#ifdef CONFIG_MAGIC_SYSRQ
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07002845static void sysrq_handle_xmon(int key)
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002846{
2847 /* ensure xmon is enabled */
2848 xmon_init(1);
David Howells7d12e782006-10-05 14:55:46 +01002849 debugger(get_irq_regs());
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002850}
2851
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07002852static struct sysrq_key_op sysrq_xmon_op = {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002853 .handler = sysrq_handle_xmon,
2854 .help_msg = "Xmon",
2855 .action_msg = "Entering xmon",
2856};
2857
2858static int __init setup_xmon_sysrq(void)
2859{
2860 register_sysrq_key('x', &sysrq_xmon_op);
2861 return 0;
2862}
2863__initcall(setup_xmon_sysrq);
2864#endif /* CONFIG_MAGIC_SYSRQ */
Michael Ellerman476792832006-10-03 14:12:08 +10002865
Olaf Heringf5e6a282007-06-24 16:57:08 +10002866static int __initdata xmon_early, xmon_off;
Michael Ellerman476792832006-10-03 14:12:08 +10002867
2868static int __init early_parse_xmon(char *p)
2869{
2870 if (!p || strncmp(p, "early", 5) == 0) {
2871 /* just "xmon" is equivalent to "xmon=early" */
2872 xmon_init(1);
2873 xmon_early = 1;
2874 } else if (strncmp(p, "on", 2) == 0)
2875 xmon_init(1);
2876 else if (strncmp(p, "off", 3) == 0)
2877 xmon_off = 1;
2878 else if (strncmp(p, "nobt", 4) == 0)
2879 xmon_no_auto_backtrace = 1;
2880 else
2881 return 1;
2882
2883 return 0;
2884}
2885early_param("xmon", early_parse_xmon);
2886
2887void __init xmon_setup(void)
2888{
2889#ifdef CONFIG_XMON_DEFAULT
2890 if (!xmon_off)
2891 xmon_init(1);
2892#endif
2893 if (xmon_early)
2894 debugger(NULL);
2895}
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002896
Arnd Bergmanne0555952006-11-27 19:18:55 +01002897#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002898
2899struct spu_info {
2900 struct spu *spu;
2901 u64 saved_mfc_sr1_RW;
2902 u32 saved_spu_runcntl_RW;
Michael Ellerman24a24c82006-11-23 00:46:41 +01002903 unsigned long dump_addr;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002904 u8 stopped_ok;
2905};
2906
2907#define XMON_NUM_SPUS 16 /* Enough for current hardware */
2908
2909static struct spu_info spu_info[XMON_NUM_SPUS];
2910
2911void xmon_register_spus(struct list_head *list)
2912{
2913 struct spu *spu;
2914
2915 list_for_each_entry(spu, list, full_list) {
2916 if (spu->number >= XMON_NUM_SPUS) {
2917 WARN_ON(1);
2918 continue;
2919 }
2920
2921 spu_info[spu->number].spu = spu;
2922 spu_info[spu->number].stopped_ok = 0;
Michael Ellerman24a24c82006-11-23 00:46:41 +01002923 spu_info[spu->number].dump_addr = (unsigned long)
2924 spu_info[spu->number].spu->local_store;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002925 }
2926}
2927
2928static void stop_spus(void)
2929{
2930 struct spu *spu;
2931 int i;
2932 u64 tmp;
2933
2934 for (i = 0; i < XMON_NUM_SPUS; i++) {
2935 if (!spu_info[i].spu)
2936 continue;
2937
2938 if (setjmp(bus_error_jmp) == 0) {
2939 catch_memory_errors = 1;
2940 sync();
2941
2942 spu = spu_info[i].spu;
2943
2944 spu_info[i].saved_spu_runcntl_RW =
2945 in_be32(&spu->problem->spu_runcntl_RW);
2946
2947 tmp = spu_mfc_sr1_get(spu);
2948 spu_info[i].saved_mfc_sr1_RW = tmp;
2949
2950 tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
2951 spu_mfc_sr1_set(spu, tmp);
2952
2953 sync();
2954 __delay(200);
2955
2956 spu_info[i].stopped_ok = 1;
Michael Ellerman2a144422006-11-23 00:46:40 +01002957
2958 printf("Stopped spu %.2d (was %s)\n", i,
2959 spu_info[i].saved_spu_runcntl_RW ?
2960 "running" : "stopped");
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002961 } else {
2962 catch_memory_errors = 0;
2963 printf("*** Error stopping spu %.2d\n", i);
2964 }
2965 catch_memory_errors = 0;
2966 }
2967}
2968
2969static void restart_spus(void)
2970{
2971 struct spu *spu;
2972 int i;
2973
2974 for (i = 0; i < XMON_NUM_SPUS; i++) {
2975 if (!spu_info[i].spu)
2976 continue;
2977
2978 if (!spu_info[i].stopped_ok) {
2979 printf("*** Error, spu %d was not successfully stopped"
2980 ", not restarting\n", i);
2981 continue;
2982 }
2983
2984 if (setjmp(bus_error_jmp) == 0) {
2985 catch_memory_errors = 1;
2986 sync();
2987
2988 spu = spu_info[i].spu;
2989 spu_mfc_sr1_set(spu, spu_info[i].saved_mfc_sr1_RW);
2990 out_be32(&spu->problem->spu_runcntl_RW,
2991 spu_info[i].saved_spu_runcntl_RW);
2992
2993 sync();
2994 __delay(200);
2995
2996 printf("Restarted spu %.2d\n", i);
2997 } else {
2998 catch_memory_errors = 0;
2999 printf("*** Error restarting spu %.2d\n", i);
3000 }
3001 catch_memory_errors = 0;
3002 }
3003}
3004
Michael Ellermana8984972006-10-24 18:31:28 +02003005#define DUMP_WIDTH 23
Michael Ellerman437a0702006-11-23 00:46:39 +01003006#define DUMP_VALUE(format, field, value) \
Michael Ellermana8984972006-10-24 18:31:28 +02003007do { \
3008 if (setjmp(bus_error_jmp) == 0) { \
3009 catch_memory_errors = 1; \
3010 sync(); \
3011 printf(" %-*s = "format"\n", DUMP_WIDTH, \
Michael Ellerman437a0702006-11-23 00:46:39 +01003012 #field, value); \
Michael Ellermana8984972006-10-24 18:31:28 +02003013 sync(); \
3014 __delay(200); \
3015 } else { \
3016 catch_memory_errors = 0; \
3017 printf(" %-*s = *** Error reading field.\n", \
3018 DUMP_WIDTH, #field); \
3019 } \
3020 catch_memory_errors = 0; \
3021} while (0)
3022
Michael Ellerman437a0702006-11-23 00:46:39 +01003023#define DUMP_FIELD(obj, format, field) \
3024 DUMP_VALUE(format, field, obj->field)
3025
Michael Ellermana8984972006-10-24 18:31:28 +02003026static void dump_spu_fields(struct spu *spu)
3027{
3028 printf("Dumping spu fields at address %p:\n", spu);
3029
3030 DUMP_FIELD(spu, "0x%x", number);
3031 DUMP_FIELD(spu, "%s", name);
Michael Ellermana8984972006-10-24 18:31:28 +02003032 DUMP_FIELD(spu, "0x%lx", local_store_phys);
3033 DUMP_FIELD(spu, "0x%p", local_store);
3034 DUMP_FIELD(spu, "0x%lx", ls_size);
3035 DUMP_FIELD(spu, "0x%x", node);
3036 DUMP_FIELD(spu, "0x%lx", flags);
Michael Ellermana8984972006-10-24 18:31:28 +02003037 DUMP_FIELD(spu, "%d", class_0_pending);
Luke Browningf3d69e02008-04-27 18:41:55 +00003038 DUMP_FIELD(spu, "0x%lx", class_0_dar);
Luke Browningf3d69e02008-04-27 18:41:55 +00003039 DUMP_FIELD(spu, "0x%lx", class_1_dar);
3040 DUMP_FIELD(spu, "0x%lx", class_1_dsisr);
Michael Ellermana8984972006-10-24 18:31:28 +02003041 DUMP_FIELD(spu, "0x%lx", irqs[0]);
3042 DUMP_FIELD(spu, "0x%lx", irqs[1]);
3043 DUMP_FIELD(spu, "0x%lx", irqs[2]);
3044 DUMP_FIELD(spu, "0x%x", slb_replace);
3045 DUMP_FIELD(spu, "%d", pid);
Michael Ellermana8984972006-10-24 18:31:28 +02003046 DUMP_FIELD(spu, "0x%p", mm);
3047 DUMP_FIELD(spu, "0x%p", ctx);
3048 DUMP_FIELD(spu, "0x%p", rq);
3049 DUMP_FIELD(spu, "0x%p", timestamp);
3050 DUMP_FIELD(spu, "0x%lx", problem_phys);
3051 DUMP_FIELD(spu, "0x%p", problem);
Michael Ellerman437a0702006-11-23 00:46:39 +01003052 DUMP_VALUE("0x%x", problem->spu_runcntl_RW,
3053 in_be32(&spu->problem->spu_runcntl_RW));
3054 DUMP_VALUE("0x%x", problem->spu_status_R,
3055 in_be32(&spu->problem->spu_status_R));
3056 DUMP_VALUE("0x%x", problem->spu_npc_RW,
3057 in_be32(&spu->problem->spu_npc_RW));
Michael Ellermana8984972006-10-24 18:31:28 +02003058 DUMP_FIELD(spu, "0x%p", priv2);
Michael Ellermana9852392006-11-23 00:46:50 +01003059 DUMP_FIELD(spu, "0x%p", pdata);
Michael Ellermana8984972006-10-24 18:31:28 +02003060}
3061
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003062int
3063spu_inst_dump(unsigned long adr, long count, int praddr)
3064{
3065 return generic_inst_dump(adr, count, praddr, print_insn_spu);
3066}
3067
3068static void dump_spu_ls(unsigned long num, int subcmd)
Michael Ellerman24a24c82006-11-23 00:46:41 +01003069{
3070 unsigned long offset, addr, ls_addr;
3071
3072 if (setjmp(bus_error_jmp) == 0) {
3073 catch_memory_errors = 1;
3074 sync();
3075 ls_addr = (unsigned long)spu_info[num].spu->local_store;
3076 sync();
3077 __delay(200);
3078 } else {
3079 catch_memory_errors = 0;
3080 printf("*** Error: accessing spu info for spu %d\n", num);
3081 return;
3082 }
3083 catch_memory_errors = 0;
3084
3085 if (scanhex(&offset))
3086 addr = ls_addr + offset;
3087 else
3088 addr = spu_info[num].dump_addr;
3089
3090 if (addr >= ls_addr + LS_SIZE) {
3091 printf("*** Error: address outside of local store\n");
3092 return;
3093 }
3094
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003095 switch (subcmd) {
3096 case 'i':
3097 addr += spu_inst_dump(addr, 16, 1);
3098 last_cmd = "sdi\n";
3099 break;
3100 default:
3101 prdump(addr, 64);
3102 addr += 64;
3103 last_cmd = "sd\n";
3104 break;
3105 }
Michael Ellerman24a24c82006-11-23 00:46:41 +01003106
3107 spu_info[num].dump_addr = addr;
3108}
3109
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003110static int do_spu_cmd(void)
3111{
Michael Ellerman24a24c82006-11-23 00:46:41 +01003112 static unsigned long num = 0;
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003113 int cmd, subcmd = 0;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003114
3115 cmd = inchar();
3116 switch (cmd) {
3117 case 's':
3118 stop_spus();
3119 break;
3120 case 'r':
3121 restart_spus();
3122 break;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003123 case 'd':
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003124 subcmd = inchar();
3125 if (isxdigit(subcmd) || subcmd == '\n')
3126 termch = subcmd;
3127 case 'f':
Michael Ellerman24a24c82006-11-23 00:46:41 +01003128 scanhex(&num);
3129 if (num >= XMON_NUM_SPUS || !spu_info[num].spu) {
Michael Ellermana8984972006-10-24 18:31:28 +02003130 printf("*** Error: invalid spu number\n");
Michael Ellerman24a24c82006-11-23 00:46:41 +01003131 return 0;
3132 }
3133
3134 switch (cmd) {
3135 case 'f':
3136 dump_spu_fields(spu_info[num].spu);
3137 break;
3138 default:
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003139 dump_spu_ls(num, subcmd);
Michael Ellerman24a24c82006-11-23 00:46:41 +01003140 break;
3141 }
3142
Michael Ellermana8984972006-10-24 18:31:28 +02003143 break;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003144 default:
3145 return -1;
3146 }
3147
3148 return 0;
3149}
Arnd Bergmanne0555952006-11-27 19:18:55 +01003150#else /* ! CONFIG_SPU_BASE */
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003151static int do_spu_cmd(void)
3152{
3153 return -1;
3154}
3155#endif