blob: 974a47b3c9b8899ea38cc3df90a78b2156d47374 [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>
20#include <linux/cpumask.h>
Paul Gortmaker4b16f8e2011-07-22 18:24:23 -040021#include <linux/export.h>
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +110022#include <linux/sysrq.h>
Andrew Morton4694ca02005-11-13 16:06:50 -080023#include <linux/interrupt.h>
David Howells7d12e782006-10-05 14:55:46 +010024#include <linux/irq.h>
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -080025#include <linux/bug.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026
27#include <asm/ptrace.h>
28#include <asm/string.h>
29#include <asm/prom.h>
30#include <asm/machdep.h>
Paul Mackerrasf78541dc2005-10-28 22:53:37 +100031#include <asm/xmon.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <asm/processor.h>
33#include <asm/pgtable.h>
34#include <asm/mmu.h>
35#include <asm/mmu_context.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include <asm/cputable.h>
37#include <asm/rtas.h>
38#include <asm/sstep.h>
Paul Mackerrasf583ffc2006-10-10 11:47:07 +100039#include <asm/irq_regs.h>
Michael Ellermanff8a8f22006-10-24 18:31:27 +020040#include <asm/spu.h>
41#include <asm/spu_priv1.h>
Stephen Rothwell1d135812006-11-13 14:50:28 +110042#include <asm/firmware.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>
Paul Mackerrasf78541dc2005-10-28 22:53:37 +100045
46#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -070047#include <asm/hvcall.h>
Paul Mackerrasf78541dc2005-10-28 22:53:37 +100048#include <asm/paca.h>
49#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070050
51#include "nonstdio.h"
Michael Ellermane0426042006-11-23 00:46:45 +010052#include "dis-asm.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070053
54#define scanhex xmon_scanhex
55#define skipbl xmon_skipbl
56
57#ifdef CONFIG_SMP
Michael Ellerman1c8950f2008-05-08 14:27:17 +100058static cpumask_t cpus_in_xmon = CPU_MASK_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070059static unsigned long xmon_taken = 1;
60static int xmon_owner;
61static int xmon_gate;
62#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"
169#define REGS_PER_LINE 4
170#define LAST_VOLATILE 13
171#else
172#define REG "%.8lx"
173#define REGS_PER_LINE 8
174#define LAST_VOLATILE 12
175#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176
177#define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
178
179#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
180 || ('a' <= (c) && (c) <= 'f') \
181 || ('A' <= (c) && (c) <= 'F'))
182#define isalnum(c) (('0' <= (c) && (c) <= '9') \
183 || ('a' <= (c) && (c) <= 'z') \
184 || ('A' <= (c) && (c) <= 'Z'))
185#define isspace(c) (c == ' ' || c == '\t' || c == 10 || c == 13 || c == 0)
186
187static char *help_string = "\
188Commands:\n\
189 b show breakpoints\n\
190 bd set data breakpoint\n\
191 bi set instruction breakpoint\n\
192 bc clear breakpoint\n"
193#ifdef CONFIG_SMP
194 "\
195 c print cpus stopped in xmon\n\
196 c# try to switch to cpu number h (in hex)\n"
197#endif
198 "\
199 C checksum\n\
200 d dump bytes\n\
201 di dump instructions\n\
202 df dump float values\n\
203 dd dump double values\n\
Vinay Sridharf312deb2009-05-14 23:13:07 +0000204 dl dump the kernel log buffer\n\
Olaf Hering7e5b5932006-03-08 20:40:28 +0100205 dr dump stream of raw bytes\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 e print exception information\n\
207 f flush cache\n\
208 la lookup symbol+offset of specified address\n\
209 ls lookup address of specified symbol\n\
210 m examine/change memory\n\
211 mm move a block of memory\n\
212 ms set a block of memory\n\
213 md compare two blocks of memory\n\
214 ml locate a block of memory\n\
215 mz zero a block of memory\n\
216 mi show information about memory allocation\n\
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000217 p call a procedure\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 r print registers\n\
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200219 s single step\n"
Arnd Bergmanne0555952006-11-27 19:18:55 +0100220#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200221" ss stop execution on all spus\n\
Michael Ellermana8984972006-10-24 18:31:28 +0200222 sr restore execution on stopped spus\n\
Michael Ellerman24a24c82006-11-23 00:46:41 +0100223 sf # dump spu fields for spu # (in hex)\n\
Michael Ellermanc99176a2007-02-26 18:14:06 +0900224 sd # dump spu local store for spu # (in hex)\n\
Michael Ellermanaf89fb82006-11-23 00:46:44 +0100225 sdi # disassemble spu local store for spu # (in hex)\n"
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200226#endif
227" S print special registers\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 t print backtrace\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 x exit monitor and recover\n\
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000230 X exit monitor and dont recover\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000231#if defined(CONFIG_PPC64) && !defined(CONFIG_PPC_BOOK3E)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000232" u dump segment table or SLB\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000233#elif defined(CONFIG_PPC_STD_MMU_32)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000234" u dump segment registers\n"
Jimi Xenidis79873e82011-09-29 11:25:10 +0000235#elif defined(CONFIG_44x) || defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100236" u dump TLB\n"
237#endif
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000238" ? help\n"
239" zr reboot\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 zh halt\n"
241;
242
243static struct pt_regs *xmon_regs;
244
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000245static inline void sync(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246{
247 asm volatile("sync; isync");
248}
249
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000250static inline void store_inst(void *p)
251{
252 asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p));
253}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000255static inline void cflush(void *p)
256{
257 asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p));
258}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000260static inline void cinval(void *p)
261{
262 asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p));
263}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264
265/*
266 * Disable surveillance (the service processor watchdog function)
267 * while we are in xmon.
268 * XXX we should re-enable it when we leave. :)
269 */
270#define SURVEILLANCE_TOKEN 9000
271
272static inline void disable_surveillance(void)
273{
274#ifdef CONFIG_PPC_PSERIES
275 /* Since this can't be a module, args should end up below 4GB. */
276 static struct rtas_args args;
277
278 /*
279 * At this point we have got all the cpus we can into
280 * xmon, so there is hopefully no other cpu calling RTAS
281 * at the moment, even though we don't take rtas.lock.
282 * If we did try to take rtas.lock there would be a
283 * real possibility of deadlock.
284 */
285 args.token = rtas_token("set-indicator");
286 if (args.token == RTAS_UNKNOWN_SERVICE)
287 return;
288 args.nargs = 3;
289 args.nret = 1;
290 args.rets = &args.args[3];
291 args.args[0] = SURVEILLANCE_TOKEN;
292 args.args[1] = 0;
293 args.args[2] = 0;
294 enter_rtas(__pa(&args));
295#endif /* CONFIG_PPC_PSERIES */
296}
297
298#ifdef CONFIG_SMP
299static int xmon_speaker;
300
301static void get_output_lock(void)
302{
303 int me = smp_processor_id() + 0x100;
304 int last_speaker = 0, prev;
305 long timeout;
306
307 if (xmon_speaker == me)
308 return;
309 for (;;) {
310 if (xmon_speaker == 0) {
311 last_speaker = cmpxchg(&xmon_speaker, 0, me);
312 if (last_speaker == 0)
313 return;
314 }
315 timeout = 10000000;
316 while (xmon_speaker == last_speaker) {
317 if (--timeout > 0)
318 continue;
319 /* hostile takeover */
320 prev = cmpxchg(&xmon_speaker, last_speaker, me);
321 if (prev == last_speaker)
322 return;
323 break;
324 }
325 }
326}
327
328static void release_output_lock(void)
329{
330 xmon_speaker = 0;
331}
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000332
333int cpus_are_in_xmon(void)
334{
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000335 return !cpumask_empty(&cpus_in_xmon);
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000336}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337#endif
338
Josh Boyerdaf8f402009-09-23 03:51:04 +0000339static inline int unrecoverable_excp(struct pt_regs *regs)
340{
Jimi Xenidis08f6d6a2011-09-29 12:05:28 +0000341#if defined(CONFIG_4xx) || defined(CONFIG_PPC_BOOK3E)
Jimi Xenidis66857b32011-09-23 05:40:46 +0000342 /* We have no MSR_RI bit on 4xx or Book3e, so we simply return false */
Josh Boyerdaf8f402009-09-23 03:51:04 +0000343 return 0;
344#else
345 return ((regs->msr & MSR_RI) == 0);
346#endif
347}
348
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000349static int xmon_core(struct pt_regs *regs, int fromipi)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350{
351 int cmd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 struct bpt *bp;
353 long recurse_jmp[JMP_BUF_LEN];
354 unsigned long offset;
Anton Blanchardf13659e2007-03-21 01:48:34 +1100355 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356#ifdef CONFIG_SMP
357 int cpu;
358 int secondary;
359 unsigned long timeout;
360#endif
361
Anton Blanchardf13659e2007-03-21 01:48:34 +1100362 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363
364 bp = in_breakpoint_table(regs->nip, &offset);
365 if (bp != NULL) {
366 regs->nip = bp->address + offset;
367 atomic_dec(&bp->ref_count);
368 }
369
370 remove_cpu_bpts();
371
372#ifdef CONFIG_SMP
373 cpu = smp_processor_id();
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000374 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 get_output_lock();
376 excprint(regs);
377 printf("cpu 0x%x: Exception %lx %s in xmon, "
378 "returning to main loop\n",
379 cpu, regs->trap, getvecname(TRAP(regs)));
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000380 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 longjmp(xmon_fault_jmp[cpu], 1);
382 }
383
384 if (setjmp(recurse_jmp) != 0) {
385 if (!in_xmon || !xmon_gate) {
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000386 get_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 printf("xmon: WARNING: bad recursive fault "
388 "on cpu 0x%x\n", cpu);
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000389 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 goto waiting;
391 }
392 secondary = !(xmon_taken && cpu == xmon_owner);
393 goto cmdloop;
394 }
395
396 xmon_fault_jmp[cpu] = recurse_jmp;
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000397 cpumask_set_cpu(cpu, &cpus_in_xmon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398
399 bp = NULL;
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000400 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 bp = at_breakpoint(regs->nip);
Josh Boyerdaf8f402009-09-23 03:51:04 +0000402 if (bp || unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 fromipi = 0;
404
405 if (!fromipi) {
406 get_output_lock();
407 excprint(regs);
408 if (bp) {
409 printf("cpu 0x%x stopped at breakpoint 0x%x (",
410 cpu, BP_NUM(bp));
411 xmon_print_symbol(regs->nip, " ", ")\n");
412 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000413 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 printf("WARNING: exception is not recoverable, "
415 "can't continue\n");
416 release_output_lock();
417 }
418
419 waiting:
420 secondary = 1;
421 while (secondary && !xmon_gate) {
422 if (in_xmon == 0) {
423 if (fromipi)
424 goto leave;
425 secondary = test_and_set_bit(0, &in_xmon);
426 }
427 barrier();
428 }
429
430 if (!secondary && !xmon_gate) {
431 /* we are the first cpu to come in */
432 /* interrupt other cpu(s) */
433 int ncpus = num_online_cpus();
434
435 xmon_owner = cpu;
436 mb();
437 if (ncpus > 1) {
Milton Millere0476372011-05-10 19:29:06 +0000438 smp_send_debugger_break();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 /* wait for other cpus to come in */
440 for (timeout = 100000000; timeout != 0; --timeout) {
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000441 if (cpumask_weight(&cpus_in_xmon) >= ncpus)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 break;
443 barrier();
444 }
445 }
446 remove_bpts();
447 disable_surveillance();
448 /* for breakpoint or single step, print the current instr. */
449 if (bp || TRAP(regs) == 0xd00)
450 ppc_inst_dump(regs->nip, 1, 0);
451 printf("enter ? for help\n");
452 mb();
453 xmon_gate = 1;
454 barrier();
455 }
456
457 cmdloop:
458 while (in_xmon) {
459 if (secondary) {
460 if (cpu == xmon_owner) {
461 if (!test_and_set_bit(0, &xmon_taken)) {
462 secondary = 0;
463 continue;
464 }
465 /* missed it */
466 while (cpu == xmon_owner)
467 barrier();
468 }
469 barrier();
470 } else {
471 cmd = cmds(regs);
472 if (cmd != 0) {
473 /* exiting xmon */
474 insert_bpts();
475 xmon_gate = 0;
476 wmb();
477 in_xmon = 0;
478 break;
479 }
480 /* have switched to some other cpu */
481 secondary = 1;
482 }
483 }
484 leave:
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000485 cpumask_clear_cpu(cpu, &cpus_in_xmon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 xmon_fault_jmp[cpu] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487#else
488 /* UP is simple... */
489 if (in_xmon) {
490 printf("Exception %lx %s in xmon, returning to main loop\n",
491 regs->trap, getvecname(TRAP(regs)));
492 longjmp(xmon_fault_jmp[0], 1);
493 }
494 if (setjmp(recurse_jmp) == 0) {
495 xmon_fault_jmp[0] = recurse_jmp;
496 in_xmon = 1;
497
498 excprint(regs);
499 bp = at_breakpoint(regs->nip);
500 if (bp) {
501 printf("Stopped at breakpoint %x (", BP_NUM(bp));
502 xmon_print_symbol(regs->nip, " ", ")\n");
503 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000504 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 printf("WARNING: exception is not recoverable, "
506 "can't continue\n");
507 remove_bpts();
508 disable_surveillance();
509 /* for breakpoint or single step, print the current instr. */
510 if (bp || TRAP(regs) == 0xd00)
511 ppc_inst_dump(regs->nip, 1, 0);
512 printf("enter ? for help\n");
513 }
514
515 cmd = cmds(regs);
516
517 insert_bpts();
518 in_xmon = 0;
519#endif
520
Josh Boyercdd39042009-10-05 04:46:05 +0000521#ifdef CONFIG_BOOKE
522 if (regs->msr & MSR_DE) {
523 bp = at_breakpoint(regs->nip);
524 if (bp != NULL) {
525 regs->nip = (unsigned long) &bp->instr[0];
526 atomic_inc(&bp->ref_count);
527 }
528 }
529#else
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000530 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 bp = at_breakpoint(regs->nip);
532 if (bp != NULL) {
533 int stepped = emulate_step(regs, bp->instr[0]);
534 if (stepped == 0) {
535 regs->nip = (unsigned long) &bp->instr[0];
536 atomic_inc(&bp->ref_count);
537 } else if (stepped < 0) {
538 printf("Couldn't single-step %s instruction\n",
539 (IS_RFID(bp->instr[0])? "rfid": "mtmsrd"));
540 }
541 }
542 }
Josh Boyercdd39042009-10-05 04:46:05 +0000543#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 insert_cpu_bpts();
545
Anton Blanchardf13659e2007-03-21 01:48:34 +1100546 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547
Paul Mackerras0a730ae2006-10-03 21:32:49 +1000548 return cmd != 'X' && cmd != EOF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549}
550
551int xmon(struct pt_regs *excp)
552{
553 struct pt_regs regs;
554
555 if (excp == NULL) {
Anton Vorontsov322b4392008-12-17 10:08:55 +0000556 ppc_save_regs(&regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 excp = &regs;
558 }
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200559
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 return xmon_core(excp, 0);
561}
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000562EXPORT_SYMBOL(xmon);
563
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000564irqreturn_t xmon_irq(int irq, void *d)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000565{
566 unsigned long flags;
567 local_irq_save(flags);
568 printf("Keyboard interrupt\n");
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000569 xmon(get_irq_regs());
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000570 local_irq_restore(flags);
571 return IRQ_HANDLED;
572}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000574static int xmon_bpt(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575{
576 struct bpt *bp;
577 unsigned long offset;
578
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000579 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 return 0;
581
582 /* Are we at the trap at bp->instr[1] for some bp? */
583 bp = in_breakpoint_table(regs->nip, &offset);
584 if (bp != NULL && offset == 4) {
585 regs->nip = bp->address + 4;
586 atomic_dec(&bp->ref_count);
587 return 1;
588 }
589
590 /* Are we at a breakpoint? */
591 bp = at_breakpoint(regs->nip);
592 if (!bp)
593 return 0;
594
595 xmon_core(regs, 0);
596
597 return 1;
598}
599
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000600static int xmon_sstep(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601{
602 if (user_mode(regs))
603 return 0;
604 xmon_core(regs, 0);
605 return 1;
606}
607
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000608static int xmon_dabr_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000610 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 return 0;
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000612 if (dabr.enabled == 0)
613 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 xmon_core(regs, 0);
615 return 1;
616}
617
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000618static int xmon_iabr_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000620 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 return 0;
Michael Ellerman9f1067c22008-05-08 14:27:16 +1000622 if (iabr == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 return 0;
624 xmon_core(regs, 0);
625 return 1;
626}
627
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000628static int xmon_ipi(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629{
630#ifdef CONFIG_SMP
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000631 if (in_xmon && !cpumask_test_cpu(smp_processor_id(), &cpus_in_xmon))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 xmon_core(regs, 1);
633#endif
634 return 0;
635}
636
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000637static int xmon_fault_handler(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638{
639 struct bpt *bp;
640 unsigned long offset;
641
642 if (in_xmon && catch_memory_errors)
643 handle_fault(regs); /* doesn't return */
644
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000645 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 bp = in_breakpoint_table(regs->nip, &offset);
647 if (bp != NULL) {
648 regs->nip = bp->address + offset;
649 atomic_dec(&bp->ref_count);
650 }
651 }
652
653 return 0;
654}
655
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656static struct bpt *at_breakpoint(unsigned long pc)
657{
658 int i;
659 struct bpt *bp;
660
661 bp = bpts;
662 for (i = 0; i < NBPTS; ++i, ++bp)
663 if (bp->enabled && pc == bp->address)
664 return bp;
665 return NULL;
666}
667
668static struct bpt *in_breakpoint_table(unsigned long nip, unsigned long *offp)
669{
670 unsigned long off;
671
672 off = nip - (unsigned long) bpts;
673 if (off >= sizeof(bpts))
674 return NULL;
675 off %= sizeof(struct bpt);
676 if (off != offsetof(struct bpt, instr[0])
677 && off != offsetof(struct bpt, instr[1]))
678 return NULL;
679 *offp = off - offsetof(struct bpt, instr[0]);
680 return (struct bpt *) (nip - off);
681}
682
683static struct bpt *new_breakpoint(unsigned long a)
684{
685 struct bpt *bp;
686
687 a &= ~3UL;
688 bp = at_breakpoint(a);
689 if (bp)
690 return bp;
691
692 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
693 if (!bp->enabled && atomic_read(&bp->ref_count) == 0) {
694 bp->address = a;
695 bp->instr[1] = bpinstr;
696 store_inst(&bp->instr[1]);
697 return bp;
698 }
699 }
700
701 printf("Sorry, no free breakpoints. Please clear one first.\n");
702 return NULL;
703}
704
705static void insert_bpts(void)
706{
707 int i;
708 struct bpt *bp;
709
710 bp = bpts;
711 for (i = 0; i < NBPTS; ++i, ++bp) {
712 if ((bp->enabled & (BP_TRAP|BP_IABR)) == 0)
713 continue;
714 if (mread(bp->address, &bp->instr[0], 4) != 4) {
715 printf("Couldn't read instruction at %lx, "
716 "disabling breakpoint there\n", bp->address);
717 bp->enabled = 0;
718 continue;
719 }
720 if (IS_MTMSRD(bp->instr[0]) || IS_RFID(bp->instr[0])) {
721 printf("Breakpoint at %lx is on an mtmsrd or rfid "
722 "instruction, disabling it\n", bp->address);
723 bp->enabled = 0;
724 continue;
725 }
726 store_inst(&bp->instr[0]);
727 if (bp->enabled & BP_IABR)
728 continue;
729 if (mwrite(bp->address, &bpinstr, 4) != 4) {
730 printf("Couldn't write instruction at %lx, "
731 "disabling breakpoint there\n", bp->address);
732 bp->enabled &= ~BP_TRAP;
733 continue;
734 }
735 store_inst((void *)bp->address);
736 }
737}
738
739static void insert_cpu_bpts(void)
740{
741 if (dabr.enabled)
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000742 set_dabr(dabr.address | (dabr.enabled & 7));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 if (iabr && cpu_has_feature(CPU_FTR_IABR))
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000744 mtspr(SPRN_IABR, iabr->address
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 | (iabr->enabled & (BP_IABR|BP_IABR_TE)));
746}
747
748static void remove_bpts(void)
749{
750 int i;
751 struct bpt *bp;
752 unsigned instr;
753
754 bp = bpts;
755 for (i = 0; i < NBPTS; ++i, ++bp) {
756 if ((bp->enabled & (BP_TRAP|BP_IABR)) != BP_TRAP)
757 continue;
758 if (mread(bp->address, &instr, 4) == 4
759 && instr == bpinstr
760 && mwrite(bp->address, &bp->instr, 4) != 4)
761 printf("Couldn't remove breakpoint at %lx\n",
762 bp->address);
763 else
764 store_inst((void *)bp->address);
765 }
766}
767
768static void remove_cpu_bpts(void)
769{
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000770 set_dabr(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 if (cpu_has_feature(CPU_FTR_IABR))
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000772 mtspr(SPRN_IABR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773}
774
775/* Command interpreting routine */
776static char *last_cmd;
777
778static int
779cmds(struct pt_regs *excp)
780{
781 int cmd = 0;
782
783 last_cmd = NULL;
784 xmon_regs = excp;
Olaf Hering26c8af52006-09-08 16:29:21 +0200785
786 if (!xmon_no_auto_backtrace) {
787 xmon_no_auto_backtrace = 1;
788 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
789 }
790
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 for(;;) {
792#ifdef CONFIG_SMP
793 printf("%x:", smp_processor_id());
794#endif /* CONFIG_SMP */
795 printf("mon> ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 flush_input();
797 termch = 0;
798 cmd = skipbl();
799 if( cmd == '\n' ) {
800 if (last_cmd == NULL)
801 continue;
802 take_input(last_cmd);
803 last_cmd = NULL;
804 cmd = inchar();
805 }
806 switch (cmd) {
807 case 'm':
808 cmd = inchar();
809 switch (cmd) {
810 case 'm':
811 case 's':
812 case 'd':
813 memops(cmd);
814 break;
815 case 'l':
816 memlocate();
817 break;
818 case 'z':
819 memzcan();
820 break;
821 case 'i':
David Rientjesb2b755b2011-03-24 15:18:15 -0700822 show_mem(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 break;
824 default:
825 termch = cmd;
826 memex();
827 }
828 break;
829 case 'd':
830 dump();
831 break;
832 case 'l':
833 symbol_lookup();
834 break;
835 case 'r':
836 prregs(excp); /* print regs */
837 break;
838 case 'e':
839 excprint(excp);
840 break;
841 case 'S':
842 super_regs();
843 break;
844 case 't':
845 backtrace(excp);
846 break;
847 case 'f':
848 cacheflush();
849 break;
850 case 's':
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200851 if (do_spu_cmd() == 0)
852 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 if (do_step(excp))
854 return cmd;
855 break;
856 case 'x':
857 case 'X':
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100858 return cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 case EOF:
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100860 printf(" <no input ...>\n");
861 mdelay(2000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 return cmd;
863 case '?':
Ishizaki Kou4d404ed2007-07-18 19:26:40 +1000864 xmon_puts(help_string);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 case 'b':
867 bpt_cmds();
868 break;
869 case 'C':
870 csum();
871 break;
872 case 'c':
873 if (cpu_cmd())
874 return 0;
875 break;
876 case 'z':
877 bootcmds();
878 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000879 case 'p':
880 proccall();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +1000882#ifdef CONFIG_PPC_STD_MMU
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 case 'u':
884 dump_segments();
885 break;
Jimi Xenidis79873e82011-09-29 11:25:10 +0000886#elif defined(CONFIG_4xx)
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100887 case 'u':
888 dump_tlb_44x();
889 break;
Jimi Xenidis79873e82011-09-29 11:25:10 +0000890#elif defined(CONFIG_PPC_BOOK3E)
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +1000891 case 'u':
892 dump_tlb_book3e();
893 break;
894#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 default:
896 printf("Unrecognized command: ");
897 do {
898 if (' ' < cmd && cmd <= '~')
899 putchar(cmd);
900 else
901 printf("\\x%x", cmd);
902 cmd = inchar();
903 } while (cmd != '\n');
904 printf(" (type ? for help)\n");
905 break;
906 }
907 }
908}
909
Josh Boyercdd39042009-10-05 04:46:05 +0000910#ifdef CONFIG_BOOKE
911static int do_step(struct pt_regs *regs)
912{
913 regs->msr |= MSR_DE;
914 mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
915 return 1;
916}
917#else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918/*
919 * Step a single instruction.
920 * Some instructions we emulate, others we execute with MSR_SE set.
921 */
922static int do_step(struct pt_regs *regs)
923{
924 unsigned int instr;
925 int stepped;
926
927 /* check we are in 64-bit kernel mode, translation enabled */
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000928 if ((regs->msr & (MSR_64BIT|MSR_PR|MSR_IR)) == (MSR_64BIT|MSR_IR)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 if (mread(regs->nip, &instr, 4) == 4) {
930 stepped = emulate_step(regs, instr);
931 if (stepped < 0) {
932 printf("Couldn't single-step %s instruction\n",
933 (IS_RFID(instr)? "rfid": "mtmsrd"));
934 return 0;
935 }
936 if (stepped > 0) {
937 regs->trap = 0xd00 | (regs->trap & 1);
938 printf("stepped to ");
939 xmon_print_symbol(regs->nip, " ", "\n");
940 ppc_inst_dump(regs->nip, 1, 0);
941 return 0;
942 }
943 }
944 }
945 regs->msr |= MSR_SE;
946 return 1;
947}
Josh Boyercdd39042009-10-05 04:46:05 +0000948#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949
950static void bootcmds(void)
951{
952 int cmd;
953
954 cmd = inchar();
955 if (cmd == 'r')
956 ppc_md.restart(NULL);
957 else if (cmd == 'h')
958 ppc_md.halt();
959 else if (cmd == 'p')
960 ppc_md.power_off();
961}
962
963static int cpu_cmd(void)
964{
965#ifdef CONFIG_SMP
966 unsigned long cpu;
967 int timeout;
968 int count;
969
970 if (!scanhex(&cpu)) {
971 /* print cpus waiting or in xmon */
972 printf("cpus stopped:");
973 count = 0;
974 for (cpu = 0; cpu < NR_CPUS; ++cpu) {
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000975 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 if (count == 0)
977 printf(" %x", cpu);
978 ++count;
979 } else {
980 if (count > 1)
981 printf("-%x", cpu - 1);
982 count = 0;
983 }
984 }
985 if (count > 1)
986 printf("-%x", NR_CPUS - 1);
987 printf("\n");
988 return 0;
989 }
990 /* try to switch to cpu specified */
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000991 if (!cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 printf("cpu 0x%x isn't in xmon\n", cpu);
993 return 0;
994 }
995 xmon_taken = 0;
996 mb();
997 xmon_owner = cpu;
998 timeout = 10000000;
999 while (!xmon_taken) {
1000 if (--timeout == 0) {
1001 if (test_and_set_bit(0, &xmon_taken))
1002 break;
1003 /* take control back */
1004 mb();
1005 xmon_owner = smp_processor_id();
1006 printf("cpu %u didn't take control\n", cpu);
1007 return 0;
1008 }
1009 barrier();
1010 }
1011 return 1;
1012#else
1013 return 0;
1014#endif /* CONFIG_SMP */
1015}
1016
1017static unsigned short fcstab[256] = {
1018 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
1019 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
1020 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
1021 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
1022 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
1023 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
1024 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
1025 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
1026 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
1027 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
1028 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
1029 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
1030 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
1031 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
1032 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
1033 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
1034 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
1035 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
1036 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
1037 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
1038 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
1039 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
1040 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
1041 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
1042 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
1043 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
1044 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
1045 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
1046 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
1047 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
1048 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
1049 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
1050};
1051
1052#define FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
1053
1054static void
1055csum(void)
1056{
1057 unsigned int i;
1058 unsigned short fcs;
1059 unsigned char v;
1060
1061 if (!scanhex(&adrs))
1062 return;
1063 if (!scanhex(&ncsum))
1064 return;
1065 fcs = 0xffff;
1066 for (i = 0; i < ncsum; ++i) {
1067 if (mread(adrs+i, &v, 1) == 0) {
1068 printf("csum stopped at %x\n", adrs+i);
1069 break;
1070 }
1071 fcs = FCS(fcs, v);
1072 }
1073 printf("%x\n", fcs);
1074}
1075
1076/*
1077 * Check if this is a suitable place to put a breakpoint.
1078 */
1079static long check_bp_loc(unsigned long addr)
1080{
1081 unsigned int instr;
1082
1083 addr &= ~3;
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001084 if (!is_kernel_addr(addr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 printf("Breakpoints may only be placed at kernel addresses\n");
1086 return 0;
1087 }
1088 if (!mread(addr, &instr, sizeof(instr))) {
1089 printf("Can't read instruction at address %lx\n", addr);
1090 return 0;
1091 }
1092 if (IS_MTMSRD(instr) || IS_RFID(instr)) {
1093 printf("Breakpoints may not be placed on mtmsrd or rfid "
1094 "instructions\n");
1095 return 0;
1096 }
1097 return 1;
1098}
1099
1100static char *breakpoint_help_string =
1101 "Breakpoint command usage:\n"
1102 "b show breakpoints\n"
1103 "b <addr> [cnt] set breakpoint at given instr addr\n"
1104 "bc clear all breakpoints\n"
1105 "bc <n/addr> clear breakpoint number n or at addr\n"
1106 "bi <addr> [cnt] set hardware instr breakpoint (POWER3/RS64 only)\n"
1107 "bd <addr> [cnt] set hardware data breakpoint\n"
1108 "";
1109
1110static void
1111bpt_cmds(void)
1112{
1113 int cmd;
1114 unsigned long a;
1115 int mode, i;
1116 struct bpt *bp;
1117 const char badaddr[] = "Only kernel addresses are permitted "
1118 "for breakpoints\n";
1119
1120 cmd = inchar();
1121 switch (cmd) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001122#ifndef CONFIG_8xx
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 case 'd': /* bd - hardware data breakpoint */
1124 mode = 7;
1125 cmd = inchar();
1126 if (cmd == 'r')
1127 mode = 5;
1128 else if (cmd == 'w')
1129 mode = 6;
1130 else
1131 termch = cmd;
1132 dabr.address = 0;
1133 dabr.enabled = 0;
1134 if (scanhex(&dabr.address)) {
Michael Ellerman51fae6de2005-12-04 18:39:15 +11001135 if (!is_kernel_addr(dabr.address)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 printf(badaddr);
1137 break;
1138 }
1139 dabr.address &= ~7;
1140 dabr.enabled = mode | BP_DABR;
1141 }
1142 break;
1143
1144 case 'i': /* bi - hardware instr breakpoint */
1145 if (!cpu_has_feature(CPU_FTR_IABR)) {
1146 printf("Hardware instruction breakpoint "
1147 "not supported on this cpu\n");
1148 break;
1149 }
1150 if (iabr) {
1151 iabr->enabled &= ~(BP_IABR | BP_IABR_TE);
1152 iabr = NULL;
1153 }
1154 if (!scanhex(&a))
1155 break;
1156 if (!check_bp_loc(a))
1157 break;
1158 bp = new_breakpoint(a);
1159 if (bp != NULL) {
1160 bp->enabled |= BP_IABR | BP_IABR_TE;
1161 iabr = bp;
1162 }
1163 break;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001164#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165
1166 case 'c':
1167 if (!scanhex(&a)) {
1168 /* clear all breakpoints */
1169 for (i = 0; i < NBPTS; ++i)
1170 bpts[i].enabled = 0;
1171 iabr = NULL;
1172 dabr.enabled = 0;
1173 printf("All breakpoints cleared\n");
1174 break;
1175 }
1176
1177 if (a <= NBPTS && a >= 1) {
1178 /* assume a breakpoint number */
1179 bp = &bpts[a-1]; /* bp nums are 1 based */
1180 } else {
1181 /* assume a breakpoint address */
1182 bp = at_breakpoint(a);
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001183 if (bp == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 printf("No breakpoint at %x\n", a);
1185 break;
1186 }
1187 }
1188
1189 printf("Cleared breakpoint %x (", BP_NUM(bp));
1190 xmon_print_symbol(bp->address, " ", ")\n");
1191 bp->enabled = 0;
1192 break;
1193
1194 default:
1195 termch = cmd;
1196 cmd = skipbl();
1197 if (cmd == '?') {
1198 printf(breakpoint_help_string);
1199 break;
1200 }
1201 termch = cmd;
1202 if (!scanhex(&a)) {
1203 /* print all breakpoints */
1204 printf(" type address\n");
1205 if (dabr.enabled) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001206 printf(" data "REG" [", dabr.address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 if (dabr.enabled & 1)
1208 printf("r");
1209 if (dabr.enabled & 2)
1210 printf("w");
1211 printf("]\n");
1212 }
1213 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
1214 if (!bp->enabled)
1215 continue;
1216 printf("%2x %s ", BP_NUM(bp),
1217 (bp->enabled & BP_IABR)? "inst": "trap");
1218 xmon_print_symbol(bp->address, " ", "\n");
1219 }
1220 break;
1221 }
1222
1223 if (!check_bp_loc(a))
1224 break;
1225 bp = new_breakpoint(a);
1226 if (bp != NULL)
1227 bp->enabled |= BP_TRAP;
1228 break;
1229 }
1230}
1231
1232/* Very cheap human name for vector lookup. */
1233static
1234const char *getvecname(unsigned long vec)
1235{
1236 char *ret;
1237
1238 switch (vec) {
1239 case 0x100: ret = "(System Reset)"; break;
1240 case 0x200: ret = "(Machine Check)"; break;
1241 case 0x300: ret = "(Data Access)"; break;
1242 case 0x380: ret = "(Data SLB Access)"; break;
1243 case 0x400: ret = "(Instruction Access)"; break;
1244 case 0x480: ret = "(Instruction SLB Access)"; break;
1245 case 0x500: ret = "(Hardware Interrupt)"; break;
1246 case 0x600: ret = "(Alignment)"; break;
1247 case 0x700: ret = "(Program Check)"; break;
1248 case 0x800: ret = "(FPU Unavailable)"; break;
1249 case 0x900: ret = "(Decrementer)"; break;
1250 case 0xc00: ret = "(System Call)"; break;
1251 case 0xd00: ret = "(Single Step)"; break;
1252 case 0xf00: ret = "(Performance Monitor)"; break;
1253 case 0xf20: ret = "(Altivec Unavailable)"; break;
1254 case 0x1300: ret = "(Instruction Breakpoint)"; break;
1255 default: ret = "";
1256 }
1257 return ret;
1258}
1259
1260static void get_function_bounds(unsigned long pc, unsigned long *startp,
1261 unsigned long *endp)
1262{
1263 unsigned long size, offset;
1264 const char *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265
1266 *startp = *endp = 0;
1267 if (pc == 0)
1268 return;
1269 if (setjmp(bus_error_jmp) == 0) {
1270 catch_memory_errors = 1;
1271 sync();
Alexey Dobriyanffb45122007-05-08 00:28:41 -07001272 name = kallsyms_lookup(pc, &size, &offset, NULL, tmpstr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 if (name != NULL) {
1274 *startp = pc - offset;
1275 *endp = pc - offset + size;
1276 }
1277 sync();
1278 }
1279 catch_memory_errors = 0;
1280}
1281
1282static int xmon_depth_to_print = 64;
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
1287#ifdef __powerpc64__
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001288#define REGS_OFFSET 0x70
1289#else
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001290#define REGS_OFFSET 16
1291#endif
1292
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293static void xmon_show_stack(unsigned long sp, unsigned long lr,
1294 unsigned long pc)
1295{
1296 unsigned long ip;
1297 unsigned long newsp;
1298 unsigned long marker;
1299 int count = 0;
1300 struct pt_regs regs;
1301
1302 do {
1303 if (sp < PAGE_OFFSET) {
1304 if (sp != 0)
1305 printf("SP (%lx) is in userspace\n", sp);
1306 break;
1307 }
1308
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001309 if (!mread(sp + LRSAVE_OFFSET, &ip, sizeof(unsigned long))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310 || !mread(sp, &newsp, sizeof(unsigned long))) {
1311 printf("Couldn't read stack frame at %lx\n", sp);
1312 break;
1313 }
1314
1315 /*
1316 * For the first stack frame, try to work out if
1317 * LR and/or the saved LR value in the bottommost
1318 * stack frame are valid.
1319 */
1320 if ((pc | lr) != 0) {
1321 unsigned long fnstart, fnend;
1322 unsigned long nextip;
1323 int printip = 1;
1324
1325 get_function_bounds(pc, &fnstart, &fnend);
1326 nextip = 0;
1327 if (newsp > sp)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001328 mread(newsp + LRSAVE_OFFSET, &nextip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 sizeof(unsigned long));
1330 if (lr == ip) {
1331 if (lr < PAGE_OFFSET
1332 || (fnstart <= lr && lr < fnend))
1333 printip = 0;
1334 } else if (lr == nextip) {
1335 printip = 0;
1336 } else if (lr >= PAGE_OFFSET
1337 && !(fnstart <= lr && lr < fnend)) {
1338 printf("[link register ] ");
1339 xmon_print_symbol(lr, " ", "\n");
1340 }
1341 if (printip) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001342 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343 xmon_print_symbol(ip, " ", " (unreliable)\n");
1344 }
1345 pc = lr = 0;
1346
1347 } else {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001348 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 xmon_print_symbol(ip, " ", "\n");
1350 }
1351
1352 /* Look for "regshere" marker to see if this is
1353 an exception frame. */
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001354 if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long))
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001355 && marker == STACK_FRAME_REGS_MARKER) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001356 if (mread(sp + REGS_OFFSET, &regs, sizeof(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 != sizeof(regs)) {
1358 printf("Couldn't read registers at %lx\n",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001359 sp + REGS_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 break;
1361 }
1362 printf("--- Exception: %lx %s at ", regs.trap,
1363 getvecname(TRAP(&regs)));
1364 pc = regs.nip;
1365 lr = regs.link;
1366 xmon_print_symbol(pc, " ", "\n");
1367 }
1368
1369 if (newsp == 0)
1370 break;
1371
1372 sp = newsp;
1373 } while (count++ < xmon_depth_to_print);
1374}
1375
1376static void backtrace(struct pt_regs *excp)
1377{
1378 unsigned long sp;
1379
1380 if (scanhex(&sp))
1381 xmon_show_stack(sp, 0, 0);
1382 else
1383 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
1384 scannl();
1385}
1386
1387static void print_bug_trap(struct pt_regs *regs)
1388{
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001389#ifdef CONFIG_BUG
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001390 const struct bug_entry *bug;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 unsigned long addr;
1392
1393 if (regs->msr & MSR_PR)
1394 return; /* not in kernel */
1395 addr = regs->nip; /* address of trap instruction */
1396 if (addr < PAGE_OFFSET)
1397 return;
1398 bug = find_bug(regs->nip);
1399 if (bug == NULL)
1400 return;
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001401 if (is_warning_bug(bug))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402 return;
1403
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001404#ifdef CONFIG_DEBUG_BUGVERBOSE
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001405 printf("kernel BUG at %s:%u!\n",
1406 bug->file, bug->line);
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001407#else
1408 printf("kernel BUG at %p!\n", (void *)bug->bug_addr);
1409#endif
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001410#endif /* CONFIG_BUG */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411}
1412
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001413static void excprint(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414{
1415 unsigned long trap;
1416
1417#ifdef CONFIG_SMP
1418 printf("cpu 0x%x: ", smp_processor_id());
1419#endif /* CONFIG_SMP */
1420
1421 trap = TRAP(fp);
1422 printf("Vector: %lx %s at [%lx]\n", fp->trap, getvecname(trap), fp);
1423 printf(" pc: ");
1424 xmon_print_symbol(fp->nip, ": ", "\n");
1425
1426 printf(" lr: ", fp->link);
1427 xmon_print_symbol(fp->link, ": ", "\n");
1428
1429 printf(" sp: %lx\n", fp->gpr[1]);
1430 printf(" msr: %lx\n", fp->msr);
1431
1432 if (trap == 0x300 || trap == 0x380 || trap == 0x600) {
1433 printf(" dar: %lx\n", fp->dar);
1434 if (trap != 0x380)
1435 printf(" dsisr: %lx\n", fp->dsisr);
1436 }
1437
1438 printf(" current = 0x%lx\n", current);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001439#ifdef CONFIG_PPC64
Benjamin Herrenschmidt7230c562012-03-06 18:27:59 +11001440 printf(" paca = 0x%lx\t softe: %d\t irq_happened: 0x%02x\n",
1441 local_paca, local_paca->soft_enabled, local_paca->irq_happened);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001442#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 if (current) {
1444 printf(" pid = %ld, comm = %s\n",
1445 current->pid, current->comm);
1446 }
1447
1448 if (trap == 0x700)
1449 print_bug_trap(fp);
1450}
1451
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001452static void prregs(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001454 int n, trap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455 unsigned long base;
1456 struct pt_regs regs;
1457
1458 if (scanhex(&base)) {
1459 if (setjmp(bus_error_jmp) == 0) {
1460 catch_memory_errors = 1;
1461 sync();
1462 regs = *(struct pt_regs *)base;
1463 sync();
1464 __delay(200);
1465 } else {
1466 catch_memory_errors = 0;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001467 printf("*** Error reading registers from "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 base);
1469 return;
1470 }
1471 catch_memory_errors = 0;
1472 fp = &regs;
1473 }
1474
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001475#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 if (FULL_REGS(fp)) {
1477 for (n = 0; n < 16; ++n)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001478 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 n, fp->gpr[n], n+16, fp->gpr[n+16]);
1480 } else {
1481 for (n = 0; n < 7; ++n)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001482 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 n, fp->gpr[n], n+7, fp->gpr[n+7]);
1484 }
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001485#else
1486 for (n = 0; n < 32; ++n) {
1487 printf("R%.2d = %.8x%s", n, fp->gpr[n],
1488 (n & 3) == 3? "\n": " ");
1489 if (n == 12 && !FULL_REGS(fp)) {
1490 printf("\n");
1491 break;
1492 }
1493 }
1494#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 printf("pc = ");
1496 xmon_print_symbol(fp->nip, " ", "\n");
Paul Mackerras48404f22011-05-01 19:48:20 +00001497 if (TRAP(fp) != 0xc00 && cpu_has_feature(CPU_FTR_CFAR)) {
1498 printf("cfar= ");
1499 xmon_print_symbol(fp->orig_gpr3, " ", "\n");
1500 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501 printf("lr = ");
1502 xmon_print_symbol(fp->link, " ", "\n");
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001503 printf("msr = "REG" cr = %.8lx\n", fp->msr, fp->ccr);
1504 printf("ctr = "REG" xer = "REG" trap = %4lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505 fp->ctr, fp->xer, fp->trap);
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001506 trap = TRAP(fp);
1507 if (trap == 0x300 || trap == 0x380 || trap == 0x600)
1508 printf("dar = "REG" dsisr = %.8lx\n", fp->dar, fp->dsisr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509}
1510
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001511static void cacheflush(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512{
1513 int cmd;
1514 unsigned long nflush;
1515
1516 cmd = inchar();
1517 if (cmd != 'i')
1518 termch = cmd;
1519 scanhex((void *)&adrs);
1520 if (termch != '\n')
1521 termch = 0;
1522 nflush = 1;
1523 scanhex(&nflush);
1524 nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES;
1525 if (setjmp(bus_error_jmp) == 0) {
1526 catch_memory_errors = 1;
1527 sync();
1528
1529 if (cmd != 'i') {
1530 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1531 cflush((void *) adrs);
1532 } else {
1533 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1534 cinval((void *) adrs);
1535 }
1536 sync();
1537 /* wait a little while to see if we get a machine check */
1538 __delay(200);
1539 }
1540 catch_memory_errors = 0;
1541}
1542
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001543static unsigned long
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544read_spr(int n)
1545{
1546 unsigned int instrs[2];
1547 unsigned long (*code)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548 unsigned long ret = -1UL;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001549#ifdef CONFIG_PPC64
1550 unsigned long opd[3];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 opd[0] = (unsigned long)instrs;
1553 opd[1] = 0;
1554 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001555 code = (unsigned long (*)(void)) opd;
1556#else
1557 code = (unsigned long (*)(void)) instrs;
1558#endif
1559
1560 /* mfspr r3,n; blr */
1561 instrs[0] = 0x7c6002a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1562 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 store_inst(instrs);
1564 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565
1566 if (setjmp(bus_error_jmp) == 0) {
1567 catch_memory_errors = 1;
1568 sync();
1569
1570 ret = code();
1571
1572 sync();
1573 /* wait a little while to see if we get a machine check */
1574 __delay(200);
1575 n = size;
1576 }
1577
1578 return ret;
1579}
1580
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001581static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582write_spr(int n, unsigned long val)
1583{
1584 unsigned int instrs[2];
1585 unsigned long (*code)(unsigned long);
Paul Mackerras548cceb2005-11-11 22:36:34 +11001586#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587 unsigned long opd[3];
1588
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589 opd[0] = (unsigned long)instrs;
1590 opd[1] = 0;
1591 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001592 code = (unsigned long (*)(unsigned long)) opd;
1593#else
1594 code = (unsigned long (*)(unsigned long)) instrs;
1595#endif
1596
1597 instrs[0] = 0x7c6003a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1598 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 store_inst(instrs);
1600 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601
1602 if (setjmp(bus_error_jmp) == 0) {
1603 catch_memory_errors = 1;
1604 sync();
1605
1606 code(val);
1607
1608 sync();
1609 /* wait a little while to see if we get a machine check */
1610 __delay(200);
1611 n = size;
1612 }
1613}
1614
1615static unsigned long regno;
1616extern char exc_prolog;
1617extern char dec_exc;
1618
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001619static void super_regs(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620{
1621 int cmd;
1622 unsigned long val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623
1624 cmd = skipbl();
1625 if (cmd == '\n') {
1626 unsigned long sp, toc;
1627 asm("mr %0,1" : "=r" (sp) :);
1628 asm("mr %0,2" : "=r" (toc) :);
1629
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001630 printf("msr = "REG" sprg0= "REG"\n",
1631 mfmsr(), mfspr(SPRN_SPRG0));
1632 printf("pvr = "REG" sprg1= "REG"\n",
1633 mfspr(SPRN_PVR), mfspr(SPRN_SPRG1));
1634 printf("dec = "REG" sprg2= "REG"\n",
1635 mfspr(SPRN_DEC), mfspr(SPRN_SPRG2));
1636 printf("sp = "REG" sprg3= "REG"\n", sp, mfspr(SPRN_SPRG3));
1637 printf("toc = "REG" dar = "REG"\n", toc, mfspr(SPRN_DAR));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638#ifdef CONFIG_PPC_ISERIES
Stephen Rothwell1d135812006-11-13 14:50:28 +11001639 if (firmware_has_feature(FW_FEATURE_ISERIES)) {
1640 struct paca_struct *ptrPaca;
1641 struct lppaca *ptrLpPaca;
Stephen Rothwell1d135812006-11-13 14:50:28 +11001642
1643 /* Dump out relevant Paca data areas. */
1644 printf("Paca: \n");
Benjamin Herrenschmidt7ac21cd2012-03-02 10:10:09 +11001645 ptrPaca = local_paca;
Stephen Rothwell1d135812006-11-13 14:50:28 +11001646
1647 printf(" Local Processor Control Area (LpPaca): \n");
1648 ptrLpPaca = ptrPaca->lppaca_ptr;
1649 printf(" Saved Srr0=%.16lx Saved Srr1=%.16lx \n",
1650 ptrLpPaca->saved_srr0, ptrLpPaca->saved_srr1);
1651 printf(" Saved Gpr3=%.16lx Saved Gpr4=%.16lx \n",
1652 ptrLpPaca->saved_gpr3, ptrLpPaca->saved_gpr4);
Gautham R Shenoy69ddb572009-10-29 19:22:48 +00001653 printf(" Saved Gpr5=%.16lx \n",
1654 ptrLpPaca->gpr5_dword.saved_gpr5);
Stephen Rothwell1d135812006-11-13 14:50:28 +11001655 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656#endif
1657
1658 return;
1659 }
1660
1661 scanhex(&regno);
1662 switch (cmd) {
1663 case 'w':
1664 val = read_spr(regno);
1665 scanhex(&val);
1666 write_spr(regno, val);
1667 /* fall through */
1668 case 'r':
1669 printf("spr %lx = %lx\n", regno, read_spr(regno));
1670 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671 }
1672 scannl();
1673}
1674
1675/*
1676 * Stuff for reading and writing memory safely
1677 */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001678static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679mread(unsigned long adrs, void *buf, int size)
1680{
1681 volatile int n;
1682 char *p, *q;
1683
1684 n = 0;
1685 if (setjmp(bus_error_jmp) == 0) {
1686 catch_memory_errors = 1;
1687 sync();
1688 p = (char *)adrs;
1689 q = (char *)buf;
1690 switch (size) {
1691 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001692 *(u16 *)q = *(u16 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 break;
1694 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001695 *(u32 *)q = *(u32 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 break;
1697 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001698 *(u64 *)q = *(u64 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 break;
1700 default:
1701 for( ; n < size; ++n) {
1702 *q++ = *p++;
1703 sync();
1704 }
1705 }
1706 sync();
1707 /* wait a little while to see if we get a machine check */
1708 __delay(200);
1709 n = size;
1710 }
1711 catch_memory_errors = 0;
1712 return n;
1713}
1714
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001715static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716mwrite(unsigned long adrs, void *buf, int size)
1717{
1718 volatile int n;
1719 char *p, *q;
1720
1721 n = 0;
1722 if (setjmp(bus_error_jmp) == 0) {
1723 catch_memory_errors = 1;
1724 sync();
1725 p = (char *) adrs;
1726 q = (char *) buf;
1727 switch (size) {
1728 case 2:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001729 *(u16 *)p = *(u16 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 break;
1731 case 4:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001732 *(u32 *)p = *(u32 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 break;
1734 case 8:
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001735 *(u64 *)p = *(u64 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 break;
1737 default:
1738 for ( ; n < size; ++n) {
1739 *p++ = *q++;
1740 sync();
1741 }
1742 }
1743 sync();
1744 /* wait a little while to see if we get a machine check */
1745 __delay(200);
1746 n = size;
1747 } else {
1748 printf("*** Error writing address %x\n", adrs + n);
1749 }
1750 catch_memory_errors = 0;
1751 return n;
1752}
1753
1754static int fault_type;
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001755static int fault_except;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756static char *fault_chars[] = { "--", "**", "##" };
1757
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001758static int handle_fault(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759{
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10001760 fault_except = TRAP(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761 switch (TRAP(regs)) {
1762 case 0x200:
1763 fault_type = 0;
1764 break;
1765 case 0x300:
1766 case 0x380:
1767 fault_type = 1;
1768 break;
1769 default:
1770 fault_type = 2;
1771 }
1772
1773 longjmp(bus_error_jmp, 1);
1774
1775 return 0;
1776}
1777
1778#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t))
1779
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001780static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781byterev(unsigned char *val, int size)
1782{
1783 int t;
1784
1785 switch (size) {
1786 case 2:
1787 SWAP(val[0], val[1], t);
1788 break;
1789 case 4:
1790 SWAP(val[0], val[3], t);
1791 SWAP(val[1], val[2], t);
1792 break;
1793 case 8: /* is there really any use for this? */
1794 SWAP(val[0], val[7], t);
1795 SWAP(val[1], val[6], t);
1796 SWAP(val[2], val[5], t);
1797 SWAP(val[3], val[4], t);
1798 break;
1799 }
1800}
1801
1802static int brev;
1803static int mnoread;
1804
1805static char *memex_help_string =
1806 "Memory examine command usage:\n"
1807 "m [addr] [flags] examine/change memory\n"
1808 " addr is optional. will start where left off.\n"
1809 " flags may include chars from this set:\n"
1810 " b modify by bytes (default)\n"
1811 " w modify by words (2 byte)\n"
1812 " l modify by longs (4 byte)\n"
1813 " d modify by doubleword (8 byte)\n"
1814 " r toggle reverse byte order mode\n"
1815 " n do not read memory (for i/o spaces)\n"
1816 " . ok to read (default)\n"
1817 "NOTE: flags are saved as defaults\n"
1818 "";
1819
1820static char *memex_subcmd_help_string =
1821 "Memory examine subcommands:\n"
1822 " hexval write this val to current location\n"
1823 " 'string' write chars from string to this location\n"
1824 " ' increment address\n"
1825 " ^ decrement address\n"
1826 " / increment addr by 0x10. //=0x100, ///=0x1000, etc\n"
1827 " \\ decrement addr by 0x10. \\\\=0x100, \\\\\\=0x1000, etc\n"
1828 " ` clear no-read flag\n"
1829 " ; stay at this addr\n"
1830 " v change to byte mode\n"
1831 " w change to word (2 byte) mode\n"
1832 " l change to long (4 byte) mode\n"
1833 " u change to doubleword (8 byte) mode\n"
1834 " m addr change current addr\n"
1835 " n toggle no-read flag\n"
1836 " r toggle byte reverse flag\n"
1837 " < count back up count bytes\n"
1838 " > count skip forward count bytes\n"
1839 " x exit this mode\n"
1840 "";
1841
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001842static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843memex(void)
1844{
1845 int cmd, inc, i, nslash;
1846 unsigned long n;
1847 unsigned char val[16];
1848
1849 scanhex((void *)&adrs);
1850 cmd = skipbl();
1851 if (cmd == '?') {
1852 printf(memex_help_string);
1853 return;
1854 } else {
1855 termch = cmd;
1856 }
1857 last_cmd = "m\n";
1858 while ((cmd = skipbl()) != '\n') {
1859 switch( cmd ){
1860 case 'b': size = 1; break;
1861 case 'w': size = 2; break;
1862 case 'l': size = 4; break;
1863 case 'd': size = 8; break;
1864 case 'r': brev = !brev; break;
1865 case 'n': mnoread = 1; break;
1866 case '.': mnoread = 0; break;
1867 }
1868 }
1869 if( size <= 0 )
1870 size = 1;
1871 else if( size > 8 )
1872 size = 8;
1873 for(;;){
1874 if (!mnoread)
1875 n = mread(adrs, val, size);
Paul Mackerrase1449ed2005-11-10 14:30:20 +11001876 printf(REG"%c", adrs, brev? 'r': ' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877 if (!mnoread) {
1878 if (brev)
1879 byterev(val, size);
1880 putchar(' ');
1881 for (i = 0; i < n; ++i)
1882 printf("%.2x", val[i]);
1883 for (; i < size; ++i)
1884 printf("%s", fault_chars[fault_type]);
1885 }
1886 putchar(' ');
1887 inc = size;
1888 nslash = 0;
1889 for(;;){
1890 if( scanhex(&n) ){
1891 for (i = 0; i < size; ++i)
1892 val[i] = n >> (i * 8);
1893 if (!brev)
1894 byterev(val, size);
1895 mwrite(adrs, val, size);
1896 inc = size;
1897 }
1898 cmd = skipbl();
1899 if (cmd == '\n')
1900 break;
1901 inc = 0;
1902 switch (cmd) {
1903 case '\'':
1904 for(;;){
1905 n = inchar();
1906 if( n == '\\' )
1907 n = bsesc();
1908 else if( n == '\'' )
1909 break;
1910 for (i = 0; i < size; ++i)
1911 val[i] = n >> (i * 8);
1912 if (!brev)
1913 byterev(val, size);
1914 mwrite(adrs, val, size);
1915 adrs += size;
1916 }
1917 adrs -= size;
1918 inc = size;
1919 break;
1920 case ',':
1921 adrs += size;
1922 break;
1923 case '.':
1924 mnoread = 0;
1925 break;
1926 case ';':
1927 break;
1928 case 'x':
1929 case EOF:
1930 scannl();
1931 return;
1932 case 'b':
1933 case 'v':
1934 size = 1;
1935 break;
1936 case 'w':
1937 size = 2;
1938 break;
1939 case 'l':
1940 size = 4;
1941 break;
1942 case 'u':
1943 size = 8;
1944 break;
1945 case '^':
1946 adrs -= size;
1947 break;
1948 break;
1949 case '/':
1950 if (nslash > 0)
1951 adrs -= 1 << nslash;
1952 else
1953 nslash = 0;
1954 nslash += 4;
1955 adrs += 1 << nslash;
1956 break;
1957 case '\\':
1958 if (nslash < 0)
1959 adrs += 1 << -nslash;
1960 else
1961 nslash = 0;
1962 nslash -= 4;
1963 adrs -= 1 << -nslash;
1964 break;
1965 case 'm':
1966 scanhex((void *)&adrs);
1967 break;
1968 case 'n':
1969 mnoread = 1;
1970 break;
1971 case 'r':
1972 brev = !brev;
1973 break;
1974 case '<':
1975 n = size;
1976 scanhex(&n);
1977 adrs -= n;
1978 break;
1979 case '>':
1980 n = size;
1981 scanhex(&n);
1982 adrs += n;
1983 break;
1984 case '?':
1985 printf(memex_subcmd_help_string);
1986 break;
1987 }
1988 }
1989 adrs += inc;
1990 }
1991}
1992
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001993static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994bsesc(void)
1995{
1996 int c;
1997
1998 c = inchar();
1999 switch( c ){
2000 case 'n': c = '\n'; break;
2001 case 'r': c = '\r'; break;
2002 case 'b': c = '\b'; break;
2003 case 't': c = '\t'; break;
2004 }
2005 return c;
2006}
2007
Olaf Hering7e5b5932006-03-08 20:40:28 +01002008static void xmon_rawdump (unsigned long adrs, long ndump)
2009{
2010 long n, m, r, nr;
2011 unsigned char temp[16];
2012
2013 for (n = ndump; n > 0;) {
2014 r = n < 16? n: 16;
2015 nr = mread(adrs, temp, r);
2016 adrs += nr;
2017 for (m = 0; m < r; ++m) {
2018 if (m < nr)
2019 printf("%.2x", temp[m]);
2020 else
2021 printf("%s", fault_chars[fault_type]);
2022 }
2023 n -= r;
2024 if (nr < r)
2025 break;
2026 }
2027 printf("\n");
2028}
2029
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
2031 || ('a' <= (c) && (c) <= 'f') \
2032 || ('A' <= (c) && (c) <= 'F'))
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002033static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034dump(void)
2035{
2036 int c;
2037
2038 c = inchar();
2039 if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
2040 termch = c;
2041 scanhex((void *)&adrs);
2042 if (termch != '\n')
2043 termch = 0;
2044 if (c == 'i') {
2045 scanhex(&nidump);
2046 if (nidump == 0)
2047 nidump = 16;
2048 else if (nidump > MAX_DUMP)
2049 nidump = MAX_DUMP;
2050 adrs += ppc_inst_dump(adrs, nidump, 1);
2051 last_cmd = "di\n";
Vinay Sridharf312deb2009-05-14 23:13:07 +00002052 } else if (c == 'l') {
2053 dump_log_buf();
Olaf Hering7e5b5932006-03-08 20:40:28 +01002054 } else if (c == 'r') {
2055 scanhex(&ndump);
2056 if (ndump == 0)
2057 ndump = 64;
2058 xmon_rawdump(adrs, ndump);
2059 adrs += ndump;
2060 last_cmd = "dr\n";
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061 } else {
2062 scanhex(&ndump);
2063 if (ndump == 0)
2064 ndump = 64;
2065 else if (ndump > MAX_DUMP)
2066 ndump = MAX_DUMP;
2067 prdump(adrs, ndump);
2068 adrs += ndump;
2069 last_cmd = "d\n";
2070 }
2071}
2072
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002073static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002074prdump(unsigned long adrs, long ndump)
2075{
2076 long n, m, c, r, nr;
2077 unsigned char temp[16];
2078
2079 for (n = ndump; n > 0;) {
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002080 printf(REG, adrs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081 putchar(' ');
2082 r = n < 16? n: 16;
2083 nr = mread(adrs, temp, r);
2084 adrs += nr;
2085 for (m = 0; m < r; ++m) {
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002086 if ((m & (sizeof(long) - 1)) == 0 && m > 0)
2087 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002088 if (m < nr)
2089 printf("%.2x", temp[m]);
2090 else
2091 printf("%s", fault_chars[fault_type]);
2092 }
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002093 for (; m < 16; ++m) {
2094 if ((m & (sizeof(long) - 1)) == 0)
2095 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 printf(" ");
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002097 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098 printf(" |");
2099 for (m = 0; m < r; ++m) {
2100 if (m < nr) {
2101 c = temp[m];
2102 putchar(' ' <= c && c <= '~'? c: '.');
2103 } else
2104 putchar(' ');
2105 }
2106 n -= r;
2107 for (; m < 16; ++m)
2108 putchar(' ');
2109 printf("|\n");
2110 if (nr < r)
2111 break;
2112 }
2113}
2114
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002115typedef int (*instruction_dump_func)(unsigned long inst, unsigned long addr);
2116
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002117static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002118generic_inst_dump(unsigned long adr, long count, int praddr,
2119 instruction_dump_func dump_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120{
2121 int nr, dotted;
2122 unsigned long first_adr;
2123 unsigned long inst, last_inst = 0;
2124 unsigned char val[4];
2125
2126 dotted = 0;
2127 for (first_adr = adr; count > 0; --count, adr += 4) {
2128 nr = mread(adr, val, 4);
2129 if (nr == 0) {
2130 if (praddr) {
2131 const char *x = fault_chars[fault_type];
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002132 printf(REG" %s%s%s%s\n", adr, x, x, x, x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133 }
2134 break;
2135 }
2136 inst = GETWORD(val);
2137 if (adr > first_adr && inst == last_inst) {
2138 if (!dotted) {
2139 printf(" ...\n");
2140 dotted = 1;
2141 }
2142 continue;
2143 }
2144 dotted = 0;
2145 last_inst = inst;
2146 if (praddr)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002147 printf(REG" %.8x", adr, inst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002148 printf("\t");
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002149 dump_func(inst, adr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150 printf("\n");
2151 }
2152 return adr - first_adr;
2153}
2154
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002155static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002156ppc_inst_dump(unsigned long adr, long count, int praddr)
2157{
2158 return generic_inst_dump(adr, count, praddr, print_insn_powerpc);
2159}
2160
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161void
2162print_address(unsigned long addr)
2163{
2164 xmon_print_symbol(addr, "\t# ", "");
2165}
2166
Vinay Sridharf312deb2009-05-14 23:13:07 +00002167void
2168dump_log_buf(void)
2169{
2170 const unsigned long size = 128;
Stephen Rothwell6d1386d2009-06-02 18:15:33 +00002171 unsigned long end, addr;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002172 unsigned char buf[size + 1];
2173
2174 addr = 0;
2175 buf[size] = '\0';
2176
2177 if (setjmp(bus_error_jmp) != 0) {
2178 printf("Unable to lookup symbol __log_buf!\n");
2179 return;
2180 }
2181
2182 catch_memory_errors = 1;
2183 sync();
2184 addr = kallsyms_lookup_name("__log_buf");
2185
2186 if (! addr)
2187 printf("Symbol __log_buf not found!\n");
2188 else {
2189 end = addr + (1 << CONFIG_LOG_BUF_SHIFT);
2190 while (addr < end) {
2191 if (! mread(addr, buf, size)) {
2192 printf("Can't read memory at address 0x%lx\n", addr);
2193 break;
2194 }
2195
2196 printf("%s", buf);
2197
2198 if (strlen(buf) < size)
2199 break;
2200
2201 addr += size;
2202 }
2203 }
2204
2205 sync();
2206 /* wait a little while to see if we get a machine check */
2207 __delay(200);
2208 catch_memory_errors = 0;
2209}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210
2211/*
2212 * Memory operations - move, set, print differences
2213 */
2214static unsigned long mdest; /* destination address */
2215static unsigned long msrc; /* source address */
2216static unsigned long mval; /* byte value to set memory to */
2217static unsigned long mcount; /* # bytes to affect */
2218static unsigned long mdiffs; /* max # differences to print */
2219
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002220static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221memops(int cmd)
2222{
2223 scanhex((void *)&mdest);
2224 if( termch != '\n' )
2225 termch = 0;
2226 scanhex((void *)(cmd == 's'? &mval: &msrc));
2227 if( termch != '\n' )
2228 termch = 0;
2229 scanhex((void *)&mcount);
2230 switch( cmd ){
2231 case 'm':
2232 memmove((void *)mdest, (void *)msrc, mcount);
2233 break;
2234 case 's':
2235 memset((void *)mdest, mval, mcount);
2236 break;
2237 case 'd':
2238 if( termch != '\n' )
2239 termch = 0;
2240 scanhex((void *)&mdiffs);
2241 memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
2242 break;
2243 }
2244}
2245
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002246static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
2248{
2249 unsigned n, prt;
2250
2251 prt = 0;
2252 for( n = nb; n > 0; --n )
2253 if( *p1++ != *p2++ )
2254 if( ++prt <= maxpr )
2255 printf("%.16x %.2x # %.16x %.2x\n", p1 - 1,
2256 p1[-1], p2 - 1, p2[-1]);
2257 if( prt > maxpr )
2258 printf("Total of %d differences\n", prt);
2259}
2260
2261static unsigned mend;
2262static unsigned mask;
2263
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002264static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265memlocate(void)
2266{
2267 unsigned a, n;
2268 unsigned char val[4];
2269
2270 last_cmd = "ml";
2271 scanhex((void *)&mdest);
2272 if (termch != '\n') {
2273 termch = 0;
2274 scanhex((void *)&mend);
2275 if (termch != '\n') {
2276 termch = 0;
2277 scanhex((void *)&mval);
2278 mask = ~0;
2279 if (termch != '\n') termch = 0;
2280 scanhex((void *)&mask);
2281 }
2282 }
2283 n = 0;
2284 for (a = mdest; a < mend; a += 4) {
2285 if (mread(a, val, 4) == 4
2286 && ((GETWORD(val) ^ mval) & mask) == 0) {
2287 printf("%.16x: %.16x\n", a, GETWORD(val));
2288 if (++n >= 10)
2289 break;
2290 }
2291 }
2292}
2293
2294static unsigned long mskip = 0x1000;
2295static unsigned long mlim = 0xffffffff;
2296
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002297static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298memzcan(void)
2299{
2300 unsigned char v;
2301 unsigned a;
2302 int ok, ook;
2303
2304 scanhex(&mdest);
2305 if (termch != '\n') termch = 0;
2306 scanhex(&mskip);
2307 if (termch != '\n') termch = 0;
2308 scanhex(&mlim);
2309 ook = 0;
2310 for (a = mdest; a < mlim; a += mskip) {
2311 ok = mread(a, &v, 1);
2312 if (ok && !ook) {
2313 printf("%.8x .. ", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314 } else if (!ok && ook)
2315 printf("%.8x\n", a - mskip);
2316 ook = ok;
2317 if (a + mskip < a)
2318 break;
2319 }
2320 if (ook)
2321 printf("%.8x\n", a - mskip);
2322}
2323
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002324static void proccall(void)
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002325{
2326 unsigned long args[8];
2327 unsigned long ret;
2328 int i;
2329 typedef unsigned long (*callfunc_t)(unsigned long, unsigned long,
2330 unsigned long, unsigned long, unsigned long,
2331 unsigned long, unsigned long, unsigned long);
2332 callfunc_t func;
2333
2334 if (!scanhex(&adrs))
2335 return;
2336 if (termch != '\n')
2337 termch = 0;
2338 for (i = 0; i < 8; ++i)
2339 args[i] = 0;
2340 for (i = 0; i < 8; ++i) {
2341 if (!scanhex(&args[i]) || termch == '\n')
2342 break;
2343 termch = 0;
2344 }
2345 func = (callfunc_t) adrs;
2346 ret = 0;
2347 if (setjmp(bus_error_jmp) == 0) {
2348 catch_memory_errors = 1;
2349 sync();
2350 ret = func(args[0], args[1], args[2], args[3],
2351 args[4], args[5], args[6], args[7]);
2352 sync();
2353 printf("return value is %x\n", ret);
2354 } else {
2355 printf("*** %x exception occurred\n", fault_except);
2356 }
2357 catch_memory_errors = 0;
2358}
2359
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360/* Input scanning routines */
2361int
2362skipbl(void)
2363{
2364 int c;
2365
2366 if( termch != 0 ){
2367 c = termch;
2368 termch = 0;
2369 } else
2370 c = inchar();
2371 while( c == ' ' || c == '\t' )
2372 c = inchar();
2373 return c;
2374}
2375
2376#define N_PTREGS 44
2377static char *regnames[N_PTREGS] = {
2378 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
2379 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
2380 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
2381 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002382 "pc", "msr", "or3", "ctr", "lr", "xer", "ccr",
2383#ifdef CONFIG_PPC64
2384 "softe",
2385#else
2386 "mq",
2387#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388 "trap", "dar", "dsisr", "res"
2389};
2390
2391int
2392scanhex(unsigned long *vp)
2393{
2394 int c, d;
2395 unsigned long v;
2396
2397 c = skipbl();
2398 if (c == '%') {
2399 /* parse register name */
2400 char regname[8];
2401 int i;
2402
2403 for (i = 0; i < sizeof(regname) - 1; ++i) {
2404 c = inchar();
2405 if (!isalnum(c)) {
2406 termch = c;
2407 break;
2408 }
2409 regname[i] = c;
2410 }
2411 regname[i] = 0;
2412 for (i = 0; i < N_PTREGS; ++i) {
2413 if (strcmp(regnames[i], regname) == 0) {
2414 if (xmon_regs == NULL) {
2415 printf("regs not available\n");
2416 return 0;
2417 }
2418 *vp = ((unsigned long *)xmon_regs)[i];
2419 return 1;
2420 }
2421 }
2422 printf("invalid register name '%%%s'\n", regname);
2423 return 0;
2424 }
2425
2426 /* skip leading "0x" if any */
2427
2428 if (c == '0') {
2429 c = inchar();
2430 if (c == 'x') {
2431 c = inchar();
2432 } else {
2433 d = hexdigit(c);
2434 if (d == EOF) {
2435 termch = c;
2436 *vp = 0;
2437 return 1;
2438 }
2439 }
2440 } else if (c == '$') {
2441 int i;
2442 for (i=0; i<63; i++) {
2443 c = inchar();
2444 if (isspace(c)) {
2445 termch = c;
2446 break;
2447 }
2448 tmpstr[i] = c;
2449 }
2450 tmpstr[i++] = 0;
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07002451 *vp = 0;
2452 if (setjmp(bus_error_jmp) == 0) {
2453 catch_memory_errors = 1;
2454 sync();
2455 *vp = kallsyms_lookup_name(tmpstr);
2456 sync();
2457 }
2458 catch_memory_errors = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459 if (!(*vp)) {
2460 printf("unknown symbol '%s'\n", tmpstr);
2461 return 0;
2462 }
2463 return 1;
2464 }
2465
2466 d = hexdigit(c);
2467 if (d == EOF) {
2468 termch = c;
2469 return 0;
2470 }
2471 v = 0;
2472 do {
2473 v = (v << 4) + d;
2474 c = inchar();
2475 d = hexdigit(c);
2476 } while (d != EOF);
2477 termch = c;
2478 *vp = v;
2479 return 1;
2480}
2481
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002482static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483scannl(void)
2484{
2485 int c;
2486
2487 c = termch;
2488 termch = 0;
2489 while( c != '\n' )
2490 c = inchar();
2491}
2492
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002493static int hexdigit(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494{
2495 if( '0' <= c && c <= '9' )
2496 return c - '0';
2497 if( 'A' <= c && c <= 'F' )
2498 return c - ('A' - 10);
2499 if( 'a' <= c && c <= 'f' )
2500 return c - ('a' - 10);
2501 return EOF;
2502}
2503
2504void
2505getstring(char *s, int size)
2506{
2507 int c;
2508
2509 c = skipbl();
2510 do {
2511 if( size > 1 ){
2512 *s++ = c;
2513 --size;
2514 }
2515 c = inchar();
2516 } while( c != ' ' && c != '\t' && c != '\n' );
2517 termch = c;
2518 *s = 0;
2519}
2520
2521static char line[256];
2522static char *lineptr;
2523
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002524static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525flush_input(void)
2526{
2527 lineptr = NULL;
2528}
2529
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002530static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531inchar(void)
2532{
2533 if (lineptr == NULL || *lineptr == 0) {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002534 if (xmon_gets(line, sizeof(line)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535 lineptr = NULL;
2536 return EOF;
2537 }
2538 lineptr = line;
2539 }
2540 return *lineptr++;
2541}
2542
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002543static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544take_input(char *str)
2545{
2546 lineptr = str;
2547}
2548
2549
2550static void
2551symbol_lookup(void)
2552{
2553 int type = inchar();
2554 unsigned long addr;
2555 static char tmp[64];
2556
2557 switch (type) {
2558 case 'a':
2559 if (scanhex(&addr))
2560 xmon_print_symbol(addr, ": ", "\n");
2561 termch = 0;
2562 break;
2563 case 's':
2564 getstring(tmp, 64);
2565 if (setjmp(bus_error_jmp) == 0) {
2566 catch_memory_errors = 1;
2567 sync();
2568 addr = kallsyms_lookup_name(tmp);
2569 if (addr)
2570 printf("%s: %lx\n", tmp, addr);
2571 else
2572 printf("Symbol '%s' not found.\n", tmp);
2573 sync();
2574 }
2575 catch_memory_errors = 0;
2576 termch = 0;
2577 break;
2578 }
2579}
2580
2581
2582/* Print an address in numeric and symbolic form (if possible) */
2583static void xmon_print_symbol(unsigned long address, const char *mid,
2584 const char *after)
2585{
2586 char *modname;
2587 const char *name = NULL;
2588 unsigned long offset, size;
2589
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002590 printf(REG, address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591 if (setjmp(bus_error_jmp) == 0) {
2592 catch_memory_errors = 1;
2593 sync();
2594 name = kallsyms_lookup(address, &size, &offset, &modname,
2595 tmpstr);
2596 sync();
2597 /* wait a little while to see if we get a machine check */
2598 __delay(200);
2599 }
2600
2601 catch_memory_errors = 0;
2602
2603 if (name) {
2604 printf("%s%s+%#lx/%#lx", mid, name, offset, size);
2605 if (modname)
2606 printf(" [%s]", modname);
2607 }
2608 printf("%s", after);
2609}
2610
Benjamin Herrenschmidt2d27cfd2009-07-23 23:15:59 +00002611#ifdef CONFIG_PPC_BOOK3S_64
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612static void dump_slb(void)
2613{
2614 int i;
will schmidtb3b95952007-12-07 08:22:23 +11002615 unsigned long esid,vsid,valid;
2616 unsigned long llp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617
2618 printf("SLB contents of cpu %x\n", smp_processor_id());
2619
Michael Neuling584f8b72007-12-06 17:24:48 +11002620 for (i = 0; i < mmu_slb_size; i++) {
will schmidtb3b95952007-12-07 08:22:23 +11002621 asm volatile("slbmfee %0,%1" : "=r" (esid) : "r" (i));
2622 asm volatile("slbmfev %0,%1" : "=r" (vsid) : "r" (i));
2623 valid = (esid & SLB_ESID_V);
2624 if (valid | esid | vsid) {
2625 printf("%02d %016lx %016lx", i, esid, vsid);
2626 if (valid) {
2627 llp = vsid & SLB_VSID_LLP;
2628 if (vsid & SLB_VSID_B_1T) {
2629 printf(" 1T ESID=%9lx VSID=%13lx LLP:%3lx \n",
2630 GET_ESID_1T(esid),
2631 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT_1T,
2632 llp);
2633 } else {
2634 printf(" 256M ESID=%9lx VSID=%13lx LLP:%3lx \n",
2635 GET_ESID(esid),
2636 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT,
2637 llp);
2638 }
2639 } else
2640 printf("\n");
2641 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642 }
2643}
2644
2645static void dump_stab(void)
2646{
2647 int i;
Benjamin Herrenschmidt7ac21cd2012-03-02 10:10:09 +11002648 unsigned long *tmp = (unsigned long *)local_paca->stab_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649
2650 printf("Segment table contents of cpu %x\n", smp_processor_id());
2651
2652 for (i = 0; i < PAGE_SIZE/16; i++) {
2653 unsigned long a, b;
2654
2655 a = *tmp++;
2656 b = *tmp++;
2657
2658 if (a || b) {
2659 printf("%03d %016lx ", i, a);
2660 printf("%016lx\n", b);
2661 }
2662 }
2663}
2664
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002665void dump_segments(void)
2666{
Matt Evans44ae3ab2011-04-06 19:48:50 +00002667 if (mmu_has_feature(MMU_FTR_SLB))
Paul Mackerrasf78541dc2005-10-28 22:53:37 +10002668 dump_slb();
2669 else
2670 dump_stab();
2671}
2672#endif
2673
2674#ifdef CONFIG_PPC_STD_MMU_32
2675void dump_segments(void)
2676{
2677 int i;
2678
2679 printf("sr0-15 =");
2680 for (i = 0; i < 16; ++i)
2681 printf(" %x", mfsrin(i));
2682 printf("\n");
2683}
2684#endif
2685
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11002686#ifdef CONFIG_44x
2687static void dump_tlb_44x(void)
2688{
2689 int i;
2690
2691 for (i = 0; i < PPC44x_TLB_SIZE; i++) {
2692 unsigned long w0,w1,w2;
2693 asm volatile("tlbre %0,%1,0" : "=r" (w0) : "r" (i));
2694 asm volatile("tlbre %0,%1,1" : "=r" (w1) : "r" (i));
2695 asm volatile("tlbre %0,%1,2" : "=r" (w2) : "r" (i));
2696 printf("[%02x] %08x %08x %08x ", i, w0, w1, w2);
2697 if (w0 & PPC44x_TLB_VALID) {
2698 printf("V %08x -> %01x%08x %c%c%c%c%c",
2699 w0 & PPC44x_TLB_EPN_MASK,
2700 w1 & PPC44x_TLB_ERPN_MASK,
2701 w1 & PPC44x_TLB_RPN_MASK,
2702 (w2 & PPC44x_TLB_W) ? 'W' : 'w',
2703 (w2 & PPC44x_TLB_I) ? 'I' : 'i',
2704 (w2 & PPC44x_TLB_M) ? 'M' : 'm',
2705 (w2 & PPC44x_TLB_G) ? 'G' : 'g',
2706 (w2 & PPC44x_TLB_E) ? 'E' : 'e');
2707 }
2708 printf("\n");
2709 }
2710}
2711#endif /* CONFIG_44x */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002712
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +10002713#ifdef CONFIG_PPC_BOOK3E
2714static void dump_tlb_book3e(void)
2715{
2716 u32 mmucfg, pidmask, lpidmask;
2717 u64 ramask;
2718 int i, tlb, ntlbs, pidsz, lpidsz, rasz, lrat = 0;
2719 int mmu_version;
2720 static const char *pgsz_names[] = {
2721 " 1K",
2722 " 2K",
2723 " 4K",
2724 " 8K",
2725 " 16K",
2726 " 32K",
2727 " 64K",
2728 "128K",
2729 "256K",
2730 "512K",
2731 " 1M",
2732 " 2M",
2733 " 4M",
2734 " 8M",
2735 " 16M",
2736 " 32M",
2737 " 64M",
2738 "128M",
2739 "256M",
2740 "512M",
2741 " 1G",
2742 " 2G",
2743 " 4G",
2744 " 8G",
2745 " 16G",
2746 " 32G",
2747 " 64G",
2748 "128G",
2749 "256G",
2750 "512G",
2751 " 1T",
2752 " 2T",
2753 };
2754
2755 /* Gather some infos about the MMU */
2756 mmucfg = mfspr(SPRN_MMUCFG);
2757 mmu_version = (mmucfg & 3) + 1;
2758 ntlbs = ((mmucfg >> 2) & 3) + 1;
2759 pidsz = ((mmucfg >> 6) & 0x1f) + 1;
2760 lpidsz = (mmucfg >> 24) & 0xf;
2761 rasz = (mmucfg >> 16) & 0x7f;
2762 if ((mmu_version > 1) && (mmucfg & 0x10000))
2763 lrat = 1;
2764 printf("Book3E MMU MAV=%d.0,%d TLBs,%d-bit PID,%d-bit LPID,%d-bit RA\n",
2765 mmu_version, ntlbs, pidsz, lpidsz, rasz);
2766 pidmask = (1ul << pidsz) - 1;
2767 lpidmask = (1ul << lpidsz) - 1;
2768 ramask = (1ull << rasz) - 1;
2769
2770 for (tlb = 0; tlb < ntlbs; tlb++) {
2771 u32 tlbcfg;
2772 int nent, assoc, new_cc = 1;
2773 printf("TLB %d:\n------\n", tlb);
2774 switch(tlb) {
2775 case 0:
2776 tlbcfg = mfspr(SPRN_TLB0CFG);
2777 break;
2778 case 1:
2779 tlbcfg = mfspr(SPRN_TLB1CFG);
2780 break;
2781 case 2:
2782 tlbcfg = mfspr(SPRN_TLB2CFG);
2783 break;
2784 case 3:
2785 tlbcfg = mfspr(SPRN_TLB3CFG);
2786 break;
2787 default:
2788 printf("Unsupported TLB number !\n");
2789 continue;
2790 }
2791 nent = tlbcfg & 0xfff;
2792 assoc = (tlbcfg >> 24) & 0xff;
2793 for (i = 0; i < nent; i++) {
2794 u32 mas0 = MAS0_TLBSEL(tlb);
2795 u32 mas1 = MAS1_TSIZE(BOOK3E_PAGESZ_4K);
2796 u64 mas2 = 0;
2797 u64 mas7_mas3;
2798 int esel = i, cc = i;
2799
2800 if (assoc != 0) {
2801 cc = i / assoc;
2802 esel = i % assoc;
2803 mas2 = cc * 0x1000;
2804 }
2805
2806 mas0 |= MAS0_ESEL(esel);
2807 mtspr(SPRN_MAS0, mas0);
2808 mtspr(SPRN_MAS1, mas1);
2809 mtspr(SPRN_MAS2, mas2);
2810 asm volatile("tlbre 0,0,0" : : : "memory");
2811 mas1 = mfspr(SPRN_MAS1);
2812 mas2 = mfspr(SPRN_MAS2);
2813 mas7_mas3 = mfspr(SPRN_MAS7_MAS3);
2814 if (assoc && (i % assoc) == 0)
2815 new_cc = 1;
2816 if (!(mas1 & MAS1_VALID))
2817 continue;
2818 if (assoc == 0)
2819 printf("%04x- ", i);
2820 else if (new_cc)
2821 printf("%04x-%c", cc, 'A' + esel);
2822 else
2823 printf(" |%c", 'A' + esel);
2824 new_cc = 0;
2825 printf(" %016llx %04x %s %c%c AS%c",
2826 mas2 & ~0x3ffull,
2827 (mas1 >> 16) & 0x3fff,
2828 pgsz_names[(mas1 >> 7) & 0x1f],
2829 mas1 & MAS1_IND ? 'I' : ' ',
2830 mas1 & MAS1_IPROT ? 'P' : ' ',
2831 mas1 & MAS1_TS ? '1' : '0');
2832 printf(" %c%c%c%c%c%c%c",
2833 mas2 & MAS2_X0 ? 'a' : ' ',
2834 mas2 & MAS2_X1 ? 'v' : ' ',
2835 mas2 & MAS2_W ? 'w' : ' ',
2836 mas2 & MAS2_I ? 'i' : ' ',
2837 mas2 & MAS2_M ? 'm' : ' ',
2838 mas2 & MAS2_G ? 'g' : ' ',
2839 mas2 & MAS2_E ? 'e' : ' ');
2840 printf(" %016llx", mas7_mas3 & ramask & ~0x7ffull);
2841 if (mas1 & MAS1_IND)
2842 printf(" %s\n",
2843 pgsz_names[(mas7_mas3 >> 1) & 0x1f]);
2844 else
2845 printf(" U%c%c%c S%c%c%c\n",
2846 mas7_mas3 & MAS3_UX ? 'x' : ' ',
2847 mas7_mas3 & MAS3_UW ? 'w' : ' ',
2848 mas7_mas3 & MAS3_UR ? 'r' : ' ',
2849 mas7_mas3 & MAS3_SX ? 'x' : ' ',
2850 mas7_mas3 & MAS3_SW ? 'w' : ' ',
2851 mas7_mas3 & MAS3_SR ? 'r' : ' ');
2852 }
2853 }
2854}
2855#endif /* CONFIG_PPC_BOOK3E */
2856
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002857static void xmon_init(int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858{
Stephen Rothwellbbb68172006-11-30 11:44:09 +11002859#ifdef CONFIG_PPC_ISERIES
2860 if (firmware_has_feature(FW_FEATURE_ISERIES))
2861 return;
2862#endif
Olaf Heringb13cfd172005-08-04 19:26:42 +02002863 if (enable) {
2864 __debugger = xmon;
2865 __debugger_ipi = xmon_ipi;
2866 __debugger_bpt = xmon_bpt;
2867 __debugger_sstep = xmon_sstep;
2868 __debugger_iabr_match = xmon_iabr_match;
2869 __debugger_dabr_match = xmon_dabr_match;
2870 __debugger_fault_handler = xmon_fault_handler;
2871 } else {
2872 __debugger = NULL;
2873 __debugger_ipi = NULL;
2874 __debugger_bpt = NULL;
2875 __debugger_sstep = NULL;
2876 __debugger_iabr_match = NULL;
2877 __debugger_dabr_match = NULL;
2878 __debugger_fault_handler = NULL;
2879 }
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002880 xmon_map_scc();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881}
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002882
2883#ifdef CONFIG_MAGIC_SYSRQ
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07002884static void sysrq_handle_xmon(int key)
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002885{
2886 /* ensure xmon is enabled */
2887 xmon_init(1);
David Howells7d12e782006-10-05 14:55:46 +01002888 debugger(get_irq_regs());
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002889}
2890
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07002891static struct sysrq_key_op sysrq_xmon_op = {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002892 .handler = sysrq_handle_xmon,
2893 .help_msg = "Xmon",
2894 .action_msg = "Entering xmon",
2895};
2896
2897static int __init setup_xmon_sysrq(void)
2898{
Stephen Rothwellbbb68172006-11-30 11:44:09 +11002899#ifdef CONFIG_PPC_ISERIES
2900 if (firmware_has_feature(FW_FEATURE_ISERIES))
2901 return 0;
2902#endif
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002903 register_sysrq_key('x', &sysrq_xmon_op);
2904 return 0;
2905}
2906__initcall(setup_xmon_sysrq);
2907#endif /* CONFIG_MAGIC_SYSRQ */
Michael Ellerman476792832006-10-03 14:12:08 +10002908
Olaf Heringf5e6a282007-06-24 16:57:08 +10002909static int __initdata xmon_early, xmon_off;
Michael Ellerman476792832006-10-03 14:12:08 +10002910
2911static int __init early_parse_xmon(char *p)
2912{
2913 if (!p || strncmp(p, "early", 5) == 0) {
2914 /* just "xmon" is equivalent to "xmon=early" */
2915 xmon_init(1);
2916 xmon_early = 1;
2917 } else if (strncmp(p, "on", 2) == 0)
2918 xmon_init(1);
2919 else if (strncmp(p, "off", 3) == 0)
2920 xmon_off = 1;
2921 else if (strncmp(p, "nobt", 4) == 0)
2922 xmon_no_auto_backtrace = 1;
2923 else
2924 return 1;
2925
2926 return 0;
2927}
2928early_param("xmon", early_parse_xmon);
2929
2930void __init xmon_setup(void)
2931{
2932#ifdef CONFIG_XMON_DEFAULT
2933 if (!xmon_off)
2934 xmon_init(1);
2935#endif
2936 if (xmon_early)
2937 debugger(NULL);
2938}
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002939
Arnd Bergmanne0555952006-11-27 19:18:55 +01002940#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002941
2942struct spu_info {
2943 struct spu *spu;
2944 u64 saved_mfc_sr1_RW;
2945 u32 saved_spu_runcntl_RW;
Michael Ellerman24a24c82006-11-23 00:46:41 +01002946 unsigned long dump_addr;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002947 u8 stopped_ok;
2948};
2949
2950#define XMON_NUM_SPUS 16 /* Enough for current hardware */
2951
2952static struct spu_info spu_info[XMON_NUM_SPUS];
2953
2954void xmon_register_spus(struct list_head *list)
2955{
2956 struct spu *spu;
2957
2958 list_for_each_entry(spu, list, full_list) {
2959 if (spu->number >= XMON_NUM_SPUS) {
2960 WARN_ON(1);
2961 continue;
2962 }
2963
2964 spu_info[spu->number].spu = spu;
2965 spu_info[spu->number].stopped_ok = 0;
Michael Ellerman24a24c82006-11-23 00:46:41 +01002966 spu_info[spu->number].dump_addr = (unsigned long)
2967 spu_info[spu->number].spu->local_store;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002968 }
2969}
2970
2971static void stop_spus(void)
2972{
2973 struct spu *spu;
2974 int i;
2975 u64 tmp;
2976
2977 for (i = 0; i < XMON_NUM_SPUS; i++) {
2978 if (!spu_info[i].spu)
2979 continue;
2980
2981 if (setjmp(bus_error_jmp) == 0) {
2982 catch_memory_errors = 1;
2983 sync();
2984
2985 spu = spu_info[i].spu;
2986
2987 spu_info[i].saved_spu_runcntl_RW =
2988 in_be32(&spu->problem->spu_runcntl_RW);
2989
2990 tmp = spu_mfc_sr1_get(spu);
2991 spu_info[i].saved_mfc_sr1_RW = tmp;
2992
2993 tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
2994 spu_mfc_sr1_set(spu, tmp);
2995
2996 sync();
2997 __delay(200);
2998
2999 spu_info[i].stopped_ok = 1;
Michael Ellerman2a144422006-11-23 00:46:40 +01003000
3001 printf("Stopped spu %.2d (was %s)\n", i,
3002 spu_info[i].saved_spu_runcntl_RW ?
3003 "running" : "stopped");
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003004 } else {
3005 catch_memory_errors = 0;
3006 printf("*** Error stopping spu %.2d\n", i);
3007 }
3008 catch_memory_errors = 0;
3009 }
3010}
3011
3012static void restart_spus(void)
3013{
3014 struct spu *spu;
3015 int i;
3016
3017 for (i = 0; i < XMON_NUM_SPUS; i++) {
3018 if (!spu_info[i].spu)
3019 continue;
3020
3021 if (!spu_info[i].stopped_ok) {
3022 printf("*** Error, spu %d was not successfully stopped"
3023 ", not restarting\n", i);
3024 continue;
3025 }
3026
3027 if (setjmp(bus_error_jmp) == 0) {
3028 catch_memory_errors = 1;
3029 sync();
3030
3031 spu = spu_info[i].spu;
3032 spu_mfc_sr1_set(spu, spu_info[i].saved_mfc_sr1_RW);
3033 out_be32(&spu->problem->spu_runcntl_RW,
3034 spu_info[i].saved_spu_runcntl_RW);
3035
3036 sync();
3037 __delay(200);
3038
3039 printf("Restarted spu %.2d\n", i);
3040 } else {
3041 catch_memory_errors = 0;
3042 printf("*** Error restarting spu %.2d\n", i);
3043 }
3044 catch_memory_errors = 0;
3045 }
3046}
3047
Michael Ellermana8984972006-10-24 18:31:28 +02003048#define DUMP_WIDTH 23
Michael Ellerman437a0702006-11-23 00:46:39 +01003049#define DUMP_VALUE(format, field, value) \
Michael Ellermana8984972006-10-24 18:31:28 +02003050do { \
3051 if (setjmp(bus_error_jmp) == 0) { \
3052 catch_memory_errors = 1; \
3053 sync(); \
3054 printf(" %-*s = "format"\n", DUMP_WIDTH, \
Michael Ellerman437a0702006-11-23 00:46:39 +01003055 #field, value); \
Michael Ellermana8984972006-10-24 18:31:28 +02003056 sync(); \
3057 __delay(200); \
3058 } else { \
3059 catch_memory_errors = 0; \
3060 printf(" %-*s = *** Error reading field.\n", \
3061 DUMP_WIDTH, #field); \
3062 } \
3063 catch_memory_errors = 0; \
3064} while (0)
3065
Michael Ellerman437a0702006-11-23 00:46:39 +01003066#define DUMP_FIELD(obj, format, field) \
3067 DUMP_VALUE(format, field, obj->field)
3068
Michael Ellermana8984972006-10-24 18:31:28 +02003069static void dump_spu_fields(struct spu *spu)
3070{
3071 printf("Dumping spu fields at address %p:\n", spu);
3072
3073 DUMP_FIELD(spu, "0x%x", number);
3074 DUMP_FIELD(spu, "%s", name);
Michael Ellermana8984972006-10-24 18:31:28 +02003075 DUMP_FIELD(spu, "0x%lx", local_store_phys);
3076 DUMP_FIELD(spu, "0x%p", local_store);
3077 DUMP_FIELD(spu, "0x%lx", ls_size);
3078 DUMP_FIELD(spu, "0x%x", node);
3079 DUMP_FIELD(spu, "0x%lx", flags);
Michael Ellermana8984972006-10-24 18:31:28 +02003080 DUMP_FIELD(spu, "%d", class_0_pending);
Luke Browningf3d69e02008-04-27 18:41:55 +00003081 DUMP_FIELD(spu, "0x%lx", class_0_dar);
Luke Browningf3d69e02008-04-27 18:41:55 +00003082 DUMP_FIELD(spu, "0x%lx", class_1_dar);
3083 DUMP_FIELD(spu, "0x%lx", class_1_dsisr);
Michael Ellermana8984972006-10-24 18:31:28 +02003084 DUMP_FIELD(spu, "0x%lx", irqs[0]);
3085 DUMP_FIELD(spu, "0x%lx", irqs[1]);
3086 DUMP_FIELD(spu, "0x%lx", irqs[2]);
3087 DUMP_FIELD(spu, "0x%x", slb_replace);
3088 DUMP_FIELD(spu, "%d", pid);
Michael Ellermana8984972006-10-24 18:31:28 +02003089 DUMP_FIELD(spu, "0x%p", mm);
3090 DUMP_FIELD(spu, "0x%p", ctx);
3091 DUMP_FIELD(spu, "0x%p", rq);
3092 DUMP_FIELD(spu, "0x%p", timestamp);
3093 DUMP_FIELD(spu, "0x%lx", problem_phys);
3094 DUMP_FIELD(spu, "0x%p", problem);
Michael Ellerman437a0702006-11-23 00:46:39 +01003095 DUMP_VALUE("0x%x", problem->spu_runcntl_RW,
3096 in_be32(&spu->problem->spu_runcntl_RW));
3097 DUMP_VALUE("0x%x", problem->spu_status_R,
3098 in_be32(&spu->problem->spu_status_R));
3099 DUMP_VALUE("0x%x", problem->spu_npc_RW,
3100 in_be32(&spu->problem->spu_npc_RW));
Michael Ellermana8984972006-10-24 18:31:28 +02003101 DUMP_FIELD(spu, "0x%p", priv2);
Michael Ellermana9852392006-11-23 00:46:50 +01003102 DUMP_FIELD(spu, "0x%p", pdata);
Michael Ellermana8984972006-10-24 18:31:28 +02003103}
3104
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003105int
3106spu_inst_dump(unsigned long adr, long count, int praddr)
3107{
3108 return generic_inst_dump(adr, count, praddr, print_insn_spu);
3109}
3110
3111static void dump_spu_ls(unsigned long num, int subcmd)
Michael Ellerman24a24c82006-11-23 00:46:41 +01003112{
3113 unsigned long offset, addr, ls_addr;
3114
3115 if (setjmp(bus_error_jmp) == 0) {
3116 catch_memory_errors = 1;
3117 sync();
3118 ls_addr = (unsigned long)spu_info[num].spu->local_store;
3119 sync();
3120 __delay(200);
3121 } else {
3122 catch_memory_errors = 0;
3123 printf("*** Error: accessing spu info for spu %d\n", num);
3124 return;
3125 }
3126 catch_memory_errors = 0;
3127
3128 if (scanhex(&offset))
3129 addr = ls_addr + offset;
3130 else
3131 addr = spu_info[num].dump_addr;
3132
3133 if (addr >= ls_addr + LS_SIZE) {
3134 printf("*** Error: address outside of local store\n");
3135 return;
3136 }
3137
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003138 switch (subcmd) {
3139 case 'i':
3140 addr += spu_inst_dump(addr, 16, 1);
3141 last_cmd = "sdi\n";
3142 break;
3143 default:
3144 prdump(addr, 64);
3145 addr += 64;
3146 last_cmd = "sd\n";
3147 break;
3148 }
Michael Ellerman24a24c82006-11-23 00:46:41 +01003149
3150 spu_info[num].dump_addr = addr;
3151}
3152
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003153static int do_spu_cmd(void)
3154{
Michael Ellerman24a24c82006-11-23 00:46:41 +01003155 static unsigned long num = 0;
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003156 int cmd, subcmd = 0;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003157
3158 cmd = inchar();
3159 switch (cmd) {
3160 case 's':
3161 stop_spus();
3162 break;
3163 case 'r':
3164 restart_spus();
3165 break;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003166 case 'd':
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003167 subcmd = inchar();
3168 if (isxdigit(subcmd) || subcmd == '\n')
3169 termch = subcmd;
3170 case 'f':
Michael Ellerman24a24c82006-11-23 00:46:41 +01003171 scanhex(&num);
3172 if (num >= XMON_NUM_SPUS || !spu_info[num].spu) {
Michael Ellermana8984972006-10-24 18:31:28 +02003173 printf("*** Error: invalid spu number\n");
Michael Ellerman24a24c82006-11-23 00:46:41 +01003174 return 0;
3175 }
3176
3177 switch (cmd) {
3178 case 'f':
3179 dump_spu_fields(spu_info[num].spu);
3180 break;
3181 default:
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003182 dump_spu_ls(num, subcmd);
Michael Ellerman24a24c82006-11-23 00:46:41 +01003183 break;
3184 }
3185
Michael Ellermana8984972006-10-24 18:31:28 +02003186 break;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003187 default:
3188 return -1;
3189 }
3190
3191 return 0;
3192}
Arnd Bergmanne0555952006-11-27 19:18:55 +01003193#else /* ! CONFIG_SPU_BASE */
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003194static int do_spu_cmd(void)
3195{
3196 return -1;
3197}
3198#endif