blob: 1f8d2f10a432442c2419228d1e7cc4cb120020ef [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Routines providing a simple monitor for use on the PowerMac.
3 *
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11004 * Copyright (C) 1996-2005 Paul Mackerras.
Michael Ellerman476792832006-10-03 14:12:08 +10005 * Copyright (C) 2001 PPC64 Team, IBM Corp
6 * Copyrignt (C) 2006 Michael Ellerman, IBM Corp
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <linux/errno.h>
14#include <linux/sched.h>
15#include <linux/smp.h>
16#include <linux/mm.h>
17#include <linux/reboot.h>
18#include <linux/delay.h>
19#include <linux/kallsyms.h>
Michael Ellermanca5dd392012-08-23 22:09:12 +000020#include <linux/kmsg_dump.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <linux/cpumask.h>
Paul Gortmaker4b16f8e2011-07-22 18:24:23 -040022#include <linux/export.h>
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +110023#include <linux/sysrq.h>
Andrew Morton4694ca02005-11-13 16:06:50 -080024#include <linux/interrupt.h>
David Howells7d12e782006-10-05 14:55:46 +010025#include <linux/irq.h>
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -080026#include <linux/bug.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070027
28#include <asm/ptrace.h>
29#include <asm/string.h>
30#include <asm/prom.h>
31#include <asm/machdep.h>
Paul Mackerrasf78541dc2005-10-28 22:53:37 +100032#include <asm/xmon.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <asm/processor.h>
34#include <asm/pgtable.h>
35#include <asm/mmu.h>
36#include <asm/mmu_context.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#include <asm/cputable.h>
38#include <asm/rtas.h>
39#include <asm/sstep.h>
Paul Mackerrasf583ffc2006-10-10 11:47:07 +100040#include <asm/irq_regs.h>
Michael Ellermanff8a8f22006-10-24 18:31:27 +020041#include <asm/spu.h>
42#include <asm/spu_priv1.h>
Michael Neulingc3b75bd2008-01-18 15:50:30 +110043#include <asm/setjmp.h>
Anton Vorontsov322b4392008-12-17 10:08:55 +000044#include <asm/reg.h>
David Howellsae3a1972012-03-28 18:30:02 +010045#include <asm/debug.h>
Paul Mackerrasf78541dc2005-10-28 22:53:37 +100046
47#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -070048#include <asm/hvcall.h>
Paul Mackerrasf78541dc2005-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
Linus Torvalds1da177e2005-04-16 15:20:36 -070055#ifdef CONFIG_SMP
Michael Ellerman1c8950f2008-05-08 14:27:17 +100056static cpumask_t cpus_in_xmon = CPU_MASK_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070057static unsigned long xmon_taken = 1;
58static int xmon_owner;
59static int xmon_gate;
Michael Ellermanddadb6b2012-09-13 23:01:31 +000060#else
61#define xmon_owner 0
Linus Torvalds1da177e2005-04-16 15:20:36 -070062#endif /* CONFIG_SMP */
63
Anton Blanchard5be34922010-01-12 00:50:14 +000064static unsigned long in_xmon __read_mostly = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
66static unsigned long adrs;
67static int size = 1;
68#define MAX_DUMP (128 * 1024)
69static unsigned long ndump = 64;
70static unsigned long nidump = 16;
71static unsigned long ncsum = 4096;
72static int termch;
73static char tmpstr[128];
74
Linus Torvalds1da177e2005-04-16 15:20:36 -070075static long bus_error_jmp[JMP_BUF_LEN];
76static int catch_memory_errors;
77static long *xmon_fault_jmp[NR_CPUS];
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
79/* Breakpoint stuff */
80struct bpt {
81 unsigned long address;
82 unsigned int instr[2];
83 atomic_t ref_count;
84 int enabled;
85 unsigned long pad;
86};
87
88/* Bits in bpt.enabled */
89#define BP_IABR_TE 1 /* IABR translation enabled */
90#define BP_IABR 2
91#define BP_TRAP 8
92#define BP_DABR 0x10
93
94#define NBPTS 256
95static struct bpt bpts[NBPTS];
96static struct bpt dabr;
97static struct bpt *iabr;
98static unsigned bpinstr = 0x7fe00008; /* trap */
99
100#define BP_NUM(bp) ((bp) - bpts + 1)
101
102/* Prototypes */
103static int cmds(struct pt_regs *);
104static int mread(unsigned long, void *, int);
105static int mwrite(unsigned long, void *, int);
106static int handle_fault(struct pt_regs *);
107static void byterev(unsigned char *, int);
108static void memex(void);
109static int bsesc(void);
110static void dump(void);
111static void prdump(unsigned long, long);
112static int ppc_inst_dump(unsigned long, long, int);
Vinay Sridharf312deb2009-05-14 23:13:07 +0000113static void dump_log_buf(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114static void backtrace(struct pt_regs *);
115static void excprint(struct pt_regs *);
116static void prregs(struct pt_regs *);
117static void memops(int);
118static void memlocate(void);
119static void memzcan(void);
120static void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned);
121int skipbl(void);
122int scanhex(unsigned long *valp);
123static void scannl(void);
124static int hexdigit(int);
125void getstring(char *, int);
126static void flush_input(void);
127static int inchar(void);
128static void take_input(char *);
129static unsigned long read_spr(int);
130static void write_spr(int, unsigned long);
131static void super_regs(void);
132static void remove_bpts(void);
133static void insert_bpts(void);
134static void remove_cpu_bpts(void);
135static void insert_cpu_bpts(void);
136static struct bpt *at_breakpoint(unsigned long pc);
137static struct bpt *in_breakpoint_table(unsigned long pc, unsigned long *offp);
138static int do_step(struct pt_regs *);
139static void bpt_cmds(void);
140static void cacheflush(void);
141static int cpu_cmd(void);
142static void csum(void);
143static void bootcmds(void);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000144static void proccall(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145void dump_segments(void);
146static void symbol_lookup(void);
Olaf Hering26c8af52006-09-08 16:29:21 +0200147static void xmon_show_stack(unsigned long sp, unsigned long lr,
148 unsigned long pc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149static void xmon_print_symbol(unsigned long address, const char *mid,
150 const char *after);
151static const char *getvecname(unsigned long vec);
152
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200153static int do_spu_cmd(void);
154
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100155#ifdef CONFIG_44x
156static void dump_tlb_44x(void);
157#endif
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +1000158#ifdef CONFIG_PPC_BOOK3E
159static void dump_tlb_book3e(void);
160#endif
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100161
Michael Ellerman9f1067c22008-05-08 14:27:16 +1000162static int xmon_no_auto_backtrace;
Olaf Hering26c8af52006-09-08 16:29:21 +0200163
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000164extern void xmon_enter(void);
165extern void xmon_leave(void);
166
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000167#ifdef CONFIG_PPC64
168#define REG "%.16lx"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000169#else
170#define REG "%.8lx"
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000171#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172
173#define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
174
175#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
176 || ('a' <= (c) && (c) <= 'f') \
177 || ('A' <= (c) && (c) <= 'F'))
178#define isalnum(c) (('0' <= (c) && (c) <= '9') \
179 || ('a' <= (c) && (c) <= 'z') \
180 || ('A' <= (c) && (c) <= 'Z'))
181#define isspace(c) (c == ' ' || c == '\t' || c == 10 || c == 13 || c == 0)
182
183static char *help_string = "\
184Commands:\n\
185 b show breakpoints\n\
186 bd set data breakpoint\n\
187 bi set instruction breakpoint\n\
188 bc clear breakpoint\n"
189#ifdef CONFIG_SMP
190 "\
191 c print cpus stopped in xmon\n\
192 c# try to switch to cpu number h (in hex)\n"
193#endif
194 "\
195 C checksum\n\
196 d dump bytes\n\
197 di dump instructions\n\
198 df dump float values\n\
199 dd dump double values\n\
Michael Ellermanddadb6b2012-09-13 23:01:31 +0000200 dl dump the kernel log buffer\n"
201#ifdef CONFIG_PPC64
202 "\
203 dp[#] dump paca for current cpu, or cpu #\n\
204 dpa dump paca for all possible cpus\n"
205#endif
206 "\
Olaf Hering7e5b5932006-03-08 20:40:28 +0100207 dr dump stream of raw bytes\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 e print exception information\n\
209 f flush cache\n\
210 la lookup symbol+offset of specified address\n\
211 ls lookup address of specified symbol\n\
212 m examine/change memory\n\
213 mm move a block of memory\n\
214 ms set a block of memory\n\
215 md compare two blocks of memory\n\
216 ml locate a block of memory\n\
217 mz zero a block of memory\n\
218 mi show information about memory allocation\n\
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000219 p call a procedure\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 r print registers\n\
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200221 s single step\n"
Arnd Bergmanne0555952006-11-27 19:18:55 +0100222#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200223" ss stop execution on all spus\n\
Michael Ellermana8984972006-10-24 18:31:28 +0200224 sr restore execution on stopped spus\n\
Michael Ellerman24a24c82006-11-23 00:46:41 +0100225 sf # dump spu fields for spu # (in hex)\n\
Michael Ellermanc99176a2007-02-26 18:14:06 +0900226 sd # dump spu local store for spu # (in hex)\n\
Michael Ellermanaf89fb82006-11-23 00:46:44 +0100227 sdi # disassemble spu local store for spu # (in hex)\n"
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200228#endif
229" S print special registers\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 t print backtrace\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 x exit monitor and recover\n\
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000232 X exit monitor and dont recover\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000233#if defined(CONFIG_PPC64) && !defined(CONFIG_PPC_BOOK3E)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000234" u dump segment table or SLB\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000235#elif defined(CONFIG_PPC_STD_MMU_32)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000236" u dump segment registers\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000237#elif defined(CONFIG_44x) || defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100238" u dump TLB\n"
239#endif
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000240" ? help\n"
241" zr reboot\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 zh halt\n"
243;
244
245static struct pt_regs *xmon_regs;
246
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000247static inline void sync(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248{
249 asm volatile("sync; isync");
250}
251
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000252static inline void store_inst(void *p)
253{
254 asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p));
255}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000257static inline void cflush(void *p)
258{
259 asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p));
260}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000262static inline void cinval(void *p)
263{
264 asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p));
265}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266
267/*
268 * Disable surveillance (the service processor watchdog function)
269 * while we are in xmon.
270 * XXX we should re-enable it when we leave. :)
271 */
272#define SURVEILLANCE_TOKEN 9000
273
274static inline void disable_surveillance(void)
275{
276#ifdef CONFIG_PPC_PSERIES
277 /* Since this can't be a module, args should end up below 4GB. */
278 static struct rtas_args args;
279
280 /*
281 * At this point we have got all the cpus we can into
282 * xmon, so there is hopefully no other cpu calling RTAS
283 * at the moment, even though we don't take rtas.lock.
284 * If we did try to take rtas.lock there would be a
285 * real possibility of deadlock.
286 */
287 args.token = rtas_token("set-indicator");
288 if (args.token == RTAS_UNKNOWN_SERVICE)
289 return;
290 args.nargs = 3;
291 args.nret = 1;
292 args.rets = &args.args[3];
293 args.args[0] = SURVEILLANCE_TOKEN;
294 args.args[1] = 0;
295 args.args[2] = 0;
296 enter_rtas(__pa(&args));
297#endif /* CONFIG_PPC_PSERIES */
298}
299
300#ifdef CONFIG_SMP
301static int xmon_speaker;
302
303static void get_output_lock(void)
304{
305 int me = smp_processor_id() + 0x100;
306 int last_speaker = 0, prev;
307 long timeout;
308
309 if (xmon_speaker == me)
310 return;
311 for (;;) {
312 if (xmon_speaker == 0) {
313 last_speaker = cmpxchg(&xmon_speaker, 0, me);
314 if (last_speaker == 0)
315 return;
316 }
317 timeout = 10000000;
318 while (xmon_speaker == last_speaker) {
319 if (--timeout > 0)
320 continue;
321 /* hostile takeover */
322 prev = cmpxchg(&xmon_speaker, last_speaker, me);
323 if (prev == last_speaker)
324 return;
325 break;
326 }
327 }
328}
329
330static void release_output_lock(void)
331{
332 xmon_speaker = 0;
333}
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000334
335int cpus_are_in_xmon(void)
336{
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000337 return !cpumask_empty(&cpus_in_xmon);
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000338}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339#endif
340
Josh Boyerdaf8f402009-09-23 03:51:04 +0000341static inline int unrecoverable_excp(struct pt_regs *regs)
342{
Jimi Xenidis08f6d6a2011-09-29 12:05:28 +0000343#if defined(CONFIG_4xx) || defined(CONFIG_PPC_BOOK3E)
Jimi Xenidis66857b32011-09-23 05:40:46 +0000344 /* We have no MSR_RI bit on 4xx or Book3e, so we simply return false */
Josh Boyerdaf8f402009-09-23 03:51:04 +0000345 return 0;
346#else
347 return ((regs->msr & MSR_RI) == 0);
348#endif
349}
350
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000351static int xmon_core(struct pt_regs *regs, int fromipi)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352{
353 int cmd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 struct bpt *bp;
355 long recurse_jmp[JMP_BUF_LEN];
356 unsigned long offset;
Anton Blanchardf13659e2007-03-21 01:48:34 +1100357 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358#ifdef CONFIG_SMP
359 int cpu;
360 int secondary;
361 unsigned long timeout;
362#endif
363
Anton Blanchardf13659e2007-03-21 01:48:34 +1100364 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365
366 bp = in_breakpoint_table(regs->nip, &offset);
367 if (bp != NULL) {
368 regs->nip = bp->address + offset;
369 atomic_dec(&bp->ref_count);
370 }
371
372 remove_cpu_bpts();
373
374#ifdef CONFIG_SMP
375 cpu = smp_processor_id();
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000376 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 get_output_lock();
378 excprint(regs);
379 printf("cpu 0x%x: Exception %lx %s in xmon, "
380 "returning to main loop\n",
381 cpu, regs->trap, getvecname(TRAP(regs)));
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000382 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 longjmp(xmon_fault_jmp[cpu], 1);
384 }
385
386 if (setjmp(recurse_jmp) != 0) {
387 if (!in_xmon || !xmon_gate) {
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000388 get_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 printf("xmon: WARNING: bad recursive fault "
390 "on cpu 0x%x\n", cpu);
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000391 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 goto waiting;
393 }
394 secondary = !(xmon_taken && cpu == xmon_owner);
395 goto cmdloop;
396 }
397
398 xmon_fault_jmp[cpu] = recurse_jmp;
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000399 cpumask_set_cpu(cpu, &cpus_in_xmon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400
401 bp = NULL;
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000402 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 bp = at_breakpoint(regs->nip);
Josh Boyerdaf8f402009-09-23 03:51:04 +0000404 if (bp || unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 fromipi = 0;
406
407 if (!fromipi) {
408 get_output_lock();
409 excprint(regs);
410 if (bp) {
411 printf("cpu 0x%x stopped at breakpoint 0x%x (",
412 cpu, BP_NUM(bp));
413 xmon_print_symbol(regs->nip, " ", ")\n");
414 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000415 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 printf("WARNING: exception is not recoverable, "
417 "can't continue\n");
418 release_output_lock();
419 }
420
421 waiting:
422 secondary = 1;
423 while (secondary && !xmon_gate) {
424 if (in_xmon == 0) {
425 if (fromipi)
426 goto leave;
427 secondary = test_and_set_bit(0, &in_xmon);
428 }
429 barrier();
430 }
431
432 if (!secondary && !xmon_gate) {
433 /* we are the first cpu to come in */
434 /* interrupt other cpu(s) */
435 int ncpus = num_online_cpus();
436
437 xmon_owner = cpu;
438 mb();
439 if (ncpus > 1) {
Milton Millere0476372011-05-10 19:29:06 +0000440 smp_send_debugger_break();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 /* wait for other cpus to come in */
442 for (timeout = 100000000; timeout != 0; --timeout) {
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000443 if (cpumask_weight(&cpus_in_xmon) >= ncpus)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 break;
445 barrier();
446 }
447 }
448 remove_bpts();
449 disable_surveillance();
450 /* for breakpoint or single step, print the current instr. */
451 if (bp || TRAP(regs) == 0xd00)
452 ppc_inst_dump(regs->nip, 1, 0);
453 printf("enter ? for help\n");
454 mb();
455 xmon_gate = 1;
456 barrier();
457 }
458
459 cmdloop:
460 while (in_xmon) {
461 if (secondary) {
462 if (cpu == xmon_owner) {
463 if (!test_and_set_bit(0, &xmon_taken)) {
464 secondary = 0;
465 continue;
466 }
467 /* missed it */
468 while (cpu == xmon_owner)
469 barrier();
470 }
471 barrier();
472 } else {
473 cmd = cmds(regs);
474 if (cmd != 0) {
475 /* exiting xmon */
476 insert_bpts();
477 xmon_gate = 0;
478 wmb();
479 in_xmon = 0;
480 break;
481 }
482 /* have switched to some other cpu */
483 secondary = 1;
484 }
485 }
486 leave:
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000487 cpumask_clear_cpu(cpu, &cpus_in_xmon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 xmon_fault_jmp[cpu] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489#else
490 /* UP is simple... */
491 if (in_xmon) {
492 printf("Exception %lx %s in xmon, returning to main loop\n",
493 regs->trap, getvecname(TRAP(regs)));
494 longjmp(xmon_fault_jmp[0], 1);
495 }
496 if (setjmp(recurse_jmp) == 0) {
497 xmon_fault_jmp[0] = recurse_jmp;
498 in_xmon = 1;
499
500 excprint(regs);
501 bp = at_breakpoint(regs->nip);
502 if (bp) {
503 printf("Stopped at breakpoint %x (", BP_NUM(bp));
504 xmon_print_symbol(regs->nip, " ", ")\n");
505 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000506 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 printf("WARNING: exception is not recoverable, "
508 "can't continue\n");
509 remove_bpts();
510 disable_surveillance();
511 /* for breakpoint or single step, print the current instr. */
512 if (bp || TRAP(regs) == 0xd00)
513 ppc_inst_dump(regs->nip, 1, 0);
514 printf("enter ? for help\n");
515 }
516
517 cmd = cmds(regs);
518
519 insert_bpts();
520 in_xmon = 0;
521#endif
522
Josh Boyercdd39042009-10-05 04:46:05 +0000523#ifdef CONFIG_BOOKE
524 if (regs->msr & MSR_DE) {
525 bp = at_breakpoint(regs->nip);
526 if (bp != NULL) {
527 regs->nip = (unsigned long) &bp->instr[0];
528 atomic_inc(&bp->ref_count);
529 }
530 }
531#else
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000532 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 bp = at_breakpoint(regs->nip);
534 if (bp != NULL) {
535 int stepped = emulate_step(regs, bp->instr[0]);
536 if (stepped == 0) {
537 regs->nip = (unsigned long) &bp->instr[0];
538 atomic_inc(&bp->ref_count);
539 } else if (stepped < 0) {
540 printf("Couldn't single-step %s instruction\n",
541 (IS_RFID(bp->instr[0])? "rfid": "mtmsrd"));
542 }
543 }
544 }
Josh Boyercdd39042009-10-05 04:46:05 +0000545#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 insert_cpu_bpts();
547
Anton Blanchardf13659e2007-03-21 01:48:34 +1100548 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549
Paul Mackerras0a730ae2006-10-03 21:32:49 +1000550 return cmd != 'X' && cmd != EOF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551}
552
553int xmon(struct pt_regs *excp)
554{
555 struct pt_regs regs;
556
557 if (excp == NULL) {
Anton Vorontsov322b4392008-12-17 10:08:55 +0000558 ppc_save_regs(&regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 excp = &regs;
560 }
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200561
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 return xmon_core(excp, 0);
563}
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000564EXPORT_SYMBOL(xmon);
565
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000566irqreturn_t xmon_irq(int irq, void *d)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000567{
568 unsigned long flags;
569 local_irq_save(flags);
570 printf("Keyboard interrupt\n");
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000571 xmon(get_irq_regs());
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000572 local_irq_restore(flags);
573 return IRQ_HANDLED;
574}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000576static int xmon_bpt(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577{
578 struct bpt *bp;
579 unsigned long offset;
580
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000581 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 return 0;
583
584 /* Are we at the trap at bp->instr[1] for some bp? */
585 bp = in_breakpoint_table(regs->nip, &offset);
586 if (bp != NULL && offset == 4) {
587 regs->nip = bp->address + 4;
588 atomic_dec(&bp->ref_count);
589 return 1;
590 }
591
592 /* Are we at a breakpoint? */
593 bp = at_breakpoint(regs->nip);
594 if (!bp)
595 return 0;
596
597 xmon_core(regs, 0);
598
599 return 1;
600}
601
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000602static int xmon_sstep(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603{
604 if (user_mode(regs))
605 return 0;
606 xmon_core(regs, 0);
607 return 1;
608}
609
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000610static int xmon_dabr_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000612 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 return 0;
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000614 if (dabr.enabled == 0)
615 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 xmon_core(regs, 0);
617 return 1;
618}
619
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000620static int xmon_iabr_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000622 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 return 0;
Michael Ellerman9f1067c22008-05-08 14:27:16 +1000624 if (iabr == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 return 0;
626 xmon_core(regs, 0);
627 return 1;
628}
629
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000630static int xmon_ipi(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631{
632#ifdef CONFIG_SMP
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000633 if (in_xmon && !cpumask_test_cpu(smp_processor_id(), &cpus_in_xmon))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 xmon_core(regs, 1);
635#endif
636 return 0;
637}
638
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000639static int xmon_fault_handler(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640{
641 struct bpt *bp;
642 unsigned long offset;
643
644 if (in_xmon && catch_memory_errors)
645 handle_fault(regs); /* doesn't return */
646
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000647 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 bp = in_breakpoint_table(regs->nip, &offset);
649 if (bp != NULL) {
650 regs->nip = bp->address + offset;
651 atomic_dec(&bp->ref_count);
652 }
653 }
654
655 return 0;
656}
657
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658static struct bpt *at_breakpoint(unsigned long pc)
659{
660 int i;
661 struct bpt *bp;
662
663 bp = bpts;
664 for (i = 0; i < NBPTS; ++i, ++bp)
665 if (bp->enabled && pc == bp->address)
666 return bp;
667 return NULL;
668}
669
670static struct bpt *in_breakpoint_table(unsigned long nip, unsigned long *offp)
671{
672 unsigned long off;
673
674 off = nip - (unsigned long) bpts;
675 if (off >= sizeof(bpts))
676 return NULL;
677 off %= sizeof(struct bpt);
678 if (off != offsetof(struct bpt, instr[0])
679 && off != offsetof(struct bpt, instr[1]))
680 return NULL;
681 *offp = off - offsetof(struct bpt, instr[0]);
682 return (struct bpt *) (nip - off);
683}
684
685static struct bpt *new_breakpoint(unsigned long a)
686{
687 struct bpt *bp;
688
689 a &= ~3UL;
690 bp = at_breakpoint(a);
691 if (bp)
692 return bp;
693
694 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
695 if (!bp->enabled && atomic_read(&bp->ref_count) == 0) {
696 bp->address = a;
697 bp->instr[1] = bpinstr;
698 store_inst(&bp->instr[1]);
699 return bp;
700 }
701 }
702
703 printf("Sorry, no free breakpoints. Please clear one first.\n");
704 return NULL;
705}
706
707static void insert_bpts(void)
708{
709 int i;
710 struct bpt *bp;
711
712 bp = bpts;
713 for (i = 0; i < NBPTS; ++i, ++bp) {
714 if ((bp->enabled & (BP_TRAP|BP_IABR)) == 0)
715 continue;
716 if (mread(bp->address, &bp->instr[0], 4) != 4) {
717 printf("Couldn't read instruction at %lx, "
718 "disabling breakpoint there\n", bp->address);
719 bp->enabled = 0;
720 continue;
721 }
722 if (IS_MTMSRD(bp->instr[0]) || IS_RFID(bp->instr[0])) {
723 printf("Breakpoint at %lx is on an mtmsrd or rfid "
724 "instruction, disabling it\n", bp->address);
725 bp->enabled = 0;
726 continue;
727 }
728 store_inst(&bp->instr[0]);
729 if (bp->enabled & BP_IABR)
730 continue;
731 if (mwrite(bp->address, &bpinstr, 4) != 4) {
732 printf("Couldn't write instruction at %lx, "
733 "disabling breakpoint there\n", bp->address);
734 bp->enabled &= ~BP_TRAP;
735 continue;
736 }
737 store_inst((void *)bp->address);
738 }
739}
740
741static void insert_cpu_bpts(void)
742{
743 if (dabr.enabled)
Michael Neuling4474ef02012-09-06 21:24:56 +0000744 set_dabr(dabr.address | (dabr.enabled & 7), DABRX_ALL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 if (iabr && cpu_has_feature(CPU_FTR_IABR))
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000746 mtspr(SPRN_IABR, iabr->address
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 | (iabr->enabled & (BP_IABR|BP_IABR_TE)));
748}
749
750static void remove_bpts(void)
751{
752 int i;
753 struct bpt *bp;
754 unsigned instr;
755
756 bp = bpts;
757 for (i = 0; i < NBPTS; ++i, ++bp) {
758 if ((bp->enabled & (BP_TRAP|BP_IABR)) != BP_TRAP)
759 continue;
760 if (mread(bp->address, &instr, 4) == 4
761 && instr == bpinstr
762 && mwrite(bp->address, &bp->instr, 4) != 4)
763 printf("Couldn't remove breakpoint at %lx\n",
764 bp->address);
765 else
766 store_inst((void *)bp->address);
767 }
768}
769
770static void remove_cpu_bpts(void)
771{
Michael Neuling4474ef02012-09-06 21:24:56 +0000772 set_dabr(0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 if (cpu_has_feature(CPU_FTR_IABR))
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000774 mtspr(SPRN_IABR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775}
776
777/* Command interpreting routine */
778static char *last_cmd;
779
780static int
781cmds(struct pt_regs *excp)
782{
783 int cmd = 0;
784
785 last_cmd = NULL;
786 xmon_regs = excp;
Olaf Hering26c8af52006-09-08 16:29:21 +0200787
788 if (!xmon_no_auto_backtrace) {
789 xmon_no_auto_backtrace = 1;
790 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
791 }
792
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 for(;;) {
794#ifdef CONFIG_SMP
795 printf("%x:", smp_processor_id());
796#endif /* CONFIG_SMP */
797 printf("mon> ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 flush_input();
799 termch = 0;
800 cmd = skipbl();
801 if( cmd == '\n' ) {
802 if (last_cmd == NULL)
803 continue;
804 take_input(last_cmd);
805 last_cmd = NULL;
806 cmd = inchar();
807 }
808 switch (cmd) {
809 case 'm':
810 cmd = inchar();
811 switch (cmd) {
812 case 'm':
813 case 's':
814 case 'd':
815 memops(cmd);
816 break;
817 case 'l':
818 memlocate();
819 break;
820 case 'z':
821 memzcan();
822 break;
823 case 'i':
David Rientjesb2b755b2011-03-24 15:18:15 -0700824 show_mem(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 break;
826 default:
827 termch = cmd;
828 memex();
829 }
830 break;
831 case 'd':
832 dump();
833 break;
834 case 'l':
835 symbol_lookup();
836 break;
837 case 'r':
838 prregs(excp); /* print regs */
839 break;
840 case 'e':
841 excprint(excp);
842 break;
843 case 'S':
844 super_regs();
845 break;
846 case 't':
847 backtrace(excp);
848 break;
849 case 'f':
850 cacheflush();
851 break;
852 case 's':
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200853 if (do_spu_cmd() == 0)
854 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 if (do_step(excp))
856 return cmd;
857 break;
858 case 'x':
859 case 'X':
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100860 return cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 case EOF:
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100862 printf(" <no input ...>\n");
863 mdelay(2000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 return cmd;
865 case '?':
Ishizaki Kou4d404ed2007-07-18 19:26:40 +1000866 xmon_puts(help_string);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 case 'b':
869 bpt_cmds();
870 break;
871 case 'C':
872 csum();
873 break;
874 case 'c':
875 if (cpu_cmd())
876 return 0;
877 break;
878 case 'z':
879 bootcmds();
880 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000881 case 'p':
882 proccall();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000884#ifdef CONFIG_PPC_STD_MMU
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 case 'u':
886 dump_segments();
887 break;
Jimi Xenidis79873e82011-09-29 11:25:10 +0000888#elif defined(CONFIG_4xx)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100889 case 'u':
890 dump_tlb_44x();
891 break;
Jimi Xenidis79873e82011-09-29 11:25:10 +0000892#elif defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +1000893 case 'u':
894 dump_tlb_book3e();
895 break;
896#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 default:
898 printf("Unrecognized command: ");
Michael Ellermane3bc8042012-08-23 22:09:13 +0000899 do {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 if (' ' < cmd && cmd <= '~')
901 putchar(cmd);
902 else
903 printf("\\x%x", cmd);
904 cmd = inchar();
Michael Ellermane3bc8042012-08-23 22:09:13 +0000905 } while (cmd != '\n');
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 printf(" (type ? for help)\n");
907 break;
908 }
909 }
910}
911
Josh Boyercdd39042009-10-05 04:46:05 +0000912#ifdef CONFIG_BOOKE
913static int do_step(struct pt_regs *regs)
914{
915 regs->msr |= MSR_DE;
916 mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
917 return 1;
918}
919#else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920/*
921 * Step a single instruction.
922 * Some instructions we emulate, others we execute with MSR_SE set.
923 */
924static int do_step(struct pt_regs *regs)
925{
926 unsigned int instr;
927 int stepped;
928
929 /* check we are in 64-bit kernel mode, translation enabled */
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000930 if ((regs->msr & (MSR_64BIT|MSR_PR|MSR_IR)) == (MSR_64BIT|MSR_IR)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 if (mread(regs->nip, &instr, 4) == 4) {
932 stepped = emulate_step(regs, instr);
933 if (stepped < 0) {
934 printf("Couldn't single-step %s instruction\n",
935 (IS_RFID(instr)? "rfid": "mtmsrd"));
936 return 0;
937 }
938 if (stepped > 0) {
939 regs->trap = 0xd00 | (regs->trap & 1);
940 printf("stepped to ");
941 xmon_print_symbol(regs->nip, " ", "\n");
942 ppc_inst_dump(regs->nip, 1, 0);
943 return 0;
944 }
945 }
946 }
947 regs->msr |= MSR_SE;
948 return 1;
949}
Josh Boyercdd39042009-10-05 04:46:05 +0000950#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951
952static void bootcmds(void)
953{
954 int cmd;
955
956 cmd = inchar();
957 if (cmd == 'r')
958 ppc_md.restart(NULL);
959 else if (cmd == 'h')
960 ppc_md.halt();
961 else if (cmd == 'p')
962 ppc_md.power_off();
963}
964
965static int cpu_cmd(void)
966{
967#ifdef CONFIG_SMP
968 unsigned long cpu;
969 int timeout;
970 int count;
971
972 if (!scanhex(&cpu)) {
973 /* print cpus waiting or in xmon */
974 printf("cpus stopped:");
975 count = 0;
Anton Blanchardbc1d7702012-06-28 19:28:57 +0000976 for_each_possible_cpu(cpu) {
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000977 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 if (count == 0)
979 printf(" %x", cpu);
980 ++count;
981 } else {
982 if (count > 1)
983 printf("-%x", cpu - 1);
984 count = 0;
985 }
986 }
987 if (count > 1)
988 printf("-%x", NR_CPUS - 1);
989 printf("\n");
990 return 0;
991 }
992 /* try to switch to cpu specified */
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000993 if (!cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 printf("cpu 0x%x isn't in xmon\n", cpu);
995 return 0;
996 }
997 xmon_taken = 0;
998 mb();
999 xmon_owner = cpu;
1000 timeout = 10000000;
1001 while (!xmon_taken) {
1002 if (--timeout == 0) {
1003 if (test_and_set_bit(0, &xmon_taken))
1004 break;
1005 /* take control back */
1006 mb();
1007 xmon_owner = smp_processor_id();
1008 printf("cpu %u didn't take control\n", cpu);
1009 return 0;
1010 }
1011 barrier();
1012 }
1013 return 1;
1014#else
1015 return 0;
1016#endif /* CONFIG_SMP */
1017}
1018
1019static unsigned short fcstab[256] = {
1020 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
1021 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
1022 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
1023 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
1024 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
1025 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
1026 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
1027 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
1028 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
1029 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
1030 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
1031 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
1032 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
1033 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
1034 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
1035 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
1036 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
1037 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
1038 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
1039 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
1040 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
1041 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
1042 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
1043 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
1044 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
1045 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
1046 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
1047 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
1048 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
1049 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
1050 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
1051 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
1052};
1053
1054#define FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
1055
1056static void
1057csum(void)
1058{
1059 unsigned int i;
1060 unsigned short fcs;
1061 unsigned char v;
1062
1063 if (!scanhex(&adrs))
1064 return;
1065 if (!scanhex(&ncsum))
1066 return;
1067 fcs = 0xffff;
1068 for (i = 0; i < ncsum; ++i) {
1069 if (mread(adrs+i, &v, 1) == 0) {
1070 printf("csum stopped at %x\n", adrs+i);
1071 break;
1072 }
1073 fcs = FCS(fcs, v);
1074 }
1075 printf("%x\n", fcs);
1076}
1077
1078/*
1079 * Check if this is a suitable place to put a breakpoint.
1080 */
1081static long check_bp_loc(unsigned long addr)
1082{
1083 unsigned int instr;
1084
1085 addr &= ~3;
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001086 if (!is_kernel_addr(addr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 printf("Breakpoints may only be placed at kernel addresses\n");
1088 return 0;
1089 }
1090 if (!mread(addr, &instr, sizeof(instr))) {
1091 printf("Can't read instruction at address %lx\n", addr);
1092 return 0;
1093 }
1094 if (IS_MTMSRD(instr) || IS_RFID(instr)) {
1095 printf("Breakpoints may not be placed on mtmsrd or rfid "
1096 "instructions\n");
1097 return 0;
1098 }
1099 return 1;
1100}
1101
Michael Ellermane3bc8042012-08-23 22:09:13 +00001102static char *breakpoint_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 "Breakpoint command usage:\n"
1104 "b show breakpoints\n"
1105 "b <addr> [cnt] set breakpoint at given instr addr\n"
1106 "bc clear all breakpoints\n"
1107 "bc <n/addr> clear breakpoint number n or at addr\n"
1108 "bi <addr> [cnt] set hardware instr breakpoint (POWER3/RS64 only)\n"
1109 "bd <addr> [cnt] set hardware data breakpoint\n"
1110 "";
1111
1112static void
1113bpt_cmds(void)
1114{
1115 int cmd;
1116 unsigned long a;
1117 int mode, i;
1118 struct bpt *bp;
1119 const char badaddr[] = "Only kernel addresses are permitted "
1120 "for breakpoints\n";
1121
1122 cmd = inchar();
1123 switch (cmd) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001124#ifndef CONFIG_8xx
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 case 'd': /* bd - hardware data breakpoint */
1126 mode = 7;
1127 cmd = inchar();
1128 if (cmd == 'r')
1129 mode = 5;
1130 else if (cmd == 'w')
1131 mode = 6;
1132 else
1133 termch = cmd;
1134 dabr.address = 0;
1135 dabr.enabled = 0;
1136 if (scanhex(&dabr.address)) {
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001137 if (!is_kernel_addr(dabr.address)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 printf(badaddr);
1139 break;
1140 }
1141 dabr.address &= ~7;
1142 dabr.enabled = mode | BP_DABR;
1143 }
1144 break;
1145
1146 case 'i': /* bi - hardware instr breakpoint */
1147 if (!cpu_has_feature(CPU_FTR_IABR)) {
1148 printf("Hardware instruction breakpoint "
1149 "not supported on this cpu\n");
1150 break;
1151 }
1152 if (iabr) {
1153 iabr->enabled &= ~(BP_IABR | BP_IABR_TE);
1154 iabr = NULL;
1155 }
1156 if (!scanhex(&a))
1157 break;
1158 if (!check_bp_loc(a))
1159 break;
1160 bp = new_breakpoint(a);
1161 if (bp != NULL) {
1162 bp->enabled |= BP_IABR | BP_IABR_TE;
1163 iabr = bp;
1164 }
1165 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001166#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167
1168 case 'c':
1169 if (!scanhex(&a)) {
1170 /* clear all breakpoints */
1171 for (i = 0; i < NBPTS; ++i)
1172 bpts[i].enabled = 0;
1173 iabr = NULL;
1174 dabr.enabled = 0;
1175 printf("All breakpoints cleared\n");
1176 break;
1177 }
1178
1179 if (a <= NBPTS && a >= 1) {
1180 /* assume a breakpoint number */
1181 bp = &bpts[a-1]; /* bp nums are 1 based */
1182 } else {
1183 /* assume a breakpoint address */
1184 bp = at_breakpoint(a);
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001185 if (bp == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186 printf("No breakpoint at %x\n", a);
1187 break;
1188 }
1189 }
1190
1191 printf("Cleared breakpoint %x (", BP_NUM(bp));
1192 xmon_print_symbol(bp->address, " ", ")\n");
1193 bp->enabled = 0;
1194 break;
1195
1196 default:
1197 termch = cmd;
Michael Ellermane3bc8042012-08-23 22:09:13 +00001198 cmd = skipbl();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199 if (cmd == '?') {
1200 printf(breakpoint_help_string);
1201 break;
1202 }
1203 termch = cmd;
1204 if (!scanhex(&a)) {
1205 /* print all breakpoints */
1206 printf(" type address\n");
1207 if (dabr.enabled) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001208 printf(" data "REG" [", dabr.address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209 if (dabr.enabled & 1)
1210 printf("r");
1211 if (dabr.enabled & 2)
1212 printf("w");
1213 printf("]\n");
1214 }
1215 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
1216 if (!bp->enabled)
1217 continue;
1218 printf("%2x %s ", BP_NUM(bp),
1219 (bp->enabled & BP_IABR)? "inst": "trap");
1220 xmon_print_symbol(bp->address, " ", "\n");
1221 }
1222 break;
1223 }
1224
1225 if (!check_bp_loc(a))
1226 break;
1227 bp = new_breakpoint(a);
1228 if (bp != NULL)
1229 bp->enabled |= BP_TRAP;
1230 break;
1231 }
1232}
1233
1234/* Very cheap human name for vector lookup. */
1235static
1236const char *getvecname(unsigned long vec)
1237{
1238 char *ret;
1239
1240 switch (vec) {
1241 case 0x100: ret = "(System Reset)"; break;
1242 case 0x200: ret = "(Machine Check)"; break;
1243 case 0x300: ret = "(Data Access)"; break;
1244 case 0x380: ret = "(Data SLB Access)"; break;
1245 case 0x400: ret = "(Instruction Access)"; break;
1246 case 0x480: ret = "(Instruction SLB Access)"; break;
1247 case 0x500: ret = "(Hardware Interrupt)"; break;
1248 case 0x600: ret = "(Alignment)"; break;
1249 case 0x700: ret = "(Program Check)"; break;
1250 case 0x800: ret = "(FPU Unavailable)"; break;
1251 case 0x900: ret = "(Decrementer)"; break;
1252 case 0xc00: ret = "(System Call)"; break;
1253 case 0xd00: ret = "(Single Step)"; break;
1254 case 0xf00: ret = "(Performance Monitor)"; break;
1255 case 0xf20: ret = "(Altivec Unavailable)"; break;
1256 case 0x1300: ret = "(Instruction Breakpoint)"; break;
1257 default: ret = "";
1258 }
1259 return ret;
1260}
1261
1262static void get_function_bounds(unsigned long pc, unsigned long *startp,
1263 unsigned long *endp)
1264{
1265 unsigned long size, offset;
1266 const char *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267
1268 *startp = *endp = 0;
1269 if (pc == 0)
1270 return;
1271 if (setjmp(bus_error_jmp) == 0) {
1272 catch_memory_errors = 1;
1273 sync();
Alexey Dobriyanffb45122007-05-08 00:28:41 -07001274 name = kallsyms_lookup(pc, &size, &offset, NULL, tmpstr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275 if (name != NULL) {
1276 *startp = pc - offset;
1277 *endp = pc - offset + size;
1278 }
1279 sync();
1280 }
1281 catch_memory_errors = 0;
1282}
1283
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001284#define LRSAVE_OFFSET (STACK_FRAME_LR_SAVE * sizeof(unsigned long))
1285#define MARKER_OFFSET (STACK_FRAME_MARKER * sizeof(unsigned long))
1286
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287static void xmon_show_stack(unsigned long sp, unsigned long lr,
1288 unsigned long pc)
1289{
Michael Ellerman0104cd62012-10-09 04:20:36 +00001290 int max_to_print = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291 unsigned long ip;
1292 unsigned long newsp;
1293 unsigned long marker;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 struct pt_regs regs;
1295
Michael Ellerman0104cd62012-10-09 04:20:36 +00001296 while (max_to_print--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 if (sp < PAGE_OFFSET) {
1298 if (sp != 0)
1299 printf("SP (%lx) is in userspace\n", sp);
1300 break;
1301 }
1302
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001303 if (!mread(sp + LRSAVE_OFFSET, &ip, sizeof(unsigned long))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 || !mread(sp, &newsp, sizeof(unsigned long))) {
1305 printf("Couldn't read stack frame at %lx\n", sp);
1306 break;
1307 }
1308
1309 /*
1310 * For the first stack frame, try to work out if
1311 * LR and/or the saved LR value in the bottommost
1312 * stack frame are valid.
1313 */
1314 if ((pc | lr) != 0) {
1315 unsigned long fnstart, fnend;
1316 unsigned long nextip;
1317 int printip = 1;
1318
1319 get_function_bounds(pc, &fnstart, &fnend);
1320 nextip = 0;
1321 if (newsp > sp)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001322 mread(newsp + LRSAVE_OFFSET, &nextip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 sizeof(unsigned long));
1324 if (lr == ip) {
1325 if (lr < PAGE_OFFSET
1326 || (fnstart <= lr && lr < fnend))
1327 printip = 0;
1328 } else if (lr == nextip) {
1329 printip = 0;
1330 } else if (lr >= PAGE_OFFSET
1331 && !(fnstart <= lr && lr < fnend)) {
1332 printf("[link register ] ");
1333 xmon_print_symbol(lr, " ", "\n");
1334 }
1335 if (printip) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001336 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 xmon_print_symbol(ip, " ", " (unreliable)\n");
1338 }
1339 pc = lr = 0;
1340
1341 } else {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001342 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343 xmon_print_symbol(ip, " ", "\n");
1344 }
1345
1346 /* Look for "regshere" marker to see if this is
1347 an exception frame. */
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001348 if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long))
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001349 && marker == STACK_FRAME_REGS_MARKER) {
Michael Ellermanc4de3802012-10-09 04:20:35 +00001350 if (mread(sp + STACK_FRAME_OVERHEAD, &regs, sizeof(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 != sizeof(regs)) {
1352 printf("Couldn't read registers at %lx\n",
Michael Ellermanc4de3802012-10-09 04:20:35 +00001353 sp + STACK_FRAME_OVERHEAD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 break;
1355 }
Michael Ellermane3bc8042012-08-23 22:09:13 +00001356 printf("--- Exception: %lx %s at ", regs.trap,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 getvecname(TRAP(&regs)));
1358 pc = regs.nip;
1359 lr = regs.link;
1360 xmon_print_symbol(pc, " ", "\n");
1361 }
1362
1363 if (newsp == 0)
1364 break;
1365
1366 sp = newsp;
Michael Ellerman0104cd62012-10-09 04:20:36 +00001367 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368}
1369
1370static void backtrace(struct pt_regs *excp)
1371{
1372 unsigned long sp;
1373
1374 if (scanhex(&sp))
1375 xmon_show_stack(sp, 0, 0);
1376 else
1377 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
1378 scannl();
1379}
1380
1381static void print_bug_trap(struct pt_regs *regs)
1382{
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001383#ifdef CONFIG_BUG
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001384 const struct bug_entry *bug;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 unsigned long addr;
1386
1387 if (regs->msr & MSR_PR)
1388 return; /* not in kernel */
1389 addr = regs->nip; /* address of trap instruction */
1390 if (addr < PAGE_OFFSET)
1391 return;
1392 bug = find_bug(regs->nip);
1393 if (bug == NULL)
1394 return;
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001395 if (is_warning_bug(bug))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 return;
1397
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001398#ifdef CONFIG_DEBUG_BUGVERBOSE
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001399 printf("kernel BUG at %s:%u!\n",
1400 bug->file, bug->line);
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001401#else
1402 printf("kernel BUG at %p!\n", (void *)bug->bug_addr);
1403#endif
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001404#endif /* CONFIG_BUG */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405}
1406
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001407static void excprint(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408{
1409 unsigned long trap;
1410
1411#ifdef CONFIG_SMP
1412 printf("cpu 0x%x: ", smp_processor_id());
1413#endif /* CONFIG_SMP */
1414
1415 trap = TRAP(fp);
1416 printf("Vector: %lx %s at [%lx]\n", fp->trap, getvecname(trap), fp);
1417 printf(" pc: ");
1418 xmon_print_symbol(fp->nip, ": ", "\n");
1419
1420 printf(" lr: ", fp->link);
1421 xmon_print_symbol(fp->link, ": ", "\n");
1422
1423 printf(" sp: %lx\n", fp->gpr[1]);
1424 printf(" msr: %lx\n", fp->msr);
1425
1426 if (trap == 0x300 || trap == 0x380 || trap == 0x600) {
1427 printf(" dar: %lx\n", fp->dar);
1428 if (trap != 0x380)
1429 printf(" dsisr: %lx\n", fp->dsisr);
1430 }
1431
1432 printf(" current = 0x%lx\n", current);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001433#ifdef CONFIG_PPC64
Benjamin Herrenschmidt7230c562012-03-06 18:27:59 +11001434 printf(" paca = 0x%lx\t softe: %d\t irq_happened: 0x%02x\n",
1435 local_paca, local_paca->soft_enabled, local_paca->irq_happened);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001436#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 if (current) {
1438 printf(" pid = %ld, comm = %s\n",
1439 current->pid, current->comm);
1440 }
1441
1442 if (trap == 0x700)
1443 print_bug_trap(fp);
1444}
1445
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001446static void prregs(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001448 int n, trap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 unsigned long base;
1450 struct pt_regs regs;
1451
1452 if (scanhex(&base)) {
1453 if (setjmp(bus_error_jmp) == 0) {
1454 catch_memory_errors = 1;
1455 sync();
1456 regs = *(struct pt_regs *)base;
1457 sync();
1458 __delay(200);
1459 } else {
1460 catch_memory_errors = 0;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001461 printf("*** Error reading registers from "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 base);
1463 return;
1464 }
1465 catch_memory_errors = 0;
1466 fp = &regs;
1467 }
1468
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001469#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470 if (FULL_REGS(fp)) {
1471 for (n = 0; n < 16; ++n)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001472 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 n, fp->gpr[n], n+16, fp->gpr[n+16]);
1474 } else {
1475 for (n = 0; n < 7; ++n)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001476 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 n, fp->gpr[n], n+7, fp->gpr[n+7]);
1478 }
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001479#else
1480 for (n = 0; n < 32; ++n) {
1481 printf("R%.2d = %.8x%s", n, fp->gpr[n],
1482 (n & 3) == 3? "\n": " ");
1483 if (n == 12 && !FULL_REGS(fp)) {
1484 printf("\n");
1485 break;
1486 }
1487 }
1488#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 printf("pc = ");
1490 xmon_print_symbol(fp->nip, " ", "\n");
Paul Mackerras48404f22011-05-01 19:48:20 +00001491 if (TRAP(fp) != 0xc00 && cpu_has_feature(CPU_FTR_CFAR)) {
1492 printf("cfar= ");
1493 xmon_print_symbol(fp->orig_gpr3, " ", "\n");
1494 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 printf("lr = ");
1496 xmon_print_symbol(fp->link, " ", "\n");
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001497 printf("msr = "REG" cr = %.8lx\n", fp->msr, fp->ccr);
1498 printf("ctr = "REG" xer = "REG" trap = %4lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 fp->ctr, fp->xer, fp->trap);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001500 trap = TRAP(fp);
1501 if (trap == 0x300 || trap == 0x380 || trap == 0x600)
1502 printf("dar = "REG" dsisr = %.8lx\n", fp->dar, fp->dsisr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503}
1504
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001505static void cacheflush(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506{
1507 int cmd;
1508 unsigned long nflush;
1509
1510 cmd = inchar();
1511 if (cmd != 'i')
1512 termch = cmd;
1513 scanhex((void *)&adrs);
1514 if (termch != '\n')
1515 termch = 0;
1516 nflush = 1;
1517 scanhex(&nflush);
1518 nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES;
1519 if (setjmp(bus_error_jmp) == 0) {
1520 catch_memory_errors = 1;
1521 sync();
1522
1523 if (cmd != 'i') {
1524 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1525 cflush((void *) adrs);
1526 } else {
1527 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1528 cinval((void *) adrs);
1529 }
1530 sync();
1531 /* wait a little while to see if we get a machine check */
1532 __delay(200);
1533 }
1534 catch_memory_errors = 0;
1535}
1536
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001537static unsigned long
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538read_spr(int n)
1539{
1540 unsigned int instrs[2];
1541 unsigned long (*code)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 unsigned long ret = -1UL;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001543#ifdef CONFIG_PPC64
1544 unsigned long opd[3];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 opd[0] = (unsigned long)instrs;
1547 opd[1] = 0;
1548 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001549 code = (unsigned long (*)(void)) opd;
1550#else
1551 code = (unsigned long (*)(void)) instrs;
1552#endif
1553
1554 /* mfspr r3,n; blr */
1555 instrs[0] = 0x7c6002a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1556 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 store_inst(instrs);
1558 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559
1560 if (setjmp(bus_error_jmp) == 0) {
1561 catch_memory_errors = 1;
1562 sync();
1563
1564 ret = code();
1565
1566 sync();
1567 /* wait a little while to see if we get a machine check */
1568 __delay(200);
1569 n = size;
1570 }
1571
1572 return ret;
1573}
1574
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001575static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576write_spr(int n, unsigned long val)
1577{
1578 unsigned int instrs[2];
1579 unsigned long (*code)(unsigned long);
Paul Mackerras548cceb2005-11-11 22:36:34 +11001580#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 unsigned long opd[3];
1582
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 opd[0] = (unsigned long)instrs;
1584 opd[1] = 0;
1585 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001586 code = (unsigned long (*)(unsigned long)) opd;
1587#else
1588 code = (unsigned long (*)(unsigned long)) instrs;
1589#endif
1590
1591 instrs[0] = 0x7c6003a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1592 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593 store_inst(instrs);
1594 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595
1596 if (setjmp(bus_error_jmp) == 0) {
1597 catch_memory_errors = 1;
1598 sync();
1599
1600 code(val);
1601
1602 sync();
1603 /* wait a little while to see if we get a machine check */
1604 __delay(200);
1605 n = size;
1606 }
1607}
1608
1609static unsigned long regno;
1610extern char exc_prolog;
1611extern char dec_exc;
1612
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001613static void super_regs(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614{
1615 int cmd;
1616 unsigned long val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617
1618 cmd = skipbl();
1619 if (cmd == '\n') {
Michael Ellermane3bc8042012-08-23 22:09:13 +00001620 unsigned long sp, toc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 asm("mr %0,1" : "=r" (sp) :);
1622 asm("mr %0,2" : "=r" (toc) :);
1623
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001624 printf("msr = "REG" sprg0= "REG"\n",
1625 mfmsr(), mfspr(SPRN_SPRG0));
1626 printf("pvr = "REG" sprg1= "REG"\n",
Michael Ellermane3bc8042012-08-23 22:09:13 +00001627 mfspr(SPRN_PVR), mfspr(SPRN_SPRG1));
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001628 printf("dec = "REG" sprg2= "REG"\n",
1629 mfspr(SPRN_DEC), mfspr(SPRN_SPRG2));
1630 printf("sp = "REG" sprg3= "REG"\n", sp, mfspr(SPRN_SPRG3));
1631 printf("toc = "REG" dar = "REG"\n", toc, mfspr(SPRN_DAR));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632
1633 return;
1634 }
1635
1636 scanhex(&regno);
1637 switch (cmd) {
1638 case 'w':
1639 val = read_spr(regno);
1640 scanhex(&val);
1641 write_spr(regno, val);
1642 /* fall through */
1643 case 'r':
1644 printf("spr %lx = %lx\n", regno, read_spr(regno));
1645 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646 }
1647 scannl();
1648}
1649
1650/*
1651 * Stuff for reading and writing memory safely
1652 */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001653static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654mread(unsigned long adrs, void *buf, int size)
1655{
1656 volatile int n;
1657 char *p, *q;
1658
1659 n = 0;
1660 if (setjmp(bus_error_jmp) == 0) {
1661 catch_memory_errors = 1;
1662 sync();
1663 p = (char *)adrs;
1664 q = (char *)buf;
1665 switch (size) {
1666 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001667 *(u16 *)q = *(u16 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 break;
1669 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001670 *(u32 *)q = *(u32 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671 break;
1672 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001673 *(u64 *)q = *(u64 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674 break;
1675 default:
1676 for( ; n < size; ++n) {
1677 *q++ = *p++;
1678 sync();
1679 }
1680 }
1681 sync();
1682 /* wait a little while to see if we get a machine check */
1683 __delay(200);
1684 n = size;
1685 }
1686 catch_memory_errors = 0;
1687 return n;
1688}
1689
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001690static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691mwrite(unsigned long adrs, void *buf, int size)
1692{
1693 volatile int n;
1694 char *p, *q;
1695
1696 n = 0;
1697 if (setjmp(bus_error_jmp) == 0) {
1698 catch_memory_errors = 1;
1699 sync();
1700 p = (char *) adrs;
1701 q = (char *) buf;
1702 switch (size) {
1703 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001704 *(u16 *)p = *(u16 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 break;
1706 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001707 *(u32 *)p = *(u32 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708 break;
1709 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001710 *(u64 *)p = *(u64 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 break;
1712 default:
1713 for ( ; n < size; ++n) {
1714 *p++ = *q++;
1715 sync();
1716 }
1717 }
1718 sync();
1719 /* wait a little while to see if we get a machine check */
1720 __delay(200);
1721 n = size;
1722 } else {
1723 printf("*** Error writing address %x\n", adrs + n);
1724 }
1725 catch_memory_errors = 0;
1726 return n;
1727}
1728
1729static int fault_type;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001730static int fault_except;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731static char *fault_chars[] = { "--", "**", "##" };
1732
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001733static int handle_fault(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001735 fault_except = TRAP(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 switch (TRAP(regs)) {
1737 case 0x200:
1738 fault_type = 0;
1739 break;
1740 case 0x300:
1741 case 0x380:
1742 fault_type = 1;
1743 break;
1744 default:
1745 fault_type = 2;
1746 }
1747
1748 longjmp(bus_error_jmp, 1);
1749
1750 return 0;
1751}
1752
1753#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t))
1754
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001755static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756byterev(unsigned char *val, int size)
1757{
1758 int t;
1759
1760 switch (size) {
1761 case 2:
1762 SWAP(val[0], val[1], t);
1763 break;
1764 case 4:
1765 SWAP(val[0], val[3], t);
1766 SWAP(val[1], val[2], t);
1767 break;
1768 case 8: /* is there really any use for this? */
1769 SWAP(val[0], val[7], t);
1770 SWAP(val[1], val[6], t);
1771 SWAP(val[2], val[5], t);
1772 SWAP(val[3], val[4], t);
1773 break;
1774 }
1775}
1776
1777static int brev;
1778static int mnoread;
1779
Michael Ellermane3bc8042012-08-23 22:09:13 +00001780static char *memex_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781 "Memory examine command usage:\n"
1782 "m [addr] [flags] examine/change memory\n"
1783 " addr is optional. will start where left off.\n"
1784 " flags may include chars from this set:\n"
1785 " b modify by bytes (default)\n"
1786 " w modify by words (2 byte)\n"
1787 " l modify by longs (4 byte)\n"
1788 " d modify by doubleword (8 byte)\n"
1789 " r toggle reverse byte order mode\n"
1790 " n do not read memory (for i/o spaces)\n"
1791 " . ok to read (default)\n"
1792 "NOTE: flags are saved as defaults\n"
1793 "";
1794
Michael Ellermane3bc8042012-08-23 22:09:13 +00001795static char *memex_subcmd_help_string =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 "Memory examine subcommands:\n"
1797 " hexval write this val to current location\n"
1798 " 'string' write chars from string to this location\n"
1799 " ' increment address\n"
1800 " ^ decrement address\n"
1801 " / increment addr by 0x10. //=0x100, ///=0x1000, etc\n"
1802 " \\ decrement addr by 0x10. \\\\=0x100, \\\\\\=0x1000, etc\n"
1803 " ` clear no-read flag\n"
1804 " ; stay at this addr\n"
1805 " v change to byte mode\n"
1806 " w change to word (2 byte) mode\n"
1807 " l change to long (4 byte) mode\n"
1808 " u change to doubleword (8 byte) mode\n"
1809 " m addr change current addr\n"
1810 " n toggle no-read flag\n"
1811 " r toggle byte reverse flag\n"
1812 " < count back up count bytes\n"
1813 " > count skip forward count bytes\n"
1814 " x exit this mode\n"
1815 "";
1816
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001817static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818memex(void)
1819{
1820 int cmd, inc, i, nslash;
1821 unsigned long n;
1822 unsigned char val[16];
1823
1824 scanhex((void *)&adrs);
1825 cmd = skipbl();
1826 if (cmd == '?') {
1827 printf(memex_help_string);
1828 return;
1829 } else {
1830 termch = cmd;
1831 }
1832 last_cmd = "m\n";
1833 while ((cmd = skipbl()) != '\n') {
1834 switch( cmd ){
1835 case 'b': size = 1; break;
1836 case 'w': size = 2; break;
1837 case 'l': size = 4; break;
1838 case 'd': size = 8; break;
1839 case 'r': brev = !brev; break;
1840 case 'n': mnoread = 1; break;
1841 case '.': mnoread = 0; break;
1842 }
1843 }
1844 if( size <= 0 )
1845 size = 1;
1846 else if( size > 8 )
1847 size = 8;
1848 for(;;){
1849 if (!mnoread)
1850 n = mread(adrs, val, size);
Paul Mackerrase1449ed2005-11-10 14:30:20 +11001851 printf(REG"%c", adrs, brev? 'r': ' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 if (!mnoread) {
1853 if (brev)
1854 byterev(val, size);
1855 putchar(' ');
1856 for (i = 0; i < n; ++i)
1857 printf("%.2x", val[i]);
1858 for (; i < size; ++i)
1859 printf("%s", fault_chars[fault_type]);
1860 }
1861 putchar(' ');
1862 inc = size;
1863 nslash = 0;
1864 for(;;){
1865 if( scanhex(&n) ){
1866 for (i = 0; i < size; ++i)
1867 val[i] = n >> (i * 8);
1868 if (!brev)
1869 byterev(val, size);
1870 mwrite(adrs, val, size);
1871 inc = size;
1872 }
1873 cmd = skipbl();
1874 if (cmd == '\n')
1875 break;
1876 inc = 0;
1877 switch (cmd) {
1878 case '\'':
1879 for(;;){
1880 n = inchar();
1881 if( n == '\\' )
1882 n = bsesc();
1883 else if( n == '\'' )
1884 break;
1885 for (i = 0; i < size; ++i)
1886 val[i] = n >> (i * 8);
1887 if (!brev)
1888 byterev(val, size);
1889 mwrite(adrs, val, size);
1890 adrs += size;
1891 }
1892 adrs -= size;
1893 inc = size;
1894 break;
1895 case ',':
1896 adrs += size;
1897 break;
1898 case '.':
1899 mnoread = 0;
1900 break;
1901 case ';':
1902 break;
1903 case 'x':
1904 case EOF:
1905 scannl();
1906 return;
1907 case 'b':
1908 case 'v':
1909 size = 1;
1910 break;
1911 case 'w':
1912 size = 2;
1913 break;
1914 case 'l':
1915 size = 4;
1916 break;
1917 case 'u':
1918 size = 8;
1919 break;
1920 case '^':
1921 adrs -= size;
1922 break;
1923 break;
1924 case '/':
1925 if (nslash > 0)
1926 adrs -= 1 << nslash;
1927 else
1928 nslash = 0;
1929 nslash += 4;
1930 adrs += 1 << nslash;
1931 break;
1932 case '\\':
1933 if (nslash < 0)
1934 adrs += 1 << -nslash;
1935 else
1936 nslash = 0;
1937 nslash -= 4;
1938 adrs -= 1 << -nslash;
1939 break;
1940 case 'm':
1941 scanhex((void *)&adrs);
1942 break;
1943 case 'n':
1944 mnoread = 1;
1945 break;
1946 case 'r':
1947 brev = !brev;
1948 break;
1949 case '<':
1950 n = size;
1951 scanhex(&n);
1952 adrs -= n;
1953 break;
1954 case '>':
1955 n = size;
1956 scanhex(&n);
1957 adrs += n;
1958 break;
1959 case '?':
1960 printf(memex_subcmd_help_string);
1961 break;
1962 }
1963 }
1964 adrs += inc;
1965 }
1966}
1967
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001968static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969bsesc(void)
1970{
1971 int c;
1972
1973 c = inchar();
1974 switch( c ){
1975 case 'n': c = '\n'; break;
1976 case 'r': c = '\r'; break;
1977 case 'b': c = '\b'; break;
1978 case 't': c = '\t'; break;
1979 }
1980 return c;
1981}
1982
Olaf Hering7e5b5932006-03-08 20:40:28 +01001983static void xmon_rawdump (unsigned long adrs, long ndump)
1984{
1985 long n, m, r, nr;
1986 unsigned char temp[16];
1987
1988 for (n = ndump; n > 0;) {
1989 r = n < 16? n: 16;
1990 nr = mread(adrs, temp, r);
1991 adrs += nr;
1992 for (m = 0; m < r; ++m) {
1993 if (m < nr)
1994 printf("%.2x", temp[m]);
1995 else
1996 printf("%s", fault_chars[fault_type]);
1997 }
1998 n -= r;
1999 if (nr < r)
2000 break;
2001 }
2002 printf("\n");
2003}
2004
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002005#ifdef CONFIG_PPC64
2006static void dump_one_paca(int cpu)
2007{
2008 struct paca_struct *p;
2009
2010 if (setjmp(bus_error_jmp) != 0) {
2011 printf("*** Error dumping paca for cpu 0x%x!\n", cpu);
2012 return;
2013 }
2014
2015 catch_memory_errors = 1;
2016 sync();
2017
2018 p = &paca[cpu];
2019
2020 printf("paca for cpu 0x%x @ %p:\n", cpu, p);
2021
2022 printf(" %-*s = %s\n", 16, "possible", cpu_possible(cpu) ? "yes" : "no");
2023 printf(" %-*s = %s\n", 16, "present", cpu_present(cpu) ? "yes" : "no");
2024 printf(" %-*s = %s\n", 16, "online", cpu_online(cpu) ? "yes" : "no");
2025
2026#define DUMP(paca, name, format) \
2027 printf(" %-*s = %#-*"format"\t(0x%lx)\n", 16, #name, 18, paca->name, \
2028 offsetof(struct paca_struct, name));
2029
2030 DUMP(p, lock_token, "x");
2031 DUMP(p, paca_index, "x");
2032 DUMP(p, kernel_toc, "lx");
2033 DUMP(p, kernelbase, "lx");
2034 DUMP(p, kernel_msr, "lx");
2035#ifdef CONFIG_PPC_STD_MMU_64
2036 DUMP(p, stab_real, "lx");
2037 DUMP(p, stab_addr, "lx");
2038#endif
2039 DUMP(p, emergency_sp, "p");
2040 DUMP(p, data_offset, "lx");
2041 DUMP(p, hw_cpu_id, "x");
2042 DUMP(p, cpu_start, "x");
2043 DUMP(p, kexec_state, "x");
2044 DUMP(p, __current, "p");
2045 DUMP(p, kstack, "lx");
2046 DUMP(p, stab_rr, "lx");
2047 DUMP(p, saved_r1, "lx");
2048 DUMP(p, trap_save, "x");
2049 DUMP(p, soft_enabled, "x");
2050 DUMP(p, irq_happened, "x");
2051 DUMP(p, io_sync, "x");
2052 DUMP(p, irq_work_pending, "x");
2053 DUMP(p, nap_state_lost, "x");
2054
2055#undef DUMP
2056
2057 catch_memory_errors = 0;
2058 sync();
2059}
2060
2061static void dump_all_pacas(void)
2062{
2063 int cpu;
2064
2065 if (num_possible_cpus() == 0) {
2066 printf("No possible cpus, use 'dp #' to dump individual cpus\n");
2067 return;
2068 }
2069
2070 for_each_possible_cpu(cpu)
2071 dump_one_paca(cpu);
2072}
2073
2074static void dump_pacas(void)
2075{
2076 unsigned long num;
2077 int c;
2078
2079 c = inchar();
2080 if (c == 'a') {
2081 dump_all_pacas();
2082 return;
2083 }
2084
2085 termch = c; /* Put c back, it wasn't 'a' */
2086
2087 if (scanhex(&num))
2088 dump_one_paca(num);
2089 else
2090 dump_one_paca(xmon_owner);
2091}
2092#endif
2093
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
2095 || ('a' <= (c) && (c) <= 'f') \
2096 || ('A' <= (c) && (c) <= 'F'))
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002097static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098dump(void)
2099{
2100 int c;
2101
2102 c = inchar();
Michael Ellermanddadb6b2012-09-13 23:01:31 +00002103
2104#ifdef CONFIG_PPC64
2105 if (c == 'p') {
2106 dump_pacas();
2107 return;
2108 }
2109#endif
2110
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111 if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
2112 termch = c;
2113 scanhex((void *)&adrs);
2114 if (termch != '\n')
2115 termch = 0;
2116 if (c == 'i') {
2117 scanhex(&nidump);
2118 if (nidump == 0)
2119 nidump = 16;
2120 else if (nidump > MAX_DUMP)
2121 nidump = MAX_DUMP;
2122 adrs += ppc_inst_dump(adrs, nidump, 1);
2123 last_cmd = "di\n";
Vinay Sridharf312deb2009-05-14 23:13:07 +00002124 } else if (c == 'l') {
2125 dump_log_buf();
Olaf Hering7e5b5932006-03-08 20:40:28 +01002126 } else if (c == 'r') {
2127 scanhex(&ndump);
2128 if (ndump == 0)
2129 ndump = 64;
2130 xmon_rawdump(adrs, ndump);
2131 adrs += ndump;
2132 last_cmd = "dr\n";
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133 } else {
2134 scanhex(&ndump);
2135 if (ndump == 0)
2136 ndump = 64;
2137 else if (ndump > MAX_DUMP)
2138 ndump = MAX_DUMP;
2139 prdump(adrs, ndump);
2140 adrs += ndump;
2141 last_cmd = "d\n";
2142 }
2143}
2144
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002145static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002146prdump(unsigned long adrs, long ndump)
2147{
2148 long n, m, c, r, nr;
2149 unsigned char temp[16];
2150
2151 for (n = ndump; n > 0;) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002152 printf(REG, adrs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153 putchar(' ');
2154 r = n < 16? n: 16;
2155 nr = mread(adrs, temp, r);
2156 adrs += nr;
2157 for (m = 0; m < r; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002158 if ((m & (sizeof(long) - 1)) == 0 && m > 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002159 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160 if (m < nr)
2161 printf("%.2x", temp[m]);
2162 else
2163 printf("%s", fault_chars[fault_type]);
2164 }
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002165 for (; m < 16; ++m) {
Michael Ellermane3bc8042012-08-23 22:09:13 +00002166 if ((m & (sizeof(long) - 1)) == 0)
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002167 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168 printf(" ");
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002169 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002170 printf(" |");
2171 for (m = 0; m < r; ++m) {
2172 if (m < nr) {
2173 c = temp[m];
2174 putchar(' ' <= c && c <= '~'? c: '.');
2175 } else
2176 putchar(' ');
2177 }
2178 n -= r;
2179 for (; m < 16; ++m)
2180 putchar(' ');
2181 printf("|\n");
2182 if (nr < r)
2183 break;
2184 }
2185}
2186
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002187typedef int (*instruction_dump_func)(unsigned long inst, unsigned long addr);
2188
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002189static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002190generic_inst_dump(unsigned long adr, long count, int praddr,
2191 instruction_dump_func dump_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192{
2193 int nr, dotted;
2194 unsigned long first_adr;
2195 unsigned long inst, last_inst = 0;
2196 unsigned char val[4];
2197
2198 dotted = 0;
2199 for (first_adr = adr; count > 0; --count, adr += 4) {
2200 nr = mread(adr, val, 4);
2201 if (nr == 0) {
2202 if (praddr) {
2203 const char *x = fault_chars[fault_type];
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002204 printf(REG" %s%s%s%s\n", adr, x, x, x, x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205 }
2206 break;
2207 }
2208 inst = GETWORD(val);
2209 if (adr > first_adr && inst == last_inst) {
2210 if (!dotted) {
2211 printf(" ...\n");
2212 dotted = 1;
2213 }
2214 continue;
2215 }
2216 dotted = 0;
2217 last_inst = inst;
2218 if (praddr)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002219 printf(REG" %.8x", adr, inst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220 printf("\t");
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002221 dump_func(inst, adr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222 printf("\n");
2223 }
2224 return adr - first_adr;
2225}
2226
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002227static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002228ppc_inst_dump(unsigned long adr, long count, int praddr)
2229{
2230 return generic_inst_dump(adr, count, praddr, print_insn_powerpc);
2231}
2232
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233void
2234print_address(unsigned long addr)
2235{
2236 xmon_print_symbol(addr, "\t# ", "");
2237}
2238
Vinay Sridharf312deb2009-05-14 23:13:07 +00002239void
2240dump_log_buf(void)
2241{
Michael Ellermanca5dd392012-08-23 22:09:12 +00002242 struct kmsg_dumper dumper = { .active = 1 };
2243 unsigned char buf[128];
2244 size_t len;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002245
Michael Ellermane3bc8042012-08-23 22:09:13 +00002246 if (setjmp(bus_error_jmp) != 0) {
Michael Ellermanca5dd392012-08-23 22:09:12 +00002247 printf("Error dumping printk buffer!\n");
Michael Ellermane3bc8042012-08-23 22:09:13 +00002248 return;
2249 }
Vinay Sridharf312deb2009-05-14 23:13:07 +00002250
Michael Ellermane3bc8042012-08-23 22:09:13 +00002251 catch_memory_errors = 1;
2252 sync();
Vinay Sridharf312deb2009-05-14 23:13:07 +00002253
Michael Ellermanca5dd392012-08-23 22:09:12 +00002254 kmsg_dump_rewind_nolock(&dumper);
2255 while (kmsg_dump_get_line_nolock(&dumper, false, buf, sizeof(buf), &len)) {
2256 buf[len] = '\0';
2257 printf("%s", buf);
2258 }
Vinay Sridharf312deb2009-05-14 23:13:07 +00002259
Michael Ellermane3bc8042012-08-23 22:09:13 +00002260 sync();
2261 /* wait a little while to see if we get a machine check */
2262 __delay(200);
2263 catch_memory_errors = 0;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002264}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265
2266/*
2267 * Memory operations - move, set, print differences
2268 */
2269static unsigned long mdest; /* destination address */
2270static unsigned long msrc; /* source address */
2271static unsigned long mval; /* byte value to set memory to */
2272static unsigned long mcount; /* # bytes to affect */
2273static unsigned long mdiffs; /* max # differences to print */
2274
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002275static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002276memops(int cmd)
2277{
2278 scanhex((void *)&mdest);
2279 if( termch != '\n' )
2280 termch = 0;
2281 scanhex((void *)(cmd == 's'? &mval: &msrc));
2282 if( termch != '\n' )
2283 termch = 0;
2284 scanhex((void *)&mcount);
2285 switch( cmd ){
2286 case 'm':
2287 memmove((void *)mdest, (void *)msrc, mcount);
2288 break;
2289 case 's':
2290 memset((void *)mdest, mval, mcount);
2291 break;
2292 case 'd':
2293 if( termch != '\n' )
2294 termch = 0;
2295 scanhex((void *)&mdiffs);
2296 memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
2297 break;
2298 }
2299}
2300
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002301static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
2303{
2304 unsigned n, prt;
2305
2306 prt = 0;
2307 for( n = nb; n > 0; --n )
2308 if( *p1++ != *p2++ )
2309 if( ++prt <= maxpr )
2310 printf("%.16x %.2x # %.16x %.2x\n", p1 - 1,
2311 p1[-1], p2 - 1, p2[-1]);
2312 if( prt > maxpr )
2313 printf("Total of %d differences\n", prt);
2314}
2315
2316static unsigned mend;
2317static unsigned mask;
2318
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002319static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320memlocate(void)
2321{
2322 unsigned a, n;
2323 unsigned char val[4];
2324
2325 last_cmd = "ml";
2326 scanhex((void *)&mdest);
2327 if (termch != '\n') {
2328 termch = 0;
2329 scanhex((void *)&mend);
2330 if (termch != '\n') {
2331 termch = 0;
2332 scanhex((void *)&mval);
2333 mask = ~0;
2334 if (termch != '\n') termch = 0;
2335 scanhex((void *)&mask);
2336 }
2337 }
2338 n = 0;
2339 for (a = mdest; a < mend; a += 4) {
2340 if (mread(a, val, 4) == 4
2341 && ((GETWORD(val) ^ mval) & mask) == 0) {
2342 printf("%.16x: %.16x\n", a, GETWORD(val));
2343 if (++n >= 10)
2344 break;
2345 }
2346 }
2347}
2348
2349static unsigned long mskip = 0x1000;
2350static unsigned long mlim = 0xffffffff;
2351
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002352static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353memzcan(void)
2354{
2355 unsigned char v;
2356 unsigned a;
2357 int ok, ook;
2358
2359 scanhex(&mdest);
2360 if (termch != '\n') termch = 0;
2361 scanhex(&mskip);
2362 if (termch != '\n') termch = 0;
2363 scanhex(&mlim);
2364 ook = 0;
2365 for (a = mdest; a < mlim; a += mskip) {
2366 ok = mread(a, &v, 1);
2367 if (ok && !ook) {
2368 printf("%.8x .. ", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369 } else if (!ok && ook)
2370 printf("%.8x\n", a - mskip);
2371 ook = ok;
2372 if (a + mskip < a)
2373 break;
2374 }
2375 if (ook)
2376 printf("%.8x\n", a - mskip);
2377}
2378
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002379static void proccall(void)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002380{
2381 unsigned long args[8];
2382 unsigned long ret;
2383 int i;
2384 typedef unsigned long (*callfunc_t)(unsigned long, unsigned long,
2385 unsigned long, unsigned long, unsigned long,
2386 unsigned long, unsigned long, unsigned long);
2387 callfunc_t func;
2388
2389 if (!scanhex(&adrs))
2390 return;
2391 if (termch != '\n')
2392 termch = 0;
2393 for (i = 0; i < 8; ++i)
2394 args[i] = 0;
2395 for (i = 0; i < 8; ++i) {
2396 if (!scanhex(&args[i]) || termch == '\n')
2397 break;
2398 termch = 0;
2399 }
2400 func = (callfunc_t) adrs;
2401 ret = 0;
2402 if (setjmp(bus_error_jmp) == 0) {
2403 catch_memory_errors = 1;
2404 sync();
2405 ret = func(args[0], args[1], args[2], args[3],
2406 args[4], args[5], args[6], args[7]);
2407 sync();
2408 printf("return value is %x\n", ret);
2409 } else {
2410 printf("*** %x exception occurred\n", fault_except);
2411 }
2412 catch_memory_errors = 0;
2413}
2414
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415/* Input scanning routines */
2416int
2417skipbl(void)
2418{
2419 int c;
2420
2421 if( termch != 0 ){
2422 c = termch;
2423 termch = 0;
2424 } else
2425 c = inchar();
2426 while( c == ' ' || c == '\t' )
2427 c = inchar();
2428 return c;
2429}
2430
2431#define N_PTREGS 44
2432static char *regnames[N_PTREGS] = {
2433 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
2434 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
2435 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
2436 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002437 "pc", "msr", "or3", "ctr", "lr", "xer", "ccr",
2438#ifdef CONFIG_PPC64
2439 "softe",
2440#else
2441 "mq",
2442#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443 "trap", "dar", "dsisr", "res"
2444};
2445
2446int
2447scanhex(unsigned long *vp)
2448{
2449 int c, d;
2450 unsigned long v;
2451
2452 c = skipbl();
2453 if (c == '%') {
2454 /* parse register name */
2455 char regname[8];
2456 int i;
2457
2458 for (i = 0; i < sizeof(regname) - 1; ++i) {
2459 c = inchar();
2460 if (!isalnum(c)) {
2461 termch = c;
2462 break;
2463 }
2464 regname[i] = c;
2465 }
2466 regname[i] = 0;
2467 for (i = 0; i < N_PTREGS; ++i) {
2468 if (strcmp(regnames[i], regname) == 0) {
2469 if (xmon_regs == NULL) {
2470 printf("regs not available\n");
2471 return 0;
2472 }
2473 *vp = ((unsigned long *)xmon_regs)[i];
2474 return 1;
2475 }
2476 }
2477 printf("invalid register name '%%%s'\n", regname);
2478 return 0;
2479 }
2480
2481 /* skip leading "0x" if any */
2482
2483 if (c == '0') {
2484 c = inchar();
2485 if (c == 'x') {
2486 c = inchar();
2487 } else {
2488 d = hexdigit(c);
2489 if (d == EOF) {
2490 termch = c;
2491 *vp = 0;
2492 return 1;
2493 }
2494 }
2495 } else if (c == '$') {
2496 int i;
2497 for (i=0; i<63; i++) {
2498 c = inchar();
2499 if (isspace(c)) {
2500 termch = c;
2501 break;
2502 }
2503 tmpstr[i] = c;
2504 }
2505 tmpstr[i++] = 0;
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07002506 *vp = 0;
2507 if (setjmp(bus_error_jmp) == 0) {
2508 catch_memory_errors = 1;
2509 sync();
2510 *vp = kallsyms_lookup_name(tmpstr);
2511 sync();
2512 }
2513 catch_memory_errors = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514 if (!(*vp)) {
2515 printf("unknown symbol '%s'\n", tmpstr);
2516 return 0;
2517 }
2518 return 1;
2519 }
2520
2521 d = hexdigit(c);
2522 if (d == EOF) {
2523 termch = c;
2524 return 0;
2525 }
2526 v = 0;
2527 do {
2528 v = (v << 4) + d;
2529 c = inchar();
2530 d = hexdigit(c);
2531 } while (d != EOF);
2532 termch = c;
2533 *vp = v;
2534 return 1;
2535}
2536
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002537static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538scannl(void)
2539{
2540 int c;
2541
2542 c = termch;
2543 termch = 0;
2544 while( c != '\n' )
2545 c = inchar();
2546}
2547
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002548static int hexdigit(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549{
2550 if( '0' <= c && c <= '9' )
2551 return c - '0';
2552 if( 'A' <= c && c <= 'F' )
2553 return c - ('A' - 10);
2554 if( 'a' <= c && c <= 'f' )
2555 return c - ('a' - 10);
2556 return EOF;
2557}
2558
2559void
2560getstring(char *s, int size)
2561{
2562 int c;
2563
2564 c = skipbl();
2565 do {
2566 if( size > 1 ){
2567 *s++ = c;
2568 --size;
2569 }
2570 c = inchar();
2571 } while( c != ' ' && c != '\t' && c != '\n' );
2572 termch = c;
2573 *s = 0;
2574}
2575
2576static char line[256];
2577static char *lineptr;
2578
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002579static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580flush_input(void)
2581{
2582 lineptr = NULL;
2583}
2584
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002585static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586inchar(void)
2587{
2588 if (lineptr == NULL || *lineptr == 0) {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002589 if (xmon_gets(line, sizeof(line)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590 lineptr = NULL;
2591 return EOF;
2592 }
2593 lineptr = line;
2594 }
2595 return *lineptr++;
2596}
2597
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002598static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599take_input(char *str)
2600{
2601 lineptr = str;
2602}
2603
2604
2605static void
2606symbol_lookup(void)
2607{
2608 int type = inchar();
2609 unsigned long addr;
2610 static char tmp[64];
2611
2612 switch (type) {
2613 case 'a':
2614 if (scanhex(&addr))
2615 xmon_print_symbol(addr, ": ", "\n");
2616 termch = 0;
2617 break;
2618 case 's':
2619 getstring(tmp, 64);
2620 if (setjmp(bus_error_jmp) == 0) {
2621 catch_memory_errors = 1;
2622 sync();
2623 addr = kallsyms_lookup_name(tmp);
2624 if (addr)
2625 printf("%s: %lx\n", tmp, addr);
2626 else
2627 printf("Symbol '%s' not found.\n", tmp);
2628 sync();
2629 }
2630 catch_memory_errors = 0;
2631 termch = 0;
2632 break;
2633 }
2634}
2635
2636
2637/* Print an address in numeric and symbolic form (if possible) */
2638static void xmon_print_symbol(unsigned long address, const char *mid,
2639 const char *after)
2640{
2641 char *modname;
2642 const char *name = NULL;
2643 unsigned long offset, size;
2644
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002645 printf(REG, address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646 if (setjmp(bus_error_jmp) == 0) {
2647 catch_memory_errors = 1;
2648 sync();
2649 name = kallsyms_lookup(address, &size, &offset, &modname,
2650 tmpstr);
2651 sync();
2652 /* wait a little while to see if we get a machine check */
2653 __delay(200);
2654 }
2655
2656 catch_memory_errors = 0;
2657
2658 if (name) {
2659 printf("%s%s+%#lx/%#lx", mid, name, offset, size);
2660 if (modname)
2661 printf(" [%s]", modname);
2662 }
2663 printf("%s", after);
2664}
2665
Benjamin Herrenschmidt2d27cfd2009-07-23 23:15:59 +00002666#ifdef CONFIG_PPC_BOOK3S_64
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667static void dump_slb(void)
2668{
2669 int i;
will schmidtb3b95952007-12-07 08:22:23 +11002670 unsigned long esid,vsid,valid;
2671 unsigned long llp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672
2673 printf("SLB contents of cpu %x\n", smp_processor_id());
2674
Michael Neuling584f8b72007-12-06 17:24:48 +11002675 for (i = 0; i < mmu_slb_size; i++) {
will schmidtb3b95952007-12-07 08:22:23 +11002676 asm volatile("slbmfee %0,%1" : "=r" (esid) : "r" (i));
2677 asm volatile("slbmfev %0,%1" : "=r" (vsid) : "r" (i));
2678 valid = (esid & SLB_ESID_V);
2679 if (valid | esid | vsid) {
2680 printf("%02d %016lx %016lx", i, esid, vsid);
2681 if (valid) {
2682 llp = vsid & SLB_VSID_LLP;
2683 if (vsid & SLB_VSID_B_1T) {
2684 printf(" 1T ESID=%9lx VSID=%13lx LLP:%3lx \n",
2685 GET_ESID_1T(esid),
2686 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT_1T,
2687 llp);
2688 } else {
2689 printf(" 256M ESID=%9lx VSID=%13lx LLP:%3lx \n",
2690 GET_ESID(esid),
2691 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT,
2692 llp);
2693 }
2694 } else
2695 printf("\n");
2696 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697 }
2698}
2699
2700static void dump_stab(void)
2701{
2702 int i;
Benjamin Herrenschmidt7ac21cd2012-03-02 10:10:09 +11002703 unsigned long *tmp = (unsigned long *)local_paca->stab_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704
2705 printf("Segment table contents of cpu %x\n", smp_processor_id());
2706
2707 for (i = 0; i < PAGE_SIZE/16; i++) {
2708 unsigned long a, b;
2709
2710 a = *tmp++;
2711 b = *tmp++;
2712
2713 if (a || b) {
2714 printf("%03d %016lx ", i, a);
2715 printf("%016lx\n", b);
2716 }
2717 }
2718}
2719
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002720void dump_segments(void)
2721{
Matt Evans44ae3ab2011-04-06 19:48:50 +00002722 if (mmu_has_feature(MMU_FTR_SLB))
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002723 dump_slb();
2724 else
2725 dump_stab();
2726}
2727#endif
2728
2729#ifdef CONFIG_PPC_STD_MMU_32
2730void dump_segments(void)
2731{
2732 int i;
2733
2734 printf("sr0-15 =");
2735 for (i = 0; i < 16; ++i)
2736 printf(" %x", mfsrin(i));
2737 printf("\n");
2738}
2739#endif
2740
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11002741#ifdef CONFIG_44x
2742static void dump_tlb_44x(void)
2743{
2744 int i;
2745
2746 for (i = 0; i < PPC44x_TLB_SIZE; i++) {
2747 unsigned long w0,w1,w2;
2748 asm volatile("tlbre %0,%1,0" : "=r" (w0) : "r" (i));
2749 asm volatile("tlbre %0,%1,1" : "=r" (w1) : "r" (i));
2750 asm volatile("tlbre %0,%1,2" : "=r" (w2) : "r" (i));
2751 printf("[%02x] %08x %08x %08x ", i, w0, w1, w2);
2752 if (w0 & PPC44x_TLB_VALID) {
2753 printf("V %08x -> %01x%08x %c%c%c%c%c",
2754 w0 & PPC44x_TLB_EPN_MASK,
2755 w1 & PPC44x_TLB_ERPN_MASK,
2756 w1 & PPC44x_TLB_RPN_MASK,
2757 (w2 & PPC44x_TLB_W) ? 'W' : 'w',
2758 (w2 & PPC44x_TLB_I) ? 'I' : 'i',
2759 (w2 & PPC44x_TLB_M) ? 'M' : 'm',
2760 (w2 & PPC44x_TLB_G) ? 'G' : 'g',
2761 (w2 & PPC44x_TLB_E) ? 'E' : 'e');
2762 }
2763 printf("\n");
2764 }
2765}
2766#endif /* CONFIG_44x */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002767
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +10002768#ifdef CONFIG_PPC_BOOK3E
2769static void dump_tlb_book3e(void)
2770{
2771 u32 mmucfg, pidmask, lpidmask;
2772 u64 ramask;
2773 int i, tlb, ntlbs, pidsz, lpidsz, rasz, lrat = 0;
2774 int mmu_version;
2775 static const char *pgsz_names[] = {
2776 " 1K",
2777 " 2K",
2778 " 4K",
2779 " 8K",
2780 " 16K",
2781 " 32K",
2782 " 64K",
2783 "128K",
2784 "256K",
2785 "512K",
2786 " 1M",
2787 " 2M",
2788 " 4M",
2789 " 8M",
2790 " 16M",
2791 " 32M",
2792 " 64M",
2793 "128M",
2794 "256M",
2795 "512M",
2796 " 1G",
2797 " 2G",
2798 " 4G",
2799 " 8G",
2800 " 16G",
2801 " 32G",
2802 " 64G",
2803 "128G",
2804 "256G",
2805 "512G",
2806 " 1T",
2807 " 2T",
2808 };
2809
2810 /* Gather some infos about the MMU */
2811 mmucfg = mfspr(SPRN_MMUCFG);
2812 mmu_version = (mmucfg & 3) + 1;
2813 ntlbs = ((mmucfg >> 2) & 3) + 1;
2814 pidsz = ((mmucfg >> 6) & 0x1f) + 1;
2815 lpidsz = (mmucfg >> 24) & 0xf;
2816 rasz = (mmucfg >> 16) & 0x7f;
2817 if ((mmu_version > 1) && (mmucfg & 0x10000))
2818 lrat = 1;
2819 printf("Book3E MMU MAV=%d.0,%d TLBs,%d-bit PID,%d-bit LPID,%d-bit RA\n",
2820 mmu_version, ntlbs, pidsz, lpidsz, rasz);
2821 pidmask = (1ul << pidsz) - 1;
2822 lpidmask = (1ul << lpidsz) - 1;
2823 ramask = (1ull << rasz) - 1;
2824
2825 for (tlb = 0; tlb < ntlbs; tlb++) {
2826 u32 tlbcfg;
2827 int nent, assoc, new_cc = 1;
2828 printf("TLB %d:\n------\n", tlb);
2829 switch(tlb) {
2830 case 0:
2831 tlbcfg = mfspr(SPRN_TLB0CFG);
2832 break;
2833 case 1:
2834 tlbcfg = mfspr(SPRN_TLB1CFG);
2835 break;
2836 case 2:
2837 tlbcfg = mfspr(SPRN_TLB2CFG);
2838 break;
2839 case 3:
2840 tlbcfg = mfspr(SPRN_TLB3CFG);
2841 break;
2842 default:
2843 printf("Unsupported TLB number !\n");
2844 continue;
2845 }
2846 nent = tlbcfg & 0xfff;
2847 assoc = (tlbcfg >> 24) & 0xff;
2848 for (i = 0; i < nent; i++) {
2849 u32 mas0 = MAS0_TLBSEL(tlb);
2850 u32 mas1 = MAS1_TSIZE(BOOK3E_PAGESZ_4K);
2851 u64 mas2 = 0;
2852 u64 mas7_mas3;
2853 int esel = i, cc = i;
2854
2855 if (assoc != 0) {
2856 cc = i / assoc;
2857 esel = i % assoc;
2858 mas2 = cc * 0x1000;
2859 }
2860
2861 mas0 |= MAS0_ESEL(esel);
2862 mtspr(SPRN_MAS0, mas0);
2863 mtspr(SPRN_MAS1, mas1);
2864 mtspr(SPRN_MAS2, mas2);
2865 asm volatile("tlbre 0,0,0" : : : "memory");
2866 mas1 = mfspr(SPRN_MAS1);
2867 mas2 = mfspr(SPRN_MAS2);
2868 mas7_mas3 = mfspr(SPRN_MAS7_MAS3);
2869 if (assoc && (i % assoc) == 0)
2870 new_cc = 1;
2871 if (!(mas1 & MAS1_VALID))
2872 continue;
2873 if (assoc == 0)
2874 printf("%04x- ", i);
2875 else if (new_cc)
2876 printf("%04x-%c", cc, 'A' + esel);
2877 else
2878 printf(" |%c", 'A' + esel);
2879 new_cc = 0;
2880 printf(" %016llx %04x %s %c%c AS%c",
2881 mas2 & ~0x3ffull,
2882 (mas1 >> 16) & 0x3fff,
2883 pgsz_names[(mas1 >> 7) & 0x1f],
2884 mas1 & MAS1_IND ? 'I' : ' ',
2885 mas1 & MAS1_IPROT ? 'P' : ' ',
2886 mas1 & MAS1_TS ? '1' : '0');
2887 printf(" %c%c%c%c%c%c%c",
2888 mas2 & MAS2_X0 ? 'a' : ' ',
2889 mas2 & MAS2_X1 ? 'v' : ' ',
2890 mas2 & MAS2_W ? 'w' : ' ',
2891 mas2 & MAS2_I ? 'i' : ' ',
2892 mas2 & MAS2_M ? 'm' : ' ',
2893 mas2 & MAS2_G ? 'g' : ' ',
2894 mas2 & MAS2_E ? 'e' : ' ');
2895 printf(" %016llx", mas7_mas3 & ramask & ~0x7ffull);
2896 if (mas1 & MAS1_IND)
2897 printf(" %s\n",
2898 pgsz_names[(mas7_mas3 >> 1) & 0x1f]);
2899 else
2900 printf(" U%c%c%c S%c%c%c\n",
2901 mas7_mas3 & MAS3_UX ? 'x' : ' ',
2902 mas7_mas3 & MAS3_UW ? 'w' : ' ',
2903 mas7_mas3 & MAS3_UR ? 'r' : ' ',
2904 mas7_mas3 & MAS3_SX ? 'x' : ' ',
2905 mas7_mas3 & MAS3_SW ? 'w' : ' ',
2906 mas7_mas3 & MAS3_SR ? 'r' : ' ');
2907 }
2908 }
2909}
2910#endif /* CONFIG_PPC_BOOK3E */
2911
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002912static void xmon_init(int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913{
Olaf Heringb13cfd172005-08-04 19:26:42 +02002914 if (enable) {
2915 __debugger = xmon;
2916 __debugger_ipi = xmon_ipi;
2917 __debugger_bpt = xmon_bpt;
2918 __debugger_sstep = xmon_sstep;
2919 __debugger_iabr_match = xmon_iabr_match;
2920 __debugger_dabr_match = xmon_dabr_match;
2921 __debugger_fault_handler = xmon_fault_handler;
2922 } else {
2923 __debugger = NULL;
2924 __debugger_ipi = NULL;
2925 __debugger_bpt = NULL;
2926 __debugger_sstep = NULL;
2927 __debugger_iabr_match = NULL;
2928 __debugger_dabr_match = NULL;
2929 __debugger_fault_handler = NULL;
2930 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002931}
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002932
2933#ifdef CONFIG_MAGIC_SYSRQ
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07002934static void sysrq_handle_xmon(int key)
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002935{
2936 /* ensure xmon is enabled */
2937 xmon_init(1);
David Howells7d12e782006-10-05 14:55:46 +01002938 debugger(get_irq_regs());
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002939}
2940
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07002941static struct sysrq_key_op sysrq_xmon_op = {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002942 .handler = sysrq_handle_xmon,
2943 .help_msg = "Xmon",
2944 .action_msg = "Entering xmon",
2945};
2946
2947static int __init setup_xmon_sysrq(void)
2948{
2949 register_sysrq_key('x', &sysrq_xmon_op);
2950 return 0;
2951}
2952__initcall(setup_xmon_sysrq);
2953#endif /* CONFIG_MAGIC_SYSRQ */
Michael Ellerman476792832006-10-03 14:12:08 +10002954
Olaf Heringf5e6a282007-06-24 16:57:08 +10002955static int __initdata xmon_early, xmon_off;
Michael Ellerman476792832006-10-03 14:12:08 +10002956
2957static int __init early_parse_xmon(char *p)
2958{
2959 if (!p || strncmp(p, "early", 5) == 0) {
2960 /* just "xmon" is equivalent to "xmon=early" */
2961 xmon_init(1);
2962 xmon_early = 1;
2963 } else if (strncmp(p, "on", 2) == 0)
2964 xmon_init(1);
2965 else if (strncmp(p, "off", 3) == 0)
2966 xmon_off = 1;
2967 else if (strncmp(p, "nobt", 4) == 0)
2968 xmon_no_auto_backtrace = 1;
2969 else
2970 return 1;
2971
2972 return 0;
2973}
2974early_param("xmon", early_parse_xmon);
2975
2976void __init xmon_setup(void)
2977{
2978#ifdef CONFIG_XMON_DEFAULT
2979 if (!xmon_off)
2980 xmon_init(1);
2981#endif
2982 if (xmon_early)
2983 debugger(NULL);
2984}
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002985
Arnd Bergmanne0555952006-11-27 19:18:55 +01002986#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002987
2988struct spu_info {
2989 struct spu *spu;
2990 u64 saved_mfc_sr1_RW;
2991 u32 saved_spu_runcntl_RW;
Michael Ellerman24a24c82006-11-23 00:46:41 +01002992 unsigned long dump_addr;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002993 u8 stopped_ok;
2994};
2995
2996#define XMON_NUM_SPUS 16 /* Enough for current hardware */
2997
2998static struct spu_info spu_info[XMON_NUM_SPUS];
2999
3000void xmon_register_spus(struct list_head *list)
3001{
3002 struct spu *spu;
3003
3004 list_for_each_entry(spu, list, full_list) {
3005 if (spu->number >= XMON_NUM_SPUS) {
3006 WARN_ON(1);
3007 continue;
3008 }
3009
3010 spu_info[spu->number].spu = spu;
3011 spu_info[spu->number].stopped_ok = 0;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003012 spu_info[spu->number].dump_addr = (unsigned long)
3013 spu_info[spu->number].spu->local_store;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003014 }
3015}
3016
3017static void stop_spus(void)
3018{
3019 struct spu *spu;
3020 int i;
3021 u64 tmp;
3022
3023 for (i = 0; i < XMON_NUM_SPUS; i++) {
3024 if (!spu_info[i].spu)
3025 continue;
3026
3027 if (setjmp(bus_error_jmp) == 0) {
3028 catch_memory_errors = 1;
3029 sync();
3030
3031 spu = spu_info[i].spu;
3032
3033 spu_info[i].saved_spu_runcntl_RW =
3034 in_be32(&spu->problem->spu_runcntl_RW);
3035
3036 tmp = spu_mfc_sr1_get(spu);
3037 spu_info[i].saved_mfc_sr1_RW = tmp;
3038
3039 tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
3040 spu_mfc_sr1_set(spu, tmp);
3041
3042 sync();
3043 __delay(200);
3044
3045 spu_info[i].stopped_ok = 1;
Michael Ellerman2a144422006-11-23 00:46:40 +01003046
3047 printf("Stopped spu %.2d (was %s)\n", i,
3048 spu_info[i].saved_spu_runcntl_RW ?
3049 "running" : "stopped");
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003050 } else {
3051 catch_memory_errors = 0;
3052 printf("*** Error stopping spu %.2d\n", i);
3053 }
3054 catch_memory_errors = 0;
3055 }
3056}
3057
3058static void restart_spus(void)
3059{
3060 struct spu *spu;
3061 int i;
3062
3063 for (i = 0; i < XMON_NUM_SPUS; i++) {
3064 if (!spu_info[i].spu)
3065 continue;
3066
3067 if (!spu_info[i].stopped_ok) {
3068 printf("*** Error, spu %d was not successfully stopped"
3069 ", not restarting\n", i);
3070 continue;
3071 }
3072
3073 if (setjmp(bus_error_jmp) == 0) {
3074 catch_memory_errors = 1;
3075 sync();
3076
3077 spu = spu_info[i].spu;
3078 spu_mfc_sr1_set(spu, spu_info[i].saved_mfc_sr1_RW);
3079 out_be32(&spu->problem->spu_runcntl_RW,
3080 spu_info[i].saved_spu_runcntl_RW);
3081
3082 sync();
3083 __delay(200);
3084
3085 printf("Restarted spu %.2d\n", i);
3086 } else {
3087 catch_memory_errors = 0;
3088 printf("*** Error restarting spu %.2d\n", i);
3089 }
3090 catch_memory_errors = 0;
3091 }
3092}
3093
Michael Ellermana8984972006-10-24 18:31:28 +02003094#define DUMP_WIDTH 23
Michael Ellerman437a0702006-11-23 00:46:39 +01003095#define DUMP_VALUE(format, field, value) \
Michael Ellermana8984972006-10-24 18:31:28 +02003096do { \
3097 if (setjmp(bus_error_jmp) == 0) { \
3098 catch_memory_errors = 1; \
3099 sync(); \
3100 printf(" %-*s = "format"\n", DUMP_WIDTH, \
Michael Ellerman437a0702006-11-23 00:46:39 +01003101 #field, value); \
Michael Ellermana8984972006-10-24 18:31:28 +02003102 sync(); \
3103 __delay(200); \
3104 } else { \
3105 catch_memory_errors = 0; \
3106 printf(" %-*s = *** Error reading field.\n", \
3107 DUMP_WIDTH, #field); \
3108 } \
3109 catch_memory_errors = 0; \
3110} while (0)
3111
Michael Ellerman437a0702006-11-23 00:46:39 +01003112#define DUMP_FIELD(obj, format, field) \
3113 DUMP_VALUE(format, field, obj->field)
3114
Michael Ellermana8984972006-10-24 18:31:28 +02003115static void dump_spu_fields(struct spu *spu)
3116{
3117 printf("Dumping spu fields at address %p:\n", spu);
3118
3119 DUMP_FIELD(spu, "0x%x", number);
3120 DUMP_FIELD(spu, "%s", name);
Michael Ellermana8984972006-10-24 18:31:28 +02003121 DUMP_FIELD(spu, "0x%lx", local_store_phys);
3122 DUMP_FIELD(spu, "0x%p", local_store);
3123 DUMP_FIELD(spu, "0x%lx", ls_size);
3124 DUMP_FIELD(spu, "0x%x", node);
3125 DUMP_FIELD(spu, "0x%lx", flags);
Michael Ellermana8984972006-10-24 18:31:28 +02003126 DUMP_FIELD(spu, "%d", class_0_pending);
Luke Browningf3d69e02008-04-27 18:41:55 +00003127 DUMP_FIELD(spu, "0x%lx", class_0_dar);
Luke Browningf3d69e02008-04-27 18:41:55 +00003128 DUMP_FIELD(spu, "0x%lx", class_1_dar);
3129 DUMP_FIELD(spu, "0x%lx", class_1_dsisr);
Michael Ellermana8984972006-10-24 18:31:28 +02003130 DUMP_FIELD(spu, "0x%lx", irqs[0]);
3131 DUMP_FIELD(spu, "0x%lx", irqs[1]);
3132 DUMP_FIELD(spu, "0x%lx", irqs[2]);
3133 DUMP_FIELD(spu, "0x%x", slb_replace);
3134 DUMP_FIELD(spu, "%d", pid);
Michael Ellermana8984972006-10-24 18:31:28 +02003135 DUMP_FIELD(spu, "0x%p", mm);
3136 DUMP_FIELD(spu, "0x%p", ctx);
3137 DUMP_FIELD(spu, "0x%p", rq);
3138 DUMP_FIELD(spu, "0x%p", timestamp);
3139 DUMP_FIELD(spu, "0x%lx", problem_phys);
3140 DUMP_FIELD(spu, "0x%p", problem);
Michael Ellerman437a0702006-11-23 00:46:39 +01003141 DUMP_VALUE("0x%x", problem->spu_runcntl_RW,
3142 in_be32(&spu->problem->spu_runcntl_RW));
3143 DUMP_VALUE("0x%x", problem->spu_status_R,
3144 in_be32(&spu->problem->spu_status_R));
3145 DUMP_VALUE("0x%x", problem->spu_npc_RW,
3146 in_be32(&spu->problem->spu_npc_RW));
Michael Ellermana8984972006-10-24 18:31:28 +02003147 DUMP_FIELD(spu, "0x%p", priv2);
Michael Ellermana9852392006-11-23 00:46:50 +01003148 DUMP_FIELD(spu, "0x%p", pdata);
Michael Ellermana8984972006-10-24 18:31:28 +02003149}
3150
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003151int
3152spu_inst_dump(unsigned long adr, long count, int praddr)
3153{
3154 return generic_inst_dump(adr, count, praddr, print_insn_spu);
3155}
3156
3157static void dump_spu_ls(unsigned long num, int subcmd)
Michael Ellerman24a24c82006-11-23 00:46:41 +01003158{
3159 unsigned long offset, addr, ls_addr;
3160
3161 if (setjmp(bus_error_jmp) == 0) {
3162 catch_memory_errors = 1;
3163 sync();
3164 ls_addr = (unsigned long)spu_info[num].spu->local_store;
3165 sync();
3166 __delay(200);
3167 } else {
3168 catch_memory_errors = 0;
3169 printf("*** Error: accessing spu info for spu %d\n", num);
3170 return;
3171 }
3172 catch_memory_errors = 0;
3173
3174 if (scanhex(&offset))
3175 addr = ls_addr + offset;
3176 else
3177 addr = spu_info[num].dump_addr;
3178
3179 if (addr >= ls_addr + LS_SIZE) {
3180 printf("*** Error: address outside of local store\n");
3181 return;
3182 }
3183
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003184 switch (subcmd) {
3185 case 'i':
3186 addr += spu_inst_dump(addr, 16, 1);
3187 last_cmd = "sdi\n";
3188 break;
3189 default:
3190 prdump(addr, 64);
3191 addr += 64;
3192 last_cmd = "sd\n";
3193 break;
3194 }
Michael Ellerman24a24c82006-11-23 00:46:41 +01003195
3196 spu_info[num].dump_addr = addr;
3197}
3198
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003199static int do_spu_cmd(void)
3200{
Michael Ellerman24a24c82006-11-23 00:46:41 +01003201 static unsigned long num = 0;
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003202 int cmd, subcmd = 0;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003203
3204 cmd = inchar();
3205 switch (cmd) {
3206 case 's':
3207 stop_spus();
3208 break;
3209 case 'r':
3210 restart_spus();
3211 break;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003212 case 'd':
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003213 subcmd = inchar();
3214 if (isxdigit(subcmd) || subcmd == '\n')
3215 termch = subcmd;
3216 case 'f':
Michael Ellerman24a24c82006-11-23 00:46:41 +01003217 scanhex(&num);
3218 if (num >= XMON_NUM_SPUS || !spu_info[num].spu) {
Michael Ellermana8984972006-10-24 18:31:28 +02003219 printf("*** Error: invalid spu number\n");
Michael Ellerman24a24c82006-11-23 00:46:41 +01003220 return 0;
3221 }
3222
3223 switch (cmd) {
3224 case 'f':
3225 dump_spu_fields(spu_info[num].spu);
3226 break;
3227 default:
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003228 dump_spu_ls(num, subcmd);
Michael Ellerman24a24c82006-11-23 00:46:41 +01003229 break;
3230 }
3231
Michael Ellermana8984972006-10-24 18:31:28 +02003232 break;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003233 default:
3234 return -1;
3235 }
3236
3237 return 0;
3238}
Arnd Bergmanne0555952006-11-27 19:18:55 +01003239#else /* ! CONFIG_SPU_BASE */
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003240static int do_spu_cmd(void)
3241{
3242 return -1;
3243}
3244#endif