blob: 42541bbcc7fa551b81254f9e4068870b0596a35c [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 Mackerrasf78541d2005-10-28 22:53:37 +100021#include <linux/module.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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-10-28 22:53:37 +100045
46#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -070047#include <asm/hvcall.h>
Paul Mackerrasf78541d2005-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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-10-28 22:53:37 +1000164extern void xmon_enter(void);
165extern void xmon_leave(void);
166
Paul Mackerrasf78541d2005-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 Mackerrasf78541d2005-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 Mackerrasf78541d2005-10-28 22:53:37 +1000230 X exit monitor and dont recover\n"
231#ifdef CONFIG_PPC64
232" u dump segment table or SLB\n"
233#endif
234#ifdef CONFIG_PPC_STD_MMU_32
235" u dump segment registers\n"
236#endif
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100237#ifdef CONFIG_44x
238" u dump TLB\n"
239#endif
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000240" ? help\n"
241" zr reboot\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 zh halt\n"
243;
244
245static struct pt_regs *xmon_regs;
246
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000247static inline void sync(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248{
249 asm volatile("sync; isync");
250}
251
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000252static inline void store_inst(void *p)
253{
254 asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p));
255}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000257static inline void cflush(void *p)
258{
259 asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p));
260}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000262static inline void cinval(void *p)
263{
264 asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p));
265}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266
267/*
268 * Disable surveillance (the service processor watchdog function)
269 * while we are in xmon.
270 * XXX we should re-enable it when we leave. :)
271 */
272#define SURVEILLANCE_TOKEN 9000
273
274static inline void disable_surveillance(void)
275{
276#ifdef CONFIG_PPC_PSERIES
277 /* Since this can't be a module, args should end up below 4GB. */
278 static struct rtas_args args;
279
280 /*
281 * At this point we have got all the cpus we can into
282 * xmon, so there is hopefully no other cpu calling RTAS
283 * at the moment, even though we don't take rtas.lock.
284 * If we did try to take rtas.lock there would be a
285 * real possibility of deadlock.
286 */
287 args.token = rtas_token("set-indicator");
288 if (args.token == RTAS_UNKNOWN_SERVICE)
289 return;
290 args.nargs = 3;
291 args.nret = 1;
292 args.rets = &args.args[3];
293 args.args[0] = SURVEILLANCE_TOKEN;
294 args.args[1] = 0;
295 args.args[2] = 0;
296 enter_rtas(__pa(&args));
297#endif /* CONFIG_PPC_PSERIES */
298}
299
300#ifdef CONFIG_SMP
301static int xmon_speaker;
302
303static void get_output_lock(void)
304{
305 int me = smp_processor_id() + 0x100;
306 int last_speaker = 0, prev;
307 long timeout;
308
309 if (xmon_speaker == me)
310 return;
311 for (;;) {
312 if (xmon_speaker == 0) {
313 last_speaker = cmpxchg(&xmon_speaker, 0, me);
314 if (last_speaker == 0)
315 return;
316 }
317 timeout = 10000000;
318 while (xmon_speaker == last_speaker) {
319 if (--timeout > 0)
320 continue;
321 /* hostile takeover */
322 prev = cmpxchg(&xmon_speaker, last_speaker, me);
323 if (prev == last_speaker)
324 return;
325 break;
326 }
327 }
328}
329
330static void release_output_lock(void)
331{
332 xmon_speaker = 0;
333}
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000334
335int cpus_are_in_xmon(void)
336{
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000337 return !cpumask_empty(&cpus_in_xmon);
Michael Ellerman1c8950f2008-05-08 14:27:17 +1000338}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339#endif
340
Josh Boyerdaf8f402009-09-23 03:51:04 +0000341static inline int unrecoverable_excp(struct pt_regs *regs)
342{
343#ifdef CONFIG_4xx
344 /* We have no MSR_RI bit on 4xx, so we simply return false */
345 return 0;
346#else
347 return ((regs->msr & MSR_RI) == 0);
348#endif
349}
350
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000351static int xmon_core(struct pt_regs *regs, int fromipi)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352{
353 int cmd = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 struct bpt *bp;
355 long recurse_jmp[JMP_BUF_LEN];
356 unsigned long offset;
Anton Blanchardf13659e2007-03-21 01:48:34 +1100357 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358#ifdef CONFIG_SMP
359 int cpu;
360 int secondary;
361 unsigned long timeout;
362#endif
363
Anton Blanchardf13659e2007-03-21 01:48:34 +1100364 local_irq_save(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365
366 bp = in_breakpoint_table(regs->nip, &offset);
367 if (bp != NULL) {
368 regs->nip = bp->address + offset;
369 atomic_dec(&bp->ref_count);
370 }
371
372 remove_cpu_bpts();
373
374#ifdef CONFIG_SMP
375 cpu = smp_processor_id();
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000376 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 get_output_lock();
378 excprint(regs);
379 printf("cpu 0x%x: Exception %lx %s in xmon, "
380 "returning to main loop\n",
381 cpu, regs->trap, getvecname(TRAP(regs)));
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000382 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 longjmp(xmon_fault_jmp[cpu], 1);
384 }
385
386 if (setjmp(recurse_jmp) != 0) {
387 if (!in_xmon || !xmon_gate) {
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000388 get_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 printf("xmon: WARNING: bad recursive fault "
390 "on cpu 0x%x\n", cpu);
Haren Myneni5cb4cc02005-08-03 15:08:18 +1000391 release_output_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 goto waiting;
393 }
394 secondary = !(xmon_taken && cpu == xmon_owner);
395 goto cmdloop;
396 }
397
398 xmon_fault_jmp[cpu] = recurse_jmp;
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000399 cpumask_set_cpu(cpu, &cpus_in_xmon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400
401 bp = NULL;
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000402 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 bp = at_breakpoint(regs->nip);
Josh Boyerdaf8f402009-09-23 03:51:04 +0000404 if (bp || unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 fromipi = 0;
406
407 if (!fromipi) {
408 get_output_lock();
409 excprint(regs);
410 if (bp) {
411 printf("cpu 0x%x stopped at breakpoint 0x%x (",
412 cpu, BP_NUM(bp));
413 xmon_print_symbol(regs->nip, " ", ")\n");
414 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000415 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 printf("WARNING: exception is not recoverable, "
417 "can't continue\n");
418 release_output_lock();
419 }
420
421 waiting:
422 secondary = 1;
423 while (secondary && !xmon_gate) {
424 if (in_xmon == 0) {
425 if (fromipi)
426 goto leave;
427 secondary = test_and_set_bit(0, &in_xmon);
428 }
429 barrier();
430 }
431
432 if (!secondary && !xmon_gate) {
433 /* we are the first cpu to come in */
434 /* interrupt other cpu(s) */
435 int ncpus = num_online_cpus();
436
437 xmon_owner = cpu;
438 mb();
439 if (ncpus > 1) {
Milton Millere0476372011-05-10 19:29:06 +0000440 smp_send_debugger_break();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 /* wait for other cpus to come in */
442 for (timeout = 100000000; timeout != 0; --timeout) {
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000443 if (cpumask_weight(&cpus_in_xmon) >= ncpus)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 break;
445 barrier();
446 }
447 }
448 remove_bpts();
449 disable_surveillance();
450 /* for breakpoint or single step, print the current instr. */
451 if (bp || TRAP(regs) == 0xd00)
452 ppc_inst_dump(regs->nip, 1, 0);
453 printf("enter ? for help\n");
454 mb();
455 xmon_gate = 1;
456 barrier();
457 }
458
459 cmdloop:
460 while (in_xmon) {
461 if (secondary) {
462 if (cpu == xmon_owner) {
463 if (!test_and_set_bit(0, &xmon_taken)) {
464 secondary = 0;
465 continue;
466 }
467 /* missed it */
468 while (cpu == xmon_owner)
469 barrier();
470 }
471 barrier();
472 } else {
473 cmd = cmds(regs);
474 if (cmd != 0) {
475 /* exiting xmon */
476 insert_bpts();
477 xmon_gate = 0;
478 wmb();
479 in_xmon = 0;
480 break;
481 }
482 /* have switched to some other cpu */
483 secondary = 1;
484 }
485 }
486 leave:
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000487 cpumask_clear_cpu(cpu, &cpus_in_xmon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 xmon_fault_jmp[cpu] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489#else
490 /* UP is simple... */
491 if (in_xmon) {
492 printf("Exception %lx %s in xmon, returning to main loop\n",
493 regs->trap, getvecname(TRAP(regs)));
494 longjmp(xmon_fault_jmp[0], 1);
495 }
496 if (setjmp(recurse_jmp) == 0) {
497 xmon_fault_jmp[0] = recurse_jmp;
498 in_xmon = 1;
499
500 excprint(regs);
501 bp = at_breakpoint(regs->nip);
502 if (bp) {
503 printf("Stopped at breakpoint %x (", BP_NUM(bp));
504 xmon_print_symbol(regs->nip, " ", ")\n");
505 }
Josh Boyerdaf8f402009-09-23 03:51:04 +0000506 if (unrecoverable_excp(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 printf("WARNING: exception is not recoverable, "
508 "can't continue\n");
509 remove_bpts();
510 disable_surveillance();
511 /* for breakpoint or single step, print the current instr. */
512 if (bp || TRAP(regs) == 0xd00)
513 ppc_inst_dump(regs->nip, 1, 0);
514 printf("enter ? for help\n");
515 }
516
517 cmd = cmds(regs);
518
519 insert_bpts();
520 in_xmon = 0;
521#endif
522
Josh Boyercdd39042009-10-05 04:46:05 +0000523#ifdef CONFIG_BOOKE
524 if (regs->msr & MSR_DE) {
525 bp = at_breakpoint(regs->nip);
526 if (bp != NULL) {
527 regs->nip = (unsigned long) &bp->instr[0];
528 atomic_inc(&bp->ref_count);
529 }
530 }
531#else
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000532 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 bp = at_breakpoint(regs->nip);
534 if (bp != NULL) {
535 int stepped = emulate_step(regs, bp->instr[0]);
536 if (stepped == 0) {
537 regs->nip = (unsigned long) &bp->instr[0];
538 atomic_inc(&bp->ref_count);
539 } else if (stepped < 0) {
540 printf("Couldn't single-step %s instruction\n",
541 (IS_RFID(bp->instr[0])? "rfid": "mtmsrd"));
542 }
543 }
544 }
Josh Boyercdd39042009-10-05 04:46:05 +0000545#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 insert_cpu_bpts();
547
Anton Blanchardf13659e2007-03-21 01:48:34 +1100548 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549
Paul Mackerras0a730ae2006-10-03 21:32:49 +1000550 return cmd != 'X' && cmd != EOF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551}
552
553int xmon(struct pt_regs *excp)
554{
555 struct pt_regs regs;
556
557 if (excp == NULL) {
Anton Vorontsov322b4392008-12-17 10:08:55 +0000558 ppc_save_regs(&regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 excp = &regs;
560 }
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200561
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 return xmon_core(excp, 0);
563}
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000564EXPORT_SYMBOL(xmon);
565
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000566irqreturn_t xmon_irq(int irq, void *d)
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000567{
568 unsigned long flags;
569 local_irq_save(flags);
570 printf("Keyboard interrupt\n");
Paul Mackerrasf583ffc2006-10-10 11:47:07 +1000571 xmon(get_irq_regs());
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000572 local_irq_restore(flags);
573 return IRQ_HANDLED;
574}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000576static int xmon_bpt(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577{
578 struct bpt *bp;
579 unsigned long offset;
580
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000581 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 return 0;
583
584 /* Are we at the trap at bp->instr[1] for some bp? */
585 bp = in_breakpoint_table(regs->nip, &offset);
586 if (bp != NULL && offset == 4) {
587 regs->nip = bp->address + 4;
588 atomic_dec(&bp->ref_count);
589 return 1;
590 }
591
592 /* Are we at a breakpoint? */
593 bp = at_breakpoint(regs->nip);
594 if (!bp)
595 return 0;
596
597 xmon_core(regs, 0);
598
599 return 1;
600}
601
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000602static int xmon_sstep(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603{
604 if (user_mode(regs))
605 return 0;
606 xmon_core(regs, 0);
607 return 1;
608}
609
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000610static int xmon_dabr_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000612 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 return 0;
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000614 if (dabr.enabled == 0)
615 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 xmon_core(regs, 0);
617 return 1;
618}
619
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000620static int xmon_iabr_match(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621{
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000622 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 return 0;
Michael Ellerman9f1067c22008-05-08 14:27:16 +1000624 if (iabr == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 return 0;
626 xmon_core(regs, 0);
627 return 1;
628}
629
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000630static int xmon_ipi(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631{
632#ifdef CONFIG_SMP
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000633 if (in_xmon && !cpumask_test_cpu(smp_processor_id(), &cpus_in_xmon))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 xmon_core(regs, 1);
635#endif
636 return 0;
637}
638
Arnd Bergmannb0da9852006-01-11 00:00:05 +0000639static int xmon_fault_handler(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640{
641 struct bpt *bp;
642 unsigned long offset;
643
644 if (in_xmon && catch_memory_errors)
645 handle_fault(regs); /* doesn't return */
646
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000647 if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 bp = in_breakpoint_table(regs->nip, &offset);
649 if (bp != NULL) {
650 regs->nip = bp->address + offset;
651 atomic_dec(&bp->ref_count);
652 }
653 }
654
655 return 0;
656}
657
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658static struct bpt *at_breakpoint(unsigned long pc)
659{
660 int i;
661 struct bpt *bp;
662
663 bp = bpts;
664 for (i = 0; i < NBPTS; ++i, ++bp)
665 if (bp->enabled && pc == bp->address)
666 return bp;
667 return NULL;
668}
669
670static struct bpt *in_breakpoint_table(unsigned long nip, unsigned long *offp)
671{
672 unsigned long off;
673
674 off = nip - (unsigned long) bpts;
675 if (off >= sizeof(bpts))
676 return NULL;
677 off %= sizeof(struct bpt);
678 if (off != offsetof(struct bpt, instr[0])
679 && off != offsetof(struct bpt, instr[1]))
680 return NULL;
681 *offp = off - offsetof(struct bpt, instr[0]);
682 return (struct bpt *) (nip - off);
683}
684
685static struct bpt *new_breakpoint(unsigned long a)
686{
687 struct bpt *bp;
688
689 a &= ~3UL;
690 bp = at_breakpoint(a);
691 if (bp)
692 return bp;
693
694 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
695 if (!bp->enabled && atomic_read(&bp->ref_count) == 0) {
696 bp->address = a;
697 bp->instr[1] = bpinstr;
698 store_inst(&bp->instr[1]);
699 return bp;
700 }
701 }
702
703 printf("Sorry, no free breakpoints. Please clear one first.\n");
704 return NULL;
705}
706
707static void insert_bpts(void)
708{
709 int i;
710 struct bpt *bp;
711
712 bp = bpts;
713 for (i = 0; i < NBPTS; ++i, ++bp) {
714 if ((bp->enabled & (BP_TRAP|BP_IABR)) == 0)
715 continue;
716 if (mread(bp->address, &bp->instr[0], 4) != 4) {
717 printf("Couldn't read instruction at %lx, "
718 "disabling breakpoint there\n", bp->address);
719 bp->enabled = 0;
720 continue;
721 }
722 if (IS_MTMSRD(bp->instr[0]) || IS_RFID(bp->instr[0])) {
723 printf("Breakpoint at %lx is on an mtmsrd or rfid "
724 "instruction, disabling it\n", bp->address);
725 bp->enabled = 0;
726 continue;
727 }
728 store_inst(&bp->instr[0]);
729 if (bp->enabled & BP_IABR)
730 continue;
731 if (mwrite(bp->address, &bpinstr, 4) != 4) {
732 printf("Couldn't write instruction at %lx, "
733 "disabling breakpoint there\n", bp->address);
734 bp->enabled &= ~BP_TRAP;
735 continue;
736 }
737 store_inst((void *)bp->address);
738 }
739}
740
741static void insert_cpu_bpts(void)
742{
743 if (dabr.enabled)
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000744 set_dabr(dabr.address | (dabr.enabled & 7));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 if (iabr && cpu_has_feature(CPU_FTR_IABR))
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000746 mtspr(SPRN_IABR, iabr->address
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 | (iabr->enabled & (BP_IABR|BP_IABR_TE)));
748}
749
750static void remove_bpts(void)
751{
752 int i;
753 struct bpt *bp;
754 unsigned instr;
755
756 bp = bpts;
757 for (i = 0; i < NBPTS; ++i, ++bp) {
758 if ((bp->enabled & (BP_TRAP|BP_IABR)) != BP_TRAP)
759 continue;
760 if (mread(bp->address, &instr, 4) == 4
761 && instr == bpinstr
762 && mwrite(bp->address, &bp->instr, 4) != 4)
763 printf("Couldn't remove breakpoint at %lx\n",
764 bp->address);
765 else
766 store_inst((void *)bp->address);
767 }
768}
769
770static void remove_cpu_bpts(void)
771{
Anton Blanchardfd9648d2005-09-10 16:01:11 +1000772 set_dabr(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 if (cpu_has_feature(CPU_FTR_IABR))
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000774 mtspr(SPRN_IABR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775}
776
777/* Command interpreting routine */
778static char *last_cmd;
779
780static int
781cmds(struct pt_regs *excp)
782{
783 int cmd = 0;
784
785 last_cmd = NULL;
786 xmon_regs = excp;
Olaf Hering26c8af52006-09-08 16:29:21 +0200787
788 if (!xmon_no_auto_backtrace) {
789 xmon_no_auto_backtrace = 1;
790 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
791 }
792
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 for(;;) {
794#ifdef CONFIG_SMP
795 printf("%x:", smp_processor_id());
796#endif /* CONFIG_SMP */
797 printf("mon> ");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 flush_input();
799 termch = 0;
800 cmd = skipbl();
801 if( cmd == '\n' ) {
802 if (last_cmd == NULL)
803 continue;
804 take_input(last_cmd);
805 last_cmd = NULL;
806 cmd = inchar();
807 }
808 switch (cmd) {
809 case 'm':
810 cmd = inchar();
811 switch (cmd) {
812 case 'm':
813 case 's':
814 case 'd':
815 memops(cmd);
816 break;
817 case 'l':
818 memlocate();
819 break;
820 case 'z':
821 memzcan();
822 break;
823 case 'i':
David Rientjesb2b755b2011-03-24 15:18:15 -0700824 show_mem(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 break;
826 default:
827 termch = cmd;
828 memex();
829 }
830 break;
831 case 'd':
832 dump();
833 break;
834 case 'l':
835 symbol_lookup();
836 break;
837 case 'r':
838 prregs(excp); /* print regs */
839 break;
840 case 'e':
841 excprint(excp);
842 break;
843 case 'S':
844 super_regs();
845 break;
846 case 't':
847 backtrace(excp);
848 break;
849 case 'f':
850 cacheflush();
851 break;
852 case 's':
Michael Ellermanff8a8f22006-10-24 18:31:27 +0200853 if (do_spu_cmd() == 0)
854 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 if (do_step(excp))
856 return cmd;
857 break;
858 case 'x':
859 case 'X':
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100860 return cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 case EOF:
Benjamin Herrenschmidtbb6b9b22005-11-30 16:54:12 +1100862 printf(" <no input ...>\n");
863 mdelay(2000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 return cmd;
865 case '?':
Ishizaki Kou4d404ed2007-07-18 19:26:40 +1000866 xmon_puts(help_string);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 case 'b':
869 bpt_cmds();
870 break;
871 case 'C':
872 csum();
873 break;
874 case 'c':
875 if (cpu_cmd())
876 return 0;
877 break;
878 case 'z':
879 bootcmds();
880 break;
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000881 case 'p':
882 proccall();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 break;
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000884#ifdef CONFIG_PPC_STD_MMU
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 case 'u':
886 dump_segments();
887 break;
Paul Mackerrasf78541d2005-10-28 22:53:37 +1000888#endif
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +1100889#ifdef CONFIG_4xx
890 case 'u':
891 dump_tlb_44x();
892 break;
893#endif
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +1000894#ifdef CONFIG_PPC_BOOK3E
895 case 'u':
896 dump_tlb_book3e();
897 break;
898#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 default:
900 printf("Unrecognized command: ");
901 do {
902 if (' ' < cmd && cmd <= '~')
903 putchar(cmd);
904 else
905 printf("\\x%x", cmd);
906 cmd = inchar();
907 } while (cmd != '\n');
908 printf(" (type ? for help)\n");
909 break;
910 }
911 }
912}
913
Josh Boyercdd39042009-10-05 04:46:05 +0000914#ifdef CONFIG_BOOKE
915static int do_step(struct pt_regs *regs)
916{
917 regs->msr |= MSR_DE;
918 mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
919 return 1;
920}
921#else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922/*
923 * Step a single instruction.
924 * Some instructions we emulate, others we execute with MSR_SE set.
925 */
926static int do_step(struct pt_regs *regs)
927{
928 unsigned int instr;
929 int stepped;
930
931 /* check we are in 64-bit kernel mode, translation enabled */
Michael Ellerman9f0b0792011-04-07 21:56:03 +0000932 if ((regs->msr & (MSR_64BIT|MSR_PR|MSR_IR)) == (MSR_64BIT|MSR_IR)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 if (mread(regs->nip, &instr, 4) == 4) {
934 stepped = emulate_step(regs, instr);
935 if (stepped < 0) {
936 printf("Couldn't single-step %s instruction\n",
937 (IS_RFID(instr)? "rfid": "mtmsrd"));
938 return 0;
939 }
940 if (stepped > 0) {
941 regs->trap = 0xd00 | (regs->trap & 1);
942 printf("stepped to ");
943 xmon_print_symbol(regs->nip, " ", "\n");
944 ppc_inst_dump(regs->nip, 1, 0);
945 return 0;
946 }
947 }
948 }
949 regs->msr |= MSR_SE;
950 return 1;
951}
Josh Boyercdd39042009-10-05 04:46:05 +0000952#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953
954static void bootcmds(void)
955{
956 int cmd;
957
958 cmd = inchar();
959 if (cmd == 'r')
960 ppc_md.restart(NULL);
961 else if (cmd == 'h')
962 ppc_md.halt();
963 else if (cmd == 'p')
964 ppc_md.power_off();
965}
966
967static int cpu_cmd(void)
968{
969#ifdef CONFIG_SMP
970 unsigned long cpu;
971 int timeout;
972 int count;
973
974 if (!scanhex(&cpu)) {
975 /* print cpus waiting or in xmon */
976 printf("cpus stopped:");
977 count = 0;
978 for (cpu = 0; cpu < NR_CPUS; ++cpu) {
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000979 if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 if (count == 0)
981 printf(" %x", cpu);
982 ++count;
983 } else {
984 if (count > 1)
985 printf("-%x", cpu - 1);
986 count = 0;
987 }
988 }
989 if (count > 1)
990 printf("-%x", NR_CPUS - 1);
991 printf("\n");
992 return 0;
993 }
994 /* try to switch to cpu specified */
KOSAKI Motohiro104699c2011-04-28 05:07:23 +0000995 if (!cpumask_test_cpu(cpu, &cpus_in_xmon)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 printf("cpu 0x%x isn't in xmon\n", cpu);
997 return 0;
998 }
999 xmon_taken = 0;
1000 mb();
1001 xmon_owner = cpu;
1002 timeout = 10000000;
1003 while (!xmon_taken) {
1004 if (--timeout == 0) {
1005 if (test_and_set_bit(0, &xmon_taken))
1006 break;
1007 /* take control back */
1008 mb();
1009 xmon_owner = smp_processor_id();
1010 printf("cpu %u didn't take control\n", cpu);
1011 return 0;
1012 }
1013 barrier();
1014 }
1015 return 1;
1016#else
1017 return 0;
1018#endif /* CONFIG_SMP */
1019}
1020
1021static unsigned short fcstab[256] = {
1022 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
1023 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
1024 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
1025 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
1026 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
1027 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
1028 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
1029 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
1030 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
1031 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
1032 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
1033 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
1034 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
1035 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
1036 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
1037 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
1038 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
1039 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
1040 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
1041 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
1042 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
1043 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
1044 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
1045 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
1046 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
1047 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
1048 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
1049 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
1050 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
1051 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
1052 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
1053 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
1054};
1055
1056#define FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
1057
1058static void
1059csum(void)
1060{
1061 unsigned int i;
1062 unsigned short fcs;
1063 unsigned char v;
1064
1065 if (!scanhex(&adrs))
1066 return;
1067 if (!scanhex(&ncsum))
1068 return;
1069 fcs = 0xffff;
1070 for (i = 0; i < ncsum; ++i) {
1071 if (mread(adrs+i, &v, 1) == 0) {
1072 printf("csum stopped at %x\n", adrs+i);
1073 break;
1074 }
1075 fcs = FCS(fcs, v);
1076 }
1077 printf("%x\n", fcs);
1078}
1079
1080/*
1081 * Check if this is a suitable place to put a breakpoint.
1082 */
1083static long check_bp_loc(unsigned long addr)
1084{
1085 unsigned int instr;
1086
1087 addr &= ~3;
Michael Ellerman51fae6d2005-12-04 18:39:15 +11001088 if (!is_kernel_addr(addr)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 printf("Breakpoints may only be placed at kernel addresses\n");
1090 return 0;
1091 }
1092 if (!mread(addr, &instr, sizeof(instr))) {
1093 printf("Can't read instruction at address %lx\n", addr);
1094 return 0;
1095 }
1096 if (IS_MTMSRD(instr) || IS_RFID(instr)) {
1097 printf("Breakpoints may not be placed on mtmsrd or rfid "
1098 "instructions\n");
1099 return 0;
1100 }
1101 return 1;
1102}
1103
1104static char *breakpoint_help_string =
1105 "Breakpoint command usage:\n"
1106 "b show breakpoints\n"
1107 "b <addr> [cnt] set breakpoint at given instr addr\n"
1108 "bc clear all breakpoints\n"
1109 "bc <n/addr> clear breakpoint number n or at addr\n"
1110 "bi <addr> [cnt] set hardware instr breakpoint (POWER3/RS64 only)\n"
1111 "bd <addr> [cnt] set hardware data breakpoint\n"
1112 "";
1113
1114static void
1115bpt_cmds(void)
1116{
1117 int cmd;
1118 unsigned long a;
1119 int mode, i;
1120 struct bpt *bp;
1121 const char badaddr[] = "Only kernel addresses are permitted "
1122 "for breakpoints\n";
1123
1124 cmd = inchar();
1125 switch (cmd) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001126#ifndef CONFIG_8xx
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 case 'd': /* bd - hardware data breakpoint */
1128 mode = 7;
1129 cmd = inchar();
1130 if (cmd == 'r')
1131 mode = 5;
1132 else if (cmd == 'w')
1133 mode = 6;
1134 else
1135 termch = cmd;
1136 dabr.address = 0;
1137 dabr.enabled = 0;
1138 if (scanhex(&dabr.address)) {
Michael Ellerman51fae6d2005-12-04 18:39:15 +11001139 if (!is_kernel_addr(dabr.address)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 printf(badaddr);
1141 break;
1142 }
1143 dabr.address &= ~7;
1144 dabr.enabled = mode | BP_DABR;
1145 }
1146 break;
1147
1148 case 'i': /* bi - hardware instr breakpoint */
1149 if (!cpu_has_feature(CPU_FTR_IABR)) {
1150 printf("Hardware instruction breakpoint "
1151 "not supported on this cpu\n");
1152 break;
1153 }
1154 if (iabr) {
1155 iabr->enabled &= ~(BP_IABR | BP_IABR_TE);
1156 iabr = NULL;
1157 }
1158 if (!scanhex(&a))
1159 break;
1160 if (!check_bp_loc(a))
1161 break;
1162 bp = new_breakpoint(a);
1163 if (bp != NULL) {
1164 bp->enabled |= BP_IABR | BP_IABR_TE;
1165 iabr = bp;
1166 }
1167 break;
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001168#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169
1170 case 'c':
1171 if (!scanhex(&a)) {
1172 /* clear all breakpoints */
1173 for (i = 0; i < NBPTS; ++i)
1174 bpts[i].enabled = 0;
1175 iabr = NULL;
1176 dabr.enabled = 0;
1177 printf("All breakpoints cleared\n");
1178 break;
1179 }
1180
1181 if (a <= NBPTS && a >= 1) {
1182 /* assume a breakpoint number */
1183 bp = &bpts[a-1]; /* bp nums are 1 based */
1184 } else {
1185 /* assume a breakpoint address */
1186 bp = at_breakpoint(a);
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001187 if (bp == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 printf("No breakpoint at %x\n", a);
1189 break;
1190 }
1191 }
1192
1193 printf("Cleared breakpoint %x (", BP_NUM(bp));
1194 xmon_print_symbol(bp->address, " ", ")\n");
1195 bp->enabled = 0;
1196 break;
1197
1198 default:
1199 termch = cmd;
1200 cmd = skipbl();
1201 if (cmd == '?') {
1202 printf(breakpoint_help_string);
1203 break;
1204 }
1205 termch = cmd;
1206 if (!scanhex(&a)) {
1207 /* print all breakpoints */
1208 printf(" type address\n");
1209 if (dabr.enabled) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001210 printf(" data "REG" [", dabr.address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 if (dabr.enabled & 1)
1212 printf("r");
1213 if (dabr.enabled & 2)
1214 printf("w");
1215 printf("]\n");
1216 }
1217 for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
1218 if (!bp->enabled)
1219 continue;
1220 printf("%2x %s ", BP_NUM(bp),
1221 (bp->enabled & BP_IABR)? "inst": "trap");
1222 xmon_print_symbol(bp->address, " ", "\n");
1223 }
1224 break;
1225 }
1226
1227 if (!check_bp_loc(a))
1228 break;
1229 bp = new_breakpoint(a);
1230 if (bp != NULL)
1231 bp->enabled |= BP_TRAP;
1232 break;
1233 }
1234}
1235
1236/* Very cheap human name for vector lookup. */
1237static
1238const char *getvecname(unsigned long vec)
1239{
1240 char *ret;
1241
1242 switch (vec) {
1243 case 0x100: ret = "(System Reset)"; break;
1244 case 0x200: ret = "(Machine Check)"; break;
1245 case 0x300: ret = "(Data Access)"; break;
1246 case 0x380: ret = "(Data SLB Access)"; break;
1247 case 0x400: ret = "(Instruction Access)"; break;
1248 case 0x480: ret = "(Instruction SLB Access)"; break;
1249 case 0x500: ret = "(Hardware Interrupt)"; break;
1250 case 0x600: ret = "(Alignment)"; break;
1251 case 0x700: ret = "(Program Check)"; break;
1252 case 0x800: ret = "(FPU Unavailable)"; break;
1253 case 0x900: ret = "(Decrementer)"; break;
1254 case 0xc00: ret = "(System Call)"; break;
1255 case 0xd00: ret = "(Single Step)"; break;
1256 case 0xf00: ret = "(Performance Monitor)"; break;
1257 case 0xf20: ret = "(Altivec Unavailable)"; break;
1258 case 0x1300: ret = "(Instruction Breakpoint)"; break;
1259 default: ret = "";
1260 }
1261 return ret;
1262}
1263
1264static void get_function_bounds(unsigned long pc, unsigned long *startp,
1265 unsigned long *endp)
1266{
1267 unsigned long size, offset;
1268 const char *name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269
1270 *startp = *endp = 0;
1271 if (pc == 0)
1272 return;
1273 if (setjmp(bus_error_jmp) == 0) {
1274 catch_memory_errors = 1;
1275 sync();
Alexey Dobriyanffb45122007-05-08 00:28:41 -07001276 name = kallsyms_lookup(pc, &size, &offset, NULL, tmpstr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 if (name != NULL) {
1278 *startp = pc - offset;
1279 *endp = pc - offset + size;
1280 }
1281 sync();
1282 }
1283 catch_memory_errors = 0;
1284}
1285
1286static int xmon_depth_to_print = 64;
1287
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001288#define LRSAVE_OFFSET (STACK_FRAME_LR_SAVE * sizeof(unsigned long))
1289#define MARKER_OFFSET (STACK_FRAME_MARKER * sizeof(unsigned long))
1290
1291#ifdef __powerpc64__
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001292#define REGS_OFFSET 0x70
1293#else
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001294#define REGS_OFFSET 16
1295#endif
1296
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297static void xmon_show_stack(unsigned long sp, unsigned long lr,
1298 unsigned long pc)
1299{
1300 unsigned long ip;
1301 unsigned long newsp;
1302 unsigned long marker;
1303 int count = 0;
1304 struct pt_regs regs;
1305
1306 do {
1307 if (sp < PAGE_OFFSET) {
1308 if (sp != 0)
1309 printf("SP (%lx) is in userspace\n", sp);
1310 break;
1311 }
1312
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001313 if (!mread(sp + LRSAVE_OFFSET, &ip, sizeof(unsigned long))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 || !mread(sp, &newsp, sizeof(unsigned long))) {
1315 printf("Couldn't read stack frame at %lx\n", sp);
1316 break;
1317 }
1318
1319 /*
1320 * For the first stack frame, try to work out if
1321 * LR and/or the saved LR value in the bottommost
1322 * stack frame are valid.
1323 */
1324 if ((pc | lr) != 0) {
1325 unsigned long fnstart, fnend;
1326 unsigned long nextip;
1327 int printip = 1;
1328
1329 get_function_bounds(pc, &fnstart, &fnend);
1330 nextip = 0;
1331 if (newsp > sp)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001332 mread(newsp + LRSAVE_OFFSET, &nextip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 sizeof(unsigned long));
1334 if (lr == ip) {
1335 if (lr < PAGE_OFFSET
1336 || (fnstart <= lr && lr < fnend))
1337 printip = 0;
1338 } else if (lr == nextip) {
1339 printip = 0;
1340 } else if (lr >= PAGE_OFFSET
1341 && !(fnstart <= lr && lr < fnend)) {
1342 printf("[link register ] ");
1343 xmon_print_symbol(lr, " ", "\n");
1344 }
1345 if (printip) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001346 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 xmon_print_symbol(ip, " ", " (unreliable)\n");
1348 }
1349 pc = lr = 0;
1350
1351 } else {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001352 printf("["REG"] ", sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 xmon_print_symbol(ip, " ", "\n");
1354 }
1355
1356 /* Look for "regshere" marker to see if this is
1357 an exception frame. */
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001358 if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long))
Benjamin Herrenschmidtec2b36b2008-04-17 14:34:59 +10001359 && marker == STACK_FRAME_REGS_MARKER) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001360 if (mread(sp + REGS_OFFSET, &regs, sizeof(regs))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 != sizeof(regs)) {
1362 printf("Couldn't read registers at %lx\n",
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001363 sp + REGS_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 break;
1365 }
1366 printf("--- Exception: %lx %s at ", regs.trap,
1367 getvecname(TRAP(&regs)));
1368 pc = regs.nip;
1369 lr = regs.link;
1370 xmon_print_symbol(pc, " ", "\n");
1371 }
1372
1373 if (newsp == 0)
1374 break;
1375
1376 sp = newsp;
1377 } while (count++ < xmon_depth_to_print);
1378}
1379
1380static void backtrace(struct pt_regs *excp)
1381{
1382 unsigned long sp;
1383
1384 if (scanhex(&sp))
1385 xmon_show_stack(sp, 0, 0);
1386 else
1387 xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
1388 scannl();
1389}
1390
1391static void print_bug_trap(struct pt_regs *regs)
1392{
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001393#ifdef CONFIG_BUG
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001394 const struct bug_entry *bug;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395 unsigned long addr;
1396
1397 if (regs->msr & MSR_PR)
1398 return; /* not in kernel */
1399 addr = regs->nip; /* address of trap instruction */
1400 if (addr < PAGE_OFFSET)
1401 return;
1402 bug = find_bug(regs->nip);
1403 if (bug == NULL)
1404 return;
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001405 if (is_warning_bug(bug))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 return;
1407
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001408#ifdef CONFIG_DEBUG_BUGVERBOSE
Jeremy Fitzhardinge73c9cea2006-12-08 03:30:41 -08001409 printf("kernel BUG at %s:%u!\n",
1410 bug->file, bug->line);
Stephen Rothwell0a7c7ef2007-03-04 17:05:34 +11001411#else
1412 printf("kernel BUG at %p!\n", (void *)bug->bug_addr);
1413#endif
Paul Mackerrasebdba9a2008-10-31 21:34:09 +11001414#endif /* CONFIG_BUG */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415}
1416
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001417static void excprint(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418{
1419 unsigned long trap;
1420
1421#ifdef CONFIG_SMP
1422 printf("cpu 0x%x: ", smp_processor_id());
1423#endif /* CONFIG_SMP */
1424
1425 trap = TRAP(fp);
1426 printf("Vector: %lx %s at [%lx]\n", fp->trap, getvecname(trap), fp);
1427 printf(" pc: ");
1428 xmon_print_symbol(fp->nip, ": ", "\n");
1429
1430 printf(" lr: ", fp->link);
1431 xmon_print_symbol(fp->link, ": ", "\n");
1432
1433 printf(" sp: %lx\n", fp->gpr[1]);
1434 printf(" msr: %lx\n", fp->msr);
1435
1436 if (trap == 0x300 || trap == 0x380 || trap == 0x600) {
1437 printf(" dar: %lx\n", fp->dar);
1438 if (trap != 0x380)
1439 printf(" dsisr: %lx\n", fp->dsisr);
1440 }
1441
1442 printf(" current = 0x%lx\n", current);
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001443#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444 printf(" paca = 0x%lx\n", get_paca());
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001445#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446 if (current) {
1447 printf(" pid = %ld, comm = %s\n",
1448 current->pid, current->comm);
1449 }
1450
1451 if (trap == 0x700)
1452 print_bug_trap(fp);
1453}
1454
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001455static void prregs(struct pt_regs *fp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456{
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001457 int n, trap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 unsigned long base;
1459 struct pt_regs regs;
1460
1461 if (scanhex(&base)) {
1462 if (setjmp(bus_error_jmp) == 0) {
1463 catch_memory_errors = 1;
1464 sync();
1465 regs = *(struct pt_regs *)base;
1466 sync();
1467 __delay(200);
1468 } else {
1469 catch_memory_errors = 0;
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001470 printf("*** Error reading registers from "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471 base);
1472 return;
1473 }
1474 catch_memory_errors = 0;
1475 fp = &regs;
1476 }
1477
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001478#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 if (FULL_REGS(fp)) {
1480 for (n = 0; n < 16; ++n)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001481 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 n, fp->gpr[n], n+16, fp->gpr[n+16]);
1483 } else {
1484 for (n = 0; n < 7; ++n)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001485 printf("R%.2ld = "REG" R%.2ld = "REG"\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 n, fp->gpr[n], n+7, fp->gpr[n+7]);
1487 }
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001488#else
1489 for (n = 0; n < 32; ++n) {
1490 printf("R%.2d = %.8x%s", n, fp->gpr[n],
1491 (n & 3) == 3? "\n": " ");
1492 if (n == 12 && !FULL_REGS(fp)) {
1493 printf("\n");
1494 break;
1495 }
1496 }
1497#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 printf("pc = ");
1499 xmon_print_symbol(fp->nip, " ", "\n");
Paul Mackerras48404f22011-05-01 19:48:20 +00001500 if (TRAP(fp) != 0xc00 && cpu_has_feature(CPU_FTR_CFAR)) {
1501 printf("cfar= ");
1502 xmon_print_symbol(fp->orig_gpr3, " ", "\n");
1503 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504 printf("lr = ");
1505 xmon_print_symbol(fp->link, " ", "\n");
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001506 printf("msr = "REG" cr = %.8lx\n", fp->msr, fp->ccr);
1507 printf("ctr = "REG" xer = "REG" trap = %4lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 fp->ctr, fp->xer, fp->trap);
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001509 trap = TRAP(fp);
1510 if (trap == 0x300 || trap == 0x380 || trap == 0x600)
1511 printf("dar = "REG" dsisr = %.8lx\n", fp->dar, fp->dsisr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512}
1513
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001514static void cacheflush(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515{
1516 int cmd;
1517 unsigned long nflush;
1518
1519 cmd = inchar();
1520 if (cmd != 'i')
1521 termch = cmd;
1522 scanhex((void *)&adrs);
1523 if (termch != '\n')
1524 termch = 0;
1525 nflush = 1;
1526 scanhex(&nflush);
1527 nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES;
1528 if (setjmp(bus_error_jmp) == 0) {
1529 catch_memory_errors = 1;
1530 sync();
1531
1532 if (cmd != 'i') {
1533 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1534 cflush((void *) adrs);
1535 } else {
1536 for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
1537 cinval((void *) adrs);
1538 }
1539 sync();
1540 /* wait a little while to see if we get a machine check */
1541 __delay(200);
1542 }
1543 catch_memory_errors = 0;
1544}
1545
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001546static unsigned long
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547read_spr(int n)
1548{
1549 unsigned int instrs[2];
1550 unsigned long (*code)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 unsigned long ret = -1UL;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001552#ifdef CONFIG_PPC64
1553 unsigned long opd[3];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 opd[0] = (unsigned long)instrs;
1556 opd[1] = 0;
1557 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001558 code = (unsigned long (*)(void)) opd;
1559#else
1560 code = (unsigned long (*)(void)) instrs;
1561#endif
1562
1563 /* mfspr r3,n; blr */
1564 instrs[0] = 0x7c6002a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1565 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 store_inst(instrs);
1567 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568
1569 if (setjmp(bus_error_jmp) == 0) {
1570 catch_memory_errors = 1;
1571 sync();
1572
1573 ret = code();
1574
1575 sync();
1576 /* wait a little while to see if we get a machine check */
1577 __delay(200);
1578 n = size;
1579 }
1580
1581 return ret;
1582}
1583
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001584static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585write_spr(int n, unsigned long val)
1586{
1587 unsigned int instrs[2];
1588 unsigned long (*code)(unsigned long);
Paul Mackerras548cceb2005-11-11 22:36:34 +11001589#ifdef CONFIG_PPC64
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 unsigned long opd[3];
1591
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592 opd[0] = (unsigned long)instrs;
1593 opd[1] = 0;
1594 opd[2] = 0;
Paul Mackerras548cceb2005-11-11 22:36:34 +11001595 code = (unsigned long (*)(unsigned long)) opd;
1596#else
1597 code = (unsigned long (*)(unsigned long)) instrs;
1598#endif
1599
1600 instrs[0] = 0x7c6003a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
1601 instrs[1] = 0x4e800020;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 store_inst(instrs);
1603 store_inst(instrs+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604
1605 if (setjmp(bus_error_jmp) == 0) {
1606 catch_memory_errors = 1;
1607 sync();
1608
1609 code(val);
1610
1611 sync();
1612 /* wait a little while to see if we get a machine check */
1613 __delay(200);
1614 n = size;
1615 }
1616}
1617
1618static unsigned long regno;
1619extern char exc_prolog;
1620extern char dec_exc;
1621
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001622static void super_regs(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623{
1624 int cmd;
1625 unsigned long val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626
1627 cmd = skipbl();
1628 if (cmd == '\n') {
1629 unsigned long sp, toc;
1630 asm("mr %0,1" : "=r" (sp) :);
1631 asm("mr %0,2" : "=r" (toc) :);
1632
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001633 printf("msr = "REG" sprg0= "REG"\n",
1634 mfmsr(), mfspr(SPRN_SPRG0));
1635 printf("pvr = "REG" sprg1= "REG"\n",
1636 mfspr(SPRN_PVR), mfspr(SPRN_SPRG1));
1637 printf("dec = "REG" sprg2= "REG"\n",
1638 mfspr(SPRN_DEC), mfspr(SPRN_SPRG2));
1639 printf("sp = "REG" sprg3= "REG"\n", sp, mfspr(SPRN_SPRG3));
1640 printf("toc = "REG" dar = "REG"\n", toc, mfspr(SPRN_DAR));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641#ifdef CONFIG_PPC_ISERIES
Stephen Rothwell1d135812006-11-13 14:50:28 +11001642 if (firmware_has_feature(FW_FEATURE_ISERIES)) {
1643 struct paca_struct *ptrPaca;
1644 struct lppaca *ptrLpPaca;
Stephen Rothwell1d135812006-11-13 14:50:28 +11001645
1646 /* Dump out relevant Paca data areas. */
1647 printf("Paca: \n");
1648 ptrPaca = get_paca();
1649
1650 printf(" Local Processor Control Area (LpPaca): \n");
1651 ptrLpPaca = ptrPaca->lppaca_ptr;
1652 printf(" Saved Srr0=%.16lx Saved Srr1=%.16lx \n",
1653 ptrLpPaca->saved_srr0, ptrLpPaca->saved_srr1);
1654 printf(" Saved Gpr3=%.16lx Saved Gpr4=%.16lx \n",
1655 ptrLpPaca->saved_gpr3, ptrLpPaca->saved_gpr4);
Gautham R Shenoy69ddb572009-10-29 19:22:48 +00001656 printf(" Saved Gpr5=%.16lx \n",
1657 ptrLpPaca->gpr5_dword.saved_gpr5);
Stephen Rothwell1d135812006-11-13 14:50:28 +11001658 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659#endif
1660
1661 return;
1662 }
1663
1664 scanhex(&regno);
1665 switch (cmd) {
1666 case 'w':
1667 val = read_spr(regno);
1668 scanhex(&val);
1669 write_spr(regno, val);
1670 /* fall through */
1671 case 'r':
1672 printf("spr %lx = %lx\n", regno, read_spr(regno));
1673 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674 }
1675 scannl();
1676}
1677
1678/*
1679 * Stuff for reading and writing memory safely
1680 */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001681static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682mread(unsigned long adrs, void *buf, int size)
1683{
1684 volatile int n;
1685 char *p, *q;
1686
1687 n = 0;
1688 if (setjmp(bus_error_jmp) == 0) {
1689 catch_memory_errors = 1;
1690 sync();
1691 p = (char *)adrs;
1692 q = (char *)buf;
1693 switch (size) {
1694 case 2:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001695 *(u16 *)q = *(u16 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 break;
1697 case 4:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001698 *(u32 *)q = *(u32 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 break;
1700 case 8:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001701 *(u64 *)q = *(u64 *)p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 break;
1703 default:
1704 for( ; n < size; ++n) {
1705 *q++ = *p++;
1706 sync();
1707 }
1708 }
1709 sync();
1710 /* wait a little while to see if we get a machine check */
1711 __delay(200);
1712 n = size;
1713 }
1714 catch_memory_errors = 0;
1715 return n;
1716}
1717
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001718static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719mwrite(unsigned long adrs, void *buf, int size)
1720{
1721 volatile int n;
1722 char *p, *q;
1723
1724 n = 0;
1725 if (setjmp(bus_error_jmp) == 0) {
1726 catch_memory_errors = 1;
1727 sync();
1728 p = (char *) adrs;
1729 q = (char *) buf;
1730 switch (size) {
1731 case 2:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001732 *(u16 *)p = *(u16 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 break;
1734 case 4:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001735 *(u32 *)p = *(u32 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 break;
1737 case 8:
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001738 *(u64 *)p = *(u64 *)q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739 break;
1740 default:
1741 for ( ; n < size; ++n) {
1742 *p++ = *q++;
1743 sync();
1744 }
1745 }
1746 sync();
1747 /* wait a little while to see if we get a machine check */
1748 __delay(200);
1749 n = size;
1750 } else {
1751 printf("*** Error writing address %x\n", adrs + n);
1752 }
1753 catch_memory_errors = 0;
1754 return n;
1755}
1756
1757static int fault_type;
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001758static int fault_except;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759static char *fault_chars[] = { "--", "**", "##" };
1760
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001761static int handle_fault(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762{
Paul Mackerrasf78541d2005-10-28 22:53:37 +10001763 fault_except = TRAP(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764 switch (TRAP(regs)) {
1765 case 0x200:
1766 fault_type = 0;
1767 break;
1768 case 0x300:
1769 case 0x380:
1770 fault_type = 1;
1771 break;
1772 default:
1773 fault_type = 2;
1774 }
1775
1776 longjmp(bus_error_jmp, 1);
1777
1778 return 0;
1779}
1780
1781#define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t))
1782
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001783static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784byterev(unsigned char *val, int size)
1785{
1786 int t;
1787
1788 switch (size) {
1789 case 2:
1790 SWAP(val[0], val[1], t);
1791 break;
1792 case 4:
1793 SWAP(val[0], val[3], t);
1794 SWAP(val[1], val[2], t);
1795 break;
1796 case 8: /* is there really any use for this? */
1797 SWAP(val[0], val[7], t);
1798 SWAP(val[1], val[6], t);
1799 SWAP(val[2], val[5], t);
1800 SWAP(val[3], val[4], t);
1801 break;
1802 }
1803}
1804
1805static int brev;
1806static int mnoread;
1807
1808static char *memex_help_string =
1809 "Memory examine command usage:\n"
1810 "m [addr] [flags] examine/change memory\n"
1811 " addr is optional. will start where left off.\n"
1812 " flags may include chars from this set:\n"
1813 " b modify by bytes (default)\n"
1814 " w modify by words (2 byte)\n"
1815 " l modify by longs (4 byte)\n"
1816 " d modify by doubleword (8 byte)\n"
1817 " r toggle reverse byte order mode\n"
1818 " n do not read memory (for i/o spaces)\n"
1819 " . ok to read (default)\n"
1820 "NOTE: flags are saved as defaults\n"
1821 "";
1822
1823static char *memex_subcmd_help_string =
1824 "Memory examine subcommands:\n"
1825 " hexval write this val to current location\n"
1826 " 'string' write chars from string to this location\n"
1827 " ' increment address\n"
1828 " ^ decrement address\n"
1829 " / increment addr by 0x10. //=0x100, ///=0x1000, etc\n"
1830 " \\ decrement addr by 0x10. \\\\=0x100, \\\\\\=0x1000, etc\n"
1831 " ` clear no-read flag\n"
1832 " ; stay at this addr\n"
1833 " v change to byte mode\n"
1834 " w change to word (2 byte) mode\n"
1835 " l change to long (4 byte) mode\n"
1836 " u change to doubleword (8 byte) mode\n"
1837 " m addr change current addr\n"
1838 " n toggle no-read flag\n"
1839 " r toggle byte reverse flag\n"
1840 " < count back up count bytes\n"
1841 " > count skip forward count bytes\n"
1842 " x exit this mode\n"
1843 "";
1844
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001845static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846memex(void)
1847{
1848 int cmd, inc, i, nslash;
1849 unsigned long n;
1850 unsigned char val[16];
1851
1852 scanhex((void *)&adrs);
1853 cmd = skipbl();
1854 if (cmd == '?') {
1855 printf(memex_help_string);
1856 return;
1857 } else {
1858 termch = cmd;
1859 }
1860 last_cmd = "m\n";
1861 while ((cmd = skipbl()) != '\n') {
1862 switch( cmd ){
1863 case 'b': size = 1; break;
1864 case 'w': size = 2; break;
1865 case 'l': size = 4; break;
1866 case 'd': size = 8; break;
1867 case 'r': brev = !brev; break;
1868 case 'n': mnoread = 1; break;
1869 case '.': mnoread = 0; break;
1870 }
1871 }
1872 if( size <= 0 )
1873 size = 1;
1874 else if( size > 8 )
1875 size = 8;
1876 for(;;){
1877 if (!mnoread)
1878 n = mread(adrs, val, size);
Paul Mackerrase1449ed2005-11-10 14:30:20 +11001879 printf(REG"%c", adrs, brev? 'r': ' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880 if (!mnoread) {
1881 if (brev)
1882 byterev(val, size);
1883 putchar(' ');
1884 for (i = 0; i < n; ++i)
1885 printf("%.2x", val[i]);
1886 for (; i < size; ++i)
1887 printf("%s", fault_chars[fault_type]);
1888 }
1889 putchar(' ');
1890 inc = size;
1891 nslash = 0;
1892 for(;;){
1893 if( scanhex(&n) ){
1894 for (i = 0; i < size; ++i)
1895 val[i] = n >> (i * 8);
1896 if (!brev)
1897 byterev(val, size);
1898 mwrite(adrs, val, size);
1899 inc = size;
1900 }
1901 cmd = skipbl();
1902 if (cmd == '\n')
1903 break;
1904 inc = 0;
1905 switch (cmd) {
1906 case '\'':
1907 for(;;){
1908 n = inchar();
1909 if( n == '\\' )
1910 n = bsesc();
1911 else if( n == '\'' )
1912 break;
1913 for (i = 0; i < size; ++i)
1914 val[i] = n >> (i * 8);
1915 if (!brev)
1916 byterev(val, size);
1917 mwrite(adrs, val, size);
1918 adrs += size;
1919 }
1920 adrs -= size;
1921 inc = size;
1922 break;
1923 case ',':
1924 adrs += size;
1925 break;
1926 case '.':
1927 mnoread = 0;
1928 break;
1929 case ';':
1930 break;
1931 case 'x':
1932 case EOF:
1933 scannl();
1934 return;
1935 case 'b':
1936 case 'v':
1937 size = 1;
1938 break;
1939 case 'w':
1940 size = 2;
1941 break;
1942 case 'l':
1943 size = 4;
1944 break;
1945 case 'u':
1946 size = 8;
1947 break;
1948 case '^':
1949 adrs -= size;
1950 break;
1951 break;
1952 case '/':
1953 if (nslash > 0)
1954 adrs -= 1 << nslash;
1955 else
1956 nslash = 0;
1957 nslash += 4;
1958 adrs += 1 << nslash;
1959 break;
1960 case '\\':
1961 if (nslash < 0)
1962 adrs += 1 << -nslash;
1963 else
1964 nslash = 0;
1965 nslash -= 4;
1966 adrs -= 1 << -nslash;
1967 break;
1968 case 'm':
1969 scanhex((void *)&adrs);
1970 break;
1971 case 'n':
1972 mnoread = 1;
1973 break;
1974 case 'r':
1975 brev = !brev;
1976 break;
1977 case '<':
1978 n = size;
1979 scanhex(&n);
1980 adrs -= n;
1981 break;
1982 case '>':
1983 n = size;
1984 scanhex(&n);
1985 adrs += n;
1986 break;
1987 case '?':
1988 printf(memex_subcmd_help_string);
1989 break;
1990 }
1991 }
1992 adrs += inc;
1993 }
1994}
1995
Michael Ellerman9f1067c22008-05-08 14:27:16 +10001996static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997bsesc(void)
1998{
1999 int c;
2000
2001 c = inchar();
2002 switch( c ){
2003 case 'n': c = '\n'; break;
2004 case 'r': c = '\r'; break;
2005 case 'b': c = '\b'; break;
2006 case 't': c = '\t'; break;
2007 }
2008 return c;
2009}
2010
Olaf Hering7e5b5932006-03-08 20:40:28 +01002011static void xmon_rawdump (unsigned long adrs, long ndump)
2012{
2013 long n, m, r, nr;
2014 unsigned char temp[16];
2015
2016 for (n = ndump; n > 0;) {
2017 r = n < 16? n: 16;
2018 nr = mread(adrs, temp, r);
2019 adrs += nr;
2020 for (m = 0; m < r; ++m) {
2021 if (m < nr)
2022 printf("%.2x", temp[m]);
2023 else
2024 printf("%s", fault_chars[fault_type]);
2025 }
2026 n -= r;
2027 if (nr < r)
2028 break;
2029 }
2030 printf("\n");
2031}
2032
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
2034 || ('a' <= (c) && (c) <= 'f') \
2035 || ('A' <= (c) && (c) <= 'F'))
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002036static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037dump(void)
2038{
2039 int c;
2040
2041 c = inchar();
2042 if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
2043 termch = c;
2044 scanhex((void *)&adrs);
2045 if (termch != '\n')
2046 termch = 0;
2047 if (c == 'i') {
2048 scanhex(&nidump);
2049 if (nidump == 0)
2050 nidump = 16;
2051 else if (nidump > MAX_DUMP)
2052 nidump = MAX_DUMP;
2053 adrs += ppc_inst_dump(adrs, nidump, 1);
2054 last_cmd = "di\n";
Vinay Sridharf312deb2009-05-14 23:13:07 +00002055 } else if (c == 'l') {
2056 dump_log_buf();
Olaf Hering7e5b5932006-03-08 20:40:28 +01002057 } else if (c == 'r') {
2058 scanhex(&ndump);
2059 if (ndump == 0)
2060 ndump = 64;
2061 xmon_rawdump(adrs, ndump);
2062 adrs += ndump;
2063 last_cmd = "dr\n";
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064 } else {
2065 scanhex(&ndump);
2066 if (ndump == 0)
2067 ndump = 64;
2068 else if (ndump > MAX_DUMP)
2069 ndump = MAX_DUMP;
2070 prdump(adrs, ndump);
2071 adrs += ndump;
2072 last_cmd = "d\n";
2073 }
2074}
2075
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002076static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077prdump(unsigned long adrs, long ndump)
2078{
2079 long n, m, c, r, nr;
2080 unsigned char temp[16];
2081
2082 for (n = ndump; n > 0;) {
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002083 printf(REG, adrs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084 putchar(' ');
2085 r = n < 16? n: 16;
2086 nr = mread(adrs, temp, r);
2087 adrs += nr;
2088 for (m = 0; m < r; ++m) {
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002089 if ((m & (sizeof(long) - 1)) == 0 && m > 0)
2090 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091 if (m < nr)
2092 printf("%.2x", temp[m]);
2093 else
2094 printf("%s", fault_chars[fault_type]);
2095 }
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002096 for (; m < 16; ++m) {
2097 if ((m & (sizeof(long) - 1)) == 0)
2098 putchar(' ');
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099 printf(" ");
Paul Mackerrase1449ed2005-11-10 14:30:20 +11002100 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101 printf(" |");
2102 for (m = 0; m < r; ++m) {
2103 if (m < nr) {
2104 c = temp[m];
2105 putchar(' ' <= c && c <= '~'? c: '.');
2106 } else
2107 putchar(' ');
2108 }
2109 n -= r;
2110 for (; m < 16; ++m)
2111 putchar(' ');
2112 printf("|\n");
2113 if (nr < r)
2114 break;
2115 }
2116}
2117
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002118typedef int (*instruction_dump_func)(unsigned long inst, unsigned long addr);
2119
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002120static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002121generic_inst_dump(unsigned long adr, long count, int praddr,
2122 instruction_dump_func dump_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002123{
2124 int nr, dotted;
2125 unsigned long first_adr;
2126 unsigned long inst, last_inst = 0;
2127 unsigned char val[4];
2128
2129 dotted = 0;
2130 for (first_adr = adr; count > 0; --count, adr += 4) {
2131 nr = mread(adr, val, 4);
2132 if (nr == 0) {
2133 if (praddr) {
2134 const char *x = fault_chars[fault_type];
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002135 printf(REG" %s%s%s%s\n", adr, x, x, x, x);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002136 }
2137 break;
2138 }
2139 inst = GETWORD(val);
2140 if (adr > first_adr && inst == last_inst) {
2141 if (!dotted) {
2142 printf(" ...\n");
2143 dotted = 1;
2144 }
2145 continue;
2146 }
2147 dotted = 0;
2148 last_inst = inst;
2149 if (praddr)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002150 printf(REG" %.8x", adr, inst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002151 printf("\t");
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002152 dump_func(inst, adr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153 printf("\n");
2154 }
2155 return adr - first_adr;
2156}
2157
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002158static int
Michael Ellerman4c4c8722006-11-23 00:46:42 +01002159ppc_inst_dump(unsigned long adr, long count, int praddr)
2160{
2161 return generic_inst_dump(adr, count, praddr, print_insn_powerpc);
2162}
2163
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164void
2165print_address(unsigned long addr)
2166{
2167 xmon_print_symbol(addr, "\t# ", "");
2168}
2169
Vinay Sridharf312deb2009-05-14 23:13:07 +00002170void
2171dump_log_buf(void)
2172{
2173 const unsigned long size = 128;
Stephen Rothwell6d1386d2009-06-02 18:15:33 +00002174 unsigned long end, addr;
Vinay Sridharf312deb2009-05-14 23:13:07 +00002175 unsigned char buf[size + 1];
2176
2177 addr = 0;
2178 buf[size] = '\0';
2179
2180 if (setjmp(bus_error_jmp) != 0) {
2181 printf("Unable to lookup symbol __log_buf!\n");
2182 return;
2183 }
2184
2185 catch_memory_errors = 1;
2186 sync();
2187 addr = kallsyms_lookup_name("__log_buf");
2188
2189 if (! addr)
2190 printf("Symbol __log_buf not found!\n");
2191 else {
2192 end = addr + (1 << CONFIG_LOG_BUF_SHIFT);
2193 while (addr < end) {
2194 if (! mread(addr, buf, size)) {
2195 printf("Can't read memory at address 0x%lx\n", addr);
2196 break;
2197 }
2198
2199 printf("%s", buf);
2200
2201 if (strlen(buf) < size)
2202 break;
2203
2204 addr += size;
2205 }
2206 }
2207
2208 sync();
2209 /* wait a little while to see if we get a machine check */
2210 __delay(200);
2211 catch_memory_errors = 0;
2212}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002213
2214/*
2215 * Memory operations - move, set, print differences
2216 */
2217static unsigned long mdest; /* destination address */
2218static unsigned long msrc; /* source address */
2219static unsigned long mval; /* byte value to set memory to */
2220static unsigned long mcount; /* # bytes to affect */
2221static unsigned long mdiffs; /* max # differences to print */
2222
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002223static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002224memops(int cmd)
2225{
2226 scanhex((void *)&mdest);
2227 if( termch != '\n' )
2228 termch = 0;
2229 scanhex((void *)(cmd == 's'? &mval: &msrc));
2230 if( termch != '\n' )
2231 termch = 0;
2232 scanhex((void *)&mcount);
2233 switch( cmd ){
2234 case 'm':
2235 memmove((void *)mdest, (void *)msrc, mcount);
2236 break;
2237 case 's':
2238 memset((void *)mdest, mval, mcount);
2239 break;
2240 case 'd':
2241 if( termch != '\n' )
2242 termch = 0;
2243 scanhex((void *)&mdiffs);
2244 memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
2245 break;
2246 }
2247}
2248
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002249static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
2251{
2252 unsigned n, prt;
2253
2254 prt = 0;
2255 for( n = nb; n > 0; --n )
2256 if( *p1++ != *p2++ )
2257 if( ++prt <= maxpr )
2258 printf("%.16x %.2x # %.16x %.2x\n", p1 - 1,
2259 p1[-1], p2 - 1, p2[-1]);
2260 if( prt > maxpr )
2261 printf("Total of %d differences\n", prt);
2262}
2263
2264static unsigned mend;
2265static unsigned mask;
2266
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002267static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268memlocate(void)
2269{
2270 unsigned a, n;
2271 unsigned char val[4];
2272
2273 last_cmd = "ml";
2274 scanhex((void *)&mdest);
2275 if (termch != '\n') {
2276 termch = 0;
2277 scanhex((void *)&mend);
2278 if (termch != '\n') {
2279 termch = 0;
2280 scanhex((void *)&mval);
2281 mask = ~0;
2282 if (termch != '\n') termch = 0;
2283 scanhex((void *)&mask);
2284 }
2285 }
2286 n = 0;
2287 for (a = mdest; a < mend; a += 4) {
2288 if (mread(a, val, 4) == 4
2289 && ((GETWORD(val) ^ mval) & mask) == 0) {
2290 printf("%.16x: %.16x\n", a, GETWORD(val));
2291 if (++n >= 10)
2292 break;
2293 }
2294 }
2295}
2296
2297static unsigned long mskip = 0x1000;
2298static unsigned long mlim = 0xffffffff;
2299
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002300static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301memzcan(void)
2302{
2303 unsigned char v;
2304 unsigned a;
2305 int ok, ook;
2306
2307 scanhex(&mdest);
2308 if (termch != '\n') termch = 0;
2309 scanhex(&mskip);
2310 if (termch != '\n') termch = 0;
2311 scanhex(&mlim);
2312 ook = 0;
2313 for (a = mdest; a < mlim; a += mskip) {
2314 ok = mread(a, &v, 1);
2315 if (ok && !ook) {
2316 printf("%.8x .. ", a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317 } else if (!ok && ook)
2318 printf("%.8x\n", a - mskip);
2319 ook = ok;
2320 if (a + mskip < a)
2321 break;
2322 }
2323 if (ook)
2324 printf("%.8x\n", a - mskip);
2325}
2326
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002327static void proccall(void)
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002328{
2329 unsigned long args[8];
2330 unsigned long ret;
2331 int i;
2332 typedef unsigned long (*callfunc_t)(unsigned long, unsigned long,
2333 unsigned long, unsigned long, unsigned long,
2334 unsigned long, unsigned long, unsigned long);
2335 callfunc_t func;
2336
2337 if (!scanhex(&adrs))
2338 return;
2339 if (termch != '\n')
2340 termch = 0;
2341 for (i = 0; i < 8; ++i)
2342 args[i] = 0;
2343 for (i = 0; i < 8; ++i) {
2344 if (!scanhex(&args[i]) || termch == '\n')
2345 break;
2346 termch = 0;
2347 }
2348 func = (callfunc_t) adrs;
2349 ret = 0;
2350 if (setjmp(bus_error_jmp) == 0) {
2351 catch_memory_errors = 1;
2352 sync();
2353 ret = func(args[0], args[1], args[2], args[3],
2354 args[4], args[5], args[6], args[7]);
2355 sync();
2356 printf("return value is %x\n", ret);
2357 } else {
2358 printf("*** %x exception occurred\n", fault_except);
2359 }
2360 catch_memory_errors = 0;
2361}
2362
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363/* Input scanning routines */
2364int
2365skipbl(void)
2366{
2367 int c;
2368
2369 if( termch != 0 ){
2370 c = termch;
2371 termch = 0;
2372 } else
2373 c = inchar();
2374 while( c == ' ' || c == '\t' )
2375 c = inchar();
2376 return c;
2377}
2378
2379#define N_PTREGS 44
2380static char *regnames[N_PTREGS] = {
2381 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
2382 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
2383 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
2384 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002385 "pc", "msr", "or3", "ctr", "lr", "xer", "ccr",
2386#ifdef CONFIG_PPC64
2387 "softe",
2388#else
2389 "mq",
2390#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391 "trap", "dar", "dsisr", "res"
2392};
2393
2394int
2395scanhex(unsigned long *vp)
2396{
2397 int c, d;
2398 unsigned long v;
2399
2400 c = skipbl();
2401 if (c == '%') {
2402 /* parse register name */
2403 char regname[8];
2404 int i;
2405
2406 for (i = 0; i < sizeof(regname) - 1; ++i) {
2407 c = inchar();
2408 if (!isalnum(c)) {
2409 termch = c;
2410 break;
2411 }
2412 regname[i] = c;
2413 }
2414 regname[i] = 0;
2415 for (i = 0; i < N_PTREGS; ++i) {
2416 if (strcmp(regnames[i], regname) == 0) {
2417 if (xmon_regs == NULL) {
2418 printf("regs not available\n");
2419 return 0;
2420 }
2421 *vp = ((unsigned long *)xmon_regs)[i];
2422 return 1;
2423 }
2424 }
2425 printf("invalid register name '%%%s'\n", regname);
2426 return 0;
2427 }
2428
2429 /* skip leading "0x" if any */
2430
2431 if (c == '0') {
2432 c = inchar();
2433 if (c == 'x') {
2434 c = inchar();
2435 } else {
2436 d = hexdigit(c);
2437 if (d == EOF) {
2438 termch = c;
2439 *vp = 0;
2440 return 1;
2441 }
2442 }
2443 } else if (c == '$') {
2444 int i;
2445 for (i=0; i<63; i++) {
2446 c = inchar();
2447 if (isspace(c)) {
2448 termch = c;
2449 break;
2450 }
2451 tmpstr[i] = c;
2452 }
2453 tmpstr[i++] = 0;
Benjamin Herrenschmidt6879dc12005-06-21 17:15:30 -07002454 *vp = 0;
2455 if (setjmp(bus_error_jmp) == 0) {
2456 catch_memory_errors = 1;
2457 sync();
2458 *vp = kallsyms_lookup_name(tmpstr);
2459 sync();
2460 }
2461 catch_memory_errors = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462 if (!(*vp)) {
2463 printf("unknown symbol '%s'\n", tmpstr);
2464 return 0;
2465 }
2466 return 1;
2467 }
2468
2469 d = hexdigit(c);
2470 if (d == EOF) {
2471 termch = c;
2472 return 0;
2473 }
2474 v = 0;
2475 do {
2476 v = (v << 4) + d;
2477 c = inchar();
2478 d = hexdigit(c);
2479 } while (d != EOF);
2480 termch = c;
2481 *vp = v;
2482 return 1;
2483}
2484
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002485static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486scannl(void)
2487{
2488 int c;
2489
2490 c = termch;
2491 termch = 0;
2492 while( c != '\n' )
2493 c = inchar();
2494}
2495
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002496static int hexdigit(int c)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497{
2498 if( '0' <= c && c <= '9' )
2499 return c - '0';
2500 if( 'A' <= c && c <= 'F' )
2501 return c - ('A' - 10);
2502 if( 'a' <= c && c <= 'f' )
2503 return c - ('a' - 10);
2504 return EOF;
2505}
2506
2507void
2508getstring(char *s, int size)
2509{
2510 int c;
2511
2512 c = skipbl();
2513 do {
2514 if( size > 1 ){
2515 *s++ = c;
2516 --size;
2517 }
2518 c = inchar();
2519 } while( c != ' ' && c != '\t' && c != '\n' );
2520 termch = c;
2521 *s = 0;
2522}
2523
2524static char line[256];
2525static char *lineptr;
2526
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002527static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528flush_input(void)
2529{
2530 lineptr = NULL;
2531}
2532
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002533static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534inchar(void)
2535{
2536 if (lineptr == NULL || *lineptr == 0) {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002537 if (xmon_gets(line, sizeof(line)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538 lineptr = NULL;
2539 return EOF;
2540 }
2541 lineptr = line;
2542 }
2543 return *lineptr++;
2544}
2545
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002546static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547take_input(char *str)
2548{
2549 lineptr = str;
2550}
2551
2552
2553static void
2554symbol_lookup(void)
2555{
2556 int type = inchar();
2557 unsigned long addr;
2558 static char tmp[64];
2559
2560 switch (type) {
2561 case 'a':
2562 if (scanhex(&addr))
2563 xmon_print_symbol(addr, ": ", "\n");
2564 termch = 0;
2565 break;
2566 case 's':
2567 getstring(tmp, 64);
2568 if (setjmp(bus_error_jmp) == 0) {
2569 catch_memory_errors = 1;
2570 sync();
2571 addr = kallsyms_lookup_name(tmp);
2572 if (addr)
2573 printf("%s: %lx\n", tmp, addr);
2574 else
2575 printf("Symbol '%s' not found.\n", tmp);
2576 sync();
2577 }
2578 catch_memory_errors = 0;
2579 termch = 0;
2580 break;
2581 }
2582}
2583
2584
2585/* Print an address in numeric and symbolic form (if possible) */
2586static void xmon_print_symbol(unsigned long address, const char *mid,
2587 const char *after)
2588{
2589 char *modname;
2590 const char *name = NULL;
2591 unsigned long offset, size;
2592
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002593 printf(REG, address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002594 if (setjmp(bus_error_jmp) == 0) {
2595 catch_memory_errors = 1;
2596 sync();
2597 name = kallsyms_lookup(address, &size, &offset, &modname,
2598 tmpstr);
2599 sync();
2600 /* wait a little while to see if we get a machine check */
2601 __delay(200);
2602 }
2603
2604 catch_memory_errors = 0;
2605
2606 if (name) {
2607 printf("%s%s+%#lx/%#lx", mid, name, offset, size);
2608 if (modname)
2609 printf(" [%s]", modname);
2610 }
2611 printf("%s", after);
2612}
2613
Benjamin Herrenschmidt2d27cfd2009-07-23 23:15:59 +00002614#ifdef CONFIG_PPC_BOOK3S_64
Linus Torvalds1da177e2005-04-16 15:20:36 -07002615static void dump_slb(void)
2616{
2617 int i;
will schmidtb3b95952007-12-07 08:22:23 +11002618 unsigned long esid,vsid,valid;
2619 unsigned long llp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620
2621 printf("SLB contents of cpu %x\n", smp_processor_id());
2622
Michael Neuling584f8b72007-12-06 17:24:48 +11002623 for (i = 0; i < mmu_slb_size; i++) {
will schmidtb3b95952007-12-07 08:22:23 +11002624 asm volatile("slbmfee %0,%1" : "=r" (esid) : "r" (i));
2625 asm volatile("slbmfev %0,%1" : "=r" (vsid) : "r" (i));
2626 valid = (esid & SLB_ESID_V);
2627 if (valid | esid | vsid) {
2628 printf("%02d %016lx %016lx", i, esid, vsid);
2629 if (valid) {
2630 llp = vsid & SLB_VSID_LLP;
2631 if (vsid & SLB_VSID_B_1T) {
2632 printf(" 1T ESID=%9lx VSID=%13lx LLP:%3lx \n",
2633 GET_ESID_1T(esid),
2634 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT_1T,
2635 llp);
2636 } else {
2637 printf(" 256M ESID=%9lx VSID=%13lx LLP:%3lx \n",
2638 GET_ESID(esid),
2639 (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT,
2640 llp);
2641 }
2642 } else
2643 printf("\n");
2644 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645 }
2646}
2647
2648static void dump_stab(void)
2649{
2650 int i;
2651 unsigned long *tmp = (unsigned long *)get_paca()->stab_addr;
2652
2653 printf("Segment table contents of cpu %x\n", smp_processor_id());
2654
2655 for (i = 0; i < PAGE_SIZE/16; i++) {
2656 unsigned long a, b;
2657
2658 a = *tmp++;
2659 b = *tmp++;
2660
2661 if (a || b) {
2662 printf("%03d %016lx ", i, a);
2663 printf("%016lx\n", b);
2664 }
2665 }
2666}
2667
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002668void dump_segments(void)
2669{
Matt Evans44ae3ab2011-04-06 19:48:50 +00002670 if (mmu_has_feature(MMU_FTR_SLB))
Paul Mackerrasf78541d2005-10-28 22:53:37 +10002671 dump_slb();
2672 else
2673 dump_stab();
2674}
2675#endif
2676
2677#ifdef CONFIG_PPC_STD_MMU_32
2678void dump_segments(void)
2679{
2680 int i;
2681
2682 printf("sr0-15 =");
2683 for (i = 0; i < 16; ++i)
2684 printf(" %x", mfsrin(i));
2685 printf("\n");
2686}
2687#endif
2688
Benjamin Herrenschmidt5a8a1a22007-11-16 18:23:33 +11002689#ifdef CONFIG_44x
2690static void dump_tlb_44x(void)
2691{
2692 int i;
2693
2694 for (i = 0; i < PPC44x_TLB_SIZE; i++) {
2695 unsigned long w0,w1,w2;
2696 asm volatile("tlbre %0,%1,0" : "=r" (w0) : "r" (i));
2697 asm volatile("tlbre %0,%1,1" : "=r" (w1) : "r" (i));
2698 asm volatile("tlbre %0,%1,2" : "=r" (w2) : "r" (i));
2699 printf("[%02x] %08x %08x %08x ", i, w0, w1, w2);
2700 if (w0 & PPC44x_TLB_VALID) {
2701 printf("V %08x -> %01x%08x %c%c%c%c%c",
2702 w0 & PPC44x_TLB_EPN_MASK,
2703 w1 & PPC44x_TLB_ERPN_MASK,
2704 w1 & PPC44x_TLB_RPN_MASK,
2705 (w2 & PPC44x_TLB_W) ? 'W' : 'w',
2706 (w2 & PPC44x_TLB_I) ? 'I' : 'i',
2707 (w2 & PPC44x_TLB_M) ? 'M' : 'm',
2708 (w2 & PPC44x_TLB_G) ? 'G' : 'g',
2709 (w2 & PPC44x_TLB_E) ? 'E' : 'e');
2710 }
2711 printf("\n");
2712 }
2713}
2714#endif /* CONFIG_44x */
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002715
Benjamin Herrenschmidt03247152010-07-09 15:34:50 +10002716#ifdef CONFIG_PPC_BOOK3E
2717static void dump_tlb_book3e(void)
2718{
2719 u32 mmucfg, pidmask, lpidmask;
2720 u64 ramask;
2721 int i, tlb, ntlbs, pidsz, lpidsz, rasz, lrat = 0;
2722 int mmu_version;
2723 static const char *pgsz_names[] = {
2724 " 1K",
2725 " 2K",
2726 " 4K",
2727 " 8K",
2728 " 16K",
2729 " 32K",
2730 " 64K",
2731 "128K",
2732 "256K",
2733 "512K",
2734 " 1M",
2735 " 2M",
2736 " 4M",
2737 " 8M",
2738 " 16M",
2739 " 32M",
2740 " 64M",
2741 "128M",
2742 "256M",
2743 "512M",
2744 " 1G",
2745 " 2G",
2746 " 4G",
2747 " 8G",
2748 " 16G",
2749 " 32G",
2750 " 64G",
2751 "128G",
2752 "256G",
2753 "512G",
2754 " 1T",
2755 " 2T",
2756 };
2757
2758 /* Gather some infos about the MMU */
2759 mmucfg = mfspr(SPRN_MMUCFG);
2760 mmu_version = (mmucfg & 3) + 1;
2761 ntlbs = ((mmucfg >> 2) & 3) + 1;
2762 pidsz = ((mmucfg >> 6) & 0x1f) + 1;
2763 lpidsz = (mmucfg >> 24) & 0xf;
2764 rasz = (mmucfg >> 16) & 0x7f;
2765 if ((mmu_version > 1) && (mmucfg & 0x10000))
2766 lrat = 1;
2767 printf("Book3E MMU MAV=%d.0,%d TLBs,%d-bit PID,%d-bit LPID,%d-bit RA\n",
2768 mmu_version, ntlbs, pidsz, lpidsz, rasz);
2769 pidmask = (1ul << pidsz) - 1;
2770 lpidmask = (1ul << lpidsz) - 1;
2771 ramask = (1ull << rasz) - 1;
2772
2773 for (tlb = 0; tlb < ntlbs; tlb++) {
2774 u32 tlbcfg;
2775 int nent, assoc, new_cc = 1;
2776 printf("TLB %d:\n------\n", tlb);
2777 switch(tlb) {
2778 case 0:
2779 tlbcfg = mfspr(SPRN_TLB0CFG);
2780 break;
2781 case 1:
2782 tlbcfg = mfspr(SPRN_TLB1CFG);
2783 break;
2784 case 2:
2785 tlbcfg = mfspr(SPRN_TLB2CFG);
2786 break;
2787 case 3:
2788 tlbcfg = mfspr(SPRN_TLB3CFG);
2789 break;
2790 default:
2791 printf("Unsupported TLB number !\n");
2792 continue;
2793 }
2794 nent = tlbcfg & 0xfff;
2795 assoc = (tlbcfg >> 24) & 0xff;
2796 for (i = 0; i < nent; i++) {
2797 u32 mas0 = MAS0_TLBSEL(tlb);
2798 u32 mas1 = MAS1_TSIZE(BOOK3E_PAGESZ_4K);
2799 u64 mas2 = 0;
2800 u64 mas7_mas3;
2801 int esel = i, cc = i;
2802
2803 if (assoc != 0) {
2804 cc = i / assoc;
2805 esel = i % assoc;
2806 mas2 = cc * 0x1000;
2807 }
2808
2809 mas0 |= MAS0_ESEL(esel);
2810 mtspr(SPRN_MAS0, mas0);
2811 mtspr(SPRN_MAS1, mas1);
2812 mtspr(SPRN_MAS2, mas2);
2813 asm volatile("tlbre 0,0,0" : : : "memory");
2814 mas1 = mfspr(SPRN_MAS1);
2815 mas2 = mfspr(SPRN_MAS2);
2816 mas7_mas3 = mfspr(SPRN_MAS7_MAS3);
2817 if (assoc && (i % assoc) == 0)
2818 new_cc = 1;
2819 if (!(mas1 & MAS1_VALID))
2820 continue;
2821 if (assoc == 0)
2822 printf("%04x- ", i);
2823 else if (new_cc)
2824 printf("%04x-%c", cc, 'A' + esel);
2825 else
2826 printf(" |%c", 'A' + esel);
2827 new_cc = 0;
2828 printf(" %016llx %04x %s %c%c AS%c",
2829 mas2 & ~0x3ffull,
2830 (mas1 >> 16) & 0x3fff,
2831 pgsz_names[(mas1 >> 7) & 0x1f],
2832 mas1 & MAS1_IND ? 'I' : ' ',
2833 mas1 & MAS1_IPROT ? 'P' : ' ',
2834 mas1 & MAS1_TS ? '1' : '0');
2835 printf(" %c%c%c%c%c%c%c",
2836 mas2 & MAS2_X0 ? 'a' : ' ',
2837 mas2 & MAS2_X1 ? 'v' : ' ',
2838 mas2 & MAS2_W ? 'w' : ' ',
2839 mas2 & MAS2_I ? 'i' : ' ',
2840 mas2 & MAS2_M ? 'm' : ' ',
2841 mas2 & MAS2_G ? 'g' : ' ',
2842 mas2 & MAS2_E ? 'e' : ' ');
2843 printf(" %016llx", mas7_mas3 & ramask & ~0x7ffull);
2844 if (mas1 & MAS1_IND)
2845 printf(" %s\n",
2846 pgsz_names[(mas7_mas3 >> 1) & 0x1f]);
2847 else
2848 printf(" U%c%c%c S%c%c%c\n",
2849 mas7_mas3 & MAS3_UX ? 'x' : ' ',
2850 mas7_mas3 & MAS3_UW ? 'w' : ' ',
2851 mas7_mas3 & MAS3_UR ? 'r' : ' ',
2852 mas7_mas3 & MAS3_SX ? 'x' : ' ',
2853 mas7_mas3 & MAS3_SW ? 'w' : ' ',
2854 mas7_mas3 & MAS3_SR ? 'r' : ' ');
2855 }
2856 }
2857}
2858#endif /* CONFIG_PPC_BOOK3E */
2859
Michael Ellerman9f1067c22008-05-08 14:27:16 +10002860static void xmon_init(int enable)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861{
Stephen Rothwellbbb68172006-11-30 11:44:09 +11002862#ifdef CONFIG_PPC_ISERIES
2863 if (firmware_has_feature(FW_FEATURE_ISERIES))
2864 return;
2865#endif
Olaf Heringb13cfd12005-08-04 19:26:42 +02002866 if (enable) {
2867 __debugger = xmon;
2868 __debugger_ipi = xmon_ipi;
2869 __debugger_bpt = xmon_bpt;
2870 __debugger_sstep = xmon_sstep;
2871 __debugger_iabr_match = xmon_iabr_match;
2872 __debugger_dabr_match = xmon_dabr_match;
2873 __debugger_fault_handler = xmon_fault_handler;
2874 } else {
2875 __debugger = NULL;
2876 __debugger_ipi = NULL;
2877 __debugger_bpt = NULL;
2878 __debugger_sstep = NULL;
2879 __debugger_iabr_match = NULL;
2880 __debugger_dabr_match = NULL;
2881 __debugger_fault_handler = NULL;
2882 }
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002883 xmon_map_scc();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884}
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002885
2886#ifdef CONFIG_MAGIC_SYSRQ
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07002887static void sysrq_handle_xmon(int key)
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002888{
2889 /* ensure xmon is enabled */
2890 xmon_init(1);
David Howells7d12e782006-10-05 14:55:46 +01002891 debugger(get_irq_regs());
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002892}
2893
Dmitry Torokhov1495cc92010-08-17 21:15:46 -07002894static struct sysrq_key_op sysrq_xmon_op = {
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002895 .handler = sysrq_handle_xmon,
2896 .help_msg = "Xmon",
2897 .action_msg = "Entering xmon",
2898};
2899
2900static int __init setup_xmon_sysrq(void)
2901{
Stephen Rothwellbbb68172006-11-30 11:44:09 +11002902#ifdef CONFIG_PPC_ISERIES
2903 if (firmware_has_feature(FW_FEATURE_ISERIES))
2904 return 0;
2905#endif
Paul Mackerrasfca5dcd2005-11-08 22:55:08 +11002906 register_sysrq_key('x', &sysrq_xmon_op);
2907 return 0;
2908}
2909__initcall(setup_xmon_sysrq);
2910#endif /* CONFIG_MAGIC_SYSRQ */
Michael Ellerman476792832006-10-03 14:12:08 +10002911
Olaf Heringf5e6a282007-06-24 16:57:08 +10002912static int __initdata xmon_early, xmon_off;
Michael Ellerman476792832006-10-03 14:12:08 +10002913
2914static int __init early_parse_xmon(char *p)
2915{
2916 if (!p || strncmp(p, "early", 5) == 0) {
2917 /* just "xmon" is equivalent to "xmon=early" */
2918 xmon_init(1);
2919 xmon_early = 1;
2920 } else if (strncmp(p, "on", 2) == 0)
2921 xmon_init(1);
2922 else if (strncmp(p, "off", 3) == 0)
2923 xmon_off = 1;
2924 else if (strncmp(p, "nobt", 4) == 0)
2925 xmon_no_auto_backtrace = 1;
2926 else
2927 return 1;
2928
2929 return 0;
2930}
2931early_param("xmon", early_parse_xmon);
2932
2933void __init xmon_setup(void)
2934{
2935#ifdef CONFIG_XMON_DEFAULT
2936 if (!xmon_off)
2937 xmon_init(1);
2938#endif
2939 if (xmon_early)
2940 debugger(NULL);
2941}
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002942
Arnd Bergmanne0555952006-11-27 19:18:55 +01002943#ifdef CONFIG_SPU_BASE
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002944
2945struct spu_info {
2946 struct spu *spu;
2947 u64 saved_mfc_sr1_RW;
2948 u32 saved_spu_runcntl_RW;
Michael Ellerman24a24c82006-11-23 00:46:41 +01002949 unsigned long dump_addr;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002950 u8 stopped_ok;
2951};
2952
2953#define XMON_NUM_SPUS 16 /* Enough for current hardware */
2954
2955static struct spu_info spu_info[XMON_NUM_SPUS];
2956
2957void xmon_register_spus(struct list_head *list)
2958{
2959 struct spu *spu;
2960
2961 list_for_each_entry(spu, list, full_list) {
2962 if (spu->number >= XMON_NUM_SPUS) {
2963 WARN_ON(1);
2964 continue;
2965 }
2966
2967 spu_info[spu->number].spu = spu;
2968 spu_info[spu->number].stopped_ok = 0;
Michael Ellerman24a24c82006-11-23 00:46:41 +01002969 spu_info[spu->number].dump_addr = (unsigned long)
2970 spu_info[spu->number].spu->local_store;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02002971 }
2972}
2973
2974static void stop_spus(void)
2975{
2976 struct spu *spu;
2977 int i;
2978 u64 tmp;
2979
2980 for (i = 0; i < XMON_NUM_SPUS; i++) {
2981 if (!spu_info[i].spu)
2982 continue;
2983
2984 if (setjmp(bus_error_jmp) == 0) {
2985 catch_memory_errors = 1;
2986 sync();
2987
2988 spu = spu_info[i].spu;
2989
2990 spu_info[i].saved_spu_runcntl_RW =
2991 in_be32(&spu->problem->spu_runcntl_RW);
2992
2993 tmp = spu_mfc_sr1_get(spu);
2994 spu_info[i].saved_mfc_sr1_RW = tmp;
2995
2996 tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
2997 spu_mfc_sr1_set(spu, tmp);
2998
2999 sync();
3000 __delay(200);
3001
3002 spu_info[i].stopped_ok = 1;
Michael Ellerman2a144422006-11-23 00:46:40 +01003003
3004 printf("Stopped spu %.2d (was %s)\n", i,
3005 spu_info[i].saved_spu_runcntl_RW ?
3006 "running" : "stopped");
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003007 } else {
3008 catch_memory_errors = 0;
3009 printf("*** Error stopping spu %.2d\n", i);
3010 }
3011 catch_memory_errors = 0;
3012 }
3013}
3014
3015static void restart_spus(void)
3016{
3017 struct spu *spu;
3018 int i;
3019
3020 for (i = 0; i < XMON_NUM_SPUS; i++) {
3021 if (!spu_info[i].spu)
3022 continue;
3023
3024 if (!spu_info[i].stopped_ok) {
3025 printf("*** Error, spu %d was not successfully stopped"
3026 ", not restarting\n", i);
3027 continue;
3028 }
3029
3030 if (setjmp(bus_error_jmp) == 0) {
3031 catch_memory_errors = 1;
3032 sync();
3033
3034 spu = spu_info[i].spu;
3035 spu_mfc_sr1_set(spu, spu_info[i].saved_mfc_sr1_RW);
3036 out_be32(&spu->problem->spu_runcntl_RW,
3037 spu_info[i].saved_spu_runcntl_RW);
3038
3039 sync();
3040 __delay(200);
3041
3042 printf("Restarted spu %.2d\n", i);
3043 } else {
3044 catch_memory_errors = 0;
3045 printf("*** Error restarting spu %.2d\n", i);
3046 }
3047 catch_memory_errors = 0;
3048 }
3049}
3050
Michael Ellermana8984972006-10-24 18:31:28 +02003051#define DUMP_WIDTH 23
Michael Ellerman437a0702006-11-23 00:46:39 +01003052#define DUMP_VALUE(format, field, value) \
Michael Ellermana8984972006-10-24 18:31:28 +02003053do { \
3054 if (setjmp(bus_error_jmp) == 0) { \
3055 catch_memory_errors = 1; \
3056 sync(); \
3057 printf(" %-*s = "format"\n", DUMP_WIDTH, \
Michael Ellerman437a0702006-11-23 00:46:39 +01003058 #field, value); \
Michael Ellermana8984972006-10-24 18:31:28 +02003059 sync(); \
3060 __delay(200); \
3061 } else { \
3062 catch_memory_errors = 0; \
3063 printf(" %-*s = *** Error reading field.\n", \
3064 DUMP_WIDTH, #field); \
3065 } \
3066 catch_memory_errors = 0; \
3067} while (0)
3068
Michael Ellerman437a0702006-11-23 00:46:39 +01003069#define DUMP_FIELD(obj, format, field) \
3070 DUMP_VALUE(format, field, obj->field)
3071
Michael Ellermana8984972006-10-24 18:31:28 +02003072static void dump_spu_fields(struct spu *spu)
3073{
3074 printf("Dumping spu fields at address %p:\n", spu);
3075
3076 DUMP_FIELD(spu, "0x%x", number);
3077 DUMP_FIELD(spu, "%s", name);
Michael Ellermana8984972006-10-24 18:31:28 +02003078 DUMP_FIELD(spu, "0x%lx", local_store_phys);
3079 DUMP_FIELD(spu, "0x%p", local_store);
3080 DUMP_FIELD(spu, "0x%lx", ls_size);
3081 DUMP_FIELD(spu, "0x%x", node);
3082 DUMP_FIELD(spu, "0x%lx", flags);
Michael Ellermana8984972006-10-24 18:31:28 +02003083 DUMP_FIELD(spu, "%d", class_0_pending);
Luke Browningf3d69e02008-04-27 18:41:55 +00003084 DUMP_FIELD(spu, "0x%lx", class_0_dar);
Luke Browningf3d69e02008-04-27 18:41:55 +00003085 DUMP_FIELD(spu, "0x%lx", class_1_dar);
3086 DUMP_FIELD(spu, "0x%lx", class_1_dsisr);
Michael Ellermana8984972006-10-24 18:31:28 +02003087 DUMP_FIELD(spu, "0x%lx", irqs[0]);
3088 DUMP_FIELD(spu, "0x%lx", irqs[1]);
3089 DUMP_FIELD(spu, "0x%lx", irqs[2]);
3090 DUMP_FIELD(spu, "0x%x", slb_replace);
3091 DUMP_FIELD(spu, "%d", pid);
Michael Ellermana8984972006-10-24 18:31:28 +02003092 DUMP_FIELD(spu, "0x%p", mm);
3093 DUMP_FIELD(spu, "0x%p", ctx);
3094 DUMP_FIELD(spu, "0x%p", rq);
3095 DUMP_FIELD(spu, "0x%p", timestamp);
3096 DUMP_FIELD(spu, "0x%lx", problem_phys);
3097 DUMP_FIELD(spu, "0x%p", problem);
Michael Ellerman437a0702006-11-23 00:46:39 +01003098 DUMP_VALUE("0x%x", problem->spu_runcntl_RW,
3099 in_be32(&spu->problem->spu_runcntl_RW));
3100 DUMP_VALUE("0x%x", problem->spu_status_R,
3101 in_be32(&spu->problem->spu_status_R));
3102 DUMP_VALUE("0x%x", problem->spu_npc_RW,
3103 in_be32(&spu->problem->spu_npc_RW));
Michael Ellermana8984972006-10-24 18:31:28 +02003104 DUMP_FIELD(spu, "0x%p", priv2);
Michael Ellermana9852392006-11-23 00:46:50 +01003105 DUMP_FIELD(spu, "0x%p", pdata);
Michael Ellermana8984972006-10-24 18:31:28 +02003106}
3107
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003108int
3109spu_inst_dump(unsigned long adr, long count, int praddr)
3110{
3111 return generic_inst_dump(adr, count, praddr, print_insn_spu);
3112}
3113
3114static void dump_spu_ls(unsigned long num, int subcmd)
Michael Ellerman24a24c82006-11-23 00:46:41 +01003115{
3116 unsigned long offset, addr, ls_addr;
3117
3118 if (setjmp(bus_error_jmp) == 0) {
3119 catch_memory_errors = 1;
3120 sync();
3121 ls_addr = (unsigned long)spu_info[num].spu->local_store;
3122 sync();
3123 __delay(200);
3124 } else {
3125 catch_memory_errors = 0;
3126 printf("*** Error: accessing spu info for spu %d\n", num);
3127 return;
3128 }
3129 catch_memory_errors = 0;
3130
3131 if (scanhex(&offset))
3132 addr = ls_addr + offset;
3133 else
3134 addr = spu_info[num].dump_addr;
3135
3136 if (addr >= ls_addr + LS_SIZE) {
3137 printf("*** Error: address outside of local store\n");
3138 return;
3139 }
3140
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003141 switch (subcmd) {
3142 case 'i':
3143 addr += spu_inst_dump(addr, 16, 1);
3144 last_cmd = "sdi\n";
3145 break;
3146 default:
3147 prdump(addr, 64);
3148 addr += 64;
3149 last_cmd = "sd\n";
3150 break;
3151 }
Michael Ellerman24a24c82006-11-23 00:46:41 +01003152
3153 spu_info[num].dump_addr = addr;
3154}
3155
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003156static int do_spu_cmd(void)
3157{
Michael Ellerman24a24c82006-11-23 00:46:41 +01003158 static unsigned long num = 0;
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003159 int cmd, subcmd = 0;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003160
3161 cmd = inchar();
3162 switch (cmd) {
3163 case 's':
3164 stop_spus();
3165 break;
3166 case 'r':
3167 restart_spus();
3168 break;
Michael Ellerman24a24c82006-11-23 00:46:41 +01003169 case 'd':
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003170 subcmd = inchar();
3171 if (isxdigit(subcmd) || subcmd == '\n')
3172 termch = subcmd;
3173 case 'f':
Michael Ellerman24a24c82006-11-23 00:46:41 +01003174 scanhex(&num);
3175 if (num >= XMON_NUM_SPUS || !spu_info[num].spu) {
Michael Ellermana8984972006-10-24 18:31:28 +02003176 printf("*** Error: invalid spu number\n");
Michael Ellerman24a24c82006-11-23 00:46:41 +01003177 return 0;
3178 }
3179
3180 switch (cmd) {
3181 case 'f':
3182 dump_spu_fields(spu_info[num].spu);
3183 break;
3184 default:
Michael Ellermanaf89fb82006-11-23 00:46:44 +01003185 dump_spu_ls(num, subcmd);
Michael Ellerman24a24c82006-11-23 00:46:41 +01003186 break;
3187 }
3188
Michael Ellermana8984972006-10-24 18:31:28 +02003189 break;
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003190 default:
3191 return -1;
3192 }
3193
3194 return 0;
3195}
Arnd Bergmanne0555952006-11-27 19:18:55 +01003196#else /* ! CONFIG_SPU_BASE */
Michael Ellermanff8a8f22006-10-24 18:31:27 +02003197static int do_spu_cmd(void)
3198{
3199 return -1;
3200}
3201#endif